Linux驱动开发之mmap设备操作

一、mmap系统调用

void* mmap ( void * addr , size_tlen , int prot , int flags ,int fd , off_t offset )

        内存映射函数mmap, 负责把文件内容映射到进程的虚拟内存空间, 通过对这段内存的读取和修改,来实现对文件的读取和修改,不需要再调用readwrite等操作。

参数说明

 1、addr:指定映射的起始地址, 通常设为NULL, 由系统指定。

 2、length:映射到内存的文件长度。

 3、prot:映射区的保护方式, 可以是:

  PROT_EXEC: 映射区可被执行

  PROT_READ: 映射区可被读取

  PROT_WRITE: 映射区可被写入

 4、flags: 映射区的特性, 可以是:

MAP_SHARED:

      写入映射区的数据会复制回文件, 且允许其他映射该文件的进程共享。

MAP_PRIVATE:

  对映射区的写入操作会产生一个映射区的复制(copy-on-write), 对此区域所做的修改不会写回原文件。

5、fd:

open返回的文件描述符, 代表要映射的文件。

6、offset

    以文件开始处的偏移量, 必须是分页大小的整数倍, 通常为0, 表示从文件头开始映射。

二、解除映射

int munmap(void *start,size_t length)

1、功能:取消参数start所指向的映射内存,参数length示取消的内存大小。

2、返回值:解除成功返回0,否则返回-1,错误原因存于errno中。

3、实例分析

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/mman.h>
#include <string.h>

int main(void)
{
int fd;
char *start;
char buf[50];

fd = open("file", O_RDWR);//打开设备文件
start = mmap(NULL, 50, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);// 建立映射关系

strcpy(buf, start);// 读文件
printf("buf=%s\n", buf);

strcpy(start, "Hello World!!!\n");// 写文件

munmap(start, 50);// 解除映射
close(fd);// 关闭设备文件

return 0;
}

三、虚拟内存区域

        虚拟内存区域是进程的虚拟地址空间中的一个同质区间,即具有同样特性的连续地址范围。一个进程的内存映象组成为:程序代码、数据、BSS(未初始化数据段)和堆栈区域,以及内存映射的区域。      

        一个进程的内存区域可通过查看/proc/pid/maps

