86 lines
3.6 KiB
Diff
86 lines
3.6 KiB
Diff
[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. 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 <travis.betak@amd.com>
|
|
|
|
Index: xen-3.1-testing/xen/arch/x86/hvm/svm/intr.c
|
|
===================================================================
|
|
--- xen-3.1-testing.orig/xen/arch/x86/hvm/svm/intr.c
|
|
+++ xen-3.1-testing/xen/arch/x86/hvm/svm/intr.c
|
|
@@ -63,9 +63,20 @@ static inline int svm_inject_extint(stru
|
|
asmlinkage void svm_intr_assist(void)
|
|
{
|
|
struct vcpu *v = current;
|
|
+ struct vlapic *vlapic = vcpu_vlapic(v);
|
|
struct vmcb_struct *vmcb = v->arch.hvm_svm.vmcb;
|
|
int intr_type = APIC_DM_EXTINT;
|
|
int intr_vector = -1;
|
|
+ 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);
|
|
|
|
/*
|
|
* Previous Interrupt delivery caused this intercept?
|
|
@@ -98,7 +109,22 @@ asmlinkage void svm_intr_assist(void)
|
|
pt_update_irq(v);
|
|
hvm_set_callback_irq_level();
|
|
if ( !cpu_has_pending_irq(v) )
|
|
+ {
|
|
+ /*
|
|
+ * 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;
|
|
|
|
/*
|
|
* If the guest can't take an interrupt right now, create a 'fake'
|
|
Index: xen-3.1-testing/xen/arch/x86/hvm/svm/vmcb.c
|
|
===================================================================
|
|
--- xen-3.1-testing.orig/xen/arch/x86/hvm/svm/vmcb.c
|
|
+++ xen-3.1-testing/xen/arch/x86/hvm/svm/vmcb.c
|
|
@@ -130,8 +130,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));
|