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