svn commit: r310297 - in head/sys: conf dev/bhnd/nvram dev/bhnd/tools modules/bhnd

Landon J. Fuller landonf at FreeBSD.org
Mon Dec 19 20:34:07 UTC 2016


Author: landonf
Date: Mon Dec 19 20:34:05 2016
New Revision: 310297
URL: https://svnweb.freebsd.org/changeset/base/310297

Log:
  bhnd(4): NVRAM serialization support.
  
  This adds support for:
  
  - Serializing an bhnd_nvram_plist (as exported from bhnd_nvram_store, etc) to
    an arbitrary NVRAM data format.
  - Generating a serialized representation of the current NVRAM store's state
    suitable for writing back to flash, or re-encoding for upload to a
    FullMAC device.
  
  Approved by:	adrian (mentor)
  Differential Revision:	https://reviews.freebsd.org/D8762

Added:
  head/sys/dev/bhnd/nvram/bhnd_nvram_data_sprom_subr.c   (contents, props changed)
Modified:
  head/sys/conf/files
  head/sys/dev/bhnd/nvram/bhnd_nvram_data.c
  head/sys/dev/bhnd/nvram/bhnd_nvram_data.h
  head/sys/dev/bhnd/nvram/bhnd_nvram_data_bcm.c
  head/sys/dev/bhnd/nvram/bhnd_nvram_data_bcmraw.c
  head/sys/dev/bhnd/nvram/bhnd_nvram_data_bcmreg.h
  head/sys/dev/bhnd/nvram/bhnd_nvram_data_btxt.c
  head/sys/dev/bhnd/nvram/bhnd_nvram_data_sprom.c
  head/sys/dev/bhnd/nvram/bhnd_nvram_data_spromvar.h
  head/sys/dev/bhnd/nvram/bhnd_nvram_data_tlv.c
  head/sys/dev/bhnd/nvram/bhnd_nvram_datavar.h
  head/sys/dev/bhnd/nvram/bhnd_nvram_private.h
  head/sys/dev/bhnd/nvram/bhnd_nvram_store.c
  head/sys/dev/bhnd/nvram/bhnd_nvram_store.h
  head/sys/dev/bhnd/tools/nvram_map_gen.awk
  head/sys/modules/bhnd/Makefile

Modified: head/sys/conf/files
==============================================================================
--- head/sys/conf/files	Mon Dec 19 20:31:27 2016	(r310296)
+++ head/sys/conf/files	Mon Dec 19 20:34:05 2016	(r310297)
@@ -1236,6 +1236,7 @@ dev/bhnd/nvram/bhnd_nvram_data_bcm.c	opt
 dev/bhnd/nvram/bhnd_nvram_data_bcmraw.c	optional bhnd
 dev/bhnd/nvram/bhnd_nvram_data_btxt.c	optional bhnd
 dev/bhnd/nvram/bhnd_nvram_data_sprom.c	optional bhnd
+dev/bhnd/nvram/bhnd_nvram_data_sprom_subr.c	optional bhnd
 dev/bhnd/nvram/bhnd_nvram_data_tlv.c	optional bhnd
 dev/bhnd/nvram/bhnd_nvram_if.m		optional bhnd
 dev/bhnd/nvram/bhnd_nvram_io.c		optional bhnd

