* [PATCH 6.6 v2 0/6] arm64: KVM: Backport VHE-only boot fixes
@ 2026-07-08 22:51 Colton Lewis
2026-07-08 22:51 ` [PATCH 6.6 v2 1/6] arm64: sysreg: Add layout for ID_AA64MMFR4_EL1 Colton Lewis
` (5 more replies)
0 siblings, 6 replies; 9+ messages in thread
From: Colton Lewis @ 2026-07-08 22:51 UTC (permalink / raw)
To: stable
Cc: oliver.upton, sashal, gregkh, mizhang, catalin.marinas, will, maz,
james.morse, suzuki.poulose, yuzenghui, mark.rutland,
ahmed.genidi, leo.yan, miguel.luis, dbrazdil, kvmarm,
linux-arm-kernel, linux-kernel, Colton Lewis
Architectural updates retroactively made FEAT_E2H0 optional, meaning
hardware can implement FEAT_VHE without FEAT_E2H0. On such CPUs,
HCR_EL2.E2H can reset to an unknown state and must be initialized early
so later code can reliably detect whether E2H mode is active.
Without these fixes, booting 6.6.y as a guest under KVM nested
virtualization will hang at boot.
This series targets 6.6.y specifically because these patches are all
present in 6.12.y and applying these patches to 6.1.y and presumably
older kernels has more conflicts and results in other issues booting
as a guest under nested virtualization. More work is needed to enable
that.
Changes in v2:
- Updated commit messages to reference correct upstream SHA1s.
- Preserved inline EL2 state initialization in Patch 4 to avoid
unrelated code churn.
- Added upstream commit 3855a7b91d42 ("KVM: arm64: Initialize SCTLR_EL1 in
__kvm_hyp_init_cpu()") as Patch 5.
- Verified boot and KVM initialization across all KVM execution modes
(nVHE, hVHE/nested, VHE, and protected).
v1:
https://lore.kernel.org/kvmarm/20260701204342.2654385-1-coltonlewis@google.com/
Ahmed Genidi (1):
KVM: arm64: Initialize SCTLR_EL1 in __kvm_hyp_init_cpu()
Marc Zyngier (4):
arm64: sysreg: Add layout for ID_AA64MMFR4_EL1
arm64: Treat HCR_EL2.E2H as RES1 when ID_AA64MMFR4_EL1.E2H0 is
negative
arm64: Fix early handling of FEAT_E2H0 not being implemented
arm64: Revamp HCR_EL2.E2H RES1 detection
Mark Rutland (1):
KVM: arm64: Initialize HCR_EL2.E2H early
arch/arm64/include/asm/el2_setup.h | 56 ++++++++++++++++++++++++++--
arch/arm64/kernel/head.S | 20 ++++------
arch/arm64/kvm/hyp/nvhe/hyp-init.S | 3 +-
arch/arm64/kvm/hyp/nvhe/psci-relay.c | 3 ++
arch/arm64/tools/sysreg | 37 ++++++++++++++++++
5 files changed, 101 insertions(+), 18 deletions(-)
base-commit: da47cbc254661aa66d61ef061485a7080305c4be
--
2.55.0.795.g602f6c329a-goog
^ permalink raw reply [flat|nested] 9+ messages in thread
* [PATCH 6.6 v2 1/6] arm64: sysreg: Add layout for ID_AA64MMFR4_EL1
2026-07-08 22:51 [PATCH 6.6 v2 0/6] arm64: KVM: Backport VHE-only boot fixes Colton Lewis
@ 2026-07-08 22:51 ` Colton Lewis
2026-07-09 10:16 ` Marc Zyngier
2026-07-08 22:51 ` [PATCH 6.6 v2 2/6] arm64: Treat HCR_EL2.E2H as RES1 when ID_AA64MMFR4_EL1.E2H0 is negative Colton Lewis
` (4 subsequent siblings)
5 siblings, 1 reply; 9+ messages in thread
From: Colton Lewis @ 2026-07-08 22:51 UTC (permalink / raw)
To: stable
Cc: oliver.upton, sashal, gregkh, mizhang, catalin.marinas, will, maz,
james.morse, suzuki.poulose, yuzenghui, mark.rutland,
ahmed.genidi, leo.yan, miguel.luis, dbrazdil, kvmarm,
linux-arm-kernel, linux-kernel
From: Marc Zyngier <maz@kernel.org>
[ Upstream commit cfc680bb04c54e61faa51a34d8383a0aa25b583f ]
ARMv9.5 has infroduced ID_AA64MMFR4_EL1 with a bunch of new features.
Add the corresponding layout.
This is extracted from the public ARM SysReg_xml_A_profile-2023-09
delivery, timestamped d55f5af8e09052abe92a02adf820deea2eaed717.
Reviewed-by: Suzuki K Poulose <suzuki.poulose@arm.com>
Signed-off-by: Marc Zyngier <maz@kernel.org>
Reviewed-by: Catalin Marinas <catalin.marinas@arm.com>
Reviewed-by: Miguel Luis <miguel.luis@oracle.com>
Link: https://lore.kernel.org/r/20240122181344.258974-5-maz@kernel.org
Signed-off-by: Oliver Upton <oliver.upton@linux.dev>
---
arch/arm64/tools/sysreg | 37 +++++++++++++++++++++++++++++++++++++
1 file changed, 37 insertions(+)
diff --git a/arch/arm64/tools/sysreg b/arch/arm64/tools/sysreg
index 76ce150e7347e..f7180d391f829 100644
--- a/arch/arm64/tools/sysreg
+++ b/arch/arm64/tools/sysreg
@@ -1669,6 +1669,43 @@ UnsignedEnum 3:0 TCRX
EndEnum
EndSysreg
+Sysreg ID_AA64MMFR4_EL1 3 0 0 7 4
+Res0 63:40
+UnsignedEnum 39:36 E3DSE
+ 0b0000 NI
+ 0b0001 IMP
+EndEnum
+Res0 35:28
+SignedEnum 27:24 E2H0
+ 0b0000 IMP
+ 0b1110 NI_NV1
+ 0b1111 NI
+EndEnum
+UnsignedEnum 23:20 NV_frac
+ 0b0000 NV_NV2
+ 0b0001 NV2_ONLY
+EndEnum
+UnsignedEnum 19:16 FGWTE3
+ 0b0000 NI
+ 0b0001 IMP
+EndEnum
+UnsignedEnum 15:12 HACDBS
+ 0b0000 NI
+ 0b0001 IMP
+EndEnum
+UnsignedEnum 11:8 ASID2
+ 0b0000 NI
+ 0b0001 IMP
+EndEnum
+SignedEnum 7:4 EIESB
+ 0b0000 NI
+ 0b0001 ToEL3
+ 0b0010 ToELx
+ 0b1111 ANY
+EndEnum
+Res0 3:0
+EndSysreg
+
Sysreg SCTLR_EL1 3 0 1 0 0
Field 63 TIDCP
Field 62 SPINTMASK
--
2.55.0.795.g602f6c329a-goog
^ permalink raw reply related [flat|nested] 9+ messages in thread
* [PATCH 6.6 v2 2/6] arm64: Treat HCR_EL2.E2H as RES1 when ID_AA64MMFR4_EL1.E2H0 is negative
2026-07-08 22:51 [PATCH 6.6 v2 0/6] arm64: KVM: Backport VHE-only boot fixes Colton Lewis
2026-07-08 22:51 ` [PATCH 6.6 v2 1/6] arm64: sysreg: Add layout for ID_AA64MMFR4_EL1 Colton Lewis
@ 2026-07-08 22:51 ` Colton Lewis
2026-07-08 22:51 ` [PATCH 6.6 v2 3/6] arm64: Fix early handling of FEAT_E2H0 not being implemented Colton Lewis
` (3 subsequent siblings)
5 siblings, 0 replies; 9+ messages in thread
From: Colton Lewis @ 2026-07-08 22:51 UTC (permalink / raw)
To: stable
Cc: oliver.upton, sashal, gregkh, mizhang, catalin.marinas, will, maz,
james.morse, suzuki.poulose, yuzenghui, mark.rutland,
ahmed.genidi, leo.yan, miguel.luis, dbrazdil, kvmarm,
linux-arm-kernel, linux-kernel
From: Marc Zyngier <maz@kernel.org>
[ Upstream commit 3944382fa6f22b54fd399632b1af92c28123979b ]
For CPUs that have ID_AA64MMFR4_EL1.E2H0 as negative, it is important
to avoid the boot path that sets HCR_EL2.E2H=0. Fortunately, we
already have this path to cope with fruity CPUs.
Tweak init_el2 to look at ID_AA64MMFR4_EL1.E2H0 first.
Reviewed-by: Suzuki K Poulose <suzuki.poulose@arm.com>
Signed-off-by: Marc Zyngier <maz@kernel.org>
Reviewed-by: Catalin Marinas <catalin.marinas@arm.com>
Link: https://lore.kernel.org/r/20240122181344.258974-8-maz@kernel.org
Signed-off-by: Oliver Upton <oliver.upton@linux.dev>
---
arch/arm64/kernel/head.S | 23 +++++++++++++++--------
1 file changed, 15 insertions(+), 8 deletions(-)
diff --git a/arch/arm64/kernel/head.S b/arch/arm64/kernel/head.S
index 6517bf2644a08..e32c8dd0b17a7 100644
--- a/arch/arm64/kernel/head.S
+++ b/arch/arm64/kernel/head.S
@@ -589,25 +589,32 @@ SYM_INNER_LABEL(init_el2, SYM_L_LOCAL)
mov_q x1, INIT_SCTLR_EL1_MMU_OFF
/*
- * Fruity CPUs seem to have HCR_EL2.E2H set to RES1,
- * making it impossible to start in nVHE mode. Is that
- * compliant with the architecture? Absolutely not!
+ * 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, 1f
-
+ cbz x0, 2f
+1:
/* Set a sane SCTLR_EL1, the VHE way */
pre_disable_mmu_workaround
msr_s SYS_SCTLR_EL12, x1
mov x2, #BOOT_CPU_FLAG_E2H
- b 2f
+ b 3f
-1:
+2:
pre_disable_mmu_workaround
msr sctlr_el1, x1
mov x2, xzr
-2:
+3:
__init_el2_nvhe_prepare_eret
mov w0, #BOOT_CPU_MODE_EL2
--
2.55.0.795.g602f6c329a-goog
^ permalink raw reply related [flat|nested] 9+ messages in thread
* [PATCH 6.6 v2 3/6] arm64: Fix early handling of FEAT_E2H0 not being implemented
2026-07-08 22:51 [PATCH 6.6 v2 0/6] arm64: KVM: Backport VHE-only boot fixes Colton Lewis
2026-07-08 22:51 ` [PATCH 6.6 v2 1/6] arm64: sysreg: Add layout for ID_AA64MMFR4_EL1 Colton Lewis
2026-07-08 22:51 ` [PATCH 6.6 v2 2/6] arm64: Treat HCR_EL2.E2H as RES1 when ID_AA64MMFR4_EL1.E2H0 is negative Colton Lewis
@ 2026-07-08 22:51 ` Colton Lewis
2026-07-08 22:51 ` [PATCH 6.6 v2 4/6] KVM: arm64: Initialize HCR_EL2.E2H early Colton Lewis
` (2 subsequent siblings)
5 siblings, 0 replies; 9+ messages in thread
From: Colton Lewis @ 2026-07-08 22:51 UTC (permalink / raw)
To: stable
Cc: oliver.upton, sashal, gregkh, mizhang, catalin.marinas, will, maz,
james.morse, suzuki.poulose, yuzenghui, mark.rutland,
ahmed.genidi, leo.yan, miguel.luis, dbrazdil, kvmarm,
linux-arm-kernel, linux-kernel
From: Marc Zyngier <maz@kernel.org>
[ Upstream commit b3320142f3db9b3f2a23460abd3e22292e1530a5 ]
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>
Link: https://lore.kernel.org/r/20240321115414.3169115-1-maz@kernel.org
Signed-off-by: Oliver Upton <oliver.upton@linux.dev>
---
arch/arm64/kernel/head.S | 29 ++++++++++++++++-------------
1 file changed, 16 insertions(+), 13 deletions(-)
diff --git a/arch/arm64/kernel/head.S b/arch/arm64/kernel/head.S
index e32c8dd0b17a7..e0e710b36da37 100644
--- a/arch/arm64/kernel/head.S
+++ b/arch/arm64/kernel/head.S
@@ -576,6 +576,21 @@ SYM_INNER_LABEL(init_el2, SYM_L_LOCAL)
isb
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
@@ -588,22 +603,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
--
2.55.0.795.g602f6c329a-goog
^ permalink raw reply related [flat|nested] 9+ messages in thread
* [PATCH 6.6 v2 4/6] KVM: arm64: Initialize HCR_EL2.E2H early
2026-07-08 22:51 [PATCH 6.6 v2 0/6] arm64: KVM: Backport VHE-only boot fixes Colton Lewis
` (2 preceding siblings ...)
2026-07-08 22:51 ` [PATCH 6.6 v2 3/6] arm64: Fix early handling of FEAT_E2H0 not being implemented Colton Lewis
@ 2026-07-08 22:51 ` Colton Lewis
2026-07-08 22:51 ` [PATCH 6.6 v2 5/6] KVM: arm64: Initialize SCTLR_EL1 in __kvm_hyp_init_cpu() Colton Lewis
2026-07-08 22:51 ` [PATCH 6.6 v2 6/6] arm64: Revamp HCR_EL2.E2H RES1 detection Colton Lewis
5 siblings, 0 replies; 9+ messages in thread
From: Colton Lewis @ 2026-07-08 22:51 UTC (permalink / raw)
To: stable
Cc: oliver.upton, sashal, gregkh, mizhang, catalin.marinas, will, maz,
james.morse, suzuki.poulose, yuzenghui, mark.rutland,
ahmed.genidi, leo.yan, miguel.luis, dbrazdil, kvmarm,
linux-arm-kernel, linux-kernel, Ben Horgan
From: Mark Rutland <mark.rutland@arm.com>
[ Upstream commit 7a68b55ff39b0a1638acb1694c185d49f6077a0d ]
On CPUs without FEAT_E2H0, HCR_EL2.E2H is RES1, but may reset to an
UNKNOWN value out of reset and consequently may not read as 1 unless it
has been explicitly initialized.
We handled this for the head.S boot code in commits:
3944382fa6f22b54 ("arm64: Treat HCR_EL2.E2H as RES1 when ID_AA64MMFR4_EL1.E2H0 is negative")
b3320142f3db9b3f ("arm64: Fix early handling of FEAT_E2H0 not being implemented")
Unfortunately, we forgot to apply a similar fix to the KVM PSCI entry
points used when relaying CPU_ON, CPU_SUSPEND, and SYSTEM SUSPEND. When
KVM is entered via these entry points, the value of HCR_EL2.E2H may be
consumed before it has been initialized (e.g. by the 'init_el2_state'
macro).
Initialize HCR_EL2.E2H early in these paths such that it can be consumed
reliably. The existing code in head.S is factored out into a new
'init_el2_hcr' macro, and this is used in the __kvm_hyp_init_cpu()
function common to all the relevant PSCI entry points.
For clarity, I've tweaked the assembly used to check whether
ID_AA64MMFR4_EL1.E2H0 is negative. The bitfield is extracted as a signed
value, and this is checked with a signed-greater-or-equal (GE) comparison.
As the hyp code will reconfigure HCR_EL2 later in ___kvm_hyp_init(), all
bits other than E2H are initialized to zero in __kvm_hyp_init_cpu().
Fixes: 3944382fa6f22b54 ("arm64: Treat HCR_EL2.E2H as RES1 when ID_AA64MMFR4_EL1.E2H0 is negative")
Fixes: b3320142f3db9b3f ("arm64: Fix early handling of FEAT_E2H0 not being implemented")
Signed-off-by: Mark Rutland <mark.rutland@arm.com>
Cc: Ahmed Genidi <ahmed.genidi@arm.com>
Cc: Ben Horgan <ben.horgan@arm.com>
Cc: Catalin Marinas <catalin.marinas@arm.com>
Cc: Leo Yan <leo.yan@arm.com>
Cc: Marc Zyngier <maz@kernel.org>
Cc: Oliver Upton <oliver.upton@linux.dev>
Cc: Will Deacon <will@kernel.org>
Link: https://lore.kernel.org/r/20250227180526.1204723-2-mark.rutland@arm.com
[maz: fixed LT->GE thinko]
Signed-off-by: Marc Zyngier <maz@kernel.org>
---
arch/arm64/include/asm/el2_setup.h | 26 ++++++++++++++++++++++++++
arch/arm64/kernel/head.S | 19 +------------------
arch/arm64/kvm/hyp/nvhe/hyp-init.S | 2 ++
3 files changed, 29 insertions(+), 18 deletions(-)
diff --git a/arch/arm64/include/asm/el2_setup.h b/arch/arm64/include/asm/el2_setup.h
index b7afaa026842b..3498dc5d02c18 100644
--- a/arch/arm64/include/asm/el2_setup.h
+++ b/arch/arm64/include/asm/el2_setup.h
@@ -16,6 +16,32 @@
#include <asm/sysreg.h>
#include <linux/irqchip/arm-gic-v3.h>
+.macro init_el2_hcr val
+ mov_q x0, \val
+
+ /*
+ * Compliant CPUs advertise their VHE-onlyness with
+ * ID_AA64MMFR4_EL1.E2H0 < 0. On such CPUs HCR_EL2.E2H is RES1, but it
+ * can reset into an UNKNOWN state and might not read as 1 until it has
+ * been initialized explicitly.
+ *
+ * Fruity CPUs seem to have HCR_EL2.E2H set to RAO/WI, but
+ * don't advertise it (they predate this relaxation).
+ *
+ * Initalize HCR_EL2.E2H so that later code can rely upon HCR_EL2.E2H
+ * indicating whether the CPU is running in E2H mode.
+ */
+ mrs_s x1, SYS_ID_AA64MMFR4_EL1
+ sbfx x1, x1, #ID_AA64MMFR4_EL1_E2H0_SHIFT, #ID_AA64MMFR4_EL1_E2H0_WIDTH
+ cmp x1, #0
+ b.ge .LnVHE_\@
+
+ orr x0, x0, #HCR_E2H
+.LnVHE_\@:
+ msr hcr_el2, x0
+ isb
+.endm
+
.macro __init_el2_sctlr
mov_q x0, INIT_SCTLR_EL2_MMU_OFF
msr sctlr_el2, x0
diff --git a/arch/arm64/kernel/head.S b/arch/arm64/kernel/head.S
index e0e710b36da37..ff7769821166a 100644
--- a/arch/arm64/kernel/head.S
+++ b/arch/arm64/kernel/head.S
@@ -575,25 +575,8 @@ SYM_INNER_LABEL(init_el2, SYM_L_LOCAL)
msr sctlr_el2, x0
isb
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
+ init_el2_hcr HCR_HOST_NVHE_FLAGS
init_el2_state
/* Hypervisor stub */
diff --git a/arch/arm64/kvm/hyp/nvhe/hyp-init.S b/arch/arm64/kvm/hyp/nvhe/hyp-init.S
index 1cc06e6797bda..3efa9cfaa9d48 100644
--- a/arch/arm64/kvm/hyp/nvhe/hyp-init.S
+++ b/arch/arm64/kvm/hyp/nvhe/hyp-init.S
@@ -202,6 +202,8 @@ SYM_CODE_START_LOCAL(__kvm_hyp_init_cpu)
2: msr SPsel, #1 // We want to use SP_EL{1,2}
+ init_el2_hcr 0
+
/* Initialize EL2 CPU state to sane values. */
init_el2_state // Clobbers x0..x2
finalise_el2_state
--
2.55.0.795.g602f6c329a-goog
^ permalink raw reply related [flat|nested] 9+ messages in thread
* [PATCH 6.6 v2 5/6] KVM: arm64: Initialize SCTLR_EL1 in __kvm_hyp_init_cpu()
2026-07-08 22:51 [PATCH 6.6 v2 0/6] arm64: KVM: Backport VHE-only boot fixes Colton Lewis
` (3 preceding siblings ...)
2026-07-08 22:51 ` [PATCH 6.6 v2 4/6] KVM: arm64: Initialize HCR_EL2.E2H early Colton Lewis
@ 2026-07-08 22:51 ` Colton Lewis
2026-07-08 22:51 ` [PATCH 6.6 v2 6/6] arm64: Revamp HCR_EL2.E2H RES1 detection Colton Lewis
5 siblings, 0 replies; 9+ messages in thread
From: Colton Lewis @ 2026-07-08 22:51 UTC (permalink / raw)
To: stable
Cc: oliver.upton, sashal, gregkh, mizhang, catalin.marinas, will, maz,
james.morse, suzuki.poulose, yuzenghui, mark.rutland,
ahmed.genidi, leo.yan, miguel.luis, dbrazdil, kvmarm,
linux-arm-kernel, linux-kernel, Ben Horgan
From: Ahmed Genidi <ahmed.genidi@arm.com>
[ Upstream commit 3855a7b91d42ebf3513b7ccffc44807274978b3d ]
When KVM is in protected mode, host calls to PSCI are proxied via EL2,
and cold entries from CPU_ON, CPU_SUSPEND, and SYSTEM_SUSPEND bounce
through __kvm_hyp_init_cpu() at EL2 before entering the host kernel's
entry point at EL1. While __kvm_hyp_init_cpu() initializes SPSR_EL2 for
the exception return to EL1, it does not initialize SCTLR_EL1.
Due to this, it's possible to enter EL1 with SCTLR_EL1 in an UNKNOWN
state. In practice this has been seen to result in kernel crashes after
CPU_ON as a result of SCTLR_EL1.M being 1 in violation of the initial
core configuration specified by PSCI.
Fix this by initializing SCTLR_EL1 for cold entry to the host kernel.
As it's necessary to write to SCTLR_EL12 in VHE mode, this
initialization is moved into __kvm_host_psci_cpu_entry() where we can
use write_sysreg_el1().
The remnants of the '__init_el2_nvhe_prepare_eret' macro are folded into
its only caller, as this is clearer than having the macro.
Fixes: cdf367192766ad11 ("KVM: arm64: Intercept host's CPU_ON SMCs")
Reported-by: Leo Yan <leo.yan@arm.com>
Signed-off-by: Ahmed Genidi <ahmed.genidi@arm.com>
[ Mark: clarify commit message, handle E2H, move to C, remove macro ]
Signed-off-by: Mark Rutland <mark.rutland@arm.com>
Cc: Ahmed Genidi <ahmed.genidi@arm.com>
Cc: Ben Horgan <ben.horgan@arm.com>
Cc: Catalin Marinas <catalin.marinas@arm.com>
Cc: Leo Yan <leo.yan@arm.com>
Cc: Marc Zyngier <maz@kernel.org>
Cc: Oliver Upton <oliver.upton@linux.dev>
Cc: Will Deacon <will@kernel.org>
Reviewed-by: Leo Yan <leo.yan@arm.com>
Link: https://lore.kernel.org/r/20250227180526.1204723-3-mark.rutland@arm.com
Signed-off-by: Marc Zyngier <maz@kernel.org>
---
arch/arm64/include/asm/el2_setup.h | 4 ----
arch/arm64/kernel/head.S | 3 ++-
arch/arm64/kvm/hyp/nvhe/hyp-init.S | 1 -
arch/arm64/kvm/hyp/nvhe/psci-relay.c | 3 +++
4 files changed, 5 insertions(+), 6 deletions(-)
diff --git a/arch/arm64/include/asm/el2_setup.h b/arch/arm64/include/asm/el2_setup.h
index 3498dc5d02c18..76b0d50d286d5 100644
--- a/arch/arm64/include/asm/el2_setup.h
+++ b/arch/arm64/include/asm/el2_setup.h
@@ -229,10 +229,6 @@
.Lskip_fgt_\@:
.endm
-.macro __init_el2_nvhe_prepare_eret
- mov x0, #INIT_PSTATE_EL1
- msr spsr_el2, x0
-.endm
/**
* Initialize EL2 registers to sane values. This should be called early on all
diff --git a/arch/arm64/kernel/head.S b/arch/arm64/kernel/head.S
index ff7769821166a..9996029853d23 100644
--- a/arch/arm64/kernel/head.S
+++ b/arch/arm64/kernel/head.S
@@ -601,7 +601,8 @@ SYM_INNER_LABEL(init_el2, SYM_L_LOCAL)
msr sctlr_el1, x1
mov x2, xzr
3:
- __init_el2_nvhe_prepare_eret
+ mov x0, #INIT_PSTATE_EL1
+ msr spsr_el2, x0
mov w0, #BOOT_CPU_MODE_EL2
orr x0, x0, x2
diff --git a/arch/arm64/kvm/hyp/nvhe/hyp-init.S b/arch/arm64/kvm/hyp/nvhe/hyp-init.S
index 3efa9cfaa9d48..9b2ada54be538 100644
--- a/arch/arm64/kvm/hyp/nvhe/hyp-init.S
+++ b/arch/arm64/kvm/hyp/nvhe/hyp-init.S
@@ -207,7 +207,6 @@ SYM_CODE_START_LOCAL(__kvm_hyp_init_cpu)
/* Initialize EL2 CPU state to sane values. */
init_el2_state // Clobbers x0..x2
finalise_el2_state
- __init_el2_nvhe_prepare_eret
/* Enable MMU, set vectors and stack. */
mov x0, x28
diff --git a/arch/arm64/kvm/hyp/nvhe/psci-relay.c b/arch/arm64/kvm/hyp/nvhe/psci-relay.c
index d57bcb6ab94d2..5688a16e2ea75 100644
--- a/arch/arm64/kvm/hyp/nvhe/psci-relay.c
+++ b/arch/arm64/kvm/hyp/nvhe/psci-relay.c
@@ -218,6 +218,9 @@ asmlinkage void __noreturn __kvm_host_psci_cpu_entry(bool is_cpu_on)
if (is_cpu_on)
release_boot_args(boot_args);
+ write_sysreg_el1(INIT_SCTLR_EL1_MMU_OFF, SYS_SCTLR);
+ write_sysreg(INIT_PSTATE_EL1, SPSR_EL2);
+
__host_enter(host_ctxt);
}
--
2.55.0.795.g602f6c329a-goog
^ permalink raw reply related [flat|nested] 9+ messages in thread
* [PATCH 6.6 v2 6/6] arm64: Revamp HCR_EL2.E2H RES1 detection
2026-07-08 22:51 [PATCH 6.6 v2 0/6] arm64: KVM: Backport VHE-only boot fixes Colton Lewis
` (4 preceding siblings ...)
2026-07-08 22:51 ` [PATCH 6.6 v2 5/6] KVM: arm64: Initialize SCTLR_EL1 in __kvm_hyp_init_cpu() Colton Lewis
@ 2026-07-08 22:51 ` Colton Lewis
5 siblings, 0 replies; 9+ messages in thread
From: Colton Lewis @ 2026-07-08 22:51 UTC (permalink / raw)
To: stable
Cc: oliver.upton, sashal, gregkh, mizhang, catalin.marinas, will, maz,
james.morse, suzuki.poulose, yuzenghui, mark.rutland,
ahmed.genidi, leo.yan, miguel.luis, dbrazdil, kvmarm,
linux-arm-kernel, linux-kernel, Jan Kotas
From: Marc Zyngier <maz@kernel.org>
[ Upstream commit ca88ecdce5f51874a7c151809bd2c936ee0d3805 ]
We currently have two ways to identify CPUs that only implement FEAT_VHE
and not FEAT_E2H0:
- either they advertise it via ID_AA64MMFR4_EL1.E2H0,
- or the HCR_EL2.E2H bit is RAO/WI
However, there is a third category of "cpus" that fall between these
two cases: on CPUs that do not implement FEAT_FGT, it is IMPDEF whether
an access to ID_AA64MMFR4_EL1 can trap to EL2 when the register value
is zero.
A consequence of this is that on systems such as Neoverse V2, a NV
guest cannot reliably detect that it is in a VHE-only configuration
(E2H is writable, and ID_AA64MMFR0_EL1 is 0), despite the hypervisor's
best effort to repaint the id register.
Replace the RAO/WI test by a sequence that makes use of the VHE
register remnapping between EL1 and EL2 to detect this situation,
and work out whether we get the VHE behaviour even after having
set HCR_EL2.E2H to 0.
This solves the NV problem, and provides a more reliable acid test
for CPUs that do not completely follow the letter of the architecture
while providing a RES1 behaviour for HCR_EL2.E2H.
Suggested-by: Mark Rutland <mark.rutland@arm.com>
Acked-by: Mark Rutland <mark.rutland@arm.com>
Acked-by: Catalin Marinas <catalin.marinas@arm.com>
Reviewed-by: Oliver Upton <oliver.upton@linux.dev>
Tested-by: Jan Kotas <jank@cadence.com>
Signed-off-by: Marc Zyngier <maz@kernel.org>
Link: https://lore.kernel.org/r/15A85F2B-1A0C-4FA7-9FE4-EEC2203CC09E@global.cadence.com
[ Backport: Resolved conflict in arch/arm64/include/asm/el2_setup.h
by replacing msr_hcr_el2 macro usages with raw msr hcr_el2 (since
the macro is missing in 6.6.y). ]
---
arch/arm64/include/asm/el2_setup.h | 38 +++++++++++++++++++++++++-----
1 file changed, 32 insertions(+), 6 deletions(-)
diff --git a/arch/arm64/include/asm/el2_setup.h b/arch/arm64/include/asm/el2_setup.h
index 76b0d50d286d5..4c7467b382b60 100644
--- a/arch/arm64/include/asm/el2_setup.h
+++ b/arch/arm64/include/asm/el2_setup.h
@@ -24,22 +24,48 @@
* ID_AA64MMFR4_EL1.E2H0 < 0. On such CPUs HCR_EL2.E2H is RES1, but it
* can reset into an UNKNOWN state and might not read as 1 until it has
* been initialized explicitly.
- *
- * Fruity CPUs seem to have HCR_EL2.E2H set to RAO/WI, but
- * don't advertise it (they predate this relaxation).
- *
* Initalize HCR_EL2.E2H so that later code can rely upon HCR_EL2.E2H
* indicating whether the CPU is running in E2H mode.
*/
mrs_s x1, SYS_ID_AA64MMFR4_EL1
sbfx x1, x1, #ID_AA64MMFR4_EL1_E2H0_SHIFT, #ID_AA64MMFR4_EL1_E2H0_WIDTH
cmp x1, #0
- b.ge .LnVHE_\@
+ b.lt .LnE2H0_\@
+ /*
+ * Unfortunately, HCR_EL2.E2H can be RES1 even if not advertised
+ * as such via ID_AA64MMFR4_EL1.E2H0:
+ *
+ * - Fruity CPUs predate the !FEAT_E2H0 relaxation, and seem to
+ * have HCR_EL2.E2H implemented as RAO/WI.
+ *
+ * - On CPUs that lack FEAT_FGT, a hypervisor can't trap guest
+ * reads of ID_AA64MMFR4_EL1 to advertise !FEAT_E2H0. NV
+ * guests on these hosts can write to HCR_EL2.E2H without
+ * trapping to the hypervisor, but these writes have no
+ * functional effect.
+ *
+ * Handle both cases by checking for an essential VHE property
+ * (system register remapping) to decide whether we're
+ * effectively VHE-only or not.
+ */
+ msr hcr_el2, x0 // Setup HCR_EL2 as nVHE
+ isb
+ mov x1, #1 // Write something to FAR_EL1
+ msr far_el1, x1
+ isb
+ mov x1, #2 // Try to overwrite it via FAR_EL2
+ msr far_el2, x1
+ isb
+ mrs x1, far_el1 // If we see the latest write in FAR_EL1,
+ cmp x1, #2 // we can safely assume we are VHE only.
+ b.ne .LnVHE_\@ // Otherwise, we know that nVHE works.
+
+.LnE2H0_\@:
orr x0, x0, #HCR_E2H
-.LnVHE_\@:
msr hcr_el2, x0
isb
+.LnVHE_\@:
.endm
.macro __init_el2_sctlr
--
2.55.0.795.g602f6c329a-goog
^ permalink raw reply related [flat|nested] 9+ messages in thread
* Re: [PATCH 6.6 v2 1/6] arm64: sysreg: Add layout for ID_AA64MMFR4_EL1
2026-07-08 22:51 ` [PATCH 6.6 v2 1/6] arm64: sysreg: Add layout for ID_AA64MMFR4_EL1 Colton Lewis
@ 2026-07-09 10:16 ` Marc Zyngier
2026-07-09 20:30 ` Colton Lewis
0 siblings, 1 reply; 9+ messages in thread
From: Marc Zyngier @ 2026-07-09 10:16 UTC (permalink / raw)
To: Colton Lewis
Cc: stable, oliver.upton, sashal, gregkh, mizhang, catalin.marinas,
will, james.morse, suzuki.poulose, yuzenghui, mark.rutland,
ahmed.genidi, leo.yan, miguel.luis, dbrazdil, kvmarm,
linux-arm-kernel, linux-kernel
On Wed, 08 Jul 2026 23:51:19 +0100,
Colton Lewis <coltonlewis@google.com> wrote:
>
> From: Marc Zyngier <maz@kernel.org>
>
> [ Upstream commit cfc680bb04c54e61faa51a34d8383a0aa25b583f ]
>
> ARMv9.5 has infroduced ID_AA64MMFR4_EL1 with a bunch of new features.
> Add the corresponding layout.
>
> This is extracted from the public ARM SysReg_xml_A_profile-2023-09
> delivery, timestamped d55f5af8e09052abe92a02adf820deea2eaed717.
>
> Reviewed-by: Suzuki K Poulose <suzuki.poulose@arm.com>
> Signed-off-by: Marc Zyngier <maz@kernel.org>
> Reviewed-by: Catalin Marinas <catalin.marinas@arm.com>
> Reviewed-by: Miguel Luis <miguel.luis@oracle.com>
> Link: https://lore.kernel.org/r/20240122181344.258974-5-maz@kernel.org
> Signed-off-by: Oliver Upton <oliver.upton@linux.dev>
Please read Documentation/process/backporting.rst, and in particular
the section indicating the requirement for your own SoB.
None of these patches can be merged if this is missing.
M.
--
Jazz isn't dead. It just smells funny.
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH 6.6 v2 1/6] arm64: sysreg: Add layout for ID_AA64MMFR4_EL1
2026-07-09 10:16 ` Marc Zyngier
@ 2026-07-09 20:30 ` Colton Lewis
0 siblings, 0 replies; 9+ messages in thread
From: Colton Lewis @ 2026-07-09 20:30 UTC (permalink / raw)
To: Marc Zyngier
Cc: stable, oliver.upton, sashal, gregkh, mizhang, catalin.marinas,
will, james.morse, suzuki.poulose, yuzenghui, mark.rutland,
ahmed.genidi, leo.yan, miguel.luis, dbrazdil, kvmarm,
linux-arm-kernel, linux-kernel
Hi Marc,
Marc Zyngier <maz@kernel.org> writes:
> On Wed, 08 Jul 2026 23:51:19 +0100,
> Colton Lewis <coltonlewis@google.com> wrote:
>> From: Marc Zyngier <maz@kernel.org>
>> [ Upstream commit cfc680bb04c54e61faa51a34d8383a0aa25b583f ]
>> ARMv9.5 has infroduced ID_AA64MMFR4_EL1 with a bunch of new features.
>> Add the corresponding layout.
>> This is extracted from the public ARM SysReg_xml_A_profile-2023-09
>> delivery, timestamped d55f5af8e09052abe92a02adf820deea2eaed717.
>> Reviewed-by: Suzuki K Poulose <suzuki.poulose@arm.com>
>> Signed-off-by: Marc Zyngier <maz@kernel.org>
>> Reviewed-by: Catalin Marinas <catalin.marinas@arm.com>
>> Reviewed-by: Miguel Luis <miguel.luis@oracle.com>
>> Link: https://lore.kernel.org/r/20240122181344.258974-5-maz@kernel.org
>> Signed-off-by: Oliver Upton <oliver.upton@linux.dev>
> Please read Documentation/process/backporting.rst, and in particular
> the section indicating the requirement for your own SoB.
> None of these patches can be merged if this is missing.
That taught me a few tricks. Thanks. And I'll make sure to include my
SoB.
> M.
> --
> Jazz isn't dead. It just smells funny.
^ permalink raw reply [flat|nested] 9+ messages in thread
end of thread, other threads:[~2026-07-09 20:30 UTC | newest]
Thread overview: 9+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-07-08 22:51 [PATCH 6.6 v2 0/6] arm64: KVM: Backport VHE-only boot fixes Colton Lewis
2026-07-08 22:51 ` [PATCH 6.6 v2 1/6] arm64: sysreg: Add layout for ID_AA64MMFR4_EL1 Colton Lewis
2026-07-09 10:16 ` Marc Zyngier
2026-07-09 20:30 ` Colton Lewis
2026-07-08 22:51 ` [PATCH 6.6 v2 2/6] arm64: Treat HCR_EL2.E2H as RES1 when ID_AA64MMFR4_EL1.E2H0 is negative Colton Lewis
2026-07-08 22:51 ` [PATCH 6.6 v2 3/6] arm64: Fix early handling of FEAT_E2H0 not being implemented Colton Lewis
2026-07-08 22:51 ` [PATCH 6.6 v2 4/6] KVM: arm64: Initialize HCR_EL2.E2H early Colton Lewis
2026-07-08 22:51 ` [PATCH 6.6 v2 5/6] KVM: arm64: Initialize SCTLR_EL1 in __kvm_hyp_init_cpu() Colton Lewis
2026-07-08 22:51 ` [PATCH 6.6 v2 6/6] arm64: Revamp HCR_EL2.E2H RES1 detection Colton Lewis
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox