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 <sys/ctype.h>
 #include <sys/kernel.h>
 #include <sys/malloc.h>
 #include <sys/systm.h>
@@ -43,6 +44,7 @@ __FBSDID("$FreeBSD$");
 
 #else /* !_KERNEL */
 
+#include <ctype.h>
 #include <inttypes.h>
 #include <errno.h>
 #include <stdlib.h>
@@ -54,6 +56,8 @@ __FBSDID("$FreeBSD$");
 
 #include "bhnd_nvram_valuevar.h"
 
+static int      bhnd_nvram_val_fmt_filter(const bhnd_nvram_val_fmt **fmt,
+                    const void *inp, size_t ilen, bhnd_nvram_type itype);
 
 static void    *bhnd_nvram_val_alloc_bytes(bhnd_nvram_val *value, size_t ilen,
                     bhnd_nvram_type itype, uint32_t flags);
@@ -62,6 +66,15 @@ static int    bhnd_nvram_val_set(bhnd_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 ***
_______________________________________________
svn-src-all@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to