mmap底层驱动实现(remap_pfn_range函数)
mmap底层驱动实现
myfb.c(申请了128K空间)
#include <linux/init.h>
#include <linux/tty.h>
#include <linux/device.h>
#include <linux/export.h>
#include <linux/types.h>
#include <linux/module.h>
#include <linux/export.h>
#include <linux/mm_types.h>
#include <linux/mm.h>
#include <linux/slab.h>#define BUFF_SIZE (32 * 4 * 1024)static char *buff;
static int major;
static struct class * myfb_class;static int myfb_mmap (struct file *fp, struct vm_area_struct *vm)
{int res;//表示该vma在虚拟地址空间中的偏移地址,单位是页(4K)//unsigned long offset = vm->vm_pgoff << PAGE_SHIFT; //计算被映射的物理内存的物理页帧号(物理地址+偏移),以页为单位, virt_to_phys将虚拟地址转成物理地址//vm->pgoff表示的是用户空间映射时在VMA中的偏移(即mmap最后一个参数,单位是字节,但vm->pgoff自动转成页单位)unsigned long pfn_start = (virt_to_phys(buff) >> PAGE_SHIFT); res = remap_pfn_range(vm, vm->vm_start, pfn_start + vm->vm_pgoff, //在物理页帧号上加上偏移vm->vm_end - vm->vm_start, vm->vm_page_prot);if(res){printk("remap_pfn_range failed\n");return -1;}printk("[kernel] pfn_start = 0x%lx, vm->vm_pgoff = 0x%lx, \\n[kernel] vm->vm_start = 0x%lx, vm->vm_end = 0x%lx, vir_ker_start = 0x%lx\n", \pfn_start, vm->vm_pgoff, vm->vm_start, vm->vm_end, (unsigned long)buff);return 0;
}static struct file_operations myfb_fops = {.owner = THIS_MODULE,.mmap = myfb_mmap,
};static int myfb_init(void)
{buff = kzalloc(BUFF_SIZE, GFP_KERNEL);if (!buff){printk("kzalloc failed!\n");return -ENOMEM;}printk("kzalloc success!\n");major = register_chrdev(0, "myfb", &myfb_fops);myfb_class = class_create(THIS_MODULE, "myfb_class");device_create(myfb_class, NULL, MKDEV(major, 0), NULL, "myfb");return 0;
}static void myfb_exit(void)
{device_destroy(myfb_class, MKDEV(major, 0));class_destroy(myfb_class);unregister_chrdev(major, "myfb");kfree(buff);
}module_init(myfb_init);
module_exit(myfb_exit);
MODULE_LICENSE("GPL");
mmap_read.c
#include <stdio.h>
#include <sys/mman.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <signal.h>
#include <unistd.h>#define PAGE_SIZE (4*1024)
#define BUFF_SIZE (1 * PAGE_SIZE)
#define OFFSET (2 * PAGE_SIZE)char *p;
int fd;void ctrlc(int signum)
{munmap(p, BUFF_SIZE);close(fd);
}int main(void)
{signal(SIGINT, ctrlc);fd = open("/dev/myfb", O_RDWR);p = (char *)mmap(NULL, BUFF_SIZE, PROT_READ | PROT_WRITE , MAP_SHARED, fd, OFFSET);if(p){printf("mmap addr = 0x%x\n", p);printf("data = %s\n", p);}else{printf("mmap failed\n");}while(1){sleep(1);}return 0;
}
mmap_write.c
#include <stdio.h>
#include <sys/mman.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <signal.h>
#include <unistd.h>#define PAGE_SIZE (4*1024)
#define BUFF_SIZE (1 * PAGE_SIZE)
#define OFFSET (0 * PAGE_SIZE)char *p;
int fd;void ctrlc(int signum)
{munmap(p, BUFF_SIZE);close(fd);
}int main(void)
{signal(SIGINT, ctrlc);fd = open("/dev/myfb", O_RDWR);p = (char *)mmap(NULL, BUFF_SIZE, PROT_READ | PROT_WRITE , MAP_SHARED, fd, OFFSET);if(p){printf("mmap addr = 0x%x\n", p);memcpy(p, "hello world", 20);}else{printf("mmap failed\n");}while(1){sleep(1);}return 0;
}
Makefile
KERNEL_DIR = /home/me/Kernel_Uboot/linux-imx-rel_imx_4.1.15_2.1.0_ga_alientekall:make -C $(KERNEL_DIR) M=`pwd` modules$(CROSS_COMPILE)gcc mmap_read.c -o mmap_read$(CROSS_COMPILE)gcc mmap_write.c -o mmap_writeclean:make -C $(KERNEL_DIR) M=`pwd` modules cleanobj-m += myfb.o
当读和写的进程内存映射地址的偏移都为0时,读进程能把写进程写入的数据读出

