DMA分配内存,能用那些函数,那些不能用?why? 因为 DMA物理地址要连续
2012-04-20 21:35
375 查看
这两天有空重读了ldd的第8章内存管理,这本书是很好,但是有的内容不太实用,下面结合工作需要把常用的内容作下总结。
注意:下文提到的 j-one 平台内存是 128M。
1. ioremap :
ioremap 会按照页的大小调整映射size。另外,当地址没有页对齐的时候,ioremap会rounding down这个地址,也就是向下圆整地址,然后返回内存页的首地址+offset。下面是ldd的原文:
ioremap simulates an unaligned mapping by “rounding down” the address to be remapped and by returning an offset into the first remapped page.
2. kmalloc :
kmalloc 分配的内存物理地址连续。
1) 两个常用的flag:GFP_KERNEL和GFP_ATOMIC
2) size :
这个函数分配的内存必须是2的n次方。另外,这个函数分配的内存有大小限制。在arm平台上,最少分配32字节。最大依平台而异。比如:公司的j-one平台,最大能分配4M。
注:
下面具体分析下它的代码,
以 arm 平台为例,kmalloc 的实现在 include\linux\slab_def.h(但是不一定都在这个文件,在宏的控制下还有可能是其他两个文件 CONFIG_SLUB,CONFIG_SLOB)。其中控制分配buffer大小的代码在 #include <linux/kmalloc_sizes.h> 里面 。
由这个文件可知,KMALLOC_MAX_SIZE 就是最大 size 。下面是这个宏的定义:
#define KMALLOC_MAX_SIZE (1UL << KMALLOC_SHIFT_HIGH)
#define KMALLOC_SHIFT_HIGH ((MAX_ORDER + PAGE_SHIFT - 1) <= 25 ? \
(MAX_ORDER + PAGE_SHIFT - 1) : 25)
下面是在j-one平台上打出来的log
**********************************
KMALLOC_MAX_SIZE = 4194304
KMALLOC_SHIFT_HIGH = 22
MAX_ORDER = 11
PAGE_SHIFT = 12
failed to alloc 4194304+1
succeed to alloc 4194304
**********************************
3)物理地址与虚拟地址的关系:
在arm平台下kmalloc分配的内存的虚拟地址和物理地址只差一个偏移量。
注:
因为 kmalloc 最终还是调用 __get_free_pages,所以只要分析这个函数就好。见 page_alloc.c。
在该函数的最后一行也就是 page_alloc.c 1987行,page_address 这个宏将物理地址转换为虚拟地址。
arm平台的 page_address 参见 include/linux/mm.h 615行,
#define page_address(page) lowmem_page_address(page)
lowmem_page_address的实现参考同一个文件 590行,可以看到它是通过__va宏来做转换。
而__va可以参考 arch/arm/include/asm/memory.h, line 185。
#define __va(x) ((void *)__phys_to_virt((unsigned long)(x)))
在同一个文件的129行,可以看到
#define __phys_to_virt(x) ((x) - PHYS_OFFSET + PAGE_OFFSET)
所以确实如书中所说从物理地址到虚拟地址,只差一个偏移量。
3. 大块内存的分配:
1)alloc_bootmem:
该函数族要在内存管理子系统启动前调用,另外这个函数族分配的内存即使释放也不能由内存管理子系统回收。
2)另外一个方法是在启动参数中保留一块高地址内存。
4. vmalloc:
虚拟地址连续,物理地址不一定连续。
注意:kmalloc与vmalloc的区别是,前者分配的内存虚拟地址与物理地址之间只差一个偏移量,而vmalloc分配的内存则不是,另外vmalloc需要重建页表,从而vmalloc有性能问题。另外,和 ioremap 一样,vmalloc 要按照 page 对 size 参数圆整。
5. __get_free_pages:
该函数在分配大块内存时使用。注意:在j-one平台上最大只能分配10个page,所以它实际上和 kmalloc 一样,只能分配最大 4M 内存。
6. dma_alloc_writecombine 和 dma_alloc_coherent
如果需要分配关闭 cache 或者关闭 write buffer 的内存,可以使用这两个函数。
两者区别参见:arch\arm\include\asm\dma-mapping.h
dma_alloc_coherent:uncached, unbuffered
dma_alloc_writecombine:uncached, buffered
注意:下文提到的 j-one 平台内存是 128M。
1. ioremap :
ioremap 会按照页的大小调整映射size。另外,当地址没有页对齐的时候,ioremap会rounding down这个地址,也就是向下圆整地址,然后返回内存页的首地址+offset。下面是ldd的原文:
ioremap simulates an unaligned mapping by “rounding down” the address to be remapped and by returning an offset into the first remapped page.
2. kmalloc :
kmalloc 分配的内存物理地址连续。
1) 两个常用的flag:GFP_KERNEL和GFP_ATOMIC
2) size :
这个函数分配的内存必须是2的n次方。另外,这个函数分配的内存有大小限制。在arm平台上,最少分配32字节。最大依平台而异。比如:公司的j-one平台,最大能分配4M。
注:
下面具体分析下它的代码,
以 arm 平台为例,kmalloc 的实现在 include\linux\slab_def.h(但是不一定都在这个文件,在宏的控制下还有可能是其他两个文件 CONFIG_SLUB,CONFIG_SLOB)。其中控制分配buffer大小的代码在 #include <linux/kmalloc_sizes.h> 里面 。
由这个文件可知,KMALLOC_MAX_SIZE 就是最大 size 。下面是这个宏的定义:
#define KMALLOC_MAX_SIZE (1UL << KMALLOC_SHIFT_HIGH)
#define KMALLOC_SHIFT_HIGH ((MAX_ORDER + PAGE_SHIFT - 1) <= 25 ? \
(MAX_ORDER + PAGE_SHIFT - 1) : 25)
下面是在j-one平台上打出来的log
**********************************
KMALLOC_MAX_SIZE = 4194304
KMALLOC_SHIFT_HIGH = 22
MAX_ORDER = 11
PAGE_SHIFT = 12
failed to alloc 4194304+1
succeed to alloc 4194304
**********************************
3)物理地址与虚拟地址的关系:
在arm平台下kmalloc分配的内存的虚拟地址和物理地址只差一个偏移量。
注:
因为 kmalloc 最终还是调用 __get_free_pages,所以只要分析这个函数就好。见 page_alloc.c。
在该函数的最后一行也就是 page_alloc.c 1987行,page_address 这个宏将物理地址转换为虚拟地址。
arm平台的 page_address 参见 include/linux/mm.h 615行,
#define page_address(page) lowmem_page_address(page)
lowmem_page_address的实现参考同一个文件 590行,可以看到它是通过__va宏来做转换。
而__va可以参考 arch/arm/include/asm/memory.h, line 185。
#define __va(x) ((void *)__phys_to_virt((unsigned long)(x)))
在同一个文件的129行,可以看到
#define __phys_to_virt(x) ((x) - PHYS_OFFSET + PAGE_OFFSET)
所以确实如书中所说从物理地址到虚拟地址,只差一个偏移量。
3. 大块内存的分配:
1)alloc_bootmem:
该函数族要在内存管理子系统启动前调用,另外这个函数族分配的内存即使释放也不能由内存管理子系统回收。
2)另外一个方法是在启动参数中保留一块高地址内存。
4. vmalloc:
虚拟地址连续,物理地址不一定连续。
注意:kmalloc与vmalloc的区别是,前者分配的内存虚拟地址与物理地址之间只差一个偏移量,而vmalloc分配的内存则不是,另外vmalloc需要重建页表,从而vmalloc有性能问题。另外,和 ioremap 一样,vmalloc 要按照 page 对 size 参数圆整。
5. __get_free_pages:
该函数在分配大块内存时使用。注意:在j-one平台上最大只能分配10个page,所以它实际上和 kmalloc 一样,只能分配最大 4M 内存。
6. dma_alloc_writecombine 和 dma_alloc_coherent
如果需要分配关闭 cache 或者关闭 write buffer 的内存,可以使用这两个函数。
两者区别参见:arch\arm\include\asm\dma-mapping.h
dma_alloc_coherent:uncached, unbuffered
dma_alloc_writecombine:uncached, buffered
相关文章推荐
- 编写一个函数new,对n个字符开辟连续的存储空间,此函数应返回一个指针(地址),指向字符串开始的空间。new(n)表示分配n个字节的内存空间。
- Linux系统下,能保证物理空间上连续的内存分配函数是?
- 在内核中分配物理地址连续的大内存.
- 习题 8.19(1) 编写一个函数new,对n个字符开辟连续的存储空间,此函数应返回一个指针(地址),指向字符串开始的空间。new(n)表示分配n个字节的内存空间。
- delphi技术专题---获取网卡物理地址之内存获取方式函数源码
- 编写了个videobuf以获得物理上连续的大的内存(DMA)
- C语言学习7 :二级指针定义,强制转换,多级指针初步,6级指针构造,错误应用*p=&a,错误应用 二级p2,void型指针的兼容性,malloc函数基本用法,malloc分配空间和堆栈空间的区别,验证malloc函数内存的分配,验证malloc函数的越界,内存泄漏,指针不能返回局部变量地址,内存分配
- Kernel 4.9 上 dma_alloc_coherent() 函数开辟 DMA 连续内存空间失败 解决办法
- Linux的内存管理主要分为两部分:物理地址到虚拟地址的映射,内核内存分配管理(主要基于slab)。
- linux内存管理之非连续物理地址分配(vmalloc)
- 不能返回函数内部new分配的内存的引用
- C语言学习9: malloc动态内存存储,动态内存分配去空格字符增长版,动态内存分配去符号incr增长版,型参和返回值都是int型的函数的指针,main函数的地址也可以用指针指向,typedef定义函数指针,函数定义与嵌套的作用,返回函数指针类型,const作用
- 终于懂了:Delphi的函数名不是地址,取地址必须遵守Object Pascal的语法(Delphi和C的类比:指针、字符串、函数指针、内存分配等)good
- 宏定义函数指针类型&函数返回左值类值 1。宏定义不分配内存,变量定义分配内存。 2。宏名和参数的括号间不能有空格 3。宏替换只作替换,不做计算,不做表达式求解 //下面是正确的标准的写法 typedef int(FUNC1)(int in); ty
- 函数指针类的虚函数表是一块连续的内存,每个内存单元中记录一个JMP指令的地址。 注意的是,编译器会为每个有虚函数的类创建一个虚函数表,该虚函数表将被该类的所有对象共享。类的每个虚成员占据虚函数表中的一
- linux内存管理之非连续物理地址分配(vmalloc)
- inux内存管理之非连续物理地址分配(vmalloc)
- 编写了个videobuf-contig.c以获得物理上连续的大的内存(DMA)
- __GFP_DIRECT_RECLAIM 对smmu申请memory的函数是申请物理不连续的内存?
- linux内存管理之非连续物理地址分配(vmalloc