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