字符设备file_oprations---mmap

参考文档:vmalloc与mmap_承刚-CSDN博客

mmap

1 概念

mmap:内核空间映射到用户空间虚拟地址上。之后,应用程序直接访问映射后的虚拟地址,实际是在访问内核空间

2 流程

image-20211109160924103

mmap :为申请的地址空间建立合适的页表

3 申请物理内存

3.1 kmalloc

内核中,申请连续的物理内存,用于小内存分配。

作用:内核中用于指定字节大小的内存分配函数,跟应用层的malloc()和free()对应。

 // kmalloc返回的虚拟地址和物理地址有一个固定偏移关系
 void  *kmalloc(size_t size,gfp_t flags);
 // 需要指定gfp_t
 void kfree(const void *ptr)

3.2 vmalloc

内核为了满足某些大块内存申请需求,提供了一组函数:

 void *vmalloc(unsigned long size)
 参数:要申请的内存块的大小
 void vfree(void *addr)

注意:用于分配一块非连续的地址空间,物理地址一般是非连续的,但是虚拟地址是连续的,分配的内存空间 被映射进入内核数据段中,从用户空间是不可见的。

这些不连续的物理块,内核中用结构struct vm_struct来表示。

image-20210929165141698

描述:这是一个链表,记录vmalloc所得到的每块的地址、大小和对应的页面等信息。

3.3 vmalloc_user()

作用:功能类似于vmalloc(),在vmalloc()的基础上将地址空间清零,这样该地址空间被映射到用户空间不会发生数据泄露。 一般情况下,这段虚拟内存是当前进程空间的,因此会给它添加一个VM_USERMAP的flag 。防止将kernel space 的数据泄露到user space。

 #include<linux/vmalloc.h>
 void *vmalloc_user(unsigned long size)
 {
     void *ret;
     #首先通过__vmalloc申请一段大小为size的虚拟内存
     ret = __vmalloc(size, GFP_KERNEL | __GFP_ZERO, PAGE_KERNEL);
     if (ret) {
         struct vm_area_struct *vma;
  
         down_write(&current->mm->mmap_sem);
         #在当前进程空间中查找这段虚拟空间,一般情况下可以找到,找到后或上VM_USERMAP
         vma = find_vma(current->mm, (unsigned long)ret);
         if (vma)
             vma->vm_flags |= VM_USERMAP;
         up_write(&current->mm->mmap_sem);
     }
     #返回虚拟地址,r如果失败的话,则返回null
     return ret;
 }

3.4 对比

3.4.1 kmalloc和vmalloc

相同:

  1. 都是申请内核空间的物理内存

不同:

  • 物理内存是否连续:kmalloc用于申请较小的,连续的物理内存

    vmalloc申请较大的,不连续的物理内存

  • 虚拟内存位置(见下图): kmalloc()分配的内存处于3GB~ high_memory(低端内存)

    vm_struct 分配的内存在VMALLOC_START ~ 4GB(高端内存)之间。相邻的vm_struct之间都有4K的安全间隙。

  • 物理地址对应关系:kmalloc返回的虚拟地址和物理地址由一个固定偏移关系,vmalloc返回的虚拟地址 和物理地址 没有线性关系,需要遍历页表才可以找到物理地址

  • kmalloc一般用于给数据结构分配内存,DMA(容易获得物理地址);vmalloc用在为活动的交换区 分配数据,为I/O驱动程序分配缓冲区,或为模块分配空间

image-20210930094954001

3.4.2 vmalloc和vmalloc_user

区别:

4 remap

4.1 remap_pfn_range()

应用:将kmalloc()申请的内存映射到用户空间

函数作用:为一段物理地址(addr ~ addr+size 之间)建立新的页表,pfn指向实际的RAM时使用

 函数原型:
 int remap_pfn_range(struct vm_area_struct *vma, unsigned long addr,
            unsigned long pfn, unsigned long size, pgprot_t prot);    
 参数:
     vma :虚拟内存区域:在一定范围内的页将被映射到该区域内
     addr:重新映射时,用户空间虚拟地址起始处
     size: 被重新映射的区域大小,字节为单位
     pfn:与物理内存对应的页帧号,虚拟内存将要被映射到该物理内存上,页帧号只是将物理地址右移PAGE_SHIFT位(物理地址 >> PAGE_SHIFT)
         
     prot:保护属性 vma->vm_page_prot
 返回值: 成功:0  
         错误:负的错误码

4.2 remap_vmalloc_range()

类似remap_pfn_range()

 /**
  * remap_vmalloc_range - map vmalloc pages to userspace
  * @vma:        mmap使用调用传下来的vma to cover (map full range of vma)
  * @addr:       vmalloc分配内存的起始地址
  * @pgoff:      偏移参数,根据vma->vm_pgoff获取
  */
 int remap_vmalloc_range(struct vm_area_struct *vma, void *addr,
                         unsigned long pgoff)
 {
     return remap_vmalloc_range_partial(vma, vma->vm_start,
                        addr, pgoff,
                        vma->vm_end - vma->vm_start);
 }
 EXPORT_SYMBOL(remap_vmalloc_range);
 ​

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值