内存映射

1.地址类型
用户虚拟地址
物理地址
总线地址
内核逻辑地址            kmalloc()分配的内存区域
内核虚拟地址            vmalloc()分配的内存区域
在<asm/page.h>中,宏__pa()/__va()可以进行逻辑地址和物理地址之间的转换。但只对低端内存页有效。
 
2.物理地址和页
PAGE_SIZE       PAGE_SHIFT
 
3.高端与低端内存
有多少内存可以直接映射到逻辑地址是受限制的。
只有内存的低端部分(依赖于硬件和呵呵的设置,一般为1到2GB)拥有逻辑地址; 
剩余的部分(高端内存)没有逻辑地址,在访问特定的高端内存页前,内核必须建立明确的虚拟映射,使该
页可在内核地址空间中被访问。因此,许多内核数据结构必须被设置在低端内存中,而高端内存趋于为用户
空间进程页所保留。
 
4.内存映射和页结构
page结构中有几个重要成员
atomic_t count;                 引用计数;
void *virtual                           如果页面被映射,则指向页的内核虚拟地址;
unsigned long flags;        描述页状态的一系列标志。
一些宏和函数
struct page *virt t_to_page(void *kaddr)        
将内核逻辑地址转换为page结构指针,因为需要逻辑地址,不能用于vmalloc()分配的地址和高端内存
struct page *pfn_to_page(int pfn)        
通过给定的页帧号返回page指针            
struct page *page_address(struct page *page)
返回页的内核虚拟地址,不可以用于未映射的高端内存
void *kmap(struct page *page)
返回页的虚拟地址,可以用于未映射的高端内存
void kunmap(struct page *page)
 
5页表
页表是将虚拟地址转换为相应的物理地址的一种机制。
 
6.虚拟内存区
进程的内存映射至少包含:程序的可执行代码区域,多个数据区域,与每个活动的内存映射对应的区域
下面给出了vm_area_struct的几个重要成员:
struct vm_area_struct { 
    struct mm_struct;
    unsigned long vm_start;     
    unsigned long vm_end;                     
    pgprot_t vm_page_prot;                            /* Access permissions of this VMA. */ 
    unsigned long vm_flags;                          //我们感兴趣的标志是VM_IO   VM_RESERVED
    struct vm_operations_struct * vm_ops; 
     unsigned long vm_pgoff;                         //该区域在文件中的偏移量
    struct file * vm_file;                                     //指向与该区域相关联的file结构指针
    void * vm_private_data;                             //保存自身信息的成员
};
给出了vm_operations_struct的重要成员
struct vm_operations_struct {
    void (*open) (...);
    void (*close) (...);
    struct page *(*nopage)(...)                       //将物理页从辅助存储器中读入后,返回指向物理页的page结构指针
}
7.内存映射处理
在系统中的每一个进程都拥有一个struct mm_struct 结构,其中包含了虚拟内存区域链表,页表以及其他大量
内存管理信息。
 
8.mmap设备操作
不是所有的设备都能进行mmap抽象的。比如像串口和其他面向流的设备就不能做这样的抽象。
mmap的另一个限制是必须以PAGE_SIZE为单位进行映射。内核只能在页表一级上对虚拟地址进行管理,因此那
些被映射的区域必须是PAGE_SIZE的整数倍。
执行mmap,驱动主要完成两件工作:
	为该地址范围建立合适的页表;
	将vma->vm_ops替换为一系列的新操作
两种建立页表的方法:
8.1 remap_pfn_range函数一次全部建立
	int remap_pfn_range(struct vm_area_struct *vma,unsigned long virt_addr,unsigned long pfn,
			unsigned long size,pgprot_t prot);
8.2 nopage VMA方法每次建立一个页表,nopage函数需要为失效地址查找正确的page结构,并且增加它的引用计数。
 	strut page *(*nopage)(struct vm_area_struct *vma,unsigned long address,int *type);
  	pfn_valid函数可以判断页帧号是否合法
	在设备驱动中,type的正确值应该总是VM_FAULT_MINOR
	返回值为一个指向page结构的指针,出错将返回NOPAGE_SIGBUS,返回NOPAGE_OOM表示资源紧张而造成的错误。
         PCI内存被映射到系统内存最高端上,因此在系统内存映射中没有这些地址的入口,无法返回一个指向page的指针,所以必须使用
	remap_pfn_range
	如果一个进程调用mremap扩充一个映射区域,而驱动程序没有实现nopage,则进程将最终得到一块全是零的内存,而不会产生段
	故障错误
9.重新映射RAM
remap_page_range只能访问保留页和超出物理内存的物理地址。在linux中,内存映射时,物理地址页被标记为“保留的”,表示内存管理
对其不起作用
remap_page_range不允许重新映射常规地址,包括调用get_free_page函数所获得的地址。但是他能重新映射高端PCI缓冲区和ISA内存和
零内存页。
10.nopage重新映射RAM,重新映射内核虚拟地址
在scullp中 virt_to_page获得相应的page结构指针 (该函数不能在内核虚拟空间使用)。
在scullv中 vmalloc_to_page获得相应的 page结构指针 
 
 
 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值