1 /* $OpenBSD: bios.c,v 1.130 2024/08/18 15:50:49 deraadt Exp $ */ 2 3 /* 4 * Copyright (c) 1997-2001 Michael Shalayeff 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 19 * IN NO EVENT SHALL THE AUTHOR OR HIS RELATIVES BE LIABLE FOR ANY DIRECT, 20 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 22 * SERVICES; LOSS OF MIND, USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 24 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 25 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 26 * THE POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29 /* #define BIOS_DEBUG */ 30 31 #include <sys/param.h> 32 #include <sys/systm.h> 33 #include <sys/device.h> 34 #include <sys/errno.h> 35 #include <sys/malloc.h> 36 #include <sys/reboot.h> 37 #include <sys/extent.h> 38 39 #include <uvm/uvm_extern.h> 40 #include <sys/sysctl.h> 41 42 #include <dev/cons.h> 43 #include <stand/boot/bootarg.h> 44 45 #include <machine/conf.h> 46 #include <machine/gdt.h> 47 #include <machine/biosvar.h> 48 #include <machine/mpbiosvar.h> 49 #include <machine/smbiosvar.h> 50 51 #include <dev/isa/isareg.h> 52 #include <i386/isa/isa_machdep.h> 53 54 #include <dev/pci/pcivar.h> 55 56 #include "apm.h" 57 #include "acpi.h" 58 #include "mpbios.h" 59 #include "pcibios.h" 60 #include "pci.h" 61 62 #include "com.h" 63 #if NCOM > 0 64 #include <sys/termios.h> 65 #include <dev/ic/comvar.h> 66 #endif 67 68 #include "softraid.h" 69 #if NSOFTRAID > 0 70 #include <dev/softraidvar.h> 71 #endif 72 73 struct bios_softc { 74 struct device sc_dev; 75 vaddr_t bios32_service_va; 76 }; 77 78 int biosprobe(struct device *, void *, void *); 79 void biosattach(struct device *, struct device *, void *); 80 int bios_print(void *, const char *); 81 char *fixstring(char *); 82 83 const struct cfattach bios_ca = { 84 sizeof(struct bios_softc), biosprobe, biosattach 85 }; 86 87 struct cfdriver bios_cd = { 88 NULL, "bios", DV_DULL 89 }; 90 91 extern dev_t bootdev; 92 93 #if NAPM > 0 || defined(DEBUG) 94 bios_apminfo_t *apm; 95 #endif 96 #if NPCI > 0 97 bios_pciinfo_t *bios_pciinfo; 98 #endif 99 bios_diskinfo_t *bios_diskinfo; 100 bios_memmap_t *bios_memmap; 101 struct bios_softc *bios_softc; 102 uint32_t bios_cksumlen; 103 struct bios32_entry bios32_entry; 104 struct smbios_entry smbios_entry; 105 #ifdef MULTIPROCESSOR 106 void *bios_smpinfo; 107 #endif 108 bios_bootmac_t *bios_bootmac; 109 #ifdef DDB 110 extern int db_console; 111 #endif 112 bios_ucode_t *bios_ucode; 113 114 void smbios_info(char*); 115 116 bios_diskinfo_t *bios_getdiskinfo(dev_t); 117 118 const char *smbios_uninfo[] = { 119 "System", 120 "Not ", 121 "To be", 122 "SYS-" 123 }; 124 125 126 char smbios_bios_date[64]; 127 char smbios_bios_version[64]; 128 char smbios_board_vendor[64]; 129 char smbios_board_prod[64]; 130 char smbios_board_serial[64]; 131 132 int 133 biosprobe(struct device *parent, void *match, void *aux) 134 { 135 struct bios_attach_args *bia = aux; 136 137 #ifdef BIOS_DEBUG 138 printf("%s%d: boot API ver %x, %x; args %p[%d]\n", 139 bia->ba_name, bios_cd.cd_ndevs, 140 bootapiver, BOOTARG_APIVER, bootargp, bootargc); 141 #endif 142 /* only one */ 143 if (bios_cd.cd_ndevs || strcmp(bia->ba_name, bios_cd.cd_name)) 144 return 0; 145 146 if (!(bootapiver & BAPIV_VECTOR) || bootargp == NULL) 147 return 0; 148 149 return 1; 150 } 151 152 void 153 biosattach(struct device *parent, struct device *self, void *aux) 154 { 155 struct bios_softc *sc = (struct bios_softc *)self; 156 #if (NPCI > 0 && NPCIBIOS > 0) || NAPM > 0 157 struct bios_attach_args *bia = aux; 158 #endif 159 struct smbios_struct_bios *sb; 160 struct smbtable bios; 161 volatile uint8_t *va; 162 char scratch[64], *str; 163 int flags, smbiosrev = 0, ncpu = 0, isa_hole_exec = 0; 164 #if NACPI > 0 || NAPM > 0 165 int usingacpi = 0; 166 #endif 167 168 bios_softc = sc; 169 /* remember flags */ 170 flags = sc->sc_dev.dv_cfdata->cf_flags; 171 172 va = ISA_HOLE_VADDR(0xffff0); 173 printf(": date %c%c/%c%c/%c%c", 174 va[5], va[6], va[8], va[9], va[11], va[12]); 175 176 /* 177 * Determining whether BIOS32 extensions are available is 178 * done by searching for the BIOS32 service directory. 179 * This 16-byte structure can be found somewhere in the 180 * range 0E0000h - 0FFFFFh and must be 16-byte aligned. 181 * 182 * _______________________________________________________ 183 * | Offset | Bytes | Description | 184 * |-------------------------------------------------------| 185 * | 0 | 4 | ASCII signature string of "_32_". | 186 * | 4 | 4 | 32-bit entry point. | 187 * | 8 | 1 | Revision Level. Typically 00h. | 188 * | 9 | 1 | Header length in 16-byte units. So | 189 * | | | would have the value of 01h. | 190 * | A | 1 | Checksum. The sum of all bytes in | 191 * | | | this header must be zero. | 192 * | B | 5 | Reserved. Set to zero. | 193 * ------------------------------------------------------- 194 * 195 * To find the service directory, we first search for the 196 * signature. If we find a match, we must also verify the 197 * checksum. This service directory may then be used to 198 * determine whether a PCI BIOS is present. 199 * 200 * For more information see the PCI BIOS Specification, 201 * Revision 2.1 (August 26, 1994). 202 */ 203 204 if (!(flags & BIOSF_BIOS32)) { 205 for (va = ISA_HOLE_VADDR(BIOS32_START); 206 va < (uint8_t *)ISA_HOLE_VADDR(BIOS32_END); va += 16) { 207 bios32_header_t h = (bios32_header_t)va; 208 uint8_t cksum; 209 int i; 210 211 if (h->signature != BIOS32_SIGNATURE) 212 continue; 213 214 /* verify checksum */ 215 for (cksum = 0, i = h->length * 16; i--; cksum += va[i]) 216 ; 217 if (cksum != 0) 218 continue; 219 220 if (h->entry <= BIOS32_START || h->entry >= BIOS32_END) 221 continue; 222 223 bios32_entry.segment = GSEL(GCODE_SEL, SEL_KPL); 224 bios32_entry.offset = (uint32_t)ISA_HOLE_VADDR(h->entry); 225 printf(", BIOS32 rev. %d @ 0x%x", h->rev, h->entry); 226 break; 227 } 228 } 229 230 /* see if we have SMBIOS extensions */ 231 if (!(flags & BIOSF_SMBIOS)) { 232 for (va = ISA_HOLE_VADDR(SMBIOS_START); 233 va < (uint8_t *)ISA_HOLE_VADDR(SMBIOS_END); va+= 16) { 234 struct smbhdr *sh = (struct smbhdr *)va; 235 char *sminfop; 236 uint8_t chksum; 237 vaddr_t eva; 238 paddr_t pa, end; 239 int i; 240 241 if (sh->sig != SMBIOS_SIGNATURE) 242 continue; 243 i = sh->len; 244 for (chksum = 0; i--; chksum += va[i]) 245 ; 246 if (chksum != 0) 247 continue; 248 va += 0x10; 249 if (!(va[0] == '_' && va[1] == 'D' && va[2] == 'M' && 250 va[3] == 'I' && va[4] == '_')) 251 continue; 252 for (chksum = 0, i = 0xf; i--; chksum += va[i]) 253 ; 254 if (chksum != 0) 255 continue; 256 257 pa = trunc_page(sh->addr); 258 end = round_page(sh->addr + sh->size); 259 eva = (vaddr_t)km_alloc(end - pa, &kv_any, 260 &kp_none, &kd_nowait); 261 if (eva == 0) 262 break; 263 264 smbios_entry.addr = (uint8_t *)(eva + 265 (sh->addr & PGOFSET)); 266 smbios_entry.len = sh->size; 267 smbios_entry.mjr = sh->majrev; 268 smbios_entry.min = sh->minrev; 269 smbios_entry.count = sh->count; 270 271 for (; pa < end; pa+= NBPG, eva+= NBPG) 272 pmap_kenter_pa(eva, pa, PROT_READ); 273 274 printf(", SMBIOS rev. %d.%d @ 0x%x (%hd entries)", 275 sh->majrev, sh->minrev, sh->addr, sh->count); 276 /* 277 * Unbelievably the SMBIOS version number 278 * sequence is like 2.3 ... 2.33 ... 2.4 ... 2.5 279 */ 280 smbiosrev = sh->majrev * 100 + sh->minrev; 281 if (sh->minrev < 10) 282 smbiosrev = sh->majrev * 100 + sh->minrev * 10; 283 284 bios.cookie = 0; 285 if (smbios_find_table(SMBIOS_TYPE_BIOS, &bios)) { 286 sb = bios.tblhdr; 287 printf("\n%s:", sc->sc_dev.dv_xname); 288 289 if ((smbios_get_string(&bios, sb->vendor, 290 scratch, sizeof(scratch))) != NULL) 291 printf(" vendor %s", 292 fixstring(scratch)); 293 if ((smbios_get_string(&bios, sb->version, 294 scratch, sizeof(scratch))) != NULL) { 295 sminfop = fixstring(scratch); 296 if (sminfop != NULL) { 297 strlcpy(smbios_bios_version, 298 sminfop, 299 sizeof(smbios_bios_version)); 300 printf(" version \"%s\"", 301 sminfop); 302 } 303 } 304 if ((smbios_get_string(&bios, sb->release, 305 scratch, sizeof(scratch))) != NULL) { 306 sminfop = fixstring(scratch); 307 if (sminfop != NULL) { 308 strlcpy(smbios_bios_date, 309 sminfop, 310 sizeof(smbios_bios_date)); 311 printf(" date %s", sminfop); 312 } 313 } 314 } 315 smbios_info(sc->sc_dev.dv_xname); 316 317 /* count cpus so that we can disable apm when cpu > 1 */ 318 bzero(&bios, sizeof(bios)); 319 while (smbios_find_table(SMBIOS_TYPE_PROCESSOR,&bios)) { 320 struct smbios_cpu *cpu = bios.tblhdr; 321 322 if (cpu->cpu_status & SMBIOS_CPUST_POPULATED) { 323 /* SMBIOS 2.5 added multicore support */ 324 if (smbiosrev >= 250 && 325 cpu->cpu_core_enabled) 326 ncpu += cpu->cpu_core_enabled; 327 else { 328 ncpu++; 329 if (cpu->cpu_id_edx & CPUID_HTT) 330 ncpu++; 331 } 332 } 333 } 334 break; 335 } 336 } 337 338 printf("\n"); 339 340 /* No SMBIOS extensions, go looking for Soekris comBIOS */ 341 if (!(flags & BIOSF_SMBIOS) && smbiosrev == 0) { 342 const char *signature = "Soekris Engineering"; 343 344 for (va = ISA_HOLE_VADDR(SMBIOS_START); 345 va <= (uint8_t *)ISA_HOLE_VADDR(SMBIOS_END - 346 (strlen(signature) - 1)); va++) 347 if (!memcmp((uint8_t *)va, signature, 348 strlen(signature))) { 349 hw_vendor = malloc(strlen(signature) + 1, 350 M_DEVBUF, M_NOWAIT); 351 if (hw_vendor) 352 strlcpy(hw_vendor, signature, 353 strlen(signature) + 1); 354 va += strlen(signature); 355 break; 356 } 357 358 for (; hw_vendor && 359 va <= (uint8_t *)ISA_HOLE_VADDR(SMBIOS_END - 6); va++) 360 /* 361 * Search for "net(4(5xx|801)|[56]501)" which matches 362 * the strings found in the comBIOS images 363 */ 364 if (!memcmp((uint8_t *)va, "net45xx", 7) || 365 !memcmp((uint8_t *)va, "net4801", 7) || 366 !memcmp((uint8_t *)va, "net5501", 7) || 367 !memcmp((uint8_t *)va, "net6501", 7)) { 368 hw_prod = malloc(8, M_DEVBUF, M_NOWAIT); 369 if (hw_prod) { 370 memcpy(hw_prod, (uint8_t *)va, 7); 371 hw_prod[7] = '\0'; 372 } 373 break; 374 } 375 } 376 377 #if NACPI > 0 378 #if NPCI > 0 379 if (smbiosrev >= 210 && pci_mode_detect() != 0) 380 #endif 381 { 382 struct bios_attach_args ba; 383 384 memset(&ba, 0, sizeof(ba)); 385 ba.ba_name = "acpi"; 386 ba.ba_func = 0x00; /* XXX ? */ 387 ba.ba_iot = I386_BUS_SPACE_IO; 388 ba.ba_memt = I386_BUS_SPACE_MEM; 389 if (config_found(self, &ba, bios_print)) { 390 flags |= BIOSF_PCIBIOS; 391 usingacpi = 1; 392 } 393 } 394 #endif 395 396 #if NAPM > 0 397 if (usingacpi == 0 && apm && ncpu < 2 && smbiosrev < 240) { 398 struct bios_attach_args ba; 399 400 #if defined(DEBUG) || defined(APMDEBUG) 401 printf("apminfo: %x, code %x[%x]/%x[%x], data %x[%x], ept %x\n", 402 apm->apm_detail, 403 apm->apm_code32_base, apm->apm_code_len, 404 apm->apm_code16_base, apm->apm_code16_len, 405 apm->apm_data_base, apm->apm_data_len, apm->apm_entry); 406 #endif 407 ba.ba_name = "apm"; 408 ba.ba_func = 0x15; 409 ba.ba_memt = bia->ba_memt; 410 ba.ba_iot = bia->ba_iot; 411 ba.ba_apmp = apm; 412 config_found(self, &ba, bios_print); 413 isa_hole_exec = 1; 414 } 415 #endif 416 417 418 #if NMPBIOS > 0 419 if (mpbios_probe(self)) { 420 struct bios_attach_args ba; 421 422 memset(&ba, 0, sizeof(ba)); 423 ba.ba_name = "mpbios"; 424 ba.ba_iot = I386_BUS_SPACE_IO; 425 ba.ba_memt = I386_BUS_SPACE_MEM; 426 427 config_found(self, &ba, bios_print); 428 } 429 #endif 430 431 #if NPCI > 0 && NPCIBIOS > 0 432 if (!(flags & BIOSF_PCIBIOS)) { 433 struct bios_attach_args ba; 434 435 ba.ba_name = "pcibios"; 436 ba.ba_func = 0x1A; 437 ba.ba_memt = bia->ba_memt; 438 ba.ba_iot = bia->ba_iot; 439 config_found(self, &ba, bios_print); 440 } 441 #endif 442 443 /* 444 * now that we gave 'em a chance to attach, 445 * scan and map all the proms we can find 446 */ 447 if (!(flags & BIOSF_PROMSCAN)) { 448 volatile uint8_t *eva; 449 450 for (str = NULL, va = ISA_HOLE_VADDR(0xc0000), 451 eva = ISA_HOLE_VADDR(0xf0000); 452 va < eva; va += 512) { 453 extern struct extent *iomem_ex; 454 bios_romheader_t romh = (bios_romheader_t)va; 455 uint32_t off, len; 456 uint8_t cksum; 457 int i; 458 459 if (romh->signature != 0xaa55) 460 continue; 461 462 /* 463 * for this and the next check we probably want 464 * to reserve the page in the extent anyway 465 */ 466 if (!romh->len || romh->len == 0xff) 467 continue; 468 469 len = romh->len * 512; 470 if (va + len > eva) 471 continue; 472 473 for (cksum = 0, i = len; i--; cksum += va[i]) 474 ; 475 off = 0xc0000 + (va - (uint8_t *) 476 ISA_HOLE_VADDR(0xc0000)); 477 478 if (!str) 479 printf("%s: ROM list:", 480 str = sc->sc_dev.dv_xname); 481 printf(" 0x%05x/0x%x%s", off, len, 482 cksum? "!" : ""); 483 484 if ((i = extent_alloc_region(iomem_ex, 485 (paddr_t)off, len, EX_NOWAIT))) 486 printf(":%d", i); 487 488 isa_hole_exec = 1; 489 va += len - 512; 490 } 491 if (str) 492 printf("\n"); 493 } 494 495 /* 496 * If we had no BIOS / proms that need exec permission in the ISA 497 * hole, remove X permissions. 498 */ 499 if (!isa_hole_exec) 500 pmap_write_protect(pmap_kernel(), (vaddr_t)atdevbase, 501 (vaddr_t)atdevbase + IOM_SIZE, PROT_READ | PROT_WRITE); 502 } 503 504 void 505 bios_getopt(void) 506 { 507 bootarg_t *q; 508 bios_ddb_t *bios_ddb; 509 bios_bootduid_t *bios_bootduid; 510 bios_bootsr_t *bios_bootsr; 511 512 #ifdef BIOS_DEBUG 513 printf("bootargv:"); 514 #endif 515 516 for(q = bootargp; q->ba_type != BOOTARG_END; q = q->ba_next) { 517 q->ba_next = (bootarg_t *)((caddr_t)q + q->ba_size); 518 switch (q->ba_type) { 519 case BOOTARG_MEMMAP: 520 bios_memmap = (bios_memmap_t *)q->ba_arg; 521 #ifdef BIOS_DEBUG 522 printf(" memmap %p", bios_memmap); 523 #endif 524 break; 525 case BOOTARG_DISKINFO: 526 bios_diskinfo = (bios_diskinfo_t *)q->ba_arg; 527 #ifdef BIOS_DEBUG 528 printf(" diskinfo %p", bios_diskinfo); 529 #endif 530 break; 531 #if NAPM > 0 || defined(DEBUG) 532 case BOOTARG_APMINFO: 533 #ifdef BIOS_DEBUG 534 printf(" apminfo %p", q->ba_arg); 535 #endif 536 apm = (bios_apminfo_t *)q->ba_arg; 537 break; 538 #endif 539 case BOOTARG_CKSUMLEN: 540 bios_cksumlen = *(uint32_t *)q->ba_arg; 541 #ifdef BIOS_DEBUG 542 printf(" cksumlen %d", bios_cksumlen); 543 #endif 544 break; 545 #if NPCI > 0 546 case BOOTARG_PCIINFO: 547 bios_pciinfo = (bios_pciinfo_t *)q->ba_arg; 548 #ifdef BIOS_DEBUG 549 printf(" pciinfo %p", bios_pciinfo); 550 #endif 551 break; 552 #endif 553 case BOOTARG_CONSDEV: 554 if (q->ba_size >= sizeof(bios_consdev_t) + 555 offsetof(bootarg_t, ba_arg)) { 556 bios_consdev_t *cdp = 557 (bios_consdev_t*)q->ba_arg; 558 #if NCOM > 0 559 static const int ports[] = 560 { 0x3f8, 0x2f8, 0x3e8, 0x2e8 }; 561 int unit = minor(cdp->consdev); 562 int consaddr = cdp->consaddr; 563 if (consaddr == -1 && unit >=0 && 564 unit < (sizeof(ports)/sizeof(ports[0]))) 565 consaddr = ports[unit]; 566 if (major(cdp->consdev) == 8 && 567 consaddr != -1) { 568 comconsunit = unit; 569 comconsaddr = consaddr; 570 comconsrate = cdp->conspeed; 571 comconsiot = I386_BUS_SPACE_IO; 572 573 /* Probe the serial port this time. */ 574 cninit(); 575 } 576 #endif 577 #ifdef BIOS_DEBUG 578 printf(" console 0x%x:%d", 579 cdp->consdev, cdp->conspeed); 580 #endif 581 } 582 break; 583 #ifdef MULTIPROCESSOR 584 case BOOTARG_SMPINFO: 585 bios_smpinfo = q->ba_arg; 586 printf(" smpinfo %p", bios_smpinfo); 587 break; 588 #endif 589 590 case BOOTARG_BOOTMAC: 591 bios_bootmac = (bios_bootmac_t *)q->ba_arg; 592 break; 593 594 case BOOTARG_DDB: 595 bios_ddb = (bios_ddb_t *)q->ba_arg; 596 #ifdef DDB 597 db_console = bios_ddb->db_console; 598 #endif 599 break; 600 601 case BOOTARG_BOOTDUID: 602 bios_bootduid = (bios_bootduid_t *)q->ba_arg; 603 bcopy(bios_bootduid, bootduid, sizeof(bootduid)); 604 break; 605 606 case BOOTARG_BOOTSR: 607 bios_bootsr = (bios_bootsr_t *)q->ba_arg; 608 #if NSOFTRAID > 0 609 bcopy(&bios_bootsr->uuid, &sr_bootuuid, 610 sizeof(sr_bootuuid)); 611 bcopy(&bios_bootsr->maskkey, &sr_bootkey, 612 sizeof(sr_bootkey)); 613 #endif 614 explicit_bzero(bios_bootsr, sizeof(bios_bootsr_t)); 615 break; 616 617 case BOOTARG_UCODE: 618 bios_ucode = (bios_ucode_t *)q->ba_arg; 619 break; 620 621 default: 622 #ifdef BIOS_DEBUG 623 printf(" unsupported arg (%d) %p", q->ba_type, 624 q->ba_arg); 625 #endif 626 break; 627 } 628 } 629 printf("\n"); 630 631 } 632 633 int 634 bios_print(void *aux, const char *pnp) 635 { 636 struct bios_attach_args *ba = aux; 637 638 if (pnp) 639 printf("%s at %s function 0x%x", 640 ba->ba_name, pnp, ba->ba_func); 641 return (UNCONF); 642 } 643 644 int 645 bios32_service(uint32_t service, bios32_entry_t e, bios32_entry_info_t ei) 646 { 647 u_long pa, endpa; 648 vaddr_t va, sva; 649 uint32_t base, count, off, ent; 650 651 if (bios32_entry.offset == 0) 652 return 0; 653 654 base = 0; 655 __asm volatile("lcall *(%4)" 656 : "+a" (service), "+b" (base), "=c" (count), "=d" (off) 657 : "D" (&bios32_entry) 658 : "%esi", "cc", "memory"); 659 660 if (service & 0xff) 661 return 0; /* not found */ 662 663 ent = base + off; 664 if (ent <= BIOS32_START || ent >= BIOS32_END) 665 return 0; 666 667 endpa = round_page(BIOS32_END); 668 669 sva = va = (vaddr_t)km_alloc(endpa, &kv_any, &kp_none, &kd_nowait); 670 if (va == 0) 671 return (0); 672 673 /* Store bios32 service kva for cleanup later */ 674 bios_softc->bios32_service_va = sva; 675 676 setgdt(GBIOS32_SEL, (caddr_t)va, BIOS32_END, SDT_MEMERA, SEL_KPL, 1, 0); 677 678 for (pa = trunc_page(BIOS32_START), 679 va += trunc_page(BIOS32_START); 680 pa < endpa; pa += NBPG, va += NBPG) { 681 pmap_enter(pmap_kernel(), va, pa, 682 PROT_READ | PROT_WRITE | PROT_EXEC, 683 PROT_READ | PROT_WRITE | PROT_EXEC | PMAP_WIRED); 684 685 if (pa >= trunc_page(base)) { 686 pmap_enter(pmap_kernel(), sva, pa, 687 PROT_READ | PROT_WRITE | PROT_EXEC, 688 PROT_READ | PROT_WRITE | PROT_EXEC | PMAP_WIRED); 689 sva += NBPG; 690 } 691 } 692 693 e->segment = GSEL(GBIOS32_SEL, SEL_KPL); 694 e->offset = (vaddr_t)ent; 695 696 ei->bei_base = base; 697 ei->bei_size = count; 698 ei->bei_entry = ent; 699 700 return 1; 701 } 702 703 void 704 bios32_cleanup(void) 705 { 706 u_long pa, size; 707 vaddr_t va; 708 709 size = round_page(BIOS32_END); 710 711 for (va = bios_softc->bios32_service_va; 712 va < bios_softc->bios32_service_va + size; 713 va += NBPG) { 714 if (pmap_extract(pmap_kernel(), va, &pa)) 715 pmap_remove(pmap_kernel(), va, va + PAGE_SIZE); 716 } 717 718 km_free((void *)bios_softc->bios32_service_va, size, 719 &kv_any, &kp_none); 720 } 721 722 int 723 biosopen(dev_t dev, int flag, int mode, struct proc *p) 724 { 725 struct bios_softc *sc = bios_cd.cd_devs[0]; 726 727 if (minor(dev)) 728 return (ENXIO); 729 730 (void)sc; 731 732 return 0; 733 } 734 735 int 736 biosclose(dev_t dev, int flag, int mode, struct proc *p) 737 { 738 struct bios_softc *sc = bios_cd.cd_devs[0]; 739 740 if (minor(dev)) 741 return (ENXIO); 742 743 (void)sc; 744 745 return 0; 746 } 747 748 int 749 biosioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p) 750 { 751 struct bios_softc *sc = bios_cd.cd_devs[0]; 752 753 if (minor(dev)) 754 return (ENXIO); 755 756 switch (cmd) { 757 default: 758 return ENXIO; 759 } 760 761 (void)sc; 762 763 return 0; 764 } 765 766 int 767 bios_sysctl(int *name, u_int namelen, void *oldp, size_t *oldlenp, void *newp, 768 size_t newlen, struct proc *p) 769 { 770 bios_diskinfo_t *pdi; 771 int biosdev; 772 773 /* all sysctl names at this level except diskinfo are terminal */ 774 if (namelen != 1 && name[0] != BIOS_DISKINFO) 775 return (ENOTDIR); /* overloaded */ 776 777 if (!(bootapiver & BAPIV_VECTOR)) 778 return EOPNOTSUPP; 779 780 switch (name[0]) { 781 case BIOS_DEV: 782 if ((pdi = bios_getdiskinfo(bootdev)) == NULL) 783 return ENXIO; 784 biosdev = pdi->bios_number; 785 return sysctl_rdint(oldp, oldlenp, newp, biosdev); 786 case BIOS_DISKINFO: 787 if (namelen != 2) 788 return ENOTDIR; 789 if ((pdi = bios_getdiskinfo(name[1])) == NULL) 790 return ENXIO; 791 return sysctl_rdstruct(oldp, oldlenp, newp, pdi, sizeof(*pdi)); 792 case BIOS_CKSUMLEN: 793 return sysctl_rdint(oldp, oldlenp, newp, bios_cksumlen); 794 default: 795 return EOPNOTSUPP; 796 } 797 /* NOTREACHED */ 798 } 799 800 bios_diskinfo_t * 801 bios_getdiskinfo(dev_t dev) 802 { 803 bios_diskinfo_t *pdi; 804 805 if (bios_diskinfo == NULL) 806 return NULL; 807 808 for (pdi = bios_diskinfo; pdi->bios_number != -1; pdi++) { 809 if ((dev & B_MAGICMASK) == B_DEVMAGIC) { /* search by bootdev */ 810 if (pdi->bsd_dev == dev) 811 break; 812 } else { 813 if (pdi->bios_number == dev) 814 break; 815 } 816 } 817 818 if (pdi->bios_number == -1) 819 return NULL; 820 else 821 return pdi; 822 } 823 824 /* 825 * smbios_find_table() takes a caller supplied smbios struct type and 826 * a pointer to a handle (struct smbtable) returning one if the structure 827 * is successfully located and zero otherwise. Callers should take care 828 * to initialize the cookie field of the smbtable structure to zero before 829 * the first invocation of this function. 830 * Multiple tables of the same type can be located by repeatedly calling 831 * smbios_find_table with the same arguments. 832 */ 833 int 834 smbios_find_table(uint8_t type, struct smbtable *st) 835 { 836 uint8_t *va, *end; 837 struct smbtblhdr *hdr; 838 int ret = 0, tcount = 1; 839 840 va = smbios_entry.addr; 841 end = va + smbios_entry.len; 842 843 /* 844 * The cookie field of the smtable structure is used to locate 845 * multiple instances of a table of an arbitrary type. Following the 846 * successful location of a table, the type is encoded as bits 0:7 of 847 * the cookie value, the offset in terms of the number of structures 848 * preceding that referenced by the handle is encoded in bits 15:31. 849 */ 850 if ((st->cookie & 0xfff) == type && st->cookie >> 16) { 851 if ((uint8_t *)st->hdr >= va && (uint8_t *)st->hdr < end) { 852 hdr = st->hdr; 853 if (hdr->type == type) { 854 va = (uint8_t *)hdr + hdr->size; 855 for (; va + 1 < end; va++) 856 if (*va == 0 && *(va + 1) == 0) 857 break; 858 va += 2; 859 tcount = st->cookie >> 16; 860 } 861 } 862 } 863 for (; va + sizeof(struct smbtblhdr) < end && 864 tcount <= smbios_entry.count; tcount++) { 865 hdr = (struct smbtblhdr *)va; 866 if (hdr->type == type) { 867 ret = 1; 868 st->hdr = hdr; 869 st->tblhdr = va + sizeof(struct smbtblhdr); 870 st->cookie = (tcount + 1) << 16 | type; 871 break; 872 } 873 if (hdr->type == SMBIOS_TYPE_EOT) 874 break; 875 va += hdr->size; 876 for (; va + 1 < end; va++) 877 if (*va == 0 && *(va + 1) == 0) 878 break; 879 va += 2; 880 } 881 return ret; 882 } 883 884 char * 885 smbios_get_string(struct smbtable *st, uint8_t indx, char *dest, size_t len) 886 { 887 uint8_t *va, *end; 888 char *ret = NULL; 889 int i; 890 891 va = (uint8_t *)st->hdr + st->hdr->size; 892 end = smbios_entry.addr + smbios_entry.len; 893 for (i = 1; va < end && i < indx && *va; i++) 894 while (*va++) 895 ; 896 if (i == indx) { 897 if (va + len < end) { 898 ret = dest; 899 memcpy(ret, va, len); 900 ret[len - 1] = '\0'; 901 } 902 } 903 904 return ret; 905 } 906 907 char * 908 fixstring(char *s) 909 { 910 char *p, *e; 911 int i; 912 913 for (i = 0; i < nitems(smbios_uninfo); i++) 914 if ((strncasecmp(s, smbios_uninfo[i], 915 strlen(smbios_uninfo[i]))) == 0) 916 return NULL; 917 /* 918 * Remove leading and trailing whitespace 919 */ 920 for (p = s; *p == ' '; p++) 921 ; 922 /* 923 * Special case entire string is whitespace 924 */ 925 if (p == s + strlen(s)) 926 return NULL; 927 for (e = s + strlen(s) - 1; e > s && *e == ' '; e--) 928 ; 929 if (p > s || e < s + strlen(s) - 1) { 930 memmove(s, p, e - p + 1); 931 s[e - p + 1] = '\0'; 932 } 933 934 return s; 935 } 936 937 void 938 smbios_info(char *str) 939 { 940 char *sminfop, sminfo[64]; 941 struct smbtable stbl, btbl; 942 struct smbios_sys *sys; 943 struct smbios_board *board; 944 int i, infolen, uuidf, havebb; 945 char *p; 946 947 if (smbios_entry.mjr < 2) 948 return; 949 /* 950 * According to the spec the system table among others is required, 951 * if it is not we do not bother with this smbios implementation. 952 */ 953 stbl.cookie = btbl.cookie = 0; 954 if (!smbios_find_table(SMBIOS_TYPE_SYSTEM, &stbl)) 955 return; 956 havebb = smbios_find_table(SMBIOS_TYPE_BASEBOARD, &btbl); 957 958 sys = (struct smbios_sys *)stbl.tblhdr; 959 if (havebb) { 960 board = (struct smbios_board *)btbl.tblhdr; 961 962 sminfop = NULL; 963 if ((p = smbios_get_string(&btbl, board->vendor, 964 sminfo, sizeof(sminfo))) != NULL) 965 sminfop = fixstring(p); 966 if (sminfop) 967 strlcpy(smbios_board_vendor, sminfop, 968 sizeof(smbios_board_vendor)); 969 970 sminfop = NULL; 971 if ((p = smbios_get_string(&btbl, board->product, 972 sminfo, sizeof(sminfo))) != NULL) 973 sminfop = fixstring(p); 974 if (sminfop) 975 strlcpy(smbios_board_prod, sminfop, 976 sizeof(smbios_board_prod)); 977 978 sminfop = NULL; 979 if ((p = smbios_get_string(&btbl, board->serial, 980 sminfo, sizeof(sminfo))) != NULL) 981 sminfop = fixstring(p); 982 if (sminfop) 983 strlcpy(smbios_board_serial, sminfop, 984 sizeof(smbios_board_serial)); 985 } 986 987 /* 988 * Some smbios implementations have no system vendor or 989 * product strings, some have very uninformative data which is 990 * harder to work around and we must rely upon various 991 * heuristics to detect this. In both cases we attempt to fall 992 * back on the base board information in the perhaps naive 993 * belief that motherboard vendors will supply this 994 * information. 995 */ 996 sminfop = NULL; 997 if ((p = smbios_get_string(&stbl, sys->vendor, sminfo, 998 sizeof(sminfo))) != NULL) 999 sminfop = fixstring(p); 1000 if (sminfop == NULL) { 1001 if (havebb) { 1002 if ((p = smbios_get_string(&btbl, board->vendor, 1003 sminfo, sizeof(sminfo))) != NULL) 1004 sminfop = fixstring(p); 1005 } 1006 } 1007 if (sminfop) { 1008 infolen = strlen(sminfop) + 1; 1009 hw_vendor = malloc(infolen, M_DEVBUF, M_NOWAIT); 1010 if (hw_vendor) 1011 strlcpy(hw_vendor, sminfop, infolen); 1012 sminfop = NULL; 1013 } 1014 if ((p = smbios_get_string(&stbl, sys->product, sminfo, 1015 sizeof(sminfo))) != NULL) 1016 sminfop = fixstring(p); 1017 if (sminfop == NULL) { 1018 if (havebb) { 1019 if ((p = smbios_get_string(&btbl, board->product, 1020 sminfo, sizeof(sminfo))) != NULL) 1021 sminfop = fixstring(p); 1022 } 1023 } 1024 if (sminfop) { 1025 infolen = strlen(sminfop) + 1; 1026 hw_prod = malloc(infolen, M_DEVBUF, M_NOWAIT); 1027 if (hw_prod) 1028 strlcpy(hw_prod, sminfop, infolen); 1029 sminfop = NULL; 1030 } 1031 if (hw_vendor != NULL && hw_prod != NULL) 1032 printf("\n%s: %s %s", str, hw_vendor, hw_prod); 1033 if ((p = smbios_get_string(&stbl, sys->version, sminfo, 1034 sizeof(sminfo))) != NULL) 1035 sminfop = fixstring(p); 1036 if (sminfop) { 1037 infolen = strlen(sminfop) + 1; 1038 hw_ver = malloc(infolen, M_DEVBUF, M_NOWAIT); 1039 if (hw_ver) 1040 strlcpy(hw_ver, sminfop, infolen); 1041 sminfop = NULL; 1042 } 1043 if ((p = smbios_get_string(&stbl, sys->serial, sminfo, 1044 sizeof(sminfo))) != NULL) 1045 sminfop = fixstring(p); 1046 if (sminfop) { 1047 infolen = strlen(sminfop) + 1; 1048 for (i = 0; i < infolen - 1; i++) 1049 enqueue_randomness(sminfop[i]); 1050 hw_serial = malloc(infolen, M_DEVBUF, M_NOWAIT); 1051 if (hw_serial) 1052 strlcpy(hw_serial, sminfop, infolen); 1053 } 1054 if (smbios_entry.mjr > 2 || (smbios_entry.mjr == 2 && 1055 smbios_entry.min >= 1)) { 1056 /* 1057 * If the uuid value is all 0xff the uuid is present but not 1058 * set, if its all 0 then the uuid isn't present at all. 1059 */ 1060 uuidf = SMBIOS_UUID_NPRESENT|SMBIOS_UUID_NSET; 1061 for (i = 0; i < sizeof(sys->uuid); i++) { 1062 if (sys->uuid[i] != 0xff) 1063 uuidf &= ~SMBIOS_UUID_NSET; 1064 if (sys->uuid[i] != 0) 1065 uuidf &= ~SMBIOS_UUID_NPRESENT; 1066 } 1067 1068 if (uuidf & SMBIOS_UUID_NPRESENT) 1069 hw_uuid = NULL; 1070 else if (uuidf & SMBIOS_UUID_NSET) 1071 hw_uuid = "Not Set"; 1072 else { 1073 for (i = 0; i < sizeof(sys->uuid); i++) 1074 enqueue_randomness(sys->uuid[i]); 1075 hw_uuid = malloc(SMBIOS_UUID_REPLEN, M_DEVBUF, 1076 M_NOWAIT); 1077 if (hw_uuid) { 1078 snprintf(hw_uuid, SMBIOS_UUID_REPLEN, 1079 SMBIOS_UUID_REP, 1080 sys->uuid[0], sys->uuid[1], sys->uuid[2], 1081 sys->uuid[3], sys->uuid[4], sys->uuid[5], 1082 sys->uuid[6], sys->uuid[7], sys->uuid[8], 1083 sys->uuid[9], sys->uuid[10], sys->uuid[11], 1084 sys->uuid[12], sys->uuid[13], sys->uuid[14], 1085 sys->uuid[15]); 1086 } 1087 } 1088 } 1089 } 1090