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 ***
_______________________________________________
svn-src-head@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to "svn-src-head-unsubscr...@freebsd.org"

Reply via email to