diff options
author | delphij <delphij@FreeBSD.org> | 2010-03-02 01:56:55 +0000 |
---|---|---|
committer | delphij <delphij@FreeBSD.org> | 2010-03-02 01:56:55 +0000 |
commit | 05b666175c3574ab196b72aa01279fbccde0db29 (patch) | |
tree | 7ed974e780fcc4cd6ef6cb1dd534de1780381fb5 | |
parent | 3af89d2d21d3e1b8b090a648e1e7d389a180a2bd (diff) | |
download | FreeBSD-src-05b666175c3574ab196b72aa01279fbccde0db29.zip FreeBSD-src-05b666175c3574ab196b72aa01279fbccde0db29.tar.gz |
MFC x86emu/x86bios emulator and make previously i386 only dpms and vesa
framebuffer driver, etc. work on FreeBSD/amd64.
A significant amount of improvements were done by jkim@ during the recent
months to make vesa(4) work better, over the initial code import. This
work is based on OpenBSD's x86emu implementation and contributed by
paradox <ddkprog yahoo com> and swell.k at gmail com.
Hopefully I have stolen all their work to 8-STABLE :)
All bugs in this commit are mine, as usual.
41 files changed, 11003 insertions, 772 deletions
diff --git a/ObsoleteFiles.inc b/ObsoleteFiles.inc index 6a1d0cf..25e43ba 100644 --- a/ObsoleteFiles.inc +++ b/ObsoleteFiles.inc @@ -14,6 +14,9 @@ # The file is partitioned: OLD_FILES first, then OLD_LIBS and OLD_DIRS last. # +# 20100301: vesa and dpms promoted to be i386/amd64 common +OLD_FILES+=usr/include/machine/pc/vesa.h +OLD_FILES+=usr/share/man/man4/i386/dpms.4.gz # 20091218: removal of rc.early(8) link OLD_FILES+=usr/share/man/man8/rc.early.8.gz # 20091027: pselect.3 implemented as syscall diff --git a/lib/Makefile b/lib/Makefile index 7cacb70..00b1c60 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -112,6 +112,7 @@ _libsmb= libsmb _libncp= libncp .endif _libsmb= libsmb +_libvgl= libvgl .endif .if ${MACHINE_ARCH} == "powerpc" diff --git a/share/man/man4/Makefile b/share/man/man4/Makefile index 812a450..f8af593 100644 --- a/share/man/man4/Makefile +++ b/share/man/man4/Makefile @@ -86,6 +86,7 @@ MAN= aac.4 \ digi.4 \ disc.4 \ divert.4 \ + ${_dpms.4} \ dpt.4 \ dummynet.4 \ ed.4 \ @@ -622,6 +623,7 @@ _amdtemp.4= amdtemp.4 _asmc.4= asmc.4 _coretemp.4= coretemp.4 _cpuctl.4= cpuctl.4 +_dpms.4= dpms.4 _hptiop.4= hptiop.4 _hptmv.4= hptmv.4 _hptrr.4= hptrr.4 diff --git a/share/man/man4/man4.i386/dpms.4 b/share/man/man4/dpms.4 index 2412b47..2412b47 100644 --- a/share/man/man4/man4.i386/dpms.4 +++ b/share/man/man4/dpms.4 diff --git a/share/man/man4/syscons.4 b/share/man/man4/syscons.4 index 3f6e9ca..2c9d21d 100644 --- a/share/man/man4/syscons.4 +++ b/share/man/man4/syscons.4 @@ -26,7 +26,7 @@ .\" .\" $FreeBSD$ .\" -.Dd October 22, 2006 +.Dd September 10, 2009 .Dt SYSCONS 4 .Os .Sh NAME @@ -325,7 +325,7 @@ This mode is useful on some laptop computers, but less so on most other systems, and it adds substantial amount of code to syscons. If this option is NOT defined, you can reduce the kernel size a lot. See the -.Dv VESA800X600 +.Dv VESAMODE flag below. .It Dv SC_TWOBUTTON_MOUSE If you have a two button mouse, you may want to add this option @@ -426,15 +426,15 @@ or else at the loader prompt (see .\".It bit 6 (QUIET_BELL) .\"This option suppresses the bell, whether audible or visual, .\"if it is rung in a background virtual terminal. -.It 0x0080 (VESA800X600) -This option puts the video card in the VESA 800x600 pixel, 16 color -mode. -It may be useful for laptop computers for which the 800x600 mode -is otherwise unsupported by the X server. +.It 0x0080 (VESAMODE) +This option puts the video card in the VESA mode specified by higher +16 bits of the flags during kernel initialization. Note that in order for this flag to work, the kernel must be compiled with the .Dv SC_PIXEL_MODE option explained above. +A list of the available mode can be obtained via +.Xr vidcontrol 1 . .\"Note also that the ``copy-and-paste'' function is not currently supported .\"in this mode and the mouse pointer will not be displayed. .It 0x0100 (AUTODETECT_KBD) diff --git a/sys/amd64/conf/NOTES b/sys/amd64/conf/NOTES index a231d33..159f12e 100644 --- a/sys/amd64/conf/NOTES +++ b/sys/amd64/conf/NOTES @@ -154,6 +154,17 @@ options AGP_DEBUG ##################################################################### # HARDWARE DEVICE CONFIGURATION +# To include support for VGA VESA video modes +options VESA + +# Turn on extra debugging checks and output for VESA support. +options VESA_DEBUG + +device dpms # DPMS suspend & resume via VESA BIOS + +# x86 real mode BIOS emulator, required by atkbdc/dpms/vesa +options X86BIOS + # # Optional devices: # @@ -213,6 +224,9 @@ options VGA_WIDTH90 # support 90 column modes # Debugging. options VGA_DEBUG +# Linear framebuffer driver for S3 VESA 1.2 cards. Works on top of VESA. +device s3pci + # 3Dfx Voodoo Graphics, Voodoo II /dev/3dfx CDEV support. This will create # the /dev/3dfx0 device to work with glide implementations. This should get # linked to /dev/3dfx and /dev/voodoo. Note that this is not the same as diff --git a/sys/compat/x86bios/x86bios.c b/sys/compat/x86bios/x86bios.c new file mode 100644 index 0000000..34da07c --- /dev/null +++ b/sys/compat/x86bios/x86bios.c @@ -0,0 +1,546 @@ +/*- + * Copyright (c) 2009 Alex Keda <admin@lissyara.su> + * Copyright (c) 2009 Jung-uk Kim <jkim@FreeBSD.org> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include "opt_x86bios.h" + +#include <sys/param.h> +#include <sys/bus.h> +#include <sys/kernel.h> +#include <sys/lock.h> +#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> +#include <contrib/x86emu/x86emu_regs.h> +#include <compat/x86bios/x86bios.h> + +#include <dev/pci/pcireg.h> +#include <dev/pci/pcivar.h> + +#include <machine/cpufunc.h> + +#include <vm/vm.h> +#include <vm/pmap.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 /* XXX EBDA? */ + +#define X86BIOS_ROM_SIZE (X86BIOS_MEM_SIZE - X86BIOS_ROM_BASE) + +#define X86BIOS_PAGES (X86BIOS_MEM_SIZE / X86BIOS_PAGE_SIZE) + +#define X86BIOS_R_DS _pad1 +#define X86BIOS_R_SS _pad2 + +static struct x86emu x86bios_emu; + +static struct mtx x86bios_lock; + +static void *x86bios_ivt; +static void *x86bios_rom; +static void *x86bios_seg; + +static vm_offset_t *x86bios_map; + +static vm_paddr_t x86bios_seg_phys; + +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_get_pages(uint32_t offset, size_t size) +{ + int i; + + if (offset + size > X86BIOS_MEM_SIZE) + return (NULL); + + i = offset / X86BIOS_PAGE_SIZE; + if (x86bios_map[i] != 0) + return ((void *)(x86bios_map[i] + offset - + i * X86BIOS_PAGE_SIZE)); + + return (NULL); +} + +static void +x86bios_set_pages(vm_offset_t va, vm_paddr_t pa, size_t size) +{ + int i, j; + + for (i = pa / X86BIOS_PAGE_SIZE, j = 0; + j < howmany(size, X86BIOS_PAGE_SIZE); i++, j++) + x86bios_map[i] = va + j * X86BIOS_PAGE_SIZE; +} + +static uint8_t +x86bios_emu_rdb(struct x86emu *emu, uint32_t addr) +{ + uint8_t *va; + + va = x86bios_get_pages(addr, sizeof(*va)); + if (va == NULL) + x86emu_halt_sys(emu); + + return (*va); +} + +static uint16_t +x86bios_emu_rdw(struct x86emu *emu, uint32_t addr) +{ + uint16_t *va; + + va = x86bios_get_pages(addr, sizeof(*va)); + if (va == NULL) + x86emu_halt_sys(emu); + + return (le16toh(*va)); +} + +static uint32_t +x86bios_emu_rdl(struct x86emu *emu, uint32_t addr) +{ + uint32_t *va; + + va = x86bios_get_pages(addr, sizeof(*va)); + if (va == NULL) + x86emu_halt_sys(emu); + + return (le32toh(*va)); +} + +static void +x86bios_emu_wrb(struct x86emu *emu, uint32_t addr, uint8_t val) +{ + uint8_t *va; + + va = x86bios_get_pages(addr, sizeof(*va)); + if (va == NULL) + x86emu_halt_sys(emu); + + *va = val; +} + +static void +x86bios_emu_wrw(struct x86emu *emu, uint32_t addr, uint16_t val) +{ + uint16_t *va; + + va = x86bios_get_pages(addr, sizeof(*va)); + if (va == NULL) + x86emu_halt_sys(emu); + + *va = htole16(val); +} + +static void +x86bios_emu_wrl(struct x86emu *emu, uint32_t addr, uint32_t val) +{ + uint32_t *va; + + va = x86bios_get_pages(addr, sizeof(*va)); + if (va == NULL) + x86emu_halt_sys(emu); + + *va = htole32(val); +} + +static uint8_t +x86bios_emu_inb(struct x86emu *emu, uint16_t port) +{ + + if (port == 0xb2) /* APM scratch register */ + return (0); + if (port >= 0x80 && port < 0x88) /* POST status register */ + return (0); + + return (inb(port)); +} + +static uint16_t +x86bios_emu_inw(struct x86emu *emu, uint16_t port) +{ + + if (port >= 0x80 && port < 0x88) /* POST status register */ + return (0); + + return (inw(port)); +} + +static uint32_t +x86bios_emu_inl(struct x86emu *emu, uint16_t port) +{ + + if (port >= 0x80 && port < 0x88) /* POST status register */ + return (0); + + return (inl(port)); +} + +static void +x86bios_emu_outb(struct x86emu *emu, uint16_t port, uint8_t val) +{ + + if (port == 0xb2) /* APM scratch register */ + return; + if (port >= 0x80 && port < 0x88) /* POST status register */ + return; + + outb(port, val); +} + +static void +x86bios_emu_outw(struct x86emu *emu, uint16_t port, uint16_t val) +{ + + if (port >= 0x80 && port < 0x88) /* POST status register */ + return; + + outw(port, val); +} + +static void +x86bios_emu_outl(struct x86emu *emu, uint16_t port, uint32_t val) +{ + + if (port >= 0x80 && port < 0x88) /* POST status register */ + return; + + outl(port, val); +} + +static void +x86bios_emu_get_intr(struct x86emu *emu, int intno) +{ + uint16_t *sp; + uint32_t iv; + + emu->x86.R_SP -= 6; + + sp = (uint16_t *)((vm_offset_t)x86bios_seg + emu->x86.R_SP); + sp[0] = htole16(emu->x86.R_IP); + sp[1] = htole16(emu->x86.R_CS); + sp[2] = htole16(emu->x86.R_FLG); + + iv = x86bios_get_intr(intno); + emu->x86.R_IP = iv & 0x000f; + emu->x86.R_CS = (iv >> 12) & 0xffff; + emu->x86.R_FLG &= ~(F_IF | F_TF); +} + +void * +x86bios_alloc(uint32_t *offset, size_t size) +{ + void *vaddr; + + if (offset == NULL || size == 0) + return (NULL); + + vaddr = contigmalloc(size, M_DEVBUF, M_NOWAIT, X86BIOS_RAM_BASE, + X86BIOS_ROM_BASE, X86BIOS_PAGE_SIZE, 0); + if (vaddr != NULL) { + *offset = vtophys(vaddr); + x86bios_set_pages((vm_offset_t)vaddr, *offset, size); + } + + return (vaddr); +} + +void +x86bios_free(void *addr, size_t size) +{ + vm_paddr_t paddr; + + if (addr == NULL || size == 0) + return; + + paddr = vtophys(addr); + if (paddr < X86BIOS_RAM_BASE || paddr >= X86BIOS_ROM_BASE || + paddr % X86BIOS_PAGE_SIZE != 0) + return; + + bzero(x86bios_map + paddr / X86BIOS_PAGE_SIZE, + sizeof(*x86bios_map) * howmany(size, X86BIOS_PAGE_SIZE)); + contigfree(addr, size, M_DEVBUF); +} + +void +x86bios_init_regs(struct x86regs *regs) +{ + + bzero(regs, sizeof(*regs)); + regs->X86BIOS_R_DS = regs->X86BIOS_R_SS = x86bios_seg_phys >> 4; +} + +void +x86bios_call(struct x86regs *regs, uint16_t seg, uint16_t off) +{ + + if (x86bios_map == NULL) + return; + + 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); + + mtx_lock_spin(&x86bios_lock); + memcpy(&x86bios_emu.x86, regs, sizeof(*regs)); + x86emu_exec_call(&x86bios_emu, seg, off); + memcpy(regs, &x86bios_emu.x86, sizeof(*regs)); + mtx_unlock_spin(&x86bios_lock); + + 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) +{ + uint32_t *iv; + + iv = (uint32_t *)((vm_offset_t)x86bios_ivt + intno * 4); + + return (le32toh(*iv)); +} + +void +x86bios_intr(struct x86regs *regs, int intno) +{ + + if (intno < 0 || intno > 255) + return; + + if (x86bios_map == NULL) + return; + + 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); + + mtx_lock_spin(&x86bios_lock); + memcpy(&x86bios_emu.x86, regs, sizeof(*regs)); + x86emu_exec_intr(&x86bios_emu, intno); + memcpy(regs, &x86bios_emu.x86, sizeof(*regs)); + mtx_unlock_spin(&x86bios_lock); + + 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) +{ + + 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 int +x86bios_map_mem(void) +{ + + x86bios_ivt = pmap_mapbios(X86BIOS_IVT_BASE, X86BIOS_IVT_SIZE); + if (x86bios_ivt == NULL) + return (1); + x86bios_rom = pmap_mapdev(X86BIOS_ROM_BASE, X86BIOS_ROM_SIZE); + if (x86bios_rom == NULL) { + pmap_unmapdev((vm_offset_t)x86bios_ivt, X86BIOS_IVT_SIZE); + return (1); + } + x86bios_seg = contigmalloc(X86BIOS_SEG_SIZE, M_DEVBUF, M_WAITOK, + X86BIOS_RAM_BASE, X86BIOS_ROM_BASE, X86BIOS_PAGE_SIZE, 0); + x86bios_seg_phys = vtophys(x86bios_seg); + + return (0); +} + +static __inline void +x86bios_unmap_mem(void) +{ + + pmap_unmapdev((vm_offset_t)x86bios_ivt, X86BIOS_IVT_SIZE); + pmap_unmapdev((vm_offset_t)x86bios_rom, X86BIOS_ROM_SIZE); + contigfree(x86bios_seg, X86BIOS_SEG_SIZE, M_DEVBUF); +} + +static void +x86bios_init(void *arg __unused) +{ + int i; + + mtx_init(&x86bios_lock, "x86bios lock", NULL, MTX_SPIN); + + if (x86bios_map_mem() != 0) + return; + + x86bios_map = malloc(sizeof(*x86bios_map) * X86BIOS_PAGES, M_DEVBUF, + M_WAITOK | M_ZERO); + x86bios_set_pages((vm_offset_t)x86bios_ivt, X86BIOS_IVT_BASE, + X86BIOS_IVT_SIZE); + x86bios_set_pages((vm_offset_t)x86bios_rom, X86BIOS_ROM_BASE, + X86BIOS_ROM_SIZE); + x86bios_set_pages((vm_offset_t)x86bios_seg, x86bios_seg_phys, + X86BIOS_SEG_SIZE); + + bzero(&x86bios_emu, sizeof(x86bios_emu)); + + x86bios_emu.emu_rdb = x86bios_emu_rdb; + x86bios_emu.emu_rdw = x86bios_emu_rdw; + x86bios_emu.emu_rdl = x86bios_emu_rdl; + x86bios_emu.emu_wrb = x86bios_emu_wrb; + x86bios_emu.emu_wrw = x86bios_emu_wrw; + x86bios_emu.emu_wrl = x86bios_emu_wrl; + + x86bios_emu.emu_inb = x86bios_emu_inb; + x86bios_emu.emu_inw = x86bios_emu_inw; + x86bios_emu.emu_inl = x86bios_emu_inl; + x86bios_emu.emu_outb = x86bios_emu_outb; + x86bios_emu.emu_outw = x86bios_emu_outw; + x86bios_emu.emu_outl = x86bios_emu_outl; + + for (i = 0; i < 256; i++) + x86bios_emu._x86emu_intrTab[i] = x86bios_emu_get_intr; +} + +static void +x86bios_uninit(void *arg __unused) +{ + vm_offset_t *map = x86bios_map; + + mtx_lock_spin(&x86bios_lock); + if (x86bios_map != NULL) { + free(x86bios_map, M_DEVBUF); + x86bios_map = NULL; + } + mtx_unlock_spin(&x86bios_lock); + + if (map != NULL) + x86bios_unmap_mem(); + + mtx_destroy(&x86bios_lock); +} + +static int +x86bios_modevent(module_t mod __unused, int type, void *data __unused) +{ + + switch (type) { + case MOD_LOAD: + x86bios_init(NULL); + break; + case MOD_UNLOAD: + x86bios_uninit(NULL); + break; + default: + return (ENOTSUP); + } + + return (0); +} + +static moduledata_t x86bios_mod = { + "x86bios", + x86bios_modevent, + NULL, +}; + +DECLARE_MODULE(x86bios, x86bios_mod, SI_SUB_CPU, SI_ORDER_ANY); +MODULE_VERSION(x86bios, 1); diff --git a/sys/compat/x86bios/x86bios.h b/sys/compat/x86bios/x86bios.h new file mode 100644 index 0000000..4ed15e0 --- /dev/null +++ b/sys/compat/x86bios/x86bios.h @@ -0,0 +1,156 @@ +/*- + * Copyright (c) 2009 Alex Keda <admin@lissyara.su> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ +/* + * x86 registers were borrowed from x86emu.h x86emu_regs.h + * for compatability. + */ + +#ifndef _X86BIOS_H_ +#define _X86BIOS_H_ + +#include <sys/endian.h> +#include <sys/systm.h> +#include <sys/types.h> + +#ifdef __BIG_ENDIAN__ + +struct x86_register32 { + uint32_t e_reg; +}; + +struct x86_register16 { + uint16_t filler0; + uint16_t x_reg; +}; + +struct x86_register8 { + uint8_t filler0; + uint8_t filler1; + uint8_t h_reg; + uint8_t l_reg; +}; + +#else /* !__BIG_ENDIAN__ */ + +struct x86_register32 { + uint32_t e_reg; +}; + +struct x86_register16 { + uint16_t x_reg; +}; + +struct x86_register8 { + uint8_t l_reg; + uint8_t h_reg; +}; + +#endif /* __BIG_ENDIAN__ */ + +union x86_register { + struct x86_register32 I32_reg; + struct x86_register16 I16_reg; + struct x86_register8 I8_reg; +}; + +struct x86regs { + uint16_t _pad0; /* CS */ + uint16_t _pad1; /* DS */ + uint16_t register_es; + uint16_t register_fs; + uint16_t register_gs; + uint16_t _pad2; /* SS */ + uint32_t register_flags; + union x86_register register_a; + union x86_register register_b; + union x86_register register_c; + union x86_register register_d; + + union x86_register _pad3; /* SP */ + union x86_register register_bp; + union x86_register register_si; + union x86_register register_di; +}; + +typedef struct x86regs x86regs_t; + +/* 8 bit registers */ +#define R_AH register_a.I8_reg.h_reg +#define R_AL register_a.I8_reg.l_reg +#define R_BH register_b.I8_reg.h_reg +#define R_BL register_b.I8_reg.l_reg +#define R_CH register_c.I8_reg.h_reg +#define R_CL register_c.I8_reg.l_reg +#define R_DH register_d.I8_reg.h_reg +#define R_DL register_d.I8_reg.l_reg + +/* 16 bit registers */ +#define R_AX register_a.I16_reg.x_reg +#define R_BX register_b.I16_reg.x_reg +#define R_CX register_c.I16_reg.x_reg +#define R_DX register_d.I16_reg.x_reg + +/* 32 bit extended registers */ +#define R_EAX register_a.I32_reg.e_reg +#define R_EBX register_b.I32_reg.e_reg +#define R_ECX register_c.I32_reg.e_reg +#define R_EDX register_d.I32_reg.e_reg + +/* special registers */ +#define R_BP register_bp.I16_reg.x_reg +#define R_SI register_si.I16_reg.x_reg +#define R_DI register_di.I16_reg.x_reg +#define R_FLG register_flags + +/* special registers */ +#define R_EBP register_bp.I32_reg.e_reg +#define R_ESI register_si.I32_reg.e_reg +#define R_EDI register_di.I32_reg.e_reg +#define R_EFLG register_flags + +/* segment registers */ +#define R_ES register_es +#define R_FS register_fs +#define R_GS register_gs + +#define X86BIOS_PHYSTOSEG(x) (((x) >> 4) & 0xffff) +#define X86BIOS_PHYSTOOFF(x) ((x) & 0x000f) + +__BEGIN_DECLS +void *x86bios_alloc(uint32_t *offset, size_t size); +void x86bios_call(struct x86regs *regs, uint16_t seg, uint16_t off); +void x86bios_free(void *addr, size_t size); +uint32_t x86bios_get_intr(int intno); +void *x86bios_get_orm(uint32_t offset); +void x86bios_init_regs(struct x86regs *regs); +void x86bios_intr(struct x86regs *regs, int intno); +int x86bios_match_device(uint32_t offset, device_t dev); +void *x86bios_offset(uint32_t offset); +__END_DECLS + +#endif /* !_X86BIOS_H_ */ diff --git a/sys/compat/x86bios/x86bios_alloc.c b/sys/compat/x86bios/x86bios_alloc.c new file mode 100644 index 0000000..624a75c --- /dev/null +++ b/sys/compat/x86bios/x86bios_alloc.c @@ -0,0 +1,81 @@ +/*- + * Copyright (C) 1999 Egbert Eich + * + * Permission to use, copy, modify, distribute, and sell this software and + * its documentation for any purpose is hereby granted without fee, + * provided that the above copyright notice appear in all copies and that + * both that copyright notice and this permission notice appear in + * supporting documentation, and that the name of the authors not be used + * in advertising or publicity pertaining to distribution of the software + * without specific, written prior permission. The authors makes no + * representations about the suitability of this software for any purpose. + * It is provided "as is" without express or implied warranty. + * + * THE AUTHORS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL THE AUTHORS BE LIABLE FOR ANY SPECIAL, INDIRECT OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF + * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR + * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + * + * xserver/hw/xfree86/int10/generic.c + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <sys/param.h> + +#include <compat/x86bios/x86bios.h> + +extern u_char *pbiosMem; +extern int busySegMap[5]; + +void * +x86biosAlloc(int count, int *segs) +{ + int i; + int j; + + /* find the free segblock of page */ + for (i = 0; i < (PAGE_RESERV - count); i++) + { + if (busySegMap[i] == 0) + { + /* find the capacity of segblock */ + for (j = i; j < (i + count); j++) + { + if (busySegMap[j] == 1) + break; + } + + if (j == (i + count)) + break; + i += count; + } + } + + if (i == (PAGE_RESERV - count)) + return NULL; + + /* make the segblock is used */ + for (j = i; j < (i + count); j++) + busySegMap[i] = 1; + + *segs = i * 4096; + + return (pbiosMem + *segs); +} + +void +x86biosFree(void *pbuf, int count) +{ + int i; + int busySeg; + + busySeg = ((u_char *)pbuf - pbiosMem) / 4096; + + for (i = busySeg; i < (busySeg + count); i++) + busySegMap[i] = 0; +} diff --git a/sys/conf/NOTES b/sys/conf/NOTES index f3058d2..768c23a 100644 --- a/sys/conf/NOTES +++ b/sys/conf/NOTES @@ -2821,3 +2821,4 @@ options AAC_DEBUG # Debugging levels: ##options BKTR_ALLOC_PAGES=(217*4+1) options BROOKTREE_ALLOC_PAGES=(217*4+1) options MAXFILES=999 + diff --git a/sys/conf/files b/sys/conf/files index d14c1ee..588e7d7 100644 --- a/sys/conf/files +++ b/sys/conf/files @@ -2893,4 +2893,3 @@ dev/xen/netfront/netfront.c optional xen | xenhvm dev/xen/xenpci/xenpci.c optional xenpci dev/xen/xenpci/evtchn.c optional xenpci dev/xen/xenpci/machine_reboot.c optional xenpci - diff --git a/sys/conf/files.amd64 b/sys/conf/files.amd64 index d7b5765..2b33ea6 100644 --- a/sys/conf/files.amd64 +++ b/sys/conf/files.amd64 @@ -163,6 +163,7 @@ dev/atkbdc/atkbdc_subr.c optional atkbdc dev/atkbdc/psm.c optional psm atkbdc dev/coretemp/coretemp.c optional coretemp dev/cpuctl/cpuctl.c optional cpuctl +dev/dpms/dpms.c optional dpms # There are no systems with isa slots, so all ed isa entries should go.. dev/ed/if_ed_3c503.c optional ed isa ed_3c503 dev/ed/if_ed_isa.c optional ed isa @@ -170,6 +171,8 @@ dev/ed/if_ed_wd80x3.c optional ed isa dev/ed/if_ed_hpp.c optional ed isa ed_hpp dev/ed/if_ed_sic.c optional ed isa ed_sic dev/fb/fb.c optional fb | vga +dev/fb/s3_pci.c optional s3pci +dev/fb/vesa.c optional vga vesa dev/fb/vga.c optional vga dev/ichwd/ichwd.c optional ichwd dev/if_ndis/if_ndis.c optional ndis @@ -220,6 +223,7 @@ dev/sio/sio_puc.c optional sio puc dev/speaker/spkr.c optional speaker dev/syscons/apm/apm_saver.c optional apm_saver apm dev/syscons/scterm-teken.c optional sc +dev/syscons/scvesactl.c optional sc vga vesa dev/syscons/scvgarndr.c optional sc vga dev/syscons/scvtb.c optional sc dev/syscons/teken/teken.c optional sc @@ -294,3 +298,8 @@ i386/cpufreq/p4tcc.c optional cpufreq # libkern/memmove.c standard libkern/memset.c standard +# +# x86 real mode BIOS emulator, required by atkbdc/dpms/vesa +# +compat/x86bios/x86bios.c optional x86bios | atkbd | dpms | vesa +contrib/x86emu/x86emu.c optional x86bios | atkbd | dpms | vesa diff --git a/sys/conf/files.i386 b/sys/conf/files.i386 index b1e60d6..4df00d7 100644 --- a/sys/conf/files.i386 +++ b/sys/conf/files.i386 @@ -151,12 +151,15 @@ dev/ctau/if_ct.c optional ctau dev/cx/csigma.c optional cx dev/cx/cxddk.c optional cx dev/cx/if_cx.c optional cx +dev/dpms/dpms.c optional dpms dev/ed/if_ed_3c503.c optional ed isa ed_3c503 dev/ed/if_ed_isa.c optional ed isa dev/ed/if_ed_wd80x3.c optional ed isa dev/ed/if_ed_hpp.c optional ed isa ed_hpp dev/ed/if_ed_sic.c optional ed isa ed_sic dev/fb/fb.c optional fb | vga +dev/fb/s3_pci.c optional s3pci +dev/fb/vesa.c optional vga vesa dev/fb/vga.c optional vga dev/fdc/fdc.c optional fdc dev/fdc/fdc_acpi.c optional fdc @@ -333,7 +336,6 @@ i386/isa/clock.c optional native i386/xen/clock.c optional xen i386/xen/xen_clock_util.c optional xen i386/xen/xen_rtc.c optional xen -i386/isa/dpms.c optional dpms i386/isa/elcr.c standard i386/isa/elink.c optional ep | ie i386/isa/isa.c optional isa @@ -343,7 +345,6 @@ i386/isa/npx.c optional npx i386/isa/pmtimer.c optional pmtimer i386/isa/prof_machdep.c optional profiling-routine i386/isa/spic.c optional spic -i386/isa/vesa.c optional vga vesa i386/linux/imgact_linux.c optional compat_linux i386/linux/linux_dummy.c optional compat_linux i386/linux/linux_locore.s optional compat_linux \ @@ -381,3 +382,8 @@ i386/xbox/xbox.c optional xbox i386/xbox/xboxfb.c optional xboxfb dev/fb/boot_font.c optional xboxfb i386/xbox/pic16l.s optional xbox +# +# x86 real mode BIOS emulator, required by atkbdc/dpms/vesa +# +compat/x86bios/x86bios.c optional x86bios | atkbd | dpms | vesa +contrib/x86emu/x86emu.c optional x86bios | atkbd | dpms | vesa diff --git a/sys/conf/options b/sys/conf/options index e336fdc..7f5fd05 100644 --- a/sys/conf/options +++ b/sys/conf/options @@ -841,3 +841,5 @@ SND_FEEDER_FULL_MULTIFORMAT opt_snd.h SND_FEEDER_RATE_HP opt_snd.h SND_PCM_64 opt_snd.h SND_OLDSTEREO opt_snd.h + +X86BIOS diff --git a/sys/conf/options.amd64 b/sys/conf/options.amd64 index beb97ed..5617da4 100644 --- a/sys/conf/options.amd64 +++ b/sys/conf/options.amd64 @@ -37,6 +37,9 @@ VGA_NO_MODE_CHANGE opt_vga.h VGA_SLOW_IOACCESS opt_vga.h VGA_WIDTH90 opt_vga.h +VESA +VESA_DEBUG opt_vesa.h + # AGP debugging support AGP_DEBUG opt_agp.h diff --git a/sys/contrib/x86emu/x86emu.c b/sys/contrib/x86emu/x86emu.c new file mode 100644 index 0000000..3e5a06a --- /dev/null +++ b/sys/contrib/x86emu/x86emu.c @@ -0,0 +1,8335 @@ +/* $OpenBSD: x86emu.c,v 1.4 2009/06/18 14:19:21 pirofti Exp $ */ +/* $NetBSD: x86emu.c,v 1.7 2009/02/03 19:26:29 joerg Exp $ */ + +/* + * + * Realmode X86 Emulator Library + * + * Copyright (C) 1996-1999 SciTech Software, Inc. + * Copyright (C) David Mosberger-Tang + * Copyright (C) 1999 Egbert Eich + * Copyright (C) 2007 Joerg Sonnenberger + * + * ======================================================================== + * + * Permission to use, copy, modify, distribute, and sell this software and + * its documentation for any purpose is hereby granted without fee, + * provided that the above copyright notice appear in all copies and that + * both that copyright notice and this permission notice appear in + * supporting documentation, and that the name of the authors not be used + * in advertising or publicity pertaining to distribution of the software + * without specific, written prior permission. The authors makes no + * representations about the suitability of this software for any purpose. + * It is provided "as is" without express or implied warranty. + * + * THE AUTHORS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL THE AUTHORS BE LIABLE FOR ANY SPECIAL, INDIRECT OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF + * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR + * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + * + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <contrib/x86emu/x86emu.h> +#include <contrib/x86emu/x86emu_regs.h> + +static void x86emu_intr_raise (struct x86emu *, uint8_t type); + +static void x86emu_exec_one_byte(struct x86emu *); +static void x86emu_exec_two_byte(struct x86emu *); + +static void fetch_decode_modrm (struct x86emu *); +static uint8_t fetch_byte_imm (struct x86emu *); +static uint16_t fetch_word_imm (struct x86emu *); +static uint32_t fetch_long_imm (struct x86emu *); +static uint8_t fetch_data_byte (struct x86emu *, uint32_t offset); +static uint8_t fetch_byte (struct x86emu *, u_int segment, uint32_t offset); +static uint16_t fetch_data_word (struct x86emu *, uint32_t offset); +static uint16_t fetch_word (struct x86emu *, uint32_t segment, uint32_t offset); +static uint32_t fetch_data_long (struct x86emu *, uint32_t offset); +static uint32_t fetch_long (struct x86emu *, uint32_t segment, uint32_t offset); +static void store_data_byte (struct x86emu *, uint32_t offset, uint8_t val); +static void store_byte (struct x86emu *, uint32_t segment, uint32_t offset, uint8_t val); +static void store_data_word (struct x86emu *, uint32_t offset, uint16_t val); +static void store_word (struct x86emu *, uint32_t segment, uint32_t offset, uint16_t val); +static void store_data_long (struct x86emu *, uint32_t offset, uint32_t val); +static void store_long (struct x86emu *, uint32_t segment, uint32_t offset, uint32_t val); +static uint8_t* decode_rl_byte_register(struct x86emu *); +static uint16_t* decode_rl_word_register(struct x86emu *); +static uint32_t* decode_rl_long_register(struct x86emu *); +static uint8_t* decode_rh_byte_register(struct x86emu *); +static uint16_t* decode_rh_word_register(struct x86emu *); +static uint32_t* decode_rh_long_register(struct x86emu *); +static uint16_t* decode_rh_seg_register(struct x86emu *); +static uint32_t decode_rl_address(struct x86emu *); + +static uint8_t decode_and_fetch_byte(struct x86emu *); +static uint16_t decode_and_fetch_word(struct x86emu *); +static uint32_t decode_and_fetch_long(struct x86emu *); + +static uint8_t decode_and_fetch_byte_imm8(struct x86emu *, uint8_t *); +static uint16_t decode_and_fetch_word_imm8(struct x86emu *, uint8_t *); +static uint32_t decode_and_fetch_long_imm8(struct x86emu *, uint8_t *); + +static uint16_t decode_and_fetch_word_disp(struct x86emu *, int16_t); +static uint32_t decode_and_fetch_long_disp(struct x86emu *, int16_t); + +static void write_back_byte(struct x86emu *, uint8_t); +static void write_back_word(struct x86emu *, uint16_t); +static void write_back_long(struct x86emu *, uint32_t); + +static uint16_t aaa_word (struct x86emu *, uint16_t d); +static uint16_t aas_word (struct x86emu *, uint16_t d); +static uint16_t aad_word (struct x86emu *, uint16_t d); +static uint16_t aam_word (struct x86emu *, uint8_t d); +static uint8_t adc_byte (struct x86emu *, uint8_t d, uint8_t s); +static uint16_t adc_word (struct x86emu *, uint16_t d, uint16_t s); +static uint32_t adc_long (struct x86emu *, uint32_t d, uint32_t s); +static uint8_t add_byte (struct x86emu *, uint8_t d, uint8_t s); +static uint16_t add_word (struct x86emu *, uint16_t d, uint16_t s); +static uint32_t add_long (struct x86emu *, uint32_t d, uint32_t s); +static uint8_t and_byte (struct x86emu *, uint8_t d, uint8_t s); +static uint16_t and_word (struct x86emu *, uint16_t d, uint16_t s); +static uint32_t and_long (struct x86emu *, uint32_t d, uint32_t s); +static uint8_t cmp_byte (struct x86emu *, uint8_t d, uint8_t s); +static uint16_t cmp_word (struct x86emu *, uint16_t d, uint16_t s); +static uint32_t cmp_long (struct x86emu *, uint32_t d, uint32_t s); +static void cmp_byte_no_return (struct x86emu *, uint8_t d, uint8_t s); +static void cmp_word_no_return (struct x86emu *, uint16_t d, uint16_t s); +static void cmp_long_no_return (struct x86emu *, uint32_t d, uint32_t s); +static uint8_t daa_byte (struct x86emu *, uint8_t d); +static uint8_t das_byte (struct x86emu *, uint8_t d); +static uint8_t dec_byte (struct x86emu *, uint8_t d); +static uint16_t dec_word (struct x86emu *, uint16_t d); +static uint32_t dec_long (struct x86emu *, uint32_t d); +static uint8_t inc_byte (struct x86emu *, uint8_t d); +static uint16_t inc_word (struct x86emu *, uint16_t d); +static uint32_t inc_long (struct x86emu *, uint32_t d); +static uint8_t or_byte (struct x86emu *, uint8_t d, uint8_t s); +static uint16_t or_word (struct x86emu *, uint16_t d, uint16_t s); +static uint32_t or_long (struct x86emu *, uint32_t d, uint32_t s); +static uint8_t neg_byte (struct x86emu *, uint8_t s); +static uint16_t neg_word (struct x86emu *, uint16_t s); +static uint32_t neg_long (struct x86emu *, uint32_t s); +static uint8_t rcl_byte (struct x86emu *, uint8_t d, uint8_t s); +static uint16_t rcl_word (struct x86emu *, uint16_t d, uint8_t s); +static uint32_t rcl_long (struct x86emu *, uint32_t d, uint8_t s); +static uint8_t rcr_byte (struct x86emu *, uint8_t d, uint8_t s); +static uint16_t rcr_word (struct x86emu *, uint16_t d, uint8_t s); +static uint32_t rcr_long (struct x86emu *, uint32_t d, uint8_t s); +static uint8_t rol_byte (struct x86emu *, uint8_t d, uint8_t s); +static uint16_t rol_word (struct x86emu *, uint16_t d, uint8_t s); +static uint32_t rol_long (struct x86emu *, uint32_t d, uint8_t s); +static uint8_t ror_byte (struct x86emu *, uint8_t d, uint8_t s); +static uint16_t ror_word (struct x86emu *, uint16_t d, uint8_t s); +static uint32_t ror_long (struct x86emu *, uint32_t d, uint8_t s); +static uint8_t shl_byte (struct x86emu *, uint8_t d, uint8_t s); +static uint16_t shl_word (struct x86emu *, uint16_t d, uint8_t s); +static uint32_t shl_long (struct x86emu *, uint32_t d, uint8_t s); +static uint8_t shr_byte (struct x86emu *, uint8_t d, uint8_t s); +static uint16_t shr_word (struct x86emu *, uint16_t d, uint8_t s); +static uint32_t shr_long (struct x86emu *, uint32_t d, uint8_t s); +static uint8_t sar_byte (struct x86emu *, uint8_t d, uint8_t s); +static uint16_t sar_word (struct x86emu *, uint16_t d, uint8_t s); +static uint32_t sar_long (struct x86emu *, uint32_t d, uint8_t s); +static uint16_t shld_word (struct x86emu *, uint16_t d, uint16_t fill, uint8_t s); +static uint32_t shld_long (struct x86emu *, uint32_t d, uint32_t fill, uint8_t s); +static uint16_t shrd_word (struct x86emu *, uint16_t d, uint16_t fill, uint8_t s); +static uint32_t shrd_long (struct x86emu *, uint32_t d, uint32_t fill, uint8_t s); +static uint8_t sbb_byte (struct x86emu *, uint8_t d, uint8_t s); +static uint16_t sbb_word (struct x86emu *, uint16_t d, uint16_t s); +static uint32_t sbb_long (struct x86emu *, uint32_t d, uint32_t s); +static uint8_t sub_byte (struct x86emu *, uint8_t d, uint8_t s); +static uint16_t sub_word (struct x86emu *, uint16_t d, uint16_t s); +static uint32_t sub_long (struct x86emu *, uint32_t d, uint32_t s); +static void test_byte (struct x86emu *, uint8_t d, uint8_t s); +static void test_word (struct x86emu *, uint16_t d, uint16_t s); +static void test_long (struct x86emu *, uint32_t d, uint32_t s); +static uint8_t xor_byte (struct x86emu *, uint8_t d, uint8_t s); +static uint16_t xor_word (struct x86emu *, uint16_t d, uint16_t s); +static uint32_t xor_long (struct x86emu *, uint32_t d, uint32_t s); +static void imul_byte (struct x86emu *, uint8_t s); +static void imul_word (struct x86emu *, uint16_t s); +static void imul_long (struct x86emu *, uint32_t s); +static void mul_byte (struct x86emu *, uint8_t s); +static void mul_word (struct x86emu *, uint16_t s); +static void mul_long (struct x86emu *, uint32_t s); +static void idiv_byte (struct x86emu *, uint8_t s); +static void idiv_word (struct x86emu *, uint16_t s); +static void idiv_long (struct x86emu *, uint32_t s); +static void div_byte (struct x86emu *, uint8_t s); +static void div_word (struct x86emu *, uint16_t s); +static void div_long (struct x86emu *, uint32_t s); +static void ins (struct x86emu *, int size); +static void outs (struct x86emu *, int size); +static void push_word (struct x86emu *, uint16_t w); +static void push_long (struct x86emu *, uint32_t w); +static uint16_t pop_word (struct x86emu *); +static uint32_t pop_long (struct x86emu *); + +/* + * REMARKS: + * Handles any pending asychronous interrupts. + */ +static void +x86emu_intr_dispatch(struct x86emu *emu, uint8_t intno) +{ + if (emu->_x86emu_intrTab[intno]) { + (*emu->_x86emu_intrTab[intno]) (emu, intno); + } else { + push_word(emu, (uint16_t) emu->x86.R_FLG); + CLEAR_FLAG(F_IF); + CLEAR_FLAG(F_TF); + push_word(emu, emu->x86.R_CS); + emu->x86.R_CS = fetch_word(emu, 0, intno * 4 + 2); + push_word(emu, emu->x86.R_IP); + emu->x86.R_IP = fetch_word(emu, 0, intno * 4); + } +} + +static void +x86emu_intr_handle(struct x86emu *emu) +{ + uint8_t intno; + + if (emu->x86.intr & INTR_SYNCH) { + intno = emu->x86.intno; + emu->x86.intr = 0; + x86emu_intr_dispatch(emu, intno); + } +} + +/* + * PARAMETERS: + * intrnum - Interrupt number to raise + * + * REMARKS: + * Raise the specified interrupt to be handled before the execution of the + * next instruction. + */ +void +x86emu_intr_raise(struct x86emu *emu, uint8_t intrnum) +{ + emu->x86.intno = intrnum; + emu->x86.intr |= INTR_SYNCH; +} + +/* + * REMARKS: + * Main execution loop for the emulator. We return from here when the system + * halts, which is normally caused by a stack fault when we return from the + * original real mode call. + */ +void +x86emu_exec(struct x86emu *emu) +{ + emu->x86.intr = 0; + + if (setjmp(emu->exec_state)) + return; + + for (;;) { + if (emu->x86.intr) { + if (((emu->x86.intr & INTR_SYNCH) && (emu->x86.intno == 0 || emu->x86.intno == 2)) || + !ACCESS_FLAG(F_IF)) { + x86emu_intr_handle(emu); + } + } + if (emu->x86.R_CS == 0 && emu->x86.R_IP == 0) + return; + x86emu_exec_one_byte(emu); + ++emu->cur_cycles; + } +} + +void +x86emu_exec_call(struct x86emu *emu, uint16_t seg, uint16_t off) +{ + push_word(emu, 0); + push_word(emu, 0); + emu->x86.R_CS = seg; + emu->x86.R_IP = off; + + x86emu_exec(emu); +} + +void +x86emu_exec_intr(struct x86emu *emu, uint8_t intr) +{ + push_word(emu, emu->x86.R_FLG); + CLEAR_FLAG(F_IF); + CLEAR_FLAG(F_TF); + push_word(emu, 0); + push_word(emu, 0); + emu->x86.R_CS = (*emu->emu_rdw)(emu, intr * 4 + 2); + emu->x86.R_IP = (*emu->emu_rdw)(emu, intr * 4); + emu->x86.intr = 0; + + x86emu_exec(emu); +} + +/* + * REMARKS: + * Halts the system by setting the halted system flag. + */ +void +x86emu_halt_sys(struct x86emu *emu) +{ + longjmp(emu->exec_state, 1); +} + +/* + * PARAMETERS: + * mod - Mod value from decoded byte + * regh - Reg h value from decoded byte + * regl - Reg l value from decoded byte + * + * REMARKS: + * Raise the specified interrupt to be handled before the execution of the + * next instruction. + * + * NOTE: Do not inline this function, as (*emu->emu_rdb) is already inline! + */ +static void +fetch_decode_modrm(struct x86emu *emu) +{ + int fetched; + + fetched = fetch_byte_imm(emu); + emu->cur_mod = (fetched >> 6) & 0x03; + emu->cur_rh = (fetched >> 3) & 0x07; + emu->cur_rl = (fetched >> 0) & 0x07; +} + +/* + * RETURNS: + * Immediate byte value read from instruction queue + * + * REMARKS: + * This function returns the immediate byte from the instruction queue, and + * moves the instruction pointer to the next value. + * + * NOTE: Do not inline this function, as (*emu->emu_rdb) is already inline! + */ +static uint8_t +fetch_byte_imm(struct x86emu *emu) +{ + uint8_t fetched; + + fetched = fetch_byte(emu, emu->x86.R_CS, emu->x86.R_IP); + emu->x86.R_IP++; + return fetched; +} + +/* + * RETURNS: + * Immediate word value read from instruction queue + * + * REMARKS: + * This function returns the immediate byte from the instruction queue, and + * moves the instruction pointer to the next value. + * + * NOTE: Do not inline this function, as (*emu->emu_rdw) is already inline! + */ +static uint16_t +fetch_word_imm(struct x86emu *emu) +{ + uint16_t fetched; + + fetched = fetch_word(emu, emu->x86.R_CS, emu->x86.R_IP); + emu->x86.R_IP += 2; + return fetched; +} + +/* + * RETURNS: + * Immediate lone value read from instruction queue + * + * REMARKS: + * This function returns the immediate byte from the instruction queue, and + * moves the instruction pointer to the next value. + * + * NOTE: Do not inline this function, as (*emu->emu_rdw) is already inline! + */ +static uint32_t +fetch_long_imm(struct x86emu *emu) +{ + uint32_t fetched; + + fetched = fetch_long(emu, emu->x86.R_CS, emu->x86.R_IP); + emu->x86.R_IP += 4; + return fetched; +} + +/* + * RETURNS: + * Value of the default data segment + * + * REMARKS: + * Inline function that returns the default data segment for the current + * instruction. + * + * On the x86 processor, the default segment is not always DS if there is + * no segment override. Address modes such as -3[BP] or 10[BP+SI] all refer to + * addresses relative to SS (ie: on the stack). So, at the minimum, all + * decodings of addressing modes would have to set/clear a bit describing + * whether the access is relative to DS or SS. That is the function of the + * cpu-state-varible emu->x86.mode. There are several potential states: + * + * repe prefix seen (handled elsewhere) + * repne prefix seen (ditto) + * + * cs segment override + * ds segment override + * es segment override + * fs segment override + * gs segment override + * ss segment override + * + * ds/ss select (in absense of override) + * + * Each of the above 7 items are handled with a bit in the mode field. + */ +static uint32_t +get_data_segment(struct x86emu *emu) +{ + switch (emu->x86.mode & SYSMODE_SEGMASK) { + case 0: /* default case: use ds register */ + case SYSMODE_SEGOVR_DS: + case SYSMODE_SEGOVR_DS | SYSMODE_SEG_DS_SS: + return emu->x86.R_DS; + case SYSMODE_SEG_DS_SS:/* non-overridden, use ss register */ + return emu->x86.R_SS; + case SYSMODE_SEGOVR_CS: + case SYSMODE_SEGOVR_CS | SYSMODE_SEG_DS_SS: + return emu->x86.R_CS; + case SYSMODE_SEGOVR_ES: + case SYSMODE_SEGOVR_ES | SYSMODE_SEG_DS_SS: + return emu->x86.R_ES; + case SYSMODE_SEGOVR_FS: + case SYSMODE_SEGOVR_FS | SYSMODE_SEG_DS_SS: + return emu->x86.R_FS; + case SYSMODE_SEGOVR_GS: + case SYSMODE_SEGOVR_GS | SYSMODE_SEG_DS_SS: + return emu->x86.R_GS; + case SYSMODE_SEGOVR_SS: + case SYSMODE_SEGOVR_SS | SYSMODE_SEG_DS_SS: + return emu->x86.R_SS; + } + x86emu_halt_sys(emu); +} + +/* + * PARAMETERS: + * offset - Offset to load data from + * + * RETURNS: + * Byte value read from the absolute memory location. + * + * NOTE: Do not inline this function as (*emu->emu_rdX) is already inline! + */ +static uint8_t +fetch_data_byte(struct x86emu *emu, uint32_t offset) +{ + return fetch_byte(emu, get_data_segment(emu), offset); +} + +/* + * PARAMETERS: + * offset - Offset to load data from + * + * RETURNS: + * Word value read from the absolute memory location. + * + * NOTE: Do not inline this function as (*emu->emu_rdX) is already inline! + */ +static uint16_t +fetch_data_word(struct x86emu *emu, uint32_t offset) +{ + return fetch_word(emu, get_data_segment(emu), offset); +} + +/* + * PARAMETERS: + * offset - Offset to load data from + * + * RETURNS: + * Long value read from the absolute memory location. + * + * NOTE: Do not inline this function as (*emu->emu_rdX) is already inline! + */ +static uint32_t +fetch_data_long(struct x86emu *emu, uint32_t offset) +{ + return fetch_long(emu, get_data_segment(emu), offset); +} + +/* + * PARAMETERS: + * segment - Segment to load data from + * offset - Offset to load data from + * + * RETURNS: + * Byte value read from the absolute memory location. + * + * NOTE: Do not inline this function as (*emu->emu_rdX) is already inline! + */ +static uint8_t +fetch_byte(struct x86emu *emu, uint32_t segment, uint32_t offset) +{ + return (*emu->emu_rdb) (emu, ((uint32_t) segment << 4) + offset); +} + +/* + * PARAMETERS: + * segment - Segment to load data from + * offset - Offset to load data from + * + * RETURNS: + * Word value read from the absolute memory location. + * + * NOTE: Do not inline this function as (*emu->emu_rdX) is already inline! + */ +static uint16_t +fetch_word(struct x86emu *emu, uint32_t segment, uint32_t offset) +{ + return (*emu->emu_rdw) (emu, ((uint32_t) segment << 4) + offset); +} + +/* + * PARAMETERS: + * segment - Segment to load data from + * offset - Offset to load data from + * + * RETURNS: + * Long value read from the absolute memory location. + * + * NOTE: Do not inline this function as (*emu->emu_rdX) is already inline! + */ +static uint32_t +fetch_long(struct x86emu *emu, uint32_t segment, uint32_t offset) +{ + return (*emu->emu_rdl) (emu, ((uint32_t) segment << 4) + offset); +} + +/* + * PARAMETERS: + * offset - Offset to store data at + * val - Value to store + * + * REMARKS: + * Writes a word value to an segmented memory location. The segment used is + * the current 'default' segment, which may have been overridden. + * + * NOTE: Do not inline this function as (*emu->emu_wrX) is already inline! + */ +static void +store_data_byte(struct x86emu *emu, uint32_t offset, uint8_t val) +{ + store_byte(emu, get_data_segment(emu), offset, val); +} + +/* + * PARAMETERS: + * offset - Offset to store data at + * val - Value to store + * + * REMARKS: + * Writes a word value to an segmented memory location. The segment used is + * the current 'default' segment, which may have been overridden. + * + * NOTE: Do not inline this function as (*emu->emu_wrX) is already inline! + */ +static void +store_data_word(struct x86emu *emu, uint32_t offset, uint16_t val) +{ + store_word(emu, get_data_segment(emu), offset, val); +} + +/* + * PARAMETERS: + * offset - Offset to store data at + * val - Value to store + * + * REMARKS: + * Writes a long value to an segmented memory location. The segment used is + * the current 'default' segment, which may have been overridden. + * + * NOTE: Do not inline this function as (*emu->emu_wrX) is already inline! + */ +static void +store_data_long(struct x86emu *emu, uint32_t offset, uint32_t val) +{ + store_long(emu, get_data_segment(emu), offset, val); +} + +/* + * PARAMETERS: + * segment - Segment to store data at + * offset - Offset to store data at + * val - Value to store + * + * REMARKS: + * Writes a byte value to an absolute memory location. + * + * NOTE: Do not inline this function as (*emu->emu_wrX) is already inline! + */ +static void +store_byte(struct x86emu *emu, uint32_t segment, uint32_t offset, uint8_t val) +{ + (*emu->emu_wrb) (emu, ((uint32_t) segment << 4) + offset, val); +} + +/* + * PARAMETERS: + * segment - Segment to store data at + * offset - Offset to store data at + * val - Value to store + * + * REMARKS: + * Writes a word value to an absolute memory location. + * + * NOTE: Do not inline this function as (*emu->emu_wrX) is already inline! + */ +static void +store_word(struct x86emu *emu, uint32_t segment, uint32_t offset, uint16_t val) +{ + (*emu->emu_wrw) (emu, ((uint32_t) segment << 4) + offset, val); +} + +/* + * PARAMETERS: + * segment - Segment to store data at + * offset - Offset to store data at + * val - Value to store + * + * REMARKS: + * Writes a long value to an absolute memory location. + * + * NOTE: Do not inline this function as (*emu->emu_wrX) is already inline! + */ +static void +store_long(struct x86emu *emu, uint32_t segment, uint32_t offset, uint32_t val) +{ + (*emu->emu_wrl) (emu, ((uint32_t) segment << 4) + offset, val); +} + +/* + * PARAMETERS: + * reg - Register to decode + * + * RETURNS: + * Pointer to the appropriate register + * + * REMARKS: + * Return a pointer to the register given by the R/RM field of the + * modrm byte, for byte operands. Also enables the decoding of instructions. + */ +static uint8_t * +decode_rm_byte_register(struct x86emu *emu, int reg) +{ + switch (reg) { + case 0: + return &emu->x86.R_AL; + case 1: + return &emu->x86.R_CL; + case 2: + return &emu->x86.R_DL; + case 3: + return &emu->x86.R_BL; + case 4: + return &emu->x86.R_AH; + case 5: + return &emu->x86.R_CH; + case 6: + return &emu->x86.R_DH; + case 7: + return &emu->x86.R_BH; + default: + x86emu_halt_sys(emu); + } +} + +static uint8_t * +decode_rl_byte_register(struct x86emu *emu) +{ + return decode_rm_byte_register(emu, emu->cur_rl); +} + +static uint8_t * +decode_rh_byte_register(struct x86emu *emu) +{ + return decode_rm_byte_register(emu, emu->cur_rh); +} + +/* + * PARAMETERS: + * reg - Register to decode + * + * RETURNS: + * Pointer to the appropriate register + * + * REMARKS: + * Return a pointer to the register given by the R/RM field of the + * modrm byte, for word operands. Also enables the decoding of instructions. + */ +static uint16_t * +decode_rm_word_register(struct x86emu *emu, int reg) +{ + switch (reg) { + case 0: + return &emu->x86.R_AX; + case 1: + return &emu->x86.R_CX; + case 2: + return &emu->x86.R_DX; + case 3: + return &emu->x86.R_BX; + case 4: + return &emu->x86.R_SP; + case 5: + return &emu->x86.R_BP; + case 6: + return &emu->x86.R_SI; + case 7: + return &emu->x86.R_DI; + default: + x86emu_halt_sys(emu); + } +} + +static uint16_t * +decode_rl_word_register(struct x86emu *emu) +{ + return decode_rm_word_register(emu, emu->cur_rl); +} + +static uint16_t * +decode_rh_word_register(struct x86emu *emu) +{ + return decode_rm_word_register(emu, emu->cur_rh); +} + +/* + * PARAMETERS: + * reg - Register to decode + * + * RETURNS: + * Pointer to the appropriate register + * + * REMARKS: + * Return a pointer to the register given by the R/RM field of the + * modrm byte, for dword operands. Also enables the decoding of instructions. + */ +static uint32_t * +decode_rm_long_register(struct x86emu *emu, int reg) +{ + switch (reg) { + case 0: + return &emu->x86.R_EAX; + case 1: + return &emu->x86.R_ECX; + case 2: + return &emu->x86.R_EDX; + case 3: + return &emu->x86.R_EBX; + case 4: + return &emu->x86.R_ESP; + case 5: + return &emu->x86.R_EBP; + case 6: + return &emu->x86.R_ESI; + case 7: + return &emu->x86.R_EDI; + default: + x86emu_halt_sys(emu); + } +} + +static uint32_t * +decode_rl_long_register(struct x86emu *emu) +{ + return decode_rm_long_register(emu, emu->cur_rl); +} + +static uint32_t * +decode_rh_long_register(struct x86emu *emu) +{ + return decode_rm_long_register(emu, emu->cur_rh); +} + + +/* + * PARAMETERS: + * reg - Register to decode + * + * RETURNS: + * Pointer to the appropriate register + * + * REMARKS: + * Return a pointer to the register given by the R/RM field of the + * modrm byte, for word operands, modified from above for the weirdo + * special case of segreg operands. Also enables the decoding of instructions. + */ +static uint16_t * +decode_rh_seg_register(struct x86emu *emu) +{ + switch (emu->cur_rh) { + case 0: + return &emu->x86.R_ES; + case 1: + return &emu->x86.R_CS; + case 2: + return &emu->x86.R_SS; + case 3: + return &emu->x86.R_DS; + case 4: + return &emu->x86.R_FS; + case 5: + return &emu->x86.R_GS; + default: + x86emu_halt_sys(emu); + } +} +/* + * + * return offset from the SIB Byte + */ +static uint32_t +decode_sib_address(struct x86emu *emu, int sib, int mod) +{ + uint32_t base = 0, i = 0, scale = 1; + + switch (sib & 0x07) { + case 0: + base = emu->x86.R_EAX; + break; + case 1: + base = emu->x86.R_ECX; + + break; + case 2: + base = emu->x86.R_EDX; + break; + case 3: + base = emu->x86.R_EBX; + break; + case 4: + base = emu->x86.R_ESP; + emu->x86.mode |= SYSMODE_SEG_DS_SS; + break; + case 5: + if (mod == 0) { + base = fetch_long_imm(emu); + } else { + base = emu->x86.R_EBP; + emu->x86.mode |= SYSMODE_SEG_DS_SS; + } + break; + case 6: + base = emu->x86.R_ESI; + break; + case 7: + base = emu->x86.R_EDI; + break; + } + switch ((sib >> 3) & 0x07) { + case 0: + i = emu->x86.R_EAX; + break; + case 1: + i = emu->x86.R_ECX; + break; + case 2: + i = emu->x86.R_EDX; + break; + case 3: + i = emu->x86.R_EBX; + break; + case 4: + i = 0; + break; + case 5: + i = emu->x86.R_EBP; + break; + case 6: + i = emu->x86.R_ESI; + break; + case 7: + i = emu->x86.R_EDI; + break; + } + scale = 1 << ((sib >> 6) & 0x03); + return base + (i * scale); +} + +/* + * PARAMETERS: + * rm - RM value to decode + * + * RETURNS: + * Offset in memory for the address decoding + * + * REMARKS: + * Return the offset given by mod=00, mod=01 or mod=10 addressing. + * Also enables the decoding of instructions. + */ +static uint32_t +decode_rl_address(struct x86emu *emu) +{ + if (emu->x86.mode & SYSMODE_PREFIX_ADDR) { + uint32_t offset, sib; + /* 32-bit addressing */ + switch (emu->cur_rl) { + case 0: + offset = emu->x86.R_EAX; + break; + case 1: + offset = emu->x86.R_ECX; + break; + case 2: + offset = emu->x86.R_EDX; + break; + case 3: + offset = emu->x86.R_EBX; + break; + case 4: + sib = fetch_byte_imm(emu); + offset = decode_sib_address(emu, sib, 0); + break; + case 5: + if (emu->cur_mod == 0) { + offset = fetch_long_imm(emu); + } else { + emu->x86.mode |= SYSMODE_SEG_DS_SS; + offset = emu->x86.R_EBP; + } + break; + case 6: + offset = emu->x86.R_ESI; + break; + case 7: + offset = emu->x86.R_EDI; + break; + default: + x86emu_halt_sys(emu); + } + if (emu->cur_mod == 1) + offset += (int8_t)fetch_byte_imm(emu); + else if (emu->cur_mod == 2) + offset += fetch_long_imm(emu); + return offset; + } else { + uint16_t offset; + + /* 16-bit addressing */ + switch (emu->cur_rl) { + case 0: + offset = emu->x86.R_BX + emu->x86.R_SI; + break; + case 1: + offset = emu->x86.R_BX + emu->x86.R_DI; + break; + case 2: + emu->x86.mode |= SYSMODE_SEG_DS_SS; + offset = emu->x86.R_BP + emu->x86.R_SI; + break; + case 3: + emu->x86.mode |= SYSMODE_SEG_DS_SS; + offset = emu->x86.R_BP + emu->x86.R_DI; + break; + case 4: + offset = emu->x86.R_SI; + break; + case 5: + offset = emu->x86.R_DI; + break; + case 6: + if (emu->cur_mod == 0) { + offset = fetch_word_imm(emu); + } else { + emu->x86.mode |= SYSMODE_SEG_DS_SS; + offset = emu->x86.R_BP; + } + break; + case 7: + offset = emu->x86.R_BX; + break; + default: + x86emu_halt_sys(emu); + } + if (emu->cur_mod == 1) + offset += (int8_t)fetch_byte_imm(emu); + else if (emu->cur_mod == 2) + offset += fetch_word_imm(emu); + return offset; + } +} + +static uint8_t +decode_and_fetch_byte(struct x86emu *emu) +{ + if (emu->cur_mod != 3) { + emu->cur_offset = decode_rl_address(emu); + return fetch_data_byte(emu, emu->cur_offset); + } else { + return *decode_rl_byte_register(emu); + } +} + +static uint16_t +decode_and_fetch_word_disp(struct x86emu *emu, int16_t disp) +{ + if (emu->cur_mod != 3) { + /* TODO: A20 gate emulation */ + emu->cur_offset = decode_rl_address(emu) + disp; + if ((emu->x86.mode & SYSMODE_PREFIX_ADDR) == 0) + emu->cur_offset &= 0xffff; + return fetch_data_word(emu, emu->cur_offset); + } else { + return *decode_rl_word_register(emu); + } +} + +static uint32_t +decode_and_fetch_long_disp(struct x86emu *emu, int16_t disp) +{ + if (emu->cur_mod != 3) { + /* TODO: A20 gate emulation */ + emu->cur_offset = decode_rl_address(emu) + disp; + if ((emu->x86.mode & SYSMODE_PREFIX_ADDR) == 0) + emu->cur_offset &= 0xffff; + return fetch_data_long(emu, emu->cur_offset); + } else { + return *decode_rl_long_register(emu); + } +} + +uint16_t +decode_and_fetch_word(struct x86emu *emu) +{ + return decode_and_fetch_word_disp(emu, 0); +} + +uint32_t +decode_and_fetch_long(struct x86emu *emu) +{ + return decode_and_fetch_long_disp(emu, 0); +} + +uint8_t +decode_and_fetch_byte_imm8(struct x86emu *emu, uint8_t *imm) +{ + if (emu->cur_mod != 3) { + emu->cur_offset = decode_rl_address(emu); + *imm = fetch_byte_imm(emu); + return fetch_data_byte(emu, emu->cur_offset); + } else { + *imm = fetch_byte_imm(emu); + return *decode_rl_byte_register(emu); + } +} + +static uint16_t +decode_and_fetch_word_imm8(struct x86emu *emu, uint8_t *imm) +{ + if (emu->cur_mod != 3) { + emu->cur_offset = decode_rl_address(emu); + *imm = fetch_byte_imm(emu); + return fetch_data_word(emu, emu->cur_offset); + } else { + *imm = fetch_byte_imm(emu); + return *decode_rl_word_register(emu); + } +} + +static uint32_t +decode_and_fetch_long_imm8(struct x86emu *emu, uint8_t *imm) +{ + if (emu->cur_mod != 3) { + emu->cur_offset = decode_rl_address(emu); + *imm = fetch_byte_imm(emu); + return fetch_data_long(emu, emu->cur_offset); + } else { + *imm = fetch_byte_imm(emu); + return *decode_rl_long_register(emu); + } +} + +static void +write_back_byte(struct x86emu *emu, uint8_t val) +{ + if (emu->cur_mod != 3) + store_data_byte(emu, emu->cur_offset, val); + else + *decode_rl_byte_register(emu) = val; +} + +static void +write_back_word(struct x86emu *emu, uint16_t val) +{ + if (emu->cur_mod != 3) + store_data_word(emu, emu->cur_offset, val); + else + *decode_rl_word_register(emu) = val; +} + +static void +write_back_long(struct x86emu *emu, uint32_t val) +{ + if (emu->cur_mod != 3) + store_data_long(emu, emu->cur_offset, val); + else + *decode_rl_long_register(emu) = val; +} + +static void +common_inc_word_long(struct x86emu *emu, union x86emu_register *reg) +{ + if (emu->x86.mode & SYSMODE_PREFIX_DATA) + reg->I32_reg.e_reg = inc_long(emu, reg->I32_reg.e_reg); + else + reg->I16_reg.x_reg = inc_word(emu, reg->I16_reg.x_reg); +} + +static void +common_dec_word_long(struct x86emu *emu, union x86emu_register *reg) +{ + if (emu->x86.mode & SYSMODE_PREFIX_DATA) + reg->I32_reg.e_reg = dec_long(emu, reg->I32_reg.e_reg); + else + reg->I16_reg.x_reg = dec_word(emu, reg->I16_reg.x_reg); +} + +static void +common_binop_byte_rm_r(struct x86emu *emu, uint8_t (*binop)(struct x86emu *, uint8_t, uint8_t)) +{ + uint32_t destoffset; + uint8_t *destreg, srcval; + uint8_t destval; + + fetch_decode_modrm(emu); + srcval = *decode_rh_byte_register(emu); + if (emu->cur_mod != 3) { + destoffset = decode_rl_address(emu); + destval = fetch_data_byte(emu, destoffset); + destval = (*binop)(emu, destval, srcval); + store_data_byte(emu, destoffset, destval); + } else { + destreg = decode_rl_byte_register(emu); + *destreg = (*binop)(emu, *destreg, srcval); + } +} + +static void +common_binop_ns_byte_rm_r(struct x86emu *emu, void (*binop)(struct x86emu *, uint8_t, uint8_t)) +{ + uint32_t destoffset; + uint8_t destval, srcval; + + fetch_decode_modrm(emu); + srcval = *decode_rh_byte_register(emu); + if (emu->cur_mod != 3) { + destoffset = decode_rl_address(emu); + destval = fetch_data_byte(emu, destoffset); + } else { + destval = *decode_rl_byte_register(emu); + } + (*binop)(emu, destval, srcval); +} + +static void +common_binop_word_rm_r(struct x86emu *emu, uint16_t (*binop)(struct x86emu *, uint16_t, uint16_t)) +{ + uint32_t destoffset; + uint16_t destval, *destreg, srcval; + + fetch_decode_modrm(emu); + srcval = *decode_rh_word_register(emu); + if (emu->cur_mod != 3) { + destoffset = decode_rl_address(emu); + destval = fetch_data_word(emu, destoffset); + destval = (*binop)(emu, destval, srcval); + store_data_word(emu, destoffset, destval); + } else { + destreg = decode_rl_word_register(emu); + *destreg = (*binop)(emu, *destreg, srcval); + } +} + +static void +common_binop_byte_r_rm(struct x86emu *emu, uint8_t (*binop)(struct x86emu *, uint8_t, uint8_t)) +{ + uint8_t *destreg, srcval; + uint32_t srcoffset; + + fetch_decode_modrm(emu); + destreg = decode_rh_byte_register(emu); + if (emu->cur_mod != 3) { + srcoffset = decode_rl_address(emu); + srcval = fetch_data_byte(emu, srcoffset); + } else { + srcval = *decode_rl_byte_register(emu); + } + *destreg = (*binop)(emu, *destreg, srcval); +} + +static void +common_binop_long_rm_r(struct x86emu *emu, uint32_t (*binop)(struct x86emu *, uint32_t, uint32_t)) +{ + uint32_t destoffset; + uint32_t destval, *destreg, srcval; + + fetch_decode_modrm(emu); + srcval = *decode_rh_long_register(emu); + if (emu->cur_mod != 3) { + destoffset = decode_rl_address(emu); + destval = fetch_data_long(emu, destoffset); + destval = (*binop)(emu, destval, srcval); + store_data_long(emu, destoffset, destval); + } else { + destreg = decode_rl_long_register(emu); + *destreg = (*binop)(emu, *destreg, srcval); + } +} + +static void +common_binop_word_long_rm_r(struct x86emu *emu, + uint16_t (*binop16)(struct x86emu *, uint16_t, uint16_t), uint32_t (*binop32)(struct x86emu *, uint32_t, uint32_t)) +{ + if (emu->x86.mode & SYSMODE_PREFIX_DATA) + common_binop_long_rm_r(emu, binop32); + else + common_binop_word_rm_r(emu, binop16); +} + +static void +common_binop_ns_word_rm_r(struct x86emu *emu, void (*binop)(struct x86emu *, uint16_t, uint16_t)) +{ + uint32_t destoffset; + uint16_t destval, srcval; + + fetch_decode_modrm(emu); + srcval = *decode_rh_word_register(emu); + if (emu->cur_mod != 3) { + destoffset = decode_rl_address(emu); + destval = fetch_data_word(emu, destoffset); + } else { + destval = *decode_rl_word_register(emu); + } + (*binop)(emu, destval, srcval); +} + + +static void +common_binop_ns_long_rm_r(struct x86emu *emu, void (*binop)(struct x86emu *, uint32_t, uint32_t)) +{ + uint32_t destoffset; + uint32_t destval, srcval; + + fetch_decode_modrm(emu); + srcval = *decode_rh_long_register(emu); + if (emu->cur_mod != 3) { + destoffset = decode_rl_address(emu); + destval = fetch_data_long(emu, destoffset); + } else { + destval = *decode_rl_long_register(emu); + } + (*binop)(emu, destval, srcval); +} + +static void +common_binop_ns_word_long_rm_r(struct x86emu *emu, + void (*binop16)(struct x86emu *, uint16_t, uint16_t), void (*binop32)(struct x86emu *, uint32_t, uint32_t)) +{ + if (emu->x86.mode & SYSMODE_PREFIX_DATA) + common_binop_ns_long_rm_r(emu, binop32); + else + common_binop_ns_word_rm_r(emu, binop16); +} + +static void +common_binop_long_r_rm(struct x86emu *emu, uint32_t (*binop)(struct x86emu *, uint32_t, uint32_t)) +{ + uint32_t srcoffset; + uint32_t *destreg, srcval; + + fetch_decode_modrm(emu); + destreg = decode_rh_long_register(emu); + if (emu->cur_mod != 3) { + srcoffset = decode_rl_address(emu); + srcval = fetch_data_long(emu, srcoffset); + } else { + srcval = *decode_rl_long_register(emu); + } + *destreg = (*binop)(emu, *destreg, srcval); +} + +static void +common_binop_word_r_rm(struct x86emu *emu, uint16_t (*binop)(struct x86emu *, uint16_t, uint16_t)) +{ + uint32_t srcoffset; + uint16_t *destreg, srcval; + + fetch_decode_modrm(emu); + destreg = decode_rh_word_register(emu); + if (emu->cur_mod != 3) { + srcoffset = decode_rl_address(emu); + srcval = fetch_data_word(emu, srcoffset); + } else { + srcval = *decode_rl_word_register(emu); + } + *destreg = (*binop)(emu, *destreg, srcval); +} + +static void +common_binop_word_long_r_rm(struct x86emu *emu, + uint16_t (*binop16)(struct x86emu *, uint16_t, uint16_t), uint32_t (*binop32)(struct x86emu *, uint32_t, uint32_t)) +{ + if (emu->x86.mode & SYSMODE_PREFIX_DATA) + common_binop_long_r_rm(emu, binop32); + else + common_binop_word_r_rm(emu, binop16); +} + +static void +common_binop_byte_imm(struct x86emu *emu, uint8_t (*binop)(struct x86emu *, uint8_t, uint8_t)) +{ + uint8_t srcval; + + srcval = fetch_byte_imm(emu); + emu->x86.R_AL = (*binop)(emu, emu->x86.R_AL, srcval); +} + +static void +common_binop_word_long_imm(struct x86emu *emu, + uint16_t (*binop16)(struct x86emu *, uint16_t, uint16_t), uint32_t (*binop32)(struct x86emu *, uint32_t, uint32_t)) +{ + if (emu->x86.mode & SYSMODE_PREFIX_DATA) { + uint32_t srcval; + + srcval = fetch_long_imm(emu); + emu->x86.R_EAX = (*binop32)(emu, emu->x86.R_EAX, srcval); + } else { + uint16_t srcval; + + srcval = fetch_word_imm(emu); + emu->x86.R_AX = (*binop16)(emu, emu->x86.R_AX, srcval); + } +} + +static void +common_push_word_long(struct x86emu *emu, union x86emu_register *reg) +{ + if (emu->x86.mode & SYSMODE_PREFIX_DATA) + push_long(emu, reg->I32_reg.e_reg); + else + push_word(emu, reg->I16_reg.x_reg); +} + +static void +common_pop_word_long(struct x86emu *emu, union x86emu_register *reg) +{ + if (emu->x86.mode & SYSMODE_PREFIX_DATA) + reg->I32_reg.e_reg = pop_long(emu); + else + reg->I16_reg.x_reg = pop_word(emu); +} + +static void +common_imul_long_IMM(struct x86emu *emu, int byte_imm) +{ + uint32_t srcoffset; + uint32_t *destreg, srcval; + int32_t imm; + uint64_t res; + + fetch_decode_modrm(emu); + destreg = decode_rh_long_register(emu); + if (emu->cur_mod != 3) { + srcoffset = decode_rl_address(emu); + srcval = fetch_data_long(emu, srcoffset); + } else { + srcval = *decode_rl_long_register(emu); + } + + if (byte_imm) + imm = (int8_t)fetch_byte_imm(emu); + else + imm = fetch_long_imm(emu); + res = (int32_t)srcval * imm; + + if (res > 0xffffffff) { + SET_FLAG(F_CF); + SET_FLAG(F_OF); + } else { + CLEAR_FLAG(F_CF); + CLEAR_FLAG(F_OF); + } + *destreg = (uint32_t)res; +} + +static void +common_imul_word_IMM(struct x86emu *emu, int byte_imm) +{ + uint32_t srcoffset; + uint16_t *destreg, srcval; + int16_t imm; + uint32_t res; + + fetch_decode_modrm(emu); + destreg = decode_rh_word_register(emu); + if (emu->cur_mod != 3) { + srcoffset = decode_rl_address(emu); + srcval = fetch_data_word(emu, srcoffset); + } else { + srcval = *decode_rl_word_register(emu); + } + + if (byte_imm) + imm = (int8_t)fetch_byte_imm(emu); + else + imm = fetch_word_imm(emu); + res = (int16_t)srcval * imm; + + if (res > 0xffff) { + SET_FLAG(F_CF); + SET_FLAG(F_OF); + } else { + CLEAR_FLAG(F_CF); + CLEAR_FLAG(F_OF); + } + *destreg = (uint16_t) res; +} + +static void +common_imul_imm(struct x86emu *emu, int byte_imm) +{ + if (emu->x86.mode & SYSMODE_PREFIX_DATA) + common_imul_long_IMM(emu, byte_imm); + else + common_imul_word_IMM(emu, byte_imm); +} + +static void +common_jmp_near(struct x86emu *emu, int cond) +{ + int8_t offset; + uint16_t target; + + offset = (int8_t) fetch_byte_imm(emu); + target = (uint16_t) (emu->x86.R_IP + (int16_t) offset); + if (cond) + emu->x86.R_IP = target; +} + +static void +common_load_far_pointer(struct x86emu *emu, uint16_t *seg) +{ + uint16_t *dstreg; + uint32_t srcoffset; + + fetch_decode_modrm(emu); + if (emu->cur_mod == 3) + x86emu_halt_sys(emu); + + dstreg = decode_rh_word_register(emu); + srcoffset = decode_rl_address(emu); + *dstreg = fetch_data_word(emu, srcoffset); + *seg = fetch_data_word(emu, srcoffset + 2); +} + +/* Implementation */ + +/* + * REMARKS: + * Handles opcode 0x3a + */ +static void +x86emuOp_cmp_byte_R_RM(struct x86emu *emu) +{ + uint8_t *destreg, srcval; + + fetch_decode_modrm(emu); + destreg = decode_rh_byte_register(emu); + srcval = decode_and_fetch_byte(emu); + cmp_byte(emu, *destreg, srcval); +} + +/* + * REMARKS: + * + * Handles opcode 0x3b + */ +static void +x86emuOp32_cmp_word_R_RM(struct x86emu *emu) +{ + uint32_t srcval, *destreg; + + fetch_decode_modrm(emu); + destreg = decode_rh_long_register(emu); + srcval = decode_and_fetch_long(emu); + cmp_long(emu, *destreg, srcval); +} + +static void +x86emuOp16_cmp_word_R_RM(struct x86emu *emu) +{ + uint16_t srcval, *destreg; + + fetch_decode_modrm(emu); + destreg = decode_rh_word_register(emu); + srcval = decode_and_fetch_word(emu); + cmp_word(emu, *destreg, srcval); +} + +static void +x86emuOp_cmp_word_R_RM(struct x86emu *emu) +{ + if (emu->x86.mode & SYSMODE_PREFIX_DATA) + x86emuOp32_cmp_word_R_RM(emu); + else + x86emuOp16_cmp_word_R_RM(emu); +} + +/* + * REMARKS: + * Handles opcode 0x3c + */ +static void +x86emuOp_cmp_byte_AL_IMM(struct x86emu *emu) +{ + uint8_t srcval; + + srcval = fetch_byte_imm(emu); + cmp_byte(emu, emu->x86.R_AL, srcval); +} + +/* + * REMARKS: + * Handles opcode 0x3d + */ +static void +x86emuOp32_cmp_word_AX_IMM(struct x86emu *emu) +{ + uint32_t srcval; + + srcval = fetch_long_imm(emu); + cmp_long(emu, emu->x86.R_EAX, srcval); +} + +static void +x86emuOp16_cmp_word_AX_IMM(struct x86emu *emu) +{ + uint16_t srcval; + + srcval = fetch_word_imm(emu); + cmp_word(emu, emu->x86.R_AX, srcval); +} + +static void +x86emuOp_cmp_word_AX_IMM(struct x86emu *emu) +{ + if (emu->x86.mode & SYSMODE_PREFIX_DATA) + x86emuOp32_cmp_word_AX_IMM(emu); + else + x86emuOp16_cmp_word_AX_IMM(emu); +} + +/* + * REMARKS: + * Handles opcode 0x60 + */ +static void +x86emuOp_push_all(struct x86emu *emu) +{ + if (emu->x86.mode & SYSMODE_PREFIX_DATA) { + uint32_t old_sp = emu->x86.R_ESP; + + push_long(emu, emu->x86.R_EAX); + push_long(emu, emu->x86.R_ECX); + push_long(emu, emu->x86.R_EDX); + push_long(emu, emu->x86.R_EBX); + push_long(emu, old_sp); + push_long(emu, emu->x86.R_EBP); + push_long(emu, emu->x86.R_ESI); + push_long(emu, emu->x86.R_EDI); + } else { + uint16_t old_sp = emu->x86.R_SP; + + push_word(emu, emu->x86.R_AX); + push_word(emu, emu->x86.R_CX); + push_word(emu, emu->x86.R_DX); + push_word(emu, emu->x86.R_BX); + push_word(emu, old_sp); + push_word(emu, emu->x86.R_BP); + push_word(emu, emu->x86.R_SI); + push_word(emu, emu->x86.R_DI); + } +} + +/* + * REMARKS: + * Handles opcode 0x61 + */ +static void +x86emuOp_pop_all(struct x86emu *emu) +{ + if (emu->x86.mode & SYSMODE_PREFIX_DATA) { + emu->x86.R_EDI = pop_long(emu); + emu->x86.R_ESI = pop_long(emu); + emu->x86.R_EBP = pop_long(emu); + emu->x86.R_ESP += 4; /* skip ESP */ + emu->x86.R_EBX = pop_long(emu); + emu->x86.R_EDX = pop_long(emu); + emu->x86.R_ECX = pop_long(emu); + emu->x86.R_EAX = pop_long(emu); + } else { + emu->x86.R_DI = pop_word(emu); + emu->x86.R_SI = pop_word(emu); + emu->x86.R_BP = pop_word(emu); + emu->x86.R_SP += 2;/* skip SP */ + emu->x86.R_BX = pop_word(emu); + emu->x86.R_DX = pop_word(emu); + emu->x86.R_CX = pop_word(emu); + emu->x86.R_AX = pop_word(emu); + } +} +/*opcode 0x62 ILLEGAL OP, calls x86emuOp_illegal_op() */ +/*opcode 0x63 ILLEGAL OP, calls x86emuOp_illegal_op() */ + + +/* + * REMARKS: + * Handles opcode 0x68 + */ +static void +x86emuOp_push_word_IMM(struct x86emu *emu) +{ + if (emu->x86.mode & SYSMODE_PREFIX_DATA) { + uint32_t imm; + + imm = fetch_long_imm(emu); + push_long(emu, imm); + } else { + uint16_t imm; + + imm = fetch_word_imm(emu); + push_word(emu, imm); + } +} + +/* + * REMARKS: + * Handles opcode 0x6a + */ +static void +x86emuOp_push_byte_IMM(struct x86emu *emu) +{ + int16_t imm; + + imm = (int8_t) fetch_byte_imm(emu); + if (emu->x86.mode & SYSMODE_PREFIX_DATA) { + push_long(emu, (int32_t) imm); + } else { + push_word(emu, imm); + } +} + +/* + * REMARKS: + * Handles opcode 0x6c and 0x6d + */ +static void +x86emuOp_ins_word(struct x86emu *emu) +{ + if (emu->x86.mode & SYSMODE_PREFIX_DATA) { + ins(emu, 4); + } else { + ins(emu, 2); + } +} + +/* + * REMARKS: + * Handles opcode 0x6f + */ +static void +x86emuOp_outs_word(struct x86emu *emu) +{ + if (emu->x86.mode & SYSMODE_PREFIX_DATA) { + outs(emu, 4); + } else { + outs(emu, 2); + } +} + +/* + * REMARKS: + * Handles opcode 0x7c + */ +static void +x86emuOp_jump_near_L(struct x86emu *emu) +{ + int sf, of; + + sf = ACCESS_FLAG(F_SF) != 0; + of = ACCESS_FLAG(F_OF) != 0; + + common_jmp_near(emu, sf != of); +} + +/* + * REMARKS: + * Handles opcode 0x7d + */ +static void +x86emuOp_jump_near_NL(struct x86emu *emu) +{ + int sf, of; + + sf = ACCESS_FLAG(F_SF) != 0; + of = ACCESS_FLAG(F_OF) != 0; + + common_jmp_near(emu, sf == of); +} + +/* + * REMARKS: + * Handles opcode 0x7e + */ +static void +x86emuOp_jump_near_LE(struct x86emu *emu) +{ + int sf, of; + + sf = ACCESS_FLAG(F_SF) != 0; + of = ACCESS_FLAG(F_OF) != 0; + + common_jmp_near(emu, sf != of || ACCESS_FLAG(F_ZF)); +} + +/* + * REMARKS: + * Handles opcode 0x7f + */ +static void +x86emuOp_jump_near_NLE(struct x86emu *emu) +{ + int sf, of; + + sf = ACCESS_FLAG(F_SF) != 0; + of = ACCESS_FLAG(F_OF) != 0; + + common_jmp_near(emu, sf == of && !ACCESS_FLAG(F_ZF)); +} + +static +uint8_t(*const opc80_byte_operation[]) (struct x86emu *, uint8_t d, uint8_t s) = +{ + add_byte, /* 00 */ + or_byte, /* 01 */ + adc_byte, /* 02 */ + sbb_byte, /* 03 */ + and_byte, /* 04 */ + sub_byte, /* 05 */ + xor_byte, /* 06 */ + cmp_byte, /* 07 */ +}; + +/* + * REMARKS: + * Handles opcode 0x80 + */ +static void +x86emuOp_opc80_byte_RM_IMM(struct x86emu *emu) +{ + uint8_t imm, destval; + + /* + * Weirdo special case instruction format. Part of the opcode + * held below in "RH". Doubly nested case would result, except + * that the decoded instruction + */ + fetch_decode_modrm(emu); + destval = decode_and_fetch_byte(emu); + imm = fetch_byte_imm(emu); + destval = (*opc80_byte_operation[emu->cur_rh]) (emu, destval, imm); + if (emu->cur_rh != 7) + write_back_byte(emu, destval); +} + +static +uint16_t(* const opc81_word_operation[]) (struct x86emu *, uint16_t d, uint16_t s) = +{ + add_word, /* 00 */ + or_word, /* 01 */ + adc_word, /* 02 */ + sbb_word, /* 03 */ + and_word, /* 04 */ + sub_word, /* 05 */ + xor_word, /* 06 */ + cmp_word, /* 07 */ +}; + +static +uint32_t(* const opc81_long_operation[]) (struct x86emu *, uint32_t d, uint32_t s) = +{ + add_long, /* 00 */ + or_long, /* 01 */ + adc_long, /* 02 */ + sbb_long, /* 03 */ + and_long, /* 04 */ + sub_long, /* 05 */ + xor_long, /* 06 */ + cmp_long, /* 07 */ +}; + +/* + * REMARKS: + * Handles opcode 0x81 + */ +static void +x86emuOp32_opc81_word_RM_IMM(struct x86emu *emu) +{ + uint32_t destval, imm; + + /* + * Weirdo special case instruction format. Part of the opcode + * held below in "RH". Doubly nested case would result, except + * that the decoded instruction + */ + fetch_decode_modrm(emu); + destval = decode_and_fetch_long(emu); + imm = fetch_long_imm(emu); + destval = (*opc81_long_operation[emu->cur_rh]) (emu, destval, imm); + if (emu->cur_rh != 7) + write_back_long(emu, destval); +} + +static void +x86emuOp16_opc81_word_RM_IMM(struct x86emu *emu) +{ + uint16_t destval, imm; + + /* + * Weirdo special case instruction format. Part of the opcode + * held below in "RH". Doubly nested case would result, except + * that the decoded instruction + */ + fetch_decode_modrm(emu); + destval = decode_and_fetch_word(emu); + imm = fetch_word_imm(emu); + destval = (*opc81_word_operation[emu->cur_rh]) (emu, destval, imm); + if (emu->cur_rh != 7) + write_back_word(emu, destval); +} + +static void +x86emuOp_opc81_word_RM_IMM(struct x86emu *emu) +{ + if (emu->x86.mode & SYSMODE_PREFIX_DATA) + x86emuOp32_opc81_word_RM_IMM(emu); + else + x86emuOp16_opc81_word_RM_IMM(emu); +} + +static +uint8_t(* const opc82_byte_operation[]) (struct x86emu *, uint8_t s, uint8_t d) = +{ + add_byte, /* 00 */ + or_byte, /* 01 *//* YYY UNUSED ???? */ + adc_byte, /* 02 */ + sbb_byte, /* 03 */ + and_byte, /* 04 *//* YYY UNUSED ???? */ + sub_byte, /* 05 */ + xor_byte, /* 06 *//* YYY UNUSED ???? */ + cmp_byte, /* 07 */ +}; + +/* + * REMARKS: + * Handles opcode 0x82 + */ +static void +x86emuOp_opc82_byte_RM_IMM(struct x86emu *emu) +{ + uint8_t imm, destval; + + /* + * Weirdo special case instruction format. Part of the opcode + * held below in "RH". Doubly nested case would result, except + * that the decoded instruction Similar to opcode 81, except that + * the immediate byte is sign extended to a word length. + */ + fetch_decode_modrm(emu); + destval = decode_and_fetch_byte(emu); + imm = fetch_byte_imm(emu); + destval = (*opc82_byte_operation[emu->cur_rh]) (emu, destval, imm); + if (emu->cur_rh != 7) + write_back_byte(emu, destval); +} + +static +uint16_t(* const opc83_word_operation[]) (struct x86emu *, uint16_t s, uint16_t d) = +{ + add_word, /* 00 */ + or_word, /* 01 *//* YYY UNUSED ???? */ + adc_word, /* 02 */ + sbb_word, /* 03 */ + and_word, /* 04 *//* YYY UNUSED ???? */ + sub_word, /* 05 */ + xor_word, /* 06 *//* YYY UNUSED ???? */ + cmp_word, /* 07 */ +}; + +static +uint32_t(* const opc83_long_operation[]) (struct x86emu *, uint32_t s, uint32_t d) = +{ + add_long, /* 00 */ + or_long, /* 01 *//* YYY UNUSED ???? */ + adc_long, /* 02 */ + sbb_long, /* 03 */ + and_long, /* 04 *//* YYY UNUSED ???? */ + sub_long, /* 05 */ + xor_long, /* 06 *//* YYY UNUSED ???? */ + cmp_long, /* 07 */ +}; + +/* + * REMARKS: + * Handles opcode 0x83 + */ +static void +x86emuOp32_opc83_word_RM_IMM(struct x86emu *emu) +{ + uint32_t destval, imm; + + fetch_decode_modrm(emu); + destval = decode_and_fetch_long(emu); + imm = (int8_t) fetch_byte_imm(emu); + destval = (*opc83_long_operation[emu->cur_rh]) (emu, destval, imm); + if (emu->cur_rh != 7) + write_back_long(emu, destval); +} + +static void +x86emuOp16_opc83_word_RM_IMM(struct x86emu *emu) +{ + uint16_t destval, imm; + + fetch_decode_modrm(emu); + destval = decode_and_fetch_word(emu); + imm = (int8_t) fetch_byte_imm(emu); + destval = (*opc83_word_operation[emu->cur_rh]) (emu, destval, imm); + if (emu->cur_rh != 7) + write_back_word(emu, destval); +} + +static void +x86emuOp_opc83_word_RM_IMM(struct x86emu *emu) +{ + if (emu->x86.mode & SYSMODE_PREFIX_DATA) + x86emuOp32_opc83_word_RM_IMM(emu); + else + x86emuOp16_opc83_word_RM_IMM(emu); +} + +/* + * REMARKS: + * Handles opcode 0x86 + */ +static void +x86emuOp_xchg_byte_RM_R(struct x86emu *emu) +{ + uint8_t *srcreg, destval, tmp; + + fetch_decode_modrm(emu); + destval = decode_and_fetch_byte(emu); + srcreg = decode_rh_byte_register(emu); + tmp = destval; + destval = *srcreg; + *srcreg = tmp; + write_back_byte(emu, destval); +} + +/* + * REMARKS: + * Handles opcode 0x87 + */ +static void +x86emuOp32_xchg_word_RM_R(struct x86emu *emu) +{ + uint32_t *srcreg, destval, tmp; + + fetch_decode_modrm(emu); + destval = decode_and_fetch_long(emu); + srcreg = decode_rh_long_register(emu); + tmp = destval; + destval = *srcreg; + *srcreg = tmp; + write_back_long(emu, destval); +} + +static void +x86emuOp16_xchg_word_RM_R(struct x86emu *emu) +{ + uint16_t *srcreg, destval, tmp; + + fetch_decode_modrm(emu); + destval = decode_and_fetch_word(emu); + srcreg = decode_rh_word_register(emu); + tmp = destval; + destval = *srcreg; + *srcreg = tmp; + write_back_word(emu, destval); +} + +static void +x86emuOp_xchg_word_RM_R(struct x86emu *emu) +{ + if (emu->x86.mode & SYSMODE_PREFIX_DATA) + x86emuOp32_xchg_word_RM_R(emu); + else + x86emuOp16_xchg_word_RM_R(emu); +} + +/* + * REMARKS: + * Handles opcode 0x88 + */ +static void +x86emuOp_mov_byte_RM_R(struct x86emu *emu) +{ + uint8_t *destreg, *srcreg; + uint32_t destoffset; + + fetch_decode_modrm(emu); + srcreg = decode_rh_byte_register(emu); + if (emu->cur_mod != 3) { + destoffset = decode_rl_address(emu); + store_data_byte(emu, destoffset, *srcreg); + } else { + destreg = decode_rl_byte_register(emu); + *destreg = *srcreg; + } +} + +/* + * REMARKS: + * Handles opcode 0x89 + */ +static void +x86emuOp32_mov_word_RM_R(struct x86emu *emu) +{ + uint32_t destoffset; + uint32_t *destreg, srcval; + + fetch_decode_modrm(emu); + srcval = *decode_rh_long_register(emu); + if (emu->cur_mod != 3) { + destoffset = decode_rl_address(emu); + store_data_long(emu, destoffset, srcval); + } else { + destreg = decode_rl_long_register(emu); + *destreg = srcval; + } +} + +static void +x86emuOp16_mov_word_RM_R(struct x86emu *emu) +{ + uint32_t destoffset; + uint16_t *destreg, srcval; + + fetch_decode_modrm(emu); + srcval = *decode_rh_word_register(emu); + if (emu->cur_mod != 3) { + destoffset = decode_rl_address(emu); + store_data_word(emu, destoffset, srcval); + } else { + destreg = decode_rl_word_register(emu); + *destreg = srcval; + } +} + +static void +x86emuOp_mov_word_RM_R(struct x86emu *emu) +{ + if (emu->x86.mode & SYSMODE_PREFIX_DATA) + x86emuOp32_mov_word_RM_R(emu); + else + x86emuOp16_mov_word_RM_R(emu); +} + +/* + * REMARKS: + * Handles opcode 0x8a + */ +static void +x86emuOp_mov_byte_R_RM(struct x86emu *emu) +{ + uint8_t *destreg; + + fetch_decode_modrm(emu); + destreg = decode_rh_byte_register(emu); + *destreg = decode_and_fetch_byte(emu); +} + +/* + * REMARKS: + * Handles opcode 0x8b + */ +static void +x86emuOp_mov_word_R_RM(struct x86emu *emu) +{ + if (emu->x86.mode & SYSMODE_PREFIX_DATA) { + uint32_t *destreg; + + fetch_decode_modrm(emu); + destreg = decode_rh_long_register(emu); + *destreg = decode_and_fetch_long(emu); + } else { + uint16_t *destreg; + + fetch_decode_modrm(emu); + destreg = decode_rh_word_register(emu); + *destreg = decode_and_fetch_word(emu); + } +} + +/* + * REMARKS: + * Handles opcode 0x8c + */ +static void +x86emuOp_mov_word_RM_SR(struct x86emu *emu) +{ + uint16_t *destreg, srcval; + uint32_t destoffset; + + fetch_decode_modrm(emu); + srcval = *decode_rh_seg_register(emu); + if (emu->cur_mod != 3) { + destoffset = decode_rl_address(emu); + store_data_word(emu, destoffset, srcval); + } else { + destreg = decode_rl_word_register(emu); + *destreg = srcval; + } +} + +/* + * REMARKS: + * Handles opcode 0x8d + */ +static void +x86emuOp_lea_word_R_M(struct x86emu *emu) +{ + uint16_t *srcreg; + uint32_t destoffset; + +/* + * TODO: Need to handle address size prefix! + * + * lea eax,[eax+ebx*2] ?? + */ + fetch_decode_modrm(emu); + if (emu->cur_mod == 3) + x86emu_halt_sys(emu); + + srcreg = decode_rh_word_register(emu); + destoffset = decode_rl_address(emu); + *srcreg = (uint16_t) destoffset; +} + +/* + * REMARKS: + * Handles opcode 0x8e + */ +static void +x86emuOp_mov_word_SR_RM(struct x86emu *emu) +{ + uint16_t *destreg; + + fetch_decode_modrm(emu); + destreg = decode_rh_seg_register(emu); + *destreg = decode_and_fetch_word(emu); + /* + * Clean up, and reset all the R_xSP pointers to the correct + * locations. This is about 3x too much overhead (doing all the + * segreg ptrs when only one is needed, but this instruction + * *cannot* be that common, and this isn't too much work anyway. + */ +} + +/* + * REMARKS: + * Handles opcode 0x8f + */ +static void +x86emuOp32_pop_RM(struct x86emu *emu) +{ + uint32_t destoffset; + uint32_t destval, *destreg; + + fetch_decode_modrm(emu); + if (emu->cur_mod != 3) { + destoffset = decode_rl_address(emu); + destval = pop_long(emu); + store_data_long(emu, destoffset, destval); + } else { + destreg = decode_rl_long_register(emu); + *destreg = pop_long(emu); + } +} + +static void +x86emuOp16_pop_RM(struct x86emu *emu) +{ + uint32_t destoffset; + uint16_t destval, *destreg; + + fetch_decode_modrm(emu); + if (emu->cur_mod != 3) { + destoffset = decode_rl_address(emu); + destval = pop_word(emu); + store_data_word(emu, destoffset, destval); + } else { + destreg = decode_rl_word_register(emu); + *destreg = pop_word(emu); + } +} + +static void +x86emuOp_pop_RM(struct x86emu *emu) +{ + if (emu->x86.mode & SYSMODE_PREFIX_DATA) + x86emuOp32_pop_RM(emu); + else + x86emuOp16_pop_RM(emu); +} + +/* + * REMARKS: + * Handles opcode 0x91 + */ +static void +x86emuOp_xchg_word_AX_CX(struct x86emu *emu) +{ + uint32_t tmp; + + if (emu->x86.mode & SYSMODE_PREFIX_DATA) { + tmp = emu->x86.R_EAX; + emu->x86.R_EAX = emu->x86.R_ECX; + emu->x86.R_ECX = tmp; + } else { + tmp = emu->x86.R_AX; + emu->x86.R_AX = emu->x86.R_CX; + emu->x86.R_CX = (uint16_t) tmp; + } +} + +/* + * REMARKS: + * Handles opcode 0x92 + */ +static void +x86emuOp_xchg_word_AX_DX(struct x86emu *emu) +{ + uint32_t tmp; + + if (emu->x86.mode & SYSMODE_PREFIX_DATA) { + tmp = emu->x86.R_EAX; + emu->x86.R_EAX = emu->x86.R_EDX; + emu->x86.R_EDX = tmp; + } else { + tmp = emu->x86.R_AX; + emu->x86.R_AX = emu->x86.R_DX; + emu->x86.R_DX = (uint16_t) tmp; + } +} + +/* + * REMARKS: + * Handles opcode 0x93 + */ +static void +x86emuOp_xchg_word_AX_BX(struct x86emu *emu) +{ + uint32_t tmp; + + if (emu->x86.mode & SYSMODE_PREFIX_DATA) { + tmp = emu->x86.R_EAX; + emu->x86.R_EAX = emu->x86.R_EBX; + emu->x86.R_EBX = tmp; + } else { + tmp = emu->x86.R_AX; + emu->x86.R_AX = emu->x86.R_BX; + emu->x86.R_BX = (uint16_t) tmp; + } +} + +/* + * REMARKS: + * Handles opcode 0x94 + */ +static void +x86emuOp_xchg_word_AX_SP(struct x86emu *emu) +{ + uint32_t tmp; + + if (emu->x86.mode & SYSMODE_PREFIX_DATA) { + tmp = emu->x86.R_EAX; + emu->x86.R_EAX = emu->x86.R_ESP; + emu->x86.R_ESP = tmp; + } else { + tmp = emu->x86.R_AX; + emu->x86.R_AX = emu->x86.R_SP; + emu->x86.R_SP = (uint16_t) tmp; + } +} + +/* + * REMARKS: + * Handles opcode 0x95 + */ +static void +x86emuOp_xchg_word_AX_BP(struct x86emu *emu) +{ + uint32_t tmp; + + if (emu->x86.mode & SYSMODE_PREFIX_DATA) { + tmp = emu->x86.R_EAX; + emu->x86.R_EAX = emu->x86.R_EBP; + emu->x86.R_EBP = tmp; + } else { + tmp = emu->x86.R_AX; + emu->x86.R_AX = emu->x86.R_BP; + emu->x86.R_BP = (uint16_t) tmp; + } +} + +/* + * REMARKS: + * Handles opcode 0x96 + */ +static void +x86emuOp_xchg_word_AX_SI(struct x86emu *emu) +{ + uint32_t tmp; + + if (emu->x86.mode & SYSMODE_PREFIX_DATA) { + tmp = emu->x86.R_EAX; + emu->x86.R_EAX = emu->x86.R_ESI; + emu->x86.R_ESI = tmp; + } else { + tmp = emu->x86.R_AX; + emu->x86.R_AX = emu->x86.R_SI; + emu->x86.R_SI = (uint16_t) tmp; + } +} + +/* + * REMARKS: + * Handles opcode 0x97 + */ +static void +x86emuOp_xchg_word_AX_DI(struct x86emu *emu) +{ + uint32_t tmp; + + if (emu->x86.mode & SYSMODE_PREFIX_DATA) { + tmp = emu->x86.R_EAX; + emu->x86.R_EAX = emu->x86.R_EDI; + emu->x86.R_EDI = tmp; + } else { + tmp = emu->x86.R_AX; + emu->x86.R_AX = emu->x86.R_DI; + emu->x86.R_DI = (uint16_t) tmp; + } +} + +/* + * REMARKS: + * Handles opcode 0x98 + */ +static void +x86emuOp_cbw(struct x86emu *emu) +{ + if (emu->x86.mode & SYSMODE_PREFIX_DATA) { + if (emu->x86.R_AX & 0x8000) { + emu->x86.R_EAX |= 0xffff0000; + } else { + emu->x86.R_EAX &= 0x0000ffff; + } + } else { + if (emu->x86.R_AL & 0x80) { + emu->x86.R_AH = 0xff; + } else { + emu->x86.R_AH = 0x0; + } + } +} + +/* + * REMARKS: + * Handles opcode 0x99 + */ +static void +x86emuOp_cwd(struct x86emu *emu) +{ + if (emu->x86.mode & SYSMODE_PREFIX_DATA) { + if (emu->x86.R_EAX & 0x80000000) { + emu->x86.R_EDX = 0xffffffff; + } else { + emu->x86.R_EDX = 0x0; + } + } else { + if (emu->x86.R_AX & 0x8000) { + emu->x86.R_DX = 0xffff; + } else { + emu->x86.R_DX = 0x0; + } + } +} + +/* + * REMARKS: + * Handles opcode 0x9a + */ +static void +x86emuOp_call_far_IMM(struct x86emu *emu) +{ + uint16_t farseg, faroff; + + faroff = fetch_word_imm(emu); + farseg = fetch_word_imm(emu); + /* XXX + * + * Hooked interrupt vectors calling into our "BIOS" will cause problems + * unless all intersegment stuff is checked for BIOS access. Check + * needed here. For moment, let it alone. */ + push_word(emu, emu->x86.R_CS); + emu->x86.R_CS = farseg; + push_word(emu, emu->x86.R_IP); + emu->x86.R_IP = faroff; +} + +/* + * REMARKS: + * Handles opcode 0x9c + */ +static void +x86emuOp_pushf_word(struct x86emu *emu) +{ + uint32_t flags; + + /* clear out *all* bits not representing flags, and turn on real bits */ + flags = (emu->x86.R_EFLG & F_MSK) | F_ALWAYS_ON; + if (emu->x86.mode & SYSMODE_PREFIX_DATA) { + push_long(emu, flags); + } else { + push_word(emu, (uint16_t) flags); + } +} + +/* + * REMARKS: + * Handles opcode 0x9d + */ +static void +x86emuOp_popf_word(struct x86emu *emu) +{ + if (emu->x86.mode & SYSMODE_PREFIX_DATA) { + emu->x86.R_EFLG = pop_long(emu); + } else { + emu->x86.R_FLG = pop_word(emu); + } +} + +/* + * REMARKS: + * Handles opcode 0x9e + */ +static void +x86emuOp_sahf(struct x86emu *emu) +{ + /* clear the lower bits of the flag register */ + emu->x86.R_FLG &= 0xffffff00; + /* or in the AH register into the flags register */ + emu->x86.R_FLG |= emu->x86.R_AH; +} + +/* + * REMARKS: + * Handles opcode 0x9f + */ +static void +x86emuOp_lahf(struct x86emu *emu) +{ + emu->x86.R_AH = (uint8_t) (emu->x86.R_FLG & 0xff); + /* undocumented TC++ behavior??? Nope. It's documented, but you have + * too look real hard to notice it. */ + emu->x86.R_AH |= 0x2; +} + +/* + * REMARKS: + * Handles opcode 0xa0 + */ +static void +x86emuOp_mov_AL_M_IMM(struct x86emu *emu) +{ + uint16_t offset; + + offset = fetch_word_imm(emu); + emu->x86.R_AL = fetch_data_byte(emu, offset); +} + +/* + * REMARKS: + * Handles opcode 0xa1 + */ +static void +x86emuOp_mov_AX_M_IMM(struct x86emu *emu) +{ + uint16_t offset; + + offset = fetch_word_imm(emu); + if (emu->x86.mode & SYSMODE_PREFIX_DATA) { + emu->x86.R_EAX = fetch_data_long(emu, offset); + } else { + emu->x86.R_AX = fetch_data_word(emu, offset); + } +} + +/* + * REMARKS: + * Handles opcode 0xa2 + */ +static void +x86emuOp_mov_M_AL_IMM(struct x86emu *emu) +{ + uint16_t offset; + + offset = fetch_word_imm(emu); + store_data_byte(emu, offset, emu->x86.R_AL); +} + +/* + * REMARKS: + * Handles opcode 0xa3 + */ +static void +x86emuOp_mov_M_AX_IMM(struct x86emu *emu) +{ + uint16_t offset; + + offset = fetch_word_imm(emu); + if (emu->x86.mode & SYSMODE_PREFIX_DATA) { + store_data_long(emu, offset, emu->x86.R_EAX); + } else { + store_data_word(emu, offset, emu->x86.R_AX); + } +} + +/* + * REMARKS: + * Handles opcode 0xa4 + */ +static void +x86emuOp_movs_byte(struct x86emu *emu) +{ + uint8_t val; + uint32_t count; + int inc; + + if (ACCESS_FLAG(F_DF)) /* down */ + inc = -1; + else + inc = 1; + count = 1; + if (emu->x86.mode & (SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE)) { + /* dont care whether REPE or REPNE */ + /* move them until CX is ZERO. */ + count = emu->x86.R_CX; + emu->x86.R_CX = 0; + emu->x86.mode &= ~(SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE); + } + while (count--) { + val = fetch_data_byte(emu, emu->x86.R_SI); + store_byte(emu, emu->x86.R_ES, emu->x86.R_DI, val); + emu->x86.R_SI += inc; + emu->x86.R_DI += inc; + } +} + +/* + * REMARKS: + * Handles opcode 0xa5 + */ +static void +x86emuOp_movs_word(struct x86emu *emu) +{ + uint32_t val; + int inc; + uint32_t count; + + if (emu->x86.mode & SYSMODE_PREFIX_DATA) + inc = 4; + else + inc = 2; + + if (ACCESS_FLAG(F_DF)) /* down */ + inc = -inc; + + count = 1; + if (emu->x86.mode & (SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE)) { + /* dont care whether REPE or REPNE */ + /* move them until CX is ZERO. */ + count = emu->x86.R_CX; + emu->x86.R_CX = 0; + emu->x86.mode &= ~(SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE); + } + while (count--) { + if (emu->x86.mode & SYSMODE_PREFIX_DATA) { + val = fetch_data_long(emu, emu->x86.R_SI); + store_long(emu, emu->x86.R_ES, emu->x86.R_DI, val); + } else { + val = fetch_data_word(emu, emu->x86.R_SI); + store_word(emu, emu->x86.R_ES, emu->x86.R_DI, (uint16_t) val); + } + emu->x86.R_SI += inc; + emu->x86.R_DI += inc; + } +} + +/* + * REMARKS: + * Handles opcode 0xa6 + */ +static void +x86emuOp_cmps_byte(struct x86emu *emu) +{ + int8_t val1, val2; + int inc; + + if (ACCESS_FLAG(F_DF)) /* down */ + inc = -1; + else + inc = 1; + + if (emu->x86.mode & SYSMODE_PREFIX_REPE) { + /* REPE */ + /* move them until CX is ZERO. */ + while (emu->x86.R_CX != 0) { + val1 = fetch_data_byte(emu, emu->x86.R_SI); + val2 = fetch_byte(emu, emu->x86.R_ES, emu->x86.R_DI); + cmp_byte(emu, val1, val2); + emu->x86.R_CX -= 1; + emu->x86.R_SI += inc; + emu->x86.R_DI += inc; + if (ACCESS_FLAG(F_ZF) == 0) + break; + } + emu->x86.mode &= ~SYSMODE_PREFIX_REPE; + } else if (emu->x86.mode & SYSMODE_PREFIX_REPNE) { + /* REPNE */ + /* move them until CX is ZERO. */ + while (emu->x86.R_CX != 0) { + val1 = fetch_data_byte(emu, emu->x86.R_SI); + val2 = fetch_byte(emu, emu->x86.R_ES, emu->x86.R_DI); + cmp_byte(emu, val1, val2); + emu->x86.R_CX -= 1; + emu->x86.R_SI += inc; + emu->x86.R_DI += inc; + if (ACCESS_FLAG(F_ZF)) + break; /* zero flag set means equal */ + } + emu->x86.mode &= ~SYSMODE_PREFIX_REPNE; + } else { + val1 = fetch_data_byte(emu, emu->x86.R_SI); + val2 = fetch_byte(emu, emu->x86.R_ES, emu->x86.R_DI); + cmp_byte(emu, val1, val2); + emu->x86.R_SI += inc; + emu->x86.R_DI += inc; + } +} + +/* + * REMARKS: + * Handles opcode 0xa7 + */ +static void +x86emuOp_cmps_word(struct x86emu *emu) +{ + uint32_t val1, val2; + int inc; + + if (emu->x86.mode & SYSMODE_PREFIX_DATA) { + if (ACCESS_FLAG(F_DF)) /* down */ + inc = -4; + else + inc = 4; + } else { + if (ACCESS_FLAG(F_DF)) /* down */ + inc = -2; + else + inc = 2; + } + if (emu->x86.mode & SYSMODE_PREFIX_REPE) { + /* REPE */ + /* move them until CX is ZERO. */ + while (emu->x86.R_CX != 0) { + if (emu->x86.mode & SYSMODE_PREFIX_DATA) { + val1 = fetch_data_long(emu, emu->x86.R_SI); + val2 = fetch_long(emu, emu->x86.R_ES, emu->x86.R_DI); + cmp_long(emu, val1, val2); + } else { + val1 = fetch_data_word(emu, emu->x86.R_SI); + val2 = fetch_word(emu, emu->x86.R_ES, emu->x86.R_DI); + cmp_word(emu, (uint16_t) val1, (uint16_t) val2); + } + emu->x86.R_CX -= 1; + emu->x86.R_SI += inc; + emu->x86.R_DI += inc; + if (ACCESS_FLAG(F_ZF) == 0) + break; + } + emu->x86.mode &= ~SYSMODE_PREFIX_REPE; + } else if (emu->x86.mode & SYSMODE_PREFIX_REPNE) { + /* REPNE */ + /* move them until CX is ZERO. */ + while (emu->x86.R_CX != 0) { + if (emu->x86.mode & SYSMODE_PREFIX_DATA) { + val1 = fetch_data_long(emu, emu->x86.R_SI); + val2 = fetch_long(emu, emu->x86.R_ES, emu->x86.R_DI); + cmp_long(emu, val1, val2); + } else { + val1 = fetch_data_word(emu, emu->x86.R_SI); + val2 = fetch_word(emu, emu->x86.R_ES, emu->x86.R_DI); + cmp_word(emu, (uint16_t) val1, (uint16_t) val2); + } + emu->x86.R_CX -= 1; + emu->x86.R_SI += inc; + emu->x86.R_DI += inc; + if (ACCESS_FLAG(F_ZF)) + break; /* zero flag set means equal */ + } + emu->x86.mode &= ~SYSMODE_PREFIX_REPNE; + } else { + if (emu->x86.mode & SYSMODE_PREFIX_DATA) { + val1 = fetch_data_long(emu, emu->x86.R_SI); + val2 = fetch_long(emu, emu->x86.R_ES, emu->x86.R_DI); + cmp_long(emu, val1, val2); + } else { + val1 = fetch_data_word(emu, emu->x86.R_SI); + val2 = fetch_word(emu, emu->x86.R_ES, emu->x86.R_DI); + cmp_word(emu, (uint16_t) val1, (uint16_t) val2); + } + emu->x86.R_SI += inc; + emu->x86.R_DI += inc; + } +} + +/* + * REMARKS: + * Handles opcode 0xa9 + */ +static void +x86emuOp_test_AX_IMM(struct x86emu *emu) +{ + if (emu->x86.mode & SYSMODE_PREFIX_DATA) { + test_long(emu, emu->x86.R_EAX, fetch_long_imm(emu)); + } else { + test_word(emu, emu->x86.R_AX, fetch_word_imm(emu)); + } +} + +/* + * REMARKS: + * Handles opcode 0xaa + */ +static void +x86emuOp_stos_byte(struct x86emu *emu) +{ + int inc; + + if (ACCESS_FLAG(F_DF)) /* down */ + inc = -1; + else + inc = 1; + if (emu->x86.mode & (SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE)) { + /* dont care whether REPE or REPNE */ + /* move them until CX is ZERO. */ + while (emu->x86.R_CX != 0) { + store_byte(emu, emu->x86.R_ES, emu->x86.R_DI, emu->x86.R_AL); + emu->x86.R_CX -= 1; + emu->x86.R_DI += inc; + } + emu->x86.mode &= ~(SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE); + } else { + store_byte(emu, emu->x86.R_ES, emu->x86.R_DI, emu->x86.R_AL); + emu->x86.R_DI += inc; + } +} + +/* + * REMARKS: + * Handles opcode 0xab + */ +static void +x86emuOp_stos_word(struct x86emu *emu) +{ + int inc; + uint32_t count; + + if (emu->x86.mode & SYSMODE_PREFIX_DATA) + inc = 4; + else + inc = 2; + + if (ACCESS_FLAG(F_DF)) /* down */ + inc = -inc; + + count = 1; + if (emu->x86.mode & (SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE)) { + /* dont care whether REPE or REPNE */ + /* move them until CX is ZERO. */ + count = emu->x86.R_CX; + emu->x86.R_CX = 0; + emu->x86.mode &= ~(SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE); + } + while (count--) { + if (emu->x86.mode & SYSMODE_PREFIX_DATA) { + store_long(emu, emu->x86.R_ES, emu->x86.R_DI, emu->x86.R_EAX); + } else { + store_word(emu, emu->x86.R_ES, emu->x86.R_DI, emu->x86.R_AX); + } + emu->x86.R_DI += inc; + } +} + +/* + * REMARKS: + * Handles opcode 0xac + */ +static void +x86emuOp_lods_byte(struct x86emu *emu) +{ + int inc; + + if (ACCESS_FLAG(F_DF)) /* down */ + inc = -1; + else + inc = 1; + if (emu->x86.mode & (SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE)) { + /* dont care whether REPE or REPNE */ + /* move them until CX is ZERO. */ + while (emu->x86.R_CX != 0) { + emu->x86.R_AL = fetch_data_byte(emu, emu->x86.R_SI); + emu->x86.R_CX -= 1; + emu->x86.R_SI += inc; + } + emu->x86.mode &= ~(SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE); + } else { + emu->x86.R_AL = fetch_data_byte(emu, emu->x86.R_SI); + emu->x86.R_SI += inc; + } +} + +/* + * REMARKS: + * Handles opcode 0xad + */ +static void +x86emuOp_lods_word(struct x86emu *emu) +{ + int inc; + uint32_t count; + + if (emu->x86.mode & SYSMODE_PREFIX_DATA) + inc = 4; + else + inc = 2; + + if (ACCESS_FLAG(F_DF)) /* down */ + inc = -inc; + + count = 1; + if (emu->x86.mode & (SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE)) { + /* dont care whether REPE or REPNE */ + /* move them until CX is ZERO. */ + count = emu->x86.R_CX; + emu->x86.R_CX = 0; + emu->x86.mode &= ~(SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE); + } + while (count--) { + if (emu->x86.mode & SYSMODE_PREFIX_DATA) { + emu->x86.R_EAX = fetch_data_long(emu, emu->x86.R_SI); + } else { + emu->x86.R_AX = fetch_data_word(emu, emu->x86.R_SI); + } + emu->x86.R_SI += inc; + } +} + +/* + * REMARKS: + * Handles opcode 0xae + */ +static void +x86emuOp_scas_byte(struct x86emu *emu) +{ + int8_t val2; + int inc; + + if (ACCESS_FLAG(F_DF)) /* down */ + inc = -1; + else + inc = 1; + if (emu->x86.mode & SYSMODE_PREFIX_REPE) { + /* REPE */ + /* move them until CX is ZERO. */ + while (emu->x86.R_CX != 0) { + val2 = fetch_byte(emu, emu->x86.R_ES, emu->x86.R_DI); + cmp_byte(emu, emu->x86.R_AL, val2); + emu->x86.R_CX -= 1; + emu->x86.R_DI += inc; + if (ACCESS_FLAG(F_ZF) == 0) + break; + } + emu->x86.mode &= ~SYSMODE_PREFIX_REPE; + } else if (emu->x86.mode & SYSMODE_PREFIX_REPNE) { + /* REPNE */ + /* move them until CX is ZERO. */ + while (emu->x86.R_CX != 0) { + val2 = fetch_byte(emu, emu->x86.R_ES, emu->x86.R_DI); + cmp_byte(emu, emu->x86.R_AL, val2); + emu->x86.R_CX -= 1; + emu->x86.R_DI += inc; + if (ACCESS_FLAG(F_ZF)) + break; /* zero flag set means equal */ + } + emu->x86.mode &= ~SYSMODE_PREFIX_REPNE; + } else { + val2 = fetch_byte(emu, emu->x86.R_ES, emu->x86.R_DI); + cmp_byte(emu, emu->x86.R_AL, val2); + emu->x86.R_DI += inc; + } +} + +/* + * REMARKS: + * Handles opcode 0xaf + */ +static void +x86emuOp_scas_word(struct x86emu *emu) +{ + int inc; + uint32_t val; + + if (emu->x86.mode & SYSMODE_PREFIX_DATA) + inc = 4; + else + inc = 2; + + if (ACCESS_FLAG(F_DF)) /* down */ + inc = -inc; + + if (emu->x86.mode & SYSMODE_PREFIX_REPE) { + /* REPE */ + /* move them until CX is ZERO. */ + while (emu->x86.R_CX != 0) { + if (emu->x86.mode & SYSMODE_PREFIX_DATA) { + val = fetch_long(emu, emu->x86.R_ES, emu->x86.R_DI); + cmp_long(emu, emu->x86.R_EAX, val); + } else { + val = fetch_word(emu, emu->x86.R_ES, emu->x86.R_DI); + cmp_word(emu, emu->x86.R_AX, (uint16_t) val); + } + emu->x86.R_CX -= 1; + emu->x86.R_DI += inc; + if (ACCESS_FLAG(F_ZF) == 0) + break; + } + emu->x86.mode &= ~SYSMODE_PREFIX_REPE; + } else if (emu->x86.mode & SYSMODE_PREFIX_REPNE) { + /* REPNE */ + /* move them until CX is ZERO. */ + while (emu->x86.R_CX != 0) { + if (emu->x86.mode & SYSMODE_PREFIX_DATA) { + val = fetch_long(emu, emu->x86.R_ES, emu->x86.R_DI); + cmp_long(emu, emu->x86.R_EAX, val); + } else { + val = fetch_word(emu, emu->x86.R_ES, emu->x86.R_DI); + cmp_word(emu, emu->x86.R_AX, (uint16_t) val); + } + emu->x86.R_CX -= 1; + emu->x86.R_DI += inc; + if (ACCESS_FLAG(F_ZF)) + break; /* zero flag set means equal */ + } + emu->x86.mode &= ~SYSMODE_PREFIX_REPNE; + } else { + if (emu->x86.mode & SYSMODE_PREFIX_DATA) { + val = fetch_long(emu, emu->x86.R_ES, emu->x86.R_DI); + cmp_long(emu, emu->x86.R_EAX, val); + } else { + val = fetch_word(emu, emu->x86.R_ES, emu->x86.R_DI); + cmp_word(emu, emu->x86.R_AX, (uint16_t) val); + } + emu->x86.R_DI += inc; + } +} + +/* + * REMARKS: + * Handles opcode 0xb8 + */ +static void +x86emuOp_mov_word_AX_IMM(struct x86emu *emu) +{ + if (emu->x86.mode & SYSMODE_PREFIX_DATA) + emu->x86.R_EAX = fetch_long_imm(emu); + else + emu->x86.R_AX = fetch_word_imm(emu); +} + +/* + * REMARKS: + * Handles opcode 0xb9 + */ +static void +x86emuOp_mov_word_CX_IMM(struct x86emu *emu) +{ + if (emu->x86.mode & SYSMODE_PREFIX_DATA) + emu->x86.R_ECX = fetch_long_imm(emu); + else + emu->x86.R_CX = fetch_word_imm(emu); +} + +/* + * REMARKS: + * Handles opcode 0xba + */ +static void +x86emuOp_mov_word_DX_IMM(struct x86emu *emu) +{ + if (emu->x86.mode & SYSMODE_PREFIX_DATA) + emu->x86.R_EDX = fetch_long_imm(emu); + else + emu->x86.R_DX = fetch_word_imm(emu); +} + +/* + * REMARKS: + * Handles opcode 0xbb + */ +static void +x86emuOp_mov_word_BX_IMM(struct x86emu *emu) +{ + if (emu->x86.mode & SYSMODE_PREFIX_DATA) + emu->x86.R_EBX = fetch_long_imm(emu); + else + emu->x86.R_BX = fetch_word_imm(emu); +} + +/* + * REMARKS: + * Handles opcode 0xbc + */ +static void +x86emuOp_mov_word_SP_IMM(struct x86emu *emu) +{ + if (emu->x86.mode & SYSMODE_PREFIX_DATA) + emu->x86.R_ESP = fetch_long_imm(emu); + else + emu->x86.R_SP = fetch_word_imm(emu); +} + +/* + * REMARKS: + * Handles opcode 0xbd + */ +static void +x86emuOp_mov_word_BP_IMM(struct x86emu *emu) +{ + if (emu->x86.mode & SYSMODE_PREFIX_DATA) + emu->x86.R_EBP = fetch_long_imm(emu); + else + emu->x86.R_BP = fetch_word_imm(emu); +} + +/* + * REMARKS: + * Handles opcode 0xbe + */ +static void +x86emuOp_mov_word_SI_IMM(struct x86emu *emu) +{ + if (emu->x86.mode & SYSMODE_PREFIX_DATA) + emu->x86.R_ESI = fetch_long_imm(emu); + else + emu->x86.R_SI = fetch_word_imm(emu); +} + +/* + * REMARKS: + * Handles opcode 0xbf + */ +static void +x86emuOp_mov_word_DI_IMM(struct x86emu *emu) +{ + if (emu->x86.mode & SYSMODE_PREFIX_DATA) + emu->x86.R_EDI = fetch_long_imm(emu); + else + emu->x86.R_DI = fetch_word_imm(emu); +} +/* used by opcodes c0, d0, and d2. */ +static +uint8_t(* const opcD0_byte_operation[]) (struct x86emu *, uint8_t d, uint8_t s) = +{ + rol_byte, + ror_byte, + rcl_byte, + rcr_byte, + shl_byte, + shr_byte, + shl_byte, /* sal_byte === shl_byte by definition */ + sar_byte, +}; + +/* + * REMARKS: + * Handles opcode 0xc0 + */ +static void +x86emuOp_opcC0_byte_RM_MEM(struct x86emu *emu) +{ + uint8_t destval, amt; + + /* + * Yet another weirdo special case instruction format. Part of + * the opcode held below in "RH". Doubly nested case would + * result, except that the decoded instruction + */ + fetch_decode_modrm(emu); + /* know operation, decode the mod byte to find the addressing mode. */ + destval = decode_and_fetch_byte_imm8(emu, &amt); + destval = (*opcD0_byte_operation[emu->cur_rh]) (emu, destval, amt); + write_back_byte(emu, destval); +} +/* used by opcodes c1, d1, and d3. */ +static +uint16_t(* const opcD1_word_operation[]) (struct x86emu *, uint16_t s, uint8_t d) = +{ + rol_word, + ror_word, + rcl_word, + rcr_word, + shl_word, + shr_word, + shl_word, /* sal_byte === shl_byte by definition */ + sar_word, +}; +/* used by opcodes c1, d1, and d3. */ +static +uint32_t(* const opcD1_long_operation[]) (struct x86emu *, uint32_t s, uint8_t d) = +{ + rol_long, + ror_long, + rcl_long, + rcr_long, + shl_long, + shr_long, + shl_long, /* sal_byte === shl_byte by definition */ + sar_long, +}; + +/* + * REMARKS: + * Handles opcode 0xc1 + */ +static void +x86emuOp_opcC1_word_RM_MEM(struct x86emu *emu) +{ + uint8_t amt; + + /* + * Yet another weirdo special case instruction format. Part of + * the opcode held below in "RH". Doubly nested case would + * result, except that the decoded instruction + */ + fetch_decode_modrm(emu); + if (emu->x86.mode & SYSMODE_PREFIX_DATA) { + uint32_t destval; + + destval = decode_and_fetch_long_imm8(emu, &amt); + destval = (*opcD1_long_operation[emu->cur_rh]) (emu, destval, amt); + write_back_long(emu, destval); + } else { + uint16_t destval; + + destval = decode_and_fetch_word_imm8(emu, &amt); + destval = (*opcD1_word_operation[emu->cur_rh]) (emu, destval, amt); + write_back_word(emu, destval); + } +} + +/* + * REMARKS: + * Handles opcode 0xc2 + */ +static void +x86emuOp_ret_near_IMM(struct x86emu *emu) +{ + uint16_t imm; + + imm = fetch_word_imm(emu); + emu->x86.R_IP = pop_word(emu); + emu->x86.R_SP += imm; +} + +/* + * REMARKS: + * Handles opcode 0xc6 + */ +static void +x86emuOp_mov_byte_RM_IMM(struct x86emu *emu) +{ + uint8_t *destreg; + uint32_t destoffset; + uint8_t imm; + + fetch_decode_modrm(emu); + if (emu->cur_rh != 0) + x86emu_halt_sys(emu); + if (emu->cur_mod != 3) { + destoffset = decode_rl_address(emu); + imm = fetch_byte_imm(emu); + store_data_byte(emu, destoffset, imm); + } else { + destreg = decode_rl_byte_register(emu); + imm = fetch_byte_imm(emu); + *destreg = imm; + } +} + +/* + * REMARKS: + * Handles opcode 0xc7 + */ +static void +x86emuOp32_mov_word_RM_IMM(struct x86emu *emu) +{ + uint32_t destoffset; + uint32_t imm, *destreg; + + fetch_decode_modrm(emu); + if (emu->cur_rh != 0) + x86emu_halt_sys(emu); + + if (emu->cur_mod != 3) { + destoffset = decode_rl_address(emu); + imm = fetch_long_imm(emu); + store_data_long(emu, destoffset, imm); + } else { + destreg = decode_rl_long_register(emu); + imm = fetch_long_imm(emu); + *destreg = imm; + } +} + +static void +x86emuOp16_mov_word_RM_IMM(struct x86emu *emu) +{ + uint32_t destoffset; + uint16_t imm, *destreg; + + fetch_decode_modrm(emu); + if (emu->cur_rh != 0) + x86emu_halt_sys(emu); + + if (emu->cur_mod != 3) { + destoffset = decode_rl_address(emu); + imm = fetch_word_imm(emu); + store_data_word(emu, destoffset, imm); + } else { + destreg = decode_rl_word_register(emu); + imm = fetch_word_imm(emu); + *destreg = imm; + } +} + +static void +x86emuOp_mov_word_RM_IMM(struct x86emu *emu) +{ + if (emu->x86.mode & SYSMODE_PREFIX_DATA) + x86emuOp32_mov_word_RM_IMM(emu); + else + x86emuOp16_mov_word_RM_IMM(emu); +} + +/* + * REMARKS: + * Handles opcode 0xc8 + */ +static void +x86emuOp_enter(struct x86emu *emu) +{ + uint16_t local, frame_pointer; + uint8_t nesting; + int i; + + local = fetch_word_imm(emu); + nesting = fetch_byte_imm(emu); + push_word(emu, emu->x86.R_BP); + frame_pointer = emu->x86.R_SP; + if (nesting > 0) { + for (i = 1; i < nesting; i++) { + emu->x86.R_BP -= 2; + push_word(emu, fetch_word(emu, emu->x86.R_SS, emu->x86.R_BP)); + } + push_word(emu, frame_pointer); + } + emu->x86.R_BP = frame_pointer; + emu->x86.R_SP = (uint16_t) (emu->x86.R_SP - local); +} + +/* + * REMARKS: + * Handles opcode 0xc9 + */ +static void +x86emuOp_leave(struct x86emu *emu) +{ + emu->x86.R_SP = emu->x86.R_BP; + emu->x86.R_BP = pop_word(emu); +} + +/* + * REMARKS: + * Handles opcode 0xca + */ +static void +x86emuOp_ret_far_IMM(struct x86emu *emu) +{ + uint16_t imm; + + imm = fetch_word_imm(emu); + emu->x86.R_IP = pop_word(emu); + emu->x86.R_CS = pop_word(emu); + emu->x86.R_SP += imm; +} + +/* + * REMARKS: + * Handles opcode 0xcb + */ +static void +x86emuOp_ret_far(struct x86emu *emu) +{ + emu->x86.R_IP = pop_word(emu); + emu->x86.R_CS = pop_word(emu); +} + +/* + * REMARKS: + * Handles opcode 0xcc + */ +static void +x86emuOp_int3(struct x86emu *emu) +{ + x86emu_intr_dispatch(emu, 3); +} + +/* + * REMARKS: + * Handles opcode 0xcd + */ +static void +x86emuOp_int_IMM(struct x86emu *emu) +{ + uint8_t intnum; + + intnum = fetch_byte_imm(emu); + x86emu_intr_dispatch(emu, intnum); +} + +/* + * REMARKS: + * Handles opcode 0xce + */ +static void +x86emuOp_into(struct x86emu *emu) +{ + if (ACCESS_FLAG(F_OF)) + x86emu_intr_dispatch(emu, 4); +} + +/* + * REMARKS: + * Handles opcode 0xcf + */ +static void +x86emuOp_iret(struct x86emu *emu) +{ + emu->x86.R_IP = pop_word(emu); + emu->x86.R_CS = pop_word(emu); + emu->x86.R_FLG = pop_word(emu); +} + +/* + * REMARKS: + * Handles opcode 0xd0 + */ +static void +x86emuOp_opcD0_byte_RM_1(struct x86emu *emu) +{ + uint8_t destval; + + fetch_decode_modrm(emu); + destval = decode_and_fetch_byte(emu); + destval = (*opcD0_byte_operation[emu->cur_rh]) (emu, destval, 1); + write_back_byte(emu, destval); +} + +/* + * REMARKS: + * Handles opcode 0xd1 + */ +static void +x86emuOp_opcD1_word_RM_1(struct x86emu *emu) +{ + if (emu->x86.mode & SYSMODE_PREFIX_DATA) { + uint32_t destval; + + fetch_decode_modrm(emu); + destval = decode_and_fetch_long(emu); + destval = (*opcD1_long_operation[emu->cur_rh]) (emu, destval, 1); + write_back_long(emu, destval); + } else { + uint16_t destval; + + fetch_decode_modrm(emu); + destval = decode_and_fetch_word(emu); + destval = (*opcD1_word_operation[emu->cur_rh]) (emu, destval, 1); + write_back_word(emu, destval); + } +} + +/* + * REMARKS: + * Handles opcode 0xd2 + */ +static void +x86emuOp_opcD2_byte_RM_CL(struct x86emu *emu) +{ + uint8_t destval; + + fetch_decode_modrm(emu); + destval = decode_and_fetch_byte(emu); + destval = (*opcD0_byte_operation[emu->cur_rh]) (emu, destval, emu->x86.R_CL); + write_back_byte(emu, destval); +} + +/* + * REMARKS: + * Handles opcode 0xd3 + */ +static void +x86emuOp_opcD3_word_RM_CL(struct x86emu *emu) +{ + if (emu->x86.mode & SYSMODE_PREFIX_DATA) { + uint32_t destval; + + fetch_decode_modrm(emu); + destval = decode_and_fetch_long(emu); + destval = (*opcD1_long_operation[emu->cur_rh]) (emu, destval, emu->x86.R_CL); + write_back_long(emu, destval); + } else { + uint16_t destval; + + fetch_decode_modrm(emu); + destval = decode_and_fetch_word(emu); + destval = (*opcD1_word_operation[emu->cur_rh]) (emu, destval, emu->x86.R_CL); + write_back_word(emu, destval); + } +} + +/* + * REMARKS: + * Handles opcode 0xd4 + */ +static void +x86emuOp_aam(struct x86emu *emu) +{ + uint8_t a; + + a = fetch_byte_imm(emu); /* this is a stupid encoding. */ + if (a != 10) { + /* fix: add base decoding aam_word(uint8_t val, int base a) */ + x86emu_halt_sys(emu); + } + /* note the type change here --- returning AL and AH in AX. */ + emu->x86.R_AX = aam_word(emu, emu->x86.R_AL); +} + +/* + * REMARKS: + * Handles opcode 0xd5 + */ +static void +x86emuOp_aad(struct x86emu *emu) +{ + uint8_t a; + + a = fetch_byte_imm(emu); + if (a != 10) { + /* fix: add base decoding aad_word(uint16_t val, int base a) */ + x86emu_halt_sys(emu); + } + emu->x86.R_AX = aad_word(emu, emu->x86.R_AX); +} +/* opcode 0xd6 ILLEGAL OPCODE */ + + +/* + * REMARKS: + * Handles opcode 0xd7 + */ +static void +x86emuOp_xlat(struct x86emu *emu) +{ + uint16_t addr; + + addr = (uint16_t) (emu->x86.R_BX + (uint8_t) emu->x86.R_AL); + emu->x86.R_AL = fetch_data_byte(emu, addr); +} + +/* opcode=0xd8 */ +static void +x86emuOp_esc_coprocess_d8(struct x86emu *emu) +{ +} +/* opcode=0xd9 */ +static void +x86emuOp_esc_coprocess_d9(struct x86emu *emu) +{ + fetch_decode_modrm(emu); + if (emu->cur_mod != 3) + decode_rl_address(emu); +} +/* opcode=0xda */ +static void +x86emuOp_esc_coprocess_da(struct x86emu *emu) +{ + fetch_decode_modrm(emu); + if (emu->cur_mod != 3) + decode_rl_address(emu); +} +/* opcode=0xdb */ +static void +x86emuOp_esc_coprocess_db(struct x86emu *emu) +{ + fetch_decode_modrm(emu); + if (emu->cur_mod != 3) + decode_rl_address(emu); +} +/* opcode=0xdc */ +static void +x86emuOp_esc_coprocess_dc(struct x86emu *emu) +{ + fetch_decode_modrm(emu); + if (emu->cur_mod != 3) + decode_rl_address(emu); +} +/* opcode=0xdd */ +static void +x86emuOp_esc_coprocess_dd(struct x86emu *emu) +{ + fetch_decode_modrm(emu); + if (emu->cur_mod != 3) + decode_rl_address(emu); +} +/* opcode=0xde */ +static void +x86emuOp_esc_coprocess_de(struct x86emu *emu) +{ + fetch_decode_modrm(emu); + if (emu->cur_mod != 3) + decode_rl_address(emu); +} +/* opcode=0xdf */ +static void +x86emuOp_esc_coprocess_df(struct x86emu *emu) +{ + fetch_decode_modrm(emu); + if (emu->cur_mod != 3) + decode_rl_address(emu); +} + + +/* + * REMARKS: + * Handles opcode 0xe0 + */ +static void +x86emuOp_loopne(struct x86emu *emu) +{ + int16_t ip; + + ip = (int8_t) fetch_byte_imm(emu); + ip += (int16_t) emu->x86.R_IP; + emu->x86.R_CX -= 1; + if (emu->x86.R_CX != 0 && !ACCESS_FLAG(F_ZF)) /* CX != 0 and !ZF */ + emu->x86.R_IP = ip; +} + +/* + * REMARKS: + * Handles opcode 0xe1 + */ +static void +x86emuOp_loope(struct x86emu *emu) +{ + int16_t ip; + + ip = (int8_t) fetch_byte_imm(emu); + ip += (int16_t) emu->x86.R_IP; + emu->x86.R_CX -= 1; + if (emu->x86.R_CX != 0 && ACCESS_FLAG(F_ZF)) /* CX != 0 and ZF */ + emu->x86.R_IP = ip; +} + +/* + * REMARKS: + * Handles opcode 0xe2 + */ +static void +x86emuOp_loop(struct x86emu *emu) +{ + int16_t ip; + + ip = (int8_t) fetch_byte_imm(emu); + ip += (int16_t) emu->x86.R_IP; + emu->x86.R_CX -= 1; + if (emu->x86.R_CX != 0) + emu->x86.R_IP = ip; +} + +/* + * REMARKS: + * Handles opcode 0xe3 + */ +static void +x86emuOp_jcxz(struct x86emu *emu) +{ + uint16_t target; + int8_t offset; + + /* jump to byte offset if overflow flag is set */ + offset = (int8_t) fetch_byte_imm(emu); + target = (uint16_t) (emu->x86.R_IP + offset); + if (emu->x86.R_CX == 0) + emu->x86.R_IP = target; +} + +/* + * REMARKS: + * Handles opcode 0xe4 + */ +static void +x86emuOp_in_byte_AL_IMM(struct x86emu *emu) +{ + uint8_t port; + + port = (uint8_t) fetch_byte_imm(emu); + emu->x86.R_AL = (*emu->emu_inb) (emu, port); +} + +/* + * REMARKS: + * Handles opcode 0xe5 + */ +static void +x86emuOp_in_word_AX_IMM(struct x86emu *emu) +{ + uint8_t port; + + port = (uint8_t) fetch_byte_imm(emu); + if (emu->x86.mode & SYSMODE_PREFIX_DATA) { + emu->x86.R_EAX = (*emu->emu_inl) (emu, port); + } else { + emu->x86.R_AX = (*emu->emu_inw) (emu, port); + } +} + +/* + * REMARKS: + * Handles opcode 0xe6 + */ +static void +x86emuOp_out_byte_IMM_AL(struct x86emu *emu) +{ + uint8_t port; + + port = (uint8_t) fetch_byte_imm(emu); + (*emu->emu_outb) (emu, port, emu->x86.R_AL); +} + +/* + * REMARKS: + * Handles opcode 0xe7 + */ +static void +x86emuOp_out_word_IMM_AX(struct x86emu *emu) +{ + uint8_t port; + + port = (uint8_t) fetch_byte_imm(emu); + if (emu->x86.mode & SYSMODE_PREFIX_DATA) { + (*emu->emu_outl) (emu, port, emu->x86.R_EAX); + } else { + (*emu->emu_outw) (emu, port, emu->x86.R_AX); + } +} + +/* + * REMARKS: + * Handles opcode 0xe8 + */ +static void +x86emuOp_call_near_IMM(struct x86emu *emu) +{ + int16_t ip; + + ip = (int16_t) fetch_word_imm(emu); + ip += (int16_t) emu->x86.R_IP; /* CHECK SIGN */ + push_word(emu, emu->x86.R_IP); + emu->x86.R_IP = ip; +} + +/* + * REMARKS: + * Handles opcode 0xe9 + */ +static void +x86emuOp_jump_near_IMM(struct x86emu *emu) +{ + int ip; + + ip = (int16_t) fetch_word_imm(emu); + ip += (int16_t) emu->x86.R_IP; + emu->x86.R_IP = (uint16_t) ip; +} + +/* + * REMARKS: + * Handles opcode 0xea + */ +static void +x86emuOp_jump_far_IMM(struct x86emu *emu) +{ + uint16_t cs, ip; + + ip = fetch_word_imm(emu); + cs = fetch_word_imm(emu); + emu->x86.R_IP = ip; + emu->x86.R_CS = cs; +} + +/* + * REMARKS: + * Handles opcode 0xeb + */ +static void +x86emuOp_jump_byte_IMM(struct x86emu *emu) +{ + uint16_t target; + int8_t offset; + + offset = (int8_t) fetch_byte_imm(emu); + target = (uint16_t) (emu->x86.R_IP + offset); + emu->x86.R_IP = target; +} + +/* + * REMARKS: + * Handles opcode 0xec + */ +static void +x86emuOp_in_byte_AL_DX(struct x86emu *emu) +{ + emu->x86.R_AL = (*emu->emu_inb) (emu, emu->x86.R_DX); +} + +/* + * REMARKS: + * Handles opcode 0xed + */ +static void +x86emuOp_in_word_AX_DX(struct x86emu *emu) +{ + if (emu->x86.mode & SYSMODE_PREFIX_DATA) { + emu->x86.R_EAX = (*emu->emu_inl) (emu, emu->x86.R_DX); + } else { + emu->x86.R_AX = (*emu->emu_inw) (emu, emu->x86.R_DX); + } +} + +/* + * REMARKS: + * Handles opcode 0xee + */ +static void +x86emuOp_out_byte_DX_AL(struct x86emu *emu) +{ + (*emu->emu_outb) (emu, emu->x86.R_DX, emu->x86.R_AL); +} + +/* + * REMARKS: + * Handles opcode 0xef + */ +static void +x86emuOp_out_word_DX_AX(struct x86emu *emu) +{ + if (emu->x86.mode & SYSMODE_PREFIX_DATA) { + (*emu->emu_outl) (emu, emu->x86.R_DX, emu->x86.R_EAX); + } else { + (*emu->emu_outw) (emu, emu->x86.R_DX, emu->x86.R_AX); + } +} + +/* + * REMARKS: + * Handles opcode 0xf0 + */ +static void +x86emuOp_lock(struct x86emu *emu) +{ +} +/*opcode 0xf1 ILLEGAL OPERATION */ + + +/* + * REMARKS: + * Handles opcode 0xf5 + */ +static void +x86emuOp_cmc(struct x86emu *emu) +{ + if (ACCESS_FLAG(F_CF)) + CLEAR_FLAG(F_CF); + else + SET_FLAG(F_CF); +} + +/* + * REMARKS: + * Handles opcode 0xf6 + */ +static void +x86emuOp_opcF6_byte_RM(struct x86emu *emu) +{ + uint8_t destval, srcval; + + /* long, drawn out code follows. Double switch for a total of 32 + * cases. */ + fetch_decode_modrm(emu); + if (emu->cur_rh == 1) + x86emu_halt_sys(emu); + + if (emu->cur_rh == 0) { + destval = decode_and_fetch_byte_imm8(emu, &srcval); + test_byte(emu, destval, srcval); + return; + } + destval = decode_and_fetch_byte(emu); + switch (emu->cur_rh) { + case 2: + destval = ~destval; + write_back_byte(emu, destval); + break; + case 3: + destval = neg_byte(emu, destval); + write_back_byte(emu, destval); + break; + case 4: + mul_byte(emu, destval); + break; + case 5: + imul_byte(emu, destval); + break; + case 6: + div_byte(emu, destval); + break; + case 7: + idiv_byte(emu, destval); + break; + } +} + +/* + * REMARKS: + * Handles opcode 0xf7 + */ +static void +x86emuOp32_opcF7_word_RM(struct x86emu *emu) +{ + uint32_t destval, srcval; + + /* long, drawn out code follows. Double switch for a total of 32 + * cases. */ + fetch_decode_modrm(emu); + if (emu->cur_rh == 1) + x86emu_halt_sys(emu); + + if (emu->cur_rh == 0) { + if (emu->cur_mod != 3) { + uint32_t destoffset; + + destoffset = decode_rl_address(emu); + srcval = fetch_long_imm(emu); + destval = fetch_data_long(emu, destoffset); + } else { + srcval = fetch_long_imm(emu); + destval = *decode_rl_long_register(emu); + } + test_long(emu, destval, srcval); + return; + } + destval = decode_and_fetch_long(emu); + switch (emu->cur_rh) { + case 2: + destval = ~destval; + write_back_long(emu, destval); + break; + case 3: + destval = neg_long(emu, destval); + write_back_long(emu, destval); + break; + case 4: + mul_long(emu, destval); + break; + case 5: + imul_long(emu, destval); + break; + case 6: + div_long(emu, destval); + break; + case 7: + idiv_long(emu, destval); + break; + } +} +static void +x86emuOp16_opcF7_word_RM(struct x86emu *emu) +{ + uint16_t destval, srcval; + + /* long, drawn out code follows. Double switch for a total of 32 + * cases. */ + fetch_decode_modrm(emu); + if (emu->cur_rh == 1) + x86emu_halt_sys(emu); + + if (emu->cur_rh == 0) { + if (emu->cur_mod != 3) { + uint32_t destoffset; + + destoffset = decode_rl_address(emu); + srcval = fetch_word_imm(emu); + destval = fetch_data_word(emu, destoffset); + } else { + srcval = fetch_word_imm(emu); + destval = *decode_rl_word_register(emu); + } + test_word(emu, destval, srcval); + return; + } + destval = decode_and_fetch_word(emu); + switch (emu->cur_rh) { + case 2: + destval = ~destval; + write_back_word(emu, destval); + break; + case 3: + destval = neg_word(emu, destval); + write_back_word(emu, destval); + break; + case 4: + mul_word(emu, destval); + break; + case 5: + imul_word(emu, destval); + break; + case 6: + div_word(emu, destval); + break; + case 7: + idiv_word(emu, destval); + break; + } +} +static void +x86emuOp_opcF7_word_RM(struct x86emu *emu) +{ + if (emu->x86.mode & SYSMODE_PREFIX_DATA) + x86emuOp32_opcF7_word_RM(emu); + else + x86emuOp16_opcF7_word_RM(emu); +} + +/* + * REMARKS: + * Handles opcode 0xfe + */ +static void +x86emuOp_opcFE_byte_RM(struct x86emu *emu) +{ + uint8_t destval; + uint32_t destoffset; + uint8_t *destreg; + + /* Yet another special case instruction. */ + fetch_decode_modrm(emu); + if (emu->cur_mod != 3) { + destoffset = decode_rl_address(emu); + switch (emu->cur_rh) { + case 0: /* inc word ptr ... */ + destval = fetch_data_byte(emu, destoffset); + destval = inc_byte(emu, destval); + store_data_byte(emu, destoffset, destval); + break; + case 1: /* dec word ptr ... */ + destval = fetch_data_byte(emu, destoffset); + destval = dec_byte(emu, destval); + store_data_byte(emu, destoffset, destval); + break; + } + } else { + destreg = decode_rl_byte_register(emu); + switch (emu->cur_rh) { + case 0: + *destreg = inc_byte(emu, *destreg); + break; + case 1: + *destreg = dec_byte(emu, *destreg); + break; + } + } +} + +/* + * REMARKS: + * Handles opcode 0xff + */ +static void +x86emuOp32_opcFF_word_RM(struct x86emu *emu) +{ + uint32_t destoffset = 0; + uint32_t destval, *destreg; + + if (emu->cur_mod != 3) { + destoffset = decode_rl_address(emu); + destval = fetch_data_long(emu, destoffset); + switch (emu->cur_rh) { + case 0: /* inc word ptr ... */ + destval = inc_long(emu, destval); + store_data_long(emu, destoffset, destval); + break; + case 1: /* dec word ptr ... */ + destval = dec_long(emu, destval); + store_data_long(emu, destoffset, destval); + break; + case 6: /* push word ptr ... */ + push_long(emu, destval); + break; + } + } else { + destreg = decode_rl_long_register(emu); + switch (emu->cur_rh) { + case 0: + *destreg = inc_long(emu, *destreg); + break; + case 1: + *destreg = dec_long(emu, *destreg); + break; + case 6: + push_long(emu, *destreg); + break; + } + } +} + +static void +x86emuOp16_opcFF_word_RM(struct x86emu *emu) +{ + uint32_t destoffset = 0; + uint16_t *destreg; + uint16_t destval; + + if (emu->cur_mod != 3) { + destoffset = decode_rl_address(emu); + destval = fetch_data_word(emu, destoffset); + switch (emu->cur_rh) { + case 0: + destval = inc_word(emu, destval); + store_data_word(emu, destoffset, destval); + break; + case 1: /* dec word ptr ... */ + destval = dec_word(emu, destval); + store_data_word(emu, destoffset, destval); + break; + case 6: /* push word ptr ... */ + push_word(emu, destval); + break; + } + } else { + destreg = decode_rl_word_register(emu); + switch (emu->cur_rh) { + case 0: + *destreg = inc_word(emu, *destreg); + break; + case 1: + *destreg = dec_word(emu, *destreg); + break; + case 6: + push_word(emu, *destreg); + break; + } + } +} + +static void +x86emuOp_opcFF_word_RM(struct x86emu *emu) +{ + uint32_t destoffset = 0; + uint16_t destval, destval2; + + /* Yet another special case instruction. */ + fetch_decode_modrm(emu); + if ((emu->cur_mod == 3 && (emu->cur_rh == 3 || emu->cur_rh == 5)) || emu->cur_rh == 7) + x86emu_halt_sys(emu); + if (emu->cur_rh == 0 || emu->cur_rh == 1 || emu->cur_rh == 6) { + if (emu->x86.mode & SYSMODE_PREFIX_DATA) + x86emuOp32_opcFF_word_RM(emu); + else + x86emuOp16_opcFF_word_RM(emu); + return; + } + + if (emu->cur_mod != 3) { + destoffset = decode_rl_address(emu); + destval = fetch_data_word(emu, destoffset); + switch (emu->cur_rh) { + case 3: /* call far ptr ... */ + destval2 = fetch_data_word(emu, destoffset + 2); + push_word(emu, emu->x86.R_CS); + emu->x86.R_CS = destval2; + push_word(emu, emu->x86.R_IP); + emu->x86.R_IP = destval; + break; + case 5: /* jmp far ptr ... */ + destval2 = fetch_data_word(emu, destoffset + 2); + emu->x86.R_IP = destval; + emu->x86.R_CS = destval2; + break; + } + } else { + destval = *decode_rl_word_register(emu); + } + + switch (emu->cur_rh) { + case 2: /* call word ptr */ + push_word(emu, emu->x86.R_IP); + emu->x86.R_IP = destval; + break; + case 4: /* jmp */ + emu->x86.R_IP = destval; + break; + } +} + +/* + * * Single byte operation code table: + */ +static void +x86emu_exec_one_byte(struct x86emu * emu) +{ + uint8_t op1; + + op1 = fetch_byte_imm(emu); + + switch (op1) { + case 0x00: + common_binop_byte_rm_r(emu, add_byte); + break; + case 0x01: + common_binop_word_long_rm_r(emu, add_word, add_long); + break; + case 0x02: + common_binop_byte_r_rm(emu, add_byte); + break; + case 0x03: + common_binop_word_long_r_rm(emu, add_word, add_long); + break; + case 0x04: + common_binop_byte_imm(emu, add_byte); + break; + case 0x05: + common_binop_word_long_imm(emu, add_word, add_long); + break; + case 0x06: + push_word(emu, emu->x86.R_ES); + break; + case 0x07: + emu->x86.R_ES = pop_word(emu); + break; + + case 0x08: + common_binop_byte_rm_r(emu, or_byte); + break; + case 0x09: + common_binop_word_long_rm_r(emu, or_word, or_long); + break; + case 0x0a: + common_binop_byte_r_rm(emu, or_byte); + break; + case 0x0b: + common_binop_word_long_r_rm(emu, or_word, or_long); + break; + case 0x0c: + common_binop_byte_imm(emu, or_byte); + break; + case 0x0d: + common_binop_word_long_imm(emu, or_word, or_long); + break; + case 0x0e: + push_word(emu, emu->x86.R_CS); + break; + case 0x0f: + x86emu_exec_two_byte(emu); + break; + + case 0x10: + common_binop_byte_rm_r(emu, adc_byte); + break; + case 0x11: + common_binop_word_long_rm_r(emu, adc_word, adc_long); + break; + case 0x12: + common_binop_byte_r_rm(emu, adc_byte); + break; + case 0x13: + common_binop_word_long_r_rm(emu, adc_word, adc_long); + break; + case 0x14: + common_binop_byte_imm(emu, adc_byte); + break; + case 0x15: + common_binop_word_long_imm(emu, adc_word, adc_long); + break; + case 0x16: + push_word(emu, emu->x86.R_SS); + break; + case 0x17: + emu->x86.R_SS = pop_word(emu); + break; + + case 0x18: + common_binop_byte_rm_r(emu, sbb_byte); + break; + case 0x19: + common_binop_word_long_rm_r(emu, sbb_word, sbb_long); + break; + case 0x1a: + common_binop_byte_r_rm(emu, sbb_byte); + break; + case 0x1b: + common_binop_word_long_r_rm(emu, sbb_word, sbb_long); + break; + case 0x1c: + common_binop_byte_imm(emu, sbb_byte); + break; + case 0x1d: + common_binop_word_long_imm(emu, sbb_word, sbb_long); + break; + case 0x1e: + push_word(emu, emu->x86.R_DS); + break; + case 0x1f: + emu->x86.R_DS = pop_word(emu); + break; + + case 0x20: + common_binop_byte_rm_r(emu, and_byte); + break; + case 0x21: + common_binop_word_long_rm_r(emu, and_word, and_long); + break; + case 0x22: + common_binop_byte_r_rm(emu, and_byte); + break; + case 0x23: + common_binop_word_long_r_rm(emu, and_word, and_long); + break; + case 0x24: + common_binop_byte_imm(emu, and_byte); + break; + case 0x25: + common_binop_word_long_imm(emu, and_word, and_long); + break; + case 0x26: + emu->x86.mode |= SYSMODE_SEGOVR_ES; + break; + case 0x27: + emu->x86.R_AL = daa_byte(emu, emu->x86.R_AL); + break; + + case 0x28: + common_binop_byte_rm_r(emu, sub_byte); + break; + case 0x29: + common_binop_word_long_rm_r(emu, sub_word, sub_long); + break; + case 0x2a: + common_binop_byte_r_rm(emu, sub_byte); + break; + case 0x2b: + common_binop_word_long_r_rm(emu, sub_word, sub_long); + break; + case 0x2c: + common_binop_byte_imm(emu, sub_byte); + break; + case 0x2d: + common_binop_word_long_imm(emu, sub_word, sub_long); + break; + case 0x2e: + emu->x86.mode |= SYSMODE_SEGOVR_CS; + break; + case 0x2f: + emu->x86.R_AL = das_byte(emu, emu->x86.R_AL); + break; + + case 0x30: + common_binop_byte_rm_r(emu, xor_byte); + break; + case 0x31: + common_binop_word_long_rm_r(emu, xor_word, xor_long); + break; + case 0x32: + common_binop_byte_r_rm(emu, xor_byte); + break; + case 0x33: + common_binop_word_long_r_rm(emu, xor_word, xor_long); + break; + case 0x34: + common_binop_byte_imm(emu, xor_byte); + break; + case 0x35: + common_binop_word_long_imm(emu, xor_word, xor_long); + break; + case 0x36: + emu->x86.mode |= SYSMODE_SEGOVR_SS; + break; + case 0x37: + emu->x86.R_AX = aaa_word(emu, emu->x86.R_AX); + break; + + case 0x38: + common_binop_ns_byte_rm_r(emu, cmp_byte_no_return); + break; + case 0x39: + common_binop_ns_word_long_rm_r(emu, cmp_word_no_return, + cmp_long_no_return); + break; + case 0x3a: + x86emuOp_cmp_byte_R_RM(emu); + break; + case 0x3b: + x86emuOp_cmp_word_R_RM(emu); + break; + case 0x3c: + x86emuOp_cmp_byte_AL_IMM(emu); + break; + case 0x3d: + x86emuOp_cmp_word_AX_IMM(emu); + break; + case 0x3e: + emu->x86.mode |= SYSMODE_SEGOVR_DS; + break; + case 0x3f: + emu->x86.R_AX = aas_word(emu, emu->x86.R_AX); + break; + + case 0x40: + common_inc_word_long(emu, &emu->x86.register_a); + break; + case 0x41: + common_inc_word_long(emu, &emu->x86.register_c); + break; + case 0x42: + common_inc_word_long(emu, &emu->x86.register_d); + break; + case 0x43: + common_inc_word_long(emu, &emu->x86.register_b); + break; + case 0x44: + common_inc_word_long(emu, &emu->x86.register_sp); + break; + case 0x45: + common_inc_word_long(emu, &emu->x86.register_bp); + break; + case 0x46: + common_inc_word_long(emu, &emu->x86.register_si); + break; + case 0x47: + common_inc_word_long(emu, &emu->x86.register_di); + break; + + case 0x48: + common_dec_word_long(emu, &emu->x86.register_a); + break; + case 0x49: + common_dec_word_long(emu, &emu->x86.register_c); + break; + case 0x4a: + common_dec_word_long(emu, &emu->x86.register_d); + break; + case 0x4b: + common_dec_word_long(emu, &emu->x86.register_b); + break; + case 0x4c: + common_dec_word_long(emu, &emu->x86.register_sp); + break; + case 0x4d: + common_dec_word_long(emu, &emu->x86.register_bp); + break; + case 0x4e: + common_dec_word_long(emu, &emu->x86.register_si); + break; + case 0x4f: + common_dec_word_long(emu, &emu->x86.register_di); + break; + + case 0x50: + common_push_word_long(emu, &emu->x86.register_a); + break; + case 0x51: + common_push_word_long(emu, &emu->x86.register_c); + break; + case 0x52: + common_push_word_long(emu, &emu->x86.register_d); + break; + case 0x53: + common_push_word_long(emu, &emu->x86.register_b); + break; + case 0x54: + common_push_word_long(emu, &emu->x86.register_sp); + break; + case 0x55: + common_push_word_long(emu, &emu->x86.register_bp); + break; + case 0x56: + common_push_word_long(emu, &emu->x86.register_si); + break; + case 0x57: + common_push_word_long(emu, &emu->x86.register_di); + break; + + case 0x58: + common_pop_word_long(emu, &emu->x86.register_a); + break; + case 0x59: + common_pop_word_long(emu, &emu->x86.register_c); + break; + case 0x5a: + common_pop_word_long(emu, &emu->x86.register_d); + break; + case 0x5b: + common_pop_word_long(emu, &emu->x86.register_b); + break; + case 0x5c: + common_pop_word_long(emu, &emu->x86.register_sp); + break; + case 0x5d: + common_pop_word_long(emu, &emu->x86.register_bp); + break; + case 0x5e: + common_pop_word_long(emu, &emu->x86.register_si); + break; + case 0x5f: + common_pop_word_long(emu, &emu->x86.register_di); + break; + + case 0x60: + x86emuOp_push_all(emu); + break; + case 0x61: + x86emuOp_pop_all(emu); + break; + /* 0x62 bound */ + /* 0x63 arpl */ + case 0x64: + emu->x86.mode |= SYSMODE_SEGOVR_FS; + break; + case 0x65: + emu->x86.mode |= SYSMODE_SEGOVR_GS; + break; + case 0x66: + emu->x86.mode |= SYSMODE_PREFIX_DATA; + break; + case 0x67: + emu->x86.mode |= SYSMODE_PREFIX_ADDR; + break; + + case 0x68: + x86emuOp_push_word_IMM(emu); + break; + case 0x69: + common_imul_imm(emu, 0); + break; + case 0x6a: + x86emuOp_push_byte_IMM(emu); + break; + case 0x6b: + common_imul_imm(emu, 1); + break; + case 0x6c: + ins(emu, 1); + break; + case 0x6d: + x86emuOp_ins_word(emu); + break; + case 0x6e: + outs(emu, 1); + break; + case 0x6f: + x86emuOp_outs_word(emu); + break; + + case 0x70: + common_jmp_near(emu, ACCESS_FLAG(F_OF)); + break; + case 0x71: + common_jmp_near(emu, !ACCESS_FLAG(F_OF)); + break; + case 0x72: + common_jmp_near(emu, ACCESS_FLAG(F_CF)); + break; + case 0x73: + common_jmp_near(emu, !ACCESS_FLAG(F_CF)); + break; + case 0x74: + common_jmp_near(emu, ACCESS_FLAG(F_ZF)); + break; + case 0x75: + common_jmp_near(emu, !ACCESS_FLAG(F_ZF)); + break; + case 0x76: + common_jmp_near(emu, ACCESS_FLAG(F_CF) || ACCESS_FLAG(F_ZF)); + break; + case 0x77: + common_jmp_near(emu, !ACCESS_FLAG(F_CF) && !ACCESS_FLAG(F_ZF)); + break; + + case 0x78: + common_jmp_near(emu, ACCESS_FLAG(F_SF)); + break; + case 0x79: + common_jmp_near(emu, !ACCESS_FLAG(F_SF)); + break; + case 0x7a: + common_jmp_near(emu, ACCESS_FLAG(F_PF)); + break; + case 0x7b: + common_jmp_near(emu, !ACCESS_FLAG(F_PF)); + break; + case 0x7c: + x86emuOp_jump_near_L(emu); + break; + case 0x7d: + x86emuOp_jump_near_NL(emu); + break; + case 0x7e: + x86emuOp_jump_near_LE(emu); + break; + case 0x7f: + x86emuOp_jump_near_NLE(emu); + break; + + case 0x80: + x86emuOp_opc80_byte_RM_IMM(emu); + break; + case 0x81: + x86emuOp_opc81_word_RM_IMM(emu); + break; + case 0x82: + x86emuOp_opc82_byte_RM_IMM(emu); + break; + case 0x83: + x86emuOp_opc83_word_RM_IMM(emu); + break; + case 0x84: + common_binop_ns_byte_rm_r(emu, test_byte); + break; + case 0x85: + common_binop_ns_word_long_rm_r(emu, test_word, test_long); + break; + case 0x86: + x86emuOp_xchg_byte_RM_R(emu); + break; + case 0x87: + x86emuOp_xchg_word_RM_R(emu); + break; + + case 0x88: + x86emuOp_mov_byte_RM_R(emu); + break; + case 0x89: + x86emuOp_mov_word_RM_R(emu); + break; + case 0x8a: + x86emuOp_mov_byte_R_RM(emu); + break; + case 0x8b: + x86emuOp_mov_word_R_RM(emu); + break; + case 0x8c: + x86emuOp_mov_word_RM_SR(emu); + break; + case 0x8d: + x86emuOp_lea_word_R_M(emu); + break; + case 0x8e: + x86emuOp_mov_word_SR_RM(emu); + break; + case 0x8f: + x86emuOp_pop_RM(emu); + break; + + case 0x90: + /* nop */ + break; + case 0x91: + x86emuOp_xchg_word_AX_CX(emu); + break; + case 0x92: + x86emuOp_xchg_word_AX_DX(emu); + break; + case 0x93: + x86emuOp_xchg_word_AX_BX(emu); + break; + case 0x94: + x86emuOp_xchg_word_AX_SP(emu); + break; + case 0x95: + x86emuOp_xchg_word_AX_BP(emu); + break; + case 0x96: + x86emuOp_xchg_word_AX_SI(emu); + break; + case 0x97: + x86emuOp_xchg_word_AX_DI(emu); + break; + + case 0x98: + x86emuOp_cbw(emu); + break; + case 0x99: + x86emuOp_cwd(emu); + break; + case 0x9a: + x86emuOp_call_far_IMM(emu); + break; + case 0x9b: + /* wait */ + break; + case 0x9c: + x86emuOp_pushf_word(emu); + break; + case 0x9d: + x86emuOp_popf_word(emu); + break; + case 0x9e: + x86emuOp_sahf(emu); + break; + case 0x9f: + x86emuOp_lahf(emu); + break; + + case 0xa0: + x86emuOp_mov_AL_M_IMM(emu); + break; + case 0xa1: + x86emuOp_mov_AX_M_IMM(emu); + break; + case 0xa2: + x86emuOp_mov_M_AL_IMM(emu); + break; + case 0xa3: + x86emuOp_mov_M_AX_IMM(emu); + break; + case 0xa4: + x86emuOp_movs_byte(emu); + break; + case 0xa5: + x86emuOp_movs_word(emu); + break; + case 0xa6: + x86emuOp_cmps_byte(emu); + break; + case 0xa7: + x86emuOp_cmps_word(emu); + break; + + case 0xa8: + test_byte(emu, emu->x86.R_AL, fetch_byte_imm(emu)); + break; + case 0xa9: + x86emuOp_test_AX_IMM(emu); + break; + case 0xaa: + x86emuOp_stos_byte(emu); + break; + case 0xab: + x86emuOp_stos_word(emu); + break; + case 0xac: + x86emuOp_lods_byte(emu); + break; + case 0xad: + x86emuOp_lods_word(emu); + break; + case 0xae: + x86emuOp_scas_byte(emu); + break; + case 0xaf: + x86emuOp_scas_word(emu); + break; + + case 0xb0: + emu->x86.R_AL = fetch_byte_imm(emu); + break; + case 0xb1: + emu->x86.R_CL = fetch_byte_imm(emu); + break; + case 0xb2: + emu->x86.R_DL = fetch_byte_imm(emu); + break; + case 0xb3: + emu->x86.R_BL = fetch_byte_imm(emu); + break; + case 0xb4: + emu->x86.R_AH = fetch_byte_imm(emu); + break; + case 0xb5: + emu->x86.R_CH = fetch_byte_imm(emu); + break; + case 0xb6: + emu->x86.R_DH = fetch_byte_imm(emu); + break; + case 0xb7: + emu->x86.R_BH = fetch_byte_imm(emu); + break; + + case 0xb8: + x86emuOp_mov_word_AX_IMM(emu); + break; + case 0xb9: + x86emuOp_mov_word_CX_IMM(emu); + break; + case 0xba: + x86emuOp_mov_word_DX_IMM(emu); + break; + case 0xbb: + x86emuOp_mov_word_BX_IMM(emu); + break; + case 0xbc: + + x86emuOp_mov_word_SP_IMM(emu); + break; + case 0xbd: + x86emuOp_mov_word_BP_IMM(emu); + break; + case 0xbe: + x86emuOp_mov_word_SI_IMM(emu); + break; + case 0xbf: + x86emuOp_mov_word_DI_IMM(emu); + break; + + case 0xc0: + x86emuOp_opcC0_byte_RM_MEM(emu); + break; + case 0xc1: + x86emuOp_opcC1_word_RM_MEM(emu); + break; + case 0xc2: + x86emuOp_ret_near_IMM(emu); + break; + case 0xc3: + emu->x86.R_IP = pop_word(emu); + break; + case 0xc4: + common_load_far_pointer(emu, &emu->x86.R_ES); + break; + case 0xc5: + common_load_far_pointer(emu, &emu->x86.R_DS); + break; + case 0xc6: + x86emuOp_mov_byte_RM_IMM(emu); + break; + case 0xc7: + x86emuOp_mov_word_RM_IMM(emu); + break; + case 0xc8: + x86emuOp_enter(emu); + break; + case 0xc9: + x86emuOp_leave(emu); + break; + case 0xca: + x86emuOp_ret_far_IMM(emu); + break; + case 0xcb: + x86emuOp_ret_far(emu); + break; + case 0xcc: + x86emuOp_int3(emu); + break; + case 0xcd: + x86emuOp_int_IMM(emu); + break; + case 0xce: + x86emuOp_into(emu); + break; + case 0xcf: + x86emuOp_iret(emu); + break; + + case 0xd0: + x86emuOp_opcD0_byte_RM_1(emu); + break; + case 0xd1: + x86emuOp_opcD1_word_RM_1(emu); + break; + case 0xd2: + x86emuOp_opcD2_byte_RM_CL(emu); + break; + case 0xd3: + x86emuOp_opcD3_word_RM_CL(emu); + break; + case 0xd4: + x86emuOp_aam(emu); + break; + case 0xd5: + x86emuOp_aad(emu); + break; + /* 0xd6 Undocumented SETALC instruction */ + case 0xd7: + x86emuOp_xlat(emu); + break; + case 0xd8: + x86emuOp_esc_coprocess_d8(emu); + break; + case 0xd9: + x86emuOp_esc_coprocess_d9(emu); + break; + case 0xda: + x86emuOp_esc_coprocess_da(emu); + break; + case 0xdb: + x86emuOp_esc_coprocess_db(emu); + break; + case 0xdc: + x86emuOp_esc_coprocess_dc(emu); + break; + case 0xdd: + x86emuOp_esc_coprocess_dd(emu); + break; + case 0xde: + x86emuOp_esc_coprocess_de(emu); + break; + case 0xdf: + x86emuOp_esc_coprocess_df(emu); + break; + + case 0xe0: + x86emuOp_loopne(emu); + break; + case 0xe1: + x86emuOp_loope(emu); + break; + case 0xe2: + x86emuOp_loop(emu); + break; + case 0xe3: + x86emuOp_jcxz(emu); + break; + case 0xe4: + x86emuOp_in_byte_AL_IMM(emu); + break; + case 0xe5: + x86emuOp_in_word_AX_IMM(emu); + break; + case 0xe6: + x86emuOp_out_byte_IMM_AL(emu); + break; + case 0xe7: + x86emuOp_out_word_IMM_AX(emu); + break; + + case 0xe8: + x86emuOp_call_near_IMM(emu); + break; + case 0xe9: + x86emuOp_jump_near_IMM(emu); + break; + case 0xea: + x86emuOp_jump_far_IMM(emu); + break; + case 0xeb: + x86emuOp_jump_byte_IMM(emu); + break; + case 0xec: + x86emuOp_in_byte_AL_DX(emu); + break; + case 0xed: + x86emuOp_in_word_AX_DX(emu); + break; + case 0xee: + x86emuOp_out_byte_DX_AL(emu); + break; + case 0xef: + x86emuOp_out_word_DX_AX(emu); + break; + + case 0xf0: + x86emuOp_lock(emu); + break; + case 0xf2: + emu->x86.mode |= SYSMODE_PREFIX_REPNE; + break; + case 0xf3: + emu->x86.mode |= SYSMODE_PREFIX_REPE; + break; + case 0xf4: + x86emu_halt_sys(emu); + break; + case 0xf5: + x86emuOp_cmc(emu); + break; + case 0xf6: + x86emuOp_opcF6_byte_RM(emu); + break; + case 0xf7: + x86emuOp_opcF7_word_RM(emu); + break; + + case 0xf8: + CLEAR_FLAG(F_CF); + break; + case 0xf9: + SET_FLAG(F_CF); + break; + case 0xfa: + CLEAR_FLAG(F_IF); + break; + case 0xfb: + SET_FLAG(F_IF); + break; + case 0xfc: + CLEAR_FLAG(F_DF); + break; + case 0xfd: + SET_FLAG(F_DF); + break; + case 0xfe: + x86emuOp_opcFE_byte_RM(emu); + break; + case 0xff: + x86emuOp_opcFF_word_RM(emu); + break; + default: + x86emu_halt_sys(emu); + break; + } + if (op1 != 0x26 && op1 != 0x2e && op1 != 0x36 && op1 != 0x3e && + (op1 | 3) != 0x67) + emu->x86.mode &= ~SYSMODE_CLRMASK; +} + +static void +common_jmp_long(struct x86emu *emu, int cond) +{ + int16_t target; + + target = (int16_t) fetch_word_imm(emu); + target += (int16_t) emu->x86.R_IP; + if (cond) + emu->x86.R_IP = (uint16_t) target; +} + +static void +common_set_byte(struct x86emu *emu, int cond) +{ + uint32_t destoffset; + uint8_t *destreg, destval; + + fetch_decode_modrm(emu); + destval = cond ? 0x01 : 0x00; + if (emu->cur_mod != 3) { + destoffset = decode_rl_address(emu); + store_data_byte(emu, destoffset, destval); + } else { + destreg = decode_rl_byte_register(emu); + *destreg = destval; + } +} + +static void +common_bitstring32(struct x86emu *emu, int op) +{ + int bit; + uint32_t srcval, *shiftreg, mask; + + fetch_decode_modrm(emu); + shiftreg = decode_rh_long_register(emu); + srcval = decode_and_fetch_long_disp(emu, (int16_t) *shiftreg >> 5); + bit = *shiftreg & 0x1F; + mask = 0x1 << bit; + CONDITIONAL_SET_FLAG(srcval & mask, F_CF); + + switch (op) { + case 0: + break; + case 1: + write_back_long(emu, srcval | mask); + break; + case 2: + write_back_long(emu, srcval & ~mask); + break; + case 3: + write_back_long(emu, srcval ^ mask); + break; + } +} + +static void +common_bitstring16(struct x86emu *emu, int op) +{ + int bit; + uint16_t srcval, *shiftreg, mask; + + fetch_decode_modrm(emu); + shiftreg = decode_rh_word_register(emu); + srcval = decode_and_fetch_word_disp(emu, (int16_t) *shiftreg >> 4); + bit = *shiftreg & 0xF; + mask = 0x1 << bit; + CONDITIONAL_SET_FLAG(srcval & mask, F_CF); + + switch (op) { + case 0: + break; + case 1: + write_back_word(emu, srcval | mask); + break; + case 2: + write_back_word(emu, srcval & ~mask); + break; + case 3: + write_back_word(emu, srcval ^ mask); + break; + } +} + +static void +common_bitstring(struct x86emu *emu, int op) +{ + if (emu->x86.mode & SYSMODE_PREFIX_DATA) + common_bitstring32(emu, op); + else + common_bitstring16(emu, op); +} + +static void +common_bitsearch32(struct x86emu *emu, int diff) +{ + uint32_t srcval, *dstreg; + + fetch_decode_modrm(emu); + dstreg = decode_rh_long_register(emu); + srcval = decode_and_fetch_long(emu); + CONDITIONAL_SET_FLAG(srcval == 0, F_ZF); + for (*dstreg = 0; *dstreg < 32; *dstreg += diff) { + if ((srcval >> *dstreg) & 1) + break; + } +} + +static void +common_bitsearch16(struct x86emu *emu, int diff) +{ + uint16_t srcval, *dstreg; + + fetch_decode_modrm(emu); + dstreg = decode_rh_word_register(emu); + srcval = decode_and_fetch_word(emu); + CONDITIONAL_SET_FLAG(srcval == 0, F_ZF); + for (*dstreg = 0; *dstreg < 16; *dstreg += diff) { + if ((srcval >> *dstreg) & 1) + break; + } +} + +static void +common_bitsearch(struct x86emu *emu, int diff) +{ + if (emu->x86.mode & SYSMODE_PREFIX_DATA) + common_bitsearch32(emu, diff); + else + common_bitsearch16(emu, diff); +} + +static void +common_shift32(struct x86emu *emu, int shift_left, int use_cl) +{ + uint8_t shift; + uint32_t destval, *shiftreg; + + fetch_decode_modrm(emu); + shiftreg = decode_rh_long_register(emu); + if (use_cl) { + destval = decode_and_fetch_long(emu); + shift = emu->x86.R_CL; + } else { + destval = decode_and_fetch_long_imm8(emu, &shift); + } + if (shift_left) + destval = shld_long(emu, destval, *shiftreg, shift); + else + destval = shrd_long(emu, destval, *shiftreg, shift); + write_back_long(emu, destval); +} + +static void +common_shift16(struct x86emu *emu, int shift_left, int use_cl) +{ + uint8_t shift; + uint16_t destval, *shiftreg; + + fetch_decode_modrm(emu); + shiftreg = decode_rh_word_register(emu); + if (use_cl) { + destval = decode_and_fetch_word(emu); + shift = emu->x86.R_CL; + } else { + destval = decode_and_fetch_word_imm8(emu, &shift); + } + if (shift_left) + destval = shld_word(emu, destval, *shiftreg, shift); + else + destval = shrd_word(emu, destval, *shiftreg, shift); + write_back_word(emu, destval); +} + +static void +common_shift(struct x86emu *emu, int shift_left, int use_cl) +{ + if (emu->x86.mode & SYSMODE_PREFIX_DATA) + common_shift32(emu, shift_left, use_cl); + else + common_shift16(emu, shift_left, use_cl); +} + +/*----------------------------- Implementation ----------------------------*/ +#define xorl(a,b) ((a) && !(b)) || (!(a) && (b)) + + +/* + * REMARKS: + * Handles opcode 0x0f,0x31 + */ +static void +x86emuOp2_rdtsc(struct x86emu *emu) +{ + emu->x86.R_EAX = emu->cur_cycles & 0xffffffff; + emu->x86.R_EDX = emu->cur_cycles >> 32; +} + +/* + * REMARKS: + * Handles opcode 0x0f,0xa0 + */ +static void +x86emuOp2_push_FS(struct x86emu *emu) +{ + push_word(emu, emu->x86.R_FS); +} + +/* + * REMARKS: + * Handles opcode 0x0f,0xa1 + */ +static void +x86emuOp2_pop_FS(struct x86emu *emu) +{ + emu->x86.R_FS = pop_word(emu); +} + +/* + * REMARKS: + * Handles opcode 0x0f,0xa1 + */ +#if defined(__i386__) || defined(__amd64__) +static void +hw_cpuid(uint32_t *a, uint32_t *b, uint32_t *c, uint32_t *d) +{ + __asm__ __volatile__("cpuid" + : "=a" (*a), "=b" (*b), + "=c" (*c), "=d" (*d) + : "a" (*a), "c" (*c) + : "cc"); +} +#endif +static void +x86emuOp2_cpuid(struct x86emu *emu) +{ +#if defined(__i386__) || defined(__amd64__) + hw_cpuid(&emu->x86.R_EAX, &emu->x86.R_EBX, &emu->x86.R_ECX, + &emu->x86.R_EDX); +#endif + switch (emu->x86.R_EAX) { + case 0: + emu->x86.R_EAX = 1; +#if !defined(__i386__) && !defined(__amd64__) + /* "GenuineIntel" */ + emu->x86.R_EBX = 0x756e6547; + emu->x86.R_EDX = 0x49656e69; + emu->x86.R_ECX = 0x6c65746e; +#endif + break; + case 1: +#if !defined(__i386__) && !defined(__amd64__) + emu->x86.R_EAX = 0x00000480; + emu->x86.R_EBX = emu->x86.R_ECX = 0; + emu->x86.R_EDX = 0x00000002; +#else + emu->x86.R_EDX &= 0x00000012; +#endif + break; + default: + emu->x86.R_EAX = emu->x86.R_EBX = emu->x86.R_ECX = + emu->x86.R_EDX = 0; + break; + } +} + +/* + * REMARKS: + * Handles opcode 0x0f,0xa3 + */ +static void +x86emuOp2_bt_R(struct x86emu *emu) +{ + common_bitstring(emu, 0); +} + +/* + * REMARKS: + * Handles opcode 0x0f,0xa4 + */ +static void +x86emuOp2_shld_IMM(struct x86emu *emu) +{ + common_shift(emu, 1, 0); +} + +/* + * REMARKS: + * Handles opcode 0x0f,0xa5 + */ +static void +x86emuOp2_shld_CL(struct x86emu *emu) +{ + common_shift(emu, 1, 1); +} + +/* + * REMARKS: + * Handles opcode 0x0f,0xa8 + */ +static void +x86emuOp2_push_GS(struct x86emu *emu) +{ + push_word(emu, emu->x86.R_GS); +} + +/* + * REMARKS: + * Handles opcode 0x0f,0xa9 + */ +static void +x86emuOp2_pop_GS(struct x86emu *emu) +{ + emu->x86.R_GS = pop_word(emu); +} + +/* + * REMARKS: + * Handles opcode 0x0f,0xab + */ +static void +x86emuOp2_bts_R(struct x86emu *emu) +{ + common_bitstring(emu, 1); +} + +/* + * REMARKS: + * Handles opcode 0x0f,0xac + */ +static void +x86emuOp2_shrd_IMM(struct x86emu *emu) +{ + common_shift(emu, 0, 0); +} + +/* + * REMARKS: + * Handles opcode 0x0f,0xad + */ +static void +x86emuOp2_shrd_CL(struct x86emu *emu) +{ + common_shift(emu, 0, 1); +} + +/* + * REMARKS: + * Handles opcode 0x0f,0xaf + */ +static void +x86emuOp2_32_imul_R_RM(struct x86emu *emu) +{ + uint32_t *destreg, srcval; + uint64_t res; + + fetch_decode_modrm(emu); + destreg = decode_rh_long_register(emu); + srcval = decode_and_fetch_long(emu); + res = (int32_t) *destreg * (int32_t)srcval; + if (res > 0xffffffff) { + SET_FLAG(F_CF); + SET_FLAG(F_OF); + } else { + CLEAR_FLAG(F_CF); + CLEAR_FLAG(F_OF); + } + *destreg = (uint32_t) res; +} + +static void +x86emuOp2_16_imul_R_RM(struct x86emu *emu) +{ + uint16_t *destreg, srcval; + uint32_t res; + + fetch_decode_modrm(emu); + destreg = decode_rh_word_register(emu); + srcval = decode_and_fetch_word(emu); + res = (int16_t) * destreg * (int16_t)srcval; + if (res > 0xFFFF) { + SET_FLAG(F_CF); + SET_FLAG(F_OF); + } else { + CLEAR_FLAG(F_CF); + CLEAR_FLAG(F_OF); + } + *destreg = (uint16_t) res; +} + +static void +x86emuOp2_imul_R_RM(struct x86emu *emu) +{ + if (emu->x86.mode & SYSMODE_PREFIX_DATA) + x86emuOp2_32_imul_R_RM(emu); + else + x86emuOp2_16_imul_R_RM(emu); +} + +/* + * REMARKS: + * Handles opcode 0x0f,0xb2 + */ +static void +x86emuOp2_lss_R_IMM(struct x86emu *emu) +{ + common_load_far_pointer(emu, &emu->x86.R_SS); +} + +/* + * REMARKS: + * Handles opcode 0x0f,0xb3 + */ +static void +x86emuOp2_btr_R(struct x86emu *emu) +{ + common_bitstring(emu, 2); +} + +/* + * REMARKS: + * Handles opcode 0x0f,0xb4 + */ +static void +x86emuOp2_lfs_R_IMM(struct x86emu *emu) +{ + common_load_far_pointer(emu, &emu->x86.R_FS); +} + +/* + * REMARKS: + * Handles opcode 0x0f,0xb5 + */ +static void +x86emuOp2_lgs_R_IMM(struct x86emu *emu) +{ + common_load_far_pointer(emu, &emu->x86.R_GS); +} + +/* + * REMARKS: + * Handles opcode 0x0f,0xb6 + */ +static void +x86emuOp2_32_movzx_byte_R_RM(struct x86emu *emu) +{ + uint32_t *destreg; + + fetch_decode_modrm(emu); + destreg = decode_rh_long_register(emu); + *destreg = decode_and_fetch_byte(emu); +} + +static void +x86emuOp2_16_movzx_byte_R_RM(struct x86emu *emu) +{ + uint16_t *destreg; + + fetch_decode_modrm(emu); + destreg = decode_rh_word_register(emu); + *destreg = decode_and_fetch_byte(emu); +} + +static void +x86emuOp2_movzx_byte_R_RM(struct x86emu *emu) +{ + if (emu->x86.mode & SYSMODE_PREFIX_DATA) + x86emuOp2_32_movzx_byte_R_RM(emu); + else + x86emuOp2_16_movzx_byte_R_RM(emu); +} + +/* + * REMARKS: + * Handles opcode 0x0f,0xb7 + */ +static void +x86emuOp2_movzx_word_R_RM(struct x86emu *emu) +{ + uint32_t *destreg; + + fetch_decode_modrm(emu); + destreg = decode_rh_long_register(emu); + *destreg = decode_and_fetch_word(emu); +} + +/* + * REMARKS: + * Handles opcode 0x0f,0xba + */ +static void +x86emuOp2_32_btX_I(struct x86emu *emu) +{ + int bit; + uint32_t srcval, mask; + uint8_t shift; + + fetch_decode_modrm(emu); + if (emu->cur_rh < 4) + x86emu_halt_sys(emu); + + srcval = decode_and_fetch_long_imm8(emu, &shift); + bit = shift & 0x1F; + mask = (0x1 << bit); + + switch (emu->cur_rh) { + case 5: + write_back_long(emu, srcval | mask); + break; + case 6: + write_back_long(emu, srcval & ~mask); + break; + case 7: + write_back_long(emu, srcval ^ mask); + break; + } + CONDITIONAL_SET_FLAG(srcval & mask, F_CF); +} + +static void +x86emuOp2_16_btX_I(struct x86emu *emu) +{ + int bit; + + uint16_t srcval, mask; + uint8_t shift; + + fetch_decode_modrm(emu); + if (emu->cur_rh < 4) + x86emu_halt_sys(emu); + + srcval = decode_and_fetch_word_imm8(emu, &shift); + bit = shift & 0xF; + mask = (0x1 << bit); + switch (emu->cur_rh) { + case 5: + write_back_word(emu, srcval | mask); + break; + case 6: + write_back_word(emu, srcval & ~mask); + break; + case 7: + write_back_word(emu, srcval ^ mask); + break; + } + CONDITIONAL_SET_FLAG(srcval & mask, F_CF); +} + +static void +x86emuOp2_btX_I(struct x86emu *emu) +{ + if (emu->x86.mode & SYSMODE_PREFIX_DATA) + x86emuOp2_32_btX_I(emu); + else + x86emuOp2_16_btX_I(emu); +} + +/* + * REMARKS: + * Handles opcode 0x0f,0xbb + */ +static void +x86emuOp2_btc_R(struct x86emu *emu) +{ + common_bitstring(emu, 3); +} + +/* + * REMARKS: + * Handles opcode 0x0f,0xbc + */ +static void +x86emuOp2_bsf(struct x86emu *emu) +{ + common_bitsearch(emu, +1); +} + +/* + * REMARKS: + * Handles opcode 0x0f,0xbd + */ +static void +x86emuOp2_bsr(struct x86emu *emu) +{ + common_bitsearch(emu, -1); +} + +/* + * REMARKS: + * Handles opcode 0x0f,0xbe + */ +static void +x86emuOp2_32_movsx_byte_R_RM(struct x86emu *emu) +{ + uint32_t *destreg; + + destreg = decode_rh_long_register(emu); + *destreg = (int32_t)(int8_t)decode_and_fetch_byte(emu); +} + +static void +x86emuOp2_16_movsx_byte_R_RM(struct x86emu *emu) +{ + uint16_t *destreg; + + fetch_decode_modrm(emu); + destreg = decode_rh_word_register(emu); + *destreg = (int16_t)(int8_t)decode_and_fetch_byte(emu); +} + +static void +x86emuOp2_movsx_byte_R_RM(struct x86emu *emu) +{ + if (emu->x86.mode & SYSMODE_PREFIX_DATA) + x86emuOp2_32_movsx_byte_R_RM(emu); + else + x86emuOp2_16_movsx_byte_R_RM(emu); +} + +/* + * REMARKS: + * Handles opcode 0x0f,0xbf + */ +static void +x86emuOp2_movsx_word_R_RM(struct x86emu *emu) +{ + uint32_t *destreg; + + fetch_decode_modrm(emu); + destreg = decode_rh_long_register(emu); + *destreg = (int32_t)(int16_t)decode_and_fetch_word(emu); +} + +static void +x86emu_exec_two_byte(struct x86emu * emu) +{ + uint8_t op2; + + op2 = fetch_byte_imm(emu); + + switch (op2) { + /* 0x00 Group F (ring 0 PM) */ + /* 0x01 Group G (ring 0 PM) */ + /* 0x02 lar (ring 0 PM) */ + /* 0x03 lsl (ring 0 PM) */ + /* 0x05 loadall (undocumented) */ + /* 0x06 clts (ring 0 PM) */ + /* 0x07 loadall (undocumented) */ + /* 0x08 invd (ring 0 PM) */ + /* 0x09 wbinvd (ring 0 PM) */ + + /* 0x20 mov reg32(op2); break;creg (ring 0 PM) */ + /* 0x21 mov reg32(op2); break;dreg (ring 0 PM) */ + /* 0x22 mov creg(op2); break;reg32 (ring 0 PM) */ + /* 0x23 mov dreg(op2); break;reg32 (ring 0 PM) */ + /* 0x24 mov reg32(op2); break;treg (ring 0 PM) */ + /* 0x26 mov treg(op2); break;reg32 (ring 0 PM) */ + + case 0x31: + x86emuOp2_rdtsc(emu); + break; + + case 0x80: + common_jmp_long(emu, ACCESS_FLAG(F_OF)); + break; + case 0x81: + common_jmp_long(emu, !ACCESS_FLAG(F_OF)); + break; + case 0x82: + common_jmp_long(emu, ACCESS_FLAG(F_CF)); + break; + case 0x83: + common_jmp_long(emu, !ACCESS_FLAG(F_CF)); + break; + case 0x84: + common_jmp_long(emu, ACCESS_FLAG(F_ZF)); + break; + case 0x85: + common_jmp_long(emu, !ACCESS_FLAG(F_ZF)); + break; + case 0x86: + common_jmp_long(emu, ACCESS_FLAG(F_CF) || ACCESS_FLAG(F_ZF)); + break; + case 0x87: + common_jmp_long(emu, !(ACCESS_FLAG(F_CF) || ACCESS_FLAG(F_ZF))); + break; + case 0x88: + common_jmp_long(emu, ACCESS_FLAG(F_SF)); + break; + case 0x89: + common_jmp_long(emu, !ACCESS_FLAG(F_SF)); + break; + case 0x8a: + common_jmp_long(emu, ACCESS_FLAG(F_PF)); + break; + case 0x8b: + common_jmp_long(emu, !ACCESS_FLAG(F_PF)); + break; + case 0x8c: + common_jmp_long(emu, xorl(ACCESS_FLAG(F_SF), ACCESS_FLAG(F_OF))); + break; + case 0x8d: + common_jmp_long(emu, !(xorl(ACCESS_FLAG(F_SF), ACCESS_FLAG(F_OF)))); + break; + case 0x8e: + common_jmp_long(emu, + (xorl(ACCESS_FLAG(F_SF), ACCESS_FLAG(F_OF)) || ACCESS_FLAG(F_ZF))); + break; + case 0x8f: + common_jmp_long(emu, + !(xorl(ACCESS_FLAG(F_SF), ACCESS_FLAG(F_OF)) || ACCESS_FLAG(F_ZF))); + break; + + case 0x90: + common_set_byte(emu, ACCESS_FLAG(F_OF)); + break; + case 0x91: + common_set_byte(emu, !ACCESS_FLAG(F_OF)); + break; + case 0x92: + common_set_byte(emu, ACCESS_FLAG(F_CF)); + break; + case 0x93: + common_set_byte(emu, !ACCESS_FLAG(F_CF)); + break; + case 0x94: + common_set_byte(emu, ACCESS_FLAG(F_ZF)); + break; + case 0x95: + common_set_byte(emu, !ACCESS_FLAG(F_ZF)); + break; + case 0x96: + common_set_byte(emu, ACCESS_FLAG(F_CF) || ACCESS_FLAG(F_ZF)); + break; + case 0x97: + common_set_byte(emu, !(ACCESS_FLAG(F_CF) || ACCESS_FLAG(F_ZF))); + break; + case 0x98: + common_set_byte(emu, ACCESS_FLAG(F_SF)); + break; + case 0x99: + common_set_byte(emu, !ACCESS_FLAG(F_SF)); + break; + case 0x9a: + common_set_byte(emu, ACCESS_FLAG(F_PF)); + break; + case 0x9b: + common_set_byte(emu, !ACCESS_FLAG(F_PF)); + break; + case 0x9c: + common_set_byte(emu, xorl(ACCESS_FLAG(F_SF), ACCESS_FLAG(F_OF))); + break; + case 0x9d: + common_set_byte(emu, xorl(ACCESS_FLAG(F_SF), ACCESS_FLAG(F_OF))); + break; + case 0x9e: + common_set_byte(emu, + (xorl(ACCESS_FLAG(F_SF), ACCESS_FLAG(F_OF)) || + ACCESS_FLAG(F_ZF))); + break; + case 0x9f: + common_set_byte(emu, + !(xorl(ACCESS_FLAG(F_SF), ACCESS_FLAG(F_OF)) || + ACCESS_FLAG(F_ZF))); + break; + + case 0xa0: + x86emuOp2_push_FS(emu); + break; + case 0xa1: + x86emuOp2_pop_FS(emu); + break; + case 0xa2: + x86emuOp2_cpuid(emu); + break; + case 0xa3: + x86emuOp2_bt_R(emu); + break; + case 0xa4: + x86emuOp2_shld_IMM(emu); + break; + case 0xa5: + x86emuOp2_shld_CL(emu); + break; + case 0xa8: + x86emuOp2_push_GS(emu); + break; + case 0xa9: + x86emuOp2_pop_GS(emu); + break; + case 0xab: + x86emuOp2_bts_R(emu); + break; + case 0xac: + x86emuOp2_shrd_IMM(emu); + break; + case 0xad: + x86emuOp2_shrd_CL(emu); + break; + case 0xaf: + x86emuOp2_imul_R_RM(emu); + break; + + /* 0xb0 TODO: cmpxchg */ + /* 0xb1 TODO: cmpxchg */ + case 0xb2: + x86emuOp2_lss_R_IMM(emu); + break; + case 0xb3: + x86emuOp2_btr_R(emu); + break; + case 0xb4: + x86emuOp2_lfs_R_IMM(emu); + break; + case 0xb5: + x86emuOp2_lgs_R_IMM(emu); + break; + case 0xb6: + x86emuOp2_movzx_byte_R_RM(emu); + break; + case 0xb7: + x86emuOp2_movzx_word_R_RM(emu); + break; + case 0xba: + x86emuOp2_btX_I(emu); + break; + case 0xbb: + x86emuOp2_btc_R(emu); + break; + case 0xbc: + x86emuOp2_bsf(emu); + break; + case 0xbd: + x86emuOp2_bsr(emu); + break; + case 0xbe: + x86emuOp2_movsx_byte_R_RM(emu); + break; + case 0xbf: + x86emuOp2_movsx_word_R_RM(emu); + break; + + /* 0xc0 TODO: xadd */ + /* 0xc1 TODO: xadd */ + /* 0xc8 TODO: bswap */ + /* 0xc9 TODO: bswap */ + /* 0xca TODO: bswap */ + /* 0xcb TODO: bswap */ + /* 0xcc TODO: bswap */ + /* 0xcd TODO: bswap */ + /* 0xce TODO: bswap */ + /* 0xcf TODO: bswap */ + + default: + x86emu_halt_sys(emu); + break; + } +} + +/* +* Carry Chain Calculation +* +* This represents a somewhat expensive calculation which is +* apparently required to emulate the setting of the OF and AF flag. +* The latter is not so important, but the former is. The overflow +* flag is the XOR of the top two bits of the carry chain for an +* addition (similar for subtraction). Since we do not want to +* simulate the addition in a bitwise manner, we try to calculate the +* carry chain given the two operands and the result. +* +* So, given the following table, which represents the addition of two +* bits, we can derive a formula for the carry chain. +* +* a b cin r cout +* 0 0 0 0 0 +* 0 0 1 1 0 +* 0 1 0 1 0 +* 0 1 1 0 1 +* 1 0 0 1 0 +* 1 0 1 0 1 +* 1 1 0 0 1 +* 1 1 1 1 1 +* +* Construction of table for cout: +* +* ab +* r \ 00 01 11 10 +* |------------------ +* 0 | 0 1 1 1 +* 1 | 0 0 1 0 +* +* By inspection, one gets: cc = ab + r'(a + b) +* +* That represents alot of operations, but NO CHOICE.... +* +* Borrow Chain Calculation. +* +* The following table represents the subtraction of two bits, from +* which we can derive a formula for the borrow chain. +* +* a b bin r bout +* 0 0 0 0 0 +* 0 0 1 1 1 +* 0 1 0 1 1 +* 0 1 1 0 1 +* 1 0 0 1 0 +* 1 0 1 0 0 +* 1 1 0 0 0 +* 1 1 1 1 1 +* +* Construction of table for cout: +* +* ab +* r \ 00 01 11 10 +* |------------------ +* 0 | 0 1 0 0 +* 1 | 1 1 1 0 +* +* By inspection, one gets: bc = a'b + r(a' + b) +* + */ + +/*------------------------- Global Variables ------------------------------*/ + +static uint32_t x86emu_parity_tab[8] = +{ + 0x96696996, + 0x69969669, + 0x69969669, + 0x96696996, + 0x69969669, + 0x96696996, + 0x96696996, + 0x69969669, +}; +#define PARITY(x) (((x86emu_parity_tab[(x) / 32] >> ((x) % 32)) & 1) == 0) +#define XOR2(x) (((x) ^ ((x)>>1)) & 0x1) + + +/* + * REMARKS: + * Implements the AAA instruction and side effects. + */ +static uint16_t +aaa_word(struct x86emu *emu, uint16_t d) +{ + uint16_t res; + if ((d & 0xf) > 0x9 || ACCESS_FLAG(F_AF)) { + d += 0x6; + d += 0x100; + SET_FLAG(F_AF); + SET_FLAG(F_CF); + } else { + CLEAR_FLAG(F_CF); + CLEAR_FLAG(F_AF); + } + res = (uint16_t) (d & 0xFF0F); + CLEAR_FLAG(F_SF); + CONDITIONAL_SET_FLAG(res == 0, F_ZF); + CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF); + return res; +} + +/* + * REMARKS: + * Implements the AAA instruction and side effects. + */ +static uint16_t +aas_word(struct x86emu *emu, uint16_t d) +{ + uint16_t res; + if ((d & 0xf) > 0x9 || ACCESS_FLAG(F_AF)) { + d -= 0x6; + d -= 0x100; + SET_FLAG(F_AF); + SET_FLAG(F_CF); + } else { + CLEAR_FLAG(F_CF); + CLEAR_FLAG(F_AF); + } + res = (uint16_t) (d & 0xFF0F); + CLEAR_FLAG(F_SF); + CONDITIONAL_SET_FLAG(res == 0, F_ZF); + CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF); + return res; +} + +/* + * REMARKS: + * Implements the AAD instruction and side effects. + */ +static uint16_t +aad_word(struct x86emu *emu, uint16_t d) +{ + uint16_t l; + uint8_t hb, lb; + + hb = (uint8_t) ((d >> 8) & 0xff); + lb = (uint8_t) ((d & 0xff)); + l = (uint16_t) ((lb + 10 * hb) & 0xFF); + + CLEAR_FLAG(F_CF); + CLEAR_FLAG(F_AF); + CLEAR_FLAG(F_OF); + CONDITIONAL_SET_FLAG(l & 0x80, F_SF); + CONDITIONAL_SET_FLAG(l == 0, F_ZF); + CONDITIONAL_SET_FLAG(PARITY(l & 0xff), F_PF); + return l; +} + +/* + * REMARKS: + * Implements the AAM instruction and side effects. + */ +static uint16_t +aam_word(struct x86emu *emu, uint8_t d) +{ + uint16_t h, l; + + h = (uint16_t) (d / 10); + l = (uint16_t) (d % 10); + l |= (uint16_t) (h << 8); + + CLEAR_FLAG(F_CF); + CLEAR_FLAG(F_AF); + CLEAR_FLAG(F_OF); + CONDITIONAL_SET_FLAG(l & 0x80, F_SF); + CONDITIONAL_SET_FLAG(l == 0, F_ZF); + CONDITIONAL_SET_FLAG(PARITY(l & 0xff), F_PF); + return l; +} + +/* + * REMARKS: + * Implements the ADC instruction and side effects. + */ +static uint8_t +adc_byte(struct x86emu *emu, uint8_t d, uint8_t s) +{ + uint32_t res; /* all operands in native machine order */ + uint32_t cc; + + if (ACCESS_FLAG(F_CF)) + res = 1 + d + s; + else + res = d + s; + + CONDITIONAL_SET_FLAG(res & 0x100, F_CF); + CONDITIONAL_SET_FLAG((res & 0xff) == 0, F_ZF); + CONDITIONAL_SET_FLAG(res & 0x80, F_SF); + CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF); + + /* calculate the carry chain SEE NOTE AT TOP. */ + cc = (s & d) | ((~res) & (s | d)); + CONDITIONAL_SET_FLAG(XOR2(cc >> 6), F_OF); + CONDITIONAL_SET_FLAG(cc & 0x8, F_AF); + return (uint8_t) res; +} + +/* + * REMARKS: + * Implements the ADC instruction and side effects. + */ +static uint16_t +adc_word(struct x86emu *emu, uint16_t d, uint16_t s) +{ + uint32_t res; /* all operands in native machine order */ + uint32_t cc; + + if (ACCESS_FLAG(F_CF)) + res = 1 + d + s; + else + res = d + s; + + CONDITIONAL_SET_FLAG(res & 0x10000, F_CF); + CONDITIONAL_SET_FLAG((res & 0xffff) == 0, F_ZF); + CONDITIONAL_SET_FLAG(res & 0x8000, F_SF); + CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF); + + /* calculate the carry chain SEE NOTE AT TOP. */ + cc = (s & d) | ((~res) & (s | d)); + CONDITIONAL_SET_FLAG(XOR2(cc >> 14), F_OF); + CONDITIONAL_SET_FLAG(cc & 0x8, F_AF); + return (uint16_t) res; +} + +/* + * REMARKS: + * Implements the ADC instruction and side effects. + */ +static uint32_t +adc_long(struct x86emu *emu, uint32_t d, uint32_t s) +{ + uint32_t lo; /* all operands in native machine order */ + uint32_t hi; + uint32_t res; + uint32_t cc; + + if (ACCESS_FLAG(F_CF)) { + lo = 1 + (d & 0xFFFF) + (s & 0xFFFF); + res = 1 + d + s; + } else { + lo = (d & 0xFFFF) + (s & 0xFFFF); + res = d + s; + } + hi = (lo >> 16) + (d >> 16) + (s >> 16); + + CONDITIONAL_SET_FLAG(hi & 0x10000, F_CF); + CONDITIONAL_SET_FLAG((res & 0xffffffff) == 0, F_ZF); + CONDITIONAL_SET_FLAG(res & 0x80000000, F_SF); + CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF); + + /* calculate the carry chain SEE NOTE AT TOP. */ + cc = (s & d) | ((~res) & (s | d)); + CONDITIONAL_SET_FLAG(XOR2(cc >> 30), F_OF); + CONDITIONAL_SET_FLAG(cc & 0x8, F_AF); + return res; +} + +/* + * REMARKS: + * Implements the ADD instruction and side effects. + */ +static uint8_t +add_byte(struct x86emu *emu, uint8_t d, uint8_t s) +{ + uint32_t res; /* all operands in native machine order */ + uint32_t cc; + + res = d + s; + CONDITIONAL_SET_FLAG(res & 0x100, F_CF); + CONDITIONAL_SET_FLAG((res & 0xff) == 0, F_ZF); + CONDITIONAL_SET_FLAG(res & 0x80, F_SF); + CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF); + + /* calculate the carry chain SEE NOTE AT TOP. */ + cc = (s & d) | ((~res) & (s | d)); + CONDITIONAL_SET_FLAG(XOR2(cc >> 6), F_OF); + CONDITIONAL_SET_FLAG(cc & 0x8, F_AF); + return (uint8_t) res; +} + +/* + * REMARKS: + * Implements the ADD instruction and side effects. + */ +static uint16_t +add_word(struct x86emu *emu, uint16_t d, uint16_t s) +{ + uint32_t res; /* all operands in native machine order */ + uint32_t cc; + + res = d + s; + CONDITIONAL_SET_FLAG(res & 0x10000, F_CF); + CONDITIONAL_SET_FLAG((res & 0xffff) == 0, F_ZF); + CONDITIONAL_SET_FLAG(res & 0x8000, F_SF); + CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF); + + /* calculate the carry chain SEE NOTE AT TOP. */ + cc = (s & d) | ((~res) & (s | d)); + CONDITIONAL_SET_FLAG(XOR2(cc >> 14), F_OF); + CONDITIONAL_SET_FLAG(cc & 0x8, F_AF); + return (uint16_t) res; +} + +/* + * REMARKS: + * Implements the ADD instruction and side effects. + */ +static uint32_t +add_long(struct x86emu *emu, uint32_t d, uint32_t s) +{ + uint32_t lo; /* all operands in native machine order */ + uint32_t hi; + uint32_t res; + uint32_t cc; + + lo = (d & 0xFFFF) + (s & 0xFFFF); + res = d + s; + hi = (lo >> 16) + (d >> 16) + (s >> 16); + + CONDITIONAL_SET_FLAG(hi & 0x10000, F_CF); + CONDITIONAL_SET_FLAG((res & 0xffffffff) == 0, F_ZF); + CONDITIONAL_SET_FLAG(res & 0x80000000, F_SF); + CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF); + + /* calculate the carry chain SEE NOTE AT TOP. */ + cc = (s & d) | ((~res) & (s | d)); + CONDITIONAL_SET_FLAG(XOR2(cc >> 30), F_OF); + CONDITIONAL_SET_FLAG(cc & 0x8, F_AF); + + return res; +} + +/* + * REMARKS: + * Implements the AND instruction and side effects. + */ +static uint8_t +and_byte(struct x86emu *emu, uint8_t d, uint8_t s) +{ + uint8_t res; /* all operands in native machine order */ + + res = d & s; + + /* set the flags */ + CLEAR_FLAG(F_OF); + CLEAR_FLAG(F_CF); + CLEAR_FLAG(F_AF); + CONDITIONAL_SET_FLAG(res & 0x80, F_SF); + CONDITIONAL_SET_FLAG(res == 0, F_ZF); + CONDITIONAL_SET_FLAG(PARITY(res), F_PF); + return res; +} + +/* + * REMARKS: + * Implements the AND instruction and side effects. + */ +static uint16_t +and_word(struct x86emu *emu, uint16_t d, uint16_t s) +{ + uint16_t res; /* all operands in native machine order */ + + res = d & s; + + /* set the flags */ + CLEAR_FLAG(F_OF); + CLEAR_FLAG(F_CF); + CLEAR_FLAG(F_AF); + CONDITIONAL_SET_FLAG(res & 0x8000, F_SF); + CONDITIONAL_SET_FLAG(res == 0, F_ZF); + CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF); + return res; +} + +/* + * REMARKS: + * Implements the AND instruction and side effects. + */ +static uint32_t +and_long(struct x86emu *emu, uint32_t d, uint32_t s) +{ + uint32_t res; /* all operands in native machine order */ + + res = d & s; + + /* set the flags */ + CLEAR_FLAG(F_OF); + CLEAR_FLAG(F_CF); + CLEAR_FLAG(F_AF); + CONDITIONAL_SET_FLAG(res & 0x80000000, F_SF); + CONDITIONAL_SET_FLAG(res == 0, F_ZF); + CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF); + return res; +} + +/* + * REMARKS: + * Implements the CMP instruction and side effects. + */ +static uint8_t +cmp_byte(struct x86emu *emu, uint8_t d, uint8_t s) +{ + uint32_t res; /* all operands in native machine order */ + uint32_t bc; + + res = d - s; + CLEAR_FLAG(F_CF); + CONDITIONAL_SET_FLAG(res & 0x80, F_SF); + CONDITIONAL_SET_FLAG((res & 0xff) == 0, F_ZF); + CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF); + + /* calculate the borrow chain. See note at top */ + bc = (res & (~d | s)) | (~d & s); + CONDITIONAL_SET_FLAG(bc & 0x80, F_CF); + CONDITIONAL_SET_FLAG(XOR2(bc >> 6), F_OF); + CONDITIONAL_SET_FLAG(bc & 0x8, F_AF); + return d; +} + +static void +cmp_byte_no_return(struct x86emu *emu, uint8_t d, uint8_t s) +{ + cmp_byte(emu, d, s); +} + +/* + * REMARKS: + * Implements the CMP instruction and side effects. + */ +static uint16_t +cmp_word(struct x86emu *emu, uint16_t d, uint16_t s) +{ + uint32_t res; /* all operands in native machine order */ + uint32_t bc; + + res = d - s; + CONDITIONAL_SET_FLAG(res & 0x8000, F_SF); + CONDITIONAL_SET_FLAG((res & 0xffff) == 0, F_ZF); + CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF); + + /* calculate the borrow chain. See note at top */ + bc = (res & (~d | s)) | (~d & s); + CONDITIONAL_SET_FLAG(bc & 0x8000, F_CF); + CONDITIONAL_SET_FLAG(XOR2(bc >> 14), F_OF); + CONDITIONAL_SET_FLAG(bc & 0x8, F_AF); + return d; +} + +static void +cmp_word_no_return(struct x86emu *emu, uint16_t d, uint16_t s) +{ + cmp_word(emu, d, s); +} + +/* + * REMARKS: + * Implements the CMP instruction and side effects. + */ +static uint32_t +cmp_long(struct x86emu *emu, uint32_t d, uint32_t s) +{ + uint32_t res; /* all operands in native machine order */ + uint32_t bc; + + res = d - s; + CONDITIONAL_SET_FLAG(res & 0x80000000, F_SF); + CONDITIONAL_SET_FLAG((res & 0xffffffff) == 0, F_ZF); + CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF); + + /* calculate the borrow chain. See note at top */ + bc = (res & (~d | s)) | (~d & s); + CONDITIONAL_SET_FLAG(bc & 0x80000000, F_CF); + CONDITIONAL_SET_FLAG(XOR2(bc >> 30), F_OF); + CONDITIONAL_SET_FLAG(bc & 0x8, F_AF); + return d; +} + +static void +cmp_long_no_return(struct x86emu *emu, uint32_t d, uint32_t s) +{ + cmp_long(emu, d, s); +} + +/* + * REMARKS: + * Implements the DAA instruction and side effects. + */ +static uint8_t +daa_byte(struct x86emu *emu, uint8_t d) +{ + uint32_t res = d; + if ((d & 0xf) > 9 || ACCESS_FLAG(F_AF)) { + res += 6; + SET_FLAG(F_AF); + } + if (res > 0x9F || ACCESS_FLAG(F_CF)) { + res += 0x60; + SET_FLAG(F_CF); + } + CONDITIONAL_SET_FLAG(res & 0x80, F_SF); + CONDITIONAL_SET_FLAG((res & 0xFF) == 0, F_ZF); + CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF); + return (uint8_t) res; +} + +/* + * REMARKS: + * Implements the DAS instruction and side effects. + */ +static uint8_t +das_byte(struct x86emu *emu, uint8_t d) +{ + if ((d & 0xf) > 9 || ACCESS_FLAG(F_AF)) { + d -= 6; + SET_FLAG(F_AF); + } + if (d > 0x9F || ACCESS_FLAG(F_CF)) { + d -= 0x60; + SET_FLAG(F_CF); + } + CONDITIONAL_SET_FLAG(d & 0x80, F_SF); + CONDITIONAL_SET_FLAG(d == 0, F_ZF); + CONDITIONAL_SET_FLAG(PARITY(d & 0xff), F_PF); + return d; +} + +/* + * REMARKS: + * Implements the DEC instruction and side effects. + */ +static uint8_t +dec_byte(struct x86emu *emu, uint8_t d) +{ + uint32_t res; /* all operands in native machine order */ + uint32_t bc; + + res = d - 1; + CONDITIONAL_SET_FLAG(res & 0x80, F_SF); + CONDITIONAL_SET_FLAG((res & 0xff) == 0, F_ZF); + CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF); + + /* calculate the borrow chain. See note at top */ + /* based on sub_byte, uses s==1. */ + bc = (res & (~d | 1)) | (~d & 1); + /* carry flag unchanged */ + CONDITIONAL_SET_FLAG(XOR2(bc >> 6), F_OF); + CONDITIONAL_SET_FLAG(bc & 0x8, F_AF); + return (uint8_t) res; +} + +/* + * REMARKS: + * Implements the DEC instruction and side effects. + */ +static uint16_t +dec_word(struct x86emu *emu, uint16_t d) +{ + uint32_t res; /* all operands in native machine order */ + uint32_t bc; + + res = d - 1; + CONDITIONAL_SET_FLAG(res & 0x8000, F_SF); + CONDITIONAL_SET_FLAG((res & 0xffff) == 0, F_ZF); + CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF); + + /* calculate the borrow chain. See note at top */ + /* based on the sub_byte routine, with s==1 */ + bc = (res & (~d | 1)) | (~d & 1); + /* carry flag unchanged */ + CONDITIONAL_SET_FLAG(XOR2(bc >> 14), F_OF); + CONDITIONAL_SET_FLAG(bc & 0x8, F_AF); + return (uint16_t) res; +} + +/* + * REMARKS: + * Implements the DEC instruction and side effects. + */ +static uint32_t +dec_long(struct x86emu *emu, uint32_t d) +{ + uint32_t res; /* all operands in native machine order */ + uint32_t bc; + + res = d - 1; + + CONDITIONAL_SET_FLAG(res & 0x80000000, F_SF); + CONDITIONAL_SET_FLAG((res & 0xffffffff) == 0, F_ZF); + CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF); + + /* calculate the borrow chain. See note at top */ + bc = (res & (~d | 1)) | (~d & 1); + /* carry flag unchanged */ + CONDITIONAL_SET_FLAG(XOR2(bc >> 30), F_OF); + CONDITIONAL_SET_FLAG(bc & 0x8, F_AF); + return res; +} + +/* + * REMARKS: + * Implements the INC instruction and side effects. + */ +static uint8_t +inc_byte(struct x86emu *emu, uint8_t d) +{ + uint32_t res; /* all operands in native machine order */ + uint32_t cc; + + res = d + 1; + CONDITIONAL_SET_FLAG((res & 0xff) == 0, F_ZF); + CONDITIONAL_SET_FLAG(res & 0x80, F_SF); + CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF); + + /* calculate the carry chain SEE NOTE AT TOP. */ + cc = ((1 & d) | (~res)) & (1 | d); + CONDITIONAL_SET_FLAG(XOR2(cc >> 6), F_OF); + CONDITIONAL_SET_FLAG(cc & 0x8, F_AF); + return (uint8_t) res; +} + +/* + * REMARKS: + * Implements the INC instruction and side effects. + */ +static uint16_t +inc_word(struct x86emu *emu, uint16_t d) +{ + uint32_t res; /* all operands in native machine order */ + uint32_t cc; + + res = d + 1; + CONDITIONAL_SET_FLAG((res & 0xffff) == 0, F_ZF); + CONDITIONAL_SET_FLAG(res & 0x8000, F_SF); + CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF); + + /* calculate the carry chain SEE NOTE AT TOP. */ + cc = (1 & d) | ((~res) & (1 | d)); + CONDITIONAL_SET_FLAG(XOR2(cc >> 14), F_OF); + CONDITIONAL_SET_FLAG(cc & 0x8, F_AF); + return (uint16_t) res; +} + +/* + * REMARKS: + * Implements the INC instruction and side effects. + */ +static uint32_t +inc_long(struct x86emu *emu, uint32_t d) +{ + uint32_t res; /* all operands in native machine order */ + uint32_t cc; + + res = d + 1; + CONDITIONAL_SET_FLAG((res & 0xffffffff) == 0, F_ZF); + CONDITIONAL_SET_FLAG(res & 0x80000000, F_SF); + CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF); + + /* calculate the carry chain SEE NOTE AT TOP. */ + cc = (1 & d) | ((~res) & (1 | d)); + CONDITIONAL_SET_FLAG(XOR2(cc >> 30), F_OF); + CONDITIONAL_SET_FLAG(cc & 0x8, F_AF); + return res; +} + +/* + * REMARKS: + * Implements the OR instruction and side effects. + */ +static uint8_t +or_byte(struct x86emu *emu, uint8_t d, uint8_t s) +{ + uint8_t res; /* all operands in native machine order */ + + res = d | s; + CLEAR_FLAG(F_OF); + CLEAR_FLAG(F_CF); + CLEAR_FLAG(F_AF); + CONDITIONAL_SET_FLAG(res & 0x80, F_SF); + CONDITIONAL_SET_FLAG(res == 0, F_ZF); + CONDITIONAL_SET_FLAG(PARITY(res), F_PF); + return res; +} + +/* + * REMARKS: + * Implements the OR instruction and side effects. + */ +static uint16_t +or_word(struct x86emu *emu, uint16_t d, uint16_t s) +{ + uint16_t res; /* all operands in native machine order */ + + res = d | s; + /* set the carry flag to be bit 8 */ + CLEAR_FLAG(F_OF); + CLEAR_FLAG(F_CF); + CLEAR_FLAG(F_AF); + CONDITIONAL_SET_FLAG(res & 0x8000, F_SF); + CONDITIONAL_SET_FLAG(res == 0, F_ZF); + CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF); + return res; +} + +/* + * REMARKS: + * Implements the OR instruction and side effects. + */ +static uint32_t +or_long(struct x86emu *emu, uint32_t d, uint32_t s) +{ + uint32_t res; /* all operands in native machine order */ + + res = d | s; + + /* set the carry flag to be bit 8 */ + CLEAR_FLAG(F_OF); + CLEAR_FLAG(F_CF); + CLEAR_FLAG(F_AF); + CONDITIONAL_SET_FLAG(res & 0x80000000, F_SF); + CONDITIONAL_SET_FLAG(res == 0, F_ZF); + CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF); + return res; +} + +/* + * REMARKS: + * Implements the OR instruction and side effects. + */ +static uint8_t +neg_byte(struct x86emu *emu, uint8_t s) +{ + uint8_t res; + uint8_t bc; + + CONDITIONAL_SET_FLAG(s != 0, F_CF); + res = (uint8_t) - s; + CONDITIONAL_SET_FLAG((res & 0xff) == 0, F_ZF); + CONDITIONAL_SET_FLAG(res & 0x80, F_SF); + CONDITIONAL_SET_FLAG(PARITY(res), F_PF); + /* calculate the borrow chain --- modified such that d=0. + * substitutiing d=0 into bc= res&(~d|s)|(~d&s); (the one used for + * sub) and simplifying, since ~d=0xff..., ~d|s == 0xffff..., and + * res&0xfff... == res. Similarly ~d&s == s. So the simplified + * result is: */ + bc = res | s; + CONDITIONAL_SET_FLAG(XOR2(bc >> 6), F_OF); + CONDITIONAL_SET_FLAG(bc & 0x8, F_AF); + return res; +} + +/* + * REMARKS: + * Implements the OR instruction and side effects. + */ +static uint16_t +neg_word(struct x86emu *emu, uint16_t s) +{ + uint16_t res; + uint16_t bc; + + CONDITIONAL_SET_FLAG(s != 0, F_CF); + res = (uint16_t) - s; + CONDITIONAL_SET_FLAG((res & 0xffff) == 0, F_ZF); + CONDITIONAL_SET_FLAG(res & 0x8000, F_SF); + CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF); + + /* calculate the borrow chain --- modified such that d=0. + * substitutiing d=0 into bc= res&(~d|s)|(~d&s); (the one used for + * sub) and simplifying, since ~d=0xff..., ~d|s == 0xffff..., and + * res&0xfff... == res. Similarly ~d&s == s. So the simplified + * result is: */ + bc = res | s; + CONDITIONAL_SET_FLAG(XOR2(bc >> 14), F_OF); + CONDITIONAL_SET_FLAG(bc & 0x8, F_AF); + return res; +} + +/* + * REMARKS: + * Implements the OR instruction and side effects. + */ +static uint32_t +neg_long(struct x86emu *emu, uint32_t s) +{ + uint32_t res; + uint32_t bc; + + CONDITIONAL_SET_FLAG(s != 0, F_CF); + res = (uint32_t) - s; + CONDITIONAL_SET_FLAG((res & 0xffffffff) == 0, F_ZF); + CONDITIONAL_SET_FLAG(res & 0x80000000, F_SF); + CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF); + + /* calculate the borrow chain --- modified such that d=0. + * substitutiing d=0 into bc= res&(~d|s)|(~d&s); (the one used for + * sub) and simplifying, since ~d=0xff..., ~d|s == 0xffff..., and + * res&0xfff... == res. Similarly ~d&s == s. So the simplified + * result is: */ + bc = res | s; + CONDITIONAL_SET_FLAG(XOR2(bc >> 30), F_OF); + CONDITIONAL_SET_FLAG(bc & 0x8, F_AF); + return res; +} + +/* + * REMARKS: + * Implements the RCL instruction and side effects. + */ +static uint8_t +rcl_byte(struct x86emu *emu, uint8_t d, uint8_t s) +{ + unsigned int res, cnt, mask, cf; + + /* s is the rotate distance. It varies from 0 - 8. */ + /* have + * + * CF B_7 B_6 B_5 B_4 B_3 B_2 B_1 B_0 + * + * want to rotate through the carry by "s" bits. We could loop, but + * that's inefficient. So the width is 9, and we split into three + * parts: + * + * The new carry flag (was B_n) the stuff in B_n-1 .. B_0 the stuff in + * B_7 .. B_n+1 + * + * The new rotate is done mod 9, and given this, for a rotation of n bits + * (mod 9) the new carry flag is then located n bits from the MSB. + * The low part is then shifted up cnt bits, and the high part is or'd + * in. Using CAPS for new values, and lowercase for the original + * values, this can be expressed as: + * + * IF n > 0 1) CF <- b_(8-n) 2) B_(7) .. B_(n) <- b_(8-(n+1)) .. b_0 + * 3) B_(n-1) <- cf 4) B_(n-2) .. B_0 <- b_7 .. b_(8-(n-1)) */ + res = d; + if ((cnt = s % 9) != 0) { + /* extract the new CARRY FLAG. */ + /* CF <- b_(8-n) */ + cf = (d >> (8 - cnt)) & 0x1; + + /* get the low stuff which rotated into the range B_7 .. B_cnt */ + /* B_(7) .. B_(n) <- b_(8-(n+1)) .. b_0 */ + /* note that the right hand side done by the mask */ + res = (d << cnt) & 0xff; + + /* now the high stuff which rotated around into the positions + * B_cnt-2 .. B_0 */ + /* B_(n-2) .. B_0 <- b_7 .. b_(8-(n-1)) */ + /* shift it downward, 7-(n-2) = 9-n positions. and mask off + * the result before or'ing in. */ + mask = (1 << (cnt - 1)) - 1; + res |= (d >> (9 - cnt)) & mask; + + /* if the carry flag was set, or it in. */ + if (ACCESS_FLAG(F_CF)) { /* carry flag is set */ + /* B_(n-1) <- cf */ + res |= 1 << (cnt - 1); + } + /* set the new carry flag, based on the variable "cf" */ + CONDITIONAL_SET_FLAG(cf, F_CF); + /* OVERFLOW is set *IFF* cnt==1, then it is the xor of CF and + * the most significant bit. Blecck. */ + /* parenthesized this expression since it appears to be + * causing OF to be misset */ + CONDITIONAL_SET_FLAG(cnt == 1 && XOR2(cf + ((res >> 6) & 0x2)), + F_OF); + + } + return (uint8_t) res; +} + +/* + * REMARKS: + * Implements the RCL instruction and side effects. + */ +static uint16_t +rcl_word(struct x86emu *emu, uint16_t d, uint8_t s) +{ + unsigned int res, cnt, mask, cf; + + res = d; + if ((cnt = s % 17) != 0) { + cf = (d >> (16 - cnt)) & 0x1; + res = (d << cnt) & 0xffff; + mask = (1 << (cnt - 1)) - 1; + res |= (d >> (17 - cnt)) & mask; + if (ACCESS_FLAG(F_CF)) { + res |= 1 << (cnt - 1); + } + CONDITIONAL_SET_FLAG(cf, F_CF); + CONDITIONAL_SET_FLAG(cnt == 1 && XOR2(cf + ((res >> 14) & 0x2)), + F_OF); + } + return (uint16_t) res; +} + +/* + * REMARKS: + * Implements the RCL instruction and side effects. + */ +static uint32_t +rcl_long(struct x86emu *emu, uint32_t d, uint8_t s) +{ + uint32_t res, cnt, mask, cf; + + res = d; + if ((cnt = s % 33) != 0) { + cf = (d >> (32 - cnt)) & 0x1; + res = (d << cnt) & 0xffffffff; + mask = (1 << (cnt - 1)) - 1; + res |= (d >> (33 - cnt)) & mask; + if (ACCESS_FLAG(F_CF)) { /* carry flag is set */ + res |= 1 << (cnt - 1); + } + CONDITIONAL_SET_FLAG(cf, F_CF); + CONDITIONAL_SET_FLAG(cnt == 1 && XOR2(cf + ((res >> 30) & 0x2)), + F_OF); + } + return res; +} + +/* + * REMARKS: + * Implements the RCR instruction and side effects. + */ +static uint8_t +rcr_byte(struct x86emu *emu, uint8_t d, uint8_t s) +{ + uint32_t res, cnt; + uint32_t mask, cf, ocf = 0; + + /* rotate right through carry */ + /* s is the rotate distance. It varies from 0 - 8. d is the byte + * object rotated. + * + * have + * + * CF B_7 B_6 B_5 B_4 B_3 B_2 B_1 B_0 + * + * The new rotate is done mod 9, and given this, for a rotation of n bits + * (mod 9) the new carry flag is then located n bits from the LSB. + * The low part is then shifted up cnt bits, and the high part is or'd + * in. Using CAPS for new values, and lowercase for the original + * values, this can be expressed as: + * + * IF n > 0 1) CF <- b_(n-1) 2) B_(8-(n+1)) .. B_(0) <- b_(7) .. b_(n) + * 3) B_(8-n) <- cf 4) B_(7) .. B_(8-(n-1)) <- b_(n-2) .. b_(0) */ + res = d; + if ((cnt = s % 9) != 0) { + /* extract the new CARRY FLAG. */ + /* CF <- b_(n-1) */ + if (cnt == 1) { + cf = d & 0x1; + /* note hackery here. Access_flag(..) evaluates to + * either 0 if flag not set non-zero if flag is set. + * doing access_flag(..) != 0 casts that into either + * 0..1 in any representation of the flags register + * (i.e. packed bit array or unpacked.) */ + ocf = ACCESS_FLAG(F_CF) != 0; + } else + cf = (d >> (cnt - 1)) & 0x1; + + /* B_(8-(n+1)) .. B_(0) <- b_(7) .. b_n */ + /* note that the right hand side done by the mask This is + * effectively done by shifting the object to the right. The + * result must be masked, in case the object came in and was + * treated as a negative number. Needed??? */ + + mask = (1 << (8 - cnt)) - 1; + res = (d >> cnt) & mask; + + /* now the high stuff which rotated around into the positions + * B_cnt-2 .. B_0 */ + /* B_(7) .. B_(8-(n-1)) <- b_(n-2) .. b_(0) */ + /* shift it downward, 7-(n-2) = 9-n positions. and mask off + * the result before or'ing in. */ + res |= (d << (9 - cnt)); + + /* if the carry flag was set, or it in. */ + if (ACCESS_FLAG(F_CF)) { /* carry flag is set */ + /* B_(8-n) <- cf */ + res |= 1 << (8 - cnt); + } + /* set the new carry flag, based on the variable "cf" */ + CONDITIONAL_SET_FLAG(cf, F_CF); + /* OVERFLOW is set *IFF* cnt==1, then it is the xor of CF and + * the most significant bit. Blecck. */ + /* parenthesized... */ + if (cnt == 1) { + CONDITIONAL_SET_FLAG(XOR2(ocf + ((d >> 6) & 0x2)), + F_OF); + } + } + return (uint8_t) res; +} + +/* + * REMARKS: + * Implements the RCR instruction and side effects. + */ +static uint16_t +rcr_word(struct x86emu *emu, uint16_t d, uint8_t s) +{ + uint32_t res, cnt; + uint32_t mask, cf, ocf = 0; + + /* rotate right through carry */ + res = d; + if ((cnt = s % 17) != 0) { + if (cnt == 1) { + cf = d & 0x1; + ocf = ACCESS_FLAG(F_CF) != 0; + } else + cf = (d >> (cnt - 1)) & 0x1; + mask = (1 << (16 - cnt)) - 1; + res = (d >> cnt) & mask; + res |= (d << (17 - cnt)); + if (ACCESS_FLAG(F_CF)) { + res |= 1 << (16 - cnt); + } + CONDITIONAL_SET_FLAG(cf, F_CF); + if (cnt == 1) { + CONDITIONAL_SET_FLAG(XOR2(ocf + ((d >> 14) & 0x2)), + F_OF); + } + } + return (uint16_t) res; +} + +/* + * REMARKS: + * Implements the RCR instruction and side effects. + */ +static uint32_t +rcr_long(struct x86emu *emu, uint32_t d, uint8_t s) +{ + uint32_t res, cnt; + uint32_t mask, cf, ocf = 0; + + /* rotate right through carry */ + res = d; + if ((cnt = s % 33) != 0) { + if (cnt == 1) { + cf = d & 0x1; + ocf = ACCESS_FLAG(F_CF) != 0; + } else + cf = (d >> (cnt - 1)) & 0x1; + mask = (1 << (32 - cnt)) - 1; + res = (d >> cnt) & mask; + if (cnt != 1) + res |= (d << (33 - cnt)); + if (ACCESS_FLAG(F_CF)) { /* carry flag is set */ + res |= 1 << (32 - cnt); + } + CONDITIONAL_SET_FLAG(cf, F_CF); + if (cnt == 1) { + CONDITIONAL_SET_FLAG(XOR2(ocf + ((d >> 30) & 0x2)), + F_OF); + } + } + return res; +} + +/* + * REMARKS: + * Implements the ROL instruction and side effects. + */ +static uint8_t +rol_byte(struct x86emu *emu, uint8_t d, uint8_t s) +{ + unsigned int res, cnt, mask; + + /* rotate left */ + /* s is the rotate distance. It varies from 0 - 8. d is the byte + * object rotated. + * + * have + * + * CF B_7 ... B_0 + * + * The new rotate is done mod 8. Much simpler than the "rcl" or "rcr" + * operations. + * + * IF n > 0 1) B_(7) .. B_(n) <- b_(8-(n+1)) .. b_(0) 2) B_(n-1) .. + * B_(0) <- b_(7) .. b_(8-n) */ + res = d; + if ((cnt = s % 8) != 0) { + /* B_(7) .. B_(n) <- b_(8-(n+1)) .. b_(0) */ + res = (d << cnt); + + /* B_(n-1) .. B_(0) <- b_(7) .. b_(8-n) */ + mask = (1 << cnt) - 1; + res |= (d >> (8 - cnt)) & mask; + + /* set the new carry flag, Note that it is the low order bit + * of the result!!! */ + CONDITIONAL_SET_FLAG(res & 0x1, F_CF); + /* OVERFLOW is set *IFF* s==1, then it is the xor of CF and + * the most significant bit. Blecck. */ + CONDITIONAL_SET_FLAG(s == 1 && + XOR2((res & 0x1) + ((res >> 6) & 0x2)), + F_OF); + } if (s != 0) { + /* set the new carry flag, Note that it is the low order bit + * of the result!!! */ + CONDITIONAL_SET_FLAG(res & 0x1, F_CF); + } + return (uint8_t) res; +} + +/* + * REMARKS: + * Implements the ROL instruction and side effects. + */ +static uint16_t +rol_word(struct x86emu *emu, uint16_t d, uint8_t s) +{ + unsigned int res, cnt, mask; + + res = d; + if ((cnt = s % 16) != 0) { + res = (d << cnt); + mask = (1 << cnt) - 1; + res |= (d >> (16 - cnt)) & mask; + CONDITIONAL_SET_FLAG(res & 0x1, F_CF); + CONDITIONAL_SET_FLAG(s == 1 && + XOR2((res & 0x1) + ((res >> 14) & 0x2)), + F_OF); + } if (s != 0) { + /* set the new carry flag, Note that it is the low order bit + * of the result!!! */ + CONDITIONAL_SET_FLAG(res & 0x1, F_CF); + } + return (uint16_t) res; +} + +/* + * REMARKS: + * Implements the ROL instruction and side effects. + */ +static uint32_t +rol_long(struct x86emu *emu, uint32_t d, uint8_t s) +{ + uint32_t res, cnt, mask; + + res = d; + if ((cnt = s % 32) != 0) { + res = (d << cnt); + mask = (1 << cnt) - 1; + res |= (d >> (32 - cnt)) & mask; + CONDITIONAL_SET_FLAG(res & 0x1, F_CF); + CONDITIONAL_SET_FLAG(s == 1 && + XOR2((res & 0x1) + ((res >> 30) & 0x2)), + F_OF); + } if (s != 0) { + /* set the new carry flag, Note that it is the low order bit + * of the result!!! */ + CONDITIONAL_SET_FLAG(res & 0x1, F_CF); + } + return res; +} + +/* + * REMARKS: + * Implements the ROR instruction and side effects. + */ +static uint8_t +ror_byte(struct x86emu *emu, uint8_t d, uint8_t s) +{ + unsigned int res, cnt, mask; + + /* rotate right */ + /* s is the rotate distance. It varies from 0 - 8. d is the byte + * object rotated. + * + * have + * + * B_7 ... B_0 + * + * The rotate is done mod 8. + * + * IF n > 0 1) B_(8-(n+1)) .. B_(0) <- b_(7) .. b_(n) 2) B_(7) .. + * B_(8-n) <- b_(n-1) .. b_(0) */ + res = d; + if ((cnt = s % 8) != 0) { /* not a typo, do nada if cnt==0 */ + /* B_(7) .. B_(8-n) <- b_(n-1) .. b_(0) */ + res = (d << (8 - cnt)); + + /* B_(8-(n+1)) .. B_(0) <- b_(7) .. b_(n) */ + mask = (1 << (8 - cnt)) - 1; + res |= (d >> (cnt)) & mask; + + /* set the new carry flag, Note that it is the low order bit + * of the result!!! */ + CONDITIONAL_SET_FLAG(res & 0x80, F_CF); + /* OVERFLOW is set *IFF* s==1, then it is the xor of the two + * most significant bits. Blecck. */ + CONDITIONAL_SET_FLAG(s == 1 && XOR2(res >> 6), F_OF); + } else if (s != 0) { + /* set the new carry flag, Note that it is the low order bit + * of the result!!! */ + CONDITIONAL_SET_FLAG(res & 0x80, F_CF); + } + return (uint8_t) res; +} + +/* + * REMARKS: + * Implements the ROR instruction and side effects. + */ +static uint16_t +ror_word(struct x86emu *emu, uint16_t d, uint8_t s) +{ + unsigned int res, cnt, mask; + + res = d; + if ((cnt = s % 16) != 0) { + res = (d << (16 - cnt)); + mask = (1 << (16 - cnt)) - 1; + res |= (d >> (cnt)) & mask; + CONDITIONAL_SET_FLAG(res & 0x8000, F_CF); + CONDITIONAL_SET_FLAG(s == 1 && XOR2(res >> 14), F_OF); + } else if (s != 0) { + /* set the new carry flag, Note that it is the low order bit + * of the result!!! */ + CONDITIONAL_SET_FLAG(res & 0x8000, F_CF); + } + return (uint16_t) res; +} + +/* + * REMARKS: + * Implements the ROR instruction and side effects. + */ +static uint32_t +ror_long(struct x86emu *emu, uint32_t d, uint8_t s) +{ + uint32_t res, cnt, mask; + + res = d; + if ((cnt = s % 32) != 0) { + res = (d << (32 - cnt)); + mask = (1 << (32 - cnt)) - 1; + res |= (d >> (cnt)) & mask; + CONDITIONAL_SET_FLAG(res & 0x80000000, F_CF); + CONDITIONAL_SET_FLAG(s == 1 && XOR2(res >> 30), F_OF); + } else if (s != 0) { + /* set the new carry flag, Note that it is the low order bit + * of the result!!! */ + CONDITIONAL_SET_FLAG(res & 0x80000000, F_CF); + } + return res; +} + +/* + * REMARKS: + * Implements the SHL instruction and side effects. + */ +static uint8_t +shl_byte(struct x86emu *emu, uint8_t d, uint8_t s) +{ + unsigned int cnt, res, cf; + + if (s < 8) { + cnt = s % 8; + + /* last bit shifted out goes into carry flag */ + if (cnt > 0) { + res = d << cnt; + cf = d & (1 << (8 - cnt)); + CONDITIONAL_SET_FLAG(cf, F_CF); + CONDITIONAL_SET_FLAG((res & 0xff) == 0, F_ZF); + CONDITIONAL_SET_FLAG(res & 0x80, F_SF); + CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF); + } else { + res = (uint8_t) d; + } + + if (cnt == 1) { + /* Needs simplification. */ + CONDITIONAL_SET_FLAG( + (((res & 0x80) == 0x80) ^ + (ACCESS_FLAG(F_CF) != 0)), + /* was (emu->x86.R_FLG&F_CF)==F_CF)), */ + F_OF); + } else { + CLEAR_FLAG(F_OF); + } + } else { + res = 0; + CONDITIONAL_SET_FLAG((d << (s - 1)) & 0x80, F_CF); + CLEAR_FLAG(F_OF); + CLEAR_FLAG(F_SF); + SET_FLAG(F_PF); + SET_FLAG(F_ZF); + } + return (uint8_t) res; +} + +/* + * REMARKS: + * Implements the SHL instruction and side effects. + */ +static uint16_t +shl_word(struct x86emu *emu, uint16_t d, uint8_t s) +{ + unsigned int cnt, res, cf; + + if (s < 16) { + cnt = s % 16; + if (cnt > 0) { + res = d << cnt; + cf = d & (1 << (16 - cnt)); + CONDITIONAL_SET_FLAG(cf, F_CF); + CONDITIONAL_SET_FLAG((res & 0xffff) == 0, F_ZF); + CONDITIONAL_SET_FLAG(res & 0x8000, F_SF); + CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF); + } else { + res = (uint16_t) d; + } + + if (cnt == 1) { + CONDITIONAL_SET_FLAG( + (((res & 0x8000) == 0x8000) ^ + (ACCESS_FLAG(F_CF) != 0)), + F_OF); + } else { + CLEAR_FLAG(F_OF); + } + } else { + res = 0; + CONDITIONAL_SET_FLAG((d << (s - 1)) & 0x8000, F_CF); + CLEAR_FLAG(F_OF); + CLEAR_FLAG(F_SF); + SET_FLAG(F_PF); + SET_FLAG(F_ZF); + } + return (uint16_t) res; +} + +/* + * REMARKS: + * Implements the SHL instruction and side effects. + */ +static uint32_t +shl_long(struct x86emu *emu, uint32_t d, uint8_t s) +{ + unsigned int cnt, res, cf; + + if (s < 32) { + cnt = s % 32; + if (cnt > 0) { + res = d << cnt; + cf = d & (1 << (32 - cnt)); + CONDITIONAL_SET_FLAG(cf, F_CF); + CONDITIONAL_SET_FLAG((res & 0xffffffff) == 0, F_ZF); + CONDITIONAL_SET_FLAG(res & 0x80000000, F_SF); + CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF); + } else { + res = d; + } + if (cnt == 1) { + CONDITIONAL_SET_FLAG((((res & 0x80000000) == 0x80000000) ^ + (ACCESS_FLAG(F_CF) != 0)), F_OF); + } else { + CLEAR_FLAG(F_OF); + } + } else { + res = 0; + CONDITIONAL_SET_FLAG((d << (s - 1)) & 0x80000000, F_CF); + CLEAR_FLAG(F_OF); + CLEAR_FLAG(F_SF); + SET_FLAG(F_PF); + SET_FLAG(F_ZF); + } + return res; +} + +/* + * REMARKS: + * Implements the SHR instruction and side effects. + */ +static uint8_t +shr_byte(struct x86emu *emu, uint8_t d, uint8_t s) +{ + unsigned int cnt, res, cf; + + if (s < 8) { + cnt = s % 8; + if (cnt > 0) { + cf = d & (1 << (cnt - 1)); + res = d >> cnt; + CONDITIONAL_SET_FLAG(cf, F_CF); + CONDITIONAL_SET_FLAG((res & 0xff) == 0, F_ZF); + CONDITIONAL_SET_FLAG(res & 0x80, F_SF); + CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF); + } else { + res = (uint8_t) d; + } + + if (cnt == 1) { + CONDITIONAL_SET_FLAG(XOR2(res >> 6), F_OF); + } else { + CLEAR_FLAG(F_OF); + } + } else { + res = 0; + CONDITIONAL_SET_FLAG((d >> (s - 1)) & 0x1, F_CF); + CLEAR_FLAG(F_OF); + CLEAR_FLAG(F_SF); + SET_FLAG(F_PF); + SET_FLAG(F_ZF); + } + return (uint8_t) res; +} + +/* + * REMARKS: + * Implements the SHR instruction and side effects. + */ +static uint16_t +shr_word(struct x86emu *emu, uint16_t d, uint8_t s) +{ + unsigned int cnt, res, cf; + + if (s < 16) { + cnt = s % 16; + if (cnt > 0) { + cf = d & (1 << (cnt - 1)); + res = d >> cnt; + CONDITIONAL_SET_FLAG(cf, F_CF); + CONDITIONAL_SET_FLAG((res & 0xffff) == 0, F_ZF); + CONDITIONAL_SET_FLAG(res & 0x8000, F_SF); + CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF); + } else { + res = d; + } + + if (cnt == 1) { + CONDITIONAL_SET_FLAG(XOR2(res >> 14), F_OF); + } else { + CLEAR_FLAG(F_OF); + } + } else { + res = 0; + CLEAR_FLAG(F_CF); + CLEAR_FLAG(F_OF); + SET_FLAG(F_ZF); + CLEAR_FLAG(F_SF); + CLEAR_FLAG(F_PF); + } + return (uint16_t) res; +} + +/* + * REMARKS: + * Implements the SHR instruction and side effects. + */ +static uint32_t +shr_long(struct x86emu *emu, uint32_t d, uint8_t s) +{ + unsigned int cnt, res, cf; + + if (s < 32) { + cnt = s % 32; + if (cnt > 0) { + cf = d & (1 << (cnt - 1)); + res = d >> cnt; + CONDITIONAL_SET_FLAG(cf, F_CF); + CONDITIONAL_SET_FLAG((res & 0xffffffff) == 0, F_ZF); + CONDITIONAL_SET_FLAG(res & 0x80000000, F_SF); + CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF); + } else { + res = d; + } + if (cnt == 1) { + CONDITIONAL_SET_FLAG(XOR2(res >> 30), F_OF); + } else { + CLEAR_FLAG(F_OF); + } + } else { + res = 0; + CLEAR_FLAG(F_CF); + CLEAR_FLAG(F_OF); + SET_FLAG(F_ZF); + CLEAR_FLAG(F_SF); + CLEAR_FLAG(F_PF); + } + return res; +} + +/* + * REMARKS: + * Implements the SAR instruction and side effects. + */ +static uint8_t +sar_byte(struct x86emu *emu, uint8_t d, uint8_t s) +{ + unsigned int cnt, res, cf, mask, sf; + + res = d; + sf = d & 0x80; + cnt = s % 8; + if (cnt > 0 && cnt < 8) { + mask = (1 << (8 - cnt)) - 1; + cf = d & (1 << (cnt - 1)); + res = (d >> cnt) & mask; + CONDITIONAL_SET_FLAG(cf, F_CF); + if (sf) { + res |= ~mask; + } + CONDITIONAL_SET_FLAG((res & 0xff) == 0, F_ZF); + CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF); + CONDITIONAL_SET_FLAG(res & 0x80, F_SF); + } else if (cnt >= 8) { + if (sf) { + res = 0xff; + SET_FLAG(F_CF); + CLEAR_FLAG(F_ZF); + SET_FLAG(F_SF); + SET_FLAG(F_PF); + } else { + res = 0; + CLEAR_FLAG(F_CF); + SET_FLAG(F_ZF); + CLEAR_FLAG(F_SF); + CLEAR_FLAG(F_PF); + } + } + return (uint8_t) res; +} + +/* + * REMARKS: + * Implements the SAR instruction and side effects. + */ +static uint16_t +sar_word(struct x86emu *emu, uint16_t d, uint8_t s) +{ + unsigned int cnt, res, cf, mask, sf; + + sf = d & 0x8000; + cnt = s % 16; + res = d; + if (cnt > 0 && cnt < 16) { + mask = (1 << (16 - cnt)) - 1; + cf = d & (1 << (cnt - 1)); + res = (d >> cnt) & mask; + CONDITIONAL_SET_FLAG(cf, F_CF); + if (sf) { + res |= ~mask; + } + CONDITIONAL_SET_FLAG((res & 0xffff) == 0, F_ZF); + CONDITIONAL_SET_FLAG(res & 0x8000, F_SF); + CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF); + } else if (cnt >= 16) { + if (sf) { + res = 0xffff; + SET_FLAG(F_CF); + CLEAR_FLAG(F_ZF); + SET_FLAG(F_SF); + SET_FLAG(F_PF); + } else { + res = 0; + CLEAR_FLAG(F_CF); + SET_FLAG(F_ZF); + CLEAR_FLAG(F_SF); + CLEAR_FLAG(F_PF); + } + } + return (uint16_t) res; +} + +/* + * REMARKS: + * Implements the SAR instruction and side effects. + */ +static uint32_t +sar_long(struct x86emu *emu, uint32_t d, uint8_t s) +{ + uint32_t cnt, res, cf, mask, sf; + + sf = d & 0x80000000; + cnt = s % 32; + res = d; + if (cnt > 0 && cnt < 32) { + mask = (1 << (32 - cnt)) - 1; + cf = d & (1 << (cnt - 1)); + res = (d >> cnt) & mask; + CONDITIONAL_SET_FLAG(cf, F_CF); + if (sf) { + res |= ~mask; + } + CONDITIONAL_SET_FLAG((res & 0xffffffff) == 0, F_ZF); + CONDITIONAL_SET_FLAG(res & 0x80000000, F_SF); + CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF); + } else if (cnt >= 32) { + if (sf) { + res = 0xffffffff; + SET_FLAG(F_CF); + CLEAR_FLAG(F_ZF); + SET_FLAG(F_SF); + SET_FLAG(F_PF); + } else { + res = 0; + CLEAR_FLAG(F_CF); + SET_FLAG(F_ZF); + CLEAR_FLAG(F_SF); + CLEAR_FLAG(F_PF); + } + } + return res; +} + +/* + * REMARKS: + * Implements the SHLD instruction and side effects. + */ +static uint16_t +shld_word(struct x86emu *emu, uint16_t d, uint16_t fill, uint8_t s) +{ + unsigned int cnt, res, cf; + + if (s < 16) { + cnt = s % 16; + if (cnt > 0) { + res = (d << cnt) | (fill >> (16 - cnt)); + cf = d & (1 << (16 - cnt)); + CONDITIONAL_SET_FLAG(cf, F_CF); + CONDITIONAL_SET_FLAG((res & 0xffff) == 0, F_ZF); + CONDITIONAL_SET_FLAG(res & 0x8000, F_SF); + CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF); + } else { + res = d; + } + if (cnt == 1) { + CONDITIONAL_SET_FLAG((((res & 0x8000) == 0x8000) ^ + (ACCESS_FLAG(F_CF) != 0)), F_OF); + } else { + CLEAR_FLAG(F_OF); + } + } else { + res = 0; + CONDITIONAL_SET_FLAG((d << (s - 1)) & 0x8000, F_CF); + CLEAR_FLAG(F_OF); + CLEAR_FLAG(F_SF); + SET_FLAG(F_PF); + SET_FLAG(F_ZF); + } + return (uint16_t) res; +} + +/* + * REMARKS: + * Implements the SHLD instruction and side effects. + */ +static uint32_t +shld_long(struct x86emu *emu, uint32_t d, uint32_t fill, uint8_t s) +{ + unsigned int cnt, res, cf; + + if (s < 32) { + cnt = s % 32; + if (cnt > 0) { + res = (d << cnt) | (fill >> (32 - cnt)); + cf = d & (1 << (32 - cnt)); + CONDITIONAL_SET_FLAG(cf, F_CF); + CONDITIONAL_SET_FLAG((res & 0xffffffff) == 0, F_ZF); + CONDITIONAL_SET_FLAG(res & 0x80000000, F_SF); + CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF); + } else { + res = d; + } + if (cnt == 1) { + CONDITIONAL_SET_FLAG((((res & 0x80000000) == 0x80000000) ^ + (ACCESS_FLAG(F_CF) != 0)), F_OF); + } else { + CLEAR_FLAG(F_OF); + } + } else { + res = 0; + CONDITIONAL_SET_FLAG((d << (s - 1)) & 0x80000000, F_CF); + CLEAR_FLAG(F_OF); + CLEAR_FLAG(F_SF); + SET_FLAG(F_PF); + SET_FLAG(F_ZF); + } + return res; +} + +/* + * REMARKS: + * Implements the SHRD instruction and side effects. + */ +static uint16_t +shrd_word(struct x86emu *emu, uint16_t d, uint16_t fill, uint8_t s) +{ + unsigned int cnt, res, cf; + + if (s < 16) { + cnt = s % 16; + if (cnt > 0) { + cf = d & (1 << (cnt - 1)); + res = (d >> cnt) | (fill << (16 - cnt)); + CONDITIONAL_SET_FLAG(cf, F_CF); + CONDITIONAL_SET_FLAG((res & 0xffff) == 0, F_ZF); + CONDITIONAL_SET_FLAG(res & 0x8000, F_SF); + CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF); + } else { + res = d; + } + + if (cnt == 1) { + CONDITIONAL_SET_FLAG(XOR2(res >> 14), F_OF); + } else { + CLEAR_FLAG(F_OF); + } + } else { + res = 0; + CLEAR_FLAG(F_CF); + CLEAR_FLAG(F_OF); + SET_FLAG(F_ZF); + CLEAR_FLAG(F_SF); + CLEAR_FLAG(F_PF); + } + return (uint16_t) res; +} + +/* + * REMARKS: + * Implements the SHRD instruction and side effects. + */ +static uint32_t +shrd_long(struct x86emu *emu, uint32_t d, uint32_t fill, uint8_t s) +{ + unsigned int cnt, res, cf; + + if (s < 32) { + cnt = s % 32; + if (cnt > 0) { + cf = d & (1 << (cnt - 1)); + res = (d >> cnt) | (fill << (32 - cnt)); + CONDITIONAL_SET_FLAG(cf, F_CF); + CONDITIONAL_SET_FLAG((res & 0xffffffff) == 0, F_ZF); + CONDITIONAL_SET_FLAG(res & 0x80000000, F_SF); + CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF); + } else { + res = d; + } + if (cnt == 1) { + CONDITIONAL_SET_FLAG(XOR2(res >> 30), F_OF); + } else { + CLEAR_FLAG(F_OF); + } + } else { + res = 0; + CLEAR_FLAG(F_CF); + CLEAR_FLAG(F_OF); + SET_FLAG(F_ZF); + CLEAR_FLAG(F_SF); + CLEAR_FLAG(F_PF); + } + return res; +} + +/* + * REMARKS: + * Implements the SBB instruction and side effects. + */ +static uint8_t +sbb_byte(struct x86emu *emu, uint8_t d, uint8_t s) +{ + uint32_t res; /* all operands in native machine order */ + uint32_t bc; + + if (ACCESS_FLAG(F_CF)) + res = d - s - 1; + else + res = d - s; + CONDITIONAL_SET_FLAG(res & 0x80, F_SF); + CONDITIONAL_SET_FLAG((res & 0xff) == 0, F_ZF); + CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF); + + /* calculate the borrow chain. See note at top */ + bc = (res & (~d | s)) | (~d & s); + CONDITIONAL_SET_FLAG(bc & 0x80, F_CF); + CONDITIONAL_SET_FLAG(XOR2(bc >> 6), F_OF); + CONDITIONAL_SET_FLAG(bc & 0x8, F_AF); + return (uint8_t) res; +} + +/* + * REMARKS: + * Implements the SBB instruction and side effects. + */ +static uint16_t +sbb_word(struct x86emu *emu, uint16_t d, uint16_t s) +{ + uint32_t res; /* all operands in native machine order */ + uint32_t bc; + + if (ACCESS_FLAG(F_CF)) + res = d - s - 1; + else + res = d - s; + CONDITIONAL_SET_FLAG(res & 0x8000, F_SF); + CONDITIONAL_SET_FLAG((res & 0xffff) == 0, F_ZF); + CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF); + + /* calculate the borrow chain. See note at top */ + bc = (res & (~d | s)) | (~d & s); + CONDITIONAL_SET_FLAG(bc & 0x8000, F_CF); + CONDITIONAL_SET_FLAG(XOR2(bc >> 14), F_OF); + CONDITIONAL_SET_FLAG(bc & 0x8, F_AF); + return (uint16_t) res; +} + +/* + * REMARKS: + * Implements the SBB instruction and side effects. + */ +static uint32_t +sbb_long(struct x86emu *emu, uint32_t d, uint32_t s) +{ + uint32_t res; /* all operands in native machine order */ + uint32_t bc; + + if (ACCESS_FLAG(F_CF)) + res = d - s - 1; + else + res = d - s; + CONDITIONAL_SET_FLAG(res & 0x80000000, F_SF); + CONDITIONAL_SET_FLAG((res & 0xffffffff) == 0, F_ZF); + CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF); + + /* calculate the borrow chain. See note at top */ + bc = (res & (~d | s)) | (~d & s); + CONDITIONAL_SET_FLAG(bc & 0x80000000, F_CF); + CONDITIONAL_SET_FLAG(XOR2(bc >> 30), F_OF); + CONDITIONAL_SET_FLAG(bc & 0x8, F_AF); + return res; +} + +/* + * REMARKS: + * Implements the SUB instruction and side effects. + */ +static uint8_t +sub_byte(struct x86emu *emu, uint8_t d, uint8_t s) +{ + uint32_t res; /* all operands in native machine order */ + uint32_t bc; + + res = d - s; + CONDITIONAL_SET_FLAG(res & 0x80, F_SF); + CONDITIONAL_SET_FLAG((res & 0xff) == 0, F_ZF); + CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF); + + /* calculate the borrow chain. See note at top */ + bc = (res & (~d | s)) | (~d & s); + CONDITIONAL_SET_FLAG(bc & 0x80, F_CF); + CONDITIONAL_SET_FLAG(XOR2(bc >> 6), F_OF); + CONDITIONAL_SET_FLAG(bc & 0x8, F_AF); + return (uint8_t) res; +} + +/* + * REMARKS: + * Implements the SUB instruction and side effects. + */ +static uint16_t +sub_word(struct x86emu *emu, uint16_t d, uint16_t s) +{ + uint32_t res; /* all operands in native machine order */ + uint32_t bc; + + res = d - s; + CONDITIONAL_SET_FLAG(res & 0x8000, F_SF); + CONDITIONAL_SET_FLAG((res & 0xffff) == 0, F_ZF); + CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF); + + /* calculate the borrow chain. See note at top */ + bc = (res & (~d | s)) | (~d & s); + CONDITIONAL_SET_FLAG(bc & 0x8000, F_CF); + CONDITIONAL_SET_FLAG(XOR2(bc >> 14), F_OF); + CONDITIONAL_SET_FLAG(bc & 0x8, F_AF); + return (uint16_t) res; +} + +/* + * REMARKS: + * Implements the SUB instruction and side effects. + */ +static uint32_t +sub_long(struct x86emu *emu, uint32_t d, uint32_t s) +{ + uint32_t res; /* all operands in native machine order */ + uint32_t bc; + + res = d - s; + CONDITIONAL_SET_FLAG(res & 0x80000000, F_SF); + CONDITIONAL_SET_FLAG((res & 0xffffffff) == 0, F_ZF); + CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF); + + /* calculate the borrow chain. See note at top */ + bc = (res & (~d | s)) | (~d & s); + CONDITIONAL_SET_FLAG(bc & 0x80000000, F_CF); + CONDITIONAL_SET_FLAG(XOR2(bc >> 30), F_OF); + CONDITIONAL_SET_FLAG(bc & 0x8, F_AF); + return res; +} + +/* + * REMARKS: + * Implements the TEST instruction and side effects. + */ +static void +test_byte(struct x86emu *emu, uint8_t d, uint8_t s) +{ + uint32_t res; /* all operands in native machine order */ + + res = d & s; + + CLEAR_FLAG(F_OF); + CONDITIONAL_SET_FLAG(res & 0x80, F_SF); + CONDITIONAL_SET_FLAG(res == 0, F_ZF); + CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF); + /* AF == dont care */ + CLEAR_FLAG(F_CF); +} + +/* + * REMARKS: + * Implements the TEST instruction and side effects. + */ +static void +test_word(struct x86emu *emu, uint16_t d, uint16_t s) +{ + uint32_t res; /* all operands in native machine order */ + + res = d & s; + + CLEAR_FLAG(F_OF); + CONDITIONAL_SET_FLAG(res & 0x8000, F_SF); + CONDITIONAL_SET_FLAG(res == 0, F_ZF); + CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF); + /* AF == dont care */ + CLEAR_FLAG(F_CF); +} + +/* + * REMARKS: + * Implements the TEST instruction and side effects. + */ +static void +test_long(struct x86emu *emu, uint32_t d, uint32_t s) +{ + uint32_t res; /* all operands in native machine order */ + + res = d & s; + + CLEAR_FLAG(F_OF); + CONDITIONAL_SET_FLAG(res & 0x80000000, F_SF); + CONDITIONAL_SET_FLAG(res == 0, F_ZF); + CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF); + /* AF == dont care */ + CLEAR_FLAG(F_CF); +} + +/* + * REMARKS: + * Implements the XOR instruction and side effects. + */ +static uint8_t +xor_byte(struct x86emu *emu, uint8_t d, uint8_t s) +{ + uint8_t res; /* all operands in native machine order */ + + res = d ^ s; + CLEAR_FLAG(F_OF); + CONDITIONAL_SET_FLAG(res & 0x80, F_SF); + CONDITIONAL_SET_FLAG(res == 0, F_ZF); + CONDITIONAL_SET_FLAG(PARITY(res), F_PF); + CLEAR_FLAG(F_CF); + CLEAR_FLAG(F_AF); + return res; +} + +/* + * REMARKS: + * Implements the XOR instruction and side effects. + */ +static uint16_t +xor_word(struct x86emu *emu, uint16_t d, uint16_t s) +{ + uint16_t res; /* all operands in native machine order */ + + res = d ^ s; + CLEAR_FLAG(F_OF); + CONDITIONAL_SET_FLAG(res & 0x8000, F_SF); + CONDITIONAL_SET_FLAG(res == 0, F_ZF); + CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF); + CLEAR_FLAG(F_CF); + CLEAR_FLAG(F_AF); + return res; +} + +/* + * REMARKS: + * Implements the XOR instruction and side effects. + */ +static uint32_t +xor_long(struct x86emu *emu, uint32_t d, uint32_t s) +{ + uint32_t res; /* all operands in native machine order */ + + res = d ^ s; + CLEAR_FLAG(F_OF); + CONDITIONAL_SET_FLAG(res & 0x80000000, F_SF); + CONDITIONAL_SET_FLAG(res == 0, F_ZF); + CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF); + CLEAR_FLAG(F_CF); + CLEAR_FLAG(F_AF); + return res; +} + +/* + * REMARKS: + * Implements the IMUL instruction and side effects. + */ +static void +imul_byte(struct x86emu *emu, uint8_t s) +{ + int16_t res = (int16_t) ((int8_t) emu->x86.R_AL * (int8_t) s); + + emu->x86.R_AX = res; + if (((emu->x86.R_AL & 0x80) == 0 && emu->x86.R_AH == 0x00) || + ((emu->x86.R_AL & 0x80) != 0 && emu->x86.R_AH == 0xFF)) { + CLEAR_FLAG(F_CF); + CLEAR_FLAG(F_OF); + } else { + SET_FLAG(F_CF); + SET_FLAG(F_OF); + } +} + +/* + * REMARKS: + * Implements the IMUL instruction and side effects. + */ +static void +imul_word(struct x86emu *emu, uint16_t s) +{ + int32_t res = (int16_t) emu->x86.R_AX * (int16_t) s; + + emu->x86.R_AX = (uint16_t) res; + emu->x86.R_DX = (uint16_t) (res >> 16); + if (((emu->x86.R_AX & 0x8000) == 0 && emu->x86.R_DX == 0x00) || + ((emu->x86.R_AX & 0x8000) != 0 && emu->x86.R_DX == 0xFF)) { + CLEAR_FLAG(F_CF); + CLEAR_FLAG(F_OF); + } else { + SET_FLAG(F_CF); + SET_FLAG(F_OF); + } +} + +/* + * REMARKS: + * Implements the IMUL instruction and side effects. + */ +static void +imul_long(struct x86emu *emu, uint32_t s) +{ + int64_t res; + + res = (int64_t)(int32_t)emu->x86.R_EAX * (int32_t)s; + emu->x86.R_EAX = (uint32_t)res; + emu->x86.R_EDX = ((uint64_t)res) >> 32; + if (((emu->x86.R_EAX & 0x80000000) == 0 && emu->x86.R_EDX == 0x00) || + ((emu->x86.R_EAX & 0x80000000) != 0 && emu->x86.R_EDX == 0xFF)) { + CLEAR_FLAG(F_CF); + CLEAR_FLAG(F_OF); + } else { + SET_FLAG(F_CF); + SET_FLAG(F_OF); + } +} + +/* + * REMARKS: + * Implements the MUL instruction and side effects. + */ +static void +mul_byte(struct x86emu *emu, uint8_t s) +{ + uint16_t res = (uint16_t) (emu->x86.R_AL * s); + + emu->x86.R_AX = res; + if (emu->x86.R_AH == 0) { + CLEAR_FLAG(F_CF); + CLEAR_FLAG(F_OF); + } else { + SET_FLAG(F_CF); + SET_FLAG(F_OF); + } +} + +/* + * REMARKS: + * Implements the MUL instruction and side effects. + */ +static void +mul_word(struct x86emu *emu, uint16_t s) +{ + uint32_t res = emu->x86.R_AX * s; + + emu->x86.R_AX = (uint16_t) res; + emu->x86.R_DX = (uint16_t) (res >> 16); + if (emu->x86.R_DX == 0) { + CLEAR_FLAG(F_CF); + CLEAR_FLAG(F_OF); + } else { + SET_FLAG(F_CF); + SET_FLAG(F_OF); + } +} + +/* + * REMARKS: + * Implements the MUL instruction and side effects. + */ +static void +mul_long(struct x86emu *emu, uint32_t s) +{ + uint64_t res = (uint64_t) emu->x86.R_EAX * s; + + emu->x86.R_EAX = (uint32_t) res; + emu->x86.R_EDX = (uint32_t) (res >> 32); + + if (emu->x86.R_EDX == 0) { + CLEAR_FLAG(F_CF); + CLEAR_FLAG(F_OF); + } else { + SET_FLAG(F_CF); + SET_FLAG(F_OF); + } +} + +/* + * REMARKS: + * Implements the IDIV instruction and side effects. + */ +static void +idiv_byte(struct x86emu *emu, uint8_t s) +{ + int32_t dvd, div, mod; + + dvd = (int16_t) emu->x86.R_AX; + if (s == 0) { + x86emu_intr_raise(emu, 8); + return; + } + div = dvd / (int8_t) s; + mod = dvd % (int8_t) s; + if (div > 0x7f || div < -0x7f) { + x86emu_intr_raise(emu, 8); + return; + } + emu->x86.R_AL = (int8_t) div; + emu->x86.R_AH = (int8_t) mod; +} + +/* + * REMARKS: + * Implements the IDIV instruction and side effects. + */ +static void +idiv_word(struct x86emu *emu, uint16_t s) +{ + int32_t dvd, div, mod; + + dvd = (((int32_t) emu->x86.R_DX) << 16) | emu->x86.R_AX; + if (s == 0) { + x86emu_intr_raise(emu, 8); + return; + } + div = dvd / (int16_t) s; + mod = dvd % (int16_t) s; + if (div > 0x7fff || div < -0x7fff) { + x86emu_intr_raise(emu, 8); + return; + } + CLEAR_FLAG(F_CF); + CLEAR_FLAG(F_SF); + CONDITIONAL_SET_FLAG(div == 0, F_ZF); + CONDITIONAL_SET_FLAG(PARITY(mod & 0xff), F_PF); + + emu->x86.R_AX = (uint16_t) div; + emu->x86.R_DX = (uint16_t) mod; +} + +/* + * REMARKS: + * Implements the IDIV instruction and side effects. + */ +static void +idiv_long(struct x86emu *emu, uint32_t s) +{ + int64_t dvd, div, mod; + + dvd = (((int64_t) emu->x86.R_EDX) << 32) | emu->x86.R_EAX; + if (s == 0) { + x86emu_intr_raise(emu, 8); + return; + } + div = dvd / (int32_t) s; + mod = dvd % (int32_t) s; + if (div > 0x7fffffff || div < -0x7fffffff) { + x86emu_intr_raise(emu, 8); + return; + } + CLEAR_FLAG(F_CF); + CLEAR_FLAG(F_AF); + CLEAR_FLAG(F_SF); + SET_FLAG(F_ZF); + CONDITIONAL_SET_FLAG(PARITY(mod & 0xff), F_PF); + + emu->x86.R_EAX = (uint32_t) div; + emu->x86.R_EDX = (uint32_t) mod; +} + +/* + * REMARKS: + * Implements the DIV instruction and side effects. + */ +static void +div_byte(struct x86emu *emu, uint8_t s) +{ + uint32_t dvd, div, mod; + + dvd = emu->x86.R_AX; + if (s == 0) { + x86emu_intr_raise(emu, 8); + return; + } + div = dvd / (uint8_t) s; + mod = dvd % (uint8_t) s; + if (div > 0xff) { + x86emu_intr_raise(emu, 8); + return; + } + emu->x86.R_AL = (uint8_t) div; + emu->x86.R_AH = (uint8_t) mod; +} + +/* + * REMARKS: + * Implements the DIV instruction and side effects. + */ +static void +div_word(struct x86emu *emu, uint16_t s) +{ + uint32_t dvd, div, mod; + + dvd = (((uint32_t) emu->x86.R_DX) << 16) | emu->x86.R_AX; + if (s == 0) { + x86emu_intr_raise(emu, 8); + return; + } + div = dvd / (uint16_t) s; + mod = dvd % (uint16_t) s; + if (div > 0xffff) { + x86emu_intr_raise(emu, 8); + return; + } + CLEAR_FLAG(F_CF); + CLEAR_FLAG(F_SF); + CONDITIONAL_SET_FLAG(div == 0, F_ZF); + CONDITIONAL_SET_FLAG(PARITY(mod & 0xff), F_PF); + + emu->x86.R_AX = (uint16_t) div; + emu->x86.R_DX = (uint16_t) mod; +} + +/* + * REMARKS: + * Implements the DIV instruction and side effects. + */ +static void +div_long(struct x86emu *emu, uint32_t s) +{ + uint64_t dvd, div, mod; + + dvd = (((uint64_t) emu->x86.R_EDX) << 32) | emu->x86.R_EAX; + if (s == 0) { + x86emu_intr_raise(emu, 8); + return; + } + div = dvd / (uint32_t) s; + mod = dvd % (uint32_t) s; + if (div > 0xffffffff) { + x86emu_intr_raise(emu, 8); + return; + } + CLEAR_FLAG(F_CF); + CLEAR_FLAG(F_AF); + CLEAR_FLAG(F_SF); + SET_FLAG(F_ZF); + CONDITIONAL_SET_FLAG(PARITY(mod & 0xff), F_PF); + + emu->x86.R_EAX = (uint32_t) div; + emu->x86.R_EDX = (uint32_t) mod; +} + +/* + * REMARKS: + * Implements the IN string instruction and side effects. + */ +static void +ins(struct x86emu *emu, int size) +{ + int inc = size; + + if (ACCESS_FLAG(F_DF)) { + inc = -size; + } + if (emu->x86.mode & (SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE)) { + /* dont care whether REPE or REPNE */ + /* in until CX is ZERO. */ + uint32_t count = ((emu->x86.mode & SYSMODE_PREFIX_DATA) ? + emu->x86.R_ECX : emu->x86.R_CX); + switch (size) { + case 1: + while (count--) { + store_byte(emu, emu->x86.R_ES, emu->x86.R_DI, + (*emu->emu_inb) (emu, emu->x86.R_DX)); + emu->x86.R_DI += inc; + } + break; + + case 2: + while (count--) { + store_word(emu, emu->x86.R_ES, emu->x86.R_DI, + (*emu->emu_inw) (emu, emu->x86.R_DX)); + emu->x86.R_DI += inc; + } + break; + case 4: + while (count--) { + store_long(emu, emu->x86.R_ES, emu->x86.R_DI, + (*emu->emu_inl) (emu, emu->x86.R_DX)); + emu->x86.R_DI += inc; + break; + } + } + emu->x86.R_CX = 0; + if (emu->x86.mode & SYSMODE_PREFIX_DATA) { + emu->x86.R_ECX = 0; + } + emu->x86.mode &= ~(SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE); + } else { + switch (size) { + case 1: + store_byte(emu, emu->x86.R_ES, emu->x86.R_DI, + (*emu->emu_inb) (emu, emu->x86.R_DX)); + break; + case 2: + store_word(emu, emu->x86.R_ES, emu->x86.R_DI, + (*emu->emu_inw) (emu, emu->x86.R_DX)); + break; + case 4: + store_long(emu, emu->x86.R_ES, emu->x86.R_DI, + (*emu->emu_inl) (emu, emu->x86.R_DX)); + break; + } + emu->x86.R_DI += inc; + } +} + +/* + * REMARKS: + * Implements the OUT string instruction and side effects. + */ +static void +outs(struct x86emu *emu, int size) +{ + int inc = size; + + if (ACCESS_FLAG(F_DF)) { + inc = -size; + } + if (emu->x86.mode & (SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE)) { + /* dont care whether REPE or REPNE */ + /* out until CX is ZERO. */ + uint32_t count = ((emu->x86.mode & SYSMODE_PREFIX_DATA) ? + emu->x86.R_ECX : emu->x86.R_CX); + switch (size) { + case 1: + while (count--) { + (*emu->emu_outb) (emu, emu->x86.R_DX, + fetch_byte(emu, emu->x86.R_ES, emu->x86.R_SI)); + emu->x86.R_SI += inc; + } + break; + + case 2: + while (count--) { + (*emu->emu_outw) (emu, emu->x86.R_DX, + fetch_word(emu, emu->x86.R_ES, emu->x86.R_SI)); + emu->x86.R_SI += inc; + } + break; + case 4: + while (count--) { + (*emu->emu_outl) (emu, emu->x86.R_DX, + fetch_long(emu, emu->x86.R_ES, emu->x86.R_SI)); + emu->x86.R_SI += inc; + break; + } + } + emu->x86.R_CX = 0; + if (emu->x86.mode & SYSMODE_PREFIX_DATA) { + emu->x86.R_ECX = 0; + } + emu->x86.mode &= ~(SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE); + } else { + switch (size) { + case 1: + (*emu->emu_outb) (emu, emu->x86.R_DX, + fetch_byte(emu, emu->x86.R_ES, emu->x86.R_SI)); + break; + case 2: + (*emu->emu_outw) (emu, emu->x86.R_DX, + fetch_word(emu, emu->x86.R_ES, emu->x86.R_SI)); + break; + case 4: + (*emu->emu_outl) (emu, emu->x86.R_DX, + fetch_long(emu, emu->x86.R_ES, emu->x86.R_SI)); + break; + } + emu->x86.R_SI += inc; + } +} + +/* + * REMARKS: + * Pushes a word onto the stack. + * + * NOTE: Do not inline this, as (*emu->emu_wrX) is already inline! + */ +static void +push_word(struct x86emu *emu, uint16_t w) +{ + emu->x86.R_SP -= 2; + store_word(emu, emu->x86.R_SS, emu->x86.R_SP, w); +} + +/* + * REMARKS: + * Pushes a long onto the stack. + * + * NOTE: Do not inline this, as (*emu->emu_wrX) is already inline! + */ +static void +push_long(struct x86emu *emu, uint32_t w) +{ + emu->x86.R_SP -= 4; + store_long(emu, emu->x86.R_SS, emu->x86.R_SP, w); +} + +/* + * REMARKS: + * Pops a word from the stack. + * + * NOTE: Do not inline this, as (*emu->emu_rdX) is already inline! + */ +static uint16_t +pop_word(struct x86emu *emu) +{ + uint16_t res; + + res = fetch_word(emu, emu->x86.R_SS, emu->x86.R_SP); + emu->x86.R_SP += 2; + return res; +} + +/* + * REMARKS: + * Pops a long from the stack. + * + * NOTE: Do not inline this, as (*emu->emu_rdX) is already inline! + */ +static uint32_t +pop_long(struct x86emu *emu) +{ + uint32_t res; + + res = fetch_long(emu, emu->x86.R_SS, emu->x86.R_SP); + emu->x86.R_SP += 4; + return res; +} diff --git a/sys/contrib/x86emu/x86emu.h b/sys/contrib/x86emu/x86emu.h new file mode 100644 index 0000000..f25a95b --- /dev/null +++ b/sys/contrib/x86emu/x86emu.h @@ -0,0 +1,184 @@ +/* $NetBSD: x86emu.h,v 1.1 2007/12/01 20:14:10 joerg Exp $ */ +/* $OpenBSD: x86emu.h,v 1.3 2009/06/06 03:45:05 matthieu Exp $ */ +/* $FreeBSD$ */ + +/**************************************************************************** +* +* Realmode X86 Emulator Library +* +* Copyright (C) 1996-1999 SciTech Software, Inc. +* Copyright (C) David Mosberger-Tang +* Copyright (C) 1999 Egbert Eich +* Copyright (C) 2007 Joerg Sonnenberger +* +* ======================================================================== +* +* Permission to use, copy, modify, distribute, and sell this software and +* its documentation for any purpose is hereby granted without fee, +* provided that the above copyright notice appear in all copies and that +* both that copyright notice and this permission notice appear in +* supporting documentation, and that the name of the authors not be used +* in advertising or publicity pertaining to distribution of the software +* without specific, written prior permission. The authors makes no +* representations about the suitability of this software for any purpose. +* It is provided "as is" without express or implied warranty. +* +* THE AUTHORS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, +* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO +* EVENT SHALL THE AUTHORS BE LIABLE FOR ANY SPECIAL, INDIRECT OR +* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF +* USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR +* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR +* PERFORMANCE OF THIS SOFTWARE. +* +****************************************************************************/ + +#ifndef __X86EMU_X86EMU_H +#define __X86EMU_X86EMU_H + +#include <sys/types.h> +#include <sys/endian.h> + +#ifdef _KERNEL +#include <sys/systm.h> +#include <machine/setjmp.h> +#else +#include <setjmp.h> +#endif + +/* + * General EAX, EBX, ECX, EDX type registers. Note that for + * portability, and speed, the issue of byte swapping is not addressed + * in the registers. All registers are stored in the default format + * available on the host machine. The only critical issue is that the + * registers should line up EXACTLY in the same manner as they do in + * the 386. That is: + * + * EAX & 0xff === AL + * EAX & 0xffff == AX + * + * etc. The result is that alot of the calculations can then be + * done using the native instruction set fully. + */ + +#ifdef __BIG_ENDIAN__ + +struct x86emu_register32 { + uint32_t e_reg; +}; + +struct x86emu_register16 { + uint16_t filler0; + uint16_t x_reg; +}; + +struct x86emu_register8 { + uint8_t filler0, filler1; + uint8_t h_reg, l_reg; +}; + +#else /* !__BIG_ENDIAN__ */ + +struct x86emu_register32 { + uint32_t e_reg; +}; + +struct x86emu_register16 { + uint16_t x_reg; +}; + +struct x86emu_register8 { + uint8_t l_reg, h_reg; +}; + +#endif /* BIG_ENDIAN */ + +union x86emu_register { + struct x86emu_register32 I32_reg; + struct x86emu_register16 I16_reg; + struct x86emu_register8 I8_reg; +}; + +struct x86emu_regs { + uint16_t register_cs; + uint16_t register_ds; + uint16_t register_es; + uint16_t register_fs; + uint16_t register_gs; + uint16_t register_ss; + uint32_t register_flags; + union x86emu_register register_a; + union x86emu_register register_b; + union x86emu_register register_c; + union x86emu_register register_d; + + union x86emu_register register_sp; + union x86emu_register register_bp; + union x86emu_register register_si; + union x86emu_register register_di; + union x86emu_register register_ip; + + /* + * MODE contains information on: + * REPE prefix 2 bits repe,repne + * SEGMENT overrides 5 bits normal,DS,SS,CS,ES + * Delayed flag set 3 bits (zero, signed, parity) + * reserved 6 bits + * interrupt # 8 bits instruction raised interrupt + * BIOS video segregs 4 bits + * Interrupt Pending 1 bits + * Extern interrupt 1 bits + * Halted 1 bits + */ + uint32_t mode; + volatile int intr; /* mask of pending interrupts */ + uint8_t intno; + uint8_t __pad[3]; +}; + +struct x86emu { + char *mem_base; + size_t mem_size; + void *sys_private; + struct x86emu_regs x86; + + jmp_buf exec_state; + + uint64_t cur_cycles; + + unsigned int cur_mod:2; + unsigned int cur_rl:3; + unsigned int cur_rh:3; + uint32_t cur_offset; + + uint8_t (*emu_rdb)(struct x86emu *, uint32_t addr); + uint16_t (*emu_rdw)(struct x86emu *, uint32_t addr); + uint32_t (*emu_rdl)(struct x86emu *, uint32_t addr); + void (*emu_wrb)(struct x86emu *, uint32_t addr,uint8_t val); + void (*emu_wrw)(struct x86emu *, uint32_t addr, uint16_t val); + void (*emu_wrl)(struct x86emu *, uint32_t addr, uint32_t val); + + uint8_t (*emu_inb)(struct x86emu *, uint16_t addr); + uint16_t (*emu_inw)(struct x86emu *, uint16_t addr); + uint32_t (*emu_inl)(struct x86emu *, uint16_t addr); + void (*emu_outb)(struct x86emu *, uint16_t addr, uint8_t val); + void (*emu_outw)(struct x86emu *, uint16_t addr, uint16_t val); + void (*emu_outl)(struct x86emu *, uint16_t addr, uint32_t val); + + void (*_x86emu_intrTab[256])(struct x86emu *, int); +}; + +__BEGIN_DECLS + +void x86emu_init_default(struct x86emu *); + +/* decode.c */ + +void x86emu_exec(struct x86emu *); +void x86emu_exec_call(struct x86emu *, uint16_t, uint16_t); +void x86emu_exec_intr(struct x86emu *, uint8_t); +void x86emu_halt_sys(struct x86emu *) __dead2; + +__END_DECLS + +#endif /* __X86EMU_X86EMU_H */ diff --git a/sys/contrib/x86emu/x86emu_regs.h b/sys/contrib/x86emu/x86emu_regs.h new file mode 100644 index 0000000..fda2d47a --- /dev/null +++ b/sys/contrib/x86emu/x86emu_regs.h @@ -0,0 +1,170 @@ +/* $NetBSD: x86emu_regs.h,v 1.1 2007/12/01 20:14:10 joerg Exp $ */ +/* $OpenBSD: x86emu_regs.h,v 1.2 2009/06/06 03:45:05 matthieu Exp $ */ + +/**************************************************************************** +* +* Realmode X86 Emulator Library +* +* Copyright (C) 1996-1999 SciTech Software, Inc. +* Copyright (C) David Mosberger-Tang +* Copyright (C) 1999 Egbert Eich +* Copyright (C) 2007 Joerg Sonnenberger +* +* ======================================================================== +* +* Permission to use, copy, modify, distribute, and sell this software and +* its documentation for any purpose is hereby granted without fee, +* provided that the above copyright notice appear in all copies and that +* both that copyright notice and this permission notice appear in +* supporting documentation, and that the name of the authors not be used +* in advertising or publicity pertaining to distribution of the software +* without specific, written prior permission. The authors makes no +* representations about the suitability of this software for any purpose. +* It is provided "as is" without express or implied warranty. +* +* THE AUTHORS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, +* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO +* EVENT SHALL THE AUTHORS BE LIABLE FOR ANY SPECIAL, INDIRECT OR +* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF +* USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR +* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR +* PERFORMANCE OF THIS SOFTWARE. +* +****************************************************************************/ + +#ifndef __X86EMU_REGS_H +#define __X86EMU_REGS_H + +/*---------------------- Macros and type definitions ----------------------*/ + +/* 8 bit registers */ +#define R_AH register_a.I8_reg.h_reg +#define R_AL register_a.I8_reg.l_reg +#define R_BH register_b.I8_reg.h_reg +#define R_BL register_b.I8_reg.l_reg +#define R_CH register_c.I8_reg.h_reg +#define R_CL register_c.I8_reg.l_reg +#define R_DH register_d.I8_reg.h_reg +#define R_DL register_d.I8_reg.l_reg + +/* 16 bit registers */ +#define R_AX register_a.I16_reg.x_reg +#define R_BX register_b.I16_reg.x_reg +#define R_CX register_c.I16_reg.x_reg +#define R_DX register_d.I16_reg.x_reg + +/* 32 bit extended registers */ +#define R_EAX register_a.I32_reg.e_reg +#define R_EBX register_b.I32_reg.e_reg +#define R_ECX register_c.I32_reg.e_reg +#define R_EDX register_d.I32_reg.e_reg + +/* special registers */ +#define R_SP register_sp.I16_reg.x_reg +#define R_BP register_bp.I16_reg.x_reg +#define R_SI register_si.I16_reg.x_reg +#define R_DI register_di.I16_reg.x_reg +#define R_IP register_ip.I16_reg.x_reg +#define R_FLG register_flags + +/* special registers */ +#define R_ESP register_sp.I32_reg.e_reg +#define R_EBP register_bp.I32_reg.e_reg +#define R_ESI register_si.I32_reg.e_reg +#define R_EDI register_di.I32_reg.e_reg +#define R_EIP register_ip.I32_reg.e_reg +#define R_EFLG register_flags + +/* segment registers */ +#define R_CS register_cs +#define R_DS register_ds +#define R_SS register_ss +#define R_ES register_es +#define R_FS register_fs +#define R_GS register_gs + +/* flag conditions */ +#define FB_CF 0x0001 /* CARRY flag */ +#define FB_PF 0x0004 /* PARITY flag */ +#define FB_AF 0x0010 /* AUX flag */ +#define FB_ZF 0x0040 /* ZERO flag */ +#define FB_SF 0x0080 /* SIGN flag */ +#define FB_TF 0x0100 /* TRAP flag */ +#define FB_IF 0x0200 /* INTERRUPT ENABLE flag */ +#define FB_DF 0x0400 /* DIR flag */ +#define FB_OF 0x0800 /* OVERFLOW flag */ + +/* 80286 and above always have bit#1 set */ +#define F_ALWAYS_ON (0x0002) /* flag bits always on */ + +/* + * Define a mask for only those flag bits we will ever pass back + * (via PUSHF) + */ +#define F_MSK (FB_CF|FB_PF|FB_AF|FB_ZF|FB_SF|FB_TF|FB_IF|FB_DF|FB_OF) + +/* following bits masked in to a 16bit quantity */ + +#define F_CF 0x0001 /* CARRY flag */ +#define F_PF 0x0004 /* PARITY flag */ +#define F_AF 0x0010 /* AUX flag */ +#define F_ZF 0x0040 /* ZERO flag */ +#define F_SF 0x0080 /* SIGN flag */ +#define F_TF 0x0100 /* TRAP flag */ +#define F_IF 0x0200 /* INTERRUPT ENABLE flag */ +#define F_DF 0x0400 /* DIR flag */ +#define F_OF 0x0800 /* OVERFLOW flag */ + +#define SET_FLAG(flag) (emu->x86.R_FLG |= (flag)) +#define CLEAR_FLAG(flag) (emu->x86.R_FLG &= ~(flag)) +#define ACCESS_FLAG(flag) (emu->x86.R_FLG & (flag)) +#define CLEARALL_FLAG(m) (emu->x86.R_FLG = 0) + +#define CONDITIONAL_SET_FLAG(COND,FLAG) \ + if (COND) SET_FLAG(FLAG); else CLEAR_FLAG(FLAG) + +#define F_PF_CALC 0x010000 /* PARITY flag has been calced */ +#define F_ZF_CALC 0x020000 /* ZERO flag has been calced */ +#define F_SF_CALC 0x040000 /* SIGN flag has been calced */ + +#define F_ALL_CALC 0xff0000 /* All have been calced */ + +/* + * Emulator machine state. + * Segment usage control. + */ +#define SYSMODE_SEG_DS_SS 0x00000001 +#define SYSMODE_SEGOVR_CS 0x00000002 +#define SYSMODE_SEGOVR_DS 0x00000004 +#define SYSMODE_SEGOVR_ES 0x00000008 +#define SYSMODE_SEGOVR_FS 0x00000010 +#define SYSMODE_SEGOVR_GS 0x00000020 +#define SYSMODE_SEGOVR_SS 0x00000040 +#define SYSMODE_PREFIX_REPE 0x00000080 +#define SYSMODE_PREFIX_REPNE 0x00000100 +#define SYSMODE_PREFIX_DATA 0x00000200 +#define SYSMODE_PREFIX_ADDR 0x00000400 +#define SYSMODE_INTR_PENDING 0x10000000 +#define SYSMODE_EXTRN_INTR 0x20000000 +#define SYSMODE_HALTED 0x40000000 + +#define SYSMODE_SEGMASK (SYSMODE_SEG_DS_SS | \ + SYSMODE_SEGOVR_CS | \ + SYSMODE_SEGOVR_DS | \ + SYSMODE_SEGOVR_ES | \ + SYSMODE_SEGOVR_FS | \ + SYSMODE_SEGOVR_GS | \ + SYSMODE_SEGOVR_SS) +#define SYSMODE_CLRMASK (SYSMODE_SEG_DS_SS | \ + SYSMODE_SEGOVR_CS | \ + SYSMODE_SEGOVR_DS | \ + SYSMODE_SEGOVR_ES | \ + SYSMODE_SEGOVR_FS | \ + SYSMODE_SEGOVR_GS | \ + SYSMODE_SEGOVR_SS | \ + SYSMODE_PREFIX_DATA | \ + SYSMODE_PREFIX_ADDR) + +#define INTR_SYNCH 0x1 + +#endif /* __X86EMU_REGS_H */ diff --git a/sys/contrib/x86emu/x86emu_util.c b/sys/contrib/x86emu/x86emu_util.c new file mode 100644 index 0000000..e96efc2 --- /dev/null +++ b/sys/contrib/x86emu/x86emu_util.c @@ -0,0 +1,208 @@ +/* $OpenBSD: x86emu_util.c,v 1.5 2009/06/18 14:19:21 pirofti Exp $ */ +/* $NetBSD: x86emu_util.c,v 1.2 2007/12/04 17:32:22 joerg Exp $ */ + +/* + * + * Realmode X86 Emulator Library + * + * Copyright (C) 1996-1999 SciTech Software, Inc. + * Copyright (C) David Mosberger-Tang + * Copyright (C) 1999 Egbert Eich + * Copyright (C) 2007 Joerg Sonnenberger + * + * ======================================================================== + * + * Permission to use, copy, modify, distribute, and sell this software and + * its documentation for any purpose is hereby granted without fee, + * provided that the above copyright notice appear in all copies and that + * both that copyright notice and this permission notice appear in + * supporting documentation, and that the name of the authors not be used + * in advertising or publicity pertaining to distribution of the software + * without specific, written prior permission. The authors makes no + * representations about the suitability of this software for any purpose. + * It is provided "as is" without express or implied warranty. + * + * THE AUTHORS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL THE AUTHORS BE LIABLE FOR ANY SPECIAL, INDIRECT OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF + * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR + * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + * + */ + +#include <sys/param.h> +#include <sys/endian.h> + +#include <dev/x86emu/x86emu.h> +#include <dev/x86emu/x86emu_regs.h> + + + +/* + * PARAMETERS: + * addr - Emulator memory address to read + * + * RETURNS: + * Byte value read from emulator memory. + * + * REMARKS: + * Reads a byte value from the emulator memory. + */ +static uint8_t +rdb(struct x86emu *emu, uint32_t addr) +{ + if (addr > emu->mem_size - 1) + x86emu_halt_sys(emu); + return emu->mem_base[addr]; +} + +/* + * PARAMETERS: + * addr - Emulator memory address to read + * + * RETURNS: + * Word value read from emulator memory. + * + * REMARKS: + * Reads a word value from the emulator memory. + */ +static uint16_t +rdw(struct x86emu *emu, uint32_t addr) +{ + if (addr > emu->mem_size - 2) + x86emu_halt_sys(emu); +#ifdef __STRICT_ALIGNMENT + if (addr & 1) { + u_int8_t *a = emu->mem_base + addr; + u_int16_t r; + + r = ((*(a + 0) << 0) & 0x00ff) | + ((*(a + 1) << 8) & 0xff00); + return r; + } else + return letoh32(*(u_int32_t *)(emu->mem_base + addr)); +#else + return letoh16(*(u_int16_t *)(emu->mem_base + addr)); +#endif +} + +/* + * PARAMETERS: + * addr - Emulator memory address to read + * + * RETURNS: + * Long value read from emulator memory. + * REMARKS: + * Reads a long value from the emulator memory. + */ +static uint32_t +rdl(struct x86emu *emu, uint32_t addr) +{ + if (addr > emu->mem_size - 4) + x86emu_halt_sys(emu); +#ifdef __STRICT_ALIGNMENT + if (addr & 3) { + u_int8_t *a = emu->mem_base + addr; + u_int32_t r; + + r = ((*(a + 0) << 0) & 0x000000ff) | + ((*(a + 1) << 8) & 0x0000ff00) | + ((*(a + 2) << 16) & 0x00ff0000) | + ((*(a + 3) << 24) & 0xff000000); + return r; + } else + return letoh32(*(u_int32_t *)(emu->mem_base + addr)); +#else + return letoh32(*(u_int32_t *)(emu->mem_base + addr)); +#endif +} + +/* + * PARAMETERS: + * addr - Emulator memory address to read + * val - Value to store + * + * REMARKS: + * Writes a byte value to emulator memory. + */ +static void +wrb(struct x86emu *emu, uint32_t addr, uint8_t val) +{ + if (addr > emu->mem_size - 1) + x86emu_halt_sys(emu); + emu->mem_base[addr] = val; +} + +/* + * PARAMETERS: + * addr - Emulator memory address to read + * val - Value to store + * + * REMARKS: + * Writes a word value to emulator memory. + */ +static void +wrw(struct x86emu *emu, uint32_t addr, uint16_t val) +{ + if (addr > emu->mem_size - 2) + x86emu_halt_sys(emu); +#ifdef __STRICT_ALIGNMENT + if (addr & 1) { + u_int8_t *a = emu->mem_base + addr; + + *((a + 0)) = (val >> 0) & 0xff; + *((a + 1)) = (val >> 8) & 0xff; + } else + *((u_int16_t *)(emu->mem_base + addr)) = htole16(val); +#else + *((u_int16_t *)(emu->mem_base + addr)) = htole16(val); +#endif +} + +/* + * PARAMETERS: + * addr - Emulator memory address to read + * val - Value to store + * + * REMARKS: + * Writes a long value to emulator memory. + */ +static void +wrl(struct x86emu *emu, uint32_t addr, uint32_t val) +{ + if (addr > emu->mem_size - 4) + x86emu_halt_sys(emu); +#ifdef __STRICT_ALIGNMENT + if (addr & 3) { + u_int8_t *a = emu->mem_base + addr; + + *((a + 0) = (val >> 0) & 0xff; + *((a + 1) = (val >> 8) & 0xff; + *((a + 2) = (val >> 16) & 0xff; + *((a + 3) = (val >> 24) & 0xff; + } else + *((u_int32_t *)(emu->mem_base + addr)) = htole32(val); +#else + *((u_int32_t *)(emu->mem_base + addr)) = htole32(val); +#endif +} + +/* Setup */ + +void +x86emu_init_default(struct x86emu *emu) +{ + int i; + + emu->emu_rdb = rdb; + emu->emu_rdw = rdw; + emu->emu_rdl = rdl; + emu->emu_wrb = wrb; + emu->emu_wrw = wrw; + emu->emu_wrl = wrl; + + for (i = 0; i < 256; i++) + emu->_x86emu_intrTab[i] = NULL; +} diff --git a/sys/dev/atkbdc/atkbd.c b/sys/dev/atkbdc/atkbd.c index 0aae153..600020f 100644 --- a/sys/dev/atkbdc/atkbd.c +++ b/sys/dev/atkbdc/atkbd.c @@ -44,10 +44,10 @@ __FBSDID("$FreeBSD$"); #include <machine/bus.h> #include <machine/resource.h> -#ifdef __i386__ +#if defined(__i386__) || defined(__amd64__) #include <machine/md_var.h> #include <machine/psl.h> -#include <machine/vm86.h> +#include <compat/x86bios/x86bios.h> #include <machine/pc/bios.h> #include <vm/vm.h> @@ -55,7 +55,7 @@ __FBSDID("$FreeBSD$"); #include <vm/vm_param.h> #include <isa/isareg.h> -#endif /* __i386__ */ +#endif /* __i386__ || __amd64__ */ #include <sys/kbio.h> #include <dev/kbd/kbdreg.h> @@ -1089,34 +1089,45 @@ atkbd_shutdown_final(void *v) static int get_typematic(keyboard_t *kbd) { -#ifdef __i386__ +#if defined(__i386__) || defined(__amd64__) /* - * Only some systems allow us to retrieve the keyboard repeat + * Only some systems allow us to retrieve the keyboard repeat * rate previously set via the BIOS... */ - struct vm86frame vmf; - u_int32_t p; - - bzero(&vmf, sizeof(vmf)); - vmf.vmf_ax = 0xc000; - vm86_intcall(0x15, &vmf); - if ((vmf.vmf_eflags & PSL_C) || vmf.vmf_ah) - return ENODEV; - p = BIOS_PADDRTOVADDR(((u_int32_t)vmf.vmf_es << 4) + vmf.vmf_bx); - if ((readb(p + 6) & 0x40) == 0) /* int 16, function 0x09 supported? */ - return ENODEV; - vmf.vmf_ax = 0x0900; - vm86_intcall(0x16, &vmf); - if ((vmf.vmf_al & 0x08) == 0) /* int 16, function 0x0306 supported? */ - return ENODEV; - vmf.vmf_ax = 0x0306; - vm86_intcall(0x16, &vmf); - kbd->kb_delay1 = typematic_delay(vmf.vmf_bh << 5); - kbd->kb_delay2 = typematic_rate(vmf.vmf_bl); - return 0; + x86regs_t regs; + uint8_t *p; + + if (x86bios_get_intr(0x15) == 0 || x86bios_get_intr(0x16) == 0) + return (ENODEV); + + /* Is BIOS system configuration table supported? */ + x86bios_init_regs(®s); + regs.R_AH = 0xc0; + x86bios_intr(®s, 0x15); + if ((regs.R_FLG & PSL_C) != 0 || regs.R_AH != 0) + return (ENODEV); + + /* Is int 0x16, function 0x09 supported? */ + p = x86bios_offset((regs.R_ES << 4) + regs.R_BX); + if (readw(p) < 5 || (readb(p + 6) & 0x40) == 0) + return (ENODEV); + + /* Is int 0x16, function 0x0306 supported? */ + x86bios_init_regs(®s); + regs.R_AH = 0x09; + x86bios_intr(®s, 0x16); + if ((regs.R_AL & 0x08) == 0) + return (ENODEV); + + x86bios_init_regs(®s); + regs.R_AX = 0x0306; + x86bios_intr(®s, 0x16); + kbd->kb_delay1 = typematic_delay(regs.R_BH << 5); + kbd->kb_delay2 = typematic_rate(regs.R_BL); + return (0); #else - return ENODEV; -#endif /* __i386__ */ + return (ENODEV); +#endif /* __i386__ || __amd64__ */ } static int diff --git a/sys/i386/isa/dpms.c b/sys/dev/dpms/dpms.c index 723a6c0..fdfed2f 100644 --- a/sys/i386/isa/dpms.c +++ b/sys/dev/dpms/dpms.c @@ -67,7 +67,7 @@ __FBSDID("$FreeBSD$"); #include <sys/libkern.h> #include <sys/module.h> -#include <machine/vm86.h> +#include <compat/x86bios/x86bios.h> /* * VESA DPMS States @@ -118,19 +118,14 @@ static driver_t dpms_driver = { static devclass_t dpms_devclass; -DRIVER_MODULE(dpms, vgapci, dpms_driver, dpms_devclass, NULL, NULL); +DRIVER_MODULE(dpms, vgapm, dpms_driver, dpms_devclass, NULL, NULL); +MODULE_DEPEND(dpms, x86bios, 1, 1, 1); static void dpms_identify(driver_t *driver, device_t parent) { - /* - * XXX: The DPMS VBE only allows for manipulating a single - * monitor, but we don't know which one. Just attach to the - * first vgapci(4) device we encounter and hope it is the - * right one. - */ - if (devclass_get_device(dpms_devclass, 0) == NULL) + if (x86bios_match_device(0xc0000, device_get_parent(parent))) device_add_child(parent, "dpms", 0); } @@ -171,8 +166,11 @@ dpms_detach(device_t dev) static int dpms_suspend(device_t dev) { + struct dpms_softc *sc; - dpms_set_state(DPMS_OFF); + sc = device_get_softc(dev); + if ((sc->dpms_supported_states & DPMS_OFF) != 0) + dpms_set_state(DPMS_OFF); return (0); } @@ -189,21 +187,23 @@ dpms_resume(device_t dev) static int dpms_call_bios(int subfunction, int *bh) { - struct vm86frame vmf; - int error; + x86regs_t regs; - bzero(&vmf, sizeof(vmf)); - vmf.vmf_ax = VBE_DPMS_FUNCTION; - vmf.vmf_bl = subfunction; - vmf.vmf_bh = *bh; - vmf.vmf_es = 0; - vmf.vmf_di = 0; - error = vm86_intcall(0x10, &vmf); - if (error == 0 && (vmf.vmf_eax & 0xffff) != 0x004f) - error = ENXIO; - if (error == 0) - *bh = vmf.vmf_bh; - return (error); + if (x86bios_get_intr(0x10) == 0) + return (ENXIO); + + x86bios_init_regs(®s); + regs.R_AX = VBE_DPMS_FUNCTION; + regs.R_BL = subfunction; + regs.R_BH = *bh; + x86bios_intr(®s, 0x10); + + if (regs.R_AX != 0x004f) + return (ENXIO); + + *bh = regs.R_BH; + + return (0); } static int diff --git a/sys/dev/fb/s3_pci.c b/sys/dev/fb/s3_pci.c index 558329b..cfddf30 100644 --- a/sys/dev/fb/s3_pci.c +++ b/sys/dev/fb/s3_pci.c @@ -54,9 +54,8 @@ __FBSDID("$FreeBSD$"); #include <dev/pci/pcivar.h> #include <machine/md_var.h> -#include <machine/vm86.h> #include <machine/pc/bios.h> -#include <machine/pc/vesa.h> +#include <dev/fb/vesa.h> #include <dev/fb/fbreg.h> #include <dev/fb/vgareg.h> diff --git a/sys/i386/isa/vesa.c b/sys/dev/fb/vesa.c index 736daff..df0dc1e 100644 --- a/sys/i386/isa/vesa.c +++ b/sys/dev/fb/vesa.c @@ -33,6 +33,7 @@ __FBSDID("$FreeBSD$"); #ifndef VGA_NO_MODE_CHANGE #include <sys/param.h> +#include <sys/bus.h> #include <sys/systm.h> #include <sys/kernel.h> #include <sys/module.h> @@ -45,19 +46,17 @@ __FBSDID("$FreeBSD$"); #include <vm/vm_param.h> #include <vm/pmap.h> -#include <machine/md_var.h> -#include <machine/vm86.h> #include <machine/pc/bios.h> -#include <machine/pc/vesa.h> +#include <dev/fb/vesa.h> #include <dev/fb/fbreg.h> #include <dev/fb/vgareg.h> -#ifndef __i386__ +#include <dev/pci/pcivar.h> + #include <isa/isareg.h> -#else -#include <i386/isa/isa.h> -#endif + +#include <compat/x86bios/x86bios.h> #define VESA_VIA_CLE266 "VIA CLE266\r\n" @@ -75,9 +74,7 @@ typedef struct adp_state adp_state_t; /* VESA video adapter */ static video_adapter_t *vesa_adp = NULL; -static int vesa_state_buf_size = 0; -#define VESA_VM86_BUFSIZE (3 * PAGE_SIZE) -static void *vesa_vm86_buf; +static ssize_t vesa_state_buf_size = -1; /* VESA functions */ #if 0 @@ -109,7 +106,6 @@ static vi_fill_rect_t vesa_fill_rect; static vi_bitblt_t vesa_bitblt; static vi_diag_t vesa_diag; static int vesa_bios_info(int level); -static struct vm86context vesa_vmcontext; static video_switch_t vesavidsw = { vesa_probe, @@ -166,9 +162,12 @@ static char *vesa_revstr = NULL; #define BIOS_SADDRTOLADDR(p) ((((p) & 0xffff0000) >> 12) + ((p) & 0x0000ffff)) static int int10_set_mode(int mode); +static int vesa_bios_post(void); static int vesa_bios_get_mode(int mode, struct vesa_mode *vmode); static int vesa_bios_set_mode(int mode); +#if 0 static int vesa_bios_get_dac(void); +#endif static int vesa_bios_set_dac(int bits); static int vesa_bios_save_palette(int start, int colors, u_char *palette, int bits); @@ -176,10 +175,8 @@ static int vesa_bios_save_palette2(int start, int colors, u_char *r, u_char *g, u_char *b, int bits); static int vesa_bios_load_palette(int start, int colors, u_char *palette, int bits); -#ifdef notyet static int vesa_bios_load_palette2(int start, int colors, u_char *r, u_char *g, u_char *b, int bits); -#endif #define STATE_SIZE 0 #define STATE_SAVE 1 #define STATE_LOAD 2 @@ -189,9 +186,11 @@ static int vesa_bios_load_palette2(int start, int colors, u_char *r, u_char *g, #define STATE_REG (1<<3) #define STATE_MOST (STATE_HW | STATE_DATA | STATE_REG) #define STATE_ALL (STATE_HW | STATE_DATA | STATE_DAC | STATE_REG) -static int vesa_bios_state_buf_size(void); +static ssize_t vesa_bios_state_buf_size(void); static int vesa_bios_save_restore(int code, void *p, size_t size); +#if 0 static int vesa_bios_get_line_length(void); +#endif static int vesa_bios_set_line_length(int pixel, int *bytes, int *lines); #if 0 static int vesa_bios_get_start(int *x, int *y); @@ -200,332 +199,446 @@ static int vesa_bios_set_start(int x, int y); static int vesa_map_gen_mode_num(int type, int color, int mode); static int vesa_translate_flags(u_int16_t vflags); static int vesa_translate_mmodel(u_int8_t vmodel); -static void *vesa_fix_ptr(u_int32_t p, u_int16_t seg, u_int16_t off, - u_char *buf); static int vesa_bios_init(void); static void vesa_clear_modes(video_info_t *info, int color); -static vm_offset_t vesa_map_buffer(u_int paddr, size_t size); -static void vesa_unmap_buffer(vm_offset_t vaddr, size_t size); #if 0 static int vesa_get_origin(video_adapter_t *adp, off_t *offset); #endif -static void -dump_buffer(u_char *buf, size_t len) +/* INT 10 BIOS calls */ +static int +int10_set_mode(int mode) { - int i; + x86regs_t regs; - for(i = 0; i < len;) { - printf("%02x ", buf[i]); - if ((++i % 16) == 0) - printf("\n"); - } + x86bios_init_regs(®s); + regs.R_AL = mode; + + x86bios_intr(®s, 0x10); + + return (0); } -/* INT 10 BIOS calls */ static int -int10_set_mode(int mode) +vesa_bios_post(void) { - struct vm86frame vmf; + x86regs_t regs; + devclass_t dc; + device_t *devs; + device_t dev; + int count, i, is_pci; + + if (x86bios_get_orm(0xc0000) == NULL) + return (1); + + dev = NULL; + is_pci = 0; + + /* Find the matching PCI video controller. */ + dc = devclass_find("vgapci"); + if (dc != NULL && devclass_get_devices(dc, &devs, &count) == 0) { + for (dev = NULL, i = 0; dev == NULL && i < count; devs++, i++) + if (device_get_flags(*devs) != 0 && + x86bios_match_device(0xc0000, *devs)) { + dev = *devs; + is_pci = 1; + break; + } + free(devs, M_TEMP); + } + + /* Try VGA if a PCI device is not found. */ + if (dev == NULL) { + dc = devclass_find(VGA_DRIVER_NAME); + if (dc != NULL) + dev = devclass_get_device(dc, 0); + } + + if (bootverbose) + printf("%s: calling BIOS POST\n", + dev == NULL ? "VESA" : device_get_nameunit(dev)); + + x86bios_init_regs(®s); + if (is_pci) { + regs.R_AH = pci_get_bus(dev); + regs.R_AL = (pci_get_slot(dev) << 3) | + (pci_get_function(dev) & 0x07); + } + regs.R_DL = 0x80; + x86bios_call(®s, 0xc000, 0x0003); + + if (x86bios_get_intr(0x10) == 0) + return (1); - bzero(&vmf, sizeof(vmf)); - vmf.vmf_eax = 0x0000 | mode; - vm86_intcall(0x10, &vmf); - return 0; + return (0); } /* VESA BIOS calls */ static int vesa_bios_get_mode(int mode, struct vesa_mode *vmode) { - struct vm86frame vmf; - u_char *buf; - int err; - - bzero(&vmf, sizeof(vmf)); - vmf.vmf_eax = 0x4f01; - vmf.vmf_ecx = mode; - buf = vesa_vm86_buf; - vm86_getptr(&vesa_vmcontext, (vm_offset_t)buf, &vmf.vmf_es, &vmf.vmf_di); - - err = vm86_datacall(0x10, &vmf, &vesa_vmcontext); - if ((err != 0) || (vmf.vmf_ax != 0x4f)) - return 1; + x86regs_t regs; + uint32_t offs; + void *buf; + + buf = x86bios_alloc(&offs, sizeof(*vmode)); + if (buf == NULL) + return (1); + + x86bios_init_regs(®s); + regs.R_AX = 0x4f01; + regs.R_CX = mode; + + regs.R_ES = X86BIOS_PHYSTOSEG(offs); + regs.R_DI = X86BIOS_PHYSTOOFF(offs); + + x86bios_intr(®s, 0x10); + + if (regs.R_AX != 0x004f) { + x86bios_free(buf, sizeof(*vmode)); + return (1); + } + bcopy(buf, vmode, sizeof(*vmode)); - return 0; + x86bios_free(buf, sizeof(*vmode)); + + return (0); } static int vesa_bios_set_mode(int mode) { - struct vm86frame vmf; - int err; - - bzero(&vmf, sizeof(vmf)); - vmf.vmf_eax = 0x4f02; - vmf.vmf_ebx = mode; - err = vm86_intcall(0x10, &vmf); - return ((err != 0) || (vmf.vmf_ax != 0x4f)); + x86regs_t regs; + + x86bios_init_regs(®s); + regs.R_AX = 0x4f02; + regs.R_BX = mode; + + x86bios_intr(®s, 0x10); + + return (regs.R_AX != 0x004f); } +#if 0 static int vesa_bios_get_dac(void) { - struct vm86frame vmf; - int err; - - bzero(&vmf, sizeof(vmf)); - vmf.vmf_eax = 0x4f08; - vmf.vmf_ebx = 1; /* get DAC width */ - err = vm86_intcall(0x10, &vmf); - if ((err != 0) || (vmf.vmf_ax != 0x4f)) - return 6; /* XXX */ - return ((vmf.vmf_ebx >> 8) & 0x00ff); + x86regs_t regs; + + x86bios_init_regs(®s); + regs.R_AX = 0x4f08; + regs.R_BL = 1; + + x86bios_intr(®s, 0x10); + + if (regs.R_AX != 0x004f) + return (6); + + return (regs.R_BH); } +#endif static int vesa_bios_set_dac(int bits) { - struct vm86frame vmf; - int err; - - bzero(&vmf, sizeof(vmf)); - vmf.vmf_eax = 0x4f08; - vmf.vmf_ebx = (bits << 8); - err = vm86_intcall(0x10, &vmf); - if ((err != 0) || (vmf.vmf_ax != 0x4f)) - return 6; /* XXX */ - return ((vmf.vmf_ebx >> 8) & 0x00ff); + x86regs_t regs; + + x86bios_init_regs(®s); + regs.R_AX = 0x4f08; + /* regs.R_BL = 0; */ + regs.R_BH = bits; + + x86bios_intr(®s, 0x10); + + if (regs.R_AX != 0x004f) + return (6); + + return (regs.R_BH); } static int vesa_bios_save_palette(int start, int colors, u_char *palette, int bits) { - struct vm86frame vmf; + x86regs_t regs; + uint32_t offs; u_char *p; - int err; int i; - bzero(&vmf, sizeof(vmf)); - vmf.vmf_eax = 0x4f09; - vmf.vmf_ebx = 1; /* get primary palette data */ - vmf.vmf_ecx = colors; - vmf.vmf_edx = start; - p = vesa_vm86_buf; - vm86_getptr(&vesa_vmcontext, (vm_offset_t)p, &vmf.vmf_es, &vmf.vmf_di); + p = (u_char *)x86bios_alloc(&offs, colors * 4); + if (p == NULL) + return (1); + + x86bios_init_regs(®s); + regs.R_AX = 0x4f09; + regs.R_BL = 1; + regs.R_CX = colors; + regs.R_DX = start; + + regs.R_ES = X86BIOS_PHYSTOSEG(offs); + regs.R_DI = X86BIOS_PHYSTOOFF(offs); - err = vm86_datacall(0x10, &vmf, &vesa_vmcontext); - if ((err != 0) || (vmf.vmf_ax != 0x4f)) - return 1; + x86bios_intr(®s, 0x10); + + if (regs.R_AX != 0x004f) { + x86bios_free(p, colors * 4); + return (1); + } bits = 8 - bits; for (i = 0; i < colors; ++i) { - palette[i*3] = p[i*4 + 2] << bits; - palette[i*3 + 1] = p[i*4 + 1] << bits; - palette[i*3 + 2] = p[i*4] << bits; + palette[i * 3] = p[i * 4 + 2] << bits; + palette[i * 3 + 1] = p[i * 4 + 1] << bits; + palette[i * 3 + 2] = p[i * 4] << bits; } - return 0; + x86bios_free(p, colors * 4); + + return (0); } static int vesa_bios_save_palette2(int start, int colors, u_char *r, u_char *g, u_char *b, int bits) { - struct vm86frame vmf; + x86regs_t regs; + uint32_t offs; u_char *p; - int err; int i; - bzero(&vmf, sizeof(vmf)); - vmf.vmf_eax = 0x4f09; - vmf.vmf_ebx = 1; /* get primary palette data */ - vmf.vmf_ecx = colors; - vmf.vmf_edx = start; - p = vesa_vm86_buf; - vm86_getptr(&vesa_vmcontext, (vm_offset_t)p, &vmf.vmf_es, &vmf.vmf_di); + p = (u_char *)x86bios_alloc(&offs, colors * 4); + if (p == NULL) + return (1); + + x86bios_init_regs(®s); + regs.R_AX = 0x4f09; + regs.R_BL = 1; + regs.R_CX = colors; + regs.R_DX = start; - err = vm86_datacall(0x10, &vmf, &vesa_vmcontext); - if ((err != 0) || (vmf.vmf_ax != 0x4f)) - return 1; + regs.R_ES = X86BIOS_PHYSTOSEG(offs); + regs.R_DI = X86BIOS_PHYSTOOFF(offs); + + x86bios_intr(®s, 0x10); + + if (regs.R_AX != 0x004f) { + x86bios_free(p, colors * 4); + return (1); + } bits = 8 - bits; for (i = 0; i < colors; ++i) { - r[i] = p[i*4 + 2] << bits; - g[i] = p[i*4 + 1] << bits; - b[i] = p[i*4] << bits; + r[i] = p[i * 4 + 2] << bits; + g[i] = p[i * 4 + 1] << bits; + b[i] = p[i * 4] << bits; } - return 0; + x86bios_free(p, colors * 4); + + return (0); } static int vesa_bios_load_palette(int start, int colors, u_char *palette, int bits) { - struct vm86frame vmf; + x86regs_t regs; + uint32_t offs; u_char *p; - int err; int i; - p = vesa_vm86_buf; + p = (u_char *)x86bios_alloc(&offs, colors * 4); + if (p == NULL) + return (1); + + x86bios_init_regs(®s); + regs.R_AX = 0x4f09; + /* regs.R_BL = 0; */ + regs.R_CX = colors; + regs.R_DX = start; + + regs.R_ES = X86BIOS_PHYSTOSEG(offs); + regs.R_DI = X86BIOS_PHYSTOOFF(offs); + bits = 8 - bits; for (i = 0; i < colors; ++i) { - p[i*4] = palette[i*3 + 2] >> bits; - p[i*4 + 1] = palette[i*3 + 1] >> bits; - p[i*4 + 2] = palette[i*3] >> bits; - p[i*4 + 3] = 0; + p[i * 4] = palette[i * 3 + 2] >> bits; + p[i * 4 + 1] = palette[i * 3 + 1] >> bits; + p[i * 4 + 2] = palette[i * 3] >> bits; + p[i * 4 + 3] = 0; } + x86bios_intr(®s, 0x10); + x86bios_free(p, colors * 4); - bzero(&vmf, sizeof(vmf)); - vmf.vmf_eax = 0x4f09; - vmf.vmf_ebx = 0; /* set primary palette data */ - vmf.vmf_ecx = colors; - vmf.vmf_edx = start; - vm86_getptr(&vesa_vmcontext, (vm_offset_t)p, &vmf.vmf_es, &vmf.vmf_di); - - err = vm86_datacall(0x10, &vmf, &vesa_vmcontext); - return ((err != 0) || (vmf.vmf_ax != 0x4f)); + return (regs.R_AX != 0x004f); } -#ifdef notyet static int vesa_bios_load_palette2(int start, int colors, u_char *r, u_char *g, u_char *b, int bits) { - struct vm86frame vmf; + x86regs_t regs; + uint32_t offs; u_char *p; - int err; int i; - p = vesa_vm86_buf; + p = (u_char *)x86bios_alloc(&offs, colors * 4); + if (p == NULL) + return (1); + + x86bios_init_regs(®s); + regs.R_AX = 0x4f09; + /* regs.R_BL = 0; */ + regs.R_CX = colors; + regs.R_DX = start; + + regs.R_ES = X86BIOS_PHYSTOSEG(offs); + regs.R_DI = X86BIOS_PHYSTOOFF(offs); + bits = 8 - bits; for (i = 0; i < colors; ++i) { - p[i*4] = b[i] >> bits; - p[i*4 + 1] = g[i] >> bits; - p[i*4 + 2] = r[i] >> bits; - p[i*4 + 3] = 0; + p[i * 4] = b[i] >> bits; + p[i * 4 + 1] = g[i] >> bits; + p[i * 4 + 2] = r[i] >> bits; + p[i * 4 + 3] = 0; } + x86bios_intr(®s, 0x10); + x86bios_free(p, colors * 4); - bzero(&vmf, sizeof(vmf)); - vmf.vmf_eax = 0x4f09; - vmf.vmf_ebx = 0; /* set primary palette data */ - vmf.vmf_ecx = colors; - vmf.vmf_edx = start; - vm86_getptr(&vesa_vmcontext, (vm_offset_t)p, &vmf.vmf_es, &vmf.vmf_di); - - err = vm86_datacall(0x10, &vmf, &vesa_vmcontext); - return ((err != 0) || (vmf.vmf_ax != 0x4f)); + return (regs.R_AX != 0x004f); } -#endif -static int +static ssize_t vesa_bios_state_buf_size(void) { - struct vm86frame vmf; - int err; - - bzero(&vmf, sizeof(vmf)); - vmf.vmf_eax = 0x4f04; - vmf.vmf_ecx = STATE_ALL; - vmf.vmf_edx = STATE_SIZE; - err = vm86_intcall(0x10, &vmf); - if ((err != 0) || (vmf.vmf_ax != 0x4f)) - return 0; - return vmf.vmf_bx*64; + x86regs_t regs; + + x86bios_init_regs(®s); + regs.R_AX = 0x4f04; + /* regs.R_DL = STATE_SIZE; */ + regs.R_CX = STATE_ALL; + + x86bios_intr(®s, 0x10); + + if (regs.R_AX != 0x004f) + return (0); + + return (regs.R_BX * 64); } static int vesa_bios_save_restore(int code, void *p, size_t size) { - struct vm86frame vmf; - u_char *buf; - int err; + x86regs_t regs; + uint32_t offs; + void *buf; - if (size > VESA_VM86_BUFSIZE) + if (code != STATE_SAVE && code != STATE_LOAD) return (1); - bzero(&vmf, sizeof(vmf)); - vmf.vmf_eax = 0x4f04; - vmf.vmf_ecx = STATE_ALL; - vmf.vmf_edx = code; /* STATE_SAVE/STATE_LOAD */ - buf = vesa_vm86_buf; - vm86_getptr(&vesa_vmcontext, (vm_offset_t)buf, &vmf.vmf_es, &vmf.vmf_bx); - bcopy(p, buf, size); - - err = vm86_datacall(0x10, &vmf, &vesa_vmcontext); - bcopy(buf, p, size); - return ((err != 0) || (vmf.vmf_ax != 0x4f)); + buf = x86bios_alloc(&offs, size); + + x86bios_init_regs(®s); + regs.R_AX = 0x4f04; + regs.R_DL = code; + regs.R_CX = STATE_ALL; + + regs.R_ES = X86BIOS_PHYSTOSEG(offs); + regs.R_BX = X86BIOS_PHYSTOOFF(offs); + + switch (code) { + case STATE_SAVE: + x86bios_intr(®s, 0x10); + bcopy(buf, p, size); + break; + case STATE_LOAD: + bcopy(p, buf, size); + x86bios_intr(®s, 0x10); + break; + } + x86bios_free(buf, size); + + return (regs.R_AX != 0x004f); } +#if 0 static int vesa_bios_get_line_length(void) { - struct vm86frame vmf; - int err; - - bzero(&vmf, sizeof(vmf)); - vmf.vmf_eax = 0x4f06; - vmf.vmf_ebx = 1; /* get scan line length */ - err = vm86_intcall(0x10, &vmf); - if ((err != 0) || (vmf.vmf_ax != 0x4f)) - return -1; - return vmf.vmf_bx; /* line length in bytes */ + x86regs_t regs; + + x86bios_init_regs(®s); + regs.R_AX = 0x4f06; + regs.R_BL = 1; + + x86bios_intr(®s, 0x10); + + if (regs.R_AX != 0x004f) + return (-1); + + return (regs.R_BX); } +#endif static int vesa_bios_set_line_length(int pixel, int *bytes, int *lines) { - struct vm86frame vmf; - int err; - - bzero(&vmf, sizeof(vmf)); - vmf.vmf_eax = 0x4f06; - vmf.vmf_ebx = 0; /* set scan line length in pixel */ - vmf.vmf_ecx = pixel; - err = vm86_intcall(0x10, &vmf); + x86regs_t regs; + + x86bios_init_regs(®s); + regs.R_AX = 0x4f06; + /* regs.R_BL = 0; */ + regs.R_CX = pixel; + + x86bios_intr(®s, 0x10); + #if VESA_DEBUG > 1 - printf("bx:%d, cx:%d, dx:%d\n", vmf.vmf_bx, vmf.vmf_cx, vmf.vmf_dx); + printf("bx:%d, cx:%d, dx:%d\n", regs.R_BX, regs.R_CX, regs.R_DX); #endif - if ((err != 0) || (vmf.vmf_ax != 0x4f)) - return 1; - if (bytes) - *bytes = vmf.vmf_bx; - if (lines) - *lines = vmf.vmf_dx; - return 0; + if (regs.R_AX != 0x004f) + return (-1); + + if (bytes != NULL) + *bytes = regs.R_BX; + if (lines != NULL) + *lines = regs.R_DX; + + return (0); } #if 0 static int vesa_bios_get_start(int *x, int *y) { - struct vm86frame vmf; - int err; - - bzero(&vmf, sizeof(vmf)); - vmf.vmf_eax = 0x4f07; - vmf.vmf_ebx = 1; /* get display start */ - err = vm86_intcall(0x10, &vmf); - if ((err != 0) || (vmf.vmf_ax != 0x4f)) - return 1; - *x = vmf.vmf_cx; - *y = vmf.vmf_dx; - return 0; + x86regs_t regs; + + x86bios_init_regs(®s); + regs.R_AX = 0x4f07; + regs.R_BL = 1; + + x86bios_intr(®s, 0x10); + + if (regs.R_AX != 0x004f) + return (-1); + + *x = regs.R_CX; + *y = regs.R_DX; + + return (0); } #endif static int vesa_bios_set_start(int x, int y) { - struct vm86frame vmf; - int err; - - bzero(&vmf, sizeof(vmf)); - vmf.vmf_eax = 0x4f07; - vmf.vmf_ebx = 0x80; /* set display start */ - vmf.vmf_edx = y; - vmf.vmf_ecx = x; - err = vm86_intcall(0x10, &vmf); - return ((err != 0) || (vmf.vmf_ax != 0x4f)); + x86regs_t regs; + + x86bios_init_regs(®s); + regs.R_AX = 0x4f07; + regs.R_BL = 0x80; + regs.R_CX = x; + regs.R_DX = y; + + x86bios_intr(®s, 0x10); + + return (regs.R_AX != 0x004f); } /* map a generic video mode to a known mode */ @@ -545,9 +658,9 @@ vesa_map_gen_mode_num(int type, int color, int mode) for (i = 0; i < sizeof(mode_map)/sizeof(mode_map[0]); ++i) { if (mode_map[i].from == mode) - return mode_map[i].to; + return (mode_map[i].to); } - return mode; + return (mode); } static int @@ -561,6 +674,7 @@ vesa_translate_flags(u_int16_t vflags) { V_MODECOLOR, V_INFO_COLOR, 0 }, { V_MODEGRAPHICS, V_INFO_GRAPHICS, 0 }, { V_MODELFB, V_INFO_LINEAR, 0 }, + { V_MODENONVGA, V_INFO_NONVGA, 0 }, }; int flags; int i; @@ -569,7 +683,7 @@ vesa_translate_flags(u_int16_t vflags) flags |= (vflags & ftable[i].mask) ? ftable[i].set : ftable[i].reset; } - return flags; + return (flags); } static int @@ -590,118 +704,153 @@ vesa_translate_mmodel(u_int8_t vmodel) for (i = 0; mtable[i].mmodel >= 0; ++i) { if (mtable[i].vmodel == vmodel) - return mtable[i].mmodel; + return (mtable[i].mmodel); } - return V_INFO_MM_OTHER; + return (V_INFO_MM_OTHER); } -static void -*vesa_fix_ptr(u_int32_t p, u_int16_t seg, u_int16_t off, u_char *buf) -{ - if (p == 0) - return NULL; - if (((p >> 16) == seg) && ((p & 0xffff) >= off)) - return (void *)(buf + ((p & 0xffff) - off)); - else { - p = BIOS_SADDRTOLADDR(p); - return (void *)BIOS_PADDRTOVADDR(p); - } -} +#define VESA_MAXSTR 256 + +#define VESA_STRCPY(dst, src) do { \ + char *str; \ + int i; \ + dst = malloc(VESA_MAXSTR, M_DEVBUF, M_WAITOK); \ + str = x86bios_offset(BIOS_SADDRTOLADDR(src)); \ + for (i = 0; i < VESA_MAXSTR - 1 && str[i] != '\0'; i++) \ + dst[i] = str[i]; \ + dst[i] = '\0'; \ +} while (0) static int vesa_bios_init(void) { - static u_char buf[512]; - struct vm86frame vmf; + static struct vesa_info buf; struct vesa_mode vmode; video_info_t *p; - u_char *vmbuf; + x86regs_t regs; + size_t bsize; + size_t msize; + void *vmbuf; + uint32_t offs; + uint16_t vers; + int bpsl; int is_via_cle266; int modes; - int err; int i; if (vesa_init_done) - return 0; + return (0); has_vesa_bios = FALSE; vesa_adp_info = NULL; vesa_vmode_max = 0; vesa_vmode[0].vi_mode = EOT; - /* Allocate a buffer and add each page to the vm86 context. */ - vesa_vm86_buf = malloc(VESA_VM86_BUFSIZE, M_DEVBUF, M_WAITOK | M_ZERO); - KASSERT(((vm_offset_t)vesa_vm86_buf & PAGE_MASK) == 0, - ("bad vesa_vm86_buf alignment")); - for (i = 0; i < howmany(VESA_VM86_BUFSIZE, PAGE_SIZE); i++) - vm86_addpage(&vesa_vmcontext, i + 1, - (vm_offset_t)vesa_vm86_buf + PAGE_SIZE * i); + /* + * If the VBE real mode interrupt vector is not found, try BIOS POST. + */ + if (x86bios_get_intr(0x10) == 0) { + if (vesa_bios_post() != 0) + return (1); + if (bootverbose) { + offs = x86bios_get_intr(0x10); + printf("VESA: interrupt vector installed (0x%x)\n", + BIOS_SADDRTOLADDR(offs)); + } + } + + x86bios_init_regs(®s); + regs.R_AX = 0x4f00; + + vmbuf = x86bios_alloc(&offs, sizeof(buf)); + if (vmbuf == NULL) + return (1); + + regs.R_ES = X86BIOS_PHYSTOSEG(offs); + regs.R_DI = X86BIOS_PHYSTOOFF(offs); - vmbuf = vesa_vm86_buf; - bzero(&vmf, sizeof(vmf)); /* paranoia */ bcopy("VBE2", vmbuf, 4); /* try for VBE2 data */ - vmf.vmf_eax = 0x4f00; - vm86_getptr(&vesa_vmcontext, (vm_offset_t)vmbuf, &vmf.vmf_es, &vmf.vmf_di); - - err = vm86_datacall(0x10, &vmf, &vesa_vmcontext); - if ((err != 0) || (vmf.vmf_ax != 0x4f) || bcmp("VESA", vmbuf, 4)) - return 1; - bcopy(vmbuf, buf, sizeof(buf)); - vesa_adp_info = (struct vesa_info *)buf; + x86bios_intr(®s, 0x10); + + if (regs.R_AX != 0x004f || bcmp("VESA", vmbuf, 4) != 0) + goto fail; + + bcopy(vmbuf, &buf, sizeof(buf)); + + vesa_adp_info = &buf; if (bootverbose) { printf("VESA: information block\n"); - dump_buffer(buf, 64); + hexdump(&buf, sizeof(buf), NULL, HD_OMIT_CHARS); } - if (vesa_adp_info->v_version < 0x0102) { + + vers = buf.v_version = le16toh(buf.v_version); + buf.v_oemstr = le32toh(buf.v_oemstr); + buf.v_flags = le32toh(buf.v_flags); + buf.v_modetable = le32toh(buf.v_modetable); + buf.v_memsize = le16toh(buf.v_memsize); + buf.v_revision = le16toh(buf.v_revision); + buf.v_venderstr = le32toh(buf.v_venderstr); + buf.v_prodstr = le32toh(buf.v_prodstr); + buf.v_revstr = le32toh(buf.v_revstr); + + if (vers < 0x0102) { printf("VESA: VBE version %d.%d is not supported; " - "version 1.2 or later is required.\n", - ((vesa_adp_info->v_version & 0xf000) >> 12) * 10 - + ((vesa_adp_info->v_version & 0x0f00) >> 8), - ((vesa_adp_info->v_version & 0x00f0) >> 4) * 10 - + (vesa_adp_info->v_version & 0x000f)); - return 1; + "version 1.2 or later is required.\n", + ((vers & 0xf000) >> 12) * 10 + ((vers & 0x0f00) >> 8), + ((vers & 0x00f0) >> 4) * 10 + (vers & 0x000f)); + return (1); } - /* fix string ptrs */ - vesa_oemstr = (char *)vesa_fix_ptr(vesa_adp_info->v_oemstr, - vmf.vmf_es, vmf.vmf_di, buf); - is_via_cle266 = strcmp(vesa_oemstr, VESA_VIA_CLE266) == 0; - - if (vesa_adp_info->v_version >= 0x0200) { - vesa_venderstr = - (char *)vesa_fix_ptr(vesa_adp_info->v_venderstr, - vmf.vmf_es, vmf.vmf_di, buf); - vesa_prodstr = - (char *)vesa_fix_ptr(vesa_adp_info->v_prodstr, - vmf.vmf_es, vmf.vmf_di, buf); - vesa_revstr = - (char *)vesa_fix_ptr(vesa_adp_info->v_revstr, - vmf.vmf_es, vmf.vmf_di, buf); + VESA_STRCPY(vesa_oemstr, buf.v_oemstr); + if (vers >= 0x0200) { + VESA_STRCPY(vesa_venderstr, buf.v_venderstr); + VESA_STRCPY(vesa_prodstr, buf.v_prodstr); + VESA_STRCPY(vesa_revstr, buf.v_revstr); } + is_via_cle266 = strncmp(vesa_oemstr, VESA_VIA_CLE266, + sizeof(VESA_VIA_CLE266)) == 0; - /* obtain video mode information */ - vesa_vmodetab = (u_int16_t *)vesa_fix_ptr(vesa_adp_info->v_modetable, - vmf.vmf_es, vmf.vmf_di, buf); - if (vesa_vmodetab == NULL) - return 1; - for (i = 0, modes = 0; - (i < (M_VESA_MODE_MAX - M_VESA_BASE + 1)) - && (vesa_vmodetab[i] != 0xffff); ++i) { + if (buf.v_modetable == 0) + goto fail; + + msize = (size_t)buf.v_memsize * 64 * 1024; + + vesa_vmodetab = x86bios_offset(BIOS_SADDRTOLADDR(buf.v_modetable)); + + for (i = 0, modes = 0; (i < (M_VESA_MODE_MAX - M_VESA_BASE + 1)) && + (vesa_vmodetab[i] != 0xffff); ++i) { + vesa_vmodetab[i] = le16toh(vesa_vmodetab[i]); if (vesa_bios_get_mode(vesa_vmodetab[i], &vmode)) continue; + vmode.v_modeattr = le16toh(vmode.v_modeattr); + vmode.v_wgran = le16toh(vmode.v_wgran); + vmode.v_wsize = le16toh(vmode.v_wsize); + vmode.v_waseg = le16toh(vmode.v_waseg); + vmode.v_wbseg = le16toh(vmode.v_wbseg); + vmode.v_posfunc = le32toh(vmode.v_posfunc); + vmode.v_bpscanline = le16toh(vmode.v_bpscanline); + vmode.v_width = le16toh(vmode.v_width); + vmode.v_height = le16toh(vmode.v_height); + vmode.v_lfb = le32toh(vmode.v_lfb); + vmode.v_offscreen = le32toh(vmode.v_offscreen); + vmode.v_offscreensize = le16toh(vmode.v_offscreensize); + vmode.v_linbpscanline = le16toh(vmode.v_linbpscanline); + vmode.v_maxpixelclock = le32toh(vmode.v_maxpixelclock); + /* reject unsupported modes */ #if 0 - if ((vmode.v_modeattr & (V_MODESUPP | V_MODEOPTINFO - | V_MODENONVGA)) - != (V_MODESUPP | V_MODEOPTINFO)) + if ((vmode.v_modeattr & + (V_MODESUPP | V_MODEOPTINFO | V_MODENONVGA)) != + (V_MODESUPP | V_MODEOPTINFO)) continue; #else if ((vmode.v_modeattr & V_MODEOPTINFO) == 0) { #if VESA_DEBUG > 1 - printf( - "Rejecting VESA %s mode: %d x %d x %d bpp attr = %x\n", - vmode.v_modeattr & V_MODEGRAPHICS ? "graphics" : "text", + printf("Rejecting VESA %s mode: %d x %d x %d bpp " + " attr = %x\n", + vmode.v_modeattr & V_MODEGRAPHICS ? + "graphics" : "text", vmode.v_width, vmode.v_height, vmode.v_bpp, vmode.v_modeattr); #endif @@ -709,14 +858,33 @@ vesa_bios_init(void) } #endif + bpsl = (vmode.v_modeattr & V_MODELFB) != 0 && vers >= 0x0300 ? + vmode.v_linbpscanline : vmode.v_bpscanline; + bsize = bpsl * vmode.v_height; + if ((vmode.v_modeattr & V_MODEGRAPHICS) != 0) + bsize *= vmode.v_planes; + + /* Does it have enough memory to support this mode? */ + if (msize < bsize) { +#if VESA_DEBUG > 1 + printf("Rejecting VESA %s mode: %d x %d x %d bpp " + " attr = %x, not enough memory\n", + vmode.v_modeattr & V_MODEGRAPHICS ? + "graphics" : "text", + vmode.v_width, vmode.v_height, vmode.v_bpp, + vmode.v_modeattr); +#endif + continue; + } + /* expand the array if necessary */ if (modes >= vesa_vmode_max) { vesa_vmode_max += MODE_TABLE_DELTA; - p = malloc(sizeof(*vesa_vmode)*(vesa_vmode_max + 1), - M_DEVBUF, M_WAITOK); + p = malloc(sizeof(*vesa_vmode) * (vesa_vmode_max + 1), + M_DEVBUF, M_WAITOK); #if VESA_DEBUG > 1 printf("vesa_bios_init(): modes:%d, vesa_mode_max:%d\n", - modes, vesa_vmode_max); + modes, vesa_vmode_max); #endif if (modes > 0) { bcopy(vesa_vmode, p, sizeof(*vesa_vmode)*modes); @@ -746,73 +914,95 @@ vesa_bios_init(void) vesa_vmode[modes].vi_planes = vmode.v_planes; vesa_vmode[modes].vi_cwidth = vmode.v_cwidth; vesa_vmode[modes].vi_cheight = vmode.v_cheight; - vesa_vmode[modes].vi_window = (u_int)vmode.v_waseg << 4; + vesa_vmode[modes].vi_window = (vm_offset_t)vmode.v_waseg << 4; /* XXX window B */ - vesa_vmode[modes].vi_window_size = vmode.v_wsize*1024; - vesa_vmode[modes].vi_window_gran = vmode.v_wgran*1024; + vesa_vmode[modes].vi_window_size = vmode.v_wsize * 1024; + vesa_vmode[modes].vi_window_gran = vmode.v_wgran * 1024; if (vmode.v_modeattr & V_MODELFB) vesa_vmode[modes].vi_buffer = vmode.v_lfb; - else - vesa_vmode[modes].vi_buffer = 0; - /* XXX */ - vesa_vmode[modes].vi_buffer_size - = vesa_adp_info->v_memsize*64*1024; -#if 0 - if (vmode.v_offscreen > vmode.v_lfb) - vesa_vmode[modes].vi_buffer_size - = vmode.v_offscreen + vmode.v_offscreensize*1024 - - vmode.v_lfb; - else - vesa_vmode[modes].vi_buffer_size - = vmode.v_offscreen + vmode.v_offscreensize*1024 -#endif - vesa_vmode[modes].vi_mem_model - = vesa_translate_mmodel(vmode.v_memmodel); - vesa_vmode[modes].vi_pixel_fields[0] = 0; - vesa_vmode[modes].vi_pixel_fields[1] = 0; - vesa_vmode[modes].vi_pixel_fields[2] = 0; - vesa_vmode[modes].vi_pixel_fields[3] = 0; - vesa_vmode[modes].vi_pixel_fsizes[0] = 0; - vesa_vmode[modes].vi_pixel_fsizes[1] = 0; - vesa_vmode[modes].vi_pixel_fsizes[2] = 0; - vesa_vmode[modes].vi_pixel_fsizes[3] = 0; - if (vesa_vmode[modes].vi_mem_model == V_INFO_MM_PACKED) { - vesa_vmode[modes].vi_pixel_size = (vmode.v_bpp + 7)/8; - } else if (vesa_vmode[modes].vi_mem_model == V_INFO_MM_DIRECT) { - vesa_vmode[modes].vi_pixel_size = (vmode.v_bpp + 7)/8; - vesa_vmode[modes].vi_pixel_fields[0] - = vmode.v_redfieldpos; - vesa_vmode[modes].vi_pixel_fields[1] - = vmode.v_greenfieldpos; - vesa_vmode[modes].vi_pixel_fields[2] - = vmode.v_bluefieldpos; - vesa_vmode[modes].vi_pixel_fields[3] - = vmode.v_resfieldpos; - vesa_vmode[modes].vi_pixel_fsizes[0] - = vmode.v_redmasksize; - vesa_vmode[modes].vi_pixel_fsizes[1] - = vmode.v_greenmasksize; - vesa_vmode[modes].vi_pixel_fsizes[2] - = vmode.v_bluemasksize; - vesa_vmode[modes].vi_pixel_fsizes[3] - = vmode.v_resmasksize; - } else { - vesa_vmode[modes].vi_pixel_size = 0; + vesa_vmode[modes].vi_buffer_size = bsize; + vesa_vmode[modes].vi_mem_model = + vesa_translate_mmodel(vmode.v_memmodel); + switch (vesa_vmode[modes].vi_mem_model) { + case V_INFO_MM_DIRECT: + if ((vmode.v_modeattr & V_MODELFB) != 0 && + vers >= 0x0300) { + vesa_vmode[modes].vi_pixel_fields[0] = + vmode.v_linredfieldpos; + vesa_vmode[modes].vi_pixel_fields[1] = + vmode.v_lingreenfieldpos; + vesa_vmode[modes].vi_pixel_fields[2] = + vmode.v_linbluefieldpos; + vesa_vmode[modes].vi_pixel_fields[3] = + vmode.v_linresfieldpos; + vesa_vmode[modes].vi_pixel_fsizes[0] = + vmode.v_linredmasksize; + vesa_vmode[modes].vi_pixel_fsizes[1] = + vmode.v_lingreenmasksize; + vesa_vmode[modes].vi_pixel_fsizes[2] = + vmode.v_linbluemasksize; + vesa_vmode[modes].vi_pixel_fsizes[3] = + vmode.v_linresmasksize; + } else { + vesa_vmode[modes].vi_pixel_fields[0] = + vmode.v_redfieldpos; + vesa_vmode[modes].vi_pixel_fields[1] = + vmode.v_greenfieldpos; + vesa_vmode[modes].vi_pixel_fields[2] = + vmode.v_bluefieldpos; + vesa_vmode[modes].vi_pixel_fields[3] = + vmode.v_resfieldpos; + vesa_vmode[modes].vi_pixel_fsizes[0] = + vmode.v_redmasksize; + vesa_vmode[modes].vi_pixel_fsizes[1] = + vmode.v_greenmasksize; + vesa_vmode[modes].vi_pixel_fsizes[2] = + vmode.v_bluemasksize; + vesa_vmode[modes].vi_pixel_fsizes[3] = + vmode.v_resmasksize; + } + /* FALLTHROUGH */ + case V_INFO_MM_PACKED: + vesa_vmode[modes].vi_pixel_size = (vmode.v_bpp + 7) / 8; + break; } - - vesa_vmode[modes].vi_flags - = vesa_translate_flags(vmode.v_modeattr) | V_INFO_VESA; + vesa_vmode[modes].vi_flags = + vesa_translate_flags(vmode.v_modeattr) | V_INFO_VESA; + ++modes; } vesa_vmode[modes].vi_mode = EOT; + if (bootverbose) printf("VESA: %d mode(s) found\n", modes); has_vesa_bios = (modes > 0); if (!has_vesa_bios) - return (1); + goto fail; + x86bios_free(vmbuf, sizeof(buf)); return (0); + +fail: + if (vmbuf != NULL) + x86bios_free(vmbuf, sizeof(buf)); + if (vesa_oemstr != NULL) { + free(vesa_oemstr, M_DEVBUF); + vesa_oemstr = NULL; + } + if (vesa_venderstr != NULL) { + free(vesa_venderstr, M_DEVBUF); + vesa_venderstr = NULL; + } + if (vesa_prodstr != NULL) { + free(vesa_prodstr, M_DEVBUF); + vesa_prodstr = NULL; + } + if (vesa_revstr != NULL) { + free(vesa_revstr, M_DEVBUF); + vesa_revstr = NULL; + } + return (1); } static void @@ -825,30 +1015,6 @@ vesa_clear_modes(video_info_t *info, int color) } } -static vm_offset_t -vesa_map_buffer(u_int paddr, size_t size) -{ - vm_offset_t vaddr; - u_int off; - - off = paddr - trunc_page(paddr); - vaddr = (vm_offset_t)pmap_mapdev(paddr - off, size + off); -#if VESA_DEBUG > 1 - printf("vesa_map_buffer: paddr:%x vaddr:%x size:%x off:%x\n", - paddr, vaddr, size, off); -#endif - return (vaddr + off); -} - -static void -vesa_unmap_buffer(vm_offset_t vaddr, size_t size) -{ -#if VESA_DEBUG > 1 - printf("vesa_unmap_buffer: vaddr:%x size:%x\n", vaddr, size); -#endif - kmem_free(kernel_map, vaddr, size); -} - /* entry points */ static int @@ -860,9 +1026,9 @@ vesa_configure(int flags) int i; if (vesa_init_done) - return 0; + return (0); if (flags & VIO_PROBE_ONLY) - return 0; /* XXX */ + return (0); /* * If the VESA module has already been loaded, abort loading @@ -870,10 +1036,11 @@ vesa_configure(int flags) */ for (i = 0; (adp = vid_get_adapter(i)) != NULL; ++i) { if (adp->va_flags & V_ADP_VESA) - return ENXIO; + return (ENXIO); if (adp->va_type == KD_VGA) break; } + /* * The VGA adapter is not found. This is because either * 1) the VGA driver has not been initialized, or 2) the VGA card @@ -882,7 +1049,7 @@ vesa_configure(int flags) */ if (adp == NULL) { vga_sub_configure = vesa_configure; - return ENODEV; + return (ENODEV); } /* count number of registered adapters */ @@ -894,7 +1061,7 @@ vesa_configure(int flags) vesa_adp = adp; if (vesa_bios_init()) { vesa_adp = NULL; - return ENXIO; + return (ENXIO); } vesa_adp->va_flags |= V_ADP_VESA; @@ -911,36 +1078,40 @@ vesa_configure(int flags) vesa_init_done = TRUE; } else { vesa_adp = NULL; - return error; + return (error); } - return 0; + return (0); } #if 0 static int vesa_nop(void) { - return 0; + + return (0); } #endif static int vesa_error(void) { - return 1; + + return (1); } static int vesa_probe(int unit, video_adapter_t **adpp, void *arg, int flags) { - return (*prevvidsw->probe)(unit, adpp, arg, flags); + + return ((*prevvidsw->probe)(unit, adpp, arg, flags)); } static int vesa_init(int unit, video_adapter_t *adp, int flags) { - return (*prevvidsw->init)(unit, adp, flags); + + return ((*prevvidsw->init)(unit, adp, flags)); } static int @@ -949,10 +1120,10 @@ vesa_get_info(video_adapter_t *adp, int mode, video_info_t *info) int i; if ((*prevvidsw->get_info)(adp, mode, info) == 0) - return 0; + return (0); if (adp != vesa_adp) - return 1; + return (1); mode = vesa_map_gen_mode_num(vesa_adp->va_type, vesa_adp->va_flags & V_ADP_COLOR, mode); @@ -961,10 +1132,10 @@ vesa_get_info(video_adapter_t *adp, int mode, video_info_t *info) continue; if (vesa_vmode[i].vi_mode == mode) { *info = vesa_vmode[i]; - return 0; + return (0); } } - return 1; + return (1); } static int @@ -973,9 +1144,9 @@ vesa_query_mode(video_adapter_t *adp, video_info_t *info) int i; if ((*prevvidsw->query_mode)(adp, info) == 0) - return 0; + return (0); if (adp != vesa_adp) - return ENODEV; + return (ENODEV); for (i = 0; vesa_vmode[i].vi_mode != EOT; ++i) { if ((info->vi_width != 0) @@ -1001,19 +1172,18 @@ vesa_query_mode(video_adapter_t *adp, video_info_t *info) && (info->vi_flags != vesa_vmode[i].vi_flags)) continue; *info = vesa_vmode[i]; - return 0; + return (0); } - return ENODEV; + return (ENODEV); } static int vesa_set_mode(video_adapter_t *adp, int mode) { video_info_t info; - int len; if (adp != vesa_adp) - return (*prevvidsw->set_mode)(adp, mode); + return ((*prevvidsw->set_mode)(adp, mode)); mode = vesa_map_gen_mode_num(adp->va_type, adp->va_flags & V_ADP_COLOR, mode); @@ -1030,11 +1200,16 @@ vesa_set_mode(video_adapter_t *adp, int mode) * the new mode correctly. */ if (VESA_MODE(adp->va_mode)) { - if ((*prevvidsw->get_info)(adp, mode, &info) == 0) { + if (!VESA_MODE(mode) && + (*prevvidsw->get_info)(adp, mode, &info) == 0) { + if ((adp->va_flags & V_ADP_DAC8) != 0) { + vesa_bios_set_dac(6); + adp->va_flags &= ~V_ADP_DAC8; + } int10_set_mode(adp->va_initial_bios_mode); if (adp->va_info.vi_flags & V_INFO_LINEAR) - vesa_unmap_buffer(adp->va_buffer, - vesa_adp_info->v_memsize*64*1024); + pmap_unmapdev(adp->va_buffer, + adp->va_buffer_size); /* * Once (*prevvidsw->get_info)() succeeded, * (*prevvidsw->set_mode)() below won't fail... @@ -1043,12 +1218,12 @@ vesa_set_mode(video_adapter_t *adp, int mode) } /* we may not need to handle this mode after all... */ - if ((*prevvidsw->set_mode)(adp, mode) == 0) - return 0; + if (!VESA_MODE(mode) && (*prevvidsw->set_mode)(adp, mode) == 0) + return (0); /* is the new mode supported? */ if (vesa_get_info(adp, mode, &info)) - return 1; + return (1); /* assert(VESA_MODE(mode)); */ #if VESA_DEBUG > 0 @@ -1059,11 +1234,19 @@ vesa_set_mode(video_adapter_t *adp, int mode) info.vi_flags &= ~V_INFO_LINEAR; if (vesa_bios_set_mode(mode | ((info.vi_flags & V_INFO_LINEAR) ? 0x4000 : 0))) - return 1; + return (1); + + /* Palette format is reset by the above VBE function call. */ + adp->va_flags &= ~V_ADP_DAC8; + + if ((vesa_adp_info->v_flags & V_DAC8) != 0 && + (info.vi_flags & V_INFO_GRAPHICS) != 0 && + (info.vi_flags & V_INFO_NONVGA) != 0 && + vesa_bios_set_dac(8) > 6) + adp->va_flags |= V_ADP_DAC8; if (adp->va_info.vi_flags & V_INFO_LINEAR) - vesa_unmap_buffer(adp->va_buffer, - vesa_adp_info->v_memsize*64*1024); + pmap_unmapdev(adp->va_buffer, adp->va_buffer_size); #if VESA_DEBUG > 0 printf("VESA: mode set!\n"); @@ -1079,183 +1262,161 @@ vesa_set_mode(video_adapter_t *adp, int mode) printf("VESA: setting up LFB\n"); #endif vesa_adp->va_buffer = - vesa_map_buffer(info.vi_buffer, - vesa_adp_info->v_memsize*64*1024); - vesa_adp->va_buffer_size = info.vi_buffer_size; + (vm_offset_t)pmap_mapdev_attr(info.vi_buffer, + info.vi_buffer_size, PAT_WRITE_COMBINING); vesa_adp->va_window = vesa_adp->va_buffer; - vesa_adp->va_window_size = info.vi_buffer_size/info.vi_planes; - vesa_adp->va_window_gran = info.vi_buffer_size/info.vi_planes; + vesa_adp->va_window_size = info.vi_buffer_size / info.vi_planes; + vesa_adp->va_window_gran = info.vi_buffer_size / info.vi_planes; } else { vesa_adp->va_buffer = 0; - vesa_adp->va_buffer_size = info.vi_buffer_size; - vesa_adp->va_window = BIOS_PADDRTOVADDR(info.vi_window); + vesa_adp->va_window = (vm_offset_t)x86bios_offset(info.vi_window); vesa_adp->va_window_size = info.vi_window_size; vesa_adp->va_window_gran = info.vi_window_gran; } + vesa_adp->va_buffer_size = info.vi_buffer_size; vesa_adp->va_window_orig = 0; - len = vesa_bios_get_line_length(); - if (len > 0) { - vesa_adp->va_line_width = len; - } else if (info.vi_flags & V_INFO_GRAPHICS) { - switch (info.vi_depth/info.vi_planes) { - case 1: - vesa_adp->va_line_width = info.vi_width/8; - break; - case 2: - vesa_adp->va_line_width = info.vi_width/4; - break; - case 4: - vesa_adp->va_line_width = info.vi_width/2; - break; - case 8: - default: /* shouldn't happen */ - vesa_adp->va_line_width = info.vi_width; - break; - case 15: - case 16: - vesa_adp->va_line_width = info.vi_width*2; - break; - case 24: - case 32: - vesa_adp->va_line_width = info.vi_width*4; - break; - } - } else { - vesa_adp->va_line_width = info.vi_width; - } + vesa_adp->va_line_width = info.vi_buffer_size / info.vi_height; + if ((info.vi_flags & V_INFO_GRAPHICS) != 0) + vesa_adp->va_line_width /= info.vi_planes; vesa_adp->va_disp_start.x = 0; vesa_adp->va_disp_start.y = 0; #if VESA_DEBUG > 0 - printf("vesa_set_mode(): vi_width:%d, len:%d, line_width:%d\n", - info.vi_width, len, vesa_adp->va_line_width); + printf("vesa_set_mode(): vi_width:%d, line_width:%d\n", + info.vi_width, vesa_adp->va_line_width); #endif bcopy(&info, &vesa_adp->va_info, sizeof(vesa_adp->va_info)); /* move hardware cursor out of the way */ (*vidsw[vesa_adp->va_index]->set_hw_cursor)(vesa_adp, -1, -1); - return 0; + return (0); } static int vesa_save_font(video_adapter_t *adp, int page, int fontsize, int fontwidth, u_char *data, int ch, int count) { - return (*prevvidsw->save_font)(adp, page, fontsize, fontwidth, data, - ch, count); + + return ((*prevvidsw->save_font)(adp, page, fontsize, fontwidth, data, + ch, count)); } static int vesa_load_font(video_adapter_t *adp, int page, int fontsize, int fontwidth, u_char *data, int ch, int count) { - return (*prevvidsw->load_font)(adp, page, fontsize, fontwidth, data, - ch, count); + + return ((*prevvidsw->load_font)(adp, page, fontsize, fontwidth, data, + ch, count)); } static int vesa_show_font(video_adapter_t *adp, int page) { - return (*prevvidsw->show_font)(adp, page); + + return ((*prevvidsw->show_font)(adp, page)); } static int vesa_save_palette(video_adapter_t *adp, u_char *palette) { int bits; - int error; - if ((adp == vesa_adp) && (vesa_adp_info->v_flags & V_DAC8) - && VESA_MODE(adp->va_mode)) { - bits = vesa_bios_get_dac(); - error = vesa_bios_save_palette(0, 256, palette, bits); - if (error == 0) - return 0; - if (bits != 6) - return error; + if (adp == vesa_adp && VESA_MODE(adp->va_mode) && + (adp->va_info.vi_flags & V_INFO_NONVGA) != 0) { + bits = (adp->va_flags & V_ADP_DAC8) != 0 ? 8 : 6; + return (vesa_bios_save_palette(0, 256, palette, bits)); } - return (*prevvidsw->save_palette)(adp, palette); + return ((*prevvidsw->save_palette)(adp, palette)); } static int vesa_load_palette(video_adapter_t *adp, u_char *palette) { -#ifdef notyet int bits; - int error; - if ((adp == vesa_adp) && (vesa_adp_info->v_flags & V_DAC8) - && VESA_MODE(adp->va_mode) && ((bits = vesa_bios_set_dac(8)) > 6)) { - error = vesa_bios_load_palette(0, 256, palette, bits); - if (error == 0) - return 0; - if (vesa_bios_set_dac(6) != 6) - return 1; + if (adp == vesa_adp && VESA_MODE(adp->va_mode) && + (adp->va_info.vi_flags & V_INFO_NONVGA) != 0) { + bits = (adp->va_flags & V_ADP_DAC8) != 0 ? 8 : 6; + return (vesa_bios_load_palette(0, 256, palette, bits)); } -#endif /* notyet */ - return (*prevvidsw->load_palette)(adp, palette); + return ((*prevvidsw->load_palette)(adp, palette)); } static int vesa_set_border(video_adapter_t *adp, int color) { - return (*prevvidsw->set_border)(adp, color); + + return ((*prevvidsw->set_border)(adp, color)); } static int vesa_save_state(video_adapter_t *adp, void *p, size_t size) { + if (adp != vesa_adp) - return (*prevvidsw->save_state)(adp, p, size); + return ((*prevvidsw->save_state)(adp, p, size)); - if (vesa_state_buf_size == 0) + if (vesa_state_buf_size == -1) { vesa_state_buf_size = vesa_bios_state_buf_size(); + if (vesa_state_buf_size == 0) + return (1); + } if (size == 0) - return (sizeof(int) + vesa_state_buf_size); - else if (size < (sizeof(int) + vesa_state_buf_size)) - return 1; + return (offsetof(adp_state_t, regs) + vesa_state_buf_size); + else if (size < (offsetof(adp_state_t, regs) + vesa_state_buf_size)) + return (1); ((adp_state_t *)p)->sig = V_STATE_SIG; bzero(((adp_state_t *)p)->regs, vesa_state_buf_size); - return vesa_bios_save_restore(STATE_SAVE, ((adp_state_t *)p)->regs, - vesa_state_buf_size); + return (vesa_bios_save_restore(STATE_SAVE, ((adp_state_t *)p)->regs, + vesa_state_buf_size)); } static int vesa_load_state(video_adapter_t *adp, void *p) { + if ((adp != vesa_adp) || (((adp_state_t *)p)->sig != V_STATE_SIG)) - return (*prevvidsw->load_state)(adp, p); + return ((*prevvidsw->load_state)(adp, p)); + + if (vesa_state_buf_size <= 0) + return (1); + + /* Try BIOS POST to restore a sane state. */ + (void)vesa_bios_post(); + (void)int10_set_mode(adp->va_initial_bios_mode); - return vesa_bios_save_restore(STATE_LOAD, ((adp_state_t *)p)->regs, - vesa_state_buf_size); + return (vesa_bios_save_restore(STATE_LOAD, ((adp_state_t *)p)->regs, + vesa_state_buf_size)); } #if 0 static int vesa_get_origin(video_adapter_t *adp, off_t *offset) { - struct vm86frame vmf; - int err; - - bzero(&vmf, sizeof(vmf)); - vmf.vmf_eax = 0x4f05; - vmf.vmf_ebx = 0x10; /* WINDOW_A, XXX */ - err = vm86_intcall(0x10, &vmf); - if ((err != 0) || (vmf.vmf_ax != 0x4f)) - return 1; - *offset = vmf.vmf_dx*adp->va_window_gran; - return 0; + x86regs_t regs; + + x86bios_init_regs(®s); + regs.R_AX = 0x4f05; + regs.R_BL = 0x10; + + x86bios_intr(®s, 0x10); + + if (regs.R_AX != 0x004f) + return (1); + *offset = regs.DX * adp->va_window_gran; + + return (0); } #endif static int vesa_set_origin(video_adapter_t *adp, off_t offset) { - struct vm86frame vmf; - int err; + x86regs_t regs; /* * This function should return as quickly as possible to @@ -1264,96 +1425,107 @@ vesa_set_origin(video_adapter_t *adp, off_t offset) * detect error. */ if (adp != vesa_adp) - return (*prevvidsw->set_win_org)(adp, offset); + return ((*prevvidsw->set_win_org)(adp, offset)); /* if this is a linear frame buffer, do nothing */ if (adp->va_info.vi_flags & V_INFO_LINEAR) - return 0; + return (0); /* XXX */ if (adp->va_window_gran == 0) - return 1; - - bzero(&vmf, sizeof(vmf)); - vmf.vmf_eax = 0x4f05; - vmf.vmf_ebx = 0; /* WINDOW_A, XXX */ - vmf.vmf_edx = offset/adp->va_window_gran; - err = vm86_intcall(0x10, &vmf); - if ((err != 0) || (vmf.vmf_ax != 0x4f)) - return 1; - bzero(&vmf, sizeof(vmf)); - vmf.vmf_eax = 0x4f05; - vmf.vmf_ebx = 1; /* WINDOW_B, XXX */ - vmf.vmf_edx = offset/adp->va_window_gran; - err = vm86_intcall(0x10, &vmf); + return (1); + + x86bios_init_regs(®s); + regs.R_AX = 0x4f05; + regs.R_DX = offset / adp->va_window_gran; + + x86bios_intr(®s, 0x10); + + if (regs.R_AX != 0x004f) + return (1); + + x86bios_init_regs(®s); + regs.R_AX = 0x4f05; + regs.R_BL = 1; + regs.R_DX = offset / adp->va_window_gran; + x86bios_intr(®s, 0x10); + adp->va_window_orig = (offset/adp->va_window_gran)*adp->va_window_gran; - return 0; /* XXX */ + return (0); /* XXX */ } static int vesa_read_hw_cursor(video_adapter_t *adp, int *col, int *row) { - return (*prevvidsw->read_hw_cursor)(adp, col, row); + + return ((*prevvidsw->read_hw_cursor)(adp, col, row)); } static int vesa_set_hw_cursor(video_adapter_t *adp, int col, int row) { - return (*prevvidsw->set_hw_cursor)(adp, col, row); + + return ((*prevvidsw->set_hw_cursor)(adp, col, row)); } static int vesa_set_hw_cursor_shape(video_adapter_t *adp, int base, int height, int celsize, int blink) { - return (*prevvidsw->set_hw_cursor_shape)(adp, base, height, celsize, - blink); + + return ((*prevvidsw->set_hw_cursor_shape)(adp, base, height, celsize, + blink)); } static int vesa_blank_display(video_adapter_t *adp, int mode) { + /* XXX: use VESA DPMS */ - return (*prevvidsw->blank_display)(adp, mode); + return ((*prevvidsw->blank_display)(adp, mode)); } static int vesa_mmap(video_adapter_t *adp, vm_offset_t offset, vm_paddr_t *paddr, int prot) { + #if VESA_DEBUG > 0 - printf("vesa_mmap(): window:0x%x, buffer:0x%x, offset:0x%x\n", + printf("vesa_mmap(): window:0x%tx, buffer:0x%tx, offset:0x%tx\n", adp->va_info.vi_window, adp->va_info.vi_buffer, offset); #endif - if ((adp == vesa_adp) && (adp->va_info.vi_flags & V_INFO_LINEAR)) { + if ((adp == vesa_adp) && + (adp->va_info.vi_flags & V_INFO_LINEAR) != 0) { /* va_window_size == va_buffer_size/vi_planes */ /* XXX: is this correct? */ if (offset > adp->va_window_size - PAGE_SIZE) - return -1; + return (-1); *paddr = adp->va_info.vi_buffer + offset; - return 0; - } else { - return (*prevvidsw->mmap)(adp, offset, paddr, prot); + return (0); } + return ((*prevvidsw->mmap)(adp, offset, paddr, prot)); } static int vesa_clear(video_adapter_t *adp) { - return (*prevvidsw->clear)(adp); + + return ((*prevvidsw->clear)(adp)); } static int vesa_fill_rect(video_adapter_t *adp, int val, int x, int y, int cx, int cy) { - return (*prevvidsw->fill_rect)(adp, val, x, y, cx, cy); + + return ((*prevvidsw->fill_rect)(adp, val, x, y, cx, cy)); } static int vesa_bitblt(video_adapter_t *adp,...) { + /* FIXME */ - return 1; + return (1); } static int @@ -1366,18 +1538,17 @@ get_palette(video_adapter_t *adp, int base, int count, int bits; int error; - if ((base < 0) || (base >= 256) || (count < 0) || (count > 256)) - return 1; + if (base < 0 || base >= 256 || count < 0 || count > 256) + return (1); if ((base + count) > 256) - return 1; - if (!(vesa_adp_info->v_flags & V_DAC8) || !VESA_MODE(adp->va_mode)) - return 1; - - bits = vesa_bios_get_dac(); - if (bits <= 6) - return 1; + return (1); + if (!VESA_MODE(adp->va_mode)) + return (1); + if ((adp->va_info.vi_flags & V_INFO_NONVGA) == 0) + return (1); - r = malloc(count*3, M_DEVBUF, M_WAITOK); + bits = (adp->va_flags & V_ADP_DAC8) != 0 ? 8 : 6; + r = malloc(count * 3, M_DEVBUF, M_WAITOK); g = r + count; b = g + count; error = vesa_bios_save_palette2(base, count, r, g, b, bits); @@ -1392,29 +1563,30 @@ get_palette(video_adapter_t *adp, int base, int count, } free(r, M_DEVBUF); - /* if error && bits != 6 at this point, we are in trouble... XXX */ - return error; + return (error); } static int set_palette(video_adapter_t *adp, int base, int count, u_char *red, u_char *green, u_char *blue, u_char *trans) { - return 1; -#ifdef notyet u_char *r; u_char *g; u_char *b; int bits; int error; - if ((base < 0) || (base >= 256) || (base + count > 256)) - return 1; - if (!(vesa_adp_info->v_flags & V_DAC8) || !VESA_MODE(adp->va_mode) - || ((bits = vesa_bios_set_dac(8)) <= 6)) - return 1; + if (base < 0 || base >= 256 || count < 0 || count > 256) + return (1); + if ((base + count) > 256) + return (1); + if (!VESA_MODE(adp->va_mode)) + return (1); + if ((adp->va_info.vi_flags & V_INFO_NONVGA) == 0) + return (1); - r = malloc(count*3, M_DEVBUF, M_WAITOK); + bits = (adp->va_flags & V_ADP_DAC8) != 0 ? 8 : 6; + r = malloc(count * 3, M_DEVBUF, M_WAITOK); g = r + count; b = g + count; copyin(red, r, count); @@ -1423,13 +1595,8 @@ set_palette(video_adapter_t *adp, int base, int count, error = vesa_bios_load_palette2(base, count, r, g, b, bits); free(r, M_DEVBUF); - if (error == 0) - return 0; - /* if the following call fails, we are in trouble... XXX */ - vesa_bios_set_dac(6); - return 1; -#endif /* notyet */ + return (error); } static int @@ -1438,7 +1605,7 @@ vesa_ioctl(video_adapter_t *adp, u_long cmd, caddr_t arg) int bytes; if (adp != vesa_adp) - return (*prevvidsw->ioctl)(adp, cmd, arg); + return ((*prevvidsw->ioctl)(adp, cmd, arg)); switch (cmd) { case FBIO_SETWINORG: /* set frame buffer window origin */ @@ -1448,24 +1615,24 @@ vesa_ioctl(video_adapter_t *adp, u_long cmd, caddr_t arg) case FBIO_SETDISPSTART: /* set display start address */ if (!VESA_MODE(adp->va_mode)) - return (*prevvidsw->ioctl)(adp, cmd, arg); + return ((*prevvidsw->ioctl)(adp, cmd, arg)); if (vesa_bios_set_start(((video_display_start_t *)arg)->x, ((video_display_start_t *)arg)->y)) - return ENODEV; + return (ENODEV); adp->va_disp_start.x = ((video_display_start_t *)arg)->x; adp->va_disp_start.y = ((video_display_start_t *)arg)->y; - return 0; + return (0); case FBIO_SETLINEWIDTH: /* set line length in pixel */ if (!VESA_MODE(adp->va_mode)) - return (*prevvidsw->ioctl)(adp, cmd, arg); + return ((*prevvidsw->ioctl)(adp, cmd, arg)); if (vesa_bios_set_line_length(*(u_int *)arg, &bytes, NULL)) - return ENODEV; + return (ENODEV); adp->va_line_width = bytes; #if VESA_DEBUG > 1 printf("new line width:%d\n", adp->va_line_width); #endif - return 0; + return (0); case FBIO_GETPALETTE: /* get color palette */ if (get_palette(adp, ((video_color_palette_t *)arg)->index, @@ -1474,8 +1641,8 @@ vesa_ioctl(video_adapter_t *adp, u_long cmd, caddr_t arg) ((video_color_palette_t *)arg)->green, ((video_color_palette_t *)arg)->blue, ((video_color_palette_t *)arg)->transparent)) - return (*prevvidsw->ioctl)(adp, cmd, arg); - return 0; + return ((*prevvidsw->ioctl)(adp, cmd, arg)); + return (0); case FBIO_SETPALETTE: /* set color palette */ @@ -1485,8 +1652,8 @@ vesa_ioctl(video_adapter_t *adp, u_long cmd, caddr_t arg) ((video_color_palette_t *)arg)->green, ((video_color_palette_t *)arg)->blue, ((video_color_palette_t *)arg)->transparent)) - return (*prevvidsw->ioctl)(adp, cmd, arg); - return 0; + return ((*prevvidsw->ioctl)(adp, cmd, arg)); + return (0); case FBIOGETCMAP: /* get color palette */ if (get_palette(adp, ((struct fbcmap *)arg)->index, @@ -1494,8 +1661,8 @@ vesa_ioctl(video_adapter_t *adp, u_long cmd, caddr_t arg) ((struct fbcmap *)arg)->red, ((struct fbcmap *)arg)->green, ((struct fbcmap *)arg)->blue, NULL)) - return (*prevvidsw->ioctl)(adp, cmd, arg); - return 0; + return ((*prevvidsw->ioctl)(adp, cmd, arg)); + return (0); case FBIOPUTCMAP: /* set color palette */ if (set_palette(adp, ((struct fbcmap *)arg)->index, @@ -1503,11 +1670,11 @@ vesa_ioctl(video_adapter_t *adp, u_long cmd, caddr_t arg) ((struct fbcmap *)arg)->red, ((struct fbcmap *)arg)->green, ((struct fbcmap *)arg)->blue, NULL)) - return (*prevvidsw->ioctl)(adp, cmd, arg); - return 0; + return ((*prevvidsw->ioctl)(adp, cmd, arg)); + return (0); default: - return (*prevvidsw->ioctl)(adp, cmd, arg); + return ((*prevvidsw->ioctl)(adp, cmd, arg)); } } @@ -1519,15 +1686,15 @@ vesa_diag(video_adapter_t *adp, int level) /* call the previous handler first */ error = (*prevvidsw->diag)(adp, level); if (error) - return error; + return (error); if (adp != vesa_adp) - return 1; + return (1); if (level <= 0) - return 0; + return (0); - return 0; + return (0); } static int @@ -1537,15 +1704,16 @@ vesa_bios_info(int level) struct vesa_mode vmode; int i; #endif + uint16_t vers; + + vers = vesa_adp_info->v_version; if (bootverbose) { /* general adapter information */ printf( "VESA: v%d.%d, %dk memory, flags:0x%x, mode table:%p (%x)\n", - ((vesa_adp_info->v_version & 0xf000) >> 12) * 10 + - ((vesa_adp_info->v_version & 0x0f00) >> 8), - ((vesa_adp_info->v_version & 0x00f0) >> 4) * 10 + - (vesa_adp_info->v_version & 0x000f), + (vers >> 12) * 10 + ((vers & 0x0f00) >> 8), + ((vers & 0x00f0) >> 4) * 10 + (vers & 0x000f), vesa_adp_info->v_memsize * 64, vesa_adp_info->v_flags, vesa_vmodetab, vesa_adp_info->v_modetable); @@ -1555,9 +1723,9 @@ vesa_bios_info(int level) } if (level <= 0) - return 0; + return (0); - if (vesa_adp_info->v_version >= 0x0200 && bootverbose) { + if (vers >= 0x0200 && bootverbose) { /* vender name, product name, product revision */ printf("VESA: %s %s %s\n", (vesa_venderstr != NULL) ? vesa_venderstr : "unknown", @@ -1604,7 +1772,7 @@ vesa_bios_info(int level) } #endif /* VESA_DEBUG > 1 */ - return 0; + return (0); } /* module loading */ @@ -1616,7 +1784,7 @@ vesa_load(void) int s; if (vesa_init_done) - return 0; + return (0); /* locate a VGA adapter */ s = spltty(); @@ -1627,7 +1795,7 @@ vesa_load(void) if (error == 0) vesa_bios_info(bootverbose); - return error; + return (error); } static int @@ -1635,12 +1803,11 @@ vesa_unload(void) { u_char palette[256*3]; int error; - int bits; int s; /* if the adapter is currently in a VESA mode, don't unload */ if ((vesa_adp != NULL) && VESA_MODE(vesa_adp->va_mode)) - return EBUSY; + return (EBUSY); /* * FIXME: if there is at least one vty which is in a VESA mode, * we shouldn't be unloading! XXX @@ -1649,15 +1816,11 @@ vesa_unload(void) s = spltty(); if ((error = vesa_unload_ioctl()) == 0) { if (vesa_adp != NULL) { - if (vesa_adp_info->v_flags & V_DAC8) { - bits = vesa_bios_get_dac(); - if (bits > 6) { - vesa_bios_save_palette(0, 256, - palette, bits); - vesa_bios_set_dac(6); - vesa_bios_load_palette(0, 256, - palette, 6); - } + if ((vesa_adp->va_flags & V_ADP_DAC8) != 0) { + vesa_bios_save_palette(0, 256, palette, 8); + vesa_bios_set_dac(6); + vesa_adp->va_flags &= ~V_ADP_DAC8; + vesa_bios_load_palette(0, 256, palette, 6); } vesa_adp->va_flags &= ~V_ADP_VESA; vidsw[vesa_adp->va_index] = prevvidsw; @@ -1665,24 +1828,30 @@ vesa_unload(void) } splx(s); - if (vesa_vm86_buf != NULL) - free(vesa_vm86_buf, M_DEVBUF); - - return error; + if (vesa_oemstr != NULL) + free(vesa_oemstr, M_DEVBUF); + if (vesa_venderstr != NULL) + free(vesa_venderstr, M_DEVBUF); + if (vesa_prodstr != NULL) + free(vesa_prodstr, M_DEVBUF); + if (vesa_revstr != NULL) + free(vesa_revstr, M_DEVBUF); + if (vesa_vmode != &vesa_vmode_empty) + free(vesa_vmode, M_DEVBUF); + return (error); } static int vesa_mod_event(module_t mod, int type, void *data) { + switch (type) { case MOD_LOAD: - return vesa_load(); + return (vesa_load()); case MOD_UNLOAD: - return vesa_unload(); - default: - return EOPNOTSUPP; + return (vesa_unload()); } - return 0; + return (EOPNOTSUPP); } static moduledata_t vesa_mod = { @@ -1692,5 +1861,6 @@ static moduledata_t vesa_mod = { }; DECLARE_MODULE(vesa, vesa_mod, SI_SUB_DRIVERS, SI_ORDER_MIDDLE); +MODULE_DEPEND(vesa, x86bios, 1, 1, 1); #endif /* VGA_NO_MODE_CHANGE */ diff --git a/sys/i386/include/pc/vesa.h b/sys/dev/fb/vesa.h index 06f1c11..25b9bd5 100644 --- a/sys/i386/include/pc/vesa.h +++ b/sys/dev/fb/vesa.h @@ -26,8 +26,8 @@ * $FreeBSD$ */ -#ifndef _MACHINE_PC_VESA_H -#define _MACHINE_PC_VESA_H +#ifndef _DEV_FB_VESA_H_ +#define _DEV_FB_VESA_H_ struct vesa_info { @@ -46,6 +46,8 @@ struct vesa_info u_int32_t v_venderstr; /* vender */ u_int32_t v_prodstr; /* product name */ u_int32_t v_revstr; /* product rev */ + u_int8_t v_strach[222]; + u_int8_t v_oemdata[256]; } __packed; struct vesa_mode @@ -106,7 +108,21 @@ struct vesa_mode u_int32_t v_lfb; u_int32_t v_offscreen; u_int16_t v_offscreensize; -}; + /* 3.0 implementations */ + u_int16_t v_linbpscanline; + u_int8_t v_bankipages; + u_int8_t v_linipages; + u_int8_t v_linredmasksize; + u_int8_t v_linredfieldpos; + u_int8_t v_lingreenmasksize; + u_int8_t v_lingreenfieldpos; + u_int8_t v_linbluemasksize; + u_int8_t v_linbluefieldpos; + u_int8_t v_linresmasksize; + u_int8_t v_linresfieldpos; + u_int32_t v_maxpixelclock; + u_int8_t v_reserved1[190]; +} __packed; #ifdef _KERNEL @@ -117,4 +133,4 @@ int vesa_unload_ioctl(void); #endif -#endif /* !_MACHINE_PC_VESA_H */ +#endif /* !_DEV_FB_VESA_H_ */ diff --git a/sys/dev/fb/vga.c b/sys/dev/fb/vga.c index 425aec2..a2e99f2 100644 --- a/sys/dev/fb/vga.c +++ b/sys/dev/fb/vga.c @@ -156,7 +156,7 @@ vga_mmap(struct cdev *dev, vga_softc_t *sc, vm_offset_t offset, vm_offset_t *pad #include <isa/rtc.h> #ifdef __i386__ -#include <machine/pc/vesa.h> +#include <dev/fb/vesa.h> #endif #define probe_done(adp) ((adp)->va_flags & V_ADP_PROBED) diff --git a/sys/dev/fb/vgareg.h b/sys/dev/fb/vgareg.h index 0a73fbd..fa9d44e 100644 --- a/sys/dev/fb/vgareg.h +++ b/sys/dev/fb/vgareg.h @@ -70,6 +70,7 @@ struct video_adapter; typedef struct vga_softc { struct video_adapter *adp; void *state_buf; + void *pal_buf; #ifdef FB_INSTALL_CDEV genfb_softc_t gensc; #endif diff --git a/sys/dev/pci/vga_pci.c b/sys/dev/pci/vga_pci.c index 3e5b1a6..19fe9df 100644 --- a/sys/dev/pci/vga_pci.c +++ b/sys/dev/pci/vga_pci.c @@ -43,6 +43,7 @@ __FBSDID("$FreeBSD$"); #include <sys/kernel.h> #include <sys/module.h> #include <sys/rman.h> +#include <sys/sysctl.h> #include <sys/systm.h> #include <dev/pci/pcireg.h> @@ -58,9 +59,19 @@ struct vga_pci_softc { struct vga_resource vga_res[PCIR_MAX_BAR_0 + 1]; }; +SYSCTL_DECL(_hw_pci); + +int vga_pci_default_unit = -1; +TUNABLE_INT("hw.pci.default_vgapci_unit", &vga_pci_default_unit); +SYSCTL_INT(_hw_pci, OID_AUTO, default_vgapci_unit, CTLFLAG_RDTUN, + &vga_pci_default_unit, -1, "Default VGA-compatible display"); + static int vga_pci_probe(device_t dev) { + device_t bdev; + int unit; + uint16_t bctl; switch (pci_get_class(dev)) { case PCIC_DISPLAY: @@ -72,6 +83,16 @@ vga_pci_probe(device_t dev) default: return (ENXIO); } + + /* Probe default display. */ + unit = device_get_unit(dev); + bdev = device_get_parent(device_get_parent(dev)); + bctl = pci_read_config(bdev, PCIR_BRIDGECTL_1, 2); + if (vga_pci_default_unit < 0 && (bctl & PCIB_BCR_VGA_ENABLE) != 0) + vga_pci_default_unit = unit; + if (vga_pci_default_unit == unit) + device_set_flags(dev, 1); + device_set_desc(dev, "VGA-compatible display"); return (BUS_PROBE_GENERIC); } diff --git a/sys/dev/syscons/scvesactl.c b/sys/dev/syscons/scvesactl.c index 9a2c253..b896484 100644 --- a/sys/dev/syscons/scvesactl.c +++ b/sys/dev/syscons/scvesactl.c @@ -43,7 +43,7 @@ __FBSDID("$FreeBSD$"); #include <sys/fbio.h> #include <sys/consio.h> -#include <machine/pc/vesa.h> +#include <dev/fb/vesa.h> #include <dev/fb/fbreg.h> #include <dev/syscons/syscons.h> diff --git a/sys/dev/syscons/scvgarndr.c b/sys/dev/syscons/scvgarndr.c index 1ab41d2..fd823ce 100644 --- a/sys/dev/syscons/scvgarndr.c +++ b/sys/dev/syscons/scvgarndr.c @@ -193,6 +193,8 @@ static u_short mouse_or_mask[16] = { case 15: \ writew(pos, vga_palette15[color]); \ break; \ + case 8: \ + writeb(pos, (uint8_t)color); \ } static uint32_t vga_palette32[16] = { @@ -215,6 +217,7 @@ static uint16_t vga_palette15[16] = { #ifndef SC_NO_CUTPASTE static uint32_t mouse_buf32[256]; static uint16_t mouse_buf16[256]; +static uint8_t mouse_buf8[256]; #endif #endif @@ -498,7 +501,9 @@ vga_rndrinit(scr_stat *scp) scp->rndr->draw_cursor = vga_pxlcursor_planar; scp->rndr->blink_cursor = vga_pxlblink_planar; scp->rndr->draw_mouse = vga_pxlmouse_planar; - } else if (scp->sc->adp->va_info.vi_mem_model == V_INFO_MM_DIRECT) { + } else + if (scp->sc->adp->va_info.vi_mem_model == V_INFO_MM_DIRECT || + scp->sc->adp->va_info.vi_mem_model == V_INFO_MM_PACKED) { scp->rndr->clear = vga_pxlclear_direct; scp->rndr->draw_border = vga_pxlborder_direct; scp->rndr->draw = vga_vgadraw_direct; @@ -1148,6 +1153,7 @@ vga_pxlmouse_direct(scr_stat *scp, int x, int y, int on) int i, j; uint32_t *u32; uint16_t *u16; + uint8_t *u8; int bpp; if (!on) @@ -1179,6 +1185,10 @@ vga_pxlmouse_direct(scr_stat *scp, int x, int y, int on) u16 = (uint16_t*)(p + j * pixel_size); writew(u16, mouse_buf16[i * 16 + j]); break; + case 8: + u8 = (uint8_t*)(p + j * pixel_size); + writeb(u8, mouse_buf8[i * 16 + j]); + break; } } @@ -1214,6 +1224,14 @@ vga_pxlmouse_direct(scr_stat *scp, int x, int y, int on) else if (mouse_and_mask[i] & (1 << (15 - j))) writew(u16, 0); break; + case 8: + u8 = (uint8_t*)(p + j * pixel_size); + mouse_buf8[i * 16 + j] = *u8; + if (mouse_or_mask[i] & (1 << (15 - j))) + writeb(u8, 15); + else if (mouse_and_mask[i] & (1 << (15 - j))) + writeb(u8, 0); + break; } } diff --git a/sys/dev/syscons/scvidctl.c b/sys/dev/syscons/scvidctl.c index d69e0a8..0f55499 100644 --- a/sys/dev/syscons/scvidctl.c +++ b/sys/dev/syscons/scvidctl.c @@ -369,30 +369,7 @@ sc_set_pixel_mode(scr_stat *scp, struct tty *tp, int xsize, int ysize, if ((info.vi_width < xsize*8) || (info.vi_height < ysize*fontsize)) return EINVAL; - /* - * We currently support the following graphic modes: - * - * - 4 bpp planar modes whose memory size does not exceed 64K - * - 15, 16, 24 and 32 bpp linear modes - */ - - if (info.vi_mem_model == V_INFO_MM_PLANAR) { - if (info.vi_planes != 4) - return ENODEV; - - /* - * A memory size >64K requires bank switching to access the entire - * screen. XXX - */ - - if (info.vi_width * info.vi_height / 8 > info.vi_window_size) - return ENODEV; - } else if (info.vi_mem_model == V_INFO_MM_DIRECT) { - if (!(info.vi_flags & V_INFO_LINEAR) && - (info.vi_depth != 15) && (info.vi_depth != 16) && - (info.vi_depth != 24) && (info.vi_depth != 32)) - return ENODEV; - } else + if (!sc_support_pixel_mode(&info)) return ENODEV; /* stop screen saver, etc */ @@ -468,6 +445,48 @@ sc_set_pixel_mode(scr_stat *scp, struct tty *tp, int xsize, int ysize, #endif /* SC_PIXEL_MODE */ } +int +sc_support_pixel_mode(void *arg) +{ +#ifdef SC_PIXEL_MODE + video_info_t *info = arg; + + if ((info->vi_flags & V_INFO_GRAPHICS) == 0) + return (0); + + /* + * We currently support the following graphic modes: + * + * - 4 bpp planar modes whose memory size does not exceed 64K + * - 15, 16, 24 and 32 bpp linear modes + */ + switch (info->vi_mem_model) { + case V_INFO_MM_PLANAR: + if (info->vi_planes != 4) + break; + /* + * A memory size >64K requires bank switching to access + * the entire screen. XXX + */ + if (info->vi_width * info->vi_height / 8 > info->vi_window_size) + break; + return (1); + case V_INFO_MM_DIRECT: + if ((info->vi_flags & V_INFO_LINEAR) == 0 && + info->vi_depth != 15 && info->vi_depth != 16 && + info->vi_depth != 24 && info->vi_depth != 32) + break; + return (1); + case V_INFO_MM_PACKED: + if ((info->vi_flags & V_INFO_LINEAR) == 0 && + info->vi_depth != 8) + break; + return (1); + } +#endif + return (0); +} + #define fb_ioctl(a, c, d) \ (((a) == NULL) ? ENODEV : \ vidd_ioctl((a), (c), (caddr_t)(d))) @@ -721,6 +740,11 @@ sc_vid_ioctl(struct tty *tp, u_long cmd, caddr_t data, struct thread *td) #endif #ifndef SC_NO_PALETTE_LOADING +#ifdef SC_PIXEL_MODE + if ((adp->va_flags & V_ADP_DAC8) != 0) + vidd_load_palette(adp, scp->sc->palette2); + else +#endif vidd_load_palette(adp, scp->sc->palette); #endif @@ -778,7 +802,10 @@ sc_vid_ioctl(struct tty *tp, u_long cmd, caddr_t data, struct thread *td) if (scp == scp->sc->cur_scp) { set_mode(scp); #ifndef SC_NO_PALETTE_LOADING - vidd_load_palette(adp, scp->sc->palette); + if ((adp->va_flags & V_ADP_DAC8) != 0) + vidd_load_palette(adp, scp->sc->palette2); + else + vidd_load_palette(adp, scp->sc->palette); #endif } sc_clear_screen(scp); diff --git a/sys/dev/syscons/syscons.c b/sys/dev/syscons/syscons.c index 653ff08..8dffe5c 100644 --- a/sys/dev/syscons/syscons.c +++ b/sys/dev/syscons/syscons.c @@ -39,6 +39,7 @@ __FBSDID("$FreeBSD$"); #include <sys/param.h> #include <sys/systm.h> +#include <sys/bus.h> #include <sys/conf.h> #include <sys/cons.h> #include <sys/consio.h> @@ -342,16 +343,105 @@ sc_alloc_tty(int index, int devnum) return (tp); } +#ifdef SC_PIXEL_MODE +static void +sc_set_vesa_mode(scr_stat *scp, sc_softc_t *sc, int unit) +{ + video_info_t info; + int depth; + int i; + int vmode; + + vmode = 0; + (void)resource_int_value("sc", unit, "vesa_mode", &vmode); + if (vmode < M_VESA_BASE || vmode > M_VESA_MODE_MAX || + vidd_get_info(sc->adp, vmode, &info) != 0 || + !sc_support_pixel_mode(&info)) + vmode = 0; + + /* + * If the mode is unset or unsupported, search for an available + * 800x600 graphics mode with the highest color depth. + */ + if (vmode == 0) { + for (depth = 0, i = M_VESA_BASE; i <= M_VESA_MODE_MAX; i++) + if (vidd_get_info(sc->adp, i, &info) == 0 && + info.vi_width == 800 && info.vi_height == 600 && + sc_support_pixel_mode(&info) && + info.vi_depth > depth) { + vmode = i; + depth = info.vi_depth; + } + if (vmode == 0) + return; + vidd_get_info(sc->adp, vmode, &info); + } + +#ifndef SC_NO_FONT_LOADING + if ((sc->fonts_loaded & FONT_16) == 0) + return; +#endif +#ifdef DEV_SPLASH + if ((sc->flags & SC_SPLASH_SCRN) != 0) + splash_term(sc->adp); +#endif +#ifndef SC_NO_HISTORY + if (scp->history != NULL) { + sc_vtb_append(&scp->vtb, 0, scp->history, + scp->ypos * scp->xsize + scp->xpos); + scp->history_pos = sc_vtb_tail(scp->history); + } +#endif + vidd_set_mode(sc->adp, vmode); + scp->status |= (UNKNOWN_MODE | PIXEL_MODE | MOUSE_HIDDEN); + scp->status &= ~(GRAPHICS_MODE | MOUSE_VISIBLE); + scp->xpixel = info.vi_width; + scp->ypixel = info.vi_height; + scp->xsize = scp->xpixel / 8; + scp->ysize = scp->ypixel / 16; + scp->xpos = 0; + scp->ypos = scp->ysize - 1; + scp->xoff = scp->yoff = 0; +#ifndef SC_NO_FONT_LOADING + scp->font = sc->font_16; +#else + scp->font = NULL; +#endif + scp->font_size = 16; + scp->font_width = 8; + scp->start = scp->xsize * scp->ysize - 1; + scp->end = 0; + scp->cursor_pos = scp->cursor_oldpos = scp->xsize * scp->xsize; + scp->mode = sc->initial_mode = vmode; +#ifndef __sparc64__ + sc_vtb_init(&scp->scr, VTB_FRAMEBUFFER, scp->xsize, scp->ysize, + (void *)sc->adp->va_window, FALSE); +#endif + sc_alloc_scr_buffer(scp, FALSE, FALSE); + sc_init_emulator(scp, NULL); +#ifndef SC_NO_CUTPASTE + sc_alloc_cut_buffer(scp, FALSE); +#endif +#ifndef SC_NO_HISTORY + sc_alloc_history_buffer(scp, 0, 0, FALSE); +#endif + sc_set_border(scp, scp->border); + sc_set_cursor_image(scp); + scp->status &= ~UNKNOWN_MODE; +#ifdef DEV_SPLASH + if ((sc->flags & SC_SPLASH_SCRN) != 0) + splash_init(sc->adp, scsplash_callback, sc); +#endif +} +#endif + int sc_attach_unit(int unit, int flags) { sc_softc_t *sc; scr_stat *scp; -#ifdef SC_PIXEL_MODE - video_info_t info; -#endif - int vc; struct cdev *dev; + int vc; flags &= ~SC_KERNEL_CONSOLE; @@ -373,21 +463,8 @@ sc_attach_unit(int unit, int flags) sc_console = scp; #ifdef SC_PIXEL_MODE - if ((sc->config & SC_VESA800X600) - && (vidd_get_info(sc->adp, M_VESA_800x600, &info) == 0)) { -#ifdef DEV_SPLASH - if (sc->flags & SC_SPLASH_SCRN) - splash_term(sc->adp); -#endif - sc_set_graphics_mode(scp, NULL, M_VESA_800x600); - sc_set_pixel_mode(scp, NULL, COL, ROW, 16, 8); - sc->initial_mode = M_VESA_800x600; -#ifdef DEV_SPLASH - /* put up the splash again! */ - if (sc->flags & SC_SPLASH_SCRN) - splash_init(sc->adp, scsplash_callback, sc); -#endif - } + if ((sc->config & SC_VESAMODE) != 0) + sc_set_vesa_mode(scp, sc, unit); #endif /* SC_PIXEL_MODE */ /* initialize cursor */ @@ -517,7 +594,7 @@ sctty_open(struct tty *tp) if (scp == NULL) { scp = SC_STAT(tp) = alloc_scp(sc, SC_VTY(tp)); if (ISGRAPHSC(scp)) - sc_set_pixel_mode(scp, NULL, COL, ROW, 16, 8); + sc_set_pixel_mode(scp, NULL, 0, 0, 16, 8); } if (!tp->t_winsize.ws_col && !tp->t_winsize.ws_row) { tp->t_winsize.ws_col = scp->xsize; @@ -2049,6 +2126,11 @@ restore_scrn_saver_mode(scr_stat *scp, int changemode) } if (set_mode(scp) == 0) { #ifndef SC_NO_PALETTE_LOADING +#ifdef SC_PIXEL_MODE + if ((scp->sc->adp->va_flags & V_ADP_DAC8) != 0) + vidd_load_palette(scp->sc->adp, scp->sc->palette2); + else +#endif vidd_load_palette(scp->sc->adp, scp->sc->palette); #endif --scrn_blanked; @@ -2452,8 +2534,14 @@ exchange_scr(sc_softc_t *sc) if (!ISGRAPHSC(scp)) sc_set_cursor_image(scp); #ifndef SC_NO_PALETTE_LOADING - if (ISGRAPHSC(sc->old_scp)) + if (ISGRAPHSC(sc->old_scp)) { +#ifdef SC_PIXEL_MODE + if ((sc->adp->va_flags & V_ADP_DAC8) != 0) + vidd_load_palette(sc->adp, sc->palette2); + else +#endif vidd_load_palette(sc->adp, sc->palette); + } #endif sc_set_border(scp, scp->border); @@ -2802,6 +2890,10 @@ scinit(int unit, int flags) #ifndef SC_NO_PALETTE_LOADING vidd_save_palette(sc->adp, sc->palette); +#ifdef SC_PIXEL_MODE + for (i = 0; i < sizeof(sc->palette2); i++) + sc->palette2[i] = i / 3; +#endif #endif #ifdef DEV_SPLASH @@ -2995,6 +3087,8 @@ init_scp(sc_softc_t *sc, int vty, scr_stat *scp) scp->ysize = info.vi_height; scp->xpixel = scp->xsize*info.vi_cwidth; scp->ypixel = scp->ysize*info.vi_cheight; + } + scp->font_size = info.vi_cheight; scp->font_width = info.vi_cwidth; if (info.vi_cheight < 14) { @@ -3016,7 +3110,7 @@ init_scp(sc_softc_t *sc, int vty, scr_stat *scp) scp->font = NULL; #endif } - } + sc_vtb_init(&scp->vtb, VTB_MEMORY, 0, 0, NULL, FALSE); #ifndef __sparc64__ sc_vtb_init(&scp->scr, VTB_FRAMEBUFFER, 0, 0, NULL, FALSE); diff --git a/sys/dev/syscons/syscons.h b/sys/dev/syscons/syscons.h index c0ed6c1..aab6b5c 100644 --- a/sys/dev/syscons/syscons.h +++ b/sys/dev/syscons/syscons.h @@ -191,7 +191,7 @@ struct tty; typedef struct sc_softc { int unit; /* unit # */ int config; /* configuration flags */ -#define SC_VESA800X600 (1 << 7) +#define SC_VESAMODE (1 << 7) #define SC_AUTODETECT_KBD (1 << 8) #define SC_KERNEL_CONSOLE (1 << 9) @@ -245,7 +245,10 @@ typedef struct sc_softc { #endif #ifndef SC_NO_PALETTE_LOADING - u_char palette[256*3]; + u_char palette[256 * 3]; +#ifdef SC_PIXEL_MODE + u_char palette2[256 * 3]; +#endif #endif #ifndef SC_NO_FONT_LOADING @@ -616,6 +619,7 @@ int sc_set_text_mode(scr_stat *scp, struct tty *tp, int mode, int sc_set_graphics_mode(scr_stat *scp, struct tty *tp, int mode); int sc_set_pixel_mode(scr_stat *scp, struct tty *tp, int xsize, int ysize, int fontsize, int font_width); +int sc_support_pixel_mode(void *arg); int sc_vid_ioctl(struct tty *tp, u_long cmd, caddr_t data, struct thread *td); diff --git a/sys/i386/conf/NOTES b/sys/i386/conf/NOTES index c4d24d7..22ae19e 100644 --- a/sys/i386/conf/NOTES +++ b/sys/i386/conf/NOTES @@ -361,6 +361,9 @@ options VESA_DEBUG device dpms # DPMS suspend & resume via VESA BIOS +# x86 real mode BIOS emulator, required by atkbdc/dpms/vesa +options X86BIOS + # # The Numeric Processing eXtension driver. This is non-optional. device npx @@ -444,6 +447,9 @@ options VGA_WIDTH90 # support 90 column modes # Debugging. options VGA_DEBUG +# Linear framebuffer driver for S3 VESA 1.2 cards. Works on top of VESA. +device s3pci + # 3Dfx Voodoo Graphics, Voodoo II /dev/3dfx CDEV support. This will create # the /dev/3dfx0 device to work with glide implementations. This should get # linked to /dev/3dfx and /dev/voodoo. Note that this is not the same as diff --git a/sys/isa/vga_isa.c b/sys/isa/vga_isa.c index 3d7cd3a..f9b2630 100644 --- a/sys/isa/vga_isa.c +++ b/sys/isa/vga_isa.c @@ -59,6 +59,69 @@ __FBSDID("$FreeBSD$"); #include <isa/isareg.h> #include <isa/isavar.h> +static void +vga_suspend(device_t dev) +{ + vga_softc_t *sc; + int nbytes; + + sc = device_get_softc(dev); + + /* Save the video state across the suspend. */ + if (sc->state_buf != NULL) + goto save_palette; + nbytes = vidd_save_state(sc->adp, NULL, 0); + if (nbytes <= 0) + goto save_palette; + sc->state_buf = malloc(nbytes, M_TEMP, M_NOWAIT); + if (sc->state_buf == NULL) + goto save_palette; + if (bootverbose) + device_printf(dev, "saving %d bytes of video state\n", nbytes); + if (vidd_save_state(sc->adp, sc->state_buf, nbytes) != 0) { + device_printf(dev, "failed to save state (nbytes=%d)\n", + nbytes); + free(sc->state_buf, M_TEMP); + sc->state_buf = NULL; + } + +save_palette: + /* Save the color palette across the suspend. */ + if (sc->pal_buf != NULL) + return; + sc->pal_buf = malloc(256 * 3, M_TEMP, M_NOWAIT); + if (sc->pal_buf == NULL) + return; + if (bootverbose) + device_printf(dev, "saving color palette\n"); + if (vidd_save_palette(sc->adp, sc->pal_buf) != 0) { + device_printf(dev, "failed to save palette\n"); + free(sc->pal_buf, M_TEMP); + sc->pal_buf = NULL; + } +} + +static void +vga_resume(device_t dev) +{ + vga_softc_t *sc; + + sc = device_get_softc(dev); + + if (sc->state_buf != NULL) { + if (vidd_load_state(sc->adp, sc->state_buf) != 0) + device_printf(dev, "failed to reload state\n"); + free(sc->state_buf, M_TEMP); + sc->state_buf = NULL; + } + if (sc->pal_buf != NULL) { + if (vidd_load_palette(sc->adp, sc->pal_buf) != 0) + device_printf(dev, "failed to reload palette\n"); + free(sc->pal_buf, M_TEMP); + sc->pal_buf = NULL; + } +} + #define VGA_SOFTC(unit) \ ((vga_softc_t *)devclass_get_softc(isavga_devclass, unit)) @@ -103,9 +166,9 @@ isavga_probe(device_t dev) if (isa_get_vendorid(dev)) return (ENXIO); - device_set_desc(dev, "Generic ISA VGA"); error = vga_probe_unit(device_get_unit(dev), &adp, device_get_flags(dev)); if (error == 0) { + device_set_desc(dev, "Generic ISA VGA"); bus_set_resource(dev, SYS_RES_IOPORT, 0, adp.va_io_base, adp.va_io_size); bus_set_resource(dev, SYS_RES_MEMORY, 0, @@ -117,7 +180,7 @@ isavga_probe(device_t dev) isa_set_msize(dev, adp.va_mem_size); #endif } - return error; + return (error); } static int @@ -140,13 +203,13 @@ isavga_attach(device_t dev) error = vga_attach_unit(unit, sc, device_get_flags(dev)); if (error) - return error; + return (error); #ifdef FB_INSTALL_CDEV /* attach a virtual frame buffer device */ error = fb_attach(VGA_MKMINOR(unit), sc->adp, &isavga_cdevsw); if (error) - return error; + return (error); #endif /* FB_INSTALL_CDEV */ if (0 && bootverbose) @@ -157,57 +220,29 @@ isavga_attach(device_t dev) bus_generic_attach(dev); #endif - return 0; + return (0); } static int isavga_suspend(device_t dev) { - vga_softc_t *sc; - int err, nbytes; + int error; - sc = device_get_softc(dev); - err = bus_generic_suspend(dev); - if (err) - return (err); + error = bus_generic_suspend(dev); + if (error != 0) + return (error); + vga_suspend(dev); - /* Save the video state across the suspend. */ - if (sc->state_buf != NULL) { - free(sc->state_buf, M_TEMP); - sc->state_buf = NULL; - } - nbytes = vidd_save_state(sc->adp, NULL, 0); - if (nbytes <= 0) - return (0); - sc->state_buf = malloc(nbytes, M_TEMP, M_NOWAIT | M_ZERO); - if (sc->state_buf == NULL) - return (0); - if (bootverbose) - device_printf(dev, "saving %d bytes of video state\n", nbytes); - if (vidd_save_state(sc->adp, sc->state_buf, nbytes) != 0) { - device_printf(dev, "failed to save state (nbytes=%d)\n", - nbytes); - free(sc->state_buf, M_TEMP); - sc->state_buf = NULL; - } - return (0); + return (error); } static int isavga_resume(device_t dev) { - vga_softc_t *sc; - sc = device_get_softc(dev); - if (sc->state_buf != NULL) { - if (vidd_load_state(sc->adp, sc->state_buf) != 0) - device_printf(dev, "failed to reload state\n"); - free(sc->state_buf, M_TEMP); - sc->state_buf = NULL; - } + vga_resume(dev); - bus_generic_resume(dev); - return 0; + return (bus_generic_resume(dev)); } #ifdef FB_INSTALL_CDEV @@ -215,37 +250,37 @@ isavga_resume(device_t dev) static int isavga_open(struct cdev *dev, int flag, int mode, struct thread *td) { - return vga_open(dev, VGA_SOFTC(VGA_UNIT(dev)), flag, mode, td); + return (vga_open(dev, VGA_SOFTC(VGA_UNIT(dev)), flag, mode, td)); } static int isavga_close(struct cdev *dev, int flag, int mode, struct thread *td) { - return vga_close(dev, VGA_SOFTC(VGA_UNIT(dev)), flag, mode, td); + return (vga_close(dev, VGA_SOFTC(VGA_UNIT(dev)), flag, mode, td)); } static int isavga_read(struct cdev *dev, struct uio *uio, int flag) { - return vga_read(dev, VGA_SOFTC(VGA_UNIT(dev)), uio, flag); + return (vga_read(dev, VGA_SOFTC(VGA_UNIT(dev)), uio, flag)); } static int isavga_write(struct cdev *dev, struct uio *uio, int flag) { - return vga_write(dev, VGA_SOFTC(VGA_UNIT(dev)), uio, flag); + return (vga_write(dev, VGA_SOFTC(VGA_UNIT(dev)), uio, flag)); } static int isavga_ioctl(struct cdev *dev, u_long cmd, caddr_t arg, int flag, struct thread *td) { - return vga_ioctl(dev, VGA_SOFTC(VGA_UNIT(dev)), cmd, arg, flag, td); + return (vga_ioctl(dev, VGA_SOFTC(VGA_UNIT(dev)), cmd, arg, flag, td)); } static int isavga_mmap(struct cdev *dev, vm_offset_t offset, vm_paddr_t *paddr, int prot) { - return vga_mmap(dev, VGA_SOFTC(VGA_UNIT(dev)), offset, paddr, prot); + return (vga_mmap(dev, VGA_SOFTC(VGA_UNIT(dev)), offset, paddr, prot)); } #endif /* FB_INSTALL_CDEV */ @@ -268,3 +303,79 @@ static driver_t isavga_driver = { }; DRIVER_MODULE(vga, isa, isavga_driver, isavga_devclass, 0, 0); + +static devclass_t vgapm_devclass; + +static void +vgapm_identify(driver_t *driver, device_t parent) +{ + + if (device_get_flags(parent) != 0) + device_add_child(parent, "vgapm", 0); +} + +static int +vgapm_probe(device_t dev) +{ + + device_set_desc(dev, "VGA suspend/resume"); + device_quiet(dev); + + return (BUS_PROBE_DEFAULT); +} + +static int +vgapm_attach(device_t dev) +{ + + bus_generic_probe(dev); + bus_generic_attach(dev); + + return (0); +} + +static int +vgapm_suspend(device_t dev) +{ + device_t vga_dev; + int error; + + error = bus_generic_suspend(dev); + if (error != 0) + return (error); + vga_dev = devclass_get_device(isavga_devclass, 0); + if (vga_dev == NULL) + return (0); + vga_suspend(vga_dev); + + return (0); +} + +static int +vgapm_resume(device_t dev) +{ + device_t vga_dev; + + vga_dev = devclass_get_device(isavga_devclass, 0); + if (vga_dev != NULL) + vga_resume(vga_dev); + + return (bus_generic_resume(dev)); +} + +static device_method_t vgapm_methods[] = { + DEVMETHOD(device_identify, vgapm_identify), + DEVMETHOD(device_probe, vgapm_probe), + DEVMETHOD(device_attach, vgapm_attach), + DEVMETHOD(device_suspend, vgapm_suspend), + DEVMETHOD(device_resume, vgapm_resume), + { 0, 0 } +}; + +static driver_t vgapm_driver = { + "vgapm", + vgapm_methods, + 0 +}; + +DRIVER_MODULE(vgapm, vgapci, vgapm_driver, vgapm_devclass, 0, 0); diff --git a/sys/modules/Makefile b/sys/modules/Makefile index 07e4bfb..9b7d550 100644 --- a/sys/modules/Makefile +++ b/sys/modules/Makefile @@ -300,6 +300,7 @@ SUBDIR= ${_3dfx} \ wlan_xauth \ ${_wpi} \ ${_wpifw} \ + ${_x86bios} \ ${_xe} \ xfs \ xl \ @@ -463,6 +464,7 @@ _padlock= padlock _s3= s3 _twa= twa _vesa= vesa +_x86bios= x86bios .elif ${MACHINE} == "pc98" _canbepm= canbepm _canbus= canbus @@ -490,6 +492,7 @@ _cpufreq= cpufreq .if ${MK_CDDL} != "no" || defined(ALL_MODULES) _cyclic= cyclic .endif +_dpms= dpms _drm= drm .if ${MK_CDDL} != "no" || defined(ALL_MODULES) _dtrace= dtrace @@ -538,14 +541,18 @@ _padlock= padlock .endif _pccard= pccard _rdma= rdma +_s3= s3 _safe= safe _scsi_low= scsi_low _smbfs= smbfs _sound= sound _speaker= speaker +_splash= splash _sppp= sppp _tmpfs= tmpfs _twa= twa +_vesa= vesa +_x86bios= x86bios _wi= wi _wpi= wpi _wpifw= wpifw diff --git a/sys/modules/dpms/Makefile b/sys/modules/dpms/Makefile index a58072e..4eabf14 100644 --- a/sys/modules/dpms/Makefile +++ b/sys/modules/dpms/Makefile @@ -1,9 +1,9 @@ # $FreeBSD$ -.PATH: ${.CURDIR}/../../i386/isa - KMOD= dpms -SRCS= dpms.c -SRCS+= bus_if.h device_if.h +SRCS= bus_if.h device_if.h pci_if.h + +.PATH: ${.CURDIR}/../../dev/dpms +SRCS+= dpms.c .include <bsd.kmod.mk> diff --git a/sys/modules/vesa/Makefile b/sys/modules/vesa/Makefile index eb49f93..69a0c33 100644 --- a/sys/modules/vesa/Makefile +++ b/sys/modules/vesa/Makefile @@ -1,8 +1,13 @@ # $FreeBSD$ -.PATH: ${.CURDIR}/../../dev/syscons ${.CURDIR}/../../i386/isa - KMOD= vesa -SRCS= vesa.c scvesactl.c opt_vga.h opt_vesa.h +SRCS= opt_vga.h opt_vesa.h +SRCS+= bus_if.h device_if.h pci_if.h + +.PATH: ${.CURDIR}/../../dev/fb +SRCS+= vesa.c + +.PATH: ${.CURDIR}/../../dev/syscons +SRCS+= scvesactl.c .include <bsd.kmod.mk> diff --git a/sys/modules/x86bios/Makefile b/sys/modules/x86bios/Makefile new file mode 100644 index 0000000..3cab285 --- /dev/null +++ b/sys/modules/x86bios/Makefile @@ -0,0 +1,11 @@ +# $FreeBSD$ + +KMOD= x86bios +SRCS= opt_x86bios.h +SRCS+= bus_if.h device_if.h pci_if.h + +.PATH: ${.CURDIR}/../../contrib/x86emu +.PATH: ${.CURDIR}/../../compat/x86bios +SRCS+= x86bios.c x86emu.c + +.include <bsd.kmod.mk> diff --git a/sys/modules/x86emu/Makefile b/sys/modules/x86emu/Makefile new file mode 100644 index 0000000..3991d6c --- /dev/null +++ b/sys/modules/x86emu/Makefile @@ -0,0 +1,8 @@ +# $FreeBSD$ + +.PATH: ${.CURDIR}/../../contrib/x86emu + +KMOD= x86emu +SRCS= x86emu.c x86emu_util.c + +.include <bsd.kmod.mk> diff --git a/sys/sys/fbio.h b/sys/sys/fbio.h index c7183df..5745182 100644 --- a/sys/sys/fbio.h +++ b/sys/sys/fbio.h @@ -269,6 +269,7 @@ struct video_info { #define V_INFO_GRAPHICS (1 << 1) #define V_INFO_LINEAR (1 << 2) #define V_INFO_VESA (1 << 3) +#define V_INFO_NONVGA (1 << 4) int vi_width; int vi_height; int vi_cwidth; @@ -331,6 +332,7 @@ struct video_adapter { #define V_ADP_INITIALIZED (1 << 17) #define V_ADP_REGISTERED (1 << 18) #define V_ADP_ATTACHED (1 << 19) +#define V_ADP_DAC8 (1 << 20) vm_offset_t va_io_base; int va_io_size; vm_offset_t va_crtc_addr; diff --git a/sys/sys/param.h b/sys/sys/param.h index 6da5e60..35caa51 100644 --- a/sys/sys/param.h +++ b/sys/sys/param.h @@ -58,7 +58,7 @@ * in the range 5 to 9. */ #undef __FreeBSD_version -#define __FreeBSD_version 800503 /* Master, propagated to newvers */ +#define __FreeBSD_version 800504 /* Master, propagated to newvers */ #ifndef LOCORE #include <sys/types.h> |