Alexander Graf c19d6b
From: Andrew Jones <drjones@redhat.com>
Alexander Graf c19d6b
Date: Sun, 4 Jun 2017 14:43:54 +0200
Alexander Graf c19d6b
Subject: KVM: arm/arm64: properly use vcpu requests
Alexander Graf c19d6b
Patch-mainline: v4.13-rc1
Alexander Graf c19d6b
Git-commit: 6a6d73be12fbe492d0678cd84d3b35e2bc9698e4
Alexander Graf c19d6b
References: bsc#1077761
Alexander Graf c19d6b
Alexander Graf c19d6b
arm/arm64 already has one VCPU request used when setting pause,
Alexander Graf c19d6b
but it doesn't properly check requests in VCPU RUN. Check it
Alexander Graf c19d6b
and also make sure we set vcpu->mode at the appropriate time
Alexander Graf c19d6b
(before the check) and with the appropriate barriers. See
Alexander Graf c19d6b
Documentation/virtual/kvm/vcpu-requests.rst. Also make sure we
Alexander Graf c19d6b
don't leave any vcpu requests we don't intend to handle later
Alexander Graf c19d6b
set in the request bitmap. If we don't clear them, then
Alexander Graf c19d6b
kvm_request_pending() may return true when it shouldn't.
Alexander Graf c19d6b
Alexander Graf c19d6b
Using VCPU requests properly fixes a small race where pause
Alexander Graf c19d6b
could get set just as a VCPU was entering guest mode.
Alexander Graf c19d6b
Alexander Graf c19d6b
Signed-off-by: Andrew Jones <drjones@redhat.com>
Alexander Graf c19d6b
Reviewed-by: Christoffer Dall <cdall@linaro.org>
Alexander Graf c19d6b
Signed-off-by: Christoffer Dall <cdall@linaro.org>
Alexander Graf c19d6b
Acked-by: Alexander Graf <agraf@suse.de>
Alexander Graf c19d6b
---
Alexander Graf c19d6b
 arch/arm/kvm/handle_exit.c   |    1 +
Alexander Graf c19d6b
 arch/arm64/kvm/handle_exit.c |    1 +
Alexander Graf c19d6b
 virt/kvm/arm/arm.c           |   14 ++++++++++++--
Alexander Graf c19d6b
 virt/kvm/arm/psci.c          |    1 +
Alexander Graf c19d6b
 4 files changed, 15 insertions(+), 2 deletions(-)
Alexander Graf c19d6b
Alexander Graf c19d6b
--- a/arch/arm/kvm/handle_exit.c
Alexander Graf c19d6b
+++ b/arch/arm/kvm/handle_exit.c
Alexander Graf c19d6b
@@ -72,6 +72,7 @@
Alexander Graf c19d6b
 		trace_kvm_wfx(*vcpu_pc(vcpu), false);
Alexander Graf c19d6b
 		vcpu->stat.wfi_exit_stat++;
Alexander Graf c19d6b
 		kvm_vcpu_block(vcpu);
Alexander Graf c19d6b
+		kvm_clear_request(KVM_REQ_UNHALT, vcpu);
Alexander Graf c19d6b
 	}
Alexander Graf c19d6b
 
Alexander Graf c19d6b
 	kvm_skip_instr(vcpu, kvm_vcpu_trap_il_is32bit(vcpu));
Alexander Graf c19d6b
--- a/arch/arm64/kvm/handle_exit.c
Alexander Graf c19d6b
+++ b/arch/arm64/kvm/handle_exit.c
Alexander Graf c19d6b
@@ -89,6 +89,7 @@
Alexander Graf c19d6b
 		trace_kvm_wfx_arm64(*vcpu_pc(vcpu), false);
Alexander Graf c19d6b
 		vcpu->stat.wfi_exit_stat++;
Alexander Graf c19d6b
 		kvm_vcpu_block(vcpu);
