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;
}
#endif /* SMS_HOSTLIB_SUBSYS */
******
I am trying to re-write the code to deal with uClinux's NOMMU world. I saw the page on MMAP here:
docs.blackfin.uclinux.org/doku.php?id=:mmap
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?
QuoteReplyEditDelete
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?
Thanks,
Dave ...