linux mmap应用与驱动共享内存

news/发布时间2024/5/17 16:49:23

mmap简介

将用户空间的一段内存区域映射到内核空间,映射成功后,用户对这段内存区域的修改可以直接反映到内核空间,同样,内核空间对这段区域的修改也直接反映用户空间。

参考文章

轻松突破文件IO瓶颈:内存映射mmap技术
深入理解内存映射:加速文件访问的神奇原理

应用实例

应用与应用共享内存

应用与应用之间共享内存一般需要有一个中间文件充当媒介,因为我们先创建一个1K大小的testfile文件来充当媒介文件(也可以在代码中添加),此时以在终端中创建为例
dd if=/dev/zero of=a.txt bs=1024 count=1
切记不能使用touch创建,因为touch没有设置文件大小,mmap申请虚拟内存会报错

示例代码

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/mman.h>int main(int argc, char** argv) {int fd;char* addr;char str[100]="hello world hello world hello world hello world";if((fd = open("testfile", O_RDWR)) == -1){perror("open testfile failed");}addr = mmap(NULL,  100, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);if(addr == MAP_FAILED)fprintf(stderr, "mmap failed\n");memcpy(addr, str, strlen(str));printf("%s\n", addr);return 0;
}

运行测试

~/linux/test$ ./write_mmap
hello world hello world hello world hello world

成功访问到虚拟内存内的字符串内容,测试通过

应用与驱动共享内存

应用与驱动之间的共享内存会比较麻烦一点,代码是简化过后,不一定能跑通,大家可以参考一下

驱动部分

#include <linux/init.h>
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/delay.h>
#include <linux/ide.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/errno.h>
#include <linux/gpio.h>
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/of_gpio.h>
#include <linux/platform_device.h>
#include <linux/miscdevice.h>
#include <asm/mach/map.h>
#include <asm/uaccess.h>
#include <asm/io.h>
#include <linux/mm.h>
#include <linux/slab.h>
#include <linux/fs.h>char* mmap_buf = NULL;static ssize_t wyr_write(struct file *filp, const char __user *buf, size_t cnt, loff_t *offt){return 0;
}static int wyr_open(struct  inode *inode, struct file *filep){filep->private_data = &ledstr;mmap_buf = kmalloc(4096, GFP_KERNEL);//4096是页大小,一定要按页大小申请空间,不然程序有问题return 0;
}static ssize_t wyr_read(struct file *filep, char __user *buf, size_t cnt, loff_t *offt){int i;for(i=1; i<101;i++){printk("%d\t", *(mmap_buf+i-1));if(i%10 == 0) printk("\n");}return 0;
}static int wyr_close(struct inode *inode, struct file *filep){if(mmap_buf)    //如果mmap_buf不为NALL,表明曾经kmalloc申请过内存,这时才需要freekfree(mmap_buf);return 0;
}static int wyr_mmap(struct file* filep, struct vm_area_struct *vma){vma->vm_flags |= VM_IO;vma->vm_flags |= VM_DONTEXPAND | VM_DONTDUMP;vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);if(remap_pfn_range(vma, vma->vm_start, virt_to_phys(mmap_buf)>>PAGE_SHIFT, vma->vm_end - vma->vm_start, vma->vm_page_prot)){printk("mmap remp_pfn_range failed\n");return -1;}return 0;
}static struct file_operations led_fops={.owner = THIS_MODULE,.open = wyr_open,.write = wyr_write,.read=wyr_read,.release = wyr_close,.mmap = wyr_mmap,
};static struct miscdevice miscdev = {.minor = 144,.name = "wyr_led",.fops = &led_fops,
};static int __init led_init(void){return misc_register(&miscdev);
}static void __exit led_exit(void){misc_deregister(&miscdev);
}
module_init(led_init);
module_exit(led_exit);MODULE_LICENSE("GPL");
MODULE_AUTHOR("wyr");

注意kmalloc申请的大小一定要是页大小的倍数sysconf(_SC_PAGESIZE)可以获取到页大小

应用部分

