Linux内核驱动--mmap设备方法【原创】

简介:

mmap系统调用(功能)

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

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

 

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

len:          映射到内存的文件长度

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

PROT_EXEC:  映射区可被执行

PROT_READ:  映射区可被读取

PROT_WRITE: 映射区可被写入

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

                 MAP_SHARED:

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

                 MAP_PRIVATE:

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

fd:            由open返回的文件描述符,代表要映射的文件

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

 

 

解除映射

int munmap(void *start, size_t length)

功能:

                 取消参数start所指向的映射内存,参数length表示欲取消的内存大小

返回值:

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

注意:

mmap      不影响原文件的长度,如果写入的长度超出了原文件的长度,那么就只能写入原文件的长度大小的数据内容

代码:

#include <stdio.h>

 #include <string.h>                                                                                

 #include <sys/types.h>

 #include <sys/stat.h>

 #include <fcntl.h>

 #include <unistd.h>

 #include <sys/mman.h>

 

 int main(void)

-{

|    int fd;

|    char *start=NULL;

|    char buf[100];

|

|    fd = open("t.txt", O_RDWR | O_CREAT);

|    start = mmap(NULL, 100, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);

|       

|    strcpy(buf, start);

|    printf("buf is %s\r\n", buf);

|

|    strcpy(start, "sky is hello");

|    munmap(start, 100);

|    close(fd);

|

|    return 0;

|}

 

虚拟内存区域

     虚拟内存区域是进程的虚拟地址空间中的一个同质区间,即具有同样特性的连续地址

范围。一个进程的内存映像由下面几部分组成:程序代码、数据、BSS和栈区域,以及内存

映射的区域。

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

例如:cat   /proc/6/maps 

 

每一行的域为:

Start_end perm offset major:minor inode

Start: 该区域起始虚拟地址

End:该区域结束虚拟地址

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

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

Major、minor: 主次设备号

Inode: 索引结点

Linux内核使用结构vm_area_struct

(<linux/mm_types.h>)来描述虚拟内存区域,其中几个主要成员如下:

unsigned long vm_start   虚拟内存区域起始地址

unsigned long vm_end    虚拟内存区域结束地址

unsigned long vm_flags    该区域的标记。如:VM_IO和VM_RESERVED。

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

 

mmap设备操作

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

内存管理单元去关联的,通过页式管理关联的,具体如何关联的去了解linux内存管理吧。

mmap设备方法需要完成什么功能?

Mmap方法是file_oprations结构的成员,在mmap系统调用发出时被调用。在此之前,内核已经完成了很多工作。Mmap设备方法所需要做的就是建立虚拟地址到物理地址的页表。

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

mmap如何完成页表的建立?

方法有二:

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

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

 

构造页表的工作可由remap_pfn_range函数完成,原型如下:

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

vma:                         虚拟内存区域指针

virt_addr:        虚拟地址的起始值

pfn:                          要映射的物理地址所在的物理页帧号,可将物理地址>>PAGE_SHIFT得到,这个宏定义是12,就是除以4KB

size:              要映射的区域的大小

prot:              VMA的保护属性

 

例子:

int memdev_mmap(struct file *filp, struct vm_area_struct *vma)

{

        //设置保护属性

        vma->vm_flags |= VM_IO;

        vma->vm_flags |= VM_RESERVED;

 

        if (remap_pfm_range(vma, vma->vma-start, virt_to_phys(dev->data)>>PAGE_SHIFT,

size, vma->vm_page_prot))

                 return –EAGAIN;

        return 0;

}

Dev-data是虚拟地址,就要用virt_to_phys转换为物理地址,如果是物理地址,那就不用转化了。

这样就实现了mmap的设备操作

欢迎交流
如有转载请注明出处

新浪博客:http://blog.sina.com.cn/u/2049150530
博客园:http://www.cnblogs.com/sky-heaven/
知乎:http://www.zhihu.com/people/zhang-bing-hua











本文转自张昺华-sky博客园博客,原文链接:http://www.cnblogs.com/sky-heaven/p/4508147.html,如需转载请自行联系原作者


相关文章
|
16天前
|
Linux C语言
Linux内核队列queue.h
Linux内核队列queue.h
|
17天前
|
关系型数据库 MySQL Linux
linux CentOS 7.4下 mysql5.7.20 密码改简单的方法
linux CentOS 7.4下 mysql5.7.20 密码改简单的方法
21 0
|
1天前
|
人工智能 Linux
Linux查找大文件的方法
Linux查找大文件的方法
|
9天前
|
算法 Linux 调度
深入理解Linux内核的进程调度机制
【4月更文挑战第17天】在多任务操作系统中,进程调度是核心功能之一,它决定了处理机资源的分配。本文旨在剖析Linux操作系统内核的进程调度机制,详细讨论其调度策略、调度算法及实现原理,并探讨了其对系统性能的影响。通过分析CFS(完全公平调度器)和实时调度策略,揭示了Linux如何在保证响应速度与公平性之间取得平衡。文章还将评估最新的调度技术趋势,如容器化和云计算环境下的调度优化。
|
11天前
|
Linux Go
Linux命令Top 100驱动人生! 面试必备
探索Linux命令不再迷茫!本文分10部分详解20个基础命令,带你由浅入深掌握文件、目录管理和文本处理。 [1]: <https://cloud.tencent.com/developer/article/2396114> [2]: <https://pan.quark.cn/s/865a0bbd5720> [3]: <https://yv4kfv1n3j.feishu.cn/docx/MRyxdaqz8ow5RjxyL1ucrvOYnnH>
64 0
|
14天前
|
算法 Linux 调度
深度解析:Linux内核的进程调度机制
【4月更文挑战第12天】 在多任务操作系统如Linux中,进程调度机制是系统的核心组成部分之一,它决定了处理器资源如何分配给多个竞争的进程。本文深入探讨了Linux内核中的进程调度策略和相关算法,包括其设计哲学、实现原理及对系统性能的影响。通过分析进程调度器的工作原理,我们能够理解操作系统如何平衡效率、公平性和响应性,进而优化系统表现和用户体验。
20 3
|
17天前
|
Linux Shell 虚拟化
linux 部署docker容器虚拟化平台(二)--------docker 镜像制作方法
linux 部署docker容器虚拟化平台(二)--------docker 镜像制作方法
28 0
|
17天前
|
网络协议 Linux SDN
虚拟网络设备与Linux网络协议栈
在现代计算环境中,虚拟网络设备在实现灵活的网络配置和隔离方面发挥了至关重要的作用🔧,特别是在容器化和虚拟化技术广泛应用的今天🌐。而Linux网络协议栈则是操作系统处理网络通信的核心💻,它支持广泛的协议和网络服务🌍,确保数据正确地在网络中传输。本文将深入分析虚拟网络设备与Linux网络协议栈的关联,揭示它们如何共同工作以支持复杂的网络需求。
|
18天前
|
存储 缓存 固态存储
Linux设备全览:从字符到块,揭秘每种设备的秘密
在Linux的世界里,设备是构成系统的基础,它们使得计算机能够与外界互动。Linux设备可以大致分为几种类型,每种类型都有其独特的特性和用途。🌌让我们一起探索这些设备类型及其特性。
|
19天前
|
监控 Linux