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