diff options
-rw-r--r-- | sys/compat/x86bios/x86bios.c | 338 | ||||
-rw-r--r-- | sys/compat/x86bios/x86bios.h | 4 | ||||
-rw-r--r-- | sys/i386/include/vm86.h | 3 |
3 files changed, 268 insertions, 77 deletions
diff --git a/sys/compat/x86bios/x86bios.c b/sys/compat/x86bios/x86bios.c index 22f1b93d9c16..94b2869bbb7c 100644 --- a/sys/compat/x86bios/x86bios.c +++ b/sys/compat/x86bios/x86bios.c @@ -37,7 +37,6 @@ __FBSDID("$FreeBSD$"); #include <sys/malloc.h> #include <sys/module.h> #include <sys/mutex.h> -#include <sys/proc.h> #include <sys/sysctl.h> #include <contrib/x86emu/x86emu.h> @@ -47,36 +46,237 @@ __FBSDID("$FreeBSD$"); #include <dev/pci/pcireg.h> #include <dev/pci/pcivar.h> -#include <machine/iodev.h> - #include <vm/vm.h> #include <vm/pmap.h> -#if defined(__amd64__) || defined(__i386__) +#ifdef __amd64__ #define X86BIOS_NATIVE_ARCH #endif +#ifdef __i386__ +#define X86BIOS_NATIVE_VM86 +#endif + +#define X86BIOS_MEM_SIZE 0x00100000 /* 1M */ + +static struct mtx x86bios_lock; + +SYSCTL_NODE(_debug, OID_AUTO, x86bios, CTLFLAG_RD, NULL, "x86bios debugging"); +static int x86bios_trace_call; +TUNABLE_INT("debug.x86bios.call", &x86bios_trace_call); +SYSCTL_INT(_debug_x86bios, OID_AUTO, call, CTLFLAG_RW, &x86bios_trace_call, 0, + "Trace far function calls"); +static int x86bios_trace_int; +TUNABLE_INT("debug.x86bios.int", &x86bios_trace_int); +SYSCTL_INT(_debug_x86bios, OID_AUTO, int, CTLFLAG_RW, &x86bios_trace_int, 0, + "Trace software interrupt handlers"); + +#ifdef X86BIOS_NATIVE_VM86 + +#include <machine/vm86.h> +#include <machine/vmparam.h> +#include <machine/pc/bios.h> + +struct vm86context x86bios_vmc; + +static void +x86bios_emu2vmf(struct x86emu_regs *regs, struct vm86frame *vmf) +{ + + vmf->vmf_ds = regs->R_DS; + vmf->vmf_es = regs->R_ES; + vmf->vmf_ss = regs->R_SS; + vmf->vmf_flags = regs->R_FLG; + vmf->vmf_ax = regs->R_AX; + vmf->vmf_bx = regs->R_BX; + vmf->vmf_cx = regs->R_CX; + vmf->vmf_dx = regs->R_DX; + vmf->vmf_sp = regs->R_SP; + vmf->vmf_bp = regs->R_BP; + vmf->vmf_si = regs->R_SI; + vmf->vmf_di = regs->R_DI; +} + +static void +x86bios_vmf2emu(struct vm86frame *vmf, struct x86emu_regs *regs) +{ + + regs->R_DS = vmf->vmf_ds; + regs->R_ES = vmf->vmf_es; + regs->R_SS = vmf->vmf_ss; + regs->R_FLG = vmf->vmf_flags; + regs->R_AX = vmf->vmf_ax; + regs->R_BX = vmf->vmf_bx; + regs->R_CX = vmf->vmf_cx; + regs->R_DX = vmf->vmf_dx; + regs->R_SP = vmf->vmf_sp; + regs->R_BP = vmf->vmf_bp; + regs->R_SI = vmf->vmf_si; + regs->R_DI = vmf->vmf_di; +} + +void * +x86bios_alloc(uint32_t *offset, size_t size, int flags) +{ + vm_offset_t addr; + int i; + + addr = (vm_offset_t)contigmalloc(size, M_DEVBUF, flags, 0, + X86BIOS_MEM_SIZE, PAGE_SIZE, 0); + if (addr != 0) { + *offset = vtophys(addr); + mtx_lock(&x86bios_lock); + for (i = 0; i < howmany(size, PAGE_SIZE); i++) + vm86_addpage(&x86bios_vmc, atop(*offset), + addr + i * PAGE_SIZE); + mtx_unlock(&x86bios_lock); + } + + return ((void *)addr); +} + +void +x86bios_free(void *addr, size_t size) +{ + int i, last; + + mtx_lock(&x86bios_lock); + for (i = 0, last = -1; i < x86bios_vmc.npages; i++) + if (x86bios_vmc.pmap[i].kva >= (vm_offset_t)addr && + x86bios_vmc.pmap[i].kva < (vm_offset_t)addr + size) { + bzero(&x86bios_vmc.pmap[i], + sizeof(x86bios_vmc.pmap[i])); + last = i; + } + if (last == x86bios_vmc.npages - 1) { + x86bios_vmc.npages -= howmany(size, PAGE_SIZE); + for (i = x86bios_vmc.npages - 1; + i >= 0 && x86bios_vmc.pmap[i].kva == 0; i--) + x86bios_vmc.npages--; + } + mtx_unlock(&x86bios_lock); + contigfree(addr, size, M_DEVBUF); +} + +void +x86bios_init_regs(struct x86regs *regs) +{ + + bzero(regs, sizeof(*regs)); +} + +void +x86bios_call(struct x86regs *regs, uint16_t seg, uint16_t off) +{ + struct vm86frame vmf; + + if (x86bios_trace_call) + printf("Calling 0x%05x (ax=0x%04x bx=0x%04x " + "cx=0x%04x dx=0x%04x es=0x%04x di=0x%04x)\n", + (seg << 4) + off, regs->R_AX, regs->R_BX, regs->R_CX, + regs->R_DX, regs->R_ES, regs->R_DI); + + bzero(&vmf, sizeof(vmf)); + x86bios_emu2vmf((struct x86emu_regs *)regs, &vmf); + vmf.vmf_cs = seg; + vmf.vmf_ip = off; + mtx_lock(&x86bios_lock); + vm86_datacall(-1, &vmf, &x86bios_vmc); + mtx_unlock(&x86bios_lock); + x86bios_vmf2emu(&vmf, (struct x86emu_regs *)regs); + + if (x86bios_trace_call) + printf("Exiting 0x%05x (ax=0x%04x bx=0x%04x " + "cx=0x%04x dx=0x%04x es=0x%04x di=0x%04x)\n", + (seg << 4) + off, regs->R_AX, regs->R_BX, regs->R_CX, + regs->R_DX, regs->R_ES, regs->R_DI); +} + +uint32_t +x86bios_get_intr(int intno) +{ + + return (readl(x86bios_offset(intno * 4))); +} + +void +x86bios_intr(struct x86regs *regs, int intno) +{ + struct vm86frame vmf; + + if (x86bios_trace_int) + printf("Calling int 0x%x (ax=0x%04x bx=0x%04x " + "cx=0x%04x dx=0x%04x es=0x%04x di=0x%04x)\n", + intno, regs->R_AX, regs->R_BX, regs->R_CX, + regs->R_DX, regs->R_ES, regs->R_DI); + + bzero(&vmf, sizeof(vmf)); + x86bios_emu2vmf((struct x86emu_regs *)regs, &vmf); + mtx_lock(&x86bios_lock); + vm86_datacall(intno, &vmf, &x86bios_vmc); + mtx_unlock(&x86bios_lock); + x86bios_vmf2emu(&vmf, (struct x86emu_regs *)regs); + + if (x86bios_trace_int) + printf("Exiting int 0x%x (ax=0x%04x bx=0x%04x " + "cx=0x%04x dx=0x%04x es=0x%04x di=0x%04x)\n", + intno, regs->R_AX, regs->R_BX, regs->R_CX, + regs->R_DX, regs->R_ES, regs->R_DI); +} + +void * +x86bios_offset(uint32_t offset) +{ + vm_offset_t addr; + + addr = vm86_getaddr(&x86bios_vmc, X86BIOS_PHYSTOSEG(offset), + X86BIOS_PHYSTOOFF(offset)); + if (addr == 0) + addr = BIOS_PADDRTOVADDR(offset); + + return ((void *)addr); +} + +static int +x86bios_init(void) +{ + + mtx_init(&x86bios_lock, "x86bios lock", NULL, MTX_DEF); + bzero(&x86bios_vmc, sizeof(x86bios_vmc)); + + return (0); +} + +static int +x86bios_uninit(void) +{ + + mtx_destroy(&x86bios_lock); + + return (0); +} + +#else + +#include <machine/iodev.h> #define X86BIOS_PAGE_SIZE 0x00001000 /* 4K */ #define X86BIOS_IVT_SIZE 0x00000500 /* 1K + 256 (BDA) */ -#define X86BIOS_SEG_SIZE 0x00010000 /* 64K */ -#define X86BIOS_MEM_SIZE 0x00100000 /* 1M */ #define X86BIOS_IVT_BASE 0x00000000 #define X86BIOS_RAM_BASE 0x00001000 #define X86BIOS_ROM_BASE 0x000a0000 #define X86BIOS_ROM_SIZE (X86BIOS_MEM_SIZE - (uint32_t)x86bios_rom_phys) +#define X86BIOS_SEG_SIZE X86BIOS_PAGE_SIZE #define X86BIOS_PAGES (X86BIOS_MEM_SIZE / X86BIOS_PAGE_SIZE) -#define X86BIOS_R_DS _pad1 #define X86BIOS_R_SS _pad2 +#define X86BIOS_R_SP _pad3.I16_reg.x_reg static struct x86emu x86bios_emu; -static struct mtx x86bios_lock; - static void *x86bios_ivt; static void *x86bios_rom; static void *x86bios_seg; @@ -91,16 +291,6 @@ static uint32_t x86bios_fault_addr; static uint16_t x86bios_fault_cs; static uint16_t x86bios_fault_ip; -SYSCTL_NODE(_debug, OID_AUTO, x86bios, CTLFLAG_RD, NULL, "x86bios debugging"); -static int x86bios_trace_call; -TUNABLE_INT("debug.x86bios.call", &x86bios_trace_call); -SYSCTL_INT(_debug_x86bios, OID_AUTO, call, CTLFLAG_RW, &x86bios_trace_call, 0, - "Trace far function calls"); -static int x86bios_trace_int; -TUNABLE_INT("debug.x86bios.int", &x86bios_trace_int); -SYSCTL_INT(_debug_x86bios, OID_AUTO, int, CTLFLAG_RW, &x86bios_trace_int, 0, - "Trace software interrupt handlers"); - static void x86bios_set_fault(struct x86emu *emu, uint32_t addr) { @@ -115,18 +305,18 @@ x86bios_set_fault(struct x86emu *emu, uint32_t addr) static void * x86bios_get_pages(uint32_t offset, size_t size) { - vm_offset_t page; + vm_offset_t addr; if (offset + size > X86BIOS_MEM_SIZE + X86BIOS_IVT_SIZE) return (NULL); if (offset >= X86BIOS_MEM_SIZE) offset -= X86BIOS_MEM_SIZE; - page = x86bios_map[offset / X86BIOS_PAGE_SIZE]; - if (page != 0) - return ((void *)(page + offset % X86BIOS_PAGE_SIZE)); + addr = x86bios_map[offset / X86BIOS_PAGE_SIZE]; + if (addr != 0) + addr += offset % X86BIOS_PAGE_SIZE; - return (NULL); + return ((void *)addr); } static void @@ -393,8 +583,8 @@ x86bios_init_regs(struct x86regs *regs) { bzero(regs, sizeof(*regs)); - regs->X86BIOS_R_DS = 0x40; - regs->X86BIOS_R_SS = x86bios_seg_phys >> 4; + regs->X86BIOS_R_SS = X86BIOS_PHYSTOSEG(x86bios_seg_phys); + regs->X86BIOS_R_SP = X86BIOS_PAGE_SIZE - 2; } void @@ -481,51 +671,6 @@ x86bios_offset(uint32_t offset) return (x86bios_get_pages(offset, 1)); } -void * -x86bios_get_orm(uint32_t offset) -{ - uint8_t *p; - - /* Does the shadow ROM contain BIOS POST code for x86? */ - p = x86bios_offset(offset); - if (p == NULL || p[0] != 0x55 || p[1] != 0xaa || p[3] != 0xe9) - return (NULL); - - return (p); -} - -int -x86bios_match_device(uint32_t offset, device_t dev) -{ - uint8_t *p; - uint16_t device, vendor; - uint8_t class, progif, subclass; - - /* Does the shadow ROM contain BIOS POST code for x86? */ - p = x86bios_get_orm(offset); - if (p == NULL) - return (0); - - /* Does it contain PCI data structure? */ - p += le16toh(*(uint16_t *)(p + 0x18)); - if (bcmp(p, "PCIR", 4) != 0 || - le16toh(*(uint16_t *)(p + 0x0a)) < 0x18 || *(p + 0x14) != 0) - return (0); - - /* Does it match the vendor, device, and classcode? */ - vendor = le16toh(*(uint16_t *)(p + 0x04)); - device = le16toh(*(uint16_t *)(p + 0x06)); - progif = *(p + 0x0d); - subclass = *(p + 0x0e); - class = *(p + 0x0f); - if (vendor != pci_get_vendor(dev) || device != pci_get_device(dev) || - class != pci_get_class(dev) || subclass != pci_get_subclass(dev) || - progif != pci_get_progif(dev)) - return (0); - - return (1); -} - static __inline void x86bios_unmap_mem(void) { @@ -549,7 +694,6 @@ x86bios_map_mem(void) #ifdef X86BIOS_NATIVE_ARCH x86bios_ivt = pmap_mapbios(X86BIOS_IVT_BASE, X86BIOS_IVT_SIZE); -#ifndef PC98 /* Probe EBDA via BDA. */ x86bios_rom_phys = *(uint16_t *)((caddr_t)x86bios_ivt + 0x40e); x86bios_rom_phys = x86bios_rom_phys << 4; @@ -558,7 +702,6 @@ x86bios_map_mem(void) x86bios_rom_phys = rounddown(x86bios_rom_phys, X86BIOS_PAGE_SIZE); else -#endif #else x86bios_ivt = malloc(X86BIOS_IVT_SIZE, M_DEVBUF, M_ZERO | M_WAITOK); #endif @@ -567,7 +710,7 @@ x86bios_map_mem(void) x86bios_rom = pmap_mapdev(x86bios_rom_phys, X86BIOS_ROM_SIZE); if (x86bios_rom == NULL) goto fail; -#if defined(X86BIOS_NATIVE_ARCH) && !defined(PC98) +#ifdef X86BIOS_NATIVE_ARCH /* Change attribute for EBDA. */ if (x86bios_rom_phys < X86BIOS_ROM_BASE && pmap_change_attr((vm_offset_t)x86bios_rom, @@ -666,6 +809,53 @@ x86bios_uninit(void) return (0); } +#endif + +void * +x86bios_get_orm(uint32_t offset) +{ + uint8_t *p; + + /* Does the shadow ROM contain BIOS POST code for x86? */ + p = x86bios_offset(offset); + if (p == NULL || p[0] != 0x55 || p[1] != 0xaa || p[3] != 0xe9) + return (NULL); + + return (p); +} + +int +x86bios_match_device(uint32_t offset, device_t dev) +{ + uint8_t *p; + uint16_t device, vendor; + uint8_t class, progif, subclass; + + /* Does the shadow ROM contain BIOS POST code for x86? */ + p = x86bios_get_orm(offset); + if (p == NULL) + return (0); + + /* Does it contain PCI data structure? */ + p += le16toh(*(uint16_t *)(p + 0x18)); + if (bcmp(p, "PCIR", 4) != 0 || + le16toh(*(uint16_t *)(p + 0x0a)) < 0x18 || *(p + 0x14) != 0) + return (0); + + /* Does it match the vendor, device, and classcode? */ + vendor = le16toh(*(uint16_t *)(p + 0x04)); + device = le16toh(*(uint16_t *)(p + 0x06)); + progif = *(p + 0x0d); + subclass = *(p + 0x0e); + class = *(p + 0x0f); + if (vendor != pci_get_vendor(dev) || device != pci_get_device(dev) || + class != pci_get_class(dev) || subclass != pci_get_subclass(dev) || + progif != pci_get_progif(dev)) + return (0); + + return (1); +} + static int x86bios_modevent(module_t mod __unused, int type, void *data __unused) { diff --git a/sys/compat/x86bios/x86bios.h b/sys/compat/x86bios/x86bios.h index 682c6f59891e..f4749329f89e 100644 --- a/sys/compat/x86bios/x86bios.h +++ b/sys/compat/x86bios/x86bios.h @@ -138,8 +138,8 @@ typedef struct x86regs x86regs_t; #define R_FS register_fs #define R_GS register_gs -#define X86BIOS_PHYSTOSEG(x) (((x) >> 4) & 0xffff) -#define X86BIOS_PHYSTOOFF(x) ((x) & 0x000f) +#define X86BIOS_PHYSTOSEG(x) (((x) >> 4) & 0xff00) +#define X86BIOS_PHYSTOOFF(x) ((x) & 0x0fff) __BEGIN_DECLS void *x86bios_alloc(uint32_t *offset, size_t size, int flags); diff --git a/sys/i386/include/vm86.h b/sys/i386/include/vm86.h index 041504abab18..b574e58e23e9 100644 --- a/sys/i386/include/vm86.h +++ b/sys/i386/include/vm86.h @@ -93,13 +93,14 @@ struct vm86frame { #define vmf_ds ds.r_w.r_x #define vmf_es es.r_w.r_x #define vmf_ss ss.r_w.r_x +#define vmf_bp ebp.r_w.r_x #define vmf_sp esp.r_w.r_x #define vmf_ip eip.r_w.r_x #define vmf_flags eflags.r_w.r_x #define vmf_eflags eflags.r_ex }; -#define VM86_PMAPSIZE 3 +#define VM86_PMAPSIZE 8 #define VMAP_MALLOC 1 /* page was malloced by us */ struct vm86context { |