1 /* 2 * Copyright (c) 2026 Abdelkader Boudih <freebsd@seuros.com> 3 * 4 * SPDX-License-Identifier: BSD-2-Clause 5 */ 6 7 /* 8 * coreboot(4) - FreeBSD driver for coreboot firmware tables 9 * 10 * Discovers the coreboot table by scanning low memory for the "LBIO" 11 * signature, follows CB_TAG_FORWARD to the high-memory table, and 12 * exposes firmware information through sysctl(9) and character devices. 13 */ 14 15 #include <sys/systm.h> 16 #include <sys/bus.h> 17 #include <sys/kernel.h> 18 #include <sys/malloc.h> 19 #include <sys/module.h> 20 #include <sys/rman.h> 21 #include <sys/sysctl.h> 22 23 #include <vm/vm.h> 24 #include <vm/vm_param.h> 25 #include <vm/pmap.h> 26 27 #include <machine/bus.h> 28 #include <machine/resource.h> 29 30 #include <dev/coreboot/coreboot.h> 31 32 static struct coreboot_softc *coreboot_sc; 33 34 /* 35 * Debug verbosity control, non-zero enables extra output. 36 * Tunable via loader.conf: hw.coreboot.debug=1 37 * Runtime: sysctl hw.coreboot.debug=1 38 * Registered dynamically under hw.coreboot in 39 * coreboot_register_sysctls(). 40 */ 41 static int coreboot_debug = 0; 42 TUNABLE_INT("hw.coreboot.debug", &coreboot_debug); 43 44 struct coreboot_softc * 45 coreboot_get_softc(void) 46 { 47 return (coreboot_sc); 48 } 49 50 static void coreboot_identify(driver_t *, device_t); 51 static int coreboot_probe(device_t); 52 static int coreboot_attach(device_t); 53 static int coreboot_detach(device_t); 54 static int coreboot_modevent(module_t, int, void *); 55 56 /* 57 * Scan a physical memory region for the "LBIO" signature. 58 * Returns the physical address of the header, or 0 if not found. 59 */ 60 static vm_paddr_t 61 coreboot_scan_region(vm_paddr_t start, vm_paddr_t end) 62 { 63 vm_paddr_t addr; 64 void *va; 65 struct cb_header *hdr; 66 67 for (addr = (start == 0 ? CB_SCAN_LOW_STEP : start); addr < end; 68 addr += CB_SCAN_LOW_STEP) { 69 va = pmap_mapbios(addr, sizeof(struct cb_header)); 70 if (va == NULL) 71 continue; 72 73 hdr = (struct cb_header *)va; 74 if (memcmp(hdr->signature, CB_HEADER_SIGNATURE, 75 CB_HEADER_SIG_LEN) == 0) { 76 pmap_unmapbios(va, sizeof(struct cb_header)); 77 return (addr); 78 } 79 pmap_unmapbios(va, sizeof(struct cb_header)); 80 } 81 return (0); 82 } 83 84 /* 85 * Validate length fields in the header before using them for mappings 86 * and pointer arithmetic. 87 */ 88 static int 89 coreboot_sanitize_header(const struct cb_header *hdr, vm_size_t *map_size) 90 { 91 uint64_t total; 92 93 if (hdr->header_bytes < sizeof(*hdr) || 94 hdr->header_bytes > CB_MAX_HEADER_BYTES) 95 return (EINVAL); 96 if ((hdr->header_bytes % CB_TABLE_ALIGN) != 0) 97 return (EINVAL); 98 if (hdr->table_bytes > CB_MAX_TABLE_BYTES) 99 return (EINVAL); 100 if ((hdr->table_bytes % CB_TABLE_ALIGN) != 0) 101 return (EINVAL); 102 103 total = (uint64_t)hdr->header_bytes + (uint64_t)hdr->table_bytes; 104 if (total > CB_MAX_TABLE_MAP_BYTES) 105 return (EINVAL); 106 107 *map_size = (vm_size_t)total; 108 return (0); 109 } 110 111 /* 112 * Validate the coreboot header checksum. 113 * Returns 0 on success, non-zero on failure. 114 */ 115 static int 116 coreboot_validate_header(struct cb_header *hdr, vm_size_t mapped_len) 117 { 118 uint16_t cksum; 119 120 if (hdr->header_bytes > mapped_len) 121 return (EINVAL); 122 123 cksum = cb_checksum(hdr, hdr->header_bytes); 124 if (cksum != 0) 125 return (EINVAL); 126 127 return (0); 128 } 129 130 /* 131 * Validate checksum for the table payload. 132 */ 133 static int 134 coreboot_validate_table(struct cb_header *hdr, vm_size_t mapped_len) 135 { 136 const uint8_t *table; 137 uint16_t cksum; 138 139 if (hdr->table_bytes == 0) 140 return (0); 141 142 if ((uint64_t)hdr->header_bytes + (uint64_t)hdr->table_bytes > 143 mapped_len) 144 return (EINVAL); 145 if (hdr->table_checksum > UINT16_MAX) 146 return (EINVAL); 147 148 table = (const uint8_t *)hdr + hdr->header_bytes; 149 cksum = cb_checksum(table, hdr->table_bytes); 150 if (cksum != (uint16_t)hdr->table_checksum) 151 return (EINVAL); 152 153 return (0); 154 } 155 156 static void 157 coreboot_copy_bounded_string(const char *src, size_t maxlen, char *dst, 158 size_t dstlen) 159 { 160 size_t slen; 161 162 if (dstlen == 0) 163 return; 164 165 slen = strnlen(src, maxlen); 166 if (slen >= dstlen) 167 slen = dstlen - 1; 168 memcpy(dst, src, slen); 169 dst[slen] = '\0'; 170 } 171 172 /* 173 * Copy a coreboot string record into a destination buffer. 174 */ 175 static void 176 coreboot_copy_string(const struct cb_string *rec, char *dst, size_t dstlen) 177 { 178 size_t slen; 179 180 slen = rec->size - sizeof(struct cb_record); 181 if (slen >= dstlen) 182 slen = dstlen - 1; 183 memcpy(dst, rec->string, slen); 184 dst[slen] = '\0'; 185 186 /* Strip trailing whitespace/nulls */ 187 while (slen > 0 && (dst[slen - 1] == '\0' || dst[slen - 1] == ' ' || 188 dst[slen - 1] == '\n')) 189 dst[--slen] = '\0'; 190 } 191 192 /* 193 * Extract mainboard vendor and part number from the strings field. 194 */ 195 static void 196 coreboot_parse_mainboard(struct coreboot_softc *sc, 197 const struct cb_mainboard *mb) 198 { 199 const char *strings = (const char *)mb->strings; 200 size_t total = mb->size - offsetof(struct cb_mainboard, strings); 201 uint8_t vendor_off, part_off; 202 203 vendor_off = mb->vendor_idx; 204 part_off = mb->part_idx; 205 206 if (vendor_off < total) 207 coreboot_copy_bounded_string(strings + vendor_off, 208 total - vendor_off, sc->mb_vendor, sizeof(sc->mb_vendor)); 209 if (part_off < total) 210 coreboot_copy_bounded_string(strings + part_off, 211 total - part_off, sc->mb_part, sizeof(sc->mb_part)); 212 } 213 214 /* 215 * Parse all records in the coreboot table and populate softc. 216 */ 217 static void 218 coreboot_parse_table(struct coreboot_softc *sc, struct cb_header *hdr) 219 { 220 uint8_t *entry; 221 uint8_t *table_end; 222 struct cb_record *rec; 223 224 entry = (uint8_t *)hdr + hdr->header_bytes; 225 table_end = entry + hdr->table_bytes; 226 227 while ((size_t)(table_end - entry) >= sizeof(struct cb_record)) { 228 size_t rec_size; 229 230 rec = (struct cb_record *)entry; 231 rec_size = rec->size; 232 233 if (rec_size < sizeof(struct cb_record)) 234 break; 235 if (rec_size > (size_t)(table_end - entry)) 236 break; 237 238 switch (rec->tag) { 239 case CB_TAG_VERSION: 240 coreboot_copy_string((struct cb_string *)rec, 241 sc->version, sizeof(sc->version)); 242 break; 243 244 case CB_TAG_EXTRA_VERSION: 245 coreboot_copy_string((struct cb_string *)rec, 246 sc->extra_version, sizeof(sc->extra_version)); 247 break; 248 249 case CB_TAG_BUILD: 250 coreboot_copy_string((struct cb_string *)rec, 251 sc->build, sizeof(sc->build)); 252 break; 253 254 case CB_TAG_COMPILE_TIME: 255 coreboot_copy_string((struct cb_string *)rec, 256 sc->compile_time, sizeof(sc->compile_time)); 257 break; 258 259 case CB_TAG_COMPILER: 260 coreboot_copy_string((struct cb_string *)rec, 261 sc->compiler, sizeof(sc->compiler)); 262 break; 263 264 case CB_TAG_PLATFORM_BLOB_VERSION: 265 coreboot_copy_string((struct cb_string *)rec, 266 sc->platform_blob_version, 267 sizeof(sc->platform_blob_version)); 268 break; 269 270 case CB_TAG_SERIALNO: 271 coreboot_copy_string((struct cb_string *)rec, 272 sc->serialno, sizeof(sc->serialno)); 273 break; 274 275 case CB_TAG_VERSION_TIMESTAMP: { 276 struct cb_version_timestamp *ts = 277 (struct cb_version_timestamp *)rec; 278 279 if (rec_size < sizeof(*ts)) 280 break; 281 sc->version_timestamp = ts->timestamp; 282 sc->has_version_timestamp = 1; 283 break; 284 } 285 286 case CB_TAG_MAINBOARD: 287 if (rec_size < offsetof(struct cb_mainboard, strings)) 288 break; 289 coreboot_parse_mainboard(sc, 290 (struct cb_mainboard *)rec); 291 break; 292 293 case CB_TAG_SERIAL: { 294 struct cb_serial *ser = (struct cb_serial *)rec; 295 296 if (rec_size < sizeof(*ser)) 297 break; 298 sc->serial_baseaddr = ser->baseaddr; 299 sc->serial_baud = ser->baud; 300 sc->serial_regwidth = ser->regwidth; 301 sc->has_serial = 1; 302 break; 303 } 304 305 case CB_TAG_TSC_INFO: { 306 struct cb_tsc_info *tsc = (struct cb_tsc_info *)rec; 307 308 if (rec_size < sizeof(*tsc)) 309 break; 310 sc->tsc_freq_khz = tsc->freq_khz; 311 sc->has_tsc_info = 1; 312 break; 313 } 314 315 case CB_TAG_PCIE: { 316 struct cb_pcie *pcie = (struct cb_pcie *)rec; 317 318 if (rec_size < sizeof(*pcie)) 319 break; 320 sc->pcie_ctrl_base = pcie->ctrl_base; 321 sc->has_pcie = 1; 322 break; 323 } 324 325 case CB_TAG_BOOT_MEDIA_PARAMS: { 326 struct cb_boot_media_params *bmp = 327 (struct cb_boot_media_params *)rec; 328 329 if (rec_size < sizeof(*bmp)) 330 break; 331 sc->fmap_offset = bmp->fmap_offset; 332 sc->cbfs_offset = bmp->cbfs_offset; 333 sc->cbfs_size = bmp->cbfs_size; 334 sc->boot_media_size = bmp->boot_media_size; 335 sc->has_boot_media = 1; 336 break; 337 } 338 339 case CB_TAG_MMC_INFO: { 340 struct cb_mmc_info *mmc = (struct cb_mmc_info *)rec; 341 342 if (rec_size < sizeof(*mmc)) 343 break; 344 sc->mmc_early_cmd1_status = mmc->early_cmd1_status; 345 sc->has_mmc_info = 1; 346 break; 347 } 348 349 case CB_TAG_CBMEM_CONSOLE: { 350 struct cb_cbmem_ref *ref = (struct cb_cbmem_ref *)rec; 351 352 if (rec_size < sizeof(*ref)) 353 break; 354 sc->console_paddr = (vm_paddr_t)ref->cbmem_addr; 355 sc->has_console = 1; 356 break; 357 } 358 359 case CB_TAG_CBMEM_ENTRY: { 360 struct cb_cbmem_entry *ent = 361 (struct cb_cbmem_entry *)rec; 362 363 if (rec_size < sizeof(*ent)) 364 break; 365 if (sc->cbmem_count < CB_MAX_CBMEM_ENTRIES) { 366 struct cbmem_entry_info *info = 367 &sc->cbmem_entries[sc->cbmem_count]; 368 info->id = ent->id; 369 info->address = ent->address; 370 info->size = ent->entry_size; 371 strlcpy(info->name, cbmem_id_to_name(ent->id), 372 sizeof(info->name)); 373 sc->cbmem_count++; 374 } 375 break; 376 } 377 378 case CB_TAG_BOARD_CONFIG: { 379 struct cb_board_config *bc = 380 (struct cb_board_config *)rec; 381 382 if (rec_size < sizeof(*bc)) 383 break; 384 sc->fw_config = bc->fw_config; 385 sc->board_id = bc->board_id; 386 sc->ram_code = bc->ram_code; 387 sc->sku_id = bc->sku_id; 388 sc->has_board_config = 1; 389 break; 390 } 391 392 case CB_TAG_MAC_ADDRS: { 393 struct cb_macs *macs = (struct cb_macs *)rec; 394 uint32_t i, count; 395 396 if (rec_size < sizeof(*macs)) 397 break; 398 count = macs->count; 399 if (count > CB_MAX_MAC_ADDRS) 400 count = CB_MAX_MAC_ADDRS; 401 if (rec_size < sizeof(*macs) + 402 count * sizeof(struct cb_mac_address)) 403 break; 404 for (i = 0; i < count; i++) 405 sc->macs[i] = macs->entries[i]; 406 sc->mac_count = count; 407 break; 408 } 409 410 case CB_TAG_ACPI_RSDP: { 411 struct cb_acpi_rsdp *rsdp = 412 (struct cb_acpi_rsdp *)rec; 413 414 if (rec_size < sizeof(*rsdp)) 415 break; 416 sc->acpi_rsdp = rsdp->rsdp_pointer; 417 sc->has_acpi_rsdp = 1; 418 break; 419 } 420 421 case CB_TAG_SPI_FLASH: { 422 struct cb_spi_flash *spi = 423 (struct cb_spi_flash *)rec; 424 425 if (rec_size < sizeof(*spi)) 426 break; 427 sc->spi_flash_size = spi->flash_size; 428 sc->spi_sector_size = spi->sector_size; 429 sc->spi_erase_cmd = spi->erase_cmd; 430 sc->spi_flags = spi->flags; 431 sc->has_spi_flash = 1; 432 break; 433 } 434 435 case CB_TAG_CONSOLE: { 436 struct cb_console *con = (struct cb_console *)rec; 437 438 if (rec_size < sizeof(*con)) 439 break; 440 sc->console_type = con->type; 441 sc->has_console_type = 1; 442 break; 443 } 444 445 case CB_TAG_FRAMEBUFFER: { 446 struct cb_framebuffer *fb = 447 (struct cb_framebuffer *)rec; 448 449 if (rec_size < CB_FRAMEBUFFER_MIN_SIZE) 450 break; 451 sc->fb_addr = fb->physical_address; 452 sc->fb_x_res = fb->x_resolution; 453 sc->fb_y_res = fb->y_resolution; 454 sc->fb_stride = fb->bytes_per_line; 455 sc->fb_bpp = fb->bits_per_pixel; 456 sc->has_framebuffer = 1; 457 break; 458 } 459 460 case CB_TAG_GPIO: { 461 struct cb_gpios *gpios = (struct cb_gpios *)rec; 462 uint32_t i, count; 463 464 if (rec_size < sizeof(*gpios)) 465 break; 466 count = gpios->count; 467 if (count > CB_MAX_GPIOS) 468 count = CB_MAX_GPIOS; 469 if (rec_size < sizeof(*gpios) + 470 count * sizeof(struct cb_gpio)) 471 break; 472 for (i = 0; i < count; i++) 473 sc->gpios[i] = gpios->entries[i]; 474 sc->gpio_count = count; 475 break; 476 } 477 478 case CB_TAG_TPM_PPI_HANDOFF: { 479 struct cb_tpm_ppi *tpm = (struct cb_tpm_ppi *)rec; 480 481 if (rec_size < sizeof(*tpm)) 482 break; 483 sc->tpm_ppi_addr = tpm->ppi_address; 484 sc->tpm_version = tpm->tpm_version; 485 sc->has_tpm = 1; 486 break; 487 } 488 489 case CB_TAG_TIMESTAMPS: { 490 struct cb_cbmem_ref *ref = (struct cb_cbmem_ref *)rec; 491 492 if (rec_size < sizeof(*ref)) 493 break; 494 sc->timestamps_paddr = (vm_paddr_t)ref->cbmem_addr; 495 sc->has_timestamps = 1; 496 break; 497 } 498 499 case CB_TAG_ACPI_GNVS: { 500 struct cb_cbmem_ref *ref = (struct cb_cbmem_ref *)rec; 501 502 if (rec_size < sizeof(*ref)) 503 break; 504 sc->acpi_gnvs_paddr = (vm_paddr_t)ref->cbmem_addr; 505 sc->has_acpi_gnvs = 1; 506 break; 507 } 508 509 case CB_TAG_ACPI_CNVS: { 510 struct cb_cbmem_ref *ref = (struct cb_cbmem_ref *)rec; 511 512 if (rec_size < sizeof(*ref)) 513 break; 514 sc->acpi_cnvs_paddr = (vm_paddr_t)ref->cbmem_addr; 515 sc->has_acpi_cnvs = 1; 516 break; 517 } 518 519 case CB_TAG_VPD: { 520 struct cb_cbmem_ref *ref = (struct cb_cbmem_ref *)rec; 521 522 if (rec_size < sizeof(*ref)) 523 break; 524 sc->vpd_paddr = (vm_paddr_t)ref->cbmem_addr; 525 sc->has_vpd = 1; 526 break; 527 } 528 529 case CB_TAG_WIFI_CALIBRATION: { 530 struct cb_cbmem_ref *ref = (struct cb_cbmem_ref *)rec; 531 532 if (rec_size < sizeof(*ref)) 533 break; 534 sc->wifi_cal_paddr = (vm_paddr_t)ref->cbmem_addr; 535 sc->has_wifi_cal = 1; 536 break; 537 } 538 539 case CB_TAG_FMAP: { 540 struct cb_cbmem_ref *ref = (struct cb_cbmem_ref *)rec; 541 542 if (rec_size < sizeof(*ref)) 543 break; 544 sc->fmap_paddr = (vm_paddr_t)ref->cbmem_addr; 545 sc->has_fmap = 1; 546 break; 547 } 548 549 case CB_TAG_VBOOT_WORKBUF: { 550 struct cb_cbmem_ref *ref = (struct cb_cbmem_ref *)rec; 551 552 if (rec_size < sizeof(*ref)) 553 break; 554 sc->vboot_workbuf_paddr = (vm_paddr_t)ref->cbmem_addr; 555 sc->has_vboot_workbuf = 1; 556 break; 557 } 558 559 case CB_TAG_TYPE_C_INFO: { 560 struct cb_cbmem_ref *ref = (struct cb_cbmem_ref *)rec; 561 562 if (rec_size < sizeof(*ref)) 563 break; 564 sc->type_c_info_paddr = (vm_paddr_t)ref->cbmem_addr; 565 sc->has_type_c_info = 1; 566 break; 567 } 568 569 case CB_TAG_ROOT_BRIDGE_INFO: { 570 struct cb_cbmem_ref *ref = (struct cb_cbmem_ref *)rec; 571 572 if (rec_size < sizeof(*ref)) 573 break; 574 sc->root_bridge_info_paddr = 575 (vm_paddr_t)ref->cbmem_addr; 576 sc->has_root_bridge_info = 1; 577 break; 578 } 579 580 case CB_TAG_TPM_CB_LOG: { 581 struct cb_cbmem_ref *ref = (struct cb_cbmem_ref *)rec; 582 583 if (rec_size < sizeof(*ref)) 584 break; 585 sc->tpm_log_paddr = (vm_paddr_t)ref->cbmem_addr; 586 sc->has_tpm_log = 1; 587 break; 588 } 589 590 case CB_TAG_SMMSTOREV2: { 591 struct cb_smmstorev2 *smm = 592 (struct cb_smmstorev2 *)rec; 593 594 if (rec_size < CB_SMMSTOREV2_BASE_SIZE) 595 break; 596 sc->smmstore_num_blocks = smm->num_blocks; 597 sc->smmstore_block_size = smm->block_size; 598 sc->smmstore_com_buffer = smm->com_buffer; 599 sc->smmstore_apm_cmd = smm->apm_cmd; 600 /* 64-bit mmap_addr only present in newer coreboot */ 601 if (rec_size >= sizeof(*smm)) 602 sc->smmstore_mmap_addr = smm->mmap_addr; 603 else 604 sc->smmstore_mmap_addr = 605 (uint64_t)smm->mmap_addr_lo; 606 sc->has_smmstore = 1; 607 break; 608 } 609 610 default: 611 break; 612 } 613 614 entry += rec_size; 615 } 616 } 617 618 /* 619 * Table-driven sysctl registration. 620 * 621 * Each leaf descriptor specifies the parent node, name, type, data offset 622 * into softc, a guard flag offset (or -1 for unconditional), and flags. 623 * Nodes that group related leaves are indexed by cb_sysctl_node. 624 */ 625 626 /* Node indices for parent selection */ 627 enum cb_sysctl_node { 628 CB_NODE_ROOT = 0, 629 CB_NODE_MAINBOARD, 630 CB_NODE_SERIAL, 631 CB_NODE_BOARD, 632 CB_NODE_BOOT_MEDIA, 633 CB_NODE_SPI_FLASH, 634 CB_NODE_FRAMEBUFFER, 635 CB_NODE_TPM, 636 CB_NODE_SMMSTORE, 637 CB_NODE_CBMEM_REFS, 638 CB_NODE_COUNT 639 }; 640 641 /* Sysctl value type discriminator */ 642 enum cb_sysctl_type { 643 CB_SYSCTL_U8, 644 CB_SYSCTL_U16, 645 CB_SYSCTL_U32, 646 CB_SYSCTL_S32, 647 CB_SYSCTL_U64, 648 CB_SYSCTL_ULONG, 649 CB_SYSCTL_STRING, 650 }; 651 652 /* 653 * Guard mode: how to decide whether a leaf should be registered. 654 * STR_NONEMPTY: check that the char[] at guard_off is non-empty 655 * FLAG_SET: check that the int at guard_off is non-zero 656 * ALWAYS: unconditional (guard_off ignored) 657 */ 658 enum cb_sysctl_guard { 659 CB_GUARD_ALWAYS, 660 CB_GUARD_FLAG_SET, 661 CB_GUARD_STR_NONEMPTY, 662 }; 663 664 struct cb_sysctl_node_desc { 665 enum cb_sysctl_node id; 666 enum cb_sysctl_node parent; 667 const char *name; 668 const char *desc; 669 }; 670 671 struct cb_sysctl_leaf { 672 enum cb_sysctl_node parent; 673 const char *name; 674 enum cb_sysctl_type type; 675 size_t data_off; 676 enum cb_sysctl_guard guard; 677 size_t guard_off; 678 int flags; 679 const char *desc; 680 }; 681 682 /* Helper macros for field offset within coreboot_softc */ 683 #define SC_OFF(field) offsetof(struct coreboot_softc, field) 684 685 static const struct cb_sysctl_node_desc cb_nodes[] = { 686 { CB_NODE_MAINBOARD, CB_NODE_ROOT, "mainboard", 687 "Mainboard information" }, 688 { CB_NODE_SERIAL, CB_NODE_ROOT, "serial", 689 "Serial port" }, 690 { CB_NODE_BOARD, CB_NODE_ROOT, "board", 691 "Board identification" }, 692 { CB_NODE_BOOT_MEDIA, CB_NODE_ROOT, "boot_media", 693 "Boot media parameters" }, 694 { CB_NODE_SPI_FLASH, CB_NODE_ROOT, "spi_flash", 695 "SPI flash parameters" }, 696 { CB_NODE_FRAMEBUFFER, CB_NODE_ROOT, "framebuffer", 697 "Framebuffer information" }, 698 { CB_NODE_TPM, CB_NODE_ROOT, "tpm", 699 "TPM information" }, 700 { CB_NODE_SMMSTORE, CB_NODE_ROOT, "smmstore", 701 "SMMSTORE v2 configuration" }, 702 { CB_NODE_CBMEM_REFS, CB_NODE_ROOT, "cbmem_refs", 703 "Additional CBMEM reference addresses" }, 704 }; 705 706 static const struct cb_sysctl_leaf cb_leaves[] = { 707 /* Root-level strings (guarded by non-empty string) */ 708 { CB_NODE_ROOT, "version", CB_SYSCTL_STRING, 709 SC_OFF(version), CB_GUARD_STR_NONEMPTY, SC_OFF(version), 710 CTLFLAG_RD, "Firmware version" }, 711 { CB_NODE_ROOT, "build", CB_SYSCTL_STRING, 712 SC_OFF(build), CB_GUARD_STR_NONEMPTY, SC_OFF(build), 713 CTLFLAG_RD, "Build date" }, 714 { CB_NODE_ROOT, "compile_time", CB_SYSCTL_STRING, 715 SC_OFF(compile_time), CB_GUARD_STR_NONEMPTY, SC_OFF(compile_time), 716 CTLFLAG_RD, "Firmware compile time" }, 717 { CB_NODE_ROOT, "compiler", CB_SYSCTL_STRING, 718 SC_OFF(compiler), CB_GUARD_STR_NONEMPTY, SC_OFF(compiler), 719 CTLFLAG_RD, "Compiler info" }, 720 { CB_NODE_ROOT, "extra_version", CB_SYSCTL_STRING, 721 SC_OFF(extra_version), CB_GUARD_STR_NONEMPTY, SC_OFF(extra_version), 722 CTLFLAG_RD, "Extra version info" }, 723 { CB_NODE_ROOT, "serialno", CB_SYSCTL_STRING, 724 SC_OFF(serialno), CB_GUARD_STR_NONEMPTY, SC_OFF(serialno), 725 CTLFLAG_RD, "Serial number" }, 726 { CB_NODE_ROOT, "platform_blob_version", CB_SYSCTL_STRING, 727 SC_OFF(platform_blob_version), CB_GUARD_STR_NONEMPTY, 728 SC_OFF(platform_blob_version), 729 CTLFLAG_RD, "Platform blob version" }, 730 731 /* Root-level scalars */ 732 { CB_NODE_ROOT, "version_timestamp", CB_SYSCTL_U32, 733 SC_OFF(version_timestamp), CB_GUARD_FLAG_SET, 734 SC_OFF(has_version_timestamp), 735 CTLFLAG_RD, "Firmware version timestamp" }, 736 { CB_NODE_ROOT, "table_addr", CB_SYSCTL_U64, 737 SC_OFF(table_paddr), CB_GUARD_ALWAYS, 0, 738 CTLFLAG_RD, "Physical address of coreboot table" }, 739 { CB_NODE_ROOT, "table_size", CB_SYSCTL_ULONG, 740 SC_OFF(table_size), CB_GUARD_ALWAYS, 0, 741 CTLFLAG_RD, "Total coreboot table size" }, 742 { CB_NODE_ROOT, "tsc_freq_khz", CB_SYSCTL_U32, 743 SC_OFF(tsc_freq_khz), CB_GUARD_FLAG_SET, SC_OFF(has_tsc_info), 744 CTLFLAG_RD, "TSC frequency in kHz" }, 745 { CB_NODE_ROOT, "pcie_ctrl_base", CB_SYSCTL_U64, 746 SC_OFF(pcie_ctrl_base), CB_GUARD_FLAG_SET, SC_OFF(has_pcie), 747 CTLFLAG_RD, "PCIe controller base address" }, 748 { CB_NODE_ROOT, "acpi_rsdp", CB_SYSCTL_U64, 749 SC_OFF(acpi_rsdp), CB_GUARD_FLAG_SET, SC_OFF(has_acpi_rsdp), 750 CTLFLAG_RD, "ACPI RSDP physical address" }, 751 { CB_NODE_ROOT, "mmc_early_cmd1_status", CB_SYSCTL_S32, 752 SC_OFF(mmc_early_cmd1_status), CB_GUARD_FLAG_SET, 753 SC_OFF(has_mmc_info), 754 CTLFLAG_RD, "Early eMMC CMD1 status" }, 755 { CB_NODE_ROOT, "console_type", CB_SYSCTL_U16, 756 SC_OFF(console_type), CB_GUARD_FLAG_SET, SC_OFF(has_console_type), 757 CTLFLAG_RD, "Firmware console type" }, 758 { CB_NODE_ROOT, "timestamps_addr", CB_SYSCTL_U64, 759 SC_OFF(timestamps_paddr), CB_GUARD_FLAG_SET, SC_OFF(has_timestamps), 760 CTLFLAG_RD, "Timestamps CBMEM physical address" }, 761 762 /* Mainboard children */ 763 { CB_NODE_MAINBOARD, "vendor", CB_SYSCTL_STRING, 764 SC_OFF(mb_vendor), CB_GUARD_STR_NONEMPTY, SC_OFF(mb_vendor), 765 CTLFLAG_RD, "Board vendor" }, 766 { CB_NODE_MAINBOARD, "part", CB_SYSCTL_STRING, 767 SC_OFF(mb_part), CB_GUARD_STR_NONEMPTY, SC_OFF(mb_part), 768 CTLFLAG_RD, "Board part number" }, 769 770 /* Serial children */ 771 { CB_NODE_SERIAL, "baseaddr", CB_SYSCTL_U32, 772 SC_OFF(serial_baseaddr), CB_GUARD_FLAG_SET, SC_OFF(has_serial), 773 CTLFLAG_RD, "Base address" }, 774 { CB_NODE_SERIAL, "baud", CB_SYSCTL_U32, 775 SC_OFF(serial_baud), CB_GUARD_FLAG_SET, SC_OFF(has_serial), 776 CTLFLAG_RD, "Baud rate" }, 777 { CB_NODE_SERIAL, "regwidth", CB_SYSCTL_U32, 778 SC_OFF(serial_regwidth), CB_GUARD_FLAG_SET, SC_OFF(has_serial), 779 CTLFLAG_RD, "Register width" }, 780 781 /* Board config children */ 782 { CB_NODE_BOARD, "fw_config", CB_SYSCTL_U64, 783 SC_OFF(fw_config), CB_GUARD_FLAG_SET, SC_OFF(has_board_config), 784 CTLFLAG_RD, "Firmware configuration bitmask" }, 785 { CB_NODE_BOARD, "board_id", CB_SYSCTL_U32, 786 SC_OFF(board_id), CB_GUARD_FLAG_SET, SC_OFF(has_board_config), 787 CTLFLAG_RD, "Board ID" }, 788 { CB_NODE_BOARD, "ram_code", CB_SYSCTL_U32, 789 SC_OFF(ram_code), CB_GUARD_FLAG_SET, SC_OFF(has_board_config), 790 CTLFLAG_RD, "RAM code" }, 791 { CB_NODE_BOARD, "sku_id", CB_SYSCTL_U32, 792 SC_OFF(sku_id), CB_GUARD_FLAG_SET, SC_OFF(has_board_config), 793 CTLFLAG_RD, "SKU ID" }, 794 795 /* Boot media children */ 796 { CB_NODE_BOOT_MEDIA, "fmap_offset", CB_SYSCTL_U64, 797 SC_OFF(fmap_offset), CB_GUARD_FLAG_SET, SC_OFF(has_boot_media), 798 CTLFLAG_RD, "FMAP offset from boot media start" }, 799 { CB_NODE_BOOT_MEDIA, "cbfs_offset", CB_SYSCTL_U64, 800 SC_OFF(cbfs_offset), CB_GUARD_FLAG_SET, SC_OFF(has_boot_media), 801 CTLFLAG_RD, "CBFS offset from boot media start" }, 802 { CB_NODE_BOOT_MEDIA, "cbfs_size", CB_SYSCTL_U64, 803 SC_OFF(cbfs_size), CB_GUARD_FLAG_SET, SC_OFF(has_boot_media), 804 CTLFLAG_RD, "CBFS size in bytes" }, 805 { CB_NODE_BOOT_MEDIA, "size", CB_SYSCTL_U64, 806 SC_OFF(boot_media_size), CB_GUARD_FLAG_SET, SC_OFF(has_boot_media), 807 CTLFLAG_RD, "Boot media size in bytes" }, 808 809 /* SPI flash children */ 810 { CB_NODE_SPI_FLASH, "size", CB_SYSCTL_U32, 811 SC_OFF(spi_flash_size), CB_GUARD_FLAG_SET, SC_OFF(has_spi_flash), 812 CTLFLAG_RD, "Flash size in bytes" }, 813 { CB_NODE_SPI_FLASH, "sector_size", CB_SYSCTL_U32, 814 SC_OFF(spi_sector_size), CB_GUARD_FLAG_SET, SC_OFF(has_spi_flash), 815 CTLFLAG_RD, "Sector size in bytes" }, 816 { CB_NODE_SPI_FLASH, "erase_cmd", CB_SYSCTL_U8, 817 SC_OFF(spi_erase_cmd), CB_GUARD_FLAG_SET, SC_OFF(has_spi_flash), 818 CTLFLAG_RD, "Erase command byte" }, 819 820 /* Framebuffer children */ 821 { CB_NODE_FRAMEBUFFER, "addr", CB_SYSCTL_U64, 822 SC_OFF(fb_addr), CB_GUARD_FLAG_SET, SC_OFF(has_framebuffer), 823 CTLFLAG_RD, "Physical address" }, 824 { CB_NODE_FRAMEBUFFER, "x_res", CB_SYSCTL_U32, 825 SC_OFF(fb_x_res), CB_GUARD_FLAG_SET, SC_OFF(has_framebuffer), 826 CTLFLAG_RD, "Horizontal resolution" }, 827 { CB_NODE_FRAMEBUFFER, "y_res", CB_SYSCTL_U32, 828 SC_OFF(fb_y_res), CB_GUARD_FLAG_SET, SC_OFF(has_framebuffer), 829 CTLFLAG_RD, "Vertical resolution" }, 830 { CB_NODE_FRAMEBUFFER, "bpp", CB_SYSCTL_U8, 831 SC_OFF(fb_bpp), CB_GUARD_FLAG_SET, SC_OFF(has_framebuffer), 832 CTLFLAG_RD, "Bits per pixel" }, 833 834 /* TPM children */ 835 { CB_NODE_TPM, "version", CB_SYSCTL_U8, 836 SC_OFF(tpm_version), CB_GUARD_FLAG_SET, SC_OFF(has_tpm), 837 CTLFLAG_RD, "TPM version (1=1.2, 2=2.0)" }, 838 { CB_NODE_TPM, "ppi_addr", CB_SYSCTL_U32, 839 SC_OFF(tpm_ppi_addr), CB_GUARD_FLAG_SET, SC_OFF(has_tpm), 840 CTLFLAG_RD, "PPI address" }, 841 { CB_NODE_TPM, "cblog_addr", CB_SYSCTL_U64, 842 SC_OFF(tpm_log_paddr), CB_GUARD_FLAG_SET, SC_OFF(has_tpm_log), 843 CTLFLAG_RD, "TPM event log physical address" }, 844 845 /* SMMSTORE children */ 846 { CB_NODE_SMMSTORE, "num_blocks", CB_SYSCTL_U32, 847 SC_OFF(smmstore_num_blocks), CB_GUARD_FLAG_SET, 848 SC_OFF(has_smmstore), 849 CTLFLAG_RD, "Number of blocks" }, 850 { CB_NODE_SMMSTORE, "block_size", CB_SYSCTL_U32, 851 SC_OFF(smmstore_block_size), CB_GUARD_FLAG_SET, 852 SC_OFF(has_smmstore), 853 CTLFLAG_RD, "Block size in bytes" }, 854 { CB_NODE_SMMSTORE, "mmap_addr", CB_SYSCTL_U64, 855 SC_OFF(smmstore_mmap_addr), CB_GUARD_FLAG_SET, 856 SC_OFF(has_smmstore), 857 CTLFLAG_RD, "Memory-mapped address" }, 858 { CB_NODE_SMMSTORE, "com_buffer", CB_SYSCTL_U32, 859 SC_OFF(smmstore_com_buffer), CB_GUARD_FLAG_SET, 860 SC_OFF(has_smmstore), 861 CTLFLAG_RD, "Communication buffer address" }, 862 { CB_NODE_SMMSTORE, "apm_cmd", CB_SYSCTL_U8, 863 SC_OFF(smmstore_apm_cmd), CB_GUARD_FLAG_SET, 864 SC_OFF(has_smmstore), 865 CTLFLAG_RD, "APM command byte" }, 866 867 /* CBMEM reference addresses */ 868 { CB_NODE_CBMEM_REFS, "acpi_gnvs", CB_SYSCTL_U64, 869 SC_OFF(acpi_gnvs_paddr), CB_GUARD_FLAG_SET, SC_OFF(has_acpi_gnvs), 870 CTLFLAG_RD, "ACPI GNVS CBMEM physical address" }, 871 { CB_NODE_CBMEM_REFS, "acpi_cnvs", CB_SYSCTL_U64, 872 SC_OFF(acpi_cnvs_paddr), CB_GUARD_FLAG_SET, SC_OFF(has_acpi_cnvs), 873 CTLFLAG_RD, "ACPI CNVS CBMEM physical address" }, 874 { CB_NODE_CBMEM_REFS, "vpd", CB_SYSCTL_U64, 875 SC_OFF(vpd_paddr), CB_GUARD_FLAG_SET, SC_OFF(has_vpd), 876 CTLFLAG_RD, "VPD CBMEM physical address" }, 877 { CB_NODE_CBMEM_REFS, "wifi_calibration", CB_SYSCTL_U64, 878 SC_OFF(wifi_cal_paddr), CB_GUARD_FLAG_SET, SC_OFF(has_wifi_cal), 879 CTLFLAG_RD, "WiFi calibration CBMEM physical address" }, 880 { CB_NODE_CBMEM_REFS, "fmap", CB_SYSCTL_U64, 881 SC_OFF(fmap_paddr), CB_GUARD_FLAG_SET, SC_OFF(has_fmap), 882 CTLFLAG_RD, "FMAP CBMEM physical address" }, 883 { CB_NODE_CBMEM_REFS, "vboot_workbuf", CB_SYSCTL_U64, 884 SC_OFF(vboot_workbuf_paddr), CB_GUARD_FLAG_SET, 885 SC_OFF(has_vboot_workbuf), 886 CTLFLAG_RD, "Vboot work buffer CBMEM physical address" }, 887 { CB_NODE_CBMEM_REFS, "type_c_info", CB_SYSCTL_U64, 888 SC_OFF(type_c_info_paddr), CB_GUARD_FLAG_SET, 889 SC_OFF(has_type_c_info), 890 CTLFLAG_RD, "Type-C info CBMEM physical address" }, 891 { CB_NODE_CBMEM_REFS, "root_bridge_info", CB_SYSCTL_U64, 892 SC_OFF(root_bridge_info_paddr), CB_GUARD_FLAG_SET, 893 SC_OFF(has_root_bridge_info), 894 CTLFLAG_RD, "Root bridge info CBMEM physical address" }, 895 }; 896 897 /* 898 * Check whether a leaf's guard condition is satisfied. 899 */ 900 static int 901 cb_sysctl_guard_check(const struct cb_sysctl_leaf *leaf, 902 const struct coreboot_softc *sc) 903 { 904 const char *base; 905 906 base = (const char *)sc; 907 switch (leaf->guard) { 908 case CB_GUARD_ALWAYS: 909 return (1); 910 case CB_GUARD_FLAG_SET: 911 return (*(const int *)(base + leaf->guard_off) != 0); 912 case CB_GUARD_STR_NONEMPTY: 913 return (*(base + leaf->guard_off) != '\0'); 914 } 915 return (0); 916 } 917 918 /* 919 * Type-to-handler mapping for sysctl_add_oid(). 920 * Mirrors the SYSCTL_ADD_* macros but avoids their CTASSERT on flags. 921 */ 922 static const struct { 923 int ctltype; 924 int (*handler)(SYSCTL_HANDLER_ARGS); 925 const char *fmt; 926 } cb_sysctl_types[] = { 927 [CB_SYSCTL_U8] = { CTLTYPE_U8, sysctl_handle_8, "CU" }, 928 [CB_SYSCTL_U16] = { CTLTYPE_U16, sysctl_handle_16, "SU" }, 929 [CB_SYSCTL_U32] = { CTLTYPE_U32, sysctl_handle_32, "IU" }, 930 [CB_SYSCTL_S32] = { CTLTYPE_S32, sysctl_handle_32, "I" }, 931 [CB_SYSCTL_U64] = { CTLTYPE_U64, sysctl_handle_64, "QU" }, 932 [CB_SYSCTL_ULONG] = { CTLTYPE_ULONG, sysctl_handle_long, "LU" }, 933 [CB_SYSCTL_STRING] = { CTLTYPE_STRING, sysctl_handle_string, "A" }, 934 }; 935 936 /* 937 * Add a single sysctl leaf under the given parent OID. 938 */ 939 static void 940 cb_sysctl_add_leaf(struct sysctl_ctx_list *ctx, struct sysctl_oid *parent, 941 const struct cb_sysctl_leaf *leaf, struct coreboot_softc *sc) 942 { 943 void *ptr; 944 945 ptr = (char *)sc + leaf->data_off; 946 947 sysctl_add_oid(ctx, SYSCTL_CHILDREN(parent), OID_AUTO, 948 leaf->name, 949 cb_sysctl_types[leaf->type].ctltype | CTLFLAG_MPSAFE | leaf->flags, 950 ptr, 0, 951 cb_sysctl_types[leaf->type].handler, 952 cb_sysctl_types[leaf->type].fmt, 953 __DESCR(leaf->desc), NULL); 954 } 955 956 /* 957 * Register the sysctl tree under hw.coreboot.* 958 * 959 * Static leaves and nodes are driven by the cb_leaves[] and cb_nodes[] 960 * tables. Dynamic entries (CBMEM, MAC, GPIO) that require loops over 961 * runtime-determined counts are handled explicitly below the table loop. 962 */ 963 static void 964 coreboot_register_sysctls(struct coreboot_softc *sc) 965 { 966 struct sysctl_oid *nodes[CB_NODE_COUNT]; 967 struct sysctl_oid *oid_cbmem, *oid_entry; 968 struct sysctl_oid *oid_mac, *oid_gpio, *oid_pin; 969 char numstr[8]; 970 uint32_t i; 971 int any_cbref; 972 973 sysctl_ctx_init(&sc->sysctl_ctx); 974 sc->sysctl_tree = SYSCTL_ADD_NODE(&sc->sysctl_ctx, 975 SYSCTL_STATIC_CHILDREN(_hw), OID_AUTO, "coreboot", 976 CTLFLAG_RD | CTLFLAG_MPSAFE, 0, "coreboot firmware information"); 977 978 if (sc->sysctl_tree == NULL) 979 return; 980 981 memset(nodes, 0, sizeof(nodes)); 982 nodes[CB_NODE_ROOT] = sc->sysctl_tree; 983 984 SYSCTL_ADD_INT(&sc->sysctl_ctx, 985 SYSCTL_CHILDREN(sc->sysctl_tree), OID_AUTO, "debug", 986 CTLFLAG_RW, &coreboot_debug, 0, 987 "Enable verbose coreboot diagnostics"); 988 989 /* 990 * Create intermediate nodes on demand. 991 * 992 * The mainboard node is special: it appears when either vendor or 993 * part is present. The TPM node appears when has_tpm or has_tpm_log 994 * is set. The cbmem_refs node appears when any of its children 995 * would be registered. All other nodes are gated by the guard 996 * flags on their children (a node is created the first time a child 997 * needs it). 998 */ 999 1000 /* Pre-create mainboard node if either string is populated */ 1001 if (sc->mb_vendor[0] != '\0' || sc->mb_part[0] != '\0') 1002 nodes[CB_NODE_MAINBOARD] = SYSCTL_ADD_NODE(&sc->sysctl_ctx, 1003 SYSCTL_CHILDREN(sc->sysctl_tree), OID_AUTO, "mainboard", 1004 CTLFLAG_RD | CTLFLAG_MPSAFE, 0, "Mainboard information"); 1005 1006 /* TPM node appears for has_tpm OR has_tpm_log */ 1007 if (sc->has_tpm || sc->has_tpm_log) 1008 nodes[CB_NODE_TPM] = SYSCTL_ADD_NODE(&sc->sysctl_ctx, 1009 SYSCTL_CHILDREN(sc->sysctl_tree), OID_AUTO, "tpm", 1010 CTLFLAG_RD | CTLFLAG_MPSAFE, 0, "TPM information"); 1011 1012 /* cbmem_refs node: created if any ref address is present */ 1013 any_cbref = sc->has_acpi_gnvs || sc->has_acpi_cnvs || sc->has_vpd || 1014 sc->has_wifi_cal || sc->has_fmap || sc->has_vboot_workbuf || 1015 sc->has_type_c_info || sc->has_root_bridge_info; 1016 if (any_cbref) 1017 nodes[CB_NODE_CBMEM_REFS] = SYSCTL_ADD_NODE(&sc->sysctl_ctx, 1018 SYSCTL_CHILDREN(sc->sysctl_tree), OID_AUTO, "cbmem_refs", 1019 CTLFLAG_RD | CTLFLAG_MPSAFE, 0, 1020 "Additional CBMEM reference addresses"); 1021 1022 /* Walk the leaf table and register matching entries */ 1023 for (i = 0; i < nitems(cb_leaves); i++) { 1024 const struct cb_sysctl_leaf *leaf = &cb_leaves[i]; 1025 enum cb_sysctl_node nid = leaf->parent; 1026 1027 if (!cb_sysctl_guard_check(leaf, sc)) 1028 continue; 1029 1030 /* Lazily create the parent node if not yet instantiated */ 1031 if (nodes[nid] == NULL) { 1032 const struct cb_sysctl_node_desc *nd; 1033 uint32_t j; 1034 1035 for (j = 0; j < nitems(cb_nodes); j++) { 1036 if (cb_nodes[j].id == nid) 1037 break; 1038 } 1039 if (j >= nitems(cb_nodes)) 1040 continue; 1041 nd = &cb_nodes[j]; 1042 nodes[nid] = SYSCTL_ADD_NODE(&sc->sysctl_ctx, 1043 SYSCTL_CHILDREN(nodes[nd->parent]), OID_AUTO, 1044 nd->name, CTLFLAG_RD | CTLFLAG_MPSAFE, 0, 1045 nd->desc); 1046 if (nodes[nid] == NULL) 1047 continue; 1048 } 1049 1050 cb_sysctl_add_leaf(&sc->sysctl_ctx, nodes[nid], leaf, sc); 1051 } 1052 1053 /* --- Dynamic entries that don't fit the static table --- */ 1054 1055 /* CBMEM entry enumeration */ 1056 if (sc->cbmem_count > 0) { 1057 oid_cbmem = SYSCTL_ADD_NODE(&sc->sysctl_ctx, 1058 SYSCTL_CHILDREN(sc->sysctl_tree), OID_AUTO, "cbmem", 1059 CTLFLAG_RD | CTLFLAG_MPSAFE, 0, "CBMEM entries"); 1060 1061 for (i = 0; i < sc->cbmem_count; i++) { 1062 struct cbmem_entry_info *info = &sc->cbmem_entries[i]; 1063 1064 snprintf(numstr, sizeof(numstr), "%u", i); 1065 oid_entry = SYSCTL_ADD_NODE(&sc->sysctl_ctx, 1066 SYSCTL_CHILDREN(oid_cbmem), OID_AUTO, numstr, 1067 CTLFLAG_RD | CTLFLAG_MPSAFE, 0, 1068 "CBMEM entry"); 1069 1070 SYSCTL_ADD_STRING(&sc->sysctl_ctx, 1071 SYSCTL_CHILDREN(oid_entry), OID_AUTO, "name", 1072 CTLFLAG_RD, info->name, 0, "Entry name"); 1073 1074 SYSCTL_ADD_U32(&sc->sysctl_ctx, 1075 SYSCTL_CHILDREN(oid_entry), OID_AUTO, "id", 1076 CTLFLAG_RD, &info->id, 0, "Entry ID (hex)"); 1077 1078 SYSCTL_ADD_U64(&sc->sysctl_ctx, 1079 SYSCTL_CHILDREN(oid_entry), OID_AUTO, "address", 1080 CTLFLAG_RD, (uint64_t *)&info->address, 0, 1081 "Physical address"); 1082 1083 SYSCTL_ADD_U32(&sc->sysctl_ctx, 1084 SYSCTL_CHILDREN(oid_entry), OID_AUTO, "size", 1085 CTLFLAG_RD, &info->size, 0, "Entry size"); 1086 } 1087 } 1088 1089 /* Factory MAC addresses */ 1090 if (sc->mac_count > 0) { 1091 oid_mac = SYSCTL_ADD_NODE(&sc->sysctl_ctx, 1092 SYSCTL_CHILDREN(sc->sysctl_tree), OID_AUTO, "mac", 1093 CTLFLAG_RD | CTLFLAG_MPSAFE, 0, 1094 "Factory MAC addresses"); 1095 1096 for (i = 0; i < sc->mac_count; i++) { 1097 uint8_t *m = sc->macs[i].mac_addr; 1098 1099 snprintf(numstr, sizeof(numstr), "%u", i); 1100 snprintf(sc->mac_strs[i], sizeof(sc->mac_strs[i]), 1101 "%02x:%02x:%02x:%02x:%02x:%02x", 1102 m[0], m[1], m[2], m[3], m[4], m[5]); 1103 1104 SYSCTL_ADD_STRING(&sc->sysctl_ctx, 1105 SYSCTL_CHILDREN(oid_mac), OID_AUTO, numstr, 1106 CTLFLAG_RD, sc->mac_strs[i], 0, 1107 "MAC address"); 1108 } 1109 } 1110 1111 /* GPIO pins */ 1112 if (sc->gpio_count > 0) { 1113 oid_gpio = SYSCTL_ADD_NODE(&sc->sysctl_ctx, 1114 SYSCTL_CHILDREN(sc->sysctl_tree), OID_AUTO, "gpio", 1115 CTLFLAG_RD | CTLFLAG_MPSAFE, 0, 1116 "GPIO pin states"); 1117 1118 for (i = 0; i < sc->gpio_count; i++) { 1119 struct cb_gpio *g = &sc->gpios[i]; 1120 1121 snprintf(numstr, sizeof(numstr), "%u", i); 1122 oid_pin = SYSCTL_ADD_NODE(&sc->sysctl_ctx, 1123 SYSCTL_CHILDREN(oid_gpio), OID_AUTO, numstr, 1124 CTLFLAG_RD | CTLFLAG_MPSAFE, 0, 1125 "GPIO pin"); 1126 1127 /* Ensure name is NUL-terminated */ 1128 g->name[sizeof(g->name) - 1] = '\0'; 1129 SYSCTL_ADD_STRING(&sc->sysctl_ctx, 1130 SYSCTL_CHILDREN(oid_pin), OID_AUTO, "name", 1131 CTLFLAG_RD, g->name, 0, "Pin name"); 1132 1133 SYSCTL_ADD_U32(&sc->sysctl_ctx, 1134 SYSCTL_CHILDREN(oid_pin), OID_AUTO, "port", 1135 CTLFLAG_RD, &g->port, 0, "Port number"); 1136 1137 SYSCTL_ADD_U32(&sc->sysctl_ctx, 1138 SYSCTL_CHILDREN(oid_pin), OID_AUTO, "value", 1139 CTLFLAG_RD, &g->value, 0, "Pin value"); 1140 1141 SYSCTL_ADD_U32(&sc->sysctl_ctx, 1142 SYSCTL_CHILDREN(oid_pin), OID_AUTO, "polarity", 1143 CTLFLAG_RD, &g->polarity, 0, "Pin polarity"); 1144 } 1145 } 1146 1147 /* Timestamp PROC sysctl */ 1148 if (sc->has_timestamps) 1149 coreboot_timestamps_register(sc, sc->sysctl_tree); 1150 } 1151 1152 /* 1153 * Map and validate a coreboot table at physical address pa. 1154 * On success, *vap points to the mapped table and *sizep is the total size. 1155 * The caller must pmap_unmapbios(*vap, *sizep) when done. 1156 */ 1157 static int 1158 coreboot_map_table(vm_paddr_t pa, void **vap, vm_size_t *sizep) 1159 { 1160 struct cb_header *hdr; 1161 void *va; 1162 vm_size_t map_size; 1163 int error; 1164 1165 va = pmap_mapbios(pa, sizeof(struct cb_header)); 1166 if (va == NULL) 1167 return (ENOMEM); 1168 1169 hdr = (struct cb_header *)va; 1170 if (memcmp(hdr->signature, CB_HEADER_SIGNATURE, 1171 CB_HEADER_SIG_LEN) != 0) { 1172 pmap_unmapbios(va, sizeof(struct cb_header)); 1173 return (ENXIO); 1174 } 1175 1176 error = coreboot_sanitize_header(hdr, &map_size); 1177 pmap_unmapbios(va, sizeof(struct cb_header)); 1178 if (error != 0) 1179 return (ENXIO); 1180 1181 va = pmap_mapbios(pa, map_size); 1182 if (va == NULL) 1183 return (ENOMEM); 1184 1185 hdr = (struct cb_header *)va; 1186 if (coreboot_validate_header(hdr, map_size) != 0 || 1187 coreboot_validate_table(hdr, map_size) != 0) { 1188 pmap_unmapbios(va, map_size); 1189 return (ENXIO); 1190 } 1191 1192 *vap = va; 1193 *sizep = map_size; 1194 return (0); 1195 } 1196 1197 /* 1198 * Identify: scan low memory for "LBIO" signature and register a child 1199 */ 1200 static void 1201 coreboot_identify(driver_t *driver, device_t parent) 1202 { 1203 vm_paddr_t low_addr, real_addr; 1204 struct cb_header *hdr; 1205 uint8_t *entry, *table_end; 1206 struct cb_record *rec; 1207 device_t child; 1208 void *va; 1209 vm_size_t map_size; 1210 int error; 1211 1212 if (!device_is_alive(parent)) 1213 return; 1214 1215 if (device_find_child(parent, "coreboot", -1) != NULL) 1216 return; 1217 1218 low_addr = coreboot_scan_region(CB_SCAN_LOW_START, CB_SCAN_LOW_END); 1219 if (low_addr == 0) 1220 return; 1221 1222 va = pmap_mapbios(low_addr, sizeof(struct cb_header)); 1223 if (va == NULL) 1224 return; 1225 1226 /* Scan already verified the signature; re-read to get sizes. */ 1227 hdr = (struct cb_header *)va; 1228 error = coreboot_sanitize_header(hdr, &map_size); 1229 pmap_unmapbios(va, sizeof(struct cb_header)); 1230 if (error != 0) 1231 return; 1232 1233 va = pmap_mapbios(low_addr, map_size); 1234 if (va == NULL) 1235 return; 1236 1237 hdr = (struct cb_header *)va; 1238 if (coreboot_validate_header(hdr, map_size) != 0 || 1239 coreboot_validate_table(hdr, map_size) != 0) { 1240 pmap_unmapbios(va, map_size); 1241 return; 1242 } 1243 1244 /* Look for CB_TAG_FORWARD to find the real table in high memory */ 1245 real_addr = low_addr; 1246 entry = (uint8_t *)hdr + hdr->header_bytes; 1247 table_end = entry + hdr->table_bytes; 1248 while ((size_t)(table_end - entry) >= sizeof(struct cb_record)) { 1249 size_t rec_size; 1250 1251 rec = (struct cb_record *)entry; 1252 rec_size = rec->size; 1253 if (rec_size < sizeof(struct cb_record)) 1254 break; 1255 if (rec_size > (size_t)(table_end - entry)) 1256 break; 1257 if (rec->tag == CB_TAG_FORWARD) { 1258 if (rec_size >= sizeof(struct cb_forward)) { 1259 struct cb_forward *fwd; 1260 1261 fwd = (struct cb_forward *)entry; 1262 real_addr = (vm_paddr_t)fwd->forward; 1263 } 1264 break; 1265 } 1266 entry += rec_size; 1267 } 1268 pmap_unmapbios(va, map_size); 1269 1270 child = BUS_ADD_CHILD(parent, 5, "coreboot", DEVICE_UNIT_ANY); 1271 if (child == NULL) 1272 return; 1273 device_set_driver(child, driver); 1274 1275 bus_set_resource(child, SYS_RES_MEMORY, 0, real_addr, PAGE_SIZE); 1276 device_set_desc(child, "coreboot firmware table"); 1277 } 1278 1279 /* 1280 * Probe: validate the coreboot header at the discovered address 1281 */ 1282 static int 1283 coreboot_probe(device_t dev) 1284 { 1285 vm_paddr_t pa; 1286 void *va; 1287 vm_size_t map_size; 1288 int error; 1289 1290 pa = bus_get_resource_start(dev, SYS_RES_MEMORY, 0); 1291 if (pa == 0) 1292 return (ENXIO); 1293 1294 error = coreboot_map_table(pa, &va, &map_size); 1295 if (error != 0) 1296 return (error); 1297 1298 pmap_unmapbios(va, map_size); 1299 return (BUS_PROBE_SPECIFIC); 1300 } 1301 1302 /* 1303 * Attach: map the full table, parse records, register sysctls and cdevs 1304 */ 1305 static int 1306 coreboot_attach(device_t dev) 1307 { 1308 struct coreboot_softc *sc; 1309 struct cb_header *hdr; 1310 vm_paddr_t pa; 1311 void *va; 1312 vm_size_t map_size; 1313 int error; 1314 1315 sc = device_get_softc(dev); 1316 sc->dev = dev; 1317 1318 pa = bus_get_resource_start(dev, SYS_RES_MEMORY, 0); 1319 1320 error = coreboot_map_table(pa, &va, &map_size); 1321 if (error != 0) { 1322 device_printf(dev, "coreboot table validation failed at %#jx\n", 1323 (uintmax_t)pa); 1324 return (error); 1325 } 1326 1327 sc->table_paddr = pa; 1328 sc->table_size = map_size; 1329 sc->table_vaddr = va; 1330 1331 hdr = (struct cb_header *)va; 1332 device_printf(dev, "coreboot table at %#jx (%u entries, %u bytes)\n", 1333 (uintmax_t)pa, hdr->table_entries, hdr->table_bytes); 1334 1335 coreboot_parse_table(sc, hdr); 1336 1337 if (sc->version[0] != '\0') 1338 device_printf(dev, "firmware: %s\n", sc->version); 1339 if (sc->mb_vendor[0] != '\0') 1340 device_printf(dev, "mainboard: %s %s\n", sc->mb_vendor, 1341 sc->mb_part); 1342 if (sc->has_console) 1343 device_printf(dev, "CBMEM console at %#jx\n", 1344 (uintmax_t)sc->console_paddr); 1345 device_printf(dev, "CBMEM entries: %u\n", sc->cbmem_count); 1346 if (sc->has_board_config) 1347 device_printf(dev, 1348 "board: id=%u sku=%u fw_config=%#jx\n", 1349 sc->board_id, sc->sku_id, 1350 (uintmax_t)sc->fw_config); 1351 if (sc->mac_count > 0) 1352 device_printf(dev, "factory MAC addresses: %u\n", 1353 sc->mac_count); 1354 if (sc->has_acpi_rsdp) 1355 device_printf(dev, "ACPI RSDP at %#jx\n", 1356 (uintmax_t)sc->acpi_rsdp); 1357 if (sc->has_pcie) 1358 device_printf(dev, "PCIe controller at %#jx\n", 1359 (uintmax_t)sc->pcie_ctrl_base); 1360 if (sc->has_boot_media) 1361 device_printf(dev, "boot media: %#jx bytes, CBFS %#jx+%#jx\n", 1362 (uintmax_t)sc->boot_media_size, 1363 (uintmax_t)sc->cbfs_offset, (uintmax_t)sc->cbfs_size); 1364 if (sc->has_mmc_info) 1365 device_printf(dev, "MMC early CMD1 status: %d\n", 1366 sc->mmc_early_cmd1_status); 1367 1368 if (bootverbose) { 1369 if (sc->has_spi_flash) 1370 device_printf(dev, 1371 "SPI flash: %u bytes, sector %u, erase %#x\n", 1372 sc->spi_flash_size, sc->spi_sector_size, 1373 sc->spi_erase_cmd); 1374 if (sc->has_console_type) 1375 device_printf(dev, "console type: %u\n", 1376 sc->console_type); 1377 if (sc->has_framebuffer) 1378 device_printf(dev, 1379 "framebuffer: %ux%u@%ubpp at %#jx\n", 1380 sc->fb_x_res, sc->fb_y_res, sc->fb_bpp, 1381 (uintmax_t)sc->fb_addr); 1382 if (sc->gpio_count > 0) 1383 device_printf(dev, "GPIO pins: %u\n", 1384 sc->gpio_count); 1385 if (sc->has_tpm) 1386 device_printf(dev, "TPM %u.%u PPI at %#x\n", 1387 sc->tpm_version == 2 ? 2 : 1, 1388 sc->tpm_version == 2 ? 0 : 2, 1389 sc->tpm_ppi_addr); 1390 } 1391 1392 if (coreboot_debug) { 1393 if (sc->has_smmstore) 1394 device_printf(dev, 1395 "SMMSTORE v2: %u blocks x %u bytes, " 1396 "apm_cmd=%#x\n", 1397 sc->smmstore_num_blocks, 1398 sc->smmstore_block_size, 1399 sc->smmstore_apm_cmd); 1400 if (sc->has_timestamps) 1401 device_printf(dev, "timestamps at %#jx\n", 1402 (uintmax_t)sc->timestamps_paddr); 1403 if (sc->has_tpm_log) 1404 device_printf(dev, "TPM CB log at %#jx\n", 1405 (uintmax_t)sc->tpm_log_paddr); 1406 if (sc->has_fmap) 1407 device_printf(dev, "FMAP at %#jx\n", 1408 (uintmax_t)sc->fmap_paddr); 1409 } 1410 1411 coreboot_register_sysctls(sc); 1412 1413 coreboot_sc = sc; 1414 1415 if (sc->has_console) { 1416 error = coreboot_console_create(sc); 1417 if (error != 0) 1418 device_printf(dev, 1419 "failed to create /dev/coreboot_console (%d)\n", 1420 error); 1421 } 1422 if (sc->cbmem_count > 0) { 1423 error = coreboot_cbmem_create(sc); 1424 if (error != 0) 1425 device_printf(dev, "failed to create /dev/cbmem (%d)\n", 1426 error); 1427 } 1428 1429 return (0); 1430 } 1431 1432 /* 1433 * Detach: unmap table, destroy cdevs and sysctls 1434 */ 1435 static int 1436 coreboot_detach(device_t dev) 1437 { 1438 struct coreboot_softc *sc; 1439 1440 sc = device_get_softc(dev); 1441 1442 coreboot_cbmem_destroy(sc); 1443 coreboot_console_destroy(sc); 1444 1445 coreboot_sc = NULL; 1446 1447 sysctl_ctx_free(&sc->sysctl_ctx); 1448 1449 if (sc->table_vaddr != NULL) { 1450 pmap_unmapbios(sc->table_vaddr, sc->table_size); 1451 sc->table_vaddr = NULL; 1452 } 1453 1454 if (sc->console_vaddr != NULL) { 1455 pmap_unmapbios(sc->console_vaddr, sc->console_size); 1456 sc->console_vaddr = NULL; 1457 sc->console_size = 0; 1458 sc->console_data_size = 0; 1459 } 1460 1461 return (0); 1462 } 1463 1464 static int 1465 coreboot_modevent(module_t mod, int what, void *arg) 1466 { 1467 device_t *devs; 1468 int count, i; 1469 1470 switch (what) { 1471 case MOD_LOAD: 1472 break; 1473 case MOD_UNLOAD: 1474 devclass_get_devices(devclass_find("coreboot"), &devs, &count); 1475 for (i = 0; i < count; i++) 1476 device_delete_child(device_get_parent(devs[i]), 1477 devs[i]); 1478 free(devs, M_TEMP); 1479 break; 1480 default: 1481 break; 1482 } 1483 1484 return (0); 1485 } 1486 1487 static device_method_t coreboot_methods[] = { 1488 DEVMETHOD(device_identify, coreboot_identify), 1489 DEVMETHOD(device_probe, coreboot_probe), 1490 DEVMETHOD(device_attach, coreboot_attach), 1491 DEVMETHOD(device_detach, coreboot_detach), 1492 DEVMETHOD_END 1493 }; 1494 1495 static driver_t coreboot_driver = { 1496 "coreboot", 1497 coreboot_methods, 1498 sizeof(struct coreboot_softc), 1499 }; 1500 1501 DRIVER_MODULE(coreboot, nexus, coreboot_driver, coreboot_modevent, NULL); 1502 MODULE_VERSION(coreboot, 1); 1503