首页 > 其他分享 >mmap与remap_pfn_range

mmap与remap_pfn_range

时间:2024-04-06 22:46:12浏览次数:26  
标签:remap 映射 mmap vm range 内存 demo include

参考资料: https://www.cnblogs.com/pengdonglin137/p/8149859.html https://blog.csdn.net/HuangChen666/article/details/133633120  

remap_pfn_range :

remap_pfn_range 是 Linux 内核中的一个函数,用于将物理页面框号(PFN)映射到用户空间的虚拟地址范围中。PFN 是物理页面在内存中的索引,而不是直接的物理地址。这个函数在内核中的 mm/memory.c 文件中定义。
int remap_pfn_range(struct vm_area_struct *vma, unsigned long virt_addr, unsigned long pfn, unsigned long size, pgprot_t prot);

// 参数和返回值说明
vma: 虚拟内存区域结构体指针,描述了要进行映射的虚拟内存区域。
virt_addr: 用户空间中要映射的虚拟地址的起始地址。
pfn: 物理页面框号的起始地址,即要映射的物理页面在内存中的索引。
size: 要映射的内存区域大小。
prot: 要应用于映射区域的页面保护标志,通常使用 vm_page_prot 定义。
映射成功返回0,失败返回错误码
 

mmap:

mmap() 是一个 Unix 和类 Unix 操作系统中的系统调用,用于在进程的地址空间中创建一个新的内存映射区域。它允许进程将文件或设备映射到其地址空间中,从而可以通过内存访问来读取和写入文件,或者与设备进行通信:
void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset);

// 参数和返回值说明
addr:欲映射的内存起始地址,通常设置为 NULL,表示由系统选择合适的地址。
length:映射区域的长度,以字节为单位。
prot:映射区域的保护方式,可以是 PROT_READ、PROT_WRITE、PROT_EXEC 和 PROT_NONE 的组合。
flags:控制映射区域的属性,可以是 MAP_SHARED、MAP_PRIVATE、MAP_ANONYMOUS 和其他标志的组合。
fd:要映射的文件描述符,如果不是映射文件,可以设置为 -1,对应的flags要带MAP_ANONYMOUS。
offset:要映射的文件的偏移量,通常设置为 0。
成功时,返回映射区域的起始地址。
失败时,返回 MAP_FAILED,并设置 errno 表示错误原因。
当flags设置为MAP_ANONYMOUS时,这个标志告诉操作系统不关联任何文件,而是直接映射到系统内核管理的一块内存区域,也成为匿名内存区域,适合的使用场景:

1、共享内存:多个进程可以通过映射同一个匿名内存区域来实现进程间通信,从而共享数据。

2、动态内存分配:malloc() 和 free() 等内存管理函数可能会使用匿名内存区域来分配和释放内存。

3、临时缓冲区:某些临时数据或缓冲区可以放置在匿名内存区域中,从而避免了频繁的文件 I/O 操作。

  mmap驱动和应用测试程序举例 mmap_demo.c
#include <linux/init.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/uaccess.h>
#include <linux/slab.h>

#define DEVICE_NAME "mmap_demo"
#define BUF_SIZE 4096

MODULE_LICENSE("GPL");

static int major;
static char *buffer;

static int mmap_demo_open(struct inode *inode, struct file *file) {
    return 0;
}

static int mmap_demo_release(struct inode *inode, struct file *file) {
    return 0;
}

static int mmap_demo_mmap(struct file *file, struct vm_area_struct *vma) {
    unsigned long size = vma->vm_end - vma->vm_start;

    // 检查请求的内存大小是否合法
    if (size > BUF_SIZE)
        return -EINVAL;

    // 将设备内存映射到用户空间    
    if (remap_pfn_range(vma, vma->vm_start, virt_to_phys(buffer) >> PAGE_SHIFT + vm->vm_pgoff, size, vma->vm_page_prot) < 0)
        return -EAGAIN;

    return 0;
}

static struct file_operations mmap_demo_fops = {
    .open = mmap_demo_open,
    .release = mmap_demo_release,
    .mmap = mmap_demo_mmap,
};

static int __init mmap_demo_init(void) {
    major = register_chrdev(0, DEVICE_NAME, &mmap_demo_fops);
    if (major < 0) {
        printk(KERN_ALERT "Failed to register a major number\n");
        return major;
    }

    buffer = kmalloc(BUF_SIZE, GFP_KERNEL);
    if (!buffer) {
        unregister_chrdev(major, DEVICE_NAME);
        printk(KERN_ALERT "Failed to allocate memory for the device\n");
        return -ENOMEM;
    }

    printk(KERN_INFO "mmap_demo module loaded\n");
    return 0;
}

static void __exit mmap_demo_exit(void) {
    kfree(buffer);
    unregister_chrdev(major, DEVICE_NAME);
    printk(KERN_INFO "mmap_demo module unloaded\n");
}

module_init(mmap_demo_init);
module_exit(mmap_demo_exit);
PAGE_SHIFT可以理解为一个页面的大小,在linux中一般为4K,也就是1 << 12。vma->vm_start表示用户空间要映射的虚拟地址的起始地址,virt_to_phys(buffer) >> PAGE_SHIFT + vm->vm_pgoff表示页帧号   应用层测试程序:
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <unistd.h>
#include <string.h>

#define DEVICE_FILE "/dev/mmap_demo"
#define BUF_SIZE 4096

