Skip to content

Commit 5739a96

Browse files
author
Marc Zyngier
committed
KVM: arm64: Force SRE traps when SRE access is not enabled
We so far only write the ICH_HCR_EL2 config in two situations: - when we need to emulate the GICv3 CPU interface due to HW bugs - when we do direct injection, as the virtual CPU interface needs to be enabled This is all good. But it also means that we don't do anything special when we emulate a GICv2, or that there is no GIC at all. What happens in this case when the guest uses the GICv3 system registers? The *guest* gets a trap for a sysreg access (EC=0x18) while we'd really like it to get an UNDEF. Fixing this is a bit involved: - we need to set all the required trap bits (TC, TALL0, TALL1, TDIR) - for these traps to take effect, we need to (counter-intuitively) set ICC_SRE_EL1.SRE to 1 so that the above traps take priority. Note that doesn't fully work when GICv2 emulation is enabled, as we cannot set ICC_SRE_EL1.SRE to 1 (it breaks Group0 delivery as IRQ). Reviewed-by: Oliver Upton <oliver.upton@linux.dev> Link: https://lore.kernel.org/r/20240827152517.3909653-3-maz@kernel.org Signed-off-by: Marc Zyngier <maz@kernel.org>
1 parent d2137ba commit 5739a96

2 files changed

Lines changed: 20 additions & 7 deletions

File tree

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

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -268,8 +268,16 @@ void __vgic_v3_activate_traps(struct vgic_v3_cpu_if *cpu_if)
268268
* starting to mess with the rest of the GIC, and VMCR_EL2 in
269269
* particular. This logic must be called before
270270
* __vgic_v3_restore_state().
271+
*
272+
* However, if the vgic is disabled (ICH_HCR_EL2.EN==0), no GIC is
273+
* provisioned at all. In order to prevent illegal accesses to the
274+
* system registers to trap to EL1 (duh), force ICC_SRE_EL1.SRE to 1
275+
* so that the trap bits can take effect. Yes, we *loves* the GIC.
271276
*/
272-
if (!cpu_if->vgic_sre) {
277+
if (!(cpu_if->vgic_hcr & ICH_HCR_EN)) {
278+
write_gicreg(ICC_SRE_EL1_SRE, ICC_SRE_EL1);
279+
isb();
280+
} else if (!cpu_if->vgic_sre) {
273281
write_gicreg(0, ICC_SRE_EL1);
274282
isb();
275283
write_gicreg(cpu_if->vgic_vmcr, ICH_VMCR_EL2);
@@ -288,19 +296,21 @@ void __vgic_v3_activate_traps(struct vgic_v3_cpu_if *cpu_if)
288296
}
289297

290298
/*
291-
* Prevent the guest from touching the GIC system registers if
292-
* SRE isn't enabled for GICv3 emulation.
299+
* Prevent the guest from touching the ICC_SRE_EL1 system
300+
* register. Note that this may not have any effect, as
301+
* ICC_SRE_EL2.Enable being RAO/WI is a valid implementation.
293302
*/
294303
write_gicreg(read_gicreg(ICC_SRE_EL2) & ~ICC_SRE_EL2_ENABLE,
295304
ICC_SRE_EL2);
296305

297306
/*
298307
* If we need to trap system registers, we must write
299308
* ICH_HCR_EL2 anyway, even if no interrupts are being
300-
* injected,
309+
* injected. Note that this also applies if we don't expect
310+
* any system register access (no vgic at all).
301311
*/
302312
if (static_branch_unlikely(&vgic_v3_cpuif_trap) ||
303-
cpu_if->its_vpe.its_vm)
313+
cpu_if->its_vpe.its_vm || !cpu_if->vgic_sre)
304314
write_gicreg(cpu_if->vgic_hcr, ICH_HCR_EL2);
305315
}
306316

@@ -326,7 +336,7 @@ void __vgic_v3_deactivate_traps(struct vgic_v3_cpu_if *cpu_if)
326336
* no interrupts were being injected, and we disable it again here.
327337
*/
328338
if (static_branch_unlikely(&vgic_v3_cpuif_trap) ||
329-
cpu_if->its_vpe.its_vm)
339+
cpu_if->its_vpe.its_vm || !cpu_if->vgic_sre)
330340
write_gicreg(0, ICH_HCR_EL2);
331341
}
332342

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

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -298,8 +298,11 @@ void vcpu_set_ich_hcr(struct kvm_vcpu *vcpu)
298298
{
299299
struct vgic_v3_cpu_if *vgic_v3 = &vcpu->arch.vgic_cpu.vgic_v3;
300300

301-
if (!kvm_has_gicv3(vcpu->kvm))
301+
/* Hide GICv3 sysreg if necessary */
302+
if (!kvm_has_gicv3(vcpu->kvm)) {
303+
vgic_v3->vgic_hcr |= ICH_HCR_TALL0 | ICH_HCR_TALL1 | ICH_HCR_TC;
302304
return;
305+
}
303306

304307
if (group0_trap)
305308
vgic_v3->vgic_hcr |= ICH_HCR_TALL0;

0 commit comments

Comments
 (0)