Modified: head/sys/dev/bhnd/nvram/bhnd_nvram_data.c
==============================================================================
--- head/sys/dev/bhnd/nvram/bhnd_nvram_data.c	Mon Dec 19 20:31:27 2016	(r310296)
+++ head/sys/dev/bhnd/nvram/bhnd_nvram_data.c	Mon Dec 19 20:34:05 2016	(r310297)
@@ -65,6 +65,54 @@ bhnd_nvram_data_class_desc(bhnd_nvram_da
 }
 
 /**
+ * Return the class-level capability flags (@see BHND_NVRAM_DATA_CAP_*) for
+ * of @p cls.
+ *
+ * @param cls The NVRAM class.
+ */
+uint32_t
+bhnd_nvram_data_class_caps(bhnd_nvram_data_class *cls)
+{
+	return (cls->caps);
+}
+
+/**
+ * Serialize all NVRAM properties in @p plist using @p cls's NVRAM data
+ * format, writing the result to @p outp.
+ * 
+ * @param		cls	The NVRAM data class to be used to perform
+ *				serialization.
+ * @param		props	The raw property values to be serialized to
+ *				@p outp, in serialization order.
+ * @param		options	Serialization options for @p cls, or NULL.
+ * @param[out]		outp	On success, the serialed NVRAM data will be
+ *				written to this buffer. This argment may be
+ *				NULL if the value is not desired.
+ * @param[in,out]	olen	The capacity of @p buf. On success, will be set
+ *				to the actual length of the serialized data.
+ *
+ * @retval 0		success
+ * 
+ * @retval ENOMEM	If @p outp is non-NULL and a buffer of @p olen is too
+ *			small to hold the serialized data.
+ * @retval EINVAL	If a property value required by @p cls is not found in
+ *			@p plist.
+ * @retval EFTYPE	If a property value in @p plist cannot be represented
+ *			as the data type required by @p cls.
+ * @retval ERANGE	If a property value in @p plist would would overflow
+ *			(or underflow) the data type required by @p cls.
+ * @retval non-zero	If serialization otherwise fails, a regular unix error
+ *			code will be returned.
+ */
+int
+bhnd_nvram_data_serialize(bhnd_nvram_data_class *cls,
+    bhnd_nvram_plist *props, bhnd_nvram_plist *options, void *outp,
+    size_t *olen)
+{
+	return (cls->op_serialize(cls, props, options, outp, olen));
+}
+
+/**
  * Probe to see if this NVRAM data class class supports the data mapped by the
  * given I/O context, returning a BHND_NVRAM_DATA_PROBE probe result.
  *
@@ -293,51 +341,6 @@ bhnd_nvram_data_options(struct bhnd_nvra
 }
 
 /**
- * Compute the size of the serialized form of @p nv.
- *
- * Serialization may be performed via bhnd_nvram_data_serialize().
- *
- * @param	nv	The NVRAM data to be queried.
- * @param[out]	len	On success, will be set to the computed size.
- * 
- * @retval 0		success
- * @retval non-zero	if computing the serialized size otherwise fails, a
- *			regular unix error code will be returned.
- */
-int
-bhnd_nvram_data_size(struct bhnd_nvram_data *nv, size_t *len)
-{
-	return (nv->cls->op_size(nv, len));
-}
-
-/**
- * Serialize the NVRAM data to @p buf, using the NVRAM data class' native
- * format.
- * 
- * The resulting serialization may be reparsed with @p nv's BHND NVRAM data
- * class.
- * 
- * @param		nv	The NVRAM data to be serialized.
- * @param[out]		buf	On success, the serialed NVRAM data will be
- *				written to this buffer. This argment may be
- *				NULL if the value is not desired.
- * @param[in,out]	len	The capacity of @p buf. On success, will be set
- *				to the actual length of the serialized data.
- *
- * @retval 0		success
- * @retval ENOMEM	If @p buf is non-NULL and a buffer of @p len is too
- *			small to hold the serialized data.
- * @retval non-zero	If serialization otherwise fails, a regular unix error
- *			code will be returned.
- */
-int
-bhnd_nvram_data_serialize(struct bhnd_nvram_data *nv,
-    void *buf, size_t *len)
-{
-	return (nv->cls->op_serialize(nv, buf, len));
-}
-
-/**
  * Return the capability flags (@see BHND_NVRAM_DATA_CAP_*) for @p nv.
  *
  * @param	nv	The NVRAM data to be queried.

Modified: head/sys/dev/bhnd/nvram/bhnd_nvram_data.h
==============================================================================
--- head/sys/dev/bhnd/nvram/bhnd_nvram_data.h	Mon Dec 19 20:31:27 2016	(r310296)
+++ head/sys/dev/bhnd/nvram/bhnd_nvram_data.h	Mon Dec 19 20:34:05 2016	(r310297)
@@ -91,6 +91,11 @@ enum {
 };
 
 const char		*bhnd_nvram_data_class_desc(bhnd_nvram_data_class *cls);
+uint32_t		 bhnd_nvram_data_class_caps(bhnd_nvram_data_class *cls);
+
+int			 bhnd_nvram_data_serialize(bhnd_nvram_data_class *cls,
+			     bhnd_nvram_plist *props, bhnd_nvram_plist *options,
+			     void *outp, size_t *olen);
 
 int			 bhnd_nvram_data_probe(bhnd_nvram_data_class *cls,
 			     struct bhnd_nvram_io *io);
@@ -110,12 +115,6 @@ void			 bhnd_nvram_data_release(struct b
 bhnd_nvram_data_class	*bhnd_nvram_data_get_class(struct bhnd_nvram_data *nv);
 
 size_t			 bhnd_nvram_data_count(struct bhnd_nvram_data *nv);
-int			 bhnd_nvram_data_size(struct bhnd_nvram_data *nv,
-			     size_t *size);
-
-int			 bhnd_nvram_data_serialize(struct bhnd_nvram_data *nv,
-			     void *buf, size_t *len);
-
 bhnd_nvram_plist	*bhnd_nvram_data_options(struct bhnd_nvram_data *nv);
 uint32_t		 bhnd_nvram_data_caps(struct bhnd_nvram_data *nv);
 

Modified: head/sys/dev/bhnd/nvram/bhnd_nvram_data_bcm.c
==============================================================================
--- head/sys/dev/bhnd/nvram/bhnd_nvram_data_bcm.c	Mon Dec 19 20:31:27 2016	(r310296)
+++ head/sys/dev/bhnd/nvram/bhnd_nvram_data_bcm.c	Mon Dec 19 20:34:05 2016	(r310297)
@@ -129,7 +129,8 @@ struct bhnd_nvram_bcm {
 	size_t				 count;	/**< total variable count */
 };
 
-BHND_NVRAM_DATA_CLASS_DEFN(bcm, "Broadcom", sizeof(struct bhnd_nvram_bcm))
+BHND_NVRAM_DATA_CLASS_DEFN(bcm, "Broadcom", BHND_NVRAM_DATA_CAP_DEVPATHS,
+    sizeof(struct bhnd_nvram_bcm))
 
 static int
 bhnd_nvram_bcm_probe(struct bhnd_nvram_io *io)
@@ -146,6 +147,190 @@ bhnd_nvram_bcm_probe(struct bhnd_nvram_i
 	return (BHND_NVRAM_DATA_PROBE_DEFAULT);
 }
 
