Skip to contentSkip to conversation

KVM: arm64: Fix CPU interface MMIO compatibility detection

PATCH In review Marc Zyngier 2 participants 2 messages Mar 23, 2021 – Mar 24, 2021

Subsystems (3)
lore
Share & tools
lore

Marc Zyngier

author maintainer
#0 lore raw

PATCH 1/1 KVM: arm64: Fix CPU interface MMIO compatibility detection

In order to detect whether a GICv3 CPU interface is MMIO capable, we switch ICC_SRE_EL1.SRE to 0 and check whether it sticks.

However, this is only possible if *ALL* of the HCR_EL2 interrupt overrides are set, and the CPU is perfectly allowed to ignore the write to ICC_SRE_EL1 otherwise. This leads KVM to pretend that a whole bunch of ARMv8.0 CPUs aren't MMIO-capable, and breaks VMs that should work correctly otherwise.

Fix this by setting IMO/FMO/IMO before touching ICC_SRE_EL1, and clear them afterwards. This allows us to reliably detect the CPU interface capabilities.

Cc Shameerali Kolothum Thodi <[email protected]>
Fixes 9739f6ef053f ("KVM: arm64: Workaround firmware wrongly advertising GICv2-on-v3 compatibility")
---
 arch/arm64/kvm/hyp/vgic-v3-sr.c | 9 +++++++++
 1 file changed, 9 insertions(+)
arch/arm64/kvm/hyp/vgic-v3-sr.c +9 -0
index ee3682b9873c..39f8f7f9227c 100644
@@ -429,6 +429,13 @@ u64 __vgic_v3_get_gic_config(void)
 	if (has_vhe())
 		flags = local_daif_save();
 
+	/*
+	 * Table 11-2 "Permitted ICC_SRE_ELx.SRE settings" indicates
+	 * that to be able to set ICC_SRE_EL1.SRE to 0, all the
+	 * interrupt overrides must be set. You've got to love this.
+	 */
+	sysreg_clear_set(hcr_el2, 0, HCR_AMO | HCR_FMO | HCR_IMO);
+	isb();
 	write_gicreg(0, ICC_SRE_EL1);
 	isb();
 
@@ -436,6 +443,8 @@ u64 __vgic_v3_get_gic_config(void)
 
 	write_gicreg(sre, ICC_SRE_EL1);
 	isb();
+	sysreg_clear_set(hcr_el2, HCR_AMO | HCR_FMO | HCR_IMO, 0);
+	isb();
 
 	if (has_vhe())
 		local_daif_restore(flags);
Signature · 6 lines
2.30.0

_______________________________________________
kvmarm mailing list
[email protected]
https://lists.cs.columbia.edu/mailman/listinfo/kvmarm
Tested-by on v1 1/1
#1 lore raw
Quoted 20 lines

-----Original Message-----
From: Marc Zyngier [mailto:[email protected]]
Sent: 23 March 2021 16:23
To: [email protected]; [email protected]; [email protected]
Cc: Ard Biesheuvel <[email protected]>; [email protected]; Shameerali Kolothum Thodi <[email protected]>
Subject: [PATCH] KVM: arm64: Fix CPU interface MMIO compatibility detection

In order to detect whether a GICv3 CPU interface is MMIO capable, we switch ICC_SRE_EL1.SRE to 0 and check whether it sticks.

However, this is only possible if *ALL* of the HCR_EL2 interrupt overrides are set, and the CPU is perfectly allowed to ignore the write to ICC_SRE_EL1 otherwise. This leads KVM to pretend that a whole bunch of ARMv8.0 CPUs aren't MMIO-capable, and breaks VMs that should work correctly otherwise.

Quoted 4 lines

Fix this by setting IMO/FMO/IMO before touching ICC_SRE_EL1, and clear them afterwards. This allows us to reliably detect the CPU interface capabilities.

Tested on HiSilicon D06 platform where the original issue(firmware wrongly advertising GICv2-on-v3 compatibility) was reported and all seems to be fine.

Though not sure whether this fix is relevant to this particular platform, FWIW,

Thanks,
Shameer

Quoted 37 lines
Cc Shameerali Kolothum Thodi <[email protected]>
Fixes 9739f6ef053f ("KVM: arm64: Workaround firmware wrongly advertising

GICv2-on-v3 compatibility")

---
 arch/arm64/kvm/hyp/vgic-v3-sr.c | 9 +++++++++
 1 file changed, 9 insertions(+)
arch/arm64/kvm/hyp/vgic-v3-sr.c +9 -1
index ee3682b9873c..39f8f7f9227c 100644
@@ -429,6 +429,13 @@ u64 __vgic_v3_get_gic_config(void)
 	if (has_vhe())
 		flags = local_daif_save();
 
+	/*
+	 * Table 11-2 "Permitted ICC_SRE_ELx.SRE settings" indicates
+	 * that to be able to set ICC_SRE_EL1.SRE to 0, all the
+	 * interrupt overrides must be set. You've got to love this.
+	 */
+	sysreg_clear_set(hcr_el2, 0, HCR_AMO | HCR_FMO | HCR_IMO);
+	isb();
 	write_gicreg(0, ICC_SRE_EL1);
 	isb();
 
@@ -436,6 +443,8 @@ u64 __vgic_v3_get_gic_config(void)
 
 	write_gicreg(sre, ICC_SRE_EL1);
 	isb();
+	sysreg_clear_set(hcr_el2, HCR_AMO | HCR_FMO | HCR_IMO, 0);
+	isb();
 
 	if (has_vhe())
 		local_daif_restore(flags);
--
Quoted 1 line

2.30.0

_______________________________________________
kvmarm mailing list
[email protected]
https://lists.cs.columbia.edu/mailman/listinfo/kvmarm