File xen-amd-v-menu-timer-issue.patch of Package kernel
Date: Wed, 25 Oct 2006 15:50:30 -0400
From: Bhavana Nagendra <bnagendr@redhat.com>
Subject: RHEL5 PATCH: AMD-V windows guest boot menu timer issue
AMD-V does not require the delaying of interrupt injection if the guest
IF_FLAG disallows interrupts. Remove the code in svm_intr_assist()
that was checking the guest IF in eflags.
This patch fixes the problem with HVM Windows guests, with observing a
very slow timer countdown on the initial boot menu, when there is more
than one boot option. Kbd response in this same Windows boot menu is
also acceptably responsive with this patch.
The upstream patches are in xen-unstable and applies cleanly to change
set 11831. I have created a single patch and it applies cleanly to
2.6.18-1.2736.el5. Please review and ACK for milestone 7.
--- xen/arch/x86/hvm/svm/intr.c.orig 2006-10-25 12:59:39.000000000 -0400
+++ xen/arch/x86/hvm/svm/intr.c 2006-10-25 14:21:39.000000000 -0400
@@ -43,7 +43,7 @@
* to be suitable for SVM.
*/
-static inline int svm_inject_extint(struct vcpu *v, int trap, int error_code)
+static inline int svm_inject_extint(struct vcpu *v, int trap)
{
struct vmcb_struct *vmcb = v->arch.hvm_svm.vmcb;
vintr_t intr;
@@ -74,7 +74,6 @@ asmlinkage void svm_intr_assist(void)
int intr_type = APIC_DM_EXTINT;
int intr_vector = -1;
int re_injecting = 0;
- unsigned long rflags;
ASSERT(vmcb);
@@ -82,19 +81,28 @@ asmlinkage void svm_intr_assist(void)
/* Previous Interrupt delivery caused this Intercept? */
if (vmcb->exitintinfo.fields.v && (vmcb->exitintinfo.fields.type == 0)) {
v->arch.hvm_svm.saved_irq_vector = vmcb->exitintinfo.fields.vector;
-// printk("Injecting PF#: saving IRQ from ExitInfo\n");
vmcb->exitintinfo.bytes = 0;
re_injecting = 1;
}
- /* Guest's interrputs masked? */
- rflags = vmcb->rflags;
- if (irq_masked(rflags)) {
- HVM_DBG_LOG(DBG_LEVEL_1, "Guest IRQs masked: rflags: %lx", rflags);
- /* bail out, we won't be injecting an interrupt this time */
+ /*
+ * If event requires injecting then do not inject int.
+ */
+ if (unlikely(v->arch.hvm_svm.inject_event)) {
+ v->arch.hvm_svm.inject_event = 0;
return;
}
-
+
+ /*
+ * create a 'fake' virtual interrupt on to intercept as soon
+ * as the guest _can_ take interrupts
+ */
+ if (irq_masked(vmcb->rflags) || vmcb->interrupt_shadow) {
+ vmcb->general1_intercepts |= GENERAL1_INTERCEPT_VINTR;
+ svm_inject_extint(v, 0x0); /* actual vector doesn't really matter */
+ return;
+ }
+
/* Previous interrupt still pending? */
if (vmcb->vintr.fields.irq) {
// printk("Re-injecting IRQ from Vintr\n");
@@ -146,8 +154,7 @@ asmlinkage void svm_intr_assist(void)
}
/* let's inject this interrupt */
TRACE_3D(TRC_VMX_INT, v->domain->domain_id, intr_vector, 0);
- svm_inject_extint(v, intr_vector, VMX_DELIVER_NO_ERROR_CODE);
- hvm_interrupt_post(v, intr_vector, intr_type);
+ svm_inject_extint(v, intr_vector);
break;
case APIC_DM_SMI:
case APIC_DM_NMI:
@@ -158,6 +165,7 @@ asmlinkage void svm_intr_assist(void)
BUG();
break;
}
+ hvm_interrupt_post(v, intr_vector, intr_type);
}
}
--- xen/arch/x86/hvm/svm/svm.c.orig 2006-10-25 13:00:04.000000000 -0400
+++ xen/arch/x86/hvm/svm/svm.c 2006-10-25 14:17:09.000000000 -0400
@@ -196,6 +196,7 @@ static inline void svm_inject_exception(
ASSERT(vmcb->eventinj.fields.v == 0);
vmcb->eventinj = event;
+ v->arch.hvm_svm.inject_event=1;
}
static void stop_svm(void)
@@ -2590,6 +2591,7 @@ asmlinkage void svm_vmexit_handler(struc
vmcb->tlb_control = 1;
+ v->arch.hvm_svm.inject_event = 0;
if (exit_reason == VMEXIT_INVALID)
{
@@ -2802,6 +2804,11 @@ asmlinkage void svm_vmexit_handler(struc
svm_inject_exception(v, TRAP_double_fault, 1, 0);
break;
+ case VMEXIT_VINTR:
+ vmcb->vintr.fields.irq = 0;
+ vmcb->general1_intercepts &= ~GENERAL1_INTERCEPT_VINTR;
+ break;
+
case VMEXIT_INTR:
break;
--- xen/include/asm-x86/hvm/svm/vmcb.h.orig 2006-10-25 14:17:39.000000000 -0400
+++ xen/include/asm-x86/hvm/svm/vmcb.h 2006-10-25 14:18:30.000000000 -0400
@@ -484,6 +484,7 @@ struct arch_svm_struct {
u32 *msrpm;
u64 vmexit_tsc; /* tsc read at #VMEXIT. for TSC_OFFSET */
int saved_irq_vector;
+ u32 inject_event;
u32 launch_core;
u32 asid_core;