Specifications
This is the Title of the Book, eMatter Edition
Copyright © 2005 O’Reilly & Associates, Inc. All rights reserved.
428
|
Chapter 15: Memory Mapping and DMA
The nopage method should also store the type of fault in the location pointed to by
the
type argument—but only if that argument is not NULL. In device drivers, the
proper value for
type will invariably be VM_FAULT_MINOR.
If you are using nopage, there is usually very little work to be done when mmap is
called; our version looks like this:
static int simple_nopage_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 = &simple_nopage_vm_ops;
simple_vma_open(vma);
return 0;
}
The main thing mmap has to do is to replace the default (NULL) vm_ops pointer with
our own operations. The nopage method then takes care of “remapping” one page at
a time and returning the address of its
struct page structure. Because we are just
implementing a window onto physical memory here, the remapping step is simple:
we only need to locate and return a pointer to the
struct page for the desired
address. Our nopage method looks like the following:
struct page *simple_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;
}
Since, once again, we are simply mapping main memory here, the nopage function
need only find the correct
struct page for the faulting address and increment its refer-
ence count. Therefore, the required sequence of events is to calculate the desired physi-
cal address, and turn it into a page frame number by right-shifting it
PAGE_SHIFT bits.
Since user space can give us any address it likes, we must ensure that we have a valid
page frame; the pfn_valid function does that for us. If the address is out of range, we
return
NOPAGE_SIGBUS, which causes a bus signal to be delivered to the calling process.
,ch15.13676 Page 428 Friday, January 21, 2005 11:04 AM