dma-mapping: Track shared DMA state through direct, pool and swiotlb paths
Subsystems (13)
v8 cover dma-mapping: Track shared DMA state through direct, pool and swiotlb paths
This series tracks confidential-computing shared DMA state through the dma-direct, dma-pool, and swiotlb paths so that encrypted and decrypted DMA buffers are handled consistently.
Today, the direct DMA path mostly relies on force_dma_unencrypted() for shared/decrypted buffer handling. This series consolidates the force_dma_unencrypted() checks in the top-level functions and ensures that the remaining DMA interfaces use DMA attributes to make the correct decisions.
The series separates mapping and allocation state:
- DMA_ATTR_CC_SHARED describes the DMA address attribute requested for a mapping. It tells the DMA mapping path that the DMA address must target shared/decrypted memory.
- __DMA_ATTR_ALLOC_CC_SHARED is an internal DMA-mapping attribute used only by allocation paths after the DMA core decides that the backing pages must be allocated as shared/decrypted memory.
The series:
- moves swiotlb-backed allocations out of __dma_direct_alloc_pages(),
- uses __DMA_ATTR_ALLOC_CC_SHARED through the dma-direct alloc/free paths
- teaches the atomic DMA pools to track encrypted versus decrypted state
- tracks swiotlb pool encryption state and enforces strict pool selection
- centralizes encrypted/decrypted pgprot handling in dma_pgprot() using DMA attributes
- passes DMA attributes down to dma_capable() so capability checks can validate whether the selected DMA address encoding matches DMA_ATTR_CC_SHARED
- makes dma_direct_map_phys() choose the DMA address encoding from DMA_ATTR_CC_SHARED and fall back to swiotlb when a shared DMA request cannot use the direct mapping, which lets arm64 and x86 CCA guests stop relying on SWIOTLB_FORCE for DMA mappings
- use the selected swiotlb pool state to derive the returned DMA address
- reports CC_ATTR_GUEST_MEM_ENCRYPT for arm64 Realms, powerpc secure guests, and s390 protected virtualization guests.
Dependency:
This series depends on the pKVM changes posted at:
https://lore.kernel.org/all/[email protected]
Please merge this series only after the pKVM changes above are merged. Otherwise pKVM will be broken.
Changes since v7:
https://lore.kernel.org/all/[email protected]
* Rebased onto dma-mapping-for-next
* Prepared the series on top of the prerequisite pKVM changes, resolving conflicts so it can be applied directly to the pKVM topic branch once ready.
https://git.gitlab.arm.com/linux-arm/linux-cca/-/commits/scratch/pkvm/testing
* Added comments documenting possible follow-up improvements for CC_SHARED atomic pools and physical-address-based pool freeing.
* Retained virtual-address-based pool freeing when CONFIG_DMA_DIRECT_REMAP is disabled.
* Applied pgprot_decrypted() only when expanding a CC_SHARED atomic pool.
Changes since v6:
https://lore.kernel.org/all/[email protected]
* Rebase onto the latest kernel.
* Add __DMA_ATTR_ALLOC_CC_SHARED for allocation paths. DMA_ATTR_CC_SHARED is now used to describe the requested DMA mapping address attribute, while __DMA_ATTR_ALLOC_CC_SHARED is used internally when allocating shared/decrypted backing pages.
* Report CC_ATTR_GUEST_MEM_ENCRYPT for arm64 Realms, powerpc secure guests, and s390 protected virtualization guests.
* Add CC_ATTR_HOST_MEM_ENCRYPT and swiotlb=force fixes.
Changes since v5:
https://lore.kernel.org/all/[email protected]
* Add Tested-by
* Drop the pKVM patch, which has now been posted separately:
https://lore.kernel.org/all/[email protected]
* Remove the DO_NOT_MERGE tag from the s390 change.
* Add a patch to drop the SWIOTLB_FORCE flag.
* Rebase onto the latest kernel.
Changes since v4:
https://lore.kernel.org/all/[email protected]
* Add new patches based on Sashiko review:
swiotlb: Preserve allocation virtual address for dynamic pools
dma: free atomic pool pages by physical address
dma: swiotlb: handle set_memory_decrypted() failures
dma: swiotlb: free dynamic pools from process context
iommu/dma: Check atomic pool allocation result directly
* Include pKVM and s390 changes as dependent patches. These are not yet ready to merge and are waiting for subsystem testing feedback.
* Drop the AMD GART patch because it requires wider testing.
* Update swiotlb_tbl_map_single() to take attrs by reference.
* Switch swiotlb_free() to use rcu_work.
* Avoid calling swiotlb_find_pool() multiple times in the free path.
* Make DMA_ATTR_MMIO imply DMA_ATTR_CC_SHARED for devices requiring unencrypted DMA.
Changes from v3:
https://lore.kernel.org/all/[email protected]
* Handle DMA_ATTR_MMIO correctly in dma_direct_map_phys()
* Address most of sashiko review
* Rebase to latest kernel
* drop SWIOTLB_FORCE for s390 and powerpc secure guest.
Changes from v2:
https://lore.kernel.org/all/[email protected]
* pass attrs to dma_capable() and update direct, swiotlb, Xen swiotlb, and x86 GART paths so the capability checks see the DMA address attr value DMA_ATTR_CC_SHARED.
* rework dma_direct_map_phys() so DMA_ATTR_CC_SHARED selects phys_to_dma_unencrypted() while the default path uses phys_to_dma_encrypted(), with swiotlb fallback when the requested shared/private state cannot be satisfied by a direct DMA address.
* stop relying on SWIOTLB_FORCE for arm64 and x86 CC guest DMA mappings; swiotlb is still enabled there, but shared mappings is now selected through the generic dma_direct_map_phys()/dma_capable() decision instead of a global force-bounce flag.
Changes from v1:
https://lore.kernel.org/all/[email protected]
* rebased to latest kernel (change from DMA_ATTR_CC_DECRYPTED -> DMA_ATTR_CC_SHARED)
* update the alloc path so DMA_ATTR_CC_SHARED is not a caller-visible attribute.
Aneesh Kumar K.V (Arm) (23):
dma-direct: return struct page from dma_direct_alloc_from_pool()
dma-pool: fix page leak in atomic_pool_expand() cleanup iommu/dma: Check atomic pool allocation result directly
dma: free atomic pool pages by physical address
swiotlb: Preserve allocation virtual address for dynamic pools
s390: Expose protected virtualization through cc_platform_has()
dma-direct: swiotlb: handle swiotlb alloc/free outside
__dma_direct_alloc_pages
coco: arm64: s390: powerpc: Mark secure guests with
CC_ATTR_GUEST_MEM_ENCRYPT
dma-mapping: Add internal shared allocation attribute
dma-direct: use __DMA_ATTR_ALLOC_CC_SHARED in alloc/free paths
dma-pool: track decrypted atomic pools and select them via attrs
dma: swiotlb: pass mapping attributes by reference
dma: swiotlb: track pool encryption state and honor DMA_ATTR_CC_SHARED
dma-mapping: make dma_pgprot() honor __DMA_ATTR_ALLOC_CC_SHARED
dma-direct: pass attrs to dma_capable() for DMA_ATTR_CC_SHARED checks
dma-direct: Move dma_direct_map_phys() to dma/direct.c
dma-direct: make dma_direct_map_phys() honor DMA_ATTR_CC_SHARED
dma-direct: set decrypted flag for remapped DMA allocations
dma-direct: select DMA address encoding from
__DMA_ATTR_ALLOC_CC_SHARED
dma-direct: rename ret to cpu_addr in alloc helpers
dma: swiotlb: free dynamic pools from process context
dma: swiotlb: handle set_memory_decrypted() failures
swiotlb: remove unused SWIOTLB_FORCE flag
Documentation/core-api/dma-attributes.rst | 29 ++ arch/arm64/mm/init.c | 5 +- arch/powerpc/platforms/pseries/cc_platform.c | 1 + arch/powerpc/platforms/pseries/svm.c | 2 +- arch/s390/Kconfig | 1 + arch/s390/mm/init.c | 17 +- arch/x86/kernel/amd_gart_64.c | 30 +- arch/x86/kernel/pci-dma.c | 4 +- drivers/iommu/dma-iommu.c | 20 +- drivers/xen/swiotlb-xen.c | 8 +- include/linux/dma-direct.h | 20 +- include/linux/dma-map-ops.h | 3 +- include/linux/dma-mapping.h | 8 + include/linux/swiotlb.h | 25 +- include/trace/events/dma.h | 3 +- kernel/dma/direct.c | 326 ++++++++++++++----- kernel/dma/direct.h | 56 +--- kernel/dma/mapping.c | 25 +- kernel/dma/pool.c | 237 ++++++++++---- kernel/dma/swiotlb.c | 292 +++++++++++++---- 20 files changed, 810 insertions(+), 302 deletions(-)
Signature · 1 line
2.43.0
PATCH v8 1/23 dma-direct: return struct page from dma_direct_alloc_from_pool()
Commit 5b138c534fda ("dma-direct: factor out a dma_direct_alloc_from_pool helper") changed dma_direct_alloc_from_pool() to return the CPU address from dma_alloc_from_pool(). That fits dma_direct_alloc(), but dma_direct_alloc_pages() also uses the helper and expects a struct page *.
Fix this by making dma_direct_alloc_from_pool() return the struct page * again, and pass the CPU address back through an out-parameter for the dma_direct_alloc() caller.
--- kernel/dma/direct.c | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-)
kernel/dma/direct.c +10 -8
@@ -164,22 +164,21 @@ static bool dma_direct_use_pool(struct device *dev, gfp_t gfp)return !gfpflags_allow_blocking (gfp) && !is_swiotlb_for_alloc (dev); } -static void *dma_direct_alloc_from_pool (struct device *dev,size_t size, -dma_addr_t *dma_handle,gfp_t gfp) +static struct page *dma_direct_alloc_from_pool (struct device *dev,size_t size, +dma_addr_t *dma_handle,void **cpu_addr,gfp_t gfp) {struct page *page;u64 phys_limit; -void *ret;if (WARN_ON_ONCE (!IS_ENABLED (CONFIG_DMA_COHERENT_POOL )))return NULL ; gfp |=dma_direct_optimal_gfp_mask (dev, &phys_limit); - page =dma_alloc_from_pool (dev, size, &ret, gfp, dma_coherent_ok); + page =dma_alloc_from_pool (dev, size, cpu_addr, gfp, dma_coherent_ok);if (!page)return NULL ; *dma_handle =phys_to_dma_direct (dev,page_to_phys (page)); -return ret; +return page; } static void *dma_direct_alloc_no_mapping(struct device *dev, size_t size,
@@ -247,8 +246,11 @@ void *dma_direct_alloc(struct device *dev, size_t size,* the atomic pools instead if we aren't allowed block. */ if ((remap ||force_dma_unencrypted (dev)) && -dma_direct_use_pool (dev, gfp)) -return dma_direct_alloc_from_pool (dev, size, dma_handle, gfp); +dma_direct_use_pool (dev, gfp)) { + page =dma_direct_alloc_from_pool (dev, size, dma_handle, + &ret, gfp); +return page ? ret :NULL ; + }/* we always manually zero the memory once we are done */ page =__dma_direct_alloc_pages (dev, size, gfp & ~__GFP_ZERO, true);
@@ -357,7 +359,7 @@ struct page *dma_direct_alloc_pages(struct device *dev, size_t size,void *ret;if (force_dma_unencrypted (dev) &&dma_direct_use_pool (dev, gfp)) -return dma_direct_alloc_from_pool (dev, size, dma_handle, gfp); +return dma_direct_alloc_from_pool (dev, size, dma_handle, &ret, gfp); page =__dma_direct_alloc_pages (dev, size, gfp, false);if (!page)
Signature · 1 line
2.43.0
Re: [PATCH v8 01/23] dma-direct: return struct page from dma_direct_alloc_from_pool()
Quoted 51 lines · Aneesh Kumar K.V (Arm)
Commit
5b138c534fda("dma-direct: factor out adma_direct_alloc_from_poolhelper") changeddma_direct_alloc_from_pool()to return the CPU address fromdma_alloc_from_pool(). That fitsdma_direct_alloc(), butdma_direct_alloc_pages()also uses the helper and expects a struct page *.Fix this by making
dma_direct_alloc_from_pool()return the struct page * again, and pass the CPU address back through an out-parameter for thedma_direct_alloc()caller.Fixes 5b138c534fda ("dma-direct: factor out a dma_direct_alloc_from_pool helper")Tested-by Michael Kelley <[email protected]>Tested-by Mostafa Saleh <[email protected]>Reviewed-by Jason Gunthorpe <[email protected]>Signed-off-by Aneesh Kumar K.V (Arm) <[email protected]>--- kernel/dma/direct.c | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-)kernel/dma/direct.c +4
-5@@ -164,22 +164,21 @@ static bool dma_direct_use_pool(struct device *dev, gfp_t gfp)return !gfpflags_allow_blocking (gfp) && !is_swiotlb_for_alloc (dev); } -static void *dma_direct_alloc_from_pool (struct device *dev,size_t size, -dma_addr_t *dma_handle,gfp_t gfp) +static struct page *dma_direct_alloc_from_pool (struct device *dev,size_t size, +dma_addr_t *dma_handle,void **cpu_addr,gfp_t gfp) {struct page *page;u64 phys_limit; -void *ret;if (WARN_ON_ONCE (!IS_ENABLED (CONFIG_DMA_COHERENT_POOL )))return NULL ; gfp |=dma_direct_optimal_gfp_mask (dev, &phys_limit); - page =dma_alloc_from_pool (dev, size, &ret, gfp, dma_coherent_ok); + page =dma_alloc_from_pool (dev, size, cpu_addr, gfp, dma_coherent_ok);if (!page)return NULL ; *dma_handle =phys_to_dma_direct (dev,page_to_phys (page)); -return ret; +return page; } static void *dma_direct_alloc_no_mapping(struct device *dev, size_t size,
kernel/dma/direct.c void *dma_direct_alloc(struct device *dev, size_t size, · line 252
Quoted 9 lines
kernel/dma/direct.c +4
-2@@ -247,8 +246,11 @@ void *dma_direct_alloc(struct device *dev, size_t size,* the atomic pools instead if we aren't allowed block. */ if ((remap ||force_dma_unencrypted (dev)) && -dma_direct_use_pool (dev, gfp)) -return dma_direct_alloc_from_pool (dev, size, dma_handle, gfp); +dma_direct_use_pool (dev, gfp)) { + page =dma_direct_alloc_from_pool (dev, size, dma_handle, + &ret, gfp); +return page ? ret :NULL ;
Sorry for joining the discussion late, but the line above caught my attention.
Why do we need both ret and page? We can derive cpu_addr from page and vice versa. Do we really need the &ret parameter? Or, more generally, do we really need "struct page *"?
static struct page *__dma_alloc_from_pool(struct device *dev, size_t size,
struct gen_pool *pool, void **cpu_addr,
bool (*phys_addr_ok)(struct device *, phys_addr_t, size_t))
{
...
*cpu_addr = (void *)addr; memset(*cpu_addr, 0, size); return pfn_to_page(__phys_to_pfn(phys)); }
Why
Quoted 17 lines
kernel/dma/direct.c +2
-1+ }/* we always manually zero the memory once we are done */ page =__dma_direct_alloc_pages (dev, size, gfp & ~__GFP_ZERO, true);@@ -357,7 +359,7 @@ struct page *dma_direct_alloc_pages(struct device *dev, size_t size,void *ret;if (force_dma_unencrypted (dev) &&dma_direct_use_pool (dev, gfp)) -return dma_direct_alloc_from_pool (dev, size, dma_handle, gfp); +return dma_direct_alloc_from_pool (dev, size, dma_handle, &ret, gfp); page =__dma_direct_alloc_pages (dev, size, gfp, false);if (!page)Signature · 1 line
2.43.0
Re: [PATCH v8 01/23] dma-direct: return struct page from dma_direct_alloc_from_pool()
Quoted 74 lines · Leon Romanovsky
Quoted 51 lines · Aneesh Kumar K.V (Arm)
Commit
5b138c534fda("dma-direct: factor out adma_direct_alloc_from_poolhelper") changeddma_direct_alloc_from_pool()to return the CPU address fromdma_alloc_from_pool(). That fitsdma_direct_alloc(), butdma_direct_alloc_pages()also uses the helper and expects a struct page *.Fix this by making
dma_direct_alloc_from_pool()return the struct page * again, and pass the CPU address back through an out-parameter for thedma_direct_alloc()caller.Fixes 5b138c534fda ("dma-direct: factor out a dma_direct_alloc_from_pool helper")Tested-by Michael Kelley <[email protected]>Tested-by Mostafa Saleh <[email protected]>Reviewed-by Jason Gunthorpe <[email protected]>Signed-off-by Aneesh Kumar K.V (Arm) <[email protected]>--- kernel/dma/direct.c | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-)kernel/dma/direct.c +4
-5@@ -164,22 +164,21 @@ static bool dma_direct_use_pool(struct device *dev, gfp_t gfp)return !gfpflags_allow_blocking (gfp) && !is_swiotlb_for_alloc (dev); } -static void *dma_direct_alloc_from_pool (struct device *dev,size_t size, -dma_addr_t *dma_handle,gfp_t gfp) +static struct page *dma_direct_alloc_from_pool (struct device *dev,size_t size, +dma_addr_t *dma_handle,void **cpu_addr,gfp_t gfp) {struct page *page;u64 phys_limit; -void *ret;if (WARN_ON_ONCE (!IS_ENABLED (CONFIG_DMA_COHERENT_POOL )))return NULL ; gfp |=dma_direct_optimal_gfp_mask (dev, &phys_limit); - page =dma_alloc_from_pool (dev, size, &ret, gfp, dma_coherent_ok); + page =dma_alloc_from_pool (dev, size, cpu_addr, gfp, dma_coherent_ok);if (!page)return NULL ; *dma_handle =phys_to_dma_direct (dev,page_to_phys (page)); -return ret; +return page; } static void *dma_direct_alloc_no_mapping(struct device *dev, size_t size,kernel/dma/direct.c void *dma_direct_alloc(struct device *dev, size_t size, · line 252
Quoted 9 lines
kernel/dma/direct.c +4
-2@@ -247,8 +246,11 @@ void *dma_direct_alloc(struct device *dev, size_t size,* the atomic pools instead if we aren't allowed block. */ if ((remap ||force_dma_unencrypted (dev)) && -dma_direct_use_pool (dev, gfp)) -return dma_direct_alloc_from_pool (dev, size, dma_handle, gfp); +dma_direct_use_pool (dev, gfp)) { + page =dma_direct_alloc_from_pool (dev, size, dma_handle, + &ret, gfp); +return page ? ret :NULL ;Sorry for joining the discussion late, but the line above caught my attention.
Why do we need both ret and page? We can derive
cpu_addrfrom page and vice versa. Do we really need the &ret parameter? Or, more generally, do we really need "struct page *"?static struct page *__dma_alloc_from_pool(struct device *dev,
size_tsize,
structgen_pool*pool, void **cpu_addr,
bool (*phys_addr_ok)(struct device *,phys_addr_t,size_t))
{
...
Quoted 7 lines
*cpu_addr = (void *)addr; memset(*cpu_addr, 0, size); return pfn_to_page(__phys_to_pfn(phys)); }Why
With CONFIG_DMA_DIRECT_REMAP the cpu_addr can be different from page_address.
-aneesh
Re: [PATCH v8 01/23] dma-direct: return struct page from dma_direct_alloc_from_pool()
Quoted 81 lines · Aneesh Kumar K.V
Quoted 79 lines · Leon Romanovsky
Quoted 51 lines · Aneesh Kumar K.V (Arm)
Commit
5b138c534fda("dma-direct: factor out adma_direct_alloc_from_poolhelper") changeddma_direct_alloc_from_pool()to return the CPU address fromdma_alloc_from_pool(). That fitsdma_direct_alloc(), butdma_direct_alloc_pages()also uses the helper and expects a struct page *.Fix this by making
dma_direct_alloc_from_pool()return the struct page * again, and pass the CPU address back through an out-parameter for thedma_direct_alloc()caller.Fixes 5b138c534fda ("dma-direct: factor out a dma_direct_alloc_from_pool helper")Tested-by Michael Kelley <[email protected]>Tested-by Mostafa Saleh <[email protected]>Reviewed-by Jason Gunthorpe <[email protected]>Signed-off-by Aneesh Kumar K.V (Arm) <[email protected]>--- kernel/dma/direct.c | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-)kernel/dma/direct.c +4
-5@@ -164,22 +164,21 @@ static bool dma_direct_use_pool(struct device *dev, gfp_t gfp)return !gfpflags_allow_blocking (gfp) && !is_swiotlb_for_alloc (dev); } -static void *dma_direct_alloc_from_pool (struct device *dev,size_t size, -dma_addr_t *dma_handle,gfp_t gfp) +static struct page *dma_direct_alloc_from_pool (struct device *dev,size_t size, +dma_addr_t *dma_handle,void **cpu_addr,gfp_t gfp) {struct page *page;u64 phys_limit; -void *ret;if (WARN_ON_ONCE (!IS_ENABLED (CONFIG_DMA_COHERENT_POOL )))return NULL ; gfp |=dma_direct_optimal_gfp_mask (dev, &phys_limit); - page =dma_alloc_from_pool (dev, size, &ret, gfp, dma_coherent_ok); + page =dma_alloc_from_pool (dev, size, cpu_addr, gfp, dma_coherent_ok);if (!page)return NULL ; *dma_handle =phys_to_dma_direct (dev,page_to_phys (page)); -return ret; +return page; } static void *dma_direct_alloc_no_mapping(struct device *dev, size_t size,kernel/dma/direct.c void *dma_direct_alloc(struct device *dev, size_t size, · line 252
Quoted 9 lines
kernel/dma/direct.c +4
-2@@ -247,8 +246,11 @@ void *dma_direct_alloc(struct device *dev, size_t size,* the atomic pools instead if we aren't allowed block. */ if ((remap ||force_dma_unencrypted (dev)) && -dma_direct_use_pool (dev, gfp)) -return dma_direct_alloc_from_pool (dev, size, dma_handle, gfp); +dma_direct_use_pool (dev, gfp)) { + page =dma_direct_alloc_from_pool (dev, size, dma_handle, + &ret, gfp); +return page ? ret :NULL ;Sorry for joining the discussion late, but the line above caught my attention.
Why do we need both ret and page? We can derive
cpu_addrfrom page and vice versa. Do we really need the &ret parameter? Or, more generally, do we really need "struct page *"?static struct page *__dma_alloc_from_pool(struct device *dev,
size_tsize,
structgen_pool*pool, void **cpu_addr,
bool (*phys_addr_ok)(struct device *,phys_addr_t,size_t))
{
...*cpu_addr = (void *)addr; memset(*cpu_addr, 0, size); return pfn_to_page(__phys_to_pfn(phys)); }
Quoted 5 lines
Quoted 2 lines
Why
With
CONFIG_DMA_DIRECT_REMAPthecpu_addrcan be different frompage_address.
Can you please point to the code there it can happen? __dma_alloc_from_pool() has direct connection between physical address and struct page.
Thanks
Quoted 3 lines
-aneesh
Re: [PATCH v8 01/23] dma-direct: return struct page from dma_direct_alloc_from_pool()
Quoted 4 lines · Leon Romanovsky
Quoted 3 lines · Aneesh Kumar K.V
Quoted 1 line · Leon Romanovsky
On Fri, Jul 17, 2026 at 11:34:19PM +0530, Aneesh Kumar K.V (Arm) wrote:
....
Quoted 32 lines
Quoted 32 lines
Quoted 31 lines
kernel/dma/direct.c void *dma_direct_alloc(struct device *dev, size_t size, · line 252
Quoted 11 lines
static void *dma_direct_alloc_no_mapping(struct device *dev,
size_tsize,kernel/dma/direct.c +4
-2@@ -247,8 +246,11 @@ void *dma_direct_alloc(struct device *dev, size_t size,* the atomic pools instead if we aren't allowed block. */ if ((remap ||force_dma_unencrypted (dev)) && -dma_direct_use_pool (dev, gfp)) -return dma_direct_alloc_from_pool (dev, size, dma_handle, gfp); +dma_direct_use_pool (dev, gfp)) { + page =dma_direct_alloc_from_pool (dev, size, dma_handle, + &ret, gfp); +return page ? ret :NULL ;Sorry for joining the discussion late, but the line above caught my attention.
Why do we need both ret and page? We can derive
cpu_addrfrom page and vice versa. Do we really need the &ret parameter? Or, more generally, do we really need "struct page *"?static struct page *__dma_alloc_from_pool(struct device *dev,
size_tsize,
structgen_pool*pool, void **cpu_addr,
bool (*phys_addr_ok)(struct device *,phys_addr_t,size_t))
{
...*cpu_addr = (void *)addr; memset(*cpu_addr, 0, size); return pfn_to_page(__phys_to_pfn(phys)); }Why
Quoted 7 lines
Quoted 2 lines
With
CONFIG_DMA_DIRECT_REMAPthecpu_addrcan be different frompage_address.Can you please point to the code there it can happen?
__dma_alloc_from_pool()has direct connection between physical address and struct page.
dma_direct_alloc -> remap = IS_ENABLED(CONFIG_DMA_DIRECT_REMAP);
if ((remap && dma_direct_use_pool(dev, gfp)) {
page = dma_direct_alloc_from_pool(dev, size,..__dma_alloc_from_pool ->
addr = gen_pool_alloc(pool, size); if (!addr)
We expand the pool as below..
atomic_pool_expand ->
#ifdef CONFIG_DMA_DIRECT_REMAP addr = dma_common_contiguous_remap(page, pool_size, pgprot_decrypted(pgprot_dmacoherent(PAGE_KERNEL)), __builtin_return_address(0)); if (!addr) goto free_page; #else addr = page_to_virt(page);
#endif
-aneesh
Re: [PATCH v8 01/23] dma-direct: return struct page from dma_direct_alloc_from_pool()
Quoted 69 lines · Aneesh Kumar K.V
Quoted 4 lines · Leon Romanovsky
Quoted 3 lines · Aneesh Kumar K.V
Quoted 1 line · Leon Romanovsky
On Fri, Jul 17, 2026 at 11:34:19PM +0530, Aneesh Kumar K.V (Arm) wrote:
....
Quoted 32 lines
Quoted 32 lines
Quoted 31 lines
kernel/dma/direct.c void *dma_direct_alloc(struct device *dev, size_t size, · line 252
Quoted 11 lines
static void *dma_direct_alloc_no_mapping(struct device *dev,
size_tsize,kernel/dma/direct.c +4
-2@@ -247,8 +246,11 @@ void *dma_direct_alloc(struct device *dev, size_t size,* the atomic pools instead if we aren't allowed block. */ if ((remap ||force_dma_unencrypted (dev)) && -dma_direct_use_pool (dev, gfp)) -return dma_direct_alloc_from_pool (dev, size, dma_handle, gfp); +dma_direct_use_pool (dev, gfp)) { + page =dma_direct_alloc_from_pool (dev, size, dma_handle, + &ret, gfp); +return page ? ret :NULL ;Sorry for joining the discussion late, but the line above caught my attention.
Why do we need both ret and page? We can derive
cpu_addrfrom page and vice versa. Do we really need the &ret parameter? Or, more generally, do we really need "struct page *"?static struct page *__dma_alloc_from_pool(struct device *dev,
size_tsize,
structgen_pool*pool, void **cpu_addr,
bool (*phys_addr_ok)(struct device *,phys_addr_t,size_t))
{
...*cpu_addr = (void *)addr; memset(*cpu_addr, 0, size); return pfn_to_page(__phys_to_pfn(phys)); }Why
Quoted 7 lines
Quoted 2 lines
With
CONFIG_DMA_DIRECT_REMAPthecpu_addrcan be different frompage_address.Can you please point to the code there it can happen?
__dma_alloc_from_pool()has direct connection between physical address and struct page.dma_direct_alloc -> remap = IS_ENABLED(CONFIG_DMA_DIRECT_REMAP); if ((remap && dma_direct_use_pool(dev, gfp)) { page = dma_direct_alloc_from_pool(dev, size,..
__dma_alloc_from_pool->addr = gen_pool_alloc(pool, size); if (!addr)We expand the pool as below..
atomic_pool_expand->#ifdef CONFIG_DMA_DIRECT_REMAP addr = dma_common_contiguous_remap(page, pool_size, pgprot_decrypted(pgprot_dmacoherent(PAGE_KERNEL)), __builtin_return_address(0)); if (!addr) goto free_page; #else addr = page_to_virt(page);
Quoted 1 line
#endif
Right, and nothing prevents you from adding a small DMA helper that translates mapped/direct addresses back to struct page.
Something like, but probably void* needs to be phys_addr_t:
static inline struct page *dma_phys_to_page(void *addr) {
#ifdef CONFIG_DMA_DIRECT_REMAP return vmalloc_to_page(addr); #else return virt_to_page(addr);
#endif
}
Architecture code already does this throughout the tree.
Thanks
Quoted 4 lines
-aneesh
Re: [PATCH v8 01/23] dma-direct: return struct page from dma_direct_alloc_from_pool()
Quoted 10 lines · Leon Romanovsky
Something like, but probably void* needs to be
phys_addr_t:static inline struct page *dma_phys_to_page(void *addr) {
#ifdef CONFIG_DMA_DIRECT_REMAP return vmalloc_to_page(addr); #else return virt_to_page(addr);#endif
}
I don't like this, we don't know for sure the addr will be in a vmap and this will fail if it isn't.
Jason
Re: [PATCH v8 01/23] dma-direct: return struct page from dma_direct_alloc_from_pool()
Quoted 13 lines · Jason Gunthorpe
Quoted 10 lines · Leon Romanovsky
Something like, but probably void* needs to be
phys_addr_t:static inline struct page *dma_phys_to_page(void *addr) {
#ifdef CONFIG_DMA_DIRECT_REMAP return vmalloc_to_page(addr); #else return virt_to_page(addr);#endif
}
Quoted 2 lines
I don't like this, we don't know for sure the addr will be in a vmap and this will fail if it isn't.
Of course we know. The existing "#ifdef CONFIG_DMA_DIRECT_REMAP" is relevant for addresses acquired from pool.
dma_phys_to_page() is a bad name for some low-level conversion function. It needs to be internal to DMA logic, in the level when we convert from phys to page.
Thanks
Quoted 3 lines
Jason
Re: [PATCH v8 01/23] dma-direct: return struct page from dma_direct_alloc_from_pool()
Quoted 14 lines · Leon Romanovsky
Quoted 13 lines · Jason Gunthorpe
Quoted 10 lines · Leon Romanovsky
Something like, but probably void* needs to be
phys_addr_t:static inline struct page *dma_phys_to_page(void *addr) {
#ifdef CONFIG_DMA_DIRECT_REMAP return vmalloc_to_page(addr); #else return virt_to_page(addr);#endif
}
Quoted 5 lines
Quoted 2 lines
I don't like this, we don't know for sure the addr will be in a vmap and this will fail if it isn't.
Of course we know. The existing "#ifdef
CONFIG_DMA_DIRECT_REMAP" is relevant for addresses acquired from pool.
Yeah, but I still don't like it :) It is hard to follow if you make those kinds of leaps, someone will call this new helper on something they shouldn't
Quoted 3 lines
dma_phys_to_page()is a bad name for some low-level conversion function. It needs to be internal to DMA logic, in the level when we convert from phys to page.
I think we should not convert from phys to page, that's also easy to do wrong
Jason
Re: [PATCH v8 01/23] dma-direct: return struct page from dma_direct_alloc_from_pool()
Quoted 18 lines · Jason Gunthorpe
Quoted 17 lines · Leon Romanovsky
Quoted 15 lines · Jason Gunthorpe
Quoted 10 lines · Leon Romanovsky
Something like, but probably void* needs to be
phys_addr_t:static inline struct page *dma_phys_to_page(void *addr) {
#ifdef CONFIG_DMA_DIRECT_REMAP return vmalloc_to_page(addr); #else return virt_to_page(addr);#endif
}I don't like this, we don't know for sure the addr will be in a vmap and this will fail if it isn't.
Quoted 6 lines
Quoted 2 lines
Of course we know. The existing "#ifdef
CONFIG_DMA_DIRECT_REMAP" is relevant for addresses acquired from pool.Yeah, but I still don't like it :) It is hard to follow if you make those kinds of leaps, someone will call this new helper on something they shouldn't
This issue is straightforward to address today. Limit the scope, use an appropriate function name, and add a comment indicating that the function is local to and specific to the pool. The latter helps AI-based review tools flag incorrect usage outside the intended scope.
Quoted 7 lines
Quoted 4 lines
dma_phys_to_page()is a bad name for some low-level conversion function. It needs to be internal to DMA logic, in the level when we convert from phys to page.I think we should not convert from phys to page, that's also easy to do wrong
Perhaps I'll reiterate my complaint. DMA internals are already hard to understand. Part of that complexity is necessary to support every possible use case, but another part comes from a maze of types that is entirely self-inflicted. I think this code only makes the latter worse.
Currently, the phys type universally describes memory and can be reliably translated into any required representation. It is the most fundamental type we have.
Thanks
Quoted 3 lines
Jason
Re: [PATCH v8 01/23] dma-direct: return struct page from dma_direct_alloc_from_pool()
Quoted 3 lines · Leon Romanovsky
Currently, the phys type universally describes memory and can be reliably translated into any required representation. It is the most fundamental type we have.
You cannot go from phys to page reliably unless you make assumptions about the phys, that's the whole issue here. If the callchain expects and intends to use a page it should really stay in a page and not take a side trip to phys.
I agree it would help to have some helpers that were more phys based for the callchains that want that since we are mixing two fairly different activities in these functions..
But making phys the only output out of the pool isn't going to be an improvement.
BTW how does a struct page even work for decrypted memory? You can't actually use it that way right? If you try to access it then you'll get the wrong IPA and it should explode?
Maybe we should be blocking the struct page path entirely for CC shared?
Jason
Re: [PATCH v8 01/23] dma-direct: return struct page from dma_direct_alloc_from_pool()
Quoted 6 lines · Jason Gunthorpe
Quoted 3 lines · Leon Romanovsky
Currently, the phys type universally describes memory and can be reliably translated into any required representation. It is the most fundamental type we have.
Quoted 8 lines
You cannot go from phys to page reliably unless you make assumptions about the phys, that's the whole issue here. If the callchain expects and intends to use a page it should really stay in a page and not take a side trip to phys.
I agree it would help to have some helpers that were more phys based for the callchains that want that since we are mixing two fairly different activities in these functions..
Yes, we are agreed here.
Quoted 3 lines
But making phys the only output out of the pool isn't going to be an improvement.
I don't know, phys was natural suggestion due to multiple page_to_phys/phys_to_page conversions down the road.
Quoted 7 lines
BTW how does a struct page even work for decrypted memory? You can't actually use it that way right? If you try to access it then you'll get the wrong IPA and it should explode?
Maybe we should be blocking the struct page path entirely for CC shared?
It will simplify things. Ultimately, this series demonstrates that CC users must be aware of the memory attribute (CC_SHARED) and struct page is too generic.
Thanks
Quoted 3 lines
Jason
Re: [PATCH v8 01/23] dma-direct: return struct page from dma_direct_alloc_from_pool()
In reply to Leon RomanovskyQuoted 39 lines · Leon Romanovsky
Quoted 18 lines · Jason Gunthorpe
Quoted 17 lines · Leon Romanovsky
Quoted 15 lines · Jason Gunthorpe
Quoted 10 lines · Leon Romanovsky
Something like, but probably void* needs to be
phys_addr_t:static inline struct page *dma_phys_to_page(void *addr) {
#ifdef CONFIG_DMA_DIRECT_REMAP return vmalloc_to_page(addr); #else return virt_to_page(addr);#endif
}I don't like this, we don't know for sure the addr will be in a vmap and this will fail if it isn't.
Quoted 6 lines
Quoted 2 lines
Of course we know. The existing "#ifdef
CONFIG_DMA_DIRECT_REMAP" is relevant for addresses acquired from pool.Yeah, but I still don't like it :) It is hard to follow if you make those kinds of leaps, someone will call this new helper on something they shouldn't
This issue is straightforward to address today. Limit the scope, use an appropriate function name, and add a comment indicating that the function is local to and specific to the pool. The latter helps AI-based review tools flag incorrect usage outside the intended scope.
Quoted 7 lines
Quoted 4 lines
dma_phys_to_page()is a bad name for some low-level conversion function. It needs to be internal to DMA logic, in the level when we convert from phys to page.I think we should not convert from phys to page, that's also easy to do wrong
Quoted 9 lines
Perhaps I'll reiterate my complaint. DMA internals are already hard to understand. Part of that complexity is necessary to support every possible use case, but another part comes from a maze of types that is entirely self-inflicted. I think this code only makes the latter worse.
Currently, the phys type universally describes memory and can be reliably translated into any required representation. It is the most fundamental type we have.
I think we can address the suggested changes as a follow-up patch series on top of this.
How about we get this picked up for the next merge window first, so that we can get the CC_SHARED related changes in? The follow-up changes should be easier once we have agreement on the overall design, and can then be done as incremental cleanups.
-aneesh
Re: [PATCH v8 01/23] dma-direct: return struct page from dma_direct_alloc_from_pool()
In reply to Aneesh Kumar K.V (Arm)Quoted 9 lines · Aneesh Kumar K.V (Arm)
Commit
5b138c534fda("dma-direct: factor out adma_direct_alloc_from_poolhelper") changeddma_direct_alloc_from_pool()to return the CPU address fromdma_alloc_from_pool(). That fitsdma_direct_alloc(), butdma_direct_alloc_pages()also uses the helper and expects a struct page *.Fix this by making
dma_direct_alloc_from_pool()return the struct page * again, and pass the CPU address back through an out-parameter for thedma_direct_alloc()caller.
Quoted 6 lines
Fixes 5b138c534fda ("dma-direct: factor out a dma_direct_alloc_from_pool helper")Tested-by Michael Kelley <[email protected]>Tested-by Mostafa Saleh <[email protected]>Reviewed-by Jason Gunthorpe <[email protected]>Signed-off-by Aneesh Kumar K.V (Arm) <[email protected]>
Thanks,
Mostafa
Quoted 61 lines
--- kernel/dma/direct.c | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-)kernel/dma/direct.c +10
-8@@ -164,22 +164,21 @@ static bool dma_direct_use_pool(struct device *dev, gfp_t gfp)return !gfpflags_allow_blocking (gfp) && !is_swiotlb_for_alloc (dev); } -static void *dma_direct_alloc_from_pool (struct device *dev,size_t size, -dma_addr_t *dma_handle,gfp_t gfp) +static struct page *dma_direct_alloc_from_pool (struct device *dev,size_t size, +dma_addr_t *dma_handle,void **cpu_addr,gfp_t gfp) {struct page *page;u64 phys_limit; -void *ret;if (WARN_ON_ONCE (!IS_ENABLED (CONFIG_DMA_COHERENT_POOL )))return NULL ; gfp |=dma_direct_optimal_gfp_mask (dev, &phys_limit); - page =dma_alloc_from_pool (dev, size, &ret, gfp, dma_coherent_ok); + page =dma_alloc_from_pool (dev, size, cpu_addr, gfp, dma_coherent_ok);if (!page)return NULL ; *dma_handle =phys_to_dma_direct (dev,page_to_phys (page)); -return ret; +return page; } static void *dma_direct_alloc_no_mapping(struct device *dev, size_t size,@@ -247,8 +246,11 @@ void *dma_direct_alloc(struct device *dev, size_t size,* the atomic pools instead if we aren't allowed block. */ if ((remap ||force_dma_unencrypted (dev)) && -dma_direct_use_pool (dev, gfp)) -return dma_direct_alloc_from_pool (dev, size, dma_handle, gfp); +dma_direct_use_pool (dev, gfp)) { + page =dma_direct_alloc_from_pool (dev, size, dma_handle, + &ret, gfp); +return page ? ret :NULL ; + }/* we always manually zero the memory once we are done */ page =__dma_direct_alloc_pages (dev, size, gfp & ~__GFP_ZERO, true);@@ -357,7 +359,7 @@ struct page *dma_direct_alloc_pages(struct device *dev, size_t size,void *ret;if (force_dma_unencrypted (dev) &&dma_direct_use_pool (dev, gfp)) -return dma_direct_alloc_from_pool (dev, size, dma_handle, gfp); +return dma_direct_alloc_from_pool (dev, size, dma_handle, &ret, gfp); page =__dma_direct_alloc_pages (dev, size, gfp, false);if (!page)Signature · 1 line
2.43.0
PATCH v8 2/23 dma-pool: fix page leak in atomic_pool_expand() cleanup
In reply to Aneesh Kumar K.V (Arm)atomic_pool_expand() frees the allocated pages from the remove_mapping error path only when CONFIG_DMA_DIRECT_REMAP is enabled.
When CONFIG_DMA_DIRECT_REMAP is disabled, failures after page allocation, such as gen_pool_add_virt(), jump to remove_mapping and return without freeing the pages.
Move __free_pages(page, order) out of the CONFIG_DMA_DIRECT_REMAP block so that cleanup paths always release the allocation.
--- kernel/dma/pool.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-)
kernel/dma/pool.c +7 -3
@@ -81,6 +81,7 @@ static int atomic_pool_expand(struct gen_pool *pool, size_t pool_size, {unsigned int order;struct page *page =NULL ; +bool leak_pages = false;void *addr;int ret = -ENOMEM ;
@@ -115,8 +116,10 @@ static int atomic_pool_expand(struct gen_pool *pool, size_t pool_size,*/ ret =set_memory_decrypted ((unsigned long )page_to_virt (page),1 << order); -if (ret) +if (ret) { + leak_pages = true; goto remove_mapping; + } ret =gen_pool_add_virt (pool, (unsigned long )addr,page_to_phys (page), pool_size,NUMA_NO_NODE );if (ret)
@@ -130,14 +133,15 @@ static int atomic_pool_expand(struct gen_pool *pool, size_t pool_size, 1 << order);if (WARN_ON_ONCE (ret)) {/* Decrypt succeeded but encrypt failed, purposely leak */ - goto out; + leak_pages = true; } remove_mapping: #ifdef CONFIG_DMA_DIRECT_REMAPdma_common_free_remap (addr ,pool_size ); free_page: -__free_pages (page, order); #endif +if (!leak_pages) +__free_pages (page, order); out:return ret; }
Signature · 1 line
2.43.0
Re: [PATCH v8 02/23] dma-pool: fix page leak in atomic_pool_expand() cleanup
Quoted 43 lines · Aneesh Kumar K.V (Arm)
atomic_pool_expand()frees the allocated pages from theremove_mappingerror path only whenCONFIG_DMA_DIRECT_REMAPis enabled.When
CONFIG_DMA_DIRECT_REMAPis disabled, failures after page allocation, such asgen_pool_add_virt(), jump toremove_mappingand return without freeing the pages.Move
__free_pages(page, order)out of theCONFIG_DMA_DIRECT_REMAPblock so that cleanup paths always release the allocation.Reviewed-by Jason Gunthorpe <[email protected]>Tested-by Michael Kelley <[email protected]>Tested-by Mostafa Saleh <[email protected]>Signed-off-by Aneesh Kumar K.V (Arm) <[email protected]>--- kernel/dma/pool.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-)kernel/dma/pool.c +4
-1@@ -81,6 +81,7 @@ static int atomic_pool_expand(struct gen_pool *pool, size_t pool_size, {unsigned int order;struct page *page =NULL ; +bool leak_pages = false;void *addr;int ret = -ENOMEM ;@@ -115,8 +116,10 @@ static int atomic_pool_expand(struct gen_pool *pool, size_t pool_size,*/ ret =set_memory_decrypted ((unsigned long )page_to_virt (page),1 << order); -if (ret) +if (ret) { + leak_pages = true; goto remove_mapping; + } ret =gen_pool_add_virt (pool, (unsigned long )addr,page_to_phys (page), pool_size,NUMA_NO_NODE );if (ret)
kernel/dma/pool.c static int atomic_pool_expand(struct gen_pool *pool, size_t pool_size, · line 136
Quoted 5 lines
kernel/dma/pool.c +1
-1@@ -130,14 +133,15 @@ static int atomic_pool_expand(struct gen_pool *pool, size_t pool_size, 1 << order);if (WARN_ON_ONCE (ret)) {/* Decrypt succeeded but encrypt failed, purposely leak */ - goto out; + leak_pages = true;
Instead of doing this dance with temporal variable, change "goto out" to be "return true".
kernel/dma/pool.c static int atomic_pool_expand(struct gen_pool *pool, size_t pool_size, · line 141
Quoted 5 lines
kernel/dma/pool.c +0
-0} remove_mapping: #ifdef CONFIG_DMA_DIRECT_REMAPdma_common_free_remap (addr ,pool_size ); free_page:
Remove free_page label, and change leftover of "goto free_page" to be "goto out"
kernel/dma/pool.c static int atomic_pool_expand(struct gen_pool *pool, size_t pool_size, · line 144
Quoted 4 lines
kernel/dma/pool.c +2
-1-__free_pages (page, order);#endif +if (!leak_pages) +__free_pages (page, order);
Put these checks under out label and rely on page != NULL as a marker. if (page)
__free_pages(page, order);
Quoted 7 lines
kernel/dma/pool.c +0
-0out:return ret; }Signature · 1 line
2.43.0
Re: [PATCH v8 02/23] dma-pool: fix page leak in atomic_pool_expand() cleanup
Quoted 44 lines · Leon Romanovsky
Quoted 43 lines · Aneesh Kumar K.V (Arm)
atomic_pool_expand()frees the allocated pages from theremove_mappingerror path only whenCONFIG_DMA_DIRECT_REMAPis enabled.When
CONFIG_DMA_DIRECT_REMAPis disabled, failures after page allocation, such asgen_pool_add_virt(), jump toremove_mappingand return without freeing the pages.Move
__free_pages(page, order)out of theCONFIG_DMA_DIRECT_REMAPblock so that cleanup paths always release the allocation.Reviewed-by Jason Gunthorpe <[email protected]>Tested-by Michael Kelley <[email protected]>Tested-by Mostafa Saleh <[email protected]>Signed-off-by Aneesh Kumar K.V (Arm) <[email protected]>--- kernel/dma/pool.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-)kernel/dma/pool.c +4
-1@@ -81,6 +81,7 @@ static int atomic_pool_expand(struct gen_pool *pool, size_t pool_size, {unsigned int order;struct page *page =NULL ; +bool leak_pages = false;void *addr;int ret = -ENOMEM ;@@ -115,8 +116,10 @@ static int atomic_pool_expand(struct gen_pool *pool, size_t pool_size,*/ ret =set_memory_decrypted ((unsigned long )page_to_virt (page),1 << order); -if (ret) +if (ret) { + leak_pages = true; goto remove_mapping; + } ret =gen_pool_add_virt (pool, (unsigned long )addr,page_to_phys (page), pool_size,NUMA_NO_NODE );if (ret)@@ -130,14 +133,15 @@ static int atomic_pool_expand(struct gen_pool *pool, size_t pool_size,
Quoted 9 lines
kernel/dma/pool.c static int atomic_pool_expand(struct gen_pool *pool, size_t pool_size, · line 136
Quoted 5 lines
kernel/dma/pool.c +1
-11 << order);if (WARN_ON_ONCE (ret)) {/* Decrypt succeeded but encrypt failed, purposely leak */ - goto out; + leak_pages = true;Instead of doing this dance with temporal variable, change "goto out" to be "return true".
I didn't follow the return true part. A failure in set_memory_encrypted() or set_memory_decrypted() requires the pages to be leaked, so this is not the only call site that sets leak_pages = true. There is a similar case a few lines above.
Quoted 10 lines
kernel/dma/pool.c static int atomic_pool_expand(struct gen_pool *pool, size_t pool_size, · line 141
Quoted 6 lines
kernel/dma/pool.c +0
-0} remove_mapping: #ifdef CONFIG_DMA_DIRECT_REMAPdma_common_free_remap (addr ,pool_size ); free_page:Remove
free_pagelabel, and change leftover of "gotofree_page" to be "goto out"
Quoted 16 lines
kernel/dma/pool.c static int atomic_pool_expand(struct gen_pool *pool, size_t pool_size, · line 144
Quoted 4 lines
kernel/dma/pool.c +2
-1-__free_pages (page, order);#endif +if (!leak_pages) +__free_pages (page, order);Put these checks under out label and rely on page != NULL as a marker. if (page)
__free_pages(page, order);Quoted 7 lines
kernel/dma/pool.c +0
-0out:return ret; }Signature · 1 line
2.43.0
-aneesh
Re: [PATCH v8 02/23] dma-pool: fix page leak in atomic_pool_expand() cleanup
Quoted 57 lines · Aneesh Kumar K.V
Quoted 44 lines · Leon Romanovsky
Quoted 43 lines · Aneesh Kumar K.V (Arm)
atomic_pool_expand()frees the allocated pages from theremove_mappingerror path only whenCONFIG_DMA_DIRECT_REMAPis enabled.When
CONFIG_DMA_DIRECT_REMAPis disabled, failures after page allocation, such asgen_pool_add_virt(), jump toremove_mappingand return without freeing the pages.Move
__free_pages(page, order)out of theCONFIG_DMA_DIRECT_REMAPblock so that cleanup paths always release the allocation.Reviewed-by Jason Gunthorpe <[email protected]>Tested-by Michael Kelley <[email protected]>Tested-by Mostafa Saleh <[email protected]>Signed-off-by Aneesh Kumar K.V (Arm) <[email protected]>--- kernel/dma/pool.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-)kernel/dma/pool.c +4
-1@@ -81,6 +81,7 @@ static int atomic_pool_expand(struct gen_pool *pool, size_t pool_size, {unsigned int order;struct page *page =NULL ; +bool leak_pages = false;void *addr;int ret = -ENOMEM ;@@ -115,8 +116,10 @@ static int atomic_pool_expand(struct gen_pool *pool, size_t pool_size,*/ ret =set_memory_decrypted ((unsigned long )page_to_virt (page),1 << order); -if (ret) +if (ret) { + leak_pages = true; goto remove_mapping; + } ret =gen_pool_add_virt (pool, (unsigned long )addr,page_to_phys (page), pool_size,NUMA_NO_NODE );if (ret)@@ -130,14 +133,15 @@ static int atomic_pool_expand(struct gen_pool *pool, size_t pool_size,Quoted 9 lines
kernel/dma/pool.c static int atomic_pool_expand(struct gen_pool *pool, size_t pool_size, · line 136
Quoted 5 lines
kernel/dma/pool.c +1
-11 << order);if (WARN_ON_ONCE (ret)) {/* Decrypt succeeded but encrypt failed, purposely leak */ - goto out; + leak_pages = true;Instead of doing this dance with temporal variable, change "goto out" to be "return true".
Quoted 4 lines
I didn't follow the return true part. A failure in
set_memory_encrypted()orset_memory_decrypted()requires the pages to be leaked, so this is not the only call site that setsleak_pages= true. There is a similar case a few lines above.
Comment about "leaked" is enough. There is no need to introduce convoluted flow just to check that page != NULL.
Thanks
Quoted 31 lines
Quoted 12 lines
kernel/dma/pool.c static int atomic_pool_expand(struct gen_pool *pool, size_t pool_size, · line 141
Quoted 8 lines
kernel/dma/pool.c +0
-0} remove_mapping: #ifdef CONFIG_DMA_DIRECT_REMAPdma_common_free_remap (addr ,pool_size ); free_page:Remove
free_pagelabel, and change leftover of "gotofree_page" to be "goto out"Quoted 16 lines
kernel/dma/pool.c static int atomic_pool_expand(struct gen_pool *pool, size_t pool_size, · line 144
Quoted 4 lines
kernel/dma/pool.c +2
-1-__free_pages (page, order);#endif +if (!leak_pages) +__free_pages (page, order);Put these checks under out label and rely on page != NULL as a marker. if (page)
__free_pages(page, order);Quoted 7 lines
kernel/dma/pool.c +0
-0out:return ret; }Signature · 1 line
2.43.0-aneesh
PATCH v8 3/23 iommu/dma: Check atomic pool allocation result directly
In reply to Aneesh Kumar K.V (Arm)The non-blocking, non-coherent allocation path uses dma_alloc_from_pool(), which returns the allocated page and fills cpu_addr only on success.
Do not rely on cpu_addr to detect allocation failure in this path. Check the returned page directly before using it for the IOMMU mapping.
--- drivers/iommu/dma-iommu.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-)
drivers/iommu/dma-iommu.c +8 -5
@@ -1671,13 +1671,16 @@ void *iommu_dma_alloc(struct device *dev, size_t size, dma_addr_t *handle, }if (IS_ENABLED (CONFIG_DMA_DIRECT_REMAP ) && - !gfpflags_allow_blocking (gfp) && !coherent) + !gfpflags_allow_blocking (gfp) && !coherent) { page =dma_alloc_from_pool (dev,PAGE_ALIGN (size), &cpu_addr, - gfp,NULL ); -else + gfp,NULL ); +if (!page) +return NULL ; + }else { cpu_addr =iommu_dma_alloc_pages (dev, size, &page, gfp, attrs); -if (!cpu_addr) -return NULL ; +if (!cpu_addr) +return NULL ; + } *handle =__iommu_dma_map (dev,page_to_phys (page), size, ioprot, dev->coherent_dma_mask);
Signature · 1 line
2.43.0
PATCH v8 4/23 dma: free atomic pool pages by physical address
In reply to Aneesh Kumar K.V (Arm)dma_direct_alloc_pages() may satisfy atomic allocations from the coherent atomic pools. The pool allocation is keyed by the virtual address stored in the gen_pool, but the pages API returns only the backing struct page.
On architectures with CONFIG_DMA_DIRECT_REMAP, atomic pool chunks are added to the gen_pool using their remapped virtual address. dma_direct_free_pages() reconstructs a linear-map address with page_address(page) and passes that to dma_free_from_pool(). That address does not match the gen_pool virtual range, so the pool lookup can fail and the code can fall through to freeing a pool-owned page through the normal page allocator path.
Add a page-based pool free helper that looks up the owning pool chunk by physical address, translates it back to the gen_pool virtual address, and frees that address to the pool. Use it from dma_direct_free_pages() while keeping the existing virtual-address helper for coherent allocation frees.
--- include/linux/dma-map-ops.h | 1 + kernel/dma/direct.c | 4 +-- kernel/dma/pool.c | 61 +++++++++++++++++++++++++++++++++++++ 3 files changed, 64 insertions(+), 2 deletions(-)
include/linux/dma-map-ops.h +1 -0
@@ -215,6 +215,7 @@ struct page *dma_alloc_from_pool(struct device *dev, size_t size, void **cpu_addr, gfp_t flags, bool (*phys_addr_ok)(struct device *, phys_addr_t, size_t));bool dma_free_from_pool (struct device *dev,void *start,size_t size); +bool dma_free_from_pool_page (struct device *dev,struct page *page,size_t size);int dma_direct_set_offset (struct device *dev,phys_addr_t cpu_start,dma_addr_t dma_start,u64 size);
kernel/dma/direct.c +2 -2
@@ -381,9 +381,9 @@ void dma_direct_free_pages(struct device *dev, size_t size, {void *vaddr =page_address (page); -/* If cpu_addr is not from an atomic pool, dma_free_from_pool() fails */ +/* If page is not from an atomic pool, dma_free_from_pool_page() fails */ if (IS_ENABLED (CONFIG_DMA_COHERENT_POOL ) && -dma_free_from_pool (dev, vaddr, size)) +dma_free_from_pool_page (dev, page, size))return ;if (dma_set_encrypted (dev, vaddr, size))
kernel/dma/pool.c +61 -0
64 lines not on this page · raw message
Signature · 1 line
2.43.0
PATCH v8 5/23 swiotlb: Preserve allocation virtual address for dynamic pools
In reply to Aneesh Kumar K.V (Arm)swiotlb_alloc_tlb() can allocate from the DMA atomic pool when a decrypted pool is needed from atomic context. With CONFIG_DMA_DIRECT_REMAP, the atomic pool is backed by remapped virtual addresses, which are not the same as the direct-map addresses returned by phys_to_virt().
swiotlb_init_io_tlb_pool() currently reconstructs the pool virtual address from the physical start address. For atomic-pool backed allocations this stores the wrong address in pool->vaddr. Later, swiotlb_free_tlb() passes that address to dma_free_from_pool(), which will fail to recognize the chunk
Pass the virtual address returned by the allocation path into swiotlb_init_io_tlb_pool(), and store that address in pool->vaddr. This keeps the pool free path using the same virtual address as the allocator.
--- kernel/dma/swiotlb.c | 31 +++++++++++++++++++------------ 1 file changed, 19 insertions(+), 12 deletions(-)
kernel/dma/swiotlb.c +19 -12
@@ -266,9 +266,9 @@ void __init swiotlb_update_mem_attributes(void) }static void swiotlb_init_io_tlb_pool (struct io_tlb_pool *mem,phys_addr_t start, -unsigned long nslabs,bool late_alloc,unsigned int nareas) +void *vaddr,unsigned long nslabs,bool late_alloc, +unsigned int nareas) { -void *vaddr =phys_to_virt (start);unsigned long bytes = nslabs <<IO_TLB_SHIFT , i; mem->nslabs = nslabs;
@@ -409,7 +409,7 @@ void __init swiotlb_init_remap(bool addressing_limit, unsigned int flags,return ; } -swiotlb_init_io_tlb_pool (mem,__pa (tlb), nslabs, false, nareas); +swiotlb_init_io_tlb_pool (mem,__pa (tlb), tlb, nslabs, false, nareas);add_mem_pool (&io_tlb_default_mem, mem);if (flags &SWIOTLB_VERBOSE )
@@ -507,7 +507,7 @@ int swiotlb_init_late(size_t size, gfp_t gfp_mask,set_memory_decrypted ((unsigned long )vstart, (nslabs <<IO_TLB_SHIFT ) >>PAGE_SHIFT ); -swiotlb_init_io_tlb_pool (mem,virt_to_phys (vstart), nslabs, true, +swiotlb_init_io_tlb_pool (mem,virt_to_phys (vstart), vstart, nslabs, true, nareas);add_mem_pool (&io_tlb_default_mem, mem);
@@ -605,25 +605,26 @@ static struct page *alloc_dma_pages(gfp_t gfp, size_t bytes, u64 phys_limit)* @bytes: Size of the buffer. * @phys_limit: Maximum allowed physical address of the buffer. * @gfp: GFP flags for the allocation. +* @vaddr: Receives the virtual address for the allocated buffer. * * Return: Allocated pages, or %NULL on allocation failure. */ static struct page *swiotlb_alloc_tlb (struct device *dev,size_t bytes, -u64 phys_limit,gfp_t gfp) +u64 phys_limit,gfp_t gfp,void **vaddr) {struct page *page; + *vaddr =NULL ; +/* * Allocate from the atomic pools if memory is encrypted and * the allocation is atomic, because decrypting may block. */ if (!gfpflags_allow_blocking (gfp) && dev &&force_dma_unencrypted (dev)) { -void *vaddr; -if (!IS_ENABLED (CONFIG_DMA_COHERENT_POOL ))return NULL ; -return dma_alloc_from_pool (dev, bytes, &vaddr, gfp, +return dma_alloc_from_pool (dev, bytes, vaddr, gfp, dma_coherent_ok); }
@@ -645,6 +646,8 @@ static struct page *swiotlb_alloc_tlb(struct device *dev, size_t bytes,return NULL ; } +if (page) + *vaddr =phys_to_virt (page_to_phys (page));return page; }
@@ -685,6 +688,7 @@ static struct io_tlb_pool *swiotlb_alloc_pool(struct device *dev, {struct io_tlb_pool *pool;unsigned int slot_order; +void *tlb_vaddr;struct page *tlb;size_t pool_size;size_t tlb_size;
@@ -701,7 +705,8 @@ static struct io_tlb_pool *swiotlb_alloc_pool(struct device *dev, pool->areas = (void *)pool +sizeof (*pool); tlb_size = nslabs <<IO_TLB_SHIFT ; -while (!(tlb =swiotlb_alloc_tlb (dev, tlb_size, phys_limit, gfp))) { +while (!(tlb =swiotlb_alloc_tlb (dev, tlb_size, phys_limit, gfp, + &tlb_vaddr))) {if (nslabs <= minslabs) goto error_tlb; nslabs =ALIGN (nslabs >>1 ,IO_TLB_SEGSIZE );
@@ -715,11 +720,12 @@ static struct io_tlb_pool *swiotlb_alloc_pool(struct device *dev,if (!pool->slots) goto error_slots; -swiotlb_init_io_tlb_pool (pool,page_to_phys (tlb), nslabs, true, nareas); +swiotlb_init_io_tlb_pool (pool,page_to_phys (tlb), tlb_vaddr, nslabs, + true, nareas);return pool; error_slots: -swiotlb_free_tlb (page_address (tlb), tlb_size); +swiotlb_free_tlb (tlb_vaddr, tlb_size); error_tlb:kfree (pool); error:
@@ -1851,7 +1857,8 @@ static int rmem_swiotlb_device_init(struct reserved_mem *rmem,set_memory_decrypted ((unsigned long )phys_to_virt (rmem->base), rmem->size >>PAGE_SHIFT ); -swiotlb_init_io_tlb_pool (pool, rmem->base, nslabs, +swiotlb_init_io_tlb_pool (pool, rmem->base,phys_to_virt (rmem->base), + nslabs, false, nareas); mem->force_bounce = true; mem->for_alloc = true;
Signature · 1 line
2.43.0
Re: [PATCH v8 05/23] swiotlb: Preserve allocation virtual address for dynamic pools
Quoted 15 lines · Aneesh Kumar K.V (Arm)
swiotlb_alloc_tlb()can allocate from the DMA atomic pool when a decrypted pool is needed from atomic context. WithCONFIG_DMA_DIRECT_REMAP, the atomic pool is backed by remapped virtual addresses, which are not the same as the direct-map addresses returned byphys_to_virt().
swiotlb_init_io_tlb_pool()currently reconstructs the pool virtual address from the physical start address. For atomic-pool backed allocations this stores the wrong address inpool->vaddr. Later,swiotlb_free_tlb()passes that address todma_free_from_pool(), which will fail to recognize the chunkPass the virtual address returned by the allocation path into
swiotlb_init_io_tlb_pool(), and store that address inpool->vaddr. This keeps the pool free path using the same virtual address as the allocator.
Quoted 6 lines
Fixes 79636caad361 ("swiotlb: if swiotlb is full, fall back to a transient memory pool")Reviewed-by Jason Gunthorpe <[email protected]>Tested-by Michael Kelley <[email protected]>Tested-by Mostafa Saleh <[email protected]>Reviewed-by Petr Tesarik <[email protected]>Signed-off-by Aneesh Kumar K.V (Arm) <[email protected]>
Thanks,
Mostafa
Quoted 124 lines
--- kernel/dma/swiotlb.c | 31 +++++++++++++++++++------------ 1 file changed, 19 insertions(+), 12 deletions(-)kernel/dma/swiotlb.c +19
-12@@ -266,9 +266,9 @@ void __init swiotlb_update_mem_attributes(void) }static void swiotlb_init_io_tlb_pool (struct io_tlb_pool *mem,phys_addr_t start, -unsigned long nslabs,bool late_alloc,unsigned int nareas) +void *vaddr,unsigned long nslabs,bool late_alloc, +unsigned int nareas) { -void *vaddr =phys_to_virt (start);unsigned long bytes = nslabs <<IO_TLB_SHIFT , i; mem->nslabs = nslabs;@@ -409,7 +409,7 @@ void __init swiotlb_init_remap(bool addressing_limit, unsigned int flags,return ; } -swiotlb_init_io_tlb_pool (mem,__pa (tlb), nslabs, false, nareas); +swiotlb_init_io_tlb_pool (mem,__pa (tlb), tlb, nslabs, false, nareas);add_mem_pool (&io_tlb_default_mem, mem);if (flags &SWIOTLB_VERBOSE )@@ -507,7 +507,7 @@ int swiotlb_init_late(size_t size, gfp_t gfp_mask,set_memory_decrypted ((unsigned long )vstart, (nslabs <<IO_TLB_SHIFT ) >>PAGE_SHIFT ); -swiotlb_init_io_tlb_pool (mem,virt_to_phys (vstart), nslabs, true, +swiotlb_init_io_tlb_pool (mem,virt_to_phys (vstart), vstart, nslabs, true, nareas);add_mem_pool (&io_tlb_default_mem, mem);@@ -605,25 +605,26 @@ static struct page *alloc_dma_pages(gfp_t gfp, size_t bytes, u64 phys_limit)* @bytes: Size of the buffer. * @phys_limit: Maximum allowed physical address of the buffer. * @gfp: GFP flags for the allocation. +* @vaddr: Receives the virtual address for the allocated buffer. * * Return: Allocated pages, or %NULL on allocation failure. */ static struct page *swiotlb_alloc_tlb (struct device *dev,size_t bytes, -u64 phys_limit,gfp_t gfp) +u64 phys_limit,gfp_t gfp,void **vaddr) {struct page *page; + *vaddr =NULL ; +/* * Allocate from the atomic pools if memory is encrypted and * the allocation is atomic, because decrypting may block. */ if (!gfpflags_allow_blocking (gfp) && dev &&force_dma_unencrypted (dev)) { -void *vaddr; -if (!IS_ENABLED (CONFIG_DMA_COHERENT_POOL ))return NULL ; -return dma_alloc_from_pool (dev, bytes, &vaddr, gfp, +return dma_alloc_from_pool (dev, bytes, vaddr, gfp, dma_coherent_ok); }@@ -645,6 +646,8 @@ static struct page *swiotlb_alloc_tlb(struct device *dev, size_t bytes,return NULL ; } +if (page) + *vaddr =phys_to_virt (page_to_phys (page));return page; }@@ -685,6 +688,7 @@ static struct io_tlb_pool *swiotlb_alloc_pool(struct device *dev, {struct io_tlb_pool *pool;unsigned int slot_order; +void *tlb_vaddr;struct page *tlb;size_t pool_size;size_t tlb_size;@@ -701,7 +705,8 @@ static struct io_tlb_pool *swiotlb_alloc_pool(struct device *dev, pool->areas = (void *)pool +sizeof (*pool); tlb_size = nslabs <<IO_TLB_SHIFT ; -while (!(tlb =swiotlb_alloc_tlb (dev, tlb_size, phys_limit, gfp))) { +while (!(tlb =swiotlb_alloc_tlb (dev, tlb_size, phys_limit, gfp, + &tlb_vaddr))) {if (nslabs <= minslabs) goto error_tlb; nslabs =ALIGN (nslabs >>1 ,IO_TLB_SEGSIZE );@@ -715,11 +720,12 @@ static struct io_tlb_pool *swiotlb_alloc_pool(struct device *dev,if (!pool->slots) goto error_slots; -swiotlb_init_io_tlb_pool (pool,page_to_phys (tlb), nslabs, true, nareas); +swiotlb_init_io_tlb_pool (pool,page_to_phys (tlb), tlb_vaddr, nslabs, + true, nareas);return pool; error_slots: -swiotlb_free_tlb (page_address (tlb), tlb_size); +swiotlb_free_tlb (tlb_vaddr, tlb_size); error_tlb:kfree (pool); error:@@ -1851,7 +1857,8 @@ static int rmem_swiotlb_device_init(struct reserved_mem *rmem,set_memory_decrypted ((unsigned long )phys_to_virt (rmem->base), rmem->size >>PAGE_SHIFT ); -swiotlb_init_io_tlb_pool (pool, rmem->base, nslabs, +swiotlb_init_io_tlb_pool (pool, rmem->base,phys_to_virt (rmem->base), + nslabs, false, nareas); mem->force_bounce = true; mem->for_alloc = true;Signature · 1 line
2.43.0
PATCH v8 6/23 s390: Expose protected virtualization through cc_platform_has()
In reply to Aneesh Kumar K.V (Arm)Protected virtualization guests use memory encryption, so advertise that to the rest of the kernel through cc_platform_has(CC_ATTR_MEM_ENCRYPT).
s390 already forces DMA mappings to be unencrypted for protected virtualization guests through force_dma_unencrypted(). Add ARCH_HAS_CC_PLATFORM and provide the matching cc_platform_has() implementation
--- arch/s390/Kconfig | 1 + arch/s390/mm/init.c | 14 ++++++++++++++ 2 files changed, 15 insertions(+)
arch/s390/Kconfig +1 -0
@@ -84,6 +84,7 @@ config S390 select ARCH_ENABLE_SPLIT_PMD_PTLOCK if PGTABLE_LEVELS > 2 select ARCH_ENABLE_THP_MIGRATION if TRANSPARENT_HUGEPAGE select ARCH_HAS_CC_CAN_LINK + select ARCH_HAS_CC_PLATFORM select ARCH_HAS_CPU_FINALIZE_INIT select ARCH_HAS_CURRENT_STACK_POINTER select ARCH_HAS_DEBUG_VIRTUAL
arch/s390/mm/init.c +14 -0
@@ -50,6 +50,7 @@#include <linux/virtio_anchor.h> #include <linux/virtio_config.h> #include <linux/execmem.h> +#include <linux/cc_platform.h> pgd_t swapper_pg_dir[PTRS_PER_PGD] __section(".bss..swapper_pg_dir"); pgd_t invalid_pg_dir[PTRS_PER_PGD] __section(".bss..invalid_pg_dir");
@@ -142,6 +143,19 @@ bool force_dma_unencrypted(struct device *dev)return is_prot_virt_guest (); } + +bool cc_platform_has (enum cc_attr attr) +{ +switch (attr) { +case CC_ATTR_MEM_ENCRYPT : +return is_prot_virt_guest (); + +default : +return false; + } +} +EXPORT_SYMBOL_GPL (cc_platform_has); +/* protected virtualization */ static void __init pv_init (void ) {
Signature · 1 line
2.43.0
PATCH v8 7/23 dma-direct: swiotlb: handle swiotlb alloc/free outside __dma_direct_alloc_pages
In reply to Aneesh Kumar K.V (Arm)Move swiotlb allocation out of __dma_direct_alloc_pages() and handle it in dma_direct_alloc() / dma_direct_alloc_pages().
This is needed for follow-up changes that simplify the handling of memory encryption/decryption based on the DMA attribute flags.
swiotlb backing pages are already mapped decrypted by swiotlb_update_mem_attributes() and rmem_swiotlb_device_init(), so dma-direct should not call dma_set_decrypted() on allocation nor dma_set_encrypted() on free for swiotlb-backed memory.
Update alloc/free paths to detect swiotlb-backed pages and skip encrypt/decrypt transitions for those paths. Keep the existing highmem rejection in dma_direct_alloc_pages() for swiotlb allocations.
Only for "restricted-dma-pool", we currently set for_alloc = true, while rmem_swiotlb_device_init() decrypts the whole pool up front. This pool is typically used together with "shared-dma-pool", where the shared region is accessed after remap/ioremap and the returned address is suitable for decrypted memory access. So existing code paths remain valid.
--- include/linux/swiotlb.h | 6 ++++ kernel/dma/direct.c | 71 ++++++++++++++++++++++++++++++----------- kernel/dma/swiotlb.c | 6 ++++ 3 files changed, 65 insertions(+), 18 deletions(-)
include/linux/swiotlb.h +6 -0
@@ -284,6 +284,8 @@ extern void swiotlb_print_info(void);#ifdef CONFIG_DMA_RESTRICTED_POOL struct page *swiotlb_alloc (struct device *dev,size_t size);bool swiotlb_free (struct device *dev,struct page *page,size_t size); +void swiotlb_free_from_pool (struct device *dev, +phys_addr_t tlb_addr,struct io_tlb_pool *pool);static inline bool is_swiotlb_for_alloc (struct device *dev) {
@@ -299,6 +301,10 @@ static inline bool swiotlb_free(struct device *dev, struct page *page, {return false; } +static inline void swiotlb_free_from_pool (struct device *dev, +phys_addr_t tlb_addr,struct io_tlb_pool *pool) +{ +}static inline bool is_swiotlb_for_alloc (struct device *dev) {return false;
kernel/dma/direct.c +53 -18
160 lines not on this page · raw message
kernel/dma/swiotlb.c +6 -0
@@ -1815,6 +1815,12 @@ bool swiotlb_free(struct device *dev, struct page *page, size_t size)return true; } +void swiotlb_free_from_pool (struct device *dev, +phys_addr_t tlb_addr,struct io_tlb_pool *pool) +{ +swiotlb_release_slots (dev, tlb_addr, pool); +} +static int rmem_swiotlb_device_init (struct reserved_mem *rmem,struct device *dev) {
Signature · 1 line
2.43.0
Re: [PATCH v8 07/23] dma-direct: swiotlb: handle swiotlb alloc/free outside __dma_direct_alloc_pages
Quoted 21 lines · Aneesh Kumar K.V (Arm)
Move swiotlb allocation out of
__dma_direct_alloc_pages()and handle it indma_direct_alloc()/dma_direct_alloc_pages().This is needed for follow-up changes that simplify the handling of memory encryption/decryption based on the DMA attribute flags.
swiotlb backing pages are already mapped decrypted by
swiotlb_update_mem_attributes()andrmem_swiotlb_device_init(), so dma-direct should not calldma_set_decrypted()on allocation nordma_set_encrypted()on free for swiotlb-backed memory.Update alloc/free paths to detect swiotlb-backed pages and skip encrypt/decrypt transitions for those paths. Keep the existing highmem rejection in
dma_direct_alloc_pages()for swiotlb allocations.Only for "restricted-dma-pool", we currently set
for_alloc = true, whilermem_swiotlb_device_init()decrypts the whole pool up front. This pool is typically used together with "shared-dma-pool", where the shared region is accessed after remap/ioremap and the returned address is suitable for decrypted memory access. So existing code paths remain valid.
Quoted 5 lines
Reviewed-by Jason Gunthorpe <[email protected]>Tested-by Jiri Pirko <[email protected]>Tested-by Michael Kelley <[email protected]>Tested-by Mostafa Saleh <[email protected]>Signed-off-by Aneesh Kumar K.V (Arm) <[email protected]>
Thanks,
Mostafa
Quoted 225 lines
--- include/linux/swiotlb.h | 6 ++++ kernel/dma/direct.c | 71 ++++++++++++++++++++++++++++++----------- kernel/dma/swiotlb.c | 6 ++++ 3 files changed, 65 insertions(+), 18 deletions(-)include/linux/swiotlb.h +6
-0@@ -284,6 +284,8 @@ extern void swiotlb_print_info(void);#ifdef CONFIG_DMA_RESTRICTED_POOL struct page *swiotlb_alloc (struct device *dev,size_t size);bool swiotlb_free (struct device *dev,struct page *page,size_t size); +void swiotlb_free_from_pool (struct device *dev, +phys_addr_t tlb_addr,struct io_tlb_pool *pool);static inline bool is_swiotlb_for_alloc (struct device *dev) {@@ -299,6 +301,10 @@ static inline bool swiotlb_free(struct device *dev, struct page *page, {return false; } +static inline void swiotlb_free_from_pool (struct device *dev, +phys_addr_t tlb_addr,struct io_tlb_pool *pool) +{ +}static inline bool is_swiotlb_for_alloc (struct device *dev) {return false;kernel/dma/direct.c +53
-18@@ -96,14 +96,6 @@ static int dma_set_encrypted(struct device *dev, void *vaddr, size_t size)return ret; } -static void __dma_direct_free_pages (struct device *dev,struct page *page, -size_t size) -{ -if (swiotlb_free (dev, page, size)) -return ; -dma_free_contiguous (dev, page, size); -} -static struct page *dma_direct_alloc_swiotlb (struct device *dev,size_t size) {struct page *page =swiotlb_alloc (dev, size);@@ -125,9 +117,6 @@ static struct page *__dma_direct_alloc_pages(struct device *dev, size_t size,WARN_ON_ONCE (!PAGE_ALIGNED (size)); -if (is_swiotlb_for_alloc (dev)) -return dma_direct_alloc_swiotlb (dev, size); - gfp |=dma_direct_optimal_gfp_mask (dev, &phys_limit); page =dma_alloc_contiguous (dev, size, gfp);if (page) {@@ -203,6 +192,7 @@ void *dma_direct_alloc(struct device *dev, size_t size, dma_addr_t *dma_handle, gfp_t gfp, unsigned long attrs) { bool remap = false, set_uncached = false; +bool mark_mem_decrypt = true;struct page *page;void *ret;@@ -252,11 +242,21 @@ void *dma_direct_alloc(struct device *dev, size_t size,return page ? ret :NULL ; } +if (is_swiotlb_for_alloc (dev)) { + page =dma_direct_alloc_swiotlb (dev, size); +if (page) { + mark_mem_decrypt = false; + goto setup_page; + } +return NULL ; + } +/* we always manually zero the memory once we are done */ page =__dma_direct_alloc_pages (dev, size, gfp & ~__GFP_ZERO, true);if (!page)return NULL ; +setup_page:/* * dma_alloc_contiguous can return highmem pages depending on a * combination the cma= arguments and per-arch setup. These need to be @@ -283,7 +283,7 @@ void *dma_direct_alloc(struct device *dev, size_t size, goto out_free_pages; }else { ret =page_address (page); -if (dma_set_decrypted (dev, ret, size)) +if (mark_mem_decrypt &&dma_set_decrypted (dev, ret, size)) goto out_leak_pages; }@@ -300,10 +300,11 @@ void *dma_direct_alloc(struct device *dev, size_t size,return ret; out_encrypt_pages: -if (dma_set_encrypted (dev,page_address (page), size)) +if (mark_mem_decrypt &&dma_set_encrypted (dev,page_address (page), size))return NULL ; out_free_pages: -__dma_direct_free_pages (dev, page, size); +if (!swiotlb_free (dev, page, size)) +dma_free_contiguous (dev, page, size);return NULL ; out_leak_pages:return NULL ;@@ -312,6 +313,9 @@ void *dma_direct_alloc(struct device *dev, size_t size,void dma_direct_free (struct device *dev,size_t size,void *cpu_addr,dma_addr_t dma_addr,unsigned long attrs) { +phys_addr_t phys; +bool mark_mem_encrypted = true; +struct io_tlb_pool *swiotlb_pool;unsigned int page_order =get_order (size); if ((attrs & DMA_ATTR_NO_KERNEL_MAPPING) &&@@ -340,16 +344,25 @@ void dma_direct_free(struct device *dev, size_t size, dma_free_from_pool(dev, cpu_addr, PAGE_ALIGN(size))) return; + phys =dma_to_phys (dev, dma_addr); + swiotlb_pool =swiotlb_find_pool (dev, phys); +if (swiotlb_pool) +/* Swiotlb doesn't need a page attribute update on free */ + mark_mem_encrypted = false; +if (is_vmalloc_addr (cpu_addr)) {vunmap (cpu_addr); }else {if (IS_ENABLED (CONFIG_ARCH_HAS_DMA_CLEAR_UNCACHED ))arch_dma_clear_uncached (cpu_addr, size); -if (dma_set_encrypted (dev, cpu_addr, size)) +if (mark_mem_encrypted &&dma_set_encrypted (dev, cpu_addr, size))return ; } -__dma_direct_free_pages (dev,dma_direct_to_page (dev, dma_addr), size); +if (swiotlb_pool) +swiotlb_free_from_pool (dev, phys, swiotlb_pool); +else +dma_free_contiguous (dev,dma_direct_to_page (dev, dma_addr), size); } struct page *dma_direct_alloc_pages(struct device *dev, size_t size,@@ -361,6 +374,15 @@ struct page *dma_direct_alloc_pages(struct device *dev, size_t size,if (force_dma_unencrypted (dev) &&dma_direct_use_pool (dev, gfp))return dma_direct_alloc_from_pool (dev, size, dma_handle, &ret, gfp); +if (is_swiotlb_for_alloc (dev)) { + page =dma_direct_alloc_swiotlb (dev, size); +if (!page) +return NULL ; + + ret =page_address (page); + goto setup_page; + } + page =__dma_direct_alloc_pages (dev, size, gfp, false);if (!page)return NULL ;@@ -368,6 +390,7 @@ struct page *dma_direct_alloc_pages(struct device *dev, size_t size, ret =page_address (page);if (dma_set_decrypted (dev, ret, size)) goto out_leak_pages; +setup_page:memset (ret,0 , size); *dma_handle =phys_to_dma_direct (dev,page_to_phys (page));return page;@@ -379,16 +402,28 @@ void dma_direct_free_pages(struct device *dev, size_t size, struct page *page, dma_addr_t dma_addr, enum dma_data_direction dir) { + phys_addr_t phys;void *vaddr =page_address (page); +struct io_tlb_pool *swiotlb_pool; +bool mark_mem_encrypted = true;/* If page is not from an atomic pool, dma_free_from_pool_page() fails */ if (IS_ENABLED (CONFIG_DMA_COHERENT_POOL ) &&dma_free_from_pool_page (dev, page, size))return ; -if (dma_set_encrypted (dev, vaddr, size)) + phys =page_to_phys (page); + swiotlb_pool =swiotlb_find_pool (dev, phys); +if (swiotlb_pool) + mark_mem_encrypted = false; + +if (mark_mem_encrypted &&dma_set_encrypted (dev, vaddr, size))return ; -__dma_direct_free_pages (dev, page, size); + +if (swiotlb_pool) +swiotlb_free_from_pool (dev, phys, swiotlb_pool); +else +dma_free_contiguous (dev, page, size); } #if defined(CONFIG_ARCH_HAS_SYNC_DMA_FOR_DEVICE) || \kernel/dma/swiotlb.c +6
-0@@ -1815,6 +1815,12 @@ bool swiotlb_free(struct device *dev, struct page *page, size_t size)return true; } +void swiotlb_free_from_pool (struct device *dev, +phys_addr_t tlb_addr,struct io_tlb_pool *pool) +{ +swiotlb_release_slots (dev, tlb_addr, pool); +} +static int rmem_swiotlb_device_init (struct reserved_mem *rmem,struct device *dev) {Signature · 1 line
2.43.0
PATCH v8 8/23 coco: arm64: s390: powerpc: Mark secure guests with CC_ATTR_GUEST_MEM_ENCRYPT
In reply to Aneesh Kumar K.V (Arm)arm64 Realms, powerpc secure guests and s390 protected virtualization guests currently report CC_ATTR_MEM_ENCRYPT, but not CC_ATTR_GUEST_MEM_ENCRYPT.
These environments are all secure guest configurations. Their force_dma_unencrypted() implementations also treat the same secure guest state as requiring unencrypted DMA. Report CC_ATTR_GUEST_MEM_ENCRYPT for the same condition so generic confidential-computing code can distinguish guest memory encryption from host memory encryption instead of relying only on CC_ATTR_MEM_ENCRYPT.
--- arch/arm64/mm/init.c | 1 + arch/powerpc/platforms/pseries/cc_platform.c | 1 + arch/s390/mm/init.c | 1 + 3 files changed, 3 insertions(+)
arch/arm64/mm/init.c +1 -0
@@ -419,6 +419,7 @@ bool cc_platform_has(enum cc_attr attr) {switch (attr) {case CC_ATTR_MEM_ENCRYPT : +case CC_ATTR_GUEST_MEM_ENCRYPT :return is_realm_world () ||is_protected_kvm_guest ();default :return false;
arch/powerpc/platforms/pseries/cc_platform.c +1 -0
@@ -17,6 +17,7 @@ bool cc_platform_has(enum cc_attr attr) {switch (attr) {case CC_ATTR_MEM_ENCRYPT : +case CC_ATTR_GUEST_MEM_ENCRYPT :return is_secure_guest ();default :
arch/s390/mm/init.c +1 -0
@@ -148,6 +148,7 @@ bool cc_platform_has(enum cc_attr attr) {switch (attr) {case CC_ATTR_MEM_ENCRYPT : +case CC_ATTR_GUEST_MEM_ENCRYPT :return is_prot_virt_guest ();default :
Signature · 1 line
2.43.0
PATCH v8 9/23 dma-mapping: Add internal shared allocation attribute
In reply to Aneesh Kumar K.V (Arm)DMA_ATTR_CC_SHARED describes an existing DMA mapping whose backing memory is already shared, or decrypted, for confidential computing. It is a mapping attribute: callers use it to request a shared DMA address encoding for memory that has already been prepared for shared DMA.
Allocation paths need a related but different state. Once the DMA core decides that an allocation must use shared backing pages, the lower-level allocation helpers need to select shared pools, decrypt newly allocated pages, derive the DMA address with the shared-memory translation and restore encryption on free. That state is internal to the DMA-mapping implementation and should not be passed by drivers to dma_alloc_attrs().
--- Documentation/core-api/dma-attributes.rst | 29 +++++++++++++++++++++++ include/linux/dma-mapping.h | 8 +++++++ include/trace/events/dma.h | 3 ++- 3 files changed, 39 insertions(+), 1 deletion(-)
Documentation/core-api/dma-attributes.rst +29 -0
@@ -179,3 +179,32 @@ interface when building their uAPIs, when possible. It must never be used in an in-kernel driver that only works with kernel memory. + +DMA_ATTR_CC_SHARED +------------------ + +This attribute indicates that a DMA mapping is shared, or decrypted, for +confidential computing guests. For normal system memory, the caller must +already have marked the memory decrypted with set_memory_decrypted(). CPU +PTEs for the mapping must use pgprot_decrypted(), and the same shared +semantic may be passed to a vIOMMU when it sets up the IOPTE. + +This attribute describes an existing mapping. It does not allocate shared +backing pages and must not be passed to dma_alloc_attrs(). For MMIO, use +this together with DMA_ATTR_MMIO to indicate shared MMIO. Unless +DMA_ATTR_MMIO is provided, the mapping requires a struct page. + +__DMA_ATTR_ALLOC_CC_SHARED +-------------------------- + +This is an internal DMA-mapping attribute for confidential computing guests. +It is used by allocation paths after the DMA core has determined that the +backing pages must be shared, or decrypted. For example, the direct DMA and +SWIOTLB allocation paths use it to select shared DMA pools, decrypt newly +allocated pages, derive DMA addresses using the shared-memory translation, and +restore encryption on free. + +__DMA_ATTR_ALLOC_CC_SHARED differs from DMA_ATTR_CC_SHARED in that it is not +a caller-visible DMA API attribute. DMA_ATTR_CC_SHARED describes an +already-shared mapping and requires the caller to have prepared normal +system memory before mapping it.
include/linux/dma-mapping.h +8 -0
@@ -103,6 +103,14 @@*/ #define DMA_ATTR_CC_SHARED (1UL << 13) +/* +* __DMA_ATTR_ALLOC_CC_SHARED: Internal DMA-mapping attribute used by +* allocation paths that create shared (decrypted) backing pages for +* confidential computing guests. Drivers must not pass this attribute to +* dma_alloc_attrs(). +*/ +#define __DMA_ATTR_ALLOC_CC_SHARED (1UL << 14) +/* * A dma_addr_t can hold any valid DMA or bus address for the platform. It can * be given to a device to use as a DMA source or target. It is specific to a
include/trace/events/dma.h +2 -1
@@ -35,7 +35,8 @@ TRACE_DEFINE_ENUM(DMA_NONE); { DMA_ATTR_MMIO, "MMIO" }, \ { DMA_ATTR_DEBUGGING_IGNORE_CACHELINES, "CACHELINES_OVERLAP" }, \ { DMA_ATTR_REQUIRE_COHERENT, "REQUIRE_COHERENT" }, \ - { DMA_ATTR_CC_SHARED, "CC_SHARED" }) + { DMA_ATTR_CC_SHARED, "CC_SHARED" }, \ + { __DMA_ATTR_ALLOC_CC_SHARED, "ALLOC_CC_SHARED" }) DECLARE_EVENT_CLASS(dma_map, TP_PROTO(struct device *dev, phys_addr_t phys_addr, dma_addr_t dma_addr,
Signature · 1 line
2.43.0
Re: [PATCH v8 09/23] dma-mapping: Add internal shared allocation attribute
Quoted 12 lines · Aneesh Kumar K.V (Arm)
DMA_ATTR_CC_SHAREDdescribes an existing DMA mapping whose backing memory is already shared, or decrypted, for confidential computing. It is a mapping attribute: callers use it to request a shared DMA address encoding for memory that has already been prepared for shared DMA.Allocation paths need a related but different state. Once the DMA core decides that an allocation must use shared backing pages, the lower-level allocation helpers need to select shared pools, decrypt newly allocated pages, derive the DMA address with the shared-memory translation and restore encryption on free. That state is internal to the DMA-mapping implementation and should not be passed by drivers to
dma_alloc_attrs().
Quoted 2 lines
Reviewed-by Jason Gunthorpe <[email protected]>Signed-off-by Aneesh Kumar K.V (Arm) <[email protected]>
Thanks,
Mostafa
Quoted 79 lines
--- Documentation/core-api/dma-attributes.rst | 29 +++++++++++++++++++++++ include/linux/dma-mapping.h | 8 +++++++ include/trace/events/dma.h | 3 ++- 3 files changed, 39 insertions(+), 1 deletion(-)Documentation/core-api/dma-attributes.rst +29
-0@@ -179,3 +179,32 @@ interface when building their uAPIs, when possible. It must never be used in an in-kernel driver that only works with kernel memory. + +DMA_ATTR_CC_SHARED +------------------ + +This attribute indicates that a DMA mapping is shared, or decrypted, for +confidential computing guests. For normal system memory, the caller must +already have marked the memory decrypted with set_memory_decrypted(). CPU +PTEs for the mapping must use pgprot_decrypted(), and the same shared +semantic may be passed to a vIOMMU when it sets up the IOPTE. + +This attribute describes an existing mapping. It does not allocate shared +backing pages and must not be passed to dma_alloc_attrs(). For MMIO, use +this together with DMA_ATTR_MMIO to indicate shared MMIO. Unless +DMA_ATTR_MMIO is provided, the mapping requires a struct page. + +__DMA_ATTR_ALLOC_CC_SHARED +-------------------------- + +This is an internal DMA-mapping attribute for confidential computing guests. +It is used by allocation paths after the DMA core has determined that the +backing pages must be shared, or decrypted. For example, the direct DMA and +SWIOTLB allocation paths use it to select shared DMA pools, decrypt newly +allocated pages, derive DMA addresses using the shared-memory translation, and +restore encryption on free. + +__DMA_ATTR_ALLOC_CC_SHARED differs from DMA_ATTR_CC_SHARED in that it is not +a caller-visible DMA API attribute. DMA_ATTR_CC_SHARED describes an +already-shared mapping and requires the caller to have prepared normal +system memory before mapping it.include/linux/dma-mapping.h +8
-0@@ -103,6 +103,14 @@*/ #define DMA_ATTR_CC_SHARED (1UL << 13) +/* +* __DMA_ATTR_ALLOC_CC_SHARED: Internal DMA-mapping attribute used by +* allocation paths that create shared (decrypted) backing pages for +* confidential computing guests. Drivers must not pass this attribute to +* dma_alloc_attrs(). +*/ +#define __DMA_ATTR_ALLOC_CC_SHARED (1UL << 14) +/* * A dma_addr_t can hold any valid DMA or bus address for the platform. It can * be given to a device to use as a DMA source or target. It is specific to a include/trace/events/dma.h +2
-1@@ -35,7 +35,8 @@ TRACE_DEFINE_ENUM(DMA_NONE); { DMA_ATTR_MMIO, "MMIO" }, \ { DMA_ATTR_DEBUGGING_IGNORE_CACHELINES, "CACHELINES_OVERLAP" }, \ { DMA_ATTR_REQUIRE_COHERENT, "REQUIRE_COHERENT" }, \ - { DMA_ATTR_CC_SHARED, "CC_SHARED" }) + { DMA_ATTR_CC_SHARED, "CC_SHARED" }, \ + { __DMA_ATTR_ALLOC_CC_SHARED, "ALLOC_CC_SHARED" }) DECLARE_EVENT_CLASS(dma_map, TP_PROTO(struct device *dev, phys_addr_t phys_addr, dma_addr_t dma_addr,Signature · 1 line
2.43.0
PATCH v8 10/23 dma-direct: use __DMA_ATTR_ALLOC_CC_SHARED in alloc/free paths
In reply to Aneesh Kumar K.V (Arm)Propagate force_dma_unencrypted() into __DMA_ATTR_ALLOC_CC_SHARED in the dma-direct allocation path and use the attribute to drive the related decisions.
This updates dma_direct_alloc(), dma_direct_free(), and dma_direct_alloc_pages() to fold the forced unencrypted case into attrs.
--- kernel/dma/direct.c | 42 +++++++++++++++++++++++++++++++++--------- kernel/dma/mapping.c | 9 +++++++++ 2 files changed, 42 insertions(+), 9 deletions(-)
kernel/dma/direct.c +33 -9
@@ -192,16 +192,22 @@ void *dma_direct_alloc(struct device *dev, size_t size, dma_addr_t *dma_handle, gfp_t gfp, unsigned long attrs) { bool remap = false, set_uncached = false; -bool mark_mem_decrypt = true; +bool mark_mem_decrypt = false;struct page *page;void *ret; +if (force_dma_unencrypted (dev)) + attrs |= __DMA_ATTR_ALLOC_CC_SHARED; + +if (attrs & __DMA_ATTR_ALLOC_CC_SHARED) + mark_mem_decrypt = true; + size =PAGE_ALIGN (size);if (attrs &DMA_ATTR_NO_WARN ) gfp |= __GFP_NOWARN; -if ((attrs &DMA_ATTR_NO_KERNEL_MAPPING ) && - !force_dma_unencrypted (dev) && !is_swiotlb_for_alloc (dev)) +if (((attrs & (DMA_ATTR_NO_KERNEL_MAPPING | __DMA_ATTR_ALLOC_CC_SHARED)) == +DMA_ATTR_NO_KERNEL_MAPPING ) && !is_swiotlb_for_alloc (dev))return dma_direct_alloc_no_mapping (dev, size, dma_handle, gfp);if (!dev_is_dma_coherent (dev)) {
@@ -235,7 +241,7 @@ void *dma_direct_alloc(struct device *dev, size_t size,* Remapping or decrypting memory may block, allocate the memory from * the atomic pools instead if we aren't allowed block. */ -if ((remap ||force_dma_unencrypted (dev)) && +if ((remap || (attrs & __DMA_ATTR_ALLOC_CC_SHARED)) &&dma_direct_use_pool (dev, gfp)) { page =dma_direct_alloc_from_pool (dev, size, dma_handle, &ret, gfp);
@@ -314,12 +320,22 @@ void dma_direct_free(struct device *dev, size_t size, void *cpu_addr, dma_addr_t dma_addr, unsigned long attrs) { phys_addr_t phys; -bool mark_mem_encrypted = true; +bool mark_mem_encrypted = false;struct io_tlb_pool *swiotlb_pool;unsigned int page_order =get_order (size); -if ((attrs &DMA_ATTR_NO_KERNEL_MAPPING ) && - !force_dma_unencrypted (dev) && !is_swiotlb_for_alloc (dev)) { +/* +* If the allocation used decrypted/shared backing pages, restore +* the encryption state on free. +*/ +if (force_dma_unencrypted (dev)) + attrs |= __DMA_ATTR_ALLOC_CC_SHARED; + +if (attrs & __DMA_ATTR_ALLOC_CC_SHARED) + mark_mem_encrypted = true; + +if (((attrs & (DMA_ATTR_NO_KERNEL_MAPPING | __DMA_ATTR_ALLOC_CC_SHARED)) == +DMA_ATTR_NO_KERNEL_MAPPING ) && !is_swiotlb_for_alloc (dev)) {/* cpu_addr is a struct page cookie, not a kernel address */ dma_free_contiguous (dev, cpu_addr, size);return ;
@@ -368,10 +384,14 @@ void dma_direct_free(struct device *dev, size_t size,struct page *dma_direct_alloc_pages (struct device *dev,size_t size,dma_addr_t *dma_handle,enum dma_data_direction dir,gfp_t gfp) { +unsigned long attrs =0 ;struct page *page;void *ret; -if (force_dma_unencrypted (dev) &&dma_direct_use_pool (dev, gfp)) +if (force_dma_unencrypted (dev)) + attrs |= __DMA_ATTR_ALLOC_CC_SHARED; + +if ((attrs & __DMA_ATTR_ALLOC_CC_SHARED) &&dma_direct_use_pool (dev, gfp))return dma_direct_alloc_from_pool (dev, size, dma_handle, &ret, gfp);if (is_swiotlb_for_alloc (dev)) {
@@ -405,7 +425,11 @@ void dma_direct_free_pages(struct device *dev, size_t size,phys_addr_t phys;void *vaddr =page_address (page);struct io_tlb_pool *swiotlb_pool; -bool mark_mem_encrypted = true; +/* +* if the device had requested for an unencrypted buffer, +* convert it to encrypted on free +*/ +bool mark_mem_encrypted =force_dma_unencrypted (dev);/* If page is not from an atomic pool, dma_free_from_pool_page() fails */ if (IS_ENABLED(CONFIG_DMA_COHERENT_POOL) &&
kernel/dma/mapping.c +9 -0
@@ -638,6 +638,15 @@ void *dma_alloc_attrs(struct device *dev, size_t size, dma_addr_t *dma_handle,if (WARN_ON_ONCE (flag & __GFP_COMP))return NULL ; +if (attrs & (DMA_ATTR_CC_SHARED | __DMA_ATTR_ALLOC_CC_SHARED)) { +trace_dma_alloc (dev,NULL ,0 , size,DMA_BIDIRECTIONAL , flag, + attrs); +return NULL ; + } + +if (force_dma_unencrypted (dev)) + attrs |= __DMA_ATTR_ALLOC_CC_SHARED; +if (dma_alloc_from_dev_coherent (dev, size, dma_handle, &cpu_addr)) {trace_dma_alloc (dev, cpu_addr, *dma_handle, size,DMA_BIDIRECTIONAL , flag, attrs);
Signature · 1 line
2.43.0
PATCH v8 11/23 dma-pool: track decrypted atomic pools and select them via attrs
In reply to Aneesh Kumar K.V (Arm)Teach the atomic DMA pool code to distinguish between encrypted and unencrypted pools, and make pool allocation select the matching pool based on DMA attributes.
Introduce a dma_gen_pool wrapper that records whether a pool is unencrypted, initialize that state when the atomic pools are created, and use it when expanding and resizing the pools. Update dma_alloc_from_pool() to take attrs and skip pools whose encrypted state does not match __DMA_ATTR_ALLOC_CC_SHARED. Update dma_free_from_pool() accordingly.
Also pass __DMA_ATTR_ALLOC_CC_SHARED from the swiotlb atomic allocation path so decrypted swiotlb allocations are taken from the correct atomic pool.
--- drivers/iommu/dma-iommu.c | 7 +- include/linux/dma-map-ops.h | 2 +- kernel/dma/direct.c | 14 ++- kernel/dma/pool.c | 182 +++++++++++++++++++++++------------- kernel/dma/swiotlb.c | 8 +- 5 files changed, 139 insertions(+), 74 deletions(-)
drivers/iommu/dma-iommu.c +6 -1
@@ -1660,9 +1660,14 @@ void *iommu_dma_alloc(struct device *dev, size_t size, dma_addr_t *handle, {bool coherent =dev_is_dma_coherent (dev);int ioprot =dma_info_to_prot (DMA_BIDIRECTIONAL , coherent, attrs); +bool is_alloc_cc_shared = attrs & __DMA_ATTR_ALLOC_CC_SHARED;struct page *page =NULL ;void *cpu_addr; +/* Not yet supported */ +if (is_alloc_cc_shared) +return NULL ; + gfp |= __GFP_ZERO; if (gfpflags_allow_blocking(gfp) &&
@@ -1673,7 +1678,7 @@ void *iommu_dma_alloc(struct device *dev, size_t size, dma_addr_t *handle,if (IS_ENABLED (CONFIG_DMA_DIRECT_REMAP ) && !gfpflags_allow_blocking (gfp) && !coherent) { page =dma_alloc_from_pool (dev,PAGE_ALIGN (size), &cpu_addr, - gfp,NULL ); + gfp, attrs,NULL );if (!page)return NULL ; }else {
include/linux/dma-map-ops.h +1 -1
@@ -212,7 +212,7 @@ void *dma_common_pages_remap(struct page **pages, size_t size, pgprot_t prot,void dma_common_free_remap (void *cpu_addr,size_t size);struct page *dma_alloc_from_pool (struct device *dev,size_t size, -void **cpu_addr,gfp_t flags, +void **cpu_addr,gfp_t flags,unsigned long attrs,bool (*phys_addr_ok)(struct device *,phys_addr_t ,size_t ));bool dma_free_from_pool (struct device *dev,void *start,size_t size);bool dma_free_from_pool_page (struct device *dev,struct page *page,size_t size);
kernel/dma/direct.c +10 -4
@@ -154,7 +154,8 @@ static bool dma_direct_use_pool(struct device *dev, gfp_t gfp) }static struct page *dma_direct_alloc_from_pool (struct device *dev,size_t size, -dma_addr_t *dma_handle,void **cpu_addr,gfp_t gfp) +dma_addr_t *dma_handle,void **cpu_addr,gfp_t gfp, +unsigned long attrs) {struct page *page;u64 phys_limit;
@@ -163,7 +164,8 @@ static struct page *dma_direct_alloc_from_pool(struct device *dev, size_t size,return NULL ; gfp |=dma_direct_optimal_gfp_mask (dev, &phys_limit); - page =dma_alloc_from_pool (dev, size, cpu_addr, gfp, dma_coherent_ok); + page =dma_alloc_from_pool (dev, size, cpu_addr, gfp, attrs, + dma_coherent_ok);if (!page)return NULL ; *dma_handle =phys_to_dma_direct (dev,page_to_phys (page));
@@ -240,11 +242,14 @@ void *dma_direct_alloc(struct device *dev, size_t size,/* * Remapping or decrypting memory may block, allocate the memory from * the atomic pools instead if we aren't allowed block. +* FIXME: With CONFIG_DMA_DIRECT_REMAP, the pool is also mapped as +* DMA-coherent (non-cacheable). We may want to create a separate pool +* dedicated to CC_SHARED atomic allocations. */ if ((remap || (attrs & __DMA_ATTR_ALLOC_CC_SHARED)) &&dma_direct_use_pool (dev, gfp)) { page =dma_direct_alloc_from_pool (dev, size, dma_handle, - &ret, gfp); + &ret, gfp, attrs);return page ? ret :NULL ; }
@@ -392,7 +397,8 @@ struct page *dma_direct_alloc_pages(struct device *dev, size_t size, attrs |= __DMA_ATTR_ALLOC_CC_SHARED;if ((attrs & __DMA_ATTR_ALLOC_CC_SHARED) &&dma_direct_use_pool (dev, gfp)) -return dma_direct_alloc_from_pool (dev, size, dma_handle, &ret, gfp); +return dma_direct_alloc_from_pool (dev, size, dma_handle, + &ret, gfp, attrs);if (is_swiotlb_for_alloc (dev)) { page =dma_direct_alloc_swiotlb (dev, size);
kernel/dma/pool.c +116 -66
321 lines not on this page · raw message
kernel/dma/swiotlb.c +6 -2
@@ -613,9 +613,9 @@ static struct page *swiotlb_alloc_tlb(struct device *dev, size_t bytes, u64 phys_limit, gfp_t gfp, void **vaddr) { struct page *page; +unsigned long attrs =0 ; *vaddr =NULL ; -/* * Allocate from the atomic pools if memory is encrypted and * the allocation is atomic, because decrypting may block.
@@ -624,8 +624,12 @@ static struct page *swiotlb_alloc_tlb(struct device *dev, size_t bytes,if (!IS_ENABLED (CONFIG_DMA_COHERENT_POOL ))return NULL ; +/* swiotlb considered decrypted by default */ +if (cc_platform_has (CC_ATTR_MEM_ENCRYPT )) + attrs = __DMA_ATTR_ALLOC_CC_SHARED; +return dma_alloc_from_pool (dev, bytes, vaddr, gfp, - dma_coherent_ok); + attrs, dma_coherent_ok); } gfp &= ~GFP_ZONEMASK ;
Signature · 1 line
2.43.0
PATCH v8 12/23 dma: swiotlb: pass mapping attributes by reference
In reply to Aneesh Kumar K.V (Arm)Change swiotlb_tbl_map_single() to take the DMA mapping attributes by reference and update the direct callers accordingly.
This is a preparatory change for a follow-up patch which updates the attributes based on the selected swiotlb pool. Keeping the signature change separate makes the follow-up patch easier to review.
No functional change in this patch.
--- drivers/iommu/dma-iommu.c | 2 +- drivers/xen/swiotlb-xen.c | 2 +- include/linux/swiotlb.h | 2 +- kernel/dma/swiotlb.c | 6 +++--- 4 files changed, 6 insertions(+), 6 deletions(-)
drivers/iommu/dma-iommu.c +1 -1
@@ -1180,7 +1180,7 @@ static phys_addr_t iommu_dma_map_swiotlb(struct device *dev, phys_addr_t phys,trace_swiotlb_bounced (dev, phys, size); phys =swiotlb_tbl_map_single (dev, phys, size,iova_mask (iovad), dir, - attrs); + &attrs);/* * Untrusted devices should not see padding areas with random leftover
drivers/xen/swiotlb-xen.c +1 -1
@@ -243,7 +243,7 @@ static dma_addr_t xen_swiotlb_map_phys(struct device *dev, phys_addr_t phys,*/ trace_swiotlb_bounced (dev, dev_addr, size); - map =swiotlb_tbl_map_single (dev, phys, size,0 , dir, attrs); + map =swiotlb_tbl_map_single (dev, phys, size,0 , dir, &attrs);if (map == (phys_addr_t )DMA_MAPPING_ERROR )return DMA_MAPPING_ERROR ;
include/linux/swiotlb.h +1 -1
@@ -238,7 +238,7 @@ static inline phys_addr_t default_swiotlb_limit(void)phys_addr_t swiotlb_tbl_map_single (struct device *hwdev,phys_addr_t phys,size_t mapping_size,unsigned int alloc_aligned_mask, -enum dma_data_direction dir,unsigned long attrs); +enum dma_data_direction dir,unsigned long *attrs);dma_addr_t swiotlb_map (struct device *dev,phys_addr_t phys,size_t size,enum dma_data_direction dir,unsigned long attrs);
kernel/dma/swiotlb.c +3 -3
@@ -1396,7 +1396,7 @@ static unsigned long mem_used(struct io_tlb_mem *mem)*/ phys_addr_t swiotlb_tbl_map_single (struct device *dev,phys_addr_t orig_addr,size_t mapping_size,unsigned int alloc_align_mask, -enum dma_data_direction dir,unsigned long attrs) +enum dma_data_direction dir,unsigned long *attrs) {struct io_tlb_mem *mem = dev->dma_io_tlb_mem;unsigned int offset;
@@ -1430,7 +1430,7 @@ phys_addr_t swiotlb_tbl_map_single(struct device *dev, phys_addr_t orig_addr, size =ALIGN (mapping_size + offset, alloc_align_mask +1 ); index =swiotlb_find_slots (dev, orig_addr, size, alloc_align_mask, &pool);if (index ==-1 ) { -if (!(attrs &DMA_ATTR_NO_WARN )) +if (!(*attrs &DMA_ATTR_NO_WARN ))dev_warn_ratelimited (dev,"swiotlb buffer is full (sz: %zd bytes), total %lu (slots), used %lu (slots)\n" , size, mem->nslabs,mem_used (mem));
@@ -1609,7 +1609,7 @@ dma_addr_t swiotlb_map(struct device *dev, phys_addr_t paddr, size_t size,trace_swiotlb_bounced (dev,phys_to_dma (dev, paddr), size); - swiotlb_addr =swiotlb_tbl_map_single (dev, paddr, size,0 , dir, attrs); + swiotlb_addr =swiotlb_tbl_map_single (dev, paddr, size,0 , dir, &attrs);if (swiotlb_addr == (phys_addr_t )DMA_MAPPING_ERROR )return DMA_MAPPING_ERROR ;
Signature · 1 line
2.43.0
Re: [PATCH v8 12/23] dma: swiotlb: pass mapping attributes by reference
Quoted 7 lines · Aneesh Kumar K.V (Arm)
Change
swiotlb_tbl_map_single()to take the DMA mapping attributes by reference and update the direct callers accordingly.This is a preparatory change for a follow-up patch which updates the attributes based on the selected swiotlb pool. Keeping the signature change separate makes the follow-up patch easier to review.
I do not understand the point of this, why would swiotlb_tbl_map_single() force attrs over the caller which should already know the context (whether DMA is shared or not) which case would this be useful to force from the SWIOTLB code?
Thanks,
Mostafa
Quoted 87 lines
No functional change in this patch.
Reviewed-by Jason Gunthorpe <[email protected]>Tested-by Michael Kelley <[email protected]>Tested-by Mostafa Saleh <[email protected]>Reviewed-by Petr Tesarik <[email protected]>Signed-off-by Aneesh Kumar K.V (Arm) <[email protected]>--- drivers/iommu/dma-iommu.c | 2 +- drivers/xen/swiotlb-xen.c | 2 +- include/linux/swiotlb.h | 2 +- kernel/dma/swiotlb.c | 6 +++--- 4 files changed, 6 insertions(+), 6 deletions(-)drivers/iommu/dma-iommu.c +1
-1@@ -1180,7 +1180,7 @@ static phys_addr_t iommu_dma_map_swiotlb(struct device *dev, phys_addr_t phys,trace_swiotlb_bounced (dev, phys, size); phys =swiotlb_tbl_map_single (dev, phys, size,iova_mask (iovad), dir, - attrs); + &attrs);/* * Untrusted devices should not see padding areas with random leftover drivers/xen/swiotlb-xen.c +1
-1@@ -243,7 +243,7 @@ static dma_addr_t xen_swiotlb_map_phys(struct device *dev, phys_addr_t phys,*/ trace_swiotlb_bounced (dev, dev_addr, size); - map =swiotlb_tbl_map_single (dev, phys, size,0 , dir, attrs); + map =swiotlb_tbl_map_single (dev, phys, size,0 , dir, &attrs);if (map == (phys_addr_t )DMA_MAPPING_ERROR )return DMA_MAPPING_ERROR ;include/linux/swiotlb.h +1
-1@@ -238,7 +238,7 @@ static inline phys_addr_t default_swiotlb_limit(void)phys_addr_t swiotlb_tbl_map_single (struct device *hwdev,phys_addr_t phys,size_t mapping_size,unsigned int alloc_aligned_mask, -enum dma_data_direction dir,unsigned long attrs); +enum dma_data_direction dir,unsigned long *attrs);dma_addr_t swiotlb_map (struct device *dev,phys_addr_t phys,size_t size,enum dma_data_direction dir,unsigned long attrs);kernel/dma/swiotlb.c +3
-3@@ -1396,7 +1396,7 @@ static unsigned long mem_used(struct io_tlb_mem *mem)*/ phys_addr_t swiotlb_tbl_map_single (struct device *dev,phys_addr_t orig_addr,size_t mapping_size,unsigned int alloc_align_mask, -enum dma_data_direction dir,unsigned long attrs) +enum dma_data_direction dir,unsigned long *attrs) {struct io_tlb_mem *mem = dev->dma_io_tlb_mem;unsigned int offset;@@ -1430,7 +1430,7 @@ phys_addr_t swiotlb_tbl_map_single(struct device *dev, phys_addr_t orig_addr, size =ALIGN (mapping_size + offset, alloc_align_mask +1 ); index =swiotlb_find_slots (dev, orig_addr, size, alloc_align_mask, &pool);if (index ==-1 ) { -if (!(attrs &DMA_ATTR_NO_WARN )) +if (!(*attrs &DMA_ATTR_NO_WARN ))dev_warn_ratelimited (dev,"swiotlb buffer is full (sz: %zd bytes), total %lu (slots), used %lu (slots)\n" , size, mem->nslabs,mem_used (mem));@@ -1609,7 +1609,7 @@ dma_addr_t swiotlb_map(struct device *dev, phys_addr_t paddr, size_t size,trace_swiotlb_bounced (dev,phys_to_dma (dev, paddr), size); - swiotlb_addr =swiotlb_tbl_map_single (dev, paddr, size,0 , dir, attrs); + swiotlb_addr =swiotlb_tbl_map_single (dev, paddr, size,0 , dir, &attrs);if (swiotlb_addr == (phys_addr_t )DMA_MAPPING_ERROR )return DMA_MAPPING_ERROR ;Signature · 1 line
2.43.0
Re: [PATCH v8 12/23] dma: swiotlb: pass mapping attributes by reference
Quoted 9 lines · Mostafa Saleh
Quoted 7 lines · Aneesh Kumar K.V (Arm)
Change
swiotlb_tbl_map_single()to take the DMA mapping attributes by reference and update the direct callers accordingly.This is a preparatory change for a follow-up patch which updates the attributes based on the selected swiotlb pool. Keeping the signature change separate makes the follow-up patch easier to review.
Quoted 5 lines
I do not understand the point of this, why would
swiotlb_tbl_map_single()force attrs over the caller which should already know the context (whether DMA is shared or not) which case would this be useful to force from the SWIOTLB code?
The mapping request was for private memory, but the device could not use it because the dma_capable() (force_dma_unencrypted() == true) check failed. As a result, dma_direct_map_phys() allocated a swiotlb bounce buffer, which is shared. Since the DMA now targets the shared bounce buffer rather than the original private memory, the attributes must be updated to reflect the new shared mapping.
dma_addr = phys_to_dma(dev, phys);
if (unlikely(!dma_capable(dev, dma_addr, size, true)))
if (is_swiotlb_active(dev)) return swiotlb_map(dev, phys, size, dir, attrs);
-aneesh
Re: [PATCH v8 12/23] dma: swiotlb: pass mapping attributes by reference
Quoted 24 lines · Aneesh Kumar K.V
Quoted 9 lines · Mostafa Saleh
Quoted 7 lines · Aneesh Kumar K.V (Arm)
Change
swiotlb_tbl_map_single()to take the DMA mapping attributes by reference and update the direct callers accordingly.This is a preparatory change for a follow-up patch which updates the attributes based on the selected swiotlb pool. Keeping the signature change separate makes the follow-up patch easier to review.
Quoted 5 lines
I do not understand the point of this, why would
swiotlb_tbl_map_single()force attrs over the caller which should already know the context (whether DMA is shared or not) which case would this be useful to force from the SWIOTLB code?The mapping request was for private memory, but the device could not use it because the
dma_capable()(force_dma_unencrypted()== true) check failed. As a result,dma_direct_map_phys()allocated a swiotlb bounce buffer, which is shared. Since the DMA now targets the shared bounce buffer rather than the original private memory, the attributes must be updated to reflect the new shared mapping.
Quoted 6 lines
dma_addr=phys_to_dma(dev, phys);
if (unlikely(!dma_capable(dev, dma_addr, size, true)))if (is_swiotlb_active(dev)) return swiotlb_map(dev, phys, size, dir, attrs);
But it does not make sense to me to have it in such a low level function, and it shouldn't change the attrs that was passed.
dma_direct_map_phys() is the right place to do this it should set the correct attrs before calling swiotlb_map().
Thanks,
Mostafa
Quoted 1 line
-aneesh
Re: [PATCH v8 12/23] dma: swiotlb: pass mapping attributes by reference
Quoted 32 lines · Mostafa Saleh
Quoted 24 lines · Aneesh Kumar K.V
Quoted 9 lines · Mostafa Saleh
Quoted 7 lines · Aneesh Kumar K.V (Arm)
Change
swiotlb_tbl_map_single()to take the DMA mapping attributes by reference and update the direct callers accordingly.This is a preparatory change for a follow-up patch which updates the attributes based on the selected swiotlb pool. Keeping the signature change separate makes the follow-up patch easier to review.
Quoted 5 lines
I do not understand the point of this, why would
swiotlb_tbl_map_single()force attrs over the caller which should already know the context (whether DMA is shared or not) which case would this be useful to force from the SWIOTLB code?The mapping request was for private memory, but the device could not use it because the
dma_capable()(force_dma_unencrypted()== true) check failed. As a result,dma_direct_map_phys()allocated a swiotlb bounce buffer, which is shared. Since the DMA now targets the shared bounce buffer rather than the original private memory, the attributes must be updated to reflect the new shared mapping.Quoted 6 lines
dma_addr=phys_to_dma(dev, phys);
if (unlikely(!dma_capable(dev, dma_addr, size, true)))if (is_swiotlb_active(dev)) return swiotlb_map(dev, phys, size, dir, attrs);
Quoted 6 lines
But it does not make sense to me to have it in such a low level function, and it shouldn't change the attrs that was passed.
dma_direct_map_phys()is the right place to do this it should set the correct attrs before callingswiotlb_map().
There is a possibility that we may support io_tlb_mem with cc_shared = false in the future. As a result, only swiotlb_map() knows which type of bounce buffer was used, making it the only place where the attributes can be updated correctly.
-aneesh
Re: [PATCH v8 12/23] dma: swiotlb: pass mapping attributes by reference
Quoted 4 lines · Aneesh Kumar K.V
There is a possibility that we may support
io_tlb_memwithcc_shared= false in the future. As a result, onlyswiotlb_map()knows which type of bounce buffer was used, making it the only place where the attributes can be updated correctly.
Yeah, +1, the attribute should be changed at the same effective place the source memory is changed away from what the DMA API user provided. Only the thing providing the new memory (eg swiotlb) should know its properties.
Jason
Re: [PATCH v8 12/23] dma: swiotlb: pass mapping attributes by reference
Quoted 10 lines · Jason Gunthorpe
Quoted 4 lines · Aneesh Kumar K.V
There is a possibility that we may support
io_tlb_memwithcc_shared= false in the future. As a result, onlyswiotlb_map()knows which type of bounce buffer was used, making it the only place where the attributes can be updated correctly.Yeah, +1, the attribute should be changed at the same effective place the source memory is changed away from what the DMA API user provided. Only the thing providing the new memory (eg swiotlb) should know its properties.
I will keep the conversation here instead of 2 threads.
That seems like a big leap, I'd be worried about devices that operate on confidential data that should not be shared/decrypted.
One example for this which exists in pKVM (this part is not upstream yet) is non coherent devices that require bouncing but they still want to keep the data private. In that case ideally they get an encrypted SWIOTLB pool, but it's always better to fail than to use a decrypted pool behind it's back.
I have not been following the work on T=1/T=0 devices, but IIRC, they required some complexity to handle their stage-2 as these modes will be emulated differently (for CCA, RMM vs untrusted host). I was thinking that it might be easier to represent those to the guest kernel as 2 separate devices (bounded to different groups...) where one is trusted and the other is not, and that way the DMA-API can have strict rules about memory sharing.
Otherwise, SWIOTLB does not seem like the right place to me, as it does not understand the context the device is operating in, and the DMA-API should deduce that from the flags passed.
Thanks,
Mostafa
Quoted 2 lines
Jason
Re: [PATCH v8 12/23] dma: swiotlb: pass mapping attributes by reference
Quoted 12 lines · Mostafa Saleh
Quoted 10 lines · Jason Gunthorpe
Quoted 4 lines · Aneesh Kumar K.V
There is a possibility that we may support
io_tlb_memwithcc_shared= false in the future. As a result, onlyswiotlb_map()knows which type of bounce buffer was used, making it the only place where the attributes can be updated correctly.Yeah, +1, the attribute should be changed at the same effective place the source memory is changed away from what the DMA API user provided. Only the thing providing the new memory (eg swiotlb) should know its properties.
Quoted 4 lines
I will keep the conversation here instead of 2 threads.
That seems like a big leap, I'd be worried about devices that operate on confidential data that should not be shared/decrypted.
That seems like something very differnt.
Quoted 5 lines
One example for this which exists in pKVM (this part is not upstream yet) is non coherent devices that require bouncing but they still want to keep the data private. In that case ideally they get an encrypted SWIOTLB pool, but it's always better to fail than to use a decrypted pool behind it's back.
We don't have any API for a DMA API caller to signal 'must be confidential'. If we want to add one it would be a flag to check before changing the physical address in swiotlb.
As defined today the DMA API expressly copies from private to shared memory, that is baked into it's design and not a bug.
My expectation is all these cases have to be solved by setting up the swiotlb properly so it provides suitable bounce buffers. Yes, this means we will eventually need both private and shared swiotlb pools.
Quoted 7 lines
I have not been following the work on T=1/T=0 devices, but IIRC, they required some complexity to handle their stage-2 as these modes will be emulated differently (for CCA, RMM vs untrusted host). I was thinking that it might be easier to represent those to the guest kernel as 2 separate devices (bounded to different groups...) where one is trusted and the other is not, and that way the DMA-API can have strict rules about memory sharing.
No way! That's would be a giant disaster for the driver model.
Each struct device will have a flag that shows if it is in T=1 or T=0 state. The flag can only change while a driver is not bound, and changing the flag will update the DMA API configuration.
A T=1 device should have the same issue as you point out for pkvm, it really needs to have a private SWIOTLB pool.
Quoted 3 lines
Otherwise, SWIOTLB does not seem like the right place to me, as it does not understand the context the device is operating in, and the DMA-API should deduce that from the flags passed.
It is exactly the right place because it is the one supplying the new memory. Context is irrelevant, the flag only describes what the new memory actually *IS*, and swiotlb knows 100% if the new memory is shared or private.
For your issue it would be appropriate to add a debugging check that the new memory is not incompatible with the expected policy. eg a T=1 device getting decrypted swiotlb memory is a bug in swiotlb setup that should be caught. But that's a debugging check, we expect the swiotlb to have selected the right kind of memory by construction. This isn't done yet since this series doesn't even yet support a T=1 device..
Jason
Robin Murphy
maintainerRe: [PATCH v8 12/23] dma: swiotlb: pass mapping attributes by reference
Quoted 45 lines · Jason Gunthorpe
Quoted 12 lines · Mostafa Saleh
Quoted 10 lines · Jason Gunthorpe
Quoted 4 lines · Aneesh Kumar K.V
There is a possibility that we may support
io_tlb_memwithcc_shared= false in the future. As a result, onlyswiotlb_map()knows which type of bounce buffer was used, making it the only place where the attributes can be updated correctly.Yeah, +1, the attribute should be changed at the same effective place the source memory is changed away from what the DMA API user provided. Only the thing providing the new memory (eg swiotlb) should know its properties.
Quoted 4 lines
I will keep the conversation here instead of 2 threads.
That seems like a big leap, I'd be worried about devices that operate on confidential data that should not be shared/decrypted.
That seems like something very differnt.
Quoted 5 lines
One example for this which exists in pKVM (this part is not upstream yet) is non coherent devices that require bouncing but they still want to keep the data private. In that case ideally they get an encrypted SWIOTLB pool, but it's always better to fail than to use a decrypted pool behind it's back.
We don't have any API for a DMA API caller to signal 'must be confidential'. If we want to add one it would be a flag to check before changing the physical address in swiotlb.
As defined today the DMA API expressly copies from private to shared memory, that is baked into it's design and not a bug.
My expectation is all these cases have to be solved by setting up the swiotlb properly so it provides suitable bounce buffers. Yes, this means we will eventually need both private and shared swiotlb pools.
Quoted 7 lines
I have not been following the work on T=1/T=0 devices, but IIRC, they required some complexity to handle their stage-2 as these modes will be emulated differently (for CCA, RMM vs untrusted host). I was thinking that it might be easier to represent those to the guest kernel as 2 separate devices (bounded to different groups...) where one is trusted and the other is not, and that way the DMA-API can have strict rules about memory sharing.
Quoted 5 lines
No way! That's would be a giant disaster for the driver model.
Each struct device will have a flag that shows if it is in T=1 or T=0 state. The flag can only change while a driver is not bound, and changing the flag will update the DMA API configuration.
I see we no longer seem to have the concern of devices in TDISP RUN state being able to send T=0 transactions other than MSI writes, where GICv3 means the host is already going to have to be in on the game to some degree there anyway. There could still be a potential concern of other non-PCIe equivalents wanting such a thing, though. However, even then we don't have support in firmware bindings nor the IOMMU API itself to be able to describe a single device being associated with both the RMM's vSMMU for the T=1 (Realm) VA space, and the NS VMM's vSMMU for the T=0 VA space, even if we did only have to care about using strictly one or the other at any given time based on device state. Having distinct struct devices is indeed clunky, but does at least reduce the problem to a currently-manageable one of the client driver having to wrangle them as a pair. Note that there are other such hardware properties that may also differ between states, such as ITS frames when we do get GICv5, so in fact having separate descriptions of the "shared" and "private" aspects of a device, based on their respective MMIO address aliases, may not be entirely unreasonable for CCA - making OSes understand that seems like it might be easier than having to reinvent swathes of ACPI and Devicetree bindings (and then still having to make OSes understand *those*).
Quoted 2 lines
A T=1 device should have the same issue as you point out for pkvm, it really needs to have a private SWIOTLB pool.
Yes, once device_cc_accepted() is true then we *must not* inadvertently share any DMA buffers, if the caller has not explicitly requested CC_SHARED (tying in to the XT use-case), otherwise we'd be breaking the end-to-end confidentiality that TDISP/IDE/etc. is all about. So until we do have an additional private SWIOTLB, we will have to just fail mappings for an accepted device which would otherwise want bouncing due to DMA mask or alignment limitations.
(And FWIW when we do get there, I'd be inclined to make the default SWIOTLB the "private" one, so all the sharing/decryption stuff can be neatly partitioned off into the CoCo etc. special cases...)
Thanks,
Robin.
Quoted 17 lines
Quoted 3 lines
Otherwise, SWIOTLB does not seem like the right place to me, as it does not understand the context the device is operating in, and the DMA-API should deduce that from the flags passed.
It is exactly the right place because it is the one supplying the new memory. Context is irrelevant, the flag only describes what the new memory actually *IS*, and swiotlb knows 100% if the new memory is shared or private.
For your issue it would be appropriate to add a debugging check that the new memory is not incompatible with the expected policy. eg a T=1 device getting decrypted swiotlb memory is a bug in swiotlb setup that should be caught. But that's a debugging check, we expect the swiotlb to have selected the right kind of memory by construction. This isn't done yet since this series doesn't even yet support a T=1 device..
Jason
Re: [PATCH v8 12/23] dma: swiotlb: pass mapping attributes by reference
Quoted 6 lines · Robin Murphy
Quoted 3 lines
Each struct device will have a flag that shows if it is in T=1 or T=0 state. The flag can only change while a driver is not bound, and changing the flag will update the DMA API configuration.
I see we no longer seem to have the concern of devices in TDISP RUN state being able to send T=0 transactions other than MSI writes,
Right it was too complex and nobody needed it, so Linux will not support T=0 through the DMA API on an T=1 device, and devices should be designed to only send T=1 to the greatest degree possible.
If someone foolishly makes a device that works otherwise they will have to take the difficult SW tasks of making it work.
Quoted 2 lines
where GICv3 means the host is already going to have to be in on the game to some degree there anyway.
As I understand it:
We will need to teach GIC to understand if/when the device uses a T=0 translation for MSI and then use a shared physical address for the ITS IOVA instead of getting an IOVA translation from the iommu. The hypervisor will setup the S2 for the T=0 SMMU translation to be identity with all shared memory and the ITS page will be shared memory.
Presumably in future we will have HW to handle a T=1 ITS page access and some way to negotiate with devices if they should use a T=1 path for MSI or not.
There won't be a vSMMU attached to the T=0 instance at all, it is just wired to be bypass.
Quoted 4 lines
support in firmware bindings nor the IOMMU API itself to be able to describe a single device being associated with both the RMM's vSMMU for the T=1 (Realm) VA space, and the NS VMM's vSMMU for the T=0 VA space, even if we
Right!
Quoted 4 lines
did only have to care about using strictly one or the other at any given time based on device state. Having distinct struct devices is indeed clunky, but does at least reduce the problem to a currently-manageable one of the client driver having to wrangle them as a pair.
So hard! A meaningful goal here is to have existing drivers largely work unchanged in a CC world, so the device starts doing T=1 for almost everything and the existing driver just works.
Quoted 3 lines
(And FWIW when we do get there, I'd be inclined to make the default SWIOTLB the "private" one, so all the sharing/decryption stuff can be neatly partitioned off into the CoCo etc. special cases...)
Yeah
Jason
Robin Murphy
maintainerRe: [PATCH v8 12/23] dma: swiotlb: pass mapping attributes by reference
Quoted 18 lines · Jason Gunthorpe
Quoted 6 lines · Robin Murphy
Quoted 3 lines
Each struct device will have a flag that shows if it is in T=1 or T=0 state. The flag can only change while a driver is not bound, and changing the flag will update the DMA API configuration.
I see we no longer seem to have the concern of devices in TDISP RUN state being able to send T=0 transactions other than MSI writes,
Right it was too complex and nobody needed it, so Linux will not support T=0 through the DMA API on an T=1 device, and devices should be designed to only send T=1 to the greatest degree possible.
If someone foolishly makes a device that works otherwise they will have to take the difficult SW tasks of making it work.
Quoted 2 lines
where GICv3 means the host is already going to have to be in on the game to some degree there anyway.
Quoted 8 lines
As I understand it:
We will need to teach GIC to understand if/when the device uses a T=0 translation for MSI and then use a shared physical address for the ITS IOVA instead of getting an IOVA translation from the iommu. The hypervisor will setup the S2 for the T=0 SMMU translation to be identity with all shared memory and the ITS page will be shared memory.
IIRC, for MSI or unlocked MSI-X it should look and work pretty much exactly like regular VFIO, as everything can be mediated by the VMM and host kernel.
Quoted 3 lines
Presumably in future we will have HW to handle a T=1 ITS page access and some way to negotiate with devices if they should use a T=1 path for MSI or not.
Locked MSI-X would be a pain right now as we cannot intercept the Realm programming the MSI-X cap with a doorbell address and EventID value decided by the ITS driver in the Realm guest, so we'd somehow have to sniff those values out of the VMM's vITS emulation then try to configure an equivalent NS LPI to match, or have a hook in the ITS driver that knows when it's in a Realm and do some RSI handshake to proxy-allocate NS MSI vectors on the host and pass the real values back into the Realm.
I'm still hoping we (both CCA and possibly Linux in general) can get away with just refusing to support Locked MSI-X without GICv5, as once we have proper Realm MSIs with direct injection then all the problems go away (or at least become much smaller RMM problems that remain invisible to the host - the one "big" problem being that the RMM has to begrudgingly implement an entire GIC driver since it now has its own whole GIC to look after).
Quoted 2 lines
There won't be a vSMMU attached to the T=0 instance at all, it is just wired to be bypass.
If that's all anyone will ever want then it does allow some degree of hackery like mirroring the whole of Realm S2 in an equivalent NS IOMMUFD domain, then forcing IOMMU_DOMAIN_IDENTITY for unaccepted devices within the guest. However I was under the impression that folks want to make meaningful use of devices while still in their untrusted pre-acceptance state (but maybe still switch them later), so it seems almost inevitable that eventually someone says "actually, we would like S1 vSMMU for untrusted scatter-gather as well..."
Quoted 7 lines
Quoted 4 lines
support in firmware bindings nor the IOMMU API itself to be able to describe a single device being associated with both the RMM's vSMMU for the T=1 (Realm) VA space, and the NS VMM's vSMMU for the T=0 VA space, even if we
Right!
Quoted 8 lines
Quoted 4 lines
did only have to care about using strictly one or the other at any given time based on device state. Having distinct struct devices is indeed clunky, but does at least reduce the problem to a currently-manageable one of the client driver having to wrangle them as a pair.
So hard! A meaningful goal here is to have existing drivers largely work unchanged in a CC world, so the device starts doing T=1 for almost everything and the existing driver just works.
Agreed, and I think with this series we should be pretty close now, at least for coherent devices with 64-bit DMA masks. And from the thread over at [1], it sounds like Hyper-V's VMbus is ready to go as potentially our first user independent of any other PCI/TSM dependencies.
Cheers,
Robin.
[1] https://lore.kernel.org/all/[email protected]/
Quoted 8 lines
Quoted 4 lines
(And FWIW when we do get there, I'd be inclined to make the default SWIOTLB the "private" one, so all the sharing/decryption stuff can be neatly partitioned off into the CoCo etc. special cases...)
Yeah
Jason
Re: [PATCH v8 12/23] dma: swiotlb: pass mapping attributes by reference
Quoted 9 lines · Robin Murphy
Quoted 6 lines
We will need to teach GIC to understand if/when the device uses a T=0 translation for MSI and then use a shared physical address for the ITS IOVA instead of getting an IOVA translation from the iommu. The hypervisor will setup the S2 for the T=0 SMMU translation to be identity with all shared memory and the ITS page will be shared memory.
IIRC, for MSI or unlocked MSI-X it should look and work pretty much exactly like regular VFIO, as everything can be mediated by the VMM and host kernel.
Right
Quoted 11 lines
Quoted 3 lines
Presumably in future we will have HW to handle a T=1 ITS page access and some way to negotiate with devices if they should use a T=1 path for MSI or not.
Locked MSI-X would be a pain right now as we cannot intercept the Realm programming the MSI-X cap with a doorbell address and EventID value decided by the ITS driver in the Realm guest, so we'd somehow have to sniff those values out of the VMM's vITS emulation then try to configure an equivalent NS LPI to match, or have a hook in the ITS driver that knows when it's in a Realm and do some RSI handshake to proxy-allocate NS MSI vectors on the host and pass the real values back into the Realm.
Yes, we'd need to move to a model where the guest programs MSI directly and we learn the configuration required to emulate through the vGIC, not through MSI trapping. This broadly is the "righter" way to do interrupt routing but it will be hard to get there, if ever.
Quoted 6 lines
I'm still hoping we (both CCA and possibly Linux in general) can get away with just refusing to support Locked MSI-X without GICv5, as once we have proper Realm MSIs with direct injection then all the problems go away (or at least become much smaller RMM problems that remain invisible to the host - the one "big" problem being that the RMM has to begrudgingly implement an entire GIC driver since it now has its own whole GIC to look after).
Yeah, I'm fine with this, if GICv5 can allow direct MSI-X programming then great.
Devices are going to need some way to negotiate if MSI-X is locked, and if MSI is T=1 or not, I don't know if PCI has something for that already..
Quoted 11 lines
Quoted 2 lines
There won't be a vSMMU attached to the T=0 instance at all, it is just wired to be bypass.
If that's all anyone will ever want then it does allow some degree of hackery like mirroring the whole of Realm S2 in an equivalent NS IOMMUFD domain, then forcing
IOMMU_DOMAIN_IDENTITYfor unaccepted devices within the guest. However I was under the impression that folks want to make meaningful use of devices while still in their untrusted pre-acceptance state (but maybe still switch them later), so it seems almost inevitable that eventually someone says "actually, we would like S1 vSMMU for untrusted scatter-gather as well..."
So far almost all VMs today don't use vIOMMU at all, the ones that do are using it for things like PASID (or interrupt remapping on x86), not for translation. The cases where a vIOMMU is deliberately needed for translation seem to be mostly around SVA and PASID which isn't going to meaningfully work out of the box on a T=0 device.
My prediction is this is fine.
At least it is sufficiently hard to make two parallel vSMMU's controlling the same PCI device, and to make the ITS routing also somehow work right, that it isn't worth doing at this point when there is so much other more basic stuff to get done.
I imagine the ACPI might someday gain a description of the T=0 vSMMU in a way that is invisible to todays Linux and a future Linux could understand how to juggle the two iommu drivers for the same struct device, somehow.
Regards,
Jason
Robin Murphy
maintainerRe: [PATCH v8 12/23] dma: swiotlb: pass mapping attributes by reference
Quoted 63 lines · Jason Gunthorpe
Quoted 9 lines · Robin Murphy
Quoted 6 lines
We will need to teach GIC to understand if/when the device uses a T=0 translation for MSI and then use a shared physical address for the ITS IOVA instead of getting an IOVA translation from the iommu. The hypervisor will setup the S2 for the T=0 SMMU translation to be identity with all shared memory and the ITS page will be shared memory.
IIRC, for MSI or unlocked MSI-X it should look and work pretty much exactly like regular VFIO, as everything can be mediated by the VMM and host kernel.
Right
Quoted 11 lines
Quoted 3 lines
Presumably in future we will have HW to handle a T=1 ITS page access and some way to negotiate with devices if they should use a T=1 path for MSI or not.
Locked MSI-X would be a pain right now as we cannot intercept the Realm programming the MSI-X cap with a doorbell address and EventID value decided by the ITS driver in the Realm guest, so we'd somehow have to sniff those values out of the VMM's vITS emulation then try to configure an equivalent NS LPI to match, or have a hook in the ITS driver that knows when it's in a Realm and do some RSI handshake to proxy-allocate NS MSI vectors on the host and pass the real values back into the Realm.
Yes, we'd need to move to a model where the guest programs MSI directly and we learn the configuration required to emulate through the vGIC, not through MSI trapping. This broadly is the "righter" way to do interrupt routing but it will be hard to get there, if ever.
Quoted 6 lines
I'm still hoping we (both CCA and possibly Linux in general) can get away with just refusing to support Locked MSI-X without GICv5, as once we have proper Realm MSIs with direct injection then all the problems go away (or at least become much smaller RMM problems that remain invisible to the host - the one "big" problem being that the RMM has to begrudgingly implement an entire GIC driver since it now has its own whole GIC to look after).
Yeah, I'm fine with this, if GICv5 can allow direct MSI-X programming then great.
Devices are going to need some way to negotiate if MSI-X is locked, and if MSI is T=1 or not, I don't know if PCI has something for that already..
Quoted 11 lines
Quoted 2 lines
There won't be a vSMMU attached to the T=0 instance at all, it is just wired to be bypass.
If that's all anyone will ever want then it does allow some degree of hackery like mirroring the whole of Realm S2 in an equivalent NS IOMMUFD domain, then forcing
IOMMU_DOMAIN_IDENTITYfor unaccepted devices within the guest. However I was under the impression that folks want to make meaningful use of devices while still in their untrusted pre-acceptance state (but maybe still switch them later), so it seems almost inevitable that eventually someone says "actually, we would like S1 vSMMU for untrusted scatter-gather as well..."So far almost all VMs today don't use vIOMMU at all, the ones that do are using it for things like PASID (or interrupt remapping on x86), not for translation. The cases where a vIOMMU is deliberately needed for translation seem to be mostly around SVA and PASID which isn't going to meaningfully work out of the box on a T=0 device.
Quoted 6 lines
My prediction is this is fine.
At least it is sufficiently hard to make two parallel vSMMU's controlling the same PCI device, and to make the ITS routing also somehow work right, that it isn't worth doing at this point when there is so much other more basic stuff to get done.
Cool. So in fact that puts us in an interesting position for now where non-CoCo "untrusted" (i.e. external) devices should have IOMMU translation forced on by default, while CoCo "unaccepted" devices (i.e. those which do have a mechanism to transition into a T=1 or equivalent state) should *not* try to use an associated IOMMU, on the assumption that it may only work for T=1 traffic. All the more reason to sort these abstractions out so we can make the right distinctions clearly :)
(And while untrusted vIOMMUs for purely-untrusted devices in CoCo environments would be pretty straightforward as well, I guess we might need some sort of acceptance status for trusted vIOMMU devices themselves? Hmm...)
Cheers,
Robin.
Quoted 7 lines
I imagine the ACPI might someday gain a description of the T=0 vSMMU in a way that is invisible to todays Linux and a future Linux could understand how to juggle the two iommu drivers for the same struct device, somehow.
Regards,
Jason
Re: [PATCH v8 12/23] dma: swiotlb: pass mapping attributes by reference
Quoted 7 lines · Robin Murphy
Cool. So in fact that puts us in an interesting position for now where non-CoCo "untrusted" (i.e. external) devices should have IOMMU translation forced on by default, while CoCo "unaccepted" devices (i.e. those which do have a mechanism to transition into a T=1 or equivalent state) should *not* try to use an associated IOMMU, on the assumption that it may only work for T=1 traffic. All the more reason to sort these abstractions out so we can make the right distinctions clearly :)
I think the guest flow works out fairly logically:
1) At boot the IOMMU core always setups blocking translation. No more auto-attaching paging or identity domains at probe time [optional, but default on for CC guest]
* This means devices that can have their DMA disabled do
* Additionally T=1 capable devices have their T=1 DMA blocked by the CC platform itself. eg RMM is to leave the T=1 STE set to blocking at VM boot until commanded otherwise.
Aside from CC this also goes hand in hand with DRTM support in the kernel where we do want to carry over the DMA access block from the secure launch until the system, ideally via userspace policy, has approved the device.
2) Before probing a driver we synchronize the TDISP state, IOMMU and configure the DMA API:
a. If no iommu, then DMA API is in physical
b. If both device and IOMMU same-T then DMA API follows IOMMU configuration:
- DMA API is physical if IOMMU configuration is identity
- DMA API is dma-iomu if paging
- IOMMU sets the proper domain for the DMA API, removes the blocking
c. If device and iommu have different T state then assume no iommu
and DMA API is physical
2b) For T=1 capable devices this is the moment we tell the CC platform
to permit DMA
3) The DMA API configuration follows per-device flags:
- Using IOMMU: Use dma-iommu not physical
- Using T=0/1: Replaces 'force dma unencrypted'. Ie T=0 uses swiotlb to get CC shared memory.
- adversarial: Replaces pdev->trusted/etc. Causes IOMMU and SWIOTLB to bounce buffer partial pages.
Causes iommu to prefer paging not identity.
4) After removing a driver we restore the IOMMU back to blocking. The CC platform is told to block DMA again, if it can.
If we ever do decide to support dual iommu then #2 would be the point we swap the iommu control between the T=0/1 iommu.
Quoted 4 lines
(And while untrusted vIOMMUs for purely-untrusted devices in CoCo environments would be pretty straightforward as well, I guess we might need some sort of acceptance status for trusted vIOMMU devices themselves? Hmm...)
That should fall into the overall plan for device acceptance. We want the kernel to have a small policy of devices it would accept prior to the initrd. Untrusted versions of iommu (and others) should not auto probe.
The initrd can then decide if it wants to probe the untrusted iommu. Probably it does not right now since we haven't done any security analysis on the SMMUv3 being operated by a hostile hypervisor. ARM should be OK here, a modular SMMUv3 will achieve this trivially. x86 will have a harder time.
Userspace will run its acceptance flow and figure out what drivers to bind. Along the way userspace will record what it is accepting in a measurement log.
So, lots of little steps along the path. I imagine various series something like:
- Basic version of #1 and #2 to generally defer opening DMA till probe
- TSM APIs to support setting T=1 and doing the evidence suff
- T=1 flag for devices supported by IOMMU and DMA API, replacing force dma unencrypted
- Userspace driven policy control over device binding
- General trust level concept, including an "adversarial" trust level which will trigger various auto configuration and mitigations
- tsm_mr improvmements
- adversarial T=1 devices, eg SWIOTLB still bounce buffers but has to support a private pool
Regards,
Jason
PATCH v8 13/23 dma: swiotlb: track pool encryption state and honor DMA_ATTR_CC_SHARED
In reply to Aneesh Kumar K.V (Arm)Teach swiotlb to distinguish between encrypted and decrypted bounce buffer pools, and make allocation and mapping paths select a pool whose state matches the requested DMA attributes.
Add a cc_shared flag to io_tlb_mem, initialize it for the default and restricted pools, and propagate __DMA_ATTR_ALLOC_CC_SHARED into swiotlb pool allocation. Reject swiotlb alloc/map requests when the selected pool does not match the required encrypted/decrypted state.
Also return DMA addresses with the matching phys_to_dma_{encrypted, unencrypted} helper so the DMA address encoding stays consistent with the chosen pool.
--- include/linux/dma-direct.h | 10 +++ include/linux/swiotlb.h | 10 ++- kernel/dma/direct.c | 13 ++- kernel/dma/swiotlb.c | 177 ++++++++++++++++++++++++++++--------- 4 files changed, 162 insertions(+), 48 deletions(-)
include/linux/dma-direct.h +10 -0
@@ -77,6 +77,10 @@ static inline dma_addr_t dma_range_map_max(const struct bus_dma_region *map)#ifndef phys_to_dma_unencrypted#define phys_to_dma_unencrypted phys_to_dma#endif + +#ifndef phys_to_dma_encrypted +#define phys_to_dma_encrypted phys_to_dma +#endif #else static inline dma_addr_t __phys_to_dma (struct device *dev,phys_addr_t paddr) {
@@ -90,6 +94,12 @@ static inline dma_addr_t phys_to_dma_unencrypted(struct device *dev, {return dma_addr_unencrypted (__phys_to_dma (dev, paddr)); } + +static inline dma_addr_t phys_to_dma_encrypted (struct device *dev, +phys_addr_t paddr) +{ +return dma_addr_encrypted (__phys_to_dma (dev, paddr)); +}/* * If memory encryption is supported, phys_to_dma will set the memory encryption * bit in the DMA address, and dma_to_phys will clear it.
include/linux/swiotlb.h +8 -2
@@ -66,6 +66,7 @@ extern void __init swiotlb_update_mem_attributes(void);* @node: Member of the IO TLB memory pool list. * @rcu: RCU head for swiotlb_dyn_free(). * @transient: %true if transient memory pool. +* @cc_shared: %true if the pool memory is shared for confidential computing. */ struct io_tlb_pool {phys_addr_t start;
@@ -81,6 +82,7 @@ struct io_tlb_pool {struct list_head node;struct rcu_head rcu;bool transient; +bool cc_shared;#endif };
@@ -92,6 +94,7 @@ struct io_tlb_pool {* @debugfs: The dentry to debugfs. * @force_bounce: %true if swiotlb bouncing is forced * @for_alloc: %true if the pool is used for memory allocation +* @cc_shared: %true if the pool memory is shared for confidential computing. * @can_grow: %true if more pools can be allocated dynamically. * @phys_limit: Maximum allowed physical address. * @lock: Lock to synchronize changes to the list.
@@ -111,6 +114,7 @@ struct io_tlb_mem {struct dentry *debugfs;bool force_bounce;bool for_alloc; +bool cc_shared;#ifdef CONFIG_SWIOTLB_DYNAMIC bool can_grow;u64 phys_limit;
@@ -282,7 +286,8 @@ static inline void swiotlb_sync_single_for_cpu(struct device *dev,extern void swiotlb_print_info (void );#ifdef CONFIG_DMA_RESTRICTED_POOL -struct page *swiotlb_alloc (struct device *dev,size_t size); +struct page *swiotlb_alloc (struct device *dev,size_t size, +unsigned long attrs);bool swiotlb_free (struct device *dev,struct page *page,size_t size);void swiotlb_free_from_pool (struct device *dev,phys_addr_t tlb_addr,struct io_tlb_pool *pool);
@@ -292,7 +297,8 @@ static inline bool is_swiotlb_for_alloc(struct device *dev) return dev->dma_io_tlb_mem->for_alloc; }#else -static inline struct page *swiotlb_alloc (struct device *dev,size_t size) +static inline struct page *swiotlb_alloc (struct device *dev,size_t size, +unsigned long attrs) {return NULL ; }
kernel/dma/direct.c +9 -4
@@ -96,9 +96,10 @@ static int dma_set_encrypted(struct device *dev, void *vaddr, size_t size)return ret; } -static struct page *dma_direct_alloc_swiotlb (struct device *dev,size_t size) +static struct page *dma_direct_alloc_swiotlb (struct device *dev,size_t size, +unsigned long attrs) { -struct page *page =swiotlb_alloc (dev, size); +struct page *page =swiotlb_alloc (dev, size, attrs);if (page && !dma_coherent_ok (dev,page_to_phys (page), size)) {swiotlb_free (dev, page, size);
@@ -254,8 +255,12 @@ void *dma_direct_alloc(struct device *dev, size_t size, }if (is_swiotlb_for_alloc (dev)) { - page =dma_direct_alloc_swiotlb (dev, size); + page =dma_direct_alloc_swiotlb (dev, size, attrs);if (page) { +/* +* swiotlb allocations comes from pool already marked +* decrypted +*/ mark_mem_decrypt = false; goto setup_page; }
@@ -401,7 +406,7 @@ struct page *dma_direct_alloc_pages(struct device *dev, size_t size, &ret, gfp, attrs);if (is_swiotlb_for_alloc (dev)) { - page =dma_direct_alloc_swiotlb (dev, size); + page =dma_direct_alloc_swiotlb (dev, size, attrs);if (!page)return NULL ;
kernel/dma/swiotlb.c +135 -42
407 lines not on this page · raw message
Signature · 1 line
2.43.0
PATCH v8 14/23 dma-mapping: make dma_pgprot() honor __DMA_ATTR_ALLOC_CC_SHARED
In reply to Aneesh Kumar K.V (Arm)Fold encrypted/decrypted pgprot selection into dma_pgprot() so callers do not need to adjust the page protection separately.
Update dma_pgprot() to apply pgprot_decrypted() when DMA_ATTR_CC_SHARED or __DMA_ATTR_ALLOC_CC_SHARED is set and pgprot_encrypted() otherwise Convert the dma-direct mmap paths to pass DMA_ATTR_CC_SHARED instead of open-coding force_dma_unencrypted() handling around dma_pgprot().
--- kernel/dma/direct.c | 8 +++----- kernel/dma/mapping.c | 16 ++++++++++++---- 2 files changed, 15 insertions(+), 9 deletions(-)
kernel/dma/direct.c +3 -5
@@ -286,9 +286,6 @@ void *dma_direct_alloc(struct device *dev, size_t size,if (remap) {pgprot_t prot =dma_pgprot (dev,PAGE_KERNEL , attrs); -if (force_dma_unencrypted (dev)) - prot =pgprot_decrypted (prot); -/* remove any dirty cache lines on the kernel alias */ arch_dma_prep_coherent (page, size);
@@ -607,9 +604,10 @@ int dma_direct_mmap(struct device *dev, struct vm_area_struct *vma,unsigned long pfn =PHYS_PFN (dma_to_phys (dev, dma_addr));int ret = -ENXIO ; - vma->vm_page_prot =dma_pgprot (dev, vma->vm_page_prot, attrs);if (force_dma_unencrypted (dev)) - vma->vm_page_prot =pgprot_decrypted (vma->vm_page_prot); + attrs |=DMA_ATTR_CC_SHARED ; + + vma->vm_page_prot =dma_pgprot (dev, vma->vm_page_prot, attrs);if (dma_mmap_from_dev_coherent (dev, vma, cpu_addr, size, &ret))return ret;
kernel/dma/mapping.c +12 -4
@@ -537,13 +537,21 @@ EXPORT_SYMBOL(dma_get_sgtable_attrs);*/ pgprot_t dma_pgprot (struct device *dev,pgprot_t prot,unsigned long attrs) { +pgprot_t dma_prot; +if (dev_is_dma_coherent (dev)) -return prot; + dma_prot = prot;#ifdef CONFIG_ARCH_HAS_DMA_WRITE_COMBINE -if (attrs &DMA_ATTR_WRITE_COMBINE ) -return pgprot_writecombine (prot); + else if (attrs & DMA_ATTR_WRITE_COMBINE) + dma_prot =pgprot_writecombine (prot);#endif -return pgprot_dmacoherent (prot); + else + dma_prot =pgprot_dmacoherent (prot); + +if (attrs & (DMA_ATTR_CC_SHARED | __DMA_ATTR_ALLOC_CC_SHARED)) +return pgprot_decrypted (dma_prot); +else +return pgprot_encrypted (dma_prot); }#endif /* CONFIG_MMU */
Signature · 1 line
2.43.0
PATCH v8 15/23 dma-direct: pass attrs to dma_capable() for DMA_ATTR_CC_SHARED checks
In reply to Aneesh Kumar K.V (Arm)Teach dma_capable() about DMA_ATTR_CC_SHARED so the capability check can reject encrypted DMA addresses for devices that require unencrypted/shared DMA.
Also propagate DMA_ATTR_CC_SHARED in swiotlb_map() when the selected SWIOTLB pool is decrypted so the capability check sees the correct DMA address attribute.
--- arch/x86/kernel/amd_gart_64.c | 30 ++++++++++++++++-------------- drivers/xen/swiotlb-xen.c | 6 +++--- include/linux/dma-direct.h | 10 +++++++++- kernel/dma/direct.h | 6 +++--- kernel/dma/swiotlb.c | 2 +- 5 files changed, 32 insertions(+), 22 deletions(-)
arch/x86/kernel/amd_gart_64.c +16 -14
@@ -180,22 +180,23 @@ static void iommu_full(struct device *dev, size_t size, int dir) }static inline int -need_iommu (struct device *dev,unsigned long addr,size_t size) +need_iommu (struct device *dev,unsigned long addr,size_t size,unsigned long attrs) { -return force_iommu || !dma_capable (dev, addr, size, true); +return force_iommu || !dma_capable (dev, addr, size, true, attrs); }static inline int -nonforced_iommu (struct device *dev,unsigned long addr,size_t size) +nonforced_iommu (struct device *dev,unsigned long addr,size_t size, +unsigned long attrs) { -return !dma_capable (dev, addr, size, true); +return !dma_capable (dev, addr, size, true, attrs); }/* Map a single continuous physical area into the IOMMU. * Caller needs to check if the iommu is needed and flush. */ static dma_addr_t dma_map_area (struct device *dev,dma_addr_t phys_mem, -size_t size,int dir,unsigned long align_mask) +size_t size,int dir,unsigned long align_mask,unsigned long attrs) {unsigned long npages =iommu_num_pages (phys_mem, size,PAGE_SIZE );unsigned long iommu_page;
@@ -206,7 +207,7 @@ static dma_addr_t dma_map_area(struct device *dev, dma_addr_t phys_mem, iommu_page =alloc_iommu (dev, npages, align_mask);if (iommu_page ==-1 ) { -if (!nonforced_iommu (dev, phys_mem, size)) +if (!nonforced_iommu (dev, phys_mem, size, attrs))return phys_mem;if (panic_on_overflow)panic ("dma_map_area overflow %lu bytes\n" , size);
@@ -231,10 +232,10 @@ static dma_addr_t gart_map_phys(struct device *dev, phys_addr_t paddr,if (unlikely (attrs &DMA_ATTR_MMIO ))return DMA_MAPPING_ERROR ; -if (!need_iommu (dev, paddr, size)) +if (!need_iommu (dev, paddr, size, attrs))return paddr; - bus =dma_map_area (dev, paddr, size, dir,0 ); + bus =dma_map_area (dev, paddr, size, dir,0 , attrs);flush_gart ();return bus;
@@ -289,7 +290,7 @@ static void gart_unmap_sg(struct device *dev, struct scatterlist *sg, int nents,/* Fallback for dma_map_sg in case of overflow */ static int dma_map_sg_nonforce (struct device *dev,struct scatterlist *sg, -int nents,int dir) +int nents,int dir,unsigned long attrs) {struct scatterlist *s;int i;
@@ -301,8 +302,8 @@ static int dma_map_sg_nonforce(struct device *dev, struct scatterlist *sg,for_each_sg (sg, s, nents, i) {unsigned long addr =sg_phys (s); -if (nonforced_iommu (dev, addr, s->length)) { - addr =dma_map_area (dev, addr, s->length, dir,0 ); +if (nonforced_iommu (dev, addr, s->length, attrs)) { + addr =dma_map_area (dev, addr, s->length, dir,0 , attrs);if (addr ==DMA_MAPPING_ERROR ) {if (i >0 )gart_unmap_sg (dev, sg, i, dir,0 );
@@ -401,7 +402,7 @@ static int gart_map_sg(struct device *dev, struct scatterlist *sg, int nents, s->dma_address = addr;BUG_ON (s->length ==0 ); - nextneed =need_iommu (dev, addr, s->length); + nextneed =need_iommu (dev, addr, s->length, attrs);/* Handle the previous not yet processed entries */ if (i > start) {
@@ -449,7 +450,7 @@ static int gart_map_sg(struct device *dev, struct scatterlist *sg, int nents,/* When it was forced or merged try again in a dumb way */ if (force_iommu || iommu_merge) { - out =dma_map_sg_nonforce (dev, sg, nents, dir); + out =dma_map_sg_nonforce (dev, sg, nents, dir, attrs);if (out >0 )return out; }
@@ -473,7 +474,8 @@ gart_alloc_coherent(struct device *dev, size_t size, dma_addr_t *dma_addr,return vaddr; *dma_addr =dma_map_area (dev,virt_to_phys (vaddr), size, -DMA_BIDIRECTIONAL , (1UL <<get_order (size)) -1 ); +DMA_BIDIRECTIONAL , + (1UL <<get_order (size)) -1 , attrs);flush_gart ();if (unlikely (*dma_addr ==DMA_MAPPING_ERROR )) goto out_free;
drivers/xen/swiotlb-xen.c +3 -3
@@ -212,7 +212,7 @@ static dma_addr_t xen_swiotlb_map_phys(struct device *dev, phys_addr_t phys,BUG_ON (dir ==DMA_NONE );if (attrs &DMA_ATTR_MMIO ) { -if (unlikely (!dma_capable (dev, phys, size, false))) { +if (unlikely (!dma_capable (dev, phys, size, false, attrs))) { dev_err_once( dev, "DMA addr %pa+%zu overflow (mask %llx, bus limit %llx).\n",
@@ -231,7 +231,7 @@ static dma_addr_t xen_swiotlb_map_phys(struct device *dev, phys_addr_t phys,* we can safely return the device addr and not worry about bounce * buffering it. */ - if (dma_capable(dev, dev_addr, size, true) && + if (dma_capable(dev, dev_addr, size, true, attrs) && !dma_kmalloc_needs_bounce(dev, size, dir) && !range_straddles_page_boundary(phys, size) && !xen_arch_need_swiotlb(dev, phys, dev_addr) &&
@@ -253,7 +253,7 @@ static dma_addr_t xen_swiotlb_map_phys(struct device *dev, phys_addr_t phys,/* * Ensure that the address returned is DMA'ble */ -if (unlikely (!dma_capable (dev, dev_addr, size, true))) { +if (unlikely (!dma_capable (dev, dev_addr, size, true, attrs))) {__swiotlb_tbl_unmap_single (dev, map, size, dir, attrs |DMA_ATTR_SKIP_CPU_SYNC ,swiotlb_find_pool (dev, map));
include/linux/dma-direct.h +9 -1
@@ -135,12 +135,20 @@ static inline bool force_dma_unencrypted(struct device *dev)#endif /* CONFIG_ARCH_HAS_FORCE_DMA_UNENCRYPTED */ static inline bool dma_capable (struct device *dev,dma_addr_t addr,size_t size, -bool is_ram) +bool is_ram,unsigned long attrs) {dma_addr_t end = addr + size -1 ;if (addr ==DMA_MAPPING_ERROR )return false; +/* +* The DMA address was derived from encrypted RAM, but this device +* requires unencrypted DMA addresses. Treat it as not DMA-capable +* so the caller can fall back to a suitable SWIOTLB pool. +*/ +if (!(attrs &DMA_ATTR_CC_SHARED ) &&force_dma_unencrypted (dev)) +return false; +if (is_ram && !IS_ENABLED (CONFIG_ARCH_DMA_ADDR_T_64BIT ) &&min (addr, end) <phys_to_dma (dev,PFN_PHYS (min_low_pfn)))return false;
kernel/dma/direct.h +3 -3
@@ -101,15 +101,15 @@ static inline dma_addr_t dma_direct_map_phys(struct device *dev,if (attrs &DMA_ATTR_MMIO ) { dma_addr = phys; -if (unlikely (!dma_capable (dev, dma_addr, size, false))) +if (unlikely (!dma_capable (dev, dma_addr, size, false, attrs))) goto err_overflow; }else if (attrs &DMA_ATTR_CC_SHARED ) { dma_addr =phys_to_dma_unencrypted (dev, phys); -if (unlikely (!dma_capable (dev, dma_addr, size, false))) +if (unlikely (!dma_capable (dev, dma_addr, size, false, attrs))) goto err_overflow; }else { dma_addr =phys_to_dma (dev, phys); -if (unlikely (!dma_capable (dev, dma_addr, size, true)) || +if (unlikely (!dma_capable (dev, dma_addr, size, true, attrs)) ||dma_kmalloc_needs_bounce (dev, size, dir)) {if (is_swiotlb_active (dev) && !(attrs &DMA_ATTR_REQUIRE_COHERENT ))
kernel/dma/swiotlb.c +1 -1
@@ -1697,7 +1697,7 @@ dma_addr_t swiotlb_map(struct device *dev, phys_addr_t paddr, size_t size,else dma_addr =phys_to_dma_encrypted (dev, swiotlb_addr); -if (unlikely (!dma_capable (dev, dma_addr, size, true))) { +if (unlikely (!dma_capable (dev, dma_addr, size, true, attrs))) {__swiotlb_tbl_unmap_single (dev, swiotlb_addr, size, dir, attrs |DMA_ATTR_SKIP_CPU_SYNC ,swiotlb_find_pool (dev, swiotlb_addr));
Signature · 1 line
2.43.0
Re: [PATCH v8 15/23] dma-direct: pass attrs to dma_capable() for DMA_ATTR_CC_SHARED checks
Quoted 169 lines · Aneesh Kumar K.V (Arm)
Teach
dma_capable()aboutDMA_ATTR_CC_SHAREDso the capability check can reject encrypted DMA addresses for devices that require unencrypted/shared DMA.Also propagate
DMA_ATTR_CC_SHAREDinswiotlb_map()when the selected SWIOTLB pool is decrypted so the capability check sees the correct DMA address attribute.Reviewed-by Jason Gunthorpe <[email protected]>Tested-by Jiri Pirko <[email protected]>Tested-by Michael Kelley <[email protected]>Tested-by Mostafa Saleh <[email protected]>Reviewed-by Petr Tesarik <[email protected]>Signed-off-by Aneesh Kumar K.V (Arm) <[email protected]>--- arch/x86/kernel/amd_gart_64.c | 30 ++++++++++++++++-------------- drivers/xen/swiotlb-xen.c | 6 +++--- include/linux/dma-direct.h | 10 +++++++++- kernel/dma/direct.h | 6 +++--- kernel/dma/swiotlb.c | 2 +- 5 files changed, 32 insertions(+), 22 deletions(-)arch/x86/kernel/amd_gart_64.c +16
-14@@ -180,22 +180,23 @@ static void iommu_full(struct device *dev, size_t size, int dir) }static inline int -need_iommu (struct device *dev,unsigned long addr,size_t size) +need_iommu (struct device *dev,unsigned long addr,size_t size,unsigned long attrs) { -return force_iommu || !dma_capable (dev, addr, size, true); +return force_iommu || !dma_capable (dev, addr, size, true, attrs); }static inline int -nonforced_iommu (struct device *dev,unsigned long addr,size_t size) +nonforced_iommu (struct device *dev,unsigned long addr,size_t size, +unsigned long attrs) { -return !dma_capable (dev, addr, size, true); +return !dma_capable (dev, addr, size, true, attrs); }/* Map a single continuous physical area into the IOMMU. * Caller needs to check if the iommu is needed and flush. */ static dma_addr_t dma_map_area (struct device *dev,dma_addr_t phys_mem, -size_t size,int dir,unsigned long align_mask) +size_t size,int dir,unsigned long align_mask,unsigned long attrs) {unsigned long npages =iommu_num_pages (phys_mem, size,PAGE_SIZE );unsigned long iommu_page;@@ -206,7 +207,7 @@ static dma_addr_t dma_map_area(struct device *dev, dma_addr_t phys_mem, iommu_page =alloc_iommu (dev, npages, align_mask);if (iommu_page ==-1 ) { -if (!nonforced_iommu (dev, phys_mem, size)) +if (!nonforced_iommu (dev, phys_mem, size, attrs))return phys_mem;if (panic_on_overflow)panic ("dma_map_area overflow %lu bytes\n" , size);@@ -231,10 +232,10 @@ static dma_addr_t gart_map_phys(struct device *dev, phys_addr_t paddr,if (unlikely (attrs &DMA_ATTR_MMIO ))return DMA_MAPPING_ERROR ; -if (!need_iommu (dev, paddr, size)) +if (!need_iommu (dev, paddr, size, attrs))return paddr; - bus =dma_map_area (dev, paddr, size, dir,0 ); + bus =dma_map_area (dev, paddr, size, dir,0 , attrs);flush_gart ();return bus;@@ -289,7 +290,7 @@ static void gart_unmap_sg(struct device *dev, struct scatterlist *sg, int nents,/* Fallback for dma_map_sg in case of overflow */ static int dma_map_sg_nonforce (struct device *dev,struct scatterlist *sg, -int nents,int dir) +int nents,int dir,unsigned long attrs) {struct scatterlist *s;int i;@@ -301,8 +302,8 @@ static int dma_map_sg_nonforce(struct device *dev, struct scatterlist *sg,for_each_sg (sg, s, nents, i) {unsigned long addr =sg_phys (s); -if (nonforced_iommu (dev, addr, s->length)) { - addr =dma_map_area (dev, addr, s->length, dir,0 ); +if (nonforced_iommu (dev, addr, s->length, attrs)) { + addr =dma_map_area (dev, addr, s->length, dir,0 , attrs);if (addr ==DMA_MAPPING_ERROR ) {if (i >0 )gart_unmap_sg (dev, sg, i, dir,0 );@@ -401,7 +402,7 @@ static int gart_map_sg(struct device *dev, struct scatterlist *sg, int nents, s->dma_address = addr;BUG_ON (s->length ==0 ); - nextneed =need_iommu (dev, addr, s->length); + nextneed =need_iommu (dev, addr, s->length, attrs);/* Handle the previous not yet processed entries */ if (i > start) {@@ -449,7 +450,7 @@ static int gart_map_sg(struct device *dev, struct scatterlist *sg, int nents,/* When it was forced or merged try again in a dumb way */ if (force_iommu || iommu_merge) { - out =dma_map_sg_nonforce (dev, sg, nents, dir); + out =dma_map_sg_nonforce (dev, sg, nents, dir, attrs);if (out >0 )return out; }@@ -473,7 +474,8 @@ gart_alloc_coherent(struct device *dev, size_t size, dma_addr_t *dma_addr,return vaddr; *dma_addr =dma_map_area (dev,virt_to_phys (vaddr), size, -DMA_BIDIRECTIONAL , (1UL <<get_order (size)) -1 ); +DMA_BIDIRECTIONAL , + (1UL <<get_order (size)) -1 , attrs);flush_gart ();if (unlikely (*dma_addr ==DMA_MAPPING_ERROR )) goto out_free;drivers/xen/swiotlb-xen.c +3
-3@@ -212,7 +212,7 @@ static dma_addr_t xen_swiotlb_map_phys(struct device *dev, phys_addr_t phys,BUG_ON (dir ==DMA_NONE );if (attrs &DMA_ATTR_MMIO ) { -if (unlikely (!dma_capable (dev, phys, size, false))) { +if (unlikely (!dma_capable (dev, phys, size, false, attrs))) { dev_err_once( dev, "DMA addr %pa+%zu overflow (mask %llx, bus limit %llx).\n",@@ -231,7 +231,7 @@ static dma_addr_t xen_swiotlb_map_phys(struct device *dev, phys_addr_t phys,* we can safely return the device addr and not worry about bounce * buffering it. */ - if (dma_capable(dev, dev_addr, size, true) && + if (dma_capable(dev, dev_addr, size, true, attrs) && !dma_kmalloc_needs_bounce(dev, size, dir) && !range_straddles_page_boundary(phys, size) && !xen_arch_need_swiotlb(dev, phys, dev_addr) &&@@ -253,7 +253,7 @@ static dma_addr_t xen_swiotlb_map_phys(struct device *dev, phys_addr_t phys,/* * Ensure that the address returned is DMA'ble */ -if (unlikely (!dma_capable (dev, dev_addr, size, true))) { +if (unlikely (!dma_capable (dev, dev_addr, size, true, attrs))) {__swiotlb_tbl_unmap_single (dev, map, size, dir, attrs |DMA_ATTR_SKIP_CPU_SYNC ,swiotlb_find_pool (dev, map));include/linux/dma-direct.h +1
-1@@ -135,12 +135,20 @@ static inline bool force_dma_unencrypted(struct device *dev)#endif /* CONFIG_ARCH_HAS_FORCE_DMA_UNENCRYPTED */ static inline bool dma_capable (struct device *dev,dma_addr_t addr,size_t size, -bool is_ram) +bool is_ram,unsigned long attrs) {dma_addr_t end = addr + size -1 ;
include/linux/dma-direct.h static inline bool force_dma_unencrypted(struct device *dev) · line 151
Quoted 10 lines
include/linux/dma-direct.h +8
-0if (addr ==DMA_MAPPING_ERROR )return false; +/* +* The DMA address was derived from encrypted RAM, but this device +* requires unencrypted DMA addresses. Treat it as not DMA-capable +* so the caller can fall back to a suitable SWIOTLB pool. +*/ +if (!(attrs &DMA_ATTR_CC_SHARED ) &&force_dma_unencrypted (dev)) +return false; +
I guess it does not make sense to check the other way? I'd be worried if some a confidential device uses shared memory which might leak info.
Thanks,
Mostafa
Quoted 42 lines
include/linux/dma-direct.h +0
-0if (is_ram && !IS_ENABLED (CONFIG_ARCH_DMA_ADDR_T_64BIT ) &&min (addr, end) <phys_to_dma (dev,PFN_PHYS (min_low_pfn)))return false;kernel/dma/direct.h +3
-3@@ -101,15 +101,15 @@ static inline dma_addr_t dma_direct_map_phys(struct device *dev,if (attrs &DMA_ATTR_MMIO ) { dma_addr = phys; -if (unlikely (!dma_capable (dev, dma_addr, size, false))) +if (unlikely (!dma_capable (dev, dma_addr, size, false, attrs))) goto err_overflow; }else if (attrs &DMA_ATTR_CC_SHARED ) { dma_addr =phys_to_dma_unencrypted (dev, phys); -if (unlikely (!dma_capable (dev, dma_addr, size, false))) +if (unlikely (!dma_capable (dev, dma_addr, size, false, attrs))) goto err_overflow; }else { dma_addr =phys_to_dma (dev, phys); -if (unlikely (!dma_capable (dev, dma_addr, size, true)) || +if (unlikely (!dma_capable (dev, dma_addr, size, true, attrs)) ||dma_kmalloc_needs_bounce (dev, size, dir)) {if (is_swiotlb_active (dev) && !(attrs &DMA_ATTR_REQUIRE_COHERENT ))kernel/dma/swiotlb.c +1
-1@@ -1697,7 +1697,7 @@ dma_addr_t swiotlb_map(struct device *dev, phys_addr_t paddr, size_t size,else dma_addr =phys_to_dma_encrypted (dev, swiotlb_addr); -if (unlikely (!dma_capable (dev, dma_addr, size, true))) { +if (unlikely (!dma_capable (dev, dma_addr, size, true, attrs))) {__swiotlb_tbl_unmap_single (dev, swiotlb_addr, size, dir, attrs |DMA_ATTR_SKIP_CPU_SYNC ,swiotlb_find_pool (dev, swiotlb_addr));Signature · 1 line
2.43.0
Re: [PATCH v8 15/23] dma-direct: pass attrs to dma_capable() for DMA_ATTR_CC_SHARED checks
Quoted 6 lines · Mostafa Saleh
Quoted 6 lines
static inline bool dma_capable(struct device *dev,
dma_addr_taddr,size_tsize,include/linux/dma-direct.h +1
-1- bool is_ram) + bool is_ram, unsigned long attrs) {dma_addr_t end = addr + size -1 ;
Quoted 14 lines
include/linux/dma-direct.h static inline bool force_dma_unencrypted(struct device *dev) · line 151
Quoted 10 lines
include/linux/dma-direct.h +8
-0if (addr ==DMA_MAPPING_ERROR )return false; +/* +* The DMA address was derived from encrypted RAM, but this device +* requires unencrypted DMA addresses. Treat it as not DMA-capable +* so the caller can fall back to a suitable SWIOTLB pool. +*/ +if (!(attrs &DMA_ATTR_CC_SHARED ) &&force_dma_unencrypted (dev)) +return false; +I guess it does not make sense to check the other way? I'd be worried if some a confidential device uses shared memory which might leak info.
From the perspective of the dma_capable() check, this should be allowed; that is, a trusted device is permitted to access shared memory.
-aneesh
Re: [PATCH v8 15/23] dma-direct: pass attrs to dma_capable() for DMA_ATTR_CC_SHARED checks
Quoted 23 lines · Aneesh Kumar K.V
Quoted 6 lines · Mostafa Saleh
Quoted 6 lines
static inline bool dma_capable(struct device *dev,
dma_addr_taddr,size_tsize,include/linux/dma-direct.h +1
-1- bool is_ram) + bool is_ram, unsigned long attrs) {dma_addr_t end = addr + size -1 ;Quoted 14 lines
include/linux/dma-direct.h static inline bool force_dma_unencrypted(struct device *dev) · line 151
Quoted 10 lines
include/linux/dma-direct.h +8
-0if (addr ==DMA_MAPPING_ERROR )return false; +/* +* The DMA address was derived from encrypted RAM, but this device +* requires unencrypted DMA addresses. Treat it as not DMA-capable +* so the caller can fall back to a suitable SWIOTLB pool. +*/ +if (!(attrs &DMA_ATTR_CC_SHARED ) &&force_dma_unencrypted (dev)) +return false; +I guess it does not make sense to check the other way? I'd be worried if some a confidential device uses shared memory which might leak info.
Quoted 2 lines
From the perspective of the
dma_capable()check, this should be allowed; that is, a trusted device is permitted to access shared memory.
Right, we have use cases that require confidential devices to use shared memory we cannot block it at the DMA layer.
It would be a reasonable DMA debugging to block shared memory without the DMA ATTR CC SHARED.
Jason
PATCH v8 16/23 dma-direct: Move dma_direct_map_phys() to dma/direct.c
In reply to Aneesh Kumar K.V (Arm)dma_direct_map_phys() is too large to benefit from being inlined. Move its implementation to direct.c and leave the declaration in direct.h.
No functional change in this patch
--- kernel/dma/direct.c | 53 ++++++++++++++++++++++++++++++++++++++++++ kernel/dma/direct.h | 56 +++------------------------------------------ 2 files changed, 56 insertions(+), 53 deletions(-)
kernel/dma/direct.c +53 -0
@@ -620,6 +620,59 @@ int dma_direct_mmap(struct device *dev, struct vm_area_struct *vma, user_count << PAGE_SHIFT, vma->vm_page_prot); } +dma_addr_t dma_direct_map_phys (struct device *dev,phys_addr_t phys, +size_t size,enum dma_data_direction dir, +unsigned long attrs,bool flush) +{ +dma_addr_t dma_addr; + +if (is_swiotlb_force_bounce (dev)) { +if (!(attrs &DMA_ATTR_CC_SHARED )) { +if (attrs & (DMA_ATTR_MMIO |DMA_ATTR_REQUIRE_COHERENT )) +return DMA_MAPPING_ERROR ; + +return swiotlb_map (dev, phys, size, dir, attrs); + } + }else if (attrs &DMA_ATTR_CC_SHARED ) { +return DMA_MAPPING_ERROR ; + } + +if (attrs &DMA_ATTR_MMIO ) { + dma_addr = phys; +if (unlikely (!dma_capable (dev, dma_addr, size, false, attrs))) + goto err_overflow; + }else if (attrs &DMA_ATTR_CC_SHARED ) { + dma_addr =phys_to_dma_unencrypted (dev, phys); +if (unlikely (!dma_capable (dev, dma_addr, size, false, attrs))) + goto err_overflow; + }else { + dma_addr =phys_to_dma (dev, phys); +if (unlikely (!dma_capable (dev, dma_addr, size, true, attrs)) || +dma_kmalloc_needs_bounce (dev, size, dir)) { +if (is_swiotlb_active (dev) && + !(attrs &DMA_ATTR_REQUIRE_COHERENT )) +return swiotlb_map (dev, phys, size, dir, attrs); + + goto err_overflow; + } + } + +if (!dev_is_dma_coherent (dev) && + !(attrs & (DMA_ATTR_SKIP_CPU_SYNC |DMA_ATTR_MMIO ))) { +arch_sync_dma_for_device (phys, size, dir); +if (flush) +arch_sync_dma_flush (); + } +return dma_addr; + +err_overflow: +dev_WARN_ONCE ( + dev,1 , +"DMA addr %pad+%zu overflow (mask %llx, bus limit %llx).\n" , + &dma_addr, size, *dev->dma_mask, dev->bus_dma_limit); +return DMA_MAPPING_ERROR ; +} +int dma_direct_supported (struct device *dev,u64 mask) {u64 min_mask = ((u64 )max_pfn <<PAGE_SHIFT ) -1 ;
kernel/dma/direct.h +3 -53
68 lines not on this page · raw message
Signature · 1 line
2.43.0
PATCH v8 17/23 dma-direct: make dma_direct_map_phys() honor DMA_ATTR_CC_SHARED
In reply to Aneesh Kumar K.V (Arm)Teach dma_direct_map_phys() to select the DMA address encoding based on DMA_ATTR_CC_SHARED.
Use phys_to_dma_unencrypted() for decrypted mappings and phys_to_dma_encrypted() otherwise. If a device requires unencrypted DMA but the source physical address is still encrypted, force the mapping through swiotlb so the DMA address and backing memory attributes remain consistent.
Update the arm64, x86, s390 and powerpc secure-guest setup to not use swiotlb force option
---
Changes from v3:
* Handle DMA_ATTR_MMIO
--- arch/arm64/mm/init.c | 4 +-- arch/powerpc/platforms/pseries/svm.c | 2 +- arch/s390/mm/init.c | 2 +- arch/x86/kernel/pci-dma.c | 4 +-- kernel/dma/direct.c | 52 ++++++++++++++++------------ 5 files changed, 34 insertions(+), 30 deletions(-)
arch/arm64/mm/init.c +1 -3
@@ -340,9 +340,7 @@ void __init arch_mm_preinit(void)unsigned int flags =SWIOTLB_VERBOSE ;bool limited_addressing = max_pfn >PFN_DOWN (arm64_dma_phys_limit); -if (is_realm_world () ||is_protected_kvm_guest ()) { - flags |=SWIOTLB_FORCE ; - }else if (!limited_addressing) { +if (!limited_addressing) {/* * If no bouncing needed for ZONE_DMA, reduce the swiotlb * buffer for kmalloc() bouncing to 1MB per 1GB of RAM.
arch/powerpc/platforms/pseries/svm.c +1 -1
@@ -29,7 +29,7 @@ static int __init init_svm(void)* need to use the SWIOTLB buffer for DMA even if dma_capable() says * otherwise. */ - ppc_swiotlb_flags |=SWIOTLB_ANY |SWIOTLB_FORCE ; + ppc_swiotlb_flags |=SWIOTLB_ANY ;/* Share the SWIOTLB buffer with the host. */ swiotlb_update_mem_attributes ();
arch/s390/mm/init.c +1 -1
@@ -166,7 +166,7 @@ static void __init pv_init(void)virtio_set_mem_acc_cb (virtio_require_restricted_mem_acc);/* make sure bounce buffers are shared */ -swiotlb_init (true,SWIOTLB_FORCE |SWIOTLB_VERBOSE ); +swiotlb_init (true,SWIOTLB_VERBOSE );swiotlb_update_mem_attributes (); }
arch/x86/kernel/pci-dma.c +1 -3
@@ -59,10 +59,8 @@ static void __init pci_swiotlb_detect(void)* bounce buffers as the hypervisor can't access arbitrary VM memory * that is not explicitly shared with it. */ -if (cc_platform_has (CC_ATTR_GUEST_MEM_ENCRYPT )) { +if (cc_platform_has (CC_ATTR_GUEST_MEM_ENCRYPT )) x86_swiotlb_enable = true; - x86_swiotlb_flags |=SWIOTLB_FORCE ; - } }#else static inline void __init pci_swiotlb_detect (void )
kernel/dma/direct.c +30 -22
81 lines not on this page · raw message
Signature · 1 line
2.43.0
PATCH 1/1 arm64: swiotlb: Keep the default size for protected guests
Realm guests and protected KVM guests may require swiotlb for device DMA even when all system RAM is addressable by the DMA zones.
Do not reduce the SWIOTLB buffer to the kmalloc-bouncing size for these guests, as the reduced number of slots can be exhausted during CCA guest operation.
--- arch/arm64/mm/init.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
arch/arm64/mm/init.c +2 -1
@@ -339,7 +339,8 @@ void __init arch_mm_preinit(void) {unsigned int flags =SWIOTLB_VERBOSE ; -if (max_pfn <=PFN_DOWN (arm64_dma_phys_limit)) { +if (!cc_platform_has (CC_ATTR_GUEST_MEM_ENCRYPT ) && + max_pfn <=PFN_DOWN (arm64_dma_phys_limit)) {/* * If no bouncing needed for ZONE_DMA, reduce the swiotlb * buffer for kmalloc() bouncing to 1MB per 1GB of RAM.
Signature · 1 line
2.43.0
[email protected]
AI reviewRe: [PATCH] arm64: swiotlb: Keep the default size for protected guests
Sashiko has reviewed this patch and found no issues. It looks great!
Quoted 9 lines
Realm guests and protected KVM guests may require swiotlb for device DMA even when all system RAM is addressable by the DMA zones.
Do not reduce the SWIOTLB buffer to the kmalloc-bouncing size for these guests, as the reduced number of slots can be exhausted during CCA guest operation.
Fixes 30c5e45ee2c5 ("dma-direct: make dma_direct_map_phys() honor DMA_ATTR_CC_SHARED")Signed-off-by Aneesh Kumar K.V (Arm) <[email protected]>
Sashiko has reviewed this patch and found no issues. It looks great!
Signature · 1 line
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=1
Will Deacon
maintainerRe: [PATCH] arm64: swiotlb: Keep the default size for protected guests
In reply to Aneesh Kumar K.V (Arm)Quoted 18 lines · Aneesh Kumar K.V (Arm)
Realm guests and protected KVM guests may require swiotlb for device DMA even when all system RAM is addressable by the DMA zones.
Do not reduce the SWIOTLB buffer to the kmalloc-bouncing size for these guests, as the reduced number of slots can be exhausted during CCA guest operation.
Fixes 30c5e45ee2c5 ("dma-direct: make dma_direct_map_phys() honor DMA_ATTR_CC_SHARED")Signed-off-by Aneesh Kumar K.V (Arm) <[email protected]>--- arch/arm64/mm/init.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)arch/arm64/mm/init.c +0
-0
arch/arm64/mm/init.c void __init arch_mm_preinit(void) · line 343
Quoted 6 lines
arch/arm64/mm/init.c +2
-1@@ -339,7 +339,8 @@ void __init arch_mm_preinit(void) {unsigned int flags =SWIOTLB_VERBOSE ; -if (max_pfn <=PFN_DOWN (arm64_dma_phys_limit)) { +if (!cc_platform_has (CC_ATTR_GUEST_MEM_ENCRYPT ) && + max_pfn <=PFN_DOWN (arm64_dma_phys_limit)) {
Protected guests under pKVM rely on restricted DMA, so won't this just waste memory for them?
Will
Re: [PATCH] arm64: swiotlb: Keep the default size for protected guests
Quoted 22 lines · Will Deacon
Quoted 21 lines · Aneesh Kumar K.V (Arm)
Realm guests and protected KVM guests may require swiotlb for device DMA even when all system RAM is addressable by the DMA zones.
Do not reduce the SWIOTLB buffer to the kmalloc-bouncing size for these guests, as the reduced number of slots can be exhausted during CCA guest operation.
Fixes 30c5e45ee2c5 ("dma-direct: make dma_direct_map_phys() honor DMA_ATTR_CC_SHARED")Signed-off-by Aneesh Kumar K.V (Arm) <[email protected]>--- arch/arm64/mm/init.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)arch/arm64/mm/init.c +0
-0@@ -339,7 +339,8 @@ void __init arch_mm_preinit(void) {unsigned int flags =SWIOTLB_VERBOSE ;
Quoted 7 lines
arch/arm64/mm/init.c void __init arch_mm_preinit(void) · line 343
Quoted 3 lines
arch/arm64/mm/init.c +2
-1-if (max_pfn <=PFN_DOWN (arm64_dma_phys_limit)) { +if (!cc_platform_has (CC_ATTR_GUEST_MEM_ENCRYPT ) && + max_pfn <=PFN_DOWN (arm64_dma_phys_limit)) {Protected guests under pKVM rely on restricted DMA, so won't this just waste memory for them?
commit 30c5e45ee2c5 ("dma-direct: make dma_direct_map_phys() honor DMA_ATTR_CC_SHARED"), which this patch fixes, has
arch/arm64/mm/init.c +1 -3
@@ -339,9 +339,7 @@ void __init arch_mm_preinit(void) {unsigned int flags =SWIOTLB_VERBOSE ; -if (is_realm_world () ||is_protected_kvm_guest ()) { - flags |=SWIOTLB_FORCE ; - }else if (max_pfn <=PFN_DOWN (arm64_dma_phys_limit)) { +if (max_pfn <=PFN_DOWN (arm64_dma_phys_limit)) {/* * If no bouncing needed for ZONE_DMA, reduce the swiotlb * buffer for kmalloc() bouncing to 1MB per 1GB of RAM.
The is_protected_kvm_guest() part was added by the commit e62decaf98e7 ("arm64/coco: Add pKVM as a CC platform")
@@ -337,7 +339,7 @@ void __init arch_mm_preinit(void)
{
unsigned int flags = SWIOTLB_VERBOSE;- if (is_realm_world()) {
+ if (is_realm_world() || is_protected_kvm_guest()) {
flags |= SWIOTLB_FORCE;
} else if (max_pfn <= PFN_DOWN(arm64_dma_phys_limit)) {
/*
@@ -412,6 +414,17 @@ void dump_mem_limit(void)
}}
I was under the impression that there is a possibility of using swiotlb instead of restricted-dma-pool with pKVM. If that is not the case, then we could change:
!cc_platform_has(CC_ATTR_GUEST_MEM_ENCRYPT) &&
to
!is_realm_world() &&
-aneesh
Will Deacon
maintainerRe: [PATCH] arm64: swiotlb: Keep the default size for protected guests
Quoted 65 lines · Aneesh Kumar K.V
Quoted 22 lines · Will Deacon
Quoted 21 lines · Aneesh Kumar K.V (Arm)
Realm guests and protected KVM guests may require swiotlb for device DMA even when all system RAM is addressable by the DMA zones.
Do not reduce the SWIOTLB buffer to the kmalloc-bouncing size for these guests, as the reduced number of slots can be exhausted during CCA guest operation.
Fixes 30c5e45ee2c5 ("dma-direct: make dma_direct_map_phys() honor DMA_ATTR_CC_SHARED")Signed-off-by Aneesh Kumar K.V (Arm) <[email protected]>--- arch/arm64/mm/init.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)arch/arm64/mm/init.c +0
-0@@ -339,7 +339,8 @@ void __init arch_mm_preinit(void) {unsigned int flags =SWIOTLB_VERBOSE ;Quoted 7 lines
arch/arm64/mm/init.c void __init arch_mm_preinit(void) · line 343
Quoted 3 lines
arch/arm64/mm/init.c +2
-1-if (max_pfn <=PFN_DOWN (arm64_dma_phys_limit)) { +if (!cc_platform_has (CC_ATTR_GUEST_MEM_ENCRYPT ) && + max_pfn <=PFN_DOWN (arm64_dma_phys_limit)) {Protected guests under pKVM rely on restricted DMA, so won't this just waste memory for them?
commit
30c5e45ee2c5("dma-direct: makedma_direct_map_phys()honorDMA_ATTR_CC_SHARED"), which this patch fixes, hasarch/arm64/mm/init.c +1
-3@@ -339,9 +339,7 @@ void __init arch_mm_preinit(void) {unsigned int flags =SWIOTLB_VERBOSE ; -if (is_realm_world () ||is_protected_kvm_guest ()) { - flags |=SWIOTLB_FORCE ; - }else if (max_pfn <=PFN_DOWN (arm64_dma_phys_limit)) { +if (max_pfn <=PFN_DOWN (arm64_dma_phys_limit)) {/* * If no bouncing needed for ZONE_DMA, reduce the swiotlb * buffer for kmalloc() bouncing to 1MB per 1GB of RAM. The
is_protected_kvm_guest()part was added by the commite62decaf98e7("arm64/coco: Add pKVM as a CC platform")arch/arm64/mm/init.c +1
-1@@ -337,7 +339,7 @@ void __init arch_mm_preinit(void) {unsigned int flags =SWIOTLB_VERBOSE ; -if (is_realm_world ()) { +if (is_realm_world () ||is_protected_kvm_guest ()) { flags |=SWIOTLB_FORCE ; }else if (max_pfn <=PFN_DOWN (arm64_dma_phys_limit)) {/* @@ -412,6 +414,17 @@ void dump_mem_limit(void) } }
Quoted 2 lines
I was under the impression that there is a possibility of using swiotlb instead of restricted-dma-pool with pKVM.
Yes, that patch enables swiotlb as a possibility for protected guests but with your patch we avoid shrinking the swiotlb buffer even when restricted dma pools are being used and that's a waste of memory.
Quoted 7 lines
If that is not the case, then we could change:
!cc_platform_has(CC_ATTR_GUEST_MEM_ENCRYPT) &&
to
!is_realm_world() &&
Perhaps, or you could just pass the swiotlb= option if the defaults don't work for you. Can you give more details about the slots exhaustion you're seeing under CCA?
Will
Re: [PATCH] arm64: swiotlb: Keep the default size for protected guests
Quoted 6 lines · Will Deacon
Quoted 2 lines
I was under the impression that there is a possibility of using swiotlb instead of restricted-dma-pool with pKVM.
Yes, that patch enables swiotlb as a possibility for protected guests but with your patch we avoid shrinking the swiotlb buffer even when restricted dma pools are being used and that's a waste of memory.
I also thought we switched pkvm to use CC-like swiotlb as part of the alignment in this rework? Mostafa ?
Quoted 11 lines
Quoted 7 lines
If that is not the case, then we could change:
!cc_platform_has(CC_ATTR_GUEST_MEM_ENCRYPT) &&
to
!is_realm_world() &&
Perhaps, or you could just pass the swiotlb= option if the defaults don't work for you. Can you give more details about the slots exhaustion you're seeing under CCA?
We see badness with swiotlb too, it basically doesn't work out of the box if you have to use it 100% for real devices. It easily runs out of memory.
Auto tuning to higher levels makes sense to me, but I'd rather the core code handled adjusting its size to the estimated need, not arch code.
Jason
Re: [PATCH] arm64: swiotlb: Keep the default size for protected guests
Quoted 11 lines · Jason Gunthorpe
Quoted 6 lines · Will Deacon
Quoted 2 lines
I was under the impression that there is a possibility of using swiotlb instead of restricted-dma-pool with pKVM.
Yes, that patch enables swiotlb as a possibility for protected guests but with your patch we avoid shrinking the swiotlb buffer even when restricted dma pools are being used and that's a waste of memory.
I also thought we switched pkvm to use CC-like swiotlb as part of the alignment in this rework? Mostafa ?
Yes, now protected VMs can use the SWIOTLB for bouncing. However for Android (and kvmtool), use restricted DMA. so SWIOTLB is not used.
However, I do not think we should over engineer this in the code, swiotlb can be set from the cmdline and now through Kconfig also.
Thanks,
Mostafa
Quoted 22 lines
Quoted 5 lines
Quoted 5 lines
If that is not the case, then we could change:
!cc_platform_has(CC_ATTR_GUEST_MEM_ENCRYPT) &&
Quoted 7 lines
Quoted 3 lines
to
!is_realm_world() &&
Perhaps, or you could just pass the swiotlb= option if the defaults don't work for you. Can you give more details about the slots exhaustion you're seeing under CCA?
We see badness with swiotlb too, it basically doesn't work out of the box if you have to use it 100% for real devices. It easily runs out of memory.
Auto tuning to higher levels makes sense to me, but I'd rather the core code handled adjusting its size to the estimated need, not arch code.
Jason
Re: [PATCH] arm64: swiotlb: Keep the default size for protected guests
Quoted 10 lines · Mostafa Saleh
Quoted 9 lines · Jason Gunthorpe
Quoted 6 lines · Will Deacon
Quoted 2 lines
I was under the impression that there is a possibility of using swiotlb instead of restricted-dma-pool with pKVM.
Yes, that patch enables swiotlb as a possibility for protected guests but with your patch we avoid shrinking the swiotlb buffer even when restricted dma pools are being used and that's a waste of memory.
Quoted 5 lines
Quoted 2 lines
I also thought we switched pkvm to use CC-like swiotlb as part of the alignment in this rework? Mostafa ?
Yes, now protected VMs can use the SWIOTLB for bouncing. However for Android (and kvmtool), use restricted DMA. so SWIOTLB is not used.
Oh? Why?
Quoted 2 lines
However, I do not think we should over engineer this in the code, swiotlb can be set from the cmdline and now through
Kconfigalso.
That's fine for android, but real users buying a cloud VM and sticking a distro on it shouldn't be expected to have to mess with cmdline just go get a halfway working system
Jason
Re: [PATCH] arm64: swiotlb: Keep the default size for protected guests
Quoted 11 lines · Jason Gunthorpe
Quoted 10 lines · Mostafa Saleh
Quoted 9 lines · Jason Gunthorpe
Quoted 6 lines · Will Deacon
Quoted 2 lines
I was under the impression that there is a possibility of using swiotlb instead of restricted-dma-pool with pKVM.
Yes, that patch enables swiotlb as a possibility for protected guests but with your patch we avoid shrinking the swiotlb buffer even when restricted dma pools are being used and that's a waste of memory.
Quoted 8 lines
Quoted 5 lines
Quoted 2 lines
I also thought we switched pkvm to use CC-like swiotlb as part of the alignment in this rework? Mostafa ?
Yes, now protected VMs can use the SWIOTLB for bouncing. However for Android (and kvmtool), use restricted DMA. so SWIOTLB is not used.
Oh? Why?
The patches are not in Linux yet, when it eventually lands in Android it should be possible, I did some initial assessment and did not see any regressions.
Quoted 6 lines
Quoted 2 lines
However, I do not think we should over engineer this in the code, swiotlb can be set from the cmdline and now through
Kconfigalso.That's fine for android, but real users buying a cloud VM and sticking a distro on it shouldn't be expected to have to mess with cmdline just go get a halfway working system
But the whole thing is best effort anyway, the kernel picks IO_TLB_DEFAULT_SIZE which does not depend on the system topology or how many devices or how much DMA they do.
SWIOTLB memory is wasted if unused so we should be careful around that as it would be the other way around and users would have to decrease it manually.
Thanks,
Mostafa
Quoted 2 lines
Jason
Re: [PATCH] arm64: swiotlb: Keep the default size for protected guests
Quoted 6 lines · Mostafa Saleh
But the whole thing is best effort anyway, the kernel picks
IO_TLB_DEFAULT_SIZEwhich does not depend on the system topology or how many devices or how much DMA they do.
SWIOTLB memory is wasted if unused so we should be careful around that as it would be the other way around and users would have to decrease it manually.
Yeah, it is why the arch code shouldn't really be sizing it directly, it should be done in common code and, yes, we are probably going to have to do something alot smarter to have the common code better auto-tune this for the CC case..
Jason
Marek Szyprowski
maintainerRe: [PATCH] arm64: swiotlb: Keep the default size for protected guests
Quoted 11 lines · Jason Gunthorpe
Quoted 6 lines · Mostafa Saleh
But the whole thing is best effort anyway, the kernel picks
IO_TLB_DEFAULT_SIZEwhich does not depend on the system topology or how many devices or how much DMA they do.
SWIOTLB memory is wasted if unused so we should be careful around that as it would be the other way around and users would have to decrease it manually.Yeah, it is why the arch code shouldn't really be sizing it directly, it should be done in common code and, yes, we are probably going to have to do something alot smarter to have the common code better auto-tune this for the CC case..
What about the $subject patch? I assume that it is still needed to
restore the behavior that was altered by the "[PATCH v8 00/23]
dma-mapping: Track shared DMA state through direct, pool and swiotlb
paths?" patchset?
Best regards
Signature · 2 lines
Marek Szyprowski, PhD Samsung R&D Institute Poland
Re: [PATCH] arm64: swiotlb: Keep the default size for protected guests
Quoted 13 lines · Marek Szyprowski
Quoted 11 lines · Jason Gunthorpe
Quoted 6 lines · Mostafa Saleh
But the whole thing is best effort anyway, the kernel picks
IO_TLB_DEFAULT_SIZEwhich does not depend on the system topology or how many devices or how much DMA they do.
SWIOTLB memory is wasted if unused so we should be careful around that as it would be the other way around and users would have to decrease it manually.Yeah, it is why the arch code shouldn't really be sizing it directly, it should be done in common code and, yes, we are probably going to have to do something alot smarter to have the common code better auto-tune this for the CC case..
Quoted 8 lines
What about the $subject patch? I assume that it is still needed to
restore the behavior that was altered by the "[PATCH v8 00/23]
dma-mapping: Track shared DMA state through direct, pool and swiotlb
paths?" patchset?
I would request that we pick this patch to fix the regression described in https://lore.kernel.org/all/[email protected]/.
We can then work separately on improving the default swiotlb pool size in generic code based on other metrics. I consider this patch independent of that work.
Even with such an improvement, this patch would still be applicable: a condition that resizes the swiotlb pool based on arm64_dma_phys_limit should not apply when guest memory encryption is in use, because the purpose of the swiotlb pool is different in that configuration.
-aneesh
Will Deacon
maintainerRe: [PATCH] arm64: swiotlb: Keep the default size for protected guests
Quoted 19 lines · Aneesh Kumar K.V
Quoted 17 lines · Marek Szyprowski
Quoted 11 lines · Jason Gunthorpe
Quoted 6 lines · Mostafa Saleh
But the whole thing is best effort anyway, the kernel picks
IO_TLB_DEFAULT_SIZEwhich does not depend on the system topology or how many devices or how much DMA they do.
SWIOTLB memory is wasted if unused so we should be careful around that as it would be the other way around and users would have to decrease it manually.Yeah, it is why the arch code shouldn't really be sizing it directly, it should be done in common code and, yes, we are probably going to have to do something alot smarter to have the common code better auto-tune this for the CC case..
What about the $subject patch? I assume that it is still needed to
restore the behavior that was altered by the "[PATCH v8 00/23]
Quoted 7 lines
Quoted 4 lines
dma-mapping: Track shared DMA state through direct, pool and swiotlb
paths?" patchset?
I would request that we pick this patch to fix the regression described in https://lore.kernel.org/all/[email protected]/.
I really don't think we need it. CCA hardware isn't exactly widespread and the KVM host side patches don't appear close to being merged.
We have time to fix this properly, rather than papering over it in the arch code.
Please consider this a NAK from the arm64 side on this patch.
Will
Marek Szyprowski
maintainerRe: [PATCH] arm64: swiotlb: Keep the default size for protected guests
Quoted 19 lines · Will Deacon
Quoted 18 lines · Aneesh Kumar K.V
Quoted 16 lines · Marek Szyprowski
Quoted 11 lines · Jason Gunthorpe
Quoted 6 lines · Mostafa Saleh
But the whole thing is best effort anyway, the kernel picks
IO_TLB_DEFAULT_SIZEwhich does not depend on the system topology or how many devices or how much DMA they do.
SWIOTLB memory is wasted if unused so we should be careful around that as it would be the other way around and users would have to decrease it manually.Yeah, it is why the arch code shouldn't really be sizing it directly, it should be done in common code and, yes, we are probably going to have to do something alot smarter to have the common code better auto-tune this for the CC case..
What about the $subject patch? I assume that it is still needed to
restore the behavior that was altered by the "[PATCH v8 00/23]
Quoted 8 lines
Quoted 6 lines
Quoted 4 lines
dma-mapping: Track shared DMA state through direct, pool and swiotlb
paths?" patchset?
I would request that we pick this patch to fix the regression described in https://lore.kernel.org/all/[email protected]/.
I really don't think we need it. CCA hardware isn't exactly widespread and the KVM host side patches don't appear close to being merged.
Does this mean that the branch for-next/coco [1] won't go to v7.3-rc1?
I've used it as a base for the mentioned DMA-mapping patchset.
[1] https://git.kernel.org/pub/scm/linux/kernel/git/arm64/linux.git/log/?h=for-next/coco
Quoted 4 lines
We have time to fix this properly, rather than papering over it in the arch code.
Please consider this a NAK from the arm64 side on this patch.
Best regards
Signature · 2 lines
Marek Szyprowski, PhD Samsung R&D Institute Poland
Will Deacon
maintainerRe: [PATCH] arm64: swiotlb: Keep the default size for protected guests
Quoted 22 lines · Marek Szyprowski
Quoted 21 lines · Will Deacon
Quoted 20 lines · Aneesh Kumar K.V
Quoted 18 lines · Marek Szyprowski
Quoted 11 lines · Jason Gunthorpe
Quoted 6 lines · Mostafa Saleh
But the whole thing is best effort anyway, the kernel picks
IO_TLB_DEFAULT_SIZEwhich does not depend on the system topology or how many devices or how much DMA they do.
SWIOTLB memory is wasted if unused so we should be careful around that as it would be the other way around and users would have to decrease it manually.Yeah, it is why the arch code shouldn't really be sizing it directly, it should be done in common code and, yes, we are probably going to have to do something alot smarter to have the common code better auto-tune this for the CC case..
What about the $subject patch? I assume that it is still needed to
restore the behavior that was altered by the "[PATCH v8 00/23]
dma-mapping: Track shared DMA state through direct, pool and swiotlb
Quoted 8 lines
Quoted 6 lines
Quoted 4 lines
Quoted 2 lines
paths?" patchset?
I would request that we pick this patch to fix the regression described in https://lore.kernel.org/all/[email protected]/.
I really don't think we need it. CCA hardware isn't exactly widespread and the KVM host side patches don't appear close to being merged.
Does this mean that the branch for-next/coco [1] won't go to v7.3-rc1?
Argh, no, I'm definitely planning to send that!
I'm just saying that this specific fixup patch (which is a PATCH sent in reply to another patch in the middle of a series...):
https://lore.kernel.org/all/[email protected]/
isn't something we should take for the upcoming merge window. There are better, alternative ways to tackle the issue (as discussed in the thread) and it's really not as urgent as Aneesh is trying to make it sound.
Will
Re: [PATCH] arm64: swiotlb: Keep the default size for protected guests
Quoted 23 lines · Will Deacon
Quoted 22 lines · Marek Szyprowski
Quoted 21 lines · Will Deacon
Quoted 20 lines · Aneesh Kumar K.V
Quoted 18 lines · Marek Szyprowski
Quoted 11 lines · Jason Gunthorpe
Quoted 6 lines · Mostafa Saleh
But the whole thing is best effort anyway, the kernel picks
IO_TLB_DEFAULT_SIZEwhich does not depend on the system topology or how many devices or how much DMA they do.
SWIOTLB memory is wasted if unused so we should be careful around that as it would be the other way around and users would have to decrease it manually.Yeah, it is why the arch code shouldn't really be sizing it directly, it should be done in common code and, yes, we are probably going to have to do something alot smarter to have the common code better auto-tune this for the CC case..
What about the $subject patch? I assume that it is still needed to
restore the behavior that was altered by the "[PATCH v8 00/23]
dma-mapping: Track shared DMA state through direct, pool and swiotlb
Quoted 8 lines
Quoted 8 lines
Quoted 6 lines
Quoted 4 lines
Quoted 2 lines
paths?" patchset?
I would request that we pick this patch to fix the regression described in https://lore.kernel.org/all/[email protected]/.
I really don't think we need it. CCA hardware isn't exactly widespread and the KVM host side patches don't appear close to being merged.
Does this mean that the branch for-next/coco [1] won't go to v7.3-rc1?
Let's not make progress on guest support contingent on KVM CCA host side patches please. I expect the CSPs will have VM instance types available based on CCA within quarters, and Linux as a Guest should work in those environments regardless of what KVM is doing. I don't really expect full KVM support for years, frankly, the patchset is massive. Even Intel and AMD don't have full KVM support yet.
People already have CCA capable HW, are already testing this stuff and the closer upstream can get to being workable as a guest without a mountain of OOT patches the better.
I agree the thing is not ideal, but it was merged to ARM like this a long time ago, this patch is just fixing a small oopsie (was it a merge conflict?) to put it back. I don't the objection.
Jason
Robin Murphy
maintainerRe: [PATCH] arm64: swiotlb: Keep the default size for protected guests
Quoted 40 lines · Jason Gunthorpe
Quoted 23 lines · Will Deacon
Quoted 22 lines · Marek Szyprowski
Quoted 21 lines · Will Deacon
Quoted 20 lines · Aneesh Kumar K.V
Quoted 18 lines · Marek Szyprowski
Quoted 11 lines · Jason Gunthorpe
Quoted 6 lines · Mostafa Saleh
But the whole thing is best effort anyway, the kernel picks
IO_TLB_DEFAULT_SIZEwhich does not depend on the system topology or how many devices or how much DMA they do.
SWIOTLB memory is wasted if unused so we should be careful around that as it would be the other way around and users would have to decrease it manually.Yeah, it is why the arch code shouldn't really be sizing it directly, it should be done in common code and, yes, we are probably going to have to do something alot smarter to have the common code better auto-tune this for the CC case..
What about the $subject patch? I assume that it is still needed to
restore the behavior that was altered by the "[PATCH v8 00/23]
dma-mapping: Track shared DMA state through direct, pool and swiotlb
Quoted 8 lines
Quoted 8 lines
Quoted 6 lines
Quoted 4 lines
Quoted 2 lines
paths?" patchset?
I would request that we pick this patch to fix the regression described in https://lore.kernel.org/all/[email protected]/.
I really don't think we need it. CCA hardware isn't exactly widespread and the KVM host side patches don't appear close to being merged.
Does this mean that the branch for-next/coco [1] won't go to v7.3-rc1?
Let's not make progress on guest support contingent on KVM CCA host side patches please. I expect the CSPs will have VM instance types available based on CCA within quarters, and Linux as a Guest should work in those environments regardless of what KVM is doing. I don't really expect full KVM support for years, frankly, the patchset is massive. Even Intel and AMD don't have full KVM support yet.
Quoted 7 lines
People already have CCA capable HW, are already testing this stuff and the closer upstream can get to being workable as a guest without a mountain of OOT patches the better.
I agree the thing is not ideal, but it was merged to ARM like this a long time ago, this patch is just fixing a small oopsie (was it a merge conflict?) to put it back. I don't the objection.
Yup, it seems pretty clearly like a straightforward bug in this series (or maybe even just the merge resolution), where it should have just removed the use of SWIOTLB_FORCE, but changing the if/else structure inadvertently upset the whole flow in a way that it shouldn't have.
For a fix patch it might be clearer to restore the "(is_realm_world() || is_protected_kvm_guest())" condition exactly as before, then save any further refactoring for the next round of new development. And if there is a concern that skipping the resizing wastes memory for pKVM, then surely that falls on e62decaf98e7 ("arm64/coco: Add pKVM as a CC platform") which intentionally added that logic.
I do concur that there's not necessarily a mad panic to get this into Marek's 7.3 pull, as folks trying to use linux-next or bleeding-edge mainline for CCA work (or indeed anything) should know the risks, but it should at least be one for the 7.3-rc fixes cycle. Aneesh, FYI generally once things are queued, please just send follow-up fixes as their own thing rather than replies, for maximum clarity.
Thanks,
Robin.
Will Deacon
maintainerRe: [PATCH] arm64: swiotlb: Keep the default size for protected guests
In reply to Jason GunthorpeQuoted 31 lines · Jason Gunthorpe
Quoted 30 lines · Will Deacon
Quoted 29 lines · Marek Szyprowski
Quoted 27 lines · Will Deacon
Quoted 16 lines · Aneesh Kumar K.V
Quoted 14 lines · Marek Szyprowski
Quoted 11 lines · Jason Gunthorpe
Quoted 6 lines · Mostafa Saleh
But the whole thing is best effort anyway, the kernel picks
IO_TLB_DEFAULT_SIZEwhich does not depend on the system topology or how many devices or how much DMA they do.
SWIOTLB memory is wasted if unused so we should be careful around that as it would be the other way around and users would have to decrease it manually.Yeah, it is why the arch code shouldn't really be sizing it directly, it should be done in common code and, yes, we are probably going to have to do something alot smarter to have the common code better auto-tune this for the CC case..
What about the $subject patch? I assume that it is still needed to
Quoted 8 lines
Quoted 6 lines
restore the behavior that was altered by the "[PATCH v8 00/23]
dma-mapping: Track shared DMA state through direct, pool and swiotlb
paths?" patchset?
I would request that we pick this patch to fix the regression described in https://lore.kernel.org/all/[email protected]/.
I really don't think we need it. CCA hardware isn't exactly widespread and the KVM host side patches don't appear close to being merged.
Quoted 8 lines
Quoted 1 line
Quoted 1 line
Does this mean that the branch for-next/coco [1] won't go to v7.3-rc1?
Let's not make progress on guest support contingent on KVM CCA host side patches please. I expect the CSPs will have VM instance types available based on CCA within quarters, and Linux as a Guest should work in those environments regardless of what KVM is doing. I don't really expect full KVM support for years, frankly, the patchset is massive. Even Intel and AMD don't have full KVM support yet.
To be clear: the only part I'm pushing back on is the realm-specific hack to size the SWIOTLB area in arch/arm64/. Even with that hack applied, I don't believe a one-size-fits-all value is going to work for everybody, so it was really great to see that special-case removed in:
https://lore.kernel.org/all/[email protected]/
but now, because it regresses some test configuration, the proposal was to penalise protected VMs too (bearing in mind that the patch above hasn't yet landed upstream):
https://lore.kernel.org/all/[email protected]/
with the alternative being to reintroduce the original hack that we just removed!
https://lore.kernel.org/all/[email protected]/
I'm saying: merge the patches as they are, without reintroducing this horrible bodge in the architecture code to drive a heuristic that most people seem to agree should be handled more robustly elsewhere.
Quoted 3 lines
People already have CCA capable HW, are already testing this stuff and the closer upstream can get to being workable as a guest without a mountain of OOT patches the better.
This specific part is about a single line of code, to control something which is already configurable in Kconfig and on the cmdline. It's not a mountain of out-of-tree patches.
Quoted 3 lines
I agree the thing is not ideal, but it was merged to ARM like this a long time ago, this patch is just fixing a small oopsie (was it a merge conflict?) to put it back. I don't the objection.
My main objection is that I have very little confidence in people trying to fix this properly if we take the realm-specific bodge in the arch code. With all the CCA patches floating about already, why would they?
Will
Catalin Marinas
maintainerRe: [PATCH] arm64: swiotlb: Keep the default size for protected guests
Quoted 41 lines · Will Deacon
Quoted 31 lines · Jason Gunthorpe
Quoted 30 lines · Will Deacon
Quoted 29 lines · Marek Szyprowski
Quoted 27 lines · Will Deacon
Quoted 16 lines · Aneesh Kumar K.V
Quoted 14 lines · Marek Szyprowski
Quoted 11 lines · Jason Gunthorpe
Quoted 6 lines · Mostafa Saleh
But the whole thing is best effort anyway, the kernel picks
IO_TLB_DEFAULT_SIZEwhich does not depend on the system topology or how many devices or how much DMA they do.
SWIOTLB memory is wasted if unused so we should be careful around that as it would be the other way around and users would have to decrease it manually.Yeah, it is why the arch code shouldn't really be sizing it directly, it should be done in common code and, yes, we are probably going to have to do something alot smarter to have the common code better auto-tune this for the CC case..
What about the $subject patch? I assume that it is still needed to
Quoted 8 lines
Quoted 6 lines
restore the behavior that was altered by the "[PATCH v8 00/23]
dma-mapping: Track shared DMA state through direct, pool and swiotlb
paths?" patchset?
I would request that we pick this patch to fix the regression described in https://lore.kernel.org/all/[email protected]/.
I really don't think we need it. CCA hardware isn't exactly widespread and the KVM host side patches don't appear close to being merged.
Quoted 8 lines
Quoted 1 line
Quoted 1 line
Does this mean that the branch for-next/coco [1] won't go to v7.3-rc1?
Let's not make progress on guest support contingent on KVM CCA host side patches please. I expect the CSPs will have VM instance types available based on CCA within quarters, and Linux as a Guest should work in those environments regardless of what KVM is doing. I don't really expect full KVM support for years, frankly, the patchset is massive. Even Intel and AMD don't have full KVM support yet.
Quoted 6 lines
To be clear: the only part I'm pushing back on is the realm-specific hack to size the SWIOTLB area in
arch/arm64/. Even with that hack applied, I don't believe a one-size-fits-all value is going to work for everybody, so it was really great to see that special-case removed in:
We had Mostafa's patch here:
https://lore.kernel.org/all/[email protected]/
adding the same swiotlb buffer allocation for pKVM guests and realms.
Aneesh's cleanup of SWIOTLB_FORCE inadvertently removed the 'else' clause and limited_addressing is now always checked, meaning that we get size limiting irrespective of whether we still need a default swiotlb.
Normally I would consider this a regression on top of mainline and Mostafa's patches rather than a cleanup. However, if the default size of the bounce buffer was never sufficient for realms, as you said, we may need something better here anyway, so not worth fixing.
I can see x86 in mem_encrypt_setup_arch() adjusting the bounce buffer to 6% of the guest memory. We could make up similar logic for arm64 or we could just rely on CONFIG_SWIOTLB_DYNAMIC (default off currently for arm64 I think).
Signature · 1 line
Catalin
Will Deacon
maintainerRe: [PATCH] arm64: swiotlb: Keep the default size for protected guests
Quoted 47 lines · Catalin Marinas
Quoted 46 lines · Will Deacon
Quoted 31 lines · Jason Gunthorpe
Quoted 30 lines · Will Deacon
Quoted 29 lines · Marek Szyprowski
Quoted 27 lines · Will Deacon
Quoted 16 lines · Aneesh Kumar K.V
Quoted 14 lines · Marek Szyprowski
Quoted 11 lines · Jason Gunthorpe
Quoted 6 lines · Mostafa Saleh
But the whole thing is best effort anyway, the kernel picks
IO_TLB_DEFAULT_SIZEwhich does not depend on the system topology or how many devices or how much DMA they do.
SWIOTLB memory is wasted if unused so we should be careful around that as it would be the other way around and users would have to decrease it manually.Yeah, it is why the arch code shouldn't really be sizing it directly, it should be done in common code and, yes, we are probably going to have to do something alot smarter to have the common code better auto-tune this for the CC case..
What about the $subject patch? I assume that it is still needed to
Quoted 8 lines
Quoted 6 lines
restore the behavior that was altered by the "[PATCH v8 00/23]
dma-mapping: Track shared DMA state through direct, pool and swiotlb
paths?" patchset?
I would request that we pick this patch to fix the regression described in https://lore.kernel.org/all/[email protected]/.
I really don't think we need it. CCA hardware isn't exactly widespread and the KVM host side patches don't appear close to being merged.
Quoted 8 lines
Quoted 1 line
Quoted 1 line
Does this mean that the branch for-next/coco [1] won't go to v7.3-rc1?
Let's not make progress on guest support contingent on KVM CCA host side patches please. I expect the CSPs will have VM instance types available based on CCA within quarters, and Linux as a Guest should work in those environments regardless of what KVM is doing. I don't really expect full KVM support for years, frankly, the patchset is massive. Even Intel and AMD don't have full KVM support yet.
To be clear: the only part I'm pushing back on is the realm-specific hack to size the SWIOTLB area in
arch/arm64/. Even with that hack applied, I don't believe a one-size-fits-all value is going to work for everybody, so it was really great to see that special-case removed in:
Quoted 7 lines
Quoted 1 line
We had Mostafa's patch here:
https://lore.kernel.org/all/[email protected]/
adding the same swiotlb buffer allocation for pKVM guests and realms.
Yes, and I think that's bad for pKVM guests which is why I'm happy to see that part removed.
Quoted 3 lines
Aneesh's cleanup of
SWIOTLB_FORCEinadvertently removed the 'else' clause andlimited_addressingis now always checked, meaning that we get size limiting irrespective of whether we still need a default swiotlb.
Inadvertently, perhaps, but it's got Tested-bys from three different companies on it and I think it's a good change. I don't think we should be special-casing these environments based on some random collection of virtio devices in a testing setup.
Quoted 9 lines
Normally I would consider this a regression on top of mainline and Mostafa's patches rather than a cleanup. However, if the default size of the bounce buffer was never sufficient for realms, as you said, we may need something better here anyway, so not worth fixing.
I can see x86 in
mem_encrypt_setup_arch()adjusting the bounce buffer to 6% of the guest memory. We could make up similar logic for arm64 or we could just rely onCONFIG_SWIOTLB_DYNAMIC(default off currently for arm64 I think).
As Jason said, this should be done outside the arch code.
Will
Catalin Marinas
maintainerRe: [PATCH] arm64: swiotlb: Keep the default size for protected guests
Quoted 7 lines · Will Deacon
Quoted 4 lines · Catalin Marinas
I can see x86 in
mem_encrypt_setup_arch()adjusting the bounce buffer to 6% of the guest memory. We could make up similar logic for arm64 or we could just rely onCONFIG_SWIOTLB_DYNAMIC(default off currently for arm64 I think).As Jason said, this should be done outside the arch code.
I agree, better in the core code. I'd prefer to go for some dynamic resizing than random percentage of guest memory like x86 (but, in the absence of dynamic swiotlb, we could pick some default).
I noticed we still have a small change in behaviour regarding dynamic swiotlb. The increment for new allocations is based on default_nslabs which is reduced with the new patches. It gets even weirder if one sets the same IO_TLB_DEFAULT_SIZE on the kernel command line, it will be overridden by swiotlb_adjust_size() anyway.
I think this core code needs a bit more tidying up.
Signature · 1 line
Catalin
Re: [PATCH] arm64: swiotlb: Keep the default size for protected guests
In reply to Jason GunthorpeQuoted 40 lines · Jason Gunthorpe
Quoted 23 lines · Will Deacon
Quoted 22 lines · Marek Szyprowski
Quoted 21 lines · Will Deacon
Quoted 20 lines · Aneesh Kumar K.V
Quoted 18 lines · Marek Szyprowski
Quoted 11 lines · Jason Gunthorpe
Quoted 6 lines · Mostafa Saleh
But the whole thing is best effort anyway, the kernel picks
IO_TLB_DEFAULT_SIZEwhich does not depend on the system topology or how many devices or how much DMA they do.
SWIOTLB memory is wasted if unused so we should be careful around that as it would be the other way around and users would have to decrease it manually.Yeah, it is why the arch code shouldn't really be sizing it directly, it should be done in common code and, yes, we are probably going to have to do something alot smarter to have the common code better auto-tune this for the CC case..
What about the $subject patch? I assume that it is still needed to
restore the behavior that was altered by the "[PATCH v8 00/23]
dma-mapping: Track shared DMA state through direct, pool and swiotlb
Quoted 8 lines
Quoted 8 lines
Quoted 6 lines
Quoted 4 lines
Quoted 2 lines
paths?" patchset?
I would request that we pick this patch to fix the regression described in https://lore.kernel.org/all/[email protected]/.
I really don't think we need it. CCA hardware isn't exactly widespread and the KVM host side patches don't appear close to being merged.
Does this mean that the branch for-next/coco [1] won't go to v7.3-rc1?
Let's not make progress on guest support contingent on KVM CCA host side patches please. I expect the CSPs will have VM instance types available based on CCA within quarters, and Linux as a Guest should work in those environments regardless of what KVM is doing. I don't really expect full KVM support for years, frankly, the patchset is massive. Even Intel and AMD don't have full KVM support yet.
Quoted 8 lines
People already have CCA capable HW, are already testing this stuff and the closer upstream can get to being workable as a guest without a mountain of OOT patches the better.
I agree the thing is not ideal, but it was merged to ARM like this a long time ago, this patch is just fixing a small oopsie (was it a merge conflict?) to put it back. I don't the objection.
It was not a merge conflict issue. The change was introduced by an incorrect rebase I did when updating the patch series on top of the pKVM changes.
-aneesh
Re: [PATCH] arm64: swiotlb: Keep the default size for protected guests
In reply to Jason GunthorpeQuoted 24 lines · Jason Gunthorpe
Quoted 6 lines · Will Deacon
Quoted 2 lines
I was under the impression that there is a possibility of using swiotlb instead of restricted-dma-pool with pKVM.
Yes, that patch enables swiotlb as a possibility for protected guests but with your patch we avoid shrinking the swiotlb buffer even when restricted dma pools are being used and that's a waste of memory.
I also thought we switched pkvm to use CC-like swiotlb as part of the alignment in this rework? Mostafa ?
Quoted 11 lines
Quoted 7 lines
If that is not the case, then we could change:
!cc_platform_has(CC_ATTR_GUEST_MEM_ENCRYPT) &&
to
!is_realm_world() &&
Perhaps, or you could just pass the swiotlb= option if the defaults don't work for you. Can you give more details about the slots exhaustion you're seeing under CCA?
Quoted 7 lines
We see badness with swiotlb too, it basically doesn't work out of the box if you have to use it 100% for real devices. It easily runs out of memory.
Auto tuning to higher levels makes sense to me, but I'd rather the core code handled adjusting its size to the estimated need, not arch code.
Agreed
-aneesh
RE: [PATCH] arm64: swiotlb: Keep the default size for protected guests
From: Aneesh Kumar K.V <[email protected]> Sent: Friday, August 7, 2026 11:01 AM
Quoted 31 lines
Quoted 28 lines · Jason Gunthorpe
Quoted 6 lines · Will Deacon
Quoted 2 lines
I was under the impression that there is a possibility of using swiotlb instead of restricted-dma-pool with pKVM.
Yes, that patch enables swiotlb as a possibility for protected guests but with your patch we avoid shrinking the swiotlb buffer even when restricted dma pools are being used and that's a waste of memory.
I also thought we switched pkvm to use CC-like swiotlb as part of the alignment in this rework? Mostafa ?
Quoted 11 lines
Quoted 7 lines
If that is not the case, then we could change:
!cc_platform_has(CC_ATTR_GUEST_MEM_ENCRYPT) &&
to
!is_realm_world() &&
Perhaps, or you could just pass the swiotlb= option if the defaults don't work for you. Can you give more details about the slots exhaustion you're seeing under CCA?
We see badness with swiotlb too, it basically doesn't work out of the box if you have to use it 100% for real devices. It easily runs out of memory.
Quoted 5 lines
Quoted 3 lines
Auto tuning to higher levels makes sense to me, but I'd rather the core code handled adjusting its size to the estimated need, not arch code.
Agreed
Nobody has mentioned it on this thread, but arch code under x86 has a heuristic for sizing the swiotlb for SEV-SNP and TDX. The heuristic is 6% of guest memory, with a max of 1 GiB. See mem_encrypt_setup_arch(). The heuristic originally went into the 5.11 kernel nearly 6 years ago for the original SEV support and hasn't changed since. See commit e998879d4fb79, which doesn't give much of an explanation. I don't think this is necessarily a good heuristic -- it tends to waste a lot of memory, but there are also a few cases where it isn't enough memory. After a few years of experience with SEV and TDX, nobody seems to have tried to come up with something better, so maybe it's not all that bad.
No doubt the heuristic should move into common code so CCA, SEV, and TDX all use the same one.
Michael
Robin Murphy
maintainerRe: [PATCH] arm64: swiotlb: Keep the default size for protected guests
Quoted 50 lines · Michael Kelley
From: Aneesh Kumar K.V <[email protected]> Sent: Friday, August 7, 2026 11:01 AM
Quoted 31 lines
Quoted 28 lines · Jason Gunthorpe
Quoted 6 lines · Will Deacon
Quoted 2 lines
I was under the impression that there is a possibility of using swiotlb instead of restricted-dma-pool with pKVM.
Yes, that patch enables swiotlb as a possibility for protected guests but with your patch we avoid shrinking the swiotlb buffer even when restricted dma pools are being used and that's a waste of memory.
I also thought we switched pkvm to use CC-like swiotlb as part of the alignment in this rework? Mostafa ?
Quoted 11 lines
Quoted 7 lines
If that is not the case, then we could change:
!cc_platform_has(CC_ATTR_GUEST_MEM_ENCRYPT) &&
to
!is_realm_world() &&
Perhaps, or you could just pass the swiotlb= option if the defaults don't work for you. Can you give more details about the slots exhaustion you're seeing under CCA?
We see badness with swiotlb too, it basically doesn't work out of the box if you have to use it 100% for real devices. It easily runs out of memory.
Quoted 5 lines
Quoted 3 lines
Auto tuning to higher levels makes sense to me, but I'd rather the core code handled adjusting its size to the estimated need, not arch code.
Agreed
Nobody has mentioned it on this thread, but arch code under x86 has a heuristic for sizing the swiotlb for SEV-SNP and TDX. The heuristic is 6% of guest memory, with a max of 1 GiB. See
mem_encrypt_setup_arch(). The heuristic originally went into the 5.11 kernel nearly 6 years ago for the original SEV support and hasn't changed since. See commite998879d4fb79, which doesn't give much of an explanation. I don't think this is necessarily a good heuristic -- it tends to waste a lot of memory, but there are also a few cases where it isn't enough memory. After a few years of experience with SEV and TDX, nobody seems to have tried to come up with something better, so maybe it's not all that bad.
Quoted 2 lines
No doubt the heuristic should move into common code so CCA, SEV, and TDX all use the same one.
Indeed that would probably make sense as a future refactoring, as I would assume the general expectations of CoCo environments should be largely independent from the specific technology of either "Co" :)
However, note that currently the arch checks are effectively serving opposite purposes - x86 is specifically *increasing* the default SWIOTLB size for SEV/TDX, while the arm64 check (and RISC-V copy), is about *reducing* the default size if we think we (mostly) don't need it.
Thanks,
Robin.
Re: [PATCH] arm64: swiotlb: Keep the default size for protected guests
In reply to Will DeaconQuoted 66 lines · Will Deacon
Quoted 65 lines · Aneesh Kumar K.V
Quoted 22 lines · Will Deacon
Quoted 21 lines · Aneesh Kumar K.V (Arm)
Realm guests and protected KVM guests may require swiotlb for device DMA even when all system RAM is addressable by the DMA zones.
Do not reduce the SWIOTLB buffer to the kmalloc-bouncing size for these guests, as the reduced number of slots can be exhausted during CCA guest operation.
Fixes 30c5e45ee2c5 ("dma-direct: make dma_direct_map_phys() honor DMA_ATTR_CC_SHARED")Signed-off-by Aneesh Kumar K.V (Arm) <[email protected]>--- arch/arm64/mm/init.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)arch/arm64/mm/init.c +0
-0@@ -339,7 +339,8 @@ void __init arch_mm_preinit(void) {unsigned int flags =SWIOTLB_VERBOSE ;Quoted 7 lines
arch/arm64/mm/init.c void __init arch_mm_preinit(void) · line 343
Quoted 3 lines
arch/arm64/mm/init.c +2
-1-if (max_pfn <=PFN_DOWN (arm64_dma_phys_limit)) { +if (!cc_platform_has (CC_ATTR_GUEST_MEM_ENCRYPT ) && + max_pfn <=PFN_DOWN (arm64_dma_phys_limit)) {Protected guests under pKVM rely on restricted DMA, so won't this just waste memory for them?
commit
30c5e45ee2c5("dma-direct: makedma_direct_map_phys()honorDMA_ATTR_CC_SHARED"), which this patch fixes, hasarch/arm64/mm/init.c +1
-3@@ -339,9 +339,7 @@ void __init arch_mm_preinit(void) {unsigned int flags =SWIOTLB_VERBOSE ; -if (is_realm_world () ||is_protected_kvm_guest ()) { - flags |=SWIOTLB_FORCE ; - }else if (max_pfn <=PFN_DOWN (arm64_dma_phys_limit)) { +if (max_pfn <=PFN_DOWN (arm64_dma_phys_limit)) {/* * If no bouncing needed for ZONE_DMA, reduce the swiotlb * buffer for kmalloc() bouncing to 1MB per 1GB of RAM. The
is_protected_kvm_guest()part was added by the commite62decaf98e7("arm64/coco: Add pKVM as a CC platform")arch/arm64/mm/init.c +1
-1@@ -337,7 +339,7 @@ void __init arch_mm_preinit(void) {unsigned int flags =SWIOTLB_VERBOSE ; -if (is_realm_world ()) { +if (is_realm_world () ||is_protected_kvm_guest ()) { flags |=SWIOTLB_FORCE ; }else if (max_pfn <=PFN_DOWN (arm64_dma_phys_limit)) {/* @@ -412,6 +414,17 @@ void dump_mem_limit(void) } }
Quoted 7 lines
Quoted 2 lines
I was under the impression that there is a possibility of using swiotlb instead of restricted-dma-pool with pKVM.
Yes, that patch enables swiotlb as a possibility for protected guests but with your patch we avoid shrinking the swiotlb buffer even when restricted dma pools are being used and that's a waste of memory.
The patch restores the behavior to what it was before that commit. That is, for both CCA and pKVM, we don't do the max_pfn check, and hence the swiotlb is never resized.
Quoted 5 lines
Quoted 5 lines
If that is not the case, then we could change:
!cc_platform_has(CC_ATTR_GUEST_MEM_ENCRYPT) &&
Quoted 7 lines
Quoted 3 lines
to
!is_realm_world() &&
Perhaps, or you could just pass the swiotlb= option if the defaults don't work for you. Can you give more details about the slots exhaustion you're seeing under CCA?
That is definitely possible. However, on arm64, the current code further reduces the default swiotlb size when max_pfn < arm64_dma_phys_limit. That reduction is only correct when swiotlb is being used as a bounce buffer because of arm64_dma_phys_limit.
With CCA, that is not the case. We use swiotlb to bounce DMA for untrusted devices. Therefore, reducing the default swiotlb size based on max_pfn is not correct for CCA configurations.
This change in behavior is also a regression for CCA. CCA configurations that booted successfully before now gives the error below.
[ 39.848004] virtio-pci 0000:00:04.0: swiotlb buffer is full (sz: 262144 bytes), total 256 (slots), used 159 (slots) [ 40.002654] virtio-pci 0000:00:04.0: swiotlb buffer is full (sz: 262144 bytes), total 256 (slots), used 159 (slots) [ 40.165933] virtio-pci 0000:00:04.0: swiotlb buffer is full (sz: 262144 bytes), total 256 (slots), used 159 (slots) [ 40.325465] virtio-pci 0000:00:04.0: swiotlb buffer is full (sz: 262144 bytes), total 512 (slots), used 415 (slots) [ 40.485932] virtio-pci 0000:00:04.0: swiotlb buffer is full (sz: 204800 bytes), total 768 (slots), used 671 (slots) [ 42.485337] EXT4-fs (vda): re-mounted 6870157e-2795-475e-aad6-3a05725fb7cf. [ 43.799800] virtio-pci 0000:00:04.0: swiotlb buffer is full (sz: 262144 bytes), total 1280 (slots), used 1153 (slots) [ 44.016682] virtio-pci 0000:00:04.0: swiotlb buffer is full (sz: 262144 bytes), total 1280 (slots), used 1153 (slots) [ 44.226566] virtio-pci 0000:00:04.0: swiotlb buffer is full (sz: 262144 bytes), total 1536 (slots), used 1409 (slots) [ 44.437194] virtio-pci 0000:00:04.0: swiotlb buffer is full (sz: 262144 bytes), total 1792 (slots), used 1665 (slots)
-aneesh
PATCH v8 18/23 dma-direct: set decrypted flag for remapped DMA allocations
In reply to Aneesh Kumar K.V (Arm)Devices that are DMA non-coherent and require a remap were skipping dma_set_decrypted(), leaving DMA buffers encrypted even when the device requires unencrypted access. Move the call after the if (remap) branch so that both the direct and remapped allocation paths correctly mark the allocation as decrypted (or fail cleanly) before use.
Fix dma_direct_alloc() and dma_direct_free() to apply set_memory_*() to the linear-map alias of the backing pages instead of the remapped CPU address. Also disallow highmem pages for __DMA_ATTR_ALLOC_CC_SHARED, because highmem buffers do not provide a usable linear-map address.
--- kernel/dma/direct.c | 56 +++++++++++++++++++++++++++++++++++---------- 1 file changed, 44 insertions(+), 12 deletions(-)
kernel/dma/direct.c +44 -12
@@ -198,14 +198,23 @@ void *dma_direct_alloc(struct device *dev, size_t size, {bool remap = false, set_uncached = false;bool mark_mem_decrypt = false; +bool allow_highmem = true;struct page *page;void *ret;if (force_dma_unencrypted (dev)) attrs |= __DMA_ATTR_ALLOC_CC_SHARED; -if (attrs & __DMA_ATTR_ALLOC_CC_SHARED) +if (attrs & __DMA_ATTR_ALLOC_CC_SHARED) { +/* +* Unencrypted/shared DMA requires a linear-mapped buffer +* address to look up the PFN and set architecture-required PFN +* attributes. This is not possible with HighMem. Avoid HighMem +* allocation. +*/ + allow_highmem = false; mark_mem_decrypt = true; + } size =PAGE_ALIGN (size);if (attrs &DMA_ATTR_NO_WARN )
@@ -270,7 +279,7 @@ void *dma_direct_alloc(struct device *dev, size_t size, }/* we always manually zero the memory once we are done */ - page =__dma_direct_alloc_pages (dev, size, gfp & ~__GFP_ZERO, true); + page =__dma_direct_alloc_pages (dev, size, gfp & ~__GFP_ZERO, allow_highmem);if (!page)return NULL ;
@@ -285,6 +294,14 @@ void *dma_direct_alloc(struct device *dev, size_t size, set_uncached = false; } +if (mark_mem_decrypt) { +void *lm_addr; + + lm_addr =page_address (page); +if (set_memory_decrypted ((unsigned long )lm_addr,PFN_UP (size))) + goto out_leak_pages; + } +if (remap) {pgprot_t prot =dma_pgprot (dev,PAGE_KERNEL , attrs);
@@ -295,29 +312,36 @@ void *dma_direct_alloc(struct device *dev, size_t size, ret =dma_common_contiguous_remap (page, size, prot,__builtin_return_address (0 ));if (!ret) - goto out_free_pages; + goto out_encrypt_pages; }else { ret =page_address (page); -if (mark_mem_decrypt &&dma_set_decrypted (dev, ret, size)) - goto out_leak_pages; }memset (ret,0 , size);if (set_uncached) { +void *uncached_cpu_addr; +arch_dma_prep_coherent (page, size); - ret =arch_dma_set_uncached (ret, size); -if (IS_ERR (ret)) - goto out_encrypt_pages; + uncached_cpu_addr =arch_dma_set_uncached (ret, size); +if (IS_ERR (uncached_cpu_addr)) + goto out_free_remap_pages; + ret = uncached_cpu_addr; } *dma_handle =phys_to_dma_direct (dev,page_to_phys (page));return ret; + +out_free_remap_pages: +if (remap) +dma_common_free_remap (ret, size); + out_encrypt_pages: -if (mark_mem_decrypt &&dma_set_encrypted (dev,page_address (page), size)) -return NULL ; -out_free_pages: +if (mark_mem_decrypt && +dma_set_encrypted (dev,page_address (page), size)) + goto out_leak_pages; +if (!swiotlb_free (dev, page, size))dma_free_contiguous (dev, page, size);return NULL ;
@@ -380,8 +404,16 @@ void dma_direct_free(struct device *dev, size_t size, }else {if (IS_ENABLED (CONFIG_ARCH_HAS_DMA_CLEAR_UNCACHED ))arch_dma_clear_uncached (cpu_addr, size); -if (mark_mem_encrypted &&dma_set_encrypted (dev, cpu_addr, size)) + } + +if (mark_mem_encrypted) { +void *lm_addr; + + lm_addr =phys_to_virt (phys); +if (set_memory_encrypted ((unsigned long )lm_addr,PFN_UP (size))) { +pr_warn_ratelimited ("leaking DMA memory that can't be re-encrypted\n" );return ; + } }if (swiotlb_pool)
Signature · 1 line
2.43.0
PATCH v8 19/23 dma-direct: select DMA address encoding from __DMA_ATTR_ALLOC_CC_SHARED
In reply to Aneesh Kumar K.V (Arm)Make the dma-direct helpers derive the DMA address encoding from __DMA_ATTR_ALLOC_CC_SHARED instead of implicitly relying on force_dma_unencrypted() inside phys_to_dma_direct()
Pass an explicit unencrypted/decrypted state into phys_to_dma_direct(), make the alloc paths return DMA addresses that match the requested buffer encryption state. Also only call dma_set_decrypted() when __DMA_ATTR_ALLOC_CC_SHARED is actually set.
--- kernel/dma/direct.c | 43 ++++++++++++++++++++++++++----------------- 1 file changed, 26 insertions(+), 17 deletions(-)
kernel/dma/direct.c +26 -17
@@ -26,11 +26,11 @@u64 zone_dma_limit__ro_after_init =DMA_BIT_MASK (24 );static inline dma_addr_t phys_to_dma_direct (struct device *dev, -phys_addr_t phys) +phys_addr_t phys,bool unencrypted) { -if (force_dma_unencrypted (dev)) +if (unencrypted)return phys_to_dma_unencrypted (dev, phys); -return phys_to_dma (dev, phys); +return phys_to_dma_encrypted (dev, phys); } static inline struct page *dma_direct_to_page(struct device *dev,
@@ -41,8 +41,9 @@ static inline struct page *dma_direct_to_page(struct device *dev,u64 dma_direct_get_required_mask (struct device *dev) { +bool require_decrypted =force_dma_unencrypted (dev);phys_addr_t phys = ((phys_addr_t )max_pfn <<PAGE_SHIFT ) -1 ; -u64 max_dma =phys_to_dma_direct (dev, phys); +u64 max_dma =phys_to_dma_direct (dev, phys, require_decrypted);return (1ULL << (fls64 (max_dma) -1 )) *2 -1 ; }
@@ -71,7 +72,8 @@ static gfp_t dma_direct_optimal_gfp_mask(struct device *dev, u64 *phys_limit)bool dma_coherent_ok (struct device *dev,phys_addr_t phys,size_t size) { -dma_addr_t dma_addr =phys_to_dma_direct (dev, phys); +bool require_decrypted =force_dma_unencrypted (dev); +dma_addr_t dma_addr =phys_to_dma_direct (dev, phys, require_decrypted);if (dma_addr ==DMA_MAPPING_ERROR )return false;
@@ -81,17 +83,18 @@ bool dma_coherent_ok(struct device *dev, phys_addr_t phys, size_t size)static int dma_set_decrypted (struct device *dev,void *vaddr,size_t size) { -if (!force_dma_unencrypted (dev)) -return 0 ; -return set_memory_decrypted ((unsigned long )vaddr,PFN_UP (size)); +int ret; + + ret =set_memory_decrypted ((unsigned long )vaddr,PFN_UP (size)); +if (ret) +pr_warn_ratelimited ("leaking DMA memory that can't be decrypted\n" ); +return ret; }static int dma_set_encrypted (struct device *dev,void *vaddr,size_t size) {int ret; -if (!force_dma_unencrypted (dev)) -return 0 ; ret =set_memory_encrypted ((unsigned long )vaddr,PFN_UP (size));if (ret)pr_warn_ratelimited ("leaking DMA memory that can't be re-encrypted\n" );
@@ -171,7 +174,8 @@ static struct page *dma_direct_alloc_from_pool(struct device *dev, size_t size, dma_coherent_ok);if (!page)return NULL ; - *dma_handle =phys_to_dma_direct (dev,page_to_phys (page)); + *dma_handle =phys_to_dma_direct (dev,page_to_phys (page), + attrs & __DMA_ATTR_ALLOC_CC_SHARED);return page; }
@@ -187,9 +191,11 @@ static void *dma_direct_alloc_no_mapping(struct device *dev, size_t size,/* remove any dirty cache lines on the kernel alias */ if (!PageHighMem (page))arch_dma_prep_coherent (page, size); - -/* return the page pointer as the opaque cookie */ - *dma_handle =phys_to_dma_direct (dev,page_to_phys (page)); +/* +* return the page pointer as the opaque cookie. +* Never used for unencrypted allocation +*/ + *dma_handle =phys_to_dma_encrypted (dev,page_to_phys (page));return page; }
@@ -329,7 +335,8 @@ void *dma_direct_alloc(struct device *dev, size_t size, ret = uncached_cpu_addr; } - *dma_handle =phys_to_dma_direct (dev,page_to_phys (page)); + *dma_handle =phys_to_dma_direct (dev,page_to_phys (page), + attrs & __DMA_ATTR_ALLOC_CC_SHARED);return ret;
@@ -450,11 +457,13 @@ struct page *dma_direct_alloc_pages(struct device *dev, size_t size,return NULL ; ret =page_address (page); -if (dma_set_decrypted (dev, ret, size)) +if ((attrs & __DMA_ATTR_ALLOC_CC_SHARED) && +dma_set_decrypted (dev, ret, size)) goto out_leak_pages; setup_page:memset (ret,0 , size); - *dma_handle =phys_to_dma_direct (dev,page_to_phys (page)); + *dma_handle =phys_to_dma_direct (dev,page_to_phys (page), + attrs & __DMA_ATTR_ALLOC_CC_SHARED);return page; out_leak_pages:return NULL ;
Signature · 1 line
2.43.0
Re: [PATCH v8 19/23] dma-direct: select DMA address encoding from __DMA_ATTR_ALLOC_CC_SHARED
Quoted 9 lines · Aneesh Kumar K.V (Arm)
Make the dma-direct helpers derive the DMA address encoding from
__DMA_ATTR_ALLOC_CC_SHAREDinstead of implicitly relying onforce_dma_unencrypted()insidephys_to_dma_direct()Pass an explicit unencrypted/decrypted state into
phys_to_dma_direct(), make the alloc paths return DMA addresses that match the requested buffer encryption state. Also only calldma_set_decrypted()when__DMA_ATTR_ALLOC_CC_SHAREDis actually set.
Quoted 5 lines
Reviewed-by Jason Gunthorpe <[email protected]>Tested-by Jiri Pirko <[email protected]>Tested-by Michael Kelley <[email protected]>Tested-by Mostafa Saleh <[email protected]>Signed-off-by Aneesh Kumar K.V (Arm) <[email protected]>
Thanks,
Mostafa
Quoted 122 lines
--- kernel/dma/direct.c | 43 ++++++++++++++++++++++++++----------------- 1 file changed, 26 insertions(+), 17 deletions(-)kernel/dma/direct.c +26
-17@@ -26,11 +26,11 @@u64 zone_dma_limit__ro_after_init =DMA_BIT_MASK (24 );static inline dma_addr_t phys_to_dma_direct (struct device *dev, -phys_addr_t phys) +phys_addr_t phys,bool unencrypted) { -if (force_dma_unencrypted (dev)) +if (unencrypted)return phys_to_dma_unencrypted (dev, phys); -return phys_to_dma (dev, phys); +return phys_to_dma_encrypted (dev, phys); } static inline struct page *dma_direct_to_page(struct device *dev,@@ -41,8 +41,9 @@ static inline struct page *dma_direct_to_page(struct device *dev,u64 dma_direct_get_required_mask (struct device *dev) { +bool require_decrypted =force_dma_unencrypted (dev);phys_addr_t phys = ((phys_addr_t )max_pfn <<PAGE_SHIFT ) -1 ; -u64 max_dma =phys_to_dma_direct (dev, phys); +u64 max_dma =phys_to_dma_direct (dev, phys, require_decrypted);return (1ULL << (fls64 (max_dma) -1 )) *2 -1 ; }@@ -71,7 +72,8 @@ static gfp_t dma_direct_optimal_gfp_mask(struct device *dev, u64 *phys_limit)bool dma_coherent_ok (struct device *dev,phys_addr_t phys,size_t size) { -dma_addr_t dma_addr =phys_to_dma_direct (dev, phys); +bool require_decrypted =force_dma_unencrypted (dev); +dma_addr_t dma_addr =phys_to_dma_direct (dev, phys, require_decrypted);if (dma_addr ==DMA_MAPPING_ERROR )return false;@@ -81,17 +83,18 @@ bool dma_coherent_ok(struct device *dev, phys_addr_t phys, size_t size)static int dma_set_decrypted (struct device *dev,void *vaddr,size_t size) { -if (!force_dma_unencrypted (dev)) -return 0 ; -return set_memory_decrypted ((unsigned long )vaddr,PFN_UP (size)); +int ret; + + ret =set_memory_decrypted ((unsigned long )vaddr,PFN_UP (size)); +if (ret) +pr_warn_ratelimited ("leaking DMA memory that can't be decrypted\n" ); +return ret; }static int dma_set_encrypted (struct device *dev,void *vaddr,size_t size) {int ret; -if (!force_dma_unencrypted (dev)) -return 0 ; ret =set_memory_encrypted ((unsigned long )vaddr,PFN_UP (size));if (ret)pr_warn_ratelimited ("leaking DMA memory that can't be re-encrypted\n" );@@ -171,7 +174,8 @@ static struct page *dma_direct_alloc_from_pool(struct device *dev, size_t size, dma_coherent_ok);if (!page)return NULL ; - *dma_handle =phys_to_dma_direct (dev,page_to_phys (page)); + *dma_handle =phys_to_dma_direct (dev,page_to_phys (page), + attrs & __DMA_ATTR_ALLOC_CC_SHARED);return page; }@@ -187,9 +191,11 @@ static void *dma_direct_alloc_no_mapping(struct device *dev, size_t size,/* remove any dirty cache lines on the kernel alias */ if (!PageHighMem (page))arch_dma_prep_coherent (page, size); - -/* return the page pointer as the opaque cookie */ - *dma_handle =phys_to_dma_direct (dev,page_to_phys (page)); +/* +* return the page pointer as the opaque cookie. +* Never used for unencrypted allocation +*/ + *dma_handle =phys_to_dma_encrypted (dev,page_to_phys (page));return page; }@@ -329,7 +335,8 @@ void *dma_direct_alloc(struct device *dev, size_t size, ret = uncached_cpu_addr; } - *dma_handle =phys_to_dma_direct (dev,page_to_phys (page)); + *dma_handle =phys_to_dma_direct (dev,page_to_phys (page), + attrs & __DMA_ATTR_ALLOC_CC_SHARED);return ret;@@ -450,11 +457,13 @@ struct page *dma_direct_alloc_pages(struct device *dev, size_t size,return NULL ; ret =page_address (page); -if (dma_set_decrypted (dev, ret, size)) +if ((attrs & __DMA_ATTR_ALLOC_CC_SHARED) && +dma_set_decrypted (dev, ret, size)) goto out_leak_pages; setup_page:memset (ret,0 , size); - *dma_handle =phys_to_dma_direct (dev,page_to_phys (page)); + *dma_handle =phys_to_dma_direct (dev,page_to_phys (page), + attrs & __DMA_ATTR_ALLOC_CC_SHARED);return page; out_leak_pages:return NULL ;Signature · 1 line
2.43.0
PATCH v8 20/23 dma-direct: rename ret to cpu_addr in alloc helpers
In reply to Aneesh Kumar K.V (Arm)ret in dma_direct_alloc() and dma_direct_alloc_pages() holds the returned CPU mapping, not a generic return value. Rename it to cpu_addr and update the remaining uses to match.
This makes the allocation paths easier to follow and keeps the local naming consistent with what the variable actually represents.
--- kernel/dma/direct.c | 40 ++++++++++++++++++++-------------------- 1 file changed, 20 insertions(+), 20 deletions(-)
kernel/dma/direct.c +20 -20
@@ -206,7 +206,7 @@ void *dma_direct_alloc(struct device *dev, size_t size,bool mark_mem_decrypt = false;bool allow_highmem = true;struct page *page; -void *ret; +void *cpu_addr;if (force_dma_unencrypted (dev)) attrs |= __DMA_ATTR_ALLOC_CC_SHARED;
@@ -266,9 +266,10 @@ void *dma_direct_alloc(struct device *dev, size_t size,*/ if ((remap || (attrs & __DMA_ATTR_ALLOC_CC_SHARED)) &&dma_direct_use_pool (dev, gfp)) { - page =dma_direct_alloc_from_pool (dev, size, dma_handle, - &ret, gfp, attrs); -return page ? ret :NULL ; + page =dma_direct_alloc_from_pool (dev, size, + dma_handle, &cpu_addr, + gfp, attrs); +return page ? cpu_addr :NULL ; }if (is_swiotlb_for_alloc (dev)) {
@@ -315,34 +316,33 @@ void *dma_direct_alloc(struct device *dev, size_t size,arch_dma_prep_coherent (page, size);/* create a coherent mapping */ - ret =dma_common_contiguous_remap (page, size, prot, -__builtin_return_address (0 )); -if (!ret) + cpu_addr =dma_common_contiguous_remap (page, size, prot, +__builtin_return_address (0 )); +if (!cpu_addr) goto out_encrypt_pages; }else { - ret =page_address (page); + cpu_addr =page_address (page); } -memset (ret,0 , size); +memset (cpu_addr,0 , size);if (set_uncached) {void *uncached_cpu_addr;arch_dma_prep_coherent (page, size); - uncached_cpu_addr =arch_dma_set_uncached (ret, size); + uncached_cpu_addr =arch_dma_set_uncached (cpu_addr, size);if (IS_ERR (uncached_cpu_addr)) goto out_free_remap_pages; - ret = uncached_cpu_addr; + cpu_addr = uncached_cpu_addr; } *dma_handle =phys_to_dma_direct (dev,page_to_phys (page), attrs & __DMA_ATTR_ALLOC_CC_SHARED); -return ret; - +return cpu_addr; out_free_remap_pages:if (remap) -dma_common_free_remap (ret, size); +dma_common_free_remap (cpu_addr, size); out_encrypt_pages: if (mark_mem_decrypt &&
@@ -434,21 +434,21 @@ struct page *dma_direct_alloc_pages(struct device *dev, size_t size, {unsigned long attrs =0 ;struct page *page; -void *ret; +void *cpu_addr;if (force_dma_unencrypted (dev)) attrs |= __DMA_ATTR_ALLOC_CC_SHARED;if ((attrs & __DMA_ATTR_ALLOC_CC_SHARED) &&dma_direct_use_pool (dev, gfp))return dma_direct_alloc_from_pool (dev, size, dma_handle, - &ret, gfp, attrs); + &cpu_addr, gfp, attrs);if (is_swiotlb_for_alloc (dev)) { page =dma_direct_alloc_swiotlb (dev, size, attrs);if (!page)return NULL ; - ret =page_address (page); + cpu_addr =page_address (page); goto setup_page; }
@@ -456,12 +456,12 @@ struct page *dma_direct_alloc_pages(struct device *dev, size_t size,if (!page)return NULL ; - ret =page_address (page); + cpu_addr =page_address (page);if ((attrs & __DMA_ATTR_ALLOC_CC_SHARED) && -dma_set_decrypted (dev, ret, size)) +dma_set_decrypted (dev, cpu_addr, size)) goto out_leak_pages; setup_page: -memset (ret,0 , size); +memset (cpu_addr,0 , size); *dma_handle =phys_to_dma_direct (dev,page_to_phys (page), attrs & __DMA_ATTR_ALLOC_CC_SHARED);return page;
Signature · 1 line
2.43.0
PATCH v8 21/23 dma: swiotlb: free dynamic pools from process context
In reply to Aneesh Kumar K.V (Arm)swiotlb_dyn_free() is used after removing a dynamic swiotlb pool from RCU-protected lists. It can call swiotlb_free_tlb(), which may need to restore the encryption state of an unencrypted pool with set_memory_encrypted() before freeing the pages.
RCU callbacks run in atomic context, but set_memory_encrypted() is not guaranteed to be atomic-safe on all architectures. For example, page attribute updates may allocate page tables or take sleeping locks.
Use queue_rcu_work() for dynamic pool freeing instead. This keeps the RCU grace period before freeing a published pool, while running the actual pool teardown from workqueue context. Use the same helper for the transient-pool error path, since that path may also be reached from atomic DMA mapping context.
--- include/linux/swiotlb.h | 4 ++-- kernel/dma/swiotlb.c | 19 +++++++++++-------- 2 files changed, 13 insertions(+), 10 deletions(-)
include/linux/swiotlb.h +2 -2
@@ -64,7 +64,7 @@ extern void __init swiotlb_update_mem_attributes(void);* @areas: Array of memory area descriptors. * @slots: Array of slot descriptors. * @node: Member of the IO TLB memory pool list. -* @rcu: RCU head for swiotlb_dyn_free(). +* @dyn_free: RCU work item used to free the pool from process context. * @transient: %true if transient memory pool. * @cc_shared: %true if the pool memory is shared for confidential computing. */
@@ -80,7 +80,7 @@ struct io_tlb_pool {struct io_tlb_slot *slots;#ifdef CONFIG_SWIOTLB_DYNAMIC struct list_head node; -struct rcu_head rcu; +struct rcu_work dyn_free;bool transient;bool cc_shared;#endif
kernel/dma/swiotlb.c +11 -8
@@ -779,13 +779,10 @@ static void swiotlb_dyn_alloc(struct work_struct *work)add_mem_pool (mem, pool); } -/** -* swiotlb_dyn_free() - RCU callback to free a memory pool -* @rcu: RCU head in the corresponding struct io_tlb_pool. -*/ -static void swiotlb_dyn_free (struct rcu_head *rcu) +static void swiotlb_dyn_free_work (struct work_struct *work) { - struct io_tlb_pool *pool = container_of(rcu, struct io_tlb_pool, rcu); +struct io_tlb_pool *pool = + container_of(to_rcu_work(work), struct io_tlb_pool, dyn_free);size_t slots_size =array_size (sizeof (*pool->slots), pool->nslabs);size_t tlb_size = pool->end - pool->start;
@@ -794,6 +791,12 @@ static void swiotlb_dyn_free(struct rcu_head *rcu)kfree (pool); } +static void swiotlb_schedule_dyn_free (struct io_tlb_pool *pool) +{ +INIT_RCU_WORK (&pool->dyn_free, swiotlb_dyn_free_work); +queue_rcu_work (system_wq, &pool->dyn_free); +} +/** * __swiotlb_find_pool() - find the IO TLB pool for a physical address * @dev: Device which has mapped the DMA buffer.
@@ -840,7 +843,7 @@ static void swiotlb_del_pool(struct device *dev, struct io_tlb_pool *pool)list_del_rcu (&pool->node);spin_unlock_irqrestore (&dev->dma_io_tlb_lock, flags); - call_rcu(&pool->rcu, swiotlb_dyn_free); + swiotlb_schedule_dyn_free(pool); }#endif /* CONFIG_SWIOTLB_DYNAMIC */
@@ -1281,7 +1284,7 @@ static int swiotlb_find_slots(struct device *dev, phys_addr_t orig_addr, index =swiotlb_search_pool_area (dev, pool,0 , orig_addr, tbl_dma_addr, alloc_size, alloc_align_mask);if (index <0 ) { -swiotlb_dyn_free (&pool->rcu); +swiotlb_schedule_dyn_free (pool);return -1 ; }
Signature · 1 line
2.43.0
PATCH v8 22/23 dma: swiotlb: handle set_memory_decrypted() failures
In reply to Aneesh Kumar K.V (Arm)Check the return value when converting swiotlb pools between encrypted and decrypted mappings. If the default pool cannot be decrypted after early initialization, mark the pool fully used so it cannot satisfy future bounce allocations.
For late initialization, return the set_memory_decrypted() failure. For restricted DMA pools, fail device initialization if the reserved pool cannot be decrypted.
This prevents swiotlb from using pools whose encryption attributes do not match their metadata, and avoids returning pages with uncertain encryption state back to the allocator.
--- kernel/dma/swiotlb.c | 80 +++++++++++++++++++++++++++++++++++--------- 1 file changed, 65 insertions(+), 15 deletions(-)
kernel/dma/swiotlb.c +65 -15
@@ -248,6 +248,23 @@ static inline unsigned long nr_slots(u64 val)return DIV_ROUND_UP (val,IO_TLB_SIZE ); } +static void swiotlb_mark_pool_used (struct io_tlb_pool *pool) +{ +unsigned long i; + +for (i =0 ; i < pool->nareas; i++) { + pool->areas[i].index =0 ; + pool->areas[i].used = pool->area_nslabs; + } + +for (i =0 ; i < pool->nslabs; i++) { + pool->slots[i].list =0 ; + pool->slots[i].orig_addr =INVALID_PHYS_ADDR ; + pool->slots[i].alloc_size =0 ; + pool->slots[i].pad_slots =0 ; + } +} +/* * Early SWIOTLB allocation may be too early to allow an architecture to * perform the desired operations. This function allows the architecture to
@@ -272,8 +289,16 @@ void __init swiotlb_update_mem_attributes(void)return ; bytes =PAGE_ALIGN (mem->nslabs <<IO_TLB_SHIFT ); -if (io_tlb_default_mem.cc_shared) -set_memory_decrypted ((unsigned long )mem->vaddr, bytes >>PAGE_SHIFT ); +if (io_tlb_default_mem.cc_shared) { +int ret; + + ret =set_memory_decrypted ((unsigned long )mem->vaddr, + bytes >>PAGE_SHIFT ); +if (ret) { +pr_warn ("Failed to decrypt default memory pool, disabling it\n" ); +swiotlb_mark_pool_used (mem); + } + } } static void swiotlb_init_io_tlb_pool(struct io_tlb_pool *mem, phys_addr_t start,
@@ -442,9 +467,10 @@ int swiotlb_init_late(size_t size, gfp_t gfp_mask, {struct io_tlb_pool *mem = &io_tlb_default_mem.defpool;unsigned long nslabs =ALIGN (size >>IO_TLB_SHIFT ,IO_TLB_SEGSIZE ); +unsigned int order, area_order, slot_order; +bool leak_pages = false;unsigned int nareas;unsigned char *vstart =NULL ; -unsigned int order, area_order;bool retried = false;int rc =0 ;
@@ -504,6 +530,7 @@ int swiotlb_init_late(size_t size, gfp_t gfp_mask, (PAGE_SIZE << order) >> 20); } + rc = -ENOMEM ; nareas =limit_nareas (default_nareas, nslabs); area_order =get_order (array_size (sizeof (*mem->areas), nareas)); mem->areas = (struct io_tlb_area *)
@@ -511,14 +538,20 @@ int swiotlb_init_late(size_t size, gfp_t gfp_mask,if (!mem->areas) goto error_area; + slot_order =get_order (array_size (sizeof (*mem->slots), nslabs)); mem->slots = (void *)__get_free_pages (GFP_KERNEL | __GFP_ZERO, -get_order (array_size (sizeof (*mem->slots), nslabs))); + slot_order);if (!mem->slots) goto error_slots; -if (io_tlb_default_mem.cc_shared) -set_memory_decrypted ((unsigned long )vstart, - (nslabs <<IO_TLB_SHIFT ) >>PAGE_SHIFT ); +if (io_tlb_default_mem.cc_shared) { + rc =set_memory_decrypted ((unsigned long )vstart, + (nslabs <<IO_TLB_SHIFT ) >>PAGE_SHIFT ); +if (rc) { + leak_pages = true; + goto error_decrypt; + } + }swiotlb_init_io_tlb_pool (mem,virt_to_phys (vstart), vstart, nslabs, true, nareas);
@@ -527,16 +560,20 @@ int swiotlb_init_late(size_t size, gfp_t gfp_mask,swiotlb_print_info ();return 0 ; +error_decrypt: +free_pages ((unsigned long )mem->slots, slot_order); error_slots:free_pages ((unsigned long )mem->areas, area_order); error_area: -free_pages ((unsigned long )vstart, order); -return -ENOMEM ; +if (!leak_pages) +free_pages ((unsigned long )vstart, order); +return rc; }void __init swiotlb_exit (void ) {struct io_tlb_pool *mem = &io_tlb_default_mem.defpool; +bool leak_pages = false;unsigned long tbl_vaddr;size_t tbl_size, slots_size;unsigned int area_order;
@@ -552,19 +589,23 @@ void __init swiotlb_exit(void) tbl_size =PAGE_ALIGN (mem->end - mem->start); slots_size =PAGE_ALIGN (array_size (sizeof (*mem->slots), mem->nslabs)); -if (io_tlb_default_mem.cc_shared) -set_memory_encrypted (tbl_vaddr, tbl_size >>PAGE_SHIFT ); +if (io_tlb_default_mem.cc_shared) { +if (set_memory_encrypted (tbl_vaddr, tbl_size >>PAGE_SHIFT )) + leak_pages = true; + }if (mem->late_alloc) { area_order =get_order (array_size (sizeof (*mem->areas), mem->nareas));free_pages ((unsigned long )mem->areas, area_order); -free_pages (tbl_vaddr,get_order (tbl_size)); +if (!leak_pages) +free_pages (tbl_vaddr,get_order (tbl_size));free_pages ((unsigned long )mem->slots,get_order (slots_size)); }else {memblock_free (mem->areas,array_size (sizeof (*mem->areas), mem->nareas)); -memblock_phys_free (mem->start, tbl_size); +if (!leak_pages) +memblock_phys_free (mem->start, tbl_size);memblock_free (mem->slots, slots_size); }
@@ -1957,9 +1998,18 @@ static int rmem_swiotlb_device_init(struct reserved_mem *rmem,* restricted mem pool is shared by default */ if (cc_platform_has (CC_ATTR_MEM_ENCRYPT )) { +int ret; + mem->cc_shared = true; -set_memory_decrypted ((unsigned long )phys_to_virt (rmem->base), - rmem->size >>PAGE_SHIFT ); + ret =set_memory_decrypted ((unsigned long )phys_to_virt (rmem->base), + rmem->size >>PAGE_SHIFT ); +if (ret) { +dev_err (dev,"Failed to decrypt restricted DMA pool\n" ); +kfree (pool->areas); +kfree (pool->slots); +kfree (mem); +return ret; + } }else { mem->cc_shared = false; }
Signature · 1 line
2.43.0
PATCH v8 23/23 swiotlb: remove unused SWIOTLB_FORCE flag
In reply to Aneesh Kumar K.V (Arm)SWIOTLB_FORCE has no remaining in-tree users. Forced bouncing is now controlled through the swiotlb=force command line option via swiotlb_force_bounce.
Remove the unused flag and simplify the force_bounce initialization.
--- include/linux/swiotlb.h | 3 +-- kernel/dma/swiotlb.c | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-)
include/linux/swiotlb.h +1 -2
@@ -15,8 +15,7 @@ struct page;struct scatterlist ;#define SWIOTLB_VERBOSE (1 << 0)/* verbose initialization */ -#define SWIOTLB_FORCE (1 << 1)/* force bounce buffering */ -#define SWIOTLB_ANY (1 << 2)/* allow any memory for the buffer */ +#define SWIOTLB_ANY (1 << 1)/* allow any memory for the buffer */ /* * Maximum allowable number of contiguous slabs to map,
kernel/dma/swiotlb.c +1 -2
@@ -400,8 +400,7 @@ void __init swiotlb_init_remap(bool addressing_limit, unsigned int flags,if (swiotlb_force_disable)return ; - io_tlb_default_mem.force_bounce = - swiotlb_force_bounce || (flags &SWIOTLB_FORCE ); + io_tlb_default_mem.force_bounce = swiotlb_force_bounce;#ifdef CONFIG_SWIOTLB_DYNAMIC if (!remap)
Signature · 1 line
2.43.0
Quoted 3 lines · Aneesh Kumar K.V (Arm)
This series tracks confidential-computing shared DMA state through the dma-direct, dma-pool, and swiotlb paths so that encrypted and decrypted DMA buffers are handled consistently.
<...>
Quoted 4 lines
- makes
dma_direct_map_phys()choose the DMA address encoding fromDMA_ATTR_CC_SHAREDand fall back to swiotlb when a shared DMA request cannot use the direct mapping, which lets arm64 and x86 CCA guests stop relying onSWIOTLB_FORCEfor DMA mappings
Why don't we continue the effort to remove "struct page" entirely from the DMA API internals?
IMHO, everything not exposed to DMA API users should use phys_addr_t, including the DMA address pool.
Thanks
Quoted 5 lines · Leon Romanovsky
Why don't we continue the effort to remove "struct page" entirely from the DMA API internals?
IMHO, everything not exposed to DMA API users should use
phys_addr_t, including the DMA address pool.
The alloc interfaces return a struct page, that is why this stuff is organized like this. Look at dma_alloc_pages()
There is also an API that forms a scatterlist that has to be struct page as well
Jason
Quoted 10 lines · Jason Gunthorpe
Quoted 5 lines · Leon Romanovsky
Why don't we continue the effort to remove "struct page" entirely from the DMA API internals?
IMHO, everything not exposed to DMA API users should use
phys_addr_t, including the DMA address pool.The alloc interfaces return a struct page, that is why this stuff is organized like this. Look at
dma_alloc_pages()
And I didn't say that we should change dma_alloc_pages(). It is external API, which needs to be struct *page. I'm talking about internals.
Even dma_alloc_pages() flow shows how convoluted and non-uniform the code underneath which performs translations all the time.
dma_alloc_pages()
-> __dma_alloc_pages() -> dma_direct_alloc_pages() .... ret = page_address(page); <--- here we need virt address if (dma_set_decrypted(dev, ret, size)) goto out_leak_pages; memset(ret, 0, size); *dma_handle = phys_to_dma_direct(dev, page_to_phys(page)); <- and here we need phys address return page;
So my point is that internal flows should not require struct page and should not depend on it.
Quoted 6 lines
There is also an API that forms a scatterlist that has to be struct page as well
Jason
Quoted 9 lines · Leon Romanovsky
Quoted 8 lines · Jason Gunthorpe
Quoted 5 lines · Leon Romanovsky
Why don't we continue the effort to remove "struct page" entirely from the DMA API internals?
IMHO, everything not exposed to DMA API users should use
phys_addr_t, including the DMA address pool.
Quoted 8 lines
Quoted 2 lines
The alloc interfaces return a struct page, that is why this stuff is organized like this. Look at
dma_alloc_pages()And I didn't say that we should change
dma_alloc_pages(). It is external API, which needs to be struct *page. I'm talking about internals.Even
dma_alloc_pages()flow shows how convoluted and non-uniform the code underneath which performs translations all the time.
Yeah, but I don't really want to go from phys/virt to page, I'd rather see the other direction that is easier to reason about
Maybe some small wrapper that returned phys or whatever would clean this up
Jason
Quoted 39 lines · Aneesh Kumar K.V (Arm)
This series tracks confidential-computing shared DMA state through the dma-direct, dma-pool, and swiotlb paths so that encrypted and decrypted DMA buffers are handled consistently.
Today, the direct DMA path mostly relies on
force_dma_unencrypted()for shared/decrypted buffer handling. This series consolidates theforce_dma_unencrypted()checks in the top-level functions and ensures that the remaining DMA interfaces use DMA attributes to make the correct decisions.The series separates mapping and allocation state:
-DMA_ATTR_CC_SHAREDdescribes the DMA address attribute requested for a mapping. It tells the DMA mapping path that the DMA address must target shared/decrypted memory.
-__DMA_ATTR_ALLOC_CC_SHAREDis an internal DMA-mapping attribute used only by allocation paths after the DMA core decides that the backing pages must be allocated as shared/decrypted memory.The series:
- moves swiotlb-backed allocations out of__dma_direct_alloc_pages(),
- uses__DMA_ATTR_ALLOC_CC_SHAREDthrough the dma-direct alloc/free paths
- teaches the atomic DMA pools to track encrypted versus decrypted state
- tracks swiotlb pool encryption state and enforces strict pool selection
- centralizes encrypted/decrypted pgprot handling indma_pgprot()using DMA attributes
- passes DMA attributes down todma_capable()so capability checks can validate whether the selected DMA address encoding matchesDMA_ATTR_CC_SHARED
- makesdma_direct_map_phys()choose the DMA address encoding fromDMA_ATTR_CC_SHAREDand fall back to swiotlb when a shared DMA request cannot use the direct mapping, which lets arm64 and x86 CCA guests stop relying onSWIOTLB_FORCEfor DMA mappings
- use the selected swiotlb pool state to derive the returned DMA address
- reportsCC_ATTR_GUEST_MEM_ENCRYPTfor arm64 Realms, powerpc secure guests, and s390 protected virtualization guests.
Quoted 7 lines
Dependency:
This series depends on the pKVM changes posted at:
https://lore.kernel.org/all/[email protected]Please merge this series only after the pKVM changes above are merged. Otherwise pKVM will be broken.
pKVM topic branch is now available
https://lore.kernel.org/all/[email protected]/
https://git.kernel.org/pub/scm/linux/kernel/git/arm64/linux.git for-next/coco
-aneesh
Marek Szyprowski
maintainerQuoted 44 lines · Aneesh Kumar K.V
Quoted 43 lines · Aneesh Kumar K.V (Arm)
This series tracks confidential-computing shared DMA state through the dma-direct, dma-pool, and swiotlb paths so that encrypted and decrypted DMA buffers are handled consistently.
Today, the direct DMA path mostly relies on
force_dma_unencrypted()for shared/decrypted buffer handling. This series consolidates theforce_dma_unencrypted()checks in the top-level functions and ensures that the remaining DMA interfaces use DMA attributes to make the correct decisions.The series separates mapping and allocation state:
-DMA_ATTR_CC_SHAREDdescribes the DMA address attribute requested for a mapping. It tells the DMA mapping path that the DMA address must target shared/decrypted memory.
-__DMA_ATTR_ALLOC_CC_SHAREDis an internal DMA-mapping attribute used only by allocation paths after the DMA core decides that the backing pages must be allocated as shared/decrypted memory.The series:
- moves swiotlb-backed allocations out of__dma_direct_alloc_pages(),
- uses__DMA_ATTR_ALLOC_CC_SHAREDthrough the dma-direct alloc/free paths
- teaches the atomic DMA pools to track encrypted versus decrypted state
- tracks swiotlb pool encryption state and enforces strict pool selection
- centralizes encrypted/decrypted pgprot handling indma_pgprot()using DMA attributes
- passes DMA attributes down todma_capable()so capability checks can validate whether the selected DMA address encoding matchesDMA_ATTR_CC_SHARED
- makesdma_direct_map_phys()choose the DMA address encoding fromDMA_ATTR_CC_SHAREDand fall back to swiotlb when a shared DMA request cannot use the direct mapping, which lets arm64 and x86 CCA guests stop relying onSWIOTLB_FORCEfor DMA mappings
- use the selected swiotlb pool state to derive the returned DMA address
- reportsCC_ATTR_GUEST_MEM_ENCRYPTfor arm64 Realms, powerpc secure guests, and s390 protected virtualization guests.Dependency:
This series depends on the pKVM changes posted at:
https://lore.kernel.org/all/[email protected]
Quoted 8 lines
Quoted 3 lines
Please merge this series only after the pKVM changes above are merged. Otherwise pKVM will be broken.
pKVM topic branch is now available
https://lore.kernel.org/all/[email protected]/
https://git.kernel.org/pub/scm/linux/kernel/git/arm64/linux.git for-next/coco
I've just got back from my holiday's and I see that there is everything ready to give this patchset some tests in linux-next. I hope nothing will break.
I've applied this patchset to dma-mapping-for-next, on top of pKVM topic branch with patch "[PATCH v8 17/23] dma-direct: make dma_direct_map_phys() honor DMA_ATTR_CC_SHARED" rebased onto latest changes in arch/arm64/mm/init.c.
The remaining items pointed in the review can be fixed incrementally.
Best regards
Signature · 2 lines
Marek Szyprowski, PhD Samsung R&D Institute Poland
Quoted 52 lines · Marek Szyprowski
Quoted 51 lines · Aneesh Kumar K.V
Quoted 39 lines · Aneesh Kumar K.V (Arm)
This series tracks confidential-computing shared DMA state through the dma-direct, dma-pool, and swiotlb paths so that encrypted and decrypted DMA buffers are handled consistently.
Today, the direct DMA path mostly relies on
force_dma_unencrypted()for shared/decrypted buffer handling. This series consolidates theforce_dma_unencrypted()checks in the top-level functions and ensures that the remaining DMA interfaces use DMA attributes to make the correct decisions.The series separates mapping and allocation state:
-DMA_ATTR_CC_SHAREDdescribes the DMA address attribute requested for a mapping. It tells the DMA mapping path that the DMA address must target shared/decrypted memory.
-__DMA_ATTR_ALLOC_CC_SHAREDis an internal DMA-mapping attribute used only by allocation paths after the DMA core decides that the backing pages must be allocated as shared/decrypted memory.The series:
- moves swiotlb-backed allocations out of__dma_direct_alloc_pages(),
- uses__DMA_ATTR_ALLOC_CC_SHAREDthrough the dma-direct alloc/free paths
- teaches the atomic DMA pools to track encrypted versus decrypted state
- tracks swiotlb pool encryption state and enforces strict pool selection
- centralizes encrypted/decrypted pgprot handling indma_pgprot()using DMA attributes
- passes DMA attributes down todma_capable()so capability checks can validate whether the selected DMA address encoding matchesDMA_ATTR_CC_SHARED
- makesdma_direct_map_phys()choose the DMA address encoding fromDMA_ATTR_CC_SHAREDand fall back to swiotlb when a shared DMA request cannot use the direct mapping, which lets arm64 and x86 CCA guests stop relying onSWIOTLB_FORCEfor DMA mappings
- use the selected swiotlb pool state to derive the returned DMA address
- reportsCC_ATTR_GUEST_MEM_ENCRYPTfor arm64 Realms, powerpc secure guests, and s390 protected virtualization guests.Quoted 7 lines
Dependency:
This series depends on the pKVM changes posted at:
https://lore.kernel.org/all/[email protected]Please merge this series only after the pKVM changes above are merged. Otherwise pKVM will be broken.
pKVM topic branch is now available
Quoted 8 lines
Quoted 1 line
https://git.kernel.org/pub/scm/linux/kernel/git/arm64/linux.git for-next/coco
I've just got back from my holiday's and I see that there is everything ready to give this patchset some tests in linux-next. I hope nothing will break.
I've applied this patchset to dma-mapping-for-next, on top of pKVM topic branch with patch "[PATCH v8 17/23] dma-direct: make
dma_direct_map_phys()honorDMA_ATTR_CC_SHARED" rebased onto latest changes inarch/arm64/mm/init.c.
That might need a fix.
From 5a9af89e74e9e2671ed0a572af129ebfa6fd4640 Mon Sep 17 00:00:00 2001
From: "Aneesh Kumar K.V (Arm)" <[email protected]>
Date: Fri, 7 Aug 2026 13:14:51 +0530
Subject: [PATCH] arm64: swiotlb: Keep the default size for protected guests
Realm guests and protected KVM guests may require swiotlb for device DMA even when all system RAM is addressable by the DMA zones.
Do not reduce the SWIOTLB buffer to the kmalloc-bouncing size for these guests, as the reduced number of slots can be exhausted during CCA guest operation.
--- arch/arm64/mm/init.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
arch/arm64/mm/init.c +2 -1
@@ -339,7 +339,8 @@ void __init arch_mm_preinit(void) {unsigned int flags =SWIOTLB_VERBOSE ; -if (max_pfn <=PFN_DOWN (arm64_dma_phys_limit)) { +if (!cc_platform_has (CC_ATTR_GUEST_MEM_ENCRYPT ) && + max_pfn <=PFN_DOWN (arm64_dma_phys_limit)) {/* * If no bouncing needed for ZONE_DMA, reduce the swiotlb * buffer for kmalloc() bouncing to 1MB per 1GB of RAM.
Signature · 1 line
2.43.0
Hi Marek,
Quoted 8 lines · Marek Szyprowski
Quoted 7 lines · Aneesh Kumar K.V
Quoted 6 lines · Aneesh Kumar K.V (Arm)
This series tracks confidential-computing shared DMA state through the dma-direct, dma-pool, and swiotlb paths so that encrypted and decrypted DMA buffers are handled consistently.
Today, the direct DMA path mostly relies on
force_dma_unencrypted()for
[...]
Quoted 9 lines
Quoted 5 lines
pKVM topic branch is now available
https://lore.kernel.org/all/[email protected]/
https://git.kernel.org/pub/scm/linux/kernel/git/arm64/linux.git for-next/coco
I've just got back from my holiday's and I see that there is everything ready to give this patchset some tests in linux-next. I hope nothing will break.
I've applied this patchset to dma-mapping-for-next, on top of pKVM topic branch with
I was trying to find this tree and it seems the MAINTAINERS file have the wrong address:
DMA MAPPING HELPERS
M: Marek Szyprowski <[email protected]> R: Robin Murphy <[email protected]> L: [email protected] S: Supported W: http://git.infradead.org/users/hch/dma-mapping.git T: git git://git.infradead.org/users/hch/dma-mapping.git
I believe the corret one is:
https://git.kernel.org/pub/scm/linux/kernel/git/mszyprowski/linux.git/
Thanks,
Mostafa
Quoted 10 lines
patch "[PATCH v8 17/23] dma-direct: make
dma_direct_map_phys()honorDMA_ATTR_CC_SHARED" rebased onto latest changes inarch/arm64/mm/init.c.The remaining items pointed in the review can be fixed incrementally.
Best regards
Signature · 2 lines
Marek Szyprowski, PhD Samsung R&D Institute Poland
Marek Szyprowski
maintainerQuoted 29 lines · Mostafa Saleh
Quoted 8 lines · Marek Szyprowski
Quoted 7 lines · Aneesh Kumar K.V
Quoted 6 lines · Aneesh Kumar K.V (Arm)
This series tracks confidential-computing shared DMA state through the dma-direct, dma-pool, and swiotlb paths so that encrypted and decrypted DMA buffers are handled consistently.
Today, the direct DMA path mostly relies on
force_dma_unencrypted()for[...]
Quoted 9 lines
Quoted 5 lines
pKVM topic branch is now available
https://lore.kernel.org/all/[email protected]/
https://git.kernel.org/pub/scm/linux/kernel/git/arm64/linux.git for-next/coco
I've just got back from my holiday's and I see that there is everything ready to give this patchset some tests in linux-next. I hope nothing will break.
I've applied this patchset to dma-mapping-for-next, on top of pKVM topic branch with
I was trying to find this tree and it seems the
MAINTAINERSfile have the wrong address:
DMA MAPPING HELPERSM: Marek Szyprowski <[email protected]> R: Robin Murphy <[email protected]> L: [email protected] S: Supported W: https://protect2.fireeye.com/v1/url?k=dbfa7485-ba7161ce-dbfbffca-74fe485fb305-800153ec5c55b6a1&q=1&e=ed464763-9bbc-4c24-9629-f9ac5e8f5ef4&u=http%3A%2F%2Fgit.infradead.org%2Fusers%2Fhch%2Fdma-mapping.git T: git git://git.infradead.org/users/hch/dma-mapping.git
Quoted 2 lines
I believe the corret one is:
https://git.kernel.org/pub/scm/linux/kernel/git/mszyprowski/linux.git/
Thanks for pointing this out! It looks that I've forgot to update it.I will send an update soon.
Best regards
Signature · 2 lines
Marek Szyprowski, PhD Samsung R&D Institute Poland
Quoted 30 lines · Aneesh Kumar K.V (Arm)
This series tracks confidential-computing shared DMA state through the dma-direct, dma-pool, and swiotlb paths so that encrypted and decrypted DMA buffers are handled consistently.
Today, the direct DMA path mostly relies on
force_dma_unencrypted()for shared/decrypted buffer handling. This series consolidates theforce_dma_unencrypted()checks in the top-level functions and ensures that the remaining DMA interfaces use DMA attributes to make the correct decisions.The series separates mapping and allocation state:
-DMA_ATTR_CC_SHAREDdescribes the DMA address attribute requested for a mapping. It tells the DMA mapping path that the DMA address must target shared/decrypted memory.
-__DMA_ATTR_ALLOC_CC_SHAREDis an internal DMA-mapping attribute used only by allocation paths after the DMA core decides that the backing pages must be allocated as shared/decrypted memory.The series:
- moves swiotlb-backed allocations out of__dma_direct_alloc_pages(),
- uses__DMA_ATTR_ALLOC_CC_SHAREDthrough the dma-direct alloc/free paths
- teaches the atomic DMA pools to track encrypted versus decrypted state
- tracks swiotlb pool encryption state and enforces strict pool selection
- centralizes encrypted/decrypted pgprot handling indma_pgprot()using DMA attributes
- passes DMA attributes down todma_capable()so capability checks can validate whether the selected DMA address encoding matchesDMA_ATTR_CC_SHARED
Quoted 9 lines
- makes
dma_direct_map_phys()choose the DMA address encoding fromDMA_ATTR_CC_SHAREDand fall back to swiotlb when a shared DMA request cannot use the direct mapping, which lets arm64 and x86 CCA guests stop relying onSWIOTLB_FORCEfor DMA mappings
- use the selected swiotlb pool state to derive the returned DMA address
- reportsCC_ATTR_GUEST_MEM_ENCRYPTfor arm64 Realms, powerpc secure guests, and s390 protected virtualization guests.
This series has been getting bigger, going through it again, I see that patches (1, 2, 3, 4, 5, 16, 20, 22) are not really related to the shared DMA work and are either fixes for exisiting bugs or clean ups. Would it make sense to have those separated?
Thanks,
Mostafa
Quoted 162 lines
Dependency:
This series depends on the pKVM changes posted at:
https://lore.kernel.org/all/[email protected]Please merge this series only after the pKVM changes above are merged. Otherwise pKVM will be broken.
Changes since v7:
https://lore.kernel.org/all/[email protected]
* Rebased onto dma-mapping-for-next
* Prepared the series on top of the prerequisite pKVM changes, resolving conflicts so it can be applied directly to the pKVM topic branch once ready.
https://git.gitlab.arm.com/linux-arm/linux-cca/-/commits/scratch/pkvm/testing
* Added comments documenting possible follow-up improvements forCC_SHAREDatomic pools and physical-address-based pool freeing.
* Retained virtual-address-based pool freeing whenCONFIG_DMA_DIRECT_REMAPis disabled.
* Appliedpgprot_decrypted()only when expanding aCC_SHAREDatomic pool.Changes since v6:
https://lore.kernel.org/all/[email protected]
* Rebase onto the latest kernel.
* Add__DMA_ATTR_ALLOC_CC_SHAREDfor allocation paths.DMA_ATTR_CC_SHAREDis now used to describe the requested DMA mapping address attribute, while__DMA_ATTR_ALLOC_CC_SHAREDis used internally when allocating shared/decrypted backing pages.
* ReportCC_ATTR_GUEST_MEM_ENCRYPTfor arm64 Realms, powerpc secure guests, and s390 protected virtualization guests.
* AddCC_ATTR_HOST_MEM_ENCRYPTand swiotlb=force fixes.Changes since v5:
https://lore.kernel.org/all/[email protected]
* Add Tested-by
* Drop the pKVM patch, which has now been posted separately:
https://lore.kernel.org/all/[email protected]
* Remove theDO_NOT_MERGEtag from the s390 change.
* Add a patch to drop theSWIOTLB_FORCEflag.
* Rebase onto the latest kernel.Changes since v4:
https://lore.kernel.org/all/[email protected]
* Add new patches based on Sashiko review:
swiotlb: Preserve allocation virtual address for dynamic pools
dma: free atomic pool pages by physical address
dma: swiotlb: handleset_memory_decrypted()failures
dma: swiotlb: free dynamic pools from process context
iommu/dma: Check atomic pool allocation result directly
* Include pKVM and s390 changes as dependent patches. These are not yet ready to merge and are waiting for subsystem testing feedback.
* Drop the AMD GART patch because it requires wider testing.
* Updateswiotlb_tbl_map_single()to take attrs by reference.
* Switchswiotlb_free()to usercu_work.
* Avoid callingswiotlb_find_pool()multiple times in the free path.
* MakeDMA_ATTR_MMIOimplyDMA_ATTR_CC_SHAREDfor devices requiring unencrypted DMA.Changes from v3:
https://lore.kernel.org/all/[email protected]
* HandleDMA_ATTR_MMIOcorrectly indma_direct_map_phys()
* Address most of sashiko review
* Rebase to latest kernel
* dropSWIOTLB_FORCEfor s390 and powerpc secure guest.Changes from v2:
https://lore.kernel.org/all/[email protected]
* pass attrs todma_capable()and update direct, swiotlb, Xen swiotlb, and x86 GART paths so the capability checks see the DMA address attr valueDMA_ATTR_CC_SHARED.
* reworkdma_direct_map_phys()soDMA_ATTR_CC_SHAREDselectsphys_to_dma_unencrypted()while the default path usesphys_to_dma_encrypted(), with swiotlb fallback when the requested shared/private state cannot be satisfied by a direct DMA address.
* stop relying onSWIOTLB_FORCEfor arm64 and x86 CC guest DMA mappings; swiotlb is still enabled there, but shared mappings is now selected through the generic dma_direct_map_phys()/dma_capable() decision instead of a global force-bounce flag.Changes from v1:
https://lore.kernel.org/all/[email protected]
* rebased to latest kernel (change fromDMA_ATTR_CC_DECRYPTED->DMA_ATTR_CC_SHARED)
* update the alloc path soDMA_ATTR_CC_SHAREDis not a caller-visible attribute.Cc Robin Murphy <[email protected]>Cc Marek Szyprowski <[email protected]>Cc Will Deacon <[email protected]>Cc Marc Zyngier <[email protected]>Cc Steven Price <[email protected]>Cc Suzuki K Poulose <[email protected]>Cc Catalin Marinas <[email protected]>Cc Jiri Pirko <[email protected]>Cc Jason Gunthorpe <[email protected]>Cc Mostafa Saleh <[email protected]>Cc Petr Tesarik <[email protected]>Cc Alexey Kardashevskiy <[email protected]>Cc Dan Williams <[email protected]>Cc Xu Yilun <[email protected]>Cc Madhavan Srinivasan <[email protected]>Cc Michael Ellerman <[email protected]>Cc Nicholas Piggin <[email protected]>Cc "Christophe Leroy (CS GROUP)" <[email protected]>Cc Alexander Gordeev <[email protected]>Cc Gerald Schaefer <[email protected]>Cc Heiko Carstens <[email protected]>Cc Vasily Gorbik <[email protected]>Cc Christian Borntraeger <[email protected]>Cc Sven Schnelle <[email protected]>Aneesh Kumar K.V (Arm) (23):
dma-direct: return struct page fromdma_direct_alloc_from_pool()
dma-pool: fix page leak inatomic_pool_expand()cleanup iommu/dma: Check atomic pool allocation result directly
dma: free atomic pool pages by physical address
swiotlb: Preserve allocation virtual address for dynamic pools
s390: Expose protected virtualization throughcc_platform_has()
dma-direct: swiotlb: handle swiotlb alloc/free outside
__dma_direct_alloc_pages
coco: arm64: s390: powerpc: Mark secure guests with
CC_ATTR_GUEST_MEM_ENCRYPT
dma-mapping: Add internal shared allocation attribute
dma-direct: use__DMA_ATTR_ALLOC_CC_SHAREDin alloc/free paths
dma-pool: track decrypted atomic pools and select them via attrs
dma: swiotlb: pass mapping attributes by reference
dma: swiotlb: track pool encryption state and honorDMA_ATTR_CC_SHARED
dma-mapping: makedma_pgprot()honor__DMA_ATTR_ALLOC_CC_SHARED
dma-direct: pass attrs todma_capable()forDMA_ATTR_CC_SHAREDchecks
dma-direct: Movedma_direct_map_phys()todma/direct.c
dma-direct: makedma_direct_map_phys()honorDMA_ATTR_CC_SHARED
dma-direct: set decrypted flag for remapped DMA allocations
dma-direct: select DMA address encoding from
__DMA_ATTR_ALLOC_CC_SHARED
dma-direct: rename ret tocpu_addrin alloc helpers
dma: swiotlb: free dynamic pools from process context
dma: swiotlb: handleset_memory_decrypted()failures
swiotlb: remove unusedSWIOTLB_FORCEflagDocumentation/core-api/dma-attributes.rst | 29 ++ arch/arm64/mm/init.c | 5 +- arch/powerpc/platforms/pseries/cc_platform.c | 1 + arch/powerpc/platforms/pseries/svm.c | 2 +- arch/s390/Kconfig | 1 + arch/s390/mm/init.c | 17 +- arch/x86/kernel/amd_gart_64.c | 30 +- arch/x86/kernel/pci-dma.c | 4 +- drivers/iommu/dma-iommu.c | 20 +- drivers/xen/swiotlb-xen.c | 8 +- include/linux/dma-direct.h | 20 +- include/linux/dma-map-ops.h | 3 +- include/linux/dma-mapping.h | 8 + include/linux/swiotlb.h | 25 +- include/trace/events/dma.h | 3 +- kernel/dma/direct.c | 326 ++++++++++++++----- kernel/dma/direct.h | 56 +--- kernel/dma/mapping.c | 25 +- kernel/dma/pool.c | 237 ++++++++++---- kernel/dma/swiotlb.c | 292 +++++++++++++---- 20 files changed, 810 insertions(+), 302 deletions(-)Signature · 1 line
2.43.0
Quoted 41 lines · Mostafa Saleh
Quoted 30 lines · Aneesh Kumar K.V (Arm)
This series tracks confidential-computing shared DMA state through the dma-direct, dma-pool, and swiotlb paths so that encrypted and decrypted DMA buffers are handled consistently.
Today, the direct DMA path mostly relies on
force_dma_unencrypted()for shared/decrypted buffer handling. This series consolidates theforce_dma_unencrypted()checks in the top-level functions and ensures that the remaining DMA interfaces use DMA attributes to make the correct decisions.The series separates mapping and allocation state:
-DMA_ATTR_CC_SHAREDdescribes the DMA address attribute requested for a mapping. It tells the DMA mapping path that the DMA address must target shared/decrypted memory.
-__DMA_ATTR_ALLOC_CC_SHAREDis an internal DMA-mapping attribute used only by allocation paths after the DMA core decides that the backing pages must be allocated as shared/decrypted memory.The series:
- moves swiotlb-backed allocations out of__dma_direct_alloc_pages(),
- uses__DMA_ATTR_ALLOC_CC_SHAREDthrough the dma-direct alloc/free paths
- teaches the atomic DMA pools to track encrypted versus decrypted state
- tracks swiotlb pool encryption state and enforces strict pool selection
- centralizes encrypted/decrypted pgprot handling indma_pgprot()using DMA attributes
- passes DMA attributes down todma_capable()so capability checks can validate whether the selected DMA address encoding matchesDMA_ATTR_CC_SHAREDQuoted 9 lines
- makes
dma_direct_map_phys()choose the DMA address encoding fromDMA_ATTR_CC_SHAREDand fall back to swiotlb when a shared DMA request cannot use the direct mapping, which lets arm64 and x86 CCA guests stop relying onSWIOTLB_FORCEfor DMA mappings
- use the selected swiotlb pool state to derive the returned DMA address
- reportsCC_ATTR_GUEST_MEM_ENCRYPTfor arm64 Realms, powerpc secure guests, and s390 protected virtualization guests.
Quoted 5 lines
This series has been getting bigger, going through it again, I see that patches (1, 2, 3, 4, 5, 16, 20, 22) are not really related to the shared DMA work and are either fixes for exisiting bugs or clean ups. Would it make sense to have those separated?
Some of these fixes were originally at the end of the series. However, it was suggested that they be moved earlier to make backporting easier. The changes are kept as a single series because of the code dependencies and to make it easier for Sashiko to apply and review them.
One of the reasons I'm also requesting that this be picked up for -next is to avoid continuing to add more changes to the series at this stage.
-aneesh