#include "stdio.h"
#include "unistd.h"
#include "sys/types.h"
#include "sys/stat.h"
#include "fcntl.h"
#include "stdlib.h"
#include "string.h"
#include <sys/mman.h>int main(int argc, char * argv[]) {int fd, retval;char* buf;char* filename;int i;fd = open(argv[1], O_RDWR);if (fd < 0){printf("Error opening\r\n");return -1;}buf = mmap(NULL, 100, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);printf("⻚大小=%d\n", sysconf(_SC_PAGESIZE));sleep(2);for(i = 0; i <100; i++){*(buf+i) = i+1;}read(fd, NULL, 1);munmap(buf, 100);retval = close(fd);if (retval < 0)printf("Error closing\r\n");return 0;
}

程序的逻辑是应用向虚拟空间写入1~100,然后在驱动中访问虚拟内存并打印出虚拟内存的内容

运行测试

/lib/modules/4.1.15 # depmod
/lib/modules/4.1.15 # modprobe leddri_wyr.ko
/lib/modules/4.1.15 # ./ledGUI /dev/wyr_led
⻚大小=4096
1       2       3       4       5       6       7       8       9       10
11      12      13      14      15      16      17      18      19      20
21      22      23      24      25      26      27      28      29      30
31      32      33      34      35      36      37      38      39      40
41      42      43      44      45      46      47      48      49      50
51      52      53      54      55      56      57      58      59      60
61      62      63      64      65      66      67      68      69      70
71      72      73      74      75      76      77      78      79      80
81      82      83      84      85      86      87      88      89      90
91      92      93      94      95      96      97      98      99      100
/lib/modules/4.1.15 #

打印成功测试通过!!!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.ulsteruni.cn/article/45814811.html

如若内容造成侵权/违法违规/事实不符,请联系编程大学网进行投诉反馈email:xxxxxxxx@qq.com,一经查实,立即删除!

相关文章

认知提升的方法

认知提升的方法一、什么是认知 经验是对于过往经历的总结归纳,当把这种经验传授给别人时,这种经验对别人来说就是知识。所以,知识是人脑对客观事物的信息沉淀。 技能是人们通过练习而获得的动作方式和系统,例如操作技能中的PS技术、木工技术、电工技术、水工技术等,而能力…

将社会脆弱性纳入高分辨率全球洪水风险绘图

贡献 将高分辨率流洪水模型的年平均超标概率估计值与网格化人口和贫困数据相结合,创建了 90 米分辨率的全球洪水脆弱性调整风险指数(VARI Flood)。该指数提供了国家内部或国家之间相对风险的估计值,并通过识别以高密度和高社会脆弱性为特征的 "热点地区",改变了…

acwing351

https://www.acwing.com/activity/content/problem/content/9051/ NOIP2007提高组T4。本题是加强版。 题目描述 设 \(T=(V, E, W)\) 是一个无圈且连通的无向图(也称为无根树),每条边带有正整数的权,我们称 \(T\) 为树网(treenetwork),其中 \(V, E\) 分别表示结点与边的集…

Unity热更学习笔记--AB包的依赖 0.98

AB包的依赖 接上一小结。 在这里我们新建一个红色材质球,赋值给Cube预制体。此时不对材质球进行AB包分类,再次进行打包。运行脚本,发现红色cube成功的从AB包中加载出来。尽管我们没有将cube所依赖的材质球进行打包分类,但是打包时候unity会自动将包中的物体相关依赖打入包中…

Y2 知识和题单

Link。 0x01 进制 引入 计数原理,对于 \(N\) 进制,那么就是逢 \(N\) 进一。 计算机中常用二进制,对应电路中的通电(\(1\))断电(\(0\))。 人类从远古以来使用十进制。 常用的有二进制、三进制、八进制、十进制、十六进制等。 由于不同进制之间数值写法可能相同,在没有特…

Clock Switch,芯片时钟切换的毛刺是什么,如何消除

背景 芯片运行过程中需要时钟切换时,要考虑到是否会产生glitch,小小的glitch有可能导致电路运行的错误。所以时钟切换时需要特别的处理。 直接使用MUX进行时钟切换或者采用如下电路结构进行时钟切换:assign outclock = (clk1 & select) | (~select & clk0);或 assig…