+static int
+bhnd_nvram_bcm_serialize(bhnd_nvram_data_class *cls, bhnd_nvram_plist *props,
+    bhnd_nvram_plist *options, void *outp, size_t *olen)
+{
+	struct bhnd_nvram_bcmhdr	 hdr;
+	bhnd_nvram_prop			*prop;
+	size_t				 limit, nbytes;
+	uint32_t			 sdram_ncdl;
+	uint16_t			 sdram_init, sdram_cfg, sdram_refresh;
+	uint8_t				 bcm_ver, crc8;
+	int				 error;
+
+	/* Determine output byte limit */
+	if (outp != NULL)
+		limit = *olen;
+	else
+		limit = 0;
+
+	/* Fetch required header variables */
+#define	PROPS_GET_HDRVAR(_name, _dest, _type)	do {			\
+		const char *name = BCM_NVRAM_ ## _name ## _VAR;	\
+		if (!bhnd_nvram_plist_contains(props, name)) {		\
+			BHND_NV_LOG("missing required property: %s\n",	\
+			    name);					\
+			return (EFTYPE);				\
+		}							\
+									\
+		error = bhnd_nvram_plist_get_encoded(props, name,	\
+		    (_dest), sizeof(*(_dest)),				\
+		    BHND_NVRAM_TYPE_ ##_type);				\
+		if (error) {						\
+			BHND_NV_LOG("error reading required header "	\
+			    "%s property: %d\n", name, error);		\
+			return (EFTYPE);				\
+		}							\
+} while (0)
+
+	PROPS_GET_HDRVAR(SDRAM_NCDL,		&sdram_ncdl,	UINT32);
+	PROPS_GET_HDRVAR(CFG0_SDRAM_INIT,	&sdram_init,	UINT16);
+	PROPS_GET_HDRVAR(CFG1_SDRAM_CFG,	&sdram_cfg,	UINT16);
+	PROPS_GET_HDRVAR(CFG1_SDRAM_REFRESH,	&sdram_refresh,	UINT16);
+
+#undef	PROPS_GET_HDRVAR
+
+	/* Fetch BCM nvram version from options */
+	if (options != NULL &&
+	    bhnd_nvram_plist_contains(options, BCM_NVRAM_ENCODE_OPT_VERSION))
+	{
+		error = bhnd_nvram_plist_get_uint8(options,
+		    BCM_NVRAM_ENCODE_OPT_VERSION, &bcm_ver);
+		if (error) {
+			BHND_NV_LOG("error reading %s uint8 option value: %d\n",
+			    BCM_NVRAM_ENCODE_OPT_VERSION, error);
+			return (EINVAL);
+		}
+	} else {
+		bcm_ver = BCM_NVRAM_CFG0_VER_DEFAULT;
+	}
+
+	/* Construct our header */
+	hdr = (struct bhnd_nvram_bcmhdr) {
+		.magic = htole32(BCM_NVRAM_MAGIC),
+		.size = 0,
+		.cfg0 = 0,
+		.cfg1 = 0,
+		.sdram_ncdl = htole32(sdram_ncdl)
+	};
+
+	hdr.cfg0 = BCM_NVRAM_SET_BITS(hdr.cfg0, BCM_NVRAM_CFG0_CRC, 0x0);
+	hdr.cfg0 = BCM_NVRAM_SET_BITS(hdr.cfg0, BCM_NVRAM_CFG0_VER, bcm_ver);
+	hdr.cfg0 = BCM_NVRAM_SET_BITS(hdr.cfg0, BCM_NVRAM_CFG0_SDRAM_INIT,
+	    htole16(sdram_init));
+	
+	hdr.cfg1 = BCM_NVRAM_SET_BITS(hdr.cfg1, BCM_NVRAM_CFG1_SDRAM_CFG,
+	    htole16(sdram_cfg));
+	hdr.cfg1 = BCM_NVRAM_SET_BITS(hdr.cfg1, BCM_NVRAM_CFG1_SDRAM_REFRESH,
+	    htole16(sdram_refresh));
+
+	/* Write the header */
+	nbytes = sizeof(hdr);
+	if (limit >= nbytes)
+		memcpy(outp, &hdr, sizeof(hdr));
+
+	/* Write all properties */
+	prop = NULL;
+	while ((prop = bhnd_nvram_plist_next(props, prop)) != NULL) {
+		const char	*name;
+		char		*p;
+		size_t		 prop_limit;
+		size_t		 name_len, value_len;
+
+		if (outp == NULL || limit < nbytes) {
+			p = NULL;
+			prop_limit = 0;
+		} else {
+			p = ((char *)outp) + nbytes;
+			prop_limit = limit - nbytes;
+		}
+
+		/* Fetch and write name + '=' to output */
+		name = bhnd_nvram_prop_name(prop);
+		name_len = strlen(name) + 1;
+
+		if (prop_limit > name_len) {
+			memcpy(p, name, name_len - 1);
+			p[name_len - 1] = '=';
+
+			prop_limit -= name_len;
+			p += name_len;
+		} else {
+			prop_limit = 0;
+			p = NULL;
+		}
+
+		/* Advance byte count */
+		if (SIZE_MAX - nbytes < name_len)
+			return (EFTYPE); /* would overflow size_t */
+
+		nbytes += name_len;
+
+		/* Attempt to write NUL-terminated value to output */
+		value_len = prop_limit;
+		error = bhnd_nvram_prop_encode(prop, p, &value_len,
+		    BHND_NVRAM_TYPE_STRING);
+
+		/* If encoding failed for any reason other than ENOMEM (which
+		 * we'll detect and report after encoding all properties),
+		 * return immediately */
+		if (error && error != ENOMEM) {
+			BHND_NV_LOG("error serializing %s to required type "
+			    "%s: %d\n", name,
+			    bhnd_nvram_type_name(BHND_NVRAM_TYPE_STRING),
+			    error);
+			return (error);
+		}
+
+		/* Advance byte count */
+		if (SIZE_MAX - nbytes < value_len)
+			return (EFTYPE); /* would overflow size_t */
+
+		nbytes += value_len;
+	}
+
+	/* Write terminating '\0' */
+	if (limit > nbytes)
+		*((char *)outp + nbytes) = '\0';
+
+	if (nbytes == SIZE_MAX)
+		return (EFTYPE); /* would overflow size_t */
+	else
+		nbytes++;
+
+	/* Update header length; this must fit within the header's 32-bit size
+	 * field */
+	if (nbytes <= UINT32_MAX) {
+		hdr.size = (uint32_t)nbytes;
+	} else {
+		BHND_NV_LOG("size %zu exceeds maximum supported size of %u "
+		    "bytes\n", nbytes, UINT32_MAX);
+		return (EFTYPE);
+	}
+
+	/* Provide required length */
+	*olen = nbytes;
+	if (limit < *olen) {
+		if (outp == NULL)
+			return (0);
+
+		return (ENOMEM);
+	}
+
+	/* Calculate the CRC value */
+	BHND_NV_ASSERT(nbytes >= BCM_NVRAM_CRC_SKIP, ("invalid output size"));
+	crc8 = bhnd_nvram_crc8((uint8_t *)outp + BCM_NVRAM_CRC_SKIP,
+	    nbytes - BCM_NVRAM_CRC_SKIP, BHND_NVRAM_CRC8_INITIAL);
+
+	/* Update CRC and write the finalized header */
+	BHND_NV_ASSERT(nbytes >= sizeof(hdr), ("invalid output size"));
+	hdr.cfg0 = BCM_NVRAM_SET_BITS(hdr.cfg0, BCM_NVRAM_CFG0_CRC, crc8);
+	memcpy(outp, &hdr, sizeof(hdr));
+
+	return (0);
+}
+
 /**
  * Initialize @p bcm with the provided NVRAM data mapped by @p src.
  * 
@@ -411,127 +596,6 @@ bhnd_nvram_bcm_options(struct bhnd_nvram
 	return (bcm->opts);
 }
 
-static int
-bhnd_nvram_bcm_size(struct bhnd_nvram_data *nv, size_t *size)
-{
-	return (bhnd_nvram_bcm_serialize(nv, NULL, size));
-}
-
-static int
-bhnd_nvram_bcm_serialize(struct bhnd_nvram_data *nv, void *buf, size_t *len)
-{
-	struct bhnd_nvram_bcm		*bcm;
-	struct bhnd_nvram_bcmhdr	 hdr;
-	void				*cookiep;
-	const char			*name;
-	size_t				 nbytes, limit;
-	uint8_t				 crc;
-	int				 error;
-
-	bcm = (struct bhnd_nvram_bcm *)nv;
-	nbytes = 0;
-
-	/* Save the output buffer limit */
-	if (buf == NULL)
-		limit = 0;
-	else
-		limit = *len;
-
-	/* Reserve space for the NVRAM header */
-	nbytes += sizeof(struct bhnd_nvram_bcmhdr);
-
-	/* Write all variables to the output buffer */
-	cookiep = NULL;
-	while ((name = bhnd_nvram_data_next(nv, &cookiep))) {
-		uint8_t		*outp;
-		size_t		 olen;
-		size_t		 name_len, val_len;
-
-		if (limit > nbytes) {
-			outp = (uint8_t *)buf + nbytes;
-			olen = limit - nbytes;
-		} else {
-			outp = NULL;
-			olen = 0;
-		}
-
-		/* Determine length of variable name */
-		name_len = strlen(name) + 1;
-
-		/* Write the variable name and '=' delimiter */
-		if (olen >= name_len) {
-			/* Copy name */
-			memcpy(outp, name, name_len - 1);
-
-			/* Append '=' */
-			*(outp + name_len - 1) = '=';
-		}
-
-		/* Adjust byte counts */
-		if (SIZE_MAX - name_len < nbytes)
-			return (ERANGE);
-
-		nbytes += name_len;
-
-		/* Reposition output */
-		if (limit > nbytes) {
-			outp = (uint8_t *)buf + nbytes;
-			olen = limit - nbytes;
-		} else {
-			outp = NULL;
-			olen = 0;
-		}
-
-		/* Coerce to NUL-terminated C string, writing to the output
-		 * buffer (or just calculating the length if outp is NULL) */
-		val_len = olen;
-		error = bhnd_nvram_data_getvar(nv, cookiep, outp, &val_len,
-		    BHND_NVRAM_TYPE_STRING);
-
-		if (error && error != ENOMEM)
-			return (error);
-
-		/* Adjust byte counts */
-		if (SIZE_MAX - val_len < nbytes)
-			return (ERANGE);
-
-		nbytes += val_len;
-	}
-
-	/* Write terminating NUL */
-	if (nbytes < limit)
-		*((uint8_t *)buf + nbytes) = '\0';
-	nbytes++;
-
-	/* Provide actual size */
-	*len = nbytes;
-	if (buf == NULL || nbytes > limit) {
-		if (buf != NULL)
-			return (ENOMEM);
-
-		return (0);
-	}
-
-	/* Fetch current NVRAM header */
-	if ((error = bhnd_nvram_io_read(bcm->data, 0x0, &hdr, sizeof(hdr))))
-		return (error);
-
-	/* Update values covered by CRC and write to output buffer */
-	hdr.size = htole32(*len);
-	memcpy(buf, &hdr, sizeof(hdr));
-
-	/* Calculate new CRC */
-	crc = bhnd_nvram_crc8((uint8_t *)buf + BCM_NVRAM_CRC_SKIP,
-	    *len - BCM_NVRAM_CRC_SKIP, BHND_NVRAM_CRC8_INITIAL);
-
-	/* Update header with valid CRC */
-	hdr.cfg0 &= ~BCM_NVRAM_CFG0_CRC_MASK;
-	hdr.cfg0 |= (crc << BCM_NVRAM_CFG0_CRC_SHIFT);
-	memcpy(buf, &hdr, sizeof(hdr));
-
-	return (0);
-}
-
 static uint32_t
 bhnd_nvram_bcm_caps(struct bhnd_nvram_data *nv)
 {

Modified: head/sys/dev/bhnd/nvram/bhnd_nvram_data_bcmraw.c
==============================================================================
--- head/sys/dev/bhnd/nvram/bhnd_nvram_data_bcmraw.c	Mon Dec 19 20:31:27 2016	(r310296)
+++ head/sys/dev/bhnd/nvram/bhnd_nvram_data_bcmraw.c	Mon Dec 19 20:34:05 2016	(r310297)
@@ -72,7 +72,7 @@ struct bhnd_nvram_bcmraw {
 };
 
 BHND_NVRAM_DATA_CLASS_DEFN(bcmraw, "Broadcom (RAW)",
-   sizeof(struct bhnd_nvram_bcmraw))
+    BHND_NVRAM_DATA_CAP_DEVPATHS, sizeof(struct bhnd_nvram_bcmraw))
 
 static int
 bhnd_nvram_bcmraw_probe(struct bhnd_nvram_io *io)
