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 ]
所谓映射是两个集合中的一种特殊的对应关系,通过这一关系把一个集合的内容投影到另一个集合中去。根据此定义可知存在这两个集合。
内存映射这个概念中,只设计一个集合内存,另一个集合呢?根据另一个集合的类型可以分为匿名映射(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 ]