bhnd(4): support direct conversion of bhnd_nvram_val
This adds support for bhnd_nvram_val_convert_init() and bhnd_nvram_val_convert_new(), which may be used to perform value format-aware encoding of an NVRAM value to a new target format/type. This will be used to simplify converting to/from serialized format-specific NVRAM value representations to common external representations. Approved by: adrian (mentor) Differential Revision: https://reviews.freebsd.org/D8757
This commit is contained in:
parent
eb68614970
commit
9be0790d19
@ -1247,6 +1247,7 @@ dev/bhnd/nvram/bhnd_nvram_subr.c optional bhnd
|
||||
dev/bhnd/nvram/bhnd_nvram_value.c optional bhnd
|
||||
dev/bhnd/nvram/bhnd_nvram_value_fmts.c optional bhnd
|
||||
dev/bhnd/nvram/bhnd_nvram_value_prf.c optional bhnd
|
||||
dev/bhnd/nvram/bhnd_nvram_value_subr.c optional bhnd
|
||||
dev/bhnd/nvram/bhnd_sprom.c optional bhnd
|
||||
dev/bhnd/siba/siba.c optional siba bhnd
|
||||
dev/bhnd/siba/siba_bhndb.c optional siba bhnd bhndb
|
||||
|
@ -111,14 +111,16 @@ typedef enum {
|
||||
NUL-terminated strings */
|
||||
} bhnd_nvram_type;
|
||||
|
||||
const char *bhnd_nvram_string_array_next(const char *inp, size_t ilen,
|
||||
const char *prev);
|
||||
|
||||
bool bhnd_nvram_is_signed_type(bhnd_nvram_type type);
|
||||
bool bhnd_nvram_is_unsigned_type(bhnd_nvram_type type);
|
||||
bool bhnd_nvram_is_int_type(bhnd_nvram_type type);
|
||||
bool bhnd_nvram_is_array_type(bhnd_nvram_type type);
|
||||
bhnd_nvram_type bhnd_nvram_base_type(bhnd_nvram_type type);
|
||||
const char *bhnd_nvram_type_name(bhnd_nvram_type type);
|
||||
size_t bhnd_nvram_type_width(bhnd_nvram_type type);
|
||||
size_t bhnd_nvram_type_host_align(bhnd_nvram_type type);
|
||||
|
||||
const char *bhnd_nvram_string_array_next(const char *inp, size_t ilen,
|
||||
const char *prev, size_t *olen);
|
||||
|
||||
#endif /* _BHND_NVRAM_BHND_NVRAM_H_ */
|
||||
|
@ -647,10 +647,8 @@ bhnd_nvram_bcm_getvar_ptr(struct bhnd_nvram_data *nv, void *cookiep,
|
||||
|
||||
/* Handle header variables */
|
||||
if ((hvar = bhnd_nvram_bcm_to_hdrvar(bcm, cookiep)) != NULL) {
|
||||
BHND_NV_ASSERT(
|
||||
hvar->len % bhnd_nvram_value_size(hvar->type, NULL, 0,
|
||||
hvar->nelem) == 0,
|
||||
("length is not aligned to type width"));
|
||||
BHND_NV_ASSERT(bhnd_nvram_value_check_aligned(&hvar->value,
|
||||
hvar->len, hvar->type) == 0, ("value misaligned"));
|
||||
|
||||
*type = hvar->type;
|
||||
*len = hvar->len;
|
||||
|
@ -597,7 +597,7 @@ bhnd_nvram_sprom_read_offset(struct bhnd_nvram_sprom *sp,
|
||||
} sp_value;
|
||||
|
||||
/* Determine type width */
|
||||
sp_width = bhnd_nvram_value_size(type, NULL, 0, 1);
|
||||
sp_width = bhnd_nvram_type_width(type);
|
||||
if (sp_width == 0) {
|
||||
/* Variable-width types are unsupported */
|
||||
BHND_NV_LOG("invalid %s SPROM offset type %d\n", var->name,
|
||||
@ -716,7 +716,7 @@ bhnd_nvram_sprom_getvar(struct bhnd_nvram_data *nv, void *cookiep, void *buf,
|
||||
var_btype = bhnd_nvram_base_type(var->type);
|
||||
|
||||
/* Calculate total byte length of the native encoding */
|
||||
if ((iwidth = bhnd_nvram_value_size(var_btype, NULL, 0, 1)) == 0) {
|
||||
if ((iwidth = bhnd_nvram_value_size(NULL, 0, var_btype, 1)) == 0) {
|
||||
/* SPROM does not use (and we do not support) decoding of
|
||||
* variable-width data types */
|
||||
BHND_NV_LOG("invalid SPROM data type: %d", var->type);
|
||||
@ -1219,7 +1219,7 @@ sprom_opcode_set_type(struct sprom_opcode_state *state, bhnd_nvram_type type)
|
||||
}
|
||||
|
||||
/* Fetch type width for use as our scale value */
|
||||
width = bhnd_nvram_value_size(type, NULL, 0, 1);
|
||||
width = bhnd_nvram_type_width(type);
|
||||
if (width == 0) {
|
||||
SPROM_OP_BAD(state, "unsupported variable-width type: %d\n",
|
||||
type);
|
||||
|
@ -167,11 +167,15 @@ int bhnd_nvram_value_coerce(const void *inp,
|
||||
void *outp, size_t *olen,
|
||||
bhnd_nvram_type otype);
|
||||
|
||||
int bhnd_nvram_value_nelem(bhnd_nvram_type type,
|
||||
const void *data, size_t len,
|
||||
int bhnd_nvram_value_check_aligned(const void *inp,
|
||||
size_t ilen, bhnd_nvram_type itype);
|
||||
|
||||
int bhnd_nvram_value_nelem(const void *inp,
|
||||
size_t ilen, bhnd_nvram_type itype,
|
||||
size_t *nelem);
|
||||
size_t bhnd_nvram_value_size(bhnd_nvram_type type,
|
||||
const void *data, size_t nbytes,
|
||||
|
||||
size_t bhnd_nvram_value_size(const void *inp,
|
||||
size_t ilen, bhnd_nvram_type itype,
|
||||
size_t nelem);
|
||||
|
||||
int bhnd_nvram_value_printf(const char *fmt,
|
||||
@ -183,6 +187,10 @@ int bhnd_nvram_value_vprintf(const char *fmt,
|
||||
bhnd_nvram_type itype, char *outp,
|
||||
size_t *olen, va_list ap);
|
||||
|
||||
const void *bhnd_nvram_value_array_next(const void *inp,
|
||||
size_t ilen, bhnd_nvram_type itype,
|
||||
const void *prev, size_t *olen);
|
||||
|
||||
const struct bhnd_nvram_vardefn *bhnd_nvram_find_vardefn(const char *varname);
|
||||
const struct bhnd_nvram_vardefn *bhnd_nvram_get_vardefn(size_t id);
|
||||
size_t bhnd_nvram_get_vardefn_id(
|
||||
|
@ -288,7 +288,7 @@ bhnd_nvram_store_setvar(struct bhnd_nvram_store *sc, const char *name,
|
||||
|
||||
/* Verify buffer size alignment for the given type. If this is a
|
||||
* variable width type, a width of 0 will always pass this check */
|
||||
if (len % bhnd_nvram_value_size(type, buf, len, 1) != 0)
|
||||
if (len % bhnd_nvram_value_size(buf, len, type, 1) != 0)
|
||||
return (EINVAL);
|
||||
|
||||
/* Determine string format (or directly add variable, if a C string) */
|
||||
|
@ -71,12 +71,6 @@ __FBSDID("$FreeBSD$");
|
||||
MALLOC_DEFINE(M_BHND_NVRAM, "bhnd_nvram", "bhnd nvram data");
|
||||
#endif
|
||||
|
||||
/** signed/unsigned 32-bit integer value storage */
|
||||
union bhnd_nvram_int_storage {
|
||||
uint32_t u32;
|
||||
int32_t s32;
|
||||
};
|
||||
|
||||
/*
|
||||
* CRC-8 lookup table used to checksum SPROM and NVRAM data via
|
||||
* bhnd_nvram_crc8().
|
||||
@ -343,242 +337,43 @@ bhnd_nvram_base_type(bhnd_nvram_type type)
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate the number of elements represented by a value of @p len bytes
|
||||
* with @p type.
|
||||
*
|
||||
* @param type The value type.
|
||||
* @param data The actual data to be queried, or NULL if unknown.
|
||||
* @param len The length in bytes of @p data, or if @p data is NULL,
|
||||
* the expected length in bytes.
|
||||
* @param[out] nelem On success, the number of elements. If @p type is not
|
||||
* a fixed width type (e.g. BHND_NVRAM_TYPE_STRING_ARRAY),
|
||||
* and @p data is NULL, an @p nelem value of 0 will be
|
||||
* returned.
|
||||
*
|
||||
* @retval 0 success
|
||||
* @retval EFTYPE if @p type is not an array type, and @p len is not
|
||||
* equal to the size of a single element of @p type.
|
||||
* @retval EFAULT if @p len is not correctly aligned for elements of
|
||||
* @p type.
|
||||
*/
|
||||
int
|
||||
bhnd_nvram_value_nelem(bhnd_nvram_type type, const void *data, size_t len,
|
||||
size_t *nelem)
|
||||
{
|
||||
bhnd_nvram_type base_type;
|
||||
size_t base_size;
|
||||
|
||||
/* Length must be aligned to the element size */
|
||||
base_type = bhnd_nvram_base_type(type);
|
||||
base_size = bhnd_nvram_value_size(base_type, NULL, 0, 1);
|
||||
if (base_size != 0 && len % base_size != 0)
|
||||
return (EFAULT);
|
||||
|
||||
switch (type) {
|
||||
case BHND_NVRAM_TYPE_STRING:
|
||||
case BHND_NVRAM_TYPE_STRING_ARRAY: {
|
||||
const char *p;
|
||||
size_t nleft;
|
||||
|
||||
/* Cannot determine the element count without parsing
|
||||
* the actual data */
|
||||
if (data == NULL) {
|
||||
*nelem = 0;
|
||||
return (0);
|
||||
}
|
||||
|
||||
/* Iterate over the NUL-terminated strings to calculate
|
||||
* total element count */
|
||||
p = data;
|
||||
nleft = len;
|
||||
*nelem = 0;
|
||||
while (nleft > 0) {
|
||||
size_t slen;
|
||||
|
||||
/* Increment element count */
|
||||
(*nelem)++;
|
||||
|
||||
/* If not a string array, data must not contain more
|
||||
* than one entry. */
|
||||
if (!bhnd_nvram_is_array_type(type) && *nelem > 1)
|
||||
return (EFTYPE);
|
||||
|
||||
/* Determine string length */
|
||||
slen = strnlen(p, nleft);
|
||||
nleft -= slen;
|
||||
|
||||
/* Advance input */
|
||||
p += slen;
|
||||
|
||||
/* Account for trailing NUL, if we haven't hit the end
|
||||
* of the input */
|
||||
if (nleft > 0) {
|
||||
nleft--;
|
||||
p++;
|
||||
}
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
case BHND_NVRAM_TYPE_INT8:
|
||||
case BHND_NVRAM_TYPE_UINT8:
|
||||
case BHND_NVRAM_TYPE_CHAR:
|
||||
case BHND_NVRAM_TYPE_INT16:
|
||||
case BHND_NVRAM_TYPE_UINT16:
|
||||
case BHND_NVRAM_TYPE_INT32:
|
||||
case BHND_NVRAM_TYPE_UINT32:
|
||||
case BHND_NVRAM_TYPE_INT64:
|
||||
case BHND_NVRAM_TYPE_UINT64:
|
||||
/* Length must be equal to the size of exactly one
|
||||
* element (arrays can represent zero elements -- non-array
|
||||
* types cannot) */
|
||||
if (len != base_size)
|
||||
return (EFTYPE);
|
||||
*nelem = 1;
|
||||
return (0);
|
||||
|
||||
case BHND_NVRAM_TYPE_UINT8_ARRAY:
|
||||
case BHND_NVRAM_TYPE_UINT16_ARRAY:
|
||||
case BHND_NVRAM_TYPE_UINT32_ARRAY:
|
||||
case BHND_NVRAM_TYPE_UINT64_ARRAY:
|
||||
case BHND_NVRAM_TYPE_INT8_ARRAY:
|
||||
case BHND_NVRAM_TYPE_INT16_ARRAY:
|
||||
case BHND_NVRAM_TYPE_INT32_ARRAY:
|
||||
case BHND_NVRAM_TYPE_INT64_ARRAY:
|
||||
case BHND_NVRAM_TYPE_CHAR_ARRAY:
|
||||
BHND_NV_ASSERT(base_size != 0, ("invalid base size"));
|
||||
*nelem = len / base_size;
|
||||
return (0);
|
||||
}
|
||||
|
||||
/* Quiesce gcc4.2 */
|
||||
BHND_NV_PANIC("bhnd nvram type %u unknown", type);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the size, in bytes, of a value of @p type with @p nelem elements.
|
||||
* Return the size, in bytes, of a single element of @p type, or 0
|
||||
* if @p type is a variable-width type.
|
||||
*
|
||||
* @param type The value type.
|
||||
* @param data The actual data to be queried, or NULL if unknown. If
|
||||
* NULL and the base type is not a fixed width type
|
||||
* (e.g. BHND_NVRAM_TYPE_STRING), 0 will be returned.
|
||||
* @param nbytes The size of @p data, in bytes, or 0 if @p data is NULL.
|
||||
* @param nelem The number of elements. If @p type is not an array type,
|
||||
* this value must be 1.
|
||||
*
|
||||
* @retval 0 If @p type has a variable width, and @p data is NULL.
|
||||
* @retval 0 If a @p nelem value greater than 1 is provided for a
|
||||
* non-array @p type.
|
||||
* @retval 0 If a @p nelem value of 0 is provided.
|
||||
* @retval 0 If the result would exceed the maximum value
|
||||
* representable by size_t.
|
||||
* @retval non-zero The size, in bytes, of @p type with @p nelem elements.
|
||||
* @param type The type to query.
|
||||
*/
|
||||
size_t
|
||||
bhnd_nvram_value_size(bhnd_nvram_type type, const void *data, size_t nbytes,
|
||||
size_t nelem)
|
||||
bhnd_nvram_type_width(bhnd_nvram_type type)
|
||||
{
|
||||
/* If nelem 0, nothing to do */
|
||||
if (nelem == 0)
|
||||
return (0);
|
||||
|
||||
/* Non-array types must have an nelem value of 1 */
|
||||
if (!bhnd_nvram_is_array_type(type) && nelem != 1)
|
||||
return (0);
|
||||
|
||||
switch (type) {
|
||||
case BHND_NVRAM_TYPE_UINT8_ARRAY:
|
||||
case BHND_NVRAM_TYPE_UINT16_ARRAY:
|
||||
case BHND_NVRAM_TYPE_UINT32_ARRAY:
|
||||
case BHND_NVRAM_TYPE_UINT64_ARRAY:
|
||||
case BHND_NVRAM_TYPE_INT8_ARRAY:
|
||||
case BHND_NVRAM_TYPE_INT16_ARRAY:
|
||||
case BHND_NVRAM_TYPE_INT32_ARRAY:
|
||||
case BHND_NVRAM_TYPE_INT64_ARRAY:
|
||||
case BHND_NVRAM_TYPE_CHAR_ARRAY: {
|
||||
bhnd_nvram_type base_type;
|
||||
size_t base_size;
|
||||
case BHND_NVRAM_TYPE_STRING:
|
||||
case BHND_NVRAM_TYPE_STRING_ARRAY:
|
||||
return (0);
|
||||
|
||||
base_type = bhnd_nvram_base_type(type);
|
||||
base_size = bhnd_nvram_value_size(base_type, NULL, 0, 1);
|
||||
|
||||
/* Would nelem * base_size overflow? */
|
||||
if (SIZE_MAX / nelem < base_size) {
|
||||
BHND_NV_LOG("cannot represent size %s * %zu\n",
|
||||
bhnd_nvram_type_name(base_type), nelem);
|
||||
return (0);
|
||||
}
|
||||
|
||||
return (nelem * base_size);
|
||||
}
|
||||
|
||||
case BHND_NVRAM_TYPE_STRING_ARRAY: {
|
||||
const char *p;
|
||||
size_t total_size;
|
||||
|
||||
if (data == NULL)
|
||||
return (0);
|
||||
|
||||
/* Iterate over the NUL-terminated strings to calculate
|
||||
* total byte length */
|
||||
p = data;
|
||||
total_size = 0;
|
||||
for (size_t i = 0; i < nelem; i++) {
|
||||
size_t elem_size;
|
||||
|
||||
elem_size = strnlen(p, nbytes - total_size);
|
||||
p += elem_size;
|
||||
|
||||
/* Check for (and skip) terminating NUL */
|
||||
if (total_size < nbytes && *p == '\0') {
|
||||
elem_size++;
|
||||
p++;
|
||||
}
|
||||
|
||||
/* Would total_size + elem_size overflow?
|
||||
*
|
||||
* A memory range larger than SIZE_MAX shouldn't be,
|
||||
* possible, but include the check for completeness */
|
||||
if (SIZE_MAX - total_size < elem_size)
|
||||
return (0);
|
||||
|
||||
total_size += elem_size;
|
||||
}
|
||||
|
||||
return (total_size);
|
||||
}
|
||||
|
||||
case BHND_NVRAM_TYPE_STRING: {
|
||||
size_t size;
|
||||
|
||||
if (data == NULL)
|
||||
return (0);
|
||||
|
||||
/* Find length */
|
||||
size = strnlen(data, nbytes);
|
||||
|
||||
/* Is there a terminating NUL, or did we just hit the
|
||||
* end of the string input */
|
||||
if (size < nbytes)
|
||||
size++;
|
||||
|
||||
return (size);
|
||||
}
|
||||
case BHND_NVRAM_TYPE_INT8:
|
||||
case BHND_NVRAM_TYPE_UINT8:
|
||||
case BHND_NVRAM_TYPE_CHAR:
|
||||
case BHND_NVRAM_TYPE_CHAR_ARRAY:
|
||||
case BHND_NVRAM_TYPE_UINT8:
|
||||
case BHND_NVRAM_TYPE_UINT8_ARRAY:
|
||||
case BHND_NVRAM_TYPE_INT8:
|
||||
case BHND_NVRAM_TYPE_INT8_ARRAY:
|
||||
return (sizeof(uint8_t));
|
||||
|
||||
case BHND_NVRAM_TYPE_INT16:
|
||||
case BHND_NVRAM_TYPE_UINT16:
|
||||
case BHND_NVRAM_TYPE_UINT16_ARRAY:
|
||||
case BHND_NVRAM_TYPE_INT16:
|
||||
case BHND_NVRAM_TYPE_INT16_ARRAY:
|
||||
return (sizeof(uint16_t));
|
||||
|
||||
case BHND_NVRAM_TYPE_INT32:
|
||||
case BHND_NVRAM_TYPE_UINT32:
|
||||
case BHND_NVRAM_TYPE_UINT32_ARRAY:
|
||||
case BHND_NVRAM_TYPE_INT32:
|
||||
case BHND_NVRAM_TYPE_INT32_ARRAY:
|
||||
return (sizeof(uint32_t));
|
||||
|
||||
case BHND_NVRAM_TYPE_UINT64:
|
||||
case BHND_NVRAM_TYPE_UINT64_ARRAY:
|
||||
case BHND_NVRAM_TYPE_INT64:
|
||||
case BHND_NVRAM_TYPE_INT64_ARRAY:
|
||||
return (sizeof(uint64_t));
|
||||
}
|
||||
|
||||
@ -587,132 +382,74 @@ bhnd_nvram_value_size(bhnd_nvram_type type, const void *data, size_t nbytes,
|
||||
}
|
||||
|
||||
/**
|
||||
* Iterate over all strings in the @p inp string array.
|
||||
* Return the native host alignment for values of @p type.
|
||||
*
|
||||
* @param type The type to query.
|
||||
*/
|
||||
size_t
|
||||
bhnd_nvram_type_host_align(bhnd_nvram_type type)
|
||||
{
|
||||
switch (type) {
|
||||
case BHND_NVRAM_TYPE_CHAR:
|
||||
case BHND_NVRAM_TYPE_CHAR_ARRAY:
|
||||
case BHND_NVRAM_TYPE_STRING:
|
||||
case BHND_NVRAM_TYPE_STRING_ARRAY:
|
||||
return (_Alignof(uint8_t));
|
||||
case BHND_NVRAM_TYPE_UINT8:
|
||||
case BHND_NVRAM_TYPE_UINT8_ARRAY:
|
||||
return (_Alignof(uint8_t));
|
||||
case BHND_NVRAM_TYPE_UINT16:
|
||||
case BHND_NVRAM_TYPE_UINT16_ARRAY:
|
||||
return (_Alignof(uint16_t));
|
||||
case BHND_NVRAM_TYPE_UINT32:
|
||||
case BHND_NVRAM_TYPE_UINT32_ARRAY:
|
||||
return (_Alignof(uint32_t));
|
||||
case BHND_NVRAM_TYPE_UINT64:
|
||||
case BHND_NVRAM_TYPE_UINT64_ARRAY:
|
||||
return (_Alignof(uint64_t));
|
||||
case BHND_NVRAM_TYPE_INT8:
|
||||
case BHND_NVRAM_TYPE_INT8_ARRAY:
|
||||
return (_Alignof(int8_t));
|
||||
case BHND_NVRAM_TYPE_INT16:
|
||||
case BHND_NVRAM_TYPE_INT16_ARRAY:
|
||||
return (_Alignof(int16_t));
|
||||
case BHND_NVRAM_TYPE_INT32:
|
||||
case BHND_NVRAM_TYPE_INT32_ARRAY:
|
||||
return (_Alignof(int32_t));
|
||||
case BHND_NVRAM_TYPE_INT64:
|
||||
case BHND_NVRAM_TYPE_INT64_ARRAY:
|
||||
return (_Alignof(int64_t));
|
||||
}
|
||||
|
||||
/* Quiesce gcc4.2 */
|
||||
BHND_NV_PANIC("bhnd nvram type %u unknown", type);
|
||||
}
|
||||
|
||||
/**
|
||||
* Iterate over all strings in the @p inp string array (@see
|
||||
* BHNF_NVRAM_TYPE_STRING_ARRAY).
|
||||
*
|
||||
* @param inp The string array to be iterated. This must be a buffer
|
||||
* of one or more NUL-terminated strings --
|
||||
* @see BHND_NVRAM_TYPE_STRING_ARRAY.
|
||||
* @param ilen The size, in bytes, of @p inp, including any
|
||||
* terminating NUL character(s).
|
||||
* @param prev The value previously returned by
|
||||
* bhnd_nvram_string_array_next(), or NULL to begin
|
||||
* iteration.
|
||||
* @param inp The string array to be iterated. This must be a
|
||||
* buffer of one or more NUL-terminated strings.
|
||||
* @param ilen The size, in bytes, of @p inp, including any
|
||||
* terminating NUL character(s).
|
||||
* @param prev The pointer previously returned by
|
||||
* bhnd_nvram_string_array_next(), or NULL to begin
|
||||
* iteration.
|
||||
* @param[in,out] olen If @p prev is non-NULL, @p olen must be a
|
||||
* pointer to the length previously returned by
|
||||
* bhnd_nvram_string_array_next(). On success, will
|
||||
* be set to the next element's length, in bytes.
|
||||
*
|
||||
* @retval non-NULL A reference to the next NUL-terminated string
|
||||
* @retval NULL If the end of the string array is reached.
|
||||
*/
|
||||
const char *
|
||||
bhnd_nvram_string_array_next(const char *inp, size_t ilen, const char *prev)
|
||||
bhnd_nvram_string_array_next(const char *inp, size_t ilen, const char *prev,
|
||||
size_t *olen)
|
||||
{
|
||||
size_t nremain, plen;
|
||||
|
||||
if (ilen == 0)
|
||||
return (NULL);
|
||||
|
||||
if (prev == NULL)
|
||||
return (inp);
|
||||
|
||||
/* Advance to next value */
|
||||
BHND_NV_ASSERT(prev >= inp, ("invalid prev pointer"));
|
||||
BHND_NV_ASSERT(prev < (inp+ilen), ("invalid prev pointer"));
|
||||
|
||||
nremain = ilen - (size_t)(prev - inp);
|
||||
plen = strnlen(prev, nremain);
|
||||
nremain -= plen;
|
||||
|
||||
/* Only a trailing NUL remains? */
|
||||
if (nremain <= 1)
|
||||
return (NULL);
|
||||
|
||||
return (prev + plen + 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Format a string representation of @p inp using @p fmt, with, writing the
|
||||
* result to @p outp.
|
||||
*
|
||||
* Refer to bhnd_nvram_val_vprintf() for full format string documentation.
|
||||
*
|
||||
* @param fmt The format string.
|
||||
* @param inp The value to be formatted.
|
||||
* @param ilen The size of @p inp, in bytes.
|
||||
* @param itype The type of @p inp.
|
||||
* @param[out] outp On success, the string value 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 outp. On success, will be set
|
||||
* to the actual size of the formatted string.
|
||||
*
|
||||
* @retval 0 success
|
||||
* @retval EINVAL If @p fmt contains unrecognized format string
|
||||
* specifiers.
|
||||
* @retval ENOMEM If the @p outp is non-NULL, and the provided @p olen
|
||||
* is too small to hold the encoded value.
|
||||
* @retval EFTYPE If value coercion from @p inp to a string value via
|
||||
* @p fmt is unsupported.
|
||||
* @retval ERANGE If value coercion of @p value would overflow (or
|
||||
* underflow) the representation defined by @p fmt.
|
||||
*/
|
||||
int
|
||||
bhnd_nvram_value_printf(const char *fmt, const void *inp, size_t ilen,
|
||||
bhnd_nvram_type itype, char *outp, size_t *olen, ...)
|
||||
{
|
||||
va_list ap;
|
||||
int error;
|
||||
|
||||
va_start(ap, olen);
|
||||
error = bhnd_nvram_value_vprintf(fmt, inp, ilen, itype, outp, olen, ap);
|
||||
va_end(ap);
|
||||
|
||||
return (error);
|
||||
}
|
||||
|
||||
/**
|
||||
* Format a string representation of @p inp using @p fmt, with, writing the
|
||||
* result to @p outp.
|
||||
*
|
||||
* Refer to bhnd_nvram_val_vprintf() for full format string documentation.
|
||||
*
|
||||
* @param fmt The format string.
|
||||
* @param inp The value to be formatted.
|
||||
* @param ilen The size of @p inp, in bytes.
|
||||
* @param itype The type of @p inp.
|
||||
* @param[out] outp On success, the string value 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 outp. On success, will be set
|
||||
* to the actual size of the formatted string.
|
||||
* @param ap Argument list.
|
||||
*
|
||||
* @retval 0 success
|
||||
* @retval EINVAL If @p fmt contains unrecognized format string
|
||||
* specifiers.
|
||||
* @retval ENOMEM If the @p outp is non-NULL, and the provided @p olen
|
||||
* is too small to hold the encoded value.
|
||||
* @retval EFTYPE If value coercion from @p inp to a string value via
|
||||
* @p fmt is unsupported.
|
||||
* @retval ERANGE If value coercion of @p value would overflow (or
|
||||
* underflow) the representation defined by @p fmt.
|
||||
*/
|
||||
int
|
||||
bhnd_nvram_value_vprintf(const char *fmt, const void *inp, size_t ilen,
|
||||
bhnd_nvram_type itype, char *outp, size_t *olen, va_list ap)
|
||||
{
|
||||
bhnd_nvram_val val;
|
||||
int error;
|
||||
|
||||
/* Map input buffer as a value instance */
|
||||
error = bhnd_nvram_val_init(&val, NULL, inp, ilen, itype,
|
||||
BHND_NVRAM_VAL_BORROW_DATA);
|
||||
if (error)
|
||||
return (error);
|
||||
|
||||
/* Attempt to format the value */
|
||||
error = bhnd_nvram_val_vprintf(&val, fmt, outp, olen, ap);
|
||||
|
||||
/* Clean up */
|
||||
bhnd_nvram_val_release(&val);
|
||||
return (error);
|
||||
return (bhnd_nvram_value_array_next(inp, ilen,
|
||||
BHND_NVRAM_TYPE_STRING_ARRAY, prev, olen));
|
||||
}
|
||||
|
||||
/* used by bhnd_nvram_find_vardefn() */
|
||||
@ -824,47 +561,6 @@ bhnd_nvram_validate_name(const char *name, size_t name_len)
|
||||
return (true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Coerce value @p inp of type @p itype to @p otype, writing the
|
||||
* result to @p outp.
|
||||
*
|
||||
* @param inp The value to be coerced.
|
||||
* @param ilen The size of @p inp, in bytes.
|
||||
* @param itype The base data type of @p inp.
|
||||
* @param[out] outp On success, the value 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 outp. On success, will be set
|
||||
* to the actual size of the requested value.
|
||||
* @param otype The data type to be written to @p outp.
|
||||
*
|
||||
* @retval 0 success
|
||||
* @retval ENOMEM If @p outp is non-NULL and a buffer of @p olen is too
|
||||
* small to hold the requested value.
|
||||
* @retval EFTYPE If the variable data cannot be coerced to @p otype.
|
||||
* @retval ERANGE If value coercion would overflow @p otype.
|
||||
*/
|
||||
int
|
||||
bhnd_nvram_value_coerce(const void *inp, size_t ilen, bhnd_nvram_type itype,
|
||||
void *outp, size_t *olen, bhnd_nvram_type otype)
|
||||
{
|
||||
bhnd_nvram_val val;
|
||||
int error;
|
||||
|
||||
/* Wrap input buffer in a value instance */
|
||||
error = bhnd_nvram_val_init(&val, NULL, inp, ilen,
|
||||
itype, BHND_NVRAM_VAL_BORROW_DATA|BHND_NVRAM_VAL_FIXED);
|
||||
if (error)
|
||||
return (error);
|
||||
|
||||
/* Try to encode as requested type */
|
||||
error = bhnd_nvram_val_encode(&val, outp, olen, otype);
|
||||
|
||||
/* Clean up and return error */
|
||||
bhnd_nvram_val_release(&val);
|
||||
return (error);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses the string in the optionally NUL-terminated @p str to as an integer
|
||||
* value of @p otype, accepting any integer format supported by the standard
|
||||
@ -1114,7 +810,7 @@ bhnd_nvram_parse_int(const char *str, size_t maxlen, u_int base,
|
||||
value = -value;
|
||||
|
||||
/* Provide (and verify) required length */
|
||||
*olen = bhnd_nvram_value_size(otype, NULL, 0, 1);
|
||||
*olen = bhnd_nvram_type_width(otype);
|
||||
if (outp == NULL)
|
||||
return (0);
|
||||
else if (limit < *olen)
|
||||
|
@ -35,6 +35,7 @@ __FBSDID("$FreeBSD$");
|
||||
|
||||
#ifdef _KERNEL
|
||||
|
||||
#include <sys/ctype.h>
|
||||
#include <sys/kernel.h>
|
||||
#include <sys/malloc.h>
|
||||
#include <sys/systm.h>
|
||||
@ -43,6 +44,7 @@ __FBSDID("$FreeBSD$");
|
||||
|
||||
#else /* !_KERNEL */
|
||||
|
||||
#include <ctype.h>
|
||||
#include <inttypes.h>
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
@ -54,6 +56,8 @@ __FBSDID("$FreeBSD$");
|
||||
|
||||
#include "bhnd_nvram_valuevar.h"
|
||||
|
||||
static int bhnd_nvram_val_fmt_filter(const bhnd_nvram_val_fmt **fmt,
|
||||
const void *inp, size_t ilen, bhnd_nvram_type itype);
|
||||
|
||||
static void *bhnd_nvram_val_alloc_bytes(bhnd_nvram_val *value, size_t ilen,
|
||||
bhnd_nvram_type itype, uint32_t flags);
|
||||
@ -62,6 +66,15 @@ static int bhnd_nvram_val_set(bhnd_nvram_val *value, const void *inp,
|
||||
static int bhnd_nvram_val_set_inline(bhnd_nvram_val *value,
|
||||
const void *inp, size_t ilen, bhnd_nvram_type itype);
|
||||
|
||||
static int bhnd_nvram_val_encode_int(const void *inp, size_t ilen,
|
||||
bhnd_nvram_type itype, void *outp, size_t *olen,
|
||||
bhnd_nvram_type otype);
|
||||
static int bhnd_nvram_val_encode_string(const void *inp, size_t ilen,
|
||||
bhnd_nvram_type itype, void *outp, size_t *olen,
|
||||
bhnd_nvram_type otype);
|
||||
|
||||
/** Initialize an empty value instance with @p _fmt, @p _storage, and
|
||||
* an implicit callee-owned reference */
|
||||
#define BHND_NVRAM_VAL_INITIALIZER(_fmt, _storage) \
|
||||
(bhnd_nvram_val) { \
|
||||
.refs = 1, \
|
||||
@ -80,6 +93,156 @@ static int bhnd_nvram_val_set_inline(bhnd_nvram_val *value,
|
||||
value->data.ptr == NULL, \
|
||||
("previously initialized value"))
|
||||
|
||||
/** Return true if BHND_NVRAM_VAL_BORROW_DATA or BHND_NVRAM_VAL_STATIC_DATA is
|
||||
* set in @p _flags (e.g. we should attempt to directly reference external
|
||||
* data */
|
||||
#define BHND_NVRAM_VAL_EXTREF_BORROWED_DATA(_flags) \
|
||||
(((_flags) & BHND_NVRAM_VAL_BORROW_DATA) || \
|
||||
((_flags) & BHND_NVRAM_VAL_STATIC_DATA))
|
||||
|
||||
/** Flags permitted when performing val-based initialization via
|
||||
* bhnd_nvram_val_convert_init() or bhnd_nvram_val_convert_new() */
|
||||
#define BHND_NVRAM_VALID_CONV_FLAGS \
|
||||
(BHND_NVRAM_VAL_FIXED | \
|
||||
BHND_NVRAM_VAL_DYNAMIC | \
|
||||
BHND_NVRAM_VAL_COPY_DATA)
|
||||
|
||||
/** Returns true if @p _val must be copied in bhnd_nvram_val_copy(), false
|
||||
* if its reference count may be safely incremented */
|
||||
#define BHND_NVRAM_VAL_NEED_COPY(_val) \
|
||||
((_val)->val_storage == BHND_NVRAM_VAL_STORAGE_AUTO || \
|
||||
(_val)->data_storage == BHND_NVRAM_VAL_DATA_EXT_WEAK)
|
||||
|
||||
volatile u_int refs; /**< reference count */
|
||||
bhnd_nvram_val_storage val_storage; /**< value structure storage */
|
||||
const bhnd_nvram_val_fmt *fmt; /**< value format */
|
||||
bhnd_nvram_val_data_storage data_storage; /**< data storage */
|
||||
bhnd_nvram_type data_type; /**< data type */
|
||||
size_t data_len; /**< data size */
|
||||
|
||||
/**
|
||||
* Return the human-readable name of @p fmt.
|
||||
*/
|
||||
const char *
|
||||
bhnd_nvram_val_fmt_name(const bhnd_nvram_val_fmt *fmt)
|
||||
{
|
||||
return (fmt->name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the default format for values of @p type.
|
||||
*/
|
||||
const bhnd_nvram_val_fmt *
|
||||
bhnd_nvram_val_default_fmt(bhnd_nvram_type type)
|
||||
{
|
||||
switch (type) {
|
||||
case BHND_NVRAM_TYPE_UINT8:
|
||||
return (&bhnd_nvram_val_uint8_fmt);
|
||||
case BHND_NVRAM_TYPE_UINT16:
|
||||
return (&bhnd_nvram_val_uint16_fmt);
|
||||
case BHND_NVRAM_TYPE_UINT32:
|
||||
return (&bhnd_nvram_val_uint32_fmt);
|
||||
case BHND_NVRAM_TYPE_UINT64:
|
||||
return (&bhnd_nvram_val_uint64_fmt);
|
||||
case BHND_NVRAM_TYPE_INT8:
|
||||
return (&bhnd_nvram_val_int8_fmt);
|
||||
case BHND_NVRAM_TYPE_INT16:
|
||||
return (&bhnd_nvram_val_int16_fmt);
|
||||
case BHND_NVRAM_TYPE_INT32:
|
||||
return (&bhnd_nvram_val_int32_fmt);
|
||||
case BHND_NVRAM_TYPE_INT64:
|
||||
return (&bhnd_nvram_val_int64_fmt);
|
||||
case BHND_NVRAM_TYPE_CHAR:
|
||||
return (&bhnd_nvram_val_char_fmt);
|
||||
case BHND_NVRAM_TYPE_STRING:
|
||||
return (&bhnd_nvram_val_string_fmt);
|
||||
case BHND_NVRAM_TYPE_UINT8_ARRAY:
|
||||
return (&bhnd_nvram_val_uint8_array_fmt);
|
||||
case BHND_NVRAM_TYPE_UINT16_ARRAY:
|
||||
return (&bhnd_nvram_val_uint16_array_fmt);
|
||||
case BHND_NVRAM_TYPE_UINT32_ARRAY:
|
||||
return (&bhnd_nvram_val_uint32_array_fmt);
|
||||
case BHND_NVRAM_TYPE_UINT64_ARRAY:
|
||||
return (&bhnd_nvram_val_uint64_array_fmt);
|
||||
case BHND_NVRAM_TYPE_INT8_ARRAY:
|
||||
return (&bhnd_nvram_val_int8_array_fmt);
|
||||
case BHND_NVRAM_TYPE_INT16_ARRAY:
|
||||
return (&bhnd_nvram_val_int16_array_fmt);
|
||||
case BHND_NVRAM_TYPE_INT32_ARRAY:
|
||||
return (&bhnd_nvram_val_int32_array_fmt);
|
||||
case BHND_NVRAM_TYPE_INT64_ARRAY:
|
||||
return (&bhnd_nvram_val_int64_array_fmt);
|
||||
case BHND_NVRAM_TYPE_CHAR_ARRAY:
|
||||
return (&bhnd_nvram_val_char_array_fmt);
|
||||
case BHND_NVRAM_TYPE_STRING_ARRAY:
|
||||
return (&bhnd_nvram_val_string_array_fmt);
|
||||
}
|
||||
|
||||
/* Quiesce gcc4.2 */
|
||||
BHND_NV_PANIC("bhnd nvram type %u unknown", type);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether @p fmt (or new format delegated to by @p fmt) is
|
||||
* capable of direct initialization from buffer @p inp.
|
||||
*
|
||||
* @param[in,out] fmt Indirect pointer to the NVRAM value format. If
|
||||
* the format instance cannot handle the data type
|
||||
* directly, it may delegate to a new format
|
||||
* instance. On success, this parameter will be
|
||||
* set to the format that should be used when
|
||||
* performing initialization from @p inp.
|
||||
* @param inp Input data.
|
||||
* @param ilen Input data length.
|
||||
* @param itype Input data type.
|
||||
*
|
||||
* @retval 0 If initialization from @p inp is supported.
|
||||
* @retval EFTYPE If initialization from @p inp is unsupported.
|
||||
* @retval EFAULT if @p ilen is not correctly aligned for elements of
|
||||
* @p itype.
|
||||
*/
|
||||
static int
|
||||
bhnd_nvram_val_fmt_filter(const bhnd_nvram_val_fmt **fmt, const void *inp,
|
||||
size_t ilen, bhnd_nvram_type itype)
|
||||
{
|
||||
const bhnd_nvram_val_fmt *ofmt, *nfmt;
|
||||
int error;
|
||||
|
||||
nfmt = ofmt = *fmt;
|
||||
|
||||
/* Validate alignment */
|
||||
if ((error = bhnd_nvram_value_check_aligned(inp, ilen, itype)))
|
||||
return (error);
|
||||
|
||||
/* If the format does not provide a filter function, it only supports
|
||||
* direct initialization from its native type */
|
||||
if (ofmt->op_filter == NULL) {
|
||||
if (itype == ofmt->native_type)
|
||||
return (0);
|
||||
|
||||
return (EFTYPE);
|
||||
}
|
||||
|
||||
/* Use the filter function to determine whether direct initialization
|
||||
* from itype is permitted */
|
||||
error = ofmt->op_filter(&nfmt, inp, ilen, itype);
|
||||
if (error)
|
||||
return (error);
|
||||
|
||||
/* Retry filter with new format? */
|
||||
if (ofmt != nfmt) {
|
||||
error = bhnd_nvram_val_fmt_filter(&nfmt, inp, ilen, itype);
|
||||
if (error)
|
||||
return (error);
|
||||
|
||||
/* Success -- provide delegated format to caller */
|
||||
*fmt = nfmt;
|
||||
}
|
||||
|
||||
/* Value can be initialized with provided format and input type */
|
||||
return (0);
|
||||
}
|
||||
|
||||
/* Common initialization support for bhnd_nvram_val_init() and
|
||||
* bhnd_nvram_val_new() */
|
||||
static int
|
||||
@ -92,35 +255,20 @@ bhnd_nvram_val_init_common(bhnd_nvram_val *value,
|
||||
size_t olen;
|
||||
int error;
|
||||
|
||||
/* If the value format is unspecified, we use the default format
|
||||
* for the input data type */
|
||||
if (fmt == NULL)
|
||||
fmt = bhnd_nvram_val_default_fmt(itype);
|
||||
|
||||
/* Determine expected data type, and allow the format to delegate to
|
||||
* a new format instance */
|
||||
if (fmt != NULL && fmt->op_filter != NULL) {
|
||||
const bhnd_nvram_val_fmt *nfmt = fmt;
|
||||
|
||||
/* Use the filter function to determine whether direct
|
||||
* initialization from is itype permitted */
|
||||
error = fmt->op_filter(&nfmt, inp, ilen, itype);
|
||||
if (error)
|
||||
return (error);
|
||||
|
||||
/* Retry initialization with new format? */
|
||||
if (nfmt != fmt) {
|
||||
return (bhnd_nvram_val_init_common(value, val_storage,
|
||||
nfmt, inp, ilen, itype, flags));
|
||||
}
|
||||
|
||||
/* Value can be initialized with provided input type */
|
||||
otype = itype;
|
||||
|
||||
} else if (fmt != NULL) {
|
||||
/* Value must be initialized with the format's native
|
||||
* type */
|
||||
if ((error = bhnd_nvram_val_fmt_filter(&fmt, inp, ilen, itype))) {
|
||||
/* Direct initialization from the provided input type is
|
||||
* not supported; alue must be initialized with the format's
|
||||
* native type */
|
||||
otype = fmt->native_type;
|
||||
|
||||
} else {
|
||||
/* No format specified; we can initialize directly from the
|
||||
* input data, and we'll handle all format operations
|
||||
* internally. */
|
||||
/* Value can be initialized with provided input type */
|
||||
otype = itype;
|
||||
}
|
||||
|
||||
@ -236,6 +384,145 @@ bhnd_nvram_val_new(bhnd_nvram_val **value, const bhnd_nvram_val_fmt *fmt,
|
||||
return (error);
|
||||
}
|
||||
|
||||
|
||||
/* Common initialization support for bhnd_nvram_val_convert_init() and
|
||||
* bhnd_nvram_val_convert_new() */
|
||||
static int
|
||||
bhnd_nvram_val_convert_common(bhnd_nvram_val *value,
|
||||
bhnd_nvram_val_storage val_storage, const bhnd_nvram_val_fmt *fmt,
|
||||
bhnd_nvram_val *src, uint32_t flags)
|
||||
{
|
||||
const void *inp;
|
||||
void *outp;
|
||||
bhnd_nvram_type itype, otype;
|
||||
size_t ilen, olen;
|
||||
int error;
|
||||
|
||||
/* Determine whether direct initialization from the source value's
|
||||
* existing data type is supported by the new format */
|
||||
inp = bhnd_nvram_val_bytes(src, &ilen, &itype);
|
||||
if (bhnd_nvram_val_fmt_filter(&fmt, inp, ilen, itype) == 0) {
|
||||
/* Adjust value flags based on the source data storage */
|
||||
switch (src->data_storage) {
|
||||
case BHND_NVRAM_VAL_DATA_NONE:
|
||||
case BHND_NVRAM_VAL_DATA_INLINE:
|
||||
case BHND_NVRAM_VAL_DATA_EXT_WEAK:
|
||||
case BHND_NVRAM_VAL_DATA_EXT_ALLOC:
|
||||
break;
|
||||
|
||||
case BHND_NVRAM_VAL_DATA_EXT_STATIC:
|
||||
/* If the source data has static storage duration,
|
||||
* we should apply that transitively */
|
||||
if (flags & BHND_NVRAM_VAL_BORROW_DATA)
|
||||
flags |= BHND_NVRAM_VAL_STATIC_DATA;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
/* Delegate to standard initialization */
|
||||
return (bhnd_nvram_val_init_common(value, val_storage, fmt, inp,
|
||||
ilen, itype, flags));
|
||||
}
|
||||
|
||||
/* Value must be initialized with the format's native type */
|
||||
otype = fmt->native_type;
|
||||
|
||||
/* Initialize value instance */
|
||||
*value = BHND_NVRAM_VAL_INITIALIZER(fmt, val_storage);
|
||||
|
||||
/* Determine size when encoded in native format */
|
||||
if ((error = bhnd_nvram_val_encode(src, NULL, &olen, otype)))
|
||||
return (error);
|
||||
|
||||
/* Fetch reference to (or allocate) an appropriately sized buffer */
|
||||
outp = bhnd_nvram_val_alloc_bytes(value, olen, otype, flags);
|
||||
if (outp == NULL)
|
||||
return (ENOMEM);
|
||||
|
||||
/* Perform encode */
|
||||
if ((error = bhnd_nvram_val_encode(src, outp, &olen, otype)))
|
||||
return (error);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize an externally allocated instance of @p value with @p fmt, and
|
||||
* attempt to initialize its internal representation from the given @p src
|
||||
* value.
|
||||
*
|
||||
* On success, the caller owns a reference to @p value, and is responsible for
|
||||
* freeing any resources allocated for @p value via bhnd_nvram_val_release().
|
||||
*
|
||||
* @param value The externally allocated value instance to be
|
||||
* initialized.
|
||||
* @param fmt The value's format.
|
||||
* @param src Input value to be converted.
|
||||
* @param flags Value flags (see BHND_NVRAM_VAL_*).
|
||||
*
|
||||
* @retval 0 success
|
||||
* @retval ENOMEM If allocation fails.
|
||||
* @retval EFTYPE If @p fmt initialization from @p src is unsupported.
|
||||
* @retval EFAULT if @p ilen is not correctly aligned for elements of
|
||||
* @p itype.
|
||||
* @retval ERANGE If value coercion of @p src would overflow
|
||||
* (or underflow) the @p fmt representation.
|
||||
*/
|
||||
int
|
||||
bhnd_nvram_val_convert_init(bhnd_nvram_val *value,
|
||||
const bhnd_nvram_val_fmt *fmt, bhnd_nvram_val *src, uint32_t flags)
|
||||
{
|
||||
int error;
|
||||
|
||||
error = bhnd_nvram_val_convert_common(value,
|
||||
BHND_NVRAM_VAL_STORAGE_AUTO, fmt, src, flags);
|
||||
if (error)
|
||||
bhnd_nvram_val_release(value);
|
||||
|
||||
return (error);
|
||||
}
|
||||
|
||||
/**
|
||||
* Allocate a value instance with @p fmt, and attempt to initialize its internal
|
||||
* representation from the given @p src value.
|
||||
*
|
||||
* On success, the caller owns a reference to @p value, and is responsible for
|
||||
* freeing any resources allocated for @p value via bhnd_nvram_val_release().
|
||||
*
|
||||
* @param[out] value On success, the allocated value instance.
|
||||
* @param fmt The value's format.
|
||||
* @param src Input value to be converted.
|
||||
* @param flags Value flags (see BHND_NVRAM_VAL_*).
|
||||
*
|
||||
* @retval 0 success
|
||||
* @retval ENOMEM If allocation fails.
|
||||
* @retval EFTYPE If @p fmt initialization from @p src is unsupported.
|
||||
* @retval EFAULT if @p ilen is not correctly aligned for elements of
|
||||
* @p itype.
|
||||
* @retval ERANGE If value coercion of @p src would overflow
|
||||
* (or underflow) the @p fmt representation.
|
||||
*/
|
||||
int
|
||||
bhnd_nvram_val_convert_new(bhnd_nvram_val **value,
|
||||
const bhnd_nvram_val_fmt *fmt, bhnd_nvram_val *src, uint32_t flags)
|
||||
{
|
||||
int error;
|
||||
|
||||
/* Allocate new instance */
|
||||
if ((*value = bhnd_nv_malloc(sizeof(**value))) == NULL)
|
||||
return (ENOMEM);
|
||||
|
||||
/* Perform common initialization. */
|
||||
error = bhnd_nvram_val_convert_common(*value,
|
||||
BHND_NVRAM_VAL_STORAGE_DYNAMIC, fmt, src, flags);
|
||||
if (error) {
|
||||
/* Will also free() the value allocation */
|
||||
bhnd_nvram_val_release(*value);
|
||||
}
|
||||
|
||||
return (error);
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy or retain a reference to @p value.
|
||||
*
|
||||
@ -250,22 +537,35 @@ bhnd_nvram_val_new(bhnd_nvram_val **value, const bhnd_nvram_val_fmt *fmt,
|
||||
bhnd_nvram_val *
|
||||
bhnd_nvram_val_copy(bhnd_nvram_val *value)
|
||||
{
|
||||
bhnd_nvram_val *result;
|
||||
bhnd_nvram_val *result;
|
||||
const void *bytes;
|
||||
bhnd_nvram_type type;
|
||||
size_t len;
|
||||
uint32_t flags;
|
||||
int error;
|
||||
|
||||
/* If dynamically allocated, simply bump the reference count */
|
||||
if (value->val_storage == BHND_NVRAM_VAL_STORAGE_DYNAMIC) {
|
||||
refcount_acquire(&value->refs);
|
||||
switch (value->val_storage) {
|
||||
case BHND_NVRAM_VAL_STORAGE_STATIC:
|
||||
/* If static, can return as-is */
|
||||
return (value);
|
||||
|
||||
case BHND_NVRAM_VAL_STORAGE_DYNAMIC:
|
||||
if (!BHND_NVRAM_VAL_NEED_COPY(value)) {
|
||||
refcount_acquire(&value->refs);
|
||||
return (value);
|
||||
}
|
||||
|
||||
/* Perform copy below */
|
||||
break;
|
||||
|
||||
case BHND_NVRAM_VAL_STORAGE_AUTO:
|
||||
BHND_NV_ASSERT(value->refs == 1, ("non-allocated value has "
|
||||
"active refcount (%u)", value->refs));
|
||||
|
||||
/* Perform copy below */
|
||||
break;
|
||||
}
|
||||
|
||||
/* Otherwise, we need to perform an actual copy */
|
||||
BHND_NV_ASSERT(value->refs == 1, ("non-allocated value has "
|
||||
"active refcount (%u)", value->refs));
|
||||
|
||||
/* Compute the new value's flags based on the source value */
|
||||
switch (value->data_storage) {
|
||||
@ -308,13 +608,26 @@ bhnd_nvram_val_release(bhnd_nvram_val *value)
|
||||
{
|
||||
BHND_NV_ASSERT(value->refs >= 1, ("value over-released"));
|
||||
|
||||
/* Skip if value is static */
|
||||
if (value->val_storage == BHND_NVRAM_VAL_STORAGE_STATIC)
|
||||
return;
|
||||
|
||||
/* Drop reference */
|
||||
if (!refcount_release(&value->refs))
|
||||
return;
|
||||
|
||||
/* Free allocated external representation data */
|
||||
if (value->data_storage == BHND_NVRAM_VAL_DATA_EXT_ALLOC)
|
||||
switch (value->data_storage) {
|
||||
case BHND_NVRAM_VAL_DATA_EXT_ALLOC:
|
||||
bhnd_nv_free(__DECONST(void *, value->data.ptr));
|
||||
break;
|
||||
case BHND_NVRAM_VAL_DATA_NONE:
|
||||
case BHND_NVRAM_VAL_DATA_INLINE:
|
||||
case BHND_NVRAM_VAL_DATA_EXT_WEAK:
|
||||
case BHND_NVRAM_VAL_DATA_EXT_STATIC:
|
||||
/* Nothing to free */
|
||||
break;
|
||||
}
|
||||
|
||||
/* Free instance if dynamically allocated */
|
||||
if (value->val_storage == BHND_NVRAM_VAL_STORAGE_DYNAMIC)
|
||||
@ -330,8 +643,8 @@ bhnd_nvram_val_release(bhnd_nvram_val *value)
|
||||
* - BHND_NVRAM_TYPE_CHAR_ARRAY
|
||||
*/
|
||||
static int
|
||||
bhnd_nvram_val_encode_string(void *outp, size_t *olen, bhnd_nvram_type otype,
|
||||
const void *inp, size_t ilen, bhnd_nvram_type itype)
|
||||
bhnd_nvram_val_encode_string(const void *inp, size_t ilen,
|
||||
bhnd_nvram_type itype, void *outp, size_t *olen, bhnd_nvram_type otype)
|
||||
{
|
||||
const char *cstr;
|
||||
bhnd_nvram_type otype_base;
|
||||
@ -358,7 +671,7 @@ bhnd_nvram_val_encode_string(void *outp, size_t *olen, bhnd_nvram_type otype,
|
||||
/* Determine string length, minus trailing NUL (if any) */
|
||||
cstr_len = strnlen(cstr, cstr_size);
|
||||
|
||||
/* Parse the field data */
|
||||
/* Parse the string data and write to output */
|
||||
switch (otype) {
|
||||
case BHND_NVRAM_TYPE_CHAR:
|
||||
case BHND_NVRAM_TYPE_CHAR_ARRAY:
|
||||
@ -459,8 +772,8 @@ bhnd_nvram_val_encode_string(void *outp, size_t *olen, bhnd_nvram_type otype,
|
||||
* Standard integer encoding implementation.
|
||||
*/
|
||||
static int
|
||||
bhnd_nvram_val_encode_int(void *outp, size_t *olen, bhnd_nvram_type otype,
|
||||
const void *inp, size_t ilen, bhnd_nvram_type itype)
|
||||
bhnd_nvram_val_encode_int(const void *inp, size_t ilen, bhnd_nvram_type itype,
|
||||
void *outp, size_t *olen, bhnd_nvram_type otype)
|
||||
{
|
||||
bhnd_nvram_type otype_base;
|
||||
size_t limit, nbytes;
|
||||
@ -722,7 +1035,7 @@ bhnd_nvram_val_encode(bhnd_nvram_val *value, void *outp, size_t *olen,
|
||||
bhnd_nvram_type otype)
|
||||
{
|
||||
/* Prefer format implementation */
|
||||
if (value->fmt != NULL && value->fmt->op_encode != NULL)
|
||||
if (value->fmt->op_encode != NULL)
|
||||
return (value->fmt->op_encode(value, outp, olen, otype));
|
||||
|
||||
return (bhnd_nvram_val_generic_encode(value, outp, olen, otype));
|
||||
@ -757,7 +1070,7 @@ bhnd_nvram_val_encode_elem(bhnd_nvram_val *value, const void *inp,
|
||||
size_t ilen, void *outp, size_t *olen, bhnd_nvram_type otype)
|
||||
{
|
||||
/* Prefer format implementation */
|
||||
if (value->fmt != NULL && value->fmt->op_encode_elem != NULL) {
|
||||
if (value->fmt->op_encode_elem != NULL) {
|
||||
return (value->fmt->op_encode_elem(value, inp, ilen, outp,
|
||||
olen, otype));
|
||||
}
|
||||
@ -807,8 +1120,8 @@ bhnd_nvram_val_bytes(bhnd_nvram_val *value, size_t *olen,
|
||||
* @param prev A value pointer previously returned by
|
||||
* bhnd_nvram_val_next() or bhnd_nvram_val_elem(),
|
||||
* or NULL to begin iteration at the first element.
|
||||
* @param[in,out] len If prev is non-NULL, len must be a pointer
|
||||
* to the length previously returned by
|
||||
* @param[in,out] olen If @p prev is non-NULL, @p olen must be a
|
||||
* pointer to the length previously returned by
|
||||
* bhnd_nvram_val_next() or bhnd_nvram_val_elem().
|
||||
* On success, will be set to the next element's
|
||||
* length, in bytes.
|
||||
@ -817,13 +1130,13 @@ bhnd_nvram_val_bytes(bhnd_nvram_val *value, size_t *olen,
|
||||
* @retval NULL If the end of the element array is reached.
|
||||
*/
|
||||
const void *
|
||||
bhnd_nvram_val_next(bhnd_nvram_val *value, const void *prev, size_t *len)
|
||||
bhnd_nvram_val_next(bhnd_nvram_val *value, const void *prev, size_t *olen)
|
||||
{
|
||||
/* Prefer the format implementation */
|
||||
if (value->fmt != NULL && value->fmt->op_next != NULL)
|
||||
return (value->fmt->op_next(value, prev, len));
|
||||
if (value->fmt->op_next != NULL)
|
||||
return (value->fmt->op_next(value, prev, olen));
|
||||
|
||||
return (bhnd_nvram_val_generic_next(value, prev, len));
|
||||
return (bhnd_nvram_val_generic_next(value, prev, olen));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -860,7 +1173,7 @@ bhnd_nvram_val_nelem(bhnd_nvram_val *value)
|
||||
int error;
|
||||
|
||||
/* Prefer format implementation */
|
||||
if (value->fmt != NULL && value->fmt->op_nelem != NULL)
|
||||
if (value->fmt->op_nelem != NULL)
|
||||
return (value->fmt->op_nelem(value));
|
||||
|
||||
/*
|
||||
@ -871,7 +1184,7 @@ bhnd_nvram_val_nelem(bhnd_nvram_val *value)
|
||||
* Instead, use bhnd_nvram_val_next() to parse the backing data and
|
||||
* produce a total count.
|
||||
*/
|
||||
if (value->fmt != NULL && value->fmt->op_next != NULL) {
|
||||
if (value->fmt->op_next != NULL) {
|
||||
const void *next;
|
||||
|
||||
next = NULL;
|
||||
@ -884,7 +1197,7 @@ bhnd_nvram_val_nelem(bhnd_nvram_val *value)
|
||||
|
||||
/* Otherwise, compute the standard element count */
|
||||
bytes = bhnd_nvram_val_bytes(value, &len, &type);
|
||||
if ((error = bhnd_nvram_value_nelem(type, bytes, len, &nelem))) {
|
||||
if ((error = bhnd_nvram_value_nelem(bytes, len, type, &nelem))) {
|
||||
/* Should always succeed */
|
||||
BHND_NV_PANIC("error calculating element count for type '%s' "
|
||||
"with length %zu: %d\n", bhnd_nvram_type_name(type), len,
|
||||
@ -914,28 +1227,31 @@ bhnd_nvram_val_generic_encode(bhnd_nvram_val *value, void *outp, size_t *olen,
|
||||
nbytes = 0;
|
||||
nelem = 0;
|
||||
otype_base = bhnd_nvram_base_type(otype);
|
||||
inp = bhnd_nvram_val_bytes(value, &ilen, &itype);
|
||||
|
||||
/*
|
||||
* Normally, a rank polymorphic type like a character array would not
|
||||
* be representable as a rank 1 type.
|
||||
* Normally, an array type is not universally representable as
|
||||
* non-array type.
|
||||
*
|
||||
* As a special-cased exception, we can support conversion directly
|
||||
* from CHAR_ARRAY to STRING by treating the character array as a
|
||||
* non-NUL-terminated string.
|
||||
*
|
||||
* This conversion is isomorphic; we also support conversion directly
|
||||
* from a STRING to a CHAR_ARRAY by the same mechanism.
|
||||
* As exceptions, we support conversion directly to/from:
|
||||
* - CHAR_ARRAY/STRING:
|
||||
* ->STRING Interpret the character array as a
|
||||
* non-NUL-terminated string.
|
||||
* ->CHAR_ARRAY Trim the trailing NUL from the string.
|
||||
*/
|
||||
inp = bhnd_nvram_val_bytes(value, &ilen, &itype);
|
||||
if ((itype == BHND_NVRAM_TYPE_CHAR_ARRAY &&
|
||||
otype == BHND_NVRAM_TYPE_STRING) ||
|
||||
(itype == BHND_NVRAM_TYPE_STRING &&
|
||||
otype == BHND_NVRAM_TYPE_CHAR_ARRAY))
|
||||
{
|
||||
#define BHND_NV_IS_ISO_CONV(_lhs, _rhs) \
|
||||
((itype == BHND_NVRAM_TYPE_ ## _lhs && \
|
||||
otype == BHND_NVRAM_TYPE_ ## _rhs) || \
|
||||
(itype == BHND_NVRAM_TYPE_ ## _rhs && \
|
||||
otype == BHND_NVRAM_TYPE_ ## _lhs))
|
||||
|
||||
if (BHND_NV_IS_ISO_CONV(CHAR_ARRAY, STRING)) {
|
||||
return (bhnd_nvram_val_encode_elem(value, inp, ilen, outp, olen,
|
||||
otype));
|
||||
}
|
||||
|
||||
#undef BHND_NV_IS_ISO_CONV
|
||||
|
||||
/*
|
||||
* If both input and output are non-array types, try to encode them
|
||||
* without performing element iteration.
|
||||
@ -1021,9 +1337,8 @@ bhnd_nvram_val_generic_encode_elem(bhnd_nvram_val *value, const void *inp,
|
||||
switch (itype) {
|
||||
case BHND_NVRAM_TYPE_STRING:
|
||||
case BHND_NVRAM_TYPE_CHAR:
|
||||
case BHND_NVRAM_TYPE_CHAR_ARRAY:
|
||||
return (bhnd_nvram_val_encode_string(outp, olen, otype, inp,
|
||||
ilen, itype));
|
||||
return (bhnd_nvram_val_encode_string(inp, ilen, itype, outp,
|
||||
olen, otype));
|
||||
|
||||
case BHND_NVRAM_TYPE_UINT8:
|
||||
case BHND_NVRAM_TYPE_UINT16:
|
||||
@ -1033,9 +1348,8 @@ bhnd_nvram_val_generic_encode_elem(bhnd_nvram_val *value, const void *inp,
|
||||
case BHND_NVRAM_TYPE_INT16:
|
||||
case BHND_NVRAM_TYPE_INT32:
|
||||
case BHND_NVRAM_TYPE_INT64:
|
||||
return (bhnd_nvram_val_encode_int(outp, olen, otype, inp, ilen,
|
||||
itype));
|
||||
|
||||
return (bhnd_nvram_val_encode_int(inp, ilen, itype, outp, olen,
|
||||
otype));
|
||||
default:
|
||||
BHND_NV_PANIC("missing encode_elem() implementation");
|
||||
}
|
||||
@ -1047,55 +1361,20 @@ bhnd_nvram_val_generic_encode_elem(bhnd_nvram_val *value, const void *inp,
|
||||
*/
|
||||
const void *
|
||||
bhnd_nvram_val_generic_next(bhnd_nvram_val *value, const void *prev,
|
||||
size_t *len)
|
||||
size_t *olen)
|
||||
{
|
||||
const uint8_t *inp;
|
||||
const uint8_t *next;
|
||||
bhnd_nvram_type itype;
|
||||
size_t ilen;
|
||||
size_t offset;
|
||||
|
||||
/* Otherwise, default to iterating over the backing representation
|
||||
* according to its native representation */
|
||||
/* Iterate over the backing representation */
|
||||
inp = bhnd_nvram_val_bytes(value, &ilen, &itype);
|
||||
|
||||
/* First element */
|
||||
if (prev == NULL) {
|
||||
/* Zero-length array? */
|
||||
if (ilen == 0)
|
||||
return (NULL);
|
||||
|
||||
*len = bhnd_nvram_value_size(itype, inp, ilen, 1);
|
||||
return (inp);
|
||||
}
|
||||
|
||||
/* Advance to next element */
|
||||
BHND_NV_ASSERT(prev >= (const void *)inp, ("invalid cookiep"));
|
||||
next = (const uint8_t *)prev + *len;
|
||||
offset = (size_t)(next - inp);
|
||||
|
||||
if (offset >= ilen) {
|
||||
/* Hit end of the array */
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
/* Determine element size */
|
||||
*len = bhnd_nvram_value_size(itype, next, ilen - offset, 1);
|
||||
if (ilen - offset < *len)
|
||||
BHND_NV_PANIC("short element -- misaligned representation");
|
||||
|
||||
return (next);
|
||||
return (bhnd_nvram_value_array_next(inp, ilen, itype, prev, olen));
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize the representation of @p value with @p ptr.
|
||||
*
|
||||
* If @p value is an externally allocated instance and the representation
|
||||
* cannot be represented inline, the given data will not be copied, and @p ptr
|
||||
* must remain valid for the lifetime of @p value.
|
||||
*
|
||||
* Otherwise, @p value will be initialized with a copy of the @p ptr.
|
||||
*
|
||||
* @param value The value to be initialized.
|
||||
* @param inp The external representation.
|
||||
* @param ilen The external representation length, in bytes.
|
||||
@ -1114,17 +1393,22 @@ bhnd_nvram_val_set(bhnd_nvram_val *value, const void *inp, size_t ilen,
|
||||
bhnd_nvram_type itype, uint32_t flags)
|
||||
{
|
||||
void *bytes;
|
||||
int error;
|
||||
|
||||
BHND_NVRAM_VAL_ASSERT_EMPTY(value);
|
||||
|
||||
/* Validate alignment */
|
||||
if ((error = bhnd_nvram_value_check_aligned(inp, ilen, itype)))
|
||||
return (error);
|
||||
|
||||
/* Reference the external data */
|
||||
if ((flags & BHND_NVRAM_VAL_BORROW_DATA) ||
|
||||
(flags & BHND_NVRAM_VAL_STATIC_DATA))
|
||||
{
|
||||
if (flags & BHND_NVRAM_VAL_BORROW_DATA)
|
||||
value->data_storage = BHND_NVRAM_VAL_DATA_EXT_WEAK;
|
||||
else
|
||||
if (flags & BHND_NVRAM_VAL_STATIC_DATA)
|
||||
value->data_storage = BHND_NVRAM_VAL_DATA_EXT_STATIC;
|
||||
else
|
||||
value->data_storage = BHND_NVRAM_VAL_DATA_EXT_WEAK;
|
||||
|
||||
value->data.ptr = inp;
|
||||
value->data_type = itype;
|
||||
@ -1170,6 +1454,7 @@ bhnd_nvram_val_set_inline(bhnd_nvram_val *value, const void *inp, size_t ilen,
|
||||
|
||||
#define NV_STORE_INIT_INLINE() do { \
|
||||
value->data_len = ilen; \
|
||||
value->data_type = itype; \
|
||||
} while(0)
|
||||
|
||||
#define NV_STORE_INLINE(_type, _dest) do { \
|
||||
|
@ -32,6 +32,7 @@
|
||||
#ifndef _BHND_NVRAM_BHND_NVRAM_VALUE_H_
|
||||
#define _BHND_NVRAM_BHND_NVRAM_VALUE_H_
|
||||
|
||||
|
||||
#include <sys/refcount.h>
|
||||
|
||||
#ifdef _KERNEL
|
||||
@ -45,16 +46,32 @@
|
||||
typedef struct bhnd_nvram_val_fmt bhnd_nvram_val_fmt;
|
||||
typedef struct bhnd_nvram_val bhnd_nvram_val;
|
||||
|
||||
const char *bhnd_nvram_val_fmt_name(
|
||||
const bhnd_nvram_val_fmt *fmt);
|
||||
|
||||
const bhnd_nvram_val_fmt *bhnd_nvram_val_default_fmt(
|
||||
bhnd_nvram_type type);
|
||||
|
||||
int bhnd_nvram_val_init(bhnd_nvram_val *value,
|
||||
const bhnd_nvram_val_fmt *fmt,
|
||||
const void *inp, size_t ilen,
|
||||
bhnd_nvram_type itype, uint32_t flags);
|
||||
|
||||
int bhnd_nvram_val_convert_init(
|
||||
bhnd_nvram_val *value,
|
||||
const bhnd_nvram_val_fmt *fmt,
|
||||
bhnd_nvram_val *src, uint32_t flags);
|
||||
|
||||
int bhnd_nvram_val_new(bhnd_nvram_val **value,
|
||||
const bhnd_nvram_val_fmt *fmt,
|
||||
const void *inp, size_t ilen,
|
||||
bhnd_nvram_type itype, uint32_t flags);
|
||||
|
||||
int bhnd_nvram_val_convert_new(
|
||||
bhnd_nvram_val **value,
|
||||
const bhnd_nvram_val_fmt *fmt,
|
||||
bhnd_nvram_val *src, uint32_t flags);
|
||||
|
||||
bhnd_nvram_val *bhnd_nvram_val_copy(bhnd_nvram_val *value);
|
||||
|
||||
void bhnd_nvram_val_release(
|
||||
@ -78,14 +95,14 @@ int bhnd_nvram_val_vprintf(bhnd_nvram_val *value,
|
||||
|
||||
|
||||
const void *bhnd_nvram_val_bytes(bhnd_nvram_val *value,
|
||||
size_t *len, bhnd_nvram_type *itype);
|
||||
size_t *olen, bhnd_nvram_type *otype);
|
||||
|
||||
bhnd_nvram_type bhnd_nvram_val_type(bhnd_nvram_val *value);
|
||||
bhnd_nvram_type bhnd_nvram_val_elem_type(
|
||||
bhnd_nvram_val *value);
|
||||
|
||||
const void *bhnd_nvram_val_next(bhnd_nvram_val *value,
|
||||
const void *prev, size_t *len);
|
||||
const void *prev, size_t *olen);
|
||||
|
||||
size_t bhnd_nvram_val_nelem(bhnd_nvram_val *value);
|
||||
|
||||
@ -136,7 +153,7 @@ enum {
|
||||
*/
|
||||
typedef enum {
|
||||
/**
|
||||
* The value structure has an automatic or static storage duration
|
||||
* The value structure has an automatic storage duration
|
||||
* (e.g. it is stack allocated, or is otherwise externally managed),
|
||||
* and no destructors will be run prior to deallocation of the value.
|
||||
*
|
||||
@ -153,6 +170,15 @@ typedef enum {
|
||||
* as-is.
|
||||
*/
|
||||
BHND_NVRAM_VAL_STORAGE_DYNAMIC = 2,
|
||||
|
||||
/**
|
||||
* The value structure has a static storage duration, and will never
|
||||
* be deallocated.
|
||||
*
|
||||
* When performing copy/retain, the existing structure may be referenced
|
||||
* without modification.
|
||||
*/
|
||||
BHND_NVRAM_VAL_STORAGE_STATIC = 3,
|
||||
} bhnd_nvram_val_storage;
|
||||
|
||||
/**
|
||||
@ -169,20 +195,21 @@ typedef enum {
|
||||
BHND_NVRAM_VAL_DATA_INLINE = 1,
|
||||
|
||||
/**
|
||||
* Value represented by an external reference to data with a static
|
||||
* storage location. The data need not be copied if copying the value.
|
||||
*/
|
||||
* Value represented by an external reference to data with a static
|
||||
* storage location. The data need not be copied if copying the value.
|
||||
*/
|
||||
BHND_NVRAM_VAL_DATA_EXT_STATIC = 2,
|
||||
|
||||
/**
|
||||
* Value represented by weak external reference, which must be copied
|
||||
* if copying the value */
|
||||
* Value represented by weak external reference, which must be copied
|
||||
* if copying the value.
|
||||
*/
|
||||
BHND_NVRAM_VAL_DATA_EXT_WEAK = 3,
|
||||
|
||||
/**
|
||||
* Value represented by an external reference that must be deallocated
|
||||
* when deallocating the value
|
||||
*/
|
||||
* Value represented by an external reference that must be deallocated
|
||||
* when deallocating the value.
|
||||
*/
|
||||
BHND_NVRAM_VAL_DATA_EXT_ALLOC = 4,
|
||||
} bhnd_nvram_val_data_storage;
|
||||
|
||||
@ -192,34 +219,56 @@ typedef enum {
|
||||
struct bhnd_nvram_val {
|
||||
volatile u_int refs; /**< reference count */
|
||||
bhnd_nvram_val_storage val_storage; /**< value structure storage */
|
||||
const bhnd_nvram_val_fmt *fmt; /**< value format, or NULL for default behavior */
|
||||
const bhnd_nvram_val_fmt *fmt; /**< value format */
|
||||
bhnd_nvram_val_data_storage data_storage; /**< data storage */
|
||||
bhnd_nvram_type data_type; /**< data type */
|
||||
size_t data_len; /**< data size */
|
||||
|
||||
/** data representation */
|
||||
union {
|
||||
uint8_t u8[8]; /**< 8-bit unsigned data */
|
||||
uint16_t u16[4]; /**< 16-bit unsigned data */
|
||||
uint32_t u32[2]; /**< 32-bit unsigned data */
|
||||
uint32_t u64[1]; /**< 64-bit unsigned data */
|
||||
int8_t i8[8]; /**< 8-bit signed data */
|
||||
int16_t i16[4]; /**< 16-bit signed data */
|
||||
int32_t i32[2]; /**< 32-bit signed data */
|
||||
int64_t i64[1]; /**< 64-bit signed data */
|
||||
unsigned char ch[8]; /**< 8-bit character data */
|
||||
const void *ptr; /**< external data */
|
||||
uint8_t u8[8]; /**< 8-bit unsigned data */
|
||||
uint16_t u16[4]; /**< 16-bit unsigned data */
|
||||
uint32_t u32[2]; /**< 32-bit unsigned data */
|
||||
uint32_t u64[1]; /**< 64-bit unsigned data */
|
||||
int8_t i8[8]; /**< 8-bit signed data */
|
||||
int16_t i16[4]; /**< 16-bit signed data */
|
||||
int32_t i32[2]; /**< 32-bit signed data */
|
||||
int64_t i64[1]; /**< 64-bit signed data */
|
||||
unsigned char ch[8]; /**< 8-bit character data */
|
||||
const void *ptr; /**< external data */
|
||||
} data;
|
||||
};
|
||||
|
||||
/** Declare a bhnd_nvram_val_fmt with name @p _n */
|
||||
#define BHND_NVRAM_VAL_TYPE_DECL(_n) \
|
||||
#define BHND_NVRAM_VAL_FMT_DECL(_n) \
|
||||
extern const bhnd_nvram_val_fmt bhnd_nvram_val_ ## _n ## _fmt;
|
||||
|
||||
BHND_NVRAM_VAL_TYPE_DECL(bcm_decimal);
|
||||
BHND_NVRAM_VAL_TYPE_DECL(bcm_hex);
|
||||
BHND_NVRAM_VAL_TYPE_DECL(bcm_leddc);
|
||||
BHND_NVRAM_VAL_TYPE_DECL(bcm_macaddr);
|
||||
BHND_NVRAM_VAL_TYPE_DECL(bcm_string);
|
||||
BHND_NVRAM_VAL_FMT_DECL(bcm_decimal);
|
||||
BHND_NVRAM_VAL_FMT_DECL(bcm_hex);
|
||||
BHND_NVRAM_VAL_FMT_DECL(bcm_leddc);
|
||||
BHND_NVRAM_VAL_FMT_DECL(bcm_macaddr);
|
||||
BHND_NVRAM_VAL_FMT_DECL(bcm_string);
|
||||
|
||||
BHND_NVRAM_VAL_FMT_DECL(uint8);
|
||||
BHND_NVRAM_VAL_FMT_DECL(uint16);
|
||||
BHND_NVRAM_VAL_FMT_DECL(uint32);
|
||||
BHND_NVRAM_VAL_FMT_DECL(uint64);
|
||||
BHND_NVRAM_VAL_FMT_DECL(int8);
|
||||
BHND_NVRAM_VAL_FMT_DECL(int16);
|
||||
BHND_NVRAM_VAL_FMT_DECL(int32);
|
||||
BHND_NVRAM_VAL_FMT_DECL(int64);
|
||||
BHND_NVRAM_VAL_FMT_DECL(char);
|
||||
BHND_NVRAM_VAL_FMT_DECL(string);
|
||||
|
||||
BHND_NVRAM_VAL_FMT_DECL(uint8_array);
|
||||
BHND_NVRAM_VAL_FMT_DECL(uint16_array);
|
||||
BHND_NVRAM_VAL_FMT_DECL(uint32_array);
|
||||
BHND_NVRAM_VAL_FMT_DECL(uint64_array);
|
||||
BHND_NVRAM_VAL_FMT_DECL(int8_array);
|
||||
BHND_NVRAM_VAL_FMT_DECL(int16_array);
|
||||
BHND_NVRAM_VAL_FMT_DECL(int32_array);
|
||||
BHND_NVRAM_VAL_FMT_DECL(int64_array);
|
||||
BHND_NVRAM_VAL_FMT_DECL(char_array);
|
||||
BHND_NVRAM_VAL_FMT_DECL(string_array);
|
||||
|
||||
#endif /* _BHND_NVRAM_BHND_NVRAM_VALUE_H_ */
|
||||
|
@ -143,7 +143,6 @@ const bhnd_nvram_val_fmt bhnd_nvram_val_bcm_leddc_fmt = {
|
||||
.op_encode_elem = bhnd_nvram_val_bcm_leddc_encode_elem,
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Broadcom NVRAM decimal integer format.
|
||||
*
|
||||
@ -199,6 +198,36 @@ static const bhnd_nvram_val_fmt bhnd_nvram_val_bcm_string_csv_fmt = {
|
||||
.op_next = bhnd_nvram_val_bcmstr_csv_next,
|
||||
};
|
||||
|
||||
|
||||
/* Built-in format definitions */
|
||||
#define BHND_NVRAM_VAL_FMT_NATIVE(_n, _type) \
|
||||
const bhnd_nvram_val_fmt bhnd_nvram_val_ ## _n ## _fmt = { \
|
||||
.name = __STRING(_n), \
|
||||
.native_type = BHND_NVRAM_TYPE_ ## _type, \
|
||||
}
|
||||
|
||||
BHND_NVRAM_VAL_FMT_NATIVE(uint8, UINT8);
|
||||
BHND_NVRAM_VAL_FMT_NATIVE(uint16, UINT16);
|
||||
BHND_NVRAM_VAL_FMT_NATIVE(uint32, UINT32);
|
||||
BHND_NVRAM_VAL_FMT_NATIVE(uint64, UINT64);
|
||||
BHND_NVRAM_VAL_FMT_NATIVE(int8, INT8);
|
||||
BHND_NVRAM_VAL_FMT_NATIVE(int16, INT16);
|
||||
BHND_NVRAM_VAL_FMT_NATIVE(int32, INT32);
|
||||
BHND_NVRAM_VAL_FMT_NATIVE(int64, INT64);
|
||||
BHND_NVRAM_VAL_FMT_NATIVE(char, CHAR);
|
||||
BHND_NVRAM_VAL_FMT_NATIVE(string, STRING);
|
||||
|
||||
BHND_NVRAM_VAL_FMT_NATIVE(uint8_array, UINT8_ARRAY);
|
||||
BHND_NVRAM_VAL_FMT_NATIVE(uint16_array, UINT16_ARRAY);
|
||||
BHND_NVRAM_VAL_FMT_NATIVE(uint32_array, UINT32_ARRAY);
|
||||
BHND_NVRAM_VAL_FMT_NATIVE(uint64_array, UINT64_ARRAY);
|
||||
BHND_NVRAM_VAL_FMT_NATIVE(int8_array, INT8_ARRAY);
|
||||
BHND_NVRAM_VAL_FMT_NATIVE(int16_array, INT16_ARRAY);
|
||||
BHND_NVRAM_VAL_FMT_NATIVE(int32_array, INT32_ARRAY);
|
||||
BHND_NVRAM_VAL_FMT_NATIVE(int64_array, INT64_ARRAY);
|
||||
BHND_NVRAM_VAL_FMT_NATIVE(char_array, CHAR_ARRAY);
|
||||
BHND_NVRAM_VAL_FMT_NATIVE(string_array, STRING_ARRAY);
|
||||
|
||||
/**
|
||||
* Common hex/decimal integer filter implementation.
|
||||
*/
|
||||
@ -292,9 +321,7 @@ bhnd_nvram_val_bcm_hex_encode_elem(bhnd_nvram_val *value, const void *inp,
|
||||
* their native width (width * two hex characters), and we do the same
|
||||
* for compatibility
|
||||
*/
|
||||
|
||||
width = bhnd_nvram_value_size(itype, NULL, 0, 1) * 2;
|
||||
|
||||
width = bhnd_nvram_type_width(itype) * 2;
|
||||
return (bhnd_nvram_value_printf("0x%0*I64X", inp, ilen, itype,
|
||||
outp, olen, width));
|
||||
}
|
||||
@ -652,16 +679,9 @@ bhnd_nvram_val_bcmstr_csv_next(bhnd_nvram_val *value, const void *prev,
|
||||
return (next);
|
||||
|
||||
case BHND_NVRAM_TYPE_STRING_ARRAY:
|
||||
next = bhnd_nvram_string_array_next(inp, ilen, prev);
|
||||
if (next != NULL) {
|
||||
*len = strlen(next);
|
||||
|
||||
/* Account for trailing NUL */
|
||||
if (*len + (size_t)(next - inp) < ilen)
|
||||
(*len)++;
|
||||
}
|
||||
|
||||
return (next);
|
||||
/* Delegate to default array iteration */
|
||||
return (bhnd_nvram_value_array_next(inp, ilen, itype, prev,
|
||||
len));
|
||||
default:
|
||||
BHND_NV_PANIC("unsupported type: %d", itype);
|
||||
}
|
||||
|
@ -830,8 +830,7 @@ bhnd_nvram_val_vprintf(bhnd_nvram_val *value, const char *fmt, char *outp,
|
||||
char c;
|
||||
|
||||
arg_type = BHND_NVRAM_TYPE_CHAR;
|
||||
arg_size = bhnd_nvram_value_size(arg_type, NULL,
|
||||
0, 1);
|
||||
arg_size = bhnd_nvram_type_width(arg_type);
|
||||
|
||||
/* Encode as single character */
|
||||
error = bhnd_nvram_val_encode_elem(value, elem,
|
||||
|
513
sys/dev/bhnd/nvram/bhnd_nvram_value_subr.c
Normal file
513
sys/dev/bhnd/nvram/bhnd_nvram_value_subr.c
Normal file
@ -0,0 +1,513 @@
|
||||
/*-
|
||||
* Copyright (c) 2015-2016 Landon Fuller <landonf@FreeBSD.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer,
|
||||
* without modification.
|
||||
* 2. Redistributions in binary form must reproduce at minimum a disclaimer
|
||||
* similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
|
||||
* redistribution must be conditioned upon including a substantially
|
||||
* similar Disclaimer requirement for further binary redistribution.
|
||||
*
|
||||
* NO WARRANTY
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
|
||||
* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
|
||||
* THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,
|
||||
* OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
|
||||
* IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
* THE POSSIBILITY OF SUCH DAMAGES.
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
#include <sys/param.h>
|
||||
|
||||
#ifdef _KERNEL
|
||||
|
||||
#include <sys/systm.h>
|
||||
|
||||
#else /* !_KERNEL */
|
||||
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
|
||||
#endif /* _KERNEL */
|
||||
|
||||
#include "bhnd_nvram_private.h"
|
||||
#include "bhnd_nvram_valuevar.h"
|
||||
|
||||
/**
|
||||
* Validate the alignment of a value of @p type.
|
||||
*
|
||||
* @param inp The value data.
|
||||
* @param ilen The value length, in bytes.
|
||||
* @param itype The value type.
|
||||
*
|
||||
* @retval 0 success
|
||||
* @retval EFTYPE if @p type is not an array type, and @p len is not
|
||||
* equal to the size of a single element of @p type.
|
||||
* @retval EFAULT if @p data is not correctly aligned to the required
|
||||
* host alignment.
|
||||
* @retval EFAULT if @p len is not aligned to the @p type width.
|
||||
*/
|
||||
int
|
||||
bhnd_nvram_value_check_aligned(const void *inp, size_t ilen,
|
||||
bhnd_nvram_type itype)
|
||||
{
|
||||
size_t align, width;
|
||||
|
||||
/* Check pointer alignment against the required host alignment */
|
||||
align = bhnd_nvram_type_host_align(itype);
|
||||
BHND_NV_ASSERT(align != 0, ("invalid zero alignment"));
|
||||
if ((uintptr_t)inp % align != 0)
|
||||
return (EFAULT);
|
||||
|
||||
/* If type is not fixed width, nothing else to check */
|
||||
width = bhnd_nvram_type_width(itype);
|
||||
if (width == 0)
|
||||
return (0);
|
||||
|
||||
/* Length must be aligned to the element width */
|
||||
if (ilen % width != 0)
|
||||
return (EFAULT);
|
||||
|
||||
/* If the type is not an array type, the length must be equal to the
|
||||
* size of a single element of @p type. */
|
||||
if (!bhnd_nvram_is_array_type(itype) && ilen != width)
|
||||
return (EFTYPE);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate the number of elements represented by a value of @p ilen bytes
|
||||
* with @p itype.
|
||||
*
|
||||
* @param inp The value data.
|
||||
* @param ilen The value length.
|
||||
* @param itype The value type.
|
||||
* @param[out] nelem On success, the number of elements.
|
||||
*
|
||||
* @retval 0 success
|
||||
* @retval EINVAL if @p inp is NULL and the element count of @p itype
|
||||
* cannot be determined without parsing the value data.
|
||||
* @retval EFTYPE if @p itype is not an array type, and @p ilen is not
|
||||
* equal to the size of a single element of @p itype.
|
||||
* @retval EFAULT if @p ilen is not correctly aligned for elements of
|
||||
* @p itype.
|
||||
*/
|
||||
int
|
||||
bhnd_nvram_value_nelem(const void *inp, size_t ilen, bhnd_nvram_type itype,
|
||||
size_t *nelem)
|
||||
{
|
||||
int error;
|
||||
|
||||
BHND_NV_ASSERT(inp != NULL, ("NULL inp"));
|
||||
|
||||
/* Check alignment */
|
||||
if ((error = bhnd_nvram_value_check_aligned(inp, ilen, itype)))
|
||||
return (error);
|
||||
|
||||
switch (itype) {
|
||||
case BHND_NVRAM_TYPE_STRING:
|
||||
/* Always exactly one element */
|
||||
*nelem = 1;
|
||||
return (0);
|
||||
|
||||
case BHND_NVRAM_TYPE_STRING_ARRAY: {
|
||||
const char *p;
|
||||
size_t nleft;
|
||||
|
||||
/* Iterate over the NUL-terminated strings to calculate
|
||||
* total element count */
|
||||
p = inp;
|
||||
nleft = ilen;
|
||||
*nelem = 0;
|
||||
while (nleft > 0) {
|
||||
size_t slen;
|
||||
|
||||
/* Increment element count */
|
||||
(*nelem)++;
|
||||
|
||||
/* Determine string length */
|
||||
slen = strnlen(p, nleft);
|
||||
nleft -= slen;
|
||||
|
||||
/* Advance input */
|
||||
p += slen;
|
||||
|
||||
/* Account for trailing NUL, if we haven't hit the end
|
||||
* of the input */
|
||||
if (nleft > 0) {
|
||||
nleft--;
|
||||
p++;
|
||||
}
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
case BHND_NVRAM_TYPE_UINT8_ARRAY:
|
||||
case BHND_NVRAM_TYPE_UINT16_ARRAY:
|
||||
case BHND_NVRAM_TYPE_UINT32_ARRAY:
|
||||
case BHND_NVRAM_TYPE_UINT64_ARRAY:
|
||||
case BHND_NVRAM_TYPE_INT8_ARRAY:
|
||||
case BHND_NVRAM_TYPE_INT16_ARRAY:
|
||||
case BHND_NVRAM_TYPE_INT32_ARRAY:
|
||||
case BHND_NVRAM_TYPE_INT64_ARRAY:
|
||||
case BHND_NVRAM_TYPE_CHAR_ARRAY: {
|
||||
size_t width = bhnd_nvram_type_width(itype);
|
||||
BHND_NV_ASSERT(width != 0, ("invalid width"));
|
||||
|
||||
*nelem = ilen / width;
|
||||
return (0);
|
||||
}
|
||||
|
||||
case BHND_NVRAM_TYPE_INT8:
|
||||
case BHND_NVRAM_TYPE_UINT8:
|
||||
case BHND_NVRAM_TYPE_CHAR:
|
||||
case BHND_NVRAM_TYPE_INT16:
|
||||
case BHND_NVRAM_TYPE_UINT16:
|
||||
case BHND_NVRAM_TYPE_INT32:
|
||||
case BHND_NVRAM_TYPE_UINT32:
|
||||
case BHND_NVRAM_TYPE_INT64:
|
||||
case BHND_NVRAM_TYPE_UINT64:
|
||||
/* Length must be equal to the size of exactly one
|
||||
* element (arrays can represent zero elements -- non-array
|
||||
* types cannot) */
|
||||
if (ilen != bhnd_nvram_type_width(itype))
|
||||
return (EFTYPE);
|
||||
*nelem = 1;
|
||||
return (0);
|
||||
}
|
||||
|
||||
/* Quiesce gcc4.2 */
|
||||
BHND_NV_PANIC("bhnd nvram type %u unknown", itype);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the size, in bytes, of a value of @p itype with @p nelem elements.
|
||||
*
|
||||
* @param inp The actual data to be queried, or NULL if unknown. If
|
||||
* NULL and the base type is not a fixed width type
|
||||
* (e.g. BHND_NVRAM_TYPE_STRING), 0 will be returned.
|
||||
* @param ilen The size of @p inp, in bytes, or 0 if @p inp is NULL.
|
||||
* @param itype The value type.
|
||||
* @param nelem The number of elements. If @p itype is not an array
|
||||
* type, this value must be 1.
|
||||
*
|
||||
* @retval 0 If @p itype has a variable width, and @p inp is NULL.
|
||||
* @retval 0 If a @p nelem value greater than 1 is provided for a
|
||||
* non-array @p itype.
|
||||
* @retval 0 If a @p nelem value of 0 is provided.
|
||||
* @retval 0 If the result would exceed the maximum value
|
||||
* representable by size_t.
|
||||
* @retval 0 If @p itype is BHND_NVRAM_TYPE_NULL.
|
||||
* @retval non-zero The size, in bytes, of @p itype with @p nelem elements.
|
||||
*/
|
||||
size_t
|
||||
bhnd_nvram_value_size(const void *inp, size_t ilen, bhnd_nvram_type itype,
|
||||
size_t nelem)
|
||||
{
|
||||
/* If nelem 0, nothing to do */
|
||||
if (nelem == 0)
|
||||
return (0);
|
||||
|
||||
/* Non-array types must have an nelem value of 1 */
|
||||
if (!bhnd_nvram_is_array_type(itype) && nelem != 1)
|
||||
return (0);
|
||||
|
||||
switch (itype) {
|
||||
case BHND_NVRAM_TYPE_UINT8_ARRAY:
|
||||
case BHND_NVRAM_TYPE_UINT16_ARRAY:
|
||||
case BHND_NVRAM_TYPE_UINT32_ARRAY:
|
||||
case BHND_NVRAM_TYPE_UINT64_ARRAY:
|
||||
case BHND_NVRAM_TYPE_INT8_ARRAY:
|
||||
case BHND_NVRAM_TYPE_INT16_ARRAY:
|
||||
case BHND_NVRAM_TYPE_INT32_ARRAY:
|
||||
case BHND_NVRAM_TYPE_INT64_ARRAY:
|
||||
case BHND_NVRAM_TYPE_CHAR_ARRAY: {
|
||||
size_t width;
|
||||
|
||||
width = bhnd_nvram_type_width(itype);
|
||||
|
||||
/* Would nelem * width overflow? */
|
||||
if (SIZE_MAX / nelem < width) {
|
||||
BHND_NV_LOG("cannot represent size %s[%zu]\n",
|
||||
bhnd_nvram_type_name(bhnd_nvram_base_type(itype)),
|
||||
nelem);
|
||||
return (0);
|
||||
}
|
||||
|
||||
return (nelem * width);
|
||||
}
|
||||
|
||||
case BHND_NVRAM_TYPE_STRING_ARRAY: {
|
||||
const char *p;
|
||||
size_t total_size;
|
||||
|
||||
if (inp == NULL)
|
||||
return (0);
|
||||
|
||||
/* Iterate over the NUL-terminated strings to calculate
|
||||
* total byte length */
|
||||
p = inp;
|
||||
total_size = 0;
|
||||
for (size_t i = 0; i < nelem; i++) {
|
||||
size_t elem_size;
|
||||
|
||||
elem_size = strnlen(p, ilen - total_size);
|
||||
p += elem_size;
|
||||
|
||||
/* Check for (and skip) terminating NUL */
|
||||
if (total_size < ilen && *p == '\0') {
|
||||
elem_size++;
|
||||
p++;
|
||||
}
|
||||
|
||||
/* Would total_size + elem_size overflow?
|
||||
*
|
||||
* A memory range larger than SIZE_MAX shouldn't be,
|
||||
* possible, but include the check for completeness */
|
||||
if (SIZE_MAX - total_size < elem_size)
|
||||
return (0);
|
||||
|
||||
total_size += elem_size;
|
||||
}
|
||||
|
||||
return (total_size);
|
||||
}
|
||||
|
||||
case BHND_NVRAM_TYPE_STRING: {
|
||||
size_t size;
|
||||
|
||||
if (inp == NULL)
|
||||
return (0);
|
||||
|
||||
/* Find length */
|
||||
size = strnlen(inp, ilen);
|
||||
|
||||
/* Is there a terminating NUL, or did we just hit the
|
||||
* end of the string input */
|
||||
if (size < ilen)
|
||||
size++;
|
||||
|
||||
return (size);
|
||||
}
|
||||
|
||||
case BHND_NVRAM_TYPE_INT8:
|
||||
case BHND_NVRAM_TYPE_UINT8:
|
||||
case BHND_NVRAM_TYPE_CHAR:
|
||||
return (sizeof(uint8_t));
|
||||
|
||||
case BHND_NVRAM_TYPE_INT16:
|
||||
case BHND_NVRAM_TYPE_UINT16:
|
||||
return (sizeof(uint16_t));
|
||||
|
||||
case BHND_NVRAM_TYPE_INT32:
|
||||
case BHND_NVRAM_TYPE_UINT32:
|
||||
return (sizeof(uint32_t));
|
||||
|
||||
case BHND_NVRAM_TYPE_UINT64:
|
||||
case BHND_NVRAM_TYPE_INT64:
|
||||
return (sizeof(uint64_t));
|
||||
}
|
||||
|
||||
/* Quiesce gcc4.2 */
|
||||
BHND_NV_PANIC("bhnd nvram type %u unknown", itype);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Format a string representation of @p inp using @p fmt, with, writing the
|
||||
* result to @p outp.
|
||||
*
|
||||
* Refer to bhnd_nvram_val_vprintf() for full format string documentation.
|
||||
*
|
||||
* @param fmt The format string.
|
||||
* @param inp The value to be formatted.
|
||||
* @param ilen The size of @p inp, in bytes.
|
||||
* @param itype The type of @p inp.
|
||||
* @param[out] outp On success, the string value 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 outp. On success, will be set
|
||||
* to the actual size of the formatted string.
|
||||
*
|
||||
* @retval 0 success
|
||||
* @retval EINVAL If @p fmt contains unrecognized format string
|
||||
* specifiers.
|
||||
* @retval ENOMEM If the @p outp is non-NULL, and the provided @p olen
|
||||
* is too small to hold the encoded value.
|
||||
* @retval EFTYPE If value coercion from @p inp to a string value via
|
||||
* @p fmt is unsupported.
|
||||
* @retval ERANGE If value coercion of @p value would overflow (or
|
||||
* underflow) the representation defined by @p fmt.
|
||||
*/
|
||||
int
|
||||
bhnd_nvram_value_printf(const char *fmt, const void *inp, size_t ilen,
|
||||
bhnd_nvram_type itype, char *outp, size_t *olen, ...)
|
||||
{
|
||||
va_list ap;
|
||||
int error;
|
||||
|
||||
va_start(ap, olen);
|
||||
error = bhnd_nvram_value_vprintf(fmt, inp, ilen, itype, outp, olen, ap);
|
||||
va_end(ap);
|
||||
|
||||
return (error);
|
||||
}
|
||||
|
||||
/**
|
||||
* Format a string representation of @p inp using @p fmt, with, writing the
|
||||
* result to @p outp.
|
||||
*
|
||||
* Refer to bhnd_nvram_val_vprintf() for full format string documentation.
|
||||
*
|
||||
* @param fmt The format string.
|
||||
* @param inp The value to be formatted.
|
||||
* @param ilen The size of @p inp, in bytes.
|
||||
* @param itype The type of @p inp.
|
||||
* @param[out] outp On success, the string value 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 outp. On success, will be set
|
||||
* to the actual size of the formatted string.
|
||||
* @param ap Argument list.
|
||||
*
|
||||
* @retval 0 success
|
||||
* @retval EINVAL If @p fmt contains unrecognized format string
|
||||
* specifiers.
|
||||
* @retval ENOMEM If the @p outp is non-NULL, and the provided @p olen
|
||||
* is too small to hold the encoded value.
|
||||
* @retval EFTYPE If value coercion from @p inp to a string value via
|
||||
* @p fmt is unsupported.
|
||||
* @retval ERANGE If value coercion of @p value would overflow (or
|
||||
* underflow) the representation defined by @p fmt.
|
||||
*/
|
||||
int
|
||||
bhnd_nvram_value_vprintf(const char *fmt, const void *inp, size_t ilen,
|
||||
bhnd_nvram_type itype, char *outp, size_t *olen, va_list ap)
|
||||
{
|
||||
bhnd_nvram_val val;
|
||||
int error;
|
||||
|
||||
/* Map input buffer as a value instance */
|
||||
error = bhnd_nvram_val_init(&val, NULL, inp, ilen, itype,
|
||||
BHND_NVRAM_VAL_BORROW_DATA);
|
||||
if (error)
|
||||
return (error);
|
||||
|
||||
/* Attempt to format the value */
|
||||
error = bhnd_nvram_val_vprintf(&val, fmt, outp, olen, ap);
|
||||
|
||||
/* Clean up */
|
||||
bhnd_nvram_val_release(&val);
|
||||
return (error);
|
||||
}
|
||||
|
||||
/**
|
||||
* Iterate over all elements in @p inp.
|
||||
*
|
||||
* @param inp The value to be iterated.
|
||||
* @param ilen The size, in bytes, of @p inp.
|
||||
* @param itype The data type of @p inp.
|
||||
* @param prev The value previously returned by
|
||||
* bhnd_nvram_value_array_next(), or NULL to begin
|
||||
* iteration.
|
||||
* @param[in,out] olen If @p prev is non-NULL, @p olen must be a
|
||||
* pointer to the length previously returned by
|
||||
* bhnd_nvram_value_array_next(). On success, will
|
||||
* be set to the next element's length, in bytes.
|
||||
*
|
||||
* @retval non-NULL A borrowed reference to the next element of @p inp.
|
||||
* @retval NULL If the end of the array is reached.
|
||||
*/
|
||||
const void *
|
||||
bhnd_nvram_value_array_next(const void *inp, size_t ilen, bhnd_nvram_type itype,
|
||||
const void *prev, size_t *olen)
|
||||
{
|
||||
const u_char *next;
|
||||
size_t offset;
|
||||
|
||||
/* Handle first element */
|
||||
if (prev == NULL) {
|
||||
/* Zero-length array? */
|
||||
if (ilen == 0)
|
||||
return (NULL);
|
||||
|
||||
*olen = bhnd_nvram_value_size(inp, ilen, itype, 1);
|
||||
return (inp);
|
||||
}
|
||||
|
||||
/* Advance to next element */
|
||||
BHND_NV_ASSERT(prev >= (const void *)inp, ("invalid cookiep"));
|
||||
next = (const u_char *)prev + *olen;
|
||||
offset = (size_t)(next - (const u_char *)inp);
|
||||
|
||||
if (offset >= ilen) {
|
||||
/* Hit end of the array */
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
/* Determine element size */
|
||||
*olen = bhnd_nvram_value_size(next, ilen - offset, itype, 1);
|
||||
if (ilen - offset < *olen) {
|
||||
BHND_NV_LOG("short element of type %s -- misaligned "
|
||||
"representation", bhnd_nvram_type_name(itype));
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
return (next);
|
||||
}
|
||||
|
||||
/**
|
||||
* Coerce value @p inp of type @p itype to @p otype, writing the
|
||||
* result to @p outp.
|
||||
*
|
||||
* @param inp The value to be coerced.
|
||||
* @param ilen The size of @p inp, in bytes.
|
||||
* @param itype The base data type of @p inp.
|
||||
* @param[out] outp On success, the value 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 outp. On success, will be set
|
||||
* to the actual size of the requested value.
|
||||
* @param otype The data type to be written to @p outp.
|
||||
*
|
||||
* @retval 0 success
|
||||
* @retval ENOMEM If @p outp is non-NULL and a buffer of @p olen is too
|
||||
* small to hold the requested value.
|
||||
* @retval EFTYPE If the variable data cannot be coerced to @p otype.
|
||||
* @retval ERANGE If value coercion would overflow @p otype.
|
||||
*/
|
||||
int
|
||||
bhnd_nvram_value_coerce(const void *inp, size_t ilen, bhnd_nvram_type itype,
|
||||
void *outp, size_t *olen, bhnd_nvram_type otype)
|
||||
{
|
||||
bhnd_nvram_val val;
|
||||
int error;
|
||||
|
||||
/* Wrap input buffer in a value instance */
|
||||
error = bhnd_nvram_val_init(&val, NULL, inp, ilen,
|
||||
itype, BHND_NVRAM_VAL_BORROW_DATA|BHND_NVRAM_VAL_FIXED);
|
||||
if (error)
|
||||
return (error);
|
||||
|
||||
/* Try to encode as requested type */
|
||||
error = bhnd_nvram_val_encode(&val, outp, olen, otype);
|
||||
|
||||
/* Clean up and return error */
|
||||
bhnd_nvram_val_release(&val);
|
||||
return (error);
|
||||
}
|
@ -40,7 +40,8 @@ int bhnd_nvram_val_generic_encode_elem(bhnd_nvram_val *value,
|
||||
const void *inp, size_t ilen, void *outp, size_t *olen,
|
||||
bhnd_nvram_type otype);
|
||||
const void *bhnd_nvram_val_generic_next(bhnd_nvram_val *value,
|
||||
const void *prev, size_t *len);
|
||||
const void *prev, size_t *olen);
|
||||
|
||||
/**
|
||||
* Filter input data prior to initialization.
|
||||
*
|
||||
@ -74,7 +75,7 @@ typedef int (bhnd_nvram_val_op_encode_elem)(bhnd_nvram_val *value,
|
||||
|
||||
/** @see bhnd_nvram_val_next() */
|
||||
typedef const void *(bhnd_nvram_val_op_next)(bhnd_nvram_val *value,
|
||||
const void *prev, size_t *len);
|
||||
const void *prev, size_t *olen);
|
||||
|
||||
/** @see bhnd_nvram_val_nelem() */
|
||||
typedef size_t (bhnd_nvram_val_op_nelem)(bhnd_nvram_val *value);
|
||||
@ -89,7 +90,6 @@ typedef size_t (bhnd_nvram_val_op_nelem)(bhnd_nvram_val *value);
|
||||
struct bhnd_nvram_val_fmt {
|
||||
const char *name; /**< type name */
|
||||
bhnd_nvram_type native_type; /**< native value representation */
|
||||
|
||||
bhnd_nvram_val_op_filter *op_filter;
|
||||
bhnd_nvram_val_op_encode *op_encode;
|
||||
bhnd_nvram_val_op_encode_elem *op_encode_elem;
|
||||
|
@ -42,6 +42,7 @@ SRCS+= bhnd_nvram_data.c \
|
||||
bhnd_nvram_value.c \
|
||||
bhnd_nvram_value_fmts.c \
|
||||
bhnd_nvram_value_prf.c \
|
||||
bhnd_nvram_value_subr.c \
|
||||
bhnd_sprom.c
|
||||
SRCS+= bhnd_nvram_map.h bhnd_nvram_map_data.h
|
||||
SRCS+= bhnd_nvram_if.c bhnd_nvram_if.h
|
||||
|
Loading…
x
Reference in New Issue
Block a user