119de5df5SJung-uk Kim /*- 23d0cd005SXin LI * Copyright (c) 2009 Alex Keda <admin@lissyara.su> 3b92184ecSJung-uk Kim * Copyright (c) 2009-2010 Jung-uk Kim <jkim@FreeBSD.org> 43d0cd005SXin LI * All rights reserved. 53d0cd005SXin LI * 63d0cd005SXin LI * Redistribution and use in source and binary forms, with or without 73d0cd005SXin LI * modification, are permitted provided that the following conditions 83d0cd005SXin LI * are met: 93d0cd005SXin LI * 1. Redistributions of source code must retain the above copyright 103d0cd005SXin LI * notice, this list of conditions and the following disclaimer. 113d0cd005SXin LI * 2. Redistributions in binary form must reproduce the above copyright 123d0cd005SXin LI * notice, this list of conditions and the following disclaimer in the 133d0cd005SXin LI * documentation and/or other materials provided with the distribution. 143d0cd005SXin LI * 153d0cd005SXin LI * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 163d0cd005SXin LI * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 173d0cd005SXin LI * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 183d0cd005SXin LI * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 193d0cd005SXin LI * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 203d0cd005SXin LI * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 213d0cd005SXin LI * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 223d0cd005SXin LI * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 233d0cd005SXin LI * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 243d0cd005SXin LI * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 253d0cd005SXin LI * SUCH DAMAGE. 2619de5df5SJung-uk Kim */ 2719de5df5SJung-uk Kim 2819de5df5SJung-uk Kim #include <sys/cdefs.h> 2919de5df5SJung-uk Kim #include "opt_x86bios.h" 3019de5df5SJung-uk Kim 3119de5df5SJung-uk Kim #include <sys/param.h> 323219f535SJung-uk Kim #include <sys/bus.h> 3319de5df5SJung-uk Kim #include <sys/kernel.h> 3419de5df5SJung-uk Kim #include <sys/lock.h> 353219f535SJung-uk Kim #include <sys/malloc.h> 3619de5df5SJung-uk Kim #include <sys/module.h> 3719de5df5SJung-uk Kim #include <sys/mutex.h> 383afa8e56SJung-uk Kim #include <sys/sysctl.h> 3919de5df5SJung-uk Kim 4019de5df5SJung-uk Kim #include <contrib/x86emu/x86emu.h> 4119de5df5SJung-uk Kim #include <contrib/x86emu/x86emu_regs.h> 4219de5df5SJung-uk Kim #include <compat/x86bios/x86bios.h> 4319de5df5SJung-uk Kim 443219f535SJung-uk Kim #include <dev/pci/pcireg.h> 453219f535SJung-uk Kim #include <dev/pci/pcivar.h> 4619de5df5SJung-uk Kim 473219f535SJung-uk Kim #include <vm/vm.h> 483219f535SJung-uk Kim #include <vm/pmap.h> 493219f535SJung-uk Kim 50439f3d8bSJung-uk Kim #ifdef __amd64__ 5148319187SJung-uk Kim #define X86BIOS_NATIVE_ARCH 5248319187SJung-uk Kim #endif 53439f3d8bSJung-uk Kim #ifdef __i386__ 54439f3d8bSJung-uk Kim #define X86BIOS_NATIVE_VM86 55439f3d8bSJung-uk Kim #endif 56439f3d8bSJung-uk Kim 57439f3d8bSJung-uk Kim #define X86BIOS_MEM_SIZE 0x00100000 /* 1M */ 58439f3d8bSJung-uk Kim 59f2c73cefSJung-uk Kim #define X86BIOS_TRACE(h, n, r) do { \ 60f2c73cefSJung-uk Kim printf(__STRING(h) \ 61f2c73cefSJung-uk Kim " (ax=0x%04x bx=0x%04x cx=0x%04x dx=0x%04x es=0x%04x di=0x%04x)\n",\ 62f2c73cefSJung-uk Kim (n), (r)->R_AX, (r)->R_BX, (r)->R_CX, (r)->R_DX, \ 63f2c73cefSJung-uk Kim (r)->R_ES, (r)->R_DI); \ 64f2c73cefSJung-uk Kim } while (0) 65f2c73cefSJung-uk Kim 66439f3d8bSJung-uk Kim static struct mtx x86bios_lock; 67439f3d8bSJung-uk Kim 687029da5cSPawel Biernacki static SYSCTL_NODE(_debug, OID_AUTO, x86bios, CTLFLAG_RD | CTLFLAG_MPSAFE, NULL, 696472ac3dSEd Schouten "x86bios debugging"); 70439f3d8bSJung-uk Kim static int x86bios_trace_call; 71af3b2549SHans Petter Selasky SYSCTL_INT(_debug_x86bios, OID_AUTO, call, CTLFLAG_RWTUN, &x86bios_trace_call, 0, 72439f3d8bSJung-uk Kim "Trace far function calls"); 73439f3d8bSJung-uk Kim static int x86bios_trace_int; 74af3b2549SHans Petter Selasky SYSCTL_INT(_debug_x86bios, OID_AUTO, int, CTLFLAG_RWTUN, &x86bios_trace_int, 0, 75439f3d8bSJung-uk Kim "Trace software interrupt handlers"); 76439f3d8bSJung-uk Kim 77439f3d8bSJung-uk Kim #ifdef X86BIOS_NATIVE_VM86 78439f3d8bSJung-uk Kim 79439f3d8bSJung-uk Kim #include <machine/vm86.h> 80439f3d8bSJung-uk Kim #include <machine/vmparam.h> 81439f3d8bSJung-uk Kim #include <machine/pc/bios.h> 82439f3d8bSJung-uk Kim 83439f3d8bSJung-uk Kim struct vm86context x86bios_vmc; 84439f3d8bSJung-uk Kim 85439f3d8bSJung-uk Kim static void 86439f3d8bSJung-uk Kim x86bios_emu2vmf(struct x86emu_regs *regs, struct vm86frame *vmf) 87439f3d8bSJung-uk Kim { 88439f3d8bSJung-uk Kim 89439f3d8bSJung-uk Kim vmf->vmf_ds = regs->R_DS; 90439f3d8bSJung-uk Kim vmf->vmf_es = regs->R_ES; 91439f3d8bSJung-uk Kim vmf->vmf_ax = regs->R_AX; 92439f3d8bSJung-uk Kim vmf->vmf_bx = regs->R_BX; 93439f3d8bSJung-uk Kim vmf->vmf_cx = regs->R_CX; 94439f3d8bSJung-uk Kim vmf->vmf_dx = regs->R_DX; 95439f3d8bSJung-uk Kim vmf->vmf_bp = regs->R_BP; 96439f3d8bSJung-uk Kim vmf->vmf_si = regs->R_SI; 97439f3d8bSJung-uk Kim vmf->vmf_di = regs->R_DI; 98439f3d8bSJung-uk Kim } 99439f3d8bSJung-uk Kim 100439f3d8bSJung-uk Kim static void 101439f3d8bSJung-uk Kim x86bios_vmf2emu(struct vm86frame *vmf, struct x86emu_regs *regs) 102439f3d8bSJung-uk Kim { 103439f3d8bSJung-uk Kim 104439f3d8bSJung-uk Kim regs->R_DS = vmf->vmf_ds; 105439f3d8bSJung-uk Kim regs->R_ES = vmf->vmf_es; 1060a3493e5SJung-uk Kim regs->R_FLG = vmf->vmf_flags; 107439f3d8bSJung-uk Kim regs->R_AX = vmf->vmf_ax; 108439f3d8bSJung-uk Kim regs->R_BX = vmf->vmf_bx; 109439f3d8bSJung-uk Kim regs->R_CX = vmf->vmf_cx; 110439f3d8bSJung-uk Kim regs->R_DX = vmf->vmf_dx; 111439f3d8bSJung-uk Kim regs->R_BP = vmf->vmf_bp; 112439f3d8bSJung-uk Kim regs->R_SI = vmf->vmf_si; 113439f3d8bSJung-uk Kim regs->R_DI = vmf->vmf_di; 114439f3d8bSJung-uk Kim } 115439f3d8bSJung-uk Kim 116439f3d8bSJung-uk Kim void * 117439f3d8bSJung-uk Kim x86bios_alloc(uint32_t *offset, size_t size, int flags) 118439f3d8bSJung-uk Kim { 119b41f3f4cSJung-uk Kim void *vaddr; 1205cb9d60eSPedro F. Giffuni u_int i; 121439f3d8bSJung-uk Kim 122b41f3f4cSJung-uk Kim if (offset == NULL || size == 0) 123b41f3f4cSJung-uk Kim return (NULL); 124b41f3f4cSJung-uk Kim vaddr = contigmalloc(size, M_DEVBUF, flags, 0, X86BIOS_MEM_SIZE, 125b41f3f4cSJung-uk Kim PAGE_SIZE, 0); 126b41f3f4cSJung-uk Kim if (vaddr != NULL) { 127b41f3f4cSJung-uk Kim *offset = vtophys(vaddr); 128439f3d8bSJung-uk Kim mtx_lock(&x86bios_lock); 129fc82156fSJung-uk Kim for (i = 0; i < atop(round_page(size)); i++) 130f1077673SJung-uk Kim vm86_addpage(&x86bios_vmc, atop(*offset) + i, 131b41f3f4cSJung-uk Kim (vm_offset_t)vaddr + ptoa(i)); 132439f3d8bSJung-uk Kim mtx_unlock(&x86bios_lock); 133439f3d8bSJung-uk Kim } 134439f3d8bSJung-uk Kim 135b41f3f4cSJung-uk Kim return (vaddr); 136439f3d8bSJung-uk Kim } 137439f3d8bSJung-uk Kim 138439f3d8bSJung-uk Kim void 139439f3d8bSJung-uk Kim x86bios_free(void *addr, size_t size) 140439f3d8bSJung-uk Kim { 141b41f3f4cSJung-uk Kim vm_paddr_t paddr; 142b41f3f4cSJung-uk Kim int i, nfree; 143439f3d8bSJung-uk Kim 144b41f3f4cSJung-uk Kim if (addr == NULL || size == 0) 145b41f3f4cSJung-uk Kim return; 146b41f3f4cSJung-uk Kim paddr = vtophys(addr); 147b41f3f4cSJung-uk Kim if (paddr >= X86BIOS_MEM_SIZE || (paddr & PAGE_MASK) != 0) 148b41f3f4cSJung-uk Kim return; 149439f3d8bSJung-uk Kim mtx_lock(&x86bios_lock); 150b41f3f4cSJung-uk Kim for (i = 0; i < x86bios_vmc.npages; i++) 151b41f3f4cSJung-uk Kim if (x86bios_vmc.pmap[i].kva == (vm_offset_t)addr) 152b41f3f4cSJung-uk Kim break; 153b41f3f4cSJung-uk Kim if (i >= x86bios_vmc.npages) { 154f1077673SJung-uk Kim mtx_unlock(&x86bios_lock); 155f1077673SJung-uk Kim return; 156f1077673SJung-uk Kim } 157b3165075SJung-uk Kim nfree = atop(round_page(size)); 158b41f3f4cSJung-uk Kim bzero(x86bios_vmc.pmap + i, sizeof(*x86bios_vmc.pmap) * nfree); 159b41f3f4cSJung-uk Kim if (i + nfree == x86bios_vmc.npages) { 160b41f3f4cSJung-uk Kim x86bios_vmc.npages -= nfree; 161b41f3f4cSJung-uk Kim while (--i >= 0 && x86bios_vmc.pmap[i].kva == 0) 162439f3d8bSJung-uk Kim x86bios_vmc.npages--; 163439f3d8bSJung-uk Kim } 164439f3d8bSJung-uk Kim mtx_unlock(&x86bios_lock); 165*d1bdc282SBjoern A. Zeeb free(addr, M_DEVBUF); 166439f3d8bSJung-uk Kim } 167439f3d8bSJung-uk Kim 168439f3d8bSJung-uk Kim void 169439f3d8bSJung-uk Kim x86bios_init_regs(struct x86regs *regs) 170439f3d8bSJung-uk Kim { 171439f3d8bSJung-uk Kim 172439f3d8bSJung-uk Kim bzero(regs, sizeof(*regs)); 173439f3d8bSJung-uk Kim } 174439f3d8bSJung-uk Kim 175439f3d8bSJung-uk Kim void 176439f3d8bSJung-uk Kim x86bios_call(struct x86regs *regs, uint16_t seg, uint16_t off) 177439f3d8bSJung-uk Kim { 178439f3d8bSJung-uk Kim struct vm86frame vmf; 179439f3d8bSJung-uk Kim 180439f3d8bSJung-uk Kim if (x86bios_trace_call) 181f2c73cefSJung-uk Kim X86BIOS_TRACE(Calling 0x%06x, (seg << 4) + off, regs); 182439f3d8bSJung-uk Kim 183439f3d8bSJung-uk Kim bzero(&vmf, sizeof(vmf)); 184439f3d8bSJung-uk Kim x86bios_emu2vmf((struct x86emu_regs *)regs, &vmf); 185439f3d8bSJung-uk Kim vmf.vmf_cs = seg; 186439f3d8bSJung-uk Kim vmf.vmf_ip = off; 187439f3d8bSJung-uk Kim mtx_lock(&x86bios_lock); 188439f3d8bSJung-uk Kim vm86_datacall(-1, &vmf, &x86bios_vmc); 189439f3d8bSJung-uk Kim mtx_unlock(&x86bios_lock); 190439f3d8bSJung-uk Kim x86bios_vmf2emu(&vmf, (struct x86emu_regs *)regs); 191439f3d8bSJung-uk Kim 192439f3d8bSJung-uk Kim if (x86bios_trace_call) 193f2c73cefSJung-uk Kim X86BIOS_TRACE(Exiting 0x%06x, (seg << 4) + off, regs); 194439f3d8bSJung-uk Kim } 195439f3d8bSJung-uk Kim 196439f3d8bSJung-uk Kim uint32_t 197439f3d8bSJung-uk Kim x86bios_get_intr(int intno) 198439f3d8bSJung-uk Kim { 199439f3d8bSJung-uk Kim 200d7a5fb63SJung-uk Kim return (readl(BIOS_PADDRTOVADDR(intno * 4))); 201439f3d8bSJung-uk Kim } 202439f3d8bSJung-uk Kim 203439f3d8bSJung-uk Kim void 20497e6525dSJung-uk Kim x86bios_set_intr(int intno, uint32_t saddr) 20597e6525dSJung-uk Kim { 20697e6525dSJung-uk Kim 20797e6525dSJung-uk Kim writel(BIOS_PADDRTOVADDR(intno * 4), saddr); 20897e6525dSJung-uk Kim } 20997e6525dSJung-uk Kim 21097e6525dSJung-uk Kim void 211439f3d8bSJung-uk Kim x86bios_intr(struct x86regs *regs, int intno) 212439f3d8bSJung-uk Kim { 213439f3d8bSJung-uk Kim struct vm86frame vmf; 214439f3d8bSJung-uk Kim 215439f3d8bSJung-uk Kim if (x86bios_trace_int) 216f2c73cefSJung-uk Kim X86BIOS_TRACE(Calling INT 0x%02x, intno, regs); 217439f3d8bSJung-uk Kim 218439f3d8bSJung-uk Kim bzero(&vmf, sizeof(vmf)); 219439f3d8bSJung-uk Kim x86bios_emu2vmf((struct x86emu_regs *)regs, &vmf); 220439f3d8bSJung-uk Kim mtx_lock(&x86bios_lock); 221439f3d8bSJung-uk Kim vm86_datacall(intno, &vmf, &x86bios_vmc); 222439f3d8bSJung-uk Kim mtx_unlock(&x86bios_lock); 223439f3d8bSJung-uk Kim x86bios_vmf2emu(&vmf, (struct x86emu_regs *)regs); 224439f3d8bSJung-uk Kim 225439f3d8bSJung-uk Kim if (x86bios_trace_int) 226f2c73cefSJung-uk Kim X86BIOS_TRACE(Exiting INT 0x%02x, intno, regs); 227439f3d8bSJung-uk Kim } 228439f3d8bSJung-uk Kim 229439f3d8bSJung-uk Kim void * 230439f3d8bSJung-uk Kim x86bios_offset(uint32_t offset) 231439f3d8bSJung-uk Kim { 232439f3d8bSJung-uk Kim vm_offset_t addr; 233439f3d8bSJung-uk Kim 234439f3d8bSJung-uk Kim addr = vm86_getaddr(&x86bios_vmc, X86BIOS_PHYSTOSEG(offset), 235439f3d8bSJung-uk Kim X86BIOS_PHYSTOOFF(offset)); 236439f3d8bSJung-uk Kim if (addr == 0) 237439f3d8bSJung-uk Kim addr = BIOS_PADDRTOVADDR(offset); 238439f3d8bSJung-uk Kim 239439f3d8bSJung-uk Kim return ((void *)addr); 240439f3d8bSJung-uk Kim } 241439f3d8bSJung-uk Kim 242439f3d8bSJung-uk Kim static int 243439f3d8bSJung-uk Kim x86bios_init(void) 244439f3d8bSJung-uk Kim { 245439f3d8bSJung-uk Kim 246439f3d8bSJung-uk Kim mtx_init(&x86bios_lock, "x86bios lock", NULL, MTX_DEF); 247439f3d8bSJung-uk Kim bzero(&x86bios_vmc, sizeof(x86bios_vmc)); 248439f3d8bSJung-uk Kim 249439f3d8bSJung-uk Kim return (0); 250439f3d8bSJung-uk Kim } 251439f3d8bSJung-uk Kim 252439f3d8bSJung-uk Kim static int 253439f3d8bSJung-uk Kim x86bios_uninit(void) 254439f3d8bSJung-uk Kim { 255439f3d8bSJung-uk Kim 256439f3d8bSJung-uk Kim mtx_destroy(&x86bios_lock); 257439f3d8bSJung-uk Kim 258439f3d8bSJung-uk Kim return (0); 259439f3d8bSJung-uk Kim } 260439f3d8bSJung-uk Kim 261439f3d8bSJung-uk Kim #else 262439f3d8bSJung-uk Kim 263439f3d8bSJung-uk Kim #include <machine/iodev.h> 26448319187SJung-uk Kim 2653219f535SJung-uk Kim #define X86BIOS_PAGE_SIZE 0x00001000 /* 4K */ 2663219f535SJung-uk Kim 2673219f535SJung-uk Kim #define X86BIOS_IVT_SIZE 0x00000500 /* 1K + 256 (BDA) */ 2683219f535SJung-uk Kim 2693219f535SJung-uk Kim #define X86BIOS_IVT_BASE 0x00000000 2703219f535SJung-uk Kim #define X86BIOS_RAM_BASE 0x00001000 271ef8201d3SJung-uk Kim #define X86BIOS_ROM_BASE 0x000a0000 2723219f535SJung-uk Kim 273f2c73cefSJung-uk Kim #define X86BIOS_ROM_SIZE (X86BIOS_MEM_SIZE - x86bios_rom_phys) 274439f3d8bSJung-uk Kim #define X86BIOS_SEG_SIZE X86BIOS_PAGE_SIZE 2753219f535SJung-uk Kim 2763219f535SJung-uk Kim #define X86BIOS_PAGES (X86BIOS_MEM_SIZE / X86BIOS_PAGE_SIZE) 2773219f535SJung-uk Kim 2783219f535SJung-uk Kim #define X86BIOS_R_SS _pad2 279439f3d8bSJung-uk Kim #define X86BIOS_R_SP _pad3.I16_reg.x_reg 28019de5df5SJung-uk Kim 28119de5df5SJung-uk Kim static struct x86emu x86bios_emu; 28219de5df5SJung-uk Kim 2833219f535SJung-uk Kim static void *x86bios_ivt; 2843219f535SJung-uk Kim static void *x86bios_rom; 2853219f535SJung-uk Kim static void *x86bios_seg; 2863219f535SJung-uk Kim 2873219f535SJung-uk Kim static vm_offset_t *x86bios_map; 2883219f535SJung-uk Kim 289ef8201d3SJung-uk Kim static vm_paddr_t x86bios_rom_phys; 2903219f535SJung-uk Kim static vm_paddr_t x86bios_seg_phys; 2913219f535SJung-uk Kim 292b92184ecSJung-uk Kim static int x86bios_fault; 293b92184ecSJung-uk Kim static uint32_t x86bios_fault_addr; 294ef8201d3SJung-uk Kim static uint16_t x86bios_fault_cs; 295ef8201d3SJung-uk Kim static uint16_t x86bios_fault_ip; 296b92184ecSJung-uk Kim 297b92184ecSJung-uk Kim static void 298b92184ecSJung-uk Kim x86bios_set_fault(struct x86emu *emu, uint32_t addr) 299b92184ecSJung-uk Kim { 300b92184ecSJung-uk Kim 301b92184ecSJung-uk Kim x86bios_fault = 1; 302b92184ecSJung-uk Kim x86bios_fault_addr = addr; 303ef8201d3SJung-uk Kim x86bios_fault_cs = emu->x86.R_CS; 304ef8201d3SJung-uk Kim x86bios_fault_ip = emu->x86.R_IP; 305ef8201d3SJung-uk Kim x86emu_halt_sys(emu); 306b92184ecSJung-uk Kim } 307b92184ecSJung-uk Kim 3083219f535SJung-uk Kim static void * 3093219f535SJung-uk Kim x86bios_get_pages(uint32_t offset, size_t size) 3103219f535SJung-uk Kim { 311439f3d8bSJung-uk Kim vm_offset_t addr; 3123219f535SJung-uk Kim 313c9cefec1SJung-uk Kim if (offset + size > X86BIOS_MEM_SIZE + X86BIOS_IVT_SIZE) 3143219f535SJung-uk Kim return (NULL); 3153219f535SJung-uk Kim 316c9cefec1SJung-uk Kim if (offset >= X86BIOS_MEM_SIZE) 317c9cefec1SJung-uk Kim offset -= X86BIOS_MEM_SIZE; 318439f3d8bSJung-uk Kim addr = x86bios_map[offset / X86BIOS_PAGE_SIZE]; 319439f3d8bSJung-uk Kim if (addr != 0) 320439f3d8bSJung-uk Kim addr += offset % X86BIOS_PAGE_SIZE; 3213219f535SJung-uk Kim 322439f3d8bSJung-uk Kim return ((void *)addr); 3233219f535SJung-uk Kim } 3243219f535SJung-uk Kim 3253219f535SJung-uk Kim static void 3263219f535SJung-uk Kim x86bios_set_pages(vm_offset_t va, vm_paddr_t pa, size_t size) 3273219f535SJung-uk Kim { 3283219f535SJung-uk Kim int i, j; 3293219f535SJung-uk Kim 3303219f535SJung-uk Kim for (i = pa / X86BIOS_PAGE_SIZE, j = 0; 3313219f535SJung-uk Kim j < howmany(size, X86BIOS_PAGE_SIZE); i++, j++) 3323219f535SJung-uk Kim x86bios_map[i] = va + j * X86BIOS_PAGE_SIZE; 3333219f535SJung-uk Kim } 3343219f535SJung-uk Kim 3353219f535SJung-uk Kim static uint8_t 3363219f535SJung-uk Kim x86bios_emu_rdb(struct x86emu *emu, uint32_t addr) 3373219f535SJung-uk Kim { 3383219f535SJung-uk Kim uint8_t *va; 3393219f535SJung-uk Kim 3403219f535SJung-uk Kim va = x86bios_get_pages(addr, sizeof(*va)); 341ef8201d3SJung-uk Kim if (va == NULL) 342b92184ecSJung-uk Kim x86bios_set_fault(emu, addr); 3433219f535SJung-uk Kim 3443219f535SJung-uk Kim return (*va); 3453219f535SJung-uk Kim } 3463219f535SJung-uk Kim 3473219f535SJung-uk Kim static uint16_t 3483219f535SJung-uk Kim x86bios_emu_rdw(struct x86emu *emu, uint32_t addr) 3493219f535SJung-uk Kim { 3503219f535SJung-uk Kim uint16_t *va; 3513219f535SJung-uk Kim 3523219f535SJung-uk Kim va = x86bios_get_pages(addr, sizeof(*va)); 353ef8201d3SJung-uk Kim if (va == NULL) 354b92184ecSJung-uk Kim x86bios_set_fault(emu, addr); 3553219f535SJung-uk Kim 356ef8201d3SJung-uk Kim #ifndef __NO_STRICT_ALIGNMENT 357ef8201d3SJung-uk Kim if ((addr & 1) != 0) 358ef8201d3SJung-uk Kim return (le16dec(va)); 359ef8201d3SJung-uk Kim else 360ef8201d3SJung-uk Kim #endif 3613219f535SJung-uk Kim return (le16toh(*va)); 3623219f535SJung-uk Kim } 3633219f535SJung-uk Kim 3643219f535SJung-uk Kim static uint32_t 3653219f535SJung-uk Kim x86bios_emu_rdl(struct x86emu *emu, uint32_t addr) 3663219f535SJung-uk Kim { 3673219f535SJung-uk Kim uint32_t *va; 3683219f535SJung-uk Kim 3693219f535SJung-uk Kim va = x86bios_get_pages(addr, sizeof(*va)); 370ef8201d3SJung-uk Kim if (va == NULL) 371b92184ecSJung-uk Kim x86bios_set_fault(emu, addr); 3723219f535SJung-uk Kim 373ef8201d3SJung-uk Kim #ifndef __NO_STRICT_ALIGNMENT 374ef8201d3SJung-uk Kim if ((addr & 3) != 0) 375ef8201d3SJung-uk Kim return (le32dec(va)); 376ef8201d3SJung-uk Kim else 377ef8201d3SJung-uk Kim #endif 3783219f535SJung-uk Kim return (le32toh(*va)); 3793219f535SJung-uk Kim } 3803219f535SJung-uk Kim 3813219f535SJung-uk Kim static void 3823219f535SJung-uk Kim x86bios_emu_wrb(struct x86emu *emu, uint32_t addr, uint8_t val) 3833219f535SJung-uk Kim { 3843219f535SJung-uk Kim uint8_t *va; 3853219f535SJung-uk Kim 3863219f535SJung-uk Kim va = x86bios_get_pages(addr, sizeof(*va)); 387ef8201d3SJung-uk Kim if (va == NULL) 388b92184ecSJung-uk Kim x86bios_set_fault(emu, addr); 3893219f535SJung-uk Kim 3903219f535SJung-uk Kim *va = val; 3913219f535SJung-uk Kim } 3923219f535SJung-uk Kim 3933219f535SJung-uk Kim static void 3943219f535SJung-uk Kim x86bios_emu_wrw(struct x86emu *emu, uint32_t addr, uint16_t val) 3953219f535SJung-uk Kim { 3963219f535SJung-uk Kim uint16_t *va; 3973219f535SJung-uk Kim 3983219f535SJung-uk Kim va = x86bios_get_pages(addr, sizeof(*va)); 399ef8201d3SJung-uk Kim if (va == NULL) 400b92184ecSJung-uk Kim x86bios_set_fault(emu, addr); 4013219f535SJung-uk Kim 402ef8201d3SJung-uk Kim #ifndef __NO_STRICT_ALIGNMENT 403ef8201d3SJung-uk Kim if ((addr & 1) != 0) 404ef8201d3SJung-uk Kim le16enc(va, val); 405ef8201d3SJung-uk Kim else 406ef8201d3SJung-uk Kim #endif 4073219f535SJung-uk Kim *va = htole16(val); 4083219f535SJung-uk Kim } 4093219f535SJung-uk Kim 4103219f535SJung-uk Kim static void 4113219f535SJung-uk Kim x86bios_emu_wrl(struct x86emu *emu, uint32_t addr, uint32_t val) 4123219f535SJung-uk Kim { 4133219f535SJung-uk Kim uint32_t *va; 4143219f535SJung-uk Kim 4153219f535SJung-uk Kim va = x86bios_get_pages(addr, sizeof(*va)); 416ef8201d3SJung-uk Kim if (va == NULL) 417b92184ecSJung-uk Kim x86bios_set_fault(emu, addr); 4183219f535SJung-uk Kim 419ef8201d3SJung-uk Kim #ifndef __NO_STRICT_ALIGNMENT 420ef8201d3SJung-uk Kim if ((addr & 3) != 0) 421ef8201d3SJung-uk Kim le32enc(va, val); 422ef8201d3SJung-uk Kim else 423ef8201d3SJung-uk Kim #endif 4243219f535SJung-uk Kim *va = htole32(val); 4253219f535SJung-uk Kim } 4263219f535SJung-uk Kim 42719de5df5SJung-uk Kim static uint8_t 42819de5df5SJung-uk Kim x86bios_emu_inb(struct x86emu *emu, uint16_t port) 42919de5df5SJung-uk Kim { 43019de5df5SJung-uk Kim 431a6d613a5SJung-uk Kim #ifndef X86BIOS_NATIVE_ARCH 43219de5df5SJung-uk Kim if (port == 0xb2) /* APM scratch register */ 43319de5df5SJung-uk Kim return (0); 43419de5df5SJung-uk Kim if (port >= 0x80 && port < 0x88) /* POST status register */ 43519de5df5SJung-uk Kim return (0); 436a6d613a5SJung-uk Kim #endif 4373219f535SJung-uk Kim 43848319187SJung-uk Kim return (iodev_read_1(port)); 43919de5df5SJung-uk Kim } 44019de5df5SJung-uk Kim 44119de5df5SJung-uk Kim static uint16_t 44219de5df5SJung-uk Kim x86bios_emu_inw(struct x86emu *emu, uint16_t port) 44319de5df5SJung-uk Kim { 44448319187SJung-uk Kim uint16_t val; 44519de5df5SJung-uk Kim 446a6d613a5SJung-uk Kim #ifndef X86BIOS_NATIVE_ARCH 44719de5df5SJung-uk Kim if (port >= 0x80 && port < 0x88) /* POST status register */ 44819de5df5SJung-uk Kim return (0); 4493219f535SJung-uk Kim 45048319187SJung-uk Kim if ((port & 1) != 0) { 45148319187SJung-uk Kim val = iodev_read_1(port); 45248319187SJung-uk Kim val |= iodev_read_1(port + 1) << 8; 45348319187SJung-uk Kim } else 45448319187SJung-uk Kim #endif 45548319187SJung-uk Kim val = iodev_read_2(port); 45648319187SJung-uk Kim 45748319187SJung-uk Kim return (val); 45819de5df5SJung-uk Kim } 45919de5df5SJung-uk Kim 46019de5df5SJung-uk Kim static uint32_t 46119de5df5SJung-uk Kim x86bios_emu_inl(struct x86emu *emu, uint16_t port) 46219de5df5SJung-uk Kim { 46348319187SJung-uk Kim uint32_t val; 46419de5df5SJung-uk Kim 465a6d613a5SJung-uk Kim #ifndef X86BIOS_NATIVE_ARCH 46619de5df5SJung-uk Kim if (port >= 0x80 && port < 0x88) /* POST status register */ 46719de5df5SJung-uk Kim return (0); 4683219f535SJung-uk Kim 46948319187SJung-uk Kim if ((port & 1) != 0) { 47048319187SJung-uk Kim val = iodev_read_1(port); 47148319187SJung-uk Kim val |= iodev_read_2(port + 1) << 8; 47248319187SJung-uk Kim val |= iodev_read_1(port + 3) << 24; 47348319187SJung-uk Kim } else if ((port & 2) != 0) { 47448319187SJung-uk Kim val = iodev_read_2(port); 47548319187SJung-uk Kim val |= iodev_read_2(port + 2) << 16; 47648319187SJung-uk Kim } else 47748319187SJung-uk Kim #endif 47848319187SJung-uk Kim val = iodev_read_4(port); 47948319187SJung-uk Kim 48048319187SJung-uk Kim return (val); 48119de5df5SJung-uk Kim } 48219de5df5SJung-uk Kim 48319de5df5SJung-uk Kim static void 48419de5df5SJung-uk Kim x86bios_emu_outb(struct x86emu *emu, uint16_t port, uint8_t val) 48519de5df5SJung-uk Kim { 48619de5df5SJung-uk Kim 487a6d613a5SJung-uk Kim #ifndef X86BIOS_NATIVE_ARCH 48819de5df5SJung-uk Kim if (port == 0xb2) /* APM scratch register */ 48919de5df5SJung-uk Kim return; 49019de5df5SJung-uk Kim if (port >= 0x80 && port < 0x88) /* POST status register */ 49119de5df5SJung-uk Kim return; 492a6d613a5SJung-uk Kim #endif 4933219f535SJung-uk Kim 49448319187SJung-uk Kim iodev_write_1(port, val); 49519de5df5SJung-uk Kim } 49619de5df5SJung-uk Kim 49719de5df5SJung-uk Kim static void 49819de5df5SJung-uk Kim x86bios_emu_outw(struct x86emu *emu, uint16_t port, uint16_t val) 49919de5df5SJung-uk Kim { 50019de5df5SJung-uk Kim 501a6d613a5SJung-uk Kim #ifndef X86BIOS_NATIVE_ARCH 50219de5df5SJung-uk Kim if (port >= 0x80 && port < 0x88) /* POST status register */ 50319de5df5SJung-uk Kim return; 5043219f535SJung-uk Kim 50548319187SJung-uk Kim if ((port & 1) != 0) { 50648319187SJung-uk Kim iodev_write_1(port, val); 50748319187SJung-uk Kim iodev_write_1(port + 1, val >> 8); 50848319187SJung-uk Kim } else 50948319187SJung-uk Kim #endif 51048319187SJung-uk Kim iodev_write_2(port, val); 51119de5df5SJung-uk Kim } 51219de5df5SJung-uk Kim 51319de5df5SJung-uk Kim static void 51419de5df5SJung-uk Kim x86bios_emu_outl(struct x86emu *emu, uint16_t port, uint32_t val) 51519de5df5SJung-uk Kim { 51619de5df5SJung-uk Kim 517a6d613a5SJung-uk Kim #ifndef X86BIOS_NATIVE_ARCH 51819de5df5SJung-uk Kim if (port >= 0x80 && port < 0x88) /* POST status register */ 51919de5df5SJung-uk Kim return; 5203219f535SJung-uk Kim 52148319187SJung-uk Kim if ((port & 1) != 0) { 52248319187SJung-uk Kim iodev_write_1(port, val); 52348319187SJung-uk Kim iodev_write_2(port + 1, val >> 8); 52448319187SJung-uk Kim iodev_write_1(port + 3, val >> 24); 52548319187SJung-uk Kim } else if ((port & 2) != 0) { 52648319187SJung-uk Kim iodev_write_2(port, val); 52748319187SJung-uk Kim iodev_write_2(port + 2, val >> 16); 52848319187SJung-uk Kim } else 52948319187SJung-uk Kim #endif 53048319187SJung-uk Kim iodev_write_4(port, val); 53119de5df5SJung-uk Kim } 53219de5df5SJung-uk Kim 5333219f535SJung-uk Kim void * 534362487c0SJung-uk Kim x86bios_alloc(uint32_t *offset, size_t size, int flags) 5353219f535SJung-uk Kim { 5363219f535SJung-uk Kim void *vaddr; 5373219f535SJung-uk Kim 5383219f535SJung-uk Kim if (offset == NULL || size == 0) 5393219f535SJung-uk Kim return (NULL); 540362487c0SJung-uk Kim vaddr = contigmalloc(size, M_DEVBUF, flags, X86BIOS_RAM_BASE, 541ef8201d3SJung-uk Kim x86bios_rom_phys, X86BIOS_PAGE_SIZE, 0); 5423219f535SJung-uk Kim if (vaddr != NULL) { 5433219f535SJung-uk Kim *offset = vtophys(vaddr); 544449918b1SJung-uk Kim mtx_lock(&x86bios_lock); 5453219f535SJung-uk Kim x86bios_set_pages((vm_offset_t)vaddr, *offset, size); 546449918b1SJung-uk Kim mtx_unlock(&x86bios_lock); 5473219f535SJung-uk Kim } 5483219f535SJung-uk Kim 5493219f535SJung-uk Kim return (vaddr); 5503219f535SJung-uk Kim } 5513219f535SJung-uk Kim 5523219f535SJung-uk Kim void 5533219f535SJung-uk Kim x86bios_free(void *addr, size_t size) 5543219f535SJung-uk Kim { 5553219f535SJung-uk Kim vm_paddr_t paddr; 5563219f535SJung-uk Kim 5573219f535SJung-uk Kim if (addr == NULL || size == 0) 5583219f535SJung-uk Kim return; 5593219f535SJung-uk Kim paddr = vtophys(addr); 560ef8201d3SJung-uk Kim if (paddr < X86BIOS_RAM_BASE || paddr >= x86bios_rom_phys || 5613219f535SJung-uk Kim paddr % X86BIOS_PAGE_SIZE != 0) 5623219f535SJung-uk Kim return; 563449918b1SJung-uk Kim mtx_lock(&x86bios_lock); 5643219f535SJung-uk Kim bzero(x86bios_map + paddr / X86BIOS_PAGE_SIZE, 5653219f535SJung-uk Kim sizeof(*x86bios_map) * howmany(size, X86BIOS_PAGE_SIZE)); 566449918b1SJung-uk Kim mtx_unlock(&x86bios_lock); 567*d1bdc282SBjoern A. Zeeb free(addr, M_DEVBUF); 5683219f535SJung-uk Kim } 5693219f535SJung-uk Kim 5703219f535SJung-uk Kim void 5713219f535SJung-uk Kim x86bios_init_regs(struct x86regs *regs) 5723219f535SJung-uk Kim { 5733219f535SJung-uk Kim 5743219f535SJung-uk Kim bzero(regs, sizeof(*regs)); 575439f3d8bSJung-uk Kim regs->X86BIOS_R_SS = X86BIOS_PHYSTOSEG(x86bios_seg_phys); 576439f3d8bSJung-uk Kim regs->X86BIOS_R_SP = X86BIOS_PAGE_SIZE - 2; 5773219f535SJung-uk Kim } 5783219f535SJung-uk Kim 5793219f535SJung-uk Kim void 5803219f535SJung-uk Kim x86bios_call(struct x86regs *regs, uint16_t seg, uint16_t off) 5813219f535SJung-uk Kim { 5823219f535SJung-uk Kim 5833afa8e56SJung-uk Kim if (x86bios_trace_call) 584f2c73cefSJung-uk Kim X86BIOS_TRACE(Calling 0x%06x, (seg << 4) + off, regs); 5853219f535SJung-uk Kim 586449918b1SJung-uk Kim mtx_lock(&x86bios_lock); 587c2a9e596SJung-uk Kim memcpy((struct x86regs *)&x86bios_emu.x86, regs, sizeof(*regs)); 588b92184ecSJung-uk Kim x86bios_fault = 0; 589077c4b48SJung-uk Kim spinlock_enter(); 5903219f535SJung-uk Kim x86emu_exec_call(&x86bios_emu, seg, off); 591449918b1SJung-uk Kim spinlock_exit(); 592077c4b48SJung-uk Kim memcpy(regs, &x86bios_emu.x86, sizeof(*regs)); 593449918b1SJung-uk Kim mtx_unlock(&x86bios_lock); 5943219f535SJung-uk Kim 595b92184ecSJung-uk Kim if (x86bios_trace_call) { 596f2c73cefSJung-uk Kim X86BIOS_TRACE(Exiting 0x%06x, (seg << 4) + off, regs); 597b92184ecSJung-uk Kim if (x86bios_fault) 598f2c73cefSJung-uk Kim printf("Page fault at 0x%06x from 0x%04x:0x%04x.\n", 599ef8201d3SJung-uk Kim x86bios_fault_addr, x86bios_fault_cs, 600ef8201d3SJung-uk Kim x86bios_fault_ip); 601b92184ecSJung-uk Kim } 6023219f535SJung-uk Kim } 6033219f535SJung-uk Kim 6043219f535SJung-uk Kim uint32_t 6053219f535SJung-uk Kim x86bios_get_intr(int intno) 6063219f535SJung-uk Kim { 6073219f535SJung-uk Kim 60897e6525dSJung-uk Kim return (le32toh(*((uint32_t *)x86bios_ivt + intno))); 60997e6525dSJung-uk Kim } 6103219f535SJung-uk Kim 61197e6525dSJung-uk Kim void 61297e6525dSJung-uk Kim x86bios_set_intr(int intno, uint32_t saddr) 61397e6525dSJung-uk Kim { 61497e6525dSJung-uk Kim 61597e6525dSJung-uk Kim *((uint32_t *)x86bios_ivt + intno) = htole32(saddr); 6163219f535SJung-uk Kim } 6173219f535SJung-uk Kim 61819de5df5SJung-uk Kim void 619a8672748SJung-uk Kim x86bios_intr(struct x86regs *regs, int intno) 62019de5df5SJung-uk Kim { 62119de5df5SJung-uk Kim 62219de5df5SJung-uk Kim if (intno < 0 || intno > 255) 62319de5df5SJung-uk Kim return; 62419de5df5SJung-uk Kim 6253afa8e56SJung-uk Kim if (x86bios_trace_int) 626f2c73cefSJung-uk Kim X86BIOS_TRACE(Calling INT 0x%02x, intno, regs); 6275ec510d8SJung-uk Kim 628449918b1SJung-uk Kim mtx_lock(&x86bios_lock); 629c2a9e596SJung-uk Kim memcpy((struct x86regs *)&x86bios_emu.x86, regs, sizeof(*regs)); 630b92184ecSJung-uk Kim x86bios_fault = 0; 631077c4b48SJung-uk Kim spinlock_enter(); 63219de5df5SJung-uk Kim x86emu_exec_intr(&x86bios_emu, intno); 633449918b1SJung-uk Kim spinlock_exit(); 634077c4b48SJung-uk Kim memcpy(regs, &x86bios_emu.x86, sizeof(*regs)); 635449918b1SJung-uk Kim mtx_unlock(&x86bios_lock); 6365ec510d8SJung-uk Kim 637b92184ecSJung-uk Kim if (x86bios_trace_int) { 638f2c73cefSJung-uk Kim X86BIOS_TRACE(Exiting INT 0x%02x, intno, regs); 639b92184ecSJung-uk Kim if (x86bios_fault) 640f2c73cefSJung-uk Kim printf("Page fault at 0x%06x from 0x%04x:0x%04x.\n", 641ef8201d3SJung-uk Kim x86bios_fault_addr, x86bios_fault_cs, 642ef8201d3SJung-uk Kim x86bios_fault_ip); 643b92184ecSJung-uk Kim } 64419de5df5SJung-uk Kim } 64519de5df5SJung-uk Kim 64619de5df5SJung-uk Kim void * 6473219f535SJung-uk Kim x86bios_offset(uint32_t offset) 64819de5df5SJung-uk Kim { 64919de5df5SJung-uk Kim 6503219f535SJung-uk Kim return (x86bios_get_pages(offset, 1)); 6513219f535SJung-uk Kim } 6523219f535SJung-uk Kim 65348319187SJung-uk Kim static __inline void 65448319187SJung-uk Kim x86bios_unmap_mem(void) 65548319187SJung-uk Kim { 65648319187SJung-uk Kim 657d01d12deSRoger Pau Monné if (x86bios_map != NULL) { 658449918b1SJung-uk Kim free(x86bios_map, M_DEVBUF); 659d01d12deSRoger Pau Monné x86bios_map = NULL; 660d01d12deSRoger Pau Monné } 661d01d12deSRoger Pau Monné if (x86bios_ivt != NULL) { 66248319187SJung-uk Kim #ifdef X86BIOS_NATIVE_ARCH 6637ae99f80SJohn Baldwin pmap_unmapbios(x86bios_ivt, X86BIOS_IVT_SIZE); 664ef8201d3SJung-uk Kim #else 66548319187SJung-uk Kim free(x86bios_ivt, M_DEVBUF); 666d01d12deSRoger Pau Monné x86bios_ivt = NULL; 667ef8201d3SJung-uk Kim #endif 668d01d12deSRoger Pau Monné } 66948319187SJung-uk Kim if (x86bios_rom != NULL) 6707ae99f80SJohn Baldwin pmap_unmapdev(x86bios_rom, X86BIOS_ROM_SIZE); 671d01d12deSRoger Pau Monné if (x86bios_seg != NULL) { 672*d1bdc282SBjoern A. Zeeb free(x86bios_seg, M_DEVBUF); 673d01d12deSRoger Pau Monné x86bios_seg = NULL; 674d01d12deSRoger Pau Monné } 67548319187SJung-uk Kim } 676ef8201d3SJung-uk Kim 6773219f535SJung-uk Kim static __inline int 6783219f535SJung-uk Kim x86bios_map_mem(void) 6793219f535SJung-uk Kim { 6803219f535SJung-uk Kim 681449918b1SJung-uk Kim x86bios_map = malloc(sizeof(*x86bios_map) * X86BIOS_PAGES, M_DEVBUF, 682d01d12deSRoger Pau Monné M_NOWAIT | M_ZERO); 683d01d12deSRoger Pau Monné if (x86bios_map == NULL) 684d01d12deSRoger Pau Monné goto fail; 685449918b1SJung-uk Kim 68648319187SJung-uk Kim #ifdef X86BIOS_NATIVE_ARCH 6875a0a9182SJung-uk Kim x86bios_ivt = pmap_mapbios(X86BIOS_IVT_BASE, X86BIOS_IVT_SIZE); 688ef8201d3SJung-uk Kim 689ef8201d3SJung-uk Kim /* Probe EBDA via BDA. */ 69048319187SJung-uk Kim x86bios_rom_phys = *(uint16_t *)((caddr_t)x86bios_ivt + 0x40e); 69148319187SJung-uk Kim x86bios_rom_phys = x86bios_rom_phys << 4; 692ef8201d3SJung-uk Kim if (x86bios_rom_phys != 0 && x86bios_rom_phys < X86BIOS_ROM_BASE && 693ef8201d3SJung-uk Kim X86BIOS_ROM_BASE - x86bios_rom_phys <= 128 * 1024) 694ef8201d3SJung-uk Kim x86bios_rom_phys = 695ef8201d3SJung-uk Kim rounddown(x86bios_rom_phys, X86BIOS_PAGE_SIZE); 696ef8201d3SJung-uk Kim else 69748319187SJung-uk Kim #else 698d01d12deSRoger Pau Monné x86bios_ivt = malloc(X86BIOS_IVT_SIZE, M_DEVBUF, M_NOWAIT | M_ZERO); 699d01d12deSRoger Pau Monné if (x86bios_ivt == NULL) 700d01d12deSRoger Pau Monné goto fail; 70148319187SJung-uk Kim #endif 70248319187SJung-uk Kim 703ef8201d3SJung-uk Kim x86bios_rom_phys = X86BIOS_ROM_BASE; 704ef8201d3SJung-uk Kim x86bios_rom = pmap_mapdev(x86bios_rom_phys, X86BIOS_ROM_SIZE); 70548319187SJung-uk Kim if (x86bios_rom == NULL) 70648319187SJung-uk Kim goto fail; 707439f3d8bSJung-uk Kim #ifdef X86BIOS_NATIVE_ARCH 708ef8201d3SJung-uk Kim /* Change attribute for EBDA. */ 709ef8201d3SJung-uk Kim if (x86bios_rom_phys < X86BIOS_ROM_BASE && 710ef8201d3SJung-uk Kim pmap_change_attr((vm_offset_t)x86bios_rom, 71148319187SJung-uk Kim X86BIOS_ROM_BASE - x86bios_rom_phys, PAT_WRITE_BACK) != 0) 71248319187SJung-uk Kim goto fail; 713ef8201d3SJung-uk Kim #endif 714ef8201d3SJung-uk Kim 715d01d12deSRoger Pau Monné x86bios_seg = contigmalloc(X86BIOS_SEG_SIZE, M_DEVBUF, M_NOWAIT, 716ef8201d3SJung-uk Kim X86BIOS_RAM_BASE, x86bios_rom_phys, X86BIOS_PAGE_SIZE, 0); 717d01d12deSRoger Pau Monné if (x86bios_seg == NULL) 718d01d12deSRoger Pau Monné goto fail; 7193219f535SJung-uk Kim x86bios_seg_phys = vtophys(x86bios_seg); 7203219f535SJung-uk Kim 721449918b1SJung-uk Kim x86bios_set_pages((vm_offset_t)x86bios_ivt, X86BIOS_IVT_BASE, 722449918b1SJung-uk Kim X86BIOS_IVT_SIZE); 723449918b1SJung-uk Kim x86bios_set_pages((vm_offset_t)x86bios_rom, x86bios_rom_phys, 724449918b1SJung-uk Kim X86BIOS_ROM_SIZE); 725449918b1SJung-uk Kim x86bios_set_pages((vm_offset_t)x86bios_seg, x86bios_seg_phys, 726449918b1SJung-uk Kim X86BIOS_SEG_SIZE); 727449918b1SJung-uk Kim 728ef8201d3SJung-uk Kim if (bootverbose) { 729f2c73cefSJung-uk Kim printf("x86bios: IVT 0x%06jx-0x%06jx at %p\n", 730f2c73cefSJung-uk Kim (vm_paddr_t)X86BIOS_IVT_BASE, 731f2c73cefSJung-uk Kim (vm_paddr_t)X86BIOS_IVT_SIZE + X86BIOS_IVT_BASE - 1, 732ef8201d3SJung-uk Kim x86bios_ivt); 733f2c73cefSJung-uk Kim printf("x86bios: SSEG 0x%06jx-0x%06jx at %p\n", 734f2c73cefSJung-uk Kim x86bios_seg_phys, 735f2c73cefSJung-uk Kim (vm_paddr_t)X86BIOS_SEG_SIZE + x86bios_seg_phys - 1, 736ef8201d3SJung-uk Kim x86bios_seg); 737ef8201d3SJung-uk Kim if (x86bios_rom_phys < X86BIOS_ROM_BASE) 738f2c73cefSJung-uk Kim printf("x86bios: EBDA 0x%06jx-0x%06jx at %p\n", 739f2c73cefSJung-uk Kim x86bios_rom_phys, (vm_paddr_t)X86BIOS_ROM_BASE - 1, 740ef8201d3SJung-uk Kim x86bios_rom); 741f2c73cefSJung-uk Kim printf("x86bios: ROM 0x%06jx-0x%06jx at %p\n", 742f2c73cefSJung-uk Kim (vm_paddr_t)X86BIOS_ROM_BASE, 743f2c73cefSJung-uk Kim (vm_paddr_t)X86BIOS_MEM_SIZE - X86BIOS_SEG_SIZE - 1, 744f2c73cefSJung-uk Kim (caddr_t)x86bios_rom + X86BIOS_ROM_BASE - x86bios_rom_phys); 745ef8201d3SJung-uk Kim } 746ef8201d3SJung-uk Kim 7473219f535SJung-uk Kim return (0); 7483219f535SJung-uk Kim 74948319187SJung-uk Kim fail: 75048319187SJung-uk Kim x86bios_unmap_mem(); 751ef8201d3SJung-uk Kim 75248319187SJung-uk Kim return (1); 75319de5df5SJung-uk Kim } 75419de5df5SJung-uk Kim 7552083bca5SJung-uk Kim static int 7562083bca5SJung-uk Kim x86bios_init(void) 75719de5df5SJung-uk Kim { 75819de5df5SJung-uk Kim 759449918b1SJung-uk Kim mtx_init(&x86bios_lock, "x86bios lock", NULL, MTX_DEF); 760449918b1SJung-uk Kim 7613219f535SJung-uk Kim if (x86bios_map_mem() != 0) 7622083bca5SJung-uk Kim return (ENOMEM); 7632083bca5SJung-uk Kim 7643219f535SJung-uk Kim bzero(&x86bios_emu, sizeof(x86bios_emu)); 7653219f535SJung-uk Kim 7663219f535SJung-uk Kim x86bios_emu.emu_rdb = x86bios_emu_rdb; 7673219f535SJung-uk Kim x86bios_emu.emu_rdw = x86bios_emu_rdw; 7683219f535SJung-uk Kim x86bios_emu.emu_rdl = x86bios_emu_rdl; 7693219f535SJung-uk Kim x86bios_emu.emu_wrb = x86bios_emu_wrb; 7703219f535SJung-uk Kim x86bios_emu.emu_wrw = x86bios_emu_wrw; 7713219f535SJung-uk Kim x86bios_emu.emu_wrl = x86bios_emu_wrl; 77219de5df5SJung-uk Kim 77319de5df5SJung-uk Kim x86bios_emu.emu_inb = x86bios_emu_inb; 77419de5df5SJung-uk Kim x86bios_emu.emu_inw = x86bios_emu_inw; 77519de5df5SJung-uk Kim x86bios_emu.emu_inl = x86bios_emu_inl; 77619de5df5SJung-uk Kim x86bios_emu.emu_outb = x86bios_emu_outb; 77719de5df5SJung-uk Kim x86bios_emu.emu_outw = x86bios_emu_outw; 77819de5df5SJung-uk Kim x86bios_emu.emu_outl = x86bios_emu_outl; 77919de5df5SJung-uk Kim 7802083bca5SJung-uk Kim return (0); 78119de5df5SJung-uk Kim } 78219de5df5SJung-uk Kim 7832083bca5SJung-uk Kim static int 7842083bca5SJung-uk Kim x86bios_uninit(void) 78519de5df5SJung-uk Kim { 78619de5df5SJung-uk Kim 7873219f535SJung-uk Kim x86bios_unmap_mem(); 78819de5df5SJung-uk Kim mtx_destroy(&x86bios_lock); 7892083bca5SJung-uk Kim 7902083bca5SJung-uk Kim return (0); 79119de5df5SJung-uk Kim } 79219de5df5SJung-uk Kim 793439f3d8bSJung-uk Kim #endif 794439f3d8bSJung-uk Kim 795439f3d8bSJung-uk Kim void * 796439f3d8bSJung-uk Kim x86bios_get_orm(uint32_t offset) 797439f3d8bSJung-uk Kim { 798439f3d8bSJung-uk Kim uint8_t *p; 799439f3d8bSJung-uk Kim 800439f3d8bSJung-uk Kim /* Does the shadow ROM contain BIOS POST code for x86? */ 801439f3d8bSJung-uk Kim p = x86bios_offset(offset); 802bc339276SJung-uk Kim if (p == NULL || p[0] != 0x55 || p[1] != 0xaa || 803bc339276SJung-uk Kim (p[3] != 0xe9 && p[3] != 0xeb)) 804439f3d8bSJung-uk Kim return (NULL); 805439f3d8bSJung-uk Kim 806439f3d8bSJung-uk Kim return (p); 807439f3d8bSJung-uk Kim } 808439f3d8bSJung-uk Kim 809439f3d8bSJung-uk Kim int 810439f3d8bSJung-uk Kim x86bios_match_device(uint32_t offset, device_t dev) 811439f3d8bSJung-uk Kim { 812439f3d8bSJung-uk Kim uint8_t *p; 813439f3d8bSJung-uk Kim uint16_t device, vendor; 814439f3d8bSJung-uk Kim uint8_t class, progif, subclass; 815439f3d8bSJung-uk Kim 816439f3d8bSJung-uk Kim /* Does the shadow ROM contain BIOS POST code for x86? */ 817439f3d8bSJung-uk Kim p = x86bios_get_orm(offset); 818439f3d8bSJung-uk Kim if (p == NULL) 819439f3d8bSJung-uk Kim return (0); 820439f3d8bSJung-uk Kim 821439f3d8bSJung-uk Kim /* Does it contain PCI data structure? */ 822439f3d8bSJung-uk Kim p += le16toh(*(uint16_t *)(p + 0x18)); 823439f3d8bSJung-uk Kim if (bcmp(p, "PCIR", 4) != 0 || 824439f3d8bSJung-uk Kim le16toh(*(uint16_t *)(p + 0x0a)) < 0x18 || *(p + 0x14) != 0) 825439f3d8bSJung-uk Kim return (0); 826439f3d8bSJung-uk Kim 827439f3d8bSJung-uk Kim /* Does it match the vendor, device, and classcode? */ 828439f3d8bSJung-uk Kim vendor = le16toh(*(uint16_t *)(p + 0x04)); 829439f3d8bSJung-uk Kim device = le16toh(*(uint16_t *)(p + 0x06)); 830439f3d8bSJung-uk Kim progif = *(p + 0x0d); 831439f3d8bSJung-uk Kim subclass = *(p + 0x0e); 832439f3d8bSJung-uk Kim class = *(p + 0x0f); 833439f3d8bSJung-uk Kim if (vendor != pci_get_vendor(dev) || device != pci_get_device(dev) || 834439f3d8bSJung-uk Kim class != pci_get_class(dev) || subclass != pci_get_subclass(dev) || 835439f3d8bSJung-uk Kim progif != pci_get_progif(dev)) 836439f3d8bSJung-uk Kim return (0); 837439f3d8bSJung-uk Kim 838439f3d8bSJung-uk Kim return (1); 839439f3d8bSJung-uk Kim } 840439f3d8bSJung-uk Kim 84119de5df5SJung-uk Kim static int 84219de5df5SJung-uk Kim x86bios_modevent(module_t mod __unused, int type, void *data __unused) 84319de5df5SJung-uk Kim { 84419de5df5SJung-uk Kim 84519de5df5SJung-uk Kim switch (type) { 84619de5df5SJung-uk Kim case MOD_LOAD: 8472083bca5SJung-uk Kim return (x86bios_init()); 84819de5df5SJung-uk Kim case MOD_UNLOAD: 8492083bca5SJung-uk Kim return (x86bios_uninit()); 85019de5df5SJung-uk Kim default: 8513219f535SJung-uk Kim return (ENOTSUP); 85219de5df5SJung-uk Kim } 85319de5df5SJung-uk Kim } 85419de5df5SJung-uk Kim 85519de5df5SJung-uk Kim static moduledata_t x86bios_mod = { 85619de5df5SJung-uk Kim "x86bios", 85719de5df5SJung-uk Kim x86bios_modevent, 85819de5df5SJung-uk Kim NULL, 85919de5df5SJung-uk Kim }; 86019de5df5SJung-uk Kim 86119de5df5SJung-uk Kim DECLARE_MODULE(x86bios, x86bios_mod, SI_SUB_CPU, SI_ORDER_ANY); 86219de5df5SJung-uk Kim MODULE_VERSION(x86bios, 1); 863