Linux核心開發之記憶體與I/O訪問(三)

來源:互聯網
上載者:User

“小王,不瞞你說,我現在是悲喜交加啊,悲的是:這最後一章,我講的是膽顫心驚(以前自己都沒學好,現在也算還賬了),喜的是每講一張,我知道離結束就近了一點,趕快把這個東西過掉,進入下一環節,那又是我牛皮吹破天的時代了”看著小王期盼和懷疑的眼神,我,昔日的風采也不見了。

“沒事的,小濤哥,其實說真的,不是我安慰你哈,從開始我什麼都不懂,到現在我也算個入門級的高手了,都是你一手帶過來的,我已經對你推崇備至了,你就放心吧,會的你盡情教,不會的,你慢慢說,我都聽你的”小王善解人意的說。

“嗯,你真好,看來我沒看錯你,那好,繼續課程”。。。

  一般情況下,使用者空間是不可能也不應該直接存取裝置的,但是裝置驅動程式可實現mmap()函數,這個函數可使得使用者空間能直接存取裝置的物理地址。實際上,mmap()S實現了這樣的一個映射過程,它將使用者空間的一段記憶體與裝置記憶體關聯,當使用者訪問使用者空間的這段位址範圍時,實際上會轉化為對裝置的訪問。

  mmp()必須以PAGE_SIZE為單位進行映射,實際上,記憶體只能以頁為單位進行映射,若要映射非PAGE_SIZE整數倍的位址範圍,要先進行頁對齊,強行以PAGE

_SIZE的倍數大小進行映射。驅動中mmp()函數原型如下:int (*mmp)(struct file *, struct vm_area_struct *);它實現的機制是建立頁表,並填充VMA結構體中

vm_operations_struct指標,vm_area_struct用於描述一個虛擬記憶體地區。結構體如下:

struct vm_area_struct {    struct mm_struct * vm_mm; //所處的地址空間    unsigned long vm_start;//開始虛擬位址    unsigned long vm_end;//結束虛擬位址    struct vm_area_struct *vm_next;    pgprot_t vm_page_prot;  //存取權限    unsigned long vm_flags; //標誌     ...    struct vm_operations_struct * vm_ops;  //操作VMA的函數集指標    unsigned long vm_pgoff; //位移(頁幀號)    struct file * vm_file;    void * vm_private_data;    ...};

其中vm_ops成員指向這個VMA的操作集,結構體定義如下:

struct vm_operations_struct {   void (*open)(struct vm_area_struct * area);   void (*close)(struct vm_area_struct * area);   struct page * (*nopage)(struct vm_area_struct * area, unsigned long address, int *type);   int (*populate)(struct vm_area_struct * area, unsigned long address, unsigned long len, pgprot_t prot, unsigned long pgoff, int nonblock);    ...};在核心產生一個VMA後,它就會調用該VMA的open()函數。
  而驅動中的mmap()函數將在使用者進行mmap()系統調用時最終被調用,當使用者調用mmap()時候核心會進行如下處理:
  1)在進程的虛擬空間尋找一塊VMA.
  2)將這塊VMA進行映射。
  3)如果裝置驅動程式或檔案系統的file_operations定義了mmap()操作,則調用它。
  4)將這個VMA插入到進程的VMA鏈表中。
file_operations中mmap()函數的第一個參數就是步驟1中找的VMA.由mmap()系統調用映射的記憶體可由munmap()解除映射。這個函數原型如下:
int munmap(caddr_t addr, size_t len);
  但是,需要注意的是:當使用者進行mmap()系統調用後,儘管VMA在裝置驅動檔案操作結構體的mmap()被調用前就已經產生,核心卻不會調用VMA的open
函數,通常需要在驅動的mmap()函數中先上調用vma->vm_ops->open().為了說明問題,給出一個vm_operations_struct操作範例:
static int xxx_mmp(struct file *filp, struct vm_area_struct *vma){    if(remap_pfn_range(vma, vma->vm_start, vm->vm_pgoff, vma->vm_end - vma->start, vma->vm_page_prot))   //建立頁表     return - EAGAIN;    vma->vm_ops = &xxx_remap_vm_ops;    xxx_vma_open(vma);    return 0;}void xxx_vma_open(struct vm_area_struct *vma) //VMA開啟函數{  ...  printk(KERN_NOTICE "xxx VMA open, virt %lx, phys %1x\n",vma->vm_start, vma->vm_pgoff 《PAGE_SHIFT);}void xxx_vma_close(struct vm_area_struct *vma)  //VMA關閉函數{  ...  printk(KERN_NOTICE "xxx VMA close. \n");}static struct vm_operation_struct xxx_remap_vm_ops = //VM操作結構體{   .open=xxx_vma_open,   .close=xxx_vma_close,   ...}
在這段代碼中調用的remap_pfn_range()建立頁表。我們前邊說過在核心空間用kmalloc申請記憶體,這部分記憶體如果要映射到使用者空間可以通過mem_map
_reserve()調用設定為保留後進行,具體怎麼操作,咱們下集繼續。
 
相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.