對於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 ) )取得 |