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/endian.h> 34 35 #ifdef _KERNEL 36 #include <sys/param.h> 37 #include <sys/ctype.h> 38 #include <sys/malloc.h> 39 #include <sys/systm.h> 40 41 #include <machine/_inttypes.h> 42 #else /* !_KERNEL */ 43 #include <ctype.h> 44 #include <errno.h> 45 #include <inttypes.h> 46 #include <stdint.h> 47 #include <stdio.h> 48 #include <stdlib.h> 49 #include <string.h> 50 #endif /* _KERNEL */ 51 52 #include "bhnd_nvram_private.h" 53 54 #include "bhnd_nvram_datavar.h" 55 56 #include "bhnd_nvram_data_spromvar.h" 57 58 /* 59 * BHND SPROM NVRAM data class 60 * 61 * The SPROM data format is a fixed-layout, non-self-descriptive binary format, 62 * used on Broadcom wireless and wired adapters, that provides a subset of the 63 * variables defined by Broadcom SoC NVRAM formats. 64 */ 65 BHND_NVRAM_DATA_CLASS_DEFN(sprom, "Broadcom SPROM", 66 sizeof(struct bhnd_nvram_sprom)) 67 68 static int sprom_sort_idx(const void *lhs, const void *rhs); 69 70 static int sprom_opcode_state_init(struct sprom_opcode_state *state, 71 const struct bhnd_sprom_layout *layout); 72 static int sprom_opcode_state_reset(struct sprom_opcode_state *state); 73 static int sprom_opcode_state_seek(struct sprom_opcode_state *state, 74 struct sprom_opcode_idx *indexed); 75 76 static int sprom_opcode_next_var(struct sprom_opcode_state *state); 77 static int sprom_opcode_parse_var(struct sprom_opcode_state *state, 78 struct sprom_opcode_idx *indexed); 79 80 static int sprom_opcode_next_binding(struct sprom_opcode_state *state); 81 82 static int sprom_opcode_set_type(struct sprom_opcode_state *state, 83 bhnd_nvram_type type); 84 85 static int sprom_opcode_set_var(struct sprom_opcode_state *state, 86 size_t vid); 87 static int sprom_opcode_clear_var(struct sprom_opcode_state *state); 88 static int sprom_opcode_flush_bind(struct sprom_opcode_state *state); 89 static int sprom_opcode_read_opval32(struct sprom_opcode_state *state, 90 uint8_t type, uint32_t *opval); 91 static int sprom_opcode_apply_scale(struct sprom_opcode_state *state, 92 uint32_t *value); 93 94 static int sprom_opcode_step(struct sprom_opcode_state *state, 95 uint8_t *opcode); 96 97 #define SPROM_OP_BAD(_state, _fmt, ...) \ 98 BHND_NV_LOG("bad encoding at %td: " _fmt, \ 99 (_state)->input - (_state)->layout->bindings, ##__VA_ARGS__) 100 101 #define SPROM_COOKIE_TO_NVRAM(_cookie) \ 102 bhnd_nvram_get_vardefn(((struct sprom_opcode_idx *)_cookie)->vid) 103 104 /** 105 * Read the magic value from @p io, and verify that it matches 106 * the @p layout's expected magic value. 107 * 108 * If @p layout does not defined a magic value, @p magic is set to 0x0 109 * and success is returned. 110 * 111 * @param io An I/O context mapping the SPROM data to be identified. 112 * @param layout The SPROM layout against which @p io should be verified. 113 * @param[out] magic On success, the SPROM magic value. 114 * 115 * @retval 0 success 116 * @retval non-zero If checking @p io otherwise fails, a regular unix 117 * error code will be returned. 118 */ 119 static int 120 bhnd_nvram_sprom_check_magic(struct bhnd_nvram_io *io, 121 const struct bhnd_sprom_layout *layout, uint16_t *magic) 122 { 123 int error; 124 125 /* Skip if layout does not define a magic value */ 126 if (layout->flags & SPROM_LAYOUT_MAGIC_NONE) 127 return (0); 128 129 /* Read the magic value */ 130 error = bhnd_nvram_io_read(io, layout->magic_offset, magic, 131 sizeof(*magic)); 132 if (error) 133 return (error); 134 135 *magic = le16toh(*magic); 136 137 /* If the signature does not match, skip to next layout */ 138 if (*magic != layout->magic_value) 139 return (ENXIO); 140 141 return (0); 142 } 143 144 /** 145 * Attempt to identify the format of the SPROM data mapped by @p io. 146 * 147 * The SPROM data format does not provide any identifying information at a 148 * known offset, instead requiring that we iterate over the known SPROM image 149 * sizes until we are able to compute a valid checksum (and, for later 150 * revisions, validate a signature at a revision-specific offset). 151 * 152 * @param io An I/O context mapping the SPROM data to be identified. 153 * @param[out] ident On success, the identified SPROM layout. 154 * @param[out] shadow On success, a correctly sized iobuf instance mapping 155 * a copy of the identified SPROM image. The caller is 156 * responsible for deallocating this instance via 157 * bhnd_nvram_io_free() 158 * 159 * @retval 0 success 160 * @retval non-zero If identifying @p io otherwise fails, a regular unix 161 * error code will be returned. 162 */ 163 static int 164 bhnd_nvram_sprom_ident(struct bhnd_nvram_io *io, 165 const struct bhnd_sprom_layout **ident, struct bhnd_nvram_io **shadow) 166 { 167 struct bhnd_nvram_io *buf; 168 uint8_t crc; 169 size_t crc_errors; 170 size_t sprom_sz_max; 171 int error; 172 173 /* Find the largest SPROM layout size */ 174 sprom_sz_max = 0; 175 for (size_t i = 0; i < bhnd_sprom_num_layouts; i++) { 176 sprom_sz_max = bhnd_nv_ummax(sprom_sz_max, 177 bhnd_sprom_layouts[i].size); 178 } 179 180 /* Allocate backing buffer and initialize CRC state */ 181 buf = bhnd_nvram_iobuf_empty(0, sprom_sz_max); 182 crc = BHND_NVRAM_CRC8_INITIAL; 183 crc_errors = 0; 184 185 /* We iterate the SPROM layouts smallest to largest, allowing us to 186 * perform incremental checksum calculation */ 187 for (size_t i = 0; i < bhnd_sprom_num_layouts; i++) { 188 const struct bhnd_sprom_layout *layout; 189 void *ptr; 190 size_t nbytes, nr; 191 uint16_t magic; 192 uint8_t srev; 193 bool crc_valid; 194 bool have_magic; 195 196 layout = &bhnd_sprom_layouts[i]; 197 nbytes = bhnd_nvram_io_getsize(buf); 198 199 if ((layout->flags & SPROM_LAYOUT_MAGIC_NONE)) { 200 have_magic = false; 201 } else { 202 have_magic = true; 203 } 204 205 /* Layout instances must be ordered from smallest to largest by 206 * the nvram_map compiler */ 207 if (nbytes > layout->size) 208 BHND_NV_PANIC("SPROM layout is defined out-of-order"); 209 210 /* Calculate number of additional bytes to be read */ 211 nr = layout->size - nbytes; 212 213 /* Adjust the buffer size and fetch a write pointer */ 214 if ((error = bhnd_nvram_io_setsize(buf, layout->size))) 215 goto failed; 216 217 error = bhnd_nvram_io_write_ptr(buf, nbytes, &ptr, nr, NULL); 218 if (error) 219 goto failed; 220 221 /* Read image data and update CRC (errors are reported 222 * after the signature check) */ 223 if ((error = bhnd_nvram_io_read(io, nbytes, ptr, nr))) 224 goto failed; 225 226 crc = bhnd_nvram_crc8(ptr, nr, crc); 227 crc_valid = (crc == BHND_NVRAM_CRC8_VALID); 228 if (!crc_valid) 229 crc_errors++; 230 231 /* Fetch SPROM revision */ 232 error = bhnd_nvram_io_read(buf, layout->srev_offset, &srev, 233 sizeof(srev)); 234 if (error) 235 goto failed; 236 237 /* Early sromrev 1 devices (specifically some BCM440x enet 238 * cards) are reported to have been incorrectly programmed 239 * with a revision of 0x10. */ 240 if (layout->rev == 1 && srev == 0x10) 241 srev = 0x1; 242 243 /* Check revision against the layout definition */ 244 if (srev != layout->rev) 245 continue; 246 247 /* Check the magic value, skipping to the next layout on 248 * failure. */ 249 error = bhnd_nvram_sprom_check_magic(buf, layout, &magic); 250 if (error) { 251 /* If the CRC is was valid, log the mismatch */ 252 if (crc_valid || BHND_NV_VERBOSE) { 253 BHND_NV_LOG("invalid sprom %hhu signature: " 254 "0x%hx (expected 0x%hx)\n", srev, 255 magic, layout->magic_value); 256 257 error = ENXIO; 258 goto failed; 259 } 260 261 continue; 262 } 263 264 /* Check for an earlier CRC error */ 265 if (!crc_valid) { 266 /* If the magic check succeeded, then we may just have 267 * data corruption -- log the CRC error */ 268 if (have_magic || BHND_NV_VERBOSE) { 269 BHND_NV_LOG("sprom %hhu CRC error (crc=%#hhx, " 270 "expected=%#x)\n", srev, crc, 271 BHND_NVRAM_CRC8_VALID); 272 } 273 274 continue; 275 } 276 277 /* Identified */ 278 *shadow = buf; 279 *ident = layout; 280 return (0); 281 } 282 283 /* No match -- set error and fallthrough */ 284 error = ENXIO; 285 if (crc_errors > 0 && BHND_NV_VERBOSE) { 286 BHND_NV_LOG("sprom parsing failed with %zu CRC errors\n", 287 crc_errors); 288 } 289 290 failed: 291 bhnd_nvram_io_free(buf); 292 return (error); 293 } 294 295 static int 296 bhnd_nvram_sprom_probe(struct bhnd_nvram_io *io) 297 { 298 const struct bhnd_sprom_layout *layout; 299 struct bhnd_nvram_io *shadow; 300 int error; 301 302 /* Try to parse the input */ 303 if ((error = bhnd_nvram_sprom_ident(io, &layout, &shadow))) 304 return (error); 305 306 /* Clean up the shadow iobuf */ 307 bhnd_nvram_io_free(shadow); 308 309 return (BHND_NVRAM_DATA_PROBE_DEFAULT); 310 } 311 312 static int 313 bhnd_nvram_sprom_new(struct bhnd_nvram_data *nv, struct bhnd_nvram_io *io) 314 { 315 struct bhnd_nvram_sprom *sp; 316 size_t num_vars; 317 int error; 318 319 sp = (struct bhnd_nvram_sprom *)nv; 320 321 /* Identify the SPROM input data */ 322 if ((error = bhnd_nvram_sprom_ident(io, &sp->layout, &sp->data))) 323 goto failed; 324 325 /* Initialize SPROM binding eval state */ 326 if ((error = sprom_opcode_state_init(&sp->state, sp->layout))) 327 goto failed; 328 329 /* Allocate our opcode index */ 330 sp->num_idx = sp->layout->num_vars; 331 if ((sp->idx = bhnd_nv_calloc(sp->num_idx, sizeof(*sp->idx))) == NULL) 332 goto failed; 333 334 /* Parse out index entries from our stateful opcode stream */ 335 for (num_vars = 0; num_vars < sp->num_idx; num_vars++) { 336 size_t opcodes; 337 338 /* Seek to next entry */ 339 if ((error = sprom_opcode_next_var(&sp->state))) { 340 SPROM_OP_BAD(&sp->state, 341 "error reading expected variable entry: %d\n", 342 error); 343 goto failed; 344 } 345 346 /* We limit the SPROM index representations to the minimal 347 * type widths capable of covering all known layouts */ 348 349 /* Save SPROM image offset */ 350 if (sp->state.offset > UINT16_MAX) { 351 SPROM_OP_BAD(&sp->state, 352 "cannot index large offset %u\n", sp->state.offset); 353 } 354 sp->idx[num_vars].offset = sp->state.offset; 355 356 /* Save current variable ID */ 357 if (sp->state.vid > UINT16_MAX) { 358 SPROM_OP_BAD(&sp->state, 359 "cannot index large vid %zu\n", sp->state.vid); 360 } 361 sp->idx[num_vars].vid = sp->state.vid; 362 363 /* Save opcode position */ 364 opcodes = (sp->state.input - sp->layout->bindings); 365 if (opcodes > UINT16_MAX) { 366 SPROM_OP_BAD(&sp->state, 367 "cannot index large opcode offset %zu\n", opcodes); 368 } 369 sp->idx[num_vars].opcodes = opcodes; 370 } 371 372 /* Should have reached end of binding table; next read must return 373 * ENOENT */ 374 if ((error = sprom_opcode_next_var(&sp->state)) != ENOENT) { 375 BHND_NV_LOG("expected EOF parsing binding table: %d\n", error); 376 goto failed; 377 } 378 379 /* Sort index by variable ID, ascending */ 380 qsort(sp->idx, sp->num_idx, sizeof(sp->idx[0]), sprom_sort_idx); 381 382 return (0); 383 384 failed: 385 if (sp->data != NULL) 386 bhnd_nvram_io_free(sp->data); 387 388 if (sp->idx != NULL) 389 bhnd_nv_free(sp->idx); 390 391 return (error); 392 } 393 394 /* sort function for sprom_opcode_idx values */ 395 static int 396 sprom_sort_idx(const void *lhs, const void *rhs) 397 { 398 const struct sprom_opcode_idx *l, *r; 399 400 l = lhs; 401 r = rhs; 402 403 if (l->vid < r->vid) 404 return (-1); 405 if (l->vid > r->vid) 406 return (1); 407 return (0); 408 } 409 410 static void 411 bhnd_nvram_sprom_free(struct bhnd_nvram_data *nv) 412 { 413 struct bhnd_nvram_sprom *sp = (struct bhnd_nvram_sprom *)nv; 414 415 bhnd_nvram_io_free(sp->data); 416 bhnd_nv_free(sp->idx); 417 } 418 419 size_t 420 bhnd_nvram_sprom_count(struct bhnd_nvram_data *nv) 421 { 422 struct bhnd_nvram_sprom *sprom = (struct bhnd_nvram_sprom *)nv; 423 return (sprom->layout->num_vars); 424 } 425 426 static int 427 bhnd_nvram_sprom_size(struct bhnd_nvram_data *nv, size_t *size) 428 { 429 struct bhnd_nvram_sprom *sprom = (struct bhnd_nvram_sprom *)nv; 430 431 /* The serialized form will be identical in length 432 * to our backing buffer representation */ 433 *size = bhnd_nvram_io_getsize(sprom->data); 434 return (0); 435 } 436 437 static int 438 bhnd_nvram_sprom_serialize(struct bhnd_nvram_data *nv, void *buf, size_t *len) 439 { 440 struct bhnd_nvram_sprom *sprom; 441 size_t limit, req_len; 442 int error; 443 444 sprom = (struct bhnd_nvram_sprom *)nv; 445 limit = *len; 446 447 /* Provide the required size */ 448 if ((error = bhnd_nvram_sprom_size(nv, &req_len))) 449 return (error); 450 451 *len = req_len; 452 453 if (buf == NULL) { 454 return (0); 455 } else if (*len > limit) { 456 return (ENOMEM); 457 } 458 459 /* Write to the output buffer */ 460 return (bhnd_nvram_io_read(sprom->data, 0x0, buf, *len)); 461 } 462 463 static uint32_t 464 bhnd_nvram_sprom_caps(struct bhnd_nvram_data *nv) 465 { 466 return (BHND_NVRAM_DATA_CAP_INDEXED); 467 } 468 469 static const char * 470 bhnd_nvram_sprom_next(struct bhnd_nvram_data *nv, void **cookiep) 471 { 472 struct bhnd_nvram_sprom *sp; 473 struct sprom_opcode_idx *idx_entry; 474 size_t idx_next; 475 const struct bhnd_nvram_vardefn *var; 476 477 sp = (struct bhnd_nvram_sprom *)nv; 478 479 /* Seek to appropriate starting point */ 480 if (*cookiep == NULL) { 481 /* Start search at first index entry */ 482 idx_next = 0; 483 } else { 484 /* Determine current index position */ 485 idx_entry = *cookiep; 486 idx_next = (size_t)(idx_entry - sp->idx); 487 BHND_NV_ASSERT(idx_next < sp->num_idx, 488 ("invalid index %zu; corrupt cookie?", idx_next)); 489 490 /* Advance to next entry */ 491 idx_next++; 492 493 /* Check for EOF */ 494 if (idx_next == sp->num_idx) 495 return (NULL); 496 } 497 498 /* Skip entries that are disabled by virtue of IGNALL1 */ 499 for (; idx_next < sp->num_idx; idx_next++) { 500 /* Fetch index entry and update cookiep */ 501 idx_entry = &sp->idx[idx_next]; 502 *cookiep = idx_entry; 503 504 /* Fetch variable definition */ 505 var = bhnd_nvram_get_vardefn(idx_entry->vid); 506 507 /* We might need to parse the variable's value to determine 508 * whether it should be treated as unset */ 509 if (var->flags & BHND_NVRAM_VF_IGNALL1) { 510 int error; 511 size_t len; 512 513 error = bhnd_nvram_sprom_getvar(nv, *cookiep, NULL, 514 &len, var->type); 515 if (error) { 516 BHND_NV_ASSERT(error == ENOENT, ("unexpected " 517 "error parsing variable: %d", error)); 518 519 continue; 520 } 521 } 522 523 /* Found! */ 524 return (var->name); 525 } 526 527 /* Reached end of index entries */ 528 return (NULL); 529 } 530 531 /* bsearch function used by bhnd_nvram_sprom_find() */ 532 static int 533 bhnd_nvram_sprom_find_vid_compare(const void *key, const void *rhs) 534 { 535 const struct sprom_opcode_idx *r; 536 size_t l; 537 538 l = *(const size_t *)key; 539 r = rhs; 540 541 if (l < r->vid) 542 return (-1); 543 if (l > r->vid) 544 return (1); 545 return (0); 546 } 547 548 static void * 549 bhnd_nvram_sprom_find(struct bhnd_nvram_data *nv, const char *name) 550 { 551 struct bhnd_nvram_sprom *sp; 552 const struct bhnd_nvram_vardefn *var; 553 size_t vid; 554 555 sp = (struct bhnd_nvram_sprom *)nv; 556 557 /* Determine the variable ID for the given name */ 558 if ((var = bhnd_nvram_find_vardefn(name)) == NULL) 559 return (NULL); 560 561 vid = bhnd_nvram_get_vardefn_id(var); 562 563 /* Search our index for the variable ID */ 564 return (bsearch(&vid, sp->idx, sp->num_idx, sizeof(sp->idx[0]), 565 bhnd_nvram_sprom_find_vid_compare)); 566 } 567 568 /** 569 * Read the value of @p type from the SPROM data at @p offset, apply @p mask 570 * and @p shift, and OR with the existing @p value. 571 * 572 * @param sp The SPROM data instance. 573 * @param var The NVRAM variable definition 574 * @param type The type to read at @p offset 575 * @param offset The data offset to be read. 576 * @param mask The mask to be applied to the value read at @p offset. 577 * @param shift The shift to be applied after masking; if positive, a right 578 * shift will be applied, if negative, a left shift. 579 * @param value The read destination; the parsed value will be OR'd with the 580 * current contents of @p value. 581 */ 582 static int 583 bhnd_nvram_sprom_read_offset(struct bhnd_nvram_sprom *sp, 584 const struct bhnd_nvram_vardefn *var, bhnd_nvram_type type, 585 size_t offset, uint32_t mask, int8_t shift, 586 union bhnd_nvram_sprom_intv *value) 587 { 588 size_t sp_width; 589 int error; 590 union { 591 uint8_t u8; 592 uint16_t u16; 593 uint32_t u32; 594 int8_t s8; 595 int16_t s16; 596 int32_t s32; 597 } sp_value; 598 599 /* Determine type width */ 600 sp_width = bhnd_nvram_value_size(type, NULL, 0, 1); 601 if (sp_width == 0) { 602 /* Variable-width types are unsupported */ 603 BHND_NV_LOG("invalid %s SPROM offset type %d\n", var->name, 604 type); 605 return (EFTYPE); 606 } 607 608 /* Perform read */ 609 error = bhnd_nvram_io_read(sp->data, offset, &sp_value, 610 sp_width); 611 if (error) { 612 BHND_NV_LOG("error reading %s SPROM offset %#zx: %d\n", 613 var->name, offset, error); 614 return (EFTYPE); 615 } 616 617 #define NV_PARSE_INT(_type, _src, _dest, _swap) do { \ 618 /* Swap to host byte order */ \ 619 sp_value. _src = (_type) _swap(sp_value. _src); \ 620 \ 621 /* Mask and shift the value */ \ 622 sp_value. _src &= mask; \ 623 if (shift > 0) { \ 624 sp_value. _src >>= shift; \ 625 } else if (shift < 0) { \ 626 sp_value. _src <<= -shift; \ 627 } \ 628 \ 629 /* Emit output, widening to 32-bit representation */ \ 630 value-> _dest |= sp_value. _src; \ 631 } while(0) 632 633 /* Apply mask/shift and widen to a common 32bit representation */ 634 switch (type) { 635 case BHND_NVRAM_TYPE_UINT8: 636 NV_PARSE_INT(uint8_t, u8, u32, ); 637 break; 638 case BHND_NVRAM_TYPE_UINT16: 639 NV_PARSE_INT(uint16_t, u16, u32, le16toh); 640 break; 641 case BHND_NVRAM_TYPE_UINT32: 642 NV_PARSE_INT(uint32_t, u32, u32, le32toh); 643 break; 644 case BHND_NVRAM_TYPE_INT8: 645 NV_PARSE_INT(int8_t, s8, s32, ); 646 break; 647 case BHND_NVRAM_TYPE_INT16: 648 NV_PARSE_INT(int16_t, s16, s32, le16toh); 649 break; 650 case BHND_NVRAM_TYPE_INT32: 651 NV_PARSE_INT(int32_t, s32, s32, le32toh); 652 break; 653 case BHND_NVRAM_TYPE_CHAR: 654 NV_PARSE_INT(uint8_t, u8, u32, ); 655 break; 656 657 case BHND_NVRAM_TYPE_UINT64: 658 case BHND_NVRAM_TYPE_INT64: 659 case BHND_NVRAM_TYPE_STRING: 660 /* fallthrough (unused by SPROM) */ 661 default: 662 BHND_NV_LOG("unhandled %s offset type: %d\n", var->name, type); 663 return (EFTYPE); 664 } 665 666 return (0); 667 } 668 669 static int 670 bhnd_nvram_sprom_getvar(struct bhnd_nvram_data *nv, void *cookiep, void *buf, 671 size_t *len, bhnd_nvram_type otype) 672 { 673 bhnd_nvram_val_t val; 674 struct bhnd_nvram_sprom *sp; 675 struct sprom_opcode_idx *idx; 676 const struct bhnd_nvram_vardefn *var; 677 union bhnd_nvram_sprom_storage storage; 678 union bhnd_nvram_sprom_storage *inp; 679 union bhnd_nvram_sprom_intv intv; 680 bhnd_nvram_type var_btype; 681 size_t ilen, ipos, iwidth; 682 size_t nelem; 683 bool all_bits_set; 684 int error; 685 686 sp = (struct bhnd_nvram_sprom *)nv; 687 idx = cookiep; 688 689 BHND_NV_ASSERT(cookiep != NULL, ("NULL variable cookiep")); 690 691 /* Fetch canonical variable definition */ 692 var = SPROM_COOKIE_TO_NVRAM(cookiep); 693 BHND_NV_ASSERT(var != NULL, ("invalid cookiep %p", cookiep)); 694 695 /* 696 * Fetch the array length from the SPROM variable definition. 697 * 698 * This generally be identical to the array length provided by the 699 * canonical NVRAM variable definition, but some SPROM layouts may 700 * define a smaller element count. 701 */ 702 if ((error = sprom_opcode_parse_var(&sp->state, idx))) { 703 BHND_NV_LOG("variable evaluation failed: %d\n", error); 704 return (error); 705 } 706 707 nelem = sp->state.var.nelem; 708 if (nelem > var->nelem) { 709 BHND_NV_LOG("SPROM array element count %zu cannot be " 710 "represented by '%s' element count of %hhu\n", nelem, 711 var->name, var->nelem); 712 return (EFTYPE); 713 } 714 715 /* Fetch the var's base element type */ 716 var_btype = bhnd_nvram_base_type(var->type); 717 718 /* Calculate total byte length of the native encoding */ 719 if ((iwidth = bhnd_nvram_value_size(var_btype, NULL, 0, 1)) == 0) { 720 /* SPROM does not use (and we do not support) decoding of 721 * variable-width data types */ 722 BHND_NV_LOG("invalid SPROM data type: %d", var->type); 723 return (EFTYPE); 724 } 725 ilen = nelem * iwidth; 726 727 /* Decode into our own local storage. */ 728 inp = &storage; 729 if (ilen > sizeof(storage)) { 730 BHND_NV_LOG("error decoding '%s', SPROM_ARRAY_MAXLEN " 731 "incorrect\n", var->name); 732 return (EFTYPE); 733 } 734 735 /* Zero-initialize our decode buffer; any output elements skipped 736 * during decode should default to zero. */ 737 memset(inp, 0, ilen); 738 739 /* 740 * Decode the SPROM data, iteratively decoding up to nelem values. 741 */ 742 if ((error = sprom_opcode_state_seek(&sp->state, idx))) { 743 BHND_NV_LOG("variable seek failed: %d\n", error); 744 return (error); 745 } 746 747 ipos = 0; 748 intv.u32 = 0x0; 749 if (var->flags & BHND_NVRAM_VF_IGNALL1) 750 all_bits_set = true; 751 else 752 all_bits_set = false; 753 while ((error = sprom_opcode_next_binding(&sp->state)) == 0) { 754 struct sprom_opcode_bind *binding; 755 struct sprom_opcode_var *binding_var; 756 bhnd_nvram_type intv_type; 757 size_t offset; 758 size_t nbyte; 759 uint32_t skip_in_bytes; 760 void *ptr; 761 762 BHND_NV_ASSERT( 763 sp->state.var_state >= SPROM_OPCODE_VAR_STATE_OPEN, 764 ("invalid var state")); 765 BHND_NV_ASSERT(sp->state.var.have_bind, ("invalid bind state")); 766 767 binding_var = &sp->state.var; 768 binding = &sp->state.var.bind; 769 770 if (ipos >= nelem) { 771 BHND_NV_LOG("output skip %u positioned " 772 "%zu beyond nelem %zu\n", 773 binding->skip_out, ipos, nelem); 774 return (EINVAL); 775 } 776 777 /* Calculate input skip bytes for this binding */ 778 skip_in_bytes = binding->skip_in; 779 error = sprom_opcode_apply_scale(&sp->state, &skip_in_bytes); 780 if (error) 781 return (error); 782 783 /* Bind */ 784 offset = sp->state.offset; 785 for (size_t i = 0; i < binding->count; i++) { 786 /* Read the offset value, OR'ing with the current 787 * value of intv */ 788 error = bhnd_nvram_sprom_read_offset(sp, var, 789 binding_var->base_type, 790 offset, 791 binding_var->mask, 792 binding_var->shift, 793 &intv); 794 if (error) 795 return (error); 796 797 /* If IGNALL1, record whether value does not have 798 * all bits set. */ 799 if (var->flags & BHND_NVRAM_VF_IGNALL1 && 800 all_bits_set) 801 { 802 uint32_t all1; 803 804 all1 = binding_var->mask; 805 if (binding_var->shift > 0) 806 all1 >>= binding_var->shift; 807 else if (binding_var->shift < 0) 808 all1 <<= -binding_var->shift; 809 810 if ((intv.u32 & all1) != all1) 811 all_bits_set = false; 812 } 813 814 /* Adjust input position; this was already verified to 815 * not overflow/underflow during SPROM opcode 816 * evaluation */ 817 if (binding->skip_in_negative) { 818 offset -= skip_in_bytes; 819 } else { 820 offset += skip_in_bytes; 821 } 822 823 /* Skip writing to inp if additional bindings are 824 * required to fully populate intv */ 825 if (binding->skip_out == 0) 826 continue; 827 828 /* We use bhnd_nvram_value_coerce() to perform 829 * overflow-checked coercion from the widened 830 * uint32/int32 intv value to the requested output 831 * type */ 832 if (bhnd_nvram_is_signed_type(var_btype)) 833 intv_type = BHND_NVRAM_TYPE_INT32; 834 else 835 intv_type = BHND_NVRAM_TYPE_UINT32; 836 837 /* Calculate address of the current element output 838 * position */ 839 ptr = (uint8_t *)inp + (iwidth * ipos); 840 841 /* Perform coercion of the array element */ 842 nbyte = iwidth; 843 error = bhnd_nvram_value_coerce(&intv, sizeof(intv), 844 intv_type, ptr, &nbyte, var_btype); 845 if (error) 846 return (error); 847 848 /* Clear temporary state */ 849 intv.u32 = 0x0; 850 851 /* Advance output position */ 852 if (SIZE_MAX - binding->skip_out < ipos) { 853 BHND_NV_LOG("output skip %u would overflow " 854 "%zu\n", binding->skip_out, ipos); 855 return (EINVAL); 856 } 857 858 ipos += binding->skip_out; 859 } 860 } 861 862 /* Did we iterate all bindings until hitting end of the variable 863 * definition? */ 864 BHND_NV_ASSERT(error != 0, ("loop terminated early")); 865 if (error != ENOENT) { 866 return (error); 867 } 868 869 /* If marked IGNALL1 and all bits are set, treat variable as 870 * unavailable */ 871 if ((var->flags & BHND_NVRAM_VF_IGNALL1) && all_bits_set) 872 return (ENOENT); 873 874 875 /* Perform value coercion from our local representation */ 876 error = bhnd_nvram_val_init(&val, var->fmt, inp, ilen, var->type, 877 BHND_NVRAM_VAL_BORROW_DATA); 878 if (error) 879 return (error); 880 881 error = bhnd_nvram_val_encode(&val, buf, len, otype); 882 883 /* Clean up */ 884 bhnd_nvram_val_release(&val); 885 return (error); 886 } 887 888 static const void * 889 bhnd_nvram_sprom_getvar_ptr(struct bhnd_nvram_data *nv, void *cookiep, 890 size_t *len, bhnd_nvram_type *type) 891 { 892 /* Unsupported */ 893 return (NULL); 894 } 895 896 static const char * 897 bhnd_nvram_sprom_getvar_name(struct bhnd_nvram_data *nv, void *cookiep) 898 { 899 const struct bhnd_nvram_vardefn *var; 900 901 BHND_NV_ASSERT(cookiep != NULL, ("NULL variable cookiep")); 902 903 var = SPROM_COOKIE_TO_NVRAM(cookiep); 904 BHND_NV_ASSERT(var != NULL, ("invalid cookiep %p", cookiep)); 905 906 return (var->name); 907 } 908 909 /** 910 * Initialize SPROM opcode evaluation state. 911 * 912 * @param state The opcode state to be initialized. 913 * @param layout The SPROM layout to be parsed by this instance. 914 * 915 * 916 * @retval 0 success 917 * @retval non-zero If initialization fails, a regular unix error code will be 918 * returned. 919 */ 920 static int 921 sprom_opcode_state_init(struct sprom_opcode_state *state, 922 const struct bhnd_sprom_layout *layout) 923 { 924 memset(state, 0, sizeof(*state)); 925 926 state->layout = layout; 927 state->input = layout->bindings; 928 state->var_state = SPROM_OPCODE_VAR_STATE_NONE; 929 930 bit_set(state->revs, layout->rev); 931 932 return (0); 933 } 934 935 /** 936 * Reset SPROM opcode evaluation state; future evaluation will be performed 937 * starting at the first opcode. 938 * 939 * @param state The opcode state to be reset. 940 * 941 * @retval 0 success 942 * @retval non-zero If reset fails, a regular unix error code will be returned. 943 */ 944 static int 945 sprom_opcode_state_reset(struct sprom_opcode_state *state) 946 { 947 return (sprom_opcode_state_init(state, state->layout)); 948 } 949 950 /** 951 * Reset SPROM opcode evaluation state and seek to the @p indexed position. 952 * 953 * @param state The opcode state to be reset. 954 * @param indexed The indexed location to which we'll seek the opcode state. 955 */ 956 static int 957 sprom_opcode_state_seek(struct sprom_opcode_state *state, 958 struct sprom_opcode_idx *indexed) 959 { 960 int error; 961 962 BHND_NV_ASSERT(indexed->opcodes < state->layout->bindings_size, 963 ("index entry references invalid opcode position")); 964 965 /* Reset state */ 966 if ((error = sprom_opcode_state_reset(state))) 967 return (error); 968 969 /* Seek to the indexed sprom opcode offset */ 970 state->input = state->layout->bindings + indexed->opcodes; 971 972 /* Restore the indexed sprom data offset and VID */ 973 state->offset = indexed->offset; 974 975 /* Restore the indexed sprom variable ID */ 976 if ((error = sprom_opcode_set_var(state, indexed->vid))) 977 return (error); 978 979 return (0); 980 } 981 982 /** 983 * Set the current revision range for @p state. This also resets 984 * variable state. 985 * 986 * @param state The opcode state to update 987 * @param start The first revision in the range. 988 * @param end The last revision in the range. 989 * 990 * @retval 0 success 991 * @retval non-zero If updating @p state fails, a regular unix error code will 992 * be returned. 993 */ 994 static inline int 995 sprom_opcode_set_revs(struct sprom_opcode_state *state, uint8_t start, 996 uint8_t end) 997 { 998 int error; 999 1000 /* Validate the revision range */ 1001 if (start > SPROM_OP_REV_MAX || 1002 end > SPROM_OP_REV_MAX || 1003 end < start) 1004 { 1005 SPROM_OP_BAD(state, "invalid revision range: %hhu-%hhu\n", 1006 start, end); 1007 return (EINVAL); 1008 } 1009 1010 /* Clear variable state */ 1011 if ((error = sprom_opcode_clear_var(state))) 1012 return (error); 1013 1014 /* Reset revision mask */ 1015 memset(state->revs, 0x0, sizeof(state->revs)); 1016 bit_nset(state->revs, start, end); 1017 1018 return (0); 1019 } 1020 1021 /** 1022 * Set the current variable's value mask for @p state. 1023 * 1024 * @param state The opcode state to update 1025 * @param mask The mask to be set 1026 * 1027 * @retval 0 success 1028 * @retval non-zero If updating @p state fails, a regular unix error code will 1029 * be returned. 1030 */ 1031 static inline int 1032 sprom_opcode_set_mask(struct sprom_opcode_state *state, uint32_t mask) 1033 { 1034 if (state->var_state != SPROM_OPCODE_VAR_STATE_OPEN) { 1035 SPROM_OP_BAD(state, "no open variable definition\n"); 1036 return (EINVAL); 1037 } 1038 1039 state->var.mask = mask; 1040 return (0); 1041 } 1042 1043 /** 1044 * Set the current variable's value shift for @p state. 1045 * 1046 * @param state The opcode state to update 1047 * @param shift The shift to be set 1048 * 1049 * @retval 0 success 1050 * @retval non-zero If updating @p state fails, a regular unix error code will 1051 * be returned. 1052 */ 1053 static inline int 1054 sprom_opcode_set_shift(struct sprom_opcode_state *state, int8_t shift) 1055 { 1056 if (state->var_state != SPROM_OPCODE_VAR_STATE_OPEN) { 1057 SPROM_OP_BAD(state, "no open variable definition\n"); 1058 return (EINVAL); 1059 } 1060 1061 state->var.shift = shift; 1062 return (0); 1063 } 1064 1065 /** 1066 * Register a new BIND/BINDN operation with @p state. 1067 * 1068 * @param state The opcode state to update. 1069 * @param count The number of elements to be bound. 1070 * @param skip_in The number of input elements to skip after each bind. 1071 * @param skip_in_negative If true, the input skip should be subtracted from 1072 * the current offset after each bind. If false, the input skip should be 1073 * added. 1074 * @param skip_out The number of output elements to skip after each bind. 1075 * 1076 * @retval 0 success 1077 * @retval EINVAL if a variable definition is not open. 1078 * @retval EINVAL if @p skip_in and @p count would trigger an overflow or 1079 * underflow when applied to the current input offset. 1080 * @retval ERANGE if @p skip_in would overflow uint32_t when multiplied by 1081 * @p count and the scale value. 1082 * @retval ERANGE if @p skip_out would overflow uint32_t when multiplied by 1083 * @p count and the scale value. 1084 * @retval non-zero If updating @p state otherwise fails, a regular unix error 1085 * code will be returned. 1086 */ 1087 static inline int 1088 sprom_opcode_set_bind(struct sprom_opcode_state *state, uint8_t count, 1089 uint8_t skip_in, bool skip_in_negative, uint8_t skip_out) 1090 { 1091 uint32_t iskip_total; 1092 uint32_t iskip_scaled; 1093 int error; 1094 1095 /* Must have an open variable */ 1096 if (state->var_state != SPROM_OPCODE_VAR_STATE_OPEN) { 1097 SPROM_OP_BAD(state, "no open variable definition\n"); 1098 SPROM_OP_BAD(state, "BIND outside of variable definition\n"); 1099 return (EINVAL); 1100 } 1101 1102 /* Cannot overwite an existing bind definition */ 1103 if (state->var.have_bind) { 1104 SPROM_OP_BAD(state, "BIND overwrites existing definition\n"); 1105 return (EINVAL); 1106 } 1107 1108 /* Must have a count of at least 1 */ 1109 if (count == 0) { 1110 SPROM_OP_BAD(state, "BIND with zero count\n"); 1111 return (EINVAL); 1112 } 1113 1114 /* Scale skip_in by the current type width */ 1115 iskip_scaled = skip_in; 1116 if ((error = sprom_opcode_apply_scale(state, &iskip_scaled))) 1117 return (error); 1118 1119 /* Calculate total input bytes skipped: iskip_scaled * count) */ 1120 if (iskip_scaled > 0 && UINT32_MAX / iskip_scaled < count) { 1121 SPROM_OP_BAD(state, "skip_in %hhu would overflow", skip_in); 1122 return (EINVAL); 1123 } 1124 1125 iskip_total = iskip_scaled * count; 1126 1127 /* Verify that the skip_in value won't under/overflow the current 1128 * input offset. */ 1129 if (skip_in_negative) { 1130 if (iskip_total > state->offset) { 1131 SPROM_OP_BAD(state, "skip_in %hhu would underflow " 1132 "offset %u\n", skip_in, state->offset); 1133 return (EINVAL); 1134 } 1135 } else { 1136 if (UINT32_MAX - iskip_total < state->offset) { 1137 SPROM_OP_BAD(state, "skip_in %hhu would overflow " 1138 "offset %u\n", skip_in, state->offset); 1139 return (EINVAL); 1140 } 1141 } 1142 1143 /* Set the actual count and skip values */ 1144 state->var.have_bind = true; 1145 state->var.bind.count = count; 1146 state->var.bind.skip_in = skip_in; 1147 state->var.bind.skip_out = skip_out; 1148 1149 state->var.bind.skip_in_negative = skip_in_negative; 1150 1151 /* Update total bind count for the current variable */ 1152 state->var.bind_total++; 1153 1154 return (0); 1155 } 1156 1157 1158 /** 1159 * Apply and clear the current opcode bind state, if any. 1160 * 1161 * @param state The opcode state to update. 1162 * 1163 * @retval 0 success 1164 * @retval non-zero If updating @p state otherwise fails, a regular unix error 1165 * code will be returned. 1166 */ 1167 static int 1168 sprom_opcode_flush_bind(struct sprom_opcode_state *state) 1169 { 1170 int error; 1171 uint32_t skip; 1172 1173 /* Nothing to do? */ 1174 if (state->var_state != SPROM_OPCODE_VAR_STATE_OPEN || 1175 !state->var.have_bind) 1176 return (0); 1177 1178 /* Apply SPROM offset adjustment */ 1179 if (state->var.bind.count > 0) { 1180 skip = state->var.bind.skip_in * state->var.bind.count; 1181 if ((error = sprom_opcode_apply_scale(state, &skip))) 1182 return (error); 1183 1184 if (state->var.bind.skip_in_negative) { 1185 state->offset -= skip; 1186 } else { 1187 state->offset += skip; 1188 } 1189 } 1190 1191 /* Clear bind state */ 1192 memset(&state->var.bind, 0, sizeof(state->var.bind)); 1193 state->var.have_bind = false; 1194 1195 return (0); 1196 } 1197 1198 /** 1199 * Set the current type to @p type, and reset type-specific 1200 * stream state. 1201 * 1202 * @param state The opcode state to update. 1203 * @param type The new type. 1204 * 1205 * @retval 0 success 1206 * @retval EINVAL if @p vid is not a valid variable ID. 1207 */ 1208 static int 1209 sprom_opcode_set_type(struct sprom_opcode_state *state, bhnd_nvram_type type) 1210 { 1211 bhnd_nvram_type base_type; 1212 size_t width; 1213 uint32_t mask; 1214 1215 /* Must have an open variable definition */ 1216 if (state->var_state != SPROM_OPCODE_VAR_STATE_OPEN) { 1217 SPROM_OP_BAD(state, "type set outside variable definition\n"); 1218 return (EINVAL); 1219 } 1220 1221 /* Fetch type width for use as our scale value */ 1222 width = bhnd_nvram_value_size(type, NULL, 0, 1); 1223 if (width == 0) { 1224 SPROM_OP_BAD(state, "unsupported variable-width type: %d\n", 1225 type); 1226 return (EINVAL); 1227 } else if (width > UINT32_MAX) { 1228 SPROM_OP_BAD(state, "invalid type width %zu for type: %d\n", 1229 width, type); 1230 return (EINVAL); 1231 } 1232 1233 /* Determine default mask value for the element type */ 1234 base_type = bhnd_nvram_base_type(type); 1235 switch (base_type) { 1236 case BHND_NVRAM_TYPE_UINT8: 1237 case BHND_NVRAM_TYPE_INT8: 1238 case BHND_NVRAM_TYPE_CHAR: 1239 mask = UINT8_MAX; 1240 break; 1241 case BHND_NVRAM_TYPE_UINT16: 1242 case BHND_NVRAM_TYPE_INT16: 1243 mask = UINT16_MAX; 1244 break; 1245 case BHND_NVRAM_TYPE_UINT32: 1246 case BHND_NVRAM_TYPE_INT32: 1247 mask = UINT32_MAX; 1248 break; 1249 case BHND_NVRAM_TYPE_STRING: 1250 /* fallthrough (unused by SPROM) */ 1251 default: 1252 SPROM_OP_BAD(state, "unsupported type: %d\n", type); 1253 return (EINVAL); 1254 } 1255 1256 /* Update state */ 1257 state->var.base_type = base_type; 1258 state->var.mask = mask; 1259 state->var.scale = (uint32_t)width; 1260 1261 return (0); 1262 } 1263 1264 /** 1265 * Clear current variable state, if any. 1266 * 1267 * @param state The opcode state to update. 1268 */ 1269 static int 1270 sprom_opcode_clear_var(struct sprom_opcode_state *state) 1271 { 1272 if (state->var_state == SPROM_OPCODE_VAR_STATE_NONE) 1273 return (0); 1274 1275 BHND_NV_ASSERT(state->var_state == SPROM_OPCODE_VAR_STATE_DONE, 1276 ("incomplete variable definition")); 1277 BHND_NV_ASSERT(!state->var.have_bind, ("stale bind state")); 1278 1279 memset(&state->var, 0, sizeof(state->var)); 1280 state->var_state = SPROM_OPCODE_VAR_STATE_NONE; 1281 1282 return (0); 1283 } 1284 1285 /** 1286 * Set the current variable's array element count to @p nelem. 1287 * 1288 * @param state The opcode state to update. 1289 * @param nelem The new array length. 1290 * 1291 * @retval 0 success 1292 * @retval EINVAL if no open variable definition exists. 1293 * @retval EINVAL if @p nelem is zero. 1294 * @retval ENXIO if @p nelem is greater than one, and the current variable does 1295 * not have an array type. 1296 * @retval ENXIO if @p nelem exceeds the array length of the NVRAM variable 1297 * definition. 1298 */ 1299 static int 1300 sprom_opcode_set_nelem(struct sprom_opcode_state *state, uint8_t nelem) 1301 { 1302 const struct bhnd_nvram_vardefn *var; 1303 1304 /* Must have a defined variable */ 1305 if (state->var_state != SPROM_OPCODE_VAR_STATE_OPEN) { 1306 SPROM_OP_BAD(state, "array length set without open variable " 1307 "state"); 1308 return (EINVAL); 1309 } 1310 1311 /* Locate the actual variable definition */ 1312 if ((var = bhnd_nvram_get_vardefn(state->vid)) == NULL) { 1313 SPROM_OP_BAD(state, "unknown variable ID: %zu\n", state->vid); 1314 return (EINVAL); 1315 } 1316 1317 /* Must be greater than zero */ 1318 if (nelem == 0) { 1319 SPROM_OP_BAD(state, "invalid nelem: %hhu\n", nelem); 1320 return (EINVAL); 1321 } 1322 1323 /* If the variable is not an array-typed value, the array length 1324 * must be 1 */ 1325 if (!bhnd_nvram_is_array_type(var->type) && nelem != 1) { 1326 SPROM_OP_BAD(state, "nelem %hhu on non-array %zu\n", nelem, 1327 state->vid); 1328 return (ENXIO); 1329 } 1330 1331 /* Cannot exceed the variable's defined array length */ 1332 if (nelem > var->nelem) { 1333 SPROM_OP_BAD(state, "nelem %hhu exceeds %zu length %hhu\n", 1334 nelem, state->vid, var->nelem); 1335 return (ENXIO); 1336 } 1337 1338 /* Valid length; update state */ 1339 state->var.nelem = nelem; 1340 1341 return (0); 1342 } 1343 1344 /** 1345 * Set the current variable ID to @p vid, and reset variable-specific 1346 * stream state. 1347 * 1348 * @param state The opcode state to update. 1349 * @param vid The new variable ID. 1350 * 1351 * @retval 0 success 1352 * @retval EINVAL if @p vid is not a valid variable ID. 1353 */ 1354 static int 1355 sprom_opcode_set_var(struct sprom_opcode_state *state, size_t vid) 1356 { 1357 const struct bhnd_nvram_vardefn *var; 1358 int error; 1359 1360 BHND_NV_ASSERT(state->var_state == SPROM_OPCODE_VAR_STATE_NONE, 1361 ("overwrite of open variable definition")); 1362 1363 /* Locate the variable definition */ 1364 if ((var = bhnd_nvram_get_vardefn(vid)) == NULL) { 1365 SPROM_OP_BAD(state, "unknown variable ID: %zu\n", vid); 1366 return (EINVAL); 1367 } 1368 1369 /* Update vid and var state */ 1370 state->vid = vid; 1371 state->var_state = SPROM_OPCODE_VAR_STATE_OPEN; 1372 1373 /* Initialize default variable record values */ 1374 memset(&state->var, 0x0, sizeof(state->var)); 1375 1376 /* Set initial base type */ 1377 if ((error = sprom_opcode_set_type(state, var->type))) 1378 return (error); 1379 1380 /* Set default array length */ 1381 if ((error = sprom_opcode_set_nelem(state, var->nelem))) 1382 return (error); 1383 1384 return (0); 1385 } 1386 1387 /** 1388 * Mark the currently open variable definition as complete. 1389 * 1390 * @param state The opcode state to update. 1391 * 1392 * @retval 0 success 1393 * @retval EINVAL if no incomplete open variable definition exists. 1394 */ 1395 static int 1396 sprom_opcode_end_var(struct sprom_opcode_state *state) 1397 { 1398 if (state->var_state != SPROM_OPCODE_VAR_STATE_OPEN) { 1399 SPROM_OP_BAD(state, "no open variable definition\n"); 1400 return (EINVAL); 1401 } 1402 1403 state->var_state = SPROM_OPCODE_VAR_STATE_DONE; 1404 return (0); 1405 } 1406 1407 /** 1408 * Apply the current scale to @p value. 1409 * 1410 * @param state The SPROM opcode state. 1411 * @param[in,out] value The value to scale 1412 * 1413 * @retval 0 success 1414 * @retval EINVAL if no open variable definition exists. 1415 * @retval EINVAL if applying the current scale would overflow. 1416 */ 1417 static int 1418 sprom_opcode_apply_scale(struct sprom_opcode_state *state, uint32_t *value) 1419 { 1420 /* Must have a defined variable (and thus, scale) */ 1421 if (state->var_state != SPROM_OPCODE_VAR_STATE_OPEN) { 1422 SPROM_OP_BAD(state, "scaled value encoded without open " 1423 "variable state"); 1424 return (EINVAL); 1425 } 1426 1427 /* Applying the scale value must not overflow */ 1428 if (UINT32_MAX / state->var.scale < *value) { 1429 SPROM_OP_BAD(state, "cannot represent %" PRIu32 " * %" PRIu32 1430 "\n", *value, state->var.scale); 1431 return (EINVAL); 1432 } 1433 1434 *value = (*value) * state->var.scale; 1435 return (0); 1436 } 1437 1438 /** 1439 * Read a SPROM_OP_DATA_* value from @p opcodes. 1440 * 1441 * @param state The SPROM opcode state. 1442 * @param type The SROM_OP_DATA_* type to be read. 1443 * @param opval On success, the 32bit data representation. If @p type is signed, 1444 * the value will be appropriately sign extended and may be directly cast to 1445 * int32_t. 1446 * 1447 * @retval 0 success 1448 * @retval non-zero If reading the value otherwise fails, a regular unix error 1449 * code will be returned. 1450 */ 1451 static int 1452 sprom_opcode_read_opval32(struct sprom_opcode_state *state, uint8_t type, 1453 uint32_t *opval) 1454 { 1455 const uint8_t *p; 1456 int error; 1457 1458 p = state->input; 1459 switch (type) { 1460 case SPROM_OP_DATA_I8: 1461 /* Convert to signed value first, then sign extend */ 1462 *opval = (int32_t)(int8_t)(*p); 1463 p += 1; 1464 break; 1465 case SPROM_OP_DATA_U8: 1466 *opval = *p; 1467 p += 1; 1468 break; 1469 case SPROM_OP_DATA_U8_SCALED: 1470 *opval = *p; 1471 1472 if ((error = sprom_opcode_apply_scale(state, opval))) 1473 return (error); 1474 1475 p += 1; 1476 break; 1477 case SPROM_OP_DATA_U16: 1478 *opval = le16dec(p); 1479 p += 2; 1480 break; 1481 case SPROM_OP_DATA_U32: 1482 *opval = le32dec(p); 1483 p += 4; 1484 break; 1485 default: 1486 SPROM_OP_BAD(state, "unsupported data type: %hhu\n", type); 1487 return (EINVAL); 1488 } 1489 1490 /* Update read address */ 1491 state->input = p; 1492 1493 return (0); 1494 } 1495 1496 /** 1497 * Return true if our layout revision is currently defined by the SPROM 1498 * opcode state. 1499 * 1500 * This may be used to test whether the current opcode stream state applies 1501 * to the layout that we are actually parsing. 1502 * 1503 * A given opcode stream may cover multiple layout revisions, switching 1504 * between them prior to defining a set of variables. 1505 */ 1506 static inline bool 1507 sprom_opcode_matches_layout_rev(struct sprom_opcode_state *state) 1508 { 1509 return (bit_test(state->revs, state->layout->rev)); 1510 } 1511 1512 /** 1513 * When evaluating @p state and @p opcode, rewrite @p opcode and the current 1514 * evaluation state, as required. 1515 * 1516 * If @p opcode is rewritten, it should be returned from 1517 * sprom_opcode_step() instead of the opcode parsed from @p state's opcode 1518 * stream. 1519 * 1520 * If @p opcode remains unmodified, then sprom_opcode_step() should proceed 1521 * to standard evaluation. 1522 */ 1523 static int 1524 sprom_opcode_rewrite_opcode(struct sprom_opcode_state *state, uint8_t *opcode) 1525 { 1526 uint8_t op; 1527 int error; 1528 1529 op = SPROM_OPCODE_OP(*opcode); 1530 switch (state->var_state) { 1531 case SPROM_OPCODE_VAR_STATE_NONE: 1532 /* No open variable definition */ 1533 return (0); 1534 1535 case SPROM_OPCODE_VAR_STATE_OPEN: 1536 /* Open variable definition; check for implicit closure. */ 1537 1538 /* 1539 * If a variable definition contains no explicit bind 1540 * instructions prior to closure, we must generate a DO_BIND 1541 * instruction with count and skip values of 1. 1542 */ 1543 if (SPROM_OP_IS_VAR_END(op) && 1544 state->var.bind_total == 0) 1545 { 1546 uint8_t count, skip_in, skip_out; 1547 bool skip_in_negative; 1548 1549 /* Create bind with skip_in/skip_out of 1, count of 1 */ 1550 count = 1; 1551 skip_in = 1; 1552 skip_out = 1; 1553 skip_in_negative = false; 1554 1555 error = sprom_opcode_set_bind(state, count, skip_in, 1556 skip_in_negative, skip_out); 1557 if (error) 1558 return (error); 1559 1560 /* Return DO_BIND */ 1561 *opcode = SPROM_OPCODE_DO_BIND | 1562 (0 << SPROM_OP_BIND_SKIP_IN_SIGN) | 1563 (1 << SPROM_OP_BIND_SKIP_IN_SHIFT) | 1564 (1 << SPROM_OP_BIND_SKIP_OUT_SHIFT); 1565 1566 return (0); 1567 } 1568 1569 /* 1570 * If a variable is implicitly closed (e.g. by a new variable 1571 * definition), we must generate a VAR_END instruction. 1572 */ 1573 if (SPROM_OP_IS_IMPLICIT_VAR_END(op)) { 1574 /* Mark as complete */ 1575 if ((error = sprom_opcode_end_var(state))) 1576 return (error); 1577 1578 /* Return VAR_END */ 1579 *opcode = SPROM_OPCODE_VAR_END; 1580 return (0); 1581 } 1582 break; 1583 1584 1585 case SPROM_OPCODE_VAR_STATE_DONE: 1586 /* Previously completed variable definition. Discard variable 1587 * state */ 1588 return (sprom_opcode_clear_var(state)); 1589 } 1590 1591 /* Nothing to do */ 1592 return (0); 1593 } 1594 1595 /** 1596 * Evaluate one opcode from @p state. 1597 * 1598 * @param state The opcode state to be evaluated. 1599 * @param[out] opcode On success, the evaluated opcode 1600 * 1601 * @retval 0 success 1602 * @retval ENOENT if EOF is reached 1603 * @retval non-zero if evaluation otherwise fails, a regular unix error 1604 * code will be returned. 1605 */ 1606 static int 1607 sprom_opcode_step(struct sprom_opcode_state *state, uint8_t *opcode) 1608 { 1609 int error; 1610 1611 while (*state->input != SPROM_OPCODE_EOF) { 1612 uint32_t val; 1613 uint8_t op, rewrite, immd; 1614 1615 /* Fetch opcode */ 1616 *opcode = *state->input; 1617 op = SPROM_OPCODE_OP(*opcode); 1618 immd = SPROM_OPCODE_IMM(*opcode); 1619 1620 /* Clear any existing bind state */ 1621 if ((error = sprom_opcode_flush_bind(state))) 1622 return (error); 1623 1624 /* Insert local opcode based on current state? */ 1625 rewrite = *opcode; 1626 if ((error = sprom_opcode_rewrite_opcode(state, &rewrite))) 1627 return (error); 1628 1629 if (rewrite != *opcode) { 1630 /* Provide rewritten opcode */ 1631 *opcode = rewrite; 1632 1633 /* We must keep evaluating until we hit a state 1634 * applicable to the SPROM revision we're parsing */ 1635 if (!sprom_opcode_matches_layout_rev(state)) 1636 continue; 1637 1638 return (0); 1639 } 1640 1641 /* Advance input */ 1642 state->input++; 1643 1644 switch (op) { 1645 case SPROM_OPCODE_VAR_IMM: 1646 if ((error = sprom_opcode_set_var(state, immd))) 1647 return (error); 1648 break; 1649 1650 case SPROM_OPCODE_VAR_REL_IMM: 1651 error = sprom_opcode_set_var(state, state->vid + immd); 1652 if (error) 1653 return (error); 1654 break; 1655 1656 case SPROM_OPCODE_VAR: 1657 error = sprom_opcode_read_opval32(state, immd, &val); 1658 if (error) 1659 return (error); 1660 1661 if ((error = sprom_opcode_set_var(state, val))) 1662 return (error); 1663 1664 break; 1665 1666 case SPROM_OPCODE_VAR_END: 1667 if ((error = sprom_opcode_end_var(state))) 1668 return (error); 1669 break; 1670 1671 case SPROM_OPCODE_NELEM: 1672 immd = *state->input; 1673 if ((error = sprom_opcode_set_nelem(state, immd))) 1674 return (error); 1675 1676 state->input++; 1677 break; 1678 1679 case SPROM_OPCODE_DO_BIND: 1680 case SPROM_OPCODE_DO_BINDN: { 1681 uint8_t count, skip_in, skip_out; 1682 bool skip_in_negative; 1683 1684 /* Fetch skip arguments */ 1685 skip_in = (immd & SPROM_OP_BIND_SKIP_IN_MASK) >> 1686 SPROM_OP_BIND_SKIP_IN_SHIFT; 1687 1688 skip_in_negative = 1689 ((immd & SPROM_OP_BIND_SKIP_IN_SIGN) != 0); 1690 1691 skip_out = (immd & SPROM_OP_BIND_SKIP_OUT_MASK) >> 1692 SPROM_OP_BIND_SKIP_OUT_SHIFT; 1693 1694 /* Fetch count argument (if any) */ 1695 if (op == SPROM_OPCODE_DO_BINDN) { 1696 /* Count is provided as trailing U8 */ 1697 count = *state->input; 1698 state->input++; 1699 } else { 1700 count = 1; 1701 } 1702 1703 /* Set BIND state */ 1704 error = sprom_opcode_set_bind(state, count, skip_in, 1705 skip_in_negative, skip_out); 1706 if (error) 1707 return (error); 1708 1709 break; 1710 } 1711 case SPROM_OPCODE_DO_BINDN_IMM: { 1712 uint8_t count, skip_in, skip_out; 1713 bool skip_in_negative; 1714 1715 /* Implicit skip_in/skip_out of 1, count encoded as immd 1716 * value */ 1717 count = immd; 1718 skip_in = 1; 1719 skip_out = 1; 1720 skip_in_negative = false; 1721 1722 error = sprom_opcode_set_bind(state, count, skip_in, 1723 skip_in_negative, skip_out); 1724 if (error) 1725 return (error); 1726 break; 1727 } 1728 1729 case SPROM_OPCODE_REV_IMM: 1730 if ((error = sprom_opcode_set_revs(state, immd, immd))) 1731 return (error); 1732 break; 1733 1734 case SPROM_OPCODE_REV_RANGE: { 1735 uint8_t range; 1736 uint8_t rstart, rend; 1737 1738 /* Revision range is encoded in next byte, as 1739 * { uint8_t start:4, uint8_t end:4 } */ 1740 range = *state->input; 1741 rstart = (range & SPROM_OP_REV_START_MASK) >> 1742 SPROM_OP_REV_START_SHIFT; 1743 rend = (range & SPROM_OP_REV_END_MASK) >> 1744 SPROM_OP_REV_END_SHIFT; 1745 1746 /* Update revision bitmask */ 1747 error = sprom_opcode_set_revs(state, rstart, rend); 1748 if (error) 1749 return (error); 1750 1751 /* Advance input */ 1752 state->input++; 1753 break; 1754 } 1755 case SPROM_OPCODE_MASK_IMM: 1756 if ((error = sprom_opcode_set_mask(state, immd))) 1757 return (error); 1758 break; 1759 1760 case SPROM_OPCODE_MASK: 1761 error = sprom_opcode_read_opval32(state, immd, &val); 1762 if (error) 1763 return (error); 1764 1765 if ((error = sprom_opcode_set_mask(state, val))) 1766 return (error); 1767 break; 1768 1769 case SPROM_OPCODE_SHIFT_IMM: 1770 if ((error = sprom_opcode_set_shift(state, immd * 2))) 1771 return (error); 1772 break; 1773 1774 case SPROM_OPCODE_SHIFT: { 1775 int8_t shift; 1776 1777 if (immd == SPROM_OP_DATA_I8) { 1778 shift = (int8_t)(*state->input); 1779 } else if (immd == SPROM_OP_DATA_U8) { 1780 val = *state->input; 1781 if (val > INT8_MAX) { 1782 SPROM_OP_BAD(state, "invalid shift " 1783 "value: %#x\n", val); 1784 } 1785 1786 shift = val; 1787 } else { 1788 SPROM_OP_BAD(state, "unsupported shift data " 1789 "type: %#hhx\n", immd); 1790 return (EINVAL); 1791 } 1792 1793 if ((error = sprom_opcode_set_shift(state, shift))) 1794 return (error); 1795 1796 state->input++; 1797 break; 1798 } 1799 case SPROM_OPCODE_OFFSET_REL_IMM: 1800 /* Fetch unscaled relative offset */ 1801 val = immd; 1802 1803 /* Apply scale */ 1804 if ((error = sprom_opcode_apply_scale(state, &val))) 1805 return (error); 1806 1807 /* Adding val must not overflow our offset */ 1808 if (UINT32_MAX - state->offset < val) { 1809 BHND_NV_LOG("offset out of range\n"); 1810 return (EINVAL); 1811 } 1812 1813 /* Adjust offset */ 1814 state->offset += val; 1815 break; 1816 case SPROM_OPCODE_OFFSET: 1817 error = sprom_opcode_read_opval32(state, immd, &val); 1818 if (error) 1819 return (error); 1820 1821 state->offset = val; 1822 break; 1823 1824 case SPROM_OPCODE_TYPE: 1825 /* Type follows as U8 */ 1826 immd = *state->input; 1827 state->input++; 1828 1829 /* fall through */ 1830 case SPROM_OPCODE_TYPE_IMM: 1831 switch (immd) { 1832 case BHND_NVRAM_TYPE_UINT8: 1833 case BHND_NVRAM_TYPE_UINT16: 1834 case BHND_NVRAM_TYPE_UINT32: 1835 case BHND_NVRAM_TYPE_UINT64: 1836 case BHND_NVRAM_TYPE_INT8: 1837 case BHND_NVRAM_TYPE_INT16: 1838 case BHND_NVRAM_TYPE_INT32: 1839 case BHND_NVRAM_TYPE_INT64: 1840 case BHND_NVRAM_TYPE_CHAR: 1841 case BHND_NVRAM_TYPE_STRING: 1842 error = sprom_opcode_set_type(state, 1843 (bhnd_nvram_type)immd); 1844 if (error) 1845 return (error); 1846 break; 1847 default: 1848 BHND_NV_LOG("unrecognized type %#hhx\n", immd); 1849 return (EINVAL); 1850 } 1851 break; 1852 1853 default: 1854 BHND_NV_LOG("unrecognized opcode %#hhx\n", *opcode); 1855 return (EINVAL); 1856 } 1857 1858 /* We must keep evaluating until we hit a state applicable to 1859 * the SPROM revision we're parsing */ 1860 if (sprom_opcode_matches_layout_rev(state)) 1861 return (0); 1862 } 1863 1864 /* End of opcode stream */ 1865 return (ENOENT); 1866 } 1867 1868 /** 1869 * Reset SPROM opcode evaluation state, seek to the @p indexed position, 1870 * and perform complete evaluation of the variable's opcodes. 1871 * 1872 * @param state The opcode state to be to be evaluated. 1873 * @param indexed The indexed variable location. 1874 * 1875 * @retval 0 success 1876 * @retval non-zero If evaluation fails, a regular unix error code will be 1877 * returned. 1878 */ 1879 static int 1880 sprom_opcode_parse_var(struct sprom_opcode_state *state, 1881 struct sprom_opcode_idx *indexed) 1882 { 1883 uint8_t opcode; 1884 int error; 1885 1886 /* Seek to entry */ 1887 if ((error = sprom_opcode_state_seek(state, indexed))) 1888 return (error); 1889 1890 /* Parse full variable definition */ 1891 while ((error = sprom_opcode_step(state, &opcode)) == 0) { 1892 /* Iterate until VAR_END */ 1893 if (SPROM_OPCODE_OP(opcode) != SPROM_OPCODE_VAR_END) 1894 continue; 1895 1896 BHND_NV_ASSERT(state->var_state == SPROM_OPCODE_VAR_STATE_DONE, 1897 ("incomplete variable definition")); 1898 1899 return (0); 1900 } 1901 1902 /* Error parsing definition */ 1903 return (error); 1904 } 1905 1906 /** 1907 * Evaluate @p state until the next variable definition is found. 1908 * 1909 * @param state The opcode state to be evaluated. 1910 * 1911 * @retval 0 success 1912 * @retval ENOENT if no additional variable definitions are available. 1913 * @retval non-zero if evaluation otherwise fails, a regular unix error 1914 * code will be returned. 1915 */ 1916 static int 1917 sprom_opcode_next_var(struct sprom_opcode_state *state) 1918 { 1919 uint8_t opcode; 1920 int error; 1921 1922 /* Step until we hit a variable opcode */ 1923 while ((error = sprom_opcode_step(state, &opcode)) == 0) { 1924 switch (SPROM_OPCODE_OP(opcode)) { 1925 case SPROM_OPCODE_VAR: 1926 case SPROM_OPCODE_VAR_IMM: 1927 case SPROM_OPCODE_VAR_REL_IMM: 1928 BHND_NV_ASSERT( 1929 state->var_state == SPROM_OPCODE_VAR_STATE_OPEN, 1930 ("missing variable definition")); 1931 1932 return (0); 1933 default: 1934 continue; 1935 } 1936 } 1937 1938 /* Reached EOF, or evaluation failed */ 1939 return (error); 1940 } 1941 1942 /** 1943 * Evaluate @p state until the next binding for the current variable definition 1944 * is found. 1945 * 1946 * @param state The opcode state to be evaluated. 1947 * 1948 * @retval 0 success 1949 * @retval ENOENT if no additional binding opcodes are found prior to reaching 1950 * a new variable definition, or the end of @p state's binding opcodes. 1951 * @retval non-zero if evaluation otherwise fails, a regular unix error 1952 * code will be returned. 1953 */ 1954 static int 1955 sprom_opcode_next_binding(struct sprom_opcode_state *state) 1956 { 1957 uint8_t opcode; 1958 int error; 1959 1960 if (state->var_state != SPROM_OPCODE_VAR_STATE_OPEN) 1961 return (EINVAL); 1962 1963 /* Step until we hit a bind opcode, or a new variable */ 1964 while ((error = sprom_opcode_step(state, &opcode)) == 0) { 1965 switch (SPROM_OPCODE_OP(opcode)) { 1966 case SPROM_OPCODE_DO_BIND: 1967 case SPROM_OPCODE_DO_BINDN: 1968 case SPROM_OPCODE_DO_BINDN_IMM: 1969 /* Found next bind */ 1970 BHND_NV_ASSERT( 1971 state->var_state == SPROM_OPCODE_VAR_STATE_OPEN, 1972 ("missing variable definition")); 1973 BHND_NV_ASSERT(state->var.have_bind, ("missing bind")); 1974 1975 return (0); 1976 1977 case SPROM_OPCODE_VAR_END: 1978 /* No further binding opcodes */ 1979 BHND_NV_ASSERT( 1980 state->var_state == SPROM_OPCODE_VAR_STATE_DONE, 1981 ("variable definition still available")); 1982 return (ENOENT); 1983 } 1984 } 1985 1986 /* Not found, or evaluation failed */ 1987 return (error); 1988 } 1989