In this example, a character device is used. The device applies for a piece of memory, and file_operations has the MMAP function. In test. C, the MMAP memory can be modified by operating the user memory.
Driver code mmap_demo.c
#include <linux/module.h>#include <linux/kernel.h>#include <linux/init.h>#include <linux/device.h>#include <linux/cdev.h>#include <linux/fs.h>#include <linux/fcntl.h>#include <linux/gfp.h>#include <linux/string.h>#include <linux/mm_types.h>#include <linux/types.h>#include <linux/mm.h>#include <linux/highmem.h>#include <asm/io.h>#include <linux/miscdevice.h>#definemmap_printk(args...) do {printk(KERN_ALERT "MMAP_DEMO " args); } while(0)#defineKSTR_DEF"hello world from kernel virtual space"#definemmap_name"mmap_demo"static struct page *pg;static struct timer_list timer;static voidtimer_func (unsigned long data){ printk ("timer_func:%s\n", (char *) data); timer.expires = jiffies + HZ * 10; add_timer (&timer);}static intdemo_open (struct inode *inode, struct file *filp){ mmap_printk ("mmap_demo device open\n"); return 0;}static intdemo_release (struct inode *inode, struct file *filp){ mmap_printk ("mmap_demo device closed\n"); return 0;}static intdemo_mmap (struct file *filp, struct vm_area_struct *vma){ int err = 0; unsigned long start = vma->vm_start; unsigned long size = vma->vm_end - vma->vm_start; err = remap_pfn_range (vma, start, vma->vm_pgoff, size, vma->vm_page_prot); return err;}static struct file_operations mmap_fops = { .owner = THIS_MODULE, .open = demo_open, .release = demo_release, .mmap = demo_mmap,};static struct miscdevice misc = { .minor = MISC_DYNAMIC_MINOR, .name = mmap_name, .fops = &mmap_fops,};static int __initdemo_map_init (void){ int ret = 0; char *kstr; pg = alloc_pages (GFP_HIGHUSER, 0); SetPageReserved (pg); kstr = (char *) kmap (pg); strcpy (kstr, KSTR_DEF); printk ("kpa = 0x%lx, kernel string = %s\n", page_to_phys (pg), kstr); init_timer (&timer); timer.function = timer_func; timer.data = (unsigned long) kstr; timer.expires = jiffies + HZ * 10; add_timer (&timer); ret = misc_register (&misc); printk ("the mmap miscdevice registered\n"); return ret;}module_init (demo_map_init);static voiddemo_map_exit (void){ del_timer_sync (&timer); misc_deregister (&misc); printk ("the device misc_mmap deregistered\n"); kunmap (pg); ClearPageReserved (pg); __free_pages (pg, 0);}module_exit (demo_map_exit);MODULE_LICENSE ("DUAL BSD/GPL");MODULE_AUTHOR ("BG2BKK");
Makefile
KERNELDIR=/lib/modules/$(shell uname -r)/buildPWD=$(shell pwd)obj-m = mmap_demo.omodules:$(MAKE) -C $(KERNELDIR) M=$(PWD) modulestest: test.cgcc $< -o $@.oclean:rm -rf *.o *~ *.ko* *.order *.symvers *.mod*
Test code
#include <stdio.h>#include <stdlib.h>#include <string.h>#include <sys/types.h>#include <sys/stat.h>#include <fcntl.h>#include <unistd.h>#include <sys/mman.h>#defineMAP_SIZE 4096#defineUSTR_DEF "String changed from the user space"int main(int argc, char *argv[]){int fd;char *pdata;if(argc <= 1){printf("USAGE: main devfile pamapped\n");return 0;}fd = open(argv[1], O_RDWR | O_NDELAY);if(fd >= 0){pdata= (char *)mmap(0, MAP_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, strtoul(argv[2], 0, 16));printf("USERAddr = %p, DATA from kernel %s\n",pdata, pdata);printf("Writing a string to the kernel space...\n");strcpy(pdata, USTR_DEF);printf("Done\n");munmap(pdata, MAP_SIZE);close(fd);}return 0;}
Test process
Make
Make Test
Sudo insmod mmap_demo.ko
Dmesg to view the Memory Page address in the mmap_demo device, and print the output
kpa = 0xc1f0000, kernel string = (null)the mmap miscdevice registered
timer_func:hello world from kernel virtual spacetimer_func:hello world from kernel virtual spacetimer_func:hello world from kernel virtual spacetimer_func:hello world from kernel virtual spacetimer_func:hello world from kernel virtual spacetimer_func:hello world from kernel virtual space
The address is 0xc1f0000.
Then sudo./test. O/dev/mmap_demo 0xc1f0000
Then the output is
USERAddr = 0xb7744000, DATA from kernel hello world from kernel virtual spaceWriting a string to the kernel space...Done
Dmesg output result is
timer_func:hello world from kernel virtual spacetimer_func:hello world from kernel virtual spaceMMAP_DEMO mmap_demo device openMMAP_DEMO mmap_demo device closedtimer_func:String changed from the user spacetimer_func:String changed from the user space
The original data in the memory.
Hello world from kernel virtual space changedString changed from the user space
This example shows how to use a simple MMAP device.