The ICC_PPI_HMRx_EL1 register is used to determine which PPIs use Level-sensitive semantics, and which use Edge. For a GICv5 guest, the correct view of the virtual PPIs must be provided to the guest. The GICv5 architecture doesn't provide an ICV_PPI_HMRx_EL1 or ICH_PPI_HMRx_EL2 register, and therefore all guest accesses must be trapped to avoid the guest directly accessing the host's ICC_PPI_HMRx_EL1 state. This change hence configures the FGTs to always trap and emulate guest accesses to the HMR running a GICv5-based guest. This change also introduces the struct vgic_v5_cpu_if, which includes the vgic_hmr. This is not yet populated as it can only be correctly populated at vcpu reset time. This will be introduced in a subsquent change. Signed-off-by: Sascha Bischoff --- arch/arm64/kvm/config.c | 6 +++++- arch/arm64/kvm/sys_regs.c | 26 ++++++++++++++++++++++++++ include/kvm/arm_vgic.h | 5 +++++ 3 files changed, 36 insertions(+), 1 deletion(-) diff --git a/arch/arm64/kvm/config.c b/arch/arm64/kvm/config.c index cbdd8ac90f4d0..7683407ce052a 100644 --- a/arch/arm64/kvm/config.c +++ b/arch/arm64/kvm/config.c @@ -1586,8 +1586,12 @@ 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 */ + /* + * ICC_IAFFIDR_EL1 and ICH_PPI_HMRx_EL1 *always* needs to be + * trapped when running a guest. + **/ *vcpu_fgt(vcpu, ICH_HFGRTR_EL2) &= ~ICH_HFGRTR_EL2_ICC_IAFFIDR_EL1; + *vcpu_fgt(vcpu, ICH_HFGRTR_EL2) &= ~ICH_HFGRTR_EL2_ICC_PPI_HMRn_EL1; } void kvm_vcpu_load_fgt(struct kvm_vcpu *vcpu) diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c index 31c08fd591d08..a4ae034340040 100644 --- a/arch/arm64/kvm/sys_regs.c +++ b/arch/arm64/kvm/sys_regs.c @@ -699,6 +699,30 @@ static bool access_gicv5_iaffid(struct kvm_vcpu *vcpu, struct sys_reg_params *p, return true; } +static bool access_gicv5_ppi_hmr(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. + */ + + if (p->Op2 == 0) { /* ICC_PPI_HMR0_EL1 */ + p->regval = vcpu->arch.vgic_cpu.vgic_v5.vgic_ppi_hmr[0]; + } else { /* ICC_PPI_HMR1_EL1 */ + p->regval = vcpu->arch.vgic_cpu.vgic_v5.vgic_ppi_hmr[1]; + } + + return true; +} + + static bool trap_raz_wi(struct kvm_vcpu *vcpu, struct sys_reg_params *p, const struct sys_reg_desc *r) @@ -3429,6 +3453,8 @@ 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_PPI_HMR0_EL1), access_gicv5_ppi_hmr }, + { SYS_DESC(SYS_ICC_PPI_HMR1_EL1), access_gicv5_ppi_hmr }, { 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 }, diff --git a/include/kvm/arm_vgic.h b/include/kvm/arm_vgic.h index be1f45a494f78..fbbaef4ad2114 100644 --- a/include/kvm/arm_vgic.h +++ b/include/kvm/arm_vgic.h @@ -358,11 +358,16 @@ struct vgic_v3_cpu_if { unsigned int used_lrs; }; +struct vgic_v5_cpu_if { + u64 vgic_ppi_hmr[2]; +}; + struct vgic_cpu { /* CPU vif control registers for world switch */ union { struct vgic_v2_cpu_if vgic_v2; struct vgic_v3_cpu_if vgic_v3; + struct vgic_v5_cpu_if vgic_v5; }; struct vgic_irq *private_irqs; -- 2.34.1