From: Mostafa Saleh <smostafa@google.com>
To: linux-arm-kernel@lists.infradead.org,
linux-kernel@vger.kernel.org, kvmarm@lists.linux.dev,
iommu@lists.linux.dev
Cc: catalin.marinas@arm.com, will@kernel.org, maz@kernel.org,
oliver.upton@linux.dev, joey.gouly@arm.com,
suzuki.poulose@arm.com, yuzenghui@huawei.com, joro@8bytes.org,
jean-philippe@linaro.org, jgg@ziepe.ca, mark.rutland@arm.com,
qperret@google.com, tabba@google.com, vdonnefort@google.com,
sebastianene@google.com, keirf@google.com,
Mostafa Saleh <smostafa@google.com>
Subject: [PATCH v6 17/25] iommu/arm-smmu-v3-kvm: Emulate CMDQ for host
Date: Fri, 1 May 2026 11:19:19 +0000 [thread overview]
Message-ID: <20260501111928.259252-18-smostafa@google.com> (raw)
In-Reply-To: <20260501111928.259252-1-smostafa@google.com>
Don’t allow access to the command queue from the host:
- ARM_SMMU_CMDQ_BASE: Only allowed to be written when CMDQ is disabled, we
use it to keep track of the host command queue base.
Reads return the saved value.
- ARM_SMMU_CMDQ_PROD: Writes trigger command queue emulation which sanitise
and filters the whole range. Reads returns the host copy.
- ARM_SMMU_CMDQ_CONS: Writes move the sw copy of the cons, but the host
can’t skip commands once submitted. Reads return the emulated value and
the error bits in the actual cons.
Signed-off-by: Mostafa Saleh <smostafa@google.com>
---
.../iommu/arm/arm-smmu-v3/pkvm/arm-smmu-v3.c | 128 +++++++++++++++++-
1 file changed, 124 insertions(+), 4 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 aac455599728..1633a3cf8a3b 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
@@ -100,7 +100,6 @@ static int smmu_unshare_pages(phys_addr_t addr, size_t size)
return 0;
}
-__maybe_unused
static bool smmu_cmdq_has_space(struct arm_smmu_queue *cmdq, u32 n)
{
struct arm_smmu_ll_queue *llq = &cmdq->llq;
@@ -351,6 +350,92 @@ static int smmu_init(void)
return ret;
}
+static bool smmu_filter_command(struct hyp_arm_smmu_v3_device *smmu, u64 *command)
+{
+ u64 command0 = le64_to_cpu(command[0]);
+ u64 command1 = le64_to_cpu(command[1]);
+ u64 type = FIELD_GET(CMDQ_0_OP, command0);
+
+ switch (type) {
+ case CMDQ_OP_CFGI_STE:
+ /* TBD: SHADOW_STE*/
+ break;
+ case CMDQ_OP_CFGI_ALL:
+ {
+ /*
+ * Linux doesn't use range STE invalidation, and only use this
+ * for CFGI_ALL, which is done on reset and not on an new STE
+ * being used.
+ * Although, this is not architectural we rely on the current Linux
+ * implementation.
+ */
+ if ((FIELD_GET(CMDQ_CFGI_1_RANGE, command1) != 31))
+ return true;
+ break;
+ }
+ case CMDQ_OP_TLBI_NH_ASID:
+ case CMDQ_OP_TLBI_NH_VA:
+ case 0x13: /* CMD_TLBI_NH_VAA: Not used by Linux */
+ {
+ /* Only allow VMID = 0 */
+ if (FIELD_GET(CMDQ_TLBI_0_VMID, command0) != 0)
+ return true;
+ break;
+ }
+ case 0x10: /* CMD_TLBI_NH_ALL: Not used by Linux */
+ case CMDQ_OP_TLBI_EL2_ALL:
+ case CMDQ_OP_TLBI_EL2_VA:
+ case CMDQ_OP_TLBI_EL2_ASID:
+ case CMDQ_OP_TLBI_S12_VMALL:
+ case CMDQ_OP_TLBI_S2_IPA:
+ case 0x23: /* CMD_TLBI_EL2_VAA: Not used by Linux */
+ return true;
+ case CMDQ_OP_CMD_SYNC:
+ if (FIELD_GET(CMDQ_SYNC_0_CS, command0) == CMDQ_SYNC_0_CS_IRQ) {
+ /* Allow it, but let the host timeout, as this should never happen. */
+ command0 &= ~CMDQ_SYNC_0_CS;
+ command0 |= FIELD_PREP(CMDQ_SYNC_0_CS, CMDQ_SYNC_0_CS_SEV);
+ command1 &= ~CMDQ_SYNC_1_MSIADDR_MASK;
+ }
+ break;
+ }
+
+ return false;
+}
+
+static int smmu_emulate_cmdq_insert(struct hyp_arm_smmu_v3_device *smmu)
+{
+ u64 *host_cmdq = hyp_phys_to_virt(smmu->cmdq_host.q_base & Q_BASE_ADDR_MASK);
+ bool use_wfe = smmu->features & ARM_SMMU_FEAT_SEV, skip;
+ u64 cmd[CMDQ_ENT_DWORDS];
+ int idx, ret;
+ u32 space;
+
+ if (!is_cmdq_enabled(smmu))
+ return 0;
+
+ space = (1 << (smmu->cmdq_host.llq.max_n_shift)) - queue_space(&smmu->cmdq_host.llq);
+ /* Wait for the command queue to have some space. */
+ ret = smmu_wait(use_wfe, smmu_cmdq_has_space(&smmu->cmdq, space));
+ if (ret)
+ return ret;
+
+ while (space--) {
+ idx = Q_IDX(&smmu->cmdq_host.llq, smmu->cmdq_host.llq.cons);
+ queue_inc_cons(&smmu->cmdq_host.llq);
+
+ memcpy(cmd, &host_cmdq[idx * CMDQ_ENT_DWORDS], CMDQ_ENT_DWORDS << 3);
+ skip = smmu_filter_command(smmu, cmd);
+ if (WARN_ON(skip))
+ continue;
+ smmu_add_cmd_raw(smmu, cmd);
+ }
+
+ writel(smmu->cmdq.llq.prod, smmu->cmdq.prod_reg);
+
+ return smmu_wait(use_wfe, smmu_cmdq_empty(&smmu->cmdq));
+}
+
static void smmu_emulate_cmdq_enable(struct hyp_arm_smmu_v3_device *smmu)
{
u32 shift = smmu->cmdq_host.q_base & Q_BASE_LOG2SIZE;
@@ -388,18 +473,51 @@ static bool smmu_dabt_device(struct hyp_arm_smmu_v3_device *smmu,
/* Clear stage-2 support, hide MSI to avoid write back to cmdq */
mask = read_only & ~(IDR0_S2P | IDR0_VMID16 | IDR0_MSI | IDR0_HYP);
break;
- /* Passthrough the register access for bisectiblity, handled later */
case ARM_SMMU_CMDQ_BASE:
+ /*
+ * Although allowed to use smaller size, we rely on the SMMUv3 driver
+ * using 64-bit store instruction for simplicity.
+ */
+ if (len != sizeof(u64))
+ break;
if (is_write) {
/* Not allowed by the architecture */
if (WARN_ON(is_cmdq_enabled(smmu)))
break;
smmu->cmdq_host.q_base = val;
+ goto out_ret;
+ } else {
+ val = smmu->cmdq_host.q_base;
+ goto out_update_regs;
}
- mask = read_write;
- break;
case ARM_SMMU_CMDQ_PROD:
+ if (len != sizeof(u32))
+ break;
+ if (is_write) {
+ smmu->cmdq_host.llq.prod = val;
+ WARN_ON(smmu_emulate_cmdq_insert(smmu));
+ goto out_ret;
+ } else {
+ val = smmu->cmdq_host.llq.prod;
+ goto out_update_regs;
+ }
case ARM_SMMU_CMDQ_CONS:
+ if (len != sizeof(u32))
+ break;
+ if (is_write) {
+ if (WARN_ON(is_cmdq_enabled(smmu)))
+ break;
+
+ smmu->cmdq_host.llq.cons = val;
+ goto out_ret;
+ } else {
+ /* Propagate errors back to the host.*/
+ u32 cons = readl_relaxed(smmu->base + ARM_SMMU_CMDQ_CONS);
+
+ val = smmu->cmdq_host.llq.cons | (CMDQ_CONS_ERR & cons);
+ goto out_update_regs;
+ }
+ /* Passthrough the register access for bisectiblity, handled later */
case ARM_SMMU_STRTAB_BASE:
case ARM_SMMU_STRTAB_BASE_CFG:
case ARM_SMMU_GBPA:
@@ -495,6 +613,8 @@ static bool smmu_dabt_device(struct hyp_arm_smmu_v3_device *smmu,
val = readq_relaxed(smmu->base + off) & mask;
else
val = readl_relaxed(smmu->base + off) & mask;
+
+out_update_regs:
/*
* Device might be read senstive, so do it but ignore writing
* back for xzr.
--
2.54.0.545.g6539524ca2-goog
next prev parent reply other threads:[~2026-05-01 11:20 UTC|newest]
Thread overview: 61+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-05-01 11:19 [PATCH v6 00/25] KVM: arm64: SMMUv3 driver for pKVM (trap and emulate) Mostafa Saleh
2026-05-01 11:19 ` [PATCH v6 01/25] KVM: arm64: Generalize trace clock Mostafa Saleh
2026-05-01 11:19 ` [PATCH v6 02/25] KVM: arm64: Donate MMIO to the hypervisor Mostafa Saleh
2026-05-01 11:19 ` [PATCH v6 03/25] iommu/arm-smmu-v3: Split code with hyp Mostafa Saleh
2026-05-01 12:44 ` Jason Gunthorpe
2026-05-04 12:13 ` Mostafa Saleh
2026-05-01 11:19 ` [PATCH v6 04/25] iommu/arm-smmu-v3: Move TLB range invalidation into common code Mostafa Saleh
2026-05-01 12:41 ` Jason Gunthorpe
2026-05-04 12:15 ` Mostafa Saleh
2026-05-05 16:17 ` Jason Gunthorpe
2026-05-05 16:43 ` Mostafa Saleh
2026-05-06 9:53 ` Jason Gunthorpe
2026-05-07 9:40 ` Mostafa Saleh
2026-05-09 23:29 ` Jason Gunthorpe
2026-05-11 11:45 ` Mostafa Saleh
2026-05-11 14:24 ` Jason Gunthorpe
2026-05-01 11:19 ` [PATCH v6 05/25] iommu/arm-smmu-v3: Move IDR parsing to common functions Mostafa Saleh
2026-05-01 12:47 ` Jason Gunthorpe
2026-05-04 12:16 ` Mostafa Saleh
2026-05-05 16:27 ` Jason Gunthorpe
2026-05-05 16:48 ` Mostafa Saleh
2026-05-06 9:56 ` Jason Gunthorpe
2026-05-07 10:13 ` Mostafa Saleh
2026-05-09 23:34 ` Jason Gunthorpe
2026-05-11 11:53 ` Mostafa Saleh
2026-05-11 14:30 ` Jason Gunthorpe
2026-05-01 11:19 ` [PATCH v6 06/25] iommu/io-pgtable-arm: Rework to use the iommu-pages API Mostafa Saleh
2026-05-01 12:24 ` Jason Gunthorpe
2026-05-04 12:19 ` Mostafa Saleh
2026-05-09 23:21 ` Jason Gunthorpe
2026-05-11 11:16 ` Mostafa Saleh
2026-05-11 14:18 ` Jason Gunthorpe
2026-05-13 21:54 ` Mostafa Saleh
2026-05-01 11:19 ` [PATCH v6 07/25] KVM: arm64: iommu: Introduce IOMMU driver infrastructure Mostafa Saleh
2026-05-01 11:19 ` [PATCH v6 08/25] KVM: arm64: iommu: Shadow host stage-2 page table Mostafa Saleh
2026-05-01 13:00 ` Jason Gunthorpe
2026-05-04 12:28 ` Mostafa Saleh
2026-05-09 23:27 ` Jason Gunthorpe
2026-05-11 11:24 ` Mostafa Saleh
2026-05-11 14:22 ` Jason Gunthorpe
2026-05-12 10:42 ` Mostafa Saleh
2026-05-12 12:36 ` Jason Gunthorpe
2026-05-01 11:19 ` [PATCH v6 09/25] KVM: arm64: iommu: Add memory pool Mostafa Saleh
2026-05-01 11:19 ` [PATCH v6 10/25] KVM: arm64: iommu: Support DABT for IOMMU Mostafa Saleh
2026-05-01 11:19 ` [PATCH v6 11/25] iommu/arm-smmu-v3-kvm: Add SMMUv3 driver Mostafa Saleh
2026-05-01 11:19 ` [PATCH v6 12/25] iommu/arm-smmu-v3-kvm: Add the kernel driver Mostafa Saleh
2026-05-01 11:19 ` [PATCH v6 13/25] iommu/arm-smmu-v3-kvm: Probe SMMU HW Mostafa Saleh
2026-05-01 12:51 ` Jason Gunthorpe
2026-05-04 12:30 ` Mostafa Saleh
2026-05-01 11:19 ` [PATCH v6 14/25] iommu/arm-smmu-v3-kvm: Add MMIO emulation Mostafa Saleh
2026-05-01 11:19 ` [PATCH v6 15/25] iommu/arm-smmu-v3-kvm: Shadow the command queue Mostafa Saleh
2026-05-01 11:19 ` [PATCH v6 16/25] iommu/arm-smmu-v3-kvm: Add CMDQ functions Mostafa Saleh
2026-05-01 11:19 ` Mostafa Saleh [this message]
2026-05-01 11:19 ` [PATCH v6 18/25] iommu/arm-smmu-v3-kvm: Shadow stream table Mostafa Saleh
2026-05-01 11:19 ` [PATCH v6 19/25] iommu/arm-smmu-v3-kvm: Shadow STEs Mostafa Saleh
2026-05-01 11:19 ` [PATCH v6 20/25] iommu/arm-smmu-v3-kvm: Share other queues Mostafa Saleh
2026-05-01 11:19 ` [PATCH v6 21/25] iommu/arm-smmu-v3-kvm: Emulate GBPA Mostafa Saleh
2026-05-01 11:19 ` [PATCH v6 22/25] iommu/io-pgtable-arm: Support io-pgtable-arm in the hypervisor Mostafa Saleh
2026-05-01 11:19 ` [PATCH v6 23/25] iommu/arm-smmu-v3-kvm: Shadow the CPU stage-2 page table Mostafa Saleh
2026-05-01 11:19 ` [PATCH v6 24/25] iommu/arm-smmu-v3-kvm: Enable nesting Mostafa Saleh
2026-05-01 11:19 ` [PATCH v6 25/25] KVM: arm64: Add documentation for pKVM DMA isolation Mostafa Saleh
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260501111928.259252-18-smostafa@google.com \
--to=smostafa@google.com \
--cc=catalin.marinas@arm.com \
--cc=iommu@lists.linux.dev \
--cc=jean-philippe@linaro.org \
--cc=jgg@ziepe.ca \
--cc=joey.gouly@arm.com \
--cc=joro@8bytes.org \
--cc=keirf@google.com \
--cc=kvmarm@lists.linux.dev \
--cc=linux-arm-kernel@lists.infradead.org \
--cc=linux-kernel@vger.kernel.org \
--cc=mark.rutland@arm.com \
--cc=maz@kernel.org \
--cc=oliver.upton@linux.dev \
--cc=qperret@google.com \
--cc=sebastianene@google.com \
--cc=suzuki.poulose@arm.com \
--cc=tabba@google.com \
--cc=vdonnefort@google.com \
--cc=will@kernel.org \
--cc=yuzenghui@huawei.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.