zoukankan      html  css  js  c++  java
  • Linux驱动mmap操作

    1.page  主要成员

    atomic_t count;

    //这个页的引用数. 当这个 count 掉到 0, 这页被返回给空闲列表.

    void *virtual;

    //如果页被映射,则表示这页的内核虚拟地址; 否则, NULL.

    unsigned long flags;

    //描述页状态的一套位标志. 这些包括 PG_locked, 它指示该页在内存中已被加锁, 以及 PG_reserved,

    //它防止内存管理系统使用该页

    2.vm_area_struct  主要成员

    unsigned long vm_start;//VMA 开始于

    unsigned long vm_end; //VMA 结束

    struct file *vm_file;

    //指向和这个区(如果有一个)关联的 struct file 结构的指针.

    unsigned long vm_pgoff;

    //文件中区的偏移, 以页计. 当一个文件和设备被映射, 这是映射在这个区的第一页的文件位置.?????

    unsigned long vm_flags;

    // 设备驱动常用的标志是 VM_IO VM_RESERVUED.

    //VM_IO 标志一个 VMA 作为内存映射的 I/O ,阻止这个区被包含在进程核转储???中.

    //VM_RESERVED 告知内存管理系统不要试图交换出这个 VMA;

    struct vm_operations_struct *vm_ops;

    //操作

    //void (*open)(struct vm_area_struct *vma);  VMA刚刚产生时,此函数被调用来初始化VMA

    //void (*close)(struct vm_area_struct *vma);  当一个区被销毁, 内核调用它的关闭操作

    //struct page *(*nopage)(struct vm_area_struct *vma, unsigned long address, int *type);

    //如果 nopage 方法没有定义,内核分配一个空页.进程存取不在内存中有效 VMA 的页时,nopage 方法被调用(如果它被定义)

    //int (*populate)(struct vm_area_struct *vm, unsigned long address, unsigned long len, pgprot_t prot, unsigned long pgoff, int

    nonblock);

    //在它们被用户空间存取之前,允许内核"预错"页到内存. 驱动通常没有必要实现这个填充方法

    void *vm_private_data;

    //驱动可以用来存储它的自身信息的成员.

    3.mmap用户空间调用与内核空间调用

    void *mmap(void *start,size_t length,int prot,int flags,int fd,off_t offset);

    //start 指向欲对应的内存起始地址,通常设为NULL,代表让系统自动选定地址,对应成功后该地址会返回

    //参数length代表将文件中多大的部分对应到内存。

    //参数prot代表映射区域的保护方式

    //fd文件描述符

    //参数offset为文件映射的偏移量,通常设置为0,代表从文件最前方开始对应,offset必须是分页大小

    //的整数倍,映射文件的起动位移量受系统虚存页长度的限制,那么如果映射区的长度不是页长度的整数

    //倍时,将如何呢?假定文件长12字节,系统页长为512字节,则系统通常提供512字节的映射区,其中

    //500字节被设为0。可以修改这500字节,但任何变动都不会在文件中反映出来

    //若映射成功则返回映射区的内存起始地址,否则返回MAP_FAILED(-1

    内核空间调用

    int (*mmap) (struct file *filp, struct vm_area_struct *vma);

    4.mmap执行的顺序

          a.在用户进程创建一个vma区域

          b.驱动程序获得页

          c.将获得的页分配给vma区域

    四、如何给VMA分配页

    1.一次完成全部

    int remap_pfn_range(struct vm_area_struct *vma, unsigned long virt_addr, unsigned long pfn, unsigned long size, pgprot_t prot);

    //vma 用户进程创建一个vma区域

    //virt_addr 重新映射应当开始的用户虚拟地址. 这个函数建立页表为这个虚拟地址范围从 virt_addr virt_addr_size.

    //pfn 页帧号, 对应虚拟地址应当被映射的物理地址. 这个页帧号简单地是物理地址右移 PAGE_SHIFT . 对大部分使用, VMA 结构的 vm_paoff 成员正好包含你需要的值. 这个函数影响物理地址从 (pfn<<PAGE_SHIFT) (pfn<<PAGE_SHIFT)+size.

    //size 正在被重新映射的区的大小, 以字节.

    //prot 给新 VMA 要求的"protection". 驱动可(并且应当)使用在vma->vm_page_prot 中找到的值.

    //返回的值常常是 0 或者一个负的错误值

    int io_remap_page_range(struct vm_area_struct *vma, unsigned long virt_addr, unsigned long phys_addr, unsigned long size, pgprot_t prot);

    //当用在 phys_addr 指向 I/O 内存时返回的值常常是 0 或者一个负的错误值???

    2.一页一页的分配

    struct page *(*nopage)(struct vm_area_struct *vma, unsigned long address, int *type);

    //address 代表从用户空间传过来的用户空间虚拟地址

    //返回一个有效映射页

    3.限制

    remap_pfn_range不能映射常规内存,只存取保留页和在物理内存顶之上的物理地址。因为保留页和在物理

    内存顶之上的物理地址内存管理系统的各个子模块管理不到。640 KB 1MB 是保留页可能映射,设备I/O

    内存也可以映射。如果想把kmalloc()申请的内存映射到用户空间,则可以通过mem_map_reserve()把相应

    的内存设置为保留后就可以。

    remap_pfn_range常用于设备内存映射,而nopage()常用于RAM映射

  • 相关阅读:
    一则线上MySql连接异常的排查过程
    有一种娱乐叫看别人编程
    程序员DNS知识指南
    中国式开源
    RSS与公众号
    论国人的素质和一个公司的商业道德
    《阿里游戏高可用架构设计实践》阅读笔记
    《淘宝数据魔方技术架构解析》阅读笔记
    软件体系架构_系统质量属性场景描述_结合《淘宝网》实例
    《余额宝技术架构及演进》阅读笔记
  • 原文地址:https://www.cnblogs.com/sinaxyz/p/2648032.html
Copyright © 2011-2022 走看看