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