当写进程内存映射地址偏移为0,读进程内存映射地址**偏移为2(单位页)**时,读进程读出数据为空

PS:注意到读写进程的pfn_start相同,这个值是映射的物理内存地址,vm->vm_pgoff 是偏移(单位页,一页=4K(4096))
但是两个进程映射的虚拟地址结果不一定相同,虚拟地址是进程自己独有的,这点很容易理解。
1. 查看虚拟内存分布
查看读写进程的pid

写进程的虚拟内存分布

读进程的虚拟内存分布

1.1 分析虚拟内存映射部分
以读进程为例,/dev/myfb所在行即是内存映射的部分
76ffa000: vm->vm_start 的值
76ffb000: vm->vm_end 的值
rw-s: 表示的是 vm->vm_flags,"rw"表示可读可写,"s"表示 share共享,"p"表示 private 私有
00000000: 表示偏移量,即 vm->vm_pgoff(单位页,此处的偏移量单位是字节,需要做一下换算)
00:06 : 表示主次设备号
2564: 表示 inode 值
/dev/myfb: 表示设备节点名
1.2 关于偏移量
将读进程中mmap函数最后一个参数改为2*4096(2页)后,进程的虚拟内存映射部分的地址分布如下。
可以看到偏移量为 00002000,即 2*4096字节 = 2页 = 8K
偏移量指的是mmap最后一个参数、同样也是vm->vm_pgoff(单位页),指的是映射时在文件的物理内存上的偏移,只映射了文件的部分内容,单位是页4K

