The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/dev/bhnd/nvram/bhnd_nvram_value.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*-
    2  * Copyright (c) 2015-2016 Landon Fuller <landonf@FreeBSD.org>
    3  * All rights reserved.
    4  *
    5  * Redistribution and use in source and binary forms, with or without
    6  * modification, are permitted provided that the following conditions
    7  * are met:
    8  * 1. Redistributions of source code must retain the above copyright
    9  *    notice, this list of conditions and the following disclaimer,
   10  *    without modification.
   11  * 2. Redistributions in binary form must reproduce at minimum a disclaimer
   12  *    similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
   13  *    redistribution must be conditioned upon including a substantially
   14  *    similar Disclaimer requirement for further binary redistribution.
   15  *
   16  * NO WARRANTY
   17  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
   18  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
   19  * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
   20  * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
   21  * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,
   22  * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   23  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
   24  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
   25  * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   26  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
   27  * THE POSSIBILITY OF SUCH DAMAGES.
   28  */
   29 
   30 #include <sys/cdefs.h>
   31 __FBSDID("$FreeBSD$");
   32 
   33 #include <sys/param.h>
   34 #include <sys/limits.h>
   35 #include <sys/sbuf.h>
   36 
   37 #ifdef _KERNEL
   38 
   39 #include <sys/ctype.h>
   40 #include <sys/kernel.h>
   41 #include <sys/malloc.h>
   42 #include <sys/systm.h>
   43 
   44 #include <machine/_inttypes.h>
   45 
   46 #else /* !_KERNEL */
   47 
   48 #include <ctype.h>
   49 #include <inttypes.h>
   50 #include <errno.h>
   51 #include <stdlib.h>
   52 #include <string.h>
   53 
   54 #endif /* _KERNEL */
   55 
   56 #include "bhnd_nvram_private.h"
   57 
   58 #include "bhnd_nvram_valuevar.h"
   59 
   60 static int       bhnd_nvram_val_fmt_filter(const bhnd_nvram_val_fmt **fmt,
   61                      const void *inp, size_t ilen, bhnd_nvram_type itype);
   62 
   63 static void     *bhnd_nvram_val_alloc_bytes(bhnd_nvram_val *value, size_t ilen,
   64                      bhnd_nvram_type itype, uint32_t flags);
   65 static int       bhnd_nvram_val_set(bhnd_nvram_val *value, const void *inp,
   66                      size_t ilen, bhnd_nvram_type itype, uint32_t flags);
   67 static int       bhnd_nvram_val_set_inline(bhnd_nvram_val *value,
   68                      const void *inp, size_t ilen, bhnd_nvram_type itype);
   69 
   70 static int       bhnd_nvram_val_encode_data(const void *inp, size_t ilen,
   71                      bhnd_nvram_type itype, void *outp, size_t *olen,
   72                      bhnd_nvram_type otype);
   73 static int       bhnd_nvram_val_encode_int(const void *inp, size_t ilen,
   74                      bhnd_nvram_type itype, void *outp, size_t *olen,
   75                      bhnd_nvram_type otype);
   76 static int       bhnd_nvram_val_encode_null(const void *inp, size_t ilen,
   77                      bhnd_nvram_type itype, void *outp, size_t *olen,
   78                      bhnd_nvram_type otype);
   79 static int       bhnd_nvram_val_encode_bool(const void *inp, size_t ilen,
   80                      bhnd_nvram_type itype, void *outp, size_t *olen,
   81                      bhnd_nvram_type otype);
   82 static int       bhnd_nvram_val_encode_string(const void *inp, size_t ilen,
   83                      bhnd_nvram_type itype, void *outp, size_t *olen,
   84                      bhnd_nvram_type otype);
   85 
   86 /** Initialize an empty value instance with @p _fmt, @p _storage, and
   87  *  an implicit callee-owned reference */
   88 #define BHND_NVRAM_VAL_INITIALIZER(_fmt, _storage)              \
   89         (bhnd_nvram_val) {                                      \
   90                 .refs = 1,                                      \
   91                 .val_storage = _storage,                        \
   92                 .fmt = _fmt,                                    \
   93                 .data_storage = BHND_NVRAM_VAL_DATA_NONE,       \
   94         };
   95 
   96 /** Assert that @p value's backing representation state has initialized
   97  *  as empty. */
   98 #define BHND_NVRAM_VAL_ASSERT_EMPTY(_value)                     \
   99         BHND_NV_ASSERT(                                         \
  100             value->data_storage == BHND_NVRAM_VAL_DATA_NONE &&  \
  101             value->data_len == 0 &&                             \
  102             value->data.ptr == NULL,                            \
  103             ("previously initialized value"))
  104 
  105 /** Return true if BHND_NVRAM_VAL_BORROW_DATA or BHND_NVRAM_VAL_STATIC_DATA is
  106  *  set in @p _flags (e.g. we should attempt to directly reference external
  107  *  data */
  108 #define BHND_NVRAM_VAL_EXTREF_BORROWED_DATA(_flags)             \
  109         (((_flags) & BHND_NVRAM_VAL_BORROW_DATA) ||             \
  110          ((_flags) & BHND_NVRAM_VAL_STATIC_DATA))
  111 
  112 /** Flags permitted when performing val-based initialization via
  113  *  bhnd_nvram_val_convert_init() or bhnd_nvram_val_convert_new() */
  114 #define BHND_NVRAM_VALID_CONV_FLAGS     \
  115         (BHND_NVRAM_VAL_FIXED |         \
  116          BHND_NVRAM_VAL_DYNAMIC |       \
  117          BHND_NVRAM_VAL_COPY_DATA)
  118 
  119 /** Returns true if @p _val must be copied in bhnd_nvram_val_copy(), false
  120  *  if its reference count may be safely incremented */
  121 #define BHND_NVRAM_VAL_NEED_COPY(_val)                          \
  122         ((_val)->val_storage == BHND_NVRAM_VAL_STORAGE_AUTO ||  \
  123          (_val)->data_storage == BHND_NVRAM_VAL_DATA_EXT_WEAK)
  124 
  125 volatile u_int                   refs;          /**< reference count */
  126 bhnd_nvram_val_storage           val_storage;   /**< value structure storage */
  127 const bhnd_nvram_val_fmt        *fmt;           /**< value format */
  128 bhnd_nvram_val_data_storage      data_storage;  /**< data storage */
  129 bhnd_nvram_type                  data_type;     /**< data type */
  130 size_t                           data_len;      /**< data size */
  131 
  132 /* Shared NULL value instance */
  133 bhnd_nvram_val bhnd_nvram_val_null = {
  134         .refs           = 1,
  135         .val_storage    = BHND_NVRAM_VAL_STORAGE_STATIC,
  136         .fmt            = &bhnd_nvram_val_null_fmt,
  137         .data_storage   = BHND_NVRAM_VAL_DATA_INLINE,
  138         .data_type      = BHND_NVRAM_TYPE_NULL,
  139         .data_len       = 0,
  140 };
  141 
  142 /**
  143  * Return the human-readable name of @p fmt.
  144  */
  145 const char *
  146 bhnd_nvram_val_fmt_name(const bhnd_nvram_val_fmt *fmt)
  147 {
  148         return (fmt->name);
  149 }
  150 
  151 /**
  152  * Return the default format for values of @p type.
  153  */
  154 const bhnd_nvram_val_fmt *
  155 bhnd_nvram_val_default_fmt(bhnd_nvram_type type)
  156 {
  157         switch (type) {
  158         case BHND_NVRAM_TYPE_UINT8:
  159                 return (&bhnd_nvram_val_uint8_fmt);
  160         case BHND_NVRAM_TYPE_UINT16:
  161                 return (&bhnd_nvram_val_uint16_fmt);
  162         case BHND_NVRAM_TYPE_UINT32:
  163                 return (&bhnd_nvram_val_uint32_fmt);
  164         case BHND_NVRAM_TYPE_UINT64:
  165                 return (&bhnd_nvram_val_uint64_fmt);
  166         case BHND_NVRAM_TYPE_INT8:
  167                 return (&bhnd_nvram_val_int8_fmt);
  168         case BHND_NVRAM_TYPE_INT16:
  169                 return (&bhnd_nvram_val_int16_fmt);
  170         case BHND_NVRAM_TYPE_INT32:
  171                 return (&bhnd_nvram_val_int32_fmt);
  172         case BHND_NVRAM_TYPE_INT64:
  173                 return (&bhnd_nvram_val_int64_fmt);
  174         case BHND_NVRAM_TYPE_CHAR:
  175                 return (&bhnd_nvram_val_char_fmt);
  176         case BHND_NVRAM_TYPE_STRING:
  177                 return (&bhnd_nvram_val_string_fmt);
  178         case BHND_NVRAM_TYPE_BOOL:
  179                 return (&bhnd_nvram_val_bool_fmt);
  180         case BHND_NVRAM_TYPE_NULL:
  181                 return (&bhnd_nvram_val_null_fmt);
  182         case BHND_NVRAM_TYPE_DATA:
  183                 return (&bhnd_nvram_val_data_fmt);
  184         case BHND_NVRAM_TYPE_UINT8_ARRAY:
  185                 return (&bhnd_nvram_val_uint8_array_fmt);
  186         case BHND_NVRAM_TYPE_UINT16_ARRAY:
  187                 return (&bhnd_nvram_val_uint16_array_fmt);
  188         case BHND_NVRAM_TYPE_UINT32_ARRAY:
  189                 return (&bhnd_nvram_val_uint32_array_fmt);
  190         case BHND_NVRAM_TYPE_UINT64_ARRAY:
  191                 return (&bhnd_nvram_val_uint64_array_fmt);
  192         case BHND_NVRAM_TYPE_INT8_ARRAY:
  193                 return (&bhnd_nvram_val_int8_array_fmt);
  194         case BHND_NVRAM_TYPE_INT16_ARRAY:
  195                 return (&bhnd_nvram_val_int16_array_fmt);
  196         case BHND_NVRAM_TYPE_INT32_ARRAY:
  197                 return (&bhnd_nvram_val_int32_array_fmt);
  198         case BHND_NVRAM_TYPE_INT64_ARRAY:
  199                 return (&bhnd_nvram_val_int64_array_fmt);
  200         case BHND_NVRAM_TYPE_CHAR_ARRAY:
  201                 return (&bhnd_nvram_val_char_array_fmt);
  202         case BHND_NVRAM_TYPE_STRING_ARRAY:
  203                 return (&bhnd_nvram_val_string_array_fmt);
  204         case BHND_NVRAM_TYPE_BOOL_ARRAY:
  205                 return (&bhnd_nvram_val_bool_array_fmt);
  206         }
  207 
  208         /* Quiesce gcc4.2 */
  209         BHND_NV_PANIC("bhnd nvram type %u unknown", type);
  210 }
  211 
  212 /**
  213  * Determine whether @p fmt (or new format delegated to by @p fmt) is
  214  * capable of direct initialization from buffer @p inp.
  215  * 
  216  * @param[in,out]       fmt     Indirect pointer to the NVRAM value format. If
  217  *                              the format instance cannot handle the data type
  218  *                              directly, it may delegate to a new format
  219  *                              instance. On success, this parameter will be
  220  *                              set to the format that should be used when
  221  *                              performing initialization from @p inp.
  222  * @param               inp     Input data.
  223  * @param               ilen    Input data length.
  224  * @param               itype   Input data type.
  225  *
  226  * @retval 0            If initialization from @p inp is supported.
  227  * @retval EFTYPE       If initialization from @p inp is unsupported.
  228  * @retval EFAULT       if @p ilen is not correctly aligned for elements of
  229  *                      @p itype.
  230  */
  231 static int
  232 bhnd_nvram_val_fmt_filter(const bhnd_nvram_val_fmt **fmt, const void *inp,
  233     size_t ilen, bhnd_nvram_type itype)
  234 {
  235         const bhnd_nvram_val_fmt        *ofmt, *nfmt;
  236         int                              error;
  237 
  238         nfmt = ofmt = *fmt;
  239 
  240         /* Validate alignment */
  241         if ((error = bhnd_nvram_value_check_aligned(inp, ilen, itype)))
  242                 return (error);
  243 
  244         /* If the format does not provide a filter function, it only supports
  245          * direct initialization from its native type */
  246         if (ofmt->op_filter == NULL) {
  247                 if (itype == ofmt->native_type)
  248                         return (0);
  249 
  250                 return (EFTYPE);
  251         }
  252 
  253         /* Use the filter function to determine whether direct initialization
  254          * from itype is permitted */
  255         error = ofmt->op_filter(&nfmt, inp, ilen, itype);
  256         if (error)
  257                 return (error);
  258 
  259         /* Retry filter with new format? */
  260         if (ofmt != nfmt) {
  261                 error = bhnd_nvram_val_fmt_filter(&nfmt, inp, ilen, itype);
  262                 if (error)
  263                         return (error);
  264 
  265                 /* Success -- provide delegated format to caller */
  266                 *fmt = nfmt;
  267         }
  268 
  269         /* Value can be initialized with provided format and input type */
  270         return (0);
  271 }
  272 
  273 /* Common initialization support for bhnd_nvram_val_init() and
  274  * bhnd_nvram_val_new() */
  275 static int
  276 bhnd_nvram_val_init_common(bhnd_nvram_val *value,
  277     bhnd_nvram_val_storage val_storage, const bhnd_nvram_val_fmt *fmt,
  278     const void *inp, size_t ilen, bhnd_nvram_type itype, uint32_t flags)
  279 {
  280         void            *outp;
  281         bhnd_nvram_type  otype;
  282         size_t           olen;
  283         int              error;
  284 
  285         /* If the value format is unspecified, we use the default format
  286          * for the input data type */
  287         if (fmt == NULL)
  288                 fmt = bhnd_nvram_val_default_fmt(itype);
  289 
  290         /* Determine expected data type, and allow the format to delegate to
  291          * a new format instance */
  292         if ((error = bhnd_nvram_val_fmt_filter(&fmt, inp, ilen, itype))) {
  293                 /* Direct initialization from the provided input type is
  294                  * not supported; alue must be initialized with the format's
  295                  * native type */
  296                 otype = fmt->native_type;
  297         } else {
  298                 /* Value can be initialized with provided input type */
  299                 otype = itype;
  300         }
  301 
  302         /* Initialize value instance */
  303         *value = BHND_NVRAM_VAL_INITIALIZER(fmt, val_storage);
  304 
  305         /* If input data already in native format, init directly. */
  306         if (otype == itype) {
  307                 error = bhnd_nvram_val_set(value, inp, ilen, itype, flags);
  308                 if (error)
  309                         return (error);
  310 
  311                 return (0);
  312         }
  313 
  314         /* Determine size when encoded in native format */
  315         error = bhnd_nvram_value_coerce(inp, ilen, itype, NULL, &olen, otype);
  316         if (error)
  317                 return (error);
  318 
  319         /* Fetch reference to (or allocate) an appropriately sized buffer */
  320         outp = bhnd_nvram_val_alloc_bytes(value, olen, otype, flags);
  321         if (outp == NULL)
  322                 return (ENOMEM);
  323 
  324         /* Perform encode */
  325         error = bhnd_nvram_value_coerce(inp, ilen, itype, outp, &olen, otype);
  326         if (error)
  327                 return (error);
  328 
  329         return (0);
  330 }
  331 
  332 /**
  333  * Initialize an externally allocated instance of @p value with @p fmt from the
  334  * given @p inp buffer of @p itype and @p ilen.
  335  *
  336  * On success, the caller owns a reference to @p value, and is responsible for
  337  * freeing any resources allocated for @p value via bhnd_nvram_val_release().
  338  *
  339  * @param       value   The externally allocated value instance to be
  340  *                      initialized.
  341  * @param       fmt     The value's format, or NULL to use the default format
  342  *                      for @p itype.
  343  * @param       inp     Input buffer.
  344  * @param       ilen    Input buffer length.
  345  * @param       itype   Input buffer type.
  346  * @param       flags   Value flags (see BHND_NVRAM_VAL_*).
  347  * 
  348  * @retval 0            success
  349  * @retval ENOMEM       If allocation fails.
  350  * @retval EFTYPE       If @p fmt initialization from @p itype is unsupported.
  351  * @retval EFAULT       if @p ilen is not correctly aligned for elements of
  352  *                      @p itype.
  353  * @retval ERANGE       If value coercion would overflow (or underflow) the
  354  *                      @p fmt representation.
  355  */
  356 int
  357 bhnd_nvram_val_init(bhnd_nvram_val *value, const bhnd_nvram_val_fmt *fmt,
  358     const void *inp, size_t ilen, bhnd_nvram_type itype, uint32_t flags)
  359 {
  360         int error;
  361 
  362         error = bhnd_nvram_val_init_common(value, BHND_NVRAM_VAL_STORAGE_AUTO,
  363             fmt, inp, ilen, itype, flags);
  364         if (error)
  365                 bhnd_nvram_val_release(value);
  366 
  367         return (error);
  368 }
  369 
  370 /**
  371  * Allocate a value instance with @p fmt, and attempt to initialize its internal
  372  * representation from the given @p inp buffer of @p itype and @p ilen.
  373  *
  374  * On success, the caller owns a reference to @p value, and is responsible for
  375  * freeing any resources allocated for @p value via bhnd_nvram_val_release().
  376  *
  377  * @param[out]  value   On success, the allocated value instance.
  378  * @param       fmt     The value's format, or NULL to use the default format
  379  *                      for @p itype.
  380  * @param       inp     Input buffer.
  381  * @param       ilen    Input buffer length.
  382  * @param       itype   Input buffer type.
  383  * @param       flags   Value flags (see BHND_NVRAM_VAL_*).
  384  * 
  385  * @retval 0            success
  386  * @retval ENOMEM       If allocation fails.
  387  * @retval EFTYPE       If @p fmt initialization from @p itype is unsupported.
  388  * @retval EFAULT       if @p ilen is not correctly aligned for elements of
  389  *                      @p itype.
  390  * @retval ERANGE       If value coercion would overflow (or underflow) the
  391  *                      @p fmt representation.
  392  */
  393 int
  394 bhnd_nvram_val_new(bhnd_nvram_val **value, const bhnd_nvram_val_fmt *fmt,
  395     const void *inp, size_t ilen, bhnd_nvram_type itype, uint32_t flags)
  396 {
  397         int error;
  398 
  399         /* Allocate new instance */
  400         if ((*value = bhnd_nv_malloc(sizeof(**value))) == NULL)
  401                 return (ENOMEM);
  402 
  403         /* Perform common initialization. */
  404         error = bhnd_nvram_val_init_common(*value,
  405             BHND_NVRAM_VAL_STORAGE_DYNAMIC, fmt, inp, ilen, itype, flags);
  406         if (error) {
  407                 /* Will also free() the value allocation */
  408                 bhnd_nvram_val_release(*value);
  409         }
  410 
  411         return (error);
  412 }
  413 
  414 /* Common initialization support for bhnd_nvram_val_convert_init() and
  415  * bhnd_nvram_val_convert_new() */
  416 static int
  417 bhnd_nvram_val_convert_common(bhnd_nvram_val *value,
  418     bhnd_nvram_val_storage val_storage, const bhnd_nvram_val_fmt *fmt,
  419     bhnd_nvram_val *src, uint32_t flags)
  420 {
  421         const void      *inp;
  422         void            *outp;
  423         bhnd_nvram_type  itype, otype;
  424         size_t           ilen, olen;
  425         int              error;
  426 
  427         /* Determine whether direct initialization from the source value's
  428          * existing data type is supported by the new format */
  429         inp = bhnd_nvram_val_bytes(src, &ilen, &itype);
  430         if (bhnd_nvram_val_fmt_filter(&fmt, inp, ilen, itype) == 0) {
  431                 /* Adjust value flags based on the source data storage */
  432                 switch (src->data_storage) {
  433                 case BHND_NVRAM_VAL_DATA_NONE:
  434                 case BHND_NVRAM_VAL_DATA_INLINE:
  435                 case BHND_NVRAM_VAL_DATA_EXT_WEAK:
  436                 case BHND_NVRAM_VAL_DATA_EXT_ALLOC:
  437                         break;
  438 
  439                 case BHND_NVRAM_VAL_DATA_EXT_STATIC:
  440                         /* If the source data has static storage duration,
  441                          * we should apply that transitively */
  442                         if (flags & BHND_NVRAM_VAL_BORROW_DATA)
  443                                 flags |= BHND_NVRAM_VAL_STATIC_DATA;
  444 
  445                         break;
  446                 }
  447 
  448                 /* Delegate to standard initialization */
  449                 return (bhnd_nvram_val_init_common(value, val_storage, fmt, inp,
  450                     ilen, itype, flags));
  451         } 
  452 
  453         /* Value must be initialized with the format's native type */
  454         otype = fmt->native_type;
  455 
  456         /* Initialize value instance */
  457         *value = BHND_NVRAM_VAL_INITIALIZER(fmt, val_storage);
  458 
  459         /* Determine size when encoded in native format */
  460         if ((error = bhnd_nvram_val_encode(src, NULL, &olen, otype)))
  461                 return (error);
  462 
  463         /* Fetch reference to (or allocate) an appropriately sized buffer */
  464         outp = bhnd_nvram_val_alloc_bytes(value, olen, otype, flags);
  465         if (outp == NULL)
  466                 return (ENOMEM);
  467 
  468         /* Perform encode */
  469         if ((error = bhnd_nvram_val_encode(src, outp, &olen, otype)))
  470                 return (error);
  471 
  472         return (0);
  473 }
  474 
  475 /**
  476  * Initialize an externally allocated instance of @p value with @p fmt, and
  477  * attempt to initialize its internal representation from the given @p src
  478  * value.
  479  *
  480  * On success, the caller owns a reference to @p value, and is responsible for
  481  * freeing any resources allocated for @p value via bhnd_nvram_val_release().
  482  *
  483  * @param       value   The externally allocated value instance to be
  484  *                      initialized.
  485  * @param       fmt     The value's format.
  486  * @param       src     Input value to be converted.
  487  * @param       flags   Value flags (see BHND_NVRAM_VAL_*).
  488  * 
  489  * @retval 0            success
  490  * @retval ENOMEM       If allocation fails.
  491  * @retval EFTYPE       If @p fmt initialization from @p src is unsupported.
  492  * @retval EFAULT       if @p ilen is not correctly aligned for elements of
  493  *                      @p itype.
  494  * @retval ERANGE       If value coercion of @p src would overflow
  495  *                      (or underflow) the @p fmt representation.
  496  */
  497 int
  498 bhnd_nvram_val_convert_init(bhnd_nvram_val *value,
  499     const bhnd_nvram_val_fmt *fmt, bhnd_nvram_val *src, uint32_t flags)
  500 {
  501         int error;
  502 
  503         error = bhnd_nvram_val_convert_common(value,
  504             BHND_NVRAM_VAL_STORAGE_AUTO, fmt, src, flags);
  505         if (error)
  506                 bhnd_nvram_val_release(value);
  507 
  508         return (error);
  509 }
  510 
  511 /**
  512  * Allocate a value instance with @p fmt, and attempt to initialize its internal
  513  * representation from the given @p src value.
  514  *
  515  * On success, the caller owns a reference to @p value, and is responsible for
  516  * freeing any resources allocated for @p value via bhnd_nvram_val_release().
  517  *
  518  * @param[out]  value   On success, the allocated value instance.
  519  * @param       fmt     The value's format.
  520  * @param       src     Input value to be converted.
  521  * @param       flags   Value flags (see BHND_NVRAM_VAL_*).
  522  * 
  523  * @retval 0            success
  524  * @retval ENOMEM       If allocation fails.
  525  * @retval EFTYPE       If @p fmt initialization from @p src is unsupported.
  526  * @retval EFAULT       if @p ilen is not correctly aligned for elements of
  527  *                      @p itype.
  528  * @retval ERANGE       If value coercion of @p src would overflow
  529  *                      (or underflow) the @p fmt representation.
  530  */
  531 int
  532 bhnd_nvram_val_convert_new(bhnd_nvram_val **value,
  533     const bhnd_nvram_val_fmt *fmt, bhnd_nvram_val *src, uint32_t flags)
  534 {
  535         int error;
  536 
  537         /* Allocate new instance */
  538         if ((*value = bhnd_nv_malloc(sizeof(**value))) == NULL)
  539                 return (ENOMEM);
  540 
  541         /* Perform common initialization. */
  542         error = bhnd_nvram_val_convert_common(*value,
  543             BHND_NVRAM_VAL_STORAGE_DYNAMIC, fmt, src, flags);
  544         if (error) {
  545                 /* Will also free() the value allocation */
  546                 bhnd_nvram_val_release(*value);
  547         }
  548 
  549         return (error);
  550 }
  551 
  552 /**
  553  * Copy or retain a reference to @p value.
  554  * 
  555  * On success, the caller is responsible for freeing the result via
  556  * bhnd_nvram_val_release().
  557  * 
  558  * @param       value   The value to be copied (or retained).
  559  * 
  560  * @retval bhnd_nvram_val       if @p value was successfully copied or retained.
  561  * @retval NULL                 if allocation failed.
  562  */
  563 bhnd_nvram_val *
  564 bhnd_nvram_val_copy(bhnd_nvram_val *value)
  565 {
  566         bhnd_nvram_val          *result;
  567         const void              *bytes;
  568         bhnd_nvram_type          type;
  569         size_t                   len;
  570         uint32_t                 flags;
  571         int                      error;
  572 
  573         switch (value->val_storage) {
  574         case BHND_NVRAM_VAL_STORAGE_STATIC:
  575                 /* If static, can return as-is */
  576                 return (value);
  577 
  578         case BHND_NVRAM_VAL_STORAGE_DYNAMIC:
  579                 if (!BHND_NVRAM_VAL_NEED_COPY(value)) {
  580                         refcount_acquire(&value->refs);
  581                         return (value);
  582                 }
  583 
  584                 /* Perform copy below */
  585                 break;
  586 
  587         case BHND_NVRAM_VAL_STORAGE_AUTO:
  588                 BHND_NV_ASSERT(value->refs == 1, ("non-allocated value has "
  589                     "active refcount (%u)", value->refs));
  590 
  591                 /* Perform copy below */
  592                 break;
  593         }
  594 
  595         /* Compute the new value's flags based on the source value */
  596         switch (value->data_storage) {
  597         case BHND_NVRAM_VAL_DATA_NONE:
  598         case BHND_NVRAM_VAL_DATA_INLINE:
  599         case BHND_NVRAM_VAL_DATA_EXT_WEAK:
  600         case BHND_NVRAM_VAL_DATA_EXT_ALLOC:
  601                 /* Copy the source data and permit additional allocation if the
  602                  * value cannot be represented inline */
  603                 flags = BHND_NVRAM_VAL_COPY_DATA|BHND_NVRAM_VAL_DYNAMIC;
  604                 break;
  605         case BHND_NVRAM_VAL_DATA_EXT_STATIC:
  606                 flags = BHND_NVRAM_VAL_STATIC_DATA;
  607                 break;
  608         default:
  609                 BHND_NV_PANIC("invalid storage type: %d", value->data_storage);
  610         }
  611 
  612         /* Allocate new value copy */
  613         bytes = bhnd_nvram_val_bytes(value, &len, &type);
  614         error = bhnd_nvram_val_new(&result, value->fmt, bytes, len, type,
  615             flags);
  616         if (error) {
  617                 BHND_NV_LOG("copy failed: %d", error);
  618                 return (NULL);
  619         }
  620 
  621         return (result);
  622 }
  623 
  624 /**
  625  * Release a reference to @p value.
  626  *
  627  * If this is the last reference, all associated resources will be freed.
  628  * 
  629  * @param       value   The value to be released.
  630  */
  631 void
  632 bhnd_nvram_val_release(bhnd_nvram_val *value)
  633 {
  634         BHND_NV_ASSERT(value->refs >= 1, ("value over-released"));
  635 
  636         /* Skip if value is static */
  637         if (value->val_storage == BHND_NVRAM_VAL_STORAGE_STATIC)
  638                 return;
  639 
  640         /* Drop reference */
  641         if (!refcount_release(&value->refs))
  642                 return;
  643 
  644         /* Free allocated external representation data */
  645         switch (value->data_storage) {
  646         case BHND_NVRAM_VAL_DATA_EXT_ALLOC:
  647                 bhnd_nv_free(__DECONST(void *, value->data.ptr));
  648                 break;
  649         case BHND_NVRAM_VAL_DATA_NONE:
  650         case BHND_NVRAM_VAL_DATA_INLINE:
  651         case BHND_NVRAM_VAL_DATA_EXT_WEAK:
  652         case BHND_NVRAM_VAL_DATA_EXT_STATIC:
  653                 /* Nothing to free */
  654                 break;
  655         }
  656 
  657         /* Free instance if dynamically allocated */
  658         if (value->val_storage == BHND_NVRAM_VAL_STORAGE_DYNAMIC)
  659                 bhnd_nv_free(value);
  660 }
  661 
  662 /**
  663  * Standard BHND_NVRAM_TYPE_NULL encoding implementation.
  664  */
  665 static int
  666 bhnd_nvram_val_encode_null(const void *inp, size_t ilen, bhnd_nvram_type itype,
  667     void *outp, size_t *olen, bhnd_nvram_type otype)
  668 {
  669         size_t  limit, nbytes;
  670 
  671         BHND_NV_ASSERT(itype == BHND_NVRAM_TYPE_NULL,
  672             ("unsupported type: %d", itype));
  673 
  674         /* Determine output byte limit */
  675         if (outp != NULL)
  676                 limit = *olen;
  677         else
  678                 limit = 0;
  679 
  680         nbytes = 0;
  681 
  682         /* Write to output */
  683         switch (otype) {
  684         case BHND_NVRAM_TYPE_NULL:
  685                 /* Can be directly encoded as a zero-length NULL value */
  686                 nbytes = 0;
  687                 break;
  688         default:
  689                 /* Not representable */
  690                 return (EFTYPE);
  691         }
  692 
  693         /* Provide required length */
  694         *olen = nbytes;
  695         if (limit < *olen) {
  696                 if (outp == NULL)
  697                         return (0);
  698 
  699                 return (ENOMEM);
  700         }
  701 
  702         return (0);
  703 }
  704 
  705 /**
  706  * Standard BHND_NVRAM_TYPE_BOOL encoding implementation.
  707  */
  708 static int
  709 bhnd_nvram_val_encode_bool(const void *inp, size_t ilen, bhnd_nvram_type itype,
  710     void *outp, size_t *olen, bhnd_nvram_type otype)
  711 {
  712         bhnd_nvram_bool_t       bval;
  713         size_t                  limit, nbytes, nelem;
  714         int                     error;
  715 
  716         BHND_NV_ASSERT(itype == BHND_NVRAM_TYPE_BOOL,
  717             ("unsupported type: %d", itype));
  718 
  719         /* Determine output byte limit */
  720         if (outp != NULL)
  721                 limit = *olen;
  722         else
  723                 limit = 0;
  724 
  725         /* Must be exactly one element in input */
  726         if ((error = bhnd_nvram_value_nelem(inp, ilen, itype, &nelem)))
  727                 return (error);
  728 
  729         if (nelem != 1)
  730                 return (EFTYPE);
  731 
  732         /* Fetch (and normalize) boolean value */
  733         bval = (*(const bhnd_nvram_bool_t *)inp != 0) ? true : false;
  734 
  735         /* Write to output */
  736         switch (otype) {
  737         case BHND_NVRAM_TYPE_NULL:
  738                 /* False can be directly encoded as a zero-length NULL value */
  739                 if (bval != false)
  740                         return (EFTYPE);
  741 
  742                 nbytes = 0;
  743                 break;
  744 
  745         case BHND_NVRAM_TYPE_STRING:
  746         case BHND_NVRAM_TYPE_STRING_ARRAY: {
  747                 /* Can encode as "true" or "false" */
  748                 const char *str = bval ? "true" : "false";
  749 
  750                 nbytes = strlen(str) + 1;
  751                 if (limit > nbytes)
  752                         strcpy(outp, str);
  753 
  754                 break;
  755         }
  756 
  757         default:
  758                 /* If output type is an integer, we can delegate to standard
  759                  * integer encoding to encode as zero or one. */
  760                 if (bhnd_nvram_is_int_type(otype)) {
  761                         uint8_t ival = bval ? 1 : 0;
  762 
  763                         return (bhnd_nvram_val_encode_int(&ival, sizeof(ival),
  764                             BHND_NVRAM_TYPE_UINT8, outp, olen, otype));
  765                 }
  766 
  767                 /* Otherwise not representable */
  768                 return (EFTYPE);
  769         }
  770 
  771         /* Provide required length */
  772         *olen = nbytes;
  773         if (limit < *olen) {
  774                 if (outp == NULL)
  775                         return (0);
  776 
  777                 return (ENOMEM);
  778         }
  779 
  780         return (0);
  781 }
  782 
  783 /**
  784  * Standard BHND_NVRAM_TYPE_DATA encoding implementation.
  785  */
  786 static int
  787 bhnd_nvram_val_encode_data(const void *inp, size_t ilen, bhnd_nvram_type itype,
  788     void *outp, size_t *olen, bhnd_nvram_type otype)
  789 {
  790         BHND_NV_ASSERT(itype == BHND_NVRAM_TYPE_DATA,
  791             ("unsupported type: %d", itype));
  792 
  793         /* Write to output */
  794         switch (otype) {
  795         case BHND_NVRAM_TYPE_STRING:
  796         case BHND_NVRAM_TYPE_STRING_ARRAY:
  797                 /* If encoding as a string, produce an EFI-style hexadecimal
  798                  * byte array (HF1F...) by interpreting the octet string
  799                  * as an array of uint8 values */
  800                 return (bhnd_nvram_value_printf("H%[]02hhX", inp, ilen,
  801                     BHND_NVRAM_TYPE_UINT8_ARRAY, outp, olen, ""));
  802 
  803         default:
  804                 /* Fall back on direct interpretation as an array of 8-bit
  805                  * integers array */
  806                 return (bhnd_nvram_value_coerce(inp, ilen,
  807                     BHND_NVRAM_TYPE_UINT8_ARRAY, outp, olen, otype));
  808         }
  809 }
  810 
  811 /**
  812  * Standard string/char array/char encoding implementation.
  813  *
  814  * Input type must be one of:
  815  * - BHND_NVRAM_TYPE_STRING
  816  * - BHND_NVRAM_TYPE_CHAR
  817  * - BHND_NVRAM_TYPE_CHAR_ARRAY
  818  */
  819 static int
  820 bhnd_nvram_val_encode_string(const void *inp, size_t ilen,
  821     bhnd_nvram_type itype, void *outp, size_t *olen, bhnd_nvram_type otype)
  822 {
  823         const char      *cstr;
  824         bhnd_nvram_type  otype_base;
  825         size_t           cstr_size, cstr_len;
  826         size_t           limit, nbytes;
  827 
  828         BHND_NV_ASSERT(
  829             itype == BHND_NVRAM_TYPE_STRING ||
  830             itype == BHND_NVRAM_TYPE_CHAR ||
  831             itype == BHND_NVRAM_TYPE_CHAR_ARRAY,
  832             ("unsupported type: %d", itype));
  833 
  834         cstr = inp;
  835         cstr_size = ilen;
  836         nbytes = 0;
  837         otype_base = bhnd_nvram_base_type(otype);
  838 
  839         /* Determine output byte limit */
  840         if (outp != NULL)
  841                 limit = *olen;
  842         else
  843                 limit = 0;
  844 
  845         /* Determine string length, minus trailing NUL (if any) */
  846         cstr_len = strnlen(cstr, cstr_size);
  847 
  848         /* Parse the string data and write to output */
  849         switch (otype) {
  850         case BHND_NVRAM_TYPE_NULL:
  851                 /* Only an empty string may be represented as a NULL value */
  852                 if (cstr_len != 0)
  853                         return (EFTYPE);
  854 
  855                 *olen = 0;
  856                 return (0);
  857 
  858         case BHND_NVRAM_TYPE_CHAR:
  859         case BHND_NVRAM_TYPE_CHAR_ARRAY:
  860                 /* String must contain exactly 1 non-terminating-NUL character
  861                  * to be represented as a single char */
  862                 if (!bhnd_nvram_is_array_type(otype)) {
  863                         if (cstr_len != 1)
  864                                 return (EFTYPE);
  865                 }
  866 
  867                 /* Copy out the characters directly (excluding trailing NUL) */
  868                 for (size_t i = 0; i < cstr_len; i++) {
  869                         if (limit > nbytes)
  870                                 *((uint8_t *)outp + nbytes) = cstr[i];
  871                         nbytes++;
  872                 }
  873 
  874                 /* Provide required length */
  875                 *olen = nbytes;
  876                 if (limit < *olen && outp != NULL)
  877                         return (ENOMEM);
  878 
  879                 return (0);
  880 
  881         case BHND_NVRAM_TYPE_BOOL:
  882         case BHND_NVRAM_TYPE_BOOL_ARRAY: {
  883                 const char              *p;
  884                 size_t                   plen;
  885                 bhnd_nvram_bool_t        bval;
  886 
  887                 /* Trim leading/trailing whitespace */
  888                 p = cstr;
  889                 plen = bhnd_nvram_trim_field(&p, cstr_len, '\0');
  890 
  891                 /* Parse string representation */
  892                 if (strncasecmp(p, "true", plen) == 0 ||
  893                     strncasecmp(p, "yes", plen) == 0 ||
  894                     strncmp(p, "1", plen) == 0)
  895                 {
  896                         bval = true;
  897                 } else if (strncasecmp(p, "false", plen) == 0 ||
  898                     strncasecmp(p, "no", plen) == 0 ||
  899                     strncmp(p, "", plen) == 0)
  900                 {
  901                         bval = false;
  902                 } else {
  903                         /* Not a recognized boolean string */
  904                         return (EFTYPE);
  905                 }
  906 
  907                 /* Write to output */
  908                 nbytes = sizeof(bhnd_nvram_bool_t);
  909                 if (limit >= nbytes)
  910                         *((bhnd_nvram_bool_t *)outp) = bval;
  911 
  912                 /* Provide required length */
  913                 *olen = nbytes;
  914                 if (limit < *olen && outp != NULL)
  915                         return (ENOMEM);
  916 
  917                 return (0);
  918         }
  919 
  920         case BHND_NVRAM_TYPE_DATA: {
  921                 const char      *p;
  922                 size_t           plen, parsed_len;
  923                 int              error;
  924 
  925                 /* Trim leading/trailing whitespace */
  926                 p = cstr;
  927                 plen = bhnd_nvram_trim_field(&p, cstr_len, '\0');
  928 
  929                 /* Check for EFI-style hexadecimal byte array string format.
  930                  * Must have a 'H' prefix  */
  931                 if (plen < 1 || bhnd_nv_toupper(*p) != 'H')
  932                         return (EFTYPE);
  933 
  934                 /* Skip leading 'H' */
  935                 p++;
  936                 plen--;
  937 
  938                 /* Parse the input string's two-char octets until the end
  939                  * of input is reached. The last octet may contain only
  940                  * one char */
  941                 while (plen > 0) {
  942                         uint8_t byte;
  943                         size_t  byte_len = sizeof(byte);
  944 
  945                         /* Parse next two-character hex octet */
  946                         error = bhnd_nvram_parse_int(p, bhnd_nv_ummin(plen, 2),
  947                             16, &parsed_len, &byte, &byte_len, otype_base);
  948                         if (error) {
  949                                 BHND_NV_DEBUG("error parsing '%.*s' as "
  950                                     "integer: %d\n", BHND_NV_PRINT_WIDTH(plen),
  951                                      p, error);
  952 
  953                                 return (error);
  954                         }
  955 
  956                         /* Write to output */
  957                         if (limit > nbytes)
  958                                 *((uint8_t *)outp + nbytes) = byte;
  959                         nbytes++;
  960 
  961                         /* Advance input */
  962                         p += parsed_len;
  963                         plen -= parsed_len;
  964                 }
  965 
  966                 /* Provide required length */
  967                 *olen = nbytes;
  968                 if (limit < *olen && outp != NULL)
  969                         return (ENOMEM);
  970 
  971                 return (0);
  972         }
  973 
  974         case BHND_NVRAM_TYPE_UINT8:
  975         case BHND_NVRAM_TYPE_UINT8_ARRAY:
  976         case BHND_NVRAM_TYPE_UINT16:
  977         case BHND_NVRAM_TYPE_UINT16_ARRAY:
  978         case BHND_NVRAM_TYPE_UINT32:
  979         case BHND_NVRAM_TYPE_UINT32_ARRAY:
  980         case BHND_NVRAM_TYPE_UINT64:
  981         case BHND_NVRAM_TYPE_UINT64_ARRAY:
  982         case BHND_NVRAM_TYPE_INT8:
  983         case BHND_NVRAM_TYPE_INT8_ARRAY:
  984         case BHND_NVRAM_TYPE_INT16:
  985         case BHND_NVRAM_TYPE_INT16_ARRAY:
  986         case BHND_NVRAM_TYPE_INT32:
  987         case BHND_NVRAM_TYPE_INT32_ARRAY:
  988         case BHND_NVRAM_TYPE_INT64:
  989         case BHND_NVRAM_TYPE_INT64_ARRAY: {
  990                 const char      *p;
  991                 size_t           plen, parsed_len;
  992                 int              error;
  993 
  994                 /* Trim leading/trailing whitespace */
  995                 p = cstr;
  996                 plen = bhnd_nvram_trim_field(&p, cstr_len, '\0');
  997 
  998                 /* Try to parse the integer value */
  999                 error = bhnd_nvram_parse_int(p, plen, 0, &parsed_len, outp,
 1000                     olen, otype_base);
 1001                 if (error) {
 1002                         BHND_NV_DEBUG("error parsing '%.*s' as integer: %d\n",
 1003                             BHND_NV_PRINT_WIDTH(plen), p, error);
 1004                         return (error);
 1005                 }
 1006 
 1007                 /* Do additional bytes remain unparsed? */
 1008                 if (plen != parsed_len) {
 1009                         BHND_NV_DEBUG("error parsing '%.*s' as a single "
 1010                             "integer value; trailing garbage '%.*s'\n",
 1011                             BHND_NV_PRINT_WIDTH(plen), p,
 1012                             BHND_NV_PRINT_WIDTH(plen-parsed_len), p+parsed_len);
 1013                         return (EFTYPE);
 1014                 }
 1015 
 1016                 return (0);
 1017         }
 1018 
 1019         case BHND_NVRAM_TYPE_STRING:
 1020         case BHND_NVRAM_TYPE_STRING_ARRAY:
 1021                 /* Copy out the string representation as-is */
 1022                 *olen = cstr_size;
 1023 
 1024                 /* Need additional space for trailing NUL? */
 1025                 if (cstr_len == cstr_size)
 1026                         (*olen)++;
 1027 
 1028                 /* Skip output? */
 1029                 if (outp == NULL)
 1030                         return (0);
 1031 
 1032                 /* Verify required length */
 1033                 if (limit < *olen)
 1034                         return (ENOMEM);
 1035 
 1036                 /* Copy and NUL terminate */
 1037                 strncpy(outp, cstr, cstr_len);
 1038                 *((char *)outp + cstr_len) = '\0';
 1039 
 1040                 return (0);
 1041         }
 1042 
 1043         BHND_NV_PANIC("unknown type %s", bhnd_nvram_type_name(otype));
 1044 }
 1045 
 1046 /**
 1047  * Standard integer encoding implementation.
 1048  */
 1049 static int
 1050 bhnd_nvram_val_encode_int(const void *inp, size_t ilen, bhnd_nvram_type itype,
 1051     void *outp, size_t *olen, bhnd_nvram_type otype)
 1052 {
 1053         bhnd_nvram_type  otype_base;
 1054         size_t           limit, nbytes;
 1055         bool             itype_signed, otype_signed, otype_int;
 1056         union {
 1057                 uint64_t        u64;
 1058                 int64_t         i64;
 1059         } intv;
 1060 
 1061         BHND_NV_ASSERT(bhnd_nvram_is_int_type(itype), ("non-integer type"));
 1062 
 1063         /* Determine output byte limit */
 1064         if (outp != NULL)
 1065                 limit = *olen;
 1066         else
 1067                 limit = 0;
 1068 
 1069         /* Fetch output type info */
 1070         otype_base = bhnd_nvram_base_type(otype);
 1071         otype_int = bhnd_nvram_is_int_type(otype);
 1072         otype_signed = bhnd_nvram_is_signed_type(otype_base);
 1073 
 1074         /*
 1075          * Promote integer value to a common 64-bit representation.
 1076          */
 1077         switch (itype) {
 1078         case BHND_NVRAM_TYPE_UINT8:
 1079                 if (ilen != sizeof(uint8_t))
 1080                         return (EFAULT);
 1081 
 1082                 itype_signed = false;
 1083                 intv.u64 = *(const uint8_t *)inp;
 1084                 break;
 1085 
 1086         case BHND_NVRAM_TYPE_UINT16:
 1087                 if (ilen != sizeof(uint16_t))
 1088                         return (EFAULT);
 1089 
 1090                 itype_signed = false;
 1091                 intv.u64 = *(const uint16_t *)inp;
 1092                 break;
 1093 
 1094         case BHND_NVRAM_TYPE_UINT32:
 1095                 if (ilen != sizeof(uint32_t))
 1096                         return (EFAULT);
 1097 
 1098                 itype_signed = false;
 1099                 intv.u64 = *(const uint32_t *)inp;
 1100                 break;
 1101 
 1102         case BHND_NVRAM_TYPE_UINT64:
 1103                 if (ilen != sizeof(uint64_t))
 1104                         return (EFAULT);
 1105 
 1106                 itype_signed = false;
 1107                 intv.u64 = *(const uint64_t *)inp;
 1108                 break;
 1109 
 1110         case BHND_NVRAM_TYPE_INT8:
 1111                 if (ilen != sizeof(int8_t))
 1112                         return (EFAULT);
 1113 
 1114                 itype_signed = true;
 1115                 intv.i64 = *(const int8_t *)inp;
 1116                 break;
 1117 
 1118         case BHND_NVRAM_TYPE_INT16:
 1119                 if (ilen != sizeof(int16_t))
 1120                         return (EFAULT);
 1121 
 1122                 itype_signed = true;
 1123                 intv.i64 = *(const int16_t *)inp;
 1124                 break;
 1125 
 1126         case BHND_NVRAM_TYPE_INT32:
 1127                 if (ilen != sizeof(int32_t))
 1128                         return (EFAULT);
 1129 
 1130                 itype_signed = true;
 1131                 intv.i64 = *(const int32_t *)inp;
 1132                 break;
 1133 
 1134         case BHND_NVRAM_TYPE_INT64:
 1135                 if (ilen != sizeof(int32_t))
 1136                         return (EFAULT);
 1137 
 1138                 itype_signed = true;
 1139                 intv.i64 = *(const int32_t *)inp;
 1140                 break;
 1141 
 1142         default:
 1143                 BHND_NV_PANIC("invalid type %d\n", itype);
 1144         }
 1145 
 1146         /* Perform signed/unsigned conversion */
 1147         if (itype_signed && otype_int && !otype_signed) {
 1148                 if (intv.i64 < 0) {
 1149                         /* Can't represent negative value */
 1150                         BHND_NV_LOG("cannot represent %" PRId64 " as %s\n",
 1151                             intv.i64, bhnd_nvram_type_name(otype));
 1152 
 1153                         return (ERANGE);
 1154                 }
 1155 
 1156                 /* Convert to unsigned representation */
 1157                 intv.u64 = intv.i64;
 1158 
 1159         } else if (!itype_signed && otype_int && otype_signed) {
 1160                 /* Handle unsigned -> signed coercions */
 1161                 if (intv.u64 > INT64_MAX) {
 1162                         /* Can't represent positive value */
 1163                         BHND_NV_LOG("cannot represent %" PRIu64 " as %s\n",
 1164                             intv.u64, bhnd_nvram_type_name(otype));
 1165                         return (ERANGE);
 1166                 }
 1167 
 1168                 /* Convert to signed representation */
 1169                 intv.i64 = intv.u64;
 1170         }
 1171 
 1172         /* Write output */
 1173         switch (otype) {
 1174         case BHND_NVRAM_TYPE_NULL:
 1175                 /* Cannot encode an integer value as NULL */
 1176                 return (EFTYPE);
 1177 
 1178         case BHND_NVRAM_TYPE_BOOL: {
 1179                 bhnd_nvram_bool_t bval;
 1180 
 1181                 if (intv.u64 == 0 || intv.u64 == 1) {
 1182                         bval = intv.u64;
 1183                 } else {
 1184                         /* Encoding as a bool would lose information */
 1185                         return (ERANGE);
 1186                 }
 1187 
 1188                 nbytes = sizeof(bhnd_nvram_bool_t);
 1189                 if (limit >= nbytes)
 1190                         *((bhnd_nvram_bool_t *)outp) = bval;
 1191 
 1192                 break;
 1193         }
 1194 
 1195         case BHND_NVRAM_TYPE_CHAR:
 1196         case BHND_NVRAM_TYPE_CHAR_ARRAY:
 1197         case BHND_NVRAM_TYPE_DATA:
 1198         case BHND_NVRAM_TYPE_UINT8:
 1199         case BHND_NVRAM_TYPE_UINT8_ARRAY:
 1200                 if (intv.u64 > UINT8_MAX)
 1201                         return (ERANGE);
 1202 
 1203                 nbytes = sizeof(uint8_t);
 1204                 if (limit >= nbytes)
 1205                         *((uint8_t *)outp) = (uint8_t)intv.u64;
 1206                 break;
 1207 
 1208         case BHND_NVRAM_TYPE_UINT16:
 1209         case BHND_NVRAM_TYPE_UINT16_ARRAY:
 1210                 if (intv.u64 > UINT16_MAX)
 1211                         return (ERANGE);
 1212 
 1213                 nbytes = sizeof(uint16_t);
 1214                 if (limit >= nbytes)
 1215                         *((uint16_t *)outp) = (uint16_t)intv.u64;
 1216                 break;
 1217 
 1218         case BHND_NVRAM_TYPE_UINT32:
 1219         case BHND_NVRAM_TYPE_UINT32_ARRAY:
 1220                 if (intv.u64 > UINT32_MAX)
 1221                         return (ERANGE);
 1222 
 1223                 nbytes = sizeof(uint32_t);
 1224                 if (limit >= nbytes)
 1225                         *((uint32_t *)outp) = (uint32_t)intv.u64;
 1226                 break;
 1227 
 1228         case BHND_NVRAM_TYPE_UINT64:
 1229         case BHND_NVRAM_TYPE_UINT64_ARRAY:
 1230                 nbytes = sizeof(uint64_t);
 1231                 if (limit >= nbytes)
 1232                         *((uint64_t *)outp) = intv.u64;
 1233                 break;
 1234 
 1235         case BHND_NVRAM_TYPE_INT8:
 1236         case BHND_NVRAM_TYPE_INT8_ARRAY:
 1237                 if (intv.i64 < INT8_MIN || intv.i64 > INT8_MAX)
 1238                         return (ERANGE);
 1239 
 1240                 nbytes = sizeof(int8_t);
 1241                 if (limit >= nbytes)
 1242                         *((int8_t *)outp) = (int8_t)intv.i64;
 1243                 break;
 1244 
 1245         case BHND_NVRAM_TYPE_INT16:
 1246         case BHND_NVRAM_TYPE_INT16_ARRAY:
 1247                 if (intv.i64 < INT16_MIN || intv.i64 > INT16_MAX)
 1248                         return (ERANGE);
 1249 
 1250                 nbytes = sizeof(int16_t);
 1251                 if (limit >= nbytes)
 1252                         *((int16_t *)outp) = (int16_t)intv.i64;
 1253                 break;
 1254 
 1255         case BHND_NVRAM_TYPE_INT32:
 1256         case BHND_NVRAM_TYPE_INT32_ARRAY:
 1257                 if (intv.i64 < INT32_MIN || intv.i64 > INT32_MAX)
 1258                         return (ERANGE);
 1259 
 1260                 nbytes = sizeof(int32_t);
 1261                 if (limit >= nbytes)
 1262                         *((int32_t *)outp) = (int32_t)intv.i64;
 1263                 break;
 1264 
 1265         case BHND_NVRAM_TYPE_INT64:
 1266         case BHND_NVRAM_TYPE_INT64_ARRAY:
 1267                 nbytes = sizeof(int64_t);
 1268                 if (limit >= nbytes)
 1269                         *((int64_t *)outp) = intv.i64;
 1270                 break;
 1271 
 1272         case BHND_NVRAM_TYPE_STRING:
 1273         case BHND_NVRAM_TYPE_STRING_ARRAY: {
 1274                 ssize_t len;
 1275 
 1276                 /* Attempt to write the entry + NUL */
 1277                 if (otype_signed) {
 1278                         len = snprintf(outp, limit, "%" PRId64, intv.i64);
 1279                 } else {
 1280                         len = snprintf(outp, limit, "%" PRIu64, intv.u64);
 1281                 }
 1282 
 1283                 if (len < 0) {
 1284                         BHND_NV_LOG("snprintf() failed: %zd\n", len);
 1285                         return (EFTYPE);
 1286                 }
 1287 
 1288                 /* Set total length to the formatted string length, plus
 1289                  * trailing NUL */
 1290                 nbytes = len + 1;
 1291                 break;
 1292         }
 1293 
 1294         default:
 1295                 BHND_NV_LOG("unknown type %s\n", bhnd_nvram_type_name(otype));
 1296                 return (EFTYPE);
 1297         }
 1298 
 1299         /* Provide required length */
 1300         *olen = nbytes;
 1301         if (limit < *olen) {
 1302                 if (outp == NULL)
 1303                         return (0);
 1304 
 1305                 return (ENOMEM);
 1306         }
 1307 
 1308         return (0);
 1309 }
 1310 
 1311 /**
 1312  * Encode the given @p value as @p otype, writing the result to @p outp.
 1313  *
 1314  * @param               value   The value to be encoded.
 1315  * @param[out]          outp    On success, the value will be written to this 
 1316  *                              buffer. This argment may be NULL if the value is
 1317  *                              not desired.
 1318  * @param[in,out]       olen    The capacity of @p outp. On success, will be set
 1319  *                              to the actual size of the requested value.
 1320  * @param               otype   The data type to be written to @p outp.
 1321  *
 1322  * @retval 0            success
 1323  * @retval ENOMEM       If the @p outp is non-NULL, and the provided @p olen
 1324  *                      is too small to hold the encoded value.
 1325  * @retval EFTYPE       If value coercion from @p value to @p otype is
 1326  *                      impossible.
 1327  * @retval ERANGE       If value coercion would overflow (or underflow) the
 1328  *                      a @p otype representation.
 1329  */
 1330 int
 1331 bhnd_nvram_val_encode(bhnd_nvram_val *value, void *outp, size_t *olen,
 1332     bhnd_nvram_type otype)
 1333 {
 1334         /* Prefer format implementation */
 1335         if (value->fmt->op_encode != NULL)
 1336                 return (value->fmt->op_encode(value, outp, olen, otype));
 1337 
 1338         return (bhnd_nvram_val_generic_encode(value, outp, olen, otype));
 1339 }
 1340 
 1341 /**
 1342  * Encode the given @p value's element as @p otype, writing the result to
 1343  * @p outp.
 1344  *
 1345  * @param               inp     The element to be encoded. Must be a value
 1346  *                              previously returned by bhnd_nvram_val_next()
 1347  *                              or bhnd_nvram_val_elem().
 1348  * @param               ilen    The size of @p inp, as returned by
 1349  *                              bhnd_nvram_val_next() or bhnd_nvram_val_elem().
 1350  * @param[out]          outp    On success, the value will be written to this 
 1351  *                              buffer. This argment may be NULL if the value is
 1352  *                              not desired.
 1353  * @param[in,out]       olen    The capacity of @p outp. On success, will be set
 1354  *                              to the actual size of the requested value.
 1355  * @param               otype   The data type to be written to @p outp.
 1356  *
 1357  * @retval 0            success
 1358  * @retval ENOMEM       If the @p outp is non-NULL, and the provided @p olen
 1359  *                      is too small to hold the encoded value.
 1360  * @retval EFTYPE       If value coercion from @p value to @p otype is
 1361  *                      impossible.
 1362  * @retval ERANGE       If value coercion would overflow (or underflow) the
 1363  *                      a @p otype representation.
 1364  */
 1365 int
 1366 bhnd_nvram_val_encode_elem(bhnd_nvram_val *value, const void *inp,
 1367     size_t ilen, void *outp, size_t *olen, bhnd_nvram_type otype)
 1368 {
 1369         /* Prefer format implementation */
 1370         if (value->fmt->op_encode_elem != NULL) {
 1371                 return (value->fmt->op_encode_elem(value, inp, ilen, outp,
 1372                     olen, otype));
 1373         }
 1374 
 1375         return (bhnd_nvram_val_generic_encode_elem(value, inp, ilen, outp,
 1376             olen, otype));
 1377 }
 1378 
 1379 /**
 1380  * Return the type, size, and a pointer to the internal representation
 1381  * of @p value.
 1382  * 
 1383  * @param       value   The value to be queried.
 1384  * @param[out]  olen    Size of the returned data, in bytes.
 1385  * @param[out]  otype   Data type.
 1386  */
 1387 const void *
 1388 bhnd_nvram_val_bytes(bhnd_nvram_val *value, size_t *olen,
 1389     bhnd_nvram_type *otype)
 1390 {
 1391         /* Provide type and length */
 1392         *otype = value->data_type;
 1393         *olen = value->data_len;
 1394 
 1395         switch (value->data_storage) {
 1396         case BHND_NVRAM_VAL_DATA_EXT_ALLOC:
 1397         case BHND_NVRAM_VAL_DATA_EXT_STATIC:
 1398         case BHND_NVRAM_VAL_DATA_EXT_WEAK:
 1399                 /* Return a pointer to external storage */
 1400                 return (value->data.ptr);
 1401 
 1402         case BHND_NVRAM_VAL_DATA_INLINE:
 1403                 /* Return a pointer to inline storage */
 1404                 return (&value->data);
 1405 
 1406         case BHND_NVRAM_VAL_DATA_NONE:
 1407                 BHND_NV_PANIC("uninitialized value");
 1408         }
 1409 
 1410         BHND_NV_PANIC("unknown storage type: %d", value->data_storage);
 1411 }
 1412 
 1413 /**
 1414  * Iterate over all array elements in @p value.
 1415  *
 1416  * @param               value   The value to be iterated
 1417  * @param               prev    A value pointer previously returned by
 1418  *                              bhnd_nvram_val_next() or bhnd_nvram_val_elem(),
 1419  *                              or NULL to begin iteration at the first element.
 1420  * @param[in,out]       olen    If @p prev is non-NULL, @p olen must be a
 1421  *                              pointer to the length previously returned by
 1422  *                              bhnd_nvram_val_next() or bhnd_nvram_val_elem().
 1423  *                              On success, will be set to the next element's
 1424  *                              length, in bytes.
 1425  *
 1426  * @retval non-NULL     A borrowed reference to the element data.
 1427  * @retval NULL         If the end of the element array is reached.
 1428  */
 1429 const void *
 1430 bhnd_nvram_val_next(bhnd_nvram_val *value, const void *prev, size_t *olen)
 1431 {
 1432         /* Prefer the format implementation */
 1433         if (value->fmt->op_next != NULL)
 1434                 return (value->fmt->op_next(value, prev, olen));
 1435 
 1436         return (bhnd_nvram_val_generic_next(value, prev, olen));
 1437 }
 1438 
 1439 /**
 1440  * Return the value's data type.
 1441  *
 1442  * @param       value   The value to be queried.
 1443  */
 1444 bhnd_nvram_type
 1445 bhnd_nvram_val_type(bhnd_nvram_val *value)
 1446 {
 1447         return (value->data_type);
 1448 }
 1449 
 1450 /**
 1451  * Return value's element data type.
 1452  *
 1453  * @param       value   The value to be queried.
 1454  */
 1455 bhnd_nvram_type
 1456 bhnd_nvram_val_elem_type(bhnd_nvram_val *value)
 1457 {
 1458         return (bhnd_nvram_base_type(value->data_type));
 1459 }
 1460 
 1461 /**
 1462  * Return the total number of elements represented by @p value.
 1463  */
 1464 size_t
 1465 bhnd_nvram_val_nelem(bhnd_nvram_val *value)
 1466 {
 1467         const void      *bytes;
 1468         bhnd_nvram_type  type;
 1469         size_t           nelem, len;
 1470         int              error;
 1471 
 1472         /* Prefer format implementation */
 1473         if (value->fmt->op_nelem != NULL)
 1474                 return (value->fmt->op_nelem(value));
 1475 
 1476         /*
 1477          * If a custom op_next() is defined, bhnd_nvram_value_nelem() almost
 1478          * certainly cannot produce a valid element count; it assumes a standard
 1479          * data format that may not apply when custom iteration is required.
 1480          *
 1481          * Instead, use bhnd_nvram_val_next() to parse the backing data and
 1482          * produce a total count.
 1483          */
 1484         if (value->fmt->op_next != NULL) {
 1485                 const void *next;
 1486 
 1487                 next = NULL;
 1488                 nelem = 0;
 1489                 while ((next = bhnd_nvram_val_next(value, next, &len)) != NULL)
 1490                         nelem++;
 1491 
 1492                 return (nelem);
 1493         }
 1494 
 1495         /* Otherwise, compute the standard element count */
 1496         bytes = bhnd_nvram_val_bytes(value, &len, &type);
 1497         if ((error = bhnd_nvram_value_nelem(bytes, len, type, &nelem))) {
 1498                 /* Should always succeed */
 1499                 BHND_NV_PANIC("error calculating element count for type '%s' "
 1500                     "with length %zu: %d\n", bhnd_nvram_type_name(type), len,
 1501                     error);
 1502         }
 1503 
 1504         return (nelem);
 1505 }
 1506 
 1507 /**
 1508  * Generic implementation of bhnd_nvram_val_op_encode(), compatible with
 1509  * all supported NVRAM data types.
 1510  */
 1511 int
 1512 bhnd_nvram_val_generic_encode(bhnd_nvram_val *value, void *outp, size_t *olen,
 1513     bhnd_nvram_type otype)
 1514 {
 1515         const void      *inp;
 1516         bhnd_nvram_type  itype;
 1517         size_t           ilen;
 1518         const void      *next;
 1519         bhnd_nvram_type  otype_base;
 1520         size_t           limit, nelem, nbytes;
 1521         size_t           next_len;
 1522         int              error;
 1523 
 1524         nbytes = 0;
 1525         nelem = 0;
 1526         otype_base = bhnd_nvram_base_type(otype);
 1527         inp = bhnd_nvram_val_bytes(value, &ilen, &itype);
 1528 
 1529         /*
 1530          * Normally, an array type is not universally representable as
 1531          * non-array type.
 1532          * 
 1533          * As exceptions, we support conversion directly to/from:
 1534          *      - CHAR_ARRAY/STRING:
 1535          *              ->STRING        Interpret the character array as a
 1536          *                              non-NUL-terminated string.
 1537          *              ->CHAR_ARRAY    Trim the trailing NUL from the string.
 1538          */
 1539 #define BHND_NV_IS_ISO_CONV(_lhs, _rhs)         \
 1540         ((itype == BHND_NVRAM_TYPE_ ## _lhs &&  \
 1541           otype == BHND_NVRAM_TYPE_ ## _rhs) || \
 1542          (itype == BHND_NVRAM_TYPE_ ## _rhs &&  \
 1543           otype == BHND_NVRAM_TYPE_ ## _lhs))
 1544 
 1545         if (BHND_NV_IS_ISO_CONV(CHAR_ARRAY, STRING)) {
 1546                 return (bhnd_nvram_val_encode_elem(value, inp, ilen, outp, olen,
 1547                     otype));
 1548         }
 1549 
 1550 #undef  BHND_NV_IS_ISO_CONV
 1551 
 1552         /*
 1553          * If both input and output are non-array types, try to encode them
 1554          * without performing element iteration.
 1555          */
 1556         if (!bhnd_nvram_is_array_type(itype) &&
 1557             !bhnd_nvram_is_array_type(otype))
 1558         {
 1559                 return (bhnd_nvram_val_encode_elem(value, inp, ilen, outp, olen,
 1560                     otype));
 1561         }
 1562 
 1563         /* Determine output byte limit */
 1564         if (outp != NULL)
 1565                 limit = *olen;
 1566         else
 1567                 limit = 0;
 1568 
 1569         /* Iterate over our array elements and encode as the requested
 1570          * type */
 1571         next = NULL;
 1572         while ((next = bhnd_nvram_val_next(value, next, &next_len))) {
 1573                 void                    *elem_outp;
 1574                 size_t                   elem_nbytes;
 1575 
 1576                 /* If the output type is not an array type, we can only encode
 1577                  * one element */
 1578                 nelem++;
 1579                 if (nelem > 1 && !bhnd_nvram_is_array_type(otype)) {
 1580                         return (EFTYPE);
 1581                 }
 1582 
 1583                 /* Determine output offset / limit */
 1584                 if (nbytes >= limit) {
 1585                         elem_nbytes = 0;
 1586                         elem_outp = NULL;
 1587                 } else {
 1588                         elem_nbytes = limit - nbytes;
 1589                         elem_outp = (uint8_t *)outp + nbytes;
 1590                 }
 1591 
 1592                 /* Attempt encode */
 1593                 error = bhnd_nvram_val_encode_elem(value, next, next_len,
 1594                     elem_outp, &elem_nbytes, otype_base);
 1595 
 1596                 /* If encoding failed for any reason other than ENOMEM (which
 1597                  * we'll detect and report below), return immediately */
 1598                 if (error && error != ENOMEM)
 1599                         return (error);
 1600 
 1601                 /* Add to total length */
 1602                 if (SIZE_MAX - nbytes < elem_nbytes)
 1603                         return (EFTYPE); /* would overflow size_t */
 1604 
 1605                 nbytes += elem_nbytes;
 1606         }
 1607 
 1608         /* Provide the actual length */
 1609         *olen = nbytes;
 1610 
 1611         /* If no output was requested, nothing left to do */
 1612         if (outp == NULL)
 1613                 return (0);
 1614 
 1615         /* Otherwise, report a memory error if the output buffer was too
 1616          * small */
 1617         if (limit < nbytes)
 1618                 return (ENOMEM);
 1619 
 1620         return (0);
 1621 }
 1622 
 1623 /**
 1624  * Generic implementation of bhnd_nvram_val_op_encode_elem(), compatible with
 1625  * all supported NVRAM data types.
 1626  */
 1627 int
 1628 bhnd_nvram_val_generic_encode_elem(bhnd_nvram_val *value, const void *inp,
 1629     size_t ilen, void *outp, size_t *olen, bhnd_nvram_type otype)
 1630 {
 1631         bhnd_nvram_type itype;
 1632 
 1633         itype = bhnd_nvram_val_elem_type(value);
 1634         switch (itype) {
 1635         case BHND_NVRAM_TYPE_NULL:
 1636                 return (bhnd_nvram_val_encode_null(inp, ilen, itype, outp, olen,
 1637                     otype));
 1638 
 1639         case BHND_NVRAM_TYPE_DATA:
 1640                 return (bhnd_nvram_val_encode_data(inp, ilen, itype, outp,
 1641                     olen, otype));
 1642 
 1643         case BHND_NVRAM_TYPE_STRING:
 1644         case BHND_NVRAM_TYPE_CHAR:
 1645                 return (bhnd_nvram_val_encode_string(inp, ilen, itype, outp,
 1646                     olen, otype));
 1647 
 1648         case BHND_NVRAM_TYPE_BOOL:
 1649                 return (bhnd_nvram_val_encode_bool(inp, ilen, itype, outp, olen,
 1650                     otype));
 1651 
 1652         case BHND_NVRAM_TYPE_UINT8:
 1653         case BHND_NVRAM_TYPE_UINT16:
 1654         case BHND_NVRAM_TYPE_UINT32:
 1655         case BHND_NVRAM_TYPE_UINT64:
 1656         case BHND_NVRAM_TYPE_INT8:
 1657         case BHND_NVRAM_TYPE_INT16:
 1658         case BHND_NVRAM_TYPE_INT32:
 1659         case BHND_NVRAM_TYPE_INT64:
 1660                 return (bhnd_nvram_val_encode_int(inp, ilen, itype, outp, olen,
 1661                     otype));    
 1662         default:
 1663                 BHND_NV_PANIC("missing encode_elem() implementation");
 1664         }
 1665 }
 1666 
 1667 /**
 1668  * Generic implementation of bhnd_nvram_val_op_next(), compatible with
 1669  * all supported NVRAM data types.
 1670  */
 1671 const void *
 1672 bhnd_nvram_val_generic_next(bhnd_nvram_val *value, const void *prev,
 1673     size_t *olen)
 1674 {
 1675         const uint8_t   *inp;
 1676         bhnd_nvram_type  itype;
 1677         size_t           ilen;
 1678 
 1679         /* Iterate over the backing representation */
 1680         inp = bhnd_nvram_val_bytes(value, &ilen, &itype);
 1681         return (bhnd_nvram_value_array_next(inp, ilen, itype, prev, olen));
 1682 }
 1683 
 1684 /**
 1685  * Initialize the representation of @p value with @p ptr.
 1686  *
 1687  * @param       value   The value to be initialized.
 1688  * @param       inp     The external representation.
 1689  * @param       ilen    The external representation length, in bytes.
 1690  * @param       itype   The external representation's data type.
 1691  * @param       flags   Value flags.
 1692  * 
 1693  * @retval 0            success.
 1694  * @retval ENOMEM       if allocation fails
 1695  * @retval EFTYPE       if @p itype is not an array type, and @p ilen is not
 1696  *                      equal to the size of a single element of @p itype.
 1697  * @retval EFAULT       if @p ilen is not correctly aligned for elements of
 1698  *                      @p itype.
 1699  */
 1700 static int
 1701 bhnd_nvram_val_set(bhnd_nvram_val *value, const void *inp, size_t ilen,
 1702     bhnd_nvram_type itype, uint32_t flags)
 1703 {
 1704         void    *bytes;
 1705         int      error;
 1706 
 1707         BHND_NVRAM_VAL_ASSERT_EMPTY(value);
 1708 
 1709         /* Validate alignment */
 1710         if ((error = bhnd_nvram_value_check_aligned(inp, ilen, itype)))
 1711                 return (error);
 1712 
 1713         /* Reference the external data */
 1714         if ((flags & BHND_NVRAM_VAL_BORROW_DATA) ||
 1715             (flags & BHND_NVRAM_VAL_STATIC_DATA))
 1716         {
 1717                 if (flags & BHND_NVRAM_VAL_STATIC_DATA)
 1718                         value->data_storage = BHND_NVRAM_VAL_DATA_EXT_STATIC;
 1719                 else
 1720                         value->data_storage = BHND_NVRAM_VAL_DATA_EXT_WEAK;
 1721 
 1722                 value->data.ptr = inp;
 1723                 value->data_type = itype;
 1724                 value->data_len = ilen;
 1725                 return (0);
 1726         }
 1727 
 1728         /* Fetch reference to (or allocate) an appropriately sized buffer */
 1729         bytes = bhnd_nvram_val_alloc_bytes(value, ilen, itype, flags);
 1730         if (bytes == NULL)
 1731                 return (ENOMEM);
 1732 
 1733         /* Copy data */
 1734         memcpy(bytes, inp, ilen);
 1735 
 1736         return (0);
 1737 }
 1738 
 1739 /**
 1740  * Initialize the internal inline representation of @p value with a copy of
 1741  * the data referenced by @p inp of @p itype.
 1742  * 
 1743  * If @p inp is NULL, @p itype and @p ilen will be validated, but no data will
 1744  * be copied.
 1745  *
 1746  * @param       value   The value to be initialized.
 1747  * @param       inp     The input data to be copied, or NULL to verify
 1748  *                      that data of @p ilen and @p itype can be represented
 1749  *                      inline.
 1750  * @param       ilen    The size of the external buffer to be allocated.
 1751  * @param       itype   The type of the external buffer to be allocated.
 1752  * 
 1753  * @retval 0            success
 1754  * @retval ENOMEM       if @p ilen is too large to be represented inline.
 1755  * @retval EFAULT       if @p ilen is not correctly aligned for elements of
 1756  *                      @p itype.
 1757  */
 1758 static int
 1759 bhnd_nvram_val_set_inline(bhnd_nvram_val *value, const void *inp, size_t ilen,
 1760     bhnd_nvram_type itype)
 1761 {
 1762         BHND_NVRAM_VAL_ASSERT_EMPTY(value);
 1763 
 1764 #define NV_STORE_INIT_INLINE()  do {                                    \
 1765         value->data_len = ilen;                                         \
 1766         value->data_type = itype;                                       \
 1767 } while(0)
 1768 
 1769 #define NV_STORE_INLINE(_type, _dest)   do {                            \
 1770         if (ilen != sizeof(_type))                                      \
 1771                 return (EFAULT);                                        \
 1772                                                                         \
 1773         if (inp != NULL) {                                              \
 1774                 value->data._dest[0] = *(const _type *)inp;             \
 1775                 NV_STORE_INIT_INLINE();                                 \
 1776         }                                                               \
 1777 } while (0)
 1778 
 1779 #define NV_COPY_ARRRAY_INLINE(_type, _dest)     do {            \
 1780         if (ilen % sizeof(_type) != 0)                          \
 1781                 return (EFAULT);                                \
 1782                                                                 \
 1783         if (ilen > nitems(value->data. _dest))                  \
 1784                 return (ENOMEM);                                \
 1785                                                                 \
 1786         if (inp == NULL)                                        \
 1787                 return (0);                                     \
 1788                                                                 \
 1789         memcpy(&value->data._dest, inp, ilen);                  \
 1790         if (inp != NULL) {                                      \
 1791                 memcpy(&value->data._dest, inp, ilen);          \
 1792                 NV_STORE_INIT_INLINE();                         \
 1793         }                                                       \
 1794 } while (0)
 1795 
 1796         /* Attempt to copy to inline storage */
 1797         switch (itype) {
 1798         case BHND_NVRAM_TYPE_NULL:
 1799                 if (ilen != 0)
 1800                         return (EFAULT);
 1801 
 1802                 /* Nothing to copy */
 1803                 NV_STORE_INIT_INLINE();
 1804                 return (0);
 1805 
 1806         case BHND_NVRAM_TYPE_CHAR:
 1807                 NV_STORE_INLINE(uint8_t, ch);
 1808                 return (0);
 1809 
 1810         case BHND_NVRAM_TYPE_BOOL:
 1811                 NV_STORE_INLINE(bhnd_nvram_bool_t, b);
 1812                 return(0);
 1813 
 1814         case BHND_NVRAM_TYPE_UINT8:
 1815         case BHND_NVRAM_TYPE_INT8:
 1816                 NV_STORE_INLINE(uint8_t, u8);
 1817                 return (0);
 1818 
 1819         case BHND_NVRAM_TYPE_UINT16:
 1820         case BHND_NVRAM_TYPE_INT16:
 1821                 NV_STORE_INLINE(uint16_t, u16);
 1822                 return (0);
 1823 
 1824         case BHND_NVRAM_TYPE_UINT32:
 1825         case BHND_NVRAM_TYPE_INT32:
 1826                 NV_STORE_INLINE(uint32_t, u32);
 1827                 return (0);
 1828 
 1829         case BHND_NVRAM_TYPE_UINT64:
 1830         case BHND_NVRAM_TYPE_INT64:
 1831                 NV_STORE_INLINE(uint32_t, u32);
 1832                 return (0);
 1833 
 1834         case BHND_NVRAM_TYPE_CHAR_ARRAY:
 1835                 NV_COPY_ARRRAY_INLINE(uint8_t, ch);
 1836                 return (0);
 1837 
 1838         case BHND_NVRAM_TYPE_DATA:
 1839         case BHND_NVRAM_TYPE_UINT8_ARRAY:
 1840         case BHND_NVRAM_TYPE_INT8_ARRAY:
 1841                 NV_COPY_ARRRAY_INLINE(uint8_t, u8);
 1842                 return (0);
 1843 
 1844         case BHND_NVRAM_TYPE_UINT16_ARRAY:
 1845         case BHND_NVRAM_TYPE_INT16_ARRAY:
 1846                 NV_COPY_ARRRAY_INLINE(uint16_t, u16);
 1847                 return (0);
 1848 
 1849         case BHND_NVRAM_TYPE_UINT32_ARRAY:
 1850         case BHND_NVRAM_TYPE_INT32_ARRAY:
 1851                 NV_COPY_ARRRAY_INLINE(uint32_t, u32);
 1852                 return (0);
 1853 
 1854         case BHND_NVRAM_TYPE_UINT64_ARRAY:
 1855         case BHND_NVRAM_TYPE_INT64_ARRAY:
 1856                 NV_COPY_ARRRAY_INLINE(uint64_t, u64);
 1857                 return (0);
 1858 
 1859         case BHND_NVRAM_TYPE_BOOL_ARRAY:
 1860                 NV_COPY_ARRRAY_INLINE(bhnd_nvram_bool_t, b);
 1861                 return(0);
 1862 
 1863         case BHND_NVRAM_TYPE_STRING:
 1864         case BHND_NVRAM_TYPE_STRING_ARRAY:
 1865                 if (ilen > sizeof(value->data.ch))
 1866                         return (ENOMEM);
 1867 
 1868                 if (inp != NULL) {
 1869                         memcpy(&value->data.ch, inp, ilen);
 1870                         NV_STORE_INIT_INLINE();
 1871                 }
 1872 
 1873                 return (0);
 1874         }
 1875 
 1876 #undef  NV_STORE_INIT_INLINE
 1877 #undef  NV_STORE_INLINE
 1878 #undef  NV_COPY_ARRRAY_INLINE
 1879 
 1880         BHND_NV_PANIC("unknown data type %d", itype);
 1881 }
 1882 
 1883 /**
 1884  * Initialize the internal representation of @p value with a buffer allocation
 1885  * of @p len and @p itype, returning a pointer to the allocated buffer.
 1886  * 
 1887  * If a buffer of @p len and @p itype can be represented inline, no
 1888  * external buffer will be allocated, and instead a pointer to the inline
 1889  * data representation will be returned.
 1890  *
 1891  * @param       value   The value to be initialized.
 1892  * @param       ilen    The size of the external buffer to be allocated.
 1893  * @param       itype   The type of the external buffer to be allocated.
 1894  * @param       flags   Value flags.
 1895  * 
 1896  * @retval non-null     The newly allocated buffer.
 1897  * @retval NULL         If allocation failed.
 1898  * @retval NULL         If @p value is an externally allocated instance.
 1899  */
 1900 static void *
 1901 bhnd_nvram_val_alloc_bytes(bhnd_nvram_val *value, size_t ilen,
 1902     bhnd_nvram_type itype, uint32_t flags)
 1903 {
 1904         void *ptr;
 1905 
 1906         BHND_NVRAM_VAL_ASSERT_EMPTY(value);
 1907 
 1908         /* Can we use inline storage? */
 1909         if (bhnd_nvram_val_set_inline(value, NULL, ilen, itype) == 0) {
 1910                 BHND_NV_ASSERT(sizeof(value->data) >= ilen,
 1911                     ("ilen exceeds inline storage"));
 1912 
 1913                 value->data_type = itype;
 1914                 value->data_len = ilen;
 1915                 value->data_storage = BHND_NVRAM_VAL_DATA_INLINE;
 1916                 return (&value->data);
 1917         }
 1918 
 1919         /* Is allocation permitted? */
 1920         if (!(flags & BHND_NVRAM_VAL_DYNAMIC))
 1921                 return (NULL);
 1922 
 1923         /* Allocate external storage */
 1924         if ((ptr = bhnd_nv_malloc(ilen)) == NULL)
 1925                 return (NULL);
 1926 
 1927         value->data.ptr = ptr;
 1928         value->data_len = ilen;
 1929         value->data_type = itype;
 1930         value->data_storage = BHND_NVRAM_VAL_DATA_EXT_ALLOC;
 1931 
 1932         return (ptr);
 1933 }

Cache object: c0b841babb9125f18afd629b1058d986


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.