浅谈ioremap,vmalloc,mmap三者之间的实现&区别

前言

系统mmu开启后, 程序对内存的访问都是虚拟地址, 之后mmu会自动将虚拟地址变为实际的物理地址(硬件行为), 所以我们的程序如果要访问物理地址的话,必须要通过mmu建立虚拟地址与物理地址之间的映射关系。对于虚拟地址映射到物理地址的操作, 涉及到3个典型的函数.

  • ioremap
    • 在driver中使用,一般用于映射registers address。
  • vmalloc
    • 在dirver中使用,在内存的vmalloc区申请一块连续的虚拟空间,生成虚拟空间所对应的物理地址并非连续。
  • mmap
    • 在应用层使用,实现在应用层也可以访问物理地址

上述阐述了三个函数的使用场景,但同样都是虚拟地址映射到物理地址,它们之间有什么区别呢? 这个问题必须要了解它们的实现才能明白,我们并不打算详细的分析代码,而是给出大体关键的脉络来解决,想通这个问题。

ioremap 与 vmalloc

这两个函数之所以放在一起讲,是因为它们的实现几乎是一样的。
这两个函数都是从VMALLOC区(内核虚拟地址空间)分配一个空闲的虚拟地址空间(※注意是虚拟地址空间), 我们看张图来理解一下函数的实现
在这里插入图片描述
首先,VMALLOC区 是由两个结构体维护的,即:struct vmap_area和 struct vm_struct。
其中vmap_area是专门用来管理 VMALLOC区域的虚拟空间。
即,一个vmap_area结构代表一块有效的虚拟空间, 当调用vmalloc函数或者ioremap时:

  • 首先通过kmalloc创建一个 vmap_area结构体。
  • 遍历vmap_area_root红黑树,找到VMALLOC区中的一个虚拟地址addr,这个addr与树中所有vmap_area结构体所管理的地址范围都没有重合。
  • 之后将addr赋值到新创建的vmap_area结构体中,并插入到 vmap_area_root的红黑树中。

以上,新创建的 vmap_area结构体管理着addr地址以及size范围,即虚拟地址已经申请好了,那又如何映射到物理地址呢?
这里就需要 struct vm_struct结构体来管理了,vm_struct记录着虚拟地址与物理地址之间的关系。
我们紧接着上面的流程:

  • vmap_area结构被赋值好后,会把其中的虚拟地址信息赋值到新创建的vm_struct中,之后
  • 对于ioremap函数,知道了虚拟地址addr,知道了物理地址:寄存器地址(传入的参数),直接调用映射函数完成对mmu的编程,实现addr与寄存器地址之间的映射关系
  • 对于vmalloc函数,知道了虚拟地址addr后,从伙伴系统中申请size(vmalloc函数的参数)大小的物理地址空间,之后调用映射函数完成虚拟地址与物理页之间的映射关系。

总结:

  • vmalloc与ioremap在驱动中才能用,因为申请的虚拟内存是在内核的地址范围内,是从VMALLOC区域申请的。
  • ioremap从VMALLOC区申请到虚拟地址后,直接映射(因为物理地址已知): virtual addr <–> regsiters address。
  • vmalloc从VMALLOC区申请到虚拟地址后,需要申请size大小的物理地址空间(vmalloc参数指定),然后在映射: virtual addr <–> 物理地址。
mmap

mmap,即实现:在应用层的虚拟地址空间(0->3G)中,找到一块可用的虚拟地址(vma),然后将这块虚拟空间的地址范围传入到driver,在driver中实现映射:vma<–>物理地址(一般显示driver经常这么用)
在这里插入图片描述
上图中我们可以看到,应用层的虚拟空间也类似于内核空间的VMALLOC区,也需要一个结构体管理:vm_area_struct,我们简称vma.不同的是,应用虚拟空间的管理,是在进程描述符中维护的,即不同的进程管理不同的vma。
对于一个进程的0-3G的虚拟空间,用vm_area_struct结构体来维护,一个vma代表一块有效的虚拟地址空间。
同一个vma存在于两个地方,一个是在mmap这个变量中,用链表维护着,方便统计,一个是在mm_rb所在的红黑树中维护,方便遍历查找。
我们通过上图中红框框的部分来描述mmap的实现过程(类似于上面的两个函数)

  • 首先,遍历mm_rb管理的红黑树,找出0-3G空间中的可用地址范围
    即,找到的地址addr,不能跟树中的所有vm_area_struct所管理的地址范围重合
  • 创建一个vma(vm_area_struct结构体), 将addr以及范围size赋值到此结构体中.
  • 把vma传给driver, error = file->f_op->mmap(file, vma);
  • driver中调用f_op->mmap,因为要映射的虚拟地址vma通过参数传进来了, 所以仅调用remap_pfn_range相关函数即可完成映射(物理地址空间是driver提前准备好的)
  • 如果映射成功,将vma 插入到mmap链表中,然后在插入到红黑树mm_rb中
    • __vma_link
总结
  • ioremap与vmalloc 是在内核虚拟空间的VMALLOC区申请虚拟地址
  • mmap是在当前进程的user虚拟空间申请虚拟内存
  • 4
    点赞
  • 28
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值