This series implements mitigations for lack of DMA access control on
systems without an IOMMU, which could result in the DMA accessing the
system memory at unexpected times and/or unexpected addresses, possibly
leading to data leakage or corruption.
For example, we plan to use the PCI-e bus for Wi-Fi and that PCI-e bus is
not behind an IOMMU. As PCI-e, by design, gives the device full access to
system memory, a vulnerability in the Wi-Fi firmware could easily escalate
to a full system exploit (remote wifi exploits: [1a], [1b] that shows a
full chain of exploits; [2], [3]).
To mitigate the security concerns, we introduce restricted DMA. Restricted
DMA utilizes the existing swiotlb to bounce streaming DMA in and out of a
specially allocated region and does memory allocation from the same region.
The feature on its own provides 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 restrict the DMA to a predefined memory region (this is
usually done at firmware level, e.g. MPU in ATF on some ARM platforms [4]).
[1a] https://googleprojectzero.blogspot.com/2017/04/over-air-exploiting-broadcoms-wi-fi_4.html
[1b] https://googleprojectzero.blogspot.com/2017/04/over-air-exploiting-broadcoms-wi-fi_11.html
[2] https://blade.tencent.com/en/advisories/qualpwn/
[3] https://www.bleepingcomputer.com/news/security/vulnerabilities-found-in-highly-popular-firmware-for-wifi-chips/
[4] https://github.com/ARM-software/arm-trusted-firmware/blob/master/plat/mediatek/mt8183/drivers/emi_mpu/emi_mpu.c#L132
v7:
Fix debugfs, PageHighMem and comment style in rmem_swiotlb_device_init
v6:
Address the comments in v5
https://lore.kernel.org/patchwork/cover/1423201/
v5:
Rebase on latest linux-next
https://lore.kernel.org/patchwork/cover/1416899/
v4:
- Fix spinlock bad magic
- Use rmem->name for debugfs entry
- Address the comments in v3
https://lore.kernel.org/patchwork/cover/1378113/
v3:
Using only one reserved memory region for both streaming DMA and memory
allocation.
https://lore.kernel.org/patchwork/cover/1360992/
v2:
Building on top of swiotlb.
https://lore.kernel.org/patchwork/cover/1280705/
v1:
Using dma_map_ops.
https://lore.kernel.org/patchwork/cover/1271660/
Claire Chang (15):
swiotlb: Refactor swiotlb init functions
swiotlb: Refactor swiotlb_create_debugfs
swiotlb: Add DMA_RESTRICTED_POOL
swiotlb: Add restricted DMA pool initialization
swiotlb: Add a new get_io_tlb_mem getter
swiotlb: Update is_swiotlb_buffer to add a struct device argument
swiotlb: Update is_swiotlb_active to add a struct device argument
swiotlb: Bounce data from/to restricted DMA pool if available
swiotlb: Move alloc_size to find_slots
swiotlb: Refactor swiotlb_tbl_unmap_single
dma-direct: Add a new wrapper __dma_direct_free_pages()
swiotlb: Add restricted DMA alloc/free support.
dma-direct: Allocate memory from restricted DMA pool if available
dt-bindings: of: Add restricted DMA pool
of: Add plumbing for restricted DMA pool
.../reserved-memory/reserved-memory.txt | 27 ++
drivers/gpu/drm/i915/gem/i915_gem_internal.c | 2 +-
drivers/gpu/drm/nouveau/nouveau_ttm.c | 2 +-
drivers/iommu/dma-iommu.c | 12 +-
drivers/of/address.c | 25 ++
drivers/of/device.c | 3 +
drivers/of/of_private.h | 5 +
drivers/pci/xen-pcifront.c | 2 +-
drivers/xen/swiotlb-xen.c | 2 +-
include/linux/device.h | 4 +
include/linux/swiotlb.h | 41 ++-
kernel/dma/Kconfig | 14 +
kernel/dma/direct.c | 63 +++--
kernel/dma/direct.h | 9 +-
kernel/dma/swiotlb.c | 242 +++++++++++++-----
15 files changed, 356 insertions(+), 97 deletions(-)
--
2.31.1.751.gd2f1c929bd-goog
Add a new function, swiotlb_init_io_tlb_mem, for the io_tlb_mem struct
initialization to make the code reusable.
Note that we now also call set_memory_decrypted in swiotlb_init_with_tbl.
Signed-off-by: Claire Chang <redacted>
---
kernel/dma/swiotlb.c | 51 ++++++++++++++++++++++----------------------
1 file changed, 25 insertions(+), 26 deletions(-)
@@ -186,16 +207,8 @@ int __init swiotlb_init_with_tbl(char *tlb, unsigned long nslabs, int verbose)if(!mem)panic("%s: Failed to allocate %zu bytes align=0x%lx\n",__func__,alloc_size,PAGE_SIZE);-mem->nslabs=nslabs;-mem->start=__pa(tlb);-mem->end=mem->start+bytes;-mem->index=0;-spin_lock_init(&mem->lock);-for(i=0;i<mem->nslabs;i++){-mem->slots[i].list=IO_TLB_SEGSIZE-io_tlb_offset(i);-mem->slots[i].orig_addr=INVALID_PHYS_ADDR;-mem->slots[i].alloc_size=0;-}++swiotlb_init_io_tlb_mem(mem,__pa(tlb),nslabs,false);io_tlb_default_mem=mem;if(verbose)
Split the debugfs creation to make the code reusable for supporting
different bounce buffer pools, e.g. restricted DMA pool.
Signed-off-by: Claire Chang <redacted>
---
kernel/dma/swiotlb.c | 25 +++++++++++++++++++------
1 file changed, 19 insertions(+), 6 deletions(-)
@@ -80,6 +80,20 @@ config SWIOTLBboolselectNEED_DMA_MAP_STATE+configDMA_RESTRICTED_POOL+bool"DMA Restricted Pool"+depends onOF&&OF_RESERVED_MEM+selectSWIOTLB+help+ThisenablessupportforrestrictedDMApoolswhichprovidealevelof+DMAmemoryprotectiononsystemswithlimitedhardwareprotection+capabilities,suchasthoselackinganIOMMU.++Formoreinformationsee+<Documentation/devicetree/bindings/reserved-memory/reserved-memory.txt>+and<kernel/dma/swiotlb.c>.+Ifunsure,say"n".+## Should be selected if we can mmap non-coherent mappings to userspace.# The only thing that is really required is a way to set an uncached bit
Add a new getter, get_io_tlb_mem, to help select the io_tlb_mem struct.
The restricted DMA pool is preferred if available.
Signed-off-by: Claire Chang <redacted>
---
include/linux/swiotlb.h | 11 +++++++++++
1 file changed, 11 insertions(+)
@@ -495,7 +495,7 @@ int dma_direct_supported(struct device *dev, u64 mask)size_tdma_direct_max_mapping_size(structdevice*dev){/* If SWIOTLB is active, use its maximum mapping size */-if(is_swiotlb_active()&&+if(is_swiotlb_active(dev)&&(dma_addressing_limited(dev)||swiotlb_force==SWIOTLB_FORCE))returnswiotlb_max_mapping_size(dev);returnSIZE_MAX;
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.
Note that is_dev_swiotlb_force doesn't check if
swiotlb_force == SWIOTLB_FORCE. Otherwise the memory allocation behavior
with default swiotlb will be changed by the following patche
("dma-direct: Allocate memory from restricted DMA pool if available").
Signed-off-by: Claire Chang <redacted>
---
include/linux/swiotlb.h | 13 +++++++++++++
kernel/dma/direct.c | 3 ++-
kernel/dma/direct.h | 3 ++-
kernel/dma/swiotlb.c | 8 ++++----
4 files changed, 21 insertions(+), 6 deletions(-)
@@ -496,7 +496,8 @@ size_t dma_direct_max_mapping_size(struct device *dev){/* If SWIOTLB is active, use its maximum mapping size */if(is_swiotlb_active(dev)&&-(dma_addressing_limited(dev)||swiotlb_force==SWIOTLB_FORCE))+(dma_addressing_limited(dev)||swiotlb_force==SWIOTLB_FORCE||+is_dev_swiotlb_force(dev)))returnswiotlb_max_mapping_size(dev);returnSIZE_MAX;}
Add a new function, release_slots, to make the code reusable for supporting
different bounce buffer pools, e.g. restricted DMA pool.
Signed-off-by: Claire Chang <redacted>
---
kernel/dma/swiotlb.c | 35 ++++++++++++++++++++---------------
1 file changed, 20 insertions(+), 15 deletions(-)
Add a new wrapper __dma_direct_free_pages() that will be useful later
for swiotlb_free().
Signed-off-by: Claire Chang <redacted>
---
kernel/dma/direct.c | 14 ++++++++++----
1 file changed, 10 insertions(+), 4 deletions(-)
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.
Note that since coherent allocation needs remapping, one must set up
another device coherent pool by shared-dma-pool and use
dma_alloc_from_dev_coherent instead for atomic coherent allocation.
Signed-off-by: Claire Chang <redacted>
---
kernel/dma/direct.c | 38 +++++++++++++++++++++++++++++---------
1 file changed, 29 insertions(+), 9 deletions(-)
@@ -161,18 +175,23 @@ void *dma_direct_alloc(struct device *dev, size_t size,}if(!IS_ENABLED(CONFIG_ARCH_HAS_DMA_SET_UNCACHED)&&-!IS_ENABLED(CONFIG_DMA_DIRECT_REMAP)&&-!dev_is_dma_coherent(dev))+!IS_ENABLED(CONFIG_DMA_DIRECT_REMAP)&&!dev_is_dma_coherent(dev)&&+!is_dev_swiotlb_force(dev))returnarch_dma_alloc(dev,size,dma_handle,gfp,attrs);/**Remappingordecryptingmemorymayblock.Ifeitherisrequiredand*wecan'tblock,allocatethememoryfromtheatomicpools.+*IfrestrictedDMA(i.e.,is_dev_swiotlb_force)isrequired,onemust+*setupanotherdevicecoherentpoolbyshared-dma-poolanduse+*dma_alloc_from_dev_coherentinstead.*/if(IS_ENABLED(CONFIG_DMA_COHERENT_POOL)&&!gfpflags_allow_blocking(gfp)&&(force_dma_unencrypted(dev)||-(IS_ENABLED(CONFIG_DMA_DIRECT_REMAP)&&!dev_is_dma_coherent(dev))))+(IS_ENABLED(CONFIG_DMA_DIRECT_REMAP)&&+!dev_is_dma_coherent(dev)))&&+!is_dev_swiotlb_force(dev))returndma_direct_alloc_from_pool(dev,size,dma_handle,gfp);/* we always manually zero the memory once we are done */
@@ -253,15 +272,15 @@ void dma_direct_free(struct device *dev, size_t size,unsignedintpage_order=get_order(size);if((attrs&DMA_ATTR_NO_KERNEL_MAPPING)&&-!force_dma_unencrypted(dev)){+!force_dma_unencrypted(dev)&&!is_dev_swiotlb_force(dev)){/* cpu_addr is a struct page cookie, not a kernel address */dma_free_contiguous(dev,cpu_addr,size);return;}if(!IS_ENABLED(CONFIG_ARCH_HAS_DMA_SET_UNCACHED)&&-!IS_ENABLED(CONFIG_DMA_DIRECT_REMAP)&&-!dev_is_dma_coherent(dev)){+!IS_ENABLED(CONFIG_DMA_DIRECT_REMAP)&&!dev_is_dma_coherent(dev)&&+!is_dev_swiotlb_force(dev)){arch_dma_free(dev,size,cpu_addr,dma_addr,attrs);return;}
Introduce the new compatible string, restricted-dma-pool, for restricted
DMA. One can specify the address and length of the restricted DMA memory
region by restricted-dma-pool in the reserved-memory node.
Signed-off-by: Claire Chang <redacted>
---
.../reserved-memory/reserved-memory.txt | 27 +++++++++++++++++++
1 file changed, 27 insertions(+)
@@ -51,6 +51,23 @@ compatible (optional) - standard definition used as a shared pool of DMA buffers for a set of devices. It can be used by an operating system to instantiate the necessary pool management subsystem if necessary.+ - restricted-dma-pool: This indicates a region of memory meant to be+ used as a pool of restricted DMA buffers for a set of devices. The+ memory region would be the only region accessible to those devices.+ When using this, the no-map and reusable properties must not be set,+ so the operating system can create a virtual mapping that will be used+ for synchronization. The main purpose for restricted DMA is to+ mitigate the lack of DMA access control on systems without an IOMMU,+ which could result in the DMA accessing the system memory at+ unexpected times and/or unexpected addresses, possibly leading to data+ leakage or corruption. The feature on its own provides 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 way to lock down+ the memory access, e.g., MPU. Note that since coherent allocation+ needs remapping, one must set up another device coherent pool by+ shared-dma-pool and use dma_alloc_from_dev_coherent instead for atomic+ coherent allocation. - vendor specific string in the form <vendor>,[<device>-]<usage> no-map (optional) - empty property - Indicates the operating system must not create a virtual mapping
If a device is not behind an IOMMU, we look up the device node and set
up the restricted DMA when the restricted-dma-pool is presented.
Signed-off-by: Claire Chang <redacted>
---
drivers/of/address.c | 25 +++++++++++++++++++++++++
drivers/of/device.c | 3 +++
drivers/of/of_private.h | 5 +++++
3 files changed, 33 insertions(+)
@@ -1112,6 +1113,30 @@ bool of_dma_is_coherent(struct device_node *np)}EXPORT_SYMBOL_GPL(of_dma_is_coherent);+intof_dma_set_restricted_buffer(structdevice*dev)+{+structdevice_node*node;+intcount,i;++if(!dev->of_node)+return0;++count=of_property_count_elems_of_size(dev->of_node,"memory-region",+sizeof(phandle));+for(i=0;i<count;i++){+node=of_parse_phandle(dev->of_node,"memory-region",i);+/* There might be multiple memory regions, but only one+*restriced-dma-poolregionisallowed.+*/+if(of_device_is_compatible(node,"restricted-dma-pool")&&+of_device_is_available(node))+returnof_reserved_mem_device_init_by_idx(+dev,dev->of_node,i);+}++return0;+}+/***of_mmio_is_nonposted-Checkifdeviceusesnon-postedMMIO*@np:devicenode
I didn't move this to a separate file because I feel it might be
confusing for swiotlb_alloc/free (and need more functions to be
non-static).
Maybe instead of moving to a separate file, we can try to come up with
a better naming?
Still keep this function because directly using dev->dma_io_tlb_mem
will cause issues for memory allocation for existing devices. The pool
can't support atomic coherent allocation so we need to distinguish the
per device pool and the default pool in swiotlb_alloc.
Add a new function, swiotlb_init_io_tlb_mem, for the io_tlb_mem struct
initialization to make the code reusable.
Note that we now also call set_memory_decrypted in swiotlb_init_with_tbl.
Signed-off-by: Claire Chang <redacted>
---
kernel/dma/swiotlb.c | 51 ++++++++++++++++++++++----------------------
1 file changed, 25 insertions(+), 26 deletions(-)
You are doing an unconditional set_memory_decrypted() followed by a
memset here, and then:
quoted hunk
+}
+
+int __init swiotlb_init_with_tbl(char *tlb, unsigned long nslabs, int verbose)
+{
struct io_tlb_mem *mem;
size_t alloc_size;
@@ -186,16 +207,8 @@ int __init swiotlb_init_with_tbl(char *tlb, unsigned long nslabs, int verbose) if (!mem) panic("%s: Failed to allocate %zu bytes align=0x%lx\n", __func__, alloc_size, PAGE_SIZE);- mem->nslabs = nslabs;- mem->start = __pa(tlb);- mem->end = mem->start + bytes;- mem->index = 0;- spin_lock_init(&mem->lock);- for (i = 0; i < mem->nslabs; i++) {- mem->slots[i].list = IO_TLB_SEGSIZE - io_tlb_offset(i);- mem->slots[i].orig_addr = INVALID_PHYS_ADDR;- mem->slots[i].alloc_size = 0;- }++ swiotlb_init_io_tlb_mem(mem, __pa(tlb), nslabs, false);
You convert this call site with swiotlb_init_io_tlb_mem() which did not
do the set_memory_decrypted()+memset(). Is this okay or should
swiotlb_init_io_tlb_mem() add an additional argument to do this
conditionally?
--
Florian
@@ -690,3 +697,72 @@ static int __init swiotlb_create_default_debugfs(void)late_initcall(swiotlb_create_default_debugfs);#endif++#ifdef CONFIG_DMA_RESTRICTED_POOL+staticintrmem_swiotlb_device_init(structreserved_mem*rmem,+structdevice*dev)+{+structio_tlb_mem*mem=rmem->priv;+unsignedlongnslabs=rmem->size>>IO_TLB_SHIFT;++if(dev->dma_io_tlb_mem)+return0;++/*+*Sincemultipledevicescansharethesamepool,theprivatedata,+*io_tlb_memstruct,willbeinitializedbythefirstdeviceattached+*toit.+*/+if(!mem){+mem=kzalloc(struct_size(mem,slots,nslabs),GFP_KERNEL);+if(!mem)+return-ENOMEM;++if(PageHighMem(pfn_to_page(PHYS_PFN(rmem->base)))){+kfree(mem);+return-EINVAL;
This could probably deserve a warning here to indicate that the reserved
area must be accessible within the linear mapping as I would expect a
lot of people to trip over that.
Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
--
Florian
Add a new getter, get_io_tlb_mem, to help select the io_tlb_mem struct.
The restricted DMA pool is preferred if available.
Signed-off-by: Claire Chang <redacted>
Update is_swiotlb_buffer to add a struct device argument. This will be
useful later to allow for restricted DMA pool.
Signed-off-by: Claire Chang <redacted>
Update is_swiotlb_active to add a struct device argument. This will be
useful later to allow for restricted DMA pool.
Signed-off-by: Claire Chang <redacted>
Split the debugfs creation to make the code reusable for supporting
different bounce buffer pools, e.g. restricted DMA pool.
Signed-off-by: Claire Chang <redacted>
@@ -690,3 +697,72 @@ static int __init swiotlb_create_default_debugfs(void)late_initcall(swiotlb_create_default_debugfs);#endif++#ifdef CONFIG_DMA_RESTRICTED_POOL+staticintrmem_swiotlb_device_init(structreserved_mem*rmem,+structdevice*dev)+{+structio_tlb_mem*mem=rmem->priv;+unsignedlongnslabs=rmem->size>>IO_TLB_SHIFT;++if(dev->dma_io_tlb_mem)+return0;++/*+*Sincemultipledevicescansharethesamepool,theprivatedata,+*io_tlb_memstruct,willbeinitializedbythefirstdeviceattached+*toit.+*/+if(!mem){+mem=kzalloc(struct_size(mem,slots,nslabs),GFP_KERNEL);+if(!mem)+return-ENOMEM;++if(PageHighMem(pfn_to_page(PHYS_PFN(rmem->base)))){+kfree(mem);+return-EINVAL;
This could probably deserve a warning here to indicate that the reserved
area must be accessible within the linear mapping as I would expect a
lot of people to trip over that.
On Thu, May 20, 2021 at 2:50 AM Florian Fainelli [off-list ref] wrote:
On 5/17/2021 11:42 PM, Claire Chang wrote:
quoted
Add a new function, swiotlb_init_io_tlb_mem, for the io_tlb_mem struct
initialization to make the code reusable.
Note that we now also call set_memory_decrypted in swiotlb_init_with_tbl.
Signed-off-by: Claire Chang <redacted>
---
kernel/dma/swiotlb.c | 51 ++++++++++++++++++++++----------------------
1 file changed, 25 insertions(+), 26 deletions(-)
You are doing an unconditional set_memory_decrypted() followed by a
memset here, and then:
quoted
+}
+
+int __init swiotlb_init_with_tbl(char *tlb, unsigned long nslabs, int verbose)
+{
struct io_tlb_mem *mem;
size_t alloc_size;
@@ -186,16 +207,8 @@ int __init swiotlb_init_with_tbl(char *tlb, unsigned long nslabs, int verbose) if (!mem) panic("%s: Failed to allocate %zu bytes align=0x%lx\n", __func__, alloc_size, PAGE_SIZE);- mem->nslabs = nslabs;- mem->start = __pa(tlb);- mem->end = mem->start + bytes;- mem->index = 0;- spin_lock_init(&mem->lock);- for (i = 0; i < mem->nslabs; i++) {- mem->slots[i].list = IO_TLB_SEGSIZE - io_tlb_offset(i);- mem->slots[i].orig_addr = INVALID_PHYS_ADDR;- mem->slots[i].alloc_size = 0;- }++ swiotlb_init_io_tlb_mem(mem, __pa(tlb), nslabs, false);
You convert this call site with swiotlb_init_io_tlb_mem() which did not
do the set_memory_decrypted()+memset(). Is this okay or should
swiotlb_init_io_tlb_mem() add an additional argument to do this
conditionally?
I'm actually not sure if this it okay. If not, will add an additional
argument for it.
From: Konrad Rzeszutek Wilk <hidden> Date: 2021-05-24 15:56:59
On Tue, May 18, 2021 at 02:48:35PM +0800, Claire Chang wrote:
I didn't move this to a separate file because I feel it might be
confusing for swiotlb_alloc/free (and need more functions to be
non-static).
Maybe instead of moving to a separate file, we can try to come up with
a better naming?
I think you are referring to:
rmem_swiotlb_setup
?
Which is ARM specific and inside the generic code?
<sigh>
Christopher wants to unify it in all the code so there is one single
source, but the "you seperate arch code out from generic" saying
makes me want to move it out.
I agree that if you move it out from generic to arch-specific we have to
expose more of the swiotlb functions, which will undo's Christopher
cleanup code.
How about this - lets leave it as is now, and when there are more
use-cases we can revisit it and then if need to move the code?
From: Konrad Rzeszutek Wilk <hidden> Date: 2021-05-24 15:58:06
On Tue, May 18, 2021 at 02:51:52PM +0800, Claire Chang wrote:
Still keep this function because directly using dev->dma_io_tlb_mem
will cause issues for memory allocation for existing devices. The pool
can't support atomic coherent allocation so we need to distinguish the
per device pool and the default pool in swiotlb_alloc.
This above should really be rolled in the commit. You can prefix it by
"The reason it was done this way was because directly using .."
On Mon, May 24, 2021 at 11:49 PM Konrad Rzeszutek Wilk
[off-list ref] wrote:
On Tue, May 18, 2021 at 02:48:35PM +0800, Claire Chang wrote:
quoted
I didn't move this to a separate file because I feel it might be
confusing for swiotlb_alloc/free (and need more functions to be
non-static).
Maybe instead of moving to a separate file, we can try to come up with
a better naming?
I think you are referring to:
rmem_swiotlb_setup
?
Yes, and the following swiotlb_alloc/free.
Which is ARM specific and inside the generic code?
<sigh>
Christopher wants to unify it in all the code so there is one single
source, but the "you seperate arch code out from generic" saying
makes me want to move it out.
I agree that if you move it out from generic to arch-specific we have to
expose more of the swiotlb functions, which will undo's Christopher
cleanup code.
How about this - lets leave it as is now, and when there are more
use-cases we can revisit it and then if need to move the code?
On Mon, May 24, 2021 at 11:51 PM Konrad Rzeszutek Wilk
[off-list ref] wrote:
On Tue, May 18, 2021 at 02:51:52PM +0800, Claire Chang wrote:
quoted
Still keep this function because directly using dev->dma_io_tlb_mem
will cause issues for memory allocation for existing devices. The pool
can't support atomic coherent allocation so we need to distinguish the
per device pool and the default pool in swiotlb_alloc.
This above should really be rolled in the commit. You can prefix it by
"The reason it was done this way was because directly using .."
From: Will Deacon <will@kernel.org> Date: 2021-05-26 12:13:38
Hi Claire,
On Tue, May 18, 2021 at 02:42:14PM +0800, Claire Chang wrote:
quoted hunk
Introduce the new compatible string, restricted-dma-pool, for restricted
DMA. One can specify the address and length of the restricted DMA memory
region by restricted-dma-pool in the reserved-memory node.
Signed-off-by: Claire Chang <redacted>
---
.../reserved-memory/reserved-memory.txt | 27 +++++++++++++++++++
1 file changed, 27 insertions(+)
@@ -51,6 +51,23 @@ compatible (optional) - standard definition used as a shared pool of DMA buffers for a set of devices. It can be used by an operating system to instantiate the necessary pool management subsystem if necessary.+ - restricted-dma-pool: This indicates a region of memory meant to be+ used as a pool of restricted DMA buffers for a set of devices. The+ memory region would be the only region accessible to those devices.+ When using this, the no-map and reusable properties must not be set,+ so the operating system can create a virtual mapping that will be used+ for synchronization. The main purpose for restricted DMA is to+ mitigate the lack of DMA access control on systems without an IOMMU,+ which could result in the DMA accessing the system memory at+ unexpected times and/or unexpected addresses, possibly leading to data+ leakage or corruption. The feature on its own provides 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 way to lock down+ the memory access, e.g., MPU. Note that since coherent allocation+ needs remapping, one must set up another device coherent pool by+ shared-dma-pool and use dma_alloc_from_dev_coherent instead for atomic+ coherent allocation. - vendor specific string in the form <vendor>,[<device>-]<usage> no-map (optional) - empty property - Indicates the operating system must not create a virtual mapping
I still don't understand how this works for individual PCIe devices -- how
is dev->of_node set to point at the node you have above?
I tried adding the memory-region to the host controller instead, and then
I see it crop up in dmesg:
| pci-host-generic 40000000.pci: assigned reserved memory node restricted_dma_mem_reserved
but none of the actual PCI devices end up with 'dma_io_tlb_mem' set, and
so the restricted DMA area is not used. In fact, swiotlb isn't used at all.
What am I missing to make this work with PCIe devices?
Thanks,
Will
I still don't understand how this works for individual PCIe devices -- how
is dev->of_node set to point at the node you have above?
I tried adding the memory-region to the host controller instead, and then
I see it crop up in dmesg:
| pci-host-generic 40000000.pci: assigned reserved memory node restricted_dma_mem_reserved
but none of the actual PCI devices end up with 'dma_io_tlb_mem' set, and
so the restricted DMA area is not used. In fact, swiotlb isn't used at all.
What am I missing to make this work with PCIe devices?
Aha, looks like we're just missing the logic to inherit the DMA
configuration. The diff below gets things working for me.
Will
--->8
@@ -1113,25 +1113,25 @@ bool of_dma_is_coherent(struct device_node *np)}EXPORT_SYMBOL_GPL(of_dma_is_coherent);-intof_dma_set_restricted_buffer(structdevice*dev)+intof_dma_set_restricted_buffer(structdevice*dev,structdevice_node*np){-structdevice_node*node;intcount,i;-if(!dev->of_node)+if(!np)return0;-count=of_property_count_elems_of_size(dev->of_node,"memory-region",+count=of_property_count_elems_of_size(np,"memory-region",sizeof(phandle));for(i=0;i<count;i++){-node=of_parse_phandle(dev->of_node,"memory-region",i);+structdevice_node*node;++node=of_parse_phandle(np,"memory-region",i);/* There might be multiple memory regions, but only one-*restriced-dma-poolregionisallowed.+*restricted-dma-poolregionisallowed.*/if(of_device_is_compatible(node,"restricted-dma-pool")&&of_device_is_available(node))-returnof_reserved_mem_device_init_by_idx(-dev,dev->of_node,i);+returnof_reserved_mem_device_init_by_idx(dev,np,i);}return0;
I still don't understand how this works for individual PCIe devices -- how
is dev->of_node set to point at the node you have above?
I tried adding the memory-region to the host controller instead, and then
I see it crop up in dmesg:
| pci-host-generic 40000000.pci: assigned reserved memory node restricted_dma_mem_reserved
but none of the actual PCI devices end up with 'dma_io_tlb_mem' set, and
so the restricted DMA area is not used. In fact, swiotlb isn't used at all.
What am I missing to make this work with PCIe devices?
Aha, looks like we're just missing the logic to inherit the DMA
configuration. The diff below gets things working for me.
I guess what was missing is the reg property in the pcie_device node.
Will update the example dts.
I still don't understand how this works for individual PCIe devices -- how
is dev->of_node set to point at the node you have above?
I tried adding the memory-region to the host controller instead, and then
I see it crop up in dmesg:
| pci-host-generic 40000000.pci: assigned reserved memory node restricted_dma_mem_reserved
but none of the actual PCI devices end up with 'dma_io_tlb_mem' set, and
so the restricted DMA area is not used. In fact, swiotlb isn't used at all.
What am I missing to make this work with PCIe devices?
Aha, looks like we're just missing the logic to inherit the DMA
configuration. The diff below gets things working for me.
I guess what was missing is the reg property in the pcie_device node.
Will update the example dts.
Thanks. I still think something like my diff makes sense, if you wouldn't mind including
it, as it allows restricted DMA to be used for situations where the PCIe
topology is not static.
Perhaps we should prefer dev->of_node if it exists, but then use the node
of the host bridge's parent node otherwise?
Will
I still don't understand how this works for individual PCIe devices -- how
is dev->of_node set to point at the node you have above?
I tried adding the memory-region to the host controller instead, and then
I see it crop up in dmesg:
| pci-host-generic 40000000.pci: assigned reserved memory node restricted_dma_mem_reserved
but none of the actual PCI devices end up with 'dma_io_tlb_mem' set, and
so the restricted DMA area is not used. In fact, swiotlb isn't used at all.
What am I missing to make this work with PCIe devices?
Aha, looks like we're just missing the logic to inherit the DMA
configuration. The diff below gets things working for me.
I guess what was missing is the reg property in the pcie_device node.
Will update the example dts.
Thanks. I still think something like my diff makes sense, if you wouldn't mind including
it, as it allows restricted DMA to be used for situations where the PCIe
topology is not static.
Perhaps we should prefer dev->of_node if it exists, but then use the node
of the host bridge's parent node otherwise?
I still don't understand how this works for individual PCIe devices -- how
is dev->of_node set to point at the node you have above?
I tried adding the memory-region to the host controller instead, and then
I see it crop up in dmesg:
| pci-host-generic 40000000.pci: assigned reserved memory node restricted_dma_mem_reserved
but none of the actual PCI devices end up with 'dma_io_tlb_mem' set, and
so the restricted DMA area is not used. In fact, swiotlb isn't used at all.
What am I missing to make this work with PCIe devices?
Aha, looks like we're just missing the logic to inherit the DMA
configuration. The diff below gets things working for me.
I guess what was missing is the reg property in the pcie_device node.
Will update the example dts.
Thanks. I still think something like my diff makes sense, if you wouldn't mind including
it, as it allows restricted DMA to be used for situations where the PCIe
topology is not static.
Perhaps we should prefer dev->of_node if it exists, but then use the node
of the host bridge's parent node otherwise?
Sure. Let me add in the next version.
Brill, thanks! I'll take it for a spin once it lands on the list.
Will
From: Christoph Hellwig <hch@lst.de> Date: 2021-05-27 13:02:24
On Wed, May 19, 2021 at 11:50:07AM -0700, Florian Fainelli wrote:
You convert this call site with swiotlb_init_io_tlb_mem() which did not
do the set_memory_decrypted()+memset(). Is this okay or should
swiotlb_init_io_tlb_mem() add an additional argument to do this
conditionally?
The zeroing is useful and was missing before. I think having a clean
state here is the right thing.
Not sure about the set_memory_decrypted, swiotlb_update_mem_attributes
kinda suggests it is too early to set the memory decrupted.
Adding Tom who should now about all this.
From: Christoph Hellwig <hch@lst.de> Date: 2021-05-27 13:27:20
On Mon, May 24, 2021 at 11:49:34AM -0400, Konrad Rzeszutek Wilk wrote:
rmem_swiotlb_setup
?
Which is ARM specific and inside the generic code?
I don't think it is arm specific at all. It is OF specific, but just
about every platform but x86 uses OF. And I can think of an ACPI version
of this as well.
From: Christoph Hellwig <hch@lst.de> Date: 2021-05-27 13:27:35
I'd still much prefer to always have the pointer in struct device.
Especially as we're also looking into things like a global 64-bit bounce
buffer. Something like this untested patch ontop of your series:
From: Christoph Hellwig <hch@lst.de> Date: 2021-05-27 13:28:31
+ if (is_swiotlb_active(NULL)) {
Passing a NULL argument to this doesn't make sense. They all should have
a struct device at hand, you'll just need to dig for it.
And this function should be about to go away anyway, but until then we
need to do this properly.
From: Tom Lendacky <thomas.lendacky@amd.com> Date: 2021-05-27 14:41:16
On 5/27/21 8:02 AM, Christoph Hellwig wrote:
On Wed, May 19, 2021 at 11:50:07AM -0700, Florian Fainelli wrote:
quoted
You convert this call site with swiotlb_init_io_tlb_mem() which did not
do the set_memory_decrypted()+memset(). Is this okay or should
swiotlb_init_io_tlb_mem() add an additional argument to do this
conditionally?
The zeroing is useful and was missing before. I think having a clean
state here is the right thing.
Not sure about the set_memory_decrypted, swiotlb_update_mem_attributes
kinda suggests it is too early to set the memory decrupted.
Adding Tom who should now about all this.
The reason for adding swiotlb_update_mem_attributes() was because having
the call to set_memory_decrypted() in swiotlb_init_with_tbl() triggered a
BUG_ON() related to interrupts not being enabled yet during boot. So that
call had to be delayed until interrupts were enabled.
Thanks,
Tom
From: Tom Lendacky <thomas.lendacky@amd.com> Date: 2021-05-27 16:32:14
On 5/27/21 9:41 AM, Tom Lendacky wrote:
On 5/27/21 8:02 AM, Christoph Hellwig wrote:
quoted
On Wed, May 19, 2021 at 11:50:07AM -0700, Florian Fainelli wrote:
quoted
You convert this call site with swiotlb_init_io_tlb_mem() which did not
do the set_memory_decrypted()+memset(). Is this okay or should
swiotlb_init_io_tlb_mem() add an additional argument to do this
conditionally?
The zeroing is useful and was missing before. I think having a clean
state here is the right thing.
Not sure about the set_memory_decrypted, swiotlb_update_mem_attributes
kinda suggests it is too early to set the memory decrupted.
Adding Tom who should now about all this.
The reason for adding swiotlb_update_mem_attributes() was because having
the call to set_memory_decrypted() in swiotlb_init_with_tbl() triggered a
BUG_ON() related to interrupts not being enabled yet during boot. So that
call had to be delayed until interrupts were enabled.
I pulled down and tested the patch set and booted with SME enabled. The
following was seen during the boot:
[ 0.134184] BUG: Bad page state in process swapper pfn:108002
[ 0.134196] page:(____ptrval____) refcount:0 mapcount:-128 mapping:0000000000000000 index:0x0 pfn:0x108002
[ 0.134201] flags: 0x17ffffc0000000(node=0|zone=2|lastcpupid=0x1fffff)
[ 0.134208] raw: 0017ffffc0000000 ffff88847f355e28 ffff88847f355e28 0000000000000000
[ 0.134210] raw: 0000000000000000 0000000000000001 00000000ffffff7f 0000000000000000
[ 0.134212] page dumped because: nonzero mapcount
[ 0.134213] Modules linked in:
[ 0.134218] CPU: 0 PID: 0 Comm: swapper Not tainted 5.13.0-rc2-sos-custom #3
[ 0.134221] Hardware name: ...
[ 0.134224] Call Trace:
[ 0.134233] dump_stack+0x76/0x94
[ 0.134244] bad_page+0xa6/0xf0
[ 0.134252] __free_pages_ok+0x331/0x360
[ 0.134256] memblock_free_all+0x158/0x1c1
[ 0.134267] mem_init+0x1f/0x14c
[ 0.134273] start_kernel+0x290/0x574
[ 0.134279] secondary_startup_64_no_verify+0xb0/0xbb
I see this about 40 times during the boot, each with a different PFN. The
system boots (which seemed odd), but I don't know if there will be side
effects to this (I didn't stress the system).
I modified the code to add a flag to not do the set_memory_decrypted(), as
suggested by Florian, when invoked from swiotlb_init_with_tbl(), and that
eliminated the bad page state BUG.
Thanks,
Tom
On Fri, May 28, 2021 at 12:32 AM Tom Lendacky [off-list ref] wrote:
On 5/27/21 9:41 AM, Tom Lendacky wrote:
quoted
On 5/27/21 8:02 AM, Christoph Hellwig wrote:
quoted
On Wed, May 19, 2021 at 11:50:07AM -0700, Florian Fainelli wrote:
quoted
You convert this call site with swiotlb_init_io_tlb_mem() which did not
do the set_memory_decrypted()+memset(). Is this okay or should
swiotlb_init_io_tlb_mem() add an additional argument to do this
conditionally?
The zeroing is useful and was missing before. I think having a clean
state here is the right thing.
Not sure about the set_memory_decrypted, swiotlb_update_mem_attributes
kinda suggests it is too early to set the memory decrupted.
Adding Tom who should now about all this.
The reason for adding swiotlb_update_mem_attributes() was because having
the call to set_memory_decrypted() in swiotlb_init_with_tbl() triggered a
BUG_ON() related to interrupts not being enabled yet during boot. So that
call had to be delayed until interrupts were enabled.
I pulled down and tested the patch set and booted with SME enabled. The
following was seen during the boot:
[ 0.134184] BUG: Bad page state in process swapper pfn:108002
[ 0.134196] page:(____ptrval____) refcount:0 mapcount:-128 mapping:0000000000000000 index:0x0 pfn:0x108002
[ 0.134201] flags: 0x17ffffc0000000(node=0|zone=2|lastcpupid=0x1fffff)
[ 0.134208] raw: 0017ffffc0000000 ffff88847f355e28 ffff88847f355e28 0000000000000000
[ 0.134210] raw: 0000000000000000 0000000000000001 00000000ffffff7f 0000000000000000
[ 0.134212] page dumped because: nonzero mapcount
[ 0.134213] Modules linked in:
[ 0.134218] CPU: 0 PID: 0 Comm: swapper Not tainted 5.13.0-rc2-sos-custom #3
[ 0.134221] Hardware name: ...
[ 0.134224] Call Trace:
[ 0.134233] dump_stack+0x76/0x94
[ 0.134244] bad_page+0xa6/0xf0
[ 0.134252] __free_pages_ok+0x331/0x360
[ 0.134256] memblock_free_all+0x158/0x1c1
[ 0.134267] mem_init+0x1f/0x14c
[ 0.134273] start_kernel+0x290/0x574
[ 0.134279] secondary_startup_64_no_verify+0xb0/0xbb
I see this about 40 times during the boot, each with a different PFN. The
system boots (which seemed odd), but I don't know if there will be side
effects to this (I didn't stress the system).
I modified the code to add a flag to not do the set_memory_decrypted(), as
suggested by Florian, when invoked from swiotlb_init_with_tbl(), and that
eliminated the bad page state BUG.
Thanks. Will add a flag to skip set_memory_decrypted() in v9.