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_subr.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 
   35 #ifdef _KERNEL
   36 
   37 #include <sys/systm.h>
   38 
   39 #else /* !_KERNEL */
   40 
   41 #include <errno.h>
   42 #include <string.h>
   43 
   44 #endif /* _KERNEL */
   45 
   46 #include "bhnd_nvram_private.h"
   47 #include "bhnd_nvram_valuevar.h"
   48 
   49 /**
   50  * Validate the alignment of a value of @p type.
   51  * 
   52  * @param       inp     The value data.
   53  * @param       ilen    The value length, in bytes.
   54  * @param       itype   The value type.
   55  *
   56  * @retval 0            success
   57  * @retval EFTYPE       if @p type is not an array type, and @p len is not
   58  *                      equal to the size of a single element of @p type.
   59  * @retval EFAULT       if @p data is not correctly aligned to the required
   60  *                      host alignment.
   61  * @retval EFAULT       if @p len is not aligned to the @p type width.
   62  */
   63 int
   64 bhnd_nvram_value_check_aligned(const void *inp, size_t ilen,
   65     bhnd_nvram_type itype)
   66 {
   67         size_t align, width;
   68 
   69         /* As a special case, NULL values have no alignment, but must
   70          * always have a length of zero */
   71         if (itype == BHND_NVRAM_TYPE_NULL) {
   72                 if (ilen != 0)
   73                         return (EFAULT);
   74 
   75                 return (0);
   76         }
   77 
   78         /* Check pointer alignment against the required host alignment */
   79         align = bhnd_nvram_type_host_align(itype);
   80         BHND_NV_ASSERT(align != 0, ("invalid zero alignment"));
   81         if ((uintptr_t)inp % align != 0)
   82                 return (EFAULT);
   83 
   84         /* If type is not fixed width, nothing else to check */
   85         width = bhnd_nvram_type_width(itype);
   86         if (width == 0)
   87                 return (0);
   88 
   89         /* Length must be aligned to the element width */
   90         if (ilen % width != 0)
   91                 return (EFAULT);
   92 
   93         /* If the type is not an array type, the length must be equal to the
   94          * size of a single element of @p type. */
   95         if (!bhnd_nvram_is_array_type(itype) && ilen != width)
   96                         return (EFTYPE);
   97 
   98         return (0);
   99 }
  100 
  101 /**
  102  * Calculate the number of elements represented by a value of @p ilen bytes
  103  * with @p itype.
  104  *
  105  * @param       inp     The value data.
  106  * @param       ilen    The value length.
  107  * @param       itype   The value type.
  108  * @param[out]  nelem   On success, the number of elements.
  109  *
  110  * @retval 0            success
  111  * @retval EINVAL       if @p inp is NULL and the element count of @p itype
  112  *                      cannot be determined without parsing the value data.
  113  * @retval EFTYPE       if @p itype is not an array type, and @p ilen is not
  114  *                      equal to the size of a single element of @p itype.
  115  * @retval EFAULT       if @p ilen is not correctly aligned for elements of
  116  *                      @p itype.
  117  */
  118 int
  119 bhnd_nvram_value_nelem(const void *inp, size_t ilen, bhnd_nvram_type itype,
  120     size_t *nelem)
  121 {
  122         int     error;
  123 
  124         BHND_NV_ASSERT(inp != NULL, ("NULL inp"));
  125 
  126         /* Check alignment */
  127         if ((error = bhnd_nvram_value_check_aligned(inp, ilen, itype)))
  128                 return (error);
  129 
  130         switch (itype) {
  131         case BHND_NVRAM_TYPE_DATA:
  132                 /* Always exactly one element */
  133                 *nelem = 1;
  134                 return (0);
  135 
  136         case BHND_NVRAM_TYPE_NULL:
  137                 /* Must be zero length */
  138                 if (ilen != 0)
  139                         return (EFAULT);
  140 
  141                 /* Always exactly one element */
  142                 *nelem = 1;
  143                 return (0);
  144 
  145         case BHND_NVRAM_TYPE_STRING:
  146                 /* Always exactly one element */
  147                 *nelem = 1;
  148                 return (0);
  149 
  150         case BHND_NVRAM_TYPE_STRING_ARRAY: {
  151                 const char      *p;
  152                 size_t           nleft;
  153 
  154                 /* Iterate over the NUL-terminated strings to calculate
  155                  * total element count */
  156                 p = inp;
  157                 nleft = ilen;
  158                 *nelem = 0;
  159                 while (nleft > 0) {
  160                         size_t slen;
  161 
  162                         /* Increment element count */
  163                         (*nelem)++;
  164 
  165                         /* Determine string length */
  166                         slen = strnlen(p, nleft);
  167                         nleft -= slen;
  168 
  169                         /* Advance input */
  170                         p += slen;
  171 
  172                         /* Account for trailing NUL, if we haven't hit the end
  173                          * of the input */
  174                         if (nleft > 0) {
  175                                 nleft--;
  176                                 p++;
  177                         }
  178                 }
  179 
  180                 return (0);
  181         }
  182 
  183         case BHND_NVRAM_TYPE_UINT8_ARRAY:
  184         case BHND_NVRAM_TYPE_UINT16_ARRAY:
  185         case BHND_NVRAM_TYPE_UINT32_ARRAY:
  186         case BHND_NVRAM_TYPE_UINT64_ARRAY:
  187         case BHND_NVRAM_TYPE_INT8_ARRAY:
  188         case BHND_NVRAM_TYPE_INT16_ARRAY:
  189         case BHND_NVRAM_TYPE_INT32_ARRAY:
  190         case BHND_NVRAM_TYPE_INT64_ARRAY:
  191         case BHND_NVRAM_TYPE_CHAR_ARRAY:
  192         case BHND_NVRAM_TYPE_BOOL_ARRAY: {
  193                 size_t width = bhnd_nvram_type_width(itype);
  194                 BHND_NV_ASSERT(width != 0, ("invalid width"));
  195 
  196                 *nelem = ilen / width;
  197                 return (0);
  198         }
  199 
  200         case BHND_NVRAM_TYPE_INT8:
  201         case BHND_NVRAM_TYPE_UINT8:
  202         case BHND_NVRAM_TYPE_CHAR:
  203         case BHND_NVRAM_TYPE_INT16:
  204         case BHND_NVRAM_TYPE_UINT16:
  205         case BHND_NVRAM_TYPE_INT32:
  206         case BHND_NVRAM_TYPE_UINT32:
  207         case BHND_NVRAM_TYPE_INT64:
  208         case BHND_NVRAM_TYPE_UINT64:
  209         case BHND_NVRAM_TYPE_BOOL:
  210                 /* Length must be equal to the size of exactly one
  211                  * element (arrays can represent zero elements -- non-array
  212                  * types cannot) */
  213                 if (ilen != bhnd_nvram_type_width(itype))
  214                         return (EFTYPE);
  215                 *nelem = 1;
  216                 return (0);
  217         }
  218 
  219         /* Quiesce gcc4.2 */
  220         BHND_NV_PANIC("bhnd nvram type %u unknown", itype);
  221 }
  222 
  223 /**
  224  * Return the size, in bytes, of a value of @p itype with @p nelem elements.
  225  * 
  226  * @param       inp     The actual data to be queried, or NULL if unknown. If
  227  *                      NULL and the base type is not a fixed width type
  228  *                      (e.g. BHND_NVRAM_TYPE_STRING), 0 will be returned.
  229  * @param       ilen    The size of @p inp, in bytes, or 0 if @p inp is NULL.
  230  * @param       itype   The value type.
  231  * @param       nelem   The number of elements. If @p itype is not an array
  232  *                      type, this value must be 1.
  233  * 
  234  * @retval 0            If @p itype has a variable width, and @p inp is NULL.
  235  * @retval 0            If a @p nelem value greater than 1 is provided for a
  236  *                      non-array @p itype.
  237  * @retval 0            If a @p nelem value of 0 is provided.
  238  * @retval 0            If the result would exceed the maximum value
  239  *                      representable by size_t.
  240  * @retval 0            If @p itype is BHND_NVRAM_TYPE_NULL.
  241  * @retval non-zero     The size, in bytes, of @p itype with @p nelem elements.
  242  */
  243 size_t
  244 bhnd_nvram_value_size(const void *inp, size_t ilen, bhnd_nvram_type itype,
  245     size_t nelem)
  246 {
  247         /* If nelem 0, nothing to do */
  248         if (nelem == 0)
  249                 return (0);
  250 
  251         /* Non-array types must have an nelem value of 1 */
  252         if (!bhnd_nvram_is_array_type(itype) && nelem != 1)
  253                 return (0);
  254 
  255         switch (itype) {
  256         case BHND_NVRAM_TYPE_UINT8_ARRAY:
  257         case BHND_NVRAM_TYPE_UINT16_ARRAY:
  258         case BHND_NVRAM_TYPE_UINT32_ARRAY:
  259         case BHND_NVRAM_TYPE_UINT64_ARRAY:
  260         case BHND_NVRAM_TYPE_INT8_ARRAY:
  261         case BHND_NVRAM_TYPE_INT16_ARRAY:
  262         case BHND_NVRAM_TYPE_INT32_ARRAY:
  263         case BHND_NVRAM_TYPE_INT64_ARRAY:
  264         case BHND_NVRAM_TYPE_CHAR_ARRAY:
  265         case BHND_NVRAM_TYPE_BOOL_ARRAY:{
  266                 size_t width;
  267 
  268                 width = bhnd_nvram_type_width(itype);
  269 
  270                 /* Would nelem * width overflow? */
  271                 if (SIZE_MAX / nelem < width) {
  272                         BHND_NV_LOG("cannot represent size %s[%zu]\n",
  273                             bhnd_nvram_type_name(bhnd_nvram_base_type(itype)),
  274                             nelem);
  275                         return (0);
  276                 }
  277 
  278                 return (nelem * width);
  279         }
  280 
  281         case BHND_NVRAM_TYPE_STRING_ARRAY: {
  282                 const char      *p;
  283                 size_t           total_size;
  284 
  285                 if (inp == NULL)
  286                         return (0);
  287 
  288                 /* Iterate over the NUL-terminated strings to calculate
  289                  * total byte length */
  290                 p = inp;
  291                 total_size = 0;
  292                 for (size_t i = 0; i < nelem; i++) {
  293                         size_t  elem_size;
  294 
  295                         elem_size = strnlen(p, ilen - total_size);
  296                         p += elem_size;
  297 
  298                         /* Check for (and skip) terminating NUL */
  299                         if (total_size < ilen && *p == '\0') {
  300                                 elem_size++;
  301                                 p++;
  302                         }
  303 
  304                         /* Would total_size + elem_size overflow?
  305                          * 
  306                          * A memory range larger than SIZE_MAX shouldn't be,
  307                          * possible, but include the check for completeness */
  308                         if (SIZE_MAX - total_size < elem_size)
  309                                 return (0);
  310 
  311                         total_size += elem_size;
  312                 }
  313 
  314                 return (total_size);
  315         }
  316 
  317         case BHND_NVRAM_TYPE_STRING: {
  318                 size_t size;
  319 
  320                 if (inp == NULL)
  321                         return (0);
  322 
  323                 /* Find length */
  324                 size = strnlen(inp, ilen);
  325 
  326                 /* Is there a terminating NUL, or did we just hit the
  327                  * end of the string input */
  328                 if (size < ilen)
  329                         size++;
  330 
  331                 return (size);
  332         }
  333 
  334         case BHND_NVRAM_TYPE_NULL:
  335                 return (0);
  336 
  337         case BHND_NVRAM_TYPE_DATA:
  338                 if (inp == NULL)
  339                         return (0);
  340 
  341                 return (ilen);
  342 
  343         case BHND_NVRAM_TYPE_BOOL:
  344                 return (sizeof(bhnd_nvram_bool_t));
  345 
  346         case BHND_NVRAM_TYPE_INT8:
  347         case BHND_NVRAM_TYPE_UINT8:
  348         case BHND_NVRAM_TYPE_CHAR:
  349                 return (sizeof(uint8_t));
  350 
  351         case BHND_NVRAM_TYPE_INT16:
  352         case BHND_NVRAM_TYPE_UINT16:
  353                 return (sizeof(uint16_t));
  354 
  355         case BHND_NVRAM_TYPE_INT32:
  356         case BHND_NVRAM_TYPE_UINT32:
  357                 return (sizeof(uint32_t));
  358 
  359         case BHND_NVRAM_TYPE_UINT64:
  360         case BHND_NVRAM_TYPE_INT64:
  361                 return (sizeof(uint64_t));
  362         }
  363 
  364         /* Quiesce gcc4.2 */
  365         BHND_NV_PANIC("bhnd nvram type %u unknown", itype);
  366 }
  367 
  368 /**
  369  * Format a string representation of @p inp using @p fmt, with, writing the
  370  * result to @p outp.
  371  *
  372  * Refer to bhnd_nvram_val_vprintf() for full format string documentation.
  373  *
  374  * @param               fmt     The format string.
  375  * @param               inp     The value to be formatted.
  376  * @param               ilen    The size of @p inp, in bytes.
  377  * @param               itype   The type of @p inp.
  378  * @param[out]          outp    On success, the string value will be written to
  379  *                              this buffer. This argment may be NULL if the
  380  *                              value is not desired.
  381  * @param[in,out]       olen    The capacity of @p outp. On success, will be set
  382  *                              to the actual size of the formatted string.
  383  *
  384  * @retval 0            success
  385  * @retval EINVAL       If @p fmt contains unrecognized format string
  386  *                      specifiers.
  387  * @retval ENOMEM       If the @p outp is non-NULL, and the provided @p olen
  388  *                      is too small to hold the encoded value.
  389  * @retval EFTYPE       If value coercion from @p inp to a string value via
  390  *                      @p fmt is unsupported.
  391  * @retval ERANGE       If value coercion of @p value would overflow (or
  392  *                      underflow) the representation defined by @p fmt.
  393  */
  394 int
  395 bhnd_nvram_value_printf(const char *fmt, const void *inp, size_t ilen,
  396     bhnd_nvram_type itype, char *outp, size_t *olen, ...)
  397 {
  398         va_list ap;
  399         int     error;
  400 
  401         va_start(ap, olen);
  402         error = bhnd_nvram_value_vprintf(fmt, inp, ilen, itype, outp, olen, ap);
  403         va_end(ap);
  404 
  405         return (error);
  406 }
  407 
  408 /**
  409  * Format a string representation of @p inp using @p fmt, with, writing the
  410  * result to @p outp.
  411  *
  412  * Refer to bhnd_nvram_val_vprintf() for full format string documentation.
  413  *
  414  * @param               fmt     The format string.
  415  * @param               inp     The value to be formatted.
  416  * @param               ilen    The size of @p inp, in bytes.
  417  * @param               itype   The type of @p inp.
  418  * @param[out]          outp    On success, the string value will be written to
  419  *                              this buffer. This argment may be NULL if the
  420  *                              value is not desired.
  421  * @param[in,out]       olen    The capacity of @p outp. On success, will be set
  422  *                              to the actual size of the formatted string.
  423  * @param               ap      Argument list.
  424  *
  425  * @retval 0            success
  426  * @retval EINVAL       If @p fmt contains unrecognized format string
  427  *                      specifiers.
  428  * @retval ENOMEM       If the @p outp is non-NULL, and the provided @p olen
  429  *                      is too small to hold the encoded value.
  430  * @retval EFTYPE       If value coercion from @p inp to a string value via
  431  *                      @p fmt is unsupported.
  432  * @retval ERANGE       If value coercion of @p value would overflow (or
  433  *                      underflow) the representation defined by @p fmt.
  434  */
  435 int
  436 bhnd_nvram_value_vprintf(const char *fmt, const void *inp, size_t ilen,
  437     bhnd_nvram_type itype, char *outp, size_t *olen, va_list ap)
  438 {
  439         bhnd_nvram_val  val;
  440         int             error;
  441 
  442         /* Map input buffer as a value instance */
  443         error = bhnd_nvram_val_init(&val, NULL, inp, ilen, itype,
  444             BHND_NVRAM_VAL_BORROW_DATA);
  445         if (error)
  446                 return (error);
  447 
  448         /* Attempt to format the value */
  449         error = bhnd_nvram_val_vprintf(&val, fmt, outp, olen, ap);
  450 
  451         /* Clean up */
  452         bhnd_nvram_val_release(&val);
  453         return (error);
  454 }
  455 
  456 /**
  457  * Iterate over all elements in @p inp.
  458  *
  459  * @param               inp     The value to be iterated.
  460  * @param               ilen    The size, in bytes, of @p inp.
  461  * @param               itype   The data type of @p inp.
  462  * @param               prev    The value previously returned by
  463  *                              bhnd_nvram_value_array_next(), or NULL to begin
  464  *                              iteration.
  465  * @param[in,out]       olen    If @p prev is non-NULL, @p olen must be a
  466  *                              pointer to the length previously returned by
  467  *                              bhnd_nvram_value_array_next(). On success, will
  468  *                              be set to the next element's length, in bytes.
  469  *
  470  * @retval non-NULL     A borrowed reference to the next element of @p inp.
  471  * @retval NULL         If the end of the array is reached.
  472  */
  473 const void *
  474 bhnd_nvram_value_array_next(const void *inp, size_t ilen, bhnd_nvram_type itype,
  475     const void *prev, size_t *olen)
  476 {
  477         const u_char    *next;
  478         size_t           offset;
  479 
  480         /* Handle first element */
  481         if (prev == NULL) {
  482                 /* Zero-length array? */
  483                 if (ilen == 0)
  484                         return (NULL);
  485 
  486                 *olen = bhnd_nvram_value_size(inp, ilen, itype, 1);
  487                 return (inp);
  488         }
  489 
  490         /* Advance to next element */
  491         BHND_NV_ASSERT(prev >= (const void *)inp, ("invalid cookiep"));
  492         next = (const u_char *)prev + *olen;
  493         offset = (size_t)(next - (const u_char *)inp);
  494 
  495         if (offset >= ilen) {
  496                 /* Hit end of the array */
  497                 return (NULL);
  498         }
  499 
  500         /* Determine element size */
  501         *olen = bhnd_nvram_value_size(next, ilen - offset, itype, 1);
  502         if (ilen - offset < *olen) {
  503                 BHND_NV_LOG("short element of type %s -- misaligned "
  504                     "representation", bhnd_nvram_type_name(itype));
  505                 return (NULL);
  506         }
  507 
  508         return (next);
  509 }
  510 
  511 /**
  512  * Coerce value @p inp of type @p itype to @p otype, writing the
  513  * result to @p outp.
  514  *
  515  * @param               inp     The value to be coerced.
  516  * @param               ilen    The size of @p inp, in bytes.
  517  * @param               itype   The base data type of @p inp.
  518  * @param[out]          outp    On success, the value will be written to this 
  519  *                              buffer. This argment may be NULL if the value
  520  *                              is not desired.
  521  * @param[in,out]       olen    The capacity of @p outp. On success, will be set
  522  *                              to the actual size of the requested value.
  523  * @param               otype   The data type to be written to @p outp.
  524  *
  525  * @retval 0            success
  526  * @retval ENOMEM       If @p outp is non-NULL and a buffer of @p olen is too
  527  *                      small to hold the requested value.
  528  * @retval EFTYPE       If the variable data cannot be coerced to @p otype.
  529  * @retval ERANGE       If value coercion would overflow @p otype.
  530  */
  531 int
  532 bhnd_nvram_value_coerce(const void *inp, size_t ilen, bhnd_nvram_type itype,
  533     void *outp, size_t *olen, bhnd_nvram_type otype)
  534 {
  535         bhnd_nvram_val  val;
  536         int             error;
  537 
  538         /* Wrap input buffer in a value instance */
  539         error = bhnd_nvram_val_init(&val, NULL, inp, ilen,
  540             itype, BHND_NVRAM_VAL_BORROW_DATA|BHND_NVRAM_VAL_FIXED);
  541         if (error)
  542                 return (error);
  543 
  544         /* Try to encode as requested type */
  545         error = bhnd_nvram_val_encode(&val, outp, olen, otype);
  546 
  547         /* Clean up and return error */
  548         bhnd_nvram_val_release(&val);
  549         return (error);
  550 }

Cache object: 36d41d834e9328d324477467cdb37f3d


[ 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.