2009-06-25 05:05:25     Still unsure on MMAP

Document created by Aaronwu Employee on Aug 15, 2013
Version 1Show Document
  • View in full screen mode

2009-06-25 05:05:25     Still unsure on MMAP

Dave Henning (UNITED STATES)

Message: 76316   


I am trying to convert a driver (drivers/media/dvb/siano) that was written for Linux with the assumption that it could use mmap() to map a driver structure into user-space.


The user code that calls mmap() is here:


hd->common_buffer = (unsigned char *) mmap (NULL, hd->common_buffer_size, PROT_READ, MAP_SHARED, hd->fd, 0);


The kernel code looks like this:



struct file_operations smschar_fops = {

    .owner = THIS_MODULE,

    .read = smschar_read,

    .write = smschar_write,

    .open = smschar_open,

    .release = smschar_release,

    .mmap = smschar_mmap,

    .poll = smschar_poll,

    .ioctl = smschar_ioctl,



static int smschar_mmap(struct file *file, struct vm_area_struct *vma)


    struct smschar_device_t *dev = file->private_data;

    return smscore_map_common_buffer(dev->coredev, vma);



int smscore_map_common_buffer(struct smscore_device_t *coredev,

        struct vm_area_struct *vma)


    unsigned long end = vma->vm_end,

    start = vma->vm_start,

    size = PAGE_ALIGN(coredev->common_buffer_size);


    if (!(vma->vm_flags & (VM_READ | VM_SHARED)) ||

            (vma->vm_flags & VM_WRITE)) {

        sms_err("invalid vm flags");

        return -EINVAL;



    if ((end - start) != size) {

        sms_err("invalid size %d expected %d",

                (int)(end - start), (int)size);

        return -EINVAL;



    if (remap_pfn_range(vma, start,

            coredev->common_buffer_phys >> PAGE_SHIFT,

            size, pgprot_noncached(vma->vm_page_prot))) {

        sms_err("remap_page_range failed");

        return -EAGAIN;


    return 0;






I am trying to re-write the code to deal with uClinux's NOMMU world.   I saw the page on MMAP here:




I have also read a few threads regarding MMAP.  It seems like if I change the calling code to use MAP_PRIVATE and modify the smscore_map_common_buffer() like this, I should be well on my way.


int smscore_map_common_buffer(struct smscore_device_t *coredev,

        struct vm_area_struct *vma) {


    vma->vm_start = (unsigned long)(coredev->common_buffer_phys);

    vma->vm_flags |= VM_MAYSHARE | VM_SHARED;

    return 0;





After I switched the MAP_PRIVATE, I got the mmap() to execute without reporting an error, but I think I have the address wrong because I quickly got a kernel panic starting with:




COMM=events/0 PID=5                                                           

CPU = 0                                                                       

invalid mm




My questions are


1. I read that Blackfin wants me to use MAP_PRIVATE instead of MAP_SHARED on one of the video-related mmap() threads.  Why is this or is it specific to certain drivers?


2.  Am I going to set vma->vm_start to the physical or logical address of the buffer in kernel space?


3.  Is it necessary to set my devices .get_unmapped_buffer field to something?


4.  Am I on the right track here?




2009-06-25 11:44:50     Re: Still unsure on MMAP

Dave Henning (UNITED STATES)

Message: 76334   


Please ignore the above post for now as I think I was on the wrong track.


Let me ask some general questions that will help point me in the right direction so I don't waste your time with reading specific code.


The driver I was given implements a character device.   This device provides a common buffer to a userspace library that interfaces with the kernel driver .  As written, the library uses a read-only, shared mmap() call to set up this buffer.   However, when executed in uClinux, the mmap() fails because it does not have a get_unmapped_buffer() function and the kernel rejects the request in mm/nommu.c::validate_mmap_request().


I re-read the 'nommu-mmap.txt' file in the Documentation folder of the kernel and studied nommuc.  I believe I need to follow the directions in the section "PROVIDING SHAREABLE CHARACTER DEVICE SUPPORT."  If that is the case, I want to be sure I understand what is being said there.


This is the process I believe I need to go through.  Please let me know if this is correct.


- Implement a function for f_op->get_unmapped_buffer()


- Set the f_op->mapping->backing_dev_info->capabilities to include BDI_CAP_MAP_DIRECT | BDI_CAP_READ_MAP in my kernel driver's init function.


- Modify my f_op->mmap function to simply return the address of the buffer without using remap_pfn_range().


- Do not change the userspace call to mmap(), specifically keeping the flag MAP_SHARED.


Does that correct?




Dave ...