0

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;
}
5
  • 1
    VMA stands for Virtual Memory Area. The 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. Commented Jun 26, 2023 at 21:17
  • Yes I get it, however I don't understand one thing. "remap_pfn_range() will map a contiguous physical address space into the virtual space represented by vm_area_struct:" What is physical address space in this case? Where is it specified? As far as I understand vma->vm_start and vma->vm_end refers to the virtual address range in the userspace process, so where are the addresses of the physical pages I want to map? Are they calculated using vma->vm_start and end (which are assigned by kernel before jumping into my mmap implementation) by translating virtual addresses into physical addresses? Commented Jun 27, 2023 at 19:34
  • And nobody knows what you want to map, don’t ask us where the addresses of the physical pages are, we do not know, but you. Commented Jun 28, 2023 at 9:46
  • It is a code snippet copied directly from LDD3, I guess it "does something" and it "maps" something so that is why I am asking about this particular example. So if there is no physical address used in this particular case, what does this code do? Don't ask me about the physical address I use, because I'm relying directly on the example from the book. If I was trying to mmap my custom device's address I would definitely mention this. Do you see the difference? Commented Jun 28, 2023 at 10:02
  • 1
    The "Remapping Specific I/O Regions" section of LDD3 is a bit more realistic for a hardware device with a single region to be mmaped, but for simple_region_start and simple_region_size, use values from the corresponding struct resource (the .start member, for the start address, and resource_size(&resource), but adjusted to align to page boundaries. Also check the how it is done by the "uio" (userspace I/O device) drivers. Commented Jun 30, 2023 at 17:06

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.