debuggers.hg
changeset 16500:f6a587e3d5c9
x86_emulate: Allow emulated injection of exceptions and interrupts.
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 | Sun Nov 25 18:05:10 2007 +0000 (2007-11-25) |
parents | d40788f07a4f |
children | 502f5b9469c3 |
files | xen/arch/x86/hvm/vmx/realmode.c xen/arch/x86/x86_emulate.c xen/include/asm-x86/x86_emulate.h |
line diff
1.1 --- a/xen/arch/x86/hvm/vmx/realmode.c Sun Nov 25 12:43:13 2007 +0000 1.2 +++ b/xen/arch/x86/hvm/vmx/realmode.c Sun Nov 25 18:05:10 2007 +0000 1.3 @@ -13,6 +13,7 @@ 1.4 #include <xen/init.h> 1.5 #include <xen/lib.h> 1.6 #include <xen/sched.h> 1.7 +#include <asm/event.h> 1.8 #include <asm/hvm/hvm.h> 1.9 #include <asm/hvm/support.h> 1.10 #include <asm/hvm/vmx/vmx.h> 1.11 @@ -23,35 +24,78 @@ 1.12 struct realmode_emulate_ctxt { 1.13 struct x86_emulate_ctxt ctxt; 1.14 1.15 - /* Cache of up to 31 bytes of instruction. */ 1.16 - uint8_t insn_buf[31]; 1.17 - uint8_t insn_buf_bytes; 1.18 + /* Cache of 16 bytes of instruction. */ 1.19 + uint8_t insn_buf[16]; 1.20 unsigned long insn_buf_eip; 1.21 1.22 struct segment_register seg_reg[10]; 1.23 }; 1.24 1.25 -static int realmode_translate_linear_addr( 1.26 - enum x86_segment seg, 1.27 - unsigned long offset, 1.28 - unsigned int bytes, 1.29 - enum hvm_access_type access_type, 1.30 - struct realmode_emulate_ctxt *rm_ctxt, 1.31 - unsigned long *paddr) 1.32 +static void realmode_deliver_exception( 1.33 + unsigned int vector, 1.34 + unsigned int insn_len, 1.35 + struct realmode_emulate_ctxt *rm_ctxt) 1.36 { 1.37 - struct segment_register *reg = &rm_ctxt->seg_reg[seg]; 1.38 - int okay; 1.39 + struct segment_register *idtr = &rm_ctxt->seg_reg[x86_seg_idtr]; 1.40 + struct segment_register *csr = &rm_ctxt->seg_reg[x86_seg_cs]; 1.41 + struct cpu_user_regs *regs = rm_ctxt->ctxt.regs; 1.42 + uint32_t cs_eip, pstk; 1.43 + uint16_t frame[3]; 1.44 + unsigned int last_byte; 1.45 1.46 - okay = hvm_virtual_to_linear_addr( 1.47 - seg, reg, offset, bytes, access_type, rm_ctxt->ctxt.addr_size, paddr); 1.48 + again: 1.49 + last_byte = (vector * 4) + 3; 1.50 + if ( idtr->limit < last_byte ) 1.51 + { 1.52 + /* Software interrupt? */ 1.53 + if ( insn_len != 0 ) 1.54 + { 1.55 + insn_len = 0; 1.56 + vector = TRAP_gp_fault; 1.57 + goto again; 1.58 + } 1.59 1.60 - if ( !okay ) 1.61 - { 1.62 - hvm_inject_exception(TRAP_gp_fault, 0, 0); 1.63 - return X86EMUL_EXCEPTION; 1.64 + /* Exception or hardware interrupt. */ 1.65 + switch ( vector ) 1.66 + { 1.67 + case TRAP_double_fault: 1.68 + hvm_triple_fault(); 1.69 + return; 1.70 + case TRAP_gp_fault: 1.71 + vector = TRAP_double_fault; 1.72 + goto again; 1.73 + default: 1.74 + vector = TRAP_gp_fault; 1.75 + goto again; 1.76 + } 1.77 } 1.78 1.79 - return 0; 1.80 + (void)hvm_copy_from_guest_phys(&cs_eip, idtr->base + vector * 4, 4); 1.81 + 1.82 + frame[0] = regs->eip + insn_len; 1.83 + frame[1] = csr->sel; 1.84 + frame[2] = regs->eflags & ~X86_EFLAGS_RF; 1.85 + 1.86 + if ( rm_ctxt->ctxt.addr_size == 32 ) 1.87 + { 1.88 + regs->esp -= 4; 1.89 + pstk = regs->esp; 1.90 + } 1.91 + else 1.92 + { 1.93 + pstk = (uint16_t)(regs->esp - 4); 1.94 + regs->esp &= ~0xffff; 1.95 + regs->esp |= pstk; 1.96 + } 1.97 + 1.98 + pstk += rm_ctxt->seg_reg[x86_seg_ss].base; 1.99 + (void)hvm_copy_to_guest_phys(pstk, frame, sizeof(frame)); 1.100 + 1.101 + csr->sel = cs_eip >> 16; 1.102 + csr->base = (uint32_t)csr->sel << 4; 1.103 + regs->eip = (uint16_t)cs_eip; 1.104 + regs->eflags &= ~(X86_EFLAGS_AC | X86_EFLAGS_TF | 1.105 + X86_EFLAGS_AC | X86_EFLAGS_RF); 1.106 } 1.107 1.108 static int 1.109 @@ -63,14 +107,7 @@ realmode_read( 1.110 enum hvm_access_type access_type, 1.111 struct realmode_emulate_ctxt *rm_ctxt) 1.112 { 1.113 - unsigned long addr; 1.114 - int rc; 1.115 - 1.116 - rc = realmode_translate_linear_addr( 1.117 - seg, offset, bytes, access_type, rm_ctxt, &addr); 1.118 - if ( rc ) 1.119 - return rc; 1.120 - 1.121 + uint32_t addr = rm_ctxt->seg_reg[seg].base + offset; 1.122 *val = 0; 1.123 (void)hvm_copy_from_guest_phys(val, addr, bytes); 1.124 return X86EMUL_OKAY; 1.125 @@ -102,7 +139,7 @@ realmode_emulate_insn_fetch( 1.126 unsigned int insn_off = offset - rm_ctxt->insn_buf_eip; 1.127 1.128 /* Fall back if requested bytes are not in the prefetch cache. */ 1.129 - if ( unlikely((insn_off + bytes) > rm_ctxt->insn_buf_bytes) ) 1.130 + if ( unlikely((insn_off + bytes) > sizeof(rm_ctxt->insn_buf)) ) 1.131 return realmode_read( 1.132 seg, offset, val, bytes, 1.133 hvm_access_insn_fetch, rm_ctxt); 1.134 @@ -123,14 +160,7 @@ realmode_emulate_write( 1.135 { 1.136 struct realmode_emulate_ctxt *rm_ctxt = 1.137 container_of(ctxt, struct realmode_emulate_ctxt, ctxt); 1.138 - unsigned long addr; 1.139 - int rc; 1.140 - 1.141 - rc = realmode_translate_linear_addr( 1.142 - seg, offset, bytes, hvm_access_write, rm_ctxt, &addr); 1.143 - if ( rc ) 1.144 - return rc; 1.145 - 1.146 + uint32_t addr = rm_ctxt->seg_reg[seg].base + offset; 1.147 (void)hvm_copy_to_guest_phys(addr, &val, bytes); 1.148 return X86EMUL_OKAY; 1.149 } 1.150 @@ -258,6 +288,31 @@ static int realmode_write_rflags( 1.151 return X86EMUL_OKAY; 1.152 } 1.153 1.154 +static int realmode_inject_hw_exception( 1.155 + uint8_t vector, 1.156 + struct x86_emulate_ctxt *ctxt) 1.157 +{ 1.158 + struct realmode_emulate_ctxt *rm_ctxt = 1.159 + container_of(ctxt, struct realmode_emulate_ctxt, ctxt); 1.160 + 1.161 + realmode_deliver_exception(vector, 0, rm_ctxt); 1.162 + 1.163 + return X86EMUL_OKAY; 1.164 +} 1.165 + 1.166 +static int realmode_inject_sw_interrupt( 1.167 + uint8_t vector, 1.168 + uint8_t insn_len, 1.169 + struct x86_emulate_ctxt *ctxt) 1.170 +{ 1.171 + struct realmode_emulate_ctxt *rm_ctxt = 1.172 + container_of(ctxt, struct realmode_emulate_ctxt, ctxt); 1.173 + 1.174 + realmode_deliver_exception(vector, insn_len, rm_ctxt); 1.175 + 1.176 + return X86EMUL_OKAY; 1.177 +} 1.178 + 1.179 static struct x86_emulate_ops realmode_emulator_ops = { 1.180 .read = realmode_emulate_read, 1.181 .insn_fetch = realmode_emulate_insn_fetch, 1.182 @@ -268,37 +323,44 @@ static struct x86_emulate_ops realmode_e 1.183 .read_io = realmode_read_io, 1.184 .write_io = realmode_write_io, 1.185 .read_cr = realmode_read_cr, 1.186 - .write_rflags = realmode_write_rflags 1.187 + .write_rflags = realmode_write_rflags, 1.188 + .inject_hw_exception = realmode_inject_hw_exception, 1.189 + .inject_sw_interrupt = realmode_inject_sw_interrupt 1.190 }; 1.191 1.192 int vmx_realmode(struct cpu_user_regs *regs) 1.193 { 1.194 struct vcpu *curr = current; 1.195 struct realmode_emulate_ctxt rm_ctxt; 1.196 - unsigned long addr; 1.197 + unsigned long intr_info; 1.198 int i, rc = 0; 1.199 1.200 + rm_ctxt.ctxt.regs = regs; 1.201 + 1.202 for ( i = 0; i < 10; i++ ) 1.203 hvm_get_segment_register(curr, i, &rm_ctxt.seg_reg[i]); 1.204 1.205 - while ( !(curr->arch.hvm_vcpu.guest_cr[0] & X86_CR0_PE) && 1.206 - !softirq_pending(smp_processor_id()) ) 1.207 - { 1.208 - rm_ctxt.ctxt.regs = regs; 1.209 - rm_ctxt.ctxt.addr_size = 1.210 - rm_ctxt.seg_reg[x86_seg_cs].attr.fields.db ? 32 : 16; 1.211 - rm_ctxt.ctxt.sp_size = 1.212 - rm_ctxt.seg_reg[x86_seg_ss].attr.fields.db ? 32 : 16; 1.213 + rm_ctxt.ctxt.addr_size = 1.214 + rm_ctxt.seg_reg[x86_seg_cs].attr.fields.db ? 32 : 16; 1.215 + rm_ctxt.ctxt.sp_size = 1.216 + rm_ctxt.seg_reg[x86_seg_ss].attr.fields.db ? 32 : 16; 1.217 1.218 + intr_info = __vmread(VM_ENTRY_INTR_INFO); 1.219 + if ( intr_info & INTR_INFO_VALID_MASK ) 1.220 + { 1.221 + __vmwrite(VM_ENTRY_INTR_INFO, 0); 1.222 + realmode_deliver_exception((uint8_t)intr_info, 0, &rm_ctxt); 1.223 + } 1.224 + 1.225 + while ( !(curr->arch.hvm_vcpu.guest_cr[0] & X86_CR0_PE) && 1.226 + !softirq_pending(smp_processor_id()) && 1.227 + !hvm_local_events_need_delivery(curr) ) 1.228 + { 1.229 rm_ctxt.insn_buf_eip = regs->eip; 1.230 - rm_ctxt.insn_buf_bytes = 1.231 - (hvm_virtual_to_linear_addr( 1.232 - x86_seg_cs, &rm_ctxt.seg_reg[x86_seg_cs], 1.233 - regs->eip, sizeof(rm_ctxt.insn_buf), 1.234 - hvm_access_insn_fetch, rm_ctxt.ctxt.addr_size, &addr) && 1.235 - !hvm_copy_from_guest_virt( 1.236 - rm_ctxt.insn_buf, addr, sizeof(rm_ctxt.insn_buf))) 1.237 - ? sizeof(rm_ctxt.insn_buf) : 0; 1.238 + (void)hvm_copy_from_guest_phys( 1.239 + rm_ctxt.insn_buf, 1.240 + (uint32_t)(rm_ctxt.seg_reg[x86_seg_cs].base + regs->eip), 1.241 + sizeof(rm_ctxt.insn_buf)); 1.242 1.243 rc = x86_emulate(&rm_ctxt.ctxt, &realmode_emulator_ops); 1.244 1.245 @@ -308,7 +370,7 @@ int vmx_realmode(struct cpu_user_regs *r 1.246 break; 1.247 } 1.248 1.249 - if ( rc ) 1.250 + if ( rc == X86EMUL_UNHANDLEABLE ) 1.251 { 1.252 gdprintk(XENLOG_DEBUG, 1.253 "RM %04x:%08lx: %02x %02x %02x %02x %02x %02x\n",
2.1 --- a/xen/arch/x86/x86_emulate.c Sun Nov 25 12:43:13 2007 +0000 2.2 +++ b/xen/arch/x86/x86_emulate.c Sun Nov 25 18:05:10 2007 +0000 2.3 @@ -149,7 +149,7 @@ static uint8_t opcode_table[256] = { 2.4 ImplicitOps, ImplicitOps, 2.5 0, 0, ByteOp|DstMem|SrcImm|ModRM|Mov, DstMem|SrcImm|ModRM|Mov, 2.6 /* 0xC8 - 0xCF */ 2.7 - 0, 0, 0, 0, 0, 0, 0, 0, 2.8 + 0, 0, 0, 0, ImplicitOps, ImplicitOps, ImplicitOps, 0, 2.9 /* 0xD0 - 0xD7 */ 2.10 ByteOp|DstMem|SrcImplicit|ModRM, DstMem|SrcImplicit|ModRM, 2.11 ByteOp|DstMem|SrcImplicit|ModRM, DstMem|SrcImplicit|ModRM, 2.12 @@ -163,7 +163,7 @@ static uint8_t opcode_table[256] = { 2.13 ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps, 2.14 ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps, 2.15 /* 0xF0 - 0xF7 */ 2.16 - 0, 0, 0, 0, 2.17 + 0, ImplicitOps, 0, 0, 2.18 0, ImplicitOps, ByteOp|DstMem|SrcNone|ModRM, DstMem|SrcNone|ModRM, 2.19 /* 0xF8 - 0xFF */ 2.20 ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps, 2.21 @@ -270,6 +270,7 @@ struct operand { 2.22 #define EFLG_OF (1<<11) 2.23 #define EFLG_DF (1<<10) 2.24 #define EFLG_IF (1<<9) 2.25 +#define EFLG_TF (1<<8) 2.26 #define EFLG_SF (1<<7) 2.27 #define EFLG_ZF (1<<6) 2.28 #define EFLG_AF (1<<4) 2.29 @@ -278,6 +279,9 @@ struct operand { 2.30 2.31 /* Exception definitions. */ 2.32 #define EXC_DE 0 2.33 +#define EXC_DB 1 2.34 +#define EXC_BP 3 2.35 +#define EXC_OF 4 2.36 #define EXC_BR 5 2.37 #define EXC_UD 6 2.38 #define EXC_GP 13 2.39 @@ -477,8 +481,13 @@ do { 2.40 if ( rc ) goto done; \ 2.41 } while (0) 2.42 2.43 -/* In future we will be able to generate arbitrary exceptions. */ 2.44 -#define generate_exception_if(p, e) fail_if(p) 2.45 +#define generate_exception_if(p, e) \ 2.46 +({ if ( (p) ) { \ 2.47 + fail_if(ops->inject_hw_exception == NULL); \ 2.48 + rc = ops->inject_hw_exception(e, ctxt) ? : X86EMUL_EXCEPTION; \ 2.49 + goto done; \ 2.50 + } \ 2.51 +}) 2.52 2.53 /* Given byte has even parity (even number of 1s)? */ 2.54 static int even_parity(uint8_t v) 2.55 @@ -1771,7 +1780,11 @@ x86_emulate( 2.56 /* Commit shadow register state. */ 2.57 _regs.eflags &= ~EFLG_RF; 2.58 *ctxt->regs = _regs; 2.59 - /* FIXME generate_exception_if(_regs.eflags & EFLG_TF, EXC_DB); */ 2.60 + 2.61 + if ( (_regs.eflags & EFLG_TF) && 2.62 + (rc == X86EMUL_OKAY) && 2.63 + (ops->inject_hw_exception != NULL) ) 2.64 + rc = ops->inject_hw_exception(EXC_DB, ctxt) ? : X86EMUL_EXCEPTION; 2.65 2.66 done: 2.67 return rc; 2.68 @@ -2152,6 +2165,25 @@ x86_emulate( 2.69 break; 2.70 } 2.71 2.72 + case 0xcc: /* int3 */ 2.73 + src.val = EXC_BP; 2.74 + goto swint; 2.75 + 2.76 + case 0xcd: /* int imm8 */ 2.77 + src.val = insn_fetch_type(uint8_t); 2.78 + swint: 2.79 + fail_if(ops->inject_sw_interrupt == NULL); 2.80 + rc = ops->inject_sw_interrupt(src.val, _regs.eip - ctxt->regs->eip, 2.81 + ctxt) ? : X86EMUL_EXCEPTION; 2.82 + goto done; 2.83 + 2.84 + case 0xce: /* into */ 2.85 + generate_exception_if(mode_64bit(), EXC_UD); 2.86 + if ( !(_regs.eflags & EFLG_OF) ) 2.87 + break; 2.88 + src.val = EXC_OF; 2.89 + goto swint; 2.90 + 2.91 case 0xd4: /* aam */ { 2.92 unsigned int base = insn_fetch_type(uint8_t); 2.93 uint8_t al = _regs.eax; 2.94 @@ -2292,6 +2324,10 @@ x86_emulate( 2.95 jmp_rel(insn_fetch_type(int8_t)); 2.96 break; 2.97 2.98 + case 0xf1: /* int1 (icebp) */ 2.99 + src.val = EXC_DB; 2.100 + goto swint; 2.101 + 2.102 case 0xf5: /* cmc */ 2.103 _regs.eflags ^= EFLG_CF; 2.104 break;
3.1 --- a/xen/include/asm-x86/x86_emulate.h Sun Nov 25 12:43:13 2007 +0000 3.2 +++ b/xen/include/asm-x86/x86_emulate.h Sun Nov 25 18:05:10 2007 +0000 3.3 @@ -274,6 +274,17 @@ struct x86_emulate_ops 3.4 /* wbinvd: Write-back and invalidate cache contents. */ 3.5 int (*wbinvd)( 3.6 struct x86_emulate_ctxt *ctxt); 3.7 + 3.8 + /* inject_hw_exception */ 3.9 + int (*inject_hw_exception)( 3.10 + uint8_t vector, 3.11 + struct x86_emulate_ctxt *ctxt); 3.12 + 3.13 + /* inject_sw_interrupt */ 3.14 + int (*inject_sw_interrupt)( 3.15 + uint8_t vector, 3.16 + uint8_t insn_len, 3.17 + struct x86_emulate_ctxt *ctxt); 3.18 }; 3.19 3.20 struct cpu_user_regs;