Skip to content

Commit 859c602

Browse files
Marc Zyngieroupton
authored andcommitted
KVM: arm64: Force HCR_EL2.xMO to 1 at all times in VHE mode
We keep setting and clearing these bits depending on the role of the host kernel, mimicking what we do for nVHE. But that's actually pretty pointless, as we always want physical interrupts to make it to the host, at EL2. This has also two problems: - it prevents IRQs from being taken when these bits are cleared if the implementation has chosen to implement these bits as masks when HCR_EL2.{TGE,xMO}=={0,0} - it triggers a bad erratum on the AmpereOne HW, which catches fire on clearing these bits while an interrupt is being taken (AC03_CPU_36). Let's kill these two birds with a single stone, and permanently set the xMO bits when running VHE. This involves a bit of surgery on code paths that rely on flipping these bits on and off for other purposes. Note that the earliest setting of hcr_el2 (in the init_hcr_el2 macro) is left untouched as is runs extremely early, with interrupts disabled, and soon enough overwritten with the final value containing the xMO bits. Reported-by: D Scott Phillips <scott@os.amperecomputing.com> Signed-off-by: Marc Zyngier <maz@kernel.org> Link: https://lore.kernel.org/r/20250429114326.3618875-1-maz@kernel.org Signed-off-by: Oliver Upton <oliver.upton@linux.dev>
1 parent 157dbc4 commit 859c602

File tree

2 files changed

+22
-16
lines changed

2 files changed

+22
-16
lines changed

arch/arm64/include/asm/kvm_arm.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@
100100
HCR_FMO | HCR_IMO | HCR_PTW | HCR_TID3 | HCR_TID1)
101101
#define HCR_HOST_NVHE_FLAGS (HCR_RW | HCR_API | HCR_APK | HCR_ATA)
102102
#define HCR_HOST_NVHE_PROTECTED_FLAGS (HCR_HOST_NVHE_FLAGS | HCR_TSC)
103-
#define HCR_HOST_VHE_FLAGS (HCR_RW | HCR_TGE | HCR_E2H)
103+
#define HCR_HOST_VHE_FLAGS (HCR_RW | HCR_TGE | HCR_E2H | HCR_AMO | HCR_IMO | HCR_FMO)
104104

105105
#define HCRX_HOST_FLAGS (HCRX_EL2_MSCEn | HCRX_EL2_TCR2En | HCRX_EL2_EnFPM)
106106
#define MPAMHCR_HOST_FLAGS 0

arch/arm64/kvm/hyp/vgic-v3-sr.c

Lines changed: 21 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -429,35 +429,41 @@ u64 __vgic_v3_get_gic_config(void)
429429
/*
430430
* To check whether we have a MMIO-based (GICv2 compatible)
431431
* CPU interface, we need to disable the system register
432-
* view. To do that safely, we have to prevent any interrupt
433-
* from firing (which would be deadly).
432+
* view.
434433
*
435-
* Note that this only makes sense on VHE, as interrupts are
436-
* already masked for nVHE as part of the exception entry to
437-
* EL2.
438-
*/
439-
if (has_vhe())
440-
flags = local_daif_save();
441-
442-
/*
443434
* Table 11-2 "Permitted ICC_SRE_ELx.SRE settings" indicates
444435
* that to be able to set ICC_SRE_EL1.SRE to 0, all the
445436
* interrupt overrides must be set. You've got to love this.
437+
*
438+
* As we always run VHE with HCR_xMO set, no extra xMO
439+
* manipulation is required in that case.
440+
*
441+
* To safely disable SRE, we have to prevent any interrupt
442+
* from firing (which would be deadly). This only makes sense
443+
* on VHE, as interrupts are already masked for nVHE as part
444+
* of the exception entry to EL2.
446445
*/
447-
sysreg_clear_set(hcr_el2, 0, HCR_AMO | HCR_FMO | HCR_IMO);
448-
isb();
446+
if (has_vhe()) {
447+
flags = local_daif_save();
448+
} else {
449+
sysreg_clear_set(hcr_el2, 0, HCR_AMO | HCR_FMO | HCR_IMO);
450+
isb();
451+
}
452+
449453
write_gicreg(0, ICC_SRE_EL1);
450454
isb();
451455

452456
val = read_gicreg(ICC_SRE_EL1);
453457

454458
write_gicreg(sre, ICC_SRE_EL1);
455459
isb();
456-
sysreg_clear_set(hcr_el2, HCR_AMO | HCR_FMO | HCR_IMO, 0);
457-
isb();
458460

459-
if (has_vhe())
461+
if (has_vhe()) {
460462
local_daif_restore(flags);
463+
} else {
464+
sysreg_clear_set(hcr_el2, HCR_AMO | HCR_FMO | HCR_IMO, 0);
465+
isb();
466+
}
461467

462468
val = (val & ICC_SRE_EL1_SRE) ? 0 : (1ULL << 63);
463469
val |= read_gicreg(ICH_VTR_EL2);

0 commit comments

Comments
 (0)