下面的程序在启动的时候保留一段内存,然后使用ioremap将它映射到内核虚拟空间,同时又用remap_page_range映射到用户虚拟空间,这样一来,内核和用户都能访问。如果在内核虚拟地址将这段内存初始化串"abcd",那么在用户虚拟地址能够读出来:
************mmap_ioremap.c**************/
#include
#include
#include
#include
#include /* for mem_map_(un)reserve */
#include /* for virt_to_phys */
#include /* for kmalloc and kfree */
MODULE_PARM(mem_start, "i");
MODULE_PARM(mem_size, "i");
static int mem_start = 101, mem_size = 10;
static char *reserve_virt_addr;
static int major;
int mmapdrv_open(struct inode *inode, struct file *file);
int mmapdrv_release(struct inode *inode, struct file *file);
int mmapdrv_mmap(struct file *file, struct vm_area_struct *vma);
static struct file_operations mmapdrv_fops =
{
owner: THIS_MODULE, mmap: mmapdrv_mmap, open: mmapdrv_open, release:
mmapdrv_release,
};
int init_module(void)
{
if ((major = register_chrdev(0, "mmapdrv", &mmapdrv_fops)) < 0)
{
printk("mmapdrv: unable to register character device\n");
return ( - EIO);
}
printk("mmap device major = %d\n", major);
printk("high memory physical address 0x%ldM\n", virt_to_phys(high_memory) /
1024 / 1024);
reserve_virt_addr = ioremap(mem_start *1024 * 1024, mem_size *1024 * 1024);
printk("reserve_virt_addr = 0x%lx\n", (unsigned long)reserve_virt_addr);
if (reserve_virt_addr)
{
int i;
for (i = 0; i < mem_size *1024 * 1024; i += 4)
{
reserve_virt_addr[i] = 'a';
reserve_virt_addr[i + 1] = 'b';
reserve_virt_addr[i + 2] = 'c';
reserve_virt_addr[i + 3] = 'd';
}
}
else
{
unregister_chrdev(major, "mmapdrv");
return - ENODEV;
}
return 0;
}
/* remove the module */
void cleanup_module(void)
{
if (reserve_virt_addr)
iounmap(reserve_virt_addr);
unregister_chrdev(major, "mmapdrv");
return ;
}
int mmapdrv_open(struct inode *inode, struct file *file)
{
MOD_INC_USE_COUNT;
return (0);
}
int mmapdrv_release(struct inode *inode, struct file *file)
{
MOD_DEC_USE_COUNT;
return (0);
}
int mmapdrv_mmap(struct file *file, struct vm_area_struct *vma)
{
unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;
unsigned long size = vma->vm_end - vma->vm_start;
if (size > mem_size *1024 * 1024)
{
printk("size too big\n");
return ( - ENXIO);
}
offset = offset + mem_start * 1024 * 1024;
/* we do not want to have this area swapped out, lock it */
vma->vm_flags |= VM_LOCKED;
if (remap_page_range(vma, vma->vm_start, offset, size, PAGE_SHARED))
{
printk("remap page range failed\n");
return - ENXIO;
}
return (0);
}
--------------------------------------------------------
remap_page_range函数的功能是构造用于映射一段物理地址的新页表,实现了内核空间与用户空间的映射,其原型如下:
int remap_page_range(vma_area_struct *vma, unsigned long from, unsigned long to, unsigned long size, pgprot_tprot);
使用mmap最典型的例子是显示卡的驱动,将显存空间直接从内核映射到用户空间将可提供显存的读写效率。
阅读(285) | 评论(0) | 转发(0) |