Re: [PATCH kernel 6/9] x86/dma-direct: Stop changing encrypted page state for TDISP devices

Robin Murphy
2026-02-25T17:08:49Z

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@amd.com>
> ---
>
> 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 */