From: kaf24@firebug.cl.cam.ac.uk Date: Wed, 9 Mar 2005 16:43:53 +0000 (+0000) Subject: bitkeeper revision 1.1236.18.1 (422f27c9EveZXnXhkLBg8iYwaAffoQ) X-Git-Tag: archive/raspbian/4.8.0-1+rpi1~1^2~17857^2~57^2~2^2 X-Git-Url: https://dgit.raspbian.org/?a=commitdiff_plain;h=4c5eeec983495e347c6ab3d40a4a70cdbdfce9af;p=xen.git bitkeeper revision 1.1236.18.1 (422f27c9EveZXnXhkLBg8iYwaAffoQ) Begin integrating new instruction decoder and emulator. Signed-off-by: Keir Fraser --- diff --git a/.rootkeys b/.rootkeys index f1e7482e2b..779e74a063 100644 --- a/.rootkeys +++ b/.rootkeys @@ -788,6 +788,8 @@ 40fcefb3yMSrZvApO9ToIi-iQwnchA tools/sv/images/xen.png 41013a83z27rKvWIxAfUBMVZ1eDCDg tools/sv/inc/script.js 40fcefb3zGC9XNBkSwTEobCoq8YClA tools/sv/inc/style.css +422f27c8MDeRoOWZNdcRC5VDTcj3TQ tools/tests/Makefile +422f27c81CCtXt4Lthf7JF3Ajr0fUA tools/tests/test_x86_emulator.c 420b963dK3yGNtqxRM8npGZtrCQd1g tools/vnet/00INSTALL 41a21888_WlknVWjSxb32Fo13_ujsw tools/vnet/00README 420a9b706I-bN_uPdiy0m3rmDifNNg tools/vnet/INSTALL @@ -1017,6 +1019,7 @@ 42000d3cMb8o1WuFBXC07c8i3lPZBw xen/arch/x86/x86_64/traps.c 40e96d3ahBTZqbTViInnq0lM03vs7A xen/arch/x86/x86_64/usercopy.c 40e96d3akN3Hu_J5Bk-WXD8OGscrYQ xen/arch/x86/x86_64/xen.lds +422f27c8J9DQfCpegccMid59XhSmGA xen/arch/x86/x86_emulate.c 3ddb79bdff-gj-jFGKjOejeHLqL8Lg xen/common/Makefile 3e397e66AyyD5fYraAySWuwi9uqSXg xen/common/ac_timer.c 3ddb79bdLX_P6iB7ILiblRLWvebapg xen/common/dom0_ops.c @@ -1180,6 +1183,7 @@ 404f1bb86rAXB3aLS1vYdcqpJiEcyg xen/include/asm-x86/x86_64/regs.h 40e1966azOJZfNI6Ilthe6Q-T3Hewg xen/include/asm-x86/x86_64/string.h 404f1bc4tWkB9Qr8RkKtZGW5eMQzhw xen/include/asm-x86/x86_64/uaccess.h +422f27c8RHFkePhD34VIEpMMqofZcA xen/include/asm-x86/x86_emulate.h 400304fcmRQmDdFYEzDh0wcBba9alg xen/include/public/COPYING 421098b7OKb9YH_EUA_UpCxBjaqtgA xen/include/public/arch-ia64.h 404f1bc68SXxmv0zQpXBWGrCzSyp8w xen/include/public/arch-x86_32.h diff --git a/BitKeeper/etc/ignore b/BitKeeper/etc/ignore index 3c7420ae36..e7c52f6ba5 100644 --- a/BitKeeper/etc/ignore +++ b/BitKeeper/etc/ignore @@ -121,32 +121,6 @@ tools/blktap/vdi_snap tools/blktap/vdi_snap_list tools/blktap/vdi_tree tools/blktap/vdi_validate -tools/blktap/xen/arch-ia64.h -tools/blktap/xen/arch-x86_32.h -tools/blktap/xen/arch-x86_64.h -tools/blktap/xen/dom0_ops.h -tools/blktap/xen/event_channel.h -tools/blktap/xen/grant_table.h -tools/blktap/xen/io/blkif.h -tools/blktap/xen/io/domain_controller.h -tools/blktap/xen/io/ioreq.h -tools/blktap/xen/io/netif.h -tools/blktap/xen/io/ring.h -tools/blktap/xen/io/usbif.h -tools/blktap/xen/linux/privcmd.h -tools/blktap/xen/linux/suspend.h -tools/blktap/xen/physdev.h -tools/blktap/xen/sched_ctl.h -tools/blktap/xen/trace.h -tools/blktap/xen/xen.h -tools/cmdline/Makefile -tools/cmdline/ringbuster -tools/cmdline/ringbuster.c -tools/cmdline/xdestroy -tools/cmdline/xdestroy.c -tools/cmdline/xevtchn -tools/cmdline/xevtchn.c -tools/cmdline/xls -tools/cmdline/xls.c -tools/cmdline/xphysinfo -tools/cmdline/xphysinfo.c +tools/blktap/xen/* +tools/cmdline/* +tools/tests/test_x86_emulator diff --git a/tools/tests/Makefile b/tools/tests/Makefile new file mode 100644 index 0000000000..3e8962a714 --- /dev/null +++ b/tools/tests/Makefile @@ -0,0 +1,22 @@ + +XEN_ROOT=../.. +include $(XEN_ROOT)/tools/Rules.mk + +TARGET := test_x86_emulator + +CC := gcc +CFLAGS := -O2 -Wall -Werror -D__TEST_HARNESS__ + +$(TARGET): x86_emulate.o test_x86_emulator.o + $(CC) -o $@ $^ + +clean: + rm -rf $(TARGET) *.o *~ core + +install: + +x86_emulate.o: $(XEN_ROOT)/xen/arch/x86/x86_emulate.c + $(CC) $(CFLAGS) -I$(XEN_ROOT)/xen/include -c -o $@ $< + +%.o: %.c + $(CC) $(CFLAGS) -I$(XEN_ROOT)/xen/include -c -o $@ $< diff --git a/tools/tests/test_x86_emulator.c b/tools/tests/test_x86_emulator.c new file mode 100644 index 0000000000..2ccc20f97f --- /dev/null +++ b/tools/tests/test_x86_emulator.c @@ -0,0 +1,168 @@ + +#include +#include +#include +#include +typedef uint8_t u8; +typedef uint16_t u16; +typedef uint32_t u32; +typedef uint64_t u64; +typedef int8_t s8; +typedef int16_t s16; +typedef int32_t s32; +typedef int64_t s64; +#include +#include + +static int read_any( + unsigned long addr, + unsigned long *val, + unsigned int bytes) +{ + switch ( bytes ) + { + case 1: *val = *(u8 *)addr; break; + case 2: *val = *(u16 *)addr; break; + case 4: *val = *(u32 *)addr; break; + case 8: *val = *(unsigned long *)addr; break; + } + return 0; +} + +static int write_any( + unsigned long addr, + unsigned long val, + unsigned int bytes) +{ + switch ( bytes ) + { + case 1: *(u8 *)addr = (u8)val; break; + case 2: *(u16 *)addr = (u16)val; break; + case 4: *(u32 *)addr = (u32)val; break; + case 8: *(unsigned long *)addr = val; break; + } + return 0; +} + +static int cmpxchg_any( + unsigned long addr, + unsigned long old, + unsigned long new, + unsigned long *seen, + unsigned int bytes) +{ + *seen = old; + switch ( bytes ) + { + case 1: *(u8 *)addr = (u8)new; break; + case 2: *(u16 *)addr = (u16)new; break; + case 4: *(u32 *)addr = (u32)new; break; + case 8: *(unsigned long *)addr = new; break; + } + return 0; +} + +static struct x86_mem_emulator emulops = { + read_any, write_any, read_any, write_any, cmpxchg_any +}; + +int main(int argc, char **argv) +{ + struct xen_regs regs; + char instr[] = { 0x01, 0x08 }; /* add %ecx,(%eax) */ + unsigned int res = 0x7FFFFFFF; + unsigned long cr2; + int rc; + + printf("%-40s", "Testing addl %%ecx,(%%eax)..."); + instr[0] = 0x01; instr[1] = 0x08; + regs.eflags = 0x200; + regs.eip = (unsigned long)&instr[0]; + regs.ecx = 0x12345678; + cr2 = (unsigned long)&res; + res = 0x7FFFFFFF; + rc = x86_emulate_memop(®s, cr2, &emulops, 4); + if ( (rc != 0) || + (res != 0x92345677) || + (regs.eflags != 0xa94) || + (regs.eip != (unsigned long)&instr[2]) ) + goto fail; + printf("okay\n"); + + printf("%-40s", "Testing xorl (%%eax),%%ecx..."); + instr[0] = 0x33; instr[1] = 0x08; + regs.eflags = 0x200; + regs.eip = (unsigned long)&instr[0]; +#ifdef __x86_64__ + regs.ecx = 0xFFFFFFFF12345678UL; +#else + regs.ecx = 0x12345678UL; +#endif + cr2 = (unsigned long)&res; + rc = x86_emulate_memop(®s, cr2, &emulops, 4); + if ( (rc != 0) || + (res != 0x92345677) || + (regs.ecx != 0x8000000FUL) || + (regs.eip != (unsigned long)&instr[2]) ) + goto fail; + printf("okay\n"); + + printf("%-40s", "Testing lock cmpxchgb %%cl,(%%eax)..."); + instr[0] = 0xf0; instr[1] = 0x0f; instr[2] = 0xb0; instr[3] = 0x08; + regs.eflags = 0x200; + regs.eip = (unsigned long)&instr[0]; + regs.eax = 0x92345677UL; + regs.ecx = 0xAA; + cr2 = (unsigned long)&res; + rc = x86_emulate_memop(®s, cr2, &emulops, 4); + if ( (rc != 0) || + (res != 0x923456AA) || + (regs.eflags != 0x244) || + (regs.eax != 0x92345677UL) || + (regs.eip != (unsigned long)&instr[4]) ) + goto fail; + printf("okay\n"); + + printf("%-40s", "Testing lock cmpxchgl %%ecx,(%%eax)..."); + instr[0] = 0xf0; instr[1] = 0x0f; instr[2] = 0xb1; instr[3] = 0x08; + regs.eflags = 0x200; + regs.eip = (unsigned long)&instr[0]; + regs.eax = 0x923456AAUL; + regs.ecx = 0xDDEEFF00L; + cr2 = (unsigned long)&res; + rc = x86_emulate_memop(®s, cr2, &emulops, 4); + if ( (rc != 0) || + (res != 0xDDEEFF00) || + (regs.eflags != 0x244) || + (regs.eax != 0x923456AAUL) || + (regs.eip != (unsigned long)&instr[4]) ) + goto fail; + printf("okay\n"); + + printf("%-40s", "Testing rep movsw..."); + instr[0] = 0xf3; instr[1] = 0x66; instr[2] = 0xa5; + res = 0x22334455; + regs.eflags = 0x200; + regs.ecx = 23; + regs.eip = (unsigned long)&instr[0]; + regs.esi = (unsigned long)&res + 0; + regs.edi = (unsigned long)&res + 2; + regs.error_code = 0; /* read fault */ + cr2 = regs.esi; + rc = x86_emulate_memop(®s, cr2, &emulops, 4); + if ( (rc != 0) || + (res != 0x44554455) || + (regs.eflags != 0x200) || + (regs.ecx != 22) || + (regs.esi != ((unsigned long)&res + 2)) || + (regs.edi != ((unsigned long)&res + 4)) || + (regs.eip != (unsigned long)&instr[0]) ) + goto fail; + printf("okay\n"); + + return 0; + + fail: + printf("failed!\n"); + return 1; +} diff --git a/xen/arch/x86/traps.c b/xen/arch/x86/traps.c index eb44a63206..9491787fcb 100644 --- a/xen/arch/x86/traps.c +++ b/xen/arch/x86/traps.c @@ -52,6 +52,7 @@ #include #include #include +#include /* * opt_nmi: one of 'ignore', 'dom0', or 'fatal'. @@ -369,8 +370,6 @@ long do_fpu_taskswitch(int set) static int emulate_privileged_op(struct xen_regs *regs) { - extern void *decode_reg(struct xen_regs *regs, u8 b); - struct exec_domain *ed = current; unsigned long *reg, eip = regs->eip; u8 opcode; @@ -405,7 +404,7 @@ static int emulate_privileged_op(struct xen_regs *regs) eip += 1; if ( (opcode & 0xc0) != 0xc0 ) goto fail; - reg = decode_reg(regs, opcode & 7); + reg = decode_register(opcode & 7, regs, 0); switch ( (opcode >> 3) & 7 ) { case 0: /* Read CR0 */ @@ -433,7 +432,7 @@ static int emulate_privileged_op(struct xen_regs *regs) eip += 1; if ( (opcode & 0xc0) != 0xc0 ) goto fail; - reg = decode_reg(regs, opcode & 7); + reg = decode_register(opcode & 7, regs, 0); switch ( (opcode >> 3) & 7 ) { case 0: /* Write CR0 */ diff --git a/xen/arch/x86/x86_32/seg_fixup.c b/xen/arch/x86/x86_32/seg_fixup.c index 00c388dc92..8c3d2a5d52 100644 --- a/xen/arch/x86/x86_32/seg_fixup.c +++ b/xen/arch/x86/x86_32/seg_fixup.c @@ -28,6 +28,7 @@ #include #include #include +#include /* Make the scary benign errors go away. */ #undef DPRINTK @@ -258,24 +259,6 @@ int fixup_seg(u16 seg, unsigned long offset) return 1; } -/* Decode Reg field of a ModRM byte: return a pointer into a register block. */ -void *decode_reg(struct xen_regs *regs, u8 b) -{ - switch ( b & 7 ) - { - case 0: return ®s->eax; - case 1: return ®s->ecx; - case 2: return ®s->edx; - case 3: return ®s->ebx; - case 4: return ®s->esp; - case 5: return ®s->ebp; - case 6: return ®s->esi; - case 7: return ®s->edi; - } - - return NULL; -} - /* * Called from the general-protection fault handler to attempt to decode * and emulate an instruction that depends on 4GB segments. @@ -402,8 +385,8 @@ int gpf_emulate_4gb(struct xen_regs *regs) } /* Decode Reg and R/M fields. */ - regreg = decode_reg(regs, reg); - memreg = decode_reg(regs, rm); + regreg = decode_register(reg, regs, 0); + memreg = decode_register(rm, regs, 0); /* Decode Mod field. */ switch ( modrm >> 6 ) diff --git a/xen/arch/x86/x86_64/traps.c b/xen/arch/x86/x86_64/traps.c index 8cc16a1279..2c74f27d0c 100644 --- a/xen/arch/x86/x86_64/traps.c +++ b/xen/arch/x86/x86_64/traps.c @@ -248,31 +248,6 @@ void __init percpu_traps_init(void) wrmsr(MSR_SYSCALL_MASK, EF_VM|EF_RF|EF_NT|EF_DF|EF_IE|EF_TF, 0U); } -void *decode_reg(struct xen_regs *regs, u8 b) -{ - switch ( b ) - { - case 0: return ®s->rax; - case 1: return ®s->rcx; - case 2: return ®s->rdx; - case 3: return ®s->rbx; - case 4: return ®s->rsp; - case 5: return ®s->rbp; - case 6: return ®s->rsi; - case 7: return ®s->rdi; - case 8: return ®s->r8; - case 9: return ®s->r9; - case 10: return ®s->r10; - case 11: return ®s->r11; - case 12: return ®s->r12; - case 13: return ®s->r13; - case 14: return ®s->r14; - case 15: return ®s->r15; - } - - return NULL; -} - long do_set_callbacks(unsigned long event_address, unsigned long failsafe_address, unsigned long syscall_address) diff --git a/xen/arch/x86/x86_emulate.c b/xen/arch/x86/x86_emulate.c new file mode 100644 index 0000000000..a36c31f4d8 --- /dev/null +++ b/xen/arch/x86/x86_emulate.c @@ -0,0 +1,968 @@ +/****************************************************************************** + * x86_emulate.c + * + * Generic x86 (32-bit and 64-bit) instruction decoder and emulator. + * + * Copyright (c) 2005 Keir Fraser + */ + +#ifdef __TEST_HARNESS__ +#include +#include +typedef uint8_t u8; +typedef uint16_t u16; +typedef uint32_t u32; +typedef uint64_t u64; +typedef int8_t s8; +typedef int16_t s16; +typedef int32_t s32; +typedef int64_t s64; +#include +#else +#include +#include +#include +#include +#endif +#include + +/* + * Opcode effective-address decode tables. + * Note that we only emulate instructions that have at least one memory + * operand (excluding implicit stack references). We assume that stack + * references and instruction fetches will never occur in special memory + * areas that require emulation. So, for example, 'mov ,' need + * not be handled. + */ + +/* Operand sizes: 8-bit operands or specified/overridden size. */ +#define ByteOp (1<<0) /* 8-bit operands. */ +/* Destination operand type. */ +#define ImplicitOps (1<<1) /* Implicit in opcode. No generic decode. */ +#define DstReg (2<<1) /* Register operand. */ +#define DstMem (3<<1) /* Memory operand. */ +#define DstMask (3<<1) +/* Source operand type. */ +#define SrcNone (0<<3) /* No source operand. */ +#define SrcImplicit (0<<3) /* Source operand is implicit in the opcode. */ +#define SrcReg (1<<3) /* Register operand. */ +#define SrcMem (2<<3) /* Memory operand. */ +#define SrcImm (3<<3) /* Immediate operand. */ +#define SrcImmByte (4<<3) /* 8-bit sign-extended immediate operand. */ +#define SrcMask (7<<3) +/* Generic ModRM decode. */ +#define ModRM (1<<6) +/* Destination is only written; never read. */ +#define Mov (1<<7) + +static u8 opcode_table[256] = { + /* 0x00 - 0x07 */ + ByteOp|DstMem|SrcReg|ModRM, DstMem|SrcReg|ModRM, + ByteOp|DstReg|SrcMem|ModRM, DstReg|SrcMem|ModRM, + 0, 0, 0, 0, + /* 0x08 - 0x0F */ + ByteOp|DstMem|SrcReg|ModRM, DstMem|SrcReg|ModRM, + ByteOp|DstReg|SrcMem|ModRM, DstReg|SrcMem|ModRM, + 0, 0, 0, 0, + /* 0x10 - 0x17 */ + ByteOp|DstMem|SrcReg|ModRM, DstMem|SrcReg|ModRM, + ByteOp|DstReg|SrcMem|ModRM, DstReg|SrcMem|ModRM, + 0, 0, 0, 0, + /* 0x18 - 0x1F */ + ByteOp|DstMem|SrcReg|ModRM, DstMem|SrcReg|ModRM, + ByteOp|DstReg|SrcMem|ModRM, DstReg|SrcMem|ModRM, + 0, 0, 0, 0, + /* 0x20 - 0x27 */ + ByteOp|DstMem|SrcReg|ModRM, DstMem|SrcReg|ModRM, + ByteOp|DstReg|SrcMem|ModRM, DstReg|SrcMem|ModRM, + 0, 0, 0, 0, + /* 0x28 - 0x2F */ + ByteOp|DstMem|SrcReg|ModRM, DstMem|SrcReg|ModRM, + ByteOp|DstReg|SrcMem|ModRM, DstReg|SrcMem|ModRM, + 0, 0, 0, 0, + /* 0x30 - 0x37 */ + ByteOp|DstMem|SrcReg|ModRM, DstMem|SrcReg|ModRM, + ByteOp|DstReg|SrcMem|ModRM, DstReg|SrcMem|ModRM, + 0, 0, 0, 0, + /* 0x38 - 0x3F */ + ByteOp|DstMem|SrcReg|ModRM, DstMem|SrcReg|ModRM, + ByteOp|DstReg|SrcMem|ModRM, DstReg|SrcMem|ModRM, + 0, 0, 0, 0, + /* 0x40 - 0x4F */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + /* 0x50 - 0x5F */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + /* 0x60 - 0x6F */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + /* 0x70 - 0x7F */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + /* 0x80 - 0x87 */ + ByteOp|DstMem|SrcImm|ModRM, DstMem|SrcImm|ModRM, + ByteOp|DstMem|SrcImm|ModRM, DstMem|SrcImmByte|ModRM, + ByteOp|DstMem|SrcReg|ModRM, DstMem|SrcReg|ModRM, + ByteOp|DstMem|SrcReg|ModRM, DstMem|SrcReg|ModRM, + /* 0x88 - 0x8F */ + ByteOp|DstMem|SrcReg|ModRM, DstMem|SrcReg|ModRM, + ByteOp|DstReg|SrcMem|ModRM, DstReg|SrcMem|ModRM, + 0, 0, 0, DstMem|SrcNone|ModRM|Mov, + /* 0x90 - 0x9F */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + /* 0xA0 - 0xA7 */ + ByteOp|DstReg|SrcMem|Mov, DstReg|SrcMem|Mov, + ByteOp|DstMem|SrcReg|Mov, DstMem|SrcReg|Mov, + ByteOp|ImplicitOps|Mov, ImplicitOps|Mov, + ByteOp|ImplicitOps, ImplicitOps, + /* 0xA8 - 0xAF */ + 0, 0, ByteOp|ImplicitOps|Mov, ImplicitOps|Mov, + ByteOp|ImplicitOps|Mov, ImplicitOps|Mov, + ByteOp|ImplicitOps, ImplicitOps, + /* 0xB0 - 0xBF */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + /* 0xC0 - 0xC7 */ + ByteOp|DstMem|SrcImm|ModRM, DstMem|SrcImmByte|ModRM, 0, 0, + 0, 0, ByteOp|DstMem|SrcImm|ModRM, DstMem|SrcImm|ModRM, + /* 0xC8 - 0xCF */ + 0, 0, 0, 0, 0, 0, 0, 0, + /* 0xD0 - 0xD7 */ + ByteOp|DstMem|SrcImplicit|ModRM, DstMem|SrcImplicit|ModRM, + ByteOp|DstMem|SrcImplicit|ModRM, DstMem|SrcImplicit|ModRM, + 0, 0, 0, 0, + /* 0xD8 - 0xDF */ + 0, 0, 0, 0, 0, 0, 0, 0, + /* 0xE0 - 0xEF */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + /* 0xF0 - 0xF7 */ + 0, 0, 0, 0, + 0, 0, ByteOp|DstMem|SrcNone|ModRM, DstMem|SrcNone|ModRM, + /* 0xF8 - 0xFF */ + 0, 0, 0, 0, + 0, 0, ByteOp|DstMem|SrcNone|ModRM, DstMem|SrcNone|ModRM +}; + +static u8 twobyte_table[256] = { + /* 0x00 - 0x0F */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ImplicitOps|ModRM, 0, 0, + /* 0x10 - 0x1F */ + 0, 0, 0, 0, 0, 0, 0, 0, ImplicitOps|ModRM, 0, 0, 0, 0, 0, 0, 0, + /* 0x20 - 0x2F */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + /* 0x30 - 0x3F */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + /* 0x40 - 0x47 */ + DstReg|SrcMem|ModRM|Mov, DstReg|SrcMem|ModRM|Mov, + DstReg|SrcMem|ModRM|Mov, DstReg|SrcMem|ModRM|Mov, + DstReg|SrcMem|ModRM|Mov, DstReg|SrcMem|ModRM|Mov, + DstReg|SrcMem|ModRM|Mov, DstReg|SrcMem|ModRM|Mov, + /* 0x48 - 0x4F */ + DstReg|SrcMem|ModRM|Mov, DstReg|SrcMem|ModRM|Mov, + DstReg|SrcMem|ModRM|Mov, DstReg|SrcMem|ModRM|Mov, + DstReg|SrcMem|ModRM|Mov, DstReg|SrcMem|ModRM|Mov, + DstReg|SrcMem|ModRM|Mov, DstReg|SrcMem|ModRM|Mov, + /* 0x50 - 0x5F */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + /* 0x60 - 0x6F */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + /* 0x70 - 0x7F */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + /* 0x80 - 0x8F */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + /* 0x90 - 0x9F */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + /* 0xA0 - 0xA7 */ + 0, 0, 0, DstMem|SrcReg|ModRM, 0, 0, 0, 0, + /* 0xA8 - 0xAF */ + 0, 0, 0, DstMem|SrcReg|ModRM, 0, 0, 0, 0, + /* 0xB0 - 0xB7 */ + ByteOp|DstMem|SrcReg|ModRM, DstMem|SrcReg|ModRM, 0, DstMem|SrcReg|ModRM, + 0, 0, 0, 0, + /* 0xB8 - 0xBF */ + 0, 0, DstMem|SrcImmByte|ModRM, DstMem|SrcReg|ModRM, 0, 0, 0, 0, + /* 0xC0 - 0xCF */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + /* 0xD0 - 0xDF */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + /* 0xE0 - 0xEF */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + /* 0xF0 - 0xFF */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +}; + +/* Type, address-of, and value of an instruction's operand. */ +struct operand { + enum { OP_REG, OP_MEM, OP_IMM } type; + unsigned int bytes; + unsigned long val, orig_val, *ptr; +}; + +/* EFLAGS bit definitions. */ +#define EFLG_OF (1<<11) +#define EFLG_DF (1<<10) +#define EFLG_SF (1<<7) +#define EFLG_ZF (1<<6) +#define EFLG_AF (1<<4) +#define EFLG_PF (1<<2) +#define EFLG_CF (1<<0) + +/* + * Instruction emulation: + * Most instructions are emulated directly via a fragment of inline assembly + * code. This allows us to save/restore EFLAGS and thus very easily pick up + * any modified flags. + */ + +#if defined(__x86_64__) +#define _LO32 "k" /* force 32-bit operand */ +#define _STK "%%rsp" /* stack pointer */ +#elif defined(__i386__) +#define _LO32 "" /* force 32-bit operand */ +#define _STK "%%esp" /* stack pointer */ +#endif + +/* + * These EFLAGS bits are restored from saved value during emulation, and + * any changes are written back to the saved value after emulation. + */ +#define EFLAGS_MASK (EFLG_OF|EFLG_SF|EFLG_ZF|EFLG_AF|EFLG_PF|EFLG_CF) + +/* Before executing instruction: restore necessary bits in EFLAGS. */ +/* EFLAGS = (_sav & _msk) | (EFLAGS & ~_msk); _sav &= ~msk; */ +#define _PRE_EFLAGS(_sav, _msk, _tmp) \ +"push %"_sav"; " \ +"movl %"_msk",%"_LO32 _tmp"; " \ +"andl %"_LO32 _tmp",("_STK"); " \ +"notl %"_LO32 _tmp"; " \ +"andl %"_LO32 _tmp",%"_sav"; " \ +"pushf; " \ +"andl %"_LO32 _tmp",("_STK"); " \ +"pop %"_tmp"; " \ +"orl %"_LO32 _tmp",("_STK"); " \ +"popf; " + +/* After executing instruction: write-back necessary bits in EFLAGS. */ +/* _sav |= EFLAGS & _msk; */ +#define _POST_EFLAGS(_sav, _msk, _tmp) \ +"pushf; " \ +"pop %"_tmp"; " \ +"andl %"_msk",%"_LO32 _tmp"; " \ +"orl %"_LO32 _tmp",%"_sav"; " + +/* Raw emulation: instruction has two explicit operands. */ +#define __emulate_2op_nobyte(_op,_src,_dst,_eflags,_wx,_wy,_lx,_ly,_qx,_qy)\ +do{ unsigned long _tmp; \ + switch ( (_dst).bytes ) \ + { \ + case 2: \ + __asm__ __volatile__ ( \ + _PRE_EFLAGS("0","4","2") \ + _op"w %"_wx"3,%1; " \ + _POST_EFLAGS("0","4","2") \ + : "=m" (_eflags), "=m" ((_dst).val), "=&r" (_tmp) \ + : _wy ((_src).val), "i" (EFLAGS_MASK) ); \ + break; \ + case 4: \ + __asm__ __volatile__ ( \ + _PRE_EFLAGS("0","4","2") \ + _op"l %"_lx"3,%1; " \ + _POST_EFLAGS("0","4","2") \ + : "=m" (_eflags), "=m" ((_dst).val), "=&r" (_tmp) \ + : _ly ((_src).val), "i" (EFLAGS_MASK) ); \ + break; \ + case 8: \ + __emulate_2op_8byte(_op, _src, _dst, _eflags, _qx, _qy); \ + break; \ + } \ +} while (0) +#define __emulate_2op(_op,_src,_dst,_eflags,_bx,_by,_wx,_wy,_lx,_ly,_qx,_qy)\ +do{ unsigned long _tmp; \ + switch ( (_dst).bytes ) \ + { \ + case 1: \ + __asm__ __volatile__ ( \ + _PRE_EFLAGS("0","4","2") \ + _op"b %"_bx"3,%1; " \ + _POST_EFLAGS("0","4","2") \ + : "=m" (_eflags), "=m" ((_dst).val), "=&r" (_tmp) \ + : _by ((_src).val), "i" (EFLAGS_MASK) ); \ + break; \ + default: \ + __emulate_2op_nobyte(_op,_src,_dst,_eflags,_wx,_wy,_lx,_ly,_qx,_qy);\ + break; \ + } \ +} while (0) +/* Source operand is byte-sized and may be restricted to just %cl. */ +#define emulate_2op_SrcB(_op, _src, _dst, _eflags) \ + __emulate_2op(_op, _src, _dst, _eflags, \ + "b", "c", "b", "c", "b", "c", "b", "c") +/* Source operand is byte, word, long or quad sized. */ +#define emulate_2op_SrcV(_op, _src, _dst, _eflags) \ + __emulate_2op(_op, _src, _dst, _eflags, \ + "b", "q", "w", "r", _LO32, "r", "", "r") +/* Source operand is word, long or quad sized. */ +#define emulate_2op_SrcV_nobyte(_op, _src, _dst, _eflags) \ + __emulate_2op_nobyte(_op, _src, _dst, _eflags, \ + "w", "r", _LO32, "r", "", "r") + +/* Instruction has only one explicit operand (no source operand). */ +#define emulate_1op(_op,_dst,_eflags) \ +do{ unsigned long _tmp; \ + switch ( (_dst).bytes ) \ + { \ + case 1: \ + __asm__ __volatile__ ( \ + _PRE_EFLAGS("0","3","2") \ + _op"b %1; " \ + _POST_EFLAGS("0","3","2") \ + : "=m" (_eflags), "=m" ((_dst).val), "=&r" (_tmp) \ + : "i" (EFLAGS_MASK) ); \ + break; \ + case 2: \ + __asm__ __volatile__ ( \ + _PRE_EFLAGS("0","3","2") \ + _op"w %1; " \ + _POST_EFLAGS("0","3","2") \ + : "=m" (_eflags), "=m" ((_dst).val), "=&r" (_tmp) \ + : "i" (EFLAGS_MASK) ); \ + break; \ + case 4: \ + __asm__ __volatile__ ( \ + _PRE_EFLAGS("0","3","2") \ + _op"l %1; " \ + _POST_EFLAGS("0","3","2") \ + : "=m" (_eflags), "=m" ((_dst).val), "=&r" (_tmp) \ + : "i" (EFLAGS_MASK) ); \ + break; \ + case 8: \ + __emulate_1op_8byte(_op, _dst, _eflags); \ + break; \ + } \ +} while (0) + +/* Emulate an instruction with quadword operands (x86/64 only). */ +#if defined(__x86_64__) +#define __emulate_2op_8byte(_op, _src, _dst, _eflags, _qx, _qy) \ +do{ __asm__ __volatile__ ( \ + _PRE_EFLAGS("0","4","2") \ + _op"q %"_qx"3,%1; " \ + _POST_EFLAGS("0","4","2") \ + : "=m" (_eflags), "=m" ((_dst).val), "=&r" (_tmp) \ + : _qy ((_src).val), "i" (EFLAGS_MASK) ); \ +} while (0) +#define __emulate_1op_8byte(_op, _dst, _eflags) \ +do{ __asm__ __volatile__ ( \ + _PRE_EFLAGS("0","3","2") \ + _op"q %1; " \ + _POST_EFLAGS("0","3","2") \ + : "=m" (_eflags), "=m" ((_dst).val), "=&r" (_tmp) \ + : "i" (EFLAGS_MASK) ); \ +} while (0) +#elif defined(__i386__) +#define __emulate_2op_8byte(_op, _src, _dst, _eflags, _qx, _qy) +#define __emulate_1op_8byte(_op, _dst, _eflags) +#endif /* __i386__ */ + +/* Fetch next part of the instruction being emulated. */ +#define insn_fetch(_type, _size, _eip) \ +({ unsigned long _x; \ + if ( ops->read_std((unsigned long)(_eip), &_x, (_size)) ) \ + goto done; \ + (_eip) += (_size); \ + (_type)_x; \ +}) + +#define DPRINTF(_f, _a...) printf( _f , ## _a ) + +void * +decode_register( + u8 modrm_reg, struct xen_regs *regs, int highbyte_regs) +{ + void *p; + + switch ( modrm_reg ) + { + case 0: p = ®s->eax; break; + case 1: p = ®s->ecx; break; + case 2: p = ®s->edx; break; + case 3: p = ®s->ebx; break; + case 4: p = (highbyte_regs ? + ((unsigned char *)®s->eax + 1) : + (unsigned char *)®s->esp); break; + case 5: p = (highbyte_regs ? + ((unsigned char *)®s->ecx + 1) : + (unsigned char *)®s->ebp); break; + case 6: p = (highbyte_regs ? + ((unsigned char *)®s->edx + 1) : + (unsigned char *)®s->esi); break; + case 7: p = (highbyte_regs ? + ((unsigned char *)®s->ebx + 1) : + (unsigned char *)®s->edi); break; +#if defined(__x86_64__) + case 8: p = ®s->r8; break; + case 9: p = ®s->r9; break; + case 10: p = ®s->r10; break; + case 11: p = ®s->r11; break; + case 12: p = ®s->r12; break; + case 13: p = ®s->r13; break; + case 14: p = ®s->r14; break; + case 15: p = ®s->r15; break; +#endif + default: p = NULL; break; + } + + return p; +} + +int +x86_emulate_memop( + struct xen_regs *regs, + unsigned long cr2, + struct x86_mem_emulator *ops, + int mode) +{ + u8 b, d, sib, twobyte = 0, rex_prefix = 0; + u8 modrm, modrm_mod = 0, modrm_reg = 0, modrm_rm = 0; + unsigned int op_bytes = (mode == 8) ? 4 : mode, ad_bytes = mode; + unsigned int lock_prefix = 0, rep_prefix = 0; + struct operand src, dst; + + /* Shadow copy of register state. Committed on successful emulation. */ + struct xen_regs _regs = *regs; + + /* Legacy prefixes. */ + next_prefix: + switch ( b = insn_fetch(u8, 1, _regs.eip) ) + { + case 0x66: /* operand-size override */ + op_bytes ^= 6; /* switch between 2/4 bytes */ + goto next_prefix; + case 0x67: /* address-size override */ + ad_bytes ^= (mode == 8) ? 12 : 6; /* switch between 2/4 or 4/8 bytes */ + goto next_prefix; + case 0x2e: /* CS override */ + case 0x3e: /* DS override */ + case 0x26: /* ES override */ + case 0x64: /* FS override */ + case 0x65: /* GS override */ + case 0x36: /* SS override */ + DPRINTF("Warning: ignoring a segment override. Probably okay. :-)\n"); + goto next_prefix; + case 0xf0: /* LOCK */ + lock_prefix = 1; + goto next_prefix; + case 0xf3: /* REP/REPE/REPZ */ + rep_prefix = 1; + goto next_prefix; + case 0xf2: /* REPNE/REPNZ */ + goto next_prefix; + } + + if ( ad_bytes == 2 ) + { + DPRINTF("Cannot parse 16-bit effective addresses.\n"); + goto cannot_emulate; + } + + /* REX prefix. */ + if ( (mode == 8) && ((b & 0xf0) == 0x40) ) + { + rex_prefix = b; + if ( b & 8 ) + op_bytes = 8; /* REX.W */ + modrm_reg = (b & 4) << 1; /* REX.R */ + /* REX.B and REX.X do not need to be decoded. */ + b = insn_fetch(u8, 1, _regs.eip); + } + + /* Opcode byte(s). */ + d = opcode_table[b]; + if ( d == 0 ) + { + /* Two-byte opcode? */ + if ( b == 0x0f ) + { + twobyte = 1; + b = insn_fetch(u8, 1, _regs.eip); + d = twobyte_table[b]; + } + + /* Unrecognised? */ + if ( d == 0 ) + goto cannot_emulate; + } + + /* ModRM and SIB bytes. */ + if ( d & ModRM ) + { + modrm = insn_fetch(u8, 1, _regs.eip); + modrm_mod |= (modrm & 0xc0) >> 6; + modrm_reg |= (modrm & 0x38) >> 3; + modrm_rm |= (modrm & 0x07); + switch ( modrm_mod ) + { + case 0: + if ( (modrm_rm == 4) && + (((sib = insn_fetch(u8, 1, _regs.eip)) & 7) == 5) ) + _regs.eip += 4; /* skip disp32 specified by SIB.base */ + else if ( modrm_rm == 5 ) + _regs.eip += 4; /* skip disp32 */ + break; + case 1: + if ( modrm_rm == 4 ) + sib = insn_fetch(u8, 1, _regs.eip); + _regs.eip += 1; /* skip disp8 */ + break; + case 2: + if ( modrm_rm == 4 ) + sib = insn_fetch(u8, 1, _regs.eip); + _regs.eip += 4; /* skip disp32 */ + break; + case 3: + DPRINTF("Cannot parse ModRM.mod == 3.\n"); + goto cannot_emulate; + } + } + + /* Decode and fetch the destination operand: register or memory. */ + switch ( d & DstMask ) + { + case ImplicitOps: + /* Special instructions do their own operand decoding. */ + goto special_insn; + case DstReg: + dst.type = OP_REG; + if ( d & ByteOp ) + { + dst.ptr = decode_register(modrm_reg, &_regs, (rex_prefix == 0)); + dst.val = *(u8 *)dst.ptr; + dst.bytes = 1; + } + else + { + dst.ptr = decode_register(modrm_reg, &_regs, 0); + switch ( (dst.bytes = op_bytes) ) + { + case 2: dst.val = *(u16 *)dst.ptr; break; + case 4: dst.val = *(u32 *)dst.ptr; break; + case 8: dst.val = *(u64 *)dst.ptr; break; + } + } + break; + case DstMem: + dst.type = OP_MEM; + dst.ptr = (unsigned long *)cr2; + dst.bytes = (d & ByteOp) ? 1 : op_bytes; + if ( !(d & Mov) && /* optimisation - avoid slow emulated read */ + ops->read_emulated((unsigned long)dst.ptr, &dst.val, dst.bytes) ) + goto done; + break; + } + dst.orig_val = dst.val; + + /* Decode and fetch the source operand: register, memory or immediate. */ + switch ( d & SrcMask ) + { + case SrcNone: + break; + case SrcReg: + src.type = OP_REG; + if ( d & ByteOp ) + { + src.ptr = decode_register(modrm_reg, &_regs, (rex_prefix == 0)); + src.val = src.orig_val = *(u8 *)src.ptr; + src.bytes = 1; + } + else + { + src.ptr = decode_register(modrm_reg, &_regs, 0); + switch ( (src.bytes = op_bytes) ) + { + case 2: src.val = src.orig_val = *(u16 *)src.ptr; break; + case 4: src.val = src.orig_val = *(u32 *)src.ptr; break; + case 8: src.val = src.orig_val = *(u64 *)src.ptr; break; + } + } + break; + case SrcMem: + src.type = OP_MEM; + src.ptr = (unsigned long *)cr2; + src.bytes = (d & ByteOp) ? 1 : op_bytes; + if ( ops->read_emulated((unsigned long)src.ptr, &src.val, src.bytes) ) + goto done; + src.orig_val = src.val; + break; + case SrcImm: + src.type = OP_IMM; + src.ptr = (unsigned long *)_regs.eip; + src.bytes = (d & ByteOp) ? 1 : op_bytes; + if ( src.bytes == 8 ) src.bytes = 4; + /* NB. Immediates are sign-extended as necessary. */ + switch ( src.bytes ) + { + case 1: src.val = insn_fetch(s8, 1, _regs.eip); break; + case 2: src.val = insn_fetch(s16, 2, _regs.eip); break; + case 4: src.val = insn_fetch(s32, 4, _regs.eip); break; + } + break; + case SrcImmByte: + src.type = OP_IMM; + src.ptr = (unsigned long *)_regs.eip; + src.bytes = 1; + src.val = insn_fetch(s8, 1, _regs.eip); + break; + } + + if ( twobyte ) + goto twobyte_insn; + + switch ( b ) + { + case 0x00 ... 0x05: add: /* add */ + emulate_2op_SrcV("add", src, dst, _regs.eflags); + break; + case 0x08 ... 0x0d: or: /* or */ + emulate_2op_SrcV("or", src, dst, _regs.eflags); + break; + case 0x10 ... 0x15: adc: /* adc */ + emulate_2op_SrcV("adc", src, dst, _regs.eflags); + break; + case 0x18 ... 0x1d: sbb: /* sbb */ + emulate_2op_SrcV("sbb", src, dst, _regs.eflags); + break; + case 0x20 ... 0x25: and: /* and */ + emulate_2op_SrcV("and", src, dst, _regs.eflags); + break; + case 0x28 ... 0x2d: sub: /* sub */ + emulate_2op_SrcV("sub", src, dst, _regs.eflags); + break; + case 0x30 ... 0x35: xor: /* xor */ + emulate_2op_SrcV("xor", src, dst, _regs.eflags); + break; + case 0x38 ... 0x3d: cmp: /* cmp */ + emulate_2op_SrcV("cmp", src, dst, _regs.eflags); + break; + case 0x80 ... 0x83: /* Grp1 */ + switch ( modrm_reg ) + { + case 0: goto add; + case 1: goto or; + case 2: goto adc; + case 3: goto sbb; + case 4: goto and; + case 5: goto sub; + case 6: goto xor; + case 7: goto cmp; + } + break; + case 0x84 ... 0x85: test: /* test */ + emulate_2op_SrcV("test", src, dst, _regs.eflags); + break; + case 0x86 ... 0x87: /* xchg */ + src.val ^= dst.val; + dst.val ^= src.val; + src.val ^= dst.val; + break; + case 0xa0 ... 0xa1: /* mov */ + dst.ptr = (unsigned long *)&_regs.eax; + dst.val = src.val; + _regs.eip += ad_bytes; /* skip src displacement */ + break; + case 0xa2 ... 0xa3: /* mov */ + dst.val = (unsigned long)_regs.eax; + _regs.eip += ad_bytes; /* skip dst displacement */ + break; + case 0x88 ... 0x8b: /* mov */ + case 0xc6 ... 0xc7: /* mov (sole member of Grp11) */ + dst.val = src.val; + break; + case 0x8f: /* pop (sole member of Grp1a) */ + /* 64-bit mode: POP defaults to 64-bit operands. */ + if ( (mode == 8) && (dst.bytes == 4) ) + dst.bytes = 8; + if ( ops->read_std(_regs.esp, &dst.val, dst.bytes) ) + goto done; + _regs.esp += dst.bytes; + break; + case 0xc0 ... 0xc1: grp2: /* Grp2 */ + switch ( modrm_reg ) + { + case 0: /* rol */ + emulate_2op_SrcB("rol", src, dst, _regs.eflags); + break; + case 1: /* ror */ + emulate_2op_SrcB("ror", src, dst, _regs.eflags); + break; + case 2: /* rcl */ + emulate_2op_SrcB("rcl", src, dst, _regs.eflags); + break; + case 3: /* rcr */ + emulate_2op_SrcB("rcr", src, dst, _regs.eflags); + break; + case 4: /* sal/shl */ + case 6: /* sal/shl */ + emulate_2op_SrcB("sal", src, dst, _regs.eflags); + break; + case 5: /* shr */ + emulate_2op_SrcB("shr", src, dst, _regs.eflags); + break; + case 7: /* sar */ + emulate_2op_SrcB("sar", src, dst, _regs.eflags); + break; + } + break; + case 0xd0 ... 0xd1: /* Grp2 */ + src.val = 1; + goto grp2; + case 0xd2 ... 0xd3: /* Grp2 */ + src.val = _regs.ecx; + goto grp2; + case 0xf6 ... 0xf7: /* Grp3 */ + switch ( modrm_reg ) + { + case 0 ... 1: /* test */ + /* Special case in Grp3: test has an immediate source operand. */ + src.type = OP_IMM; + src.ptr = (unsigned long *)_regs.eip; + src.bytes = (d & ByteOp) ? 1 : op_bytes; + if ( src.bytes == 8 ) src.bytes = 4; + switch ( src.bytes ) + { + case 1: src.val = insn_fetch(s8, 1, _regs.eip); break; + case 2: src.val = insn_fetch(s16, 2, _regs.eip); break; + case 4: src.val = insn_fetch(s32, 4, _regs.eip); break; + } + goto test; + case 2: /* not */ + dst.val = ~dst.val; + break; + case 3: /* neg */ + emulate_1op("neg", dst, _regs.eflags); + break; + default: + goto cannot_emulate; + } + break; + case 0xfe ... 0xff: /* Grp4/Grp5 */ + switch ( modrm_reg ) + { + case 0: /* inc */ + emulate_1op("inc", dst, _regs.eflags); + break; + case 1: /* dec */ + emulate_1op("dec", dst, _regs.eflags); + break; + case 6: /* push */ + /* 64-bit mode: PUSH defaults to 64-bit operands. */ + if ( (mode == 8) && (dst.bytes == 4) ) + { + dst.bytes = 8; + if ( ops->read_std((unsigned long)dst.ptr, &dst.val, 8) ) + goto done; + } + _regs.esp -= dst.bytes; + if ( ops->write_std(_regs.esp, dst.val, dst.bytes) ) + goto done; + dst.val = dst.orig_val; /* skanky: disable writeback */ + break; + default: + goto cannot_emulate; + } + break; + } + + writeback: + if ( (d & Mov) || (dst.orig_val != dst.val) ) + { + switch ( dst.type ) + { + case OP_REG: + /* The 4-byte case *is* correct: in 64-bit mode we zero-extend. */ + switch ( dst.bytes ) + { + case 1: *(u8 *)dst.ptr = (u8)dst.val; break; + case 2: *(u16 *)dst.ptr = (u16)dst.val; break; + case 4: *dst.ptr = (u32)dst.val; break; /* 64b mode: zero-extend */ + case 8: *dst.ptr = dst.val; break; + } + break; + case OP_MEM: + if ( lock_prefix ) + { + unsigned long seen; + if ( ops->cmpxchg_emulated((unsigned long)dst.ptr, + dst.orig_val, dst.val, + &seen, dst.bytes) ) + goto done; + if ( seen != dst.orig_val ) + goto done; /* Try again... */ + } + else + { + if ( ops->write_emulated((unsigned long)dst.ptr, + dst.val, dst.bytes) ) + goto done; + } + break; + default: + break; + } + } + + /* Commit shadow register state. */ + *regs = _regs; + + done: + return 0; + + special_insn: + if ( twobyte ) + goto twobyte_special_insn; + if ( rep_prefix ) + { + if ( _regs.ecx == 0 ) + { + regs->eip = _regs.eip; + goto done; + } + _regs.ecx--; + _regs.eip = regs->eip; + } + switch ( b ) + { + case 0xa4 ... 0xa5: /* movs */ + dst.type = OP_MEM; + dst.bytes = (d & ByteOp) ? 1 : op_bytes; + if ( _regs.error_code & 2 ) + { + /* Write fault: destination is special memory. */ + dst.ptr = (unsigned long *)cr2; + if ( ops->read_std(_regs.esi - _regs.edi + cr2, + &dst.val, dst.bytes) ) + goto done; + } + else + { + /* Read fault: source is special memory. */ + dst.ptr = (unsigned long *)(_regs.edi - _regs.esi + cr2); + if ( ops->read_emulated(cr2, &dst.val, dst.bytes) ) + goto done; + } + _regs.esi += (_regs.eflags & EFLG_DF) ? -dst.bytes : dst.bytes; + _regs.edi += (_regs.eflags & EFLG_DF) ? -dst.bytes : dst.bytes; + break; + case 0xa6 ... 0xa7: /* cmps */ + DPRINTF("Urk! I don't handle CMPS.\n"); + goto cannot_emulate; + case 0xaa ... 0xab: /* stos */ + dst.type = OP_MEM; + dst.bytes = (d & ByteOp) ? 1 : op_bytes; + dst.ptr = (unsigned long *)cr2; + dst.val = _regs.eax; + _regs.edi += (_regs.eflags & EFLG_DF) ? -dst.bytes : dst.bytes; + break; + case 0xac ... 0xad: /* lods */ + dst.type = OP_REG; + dst.bytes = (d & ByteOp) ? 1 : op_bytes; + dst.ptr = (unsigned long *)&_regs.eax; + if ( ops->read_emulated(cr2, &dst.val, dst.bytes) ) + goto done; + _regs.esi += (_regs.eflags & EFLG_DF) ? -dst.bytes : dst.bytes; + break; + case 0xae ... 0xaf: /* scas */ + DPRINTF("Urk! I don't handle SCAS.\n"); + goto cannot_emulate; + } + goto writeback; + + twobyte_insn: + switch ( b ) + { + case 0x40 ... 0x4f: /* cmov */ + dst.val = dst.orig_val = src.val; + d &= ~Mov; /* default to no move */ + /* First, assume we're decoding an even cmov opcode (lsb == 0). */ + switch ( (b & 15) >> 1 ) + { + case 0: /* cmovo */ + d |= (_regs.eflags & EFLG_OF) ? Mov : 0; + break; + case 1: /* cmovb/cmovc/cmovnae */ + d |= (_regs.eflags & EFLG_CF) ? Mov : 0; + break; + case 2: /* cmovz/cmove */ + d |= (_regs.eflags & EFLG_ZF) ? Mov : 0; + break; + case 3: /* cmovbe/cmovna */ + d |= (_regs.eflags & (EFLG_CF|EFLG_ZF)) ? Mov : 0; + break; + case 4: /* cmovs */ + d |= (_regs.eflags & EFLG_SF) ? Mov : 0; + break; + case 5: /* cmovp/cmovpe */ + d |= (_regs.eflags & EFLG_PF) ? Mov : 0; + break; + case 7: /* cmovle/cmovng */ + d |= (_regs.eflags & EFLG_ZF) ? Mov : 0; + /* fall through */ + case 6: /* cmovl/cmovnge */ + d |= (!(_regs.eflags & EFLG_SF) != !(_regs.eflags & EFLG_OF)) ? + Mov : 0; + break; + } + /* Odd cmov opcodes (lsb == 1) have inverted sense. */ + d ^= (b & 1) ? Mov : 0; + break; + case 0xb0 ... 0xb1: /* cmpxchg */ + /* Save real source value, then compare EAX against destination. */ + src.orig_val = src.val; + src.val = _regs.eax; + emulate_2op_SrcV("cmp", src, dst, _regs.eflags); + /* Always write back. The question is: where to? */ + d |= Mov; + if ( _regs.eflags & EFLG_ZF ) + { + /* Success: write back to memory. */ + dst.val = src.orig_val; + } + else + { + /* Failure: write the value we saw to EAX. */ + dst.type = OP_REG; + dst.ptr = (unsigned long *)&_regs.eax; + } + break; + case 0xa3: bt: /* bt */ + src.val &= (1UL << (1 << dst.bytes)) - 1; /* only subword offset */ + emulate_2op_SrcV_nobyte("bt", src, dst, _regs.eflags); + break; + case 0xb3: btr: /* btr */ + src.val &= (1UL << (1 << dst.bytes)) - 1; /* only subword offset */ + emulate_2op_SrcV_nobyte("btr", src, dst, _regs.eflags); + break; + case 0xab: bts: /* bts */ + src.val &= (1UL << (1 << dst.bytes)) - 1; /* only subword offset */ + emulate_2op_SrcV_nobyte("bts", src, dst, _regs.eflags); + break; + case 0xbb: btc: /* btc */ + src.val &= (1UL << (1 << dst.bytes)) - 1; /* only subword offset */ + emulate_2op_SrcV_nobyte("btc", src, dst, _regs.eflags); + break; + case 0xba: /* Grp8 */ + switch ( modrm_reg >> 1 ) + { + case 0: goto bt; + case 1: goto bts; + case 2: goto btr; + case 3: goto btc; + } + break; + } + goto writeback; + + twobyte_special_insn: + /* Only prefetch instructions get here, so nothing to do. */ + dst.orig_val = dst.val; /* disable writeback */ + goto writeback; + + cannot_emulate: + DPRINTF("Cannot emulate %02x\n", b); + return -1; +} diff --git a/xen/include/asm-x86/x86_emulate.h b/xen/include/asm-x86/x86_emulate.h new file mode 100644 index 0000000000..fc2301d376 --- /dev/null +++ b/xen/include/asm-x86/x86_emulate.h @@ -0,0 +1,131 @@ +/****************************************************************************** + * x86_emulate.h + * + * Generic x86 (32-bit and 64-bit) instruction decoder and emulator. + * + * Copyright (c) 2005 Keir Fraser + */ + +#ifndef __X86_EMULATE_H__ +#define __X86_EMULATE_H__ + +/* + * x86_mem_emulator: + * + * These operations represent the instruction emulator's interface to memory. + * There are two categories of operation: those that act on ordinary memory + * regions (*_std), and those that act on memory regions known to require + * special treatment or emulation (*_emulated). + * + * The emulator assumes that an instruction accesses only one 'emulated memory' + * location, and that this is one of its data operands. Instruction fetches and + * stack operations are assumed never to access emulated memory. The emulator + * automatically deduces which operand of a string-move operation is accessing + * emulated memory, and requires that the other operand accesses normal memory. + * + * NOTES: + * 1. The emulator isn't very smart about emulated vs. standard memory. + * 'Emulated memory' access addresses should be checked for sanity. + * 'Normal memory' accesses may fault, and the caller must arrange to + * detect and handle reentrancy into the emulator via recursive faults. + * Accesses may be unaligned and may cross page boundaries. + * 2. If the access fails (cannot emulate, or a standard access faults) then + * it is up to the memop to propagate the fault to the guest VM via + * some out-of-band mechanism, unknown to the emulator. The memop signals + * failure by returning a non-zero value to the emulator, which will then + * immediately bail. + */ +struct x86_mem_emulator +{ + /* + * read_std: Read bytes of standard (non-emulated/special) memory. + * Used for instruction fetch, stack operations, and others. + * @addr: [IN ] Linear address from which to read. + * @val: [OUT] Value read from memory, zero-extended to 'u_long'. + * @bytes: [IN ] Number of bytes to read from memory. + */ + int (*read_std)( + unsigned long addr, + unsigned long *val, + unsigned int bytes); + + /* + * write_std: Write bytes of standard (non-emulated/special) memory. + * Used for stack operations, and others. + * @addr: [IN ] Linear address to which to write. + * @val: [IN ] Value to write to memory (low-order bytes used as req'd). + * @bytes: [IN ] Number of bytes to write to memory. + */ + int (*write_std)( + unsigned long addr, + unsigned long val, + unsigned int bytes); + + /* + * read_emulated: Read bytes from emulated/special memory area. + * @addr: [IN ] Linear address from which to read. + * @val: [OUT] Value read from memory, zero-extended to 'u_long'. + * @bytes: [IN ] Number of bytes to read from memory. + */ + int (*read_emulated)( + unsigned long addr, + unsigned long *val, + unsigned int bytes); + + /* + * write_emulated: Read bytes from emulated/special memory area. + * @addr: [IN ] Linear address to which to write. + * @val: [IN ] Value to write to memory (low-order bytes used as req'd). + * @bytes: [IN ] Number of bytes to write to memory. + */ + int (*write_emulated)( + unsigned long addr, + unsigned long val, + unsigned int bytes); + + /* + * cmpxchg_emulated: Emulate an atomic (LOCKed) CMPXCHG operation on an + * emulated/special memory area. + * @addr: [IN ] Linear address to access. + * @old: [IN ] Value expected to be current at @addr. + * @new: [IN ] Value to write to @addr. + * @seen: [OUT] Value actually seen at @addr, zero-extended to 'u_long'. + * @bytes: [IN ] Number of bytes to access using CMPXCHG. + */ + int (*cmpxchg_emulated)( + unsigned long addr, + unsigned long old, + unsigned long new, + unsigned long *seen, + unsigned int bytes); +}; + + +struct xen_regs; + +/* + * x86_emulate_memop: Emulate an instruction that faulted attempting to + * read/write a 'special' memory area. + * @regs: Register state at time of fault. + * @cr2: Linear faulting address. + * @ops: Interface to access special memory. + * @mode: Current execution mode, represented by the default size of memory + * addresses, in bytes. Valid values are 2, 4 and 8 (x86/64 only). + */ +extern int +x86_emulate_memop( + struct xen_regs *regs, + unsigned long cr2, + struct x86_mem_emulator *ops, + int mode); + +/* + * Given the 'reg' portion of a ModRM byte, and a register block, return a + * pointer into the block that addresses the relevant register. + * @highbyte_regs specifies whether to decode AH,CH,DH,BH. + */ +extern void * +decode_register( + u8 modrm_reg, struct xen_regs *regs, int highbyte_regs); + +#endif /* __X86_EMULATE_H__ */