From b410060a395356eb4bca3ae31de7acb8c261b3f1 Mon Sep 17 00:00:00 2001
From: Sheng Yang <[EMAIL PROTECTED]>
Date: Thu, 15 May 2008 18:23:27 +0800
Subject: [PATCH] KVM: Enable NMI Watchdog by PIT source

The NMI watchdog used LINT0 of LAPIC to deliver NMI. It didn't disable PIC 
after
switch to IOAPIC, but program LVT0 of every LAPIC as NMI, then deliver PIT
interrupt to LINT0. So NMIs got the same generate freqency as PIT interrupts.

The patch emulated this process and enabled NMI watchdog. For currently KVM, 
in
fact we didn't connected PIC to LAPIC, so the patch bypassed PIC, sent the
signal directly to the LAPIC.

Signed-off-by: Sheng Yang <[EMAIL PROTECTED]>
---
 arch/x86/kvm/i8254.c |   16 ++++++++++++++++
 arch/x86/kvm/irq.h   |    1 +
 arch/x86/kvm/lapic.c |   32 ++++++++++++++++++++++++++++----
 3 files changed, 45 insertions(+), 4 deletions(-)

diff --git a/arch/x86/kvm/i8254.c b/arch/x86/kvm/i8254.c
index 6d6dc6c..7c6ea62 100644
--- a/arch/x86/kvm/i8254.c
+++ b/arch/x86/kvm/i8254.c
@@ -563,12 +563,28 @@ void kvm_free_pit(struct kvm *kvm)

 static void __inject_pit_timer_intr(struct kvm *kvm)
 {
+       int i;
+       struct kvm_vcpu *vcpu;
+
        mutex_lock(&kvm->lock);
        kvm_ioapic_set_irq(kvm->arch.vioapic, 0, 1);
        kvm_ioapic_set_irq(kvm->arch.vioapic, 0, 0);
        kvm_pic_set_irq(pic_irqchip(kvm), 0, 1);
        kvm_pic_set_irq(pic_irqchip(kvm), 0, 0);
        mutex_unlock(&kvm->lock);
+
+       /*
+        * For NMI watchdog in IOAPIC mode
+        * After IOAPIC enabled, NMI watchdog programmed LVT0 of lapic as NMI,
+        * then a timer interrupt through IOAPIC and a NMI through PIC to lapic
+        * would be delivered when PIT time up.
+        */
+       for (i = 0; i < KVM_MAX_VCPUS; ++i) {
+               vcpu = kvm->vcpus[i];
+               if (!vcpu)
+                       continue;
+               kvm_apic_local_deliver(vcpu, APIC_LVT0);
+       }
 }

 void kvm_inject_pit_timer_irqs(struct kvm_vcpu *vcpu)
diff --git a/arch/x86/kvm/irq.h b/arch/x86/kvm/irq.h
index 1802134..7066660 100644
--- a/arch/x86/kvm/irq.h
+++ b/arch/x86/kvm/irq.h
@@ -84,6 +84,7 @@ void kvm_timer_intr_post(struct kvm_vcpu *vcpu, int vec);
 void kvm_inject_pending_timer_irqs(struct kvm_vcpu *vcpu);
 void kvm_inject_apic_timer_irqs(struct kvm_vcpu *vcpu);
 void __kvm_migrate_apic_timer(struct kvm_vcpu *vcpu);
+int kvm_apic_local_deliver(struct kvm_vcpu *vcpu, int lvt_type);

 int pit_has_pending_timer(struct kvm_vcpu *vcpu);
 int apic_has_pending_timer(struct kvm_vcpu *vcpu);
diff --git a/arch/x86/kvm/lapic.c b/arch/x86/kvm/lapic.c
index 2273836..62f70a1 100644
--- a/arch/x86/kvm/lapic.c
+++ b/arch/x86/kvm/lapic.c
@@ -388,6 +388,14 @@ static int __apic_accept_irq(struct kvm_lapic *apic, int 
delivery_mode,
                }
                break;

+       case APIC_DM_EXTINT:
+               /*
+                * Should only be called by kvm_apic_local_deliver() with LVT0,
+                * before NMI watchdog was enabled. Already handled by
+                * kvm_apic_accept_pic_intr().
+                */
+               break;
+
        default:
                printk(KERN_ERR "TODO: unsupported delivery mode %x\n",
                       delivery_mode);
