http://blog.163.com/chujb_chen/blog/static/10571112013392331217/
函数功能描述:
alloc_pages( )函数以gfp_mask分配方式分配2的order次方(1<<order)个连续的物理页。
输入参数说明:
gfp_mask: 是分配标志,内核分配内存有多种方式,该参数告诉内核如何分配以及在哪分配所需的内存,内存分配最终总是调用 __get_free_pages( ) 来实现,这也是 GFP_ 前缀的由来。其中分配标志(gfp_mask)可以取以下各值:
GFP_KERNEL
该分配方式最常用,是内核内存的正常分配,它可能睡眠。
GFP_ATOMIC
该分配方式常用来从中断处理和进程上下文之外的其他代码中分配内存,从不睡眠。
GFP_USER
用来为用户空间分配内存页,可能睡眠。
GFP_HIGHUSER
类似GFP_USER,如果有高端内存,就从高端内存分配页。
GFP_NOIO
GFP_NOFS
功能类似于GFP_KERNEL,但是为内核分配内存的工作增加了限制。具有GFP_NOFS 的分配不允许执行任何文件系统调用,而 GFP_NOIO 禁止任何 I/O 初始化。它们主要用在文件系统和虚拟内存代码,那里允许分配休眠,但不应发生递归的文件系统调用。
有的标志用双下划线做前缀,他们可与上面标志“或”起来使用,以控制分配方式:
__GFP_DMA
要求分配可用于DMA的内存。
__GFP_HIGHMEM
分配的内存可以位于高端内存。
__GFP_NOWARN
当一个分配无法满足,阻止内核发出警告(使用 printk )。
__GFP_HIGH
高优先级请求,允许为紧急状况消耗被内核保留的最后一些内存页。
__GFP_REPEAT
__GFP_NOFAIL
__GFP_NORETRY
告诉分配器当满足一个分配有困难时,如何动作。__GFP_REPEAT 表示努力再尝试一次,仍然可能失败;__GFP_NOFAIL告诉分配器尽最大努力来满足要求,始终不返回失败,不推荐使用;__GFP_NORETRY 告知分配器如果无法满足请求,立即返回。
order:指要释放的物理页数,其取值为2的order次方个。
返回参数说明:
alloc_pages( )函数返回page结构体指针,指向所分配的物理页中的第一个页,如果分配不成功,则返回NULL。
实例解析:
编写测试文件:alloc_page.c
头文件及全局变量声明如下:
#include <linux/init.h>
#include <linux/module.h>
#include <linux/gfp.h>
#include <linux/mm_types.h>
#include <linux/mm.h>
MODULE_LICENSE("GPL");
static int __init alloc_pages_init(void);
static void __exit alloc_pages_exit(void);
struct page * pages = NULL;
int __init alloc_pages_init(void)
{
pages = alloc_pages(GFP_KERNEL,3); //分配8个物理页
if(!pages)
{
return -ENOMEM;
}
else
{
printk("<0>alloc_pages Successfully!\n");
printk("<0>pages = 0x%lx\n",(unsigned long)pages); //输出pages值,即第一个页的页描述符地址
//输出mem_map数组的起始地址
printk("<0>mem_map = 0x%lx\n",(unsigned long)mem_map);
//分配的第一个页相对mem_map数组起始位置的偏移
printk("<0>pages-mem_map = 0x%lx\n",(unsigned long)pages-(unsigned long)mem_map);
//第一个页pages的物理地址
printk("(pages-mem_map)*4096 = 0x%lx\n",(unsigned long)(pages-mem_map)*4096);
//第一个页pages的逻辑地址
printk("<0>page_address(pages) = 0x%lx\n",(unsigned long)page_address(pages));
}
return 0;
}
void __exit alloc_pages_exit(void)
{
if(pages)
{
__free_pages(pages,3); //释放所分配的8个页
printk("<0>__free_pages ok!\n");
}
printk("<0>exit\n");
}
module_init(alloc_pages_init);
module_exit(alloc_pages_exit);
实例运行结果及分析:
首先编译模块,执行命令insmod alloc_pages.ko插入模块,然后执行命令dmesg –c,会出现如图所示的结果:
测试程序中调用了内核函数alloc_pages( )分配2的3次方即8个连续的物理页面,返回指针赋值给pages,指向所分配的物理页中第一个页的结构体。之后通过输出pages相关的一些信息来获取页的分配情况。
首 先输出pages的值,即是第一个页描述符的地址为0xc12c5400。然后输出mem_map数组的起始地址为0xc1000000,它是一个 page类型的数组,管理所有的物理内存,其位置一般是在0xc1000000。(pages-mem_map)是alloc_pages( )函数所分配的第一个页相对mem_map数组起始位置的偏移,由输出信息可知,该偏移值为0x2c5400。(pages-mem_map)*4096 即为页的物理地址(其中4096为每一页面大小),它为0x162a0000。最后调用了宏page_address( ),它接收页的描述符指针作为参数得到该页的逻辑地址,由输出信息可知第一个页pages的逻辑地址为0xd62a0000,它是由该页物理地址 0x162a0000加上PAGE_OFFSET(3G).
具体分析请参考文献:《Linux内核API完全参考手册》邱铁,周玉,邓莹莹 编著,机械工业出版社 2011年1月1日出版
得到的
转载自:http://hi.baidu.com/armlinuxqt/item/2c1f9e049f9106c775cd3c66