@@ -132,6 +132,103 @@ bhnd_nvram_bcmraw_probe(struct bhnd_nvra
 	return (BHND_NVRAM_DATA_PROBE_MAYBE + 1);
 }
 
+static int
+bhnd_nvram_bcmraw_serialize(bhnd_nvram_data_class *cls, bhnd_nvram_plist *props,
+    bhnd_nvram_plist *options, void *outp, size_t *olen)
+{
+	bhnd_nvram_prop	*prop;
+	size_t		 limit, nbytes;
+	int		 error;
+
+	/* Determine output byte limit */
+	if (outp != NULL)
+		limit = *olen;
+	else
+		limit = 0;
+
+	nbytes = 0;
+
+	/* Write all properties */
+	prop = NULL;
+	while ((prop = bhnd_nvram_plist_next(props, prop)) != NULL) {
+		const char	*name;
+		char		*p;
+		size_t		 prop_limit;
+		size_t		 name_len, value_len;
+
+		if (outp == NULL || limit < nbytes) {
+			p = NULL;
+			prop_limit = 0;
+		} else {
+			p = ((char *)outp) + nbytes;
+			prop_limit = limit - nbytes;
+		}
+
+		/* Fetch and write name + '=' to output */
+		name = bhnd_nvram_prop_name(prop);
+		name_len = strlen(name) + 1;
+
+		if (prop_limit > name_len) {
+			memcpy(p, name, name_len - 1);
+			p[name_len - 1] = '=';
+
+			prop_limit -= name_len;
+			p += name_len;
+		} else {
+			prop_limit = 0;
+			p = NULL;
+		}
+
+		/* Advance byte count */
+		if (SIZE_MAX - nbytes < name_len)
+			return (EFTYPE); /* would overflow size_t */
+
+		nbytes += name_len;
+
+		/* Attempt to write NUL-terminated value to output */
+		value_len = prop_limit;
+		error = bhnd_nvram_prop_encode(prop, p, &value_len,
+		    BHND_NVRAM_TYPE_STRING);
+
+		/* If encoding failed for any reason other than ENOMEM (which
+		 * we'll detect and report after encoding all properties),
+		 * return immediately */
+		if (error && error != ENOMEM) {
+			BHND_NV_LOG("error serializing %s to required type "
+			    "%s: %d\n", name,
+			    bhnd_nvram_type_name(BHND_NVRAM_TYPE_STRING),
+			    error);
+			return (error);
+		}
+
+		/* Advance byte count */
+		if (SIZE_MAX - nbytes < value_len)
+			return (EFTYPE); /* would overflow size_t */
+
+		nbytes += value_len;
+	}
+
+	/* Write terminating '\0' */
+	if (limit > nbytes)
+		*((char *)outp + nbytes) = '\0';
+
+	if (nbytes == SIZE_MAX)
+		return (EFTYPE); /* would overflow size_t */
+	else
+		nbytes++;
+
+	/* Provide required length */
+	*olen = nbytes;
+	if (limit < *olen) {
+		if (outp == NULL)
+			return (0);
+
+		return (ENOMEM);
+	}
+
+	return (0);
+}
+
 /**
  * Initialize @p bcm with the provided NVRAM data mapped by @p src.
  * 
@@ -249,85 +346,18 @@ bhnd_nvram_bcmraw_free(struct bhnd_nvram
 		bhnd_nv_free(bcm->data);
 }
 
-static size_t
-bhnd_nvram_bcmraw_count(struct bhnd_nvram_data *nv)
-{
-	struct bhnd_nvram_bcmraw *bcm = (struct bhnd_nvram_bcmraw *)nv;
-
-	return (bcm->count);
-}
-
 static bhnd_nvram_plist *
 bhnd_nvram_bcmraw_options(struct bhnd_nvram_data *nv)
 {
 	return (NULL);
 }
 
-static int
-bhnd_nvram_bcmraw_size(struct bhnd_nvram_data *nv, size_t *size)
-{
-	return (bhnd_nvram_bcmraw_serialize(nv, NULL, size));
-}
-
-static int
-bhnd_nvram_bcmraw_serialize(struct bhnd_nvram_data *nv, void *buf, size_t *len)
+static size_t
+bhnd_nvram_bcmraw_count(struct bhnd_nvram_data *nv)
 {
-	struct bhnd_nvram_bcmraw	*bcm;
-	char * const			 p = (char *)buf;
-	size_t				 limit;
-	size_t				 offset;
-
-	bcm = (struct bhnd_nvram_bcmraw *)nv;
-
-	/* Save the output buffer limit */
-	if (buf == NULL)
-		limit = 0;
-	else
-		limit = *len;
-
-	/* The serialized form will be exactly the length
-	 * of our backing buffer representation */
-	*len = bcm->size;
-
-	/* Skip serialization if not requested, or report ENOMEM if
-	 * buffer is too small */
-	if (buf == NULL) {
-		return (0);
-	} else if (*len > limit) {
-		return (ENOMEM);
-	}
-
-	/* Write all variables to the output buffer */
-	memcpy(buf, bcm->data, *len);
-
-	/* Rewrite all '\0' delimiters back to '=' */
-	offset = 0;
-	while (offset < bcm->size) {
-		size_t name_len, value_len;
-
-		name_len = strlen(p + offset);
-
-		/* EOF? */
-		if (name_len == 0) {
-			BHND_NV_ASSERT(*(p + offset) == '\0',
-			    ("no NUL terminator"));
-
-			offset++;
-			break;
-		}
-
-		/* Rewrite 'name\0' to 'name=' */
-		offset += name_len;
-		BHND_NV_ASSERT(*(p + offset) == '\0', ("incorrect offset"));
-
-		*(p + offset) = '=';
-		offset++;
-
-		value_len = strlen(p + offset);
-		offset += value_len + 1;
-	}
+	struct bhnd_nvram_bcmraw *bcm = (struct bhnd_nvram_bcmraw *)nv;
 