int main() {
    int fd;
    char *mapped_mem;

    // 打开设备文件
    fd = open(DEVICE_FILE, O_RDWR);
    if (fd == -1) {
        perror("open");
        exit(EXIT_FAILURE);
    }

    // 将设备内存映射到用户空间
    mapped_mem = mmap(NULL, BUF_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
    if (mapped_mem == MAP_FAILED) {
        perror("mmap");
        exit(EXIT_FAILURE);
    }

    // 写入数据到设备内存
    const char *data = "Hello, mmap from user space!";
    strncpy(mapped_mem, data, strlen(data));

    // 从设备内存读取数据
    printf("Data from device memory: %s\n", mapped_mem);

    // 解除内存映射
    if (munmap(mapped_mem, BUF_SIZE) == -1) {
        perror("munmap");
    }

    // 关闭设备文件
    if (close(fd) == -1) {
        perror("close");
        exit(EXIT_FAILURE);
    }

    return 0;
}

 

 

 

 

   

标签:remap,映射,mmap,vm,range,内存,demo,include
From: https://www.cnblogs.com/lethe1203/p/18118114

相关文章

  • 【CANN训练营笔记】OrangePI AIPro 体验手写体识别模型训练与推理
    CANN简介当我们谈到香橙派AIPro的时候,总会把她和昇腾生态关联起来,因为在昇腾芯片的加持下,这款开发板有着出色的算力,被众多开发者追捧。而谈到昇腾芯片,我们不得不提上层的AI异构计算架构CANN。异构计算架构CANN(ComputeArchitectureforNeuralNetworks)是华为针对AI场......
  • RangeDet
    PDF:RangeDet:InDefenseofRangeViewforLiDAR-based3DObjectDetectionCODE:https://github.com/TuSimple/RangeDet一、大体内容RangeDet是一个Anchor-free的单阶段3D目标检测网络,其输入数据不是Voxel和Point,而是RangeImage。这三种数据区别如下图所示。作者对比......
  • MIT 6.S081入门lab10 mmap
    MIT6.S081入门lab10mmap一、参考资料阅读与总结1.JournalingtheLinuxext2fsFilesystem文件系统可靠性:磁盘崩溃前数据的稳定性;故障模式的可预测性;操作的原子性-论文核心:将日志事务系统加入Linux的文件系统中;事务系统的要求:元数据的更新;事务系统的顺序性;数据块写入磁......
  • 论文阅读RangeDet: In Defense of Range View for LiDAR-based 3D Object Detection
    文章目录RangeDet:InDefenseofRangeViewforLiDAR-based3DObjectDetection问题笛卡尔坐标结构图Meta-KernelConvolutionRangeDet:InDefenseofRangeViewforLiDAR-based3DObjectDetection论文:https://arxiv.org/pdf/2103.10039.pdf代码:https://......
  • 题解:AT_arc175_b [ARC175B] Parenthesis Arrangemen
    前言警示后人:字符串最大长度为\(65535\),会\(RE\)!!!\(10^7\)会爆栈!!!题意给出一个括号序列\(s\),有两种操作方式,交换两个字符需要花费\(A\),直接修改一个字符需要花费\(B\),求使这个序列合法需要的最小花费。分析我们可以先将\(s\)中能匹配的括号序列消除掉(即括号匹配......
  • java.sql.BatchUpdateException: Date truncation: Out of range value for column xx
    报错:java.sql.BatchUpdateException:Datetruncation:Outofrangevalueforcolumnxxxxx原因:xxx列ddl中为stock_num(12,2)数据库值为0.06需要更新为:0.06-0.21就会出现该错误参考:https://www.jb51.net/article/158166.htmhttps://blog.csdn.net/stone_tomca......
  • 题解:CF1623B Game on Ranges
    题意理解(建议先自己把原题描述看一遍再来看我的理解)有一个集合,这个集合的元素是区间,一开始集合里只有一个元素就是\([1,n]\)的区间,对这个集合我们可以选择其中的一个元素(区间),然后在区间内选一个数d,以\([l,d-1]\)和\([d+1,r]\)这两个区间替换掉我们选择的这个区间(\(l\)和......
  • AtCoder Regular Contest 173 E Rearrange and Adjacent XOR
    洛谷传送门AtCoder传送门不妨考虑最后的结果可以成为哪些\(a_i\)的组合。为了方便分析,我们令\(a_i=2^{i-1}\)。进行一次操作后,所有\(\text{popcount}(a_i)\)都为偶数。所以一个\(x\in[0,2^n-1]\)能被生成出来的必要条件是\(\text{popcount}(x)\)为偶数。然......
  • Python的range语句
    语法1:range(num)如range(5)得到的数据是:[0,1,2,3,4]语法2:range(num1,num2)获得从num1开始,到num2结束的数字序列(部包含num2本身)如range(5,10)得到[5,6,7,8,9]语法3:range(num1,num2,step)获得一个从num1开始,到num2结束的数字序列(不含num2本身)数字之间的步长为step如range(5,10,2)得[5,7......
  • 用索引"copyofRange(int[] arr, int from,int to)"复制数组中的数,形成新数组的方法
    publicclasstest2{publicstaticvoidmain(String[]args){//定义原数组int[]arr={1,2,3,4,5,6,7,8,9};//引用copyofRange方法复制元素到新数组中int[]newcopy=copyofRange(arr,3,7);//输出新数组for(inti=......