# HG changeset patch # User Travis Betak # Date 1188580751 18000 # Node ID fa50fc74c4841bda6f06411eefbd476f7b14372e # Parent a1cfbb3b438df667d5f6a5b02b78ceb3a5551c38 [SVM] Greatly reduce total number of CR8 intercepts This patch reduces the number of CR8 intercept to a fraction of the number of CR8 intercepts without. First, CR8 read intercepts are completely disabled since the SVM vTPR is kept kept in sync with the HVM vLAPIC TPR. Second, CR8 write intercepts are enabled and disabled based upon certain conditions. Most of the time, CR8 write intercepts are disabled. They are enabled only when there is a pending interrupt that can't be delivered because of either the current ISR or TPR (aka PPR) because this is the only time the TPR matters. With this patch, the number of CR8 intercepts dropped from around 10,000,000 to around 6,000 during boot of Windows 2003 Server 64-bit (this is a rough estimate). Signed-off-by: Travis Betak diff -r a1cfbb3b438d -r fa50fc74c484 xen/arch/x86/hvm/svm/intr.c --- a/xen/arch/x86/hvm/svm/intr.c Fri Aug 31 11:49:50 2007 -0500 +++ b/xen/arch/x86/hvm/svm/intr.c Fri Aug 31 12:19:11 2007 -0500 @@ -30,6 +30,7 @@ #include #include #include +#include #include #include #include @@ -103,8 +104,19 @@ asmlinkage void svm_intr_assist(void) { struct vcpu *v = current; struct vmcb_struct *vmcb = v->arch.hvm_svm.vmcb; + struct vlapic *vlapic = vcpu_vlapic(v); enum hvm_intack intr_source; int intr_vector; + vintr_t *intr = &vmcb->vintr; + + /* + * 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(vlapic, APIC_TASKPRI, (intr->fields.tpr & 0x0F) << 4); /* Crank the handle on interrupt state. */ pt_update_irq(v); @@ -113,7 +125,22 @@ asmlinkage void svm_intr_assist(void) do { intr_source = hvm_vcpu_has_pending_irq(v); if ( likely(intr_source == hvm_intack_none) ) + { + /* + * Before we return, let's check if there is a pending interrupt + * that just happens to be blocked (either ISR or TPR aka PPR). + * Enable CR8 write intercepts in case the guest unmasks the + * pending interrupt. + */ + if ( vlapic_enabled(vlapic) + && (vlapic_find_highest_irr(vlapic) != -1) ) + vmcb->cr_intercepts |= CR_INTERCEPT_CR8_WRITE; + return; + } + + /* It should be fairly safe to disable CR8 write intercepts here */ + vmcb->cr_intercepts &= ~CR_INTERCEPT_CR8_WRITE; /* * Pending IRQs must be delayed if: diff -r a1cfbb3b438d -r fa50fc74c484 xen/arch/x86/hvm/svm/vmcb.c --- a/xen/arch/x86/hvm/svm/vmcb.c Fri Aug 31 11:49:50 2007 -0500 +++ b/xen/arch/x86/hvm/svm/vmcb.c Fri Aug 31 12:19:11 2007 -0500 @@ -129,8 +129,13 @@ static int construct_vmcb(struct vcpu *v /* Intercept all debug-register writes. */ vmcb->dr_intercepts = DR_INTERCEPT_ALL_WRITES; - /* 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));