[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-changelog] [xen-unstable] x86_emulate: Support most common segment load/save instructions.
# HG changeset patch # User Keir Fraser <keir.fraser@xxxxxxxxxx> # Date 1195940419 0 # Node ID d5c3961288970acd963855b12c84ede7d8ebabfc # Parent 2e7fcea74cb1117640c7ba6a2152d42223335259 x86_emulate: Support most common segment load/save instructions. Signed-off-by: Keir Fraser <keir.fraser@xxxxxxxxxx> --- xen/arch/x86/x86_emulate.c | 223 +++++++++++++++++++++++++++++++++++-- xen/include/asm-x86/hvm/hvm.h | 30 ---- xen/include/asm-x86/hvm/svm/vmcb.h | 2 xen/include/asm-x86/x86_emulate.h | 53 ++++++++ 4 files changed, 264 insertions(+), 44 deletions(-) diff -r 2e7fcea74cb1 -r d5c396128897 xen/arch/x86/x86_emulate.c --- a/xen/arch/x86/x86_emulate.c Sat Nov 24 16:16:57 2007 +0000 +++ b/xen/arch/x86/x86_emulate.c Sat Nov 24 21:40:19 2007 +0000 @@ -60,19 +60,19 @@ static uint8_t opcode_table[256] = { /* 0x00 - 0x07 */ ByteOp|DstMem|SrcReg|ModRM, DstMem|SrcReg|ModRM, ByteOp|DstReg|SrcMem|ModRM, DstReg|SrcMem|ModRM, - ByteOp|DstReg|SrcImm, DstReg|SrcImm, 0, 0, + ByteOp|DstReg|SrcImm, DstReg|SrcImm, ImplicitOps, ImplicitOps, /* 0x08 - 0x0F */ ByteOp|DstMem|SrcReg|ModRM, DstMem|SrcReg|ModRM, ByteOp|DstReg|SrcMem|ModRM, DstReg|SrcMem|ModRM, - ByteOp|DstReg|SrcImm, DstReg|SrcImm, 0, 0, + ByteOp|DstReg|SrcImm, DstReg|SrcImm, ImplicitOps, 0, /* 0x10 - 0x17 */ ByteOp|DstMem|SrcReg|ModRM, DstMem|SrcReg|ModRM, ByteOp|DstReg|SrcMem|ModRM, DstReg|SrcMem|ModRM, - ByteOp|DstReg|SrcImm, DstReg|SrcImm, 0, 0, + ByteOp|DstReg|SrcImm, DstReg|SrcImm, ImplicitOps, ImplicitOps, /* 0x18 - 0x1F */ ByteOp|DstMem|SrcReg|ModRM, DstMem|SrcReg|ModRM, ByteOp|DstReg|SrcMem|ModRM, DstReg|SrcMem|ModRM, - ByteOp|DstReg|SrcImm, DstReg|SrcImm, 0, 0, + ByteOp|DstReg|SrcImm, DstReg|SrcImm, ImplicitOps, ImplicitOps, /* 0x20 - 0x27 */ ByteOp|DstMem|SrcReg|ModRM, DstMem|SrcReg|ModRM, ByteOp|DstReg|SrcMem|ModRM, DstReg|SrcMem|ModRM, @@ -120,7 +120,8 @@ static uint8_t opcode_table[256] = { /* 0x88 - 0x8F */ ByteOp|DstMem|SrcReg|ModRM|Mov, DstMem|SrcReg|ModRM|Mov, ByteOp|DstReg|SrcMem|ModRM|Mov, DstReg|SrcMem|ModRM|Mov, - 0, DstReg|SrcNone|ModRM, 0, DstMem|SrcNone|ModRM|Mov, + DstMem|SrcReg|ModRM|Mov, DstReg|SrcNone|ModRM, + DstReg|SrcMem|ModRM|Mov, DstMem|SrcNone|ModRM|Mov, /* 0x90 - 0x97 */ ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps, @@ -158,7 +159,7 @@ static uint8_t opcode_table[256] = { ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps, /* 0xE8 - 0xEF */ - ImplicitOps, ImplicitOps, 0, ImplicitOps, + ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps, /* 0xF0 - 0xF7 */ 0, 0, 0, 0, @@ -170,7 +171,7 @@ static uint8_t opcode_table[256] = { static uint8_t twobyte_table[256] = { /* 0x00 - 0x07 */ - 0, 0, 0, 0, 0, ImplicitOps, 0, 0, + 0, ImplicitOps|ModRM, 0, 0, 0, ImplicitOps, 0, 0, /* 0x08 - 0x0F */ ImplicitOps, ImplicitOps, 0, 0, 0, ImplicitOps|ModRM, 0, 0, /* 0x10 - 0x17 */ @@ -220,9 +221,10 @@ static uint8_t twobyte_table[256] = { ByteOp|DstMem|SrcNone|ModRM|Mov, ByteOp|DstMem|SrcNone|ModRM|Mov, ByteOp|DstMem|SrcNone|ModRM|Mov, ByteOp|DstMem|SrcNone|ModRM|Mov, /* 0xA0 - 0xA7 */ - 0, 0, 0, DstBitBase|SrcReg|ModRM, 0, 0, 0, 0, + ImplicitOps, ImplicitOps, 0, DstBitBase|SrcReg|ModRM, 0, 0, 0, 0, /* 0xA8 - 0xAF */ - 0, 0, 0, DstBitBase|SrcReg|ModRM, 0, 0, 0, DstReg|SrcMem|ModRM, + ImplicitOps, ImplicitOps, 0, DstBitBase|SrcReg|ModRM, + 0, 0, 0, DstReg|SrcMem|ModRM, /* 0xB0 - 0xB7 */ ByteOp|DstMem|SrcReg|ModRM, DstMem|SrcReg|ModRM, 0, DstBitBase|SrcReg|ModRM, @@ -677,6 +679,45 @@ test_cc( return (!!rc ^ (condition & 1)); } +static int +in_realmode( + struct x86_emulate_ctxt *ctxt, + struct x86_emulate_ops *ops) +{ + unsigned long cr0; + int rc; + + if ( ops->read_cr == NULL ) + return 0; + + rc = ops->read_cr(0, &cr0, ctxt); + return (!rc && !(cr0 & 1)); +} + +static int +load_seg( + enum x86_segment seg, + uint16_t sel, + struct x86_emulate_ctxt *ctxt, + struct x86_emulate_ops *ops) +{ + struct segment_register reg; + int rc; + + if ( !in_realmode(ctxt, ops) || + (ops->read_segment == NULL) || + (ops->write_segment == NULL) ) + return X86EMUL_UNHANDLEABLE; + + if ( (rc = ops->read_segment(seg, ®, ctxt)) != 0 ) + return rc; + + reg.sel = sel; + reg.base = (uint32_t)sel << 4; + + return ops->write_segment(seg, ®, ctxt); +} + void * decode_register( uint8_t modrm_reg, struct cpu_user_regs *regs, int highbyte_regs) @@ -715,6 +756,24 @@ decode_register( } return p; +} + +#define decode_segment_failed x86_seg_tr +enum x86_segment +decode_segment( + uint8_t modrm_reg) +{ + switch ( modrm_reg ) + { + case 0: return x86_seg_es; + case 1: return x86_seg_cs; + case 2: return x86_seg_ss; + case 3: return x86_seg_ds; + case 4: return x86_seg_fs; + case 5: return x86_seg_gs; + default: break; + } + return decode_segment_failed; } int @@ -1205,6 +1264,7 @@ x86_emulate( dst.val = (dst.val & ~3) | (src_val & 3); else dst.type = OP_NONE; + generate_exception_if(in_realmode(ctxt, ops), EXC_UD); } break; @@ -1283,6 +1343,28 @@ x86_emulate( case 0x88 ... 0x8b: /* mov */ dst.val = src.val; break; + + case 0x8c: /* mov Sreg,r/m */ { + struct segment_register reg; + enum x86_segment seg = decode_segment(modrm_reg); + generate_exception_if(seg == decode_segment_failed, EXC_UD); + fail_if(ops->read_segment == NULL); + if ( (rc = ops->read_segment(seg, ®, ctxt)) != 0 ) + goto done; + dst.val = reg.sel; + if ( dst.type == OP_MEM ) + dst.bytes = 2; + break; + } + + case 0x8e: /* mov r/m,Sreg */ { + enum x86_segment seg = decode_segment(modrm_reg); + generate_exception_if(seg == decode_segment_failed, EXC_UD); + if ( (rc = load_seg(seg, (uint16_t)src.val, ctxt, ops)) != 0 ) + goto done; + dst.type = OP_NONE; + break; + } case 0x8d: /* lea */ dst.val = ea.mem.off; @@ -1657,6 +1739,56 @@ x86_emulate( switch ( b ) { + case 0x06: /* push %%es */ { + struct segment_register reg; + src.val = x86_seg_es; + push_seg: + fail_if(ops->read_segment == NULL); + if ( (rc = ops->read_segment(src.val, ®, ctxt)) != 0 ) + return rc; + /* 64-bit mode: PUSH defaults to a 64-bit operand. */ + if ( mode_64bit() && (op_bytes == 4) ) + op_bytes = 8; + if ( (rc = ops->write(x86_seg_ss, sp_pre_dec(op_bytes), + reg.sel, op_bytes, ctxt)) != 0 ) + goto done; + break; + } + + case 0x07: /* pop %%es */ + src.val = x86_seg_es; + pop_seg: + fail_if(ops->write_segment == NULL); + /* 64-bit mode: PUSH defaults to a 64-bit operand. */ + if ( mode_64bit() && (op_bytes == 4) ) + op_bytes = 8; + if ( (rc = ops->read(x86_seg_ss, sp_post_inc(op_bytes), + &dst.val, op_bytes, ctxt)) != 0 ) + goto done; + if ( (rc = load_seg(src.val, (uint16_t)dst.val, ctxt, ops)) != 0 ) + return rc; + break; + + case 0x0e: /* push %%cs */ + src.val = x86_seg_cs; + goto push_seg; + + case 0x16: /* push %%ss */ + src.val = x86_seg_ss; + goto push_seg; + + case 0x17: /* pop %%ss */ + src.val = x86_seg_ss; + goto pop_seg; + + case 0x1e: /* push %%ds */ + src.val = x86_seg_ds; + goto push_seg; + + case 0x1f: /* pop %%ds */ + src.val = x86_seg_ds; + goto pop_seg; + case 0x27: /* daa */ { uint8_t al = _regs.eax; unsigned long eflags = _regs.eflags; @@ -2066,6 +2198,18 @@ x86_emulate( break; } + case 0xea: /* jmp (far, absolute) */ { + uint16_t sel; + uint32_t eip; + generate_exception_if(mode_64bit(), EXC_UD); + eip = insn_fetch_bytes(op_bytes); + sel = insn_fetch_type(uint16_t); + if ( (rc = load_seg(x86_seg_cs, sel, ctxt, ops)) != 0 ) + goto done; + _regs.eip = eip; + break; + } + case 0xeb: /* jmp (short) */ jmp_rel(insn_fetch_type(int8_t)); break; @@ -2252,6 +2396,51 @@ x86_emulate( twobyte_special_insn: switch ( b ) { + case 0x01: /* Grp7 */ { + struct segment_register reg; + + switch ( modrm_reg & 7 ) + { + case 0: /* sgdt */ + case 1: /* sidt */ + generate_exception_if(ea.type != OP_MEM, EXC_UD); + fail_if(ops->read_segment == NULL); + if ( (rc = ops->read_segment((modrm_reg & 1) ? + x86_seg_idtr : x86_seg_gdtr, + ®, ctxt)) ) + goto done; + if ( op_bytes == 2 ) + reg.base &= 0xffffff; + if ( (rc = ops->write(ea.mem.seg, ea.mem.off+0, + reg.limit, 2, ctxt)) || + (rc = ops->write(ea.mem.seg, ea.mem.off+2, + reg.base, mode_64bit() ? 8 : 4, ctxt)) ) + goto done; + break; + case 2: /* lgdt */ + case 3: /* lidt */ + generate_exception_if(ea.type != OP_MEM, EXC_UD); + fail_if(ops->write_segment == NULL); + memset(®, 0, sizeof(reg)); + if ( (rc = ops->read(ea.mem.seg, ea.mem.off+0, + (unsigned long *)®.limit, 2, ctxt)) || + (rc = ops->read(ea.mem.seg, ea.mem.off+2, + (unsigned long *)®.base, + mode_64bit() ? 8 : 4, ctxt)) ) + goto done; + if ( op_bytes == 2 ) + reg.base &= 0xffffff; + if ( (rc = ops->write_segment((modrm_reg & 1) ? + x86_seg_idtr : x86_seg_gdtr, + ®, ctxt)) ) + goto done; + break; + default: + goto cannot_emulate; + } + break; + } + case 0x06: /* clts */ generate_exception_if(!mode_ring0(), EXC_GP); fail_if((ops->read_cr == NULL) || (ops->write_cr == NULL)); @@ -2341,6 +2530,22 @@ x86_emulate( break; } + case 0xa0: /* push %%fs */ + src.val = x86_seg_fs; + goto push_seg; + + case 0xa1: /* pop %%fs */ + src.val = x86_seg_fs; + goto pop_seg; + + case 0xa8: /* push %%gs */ + src.val = x86_seg_gs; + goto push_seg; + + case 0xa9: /* pop %%gs */ + src.val = x86_seg_gs; + goto pop_seg; + case 0xc7: /* Grp9 (cmpxchg8b) */ #if defined(__i386__) { diff -r 2e7fcea74cb1 -r d5c396128897 xen/include/asm-x86/hvm/hvm.h --- a/xen/include/asm-x86/hvm/hvm.h Sat Nov 24 16:16:57 2007 +0000 +++ b/xen/include/asm-x86/hvm/hvm.h Sat Nov 24 21:40:19 2007 +0000 @@ -25,36 +25,6 @@ #include <asm/x86_emulate.h> #include <public/domctl.h> #include <public/hvm/save.h> - -/* - * Attribute for segment selector. This is a copy of bit 40:47 & 52:55 of the - * segment descriptor. It happens to match the format of an AMD SVM VMCB. - */ -typedef union segment_attributes { - u16 bytes; - struct - { - u16 type:4; /* 0; Bit 40-43 */ - u16 s: 1; /* 4; Bit 44 */ - u16 dpl: 2; /* 5; Bit 45-46 */ - u16 p: 1; /* 7; Bit 47 */ - u16 avl: 1; /* 8; Bit 52 */ - u16 l: 1; /* 9; Bit 53 */ - u16 db: 1; /* 10; Bit 54 */ - u16 g: 1; /* 11; Bit 55 */ - } fields; -} __attribute__ ((packed)) segment_attributes_t; - -/* - * Full state of a segment register (visible and hidden portions). - * Again, this happens to match the format of an AMD SVM VMCB. - */ -typedef struct segment_register { - u16 sel; - segment_attributes_t attr; - u32 limit; - u64 base; -} __attribute__ ((packed)) segment_register_t; /* Interrupt acknowledgement sources. */ enum hvm_intsrc { diff -r 2e7fcea74cb1 -r d5c396128897 xen/include/asm-x86/hvm/svm/vmcb.h --- a/xen/include/asm-x86/hvm/svm/vmcb.h Sat Nov 24 16:16:57 2007 +0000 +++ b/xen/include/asm-x86/hvm/svm/vmcb.h Sat Nov 24 21:40:19 2007 +0000 @@ -304,7 +304,7 @@ enum VMEXIT_EXITCODE }; /* Definition of segment state is borrowed by the generic HVM code. */ -typedef segment_register_t svm_segment_register_t; +typedef struct segment_register svm_segment_register_t; typedef union { diff -r 2e7fcea74cb1 -r d5c396128897 xen/include/asm-x86/x86_emulate.h --- a/xen/include/asm-x86/x86_emulate.h Sat Nov 24 16:16:57 2007 +0000 +++ b/xen/include/asm-x86/x86_emulate.h Sat Nov 24 21:40:19 2007 +0000 @@ -26,10 +26,7 @@ struct x86_emulate_ctxt; -/* - * Comprehensive enumeration of x86 segment registers. Note that the system - * registers (TR, LDTR, GDTR, IDTR) are never referenced by the emulator. - */ +/* Comprehensive enumeration of x86 segment registers. */ enum x86_segment { /* General purpose. */ x86_seg_cs, @@ -45,6 +42,36 @@ enum x86_segment { x86_seg_idtr }; +/* + * Attribute for segment selector. This is a copy of bit 40:47 & 52:55 of the + * segment descriptor. It happens to match the format of an AMD SVM VMCB. + */ +typedef union segment_attributes { + u16 bytes; + struct + { + u16 type:4; /* 0; Bit 40-43 */ + u16 s: 1; /* 4; Bit 44 */ + u16 dpl: 2; /* 5; Bit 45-46 */ + u16 p: 1; /* 7; Bit 47 */ + u16 avl: 1; /* 8; Bit 52 */ + u16 l: 1; /* 9; Bit 53 */ + u16 db: 1; /* 10; Bit 54 */ + u16 g: 1; /* 11; Bit 55 */ + } fields; +} __attribute__ ((packed)) segment_attributes_t; + +/* + * Full state of a segment register (visible and hidden portions). + * Again, this happens to match the format of an AMD SVM VMCB. + */ +struct segment_register { + u16 sel; + segment_attributes_t attr; + u32 limit; + u64 base; +} __attribute__ ((packed)); + /* * Return codes from state-accessor functions and from x86_emulate(). */ @@ -148,6 +175,24 @@ struct x86_emulate_ops struct x86_emulate_ctxt *ctxt); /* + * read_segment: Emulate a read of full context of a segment register. + * @reg: [OUT] Contents of segment register (visible and hidden state). + */ + int (*read_segment)( + enum x86_segment seg, + struct segment_register *reg, + struct x86_emulate_ctxt *ctxt); + + /* + * write_segment: Emulate a read of full context of a segment register. + * @reg: [OUT] Contents of segment register (visible and hidden state). + */ + int (*write_segment)( + enum x86_segment seg, + struct segment_register *reg, + struct x86_emulate_ctxt *ctxt); + + /* * read_io: Read from I/O port(s). * @port: [IN ] Base port for access. */ _______________________________________________ Xen-changelog mailing list Xen-changelog@xxxxxxxxxxxxxxxxxxx http://lists.xensource.com/xen-changelog
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |