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

來源:互聯網
上載者:User

時間:晚上7點

地點:寢室中..

“小王,今天就不多話了,接著昨天沒講完的,不然連不起來了,都..”我催促著。

  上節講到kmalloc()申請的記憶體若要被映射到使用者空間可以通過mem_map_reserve()設定為保留後進行。具體怎麼操作呢,給你一個模版吧:

// 核心模組載入函數int __init kmalloc_map_init(void){    ../申請裝置號,添加cedv結構體  buffer = kmalloc(BUF_SIZE, GFP_KERNEL); //申請buffer  for(page = virt_to_page(buffer); page< virt_to_page(buffer+BUF_SIZE); page++)  {     mem_map_reserve(page);  //置業為保留  }}//mmap()函數static int kmalloc_map_mmap(struct file *filp, struct vm_area_struct *vma){    unsigned long page, pos;    unsigned long start = (unsigned long)vma->start;    unsigned long size = (unsigned long)(vma->end - vma->start);    printk(KERN_INFO, "mmaptest_mmap called\n");    if(size > BUF_SIZE)  //使用者要映射的地區太大        return - EINVAL;    pos = (unsigned long)buffer;    while(size > 0)   //映射buffer中的所有頁    {        page = virt_to_phys((void *)pos);        if(remap_page_range(start, page, PAGE_SIZE, PAGE_SHARRED))            return -EAGAIN;        start += PAGE_SIZE;        pos +=PAGE_SIZE;        size -= PAGE_SIZE;    }    return 0;}

另外通常,IO記憶體被映射時需要是nocache的,這個時候應該對vma->vm_page_prot設定nocache標誌。如下:

static int xxx_nocache_mmap(struct file *filp, struct vm_area_struct *vma){  vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);   //賦nocache標誌  vma->vm_pgoff = ((u32)map_start >> PAGE_SHIFT);  if(rempa_pfn_range(vma, vma->vm_start, vma->vm_pgoff, vma->vm_end - vm_start, vma->vm_page_prot));     return - EAGGIN;  return 0;}

這段代碼中的pgprot_noncached()是一個宏,它實際上禁止了相關頁的cache和寫緩衝(write buffer),另外一個稍微少的一些限制的宏是:

#define pgprot_writecombine(prot)  __pgprot(pgprot_val (prot) & –L_PTE_CACHEABLE);    它則沒有禁止寫緩衝

而除了rempa_pfn_range()外,在驅動程式中實現VMA的nopage()函數通常可以為裝置提供更加靈活的記憶體映射途徑。當發生缺頁時,nopage()會被核心自動調用,。這是因為,當發生缺頁異常時,系統會經過如下處理過程:

1)找到缺頁的虛擬位址所在的VMA             2)如果必要,分配中間頁目錄表和頁表              

3)如果頁表項對應的物理頁表不存在,則調用這個VMA的nopage()方法,它返回物理頁面的頁描述符。

4)將物理頁面的地址填充到頁表中。

實現nopage後,使用者空間可以通過mremap()系統調用重新綁定映射區所綁定的地址,下面給出一個在裝置驅動中使用nopage()的典型範例:

static int xxx_mmap(struct file *filp, struct vm_area_struct *vma);{     unsigned long offset = vma->vm_pgoff << PAGE_OFFSET;     if(offset >= _ _pa(high_memory) || (filp->flags &O_SYNC))             vma->vm_flags |=VM_IO;     vma->vm_ops = &xxx_nopage_vm_ops;     xxx_vma_open(vma);     return 0;}struct page *xxx_vma_nopage(struct vm_area_struct *vma, unsigned long address, int *type){   struct page *pageptr;   unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;   unsigned long physaddr = address - vma->vm_start + offset;   //實體記憶體   unsigned long pageframe = physaddr >> PAGE_SHIFT;  //頁幀號   if(!pfn_valid(pageframe))   //頁幀號有效      return NOPAGE_SIGBUS;   pageptr = pfn_to_page(pageframe);    //頁幀號->頁描述符   get_page(pageptr);   //獲得頁,增加頁的使用計數   if(type)      *type = VM_FAULT_MINOR;   return pageptr;    //返回頁描述符
}

上述函數對常規記憶體進行映射,返回一個頁描述符,可用於擴大或縮小映射的記憶體地區,由此可見,nopage()和remap_pfn_range()一個較大的區別在於remap_pfn

_range()一般用於裝置記憶體映射,而nopage()還可以用於RAM映射。

 

小王,這節和前邊一節是在一起看的,我也可以喘口氣歇歇了,你慢慢看吧,就不煩你了,晚上吃飯叫上我哈..

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.