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_data_bcmraw.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) 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 #ifdef _KERNEL
   34 
   35 #include <sys/param.h>
   36 #include <sys/ctype.h>
   37 #include <sys/malloc.h>
   38 #include <sys/systm.h>
   39 
   40 #else /* !_KERNEL */
   41 
   42 #include <ctype.h>
   43 #include <stdint.h>
   44 #include <stdio.h>
   45 #include <stdlib.h>
   46 #include <string.h>
   47 
   48 #endif /* _KERNEL */
   49 
   50 #include "bhnd_nvram_private.h"
   51 
   52 #include "bhnd_nvram_datavar.h"
   53 #include "bhnd_nvram_data_bcmvar.h"
   54 
   55 /*
   56  * Broadcom-RAW NVRAM data class.
   57  * 
   58  * The Broadcom NVRAM NUL-delimited ASCII format is used by most
   59  * Broadcom SoCs.
   60  * 
   61  * The NVRAM data is encoded as a stream of of NUL-terminated 'key=value'
   62  * strings; the end of the stream is denoted by a single extra NUL character.
   63  */
   64 
   65 struct bhnd_nvram_bcmraw;
   66 
   67 /** BCM-RAW NVRAM data class instance */
   68 struct bhnd_nvram_bcmraw {
   69         struct bhnd_nvram_data           nv;    /**< common instance state */
   70         char                            *data;  /**< backing buffer */
   71         size_t                           size;  /**< buffer size */
   72         size_t                           count; /**< variable count */
   73 };
   74 
   75 BHND_NVRAM_DATA_CLASS_DEFN(bcmraw, "Broadcom (RAW)",
   76     BHND_NVRAM_DATA_CAP_DEVPATHS, sizeof(struct bhnd_nvram_bcmraw))
   77 
   78 static int
   79 bhnd_nvram_bcmraw_probe(struct bhnd_nvram_io *io)
   80 {
   81         char     envp[16];
   82         size_t   envp_len;
   83         size_t   io_size;
   84         int      error;
   85 
   86         io_size = bhnd_nvram_io_getsize(io);
   87 
   88         /*
   89          * Fetch initial bytes
   90          */
   91         envp_len = bhnd_nv_ummin(sizeof(envp), io_size);
   92         if ((error = bhnd_nvram_io_read(io, 0x0, envp, envp_len)))
   93                 return (error);
   94 
   95         /* An empty BCM-RAW buffer should still contain a single terminating
   96          * NUL */
   97         if (envp_len == 0)
   98                 return (ENXIO);
   99 
  100         if (envp_len == 1) {
  101                 if (envp[0] != '\0')
  102                         return (ENXIO);
  103 
  104                 return (BHND_NVRAM_DATA_PROBE_MAYBE);
  105         }
  106 
  107         /* Must contain only printable ASCII characters delimited
  108          * by NUL record delimiters */
  109         for (size_t i = 0; i < envp_len; i++) {
  110                 char c = envp[i];
  111 
  112                 /* If we hit a newline, this is probably BCM-TXT */
  113                 if (c == '\n')
  114                         return (ENXIO);
  115 
  116                 if (c == '\0' && !bhnd_nv_isprint(c))
  117                         continue;
  118         }
  119 
  120         /* A valid BCM-RAW buffer should contain a terminating NUL for
  121          * the last record, followed by a final empty record terminated by
  122          * NUL */
  123         envp_len = 2;
  124         if (io_size < envp_len)
  125                 return (ENXIO);
  126 
  127         if ((error = bhnd_nvram_io_read(io, io_size-envp_len, envp, envp_len)))
  128                 return (error);
  129 
  130         if (envp[0] != '\0' || envp[1] != '\0')
  131                 return (ENXIO);
  132 
  133         return (BHND_NVRAM_DATA_PROBE_MAYBE + 1);
  134 }
  135 
  136 static int
  137 bhnd_nvram_bcmraw_getvar_direct(struct bhnd_nvram_io *io, const char *name,
  138     void *buf, size_t *len, bhnd_nvram_type type)
  139 {
  140         return (bhnd_nvram_bcm_getvar_direct_common(io, name, buf, len, type,
  141             false));
  142 }
  143 
  144 static int
  145 bhnd_nvram_bcmraw_serialize(bhnd_nvram_data_class *cls, bhnd_nvram_plist *props,
  146     bhnd_nvram_plist *options, void *outp, size_t *olen)
  147 {
  148         bhnd_nvram_prop *prop;
  149         size_t           limit, nbytes;
  150         int              error;
  151 
  152         /* Determine output byte limit */
  153         if (outp != NULL)
  154                 limit = *olen;
  155         else
  156                 limit = 0;
  157 
  158         nbytes = 0;
  159 
  160         /* Write all properties */
  161         prop = NULL;
  162         while ((prop = bhnd_nvram_plist_next(props, prop)) != NULL) {
  163                 const char      *name;
  164                 char            *p;
  165                 size_t           prop_limit;
  166                 size_t           name_len, value_len;
  167 
  168                 if (outp == NULL || limit < nbytes) {
  169                         p = NULL;
  170                         prop_limit = 0;
  171                 } else {
  172                         p = ((char *)outp) + nbytes;
  173                         prop_limit = limit - nbytes;
  174                 }
  175 
  176                 /* Fetch and write name + '=' to output */
  177                 name = bhnd_nvram_prop_name(prop);
  178                 name_len = strlen(name) + 1;
  179 
  180                 if (prop_limit > name_len) {
  181                         memcpy(p, name, name_len - 1);
  182                         p[name_len - 1] = '=';
  183 
  184                         prop_limit -= name_len;
  185                         p += name_len;
  186                 } else {
  187                         prop_limit = 0;
  188                         p = NULL;
  189                 }
  190 
  191                 /* Advance byte count */
  192                 if (SIZE_MAX - nbytes < name_len)
  193                         return (EFTYPE); /* would overflow size_t */
  194 
  195                 nbytes += name_len;
  196 
  197                 /* Attempt to write NUL-terminated value to output */
  198                 value_len = prop_limit;
  199                 error = bhnd_nvram_prop_encode(prop, p, &value_len,
  200                     BHND_NVRAM_TYPE_STRING);
  201 
  202                 /* If encoding failed for any reason other than ENOMEM (which
  203                  * we'll detect and report after encoding all properties),
  204                  * return immediately */
  205                 if (error && error != ENOMEM) {
  206                         BHND_NV_LOG("error serializing %s to required type "
  207                             "%s: %d\n", name,
  208                             bhnd_nvram_type_name(BHND_NVRAM_TYPE_STRING),
  209                             error);
  210                         return (error);
  211                 }
  212 
  213                 /* Advance byte count */
  214                 if (SIZE_MAX - nbytes < value_len)
  215                         return (EFTYPE); /* would overflow size_t */
  216 
  217                 nbytes += value_len;
  218         }
  219 
  220         /* Write terminating '\0' */
  221         if (limit > nbytes)
  222                 *((char *)outp + nbytes) = '\0';
  223 
  224         if (nbytes == SIZE_MAX)
  225                 return (EFTYPE); /* would overflow size_t */
  226         else
  227                 nbytes++;
  228 
  229         /* Provide required length */
  230         *olen = nbytes;
  231         if (limit < *olen) {
  232                 if (outp == NULL)
  233                         return (0);
  234 
  235                 return (ENOMEM);
  236         }
  237 
  238         return (0);
  239 }
  240 
  241 /**
  242  * Initialize @p bcm with the provided NVRAM data mapped by @p src.
  243  * 
  244  * @param bcm A newly allocated data instance.
  245  */
  246 static int
  247 bhnd_nvram_bcmraw_init(struct bhnd_nvram_bcmraw *bcm, struct bhnd_nvram_io *src)
  248 {
  249         size_t   io_size;
  250         size_t   capacity, offset;
  251         int      error;
  252 
  253         /* Fetch the input image size */
  254         io_size = bhnd_nvram_io_getsize(src);
  255 
  256         /* Allocate a buffer large enough to hold the NVRAM image, and
  257          * an extra EOF-signaling NUL (on the chance it's missing from the
  258          * source data) */
  259         if (io_size == SIZE_MAX)
  260                 return (ENOMEM);
  261 
  262         capacity = io_size + 1 /* room for extra NUL */;
  263         bcm->size = io_size;
  264         if ((bcm->data = bhnd_nv_malloc(capacity)) == NULL)
  265                 return (ENOMEM);
  266 
  267         /* Copy in the NVRAM image */
  268         if ((error = bhnd_nvram_io_read(src, 0x0, bcm->data, io_size)))
  269                 return (error);
  270 
  271         /* Process the buffer */
  272         bcm->count = 0;
  273         for (offset = 0; offset < bcm->size; offset++) {
  274                 char            *envp;
  275                 const char      *name, *value;
  276                 size_t           envp_len;
  277                 size_t           name_len, value_len;
  278 
  279                 /* Parse the key=value string */
  280                 envp = (char *) (bcm->data + offset);
  281                 envp_len = strnlen(envp, bcm->size - offset);
  282                 error = bhnd_nvram_parse_env(envp, envp_len, '=', &name,
  283                                              &name_len, &value, &value_len);
  284                 if (error) {
  285                         BHND_NV_LOG("error parsing envp at offset %#zx: %d\n",
  286                             offset, error);
  287                         return (error);
  288                 }
  289 
  290                 /* Insert a '\0' character, replacing the '=' delimiter and
  291                  * allowing us to vend references directly to the variable
  292                  * name */
  293                 *(envp + name_len) = '\0';
  294 
  295                 /* Add to variable count */
  296                 bcm->count++;
  297 
  298                 /* Seek past the value's terminating '\0' */
  299                 offset += envp_len;
  300                 if (offset == io_size) {
  301                         BHND_NV_LOG("missing terminating NUL at offset %#zx\n",
  302                             offset);
  303                         return (EINVAL);
  304                 }
  305 
  306                 /* If we hit EOF without finding a terminating NUL
  307                  * byte, we need to append it */
  308                 if (++offset == bcm->size) {
  309                         BHND_NV_ASSERT(offset < capacity,
  310                             ("appending past end of buffer"));
  311                         bcm->size++;
  312                         *(bcm->data + offset) = '\0';
  313                 }
  314 
  315                 /* Check for explicit EOF (encoded as a single empty NUL
  316                  * terminated string) */
  317                 if (*(bcm->data + offset) == '\0')
  318                         break;
  319         }
  320 
  321         /* Reclaim any unused space in the backing buffer */
  322         if (offset < bcm->size) {
  323                 bcm->data = bhnd_nv_reallocf(bcm->data, bcm->size);
  324                 if (bcm->data == NULL)
  325                         return (ENOMEM);
  326         }
  327 
  328         return (0);
  329 }
  330 
  331 static int
  332 bhnd_nvram_bcmraw_new(struct bhnd_nvram_data *nv, struct bhnd_nvram_io *io)
  333 {
  334         struct bhnd_nvram_bcmraw        *bcm;
  335         int                              error;
  336 
  337         bcm = (struct bhnd_nvram_bcmraw *)nv;
  338 
  339         /* Parse the BCM input data and initialize our backing
  340          * data representation */
  341         if ((error = bhnd_nvram_bcmraw_init(bcm, io))) {
  342                 bhnd_nvram_bcmraw_free(nv);
  343                 return (error);
  344         }
  345 
  346         return (0);
  347 }
  348 
  349 static void
  350 bhnd_nvram_bcmraw_free(struct bhnd_nvram_data *nv)
  351 {
  352         struct bhnd_nvram_bcmraw *bcm = (struct bhnd_nvram_bcmraw *)nv;
  353 
  354         if (bcm->data != NULL)
  355                 bhnd_nv_free(bcm->data);
  356 }
  357 
  358 static bhnd_nvram_plist *
  359 bhnd_nvram_bcmraw_options(struct bhnd_nvram_data *nv)
  360 {
  361         return (NULL);
  362 }
  363 
  364 static size_t
  365 bhnd_nvram_bcmraw_count(struct bhnd_nvram_data *nv)
  366 {
  367         struct bhnd_nvram_bcmraw *bcm = (struct bhnd_nvram_bcmraw *)nv;
  368 
  369         return (bcm->count);
  370 }
  371 
  372 static uint32_t
  373 bhnd_nvram_bcmraw_caps(struct bhnd_nvram_data *nv)
  374 {
  375         return (BHND_NVRAM_DATA_CAP_READ_PTR|BHND_NVRAM_DATA_CAP_DEVPATHS);
  376 }
  377 
  378 static const char *
  379 bhnd_nvram_bcmraw_next(struct bhnd_nvram_data *nv, void **cookiep)
  380 {
  381         struct bhnd_nvram_bcmraw        *bcm;
  382         const char                      *envp;
  383 
  384         bcm = (struct bhnd_nvram_bcmraw *)nv;
  385 
  386         if (*cookiep == NULL) {
  387                 /* Start at the first NVRAM data record */
  388                 envp = bcm->data;
  389         } else {
  390                 /* Seek to next record */
  391                 envp = *cookiep;
  392                 envp += strlen(envp) + 1;       /* key + '\0' */
  393                 envp += strlen(envp) + 1;       /* value + '\0' */
  394         }
  395 
  396         /* EOF? */
  397         if (*envp == '\0')
  398                 return (NULL);
  399 
  400         *cookiep = (void *)(uintptr_t)envp;
  401         return (envp);
  402 }
  403 
  404 static void *
  405 bhnd_nvram_bcmraw_find(struct bhnd_nvram_data *nv, const char *name)
  406 {
  407         return (bhnd_nvram_data_generic_find(nv, name));
  408 }
  409 
  410 static int
  411 bhnd_nvram_bcmraw_getvar_order(struct bhnd_nvram_data *nv, void *cookiep1,
  412     void *cookiep2)
  413 {
  414         if (cookiep1 < cookiep2)
  415                 return (-1);
  416 
  417         if (cookiep1 > cookiep2)
  418                 return (1);
  419 
  420         return (0);
  421 }
  422 
  423 static int
  424 bhnd_nvram_bcmraw_getvar(struct bhnd_nvram_data *nv, void *cookiep, void *buf,
  425     size_t *len, bhnd_nvram_type type)
  426 {
  427         return (bhnd_nvram_data_generic_rp_getvar(nv, cookiep, buf, len, type));
  428 }
  429 
  430 static int
  431 bhnd_nvram_bcmraw_copy_val(struct bhnd_nvram_data *nv, void *cookiep,
  432     bhnd_nvram_val **value)
  433 {
  434         return (bhnd_nvram_data_generic_rp_copy_val(nv, cookiep, value));
  435 }
  436 
  437 static const void *
  438 bhnd_nvram_bcmraw_getvar_ptr(struct bhnd_nvram_data *nv, void *cookiep,
  439     size_t *len, bhnd_nvram_type *type)
  440 {
  441         const char *envp;
  442 
  443         /* Cookie points to key\0value\0 -- get the value address */
  444         envp = cookiep;
  445         envp += strlen(envp) + 1;       /* key + '\0' */
  446         *len = strlen(envp) + 1;        /* value + '\0' */
  447         *type = BHND_NVRAM_TYPE_STRING;
  448 
  449         return (envp);
  450 }
  451 
  452 static const char *
  453 bhnd_nvram_bcmraw_getvar_name(struct bhnd_nvram_data *nv, void *cookiep)
  454 {
  455         /* Cookie points to key\0value\0 */
  456         return (cookiep);
  457 }
  458 
  459 static int
  460 bhnd_nvram_bcmraw_filter_setvar(struct bhnd_nvram_data *nv, const char *name,
  461     bhnd_nvram_val *value, bhnd_nvram_val **result)
  462 {
  463         bhnd_nvram_val  *str;
  464         int              error;
  465 
  466         /* Name (trimmed of any path prefix) must be valid */
  467         if (!bhnd_nvram_validate_name(bhnd_nvram_trim_path_name(name)))
  468                 return (EINVAL);
  469 
  470         /* Value must be bcm-formatted string */
  471         error = bhnd_nvram_val_convert_new(&str, &bhnd_nvram_val_bcm_string_fmt,
  472             value, BHND_NVRAM_VAL_DYNAMIC);
  473         if (error)
  474                 return (error);
  475 
  476         /* Success. Transfer result ownership to the caller. */
  477         *result = str;
  478         return (0);
  479 }
  480 
  481 static int
  482 bhnd_nvram_bcmraw_filter_unsetvar(struct bhnd_nvram_data *nv, const char *name)
  483 {
  484         /* We permit deletion of any variable */
  485         return (0);
  486 }

Cache object: 845be6fb2278b94725f16ca235c6373d


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