xref: /freebsd/sys/dev/bhnd/nvram/bhnd_nvram_data_sprom_subr.c (revision 22cf89c938886d14f5796fc49f9f020c23ea8eaf)
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
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
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
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
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
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 *
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 *
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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