您的位置:首页 > 其它

通过mmap将连续物理地址映射到用户空间

2013-12-13 20:40 429 查看
        由于MMU对用户空间的内存采用页式管理,用户空间的内存都是虚拟的,只有当真正写入物理内存时,系统才会判断是否为该虚拟内存分配物理内存,如果未分配就会触发缺页中断,然后分配一整页的内存给应用程序。所以用户空间的内存表面上连续,但是实际的物理内存不一定连续。

 

        由于种种原因,我们有时候会需要用户空间的虚拟内存在物理上面也连续。按照MMU的管理方式,虚拟内存最多只能有一页——4096字节在物理上面也是连续的。而这是远远不能满足我们的需求的。

 

        多方查阅资料,发现采用mmap可以达到这个目的。mmap是由内核实现,应用程序通过接口调用而产生一块内核和应用程序都能访问的内存,主要用于显卡驱动。下面介绍一个简单的例子,用于通过mmap为应用程序分配较大的连续物理内存。

 

 kernel部分:主要是创建一个字符设备,配置其mmap函数,分配连续内存。

#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/types.h>
#include <linux/errno.h>
#include <linux/fcntl.h>
#include <linux/vmalloc.h>
#include <asm/uaccess.h>
#include <asm/io.h>
#include <asm/page.h>
#include <linux/mm.h>
#include <linux/platform_device.h>
#include <linux/device.h>
#include <linux/moduleparam.h>
#include <linux/cdev.h>
#include <linux/slab.h>

#define MMAPIOMEM_DEV_NAME "mmapiomem"
#define MMAPIOMEM_DEV_MAJOR 280
#define MMAP_BUF_SIZE 0x500

char *mmap_buf_ptr;

int mmapiomem_open(struct inode *inode,struct file *filp)
{
return 0;
}

int mmapiomem_release(struct inode *inode,struct file *filp)
{
return 0;
}

int mmapiomem_mmap(struct file *filp,struct vm_area_struct *vma)
{

int result;

vma->vm_flags|=VM_RESERVED|VM_SHARED;

vma->vm_flags|=VM_IO;

result=remap_pfn_range(vma,
vma->vm_start,
((unsigned int)mmap_buf_ptr)>>PAGE_SHIFT,
PAGE_SIZE *4,
vma->vm_page_prot);

if(result){
return -EAGAIN;
}

return 0;
}

struct file_operations mmapiomem_fops={
.owner=THIS_MODULE,
.open=mmapiomem_open,
.release=mmapiomem_release,
.mmap=mmapiomem_mmap,
};

struct cdev *mmap_cdev;
struct class *mmap_class;

int mmapiomem_init(void)
{
int result;
int devno = MKDEV(MMAPIOMEM_DEV_MAJOR,0);
mmap_buf_ptr = (char *)__get_free_pages(GFP_KERNEL,2);//alloc 4pages
printk("%s,the mmap_buf_ptr is 0x%.8x\n",__func__,(unsigned int)mmap_buf_ptr);
memset(mmap_buf_ptr,0,PAGE_SIZE *4);
*((unsigned int *)(mmap_buf_ptr)) = 0x11111111;
*((unsigned int *)(mmap_buf_ptr+PAGE_SIZE*1)) = 0x22222222;
*((unsigned int *)(mmap_buf_ptr+PAGE_SIZE*2)) = 0x33333333;
*((unsigned int *)(mmap_buf_ptr+PAGE_SIZE*3)) = 0x44444444;

mmap_cdev = cdev_alloc();

result = register_chrdev_region(devno,1,"mmap_char_mem");

cdev_init(mmap_cdev,&mmapiomem_fops);
mmap_cdev->owner = THIS_MODULE;
result = cdev_add(mmap_cdev, devno,1);

mmap_class = class_create(THIS_MODULE,"mmap_char_class");
if (IS_ERR(mmap_class)) {
result= PTR_ERR(mmap_class);
return -1;
}

device_create(mmap_class, NULL, devno, NULL, MMAPIOMEM_DEV_NAME);

return 0;
}

void mmapiomem_exit(void)
{
if (mmap_cdev != NULL)
cdev_del(mmap_cdev);
device_destroy(mmap_class,MKDEV(MMAPIOMEM_DEV_MAJOR,0));
class_destroy(mmap_class);

unregister_chrdev_region(MKDEV(MMAPIOMEM_DEV_MAJOR,0),1);
}

module_init(mmapiomem_init);
module_exit(mmapiomem_exit);

MODULE_LICENSE("Dual BSD/GPL");


应用部分:

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/mman.h>
#include <linux/vt.h>

#define DEVICE_FILENAME "/dev/mmapiomem"
#define MMAP_SIZE 0x8000

int main()
{

int ttydev;
int dev;
int loop,loop2;
char *ptrdata;

dev=open(DEVICE_FILENAME,O_RDWR|O_NDELAY);
if(dev>=0){
printf("2)open the dev success\n");

ptrdata=(char*)mmap(0,
MMAP_SIZE,
PROT_READ|PROT_WRITE,
MAP_SHARED,
dev,
0);
for(loop = 0;loop < 64 * 5; loop ++)
{
for(loop2 = 0;loop2 < 16; loop2 ++)
{
printf("%.8x,",*((unsigned int *)(ptrdata + 4*(loop2 + 16 * loop))));
}
printf("\n");

}

if(ptrdata!=NULL){
printf("the value of ptrdata is 0x%.8x\n",*((unsigned int *)ptrdata));
}

munmap(ptrdata,MMAP_SIZE);
}

close(dev);
printf("6)here close the dev\n");

return 0;
}

 

通过打印信息,可以看到已经获得了连续的物理内存(由内核分配,应用可以使用)。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: