小男孩‘自慰网亚洲一区二区,亚洲一级在线播放毛片,亚洲中文字幕av每天更新,黄aⅴ永久免费无码,91成人午夜在线精品,色网站免费在线观看,亚洲欧洲wwwww在线观看

分享

Linux內(nèi)核開發(fā)之內(nèi)存與I/O訪問(四)

 看風(fēng)景D人 2014-07-19

時(shí)間:晚上7點(diǎn)

地點(diǎn):寢室中..

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

  上節(jié)講到kmalloc()申請的內(nèi)存若要被映射到用戶空間可以通過mem_map_reserve()設(shè)置為保留后進(jìn)行。具體怎么操作呢,給你一個(gè)模版吧:

// 內(nèi)核模塊加載函數(shù)
int __init kmalloc_map_init(void)
{
    ../申請?jiān)O(shè)備號,添加cedv結(jié)構(gòu)體
  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);  //置業(yè)為保留
  }
}
//mmap()函數(shù)
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)  //用戶要映射的區(qū)域太大
        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內(nèi)存被映射時(shí)需要是nocache的,這個(gè)時(shí)候應(yīng)該對vma->vm_page_prot設(shè)置nocache標(biāo)志。如下:


static int xxx_nocache_mmap(struct file *filp, struct vm_area_struct *vma)
{
  vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);   //賦nocache標(biāo)志
  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()是一個(gè)宏,它實(shí)際上禁止了相關(guān)頁的cache和寫緩沖(write buffer),另外一個(gè)稍微少的一些限制的宏是:


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


而除了rempa_pfn_range()外,在驅(qū)動(dòng)程序中實(shí)現(xiàn)VMA的nopage()函數(shù)通??梢詾樵O(shè)備提供更加靈活的內(nèi)存映射途徑。當(dāng)發(fā)生缺頁時(shí),nopage()會(huì)被內(nèi)核自動(dòng)調(diào)用,。這是因?yàn)?當(dāng)發(fā)生缺頁異常時(shí),系統(tǒng)會(huì)經(jīng)過如下處理過程:


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


3)如果頁表項(xiàng)對應(yīng)的物理頁表不存在,則調(diào)用這個(gè)VMA的nopage()方法,它返回物理頁面的頁描述符。


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


實(shí)現(xiàn)nopage后,用戶空間可以通過mremap()系統(tǒng)調(diào)用重新綁定映射區(qū)所綁定的地址,下面給出一個(gè)在設(shè)備驅(qū)動(dòng)中使用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;   //物理內(nèi)存
   unsigned long pageframe = physaddr >> PAGE_SHIFT;  //頁幀號
   if(!pfn_valid(pageframe))   //頁幀號有效
      return NOPAGE_SIGBUS;
   pageptr = pfn_to_page(pageframe);    //頁幀號->頁描述符
   get_page(pageptr);   //獲得頁,增加頁的使用計(jì)數(shù)
   if(type)
      *type = VM_FAULT_MINOR;
   return pageptr;    //返回頁描述符
}

上述函數(shù)對常規(guī)內(nèi)存進(jìn)行映射,返回一個(gè)頁描述符,可用于擴(kuò)大或縮小映射的內(nèi)存區(qū)域,由此可見,nopage()和remap_pfn_range()一個(gè)較大的區(qū)別在于remap_pfn


_range()一般用于設(shè)備內(nèi)存映射,而nopage()還可以用于RAM映射。


 


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

    本站是提供個(gè)人知識管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多