ia64/xen-unstable
changeset 16454:d5c396128897
x86_emulate: Support most common segment load/save instructions.
Signed-off-by: Keir Fraser <keir.fraser@citrix.com>
Signed-off-by: Keir Fraser <keir.fraser@citrix.com>
author | Keir Fraser <keir.fraser@citrix.com> |
---|---|
date | Sat Nov 24 21:40:19 2007 +0000 (2007-11-24) |
parents | 2e7fcea74cb1 |
children | 51082cf273d4 |
files | xen/arch/x86/x86_emulate.c xen/include/asm-x86/hvm/hvm.h xen/include/asm-x86/hvm/svm/vmcb.h xen/include/asm-x86/x86_emulate.h |
line diff
1.1 --- a/xen/arch/x86/x86_emulate.c Sat Nov 24 16:16:57 2007 +0000 1.2 +++ b/xen/arch/x86/x86_emulate.c Sat Nov 24 21:40:19 2007 +0000 1.3 @@ -60,19 +60,19 @@ static uint8_t opcode_table[256] = { 1.4 /* 0x00 - 0x07 */ 1.5 ByteOp|DstMem|SrcReg|ModRM, DstMem|SrcReg|ModRM, 1.6 ByteOp|DstReg|SrcMem|ModRM, DstReg|SrcMem|ModRM, 1.7 - ByteOp|DstReg|SrcImm, DstReg|SrcImm, 0, 0, 1.8 + ByteOp|DstReg|SrcImm, DstReg|SrcImm, ImplicitOps, ImplicitOps, 1.9 /* 0x08 - 0x0F */ 1.10 ByteOp|DstMem|SrcReg|ModRM, DstMem|SrcReg|ModRM, 1.11 ByteOp|DstReg|SrcMem|ModRM, DstReg|SrcMem|ModRM, 1.12 - ByteOp|DstReg|SrcImm, DstReg|SrcImm, 0, 0, 1.13 + ByteOp|DstReg|SrcImm, DstReg|SrcImm, ImplicitOps, 0, 1.14 /* 0x10 - 0x17 */ 1.15 ByteOp|DstMem|SrcReg|ModRM, DstMem|SrcReg|ModRM, 1.16 ByteOp|DstReg|SrcMem|ModRM, DstReg|SrcMem|ModRM, 1.17 - ByteOp|DstReg|SrcImm, DstReg|SrcImm, 0, 0, 1.18 + ByteOp|DstReg|SrcImm, DstReg|SrcImm, ImplicitOps, ImplicitOps, 1.19 /* 0x18 - 0x1F */ 1.20 ByteOp|DstMem|SrcReg|ModRM, DstMem|SrcReg|ModRM, 1.21 ByteOp|DstReg|SrcMem|ModRM, DstReg|SrcMem|ModRM, 1.22 - ByteOp|DstReg|SrcImm, DstReg|SrcImm, 0, 0, 1.23 + ByteOp|DstReg|SrcImm, DstReg|SrcImm, ImplicitOps, ImplicitOps, 1.24 /* 0x20 - 0x27 */ 1.25 ByteOp|DstMem|SrcReg|ModRM, DstMem|SrcReg|ModRM, 1.26 ByteOp|DstReg|SrcMem|ModRM, DstReg|SrcMem|ModRM, 1.27 @@ -120,7 +120,8 @@ static uint8_t opcode_table[256] = { 1.28 /* 0x88 - 0x8F */ 1.29 ByteOp|DstMem|SrcReg|ModRM|Mov, DstMem|SrcReg|ModRM|Mov, 1.30 ByteOp|DstReg|SrcMem|ModRM|Mov, DstReg|SrcMem|ModRM|Mov, 1.31 - 0, DstReg|SrcNone|ModRM, 0, DstMem|SrcNone|ModRM|Mov, 1.32 + DstMem|SrcReg|ModRM|Mov, DstReg|SrcNone|ModRM, 1.33 + DstReg|SrcMem|ModRM|Mov, DstMem|SrcNone|ModRM|Mov, 1.34 /* 0x90 - 0x97 */ 1.35 ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps, 1.36 ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps, 1.37 @@ -158,7 +159,7 @@ static uint8_t opcode_table[256] = { 1.38 ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps, 1.39 ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps, 1.40 /* 0xE8 - 0xEF */ 1.41 - ImplicitOps, ImplicitOps, 0, ImplicitOps, 1.42 + ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps, 1.43 ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps, 1.44 /* 0xF0 - 0xF7 */ 1.45 0, 0, 0, 0, 1.46 @@ -170,7 +171,7 @@ static uint8_t opcode_table[256] = { 1.47 1.48 static uint8_t twobyte_table[256] = { 1.49 /* 0x00 - 0x07 */ 1.50 - 0, 0, 0, 0, 0, ImplicitOps, 0, 0, 1.51 + 0, ImplicitOps|ModRM, 0, 0, 0, ImplicitOps, 0, 0, 1.52 /* 0x08 - 0x0F */ 1.53 ImplicitOps, ImplicitOps, 0, 0, 0, ImplicitOps|ModRM, 0, 0, 1.54 /* 0x10 - 0x17 */ 1.55 @@ -220,9 +221,10 @@ static uint8_t twobyte_table[256] = { 1.56 ByteOp|DstMem|SrcNone|ModRM|Mov, ByteOp|DstMem|SrcNone|ModRM|Mov, 1.57 ByteOp|DstMem|SrcNone|ModRM|Mov, ByteOp|DstMem|SrcNone|ModRM|Mov, 1.58 /* 0xA0 - 0xA7 */ 1.59 - 0, 0, 0, DstBitBase|SrcReg|ModRM, 0, 0, 0, 0, 1.60 + ImplicitOps, ImplicitOps, 0, DstBitBase|SrcReg|ModRM, 0, 0, 0, 0, 1.61 /* 0xA8 - 0xAF */ 1.62 - 0, 0, 0, DstBitBase|SrcReg|ModRM, 0, 0, 0, DstReg|SrcMem|ModRM, 1.63 + ImplicitOps, ImplicitOps, 0, DstBitBase|SrcReg|ModRM, 1.64 + 0, 0, 0, DstReg|SrcMem|ModRM, 1.65 /* 0xB0 - 0xB7 */ 1.66 ByteOp|DstMem|SrcReg|ModRM, DstMem|SrcReg|ModRM, 1.67 0, DstBitBase|SrcReg|ModRM, 1.68 @@ -677,6 +679,45 @@ test_cc( 1.69 return (!!rc ^ (condition & 1)); 1.70 } 1.71 1.72 +static int 1.73 +in_realmode( 1.74 + struct x86_emulate_ctxt *ctxt, 1.75 + struct x86_emulate_ops *ops) 1.76 +{ 1.77 + unsigned long cr0; 1.78 + int rc; 1.79 + 1.80 + if ( ops->read_cr == NULL ) 1.81 + return 0; 1.82 + 1.83 + rc = ops->read_cr(0, &cr0, ctxt); 1.84 + return (!rc && !(cr0 & 1)); 1.85 +} 1.86 + 1.87 +static int 1.88 +load_seg( 1.89 + enum x86_segment seg, 1.90 + uint16_t sel, 1.91 + struct x86_emulate_ctxt *ctxt, 1.92 + struct x86_emulate_ops *ops) 1.93 +{ 1.94 + struct segment_register reg; 1.95 + int rc; 1.96 + 1.97 + if ( !in_realmode(ctxt, ops) || 1.98 + (ops->read_segment == NULL) || 1.99 + (ops->write_segment == NULL) ) 1.100 + return X86EMUL_UNHANDLEABLE; 1.101 + 1.102 + if ( (rc = ops->read_segment(seg, ®, ctxt)) != 0 ) 1.103 + return rc; 1.104 + 1.105 + reg.sel = sel; 1.106 + reg.base = (uint32_t)sel << 4; 1.107 + 1.108 + return ops->write_segment(seg, ®, ctxt); 1.109 +} 1.110 + 1.111 void * 1.112 decode_register( 1.113 uint8_t modrm_reg, struct cpu_user_regs *regs, int highbyte_regs) 1.114 @@ -717,6 +758,24 @@ decode_register( 1.115 return p; 1.116 } 1.117 1.118 +#define decode_segment_failed x86_seg_tr 1.119 +enum x86_segment 1.120 +decode_segment( 1.121 + uint8_t modrm_reg) 1.122 +{ 1.123 + switch ( modrm_reg ) 1.124 + { 1.125 + case 0: return x86_seg_es; 1.126 + case 1: return x86_seg_cs; 1.127 + case 2: return x86_seg_ss; 1.128 + case 3: return x86_seg_ds; 1.129 + case 4: return x86_seg_fs; 1.130 + case 5: return x86_seg_gs; 1.131 + default: break; 1.132 + } 1.133 + return decode_segment_failed; 1.134 +} 1.135 + 1.136 int 1.137 x86_emulate( 1.138 struct x86_emulate_ctxt *ctxt, 1.139 @@ -1205,6 +1264,7 @@ x86_emulate( 1.140 dst.val = (dst.val & ~3) | (src_val & 3); 1.141 else 1.142 dst.type = OP_NONE; 1.143 + generate_exception_if(in_realmode(ctxt, ops), EXC_UD); 1.144 } 1.145 break; 1.146 1.147 @@ -1284,6 +1344,28 @@ x86_emulate( 1.148 dst.val = src.val; 1.149 break; 1.150 1.151 + case 0x8c: /* mov Sreg,r/m */ { 1.152 + struct segment_register reg; 1.153 + enum x86_segment seg = decode_segment(modrm_reg); 1.154 + generate_exception_if(seg == decode_segment_failed, EXC_UD); 1.155 + fail_if(ops->read_segment == NULL); 1.156 + if ( (rc = ops->read_segment(seg, ®, ctxt)) != 0 ) 1.157 + goto done; 1.158 + dst.val = reg.sel; 1.159 + if ( dst.type == OP_MEM ) 1.160 + dst.bytes = 2; 1.161 + break; 1.162 + } 1.163 + 1.164 + case 0x8e: /* mov r/m,Sreg */ { 1.165 + enum x86_segment seg = decode_segment(modrm_reg); 1.166 + generate_exception_if(seg == decode_segment_failed, EXC_UD); 1.167 + if ( (rc = load_seg(seg, (uint16_t)src.val, ctxt, ops)) != 0 ) 1.168 + goto done; 1.169 + dst.type = OP_NONE; 1.170 + break; 1.171 + } 1.172 + 1.173 case 0x8d: /* lea */ 1.174 dst.val = ea.mem.off; 1.175 break; 1.176 @@ -1657,6 +1739,56 @@ x86_emulate( 1.177 1.178 switch ( b ) 1.179 { 1.180 + case 0x06: /* push %%es */ { 1.181 + struct segment_register reg; 1.182 + src.val = x86_seg_es; 1.183 + push_seg: 1.184 + fail_if(ops->read_segment == NULL); 1.185 + if ( (rc = ops->read_segment(src.val, ®, ctxt)) != 0 ) 1.186 + return rc; 1.187 + /* 64-bit mode: PUSH defaults to a 64-bit operand. */ 1.188 + if ( mode_64bit() && (op_bytes == 4) ) 1.189 + op_bytes = 8; 1.190 + if ( (rc = ops->write(x86_seg_ss, sp_pre_dec(op_bytes), 1.191 + reg.sel, op_bytes, ctxt)) != 0 ) 1.192 + goto done; 1.193 + break; 1.194 + } 1.195 + 1.196 + case 0x07: /* pop %%es */ 1.197 + src.val = x86_seg_es; 1.198 + pop_seg: 1.199 + fail_if(ops->write_segment == NULL); 1.200 + /* 64-bit mode: PUSH defaults to a 64-bit operand. */ 1.201 + if ( mode_64bit() && (op_bytes == 4) ) 1.202 + op_bytes = 8; 1.203 + if ( (rc = ops->read(x86_seg_ss, sp_post_inc(op_bytes), 1.204 + &dst.val, op_bytes, ctxt)) != 0 ) 1.205 + goto done; 1.206 + if ( (rc = load_seg(src.val, (uint16_t)dst.val, ctxt, ops)) != 0 ) 1.207 + return rc; 1.208 + break; 1.209 + 1.210 + case 0x0e: /* push %%cs */ 1.211 + src.val = x86_seg_cs; 1.212 + goto push_seg; 1.213 + 1.214 + case 0x16: /* push %%ss */ 1.215 + src.val = x86_seg_ss; 1.216 + goto push_seg; 1.217 + 1.218 + case 0x17: /* pop %%ss */ 1.219 + src.val = x86_seg_ss; 1.220 + goto pop_seg; 1.221 + 1.222 + case 0x1e: /* push %%ds */ 1.223 + src.val = x86_seg_ds; 1.224 + goto push_seg; 1.225 + 1.226 + case 0x1f: /* pop %%ds */ 1.227 + src.val = x86_seg_ds; 1.228 + goto pop_seg; 1.229 + 1.230 case 0x27: /* daa */ { 1.231 uint8_t al = _regs.eax; 1.232 unsigned long eflags = _regs.eflags; 1.233 @@ -2066,6 +2198,18 @@ x86_emulate( 1.234 break; 1.235 } 1.236 1.237 + case 0xea: /* jmp (far, absolute) */ { 1.238 + uint16_t sel; 1.239 + uint32_t eip; 1.240 + generate_exception_if(mode_64bit(), EXC_UD); 1.241 + eip = insn_fetch_bytes(op_bytes); 1.242 + sel = insn_fetch_type(uint16_t); 1.243 + if ( (rc = load_seg(x86_seg_cs, sel, ctxt, ops)) != 0 ) 1.244 + goto done; 1.245 + _regs.eip = eip; 1.246 + break; 1.247 + } 1.248 + 1.249 case 0xeb: /* jmp (short) */ 1.250 jmp_rel(insn_fetch_type(int8_t)); 1.251 break; 1.252 @@ -2252,6 +2396,51 @@ x86_emulate( 1.253 twobyte_special_insn: 1.254 switch ( b ) 1.255 { 1.256 + case 0x01: /* Grp7 */ { 1.257 + struct segment_register reg; 1.258 + 1.259 + switch ( modrm_reg & 7 ) 1.260 + { 1.261 + case 0: /* sgdt */ 1.262 + case 1: /* sidt */ 1.263 + generate_exception_if(ea.type != OP_MEM, EXC_UD); 1.264 + fail_if(ops->read_segment == NULL); 1.265 + if ( (rc = ops->read_segment((modrm_reg & 1) ? 1.266 + x86_seg_idtr : x86_seg_gdtr, 1.267 + ®, ctxt)) ) 1.268 + goto done; 1.269 + if ( op_bytes == 2 ) 1.270 + reg.base &= 0xffffff; 1.271 + if ( (rc = ops->write(ea.mem.seg, ea.mem.off+0, 1.272 + reg.limit, 2, ctxt)) || 1.273 + (rc = ops->write(ea.mem.seg, ea.mem.off+2, 1.274 + reg.base, mode_64bit() ? 8 : 4, ctxt)) ) 1.275 + goto done; 1.276 + break; 1.277 + case 2: /* lgdt */ 1.278 + case 3: /* lidt */ 1.279 + generate_exception_if(ea.type != OP_MEM, EXC_UD); 1.280 + fail_if(ops->write_segment == NULL); 1.281 + memset(®, 0, sizeof(reg)); 1.282 + if ( (rc = ops->read(ea.mem.seg, ea.mem.off+0, 1.283 + (unsigned long *)®.limit, 2, ctxt)) || 1.284 + (rc = ops->read(ea.mem.seg, ea.mem.off+2, 1.285 + (unsigned long *)®.base, 1.286 + mode_64bit() ? 8 : 4, ctxt)) ) 1.287 + goto done; 1.288 + if ( op_bytes == 2 ) 1.289 + reg.base &= 0xffffff; 1.290 + if ( (rc = ops->write_segment((modrm_reg & 1) ? 1.291 + x86_seg_idtr : x86_seg_gdtr, 1.292 + ®, ctxt)) ) 1.293 + goto done; 1.294 + break; 1.295 + default: 1.296 + goto cannot_emulate; 1.297 + } 1.298 + break; 1.299 + } 1.300 + 1.301 case 0x06: /* clts */ 1.302 generate_exception_if(!mode_ring0(), EXC_GP); 1.303 fail_if((ops->read_cr == NULL) || (ops->write_cr == NULL)); 1.304 @@ -2341,6 +2530,22 @@ x86_emulate( 1.305 break; 1.306 } 1.307 1.308 + case 0xa0: /* push %%fs */ 1.309 + src.val = x86_seg_fs; 1.310 + goto push_seg; 1.311 + 1.312 + case 0xa1: /* pop %%fs */ 1.313 + src.val = x86_seg_fs; 1.314 + goto pop_seg; 1.315 + 1.316 + case 0xa8: /* push %%gs */ 1.317 + src.val = x86_seg_gs; 1.318 + goto push_seg; 1.319 + 1.320 + case 0xa9: /* pop %%gs */ 1.321 + src.val = x86_seg_gs; 1.322 + goto pop_seg; 1.323 + 1.324 case 0xc7: /* Grp9 (cmpxchg8b) */ 1.325 #if defined(__i386__) 1.326 {
2.1 --- a/xen/include/asm-x86/hvm/hvm.h Sat Nov 24 16:16:57 2007 +0000 2.2 +++ b/xen/include/asm-x86/hvm/hvm.h Sat Nov 24 21:40:19 2007 +0000 2.3 @@ -26,36 +26,6 @@ 2.4 #include <public/domctl.h> 2.5 #include <public/hvm/save.h> 2.6 2.7 -/* 2.8 - * Attribute for segment selector. This is a copy of bit 40:47 & 52:55 of the 2.9 - * segment descriptor. It happens to match the format of an AMD SVM VMCB. 2.10 - */ 2.11 -typedef union segment_attributes { 2.12 - u16 bytes; 2.13 - struct 2.14 - { 2.15 - u16 type:4; /* 0; Bit 40-43 */ 2.16 - u16 s: 1; /* 4; Bit 44 */ 2.17 - u16 dpl: 2; /* 5; Bit 45-46 */ 2.18 - u16 p: 1; /* 7; Bit 47 */ 2.19 - u16 avl: 1; /* 8; Bit 52 */ 2.20 - u16 l: 1; /* 9; Bit 53 */ 2.21 - u16 db: 1; /* 10; Bit 54 */ 2.22 - u16 g: 1; /* 11; Bit 55 */ 2.23 - } fields; 2.24 -} __attribute__ ((packed)) segment_attributes_t; 2.25 - 2.26 -/* 2.27 - * Full state of a segment register (visible and hidden portions). 2.28 - * Again, this happens to match the format of an AMD SVM VMCB. 2.29 - */ 2.30 -typedef struct segment_register { 2.31 - u16 sel; 2.32 - segment_attributes_t attr; 2.33 - u32 limit; 2.34 - u64 base; 2.35 -} __attribute__ ((packed)) segment_register_t; 2.36 - 2.37 /* Interrupt acknowledgement sources. */ 2.38 enum hvm_intsrc { 2.39 hvm_intsrc_none,
3.1 --- a/xen/include/asm-x86/hvm/svm/vmcb.h Sat Nov 24 16:16:57 2007 +0000 3.2 +++ b/xen/include/asm-x86/hvm/svm/vmcb.h Sat Nov 24 21:40:19 2007 +0000 3.3 @@ -304,7 +304,7 @@ enum VMEXIT_EXITCODE 3.4 }; 3.5 3.6 /* Definition of segment state is borrowed by the generic HVM code. */ 3.7 -typedef segment_register_t svm_segment_register_t; 3.8 +typedef struct segment_register svm_segment_register_t; 3.9 3.10 typedef union 3.11 {
4.1 --- a/xen/include/asm-x86/x86_emulate.h Sat Nov 24 16:16:57 2007 +0000 4.2 +++ b/xen/include/asm-x86/x86_emulate.h Sat Nov 24 21:40:19 2007 +0000 4.3 @@ -26,10 +26,7 @@ 4.4 4.5 struct x86_emulate_ctxt; 4.6 4.7 -/* 4.8 - * Comprehensive enumeration of x86 segment registers. Note that the system 4.9 - * registers (TR, LDTR, GDTR, IDTR) are never referenced by the emulator. 4.10 - */ 4.11 +/* Comprehensive enumeration of x86 segment registers. */ 4.12 enum x86_segment { 4.13 /* General purpose. */ 4.14 x86_seg_cs, 4.15 @@ -45,6 +42,36 @@ enum x86_segment { 4.16 x86_seg_idtr 4.17 }; 4.18 4.19 +/* 4.20 + * Attribute for segment selector. This is a copy of bit 40:47 & 52:55 of the 4.21 + * segment descriptor. It happens to match the format of an AMD SVM VMCB. 4.22 + */ 4.23 +typedef union segment_attributes { 4.24 + u16 bytes; 4.25 + struct 4.26 + { 4.27 + u16 type:4; /* 0; Bit 40-43 */ 4.28 + u16 s: 1; /* 4; Bit 44 */ 4.29 + u16 dpl: 2; /* 5; Bit 45-46 */ 4.30 + u16 p: 1; /* 7; Bit 47 */ 4.31 + u16 avl: 1; /* 8; Bit 52 */ 4.32 + u16 l: 1; /* 9; Bit 53 */ 4.33 + u16 db: 1; /* 10; Bit 54 */ 4.34 + u16 g: 1; /* 11; Bit 55 */ 4.35 + } fields; 4.36 +} __attribute__ ((packed)) segment_attributes_t; 4.37 + 4.38 +/* 4.39 + * Full state of a segment register (visible and hidden portions). 4.40 + * Again, this happens to match the format of an AMD SVM VMCB. 4.41 + */ 4.42 +struct segment_register { 4.43 + u16 sel; 4.44 + segment_attributes_t attr; 4.45 + u32 limit; 4.46 + u64 base; 4.47 +} __attribute__ ((packed)); 4.48 + 4.49 /* 4.50 * Return codes from state-accessor functions and from x86_emulate(). 4.51 */ 4.52 @@ -148,6 +175,24 @@ struct x86_emulate_ops 4.53 struct x86_emulate_ctxt *ctxt); 4.54 4.55 /* 4.56 + * read_segment: Emulate a read of full context of a segment register. 4.57 + * @reg: [OUT] Contents of segment register (visible and hidden state). 4.58 + */ 4.59 + int (*read_segment)( 4.60 + enum x86_segment seg, 4.61 + struct segment_register *reg, 4.62 + struct x86_emulate_ctxt *ctxt); 4.63 + 4.64 + /* 4.65 + * write_segment: Emulate a read of full context of a segment register. 4.66 + * @reg: [OUT] Contents of segment register (visible and hidden state). 4.67 + */ 4.68 + int (*write_segment)( 4.69 + enum x86_segment seg, 4.70 + struct segment_register *reg, 4.71 + struct x86_emulate_ctxt *ctxt); 4.72 + 4.73 + /* 4.74 * read_io: Read from I/O port(s). 4.75 * @port: [IN ] Base port for access. 4.76 */