[PATCH v9 20/25] iommu/arm-smmu-v3-kvm: Emulate GBPA
From: Mostafa Saleh
Date: Thu Oct 15 2026 - 16:12:36 EST
The last bit of emulation is GBPA. it must be always set to ABORT,
as when the SMMU is disabled it's not allowed for the host to bypass
the SMMU.
That's is done by setting the GBPA to ABORT at init time, and host
writes are always ignored and host reads always return ABORT.
Signed-off-by: Mostafa Saleh <smostafa@xxxxxxxxxx>
---
.../arm/arm-smmu-v3/pkvm/arm-smmu-v3-hyp.c | 32 +++++++++++++++++--
1 file changed, 29 insertions(+), 3 deletions(-)
diff --git a/drivers/iommu/arm/arm-smmu-v3/pkvm/arm-smmu-v3-hyp.c b/drivers/iommu/arm/arm-smmu-v3/pkvm/arm-smmu-v3-hyp.c
index 1972df1d2a8d..943ffef0bb4a 100644
--- a/drivers/iommu/arm/arm-smmu-v3/pkvm/arm-smmu-v3-hyp.c
+++ b/drivers/iommu/arm/arm-smmu-v3/pkvm/arm-smmu-v3-hyp.c
@@ -217,6 +217,22 @@ static int smmu_send_cmd(struct hyp_arm_smmu_v3_device *smmu,
return smmu_sync_cmd(smmu);
}
+static int smmu_abort_gbpa(struct hyp_arm_smmu_v3_device *smmu)
+{
+ int ret;
+ u32 reg;
+
+ ret = smmu_wait(false,
+ (readl_relaxed(smmu->base + ARM_SMMU_GBPA) & GBPA_UPDATE) == 0);
+ if (ret)
+ return ret;
+
+ reg = readl_relaxed(smmu->base + ARM_SMMU_GBPA);
+ writel_relaxed(GBPA_UPDATE | GBPA_ABORT | reg, smmu->base + ARM_SMMU_GBPA);
+ return smmu_wait(false,
+ (readl_relaxed(smmu->base + ARM_SMMU_GBPA) & GBPA_UPDATE) == 0);
+}
+
/* Put the device in a state that can be probed by the host driver. */
static void smmu_deinit_device(struct hyp_arm_smmu_v3_device *smmu)
{
@@ -456,6 +472,10 @@ static int smmu_init_device(struct hyp_arm_smmu_v3_device *smmu)
if (ret)
goto out_deinit;
+ ret = smmu_abort_gbpa(smmu);
+ if (ret)
+ goto out_deinit;
+
return 0;
out_deinit:
@@ -781,10 +801,16 @@ static bool smmu_dabt_device(struct hyp_arm_smmu_v3_device *smmu,
val = smmu->host_ste_cfg;
goto out_update_regs;
}
- /* Passthrough the register access for bisectability, handled later */
case ARM_SMMU_GBPA:
- mask = read_write;
- break;
+ if (len != sizeof(u32))
+ break;
+
+ /* Ignore write, always read to abort. */
+ if (!is_write) {
+ val = GBPA_ABORT;
+ goto out_update_regs;
+ }
+ goto out_ret;
case ARM_SMMU_CR0:
if (len != sizeof(u32))
break;
--
2.56.0.176.g3575e65682-goog