00400000-0043d000 r-xp 00000000 08:09 10622706                           /usr/lib/udisks/udisks-daemon
0063c000-0063d000 r--p 0003c000 08:09 10622706                           /usr/lib/udisks/udisks-daemon
0063d000-0063e000 rw-p 0003d000 08:09 10622706                           /usr/lib/udisks/udisks-daemon
0063e000-0063f000 rw-p 00000000 00:00 0 
01de1000-01e02000 rw-p 00000000 00:00 0                                  [heap]
7f65e0607000-7f65e0609000 r-xp 00000000 08:09 25953191                   /lib/x86_64-linux-gnu/libdl-2.15.so
7f65e0609000-7f65e0809000 ---p 00002000 08:09 25953191                   /lib/x86_64-linux-gnu/libdl-2.15.so
7f65e0809000-7f65e080a000 r--p 00002000 08:09 25953191                   /lib/x86_64-linux-gnu/libdl-2.15.so
7f65e080a000-7f65e080b000 rw-p 00003000 08:09 25953191                   /lib/x86_64-linux-gnu/libdl-2.15.so
7f65e080b000-7f65e0847000 r-xp 00000000 08:09 25953848                   /lib/x86_64-linux-gnu/libpcre.so.3.12.1
7f65e0847000-7f65e0a46000 ---p 0003c000 08:09 25953848                   /lib/x86_64-linux-gnu/libpcre.so.3.12.1
7f65e0a46000-7f65e0a47000 r--p 0003b000 08:09 25953848                   /lib/x86_64-linux-gnu/libpcre.so.3.12.1
7f65e0a47000-7f65e0a48000 rw-p 0003c000 08:09 25953848                   /lib/x86_64-linux-gnu/libpcre.so.3.12.1
7f65e0a48000-7f65e0a4f000 r-xp 00000000 08:09 10618343                   /usr/lib/x86_64-linux-gnu/libffi.so.6.0.0
7f65e0a4f000-7f65e0c4e000 ---p 00007000 08:09 10618343                   /usr/lib/x86_64-linux-gnu/libffi.so.6.0.0
7f65e0c4e000-7f65e0c4f000 r--p 00006000 08:09 10618343                   /usr/lib/x86_64-linux-gnu/libffi.so.6.0.0
7f65e0c4f000-7f65e0c50000 rw-p 00007000 08:09 10618343                   /usr/lib/x86_64-linux-gnu/libffi.so.6.0.0
7f65e0c50000-7f65e0c5c000 r-xp 00000000 08:09 25953698                   /lib/x86_64-linux-gnu/libudev.so.0.13.0
7f65e0c5c000-7f65e0e5b000 ---p 0000c000 08:09 25953698                   /lib/x86_64-linux-gnu/libudev.so.0.13.0
7f65e0e5b000-7f65e0e5c000 r--p 0000b000 08:09 25953698                   /lib/x86_64-linux-gnu/libudev.so.0.13.0
7f65e0e5c000-7f65e0e5d000 rw-p 0000c000 08:09 25953698                   /lib/x86_64-linux-gnu/libudev.so.0.13.0
7f65e0e5d000-7f65e0e75000 r-xp 00000000 08:09 25953197                   /lib/x86_64-linux-gnu/libresolv-2.15.so
7f65e0e75000-7f65e1075000 ---p 00018000 08:09 25953197                   /lib/x86_64-linux-gnu/libresolv-2.15.so
7f65e1075000-7f65e1076000 r--p 00018000 08:09 25953197                   /lib/x86_64-linux-gnu/libresolv-2.15.so
7f65e1076000-7f65e1077000 rw-p 00019000 08:09 25953197                   /lib/x86_64-linux-gnu/libresolv-2.15.so
7f65e1077000-7f65e1079000 rw-p 00000000 00:00 0 
7f65e1079000-7f65e1096000 r-xp 00000000 08:09 25979837                   /lib/x86_64-linux-gnu/libselinux.so.1

每一行的域为:start_end perm offset major:minor inode

 start: 该区域起始虚拟地址 

 end:   该区域结束虚拟地址

 perm读、写和执行权限;表示对这个区域,允 许进程做什么。这个域的最后一个字符要么是p表示私有的, 要么是s表示共享的。

offset : 被映射部分在文件中的起始地址

majorminor:主次设备号

inode:索引结点

Linux内核使用结构体vm_area_struct<linux/mm_types.h>)来描述虚拟内存区域,其中几个主要成员如下:

unsigned long vm_start

虚拟内存区域起始地址

unsigned long vm_end

虚拟内存区域结束地址

unsignedlong vm_flags

该区域的标记。如:VM_IOVM_RESERVEDVM_IO 将 该 VMA 标记 为 内 存 映 射 的 IO 区域 , VM_IO会阻止系统将该区域包含在进程的存放转(core dump )中,VM_RESERVED标志内存区域不能被换出。

        映射一个设备是指把用户空间的一段地址关联到设备内存上。当程序读写这段用户空间的地址时,实际上是在访问设备。       

        mmap方法是file_oprations结构体的成员,在mmap系统调用发出时被调用。在此之前,内核已经完成

了很多工作。mmap设备方法所需要做的就是建立虚拟地址到物理地址的页表

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

mmap如何完成页表的建立?

方法有二:

1、使用remap_pfn_range一次建立所有页表;

2、使用nopage VMA方法每次建立一个页表。

include/linux/mm.h
int remap_pfn_range(struct vm_area_struct *, unsigned long addr,
                        unsigned long pfn, unsigned long size, pgprot_t);

1)vma:虚拟内存区域指针

2)virt_addr:虚拟地址的起始值

3)pfn:要映射的物理地址所在的物理页帧号,可将物理地址>>PAGE_SHIFT得到。

4) size:要映射的区域的大小。

5) prot:VMA的保护属性。


  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值