设为首页 加入收藏

TOP

Linux内核中ioremap映射的透彻理解(二)
2014-11-24 08:17:53 来源: 作者: 【 】 浏览:5
Tags:Linux 内核 ioremap 映射 透彻 理解
,这个宏定义为:


#define bRTC(Nb) __REG(0x57000000 + (Nb))


  其中又借助了宏__REG,而__REG又定义为:


# define __REG(x) io_p2v(x)


  最后的io_p2v才是真正"玩"虚拟地址和物理地址转换的地方:


#define io_p2v(x) ((x) | 0xa0000000)


  与__REG对应的有个__PREG:


# define __PREG(x) io_v2p(x)


  与io_p2v对应的有个io_v2p:


#define io_v2p(x) ((x) & ~0xa0000000)


  可见有没有出现ioremap是次要的,关键问题是有无虚拟地址和物理地址的转换!


  下面的程序在启动的时候保留一段内存,然后使用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最典型的例子是显示卡的驱动,将显存空间直接从内核映射到用户空间将可提供显存的读写效率。


(在内核驱动程序的初始化阶段,通过ioremap()将物理地址映射到内核虚拟空间;在驱动程序的mmap系统调用中,使用remap_page_range()将该块ROM映射到用户虚拟空间。这样内核空间和用户空间都能访问这段被映射后的虚拟地址。)


首页 上一页 1 2 下一页 尾页 2/2/2
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
分享到: 
上一篇Android 横屏,竖屏切换时候的状.. 下一篇ARM Linux基本运算符综合实例

评论

帐  号: 密码: (新用户注册)
验 证 码:
表  情:
内  容:

·C 内存管理 | 菜鸟教 (2025-12-26 20:20:37)
·如何在 C 语言函数中 (2025-12-26 20:20:34)
·国际音标 [ç] (2025-12-26 20:20:31)
·微服务 Spring Boot (2025-12-26 18:20:10)
·如何调整 Redis 内存 (2025-12-26 18:20:07)