diff mbox series

arm64: Fix early handling of FEAT_E2H0 not being implemented

Message ID 20240321115414.3169115-1-maz@kernel.org (mailing list archive)
State New, archived
Headers show
Series arm64: Fix early handling of FEAT_E2H0 not being implemented | expand

Commit Message

Marc Zyngier March 21, 2024, 11:54 a.m. UTC
Commit 3944382fa6f2 introduced checks for the FEAT_E2H0 not being
implemented. However, the check is absolutely wrong and makes a
point it testing a bit that is guaranteed to be zero.

On top of that, the detection happens way too late, after the
init_el2_state has done its job.

This went undetected because the HW this was tested on has E2H being
RAO/WI, and not RES1. However, the bug shows up when run as a nested
guest, where HCR_EL2.E2H is not necessarily set to 1. As a result,
booting the kernel in hVHE mode fails with timer accesses being
cought in a trap loop (which was fun to debug).

Fix the check for ID_AA64MMFR4_EL1.E2H0, and set the HCR_EL2.E2H bit
early so that it can be checked by the rest of the init sequence.

With this, hVHE works again in a NV environment that doesn't have
FEAT_E2H0.

Fixes: 3944382fa6f2 ("arm64: Treat HCR_EL2.E2H as RES1 when ID_AA64MMFR4_EL1.E2H0 is negative")
Signed-off-by: Marc Zyngier <maz@kernel.org>
---
 arch/arm64/kernel/head.S | 29 ++++++++++++++++-------------
 1 file changed, 16 insertions(+), 13 deletions(-)

Comments

Catalin Marinas March 21, 2024, 8:16 p.m. UTC | #1
On Thu, Mar 21, 2024 at 11:54:14AM +0000, Marc Zyngier wrote:
> Commit 3944382fa6f2 introduced checks for the FEAT_E2H0 not being
> implemented. However, the check is absolutely wrong and makes a
> point it testing a bit that is guaranteed to be zero.
> 
> On top of that, the detection happens way too late, after the
> init_el2_state has done its job.
> 
> This went undetected because the HW this was tested on has E2H being
> RAO/WI, and not RES1. However, the bug shows up when run as a nested
> guest, where HCR_EL2.E2H is not necessarily set to 1. As a result,
> booting the kernel in hVHE mode fails with timer accesses being
> cought in a trap loop (which was fun to debug).
> 
> Fix the check for ID_AA64MMFR4_EL1.E2H0, and set the HCR_EL2.E2H bit
> early so that it can be checked by the rest of the init sequence.
> 
> With this, hVHE works again in a NV environment that doesn't have
> FEAT_E2H0.
> 
> Fixes: 3944382fa6f2 ("arm64: Treat HCR_EL2.E2H as RES1 when ID_AA64MMFR4_EL1.E2H0 is negative")
> Signed-off-by: Marc Zyngier <maz@kernel.org>

Acked-by: Catalin Marinas <catalin.marinas@arm.com>

I assume Oliver will take it, otherwise I can pick it up after -rc1
since I don't have the fixed commit in my tree.
Oliver Upton March 21, 2024, 11:34 p.m. UTC | #2
On Thu, Mar 21, 2024 at 08:16:15PM +0000, Catalin Marinas wrote:
> On Thu, Mar 21, 2024 at 11:54:14AM +0000, Marc Zyngier wrote:
> > Commit 3944382fa6f2 introduced checks for the FEAT_E2H0 not being
> > implemented. However, the check is absolutely wrong and makes a
> > point it testing a bit that is guaranteed to be zero.
> > 
> > On top of that, the detection happens way too late, after the
> > init_el2_state has done its job.
> > 
> > This went undetected because the HW this was tested on has E2H being
> > RAO/WI, and not RES1. However, the bug shows up when run as a nested
> > guest, where HCR_EL2.E2H is not necessarily set to 1. As a result,
> > booting the kernel in hVHE mode fails with timer accesses being
> > cought in a trap loop (which was fun to debug).
> > 
> > Fix the check for ID_AA64MMFR4_EL1.E2H0, and set the HCR_EL2.E2H bit
> > early so that it can be checked by the rest of the init sequence.
> > 
> > With this, hVHE works again in a NV environment that doesn't have
> > FEAT_E2H0.
> > 
> > Fixes: 3944382fa6f2 ("arm64: Treat HCR_EL2.E2H as RES1 when ID_AA64MMFR4_EL1.E2H0 is negative")
> > Signed-off-by: Marc Zyngier <maz@kernel.org>
> 
> Acked-by: Catalin Marinas <catalin.marinas@arm.com>

