《深入Linux设备驱动程序内核机制》中的mmap_demo.c例程

本文介绍了一个具体的Linux内核模块示例,展示了如何使用mmap进行内存映射,包括驱动代码实现及Makefile配置,还有用户空间程序如何与内核模块交互。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

驱动代码如下:

  1 #include <linux/module.h>
  2 #include <linux/kernel.h>
  3 #include <linux/types.h>
  4 #include <linux/init.h>
  5 #include <linux/errno.h>
  6 #include <linux/sched.h>
  7 
  8 #include <linux/device.h>
  9 #include <linux/cdev.h>
 10 #include <linux/fs.h>
 11 #include <linux/fcntl.h>
 12 #include <linux/gfp.h>
 13 #include <linux/string.h>
 14 #include <linux/mm_types.h>
 15 #include <linux/mm.h>
 16 #include <linux/highmem.h>
 17 #include <linux/timer.h>
 18 
 19 #include <asm/io.h>
 20 #include <asm/system.h>
 21 #include <asm/uaccess.h>
 22 
 23 #define KSTR_DEF "Hello world from kernel virtual space"
 24 
 25 static struct cdev *pcdev;
 26 static dev_t ndev;
 27 static struct page *pg;
 28 static struct timer_list timer;
 29 
 30 static void timer_func(unsigned long data)
 31 {
 32         printk("timer_func:%s\n",(char *)data);
 33         timer.expires = jiffies + HZ*10;
 34         add_timer(&timer);
 35 }
 36 
 37 static int demo_open(struct inode *inode,struct file *filp)
 38 {
 39         return 0;
 40 }
 41 
 42 
 43 static int demo_release(struct inode *inode,struct file *filp)
 44 {
 45         return 0;
 46 }
 47 
 48 static int demo_mmap(struct file *filp,struct vm_area_struct *vma)
 49 {
 50         int err = 0;
 51         unsigned long start = vma->vm_start;
 52         unsigned long size = vma->vm_end - vma->vm_start;
 53 
 54         err = remap_pfn_range(vma,start,vma->vm_pgoff,size,vma->vm_page_prot);
 55         printk("vma->vm_pgoff = 0x%x\n",vma->vm_pgoff);
 56         return err;
 57 }
 58 
 59 static struct file_operations mmap_fops =
 60 {
 61         .owner  = THIS_MODULE,
 62         .open   = demo_open,
 63         .release= demo_release,
 64         .mmap   = demo_mmap,
 65 };
 66 
 67 static demo_map_init(void)
 68 {
 69         int err = 0;
 70         char *kstr;
 71 
 72         pg = alloc_pages(GFP_HIGHUSER,0);
 73         SetPageReserved(pg);
 74 
 75         kstr = (char *)kmap(pg);
 76         strcpy(kstr,KSTR_DEF);
 77         printk("kpa = 0x%x,kernel string = %s\n",page_to_phys(pg),kstr);
 78 
 79         pcdev = cdev_alloc();
 80         cdev_init(pcdev,&mmap_fops);
 81         alloc_chrdev_region(&ndev,0,1,"mmap_dev");
 82         printk("major = %d,minor = %d\n",MAJOR(ndev),MINOR(ndev));
 83         pcdev->owner = THIS_MODULE;
 84         cdev_add(pcdev,ndev,1);
 85 
 86         init_timer(&timer);
 87         timer.function = timer_func;
 88         timer.data = (unsigned long)kstr;
 89         timer.expires = jiffies + HZ*10;
 90         add_timer(&timer);
 91 
 92         return err;
 93 }
 94 
 95 static void demo_map_exit(void)
 96 {
 97         del_timer_sync(&timer);
 98         cdev_del(pcdev);
 99         unregister_chrdev_region(ndev,1);
100         kunmap(pg);
101         ClearPageReserved(pg);
102         __free_pages(pg,0);
103 }
104 
105 module_init(demo_map_init);
106 module_exit(demo_map_exit);

Makefile

 1 export ARCH=x86
 2 export CROSS_COMPILE=
 3 obj-m := mmap_demo.o
 4 KERNELDIR := /lib/modules/$(shell uname -r)/build
 5 PWD := $(shell pwd)
 6 
 7 default:
 8         $(MAKE) -C $(KERNELDIR) M=$(PWD) modules
 9 clean:
10         rm -f *.o *.ko *.mod.*

  注意上面两行,由于我的机器上配置了arm交叉编译,ARCH/CROSS_COMPILE进行了配置,如果编译x86的ko,必须取消之,否则总是提示.h之类的奇怪错误。

应用程序:

 1 #include <stdio.h>
 2 #include <stdlib.h>
 3 #include <string.h>
 4 #include <sys/types.h>
 5 #include <sys/stat.h>
 6 #include <fcntl.h>
 7 #include <unistd.h>
 8 #include <sys/mman.h>
 9 
10 #define MAP_SIZE 4096
11 #define USTR_DEF "String changed from User Space"
12 
13 int main(int argc,char *argv[])
14 {
15         int fd;
16         char *pdata;
17 
18         if(argc <= 1)
19         {
20                 printf("Usage: main devfile pamapped\n");
21                 return 0;
22         }
23         fd = open(argv[1],O_RDWR|O_NDELAY);
24         if(fd < 0)
25                 return -1;
26         pdata = (char *)mmap(0,MAP_SIZE,PROT_READ|PROT_WRITE,MAP_SHARED,
27                                                 fd,strtoul(argv[2],0,16));
28         printf("UserAddr = %p,Data from kernel:%s\n",pdata,pdata);
29         printf("Writing a string to the kernel space...");
30         strcpy(pdata,USTR_DEF);
31         printf("Done\n");
32         munmap(pdata,MAP_SIZE);
33         close(fd);
34         return 0;
35 }

特别注意

mmap最后一个参数:

void *mmap(void *start,size_t length,int prot,int flags,int fd,off_t offset);

offset: 映射文件的位置,一般从头开始。而在设备文件中,表示映射物理地址的起始地址;

kpa = 0x790a4000,kernel string = <NULL>
major = 248,minor = 0
timer_func:Hello world from kernel virtual space
timer_func:Hello world from kernel virtual space
vma->vm_pgoff = 0x790a4//vm_pgoff表示的是物理地址偏移 
timer_func:String changed from User Space

 

 

 

转载于:https://www.cnblogs.com/dzyht/p/3146270.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值