本例例化一个字符设备,该设备申请一块内存,file_operations中有mmap的功能,在测试程序test.c中mmap这块内存,操作这块用户内存即可以修改设备内存
驱动代码 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> #define mmap_printk(args...) do {printk(KERN_ALERT "MMAP_DEMO " args); } while(0) #define KSTR_DEF "hello world from kernel virtual space" #define mmap_name "mmap_demo" static struct page *pg; static struct timer_list timer; static void timer_func (unsigned long data) { printk ("timer_func:%s\n", (char *) data); timer.expires = jiffies + HZ * 10; add_timer (&timer); } static int demo_open (struct inode *inode, struct file *filp) { mmap_printk ("mmap_demo device open\n"); return 0; } static int demo_release (struct inode *inode, struct file *filp) { mmap_printk ("mmap_demo device closed\n"); return 0; } static int demo_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 __init demo_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 void demo_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)/build PWD=$(shell pwd) obj-m = mmap_demo.o modules: $(MAKE) -C $(KERNELDIR) M=$(PWD) modules test: test.c gcc $< -o [email protected] clean: rm -rf *.o *~ *.ko* *.order *.symvers *.mod*
#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> #define MAP_SIZE 4096 #define USTR_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; }
make
make test
sudo insmod mmap_demo.ko
再dmesg查看mmap_demo设备中的内存页面地址,打印输出为
kpa = 0xc1f0000, kernel string = (null) the mmap miscdevice registered
timer_func:hello world from kernel virtual space timer_func:hello world from kernel virtual space timer_func:hello world from kernel virtual space timer_func:hello world from kernel virtual space timer_func:hello world from kernel virtual space timer_func:hello world from kernel virtual space可知地址为0xc1f0000
然后sudo ./test.o /dev/mmap_demo 0xc1f0000
然后输出为
USERAddr = 0xb7744000, DATA from kernel hello world from kernel virtual space Writing a string to the kernel space... Done
timer_func:hello world from kernel virtual space timer_func:hello world from kernel virtual space MMAP_DEMO mmap_demo device open MMAP_DEMO mmap_demo device closed timer_func:String changed from the user space timer_func:String changed from the user space这段内存中原来的数据
hello world from kernel virtual space 变为了String changed from the user space这个例子表示了简单的mmap设备的使用方法。