微波EDA网,见证研发工程师的成长!
首页 > 硬件设计 > 嵌入式设计 > arm驱动linux设备地址映射到用户空间

arm驱动linux设备地址映射到用户空间

时间:11-19 来源:互联网 点击:
[《[arm驱动]linux设备地址映射用户空间》涉及内核驱动函数二个,内核结构体二个,分析了内核驱动函数二个;可参考的相关应用程序模板或内核驱动模板二个,可参考的相关应用程序模板或内核驱动四个

一、问题描述:一般情况下,用户空间是不可能也不应该直接访问设备的,但是,设备驱动程序中可实现mmap()函数,这个函数可使用户空间直接访问设备的物理地址。
1、mmap()函数工作原理:mmap()实现了这样的一个映射过程,它将用户的内存空间的一般内存(准确来说是执行mmap进程的映射区域内存)与设备内存关联,当用户访问用户空间的这段地址范围时,实际上会转化为对设备的访问(linux上一切皆文件)。

文件内存映射原理图示 a

2、mmap优点:1、对于设备文件,最大的有点就是用户空间可以直接访问设备内存;2、普通文件被映射到进程地址空间后,进程进程访问文件的速度也变块,不必再调read(),write(),可以用memcpy,strcpy等操作写文件,写完后用msync()同步一下。(感觉还是很抽象,看了后面的实例一就明白了)
3、应用场景:mmap()的这种能力用于显示适配器一类的设备,屏幕帧的像素不再需要从一个用户空间到内核空间的复制过程。
二、应用程序相关函数
1、建立映射:

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

a) 参数含义:
addr:指定映射的起始地址, 通常设为NULL, 由系统指定。
length: 映射到内存的文件长度。
prot: 映射区的保护方式, 可以是:
PROT_EXEC: 映射区可被执行
PROT_READ: 映射区可被读取
PROT_WRITE: 映射区可被写入
PROT_NONE 映射区不可访问.

flags: 映射区的特性, 可以是:
MAP_SHARED:对此区域所做的修改内容奖写入文件内;允许其他映射该文件的进程共享,意思是:n个mmap.out程序在运行,这n个进程的“虚拟内存区域”的物理空间空间都相同。详看《虚拟内存共享原理图b》

虚拟内存共享原理图b

MAP_PRIVATE:对此区域所做的修改不会更改原来的文件内容,对映射区的写入操作会产生一个映射区的复制(copy-on-write);意思是:n个mmap.out程序在运行,但是虚拟内存区域的物理地址会被内核另外分配。详看《虚拟内存共享原理图c》

虚拟内存共享原理图c

fd: 由open返回的文件描述符, 代表要映射的文件。
offset: 以文件开始处的偏移量, 必须是分页大小的整数倍, 通常为0, 表示从文件头开始映射。

b)返回值:返回成功----函数的返回值为最后文件映射到进程空间的地址(参照文件内存映射原理图示 a),进程可直接操作起始地址为该值的有效地址。返回失败返回MAP_FAILED(-1),错误原因存于errno 中。

2、解除映射:

int munmap(void *addr, size_t length);

3、 同步回写函数:

int msync(const void *start, size_t length, int flags);

如果您希望立即将数据写入文件中,可使用msync。
a)参数

start为记忆体开始位置(mmap函数返回的值---地址),length为长度。
flags则有三个:
MS_ASYNC : 请Kernel快将资料写入,发出回写请求后立即返回
MS_SYNC : 在msync结束返回前,将资料写入。
MS_INVALIDATE使用回写的内容更新该文件的其它映射

实例一)mmap普通文件被映射到进程地址空间实例

mmapfile.c

#include
#include
#include
#include
#include
#include
#include
#include
void printfMapChar(char *nameChar, char *mapChar){//打印mapChar的内容
printf("%s = %s\n\n", nameChar,mapChar);
}
void printfMmapAddr(char *nameChar, char *mmapChar){//打印mmapChar的地址
printf("%saddress = %p\n",nameChar, mmapChar);
}
void printfDivLine(char *desc){
printf("********%s*******\n", desc);
}
int main(){
int fd;
char *mapChar;//mapchar存放虚拟内存地址
char *checkChar;//验证是否mapChar是映射地址
printf("mypid is %d\n",getpid());//输出本pid
/*获得映射区域地址,赋值mapChar*/
fd = open("/tmp/test.txt",O_RDWR);
mapChar = mmap(NULL,100,PROT_READ|PROT_WRITE,MAP_SHARED,fd,0);//获得映射区域地址MAP_SHARED更改mapchar后改变fd文件内容
/*****************/

Tip:此时mapchar就是虚拟内存区域的物理地址部分的首地址;也就是《文件内存映射原理图示 a》中的fd文件存储映射部分对应的的首地址,当进车访问mapchar这段地址范围时,实际上会转化为对文件fd的访问

/********打印映射区域内容;和mapChar*********/
printfDivLine("打印映射区域内容;和mapChar");
printfMapChar("mapChar", mapChar);
/**************/
/*******通过mapChar将数据写入映射区域*******/
strcpy(mapChar, "writeSrc,writeSrc,writeSrc,writeSrc,writeSrc,writeSrc,");//写入映射区域
printfDivLine("通过mapChar将数据写入映射区域");
printfMapChar("mapChar", mapChar);
/**********checkChar验证*********/
checkChar = mmap(NULL,100,PROT_READ|PROT_WRITE,MAP_SHARED,fd,0);//获得映射区域地址
close(fd);//不使用fd时就可以close
printfDivLine("checkChar验证");
printfMmapAddr("mapChar", mapChar);
printfMmapAddr("checkChar", checkChar);
printfMapChar("checkChar", checkChar);
munmap(mapChar, 100);//释放mapchar的映射,此时文件的映射在内存内然存在
munmap(checkChar, 100);
return 0;
}

Copyright © 2017-2020 微波EDA网 版权所有

网站地图

Top