[PATCH v7 20/24] iommu/arm-smmu-v3-kvm: Emulate GBPA

From: Mostafa Saleh

Date: Wed Jul 15 2026 - 08:02:03 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>
---
.../iommu/arm/arm-smmu-v3/pkvm/arm-smmu-v3.c | 32 +++++++++++++++++--
1 file changed, 29 insertions(+), 3 deletions(-)

diff --git a/drivers/iommu/arm/arm-smmu-v3/pkvm/arm-smmu-v3.c b/drivers/iommu/arm/arm-smmu-v3/pkvm/arm-smmu-v3.c
index 11de73640a6f..45dbab1b18ad 100644
--- a/drivers/iommu/arm/arm-smmu-v3/pkvm/arm-smmu-v3.c
+++ b/drivers/iommu/arm/arm-smmu-v3/pkvm/arm-smmu-v3.c
@@ -139,6 +139,22 @@ static bool smmu_cmdq_has_space(struct arm_smmu_queue *cmdq, u32 n)
return queue_has_space(llq, n);
}

+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);
+}
+
static bool smmu_cmdq_full(struct arm_smmu_queue *cmdq)
{
struct arm_smmu_ll_queue *llq = &cmdq->llq;
@@ -450,6 +466,10 @@ static int smmu_init_device(struct hyp_arm_smmu_v3_device *smmu)
if (ret)
goto out_ret;

+ ret = smmu_abort_gbpa(smmu);
+ if (ret)
+ goto out_ret;
+
return 0;

out_ret:
@@ -763,10 +783,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 bisectiblity, 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.55.0.141.g00534a21ce-goog