xref: /freebsd/sys/compat/x86bios/x86bios.c (revision 869ae66dfc85569a88b27792e5173f48efaf699c)
1 /*-
2  * Copyright (c) 2009 Alex Keda <admin@lissyara.su>
3  * Copyright (c) 2009-2010 Jung-uk Kim <jkim@FreeBSD.org>
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25  * SUCH DAMAGE.
26  */
27 
28 #include <sys/cdefs.h>
29 __FBSDID("$FreeBSD$");
30 
31 #include "opt_x86bios.h"
32 
33 #include <sys/param.h>
34 #include <sys/bus.h>
35 #include <sys/kernel.h>
36 #include <sys/lock.h>
37 #include <sys/malloc.h>
38 #include <sys/module.h>
39 #include <sys/mutex.h>
40 #include <sys/sysctl.h>
41 
42 #include <contrib/x86emu/x86emu.h>
43 #include <contrib/x86emu/x86emu_regs.h>
44 #include <compat/x86bios/x86bios.h>
45 
46 #include <dev/pci/pcireg.h>
47 #include <dev/pci/pcivar.h>
48 
49 #include <vm/vm.h>
50 #include <vm/pmap.h>
51 
52 #ifdef __amd64__
53 #define	X86BIOS_NATIVE_ARCH
54 #endif
55 #ifdef __i386__
56 #define	X86BIOS_NATIVE_VM86
57 #endif
58 
59 #define	X86BIOS_MEM_SIZE	0x00100000	/* 1M */
60 
61 static struct mtx x86bios_lock;
62 
63 SYSCTL_NODE(_debug, OID_AUTO, x86bios, CTLFLAG_RD, NULL, "x86bios debugging");
64 static int x86bios_trace_call;
65 TUNABLE_INT("debug.x86bios.call", &x86bios_trace_call);
66 SYSCTL_INT(_debug_x86bios, OID_AUTO, call, CTLFLAG_RW, &x86bios_trace_call, 0,
67     "Trace far function calls");
68 static int x86bios_trace_int;
69 TUNABLE_INT("debug.x86bios.int", &x86bios_trace_int);
70 SYSCTL_INT(_debug_x86bios, OID_AUTO, int, CTLFLAG_RW, &x86bios_trace_int, 0,
71     "Trace software interrupt handlers");
72 
73 #ifdef X86BIOS_NATIVE_VM86
74 
75 #include <machine/vm86.h>
76 #include <machine/vmparam.h>
77 #include <machine/pc/bios.h>
78 
79 struct vm86context x86bios_vmc;
80 
81 static void
82 x86bios_emu2vmf(struct x86emu_regs *regs, struct vm86frame *vmf)
83 {
84 
85 	vmf->vmf_ds = regs->R_DS;
86 	vmf->vmf_es = regs->R_ES;
87 	vmf->vmf_ax = regs->R_AX;
88 	vmf->vmf_bx = regs->R_BX;
89 	vmf->vmf_cx = regs->R_CX;
90 	vmf->vmf_dx = regs->R_DX;
91 	vmf->vmf_bp = regs->R_BP;
92 	vmf->vmf_si = regs->R_SI;
93 	vmf->vmf_di = regs->R_DI;
94 }
95 
96 static void
97 x86bios_vmf2emu(struct vm86frame *vmf, struct x86emu_regs *regs)
98 {
99 
100 	regs->R_DS = vmf->vmf_ds;
101 	regs->R_ES = vmf->vmf_es;
102 	regs->R_FLG = vmf->vmf_flags;
103 	regs->R_AX = vmf->vmf_ax;
104 	regs->R_BX = vmf->vmf_bx;
105 	regs->R_CX = vmf->vmf_cx;
106 	regs->R_DX = vmf->vmf_dx;
107 	regs->R_BP = vmf->vmf_bp;
108 	regs->R_SI = vmf->vmf_si;
109 	regs->R_DI = vmf->vmf_di;
110 }
111 
112 void *
113 x86bios_alloc(uint32_t *offset, size_t size, int flags)
114 {
115 	vm_offset_t addr;
116 	int i;
117 
118 	addr = (vm_offset_t)contigmalloc(size, M_DEVBUF, flags, 0,
119 	    X86BIOS_MEM_SIZE, PAGE_SIZE, 0);
120 	if (addr != 0) {
121 		*offset = vtophys(addr);
122 		mtx_lock(&x86bios_lock);
123 		for (i = 0; i < atop(round_page(size)); i++)
124 			vm86_addpage(&x86bios_vmc, atop(*offset) + i,
125 			    addr + ptoa(i));
126 		mtx_unlock(&x86bios_lock);
127 	}
128 
129 	return ((void *)addr);
130 }
131 
132 void
133 x86bios_free(void *addr, size_t size)
134 {
135 	int i, last;
136 
137 	mtx_lock(&x86bios_lock);
138 	for (i = 0, last = -1; i < x86bios_vmc.npages; i++)
139 		if (x86bios_vmc.pmap[i].kva >= (vm_offset_t)addr &&
140 		    x86bios_vmc.pmap[i].kva < (vm_offset_t)addr + size) {
141 			bzero(&x86bios_vmc.pmap[i],
142 			    sizeof(x86bios_vmc.pmap[i]));
143 			last = i;
144 		}
145 	if (last < 0) {
146 		mtx_unlock(&x86bios_lock);
147 		return;
148 	}
149 	if (last == x86bios_vmc.npages - 1) {
150 		x86bios_vmc.npages -= atop(round_page(size));
151 		for (i = x86bios_vmc.npages - 1;
152 		    i >= 0 && x86bios_vmc.pmap[i].kva == 0; i--)
153 			x86bios_vmc.npages--;
154 	}
155 	mtx_unlock(&x86bios_lock);
156 	contigfree(addr, size, M_DEVBUF);
157 }
158 
159 void
160 x86bios_init_regs(struct x86regs *regs)
161 {
162 
163 	bzero(regs, sizeof(*regs));
164 }
165 
166 void
167 x86bios_call(struct x86regs *regs, uint16_t seg, uint16_t off)
168 {
169 	struct vm86frame vmf;
170 
171 	if (x86bios_trace_call)
172 		printf("Calling 0x%05x (ax=0x%04x bx=0x%04x "
173 		    "cx=0x%04x dx=0x%04x es=0x%04x di=0x%04x)\n",
174 		    (seg << 4) + off, regs->R_AX, regs->R_BX, regs->R_CX,
175 		    regs->R_DX, regs->R_ES, regs->R_DI);
176 
177 	bzero(&vmf, sizeof(vmf));
178 	x86bios_emu2vmf((struct x86emu_regs *)regs, &vmf);
179 	vmf.vmf_cs = seg;
180 	vmf.vmf_ip = off;
181 	mtx_lock(&x86bios_lock);
182 	vm86_datacall(-1, &vmf, &x86bios_vmc);
183 	mtx_unlock(&x86bios_lock);
184 	x86bios_vmf2emu(&vmf, (struct x86emu_regs *)regs);
185 
186 	if (x86bios_trace_call)
187 		printf("Exiting 0x%05x (ax=0x%04x bx=0x%04x "
188 		    "cx=0x%04x dx=0x%04x es=0x%04x di=0x%04x)\n",
189 		    (seg << 4) + off, regs->R_AX, regs->R_BX, regs->R_CX,
190 		    regs->R_DX, regs->R_ES, regs->R_DI);
191 }
192 
193 uint32_t
194 x86bios_get_intr(int intno)
195 {
196 
197 	return (readl(x86bios_offset(intno * 4)));
198 }
199 
200 void
201 x86bios_intr(struct x86regs *regs, int intno)
202 {
203 	struct vm86frame vmf;
204 
205 	if (x86bios_trace_int)
206 		printf("Calling int 0x%x (ax=0x%04x bx=0x%04x "
207 		    "cx=0x%04x dx=0x%04x es=0x%04x di=0x%04x)\n",
208 		    intno, regs->R_AX, regs->R_BX, regs->R_CX,
209 		    regs->R_DX, regs->R_ES, regs->R_DI);
210 
211 	bzero(&vmf, sizeof(vmf));
212 	x86bios_emu2vmf((struct x86emu_regs *)regs, &vmf);
213 	mtx_lock(&x86bios_lock);
214 	vm86_datacall(intno, &vmf, &x86bios_vmc);
215 	mtx_unlock(&x86bios_lock);
216 	x86bios_vmf2emu(&vmf, (struct x86emu_regs *)regs);
217 
218 	if (x86bios_trace_int)
219 		printf("Exiting int 0x%x (ax=0x%04x bx=0x%04x "
220 		    "cx=0x%04x dx=0x%04x es=0x%04x di=0x%04x)\n",
221 		    intno, regs->R_AX, regs->R_BX, regs->R_CX,
222 		    regs->R_DX, regs->R_ES, regs->R_DI);
223 }
224 
225 void *
226 x86bios_offset(uint32_t offset)
227 {
228 	vm_offset_t addr;
229 
230 	addr = vm86_getaddr(&x86bios_vmc, X86BIOS_PHYSTOSEG(offset),
231 	    X86BIOS_PHYSTOOFF(offset));
232 	if (addr == 0)
233 		addr = BIOS_PADDRTOVADDR(offset);
234 
235 	return ((void *)addr);
236 }
237 
238 static int
239 x86bios_init(void)
240 {
241 
242 	mtx_init(&x86bios_lock, "x86bios lock", NULL, MTX_DEF);
243 	bzero(&x86bios_vmc, sizeof(x86bios_vmc));
244 
245 	return (0);
246 }
247 
248 static int
249 x86bios_uninit(void)
250 {
251 
252 	mtx_destroy(&x86bios_lock);
253 
254 	return (0);
255 }
256 
257 #else
258 
259 #include <machine/iodev.h>
260 
261 #define	X86BIOS_PAGE_SIZE	0x00001000	/* 4K */
262 
263 #define	X86BIOS_IVT_SIZE	0x00000500	/* 1K + 256 (BDA) */
264 
265 #define	X86BIOS_IVT_BASE	0x00000000
266 #define	X86BIOS_RAM_BASE	0x00001000
267 #define	X86BIOS_ROM_BASE	0x000a0000
268 
269 #define	X86BIOS_ROM_SIZE	(X86BIOS_MEM_SIZE - (uint32_t)x86bios_rom_phys)
270 #define	X86BIOS_SEG_SIZE	X86BIOS_PAGE_SIZE
271 
272 #define	X86BIOS_PAGES		(X86BIOS_MEM_SIZE / X86BIOS_PAGE_SIZE)
273 
274 #define	X86BIOS_R_SS		_pad2
275 #define	X86BIOS_R_SP		_pad3.I16_reg.x_reg
276 
277 static struct x86emu x86bios_emu;
278 
279 static void *x86bios_ivt;
280 static void *x86bios_rom;
281 static void *x86bios_seg;
282 
283 static vm_offset_t *x86bios_map;
284 
285 static vm_paddr_t x86bios_rom_phys;
286 static vm_paddr_t x86bios_seg_phys;
287 
288 static int x86bios_fault;
289 static uint32_t x86bios_fault_addr;
290 static uint16_t x86bios_fault_cs;
291 static uint16_t x86bios_fault_ip;
292 
293 static void
294 x86bios_set_fault(struct x86emu *emu, uint32_t addr)
295 {
296 
297 	x86bios_fault = 1;
298 	x86bios_fault_addr = addr;
299 	x86bios_fault_cs = emu->x86.R_CS;
300 	x86bios_fault_ip = emu->x86.R_IP;
301 	x86emu_halt_sys(emu);
302 }
303 
304 static void *
305 x86bios_get_pages(uint32_t offset, size_t size)
306 {
307 	vm_offset_t addr;
308 
309 	if (offset + size > X86BIOS_MEM_SIZE + X86BIOS_IVT_SIZE)
310 		return (NULL);
311 
312 	if (offset >= X86BIOS_MEM_SIZE)
313 		offset -= X86BIOS_MEM_SIZE;
314 	addr = x86bios_map[offset / X86BIOS_PAGE_SIZE];
315 	if (addr != 0)
316 		addr += offset % X86BIOS_PAGE_SIZE;
317 
318 	return ((void *)addr);
319 }
320 
321 static void
322 x86bios_set_pages(vm_offset_t va, vm_paddr_t pa, size_t size)
323 {
324 	int i, j;
325 
326 	for (i = pa / X86BIOS_PAGE_SIZE, j = 0;
327 	    j < howmany(size, X86BIOS_PAGE_SIZE); i++, j++)
328 		x86bios_map[i] = va + j * X86BIOS_PAGE_SIZE;
329 }
330 
331 static uint8_t
332 x86bios_emu_rdb(struct x86emu *emu, uint32_t addr)
333 {
334 	uint8_t *va;
335 
336 	va = x86bios_get_pages(addr, sizeof(*va));
337 	if (va == NULL)
338 		x86bios_set_fault(emu, addr);
339 
340 	return (*va);
341 }
342 
343 static uint16_t
344 x86bios_emu_rdw(struct x86emu *emu, uint32_t addr)
345 {
346 	uint16_t *va;
347 
348 	va = x86bios_get_pages(addr, sizeof(*va));
349 	if (va == NULL)
350 		x86bios_set_fault(emu, addr);
351 
352 #ifndef __NO_STRICT_ALIGNMENT
353 	if ((addr & 1) != 0)
354 		return (le16dec(va));
355 	else
356 #endif
357 	return (le16toh(*va));
358 }
359 
360 static uint32_t
361 x86bios_emu_rdl(struct x86emu *emu, uint32_t addr)
362 {
363 	uint32_t *va;
364 
365 	va = x86bios_get_pages(addr, sizeof(*va));
366 	if (va == NULL)
367 		x86bios_set_fault(emu, addr);
368 
369 #ifndef __NO_STRICT_ALIGNMENT
370 	if ((addr & 3) != 0)
371 		return (le32dec(va));
372 	else
373 #endif
374 	return (le32toh(*va));
375 }
376 
377 static void
378 x86bios_emu_wrb(struct x86emu *emu, uint32_t addr, uint8_t val)
379 {
380 	uint8_t *va;
381 
382 	va = x86bios_get_pages(addr, sizeof(*va));
383 	if (va == NULL)
384 		x86bios_set_fault(emu, addr);
385 
386 	*va = val;
387 }
388 
389 static void
390 x86bios_emu_wrw(struct x86emu *emu, uint32_t addr, uint16_t val)
391 {
392 	uint16_t *va;
393 
394 	va = x86bios_get_pages(addr, sizeof(*va));
395 	if (va == NULL)
396 		x86bios_set_fault(emu, addr);
397 
398 #ifndef __NO_STRICT_ALIGNMENT
399 	if ((addr & 1) != 0)
400 		le16enc(va, val);
401 	else
402 #endif
403 	*va = htole16(val);
404 }
405 
406 static void
407 x86bios_emu_wrl(struct x86emu *emu, uint32_t addr, uint32_t val)
408 {
409 	uint32_t *va;
410 
411 	va = x86bios_get_pages(addr, sizeof(*va));
412 	if (va == NULL)
413 		x86bios_set_fault(emu, addr);
414 
415 #ifndef __NO_STRICT_ALIGNMENT
416 	if ((addr & 3) != 0)
417 		le32enc(va, val);
418 	else
419 #endif
420 	*va = htole32(val);
421 }
422 
423 static uint8_t
424 x86bios_emu_inb(struct x86emu *emu, uint16_t port)
425 {
426 
427 	if (port == 0xb2) /* APM scratch register */
428 		return (0);
429 	if (port >= 0x80 && port < 0x88) /* POST status register */
430 		return (0);
431 
432 	return (iodev_read_1(port));
433 }
434 
435 static uint16_t
436 x86bios_emu_inw(struct x86emu *emu, uint16_t port)
437 {
438 	uint16_t val;
439 
440 	if (port >= 0x80 && port < 0x88) /* POST status register */
441 		return (0);
442 
443 #ifndef X86BIOS_NATIVE_ARCH
444 	if ((port & 1) != 0) {
445 		val = iodev_read_1(port);
446 		val |= iodev_read_1(port + 1) << 8;
447 	} else
448 #endif
449 	val = iodev_read_2(port);
450 
451 	return (val);
452 }
453 
454 static uint32_t
455 x86bios_emu_inl(struct x86emu *emu, uint16_t port)
456 {
457 	uint32_t val;
458 
459 	if (port >= 0x80 && port < 0x88) /* POST status register */
460 		return (0);
461 
462 #ifndef X86BIOS_NATIVE_ARCH
463 	if ((port & 1) != 0) {
464 		val = iodev_read_1(port);
465 		val |= iodev_read_2(port + 1) << 8;
466 		val |= iodev_read_1(port + 3) << 24;
467 	} else if ((port & 2) != 0) {
468 		val = iodev_read_2(port);
469 		val |= iodev_read_2(port + 2) << 16;
470 	} else
471 #endif
472 	val = iodev_read_4(port);
473 
474 	return (val);
475 }
476 
477 static void
478 x86bios_emu_outb(struct x86emu *emu, uint16_t port, uint8_t val)
479 {
480 
481 	if (port == 0xb2) /* APM scratch register */
482 		return;
483 	if (port >= 0x80 && port < 0x88) /* POST status register */
484 		return;
485 
486 	iodev_write_1(port, val);
487 }
488 
489 static void
490 x86bios_emu_outw(struct x86emu *emu, uint16_t port, uint16_t val)
491 {
492 
493 	if (port >= 0x80 && port < 0x88) /* POST status register */
494 		return;
495 
496 #ifndef X86BIOS_NATIVE_ARCH
497 	if ((port & 1) != 0) {
498 		iodev_write_1(port, val);
499 		iodev_write_1(port + 1, val >> 8);
500 	} else
501 #endif
502 	iodev_write_2(port, val);
503 }
504 
505 static void
506 x86bios_emu_outl(struct x86emu *emu, uint16_t port, uint32_t val)
507 {
508 
509 	if (port >= 0x80 && port < 0x88) /* POST status register */
510 		return;
511 
512 #ifndef X86BIOS_NATIVE_ARCH
513 	if ((port & 1) != 0) {
514 		iodev_write_1(port, val);
515 		iodev_write_2(port + 1, val >> 8);
516 		iodev_write_1(port + 3, val >> 24);
517 	} else if ((port & 2) != 0) {
518 		iodev_write_2(port, val);
519 		iodev_write_2(port + 2, val >> 16);
520 	} else
521 #endif
522 	iodev_write_4(port, val);
523 }
524 
525 static void
526 x86bios_emu_get_intr(struct x86emu *emu, int intno)
527 {
528 	uint16_t *sp;
529 	uint32_t iv;
530 
531 	emu->x86.R_SP -= 6;
532 
533 	sp = (uint16_t *)((vm_offset_t)x86bios_seg + emu->x86.R_SP);
534 	sp[0] = htole16(emu->x86.R_IP);
535 	sp[1] = htole16(emu->x86.R_CS);
536 	sp[2] = htole16(emu->x86.R_FLG);
537 
538 	iv = x86bios_get_intr(intno);
539 	emu->x86.R_IP = iv & 0xffff;
540 	emu->x86.R_CS = (iv >> 16) & 0xffff;
541 	emu->x86.R_FLG &= ~(F_IF | F_TF);
542 }
543 
544 void *
545 x86bios_alloc(uint32_t *offset, size_t size, int flags)
546 {
547 	void *vaddr;
548 
549 	if (offset == NULL || size == 0)
550 		return (NULL);
551 
552 	vaddr = contigmalloc(size, M_DEVBUF, flags, X86BIOS_RAM_BASE,
553 	    x86bios_rom_phys, X86BIOS_PAGE_SIZE, 0);
554 	if (vaddr != NULL) {
555 		*offset = vtophys(vaddr);
556 		x86bios_set_pages((vm_offset_t)vaddr, *offset, size);
557 	}
558 
559 	return (vaddr);
560 }
561 
562 void
563 x86bios_free(void *addr, size_t size)
564 {
565 	vm_paddr_t paddr;
566 
567 	if (addr == NULL || size == 0)
568 		return;
569 
570 	paddr = vtophys(addr);
571 	if (paddr < X86BIOS_RAM_BASE || paddr >= x86bios_rom_phys ||
572 	    paddr % X86BIOS_PAGE_SIZE != 0)
573 		return;
574 
575 	bzero(x86bios_map + paddr / X86BIOS_PAGE_SIZE,
576 	    sizeof(*x86bios_map) * howmany(size, X86BIOS_PAGE_SIZE));
577 	contigfree(addr, size, M_DEVBUF);
578 }
579 
580 void
581 x86bios_init_regs(struct x86regs *regs)
582 {
583 
584 	bzero(regs, sizeof(*regs));
585 	regs->X86BIOS_R_SS = X86BIOS_PHYSTOSEG(x86bios_seg_phys);
586 	regs->X86BIOS_R_SP = X86BIOS_PAGE_SIZE - 2;
587 }
588 
589 void
590 x86bios_call(struct x86regs *regs, uint16_t seg, uint16_t off)
591 {
592 
593 	if (x86bios_map == NULL)
594 		return;
595 
596 	if (x86bios_trace_call)
597 		printf("Calling 0x%05x (ax=0x%04x bx=0x%04x "
598 		    "cx=0x%04x dx=0x%04x es=0x%04x di=0x%04x)\n",
599 		    (seg << 4) + off, regs->R_AX, regs->R_BX, regs->R_CX,
600 		    regs->R_DX, regs->R_ES, regs->R_DI);
601 
602 	mtx_lock_spin(&x86bios_lock);
603 	memcpy(&x86bios_emu.x86, regs, sizeof(*regs));
604 	x86bios_fault = 0;
605 	x86emu_exec_call(&x86bios_emu, seg, off);
606 	memcpy(regs, &x86bios_emu.x86, sizeof(*regs));
607 	mtx_unlock_spin(&x86bios_lock);
608 
609 	if (x86bios_trace_call) {
610 		printf("Exiting 0x%05x (ax=0x%04x bx=0x%04x "
611 		    "cx=0x%04x dx=0x%04x es=0x%04x di=0x%04x)\n",
612 		    (seg << 4) + off, regs->R_AX, regs->R_BX, regs->R_CX,
613 		    regs->R_DX, regs->R_ES, regs->R_DI);
614 		if (x86bios_fault)
615 			printf("Page fault at 0x%05x from 0x%04x:0x%04x.\n",
616 			    x86bios_fault_addr, x86bios_fault_cs,
617 			    x86bios_fault_ip);
618 	}
619 }
620 
621 uint32_t
622 x86bios_get_intr(int intno)
623 {
624 	uint32_t *iv;
625 
626 	iv = (uint32_t *)((vm_offset_t)x86bios_ivt + intno * 4);
627 
628 	return (le32toh(*iv));
629 }
630 
631 void
632 x86bios_intr(struct x86regs *regs, int intno)
633 {
634 
635 	if (intno < 0 || intno > 255)
636 		return;
637 
638 	if (x86bios_map == NULL)
639 		return;
640 
641 	if (x86bios_trace_int)
642 		printf("Calling int 0x%x (ax=0x%04x bx=0x%04x "
643 		    "cx=0x%04x dx=0x%04x es=0x%04x di=0x%04x)\n",
644 		    intno, regs->R_AX, regs->R_BX, regs->R_CX,
645 		    regs->R_DX, regs->R_ES, regs->R_DI);
646 
647 	mtx_lock_spin(&x86bios_lock);
648 	memcpy(&x86bios_emu.x86, regs, sizeof(*regs));
649 	x86bios_fault = 0;
650 	x86emu_exec_intr(&x86bios_emu, intno);
651 	memcpy(regs, &x86bios_emu.x86, sizeof(*regs));
652 	mtx_unlock_spin(&x86bios_lock);
653 
654 	if (x86bios_trace_int) {
655 		printf("Exiting int 0x%x (ax=0x%04x bx=0x%04x "
656 		    "cx=0x%04x dx=0x%04x es=0x%04x di=0x%04x)\n",
657 		    intno, regs->R_AX, regs->R_BX, regs->R_CX,
658 		    regs->R_DX, regs->R_ES, regs->R_DI);
659 		if (x86bios_fault)
660 			printf("Page fault at 0x%05x from 0x%04x:0x%04x.\n",
661 			    x86bios_fault_addr, x86bios_fault_cs,
662 			    x86bios_fault_ip);
663 	}
664 }
665 
666 void *
667 x86bios_offset(uint32_t offset)
668 {
669 
670 	return (x86bios_get_pages(offset, 1));
671 }
672 
673 static __inline void
674 x86bios_unmap_mem(void)
675 {
676 
677 	if (x86bios_ivt != NULL)
678 #ifdef X86BIOS_NATIVE_ARCH
679 		pmap_unmapdev((vm_offset_t)x86bios_ivt, X86BIOS_IVT_SIZE);
680 #else
681 		free(x86bios_ivt, M_DEVBUF);
682 #endif
683 	if (x86bios_rom != NULL)
684 		pmap_unmapdev((vm_offset_t)x86bios_rom, X86BIOS_ROM_SIZE);
685 	if (x86bios_seg != NULL)
686 		contigfree(x86bios_seg, X86BIOS_SEG_SIZE, M_DEVBUF);
687 }
688 
689 static __inline int
690 x86bios_map_mem(void)
691 {
692 
693 #ifdef X86BIOS_NATIVE_ARCH
694 	x86bios_ivt = pmap_mapbios(X86BIOS_IVT_BASE, X86BIOS_IVT_SIZE);
695 
696 	/* Probe EBDA via BDA. */
697 	x86bios_rom_phys = *(uint16_t *)((caddr_t)x86bios_ivt + 0x40e);
698 	x86bios_rom_phys = x86bios_rom_phys << 4;
699 	if (x86bios_rom_phys != 0 && x86bios_rom_phys < X86BIOS_ROM_BASE &&
700 	    X86BIOS_ROM_BASE - x86bios_rom_phys <= 128 * 1024)
701 		x86bios_rom_phys =
702 		    rounddown(x86bios_rom_phys, X86BIOS_PAGE_SIZE);
703 	else
704 #else
705 	x86bios_ivt = malloc(X86BIOS_IVT_SIZE, M_DEVBUF, M_ZERO | M_WAITOK);
706 #endif
707 
708 	x86bios_rom_phys = X86BIOS_ROM_BASE;
709 	x86bios_rom = pmap_mapdev(x86bios_rom_phys, X86BIOS_ROM_SIZE);
710 	if (x86bios_rom == NULL)
711 		goto fail;
712 #ifdef X86BIOS_NATIVE_ARCH
713 	/* Change attribute for EBDA. */
714 	if (x86bios_rom_phys < X86BIOS_ROM_BASE &&
715 	    pmap_change_attr((vm_offset_t)x86bios_rom,
716 	    X86BIOS_ROM_BASE - x86bios_rom_phys, PAT_WRITE_BACK) != 0)
717 		goto fail;
718 #endif
719 
720 	x86bios_seg = contigmalloc(X86BIOS_SEG_SIZE, M_DEVBUF, M_WAITOK,
721 	    X86BIOS_RAM_BASE, x86bios_rom_phys, X86BIOS_PAGE_SIZE, 0);
722 	x86bios_seg_phys = vtophys(x86bios_seg);
723 
724 	if (bootverbose) {
725 		printf("x86bios:   IVT 0x%06x-0x%06x at %p\n",
726 		    X86BIOS_IVT_BASE, X86BIOS_IVT_SIZE + X86BIOS_IVT_BASE - 1,
727 		    x86bios_ivt);
728 		printf("x86bios:  SSEG 0x%06x-0x%06x at %p\n",
729 		    (uint32_t)x86bios_seg_phys,
730 		    X86BIOS_SEG_SIZE + (uint32_t)x86bios_seg_phys - 1,
731 		    x86bios_seg);
732 		if (x86bios_rom_phys < X86BIOS_ROM_BASE)
733 			printf("x86bios:  EBDA 0x%06x-0x%06x at %p\n",
734 			    (uint32_t)x86bios_rom_phys, X86BIOS_ROM_BASE - 1,
735 			    x86bios_rom);
736 		printf("x86bios:   ROM 0x%06x-0x%06x at %p\n",
737 		    X86BIOS_ROM_BASE, X86BIOS_MEM_SIZE - X86BIOS_SEG_SIZE - 1,
738 		    (void *)((vm_offset_t)x86bios_rom + X86BIOS_ROM_BASE -
739 		    (vm_offset_t)x86bios_rom_phys));
740 	}
741 
742 	return (0);
743 
744 fail:
745 	x86bios_unmap_mem();
746 
747 	return (1);
748 }
749 
750 static int
751 x86bios_init(void)
752 {
753 	int i;
754 
755 	if (x86bios_map_mem() != 0)
756 		return (ENOMEM);
757 
758 	mtx_init(&x86bios_lock, "x86bios lock", NULL, MTX_SPIN);
759 
760 	x86bios_map = malloc(sizeof(*x86bios_map) * X86BIOS_PAGES, M_DEVBUF,
761 	    M_WAITOK | M_ZERO);
762 	x86bios_set_pages((vm_offset_t)x86bios_ivt, X86BIOS_IVT_BASE,
763 	    X86BIOS_IVT_SIZE);
764 	x86bios_set_pages((vm_offset_t)x86bios_rom, x86bios_rom_phys,
765 	    X86BIOS_ROM_SIZE);
766 	x86bios_set_pages((vm_offset_t)x86bios_seg, x86bios_seg_phys,
767 	    X86BIOS_SEG_SIZE);
768 
769 	bzero(&x86bios_emu, sizeof(x86bios_emu));
770 
771 	x86bios_emu.emu_rdb = x86bios_emu_rdb;
772 	x86bios_emu.emu_rdw = x86bios_emu_rdw;
773 	x86bios_emu.emu_rdl = x86bios_emu_rdl;
774 	x86bios_emu.emu_wrb = x86bios_emu_wrb;
775 	x86bios_emu.emu_wrw = x86bios_emu_wrw;
776 	x86bios_emu.emu_wrl = x86bios_emu_wrl;
777 
778 	x86bios_emu.emu_inb = x86bios_emu_inb;
779 	x86bios_emu.emu_inw = x86bios_emu_inw;
780 	x86bios_emu.emu_inl = x86bios_emu_inl;
781 	x86bios_emu.emu_outb = x86bios_emu_outb;
782 	x86bios_emu.emu_outw = x86bios_emu_outw;
783 	x86bios_emu.emu_outl = x86bios_emu_outl;
784 
785 	for (i = 0; i < 256; i++)
786 		x86bios_emu._x86emu_intrTab[i] = x86bios_emu_get_intr;
787 
788 	return (0);
789 }
790 
791 static int
792 x86bios_uninit(void)
793 {
794 	vm_offset_t *map = x86bios_map;
795 
796 	mtx_lock_spin(&x86bios_lock);
797 	if (x86bios_map != NULL) {
798 		free(x86bios_map, M_DEVBUF);
799 		x86bios_map = NULL;
800 	}
801 	mtx_unlock_spin(&x86bios_lock);
802 
803 	if (map != NULL)
804 		x86bios_unmap_mem();
805 
806 	mtx_destroy(&x86bios_lock);
807 
808 	return (0);
809 }
810 
811 #endif
812 
813 void *
814 x86bios_get_orm(uint32_t offset)
815 {
816 	uint8_t *p;
817 
818 	/* Does the shadow ROM contain BIOS POST code for x86? */
819 	p = x86bios_offset(offset);
820 	if (p == NULL || p[0] != 0x55 || p[1] != 0xaa || p[3] != 0xe9)
821 		return (NULL);
822 
823 	return (p);
824 }
825 
826 int
827 x86bios_match_device(uint32_t offset, device_t dev)
828 {
829 	uint8_t *p;
830 	uint16_t device, vendor;
831 	uint8_t class, progif, subclass;
832 
833 	/* Does the shadow ROM contain BIOS POST code for x86? */
834 	p = x86bios_get_orm(offset);
835 	if (p == NULL)
836 		return (0);
837 
838 	/* Does it contain PCI data structure? */
839 	p += le16toh(*(uint16_t *)(p + 0x18));
840 	if (bcmp(p, "PCIR", 4) != 0 ||
841 	    le16toh(*(uint16_t *)(p + 0x0a)) < 0x18 || *(p + 0x14) != 0)
842 		return (0);
843 
844 	/* Does it match the vendor, device, and classcode? */
845 	vendor = le16toh(*(uint16_t *)(p + 0x04));
846 	device = le16toh(*(uint16_t *)(p + 0x06));
847 	progif = *(p + 0x0d);
848 	subclass = *(p + 0x0e);
849 	class = *(p + 0x0f);
850 	if (vendor != pci_get_vendor(dev) || device != pci_get_device(dev) ||
851 	    class != pci_get_class(dev) || subclass != pci_get_subclass(dev) ||
852 	    progif != pci_get_progif(dev))
853 		return (0);
854 
855 	return (1);
856 }
857 
858 static int
859 x86bios_modevent(module_t mod __unused, int type, void *data __unused)
860 {
861 
862 	switch (type) {
863 	case MOD_LOAD:
864 		return (x86bios_init());
865 	case MOD_UNLOAD:
866 		return (x86bios_uninit());
867 	default:
868 		return (ENOTSUP);
869 	}
870 }
871 
872 static moduledata_t x86bios_mod = {
873 	"x86bios",
874 	x86bios_modevent,
875 	NULL,
876 };
877 
878 DECLARE_MODULE(x86bios, x86bios_mod, SI_SUB_CPU, SI_ORDER_ANY);
879 MODULE_VERSION(x86bios, 1);
880