linux内核中内存相关的操作函数.doc

上传人:大米 文档编号:563018544 上传时间:2023-10-27 格式:DOC 页数:6 大小:157.50KB
返回 下载 相关 举报
linux内核中内存相关的操作函数.doc_第1页
第1页 / 共6页
linux内核中内存相关的操作函数.doc_第2页
第2页 / 共6页
linux内核中内存相关的操作函数.doc_第3页
第3页 / 共6页
linux内核中内存相关的操作函数.doc_第4页
第4页 / 共6页
linux内核中内存相关的操作函数.doc_第5页
第5页 / 共6页
点击查看更多>>
资源描述

《linux内核中内存相关的操作函数.doc》由会员分享,可在线阅读,更多相关《linux内核中内存相关的操作函数.doc(6页珍藏版)》请在金锄头文库上搜索。

1、linux内核中内存相关的操作函数作者:harvey wang 邮箱:新浪博客地址:http:/ ,有关于减肥和学习英语相关的博文,欢迎交流1、kmalloc()/kfree()static _always_inline void *kmalloc(size_t size, gfp_t flags)内核空间申请指定大小的内存区域,返回内核空间虚拟地址。在函数实现中,如果申请的内存空间较大的话,会从buddy系统申请若干内存页面,如果申请的内存空间大小较小的话,会从slab系统中申请内存空间。有关buddy和slab,请参见linux内核之内存管理.docgfp_t flags 的选项较多。参考

2、内核文件gfp.h。在函数kmalloc()实现中,如果申请的空间较小,会根据申请空间的大小从slab中获取;如果申请的空间较大,如超过一个页面,会直接从buddy系统中获取。2、vmalloc()/vfree()void *vmalloc(unsigned long size)函数作用:从高端(如果存在,优先从高端)申请内存页面,并把申请的内存页面映射到内核的动态映射空间。vmalloc()函数的功能和alloc_pages(_GFP_HIGHMEM)+kmap() 的功能相似,只所以说是相似而不是相同,原因在于用vmalloc()申请的物理内存页面映射到内核的动态映射区(见下图),并且,用

3、vmalloc()申请的页面的物理地址可能是不连续的。而alloc_pages(_GFP_HIGHMEM)+kmap()申请的页面的物理地址是连续的,被映射到内核的KMAP区。vmalloc分配的地址则限于vmalloc_start与vmalloc_end之间。每一块vmalloc分配的内核虚拟内存都对应一个vm_struct结构体(可别和vm_area_struct搞混,那可是进程虚拟内存区域的结构),不同的内核虚拟地址被4k大小的空闲区间隔,以防止越界见下图)。与进程虚拟地址的特性一样,这些虚拟地址与物理内存没有简单的位移关系,必须通过内核页表才可转换为物理地址或物理页。它们有可能尚未被映

4、射,在发生缺页时才真正分配物理页面。如果内存紧张,连续区域无法满足,调用vmalloc分配是必须的,因为它可以将物理不连续的空间组合后分配,所以更能满足分配要求。vmalloc可以映射高端页框,也可以映射底端页框。vmalloc的作用只是为了提供逻辑上连续的地址。注意:在申请页面时,如果注明_GFP_HIGHMEM,即从高端申请。则实际是优先从高端内存申请,顺序为(分配顺序是HIGH, NORMAL, DMA )。3、alloc_pages()/free_pages()内核空间申请指定个数的内存页,内存页数必须是2order个页。alloc_pages(gfp_mask, order) 中,g

5、fp_mask 是flag标志,其中可以为_ _GFP_DMA、_GFP_HIGHMEM 分别对应DMA和高端内存。注:该函数基于buddy系统申请内存,申请的内存空间大小为2order个内存页面。参见linux内核之内存管理.doc通过函数alloc_pages()申请的内存,需要使用kmap()函数分配内核的虚拟地址。4、_get_free_pages()/_free_pages()unsigned long _get_free_pages(gfp_t gfp_mask, unsigned int order)作用相当于alloc_pages(NORMAL)+kmap(),但不能申请高端内

6、存页面。_get_free_page()只申请一个页面。5、kmap()/kunmap()返回指定页面对应内核空间的虚拟地址。#include void *kmap(struct page *page);void kunmap(struct page *page); kmap 为系统中的任何页返回一个内核虚拟地址. 对于低端内存页,它只返回页的逻辑地址; 对于高端内存页, kmap在“内核永久映射空间”中创建一个特殊的映射.这样的映射数目是有限, 因此最好不要持有过长的时间. 使用 kmap 创建的映射应当使用 kunmap 来释放; kmap 调用维护一个计数器, 因此若2个或多个函数都在同

