2.6.18内核和2.6.25以后内核remap_pfn_range()对kmalloc()到的区别

对于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内核就必须按照下面的步骤来完成映射
对于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 ) )取得

你可能感兴趣的:(2.6.18内核和2.6.25以后内核remap_pfn_range()对kmalloc()到的区别)