GICv5 doesn't include an ICV_IAFFIDR_EL1 or ICH_IAFFIDR_EL2 for providing the IAFFID to the guest. A guest access to the ICH_IAFFIDR_EL1 must therefore be trapped and emulated to avoid the guest accessing the host's ICC_IAFFIDR_EL1. For GICv5, the VPE ID corresponds to the virtual IAFFID for the purposes of specifying the affinity of virtual interrupts. The VPE ID is the index into the VPE Table, which will be the same as the vcpu->vcpu_id once the various GICv5 VM tables are introduced. At this stage, said VM tables have yet to be introduced as they are not required for PPI support. Moreover, the IAFFID should go largely unused by any guest using just PPIs as they are not routable to a different PE. That said, we still need to trap and emulate the guest's accesses to avoid leaking host state into the guest. The virtual IAFFID is provided to the guest when it reads ICC_IAFFID_EL1 (which always traps back to the hypervisor). Writes are rightly ignored. The trapping for the ICC_IAFFIDR_EL2 is always enabled when in a guest context. Co-authored-by: Timothy Hayes Signed-off-by: Timothy Hayes Signed-off-by: Sascha Bischoff --- arch/arm64/kvm/config.c | 10 +++++++++- arch/arm64/kvm/sys_regs.c | 19 +++++++++++++++++++ 2 files changed, 28 insertions(+), 1 deletion(-) diff --git a/arch/arm64/kvm/config.c b/arch/arm64/kvm/config.c index 57ef67f718113..cbdd8ac90f4d0 100644 --- a/arch/arm64/kvm/config.c +++ b/arch/arm64/kvm/config.c @@ -1582,6 +1582,14 @@ static void __compute_hdfgwtr(struct kvm_vcpu *vcpu) *vcpu_fgt(vcpu, HDFGWTR_EL2) |= HDFGWTR_EL2_MDSCR_EL1; } +static void __compute_ich_hfgrtr(struct kvm_vcpu *vcpu) +{ + __compute_fgt(vcpu, ICH_HFGRTR_EL2); + + /* ICC_IAFFIDR_EL1 *always* needs to be trapped when running a guest */ + *vcpu_fgt(vcpu, ICH_HFGRTR_EL2) &= ~ICH_HFGRTR_EL2_ICC_IAFFIDR_EL1; +} + void kvm_vcpu_load_fgt(struct kvm_vcpu *vcpu) { if (!cpus_have_final_cap(ARM64_HAS_FGT)) @@ -1607,7 +1615,7 @@ void kvm_vcpu_load_fgt(struct kvm_vcpu *vcpu) if (!cpus_have_final_cap(ARM64_HAS_GICV5_CPUIF)) return; - __compute_fgt(vcpu, ICH_HFGRTR_EL2); + __compute_ich_hfgrtr(vcpu); __compute_fgt(vcpu, ICH_HFGWTR_EL2); __compute_fgt(vcpu, ICH_HFGITR_EL2); } diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c index fbbd7b6ff6507..31c08fd591d08 100644 --- a/arch/arm64/kvm/sys_regs.c +++ b/arch/arm64/kvm/sys_regs.c @@ -681,6 +681,24 @@ static bool access_gic_dir(struct kvm_vcpu *vcpu, return true; } +static bool access_gicv5_iaffid(struct kvm_vcpu *vcpu, struct sys_reg_params *p, + const struct sys_reg_desc *r) +{ + if (!vgic_is_v5(vcpu->kvm)) + return undef_access(vcpu, p, r); + + if (p->is_write) + return ignore_write(vcpu, p); + + /* + * For GICv5 VMs, the IAFFID value is the same as the VPE ID. The VPE ID + * is the same as the VCPU's ID. + */ + p->regval = FIELD_PREP(ICC_IAFFIDR_EL1_IAFFID, vcpu->vcpu_id); + + return true; +} + static bool trap_raz_wi(struct kvm_vcpu *vcpu, struct sys_reg_params *p, const struct sys_reg_desc *r) @@ -3411,6 +3429,7 @@ static const struct sys_reg_desc sys_reg_descs[] = { { SYS_DESC(SYS_ICC_AP1R1_EL1), undef_access }, { SYS_DESC(SYS_ICC_AP1R2_EL1), undef_access }, { SYS_DESC(SYS_ICC_AP1R3_EL1), undef_access }, + { SYS_DESC(SYS_ICC_IAFFIDR_EL1), access_gicv5_iaffid }, { SYS_DESC(SYS_ICC_DIR_EL1), access_gic_dir }, { SYS_DESC(SYS_ICC_RPR_EL1), undef_access }, { SYS_DESC(SYS_ICC_SGI1R_EL1), access_gic_sgi }, -- 2.34.1