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_sprom_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 #include <sys/endian.h>
   35 
   36 #ifdef _KERNEL
   37 #include <sys/systm.h>
   38 #include <machine/_inttypes.h>
   39 #else /* !_KERNEL */
   40 #include <errno.h>
   41 #include <inttypes.h>
   42 #include <stdint.h>
   43 #include <string.h>
   44 #endif /* _KERNEL */
   45 
   46 #include "bhnd_nvram_private.h"
   47 #include "bhnd_nvram_data_spromvar.h"
   48 
   49 static int      bhnd_sprom_opcode_sort_idx(const void *lhs, const void *rhs);
   50 static int      bhnd_nvram_opcode_idx_vid_compare(const void *key,
   51                     const void *rhs);
   52 
   53 static int      bhnd_sprom_opcode_reset(bhnd_sprom_opcode_state *state);
   54 
   55 static int      bhnd_sprom_opcode_set_type(bhnd_sprom_opcode_state *state,
   56                     bhnd_nvram_type type);
   57 
   58 static int      bhnd_sprom_opcode_set_var(bhnd_sprom_opcode_state *state,
   59                     size_t vid);
   60 static int      bhnd_sprom_opcode_clear_var(bhnd_sprom_opcode_state *state);
   61 
   62 static int      bhnd_sprom_opcode_flush_bind(bhnd_sprom_opcode_state *state);
   63 
   64 static int      bhnd_sprom_opcode_read_opval32(bhnd_sprom_opcode_state *state,
   65                     uint8_t type, uint32_t *opval);
   66 
   67 static int      bhnd_sprom_opcode_step(bhnd_sprom_opcode_state *state,
   68                     uint8_t *opcode);
   69 
   70 #define SPROM_OP_BAD(_state, _fmt, ...)                                 \
   71         BHND_NV_LOG("bad encoding at %td: " _fmt,                       \
   72             (_state)->input - (_state)->layout->bindings, ##__VA_ARGS__)
   73 
   74 /**
   75  * Initialize SPROM opcode evaluation state.
   76  * 
   77  * @param state The opcode state to be initialized.
   78  * @param layout The SPROM layout to be parsed by this instance.
   79  * 
   80  * 
   81  * @retval 0 success
   82  * @retval non-zero If initialization fails, a regular unix error code will be
   83  * returned.
   84  */
   85 int
   86 bhnd_sprom_opcode_init(bhnd_sprom_opcode_state *state,
   87     const struct bhnd_sprom_layout *layout)
   88 {
   89         bhnd_sprom_opcode_idx_entry     *idx;
   90         size_t                           num_vars, num_idx;
   91         int                              error;
   92 
   93         idx = NULL;
   94 
   95         state->layout = layout;
   96         state->idx = NULL;
   97         state->num_idx = 0;
   98 
   99         /* Initialize interpretation state */
  100         if ((error = bhnd_sprom_opcode_reset(state)))
  101                 return (error);
  102 
  103         /* Allocate and populate our opcode index */
  104         num_idx = state->layout->num_vars;
  105         idx = bhnd_nv_calloc(num_idx, sizeof(*idx));
  106         if (idx == NULL)
  107                 return (ENOMEM);
  108 
  109         for (num_vars = 0; num_vars < num_idx; num_vars++) {
  110                 /* Seek to next entry */
  111                 if ((error = bhnd_sprom_opcode_next_var(state))) {
  112                         SPROM_OP_BAD(state, "error reading expected variable "
  113                             "entry: %d\n", error);
  114                         bhnd_nv_free(idx);
  115                         return (error);
  116                 }
  117 
  118                 /* Record entry state in our index */
  119                 error = bhnd_sprom_opcode_init_entry(state, &idx[num_vars]);
  120                 if (error) {
  121                         SPROM_OP_BAD(state, "error initializing index for "
  122                             "entry: %d\n", error);
  123                         bhnd_nv_free(idx);
  124                         return (error);
  125                 }
  126         }
  127 
  128         /* Should have reached end of binding table; next read must return
  129          * ENOENT */
  130         if ((error = bhnd_sprom_opcode_next_var(state)) != ENOENT) {
  131                 BHND_NV_LOG("expected EOF parsing binding table: %d\n", error);
  132                 bhnd_nv_free(idx);
  133                 return (ENXIO);
  134         }
  135 
  136         /* Reset interpretation state */
  137         if ((error = bhnd_sprom_opcode_reset(state))) {
  138                 bhnd_nv_free(idx);
  139                 return (error);
  140         }
  141 
  142         /* Make index available to opcode state evaluation */
  143         qsort(idx, num_idx, sizeof(idx[0]), bhnd_sprom_opcode_sort_idx);
  144 
  145         state->idx = idx;
  146         state->num_idx = num_idx;
  147 
  148         return (0);
  149 }
  150 
  151 /**
  152  * Reset SPROM opcode evaluation state; future evaluation will be performed
  153  * starting at the first opcode.
  154  * 
  155  * @param state The opcode state to be reset.
  156  *
  157  * @retval 0 success
  158  * @retval non-zero If reset fails, a regular unix error code will be returned.
  159  */
  160 static int
  161 bhnd_sprom_opcode_reset(bhnd_sprom_opcode_state *state)
  162 {
  163         memset(&state->var, 0, sizeof(state->var));
  164 
  165         state->input = state->layout->bindings;
  166         state->offset = 0;
  167         state->vid = 0;
  168         state->var_state = SPROM_OPCODE_VAR_STATE_NONE;
  169         bit_set(state->revs, state->layout->rev);
  170 
  171         return (0);
  172 }
  173 
  174 /**
  175  * Free any resources associated with @p state.
  176  * 
  177  * @param state An opcode state previously successfully initialized with
  178  * bhnd_sprom_opcode_init().
  179  */
  180 void
  181 bhnd_sprom_opcode_fini(bhnd_sprom_opcode_state *state)
  182 {
  183         bhnd_nv_free(state->idx);
  184 }
  185 
  186 /**
  187  * Sort function used to prepare our index for querying; sorts
  188  * bhnd_sprom_opcode_idx_entry values by variable ID, ascending.
  189  */
  190 static int
  191 bhnd_sprom_opcode_sort_idx(const void *lhs, const void *rhs)
  192 {
  193         const bhnd_sprom_opcode_idx_entry *l, *r;
  194 
  195         l = lhs;
  196         r = rhs;
  197 
  198         if (l->vid < r->vid)
  199                 return (-1);
  200         if (l->vid > r->vid)
  201                 return (1);
  202         return (0);
  203 }
  204 
  205 /**
  206  * Binary search comparison function used by bhnd_sprom_opcode_index_find();
  207  * searches bhnd_sprom_opcode_idx_entry values by variable ID, ascending.
  208  */
  209 static int
  210 bhnd_nvram_opcode_idx_vid_compare(const void *key, const void *rhs)
  211 {
  212         const bhnd_sprom_opcode_idx_entry       *entry;
  213         size_t                                   vid;
  214 
  215         vid = *(const size_t *)key;
  216         entry = rhs;
  217 
  218         if (vid < entry->vid)
  219                 return (-1);
  220         if (vid > entry->vid)
  221                 return (1);
  222 
  223         return (0);
  224 }
  225 
  226 /**
  227  * Locate an index entry for the variable with @p name, or NULL if not found.
  228  * 
  229  * @param state The opcode state to be queried.
  230  * @param name  The name to search for.
  231  *
  232  * @retval non-NULL     If @p name is found, its index entry value will be
  233  *                      returned.
  234  * @retval NULL         If @p name is not found.
  235  */
  236 bhnd_sprom_opcode_idx_entry *
  237 bhnd_sprom_opcode_index_find(bhnd_sprom_opcode_state *state, const char *name)
  238 {
  239         const struct bhnd_nvram_vardefn *var;
  240         size_t                           vid;
  241 
  242         /* Determine the variable ID for the given name */
  243         if ((var = bhnd_nvram_find_vardefn(name)) == NULL)
  244                 return (NULL);
  245 
  246         vid = bhnd_nvram_get_vardefn_id(var);
  247 
  248         /* Search our index for the variable ID */
  249         return (bsearch(&vid, state->idx, state->num_idx, sizeof(state->idx[0]),
  250             bhnd_nvram_opcode_idx_vid_compare));
  251 }
  252 
  253 /**
  254  * Iterate over all index entries in @p state.
  255  * 
  256  * @param               state   The opcode state to be iterated.
  257  * @param[in,out]       prev    An entry previously returned by
  258  *                              bhnd_sprom_opcode_index_next(), or a NULL value
  259  *                              to begin iteration.
  260  * 
  261  * @return Returns the next index entry name, or NULL if all entries have
  262  * been iterated.
  263  */
  264 bhnd_sprom_opcode_idx_entry *
  265 bhnd_sprom_opcode_index_next(bhnd_sprom_opcode_state *state,
  266     bhnd_sprom_opcode_idx_entry *prev)
  267 {
  268         size_t idxpos;
  269 
  270         /* Get next index position */
  271         if (prev == NULL) {
  272                 idxpos = 0;
  273         } else {
  274                 /* Determine current position */
  275                 idxpos = (size_t)(prev - state->idx);
  276                 BHND_NV_ASSERT(idxpos < state->num_idx,
  277                     ("invalid index %zu", idxpos));
  278 
  279                 /* Advance to next entry */
  280                 idxpos++;
  281         }
  282 
  283         /* Check for EOF */
  284         if (idxpos == state->num_idx)
  285                 return (NULL);
  286 
  287         return (&state->idx[idxpos]);
  288 }
  289 
  290 /**
  291  * Initialize @p entry with the current variable's opcode state.
  292  * 
  293  * @param       state   The opcode state to be saved.
  294  * @param[out]  entry   The opcode index entry to be initialized from @p state.
  295  * 
  296  * @retval 0            success
  297  * @retval ENXIO        if @p state cannot be serialized as an index entry.
  298  */
  299 int
  300 bhnd_sprom_opcode_init_entry(bhnd_sprom_opcode_state *state,
  301     bhnd_sprom_opcode_idx_entry *entry)
  302 {
  303         size_t opcodes;
  304 
  305         /* We limit the SPROM index representations to the minimal type widths
  306          * capable of covering all known layouts */
  307 
  308         /* Save SPROM image offset */
  309         if (state->offset > UINT16_MAX) {
  310                 SPROM_OP_BAD(state, "cannot index large offset %u\n",
  311                     state->offset);
  312                 return (ENXIO);
  313         }
  314 
  315         entry->offset = state->offset;
  316 
  317         /* Save current variable ID */
  318         if (state->vid > UINT16_MAX) {
  319                 SPROM_OP_BAD(state, "cannot index large vid %zu\n",
  320                     state->vid);
  321                 return (ENXIO);
  322         }
  323         entry->vid = state->vid;
  324 
  325         /* Save opcode position */
  326         opcodes = (state->input - state->layout->bindings);
  327         if (opcodes > UINT16_MAX) {
  328                 SPROM_OP_BAD(state, "cannot index large opcode offset "
  329                     "%zu\n", opcodes);
  330                 return (ENXIO);
  331         }
  332         entry->opcodes = opcodes;
  333 
  334         return (0);
  335 }
  336 
  337 /**
  338  * Reset SPROM opcode evaluation state and seek to the @p entry's position.
  339  * 
  340  * @param state The opcode state to be reset.
  341  * @param entry The indexed entry to which we'll seek the opcode state.
  342  */
  343 int
  344 bhnd_sprom_opcode_seek(bhnd_sprom_opcode_state *state,
  345     bhnd_sprom_opcode_idx_entry *entry)
  346 {
  347         int error;
  348 
  349         BHND_NV_ASSERT(entry->opcodes < state->layout->bindings_size,
  350             ("index entry references invalid opcode position"));
  351 
  352         /* Reset state */
  353         if ((error = bhnd_sprom_opcode_reset(state)))
  354                 return (error);
  355 
  356         /* Seek to the indexed sprom opcode offset */
  357         state->input = state->layout->bindings + entry->opcodes;
  358 
  359         /* Restore the indexed sprom data offset and VID */
  360         state->offset = entry->offset;
  361 
  362         /* Restore the indexed sprom variable ID */
  363         if ((error = bhnd_sprom_opcode_set_var(state, entry->vid)))
  364                 return (error);
  365 
  366         return (0);
  367 }
  368 
  369 /**
  370  * Set the current revision range for @p state. This also resets
  371  * variable state.
  372  * 
  373  * @param state The opcode state to update
  374  * @param start The first revision in the range.
  375  * @param end The last revision in the range.
  376  *
  377  * @retval 0 success
  378  * @retval non-zero If updating @p state fails, a regular unix error code will
  379  * be returned.
  380  */
  381 static inline int
  382 bhnd_sprom_opcode_set_revs(bhnd_sprom_opcode_state *state, uint8_t start,
  383     uint8_t end)
  384 {
  385         int error;
  386 
  387         /* Validate the revision range */
  388         if (start > SPROM_OP_REV_MAX ||
  389             end > SPROM_OP_REV_MAX ||
  390             end < start)
  391         {
  392                 SPROM_OP_BAD(state, "invalid revision range: %hhu-%hhu\n",
  393                     start, end);
  394                 return (EINVAL);
  395         }
  396 
  397         /* Clear variable state */
  398         if ((error = bhnd_sprom_opcode_clear_var(state)))
  399                 return (error);
  400 
  401         /* Reset revision mask */
  402         memset(state->revs, 0x0, sizeof(state->revs));
  403         bit_nset(state->revs, start, end);
  404 
  405         return (0);
  406 }
  407 
  408 /**
  409  * Set the current variable's value mask for @p state.
  410  * 
  411  * @param state The opcode state to update
  412  * @param mask The mask to be set
  413  *
  414  * @retval 0 success
  415  * @retval non-zero If updating @p state fails, a regular unix error code will
  416  * be returned.
  417  */
  418 static inline int
  419 bhnd_sprom_opcode_set_mask(bhnd_sprom_opcode_state *state, uint32_t mask)
  420 {
  421         if (state->var_state != SPROM_OPCODE_VAR_STATE_OPEN) {
  422                 SPROM_OP_BAD(state, "no open variable definition\n");
  423                 return (EINVAL);
  424         }
  425 
  426         state->var.mask = mask;
  427         return (0);
  428 }
  429 
  430 /**
  431  * Set the current variable's value shift for @p state.
  432  * 
  433  * @param state The opcode state to update
  434  * @param shift The shift to be set
  435  *
  436  * @retval 0 success
  437  * @retval non-zero If updating @p state fails, a regular unix error code will
  438  * be returned.
  439  */
  440 static inline int
  441 bhnd_sprom_opcode_set_shift(bhnd_sprom_opcode_state *state, int8_t shift)
  442 {
  443         if (state->var_state != SPROM_OPCODE_VAR_STATE_OPEN) {
  444                 SPROM_OP_BAD(state, "no open variable definition\n");
  445                 return (EINVAL);
  446         }
  447 
  448         state->var.shift = shift;
  449         return (0);
  450 }
  451 
  452 /**
  453  * Register a new BIND/BINDN operation with @p state.
  454  * 
  455  * @param state The opcode state to update.
  456  * @param count The number of elements to be bound.
  457  * @param skip_in The number of input elements to skip after each bind.
  458  * @param skip_in_negative If true, the input skip should be subtracted from
  459  * the current offset after each bind. If false, the input skip should be
  460  * added.
  461  * @param skip_out The number of output elements to skip after each bind.
  462  * 
  463  * @retval 0 success
  464  * @retval EINVAL if a variable definition is not open.
  465  * @retval EINVAL if @p skip_in and @p count would trigger an overflow or
  466  * underflow when applied to the current input offset.
  467  * @retval ERANGE if @p skip_in would overflow uint32_t when multiplied by
  468  * @p count and the scale value.
  469  * @retval ERANGE if @p skip_out would overflow uint32_t when multiplied by
  470  * @p count and the scale value.
  471  * @retval non-zero If updating @p state otherwise fails, a regular unix error
  472  * code will be returned.
  473  */
  474 static inline int
  475 bhnd_sprom_opcode_set_bind(bhnd_sprom_opcode_state *state, uint8_t count,
  476     uint8_t skip_in, bool skip_in_negative, uint8_t skip_out)
  477 {
  478         uint32_t        iskip_total;
  479         uint32_t        iskip_scaled;
  480         int             error;
  481 
  482         /* Must have an open variable */
  483         if (state->var_state != SPROM_OPCODE_VAR_STATE_OPEN) {
  484                 SPROM_OP_BAD(state, "no open variable definition\n");
  485                 SPROM_OP_BAD(state, "BIND outside of variable definition\n");
  486                 return (EINVAL);
  487         }
  488 
  489         /* Cannot overwite an existing bind definition */
  490         if (state->var.have_bind) {
  491                 SPROM_OP_BAD(state, "BIND overwrites existing definition\n");
  492                 return (EINVAL);
  493         }
  494 
  495         /* Must have a count of at least 1 */
  496         if (count == 0) {
  497                 SPROM_OP_BAD(state, "BIND with zero count\n");
  498                 return (EINVAL);
  499         }
  500 
  501         /* Scale skip_in by the current type width */
  502         iskip_scaled = skip_in;
  503         if ((error = bhnd_sprom_opcode_apply_scale(state, &iskip_scaled)))
  504                 return (error);
  505 
  506         /* Calculate total input bytes skipped: iskip_scaled * count) */
  507         if (iskip_scaled > 0 && UINT32_MAX / iskip_scaled < count) {
  508                 SPROM_OP_BAD(state, "skip_in %hhu would overflow", skip_in);
  509                 return (EINVAL);
  510         }
  511 
  512         iskip_total = iskip_scaled * count;
  513 
  514         /* Verify that the skip_in value won't under/overflow the current
  515          * input offset. */
  516         if (skip_in_negative) {
  517                 if (iskip_total > state->offset) {
  518                         SPROM_OP_BAD(state, "skip_in %hhu would underflow "
  519                             "offset %u\n", skip_in, state->offset);
  520                         return (EINVAL);
  521                 }
  522         } else {
  523                 if (UINT32_MAX - iskip_total < state->offset) {
  524                         SPROM_OP_BAD(state, "skip_in %hhu would overflow "
  525                             "offset %u\n", skip_in, state->offset);
  526                         return (EINVAL);
  527                 }
  528         }
  529 
  530         /* Set the actual count and skip values */
  531         state->var.have_bind = true;
  532         state->var.bind.count = count;
  533         state->var.bind.skip_in = skip_in;
  534         state->var.bind.skip_out = skip_out;
  535 
  536         state->var.bind.skip_in_negative = skip_in_negative;
  537 
  538         /* Update total bind count for the current variable */
  539         state->var.bind_total++;
  540 
  541         return (0);
  542 }
  543 
  544 /**
  545  * Apply and clear the current opcode bind state, if any.
  546  * 
  547  * @param state The opcode state to update.
  548  * 
  549  * @retval 0 success
  550  * @retval non-zero If updating @p state otherwise fails, a regular unix error
  551  * code will be returned.
  552  */
  553 static int
  554 bhnd_sprom_opcode_flush_bind(bhnd_sprom_opcode_state *state)
  555 {
  556         int             error;
  557         uint32_t        skip;
  558 
  559         /* Nothing to do? */
  560         if (state->var_state != SPROM_OPCODE_VAR_STATE_OPEN ||
  561             !state->var.have_bind)
  562                 return (0);
  563 
  564         /* Apply SPROM offset adjustment */
  565         if (state->var.bind.count > 0) {
  566                 skip = state->var.bind.skip_in * state->var.bind.count;
  567                 if ((error = bhnd_sprom_opcode_apply_scale(state, &skip)))
  568                         return (error);
  569 
  570                 if (state->var.bind.skip_in_negative) {
  571                         state->offset -= skip;
  572                 } else {
  573                         state->offset += skip;
  574                 }
  575         }
  576 
  577         /* Clear bind state */
  578         memset(&state->var.bind, 0, sizeof(state->var.bind));
  579         state->var.have_bind = false;
  580 
  581         return (0);
  582 }
  583 
  584 /**
  585  * Set the current type to @p type, and reset type-specific
  586  * stream state.
  587  *
  588  * @param state The opcode state to update.
  589  * @param type The new type.
  590  * 
  591  * @retval 0 success
  592  * @retval EINVAL if @p vid is not a valid variable ID.
  593  */
  594 static int
  595 bhnd_sprom_opcode_set_type(bhnd_sprom_opcode_state *state, bhnd_nvram_type type)
  596 {
  597         bhnd_nvram_type base_type;
  598         size_t          width;
  599         uint32_t        mask;
  600 
  601         /* Must have an open variable definition */
  602         if (state->var_state != SPROM_OPCODE_VAR_STATE_OPEN) {
  603                 SPROM_OP_BAD(state, "type set outside variable definition\n");
  604                 return (EINVAL);
  605         }
  606 
  607         /* Fetch type width for use as our scale value */
  608         width = bhnd_nvram_type_width(type);
  609         if (width == 0) {
  610                 SPROM_OP_BAD(state, "unsupported variable-width type: %d\n",
  611                     type);
  612                 return (EINVAL);
  613         } else if (width > UINT32_MAX) {
  614                 SPROM_OP_BAD(state, "invalid type width %zu for type: %d\n",
  615                     width, type);
  616                 return (EINVAL);
  617         }
  618 
  619         /* Determine default mask value for the element type */
  620         base_type = bhnd_nvram_base_type(type);
  621         switch (base_type) {
  622         case BHND_NVRAM_TYPE_UINT8:
  623         case BHND_NVRAM_TYPE_INT8:
  624         case BHND_NVRAM_TYPE_CHAR:
  625                 mask = UINT8_MAX;
  626                 break;
  627         case BHND_NVRAM_TYPE_UINT16:
  628         case BHND_NVRAM_TYPE_INT16:
  629                 mask = UINT16_MAX;
  630                 break;
  631         case BHND_NVRAM_TYPE_UINT32:
  632         case BHND_NVRAM_TYPE_INT32:
  633                 mask = UINT32_MAX;
  634                 break;
  635         case BHND_NVRAM_TYPE_STRING:
  636                 /* fallthrough (unused by SPROM) */
  637         default:
  638                 SPROM_OP_BAD(state, "unsupported type: %d\n", type);
  639                 return (EINVAL);
  640         }
  641 
  642         /* Update state */
  643         state->var.base_type = base_type;
  644         state->var.mask = mask;
  645         state->var.scale = (uint32_t)width;
  646 
  647         return (0);
  648 }
  649 
  650 /**
  651  * Clear current variable state, if any.
  652  * 
  653  * @param state The opcode state to update.
  654  */
  655 static int
  656 bhnd_sprom_opcode_clear_var(bhnd_sprom_opcode_state *state)
  657 {
  658         if (state->var_state == SPROM_OPCODE_VAR_STATE_NONE)
  659                 return (0);
  660 
  661         BHND_NV_ASSERT(state->var_state == SPROM_OPCODE_VAR_STATE_DONE,
  662             ("incomplete variable definition"));
  663         BHND_NV_ASSERT(!state->var.have_bind, ("stale bind state"));
  664 
  665         memset(&state->var, 0, sizeof(state->var));
  666         state->var_state = SPROM_OPCODE_VAR_STATE_NONE;
  667 
  668         return (0);
  669 }
  670 
  671 /**
  672  * Set the current variable's array element count to @p nelem.
  673  *
  674  * @param state The opcode state to update.
  675  * @param nelem The new array length.
  676  * 
  677  * @retval 0 success
  678  * @retval EINVAL if no open variable definition exists.
  679  * @retval EINVAL if @p nelem is zero.
  680  * @retval ENXIO if @p nelem is greater than one, and the current variable does
  681  * not have an array type.
  682  * @retval ENXIO if @p nelem exceeds the array length of the NVRAM variable
  683  * definition.
  684  */
  685 static int
  686 bhnd_sprom_opcode_set_nelem(bhnd_sprom_opcode_state *state, uint8_t nelem)
  687 {
  688         const struct bhnd_nvram_vardefn *var;
  689 
  690         /* Must have a defined variable */
  691         if (state->var_state != SPROM_OPCODE_VAR_STATE_OPEN) {
  692                 SPROM_OP_BAD(state, "array length set without open variable "
  693                     "state");
  694                 return (EINVAL);
  695         }
  696 
  697         /* Locate the actual variable definition */
  698         if ((var = bhnd_nvram_get_vardefn(state->vid)) == NULL) {
  699                 SPROM_OP_BAD(state, "unknown variable ID: %zu\n", state->vid);
  700                 return (EINVAL);
  701         }
  702 
  703         /* Must be greater than zero */
  704         if (nelem == 0) {
  705                 SPROM_OP_BAD(state, "invalid nelem: %hhu\n", nelem);
  706                 return (EINVAL);
  707         }
  708 
  709         /* If the variable is not an array-typed value, the array length
  710          * must be 1 */
  711         if (!bhnd_nvram_is_array_type(var->type) && nelem != 1) {
  712                 SPROM_OP_BAD(state, "nelem %hhu on non-array %zu\n", nelem,
  713                     state->vid);
  714                 return (ENXIO);
  715         }
  716 
  717         /* Cannot exceed the variable's defined array length */
  718         if (nelem > var->nelem) {
  719                 SPROM_OP_BAD(state, "nelem %hhu exceeds %zu length %hhu\n",
  720                     nelem, state->vid, var->nelem);
  721                 return (ENXIO);
  722         }
  723 
  724         /* Valid length; update state */
  725         state->var.nelem = nelem;
  726 
  727         return (0);
  728 }
  729 
  730 /**
  731  * Set the current variable ID to @p vid, and reset variable-specific
  732  * stream state.
  733  *
  734  * @param state The opcode state to update.
  735  * @param vid The new variable ID.
  736  * 
  737  * @retval 0 success
  738  * @retval EINVAL if @p vid is not a valid variable ID.
  739  */
  740 static int
  741 bhnd_sprom_opcode_set_var(bhnd_sprom_opcode_state *state, size_t vid)
  742 {
  743         const struct bhnd_nvram_vardefn *var;
  744         int                              error;
  745 
  746         BHND_NV_ASSERT(state->var_state == SPROM_OPCODE_VAR_STATE_NONE,
  747             ("overwrite of open variable definition"));
  748 
  749         /* Locate the variable definition */
  750         if ((var = bhnd_nvram_get_vardefn(vid)) == NULL) {
  751                 SPROM_OP_BAD(state, "unknown variable ID: %zu\n", vid);
  752                 return (EINVAL);
  753         }
  754 
  755         /* Update vid and var state */
  756         state->vid = vid;
  757         state->var_state = SPROM_OPCODE_VAR_STATE_OPEN;
  758 
  759         /* Initialize default variable record values */
  760         memset(&state->var, 0x0, sizeof(state->var));
  761 
  762         /* Set initial base type */
  763         if ((error = bhnd_sprom_opcode_set_type(state, var->type)))
  764                 return (error);
  765 
  766         /* Set default array length */
  767         if ((error = bhnd_sprom_opcode_set_nelem(state, var->nelem)))
  768                 return (error);
  769 
  770         return (0);
  771 }
  772 
  773 /**
  774  * Mark the currently open variable definition as complete.
  775  * 
  776  * @param state The opcode state to update.
  777  *
  778  * @retval 0 success
  779  * @retval EINVAL if no incomplete open variable definition exists.
  780  */
  781 static int
  782 bhnd_sprom_opcode_end_var(bhnd_sprom_opcode_state *state)
  783 {
  784         if (state->var_state != SPROM_OPCODE_VAR_STATE_OPEN) {
  785                 SPROM_OP_BAD(state, "no open variable definition\n");
  786                 return (EINVAL);
  787         }
  788 
  789         state->var_state = SPROM_OPCODE_VAR_STATE_DONE;
  790         return (0);
  791 }
  792 
  793 /**
  794  * Apply the current scale to @p value.
  795  * 
  796  * @param state The SPROM opcode state.
  797  * @param[in,out] value The value to scale
  798  * 
  799  * @retval 0 success
  800  * @retval EINVAL if no open variable definition exists.
  801  * @retval EINVAL if applying the current scale would overflow.
  802  */
  803 int
  804 bhnd_sprom_opcode_apply_scale(bhnd_sprom_opcode_state *state, uint32_t *value)
  805 {
  806         /* Must have a defined variable (and thus, scale) */
  807         if (state->var_state != SPROM_OPCODE_VAR_STATE_OPEN) {
  808                 SPROM_OP_BAD(state, "scaled value encoded without open "
  809                     "variable state");
  810                 return (EINVAL);
  811         }
  812 
  813         /* Applying the scale value must not overflow */
  814         if (UINT32_MAX / state->var.scale < *value) {
  815                 SPROM_OP_BAD(state, "cannot represent %" PRIu32 " * %" PRIu32
  816                     "\n", *value, state->var.scale);
  817                 return (EINVAL);
  818         }
  819 
  820         *value = (*value) * state->var.scale;
  821         return (0);
  822 }
  823 
  824 /**
  825  * Read a SPROM_OP_DATA_* value from @p opcodes.
  826  * 
  827  * @param state The SPROM opcode state.
  828  * @param type The SROM_OP_DATA_* type to be read.
  829  * @param opval On success, the 32bit data representation. If @p type is signed,
  830  * the value will be appropriately sign extended and may be directly cast to
  831  * int32_t.
  832  * 
  833  * @retval 0 success
  834  * @retval non-zero If reading the value otherwise fails, a regular unix error
  835  * code will be returned.
  836  */
  837 static int
  838 bhnd_sprom_opcode_read_opval32(bhnd_sprom_opcode_state *state, uint8_t type,
  839    uint32_t *opval)
  840 {
  841         const uint8_t   *p;
  842         int              error;
  843 
  844         p = state->input;
  845         switch (type) {
  846         case SPROM_OP_DATA_I8:
  847                 /* Convert to signed value first, then sign extend */
  848                 *opval = (int32_t)(int8_t)(*p);
  849                 p += 1;
  850                 break;
  851         case SPROM_OP_DATA_U8:
  852                 *opval = *p;
  853                 p += 1;
  854                 break;
  855         case SPROM_OP_DATA_U8_SCALED:
  856                 *opval = *p;
  857 
  858                 if ((error = bhnd_sprom_opcode_apply_scale(state, opval)))
  859                         return (error);
  860 
  861                 p += 1;
  862                 break;
  863         case SPROM_OP_DATA_U16:
  864                 *opval = le16dec(p);
  865                 p += 2;
  866                 break;
  867         case SPROM_OP_DATA_U32:
  868                 *opval = le32dec(p);
  869                 p += 4;
  870                 break;
  871         default:
  872                 SPROM_OP_BAD(state, "unsupported data type: %hhu\n", type);
  873                 return (EINVAL);
  874         }
  875 
  876         /* Update read address */
  877         state->input = p;
  878 
  879         return (0);
  880 }
  881 
  882 /**
  883  * Return true if our layout revision is currently defined by the SPROM
  884  * opcode state.
  885  * 
  886  * This may be used to test whether the current opcode stream state applies
  887  * to the layout that we are actually parsing.
  888  * 
  889  * A given opcode stream may cover multiple layout revisions, switching
  890  * between them prior to defining a set of variables.
  891  */
  892 static inline bool
  893 bhnd_sprom_opcode_matches_layout_rev(bhnd_sprom_opcode_state *state)
  894 {
  895         return (bit_test(state->revs, state->layout->rev));
  896 }
  897 
  898 /**
  899  * When evaluating @p state and @p opcode, rewrite @p opcode based on the
  900  * current evaluation state.
  901  * 
  902  * This allows the insertion of implicit opcodes into interpretation of the
  903  * opcode stream.
  904  * 
  905  * If @p opcode is rewritten, it should be returned from
  906  * bhnd_sprom_opcode_step() instead of the opcode parsed from @p state's opcode
  907  * stream.
  908  * 
  909  * If @p opcode remains unmodified, then bhnd_sprom_opcode_step() should
  910  * proceed to standard evaluation.
  911  */
  912 static int
  913 bhnd_sprom_opcode_rewrite_opcode(bhnd_sprom_opcode_state *state,
  914     uint8_t *opcode)
  915 {
  916         uint8_t op;
  917         int     error;
  918 
  919         op = SPROM_OPCODE_OP(*opcode);
  920         switch (state->var_state) {
  921         case SPROM_OPCODE_VAR_STATE_NONE:
  922                 /* No open variable definition */
  923                 return (0);
  924 
  925         case SPROM_OPCODE_VAR_STATE_OPEN:
  926                 /* Open variable definition; check for implicit closure. */
  927 
  928                 /*
  929                  * If a variable definition contains no explicit bind
  930                  * instructions prior to closure, we must generate a DO_BIND
  931                  * instruction with count and skip values of 1.
  932                  */
  933                 if (SPROM_OP_IS_VAR_END(op) &&
  934                     state->var.bind_total == 0)
  935                 {
  936                         uint8_t count, skip_in, skip_out;
  937                         bool    skip_in_negative;
  938 
  939                         /* Create bind with skip_in/skip_out of 1, count of 1 */
  940                         count = 1;
  941                         skip_in = 1;
  942                         skip_out = 1;
  943                         skip_in_negative = false;
  944 
  945                         error = bhnd_sprom_opcode_set_bind(state, count,
  946                             skip_in, skip_in_negative, skip_out);
  947                         if (error)
  948                                 return (error);
  949 
  950                         /* Return DO_BIND */
  951                         *opcode = SPROM_OPCODE_DO_BIND |
  952                             (0 << SPROM_OP_BIND_SKIP_IN_SIGN) |
  953                             (1 << SPROM_OP_BIND_SKIP_IN_SHIFT) |
  954                             (1 << SPROM_OP_BIND_SKIP_OUT_SHIFT);
  955 
  956                         return (0);
  957                 }
  958 
  959                 /*
  960                  * If a variable is implicitly closed (e.g. by a new variable
  961                  * definition), we must generate a VAR_END instruction.
  962                  */
  963                 if (SPROM_OP_IS_IMPLICIT_VAR_END(op)) {
  964                         /* Mark as complete */
  965                         if ((error = bhnd_sprom_opcode_end_var(state)))
  966                                 return (error);
  967 
  968                         /* Return VAR_END */
  969                         *opcode = SPROM_OPCODE_VAR_END;
  970                         return (0);
  971                 }
  972                 break;
  973 
  974         case SPROM_OPCODE_VAR_STATE_DONE:
  975                 /* Previously completed variable definition. Discard variable
  976                  * state */
  977                 return (bhnd_sprom_opcode_clear_var(state));
  978         }
  979 
  980         /* Nothing to do */
  981         return (0);
  982 }
  983 
  984 /**
  985  * Evaluate one opcode from @p state.
  986  *
  987  * @param state The opcode state to be evaluated.
  988  * @param[out] opcode On success, the evaluated opcode
  989  * 
  990  * @retval 0 success
  991  * @retval ENOENT if EOF is reached
  992  * @retval non-zero if evaluation otherwise fails, a regular unix error
  993  * code will be returned.
  994  */
  995 static int
  996 bhnd_sprom_opcode_step(bhnd_sprom_opcode_state *state, uint8_t *opcode)
  997 {
  998         int error;
  999 
 1000         while (*state->input != SPROM_OPCODE_EOF) {
 1001                 uint32_t        val;
 1002                 uint8_t         op, rewrite, immd;
 1003 
 1004                 /* Fetch opcode */
 1005                 *opcode = *state->input;
 1006                 op = SPROM_OPCODE_OP(*opcode);
 1007                 immd = SPROM_OPCODE_IMM(*opcode);
 1008 
 1009                 /* Clear any existing bind state */
 1010                 if ((error = bhnd_sprom_opcode_flush_bind(state)))
 1011                         return (error);
 1012 
 1013                 /* Insert local opcode based on current state? */
 1014                 rewrite = *opcode;
 1015                 if ((error = bhnd_sprom_opcode_rewrite_opcode(state, &rewrite)))
 1016                         return (error);
 1017 
 1018                 if (rewrite != *opcode) {
 1019                         /* Provide rewritten opcode */
 1020                         *opcode = rewrite;
 1021 
 1022                         /* We must keep evaluating until we hit a state
 1023                          * applicable to the SPROM revision we're parsing */
 1024                         if (!bhnd_sprom_opcode_matches_layout_rev(state))
 1025                                 continue;
 1026 
 1027                         return (0);
 1028                 }
 1029 
 1030                 /* Advance input */
 1031                 state->input++;
 1032 
 1033                 switch (op) {
 1034                 case SPROM_OPCODE_VAR_IMM:
 1035                         if ((error = bhnd_sprom_opcode_set_var(state, immd)))
 1036                                 return (error);
 1037                         break;
 1038 
 1039                 case SPROM_OPCODE_VAR_REL_IMM:
 1040                         error = bhnd_sprom_opcode_set_var(state,
 1041                             state->vid + immd);
 1042                         if (error)
 1043                                 return (error);
 1044                         break;
 1045 
 1046                 case SPROM_OPCODE_VAR:
 1047                         error = bhnd_sprom_opcode_read_opval32(state, immd,
 1048                             &val);
 1049                         if (error)
 1050                                 return (error);
 1051 
 1052                         if ((error = bhnd_sprom_opcode_set_var(state, val)))
 1053                                 return (error);
 1054 
 1055                         break;
 1056 
 1057                 case SPROM_OPCODE_VAR_END:
 1058                         if ((error = bhnd_sprom_opcode_end_var(state)))
 1059                                 return (error);
 1060                         break;
 1061 
 1062                 case SPROM_OPCODE_NELEM:
 1063                         immd = *state->input;
 1064                         if ((error = bhnd_sprom_opcode_set_nelem(state, immd)))
 1065                                 return (error);
 1066 
 1067                         state->input++;
 1068                         break;
 1069 
 1070                 case SPROM_OPCODE_DO_BIND:
 1071                 case SPROM_OPCODE_DO_BINDN: {
 1072                         uint8_t count, skip_in, skip_out;
 1073                         bool    skip_in_negative;
 1074 
 1075                         /* Fetch skip arguments */
 1076                         skip_in = (immd & SPROM_OP_BIND_SKIP_IN_MASK) >>
 1077                             SPROM_OP_BIND_SKIP_IN_SHIFT;
 1078 
 1079                         skip_in_negative =
 1080                             ((immd & SPROM_OP_BIND_SKIP_IN_SIGN) != 0);
 1081 
 1082                         skip_out = (immd & SPROM_OP_BIND_SKIP_OUT_MASK) >>
 1083                               SPROM_OP_BIND_SKIP_OUT_SHIFT;
 1084 
 1085                         /* Fetch count argument (if any) */
 1086                         if (op == SPROM_OPCODE_DO_BINDN) {
 1087                                 /* Count is provided as trailing U8 */
 1088                                 count = *state->input;
 1089                                 state->input++;
 1090                         } else {
 1091                                 count = 1;
 1092                         }
 1093 
 1094                         /* Set BIND state */
 1095                         error = bhnd_sprom_opcode_set_bind(state, count,
 1096                             skip_in, skip_in_negative, skip_out);
 1097                         if (error)
 1098                                 return (error);
 1099 
 1100                         break;
 1101                 }
 1102                 case SPROM_OPCODE_DO_BINDN_IMM: {
 1103                         uint8_t count, skip_in, skip_out;
 1104                         bool    skip_in_negative;
 1105 
 1106                         /* Implicit skip_in/skip_out of 1, count encoded as immd
 1107                          * value */
 1108                         count = immd;
 1109                         skip_in = 1;
 1110                         skip_out = 1;
 1111                         skip_in_negative = false;
 1112 
 1113                         error = bhnd_sprom_opcode_set_bind(state, count,
 1114                             skip_in, skip_in_negative, skip_out);
 1115                         if (error)
 1116                                 return (error);
 1117                         break;
 1118                 }
 1119 
 1120                 case SPROM_OPCODE_REV_IMM:
 1121                         error = bhnd_sprom_opcode_set_revs(state, immd, immd);
 1122                         if (error)
 1123                                 return (error);
 1124                         break;
 1125 
 1126                 case SPROM_OPCODE_REV_RANGE: {
 1127                         uint8_t range;
 1128                         uint8_t rstart, rend;
 1129 
 1130                         /* Revision range is encoded in next byte, as
 1131                          * { uint8_t start:4, uint8_t end:4 } */
 1132                         range = *state->input;
 1133                         rstart = (range & SPROM_OP_REV_START_MASK) >>
 1134                             SPROM_OP_REV_START_SHIFT;
 1135                         rend = (range & SPROM_OP_REV_END_MASK) >>
 1136                             SPROM_OP_REV_END_SHIFT;
 1137 
 1138                         /* Update revision bitmask */
 1139                         error = bhnd_sprom_opcode_set_revs(state, rstart, rend);
 1140                         if (error)
 1141                                 return (error);
 1142 
 1143                         /* Advance input */
 1144                         state->input++;
 1145                         break;
 1146                 }
 1147                 case SPROM_OPCODE_MASK_IMM:
 1148                         if ((error = bhnd_sprom_opcode_set_mask(state, immd)))
 1149                                 return (error);
 1150                         break;
 1151 
 1152                 case SPROM_OPCODE_MASK:
 1153                         error = bhnd_sprom_opcode_read_opval32(state, immd,
 1154                             &val);
 1155                         if (error)
 1156                                 return (error);
 1157 
 1158                         if ((error = bhnd_sprom_opcode_set_mask(state, val)))
 1159                                 return (error);
 1160                         break;
 1161 
 1162                 case SPROM_OPCODE_SHIFT_IMM:
 1163                         error = bhnd_sprom_opcode_set_shift(state, immd * 2);
 1164                         if (error)
 1165                                 return (error);
 1166                         break;
 1167 
 1168                 case SPROM_OPCODE_SHIFT: {
 1169                         int8_t shift;
 1170 
 1171                         if (immd == SPROM_OP_DATA_I8) {
 1172                                 shift = (int8_t)(*state->input);
 1173                         } else if (immd == SPROM_OP_DATA_U8) {
 1174                                 val = *state->input;
 1175                                 if (val > INT8_MAX) {
 1176                                         SPROM_OP_BAD(state, "invalid shift "
 1177                                             "value: %#x\n", val);
 1178                                 }
 1179 
 1180                                 shift = val;
 1181                         } else {
 1182                                 SPROM_OP_BAD(state, "unsupported shift data "
 1183                                     "type: %#hhx\n", immd);
 1184                                 return (EINVAL);
 1185                         }
 1186 
 1187                         if ((error = bhnd_sprom_opcode_set_shift(state, shift)))
 1188                                 return (error);
 1189 
 1190                         state->input++;
 1191                         break;
 1192                 }
 1193                 case SPROM_OPCODE_OFFSET_REL_IMM:
 1194                         /* Fetch unscaled relative offset */
 1195                         val = immd;
 1196 
 1197                         /* Apply scale */
 1198                         error = bhnd_sprom_opcode_apply_scale(state, &val);
 1199                         if (error)
 1200                                 return (error);
 1201 
 1202                         /* Adding val must not overflow our offset */
 1203                         if (UINT32_MAX - state->offset < val) {
 1204                                 BHND_NV_LOG("offset out of range\n");
 1205                                 return (EINVAL);
 1206                         }
 1207 
 1208                         /* Adjust offset */
 1209                         state->offset += val;
 1210                         break;
 1211                 case SPROM_OPCODE_OFFSET:
 1212                         error = bhnd_sprom_opcode_read_opval32(state, immd,
 1213                             &val);
 1214                         if (error)
 1215                                 return (error);
 1216 
 1217                         state->offset = val;
 1218                         break;
 1219 
 1220                 case SPROM_OPCODE_TYPE:
 1221                         /* Type follows as U8 */
 1222                         immd = *state->input;
 1223                         state->input++;
 1224 
 1225                         /* fall through */
 1226                 case SPROM_OPCODE_TYPE_IMM:
 1227                         switch (immd) {
 1228                         case BHND_NVRAM_TYPE_UINT8:
 1229                         case BHND_NVRAM_TYPE_UINT16:
 1230                         case BHND_NVRAM_TYPE_UINT32:
 1231                         case BHND_NVRAM_TYPE_UINT64:
 1232                         case BHND_NVRAM_TYPE_INT8:
 1233                         case BHND_NVRAM_TYPE_INT16:
 1234                         case BHND_NVRAM_TYPE_INT32:
 1235                         case BHND_NVRAM_TYPE_INT64:
 1236                         case BHND_NVRAM_TYPE_CHAR:
 1237                         case BHND_NVRAM_TYPE_STRING:
 1238                                 error = bhnd_sprom_opcode_set_type(state,
 1239                                     (bhnd_nvram_type)immd);
 1240                                 if (error)
 1241                                         return (error);
 1242                                 break;
 1243                         default:
 1244                                 BHND_NV_LOG("unrecognized type %#hhx\n", immd);
 1245                                 return (EINVAL);
 1246                         }
 1247                         break;
 1248 
 1249                 default:
 1250                         BHND_NV_LOG("unrecognized opcode %#hhx\n", *opcode);
 1251                         return (EINVAL);
 1252                 }
 1253 
 1254                 /* We must keep evaluating until we hit a state applicable to
 1255                  * the SPROM revision we're parsing */
 1256                 if (bhnd_sprom_opcode_matches_layout_rev(state))
 1257                         return (0);
 1258         }
 1259 
 1260         /* End of opcode stream */
 1261         return (ENOENT);
 1262 }
 1263 
 1264 /**
 1265  * Reset SPROM opcode evaluation state, seek to the @p entry's position,
 1266  * and perform complete evaluation of the variable's opcodes.
 1267  * 
 1268  * @param state The opcode state to be to be evaluated.
 1269  * @param entry The indexed variable location.
 1270  *
 1271  * @retval 0 success
 1272  * @retval non-zero If evaluation fails, a regular unix error code will be
 1273  * returned.
 1274  */
 1275 int
 1276 bhnd_sprom_opcode_eval_var(bhnd_sprom_opcode_state *state,
 1277     bhnd_sprom_opcode_idx_entry *entry)
 1278 {
 1279         uint8_t opcode;
 1280         int     error;
 1281 
 1282         /* Seek to entry */
 1283         if ((error = bhnd_sprom_opcode_seek(state, entry)))
 1284                 return (error);
 1285 
 1286         /* Parse full variable definition */
 1287         while ((error = bhnd_sprom_opcode_step(state, &opcode)) == 0) {
 1288                 /* Iterate until VAR_END */
 1289                 if (SPROM_OPCODE_OP(opcode) != SPROM_OPCODE_VAR_END)
 1290                         continue;
 1291 
 1292                 BHND_NV_ASSERT(state->var_state == SPROM_OPCODE_VAR_STATE_DONE,
 1293                     ("incomplete variable definition"));
 1294 
 1295                 return (0);
 1296         }
 1297 
 1298         /* Error parsing definition */
 1299         return (error);
 1300 }
 1301 
 1302 /**
 1303  * Evaluate @p state until the next variable definition is found.
 1304  * 
 1305  * @param state The opcode state to be evaluated.
 1306  * 
 1307  * @retval 0 success
 1308  * @retval ENOENT if no additional variable definitions are available.
 1309  * @retval non-zero if evaluation otherwise fails, a regular unix error
 1310  * code will be returned.
 1311  */
 1312 int
 1313 bhnd_sprom_opcode_next_var(bhnd_sprom_opcode_state *state)
 1314 {
 1315         uint8_t opcode;
 1316         int     error;
 1317 
 1318         /* Step until we hit a variable opcode */
 1319         while ((error = bhnd_sprom_opcode_step(state, &opcode)) == 0) {
 1320                 switch (SPROM_OPCODE_OP(opcode)) {
 1321                 case SPROM_OPCODE_VAR:
 1322                 case SPROM_OPCODE_VAR_IMM:
 1323                 case SPROM_OPCODE_VAR_REL_IMM:
 1324                         BHND_NV_ASSERT(
 1325                             state->var_state == SPROM_OPCODE_VAR_STATE_OPEN,
 1326                             ("missing variable definition"));
 1327 
 1328                         return (0);
 1329                 default:
 1330                         continue;
 1331                 }
 1332         }
 1333 
 1334         /* Reached EOF, or evaluation failed */
 1335         return (error);
 1336 }
 1337 
 1338 /**
 1339  * Evaluate @p state until the next binding for the current variable definition
 1340  * is found.
 1341  * 
 1342  * @param state The opcode state to be evaluated.
 1343  * 
 1344  * @retval 0 success
 1345  * @retval ENOENT if no additional binding opcodes are found prior to reaching
 1346  * a new variable definition, or the end of @p state's binding opcodes.
 1347  * @retval non-zero if evaluation otherwise fails, a regular unix error
 1348  * code will be returned.
 1349  */
 1350 int
 1351 bhnd_sprom_opcode_next_binding(bhnd_sprom_opcode_state *state)
 1352 {
 1353         uint8_t opcode;
 1354         int     error;
 1355 
 1356         if (state->var_state != SPROM_OPCODE_VAR_STATE_OPEN)
 1357                 return (EINVAL);
 1358 
 1359         /* Step until we hit a bind opcode, or a new variable */
 1360         while ((error = bhnd_sprom_opcode_step(state, &opcode)) == 0) {
 1361                 switch (SPROM_OPCODE_OP(opcode)) {
 1362                 case SPROM_OPCODE_DO_BIND:
 1363                 case SPROM_OPCODE_DO_BINDN:
 1364                 case SPROM_OPCODE_DO_BINDN_IMM:
 1365                         /* Found next bind */
 1366                         BHND_NV_ASSERT(
 1367                             state->var_state == SPROM_OPCODE_VAR_STATE_OPEN,
 1368                             ("missing variable definition"));
 1369                         BHND_NV_ASSERT(state->var.have_bind, ("missing bind"));
 1370 
 1371                         return (0);
 1372 
 1373                 case SPROM_OPCODE_VAR_END:
 1374                         /* No further binding opcodes */ 
 1375                         BHND_NV_ASSERT(
 1376                             state->var_state == SPROM_OPCODE_VAR_STATE_DONE,
 1377                             ("variable definition still available"));
 1378                         return (ENOENT);
 1379                 }
 1380         }
 1381 
 1382         /* Not found, or evaluation failed */
 1383         return (error);
 1384 }

Cache object: 0a3fc427c0ac40e4d15279fe9abf0288


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