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

KVM: arm64: nv: Fold GICv3 host trapping requirements into guest setup

Popular HW that is able to use NV also has a broken vgic implementation
that requires trapping.

On such HW, propagate the host trap bits into the guest's shadow
ICH_HCR_EL2 register, making sure we don't allow an L2 guest to bring
the system down.

This involves a bit of tweaking so that the emulation code correctly
poicks up the shadow state as needed, and to only partially sync
ICH_HCR_EL2 back with the guest state to capture EOIcount.

Signed-off-by: Marc Zyngier <maz@kernel.org>
Link: https://lore.kernel.org/r/20250225172930.1850838-15-maz@kernel.org
Signed-off-by: Oliver Upton <oliver.upton@linux.dev>

authored by

Marc Zyngier and committed by
Oliver Upton
89896cc1 7682c023

+17 -3
+17 -3
arch/arm64/kvm/vgic/vgic-v3-nested.c
··· 296 296 struct vgic_v3_cpu_if *s_cpu_if) 297 297 { 298 298 struct vgic_v3_cpu_if *host_if = &vcpu->arch.vgic_cpu.vgic_v3; 299 + u64 val = 0; 299 300 int i; 300 301 301 - s_cpu_if->vgic_hcr = __vcpu_sys_reg(vcpu, ICH_HCR_EL2); 302 + /* 303 + * If we're on a system with a broken vgic that requires 304 + * trapping, propagate the trapping requirements. 305 + * 306 + * Ah, the smell of rotten fruits... 307 + */ 308 + if (static_branch_unlikely(&vgic_v3_cpuif_trap)) 309 + val = host_if->vgic_hcr & (ICH_HCR_EL2_TALL0 | ICH_HCR_EL2_TALL1 | 310 + ICH_HCR_EL2_TC | ICH_HCR_EL2_TDIR); 311 + s_cpu_if->vgic_hcr = __vcpu_sys_reg(vcpu, ICH_HCR_EL2) | val; 302 312 s_cpu_if->vgic_vmcr = __vcpu_sys_reg(vcpu, ICH_VMCR_EL2); 303 313 s_cpu_if->vgic_sre = host_if->vgic_sre; 304 314 ··· 345 335 { 346 336 struct shadow_if *shadow_if = get_shadow_if(); 347 337 struct vgic_v3_cpu_if *s_cpu_if = &shadow_if->cpuif; 338 + u64 val; 348 339 int i; 349 340 350 341 __vgic_v3_save_vmcr_aprs(s_cpu_if); ··· 356 345 * Translate the shadow state HW fields back to the virtual ones 357 346 * before copying the shadow struct back to the nested one. 358 347 */ 359 - __vcpu_sys_reg(vcpu, ICH_HCR_EL2) = s_cpu_if->vgic_hcr; 348 + val = __vcpu_sys_reg(vcpu, ICH_HCR_EL2); 349 + val &= ~ICH_HCR_EL2_EOIcount_MASK; 350 + val |= (s_cpu_if->vgic_hcr & ICH_HCR_EL2_EOIcount_MASK); 351 + __vcpu_sys_reg(vcpu, ICH_HCR_EL2) = val; 360 352 __vcpu_sys_reg(vcpu, ICH_VMCR_EL2) = s_cpu_if->vgic_vmcr; 361 353 362 354 for (i = 0; i < 4; i++) { ··· 368 354 } 369 355 370 356 for_each_set_bit(i, &shadow_if->lr_map, kvm_vgic_global_state.nr_lr) { 371 - u64 val = __vcpu_sys_reg(vcpu, ICH_LRN(i)); 357 + val = __vcpu_sys_reg(vcpu, ICH_LRN(i)); 372 358 373 359 val &= ~ICH_LR_STATE; 374 360 val |= s_cpu_if->vgic_lr[i] & ICH_LR_STATE;