Skip to content

Commit 0b84e4f

Browse files
Claire Changkonradwilk
authored andcommitted
swiotlb: Add restricted DMA pool initialization
Add the initialization function to create restricted DMA pools from matching reserved-memory nodes. Regardless of swiotlb setting, the restricted DMA pool is preferred if available. The restricted DMA pools provide a basic level of protection against the DMA overwriting buffer contents at unexpected times. However, to protect against general data leakage and system memory corruption, the system needs to provide a way to lock down the memory access, e.g., MPU. Signed-off-by: Claire Chang <[email protected]> Reviewed-by: Christoph Hellwig <[email protected]> Tested-by: Stefano Stabellini <[email protected]> Tested-by: Will Deacon <[email protected]> Signed-off-by: Konrad Rzeszutek Wilk <[email protected]>
1 parent f4111e3 commit 0b84e4f

File tree

3 files changed

+92
-1
lines changed

3 files changed

+92
-1
lines changed

include/linux/swiotlb.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,8 @@ extern enum swiotlb_force swiotlb_force;
7373
* range check to see if the memory was in fact allocated by this
7474
* API.
7575
* @nslabs: The number of IO TLB blocks (in groups of 64) between @start and
76-
* @end. This is command line adjustable via setup_io_tlb_npages.
76+
* @end. For default swiotlb, this is command line adjustable via
77+
* setup_io_tlb_npages.
7778
* @used: The number of used IO TLB block.
7879
* @list: The free list describing the number of free entries available
7980
* from each index.

kernel/dma/Kconfig

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,20 @@ config SWIOTLB
8080
bool
8181
select NEED_DMA_MAP_STATE
8282

83+
config DMA_RESTRICTED_POOL
84+
bool "DMA Restricted Pool"
85+
depends on OF && OF_RESERVED_MEM
86+
select SWIOTLB
87+
help
88+
This enables support for restricted DMA pools which provide a level of
89+
DMA memory protection on systems with limited hardware protection
90+
capabilities, such as those lacking an IOMMU.
91+
92+
For more information see
93+
<Documentation/devicetree/bindings/reserved-memory/reserved-memory.txt>
94+
and <kernel/dma/swiotlb.c>.
95+
If unsure, say "n".
96+
8397
#
8498
# Should be selected if we can mmap non-coherent mappings to userspace.
8599
# The only thing that is really required is a way to set an uncached bit

kernel/dma/swiotlb.c

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,13 @@
3939
#ifdef CONFIG_DEBUG_FS
4040
#include <linux/debugfs.h>
4141
#endif
42+
#ifdef CONFIG_DMA_RESTRICTED_POOL
43+
#include <linux/io.h>
44+
#include <linux/of.h>
45+
#include <linux/of_fdt.h>
46+
#include <linux/of_reserved_mem.h>
47+
#include <linux/slab.h>
48+
#endif
4249

4350
#include <asm/io.h>
4451
#include <asm/dma.h>
@@ -735,4 +742,73 @@ bool swiotlb_free(struct device *dev, struct page *page, size_t size)
735742
return true;
736743
}
737744

745+
static int rmem_swiotlb_device_init(struct reserved_mem *rmem,
746+
struct device *dev)
747+
{
748+
struct io_tlb_mem *mem = rmem->priv;
749+
unsigned long nslabs = rmem->size >> IO_TLB_SHIFT;
750+
751+
/*
752+
* Since multiple devices can share the same pool, the private data,
753+
* io_tlb_mem struct, will be initialized by the first device attached
754+
* to it.
755+
*/
756+
if (!mem) {
757+
mem = kzalloc(struct_size(mem, slots, nslabs), GFP_KERNEL);
758+
if (!mem)
759+
return -ENOMEM;
760+
761+
set_memory_decrypted((unsigned long)phys_to_virt(rmem->base),
762+
rmem->size >> PAGE_SHIFT);
763+
swiotlb_init_io_tlb_mem(mem, rmem->base, nslabs, false);
764+
mem->force_bounce = true;
765+
mem->for_alloc = true;
766+
767+
rmem->priv = mem;
768+
769+
if (IS_ENABLED(CONFIG_DEBUG_FS)) {
770+
mem->debugfs =
771+
debugfs_create_dir(rmem->name, debugfs_dir);
772+
swiotlb_create_debugfs_files(mem);
773+
}
774+
}
775+
776+
dev->dma_io_tlb_mem = mem;
777+
778+
return 0;
779+
}
780+
781+
static void rmem_swiotlb_device_release(struct reserved_mem *rmem,
782+
struct device *dev)
783+
{
784+
dev->dma_io_tlb_mem = io_tlb_default_mem;
785+
}
786+
787+
static const struct reserved_mem_ops rmem_swiotlb_ops = {
788+
.device_init = rmem_swiotlb_device_init,
789+
.device_release = rmem_swiotlb_device_release,
790+
};
791+
792+
static int __init rmem_swiotlb_setup(struct reserved_mem *rmem)
793+
{
794+
unsigned long node = rmem->fdt_node;
795+
796+
if (of_get_flat_dt_prop(node, "reusable", NULL) ||
797+
of_get_flat_dt_prop(node, "linux,cma-default", NULL) ||
798+
of_get_flat_dt_prop(node, "linux,dma-default", NULL) ||
799+
of_get_flat_dt_prop(node, "no-map", NULL))
800+
return -EINVAL;
801+
802+
if (PageHighMem(pfn_to_page(PHYS_PFN(rmem->base)))) {
803+
pr_err("Restricted DMA pool must be accessible within the linear mapping.");
804+
return -EINVAL;
805+
}
806+
807+
rmem->ops = &rmem_swiotlb_ops;
808+
pr_info("Reserved memory: created restricted DMA pool at %pa, size %ld MiB\n",
809+
&rmem->base, (unsigned long)rmem->size / SZ_1M);
810+
return 0;
811+
}
812+
813+
RESERVEDMEM_OF_DECLARE(dma, "restricted-dma-pool", rmem_swiotlb_setup);
738814
#endif /* CONFIG_DMA_RESTRICTED_POOL */

0 commit comments

Comments
 (0)