Thanks!

> I assume Oliver will take it, otherwise I can pick it up after -rc1
> since I don't have the fixed commit in my tree.

I'll pick it up but wont be sending anything out until -rc1.
Oliver Upton April 1, 2024, 8:46 a.m. UTC | #3
On Thu, 21 Mar 2024 11:54:14 +0000, Marc Zyngier wrote:
> Commit 3944382fa6f2 introduced checks for the FEAT_E2H0 not being
> implemented. However, the check is absolutely wrong and makes a
> point it testing a bit that is guaranteed to be zero.
> 
> On top of that, the detection happens way too late, after the
> init_el2_state has done its job.
> 
> [...]

Applied, thanks!

[1/1] arm64: Fix early handling of FEAT_E2H0 not being implemented
      commit: b3320142f3db9b3f2a23460abd3e22292e1530a5

Best regards,
diff mbox series

Patch

diff --git a/arch/arm64/kernel/head.S b/arch/arm64/kernel/head.S
index ce08b744aaab..06234c3a15f3 100644
--- a/arch/arm64/kernel/head.S
+++ b/arch/arm64/kernel/head.S
@@ -291,6 +291,21 @@  SYM_INNER_LABEL(init_el2, SYM_L_LOCAL)
 	blr	x2
 0:
 	mov_q	x0, HCR_HOST_NVHE_FLAGS
+
+	/*
+	 * Compliant CPUs advertise their VHE-onlyness with
+	 * ID_AA64MMFR4_EL1.E2H0 < 0. HCR_EL2.E2H can be
+	 * RES1 in that case. Publish the E2H bit early so that
+	 * it can be picked up by the init_el2_state macro.
+	 *
+	 * Fruity CPUs seem to have HCR_EL2.E2H set to RAO/WI, but
+	 * don't advertise it (they predate this relaxation).
+	 */
+	mrs_s	x1, SYS_ID_AA64MMFR4_EL1
+	tbz	x1, #(ID_AA64MMFR4_EL1_E2H0_SHIFT + ID_AA64MMFR4_EL1_E2H0_WIDTH - 1), 1f
+
+	orr	x0, x0, #HCR_E2H
+1:
 	msr	hcr_el2, x0
 	isb
 
@@ -303,22 +318,10 @@  SYM_INNER_LABEL(init_el2, SYM_L_LOCAL)
 
 	mov_q	x1, INIT_SCTLR_EL1_MMU_OFF
 
-	/*
-	 * Compliant CPUs advertise their VHE-onlyness with
-	 * ID_AA64MMFR4_EL1.E2H0 < 0. HCR_EL2.E2H can be
-	 * RES1 in that case.
-	 *
-	 * Fruity CPUs seem to have HCR_EL2.E2H set to RES1, but
-	 * don't advertise it (they predate this relaxation).
-	 */
-	mrs_s	x0, SYS_ID_AA64MMFR4_EL1
-	ubfx	x0, x0, #ID_AA64MMFR4_EL1_E2H0_SHIFT, #ID_AA64MMFR4_EL1_E2H0_WIDTH
-	tbnz	x0, #(ID_AA64MMFR4_EL1_E2H0_SHIFT + ID_AA64MMFR4_EL1_E2H0_WIDTH - 1), 1f
-
 	mrs	x0, hcr_el2
 	and	x0, x0, #HCR_E2H
 	cbz	x0, 2f
-1:
+
 	/* Set a sane SCTLR_EL1, the VHE way */
 	pre_disable_mmu_workaround
 	msr_s	SYS_SCTLR_EL12, x1