Skip to content

Commit 7a68b55

Browse files
Mark RutlandMarc Zyngier
Mark Rutland
authored and
Marc Zyngier
committed
KVM: arm64: Initialize HCR_EL2.E2H early
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 <[email protected]> Cc: Ahmed Genidi <[email protected]> Cc: Ben Horgan <[email protected]> Cc: Catalin Marinas <[email protected]> Cc: Leo Yan <[email protected]> Cc: Marc Zyngier <[email protected]> Cc: Oliver Upton <[email protected]> Cc: Will Deacon <[email protected]> Link: https://lore.kernel.org/r/[email protected] [maz: fixed LT->GE thinko] Signed-off-by: Marc Zyngier <[email protected]>
1 parent fa808ed commit 7a68b55

File tree

3 files changed

+34
-19
lines changed

3 files changed

+34
-19
lines changed

arch/arm64/include/asm/el2_setup.h

+26
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

+1-18
Original file line numberDiff line numberDiff line change
@@ -298,25 +298,8 @@ SYM_INNER_LABEL(init_el2, SYM_L_LOCAL)
298298
msr sctlr_el2, x0
299299
isb
300300
0:
301-
mov_q x0, HCR_HOST_NVHE_FLAGS
302-
303-
/*
304-
* Compliant CPUs advertise their VHE-onlyness with
305-
* ID_AA64MMFR4_EL1.E2H0 < 0. HCR_EL2.E2H can be
306-
* RES1 in that case. Publish the E2H bit early so that
307-
* it can be picked up by the init_el2_state macro.
308-
*
309-
* Fruity CPUs seem to have HCR_EL2.E2H set to RAO/WI, but
310-
* don't advertise it (they predate this relaxation).
311-
*/
312-
mrs_s x1, SYS_ID_AA64MMFR4_EL1
313-
tbz x1, #(ID_AA64MMFR4_EL1_E2H0_SHIFT + ID_AA64MMFR4_EL1_E2H0_WIDTH - 1), 1f
314-
315-
orr x0, x0, #HCR_E2H
316-
1:
317-
msr hcr_el2, x0
318-
isb
319301

302+
init_el2_hcr HCR_HOST_NVHE_FLAGS
320303
init_el2_state
321304

322305
/* Hypervisor stub */

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

+7-1
Original file line numberDiff line numberDiff line change
@@ -73,8 +73,12 @@ __do_hyp_init:
7373
eret
7474
SYM_CODE_END(__kvm_hyp_init)
7575

76+
/*
77+
* Initialize EL2 CPU state to sane values.
78+
*
79+
* HCR_EL2.E2H must have been initialized already.
80+
*/
7681
SYM_CODE_START_LOCAL(__kvm_init_el2_state)
77-
/* Initialize EL2 CPU state to sane values. */
7882
init_el2_state // Clobbers x0..x2
7983
finalise_el2_state
8084
ret
@@ -206,6 +210,8 @@ SYM_CODE_START_LOCAL(__kvm_hyp_init_cpu)
206210

207211
2: msr SPsel, #1 // We want to use SP_EL{1,2}
208212

213+
init_el2_hcr 0
214+
209215
bl __kvm_init_el2_state
210216

211217
__init_el2_nvhe_prepare_eret

0 commit comments

Comments
 (0)