I'm browsing through LDD3 and I have difficulty understanding a chapter about mmap().
Here is a code snipped from the book:
static int simple_remap_mmap(struct file *file, struct vm_area_struct *vma)
{
if (remap_pfn_range(vma, vma->vm_start, vma->vm_pgoff,
vma->vm_end - vma->vm_start,
vma->vm_page_prot))
return -EAGAIN;
vma->vm_ops = &simple_remap_vm_ops;
simple_vma_open(vma);
return 0;
}
If I understand it correctly this piece of code is supposed to map my device's I/O memory into user space. But how? Basically this function does almost nothing, so how would it map some device's memory area into the userspace process if it does not use any physical addresses? Also, I've read that it is not able to map RAM - so what does this function actually map?
Here is another code snippet that basically should cover the same chapter from this book, but as you can see it is completely different. Why is that? Why in the second example there is an explicit page allocation whereas, in the first one, there is none?
static struct vm_operations_struct simple_remap_vm_ops = {
.open = simple_vma_open,
.close = simple_vma_close,
};
static int simple_remap_mmap(struct file *filp, struct vm_area_struct *vma)
{
int rv;
size_t len = vma->vm_end - vma->vm_start;
struct page *pages;
/*
* To prevent from memory over run. Limit the maximux mmap size here
* to 10 * PAGE_SIZE
*/
if (len >> PAGE_SHIFT > 10) {
pr_err("Map size overflow! len=%ld pages\n", len >> PAGE_SHIFT);
return -EFAULT;
}
/*
* Allocate necessary pages and initialize it properly.
* We initialize all memory to a special value: 0xdeadbeef
*/
pages = alloc_pages(GFP_KERNEL, get_order(len));
memset32(page_address(pages), 0xdeadbeef,
(1 << get_order(len)) * PAGE_SIZE / 4);
rv = remap_pfn_range(vma, vma->vm_start, page_to_pfn(pages),
vma->vm_end - vma->vm_start,
vma->vm_page_prot);
if (rv) {
return -EAGAIN;
}
pr_debug("vm_start: %#lx, vm_end: %#lx\n, len: %#lx, vm_pgoff: %#lx(%#lx), ops=%p\n",
vma->vm_start, vma->vm_end, len,
vma->vm_pgoff, vma->vm_pgoff << PAGE_SHIFT,
vma->vm_ops);
vma->vm_ops = &simple_remap_vm_ops;
simple_vma_open(vma);
return 0;
}
remap_pfn_range()takes existing virtual mapping and maps it again into virtual address space. Something should first to map the MMIO into memory address space, before you can remap it. That's how I understand this.simple_region_startandsimple_region_size, use values from the correspondingstruct resource(the.startmember, for the start address, andresource_size(&resource), but adjusted to align to page boundaries. Also check the how it is done by the "uio" (userspace I/O device) drivers.