Skip to content

Commit a2c3433

Browse files
mrutland-armgregkh
authored andcommitted
KVM: arm64: Initialize HCR_EL2.E2H early
[ Upstream commit 7a68b55 ] 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: 3944382 ("arm64: Treat HCR_EL2.E2H as RES1 when ID_AA64MMFR4_EL1.E2H0 is negative") b332014 ("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: 3944382 ("arm64: Treat HCR_EL2.E2H as RES1 when ID_AA64MMFR4_EL1.E2H0 is negative") Fixes: b332014 ("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> [ Backport: Resolved trivial conflict in arch/arm64/kvm/hyp/nvhe/hyp-init.S caused by __kvm_init_el2_state not existing in 6.6.y (EL2 state is initialized inline via init_el2_state / finalise_el2_state); placed init_el2_hcr 0 directly before the inline sequence. ] Signed-off-by: Colton Lewis <coltonlewis@google.com> Signed-off-by: Sasha Levin <sashal@kernel.org>
1 parent 153ed82 commit a2c3433

3 files changed

Lines changed: 29 additions & 18 deletions

File tree

arch/arm64/include/asm/el2_setup.h

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,32 @@
1616
#include <asm/sysreg.h>
1717
#include <linux/irqchip/arm-gic-v3.h>
1818

19+
.macro init_el2_hcr val
20+
mov_q x0, \val
21+
22+
/*
23+
* Compliant CPUs advertise their VHE-onlyness with
24+
* ID_AA64MMFR4_EL1.E2H0 < 0. On such CPUs HCR_EL2.E2H is RES1, but it
25+
* can reset into an UNKNOWN state and might not read as 1 until it has
26+
* been initialized explicitly.
27+
*
28+
* Fruity CPUs seem to have HCR_EL2.E2H set to RAO/WI, but
29+
* don't advertise it (they predate this relaxation).
30+
*
31+
* Initalize HCR_EL2.E2H so that later code can rely upon HCR_EL2.E2H
32+
* indicating whether the CPU is running in E2H mode.
33+
*/
34+
mrs_s x1, SYS_ID_AA64MMFR4_EL1
35+
sbfx x1, x1, #ID_AA64MMFR4_EL1_E2H0_SHIFT, #ID_AA64MMFR4_EL1_E2H0_WIDTH
36+
cmp x1, #0
37+
b.ge .LnVHE_\@
38+
39+
orr x0, x0, #HCR_E2H
40+
.LnVHE_\@:
41+
msr hcr_el2, x0
42+
isb
43+
.endm
44+
1945
.macro __init_el2_sctlr
2046
mov_q x0, INIT_SCTLR_EL2_MMU_OFF
2147
msr sctlr_el2, x0

arch/arm64/kernel/head.S

Lines changed: 1 addition & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -575,25 +575,8 @@ SYM_INNER_LABEL(init_el2, SYM_L_LOCAL)
575575
msr sctlr_el2, x0
576576
isb
577577
0:
578-
mov_q x0, HCR_HOST_NVHE_FLAGS
579-
580-
/*
581-
* Compliant CPUs advertise their VHE-onlyness with
582-
* ID_AA64MMFR4_EL1.E2H0 < 0. HCR_EL2.E2H can be
583-
* RES1 in that case. Publish the E2H bit early so that
584-
* it can be picked up by the init_el2_state macro.
585-
*
586-
* Fruity CPUs seem to have HCR_EL2.E2H set to RAO/WI, but
587-
* don't advertise it (they predate this relaxation).
588-
*/
589-
mrs_s x1, SYS_ID_AA64MMFR4_EL1
590-
tbz x1, #(ID_AA64MMFR4_EL1_E2H0_SHIFT + ID_AA64MMFR4_EL1_E2H0_WIDTH - 1), 1f
591-
592-
orr x0, x0, #HCR_E2H
593-
1:
594-
msr hcr_el2, x0
595-
isb
596578

579+
init_el2_hcr HCR_HOST_NVHE_FLAGS
597580
init_el2_state
598581

599582
/* Hypervisor stub */

arch/arm64/kvm/hyp/nvhe/hyp-init.S

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -202,6 +202,8 @@ SYM_CODE_START_LOCAL(__kvm_hyp_init_cpu)
202202

203203
2: msr SPsel, #1 // We want to use SP_EL{1,2}
204204

205+
init_el2_hcr 0
206+
205207
/* Initialize EL2 CPU state to sane values. */
206208
init_el2_state // Clobbers x0..x2
207209
finalise_el2_state

0 commit comments

Comments
 (0)