mmap driver implementation
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/debugfs.h>
#include <linux/slab.h>
#include <linux/version.h>
#include <linux/mm.h> /* mmap related stuff */
#define DEV_NAME "mmap_example"
#define PRINTFUNC() printk(KERN_ALERT DEV_NAME ": %s called\n", __func__)
#define PRINT(a) printk(KERN_ALERT DEV_NAME ": %s: %s\n", __func__, a)
struct dentry* file1;
struct mmap_info {
char* data;
int reference;
};
void mmap_open(struct vm_area_struct* vma)
{
struct mmap_info* info = (struct mmap_info*)vma->vm_private_data;
info->reference++;
}
void mmap_close(struct vm_area_struct* vma)
{
struct mmap_info* info = (struct mmap_info*)vma->vm_private_data;
info->reference--;
}
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
struct page* mmap_nopage(struct vm_area_struct* vma, unsigned long address,
int* type)
#else
int mmap_fault(struct vm_area_struct* vma, struct vm_fault* vmf)
#endif
{
struct page* page;
struct mmap_info* info;
#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,0)
unsigned long address = (unsigned long)vmf->virtual_address;
#endif
PRINTFUNC();
if (address > vma->vm_end) {
PRINT("invalid address");
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
return NOPAGE_SIGBUS;
#else
return VM_FAULT_SIGBUS;
#endif
}
info = (struct mmap_info*)vma->vm_private_data;
if (!info->data) {
PRINT("no data");
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
return NOPAGE_OOM;
#else
return VM_FAULT_SIGBUS;
#endif
}
page = virt_to_page(info->data);
get_page(page);
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
if (type) {
*type = VM_FAULT_MINOR;
}
return page;
#else
vmf->page = page;
return 0;
#endif
}
struct vm_operations_struct mmap_vm_ops = {
.open = mmap_open,
.close = mmap_close,
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
.nopage = mmap_nopage,
#else
.fault = mmap_fault,
#endif
};
int my_mmap(struct file* filp, struct vm_area_struct* vma)
{
PRINTFUNC();
vma->vm_ops = &mmap_vm_ops;
vma->vm_flags |= VM_RESERVED;
vma->vm_private_data = filp->private_data;
mmap_open(vma);
return 0;
}
int my_close(struct inode* inode, struct file* filp)
{
struct mmap_info* info = filp->private_data;
PRINTFUNC();
free_page((unsigned long)info->data);
kfree(info);
filp->private_data = NULL;
return 0;
}
int my_open(struct inode* inode, struct file* filp)
{
struct mmap_info* info;
PRINTFUNC();
info = kmalloc(sizeof(struct mmap_info), GFP_KERNEL);
info->data = (char*)get_zeroed_page(GFP_KERNEL);
memcpy(info->data, "hello from kernel this is file: ", 32);
memcpy(info->data + 32, filp->f_dentry->d_name.name,
strlen(filp->f_dentry->d_name.name));
filp->private_data = info;
return 0;
}
static const struct file_operations my_fops = {
.open = my_open,
.release = my_close,
.mmap = my_mmap,
};
static int __init mmapexample_module_init(void)
{
PRINTFUNC();
file1 = debugfs_create_file(DEV_NAME, 0644, NULL, NULL, &my_fops);
return 0;
}
static void __exit mmapexample_module_exit(void)
{
PRINTFUNC();
debugfs_remove(file1);
}
module_init(mmapexample_module_init);
module_exit(mmapexample_module_exit);
MODULE_AUTHOR("Jose Medina");
MODULE_LICENSE("GPL");
obj-m := mmap_kernel.o
KDIR := /lib/modules/$(shell uname -r)/build
PWD := $(shell pwd)
all:
$(MAKE) -C $(KDIR) SUBDIRS=$(PWD) modules
#include <stdio.h>
#include <string.h>
#include <fcntl.h>
#include <sys/mman.h>
#define PAGE_SIZE 4096
int main(int argc, char** argv)
{
int configfd;
configfd = open("/sys/kernel/debug/mmap_example", O_RDWR);
if (configfd < 0) {
perror("open");
return -1;
}
char* address = NULL;
address = mmap(NULL, PAGE_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, configfd,
0);
if (address == MAP_FAILED) {
perror("mmap");
return -1;
}
printf("initial message: %s\n", address);
memcpy(address + 11 , "*user*", 6);
printf("changed message: %s\n", address);
close(configfd);
return 0;
}
root@debian:/home/user/Documents/mmap
make -C /lib/modules/3.2.0-4-686-pae/build SUBDIRS=/home/user/Documents/mmap modules
make[1]: Entering directory `/usr/src/linux-headers-3.2.0-4-686-pae'
Building modules, stage 2.
MODPOST 1 modules
make[1]: Leaving directory `/usr/src/linux-headers-3.2.0-4-686-pae'
root@debian:/home/user/Documents/mmap
root@debian:/home/user/Documents/mmap
root@debian:/home/user/Documents/mmap
root@debian:/home/user/Documents/mmap
initial message: hello from kernel this is file: mmap_example
changed message: hello from *user* this is file: mmap_example
Apr 14 13:29:03 debian kernel: [14012.052550] mmap_example: mmapexample_module_init called
Apr 14 13:35:29 debian kernel: [14396.556063] mmap_example: my_open called
Apr 14 13:35:29 debian kernel: [14396.556414] mmap_example: my_mmap called
Apr 14 13:35:29 debian kernel: [14396.556997] mmap_example: mmap_fault called
Apr 14 13:35:29 debian kernel: [14396.575186] mmap_example: my_close called