Linux驱动----设备内存映射

1.什么是内存映射呢?如何理解?
所谓映射是两个集合中的一种特殊的对应关系,通过这一关系把一个集合的内容投影到另一个集合中去。根据此定义可知存在这两个集合。
内存映射这个概念中,只设计一个集合内存,另一个集合呢?根据另一个集合的类型可以分为匿名映射(anonymous)和文件映射(file_backed). 在Linux系统中, 文件有可分为普通文件和设备文件等。
普通文件的内存映射系统已经提供了通用实现, 而设备千差万别,根据设备的作用可实现此操作,设备存在内存空间,我们可以把其空间映射到用户空间去,用户可以访问。 为了理解此概念,我们提供了下面一个实例(该测试用例,只提供一个框架)。

2.上面只是探讨了两个集合,但这两个集合又是如何投影呢?
由于我们把文件映射到内存集合中,所以访问(读写)映射内存相当与读写文件。
具体投影过程由内核提供, 当我们提供映射要求时(即调用mmap函数), 内核分配一定映射大小虚拟内存,并关联到文件对象。
当我们读写虚拟内存时,由于可能没有为其分配物理内存,就发生了确页中断,然后分配物理内存。
最后读取文件内容放并放到这块分配物理内存中,这样就实现基于文件的内存映射。

3.对于物理内存与虚拟内存,这里做简单描述。
物理内存:
在Linux系统中,通过struct page结构描述内存页, 整个物理内存页通过数组来组织。
虚拟内存:
在Linux系统中,通过struct vm_area_struct结构描述内存区域, 整个用户空间的虚拟内存通过二查树和链表来组织。
页表:
两者关系,通过页表来关联, 当用户访问内存时, 实际访问虚拟内存,查找页表可以找到对应的物理内存,如果不存在发生确页中断,从整个物理内存中,分配一页。


4.设备内存映射实例
.内核版本:
# uname -r
2.6.32-71.el6
/
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/cdev.h>
#include <linux/mm.h>
#include <linux/miscdevice.h>
#define MISC_MINOR 222
struct page * fault_page = NULL;
static int misc_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
{
    char *virtual;

    fault_page = alloc_page(GFP_KERNEL);
    if(fault_page == NULL){
        return  -ENOMEM;
    }

    virtual = page_address(fault_page);
    sprintf(virtual, "hello misc_fault");

    get_page(fault_page);
    vmf->page = fault_page;
    printk("misc_fault:%d\n", page_count(fault_page));
    return 0;
}

/* virtual memory area operation */
static struct vm_operations_struct misc_vm_ops = {
    .fault = misc_fault,
};

static int misc_mmap(struct file *file, struct vm_area_struct *vma)
{
    vma->vm_ops = &misc_vm_ops;
    printk("misc_mmap\n");
    return 0;
}

/* device file operation */
static struct file_operations misc_fops = {
    .mmap       =  misc_mmap,
};

/* misc device */
static struct miscdevice misc_dev = {
    MISC_MINOR,
    "mmap",
    &misc_fops,
};

static int __init  misc_init(void)
{
        int r;
        r = misc_register(&misc_dev);
        return r;
}

static void __exit misc_exit(void)
{

    if(fault_page){
        printk("misc_exit:%d\n", page_count(fault_page));
        __free_page(fault_page);
    }
    misc_deregister(&misc_dev);
}

module_init(misc_init);
module_exit(misc_exit);
MODULE_LICENSE("GPL");

5.用户空间测试:
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

#define MMAP_SIZE 8096
int main()
{
        int fd = open("/dev/mmap", O_RDWR);
        if(fd < 0){
            perror("open");
            return -1;
        }
       char *addr = mmap(NULL, MMAP_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd,0);
       printf("%s\n", addr);
       addr[0]='h';
       addr[4096]='e';
       getchar();
       munmap(addr, MMAP_SIZE);
       close(fd);
       getchar();
}
编译
#gcc test.c
执行
#./a.out
查询
#ps aux | grep a.out
# pmap  3224
3224:   ./a.out
0000000000400000      4K r-x--  /root/mmap_driver/test/a.out
0000000000600000      4K rw---  /root/mmap_driver/test/a.out
00007f4e5d41e000   1572K r-x--  /lib64/libc-2.12.so
00007f4e5d5a7000   2048K -----  /lib64/libc-2.12.so
00007f4e5d7a7000     16K r----  /lib64/libc-2.12.so
00007f4e5d7ab000      4K rw---  /lib64/libc-2.12.so
00007f4e5d7ac000     20K rw---    [ anon ]
00007f4e5d7b1000    128K r-x--  /lib64/ld-2.12.so
00007f4e5d9b5000     12K rw---    [ anon ]
00007f4e5d9cb000      8K rw---    [ anon ]

00007f4e5d9cd000      8K rw-s-  /dev/mmap


00007f4e5d9cf000      4K rw---    [ anon ]
00007f4e5d9d0000      4K r----  /lib64/ld-2.12.so
00007f4e5d9d1000      4K rw---  /lib64/ld-2.12.so
00007f4e5d9d2000      4K rw---    [ anon ]
00007fff70d95000     84K rw---    [ stack ]
00007fff70dff000      4K r-x--    [ anon ]
ffffffffff600000      4K r-x--    [ anon ]
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值