Chinaunix首页 | 论坛 | 博客
  • 博客访问: 468475
  • 博文数量: 150
  • 博客积分: 2706
  • 博客等级: 少校
  • 技术积分: 1200
  • 用 户 组: 普通用户
  • 注册时间: 2009-11-09 11:41
文章分类

全部博文(150)

文章存档

2012年(7)

2011年(6)

2010年(68)

2009年(69)

我的朋友

分类: LINUX

2010-08-11 17:52:20

这一周在调frame buffer的mmap问题,费了不少脑筋,找到一篇比较有帮助性的文章,特转载如下。

对于2.6.25以上内核,直接调用

vma->vm_flags |= VM_SHARED | VM_RESERVED;
io_remap_pfn_range(vma, vma->vm_start, phy_addr >> PAGE_SHIFT,
                 vma->vm_end - vma->vm_start, vma->vm_page_prot);

但是2.6.18内核就必须按照下面的步骤来完成映射[luther.gliethtttp].
对于2.6.18内核使用如下方法的驱动实例可以参考2.6.18.5内核源码
sound/oss/i810_audio.c|1044| SetPageReserved(page);
alloc_dmabuf {
    /* now mark the pages as reserved; otherwise remap_pfn_range doesn't do what we want */
    pend = virt_to_page(rawbuf + (PAGE_SIZE << order) - 1);
    for (page = virt_to_page(rawbuf); page <= pend; page++)
        SetPageReserved(page);
}
dealloc_dmabuf {
    for (page = virt_to_page(dmabuf->rawbuf); page <= pend; page++)
            ClearPageReserved(page);
}
static int i810_mmap(struct file *file, struct vm_area_struct *vma)
{
    if (remap_pfn_range(vma, vma->vm_start,
                 virt_to_phys(dmabuf->rawbuf) >> PAGE_SHIFT,
                 size, vma->vm_page_prot))
}
remap_pfn_range 通过你的页帧号来建立页表, 并映射到用户空间!
一般情况是你的驱动分配一块内存,然后在驱动的mmap中使用这块内存的 物理地址转成页帧号, 再调用remap_pfn_range!
假设1你是通过kmalloc(),get_free_pages()等分配的这种内存页是不能通过remap_pfn_range()映射出去的要对每个页面调用SetPageReserverd()标记为“保留”才可以,virt_to_phys()函数只是得到其物理地 址,remap_pfn_range()中的第三个参数是要求物理页便的“帧”号,即pfn,所以你的phys还要“> > PAGE_SHIFT”操作 
假设2你是通过vmalloc分配得来的,同上,不同的是要用vmalloc_to_pfn 
3,用kmalloc,get_free_pages,vmalloc分配的物理内存页面最好还是不要用remap_pfn_page方法,建议使用VMA的nopage方法 
4,对于这样的设备内存,最好对调用pgprot_nocached(vma-> vm_page_prot)后传给remap_pfn_range,防止处理器缓存 
5,你写的是framebuffer驱动,最好是用fb_mmap(),可扩展 

static int mmap_xxxxx(struct file *filp, struct vm_area_struct *vma)
{
unsigned long start = vma->vm_start;
unsigned long size = vma->vm_end - vma->vm_start;
unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;
unsigned long page, pos;

if(size > MMAP_MEM_SIZE)
return -EINVAL; 

printk( "start=0x%08x offset=0x%08x\n", start, offset );
printk( "kernel msg=%s\n", mmap_buf );
pos = (unsigned long)mmap_buf + offset;
page = virt_to_phys( pos ) >> PAGE_SHIFT ;
if ( remap_pfn_range( vma, start, page, size, PAGE_SHARED )) {
return -EAGAIN;
}
else {
printk( "remap_pfn_range %u\n success\n", page );
}
vma->vm_flags &= ~VM_IO; 
vma->vm_flags |= VM_RESERVED; 
return 0;
}
还有就是
offset参数右移PAGE_SHIFT 
就是得到页帧号, 前提是offset 是内核物理地址!
kmalloc, get_free_pages都可以通过 virt_to_phy取得
vmalloc 可以通过page_address( vmalloc_to_page( addr ) )取得




阅读(7239) | 评论(0) | 转发(1) |
给主人留下些什么吧!~~