summaryrefslogtreecommitdiffstats
path: root/arch/arm64
diff options
context:
space:
mode:
authorJames Morse <james.morse@arm.com>2022-01-27 12:20:51 +0000
committerMarc Zyngier <maz@kernel.org>2022-02-03 09:20:05 +0000
commit1229630af88620f6e3a621a1ebd1ca14d9340df7 (patch)
treedba4454a67f3e3946d7a4caf780f5a710866df11 /arch/arm64
parent1c71dbc8a179d99dd9bb7e7fc1888db613cf85de (diff)
downloadlinux-1229630af88620f6e3a621a1ebd1ca14d9340df7.tar.gz
linux-1229630af88620f6e3a621a1ebd1ca14d9340df7.tar.bz2
linux-1229630af88620f6e3a621a1ebd1ca14d9340df7.zip
KVM: arm64: Stop handle_exit() from handling HVC twice when an SError occurs
Prior to commit defe21f49bc9 ("KVM: arm64: Move PC rollback on SError to HYP"), when an SError is synchronised due to another exception, KVM handles the SError first. If the guest survives, the instruction that triggered the original exception is re-exectued to handle the first exception. HVC is treated as a special case as the instruction wouldn't normally be re-exectued, as its not a trap. Commit defe21f49bc9 didn't preserve the behaviour of the 'return 1' that skips the rest of handle_exit(). Since commit defe21f49bc9, KVM will try to handle the SError and the original exception at the same time. When the exception was an HVC, fixup_guest_exit() has already rolled back ELR_EL2, meaning if the guest has virtual SError masked, it will execute and handle the HVC twice. Restore the original behaviour. Fixes: defe21f49bc9 ("KVM: arm64: Move PC rollback on SError to HYP") Cc: stable@vger.kernel.org Signed-off-by: James Morse <james.morse@arm.com> Signed-off-by: Marc Zyngier <maz@kernel.org> Link: https://lore.kernel.org/r/20220127122052.1584324-4-james.morse@arm.com
Diffstat (limited to 'arch/arm64')
-rw-r--r--arch/arm64/kvm/handle_exit.c8
1 files changed, 8 insertions, 0 deletions
diff --git a/arch/arm64/kvm/handle_exit.c b/arch/arm64/kvm/handle_exit.c
index fd2dd26caf91..e3140abd2e2e 100644
--- a/arch/arm64/kvm/handle_exit.c
+++ b/arch/arm64/kvm/handle_exit.c
@@ -228,6 +228,14 @@ int handle_exit(struct kvm_vcpu *vcpu, int exception_index)
{
struct kvm_run *run = vcpu->run;
+ if (ARM_SERROR_PENDING(exception_index)) {
+ /*
+ * The SError is handled by handle_exit_early(). If the guest
+ * survives it will re-execute the original instruction.
+ */
+ return 1;
+ }
+
exception_index = ARM_EXCEPTION_CODE(exception_index);
switch (exception_index) {