Alexander Graf c19d6b
+		kvm_clear_request(KVM_REQ_UNHALT, vcpu);
Alexander Graf c19d6b
 	}
Alexander Graf c19d6b
 
Alexander Graf c19d6b
 	kvm_skip_instr(vcpu, kvm_vcpu_trap_il_is32bit(vcpu));
Alexander Graf c19d6b
--- a/virt/kvm/arm/arm.c
Alexander Graf c19d6b
+++ b/virt/kvm/arm/arm.c
Alexander Graf c19d6b
@@ -546,6 +546,7 @@
Alexander Graf c19d6b
 
Alexander Graf c19d6b
 	kvm_for_each_vcpu(i, vcpu, kvm) {
Alexander Graf c19d6b
 		vcpu->arch.pause = false;
Alexander Graf c19d6b
+		kvm_clear_request(KVM_REQ_VCPU_EXIT, vcpu);
Alexander Graf c19d6b
 		swake_up(kvm_arch_vcpu_wq(vcpu));
Alexander Graf c19d6b
 	}
Alexander Graf c19d6b
 }
Alexander Graf c19d6b
@@ -638,8 +639,18 @@
Alexander Graf c19d6b
 			run->exit_reason = KVM_EXIT_INTR;
Alexander Graf c19d6b
 		}
Alexander Graf c19d6b
 
Alexander Graf c19d6b
+		/*
Alexander Graf c19d6b
+		 * Ensure we set mode to IN_GUEST_MODE after we disable
Alexander Graf c19d6b
+		 * interrupts and before the final VCPU requests check.
Alexander Graf c19d6b
+		 * See the comment in kvm_vcpu_exiting_guest_mode() and
Alexander Graf c19d6b
+		 * Documentation/virtual/kvm/vcpu-requests.rst
Alexander Graf c19d6b
+		 */
Alexander Graf c19d6b
+		smp_store_mb(vcpu->mode, IN_GUEST_MODE);
Alexander Graf c19d6b
+
Alexander Graf c19d6b
 		if (ret <= 0 || need_new_vmid_gen(vcpu->kvm) ||
Alexander Graf c19d6b
-			vcpu->arch.power_off || vcpu->arch.pause) {
Alexander Graf c19d6b
+		    kvm_request_pending(vcpu) ||
Alexander Graf c19d6b
+		    vcpu->arch.power_off || vcpu->arch.pause) {
Alexander Graf c19d6b
+			vcpu->mode = OUTSIDE_GUEST_MODE;
Alexander Graf c19d6b
 			local_irq_enable();
Alexander Graf c19d6b
 			kvm_pmu_sync_hwstate(vcpu);
Alexander Graf c19d6b
 			kvm_timer_sync_hwstate(vcpu);
Alexander Graf c19d6b
@@ -655,7 +666,6 @@
Alexander Graf c19d6b
 		 */
Alexander Graf c19d6b
 		trace_kvm_entry(*vcpu_pc(vcpu));
Alexander Graf c19d6b
 		guest_enter_irqoff();
Alexander Graf c19d6b
-		vcpu->mode = IN_GUEST_MODE;
Alexander Graf c19d6b
 
Alexander Graf c19d6b
 		ret = kvm_call_hyp(__kvm_vcpu_run, vcpu);
Alexander Graf c19d6b
 
Alexander Graf c19d6b
--- a/virt/kvm/arm/psci.c
Alexander Graf c19d6b
+++ b/virt/kvm/arm/psci.c
Alexander Graf c19d6b
@@ -57,6 +57,7 @@
Alexander Graf c19d6b
 	 * for KVM will preserve the register state.
Alexander Graf c19d6b
 	 */
Alexander Graf c19d6b
 	kvm_vcpu_block(vcpu);
Alexander Graf c19d6b
+	kvm_clear_request(KVM_REQ_UNHALT, vcpu);
Alexander Graf c19d6b
 
Alexander Graf c19d6b
 	return PSCI_RET_SUCCESS;
Alexander Graf c19d6b
 }