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
This commit is contained in:
parent
3299d2687a
commit
378d13bcd3
@ -1236,6 +1236,7 @@ dev/bhnd/nvram/bhnd_nvram_data_bcm.c optional bhnd
|
||||
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
|
||||
|
@ -64,6 +64,54 @@ bhnd_nvram_data_class_desc(bhnd_nvram_data_class *cls)
|
||||
return (cls->desc);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
@ -292,51 +340,6 @@ bhnd_nvram_data_options(struct bhnd_nvram_data *nv)
|
||||
return (nv->cls->op_options(nv));
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
|
@ -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 bhnd_nvram_data *nv);
|
||||
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);
|
||||
|
||||
|
@ -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_io *io)
|
||||
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_data *nv)
|
||||
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)
|
||||
{
|
||||
|
@ -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_nvram_io *io)
|
||||
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_data *nv)
|
||||
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)
|
||||
static size_t
|
||||
bhnd_nvram_bcmraw_count(struct bhnd_nvram_data *nv)
|
||||
{
|
||||
return (bhnd_nvram_bcmraw_serialize(nv, NULL, size));
|
||||
}
|
||||
struct bhnd_nvram_bcmraw *bcm = (struct bhnd_nvram_bcmraw *)nv;
|
||||
|
||||
static int
|
||||
bhnd_nvram_bcmraw_serialize(struct bhnd_nvram_data *nv, void *buf, size_t *len)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
return (0);
|
||||
return (bcm->count);
|
||||
}
|
||||
|
||||
static uint32_t
|
||||
|
@ -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
|
||||
|
@ -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_io *io)
|
||||
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_nvram_data *nv)
|
||||
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)
|
||||
{
|
||||
|
File diff suppressed because it is too large
Load Diff
1366
sys/dev/bhnd/nvram/bhnd_nvram_data_sprom_subr.c
Normal file
1366
sys/dev/bhnd/nvram/bhnd_nvram_data_sprom_subr.c
Normal file
File diff suppressed because it is too large
Load Diff
@ -44,12 +44,43 @@
|
||||
#include "bhnd_nvram_io.h"
|
||||
|
||||
/** The maximum number of array elements encoded in a single SPROM variable */
|
||||
#define SPROM_ARRAY_MAXLEN 12
|
||||
#define BHND_SPROM_ARRAY_MAXLEN 12
|
||||
|
||||
typedef struct bhnd_sprom_opcode_state bhnd_sprom_opcode_state;
|
||||
typedef struct bhnd_sprom_opcode_bind bhnd_sprom_opcode_bind;
|
||||
typedef struct bhnd_sprom_opcode_var bhnd_sprom_opcode_var;
|
||||
typedef struct bhnd_sprom_opcode_idx_entry bhnd_sprom_opcode_idx_entry;
|
||||
|
||||
int bhnd_sprom_opcode_init(
|
||||
bhnd_sprom_opcode_state *state,
|
||||
const bhnd_sprom_layout *layout);
|
||||
void bhnd_sprom_opcode_fini(
|
||||
bhnd_sprom_opcode_state *state);
|
||||
|
||||
bhnd_sprom_opcode_idx_entry *bhnd_sprom_opcode_index_find(
|
||||
bhnd_sprom_opcode_state *state,
|
||||
const char *name);
|
||||
bhnd_sprom_opcode_idx_entry *bhnd_sprom_opcode_index_next(
|
||||
bhnd_sprom_opcode_state *state,
|
||||
bhnd_sprom_opcode_idx_entry *prev);
|
||||
|
||||
int bhnd_sprom_opcode_parse_var(
|
||||
bhnd_sprom_opcode_state *state,
|
||||
bhnd_sprom_opcode_idx_entry *entry);
|
||||
|
||||
int bhnd_sprom_opcode_seek(
|
||||
bhnd_sprom_opcode_state *state,
|
||||
bhnd_sprom_opcode_idx_entry *entry);
|
||||
int bhnd_sprom_opcode_next_binding(
|
||||
bhnd_sprom_opcode_state *state);
|
||||
int bhnd_sprom_opcode_apply_scale(
|
||||
bhnd_sprom_opcode_state *state,
|
||||
uint32_t *value);
|
||||
|
||||
/**
|
||||
* SPROM opcode per-bind evaluation state.
|
||||
*/
|
||||
struct sprom_opcode_bind {
|
||||
struct bhnd_sprom_opcode_bind {
|
||||
uint8_t count;
|
||||
uint32_t skip_in; /**< input element skips */
|
||||
bool skip_in_negative; /**< skip_in should be subtracted */
|
||||
@ -59,15 +90,15 @@ struct sprom_opcode_bind {
|
||||
/**
|
||||
* SPROM opcode per-variable evaluation state.
|
||||
*/
|
||||
struct sprom_opcode_var {
|
||||
uint8_t nelem; /**< variable array length */
|
||||
uint32_t mask; /**< current bind input mask */
|
||||
int8_t shift; /**< current bind input shift */
|
||||
bhnd_nvram_type base_type; /**< current bind input type */
|
||||
uint32_t scale; /**< current scale to apply to scaled encodings */
|
||||
struct sprom_opcode_bind bind; /**< current bind state */
|
||||
bool have_bind; /**< if bind state is defined */
|
||||
size_t bind_total; /**< total count of bind operations performed */
|
||||
struct bhnd_sprom_opcode_var {
|
||||
uint8_t nelem; /**< variable array length */
|
||||
uint32_t mask; /**< current bind input mask */
|
||||
int8_t shift; /**< current bind input shift */
|
||||
bhnd_nvram_type base_type; /**< current bind input type */
|
||||
uint32_t scale; /**< current scale to apply to scaled encodings */
|
||||
bhnd_sprom_opcode_bind bind; /**< current bind state */
|
||||
bool have_bind; /**< if bind state is defined */
|
||||
size_t bind_total; /**< total count of bind operations performed */
|
||||
};
|
||||
|
||||
/**
|
||||
@ -80,13 +111,16 @@ typedef enum {
|
||||
SPROM_OPCODE_VAR_STATE_NONE = 1, /**< no variable entry available */
|
||||
SPROM_OPCODE_VAR_STATE_OPEN = 2, /**< currently parsing a variable entry */
|
||||
SPROM_OPCODE_VAR_STATE_DONE = 3 /**< full variable entry has been parsed */
|
||||
} sprom_opcode_var_state;
|
||||
} bhnd_sprom_opcode_var_state;
|
||||
|
||||
/**
|
||||
* SPROM opcode evaluation state
|
||||
*/
|
||||
struct sprom_opcode_state {
|
||||
const struct bhnd_sprom_layout *layout; /**< SPROM layout */
|
||||
struct bhnd_sprom_opcode_state {
|
||||
const bhnd_sprom_layout *layout; /**< SPROM layout */
|
||||
|
||||
bhnd_sprom_opcode_idx_entry *idx; /**< variable index (NULL during initialization) */
|
||||
size_t num_idx; /**< variable index entry count */
|
||||
|
||||
/** Current SPROM revision range */
|
||||
bitstr_t bit_decl(revs, SPROM_OP_REV_MAX);
|
||||
@ -98,14 +132,14 @@ struct sprom_opcode_state {
|
||||
size_t vid; /**< Variable ID */
|
||||
|
||||
/* State reset after end of each variable definition */
|
||||
struct sprom_opcode_var var; /**< variable record (if any) */
|
||||
sprom_opcode_var_state var_state; /**< variable record state */
|
||||
bhnd_sprom_opcode_var var; /**< variable record (if any) */
|
||||
bhnd_sprom_opcode_var_state var_state; /**< variable record state */
|
||||
};
|
||||
|
||||
/**
|
||||
* SPROM opcode variable index entry
|
||||
*/
|
||||
struct sprom_opcode_idx {
|
||||
struct bhnd_sprom_opcode_idx_entry {
|
||||
uint16_t vid; /**< SPROM variable ID */
|
||||
uint16_t offset; /**< SPROM input offset */
|
||||
uint16_t opcodes; /**< SPROM opcode offset */
|
||||
@ -118,33 +152,23 @@ struct sprom_opcode_idx {
|
||||
* variable.
|
||||
*/
|
||||
union bhnd_nvram_sprom_storage {
|
||||
uint8_t u8[SPROM_ARRAY_MAXLEN];
|
||||
uint16_t u16[SPROM_ARRAY_MAXLEN];
|
||||
uint32_t u32[SPROM_ARRAY_MAXLEN];
|
||||
int8_t i8[SPROM_ARRAY_MAXLEN];
|
||||
int16_t i16[SPROM_ARRAY_MAXLEN];
|
||||
int32_t i32[SPROM_ARRAY_MAXLEN];
|
||||
char ch[SPROM_ARRAY_MAXLEN];
|
||||
};
|
||||
|
||||
/**
|
||||
* SPROM common integer value representation.
|
||||
*/
|
||||
union bhnd_nvram_sprom_intv {
|
||||
uint32_t u32;
|
||||
int32_t s32;
|
||||
uint8_t u8[BHND_SPROM_ARRAY_MAXLEN];
|
||||
uint16_t u16[BHND_SPROM_ARRAY_MAXLEN];
|
||||
uint32_t u32[BHND_SPROM_ARRAY_MAXLEN];
|
||||
int8_t i8[BHND_SPROM_ARRAY_MAXLEN];
|
||||
int16_t i16[BHND_SPROM_ARRAY_MAXLEN];
|
||||
int32_t i32[BHND_SPROM_ARRAY_MAXLEN];
|
||||
char ch[BHND_SPROM_ARRAY_MAXLEN];
|
||||
};
|
||||
|
||||
/**
|
||||
* SPROM data class instance state.
|
||||
*/
|
||||
struct bhnd_nvram_sprom {
|
||||
struct bhnd_nvram_data nv; /**< common instance state */
|
||||
struct bhnd_nvram_io *data; /**< backing SPROM image */
|
||||
const struct bhnd_sprom_layout *layout; /**< layout definition */
|
||||
struct sprom_opcode_state state; /**< opcode eval state */
|
||||
struct sprom_opcode_idx *idx; /**< opcode index entries */
|
||||
size_t num_idx; /**< opcode index entry count */
|
||||
struct bhnd_nvram_data nv; /**< common instance state */
|
||||
struct bhnd_nvram_io *data; /**< backing SPROM image */
|
||||
const bhnd_sprom_layout *layout; /**< layout definition */
|
||||
bhnd_sprom_opcode_state state; /**< opcode eval state */
|
||||
};
|
||||
|
||||
#endif /* _BHND_NVRAM_BHND_NVRAM_SPROMVAR_H_ */
|
||||
|
@ -62,7 +62,8 @@ struct bhnd_nvram_tlv {
|
||||
size_t count; /**< variable count */
|
||||
};
|
||||
|
||||
BHND_NVRAM_DATA_CLASS_DEFN(tlv, "WGT634U", sizeof(struct bhnd_nvram_tlv))
|
||||
BHND_NVRAM_DATA_CLASS_DEFN(tlv, "WGT634U", BHND_NVRAM_DATA_CAP_DEVPATHS,
|
||||
sizeof(struct bhnd_nvram_tlv))
|
||||
|
||||
/** Minimal TLV_ENV record header */
|
||||
struct bhnd_nvram_tlv_env_hdr {
|
||||
@ -163,6 +164,123 @@ bhnd_nvram_tlv_probe(struct bhnd_nvram_io *io)
|
||||
return (BHND_NVRAM_DATA_PROBE_DEFAULT);
|
||||
}
|
||||
|
||||
static int
|
||||
bhnd_nvram_tlv_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) {
|
||||
struct bhnd_nvram_tlv_env env;
|
||||
const char *name;
|
||||
uint8_t *p;
|
||||
size_t name_len, value_len;
|
||||
size_t rec_size;
|
||||
|
||||
env.hdr.tag = NVRAM_TLV_TYPE_ENV;
|
||||
env.hdr.size = sizeof(env.flags);
|
||||
env.flags = 0x0;
|
||||
|
||||
/* Fetch name value and add to record length */
|
||||
name = bhnd_nvram_prop_name(prop);
|
||||
name_len = strlen(name) + 1 /* '=' */;
|
||||
|
||||
if (UINT8_MAX - env.hdr.size < name_len) {
|
||||
BHND_NV_LOG("%s name exceeds maximum TLV record "
|
||||
"length\n", name);
|
||||
return (EFTYPE); /* would overflow TLV size */
|
||||
}
|
||||
|
||||
env.hdr.size += name_len;
|
||||
|
||||
/* Add string value to record length */
|
||||
error = bhnd_nvram_prop_encode(prop, NULL, &value_len,
|
||||
BHND_NVRAM_TYPE_STRING);
|
||||
if (error) {
|
||||
BHND_NV_LOG("error serializing %s to required type "
|
||||
"%s: %d\n", name,
|
||||
bhnd_nvram_type_name(BHND_NVRAM_TYPE_STRING),
|
||||
error);
|
||||
return (error);
|
||||
}
|
||||
|
||||
if (UINT8_MAX - env.hdr.size < value_len) {
|
||||
BHND_NV_LOG("%s value exceeds maximum TLV record "
|
||||
"length\n", name);
|
||||
return (EFTYPE); /* would overflow TLV size */
|
||||
}
|
||||
|
||||
env.hdr.size += value_len;
|
||||
|
||||
/* Calculate total record size */
|
||||
rec_size = sizeof(env.hdr) + env.hdr.size;
|
||||
if (SIZE_MAX - nbytes < rec_size)
|
||||
return (EFTYPE); /* would overflow size_t */
|
||||
|
||||
/* Calculate our output pointer */
|
||||
if (nbytes > limit || limit - nbytes < rec_size) {
|
||||
/* buffer is full; cannot write */
|
||||
p = NULL;
|
||||
} else {
|
||||
p = (uint8_t *)outp + nbytes;
|
||||
}
|
||||
|
||||
/* Write to output */
|
||||
if (p != NULL) {
|
||||
memcpy(p, &env, sizeof(env));
|
||||
p += sizeof(env);
|
||||
|
||||
memcpy(p, name, name_len - 1);
|
||||
p[name_len - 1] = '=';
|
||||
p += name_len;
|
||||
|
||||
error = bhnd_nvram_prop_encode(prop, p, &value_len,
|
||||
BHND_NVRAM_TYPE_STRING);
|
||||
if (error) {
|
||||
BHND_NV_LOG("error serializing %s to required "
|
||||
"type %s: %d\n", name,
|
||||
bhnd_nvram_type_name(
|
||||
BHND_NVRAM_TYPE_STRING),
|
||||
error);
|
||||
return (error);
|
||||
}
|
||||
}
|
||||
|
||||
nbytes += rec_size;
|
||||
}
|
||||
|
||||
/* Write terminating END record */
|
||||
if (limit > nbytes)
|
||||
*((uint8_t *)outp + nbytes) = NVRAM_TLV_TYPE_END;
|
||||
|
||||
if (nbytes == SIZE_MAX)
|
||||
return (EFTYPE); /* would overflow size_t */
|
||||
nbytes++;
|
||||
|
||||
/* Provide required length */
|
||||
*olen = nbytes;
|
||||
if (limit < *olen) {
|
||||
if (outp == NULL)
|
||||
return (0);
|
||||
|
||||
return (ENOMEM);
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize @p tlv with the provided NVRAM TLV data mapped by @p src.
|
||||
*
|
||||
@ -256,91 +374,13 @@ bhnd_nvram_tlv_count(struct bhnd_nvram_data *nv)
|
||||
return (tlv->count);
|
||||
}
|
||||
|
||||
|
||||
static bhnd_nvram_plist *
|
||||
bhnd_nvram_tlv_options(struct bhnd_nvram_data *nv)
|
||||
{
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
static int
|
||||
bhnd_nvram_tlv_size(struct bhnd_nvram_data *nv, size_t *size)
|
||||
{
|
||||
/* Let the serialization implementation calculate the length */
|
||||
return (bhnd_nvram_data_serialize(nv, NULL, size));
|
||||
}
|
||||
|
||||
static int
|
||||
bhnd_nvram_tlv_serialize(struct bhnd_nvram_data *nv, void *buf, size_t *len)
|
||||
{
|
||||
struct bhnd_nvram_tlv *tlv;
|
||||
size_t limit;
|
||||
size_t next;
|
||||
uint8_t tag;
|
||||
int error;
|
||||
|
||||
tlv = (struct bhnd_nvram_tlv *)nv;
|
||||
|
||||
/* Save the buffer capacity */
|
||||
if (buf == NULL)
|
||||
limit = 0;
|
||||
else
|
||||
limit = *len;
|
||||
|
||||
/* Write all of our TLV records to the output buffer (or just
|
||||
* calculate the buffer size that would be required) */
|
||||
next = 0;
|
||||
do {
|
||||
struct bhnd_nvram_tlv_env *env;
|
||||
uint8_t *p;
|
||||
size_t name_len;
|
||||
size_t rec_offset, rec_size;
|
||||
|
||||
/* Parse the TLV record */
|
||||
error = bhnd_nvram_tlv_next_record(tlv->data, &next,
|
||||
&rec_offset, &tag);
|
||||
if (error)
|
||||
return (error);
|
||||
|
||||
rec_size = next - rec_offset;
|
||||
|
||||
/* Calculate our output pointer */
|
||||
if (rec_offset > limit || limit - rec_offset < rec_size) {
|
||||
/* buffer is full; cannot write */
|
||||
p = NULL;
|
||||
} else {
|
||||
p = (uint8_t *)buf + rec_offset;
|
||||
}
|
||||
|
||||
/* If not writing, nothing further to do for this record */
|
||||
if (p == NULL)
|
||||
continue;
|
||||
|
||||
/* Copy to the output buffer */
|
||||
error = bhnd_nvram_io_read(tlv->data, rec_offset, p, rec_size);
|
||||
if (error)
|
||||
return (error);
|
||||
|
||||
/* All further processing is TLV_ENV-specific */
|
||||
if (tag != NVRAM_TLV_TYPE_ENV)
|
||||
continue;
|
||||
|
||||
/* Restore the original key=value format, rewriting '\0'
|
||||
* delimiter back to '=' */
|
||||
env = (struct bhnd_nvram_tlv_env *)p;
|
||||
name_len = strlen(env->envp); /* skip variable name */
|
||||
*(env->envp + name_len) = '='; /* set '=' */
|
||||
} while (tag != NVRAM_TLV_TYPE_END);
|
||||
|
||||
/* The 'next' offset should now point at EOF, and represents
|
||||
* the total length of the serialized output. */
|
||||
*len = next;
|
||||
|
||||
if (buf != NULL && limit < *len)
|
||||
return (ENOMEM);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static uint32_t
|
||||
bhnd_nvram_tlv_caps(struct bhnd_nvram_data *nv)
|
||||
{
|
||||
|
@ -55,6 +55,13 @@ int bhnd_nvram_data_generic_rp_copy_val(
|
||||
/** @see bhnd_nvram_data_probe() */
|
||||
typedef int (bhnd_nvram_data_op_probe)(struct bhnd_nvram_io *io);
|
||||
|
||||
/** @see bhnd_nvram_data_serialize() */
|
||||
typedef int (bhnd_nvram_data_op_serialize)(
|
||||
bhnd_nvram_data_class *cls,
|
||||
bhnd_nvram_plist *props,
|
||||
bhnd_nvram_plist *options, void *outp,
|
||||
size_t *olen);
|
||||
|
||||
/** @see bhnd_nvram_data_new() */
|
||||
typedef int (bhnd_nvram_data_op_new)(struct bhnd_nvram_data *nv,
|
||||
struct bhnd_nvram_io *io);
|
||||
@ -66,15 +73,6 @@ typedef void (bhnd_nvram_data_op_free)(struct bhnd_nvram_data *nv);
|
||||
/** @see bhnd_nvram_data_count() */
|
||||
typedef size_t (bhnd_nvram_data_op_count)(struct bhnd_nvram_data *nv);
|
||||
|
||||
/** @see bhnd_nvram_data_size() */
|
||||
typedef int (bhnd_nvram_data_op_size)(struct bhnd_nvram_data *nv,
|
||||
size_t *len);
|
||||
|
||||
/** @see bhnd_nvram_data_serialize() */
|
||||
typedef int (bhnd_nvram_data_op_serialize)(
|
||||
struct bhnd_nvram_data *nv, void *buf,
|
||||
size_t *len);
|
||||
|
||||
/** @see bhnd_nvram_data_options() */
|
||||
typedef bhnd_nvram_plist*(bhnd_nvram_data_op_options)(
|
||||
struct bhnd_nvram_data *nv);
|
||||
@ -129,14 +127,14 @@ typedef int (bhnd_nvram_data_op_filter_unsetvar)(
|
||||
*/
|
||||
struct bhnd_nvram_data_class {
|
||||
const char *desc; /**< description */
|
||||
uint32_t caps; /**< capabilities (BHND_NVRAM_DATA_CAP_*) */
|
||||
size_t size; /**< instance size */
|
||||
|
||||
bhnd_nvram_data_op_probe *op_probe;
|
||||
bhnd_nvram_data_op_serialize *op_serialize;
|
||||
bhnd_nvram_data_op_new *op_new;
|
||||
bhnd_nvram_data_op_free *op_free;
|
||||
bhnd_nvram_data_op_count *op_count;
|
||||
bhnd_nvram_data_op_size *op_size;
|
||||
bhnd_nvram_data_op_serialize *op_serialize;
|
||||
bhnd_nvram_data_op_options *op_options;
|
||||
bhnd_nvram_data_op_caps *op_caps;
|
||||
bhnd_nvram_data_op_next *op_next;
|
||||
@ -186,11 +184,10 @@ struct bhnd_nvram_data {
|
||||
*/
|
||||
#define BHND_NVRAM_DATA_CLASS_ITER_METHODS(_cname, _macro) \
|
||||
_macro(_cname, probe) \
|
||||
_macro(_cname, serialize) \
|
||||
_macro(_cname, new) \
|
||||
_macro(_cname, free) \
|
||||
_macro(_cname, count) \
|
||||
_macro(_cname, size) \
|
||||
_macro(_cname, serialize) \
|
||||
_macro(_cname, options) \
|
||||
_macro(_cname, caps) \
|
||||
_macro(_cname, next) \
|
||||
@ -207,12 +204,13 @@ struct bhnd_nvram_data {
|
||||
* Define a bhnd_nvram_data_class with class name @p _n and description
|
||||
* @p _desc, and register with bhnd_nvram_data_class_set.
|
||||
*/
|
||||
#define BHND_NVRAM_DATA_CLASS_DEFN(_cname, _desc, _size) \
|
||||
#define BHND_NVRAM_DATA_CLASS_DEFN(_cname, _desc, _caps, _size) \
|
||||
BHND_NVRAM_DATA_CLASS_ITER_METHODS(_cname, \
|
||||
BHND_NVRAM_DATA_CLASS_DECL_METHOD) \
|
||||
\
|
||||
struct bhnd_nvram_data_class bhnd_nvram_## _cname ## _class = { \
|
||||
.desc = (_desc), \
|
||||
.caps = (_caps), \
|
||||
.size = (_size), \
|
||||
BHND_NVRAM_DATA_CLASS_ITER_METHODS(_cname, \
|
||||
BHND_NVRAM_DATA_CLASS_ASSIGN_METHOD) \
|
||||
|
@ -314,7 +314,7 @@ struct bhnd_nvram_vardefn {
|
||||
bhnd_nvram_type type; /**< variable type */
|
||||
uint8_t nelem; /**< element count, or 1 if not
|
||||
an array-typed variable */
|
||||
const bhnd_nvram_val_fmt *fmt; /**< value format, or NULL */
|
||||
const bhnd_nvram_val_fmt *fmt; /**< value format */
|
||||
uint32_t flags; /**< flags (BHND_NVRAM_VF_*) */
|
||||
};
|
||||
|
||||
@ -327,19 +327,20 @@ extern const size_t bhnd_nvram_num_vardefns;
|
||||
/**
|
||||
* SPROM layout descriptor.
|
||||
*/
|
||||
struct bhnd_sprom_layout {
|
||||
typedef struct bhnd_sprom_layout {
|
||||
size_t size; /**< SPROM image size, in bytes */
|
||||
uint8_t rev; /**< SPROM revision */
|
||||
uint8_t flags; /**< layout flags (SPROM_LAYOUT_*) */
|
||||
size_t srev_offset; /**< offset to SROM revision */
|
||||
size_t magic_offset; /**< offset to magic value */
|
||||
uint16_t magic_value; /**< expected magic value */
|
||||
size_t crc_offset; /**< offset to crc8 value */
|
||||
const uint8_t *bindings; /**< SPROM binding opcode table */
|
||||
size_t bindings_size; /**< SPROM binding opcode table size */
|
||||
uint16_t num_vars; /**< total number of variables defined
|
||||
for this layout by the binding
|
||||
table */
|
||||
};
|
||||
} bhnd_sprom_layout;
|
||||
|
||||
/*
|
||||
* SPROM layout descriptions generated from nvram_map.
|
||||
|
@ -997,6 +997,90 @@ bhnd_nvram_store_export(struct bhnd_nvram_store *sc, const char *path,
|
||||
return (error);
|
||||
}
|
||||
|
||||
/**
|
||||
* Encode all NVRAM properties at @p path, using the @p store's current NVRAM
|
||||
* data format.
|
||||
*
|
||||
* @param sc The NVRAM store instance.
|
||||
* @param path The NVRAM path to export, or NULL to select the root
|
||||
* path.
|
||||
* @param[out] data On success, will be set to the newly serialized value.
|
||||
* The caller is responsible for freeing this value
|
||||
* via bhnd_nvram_io_free().
|
||||
* @param flags Export flags. See BHND_NVSTORE_EXPORT_*.
|
||||
*
|
||||
* @retval 0 success
|
||||
* @retval EINVAL If @p flags is invalid.
|
||||
* @retval ENOENT The requested path was not found.
|
||||
* @retval ENOMEM If allocation fails.
|
||||
* @retval non-zero If serialization of @p path otherwise fails, a regular
|
||||
* unix error code will be returned.
|
||||
*/
|
||||
int
|
||||
bhnd_nvram_store_serialize(struct bhnd_nvram_store *sc, const char *path,
|
||||
struct bhnd_nvram_io **data, uint32_t flags)
|
||||
{
|
||||
bhnd_nvram_plist *props;
|
||||
bhnd_nvram_plist *options;
|
||||
bhnd_nvram_data_class *cls;
|
||||
struct bhnd_nvram_io *io;
|
||||
void *outp;
|
||||
size_t olen;
|
||||
int error;
|
||||
|
||||
props = NULL;
|
||||
options = NULL;
|
||||
io = NULL;
|
||||
|
||||
/* Perform requested export */
|
||||
error = bhnd_nvram_store_export(sc, path, &cls, &props, &options,
|
||||
flags);
|
||||
if (error)
|
||||
return (error);
|
||||
|
||||
/* Determine serialized size */
|
||||
error = bhnd_nvram_data_serialize(cls, props, options, NULL, &olen);
|
||||
if (error)
|
||||
goto failed;
|
||||
|
||||
/* Allocate output buffer */
|
||||
if ((io = bhnd_nvram_iobuf_empty(olen, olen)) == NULL) {
|
||||
error = ENOMEM;
|
||||
goto failed;
|
||||
}
|
||||
|
||||
/* Fetch write pointer */
|
||||
if ((error = bhnd_nvram_io_write_ptr(io, 0, &outp, olen, NULL)))
|
||||
goto failed;
|
||||
|
||||
/* Perform serialization */
|
||||
error = bhnd_nvram_data_serialize(cls, props, options, outp, &olen);
|
||||
if (error)
|
||||
goto failed;
|
||||
|
||||
if ((error = bhnd_nvram_io_setsize(io, olen)))
|
||||
goto failed;
|
||||
|
||||
/* Success */
|
||||
bhnd_nvram_plist_release(props);
|
||||
bhnd_nvram_plist_release(options);
|
||||
|
||||
*data = io;
|
||||
return (0);
|
||||
|
||||
failed:
|
||||
if (props != NULL)
|
||||
bhnd_nvram_plist_release(props);
|
||||
|
||||
if (options != NULL)
|
||||
bhnd_nvram_plist_release(options);
|
||||
|
||||
if (io != NULL)
|
||||
bhnd_nvram_io_free(io);
|
||||
|
||||
return (error);
|
||||
}
|
||||
|
||||
/**
|
||||
* Read an NVRAM variable.
|
||||
*
|
||||
|
@ -76,6 +76,9 @@ int bhnd_nvram_store_export(struct bhnd_nvram_store *store,
|
||||
bhnd_nvram_plist **props, bhnd_nvram_plist **options,
|
||||
uint32_t flags);
|
||||
|
||||
int bhnd_nvram_store_serialize(struct bhnd_nvram_store *store,
|
||||
const char *path, struct bhnd_nvram_io **data, uint32_t flags);
|
||||
|
||||
int bhnd_nvram_store_getvar(struct bhnd_nvram_store *sc, const char *name,
|
||||
void *outp, size_t *olen, bhnd_nvram_type otype);
|
||||
int bhnd_nvram_store_setvar(struct bhnd_nvram_store *sc, const char *name,
|
||||
|
@ -253,14 +253,19 @@ function main(_i) {
|
||||
# Value Formats
|
||||
Fmt = class_new("Fmt")
|
||||
class_add_prop(Fmt, p_name, "name")
|
||||
class_add_prop(Fmt, p_symbol, "const")
|
||||
class_add_prop(Fmt, p_symbol, "symbol")
|
||||
class_add_prop(Fmt, p_array_fmt, "array_fmt")
|
||||
|
||||
FmtHex = fmt_new("hex", "bhnd_nvram_val_bcm_hex_fmt")
|
||||
FmtDec = fmt_new("decimal", "bhnd_nvram_val_bcm_decimal_fmt")
|
||||
FmtMAC = fmt_new("macaddr", "bhnd_nvram_val_bcm_macaddr_fmt")
|
||||
FmtLEDDC = fmt_new("leddc", "bhnd_nvram_val_bcm_leddc_fmt")
|
||||
FmtCharArray = fmt_new("char_array", "bhnd_nvram_val_char_array_fmt")
|
||||
FmtChar = fmt_new("char", "bhnd_nvram_val_char_array_fmt",
|
||||
FmtCharArray)
|
||||
FmtStr = fmt_new("string", "bhnd_nvram_val_bcm_string_fmt")
|
||||
|
||||
# User-specifiable value formats
|
||||
ValueFormats = map_new()
|
||||
map_set(ValueFormats, get(FmtHex, p_name), FmtHex)
|
||||
map_set(ValueFormats, get(FmtDec, p_name), FmtDec)
|
||||
@ -315,7 +320,7 @@ function main(_i) {
|
||||
"BHND_NVRAM_TYPE_INT32_ARRAY", FmtDec, UInt32Max, 6, 22)
|
||||
|
||||
Char = type_new("char", 1, 1, "BHND_NVRAM_TYPE_CHAR",
|
||||
"BHND_NVRAM_TYPE_CHAR_ARRAY", FmtStr, UInt8Max, 8, 24)
|
||||
"BHND_NVRAM_TYPE_CHAR_ARRAY", FmtChar, UInt8Max, 8, 24)
|
||||
|
||||
BaseTypes = map_new()
|
||||
map_set(BaseTypes, get(UInt8, p_name), UInt8)
|
||||
@ -634,7 +639,7 @@ function write_data_nvram_vardefn(v, _desc, _help, _type, _fmt) {
|
||||
# Write a top-level bhnd_sprom_layout entry for the given revision
|
||||
# and layout definition
|
||||
function write_data_srom_layout(layout, revision, _flags, _size,
|
||||
_sromcrc, _crc_seg,
|
||||
_sromcrc, _crc_seg, _crc_off,
|
||||
_sromsig, _sig_seg, _sig_offset, _sig_value,
|
||||
_sromrev, _rev_seg, _rev_off,
|
||||
_num_vars)
|
||||
@ -648,7 +653,8 @@ function write_data_srom_layout(layout, revision, _flags, _size,
|
||||
"cannot compute total size")
|
||||
} else {
|
||||
_crc_seg = srom_entry_get_single_segment(_sromcrc)
|
||||
_size = get(_crc_seg, p_offset)
|
||||
_crc_off = get(_crc_seg, p_offset)
|
||||
_size = _crc_off
|
||||
_size += get(get(_crc_seg, p_type), p_width)
|
||||
}
|
||||
|
||||
@ -703,6 +709,8 @@ function write_data_srom_layout(layout, revision, _flags, _size,
|
||||
emit(".magic_value = 0,\n")
|
||||
}
|
||||
|
||||
emit(".crc_offset = " _crc_off ",\n")
|
||||
|
||||
emit(".bindings = " srom_layout_get_variable_name(layout) ",\n")
|
||||
emit(".bindings_size = nitems(" \
|
||||
srom_layout_get_variable_name(layout) "),\n")
|
||||
@ -1741,6 +1749,9 @@ function class_has_prop_id(class, prop_id, _super) {
|
||||
if (class == null)
|
||||
return (0)
|
||||
|
||||
if (prop_id == null)
|
||||
return (0)
|
||||
|
||||
# Check class<->prop cache
|
||||
if ((class, prop_id) in _g_class_prop_cache)
|
||||
return (1)
|
||||
@ -2538,9 +2549,17 @@ function type_get_base(type) {
|
||||
}
|
||||
|
||||
# Return the default fmt for a given type instance
|
||||
function type_get_default_fmt(type, _base) {
|
||||
function type_get_default_fmt(type, _base, _fmt, _array_fmt) {
|
||||
_base = type_get_base(type)
|
||||
return (get(_base, p_default_fmt))
|
||||
_fmt = get(_base, p_default_fmt)
|
||||
|
||||
if (obj_is_instanceof(type, ArrayType)) {
|
||||
_array_fmt = get(_fmt, p_array_fmt)
|
||||
if (_array_fmt != null)
|
||||
_fmt = _array_fmt
|
||||
}
|
||||
|
||||
return (_fmt)
|
||||
}
|
||||
|
||||
# Return a string representation of the given type
|
||||
@ -2641,11 +2660,14 @@ function type_named(name, _n, _type) {
|
||||
}
|
||||
|
||||
# Create a new Fmt instance
|
||||
function fmt_new(name, symbol, _obj) {
|
||||
function fmt_new(name, symbol, array_fmt, _obj) {
|
||||
_obj = obj_new(Fmt)
|
||||
set(_obj, p_name, name)
|
||||
set(_obj, p_symbol, symbol)
|
||||
|
||||
if (array_fmt != null)
|
||||
set(_obj, p_array_fmt, array_fmt)
|
||||
|
||||
return (_obj)
|
||||
}
|
||||
|
||||
|
@ -32,6 +32,7 @@ SRCS+= bhnd_nvram_data.c \
|
||||
bhnd_nvram_data_bcmraw.c \
|
||||
bhnd_nvram_data_btxt.c \
|
||||
bhnd_nvram_data_sprom.c \
|
||||
bhnd_nvram_data_sprom_subr.c \
|
||||
bhnd_nvram_data_tlv.c \
|
||||
bhnd_nvram_io.c \
|
||||
bhnd_nvram_iobuf.c \
|
||||
|
Loading…
Reference in New Issue
Block a user