Takashi Iwai e8a81f
From 86ddc7397906772f877e9f32defa819b4edc77c0 Mon Sep 17 00:00:00 2001
Takashi Iwai e8a81f
From: Will Deacon <will@kernel.org>
Takashi Iwai e8a81f
Date: Fri, 13 Aug 2021 14:03:36 +0100
Takashi Iwai e8a81f
Subject: [PATCH] KVM: arm64: Make hyp_panic() more robust when protected mode is enabled
Takashi Iwai e8a81f
Git-commit: ccac96977243d7916053550f62e6489760ad0adc
Takashi Iwai e8a81f
Patch-mainline: v5.15-rc1
Takashi Iwai e8a81f
References: stable-5.14.7
Takashi Iwai e8a81f
Takashi Iwai e8a81f
[ Upstream commit ccac96977243d7916053550f62e6489760ad0adc ]
Takashi Iwai e8a81f
Takashi Iwai e8a81f
When protected mode is enabled, the host is unable to access most parts
Takashi Iwai e8a81f
of the EL2 hypervisor image, including 'hyp_physvirt_offset' and the
Takashi Iwai e8a81f
contents of the hypervisor's '.rodata.str' section. Unfortunately,
Takashi Iwai e8a81f
nvhe_hyp_panic_handler() tries to read from both of these locations when
Takashi Iwai e8a81f
handling a BUG() triggered at EL2; the former for converting the ELR to
Takashi Iwai e8a81f
a physical address and the latter for displaying the name of the source
Takashi Iwai e8a81f
file where the BUG() occurred.
Takashi Iwai e8a81f
Takashi Iwai e8a81f
Hack the EL2 panic asm to pass both physical and virtual ELR values to
Takashi Iwai e8a81f
the host and utilise the newly introduced CONFIG_NVHE_EL2_DEBUG so that
Takashi Iwai e8a81f
we disable stage-2 protection for the host before returning to the EL1
Takashi Iwai e8a81f
panic handler. If the debug option is not enabled, display the address
Takashi Iwai e8a81f
instead of the source file:line information.
Takashi Iwai e8a81f
Takashi Iwai e8a81f
Cc: Andrew Scull <ascull@google.com>
Takashi Iwai e8a81f
Cc: Quentin Perret <qperret@google.com>
Takashi Iwai e8a81f
Signed-off-by: Will Deacon <will@kernel.org>
Takashi Iwai e8a81f
Signed-off-by: Marc Zyngier <maz@kernel.org>
Takashi Iwai e8a81f
Link: https://lore.kernel.org/r/20210813130336.8139-1-will@kernel.org
Takashi Iwai e8a81f
Signed-off-by: Sasha Levin <sashal@kernel.org>
Takashi Iwai e8a81f
Acked-by: Takashi Iwai <tiwai@suse.de>
Takashi Iwai e8a81f
Takashi Iwai e8a81f
---
Takashi Iwai e8a81f
 arch/arm64/kvm/handle_exit.c   | 23 ++++++++++++++---------
Takashi Iwai e8a81f
 arch/arm64/kvm/hyp/nvhe/host.S | 21 +++++++++++++++++----
Takashi Iwai e8a81f
 2 files changed, 31 insertions(+), 13 deletions(-)
Takashi Iwai e8a81f
Takashi Iwai e8a81f
diff --git a/arch/arm64/kvm/handle_exit.c b/arch/arm64/kvm/handle_exit.c
Takashi Iwai e8a81f
index 6f48336b1d86..04ebab299aa4 100644
Takashi Iwai e8a81f
--- a/arch/arm64/kvm/handle_exit.c
Takashi Iwai e8a81f
+++ b/arch/arm64/kvm/handle_exit.c
Takashi Iwai e8a81f
@@ -292,11 +292,12 @@ void handle_exit_early(struct kvm_vcpu *vcpu, int exception_index)
Takashi Iwai e8a81f
 		kvm_handle_guest_serror(vcpu, kvm_vcpu_get_esr(vcpu));