2. remap_pfn_range函数
2.1 remap_pfn_range函数原型
/*** remap_pfn_range - remap kernel memory to userspace* @vma: user vma to map to* @addr: target user address to start at* @pfn: physical address of kernel memory* @size: size of map area* @prot: page protection flags for this mapping** Note: this is only safe if the mm semaphore is held when called.*/
int remap_pfn_range(struct vm_area_struct *vma, unsigned long addr,unsigned long pfn, unsigned long size, pgprot_t prot)
| 参数 | 含义 |
|---|---|
| vm | 虚拟内存区域描述符,用于表示映射的虚拟内存区域 |
| addr | 映射的虚拟内存区域的首地址 |
| pfn | 物理页帧号 |
| size | 映射区域的大小 |
| prot | 物理页面的操作属性,例如读/写/执行权限 |
2.2 remap_pfn_range函数使用
这里主要搞懂 myfb.c 驱动代码中的 remap_pfn_range 中的如下代码
unsigned long pfn_start = (virt_to_phys(buff) >> PAGE_SHIFT); res = remap_pfn_range(vm, vm->vm_start, pfn_start + vm->vm_pgoff, //在物理页帧号上加上偏移vm->vm_end - vm->vm_start, vm->vm_page_prot);
- vm: 调用mmap时内核自动生成的VMA(虚拟内存描述符)
- vm->vm_start: 该VMA的起始地址
- vm->_end: 该VMA的结束地址
- virt_to_phys: 将虚拟地址转成物理地址
- PAGE_SHIFT: 宏,值为12,1<<PAGE_SHIFT表示4096,即4K,一页的大小
- vm->vm_pgoff: 指的是映射时在文件的物理内存上的偏移,只映射了文件的部分内容,单位是页(4K)
- vm->vm_page_prot: 该虚拟内存的访问权限,由mmap的参数决定,例如可读可写,共享等
相关文章:
mmap底层驱动实现(remap_pfn_range函数)
mmap底层驱动实现 myfb.c(申请了128K空间) #include <linux/init.h> #include <linux/tty.h> #include <linux/device.h> #include <linux/export.h> #include <linux/types.h> #include <linux/module.h> #inclu…...
品牌如何查窜货
当渠道中的产品出现不按规定区域销售时,这种行为就叫做窜货,窜货不仅会扰乱渠道的健康发展,损害经销商的利益,同时会滋生低价、假货的发生,有效的管控窜货,需要品牌先将窜货链店铺找出来,才能进…...
Java基于SpringBoot的车辆充电桩
博主介绍:✌程序员徐师兄、7年大厂程序员经历。全网粉丝30W,Csdn博客专家、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ 文章目录 1、效果演示效果图 技术栈2、 前言介绍(完整源码请私聊)3、主要技术3.4.1…...
【ARM】(1)架构简介
前言 ARM既可以认为是一个公司的名字,也可以认为是对一类微处理器的通称,还可以认为是一种技术的名字。 ARM公司是专门从事基于RISC技术芯片设计开发的公司,作为知识产权(IP)供应商,本身不直接从事芯片生产…...
企业完善质量、环境、健康安全三体系认证的作用及其意义!
一、ISO三体系标准作用 ISO9001:质量管理体系,专门针对企业的质量管理,投标首选,很多大客户要求企业必备这项。 ISO14001:环境管理体系,针对企业的生产环境,排污,节能环保…...
<HarmonyOS第一课>运行Hello World——闯关习题及答案
判断题 1.DevEco Studio是开发HarmonyOS应用的一站式集成开发环境。( 对 ) 2.main_pages.json存放页面page路径配置信息。( 对 ) 单选题 1.在stage模型中,下列配置文件属于AppScope文件夹的是?ÿ…...
NLP 02 RNN
一、RNN RNN(Recurrent Neural Network),中文称作循环神经网络它一般以序列数据为输入通过网络内部的结构设计有效捕捉序列之间的关系特征,一般也是以序列形式进行输出。 传统神经网络(包括CNN),输入和输出都是互相独立的。但有些任务,后续的输出和之前…...
@PostConstruct注解
PostConstruct注解 PostConstruct注解是javax.annotation包下的一个注解,用于标记一个方法,在构造函数执行之后,依赖注入(如Autowired,意味着在方法内部可以安全地使用依赖注入的成员变量,而不会出现空指针异常&#…...
拓世AI|中秋节营销攻略,创意文案和海报一键生成
秋风意境多诗情,中秋月圆思最浓。又是一年中秋节,作为中国传统的重要节日之一,中秋节的意义早已不再仅仅是一家团圆的节日,更是一场商业盛宴。品牌方们纷纷加入其中,希望能够借助这一节日为自己的产品赢得更多的关注和…...
基于知识蒸馏的两阶段去雨去雪去雾模型学习记录(三)之知识测试阶段与评估模块
去雨去雾去雪算法分为两个阶段,分别是知识收集阶段与知识测试阶段,前面我们已经学习了知识收集阶段,了解到知识阶段的特征迁移模块(CKT)与软损失(SCRLoss),那么在知识收集阶段的主要重点便是HCRLoss(硬损失…...
代码随想录二刷day46
提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 前言一、力扣139. 单词拆分二、力扣动态规划:关于多重背包,你该了解这些! 前言 提示:以下是本篇文章正文内容&#x…...
计算机竞赛 行人重识别(person reid) - 机器视觉 深度学习 opencv python
文章目录 0 前言1 技术背景2 技术介绍3 重识别技术实现3.1 数据集3.2 Person REID3.2.1 算法原理3.2.2 算法流程图 4 实现效果5 部分代码6 最后 0 前言 🔥 优质竞赛项目系列,今天要分享的是 🚩 深度学习行人重识别(person reid)系统 该项目…...
在线图片转BASE64、在线BASE64转图片
图片转BASE64、BASE64转图片...
什么是RPA?一文了解RPA发展与进程!
RPA(Robotic Process Automation,机器人流程自动化)是一种通过软件机器人模拟人类在计算机上执行重复性任务的技术。RPA的核心理念是将规则、过程和数据“机器人化”,从而实现对业务流程的自动化。RPA技术可以显著提高企业的工作效…...
【云备份项目】【Linux】:环境搭建(g++、json库、bundle库、httplib库)
文章目录 1. g 升级到 7.3 版本2. 安装 jsoncpp 库3. 下载 bundle 数据压缩库4. 下载 httplib 库从 Win 传输文件到 Linux解压缩 1. g 升级到 7.3 版本 🔗链接跳转 2. 安装 jsoncpp 库 🔗链接跳转 3. 下载 bundle 数据压缩库 安装 git 工具 sudo yum…...
工信部教考中心:什么是《研发效能(DevOps)工程师》认证,拿到证书之后有什么作用!(下篇)丨IDCF
拿到证书有什么用? 提高职业竞争力:通过学习认证培训课程可以提升专业技能,了解项目或产品研发全生命周期的核心原则,掌握端到端的研发效能提升方法与实践,包括组织与协作、产品设计与运营、开发与交付、测试与安全、…...
Linux进程相关管理(ps、top、kill)
目录 一、概念 二、查看进程 1、ps命令查看进程 1)ps显示某个时间点的程序运行情况 2)查看指定的进程信息 2、top命令查看进程 1)信息统计区: 2)进程信息区 3)交互式命令 三、信号控制进程 四、…...
微服务技术栈-Ribbon负载均衡和Nacos注册中心
文章目录 前言一、Ribbon负载均衡1.LoadBalancerInterceptor(负载均衡拦截器)2.负载均衡策略IRule 二、Nacos注册中心1.Nacos简介2.搭建Nacos注册中心3.服务分级存储模型4.环境隔离5.Nacos与Eureka的区别 总结 前言 在上面那个文章中介绍了微服务架构的…...
知识图谱和大语言模型的共存之道
源自:开放知识图谱 “人工智能技术与咨询” 发布 导 读 01 知识图谱和大语言模型的历史 图1 图2 图3 图4 图5 02 知识图谱和大语言模型作为知识库的优缺点 图6 图7 表1 表2 图8 图9 03 知识图谱和大语言模型双知识平台融合 图10 图11 04 总结与展望 声明:公众号转…...
enum, sizeof, typedef
枚举类型enum enum 是 C 语言中的一种自定义类型enum 值是可以根据需要自定义的整型值第一个定义的 enum 值默认为 0默认情况下的 enum 值在前一个定义值得基础上加 1enum 类型的变量只能取定义时得离散值 void code() {enum Color{GREEN, // 0RED 2, // 2BLUE, …...
linux之kylin系统nginx的安装
一、nginx的作用 1.可做高性能的web服务器 直接处理静态资源(HTML/CSS/图片等),响应速度远超传统服务器类似apache支持高并发连接 2.反向代理服务器 隐藏后端服务器IP地址,提高安全性 3.负载均衡服务器 支持多种策略分发流量…...
阿里云ACP云计算备考笔记 (5)——弹性伸缩
目录 第一章 概述 第二章 弹性伸缩简介 1、弹性伸缩 2、垂直伸缩 3、优势 4、应用场景 ① 无规律的业务量波动 ② 有规律的业务量波动 ③ 无明显业务量波动 ④ 混合型业务 ⑤ 消息通知 ⑥ 生命周期挂钩 ⑦ 自定义方式 ⑧ 滚的升级 5、使用限制 第三章 主要定义 …...
聊聊 Pulsar:Producer 源码解析
一、前言 Apache Pulsar 是一个企业级的开源分布式消息传递平台,以其高性能、可扩展性和存储计算分离架构在消息队列和流处理领域独树一帜。在 Pulsar 的核心架构中,Producer(生产者) 是连接客户端应用与消息队列的第一步。生产者…...
CentOS下的分布式内存计算Spark环境部署
一、Spark 核心架构与应用场景 1.1 分布式计算引擎的核心优势 Spark 是基于内存的分布式计算框架,相比 MapReduce 具有以下核心优势: 内存计算:数据可常驻内存,迭代计算性能提升 10-100 倍(文档段落:3-79…...
汇编常见指令
汇编常见指令 一、数据传送指令 指令功能示例说明MOV数据传送MOV EAX, 10将立即数 10 送入 EAXMOV [EBX], EAX将 EAX 值存入 EBX 指向的内存LEA加载有效地址LEA EAX, [EBX4]将 EBX4 的地址存入 EAX(不访问内存)XCHG交换数据XCHG EAX, EBX交换 EAX 和 EB…...
DeepSeek 技术赋能无人农场协同作业:用 AI 重构农田管理 “神经网”
目录 一、引言二、DeepSeek 技术大揭秘2.1 核心架构解析2.2 关键技术剖析 三、智能农业无人农场协同作业现状3.1 发展现状概述3.2 协同作业模式介绍 四、DeepSeek 的 “农场奇妙游”4.1 数据处理与分析4.2 作物生长监测与预测4.3 病虫害防治4.4 农机协同作业调度 五、实际案例大…...
初学 pytest 记录
安装 pip install pytest用例可以是函数也可以是类中的方法 def test_func():print()class TestAdd: # def __init__(self): 在 pytest 中不可以使用__init__方法 # self.cc 12345 pytest.mark.api def test_str(self):res add(1, 2)assert res 12def test_int(self):r…...
短视频矩阵系统文案创作功能开发实践,定制化开发
在短视频行业迅猛发展的当下,企业和个人创作者为了扩大影响力、提升传播效果,纷纷采用短视频矩阵运营策略,同时管理多个平台、多个账号的内容发布。然而,频繁的文案创作需求让运营者疲于应对,如何高效产出高质量文案成…...
JavaScript基础-API 和 Web API
在学习JavaScript的过程中,理解API(应用程序接口)和Web API的概念及其应用是非常重要的。这些工具极大地扩展了JavaScript的功能,使得开发者能够创建出功能丰富、交互性强的Web应用程序。本文将深入探讨JavaScript中的API与Web AP…...
C++课设:简易日历程序(支持传统节假日 + 二十四节气 + 个人纪念日管理)
名人说:路漫漫其修远兮,吾将上下而求索。—— 屈原《离骚》 创作者:Code_流苏(CSDN)(一个喜欢古诗词和编程的Coder😊) 专栏介绍:《编程项目实战》 目录 一、为什么要开发一个日历程序?1. 深入理解时间算法2. 练习面向对象设计3. 学习数据结构应用二、核心算法深度解析…...
