Annotation of sys/arch/i386/i386/bios.c, Revision 1.1.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