7、一个页上调用kmap也是允许的.通常情况下,“内核永久映射空间”是 4M 大小,因此仅仅需要一个页表即可,内核通过来 pkmap_page_table 寻找这个页表。注意:不用时及时释放。kmalloc()和vmalloc()相比,kmalloc()总是从ZONE_NORMAL(下图中的直接映射区)申请内存。kmalloc()分配的内存空间通常用于linux内核的系统数据结构和链表。因内核需要经常访问其数据结构和链表,使用固定映射的ZONE_NORMAL空间的内存有利于提高效率。使用vmalloc()可以申请非连续的物理内存页,并组成虚拟连续内存空间。vmalloc()优先从高端内存(下图中的

8、动态映射区)申请。内核在分配那些不经常使用的内存时,都用高端内存空间(如果有),所谓不经常使用是相对来说的,比如内核的一些数据结构就属于经常使用的,而用户的一些数据就属于不经常使用的。alloc_pages(_GFP_HIGHMEM)+kmap() 方式申请的内存使用内核永久映射空间(下图中的KMAP区),空间较小(通常4M线性空间),不用时需要及时释放。另外,可以指定alloc_pages()从直接映射区申请内存,需要使用_GFP_NORMAL属性指定。_get_free_pages()/_free_pages() 不能申请高端内存页面,操作区域和kmalloc()相同(下图中的动态映射区)

9、。6、virt_to_page()其作用是由内核空间的虚拟地址得到页结构。见下面的宏定义。#define virt_to_pfn(kaddr)(_pa(kaddr) PAGE_SHIFT)#define pfn_to_virt(pfn)_va(pfn) PAGE_SHIFT)#define virt_to_page(addr)pfn_to_page(virt_to_pfn(addr)#define page_to_virt(page)pfn_to_virt(page_to_pfn(page)#define _pfn_to_page(pfn)(mem_map + (pfn) - ARCH_PFN

10、_OFFSET)#define _page_to_pfn(page)(unsigned long)(page) - mem_map) + ARCH_PFN_OFFSET)7、物理地址和虚拟地址之间转换#ifdef CONFIG_BOOKE#define _va(x) (void *)(unsigned long)(phys_addr_t)(x) + VIRT_PHYS_OFFSET)#define _pa(x) (unsigned long)(x) - VIRT_PHYS_OFFSET)#else#define _va(x) (void *)(unsigned long)(phys_addr_

11、t)(x) + PAGE_OFFSET - MEMORY_START)#define _pa(x) (unsigned long)(x) - PAGE_OFFSET + MEMORY_START)#endif8、ioremap()/iounmap()ioremap()的作用是把device寄存器和内存的物理地址区域映射到内核虚拟区域,返回值为内核的虚拟地址。注明:在内核中操作内存空间时使用的都是内核虚拟地址,必须把device的空间映射到内核虚拟空间。#include void *ioremap(unsigned long phys_addr, unsigned long size);void

12、 *ioremap_nocache(unsigned long phys_addr, unsigned long size); 映射非cache的io内存区域void iounmap(void * addr);为了增加可移植性,最好使用下面的接口函数读写io内存区域, unsigned int ioread8(void *addr);unsigned int ioread16(void *addr);unsigned int ioread32(void *addr); void iowrite8(u8 value, void *addr);void iowrite16(u16 value, v

13、oid *addr);void iowrite32(u32 value, void *addr);如果你必须读和写一系列值到一个给定的 I/O 内存地址, 你可以使用这些函数的重复版本:void ioread8_rep(void *addr, void *buf, unsigned long count);void ioread16_rep(void *addr, void *buf, unsigned long count);void ioread32_rep(void *addr, void *buf, unsigned long count);void iowrite8_rep(void

14、 *addr, const void *buf, unsigned long count);void iowrite16_rep(void *addr, const void *buf, unsigned long count);void iowrite32_rep(void *addr, const void *buf, unsigned long count);这些函数读或写 count 值从给定的 buf 到 给定的 addr. 注意 count 表达为在被写入的数据大小; ioread32_rep 读取 count 32-位值从 buf 开始.9、request_mem_region(

15、)本函数的作用是:外设的io端口映射到io memory region中。在本函数实现中会检查输入到本函数的参数所描述的空间(下面成为本io空间)是否和io memory region中已存在的空间冲突等,并设置本io空间的parent字段等(把本io空间插入到io 空间树种)。注明:io memory region 空间中是以树形结构组织的,默认的根为iomem_resource描述的io空间,其name为PCI mem。request_mem_region(start,n,name) 输入的参数依次是设备的物理地址,字节长度,设备名字。函数返回类型如下struct resource resource_size_t start;resource_size_t end;const char *name;unsigned long flags;struct resource *par

展开阅读全文
相关资源
相关搜索

当前位置:首页 > 生活休闲 > 社会民生

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