Re: [PATCH kernel 6/9] x86/dma-direct: Stop changing encrypted page state for TDISP devices
From: Robin Murphy
Date: Wed Feb 25 2026 - 12:11:54 EST
On 2026-02-25 5:37 am, Alexey Kardashevskiy wrote:
TDISP devices operate in CoCo VMs only and capable of accessing
encrypted guest memory.
Currently when SME is on, the DMA subsystem forces the SME mask in
DMA handles in phys_to_dma() which assumes IOMMU pass through
which is never the case with CoCoVM running with a TDISP device.
Define X86's version of phys_to_dma() to skip leaking SME mask to
the device.
Signed-off-by: Alexey Kardashevskiy <aik@xxxxxxx>
---
Doing this in the generic version breaks ARM which uses
the SME mask in DMA handles, hence ARCH_HAS_PHYS_TO_DMA.
That smells a bit off... In CCA we should be in the same boat, wherein a trusted device can access memory at a DMA address based on its "normal" (private) GPA, rather than having to be redirected to the shared alias (it's really not an "SME mask" in that sense at all).
I guess this comes back to the point I just raised on the previous patch - the current assumption is that devices cannot access private memory at all, and thus phys_to_dma() is implicitly only dealing with the mechanics of how the given device accesses shared memory. Once that no longer holds, I don't see how we can find the right answer without also consulting the relevant state of paddr itself, and that really *should* be able to be commonly abstracted across CoCo environments. And if in the process of that we could untangle the "implicit vs. explicit SME mask for shared memory or non-CoCo SME" case from common code and punt *that* into an x86-specific special case, all the better :)
Thanks,
Robin.
pci_device_add() enforces the FFFF_FFFF coherent DMA mask so
dma_alloc_coherent() fails when SME=on, this is how I ended up fixing
phys_to_dma() and not quite sure it is the right fix.
---
arch/x86/Kconfig | 1 +
arch/x86/include/asm/dma-direct.h | 39 ++++++++++++++++++++
2 files changed, 40 insertions(+)
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
index fa3b616af03a..c46283064518 100644
--- a/arch/x86/Kconfig
+++ b/arch/x86/Kconfig
@@ -112,6 +112,7 @@ config X86
select ARCH_HAS_UBSAN
select ARCH_HAS_DEBUG_WX
select ARCH_HAS_ZONE_DMA_SET if EXPERT
+ select ARCH_HAS_PHYS_TO_DMA
select ARCH_HAVE_NMI_SAFE_CMPXCHG
select ARCH_HAVE_EXTRA_ELF_NOTES
select ARCH_MHP_MEMMAP_ON_MEMORY_ENABLE
diff --git a/arch/x86/include/asm/dma-direct.h b/arch/x86/include/asm/dma-direct.h
new file mode 100644
index 000000000000..f50e03d643c1
--- /dev/null
+++ b/arch/x86/include/asm/dma-direct.h
@@ -0,0 +1,39 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef ASM_X86_DMA_DIRECT_H
+#define ASM_X86_DMA_DIRECT_H 1
+
+static inline dma_addr_t __phys_to_dma(struct device *dev, phys_addr_t paddr)
+{
+ if (dev->dma_range_map)
+ return translate_phys_to_dma(dev, paddr);
+ return paddr;
+}
+
+static inline dma_addr_t phys_to_dma(struct device *dev, phys_addr_t paddr)
+{
+ /*
+ * TDISP devices only work in CoCoVMs and rely on IOMMU to
+ * decide on the memory encryption.
+ * Stop leaking the SME mask in DMA handles and return
+ * the real address.
+ */
+ if (device_cc_accepted(dev))
+ return dma_addr_unencrypted(__phys_to_dma(dev, paddr));
+
+ return dma_addr_encrypted(__phys_to_dma(dev, paddr));
+}
+
+static inline phys_addr_t dma_to_phys(struct device *dev, dma_addr_t daddr)
+{
+ return daddr;
+}
+
+static inline dma_addr_t phys_to_dma_unencrypted(struct device *dev,
+ phys_addr_t paddr)
+{
+ return dma_addr_unencrypted(__phys_to_dma(dev, paddr));
+}
+
+#define phys_to_dma_unencrypted phys_to_dma_unencrypted
+
+#endif /* ASM_X86_DMA_DIRECT_H */