應用與裝置驅動之間資料互動,很多時候都使用copy_to_user與copy_from_user。但如果在追求高效能的驅動上,這種拷貝顯然不是最佳的做法。
linux核心提供了一種記憶體對映的機制,它主要完成將裝置的位址空間對映到使用者空間或者直接使用使用者空間中的位址,這樣做的目的顯然是為了提公升系統效能。
本節要討論的mmap主要用來將使用者空間的一段虛擬位址對映到裝置io空間中,這樣,使用者空間程序可以直接訪問裝置記憶體。驅動程式在此主要要完成的是在其內部實現file_operations中的mmap方法。
file_operations中定義的mmap函式原型:
struct file_operations linear;
struct list_head nonlinear;
const char __user *anon_name;
} shared;
/** a file's map_private vma can be in both i_mmap tree and anon_vma
* list, after a cow of one of
thefile pages. a map_shared vma
* can only be in
the i_mmap tree. an anonymous map_private, stack
* or brk vma (with null file) can only be in an anon_vma list.
*/struct list_head anon_vma_chain; /* serialized by mmap_sem &
* page_table_lock */
struct anon_vma *anon_vma; /* serialized by page_table_lock */
/* function pointers to deal with this struct. */
const struct vm_operations_struct *vm_ops;
/* information about our backing store: */
unsigned long vm_pgoff; /* offset (within vm_file) in page_size
units, *not* page_cache_size */
struct file * vm_file; /* file we map to (can be null). */
void * vm_private_data; /* was vm_pte (shared mem) */
#ifndef config_mmu
#endif
#ifdef config_numa
struct mempolicy *vm_policy; /* numa policy for
the vma */
#endif}
核心中的每個vm_area_struct物件都表示使用者程序位址空間的一段區域,它是訪問使用者程序中mmap位址空間的最小單元。核心使用紅黑樹管理這些vm_area_struct物件。
當linux系統執行乙個應用程式時,系統呼叫exec通過呼叫load_elf_binary函式將該應用程式對應的elf二進位制檔案載入到程序3gb大小的虛擬位址空間中。布局由此產生。
mmap工作原理是:核心先在程序虛擬位址空間的mmap區域分配 乙個空閒的vma物件,然後通過頁表方式將vma物件代表的虛擬位址空間對映到裝置的儲存空間中。因為通過頁表方式,這意味著每個vma物件表示的位址空間應該是頁對齊的,大小是頁的整數倍。
如果一切正常,mmap函式將返回已經被對映在mmap區域中一段虛擬位址的起始位址.
前面已經說過,驅動通過配置相應的虛擬位址頁目錄表項完成mmap的實現.主要remap_pfn_range介面.
int remap_pfn_range(struct vm_area_struct *vma, unsigned long addr,
unsigned long pfn, unsigned long size, pgprot_t prot)
err = track_pfn_remap(vma, &prot, pfn, addr, page_align(size));
if (err)
return -einval;
vma->vm_flags |= vm_io | vm_pfnmap | vm_dontexpand | vm_dontdump;
bug_on(addr >= end);
pfn -= addr >> page_shift;
pgd = pgd_offset(mm, addr);
flush_cache_range(vma, addr, end);
do while (pgd++, addr = next, addr != end);
if (err)
untrack_pfn(vma, pfn, page_align(size));
return err;
}
這個函式的作用是為[addr, addr+size]範圍的位址建立頁表,將其對映到pfn開始的物理頁面上.如果不希望cache機制起作用,可能通過引數port引數來控制.比如使用pgprot_noncached().
munmap做的事情與mmap恰好相反,核心會根據現有的對映資訊拆除在mmap中建立的頁表項.這部分操作無需驅動實現,因此驅動中無對應的munmap.
fd=open(name, flag, mode); if(fd<0) ...
ptr=mmap(null, len , prot_read|prot_write, map_shared , fd , 0);
mmap記憶體對映
記憶體對映是個很有用,也很有意思的思想。我們都知道作業系統分為使用者態和核心態,使用者態是不能直接和物理裝置打交道的,如果想把硬碟的一塊區域讀到使用者態,則需要兩次拷貝 硬碟 核心 使用者 但是記憶體對映的設計只需要發生一次的拷貝,大大的提高了讀取資料的效率。那麼記憶體對映的原理和核心是如何實現的呢...
mmap記憶體對映
記憶體對映是個很有用,也很有意思的思想。我們都知道作業系統分為使用者態和核心態,使用者態是不能直接和物理裝置打交道的,如果想把硬碟的一塊區域讀到使用者態,則需要兩次拷貝 硬碟 核心 使用者 但是記憶體對映的設計只需要發生一次的拷貝,大大的提高了讀取資料的效率。那麼記憶體對映的原理和核心是如何實現的呢...
Linux記憶體對映 mmap
linux提供了記憶體對映函式mmap,它把檔案內容對映到一段記憶體上 準確說是虛擬記憶體上 通過對這段記憶體的讀取和修改,實現對檔案的讀取和修改,先來看一下mmap的函式宣告 原型 void mmap void addr,size t length,int prot,int flags,int f...