Takashi Iwai e8a81f
 }
Takashi Iwai e8a81f
 
Takashi Iwai e8a81f
-void __noreturn __cold nvhe_hyp_panic_handler(u64 esr, u64 spsr, u64 elr,
Takashi Iwai e8a81f
+void __noreturn __cold nvhe_hyp_panic_handler(u64 esr, u64 spsr,
Takashi Iwai e8a81f
+					      u64 elr_virt, u64 elr_phys,
Takashi Iwai e8a81f
 					      u64 par, uintptr_t vcpu,
Takashi Iwai e8a81f
 					      u64 far, u64 hpfar) {
Takashi Iwai e8a81f
-	u64 elr_in_kimg = __phys_to_kimg(__hyp_pa(elr));
Takashi Iwai e8a81f
-	u64 hyp_offset = elr_in_kimg - kaslr_offset() - elr;
Takashi Iwai e8a81f
+	u64 elr_in_kimg = __phys_to_kimg(elr_phys);
Takashi Iwai e8a81f
+	u64 hyp_offset = elr_in_kimg - kaslr_offset() - elr_virt;
Takashi Iwai e8a81f
 	u64 mode = spsr & PSR_MODE_MASK;
Takashi Iwai e8a81f
 
Takashi Iwai e8a81f
 	/*
Takashi Iwai e8a81f
@@ -309,20 +310,24 @@ void __noreturn __cold nvhe_hyp_panic_handler(u64 esr, u64 spsr, u64 elr,
Takashi Iwai e8a81f
 		kvm_err("Invalid host exception to nVHE hyp!\n");
Takashi Iwai e8a81f
 	} else if (ESR_ELx_EC(esr) == ESR_ELx_EC_BRK64 &&
Takashi Iwai e8a81f
 		   (esr & ESR_ELx_BRK64_ISS_COMMENT_MASK) == BUG_BRK_IMM) {
Takashi Iwai e8a81f
-		struct bug_entry *bug = find_bug(elr_in_kimg);
Takashi Iwai e8a81f
 		const char *file = NULL;
Takashi Iwai e8a81f
 		unsigned int line = 0;
Takashi Iwai e8a81f
 
Takashi Iwai e8a81f
 		/* All hyp bugs, including warnings, are treated as fatal. */
Takashi Iwai e8a81f
-		if (bug)
Takashi Iwai e8a81f
-			bug_get_file_line(bug, &file, &line);
Takashi Iwai e8a81f
+		if (!is_protected_kvm_enabled() ||
Takashi Iwai e8a81f
+		    IS_ENABLED(CONFIG_NVHE_EL2_DEBUG)) {
Takashi Iwai e8a81f
+			struct bug_entry *bug = find_bug(elr_in_kimg);
Takashi Iwai e8a81f
+
Takashi Iwai e8a81f
+			if (bug)
Takashi Iwai e8a81f
+				bug_get_file_line(bug, &file, &line);
Takashi Iwai e8a81f
+		}
Takashi Iwai e8a81f
 
Takashi Iwai e8a81f
 		if (file)
Takashi Iwai e8a81f
 			kvm_err("nVHE hyp BUG at: %s:%u!\n", file, line);
Takashi Iwai e8a81f
 		else
Takashi Iwai e8a81f
-			kvm_err("nVHE hyp BUG at: %016llx!\n", elr + hyp_offset);
Takashi Iwai e8a81f
+			kvm_err("nVHE hyp BUG at: %016llx!\n", elr_virt + hyp_offset);
Takashi Iwai e8a81f
 	} else {
Takashi Iwai e8a81f
-		kvm_err("nVHE hyp panic at: %016llx!\n", elr + hyp_offset);
Takashi Iwai e8a81f
+		kvm_err("nVHE hyp panic at: %016llx!\n", elr_virt + hyp_offset);
Takashi Iwai e8a81f
 	}
Takashi Iwai e8a81f
 
Takashi Iwai e8a81f
 	/*
Takashi Iwai e8a81f
@@ -334,5 +339,5 @@ void __noreturn __cold nvhe_hyp_panic_handler(u64 esr, u64 spsr, u64 elr,
Takashi Iwai e8a81f
 	kvm_err("Hyp Offset: 0x%llx\n", hyp_offset);
Takashi Iwai e8a81f
 
Takashi Iwai e8a81f
 	panic("HYP panic:\nPS:%08llx PC:%016llx ESR:%08llx\nFAR:%016llx HPFAR:%016llx PAR:%016llx\nVCPU:%016lx\n",
Takashi Iwai e8a81f
-	      spsr, elr, esr, far, hpfar, par, vcpu);
Takashi Iwai e8a81f
+	      spsr, elr_virt, esr, far, hpfar, par, vcpu);
Takashi Iwai e8a81f
 }
Takashi Iwai e8a81f
diff --git a/arch/arm64/kvm/hyp/nvhe/host.S b/arch/arm64/kvm/hyp/nvhe/host.S
Takashi Iwai e8a81f
index 2b23400e0fb3..4b652ffb591d 100644
Takashi Iwai e8a81f
--- a/arch/arm64/kvm/hyp/nvhe/host.S
Takashi Iwai e8a81f
+++ b/arch/arm64/kvm/hyp/nvhe/host.S
Takashi Iwai e8a81f
@@ -7,6 +7,7 @@
Takashi Iwai e8a81f
 #include <linux/linkage.h>
Takashi Iwai e8a81f
 
Takashi Iwai e8a81f
 #include <asm/assembler.h>
Takashi Iwai e8a81f
+#include <asm/kvm_arm.h>
Takashi Iwai e8a81f
 #include <asm/kvm_asm.h>
Takashi Iwai e8a81f
 #include <asm/kvm_mmu.h>
Takashi Iwai e8a81f
 
Takashi Iwai e8a81f
@@ -85,12 +86,24 @@ SYM_FUNC_START(__hyp_do_panic)
Takashi Iwai e8a81f
 
Takashi Iwai e8a81f
 	mov	x29, x0
Takashi Iwai e8a81f
 
Takashi Iwai e8a81f
+#ifdef CONFIG_NVHE_EL2_DEBUG
Takashi Iwai e8a81f
+	/* Ensure host stage-2 is disabled */
Takashi Iwai e8a81f
+	mrs	x0, hcr_el2
Takashi Iwai e8a81f
+	bic	x0, x0, #HCR_VM
Takashi Iwai e8a81f
+	msr	hcr_el2, x0
Takashi Iwai e8a81f
+	isb
Takashi Iwai e8a81f
+	tlbi	vmalls12e1
Takashi Iwai e8a81f
+	dsb	nsh
Takashi Iwai e8a81f
+#endif
Takashi Iwai e8a81f
+
Takashi Iwai e8a81f
 	/* Load the panic arguments into x0-7 */
Takashi Iwai e8a81f
 	mrs	x0, esr_el2
Takashi Iwai e8a81f
-	get_vcpu_ptr x4, x5
Takashi Iwai e8a81f
-	mrs	x5, far_el2
Takashi Iwai e8a81f
-	mrs	x6, hpfar_el2
Takashi Iwai e8a81f
-	mov	x7, xzr			// Unused argument
Takashi Iwai e8a81f
+	mov	x4, x3
Takashi Iwai e8a81f
+	mov	x3, x2
Takashi Iwai e8a81f
+	hyp_pa	x3, x6
Takashi Iwai e8a81f
+	get_vcpu_ptr x5, x6
Takashi Iwai e8a81f
+	mrs	x6, far_el2
Takashi Iwai e8a81f
+	mrs	x7, hpfar_el2
Takashi Iwai e8a81f
 
Takashi Iwai e8a81f
 	/* Enter the host, conditionally restoring the host context. */
Takashi Iwai e8a81f
 	cbz	x29, __host_enter_without_restoring
Takashi Iwai e8a81f
-- 
Takashi Iwai e8a81f
2.26.2
Takashi Iwai e8a81f