Annotation of sys/arch/i386/i386/bios.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: bios.c,v 1.70 2007/08/06 16:12:25 gwk 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/kernel.h>
! 34: #include <sys/device.h>
! 35: #include <sys/errno.h>
! 36: #include <sys/proc.h>
! 37: #include <sys/malloc.h>
! 38: #include <sys/reboot.h>
! 39: #include <sys/extent.h>
! 40:
! 41: #include <uvm/uvm_extern.h>
! 42: #include <sys/sysctl.h>
! 43:
! 44: #include <dev/cons.h>
! 45: #include <stand/boot/bootarg.h>
! 46:
! 47: #include <machine/cpu.h>
! 48: #include <machine/pio.h>
! 49: #include <machine/cpufunc.h>
! 50: #include <machine/conf.h>
! 51: #include <machine/gdt.h>
! 52: #include <machine/pcb.h>
! 53: #include <machine/biosvar.h>
! 54: #include <machine/apmvar.h>
! 55: #include <machine/smbiosvar.h>
! 56:
! 57: #include <dev/isa/isareg.h>
! 58: #include <i386/isa/isa_machdep.h>
! 59:
! 60: #include "apm.h"
! 61: #include "pcibios.h"
! 62: #include "pci.h"
! 63:
! 64: struct bios_softc {
! 65: struct device sc_dev;
! 66: };
! 67:
! 68: int biosprobe(struct device *, void *, void *);
! 69: void biosattach(struct device *, struct device *, void *);
! 70: int bios_print(void *, const char *);
! 71: char *fixstring(char *);
! 72:
! 73: struct cfattach bios_ca = {
! 74: sizeof(struct bios_softc), biosprobe, biosattach
! 75: };
! 76:
! 77: struct cfdriver bios_cd = {
! 78: NULL, "bios", DV_DULL
! 79: };
! 80:
! 81: extern dev_t bootdev;
! 82:
! 83: #if NAPM > 0 || defined(DEBUG)
! 84: bios_apminfo_t *apm;
! 85: #endif
! 86: #if NPCI > 0
! 87: bios_pciinfo_t *bios_pciinfo;
! 88: #endif
! 89: bios_diskinfo_t *bios_diskinfo;
! 90: bios_memmap_t *bios_memmap;
! 91: u_int32_t bios_cksumlen;
! 92: struct bios32_entry bios32_entry;
! 93: struct smbios_entry smbios_entry;
! 94: #ifdef MULTIPROCESSOR
! 95: void *bios_smpinfo;
! 96: #endif
! 97: #ifdef NFSCLIENT
! 98: bios_bootmac_t *bios_bootmac;
! 99: #endif
! 100:
! 101: void smbios_info(char*);
! 102:
! 103: bios_diskinfo_t *bios_getdiskinfo(dev_t);
! 104:
! 105: /*
! 106: * used by hw_sysctl
! 107: */
! 108: extern char *hw_vendor, *hw_prod, *hw_uuid, *hw_serial, *hw_ver;
! 109: const char *smbios_uninfo[] = {
! 110: "System",
! 111: "Not ",
! 112: "To be",
! 113: "SYS-"
! 114: };
! 115:
! 116:
! 117: int
! 118: biosprobe(struct device *parent, void *match, void *aux)
! 119: {
! 120: struct bios_attach_args *bia = aux;
! 121:
! 122: #ifdef BIOS_DEBUG
! 123: printf("%s%d: boot API ver %x, %x; args %p[%d]\n",
! 124: bia->bios_dev, bios_cd.cd_ndevs,
! 125: bootapiver, BOOTARG_APIVER, bootargp, bootargc);
! 126: #endif
! 127: /* there could be only one */
! 128: if (bios_cd.cd_ndevs || strcmp(bia->bios_dev, bios_cd.cd_name))
! 129: return 0;
! 130:
! 131: if (!(bootapiver & BAPIV_VECTOR) || bootargp == NULL)
! 132: return 0;
! 133:
! 134: return 1;
! 135: }
! 136:
! 137: void
! 138: biosattach(struct device *parent, struct device *self, void *aux)
! 139: {
! 140: struct bios_softc *sc = (struct bios_softc *)self;
! 141: #if (NPCI > 0 && NPCIBIOS > 0) || NAPM > 0
! 142: struct bios_attach_args *bia = aux;
! 143: #endif
! 144: struct smbios_struct_bios *sb;
! 145: struct smbtable bios;
! 146: volatile u_int8_t *va;
! 147: char scratch[64], *str;
! 148: int flags;
! 149:
! 150: /* remember flags */
! 151: flags = sc->sc_dev.dv_cfdata->cf_flags;
! 152:
! 153: va = ISA_HOLE_VADDR(0xffff0);
! 154: switch (va[14]) {
! 155: default:
! 156: case 0xff: str = "PC"; break;
! 157: case 0xfe: str = "PC/XT"; break;
! 158: case 0xfd: str = "PCjr"; break;
! 159: case 0xfc: str = "AT/286+"; break;
! 160: case 0xfb: str = "PC/XT+"; break;
! 161: case 0xfa: str = "PS/2 25/30"; break;
! 162: case 0xf9: str = "PC Convertible";break;
! 163: case 0xf8: str = "PS/2 386+"; break;
! 164: }
! 165: printf(": %s BIOS, date %c%c/%c%c/%c%c",
! 166: str, va[5], va[6], va[8], va[9], va[11], va[12]);
! 167:
! 168: /*
! 169: * Determining whether BIOS32 extensions are available is
! 170: * done by searching for the BIOS32 service directory.
! 171: * This 16-byte structure can be found somewhere in the
! 172: * range 0E0000h - 0FFFFFh and must be 16-byte aligned.
! 173: *
! 174: * _______________________________________________________
! 175: * | Offset | Bytes | Description |
! 176: * |-------------------------------------------------------|
! 177: * | 0 | 4 | ASCII signature string of "_32_". |
! 178: * | 4 | 4 | 32-bit entry point. |
! 179: * | 8 | 1 | Revision Level. Typically 00h. |
! 180: * | 9 | 1 | Header length in 16-byte units. So |
! 181: * | | | would have the value of 01h. |
! 182: * | A | 1 | Checksum. The sum of all bytes in |
! 183: * | | | this header must be zero. |
! 184: * | B | 5 | Reserved. Set to zero. |
! 185: * -------------------------------------------------------
! 186: *
! 187: * To find the service directory, we first search for the
! 188: * signature. If we find a match, we must also verify the
! 189: * checksum. This service directory may then be used to
! 190: * determine whether a PCI BIOS is present.
! 191: *
! 192: * For more information see the PCI BIOS Specification,
! 193: * Revision 2.1 (August 26, 1994).
! 194: */
! 195:
! 196: if (!(flags & BIOSF_BIOS32)) {
! 197: for (va = ISA_HOLE_VADDR(BIOS32_START);
! 198: va < (u_int8_t *)ISA_HOLE_VADDR(BIOS32_END); va += 16) {
! 199: bios32_header_t h = (bios32_header_t)va;
! 200: u_int8_t cksum;
! 201: int i;
! 202:
! 203: if (h->signature != BIOS32_SIGNATURE)
! 204: continue;
! 205:
! 206: /* verify checksum */
! 207: for (cksum = 0, i = h->length * 16; i--; cksum += va[i])
! 208: ;
! 209: if (cksum != 0)
! 210: continue;
! 211:
! 212: if (h->entry <= BIOS32_START || h->entry >= BIOS32_END)
! 213: continue;
! 214:
! 215: bios32_entry.segment = GSEL(GCODE_SEL, SEL_KPL);
! 216: bios32_entry.offset = (u_int32_t)ISA_HOLE_VADDR(h->entry);
! 217: printf(", BIOS32 rev. %d @ 0x%lx", h->rev, h->entry);
! 218: break;
! 219: }
! 220: }
! 221:
! 222: /* see if we have SMBIOS extensions */
! 223: if (!(flags & BIOSF_SMBIOS)) {
! 224: for (va = ISA_HOLE_VADDR(SMBIOS_START);
! 225: va < (u_int8_t *)ISA_HOLE_VADDR(SMBIOS_END); va+= 16) {
! 226: struct smbhdr * sh = (struct smbhdr *)va;
! 227: u_int8_t chksum;
! 228: vaddr_t eva;
! 229: paddr_t pa, end;
! 230: int i;
! 231:
! 232: if (sh->sig != SMBIOS_SIGNATURE)
! 233: continue;
! 234: i = sh->len;
! 235: for (chksum = 0; i--; chksum += va[i])
! 236: ;
! 237: if (chksum != 0)
! 238: continue;
! 239: va += 0x10;
! 240: if (va[0] != '_' && va[1] != 'D' && va[2] != 'M' &&
! 241: va[3] != 'I' && va[4] != '_')
! 242: continue;
! 243: for (chksum = 0, i = 0xf; i--; chksum += va[i]);
! 244: ;
! 245: if (chksum != 0)
! 246: continue;
! 247:
! 248: pa = trunc_page(sh->addr);
! 249: end = round_page(sh->addr + sh->size);
! 250: eva = uvm_km_valloc(kernel_map, end-pa);
! 251: if (eva == 0)
! 252: break;
! 253:
! 254: smbios_entry.addr = (u_int8_t *)(eva +
! 255: (sh->addr & PGOFSET));
! 256: smbios_entry.len = sh->size;
! 257: smbios_entry.mjr = sh->majrev;
! 258: smbios_entry.min = sh->minrev;
! 259: smbios_entry.count = sh->count;
! 260:
! 261: for (; pa < end; pa+= NBPG, eva+= NBPG)
! 262: pmap_kenter_pa(eva, pa, VM_PROT_READ);
! 263:
! 264: printf(", SMBIOS rev. %d.%d @ 0x%lx (%d entries)",
! 265: sh->majrev, sh->minrev, sh->addr, sh->count);
! 266:
! 267: bios.cookie = 0;
! 268: if (smbios_find_table(SMBIOS_TYPE_BIOS, &bios)) {
! 269: sb = bios.tblhdr;
! 270: printf("\n%s:", sc->sc_dev.dv_xname);
! 271:
! 272: if ((smbios_get_string(&bios, sb->vendor,
! 273: scratch, sizeof(scratch))) != NULL)
! 274: printf(" vendor %s", scratch);
! 275: if ((smbios_get_string(&bios, sb->version,
! 276: scratch, sizeof(scratch))) != NULL)
! 277: printf(" version \"%s\"", scratch);
! 278: if ((smbios_get_string(&bios, sb->release,
! 279: scratch, sizeof(scratch))) != NULL)
! 280: printf(" date %s", scratch);
! 281: }
! 282: smbios_info(sc->sc_dev.dv_xname);
! 283: break;
! 284: }
! 285: }
! 286:
! 287: printf("\n");
! 288:
! 289: #if NAPM > 0
! 290: if (apm) {
! 291: struct bios_attach_args ba;
! 292: #if defined(DEBUG) || defined(APMDEBUG)
! 293: printf("apminfo: %x, code %x[%x]/%x[%x], data %x[%x], ept %x\n",
! 294: apm->apm_detail,
! 295: apm->apm_code32_base, apm->apm_code_len,
! 296: apm->apm_code16_base, apm->apm_code16_len,
! 297: apm->apm_data_base, apm->apm_data_len, apm->apm_entry);
! 298: #endif
! 299: ba.bios_dev = "apm";
! 300: ba.bios_func = 0x15;
! 301: ba.bios_memt = bia->bios_memt;
! 302: ba.bios_iot = bia->bios_iot;
! 303: ba.bios_apmp = apm;
! 304: config_found(self, &ba, bios_print);
! 305: }
! 306: #endif
! 307: #if NPCI > 0 && NPCIBIOS > 0
! 308: if (!(flags & BIOSF_PCIBIOS)) {
! 309: struct bios_attach_args ba;
! 310:
! 311: ba.bios_dev = "pcibios";
! 312: ba.bios_func = 0x1A;
! 313: ba.bios_memt = bia->bios_memt;
! 314: ba.bios_iot = bia->bios_iot;
! 315: config_found(self, &ba, bios_print);
! 316: }
! 317: #endif
! 318:
! 319: /*
! 320: * now that we gave 'em a chance to attach,
! 321: * scan and map all the proms we can find
! 322: */
! 323: if (!(flags & BIOSF_PROMSCAN)) {
! 324: volatile u_int8_t *eva;
! 325:
! 326: for (str = NULL, va = ISA_HOLE_VADDR(0xc0000),
! 327: eva = ISA_HOLE_VADDR(0xf0000);
! 328: va < eva; va += 512) {
! 329: extern struct extent *iomem_ex;
! 330: bios_romheader_t romh = (bios_romheader_t)va;
! 331: u_int32_t off, len;
! 332: u_int8_t cksum;
! 333: int i;
! 334:
! 335: if (romh->signature != 0xaa55)
! 336: continue;
! 337:
! 338: /*
! 339: * for this and the next check we probably want
! 340: * to reserve the page in the extent anyway
! 341: */
! 342: if (!romh->len || romh->len == 0xff)
! 343: continue;
! 344:
! 345: len = romh->len * 512;
! 346: if (va + len > eva)
! 347: continue;
! 348:
! 349: for (cksum = 0, i = len; i--; cksum += va[i])
! 350: ;
! 351: #ifdef __stinkpad_sucks__
! 352: if (cksum != 0)
! 353: continue;
! 354: #endif
! 355:
! 356: off = 0xc0000 + (va - (u_int8_t *)
! 357: ISA_HOLE_VADDR(0xc0000));
! 358:
! 359: if (!str)
! 360: printf("%s: ROM list:",
! 361: str = sc->sc_dev.dv_xname);
! 362: printf(" 0x%05x/0x%x%s", off, len,
! 363: cksum? "!" : "");
! 364:
! 365: if ((i = extent_alloc_region(iomem_ex,
! 366: (paddr_t)off, len, EX_NOWAIT)))
! 367: printf(":%d", i);
! 368:
! 369: va += len - 512;
! 370: }
! 371: }
! 372:
! 373: if (str)
! 374: printf("\n");
! 375: }
! 376:
! 377: void
! 378: bios_getopt()
! 379: {
! 380: bootarg_t *q;
! 381:
! 382: #ifdef BIOS_DEBUG
! 383: printf("bootargv:");
! 384: #endif
! 385:
! 386: for(q = bootargp; q->ba_type != BOOTARG_END; q = q->ba_next) {
! 387: q->ba_next = (bootarg_t *)((caddr_t)q + q->ba_size);
! 388: switch (q->ba_type) {
! 389: case BOOTARG_MEMMAP:
! 390: bios_memmap = (bios_memmap_t *)q->ba_arg;
! 391: #ifdef BIOS_DEBUG
! 392: printf(" memmap %p", bios_memmap);
! 393: #endif
! 394: break;
! 395: case BOOTARG_DISKINFO:
! 396: bios_diskinfo = (bios_diskinfo_t *)q->ba_arg;
! 397: #ifdef BIOS_DEBUG
! 398: printf(" diskinfo %p", bios_diskinfo);
! 399: #endif
! 400: break;
! 401: #if NAPM > 0 || defined(DEBUG)
! 402: case BOOTARG_APMINFO:
! 403: #ifdef BIOS_DEBUG
! 404: printf(" apminfo %p", q->ba_arg);
! 405: #endif
! 406: apm = (bios_apminfo_t *)q->ba_arg;
! 407: break;
! 408: #endif
! 409: case BOOTARG_CKSUMLEN:
! 410: bios_cksumlen = *(u_int32_t *)q->ba_arg;
! 411: #ifdef BIOS_DEBUG
! 412: printf(" cksumlen %d", bios_cksumlen);
! 413: #endif
! 414: break;
! 415: #if NPCI > 0
! 416: case BOOTARG_PCIINFO:
! 417: bios_pciinfo = (bios_pciinfo_t *)q->ba_arg;
! 418: #ifdef BIOS_DEBUG
! 419: printf(" pciinfo %p", bios_pciinfo);
! 420: #endif
! 421: break;
! 422: #endif
! 423: case BOOTARG_CONSDEV:
! 424: if (q->ba_size >= sizeof(bios_consdev_t))
! 425: {
! 426: bios_consdev_t *cdp = (bios_consdev_t*)q->ba_arg;
! 427: #include "com.h"
! 428: #include "pccom.h"
! 429: #if NCOM + NPCCOM > 0
! 430: extern int comdefaultrate; /* ic/com.c */
! 431: comdefaultrate = cdp->conspeed;
! 432: #endif
! 433: #ifdef BIOS_DEBUG
! 434: printf(" console 0x%x:%d",
! 435: cdp->consdev, cdp->conspeed);
! 436: #endif
! 437: cnset(cdp->consdev);
! 438: }
! 439: break;
! 440: #ifdef MULTIPROCESSOR
! 441: case BOOTARG_SMPINFO:
! 442: bios_smpinfo = q->ba_arg;
! 443: printf(" smpinfo %p", bios_smpinfo);
! 444: break;
! 445: #endif
! 446:
! 447: #ifdef NFSCLIENT
! 448: case BOOTARG_BOOTMAC:
! 449: bios_bootmac = (bios_bootmac_t *)q->ba_arg;
! 450: break;
! 451: #endif
! 452:
! 453: default:
! 454: #ifdef BIOS_DEBUG
! 455: printf(" unsupported arg (%d) %p", q->ba_type,
! 456: q->ba_arg);
! 457: #endif
! 458: break;
! 459: }
! 460: }
! 461: printf("\n");
! 462:
! 463: }
! 464:
! 465: int
! 466: bios_print(void *aux, const char *pnp)
! 467: {
! 468: struct bios_attach_args *ba = aux;
! 469:
! 470: if (pnp)
! 471: printf("%s at %s function 0x%x",
! 472: ba->bios_dev, pnp, ba->bios_func);
! 473: return (UNCONF);
! 474: }
! 475:
! 476: int
! 477: bios32_service(u_int32_t service, bios32_entry_t e, bios32_entry_info_t ei)
! 478: {
! 479: u_long pa, endpa;
! 480: vaddr_t va, sva;
! 481: u_int32_t base, count, off, ent;
! 482: int slot;
! 483:
! 484: if (bios32_entry.offset == 0)
! 485: return 0;
! 486:
! 487: base = 0;
! 488: __asm __volatile("lcall *(%4)"
! 489: : "+a" (service), "+b" (base), "=c" (count), "=d" (off)
! 490: : "D" (&bios32_entry)
! 491: : "%esi", "cc", "memory");
! 492:
! 493: if (service & 0xff)
! 494: return 0; /* not found */
! 495:
! 496: ent = base + off;
! 497: if (ent <= BIOS32_START || ent >= BIOS32_END)
! 498: return 0;
! 499:
! 500:
! 501: endpa = round_page(BIOS32_END);
! 502:
! 503: sva = va = uvm_km_valloc(kernel_map, endpa);
! 504: if (va == 0)
! 505: return (0);
! 506:
! 507: slot = gdt_get_slot();
! 508: setgdt(slot, (caddr_t)va, BIOS32_END, SDT_MEMERA, SEL_KPL, 1, 0);
! 509:
! 510: for (pa = trunc_page(BIOS32_START),
! 511: va += trunc_page(BIOS32_START);
! 512: pa < endpa; pa += NBPG, va += NBPG) {
! 513: pmap_enter(pmap_kernel(), va, pa,
! 514: VM_PROT_READ | VM_PROT_WRITE,
! 515: VM_PROT_READ | VM_PROT_WRITE | PMAP_WIRED);
! 516:
! 517: /* for all you, broken hearted */
! 518: if (pa >= trunc_page(base)) {
! 519: pmap_enter(pmap_kernel(), sva, pa,
! 520: VM_PROT_READ | VM_PROT_WRITE,
! 521: VM_PROT_READ | VM_PROT_WRITE | PMAP_WIRED);
! 522: sva += NBPG;
! 523: }
! 524: }
! 525:
! 526: e->segment = GSEL(slot, SEL_KPL);
! 527: e->offset = (vaddr_t)ent;
! 528:
! 529: ei->bei_base = base;
! 530: ei->bei_size = count;
! 531: ei->bei_entry = ent;
! 532:
! 533: return 1;
! 534: }
! 535:
! 536: int
! 537: biosopen(dev_t dev, int flag, int mode, struct proc *p)
! 538: {
! 539: struct bios_softc *sc = bios_cd.cd_devs[0];
! 540:
! 541: if (minor(dev))
! 542: return (ENXIO);
! 543:
! 544: (void)sc;
! 545:
! 546: return 0;
! 547: }
! 548:
! 549: int
! 550: biosclose(dev_t dev, int flag, int mode, struct proc *p)
! 551: {
! 552: struct bios_softc *sc = bios_cd.cd_devs[0];
! 553:
! 554: if (minor(dev))
! 555: return (ENXIO);
! 556:
! 557: (void)sc;
! 558:
! 559: return 0;
! 560: }
! 561:
! 562: int
! 563: biosioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p)
! 564: {
! 565: struct bios_softc *sc = bios_cd.cd_devs[0];
! 566:
! 567: if (minor(dev))
! 568: return (ENXIO);
! 569:
! 570: switch (cmd) {
! 571: default:
! 572: return ENXIO;
! 573: }
! 574:
! 575: (void)sc;
! 576:
! 577: return 0;
! 578: }
! 579:
! 580: void
! 581: bioscnprobe(struct consdev *cn)
! 582: {
! 583: #if 0
! 584: bios_init(I386_BUS_SPACE_MEM); /* XXX */
! 585: if (!bios_cd.cd_ndevs)
! 586: return;
! 587:
! 588: if (0 && bios_call(BOOTC_CHECK, NULL))
! 589: return;
! 590:
! 591: cn->cn_pri = CN_NORMAL;
! 592: cn->cn_dev = makedev(48, 0);
! 593: #endif
! 594: }
! 595:
! 596: void
! 597: bioscninit(struct consdev *cn)
! 598: {
! 599:
! 600: }
! 601:
! 602: void
! 603: bioscnputc(dev_t dev, int ch)
! 604: {
! 605:
! 606: }
! 607:
! 608: int
! 609: bioscngetc(dev_t dev)
! 610: {
! 611: return -1;
! 612: }
! 613:
! 614: void
! 615: bioscnpollc(dev_t dev, int on)
! 616: {
! 617: }
! 618:
! 619: int
! 620: bios_sysctl(int *name, u_int namelen, void *oldp, size_t *oldlenp, void *newp,
! 621: size_t newlen, struct proc *p)
! 622: {
! 623: bios_diskinfo_t *pdi;
! 624: int biosdev;
! 625:
! 626: /* all sysctl names at this level except diskinfo are terminal */
! 627: if (namelen != 1 && name[0] != BIOS_DISKINFO)
! 628: return (ENOTDIR); /* overloaded */
! 629:
! 630: if (!(bootapiver & BAPIV_VECTOR))
! 631: return EOPNOTSUPP;
! 632:
! 633: switch (name[0]) {
! 634: case BIOS_DEV:
! 635: if ((pdi = bios_getdiskinfo(bootdev)) == NULL)
! 636: return ENXIO;
! 637: biosdev = pdi->bios_number;
! 638: return sysctl_rdint(oldp, oldlenp, newp, biosdev);
! 639: case BIOS_DISKINFO:
! 640: if (namelen != 2)
! 641: return ENOTDIR;
! 642: if ((pdi = bios_getdiskinfo(name[1])) == NULL)
! 643: return ENXIO;
! 644: return sysctl_rdstruct(oldp, oldlenp, newp, pdi, sizeof(*pdi));
! 645: case BIOS_CKSUMLEN:
! 646: return sysctl_rdint(oldp, oldlenp, newp, bios_cksumlen);
! 647: default:
! 648: return EOPNOTSUPP;
! 649: }
! 650: /* NOTREACHED */
! 651: }
! 652:
! 653: bios_diskinfo_t *
! 654: bios_getdiskinfo(dev_t dev)
! 655: {
! 656: bios_diskinfo_t *pdi;
! 657:
! 658: if (bios_diskinfo == NULL)
! 659: return NULL;
! 660:
! 661: for (pdi = bios_diskinfo; pdi->bios_number != -1; pdi++) {
! 662: if ((dev & B_MAGICMASK) == B_DEVMAGIC) { /* search by bootdev */
! 663: if (pdi->bsd_dev == dev)
! 664: break;
! 665: } else {
! 666: if (pdi->bios_number == dev)
! 667: break;
! 668: }
! 669: }
! 670:
! 671: if (pdi->bios_number == -1)
! 672: return NULL;
! 673: else
! 674: return pdi;
! 675: }
! 676:
! 677: /*
! 678: * smbios_find_table() takes a caller supplied smbios struct type and
! 679: * a pointer to a handle (struct smbtable) returning one if the structure
! 680: * is sucessfully located and zero otherwise. Callers should take care
! 681: * to initialize the cookie field of the smbtable structure to zero before
! 682: * the first invocation of this function.
! 683: * Multiple tables of the same type can be located by repeatedly calling
! 684: * smbios_find_table with the same arguments.
! 685: */
! 686: int
! 687: smbios_find_table(u_int8_t type, struct smbtable *st)
! 688: {
! 689: u_int8_t *va, *end;
! 690: struct smbtblhdr *hdr;
! 691: int ret = 0, tcount = 1;
! 692:
! 693: va = smbios_entry.addr;
! 694: end = va + smbios_entry.len;
! 695:
! 696: /*
! 697: * The cookie field of the smtable structure is used to locate
! 698: * multiple instances of a table of an arbitrary type. Following the
! 699: * sucessful location of a table, the type is encoded as bits 0:7 of
! 700: * the cookie value, the offset in terms of the number of structures
! 701: * preceding that referenced by the handle is encoded in bits 15:31.
! 702: */
! 703: if ((st->cookie & 0xfff) == type && st->cookie >> 16) {
! 704: if ((u_int8_t *)st->hdr >= va && (u_int8_t *)st->hdr < end) {
! 705: hdr = st->hdr;
! 706: if (hdr->type == type) {
! 707: va = (u_int8_t *)hdr + hdr->size;
! 708: for (; va + 1 < end; va++)
! 709: if (*va == NULL && *(va + 1) == NULL)
! 710: break;
! 711: va+= 2;
! 712: tcount = st->cookie >> 16;
! 713: }
! 714: }
! 715: }
! 716: for (; va + sizeof(struct smbtblhdr) < end && tcount <=
! 717: smbios_entry.count; tcount++) {
! 718: hdr = (struct smbtblhdr *)va;
! 719: if (hdr->type == type) {
! 720: ret = 1;
! 721: st->hdr = hdr;
! 722: st->tblhdr = va + sizeof(struct smbtblhdr);
! 723: st->cookie = (tcount + 1) << 16 | type;
! 724: break;
! 725: }
! 726: if (hdr->type == SMBIOS_TYPE_EOT)
! 727: break;
! 728: va+= hdr->size;
! 729: for (; va + 1 < end; va++)
! 730: if (*va == NULL && *(va + 1) == NULL)
! 731: break;
! 732: va+=2;
! 733: }
! 734:
! 735: return ret;
! 736: }
! 737:
! 738: char *
! 739: smbios_get_string(struct smbtable *st, u_int8_t indx, char *dest, size_t len)
! 740: {
! 741: u_int8_t *va, *end;
! 742: char *ret = NULL;
! 743: int i;
! 744:
! 745: va = (u_int8_t *)st->hdr + st->hdr->size;
! 746: end = smbios_entry.addr + smbios_entry.len;
! 747: for (i = 1; va < end && i < indx && *va; i++)
! 748: while (*va++)
! 749: ;
! 750: if (i == indx) {
! 751: if (va + len < end) {
! 752: ret = dest;
! 753: bcopy(va, ret, len);
! 754: ret[len - 1] = '\0';
! 755: }
! 756: }
! 757:
! 758: return ret;
! 759: }
! 760:
! 761: char *
! 762: fixstring(char *s)
! 763: {
! 764: char *p, *e;
! 765: int i;
! 766:
! 767: for (i= 0; i < sizeof(smbios_uninfo)/sizeof(smbios_uninfo[0]); i++)
! 768: if ((strncasecmp(s, smbios_uninfo[i], strlen(smbios_uninfo[i])))==0)
! 769: return NULL;
! 770: /*
! 771: * Remove leading and trailing whitespace
! 772: */
! 773: for (p = s; *p == ' '; p++)
! 774: ;
! 775: /*
! 776: * Special case entire string is whitespace
! 777: */
! 778: if (p == s + strlen(s))
! 779: return NULL;
! 780: for (e = s + strlen(s) - 1; e > s && *e == ' '; e--)
! 781: ;
! 782: if (p > s || e < s + strlen(s) - 1) {
! 783: bcopy(p, s, e-p + 1);
! 784: s[e - p + 1] = '\0';
! 785: }
! 786:
! 787: return s;
! 788: }
! 789:
! 790: void
! 791: smbios_info(char * str)
! 792: {
! 793: char *sminfop, sminfo[64];
! 794: struct smbtable stbl, btbl;
! 795: struct smbios_sys *sys;
! 796: struct smbios_board *board;
! 797: int i, infolen, uuidf, havebb;
! 798: char *p;
! 799:
! 800: if (smbios_entry.mjr < 2)
! 801: return;
! 802: /*
! 803: * According to the spec the system table among others is required,
! 804: * if it is not we do not bother with this smbios implementation.
! 805: */
! 806: stbl.cookie = btbl.cookie = 0;
! 807: if (!smbios_find_table(SMBIOS_TYPE_SYSTEM, &stbl))
! 808: return;
! 809: havebb = smbios_find_table(SMBIOS_TYPE_BASEBOARD, &btbl);
! 810:
! 811: sys = (struct smbios_sys *)stbl.tblhdr;
! 812: if (havebb)
! 813: board = (struct smbios_board *)btbl.tblhdr;
! 814: /*
! 815: * Some smbios implementations have no system vendor or product strings,
! 816: * some have very uninformative data which is harder to work around
! 817: * and we must rely upon various heuristics to detect this. In both
! 818: * cases we attempt to fall back on the base board information in the
! 819: * perhaps naive belief that motherboard vendors will supply this
! 820: * information.
! 821: */
! 822: sminfop = NULL;
! 823: if ((p = smbios_get_string(&stbl, sys->vendor, sminfo,
! 824: sizeof(sminfo))) != NULL)
! 825: sminfop = fixstring(p);
! 826: if (sminfop == NULL) {
! 827: if (havebb) {
! 828: if ((p = smbios_get_string(&btbl, board->vendor,
! 829: sminfo, sizeof(sminfo))) != NULL)
! 830: sminfop = fixstring(p);
! 831: }
! 832: }
! 833: if (sminfop) {
! 834: infolen = strlen(sminfop) + 1;
! 835: hw_vendor = malloc(infolen, M_DEVBUF, M_NOWAIT);
! 836: if (hw_vendor)
! 837: strlcpy(hw_vendor, sminfop, infolen);
! 838: sminfop = NULL;
! 839: }
! 840: if ((p = smbios_get_string(&stbl, sys->product, sminfo,
! 841: sizeof(sminfo))) != NULL)
! 842: sminfop = fixstring(p);
! 843: if (sminfop == NULL) {
! 844: if (havebb) {
! 845: if ((p = smbios_get_string(&btbl, board->product,
! 846: sminfo, sizeof(sminfo))) != NULL)
! 847: sminfop = fixstring(p);
! 848: }
! 849: }
! 850: if (sminfop) {
! 851: infolen = strlen(sminfop) + 1;
! 852: hw_prod = malloc(infolen, M_DEVBUF, M_NOWAIT);
! 853: if (hw_prod)
! 854: strlcpy(hw_prod, sminfop, infolen);
! 855: sminfop = NULL;
! 856: }
! 857: if (hw_vendor != NULL && hw_prod != NULL)
! 858: printf("\n%s: %s %s", str, hw_vendor, hw_prod);
! 859: if ((p = smbios_get_string(&stbl, sys->version, sminfo,
! 860: sizeof(sminfo))) != NULL)
! 861: sminfop = fixstring(p);
! 862: if (sminfop) {
! 863: infolen = strlen(sminfop) + 1;
! 864: hw_ver = malloc(infolen, M_DEVBUF, M_NOWAIT);
! 865: if (hw_ver)
! 866: strlcpy(hw_ver, sminfop, infolen);
! 867: sminfop = NULL;
! 868: }
! 869: if ((p = smbios_get_string(&stbl, sys->serial, sminfo,
! 870: sizeof(sminfo))) != NULL)
! 871: sminfop = fixstring(p);
! 872: if (sminfop) {
! 873: infolen = strlen(sminfop) + 1;
! 874: hw_serial = malloc(infolen, M_DEVBUF, M_NOWAIT);
! 875: if (hw_serial)
! 876: strlcpy(hw_serial, sminfop, infolen);
! 877: }
! 878: if (smbios_entry.mjr > 2 || (smbios_entry.mjr == 2 &&
! 879: smbios_entry.min >= 1)) {
! 880: /*
! 881: * If the uuid value is all 0xff the uuid is present but not
! 882: * set, if its all 0 then the uuid isn't present at all.
! 883: */
! 884: uuidf |= SMBIOS_UUID_NPRESENT|SMBIOS_UUID_NSET;
! 885: for (i = 0; i < sizeof(sys->uuid); i++) {
! 886: if (sys->uuid[i] != 0xff)
! 887: uuidf &= ~SMBIOS_UUID_NSET;
! 888: if (sys->uuid[i] != 0)
! 889: uuidf &= ~SMBIOS_UUID_NPRESENT;
! 890: }
! 891:
! 892: if (uuidf & SMBIOS_UUID_NPRESENT)
! 893: hw_uuid = NULL;
! 894: else if (uuidf & SMBIOS_UUID_NSET)
! 895: hw_uuid = "Not Set";
! 896: else {
! 897: hw_uuid = malloc(SMBIOS_UUID_REPLEN, M_DEVBUF,
! 898: M_NOWAIT);
! 899: if (hw_uuid) {
! 900: snprintf(hw_uuid, SMBIOS_UUID_REPLEN,
! 901: SMBIOS_UUID_REP,
! 902: sys->uuid[0], sys->uuid[1], sys->uuid[2],
! 903: sys->uuid[3], sys->uuid[4], sys->uuid[5],
! 904: sys->uuid[6], sys->uuid[7], sys->uuid[8],
! 905: sys->uuid[9], sys->uuid[10], sys->uuid[11],
! 906: sys->uuid[12], sys->uuid[13], sys->uuid[14],
! 907: sys->uuid[15]);
! 908: }
! 909: }
! 910: }
! 911: }
CVSweb