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