本例例化一個字符設備,該設備申請一塊內存,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 $@.o
clean:
rm -rf *.o *~ *.ko* *.order *.symvers *.mod*
測試代碼 test.c
#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設備中的內存頁面地址,打印輸出為
[10392.291764] kpa = 0x6e5ea3000, kernel string = hello world from kernel virtual space
[10392.291912] 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
可知地址為 0x6e5ea3000 然後
sudo ./test.o /dev/mmap_demo 0x6e5ea3000
然後輸出為
USERAddr = 0x7f7c65eb9000, DATA from kernel String changed from the user space
Writing a string to the kernel space...
Done
dmesg的輸出結果為
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