@@ -753,6 +761,9 @@ static void apic_mmio_write(struct kvm_io_device *this,
        case APIC_LVTTHMR:
        case APIC_LVTPC:
        case APIC_LVT0:
+               if (val == APIC_DM_NMI)
+                       apic_debug("Receive NMI setting on APIC_LVT0 "
+                               "for cpu %d\n", apic->vcpu->vcpu_id);
        case APIC_LVT1:
        case APIC_LVTERR:
                /* TODO: Check vector */
@@ -968,12 +979,25 @@ int apic_has_pending_timer(struct kvm_vcpu *vcpu)
        return 0;
 }

-static int __inject_apic_timer_irq(struct kvm_lapic *apic)
+int kvm_apic_local_deliver(struct kvm_vcpu *vcpu, int lvt_type)
 {
-       int vector;
+       struct kvm_lapic *apic = vcpu->arch.apic;
+       int vector, mode, trig_mode;
+       u32 reg;
+
+       if (apic && apic_enabled(apic)) {
+               reg = apic_get_reg(apic, lvt_type);
+               vector = reg & APIC_VECTOR_MASK;
+               mode = reg & APIC_MODE_MASK;
+               trig_mode = reg & APIC_LVT_LEVEL_TRIGGER;
+               return __apic_accept_irq(apic, mode, vector, 1, trig_mode);
+       }
+       return 0;
+}

-       vector = apic_lvt_vector(apic, APIC_LVTT);
-       return __apic_accept_irq(apic, APIC_DM_FIXED, vector, 1, 0);
+static int __inject_apic_timer_irq(struct kvm_lapic *apic)
+{
+       return kvm_apic_local_deliver(apic->vcpu, APIC_LVTT);
 }

 static enum hrtimer_restart apic_timer_fn(struct hrtimer *data)
--
1.5.5

From b410060a395356eb4bca3ae31de7acb8c261b3f1 Mon Sep 17 00:00:00 2001
From: Sheng Yang <[EMAIL PROTECTED]>
Date: Thu, 15 May 2008 18:23:27 +0800
Subject: [PATCH] KVM: Enable NMI Watchdog by PIT source

The NMI watchdog used LINT0 of LAPIC to deliver NMI. It didn't disable PIC after
switch to IOAPIC, but program LVT0 of every LAPIC as NMI, then deliver PIT
interrupt to LINT0. So NMIs got the same generate freqency as PIT interrupts.

The patch emulated this process and enabled NMI watchdog. For currently KVM, in
fact we didn't connected PIC to LAPIC, so the patch bypassed PIC, sent the
signal directly to the LAPIC.

Signed-off-by: Sheng Yang <[EMAIL PROTECTED]>
---
 arch/x86/kvm/i8254.c |   16 ++++++++++++++++
 arch/x86/kvm/irq.h   |    1 +
 arch/x86/kvm/lapic.c |   32 ++++++++++++++++++++++++++++----
 3 files changed, 45 insertions(+), 4 deletions(-)

diff --git a/arch/x86/kvm/i8254.c b/arch/x86/kvm/i8254.c
index 6d6dc6c..7c6ea62 100644
--- a/arch/x86/kvm/i8254.c
+++ b/arch/x86/kvm/i8254.c
@@ -563,12 +563,28 @@ void kvm_free_pit(struct kvm *kvm)
 
 static void __inject_pit_timer_intr(struct kvm *kvm)
 {
+	int i;
+	struct kvm_vcpu *vcpu;
+
 	mutex_lock(&kvm->lock);
 	kvm_ioapic_set_irq(kvm->arch.vioapic, 0, 1);
 	kvm_ioapic_set_irq(kvm->arch.vioapic, 0, 0);
 	kvm_pic_set_irq(pic_irqchip(kvm), 0, 1);
 	kvm_pic_set_irq(pic_irqchip(kvm), 0, 0);
 	mutex_unlock(&kvm->lock);
+
+	/*
+	 * For NMI watchdog in IOAPIC mode
+	 * After IOAPIC enabled, NMI watchdog programmed LVT0 of lapic as NMI,
+	 * then a timer interrupt through IOAPIC and a NMI through PIC to lapic
+	 * would be delivered when PIT time up.
+	 */
+	for (i = 0; i < KVM_MAX_VCPUS; ++i) {
+		vcpu = kvm->vcpus[i];
+		if (!vcpu)
+			continue;
+		kvm_apic_local_deliver(vcpu, APIC_LVT0);
+	}
 }
 
 void kvm_inject_pit_timer_irqs(struct kvm_vcpu *vcpu)
