MIPS: KVM: Fix timer IRQ race when writing CP0_Compare
commitf1df969d3a2345a75b26117843fbc12104ba25f0
authorJames Hogan <james.hogan@imgtec.com>
Fri, 22 Apr 2016 09:38:46 +0000 (22 10:38 +0100)
committerSasha Levin <sasha.levin@oracle.com>
Mon, 6 Jun 2016 23:11:02 +0000 (6 19:11 -0400)
tree173aff9e8ea777bbdfcf85631352c056cac3f70c
parentf255eae4b8c9fdac4cf3138bb80c5dc584a781ed
MIPS: KVM: Fix timer IRQ race when writing CP0_Compare

[ Upstream commit b45bacd2d048f405c7760e5cc9b60dd67708734f ]

Writing CP0_Compare clears the timer interrupt pending bit
(CP0_Cause.TI), but this wasn't being done atomically. If a timer
interrupt raced with the write of the guest CP0_Compare, the timer
interrupt could end up being pending even though the new CP0_Compare is
nowhere near CP0_Count.

We were already updating the hrtimer expiry with
kvm_mips_update_hrtimer(), which used both kvm_mips_freeze_hrtimer() and
kvm_mips_resume_hrtimer(). Close the race window by expanding out
kvm_mips_update_hrtimer(), and clearing CP0_Cause.TI and setting
CP0_Compare between the freeze and resume. Since the pending timer
interrupt should not be cleared when CP0_Compare is written via the KVM
user API, an ack argument is added to distinguish the source of the
write.

Fixes: e30492bbe95a ("MIPS: KVM: Rewrite count/compare timer emulation")
Signed-off-by: James Hogan <james.hogan@imgtec.com>
Cc: Paolo Bonzini <pbonzini@redhat.com>
Cc: "Radim Krčmář" <rkrcmar@redhat.com>
Cc: Ralf Baechle <ralf@linux-mips.org>
Cc: linux-mips@linux-mips.org
Cc: kvm@vger.kernel.org
Cc: <stable@vger.kernel.org> # 3.16.x-
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Signed-off-by: Sasha Levin <sasha.levin@oracle.com>
arch/mips/include/asm/kvm_host.h
arch/mips/kvm/emulate.c
arch/mips/kvm/trap_emul.c