mmap() problem - segmentation fault

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hi,
I was testing the mmap() functionality in my driver code as shown below.
Actually this code has code for versions below 2.4.x and >= 2.4.x. We need to enble the appropriate calls
The code below is enabled for >=  2.4.
I am working on version 2.4.18.
From the user space process,
  1. Open the device --> returned success
  2. call mmap() --> returned success
  3. Try to access the addressfrom user space returned by mmap() --> segmentation fault!!!!!!!!!!!!!!
Whats the reason for the segmentation fault????
When i enable the code for <2.4, it works fine.
 
Code
=====

#include <linux/kernel.h>
#include <linux/module.h>
/* needed for __init,__exit directives */
#include <linux/init.h>
/* needed for remap_page_range */
#include <linux/mm.h>
/* obviously, for kmalloc */
#include <linux/malloc.h>
/* for struct file_operations, register_chrdev() */
#include <linux/fs.h>

/* this header files wraps some common module-space operations ...
   here we use mem_map_reserve() macro */
#include <linux/wrapper.h>

/* needed for virt_to_phys() */
#include <asm/io.h> // virt_to_phys()

/* here's the pointer to the buffer */
static char *buffer;

/* how big is the buffer ? */
/* two pages on x86 */
#define MMT_BUF_SIZE 8192

/* the device's mmap method. The VFS has kindly prepared the process's
   vm_area_struct for us, so we examine this to see what was requested.
   this code is adapted from drivers/char/bttv.c:do_bttv_mmap */
static int mmaptest_mmap(struct file *filp, struct vm_area_struct *vma)
{
        unsigned long page,pos;
unsigned long start = (unsigned long)vma->vm_start;
unsigned long size = (unsigned long)(vma->vm_end-vma->vm_start);

printk(KERN_INFO "mmaptest_mmap called\n");

/* if userspace tries to mmap beyond end of our buffer, fail */
        if (size>MMT_BUF_SIZE)
                return -EINVAL;

/* start off at the start of the buffer */
        pos=(unsigned long) buffer;

/* loop through all the physical pages in the buffer */
/* Remember this won't work for vmalloc()d memory ! */
        while (size > 0) {
/* remap a single physical page to the process's vma */
                page = virt_to_phys((void *)pos);
/* fourth argument is the protection of the map. you might
* want to use vma->vm_page_prot instead.
*/
                if (remap_page_range(start, page, PAGE_SIZE, PAGE_SHARED))
                        return -EAGAIN;
                start+=PAGE_SIZE;
                pos+=PAGE_SIZE;
                size-=PAGE_SIZE;
        }
        return 0;
}

static int mmaptest_open(struct inode *inode, struct file *filp)
{
MOD_INC_USE_COUNT;
return 0;
}

static int mmaptest_release(struct inode *inode, struct file *filp)
{
MOD_DEC_USE_COUNT;
return 0;
}

/* VFS methods */
static struct file_operations mmaptest_fops = {
mmap: mmaptest_mmap,
        open: mmaptest_open,
release: mmaptest_release,
};

int __init init_mmaptest(void)
{
struct page *page;

/* if you want to test the module, you obviously need to
   "mknod". Note that normally you would use the misc_device
   interface, but I'm too lazy to change it. */
register_chrdev(187,"mmaptest",&mmaptest_fops);
buffer = kmalloc(MMT_BUF_SIZE,GFP_KERNEL);
if (!buffer) {
printk(KERN_INFO "failed kmalloc\n");
unregister_chrdev(187,"mmaptest");
return 0;
}

/* now we've got MMT_BUF_SIZE bytes of kernel memory, but it can still be
   swapped out. We need to stop the VM system from removing our
   pages from main memory. To do this we just need to set the PG_reserved
   bit on each page, via mem_map_reserve() macro. */

/* If we don't set the reserved bit, the user-space application sees all-zeroes
   pages. This is because remap_page_range() won't allow you to map non-reserved pages
   (check remap_pte_range()). The pte's will be cleared, resulting in a page faulting in
   a new zeroed page instead of the pages we are trying to mmap().
   (explanation from Martin Maletinsky) */
for (page = virt_to_page(buffer); page < virt_to_page(buffer + MMT_BUF_SIZE); page++) {
mem_map_reserve(page);
        }

/* this is the code we would use for kernels earlier than 2.4, where virt_to_page
* doesn't exist
for (i = MAP_NR(buffer); i <= MAP_NR(buffer + 4095); i++) {
mem_map_reserve(i);
        } */

/* something to read out */
strcpy(buffer,"This is a mmaptest");
return 0;
}


void __exit cleanup_mmaptest(void)
{
struct page *page;

for (page = virt_to_page(buffer); page < virt_to_page(buffer + MMT_BUF_SIZE); page++) {
mem_map_unreserve(page);
}

kfree(buffer);
unregister_chrdev(187,"mmaptest");
return;
}

module_init(init_mmaptest);
module_exit(cleanup_mmaptest);
 
 
 
Thanks in advance.
 
Regards,
Anj

[Index of Archives]     [Newbies FAQ]     [Linux Kernel Mentors]     [Linux Kernel Development]     [IETF Annouce]     [Git]     [Networking]     [Security]     [Bugtraq]     [Yosemite]     [MIPS Linux]     [ARM Linux]     [Linux RAID]     [Linux SCSI]     [Linux ACPI]
  Powered by Linux