diff --git a/arch/x86/kvm/irq.h b/arch/x86/kvm/irq.h
index 1802134..7066660 100644
--- a/arch/x86/kvm/irq.h
+++ b/arch/x86/kvm/irq.h
@@ -84,6 +84,7 @@ void kvm_timer_intr_post(struct kvm_vcpu *vcpu, int vec);
 void kvm_inject_pending_timer_irqs(struct kvm_vcpu *vcpu);
 void kvm_inject_apic_timer_irqs(struct kvm_vcpu *vcpu);
 void __kvm_migrate_apic_timer(struct kvm_vcpu *vcpu);
+int kvm_apic_local_deliver(struct kvm_vcpu *vcpu, int lvt_type);
 
 int pit_has_pending_timer(struct kvm_vcpu *vcpu);
 int apic_has_pending_timer(struct kvm_vcpu *vcpu);
diff --git a/arch/x86/kvm/lapic.c b/arch/x86/kvm/lapic.c
index 2273836..62f70a1 100644
--- a/arch/x86/kvm/lapic.c
+++ b/arch/x86/kvm/lapic.c
@@ -388,6 +388,14 @@ static int __apic_accept_irq(struct kvm_lapic *apic, int delivery_mode,
 		}
 		break;
 
+	case APIC_DM_EXTINT:
+		/*
+		 * Should only be called by kvm_apic_local_deliver() with LVT0,
+		 * before NMI watchdog was enabled. Already handled by
+		 * kvm_apic_accept_pic_intr().
+		 */
+		break;
+
 	default:
 		printk(KERN_ERR "TODO: unsupported delivery mode %x\n",
 		       delivery_mode);
@@ -753,6 +761,9 @@ static void apic_mmio_write(struct kvm_io_device *this,
 	case APIC_LVTTHMR:
 	case APIC_LVTPC:
 	case APIC_LVT0:
+		if (val == APIC_DM_NMI)
+			apic_debug("Receive NMI setting on APIC_LVT0 "
+				"for cpu %d\n", apic->vcpu->vcpu_id);
 	case APIC_LVT1:
 	case APIC_LVTERR:
 		/* TODO: Check vector */
@@ -968,12 +979,25 @@ int apic_has_pending_timer(struct kvm_vcpu *vcpu)
 	return 0;
 }
 
-static int __inject_apic_timer_irq(struct kvm_lapic *apic)
+int kvm_apic_local_deliver(struct kvm_vcpu *vcpu, int lvt_type)
 {
-	int vector;
+	struct kvm_lapic *apic = vcpu->arch.apic;
+	int vector, mode, trig_mode;
+	u32 reg;
+
+	if (apic && apic_enabled(apic)) {
+		reg = apic_get_reg(apic, lvt_type);
+		vector = reg & APIC_VECTOR_MASK;
+		mode = reg & APIC_MODE_MASK;
+		trig_mode = reg & APIC_LVT_LEVEL_TRIGGER;
+		return __apic_accept_irq(apic, mode, vector, 1, trig_mode);
+	}
+	return 0;
+}
 
-	vector = apic_lvt_vector(apic, APIC_LVTT);
-	return __apic_accept_irq(apic, APIC_DM_FIXED, vector, 1, 0);
+static int __inject_apic_timer_irq(struct kvm_lapic *apic)
+{
+	return kvm_apic_local_deliver(apic->vcpu, APIC_LVTT);
 }
 
 static enum hrtimer_restart apic_timer_fn(struct hrtimer *data)
-- 
1.5.5

-------------------------------------------------------------------------
This SF.net email is sponsored by: Microsoft 
Defy all challenges. Microsoft(R) Visual Studio 2008. 
http://clk.atdmt.com/MRT/go/vse0120000070mrt/direct/01/
_______________________________________________
kvm-devel mailing list
kvm-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/kvm-devel

Reply via email to