[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-changelog] [xen-unstable] x86_emulate: Allow emulated injection of exceptions and interrupts.
# HG changeset patch # User Keir Fraser <keir.fraser@xxxxxxxxxx> # Date 1196013910 0 # Node ID f6a587e3d5c981b7cea8c3e97d234e14e3ca81bb # Parent d40788f07a4f40ac95c1f297f808c63b85baa3ff x86_emulate: Allow emulated injection of exceptions and interrupts. Signed-off-by: Keir Fraser <keir.fraser@xxxxxxxxxx> --- xen/arch/x86/hvm/vmx/realmode.c | 182 +++++++++++++++++++++++++------------- xen/arch/x86/x86_emulate.c | 46 ++++++++- xen/include/asm-x86/x86_emulate.h | 11 ++ 3 files changed, 174 insertions(+), 65 deletions(-) diff -r d40788f07a4f -r f6a587e3d5c9 xen/arch/x86/hvm/vmx/realmode.c --- a/xen/arch/x86/hvm/vmx/realmode.c Sun Nov 25 12:43:13 2007 +0000 +++ b/xen/arch/x86/hvm/vmx/realmode.c Sun Nov 25 18:05:10 2007 +0000 @@ -13,6 +13,7 @@ #include <xen/init.h> #include <xen/lib.h> #include <xen/sched.h> +#include <asm/event.h> #include <asm/hvm/hvm.h> #include <asm/hvm/support.h> #include <asm/hvm/vmx/vmx.h> @@ -23,35 +24,78 @@ struct realmode_emulate_ctxt { struct realmode_emulate_ctxt { struct x86_emulate_ctxt ctxt; - /* Cache of up to 31 bytes of instruction. */ - uint8_t insn_buf[31]; - uint8_t insn_buf_bytes; + /* Cache of 16 bytes of instruction. */ + uint8_t insn_buf[16]; unsigned long insn_buf_eip; struct segment_register seg_reg[10]; }; -static int realmode_translate_linear_addr( - enum x86_segment seg, - unsigned long offset, - unsigned int bytes, - enum hvm_access_type access_type, - struct realmode_emulate_ctxt *rm_ctxt, - unsigned long *paddr) -{ - struct segment_register *reg = &rm_ctxt->seg_reg[seg]; - int okay; - - okay = hvm_virtual_to_linear_addr( - seg, reg, offset, bytes, access_type, rm_ctxt->ctxt.addr_size, paddr); - - if ( !okay ) - { - hvm_inject_exception(TRAP_gp_fault, 0, 0); - return X86EMUL_EXCEPTION; - } - - return 0; +static void realmode_deliver_exception( + unsigned int vector, + unsigned int insn_len, + struct realmode_emulate_ctxt *rm_ctxt) +{ + struct segment_register *idtr = &rm_ctxt->seg_reg[x86_seg_idtr]; + struct segment_register *csr = &rm_ctxt->seg_reg[x86_seg_cs]; + struct cpu_user_regs *regs = rm_ctxt->ctxt.regs; + uint32_t cs_eip, pstk; + uint16_t frame[3]; + unsigned int last_byte; + + again: + last_byte = (vector * 4) + 3; + if ( idtr->limit < last_byte ) + { + /* Software interrupt? */ + if ( insn_len != 0 ) + { + insn_len = 0; + vector = TRAP_gp_fault; + goto again; + } + + /* Exception or hardware interrupt. */ + switch ( vector ) + { + case TRAP_double_fault: + hvm_triple_fault(); + return; + case TRAP_gp_fault: + vector = TRAP_double_fault; + goto again; + default: + vector = TRAP_gp_fault; + goto again; + } + } + + (void)hvm_copy_from_guest_phys(&cs_eip, idtr->base + vector * 4, 4); + + frame[0] = regs->eip + insn_len; + frame[1] = csr->sel; + frame[2] = regs->eflags & ~X86_EFLAGS_RF; + + if ( rm_ctxt->ctxt.addr_size == 32 ) + { + regs->esp -= 4; + pstk = regs->esp; + } + else + { + pstk = (uint16_t)(regs->esp - 4); + regs->esp &= ~0xffff; + regs->esp |= pstk; + } + + pstk += rm_ctxt->seg_reg[x86_seg_ss].base; + (void)hvm_copy_to_guest_phys(pstk, frame, sizeof(frame)); + + csr->sel = cs_eip >> 16; + csr->base = (uint32_t)csr->sel << 4; + regs->eip = (uint16_t)cs_eip; + regs->eflags &= ~(X86_EFLAGS_AC | X86_EFLAGS_TF | + X86_EFLAGS_AC | X86_EFLAGS_RF); } static int @@ -63,14 +107,7 @@ realmode_read( enum hvm_access_type access_type, struct realmode_emulate_ctxt *rm_ctxt) { - unsigned long addr; - int rc; - - rc = realmode_translate_linear_addr( - seg, offset, bytes, access_type, rm_ctxt, &addr); - if ( rc ) - return rc; - + uint32_t addr = rm_ctxt->seg_reg[seg].base + offset; *val = 0; (void)hvm_copy_from_guest_phys(val, addr, bytes); return X86EMUL_OKAY; @@ -102,7 +139,7 @@ realmode_emulate_insn_fetch( unsigned int insn_off = offset - rm_ctxt->insn_buf_eip; /* Fall back if requested bytes are not in the prefetch cache. */ - if ( unlikely((insn_off + bytes) > rm_ctxt->insn_buf_bytes) ) + if ( unlikely((insn_off + bytes) > sizeof(rm_ctxt->insn_buf)) ) return realmode_read( seg, offset, val, bytes, hvm_access_insn_fetch, rm_ctxt); @@ -123,14 +160,7 @@ realmode_emulate_write( { struct realmode_emulate_ctxt *rm_ctxt = container_of(ctxt, struct realmode_emulate_ctxt, ctxt); - unsigned long addr; - int rc; - - rc = realmode_translate_linear_addr( - seg, offset, bytes, hvm_access_write, rm_ctxt, &addr); - if ( rc ) - return rc; - + uint32_t addr = rm_ctxt->seg_reg[seg].base + offset; (void)hvm_copy_to_guest_phys(addr, &val, bytes); return X86EMUL_OKAY; } @@ -254,6 +284,31 @@ static int realmode_write_rflags( intr_shadow ^= VMX_INTR_SHADOW_STI; __vmwrite(GUEST_INTERRUPTIBILITY_INFO, intr_shadow); } + + return X86EMUL_OKAY; +} + +static int realmode_inject_hw_exception( + uint8_t vector, + struct x86_emulate_ctxt *ctxt) +{ + struct realmode_emulate_ctxt *rm_ctxt = + container_of(ctxt, struct realmode_emulate_ctxt, ctxt); + + realmode_deliver_exception(vector, 0, rm_ctxt); + + return X86EMUL_OKAY; +} + +static int realmode_inject_sw_interrupt( + uint8_t vector, + uint8_t insn_len, + struct x86_emulate_ctxt *ctxt) +{ + struct realmode_emulate_ctxt *rm_ctxt = + container_of(ctxt, struct realmode_emulate_ctxt, ctxt); + + realmode_deliver_exception(vector, insn_len, rm_ctxt); return X86EMUL_OKAY; } @@ -268,37 +323,44 @@ static struct x86_emulate_ops realmode_e .read_io = realmode_read_io, .write_io = realmode_write_io, .read_cr = realmode_read_cr, - .write_rflags = realmode_write_rflags + .write_rflags = realmode_write_rflags, + .inject_hw_exception = realmode_inject_hw_exception, + .inject_sw_interrupt = realmode_inject_sw_interrupt }; int vmx_realmode(struct cpu_user_regs *regs) { struct vcpu *curr = current; struct realmode_emulate_ctxt rm_ctxt; - unsigned long addr; + unsigned long intr_info; int i, rc = 0; + + rm_ctxt.ctxt.regs = regs; for ( i = 0; i < 10; i++ ) hvm_get_segment_register(curr, i, &rm_ctxt.seg_reg[i]); + rm_ctxt.ctxt.addr_size = + rm_ctxt.seg_reg[x86_seg_cs].attr.fields.db ? 32 : 16; + rm_ctxt.ctxt.sp_size = + rm_ctxt.seg_reg[x86_seg_ss].attr.fields.db ? 32 : 16; + + intr_info = __vmread(VM_ENTRY_INTR_INFO); + if ( intr_info & INTR_INFO_VALID_MASK ) + { + __vmwrite(VM_ENTRY_INTR_INFO, 0); + realmode_deliver_exception((uint8_t)intr_info, 0, &rm_ctxt); + } + while ( !(curr->arch.hvm_vcpu.guest_cr[0] & X86_CR0_PE) && - !softirq_pending(smp_processor_id()) ) - { - rm_ctxt.ctxt.regs = regs; - rm_ctxt.ctxt.addr_size = - rm_ctxt.seg_reg[x86_seg_cs].attr.fields.db ? 32 : 16; - rm_ctxt.ctxt.sp_size = - rm_ctxt.seg_reg[x86_seg_ss].attr.fields.db ? 32 : 16; - + !softirq_pending(smp_processor_id()) && + !hvm_local_events_need_delivery(curr) ) + { rm_ctxt.insn_buf_eip = regs->eip; - rm_ctxt.insn_buf_bytes = - (hvm_virtual_to_linear_addr( - x86_seg_cs, &rm_ctxt.seg_reg[x86_seg_cs], - regs->eip, sizeof(rm_ctxt.insn_buf), - hvm_access_insn_fetch, rm_ctxt.ctxt.addr_size, &addr) && - !hvm_copy_from_guest_virt( - rm_ctxt.insn_buf, addr, sizeof(rm_ctxt.insn_buf))) - ? sizeof(rm_ctxt.insn_buf) : 0; + (void)hvm_copy_from_guest_phys( + rm_ctxt.insn_buf, + (uint32_t)(rm_ctxt.seg_reg[x86_seg_cs].base + regs->eip), + sizeof(rm_ctxt.insn_buf)); rc = x86_emulate(&rm_ctxt.ctxt, &realmode_emulator_ops); @@ -308,7 +370,7 @@ int vmx_realmode(struct cpu_user_regs *r break; } - if ( rc ) + if ( rc == X86EMUL_UNHANDLEABLE ) { gdprintk(XENLOG_DEBUG, "RM %04x:%08lx: %02x %02x %02x %02x %02x %02x\n", diff -r d40788f07a4f -r f6a587e3d5c9 xen/arch/x86/x86_emulate.c --- a/xen/arch/x86/x86_emulate.c Sun Nov 25 12:43:13 2007 +0000 +++ b/xen/arch/x86/x86_emulate.c Sun Nov 25 18:05:10 2007 +0000 @@ -149,7 +149,7 @@ static uint8_t opcode_table[256] = { ImplicitOps, ImplicitOps, 0, 0, ByteOp|DstMem|SrcImm|ModRM|Mov, DstMem|SrcImm|ModRM|Mov, /* 0xC8 - 0xCF */ - 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, ImplicitOps, ImplicitOps, ImplicitOps, 0, /* 0xD0 - 0xD7 */ ByteOp|DstMem|SrcImplicit|ModRM, DstMem|SrcImplicit|ModRM, ByteOp|DstMem|SrcImplicit|ModRM, DstMem|SrcImplicit|ModRM, @@ -163,7 +163,7 @@ static uint8_t opcode_table[256] = { ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps, /* 0xF0 - 0xF7 */ - 0, 0, 0, 0, + 0, ImplicitOps, 0, 0, 0, ImplicitOps, ByteOp|DstMem|SrcNone|ModRM, DstMem|SrcNone|ModRM, /* 0xF8 - 0xFF */ ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps, @@ -270,6 +270,7 @@ struct operand { #define EFLG_OF (1<<11) #define EFLG_DF (1<<10) #define EFLG_IF (1<<9) +#define EFLG_TF (1<<8) #define EFLG_SF (1<<7) #define EFLG_ZF (1<<6) #define EFLG_AF (1<<4) @@ -278,6 +279,9 @@ struct operand { /* Exception definitions. */ #define EXC_DE 0 +#define EXC_DB 1 +#define EXC_BP 3 +#define EXC_OF 4 #define EXC_BR 5 #define EXC_UD 6 #define EXC_GP 13 @@ -477,8 +481,13 @@ do { if ( rc ) goto done; \ } while (0) -/* In future we will be able to generate arbitrary exceptions. */ -#define generate_exception_if(p, e) fail_if(p) +#define generate_exception_if(p, e) \ +({ if ( (p) ) { \ + fail_if(ops->inject_hw_exception == NULL); \ + rc = ops->inject_hw_exception(e, ctxt) ? : X86EMUL_EXCEPTION; \ + goto done; \ + } \ +}) /* Given byte has even parity (even number of 1s)? */ static int even_parity(uint8_t v) @@ -1771,7 +1780,11 @@ x86_emulate( /* Commit shadow register state. */ _regs.eflags &= ~EFLG_RF; *ctxt->regs = _regs; - /* FIXME generate_exception_if(_regs.eflags & EFLG_TF, EXC_DB); */ + + if ( (_regs.eflags & EFLG_TF) && + (rc == X86EMUL_OKAY) && + (ops->inject_hw_exception != NULL) ) + rc = ops->inject_hw_exception(EXC_DB, ctxt) ? : X86EMUL_EXCEPTION; done: return rc; @@ -2152,6 +2165,25 @@ x86_emulate( break; } + case 0xcc: /* int3 */ + src.val = EXC_BP; + goto swint; + + case 0xcd: /* int imm8 */ + src.val = insn_fetch_type(uint8_t); + swint: + fail_if(ops->inject_sw_interrupt == NULL); + rc = ops->inject_sw_interrupt(src.val, _regs.eip - ctxt->regs->eip, + ctxt) ? : X86EMUL_EXCEPTION; + goto done; + + case 0xce: /* into */ + generate_exception_if(mode_64bit(), EXC_UD); + if ( !(_regs.eflags & EFLG_OF) ) + break; + src.val = EXC_OF; + goto swint; + case 0xd4: /* aam */ { unsigned int base = insn_fetch_type(uint8_t); uint8_t al = _regs.eax; @@ -2291,6 +2323,10 @@ x86_emulate( case 0xeb: /* jmp (short) */ jmp_rel(insn_fetch_type(int8_t)); break; + + case 0xf1: /* int1 (icebp) */ + src.val = EXC_DB; + goto swint; case 0xf5: /* cmc */ _regs.eflags ^= EFLG_CF; diff -r d40788f07a4f -r f6a587e3d5c9 xen/include/asm-x86/x86_emulate.h --- a/xen/include/asm-x86/x86_emulate.h Sun Nov 25 12:43:13 2007 +0000 +++ b/xen/include/asm-x86/x86_emulate.h Sun Nov 25 18:05:10 2007 +0000 @@ -274,6 +274,17 @@ struct x86_emulate_ops /* wbinvd: Write-back and invalidate cache contents. */ int (*wbinvd)( struct x86_emulate_ctxt *ctxt); + + /* inject_hw_exception */ + int (*inject_hw_exception)( + uint8_t vector, + struct x86_emulate_ctxt *ctxt); + + /* inject_sw_interrupt */ + int (*inject_sw_interrupt)( + uint8_t vector, + uint8_t insn_len, + struct x86_emulate_ctxt *ctxt); }; struct cpu_user_regs; _______________________________________________ Xen-changelog mailing list Xen-changelog@xxxxxxxxxxxxxxxxxxx http://lists.xensource.com/xen-changelog
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |