Index: head/sys/conf/files =================================================================== --- head/sys/conf/files +++ head/sys/conf/files @@ -1247,6 +1247,7 @@ 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 Index: head/sys/dev/bhnd/nvram/bhnd_nvram.h =================================================================== --- head/sys/dev/bhnd/nvram/bhnd_nvram.h +++ head/sys/dev/bhnd/nvram/bhnd_nvram.h @@ -111,14 +111,16 @@ 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_ */ Index: head/sys/dev/bhnd/nvram/bhnd_nvram_data_bcm.c =================================================================== --- head/sys/dev/bhnd/nvram/bhnd_nvram_data_bcm.c +++ head/sys/dev/bhnd/nvram/bhnd_nvram_data_bcm.c @@ -647,10 +647,8 @@ /* 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; Index: head/sys/dev/bhnd/nvram/bhnd_nvram_data_sprom.c =================================================================== --- head/sys/dev/bhnd/nvram/bhnd_nvram_data_sprom.c +++ head/sys/dev/bhnd/nvram/bhnd_nvram_data_sprom.c @@ -597,7 +597,7 @@ } 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 @@ 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 @@ } /* 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); Index: head/sys/dev/bhnd/nvram/bhnd_nvram_private.h =================================================================== --- head/sys/dev/bhnd/nvram/bhnd_nvram_private.h +++ head/sys/dev/bhnd/nvram/bhnd_nvram_private.h @@ -167,11 +167,15 @@ 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 @@ 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( Index: head/sys/dev/bhnd/nvram/bhnd_nvram_store.c =================================================================== --- head/sys/dev/bhnd/nvram/bhnd_nvram_store.c +++ head/sys/dev/bhnd/nvram/bhnd_nvram_store.c @@ -288,7 +288,7 @@ /* 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) */ Index: head/sys/dev/bhnd/nvram/bhnd_nvram_subr.c =================================================================== --- head/sys/dev/bhnd/nvram/bhnd_nvram_subr.c +++ head/sys/dev/bhnd/nvram/bhnd_nvram_subr.c @@ -71,12 +71,6 @@ 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,112 +337,44 @@ } /** - * 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. + * 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 type to query. */ -int -bhnd_nvram_value_nelem(bhnd_nvram_type type, const void *data, size_t len, - size_t *nelem) +size_t +bhnd_nvram_type_width(bhnd_nvram_type type) { - 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; + case BHND_NVRAM_TYPE_STRING_ARRAY: return (0); + 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_UINT16_ARRAY: - case BHND_NVRAM_TYPE_UINT32_ARRAY: - case BHND_NVRAM_TYPE_UINT64_ARRAY: + case BHND_NVRAM_TYPE_INT8: case BHND_NVRAM_TYPE_INT8_ARRAY: + return (sizeof(uint8_t)); + + 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_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: - case BHND_NVRAM_TYPE_CHAR_ARRAY: - BHND_NV_ASSERT(base_size != 0, ("invalid base size")); - *nelem = len / base_size; - return (0); + return (sizeof(uint64_t)); } /* Quiesce gcc4.2 */ @@ -456,130 +382,43 @@ } /** - * Return the size, in bytes, of a value of @p type with @p nelem elements. + * Return the native host alignment for values of @p 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_host_align(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_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: - 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; - - 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); - } + return (_Alignof(uint64_t)); case BHND_NVRAM_TYPE_INT8: - case BHND_NVRAM_TYPE_UINT8: - case BHND_NVRAM_TYPE_CHAR: - return (sizeof(uint8_t)); - + case BHND_NVRAM_TYPE_INT8_ARRAY: + return (_Alignof(int8_t)); case BHND_NVRAM_TYPE_INT16: - case BHND_NVRAM_TYPE_UINT16: - return (sizeof(uint16_t)); - + case BHND_NVRAM_TYPE_INT16_ARRAY: + return (_Alignof(int16_t)); case BHND_NVRAM_TYPE_INT32: - case BHND_NVRAM_TYPE_UINT32: - return (sizeof(uint32_t)); - - case BHND_NVRAM_TYPE_UINT64: + case BHND_NVRAM_TYPE_INT32_ARRAY: + return (_Alignof(int32_t)); case BHND_NVRAM_TYPE_INT64: - return (sizeof(uint64_t)); + case BHND_NVRAM_TYPE_INT64_ARRAY: + return (_Alignof(int64_t)); } /* Quiesce gcc4.2 */ @@ -587,132 +426,30 @@ } /** - * Iterate over all strings in the @p inp string array. + * 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() */ @@ -825,47 +562,6 @@ } /** - * 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 * strtoul(). @@ -1114,7 +810,7 @@ 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) Index: head/sys/dev/bhnd/nvram/bhnd_nvram_value.h =================================================================== --- head/sys/dev/bhnd/nvram/bhnd_nvram_value.h +++ head/sys/dev/bhnd/nvram/bhnd_nvram_value.h @@ -32,6 +32,7 @@ #ifndef _BHND_NVRAM_BHND_NVRAM_VALUE_H_ #define _BHND_NVRAM_BHND_NVRAM_VALUE_H_ + #include #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 @@ 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 @@ */ 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 @@ * 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 @@ 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 @@ 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_ */ Index: head/sys/dev/bhnd/nvram/bhnd_nvram_value.c =================================================================== --- head/sys/dev/bhnd/nvram/bhnd_nvram_value.c +++ head/sys/dev/bhnd/nvram/bhnd_nvram_value.c @@ -35,6 +35,7 @@ #ifdef _KERNEL +#include #include #include #include @@ -43,6 +44,7 @@ #else /* !_KERNEL */ +#include #include #include #include @@ -54,6 +56,8 @@ #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_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 @@ 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 @@ 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 @@ 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 * 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_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_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 @@ /* 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 @@ * 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_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 @@ 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 @@ * @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 @@ * @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 @@ 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 @@ * 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 @@ /* 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 @@ 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 @@ 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 @@ 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 @@ */ 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_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 @@ #define NV_STORE_INIT_INLINE() do { \ value->data_len = ilen; \ + value->data_type = itype; \ } while(0) #define NV_STORE_INLINE(_type, _dest) do { \ Index: head/sys/dev/bhnd/nvram/bhnd_nvram_value_fmts.c =================================================================== --- head/sys/dev/bhnd/nvram/bhnd_nvram_value_fmts.c +++ head/sys/dev/bhnd/nvram/bhnd_nvram_value_fmts.c @@ -143,7 +143,6 @@ .op_encode_elem = bhnd_nvram_val_bcm_leddc_encode_elem, }; - /** * Broadcom NVRAM decimal integer format. * @@ -199,6 +198,36 @@ .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 @@ * 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 @@ 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); } Index: head/sys/dev/bhnd/nvram/bhnd_nvram_value_prf.c =================================================================== --- head/sys/dev/bhnd/nvram/bhnd_nvram_value_prf.c +++ head/sys/dev/bhnd/nvram/bhnd_nvram_value_prf.c @@ -830,8 +830,7 @@ 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, Index: head/sys/dev/bhnd/nvram/bhnd_nvram_value_subr.c =================================================================== --- head/sys/dev/bhnd/nvram/bhnd_nvram_value_subr.c +++ head/sys/dev/bhnd/nvram/bhnd_nvram_value_subr.c @@ -0,0 +1,513 @@ +/*- + * Copyright (c) 2015-2016 Landon Fuller + * 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 +__FBSDID("$FreeBSD$"); + +#include + +#ifdef _KERNEL + +#include + +#else /* !_KERNEL */ + +#include +#include + +#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); +} Index: head/sys/dev/bhnd/nvram/bhnd_nvram_valuevar.h =================================================================== --- head/sys/dev/bhnd/nvram/bhnd_nvram_valuevar.h +++ head/sys/dev/bhnd/nvram/bhnd_nvram_valuevar.h @@ -40,7 +40,8 @@ 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 @@ /** @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 @@ 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; Index: head/sys/modules/bhnd/Makefile =================================================================== --- head/sys/modules/bhnd/Makefile +++ head/sys/modules/bhnd/Makefile @@ -42,6 +42,7 @@ 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