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: gic-v5: Trap and emulate ICC_IDR0_EL1 accesses

Unless accesses to the ICC_IDR0_EL1 are trapped by KVM, the guest
reads the same state as the host. This isn't desirable as it limits
the migratability of VMs and means that KVM can't hide hardware
features such as FEAT_GCIE_LEGACY.

Trap and emulate accesses to the register, and present KVM's chosen ID
bits and Priority bits (which is 5, as GICv5 only supports 5 bits of
priority in the CPU interface). FEAT_GCIE_LEGACY is never presented to
the guest as it is only relevant for nested guests doing mixed GICv5
and GICv3 support.

Signed-off-by: Sascha Bischoff <sascha.bischoff@arm.com>
Reviewed-by: Jonathan Cameron <jonathan.cameron@huawei.com>
Link: https://patch.msgid.link/20260319154937.3619520-16-sascha.bischoff@arm.com
Signed-off-by: Marc Zyngier <maz@kernel.org>

authored by

Sascha Bischoff and committed by
Marc Zyngier
070543a8 607871ce

+32 -2
+9 -2
arch/arm64/kvm/config.c
··· 1688 1688 { 1689 1689 __compute_fgt(vcpu, ICH_HFGRTR_EL2); 1690 1690 1691 - /* ICC_IAFFIDR_EL1 *always* needs to be trapped when running a guest */ 1692 - *vcpu_fgt(vcpu, ICH_HFGRTR_EL2) &= ~ICH_HFGRTR_EL2_ICC_IAFFIDR_EL1; 1691 + /* 1692 + * ICC_IAFFIDR_EL1 *always* needs to be trapped when running a guest. 1693 + * 1694 + * We also trap accesses to ICC_IDR0_EL1 to allow us to completely hide 1695 + * FEAT_GCIE_LEGACY from the guest, and to (potentially) present fewer 1696 + * ID bits than the host supports. 1697 + */ 1698 + *vcpu_fgt(vcpu, ICH_HFGRTR_EL2) &= ~(ICH_HFGRTR_EL2_ICC_IAFFIDR_EL1 | 1699 + ICH_HFGRTR_EL2_ICC_IDRn_EL1); 1693 1700 } 1694 1701 1695 1702 void kvm_vcpu_load_fgt(struct kvm_vcpu *vcpu)
+23
arch/arm64/kvm/sys_regs.c
··· 681 681 return true; 682 682 } 683 683 684 + static bool access_gicv5_idr0(struct kvm_vcpu *vcpu, struct sys_reg_params *p, 685 + const struct sys_reg_desc *r) 686 + { 687 + if (p->is_write) 688 + return undef_access(vcpu, p, r); 689 + 690 + /* 691 + * Expose KVM's priority- and ID-bits to the guest, but not GCIE_LEGACY. 692 + * 693 + * Note: for GICv5 the mimic the way that the num_pri_bits and 694 + * num_id_bits fields are used with GICv3: 695 + * - num_pri_bits stores the actual number of priority bits, whereas the 696 + * register field stores num_pri_bits - 1. 697 + * - num_id_bits stores the raw field value, which is 0b0000 for 16 bits 698 + * and 0b0001 for 24 bits. 699 + */ 700 + p->regval = FIELD_PREP(ICC_IDR0_EL1_PRI_BITS, vcpu->arch.vgic_cpu.num_pri_bits - 1) | 701 + FIELD_PREP(ICC_IDR0_EL1_ID_BITS, vcpu->arch.vgic_cpu.num_id_bits); 702 + 703 + return true; 704 + } 705 + 684 706 static bool access_gicv5_iaffid(struct kvm_vcpu *vcpu, struct sys_reg_params *p, 685 707 const struct sys_reg_desc *r) 686 708 { ··· 3442 3420 { SYS_DESC(SYS_ICC_AP1R1_EL1), undef_access }, 3443 3421 { SYS_DESC(SYS_ICC_AP1R2_EL1), undef_access }, 3444 3422 { SYS_DESC(SYS_ICC_AP1R3_EL1), undef_access }, 3423 + { SYS_DESC(SYS_ICC_IDR0_EL1), access_gicv5_idr0 }, 3445 3424 { SYS_DESC(SYS_ICC_IAFFIDR_EL1), access_gicv5_iaffid }, 3446 3425 { SYS_DESC(SYS_ICC_DIR_EL1), access_gic_dir }, 3447 3426 { SYS_DESC(SYS_ICC_RPR_EL1), undef_access },