Skip to content

Commit 9664d58

Browse files
author
Marc Zyngier
committed
KVM: arm64: Don't access ICC_SRE_EL2 if GICv3 doesn't support v2 compatibility
We currently access ICC_SRE_EL2 at each load/put on VHE, and on each entry/exit on nVHE. Both are quite onerous on NV, as this register always traps. We do this to make sure the EL1 guest doesn't flip between v2 and v3 behind our back. But all modern implementations have dropped v2, and this is just overhead. At the same time, the GICv5 spec has been fixed to allow access to ICC_SRE_EL2 in legacy mode. Use this opportunity to replace the GICv5 checks for v2 compat checks, with an ad-hoc static key. Co-developed-by: Sascha Bischoff <sascha.bischoff@arm.com> Signed-off-by: Sascha Bischoff <sascha.bischoff@arm.com> Reviewed-by: Oliver Upton <oliver.upton@linux.dev> Signed-off-by: Marc Zyngier <maz@kernel.org>
1 parent b320789 commit 9664d58

4 files changed

Lines changed: 21 additions & 16 deletions

File tree

arch/arm64/kernel/image-vars.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,9 @@ KVM_NVHE_ALIAS(__hyp_stub_vectors);
105105
KVM_NVHE_ALIAS(vgic_v2_cpuif_trap);
106106
KVM_NVHE_ALIAS(vgic_v3_cpuif_trap);
107107

108+
/* Static key indicating whether GICv3 has GICv2 compatibility */
109+
KVM_NVHE_ALIAS(vgic_v3_has_v2_compat);
110+
108111
/* Static key which is set if CNTVOFF_EL2 is unusable */
109112
KVM_NVHE_ALIAS(broken_cntvoff_key);
110113

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

Lines changed: 9 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -295,12 +295,8 @@ void __vgic_v3_activate_traps(struct vgic_v3_cpu_if *cpu_if)
295295
}
296296
}
297297

298-
/*
299-
* GICv5 BET0 FEAT_GCIE_LEGACY doesn't include ICC_SRE_EL2. This is due
300-
* to be relaxed in a future spec release, at which point this in
301-
* condition can be dropped.
302-
*/
303-
if (!cpus_have_final_cap(ARM64_HAS_GICV5_CPUIF)) {
298+
/* Only disable SRE if the host implements the GICv2 interface */
299+
if (static_branch_unlikely(&vgic_v3_has_v2_compat)) {
304300
/*
305301
* Prevent the guest from touching the ICC_SRE_EL1 system
306302
* register. Note that this may not have any effect, as
@@ -329,19 +325,16 @@ void __vgic_v3_deactivate_traps(struct vgic_v3_cpu_if *cpu_if)
329325
cpu_if->vgic_vmcr = read_gicreg(ICH_VMCR_EL2);
330326
}
331327

332-
/*
333-
* Can be dropped in the future when GICv5 spec is relaxed. See comment
334-
* above.
335-
*/
336-
if (!cpus_have_final_cap(ARM64_HAS_GICV5_CPUIF)) {
328+
/* Only restore SRE if the host implements the GICv2 interface */
329+
if (static_branch_unlikely(&vgic_v3_has_v2_compat)) {
337330
val = read_gicreg(ICC_SRE_EL2);
338331
write_gicreg(val | ICC_SRE_EL2_ENABLE, ICC_SRE_EL2);
339-
}
340332

341-
if (!cpu_if->vgic_sre) {
342-
/* Make sure ENABLE is set at EL2 before setting SRE at EL1 */
343-
isb();
344-
write_gicreg(1, ICC_SRE_EL1);
333+
if (!cpu_if->vgic_sre) {
334+
/* Make sure ENABLE is set at EL2 before setting SRE at EL1 */
335+
isb();
336+
write_gicreg(1, ICC_SRE_EL1);
337+
}
345338
}
346339

347340
/*

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

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -588,6 +588,7 @@ int vgic_v3_map_resources(struct kvm *kvm)
588588
}
589589

590590
DEFINE_STATIC_KEY_FALSE(vgic_v3_cpuif_trap);
591+
DEFINE_STATIC_KEY_FALSE(vgic_v3_has_v2_compat);
591592

592593
static int __init early_group0_trap_cfg(char *buf)
593594
{
@@ -697,6 +698,13 @@ int vgic_v3_probe(const struct gic_kvm_info *info)
697698
if (kvm_vgic_global_state.vcpu_base == 0)
698699
kvm_info("disabling GICv2 emulation\n");
699700

701+
/*
702+
* Flip the static branch if the HW supports v2, even if we're
703+
* not using it (such as in protected mode).
704+
*/
705+
if (has_v2)
706+
static_branch_enable(&vgic_v3_has_v2_compat);
707+
700708
if (cpus_have_final_cap(ARM64_WORKAROUND_CAVIUM_30115)) {
701709
group0_trap = true;
702710
group1_trap = true;

include/kvm/arm_vgic.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -375,6 +375,7 @@ struct vgic_cpu {
375375

376376
extern struct static_key_false vgic_v2_cpuif_trap;
377377
extern struct static_key_false vgic_v3_cpuif_trap;
378+
extern struct static_key_false vgic_v3_has_v2_compat;
378379

379380
int kvm_set_legacy_vgic_v2_addr(struct kvm *kvm, struct kvm_arm_device_addr *dev_addr);
380381
void kvm_vgic_early_init(struct kvm *kvm);

0 commit comments

Comments
 (0)