1/* $NetBSD: ieee1212.c,v 1.15 2021/08/07 16:19:16 thorpej Exp $ */ 2 3/* 4 * Copyright (c) 2000 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by James Chacon. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 * POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32#include <sys/cdefs.h> 33__KERNEL_RCSID(0, "$NetBSD: ieee1212.c,v 1.15 2021/08/07 16:19:16 thorpej Exp $"); 34 35#include <sys/param.h> 36#include <sys/systm.h> 37#include <sys/device.h> 38#include <sys/kernel.h> 39#include <sys/malloc.h> 40 41#include <dev/std/ieee1212reg.h> 42#include <dev/std/ieee1212var.h> 43 44static const char * const p1212_keytype_strings[] = P1212_KEYTYPE_STRINGS ; 45static const char * const p1212_keyvalue_strings[] = P1212_KEYVALUE_STRINGS ; 46 47static u_int16_t p1212_calc_crc(u_int32_t, u_int32_t *, int, int); 48static int p1212_parse_directory(struct p1212_dir *, u_int32_t *, u_int32_t); 49static struct p1212_leafdata *p1212_parse_leaf(u_int32_t *); 50static int p1212_parse_textdir(struct p1212_com *, u_int32_t *); 51static struct p1212_textdata *p1212_parse_text_desc(u_int32_t *); 52static void p1212_print_node(struct p1212_key *, void *); 53static int p1212_validate_offset(u_int16_t, u_int32_t); 54static int p1212_validate_immed(u_int16_t, u_int32_t); 55static int p1212_validate_leaf(u_int16_t, u_int32_t); 56static int p1212_validate_dir(u_int16_t, u_int32_t); 57 58#ifdef P1212_DEBUG 59#define DPRINTF(x) if (p1212debug) printf x 60#define DPRINTFN(n,x) if (p1212debug>(n)) printf x 61int p1212debug = 1; 62#else 63#define DPRINTF(x) 64#define DPRINTFN(n,x) 65#endif 66 67/* 68 * Routines to parse the ROM into a tree that's usable. Also verify integrity 69 * vs. the P1212 standard 70 */ 71 72/* 73 * A buffer of u_int32_t's and a size in quads gets passed in. The output will 74 * return -1 on error, or 0 on success and possibly reset *size to a larger 75 * value. 76 * 77 * NOTE: Rom's are guaranteed per the ISO spec to be contiguous but only the 78 * first 1k is directly mapped. Anything past 1k is supposed to use a loop 79 * around the indirect registers to read in the rom. This code only assumes the 80 * buffer passed in represents a total rom regardless of end size. It is the 81 * callers responsibility to treat a size > 1024 as a special case. 82 */ 83 84int 85p1212_iscomplete(u_int32_t *t, u_int32_t *size) 86{ 87 u_int16_t infolen, crclen, len; 88 u_int32_t newlen, offset, test; 89 int complete, i, numdirs, type, val, *dirs; 90 91 dirs = NULL; 92 93 if (*size == 0) { 94 DPRINTF(("Invalid size for ROM: %d\n", (unsigned int)*size)); 95 return -1; 96 } 97 98 infolen = P1212_ROMFMT_GET_INFOLEN((ntohl(t[0]))); 99 if (infolen <= 1) { 100 DPRINTF(("ROM not initialized or minimal ROM: Info " 101 "length: %d\n", infolen)); 102 return -1; 103 } 104 crclen = P1212_ROMFMT_GET_CRCLEN((ntohl(t[0]))); 105 if (crclen < infolen) { 106 DPRINTF(("CRC len less than info len. CRC len: %d, " 107 "Info len: %d\n", crclen, infolen)); 108 return -1; 109 } 110 111 /* 112 * Now loop through it to check if all the offsets referenced are 113 * within the image stored so far. If not, get those as well. 114 */ 115 116 offset = P1212_ROMFMT_GET_INFOLEN((ntohl(t[0]))) + 1; 117 118 /* 119 * Make sure at least the bus info block is in memory + the root dir 120 * header quad. Add 1 here since offset is an array offset and size is 121 * the total array size we want. If this is getting the root dir 122 * then add another since infolen doesn't end on the root dir entry but 123 * right before it. 124 */ 125 126 if ((*size == 1) || (*size < (offset + 1))) { 127 *size = (crclen > infolen) ? crclen : infolen; 128 if (crclen == infolen) 129 (*size)++; 130 (*size)++; 131 return 0; 132 } 133 134 complete = 0; 135 numdirs = 0; 136 newlen = 0; 137 138 while (!complete) { 139 140 /* 141 * Make sure the whole directory is in memory. If not, bail now 142 * and read it in. 143 */ 144 145 newlen = P1212_DIRENT_GET_LEN((ntohl(t[offset]))); 146 if ((offset + newlen + 1) > *size) { 147 newlen += offset + 1; 148 break; 149 } 150 151 if (newlen == 0) { 152 DPRINTF(("Impossible directory length of 0!\n")); 153 return -1; 154 } 155 156 /* 157 * Starting with the first byte of the directory, read through 158 * and check the values found. On offsets and directories read 159 * them in if appropriate (always for offsets, if not in memory 160 * for leaf/directories). 161 */ 162 163 offset++; 164 len = newlen; 165 newlen = 0; 166 for (i = 0; i < len; i++) { 167 type = P1212_DIRENT_GET_KEYTYPE((ntohl(t[offset+i]))); 168 val = P1212_DIRENT_GET_VALUE((ntohl(t[offset+i]))); 169 switch (type) { 170 case P1212_KEYTYPE_Immediate: 171 case P1212_KEYTYPE_Offset: 172 break; 173 case P1212_KEYTYPE_Leaf: 174 175 /* 176 * If a leaf is found, and it's beyond the 177 * current rom length and it's beyond the 178 * current newlen setting, 179 * then set newlen accordingly. 180 */ 181 182 test = offset + i + val + 1; 183 if ((test > *size) && (test > newlen)) { 184 newlen = test; 185 break; 186 } 187 188 /* 189 * For leaf nodes just make sure the whole leaf 190 * length is in the buffer. There's no data 191 * inside of them that can refer to outside 192 * nodes. (Uless it's vendor specific and then 193 * you're on your own anyways). 194 */ 195 196 test--; 197 infolen = 198 P1212_DIRENT_GET_LEN((ntohl(t[test]))); 199 test++; 200 test += infolen; 201 if ((test > *size) && (test > newlen)) { 202 newlen = test; 203 } 204 break; 205 206 case P1212_KEYTYPE_Directory: 207 208 /* Make sure the first quad is in memory. */ 209 210 test = offset + i + val + 1; 211 if ((test > *size) && (test > newlen)) { 212 newlen = test; 213 break; 214 } 215 216 /* 217 * Can't just walk the ROM looking at type 218 * codes since these are only valid on 219 * directory entries. So save any directories 220 * we find into a queue and the bottom of the 221 * while loop will pop the last one off and 222 * walk that directory. 223 */ 224 225 test--; 226 dirs = realloc(dirs, 227 sizeof(int) * (numdirs + 1), M_DEVBUF, 228 M_WAITOK); 229 dirs[numdirs++] = test; 230 break; 231 default: 232 panic("Impossible type code: 0x%04hx", 233 (unsigned short)type); 234 break; 235 } 236 } 237 238 if (newlen) { 239 /* Cleanup. */ 240 if (dirs) 241 free(dirs, M_DEVBUF); 242 break; 243 } 244 if (dirs) { 245 offset = dirs[--numdirs]; 246 dirs = realloc(dirs, sizeof(int) * numdirs, M_DEVBUF, 247 M_WAITOK); 248 } else 249 complete = 1; 250 } 251 252 if (newlen) 253 *size = newlen; 254 return 0; 255 256} 257 258struct p1212_rom * 259p1212_parse(u_int32_t *t, u_int32_t size, u_int32_t mask) 260{ 261 262 u_int16_t crc, romcrc, crc1; 263 u_int32_t next, check; 264 struct p1212_rom *rom; 265 int i; 266 267 check = size; 268 269 if (p1212_iscomplete(t, &check) == -1) { 270 DPRINTF(("ROM is not complete\n")); 271 return NULL; 272 } 273 if (check != size) { 274 DPRINTF(("ROM is not complete (check != size)\n")); 275 return NULL; 276 } 277 278 /* Calculate both a good and known bad crc. */ 279 280 /* CRC's are calculated from everything except the first quad. */ 281 282 crc = p1212_calc_crc(0, &t[1], P1212_ROMFMT_GET_CRCLEN((ntohl(t[0]))), 283 0); 284 285 romcrc = P1212_ROMFMT_GET_CRC((ntohl(t[0]))); 286 if (crc != romcrc) { 287 crc1 = p1212_calc_crc(0, &t[1], 288 P1212_ROMFMT_GET_CRCLEN((ntohl(t[0]))), 1); 289 if (crc1 != romcrc) { 290 DPRINTF(("Invalid ROM: CRC: 0x%04hx, Calculated " 291 "CRC: 0x%04hx, CRC1: 0x%04hx\n", 292 (unsigned short)romcrc, (unsigned short)crc, 293 (unsigned short)crc1)); 294 return NULL; 295 } 296 } 297 298 /* Now, walk the ROM. */ 299 300 /* Get the initial offset for the root dir. */ 301 302 rom = malloc(sizeof(struct p1212_rom), M_DEVBUF, M_WAITOK); 303 rom->len = P1212_ROMFMT_GET_INFOLEN((ntohl(t[0]))); 304 next = rom->len + 1; 305 306 if ((rom->len < 1) || (rom->len > size)) { 307 DPRINTF(("Invalid ROM info length: %d\n", rom->len)); 308 free(rom, M_DEVBUF); 309 return NULL; 310 } 311 312 /* Exclude the quad which covers the bus name. */ 313 rom->len--; 314 315 if (rom->len) { 316 rom->data = malloc(sizeof(u_int32_t) * rom->len, M_DEVBUF, 317 M_WAITOK); 318 /* Add 2 to account for info/crc and bus name skipped. */ 319 for (i = 0; i < rom->len; i++) 320 rom->data[i] = t[i + 2]; 321 } 322 323 /* The name field is always 4 bytes and always the 2nd field. */ 324 strncpy(rom->name, (char *)&t[1], 4); 325 rom->name[4] = 0; 326 327 /* 328 * Fill out the root directory. All these values are hardcoded so the 329 * parse/print/match routines have a standard layout to work against. 330 */ 331 332 rom->root = malloc(sizeof(*rom->root), M_DEVBUF, M_WAITOK|M_ZERO); 333 rom->root->com.key.key_type = P1212_KEYTYPE_Directory; 334 rom->root->com.key.key_value = 0; 335 rom->root->com.key.key = (u_int8_t)P1212_KEYTYPE_Directory; 336 rom->root->com.key.val = 0; 337 TAILQ_INIT(&rom->root->data_root); 338 TAILQ_INIT(&rom->root->subdir_root); 339 340 if (p1212_parse_directory(rom->root, &t[next], mask)) { 341 DPRINTF(("Parse error in ROM. Bailing\n")); 342 p1212_free(rom); 343 return NULL; 344 } 345 return rom; 346} 347 348static int 349p1212_parse_directory(struct p1212_dir *root, u_int32_t *addr, u_int32_t mask) 350{ 351 struct p1212_dir *dir, *sdir; 352 struct p1212_data *data; 353 struct p1212_com *com; 354 u_int32_t *t, desc; 355 u_int16_t crclen, crc, crc1, romcrc; 356 u_int8_t type, val; 357 unsigned long size; 358 int i, module_vendor_flag, module_sw_flag, node_sw_flag, unit_sw_flag; 359 int node_capabilities_flag, offset, unit_location_flag, unitdir_cnt; 360 int leafoff; 361 362 t = addr; 363 dir = root; 364 365 module_vendor_flag = 0; 366 module_sw_flag = 0; 367 node_sw_flag = 0; 368 node_capabilities_flag = 0; 369 unitdir_cnt = 0; 370 offset = 0; 371 372 while (dir) { 373 dir->match = 0; 374 crclen = P1212_DIRENT_GET_LEN((ntohl(t[offset]))); 375 romcrc = P1212_DIRENT_GET_CRC((ntohl(t[offset]))); 376 377 crc = p1212_calc_crc(0, &t[offset + 1], crclen, 0); 378 if (crc != romcrc) { 379 crc1 = p1212_calc_crc(0, &t[offset + 1], crclen, 1); 380 if (crc1 != romcrc) { 381 DPRINTF(("Invalid ROM: CRC: 0x%04hx, " 382 "Calculated CRC: " 383 "0x%04hx, CRC1: 0x%04hx\n", 384 (unsigned short)romcrc, 385 (unsigned short)crc, 386 (unsigned short)crc1)); 387 return 1; 388 } 389 } 390 com = NULL; 391 unit_sw_flag = 0; 392 unit_location_flag = 0; 393 offset++; 394 395 if ((dir->parent == NULL) && dir->com.key.val) { 396 DPRINTF(("Invalid root dir. key.val is 0x%0x and not" 397 " 0x0\n", dir->com.key.val)); 398 return 1; 399 } 400 401 for (i = offset; i < (offset + crclen); i++) { 402 desc = ntohl(t[i]); 403 type = P1212_DIRENT_GET_KEYTYPE(desc); 404 val = P1212_DIRENT_GET_KEYVALUE(desc); 405 406 /* 407 * Sanity check for valid types/locations/etc. 408 * 409 * See pages 79-100 of 410 * ISO/IEC 13213:1194(ANSI/IEEE Std 1212, 1994 edition) 411 * for specifics. 412 * 413 * XXX: These all really should be broken out into 414 * subroutines as it's grown large and complicated 415 * in certain cases. 416 */ 417 418 switch (val) { 419 case P1212_KEYVALUE_Unit_Spec_Id: 420 case P1212_KEYVALUE_Unit_Sw_Version: 421 case P1212_KEYVALUE_Unit_Dependent_Info: 422 case P1212_KEYVALUE_Unit_Location: 423 case P1212_KEYVALUE_Unit_Poll_Mask: 424 if (dir->parent == NULL) { 425 DPRINTF(("Invalid ROM: %s is not " 426 "valid in the root directory.\n", 427 p1212_keyvalue_strings[val])); 428 return 1; 429 } 430 break; 431 default: 432 if (dir->com.key.val == 433 P1212_KEYVALUE_Unit_Directory) { 434 DPRINTF(("Invalid ROM: %s is " 435 "not valid in a unit directory.\n", 436 p1212_keyvalue_strings[val])); 437 return 1; 438 } 439 break; 440 } 441 442 switch (type) { 443 case P1212_KEYTYPE_Immediate: 444 if (p1212_validate_immed(val, mask)) { 445 DPRINTF(("Invalid ROM: Can't have an " 446 "immediate type with %s value. Key" 447 " used at location 0x%0x in ROM\n", 448 p1212_keyvalue_strings[val], 449 (unsigned int)(&t[i]-&addr[0]))); 450 return 1; 451 } 452 break; 453 case P1212_KEYTYPE_Offset: 454 if (p1212_validate_offset(val, mask)) { 455 DPRINTF(("Invalid ROM: Can't have " 456 "an offset type with key %s." 457 " Used at location 0x%0x in ROM\n", 458 p1212_keyvalue_strings[val], 459 (unsigned int)(&t[i]-&addr[0]))); 460 return 1; 461 } 462 break; 463 case P1212_KEYTYPE_Leaf: 464 if (p1212_validate_leaf(val, mask)) { 465 DPRINTF(("Invalid ROM: Can't have a " 466 "leaf type with %s value. Key " 467 "used at location 0x%0x in ROM\n", 468 p1212_keyvalue_strings[val], 469 (unsigned int)(&t[i]-&addr[0]))); 470 return 1; 471 } 472 break; 473 case P1212_KEYTYPE_Directory: 474 if (p1212_validate_dir(val, mask)) { 475 DPRINTF(("Invalid ROM: Can't have a " 476 "directory type with %s value. Key" 477 " used at location 0x%0x in ROM\n", 478 p1212_keyvalue_strings[val], 479 (unsigned int)(&t[i]-&addr[0]))); 480 return 1; 481 } 482 break; 483 default: 484 panic("Impossible type code: 0x%04hx", 485 (unsigned short)type); 486 break; 487 } 488 489 /* Note flags for required fields. */ 490 491 if (val == P1212_KEYVALUE_Module_Vendor_Id) { 492 module_vendor_flag = 1; 493 } 494 495 if (val == P1212_KEYVALUE_Node_Capabilities) { 496 node_capabilities_flag = 1; 497 } 498 499 if (val == P1212_KEYVALUE_Unit_Sw_Version) 500 unit_sw_flag = 1; 501 502 if (val == P1212_KEYVALUE_Unit_Location) 503 unit_location_flag = 1; 504 505 /* 506 * This is just easier to spell out. You can't have 507 * a module sw version if you include a node sw version 508 * and vice-versa. Both aren't allowed if you have unit 509 * dirs. 510 */ 511 512 if (val == P1212_KEYVALUE_Module_Sw_Version) { 513 if (node_sw_flag) { 514 DPRINTF(("Can't have a module software" 515 " version along with a node " 516 "software version entry\n")); 517 return 1; 518 } 519 if (unitdir_cnt) { 520 DPRINTF(("Can't have unit directories " 521 "with module software version " 522 "defined.\n")); 523 return 1; 524 } 525 module_sw_flag = 1; 526 } 527 528 if (val == P1212_KEYVALUE_Node_Sw_Version) { 529 if (module_sw_flag) { 530 DPRINTF(("Can't have a node software " 531 "version along with a module " 532 "software version entry\n")); 533 return 1; 534 } 535 if (unitdir_cnt) { 536 DPRINTF(("Can't have unit directories " 537 "with node software version " 538 "defined.\n")); 539 return 1; 540 } 541 node_sw_flag = 1; 542 } 543 544 if (val == P1212_KEYVALUE_Unit_Directory) { 545 if (module_sw_flag || node_sw_flag) { 546 DPRINTF(("Can't have unit directories " 547 "with either module or node " 548 "software version defined.\n")); 549 return 1; 550 } 551 unitdir_cnt++; 552 } 553 554 /* 555 * Text descriptors are special. They describe the 556 * last entry they follow. So they need to be included 557 * with its struct and there's nothing in the spec 558 * preventing one from putting text descriptors after 559 * directory descriptors. Also they can be a single 560 * value or a list of them in a directory format so 561 * account for either. Finally if they're in a 562 * directory those can be the only types in a 563 * directory. 564 */ 565 566 if (val == P1212_KEYVALUE_Textual_Descriptor) { 567 568 size = sizeof(struct p1212_textdata *); 569 leafoff = P1212_DIRENT_GET_VALUE(desc); 570 leafoff += i; 571 572 if (com == NULL) { 573 DPRINTF(("Can't have a text descriptor" 574 " as the first entry in a " 575 "directory\n")); 576 return 1; 577 } 578 579 if (com->textcnt != 0) { 580 DPRINTF(("Text descriptors can't " 581 "follow each other in a " 582 "directory\n")); 583 return 1; 584 } 585 586 if (type == P1212_KEYTYPE_Leaf) { 587 com->text = 588 malloc(size, M_DEVBUF, M_WAITOK); 589 com->text[0] = 590 p1212_parse_text_desc(&t[leafoff]); 591 if (com->text[0] == NULL) { 592 DPRINTF(("Got an error parsing" 593 " text descriptor at " 594 "offset 0x%0x\n", 595 &t[leafoff]-&addr[0])); 596 free(com->text, M_DEVBUF); 597 return 1; 598 } 599 com->textcnt = 1; 600 } else { 601 i = p1212_parse_textdir(com, 602 &t[leafoff]); 603 if (i) 604 return 1; 605 } 606 } 607 608 if ((type != P1212_KEYTYPE_Directory) && 609 (val != P1212_KEYVALUE_Textual_Descriptor)) { 610 data = malloc(sizeof(struct p1212_data), 611 M_DEVBUF, M_WAITOK|M_ZERO); 612 data->com.key.key_type = type; 613 data->com.key.key_value = val; 614 data->com.key.key = 615 P1212_DIRENT_GET_KEY((ntohl(t[i]))); 616 data->com.key.val = 617 P1212_DIRENT_GET_VALUE((ntohl(t[i]))); 618 com = &data->com; 619 620 /* 621 * Don't try and read the offset. It may be 622 * a register or something special. Generally 623 * these are node specific so let the upper 624 * level code figure it out. 625 */ 626 627 if ((type == P1212_KEYTYPE_Immediate) || 628 (type == P1212_KEYTYPE_Offset)) 629 data->val = data->com.key.val; 630 631 data->leafdata = NULL; 632 TAILQ_INSERT_TAIL(&dir->data_root, data, data); 633 634 if (type == P1212_KEYTYPE_Leaf) { 635 leafoff = i + data->com.key.val; 636 data->leafdata = 637 p1212_parse_leaf(&t[leafoff]); 638 if (data->leafdata == NULL) { 639 DPRINTF(("Error parsing leaf\n")); 640 return 1; 641 } 642 } 643 } 644 if (type == P1212_KEYTYPE_Directory) { 645 646 sdir = malloc(sizeof(struct p1212_dir), 647 M_DEVBUF, M_WAITOK|M_ZERO); 648 sdir->parent = dir; 649 sdir->com.key.key_type = type; 650 sdir->com.key.key_value = val; 651 sdir->com.key.key = 652 P1212_DIRENT_GET_KEY((ntohl(t[i]))); 653 sdir->com.key.val = 654 P1212_DIRENT_GET_VALUE((ntohl(t[i]))); 655 com = &sdir->com; 656 sdir->match = sdir->com.key.val + i; 657 TAILQ_INIT(&sdir->data_root); 658 TAILQ_INIT(&sdir->subdir_root); 659 TAILQ_INSERT_TAIL(&dir->subdir_root, sdir,dir); 660 } 661 } 662 663 /* More validity checks. */ 664 665 if (dir->parent == NULL) { 666 if (module_vendor_flag == 0) { 667 DPRINTF(("Missing module vendor entry in root " 668 "directory.\n")); 669 return 1; 670 } 671 if (node_capabilities_flag == 0) { 672 DPRINTF(("Missing node capabilities entry in " 673 "root directory.\n")); 674 return 1; 675 } 676 } else { 677 if ((unitdir_cnt > 1) && (unit_location_flag == 0)) { 678 DPRINTF(("Must have a unit location in each " 679 "unit directory when more than one unit " 680 "directory exists.\n")); 681 return 1; 682 } 683 } 684 685 /* 686 * Ok, done with this directory and it's sanity checked. Now 687 * loop through and either find an unparsed subdir or one 688 * farther back up the chain. 689 */ 690 691 if (!TAILQ_EMPTY(&dir->subdir_root)) { 692 sdir = TAILQ_FIRST(&dir->subdir_root); 693 } else { 694 do { 695 sdir = TAILQ_NEXT(dir, dir); 696 if (sdir == NULL) { 697 dir = dir->parent; 698 } 699 } while ((sdir == NULL) && (dir != NULL)); 700 } 701 if (dir) { 702 dir = sdir; 703 if (!dir->match) { 704 DPRINTF(("Invalid subdir..Has no offset\n")); 705 return 1; 706 } 707 offset = dir->match; 708 } 709 } 710 return 0; 711} 712 713static struct p1212_leafdata * 714p1212_parse_leaf(u_int32_t *t) 715{ 716 u_int16_t crclen, crc, crc1, romcrc; 717 struct p1212_leafdata *leafdata; 718 int i; 719 720 crclen = P1212_DIRENT_GET_LEN((ntohl(t[0]))); 721 romcrc = P1212_DIRENT_GET_CRC((ntohl(t[0]))); 722 crc = p1212_calc_crc(0, &t[1], crclen, 0); 723 crc1 = p1212_calc_crc(0,&t[1], crclen, 1); 724 if ((crc != romcrc) && (crc1 != romcrc)) { 725 DPRINTF(("Invalid ROM: CRC: 0x%04hx, Calculated CRC: " 726 "0x%04hx, CRC1: 0x%04hx\n", (unsigned short)romcrc, 727 (unsigned short)crc, (unsigned short)crc1)); 728 return NULL; 729 } 730 t++; 731 732 /* 733 * Most of these are vendor specific so don't bother trying to map them 734 * out. Anything which needs them later on can extract them. 735 */ 736 737 leafdata = malloc(sizeof(struct p1212_leafdata), M_DEVBUF, M_WAITOK); 738 leafdata->data = malloc((sizeof(u_int32_t) * crclen), M_DEVBUF, 739 M_WAITOK); 740 leafdata->len = crclen; 741 for (i = 0; i < crclen; i++) 742 leafdata->data[i] = ntohl(t[i]); 743 return leafdata; 744} 745 746static int 747p1212_parse_textdir(struct p1212_com *com, u_int32_t *addr) 748{ 749 u_int32_t *t, entry, new; 750 u_int16_t crclen, crc, crc1, romcrc; 751 u_int8_t type, val; 752 int i, size; 753 754 /* 755 * A bit more complicated. A directory for a text descriptor can 756 * contain text descriptor leaf nodes only. 757 */ 758 759 com->text = NULL; 760 size = sizeof(struct p1212_text *); 761 t = addr; 762 763 crclen = P1212_DIRENT_GET_LEN((ntohl(t[0]))); 764 romcrc = P1212_DIRENT_GET_CRC((ntohl(t[0]))); 765 crc = p1212_calc_crc(0, &t[1], crclen, 0); 766 crc1 = p1212_calc_crc(0,&t[1], crclen, 1); 767 if ((crc != romcrc) && (crc1 != romcrc)) { 768 DPRINTF(("Invalid ROM: CRC: 0x%04hx, Calculated CRC: " 769 "0x%04hx, CRC1: 0x%04hx\n", (unsigned short)romcrc, 770 (unsigned short)crc, (unsigned short)crc1)); 771 return 1; 772 } 773 t++; 774 for (i = 0; i < crclen; i++) { 775 entry = ntohl(t[i]); 776 777 type = P1212_DIRENT_GET_KEYTYPE(entry); 778 val = P1212_DIRENT_GET_KEYVALUE(entry); 779 if ((type != P1212_KEYTYPE_Leaf) || 780 (val != P1212_KEYVALUE_Textual_Descriptor)) { 781 DPRINTF(("Text descriptor directories can only " 782 "contain text descriptors. Type: %s, value: %s " 783 "isn't valid at offset 0x%0x\n", 784 p1212_keytype_strings[type], 785 p1212_keyvalue_strings[val], &t[i]-&addr[0])); 786 return 1; 787 } 788 789 new = P1212_DIRENT_GET_VALUE(entry); 790 com->text = realloc(com->text, size * (com->textcnt + 1), 791 M_DEVBUF, M_WAITOK); 792 if ((com->text[i] = p1212_parse_text_desc(&t[i+new])) == NULL) { 793 DPRINTF(("Got an error parsing text descriptor.\n")); 794 if (com->textcnt == 0) 795 free(com->text, M_DEVBUF); 796 return 1; 797 } 798 com->textcnt++; 799 } 800 return 0; 801} 802 803static struct p1212_textdata * 804p1212_parse_text_desc(u_int32_t *addr) 805{ 806 u_int32_t *t; 807 u_int16_t crclen, crc, crc1, romcrc; 808 struct p1212_textdata *text; 809 int size; 810 811 t = addr; 812 813 crclen = P1212_DIRENT_GET_LEN((ntohl(t[0]))); 814 romcrc = P1212_DIRENT_GET_CRC((ntohl(t[0]))); 815 816 if (crclen < P1212_TEXT_Min_Leaf_Length) { 817 DPRINTF(("Invalid ROM: text descriptor too short\n")); 818 return NULL; 819 } 820 821 crc = p1212_calc_crc(0, &t[1], crclen, 0); 822 if (crc != romcrc) { 823 crc1 = p1212_calc_crc(0, &t[1], crclen, 1); 824 if (crc1 != romcrc) { 825 DPRINTF(("Invalid ROM: CRC: 0x%04hx, Calculated CRC: " 826 "0x%04hx, CRC1: 0x%04hx\n", (unsigned short)romcrc, 827 (unsigned short)crc, (unsigned short)crc1)); 828 return NULL; 829 } 830 } 831 832 t++; 833 text = malloc(sizeof(struct p1212_textdata), M_DEVBUF, M_WAITOK); 834 text->spec_type = P1212_TEXT_GET_Spec_Type((ntohl(t[0]))); 835 text->spec_id = P1212_TEXT_GET_Spec_Id((ntohl(t[0]))); 836 text->lang_id = ntohl(t[1]); 837 838 t++; 839 t++; 840 crclen -= 2; 841 size = (crclen * sizeof(u_int32_t)); 842 843 text->text = malloc(size + 1, M_DEVBUF, M_WAITOK|M_ZERO); 844 845 memcpy(text->text, &t[0], size); 846 847 return text; 848} 849 850struct p1212_key ** 851p1212_find(struct p1212_dir *root, int type, int value, int flags) 852{ 853 struct p1212_key **retkeys; 854 struct p1212_dir *dir, *sdir, *parent; 855 struct p1212_data *data; 856 int numkeys; 857 858 numkeys = 0; 859 retkeys = NULL; 860 861 if ((type < P1212_KEYTYPE_Immediate) || 862 (type > P1212_KEYTYPE_Directory)) { 863#ifdef DIAGNOSTIC 864 printf("p1212_find: invalid type - %d\n", type); 865#endif 866 return NULL; 867 } 868 869 if ((value < -1) || 870 (value > (sizeof(p1212_keyvalue_strings) / sizeof(char *)))) { 871#ifdef DIAGNOSTIC 872 printf("p1212_find: invalid value - %d\n", value); 873#endif 874 return NULL; 875 } 876 877 if (flags & ~(P1212_FIND_SEARCHALL | P1212_FIND_RETURNALL)) { 878#ifdef DIAGNOSTIC 879 printf("p1212_find: invalid flags - %d\n", flags); 880#endif 881 return NULL; 882 } 883 884 /* 885 * Part of this is copied from p1212_walk to do depth first traversal 886 * without using recursion. Using the walk API would have made things 887 * more complicated in trying to build up the return struct otherwise. 888 */ 889 890 dir = root; 891 sdir = NULL; 892 893 parent = root->parent; 894 root->parent = NULL; 895 896 while (dir) { 897 if (type == P1212_KEYTYPE_Directory) { 898 TAILQ_FOREACH(sdir, &dir->subdir_root, dir) { 899 if ((sdir->com.key.key_value == value) || 900 (value == -1)) { 901 numkeys++; 902 retkeys = realloc(retkeys, 903 sizeof(struct p1212_key *) * 904 (numkeys + 1), M_DEVBUF, M_WAITOK); 905 retkeys[numkeys - 1] = &sdir->com.key; 906 retkeys[numkeys] = NULL; 907 if ((flags & P1212_FIND_RETURNALL) 908 == 0) { 909 root->parent = parent; 910 return retkeys; 911 } 912 } 913 } 914 } else { 915 TAILQ_FOREACH(data, &dir->data_root, data) { 916 if (((data->com.key.key_type == type) && 917 (data->com.key.key_value == value)) || 918 ((data->com.key.key_type == type) && 919 (value == -1))) { 920 numkeys++; 921 retkeys = realloc(retkeys, 922 sizeof(struct p1212_key *) * 923 (numkeys + 1), M_DEVBUF, M_WAITOK); 924 retkeys[numkeys - 1] = &data->com.key; 925 retkeys[numkeys] = NULL; 926 if ((flags & P1212_FIND_RETURNALL) 927 == 0) { 928 root->parent = parent; 929 return retkeys; 930 } 931 } 932 } 933 } 934 if (flags & P1212_FIND_SEARCHALL) { 935 do { 936 sdir = TAILQ_NEXT(dir, dir); 937 if (sdir == NULL) { 938 dir = dir->parent; 939 } 940 } while ((sdir == NULL) && (dir != NULL)); 941 dir = sdir; 942 } else 943 dir = NULL; 944 } 945 root->parent = parent; 946 return retkeys; 947} 948 949void 950p1212_walk(struct p1212_dir *root, void *arg, 951 void (*func)(struct p1212_key *, void *)) 952{ 953 struct p1212_data *data; 954 struct p1212_dir *sdir, *dir, *parent; 955 956 dir = root; 957 sdir = NULL; 958 959 if (func == NULL) { 960#ifdef DIAGNOSTIC 961 printf("p1212_walk: Passed in NULL function\n"); 962#endif 963 return; 964 } 965 if (root == NULL) { 966#ifdef DIAGNOSTIC 967 printf("p1212_walk: Called with NULL root\n"); 968#endif 969 return; 970 } 971 972 /* Allow walking from any point. Just mark the starting point. */ 973 parent = root->parent; 974 root->parent = NULL; 975 976 /* 977 * Depth first traversal that doesn't use recursion. 978 * 979 * Call the function first for the directory node and then loop through 980 * all the data nodes and call the function for them. 981 * 982 * Finally, figure out the next possible directory node if one is 983 * available or bail out. 984 */ 985 986 while (dir) { 987 func((struct p1212_key *) dir, arg); 988 TAILQ_FOREACH(data, &dir->data_root, data) 989 func((struct p1212_key *) data, arg); 990 if (!TAILQ_EMPTY(&dir->subdir_root)) { 991 sdir = TAILQ_FIRST(&dir->subdir_root); 992 } else { 993 do { 994 sdir = TAILQ_NEXT(dir, dir); 995 if (sdir == NULL) { 996 dir = dir->parent; 997 } 998 } while ((sdir == NULL) && dir); 999 } 1000 dir = sdir; 1001 } 1002 1003 root->parent = parent; 1004} 1005 1006void 1007p1212_print(struct p1212_dir *dir) 1008{ 1009 int indent; 1010 1011 indent = 0; 1012 1013 p1212_walk(dir, &indent, p1212_print_node); 1014 printf("\n"); 1015} 1016 1017static void 1018p1212_print_node(struct p1212_key *key, void *arg) 1019{ 1020 1021 struct p1212_data *data; 1022 struct p1212_dir *sdir, *dir; 1023 int i, j, *indent; 1024 1025 indent = arg; 1026 1027 if (key->key_type == P1212_KEYTYPE_Directory) { 1028 dir = (struct p1212_dir *) key; 1029 data = NULL; 1030 } else { 1031 data = (struct p1212_data *) key; 1032 dir = NULL; 1033 } 1034 1035 /* Recompute the indent level on each directory. */ 1036 if (dir) { 1037 *indent = 0; 1038 sdir = dir->parent; 1039 while (sdir != NULL) { 1040 (*indent)++; 1041 sdir = sdir->parent; 1042 } 1043 } 1044 1045 if (dir && dir->parent) 1046 printf("\n"); 1047 1048 /* Set the indent string up. 4 spaces per level. */ 1049 for (i = 0; i < (*indent * 4); i++) 1050 printf(" "); 1051 1052 if (dir) { 1053 printf("Directory: "); 1054 if (dir->print) 1055 dir->print(dir); 1056 else { 1057 if (key->key_value >= 1058 (sizeof(p1212_keyvalue_strings) / sizeof(char *))) 1059 printf("Unknown type 0x%04hx\n", 1060 (unsigned short)key->key_value); 1061 else 1062 printf("%s\n", 1063 p1212_keyvalue_strings[key->key_value]); 1064 } 1065 if (dir->com.textcnt) { 1066 for (i = 0; i < dir->com.textcnt; i++) { 1067 for (j = 0; j < (*indent * 4); j++) 1068 printf(" "); 1069 printf("Text descriptor: %s\n", 1070 dir->com.text[i]->text); 1071 } 1072 } 1073 printf("\n"); 1074 } else { 1075 if (data->print) 1076 data->print(data); 1077 else { 1078 if (key->key_value >= 1079 (sizeof(p1212_keyvalue_strings) / sizeof(char *))) 1080 printf("Unknown type 0x%04hx: ", 1081 (unsigned short)key->key_value); 1082 else 1083 printf("%s: ", 1084 p1212_keyvalue_strings[key->key_value]); 1085 1086 printf("0x%08x\n", key->val); 1087#ifdef DIAGNOSTIC 1088 if ((data->com.key.key_type == P1212_KEYTYPE_Leaf) && 1089 (data->leafdata == NULL)) 1090 panic("Invalid data node in configrom tree"); 1091#endif 1092 1093 if (data->leafdata) { 1094 for (i = 0; i < data->leafdata->len; i++) { 1095 for (j = 0; j < (*indent * 4); j++) 1096 printf(" "); 1097 printf ("Leaf data: 0x%08x\n", 1098 data->leafdata->data[i]); 1099 } 1100 } 1101 if (data->com.textcnt) 1102 for (i = 0; i < data->com.textcnt; i++) { 1103 for (j = 0; j < (*indent * 4); j++) 1104 printf(" "); 1105 printf("Text descriptor: %s\n", 1106 data->com.text[i]->text); 1107 } 1108 1109 } 1110 } 1111} 1112 1113 1114void 1115p1212_free(struct p1212_rom *rom) 1116{ 1117 struct p1212_dir *sdir, *dir; 1118 struct p1212_data *data; 1119 int i; 1120 1121 dir = rom->root; 1122 1123 /* Avoid recursing. Find the bottom most node and work back. */ 1124 while (dir) { 1125 if (!TAILQ_EMPTY(&dir->subdir_root)) { 1126 sdir = TAILQ_FIRST(&dir->subdir_root); 1127 if (TAILQ_EMPTY(&sdir->subdir_root)) { 1128 TAILQ_REMOVE(&dir->subdir_root, sdir, dir); 1129 dir = sdir; 1130 } 1131 else { 1132 dir = sdir; 1133 continue; 1134 } 1135 } else { 1136 if (dir->parent) 1137 TAILQ_REMOVE(&dir->parent->subdir_root, dir, 1138 dir); 1139 } 1140 1141 while ((data = TAILQ_FIRST(&dir->data_root))) { 1142 if (data->leafdata) { 1143 if (data->leafdata->data) 1144 free(data->leafdata->data, M_DEVBUF); 1145 free(data->leafdata, M_DEVBUF); 1146 } 1147 TAILQ_REMOVE(&dir->data_root, data, data); 1148 if (data->com.textcnt) { 1149 for (i = 0; i < data->com.textcnt; i++) 1150 free(data->com.text[i], M_DEVBUF); 1151 free(data->com.text, M_DEVBUF); 1152 } 1153 free(data, M_DEVBUF); 1154 } 1155 sdir = dir; 1156 if (dir->parent) 1157 dir = dir->parent; 1158 else 1159 dir = NULL; 1160 if (sdir->com.textcnt) { 1161 for (i = 0; i < sdir->com.textcnt; i++) 1162 free(sdir->com.text[i], M_DEVBUF); 1163 free(sdir->com.text, M_DEVBUF); 1164 } 1165 free(sdir, M_DEVBUF); 1166 } 1167 if (rom->len) 1168 free(rom->data, M_DEVBUF); 1169 free(rom, M_DEVBUF); 1170} 1171 1172/* 1173 * A fairly well published reference implementation of the CRC routine had 1174 * a typo in it and some devices may be using it rather than the correct one 1175 * in calculating their ROM CRC's. To compensate an interface for generating 1176 * either is provided. 1177 * 1178 * len is the number of u_int32_t entries, not bytes. 1179 */ 1180 1181static u_int16_t 1182p1212_calc_crc(u_int32_t crc, u_int32_t *data, int len, int broke) 1183{ 1184 int shift; 1185 u_int32_t sum; 1186 int i; 1187 1188 for (i = 0; i < len; i++) { 1189 for (shift = 28; shift > 0; shift -= 4) { 1190 sum = ((crc >> 12) ^ (ntohl(data[i]) >> shift)) & 1191 0x0000000f; 1192 crc = (crc << 4) ^ (sum << 12) ^ (sum << 5) ^ sum; 1193 } 1194 1195 1196 /* The broken implementation doesn't do the last shift. */ 1197 if (!broke) { 1198 sum = ((crc >> 12) ^ ntohl(data[i])) & 0x0000000f; 1199 crc = (crc << 4) ^ (sum << 12) ^ (sum << 5) ^ sum; 1200 } 1201 } 1202 return (u_int16_t)crc; 1203} 1204 1205/* 1206 * This is almost identical to the standard autoconf *match idea except it 1207 * can match and attach multiple children in one pass. 1208 */ 1209 1210device_t * 1211p1212_match_units(device_t sc, struct p1212_dir *dir, 1212 int (*print)(void *, const char *)) 1213{ 1214 struct p1212_dir **udirs; 1215 device_t *devret, *dev; 1216 int numdev; 1217 1218 /* 1219 * Setup typical return val. Always allocate one extra pointer for a 1220 * NULL guard end pointer. 1221 */ 1222 1223 numdev = 0; 1224 devret = malloc(sizeof(device_t) * 2, M_DEVBUF, M_WAITOK); 1225 devret[1] = NULL; 1226 1227 udirs = (struct p1212_dir **)p1212_find(dir, P1212_KEYTYPE_Directory, 1228 P1212_KEYVALUE_Unit_Directory, 1229 P1212_FIND_SEARCHALL|P1212_FIND_RETURNALL); 1230 1231 if (udirs) { 1232 do { 1233 dev = config_found(sc, udirs, print, 1234 CFARGS(.iattr = "fwnode")); 1235 if (dev && numdev) { 1236 devret = realloc(devret, 1237 sizeof(device_t) * 1238 (numdev + 2), M_DEVBUF, M_WAITOK); 1239 devret[numdev++] = dev; 1240 devret[numdev] = NULL; 1241 } else if (dev) { 1242 devret[0] = dev; 1243 numdev++; 1244 } 1245 udirs++; 1246 } while (*udirs); 1247 } 1248 if (numdev == 0) { 1249 free(devret, M_DEVBUF); 1250 return NULL; 1251 } 1252 return devret; 1253} 1254 1255/* 1256 * Make these their own functions as they have slightly complicated rules. 1257 * 1258 * For example: 1259 * 1260 * Under normal circumstances only the 2 extent types can be offset 1261 * types. However some spec's which use p1212 like SBP2 for 1262 * firewire/1394 will define a dependent info type as an offset value. 1263 * Allow the upper level code to flag this and pass it down during 1264 * parsing. The same thing applies to immediate types. 1265 */ 1266 1267static int 1268p1212_validate_offset(u_int16_t val, u_int32_t mask) 1269{ 1270 if ((val == P1212_KEYVALUE_Node_Units_Extent) || 1271 (val == P1212_KEYVALUE_Node_Memory_Extent) || 1272 ((mask & P1212_ALLOW_DEPENDENT_INFO_OFFSET_TYPE) && 1273 ((val == P1212_KEYVALUE_Unit_Dependent_Info) || 1274 (val == P1212_KEYVALUE_Node_Dependent_Info) || 1275 (val == P1212_KEYVALUE_Module_Dependent_Info)))) 1276 return 0; 1277 return 1; 1278} 1279 1280static int 1281p1212_validate_immed(u_int16_t val, u_int32_t mask) 1282{ 1283 switch (val) { 1284 case P1212_KEYVALUE_Textual_Descriptor: 1285 case P1212_KEYVALUE_Bus_Dependent_Info: 1286 case P1212_KEYVALUE_Module_Dependent_Info: 1287 case P1212_KEYVALUE_Node_Unique_Id: 1288 case P1212_KEYVALUE_Node_Dependent_Info: 1289 case P1212_KEYVALUE_Unit_Directory: 1290 case P1212_KEYVALUE_Unit_Dependent_Info: 1291 case P1212_KEYVALUE_Unit_Location: 1292 if ((mask & P1212_ALLOW_DEPENDENT_INFO_IMMED_TYPE) && 1293 ((val == P1212_KEYVALUE_Module_Dependent_Info) || 1294 (val == P1212_KEYVALUE_Node_Dependent_Info) || 1295 (val == P1212_KEYVALUE_Unit_Dependent_Info))) 1296 break; 1297 return 1; 1298 break; 1299 default: 1300 break; 1301 } 1302 return 0; 1303} 1304 1305static int 1306p1212_validate_leaf(u_int16_t val, u_int32_t mask) 1307{ 1308 switch(val) { 1309 case P1212_KEYVALUE_Textual_Descriptor: 1310 case P1212_KEYVALUE_Bus_Dependent_Info: 1311 case P1212_KEYVALUE_Module_Dependent_Info: 1312 case P1212_KEYVALUE_Node_Unique_Id: 1313 case P1212_KEYVALUE_Node_Dependent_Info: 1314 case P1212_KEYVALUE_Unit_Dependent_Info: 1315 case P1212_KEYVALUE_Unit_Location: 1316 break; 1317 default: 1318 return 1; 1319 break; 1320 } 1321 return 0; 1322} 1323 1324static int 1325p1212_validate_dir(u_int16_t val, u_int32_t mask) 1326{ 1327 switch(val) { 1328 case P1212_KEYVALUE_Textual_Descriptor: 1329 case P1212_KEYVALUE_Bus_Dependent_Info: 1330 case P1212_KEYVALUE_Module_Dependent_Info: 1331 case P1212_KEYVALUE_Node_Dependent_Info: 1332 case P1212_KEYVALUE_Unit_Directory: 1333 case P1212_KEYVALUE_Unit_Dependent_Info: 1334 break; 1335 default: 1336 if ((mask & P1212_ALLOW_VENDOR_DIRECTORY_TYPE) && 1337 (val == P1212_KEYVALUE_Module_Vendor_Id)) 1338 break; 1339 return 1; 1340 break; 1341 } 1342 return 0; 1343} 1344