nopage
除了 remap_pfn_range()以外,在驱动程序中实现 VMA 的 nopage()函数通常可以为设备提供更加灵活的内存映射途径。当访问的页不在内存,即发生缺页异常时, nopage()会被内核自动调用。
static int xxx_mmap(struct file *filp, struct vm_area_struct *vma)
{
unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;
if (offset >= _ _pa(high_memory) || (filp->f_flags &O_SYNC))
vma->vm_flags |= VM_IO;
vma->vm_flags |= VM_RESERVED;
/* 预留 */
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 映射,其调用发生在缺页异常时。