xref: /openbsd/sys/arch/i386/i386/bios.c (revision 130ea1ec)
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