Linuxカーネル開発のメモリとI/Oアクセス(四)

6384 ワード

時間:午後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
"); 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マッピングにも用いられる.
 
王さん、この節は前の節と一緒に見ています.私も息を吐いて休むことができます.ゆっくり見てください.邪魔しないでください.晩ご飯を食べて私を呼んでください.