#include <sys/param.h>
#include <sys/endian.h>
#ifdef _KERNEL
#include <sys/systm.h>
#include <machine/_inttypes.h>
#else
#include <errno.h>
#include <inttypes.h>
#include <stdint.h>
#include <string.h>
#endif
#include "bhnd_nvram_private.h"
#include "bhnd_nvram_data_spromvar.h"
static int bhnd_sprom_opcode_sort_idx(const void *lhs, const void *rhs);
static int bhnd_nvram_opcode_idx_vid_compare(const void *key,
const void *rhs);
static int bhnd_sprom_opcode_reset(bhnd_sprom_opcode_state *state);
static int bhnd_sprom_opcode_set_type(bhnd_sprom_opcode_state *state,
bhnd_nvram_type type);
static int bhnd_sprom_opcode_set_var(bhnd_sprom_opcode_state *state,
size_t vid);
static int bhnd_sprom_opcode_clear_var(bhnd_sprom_opcode_state *state);
static int bhnd_sprom_opcode_flush_bind(bhnd_sprom_opcode_state *state);
static int bhnd_sprom_opcode_read_opval32(bhnd_sprom_opcode_state *state,
uint8_t type, uint32_t *opval);
static int bhnd_sprom_opcode_step(bhnd_sprom_opcode_state *state,
uint8_t *opcode);
#define SPROM_OP_BAD(_state, _fmt, ...) \
BHND_NV_LOG("bad encoding at %td: " _fmt, \
(_state)->input - (_state)->layout->bindings, ##__VA_ARGS__)
int
bhnd_sprom_opcode_init(bhnd_sprom_opcode_state *state,
const struct bhnd_sprom_layout *layout)
{
bhnd_sprom_opcode_idx_entry *idx;
size_t num_vars, num_idx;
int error;
idx = NULL;
state->layout = layout;
state->idx = NULL;
state->num_idx = 0;
if ((error = bhnd_sprom_opcode_reset(state)))
return (error);
num_idx = state->layout->num_vars;
idx = bhnd_nv_calloc(num_idx, sizeof(*idx));
if (idx == NULL)
return (ENOMEM);
for (num_vars = 0; num_vars < num_idx; num_vars++) {
if ((error = bhnd_sprom_opcode_next_var(state))) {
SPROM_OP_BAD(state, "error reading expected variable "
"entry: %d\n", error);
bhnd_nv_free(idx);
return (error);
}
error = bhnd_sprom_opcode_init_entry(state, &idx[num_vars]);
if (error) {
SPROM_OP_BAD(state, "error initializing index for "
"entry: %d\n", error);
bhnd_nv_free(idx);
return (error);
}
}
if ((error = bhnd_sprom_opcode_next_var(state)) != ENOENT) {
BHND_NV_LOG("expected EOF parsing binding table: %d\n", error);
bhnd_nv_free(idx);
return (ENXIO);
}
if ((error = bhnd_sprom_opcode_reset(state))) {
bhnd_nv_free(idx);
return (error);
}
qsort(idx, num_idx, sizeof(idx[0]), bhnd_sprom_opcode_sort_idx);
state->idx = idx;
state->num_idx = num_idx;
return (0);
}
static int
bhnd_sprom_opcode_reset(bhnd_sprom_opcode_state *state)
{
memset(&state->var, 0, sizeof(state->var));
state->input = state->layout->bindings;
state->offset = 0;
state->vid = 0;
state->var_state = SPROM_OPCODE_VAR_STATE_NONE;
bit_set(state->revs, state->layout->rev);
return (0);
}
void
bhnd_sprom_opcode_fini(bhnd_sprom_opcode_state *state)
{
bhnd_nv_free(state->idx);
}
static int
bhnd_sprom_opcode_sort_idx(const void *lhs, const void *rhs)
{
const bhnd_sprom_opcode_idx_entry *l, *r;
l = lhs;
r = rhs;
if (l->vid < r->vid)
return (-1);
if (l->vid > r->vid)
return (1);
return (0);
}
static int
bhnd_nvram_opcode_idx_vid_compare(const void *key, const void *rhs)
{
const bhnd_sprom_opcode_idx_entry *entry;
size_t vid;
vid = *(const size_t *)key;
entry = rhs;
if (vid < entry->vid)
return (-1);
if (vid > entry->vid)
return (1);
return (0);
}
bhnd_sprom_opcode_idx_entry *
bhnd_sprom_opcode_index_find(bhnd_sprom_opcode_state *state, const char *name)
{
const struct bhnd_nvram_vardefn *var;
size_t vid;
if ((var = bhnd_nvram_find_vardefn(name)) == NULL)
return (NULL);
vid = bhnd_nvram_get_vardefn_id(var);
return (bsearch(&vid, state->idx, state->num_idx, sizeof(state->idx[0]),
bhnd_nvram_opcode_idx_vid_compare));
}
bhnd_sprom_opcode_idx_entry *
bhnd_sprom_opcode_index_next(bhnd_sprom_opcode_state *state,
bhnd_sprom_opcode_idx_entry *prev)
{
size_t idxpos;
if (prev == NULL) {
idxpos = 0;
} else {
idxpos = (size_t)(prev - state->idx);
BHND_NV_ASSERT(idxpos < state->num_idx,
("invalid index %zu", idxpos));
idxpos++;
}
if (idxpos == state->num_idx)
return (NULL);
return (&state->idx[idxpos]);
}
int
bhnd_sprom_opcode_init_entry(bhnd_sprom_opcode_state *state,
bhnd_sprom_opcode_idx_entry *entry)
{
size_t opcodes;
if (state->offset > UINT16_MAX) {
SPROM_OP_BAD(state, "cannot index large offset %u\n",
state->offset);
return (ENXIO);
}
entry->offset = state->offset;
if (state->vid > UINT16_MAX) {
SPROM_OP_BAD(state, "cannot index large vid %zu\n",
state->vid);
return (ENXIO);
}
entry->vid = state->vid;
opcodes = (state->input - state->layout->bindings);
if (opcodes > UINT16_MAX) {
SPROM_OP_BAD(state, "cannot index large opcode offset "
"%zu\n", opcodes);
return (ENXIO);
}
entry->opcodes = opcodes;
return (0);
}
int
bhnd_sprom_opcode_seek(bhnd_sprom_opcode_state *state,
bhnd_sprom_opcode_idx_entry *entry)
{
int error;
BHND_NV_ASSERT(entry->opcodes < state->layout->bindings_size,
("index entry references invalid opcode position"));
if ((error = bhnd_sprom_opcode_reset(state)))
return (error);
state->input = state->layout->bindings + entry->opcodes;
state->offset = entry->offset;
if ((error = bhnd_sprom_opcode_set_var(state, entry->vid)))
return (error);
return (0);
}
static inline int
bhnd_sprom_opcode_set_revs(bhnd_sprom_opcode_state *state, uint8_t start,
uint8_t end)
{
int error;
if (start > SPROM_OP_REV_MAX ||
end > SPROM_OP_REV_MAX ||
end < start)
{
SPROM_OP_BAD(state, "invalid revision range: %hhu-%hhu\n",
start, end);
return (EINVAL);
}
if ((error = bhnd_sprom_opcode_clear_var(state)))
return (error);
memset(state->revs, 0x0, sizeof(state->revs));
bit_nset(state->revs, start, end);
return (0);
}
static inline int
bhnd_sprom_opcode_set_mask(bhnd_sprom_opcode_state *state, uint32_t mask)
{
if (state->var_state != SPROM_OPCODE_VAR_STATE_OPEN) {
SPROM_OP_BAD(state, "no open variable definition\n");
return (EINVAL);
}
state->var.mask = mask;
return (0);
}
static inline int
bhnd_sprom_opcode_set_shift(bhnd_sprom_opcode_state *state, int8_t shift)
{
if (state->var_state != SPROM_OPCODE_VAR_STATE_OPEN) {
SPROM_OP_BAD(state, "no open variable definition\n");
return (EINVAL);
}
state->var.shift = shift;
return (0);
}
static inline int
bhnd_sprom_opcode_set_bind(bhnd_sprom_opcode_state *state, uint8_t count,
uint8_t skip_in, bool skip_in_negative, uint8_t skip_out)
{
uint32_t iskip_total;
uint32_t iskip_scaled;
int error;
if (state->var_state != SPROM_OPCODE_VAR_STATE_OPEN) {
SPROM_OP_BAD(state, "no open variable definition\n");
SPROM_OP_BAD(state, "BIND outside of variable definition\n");
return (EINVAL);
}
if (state->var.have_bind) {
SPROM_OP_BAD(state, "BIND overwrites existing definition\n");
return (EINVAL);
}
if (count == 0) {
SPROM_OP_BAD(state, "BIND with zero count\n");
return (EINVAL);
}
iskip_scaled = skip_in;
if ((error = bhnd_sprom_opcode_apply_scale(state, &iskip_scaled)))
return (error);
if (iskip_scaled > 0 && UINT32_MAX / iskip_scaled < count) {
SPROM_OP_BAD(state, "skip_in %hhu would overflow", skip_in);
return (EINVAL);
}
iskip_total = iskip_scaled * count;
if (skip_in_negative) {
if (iskip_total > state->offset) {
SPROM_OP_BAD(state, "skip_in %hhu would underflow "
"offset %u\n", skip_in, state->offset);
return (EINVAL);
}
} else {
if (UINT32_MAX - iskip_total < state->offset) {
SPROM_OP_BAD(state, "skip_in %hhu would overflow "
"offset %u\n", skip_in, state->offset);
return (EINVAL);
}
}
state->var.have_bind = true;
state->var.bind.count = count;
state->var.bind.skip_in = skip_in;
state->var.bind.skip_out = skip_out;
state->var.bind.skip_in_negative = skip_in_negative;
state->var.bind_total++;
return (0);
}
static int
bhnd_sprom_opcode_flush_bind(bhnd_sprom_opcode_state *state)
{
int error;
uint32_t skip;
if (state->var_state != SPROM_OPCODE_VAR_STATE_OPEN ||
!state->var.have_bind)
return (0);
if (state->var.bind.count > 0) {
skip = state->var.bind.skip_in * state->var.bind.count;
if ((error = bhnd_sprom_opcode_apply_scale(state, &skip)))
return (error);
if (state->var.bind.skip_in_negative) {
state->offset -= skip;
} else {
state->offset += skip;
}
}
memset(&state->var.bind, 0, sizeof(state->var.bind));
state->var.have_bind = false;
return (0);
}
static int
bhnd_sprom_opcode_set_type(bhnd_sprom_opcode_state *state, bhnd_nvram_type type)
{
bhnd_nvram_type base_type;
size_t width;
uint32_t mask;
if (state->var_state != SPROM_OPCODE_VAR_STATE_OPEN) {
SPROM_OP_BAD(state, "type set outside variable definition\n");
return (EINVAL);
}
width = bhnd_nvram_type_width(type);
if (width == 0) {
SPROM_OP_BAD(state, "unsupported variable-width type: %d\n",
type);
return (EINVAL);
} else if (width > UINT32_MAX) {
SPROM_OP_BAD(state, "invalid type width %zu for type: %d\n",
width, type);
return (EINVAL);
}
base_type = bhnd_nvram_base_type(type);
switch (base_type) {
case BHND_NVRAM_TYPE_UINT8:
case BHND_NVRAM_TYPE_INT8:
case BHND_NVRAM_TYPE_CHAR:
mask = UINT8_MAX;
break;
case BHND_NVRAM_TYPE_UINT16:
case BHND_NVRAM_TYPE_INT16:
mask = UINT16_MAX;
break;
case BHND_NVRAM_TYPE_UINT32:
case BHND_NVRAM_TYPE_INT32:
mask = UINT32_MAX;
break;
case BHND_NVRAM_TYPE_STRING:
default:
SPROM_OP_BAD(state, "unsupported type: %d\n", type);
return (EINVAL);
}
state->var.base_type = base_type;
state->var.mask = mask;
state->var.scale = (uint32_t)width;
return (0);
}
static int
bhnd_sprom_opcode_clear_var(bhnd_sprom_opcode_state *state)
{
if (state->var_state == SPROM_OPCODE_VAR_STATE_NONE)
return (0);
BHND_NV_ASSERT(state->var_state == SPROM_OPCODE_VAR_STATE_DONE,
("incomplete variable definition"));
BHND_NV_ASSERT(!state->var.have_bind, ("stale bind state"));
memset(&state->var, 0, sizeof(state->var));
state->var_state = SPROM_OPCODE_VAR_STATE_NONE;
return (0);
}
static int
bhnd_sprom_opcode_set_nelem(bhnd_sprom_opcode_state *state, uint8_t nelem)
{
const struct bhnd_nvram_vardefn *var;
if (state->var_state != SPROM_OPCODE_VAR_STATE_OPEN) {
SPROM_OP_BAD(state, "array length set without open variable "
"state");
return (EINVAL);
}
if ((var = bhnd_nvram_get_vardefn(state->vid)) == NULL) {
SPROM_OP_BAD(state, "unknown variable ID: %zu\n", state->vid);
return (EINVAL);
}
if (nelem == 0) {
SPROM_OP_BAD(state, "invalid nelem: %hhu\n", nelem);
return (EINVAL);
}
if (!bhnd_nvram_is_array_type(var->type) && nelem != 1) {
SPROM_OP_BAD(state, "nelem %hhu on non-array %zu\n", nelem,
state->vid);
return (ENXIO);
}
if (nelem > var->nelem) {
SPROM_OP_BAD(state, "nelem %hhu exceeds %zu length %hhu\n",
nelem, state->vid, var->nelem);
return (ENXIO);
}
state->var.nelem = nelem;
return (0);
}
static int
bhnd_sprom_opcode_set_var(bhnd_sprom_opcode_state *state, size_t vid)
{
const struct bhnd_nvram_vardefn *var;
int error;
BHND_NV_ASSERT(state->var_state == SPROM_OPCODE_VAR_STATE_NONE,
("overwrite of open variable definition"));
if ((var = bhnd_nvram_get_vardefn(vid)) == NULL) {
SPROM_OP_BAD(state, "unknown variable ID: %zu\n", vid);
return (EINVAL);
}
state->vid = vid;
state->var_state = SPROM_OPCODE_VAR_STATE_OPEN;
memset(&state->var, 0x0, sizeof(state->var));
if ((error = bhnd_sprom_opcode_set_type(state, var->type)))
return (error);
if ((error = bhnd_sprom_opcode_set_nelem(state, var->nelem)))
return (error);
return (0);
}
static int
bhnd_sprom_opcode_end_var(bhnd_sprom_opcode_state *state)
{
if (state->var_state != SPROM_OPCODE_VAR_STATE_OPEN) {
SPROM_OP_BAD(state, "no open variable definition\n");
return (EINVAL);
}
state->var_state = SPROM_OPCODE_VAR_STATE_DONE;
return (0);
}
int
bhnd_sprom_opcode_apply_scale(bhnd_sprom_opcode_state *state, uint32_t *value)
{
if (state->var_state != SPROM_OPCODE_VAR_STATE_OPEN) {
SPROM_OP_BAD(state, "scaled value encoded without open "
"variable state");
return (EINVAL);
}
if (UINT32_MAX / state->var.scale < *value) {
SPROM_OP_BAD(state, "cannot represent %" PRIu32 " * %" PRIu32
"\n", *value, state->var.scale);
return (EINVAL);
}
*value = (*value) * state->var.scale;
return (0);
}
static int
bhnd_sprom_opcode_read_opval32(bhnd_sprom_opcode_state *state, uint8_t type,
uint32_t *opval)
{
const uint8_t *p;
int error;
p = state->input;
switch (type) {
case SPROM_OP_DATA_I8:
*opval = (int32_t)(int8_t)(*p);
p += 1;
break;
case SPROM_OP_DATA_U8:
*opval = *p;
p += 1;
break;
case SPROM_OP_DATA_U8_SCALED:
*opval = *p;
if ((error = bhnd_sprom_opcode_apply_scale(state, opval)))
return (error);
p += 1;
break;
case SPROM_OP_DATA_U16:
*opval = le16dec(p);
p += 2;
break;
case SPROM_OP_DATA_U32:
*opval = le32dec(p);
p += 4;
break;
default:
SPROM_OP_BAD(state, "unsupported data type: %hhu\n", type);
return (EINVAL);
}
state->input = p;
return (0);
}
static inline bool
bhnd_sprom_opcode_matches_layout_rev(bhnd_sprom_opcode_state *state)
{
return (bit_test(state->revs, state->layout->rev));
}
static int
bhnd_sprom_opcode_rewrite_opcode(bhnd_sprom_opcode_state *state,
uint8_t *opcode)
{
uint8_t op;
int error;
op = SPROM_OPCODE_OP(*opcode);
switch (state->var_state) {
case SPROM_OPCODE_VAR_STATE_NONE:
return (0);
case SPROM_OPCODE_VAR_STATE_OPEN:
if (SPROM_OP_IS_VAR_END(op) &&
state->var.bind_total == 0)
{
uint8_t count, skip_in, skip_out;
bool skip_in_negative;
count = 1;
skip_in = 1;
skip_out = 1;
skip_in_negative = false;
error = bhnd_sprom_opcode_set_bind(state, count,
skip_in, skip_in_negative, skip_out);
if (error)
return (error);
*opcode = SPROM_OPCODE_DO_BIND |
(0 << SPROM_OP_BIND_SKIP_IN_SIGN) |
(1 << SPROM_OP_BIND_SKIP_IN_SHIFT) |
(1 << SPROM_OP_BIND_SKIP_OUT_SHIFT);
return (0);
}
if (SPROM_OP_IS_IMPLICIT_VAR_END(op)) {
if ((error = bhnd_sprom_opcode_end_var(state)))
return (error);
*opcode = SPROM_OPCODE_VAR_END;
return (0);
}
break;
case SPROM_OPCODE_VAR_STATE_DONE:
return (bhnd_sprom_opcode_clear_var(state));
}
return (0);
}
static int
bhnd_sprom_opcode_step(bhnd_sprom_opcode_state *state, uint8_t *opcode)
{
int error;
while (*state->input != SPROM_OPCODE_EOF) {
uint32_t val;
uint8_t op, rewrite, immd;
*opcode = *state->input;
op = SPROM_OPCODE_OP(*opcode);
immd = SPROM_OPCODE_IMM(*opcode);
if ((error = bhnd_sprom_opcode_flush_bind(state)))
return (error);
rewrite = *opcode;
if ((error = bhnd_sprom_opcode_rewrite_opcode(state, &rewrite)))
return (error);
if (rewrite != *opcode) {
*opcode = rewrite;
if (!bhnd_sprom_opcode_matches_layout_rev(state))
continue;
return (0);
}
state->input++;
switch (op) {
case SPROM_OPCODE_VAR_IMM:
if ((error = bhnd_sprom_opcode_set_var(state, immd)))
return (error);
break;
case SPROM_OPCODE_VAR_REL_IMM:
error = bhnd_sprom_opcode_set_var(state,
state->vid + immd);
if (error)
return (error);
break;
case SPROM_OPCODE_VAR:
error = bhnd_sprom_opcode_read_opval32(state, immd,
&val);
if (error)
return (error);
if ((error = bhnd_sprom_opcode_set_var(state, val)))
return (error);
break;
case SPROM_OPCODE_VAR_END:
if ((error = bhnd_sprom_opcode_end_var(state)))
return (error);
break;
case SPROM_OPCODE_NELEM:
immd = *state->input;
if ((error = bhnd_sprom_opcode_set_nelem(state, immd)))
return (error);
state->input++;
break;
case SPROM_OPCODE_DO_BIND:
case SPROM_OPCODE_DO_BINDN: {
uint8_t count, skip_in, skip_out;
bool skip_in_negative;
skip_in = (immd & SPROM_OP_BIND_SKIP_IN_MASK) >>
SPROM_OP_BIND_SKIP_IN_SHIFT;
skip_in_negative =
((immd & SPROM_OP_BIND_SKIP_IN_SIGN) != 0);
skip_out = (immd & SPROM_OP_BIND_SKIP_OUT_MASK) >>
SPROM_OP_BIND_SKIP_OUT_SHIFT;
if (op == SPROM_OPCODE_DO_BINDN) {
count = *state->input;
state->input++;
} else {
count = 1;
}
error = bhnd_sprom_opcode_set_bind(state, count,
skip_in, skip_in_negative, skip_out);
if (error)
return (error);
break;
}
case SPROM_OPCODE_DO_BINDN_IMM: {
uint8_t count, skip_in, skip_out;
bool skip_in_negative;
count = immd;
skip_in = 1;
skip_out = 1;
skip_in_negative = false;
error = bhnd_sprom_opcode_set_bind(state, count,
skip_in, skip_in_negative, skip_out);
if (error)
return (error);
break;
}
case SPROM_OPCODE_REV_IMM:
error = bhnd_sprom_opcode_set_revs(state, immd, immd);
if (error)
return (error);
break;
case SPROM_OPCODE_REV_RANGE: {
uint8_t range;
uint8_t rstart, rend;
range = *state->input;
rstart = (range & SPROM_OP_REV_START_MASK) >>
SPROM_OP_REV_START_SHIFT;
rend = (range & SPROM_OP_REV_END_MASK) >>
SPROM_OP_REV_END_SHIFT;
error = bhnd_sprom_opcode_set_revs(state, rstart, rend);
if (error)
return (error);
state->input++;
break;
}
case SPROM_OPCODE_MASK_IMM:
if ((error = bhnd_sprom_opcode_set_mask(state, immd)))
return (error);
break;
case SPROM_OPCODE_MASK:
error = bhnd_sprom_opcode_read_opval32(state, immd,
&val);
if (error)
return (error);
if ((error = bhnd_sprom_opcode_set_mask(state, val)))
return (error);
break;
case SPROM_OPCODE_SHIFT_IMM:
error = bhnd_sprom_opcode_set_shift(state, immd * 2);
if (error)
return (error);
break;
case SPROM_OPCODE_SHIFT: {
int8_t shift;
if (immd == SPROM_OP_DATA_I8) {
shift = (int8_t)(*state->input);
} else if (immd == SPROM_OP_DATA_U8) {
val = *state->input;
if (val > INT8_MAX) {
SPROM_OP_BAD(state, "invalid shift "
"value: %#x\n", val);
}
shift = val;
} else {
SPROM_OP_BAD(state, "unsupported shift data "
"type: %#hhx\n", immd);
return (EINVAL);
}
if ((error = bhnd_sprom_opcode_set_shift(state, shift)))
return (error);
state->input++;
break;
}
case SPROM_OPCODE_OFFSET_REL_IMM:
val = immd;
error = bhnd_sprom_opcode_apply_scale(state, &val);
if (error)
return (error);
if (UINT32_MAX - state->offset < val) {
BHND_NV_LOG("offset out of range\n");
return (EINVAL);
}
state->offset += val;
break;
case SPROM_OPCODE_OFFSET:
error = bhnd_sprom_opcode_read_opval32(state, immd,
&val);
if (error)
return (error);
state->offset = val;
break;
case SPROM_OPCODE_TYPE:
immd = *state->input;
state->input++;
case SPROM_OPCODE_TYPE_IMM:
switch (immd) {
case BHND_NVRAM_TYPE_UINT8:
case BHND_NVRAM_TYPE_UINT16:
case BHND_NVRAM_TYPE_UINT32:
case BHND_NVRAM_TYPE_UINT64:
case BHND_NVRAM_TYPE_INT8:
case BHND_NVRAM_TYPE_INT16:
case BHND_NVRAM_TYPE_INT32:
case BHND_NVRAM_TYPE_INT64:
case BHND_NVRAM_TYPE_CHAR:
case BHND_NVRAM_TYPE_STRING:
error = bhnd_sprom_opcode_set_type(state,
(bhnd_nvram_type)immd);
if (error)
return (error);
break;
default:
BHND_NV_LOG("unrecognized type %#hhx\n", immd);
return (EINVAL);
}
break;
default:
BHND_NV_LOG("unrecognized opcode %#hhx\n", *opcode);
return (EINVAL);
}
if (bhnd_sprom_opcode_matches_layout_rev(state))
return (0);
}
return (ENOENT);
}
int
bhnd_sprom_opcode_eval_var(bhnd_sprom_opcode_state *state,
bhnd_sprom_opcode_idx_entry *entry)
{
uint8_t opcode;
int error;
if ((error = bhnd_sprom_opcode_seek(state, entry)))
return (error);
while ((error = bhnd_sprom_opcode_step(state, &opcode)) == 0) {
if (SPROM_OPCODE_OP(opcode) != SPROM_OPCODE_VAR_END)
continue;
BHND_NV_ASSERT(state->var_state == SPROM_OPCODE_VAR_STATE_DONE,
("incomplete variable definition"));
return (0);
}
return (error);
}
int
bhnd_sprom_opcode_next_var(bhnd_sprom_opcode_state *state)
{
uint8_t opcode;
int error;
while ((error = bhnd_sprom_opcode_step(state, &opcode)) == 0) {
switch (SPROM_OPCODE_OP(opcode)) {
case SPROM_OPCODE_VAR:
case SPROM_OPCODE_VAR_IMM:
case SPROM_OPCODE_VAR_REL_IMM:
BHND_NV_ASSERT(
state->var_state == SPROM_OPCODE_VAR_STATE_OPEN,
("missing variable definition"));
return (0);
default:
continue;
}
}
return (error);
}
int
bhnd_sprom_opcode_next_binding(bhnd_sprom_opcode_state *state)
{
uint8_t opcode;
int error;
if (state->var_state != SPROM_OPCODE_VAR_STATE_OPEN)
return (EINVAL);
while ((error = bhnd_sprom_opcode_step(state, &opcode)) == 0) {
switch (SPROM_OPCODE_OP(opcode)) {
case SPROM_OPCODE_DO_BIND:
case SPROM_OPCODE_DO_BINDN:
case SPROM_OPCODE_DO_BINDN_IMM:
BHND_NV_ASSERT(
state->var_state == SPROM_OPCODE_VAR_STATE_OPEN,
("missing variable definition"));
BHND_NV_ASSERT(state->var.have_bind, ("missing bind"));
return (0);
case SPROM_OPCODE_VAR_END:
BHND_NV_ASSERT(
state->var_state == SPROM_OPCODE_VAR_STATE_DONE,
("variable definition still available"));
return (ENOENT);
}
}
return (error);
}