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
biosprobe(struct device * parent,void * match,void * aux)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
biosattach(struct device * parent,struct device * self,void * aux)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
bios_getopt(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
bios_print(void * aux,const char * pnp)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
bios32_service(uint32_t service,bios32_entry_t e,bios32_entry_info_t ei)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
bios32_cleanup(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
biosopen(dev_t dev,int flag,int mode,struct proc * p)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
biosclose(dev_t dev,int flag,int mode,struct proc * p)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
biosioctl(dev_t dev,u_long cmd,caddr_t data,int flag,struct proc * p)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
bios_sysctl(int * name,u_int namelen,void * oldp,size_t * oldlenp,void * newp,size_t newlen,struct proc * p)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 *
bios_getdiskinfo(dev_t dev)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
smbios_find_table(uint8_t type,struct smbtable * st)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 *
smbios_get_string(struct smbtable * st,uint8_t indx,char * dest,size_t len)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 *
fixstring(char * s)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
smbios_info(char * str)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