Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

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>

+21 -16
+3
arch/arm64/kernel/image-vars.h
··· 105 105 KVM_NVHE_ALIAS(vgic_v2_cpuif_trap); 106 106 KVM_NVHE_ALIAS(vgic_v3_cpuif_trap); 107 107 108 + /* Static key indicating whether GICv3 has GICv2 compatibility */ 109 + KVM_NVHE_ALIAS(vgic_v3_has_v2_compat); 110 + 108 111 /* Static key which is set if CNTVOFF_EL2 is unusable */ 109 112 KVM_NVHE_ALIAS(broken_cntvoff_key); 110 113
+9 -16
arch/arm64/kvm/hyp/vgic-v3-sr.c
··· 295 295 } 296 296 } 297 297 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)) { 304 300 /* 305 301 * Prevent the guest from touching the ICC_SRE_EL1 system 306 302 * register. Note that this may not have any effect, as ··· 325 329 cpu_if->vgic_vmcr = read_gicreg(ICH_VMCR_EL2); 326 330 } 327 331 328 - /* 329 - * Can be dropped in the future when GICv5 spec is relaxed. See comment 330 - * above. 331 - */ 332 - if (!cpus_have_final_cap(ARM64_HAS_GICV5_CPUIF)) { 332 + /* Only restore SRE if the host implements the GICv2 interface */ 333 + if (static_branch_unlikely(&vgic_v3_has_v2_compat)) { 333 334 val = read_gicreg(ICC_SRE_EL2); 334 335 write_gicreg(val | ICC_SRE_EL2_ENABLE, ICC_SRE_EL2); 335 - } 336 336 337 - if (!cpu_if->vgic_sre) { 338 - /* Make sure ENABLE is set at EL2 before setting SRE at EL1 */ 339 - isb(); 340 - write_gicreg(1, ICC_SRE_EL1); 337 + if (!cpu_if->vgic_sre) { 338 + /* Make sure ENABLE is set at EL2 before setting SRE at EL1 */ 339 + isb(); 340 + write_gicreg(1, ICC_SRE_EL1); 341 + } 341 342 } 342 343 343 344 /*
+8
arch/arm64/kvm/vgic/vgic-v3.c
··· 588 588 } 589 589 590 590 DEFINE_STATIC_KEY_FALSE(vgic_v3_cpuif_trap); 591 + DEFINE_STATIC_KEY_FALSE(vgic_v3_has_v2_compat); 591 592 592 593 static int __init early_group0_trap_cfg(char *buf) 593 594 { ··· 697 696 698 697 if (kvm_vgic_global_state.vcpu_base == 0) 699 698 kvm_info("disabling GICv2 emulation\n"); 699 + 700 + /* 701 + * Flip the static branch if the HW supports v2, even if we're 702 + * not using it (such as in protected mode). 703 + */ 704 + if (has_v2) 705 + static_branch_enable(&vgic_v3_has_v2_compat); 700 706 701 707 if (cpus_have_final_cap(ARM64_WORKAROUND_CAVIUM_30115)) { 702 708 group0_trap = true;
+1
include/kvm/arm_vgic.h
··· 375 375 376 376 extern struct static_key_false vgic_v2_cpuif_trap; 377 377 extern struct static_key_false vgic_v3_cpuif_trap; 378 + extern struct static_key_false vgic_v3_has_v2_compat; 378 379 379 380 int kvm_set_legacy_vgic_v2_addr(struct kvm *kvm, struct kvm_arm_device_addr *dev_addr); 380 381 void kvm_vgic_early_init(struct kvm *kvm);