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"