How can I map device's IO memory to userspace using `mmap()`?

369 Views Asked by At

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;
}
0

There are 0 best solutions below