diff -r d5eb5205ff35 -r bfb710d768eb xen/arch/x86/hvm/svm/svm.c --- a/xen/arch/x86/hvm/svm/svm.c Thu Aug 24 16:25:49 2006 +0100 +++ b/xen/arch/x86/hvm/svm/svm.c Fri Aug 25 11:57:57 2006 -0500 @@ -403,6 +403,50 @@ static inline int long_mode_do_msr_write return 1; } + +#define loaddebug(_v,_reg) \ + __asm__ __volatile__ ("mov %0,%%db" #_reg : : "r" ((_v)->debugreg[_reg])) +#define savedebug(_v,_reg) \ + __asm__ __volatile__ ("mov %%db" #_reg ",%0" : : "r" ((_v)->debugreg[_reg])) + + +static inline void svm_save_dr(struct vcpu *v) +{ + if (v->arch.hvm_vcpu.flag_dr_dirty) + { + /* clear the DR dirty flag and re-enable intercepts for DR accesses */ + v->arch.hvm_vcpu.flag_dr_dirty = 0; + v->arch.hvm_svm.vmcb->dr_intercepts = DR_INTERCEPT_ALL_WRITES; + + savedebug(&v->arch.guest_context, 0); + savedebug(&v->arch.guest_context, 1); + savedebug(&v->arch.guest_context, 2); + savedebug(&v->arch.guest_context, 3); + } +} + + +static inline void __restore_debug_registers(struct vcpu *v) +{ + loaddebug(&v->arch.guest_context, 0); + loaddebug(&v->arch.guest_context, 1); + loaddebug(&v->arch.guest_context, 2); + loaddebug(&v->arch.guest_context, 3); +} + + +static inline void svm_restore_dr(struct vcpu *v) +{ + struct vmcb_struct *vmcb = v->arch.hvm_svm.vmcb; + + if (!vmcb) + return; + + if (unlikely(vmcb->dr7 & 0xFF)) + __restore_debug_registers(v); +} + + static int svm_realmode(struct vcpu *v) { unsigned long cr0 = v->arch.hvm_svm.cpu_shadow_cr0; @@ -717,6 +761,7 @@ static void svm_ctxt_switch_from(struct static void svm_ctxt_switch_from(struct vcpu *v) { svm_freeze_time(v); + svm_save_dr(v); } static void svm_ctxt_switch_to(struct vcpu *v) @@ -732,6 +777,7 @@ static void svm_ctxt_switch_to(struct vc set_segment_register(es, 0); set_segment_register(ss, 0); #endif + svm_restore_dr(v); } @@ -1183,55 +1229,16 @@ static inline void set_reg(unsigned int } -static void svm_dr_access (struct vcpu *v, unsigned int reg, unsigned int type, - struct cpu_user_regs *regs) -{ - unsigned long *reg_p = 0; - unsigned int gpreg = 0; - unsigned long eip; - int inst_len; - int index; - struct vmcb_struct *vmcb; - u8 buffer[MAX_INST_LEN]; - u8 prefix = 0; - - vmcb = v->arch.hvm_svm.vmcb; - - ASSERT(vmcb); - - eip = vmcb->rip; - inst_copy_from_guest(buffer, svm_rip2pointer(vmcb), sizeof(buffer)); - index = skip_prefix_bytes(buffer, sizeof(buffer)); - - ASSERT(buffer[index+0] == 0x0f && (buffer[index+1] & 0xFD) == 0x21); - - if (index > 0 && (buffer[index-1] & 0xF0) == 0x40) - prefix = buffer[index-1]; - - gpreg = decode_src_reg(prefix, buffer[index + 2]); - ASSERT(reg == decode_dest_reg(prefix, buffer[index + 2])); - - HVM_DBG_LOG(DBG_LEVEL_1, "svm_dr_access : eip=%lx, reg=%d, gpreg = %x", - eip, reg, gpreg); - - reg_p = get_reg_p(gpreg, regs, vmcb); - - switch (type) - { - case TYPE_MOV_TO_DR: - inst_len = __get_instruction_length(vmcb, INSTR_MOV2DR, buffer); - v->arch.guest_context.debugreg[reg] = *reg_p; - break; - case TYPE_MOV_FROM_DR: - inst_len = __get_instruction_length(vmcb, INSTR_MOVDR2, buffer); - *reg_p = v->arch.guest_context.debugreg[reg]; - break; - default: - __hvm_bug(regs); - break; - } - ASSERT(inst_len > 0); - __update_guest_eip(vmcb, inst_len); +static void svm_dr_access(struct vcpu *v, struct cpu_user_regs *regs) +{ + struct vmcb_struct *vmcb = v->arch.hvm_svm.vmcb; + + v->arch.hvm_vcpu.flag_dr_dirty = 1; + + __restore_debug_registers(v); + + /* allow the guest full access to the debug registers */ + vmcb->dr_intercepts = 0; } @@ -2862,53 +2869,9 @@ asmlinkage void svm_vmexit_handler(struc case VMEXIT_CR8_WRITE: svm_cr_access(v, 8, TYPE_MOV_TO_CR, ®s); break; - - case VMEXIT_DR0_READ: - svm_dr_access(v, 0, TYPE_MOV_FROM_DR, ®s); - break; - - case VMEXIT_DR1_READ: - svm_dr_access(v, 1, TYPE_MOV_FROM_DR, ®s); - break; - - case VMEXIT_DR2_READ: - svm_dr_access(v, 2, TYPE_MOV_FROM_DR, ®s); - break; - - case VMEXIT_DR3_READ: - svm_dr_access(v, 3, TYPE_MOV_FROM_DR, ®s); - break; - - case VMEXIT_DR6_READ: - svm_dr_access(v, 6, TYPE_MOV_FROM_DR, ®s); - break; - - case VMEXIT_DR7_READ: - svm_dr_access(v, 7, TYPE_MOV_FROM_DR, ®s); - break; - - case VMEXIT_DR0_WRITE: - svm_dr_access(v, 0, TYPE_MOV_TO_DR, ®s); - break; - - case VMEXIT_DR1_WRITE: - svm_dr_access(v, 1, TYPE_MOV_TO_DR, ®s); - break; - - case VMEXIT_DR2_WRITE: - svm_dr_access(v, 2, TYPE_MOV_TO_DR, ®s); - break; - - case VMEXIT_DR3_WRITE: - svm_dr_access(v, 3, TYPE_MOV_TO_DR, ®s); - break; - - case VMEXIT_DR6_WRITE: - svm_dr_access(v, 6, TYPE_MOV_TO_DR, ®s); - break; - - case VMEXIT_DR7_WRITE: - svm_dr_access(v, 7, TYPE_MOV_TO_DR, ®s); + + case VMEXIT_DR0_WRITE ... VMEXIT_DR7_WRITE: + svm_dr_access(v, ®s); break; case VMEXIT_IOIO: diff -r d5eb5205ff35 -r bfb710d768eb xen/arch/x86/hvm/svm/vmcb.c --- a/xen/arch/x86/hvm/svm/vmcb.c Thu Aug 24 16:25:49 2006 +0100 +++ b/xen/arch/x86/hvm/svm/vmcb.c Fri Aug 25 11:57:57 2006 -0500 @@ -121,7 +121,7 @@ static int construct_vmcb_controls(struc GENERAL2_INTERCEPT_SKINIT | GENERAL2_INTERCEPT_RDTSCP; /* read or write all debug registers 0 - 15 */ - vmcb->dr_intercepts = 0; + vmcb->dr_intercepts = DR_INTERCEPT_ALL_WRITES; /* RD/WR all control registers 0 - 15, but not read CR2 */ vmcb->cr_intercepts = ~(CR_INTERCEPT_CR2_READ | CR_INTERCEPT_CR2_WRITE); diff -r d5eb5205ff35 -r bfb710d768eb xen/include/asm-x86/hvm/svm/vmcb.h --- a/xen/include/asm-x86/hvm/svm/vmcb.h Thu Aug 24 16:25:49 2006 +0100 +++ b/xen/include/asm-x86/hvm/svm/vmcb.h Fri Aug 25 11:57:57 2006 -0500 @@ -113,6 +113,51 @@ enum CRInterceptBits CR_INTERCEPT_CR14_WRITE = 1 << 30, CR_INTERCEPT_CR15_WRITE = 1 << 31, }; + + +/* debug register intercepts */ +enum DRInterceptBits +{ + DR_INTERCEPT_DR0_READ = 1 << 0, + DR_INTERCEPT_DR1_READ = 1 << 1, + DR_INTERCEPT_DR2_READ = 1 << 2, + DR_INTERCEPT_DR3_READ = 1 << 3, + DR_INTERCEPT_DR4_READ = 1 << 4, + DR_INTERCEPT_DR5_READ = 1 << 5, + DR_INTERCEPT_DR6_READ = 1 << 6, + DR_INTERCEPT_DR7_READ = 1 << 7, + DR_INTERCEPT_DR8_READ = 1 << 8, + DR_INTERCEPT_DR9_READ = 1 << 9, + DR_INTERCEPT_DR10_READ = 1 << 10, + DR_INTERCEPT_DR11_READ = 1 << 11, + DR_INTERCEPT_DR12_READ = 1 << 12, + DR_INTERCEPT_DR13_READ = 1 << 13, + DR_INTERCEPT_DR14_READ = 1 << 14, + DR_INTERCEPT_DR15_READ = 1 << 15, + DR_INTERCEPT_DR0_WRITE = 1 << 16, + DR_INTERCEPT_DR1_WRITE = 1 << 17, + DR_INTERCEPT_DR2_WRITE = 1 << 18, + DR_INTERCEPT_DR3_WRITE = 1 << 19, + DR_INTERCEPT_DR4_WRITE = 1 << 20, + DR_INTERCEPT_DR5_WRITE = 1 << 21, + DR_INTERCEPT_DR6_WRITE = 1 << 22, + DR_INTERCEPT_DR7_WRITE = 1 << 23, + DR_INTERCEPT_DR8_WRITE = 1 << 24, + DR_INTERCEPT_DR9_WRITE = 1 << 25, + DR_INTERCEPT_DR10_WRITE = 1 << 26, + DR_INTERCEPT_DR11_WRITE = 1 << 27, + DR_INTERCEPT_DR12_WRITE = 1 << 28, + DR_INTERCEPT_DR13_WRITE = 1 << 29, + DR_INTERCEPT_DR14_WRITE = 1 << 30, + DR_INTERCEPT_DR15_WRITE = 1 << 31, +}; + +/* for lazy save/restore we'd like to intercept all DR writes */ +#define DR_INTERCEPT_ALL_WRITES \ + (DR_INTERCEPT_DR0_WRITE|DR_INTERCEPT_DR1_WRITE|DR_INTERCEPT_DR2_WRITE \ + |DR_INTERCEPT_DR3_WRITE|DR_INTERCEPT_DR4_WRITE|DR_INTERCEPT_DR5_WRITE \ + |DR_INTERCEPT_DR6_WRITE|DR_INTERCEPT_DR7_WRITE) + enum VMEXIT_EXITCODE {