[PATCH 11/32] KVM: arm64: gic-v5: Trap and emulate ICH_PPI_HMRx_EL1 accesses
Sascha Bischoff
Sascha.Bischoff at arm.com
Fri Dec 12 07:22:39 PST 2025
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 <sascha.bischoff at arm.com>
---
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
More information about the linux-arm-kernel
mailing list