[PATCH v8 20/25] iommu/arm-smmu-v3-kvm: Emulate GBPA
Mostafa Saleh
smostafa at google.com
Tue Sep 22 06:12:53 PDT 2026
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 at google.com>
---
.../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 00528380774f..6e023e968ed3 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
@@ -215,6 +215,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)
{
@@ -453,6 +469,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:
@@ -778,10 +798,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.55.0.1082.g2b9226bbc0-goog
More information about the linux-arm-kernel
mailing list