linux设备驱动归纳总结(五)1在内核空间分配内存

上传人:ss****gk 文档编号:209184481 上传时间:2021-11-09 格式:DOC 页数:10 大小:79KB
返回 下载 相关 举报
linux设备驱动归纳总结(五)1在内核空间分配内存_第1页
第1页 / 共10页
linux设备驱动归纳总结(五)1在内核空间分配内存_第2页
第2页 / 共10页
linux设备驱动归纳总结(五)1在内核空间分配内存_第3页
第3页 / 共10页
linux设备驱动归纳总结(五)1在内核空间分配内存_第4页
第4页 / 共10页
linux设备驱动归纳总结(五)1在内核空间分配内存_第5页
第5页 / 共10页
点击查看更多>>
资源描述

《linux设备驱动归纳总结(五)1在内核空间分配内存》由会员分享,可在线阅读,更多相关《linux设备驱动归纳总结(五)1在内核空间分配内存(10页珍藏版)》请在金锄头文库上搜索。

1、一般的,用户空间使用函数malloc在堆上分配内存空间,同样的,在内核空间 同样有一套类似的函数来分配空间。下面的知识会涉及页式管理的内存机制,如 果不懂的要先复习一下,在S3C2440数据手册的MMU部分有介绍。XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX一、内核空间和用户空间有什么不同学C语言的时候应该学过,从用户空间看,每个进程都傻乎乎的以为自己有4G 的内存空间,其中位于高地址(3G-4G)的1G空间给内核用,另外的3G (0-3G) 都是它一个人独占的。所以

2、用户空间很慷慨的把3G的空间分了好几个区域,如 堆、栈、代码段等。其中,mallocO分配的空间位于堆,而程序中的自动变量, 如你在函数内定义的“inti”,它是放在栈上,同时。用户空间的栈是可变栈,即 随着数据的增多,对应函数的栈空间也会增多。跟每个用户空间的进程不一样,内核只有1G的空间,同时,除了自己本身有进 程运行外,内核还要允许用户空间进程调用系统调用进入内核空间去执行。所以, 内核对此相当吝啬,它规定在内核中的每个进程都只有4KB或8KB (32位下) 的定长栈。出于这样的原因,大的数据结构就不能在栈中分配,只能请求内核分 配新的空间来存放数据,如函数kmalloc()。XXXXX

3、XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX二、内存的基本单位是字节吗?在介绍分配内存空间的函数前,我们还要了解一下内存是怎么被划分的。内核不仅知道用户空间中看到的1G内核空间是假的,它还知道实际的物理内存 是多少(我的开发板是64M)。所以,内核的其中一个任务就是,当这段虚假 内存中的数据需要调用时,内核把这段虚拟内存与实际的物理内存对应上,运行 完后又把两段内存的对应关系撤销掉给男外的虚拟内存用。既然知道虚拟内存与物理内存的关系,那它们是怎么对应的,难道是一个一个字 节?如

4、果这样子做的话内核肯定觉得崩溃。页是内存管理的基木单位。内存管理器(MMU,用于虚拟地址与物理地址之间 的转换)通常以页为单位进行出来。页是内存管理的最小单位。在32位的系统 中,一页的大小为4KB。所以,64M的物理内存将被分为16384个页。每一个 物理页对皮地用一个struct page来维护,注意,该结构体是用来维护物理页,而 不是虚拟也,结构体记录该页是否被使用,对应的虚拟地址是多少等信息。由于内存访问的限制,内核乂把内存分成了3个区。如有些硬件的访问只能在24位的地址空间寻址,出于这总访问限制,lirwx把前 16MB划分为ZONE_DMA用于直接内存访问(MDA)。在x86体系里

5、,高于896M的内存空间称为高端内存,这段内存区域的页和普通 的内存页操作后有差异,这段区域划分为ZONE_HIGHMEM。剩下的,加载这两段区域之间的就是我们平时用的普通内存区域ZONE_NORMALo这这里要注意一下:1)这些分区是指linux自己分的,当然,如果普通分区不够用,当然也可以占用 其他区的空间。2)分区的大小是根据体系结构而定的,一般的ARM下,ZONE_NORMAL就是 所有的可用内存区域。XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX三、分配内存时

6、使用的标记gfp_mask在讲如何分配内存之前,先讲一下分配内存时将会用到的gfp_mask。简单地讲, 这个标记指定了分配内存时的要求。具体分三类:行为修饰符:表示内核应当如何分配内存,如指定不能休眠等。区修饰符:指定内存将耍分配到上面讲的三个区中的哪一个。类型标记:这含了上面两种修饰符(或运算),这些标记是为了让用户更好地 去使用。标记有很多,我这里不一一介绍,需要的可以自己查阅linux内核设计与实现 (第三版)P238页。这里我讲两个常用的类型标记:1) GFP_KERNEL:最常用的标记,用于可睡眠的进程上下文。2) GFP.ATOMIC:使用了这个标记,内存分配函数不会引起随眠。3