-	return (0);
+	return (bcm->count);
 }
 
 static uint32_t

Modified: head/sys/dev/bhnd/nvram/bhnd_nvram_data_bcmreg.h
==============================================================================
--- head/sys/dev/bhnd/nvram/bhnd_nvram_data_bcmreg.h	Mon Dec 19 20:31:27 2016	(r310296)
+++ head/sys/dev/bhnd/nvram/bhnd_nvram_data_bcmreg.h	Mon Dec 19 20:34:05 2016	(r310297)
@@ -32,9 +32,13 @@
 #ifndef _BHND_NVRAM_BHND_NVRAM_BCMREG_H_
 #define _BHND_NVRAM_BHND_NVRAM_BCMREG_H_
 
-#define BCM_NVRAM_GET_BITS(_value, _field)  \
+#define BCM_NVRAM_GET_BITS(_value, _field)			\
 	((_value & _field ## _MASK) >> _field ## _SHIFT)
 
+#define BCM_NVRAM_SET_BITS(_value, _field, _bits)		\
+	((_value & ~(_field ## _MASK)) |			\
+	    (((_bits) << _field ## _SHIFT) & _field ## _MASK))
+
 /* BCM NVRAM header fields */
 #define	BCM_NVRAM_MAGIC				0x48534C46	/* 'FLSH' */
 #define	BCM_NVRAM_VERSION			1
@@ -45,6 +49,7 @@
 #define	BCM_NVRAM_CFG0_CRC_SHIFT		0
 #define	BCM_NVRAM_CFG0_VER_MASK			0x0000FF00
 #define	BCM_NVRAM_CFG0_VER_SHIFT		8
+#define	BCM_NVRAM_CFG0_VER_DEFAULT		1		/* default version */
 
 #define	BCM_NVRAM_CFG0_SDRAM_INIT_FIELD		cfg0
 #define	BCM_NVRAM_CFG0_SDRAM_INIT_MASK		0xFFFF0000

Modified: head/sys/dev/bhnd/nvram/bhnd_nvram_data_btxt.c
==============================================================================
--- head/sys/dev/bhnd/nvram/bhnd_nvram_data_btxt.c	Mon Dec 19 20:31:27 2016	(r310296)
+++ head/sys/dev/bhnd/nvram/bhnd_nvram_data_btxt.c	Mon Dec 19 20:34:05 2016	(r310297)
@@ -69,7 +69,7 @@ struct bhnd_nvram_btxt {
 };
 
 BHND_NVRAM_DATA_CLASS_DEFN(btxt, "Broadcom Board Text",
-    sizeof(struct bhnd_nvram_btxt))
+    BHND_NVRAM_DATA_CAP_DEVPATHS, sizeof(struct bhnd_nvram_btxt))
 
 /** Minimal identification header */
 union bhnd_nvram_btxt_ident {
@@ -124,6 +124,100 @@ bhnd_nvram_btxt_probe(struct bhnd_nvram_
 	return (BHND_NVRAM_DATA_PROBE_MAYBE);
 }
 
+static int
+bhnd_nvram_btxt_serialize(bhnd_nvram_data_class *cls, bhnd_nvram_plist *props,
+    bhnd_nvram_plist *options, void *outp, size_t *olen)
+{
+	bhnd_nvram_prop	*prop;
+	size_t		 limit, nbytes;
+	int		 error;
+
+	/* Determine output byte limit */
+	if (outp != NULL)
+		limit = *olen;
+	else
+		limit = 0;
+
+	nbytes = 0;
+
+	/* Write all properties */
+	prop = NULL;
+	while ((prop = bhnd_nvram_plist_next(props, prop)) != NULL) {
+		const char	*name;
+		char		*p;
+		size_t		 prop_limit;
+		size_t		 name_len, value_len;
+
+		if (outp == NULL || limit < nbytes) {
+			p = NULL;
+			prop_limit = 0;
+		} else {
+			p = ((char *)outp) + nbytes;
+			prop_limit = limit - nbytes;
+		}
+
+		/* Fetch and write 'name=' to output */
+		name = bhnd_nvram_prop_name(prop);
+		name_len = strlen(name) + 1;
+
+		if (prop_limit > name_len) {
+			memcpy(p, name, name_len - 1);
+			p[name_len - 1] = '=';
+
+			prop_limit -= name_len;
+			p += name_len;
+		} else {
+			prop_limit = 0;
+			p = NULL;
+		}
+
+		/* Advance byte count */
+		if (SIZE_MAX - nbytes < name_len)
+			return (EFTYPE); /* would overflow size_t */
+
+		nbytes += name_len;
+
+		/* Write NUL-terminated value to output, rewrite NUL as
+		 * '\n' record delimiter */
+		value_len = prop_limit;
+		error = bhnd_nvram_prop_encode(prop, p, &value_len,
+		    BHND_NVRAM_TYPE_STRING);
+		if (p != NULL && error == 0) {
+			/* Replace trailing '\0' with newline */
+			BHND_NV_ASSERT(value_len > 0, ("string length missing "
+			    "minimum required trailing NUL"));
+
+			*(p + (value_len - 1)) = '\n';
+		} else if (error && error != ENOMEM) {
+			/* If encoding failed for any reason other than ENOMEM
+			 * (which we'll detect and report after encoding all
+			 * properties), return immediately */
+			BHND_NV_LOG("error serializing %s to required type "
+			    "%s: %d\n", name,
+			    bhnd_nvram_type_name(BHND_NVRAM_TYPE_STRING),
+			    error);
+			return (error);
+		}
+
+		/* Advance byte count */
+		if (SIZE_MAX - nbytes < value_len)
+			return (EFTYPE); /* would overflow size_t */
+
+		nbytes += value_len;
+	}
+
+	/* Provide required length */
+	*olen = nbytes;
+	if (limit < *olen) {
+		if (outp == NULL)
+			return (0);
+
+		return (ENOMEM);
+	}
+
+	return (0);
+}
+
 /**
  * Initialize @p btxt with the provided board text data mapped by @p src.
  * 
@@ -261,52 +355,6 @@ bhnd_nvram_btxt_options(struct bhnd_nvra
 	return (NULL);
 }
 
-static int
-bhnd_nvram_btxt_size(struct bhnd_nvram_data *nv, size_t *size)
-{
-	struct bhnd_nvram_btxt *btxt = (struct bhnd_nvram_btxt *)nv;
-
-	/* The serialized form will be identical in length
-	 * to our backing buffer representation */
-	*size = bhnd_nvram_io_getsize(btxt->data);
-	return (0);
-}
-
-static int
-bhnd_nvram_btxt_serialize(struct bhnd_nvram_data *nv, void *buf, size_t *len)
-{
-	struct bhnd_nvram_btxt	*btxt;
-	size_t			 limit;
-	int			 error;
-
-	btxt = (struct bhnd_nvram_btxt *)nv;
-
-	limit = *len;
-
-	/* Provide actual output size */
-	if ((error = bhnd_nvram_data_size(nv, len)))
-		return (error);
-
-	if (buf == NULL) {
-		return (0);
-	} else if (limit < *len) {
-		return (ENOMEM);
-	}	
-
-	/* Copy our internal representation to the output buffer */
-	if ((error = bhnd_nvram_io_read(btxt->data, 0x0, buf, *len)))
-		return (error);
-
-	/* Restore the original key=value format, rewriting all '\0'
-	 * key\0value delimiters back to '=' */
-	for (char *p = buf; (size_t)(p - (char *)buf) < *len; p++) {
-		if (*p == '\0')
-			*p = '=';
-	}
-
-	return (0);
-}
-
 static uint32_t
 bhnd_nvram_btxt_caps(struct bhnd_nvram_data *nv)
 {

Modified: head/sys/dev/bhnd/nvram/bhnd_nvram_data_sprom.c
==============================================================================
--- head/sys/dev/bhnd/nvram/bhnd_nvram_data_sprom.c	Mon Dec 19 20:31:27 2016	(r310296)
+++ head/sys/dev/bhnd/nvram/bhnd_nvram_data_sprom.c	Mon Dec 19 20:34:05 2016	(r310297)
@@ -49,8 +49,9 @@ __FBSDID("$FreeBSD$");
 #include <string.h>
 #endif /* _KERNEL */
 
-#include "bhnd_nvram_private.h"
+#include "bhnd_nvram_map.h"
 
+#include "bhnd_nvram_private.h"
 #include "bhnd_nvram_datavar.h"
 
 #include "bhnd_nvram_data_spromvar.h"
@@ -62,44 +63,45 @@ __FBSDID("$FreeBSD$");
  * used on Broadcom wireless and wired adapters, that provides a subset of the
  * variables defined by Broadcom SoC NVRAM formats.
  */
-BHND_NVRAM_DATA_CLASS_DEFN(sprom, "Broadcom SPROM",
-   sizeof(struct bhnd_nvram_sprom))
 
-static int	sprom_sort_idx(const void *lhs, const void *rhs);
+static const bhnd_sprom_layout  *bhnd_nvram_sprom_get_layout(uint8_t sromrev);
+
+static int			 bhnd_nvram_sprom_ident(
+				     struct bhnd_nvram_io *io,
+				     const bhnd_sprom_layout **ident,
+				     struct bhnd_nvram_io **shadow);
+
+static int			 bhnd_nvram_sprom_write_var(
+				     bhnd_sprom_opcode_state *state,
+				     bhnd_sprom_opcode_idx_entry *entry,
+				     bhnd_nvram_val *value,
+				     struct bhnd_nvram_io *io);
+
+static int			 bhnd_nvram_sprom_write_offset(
+				     const struct bhnd_nvram_vardefn *var,
+				     struct bhnd_nvram_io *data,
+				     bhnd_nvram_type type, size_t offset,
+				     uint32_t mask, int8_t shift,
+				     uint32_t value);
+
+static int			 bhnd_nvram_sprom_read_offset(
+				     const struct bhnd_nvram_vardefn *var,
+				     struct bhnd_nvram_io *data,
+				     bhnd_nvram_type type, size_t offset,
+				     uint32_t mask, int8_t shift,
+				     uint32_t *value);
 
-static int	sprom_opcode_state_init(struct sprom_opcode_state *state,
-		    const struct bhnd_sprom_layout *layout);
-static int	sprom_opcode_state_reset(struct sprom_opcode_state *state);
-static int	sprom_opcode_state_seek(struct sprom_opcode_state *state,
-		    struct sprom_opcode_idx *indexed);
-
-static int	sprom_opcode_next_var(struct sprom_opcode_state *state);
-static int	sprom_opcode_parse_var(struct sprom_opcode_state *state,
-		    struct sprom_opcode_idx *indexed);
-  
-static int	sprom_opcode_next_binding(struct sprom_opcode_state *state);
-
-static int	sprom_opcode_set_type(struct sprom_opcode_state *state,
-		    bhnd_nvram_type type);
-
-static int	sprom_opcode_set_var(struct sprom_opcode_state *state,
-		    size_t vid);
-static int	sprom_opcode_clear_var(struct sprom_opcode_state *state);
-static int	sprom_opcode_flush_bind(struct sprom_opcode_state *state);
-static int	sprom_opcode_read_opval32(struct sprom_opcode_state *state,
-		    uint8_t type, uint32_t *opval);
-static int	sprom_opcode_apply_scale(struct sprom_opcode_state *state,
-		    uint32_t *value);
-
-static int	sprom_opcode_step(struct sprom_opcode_state *state,
-		    uint8_t *opcode);
-
-#define	SPROM_OP_BAD(_state, _fmt, ...)					\
-	BHND_NV_LOG("bad encoding at %td: " _fmt,			\
-	    (_state)->input - (_state)->layout->bindings, ##__VA_ARGS__)
+static bool			 bhnd_sprom_is_external_immutable(
+				     const char *name);
 
-#define	SPROM_COOKIE_TO_NVRAM(_cookie)	\
-	bhnd_nvram_get_vardefn(((struct sprom_opcode_idx *)_cookie)->vid)
+BHND_NVRAM_DATA_CLASS_DEFN(sprom, "Broadcom SPROM",
+    BHND_NVRAM_DATA_CAP_DEVPATHS, sizeof(struct bhnd_nvram_sprom))
+
+#define	SPROM_COOKIE_TO_VID(_cookie)	\
+	(((struct bhnd_sprom_opcode_idx_entry *)(_cookie))->vid)
+
+#define	SPROM_COOKIE_TO_NVRAM_VAR(_cookie)	\
+	bhnd_nvram_get_vardefn(SPROM_COOKIE_TO_VID(_cookie))
 
 /**
  * Read the magic value from @p io, and verify that it matches
@@ -118,7 +120,7 @@ static int	sprom_opcode_step(struct spro
  */
 static int
 bhnd_nvram_sprom_check_magic(struct bhnd_nvram_io *io,
-    const struct bhnd_sprom_layout *layout, uint16_t *magic)
+    const bhnd_sprom_layout *layout, uint16_t *magic)
 {
 	int error;
 
@@ -162,7 +164,7 @@ bhnd_nvram_sprom_check_magic(struct bhnd
  */
 static int
 bhnd_nvram_sprom_ident(struct bhnd_nvram_io *io,
-    const struct bhnd_sprom_layout **ident, struct bhnd_nvram_io **shadow)
+    const bhnd_sprom_layout **ident, struct bhnd_nvram_io **shadow)
 {
 	struct bhnd_nvram_io	*buf;
 	uint8_t			 crc;
@@ -185,13 +187,13 @@ bhnd_nvram_sprom_ident(struct bhnd_nvram
 	/* We iterate the SPROM layouts smallest to largest, allowing us to
 	 * perform incremental checksum calculation */
 	for (size_t i = 0; i < bhnd_sprom_num_layouts; i++) {
-		const struct bhnd_sprom_layout	*layout;
-		void				*ptr;
-		size_t				 nbytes, nr;
-		uint16_t			 magic;
-		uint8_t				 srev;
-		bool				 crc_valid;
-		bool				 have_magic;
+		const bhnd_sprom_layout	*layout;
+		void			*ptr;
+		size_t			 nbytes, nr;
+		uint16_t		 magic;
+		uint8_t			 srev;

*** DIFF OUTPUT TRUNCATED AT 1000 LINES ***


More information about the svn-src-all mailing list