# HG changeset patch # User Travis Betak # Date 1197416888 21600 # Node ID 49a4b1b62ecbe6540dc6880f70522b0759726f9a # Parent f4dc0d3dfb0f594e91af79952c65348784aaeb72 This is a backport of changeset 15844 in the unstable tree. It disables CR8 read intercpets and selectively enables/disables CR8 write intercpets based upon pending interrupt conditions. Signed-off-by: Travis Betak diff -r f4dc0d3dfb0f -r 49a4b1b62ecb xen/arch/x86/hvm/svm/intr.c --- a/xen/arch/x86/hvm/svm/intr.c Sat Dec 08 17:23:05 2007 +0000 +++ b/xen/arch/x86/hvm/svm/intr.c Tue Dec 11 17:48:08 2007 -0600 @@ -31,6 +31,7 @@ #include #include #include +#include #include #include #include @@ -59,6 +60,32 @@ static inline int svm_inject_extint(stru return 0; } + +static void update_cr8_intercept( + struct vcpu *v, int intr_window_enabled) +{ + struct vmcb_struct *vmcb = v->arch.hvm_svm.vmcb; + struct vlapic *vlapic = vcpu_vlapic(v); + int max_irr; + + vmcb->cr_intercepts &= ~CR_INTERCEPT_CR8_WRITE; + + /* + * If ExtInts are masked then that dominates the TPR --- the 'interrupt + * window' has already been enabled in this case. + */ + if ( intr_window_enabled ) + return; + + /* Is there an interrupt pending at the LAPIC? Nothing to do if not. */ + if ( !vlapic_enabled(vlapic) || + ((max_irr = vlapic_find_highest_irr(vlapic)) == -1) ) + return; + + /* Highest-priority pending interrupt is masked by the TPR? */ + if ( (vmcb->vintr.fields.tpr & 0xf) >= (max_irr >> 4) ) + vmcb->cr_intercepts |= CR_INTERCEPT_CR8_WRITE; +} asmlinkage void svm_intr_assist(void) { @@ -66,6 +93,7 @@ asmlinkage void svm_intr_assist(void) struct vmcb_struct *vmcb = v->arch.hvm_svm.vmcb; int intr_type = APIC_DM_EXTINT; int intr_vector = -1; + int intr_window_enabled = 0; /* * Previous Interrupt delivery caused this intercept? @@ -83,7 +111,7 @@ asmlinkage void svm_intr_assist(void) vmcb->exitintinfo.bytes = 0; HVMTRACE_1D(REINJ_VIRQ, v, intr_vector); svm_inject_extint(v, intr_vector); - return; + goto out; } /* @@ -92,13 +120,13 @@ asmlinkage void svm_intr_assist(void) * external physical interrupt was pending when we executed VMRUN. */ if ( vmcb->vintr.fields.irq ) - return; + goto out; /* Crank the handle on interrupt state and check for new interrrupts. */ pt_update_irq(v); hvm_set_callback_irq_level(); if ( !cpu_has_pending_irq(v) ) - return; + goto out; /* * If the guest can't take an interrupt right now, create a 'fake' @@ -122,7 +150,8 @@ asmlinkage void svm_intr_assist(void) vmcb->general1_intercepts |= GENERAL1_INTERCEPT_VINTR; HVMTRACE_2D(INJ_VIRQ, v, 0x0, /*fake=*/ 1); svm_inject_extint(v, 0x0); /* actual vector doesn't matter */ - return; + intr_window_enabled = 1; + goto out; } /* Okay, we can deliver the interrupt: grab it and update PIC state. */ @@ -133,6 +162,9 @@ asmlinkage void svm_intr_assist(void) svm_inject_extint(v, intr_vector); pt_intr_post(v, intr_vector, intr_type); + + out: + update_cr8_intercept(v, intr_window_enabled); } /* diff -r f4dc0d3dfb0f -r 49a4b1b62ecb xen/arch/x86/hvm/svm/svm.c --- a/xen/arch/x86/hvm/svm/svm.c Sat Dec 08 17:23:05 2007 +0000 +++ b/xen/arch/x86/hvm/svm/svm.c Tue Dec 11 17:48:08 2007 -0600 @@ -2422,6 +2422,16 @@ asmlinkage void svm_vmexit_handler(struc struct vmcb_struct *vmcb = v->arch.hvm_svm.vmcb; int inst_len, rc; + /* + * Before doing anything else, we need to sync up the VLAPIC's TPR with + * SVM's vTPR if CR8 writes are currently disabled. It's OK if the + * guest doesn't touch the CR8 (e.g. 32-bit Windows) because we update + * the vTPR on MMIO writes to the TPR + */ + if ( !(vmcb->cr_intercepts & CR_INTERCEPT_CR8_WRITE) ) + vlapic_set_reg(vcpu_vlapic(v), APIC_TASKPRI, + (vmcb->vintr.fields.tpr & 0x0F) << 4); + exit_reason = vmcb->exitcode; HVMTRACE_2D(VMEXIT, v, vmcb->rip, exit_reason); diff -r f4dc0d3dfb0f -r 49a4b1b62ecb xen/arch/x86/hvm/svm/vmcb.c --- a/xen/arch/x86/hvm/svm/vmcb.c Sat Dec 08 17:23:05 2007 +0000 +++ b/xen/arch/x86/hvm/svm/vmcb.c Tue Dec 11 17:48:08 2007 -0600 @@ -131,8 +131,14 @@ static int construct_vmcb(struct vcpu *v /* Intercept all debug-register writes. */ vmcb->dr_intercepts = ~0u; - /* Intercept all control-register accesses, except to CR2. */ - vmcb->cr_intercepts = ~(CR_INTERCEPT_CR2_READ | CR_INTERCEPT_CR2_WRITE); + /* + * Intercept all control-register accesses except for CR2 reads/writes + * and CR8 reads (and actually CR8 writes, but that's a special case + * that's handled in svm/intr.c). + */ + vmcb->cr_intercepts = ~(CR_INTERCEPT_CR2_READ | + CR_INTERCEPT_CR2_WRITE | + CR_INTERCEPT_CR8_READ); /* I/O and MSR permission bitmaps. */ arch_svm->msrpm = alloc_xenheap_pages(get_order_from_bytes(MSRPM_SIZE));