From 00741ee76dceb7b4410ae63afe2891819825d9ff Mon Sep 17 00:00:00 2001 From: Marcelo Tosatti <mtosatti@redhat.com> Date: Fri, 30 Dec 2011 11:11:55 -0200 Subject: [PATCH] KVM: x86: Prevent starting PIT timers in the absence of irqchip support (upstream commit 15c875cbb8748513f92aba35a7e5aa9d5026baa9) From: Jan Kiszka <jan.kiszka@siemens.com> User space may create the PIT and forgets about setting up the irqchips. In that case, firing PIT IRQs will crash the host: BUG: unable to handle kernel NULL pointer dereference at 0000000000000128 IP: [<ffffffffa10f6280>] kvm_set_irq+0x30/0x170 [kvm] ... Call Trace: [<ffffffffa11228c1>] pit_do_work+0x51/0xd0 [kvm] [<ffffffff81071431>] process_one_work+0x111/0x4d0 [<ffffffff81071bb2>] worker_thread+0x152/0x340 [<ffffffff81075c8e>] kthread+0x7e/0x90 [<ffffffff815a4474>] kernel_thread_helper+0x4/0x10 Prevent this by checking the irqchip mode before starting a timer. We can't deny creating the PIT if the irqchips aren't set up yet as current user land expects this order to work. BZ: 770101 Signed-off-by: Marcelo Tosatti <mtosatti@redhat.com> Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com> Signed-off-by: Michal Novotny <mignov@gmail.com> --- arch/x86/kvm/i8254.c | 10 +++++++--- 1 files changed, 7 insertions(+), 3 deletions(-) diff --git a/arch/x86/kvm/i8254.c b/arch/x86/kvm/i8254.c index 4cc536a..229b30a 100644 --- a/arch/x86/kvm/i8254.c +++ b/arch/x86/kvm/i8254.c @@ -269,13 +269,17 @@ static void destroy_pit_timer(struct kvm_kpit_timer *pt) hrtimer_cancel(&pt->timer); } -static void create_pit_timer(struct kvm_kpit_state *ps, u32 val, int is_period) +static void create_pit_timer(struct kvm *kvm, struct kvm_kpit_state *ps, + u32 val, int is_period) { struct kvm_kpit_timer *pt = &ps->pit_timer; s64 interval; interval = muldiv64(val, NSEC_PER_SEC, KVM_PIT_FREQ); + if (!irqchip_in_kernel(kvm)) + return; + pr_debug("pit: create pit timer, interval is %llu nsec\n", interval); /* TODO The new value only affected after the retriggered */ @@ -318,11 +322,11 @@ static void pit_load_count(struct kvm *kvm, int channel, u32 val) case 1: /* FIXME: enhance mode 4 precision */ case 4: - create_pit_timer(ps, val, 0); + create_pit_timer(kvm, ps, val, 0); break; case 2: case 3: - create_pit_timer(ps, val, 1); + create_pit_timer(kvm, ps, val, 1); break; default: destroy_pit_timer(&ps->pit_timer); -- 1.7.7.4