pax_global_header00006660000000000000000000000064124750374140014521gustar00rootroot0000000000000052 comment=2eac29a32291ede07104cb614a157eca1bbb18e8 libx86emu-1.5/000077500000000000000000000000001247503741400132115ustar00rootroot00000000000000libx86emu-1.5/.gitignore000066400000000000000000000000221247503741400151730ustar00rootroot00000000000000changelog VERSION libx86emu-1.5/LICENSE000066400000000000000000000013421247503741400142160ustar00rootroot00000000000000 License information ------------------- The x86emu library is under a BSD style license, comaptible with the XFree86 and X licenses used by XFree86. The original x86emu libraries were under the GNU General Public License. Due to license incompatibilities between the GPL and the XFree86 license, the original authors of the code decided to allow a license change. If you have submitted code to the original x86emu project, and you don't agree with the license change, please contact us and let you know. Your code will be removed to comply with your wishes. If you have any questions about this, please send email to x86emu@linuxlabs.com or KendallB@scitechsoft.com for clarification. libx86emu-1.5/Makefile000066400000000000000000000035561247503741400146620ustar00rootroot00000000000000ARCH := $(shell uname -m) ifneq ($(filter i386 i486 i586 i686, $(ARCH)),) ARCH := i386 endif GIT2LOG := $(shell if [ -x ./git2log ] ; then echo ./git2log --update ; else echo true ; fi) GITDEPS := $(shell [ -d .git ] && echo .git/HEAD .git/refs/heads .git/refs/tags) VERSION := $(shell $(GIT2LOG) --version VERSION ; cat VERSION) BRANCH := $(shell [ -d .git ] && git branch | perl -ne 'print $$_ if s/^\*\s*//') PREFIX := libx86emu-$(VERSION) MAJOR_VERSION := $(shell $(GIT2LOG) --version VERSION ; cut -d . -f 1 VERSION) CC = gcc CFLAGS = -g -O2 -fPIC -fomit-frame-pointer -Wall ifneq ($(filter x86_64, $(ARCH)),) LIBDIR = /usr/lib64 else LIBDIR = /usr/lib endif LIBX86 = libx86emu CFILES = $(wildcard *.c) OBJS = $(CFILES:.c=.o) LIB_NAME = $(LIBX86).so.$(VERSION) LIB_SONAME = $(LIBX86).so.$(MAJOR_VERSION) .PHONY: all shared install test clean %.o: %.c $(CC) -c $(CFLAGS) $< all: changelog shared changelog: $(GITDEPS) $(GIT2LOG) --changelog changelog shared: $(LIB_NAME) install: shared install -D $(LIB_NAME) $(DESTDIR)$(LIBDIR)/$(LIB_NAME) ln -snf $(LIB_NAME) $(DESTDIR)$(LIBDIR)/$(LIB_SONAME) ln -snf $(LIB_SONAME) $(DESTDIR)$(LIBDIR)/$(LIBX86).so install -m 644 -D include/x86emu.h $(DESTDIR)/usr/include/x86emu.h $(LIB_NAME): .depend $(OBJS) $(CC) -shared -Wl,-soname,$(LIB_SONAME) $(OBJS) -o $(LIB_NAME) test: make -C test archive: changelog @if [ ! -d .git ] ; then echo no git repo ; false ; fi mkdir -p package git archive --prefix=$(PREFIX)/ $(BRANCH) > package/$(PREFIX).tar tar -r -f package/$(PREFIX).tar --mode=0664 --owner=root --group=root --mtime="`git show -s --format=%ci`" --transform='s:^:$(PREFIX)/:' VERSION changelog xz -f package/$(PREFIX).tar clean: make -C test clean rm -f *.o *~ include/*~ *.so.* .depend rm -rf package ifneq "$(MAKECMDGOALS)" "clean" .depend: $(CFILES) @$(CC) -MG -MM $(CFLAGS) $(CFILES) >$@ -include .depend endif libx86emu-1.5/README000066400000000000000000000152471247503741400141020ustar00rootroot00000000000000x86 emulation library ===================== API functions ------------- - create new emulation object x86emu_t *x86emu_new(unsigned def_mem_perm, unsigned def_io_perm); def_mem_perm are the default permissions for memory accesses, def_io_perm for io. See x86emu_set_perm(), x86emu_set_io_perm(). Free object later with x86emu_done(). - delete emulation object x86emu_t *x86emu_done(x86emu_t *emu); Frees all memory; returns NULL; - clone emulation object x86emu_t *x86emu_clone(x86emu_t *emu); Creates a copy of emu. Free the copy later with x86emu_done(). - reset cpu state void x86emu_reset(x86emu_t *emu); Does a normal cpu reset (clear registers, set cs:eip). - start emulation unsigned x86emu_run(x86emu_t *emu, unsigned flags); - flags: X86EMU_RUN_TIMEOUT X86EMU_RUN_MAX_INSTR X86EMU_RUN_NO_EXEC X86EMU_RUN_NO_CODE X86EMU_RUN_LOOP X86EMU_RUN_TIMEOUT: set emu->timeout to max. seconds to run. X86EMU_RUN_MAX_INSTR: set emu->max_instr to max. instructions to emulate. Return value indicates why x86emu_run() stopped (see flags). Note: copies emu to global variable x86emu while running! - stop emulation void x86emu_stop(x86emu_t *emu); Use this function in callbacks (e.g. interrupt handler) to tell the emulator to stop. The emulator returns from x86emu_run() when the current instruction has been finished. - set log buffer void x86emu_set_log(x86emu_t *emu, char *buffer, unsigned buffer_size, x86emu_flush_func_t flush); typedef void (* x86emu_flush_func_t)(x86emu_t *emu, char *buf, unsigned size); If the log buffer is full, flush() is called (if not NULL). The buffer is freed in x86emu_done(). - write to log void x86emu_log(x86emu_t *emu, const char *format, ...) __attribute__ ((format (printf, 1, 2))); - clear log void x86emu_clear_log(x86emu_t *emu, int flush); Clear log buffer. If flush != 0, write current log via flush() function (see x86emu_set_log()). - dump emulator state void x86emu_dump(x86emu_t *emu, int flags); - flags: X86EMU_DUMP_REGS X86EMU_DUMP_MEM X86EMU_DUMP_ACC_MEM X86EMU_DUMP_INV_MEM X86EMU_DUMP_ATTR X86EMU_DUMP_ASCII X86EMU_DUMP_IO X86EMU_DUMP_INTS X86EMU_DUMP_TIME Writes emulator state to log. - memory permissions void x86emu_set_perm(x86emu_t *emu, unsigned start, unsigned end, unsigned perm); - perm: bitmask of X86EMU_PERM_R X86EMU_PERM_W X86EMU_PERM_X X86EMU_PERM_VALID X86EMU_ACC_R X86EMU_ACC_W X86EMU_ACC_X X86EMU_ACC_INVALID X86EMU_PERM_{R,W,X}: memory is readable, writable, executable X86EMU_PERM_VALID: memory has been initialized (say, been written to) X86EMU_ACC_{R,W,X}: memory has been read, written, executed X86EMU_ACC_INVALID: there was an invalid access (e.g. tried to read but not readable) - direct memory access void x86emu_set_page(x86emu_t *emu, unsigned offset, void *address); Map memory area of X86EMU_PAGE_SIZE size at address into emulator at offset. offset must be X86EMU_PAGE_SIZE aligned, address needs not. Memory permissions still apply (via x86emu_set_perm()). If address is NULL, switch back to emulated memory. - io permissions void x86emu_set_io_perm(x86emu_t *emu, unsigned start, unsigned end, unsigned perm); - perm: see x86emu_set_perm() - reset memory access statistics void x86emu_reset_access_stats(x86emu_t *emu); Resets the X86EMU_ACC_* bits for the whole memory (see x86emu_set_perm()). - execution hook x86emu_code_handler_t x86emu_set_code_handler(x86emu_t *emu, x86emu_code_handler_t handler); typedef int (* x86emu_code_handler_t)(x86emu_t *emu); If defined, the function is called before a new instruction is decoded and emulated. If logging is enabled the current cpu state has already been logged. If the function returns a value != 0, the emulation is stopped. - set interrupt handler x86emu_intr_handler_t x86emu_set_intr_handler(x86emu_t *emu, x86emu_intr_handler_t handler); typedef int (* x86emu_intr_handler_t)(x86emu_t *emu, u8 num, unsigned type); - type: INTR_TYPE_SOFT INTR_TYPE_FAULT + bitmask of INTR_MODE_RESTART INTR_MODE_ERRCODE If defined, the interrupt handler is called at the start of the interrupt handling procedure. The handler should return 1 to indicate the interrupt handling is complete and the emulator can skip its own interrupt processing or 0 to indicate the emulator should continue with normal interrupt processing. - set alternative callback function that handles memory and io accesses x86emu_memio_handler_t x86emu_set_memio_handler(x86emu_t *emu, x86emu_memio_handler_t handler); typedef unsigned (* x86emu_memio_handler_t)(x86emu_t *emu, u32 addr, u32 *val, unsigned type); - type: one of X86EMU_MEMIO_8 X86EMU_MEMIO_16 X86EMU_MEMIO_32 X86EMU_MEMIO_8_NOPERM + one of X86EMU_MEMIO_R X86EMU_MEMIO_W X86EMU_MEMIO_X X86EMU_MEMIO_I X86EMU_MEMIO_O Returns old function. - raise an interrupt void x86emu_intr_raise(x86emu_t *emu, u8 intr_nr, unsigned type, unsigned err); The interrupt is handled before the next instruction. For type see x86emu_set_intr_func(); if INTR_MODE_ERRCODE is set, err is the error code pushed to the stack. - memory access functions unsigned x86emu_read_byte(x86emu_t *emu, unsigned addr); unsigned x86emu_read_byte_noperm(x86emu_t *emu, unsigned addr); unsigned x86emu_read_word(x86emu_t *emu, unsigned addr); unsigned x86emu_read_dword(x86emu_t *emu, unsigned addr); void x86emu_write_byte(x86emu_t *emu, unsigned addr, unsigned val); void x86emu_write_byte_noperm(x86emu_t *emu, unsigned addr, unsigned val); void x86emu_write_word(x86emu_t *emu, unsigned addr, unsigned val); void x86emu_write_dword(x86emu_t *emu, unsigned addr, unsigned val); Convenience functions to access emulator memory. Memory access restrictions (see x86emu_set_perm()) apply except for x86emu_*_noperm() which do not check permissions. - set segment register void x86emu_set_seg_register(x86emu_t *emu, sel_t *seg, u16 val); R_CS_SEL, R_DS_SEL, R_ES_SEL, R_FS_SEL, R_GS_SEL, R_SS_SEL Example: x86emu_set_seg_register(emu, emu->x86.R_CS_SEL, 0x7c0); debug instruction ----------------- If the X86EMU_TRACE_DEBUG flags is set, the emulator interprets a special debug intruction: db 0x67, 0xeb, LEN, DATA... which is basically a short jump with address size prefix (an instruction normally not used). LEN is the size of DATA. DATA can be: - db 0x01 db STRING Print STRING to log. STRING is not 0-zerminated. - db 0x02 dd flags Set trace flags. - db 0x03 dd flags Clear trace flags. - db 0x04 dd flags Dump emulator state. For flags, see x86emu_dump(). - db 0x05 Reset memory access stats. See x86emu_reset_access_stats(). libx86emu-1.5/api.c000066400000000000000000000333061247503741400141330ustar00rootroot00000000000000#include "include/x86emu_int.h" #define LINE_LEN 16 x86emu_t *x86emu_new(unsigned def_mem_perm, unsigned def_io_perm) { x86emu_t *emu = calloc(1, sizeof *emu); emu->mem = emu_mem_new(def_mem_perm); emu->io.map = calloc(X86EMU_IO_PORTS, sizeof *emu->io.map); emu->io.stats_i = calloc(X86EMU_IO_PORTS, sizeof *emu->io.stats_i); emu->io.stats_o = calloc(X86EMU_IO_PORTS, sizeof *emu->io.stats_o); if(def_io_perm) x86emu_set_io_perm(emu, 0, X86EMU_IO_PORTS - 1, def_io_perm); x86emu_set_memio_handler(emu, vm_memio); x86emu_reset(emu); return emu; } x86emu_t *x86emu_done(x86emu_t *emu) { if(emu) { emu_mem_free(emu->mem); free(emu->log.buf); free(emu->io.map); free(emu->io.stats_i); free(emu->io.stats_o); free(emu->x86.msr); free(emu->x86.msr_perm); free(emu); } return NULL; } x86emu_t *x86emu_clone(x86emu_t *emu) { x86emu_t *new_emu = NULL; if(!emu) return new_emu; new_emu = mem_dup(emu, sizeof *emu); new_emu->mem = emu_mem_clone(emu->mem); if(emu->log.buf && emu->log.ptr) { new_emu->log.buf = malloc(emu->log.size); // copy only used log space if(emu->log.ptr <= emu->log.buf + emu->log.size) { new_emu->log.ptr = new_emu->log.buf + (emu->log.ptr - emu->log.buf); memcpy(new_emu->log.buf, emu->log.buf, emu->log.ptr - emu->log.buf); } } new_emu->io.map = mem_dup(emu->io.map, X86EMU_IO_PORTS * sizeof *emu->io.map); new_emu->io.stats_i = mem_dup(emu->io.stats_i, X86EMU_IO_PORTS * sizeof *emu->io.stats_i); new_emu->io.stats_o = mem_dup(emu->io.stats_o, X86EMU_IO_PORTS * sizeof *emu->io.stats_o); new_emu->x86.msr = mem_dup(emu->x86.msr, X86EMU_MSRS * sizeof *emu->x86.msr); new_emu->x86.msr_perm = mem_dup(emu->x86.msr_perm, X86EMU_MSRS * sizeof *emu->x86.msr_perm); return new_emu; } void x86emu_reset(x86emu_t *emu) { x86emu_regs_t *x86 = &emu->x86; free(x86->msr); free(x86->msr_perm); memset(x86, 0, sizeof *x86); x86->R_EFLG = 2; x86->R_CS_LIMIT = x86->R_DS_LIMIT = x86->R_SS_LIMIT = x86->R_ES_LIMIT = x86->R_FS_LIMIT = x86->R_GS_LIMIT = 0xffff; // resp. 0x4093/9b for 4GB x86->R_CS_ACC = 0x9b; x86->R_SS_ACC = x86->R_DS_ACC = x86->R_ES_ACC = x86->R_FS_ACC = x86->R_GS_ACC = 0x93; x86->R_CS = 0xf000; x86->R_CS_BASE = 0xf0000; x86->R_EIP = 0xfff0; x86->R_GDT_LIMIT = 0xffff; x86->R_IDT_LIMIT = 0xffff; x86->msr = calloc(X86EMU_MSRS, sizeof *x86->msr); x86->msr_perm = calloc(X86EMU_MSRS, sizeof *x86->msr_perm); x86->msr_perm[0x10] = X86EMU_ACC_X; // tsc x86->msr_perm[0x11] = X86EMU_ACC_X; // last real tsc x86->msr_perm[0x12] = X86EMU_ACC_X; // real tsc } x86emu_memio_handler_t x86emu_set_memio_handler(x86emu_t *emu, x86emu_memio_handler_t handler) { x86emu_memio_handler_t old = NULL; if(emu) { old = emu->memio; emu->memio = handler; } return old; } x86emu_intr_handler_t x86emu_set_intr_handler(x86emu_t *emu, x86emu_intr_handler_t handler) { x86emu_intr_handler_t old = NULL; if(emu) { old = emu->intr; emu->intr = handler; } return old; } x86emu_code_handler_t x86emu_set_code_handler(x86emu_t *emu, x86emu_code_handler_t handler) { x86emu_code_handler_t old = NULL; if(emu) { old = emu->code_check; emu->code_check = handler; } return old; } unsigned x86emu_read_byte(x86emu_t *emu, unsigned addr) { u32 val = 0xff; if(emu) emu->memio(emu, addr, &val, X86EMU_MEMIO_R | X86EMU_MEMIO_8); return val; } unsigned x86emu_read_byte_noperm(x86emu_t *emu, unsigned addr) { u32 val = 0xff; if(emu) emu->memio(emu, addr, &val, X86EMU_MEMIO_R | X86EMU_MEMIO_8_NOPERM); return val; } unsigned x86emu_read_word(x86emu_t *emu, unsigned addr) { u32 val = 0xffff; if(emu) emu->memio(emu, addr, &val, X86EMU_MEMIO_R | X86EMU_MEMIO_16); return val; } unsigned x86emu_read_dword(x86emu_t *emu, unsigned addr) { u32 val = 0xffffffff; if(emu) emu->memio(emu, addr, &val, X86EMU_MEMIO_R | X86EMU_MEMIO_32); return val; } void x86emu_write_byte(x86emu_t *emu, unsigned addr, unsigned val) { u32 val32 = val; if(emu) emu->memio(emu, addr, &val32, X86EMU_MEMIO_W | X86EMU_MEMIO_8); } void x86emu_write_byte_noperm(x86emu_t *emu, unsigned addr, unsigned val) { u32 val32 = val; if(emu) emu->memio(emu, addr, &val32, X86EMU_MEMIO_W | X86EMU_MEMIO_8_NOPERM); } void x86emu_write_word(x86emu_t *emu, unsigned addr, unsigned val) { u32 val32 = val; if(emu) emu->memio(emu, addr, &val32, X86EMU_MEMIO_W | X86EMU_MEMIO_16); } void x86emu_write_dword(x86emu_t *emu, unsigned addr, unsigned val) { u32 val32 = val; if(emu) emu->memio(emu, addr, &val32, X86EMU_MEMIO_W | X86EMU_MEMIO_32); } void x86emu_set_log(x86emu_t *emu, unsigned buffer_size, x86emu_flush_func_t flush) { if(emu) { if(emu->log.buf) free(emu->log.buf); emu->log.size = buffer_size; emu->log.buf = buffer_size ? calloc(1, buffer_size) : NULL; emu->log.ptr = emu->log.buf; emu->log.flush = flush; } } unsigned x86emu_clear_log(x86emu_t *emu, int flush) { if(!emu) emu = &M; if(flush && emu->log.flush) { if(emu->log.ptr && emu->log.ptr != emu->log.buf) { emu->log.flush(emu, emu->log.buf, emu->log.ptr - emu->log.buf); } } if((emu->log.ptr = emu->log.buf)) *emu->log.ptr = 0; return emu->log.ptr ? LOG_FREE(emu) : 0; } void x86emu_log(x86emu_t *emu, const char *format, ...) { va_list args; int size; if(!emu || !emu->log.ptr) return; size = emu->log.size - (emu->log.ptr - emu->log.buf); va_start(args, format); if(size > 0) { size = vsnprintf(emu->log.ptr, size, format, args); if(size > 0) { emu->log.ptr += size; } else { *emu->log.ptr = 0; } } va_end(args); } /* * flags: * bits 0-7: * 0: show all initialized memory * 1: show only accessed memory * 2: show only invalidly accessed memory * * bit 8: show ascii, too */ static void dump_data(unsigned char *data, unsigned char *attr, char *str_data, char *str_attr, int flags) { unsigned u, u1, flag_ascii; char c; int ok = 0; char *sd = str_data, *sa = str_attr; char *ascii = str_data + 4 * LINE_LEN + 2; flag_ascii = flags & 0x100; flags &= 0xff; for(u = 0; u < LINE_LEN; u++) { *str_data++ = (attr[u] & X86EMU_ACC_INVALID) ? '*' : ' '; if( (flags == 0 && (attr[u] & X86EMU_PERM_VALID)) || (flags == 1 && (attr[u] & (X86EMU_ACC_R | X86EMU_ACC_W | X86EMU_ACC_X | X86EMU_ACC_INVALID))) || (flags == 2 && (attr[u] & X86EMU_ACC_INVALID)) ) { ok = 1; decode_hex2(&str_data, u1 = data[u]); c = (attr[u] & X86EMU_PERM_R) ? (attr[u] & X86EMU_ACC_R) ? 'R' : 'r' : ' '; *str_attr++ = c; c = (attr[u] & X86EMU_PERM_W) ? (attr[u] & X86EMU_ACC_W) ? 'W' : 'w' : ' '; *str_attr++ = c; c = (attr[u] & X86EMU_PERM_X) ? (attr[u] & X86EMU_ACC_X) ? 'X' : 'x' : ' '; *str_attr++ = c; if(u1 < 0x20 || u1 >= 0x7f) u1 = '.'; ascii[u] = u1; } else { *str_data++ = ' '; *str_data++ = ' '; *str_attr++ = ' '; *str_attr++ = ' '; *str_attr++ = ' '; ascii[u] = ' '; } *str_data++ = ' '; *str_attr++ = ' '; } if(ok) { if(flag_ascii) { str_data[0] = ' '; str_data[1] = ' '; str_data += 2 + LINE_LEN; } } else { str_data = sd; str_attr = sa; } *str_data = *str_attr = 0; while(str_data > sd && str_data[-1] == ' ') *--str_data = 0; while(str_attr > sa && str_attr[-1] == ' ') *--str_attr = 0; } void x86emu_dump(x86emu_t *emu, int flags) { x86emu_mem_t *mem = emu->mem; mem2_pdir_t *pdir; mem2_ptable_t *ptable; mem2_page_t page; unsigned pdir_idx, u, u1, u2, addr; char str_data[LINE_LEN * 8], str_attr[LINE_LEN * 8], fbuf[64]; unsigned char def_data[LINE_LEN], def_attr[LINE_LEN]; int dump_flags; if( mem && mem->pdir && (flags & (X86EMU_DUMP_MEM | X86EMU_DUMP_ACC_MEM | X86EMU_DUMP_INV_MEM | X86EMU_DUMP_ATTR)) ) { x86emu_log(emu, "; - - memory\n"); x86emu_log(emu, "; "); for(u1 = 0; u1 < 16; u1++) x86emu_log(emu, "%4x", u1); x86emu_log(emu, "\n"); dump_flags = 0; if(flags & X86EMU_DUMP_INV_MEM) dump_flags = 2; if(flags & X86EMU_DUMP_ACC_MEM) dump_flags = 1; if(flags & X86EMU_DUMP_MEM) dump_flags = 0; if(flags & X86EMU_DUMP_ASCII) dump_flags |= 0x100; pdir = mem->pdir; for(pdir_idx = 0; pdir_idx < (1 << X86EMU_PDIR_BITS); pdir_idx++) { ptable = (*pdir)[pdir_idx]; if(!ptable) continue; for(u1 = 0; u1 < (1 << X86EMU_PTABLE_BITS); u1++) { page = (*ptable)[u1]; if(page.data) { for(u2 = 0; u2 < X86EMU_PAGE_SIZE; u2 += LINE_LEN) { memcpy(def_data, page.data + u2, LINE_LEN); if(page.attr) { memcpy(def_attr, page.attr + u2, LINE_LEN); } else { memset(def_attr, page.def_attr, LINE_LEN); } dump_data(def_data, def_attr, str_data, str_attr, dump_flags); if(*str_data) { addr = (((pdir_idx << X86EMU_PTABLE_BITS) + u1) << X86EMU_PAGE_BITS) + u2; x86emu_log(emu, "%08x: %s\n", addr, str_data); if((flags & X86EMU_DUMP_ATTR)) x86emu_log(emu, " %s\n", str_attr); } } } } } x86emu_log(emu, "\n"); } if((flags & X86EMU_DUMP_IO)) { x86emu_log(emu, "; - - io accesses\n"); for(u = 0; u < X86EMU_IO_PORTS; u++) { if(emu->io.map[u] & (X86EMU_ACC_R | X86EMU_ACC_W | X86EMU_ACC_INVALID)) { x86emu_log(emu, "%04x: %c%c%c in=%08x out=%08x\n", u, (emu->io.map[u] & X86EMU_ACC_INVALID) ? '*' : ' ', (emu->io.map[u] & X86EMU_PERM_R) ? 'r' : ' ', (emu->io.map[u] & X86EMU_PERM_W) ? 'w' : ' ', emu->io.stats_i[u], emu->io.stats_o[u] ); } } x86emu_log(emu, "\n"); } if((flags & X86EMU_DUMP_INTS)) { x86emu_log(emu, "; - - interrupt statistics\n"); for(u1 = 0; u1 < 0x100; u1++) { if(emu->x86.intr_stats[u1]) x86emu_log(emu, "int %02x: %08x\n", u1, emu->x86.intr_stats[u1]); } x86emu_log(emu, "\n"); } if((flags & X86EMU_DUMP_REGS)) { x86emu_log(emu, "; - - registers\n"); for(u = u1 = 0; u < X86EMU_MSRS; u++) { if(u >= 0x11 && u <= 0x12 && !(flags & X86EMU_DUMP_TIME)) continue; if(emu->x86.msr_perm[u]) { u1 = 1; x86emu_log(emu, "msr[%04x] %c%c %016llx", u, (emu->x86.msr_perm[u] & X86EMU_ACC_R) ? 'r' : ' ', (emu->x86.msr_perm[u] & X86EMU_ACC_W) ? 'w' : ' ', (unsigned long long) emu->x86.msr[u] ); switch(u) { case 0x10: x86emu_log(emu, " ; tsc"); break; case 0x11: x86emu_log(emu, " ; real tsc (previous)"); break; case 0x12: x86emu_log(emu, " ; real tsc"); if(emu->x86.R_TSC) { x86emu_log(emu, ", ratio=%.2f", (double) emu->x86.R_REAL_TSC / emu->x86.R_TSC); } break; } x86emu_log(emu, "\n"); } } if(u1) x86emu_log(emu, "\n"); x86emu_log(emu, "cr0=%08x cr1=%08x cr2=%08x cr3=%08x cr4=%08x\n", emu->x86.R_CR0, emu->x86.R_CR1, emu->x86.R_CR2, emu->x86.R_CR3, emu->x86.R_CR4 ); x86emu_log(emu, "dr0=%08x dr1=%08x dr2=%08x dr3=%08x dr6=%08x dr7=%08x\n\n", emu->x86.R_DR0, emu->x86.R_DR1, emu->x86.R_DR2, emu->x86.R_DR3, emu->x86.R_DR6, emu->x86.R_DR7 ); x86emu_log(emu, "gdt.base=%08x gdt.limit=%04x\n", emu->x86.R_GDT_BASE, emu->x86.R_GDT_LIMIT ); x86emu_log(emu, "idt.base=%08x idt.limit=%04x\n", emu->x86.R_IDT_BASE, emu->x86.R_IDT_LIMIT ); x86emu_log(emu, "tr=%04x tr.base=%08x tr.limit=%08x tr.acc=%04x\n", emu->x86.R_TR, emu->x86.R_TR_BASE, emu->x86.R_TR_LIMIT, emu->x86.R_TR_ACC ); x86emu_log(emu, "ldt=%04x ldt.base=%08x ldt.limit=%08x ldt.acc=%04x\n\n", emu->x86.R_LDT, emu->x86.R_LDT_BASE, emu->x86.R_LDT_LIMIT, emu->x86.R_LDT_ACC ); x86emu_log(emu, "cs=%04x cs.base=%08x cs.limit=%08x cs.acc=%04x\n", emu->x86.R_CS, emu->x86.R_CS_BASE, emu->x86.R_CS_LIMIT, emu->x86.R_CS_ACC ); x86emu_log(emu, "ss=%04x ss.base=%08x ss.limit=%08x ss.acc=%04x\n", emu->x86.R_SS, emu->x86.R_SS_BASE, emu->x86.R_SS_LIMIT, emu->x86.R_SS_ACC ); x86emu_log(emu, "ds=%04x ds.base=%08x ds.limit=%08x ds.acc=%04x\n", emu->x86.R_DS, emu->x86.R_DS_BASE, emu->x86.R_DS_LIMIT, emu->x86.R_DS_ACC ); x86emu_log(emu, "es=%04x es.base=%08x es.limit=%08x es.acc=%04x\n", emu->x86.R_ES, emu->x86.R_ES_BASE, emu->x86.R_ES_LIMIT, emu->x86.R_ES_ACC ); x86emu_log(emu, "fs=%04x fs.base=%08x fs.limit=%08x fs.acc=%04x\n", emu->x86.R_FS, emu->x86.R_FS_BASE, emu->x86.R_FS_LIMIT, emu->x86.R_FS_ACC ); x86emu_log(emu, "gs=%04x gs.base=%08x gs.limit=%08x gs.acc=%04x\n\n", emu->x86.R_GS, emu->x86.R_GS_BASE, emu->x86.R_GS_LIMIT, emu->x86.R_GS_ACC ); x86emu_log(emu, "eax=%08x ebx=%08x ecx=%08x edx=%08x\n", emu->x86.R_EAX, emu->x86.R_EBX, emu->x86.R_ECX, emu->x86.R_EDX ); x86emu_log(emu, "esi=%08x edi=%08x ebp=%08x esp=%08x\n", emu->x86.R_ESI, emu->x86.R_EDI, emu->x86.R_EBP, emu->x86.R_ESP ); x86emu_log(emu, "eip=%08x eflags=%08x", emu->x86.R_EIP, emu->x86.R_EFLG); *fbuf = 0; if(emu->x86.R_EFLG & 0x800) strcat(fbuf, " of"); if(emu->x86.R_EFLG & 0x400) strcat(fbuf, " df"); if(emu->x86.R_EFLG & 0x200) strcat(fbuf, " if"); if(emu->x86.R_EFLG & 0x080) strcat(fbuf, " sf"); if(emu->x86.R_EFLG & 0x040) strcat(fbuf, " zf"); if(emu->x86.R_EFLG & 0x010) strcat(fbuf, " af"); if(emu->x86.R_EFLG & 0x004) strcat(fbuf, " pf"); if(emu->x86.R_EFLG & 0x001) strcat(fbuf, " cf"); if(*fbuf) x86emu_log(emu, " ;%s", fbuf); x86emu_log(emu, "\n\n"); } } libx86emu-1.5/decode.c000066400000000000000000001415571247503741400146150ustar00rootroot00000000000000/**************************************************************************** * * Realmode X86 Emulator Library * * Copyright (C) 1996-1999 SciTech Software, Inc. * Copyright (C) David Mosberger-Tang * 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. * * ======================================================================== * * Language: ANSI C * Environment: Any * Developer: Kendall Bennett * * Description: This file includes subroutines which are related to * instruction decoding and accessess of immediate data via IP. etc. * ****************************************************************************/ #include "include/x86emu_int.h" #include /*----------------------------- Implementation ----------------------------*/ x86emu_t M L_SYM; static void handle_interrupt(void); static void generate_int(u8 nr, unsigned type, unsigned errcode); static void log_regs(void); static void log_code(void); static void check_data_access(sel_t *seg, u32 ofs, u32 size); static unsigned decode_memio(u32 addr, u32 *val, unsigned type); static unsigned emu_memio(x86emu_t *emu, u32 addr, u32 *val, unsigned type); static void idt_lookup(u8 nr, u32 *new_cs, u32 *new_eip); /**************************************************************************** REMARKS: Main execution loop for the emulator. We return from here when the system halts, timeouts, or one of the conditions in flags are met. ****************************************************************************/ unsigned x86emu_run(x86emu_t *emu, unsigned flags) { u8 op1, u_m1; s32 ofs32; char **p; unsigned u, rs = 0; time_t t0; #if WITH_TSC u64 tsc_ofs; #endif static unsigned char is_prefix[0x100] = { [0x26] = 1, [0x2e] = 1, [0x36] = 1, [0x3e] = 1, [0x64 ... 0x67] = 1, [0xf0] = 1, [0xf2 ... 0xf3] = 1 }; if(emu) M = *emu; p = &M.log.ptr; t0 = time(NULL); #if WITH_TSC tsc_ofs = tsc() - M.x86.R_REAL_TSC; #endif #if WITH_IOPL M.io.iopl_ok = M.io.iopl_needed && getiopl() != 3 ? 0 : 1; #else M.io.iopl_ok = 1; #endif for(;;) { *(M.x86.disasm_ptr = M.x86.disasm_buf) = 0; M.x86.instr_len = 0; M.x86.mode = 0; if(ACC_D(M.x86.R_CS_ACC)) { M.x86.mode |= _MODE_DATA32 | _MODE_ADDR32 | _MODE_CODE32; } if(ACC_D(M.x86.R_SS_ACC)) { M.x86.mode |= _MODE_STACK32; } M.x86.default_seg = NULL; /* save EIP and CS values */ M.x86.saved_cs = M.x86.R_CS; M.x86.saved_eip = M.x86.R_EIP; log_regs(); if( (flags & X86EMU_RUN_MAX_INSTR) && M.max_instr && M.x86.R_TSC >= M.max_instr ) { rs |= X86EMU_RUN_MAX_INSTR; break; } if( (flags & X86EMU_RUN_TIMEOUT) && M.timeout && !(M.x86.R_TSC & 0xffff) && time(NULL) - t0 > M.timeout ) { rs |= X86EMU_RUN_TIMEOUT; break; } if(M.code_check) { if((*M.code_check)(&M) || MODE_HALTED) { rs |= X86EMU_RUN_NO_CODE; break; } } memcpy(M.x86.decode_seg, "[", 1); /* handle prefixes here */ while(is_prefix[op1 = fetch_byte()]) { switch(op1) { case 0x26: memcpy(M.x86.decode_seg, "es:[", 4); M.x86.default_seg = M.x86.seg + R_ES_INDEX; break; case 0x2e: memcpy(M.x86.decode_seg, "cs:[", 4); M.x86.default_seg = M.x86.seg + R_CS_INDEX; break; case 0x36: memcpy(M.x86.decode_seg, "ss:[", 4); M.x86.default_seg = M.x86.seg + R_SS_INDEX; break; case 0x3e: memcpy(M.x86.decode_seg, "ds:[", 4); M.x86.default_seg = M.x86.seg + R_DS_INDEX; break; case 0x64: memcpy(M.x86.decode_seg, "fs:[", 4); M.x86.default_seg = M.x86.seg + R_FS_INDEX; break; case 0x65: memcpy(M.x86.decode_seg, "gs:[", 4); M.x86.default_seg = M.x86.seg + R_GS_INDEX; break; case 0x66: M.x86.mode ^= _MODE_DATA32; break; case 0x67: M.x86.mode ^= _MODE_ADDR32; break; case 0xf0: OP_DECODE("lock: "); break; case 0xf2: OP_DECODE("repne "); M.x86.mode |= _MODE_REPNE; break; case 0xf3: OP_DECODE("repe "); M.x86.mode |= _MODE_REPE; break; } } if(MODE_HALTED) { rs |= X86EMU_RUN_NO_EXEC; M.x86.R_EIP = M.x86.saved_eip; break; } if(flags & X86EMU_RUN_LOOP) { u = M.x86.R_CS_BASE + M.x86.R_EIP; ofs32 = 0; if(op1 == 0xeb) { ofs32 = (s32) (s8) x86emu_read_byte_noperm(&M, u) + 1; } else if(op1 == 0xe9) { if(MODE_DATA32) { ofs32 = (x86emu_read_byte_noperm(&M, u) + (x86emu_read_byte_noperm(&M, u + 1) << 8)) + (x86emu_read_byte_noperm(&M, u + 2) << 16) + (x86emu_read_byte_noperm(&M, u + 3) << 24) + 4; } else { ofs32 = (s32) (s16) ( x86emu_read_byte_noperm(&M, u) + (x86emu_read_byte_noperm(&M, u + 1) << 8)) + 2; } } if(ofs32) { if(M.x86.R_EIP + ofs32 == M.x86.saved_eip) { rs |= X86EMU_RUN_LOOP; } else if(M.x86.R_EIP + 1 + ofs32 == M.x86.saved_eip && M.x86.saved_eip >= 1) { u_m1 = x86emu_read_byte_noperm(&M, M.x86.R_CS_BASE + M.x86.saved_eip - 1); if(u_m1 >= 0xf8 && u_m1 <= 0xfd) rs |= X86EMU_RUN_LOOP; } if(rs) x86emu_stop(&M); } } if(flags & X86EMU_RUN_NO_CODE) { u = M.x86.R_CS_BASE + M.x86.R_EIP; if(M.x86.mode == 0 && op1 == 0x00 && x86emu_read_byte_noperm(&M, u) == 0x00) { rs |= X86EMU_RUN_NO_CODE; } if(rs) x86emu_stop(&M); } (*x86emu_optab[op1])(op1); *M.x86.disasm_ptr = 0; handle_interrupt(); #if WITH_TSC M.x86.R_LAST_REAL_TSC = M.x86.R_REAL_TSC; M.x86.R_REAL_TSC = tsc() - tsc_ofs; #endif log_code(); if(M.x86.debug_len) { emu_process_debug(M.x86.debug_start, M.x86.debug_len); M.x86.debug_len = M.x86.debug_start = 0; } M.x86.R_TSC++; // time stamp counter if(MODE_HALTED) break; } if(*p) { if((rs & X86EMU_RUN_TIMEOUT)) { LOG_STR("* timeout\n"); } if((rs & X86EMU_RUN_MAX_INSTR)) { LOG_STR("* too many instructions\n"); } if((rs & X86EMU_RUN_NO_EXEC)) { LOG_STR("* memory not executable\n"); } if((rs & X86EMU_RUN_NO_CODE)) { LOG_STR("* no proper code\n"); } if((rs & X86EMU_RUN_LOOP)) { LOG_STR("* infinite loop\n"); } **p = 0; } #if WITH_TSC M.x86.R_REAL_TSC = tsc() - tsc_ofs; #endif if(emu) *emu = M; return rs; } /**************************************************************************** REMARKS: Halts the system by setting the halted system flag. ****************************************************************************/ void x86emu_stop(x86emu_t *emu) { emu->x86.mode |= _MODE_HALTED; } /**************************************************************************** REMARKS: Handles any pending asychronous interrupts. ****************************************************************************/ void handle_interrupt() { char **p = &M.log.ptr; unsigned lf; if(M.x86.intr_type) { if((M.log.trace & X86EMU_TRACE_INTS) && *p) { lf = LOG_FREE(&M); if(lf < 128) lf = x86emu_clear_log(&M, 1); if(lf >= 128) { if((M.x86.intr_type & 0xff) == INTR_TYPE_FAULT) { LOG_STR("* fault "); } else { LOG_STR("* int "); } decode_hex2(p, M.x86.intr_nr & 0xff); LOG_STR("\n"); **p = 0; } } generate_int(M.x86.intr_nr, M.x86.intr_type, M.x86.intr_errcode); } M.x86.intr_type = 0; } void x86emu_intr_raise(x86emu_t *emu, u8 intr_nr, unsigned type, unsigned err) { if(emu && !emu->x86.intr_type) { emu->x86.intr_nr = intr_nr; emu->x86.intr_type = type; emu->x86.intr_errcode = err; } } /**************************************************************************** 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. ****************************************************************************/ void fetch_decode_modrm(int *mod, int *regh, int *regl) { u8 fetched; fetched = fetch_byte(); *mod = (fetched >> 6) & 0x03; *regh = (fetched >> 3) & 0x07; *regl = (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. ****************************************************************************/ u8 fetch_byte(void) { u32 val; unsigned err; err = decode_memio(M.x86.R_CS_BASE + M.x86.R_EIP, &val, X86EMU_MEMIO_8 + X86EMU_MEMIO_X); if(err) x86emu_stop(&M); if(MODE_CODE32) { M.x86.R_EIP++; } else { M.x86.R_IP++; } if(M.x86.instr_len < sizeof M.x86.instr_buf) { M.x86.instr_buf[M.x86.instr_len++] = val; } return val; } /**************************************************************************** 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. ****************************************************************************/ u16 fetch_word(void) { u32 val; unsigned err; err = decode_memio(M.x86.R_CS_BASE + M.x86.R_EIP, &val, X86EMU_MEMIO_16 + X86EMU_MEMIO_X); if(err) x86emu_stop(&M); if(MODE_CODE32) { M.x86.R_EIP += 2; } else { M.x86.R_IP += 2; } if(M.x86.instr_len + 1 < sizeof M.x86.instr_buf) { M.x86.instr_buf[M.x86.instr_len++] = val; M.x86.instr_buf[M.x86.instr_len++] = val >> 8; } return val; } /**************************************************************************** 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. ****************************************************************************/ u32 fetch_long(void) { u32 val; unsigned err; err = decode_memio(M.x86.R_CS_BASE + M.x86.R_EIP, &val, X86EMU_MEMIO_32 + X86EMU_MEMIO_X); if(err) x86emu_stop(&M); if(MODE_CODE32) { M.x86.R_EIP += 4; } else { M.x86.R_IP += 4; } if(M.x86.instr_len + 3 < sizeof M.x86.instr_buf) { M.x86.instr_buf[M.x86.instr_len++] = val; M.x86.instr_buf[M.x86.instr_len++] = val >> 8; M.x86.instr_buf[M.x86.instr_len++] = val >> 16; M.x86.instr_buf[M.x86.instr_len++] = val >> 24; } return val; } /**************************************************************************** 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 M.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 sel_t *get_data_segment(void) { sel_t *seg; if(!(seg = M.x86.default_seg)) { seg = M.x86.seg + (M.x86.mode & _MODE_SEG_DS_SS ? R_SS_INDEX : R_DS_INDEX); } return seg; } /**************************************************************************** PARAMETERS: offset - Offset to load data from RETURNS: Byte value read from the absolute memory location. ****************************************************************************/ u8 fetch_data_byte(u32 ofs) { return fetch_data_byte_abs(get_data_segment(), ofs); } /**************************************************************************** PARAMETERS: offset - Offset to load data from RETURNS: Word value read from the absolute memory location. ****************************************************************************/ u16 fetch_data_word(u32 ofs) { return fetch_data_word_abs(get_data_segment(), ofs); } /**************************************************************************** PARAMETERS: offset - Offset to load data from RETURNS: Long value read from the absolute memory location. ****************************************************************************/ u32 fetch_data_long(u32 ofs) { return fetch_data_long_abs(get_data_segment(), ofs); } /**************************************************************************** PARAMETERS: segment - Segment to load data from offset - Offset to load data from RETURNS: Byte value read from the absolute memory location. ****************************************************************************/ u8 fetch_data_byte_abs(sel_t *seg, u32 ofs) { u32 val; check_data_access(seg, ofs, 1); decode_memio(seg->base + ofs, &val, X86EMU_MEMIO_8 + X86EMU_MEMIO_R); return val; } /**************************************************************************** PARAMETERS: segment - Segment to load data from offset - Offset to load data from RETURNS: Word value read from the absolute memory location. ****************************************************************************/ u16 fetch_data_word_abs(sel_t *seg, u32 ofs) { u32 val; check_data_access(seg, ofs, 2); decode_memio(seg->base + ofs, &val, X86EMU_MEMIO_16 + X86EMU_MEMIO_R); return val; } /**************************************************************************** PARAMETERS: segment - Segment to load data from offset - Offset to load data from RETURNS: Long value read from the absolute memory location. ****************************************************************************/ u32 fetch_data_long_abs(sel_t *seg, u32 ofs) { u32 val; check_data_access(seg, ofs, 4); decode_memio(seg->base + ofs, &val, X86EMU_MEMIO_32 + X86EMU_MEMIO_R); return 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. ****************************************************************************/ void store_data_byte(u32 ofs, u8 val) { store_data_byte_abs(get_data_segment(), ofs, 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. ****************************************************************************/ void store_data_word(u32 ofs, u16 val) { store_data_word_abs(get_data_segment(), ofs, 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. ****************************************************************************/ void store_data_long(u32 ofs, u32 val) { store_data_long_abs(get_data_segment(), ofs, 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. ****************************************************************************/ void store_data_byte_abs(sel_t *seg, u32 ofs, u8 val) { u32 val32 = val; check_data_access(seg, ofs, 1); decode_memio(seg->base + ofs, &val32, X86EMU_MEMIO_8 + X86EMU_MEMIO_W); } /**************************************************************************** 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. ****************************************************************************/ void store_data_word_abs(sel_t *seg, u32 ofs, u16 val) { u32 val32 = val; check_data_access(seg, ofs, 2); decode_memio(seg->base + ofs, &val32, X86EMU_MEMIO_16 + X86EMU_MEMIO_W); } /**************************************************************************** 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. ****************************************************************************/ void store_data_long_abs(sel_t *seg, u32 ofs, u32 val) { check_data_access(seg, ofs, 4); decode_memio(seg->base + ofs, &val, X86EMU_MEMIO_32 + X86EMU_MEMIO_W); } u8 fetch_io_byte(u32 port) { u32 val; decode_memio(port, &val, X86EMU_MEMIO_8 + X86EMU_MEMIO_I); return val; } u16 fetch_io_word(u32 port) { u32 val; decode_memio(port, &val, X86EMU_MEMIO_16 + X86EMU_MEMIO_I); return val; } u32 fetch_io_long(u32 port) { u32 val; decode_memio(port, &val, X86EMU_MEMIO_32 + X86EMU_MEMIO_I); return val; } void store_io_byte(u32 port, u8 val) { u32 val32 = val; decode_memio(port, &val32, X86EMU_MEMIO_8 + X86EMU_MEMIO_O); } void store_io_word(u32 port, u16 val) { u32 val32 = val; decode_memio(port, &val32, X86EMU_MEMIO_16 + X86EMU_MEMIO_O); } void store_io_long(u32 port, u32 val) { decode_memio(port, &val, X86EMU_MEMIO_32 + X86EMU_MEMIO_O); } /**************************************************************************** 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. ****************************************************************************/ u8* decode_rm_byte_register(int reg) { switch(reg) { case 0: OP_DECODE("al"); return &M.x86.R_AL; case 1: OP_DECODE("cl"); return &M.x86.R_CL; case 2: OP_DECODE("dl"); return &M.x86.R_DL; case 3: OP_DECODE("bl"); return &M.x86.R_BL; case 4: OP_DECODE("ah"); return &M.x86.R_AH; case 5: OP_DECODE("ch"); return &M.x86.R_CH; case 6: OP_DECODE("dh"); return &M.x86.R_DH; case 7: OP_DECODE("bh"); return &M.x86.R_BH; } return NULL; /* NOT REACHED OR REACHED ON ERROR */ } /**************************************************************************** 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. ****************************************************************************/ u16* decode_rm_word_register(int reg) { switch(reg) { case 0: OP_DECODE("ax"); return &M.x86.R_AX; case 1: OP_DECODE("cx"); return &M.x86.R_CX; case 2: OP_DECODE("dx"); return &M.x86.R_DX; case 3: OP_DECODE("bx"); return &M.x86.R_BX; case 4: OP_DECODE("sp"); return &M.x86.R_SP; case 5: OP_DECODE("bp"); return &M.x86.R_BP; case 6: OP_DECODE("si"); return &M.x86.R_SI; case 7: OP_DECODE("di"); return &M.x86.R_DI; } return NULL; /* NOTREACHED OR REACHED ON ERROR */ } /**************************************************************************** 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. ****************************************************************************/ u32* decode_rm_long_register(int reg) { switch(reg) { case 0: OP_DECODE("eax"); return &M.x86.R_EAX; case 1: OP_DECODE("ecx"); return &M.x86.R_ECX; case 2: OP_DECODE("edx"); return &M.x86.R_EDX; case 3: OP_DECODE("ebx"); return &M.x86.R_EBX; case 4: OP_DECODE("esp"); return &M.x86.R_ESP; case 5: OP_DECODE("ebp"); return &M.x86.R_EBP; case 6: OP_DECODE("esi"); return &M.x86.R_ESI; case 7: OP_DECODE("edi"); return &M.x86.R_EDI; } return NULL; /* NOTREACHED OR REACHED ON ERROR */ } /**************************************************************************** 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. ****************************************************************************/ sel_t *decode_rm_seg_register(int reg) { switch(reg) { case 0: OP_DECODE("es"); break; case 1: OP_DECODE("cs"); break; case 2: OP_DECODE("ss"); break; case 3: OP_DECODE("ds"); break; case 4: OP_DECODE("fs"); break; case 5: OP_DECODE("gs"); break; default: INTR_RAISE_UD(&M); reg = 6; break; } return M.x86.seg + reg; } void decode_hex(char **p, u32 ofs) { unsigned u; static const char *h = "0123456789abcdef"; if(ofs) { u = 8; while(!(ofs & 0xf0000000)) ofs <<= 4, u--; for(; u ; ofs <<= 4, u--) { *(*p)++ = h[(ofs >> 28) & 0xf]; } } else { *(*p)++ = '0'; } } void decode_hex1(char **p, u32 ofs) { static const char *h = "0123456789abcdef"; char *s = *p; (*p)++; *s = h[ofs & 0xf]; } void decode_hex2(char **p, u32 ofs) { static const char *h = "0123456789abcdef"; char *s = *p; *p += 2; s[1] = h[ofs & 0xf]; ofs >>= 4; s[0] = h[ofs & 0xf]; } void decode_hex4(char **p, u32 ofs) { static const char *h = "0123456789abcdef"; char *s = *p; *p += 4; s[3] = h[ofs & 0xf]; ofs >>= 4; s[2] = h[ofs & 0xf]; ofs >>= 4; s[1] = h[ofs & 0xf]; ofs >>= 4; s[0] = h[ofs & 0xf]; } void decode_hex8(char **p, u32 ofs) { decode_hex4(p, ofs >> 16); decode_hex4(p, ofs & 0xffff); } void decode_hex_addr(char **p, u32 ofs) { if(MODE_CODE32) { decode_hex4(p, ofs >> 16); decode_hex4(p, ofs & 0xffff); } else { decode_hex4(p, ofs & 0xffff); } } void decode_hex2s(char **p, s32 ofs) { static const char *h = "0123456789abcdef"; char *s = *p; *p += 3; if(ofs >= 0) { s[0] = '+'; } else { s[0] = '-'; ofs = -ofs; } s[2] = h[ofs & 0xf]; ofs >>= 4; s[1] = h[ofs & 0xf]; } void decode_hex4s(char **p, s32 ofs) { static const char *h = "0123456789abcdef"; char *s = *p; *p += 5; if(ofs >= 0) { s[0] = '+'; } else { s[0] = '-'; ofs = -ofs; } s[4] = h[ofs & 0xf]; ofs >>= 4; s[3] = h[ofs & 0xf]; ofs >>= 4; s[2] = h[ofs & 0xf]; ofs >>= 4; s[1] = h[ofs & 0xf]; } void decode_hex8s(char **p, s32 ofs) { if(ofs >= 0) { *(*p)++ = '+'; } else { *(*p)++ = '-'; ofs = -ofs; } decode_hex8(p, ofs); } /**************************************************************************** PARAMETERS: rm - RM value to decode RETURNS: Offset in memory for the address decoding REMARKS: Return the offset given by mod=00 addressing. Also enables the decoding of instructions. NOTE: The code which specifies the corresponding segment (ds vs ss) below in the case of [BP+..]. The assumption here is that at the point that this subroutine is called, the bit corresponding to _MODE_SEG_DS_SS will be zero. After every instruction except the segment override instructions, this bit (as well as any bits indicating segment overrides) will be clear. So if a SS access is needed, set this bit. Otherwise, DS access occurs (unless any of the segment override bits are set). ****************************************************************************/ u32 decode_rm_address(int mod, int rl) { switch(mod) { case 0: return decode_rm00_address(rl); break; case 1: return decode_rm01_address(rl); break; case 2: return decode_rm10_address(rl); break; default: INTR_RAISE_UD(&M); break; } return 0; } u32 decode_rm00_address(int rm) { u32 offset, base; int sib; if(MODE_ADDR32) { /* 32-bit addressing */ switch(rm) { case 0: SEGPREF_DECODE; OP_DECODE("eax]"); return M.x86.R_EAX; case 1: SEGPREF_DECODE; OP_DECODE("ecx]"); return M.x86.R_ECX; case 2: SEGPREF_DECODE; OP_DECODE("edx]"); return M.x86.R_EDX; case 3: SEGPREF_DECODE; OP_DECODE("ebx]"); return M.x86.R_EBX; case 4: sib = fetch_byte(); base = decode_sib_address(sib, 0); OP_DECODE("]"); return base; case 5: offset = fetch_long(); SEGPREF_DECODE; DECODE_HEX8(offset); OP_DECODE("]"); return offset; case 6: SEGPREF_DECODE; OP_DECODE("esi]"); return M.x86.R_ESI; case 7: SEGPREF_DECODE; OP_DECODE("edi]"); return M.x86.R_EDI; } } else { /* 16-bit addressing */ switch(rm) { case 0: SEGPREF_DECODE; OP_DECODE("bx+si]"); return (M.x86.R_BX + M.x86.R_SI) & 0xffff; case 1: SEGPREF_DECODE; OP_DECODE("bx+di]"); return (M.x86.R_BX + M.x86.R_DI) & 0xffff; case 2: SEGPREF_DECODE; OP_DECODE("bp+si]"); M.x86.mode |= _MODE_SEG_DS_SS; return (M.x86.R_BP + M.x86.R_SI) & 0xffff; case 3: SEGPREF_DECODE; OP_DECODE("bp+di]"); M.x86.mode |= _MODE_SEG_DS_SS; return (M.x86.R_BP + M.x86.R_DI) & 0xffff; case 4: SEGPREF_DECODE; OP_DECODE("si]"); return M.x86.R_SI; case 5: SEGPREF_DECODE; OP_DECODE("di]"); return M.x86.R_DI; case 6: offset = fetch_word(); SEGPREF_DECODE; DECODE_HEX4(offset); OP_DECODE("]"); return offset; case 7: SEGPREF_DECODE; OP_DECODE("bx]"); return M.x86.R_BX; } } return 0; } u32 decode_rm01_address(int rm) { s32 displacement = 0; u32 base; int sib; /* Fetch disp8 if no SIB byte */ if(!(MODE_ADDR32 && (rm == 4))) { displacement = (s8) fetch_byte(); } if(MODE_ADDR32) { /* 32-bit addressing */ switch(rm) { case 0: SEGPREF_DECODE; OP_DECODE("eax"); DECODE_HEX2S(displacement); OP_DECODE("]"); return M.x86.R_EAX + displacement; case 1: SEGPREF_DECODE; OP_DECODE("ecx"); DECODE_HEX2S(displacement); OP_DECODE("]"); return M.x86.R_ECX + displacement; case 2: SEGPREF_DECODE; OP_DECODE("edx"); DECODE_HEX2S(displacement); OP_DECODE("]"); return M.x86.R_EDX + displacement; case 3: SEGPREF_DECODE; OP_DECODE("ebx"); DECODE_HEX2S(displacement); OP_DECODE("]"); return M.x86.R_EBX + displacement; case 4: sib = fetch_byte(); base = decode_sib_address(sib, 1); displacement = (s8) fetch_byte(); DECODE_HEX2S(displacement); OP_DECODE("]"); return base + displacement; case 5: SEGPREF_DECODE; OP_DECODE("ebp"); DECODE_HEX2S(displacement); OP_DECODE("]"); return M.x86.R_EBP + displacement; case 6: SEGPREF_DECODE; OP_DECODE("esi"); DECODE_HEX2S(displacement); OP_DECODE("]"); return M.x86.R_ESI + displacement; case 7: SEGPREF_DECODE; OP_DECODE("edi"); DECODE_HEX2S(displacement); OP_DECODE("]"); return M.x86.R_EDI + displacement; } } else { /* 16-bit addressing */ switch(rm) { case 0: SEGPREF_DECODE; OP_DECODE("bx+si"); DECODE_HEX2S(displacement); OP_DECODE("]"); return (M.x86.R_BX + M.x86.R_SI + displacement) & 0xffff; case 1: SEGPREF_DECODE; OP_DECODE("bx+di"); DECODE_HEX2S(displacement); OP_DECODE("]"); return (M.x86.R_BX + M.x86.R_DI + displacement) & 0xffff; case 2: SEGPREF_DECODE; OP_DECODE("bp+si"); DECODE_HEX2S(displacement); OP_DECODE("]"); M.x86.mode |= _MODE_SEG_DS_SS; return (M.x86.R_BP + M.x86.R_SI + displacement) & 0xffff; case 3: SEGPREF_DECODE; OP_DECODE("bp+di"); DECODE_HEX2S(displacement); OP_DECODE("]"); M.x86.mode |= _MODE_SEG_DS_SS; return (M.x86.R_BP + M.x86.R_DI + displacement) & 0xffff; case 4: SEGPREF_DECODE; OP_DECODE("si"); DECODE_HEX2S(displacement); OP_DECODE("]"); return (M.x86.R_SI + displacement) & 0xffff; case 5: SEGPREF_DECODE; OP_DECODE("di"); DECODE_HEX2S(displacement); OP_DECODE("]"); return (M.x86.R_DI + displacement) & 0xffff; case 6: SEGPREF_DECODE; OP_DECODE("bp"); DECODE_HEX2S(displacement); OP_DECODE("]"); M.x86.mode |= _MODE_SEG_DS_SS; return (M.x86.R_BP + displacement) & 0xffff; case 7: SEGPREF_DECODE; OP_DECODE("bx"); DECODE_HEX2S(displacement); OP_DECODE("]"); return (M.x86.R_BX + displacement) & 0xffff; } } return 0; } u32 decode_rm10_address(int rm) { s32 displacement = 0; u32 base; int sib; /* Fetch disp16 if 16-bit addr mode */ if(!MODE_ADDR32) { displacement = (s16) fetch_word(); } else { /* Fetch disp32 if no SIB byte */ if(rm != 4) displacement = (s32) fetch_long(); } if(MODE_ADDR32) { /* 32-bit addressing */ switch(rm) { case 0: SEGPREF_DECODE; OP_DECODE("eax"); DECODE_HEX8S(displacement); OP_DECODE("]"); return M.x86.R_EAX + displacement; case 1: SEGPREF_DECODE; OP_DECODE("ecx"); DECODE_HEX8S(displacement); OP_DECODE("]"); return M.x86.R_ECX + displacement; case 2: SEGPREF_DECODE; OP_DECODE("edx"); DECODE_HEX8S(displacement); OP_DECODE("]"); return M.x86.R_EDX + displacement; case 3: SEGPREF_DECODE; OP_DECODE("ebx"); DECODE_HEX8S(displacement); OP_DECODE("]"); return M.x86.R_EBX + displacement; case 4: sib = fetch_byte(); base = decode_sib_address(sib, 2); displacement = (s32) fetch_long(); DECODE_HEX8S(displacement); OP_DECODE("]"); return base + displacement; break; case 5: SEGPREF_DECODE; OP_DECODE("ebp"); DECODE_HEX8S(displacement); OP_DECODE("]"); M.x86.mode |= _MODE_SEG_DS_SS; return M.x86.R_EBP + displacement; case 6: SEGPREF_DECODE; OP_DECODE("esi"); DECODE_HEX8S(displacement); OP_DECODE("]"); return M.x86.R_ESI + displacement; case 7: SEGPREF_DECODE; OP_DECODE("edi"); DECODE_HEX8S(displacement); OP_DECODE("]"); return M.x86.R_EDI + displacement; } } else { /* 16-bit addressing */ switch(rm) { case 0: SEGPREF_DECODE; OP_DECODE("bx+si"); DECODE_HEX4S(displacement); OP_DECODE("]"); return (M.x86.R_BX + M.x86.R_SI + displacement) & 0xffff; case 1: SEGPREF_DECODE; OP_DECODE("bx+di"); DECODE_HEX4S(displacement); OP_DECODE("]"); return (M.x86.R_BX + M.x86.R_DI + displacement) & 0xffff; case 2: SEGPREF_DECODE; OP_DECODE("bp+si"); DECODE_HEX4S(displacement); OP_DECODE("]"); M.x86.mode |= _MODE_SEG_DS_SS; return (M.x86.R_BP + M.x86.R_SI + displacement) & 0xffff; case 3: SEGPREF_DECODE; OP_DECODE("bp+di"); DECODE_HEX4S(displacement); OP_DECODE("]"); M.x86.mode |= _MODE_SEG_DS_SS; return (M.x86.R_BP + M.x86.R_DI + displacement) & 0xffff; case 4: SEGPREF_DECODE; OP_DECODE("si"); DECODE_HEX4S(displacement); OP_DECODE("]"); return (M.x86.R_SI + displacement) & 0xffff; case 5: SEGPREF_DECODE; OP_DECODE("di"); DECODE_HEX4S(displacement); OP_DECODE("]"); return (M.x86.R_DI + displacement) & 0xffff; case 6: SEGPREF_DECODE; OP_DECODE("bp"); DECODE_HEX4S(displacement); OP_DECODE("]"); M.x86.mode |= _MODE_SEG_DS_SS; return (M.x86.R_BP + displacement) & 0xffff; case 7: SEGPREF_DECODE; OP_DECODE("bx"); DECODE_HEX4S(displacement); OP_DECODE("]"); return (M.x86.R_BX + displacement) & 0xffff; } } return 0; } /* * * return offset from the SIB Byte */ u32 decode_sib_address(int sib, int mod) { u32 base = 0, i = 0, scale = 1; /* sib base */ switch(sib & 0x07) { case 0: SEGPREF_DECODE; OP_DECODE("eax"); base = M.x86.R_EAX; break; case 1: SEGPREF_DECODE; OP_DECODE("ecx"); base = M.x86.R_ECX; break; case 2: SEGPREF_DECODE; OP_DECODE("edx"); base = M.x86.R_EDX; break; case 3: SEGPREF_DECODE; OP_DECODE("ebx"); base = M.x86.R_EBX; break; case 4: SEGPREF_DECODE; OP_DECODE("esp"); base = M.x86.R_ESP; M.x86.mode |= _MODE_SEG_DS_SS; break; case 5: SEGPREF_DECODE; if(mod == 0) { base = fetch_long(); DECODE_HEX8(base); } else { OP_DECODE("ebp"); base = M.x86.R_EBP; M.x86.mode |= _MODE_SEG_DS_SS; } break; case 6: SEGPREF_DECODE; OP_DECODE("esi"); base = M.x86.R_ESI; break; case 7: SEGPREF_DECODE; OP_DECODE("edi"); base = M.x86.R_EDI; break; } /* sib index */ switch((sib >> 3) & 0x07) { case 0: OP_DECODE("+eax"); i = M.x86.R_EAX; break; case 1: OP_DECODE("+ecx"); i = M.x86.R_ECX; break; case 2: OP_DECODE("+edx"); i = M.x86.R_EDX; break; case 3: OP_DECODE("+ebx"); i = M.x86.R_EBX; break; case 4: i = 0; break; case 5: OP_DECODE("+ebp"); i = M.x86.R_EBP; break; case 6: OP_DECODE("+esi"); i = M.x86.R_ESI; break; case 7: OP_DECODE("+edi"); i = M.x86.R_EDI; break; } scale = (sib >> 6) & 0x03; if(((sib >> 3) & 0x07) != 4) { if(scale) { OP_DECODE("*"); *M.x86.disasm_ptr++ = '0' + (1 << scale); } } return base + (i << scale); } void log_code() { unsigned u, lf; char **p = &M.log.ptr; if(!(M.log.trace & X86EMU_TRACE_CODE) || !*p) return; lf = LOG_FREE(&M); if(lf < 512) lf = x86emu_clear_log(&M, 1); if(lf < 512) return; decode_hex(p, M.x86.R_TSC); #if WITH_TSC if(M.log.trace & X86EMU_TRACE_TIME) { LOG_STR(" +"); decode_hex(p, M.x86.R_REAL_TSC - M.x86.R_LAST_REAL_TSC); } #endif LOG_STR(" "); decode_hex4(p, M.x86.saved_cs); LOG_STR(":"); MODE_CODE32 ? decode_hex8(p, M.x86.saved_eip) : decode_hex4(p, M.x86.saved_eip); LOG_STR(" "); for(u = 0; u < M.x86.instr_len; u++) { decode_hex2(p, M.x86.instr_buf[u]); } while(u++ < 12) { LOG_STR(" "); } LOG_STR(" "); u = M.x86.disasm_ptr - M.x86.disasm_buf; memcpy(*p, M.x86.disasm_buf, u); *p += u; LOG_STR("\n"); **p = 0; } void log_regs() { char **p = &M.log.ptr; unsigned lf; if(!(M.log.trace & X86EMU_TRACE_REGS) || !*p) return; lf = LOG_FREE(&M); if(lf < 512) lf = x86emu_clear_log(&M, 1); if(lf < 512) return; LOG_STR("\neax "); decode_hex8(p, M.x86.R_EAX); LOG_STR(", ebx "); decode_hex8(p, M.x86.R_EBX); LOG_STR(", ecx "); decode_hex8(p, M.x86.R_ECX); LOG_STR(", edx "); decode_hex8(p, M.x86.R_EDX); LOG_STR("\nesi "); decode_hex8(p, M.x86.R_ESI); LOG_STR(", edi "); decode_hex8(p, M.x86.R_EDI); LOG_STR(", ebp "); decode_hex8(p, M.x86.R_EBP); LOG_STR(", esp "); decode_hex8(p, M.x86.R_ESP); LOG_STR("\ncs "); decode_hex4(p, M.x86.R_CS); LOG_STR(", ss "); decode_hex4(p, M.x86.R_SS); LOG_STR(", ds "); decode_hex4(p, M.x86.R_DS); LOG_STR(", es "); decode_hex4(p, M.x86.R_ES); LOG_STR(", fs "); decode_hex4(p, M.x86.R_FS); LOG_STR(", gs "); decode_hex4(p, M.x86.R_GS); LOG_STR("\neip "); decode_hex8(p, M.x86.R_EIP); LOG_STR(", eflags "); decode_hex8(p, M.x86.R_EFLG); if(ACCESS_FLAG(F_OF)) LOG_STR(" of"); if(ACCESS_FLAG(F_DF)) LOG_STR(" df"); if(ACCESS_FLAG(F_IF)) LOG_STR(" if"); if(ACCESS_FLAG(F_SF)) LOG_STR(" sf"); if(ACCESS_FLAG(F_ZF)) LOG_STR(" zf"); if(ACCESS_FLAG(F_AF)) LOG_STR(" af"); if(ACCESS_FLAG(F_PF)) LOG_STR(" pf"); if(ACCESS_FLAG(F_CF)) LOG_STR(" cf"); LOG_STR("\n"); **p = 0; } void check_data_access(sel_t *seg, u32 ofs, u32 size) { char **p = &M.log.ptr; static char seg_name[7] = "ecsdfg?"; unsigned idx = seg - M.x86.seg, lf; if((M.log.trace & X86EMU_TRACE_ACC) && *p) { lf = LOG_FREE(&M); if(lf < 512) lf = x86emu_clear_log(&M, 1); if(lf >= 512) { LOG_STR("a ["); switch(size) { case 1: LOG_STR("byte "); break; case 2: LOG_STR("word "); break; case 4: LOG_STR("dword "); break; } if(idx > 6) idx = 6; *(*p)++ = seg_name[idx]; LOG_STR("s:"); decode_hex8(p, ofs); LOG_STR("]\n"); **p = 0; } } if(ofs + size - 1 > seg->limit) { INTR_RAISE_GP(&M, seg->sel); } return; } void decode_descriptor(descr_t *d, u32 dl, u32 dh) { char **p = &M.log.ptr; unsigned lf, acc; memset(d, 0, sizeof *d); d->acc = acc = ((dh >> 8) & 0xff) + ((dh >> 12) & 0xf00); d->base = ((dl >> 16) & 0xffff) + ((dh & 0xff) << 16) + (dh & 0xff000000); d->limit = (dl & 0xffff) + (dh & 0xf0000); if(ACC_G(acc)) d->limit = (d->limit << 12) + 0xfff; d->g = ACC_G(acc); d->p = ACC_P(acc); d->dpl = ACC_DPL(acc); if(ACC_S(acc)) { d->seg = 1; d->is_i386 = ACC_D(acc); d->a = ACC_A(acc); if(ACC_E(acc)) { // code d->x = 1; d->c = ACC_C(acc); d->r = ACC_R(acc); } else { // data d->r = 1; d->ed = ACC_ED(acc); d->w = ACC_W(acc); } } else { if(acc & 8) d->is_i386 = 1; switch(acc & 7) { case 0: d->invalid = 1; break; case 3: // tss busy d->busy = 1; case 1: // tss avail d->tss = 1; break; case 2: d->ldt = 1; break; case 4: d->c_gate = 1; break; case 5: d->t_gate = 1; break; case 7: d->trap = 1; case 6: d->i_gate = 1; break; } if(d->c_gate || d->i_gate || d->t_gate) { d->offset = (dl & 0xffff) + (dh & 0xffff0000); d->sel = dl >> 16; d->w_count = dh & 0x1f; } } if((M.log.trace & X86EMU_TRACE_ACC) && *p) { lf = LOG_FREE(&M); if(lf < 512) lf = x86emu_clear_log(&M, 1); if(lf >= 512) { LOG_STR("d ["); decode_hex8(p, dh); LOG_STR(" "); decode_hex8(p, dl); LOG_STR("] ="); if(d->seg) { LOG_STR(" base="); decode_hex8(p, d->base); LOG_STR(" limit="); decode_hex8(p, d->limit); } else { LOG_STR(" sel="); decode_hex4(p, d->sel); LOG_STR(" ofs="); decode_hex8(p, d->offset); LOG_STR(" wcnt="); decode_hex2(p, d->w_count); } LOG_STR(" dpl="); decode_hex1(p, d->dpl); if(d->p) LOG_STR(" p"); if(d->a) LOG_STR(" a"); if(d->r) LOG_STR(" r"); if(d->w) LOG_STR(" w"); if(d->x) LOG_STR(" x"); if(d->c) LOG_STR(" c"); if(d->ed) LOG_STR(" ed"); if(d->g) LOG_STR(" g"); if(d->is_i386) LOG_STR(" 32"); if(d->ldt) LOG_STR(" ldt"); if(d->tss) LOG_STR(" tss"); if(d->busy) LOG_STR(" busy"); if(d->c_gate) LOG_STR(" callgate"); if(d->i_gate) LOG_STR(" intgate"); if(d->t_gate) LOG_STR(" taskgate"); if(d->trap) LOG_STR(" trap"); if(d->invalid) LOG_STR(" invalid"); LOG_STR("\n"); **p = 0; } } } void x86emu_set_seg_register(x86emu_t *emu, sel_t *seg, u16 val) { int err = 1; unsigned ofs; u32 dl, dh, dt_base, dt_limit; descr_t d; if(MODE_REAL(emu)) { seg->sel = val; seg->base = val << 4; err = 0; } else { ofs = val & ~7; if(val & 4) { dt_base = emu->x86.R_LDT_BASE; dt_limit = emu->x86.R_LDT_LIMIT; } else { dt_base = emu->x86.R_GDT_BASE; dt_limit = emu->x86.R_GDT_LIMIT; } if(ofs == 0) { seg->sel = 0; seg->base = 0; seg->limit = 0; seg->acc = 0; err = 0; } else if(ofs + 7 <= dt_limit) { err = emu_memio(emu, dt_base + ofs, &dl, X86EMU_MEMIO_32 + X86EMU_MEMIO_R) | emu_memio(emu, dt_base + ofs + 4, &dh, X86EMU_MEMIO_32 + X86EMU_MEMIO_R); if(!err) { decode_descriptor(&d, dl, dh); if(!d.invalid && d.p && d.seg) { seg->sel = val; seg->base = d.base; seg->limit = d.limit; seg->acc = d.acc; } else { err = 1; } } } } if(err) INTR_RAISE_GP(emu, val); } void idt_lookup(u8 nr, u32 *new_cs, u32 *new_eip) { unsigned err, ofs; u32 dl, dh; descr_t d1; if(MODE_REAL(&M)) { ofs = nr << 2; err = decode_memio(M.x86.R_IDT_BASE + ofs, new_eip, X86EMU_MEMIO_16 + X86EMU_MEMIO_R) | decode_memio(M.x86.R_IDT_BASE + ofs + 2, new_cs, X86EMU_MEMIO_16 + X86EMU_MEMIO_R); } else { ofs = nr << 3; if(ofs + 7 <= M.x86.R_IDT_LIMIT) { err = decode_memio(M.x86.R_IDT_BASE + ofs, &dl, X86EMU_MEMIO_32 + X86EMU_MEMIO_R) | decode_memio(M.x86.R_IDT_BASE + ofs + 4, &dh, X86EMU_MEMIO_32 + X86EMU_MEMIO_R); } else { err = 1; } if(!err) { decode_descriptor(&d1, dl, dh); if(!d1.invalid && d1.p && d1.i_gate) { *new_cs = d1.sel; *new_eip = d1.offset; } } } } void generate_int(u8 nr, unsigned type, unsigned errcode) { u32 cs, eip, new_cs, new_eip; int i; M.x86.intr_stats[nr]++; i = M.intr ? (*M.intr)(&M, nr, type) : 0; if(!i) { if(type & INTR_MODE_RESTART) { eip = M.x86.saved_eip; cs = M.x86.saved_cs; } else { eip = M.x86.R_EIP; cs = M.x86.R_CS; } new_cs = cs; new_eip = eip; idt_lookup(nr, &new_cs, &new_eip); if(MODE_PROTECTED(&M) && MODE_CODE32) { push_long(M.x86.R_EFLG); push_long(cs); push_long(eip); } else { push_word(M.x86.R_FLG); push_word(cs); push_word(eip); } if(type & INTR_MODE_ERRCODE) push_long(errcode); CLEAR_FLAG(F_IF); CLEAR_FLAG(F_TF); x86emu_set_seg_register(&M, M.x86.R_CS_SEL, new_cs); M.x86.R_EIP = new_eip; } } unsigned decode_memio(u32 addr, u32 *val, unsigned type) { unsigned err, bits = type & 0xff, lf; char **p = &M.log.ptr; err = M.memio(&M, addr, val, type); type &= ~0xff; if(!*p || !((M.log.trace & X86EMU_TRACE_DATA) || (M.log.trace & X86EMU_TRACE_IO))) return err; if( !((M.log.trace & X86EMU_TRACE_IO) && (type == X86EMU_MEMIO_I || type == X86EMU_MEMIO_O)) && !((M.log.trace & X86EMU_TRACE_DATA) && (type == X86EMU_MEMIO_R || type == X86EMU_MEMIO_W || X86EMU_MEMIO_X)) ) return err; lf = LOG_FREE(&M); if(lf < 1024) lf = x86emu_clear_log(&M, 1); if(lf < 1024) return err; switch(type) { case X86EMU_MEMIO_R: LOG_STR("r ["); break; case X86EMU_MEMIO_W: LOG_STR("w ["); break; case X86EMU_MEMIO_X: LOG_STR("x ["); break; case X86EMU_MEMIO_I: LOG_STR("i ["); break; case X86EMU_MEMIO_O: LOG_STR("o ["); break; } decode_hex8(p, addr); LOG_STR("] = "); switch(bits) { case X86EMU_MEMIO_8: if(err) { LOG_STR("??"); } else { decode_hex2(p, *val); } break; case X86EMU_MEMIO_16: if(err) { LOG_STR("????"); } else { decode_hex4(p, *val); } break; case X86EMU_MEMIO_32: if(err) { LOG_STR("????????"); } else { decode_hex8(p, *val); } break; } LOG_STR("\n"); **p = 0; return err; } unsigned emu_memio(x86emu_t *emu, u32 addr, u32 *val, unsigned type) { unsigned err, bits = type & 0xff, lf; char **p = &emu->log.ptr; err = emu->memio(emu, addr, val, type); type &= ~0xff; if(!*p || !((emu->log.trace & X86EMU_TRACE_DATA) || (emu->log.trace & X86EMU_TRACE_IO))) return err; if( !((emu->log.trace & X86EMU_TRACE_IO) && (type == X86EMU_MEMIO_I || type == X86EMU_MEMIO_O)) && !((emu->log.trace & X86EMU_TRACE_DATA) && (type == X86EMU_MEMIO_R || type == X86EMU_MEMIO_W || X86EMU_MEMIO_X)) ) return err; lf = LOG_FREE(emu); if(lf < 1024) lf = x86emu_clear_log(emu, 1); if(lf < 1024) return err; switch(type) { case X86EMU_MEMIO_R: LOG_STR("r ["); break; case X86EMU_MEMIO_W: LOG_STR("w ["); break; case X86EMU_MEMIO_X: LOG_STR("x ["); break; case X86EMU_MEMIO_I: LOG_STR("i ["); break; case X86EMU_MEMIO_O: LOG_STR("o ["); break; } decode_hex8(p, addr); LOG_STR("] = "); switch(bits) { case X86EMU_MEMIO_8: if(err) { LOG_STR("??"); } else { decode_hex2(p, *val); } break; case X86EMU_MEMIO_16: if(err) { LOG_STR("????"); } else { decode_hex4(p, *val); } break; case X86EMU_MEMIO_32: if(err) { LOG_STR("????????"); } else { decode_hex8(p, *val); } break; } LOG_STR("\n"); **p = 0; return err; } void emu_process_debug(unsigned start, unsigned len) { unsigned lf, type, u; char **p = &M.log.ptr; if(!*p) return; lf = LOG_FREE(&M); if(lf < 1024) lf = x86emu_clear_log(&M, 1); if(lf < 1024) return; type = x86emu_read_byte_noperm(&M, start++); len--; switch(type) { case 1: LOG_STR("\n"); while(len--) { *(*p)++ = x86emu_read_byte_noperm(&M, start++); } LOG_STR("\n"); break; case 2: u = x86emu_read_byte_noperm(&M, start++); u += x86emu_read_byte_noperm(&M, start++) << 8; u += x86emu_read_byte_noperm(&M, start++) << 16; u += x86emu_read_byte_noperm(&M, start++) << 24; M.log.trace |= u; break; case 3: u = x86emu_read_byte_noperm(&M, start++); u += x86emu_read_byte_noperm(&M, start++) << 8; u += x86emu_read_byte_noperm(&M, start++) << 16; u += x86emu_read_byte_noperm(&M, start++) << 24; M.log.trace &= ~u; break; case 4: u = x86emu_read_byte_noperm(&M, start++); u += x86emu_read_byte_noperm(&M, start++) << 8; u += x86emu_read_byte_noperm(&M, start++) << 16; u += x86emu_read_byte_noperm(&M, start++) << 24; x86emu_dump(&M, u); break; case 5: x86emu_reset_access_stats(&M); break; } **p = 0; } libx86emu-1.5/git2log000077500000000000000000000130131247503741400145040ustar00rootroot00000000000000#! /usr/bin/perl use strict; use Getopt::Long; use Data::Dumper; $Data::Dumper::Sortkeys = 1; $Data::Dumper::Terse = 1; $Data::Dumper::Indent = 1; sub usage; sub get_branch_tags; sub get_branch; sub get_parent_branch; sub get_version; usage 0 if !@ARGV; my @deps = qw ( .git/HEAD .git/refs/heads .git/refs/tags ); my $branch; my $current_version; my @tags; my @all_tags; my $opt_log; my $opt_version; my $opt_branch; my $opt_update; my $opt_file; GetOptions( 'help' => sub { usage 0 }, 'version' => \$opt_version, 'branch' => \$opt_branch, 'update' => \$opt_update, 'log|changelog' => \$opt_log, ) || usage 1; usage 1 if @ARGV > 1 || !($opt_log || $opt_version || $opt_branch); $opt_file = @ARGV ? shift : '-'; die "no git repo\n" unless -d ".git"; if($opt_update && $opt_file ne '-' && -f($opt_file)) { my $ok = 1; my $t = (stat $opt_file)[9]; for (@deps) { $ok = 0 if (stat)[9] > $t; } exit 0 if $ok; } @all_tags = `git tag`; chomp @all_tags; $branch = get_branch; die "no branch?\n" unless $branch; @tags = get_branch_tags; die "no tags at all?\n" unless @tags; if($branch ne 'master') { if(!grep { /^$branch\-/ } @tags) { $branch = get_parent_branch; die "sorry, can't determine branch\n" unless $branch; @tags = get_branch_tags; die "no tags at all?\n" unless @tags; } } else { @tags = get_branch_tags; die "no tags at all?\n" unless @tags; } if($opt_branch) { open my $f, ">$opt_file"; print $f "$branch\n"; close $f; exit 0; } $current_version = get_version; if($opt_version) { open my $f, ">$opt_file"; print $f "$current_version\n"; close $f; exit 0; } if($branch ne 'master') { my ($i1, $i2, $bi); for (my $i = 0; $i < @tags; $i++) { if($tags[$i] =~ /^$branch\-(\S+)/) { $i2 = $i; $bi = $1; last; } } # print STDERR ">> $branch-$bi\n"; warn "no tags in this branch yet\n" unless $bi; for (my $i = 0; $i < $i2; $i++) { if($tags[$i] ge $bi) { if($tags[$i] eq $bi) { $i1 = $i; } elsif($i > 0) { $i1 = $i - 1; } last; } } splice @tags, $i1, $i2 - $i1; } map { s/(\d+)/$1 + 0/eg } @tags; push @tags, "HEAD"; # print Dumper(\@tags); open F, ">$opt_file"; for (my $i = @tags - 1; $i > 0; $i--) { my ($date, @t2); my @t = `git log --pretty=medium --date=iso '$tags[$i-1]..$tags[$i]'`; # print "\n--- $tags[$i-1]..$tags[$i] ---\n", @t, "---\n"; my $merge = 0; for (@t) { $merge = 1 if /^Merge: /; $merge = 0 if /^commit /; push @t2, $_ if !$merge; } @t = @t2; undef @t2; my $detail = 0; for (@t) { $detail = 1 if /^ $/; $detail = 2 if /^ Conflicts:$/; $detail = 0 if /^commit /; if(!$detail || !/^ [^\-\s]/) { push @t2, $_ if $detail < 2; } } @t = @t2; # print "\n--- $tags[$i-1]..$tags[$i] ---\n", @t; chomp @t; for (@t) { if(/^Date:\s*(\S+)/) { $date = $1; last; } } # handle white space in every first line once and for all my $empty = 1; for (@t) { $empty = 1, $_ = "", next if $_ =~ /^\s*$/; next if !$empty; s/^\s*//; $empty = 0; } @t = grep { !/^(commit|Author:|Date:|Merge:|\s*$)|created.*tag/ } @t; if(@t) { # rewrite a bit to have it look more consistent map { s/(fate|bnc|bsc)#/$1 #/g } @t; map { s/(fate|bnc|bsc)\s*(\d{4})/$1 #$2/g } @t; map { s/\(#/(bnc #/g } @t; map { s/bug\s*#/bnc #/g } @t; map { s/feat(\.|ure)?\s*#?(\d+)/fate #$2/g } @t; map { s/^ {4}// } @t; map { s/^ {8}// } @t; map { s/^ +/ / } @t; map { s/^\s*[+\-][\-\s]*/- / } @t; map { s/^([^ \-])/- $1/ } @t; map { s/^/\t/ } @t; map { s/\\'/'/ } @t; # print "\n--- $tags[$i-1]..$tags[$i] ---\n", join("\n", @t); my $t = $tags[$i]; $t = "${branch}-$t" if $branch ne 'master' && $t eq "HEAD"; $t =~ s/HEAD/$current_version/; print F "$date:\t$t\n"; print F join("\n", @t), "\n\n"; } } close F; # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - sub usage { my $err = shift; print <<" usage"; Usage: git2log [OPTIONS] [FILE] Create changelog and project version from git repo. --changelog Write changelog to FILE. --version Write version number to FILE. --branch Write current branch to FILE. --update Write changelog or version only if FILE is outdated. --help Print this help text. usage exit $err; } # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - sub get_branch_tags { my @ntags; for (@all_tags) { if(/^\d/) { s/(\d+)/sprintf "%04d", $1/eg; push @ntags, $_; } elsif(s/^$branch\-//) { s/(\d+)/sprintf "%04d", $1/eg; push @ntags, "$branch-$_"; } } return sort @ntags; } # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - sub get_branch { my $b; for (`git branch`) { if(/^\*\s+(\S+)/) { $b = $1; last; } } $b = "master" if $b eq '(no'; return $b; } # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - sub get_parent_branch { my $p; for (`git log -g --pretty=oneline`) { $p = $1 if /checkout: moving from (\S+) to $branch/; } # print "parent = $p\n"; return $p || "master"; } # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - sub get_version { my $v = $tags[-1]; $v =~ s/(\d+)/$1 + 0/eg; if(`git log --pretty=medium --date=iso '$v..HEAD'`) { $v =~ s/(\d+)$/$1 + 1/e; } $v =~ s/^$branch\-//; return $v; } libx86emu-1.5/include/000077500000000000000000000000001247503741400146345ustar00rootroot00000000000000libx86emu-1.5/include/decode.h000066400000000000000000000113561247503741400162360ustar00rootroot00000000000000/**************************************************************************** * * Realmode X86 Emulator Library * * Copyright (C) 1996-1999 SciTech Software, Inc. * Copyright (C) David Mosberger-Tang * 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. * * ======================================================================== * * Language: ANSI C * Environment: Any * Developer: Kendall Bennett * * Description: Header file for instruction decoding logic. * ****************************************************************************/ #ifndef __X86EMU_DECODE_H #define __X86EMU_DECODE_H /*---------------------- Macros and type definitions ----------------------*/ /* Instruction Decoding */ #define OP_DECODE(a) \ memcpy(M.x86.disasm_ptr, a, sizeof a - 1), \ M.x86.disasm_ptr += sizeof a - 1 #define SEGPREF_DECODE \ memcpy(M.x86.disasm_ptr, M.x86.decode_seg, 4), \ M.x86.disasm_ptr += M.x86.default_seg ? 4 : 1 #define DECODE_HEX1(ofs) decode_hex1(&M.x86.disasm_ptr, ofs) #define DECODE_HEX2(ofs) decode_hex2(&M.x86.disasm_ptr, ofs) #define DECODE_HEX4(ofs) decode_hex4(&M.x86.disasm_ptr, ofs) #define DECODE_HEX8(ofs) decode_hex8(&M.x86.disasm_ptr, ofs) #define DECODE_HEX2S(ofs) decode_hex2s(&M.x86.disasm_ptr, ofs) #define DECODE_HEX4S(ofs) decode_hex4s(&M.x86.disasm_ptr, ofs) #define DECODE_HEX8S(ofs) decode_hex8s(&M.x86.disasm_ptr, ofs) #define DECODE_HEX_ADDR(ofs) decode_hex_addr(&M.x86.disasm_ptr, ofs) /*-------------------------- Function Prototypes --------------------------*/ #ifdef __cplusplus extern "C" { /* Use "C" linkage when in C++ mode */ #endif void fetch_decode_modrm(int *mod, int *regh, int *regl) L_SYM; u8 fetch_byte(void) L_SYM; u16 fetch_word(void) L_SYM; u32 fetch_long(void) L_SYM; u8 fetch_data_byte(u32 offset) L_SYM; u8 fetch_data_byte_abs(sel_t *seg, u32 offset) L_SYM; u16 fetch_data_word(u32 offset) L_SYM; u16 fetch_data_word_abs(sel_t *seg, u32 offset) L_SYM; u32 fetch_data_long(u32 offset) L_SYM; u32 fetch_data_long_abs(sel_t *seg, u32 offset) L_SYM; void store_data_byte(u32 offset, u8 val) L_SYM; void store_data_byte_abs(sel_t *seg, u32 offset, u8 val) L_SYM; void store_data_word(u32 offset, u16 val) L_SYM; void store_data_word_abs(sel_t *seg, u32 offset, u16 val) L_SYM; void store_data_long(u32 offset, u32 val) L_SYM; void store_data_long_abs(sel_t *seg, u32 offset, u32 val) L_SYM; u8 fetch_io_byte(u32 offset) L_SYM; u16 fetch_io_word(u32 offset) L_SYM; u32 fetch_io_long(u32 offset) L_SYM; void store_io_byte(u32 port, u8 val) L_SYM; void store_io_word(u32 port, u16 val) L_SYM; void store_io_long(u32 port, u32 val) L_SYM; u8* decode_rm_byte_register(int reg) L_SYM; u16* decode_rm_word_register(int reg) L_SYM; u32* decode_rm_long_register(int reg) L_SYM; sel_t *decode_rm_seg_register(int reg) L_SYM; u32 decode_rm00_address(int rm) L_SYM; u32 decode_rm01_address(int rm) L_SYM; u32 decode_rm10_address(int rm) L_SYM; u32 decode_sib_address(int sib, int mod) L_SYM; u32 decode_rm_address(int mod, int rl) L_SYM; void decode_hex(char **p, u32 ofs) L_SYM; void decode_hex1(char **p, u32 ofs) L_SYM; void decode_hex2(char **p, u32 ofs) L_SYM; void decode_hex4(char **p, u32 ofs) L_SYM; void decode_hex8(char **p, u32 ofs) L_SYM; void decode_hex_addr(char **p, u32 ofs) L_SYM; void decode_hex2s(char **p, s32 ofs) L_SYM; void decode_hex4s(char **p, s32 ofs) L_SYM; void decode_hex8s(char **p, s32 ofs) L_SYM; void decode_descriptor(descr_t *d, u32 dl, u32 dh); void emu_process_debug(unsigned start, unsigned len) L_SYM; #ifdef __cplusplus } /* End of "C" linkage for C++ */ #endif #endif /* __X86EMU_DECODE_H */ libx86emu-1.5/include/mem.h000066400000000000000000000004271247503741400155660ustar00rootroot00000000000000unsigned vm_memio(x86emu_t *emu, u32 addr, u32 *val, unsigned type) L_SYM; x86emu_mem_t *emu_mem_new(unsigned perm) L_SYM; x86emu_mem_t *emu_mem_free(x86emu_mem_t *mem) L_SYM; x86emu_mem_t *emu_mem_clone(x86emu_mem_t *mem) L_SYM; void *mem_dup(const void *src, size_t n) L_SYM; libx86emu-1.5/include/ops.h000066400000000000000000000036311247503741400156110ustar00rootroot00000000000000/**************************************************************************** * * Realmode X86 Emulator Library * * Copyright (C) 1996-1999 SciTech Software, Inc. * Copyright (C) David Mosberger-Tang * 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. * * ======================================================================== * * Language: ANSI C * Environment: Any * Developer: Kendall Bennett * * Description: Header file for operand decoding functions. * ****************************************************************************/ #ifndef __X86EMU_OPS_H #define __X86EMU_OPS_H void (*x86emu_optab[0x100])(u8 op1) L_SYM; void (*x86emu_optab2[0x100])(u8 op2) L_SYM; void decode_cond(int type) L_SYM; #endif /* __X86EMU_OPS_H */ libx86emu-1.5/include/prim_ops.h000066400000000000000000000123101247503741400166320ustar00rootroot00000000000000/**************************************************************************** * * Realmode X86 Emulator Library * * Copyright (C) 1996-1999 SciTech Software, Inc. * Copyright (C) David Mosberger-Tang * 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. * * ======================================================================== * * Language: ANSI C * Environment: Any * Developer: Kendall Bennett * * Description: Header file for primitive operation functions. * ****************************************************************************/ #ifndef __X86EMU_PRIM_OPS_H #define __X86EMU_PRIM_OPS_H #ifdef __cplusplus extern "C" { /* Use "C" linkage when in C++ mode */ #endif u16 aaa_word (u16 d) L_SYM; u16 aas_word (u16 d) L_SYM; u16 aad_word (u16 d, u8 base) L_SYM; u16 aam_word (u8 d, u8 base) L_SYM; u8 adc_byte (u8 d, u8 s) L_SYM; u16 adc_word (u16 d, u16 s) L_SYM; u32 adc_long (u32 d, u32 s) L_SYM; u8 add_byte (u8 d, u8 s) L_SYM; u16 add_word (u16 d, u16 s) L_SYM; u32 add_long (u32 d, u32 s) L_SYM; u8 and_byte (u8 d, u8 s) L_SYM; u16 and_word (u16 d, u16 s) L_SYM; u32 and_long (u32 d, u32 s) L_SYM; u8 cmp_byte (u8 d, u8 s) L_SYM; u16 cmp_word (u16 d, u16 s) L_SYM; u32 cmp_long (u32 d, u32 s) L_SYM; u8 daa_byte (u8 d) L_SYM; u8 das_byte (u8 d) L_SYM; u8 dec_byte (u8 d) L_SYM; u16 dec_word (u16 d) L_SYM; u32 dec_long (u32 d) L_SYM; u8 inc_byte (u8 d) L_SYM; u16 inc_word (u16 d) L_SYM; u32 inc_long (u32 d) L_SYM; u8 or_byte (u8 d, u8 s) L_SYM; u16 or_word (u16 d, u16 s) L_SYM; u32 or_long (u32 d, u32 s) L_SYM; u8 neg_byte (u8 s) L_SYM; u16 neg_word (u16 s) L_SYM; u32 neg_long (u32 s) L_SYM; u8 not_byte (u8 s) L_SYM; u16 not_word (u16 s) L_SYM; u32 not_long (u32 s) L_SYM; u8 rcl_byte (u8 d, u8 s) L_SYM; u16 rcl_word (u16 d, u8 s) L_SYM; u32 rcl_long (u32 d, u8 s) L_SYM; u8 rcr_byte (u8 d, u8 s) L_SYM; u16 rcr_word (u16 d, u8 s) L_SYM; u32 rcr_long (u32 d, u8 s) L_SYM; u8 rol_byte (u8 d, u8 s) L_SYM; u16 rol_word (u16 d, u8 s) L_SYM; u32 rol_long (u32 d, u8 s) L_SYM; u8 ror_byte (u8 d, u8 s) L_SYM; u16 ror_word (u16 d, u8 s) L_SYM; u32 ror_long (u32 d, u8 s) L_SYM; u8 shl_byte (u8 d, u8 s) L_SYM; u16 shl_word (u16 d, u8 s) L_SYM; u32 shl_long (u32 d, u8 s) L_SYM; u8 shr_byte (u8 d, u8 s) L_SYM; u16 shr_word (u16 d, u8 s) L_SYM; u32 shr_long (u32 d, u8 s) L_SYM; u8 sar_byte (u8 d, u8 s) L_SYM; u16 sar_word (u16 d, u8 s) L_SYM; u32 sar_long (u32 d, u8 s) L_SYM; u16 shld_word (u16 d, u16 fill, u8 s) L_SYM; u32 shld_long (u32 d, u32 fill, u8 s) L_SYM; u16 shrd_word (u16 d, u16 fill, u8 s) L_SYM; u32 shrd_long (u32 d, u32 fill, u8 s) L_SYM; u8 sbb_byte (u8 d, u8 s) L_SYM; u16 sbb_word (u16 d, u16 s) L_SYM; u32 sbb_long (u32 d, u32 s) L_SYM; u8 sub_byte (u8 d, u8 s) L_SYM; u16 sub_word (u16 d, u16 s) L_SYM; u32 sub_long (u32 d, u32 s) L_SYM; void test_byte (u8 d, u8 s) L_SYM; void test_word (u16 d, u16 s) L_SYM; void test_long (u32 d, u32 s) L_SYM; u8 xor_byte (u8 d, u8 s) L_SYM; u16 xor_word (u16 d, u16 s) L_SYM; u32 xor_long (u32 d, u32 s) L_SYM; void imul_byte (u8 s) L_SYM; void imul_word (u16 s) L_SYM; void imul_long (u32 s) L_SYM; void imul_long_direct(u32 *res_lo, u32* res_hi, u32 d, u32 s) L_SYM; void mul_byte (u8 s) L_SYM; void mul_word (u16 s) L_SYM; void mul_long (u32 s) L_SYM; void idiv_byte (u8 s) L_SYM; void idiv_word (u16 s) L_SYM; void idiv_long (u32 s) L_SYM; void div_byte (u8 s) L_SYM; void div_word (u16 s) L_SYM; void div_long (u32 s) L_SYM; void ins (int size) L_SYM; void outs (int size) L_SYM; void push_word (u16 w) L_SYM; void push_long (u32 w) L_SYM; u16 pop_word (void) L_SYM; u32 pop_long (void) L_SYM; int eval_condition(unsigned type) L_SYM; #ifdef __cplusplus } /* End of "C" linkage for C++ */ #endif #endif /* __X86EMU_PRIM_OPS_H */ libx86emu-1.5/include/x86emu.h000066400000000000000000000414351247503741400161500ustar00rootroot00000000000000/**************************************************************************** * * Realmode X86 Emulator Library * * Copyright (C) 1996-1999 SciTech Software, Inc. * Copyright (C) David Mosberger-Tang * 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. * * ======================================================================== * * Language: ANSI C * Environment: Any * Developer: Kendall Bennett * * Description: Header file for public specific functions. * Any application linking against us should only * include this header * ****************************************************************************/ #ifndef __X86EMU_X86EMU_H #define __X86EMU_X86EMU_H #ifdef __cplusplus extern "C" { /* Use "C" linkage when in C++ mode */ #endif #include /*---------------------- Macros and type definitions ----------------------*/ #define u8 uint8_t #define u16 uint16_t #define u32 uint32_t #define u64 uint64_t #define s8 int8_t #define s16 int16_t #define s32 int32_t #define s64 int64_t /* * 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__ typedef struct { u32 e_reg; } I32_reg_t; typedef struct { u16 filler0, x_reg; } I16_reg_t; typedef struct { u8 filler0, filler1, h_reg, l_reg; } I8_reg_t; #else /* !__BIG_ENDIAN__ */ typedef struct { u32 e_reg; } I32_reg_t; typedef struct { u16 x_reg; } I16_reg_t; typedef struct { u8 l_reg, h_reg; } I8_reg_t; #endif /* BIG_ENDIAN */ typedef union { I32_reg_t I32_reg; I16_reg_t I16_reg; I8_reg_t I8_reg; } i386_general_register; struct i386_general_regs { i386_general_register A, B, C, D; }; struct i386_special_regs { i386_general_register SP, BP, SI, DI, IP; u32 FLAGS; }; typedef struct { union { u32 base; // segment base u32 offset; // gate offset }; union { u32 limit; // segment limit struct { u16 sel; // gate selector u16 w_count; // gate (d)word count }; }; u16 acc; // access flags (12 bits) unsigned invalid:1; // invalid descriptor type unsigned seg:1; // is segment unsigned dpl:2; unsigned r:1; // readable seg unsigned w:1; // writable seg unsigned x:1; // executable seg unsigned c:1; // conforming code seg unsigned a:1; // accessed seg unsigned p:1; // present unsigned g:1; // granularity unsigned ed:1; // expand down data seg unsigned ldt:1; // ldt unsigned c_gate:1; // call gate unsigned i_gate:1; // interrupt gate unsigned t_gate:1; // task gate unsigned tss:1; // tss unsigned busy:1; // tss is busy unsigned trap:1; // interrupt gate is trap gate unsigned is_i386:1; // i386 (32 bit) descriptor or 32 bit segment } descr_t; /* * segment registers here represent 16 bit selectors & base/limit cache * ldt & tr are quite similar to segment selectors */ typedef struct { u32 base, limit; u16 sel; u16 acc; } sel_t; #define ACC_G(a) ((a >> 11) & 1) /* 0/1: granularity bytes/4k */ #define ACC_D(a) ((a >> 10) & 1) /* 0/1: default size 16/32 bit */ #define ACC_P(a) ((a >> 7) & 1) /* 0/1: present no/yes */ #define ACC_DPL(a) ((a >> 5) & 3) /* 0..3: dpl */ #define ACC_S(a) ((a >> 4) & 1) /* 0/1: system/normal */ #define ACC_E(a) ((a >> 3) & 1) /* 0/1: type data/code (ACC_S = normal) */ #define ACC_ED(a) ((a >> 2) & 1) /* 0/1: expand up/down (ACC_E = data) */ #define ACC_C(a) ((a >> 2) & 1) /* 0/1: conforming no/yes (ACC_E = code) */ #define ACC_W(a) ((a >> 1) & 1) /* 0/1: writable no/yes (ACC_E = data) */ #define ACC_R(a) ((a >> 1) & 1) /* 0/1: readable no/yes (ACC_E = code) */ #define ACC_A(a) (a & 1) /* 0/1: accessed no/yes */ #define ACC_TYPE(a) (a & 0xf) /* 0..0xf: system descr type (ACC_S = system) */ /* 8 bit registers */ #define R_AH gen.A.I8_reg.h_reg #define R_AL gen.A.I8_reg.l_reg #define R_BH gen.B.I8_reg.h_reg #define R_BL gen.B.I8_reg.l_reg #define R_CH gen.C.I8_reg.h_reg #define R_CL gen.C.I8_reg.l_reg #define R_DH gen.D.I8_reg.h_reg #define R_DL gen.D.I8_reg.l_reg /* 16 bit registers */ #define R_AX gen.A.I16_reg.x_reg #define R_BX gen.B.I16_reg.x_reg #define R_CX gen.C.I16_reg.x_reg #define R_DX gen.D.I16_reg.x_reg /* 32 bit extended registers */ #define R_EAX gen.A.I32_reg.e_reg #define R_EBX gen.B.I32_reg.e_reg #define R_ECX gen.C.I32_reg.e_reg #define R_EDX gen.D.I32_reg.e_reg /* special registers */ #define R_SP spc.SP.I16_reg.x_reg #define R_BP spc.BP.I16_reg.x_reg #define R_SI spc.SI.I16_reg.x_reg #define R_DI spc.DI.I16_reg.x_reg #define R_IP spc.IP.I16_reg.x_reg #define R_FLG spc.FLAGS /* special registers */ #define R_ESP spc.SP.I32_reg.e_reg #define R_EBP spc.BP.I32_reg.e_reg #define R_ESI spc.SI.I32_reg.e_reg #define R_EDI spc.DI.I32_reg.e_reg #define R_EIP spc.IP.I32_reg.e_reg #define R_EFLG spc.FLAGS /* segment registers */ #define R_ES_INDEX 0 #define R_CS_INDEX 1 #define R_SS_INDEX 2 #define R_DS_INDEX 3 #define R_FS_INDEX 4 #define R_GS_INDEX 5 #define R_NOSEG_INDEX 6 #define R_ES_SEL seg + R_ES_INDEX #define R_ES seg[R_ES_INDEX].sel #define R_ES_BASE seg[R_ES_INDEX].base #define R_ES_LIMIT seg[R_ES_INDEX].limit #define R_ES_ACC seg[R_ES_INDEX].acc #define R_CS_SEL seg + R_CS_INDEX #define R_CS seg[R_CS_INDEX].sel #define R_CS_BASE seg[R_CS_INDEX].base #define R_CS_LIMIT seg[R_CS_INDEX].limit #define R_CS_ACC seg[R_CS_INDEX].acc #define R_SS_SEL seg + R_SS_INDEX #define R_SS seg[R_SS_INDEX].sel #define R_SS_BASE seg[R_SS_INDEX].base #define R_SS_LIMIT seg[R_SS_INDEX].limit #define R_SS_ACC seg[R_SS_INDEX].acc #define R_DS_SEL seg + R_DS_INDEX #define R_DS seg[R_DS_INDEX].sel #define R_DS_BASE seg[R_DS_INDEX].base #define R_DS_LIMIT seg[R_DS_INDEX].limit #define R_DS_ACC seg[R_DS_INDEX].acc #define R_FS_SEL seg + R_FS_INDEX #define R_FS seg[R_FS_INDEX].sel #define R_FS_BASE seg[R_FS_INDEX].base #define R_FS_LIMIT seg[R_FS_INDEX].limit #define R_FS_ACC seg[R_FS_INDEX].acc #define R_GS_SEL seg + R_GS_INDEX #define R_GS seg[R_GS_INDEX].sel #define R_GS_BASE seg[R_GS_INDEX].base #define R_GS_LIMIT seg[R_GS_INDEX].limit #define R_GS_ACC seg[R_GS_INDEX].acc #define R_NOSEG_SEL seg + R_NOSEG_INDEX #define R_NOSEG seg[R_NOSEG_INDEX].sel #define R_NOSEG_BASE seg[R_NOSEG_INDEX].base #define R_NOSEG_LIMIT seg[R_NOSEG_INDEX].limit #define R_NOSEG_ACC seg[R_NOSEG_INDEX].acc /* other registers: tr, ldt, gdt, idt */ #define R_TR tr.sel #define R_TR_BASE tr.base #define R_TR_LIMIT tr.limit #define R_TR_ACC tr.acc #define R_LDT ldt.sel #define R_LDT_BASE ldt.base #define R_LDT_LIMIT ldt.limit #define R_LDT_ACC ldt.acc #define R_GDT_BASE gdt.base #define R_GDT_LIMIT gdt.limit #define R_IDT_BASE idt.base #define R_IDT_LIMIT idt.limit /* machine status & debug registers: CRx, DRx, TRx */ #define R_CR0 crx[0] #define R_CR1 crx[1] #define R_CR2 crx[2] #define R_CR3 crx[3] #define R_CR4 crx[4] #define R_CR5 crx[5] #define R_CR6 crx[6] #define R_CR7 crx[7] #define R_DR0 drx[0] #define R_DR1 drx[1] #define R_DR2 drx[2] #define R_DR3 drx[3] #define R_DR4 drx[4] #define R_DR5 drx[5] #define R_DR6 drx[6] #define R_DR7 drx[7] #define R_TSC msr[0x10] #define R_LAST_REAL_TSC msr[0x11] #define R_REAL_TSC msr[0x12] /* 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 X86EMU_TOGGLE_FLAG(emu, flag) (emu->x86.R_FLG ^= (flag)) #define X86EMU_SET_FLAG(emu, flag) (emu->x86.R_FLG |= (flag)) #define X86EMU_CLEAR_FLAG(emu, flag) (emu->x86.R_FLG &= ~(flag)) /* * Emulator machine state. * Segment usage control. */ #define _MODE_SEG_DS_SS 0x00000001 #define _MODE_REPE 0x00000002 #define _MODE_REPNE 0x00000004 #define _MODE_DATA32 0x00000008 #define _MODE_ADDR32 0x00000010 #define _MODE_STACK32 0x00000020 #define _MODE_CODE32 0x00000040 #define _MODE_HALTED 0x00000080 #define INTR_TYPE_SOFT 1 #define INTR_TYPE_FAULT 2 #define INTR_MODE_RESTART 0x100 #define INTR_MODE_ERRCODE 0x200 #define X86EMU_RUN_TIMEOUT (1 << 0) #define X86EMU_RUN_MAX_INSTR (1 << 1) #define X86EMU_RUN_NO_EXEC (1 << 2) #define X86EMU_RUN_NO_CODE (1 << 3) #define X86EMU_RUN_LOOP (1 << 4) #define X86EMU_MEMIO_8 0 #define X86EMU_MEMIO_16 1 #define X86EMU_MEMIO_32 2 #define X86EMU_MEMIO_8_NOPERM 3 #define X86EMU_MEMIO_R (0 << 8) #define X86EMU_MEMIO_W (1 << 8) #define X86EMU_MEMIO_X (2 << 8) #define X86EMU_MEMIO_I (3 << 8) #define X86EMU_MEMIO_O (4 << 8) #define X86EMU_MSRS 0x800 struct x86emu_s; typedef unsigned (* x86emu_memio_handler_t)(struct x86emu_s *, u32 addr, u32 *val, unsigned type); typedef int (* x86emu_intr_handler_t)(struct x86emu_s *, u8 num, unsigned type); typedef int (* x86emu_code_handler_t)(struct x86emu_s *); typedef void (* x86emu_flush_func_t)(struct x86emu_s *, char *buf, unsigned size); typedef struct { struct i386_general_regs gen; struct i386_special_regs spc; sel_t seg[8]; sel_t ldt; sel_t tr; u32 crx[8]; u32 drx[8]; struct { u32 base, limit; } gdt; struct { u32 base, limit; } idt; u64 *msr; /* X86EMU_MSRS */ unsigned char *msr_perm; /* X86EMU_MSRS */ u32 mode; sel_t *default_seg; u32 saved_eip; u16 saved_cs; char decode_seg[4]; unsigned char instr_buf[32]; /* instruction bytes */ unsigned instr_len; /* bytes in instr_buf */ char disasm_buf[256]; char *disasm_ptr; u8 intr_nr; unsigned intr_type; unsigned intr_errcode; unsigned intr_stats[0x100]; unsigned debug_start, debug_len; } x86emu_regs_t; #define X86EMU_TRACE_REGS (1 << 0) #define X86EMU_TRACE_CODE (1 << 1) #define X86EMU_TRACE_DATA (1 << 2) #define X86EMU_TRACE_ACC (1 << 3) #define X86EMU_TRACE_IO (1 << 4) #define X86EMU_TRACE_INTS (1 << 5) #define X86EMU_TRACE_TIME (1 << 6) #define X86EMU_TRACE_DEBUG (1 << 7) #define X86EMU_TRACE_DEFAULT (X86EMU_TRACE_REGS | X86EMU_TRACE_CODE | X86EMU_TRACE_DATA | X86EMU_TRACE_IO | X86EMU_TRACE_INTS) #define X86EMU_DUMP_REGS (1 << 0) #define X86EMU_DUMP_MEM (1 << 1) #define X86EMU_DUMP_ACC_MEM (1 << 2) #define X86EMU_DUMP_INV_MEM (1 << 3) #define X86EMU_DUMP_ATTR (1 << 4) #define X86EMU_DUMP_ASCII (1 << 5) #define X86EMU_DUMP_IO (1 << 6) #define X86EMU_DUMP_INTS (1 << 7) #define X86EMU_DUMP_TIME (1 << 8) #define X86EMU_DUMP_DEFAULT (X86EMU_DUMP_REGS | X86EMU_DUMP_INV_MEM | X86EMU_DUMP_ATTR | X86EMU_DUMP_ASCII | X86EMU_DUMP_IO | X86EMU_DUMP_INTS | X86EMU_DUMP_TIME) #define X86EMU_PERM_R (1 << 0) #define X86EMU_PERM_W (1 << 1) #define X86EMU_PERM_X (1 << 2) #define X86EMU_PERM_VALID (1 << 3) #define X86EMU_ACC_R (1 << 4) #define X86EMU_ACC_W (1 << 5) #define X86EMU_ACC_X (1 << 6) #define X86EMU_ACC_INVALID (1 << 7) /* for convenience */ #define X86EMU_PERM_RW (X86EMU_PERM_R | X86EMU_PERM_W) #define X86EMU_PERM_RX (X86EMU_PERM_R | X86EMU_PERM_X) #define X86EMU_PERM_RWX (X86EMU_PERM_R | X86EMU_PERM_W | X86EMU_PERM_X) /* 4k pages */ #define X86EMU_PAGE_BITS 12 #define X86EMU_PTABLE_BITS 10 #define X86EMU_PDIR_BITS (32 - X86EMU_PTABLE_BITS - X86EMU_PAGE_BITS) #define X86EMU_PAGE_SIZE (1 << X86EMU_PAGE_BITS) #define X86EMU_IO_PORTS (1 << 16) typedef struct { unsigned char *attr; // malloc'ed unsigned char *data; // NOT malloc'ed unsigned char def_attr; } mem2_page_t; typedef mem2_page_t mem2_ptable_t[1 << X86EMU_PTABLE_BITS]; typedef mem2_ptable_t *mem2_pdir_t[1 << X86EMU_PDIR_BITS]; typedef struct { mem2_pdir_t *pdir; unsigned invalid:1; unsigned char def_attr; } x86emu_mem_t; /**************************************************************************** REMARKS: Structure maintaining the emulator machine state. MEMBERS: private - private data pointer x86 - X86 registers ****************************************************************************/ typedef struct x86emu_s { x86emu_regs_t x86; x86emu_code_handler_t code_check; x86emu_memio_handler_t memio; x86emu_intr_handler_t intr; x86emu_mem_t *mem; struct { unsigned char *map; unsigned *stats_i, *stats_o; unsigned iopl_needed:1; unsigned iopl_ok:1; } io; struct { x86emu_flush_func_t flush; unsigned size; char *buf; char *ptr; unsigned trace; /* trace flags: X86EMU_TRACE_* */ } log; unsigned timeout; u64 max_instr; union { void *_private; #ifndef __cplusplus void *private; /* deprecated: use _private */ #endif }; } x86emu_t; /*-------------------------- Function Prototypes --------------------------*/ x86emu_t *x86emu_new(unsigned def_mem_perm, unsigned def_io_perm); x86emu_t *x86emu_done(x86emu_t *emu); x86emu_t *x86emu_clone(x86emu_t *emu); void x86emu_reset(x86emu_t *emu); unsigned x86emu_run(x86emu_t *emu, unsigned flags); void x86emu_stop(x86emu_t *emu); void x86emu_set_log(x86emu_t *emu, unsigned buffer_size, x86emu_flush_func_t flush); unsigned x86emu_clear_log(x86emu_t *emu, int flush); void x86emu_log(x86emu_t *emu, const char *format, ...) __attribute__ ((format (printf, 2, 3))); void x86emu_dump(x86emu_t *emu, int flags); void x86emu_set_perm(x86emu_t *emu, unsigned start, unsigned end, unsigned perm); void x86emu_set_io_perm(x86emu_t *emu, unsigned start, unsigned end, unsigned perm); void x86emu_set_page(x86emu_t *emu, unsigned page, void *address); void x86emu_reset_access_stats(x86emu_t *emu); x86emu_code_handler_t x86emu_set_code_handler(x86emu_t *emu, x86emu_code_handler_t handler); x86emu_intr_handler_t x86emu_set_intr_handler(x86emu_t *emu, x86emu_intr_handler_t handler); x86emu_memio_handler_t x86emu_set_memio_handler(x86emu_t *emu, x86emu_memio_handler_t handler); void x86emu_intr_raise(x86emu_t *emu, u8 intr_nr, unsigned type, unsigned err); unsigned x86emu_read_byte(x86emu_t *emu, unsigned addr); unsigned x86emu_read_byte_noperm(x86emu_t *emu, unsigned addr); unsigned x86emu_read_word(x86emu_t *emu, unsigned addr); unsigned x86emu_read_dword(x86emu_t *emu, unsigned addr); void x86emu_write_byte(x86emu_t *emu, unsigned addr, unsigned val); void x86emu_write_byte_noperm(x86emu_t *emu, unsigned addr, unsigned val); void x86emu_write_word(x86emu_t *emu, unsigned addr, unsigned val); void x86emu_write_dword(x86emu_t *emu, unsigned addr, unsigned val); void x86emu_set_seg_register(x86emu_t *emu, sel_t *seg, u16 val); #ifdef __cplusplus } /* End of "C" linkage for C++ */ #endif #endif /* __X86EMU_X86EMU_H */ libx86emu-1.5/include/x86emu_int.h000066400000000000000000000110201247503741400170050ustar00rootroot00000000000000/**************************************************************************** * * Realmode X86 Emulator Library * * Copyright (C) 1996-1999 SciTech Software, Inc. * Copyright (C) David Mosberger-Tang * 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. * * ======================================================================== * * Language: ANSI C * Environment: Any * Developer: Kendall Bennett * * Description: Header file for system specific functions. These functions * are always compiled and linked in the OS depedent libraries, * and never in a binary portable driver. * ****************************************************************************/ #ifndef __X86EMU_X86EMU_INT_H #define __X86EMU_X86EMU_INT_H #include #include #include #include #define L_SYM __attribute__((visibility("internal"))) #define M x86emu #include "x86emu.h" #include "decode.h" #include "ops.h" #include "prim_ops.h" #include "mem.h" // global emulator state extern x86emu_t M; #define INTR_RAISE_DIV0(a) x86emu_intr_raise(a, 0, INTR_TYPE_SOFT | INTR_MODE_RESTART, 0) #define INTR_RAISE_SOFT(a, n) x86emu_intr_raise(a, n, INTR_TYPE_SOFT, 0) #define INTR_RAISE_GP(a, err) x86emu_intr_raise(a, 0x0d, INTR_TYPE_FAULT | INTR_MODE_RESTART | INTR_MODE_ERRCODE, err) #define INTR_RAISE_UD(a) x86emu_intr_raise(a, 0x06, INTR_TYPE_FAULT | INTR_MODE_RESTART, 0) #define MODE_REPE (M.x86.mode & _MODE_REPE) #define MODE_REPNE (M.x86.mode & _MODE_REPNE) #define MODE_REP (M.x86.mode & (_MODE_REPE | _MODE_REPNE)) #define MODE_DATA32 (M.x86.mode & _MODE_DATA32) #define MODE_ADDR32 (M.x86.mode & _MODE_ADDR32) #define MODE_STACK32 (M.x86.mode & _MODE_STACK32) #define MODE_CODE32 (M.x86.mode & _MODE_CODE32) #define MODE_HALTED (M.x86.mode & _MODE_HALTED) #define MODE_PROTECTED(a) ((a)->x86.R_CR0 & 1) #define MODE_REAL(a) (!MODE_PROTECTED(a)) #define TOGGLE_FLAG(flag) (M.x86.R_FLG ^= (flag)) #define SET_FLAG(flag) (M.x86.R_FLG |= (flag)) #define CLEAR_FLAG(flag) (M.x86.R_FLG &= ~(flag)) #define ACCESS_FLAG(flag) (M.x86.R_FLG & (flag)) #define CLEARALL_FLAG(m) (M.x86.R_FLG = 0) #define CONDITIONAL_SET_FLAG(COND,FLAG) \ if(COND) SET_FLAG(FLAG); else CLEAR_FLAG(FLAG) #define LOG_STR(a) memcpy(*p, a, sizeof (a) - 1), *p += sizeof (a) - 1 #define LOG_FREE(emu) ((emu)->log.size + (emu)->log.buf - (emu)->log.ptr) #if defined(__i386__) || defined (__x86_64__) #define WITH_TSC 1 #define WITH_IOPL 1 #else #define WITH_TSC 0 #define WITH_IOPL 0 #endif #if WITH_TSC #if defined(__i386__) static inline u64 tsc() { register u64 tsc asm ("%eax"); asm ( "rdtsc" : "=r" (tsc) ); return tsc; } #endif #if defined (__x86_64__) static inline u64 tsc() { register u64 tsc asm ("%rax"); asm ( "push %%rdx\n" "rdtsc\n" "xchg %%edx,%%eax\n" "shl $32,%%rax\n" "add %%rdx,%%rax\n" "pop %%rdx" : "=r" (tsc) ); return tsc; } #endif #endif #if WITH_IOPL #if defined(__i386__) static inline unsigned getiopl() { register u32 i asm ("%eax"); asm( "pushf\n" "pop %%eax" : "=r" (i) ); i = (i >> 12) & 3; return i; } #endif #if defined (__x86_64__) static inline unsigned getiopl() { register unsigned i asm ("%rax"); asm( "pushf\n" "pop %%rax" : "=r" (i) ); i = (i >> 12) & 3; return i; } #endif #endif #endif /* __X86EMU_X86EMU_INT_H */ libx86emu-1.5/mem.c000066400000000000000000000425201247503741400141360ustar00rootroot00000000000000#include "include/x86emu_int.h" #include #define PERM16(a) ((a) + ((a) << 8)) #define PERM32(a) (PERM16(a) + (PERM16(a) << 16)) // avoid unaligned memory accesses #define STRICT_ALIGN 0 static unsigned vm_r_byte(x86emu_mem_t *vm, unsigned addr); static unsigned vm_r_byte_noperm(x86emu_mem_t *vm, unsigned addr); static unsigned vm_r_word(x86emu_mem_t *vm, unsigned addr); static unsigned vm_r_dword(x86emu_mem_t *vm, unsigned addr); static unsigned vm_x_byte(x86emu_mem_t *vm, unsigned addr); static unsigned vm_x_word(x86emu_mem_t *vm, unsigned addr); static unsigned vm_x_dword(x86emu_mem_t *vm, unsigned addr); static void vm_w_byte(x86emu_mem_t *vm, unsigned addr, unsigned val); static void vm_w_byte_noperm(x86emu_mem_t *vm, unsigned addr, unsigned val); static void vm_w_word(x86emu_mem_t *vm, unsigned addr, unsigned val); static void vm_w_dword(x86emu_mem_t *vm, unsigned addr, unsigned val); static mem2_page_t *vm_get_page(x86emu_mem_t *mem, unsigned addr, int create); static unsigned vm_i_byte(unsigned addr); static unsigned vm_i_dword(unsigned addr); static unsigned vm_i_word(unsigned addr); static void vm_o_byte(unsigned addr, unsigned val); static void vm_o_dword(unsigned addr, unsigned val); static void vm_o_word(unsigned addr, unsigned val); void *mem_dup(const void *src, size_t n) { void *dst; if(!src || !n || !(dst = malloc(n))) return NULL; memcpy(dst, src, n); return dst; } x86emu_mem_t *emu_mem_new(unsigned perm) { x86emu_mem_t *mem; mem = calloc(1, sizeof *mem); mem->def_attr = perm; return mem; } x86emu_mem_t *emu_mem_free(x86emu_mem_t *mem) { mem2_pdir_t *pdir; mem2_ptable_t *ptable; mem2_page_t page; unsigned pdir_idx, u1; if(mem) { if((pdir = mem->pdir)) { for(pdir_idx = 0; pdir_idx < (1 << X86EMU_PDIR_BITS); pdir_idx++) { ptable = (*pdir)[pdir_idx]; if(!ptable) continue; for(u1 = 0; u1 < (1 << X86EMU_PTABLE_BITS); u1++) { page = (*ptable)[u1]; free(page.attr); } free(ptable); } free(pdir); } free(mem); } return NULL; } x86emu_mem_t *emu_mem_clone(x86emu_mem_t *mem) { mem2_pdir_t *pdir, *new_pdir; mem2_ptable_t *ptable, *new_ptable; mem2_page_t page; unsigned pdir_idx, u1; x86emu_mem_t *new_mem = NULL; if(!mem) return new_mem; new_mem = mem_dup(mem, sizeof *new_mem); if((pdir = mem->pdir)) { new_pdir = new_mem->pdir = mem_dup(mem->pdir, sizeof *mem->pdir); for(pdir_idx = 0; pdir_idx < (1 << X86EMU_PDIR_BITS); pdir_idx++) { ptable = (*pdir)[pdir_idx]; if(!ptable) continue; new_ptable = (*new_pdir)[pdir_idx] = mem_dup(ptable, sizeof *ptable); for(u1 = 0; u1 < (1 << X86EMU_PTABLE_BITS); u1++) { page = (*ptable)[u1]; if(page.attr) { (*new_ptable)[u1].attr = mem_dup(page.attr, 2 * X86EMU_PAGE_SIZE); if(page.data == page.attr + X86EMU_PAGE_SIZE) { (*new_ptable)[u1].data = (*new_ptable)[u1].attr + X86EMU_PAGE_SIZE; } } } } } return new_mem; } void x86emu_reset_access_stats(x86emu_t *emu) { mem2_pdir_t *pdir; mem2_ptable_t *ptable; mem2_page_t page; unsigned pdir_idx, u, u1; if(!emu || !emu->mem || !(pdir = emu->mem->pdir)) return; for(pdir_idx = 0; pdir_idx < (1 << X86EMU_PDIR_BITS); pdir_idx++) { ptable = (*pdir)[pdir_idx]; if(!ptable) continue; for(u = 0; u < (1 << X86EMU_PTABLE_BITS); u++) { page = (*ptable)[u]; if(page.attr) { for(u1 = 0; u1 < X86EMU_PAGE_SIZE; u1++) { page.attr[u1] &= X86EMU_PERM_RWX | X86EMU_PERM_VALID; } } } } } void x86emu_set_io_perm(x86emu_t *emu, unsigned start, unsigned end, unsigned perm) { if(!emu) return; if(end > X86EMU_IO_PORTS - 1) end = X86EMU_IO_PORTS - 1; while(start <= end) emu->io.map[start++] = perm; for(start = perm = 0; start < X86EMU_IO_PORTS; start++) { perm |= emu->io.map[start]; } emu->io.iopl_needed = (perm & (X86EMU_PERM_R | X86EMU_PERM_W)) ? 1 : 0; #if WITH_IOPL emu->io.iopl_ok = emu->io.iopl_needed && getiopl() != 3 ? 0 : 1; #else emu->io.iopl_ok = 1; #endif } mem2_page_t *vm_get_page(x86emu_mem_t *mem, unsigned addr, int create) { mem2_pdir_t *pdir; mem2_ptable_t *ptable; mem2_page_t page; unsigned pdir_idx = addr >> (32 - X86EMU_PDIR_BITS); unsigned ptable_idx = (addr >> X86EMU_PAGE_BITS) & ((1 << X86EMU_PTABLE_BITS) - 1); unsigned u; pdir = mem->pdir; if(!pdir) { mem->pdir = pdir = calloc(1, sizeof *pdir); // fprintf(stderr, "pdir = %p (%d)\n", pdir, sizeof *pdir); } ptable = (*pdir)[pdir_idx]; if(!ptable) { ptable = (*pdir)[pdir_idx] = calloc(1, sizeof *ptable); // fprintf(stderr, "ptable = %p\n", ptable); for(u = 0; u < (1 << X86EMU_PTABLE_BITS); u++) { (*ptable)[u].def_attr = mem->def_attr; // fprintf(stderr, "ptable[%u] = %p\n", u, &((*ptable)[u].def_attr)); } // fprintf(stderr, "pdir[%d] = %p (%d)\n", pdir_idx, ptable, sizeof *ptable); } if(create) { page = (*ptable)[ptable_idx]; if(!page.attr) { page.attr = calloc(1, 2 * X86EMU_PAGE_SIZE); page.data = page.attr + X86EMU_PAGE_SIZE; // fprintf(stderr, "page = %p, page.def_attr = %p\n", page, &page.def_attr); memset(page.attr, page.def_attr, X86EMU_PAGE_SIZE); (*ptable)[ptable_idx] = page; // fprintf(stderr, "page.attr[%d] = %p\n", ptable_idx, page.attr); } } return (*ptable) + ptable_idx; } void x86emu_set_perm(x86emu_t *emu, unsigned start, unsigned end, unsigned perm) { x86emu_mem_t *mem; mem2_page_t *page; unsigned idx; if(!emu || !(mem = emu->mem)) return; if(start > end) return; // x86emu_log(emu, "set perm: start 0x%x, end 0x%x, perm 0x%x\n", start, end, perm); if((idx = start & (X86EMU_PAGE_SIZE - 1))) { page = vm_get_page(mem, start, 1); for(; idx < X86EMU_PAGE_SIZE && start <= end; start++) { // x86emu_log(emu, " page %p, idx = 0x%x\n", page, idx); page->attr[idx++] = perm; } if(!start || start > end) return; } // x86emu_log(emu, " 2: start 0x%x, end 0x%x\n", start, end); for(; end - start >= X86EMU_PAGE_SIZE - 1; start += X86EMU_PAGE_SIZE) { page = vm_get_page(mem, start, 0); page->def_attr = perm; // x86emu_log(emu, " page %p (start 0x%x, end - start 0x%x)\n", page, start, end - start); if(page->attr) memset(page->attr, page->def_attr, X86EMU_PAGE_SIZE); if(!start) return; if(end - start == X86EMU_PAGE_SIZE - 1) { start += X86EMU_PAGE_SIZE; break; } } if(start > end) return; // x86emu_log(emu, " 3: start 0x%x, end 0x%x\n", start, end); page = vm_get_page(mem, start, 1); end = end - start + 1; for(idx = 0; idx < end; idx++) { // x86emu_log(emu, " page %p, idx = 0x%x\n", page, idx); page->attr[idx] = perm; } } void x86emu_set_page(x86emu_t *emu, unsigned page, void *address) { x86emu_mem_t *mem; mem2_page_t *p; unsigned u; if(!emu || !(mem = emu->mem)) return; p = vm_get_page(mem, page, 1); if(address) { p->data = address; // tag memory as initialized for(u = 0; u < X86EMU_PAGE_SIZE; u++) { p->attr[u] |= X86EMU_PERM_VALID; } } else { p->data = p->attr + X86EMU_PAGE_SIZE; } } unsigned vm_r_byte(x86emu_mem_t *mem, unsigned addr) { mem2_page_t *page; unsigned page_idx = addr & (X86EMU_PAGE_SIZE - 1); unsigned char *perm; page = vm_get_page(mem, addr, 1); perm = page->attr + page_idx; if(*perm & X86EMU_PERM_R) { *perm |= X86EMU_ACC_R; if(!(*perm & X86EMU_PERM_VALID)) { *perm |= X86EMU_ACC_INVALID; mem->invalid = 1; } return page->data[page_idx]; } mem->invalid = 1; return 0xff; } unsigned vm_r_byte_noperm(x86emu_mem_t *mem, unsigned addr) { mem2_page_t *page; unsigned page_idx = addr & (X86EMU_PAGE_SIZE - 1); // unsigned char *attr; page = vm_get_page(mem, addr, 1); // attr = page->attr + page_idx; return page->data[page_idx]; } unsigned vm_r_word(x86emu_mem_t *mem, unsigned addr) { mem2_page_t *page; unsigned val, page_idx = addr & (X86EMU_PAGE_SIZE - 1); u16 *perm16; page = vm_get_page(mem, addr, 1); perm16 = (u16 *) (page->attr + page_idx); if( #if STRICT_ALIGN (page_idx & 1) || #else page_idx >= X86EMU_PAGE_SIZE - 1 || #endif (*perm16 & PERM16(X86EMU_PERM_R | X86EMU_PERM_VALID)) != PERM16(X86EMU_PERM_R | X86EMU_PERM_VALID) ) { val = vm_r_byte(mem, addr); val += vm_r_byte(mem, addr + 1) << 8; return val; } *perm16 |= PERM16(X86EMU_ACC_R); #if defined(__BIG_ENDIAN__) || STRICT_ALIGN val = page->data[page_idx] + (page->data[page_idx + 1] << 8); #else val = *(u16 *) (page->data + page_idx); #endif return val; } unsigned vm_r_dword(x86emu_mem_t *mem, unsigned addr) { mem2_page_t *page; unsigned val, page_idx = addr & (X86EMU_PAGE_SIZE - 1); u32 *perm32; page = vm_get_page(mem, addr, 1); perm32 = (u32 *) (page->attr + page_idx); if( #if STRICT_ALIGN (page_idx & 3) || #else page_idx >= X86EMU_PAGE_SIZE - 3 || #endif (*perm32 & PERM32(X86EMU_PERM_R | X86EMU_PERM_VALID)) != PERM32(X86EMU_PERM_R | X86EMU_PERM_VALID) ) { val = vm_r_byte(mem, addr); val += vm_r_byte(mem, addr + 1) << 8; val += vm_r_byte(mem, addr + 2) << 16; val += vm_r_byte(mem, addr + 3) << 24; return val; } *perm32 |= PERM32(X86EMU_ACC_R); #if defined(__BIG_ENDIAN__) || STRICT_ALIGN val = page->data[page_idx] + (page->data[page_idx + 1] << 8) + (page->data[page_idx + 2] << 16) + (page->data[page_idx + 3] << 24); #else val = *(u32 *) (page->data + page_idx); #endif return val; } unsigned vm_x_byte(x86emu_mem_t *mem, unsigned addr) { mem2_page_t *page; unsigned page_idx = addr & (X86EMU_PAGE_SIZE - 1); unsigned char *attr; page = vm_get_page(mem, addr, 1); attr = page->attr + page_idx; if(*attr & X86EMU_PERM_X) { *attr |= X86EMU_ACC_X; if(!(*attr & X86EMU_PERM_VALID)) { *attr |= X86EMU_ACC_INVALID; mem->invalid = 1; } return page->data[page_idx]; } mem->invalid = 1; return 0xff; } unsigned vm_x_word(x86emu_mem_t *mem, unsigned addr) { return vm_x_byte(mem, addr) + (vm_x_byte(mem, addr + 1) << 8); } unsigned vm_x_dword(x86emu_mem_t *mem, unsigned addr) { return vm_x_word(mem, addr) + (vm_x_word(mem, addr + 2) << 16); } void vm_w_byte(x86emu_mem_t *mem, unsigned addr, unsigned val) { mem2_page_t *page; unsigned page_idx = addr & (X86EMU_PAGE_SIZE - 1); unsigned char *attr; page = vm_get_page(mem, addr, 1); attr = page->attr + page_idx; if(*attr & X86EMU_PERM_W) { *attr |= X86EMU_PERM_VALID | X86EMU_ACC_W; page->data[page_idx] = val; } else { *attr |= X86EMU_ACC_INVALID; mem->invalid = 1; } } void vm_w_byte_noperm(x86emu_mem_t *mem, unsigned addr, unsigned val) { mem2_page_t *page; unsigned page_idx = addr & (X86EMU_PAGE_SIZE - 1); unsigned char *attr; page = vm_get_page(mem, addr, 1); attr = page->attr + page_idx; *attr |= X86EMU_PERM_VALID | X86EMU_ACC_W; page->data[page_idx] = val; } void vm_w_word(x86emu_mem_t *mem, unsigned addr, unsigned val) { mem2_page_t *page; unsigned page_idx = addr & (X86EMU_PAGE_SIZE - 1); u16 *perm16; page = vm_get_page(mem, addr, 1); perm16 = (u16 *) (page->attr + page_idx); if( #if STRICT_ALIGN (page_idx & 1) || #else page_idx >= X86EMU_PAGE_SIZE - 1 || #endif (*perm16 & PERM16(X86EMU_PERM_W)) != PERM16(X86EMU_PERM_W) ) { vm_w_byte(mem, addr, val); vm_w_byte(mem, addr + 1, val >> 8); return; } *perm16 |= PERM16(X86EMU_PERM_VALID | X86EMU_ACC_W); #if defined(__BIG_ENDIAN__) || STRICT_ALIGN page->data[page_idx] = val; page->data[page_idx + 1] = val >> 8; #else *(u16 *) (page->data + page_idx) = val; #endif } void vm_w_dword(x86emu_mem_t *mem, unsigned addr, unsigned val) { mem2_page_t *page; unsigned page_idx = addr & (X86EMU_PAGE_SIZE - 1); u32 *perm32; page = vm_get_page(mem, addr, 1); perm32 = (u32 *) (page->attr + page_idx); if( #if STRICT_ALIGN (page_idx & 3) || #else page_idx >= X86EMU_PAGE_SIZE - 3 || #endif (*perm32 & PERM32(X86EMU_PERM_W)) != PERM32(X86EMU_PERM_W) ) { vm_w_byte(mem, addr, val); vm_w_byte(mem, addr + 1, val >> 8); vm_w_byte(mem, addr + 2, val >> 16); vm_w_byte(mem, addr + 3, val >> 24); return; } *perm32 |= PERM32(X86EMU_PERM_VALID | X86EMU_ACC_W); #if defined(__BIG_ENDIAN__) || STRICT_ALIGN page->data[page_idx] = val; page->data[page_idx + 1] = val >> 8; page->data[page_idx + 2] = val >> 16; page->data[page_idx + 3] = val >> 24; #else *(u32 *) (page->data + page_idx) = val; #endif } unsigned vm_i_byte(unsigned addr) { unsigned char *perm; addr &= 0xffff; perm = M.io.map + addr; if( M.io.iopl_ok && (*perm & X86EMU_PERM_R) ) { *perm |= X86EMU_ACC_R; M.io.stats_i[addr]++; return inb(addr); } else { *perm |= X86EMU_ACC_INVALID; } M.mem->invalid = 1; return 0xff; } unsigned vm_i_word(unsigned addr) { unsigned char *perm; unsigned val; addr &= 0xffff; perm = M.io.map + addr; if( !M.io.iopl_ok || addr == 0xffff || !(perm[0] & X86EMU_PERM_R) || !(perm[1] & X86EMU_PERM_R) ) { val = vm_i_byte(addr); val += (vm_i_byte(addr + 1) << 8); return val; } perm[0] |= X86EMU_ACC_R; perm[1] |= X86EMU_ACC_R; M.io.stats_i[addr]++; M.io.stats_i[addr + 1]++; return inw(addr); } unsigned vm_i_dword(unsigned addr) { unsigned char *perm; unsigned val; addr &= 0xffff; perm = M.io.map + addr; if( !M.io.iopl_ok || addr >= 0xfffd || !(perm[0] & X86EMU_PERM_R) || !(perm[1] & X86EMU_PERM_R) || !(perm[2] & X86EMU_PERM_R) || !(perm[3] & X86EMU_PERM_R) ) { val = vm_i_byte(addr); val += (vm_i_byte(addr + 1) << 8); val += (vm_i_byte(addr + 2) << 16); val += (vm_i_byte(addr + 3) << 24); return val; } perm[0] |= X86EMU_ACC_R; perm[1] |= X86EMU_ACC_R; perm[2] |= X86EMU_ACC_R; perm[3] |= X86EMU_ACC_R; M.io.stats_i[addr]++; M.io.stats_i[addr + 1]++; M.io.stats_i[addr + 2]++; M.io.stats_i[addr + 3]++; return inl(addr); } void vm_o_byte(unsigned addr, unsigned val) { unsigned char *perm; addr &= 0xffff; perm = M.io.map + addr; if( M.io.iopl_ok && (*perm & X86EMU_PERM_W) ) { *perm |= X86EMU_ACC_W; M.io.stats_o[addr]++; outb(val, addr); } else { *perm |= X86EMU_ACC_INVALID; M.mem->invalid = 1; } } void vm_o_word(unsigned addr, unsigned val) { unsigned char *perm; addr &= 0xffff; perm = M.io.map + addr; if( !M.io.iopl_ok || addr == 0xffff || !(perm[0] & X86EMU_PERM_W) || !(perm[1] & X86EMU_PERM_W) ) { vm_o_byte(addr, val); vm_o_byte(addr + 1, val); return; } perm[0] |= X86EMU_ACC_W; perm[1] |= X86EMU_ACC_W; M.io.stats_o[addr]++; M.io.stats_o[addr + 1]++; outw(val, addr); } void vm_o_dword(unsigned addr, unsigned val) { unsigned char *perm; addr &= 0xffff; perm = M.io.map + addr; if( !M.io.iopl_ok || addr >= 0xfffd || !(perm[0] & X86EMU_PERM_W) || !(perm[1] & X86EMU_PERM_W) || !(perm[2] & X86EMU_PERM_W) || !(perm[3] & X86EMU_PERM_W) ) { vm_o_byte(addr, val); vm_o_byte(addr + 1, val); vm_o_byte(addr + 2, val); vm_o_byte(addr + 3, val); return; } perm[0] |= X86EMU_ACC_W; perm[1] |= X86EMU_ACC_W; perm[2] |= X86EMU_ACC_W; perm[3] |= X86EMU_ACC_W; M.io.stats_o[addr]++; M.io.stats_o[addr + 1]++; M.io.stats_o[addr + 2]++; M.io.stats_o[addr + 3]++; outl(val, addr); } unsigned vm_memio(x86emu_t *emu, u32 addr, u32 *val, unsigned type) { x86emu_mem_t *mem = emu->mem; unsigned bits = type & 0xff; type &= ~0xff; mem->invalid = 0; switch(type) { case X86EMU_MEMIO_R: switch(bits) { case X86EMU_MEMIO_8: *val = vm_r_byte(mem, addr); break; case X86EMU_MEMIO_16: *val = vm_r_word(mem, addr); break; case X86EMU_MEMIO_32: *val = vm_r_dword(mem, addr); break; case X86EMU_MEMIO_8_NOPERM: *val = vm_r_byte_noperm(mem, addr); break; } break; case X86EMU_MEMIO_W: switch(bits) { case X86EMU_MEMIO_8: vm_w_byte(mem, addr, *val); break; case X86EMU_MEMIO_16: vm_w_word(mem, addr, *val); break; case X86EMU_MEMIO_32: vm_w_dword(mem, addr, *val); break; case X86EMU_MEMIO_8_NOPERM: vm_w_byte_noperm(mem, addr, *val); break; } break; case X86EMU_MEMIO_X: switch(bits) { case X86EMU_MEMIO_8: *val = vm_x_byte(mem, addr); break; case X86EMU_MEMIO_16: *val = vm_x_word(mem, addr); break; case X86EMU_MEMIO_32: *val = vm_x_dword(mem, addr); break; } break; case X86EMU_MEMIO_I: switch(bits) { case X86EMU_MEMIO_8: *val = vm_i_byte(addr); break; case X86EMU_MEMIO_16: *val = vm_i_word(addr); break; case X86EMU_MEMIO_32: *val = vm_i_dword(addr); break; } break; case X86EMU_MEMIO_O: switch(bits) { case X86EMU_MEMIO_8: vm_o_byte(addr, *val); break; case X86EMU_MEMIO_16: vm_o_word(addr, *val); break; case X86EMU_MEMIO_32: vm_o_dword(addr, *val); break; } break; } return mem->invalid; } libx86emu-1.5/ops.c000066400000000000000000004017741247503741400141730ustar00rootroot00000000000000/**************************************************************************** * * Realmode X86 Emulator Library * * Copyright (C) 1996-1999 SciTech Software, Inc. * Copyright (C) David Mosberger-Tang * 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. * * ======================================================================== * * Language: ANSI C * Environment: Any * Developer: Kendall Bennett * * Description: This file includes subroutines to implement the decoding * and emulation of all the x86 processor instructions. * * There are approximately 250 subroutines in here, which correspond * to the 256 byte-"opcodes" found on the 8086. The table which * dispatches this is found in the files optab.[ch]. * * Each opcode proc has a comment preceeding it which gives it's table * address. Several opcodes are missing (undefined) in the table. * * Each proc includes information for decoding (OP_DECODE). * * Many of the procedures are *VERY* similar in coding. This has * allowed for a very large amount of code to be generated in a fairly * short amount of time (i.e. cut, paste, and modify). The result is * that much of the code below could have been folded into subroutines * for a large reduction in size of this file. The downside would be * that there would be a penalty in execution speed. The file could * also have been *MUCH* larger by inlining certain functions which * were called. This could have resulted even faster execution. The * prime directive I used to decide whether to inline the code or to * modularize it, was basically: 1) no unnecessary subroutine calls, * 2) no routines more than about 200 lines in size, and 3) modularize * any code that I might not get right the first time. The fetch_* * subroutines fall into the latter category. The The decode_* fall * into the second category. The coding of the "switch(mod){ .... }" * in many of the subroutines below falls into the first category. * Especially, the coding of {add,and,or,sub,...}_{byte,word} * subroutines are an especially glaring case of the third guideline. * Since so much of the code is cloned from other modules (compare * opcode #00 to opcode #01), making the basic operations subroutine * calls is especially important; otherwise mistakes in coding an * "add" would represent a nightmare in maintenance. * ****************************************************************************/ #include "include/x86emu_int.h" /*----------------------------- Implementation ----------------------------*/ static u8 (*op_A_byte[8])(u8 d, u8 s) = { add_byte, or_byte, adc_byte, sbb_byte, and_byte, sub_byte, xor_byte, cmp_byte }; static u16 (*op_A_word[8])(u16 d, u16 s) = { add_word, or_word, adc_word, sbb_word, and_word, sub_word, xor_word, cmp_word }; static u32 (*op_A_long[8])(u32 d, u32 s) = { add_long, or_long, adc_long, sbb_long, and_long, sub_long, xor_long, cmp_long }; static void decode_op_A(int type) { switch(type) { case 0: OP_DECODE("add "); break; case 1: OP_DECODE("or "); break; case 2: OP_DECODE("adc "); break; case 3: OP_DECODE("sbb "); break; case 4: OP_DECODE("and "); break; case 5: OP_DECODE("sub "); break; case 6: OP_DECODE("xor "); break; case 7: OP_DECODE("cmp "); break; } } static u8 (*op_B_byte[8])(u8 d, u8 s) = { rol_byte, ror_byte, rcl_byte, rcr_byte, shl_byte, shr_byte, shl_byte, sar_byte }; static u16 (*op_B_word[8])(u16 s, u8 d) = { rol_word, ror_word, rcl_word, rcr_word, shl_word, shr_word, shl_word, sar_word }; static u32 (*op_B_long[8])(u32 s, u8 d) = { rol_long, ror_long, rcl_long, rcr_long, shl_long, shr_long, shl_long, sar_long }; static void decode_op_B(int type) { switch(type) { case 0: OP_DECODE("rol "); break; case 1: OP_DECODE("ror "); break; case 2: OP_DECODE("rcl "); break; case 3: OP_DECODE("rcr "); break; case 4: OP_DECODE("shl "); break; case 5: OP_DECODE("shr "); break; case 6: OP_DECODE("sal "); break; case 7: OP_DECODE("sar "); break; } } void decode_cond(int type) { switch(type) { case 0: OP_DECODE("o "); break; case 1: OP_DECODE("no "); break; case 2: OP_DECODE("b "); break; case 3: OP_DECODE("nb "); break; case 4: OP_DECODE("z "); break; case 5: OP_DECODE("nz "); break; case 6: OP_DECODE("na "); break; case 7: OP_DECODE("a "); break; case 8: OP_DECODE("s "); break; case 9: OP_DECODE("ns "); break; case 10: OP_DECODE("p "); break; case 11: OP_DECODE("np "); break; case 12: OP_DECODE("l "); break; case 13: OP_DECODE("nl "); break; case 14: OP_DECODE("ng "); break; case 15: OP_DECODE("g "); break; } } /**************************************************************************** PARAMETERS: op1 - Instruction op code REMARKS: Handles illegal opcodes. ****************************************************************************/ static void x86emuOp_illegal_op(u8 op1) { OP_DECODE("illegal opcode"); INTR_RAISE_UD(&M); } /**************************************************************************** REMARKS: Handles opcode 0x00, 0x08, 0x10, 0x18, 0x20, 0x28, 0x30, 0x38 ****************************************************************************/ static void x86emuOp_op_A_byte_RM_R(u8 op1) { int mod, rl, rh, type; u8 *src, *dst, val; u32 addr; type = op1 >> 3; decode_op_A(type); fetch_decode_modrm(&mod, &rh, &rl); if(mod == 3) { dst = decode_rm_byte_register(rl); OP_DECODE(","); src = decode_rm_byte_register(rh); *dst = (*op_A_byte[type])(*dst, *src); } else { addr = decode_rm_address(mod, rl); OP_DECODE(","); val = fetch_data_byte(addr); src = decode_rm_byte_register(rh); val = (*op_A_byte[type])(val, *src); if(type != 7) store_data_byte(addr, val); } } /**************************************************************************** REMARKS: Handles opcode 0x01, 0x09, 0x11, 0x19, 0x21, 0x29, 0x31, 0x39 ****************************************************************************/ static void x86emuOp_op_A_word_RM_R(u8 op1) { int mod, rl, rh, type; u32 *src32, *dst32, val, addr; u16 *src16, *dst16; type = op1 >> 3; decode_op_A(type); fetch_decode_modrm(&mod, &rh, &rl); if(mod == 3) { if(MODE_DATA32) { dst32 = decode_rm_long_register(rl); OP_DECODE(","); src32 = decode_rm_long_register(rh); *dst32 = (*op_A_long[type])(*dst32, *src32); } else { dst16 = decode_rm_word_register(rl); OP_DECODE(","); src16 = decode_rm_word_register(rh); *dst16 = (*op_A_word[type])(*dst16, *src16); } } else { addr = decode_rm_address(mod, rl); OP_DECODE(","); if(MODE_DATA32) { val = fetch_data_long(addr); src32 = decode_rm_long_register(rh); val = (*op_A_long[type])(val, *src32); if(type != 7) store_data_long(addr, val); } else { val = fetch_data_word(addr); src16 = decode_rm_word_register(rh); val = (*op_A_word[type])(val, *src16); if(type != 7) store_data_word(addr, val); } } } /**************************************************************************** REMARKS: Handles opcode 0x02, 0x0a, 0x12, 0x1a, 0x22, 0x2a, 0x32, 0x3a ****************************************************************************/ static void x86emuOp_op_A_byte_R_RM(u8 op1) { int mod, rl, rh, type; u8 *src, *dst, val; u32 addr; type = op1 >> 3; decode_op_A(type); fetch_decode_modrm(&mod, &rh, &rl); if(mod == 3) { dst = decode_rm_byte_register(rh); OP_DECODE(","); src = decode_rm_byte_register(rl); *dst = (*op_A_byte[type])(*dst, *src); } else { dst = decode_rm_byte_register(rh); OP_DECODE(","); addr = decode_rm_address(mod, rl); val = fetch_data_byte(addr); *dst = (*op_A_byte[type])(*dst, val); } } /**************************************************************************** REMARKS: Handles opcode 0x03, 0x0b, 0x13, 0x1b, 0x23, 0x2b, 0x33, 0x3b ****************************************************************************/ static void x86emuOp_op_A_word_R_RM(u8 op1) { int mod, rl, rh, type; u32 *src32, *dst32, val, addr; u16 *src16, *dst16; type = op1 >> 3; decode_op_A(type); fetch_decode_modrm(&mod, &rh, &rl); if(mod == 3) { if(MODE_DATA32) { dst32 = decode_rm_long_register(rh); OP_DECODE(","); src32 = decode_rm_long_register(rl); *dst32 = (*op_A_long[type])(*dst32, *src32); } else { dst16 = decode_rm_word_register(rh); OP_DECODE(","); src16 = decode_rm_word_register(rl); *dst16 = (*op_A_word[type])(*dst16, *src16); } } else { if(MODE_DATA32) { dst32 = decode_rm_long_register(rh); OP_DECODE(","); addr = decode_rm_address(mod, rl); val = fetch_data_long(addr); *dst32 = (*op_A_long[type])(*dst32, val); } else { dst16 = decode_rm_word_register(rh); OP_DECODE(","); addr = decode_rm_address(mod, rl); val = fetch_data_word(addr); *dst16 = (*op_A_word[type])(*dst16, val); } } } /**************************************************************************** REMARKS: Handles opcode 0x04, 0x0c, 0x14, 0x1c, 0x24, 0x2c, 0x34, 0x3c ****************************************************************************/ static void x86emuOp_op_A_byte_AL_IMM(u8 op1) { int type; u8 val; type = op1 >> 3; decode_op_A(type); OP_DECODE("al,"); val = fetch_byte(); DECODE_HEX2(val); M.x86.R_AL = (*op_A_byte[type])(M.x86.R_AL, val); } /**************************************************************************** REMARKS: Handles opcode 0x05, 0x0d, 0x15, 0x1d, 0x25, 0x2d, 0x35, 0x3d ****************************************************************************/ static void x86emuOp_op_A_word_AX_IMM(u8 op1) { int type; u32 val; type = op1 >> 3; decode_op_A(type); if(MODE_DATA32) { OP_DECODE("eax,"); val = fetch_long(); DECODE_HEX8(val); M.x86.R_EAX = (*op_A_long[type])(M.x86.R_EAX, val); } else { OP_DECODE("ax,"); val = fetch_word(); DECODE_HEX4(val); M.x86.R_AX = (*op_A_word[type])(M.x86.R_AX, val); } } /**************************************************************************** REMARKS: Handles opcode 0x06 ****************************************************************************/ static void x86emuOp_push_ES(u8 op1) { OP_DECODE("push es"); if(MODE_DATA32) { push_long(M.x86.R_ES); } else { push_word(M.x86.R_ES); } } /**************************************************************************** REMARKS: Handles opcode 0x07 ****************************************************************************/ static void x86emuOp_pop_ES(u8 op1) { OP_DECODE("pop es"); x86emu_set_seg_register(&M, M.x86.R_ES_SEL, MODE_DATA32 ? pop_long() : pop_word()); } /**************************************************************************** REMARKS: Handles opcode 0x0e ****************************************************************************/ static void x86emuOp_push_CS(u8 op1) { OP_DECODE("push cs"); if(MODE_DATA32) { push_long(M.x86.R_CS); } else { push_word(M.x86.R_CS); } } /**************************************************************************** REMARKS: Handles opcode 0x0f. Escape for two-byte opcode (286 or better) ****************************************************************************/ static void x86emuOp_two_byte(u8 op1) { u8 op2 = fetch_byte(); (*x86emu_optab2[op2])(op2); } /**************************************************************************** REMARKS: Handles opcode 0x16 ****************************************************************************/ static void x86emuOp_push_SS(u8 op1) { OP_DECODE("push ss"); if(MODE_DATA32) { push_long(M.x86.R_SS); } else { push_word(M.x86.R_SS); } } /**************************************************************************** REMARKS: Handles opcode 0x17 ****************************************************************************/ static void x86emuOp_pop_SS(u8 op1) { OP_DECODE("pop ss"); x86emu_set_seg_register(&M, M.x86.R_SS_SEL, MODE_DATA32 ? pop_long() : pop_word()); } /**************************************************************************** REMARKS: Handles opcode 0x1e ****************************************************************************/ static void x86emuOp_push_DS(u8 op1) { OP_DECODE("push ds"); if(MODE_DATA32) { push_long(M.x86.R_DS); } else { push_word(M.x86.R_DS); } } /**************************************************************************** REMARKS: Handles opcode 0x1f ****************************************************************************/ static void x86emuOp_pop_DS(u8 op1) { OP_DECODE("pop ds"); x86emu_set_seg_register(&M, M.x86.R_DS_SEL, MODE_DATA32 ? pop_long() : pop_word()); } /**************************************************************************** REMARKS: Handles opcode 0x27 ****************************************************************************/ static void x86emuOp_daa(u8 op1) { OP_DECODE("daa"); M.x86.R_AL = daa_byte(M.x86.R_AL); } /**************************************************************************** REMARKS: Handles opcode 0x2f ****************************************************************************/ static void x86emuOp_das(u8 op1) { OP_DECODE("das"); M.x86.R_AL = das_byte(M.x86.R_AL); } /**************************************************************************** REMARKS: Handles opcode 0x37 ****************************************************************************/ static void x86emuOp_aaa(u8 op1) { OP_DECODE("aaa"); M.x86.R_AX = aaa_word(M.x86.R_AX); } /**************************************************************************** REMARKS: Handles opcode 0x3f ****************************************************************************/ static void x86emuOp_aas(u8 op1) { OP_DECODE("aas"); M.x86.R_AX = aas_word(M.x86.R_AX); } /**************************************************************************** REMARKS: Handles opcode 0x40 ****************************************************************************/ static void x86emuOp_inc_AX(u8 op1) { if(MODE_DATA32) { OP_DECODE("inc eax"); M.x86.R_EAX = inc_long(M.x86.R_EAX); } else { OP_DECODE("inc ax"); M.x86.R_AX = inc_word(M.x86.R_AX); } } /**************************************************************************** REMARKS: Handles opcode 0x41 ****************************************************************************/ static void x86emuOp_inc_CX(u8 op1) { if(MODE_DATA32) { OP_DECODE("inc ecx"); M.x86.R_ECX = inc_long(M.x86.R_ECX); } else { OP_DECODE("inc cx"); M.x86.R_CX = inc_word(M.x86.R_CX); } } /**************************************************************************** REMARKS: Handles opcode 0x42 ****************************************************************************/ static void x86emuOp_inc_DX(u8 op1) { if(MODE_DATA32) { OP_DECODE("inc edx"); M.x86.R_EDX = inc_long(M.x86.R_EDX); } else { OP_DECODE("inc dx"); M.x86.R_DX = inc_word(M.x86.R_DX); } } /**************************************************************************** REMARKS: Handles opcode 0x43 ****************************************************************************/ static void x86emuOp_inc_BX(u8 op1) { if(MODE_DATA32) { OP_DECODE("inc ebx"); M.x86.R_EBX = inc_long(M.x86.R_EBX); } else { OP_DECODE("inc bx"); M.x86.R_BX = inc_word(M.x86.R_BX); } } /**************************************************************************** REMARKS: Handles opcode 0x44 ****************************************************************************/ static void x86emuOp_inc_SP(u8 op1) { if(MODE_DATA32) { OP_DECODE("inc esp"); M.x86.R_ESP = inc_long(M.x86.R_ESP); } else { OP_DECODE("inc sp"); M.x86.R_SP = inc_word(M.x86.R_SP); } } /**************************************************************************** REMARKS: Handles opcode 0x45 ****************************************************************************/ static void x86emuOp_inc_BP(u8 op1) { if(MODE_DATA32) { OP_DECODE("inc ebp"); M.x86.R_EBP = inc_long(M.x86.R_EBP); } else { OP_DECODE("inc bp"); M.x86.R_BP = inc_word(M.x86.R_BP); } } /**************************************************************************** REMARKS: Handles opcode 0x46 ****************************************************************************/ static void x86emuOp_inc_SI(u8 op1) { if(MODE_DATA32) { OP_DECODE("inc esi"); M.x86.R_ESI = inc_long(M.x86.R_ESI); } else { OP_DECODE("inc si"); M.x86.R_SI = inc_word(M.x86.R_SI); } } /**************************************************************************** REMARKS: Handles opcode 0x47 ****************************************************************************/ static void x86emuOp_inc_DI(u8 op1) { if(MODE_DATA32) { OP_DECODE("inc edi"); M.x86.R_EDI = inc_long(M.x86.R_EDI); } else { OP_DECODE("inc di"); M.x86.R_DI = inc_word(M.x86.R_DI); } } /**************************************************************************** REMARKS: Handles opcode 0x48 ****************************************************************************/ static void x86emuOp_dec_AX(u8 op1) { if(MODE_DATA32) { OP_DECODE("dec eax"); M.x86.R_EAX = dec_long(M.x86.R_EAX); } else { OP_DECODE("dec ax"); M.x86.R_AX = dec_word(M.x86.R_AX); } } /**************************************************************************** REMARKS: Handles opcode 0x49 ****************************************************************************/ static void x86emuOp_dec_CX(u8 op1) { if(MODE_DATA32) { OP_DECODE("dec ecx"); M.x86.R_ECX = dec_long(M.x86.R_ECX); } else { OP_DECODE("dec cx"); M.x86.R_CX = dec_word(M.x86.R_CX); } } /**************************************************************************** REMARKS: Handles opcode 0x4a ****************************************************************************/ static void x86emuOp_dec_DX(u8 op1) { if(MODE_DATA32) { OP_DECODE("dec edx"); M.x86.R_EDX = dec_long(M.x86.R_EDX); } else { OP_DECODE("dec dx"); M.x86.R_DX = dec_word(M.x86.R_DX); } } /**************************************************************************** REMARKS: Handles opcode 0x4b ****************************************************************************/ static void x86emuOp_dec_BX(u8 op1) { if(MODE_DATA32) { OP_DECODE("dec ebx"); M.x86.R_EBX = dec_long(M.x86.R_EBX); } else { OP_DECODE("dec bx"); M.x86.R_BX = dec_word(M.x86.R_BX); } } /**************************************************************************** REMARKS: Handles opcode 0x4c ****************************************************************************/ static void x86emuOp_dec_SP(u8 op1) { if(MODE_DATA32) { OP_DECODE("dec esp"); M.x86.R_ESP = dec_long(M.x86.R_ESP); } else { OP_DECODE("dec sp"); M.x86.R_SP = dec_word(M.x86.R_SP); } } /**************************************************************************** REMARKS: Handles opcode 0x4d ****************************************************************************/ static void x86emuOp_dec_BP(u8 op1) { if(MODE_DATA32) { OP_DECODE("dec ebp"); M.x86.R_EBP = dec_long(M.x86.R_EBP); } else { OP_DECODE("dec bp"); M.x86.R_BP = dec_word(M.x86.R_BP); } } /**************************************************************************** REMARKS: Handles opcode 0x4e ****************************************************************************/ static void x86emuOp_dec_SI(u8 op1) { if(MODE_DATA32) { OP_DECODE("dec esi"); M.x86.R_ESI = dec_long(M.x86.R_ESI); } else { OP_DECODE("dec si"); M.x86.R_SI = dec_word(M.x86.R_SI); } } /**************************************************************************** REMARKS: Handles opcode 0x4f ****************************************************************************/ static void x86emuOp_dec_DI(u8 op1) { if(MODE_DATA32) { OP_DECODE("dec edi"); M.x86.R_EDI = dec_long(M.x86.R_EDI); } else { OP_DECODE("dec di"); M.x86.R_DI = dec_word(M.x86.R_DI); } } /**************************************************************************** REMARKS: Handles opcode 0x50 ****************************************************************************/ static void x86emuOp_push_AX(u8 op1) { if(MODE_DATA32) { OP_DECODE("push eax"); push_long(M.x86.R_EAX); } else { OP_DECODE("push ax"); push_word(M.x86.R_AX); } } /**************************************************************************** REMARKS: Handles opcode 0x51 ****************************************************************************/ static void x86emuOp_push_CX(u8 op1) { if(MODE_DATA32) { OP_DECODE("push ecx"); push_long(M.x86.R_ECX); } else { OP_DECODE("push cx"); push_word(M.x86.R_CX); } } /**************************************************************************** REMARKS: Handles opcode 0x52 ****************************************************************************/ static void x86emuOp_push_DX(u8 op1) { if(MODE_DATA32) { OP_DECODE("push edx"); push_long(M.x86.R_EDX); } else { OP_DECODE("push dx"); push_word(M.x86.R_DX); } } /**************************************************************************** REMARKS: Handles opcode 0x53 ****************************************************************************/ static void x86emuOp_push_BX(u8 op1) { if(MODE_DATA32) { OP_DECODE("push ebx"); push_long(M.x86.R_EBX); } else { OP_DECODE("push bx"); push_word(M.x86.R_BX); } } /**************************************************************************** REMARKS: Handles opcode 0x54 ****************************************************************************/ static void x86emuOp_push_SP(u8 op1) { if(MODE_DATA32) { OP_DECODE("push esp"); push_long(M.x86.R_ESP); } else { OP_DECODE("push sp"); push_word(M.x86.R_SP); } } /**************************************************************************** REMARKS: Handles opcode 0x55 ****************************************************************************/ static void x86emuOp_push_BP(u8 op1) { if(MODE_DATA32) { OP_DECODE("push ebp"); push_long(M.x86.R_EBP); } else { OP_DECODE("push bp"); push_word(M.x86.R_BP); } } /**************************************************************************** REMARKS: Handles opcode 0x56 ****************************************************************************/ static void x86emuOp_push_SI(u8 op1) { if(MODE_DATA32) { OP_DECODE("push esi"); push_long(M.x86.R_ESI); } else { OP_DECODE("push si"); push_word(M.x86.R_SI); } } /**************************************************************************** REMARKS: Handles opcode 0x57 ****************************************************************************/ static void x86emuOp_push_DI(u8 op1) { if(MODE_DATA32) { OP_DECODE("push edi"); push_long(M.x86.R_EDI); } else { OP_DECODE("push di"); push_word(M.x86.R_DI); } } /**************************************************************************** REMARKS: Handles opcode 0x58 ****************************************************************************/ static void x86emuOp_pop_AX(u8 op1) { if(MODE_DATA32) { OP_DECODE("pop eax"); M.x86.R_EAX = pop_long(); } else { OP_DECODE("pop ax"); M.x86.R_AX = pop_word(); } } /**************************************************************************** REMARKS: Handles opcode 0x59 ****************************************************************************/ static void x86emuOp_pop_CX(u8 op1) { if(MODE_DATA32) { OP_DECODE("pop ecx"); M.x86.R_ECX = pop_long(); } else { OP_DECODE("pop cx"); M.x86.R_CX = pop_word(); } } /**************************************************************************** REMARKS: Handles opcode 0x5a ****************************************************************************/ static void x86emuOp_pop_DX(u8 op1) { if(MODE_DATA32) { OP_DECODE("pop edx"); M.x86.R_EDX = pop_long(); } else { OP_DECODE("pop dx"); M.x86.R_DX = pop_word(); } } /**************************************************************************** REMARKS: Handles opcode 0x5b ****************************************************************************/ static void x86emuOp_pop_BX(u8 op1) { if(MODE_DATA32) { OP_DECODE("pop ebx"); M.x86.R_EBX = pop_long(); } else { OP_DECODE("pop bx"); M.x86.R_BX = pop_word(); } } /**************************************************************************** REMARKS: Handles opcode 0x5c ****************************************************************************/ static void x86emuOp_pop_SP(u8 op1) { if(MODE_DATA32) { OP_DECODE("pop esp"); M.x86.R_ESP = pop_long(); } else { OP_DECODE("pop sp"); M.x86.R_SP = pop_word(); } } /**************************************************************************** REMARKS: Handles opcode 0x5d ****************************************************************************/ static void x86emuOp_pop_BP(u8 op1) { if(MODE_DATA32) { OP_DECODE("pop ebp"); M.x86.R_EBP = pop_long(); } else { OP_DECODE("pop bp"); M.x86.R_BP = pop_word(); } } /**************************************************************************** REMARKS: Handles opcode 0x5e ****************************************************************************/ static void x86emuOp_pop_SI(u8 op1) { if(MODE_DATA32) { OP_DECODE("pop esi"); M.x86.R_ESI = pop_long(); } else { OP_DECODE("pop si"); M.x86.R_SI = pop_word(); } } /**************************************************************************** REMARKS: Handles opcode 0x5f ****************************************************************************/ static void x86emuOp_pop_DI(u8 op1) { if(MODE_DATA32) { OP_DECODE("pop edi"); M.x86.R_EDI = pop_long(); } else { OP_DECODE("pop di"); M.x86.R_DI = pop_word(); } } /**************************************************************************** REMARKS: Handles opcode 0x60 ****************************************************************************/ static void x86emuOp_push_all(u8 op1) { u32 esp = M.x86.R_ESP; if(MODE_DATA32) { OP_DECODE("pushad"); push_long(M.x86.R_EAX); push_long(M.x86.R_ECX); push_long(M.x86.R_EDX); push_long(M.x86.R_EBX); push_long(esp); push_long(M.x86.R_EBP); push_long(M.x86.R_ESI); push_long(M.x86.R_EDI); } else { OP_DECODE("pusha"); push_word(M.x86.R_AX); push_word(M.x86.R_CX); push_word(M.x86.R_DX); push_word(M.x86.R_BX); push_word(esp); push_word(M.x86.R_BP); push_word(M.x86.R_SI); push_word(M.x86.R_DI); } } /**************************************************************************** REMARKS: Handles opcode 0x61 ****************************************************************************/ static void x86emuOp_pop_all(u8 op1) { if(MODE_DATA32) { OP_DECODE("popad"); M.x86.R_EDI = pop_long(); M.x86.R_ESI = pop_long(); M.x86.R_EBP = pop_long(); M.x86.R_ESP += 4; M.x86.R_EBX = pop_long(); M.x86.R_EDX = pop_long(); M.x86.R_ECX = pop_long(); M.x86.R_EAX = pop_long(); } else { OP_DECODE("popa"); M.x86.R_DI = pop_word(); M.x86.R_SI = pop_word(); M.x86.R_BP = pop_word(); M.x86.R_SP += 2; M.x86.R_BX = pop_word(); M.x86.R_DX = pop_word(); M.x86.R_CX = pop_word(); M.x86.R_AX = pop_word(); } } /* opcode 0x62: BOUND (not implemented) */ /* opcode 0x63: ARPL (not implemented) */ /**************************************************************************** REMARKS: Handles opcode 0x68 ****************************************************************************/ static void x86emuOp_push_word_IMM(u8 op1) { u32 imm; OP_DECODE("push "); if(MODE_DATA32) { imm = fetch_long(); DECODE_HEX8(imm); push_long(imm); } else { imm = fetch_word(); DECODE_HEX4(imm); push_word(imm); } } /**************************************************************************** REMARKS: Handles opcode 0x69 ****************************************************************************/ static void x86emuOp_imul_word_IMM(u8 op1) { int mod, rl, rh; s32 imm; u32 *src32, *dst32, val, addr, res_lo, res_hi; u16 *src16, *dst16; OP_DECODE("imul "); fetch_decode_modrm(&mod, &rh, &rl); if(mod == 3) { if(MODE_DATA32) { dst32 = decode_rm_long_register(rh); OP_DECODE(","); src32 = decode_rm_long_register(rl); imm = fetch_long(); OP_DECODE(","); DECODE_HEX8S(imm); imul_long_direct(&res_lo, &res_hi, *src32, imm); if(res_hi != 0) { SET_FLAG(F_CF); SET_FLAG(F_OF); } else { CLEAR_FLAG(F_CF); CLEAR_FLAG(F_OF); } *dst32 = res_lo; } else { dst16 = decode_rm_word_register(rh); OP_DECODE(","); src16 = decode_rm_word_register(rl); imm = (s16) fetch_word(); OP_DECODE(","); DECODE_HEX4S(imm); res_lo = (s32) ((s16) *src16 * imm); if(res_lo > 0xffff) { SET_FLAG(F_CF); SET_FLAG(F_OF); } else { CLEAR_FLAG(F_CF); CLEAR_FLAG(F_OF); } *dst16 = res_lo; } } else { if(MODE_DATA32) { dst32 = decode_rm_long_register(rh); OP_DECODE(","); addr = decode_rm_address(mod, rl); val = fetch_data_long(addr); imm = fetch_long(); OP_DECODE(","); DECODE_HEX8S(imm); imul_long_direct(&res_lo, &res_hi, val, imm); if(res_hi != 0) { SET_FLAG(F_CF); SET_FLAG(F_OF); } else { CLEAR_FLAG(F_CF); CLEAR_FLAG(F_OF); } *dst32 = res_lo; } else { dst16 = decode_rm_word_register(rh); OP_DECODE(","); addr = decode_rm_address(mod, rl); val = fetch_data_word(addr); imm = (s32) fetch_word(); OP_DECODE(","); DECODE_HEX4S(imm); res_lo = (s32) ((s16) val * imm); if(res_lo > 0xffff) { SET_FLAG(F_CF); SET_FLAG(F_OF); } else { CLEAR_FLAG(F_CF); CLEAR_FLAG(F_OF); } *dst16 = res_lo; } } } /**************************************************************************** REMARKS: Handles opcode 0x6a ****************************************************************************/ static void x86emuOp_push_byte_IMM(u8 op1) { s32 imm; OP_DECODE("push "); imm = (s8) fetch_byte(); DECODE_HEX2S(imm); if(MODE_DATA32) { push_long(imm); } else { push_word(imm); } } /**************************************************************************** REMARKS: Handles opcode 0x6b ****************************************************************************/ static void x86emuOp_imul_byte_IMM(u8 op1) { int mod, rl, rh; s32 imm; u32 *src32, *dst32, val, addr, res_lo, res_hi; u16 *src16, *dst16; OP_DECODE("imul "); fetch_decode_modrm(&mod, &rh, &rl); if(mod == 3) { if(MODE_DATA32) { dst32 = decode_rm_long_register(rh); OP_DECODE(","); src32 = decode_rm_long_register(rl); imm = (s8) fetch_byte(); OP_DECODE(","); DECODE_HEX2S(imm); imul_long_direct(&res_lo, &res_hi, *src32, imm); if(res_hi != 0) { SET_FLAG(F_CF); SET_FLAG(F_OF); } else { CLEAR_FLAG(F_CF); CLEAR_FLAG(F_OF); } *dst32 = res_lo; } else { dst16 = decode_rm_word_register(rh); OP_DECODE(","); src16 = decode_rm_word_register(rl); imm = (s8) fetch_byte(); OP_DECODE(","); DECODE_HEX2S(imm); res_lo = (s32) ((s16) *src16 * imm); if(res_lo > 0xffff) { SET_FLAG(F_CF); SET_FLAG(F_OF); } else { CLEAR_FLAG(F_CF); CLEAR_FLAG(F_OF); } *dst16 = res_lo; } } else { if(MODE_DATA32) { dst32 = decode_rm_long_register(rh); OP_DECODE(","); addr = decode_rm_address(mod, rl); val = fetch_data_long(addr); imm = (s8) fetch_byte(); OP_DECODE(","); DECODE_HEX2S(imm); imul_long_direct(&res_lo, &res_hi, val, imm); if(res_hi != 0) { SET_FLAG(F_CF); SET_FLAG(F_OF); } else { CLEAR_FLAG(F_CF); CLEAR_FLAG(F_OF); } *dst32 = res_lo; } else { dst16 = decode_rm_word_register(rh); OP_DECODE(","); addr = decode_rm_address(mod, rl); val = fetch_data_word(addr); imm = (s8) fetch_byte(); OP_DECODE(","); DECODE_HEX2S(imm); res_lo = (s32) ((s16) val * imm); if(res_lo > 0xffff) { SET_FLAG(F_CF); SET_FLAG(F_OF); } else { CLEAR_FLAG(F_CF); CLEAR_FLAG(F_OF); } *dst16 = res_lo; } } } /**************************************************************************** REMARKS: Handles opcode 0x6c ****************************************************************************/ static void x86emuOp_ins_byte(u8 op1) { if((MODE_ADDR32 && !MODE_CODE32) || (!MODE_ADDR32 && MODE_CODE32)) { /* xor */ OP_DECODE("a32 "); } OP_DECODE("insb"); ins(1); } /**************************************************************************** REMARKS: Handles opcode 0x6d ****************************************************************************/ static void x86emuOp_ins_word(u8 op1) { if((MODE_ADDR32 && !MODE_CODE32) || (!MODE_ADDR32 && MODE_CODE32)) { /* xor */ OP_DECODE("a32 "); } if(MODE_DATA32) { OP_DECODE("insd"); ins(4); } else { OP_DECODE("insw"); ins(2); } } /**************************************************************************** REMARKS: Handles opcode 0x6e ****************************************************************************/ static void x86emuOp_outs_byte(u8 op1) { if((MODE_ADDR32 && !MODE_CODE32) || (!MODE_ADDR32 && MODE_CODE32)) { /* xor */ OP_DECODE("a32 "); } OP_DECODE("outsb"); outs(1); } /**************************************************************************** REMARKS: Handles opcode 0x6f ****************************************************************************/ static void x86emuOp_outs_word(u8 op1) { if((MODE_ADDR32 && !MODE_CODE32) || (!MODE_ADDR32 && MODE_CODE32)) { /* xor */ OP_DECODE("a32 "); } if(MODE_DATA32) { OP_DECODE("outsd"); outs(4); } else { OP_DECODE("outsw"); outs(2); } } /**************************************************************************** REMARKS: Handles opcode 0x70-0x7F ****************************************************************************/ static void x86emuOp_jump_short_cc(u8 op1) { s32 ofs; u32 eip; unsigned type = op1 & 0xf; OP_DECODE("j"); decode_cond(type); ofs = (s8) fetch_byte(); eip = M.x86.R_EIP + ofs; DECODE_HEX_ADDR(eip); if(!MODE_DATA32) eip &= 0xffff; if(eval_condition(type)) M.x86.R_EIP = eip; } /**************************************************************************** REMARKS: Handles opcode 0x80 ****************************************************************************/ static void x86emuOp_opc80_byte_RM_IMM(u8 op1) { int mod, rl, rh; u8 *reg8, val, imm; u32 addr; fetch_decode_modrm(&mod, &rh, &rl); decode_op_A(rh); if(mod == 3) { reg8 = decode_rm_byte_register(rl); OP_DECODE(","); imm = fetch_byte(); DECODE_HEX2(imm); val = (*op_A_byte[rh])(*reg8, imm); if(rh != 7) *reg8 = val; } else { OP_DECODE("byte "); addr = decode_rm_address(mod, rl); OP_DECODE(","); val = fetch_data_byte(addr); imm = fetch_byte(); DECODE_HEX2(imm); val = (*op_A_byte[rh])(val, imm); if(rh != 7) store_data_byte(addr, val); } } /**************************************************************************** REMARKS: Handles opcode 0x81 ****************************************************************************/ static void x86emuOp_opc81_word_RM_IMM(u8 op1) { int mod, rl, rh; u16 *reg16; u32 *reg32, val, imm, addr; fetch_decode_modrm(&mod, &rh, &rl); decode_op_A(rh); if(mod == 3) { if(MODE_DATA32) { reg32 = decode_rm_long_register(rl); OP_DECODE(","); imm = fetch_long(); DECODE_HEX8(imm); val = (*op_A_long[rh])(*reg32, imm); if(rh != 7) *reg32 = val; } else { reg16 = decode_rm_word_register(rl); OP_DECODE(","); imm = fetch_word(); DECODE_HEX4(imm); val = (*op_A_word[rh])(*reg16, imm); if(rh != 7) *reg16 = val; } } else { if(MODE_DATA32) { OP_DECODE("dword "); addr = decode_rm_address(mod, rl); OP_DECODE(","); val = fetch_data_long(addr); imm = fetch_long(); DECODE_HEX8(imm); val = (*op_A_long[rh])(val, imm); if(rh != 7) store_data_long(addr, val); } else { OP_DECODE("word "); addr = decode_rm_address(mod, rl); OP_DECODE(","); val = fetch_data_word(addr); imm = fetch_word(); DECODE_HEX4(imm); val = (*op_A_word[rh])(val, imm); if(rh != 7) store_data_word(addr, val); } } } /* opcode 0x82: same as 0x80 */ /**************************************************************************** REMARKS: Handles opcode 0x83 ****************************************************************************/ static void x86emuOp_opc83_word_RM_IMM(u8 op1) { int mod, rl, rh; u16 *reg16; u32 *reg32, val, imm, addr; fetch_decode_modrm(&mod, &rh, &rl); decode_op_A(rh); if(mod == 3) { if(MODE_DATA32) { reg32 = decode_rm_long_register(rl); OP_DECODE(","); imm = (s8) fetch_byte(); DECODE_HEX2S(imm); val = (*op_A_long[rh])(*reg32, imm); if(rh != 7) *reg32 = val; } else { reg16 = decode_rm_word_register(rl); OP_DECODE(","); imm = (s8) fetch_byte(); DECODE_HEX2S(imm); val = (*op_A_word[rh])(*reg16, imm); if(rh != 7) *reg16 = val; } } else { if(MODE_DATA32) { OP_DECODE("dword "); addr = decode_rm_address(mod, rl); OP_DECODE(","); val = fetch_data_long(addr); imm = (s8) fetch_byte(); DECODE_HEX2S(imm); val = (*op_A_long[rh])(val, imm); if(rh != 7) store_data_long(addr, val); } else { OP_DECODE("word "); addr = decode_rm_address(mod, rl); OP_DECODE(","); val = fetch_data_word(addr); imm = (s8) fetch_byte(); DECODE_HEX2S(imm); val = (*op_A_word[rh])(val, imm); if(rh != 7) store_data_word(addr, val); } } } /**************************************************************************** REMARKS: Handles opcode 0x84 ****************************************************************************/ static void x86emuOp_test_byte_RM_R(u8 op1) { int mod, rl, rh; u8 *dst, *src, val; u32 addr; OP_DECODE("test "); fetch_decode_modrm(&mod, &rh, &rl); if(mod == 3) { dst = decode_rm_byte_register(rl); OP_DECODE(","); src = decode_rm_byte_register(rh); test_byte(*dst, *src); } else { addr = decode_rm_address(mod, rl); OP_DECODE(","); val = fetch_data_byte(addr); src = decode_rm_byte_register(rh); test_byte(val, *src); } } /**************************************************************************** REMARKS: Handles opcode 0x85 ****************************************************************************/ static void x86emuOp_test_word_RM_R(u8 op1) { int mod, rl, rh; u16 *src16, *dst16; u32 *src32, *dst32, addr, val; OP_DECODE("test "); fetch_decode_modrm(&mod, &rh, &rl); if(mod == 3) { if(MODE_DATA32) { dst32 = decode_rm_long_register(rl); OP_DECODE(","); src32 = decode_rm_long_register(rh); test_long(*dst32, *src32); } else { dst16 = decode_rm_word_register(rl); OP_DECODE(","); src16 = decode_rm_word_register(rh); test_word(*dst16, *src16); } } else { addr = decode_rm_address(mod, rl); OP_DECODE(","); if(MODE_DATA32) { val = fetch_data_long(addr); src32 = decode_rm_long_register(rh); test_long(val, *src32); } else { val = fetch_data_word(addr); src16 = decode_rm_word_register(rh); test_word(val, *src16); } } } /**************************************************************************** REMARKS: Handles opcode 0x86 ****************************************************************************/ static void x86emuOp_xchg_byte_RM_R(u8 op1) { int mod, rl, rh; u8 *dst, *src, val; u32 addr; OP_DECODE("xchg "); fetch_decode_modrm(&mod, &rh, &rl); if(mod == 3) { dst = decode_rm_byte_register(rl); OP_DECODE(","); src = decode_rm_byte_register(rh); val = *src; *src = *dst; *dst = val; } else { addr = decode_rm_address(mod, rl); OP_DECODE(","); val = fetch_data_byte(addr); src = decode_rm_byte_register(rh); store_data_byte(addr, *src); *src = val; } } /**************************************************************************** REMARKS: Handles opcode 0x87 ****************************************************************************/ static void x86emuOp_xchg_word_RM_R(u8 op1) { int mod, rl, rh; u16 *src16, *dst16; u32 *src32, *dst32, addr, val; OP_DECODE("xchg "); fetch_decode_modrm(&mod, &rh, &rl); if(mod == 3) { if(MODE_DATA32) { dst32 = decode_rm_long_register(rl); OP_DECODE(","); src32 = decode_rm_long_register(rh); val = *src32; *src32 = *dst32; *dst32 = val; } else { dst16 = decode_rm_word_register(rl); OP_DECODE(","); src16 = decode_rm_word_register(rh); val = *src16; *src16 = *dst16; *dst16 = val; } } else { addr = decode_rm_address(mod, rl); OP_DECODE(","); if(MODE_DATA32) { val = fetch_data_long(addr); src32 = decode_rm_long_register(rh); store_data_long(addr, *src32); *src32 = val; } else { val = fetch_data_word(addr); src16 = decode_rm_word_register(rh); store_data_word(addr, *src16); *src16 = val; } } } /**************************************************************************** REMARKS: Handles opcode 0x88 ****************************************************************************/ static void x86emuOp_mov_byte_RM_R(u8 op1) { int mod, rl, rh; u8 *dst, *src; u32 addr; OP_DECODE("mov "); fetch_decode_modrm(&mod, &rh, &rl); if(mod == 3) { dst = decode_rm_byte_register(rl); OP_DECODE(","); src = decode_rm_byte_register(rh); *dst = *src; } else { addr = decode_rm_address(mod, rl); OP_DECODE(","); src = decode_rm_byte_register(rh); store_data_byte(addr, *src); } } /**************************************************************************** REMARKS: Handles opcode 0x89 ****************************************************************************/ static void x86emuOp_mov_word_RM_R(u8 op1) { int mod, rl, rh; u16 *src16, *dst16; u32 *src32, *dst32, addr; OP_DECODE("mov "); fetch_decode_modrm(&mod, &rh, &rl); if(mod == 3) { if(MODE_DATA32) { dst32 = decode_rm_long_register(rl); OP_DECODE(","); src32 = decode_rm_long_register(rh); *dst32 = *src32; } else { dst16 = decode_rm_word_register(rl); OP_DECODE(","); src16 = decode_rm_word_register(rh); *dst16 = *src16; } } else { addr = decode_rm_address(mod, rl); OP_DECODE(","); if(MODE_DATA32) { src32 = decode_rm_long_register(rh); store_data_long(addr, *src32); } else { src16 = decode_rm_word_register(rh); store_data_word(addr, *src16); } } } /**************************************************************************** REMARKS: Handles opcode 0x8a ****************************************************************************/ static void x86emuOp_mov_byte_R_RM(u8 op1) { int mod, rl, rh; u8 *dst, *src; u32 addr; OP_DECODE("mov "); fetch_decode_modrm(&mod, &rh, &rl); if(mod == 3) { dst = decode_rm_byte_register(rh); OP_DECODE(","); src = decode_rm_byte_register(rl); *dst = *src; } else { dst = decode_rm_byte_register(rh); OP_DECODE(","); addr = decode_rm_address(mod, rl); *dst = fetch_data_byte(addr); } } /**************************************************************************** REMARKS: Handles opcode 0x8b ****************************************************************************/ static void x86emuOp_mov_word_R_RM(u8 op1) { int mod, rl, rh; u16 *src16, *dst16; u32 *src32, *dst32, addr; OP_DECODE("mov "); fetch_decode_modrm(&mod, &rh, &rl); if(mod == 3) { if(MODE_DATA32) { dst32 = decode_rm_long_register(rh); OP_DECODE(","); src32 = decode_rm_long_register(rl); *dst32 = *src32; } else { dst16 = decode_rm_word_register(rh); OP_DECODE(","); src16 = decode_rm_word_register(rl); *dst16 = *src16; } } else { if(MODE_DATA32) { dst32 = decode_rm_long_register(rh); OP_DECODE(","); addr = decode_rm_address(mod, rl); *dst32 = fetch_data_long(addr); } else { dst16 = decode_rm_word_register(rh); OP_DECODE(","); addr = decode_rm_address(mod, rl); *dst16 = fetch_data_word(addr); } } } /**************************************************************************** REMARKS: Handles opcode 0x8c ****************************************************************************/ static void x86emuOp_mov_word_RM_SR(u8 op1) { int mod, rl, rh; u16 *reg16, val; u32 *reg32, addr; OP_DECODE("mov "); fetch_decode_modrm(&mod, &rh, &rl); if(mod == 3) { /* register */ if(MODE_DATA32) { reg32 = decode_rm_long_register(rl); OP_DECODE(","); *reg32 = decode_rm_seg_register(rh)->sel; } else { reg16 = decode_rm_word_register(rl); OP_DECODE(","); *reg16 = decode_rm_seg_register(rh)->sel; } } else { /* memory */ addr = decode_rm_address(mod, rl); OP_DECODE(","); val = decode_rm_seg_register(rh)->sel; store_data_word(addr, val); } } /**************************************************************************** REMARKS: Handles opcode 0x8d ****************************************************************************/ static void x86emuOp_lea_word_R_M(u8 op1) { int mod, rl, rh; u16 *reg16; u32 *reg32, addr; OP_DECODE("lea "); fetch_decode_modrm(&mod, &rh, &rl); if(mod == 3) { INTR_RAISE_UD(&M); } else { if(MODE_DATA32) { reg32 = decode_rm_long_register(rh); OP_DECODE(","); addr = decode_rm_address(mod, rl); *reg32 = addr; } else { reg16 = decode_rm_word_register(rh); OP_DECODE(","); addr = decode_rm_address(mod, rl); *reg16 = addr; } } } /**************************************************************************** REMARKS: Handles opcode 0x8e ****************************************************************************/ static void x86emuOp_mov_word_SR_RM(u8 op1) { int mod, rl, rh; u16 val; sel_t *seg; OP_DECODE("mov "); fetch_decode_modrm(&mod, &rh, &rl); seg = decode_rm_seg_register(rh); OP_DECODE(","); if(mod == 3) { /* register */ val = *decode_rm_word_register(rl); } else { /* memory */ val = fetch_data_word(decode_rm_address(mod, rl)); } x86emu_set_seg_register(&M, seg, val); } /**************************************************************************** REMARKS: Handles opcode 0x8f ****************************************************************************/ static void x86emuOp_pop_RM(u8 op1) { int mod, rl, rh; u16 *reg16; u32 *reg32, addr, val; OP_DECODE("pop "); fetch_decode_modrm(&mod, &rh, &rl); if(rh != 0) { INTR_RAISE_UD(&M); return; } if(mod == 3) { if(MODE_DATA32) { reg32 = decode_rm_long_register(rl); *reg32 = pop_long(); } else { reg16 = decode_rm_word_register(rl); *reg16 = pop_word(); } } else { addr = decode_rm_address(mod, rl); if(MODE_DATA32) { val = pop_long(); store_data_long(addr, val); } else { val = pop_word(); store_data_word(addr, val); } } } /**************************************************************************** REMARKS: Handles opcode 0x90 ****************************************************************************/ static void x86emuOp_nop(u8 op1) { OP_DECODE("nop"); } /**************************************************************************** REMARKS: Handles opcode 0x91 ****************************************************************************/ static void x86emuOp_xchg_word_AX_CX(u8 op1) { u32 val; if(MODE_DATA32) { OP_DECODE("xchg eax,ecx"); val = M.x86.R_EAX; M.x86.R_EAX = M.x86.R_ECX; M.x86.R_ECX = val; } else { OP_DECODE("xchg ax,cx"); val = M.x86.R_AX; M.x86.R_AX = M.x86.R_CX; M.x86.R_CX = val; } } /**************************************************************************** REMARKS: Handles opcode 0x92 ****************************************************************************/ static void x86emuOp_xchg_word_AX_DX(u8 op1) { u32 val; if(MODE_DATA32) { OP_DECODE("xchg eax,edx"); val = M.x86.R_EAX; M.x86.R_EAX = M.x86.R_EDX; M.x86.R_EDX = val; } else { OP_DECODE("xchg ax,dx"); val = M.x86.R_AX; M.x86.R_AX = M.x86.R_DX; M.x86.R_DX = val; } } /**************************************************************************** REMARKS: Handles opcode 0x93 ****************************************************************************/ static void x86emuOp_xchg_word_AX_BX(u8 op1) { u32 val; if(MODE_DATA32) { OP_DECODE("xchg eax,ebx"); val = M.x86.R_EAX; M.x86.R_EAX = M.x86.R_EBX; M.x86.R_EBX = val; } else { OP_DECODE("xchg ax,bx"); val = M.x86.R_AX; M.x86.R_AX = M.x86.R_BX; M.x86.R_BX = val; } } /**************************************************************************** REMARKS: Handles opcode 0x94 ****************************************************************************/ static void x86emuOp_xchg_word_AX_SP(u8 op1) { u32 val; if(MODE_DATA32) { OP_DECODE("xchg eax,esp"); val = M.x86.R_EAX; M.x86.R_EAX = M.x86.R_ESP; M.x86.R_ESP = val; } else { OP_DECODE("xchg ax,sp"); val = M.x86.R_AX; M.x86.R_AX = M.x86.R_SP; M.x86.R_SP = val; } } /**************************************************************************** REMARKS: Handles opcode 0x95 ****************************************************************************/ static void x86emuOp_xchg_word_AX_BP(u8 op1) { u32 val; if(MODE_DATA32) { OP_DECODE("xchg eax,ebp"); val = M.x86.R_EAX; M.x86.R_EAX = M.x86.R_EBP; M.x86.R_EBP = val; } else { OP_DECODE("xchg ax,bp"); val = M.x86.R_AX; M.x86.R_AX = M.x86.R_BP; M.x86.R_BP = val; } } /**************************************************************************** REMARKS: Handles opcode 0x96 ****************************************************************************/ static void x86emuOp_xchg_word_AX_SI(u8 op1) { u32 val; if(MODE_DATA32) { OP_DECODE("xchg eax,esi"); val = M.x86.R_EAX; M.x86.R_EAX = M.x86.R_ESI; M.x86.R_ESI = val; } else { OP_DECODE("xchg ax,si"); val = M.x86.R_AX; M.x86.R_AX = M.x86.R_SI; M.x86.R_SI = val; } } /**************************************************************************** REMARKS: Handles opcode 0x97 ****************************************************************************/ static void x86emuOp_xchg_word_AX_DI(u8 op1) { u32 val; if(MODE_DATA32) { OP_DECODE("xchg eax,edi"); val = M.x86.R_EAX; M.x86.R_EAX = M.x86.R_EDI; M.x86.R_EDI = val; } else { OP_DECODE("xchg ax,di"); val = M.x86.R_AX; M.x86.R_AX = M.x86.R_DI; M.x86.R_DI = val; } } /**************************************************************************** REMARKS: Handles opcode 0x98 ****************************************************************************/ static void x86emuOp_cbw(u8 op1) { if(MODE_DATA32) { OP_DECODE("cwde"); M.x86.R_EAX = (s16) M.x86.R_AX; } else { OP_DECODE("cbw"); M.x86.R_AX = (s8) M.x86.R_AL; } } /**************************************************************************** REMARKS: Handles opcode 0x99 ****************************************************************************/ static void x86emuOp_cwd(u8 op1) { if(MODE_DATA32) { OP_DECODE("cdq"); M.x86.R_EDX = - (M.x86.R_EAX >> 31); } else { OP_DECODE("cwd"); M.x86.R_DX = - (M.x86.R_AX >> 15); } } /**************************************************************************** REMARKS: Handles opcode 0x9a ****************************************************************************/ static void x86emuOp_call_far_IMM(u8 op1) { u16 cs; u32 eip; OP_DECODE("call far "); eip = MODE_DATA32 ? fetch_long() : fetch_word(); cs = fetch_word(); DECODE_HEX4(cs); OP_DECODE(":"); if(MODE_DATA32) { DECODE_HEX8(eip); push_long(M.x86.R_CS); push_long(M.x86.R_EIP); } else { DECODE_HEX4(eip); push_word(M.x86.R_CS); push_word(M.x86.R_IP); } x86emu_set_seg_register(&M, M.x86.R_CS_SEL, cs); M.x86.R_EIP = eip; } /**************************************************************************** REMARKS: Handles opcode 0x9b ****************************************************************************/ static void x86emuOp_wait(u8 op1) { OP_DECODE("wait"); } /**************************************************************************** REMARKS: Handles opcode 0x9c ****************************************************************************/ static void x86emuOp_pushf_word(u8 op1) { u32 flags; /* clear out *all* bits not representing flags, and turn on real bits */ flags = (M.x86.R_EFLG & F_MSK) | F_ALWAYS_ON; if(MODE_DATA32) { OP_DECODE("pushfd"); push_long(flags); } else { OP_DECODE("pushf"); push_word(flags); } } /**************************************************************************** REMARKS: Handles opcode 0x9d ****************************************************************************/ static void x86emuOp_popf_word(u8 op1) { if(MODE_DATA32) { OP_DECODE("popfd"); M.x86.R_EFLG = pop_long() | F_ALWAYS_ON; } else { OP_DECODE("popf"); M.x86.R_FLG = pop_word() | F_ALWAYS_ON; } } /**************************************************************************** REMARKS: Handles opcode 0x9e ****************************************************************************/ static void x86emuOp_sahf(u8 op1) { OP_DECODE("sahf"); M.x86.R_FLG &= 0xffffff00; M.x86.R_FLG |= (M.x86.R_AH | F_ALWAYS_ON) & 0xff; } /**************************************************************************** REMARKS: Handles opcode 0x9f ****************************************************************************/ static void x86emuOp_lahf(u8 op1) { OP_DECODE("lahf"); M.x86.R_AH = M.x86.R_FLG | F_ALWAYS_ON; } /**************************************************************************** REMARKS: Handles opcode 0xa0 ****************************************************************************/ static void x86emuOp_mov_AL_M_IMM(u8 op1) { u32 addr; OP_DECODE("mov al,["); if(MODE_ADDR32) { addr = fetch_long(); DECODE_HEX8(addr); } else { addr = fetch_word(); DECODE_HEX4(addr); } OP_DECODE("]"); M.x86.R_AL = fetch_data_byte(addr); } /**************************************************************************** REMARKS: Handles opcode 0xa1 ****************************************************************************/ static void x86emuOp_mov_AX_M_IMM(u8 op1) { u32 addr; if(MODE_DATA32) { OP_DECODE("mov eax,["); } else { OP_DECODE("mov ax,["); } if(MODE_ADDR32) { addr = fetch_long(); DECODE_HEX8(addr); } else { addr = fetch_word(); DECODE_HEX4(addr); } OP_DECODE("]"); if(MODE_DATA32) { M.x86.R_EAX = fetch_data_long(addr); } else { M.x86.R_AX = fetch_data_word(addr); } } /**************************************************************************** REMARKS: Handles opcode 0xa2 ****************************************************************************/ static void x86emuOp_mov_M_AL_IMM(u8 op1) { u32 addr; OP_DECODE("mov ["); if(MODE_ADDR32) { addr = fetch_long(); DECODE_HEX8(addr); } else { addr = fetch_word(); DECODE_HEX4(addr); } OP_DECODE("],al"); store_data_byte(addr, M.x86.R_AL); } /**************************************************************************** REMARKS: Handles opcode 0xa3 ****************************************************************************/ static void x86emuOp_mov_M_AX_IMM(u8 op1) { u32 addr; OP_DECODE("mov ["); if(MODE_ADDR32) { addr = fetch_long(); DECODE_HEX8(addr); } else { addr = fetch_word(); DECODE_HEX4(addr); } if(MODE_DATA32) { OP_DECODE("],eax"); store_data_long(addr, M.x86.R_EAX); } else { OP_DECODE("],ax"); store_data_word(addr, M.x86.R_AX); } } /**************************************************************************** REMARKS: Handles opcode 0xa4 ****************************************************************************/ static void x86emuOp_movs_byte(u8 op1) { u8 val; u32 count; s32 inc; inc = ACCESS_FLAG(F_DF) ? -1 : 1; /* direction */ count = 1; if(MODE_ADDR32) { if(!MODE_CODE32) OP_DECODE("a32 "); OP_DECODE("movsb"); if(MODE_REP) { count = M.x86.R_ECX; M.x86.R_ECX = 0; } while(count--) { val = fetch_data_byte(M.x86.R_ESI); store_data_byte_abs(M.x86.seg + R_ES_INDEX, M.x86.R_EDI, val); M.x86.R_ESI += inc; M.x86.R_EDI += inc; } } else { if(MODE_CODE32) OP_DECODE("a32 "); OP_DECODE("movsb"); if(MODE_REP) { /* dont care whether REPE or REPNE */ /* move them until CX is ZERO. */ count = M.x86.R_CX; M.x86.R_CX = 0; } while(count--) { val = fetch_data_byte(M.x86.R_SI); store_data_byte_abs(M.x86.seg + R_ES_INDEX, M.x86.R_DI, val); M.x86.R_SI += inc; M.x86.R_DI += inc; } } } /**************************************************************************** REMARKS: Handles opcode 0xa5 ****************************************************************************/ static void x86emuOp_movs_word(u8 op1) { u32 val, count; s32 inc; if((MODE_ADDR32 && !MODE_CODE32) || (!MODE_ADDR32 && MODE_CODE32)) { /* xor */ OP_DECODE("a32 "); } if(MODE_DATA32) { OP_DECODE("movsd"); inc = ACCESS_FLAG(F_DF) ? -4 : 4; } else { OP_DECODE("movsw"); inc = ACCESS_FLAG(F_DF) ? -2 : 2; } count = 1; if(MODE_ADDR32) { if(MODE_REP) { count = M.x86.R_ECX; M.x86.R_ECX = 0; } while(count--) { if(MODE_DATA32) { val = fetch_data_long(M.x86.R_ESI); store_data_long_abs(M.x86.seg + R_ES_INDEX, M.x86.R_EDI, val); } else { val = fetch_data_word(M.x86.R_ESI); store_data_word_abs(M.x86.seg + R_ES_INDEX, M.x86.R_EDI, val); } M.x86.R_ESI += inc; M.x86.R_EDI += inc; } } else { if(MODE_REP) { /* dont care whether REPE or REPNE */ /* move them until CX is ZERO. */ count = M.x86.R_CX; M.x86.R_CX = 0; } while(count--) { if(MODE_DATA32) { val = fetch_data_long(M.x86.R_SI); store_data_long_abs(M.x86.seg + R_ES_INDEX, M.x86.R_DI, val); } else { val = fetch_data_word(M.x86.R_SI); store_data_word_abs(M.x86.seg + R_ES_INDEX, M.x86.R_DI, val); } M.x86.R_SI += inc; M.x86.R_DI += inc; } } } /**************************************************************************** REMARKS: Handles opcode 0xa6 ****************************************************************************/ static void x86emuOp_cmps_byte(u8 op1) { u8 val1, val2; s32 inc; unsigned cond; inc = ACCESS_FLAG(F_DF) ? -1 : 1; cond = MODE_REPE ? (2 << 1) + 1 /* NZ */ : (2 << 1) /* Z */; if(MODE_ADDR32) { if(!MODE_CODE32) OP_DECODE("a32 "); OP_DECODE("cmpsb"); if(MODE_REP) { while(M.x86.R_ECX) { val1 = fetch_data_byte(M.x86.R_ESI); val2 = fetch_data_byte_abs(M.x86.seg + R_ES_INDEX, M.x86.R_EDI); cmp_byte(val1, val2); M.x86.R_ECX--; M.x86.R_ESI += inc; M.x86.R_EDI += inc; if(eval_condition(cond)) break; } } else { val1 = fetch_data_byte(M.x86.R_ESI); val2 = fetch_data_byte_abs(M.x86.seg + R_ES_INDEX, M.x86.R_EDI); cmp_byte(val1, val2); M.x86.R_ESI += inc; M.x86.R_EDI += inc; } } else { if(MODE_CODE32) OP_DECODE("a32 "); OP_DECODE("cmpsb"); if(MODE_REP) { while(M.x86.R_CX) { val1 = fetch_data_byte(M.x86.R_SI); val2 = fetch_data_byte_abs(M.x86.seg + R_ES_INDEX, M.x86.R_DI); cmp_byte(val1, val2); M.x86.R_CX--; M.x86.R_SI += inc; M.x86.R_DI += inc; if(eval_condition(cond)) break; } } else { val1 = fetch_data_byte(M.x86.R_SI); val2 = fetch_data_byte_abs(M.x86.seg + R_ES_INDEX, M.x86.R_DI); cmp_byte(val1, val2); M.x86.R_SI += inc; M.x86.R_DI += inc; } } } /**************************************************************************** REMARKS: Handles opcode 0xa7 ****************************************************************************/ static void x86emuOp_cmps_word(u8 op1) { u32 val1, val2; s32 inc; unsigned cond; if((MODE_ADDR32 && !MODE_CODE32) || (!MODE_ADDR32 && MODE_CODE32)) { /* xor */ OP_DECODE("a32 "); } if(MODE_DATA32) { OP_DECODE("cmpsd"); inc = ACCESS_FLAG(F_DF) ? -4 : 4; } else { OP_DECODE("cmpsw"); inc = ACCESS_FLAG(F_DF) ? -2 : 2; } cond = MODE_REPE ? (2 << 1) + 1 /* NZ */ : (2 << 1) /* Z */; if(MODE_ADDR32) { if(MODE_REP) { while(M.x86.R_ECX) { if(MODE_DATA32) { val1 = fetch_data_long(M.x86.R_ESI); val2 = fetch_data_long_abs(M.x86.seg + R_ES_INDEX, M.x86.R_EDI); cmp_long(val1, val2); } else { val1 = fetch_data_word(M.x86.R_ESI); val2 = fetch_data_word_abs(M.x86.seg + R_ES_INDEX, M.x86.R_EDI); cmp_word(val1, val2); } M.x86.R_ECX--; M.x86.R_ESI += inc; M.x86.R_EDI += inc; if(eval_condition(cond)) break; } } else { if(MODE_DATA32) { val1 = fetch_data_long(M.x86.R_ESI); val2 = fetch_data_long_abs(M.x86.seg + R_ES_INDEX, M.x86.R_EDI); cmp_long(val1, val2); } else { val1 = fetch_data_word(M.x86.R_ESI); val2 = fetch_data_word_abs(M.x86.seg + R_ES_INDEX, M.x86.R_EDI); cmp_word(val1, val2); } M.x86.R_ESI += inc; M.x86.R_EDI += inc; } } else { if(MODE_REP) { while(M.x86.R_CX) { if(MODE_DATA32) { val1 = fetch_data_long(M.x86.R_SI); val2 = fetch_data_long_abs(M.x86.seg + R_ES_INDEX, M.x86.R_DI); cmp_long(val1, val2); } else { val1 = fetch_data_word(M.x86.R_SI); val2 = fetch_data_word_abs(M.x86.seg + R_ES_INDEX, M.x86.R_DI); cmp_word(val1, val2); } M.x86.R_CX--; M.x86.R_SI += inc; M.x86.R_DI += inc; if(eval_condition(cond)) break; } } else { if(MODE_DATA32) { val1 = fetch_data_long(M.x86.R_SI); val2 = fetch_data_long_abs(M.x86.seg + R_ES_INDEX, M.x86.R_DI); cmp_long(val1, val2); } else { val1 = fetch_data_word(M.x86.R_SI); val2 = fetch_data_word_abs(M.x86.seg + R_ES_INDEX, M.x86.R_DI); cmp_word(val1, val2); } M.x86.R_SI += inc; M.x86.R_DI += inc; } } } /**************************************************************************** REMARKS: Handles opcode 0xa8 ****************************************************************************/ static void x86emuOp_test_AL_IMM(u8 op1) { u8 imm; OP_DECODE("test al,"); imm = fetch_byte(); DECODE_HEX2(imm); test_byte(M.x86.R_AL, imm); } /**************************************************************************** REMARKS: Handles opcode 0xa9 ****************************************************************************/ static void x86emuOp_test_AX_IMM(u8 op1) { u32 imm; if(MODE_DATA32) { OP_DECODE("test eax,"); imm = fetch_long(); DECODE_HEX8(imm); test_long(M.x86.R_EAX, imm); } else { OP_DECODE("test ax,"); imm = fetch_word(); DECODE_HEX4(imm); test_word(M.x86.R_AX, imm); } } /**************************************************************************** REMARKS: Handles opcode 0xaa ****************************************************************************/ static void x86emuOp_stos_byte(u8 op1) { s32 inc; u32 count; u8 val; inc = ACCESS_FLAG(F_DF) ? -1 : 1; val = M.x86.R_AL; count = 1; if(MODE_ADDR32) { if(!MODE_CODE32) OP_DECODE("a32 "); OP_DECODE("stosb"); if(MODE_REP) { count = M.x86.R_ECX; M.x86.R_ECX = 0; } while(count--) { store_data_byte_abs(M.x86.seg + R_ES_INDEX, M.x86.R_EDI, val); M.x86.R_EDI += inc; } } else { if(MODE_CODE32) OP_DECODE("a32 "); OP_DECODE("stosb"); if(MODE_REP) { count = M.x86.R_CX; M.x86.R_CX = 0; } while(count--) { store_data_byte_abs(M.x86.seg + R_ES_INDEX, M.x86.R_DI, val); M.x86.R_DI += inc; } } } /**************************************************************************** REMARKS: Handles opcode 0xab ****************************************************************************/ static void x86emuOp_stos_word(u8 op1) { s32 inc; u32 count, val; if((MODE_ADDR32 && !MODE_CODE32) || (!MODE_ADDR32 && MODE_CODE32)) { /* xor */ OP_DECODE("a32 "); } if(MODE_DATA32) { OP_DECODE("stosd"); inc = ACCESS_FLAG(F_DF) ? -4 : 4; } else { OP_DECODE("stosw"); inc = ACCESS_FLAG(F_DF) ? -2 : 2; } val = M.x86.R_EAX; count = 1; if(MODE_ADDR32) { if(MODE_REP) { count = M.x86.R_ECX; M.x86.R_ECX = 0; } while(count--) { if(MODE_DATA32) { store_data_long_abs(M.x86.seg + R_ES_INDEX, M.x86.R_EDI, val); } else { store_data_word_abs(M.x86.seg + R_ES_INDEX, M.x86.R_EDI, val); } M.x86.R_EDI += inc; } } else { if(MODE_REP) { count = M.x86.R_CX; M.x86.R_CX = 0; } while(count--) { if(MODE_DATA32) { store_data_long_abs(M.x86.seg + R_ES_INDEX, M.x86.R_DI, val); } else { store_data_word_abs(M.x86.seg + R_ES_INDEX, M.x86.R_DI, val); } M.x86.R_DI += inc; } } } /**************************************************************************** REMARKS: Handles opcode 0xac ****************************************************************************/ static void x86emuOp_lods_byte(u8 op1) { s32 inc; u32 count; inc = ACCESS_FLAG(F_DF) ? -1 : 1; count = 1; if(MODE_ADDR32) { if(!MODE_CODE32) OP_DECODE("a32 "); OP_DECODE("lodsb"); if(MODE_REP) { count = M.x86.R_ECX; M.x86.R_ECX = 0; } while(count--) { M.x86.R_AL = fetch_data_byte(M.x86.R_ESI); M.x86.R_ESI += inc; } } else { if(MODE_CODE32) OP_DECODE("a32 "); OP_DECODE("lodsb"); if(MODE_REP) { count = M.x86.R_CX; M.x86.R_CX = 0; } while(count--) { M.x86.R_AL = fetch_data_byte(M.x86.R_SI); M.x86.R_SI += inc; } } } /**************************************************************************** REMARKS: Handles opcode 0xad ****************************************************************************/ static void x86emuOp_lods_word(u8 op1) { s32 inc; u32 count; if((MODE_ADDR32 && !MODE_CODE32) || (!MODE_ADDR32 && MODE_CODE32)) { /* xor */ OP_DECODE("a32 "); } if(MODE_DATA32) { OP_DECODE("lodsd"); inc = ACCESS_FLAG(F_DF) ? -4 : 4; } else { OP_DECODE("lodsw"); inc = ACCESS_FLAG(F_DF) ? -2 : 2; } count = 1; if(MODE_ADDR32) { if(MODE_REP) { count = M.x86.R_ECX; M.x86.R_ECX = 0; } while(count--) { if(MODE_DATA32) { M.x86.R_EAX = fetch_data_long(M.x86.R_ESI); } else { M.x86.R_AX = fetch_data_word(M.x86.R_ESI); } M.x86.R_ESI += inc; } } else { if(MODE_REP) { count = M.x86.R_CX; M.x86.R_CX = 0; } while(count--) { if(MODE_DATA32) { M.x86.R_EAX = fetch_data_long(M.x86.R_SI); } else { M.x86.R_AX = fetch_data_word(M.x86.R_SI); } M.x86.R_SI += inc; } } } /**************************************************************************** REMARKS: Handles opcode 0xae ****************************************************************************/ static void x86emuOp_scas_byte(u8 op1) { s8 val; s32 inc; unsigned cond; inc = ACCESS_FLAG(F_DF) ? -1 : 1; cond = MODE_REPE ? (2 << 1) + 1 /* NZ */ : (2 << 1) /* Z */; if(MODE_ADDR32) { if(!MODE_CODE32) OP_DECODE("a32 "); OP_DECODE("scasb"); if(MODE_REP) { while(M.x86.R_ECX) { val = fetch_data_byte_abs(M.x86.seg + R_ES_INDEX, M.x86.R_EDI); cmp_byte(M.x86.R_AL, val); M.x86.R_ECX--; M.x86.R_EDI += inc; if(eval_condition(cond)) break; } } else { val = fetch_data_byte_abs(M.x86.seg + R_ES_INDEX, M.x86.R_EDI); cmp_byte(M.x86.R_AL, val); M.x86.R_EDI += inc; } } else { if(MODE_CODE32) OP_DECODE("a32 "); OP_DECODE("scasb"); if(MODE_REP) { while(M.x86.R_CX) { val = fetch_data_byte_abs(M.x86.seg + R_ES_INDEX, M.x86.R_DI); cmp_byte(M.x86.R_AL, val); M.x86.R_CX--; M.x86.R_DI += inc; if(eval_condition(cond)) break; } } else { val = fetch_data_byte_abs(M.x86.seg + R_ES_INDEX, M.x86.R_DI); cmp_byte(M.x86.R_AL, val); M.x86.R_DI += inc; } } } /**************************************************************************** REMARKS: Handles opcode 0xaf ****************************************************************************/ static void x86emuOp_scas_word(u8 op1) { s32 inc; u32 val; unsigned cond; if((MODE_ADDR32 && !MODE_CODE32) || (!MODE_ADDR32 && MODE_CODE32)) { /* xor */ OP_DECODE("a32 "); } if(MODE_DATA32) { OP_DECODE("scasd"); inc = ACCESS_FLAG(F_DF) ? -4 : 4; } else { OP_DECODE("scasw"); inc = ACCESS_FLAG(F_DF) ? -2 : 2; } cond = MODE_REPE ? (2 << 1) + 1 /* NZ */ : (2 << 1) /* Z */; if(MODE_ADDR32) { if(MODE_REP) { while(M.x86.R_ECX) { if(MODE_DATA32) { val = fetch_data_long_abs(M.x86.seg + R_ES_INDEX, M.x86.R_EDI); cmp_long(M.x86.R_EAX, val); } else { val = fetch_data_word_abs(M.x86.seg + R_ES_INDEX, M.x86.R_EDI); cmp_word(M.x86.R_AX, val); } M.x86.R_ECX--; M.x86.R_EDI += inc; if(eval_condition(cond)) break; } } else { if(MODE_DATA32) { val = fetch_data_long_abs(M.x86.seg + R_ES_INDEX, M.x86.R_EDI); cmp_long(M.x86.R_EAX, val); } else { val = fetch_data_word_abs(M.x86.seg + R_ES_INDEX, M.x86.R_EDI); cmp_word(M.x86.R_AX, val); } M.x86.R_EDI += inc; } } else { if(MODE_REP) { while(M.x86.R_CX) { if(MODE_DATA32) { val = fetch_data_long_abs(M.x86.seg + R_ES_INDEX, M.x86.R_DI); cmp_long(M.x86.R_EAX, val); } else { val = fetch_data_word_abs(M.x86.seg + R_ES_INDEX, M.x86.R_DI); cmp_word(M.x86.R_AX, val); } M.x86.R_CX--; M.x86.R_DI += inc; if(eval_condition(cond)) break; } } else { if(MODE_DATA32) { val = fetch_data_long_abs(M.x86.seg + R_ES_INDEX, M.x86.R_DI); cmp_long(M.x86.R_EAX, val); } else { val = fetch_data_word_abs(M.x86.seg + R_ES_INDEX, M.x86.R_DI); cmp_word(M.x86.R_AX, val); } M.x86.R_DI += inc; } } } /**************************************************************************** REMARKS: Handles opcode 0xb0 ****************************************************************************/ static void x86emuOp_mov_byte_AL_IMM(u8 op1) { u8 val; OP_DECODE("mov al,"); val = fetch_byte(); DECODE_HEX2(val); M.x86.R_AL = val; } /**************************************************************************** REMARKS: Handles opcode 0xb1 ****************************************************************************/ static void x86emuOp_mov_byte_CL_IMM(u8 op1) { u8 val; OP_DECODE("mov cl,"); val = fetch_byte(); DECODE_HEX2(val); M.x86.R_CL = val; } /**************************************************************************** REMARKS: Handles opcode 0xb2 ****************************************************************************/ static void x86emuOp_mov_byte_DL_IMM(u8 op1) { u8 val; OP_DECODE("mov dl,"); val = fetch_byte(); DECODE_HEX2(val); M.x86.R_DL = val; } /**************************************************************************** REMARKS: Handles opcode 0xb3 ****************************************************************************/ static void x86emuOp_mov_byte_BL_IMM(u8 op1) { u8 val; OP_DECODE("mov bl,"); val = fetch_byte(); DECODE_HEX2(val); M.x86.R_BL = val; } /**************************************************************************** REMARKS: Handles opcode 0xb4 ****************************************************************************/ static void x86emuOp_mov_byte_AH_IMM(u8 op1) { u8 val; OP_DECODE("mov ah,"); val = fetch_byte(); DECODE_HEX2(val); M.x86.R_AH = val; } /**************************************************************************** REMARKS: Handles opcode 0xb5 ****************************************************************************/ static void x86emuOp_mov_byte_CH_IMM(u8 op1) { u8 val; OP_DECODE("mov ch,"); val = fetch_byte(); DECODE_HEX2(val); M.x86.R_CH = val; } /**************************************************************************** REMARKS: Handles opcode 0xb6 ****************************************************************************/ static void x86emuOp_mov_byte_DH_IMM(u8 op1) { u8 val; OP_DECODE("mov dh,"); val = fetch_byte(); DECODE_HEX2(val); M.x86.R_DH = val; } /**************************************************************************** REMARKS: Handles opcode 0xb7 ****************************************************************************/ static void x86emuOp_mov_byte_BH_IMM(u8 op1) { u8 val; OP_DECODE("mov bh,"); val = fetch_byte(); DECODE_HEX2(val); M.x86.R_BH = val; } /**************************************************************************** REMARKS: Handles opcode 0xb8 ****************************************************************************/ static void x86emuOp_mov_word_AX_IMM(u8 op1) { u32 val; if(MODE_DATA32) { OP_DECODE("mov eax,"); val = fetch_long(); DECODE_HEX8(val); M.x86.R_EAX = val; } else { OP_DECODE("mov ax,"); val = fetch_word(); DECODE_HEX4(val); M.x86.R_AX = val; } } /**************************************************************************** REMARKS: Handles opcode 0xb9 ****************************************************************************/ static void x86emuOp_mov_word_CX_IMM(u8 op1) { u32 val; if(MODE_DATA32) { OP_DECODE("mov ecx,"); val = fetch_long(); DECODE_HEX8(val); M.x86.R_ECX = val; } else { OP_DECODE("mov cx,"); val = fetch_word(); DECODE_HEX4(val); M.x86.R_CX = val; } } /**************************************************************************** REMARKS: Handles opcode 0xba ****************************************************************************/ static void x86emuOp_mov_word_DX_IMM(u8 op1) { u32 val; if(MODE_DATA32) { OP_DECODE("mov edx,"); val = fetch_long(); DECODE_HEX8(val); M.x86.R_EDX = val; } else { OP_DECODE("mov dx,"); val = fetch_word(); DECODE_HEX4(val); M.x86.R_DX = val; } } /**************************************************************************** REMARKS: Handles opcode 0xbb ****************************************************************************/ static void x86emuOp_mov_word_BX_IMM(u8 op1) { u32 val; if(MODE_DATA32) { OP_DECODE("mov ebx,"); val = fetch_long(); DECODE_HEX8(val); M.x86.R_EBX = val; } else { OP_DECODE("mov bx,"); val = fetch_word(); DECODE_HEX4(val); M.x86.R_BX = val; } } /**************************************************************************** REMARKS: Handles opcode 0xbc ****************************************************************************/ static void x86emuOp_mov_word_SP_IMM(u8 op1) { u32 val; if(MODE_DATA32) { OP_DECODE("mov esp,"); val = fetch_long(); DECODE_HEX8(val); M.x86.R_ESP = val; } else { OP_DECODE("mov sp,"); val = fetch_word(); DECODE_HEX4(val); M.x86.R_SP = val; } } /**************************************************************************** REMARKS: Handles opcode 0xbd ****************************************************************************/ static void x86emuOp_mov_word_BP_IMM(u8 op1) { u32 val; if(MODE_DATA32) { OP_DECODE("mov ebp,"); val = fetch_long(); DECODE_HEX8(val); M.x86.R_EBP = val; } else { OP_DECODE("mov bp,"); val = fetch_word(); DECODE_HEX4(val); M.x86.R_BP = val; } } /**************************************************************************** REMARKS: Handles opcode 0xbe ****************************************************************************/ static void x86emuOp_mov_word_SI_IMM(u8 op1) { u32 val; if(MODE_DATA32) { OP_DECODE("mov esi,"); val = fetch_long(); DECODE_HEX8(val); M.x86.R_ESI = val; } else { OP_DECODE("mov si,"); val = fetch_word(); DECODE_HEX4(val); M.x86.R_SI = val; } } /**************************************************************************** REMARKS: Handles opcode 0xbf ****************************************************************************/ static void x86emuOp_mov_word_DI_IMM(u8 op1) { u32 val; if(MODE_DATA32) { OP_DECODE("mov edi,"); val = fetch_long(); DECODE_HEX8(val); M.x86.R_EDI = val; } else { OP_DECODE("mov di,"); val = fetch_word(); DECODE_HEX4(val); M.x86.R_DI = val; } } /**************************************************************************** REMARKS: Handles opcode 0xc0 ****************************************************************************/ static void x86emuOp_opcC0_byte_RM_MEM(u8 op1) { int mod, rl, rh; u8 *reg8, val, imm; u32 addr; fetch_decode_modrm(&mod, &rh, &rl); decode_op_B(rh); if(mod == 3) { reg8 = decode_rm_byte_register(rl); OP_DECODE(","); imm = fetch_byte(); DECODE_HEX2(imm); val = (*op_B_byte[rh])(*reg8, imm); *reg8 = val; } else { OP_DECODE("byte "); addr = decode_rm_address(mod, rl); OP_DECODE(","); val = fetch_data_byte(addr); imm = fetch_byte(); DECODE_HEX2(imm); val = (*op_B_byte[rh])(val, imm); store_data_byte(addr, val); } } /**************************************************************************** REMARKS: Handles opcode 0xc1 ****************************************************************************/ static void x86emuOp_opcC1_word_RM_MEM(u8 op1) { int mod, rl, rh; u8 imm; u16 *reg16; u32 *reg32, val, addr; fetch_decode_modrm(&mod, &rh, &rl); decode_op_B(rh); if(mod == 3) { if(MODE_DATA32) { reg32 = decode_rm_long_register(rl); OP_DECODE(","); imm = fetch_byte(); DECODE_HEX2(imm); val = (*op_B_long[rh])(*reg32, imm); *reg32 = val; } else { reg16 = decode_rm_word_register(rl); OP_DECODE(","); imm = fetch_byte(); DECODE_HEX2(imm); val = (*op_B_word[rh])(*reg16, imm); *reg16 = val; } } else { if(MODE_DATA32) { OP_DECODE("dword "); addr = decode_rm_address(mod, rl); OP_DECODE(","); val = fetch_data_long(addr); imm = fetch_byte(); DECODE_HEX2(imm); val = (*op_B_long[rh])(val, imm); store_data_long(addr, val); } else { OP_DECODE("word "); addr = decode_rm_address(mod, rl); OP_DECODE(","); val = fetch_data_word(addr); imm = fetch_byte(); DECODE_HEX2(imm); val = (*op_B_word[rh])(val, imm); store_data_word(addr, val); } } } /**************************************************************************** REMARKS: Handles opcode 0xc2 ****************************************************************************/ static void x86emuOp_ret_near_IMM(u8 op1) { u32 imm; OP_DECODE("ret "); imm = MODE_DATA32 ? fetch_long() : fetch_word(); if(MODE_DATA32) { DECODE_HEX8(imm); M.x86.R_EIP = pop_long(); M.x86.R_ESP += imm; } else { DECODE_HEX4(imm); M.x86.R_EIP = pop_word(); M.x86.R_SP += imm; } } /**************************************************************************** REMARKS: Handles opcode 0xc3 ****************************************************************************/ static void x86emuOp_ret_near(u8 op1) { OP_DECODE("ret"); if(MODE_DATA32) { M.x86.R_EIP = pop_long(); } else { M.x86.R_EIP = pop_word(); } } /**************************************************************************** REMARKS: Handles opcode 0xc4 ****************************************************************************/ static void x86emuOp_les_R_IMM(u8 op1) { int mod, rh, rl; u16 *reg16; u32 *reg32, addr; OP_DECODE("les "); fetch_decode_modrm(&mod, &rh, &rl); if(mod == 3) { INTR_RAISE_UD(&M); } else { if(MODE_DATA32){ reg32 = decode_rm_long_register(rh); OP_DECODE(","); addr = decode_rm_address(mod, rl); *reg32 = fetch_data_long(addr); addr += 4; } else { reg16 = decode_rm_word_register(rh); OP_DECODE(","); addr = decode_rm_address(mod, rl); *reg16 = fetch_data_word(addr); addr += 2; } x86emu_set_seg_register(&M, M.x86.R_ES_SEL, fetch_data_word(addr)); } } /**************************************************************************** REMARKS: Handles opcode 0xc5 ****************************************************************************/ static void x86emuOp_lds_R_IMM(u8 op1) { int mod, rh, rl; u16 *reg16; u32 *reg32, addr; OP_DECODE("lds "); fetch_decode_modrm(&mod, &rh, &rl); if(mod == 3) { INTR_RAISE_UD(&M); } else { if(MODE_DATA32){ reg32 = decode_rm_long_register(rh); OP_DECODE(","); addr = decode_rm_address(mod, rl); *reg32 = fetch_data_long(addr); addr += 4; } else { reg16 = decode_rm_word_register(rh); OP_DECODE(","); addr = decode_rm_address(mod, rl); *reg16 = fetch_data_word(addr); addr += 2; } x86emu_set_seg_register(&M, M.x86.R_DS_SEL, fetch_data_word(addr)); } } /**************************************************************************** REMARKS: Handles opcode 0xc6 ****************************************************************************/ static void x86emuOp_mov_byte_RM_IMM(u8 op1) { int mod, rl, rh; u8 *reg8, imm; u32 addr; OP_DECODE("mov "); fetch_decode_modrm(&mod, &rh, &rl); if(rh != 0) { INTR_RAISE_UD(&M); return; } if(mod == 3) { reg8 = decode_rm_byte_register(rl); imm = fetch_byte(); DECODE_HEX2(imm); *reg8 = imm; } else { addr = decode_rm_address(mod, rl); OP_DECODE(","); imm = fetch_byte(); DECODE_HEX2(imm); store_data_byte(addr, imm); } } /**************************************************************************** REMARKS: Handles opcode 0xc7 ****************************************************************************/ static void x86emuOp_mov_word_RM_IMM(u8 op1) { int mod, rl, rh; u16 *reg16; u32 *reg32, addr, imm; OP_DECODE("mov "); fetch_decode_modrm(&mod, &rh, &rl); if(rh != 0) { INTR_RAISE_UD(&M); } if(mod == 3) { if(MODE_DATA32) { reg32 = decode_rm_long_register(rl); imm = fetch_long(); DECODE_HEX8(imm); *reg32 = imm; } else { reg16 = decode_rm_word_register(rl); imm = fetch_word(); DECODE_HEX4(imm); *reg16 = imm; } } else { addr = decode_rm_address(mod, rl); OP_DECODE(","); if(MODE_DATA32) { imm = fetch_long(); DECODE_HEX8(imm); store_data_long(addr, imm); } else { imm = fetch_word(); DECODE_HEX4(imm); store_data_word(addr, imm); } } } /**************************************************************************** REMARKS: Handles opcode 0xc8 ****************************************************************************/ static void x86emuOp_enter(u8 op1) { u32 local, frame_pointer; unsigned i, nesting; OP_DECODE("enter "); local = fetch_word(); nesting = fetch_byte(); DECODE_HEX4(local); OP_DECODE(","); DECODE_HEX2(nesting); nesting &= 0x1f; if(MODE_STACK32) { push_long(M.x86.R_EBP); frame_pointer = M.x86.R_ESP; } else { push_word(M.x86.R_BP); frame_pointer = M.x86.R_SP; } if(nesting > 0) { if(MODE_DATA32) { for(i = 1; i < nesting; i++) { if(MODE_STACK32) { M.x86.R_EBP -= 4; push_long(fetch_data_long_abs(M.x86.seg + R_SS_INDEX, M.x86.R_EBP)); } else { M.x86.R_BP -= 4; push_long(fetch_data_long_abs(M.x86.seg + R_SS_INDEX, M.x86.R_BP)); } } } else { for(i = 1; i < nesting; i++) { if(MODE_STACK32) { M.x86.R_EBP -= 2; push_word(fetch_data_word_abs(M.x86.seg + R_SS_INDEX, M.x86.R_EBP)); } else { M.x86.R_BP -= 2; push_word(fetch_data_word_abs(M.x86.seg + R_SS_INDEX, M.x86.R_BP)); } } } if(MODE_DATA32) { push_long(frame_pointer); } else { push_word(frame_pointer); } } // FIXME: really esp - local (not: ebp - local)??? if(MODE_STACK32) { M.x86.R_EBP = frame_pointer; M.x86.R_ESP = M.x86.R_ESP - local; } else { M.x86.R_BP = frame_pointer; M.x86.R_SP = M.x86.R_SP - local; } } /**************************************************************************** REMARKS: Handles opcode 0xc9 ****************************************************************************/ static void x86emuOp_leave(u8 op1) { OP_DECODE("leave"); if(MODE_STACK32) { M.x86.R_ESP = M.x86.R_EBP; } else { M.x86.R_SP = M.x86.R_BP; } if(MODE_DATA32) { M.x86.R_EBP = pop_long(); } else { M.x86.R_BP = pop_word(); } } /**************************************************************************** REMARKS: Handles opcode 0xca ****************************************************************************/ static void x86emuOp_ret_far_IMM(u8 op1) { u16 cs; u32 imm, eip; OP_DECODE("retf "); imm = MODE_DATA32 ? fetch_long() : fetch_word(); if(MODE_DATA32) { DECODE_HEX8(imm); eip = pop_long(); cs = pop_long(); M.x86.R_ESP += imm; } else { DECODE_HEX4(imm); eip = pop_word(); cs = pop_word(); M.x86.R_SP += imm; } x86emu_set_seg_register(&M, M.x86.R_CS_SEL, cs); M.x86.R_EIP = eip; } /**************************************************************************** REMARKS: Handles opcode 0xcb ****************************************************************************/ static void x86emuOp_ret_far(u8 op1) { u16 cs; u32 eip; OP_DECODE("retf"); if(MODE_DATA32) { eip = pop_long(); cs = pop_long(); } else { eip = pop_word(); cs = pop_word(); } x86emu_set_seg_register(&M, M.x86.R_CS_SEL, cs); M.x86.R_EIP = eip; } /**************************************************************************** REMARKS: Handles opcode 0xcc ****************************************************************************/ static void x86emuOp_int3(u8 op1) { OP_DECODE("int 3"); INTR_RAISE_SOFT(&M, 3); } /**************************************************************************** REMARKS: Handles opcode 0xcd ****************************************************************************/ static void x86emuOp_int_IMM(u8 op1) { u8 nr; OP_DECODE("int "); nr = fetch_byte(); DECODE_HEX2(nr); INTR_RAISE_SOFT(&M, nr); } /**************************************************************************** REMARKS: Handles opcode 0xce ****************************************************************************/ static void x86emuOp_into(u8 op1) { OP_DECODE("into"); if(ACCESS_FLAG(F_OF)) INTR_RAISE_SOFT(&M, 4); } /**************************************************************************** REMARKS: Handles opcode 0xcf ****************************************************************************/ static void x86emuOp_iret(u8 op1) { u16 cs; u32 eip; OP_DECODE("iret"); if(MODE_DATA32) { eip = pop_long(); cs = pop_long(); M.x86.R_EFLG = pop_long() | F_ALWAYS_ON; } else { eip = pop_word(); cs = pop_word(); M.x86.R_FLG = pop_word() | F_ALWAYS_ON; } x86emu_set_seg_register(&M, M.x86.R_CS_SEL, cs); M.x86.R_EIP = eip; } /**************************************************************************** REMARKS: Handles opcode 0xd0 ****************************************************************************/ static void x86emuOp_opcD0_byte_RM_1(u8 op1) { int mod, rl, rh; u8 *reg8, val; u32 addr; fetch_decode_modrm(&mod, &rh, &rl); decode_op_B(rh); if(mod == 3) { reg8 = decode_rm_byte_register(rl); OP_DECODE(",1"); val = (*op_B_byte[rh])(*reg8, 1); *reg8 = val; } else { OP_DECODE("byte "); addr = decode_rm_address(mod, rl); OP_DECODE(",1"); val = fetch_data_byte(addr); val = (*op_B_byte[rh])(val, 1); store_data_byte(addr, val); } } /**************************************************************************** REMARKS: Handles opcode 0xd1 ****************************************************************************/ static void x86emuOp_opcD1_word_RM_1(u8 op1) { int mod, rl, rh; u16 *reg16; u32 *reg32, val, addr; fetch_decode_modrm(&mod, &rh, &rl); decode_op_B(rh); if(mod == 3) { if(MODE_DATA32) { reg32 = decode_rm_long_register(rl); OP_DECODE(",1"); val = (*op_B_long[rh])(*reg32, 1); *reg32 = val; } else { reg16 = decode_rm_word_register(rl); OP_DECODE(",1"); val = (*op_B_word[rh])(*reg16, 1); *reg16 = val; } } else { if(MODE_DATA32) { OP_DECODE("dword "); addr = decode_rm_address(mod, rl); OP_DECODE(",1"); val = fetch_data_long(addr); val = (*op_B_long[rh])(val, 1); store_data_long(addr, val); } else { OP_DECODE("word "); addr = decode_rm_address(mod, rl); OP_DECODE(",1"); val = fetch_data_word(addr); val = (*op_B_word[rh])(val, 1); store_data_word(addr, val); } } } /**************************************************************************** REMARKS: Handles opcode 0xd2 ****************************************************************************/ static void x86emuOp_opcD2_byte_RM_CL(u8 op1) { int mod, rl, rh; u8 *reg8, val, imm; u32 addr; fetch_decode_modrm(&mod, &rh, &rl); decode_op_B(rh); imm = M.x86.R_CL; if(mod == 3) { reg8 = decode_rm_byte_register(rl); OP_DECODE(",cl"); val = (*op_B_byte[rh])(*reg8, imm); *reg8 = val; } else { OP_DECODE("byte "); addr = decode_rm_address(mod, rl); OP_DECODE(",cl"); val = fetch_data_byte(addr); val = (*op_B_byte[rh])(val, imm); store_data_byte(addr, val); } } /**************************************************************************** REMARKS: Handles opcode 0xd3 ****************************************************************************/ static void x86emuOp_opcD3_word_RM_CL(u8 op1) { int mod, rl, rh; u8 imm; u16 *reg16; u32 *reg32, val, addr; fetch_decode_modrm(&mod, &rh, &rl); decode_op_B(rh); imm = M.x86.R_CL; if(mod == 3) { if(MODE_DATA32) { reg32 = decode_rm_long_register(rl); OP_DECODE(",cl"); val = (*op_B_long[rh])(*reg32, imm); *reg32 = val; } else { reg16 = decode_rm_word_register(rl); OP_DECODE(",cl"); val = (*op_B_word[rh])(*reg16, imm); *reg16 = val; } } else { if(MODE_DATA32) { OP_DECODE("dword "); addr = decode_rm_address(mod, rl); OP_DECODE(",cl"); val = fetch_data_long(addr); val = (*op_B_long[rh])(val, imm); store_data_long(addr, val); } else { OP_DECODE("word "); addr = decode_rm_address(mod, rl); OP_DECODE(",cl"); val = fetch_data_word(addr); val = (*op_B_word[rh])(val, imm); store_data_word(addr, val); } } } /**************************************************************************** REMARKS: Handles opcode 0xd4 ****************************************************************************/ static void x86emuOp_aam(u8 op1) { u8 base; OP_DECODE("aam"); base = fetch_byte(); if(base == 0) INTR_RAISE_DIV0(&M); M.x86.R_AX = aam_word(M.x86.R_AL, base); } /**************************************************************************** REMARKS: Handles opcode 0xd5 ****************************************************************************/ static void x86emuOp_aad(u8 op1) { u8 base; OP_DECODE("aad"); base = fetch_byte(); M.x86.R_AX = aad_word(M.x86.R_AX, base); } /**************************************************************************** REMARKS: Handles opcode 0xd6 ****************************************************************************/ static void x86emuOp_setalc(u8 op1) { OP_DECODE("setalc"); M.x86.R_AL = ACCESS_FLAG(F_CF) ? 0xff : 0; } /**************************************************************************** REMARKS: Handles opcode 0xd7 ****************************************************************************/ static void x86emuOp_xlat(u8 op1) { u32 addr; OP_DECODE("xlat"); if(MODE_DATA32) { addr = M.x86.R_EBX + M.x86.R_AL; } else { addr = (M.x86.R_BX + M.x86.R_AL) & 0xffff; } M.x86.R_AL = fetch_data_byte(addr); } /* instuctions D8 .. DF are in i87_ops.c */ /**************************************************************************** REMARKS: Handles opcode 0xe0 ****************************************************************************/ static void x86emuOp_loopne(u8 op1) { s32 ofs; u32 eip; OP_DECODE("loopnz "); ofs = (s8) fetch_byte(); eip = M.x86.R_EIP + ofs; DECODE_HEX_ADDR(eip); if(MODE_DATA32) { if(--M.x86.R_ECX && !ACCESS_FLAG(F_ZF)) M.x86.R_EIP = eip; } else { eip &= 0xffff; // FIXME: is not correct if(--M.x86.R_CX && !ACCESS_FLAG(F_ZF)) M.x86.R_EIP = eip; } } /**************************************************************************** REMARKS: Handles opcode 0xe1 ****************************************************************************/ static void x86emuOp_loope(u8 op1) { s32 ofs; u32 eip; OP_DECODE("loopz "); ofs = (s8) fetch_byte(); eip = M.x86.R_EIP + ofs; DECODE_HEX_ADDR(eip); if(MODE_DATA32) { if(--M.x86.R_ECX && ACCESS_FLAG(F_ZF)) M.x86.R_EIP = eip; } else { eip &= 0xffff; // FIXME: is not correct if(--M.x86.R_CX && ACCESS_FLAG(F_ZF)) M.x86.R_EIP = eip; } } /**************************************************************************** REMARKS: Handles opcode 0xe2 ****************************************************************************/ static void x86emuOp_loop(u8 op1) { s32 ofs; u32 eip; OP_DECODE("loop "); ofs = (s8) fetch_byte(); eip = M.x86.R_EIP + ofs; DECODE_HEX_ADDR(eip); if(MODE_DATA32) { if(--M.x86.R_ECX) M.x86.R_EIP = eip; } else { eip &= 0xffff; // FIXME: is not correct if(--M.x86.R_CX) M.x86.R_EIP = eip; } } /**************************************************************************** REMARKS: Handles opcode 0xe3 ****************************************************************************/ static void x86emuOp_jcxz(u8 op1) { s32 ofs; u32 eip; ofs = (s8) fetch_byte(); eip = M.x86.R_EIP + ofs; if(MODE_DATA32) { OP_DECODE("jecxz "); DECODE_HEX_ADDR(eip); if(M.x86.R_ECX == 0) M.x86.R_EIP = eip; } else { OP_DECODE("jcxz "); eip &= 0xffff; // FIXME: is not correct DECODE_HEX_ADDR(eip); if(M.x86.R_CX == 0) M.x86.R_EIP = eip; } } /**************************************************************************** REMARKS: Handles opcode 0xe4 ****************************************************************************/ static void x86emuOp_in_byte_AL_IMM(u8 op1) { u8 port; OP_DECODE("in al,"); port = fetch_byte(); DECODE_HEX2(port); M.x86.R_AL = fetch_io_byte(port); } /**************************************************************************** REMARKS: Handles opcode 0xe5 ****************************************************************************/ static void x86emuOp_in_word_AX_IMM(u8 op1) { u8 port; OP_DECODE("in "); port = fetch_byte(); if(MODE_DATA32) { OP_DECODE("eax,"); M.x86.R_EAX = fetch_io_long(port); } else { OP_DECODE("ax,"); M.x86.R_AX = fetch_io_word(port); } DECODE_HEX2(port); } /**************************************************************************** REMARKS: Handles opcode 0xe6 ****************************************************************************/ static void x86emuOp_out_byte_IMM_AL(u8 op1) { u8 port; OP_DECODE("out "); port = fetch_byte(); DECODE_HEX2(port); OP_DECODE(",al"); store_io_byte(port, M.x86.R_AL); } /**************************************************************************** REMARKS: Handles opcode 0xe7 ****************************************************************************/ static void x86emuOp_out_word_IMM_AX(u8 op1) { u8 port; OP_DECODE("out "); port = fetch_byte(); DECODE_HEX2(port); if(MODE_DATA32) { OP_DECODE(",eax"); store_io_long(port, M.x86.R_EAX); } else { OP_DECODE(",ax"); store_io_word(port, M.x86.R_AX); } } /**************************************************************************** REMARKS: Handles opcode 0xe8 ****************************************************************************/ static void x86emuOp_call_near_IMM(u8 op1) { s32 ofs; u32 eip; OP_DECODE("call "); if(MODE_DATA32) { ofs = fetch_long(); } else { ofs = (s16) fetch_word(); } eip = M.x86.R_EIP + ofs; if(MODE_DATA32) { DECODE_HEX_ADDR(eip); push_long(M.x86.R_EIP); } else { eip &= 0xffff; // FIXME: is not correct DECODE_HEX_ADDR(eip); push_word(M.x86.R_IP); } M.x86.R_EIP = eip; } /**************************************************************************** REMARKS: Handles opcode 0xe9 ****************************************************************************/ static void x86emuOp_jump_near_IMM(u8 op1) { s32 ofs; u32 eip; OP_DECODE("jmp "); if(MODE_DATA32) { ofs = fetch_long(); } else { ofs = (s16) fetch_word(); } eip = M.x86.R_EIP + ofs; if(!MODE_DATA32) eip &= 0xffff; DECODE_HEX_ADDR(eip); M.x86.R_EIP = eip; } /**************************************************************************** REMARKS: Handles opcode 0xea ****************************************************************************/ static void x86emuOp_jump_far_IMM(u8 op1) { u16 cs; u32 eip; OP_DECODE("jmp far "); eip = MODE_DATA32 ? fetch_long() : fetch_word(); cs = fetch_word(); x86emu_set_seg_register(&M, M.x86.R_CS_SEL, cs); M.x86.R_EIP = eip; DECODE_HEX4(cs); OP_DECODE(":"); if(MODE_DATA32) { DECODE_HEX8(eip); } else { DECODE_HEX4(eip); } } /**************************************************************************** REMARKS: Handles opcode 0xeb ****************************************************************************/ static void x86emuOp_jump_byte_IMM(u8 op1) { s32 ofs; u32 eip; OP_DECODE("jmp "); ofs = (s8) fetch_byte(); eip = M.x86.R_EIP + ofs; if(MODE_DATA32) { DECODE_HEX_ADDR(eip); } else { eip &= 0xffff; // FIXME: is not correct DECODE_HEX_ADDR(eip); } // we had a prefix: special debug instruction if((M.log.trace & X86EMU_TRACE_DEBUG) && M.x86.R_EIP - M.x86.saved_eip == 3 && ofs >= 1) { M.x86.debug_start = M.x86.R_CS_BASE + M.x86.R_EIP; M.x86.debug_len = ofs; } M.x86.R_EIP = eip; } /**************************************************************************** REMARKS: Handles opcode 0xec ****************************************************************************/ static void x86emuOp_in_byte_AL_DX(u8 op1) { OP_DECODE("in al,dx"); M.x86.R_AL = fetch_io_byte(M.x86.R_DX); } /**************************************************************************** REMARKS: Handles opcode 0xed ****************************************************************************/ static void x86emuOp_in_word_AX_DX(u8 op1) { if(MODE_DATA32) { OP_DECODE("in eax,dx"); M.x86.R_EAX = fetch_io_long(M.x86.R_DX); } else { OP_DECODE("in ax,dx"); M.x86.R_AX = fetch_io_word(M.x86.R_DX); } } /**************************************************************************** REMARKS: Handles opcode 0xee ****************************************************************************/ static void x86emuOp_out_byte_DX_AL(u8 op1) { OP_DECODE("out dx,al"); store_io_byte(M.x86.R_DX, M.x86.R_AL); } /**************************************************************************** REMARKS: Handles opcode 0xef ****************************************************************************/ static void x86emuOp_out_word_DX_AX(u8 op1) { if(MODE_DATA32) { OP_DECODE("out dx,eax"); store_io_long(M.x86.R_DX, M.x86.R_EAX); } else { OP_DECODE("out dx,ax"); store_io_word(M.x86.R_DX, M.x86.R_AX); } } /**************************************************************************** REMARKS: Handles opcode 0xf4 ****************************************************************************/ static void x86emuOp_hlt(u8 op1) { OP_DECODE("hlt"); x86emu_stop(&M); } /**************************************************************************** REMARKS: Handles opcode 0xf5 ****************************************************************************/ static void x86emuOp_cmc(u8 op1) { /* complement the carry flag. */ OP_DECODE("cmc"); TOGGLE_FLAG(F_CF); } /**************************************************************************** REMARKS: Handles opcode 0xf6 ****************************************************************************/ static void x86emuOp_opcF6_byte_RM(u8 op1) { int mod, rl, rh; u8 *reg8, val, imm; u32 addr; fetch_decode_modrm(&mod, &rh, &rl); if(mod == 3) { switch(rh) { case 0: case 1: /* test imm */ OP_DECODE("test "); reg8 = decode_rm_byte_register(rl); OP_DECODE(","); imm = fetch_byte(); DECODE_HEX2(imm); test_byte(*reg8, imm); break; case 2: /* not */ OP_DECODE("not "); reg8 = decode_rm_byte_register(rl); *reg8 = not_byte(*reg8); break; case 3: /* neg */ OP_DECODE("neg "); reg8 = decode_rm_byte_register(rl); *reg8 = neg_byte(*reg8); break; case 4: /* mul al, */ OP_DECODE("mul "); reg8 = decode_rm_byte_register(rl); mul_byte(*reg8); break; case 5: /* imul al, */ OP_DECODE("imul "); reg8 = decode_rm_byte_register(rl); imul_byte(*reg8); break; case 6: /* div ax, */ OP_DECODE("div "); reg8 = decode_rm_byte_register(rl); div_byte(*reg8); break; case 7: /* idiv ax, */ OP_DECODE("idiv "); reg8 = decode_rm_byte_register(rl); idiv_byte(*reg8); break; } } else { switch(rh) { case 0: case 1: /* test imm */ OP_DECODE("test byte "); addr = decode_rm_address(mod, rl); OP_DECODE(","); imm = fetch_byte(); DECODE_HEX2(imm); val = fetch_data_byte(addr); test_byte(val, imm); break; case 2: /* not */ OP_DECODE("not byte "); addr = decode_rm_address(mod, rl); val = fetch_data_byte(addr); val = not_byte(val); store_data_byte(addr, val); break; case 3: /* neg */ OP_DECODE("neg byte "); addr = decode_rm_address(mod, rl); val = fetch_data_byte(addr); val = neg_byte(val); store_data_byte(addr, val); break; case 4: /* mul al, */ OP_DECODE("mul byte "); addr = decode_rm_address(mod, rl); val = fetch_data_byte(addr); mul_byte(val); break; case 5: /* imul al, */ OP_DECODE("imul byte "); addr = decode_rm_address(mod, rl); val = fetch_data_byte(addr); imul_byte(val); break; case 6: /* div ax, */ OP_DECODE("div byte "); addr = decode_rm_address(mod, rl); val = fetch_data_byte(addr); div_byte(val); break; case 7: /* idiv ax, */ OP_DECODE("idiv byte "); addr = decode_rm_address(mod, rl); val = fetch_data_byte(addr); idiv_byte(val); break; } } } /**************************************************************************** REMARKS: Handles opcode 0xf7 ****************************************************************************/ static void x86emuOp_opcF7_word_RM(u8 op1) { int mod, rl, rh; u16 *reg16; u32 *reg32, addr, imm, val; fetch_decode_modrm(&mod, &rh, &rl); if(mod == 3) { switch(rh) { case 0: case 1: /* test imm */ OP_DECODE("test "); if(MODE_DATA32) { reg32 = decode_rm_long_register(rl); OP_DECODE(","); imm = fetch_long(); DECODE_HEX8(imm); test_long(*reg32, imm); } else { reg16 = decode_rm_word_register(rl); OP_DECODE(","); imm = fetch_word(); DECODE_HEX4(imm); test_word(*reg16, imm); } break; case 2: /* not */ OP_DECODE("not "); if(MODE_DATA32) { reg32 = decode_rm_long_register(rl); *reg32 = not_long(*reg32); } else { reg16 = decode_rm_word_register(rl); *reg16 = not_word(*reg16); } break; case 3: /* neg */ OP_DECODE("neg "); if(MODE_DATA32) { reg32 = decode_rm_long_register(rl); *reg32 = neg_long(*reg32); } else { reg16 = decode_rm_word_register(rl); *reg16 = neg_word(*reg16); } break; case 4: /* mul ax, */ OP_DECODE("mul "); if(MODE_DATA32) { reg32 = decode_rm_long_register(rl); mul_long(*reg32); } else { reg16 = decode_rm_word_register(rl); mul_word(*reg16); } break; case 5: /* imul ax, */ OP_DECODE("imul "); if(MODE_DATA32) { reg32 = decode_rm_long_register(rl); imul_long(*reg32); } else { reg16 = decode_rm_word_register(rl); imul_word(*reg16); } break; case 6: /* div dx:ax, */ OP_DECODE("div "); if(MODE_DATA32) { reg32 = decode_rm_long_register(rl); div_long(*reg32); } else { reg16 = decode_rm_word_register(rl); div_word(*reg16); } break; case 7: /* idiv dx:ax, */ OP_DECODE("idiv "); if(MODE_DATA32) { reg32 = decode_rm_long_register(rl); idiv_long(*reg32); } else { reg16 = decode_rm_word_register(rl); idiv_word(*reg16); } break; } } else { switch(rh) { case 0: case 1: /* test imm */ if(MODE_DATA32) { OP_DECODE("test dword "); addr = decode_rm_address(mod, rl); OP_DECODE(","); imm = fetch_long(); DECODE_HEX8(imm); val = fetch_data_long(addr); test_long(val, imm); } else { OP_DECODE("test word "); addr = decode_rm_address(mod, rl); OP_DECODE(","); imm = fetch_word(); DECODE_HEX4(imm); val = fetch_data_word(addr); test_word(val, imm); } break; case 2: /* not */ if(MODE_DATA32) { OP_DECODE("not dword "); addr = decode_rm_address(mod, rl); val = fetch_data_long(addr); val = not_long(val); store_data_long(addr, val); } else { OP_DECODE("not word "); addr = decode_rm_address(mod, rl); val = fetch_data_word(addr); val = not_word(val); store_data_word(addr, val); } break; case 3: /* neg */ if(MODE_DATA32) { OP_DECODE("neg dword "); addr = decode_rm_address(mod, rl); val = fetch_data_long(addr); val = neg_long(val); store_data_long(addr, val); } else { OP_DECODE("neg word "); addr = decode_rm_address(mod, rl); val = fetch_data_word(addr); val = neg_word(val); store_data_word(addr, val); } break; case 4: /* mul ax, */ if(MODE_DATA32) { OP_DECODE("mul dword "); addr = decode_rm_address(mod, rl); val = fetch_data_long(addr); mul_long(val); } else { OP_DECODE("mul word "); addr = decode_rm_address(mod, rl); val = fetch_data_word(addr); mul_word(val); } break; case 5: /* imul ax, */ if(MODE_DATA32) { OP_DECODE("imul dword "); addr = decode_rm_address(mod, rl); val = fetch_data_long(addr); imul_long(val); } else { OP_DECODE("imul word "); addr = decode_rm_address(mod, rl); val = fetch_data_word(addr); imul_word(val); } break; case 6: /* div dx:ax, */ if(MODE_DATA32) { OP_DECODE("div dword "); addr = decode_rm_address(mod, rl); val = fetch_data_long(addr); div_long(val); } else { OP_DECODE("div word "); addr = decode_rm_address(mod, rl); val = fetch_data_word(addr); div_word(val); } break; case 7: /* idiv dx:ax, */ if(MODE_DATA32) { OP_DECODE("idiv dword "); addr = decode_rm_address(mod, rl); val = fetch_data_long(addr); idiv_long(val); } else { OP_DECODE("idiv word "); addr = decode_rm_address(mod, rl); val = fetch_data_word(addr); idiv_word(val); } break; } } } /**************************************************************************** REMARKS: Handles opcode 0xf8 ****************************************************************************/ static void x86emuOp_clc(u8 op1) { /* clear carry flag. */ OP_DECODE("clc"); CLEAR_FLAG(F_CF); } /**************************************************************************** REMARKS: Handles opcode 0xf9 ****************************************************************************/ static void x86emuOp_stc(u8 op1) { /* set carry flag. */ OP_DECODE("stc"); SET_FLAG(F_CF); } /**************************************************************************** REMARKS: Handles opcode 0xfa ****************************************************************************/ static void x86emuOp_cli(u8 op1) { /* clear interrupts. */ OP_DECODE("cli"); CLEAR_FLAG(F_IF); } /**************************************************************************** REMARKS: Handles opcode 0xfb ****************************************************************************/ static void x86emuOp_sti(u8 op1) { /* enable interrupts. */ OP_DECODE("sti"); SET_FLAG(F_IF); } /**************************************************************************** REMARKS: Handles opcode 0xfc ****************************************************************************/ static void x86emuOp_cld(u8 op1) { /* direction = increment */ OP_DECODE("cld"); CLEAR_FLAG(F_DF); } /**************************************************************************** REMARKS: Handles opcode 0xfd ****************************************************************************/ static void x86emuOp_std(u8 op1) { /* direction = decrement */ OP_DECODE("std"); SET_FLAG(F_DF); } /**************************************************************************** REMARKS: Handles opcode 0xfe ****************************************************************************/ static void x86emuOp_opcFE_byte_RM(u8 op1) { int mod, rh, rl; u8 *reg8, val; u32 addr; fetch_decode_modrm(&mod, &rh, &rl); switch(rh) { case 0: OP_DECODE("inc "); break; case 1: OP_DECODE("dec "); break; default: INTR_RAISE_UD(&M); return; } if(mod == 3) { reg8 = decode_rm_byte_register(rl); *reg8 = rh == 0 ? inc_byte(*reg8) : dec_byte(*reg8); } else { OP_DECODE("byte "); addr = decode_rm_address(mod, rl); val = fetch_data_byte(addr); val = rh == 0 ? inc_byte(val) : dec_byte(val); store_data_byte(addr, val); } } /**************************************************************************** REMARKS: Handles opcode 0xff ****************************************************************************/ static void x86emuOp_opcFF_word_RM(u8 op1) { int mod, rh, rl; u16 *reg16, cs; u32 *reg32, addr, val; fetch_decode_modrm(&mod, &rh, &rl); if(mod == 3) { switch(rh) { case 0: /* inc */ OP_DECODE("inc "); if(MODE_DATA32) { reg32 = decode_rm_long_register(rl); *reg32 = inc_long(*reg32); } else { reg16 = decode_rm_word_register(rl); *reg16 = inc_word(*reg16); } break; case 1: /* dec */ OP_DECODE("dec "); if(MODE_DATA32) { reg32 = decode_rm_long_register(rl); *reg32 = dec_long(*reg32); } else { reg16 = decode_rm_word_register(rl); *reg16 = dec_word(*reg16); } break; case 2: /* call */ OP_DECODE("call "); if(MODE_DATA32) { reg32 = decode_rm_long_register(rl); push_long(M.x86.R_EIP); M.x86.R_EIP = *reg32; } else { reg16 = decode_rm_word_register(rl); push_word(M.x86.R_IP); M.x86.R_EIP = *reg16; } break; case 4: /* jmp */ OP_DECODE("jmp "); if(MODE_DATA32) { reg32 = decode_rm_long_register(rl); M.x86.R_EIP = *reg32; } else { reg16 = decode_rm_word_register(rl); M.x86.R_EIP = *reg16; } break; case 6: OP_DECODE("push "); if(MODE_DATA32) { reg32 = decode_rm_long_register(rl); push_long(*reg32); } else { reg16 = decode_rm_word_register(rl); push_word(*reg16); } break; default: INTR_RAISE_UD(&M); break; } } else { switch(rh) { case 0: /* inc */ OP_DECODE("inc "); if(MODE_DATA32) { OP_DECODE("dword "); addr = decode_rm_address(mod, rl); val = fetch_data_long(addr); val = inc_long(val); store_data_long(addr, val); } else { OP_DECODE("word "); addr = decode_rm_address(mod, rl); val = fetch_data_word(addr); val = inc_word(val); store_data_word(addr, val); } break; case 1: /* dec */ OP_DECODE("dec "); if(MODE_DATA32) { OP_DECODE("dword "); addr = decode_rm_address(mod, rl); val = fetch_data_long(addr); val = dec_long(val); store_data_long(addr, val); } else { OP_DECODE("word "); addr = decode_rm_address(mod, rl); val = fetch_data_word(addr); val = dec_word(val); store_data_word(addr, val); } break; case 2: /* call */ OP_DECODE("call "); if(MODE_DATA32) { OP_DECODE("dword "); addr = decode_rm_address(mod, rl); val = fetch_data_long(addr); push_long(M.x86.R_EIP); } else { OP_DECODE("word "); addr = decode_rm_address(mod, rl); val = fetch_data_word(addr); push_word(M.x86.R_IP); } M.x86.R_EIP = val; break; case 3: /* call far */ OP_DECODE("call far "); if(MODE_DATA32) { if(!MODE_CODE32) OP_DECODE("word "); addr = decode_rm_address(mod, rl); val = fetch_data_long(addr); cs = fetch_data_word(addr + 4); push_long(M.x86.R_CS); push_long(M.x86.R_EIP); } else { if(MODE_CODE32) OP_DECODE("dword "); addr = decode_rm_address(mod, rl); val = fetch_data_word(addr); cs = fetch_data_word(addr + 2); push_word(M.x86.R_CS); push_word(M.x86.R_IP); } x86emu_set_seg_register(&M, M.x86.R_CS_SEL, cs); M.x86.R_EIP = val; break; case 4: /* jmp */ OP_DECODE("jmp "); if(MODE_DATA32) { OP_DECODE("dword "); addr = decode_rm_address(mod, rl); val = fetch_data_long(addr); } else { OP_DECODE("word "); addr = decode_rm_address(mod, rl); val = fetch_data_word(addr); } M.x86.R_EIP = val; break; case 5: /* jmp far */ OP_DECODE("jmp far "); if(MODE_DATA32) { if(!MODE_CODE32) OP_DECODE("word "); addr = decode_rm_address(mod, rl); val = fetch_data_long(addr); cs = fetch_data_word(addr + 4); } else { if(MODE_CODE32) OP_DECODE("dword "); addr = decode_rm_address(mod, rl); val = fetch_data_word(addr); cs = fetch_data_word(addr + 2); } x86emu_set_seg_register(&M, M.x86.R_CS_SEL, cs); M.x86.R_EIP = val; break; case 6: /* push */ OP_DECODE("push "); if(MODE_DATA32) { OP_DECODE("dword "); addr = decode_rm_address(mod, rl); val = fetch_data_long(addr); push_long(val); } else { OP_DECODE("word "); addr = decode_rm_address(mod, rl); val = fetch_data_word(addr); push_word(val); } break; case 7: INTR_RAISE_UD(&M); break; } } } /*************************************************************************** * Single byte operation code table: **************************************************************************/ void (*x86emu_optab[256])(u8) = { /* 0x00 */ x86emuOp_op_A_byte_RM_R, /* 0x01 */ x86emuOp_op_A_word_RM_R, /* 0x02 */ x86emuOp_op_A_byte_R_RM, /* 0x03 */ x86emuOp_op_A_word_R_RM, /* 0x04 */ x86emuOp_op_A_byte_AL_IMM, /* 0x05 */ x86emuOp_op_A_word_AX_IMM, /* 0x06 */ x86emuOp_push_ES, /* 0x07 */ x86emuOp_pop_ES, /* 0x08 */ x86emuOp_op_A_byte_RM_R, /* 0x09 */ x86emuOp_op_A_word_RM_R, /* 0x0a */ x86emuOp_op_A_byte_R_RM, /* 0x0b */ x86emuOp_op_A_word_R_RM, /* 0x0c */ x86emuOp_op_A_byte_AL_IMM, /* 0x0d */ x86emuOp_op_A_word_AX_IMM, /* 0x0e */ x86emuOp_push_CS, /* 0x0f */ x86emuOp_two_byte, /* 0x10 */ x86emuOp_op_A_byte_RM_R, /* 0x11 */ x86emuOp_op_A_word_RM_R, /* 0x12 */ x86emuOp_op_A_byte_R_RM, /* 0x13 */ x86emuOp_op_A_word_R_RM, /* 0x14 */ x86emuOp_op_A_byte_AL_IMM, /* 0x15 */ x86emuOp_op_A_word_AX_IMM, /* 0x16 */ x86emuOp_push_SS, /* 0x17 */ x86emuOp_pop_SS, /* 0x18 */ x86emuOp_op_A_byte_RM_R, /* 0x19 */ x86emuOp_op_A_word_RM_R, /* 0x1a */ x86emuOp_op_A_byte_R_RM, /* 0x1b */ x86emuOp_op_A_word_R_RM, /* 0x1c */ x86emuOp_op_A_byte_AL_IMM, /* 0x1d */ x86emuOp_op_A_word_AX_IMM, /* 0x1e */ x86emuOp_push_DS, /* 0x1f */ x86emuOp_pop_DS, /* 0x20 */ x86emuOp_op_A_byte_RM_R, /* 0x21 */ x86emuOp_op_A_word_RM_R, /* 0x22 */ x86emuOp_op_A_byte_R_RM, /* 0x23 */ x86emuOp_op_A_word_R_RM, /* 0x24 */ x86emuOp_op_A_byte_AL_IMM, /* 0x25 */ x86emuOp_op_A_word_AX_IMM, /* 0x26 */ x86emuOp_illegal_op, /* ES: */ /* 0x27 */ x86emuOp_daa, /* 0x28 */ x86emuOp_op_A_byte_RM_R, /* 0x29 */ x86emuOp_op_A_word_RM_R, /* 0x2a */ x86emuOp_op_A_byte_R_RM, /* 0x2b */ x86emuOp_op_A_word_R_RM, /* 0x2c */ x86emuOp_op_A_byte_AL_IMM, /* 0x2d */ x86emuOp_op_A_word_AX_IMM, /* 0x2e */ x86emuOp_illegal_op, /* CS: */ /* 0x2f */ x86emuOp_das, /* 0x30 */ x86emuOp_op_A_byte_RM_R, /* 0x31 */ x86emuOp_op_A_word_RM_R, /* 0x32 */ x86emuOp_op_A_byte_R_RM, /* 0x33 */ x86emuOp_op_A_word_R_RM, /* 0x34 */ x86emuOp_op_A_byte_AL_IMM, /* 0x35 */ x86emuOp_op_A_word_AX_IMM, /* 0x36 */ x86emuOp_illegal_op, /* SS: */ /* 0x37 */ x86emuOp_aaa, /* 0x38 */ x86emuOp_op_A_byte_RM_R, /* 0x39 */ x86emuOp_op_A_word_RM_R, /* 0x3a */ x86emuOp_op_A_byte_R_RM, /* 0x3b */ x86emuOp_op_A_word_R_RM, /* 0x3c */ x86emuOp_op_A_byte_AL_IMM, /* 0x3d */ x86emuOp_op_A_word_AX_IMM, /* 0x3e */ x86emuOp_illegal_op, /* DS: */ /* 0x3f */ x86emuOp_aas, /* 0x40 */ x86emuOp_inc_AX, /* 0x41 */ x86emuOp_inc_CX, /* 0x42 */ x86emuOp_inc_DX, /* 0x43 */ x86emuOp_inc_BX, /* 0x44 */ x86emuOp_inc_SP, /* 0x45 */ x86emuOp_inc_BP, /* 0x46 */ x86emuOp_inc_SI, /* 0x47 */ x86emuOp_inc_DI, /* 0x48 */ x86emuOp_dec_AX, /* 0x49 */ x86emuOp_dec_CX, /* 0x4a */ x86emuOp_dec_DX, /* 0x4b */ x86emuOp_dec_BX, /* 0x4c */ x86emuOp_dec_SP, /* 0x4d */ x86emuOp_dec_BP, /* 0x4e */ x86emuOp_dec_SI, /* 0x4f */ x86emuOp_dec_DI, /* 0x50 */ x86emuOp_push_AX, /* 0x51 */ x86emuOp_push_CX, /* 0x52 */ x86emuOp_push_DX, /* 0x53 */ x86emuOp_push_BX, /* 0x54 */ x86emuOp_push_SP, /* 0x55 */ x86emuOp_push_BP, /* 0x56 */ x86emuOp_push_SI, /* 0x57 */ x86emuOp_push_DI, /* 0x58 */ x86emuOp_pop_AX, /* 0x59 */ x86emuOp_pop_CX, /* 0x5a */ x86emuOp_pop_DX, /* 0x5b */ x86emuOp_pop_BX, /* 0x5c */ x86emuOp_pop_SP, /* 0x5d */ x86emuOp_pop_BP, /* 0x5e */ x86emuOp_pop_SI, /* 0x5f */ x86emuOp_pop_DI, /* 0x60 */ x86emuOp_push_all, /* 0x61 */ x86emuOp_pop_all, /* 0x62 */ x86emuOp_illegal_op, /* bound */ /* 0x63 */ x86emuOp_illegal_op, /* arpl */ /* 0x64 */ x86emuOp_illegal_op, /* FS: */ /* 0x65 */ x86emuOp_illegal_op, /* GS: */ /* 0x66 */ x86emuOp_illegal_op, /* DATA32: */ /* 0x67 */ x86emuOp_illegal_op, /* ADDR32: */ /* 0x68 */ x86emuOp_push_word_IMM, /* 0x69 */ x86emuOp_imul_word_IMM, /* 0x6a */ x86emuOp_push_byte_IMM, /* 0x6b */ x86emuOp_imul_byte_IMM, /* 0x6c */ x86emuOp_ins_byte, /* 0x6d */ x86emuOp_ins_word, /* 0x6e */ x86emuOp_outs_byte, /* 0x6f */ x86emuOp_outs_word, /* 0x70 */ x86emuOp_jump_short_cc, /* 0x71 */ x86emuOp_jump_short_cc, /* 0x72 */ x86emuOp_jump_short_cc, /* 0x73 */ x86emuOp_jump_short_cc, /* 0x74 */ x86emuOp_jump_short_cc, /* 0x75 */ x86emuOp_jump_short_cc, /* 0x76 */ x86emuOp_jump_short_cc, /* 0x77 */ x86emuOp_jump_short_cc, /* 0x78 */ x86emuOp_jump_short_cc, /* 0x79 */ x86emuOp_jump_short_cc, /* 0x7a */ x86emuOp_jump_short_cc, /* 0x7b */ x86emuOp_jump_short_cc, /* 0x7c */ x86emuOp_jump_short_cc, /* 0x7d */ x86emuOp_jump_short_cc, /* 0x7e */ x86emuOp_jump_short_cc, /* 0x7f */ x86emuOp_jump_short_cc, /* 0x80 */ x86emuOp_opc80_byte_RM_IMM, /* 0x81 */ x86emuOp_opc81_word_RM_IMM, /* 0x82 */ x86emuOp_opc80_byte_RM_IMM, /* 0x83 */ x86emuOp_opc83_word_RM_IMM, /* 0x84 */ x86emuOp_test_byte_RM_R, /* 0x85 */ x86emuOp_test_word_RM_R, /* 0x86 */ x86emuOp_xchg_byte_RM_R, /* 0x87 */ x86emuOp_xchg_word_RM_R, /* 0x88 */ x86emuOp_mov_byte_RM_R, /* 0x89 */ x86emuOp_mov_word_RM_R, /* 0x8a */ x86emuOp_mov_byte_R_RM, /* 0x8b */ x86emuOp_mov_word_R_RM, /* 0x8c */ x86emuOp_mov_word_RM_SR, /* 0x8d */ x86emuOp_lea_word_R_M, /* 0x8e */ x86emuOp_mov_word_SR_RM, /* 0x8f */ x86emuOp_pop_RM, /* 0x90 */ x86emuOp_nop, /* 0x91 */ x86emuOp_xchg_word_AX_CX, /* 0x92 */ x86emuOp_xchg_word_AX_DX, /* 0x93 */ x86emuOp_xchg_word_AX_BX, /* 0x94 */ x86emuOp_xchg_word_AX_SP, /* 0x95 */ x86emuOp_xchg_word_AX_BP, /* 0x96 */ x86emuOp_xchg_word_AX_SI, /* 0x97 */ x86emuOp_xchg_word_AX_DI, /* 0x98 */ x86emuOp_cbw, /* 0x99 */ x86emuOp_cwd, /* 0x9a */ x86emuOp_call_far_IMM, /* 0x9b */ x86emuOp_wait, /* 0x9c */ x86emuOp_pushf_word, /* 0x9d */ x86emuOp_popf_word, /* 0x9e */ x86emuOp_sahf, /* 0x9f */ x86emuOp_lahf, /* 0xa0 */ x86emuOp_mov_AL_M_IMM, /* 0xa1 */ x86emuOp_mov_AX_M_IMM, /* 0xa2 */ x86emuOp_mov_M_AL_IMM, /* 0xa3 */ x86emuOp_mov_M_AX_IMM, /* 0xa4 */ x86emuOp_movs_byte, /* 0xa5 */ x86emuOp_movs_word, /* 0xa6 */ x86emuOp_cmps_byte, /* 0xa7 */ x86emuOp_cmps_word, /* 0xa8 */ x86emuOp_test_AL_IMM, /* 0xa9 */ x86emuOp_test_AX_IMM, /* 0xaa */ x86emuOp_stos_byte, /* 0xab */ x86emuOp_stos_word, /* 0xac */ x86emuOp_lods_byte, /* 0xad */ x86emuOp_lods_word, /* 0xac */ x86emuOp_scas_byte, /* 0xad */ x86emuOp_scas_word, /* 0xb0 */ x86emuOp_mov_byte_AL_IMM, /* 0xb1 */ x86emuOp_mov_byte_CL_IMM, /* 0xb2 */ x86emuOp_mov_byte_DL_IMM, /* 0xb3 */ x86emuOp_mov_byte_BL_IMM, /* 0xb4 */ x86emuOp_mov_byte_AH_IMM, /* 0xb5 */ x86emuOp_mov_byte_CH_IMM, /* 0xb6 */ x86emuOp_mov_byte_DH_IMM, /* 0xb7 */ x86emuOp_mov_byte_BH_IMM, /* 0xb8 */ x86emuOp_mov_word_AX_IMM, /* 0xb9 */ x86emuOp_mov_word_CX_IMM, /* 0xba */ x86emuOp_mov_word_DX_IMM, /* 0xbb */ x86emuOp_mov_word_BX_IMM, /* 0xbc */ x86emuOp_mov_word_SP_IMM, /* 0xbd */ x86emuOp_mov_word_BP_IMM, /* 0xbe */ x86emuOp_mov_word_SI_IMM, /* 0xbf */ x86emuOp_mov_word_DI_IMM, /* 0xc0 */ x86emuOp_opcC0_byte_RM_MEM, /* 0xc1 */ x86emuOp_opcC1_word_RM_MEM, /* 0xc2 */ x86emuOp_ret_near_IMM, /* 0xc3 */ x86emuOp_ret_near, /* 0xc4 */ x86emuOp_les_R_IMM, /* 0xc5 */ x86emuOp_lds_R_IMM, /* 0xc6 */ x86emuOp_mov_byte_RM_IMM, /* 0xc7 */ x86emuOp_mov_word_RM_IMM, /* 0xc8 */ x86emuOp_enter, /* 0xc9 */ x86emuOp_leave, /* 0xca */ x86emuOp_ret_far_IMM, /* 0xcb */ x86emuOp_ret_far, /* 0xcc */ x86emuOp_int3, /* 0xcd */ x86emuOp_int_IMM, /* 0xce */ x86emuOp_into, /* 0xcf */ x86emuOp_iret, /* 0xd0 */ x86emuOp_opcD0_byte_RM_1, /* 0xd1 */ x86emuOp_opcD1_word_RM_1, /* 0xd2 */ x86emuOp_opcD2_byte_RM_CL, /* 0xd3 */ x86emuOp_opcD3_word_RM_CL, /* 0xd4 */ x86emuOp_aam, /* 0xd5 */ x86emuOp_aad, /* 0xd6 */ x86emuOp_setalc, /* 0xd7 */ x86emuOp_xlat, #if 0 /* 0xd8 */ x86emuOp_esc_coprocess_d8, /* 0xd9 */ x86emuOp_esc_coprocess_d9, /* 0xda */ x86emuOp_esc_coprocess_da, /* 0xdb */ x86emuOp_esc_coprocess_db, /* 0xdc */ x86emuOp_esc_coprocess_dc, /* 0xdd */ x86emuOp_esc_coprocess_dd, /* 0xde */ x86emuOp_esc_coprocess_de, /* 0xdf */ x86emuOp_esc_coprocess_df, #else /* 0xd8 */ x86emuOp_illegal_op, /* 0xd9 */ x86emuOp_illegal_op, /* 0xda */ x86emuOp_illegal_op, /* 0xdb */ x86emuOp_illegal_op, /* 0xdc */ x86emuOp_illegal_op, /* 0xdd */ x86emuOp_illegal_op, /* 0xde */ x86emuOp_illegal_op, /* 0xdf */ x86emuOp_illegal_op, #endif /* 0xe0 */ x86emuOp_loopne, /* 0xe1 */ x86emuOp_loope, /* 0xe2 */ x86emuOp_loop, /* 0xe3 */ x86emuOp_jcxz, /* 0xe4 */ x86emuOp_in_byte_AL_IMM, /* 0xe5 */ x86emuOp_in_word_AX_IMM, /* 0xe6 */ x86emuOp_out_byte_IMM_AL, /* 0xe7 */ x86emuOp_out_word_IMM_AX, /* 0xe8 */ x86emuOp_call_near_IMM, /* 0xe9 */ x86emuOp_jump_near_IMM, /* 0xea */ x86emuOp_jump_far_IMM, /* 0xeb */ x86emuOp_jump_byte_IMM, /* 0xec */ x86emuOp_in_byte_AL_DX, /* 0xed */ x86emuOp_in_word_AX_DX, /* 0xee */ x86emuOp_out_byte_DX_AL, /* 0xef */ x86emuOp_out_word_DX_AX, /* 0xf0 */ x86emuOp_illegal_op, /* LOCK: */ /* 0xf1 */ x86emuOp_illegal_op, /* 0xf2 */ x86emuOp_illegal_op, /* REPNE: */ /* 0xf3 */ x86emuOp_illegal_op, /* REPE: */ /* 0xf4 */ x86emuOp_hlt, /* 0xf5 */ x86emuOp_cmc, /* 0xf6 */ x86emuOp_opcF6_byte_RM, /* 0xf7 */ x86emuOp_opcF7_word_RM, /* 0xf8 */ x86emuOp_clc, /* 0xf9 */ x86emuOp_stc, /* 0xfa */ x86emuOp_cli, /* 0xfb */ x86emuOp_sti, /* 0xfc */ x86emuOp_cld, /* 0xfd */ x86emuOp_std, /* 0xfe */ x86emuOp_opcFE_byte_RM, /* 0xff */ x86emuOp_opcFF_word_RM, }; libx86emu-1.5/ops2.c000066400000000000000000001400571247503741400142470ustar00rootroot00000000000000/**************************************************************************** * * Realmode X86 Emulator Library * * Copyright (C) 1996-1999 SciTech Software, Inc. * Copyright (C) David Mosberger-Tang * 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. * * ======================================================================== * * Language: ANSI C * Environment: Any * Developer: Kendall Bennett * * Description: This file includes subroutines to implement the decoding * and emulation of all the x86 extended two-byte processor * instructions. * ****************************************************************************/ #include "include/x86emu_int.h" /*----------------------------- Implementation ----------------------------*/ /**************************************************************************** PARAMETERS: op2 - Instruction op code REMARKS: Handles illegal opcodes. ****************************************************************************/ static void x86emuOp2_illegal_op(u8 op2) { OP_DECODE("illegal opcode"); INTR_RAISE_UD(&M); } /**************************************************************************** REMARKS: Handles opcode 0x0f,0x00 ****************************************************************************/ static void x86emuOp2_opc_00(u8 op2) { int mod, rl, rh; u16 *reg16; u32 addr, val; fetch_decode_modrm(&mod, &rh, &rl); switch(rh) { case 0: OP_DECODE("sldt "); break; case 1: OP_DECODE("str "); break; case 2: OP_DECODE("lldt "); break; case 3: OP_DECODE("ltr "); break; case 4: OP_DECODE("verr "); break; case 5: OP_DECODE("verw "); break; default: INTR_RAISE_UD(&M); return; } if(mod == 3) { reg16 = decode_rm_word_register(rl); switch(rh) { case 0: /* sldt */ *reg16 = M.x86.R_LDT; break; case 1: /* str */ *reg16 = M.x86.R_TR; break; case 2: /* lldt */ x86emu_set_seg_register(&M, &M.x86.ldt, *reg16); break; case 3: /* ltr */ M.x86.R_TR = *reg16; break; case 4: /* verr */ if(*reg16 != 0) SET_FLAG(F_ZF); break; case 5: /* verw */ if(*reg16 != 0) SET_FLAG(F_ZF); break; } } else { addr = decode_rm_address(mod, rl); switch(rh) { case 0: /* sldt */ store_data_word(addr, M.x86.R_LDT); break; case 1: /* str */ store_data_word(addr, M.x86.R_TR); break; case 2: /* lldt */ val = fetch_data_word(addr); x86emu_set_seg_register(&M, &M.x86.ldt, val); break; case 3: /* ltr */ val = fetch_data_word(addr); M.x86.R_TR = val; break; case 4: /* verr */ val = fetch_data_word(addr); if(val != 0) SET_FLAG(F_ZF); break; case 5: /* verw */ val = fetch_data_word(addr); if(val != 0) SET_FLAG(F_ZF); break; } } } /**************************************************************************** REMARKS: Handles opcode 0x0f,0x01 ****************************************************************************/ static void x86emuOp2_opc_01(u8 op2) { int mod, rl, rh; u16 *reg16; u32 base, addr, val; u16 limit; fetch_decode_modrm(&mod, &rh, &rl); if(mod == 3 && rh != 4 && rh != 6) { INTR_RAISE_UD(&M); } else { switch(rh) { case 0: /* sgdt */ OP_DECODE("sgdt "); addr = decode_rm_address(mod, rl); base = M.x86.gdt.base; if(!MODE_DATA32) base &= 0xffffff; store_data_word(addr, M.x86.gdt.limit); store_data_long(addr + 2, base); break; case 1: /* sidt */ OP_DECODE("sidt "); addr = decode_rm_address(mod, rl); base = M.x86.idt.base; if(!MODE_DATA32) base &= 0xffffff; store_data_word(addr, M.x86.idt.limit); store_data_long(addr + 2, base); break; case 2: /* lgdt */ OP_DECODE("lgdt "); addr = decode_rm_address(mod, rl); limit = fetch_data_word(addr); base = fetch_data_long(addr + 2); if(!MODE_DATA32) base &= 0xffffff; M.x86.gdt.limit = limit; M.x86.gdt.base = base; break; case 3: /* lidt */ OP_DECODE("lidt "); addr = decode_rm_address(mod, rl); limit = fetch_data_word(addr); base = fetch_data_long(addr + 2); if(!MODE_DATA32) base &= 0xffffff; M.x86.idt.limit = limit; M.x86.idt.base = base; break; case 4: OP_DECODE("smsw "); if(mod == 3) { reg16 = decode_rm_word_register(rl); *reg16 = M.x86.R_CR0; } else { addr = decode_rm_address(mod, rl); store_data_word(addr, M.x86.R_CR0); } break; case 5: INTR_RAISE_UD(&M); break; case 6: OP_DECODE("lmsw "); if(mod == 3) { reg16 = decode_rm_word_register(rl); M.x86.R_CR0 = (M.x86.R_CR0 & ~0xffff) + *reg16; } else { addr = decode_rm_address(mod, rl); val = fetch_data_word(addr); M.x86.R_CR0 = (M.x86.R_CR0 & ~0xffff) + val; } break; case 7: OP_DECODE("invlpg "); decode_rm_address(mod, rl); break; } } } /**************************************************************************** REMARKS: Handles opcode 0x0f,0x06 ****************************************************************************/ static void x86emuOp2_clts(u8 op2) { OP_DECODE("clts"); M.x86.R_CR0 &= ~8; } /**************************************************************************** REMARKS: Handles opcode 0x0f,0x08 ****************************************************************************/ static void x86emuOp2_invd(u8 op2) { OP_DECODE("invd"); } /**************************************************************************** REMARKS: Handles opcode 0x0f,0x09 ****************************************************************************/ static void x86emuOp2_wbinvd(u8 op2) { OP_DECODE("wbinvd"); } /**************************************************************************** REMARKS: Handles opcode 0x0f,0x20 ****************************************************************************/ static void x86emuOp2_mov_word_RM_CRx(u8 op2) { int mod, rl, rh; u32 *reg32; OP_DECODE("mov "); fetch_decode_modrm(&mod, &rh, &rl); if(mod == 3) { reg32 = decode_rm_long_register(rl); OP_DECODE(",cr"); DECODE_HEX1(rh); *reg32 = M.x86.crx[rh]; } else { INTR_RAISE_UD(&M); } } /**************************************************************************** REMARKS: Handles opcode 0x0f,0x21 ****************************************************************************/ static void x86emuOp2_mov_word_RM_DRx(u8 op2) { int mod, rl, rh; u32 *reg32; OP_DECODE("mov "); fetch_decode_modrm(&mod, &rh, &rl); if(mod == 3) { reg32 = decode_rm_long_register(rl); OP_DECODE(",dr"); DECODE_HEX1(rh); *reg32 = M.x86.drx[rh]; } else { INTR_RAISE_UD(&M); } } /**************************************************************************** REMARKS: Handles opcode 0x0f,0x22 ****************************************************************************/ static void x86emuOp2_mov_word_CRx_RM(u8 op2) { int mod, rl, rh; OP_DECODE("mov cr"); fetch_decode_modrm(&mod, &rh, &rl); DECODE_HEX1(rh); OP_DECODE(","); if(mod == 3) { M.x86.crx[rh] = *decode_rm_long_register(rl); } else { INTR_RAISE_UD(&M); } } /**************************************************************************** REMARKS: Handles opcode 0x0f,0x23 ****************************************************************************/ static void x86emuOp2_mov_word_DRx_RM(u8 op2) { int mod, rl, rh; OP_DECODE("mov dr"); fetch_decode_modrm(&mod, &rh, &rl); DECODE_HEX1(rh); OP_DECODE(","); if(mod == 3) { M.x86.drx[rh] = *decode_rm_long_register(rl); } else { INTR_RAISE_UD(&M); } } /**************************************************************************** REMARKS: Handles opcode 0x0f,0x30 ****************************************************************************/ static void x86emuOp2_wrmsr(u8 op2) { unsigned u; OP_DECODE("wrmsr"); u = M.x86.R_ECX; if(u >= X86EMU_MSRS) { INTR_RAISE_UD(&M); } else { M.x86.msr[u] = ((u64) M.x86.R_EDX << 32) + M.x86.R_EAX; M.x86.msr_perm[u] |= X86EMU_ACC_W; } } /**************************************************************************** REMARKS: Handles opcode 0x0f,0x31 ****************************************************************************/ static void x86emuOp2_rdtsc(u8 op2) { OP_DECODE("rdtsc"); M.x86.R_EAX = M.x86.R_TSC; M.x86.R_EDX = M.x86.R_TSC >> 32; M.x86.msr_perm[0x10] |= X86EMU_ACC_R; } /**************************************************************************** REMARKS: Handles opcode 0x0f,0x32 ****************************************************************************/ static void x86emuOp2_rdmsr(u8 op2) { unsigned u; OP_DECODE("rdmsr"); u = M.x86.R_ECX; if(u >= X86EMU_MSRS) { INTR_RAISE_UD(&M); } else { M.x86.R_EDX = M.x86.msr[u] >> 32; M.x86.R_EAX = M.x86.msr[u]; M.x86.msr_perm[u] |= X86EMU_ACC_R; } } /**************************************************************************** REMARKS: Handles opcode 0x0f,0x33 ****************************************************************************/ static void x86emuOp2_rdpmc(u8 op2) { // unsigned u; OP_DECODE("rdpmc"); // u = M.x86.R_ECX; // counter index // not implemented M.x86.R_EDX = 0; M.x86.R_EAX = 0; } /**************************************************************************** REMARKS: Handles opcode 0x0f,0x34 ****************************************************************************/ static void x86emuOp2_sysenter(u8 op2) { OP_DECODE("sysenter"); // not implemented INTR_RAISE_UD(&M); } /**************************************************************************** REMARKS: Handles opcode 0x0f,0x35 ****************************************************************************/ static void x86emuOp2_sysexit(u8 op2) { OP_DECODE("sysexit"); // not implemented INTR_RAISE_UD(&M); } /**************************************************************************** REMARKS: Handles opcode 0x0f,0x80-0x8F ****************************************************************************/ static void x86emuOp2_long_jump(u8 op2) { s32 ofs; u32 eip; unsigned type = op2 & 0xf; OP_DECODE("j"); decode_cond(type); if(MODE_DATA32) { ofs = fetch_long(); } else { ofs = (s16) fetch_word(); } eip = M.x86.R_EIP + ofs; if(!MODE_DATA32) eip &= 0xffff; DECODE_HEX_ADDR(eip); if(eval_condition(type)) M.x86.R_EIP = eip; } /**************************************************************************** REMARKS: Handles opcode 0x0f,0x90-0x9F ****************************************************************************/ static void x86emuOp2_set_byte(u8 op2) { int mod, rl, rh; u32 addr; u8 *reg8; unsigned type = op2 & 0xf; OP_DECODE("set"); decode_cond(type); fetch_decode_modrm(&mod, &rh, &rl); if(mod == 3) { reg8 = decode_rm_byte_register(rl); *reg8 = eval_condition(type) ? 1 : 0; } else { addr = decode_rm_address(mod, rl); store_data_byte(addr, eval_condition(type) ? 1 : 0); } } /**************************************************************************** REMARKS: Handles opcode 0x0f,0xa0 ****************************************************************************/ static void x86emuOp2_push_FS(u8 op2) { OP_DECODE("push fs"); if(MODE_DATA32) { push_long(M.x86.R_FS); } else { push_word(M.x86.R_FS); } } /**************************************************************************** REMARKS: Handles opcode 0x0f,0xa1 ****************************************************************************/ static void x86emuOp2_pop_FS(u8 op2) { OP_DECODE("pop fs"); x86emu_set_seg_register(&M, M.x86.R_FS_SEL, MODE_DATA32 ? pop_long() : pop_word()); } /**************************************************************************** REMARKS: Handles opcode 0x0f,0xa3 ****************************************************************************/ static void x86emuOp2_bt_R(u8 op2) { int mod, rl, rh; u32 *reg32, val, addr, mask; u16 *reg16; s32 disp; OP_DECODE("bt "); fetch_decode_modrm(&mod, &rh, &rl); if(mod == 3) { if(MODE_DATA32) { reg32 = decode_rm_long_register(rl); OP_DECODE(","); mask = 1 << (*decode_rm_long_register(rh) & 0x1f); CONDITIONAL_SET_FLAG(*reg32 & mask, F_CF); } else { reg16 = decode_rm_word_register(rl); OP_DECODE(","); mask = 1 << (*decode_rm_word_register(rh) & 0x0f); CONDITIONAL_SET_FLAG(*reg16 & mask, F_CF); } } else { addr = decode_rm_address(mod, rl); OP_DECODE(","); if(MODE_DATA32) { disp = *decode_rm_long_register(rh); mask = 1 << (disp & 0x1f); disp >>= 5; val = fetch_data_long(addr + disp); CONDITIONAL_SET_FLAG(val & mask, F_CF); } else { disp = (s16) *decode_rm_word_register(rh); mask = 1 << (disp & 0x0f); disp >>= 4; val = fetch_data_word(addr + disp); CONDITIONAL_SET_FLAG(val & mask, F_CF); } } } /**************************************************************************** REMARKS: Handles opcode 0x0f,0xa4 ****************************************************************************/ static void x86emuOp2_shld_IMM(u8 op2) { int mod, rl, rh; u32 *dst32, *src32, addr, val; u16 *dst16, *src16; u8 imm; OP_DECODE("shld "); fetch_decode_modrm(&mod, &rh, &rl); if(mod == 3) { if(MODE_DATA32) { dst32 = decode_rm_long_register(rl); OP_DECODE(","); src32 = decode_rm_long_register(rh); OP_DECODE(","); imm = fetch_byte(); DECODE_HEX2(imm); *dst32 = shld_long(*dst32, *src32, imm); } else { dst16 = decode_rm_word_register(rl); OP_DECODE(","); src16 = decode_rm_word_register(rh); OP_DECODE(","); imm = fetch_byte(); DECODE_HEX2(imm); *dst16 = shld_word(*dst16, *src16, imm); } } else { addr = decode_rm_address(mod, rl); OP_DECODE(","); if(MODE_DATA32) { src32 = decode_rm_long_register(rh); OP_DECODE(","); imm = fetch_byte(); DECODE_HEX2(imm); val = fetch_data_long(addr); val = shld_long(val, *src32, imm); store_data_long(addr, val); } else { src16 = decode_rm_word_register(rh); OP_DECODE(","); imm = fetch_byte(); DECODE_HEX2(imm); val = fetch_data_word(addr); val = shld_word(val, *src16, imm); store_data_word(addr, val); } } } /**************************************************************************** REMARKS: Handles opcode 0x0f,0xa5 ****************************************************************************/ static void x86emuOp2_shld_CL(u8 op2) { int mod, rl, rh; u32 *dst32, *src32, addr, val; u16 *dst16, *src16; OP_DECODE("shld "); fetch_decode_modrm(&mod, &rh, &rl); if(mod == 3) { if(MODE_DATA32) { dst32 = decode_rm_long_register(rl); OP_DECODE(","); src32 = decode_rm_long_register(rh); OP_DECODE(",cl"); *dst32 = shld_long(*dst32, *src32, M.x86.R_CL); } else { dst16 = decode_rm_word_register(rl); OP_DECODE(","); src16 = decode_rm_word_register(rh); OP_DECODE(",cl"); *dst16 = shld_word(*dst16, *src16, M.x86.R_CL); } } else { addr = decode_rm_address(mod, rl); OP_DECODE(","); if(MODE_DATA32) { src32 = decode_rm_long_register(rh); OP_DECODE(",cl"); val = fetch_data_long(addr); val = shld_long(val, *src32, M.x86.R_CL); store_data_long(addr, val); } else { src16 = decode_rm_word_register(rh); OP_DECODE(",cl"); val = fetch_data_word(addr); val = shld_word(val, *src16, M.x86.R_CL); store_data_word(addr, val); } } } /**************************************************************************** REMARKS: Handles opcode 0x0f,0xa8 ****************************************************************************/ static void x86emuOp2_push_GS(u8 op2) { OP_DECODE("push gs"); if(MODE_DATA32) { push_long(M.x86.R_GS); } else { push_word(M.x86.R_GS); } } /**************************************************************************** REMARKS: Handles opcode 0x0f,0xa9 ****************************************************************************/ static void x86emuOp2_pop_GS(u8 op2) { OP_DECODE("pop gs"); x86emu_set_seg_register(&M, M.x86.R_GS_SEL, MODE_DATA32 ? pop_long() : pop_word()); } /**************************************************************************** REMARKS: Handles opcode 0x0f,0xab ****************************************************************************/ static void x86emuOp2_bts_R(u8 op2) { int mod, rl, rh; u32 *reg32, val, addr, mask; u16 *reg16; s32 disp; OP_DECODE("bts "); fetch_decode_modrm(&mod, &rh, &rl); if(mod == 3) { if(MODE_DATA32) { reg32 = decode_rm_long_register(rl); OP_DECODE(","); mask = 1 << (*decode_rm_long_register(rh) & 0x1f); CONDITIONAL_SET_FLAG(*reg32 & mask, F_CF); *reg32 |= mask; } else { reg16 = decode_rm_word_register(rl); OP_DECODE(","); mask = 1 << (*decode_rm_word_register(rh) & 0x0f); CONDITIONAL_SET_FLAG(*reg16 & mask, F_CF); *reg16 |= mask; } } else { addr = decode_rm_address(mod, rl); OP_DECODE(","); if(MODE_DATA32) { disp = *decode_rm_long_register(rh); mask = 1 << (disp & 0x1f); disp >>= 5; val = fetch_data_long(addr + disp); CONDITIONAL_SET_FLAG(val & mask, F_CF); store_data_long(addr + disp, val | mask); } else { disp = (s16) *decode_rm_word_register(rh); mask = 1 << (disp & 0x0f); disp >>= 5; val = fetch_data_word(addr + disp); CONDITIONAL_SET_FLAG(val & mask, F_CF); store_data_word(addr + disp, val | mask); } } } /**************************************************************************** REMARKS: Handles opcode 0x0f,0xac ****************************************************************************/ static void x86emuOp2_shrd_IMM(u8 op2) { int mod, rl, rh; u32 *dst32, *src32, addr, val; u16 *dst16, *src16; u8 imm; OP_DECODE("shrd "); fetch_decode_modrm(&mod, &rh, &rl); if(mod == 3) { if(MODE_DATA32) { dst32 = decode_rm_long_register(rl); OP_DECODE(","); src32 = decode_rm_long_register(rh); OP_DECODE(","); imm = fetch_byte(); DECODE_HEX2(imm); *dst32 = shrd_long(*dst32, *src32, imm); } else { dst16 = decode_rm_word_register(rl); OP_DECODE(","); src16 = decode_rm_word_register(rh); OP_DECODE(","); imm = fetch_byte(); DECODE_HEX2(imm); *dst16 = shrd_word(*dst16, *src16, imm); } } else { addr = decode_rm_address(mod, rl); OP_DECODE(","); if(MODE_DATA32) { src32 = decode_rm_long_register(rh); OP_DECODE(","); imm = fetch_byte(); DECODE_HEX2(imm); val = fetch_data_long(addr); val = shrd_long(val, *src32, imm); store_data_long(addr, val); } else { src16 = decode_rm_word_register(rh); OP_DECODE(","); imm = fetch_byte(); DECODE_HEX2(imm); val = fetch_data_word(addr); val = shrd_word(val, *src16, imm); store_data_word(addr, val); } } } /**************************************************************************** REMARKS: Handles opcode 0x0f,0xad ****************************************************************************/ static void x86emuOp2_shrd_CL(u8 op2) { int mod, rl, rh; u32 *dst32, *src32, addr, val; u16 *dst16, *src16; OP_DECODE("shrd "); fetch_decode_modrm(&mod, &rh, &rl); if(mod == 3) { if(MODE_DATA32) { dst32 = decode_rm_long_register(rl); OP_DECODE(","); src32 = decode_rm_long_register(rh); OP_DECODE(",cl"); *dst32 = shrd_long(*dst32, *src32, M.x86.R_CL); } else { dst16 = decode_rm_word_register(rl); OP_DECODE(","); src16 = decode_rm_word_register(rh); OP_DECODE(",cl"); *dst16 = shrd_word(*dst16, *src16, M.x86.R_CL); } } else { addr = decode_rm_address(mod, rl); OP_DECODE(","); if(MODE_DATA32) { src32 = decode_rm_long_register(rh); OP_DECODE(",cl"); val = fetch_data_long(addr); val = shrd_long(val, *src32, M.x86.R_CL); store_data_long(addr, val); } else { src16 = decode_rm_word_register(rh); OP_DECODE(",cl"); val = fetch_data_word(addr); val = shrd_word(val, *src16, M.x86.R_CL); store_data_word(addr, val); } } } /**************************************************************************** REMARKS: Handles opcode 0x0f,0xaf ****************************************************************************/ static void x86emuOp2_imul_R_RM(u8 op2) { int mod, rl, rh; u32 *src32, *dst32, val, addr, res_lo, res_hi; u16 *src16, *dst16; OP_DECODE("imul "); fetch_decode_modrm(&mod, &rh, &rl); if(mod == 3) { if(MODE_DATA32) { dst32 = decode_rm_long_register(rh); OP_DECODE(","); src32 = decode_rm_long_register(rl); imul_long_direct(&res_lo, &res_hi, *dst32, *src32); if(res_hi != 0) { SET_FLAG(F_CF); SET_FLAG(F_OF); } else { CLEAR_FLAG(F_CF); CLEAR_FLAG(F_OF); } *dst32= res_lo; } else { dst16 = decode_rm_word_register(rh); OP_DECODE(","); src16 = decode_rm_word_register(rl); res_lo = (s32) ((s16) *dst16 * (s16) *src16); if(res_lo > 0xffff) { SET_FLAG(F_CF); SET_FLAG(F_OF); } else { CLEAR_FLAG(F_CF); CLEAR_FLAG(F_OF); } *dst16 = res_lo; } } else { if(MODE_DATA32) { dst32 = decode_rm_long_register(rh); OP_DECODE(","); addr = decode_rm_address(mod, rl); val = fetch_data_long(addr); imul_long_direct(&res_lo, &res_hi, *dst32, val); if(res_hi != 0) { SET_FLAG(F_CF); SET_FLAG(F_OF); } else { CLEAR_FLAG(F_CF); CLEAR_FLAG(F_OF); } *dst32 = res_lo; } else { dst16 = decode_rm_word_register(rh); OP_DECODE(","); addr = decode_rm_address(mod, rl); val = fetch_data_word(addr); res_lo = (s32) ((s16) *dst16 * (s16) val); if(res_lo > 0xffff) { SET_FLAG(F_CF); SET_FLAG(F_OF); } else { CLEAR_FLAG(F_CF); CLEAR_FLAG(F_OF); } *dst16 = res_lo; } } } /**************************************************************************** REMARKS: Handles opcode 0x0f,0xb2 ****************************************************************************/ static void x86emuOp2_lss_R_IMM(u8 op2) { int mod, rh, rl; u16 *reg16; u32 *reg32, addr; OP_DECODE("lss "); fetch_decode_modrm(&mod, &rh, &rl); if(mod == 3) { INTR_RAISE_UD(&M); } else { if(MODE_DATA32){ reg32 = decode_rm_long_register(rh); OP_DECODE(","); addr = decode_rm_address(mod, rl); *reg32 = fetch_data_long(addr); addr += 4; } else { reg16 = decode_rm_word_register(rh); OP_DECODE(","); addr = decode_rm_address(mod, rl); *reg16 = fetch_data_word(addr); addr += 2; } x86emu_set_seg_register(&M, M.x86.R_SS_SEL, fetch_data_word(addr)); } } /**************************************************************************** REMARKS: Handles opcode 0x0f,0xb3 ****************************************************************************/ static void x86emuOp2_btr_R(u8 op2) { int mod, rl, rh; u32 *reg32, val, addr, mask; u16 *reg16; s32 disp; OP_DECODE("btr "); fetch_decode_modrm(&mod, &rh, &rl); if(mod == 3) { if(MODE_DATA32) { reg32 = decode_rm_long_register(rl); OP_DECODE(","); mask = 1 << (*decode_rm_long_register(rh) & 0x1f); CONDITIONAL_SET_FLAG(*reg32 & mask, F_CF); *reg32 &= ~mask; } else { reg16 = decode_rm_word_register(rl); OP_DECODE(","); mask = 1 << (*decode_rm_word_register(rh) & 0x0f); CONDITIONAL_SET_FLAG(*reg16 & mask, F_CF); *reg16 &= ~mask; } } else { addr = decode_rm_address(mod, rl); OP_DECODE(","); if(MODE_DATA32) { disp = *decode_rm_long_register(rh); mask = 1 << (disp & 0x1f); disp >>= 5; val = fetch_data_long(addr + disp); CONDITIONAL_SET_FLAG(val & mask, F_CF); store_data_long(addr + disp, val & ~mask); } else { disp = (s16) *decode_rm_word_register(rh); mask = 1 << (disp & 0x0f); disp >>= 5; val = fetch_data_word(addr + disp); CONDITIONAL_SET_FLAG(val & mask, F_CF); store_data_word(addr + disp, val & ~mask); } } } /**************************************************************************** REMARKS: Handles opcode 0x0f,0xb4 ****************************************************************************/ static void x86emuOp2_lfs_R_IMM(u8 op2) { int mod, rh, rl; u16 *reg16; u32 *reg32, addr; OP_DECODE("lfs "); fetch_decode_modrm(&mod, &rh, &rl); if(mod == 3) { INTR_RAISE_UD(&M); } else { if(MODE_DATA32){ reg32 = decode_rm_long_register(rh); OP_DECODE(","); addr = decode_rm_address(mod, rl); *reg32 = fetch_data_long(addr); addr += 4; } else { reg16 = decode_rm_word_register(rh); OP_DECODE(","); addr = decode_rm_address(mod, rl); *reg16 = fetch_data_word(addr); addr += 2; } x86emu_set_seg_register(&M, M.x86.R_FS_SEL, fetch_data_word(addr)); } } /**************************************************************************** REMARKS: Handles opcode 0x0f,0xb5 ****************************************************************************/ static void x86emuOp2_lgs_R_IMM(u8 op2) { int mod, rh, rl; u16 *reg16; u32 *reg32, addr; OP_DECODE("lgs "); fetch_decode_modrm(&mod, &rh, &rl); if(mod == 3) { INTR_RAISE_UD(&M); } else { if(MODE_DATA32){ reg32 = decode_rm_long_register(rh); OP_DECODE(","); addr = decode_rm_address(mod, rl); *reg32 = fetch_data_long(addr); addr += 4; } else { reg16 = decode_rm_word_register(rh); OP_DECODE(","); addr = decode_rm_address(mod, rl); *reg16 = fetch_data_word(addr); addr += 2; } x86emu_set_seg_register(&M, M.x86.R_GS_SEL, fetch_data_word(addr)); } } /**************************************************************************** REMARKS: Handles opcode 0x0f,0xb6 ****************************************************************************/ static void x86emuOp2_movzx_byte_R_RM(u8 op2) { int mod, rl, rh; u32 *reg32, addr, val; u16 *reg16; u8 *reg8; OP_DECODE("movzx "); fetch_decode_modrm(&mod, &rh, &rl); if(mod == 3) { if(MODE_DATA32) { reg32 = decode_rm_long_register(rh); OP_DECODE(","); reg8 = decode_rm_byte_register(rl); *reg32 = *reg8; } else { reg16 = decode_rm_word_register(rh); OP_DECODE(","); reg8 = decode_rm_byte_register(rl); *reg16 = *reg8; } } else { if(MODE_DATA32) { reg32 = decode_rm_long_register(rh); OP_DECODE(",byte "); addr = decode_rm_address(mod, rl); val = fetch_data_byte(addr); *reg32 = val; } else { reg16 = decode_rm_word_register(rh); OP_DECODE(",byte "); addr = decode_rm_address(mod, rl); val = fetch_data_byte(addr); *reg16 = val; } } } /**************************************************************************** REMARKS: Handles opcode 0x0f,0xb7 ****************************************************************************/ static void x86emuOp2_movzx_word_R_RM(u8 op2) { int mod, rl, rh; u32 *reg32, addr, val; u16 *reg16; OP_DECODE("movzx "); fetch_decode_modrm(&mod, &rh, &rl); if(mod == 3) { if(MODE_DATA32) { reg32 = decode_rm_long_register(rh); OP_DECODE(","); reg16 = decode_rm_word_register(rl); *reg32 = *reg16; } else { reg16 = decode_rm_word_register(rh); OP_DECODE(","); *reg16 = *decode_rm_word_register(rl); } } else { if(MODE_DATA32) { reg32 = decode_rm_long_register(rh); OP_DECODE(",word "); addr = decode_rm_address(mod, rl); val = fetch_data_word(addr); *reg32 = val; } else { reg16 = decode_rm_word_register(rh); OP_DECODE(",word "); addr = decode_rm_address(mod, rl); val = fetch_data_word(addr); *reg16 = val; } } } /**************************************************************************** REMARKS: Handles opcode 0x0f,0xba ****************************************************************************/ static void x86emuOp2_btX_I(u8 op2) { int mod, rl, rh; u32 *reg32, val, addr, mask; u16 *reg16; u8 imm; fetch_decode_modrm(&mod, &rh, &rl); switch (rh) { case 4: OP_DECODE("bt "); break; case 5: OP_DECODE("bts "); break; case 6: OP_DECODE("btr "); break; case 7: OP_DECODE("btc "); break; default: INTR_RAISE_UD(&M); return; } if(mod == 3) { if(MODE_DATA32) { reg32 = decode_rm_long_register(rl); OP_DECODE(","); imm = fetch_byte(); DECODE_HEX2(imm); mask = 1 << (imm & 0x1f); CONDITIONAL_SET_FLAG(*reg32 & mask, F_CF); switch(rh) { case 5: *reg32 |= mask; break; case 6: *reg32 &= ~mask; break; case 7: *reg32 ^= mask; break; } } else { reg16 = decode_rm_word_register(rl); OP_DECODE(","); imm = fetch_byte(); DECODE_HEX2(imm); mask = 1 << (imm & 0x1f); CONDITIONAL_SET_FLAG(*reg16 & mask, F_CF); switch(rh) { case 5: *reg16 |= mask; break; case 6: *reg16 &= ~mask; break; case 7: *reg16 ^= mask; break; } } } else { addr = decode_rm_address(mod, rl); OP_DECODE(","); imm = fetch_byte(); DECODE_HEX2(imm); if(MODE_DATA32) { mask = 1 << (imm & 0x1f); val = fetch_data_long(addr); CONDITIONAL_SET_FLAG(val & mask, F_CF); switch(rh) { case 5: store_data_long(addr, val | mask); break; case 6: store_data_long(addr, val & ~mask); break; case 7: store_data_long(addr, val ^ mask); break; } } else { mask = 1 << (imm & 0x0f); val = fetch_data_word(addr); CONDITIONAL_SET_FLAG(val & mask, F_CF); switch(rh) { case 5: store_data_word(addr, val | mask); break; case 6: store_data_word(addr, val & ~mask); break; case 7: store_data_word(addr, val ^ mask); break; } } } } /**************************************************************************** REMARKS: Handles opcode 0x0f,0xbb ****************************************************************************/ static void x86emuOp2_btc_R(u8 op2) { int mod, rl, rh; u32 *reg32, val, addr, mask; u16 *reg16; s32 disp; OP_DECODE("btc "); fetch_decode_modrm(&mod, &rh, &rl); if(mod == 3) { if(MODE_DATA32) { reg32 = decode_rm_long_register(rl); OP_DECODE(","); mask = 1 << (*decode_rm_long_register(rh) & 0x1f); CONDITIONAL_SET_FLAG(*reg32 & mask, F_CF); *reg32 ^= mask; } else { reg16 = decode_rm_word_register(rl); OP_DECODE(","); mask = 1 << (*decode_rm_word_register(rh) & 0x0f); CONDITIONAL_SET_FLAG(*reg16 & mask, F_CF); *reg16 ^= mask; } } else { addr = decode_rm_address(mod, rl); OP_DECODE(","); if(MODE_DATA32) { disp = *decode_rm_long_register(rh); mask = 1 << (disp & 0x1f); disp >>= 5; val = fetch_data_long(addr + disp); CONDITIONAL_SET_FLAG(val & mask, F_CF); store_data_long(addr + disp, val ^ mask); } else { disp = (s16) *decode_rm_word_register(rh); mask = 1 << (disp & 0x0f); disp >>= 5; val = fetch_data_word(addr + disp); CONDITIONAL_SET_FLAG(val & mask, F_CF); store_data_word(addr + disp, val ^ mask); } } } /**************************************************************************** REMARKS: Handles opcode 0x0f,0xbc ****************************************************************************/ static void x86emuOp2_bsf(u8 op2) { int mod, rl, rh; u32 *reg32, addr, val, cnt; u16 *reg16; OP_DECODE("bsf "); fetch_decode_modrm(&mod, &rh, &rl); if(mod == 3) { if(MODE_DATA32) { val = *decode_rm_long_register(rl); OP_DECODE(","); reg32 = decode_rm_long_register(rh); CONDITIONAL_SET_FLAG(val == 0, F_ZF); for(cnt = 0; cnt < 32; cnt++) if((val >> cnt) & 1) break; *reg32 = cnt; } else { val = *decode_rm_word_register(rl); OP_DECODE(","); reg16 = decode_rm_word_register(rh); CONDITIONAL_SET_FLAG(val == 0, F_ZF); for(cnt = 0; cnt < 16; cnt++) if((val >> cnt) & 1) break; *reg16 = cnt; } } else { addr = decode_rm_address(mod, rl); OP_DECODE(","); if(MODE_DATA32) { reg32 = decode_rm_long_register(rh); val = fetch_data_long(addr); CONDITIONAL_SET_FLAG(val == 0, F_ZF); for(cnt = 0; cnt < 32; cnt++) if((val >> cnt) & 1) break; *reg32 = cnt; } else { reg16 = decode_rm_word_register(rh); val = fetch_data_word(addr); CONDITIONAL_SET_FLAG(val == 0, F_ZF); for(cnt = 0; cnt < 16; cnt++) if((val >> cnt) & 1) break; *reg16 = cnt; } } } /**************************************************************************** REMARKS: Handles opcode 0x0f,0xbd ****************************************************************************/ static void x86emuOp2_bsr(u8 op2) { int mod, rl, rh; u32 *reg32, addr, val, cnt; u16 *reg16; OP_DECODE("bsr "); fetch_decode_modrm(&mod, &rh, &rl); if(mod == 3) { if(MODE_DATA32) { val = *decode_rm_long_register(rl); OP_DECODE(","); reg32 = decode_rm_long_register(rh); CONDITIONAL_SET_FLAG(val == 0, F_ZF); for(cnt = 31; cnt > 0; cnt--) if((val >> cnt) & 1) break; *reg32 = cnt; } else { val = *decode_rm_word_register(rl); OP_DECODE(","); reg16 = decode_rm_word_register(rh); CONDITIONAL_SET_FLAG(val == 0, F_ZF); for(cnt = 15; cnt > 0; cnt--) if((val >> cnt) & 1) break; *reg16 = cnt; } } else { addr = decode_rm_address(mod, rl); OP_DECODE(","); if(MODE_DATA32) { reg32 = decode_rm_long_register(rh); val = fetch_data_long(addr); CONDITIONAL_SET_FLAG(val == 0, F_ZF); for(cnt = 31; cnt > 0; cnt--) if((val >> cnt) & 1) break; *reg32 = cnt; } else { reg16 = decode_rm_word_register(rh); val = fetch_data_word(addr); CONDITIONAL_SET_FLAG(val == 0, F_ZF); for(cnt = 15; cnt > 0; cnt--) if((val >> cnt) & 1) break; *reg16 = cnt; } } } /**************************************************************************** REMARKS: Handles opcode 0x0f,0xbe ****************************************************************************/ static void x86emuOp2_movsx_byte_R_RM(u8 op2) { int mod, rl, rh; u32 *reg32, addr, val; u16 *reg16; u8 *reg8; OP_DECODE("movsx "); fetch_decode_modrm(&mod, &rh, &rl); if(mod == 3) { if(MODE_DATA32) { reg32 = decode_rm_long_register(rh); OP_DECODE(","); reg8 = decode_rm_byte_register(rl); *reg32 = (s8) *reg8; } else { reg16 = decode_rm_word_register(rh); OP_DECODE(","); reg8 = decode_rm_byte_register(rl); *reg16 = (s8) *reg8; } } else { if(MODE_DATA32) { reg32 = decode_rm_long_register(rh); OP_DECODE(",byte "); addr = decode_rm_address(mod, rl); val = (s8) fetch_data_byte(addr); *reg32 = val; } else { reg16 = decode_rm_word_register(rh); OP_DECODE(",byte "); addr = decode_rm_address(mod, rl); val = (s8) fetch_data_byte(addr); *reg16 = val; } } } /**************************************************************************** REMARKS: Handles opcode 0x0f,0xbf ****************************************************************************/ static void x86emuOp2_movsx_word_R_RM(u8 op2) { int mod, rl, rh; u32 *reg32, addr, val; u16 *reg16; OP_DECODE("movsx "); fetch_decode_modrm(&mod, &rh, &rl); if(mod == 3) { if(MODE_DATA32) { reg32 = decode_rm_long_register(rh); OP_DECODE(","); reg16 = decode_rm_word_register(rl); *reg32 = (s16) *reg16; } else { reg16 = decode_rm_word_register(rh); OP_DECODE(","); *reg16 = (s16) *decode_rm_word_register(rl); } } else { if(MODE_DATA32) { reg32 = decode_rm_long_register(rh); OP_DECODE(",word "); addr = decode_rm_address(mod, rl); val = (s16) fetch_data_word(addr); *reg32 = val; } else { reg16 = decode_rm_word_register(rh); OP_DECODE(",word "); addr = decode_rm_address(mod, rl); val = (s16) fetch_data_word(addr); *reg16 = val; } } } /*************************************************************************** * Double byte operation code table: **************************************************************************/ void (*x86emu_optab2[256])(u8) = { /* 0x00 */ x86emuOp2_opc_00, /* Group F (ring 0 PM) */ /* 0x01 */ x86emuOp2_opc_01, /* Group G (ring 0 PM) */ /* 0x02 */ x86emuOp2_illegal_op, /* lar (ring 0 PM) */ /* 0x03 */ x86emuOp2_illegal_op, /* lsl (ring 0 PM) */ /* 0x04 */ x86emuOp2_illegal_op, /* 0x05 */ x86emuOp2_illegal_op, /* loadall (undocumented) */ /* 0x06 */ x86emuOp2_clts, /* clts (ring 0 PM) */ /* 0x07 */ x86emuOp2_illegal_op, /* loadall (undocumented) */ /* 0x08 */ x86emuOp2_invd, /* invd (ring 0 PM) */ /* 0x09 */ x86emuOp2_wbinvd, /* wbinvd (ring 0 PM) */ /* 0x0a */ x86emuOp2_illegal_op, /* 0x0b */ x86emuOp2_illegal_op, /* 0x0c */ x86emuOp2_illegal_op, /* 0x0d */ x86emuOp2_illegal_op, /* 0x0e */ x86emuOp2_illegal_op, /* 0x0f */ x86emuOp2_illegal_op, /* 0x10 */ x86emuOp2_illegal_op, /* 0x11 */ x86emuOp2_illegal_op, /* 0x12 */ x86emuOp2_illegal_op, /* 0x13 */ x86emuOp2_illegal_op, /* 0x14 */ x86emuOp2_illegal_op, /* 0x15 */ x86emuOp2_illegal_op, /* 0x16 */ x86emuOp2_illegal_op, /* 0x17 */ x86emuOp2_illegal_op, /* 0x18 */ x86emuOp2_illegal_op, /* 0x19 */ x86emuOp2_illegal_op, /* 0x1a */ x86emuOp2_illegal_op, /* 0x1b */ x86emuOp2_illegal_op, /* 0x1c */ x86emuOp2_illegal_op, /* 0x1d */ x86emuOp2_illegal_op, /* 0x1e */ x86emuOp2_illegal_op, /* 0x1f */ x86emuOp2_illegal_op, /* 0x20 */ x86emuOp2_mov_word_RM_CRx, /* 0x21 */ x86emuOp2_mov_word_RM_DRx, /* 0x22 */ x86emuOp2_mov_word_CRx_RM, /* 0x23 */ x86emuOp2_mov_word_DRx_RM, /* 0x24 */ x86emuOp2_illegal_op, /* mov reg32,treg (ring 0 PM) */ /* 0x25 */ x86emuOp2_illegal_op, /* 0x26 */ x86emuOp2_illegal_op, /* mov treg,reg32 (ring 0 PM) */ /* 0x27 */ x86emuOp2_illegal_op, /* 0x28 */ x86emuOp2_illegal_op, /* 0x29 */ x86emuOp2_illegal_op, /* 0x2a */ x86emuOp2_illegal_op, /* 0x2b */ x86emuOp2_illegal_op, /* 0x2c */ x86emuOp2_illegal_op, /* 0x2d */ x86emuOp2_illegal_op, /* 0x2e */ x86emuOp2_illegal_op, /* 0x2f */ x86emuOp2_illegal_op, /* 0x30 */ x86emuOp2_wrmsr, /* 0x31 */ x86emuOp2_rdtsc, /* 0x32 */ x86emuOp2_rdmsr, /* 0x33 */ x86emuOp2_rdpmc, /* 0x34 */ x86emuOp2_sysenter, /* 0x35 */ x86emuOp2_sysexit, /* 0x36 */ x86emuOp2_illegal_op, /* 0x37 */ x86emuOp2_illegal_op, /* 0x38 */ x86emuOp2_illegal_op, /* 0x39 */ x86emuOp2_illegal_op, /* 0x3a */ x86emuOp2_illegal_op, /* 0x3b */ x86emuOp2_illegal_op, /* 0x3c */ x86emuOp2_illegal_op, /* 0x3d */ x86emuOp2_illegal_op, /* 0x3e */ x86emuOp2_illegal_op, /* 0x3f */ x86emuOp2_illegal_op, /* 0x40 */ x86emuOp2_illegal_op, /* 0x41 */ x86emuOp2_illegal_op, /* 0x42 */ x86emuOp2_illegal_op, /* 0x43 */ x86emuOp2_illegal_op, /* 0x44 */ x86emuOp2_illegal_op, /* 0x45 */ x86emuOp2_illegal_op, /* 0x46 */ x86emuOp2_illegal_op, /* 0x47 */ x86emuOp2_illegal_op, /* 0x48 */ x86emuOp2_illegal_op, /* 0x49 */ x86emuOp2_illegal_op, /* 0x4a */ x86emuOp2_illegal_op, /* 0x4b */ x86emuOp2_illegal_op, /* 0x4c */ x86emuOp2_illegal_op, /* 0x4d */ x86emuOp2_illegal_op, /* 0x4e */ x86emuOp2_illegal_op, /* 0x4f */ x86emuOp2_illegal_op, /* 0x50 */ x86emuOp2_illegal_op, /* 0x51 */ x86emuOp2_illegal_op, /* 0x52 */ x86emuOp2_illegal_op, /* 0x53 */ x86emuOp2_illegal_op, /* 0x54 */ x86emuOp2_illegal_op, /* 0x55 */ x86emuOp2_illegal_op, /* 0x56 */ x86emuOp2_illegal_op, /* 0x57 */ x86emuOp2_illegal_op, /* 0x58 */ x86emuOp2_illegal_op, /* 0x59 */ x86emuOp2_illegal_op, /* 0x5a */ x86emuOp2_illegal_op, /* 0x5b */ x86emuOp2_illegal_op, /* 0x5c */ x86emuOp2_illegal_op, /* 0x5d */ x86emuOp2_illegal_op, /* 0x5e */ x86emuOp2_illegal_op, /* 0x5f */ x86emuOp2_illegal_op, /* 0x60 */ x86emuOp2_illegal_op, /* 0x61 */ x86emuOp2_illegal_op, /* 0x62 */ x86emuOp2_illegal_op, /* 0x63 */ x86emuOp2_illegal_op, /* 0x64 */ x86emuOp2_illegal_op, /* 0x65 */ x86emuOp2_illegal_op, /* 0x66 */ x86emuOp2_illegal_op, /* 0x67 */ x86emuOp2_illegal_op, /* 0x68 */ x86emuOp2_illegal_op, /* 0x69 */ x86emuOp2_illegal_op, /* 0x6a */ x86emuOp2_illegal_op, /* 0x6b */ x86emuOp2_illegal_op, /* 0x6c */ x86emuOp2_illegal_op, /* 0x6d */ x86emuOp2_illegal_op, /* 0x6e */ x86emuOp2_illegal_op, /* 0x6f */ x86emuOp2_illegal_op, /* 0x70 */ x86emuOp2_illegal_op, /* 0x71 */ x86emuOp2_illegal_op, /* 0x72 */ x86emuOp2_illegal_op, /* 0x73 */ x86emuOp2_illegal_op, /* 0x74 */ x86emuOp2_illegal_op, /* 0x75 */ x86emuOp2_illegal_op, /* 0x76 */ x86emuOp2_illegal_op, /* 0x77 */ x86emuOp2_illegal_op, /* 0x78 */ x86emuOp2_illegal_op, /* 0x79 */ x86emuOp2_illegal_op, /* 0x7a */ x86emuOp2_illegal_op, /* 0x7b */ x86emuOp2_illegal_op, /* 0x7c */ x86emuOp2_illegal_op, /* 0x7d */ x86emuOp2_illegal_op, /* 0x7e */ x86emuOp2_illegal_op, /* 0x7f */ x86emuOp2_illegal_op, /* 0x80 */ x86emuOp2_long_jump, /* 0x81 */ x86emuOp2_long_jump, /* 0x82 */ x86emuOp2_long_jump, /* 0x83 */ x86emuOp2_long_jump, /* 0x84 */ x86emuOp2_long_jump, /* 0x85 */ x86emuOp2_long_jump, /* 0x86 */ x86emuOp2_long_jump, /* 0x87 */ x86emuOp2_long_jump, /* 0x88 */ x86emuOp2_long_jump, /* 0x89 */ x86emuOp2_long_jump, /* 0x8a */ x86emuOp2_long_jump, /* 0x8b */ x86emuOp2_long_jump, /* 0x8c */ x86emuOp2_long_jump, /* 0x8d */ x86emuOp2_long_jump, /* 0x8e */ x86emuOp2_long_jump, /* 0x8f */ x86emuOp2_long_jump, /* 0x90 */ x86emuOp2_set_byte, /* 0x91 */ x86emuOp2_set_byte, /* 0x92 */ x86emuOp2_set_byte, /* 0x93 */ x86emuOp2_set_byte, /* 0x94 */ x86emuOp2_set_byte, /* 0x95 */ x86emuOp2_set_byte, /* 0x96 */ x86emuOp2_set_byte, /* 0x97 */ x86emuOp2_set_byte, /* 0x98 */ x86emuOp2_set_byte, /* 0x99 */ x86emuOp2_set_byte, /* 0x9a */ x86emuOp2_set_byte, /* 0x9b */ x86emuOp2_set_byte, /* 0x9c */ x86emuOp2_set_byte, /* 0x9d */ x86emuOp2_set_byte, /* 0x9e */ x86emuOp2_set_byte, /* 0x9f */ x86emuOp2_set_byte, /* 0xa0 */ x86emuOp2_push_FS, /* 0xa1 */ x86emuOp2_pop_FS, /* 0xa2 */ x86emuOp2_illegal_op, /* 0xa3 */ x86emuOp2_bt_R, /* 0xa4 */ x86emuOp2_shld_IMM, /* 0xa5 */ x86emuOp2_shld_CL, /* 0xa6 */ x86emuOp2_illegal_op, /* 0xa7 */ x86emuOp2_illegal_op, /* 0xa8 */ x86emuOp2_push_GS, /* 0xa9 */ x86emuOp2_pop_GS, /* 0xaa */ x86emuOp2_illegal_op, /* 0xab */ x86emuOp2_bts_R, /* 0xac */ x86emuOp2_shrd_IMM, /* 0xad */ x86emuOp2_shrd_CL, /* 0xae */ x86emuOp2_illegal_op, /* 0xaf */ x86emuOp2_imul_R_RM, /* 0xb0 */ x86emuOp2_illegal_op, /* TODO: cmpxchg */ /* 0xb1 */ x86emuOp2_illegal_op, /* TODO: cmpxchg */ /* 0xb2 */ x86emuOp2_lss_R_IMM, /* 0xb3 */ x86emuOp2_btr_R, /* 0xb4 */ x86emuOp2_lfs_R_IMM, /* 0xb5 */ x86emuOp2_lgs_R_IMM, /* 0xb6 */ x86emuOp2_movzx_byte_R_RM, /* 0xb7 */ x86emuOp2_movzx_word_R_RM, /* 0xb8 */ x86emuOp2_illegal_op, /* 0xb9 */ x86emuOp2_illegal_op, /* 0xba */ x86emuOp2_btX_I, /* 0xbb */ x86emuOp2_btc_R, /* 0xbc */ x86emuOp2_bsf, /* 0xbd */ x86emuOp2_bsr, /* 0xbe */ x86emuOp2_movsx_byte_R_RM, /* 0xbf */ x86emuOp2_movsx_word_R_RM, /* 0xc0 */ x86emuOp2_illegal_op, /* TODO: xadd */ /* 0xc1 */ x86emuOp2_illegal_op, /* TODO: xadd */ /* 0xc2 */ x86emuOp2_illegal_op, /* 0xc3 */ x86emuOp2_illegal_op, /* 0xc4 */ x86emuOp2_illegal_op, /* 0xc5 */ x86emuOp2_illegal_op, /* 0xc6 */ x86emuOp2_illegal_op, /* 0xc7 */ x86emuOp2_illegal_op, /* 0xc8 */ x86emuOp2_illegal_op, /* TODO: bswap */ /* 0xc9 */ x86emuOp2_illegal_op, /* TODO: bswap */ /* 0xca */ x86emuOp2_illegal_op, /* TODO: bswap */ /* 0xcb */ x86emuOp2_illegal_op, /* TODO: bswap */ /* 0xcc */ x86emuOp2_illegal_op, /* TODO: bswap */ /* 0xcd */ x86emuOp2_illegal_op, /* TODO: bswap */ /* 0xce */ x86emuOp2_illegal_op, /* TODO: bswap */ /* 0xcf */ x86emuOp2_illegal_op, /* TODO: bswap */ /* 0xd0 */ x86emuOp2_illegal_op, /* 0xd1 */ x86emuOp2_illegal_op, /* 0xd2 */ x86emuOp2_illegal_op, /* 0xd3 */ x86emuOp2_illegal_op, /* 0xd4 */ x86emuOp2_illegal_op, /* 0xd5 */ x86emuOp2_illegal_op, /* 0xd6 */ x86emuOp2_illegal_op, /* 0xd7 */ x86emuOp2_illegal_op, /* 0xd8 */ x86emuOp2_illegal_op, /* 0xd9 */ x86emuOp2_illegal_op, /* 0xda */ x86emuOp2_illegal_op, /* 0xdb */ x86emuOp2_illegal_op, /* 0xdc */ x86emuOp2_illegal_op, /* 0xdd */ x86emuOp2_illegal_op, /* 0xde */ x86emuOp2_illegal_op, /* 0xdf */ x86emuOp2_illegal_op, /* 0xe0 */ x86emuOp2_illegal_op, /* 0xe1 */ x86emuOp2_illegal_op, /* 0xe2 */ x86emuOp2_illegal_op, /* 0xe3 */ x86emuOp2_illegal_op, /* 0xe4 */ x86emuOp2_illegal_op, /* 0xe5 */ x86emuOp2_illegal_op, /* 0xe6 */ x86emuOp2_illegal_op, /* 0xe7 */ x86emuOp2_illegal_op, /* 0xe8 */ x86emuOp2_illegal_op, /* 0xe9 */ x86emuOp2_illegal_op, /* 0xea */ x86emuOp2_illegal_op, /* 0xeb */ x86emuOp2_illegal_op, /* 0xec */ x86emuOp2_illegal_op, /* 0xed */ x86emuOp2_illegal_op, /* 0xee */ x86emuOp2_illegal_op, /* 0xef */ x86emuOp2_illegal_op, /* 0xf0 */ x86emuOp2_illegal_op, /* 0xf1 */ x86emuOp2_illegal_op, /* 0xf2 */ x86emuOp2_illegal_op, /* 0xf3 */ x86emuOp2_illegal_op, /* 0xf4 */ x86emuOp2_illegal_op, /* 0xf5 */ x86emuOp2_illegal_op, /* 0xf6 */ x86emuOp2_illegal_op, /* 0xf7 */ x86emuOp2_illegal_op, /* 0xf8 */ x86emuOp2_illegal_op, /* 0xf9 */ x86emuOp2_illegal_op, /* 0xfa */ x86emuOp2_illegal_op, /* 0xfb */ x86emuOp2_illegal_op, /* 0xfc */ x86emuOp2_illegal_op, /* 0xfd */ x86emuOp2_illegal_op, /* 0xfe */ x86emuOp2_illegal_op, /* 0xff */ x86emuOp2_illegal_op, }; libx86emu-1.5/prim_ops.c000066400000000000000000002236541247503741400152210ustar00rootroot00000000000000/**************************************************************************** * * Realmode X86 Emulator Library * * Copyright (C) 1996-1999 SciTech Software, Inc. * Copyright (C) David Mosberger-Tang * 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. * * ======================================================================== * * Language: ANSI C * Environment: Any * Developer: Kendall Bennett * * Description: This file contains the code to implement the primitive * machine operations used by the emulation code in ops.c * * 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) * ****************************************************************************/ #include "include/x86emu_int.h" /*------------------------- Global Variables ------------------------------*/ static u32 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) /*----------------------------- Implementation ----------------------------*/ /**************************************************************************** REMARKS: Implements the AAA instruction and side effects. ****************************************************************************/ u16 aaa_word(u16 d) { u16 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 = (u16)(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. ****************************************************************************/ u16 aas_word(u16 d) { u16 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 = (u16)(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. ****************************************************************************/ u16 aad_word(u16 d, u8 base) { u16 l; u8 hb, lb; hb = (u8)((d >> 8) & 0xff); lb = (u8)((d & 0xff)); l = (u16)((lb + base * 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. ****************************************************************************/ u16 aam_word(u8 d, u8 base) { u16 h, l; h = (u16)(d / base); l = (u16)(d % base); l |= (u16)(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. ****************************************************************************/ u8 adc_byte(u8 d, u8 s) { register u32 res; /* all operands in native machine order */ register u32 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 (u8)res; } /**************************************************************************** REMARKS: Implements the ADC instruction and side effects. ****************************************************************************/ u16 adc_word(u16 d, u16 s) { register u32 res; /* all operands in native machine order */ register u32 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 (u16)res; } /**************************************************************************** REMARKS: Implements the ADC instruction and side effects. ****************************************************************************/ u32 adc_long(u32 d, u32 s) { register u32 lo; /* all operands in native machine order */ register u32 hi; register u32 res; register u32 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. ****************************************************************************/ u8 add_byte(u8 d, u8 s) { register u32 res; /* all operands in native machine order */ register u32 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 (u8)res; } /**************************************************************************** REMARKS: Implements the ADD instruction and side effects. ****************************************************************************/ u16 add_word(u16 d, u16 s) { register u32 res; /* all operands in native machine order */ register u32 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 (u16)res; } /**************************************************************************** REMARKS: Implements the ADD instruction and side effects. ****************************************************************************/ u32 add_long(u32 d, u32 s) { register u32 lo; /* all operands in native machine order */ register u32 hi; register u32 res; register u32 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. ****************************************************************************/ u8 and_byte(u8 d, u8 s) { register u8 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. ****************************************************************************/ u16 and_word(u16 d, u16 s) { register u16 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. ****************************************************************************/ u32 and_long(u32 d, u32 s) { register u32 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. ****************************************************************************/ u8 cmp_byte(u8 d, u8 s) { register u32 res; /* all operands in native machine order */ register u32 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; } /**************************************************************************** REMARKS: Implements the CMP instruction and side effects. ****************************************************************************/ u16 cmp_word(u16 d, u16 s) { register u32 res; /* all operands in native machine order */ register u32 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; } /**************************************************************************** REMARKS: Implements the CMP instruction and side effects. ****************************************************************************/ u32 cmp_long(u32 d, u32 s) { register u32 res; /* all operands in native machine order */ register u32 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; } /**************************************************************************** REMARKS: Implements the DAA instruction and side effects. ****************************************************************************/ u8 daa_byte(u8 d) { u32 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 (u8)res; } /**************************************************************************** REMARKS: Implements the DAS instruction and side effects. ****************************************************************************/ u8 das_byte(u8 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. ****************************************************************************/ u8 dec_byte(u8 d) { register u32 res; /* all operands in native machine order */ register u32 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 (u8)res; } /**************************************************************************** REMARKS: Implements the DEC instruction and side effects. ****************************************************************************/ u16 dec_word(u16 d) { register u32 res; /* all operands in native machine order */ register u32 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 (u16)res; } /**************************************************************************** REMARKS: Implements the DEC instruction and side effects. ****************************************************************************/ u32 dec_long(u32 d) { register u32 res; /* all operands in native machine order */ register u32 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. ****************************************************************************/ u8 inc_byte(u8 d) { register u32 res; /* all operands in native machine order */ register u32 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 (u8)res; } /**************************************************************************** REMARKS: Implements the INC instruction and side effects. ****************************************************************************/ u16 inc_word(u16 d) { register u32 res; /* all operands in native machine order */ register u32 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 (u16)res; } /**************************************************************************** REMARKS: Implements the INC instruction and side effects. ****************************************************************************/ u32 inc_long(u32 d) { register u32 res; /* all operands in native machine order */ register u32 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. ****************************************************************************/ u8 or_byte(u8 d, u8 s) { register u8 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. ****************************************************************************/ u16 or_word(u16 d, u16 s) { register u16 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. ****************************************************************************/ u32 or_long(u32 d, u32 s) { register u32 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. ****************************************************************************/ u8 neg_byte(u8 s) { register u8 res; register u8 bc; CONDITIONAL_SET_FLAG(s != 0, F_CF); res = (u8)-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. ****************************************************************************/ u16 neg_word(u16 s) { register u16 res; register u16 bc; CONDITIONAL_SET_FLAG(s != 0, F_CF); res = (u16)-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. ****************************************************************************/ u32 neg_long(u32 s) { register u32 res; register u32 bc; CONDITIONAL_SET_FLAG(s != 0, F_CF); res = (u32)-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 NOT instruction and side effects. ****************************************************************************/ u8 not_byte(u8 s) { return ~s; } /**************************************************************************** REMARKS: Implements the NOT instruction and side effects. ****************************************************************************/ u16 not_word(u16 s) { return ~s; } /**************************************************************************** REMARKS: Implements the NOT instruction and side effects. ****************************************************************************/ u32 not_long(u32 s) { return ~s; } /**************************************************************************** REMARKS: Implements the RCL instruction and side effects. ****************************************************************************/ u8 rcl_byte(u8 d, u8 s) { register 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 (u8)res; } /**************************************************************************** REMARKS: Implements the RCL instruction and side effects. ****************************************************************************/ u16 rcl_word(u16 d, u8 s) { register 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 (u16)res; } /**************************************************************************** REMARKS: Implements the RCL instruction and side effects. ****************************************************************************/ u32 rcl_long(u32 d, u8 s) { register u32 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. ****************************************************************************/ u8 rcr_byte(u8 d, u8 s) { u32 res, cnt; u32 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 (u8)res; } /**************************************************************************** REMARKS: Implements the RCR instruction and side effects. ****************************************************************************/ u16 rcr_word(u16 d, u8 s) { u32 res, cnt; u32 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 (u16)res; } /**************************************************************************** REMARKS: Implements the RCR instruction and side effects. ****************************************************************************/ u32 rcr_long(u32 d, u8 s) { u32 res, cnt; u32 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. ****************************************************************************/ u8 rol_byte(u8 d, u8 s) { register 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 (u8)res; } /**************************************************************************** REMARKS: Implements the ROL instruction and side effects. ****************************************************************************/ u16 rol_word(u16 d, u8 s) { register 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 (u16)res; } /**************************************************************************** REMARKS: Implements the ROL instruction and side effects. ****************************************************************************/ u32 rol_long(u32 d, u8 s) { register u32 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. ****************************************************************************/ u8 ror_byte(u8 d, u8 s) { register 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 (u8)res; } /**************************************************************************** REMARKS: Implements the ROR instruction and side effects. ****************************************************************************/ u16 ror_word(u16 d, u8 s) { register 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 (u16)res; } /**************************************************************************** REMARKS: Implements the ROR instruction and side effects. ****************************************************************************/ u32 ror_long(u32 d, u8 s) { register u32 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. ****************************************************************************/ u8 shl_byte(u8 d, u8 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 = (u8) d; } if (cnt == 1) { /* Needs simplification. */ CONDITIONAL_SET_FLAG( (((res & 0x80) == 0x80) ^ (ACCESS_FLAG(F_CF) != 0)), /* was (M.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 (u8)res; } /**************************************************************************** REMARKS: Implements the SHL instruction and side effects. ****************************************************************************/ u16 shl_word(u16 d, u8 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 = (u16) 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 (u16)res; } /**************************************************************************** REMARKS: Implements the SHL instruction and side effects. ****************************************************************************/ u32 shl_long(u32 d, u8 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. ****************************************************************************/ u8 shr_byte(u8 d, u8 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 = (u8) 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 (u8)res; } /**************************************************************************** REMARKS: Implements the SHR instruction and side effects. ****************************************************************************/ u16 shr_word(u16 d, u8 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 (u16)res; } /**************************************************************************** REMARKS: Implements the SHR instruction and side effects. ****************************************************************************/ u32 shr_long(u32 d, u8 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. ****************************************************************************/ u8 sar_byte(u8 d, u8 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 (u8)res; } /**************************************************************************** REMARKS: Implements the SAR instruction and side effects. ****************************************************************************/ u16 sar_word(u16 d, u8 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 (u16)res; } /**************************************************************************** REMARKS: Implements the SAR instruction and side effects. ****************************************************************************/ u32 sar_long(u32 d, u8 s) { u32 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. ****************************************************************************/ u16 shld_word (u16 d, u16 fill, u8 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 (u16)res; } /**************************************************************************** REMARKS: Implements the SHLD instruction and side effects. ****************************************************************************/ u32 shld_long (u32 d, u32 fill, u8 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. ****************************************************************************/ u16 shrd_word (u16 d, u16 fill, u8 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 (u16)res; } /**************************************************************************** REMARKS: Implements the SHRD instruction and side effects. ****************************************************************************/ u32 shrd_long (u32 d, u32 fill, u8 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. ****************************************************************************/ u8 sbb_byte(u8 d, u8 s) { register u32 res; /* all operands in native machine order */ register u32 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 (u8)res; } /**************************************************************************** REMARKS: Implements the SBB instruction and side effects. ****************************************************************************/ u16 sbb_word(u16 d, u16 s) { register u32 res; /* all operands in native machine order */ register u32 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 (u16)res; } /**************************************************************************** REMARKS: Implements the SBB instruction and side effects. ****************************************************************************/ u32 sbb_long(u32 d, u32 s) { register u32 res; /* all operands in native machine order */ register u32 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. ****************************************************************************/ u8 sub_byte(u8 d, u8 s) { register u32 res; /* all operands in native machine order */ register u32 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 (u8)res; } /**************************************************************************** REMARKS: Implements the SUB instruction and side effects. ****************************************************************************/ u16 sub_word(u16 d, u16 s) { register u32 res; /* all operands in native machine order */ register u32 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 (u16)res; } /**************************************************************************** REMARKS: Implements the SUB instruction and side effects. ****************************************************************************/ u32 sub_long(u32 d, u32 s) { register u32 res; /* all operands in native machine order */ register u32 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. ****************************************************************************/ void test_byte(u8 d, u8 s) { register u32 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. ****************************************************************************/ void test_word(u16 d, u16 s) { register u32 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. ****************************************************************************/ void test_long(u32 d, u32 s) { register u32 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. ****************************************************************************/ u8 xor_byte(u8 d, u8 s) { register u8 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. ****************************************************************************/ u16 xor_word(u16 d, u16 s) { register u16 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. ****************************************************************************/ u32 xor_long(u32 d, u32 s) { register u32 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. ****************************************************************************/ void imul_byte(u8 s) { s16 res = (s16)((s8)M.x86.R_AL * (s8)s); M.x86.R_AX = res; if (((M.x86.R_AL & 0x80) == 0 && M.x86.R_AH == 0x00) || ((M.x86.R_AL & 0x80) != 0 && M.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. ****************************************************************************/ void imul_word(u16 s) { s32 res = (s16)M.x86.R_AX * (s16)s; M.x86.R_AX = (u16)res; M.x86.R_DX = (u16)(res >> 16); if (((M.x86.R_AX & 0x8000) == 0 && M.x86.R_DX == 0x00) || ((M.x86.R_AX & 0x8000) != 0 && M.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. ****************************************************************************/ void imul_long_direct(u32 *res_lo, u32* res_hi,u32 d, u32 s) { #ifdef __HAS_LONG_LONG__ s64 res = (s32)d * (s32)s; *res_lo = (u32)res; *res_hi = (u32)(res >> 32); #else u32 d_lo,d_hi,d_sign; u32 s_lo,s_hi,s_sign; u32 rlo_lo,rlo_hi,rhi_lo; if ((d_sign = d & 0x80000000) != 0) d = -d; d_lo = d & 0xFFFF; d_hi = d >> 16; if ((s_sign = s & 0x80000000) != 0) s = -s; s_lo = s & 0xFFFF; s_hi = s >> 16; rlo_lo = d_lo * s_lo; rlo_hi = (d_hi * s_lo + d_lo * s_hi) + (rlo_lo >> 16); rhi_lo = d_hi * s_hi + (rlo_hi >> 16); *res_lo = (rlo_hi << 16) | (rlo_lo & 0xFFFF); *res_hi = rhi_lo; if (d_sign != s_sign) { d = ~*res_lo; s = (((d & 0xFFFF) + 1) >> 16) + (d >> 16); *res_lo = ~*res_lo+1; *res_hi = ~*res_hi+(s >> 16); } #endif } /**************************************************************************** REMARKS: Implements the IMUL instruction and side effects. ****************************************************************************/ void imul_long(u32 s) { imul_long_direct(&M.x86.R_EAX,&M.x86.R_EDX,M.x86.R_EAX,s); if (((M.x86.R_EAX & 0x80000000) == 0 && M.x86.R_EDX == 0x00) || ((M.x86.R_EAX & 0x80000000) != 0 && M.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. ****************************************************************************/ void mul_byte(u8 s) { u16 res = (u16)(M.x86.R_AL * s); M.x86.R_AX = res; if (M.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. ****************************************************************************/ void mul_word(u16 s) { u32 res = M.x86.R_AX * s; M.x86.R_AX = (u16)res; M.x86.R_DX = (u16)(res >> 16); if (M.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. ****************************************************************************/ void mul_long(u32 s) { #ifdef __HAS_LONG_LONG__ u64 res = (u32)M.x86.R_EAX * (u32)s; M.x86.R_EAX = (u32)res; M.x86.R_EDX = (u32)(res >> 32); #else u32 a,a_lo,a_hi; u32 s_lo,s_hi; u32 rlo_lo,rlo_hi,rhi_lo; a = M.x86.R_EAX; a_lo = a & 0xFFFF; a_hi = a >> 16; s_lo = s & 0xFFFF; s_hi = s >> 16; rlo_lo = a_lo * s_lo; rlo_hi = (a_hi * s_lo + a_lo * s_hi) + (rlo_lo >> 16); rhi_lo = a_hi * s_hi + (rlo_hi >> 16); M.x86.R_EAX = (rlo_hi << 16) | (rlo_lo & 0xFFFF); M.x86.R_EDX = rhi_lo; #endif if (M.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. ****************************************************************************/ void idiv_byte(u8 s) { s32 dvd, div, mod; dvd = (s16)M.x86.R_AX; if (s == 0) { INTR_RAISE_DIV0(&M); return; } div = dvd / (s8)s; mod = dvd % (s8)s; if (abs(div) > 0x7f) { INTR_RAISE_DIV0(&M); return; } M.x86.R_AL = (s8) div; M.x86.R_AH = (s8) mod; } /**************************************************************************** REMARKS: Implements the IDIV instruction and side effects. ****************************************************************************/ void idiv_word(u16 s) { s32 dvd, div, mod; dvd = (((s32)M.x86.R_DX) << 16) | M.x86.R_AX; if (s == 0) { INTR_RAISE_DIV0(&M); return; } div = dvd / (s16)s; mod = dvd % (s16)s; if (abs(div) > 0x7fff) { INTR_RAISE_DIV0(&M); return; } CLEAR_FLAG(F_CF); CLEAR_FLAG(F_SF); CONDITIONAL_SET_FLAG(div == 0, F_ZF); CONDITIONAL_SET_FLAG(PARITY(mod & 0xff), F_PF); M.x86.R_AX = (u16)div; M.x86.R_DX = (u16)mod; } /**************************************************************************** REMARKS: Implements the IDIV instruction and side effects. ****************************************************************************/ void idiv_long(u32 s) { #ifdef __HAS_LONG_LONG__ s64 dvd, div, mod; dvd = (((s64)M.x86.R_EDX) << 32) | M.x86.R_EAX; if (s == 0) { INTR_RAISE_DIV0(&M); return; } div = dvd / (s32)s; mod = dvd % (s32)s; if (abs(div) > 0x7fffffff) { INTR_RAISE_DIV0(&M); return; } #else s32 div = 0, mod; s32 h_dvd = M.x86.R_EDX; u32 l_dvd = M.x86.R_EAX; u32 abs_s = s & 0x7FFFFFFF; u32 abs_h_dvd = h_dvd & 0x7FFFFFFF; u32 h_s = abs_s >> 1; u32 l_s = abs_s << 31; int counter = 31; int carry; if (s == 0) { INTR_RAISE_DIV0(&M); return; } do { div <<= 1; carry = (l_dvd >= l_s) ? 0 : 1; if (abs_h_dvd < (h_s + carry)) { h_s >>= 1; l_s = abs_s << (--counter); continue; } else { abs_h_dvd -= (h_s + carry); l_dvd = carry ? ((0xFFFFFFFF - l_s) + l_dvd + 1) : (l_dvd - l_s); h_s >>= 1; l_s = abs_s << (--counter); div |= 1; continue; } } while (counter > -1); /* overflow */ if (abs_h_dvd || (l_dvd > abs_s)) { INTR_RAISE_DIV0(&M); return; } /* sign */ div |= ((h_dvd & 0x10000000) ^ (s & 0x10000000)); mod = l_dvd; #endif CLEAR_FLAG(F_CF); CLEAR_FLAG(F_AF); CLEAR_FLAG(F_SF); SET_FLAG(F_ZF); CONDITIONAL_SET_FLAG(PARITY(mod & 0xff), F_PF); M.x86.R_EAX = (u32)div; M.x86.R_EDX = (u32)mod; } /**************************************************************************** REMARKS: Implements the DIV instruction and side effects. ****************************************************************************/ void div_byte(u8 s) { u32 dvd, div, mod; dvd = M.x86.R_AX; if (s == 0) { INTR_RAISE_DIV0(&M); return; } div = dvd / (u8)s; mod = dvd % (u8)s; if (abs(div) > 0xff) { INTR_RAISE_DIV0(&M); return; } M.x86.R_AL = (u8)div; M.x86.R_AH = (u8)mod; } /**************************************************************************** REMARKS: Implements the DIV instruction and side effects. ****************************************************************************/ void div_word(u16 s) { u32 dvd, div, mod; dvd = (((u32)M.x86.R_DX) << 16) | M.x86.R_AX; if (s == 0) { INTR_RAISE_DIV0(&M); return; } div = dvd / (u16)s; mod = dvd % (u16)s; if (abs(div) > 0xffff) { INTR_RAISE_DIV0(&M); return; } CLEAR_FLAG(F_CF); CLEAR_FLAG(F_SF); CONDITIONAL_SET_FLAG(div == 0, F_ZF); CONDITIONAL_SET_FLAG(PARITY(mod & 0xff), F_PF); M.x86.R_AX = (u16)div; M.x86.R_DX = (u16)mod; } /**************************************************************************** REMARKS: Implements the DIV instruction and side effects. ****************************************************************************/ void div_long(u32 s) { #ifdef __HAS_LONG_LONG__ u64 dvd, div, mod; dvd = (((u64)M.x86.R_EDX) << 32) | M.x86.R_EAX; if (s == 0) { INTR_RAISE_DIV0(&M); return; } div = dvd / (u32)s; mod = dvd % (u32)s; if (abs(div) > 0xffffffff) { INTR_RAISE_DIV0(&M); return; } #else s32 div = 0, mod; s32 h_dvd = M.x86.R_EDX; u32 l_dvd = M.x86.R_EAX; u32 h_s = s; u32 l_s = 0; int counter = 32; int carry; if (s == 0) { INTR_RAISE_DIV0(&M); return; } do { div <<= 1; carry = (l_dvd >= l_s) ? 0 : 1; if (h_dvd < (h_s + carry)) { h_s >>= 1; l_s = s << (--counter); continue; } else { h_dvd -= (h_s + carry); l_dvd = carry ? ((0xFFFFFFFF - l_s) + l_dvd + 1) : (l_dvd - l_s); h_s >>= 1; l_s = s << (--counter); div |= 1; continue; } } while (counter > -1); /* overflow */ if (h_dvd || (l_dvd > s)) { INTR_RAISE_DIV0(&M); return; } mod = l_dvd; #endif CLEAR_FLAG(F_CF); CLEAR_FLAG(F_AF); CLEAR_FLAG(F_SF); SET_FLAG(F_ZF); CONDITIONAL_SET_FLAG(PARITY(mod & 0xff), F_PF); M.x86.R_EAX = (u32)div; M.x86.R_EDX = (u32)mod; } /**************************************************************************** REMARKS: Implements the IN string instruction and side effects. ****************************************************************************/ void ins(int size) { s32 inc; u32 count; inc = ACCESS_FLAG(F_DF) ? -1 : 1; if(MODE_ADDR32) { if(MODE_REP) { count = M.x86.R_ECX; M.x86.R_ECX = 0; switch(size) { case 1: while(count--) { store_data_byte_abs(M.x86.seg + R_ES_INDEX, M.x86.R_EDI, fetch_io_byte(M.x86.R_DX)); M.x86.R_EDI += inc; } break; case 2: while(count--) { store_data_word_abs(M.x86.seg + R_ES_INDEX, M.x86.R_EDI, fetch_io_word(M.x86.R_DX)); M.x86.R_EDI += inc; } break; case 4: while(count--) { store_data_long_abs(M.x86.seg + R_ES_INDEX, M.x86.R_EDI, fetch_io_long(M.x86.R_DX)); M.x86.R_EDI += inc; } break; } } else { switch(size) { case 1: store_data_byte_abs(M.x86.seg + R_ES_INDEX, M.x86.R_EDI, fetch_io_byte(M.x86.R_DX)); break; case 2: store_data_word_abs(M.x86.seg + R_ES_INDEX, M.x86.R_EDI, fetch_io_word(M.x86.R_DX)); break; case 4: store_data_long_abs(M.x86.seg + R_ES_INDEX, M.x86.R_EDI, fetch_io_long(M.x86.R_DX)); break; } M.x86.R_EDI += inc; } } else { if(MODE_REP) { count = M.x86.R_CX; M.x86.R_CX = 0; switch(size) { case 1: while(count--) { store_data_byte_abs(M.x86.seg + R_ES_INDEX, M.x86.R_DI, fetch_io_byte(M.x86.R_DX)); M.x86.R_DI += inc; } break; case 2: while(count--) { store_data_word_abs(M.x86.seg + R_ES_INDEX, M.x86.R_DI, fetch_io_word(M.x86.R_DX)); M.x86.R_DI += inc; } break; case 4: while(count--) { store_data_long_abs(M.x86.seg + R_ES_INDEX, M.x86.R_DI, fetch_io_long(M.x86.R_DX)); M.x86.R_DI += inc; } break; } } else { switch(size) { case 1: store_data_byte_abs(M.x86.seg + R_ES_INDEX, M.x86.R_DI, fetch_io_byte(M.x86.R_DX)); break; case 2: store_data_word_abs(M.x86.seg + R_ES_INDEX, M.x86.R_DI, fetch_io_word(M.x86.R_DX)); break; case 4: store_data_long_abs(M.x86.seg + R_ES_INDEX, M.x86.R_DI, fetch_io_byte(M.x86.R_DX)); break; } M.x86.R_DI += inc; } } } /**************************************************************************** REMARKS: Implements the OUT string instruction and side effects. ****************************************************************************/ void outs(int size) { s32 inc; u32 count; inc = ACCESS_FLAG(F_DF) ? -1 : 1; if(MODE_ADDR32) { if(MODE_REP) { count = M.x86.R_ECX; M.x86.R_ECX = 0; switch(size) { case 1: while(count--) { store_io_byte(M.x86.R_DX, fetch_data_byte_abs(M.x86.seg + R_ES_INDEX, M.x86.R_ESI)); M.x86.R_ESI += inc; } break; case 2: while(count--) { store_io_word(M.x86.R_DX, fetch_data_word_abs(M.x86.seg + R_ES_INDEX, M.x86.R_ESI)); M.x86.R_ESI += inc; } break; case 4: while(count--) { store_io_long(M.x86.R_DX, fetch_data_long_abs(M.x86.seg + R_ES_INDEX, M.x86.R_ESI)); M.x86.R_ESI += inc; } break; } } else { switch(size) { case 1: store_io_byte(M.x86.R_DX, fetch_data_byte_abs(M.x86.seg + R_ES_INDEX, M.x86.R_ESI)); break; case 2: store_io_word(M.x86.R_DX, fetch_data_word_abs(M.x86.seg + R_ES_INDEX, M.x86.R_ESI)); break; case 4: store_io_long(M.x86.R_DX, fetch_data_long_abs(M.x86.seg + R_ES_INDEX, M.x86.R_ESI)); break; } M.x86.R_SI += inc; } } else { if(MODE_REP) { count = M.x86.R_CX; M.x86.R_CX = 0; switch(size) { case 1: while(count--) { store_io_byte(M.x86.R_DX, fetch_data_byte_abs(M.x86.seg + R_ES_INDEX, M.x86.R_SI)); M.x86.R_SI += inc; } break; case 2: while(count--) { store_io_word(M.x86.R_DX, fetch_data_word_abs(M.x86.seg + R_ES_INDEX, M.x86.R_SI)); M.x86.R_SI += inc; } break; case 4: while(count--) { store_io_long(M.x86.R_DX, fetch_data_long_abs(M.x86.seg + R_ES_INDEX, M.x86.R_SI)); M.x86.R_SI += inc; } break; } } else { switch(size) { case 1: store_io_byte(M.x86.R_DX, fetch_data_byte_abs(M.x86.seg + R_ES_INDEX, M.x86.R_SI)); break; case 2: store_io_word(M.x86.R_DX, fetch_data_word_abs(M.x86.seg + R_ES_INDEX, M.x86.R_SI)); break; case 4: store_io_long(M.x86.R_DX, fetch_data_long_abs(M.x86.seg + R_ES_INDEX, M.x86.R_SI)); break; } M.x86.R_SI += inc; } } } /**************************************************************************** REMARKS: Pushes a word onto the stack. ****************************************************************************/ void push_word(u16 w) { if(MODE_STACK32) { M.x86.R_ESP -= 2; store_data_word_abs(M.x86.seg + R_SS_INDEX, M.x86.R_ESP, w); } else { M.x86.R_SP -= 2; store_data_word_abs(M.x86.seg + R_SS_INDEX, M.x86.R_SP, w); } } /**************************************************************************** REMARKS: Pushes a long onto the stack. ****************************************************************************/ void push_long(u32 w) { if(MODE_STACK32) { M.x86.R_ESP -= 4; store_data_long_abs(M.x86.seg + R_SS_INDEX, M.x86.R_ESP, w); } else { M.x86.R_SP -= 4; store_data_long_abs(M.x86.seg + R_SS_INDEX, M.x86.R_SP, w); } } /**************************************************************************** REMARKS: Pops a word from the stack. ****************************************************************************/ u16 pop_word(void) { u16 res; if(MODE_STACK32) { res = fetch_data_word_abs(M.x86.seg + R_SS_INDEX, M.x86.R_ESP); M.x86.R_ESP += 2; } else { res = fetch_data_word_abs(M.x86.seg + R_SS_INDEX, M.x86.R_SP); M.x86.R_SP += 2; } return res; } /**************************************************************************** REMARKS: Pops a long from the stack. ****************************************************************************/ u32 pop_long(void) { u32 res; if(MODE_STACK32) { res = fetch_data_long_abs(M.x86.seg + R_SS_INDEX, M.x86.R_ESP); M.x86.R_ESP += 4; } else { res = fetch_data_long_abs(M.x86.seg + R_SS_INDEX, M.x86.R_SP); M.x86.R_SP += 4; } return res; } int eval_condition(unsigned type) { int cond = 0; unsigned flags = M.x86.R_EFLG; switch(type >> 1) { case 0: /* O */ cond = flags & F_OF; break; case 1: /* B */ cond = flags & F_CF; break; case 3: /* BE */ cond = (flags & F_CF) != 0; case 2: /* Z */ cond |= (flags & F_ZF) != 0; break; case 4: /* S */ cond = flags & F_SF; break; case 5: /* P */ cond = flags & F_PF; break; case 7: /* LE */ cond = (flags & F_ZF) != 0; case 6: /* L */ cond |= ((flags & F_SF) != 0) ^ ((flags & F_OF) != 0); break; } return type & 1 ? !cond : cond; } libx86emu-1.5/test/000077500000000000000000000000001247503741400141705ustar00rootroot00000000000000libx86emu-1.5/test/0001_00_add.done000066400000000000000000000043361247503741400165340ustar00rootroot00000000000000; - - memory ; 0 1 2 3 4 5 6 7 8 9 a b c d e f 00001000: 00 08 00 09 00 0a 00 0b 00 0c 00 0d 00 0e 00 90 00001010: 00 0f 00 68 40 00 69 40 00 6a 40 00 6b 40 00 6c 00001020: 40 00 6d 40 00 6e 40 00 6f 40 26 00 90 00 08 26 00001030: 00 91 00 08 26 00 92 00 08 26 00 93 00 08 26 00 00001040: 94 00 08 26 00 95 00 08 26 00 96 00 08 26 00 97 00001050: 00 08 00 f0 00 f1 00 f2 00 f3 00 f4 00 f5 00 f6 00001060: 00 f7 67 00 01 f4 00020000: *55 00020030: *66 00020040: *66 00024ff0: *55 00025000: *aa 00025030: *66 00025040: *cc 00029000: *55 0002aa90: *44 0002fff0: *55 00049ff0: *55 0004a000: *55 0004a030: *66 0004a040: *cc 000607f0: *33 00060800: *33 000657f0: *33 00065800: *66 0006a7f0: *33 0006a800: *66 ; - - registers msr[0010] 0000000000000022 ; tsc cr0=00000000 cr1=00000000 cr2=00000000 cr3=00000000 cr4=00000000 dr0=00000000 dr1=00000000 dr2=00000000 dr3=00000000 dr6=00000000 dr7=00000000 gdt.base=00000000 gdt.limit=ffff idt.base=00000000 idt.limit=ffff tr=0000 tr.base=00000000 tr.limit=00000000 tr.acc=0000 ldt=0000 ldt.base=00000000 ldt.limit=00000000 ldt.acc=0000 cs=0100 cs.base=00001000 cs.limit=0000ffff cs.acc=009b ss=4000 ss.base=00040000 ss.limit=0000ffff ss.acc=0093 ds=2000 ds.base=00020000 ds.limit=0000ffff ds.acc=0093 es=6000 es.base=00060000 es.limit=0000ffff es.acc=0093 fs=0000 fs.base=00000000 fs.limit=0000ffff fs.acc=0093 gs=0000 gs.base=00000000 gs.limit=0000ffff gs.acc=0093 eax=00004444 ebx=0000d844 ecx=0000aa99 edx=00008877 esi=00000000 edi=0000ffff ebp=0000a000 esp=00000000 eip=00000066 eflags=00000006 ; pf libx86emu-1.5/test/0001_00_add.tst000066400000000000000000000012741247503741400164170ustar00rootroot00000000000000[init] esi=0x0000 edi=0xffff ebp=0xa000 ebx=0x5000 edx=0x4433 ecx=0x6655 ds=0x2000 ss=0x4000 es=0x6000 [code start=0x100:0x0] add [bx+si],cl add [bx+di],cl add [bp+si],cl add [bp+di],cl add [si],cl add [di],cl add [0x9000],cl add [bx],cl add [bx+si+0x40],ch add [bx+di+0x40],ch add [bp+si+0x40],ch add [bp+di+0x40],ch add [si+0x40],ch add [di+0x40],ch add [bp+0x40],ch add [bx+0x40],ch add [es:bx+si+0x800],dl add [es:bx+di+0x800],dl add [es:bp+si+0x800],dl add [es:bp+di+0x800],dl add [es:si+0x800],dl add [es:di+0x800],dl add [es:bp+0x800],dl add [es:bx+0x800],dl add al,dh add cl,dh add dl,dh add bl,dh add ah,dh add ch,dh add dh,dh add bh,dh add [ecx],al libx86emu-1.5/test/0002_8e_mov_sr.done000066400000000000000000000022171247503741400174030ustar00rootroot00000000000000; - - memory ; 0 1 2 3 4 5 6 7 8 9 a b c d e f 00001000: 8e c1 8e e2 2e 8e 2e 00 07 0f a8 8c 2e 04 17 ea 00001010: 17 04 c0 00 b9 11 11 bb 99 99 f4 00001700: 01 02 01 02 00008ff0: 01 02 ; - - registers msr[0010] 0000000000000008 ; tsc cr0=00000000 cr1=00000000 cr2=00000000 cr3=00000000 cr4=00000000 dr0=00000000 dr1=00000000 dr2=00000000 dr3=00000000 dr6=00000000 dr7=00000000 gdt.base=00000000 gdt.limit=ffff idt.base=00000000 idt.limit=ffff tr=0000 tr.base=00000000 tr.limit=00000000 tr.acc=0000 ldt=0000 ldt.base=00000000 ldt.limit=00000000 ldt.acc=0000 cs=00c0 cs.base=00000c00 cs.limit=0000ffff cs.acc=009b ss=0000 ss.base=00000000 ss.limit=0000ffff ss.acc=0093 ds=0000 ds.base=00000000 ds.limit=0000ffff ds.acc=0093 es=6789 es.base=00067890 es.limit=0000ffff es.acc=0093 fs=5555 fs.base=00055550 fs.limit=0000ffff fs.acc=0093 gs=0201 gs.base=00002010 gs.limit=0000ffff gs.acc=0093 eax=00000000 ebx=00009999 ecx=00006789 edx=00005555 esi=00000000 edi=00000000 ebp=00000000 esp=00008ffe eip=0000041b eflags=00000002 libx86emu-1.5/test/0002_8e_mov_sr.tst000066400000000000000000000003141247503741400172640ustar00rootroot00000000000000[init] 0x1700: 1 2 ecx=0x6789 edx=0x5555 esp=0x9000 [code start=0x100:0x0] mov es,cx mov fs,edx mov gs,[cs:0x700] push gs mov [0x1704],gs jmp 0xc0:foo+0x400 mov cx,0x1111 foo: mov bx,0x9999 libx86emu-1.5/test/0003_lds_real.done000066400000000000000000000021411247503741400172640ustar00rootroot00000000000000; - - memory ; 0 1 2 3 4 5 6 7 8 9 a b c d e f 00001000: 66 67 c4 35 00 20 00 00 66 0f b4 3f 67 0f b5 29 00001010: f4 00002000: 70 8c 30 78 14 41 00002010: cb e3 c8 da 8c a3 00002020: 5b 34 d5 eb 1b d8 ; - - registers msr[0010] 0000000000000004 ; tsc cr0=00000000 cr1=00000000 cr2=00000000 cr3=00000000 cr4=00000000 dr0=00000000 dr1=00000000 dr2=00000000 dr3=00000000 dr6=00000000 dr7=00000000 gdt.base=00000000 gdt.limit=ffff idt.base=00000000 idt.limit=ffff tr=0000 tr.base=00000000 tr.limit=00000000 tr.acc=0000 ldt=0000 ldt.base=00000000 ldt.limit=00000000 ldt.acc=0000 cs=0100 cs.base=00001000 cs.limit=0000ffff cs.acc=009b ss=0000 ss.base=00000000 ss.limit=0000ffff ss.acc=0093 ds=0000 ds.base=00000000 ds.limit=0000ffff ds.acc=0093 es=4114 es.base=00041140 es.limit=0000ffff es.acc=0093 fs=a38c fs.base=000a38c0 fs.limit=0000ffff fs.acc=0093 gs=ebd5 gs.base=000ebd50 gs.limit=0000ffff gs.acc=0093 eax=00000000 ebx=12342010 ecx=00002020 edx=00000000 esi=78308c70 edi=dac8e3cb ebp=0000345b esp=00000000 eip=00000011 eflags=00000002 libx86emu-1.5/test/0003_lds_real.tst000066400000000000000000000003041247503741400171500ustar00rootroot00000000000000[init srand=6 mode=real] 0x2000-0x2005: rand 0x2010-0x2015: rand 0x2020-0x2025: rand ebx=0x12342010 ecx=0x2020 [code start=0x100:0 bits=16] les esi,[dword 0x2000] lfs edi,[bx] lgs bp,[ecx] libx86emu-1.5/test/0004_stack32_real.done000066400000000000000000000020031247503741400177520ustar00rootroot00000000000000; - - memory ; 0 1 2 3 4 5 6 7 8 9 a b c d e f 00001000: 50 5b f4 fffffff0: 72 ff 2a 23 ; - - registers msr[0010] 0000000000000003 ; tsc cr0=00000000 cr1=00000000 cr2=00000000 cr3=00000000 cr4=00000000 dr0=00000000 dr1=00000000 dr2=00000000 dr3=00000000 dr6=00000000 dr7=00000000 gdt.base=00000000 gdt.limit=ffff idt.base=00000000 idt.limit=ffff tr=0000 tr.base=00000000 tr.limit=00000000 tr.acc=0000 ldt=0000 ldt.base=00000000 ldt.limit=00000000 ldt.acc=0000 cs=0100 cs.base=00001000 cs.limit=0000ffff cs.acc=049b ss=0000 ss.base=00000000 ss.limit=ffffffff ss.acc=0c93 ds=0000 ds.base=00000000 ds.limit=0000ffff ds.acc=0093 es=0000 es.base=00000000 es.limit=0000ffff es.acc=0093 fs=0000 fs.base=00000000 fs.limit=0000ffff fs.acc=0093 gs=0000 gs.base=00000000 gs.limit=0000ffff gs.acc=0093 eax=232aff72 ebx=232aff72 ecx=00000000 edx=00000000 esi=00000000 edi=00000000 ebp=00000000 esp=00000000 eip=00000003 eflags=00000002 libx86emu-1.5/test/0004_stack32_real.tst000066400000000000000000000001521247503741400176420ustar00rootroot00000000000000[init srand=8 mode=real] eax=rand ss.limit=0xffffffff [code start=0x100:0 bits=32] push eax pop ebx libx86emu-1.5/test/0005_stack16_real.done000066400000000000000000000020131247503741400177560ustar00rootroot00000000000000; - - memory ; 0 1 2 3 4 5 6 7 8 9 a b c d e f 00001000: 66 50 66 5b f4 0000fff0: 73 1f 11 02 ; - - registers msr[0010] 0000000000000003 ; tsc cr0=00000000 cr1=00000000 cr2=00000000 cr3=00000000 cr4=00000000 dr0=00000000 dr1=00000000 dr2=00000000 dr3=00000000 dr6=00000000 dr7=00000000 gdt.base=00000000 gdt.limit=ffff idt.base=00000000 idt.limit=ffff tr=0000 tr.base=00000000 tr.limit=00000000 tr.acc=0000 ldt=0000 ldt.base=00000000 ldt.limit=00000000 ldt.acc=0000 cs=0100 cs.base=00001000 cs.limit=0000ffff cs.acc=009b ss=0000 ss.base=00000000 ss.limit=0000ffff ss.acc=0093 ds=0000 ds.base=00000000 ds.limit=0000ffff ds.acc=0093 es=0000 es.base=00000000 es.limit=0000ffff es.acc=0093 fs=0000 fs.base=00000000 fs.limit=0000ffff fs.acc=0093 gs=0000 gs.base=00000000 gs.limit=0000ffff gs.acc=0093 eax=02111f73 ebx=02111f73 ecx=00000000 edx=00000000 esi=00000000 edi=00000000 ebp=00000000 esp=00000000 eip=00000005 eflags=00000002 libx86emu-1.5/test/0005_stack16_real.tst000066400000000000000000000001251247503741400176450ustar00rootroot00000000000000[init srand=9 mode=real] eax=rand [code start=0x100:0 bits=16] push eax pop ebx libx86emu-1.5/test/0006_div0.done000066400000000000000000000021011247503741400163400ustar00rootroot00000000000000; - - memory ; 0 1 2 3 4 5 6 7 8 9 a b c d e f 00001050: f7 f1 f4 66 5b 66 53 b9 00 01 cf f4 00009000: 53 00 00 01 0000fff0: 50 00 00 01 02 00 ; - - registers msr[0010] 0000000000000007 ; tsc cr0=00000000 cr1=00000000 cr2=00000000 cr3=00000000 cr4=00000000 dr0=00000000 dr1=00000000 dr2=00000000 dr3=00000000 dr6=00000000 dr7=00000000 gdt.base=00000000 gdt.limit=ffff idt.base=00009000 idt.limit=ffff tr=0000 tr.base=00000000 tr.limit=00000000 tr.acc=0000 ldt=0000 ldt.base=00000000 ldt.limit=00000000 ldt.acc=0000 cs=0100 cs.base=00001000 cs.limit=0000ffff cs.acc=009b ss=0000 ss.base=00000000 ss.limit=0000ffff ss.acc=0093 ds=0000 ds.base=00000000 ds.limit=0000ffff ds.acc=0093 es=0000 es.base=00000000 es.limit=0000ffff es.acc=0093 fs=0000 fs.base=00000000 fs.limit=0000ffff fs.acc=0093 gs=0000 gs.base=00000000 gs.limit=0000ffff gs.acc=0093 eax=00000120 ebx=01000050 ecx=00000100 edx=00000045 esi=00000000 edi=00000000 ebp=00000000 esp=00000000 eip=00000053 eflags=00000002 libx86emu-1.5/test/0006_div0.tst000066400000000000000000000002241247503741400162310ustar00rootroot00000000000000[init mode=real] idt.base=0x9000 edx=0x1 eax=0x2045 [code start=0x100:0x50] div cx hlt interrupt_00: pop ebx push ebx mov cx,0x100 iret libx86emu-1.5/test/0007_seg_load_pm16.done000066400000000000000000000023451247503741400201310ustar00rootroot00000000000000; - - memory ; 0 1 2 3 4 5 6 7 8 9 a b c d e f 00001000: 8e c3 26 66 c7 06 50 00 78 56 34 12 8e e1 90 f4 00002000: 00 00 00 00 00 00 00 00 ff 8f 00 10 00 9b 00 00 00002010: 00 00 00 30 00 93 ca 00 99 00 00 00 00 13 00 00 00003050: 78 56 34 12 0000fff0: 18 00 00 00 0c 00 08 00 02 00 ; - - registers msr[0010] 0000000000000003 ; tsc cr0=00000001 cr1=00000000 cr2=00000000 cr3=00000000 cr4=00000000 dr0=00000000 dr1=00000000 dr2=00000000 dr3=00000000 dr6=00000000 dr7=00000000 gdt.base=00002000 gdt.limit=ffff idt.base=00000000 idt.limit=ffff tr=0000 tr.base=00000000 tr.limit=00000000 tr.acc=0000 ldt=0000 ldt.base=00000000 ldt.limit=00000000 ldt.acc=0000 cs=0008 cs.base=00001000 cs.limit=00008fff cs.acc=009b ss=0000 ss.base=00000000 ss.limit=00000000 ss.acc=0000 ds=0000 ds.base=00000000 ds.limit=00000000 ds.acc=0000 es=0010 es.base=00003000 es.limit=a0000fff es.acc=0c93 fs=0000 fs.base=00000000 fs.limit=00000000 fs.acc=0000 gs=0000 gs.base=00000000 gs.limit=00000000 gs.acc=0000 eax=00000000 ebx=00000010 ecx=00000018 edx=00000000 esi=00000000 edi=00000000 ebp=00000000 esp=0000fff6 eip=0000000c eflags=00000002 libx86emu-1.5/test/0007_seg_load_pm16.tst000066400000000000000000000004561247503741400200170ustar00rootroot00000000000000[init mode=pm] gdt.base=0x2000 gdt[0x00]=0 gdt[0x08]=descr(base=0x1000,limit=0x8fff,acc=0x9b) gdt[0x10]=descr(base=0x3000,limit=0xa0000fff,acc=0xc93) gdt[0x18]=descr(base=0,limit=0x99,acc=0x013) ebx=0x10 ecx=0x18 [code start=8:0 bits=16] mov es,bx mov dword [es:0x50],0x12345678 mov fs,cx nop libx86emu-1.5/test/0008_seg_load_pm32.done000066400000000000000000000023631247503741400201300ustar00rootroot00000000000000; - - memory ; 0 1 2 3 4 5 6 7 8 9 a b c d e f 00001000: 8e c3 26 c7 05 50 00 00 00 78 56 34 12 8e e1 90 00001010: f4 00002000: 00 00 00 00 00 00 00 00 ff 8f 00 10 00 9b 40 00 00002010: 00 00 00 30 00 93 ca 00 77 00 00 00 00 13 00 00 00003050: 78 56 34 12 0000fff0: 18 00 00 00 0d 00 00 00 08 00 00 00 02 00 00 00 ; - - registers msr[0010] 0000000000000003 ; tsc cr0=00000001 cr1=00000000 cr2=00000000 cr3=00000000 cr4=00000000 dr0=00000000 dr1=00000000 dr2=00000000 dr3=00000000 dr6=00000000 dr7=00000000 gdt.base=00002000 gdt.limit=ffff idt.base=00000000 idt.limit=ffff tr=0000 tr.base=00000000 tr.limit=00000000 tr.acc=0000 ldt=0000 ldt.base=00000000 ldt.limit=00000000 ldt.acc=0000 cs=0008 cs.base=00001000 cs.limit=00008fff cs.acc=049b ss=0000 ss.base=00000000 ss.limit=00000000 ss.acc=0000 ds=0000 ds.base=00000000 ds.limit=00000000 ds.acc=0000 es=0010 es.base=00003000 es.limit=a0000fff es.acc=0c93 fs=0000 fs.base=00000000 fs.limit=00000000 fs.acc=0000 gs=0000 gs.base=00000000 gs.limit=00000000 gs.acc=0000 eax=00000000 ebx=00000010 ecx=00000018 edx=00000000 esi=00000000 edi=00000000 ebp=00000000 esp=0000fff0 eip=0000000d eflags=00000002 libx86emu-1.5/test/0008_seg_load_pm32.tst000066400000000000000000000004561247503741400200160ustar00rootroot00000000000000[init mode=pm] gdt.base=0x2000 gdt[0]=0 gdt[0x08]=descr(base=0x1000,limit=0x8fff,acc=0x49b) gdt[0x10]=descr(base=0x3000,limit=0xa0000fff,acc=0xc93) gdt[0x18]=descr(base=0,limit=0x77,acc=0x013) ebx=0x10 ecx=0x18 [code start=8:0 bits=32] mov es,ebx mov dword [es:0x50],0x12345678 mov fs,ecx nop libx86emu-1.5/test/0009_loop32.done000066400000000000000000000021121247503741400166210ustar00rootroot00000000000000; - - memory ; 0 1 2 3 4 5 6 7 8 9 a b c d e f 00001000: b9 10 00 00 00 43 e2 fd f4 00002000: 00 00 00 00 00 00 00 00 ff ff 00 10 00 93 40 00 00002010: ff ff 00 00 00 93 cf 00 ; - - registers msr[0010] 0000000000000022 ; tsc cr0=00000001 cr1=00000000 cr2=00000000 cr3=00000000 cr4=00000000 dr0=00000000 dr1=00000000 dr2=00000000 dr3=00000000 dr6=00000000 dr7=00000000 gdt.base=00002000 gdt.limit=ffff idt.base=00000000 idt.limit=ffff tr=0000 tr.base=00000000 tr.limit=00000000 tr.acc=0000 ldt=0000 ldt.base=00000000 ldt.limit=00000000 ldt.acc=0000 cs=0008 cs.base=00001000 cs.limit=0000ffff cs.acc=0493 ss=0000 ss.base=00000000 ss.limit=00000000 ss.acc=0000 ds=0000 ds.base=00000000 ds.limit=00000000 ds.acc=0000 es=0000 es.base=00000000 es.limit=00000000 es.acc=0000 fs=0000 fs.base=00000000 fs.limit=00000000 fs.acc=0000 gs=0000 gs.base=00000000 gs.limit=00000000 gs.acc=0000 eax=00000000 ebx=00000010 ecx=00000000 edx=00000000 esi=00000000 edi=00000000 ebp=00000000 esp=00000000 eip=00000009 eflags=00000012 ; af libx86emu-1.5/test/0009_loop32.tst000066400000000000000000000003321247503741400165100ustar00rootroot00000000000000[init mode=protected] gdt.base=0x2000 gdt[0x00]=0 gdt[0x08]=descr(base=0x1000,limit=0xffff,acc=0x493) gdt[0x10]=descr(base=0,limit=0xffffffff,acc=0xc93) [code start=8:0 bits=32] mov ecx,0x10 l1: inc ebx loop l1 libx86emu-1.5/test/0010_loop16.done000066400000000000000000000021221247503741400166140ustar00rootroot00000000000000; - - memory ; 0 1 2 3 4 5 6 7 8 9 a b c d e f 00001000: 66 b9 10 00 07 00 66 43 e2 fc f4 00002000: 00 00 00 00 00 00 00 00 ff ff 00 10 00 93 00 00 00002010: ff ff 00 00 00 93 cf 00 ; - - registers msr[0010] 0000000000000022 ; tsc cr0=00000001 cr1=00000000 cr2=00000000 cr3=00000000 cr4=00000000 dr0=00000000 dr1=00000000 dr2=00000000 dr3=00000000 dr6=00000000 dr7=00000000 gdt.base=00002000 gdt.limit=ffff idt.base=00000000 idt.limit=ffff tr=0000 tr.base=00000000 tr.limit=00000000 tr.acc=0000 ldt=0000 ldt.base=00000000 ldt.limit=00000000 ldt.acc=0000 cs=0008 cs.base=00001000 cs.limit=0000ffff cs.acc=0093 ss=0000 ss.base=00000000 ss.limit=00000000 ss.acc=0000 ds=0000 ds.base=00000000 ds.limit=00000000 ds.acc=0000 es=0000 es.base=00000000 es.limit=00000000 es.acc=0000 fs=0000 fs.base=00000000 fs.limit=00000000 fs.acc=0000 gs=0000 gs.base=00000000 gs.limit=00000000 gs.acc=0000 eax=00000000 ebx=00000010 ecx=00070000 edx=00000000 esi=00000000 edi=00000000 ebp=00000000 esp=00000000 eip=0000000b eflags=00000012 ; af libx86emu-1.5/test/0010_loop16.tst000066400000000000000000000003351247503741400165050ustar00rootroot00000000000000[init mode=protected] gdt.base=0x2000 gdt[0x00]=0 gdt[0x08]=descr(base=0x1000,limit=0xffff,acc=0x093) gdt[0x10]=descr(base=0,limit=0xffffffff,acc=0xc93) [code start=8:0 bits=16] mov ecx,0x70010 l1: inc ebx loop l1 libx86emu-1.5/test/0011_jmp_short_cc.done000066400000000000000000000034071247503741400201560ustar00rootroot00000000000000; - - memory ; 0 1 2 3 4 5 6 7 8 9 a b c d e f 00001000: 38 cf 70 02 b0 01 fe c4 38 d1 71 02 b0 01 fe c4 00001010: 38 d1 72 02 b0 01 fe c4 38 ca 73 02 b0 01 fe c4 00001020: 38 d2 73 02 b0 01 fe c4 38 c9 74 02 b0 01 fe c4 00001030: 38 d1 75 02 b0 01 fe c4 38 d1 76 02 b0 01 fe c4 00001040: 38 c9 76 02 b0 01 fe c4 38 ca 77 02 b0 01 fe c4 00001050: 38 d1 78 02 b0 01 fe c4 38 ca 79 02 b0 01 fe c4 00001060: 38 c9 7a 02 b0 01 fe c4 38 ca 7b 02 b0 01 fe c4 00001070: 38 d1 7c 02 b0 01 fe c4 38 cd 7c 02 b0 01 fe c4 00001080: 38 ca 7d 02 b0 01 fe c4 38 f2 7d 02 b0 01 fe c4 00001090: 38 d1 7e 02 b0 01 fe c4 38 cd 7e 02 b0 01 fe c4 000010a0: 38 ed 7e 02 b0 01 fe c4 38 ca 7f 02 b0 01 fe c4 000010b0: 38 e9 7f 02 b0 01 fe c4 f4 ; - - registers msr[0010] 0000000000000046 ; tsc cr0=00000000 cr1=00000000 cr2=00000000 cr3=00000000 cr4=00000000 dr0=00000000 dr1=00000000 dr2=00000000 dr3=00000000 dr6=00000000 dr7=00000000 gdt.base=00000000 gdt.limit=ffff idt.base=00000000 idt.limit=ffff tr=0000 tr.base=00000000 tr.limit=00000000 tr.acc=0000 ldt=0000 ldt.base=00000000 ldt.limit=00000000 ldt.acc=0000 cs=0100 cs.base=00001000 cs.limit=0000ffff cs.acc=009b ss=0000 ss.base=00000000 ss.limit=0000ffff ss.acc=0093 ds=0000 ds.base=00000000 ds.limit=0000ffff ds.acc=0093 es=0000 es.base=00000000 es.limit=0000ffff es.acc=0093 fs=0000 fs.base=00000000 fs.limit=0000ffff fs.acc=0093 gs=0000 gs.base=00000000 gs.limit=0000ffff gs.acc=0093 eax=00001700 ebx=0000807f ecx=0000ff01 edx=0000fe02 esi=00000000 edi=00000000 ebp=00000000 esp=00000000 eip=000000b9 eflags=00000007 ; pf cf libx86emu-1.5/test/0011_jmp_short_cc.tst000066400000000000000000000021501247503741400200350ustar00rootroot00000000000000[init] eax=0 ebx=0x807f ecx=0xff01 edx=0xfe02 [code start=0x100:0x0] cmp bh,cl jo l_o mov al,1 l_o: inc ah cmp cl,dl jno l_no mov al,1 l_no: inc ah cmp cl,dl jb l_b mov al,1 l_b: inc ah cmp dl,cl jnb l_nb1 mov al,1 l_nb1: inc ah cmp dl,dl jnb l_nb2 mov al,1 l_nb2: inc ah cmp cl,cl jz l_z mov al,1 l_z: inc ah cmp cl,dl jnz l_nz mov al,1 l_nz: inc ah cmp cl,dl jna l_na1 mov al,1 l_na1: inc ah cmp cl,cl jna l_na2 mov al,1 l_na2: inc ah cmp dl,cl ja l_a mov al,1 l_a: inc ah cmp cl,dl js l_s mov al,1 l_s: inc ah cmp dl,cl jns l_ns mov al,1 l_ns: inc ah cmp cl,cl jp l_p mov al,1 l_p: inc ah cmp dl,cl jnp l_np mov al,1 l_np: inc ah cmp cl,dl jl l_l1 mov al,1 l_l1: inc ah cmp ch,cl jl l_l2 mov al,1 l_l2: inc ah cmp dl,cl jnl l_nl1 mov al,1 l_nl1: inc ah cmp dl,dh jnl l_nl2 mov al,1 l_nl2: inc ah cmp cl,dl jng l_ng1 mov al,1 l_ng1: inc ah cmp ch,cl jng l_ng2 mov al,1 l_ng2: inc ah cmp ch,ch jng l_ng3 mov al,1 l_ng3: inc ah cmp dl,cl jg l_g1 mov al,1 l_g1: inc ah cmp cl,ch jg l_g2 mov al,1 l_g2: inc ah libx86emu-1.5/test/0012_jmp_near_cc.done000066400000000000000000000037351247503741400177510ustar00rootroot00000000000000; - - memory ; 0 1 2 3 4 5 6 7 8 9 a b c d e f 00001000: 38 cf 0f 80 02 00 b0 01 fe c4 38 d1 0f 81 02 00 00001010: b0 01 fe c4 38 d1 0f 82 02 00 b0 01 fe c4 38 ca 00001020: 0f 83 02 00 b0 01 fe c4 38 d2 0f 83 02 00 b0 01 00001030: fe c4 38 c9 0f 84 02 00 b0 01 fe c4 38 d1 0f 85 00001040: 02 00 b0 01 fe c4 38 d1 0f 86 02 00 b0 01 fe c4 00001050: 38 c9 0f 86 02 00 b0 01 fe c4 38 ca 0f 87 02 00 00001060: b0 01 fe c4 38 d1 0f 88 02 00 b0 01 fe c4 38 ca 00001070: 0f 89 02 00 b0 01 fe c4 38 c9 0f 8a 02 00 b0 01 00001080: fe c4 38 ca 0f 8b 02 00 b0 01 fe c4 38 d1 0f 8c 00001090: 02 00 b0 01 fe c4 38 cd 0f 8c 02 00 b0 01 fe c4 000010a0: 38 ca 0f 8d 02 00 b0 01 fe c4 38 f2 0f 8d 02 00 000010b0: b0 01 fe c4 38 d1 0f 8e 02 00 b0 01 fe c4 38 cd 000010c0: 0f 8e 02 00 b0 01 fe c4 38 ed 0f 8e 02 00 b0 01 000010d0: fe c4 38 ca 0f 8f 02 00 b0 01 fe c4 38 e9 0f 8f 000010e0: 02 00 b0 01 fe c4 f4 ; - - registers msr[0010] 0000000000000046 ; tsc cr0=00000000 cr1=00000000 cr2=00000000 cr3=00000000 cr4=00000000 dr0=00000000 dr1=00000000 dr2=00000000 dr3=00000000 dr6=00000000 dr7=00000000 gdt.base=00000000 gdt.limit=ffff idt.base=00000000 idt.limit=ffff tr=0000 tr.base=00000000 tr.limit=00000000 tr.acc=0000 ldt=0000 ldt.base=00000000 ldt.limit=00000000 ldt.acc=0000 cs=0100 cs.base=00001000 cs.limit=0000ffff cs.acc=009b ss=0000 ss.base=00000000 ss.limit=0000ffff ss.acc=0093 ds=0000 ds.base=00000000 ds.limit=0000ffff ds.acc=0093 es=0000 es.base=00000000 es.limit=0000ffff es.acc=0093 fs=0000 fs.base=00000000 fs.limit=0000ffff fs.acc=0093 gs=0000 gs.base=00000000 gs.limit=0000ffff gs.acc=0093 eax=00001700 ebx=0000807f ecx=0000ff01 edx=0000fe02 esi=00000000 edi=00000000 ebp=00000000 esp=00000000 eip=000000e7 eflags=00000007 ; pf cf libx86emu-1.5/test/0012_jmp_near_cc.tst000066400000000000000000000023331247503741400176270ustar00rootroot00000000000000[init] eax=0 ebx=0x807f ecx=0xff01 edx=0xfe02 [code start=0x100:0x0] cmp bh,cl jo near l_o mov al,1 l_o: inc ah cmp cl,dl jno near l_no mov al,1 l_no: inc ah cmp cl,dl jb near l_b mov al,1 l_b: inc ah cmp dl,cl jnb near l_nb1 mov al,1 l_nb1: inc ah cmp dl,dl jnb near l_nb2 mov al,1 l_nb2: inc ah cmp cl,cl jz near l_z mov al,1 l_z: inc ah cmp cl,dl jnz near l_nz mov al,1 l_nz: inc ah cmp cl,dl jna near l_na1 mov al,1 l_na1: inc ah cmp cl,cl jna near l_na2 mov al,1 l_na2: inc ah cmp dl,cl ja near l_a mov al,1 l_a: inc ah cmp cl,dl js near l_s mov al,1 l_s: inc ah cmp dl,cl jns near l_ns mov al,1 l_ns: inc ah cmp cl,cl jp near l_p mov al,1 l_p: inc ah cmp dl,cl jnp near l_np mov al,1 l_np: inc ah cmp cl,dl jl near l_l1 mov al,1 l_l1: inc ah cmp ch,cl jl near l_l2 mov al,1 l_l2: inc ah cmp dl,cl jnl near l_nl1 mov al,1 l_nl1: inc ah cmp dl,dh jnl near l_nl2 mov al,1 l_nl2: inc ah cmp cl,dl jng near l_ng1 mov al,1 l_ng1: inc ah cmp ch,cl jng near l_ng2 mov al,1 l_ng2: inc ah cmp ch,ch jng near l_ng3 mov al,1 l_ng3: inc ah cmp dl,cl jg near l_g1 mov al,1 l_g1: inc ah cmp cl,ch jg near l_g2 mov al,1 l_g2: inc ah libx86emu-1.5/test/0013_add.done000066400000000000000000000026261247503741400162400ustar00rootroot00000000000000; - - memory ; 0 1 2 3 4 5 6 7 8 9 a b c d e f 00001000: 00 0d 9c 00 ea 9c 02 6d 01 9c 02 f1 9c 01 5d 02 00001010: 9c 01 f5 9c 03 75 04 9c 03 d3 9c 66 01 5d 06 9c 00001020: 66 01 f5 9c 66 03 75 0a 9c 66 03 d3 9c 04 97 9c 00001030: 05 57 12 9c 66 05 52 30 49 87 9c f4 00020100: 2d dd 02 6a eb 30 65 6c 54 0a 66 b2 74 4b 0003ffe0: 82 00 02 00 17 00 03 00 03 00 13 08 17 00 0003fff0: 13 00 17 00 83 00 13 00 97 00 17 08 92 00 07 00 ; - - registers msr[0010] 000000000000001f ; tsc cr0=00000000 cr1=00000000 cr2=00000000 cr3=00000000 cr4=00000000 dr0=00000000 dr1=00000000 dr2=00000000 dr3=00000000 dr6=00000000 dr7=00000000 gdt.base=00000000 gdt.limit=ffff idt.base=00000000 idt.limit=ffff tr=0000 tr.base=00000000 tr.limit=00000000 tr.acc=0000 ldt=0000 ldt.base=00000000 ldt.limit=00000000 ldt.acc=0000 cs=0100 cs.base=00001000 cs.limit=0000ffff cs.acc=009b ss=3000 ss.base=00030000 ss.limit=0000ffff ss.acc=0093 ds=2000 ds.base=00020000 ds.limit=0000ffff ds.acc=0093 es=0000 es.base=00000000 es.limit=0000ffff es.acc=0093 fs=0000 fs.base=00000000 fs.limit=0000ffff fs.acc=0093 gs=0000 gs.base=00000000 gs.limit=0000ffff gs.acc=0093 eax=fa6262ba ebx=a21a7109 ecx=85107be8 edx=00c885fb esi=3b6eb629 edi=00000100 ebp=77959131 esp=0000ffe2 eip=0000003c eflags=00000082 ; sf libx86emu-1.5/test/0013_add.tst000066400000000000000000000010131247503741400161120ustar00rootroot00000000000000[init srand=10] 0x20100-0x2010d: rand eax=rand ebx=rand ecx=rand edx=rand esi=rand ebp=rand edi=0x100 ds=0x2000 ss=0x3000 [code start=0x100:0x0] add [di],cl pushf add dl,ch pushf add ch,[di+1] pushf db 0x02, 0xf1 ; add dh,cl pushf add [di+2],bx pushf add bp,si pushf add si,[di+4] pushf db 0x03, 0xd3 ; add dx,bx pushf add [di+6],ebx pushf add ebp,esi pushf add esi,[di+10] pushf db 0x66, 0x03, 0xd3 ; add edx,ebx pushf add al,0x97 pushf add ax,0x1257 pushf add eax,0x87493052 pushf libx86emu-1.5/test/0014_or.done000066400000000000000000000026311247503741400161250ustar00rootroot00000000000000; - - memory ; 0 1 2 3 4 5 6 7 8 9 a b c d e f 00001000: 08 0d 9c 08 ea 9c 0a 6d 01 9c 0a f1 9c 09 5d 02 00001010: 9c 09 f5 9c 0b 75 04 9c 0b d3 9c 66 09 5d 06 9c 00001020: 66 09 f5 9c 66 0b 75 0a 9c 66 0b d3 9c 0c 97 9c 00001030: 0d 57 12 9c 66 0d 52 30 49 87 9c f4 00020100: 67 5a dd ff f8 a0 df bd 6f ef d1 aa 1d 39 0003ffe0: 86 00 86 00 86 00 06 00 02 00 06 00 82 00 0003fff0: 86 00 86 00 82 00 86 00 06 00 82 00 86 00 02 00 ; - - registers msr[0010] 000000000000001f ; tsc cr0=00000000 cr1=00000000 cr2=00000000 cr3=00000000 cr4=00000000 dr0=00000000 dr1=00000000 dr2=00000000 dr3=00000000 dr6=00000000 dr7=00000000 gdt.base=00000000 gdt.limit=ffff idt.base=00000000 idt.limit=ffff tr=0000 tr.base=00000000 tr.limit=00000000 tr.acc=0000 ldt=0000 ldt.base=00000000 ldt.limit=00000000 ldt.acc=0000 cs=0100 cs.base=00001000 cs.limit=0000ffff cs.acc=009b ss=3000 ss.base=00030000 ss.limit=0000ffff ss.acc=0093 ds=2000 ds.base=00020000 ds.limit=0000ffff ds.acc=0093 es=0000 es.base=00000000 es.limit=0000ffff es.acc=0093 fs=0000 fs.base=00000000 fs.limit=0000ffff fs.acc=0093 gs=0000 gs.base=00000000 gs.limit=0000ffff gs.acc=0093 eax=975dbbff ebx=676e9ddd ecx=b157fe67 edx=676fffff esi=3f7dbffb edi=00000100 ebp=77f4bdfa esp=0000ffe2 eip=0000003c eflags=00000086 ; sf pf libx86emu-1.5/test/0014_or.tst000066400000000000000000000007741247503741400160200ustar00rootroot00000000000000[init srand=11] 0x20100-0x2010d: rand eax=rand ebx=rand ecx=rand edx=rand esi=rand ebp=rand edi=0x100 ds=0x2000 ss=0x3000 [code start=0x100:0x0] or [di],cl pushf or dl,ch pushf or ch,[di+1] pushf db 0x0a, 0xf1 ; or dh,cl pushf or [di+2],bx pushf or bp,si pushf or si,[di+4] pushf db 0x0b, 0xd3 ; or dx,bx pushf or [di+6],ebx pushf or ebp,esi pushf or esi,[di+10] pushf db 0x66, 0x0b, 0xd3 ; or edx,ebx pushf or al,0x97 pushf or ax,0x1257 pushf or eax,0x87493052 pushf libx86emu-1.5/test/0015_adc.done000066400000000000000000000026341247503741400162400ustar00rootroot00000000000000; - - memory ; 0 1 2 3 4 5 6 7 8 9 a b c d e f 00001000: 10 0d 9c 10 ea 9c 12 6d 01 9c 12 f1 9c 11 5d 02 00001010: 9c 11 f5 9c 13 75 04 9c 13 d3 9c 66 11 5d 06 9c 00001020: 66 11 f5 9c 66 13 75 0a 9c 66 13 d3 9c 14 97 9c 00001030: 15 57 12 9c 66 15 52 30 49 87 9c f4 00020100: 2d 06 0d c9 05 10 90 ae fb 5a 3c a2 97 56 0003ffe0: 07 08 82 00 96 00 86 08 16 00 16 00 16 00 0003fff0: 07 00 06 00 92 08 82 00 86 00 12 00 92 00 07 00 ; - - registers msr[0010] 000000000000001f ; tsc cr0=00000000 cr1=00000000 cr2=00000000 cr3=00000000 cr4=00000000 dr0=00000000 dr1=00000000 dr2=00000000 dr3=00000000 dr6=00000000 dr7=00000000 gdt.base=00000000 gdt.limit=ffff idt.base=00000000 idt.limit=ffff tr=0000 tr.base=00000000 tr.limit=00000000 tr.acc=0000 ldt=0000 ldt.base=00000000 ldt.limit=00000000 ldt.acc=0000 cs=0100 cs.base=00001000 cs.limit=0000ffff cs.acc=009b ss=3000 ss.base=00030000 ss.limit=0000ffff ss.acc=0093 ds=2000 ds.base=00020000 ds.limit=0000ffff ds.acc=0093 es=0000 es.base=00000000 es.limit=0000ffff es.acc=0093 fs=0000 fs.base=00000000 fs.limit=0000ffff fs.acc=0093 gs=0000 gs.base=00000000 gs.limit=0000ffff gs.acc=0093 eax=3683db8d ebx=2cdb1082 ecx=dd9e43e6 edx=9a3f20c6 esi=7546057b edi=00000100 ebp=7aa41133 esp=0000ffe2 eip=0000003c eflags=00000807 ; of pf cf libx86emu-1.5/test/0015_adc.tst000066400000000000000000000010131247503741400161130ustar00rootroot00000000000000[init srand=12] 0x20100-0x2010d: rand eax=rand ebx=rand ecx=rand edx=rand esi=rand ebp=rand edi=0x100 ds=0x2000 ss=0x3000 [code start=0x100:0x0] adc [di],cl pushf adc dl,ch pushf adc ch,[di+1] pushf db 0x12, 0xf1 ; adc dh,cl pushf adc [di+2],bx pushf adc bp,si pushf adc si,[di+4] pushf db 0x13, 0xd3 ; adc dx,bx pushf adc [di+6],ebx pushf adc ebp,esi pushf adc esi,[di+10] pushf db 0x66, 0x13, 0xd3 ; adc edx,ebx pushf adc al,0x97 pushf adc ax,0x1257 pushf adc eax,0x87493052 pushf libx86emu-1.5/test/0016_sbb.done000066400000000000000000000026211247503741400162540ustar00rootroot00000000000000; - - memory ; 0 1 2 3 4 5 6 7 8 9 a b c d e f 00001000: 18 0d 9c 18 ea 9c 1a 6d 01 9c 1a f1 9c 19 5d 02 00001010: 9c 19 f5 9c 1b 75 04 9c 1b d3 9c 66 19 5d 06 9c 00001020: 66 19 f5 9c 66 1b 75 0a 9c 66 1b d3 9c 1c 97 9c 00001030: 1d 57 12 9c 66 1d 52 30 49 87 9c f4 00020100: b4 83 e9 71 e3 ae a8 1b b5 a0 a7 9a 11 44 0003ffe0: 02 00 12 00 83 08 83 08 97 00 16 00 83 00 0003fff0: 16 00 87 08 86 00 02 08 06 08 06 00 12 00 87 00 ; - - registers msr[0010] 000000000000001f ; tsc cr0=00000000 cr1=00000000 cr2=00000000 cr3=00000000 cr4=00000000 dr0=00000000 dr1=00000000 dr2=00000000 dr3=00000000 dr6=00000000 dr7=00000000 gdt.base=00000000 gdt.limit=ffff idt.base=00000000 idt.limit=ffff tr=0000 tr.base=00000000 tr.limit=00000000 tr.acc=0000 ldt=0000 ldt.base=00000000 ldt.limit=00000000 ldt.acc=0000 cs=0100 cs.base=00001000 cs.limit=0000ffff cs.acc=009b ss=3000 ss.base=00030000 ss.limit=0000ffff ss.acc=0093 ds=2000 ds.base=00020000 ds.limit=0000ffff ds.acc=0093 es=0000 es.base=00000000 es.limit=0000ffff es.acc=0093 fs=0000 fs.base=00000000 fs.limit=0000ffff fs.acc=0093 gs=0000 gs.base=00000000 gs.limit=0000ffff gs.acc=0093 eax=45f5ef0b ebx=f2303d55 ecx=09e50a65 edx=828de867 esi=f202ecca edi=00000100 ebp=10190fee esp=0000ffe2 eip=0000003c eflags=00000002 libx86emu-1.5/test/0016_sbb.tst000066400000000000000000000010131247503741400161330ustar00rootroot00000000000000[init srand=13] 0x20100-0x2010d: rand eax=rand ebx=rand ecx=rand edx=rand esi=rand ebp=rand edi=0x100 ds=0x2000 ss=0x3000 [code start=0x100:0x0] sbb [di],cl pushf sbb dl,ch pushf sbb ch,[di+1] pushf db 0x1a, 0xf1 ; sbb dh,cl pushf sbb [di+2],bx pushf sbb bp,si pushf sbb si,[di+4] pushf db 0x1b, 0xd3 ; sbb dx,bx pushf sbb [di+6],ebx pushf sbb ebp,esi pushf sbb esi,[di+10] pushf db 0x66, 0x1b, 0xd3 ; sbb edx,ebx pushf sbb al,0x97 pushf sbb ax,0x1257 pushf sbb eax,0x87493052 pushf libx86emu-1.5/test/0017_and.done000066400000000000000000000026261247503741400162560ustar00rootroot00000000000000; - - memory ; 0 1 2 3 4 5 6 7 8 9 a b c d e f 00001000: 20 0d 9c 20 ea 9c 22 6d 01 9c 22 f1 9c 21 5d 02 00001010: 9c 21 f5 9c 23 75 04 9c 23 d3 9c 66 21 5d 06 9c 00001020: 66 21 f5 9c 66 23 75 0a 9c 66 23 d3 9c 24 97 9c 00001030: 25 57 12 9c 66 25 52 30 49 87 9c f4 00020100: 02 2e 20 22 f0 1e 28 40 80 b5 12 92 ba 61 0003ffe0: 82 00 06 00 06 00 02 00 02 00 06 00 86 00 0003fff0: 02 00 06 00 86 00 02 00 06 00 06 00 86 00 02 00 ; - - registers msr[0010] 000000000000001f ; tsc cr0=00000000 cr1=00000000 cr2=00000000 cr3=00000000 cr4=00000000 dr0=00000000 dr1=00000000 dr2=00000000 dr3=00000000 dr6=00000000 dr7=00000000 gdt.base=00000000 gdt.limit=ffff idt.base=00000000 idt.limit=ffff tr=0000 tr.base=00000000 tr.limit=00000000 tr.acc=0000 ldt=0000 ldt.base=00000000 ldt.limit=00000000 ldt.acc=0000 cs=0100 cs.base=00001000 cs.limit=0000ffff cs.acc=009b ss=3000 ss.base=00030000 ss.limit=0000ffff ss.acc=0093 ds=2000 ds.base=00020000 ds.limit=0000ffff ds.acc=0093 es=0000 es.base=00000000 es.limit=0000ffff es.acc=0093 fs=0000 fs.base=00000000 fs.limit=0000ffff fs.acc=0093 gs=0000 gs.base=00000000 gs.limit=0000ffff gs.acc=0093 eax=83410002 ebx=b7846a28 ecx=362b0ce3 edx=34006208 esi=41201210 edi=00000100 ebp=00401290 esp=0000ffe2 eip=0000003c eflags=00000082 ; sf libx86emu-1.5/test/0017_and.tst000066400000000000000000000010131247503741400161300ustar00rootroot00000000000000[init srand=14] 0x20100-0x2010d: rand eax=rand ebx=rand ecx=rand edx=rand esi=rand ebp=rand edi=0x100 ds=0x2000 ss=0x3000 [code start=0x100:0x0] and [di],cl pushf and dl,ch pushf and ch,[di+1] pushf db 0x22, 0xf1 ; and dh,cl pushf and [di+2],bx pushf and bp,si pushf and si,[di+4] pushf db 0x23, 0xd3 ; and dx,bx pushf and [di+6],ebx pushf and ebp,esi pushf and esi,[di+10] pushf db 0x66, 0x23, 0xd3 ; and edx,ebx pushf and al,0x97 pushf and ax,0x1257 pushf and eax,0x87493052 pushf libx86emu-1.5/test/0018_sub.done000066400000000000000000000026341247503741400163050ustar00rootroot00000000000000; - - memory ; 0 1 2 3 4 5 6 7 8 9 a b c d e f 00001000: 28 0d 9c 28 ea 9c 2a 6d 01 9c 2a f1 9c 29 5d 02 00001010: 9c 29 f5 9c 2b 75 04 9c 2b d3 9c 66 29 5d 06 9c 00001020: 66 29 f5 9c 66 2b 75 0a 9c 66 2b d3 9c 2c 97 9c 00001030: 2d 57 12 9c 66 2d 52 30 49 87 9c f4 00020100: b9 ab d6 d8 fd 8e e1 65 f3 dc 7d b9 35 50 0003ffe0: 83 08 82 00 93 08 16 08 16 00 93 00 87 00 0003fff0: 02 00 97 08 83 00 93 08 83 00 87 08 92 00 83 00 ; - - registers msr[0010] 000000000000001f ; tsc cr0=00000000 cr1=00000000 cr2=00000000 cr3=00000000 cr4=00000000 dr0=00000000 dr1=00000000 dr2=00000000 dr3=00000000 dr6=00000000 dr7=00000000 gdt.base=00000000 gdt.limit=ffff idt.base=00000000 idt.limit=ffff tr=0000 tr.base=00000000 tr.limit=00000000 tr.acc=0000 ldt=0000 ldt.base=00000000 ldt.limit=00000000 ldt.acc=0000 cs=0100 cs.base=00001000 cs.limit=0000ffff cs.acc=009b ss=3000 ss.base=00030000 ss.limit=0000ffff ss.acc=0093 ds=2000 ds.base=00020000 ds.limit=0000ffff ds.acc=0093 es=0000 es.base=00000000 es.limit=0000ffff es.acc=0093 fs=0000 fs.base=00000000 fs.limit=0000ffff fs.acc=0093 gs=0000 gs.base=00000000 gs.limit=0000ffff gs.acc=0093 eax=821666e0 ebx=7cd996fb ecx=62738162 edx=069b96b8 esi=147b286a edi=00000100 ebp=b5d71b0d esp=0000ffe2 eip=0000003c eflags=00000883 ; of sf cf libx86emu-1.5/test/0018_sub.tst000066400000000000000000000010131247503741400161600ustar00rootroot00000000000000[init srand=15] 0x20100-0x2010d: rand eax=rand ebx=rand ecx=rand edx=rand esi=rand ebp=rand edi=0x100 ds=0x2000 ss=0x3000 [code start=0x100:0x0] sub [di],cl pushf sub dl,ch pushf sub ch,[di+1] pushf db 0x2a, 0xf1 ; sub dh,cl pushf sub [di+2],bx pushf sub bp,si pushf sub si,[di+4] pushf db 0x2b, 0xd3 ; sub dx,bx pushf sub [di+6],ebx pushf sub ebp,esi pushf sub esi,[di+10] pushf db 0x66, 0x2b, 0xd3 ; sub edx,ebx pushf sub al,0x97 pushf sub ax,0x1257 pushf sub eax,0x87493052 pushf libx86emu-1.5/test/0019_xor.done000066400000000000000000000026261247503741400163260ustar00rootroot00000000000000; - - memory ; 0 1 2 3 4 5 6 7 8 9 a b c d e f 00001000: 30 0d 9c 30 ea 9c 32 6d 01 9c 32 f1 9c 31 5d 02 00001010: 9c 31 f5 9c 33 75 04 9c 33 d3 9c 66 31 5d 06 9c 00001020: 66 31 f5 9c 66 33 75 0a 9c 66 33 d3 9c 34 97 9c 00001030: 35 57 12 9c 66 35 52 30 49 87 9c f4 00020100: fd 57 4c a5 dc fe 03 75 bf a9 e8 b1 de 6d 0003ffe0: 82 00 06 00 82 00 82 00 06 00 06 00 86 00 0003fff0: 82 00 86 00 86 00 82 00 02 00 02 00 82 00 82 00 ; - - registers msr[0010] 000000000000001f ; tsc cr0=00000000 cr1=00000000 cr2=00000000 cr3=00000000 cr4=00000000 dr0=00000000 dr1=00000000 dr2=00000000 dr3=00000000 dr6=00000000 dr7=00000000 gdt.base=00000000 gdt.limit=ffff idt.base=00000000 idt.limit=ffff tr=0000 tr.base=00000000 tr.limit=00000000 tr.acc=0000 ldt=0000 ldt.base=00000000 ldt.limit=00000000 ldt.acc=0000 cs=0100 cs.base=00001000 cs.limit=0000ffff cs.acc=009b ss=3000 ss.base=00030000 ss.limit=0000ffff ss.acc=0093 ds=2000 ds.base=00020000 ds.limit=0000ffff ds.acc=0093 es=0000 es.base=00000000 es.limit=0000ffff es.acc=0093 fs=0000 fs.base=00000000 fs.limit=0000ffff fs.acc=0093 gs=0000 gs.base=00000000 gs.limit=0000ffff gs.acc=0093 eax=a02d60b3 ebx=422ec3cf ecx=8eba2ce1 edx=c8e1348c esi=11c81cc9 edi=00000100 ebp=78be65dd esp=0000ffe2 eip=0000003c eflags=00000082 ; sf libx86emu-1.5/test/0019_xor.tst000066400000000000000000000010131247503741400162000ustar00rootroot00000000000000[init srand=16] 0x20100-0x2010d: rand eax=rand ebx=rand ecx=rand edx=rand esi=rand ebp=rand edi=0x100 ds=0x2000 ss=0x3000 [code start=0x100:0x0] xor [di],cl pushf xor dl,ch pushf xor ch,[di+1] pushf db 0x32, 0xf1 ; xor dh,cl pushf xor [di+2],bx pushf xor bp,si pushf xor si,[di+4] pushf db 0x33, 0xd3 ; xor dx,bx pushf xor [di+6],ebx pushf xor ebp,esi pushf xor esi,[di+10] pushf db 0x66, 0x33, 0xd3 ; xor edx,ebx pushf xor al,0x97 pushf xor ax,0x1257 pushf xor eax,0x87493052 pushf libx86emu-1.5/test/0020_cmp.done000066400000000000000000000026421247503741400162630ustar00rootroot00000000000000; - - memory ; 0 1 2 3 4 5 6 7 8 9 a b c d e f 00001000: 38 0d 9c 38 ea 9c 3a 6d 01 9c 3a f1 9c 39 5d 02 00001010: 9c 39 f5 9c 3b 75 04 9c 3b d3 9c 66 39 5d 06 9c 00001020: 66 39 f5 9c 66 3b 75 0a 9c 66 3b d3 9c 3c 97 9c 00001030: 3d 57 12 9c 66 3d 52 30 49 87 9c f4 00020100: ee d4 35 2f e9 9d 8d 9f 85 4e 53 a9 58 5b 0003ffe0: 97 08 96 00 93 08 86 00 02 08 02 00 02 00 0003fff0: 86 00 16 00 03 00 83 00 06 08 83 00 12 00 86 00 ; - - registers msr[0010] 000000000000001f ; tsc cr0=00000000 cr1=00000000 cr2=00000000 cr3=00000000 cr4=00000000 dr0=00000000 dr1=00000000 dr2=00000000 dr3=00000000 dr6=00000000 dr7=00000000 gdt.base=00000000 gdt.limit=ffff idt.base=00000000 idt.limit=ffff tr=0000 tr.base=00000000 tr.limit=00000000 tr.acc=0000 ldt=0000 ldt.base=00000000 ldt.limit=00000000 ldt.acc=0000 cs=0100 cs.base=00001000 cs.limit=0000ffff cs.acc=009b ss=3000 ss.base=00030000 ss.limit=0000ffff ss.acc=0093 ds=2000 ds.base=00020000 ds.limit=0000ffff ds.acc=0093 es=0000 es.base=00000000 es.limit=0000ffff es.acc=0093 fs=0000 fs.base=00000000 fs.limit=0000ffff fs.acc=0093 gs=0000 gs.base=00000000 gs.limit=0000ffff gs.acc=0093 eax=4568db21 ebx=079a3674 ecx=bb00cb60 edx=9241cae5 esi=9363f145 edi=00000100 ebp=eee10dfb esp=0000ffe2 eip=0000003c eflags=00000897 ; of sf af pf cf libx86emu-1.5/test/0020_cmp.tst000066400000000000000000000010131247503741400161370ustar00rootroot00000000000000[init srand=17] 0x20100-0x2010d: rand eax=rand ebx=rand ecx=rand edx=rand esi=rand ebp=rand edi=0x100 ds=0x2000 ss=0x3000 [code start=0x100:0x0] cmp [di],cl pushf cmp dl,ch pushf cmp ch,[di+1] pushf db 0x3a, 0xf1 ; cmp dh,cl pushf cmp [di+2],bx pushf cmp bp,si pushf cmp si,[di+4] pushf db 0x3b, 0xd3 ; cmp dx,bx pushf cmp [di+6],ebx pushf cmp ebp,esi pushf cmp esi,[di+10] pushf db 0x66, 0x3b, 0xd3 ; cmp edx,ebx pushf cmp al,0x97 pushf cmp ax,0x1257 pushf cmp eax,0x87493052 pushf libx86emu-1.5/test/0021_imul_b.done000066400000000000000000000022371247503741400167540ustar00rootroot00000000000000; - - memory ; 0 1 2 3 4 5 6 7 8 9 a b c d e f 00001000: 6b d9 07 9c 6b d6 cb 9c 6b 05 66 9c 66 6b ee 26 00001010: 9c 66 6b f3 cf 9c 66 6b 4d 02 b9 9c f4 00020100: ef 7f e7 26 c7 0d 0003fff0: 03 08 03 08 03 08 03 08 03 08 03 08 ; - - registers msr[0010] 000000000000000d ; tsc cr0=00000000 cr1=00000000 cr2=00000000 cr3=00000000 cr4=00000000 dr0=00000000 dr1=00000000 dr2=00000000 dr3=00000000 dr6=00000000 dr7=00000000 gdt.base=00000000 gdt.limit=ffff idt.base=00000000 idt.limit=ffff tr=0000 tr.base=00000000 tr.limit=00000000 tr.acc=0000 ldt=0000 ldt.base=00000000 ldt.limit=00000000 ldt.acc=0000 cs=0100 cs.base=00001000 cs.limit=0000ffff cs.acc=009b ss=3000 ss.base=00030000 ss.limit=0000ffff ss.acc=0093 ds=2000 ds.base=00020000 ds.limit=0000ffff ds.acc=0093 es=0000 es.base=00000000 es.limit=0000ffff es.acc=0093 fs=0000 fs.base=00000000 fs.limit=0000ffff fs.acc=0093 gs=0000 gs.base=00000000 gs.limit=0000ffff gs.acc=0093 eax=eef3f93a ebx=699ef348 ecx=2dc435ef edx=5a589eaa esi=c8936f38 edi=00000100 ebp=099fc834 esp=0000fff4 eip=0000001d eflags=00000803 ; of cf libx86emu-1.5/test/0021_imul_b.tst000066400000000000000000000004551247503741400166410ustar00rootroot00000000000000[init srand=18] 0x20100-0x20105: rand eax=rand ebx=rand ecx=rand edx=rand esi=rand ebp=rand edi=0x100 ds=0x2000 ss=0x3000 [code start=0x100:0x0] imul bx,cx,7 pushf imul dx,si,-53 pushf imul ax,[di],102 pushf imul ebp,esi,38 pushf imul esi,ebx,-49 pushf imul ecx,[di+2],-71 pushf libx86emu-1.5/test/0022_imul_w.done000066400000000000000000000023311247503741400167750ustar00rootroot00000000000000; - - memory ; 0 1 2 3 4 5 6 7 8 9 a b c d e f 00001000: 69 d9 9a 52 9c 69 d6 79 bd 9c 69 05 03 09 9c 66 00001010: 69 ee 61 0a b2 79 9c 66 69 f3 1c 2d fa d6 9c 66 00001020: 69 4d 02 a6 cf af 94 9c f4 00020100: f0 fc 99 1d d4 7d 0003fff0: 03 08 03 08 03 08 03 08 03 08 03 08 ; - - registers msr[0010] 000000000000000d ; tsc cr0=00000000 cr1=00000000 cr2=00000000 cr3=00000000 cr4=00000000 dr0=00000000 dr1=00000000 dr2=00000000 dr3=00000000 dr6=00000000 dr7=00000000 gdt.base=00000000 gdt.limit=ffff idt.base=00000000 idt.limit=ffff tr=0000 tr.base=00000000 tr.limit=00000000 tr.acc=0000 ldt=0000 ldt.base=00000000 ldt.limit=00000000 ldt.acc=0000 cs=0100 cs.base=00001000 cs.limit=0000ffff cs.acc=009b ss=3000 ss.base=00030000 ss.limit=0000ffff ss.acc=0093 ds=2000 ds.base=00020000 ds.limit=0000ffff ds.acc=0093 es=0000 es.base=00000000 es.limit=0000ffff es.acc=0093 fs=0000 fs.base=00000000 fs.limit=0000ffff fs.acc=0093 gs=0000 gs.base=00000000 gs.limit=0000ffff gs.acc=0093 eax=555766d0 ebx=f82012b2 ecx=cb10e836 edx=71a3da1f esi=d49f5578 edi=00000100 ebp=e37c6cf7 esp=0000fff4 eip=00000029 eflags=00000803 ; of cf libx86emu-1.5/test/0022_imul_w.tst000066400000000000000000000005201247503741400166600ustar00rootroot00000000000000[init srand=19] 0x20100-0x20105: rand eax=rand ebx=rand ecx=rand edx=rand esi=rand ebp=rand edi=0x100 ds=0x2000 ss=0x3000 [code start=0x100:0x0] imul bx,cx,0x529a pushf imul dx,si,-0x4287 pushf imul ax,[di],0x903 pushf imul ebp,esi,0x79b20a61 pushf imul esi,ebx,-0x2905d2e4 pushf imul ecx,[di+2],-0x6b50305a pushf libx86emu-1.5/test/0023_op_A_80.tst000066400000000000000000000005441247503741400165600ustar00rootroot00000000000000[init srand=23] 0x20000-0x20017: rand ds=0x2000 ss=0x3000 [code start=0x100:0x0] mov al,0 l_10: mov cl,[si] lea si,[si+1] m0: add cl,0x23 pushf mov dh,[si] lea si,[si+1] m1: add dh,-0x49 pushf m2: add byte[si],0x72 lea si,[si+1] pushf add al,8 add byte [cs:m0+1],8 add byte [cs:m1+1],8 add byte [cs:m2+1],8 cmp al,0x40 jb l_10 libx86emu-1.5/test/0024_cwd.done000066400000000000000000000020571247503741400162650ustar00rootroot00000000000000; - - memory ; 0 1 2 3 4 5 6 7 8 9 a b c d e f 00001000: b8 34 12 99 52 66 89 da b8 76 98 99 52 f4 0003fff0: ff ff 00 00 ; - - registers msr[0010] 0000000000000008 ; tsc cr0=00000000 cr1=00000000 cr2=00000000 cr3=00000000 cr4=00000000 dr0=00000000 dr1=00000000 dr2=00000000 dr3=00000000 dr6=00000000 dr7=00000000 gdt.base=00000000 gdt.limit=ffff idt.base=00000000 idt.limit=ffff tr=0000 tr.base=00000000 tr.limit=00000000 tr.acc=0000 ldt=0000 ldt.base=00000000 ldt.limit=00000000 ldt.acc=0000 cs=0100 cs.base=00001000 cs.limit=0000ffff cs.acc=009b ss=3000 ss.base=00030000 ss.limit=0000ffff ss.acc=0093 ds=0000 ds.base=00000000 ds.limit=0000ffff ds.acc=0093 es=0000 es.base=00000000 es.limit=0000ffff es.acc=0093 fs=0000 fs.base=00000000 fs.limit=0000ffff fs.acc=0093 gs=0000 gs.base=00000000 gs.limit=0000ffff gs.acc=0093 eax=11ff9876 ebx=4b4a8d43 ecx=00000000 edx=4b4affff esi=00000000 edi=00000000 ebp=00000000 esp=0000fffc eip=0000000e eflags=00000002 libx86emu-1.5/test/0024_cwd.tst000066400000000000000000000002271247503741400161470ustar00rootroot00000000000000[init srand=24] eax=rand edx=rand ebx=rand ss=0x3000 [code start=0x100:0x0] mov ax,1234h cwd push dx mov edx,ebx mov ax,9876h cwd push dx libx86emu-1.5/test/0025_cdq.done000066400000000000000000000021411247503741400162520ustar00rootroot00000000000000; - - memory ; 0 1 2 3 4 5 6 7 8 9 a b c d e f 00001000: 66 b8 78 56 34 12 66 99 66 52 66 89 da 66 b8 32 00001010: 54 76 98 66 99 66 52 f4 0003fff0: ff ff ff ff 00 00 00 00 ; - - registers msr[0010] 0000000000000008 ; tsc cr0=00000000 cr1=00000000 cr2=00000000 cr3=00000000 cr4=00000000 dr0=00000000 dr1=00000000 dr2=00000000 dr3=00000000 dr6=00000000 dr7=00000000 gdt.base=00000000 gdt.limit=ffff idt.base=00000000 idt.limit=ffff tr=0000 tr.base=00000000 tr.limit=00000000 tr.acc=0000 ldt=0000 ldt.base=00000000 ldt.limit=00000000 ldt.acc=0000 cs=0100 cs.base=00001000 cs.limit=0000ffff cs.acc=009b ss=3000 ss.base=00030000 ss.limit=0000ffff ss.acc=0093 ds=0000 ds.base=00000000 ds.limit=0000ffff ds.acc=0093 es=0000 es.base=00000000 es.limit=0000ffff es.acc=0093 fs=0000 fs.base=00000000 fs.limit=0000ffff fs.acc=0093 gs=0000 gs.base=00000000 gs.limit=0000ffff gs.acc=0093 eax=98765432 ebx=48314e23 ecx=00000000 edx=ffffffff esi=00000000 edi=00000000 ebp=00000000 esp=0000fff8 eip=00000018 eflags=00000002 libx86emu-1.5/test/0025_cdq.tst000066400000000000000000000002431247503741400161400ustar00rootroot00000000000000[init srand=25] eax=rand edx=rand ebx=rand ss=0x3000 [code start=0x100:0x0] mov eax,12345678h cdq push edx mov edx,ebx mov eax,98765432h cdq push edx libx86emu-1.5/test/0026_cbw.done000066400000000000000000000020431247503741400162600ustar00rootroot00000000000000; - - memory ; 0 1 2 3 4 5 6 7 8 9 a b c d e f 00001000: b0 34 98 50 88 fc b0 86 98 50 f4 0003fff0: 86 ff 34 00 ; - - registers msr[0010] 0000000000000008 ; tsc cr0=00000000 cr1=00000000 cr2=00000000 cr3=00000000 cr4=00000000 dr0=00000000 dr1=00000000 dr2=00000000 dr3=00000000 dr6=00000000 dr7=00000000 gdt.base=00000000 gdt.limit=ffff idt.base=00000000 idt.limit=ffff tr=0000 tr.base=00000000 tr.limit=00000000 tr.acc=0000 ldt=0000 ldt.base=00000000 ldt.limit=00000000 ldt.acc=0000 cs=0100 cs.base=00001000 cs.limit=0000ffff cs.acc=009b ss=3000 ss.base=00030000 ss.limit=0000ffff ss.acc=0093 ds=0000 ds.base=00000000 ds.limit=0000ffff ds.acc=0093 es=0000 es.base=00000000 es.limit=0000ffff es.acc=0093 fs=0000 fs.base=00000000 fs.limit=0000ffff fs.acc=0093 gs=0000 gs.base=00000000 gs.limit=0000ffff gs.acc=0093 eax=cfcbff86 ebx=4bd9aaf3 ecx=00000000 edx=00000000 esi=00000000 edi=00000000 ebp=00000000 esp=0000fffc eip=0000000b eflags=00000002 libx86emu-1.5/test/0026_cbw.tst000066400000000000000000000002101247503741400161370ustar00rootroot00000000000000[init srand=26] eax=rand ebx=rand ss=0x3000 [code start=0x100:0x0] mov al,34h cbw push ax mov ah,bh mov al,86h cbw push ax libx86emu-1.5/test/0027_cwde.done000066400000000000000000000021111247503741400164240ustar00rootroot00000000000000; - - memory ; 0 1 2 3 4 5 6 7 8 9 a b c d e f 00001000: b8 68 35 66 98 66 50 66 89 d8 b8 75 81 66 98 66 00001010: 50 f4 0003fff0: 75 81 ff ff 68 35 00 00 ; - - registers msr[0010] 0000000000000008 ; tsc cr0=00000000 cr1=00000000 cr2=00000000 cr3=00000000 cr4=00000000 dr0=00000000 dr1=00000000 dr2=00000000 dr3=00000000 dr6=00000000 dr7=00000000 gdt.base=00000000 gdt.limit=ffff idt.base=00000000 idt.limit=ffff tr=0000 tr.base=00000000 tr.limit=00000000 tr.acc=0000 ldt=0000 ldt.base=00000000 ldt.limit=00000000 ldt.acc=0000 cs=0100 cs.base=00001000 cs.limit=0000ffff cs.acc=009b ss=3000 ss.base=00030000 ss.limit=0000ffff ss.acc=0093 ds=0000 ds.base=00000000 ds.limit=0000ffff ds.acc=0093 es=0000 es.base=00000000 es.limit=0000ffff es.acc=0093 fs=0000 fs.base=00000000 fs.limit=0000ffff fs.acc=0093 gs=0000 gs.base=00000000 gs.limit=0000ffff gs.acc=0093 eax=ffff8175 ebx=08d83a9f ecx=00000000 edx=00000000 esi=00000000 edi=00000000 ebp=00000000 esp=0000fff8 eip=00000012 eflags=00000002 libx86emu-1.5/test/0027_cwde.tst000066400000000000000000000002221247503741400163120ustar00rootroot00000000000000[init srand=27] eax=rand ebx=rand ss=0x3000 [code start=0x100:0x0] mov ax,3568h cwde push eax mov eax,ebx mov ax,8175h cwde push eax libx86emu-1.5/test/0028_movsb.done000066400000000000000000000021651247503741400166420ustar00rootroot00000000000000; - - memory ; 0 1 2 3 4 5 6 7 8 9 a b c d e f 00001000: be 00 00 bf 50 00 b9 0f 00 a4 f3 a4 f4 00020000: 6d 1c 3a 14 bd ca 7e 5b 41 93 1a af 55 82 6d 2b 00040050: 6d 1c 3a 14 bd ca 7e 5b 41 93 1a af 55 82 6d 2b ; - - registers msr[0010] 0000000000000006 ; tsc cr0=00000000 cr1=00000000 cr2=00000000 cr3=00000000 cr4=00000000 dr0=00000000 dr1=00000000 dr2=00000000 dr3=00000000 dr6=00000000 dr7=00000000 gdt.base=00000000 gdt.limit=ffff idt.base=00000000 idt.limit=ffff tr=0000 tr.base=00000000 tr.limit=00000000 tr.acc=0000 ldt=0000 ldt.base=00000000 ldt.limit=00000000 ldt.acc=0000 cs=0100 cs.base=00001000 cs.limit=0000ffff cs.acc=009b ss=0000 ss.base=00000000 ss.limit=0000ffff ss.acc=0093 ds=2000 ds.base=00020000 ds.limit=0000ffff ds.acc=0093 es=4000 es.base=00040000 es.limit=0000ffff es.acc=0093 fs=0000 fs.base=00000000 fs.limit=0000ffff fs.acc=0093 gs=0000 gs.base=00000000 gs.limit=0000ffff gs.acc=0093 eax=00000000 ebx=00000000 ecx=a23b0000 edx=00000000 esi=e32a0010 edi=94350060 ebp=00000000 esp=00000000 eip=0000000d eflags=00000002 libx86emu-1.5/test/0028_movsb.tst000066400000000000000000000002471247503741400165260ustar00rootroot00000000000000[init srand=28] 0x20000-0x2000f: rand ecx=rand esi=rand edi=rand ds=0x2000 es=0x4000 [code start=0x100:0x0] mov si,0 mov di,0x50 mov cx,0x0f movsb rep movsb libx86emu-1.5/test/0029_movsb_32.done000066400000000000000000000022271247503741400171460ustar00rootroot00000000000000; - - memory ; 0 1 2 3 4 5 6 7 8 9 a b c d e f 00001000: be 00 00 00 90 bf 50 00 00 90 b9 0f 00 00 00 a4 00001010: f3 a4 f4 90020000: 6e c7 1b 0b 9b 3a 6e 16 35 f7 b3 a8 fe 71 3f fe 90040050: 6e c7 1b 0b 9b 3a 6e 16 35 f7 b3 a8 fe 71 3f fe ; - - registers msr[0010] 0000000000000006 ; tsc cr0=00000000 cr1=00000000 cr2=00000000 cr3=00000000 cr4=00000000 dr0=00000000 dr1=00000000 dr2=00000000 dr3=00000000 dr6=00000000 dr7=00000000 gdt.base=00000000 gdt.limit=ffff idt.base=00000000 idt.limit=ffff tr=0000 tr.base=00000000 tr.limit=00000000 tr.acc=0000 ldt=0000 ldt.base=00000000 ldt.limit=00000000 ldt.acc=0000 cs=0100 cs.base=00001000 cs.limit=0000ffff cs.acc=049b ss=0000 ss.base=00000000 ss.limit=0000ffff ss.acc=0493 ds=2000 ds.base=00020000 ds.limit=efffffff ds.acc=0893 es=4000 es.base=00040000 es.limit=efffffff es.acc=0893 fs=0000 fs.base=00000000 fs.limit=0000ffff fs.acc=0093 gs=0000 gs.base=00000000 gs.limit=0000ffff gs.acc=0093 eax=00000000 ebx=00000000 ecx=00000000 edx=00000000 esi=90000010 edi=90000060 ebp=00000000 esp=00000000 eip=00000013 eflags=00000002 libx86emu-1.5/test/0029_movsb_32.tst000066400000000000000000000003571247503741400170350ustar00rootroot00000000000000[init srand=29] 0x90020000-0x9002000f: rand ecx=rand esi=rand edi=rand ds=0x2000 es=0x4000 ds.limit=0xefffffff es.limit=0xefffffff [code start=0x100:0x0 bits=32] mov esi,0x90000000 mov edi,0x90000050 mov ecx,0x0f movsb rep movsb libx86emu-1.5/test/0030_int_rm16.tst000066400000000000000000000002461247503741400170270ustar00rootroot00000000000000[init mode=real] idt.base=0x9000 edx=0x1 eax=0x2045 [code start=0x100:0x50] sti int 8 mov dl,0x77 hlt interrupt_08: pop ebx push ebx mov cx,0x100 iret libx86emu-1.5/test/0031_io.tst000066400000000000000000000002651247503741400160010ustar00rootroot00000000000000[init mode=real srand=31] idt.base=0x9000 eax=rand edx=rand [code start=0x100:0x50] out dx,al out dx,ax out dx,eax in al,dx in ax,dx in eax,dx in al,0x57 out 0x67,al libx86emu-1.5/test/Makefile000066400000000000000000000011601247503741400156260ustar00rootroot00000000000000CC = gcc CFLAGS = -g -Wall -fomit-frame-pointer -O2 TST_FILES = $(wildcard *.tst) INIT_FILES = $(addsuffix .init,$(basename $(wildcard *.tst))) RES_FILES = $(addsuffix .result,$(basename $(wildcard *.tst))) TEST_OPTS = --verbose --show code,regs,data,acc,io,ints,attr,time .PHONY: all test clean .SECONDARY: $(INIT_FILES) test: x86test $(RES_FILES) all: x86test @./prepare_test *.tst @./x86test $(TEST_OPTS) *.init x86test: x86test.c $(CC) $(CFLAGS) $< -lx86emu -o $@ %.result: %.init @./x86test $(TEST_OPTS) $< %.init: %.tst @./prepare_test $< clean: rm -f *~ *.o x86test *.init *.result *.log libx86emu-1.5/test/foo1.tst000066400000000000000000000015331247503741400155720ustar00rootroot00000000000000[init] 0x1700: 1 2 ecx=0x6789 edx=0x5555 esp=0x9000 [code start=0x100:0x0] mov es,cx mov fs,edx mov gs,[cs:0x700] push gs mov eax,0x1000 mov [cs:eax],es mov [cs:eax+0x77],es mov [cs:eax-0x66],es mov [ds:bx],es mov [ss:0x1234],es mov [ss:bx+si+0x12],es mov [ss:eax+ebx],es mov [ss:eax+ebx+0x12],es mov [ss:eax+ebx+0x12345678],es mov [ss:eax+ebx*4],es mov [ss:eax+ebx*4+0x12],es mov [ss:eax+ebx*4+0x12345678],es mov [ss:ebx*8+0x12345678],es mov [ss:esi*2],es mov [ss:esi-1],es mov [ss:esi*2-1],es mov [ss:esi*2+1],es mov [ss:esi*8],es mov [ss:esi*8+1],es mov [ebp+1],es mov [esp+1],es db 0x36, 0x67, 0x8c, 0x04, 0x25, 0x01, 0x00, 0x00, 0x00 db 0x36, 0x67, 0x8c, 0x04, 0x25, 0x01, 0x00, 0x00, 0xff mov ax,es mov ebx,fs mov [0x1704],gs pop gs jmp 0xc0:foo+0x400 mov cx,0x1111 foo: mov bx,0x9999 mov bl,0x71 mov dh,0x34 libx86emu-1.5/test/foo10.tst000066400000000000000000000002401247503741400156440ustar00rootroot00000000000000[init mode=real] idt.base=0x9000 edx=0x1 eax=0x2045 [code start=0x100:0x50] int 8 mov dl,0x77 hlt interrupt_08: pop ebx push ebx mov cx,0x100 iret libx86emu-1.5/test/foo11.tst000066400000000000000000000001131247503741400156440ustar00rootroot00000000000000[init mode=real srand=31] [code start=0x100:0x0] lmsw ax smsw ax nop libx86emu-1.5/test/foo12.tst000066400000000000000000000002461247503741400156540ustar00rootroot00000000000000[init mode=real srand=31] idt.base=0x9000 edx=0x3da [code start=0x100:0x50] in al,dx mov ah,al in al,dx shl eax,16 in al,dx mov ah,al out dx,al in al,dx libx86emu-1.5/test/foo13.tst000066400000000000000000000001061247503741400156500ustar00rootroot00000000000000[init mode=real srand=31] [code start=0x100:0x50] mov ah,al jmp $ libx86emu-1.5/test/foo14.tst000066400000000000000000000001061247503741400156510ustar00rootroot00000000000000[init mode=real srand=31] [code start=0x100:0x50] jmp near dword $ libx86emu-1.5/test/foo15.tst000066400000000000000000000001061247503741400156520ustar00rootroot00000000000000[init mode=real srand=31] [code start=0x100:0x50] xxx: cli jmp xxx libx86emu-1.5/test/foo16.tst000066400000000000000000000001131247503741400156510ustar00rootroot00000000000000[init mode=real srand=31] [code start=0x100:0x50] xxx: cli jmp near xxx libx86emu-1.5/test/foo17.tst000066400000000000000000000003511247503741400156560ustar00rootroot00000000000000[init mode=real] idt.base=0x9000 edx=0x1 eax=0x2045 0x0000: 0xff 0xff 0xff 0xff 0x9040: 0 0 0 0 [code start=0x100:0x50] sti int 8 mov dl,0x77 int 0x10 mov dh,0x99 hlt interrupt_08: pop ebx push ebx mov cx,0x100 iret libx86emu-1.5/test/foo2.tst000066400000000000000000000003271247503741400155730ustar00rootroot00000000000000[init] ecx=0x1234 [code start=0x100:0x0] mov es,ecx jmp l1 mov [0x2000],es l1: mov [0x3000],es jmp near l2 mov [0x2004],es l2: mov [0x3004],es jmp 0xc0:l3+0x400 mov [0x2008],es l3: mov [0x3008],es libx86emu-1.5/test/foo3.tst000066400000000000000000000003411247503741400155700ustar00rootroot00000000000000[init] ecx=0x1234 [code start=0x100:0x0] mov es,ecx call l1 mov [0x2000],es l1: mov [0x3000],es call l2 mov [0x2004],es l2: mov [0x3004],es call 0xc0:l3+0x400 mov [0x2008],es hlt l3: mov [0x3008],es retf libx86emu-1.5/test/foo6.tst000066400000000000000000000002611247503741400155740ustar00rootroot00000000000000[init srand=25] 0x20050-0x20053: rand eax=rand ebx=rand ds=0x2000 [code start=0x100:0] mov ah,8 rdtsc mov cr1,ebx mov dr6,ebx mov cr2,eax mov ecx,cr2 mov edx,dr6 libx86emu-1.5/test/foo7.tst000066400000000000000000000004711247503741400156000ustar00rootroot00000000000000[init mode=pm] eax=0xffff gdt.base=0x2000 gdt[0]=0 gdt[8]=descr(base=0x1000,limit=0x8fff,acc=0x9b) gdt[16]=descr(base=0x3000,limit=0xa0000fff,acc=0xc93) [code start=8:0 bits=16] inc ax mov bx,16 mov es,bx mov dword [es:0x50],0x12345678 mov ecx,0x10 l1: inc ebx loop l1 mov bx,12 mov fs,bx nop libx86emu-1.5/test/foo8.tst000066400000000000000000000003061247503741400155760ustar00rootroot00000000000000[init mode=pm] gdt.base=0x2000 gdt[0]=0 gdt[8]=descr(base=0x1000,limit=0x8fff,acc=0x9b) gdt[16]=descr(base=0x3000,limit=0xa0000fff,acc=0xc93) [code start=8:0 bits=16] mov bx,12 mov fs,bx nop libx86emu-1.5/test/foo9.tst000066400000000000000000000005041247503741400155770ustar00rootroot00000000000000[init mode=real] gdt.base=0x2000 gdt[0x00]=0 gdt[0x08]=descr(base=0x1000,limit=0x8fff,acc=0x9b) gdt[0x10]=descr(base=0x3000,limit=0xa0000fff,acc=0xc93) gdt[0x18]=descr(base=0,limit=0x99,acc=0x013) eax=1 ebx=0x10 ecx=0x18 [code start=8:0 bits=16] mov cr0,eax mov es,bx mov dword [es:0x50],0x12345678 mov fs,cx nop libx86emu-1.5/test/prepare_test000077500000000000000000000303531247503741400166170ustar00rootroot00000000000000#! /usr/bin/perl use Getopt::Long; sub prepare; sub add_interrupt_table; sub print_listing; sub print_mem; sub print_regs; sub nr; sub seg_ofs; sub decode_descr; sub new_tmp_file; sub cleanup; END { cleanup } $SIG{INT} = \&cleanup; $SIG{TERM} = \&cleanup; $opt_save_temp = 0; GetOptions( 'save-temp' => \$opt_save_temp ); for $name (@ARGV) { prepare $name; } sub prepare { $file_name = shift; my ($section_name, $section, $line, $addr, $v, @i, $i); my ($asm, $bin, $start_cs, $start_eip, $bits, $listing); if(!open(F, $file_name)) { print STDERR "$file_name: $!\n"; return; } while(1) { $_ = ; chomp; next if /^\s*;/; $line = $_; if(/^\s*\[(\S*)(\s+(.*?))?\]/ || !defined($_)) { if(defined $_) { $section_name = $1; map { $section->{$section_name}{args}{$1} = $2 if /(.*)=(.*)/ } split ' ', $3; srand $section->{$section_name}{args}{srand} if exists $section->{$section_name}{args}{srand}; if($section_name eq 'init') { if( $section->{$section_name}{args}{mode} eq 'pm' || $section->{$section_name}{args}{mode} eq 'protected' ) { $section->{$section_name}{args}{mode} = 'protected'; $section->{$section_name}{regs}{cr0} = 1; } else { $section->{$section_name}{args}{mode} = 'real'; } } } if($asm) { print A "\n\thlt\n"; close A; $bin = new_tmp_file; $lst = new_tmp_file; $i = system "nasm -f bin -O99 -o $bin -l $lst $asm"; die "nasm failed\n" if $i; @{$section->{init}{listing}} = `ndisasm -o $start_eip -b $bits $bin`; # map { s/^(0000| )// } @{$section->{init}{listing}} if $bits == 16; map { s/^(.)/($1 eq ' ' ? " " : "cs:") . $1/e } @{$section->{init}{listing}}; add_interrupt_table $section, $lst; $i = `cat $bin`; if($section->{init}{regs}{cr0} & 1) { $addr = decode_descr($section, $start_cs)->{base}; } else { $addr = $start_cs << 4; } $addr += $start_eip; for $v (unpack "C*", $i) { $section->{init}{mem}{$addr++} = $v; } } last unless defined $_; next; } if($section_name eq 'init') { if(s/^\s*(\d\S+?)\s*-\s*(\d\S+?)\s*:\s*//) { undef $v; @i = split ' '; for ($addr = nr $1; $addr <= nr $2; $addr++) { $v = $i[0]; shift @i if @i > 1; $section->{$section_name}{mem}{$addr} = nr($v) & 0xff; } # print "$1 $2 >$_<\n"; } elsif(s/^\s*(\d\S*?)\s*:\s*//) { $addr = nr $1; map { $section->{$section_name}{mem}{$addr++} = nr($_) & 0xff } split ' '; # print "$1 >$_<\n"; } else { map { if(/(.+?)=(.*)/) { $r = $1; $v = $2; if($r =~ /^gdt\[(\S+)\]$/) { die "$file_name:$.: no gdb base set\n" unless exists $section->{$section_name}{regs}{'gdt.base'}; my $gdt_base = $section->{$section_name}{regs}{'gdt.base'}; $idx = nr $1; die "$file_name:$.: $idx: invalid gdt index\n" if $idx & 7; $gdt_base += $idx; if($v eq '0') { for ($i = 0; $i < 8; $i++) { $section->{$section_name}{mem}{$gdt_base + $i} = 0; } } else { die "$file_name:$.: invalid data: \"$_\"\n$line\n" unless $v =~ /^descr\((\S+)\)/; $v = $1; my $base = 0; my $limit = 0; my $acc = 0; for $vv (split /,/, $v) { if($vv =~ /(.+?)=(.*)/) { $base = nr $2 if $1 eq 'base'; $limit = nr $2 if $1 eq 'limit'; $acc = nr $2 if $1 eq 'acc'; } } die "$file_name:$.: invalid access rights\n" if ($acc & ~0xcff); if(($acc & 0x800)) { die "$file_name:$.: invalid limit\n" unless ($limit & 0xfff) == 0xfff; $limit >>= 12; $limit &= 0xfffff; } die "$file_name:$.: invalid limit\n" unless $limit <= 0xfffff; $section->{$section_name}{mem}{$gdt_base} = $limit & 0xff; $section->{$section_name}{mem}{$gdt_base + 1} = ($limit >> 8) & 0xff; $section->{$section_name}{mem}{$gdt_base + 2} = $base & 0xff; $section->{$section_name}{mem}{$gdt_base + 3} = ($base >> 8) & 0xff; $section->{$section_name}{mem}{$gdt_base + 4} = ($base >> 16) & 0xff; $section->{$section_name}{mem}{$gdt_base + 5} = $acc & 0xff; $section->{$section_name}{mem}{$gdt_base + 6} = (($acc >> 4) & 0xf0) + (($limit >> 16) & 0xf); $section->{$section_name}{mem}{$gdt_base + 7} = ($base >> 24) & 0xff; } } else { $section->{$section_name}{regs}{$r} = nr $v; } } else { die "$file_name:$.: invalid data: \"$_\"\n$line\n"; } } split ' '; } } elsif($section_name eq 'code') { if(! $asm) { ($start_cs, $start_eip) = seg_ofs $section->{$section_name}{args}{start}; $bits = nr $section->{$section_name}{args}{bits}; $bits = 16 if $bits != 16 && $bits != 32; $section->{init}{regs}{bits} = $bits; $section->{init}{args}{bits} = $bits; $section->{init}{regs}{eip} = $start_eip; $section->{init}{regs}{cs} = $start_cs; $asm = new_tmp_file; open A, ">$asm"; print A "\tsection .text\n\n"; print A "\tbits $bits\n\n"; print A "\torg $start_eip\n\n"; } print A "$_\n"; } } close F; ($i = $file_name) =~ s/\.tst$/.init/; open W, ">$i"; $section_name = 'init'; if(%{$section->{$section_name}{args}}) { print W "; " . join(', ', map "$_=$section->{$section_name}{args}{$_}", sort keys %{$section->{$section_name}{args}}) . "\n"; print W "\n"; } if($section->{$section_name}{listing}) { print_listing $section->{$section_name}{listing}; print W "\n"; } if($section->{$section_name}{mem}) { print_mem $section->{$section_name}{mem}; print W "\n"; } if($section->{$section_name}{regs}) { print_regs $section, $section->{$section_name}{regs}; print W "\n"; } close W; } sub add_interrupt_table { local $_; my (%int, $i, $eip, $org, $idt_base, $cs, $addr); my $section = shift; my $file = shift; open L, $file; while() { if(/^\s*(\S+)\s+interrupt_([0-9a-f]{2})(:|\s)/) { $i = $2; $_ = ; $int{$i} = $2 if(/^\s*(\S+)\s+(\S+)/); } elsif(/^\s*(\S+)\s+(\S+)\s+\S+\s+interrupt_([0-9a-f]{2})(:|\s)/) { $int{$3} = $2; } } close L; $idt_base = $section->{init}{regs}{'idt.base'}; $cs = $section->{init}{regs}{cs}; $org = $section->{init}{regs}{eip}; for (sort keys %int) { $i = nr "0x$_"; $eip = $org + nr "0x$int{$_}"; if($section->{init}{regs}{cr0} & 1) { $addr = 8*$i + $idt_base; } else { $addr = 4*$i + $idt_base; $section->{init}{mem}{$addr} = $eip & 0xff; $section->{init}{mem}{$addr+1} = ($eip >> 8) & 0xff; $section->{init}{mem}{$addr+2} = $cs & 0xff; $section->{init}{mem}{$addr+3} = ($cs >> 8) & 0xff; } } } sub print_listing { my $l = shift; local $_; for (@$l) { print W "; \L$1\E$2\n" if /^(\S+\s+\S+|\s+\-\S+)(.*)/; } } sub print_mem { my $mem = shift; my ($base_addr, $last_addr, $i); local $_; print W "; "; printf W " %x", $_ for (0..15); print W "\n"; for (sort { $a <=> $b } keys %{$mem}) { $i = $_ & ~0xf; if($i != $base_addr || !defined $base_addr) { print W "\n" if defined $base_addr; $base_addr = $i; $last_addr = $base_addr - 1; printf W "%08x:", $base_addr; } $i = $_ - $last_addr - 1; print W " " x $i; printf W " %02x", $mem->{$_}; $last_addr = $_; } print W "\n" if defined $last_addr; } sub print_regs { my $section = shift; my $regs = shift; my ($i, $rl, $w, $v); local $_; my @reg_list = ( 'cr0 cr1 cr2 cr3 cr4', 'dr0 dr1 dr2 dr3 dr6 dr7', '', 'gdt.base gdt.limit', 'idt.base idt.limit', 'tr ldt', '', 'cs ss ds es fs gs', '', 'eax ebx ecx edx', 'esi edi ebp esp', 'eip eflags' ); $regs->{'gdt.limit'} = 0xffff unless defined $regs->{'gdt.limit'}; $regs->{'idt.limit'} = 0xffff unless defined $regs->{'idt.limit'}; $regs->{'eflags'} = 2 unless defined $regs->{'eflags'}; for (qw (cs ss ds es fs gs)) { if($regs->{cr0} & 1) { $x = decode_descr $section, $regs->{$_}; $regs->{"$_.base"} = $x->{base} unless defined $regs->{"$_.base"}; $regs->{"$_.limit"} = $x->{limit} unless defined $regs->{"$_.limit"}; $regs->{"$_.acc"} = $x->{acc} unless defined $regs->{"$_.acc"}; if( $regs->{"$_.base"} != $x->{base} || $regs->{"$_.limit"} != $x->{limit} || $regs->{"$_.acc"} != $x->{acc} ) { die "$file_name: $_: selector cache does not match gdt\n"; } } else { $regs->{"$_.base"} = $regs->{$_} << 4 unless defined $regs->{"$_.base"}; $regs->{"$_.limit"} = 0xffff unless defined $regs->{"$_.limit"}; if(!defined $regs->{"$_.acc"}) { $regs->{"$_.acc"} = $_ eq 'cs' ? 0x9b : 0x93; $regs->{"$_.acc"} |= 0x400 if ($_ eq 'cs' || $_ eq 'ss') && $regs->{bits} == 32; if($regs->{"$_.limit"} & ~0xfffff) { $regs->{"$_.limit"} |= 0xfff; $regs->{"$_.acc"} |= 0x800; } } } } for $rl (@reg_list) { $i = 0; if($rl eq '') { print W "\n"; next; } for (split ' ', $rl) { $v = $regs->{$_} + 0; if(/^(cs|ds|es|fs|gs|ss|tr|ldt)$/) { print W "\n" if $i; printf W "%s=%04x %s.base=%08x %s.limit=%08x %s.acc=%04x", $_, $regs->{$_}, $_, $regs->{"$_.base"}, $_, $regs->{"$_.limit"}, $_, $regs->{"$_.acc"}; } else { $w = /^(gdt\.limit|idt\.limit)$/ ? 4 : 8; printf W "%s%s=%0${w}x", $i ? ' ' : '', $_, $regs->{$_}; if($_ eq 'eflags') { my $f = $regs->{$_}; my $d; $d .= " of" if $f & 0x800; $d .= " df" if $f & 0x400; $d .= " if" if $f & 0x200; $d .= " sf" if $f & 0x080; $d .= " zf" if $f & 0x040; $d .= " af" if $f & 0x010; $d .= " pf" if $f & 0x004; $d .= " cf" if $f & 0x001; printf W " ;$d" if $d; } } $i++; } print W "\n" if $i; } } sub nr { my $n = shift; my $foo; if($n ne 'rand') { $n = oct $n if $n =~ /^0/; return $n + 0; } $n = ((int rand 0x1000000) & 0xffff00) << 8; $n += int((rand 0x1000000) / 11); return $n; } sub seg_ofs { my @n = split /:/, $_[0]; $n[0] = nr $n[0]; $n[1] = nr $n[1] if @n > 1; unshift @n, undef if @n <= 1; return @n; } sub decode_descr { my ($i, $gdt, $base, $limit, $acc); my $section = shift; my $sel = shift; die "$file_name: no gdt\n" unless exists $section->{init}{regs}{'gdt.base'}; $gdt = $section->{init}{regs}{'gdt.base'} + ($sel & ~7); die "$file_name: selector $sel not in gdt\n" if $sel & 4; for ($i = 0; $i < 8; $i++) { die "$file_name: selector $sel not found\n" unless defined $section->{init}{mem}{$gdt + $i}; } $base = $section->{init}{mem}{$gdt + 2} + ($section->{init}{mem}{$gdt + 3} << 8) + ($section->{init}{mem}{$gdt + 4} << 16) + ($section->{init}{mem}{$gdt + 7} << 24); $limit = $section->{init}{mem}{$gdt} + ($section->{init}{mem}{$gdt + 1} << 8) + (($section->{init}{mem}{$gdt + 6} & 0xf) << 16); $acc = $section->{init}{mem}{$gdt + 5} + (($section->{init}{mem}{$gdt + 6} & 0xf0) << 4); $limit = ($limit << 12) + 0xfff if $acc & 0x800; return { base => $base, limit => $limit, acc => $acc }; } sub new_tmp_file { local $_; chomp ($_ = `mktemp /tmp/x86test.XXXXXXXXXX`); die "error: mktemp failed\n" if $?; push @tmp_files, $_; return $_; } sub cleanup { unlink @tmp_files unless $opt_save_temp; undef @tmp_files; } libx86emu-1.5/test/timing000077500000000000000000000002461247503741400154070ustar00rootroot00000000000000#! /usr/bin/perl while(<>) { if(/^\S+\s+\+(\S+)\s+\S+:\S+\s+/) { $t = hex $1; $total += $t; $count++; } } printf "%.2f\n", $total/$count if $count; libx86emu-1.5/test/x86test.c000066400000000000000000000312411247503741400156620ustar00rootroot00000000000000#define _GNU_SOURCE #include #include #include #include #include #include #include #include #include #include typedef struct { x86emu_t *emu; } vm_t; void lprintf(const char *format, ...) __attribute__ ((format (printf, 1, 2))); void flush_log(x86emu_t *emu, char *buf, unsigned size); void help(void); int do_int(x86emu_t *emu, u8 num, unsigned type); char *skip_spaces(char *s); vm_t *vm_new(void); void vm_free(vm_t *vm); int vm_init(vm_t *vm, char *file); void vm_run(vm_t *vm); void vm_dump(vm_t *vm, char *file); char *build_file_name(char *file, char *suffix); int result_cmp(char *file); int run_test(char *file); struct option options[] = { { "help", 0, NULL, 'h' }, { "verbose", 0, NULL, 'v' }, { "show", 1, NULL, 1001 }, { "max", 1, NULL, 1003 }, { "stderr", 0, NULL, 1004 }, { } }; struct { unsigned verbose; unsigned inst_max; unsigned trace_flags; unsigned dump_flags; struct { unsigned stderr:1; } show; FILE *log_file; } opt; int main(int argc, char **argv) { int i, err = 0; char *s, *t; unsigned u, tbits, dbits; opterr = 0; while((i = getopt_long(argc, argv, "hv", options, NULL)) != -1) { switch(i) { case 'v': opt.verbose++; break; case 1001: for(s = optarg; (t = strsep(&s, ",")); ) { u = 1; tbits = dbits = 0; while(*t == '+' || *t == '-') u = *t++ == '+' ? 1 : 0; if(!strcmp(t, "trace")) tbits = X86EMU_TRACE_DEFAULT; else if(!strcmp(t, "code")) tbits = X86EMU_TRACE_CODE; else if(!strcmp(t, "regs")) tbits = X86EMU_TRACE_REGS; else if(!strcmp(t, "data")) tbits = X86EMU_TRACE_DATA; else if(!strcmp(t, "acc")) tbits = X86EMU_TRACE_ACC; else if(!strcmp(t, "io")) tbits = X86EMU_TRACE_IO; else if(!strcmp(t, "ints")) tbits = X86EMU_TRACE_INTS; else if(!strcmp(t, "time")) tbits = X86EMU_TRACE_TIME; else if(!strcmp(t, "attr")) dbits = X86EMU_DUMP_ATTR; else if(!strcmp(t, "ascii")) dbits = X86EMU_DUMP_ASCII; else err = 5; if(err) { fprintf(stderr, "error: invalid flag '%s'\n", t); return 1; } else { if(tbits) { if(u) { opt.trace_flags |= tbits; } else { opt.trace_flags &= ~tbits; } } if(dbits) { if(u) { opt.dump_flags |= dbits; } else { opt.dump_flags &= ~dbits; } } } } break; case 1003: opt.inst_max = strtoul(optarg, NULL, 0); break; case 1004: opt.show.stderr = 1; break; default: help(); return i == 'h' ? 0 : 1; } } argc -= optind; argv += optind; if(!argc) { help(); return 1; } do { err |= run_test(argv[0]); } while(argv++, --argc); return err; } void lprintf(const char *format, ...) { va_list args; va_start(args, format); if(opt.log_file) vfprintf(opt.log_file, format, args); va_end(args); } void flush_log(x86emu_t *emu, char *buf, unsigned size) { if(!buf || !size || !opt.log_file) return; fwrite(buf, size, 1, opt.log_file); } void help() { fprintf(stderr, "libx86 Test\nusage: x86test test_file\n" ); } int do_int(x86emu_t *emu, u8 num, unsigned type) { if((type & 0xff) == INTR_TYPE_FAULT) { x86emu_stop(emu); } return 0; } char *skip_spaces(char *s) { while(isspace(*s)) s++; return s; } vm_t *vm_new() { vm_t *vm; vm = calloc(1, sizeof *vm); vm->emu = x86emu_new(X86EMU_PERM_R | X86EMU_PERM_W | X86EMU_PERM_X, 0); vm->emu->private = vm; x86emu_set_log(vm->emu, 1000000, flush_log); x86emu_set_intr_handler(vm->emu, do_int); vm->emu->log.trace = opt.trace_flags; return vm; } void vm_free(vm_t *vm) { x86emu_done(vm->emu); free(vm); } int vm_init(vm_t *vm, char *file) { FILE *f; char buf[1024], *s, *s1, *s2; unsigned u, addr, line = 0; if(!vm || !file) return 1; if(!(f = fopen(file, "r"))) return 0; lprintf("- - - - - - - - initial vm state [%s] - - - - - - - -\n", file); while(fgets(buf, sizeof buf, f)) { lprintf("%s", buf); line++; if((s = strchr(buf, ';'))) *s = 0; s = skip_spaces(buf); if(*s == 0) continue; addr = strtoul(s, &s1, 16); if(s1 - s == 8 && *s1 == ':') { s = s1 + 1; while( isspace(s[0]) && isspace(s[1]) && ((isxdigit(s[2]) && isxdigit(s[3])) || (isspace(s[2]) && isspace(s[3]))) && !isxdigit(s[4]) ) { if(isxdigit(s[2])) x86emu_write_byte(vm->emu, addr, strtoul(s, NULL, 16)); addr++; s += 4; } } else { while((s1 = strchr(s, '='))) { u = strtoul(s1 + 1, &s2, 16); if(*s2 && !isspace(*s2)) { lprintf("%s:%u: invalid line:\n%s", file, line, buf); return 0; } s1++; if(!memcmp(s, "eax=", s1 - s)) vm->emu->x86.R_EAX = u; else if(!memcmp(s, "ebx=", s1 - s)) vm->emu->x86.R_EBX = u; else if(!memcmp(s, "ecx=", s1 - s)) vm->emu->x86.R_ECX = u; else if(!memcmp(s, "edx=", s1 - s)) vm->emu->x86.R_EDX = u; else if(!memcmp(s, "esi=", s1 - s)) vm->emu->x86.R_ESI = u; else if(!memcmp(s, "edi=", s1 - s)) vm->emu->x86.R_EDI = u; else if(!memcmp(s, "ebp=", s1 - s)) vm->emu->x86.R_EBP = u; else if(!memcmp(s, "esp=", s1 - s)) vm->emu->x86.R_ESP = u; else if(!memcmp(s, "eip=", s1 - s)) vm->emu->x86.R_EIP = u; else if(!memcmp(s, "eflags=", s1 - s)) vm->emu->x86.R_EFLG = u; else if(!memcmp(s, "cs=", s1 - s)) { vm->emu->x86.R_CS = u; vm->emu->x86.R_CS_BASE = vm->emu->x86.R_CS << 4; } else if(!memcmp(s, "ds=", s1 - s)) { vm->emu->x86.R_DS = u; vm->emu->x86.R_DS_BASE = vm->emu->x86.R_DS << 4; } else if(!memcmp(s, "es=", s1 - s)) { vm->emu->x86.R_ES = u; vm->emu->x86.R_ES_BASE = vm->emu->x86.R_ES << 4; } else if(!memcmp(s, "fs=", s1 - s)) { vm->emu->x86.R_FS = u; vm->emu->x86.R_FS_BASE = vm->emu->x86.R_FS << 4; } else if(!memcmp(s, "gs=", s1 - s)) { vm->emu->x86.R_GS = u; vm->emu->x86.R_GS_BASE = vm->emu->x86.R_GS << 4; } else if(!memcmp(s, "ss=", s1 - s)) { vm->emu->x86.R_SS = u; vm->emu->x86.R_SS_BASE = vm->emu->x86.R_SS << 4; } else if(!memcmp(s, "cs.base=", s1 - s)) vm->emu->x86.R_CS_BASE = u; else if(!memcmp(s, "ds.base=", s1 - s)) vm->emu->x86.R_DS_BASE = u; else if(!memcmp(s, "es.base=", s1 - s)) vm->emu->x86.R_ES_BASE = u; else if(!memcmp(s, "fs.base=", s1 - s)) vm->emu->x86.R_FS_BASE = u; else if(!memcmp(s, "gs.base=", s1 - s)) vm->emu->x86.R_GS_BASE = u; else if(!memcmp(s, "ss.base=", s1 - s)) vm->emu->x86.R_SS_BASE = u; else if(!memcmp(s, "cs.limit=", s1 - s)) vm->emu->x86.R_CS_LIMIT = u; else if(!memcmp(s, "ds.limit=", s1 - s)) vm->emu->x86.R_DS_LIMIT = u; else if(!memcmp(s, "es.limit=", s1 - s)) vm->emu->x86.R_ES_LIMIT = u; else if(!memcmp(s, "fs.limit=", s1 - s)) vm->emu->x86.R_FS_LIMIT = u; else if(!memcmp(s, "gs.limit=", s1 - s)) vm->emu->x86.R_GS_LIMIT = u; else if(!memcmp(s, "ss.limit=", s1 - s)) vm->emu->x86.R_SS_LIMIT = u; else if(!memcmp(s, "cs.acc=", s1 - s)) vm->emu->x86.R_CS_ACC = u; else if(!memcmp(s, "ds.acc=", s1 - s)) vm->emu->x86.R_DS_ACC = u; else if(!memcmp(s, "es.acc=", s1 - s)) vm->emu->x86.R_ES_ACC = u; else if(!memcmp(s, "fs.acc=", s1 - s)) vm->emu->x86.R_FS_ACC = u; else if(!memcmp(s, "gs.acc=", s1 - s)) vm->emu->x86.R_GS_ACC = u; else if(!memcmp(s, "ss.acc=", s1 - s)) vm->emu->x86.R_SS_ACC = u; else if(!memcmp(s, "tr=", s1 - s)) vm->emu->x86.R_TR = u; else if(!memcmp(s, "tr.base=", s1 - s)) vm->emu->x86.R_TR_BASE = u; else if(!memcmp(s, "tr.limit=", s1 - s)) vm->emu->x86.R_TR_LIMIT = u; else if(!memcmp(s, "tr.acc=", s1 - s)) vm->emu->x86.R_TR_ACC = u; else if(!memcmp(s, "ldt=", s1 - s)) vm->emu->x86.R_LDT = u; else if(!memcmp(s, "ldt.base=", s1 - s)) vm->emu->x86.R_LDT_BASE = u; else if(!memcmp(s, "ldt.limit=", s1 - s)) vm->emu->x86.R_LDT_LIMIT = u; else if(!memcmp(s, "ldt.acc=", s1 - s)) vm->emu->x86.R_LDT_ACC = u; else if(!memcmp(s, "gdt.base=", s1 - s)) vm->emu->x86.R_GDT_BASE = u; else if(!memcmp(s, "gdt.limit=", s1 - s)) vm->emu->x86.R_GDT_LIMIT = u; else if(!memcmp(s, "idt.base=", s1 - s)) vm->emu->x86.R_IDT_BASE = u; else if(!memcmp(s, "idt.limit=", s1 - s)) vm->emu->x86.R_IDT_LIMIT = u; else if(!memcmp(s, "cr0=", s1 - s)) vm->emu->x86.R_CR0 = u; else if(!memcmp(s, "cr1=", s1 - s)) vm->emu->x86.R_CR1 = u; else if(!memcmp(s, "cr2=", s1 - s)) vm->emu->x86.R_CR2 = u; else if(!memcmp(s, "cr3=", s1 - s)) vm->emu->x86.R_CR3 = u; else if(!memcmp(s, "cr4=", s1 - s)) vm->emu->x86.R_CR4 = u; else if(!memcmp(s, "dr0=", s1 - s)) vm->emu->x86.R_DR0 = u; else if(!memcmp(s, "dr1=", s1 - s)) vm->emu->x86.R_DR1 = u; else if(!memcmp(s, "dr2=", s1 - s)) vm->emu->x86.R_DR2 = u; else if(!memcmp(s, "dr3=", s1 - s)) vm->emu->x86.R_DR3 = u; else if(!memcmp(s, "dr6=", s1 - s)) vm->emu->x86.R_DR6 = u; else if(!memcmp(s, "dr7=", s1 - s)) vm->emu->x86.R_DR7 = u; else break; s = skip_spaces(s2); } s = skip_spaces(s); if(*s) { lprintf("%s:%u: invalid line:\n%s", file, line, buf); return 0; } } } lprintf("- - - - - - - - - - - - - - - -\n"); fclose(f); return 1; } void vm_run(vm_t *vm) { unsigned flags; // x86emu_set_perm(vm->emu, 0x1004, 0x1004, X86EMU_PERM_VALID | X86EMU_PERM_R); // x86emu_set_io_perm(vm->emu, 0, 0x3ff, X86EMU_PERM_R | X86EMU_PERM_W); // iopl(3); flags = X86EMU_RUN_LOOP | X86EMU_RUN_NO_CODE; if(opt.inst_max) { vm->emu->max_instr = opt.inst_max; flags |= X86EMU_RUN_MAX_INSTR; } x86emu_run(vm->emu, flags); x86emu_clear_log(vm->emu, 1); } void vm_dump(vm_t *vm, char *file) { FILE *old_log; old_log = opt.log_file; if(file) opt.log_file = fopen(file, "w"); if(opt.log_file) { x86emu_dump(vm->emu, X86EMU_DUMP_MEM | X86EMU_DUMP_REGS | (!file && opt.dump_flags ? opt.dump_flags : 0) ); x86emu_clear_log(vm->emu, 1); } if(file) fclose(opt.log_file); opt.log_file = old_log; } char *build_file_name(char *file, char *suffix) { int i; static char *s = NULL; free(s); s = NULL; if(!file || !suffix) return s; i = strlen(file); // 5 = strlen(".init") if(i >= 5 && !strcmp(file + i - 5, ".init")) { s = calloc(1, i - 5 + strlen(suffix) + 1); memcpy(s, file, i - 5); strcat(s, suffix); } else { asprintf(&s, "%s%s", file, suffix); } return s; } int result_cmp(char *file) { FILE *f0, *f1; int err = 1; unsigned char *buf0, *buf1; int i, l0, l1; f0 = fopen(build_file_name(file, ".result"), "r"); f1 = fopen(build_file_name(file, ".done"), "r"); if(!f1) err = 2; if(f0 && f1) { l0 = fseek(f0, 0, SEEK_END); l1 = fseek(f1, 0, SEEK_END); if(!l0 && !l1) { l0 = ftell(f0); l1 = ftell(f1); rewind(f0); rewind(f1); if(l0 && l0 == l1) { i = l0; buf0 = malloc(i); buf1 = malloc(i); l0 = fread(buf0, 1, i, f0); l1 = fread(buf1, 1, i, f1); if(l0 == i && l1 == i && !memcmp(buf0, buf1, i)) err = 0; free(buf1); free(buf0); } } } if(f1) fclose(f1); if(f0) fclose(f0); build_file_name(NULL, NULL); return err; } int run_test(char *file) { vm_t *vm = vm_new(); int ok = 0, result = 0; if(!file) return 1; opt.log_file = opt.show.stderr ? stderr : fopen(build_file_name(file, ".log"), "w"); ok = vm_init(vm, file); if(ok) { lprintf("%s: starting test\n", file); vm_run(vm); lprintf("\n- - - - - - - - final vm state - - - - - - - -\n"); vm_dump(vm, NULL); lprintf("- - - - - - - - - - - - - - - -\n"); vm_dump(vm, build_file_name(file, ".result")); } vm_free(vm); if(ok) { result = result_cmp(file); } else { result = 1; } lprintf("%s: %s\n", file, result == 0 ? "ok" : result == 1 ? "failed" : "unchecked"); fprintf(stderr, "%s %s\n", result == 0 ? "ok" : result == 1 ? "F " : "- ", file); fclose(opt.log_file); opt.log_file = NULL; build_file_name(NULL, NULL); return result == 1 ? 1 : 0; }