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,
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
|