Kmap
来源:互联网 发布:源码交易系统 编辑:程序博客网 时间:2024/06/14 16:53
Kmap
void *kmap(struct page *page)
这个函数在高端内存或低端内存上都能用。如果page结构对应的是低端内存中的一页,函数只会单纯的返回该页的虚拟地址。如果页位于高端内存,则会建立一个永久映射,再返回地址。这个函数可以睡眠,因此kmap()只能在进程上下文中。
因为允许永久映射是有限的,当不需要高端内存时,应该接触映射,可以通过以下函数解除。
void kunmap(struct page *page)
高端内存
Linux将内核地址空间划分为三部分ZONE_DMA
ZONE_NORMAL
ZONE_HIGHMEM
,高端内存HIGH_MEM地址空间范围为 0xF8000000 ~ 0xFFFFFFFF(896MB~1024MB)。那么如内核是如何借助128MB高端内存地址空间是如何实现访问可以所有物理内存?
当内核想访问高于896MB物理地址内存时,从0xF8000000 ~ 0xFFFFFFFF地址空间范围内找一段相应大小空闲的逻辑地址空间,借用一会。借用这段逻辑地址空间,建立映射到想访问的那段物理内存(即填充内核PTE页面表),临时用一会,用完后归还
。这样别人也可以借用这段地址空间访问其他物理内存,实现了使用有限的地址空间,访问所有所有物理内存。如下图。
例 如内核想访问2G开始的一段大小为1MB的物理内存,即物理地址范围为0×80000000 ~ 0x800FFFFF。访问之前先找到一段1MB大小的空闲地址空间,假设找到的空闲地址空间为0xF8700000 ~ 0xF87FFFFF,用这1MB的逻辑地址空间映射到物理地址空间0×80000000 ~ 0x800FFFFF的内存。映射关系如下:
当内核访问完0×80000000 ~ 0x800FFFFF物理内存后,就将0xF8700000 ~ 0xF87FFFFF内核线性空间释放。这样其他进程或代码也可以使用0xF8700000 ~ 0xF87FFFFF这段地址访问其他物理内存。
具体实现
void *kmap(struct page *page){ might_sleep(); if (!PageHighMem(page))//如果是低端内存,直接返回内存页对应的虚拟地址。 return page_address(page); return kmap_high(page);//否则 需要进行高端内存映射}void *kmap_high(struct page *page){ unsigned long vaddr; /* * For highmem pages, we can't trust "virtual" until * after we have the lock. */ lock_kmap();//防止并发 vaddr = (unsigned long)page_address(page);//直接进行映射 if (!vaddr)//如果上一步失败 vaddr = map_new_virtual(page);//建立新的映射 pkmap_count[PKMAP_NR(vaddr)]++;//如果建立成功,引用加1,表示已被映射,2表示此映射还有额外的引用 BUG_ON(pkmap_count[PKMAP_NR(vaddr)] < 2); unlock_kmap(); return (void*) vaddr;}static inline unsigned long map_new_virtual(struct page *page){ unsigned long vaddr; int count;start: count = LAST_PKMAP; /* Find an empty entry */ for (;;) { last_pkmap_nr = (last_pkmap_nr + 1) & LAST_PKMAP_MASK; if (!last_pkmap_nr) { flush_all_zero_pkmaps();//先解除一部分映射 count = LAST_PKMAP; } if (!pkmap_count[last_pkmap_nr])//计数为零 证明没有人在使用 break; /* Found a usable entry */ if (--count)//遍历整个kmap空间,如果不存在未使用的映射,就睡眠等待kunmap continue; /* * Sleep for somebody else to unmap their entries */ { DECLARE_WAITQUEUE(wait, current); __set_current_state(TASK_UNINTERRUPTIBLE); add_wait_queue(&pkmap_map_wait, &wait); unlock_kmap(); schedule(); remove_wait_queue(&pkmap_map_wait, &wait); lock_kmap(); /* Somebody else might have mapped it while we slept */ if (page_address(page)) return (unsigned long)page_address(page); /* Re-start */ goto start; } } vaddr = PKMAP_ADDR(last_pkmap_nr); set_pte_at(&init_mm, vaddr, &(pkmap_page_table[last_pkmap_nr]), mk_pte(page, kmap_prot)); pkmap_count[last_pkmap_nr] = 1; set_page_address(page, (void *)vaddr); return vaddr;}
实现流程图
参考文档
linux 用户空间与内核空间——高端内存详解
- Kmap
- kmap的实现分析
- bzoj 3743 kmap
- 关于kmalloc、vmalloc及kmap
- 关于kmalloc、vmalloc及kmap
- 关于kmalloc、vmalloc及kmap
- 关于kmalloc、vmalloc及kmap
- kmap/kmalloc/ioremap/kmalloc/kzalloc/kcalloc/vmalloc
- kmap/kmalloc/ioremap/kmalloc/kzalloc/kcalloc/vmalloc
- kmalloc,vmalloc,kmap 缺页的讨论
- kmap的实现分析与实验
- kmalloc、vmalloc、kmap、malloc的区别
- [Linux内存]永久内存映射kmap
- kmap的实现分析与实验
- kmap的实现分析与实验
- 高端内存映射之kmap持久内核映射--Linux内存管理(二十)
- mfc 多文档 静态视图分拆
- 2017-03-11 [IOI2002]任务安排
- Win7下用U盘安装Centos6.3双系统
- Linux_C第二次作业
- CentOS7安装tkinter
- Kmap
- iframe 获取值无法将console.log的对象转换为 string
- 单例的理解和应用
- linux上搭建hadoop环境(hadoop 2.7.1)总结
- Redis常用命令-Hash
- 机器视觉学习笔记(3)--如何去雾
- 巧用Live Template,不仅能提升AS开发效率,还能装逼
- 简单递归求阶乘
- 浮点数介绍及使用注意事项