本例例化一個字符設備,該設備申請一塊內存,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
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
這段內存中原來的數據hello world from kernel virtual space 變爲了
String changed from the user space
這個例子表示了簡單的mmap設備的使用方法。