Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

mmap: mapping in user space a kernel buffer allocated with kmalloc

Which is the correct way to map in an user space process a buffer allocated with kmalloc? Maybe i didn't understand memory mapping yet...I write a kernel module that allocs this buffer (for example 120 bytes) and i would read and write it in a user-space process. Obviously i created a char device and implemented a mmap method in the file_operations struct. My method is:

static int my_mmap(struct file *filp, struct vm_area_struct *vma)
{
  //printk(KERN_INFO "Allocated virtual memory length = %d", vma->vm_end - vma->vm_start);

  long unsigned int size = vma->vm_end - vma->vm_start;

  if (remap_pfn_range(vma, vma->vm_start,
                      __pa(mem_area) >> PAGE_SHIFT,  //what about vma->vm_pgoff?
                      size,
                      vma->vm_page_prot) < 0)
    return -EAGAIN;

  vma->vm_flags |= VM_LOCKED;
  vma->vm_ops = &vmops;
  vma->vm_flags |= VM_RESERVED;

  my_vm_open(vma);

  return 0;
}

where mem_area points at a memory area allocated with kmalloc at module init. The area is filled with the same value (for example 0x10). All works but i think there is something wrong in this code:

  1. kmalloc could return a pointer that isn't page aligned and, in that case, i don't think is correct the value of the third parameter of remap_pfn_range in fact in user space i read the wrong value. Instead all works if i use __get_free_page (because the the function always returns a pointer that is page aligned) or when kmalloc returns a page aligned pointer. Memory mapping works with memory regions that are multple of PAGE_SIZE so, should i allocate an entire page instead of using kmalloc?

  2. When my_mmap is called, the kernel has allocated some pages yet? I ask this because i found some implementations of custom mmap method that call remap_pfn_range with vma->vm_pgoff as third parameter...how could be useful this? Is this the page frame of the first new allocated page? If i pass as third parameter a page frame like i do in my_mmap, i should free pages starting from page in vma->vm_pgoff?

  3. However i found an implementation of mmap method that maps a buffer allocated with kmalloc. To correctly map the buffer an operation (that i don't undestand for now) is performed before remap_pfn_range. Suppose that mem is the pointer returned by kmalloc, mem_area is initialized in this manner:

    mem_area=(int *)(((unsigned long)mem + PAGE_SIZE - 1) & PAGE_MASK);
    

So mem_area contains the same value of mem only if mem is page aligned otherwise is should contain the pointer at the beginning of the next page. However, with this operation if i pass as third param of remap_pfn_range the value __pa(mem_area) >> PAGE_SHIFT mapping works well. Why?

Thank you all!

like image 263
MirkoBanchi Avatar asked Aug 06 '11 15:08

MirkoBanchi


People also ask

Why is kernel mapped to the same address space as processes?

The reason why kernel is mapped into userspace is mostly performance-related. Kernel can also set own different page table at any time to access physical memory it wants, but that would also trash all caches and degrade performance dramatically.

How do I access user-space from kernel?

Whilst a user-space program is not allowed to access kernel memory, it is possible for the kernel to access user memory. However, the kernel must never execute user-space memory and it must also never access user-space memory without explicit expectation to do so.

What is the maximum memory that can be allocated using Kmalloc?

The maximum size allocatable by kmalloc() is 1024 pages, or 4MB on x86. Generally for requests larger than 64kB, one should use __get_free_page() functions to ensure inter-platform compatibility.

How mmap is implemented in Linux?

To assign a mmap() operation to a driver, the mmap field of the device driver's struct file_operations must be implemented. If that is the case, the user space process can then use the mmap() system call on a file descriptor associated with the device.


1 Answers

  1. Yes, you should be allocating a whole number of pages.

  2. No, the kernel hasn't allocated any pages. vm->vm_pgoff is the requested offset within the device being mapped - it's the last parameter to the userspace mmap() call, translated from bytes to pages. You're probably looking at the mem or kmem mmap implementations, in which case the offset represents the physical or linear page that userspace wants to map.

  3. That is just allocating a page-aligned buffer within the kmalloc() allocated buffer. You're better off using __get_free_pages() as you've already surmised, cutting out the middle-man.

You should be testing that the size being mapped does not exceed your buffer.

like image 128
caf Avatar answered Sep 29 '22 17:09

caf