From owner-svn-src-all@freebsd.org Mon Dec 19 20:20:35 2016 Return-Path: Delivered-To: svn-src-all@mailman.ysv.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:1900:2254:206a::19:1]) by mailman.ysv.freebsd.org (Postfix) with ESMTP id D4CF7C885D4; Mon, 19 Dec 2016 20:20:35 +0000 (UTC) (envelope-from landonf@FreeBSD.org) Received: from repo.freebsd.org (repo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by mx1.freebsd.org (Postfix) with ESMTPS id 9CED911A7; Mon, 19 Dec 2016 20:20:35 +0000 (UTC) (envelope-from landonf@FreeBSD.org) Received: from repo.freebsd.org ([127.0.1.37]) by repo.freebsd.org (8.15.2/8.15.2) with ESMTP id uBJKKYT1052386; Mon, 19 Dec 2016 20:20:34 GMT (envelope-from landonf@FreeBSD.org) Received: (from landonf@localhost) by repo.freebsd.org (8.15.2/8.15.2/Submit) id uBJKKY0O052377; Mon, 19 Dec 2016 20:20:34 GMT (envelope-from landonf@FreeBSD.org) Message-Id: <201612192020.uBJKKY0O052377@repo.freebsd.org> X-Authentication-Warning: repo.freebsd.org: landonf set sender to landonf@FreeBSD.org using -f From: "Landon J. Fuller" Date: Mon, 19 Dec 2016 20:20:34 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r310292 - in head/sys: conf dev/bhnd/nvram modules/bhnd X-SVN-Group: head MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-all@freebsd.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: "SVN commit messages for the entire src tree \(except for " user" and " projects" \)" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 19 Dec 2016 20:20:35 -0000 Author: landonf Date: Mon Dec 19 20:20:33 2016 New Revision: 310292 URL: https://svnweb.freebsd.org/changeset/base/310292 Log: 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 Added: head/sys/dev/bhnd/nvram/bhnd_nvram_value_subr.c (contents, props changed) Modified: head/sys/conf/files head/sys/dev/bhnd/nvram/bhnd_nvram.h head/sys/dev/bhnd/nvram/bhnd_nvram_data_bcm.c head/sys/dev/bhnd/nvram/bhnd_nvram_data_sprom.c head/sys/dev/bhnd/nvram/bhnd_nvram_private.h head/sys/dev/bhnd/nvram/bhnd_nvram_store.c head/sys/dev/bhnd/nvram/bhnd_nvram_subr.c head/sys/dev/bhnd/nvram/bhnd_nvram_value.c head/sys/dev/bhnd/nvram/bhnd_nvram_value.h head/sys/dev/bhnd/nvram/bhnd_nvram_value_fmts.c head/sys/dev/bhnd/nvram/bhnd_nvram_value_prf.c head/sys/dev/bhnd/nvram/bhnd_nvram_valuevar.h head/sys/modules/bhnd/Makefile Modified: head/sys/conf/files ============================================================================== --- head/sys/conf/files Mon Dec 19 20:11:48 2016 (r310291) +++ head/sys/conf/files Mon Dec 19 20:20:33 2016 (r310292) @@ -1247,6 +1247,7 @@ dev/bhnd/nvram/bhnd_nvram_subr.c optiona 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 Modified: head/sys/dev/bhnd/nvram/bhnd_nvram.h ============================================================================== --- head/sys/dev/bhnd/nvram/bhnd_nvram.h Mon Dec 19 20:11:48 2016 (r310291) +++ head/sys/dev/bhnd/nvram/bhnd_nvram.h Mon Dec 19 20:20:33 2016 (r310292) @@ -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_ */ Modified: head/sys/dev/bhnd/nvram/bhnd_nvram_data_bcm.c ============================================================================== --- head/sys/dev/bhnd/nvram/bhnd_nvram_data_bcm.c Mon Dec 19 20:11:48 2016 (r310291) +++ head/sys/dev/bhnd/nvram/bhnd_nvram_data_bcm.c Mon Dec 19 20:20:33 2016 (r310292) @@ -647,10 +647,8 @@ bhnd_nvram_bcm_getvar_ptr(struct bhnd_nv /* 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; Modified: head/sys/dev/bhnd/nvram/bhnd_nvram_data_sprom.c ============================================================================== --- head/sys/dev/bhnd/nvram/bhnd_nvram_data_sprom.c Mon Dec 19 20:11:48 2016 (r310291) +++ head/sys/dev/bhnd/nvram/bhnd_nvram_data_sprom.c Mon Dec 19 20:20:33 2016 (r310292) @@ -597,7 +597,7 @@ bhnd_nvram_sprom_read_offset(struct bhnd } 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_nvra 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_opcod } /* 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); Modified: head/sys/dev/bhnd/nvram/bhnd_nvram_private.h ============================================================================== --- head/sys/dev/bhnd/nvram/bhnd_nvram_private.h Mon Dec 19 20:11:48 2016 (r310291) +++ head/sys/dev/bhnd/nvram/bhnd_nvram_private.h Mon Dec 19 20:20:33 2016 (r310292) @@ -167,11 +167,15 @@ int bhnd_nvram_value_coerce(const vo 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 c 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( Modified: head/sys/dev/bhnd/nvram/bhnd_nvram_store.c ============================================================================== --- head/sys/dev/bhnd/nvram/bhnd_nvram_store.c Mon Dec 19 20:11:48 2016 (r310291) +++ head/sys/dev/bhnd/nvram/bhnd_nvram_store.c Mon Dec 19 20:20:33 2016 (r310292) @@ -288,7 +288,7 @@ bhnd_nvram_store_setvar(struct bhnd_nvra /* 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) */ Modified: head/sys/dev/bhnd/nvram/bhnd_nvram_subr.c ============================================================================== --- head/sys/dev/bhnd/nvram/bhnd_nvram_subr.c Mon Dec 19 20:11:48 2016 (r310291) +++ head/sys/dev/bhnd/nvram/bhnd_nvram_subr.c Mon Dec 19 20:20:33 2016 (r310292) @@ -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,112 +337,44 @@ bhnd_nvram_base_type(bhnd_nvram_type typ } /** - * 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 @@ bhnd_nvram_value_nelem(bhnd_nvram_type t } /** - * 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 @@ bhnd_nvram_value_size(bhnd_nvram_type ty } /** - * 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 @@ bhnd_nvram_validate_name(const char *nam } /** - * 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 @@ bhnd_nvram_parse_int(const char *str, si 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) Modified: head/sys/dev/bhnd/nvram/bhnd_nvram_value.c ============================================================================== --- head/sys/dev/bhnd/nvram/bhnd_nvram_value.c Mon Dec 19 20:11:48 2016 (r310291) +++ head/sys/dev/bhnd/nvram/bhnd_nvram_value.c Mon Dec 19 20:20:33 2016 (r310292) @@ -35,6 +35,7 @@ __FBSDID("$FreeBSD$"); #ifdef _KERNEL +#include #include #include #include @@ -43,6 +44,7 @@ __FBSDID("$FreeBSD$"); #else /* !_KERNEL */ +#include #include #include #include @@ -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_nvra 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(bh 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_va 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 **valu 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. *** DIFF OUTPUT TRUNCATED AT 1000 LINES ***