7、) GFP_USER:当需要给用户空间分配内存空间时使用该标记。XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX四、分配内存的第一种方法按页分配这是内核提供的一种请求内存的底层机制,都是以页为单位分配内存。以下函数 包含在 linux/gfh.h这分为两个步骤:1、请求内核分配页,获得物理页对应的结构体struct page:static inline struct page * alloc_pages(gfp_t gfp_mask, unsigned int order

8、)使用:该函数用于申请(lother)即2的other次方个连续物理页,gfp_mask用于指 定分配的方式,一般使用GFP_KERNEL或GFP_ATOMIC。注意:函数会引起 睡眠返回值:成功返回一个指针,指向这连续物理页的第一个struct page结构体,失败返回 NULL。2、分配页后还不能直接用,需要得到该页对应的虚拟地址: void *page_address(struct page *page)其实这个函数就是获取page的成员virtual,但千万不耍直接访问,需要使用这 个函数。函数返回的是物理页对应的虚拟地址,注意,如果你申请了多个物理页, 分配的物理页是连续的,对应的虚

9、拟地址也是连续的。上而的两个步骤其实可以合成一个函数:unsigned long _get_free_pages(gfp_t gfp_mask, unsigned int order)这个函数的传参和alloc_pages的一样,不过它直接返回申请的物理页对应的虚 拟地址。当然,无论使用上而的哪种方法,当内存不用时,需要调用函数释放:1、如果你使用上面的第一种方法:void _free_pages(struct page *page,unsigned int order)2、如果你使用的是第二种方法:void free_pages(unsigned long addr,unsigned int

10、 order)下而来个程序:/*5th_mm/5th_mm_l/l st/test.c*/1 #include 2 #include 33 #include 54 struct page *p;5 char *s;86 static int _init test_init(void) /模块初始化函数7 8 unsigned long virt, phys;129 #define SWITCH 0 /通过定义这个来切换校验这两种不同的方法10 #if SWITCH11 /alloc 2 pages16p = alloc_pages(GFP_KERNEL, 1);17 if (NULL = p)

11、 /必须检验错误18 printk(alloc page error!n);19 return - ENOMEM;20 21 s = page_address(p);22 #else23 s = (char *)_get_free_pages(GFP_KERNEL, 1);24 if (NULL = s)25 printkCalloc page error!n);26 return - ENOMEM;27 28 #endif2929 phys = _pa(unsigned long)s); /通过虚拟地址获得对应的物理地址30 virt = (unsigned long)_va(phys);

12、/通过物理地址获得对应的虚拟地址31 printk(virtual, s%pnn, s); /打印获得的虚拟地址32 prmtk(%pn, (void *)phys); /打印对应的物理地址33 printk(H%pnH, (void *)virt); /再打印虚拟地址,其实就是分配函数返回 的地址3534 memcpy(s, hello mm, 20);3735 printk(hello kerneln);36 return 0;37 4138 static void exit test exit(void) /模块卸载函数39 40 #if SWITCH41 _free_pages(p,

13、1);42 #else43 free_pages(unsigned long)s, 1);44 #endif4945 printk(”good bye kerneln);46 5247 module_init(test_init);48 module_exit(test一exit);5549 MODULE_LICENSECGPLH);50 MODULE_AUTHOR(xoao baiH);51 MODULE一VERSIONSvO.l);再检验一下:root: 1st# insmod test.ko virtual, sc3968000 /虚拟地址 33968000 /对应的实际地址 c3968

14、000hello kernel hello mm打印出来了,hello 美眉!上面我分配了两页后什么也没做,当然,如果你要是只分配一页,内核有贴心函 数:#define alloc_page(gfp_mask) alloc_pages(gfp_mask, 0)#define _get一free一page(gfp_mask) _get_free_pages(gfp_mask),O)男外还有一个函数,不仅给你分配一页空间,还帮你清零了,特别适用于给用户 空间分配内存。nsigned long get_zeroed_page(gfp_t gfp一mask)xxxxxxxxxxxxxxxxxxxxxx

15、xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx五、分配内存的第二种方法kmalloc()kmalloc()的用法和malloc差不多,只是多了一个我前面介绍的标志gfp_flag。上函数,需要包含头文件linux/slab.h void *kmalloc(size_t size, gfp_t flags)成功返回指向这块内存的地址(虚拟地址),失败返回NULL。这里注意一下, 返回的内存大小不一定是size,因为内存的分配是基于页来分配的,有时需要地 址对齐之类,所有分配的内存地址可能比size大。函数同样会引起睡眠,如果不 能睡眠需要使用GFP_ATOMIC。分配的内存必须释放,使用函数: void kfree(const void *objp)上个程序:/*5

展开阅读全文
相关资源
正为您匹配相似的精品文档
相关搜索

最新文档


当前位置:首页 > 办公文档 > 其它办公文档

电脑版 |金锄头文库版权所有
经营许可证:蜀ICP备13022795号 | 川公网安备 51140202000112号