Linux内核模块驱动加载与dmesg调试
因为近期用到了Linux内核的相关知识,下面随笔将给出内核模块的编写记录,供大家参考。
1、运行环境
Ubuntu 版本:20.04
Linux内核版本:5.4.0-42-generic
gcc版本:gcc version 9.3.0
驱动和一般应用程序的执行方式很大不同
2、内核模块模型说明
(1)驱动和一般应用程序的执行方式很大不同
一般应用由main函数开始执行,流程基本由程序自身控制
驱动程序没有main函数,由回调方式驱动运行
(2)回调方式:
先向内核注册函数,然后应用程序触发这些函数的执行
例如:驱动程序在初始化时,向内核注册处理某个设备写操作的函数
当应用程序使用write系统调用写该设备时,内核就会调用注册的上述函数
3、内核模型常见的回调函数举例
(1)DriverInitialize
驱动初始化函数,通过宏静态注册;
$ insmod PrintModule.ko,安装驱动并触发该函数,通常会创建设备对象;
(2)DriverUninitialize
驱动销毁函数,通过宏静态注册;
$ rmmod PrintModule,卸载驱动并触发该函数;
(3)DriverOpen
打开设备函数,动态注册;
应用调用open函数打开设备对象时,会触发该函数;
(4)DriverRead
读设备函数,动态注册;
应用调用read函数读设备时,会触发该函数;
(5)DriverWrite
写设备函数,动态注册;
应用调用write函数写设备时,会触发该函数;
(7)DriverIOControl
设备控制函数,动态注册;
应用调用ioctl函数操作设备时,会触发该函数;
(8)DriverMMap
设备内存映射函数,动态注册;
应用调用mmap函数时,会触发该函数;
下面给出驱动模块编写函数:
4、DriverMain.c
1 #include "DriverMain.h"
2
3 #include "DriverFileOperations.h"
4
5 #include "ToolFunctions.h"
6
7
8
9 MODULE_LICENSE("Dual BSD/GPL");
10
11
12
13 struct SLDriverParameters gslDriverParameters = {0};
14
15
16
17 struct file_operations gslNvmDriverFileOperations =
18
19 {
20
21 .owner = THIS_MODULE,
22
23 .open = DriverOpen,
24
25 .release = DriverClose,
26
27 .read = DriverRead,
28
29 .write = DriverWrite,
30
31 .unlocked_ioctl = DriverIOControl,
32
33 .mmap = DriverMMap,
34
35 };
36
37
38
39 int InitalizeCharDevice(void)
40
41 {
42
43 int result;
44
45 struct device *pdevice;
46
47
48
49 result = alloc_chrdev_region(&(gslDriverParameters.uiDeviceNumber), 0, 1, DEVICE_NAME);
50
51 if(result < 0)
52
53 {
54
55 printk(KERN_ALERT DEVICE_NAME " alloc_chrdev_region error\n");
56
57 return result;
58
59 }
60
61
62
63 gslDriverParameters.pslDriverClass = class_create(THIS_MODULE, DEVICE_NAME);
64
65 if(IS_ERR(gslDriverParameters.pslDriverClass))
66
67 {
68
69 printk(KERN_ALERT DEVICE_NAME " class_create error\n");
70
71
72
73 result = PTR_ERR(gslDriverParameters.pslDriverClass);
74
75 goto CLASS_CREATE_ERROR;
76
77 }
78
79
80
81 cdev_init(&(gslDriverParameters.slCharDevice), &gslNvmDriverFileOperations);
82
83 gslDriverParameters.slCharDevice.owner = THIS_MODULE;
84
85
86
87 result = cdev_add(&(gslDriverParameters.slCharDevice), gslDriverParameters.uiDeviceNumber, 1);
88
89 if(result < 0)
90
91 {
92
93 printk(KERN_ALERT DEVICE_NAME " cdev_add error\n");
94
95 goto CDEV_ADD_ERROR;
96
97 }
98
99
100
101 pdevice = device_create(gslDriverParameters.pslDriverClass, NULL, gslDriverParameters.uiDeviceNumber, NULL, DEVICE_NAME);
102
103 if(IS_ERR(pdevice))
104
105 {
106
107 printk(KERN_ALERT DEVICE_NAME " device_create error\n");
108
109
110
111 result = PTR_ERR(pdevice);
112
113 goto DEVICE_CREATE_ERROR;
114
115 }
116
117
118
119 return 0;
120
121
122
123 DEVICE_CREATE_ERROR:
124
125 cdev_del(&(gslDriverParameters.slCharDevice));
126
127
128
129 CDEV_ADD_ERROR:
130
131 class_destroy(gslDriverParameters.pslDriverClass);
132
133
134
135 CLASS_CREATE_ERROR:
136
137 unregister_chrdev_region(gslDriverParameters.uiDeviceNumber, 1);
138
139
140
141 return result;
142
143 }
144
145
146
147 void UninitialCharDevice(void)
148
149 {
150
151 device_destroy(gslDriverParameters.pslDriverClass, gslDriverParameters.uiDeviceNumber);
152
153
154
155 cdev_del(&(gslDriverParameters.slCharDevice));
156
157
158
159 class_destroy(gslDriverParameters.pslDriverClass);
160
161
162
163 unregister_chrdev_region(gslDriverParameters.uiDeviceNumber, 1);
164
165 }
166
167
168
169 static int DriverInitialize(void)
170
171 {
172
173 DEBUG_PRINT(DEVICE_NAME " Initialize\n");
174
175
176
177 return InitalizeCharDevice();
178
179 }
180
181
182
183 static void DriverUninitialize(void)
184
185 {
186
187 DEBUG_PRINT(DEVICE_NAME " Uninitialize\n");
188
189
190
191 UninitialCharDevice();
192
193 }
194
195
196
197 module_init(DriverInitialize);
198
199 module_exit(DriverUninitialize);
5、DriverMain.h
1 #ifndef DriverMain_H
2
3 #define DriverMain_H
4
5
6
7 #include <linux/init.h>
8
9 #include <linux/module.h>
10
11 #include <asm/mtrr.h>
12
13 #include <linux/device.h>
14
15 #include <linux/mm.h>
16
17 #include <linux/cdev.h>
18
19 #include <linux/slab.h>
20
21
22
23 #define DEVICE_NAME "msg_printer"
24
25
26
27 struct SLDriverParameters
28
29 {
30
31 struct class *pslDriverClass;
32
33 dev_t uiDeviceNumber;
34
35 struct cdev slCharDevice;
36
37 };
38
39
40
41 extern struct SLDriverParameters gslDriverParameters;
42
43
44
45 #endif
6、DriverFileOperations.c
1 #include "DriverMain.h"
2
3 #include "DriverFileOperations.h"
4
5 #include "ToolFunctions.h"
6
7
8
9 MODULE_LICENSE("Dual BSD/GPL");
10
11
12
13 struct SLDriverParameters gslDriverParameters = {0};
14
15
16
17 struct file_operations gslNvmDriverFileOperations =
18
19 {
20
21 .owner = THIS_MODULE,
22
23 .open = DriverOpen,
24
25 .release = DriverClose,
26
27 .read = DriverRead,
28
29 .write = DriverWrite,
30
31 .unlocked_ioctl = DriverIOControl,
32
33 .mmap = DriverMMap,
34
35 };
36
37
38
39 int InitalizeCharDevice(void)
40
41 {
42
43 int result;
44
45 struct device *pdevice;
46
47
48
49 result = alloc_chrdev_region(&(gslDriverParameters.uiDeviceNumber), 0, 1, DEVICE_NAME);
50
51 if(result < 0)
52
53 {
54
55 printk(KERN_ALERT DEVICE_NAME " alloc_chrdev_region error\n");
56
57 return result;
58
59 }
60
61
62
63 gslDriverParameters.pslDriverClass = class_create(THIS_MODULE, DEVICE_NAME);
64
65 if(IS_ERR(gslDriverParameters.pslDriverClass))
66
67 {
68
69 printk(KERN_ALERT DEVICE_NAME " class_create error\n");
70
71
72
73 result = PTR_ERR(gslDriverParameters.pslDriverClass);
74
75 goto CLASS_CREATE_ERROR;
76
77 }
78
79
80
81 cdev_init(&(gslDriverParameters.slCharDevice), &gslNvmDriverFileOperations);
82
83 gslDriverParameters.slCharDevice.owner = THIS_MODULE;
84
85
86
87 result = cdev_add(&(gslDriverParameters.slCharDevice), gslDriverParameters.uiDeviceNumber, 1);
88
89 if(result < 0)
90
91 {
92
93 printk(KERN_ALERT DEVICE_NAME " cdev_add error\n");
94
95 goto CDEV_ADD_ERROR;
96
97 }
98
99
100
101 pdevice = device_create(gslDriverParameters.pslDriverClass, NULL, gslDriverParameters.uiDeviceNumber, NULL, DEVICE_NAME);
102
103 if(IS_ERR(pdevice))
104
105 {
106
107 printk(KERN_ALERT DEVICE_NAME " device_create error\n");
108
109
110
111 result = PTR_ERR(pdevice);
112
113 goto DEVICE_CREATE_ERROR;
114
115 }
116
117
118
119 return 0;
120
121
122
123 DEVICE_CREATE_ERROR:
124
125 cdev_del(&(gslDriverParameters.slCharDevice));
126
127
128
129 CDEV_ADD_ERROR:
130
131 class_destroy(gslDriverParameters.pslDriverClass);
132
133
134
135 CLASS_CREATE_ERROR:
136
137 unregister_chrdev_region(gslDriverParameters.uiDeviceNumber, 1);
138
139
140
141 return result;
142
143 }
144
145
146
147 void UninitialCharDevice(void)
148
149 {
150
151 device_destroy(gslDriverParameters.pslDriverClass, gslDriverParameters.uiDeviceNumber);
152
153
154
155 cdev_del(&(gslDriverParameters.slCharDevice));
156
157
158
159 class_destroy(gslDriverParameters.pslDriverClass);
160
161
162
163 unregister_chrdev_region(gslDriverParameters.uiDeviceNumber, 1);
164
165 }
166
167
168
169 static int DriverInitialize(void)
170
171 {
172
173 DEBUG_PRINT(DEVICE_NAME " Initialize\n");
174
175
176
177 return InitalizeCharDevice();
178
179 }
180
181
182
183 static void DriverUninitialize(void)
184
185 {
186
187 DEBUG_PRINT(DEVICE_NAME " Uninitialize\n");
188
189
190
191 UninitialCharDevice();
192
193 }
194
195
196
197 module_init(DriverInitialize);
198
199 module_exit(DriverUninitialize);
7、DriverFileOperations.h
1 #ifndef DriverFileOperations_H
2
3 #define DriverFileOperations_H
4
5 int DriverOpen(struct inode *pslINode, struct file *pslFileStruct)
6
7 int DriverClose(struct inode *pslINode, struct file *pslFileStruct);
8
9 ssize_t DriverRead(struct file *pslFileStruct, char __user *pBuffer, size_t nCount, loff_t *pOffset);
10
11 ssize_t DriverWrite(struct file *pslFileStruct, const char __user *pBuffer, size_t nCount, loff_t *pOffset);
12
13 long DriverIOControl(struct file *pslFileStruct, unsigned int uiCmd, unsigned long ulArg);
14
15 int DriverMMap(struct file *pslFileStruct, struct vm_area_struct *pslVirtualMemoryArea);
16
17 #endif
8、编译内核模块的MakeFile文件:
1 ifneq ($(KERNELRELEASE),)
2
3 obj-m := PrintModule.o
4
5 PrintModule-objs := DriverMain.o DriverFileOperations.o
6
7 EXTRA_CFLAGS := -DTEST_DEBUG -ggdb -O0
8
9 else
10
11 KERNELDIR ?= /lib/modules/$(shell uname -r)/build
12
13 PWD := $(shell pwd)
14
15 default:
16
17 $(MAKE) -C $(KERNELDIR) M=$(PWD) modules
18
19 rm *.order *.symvers *.mod.c *.o .*.o.cmd .*.cmd .tmp_versions -rf
20
21 endif
9、运行测试
首先运行MakeFile文件,通过终端输入make命令即可,生成PrintModule.ko和PrintModule.mod:
之后加载内核驱动,通过输入$ sudo insmod PrintModule.ko命令,之后查看dmesg查看驱动信息(也可通过输出调试信息的函数printk来进行调试),具体如下:
随之通过输入$ sudo rmmod PrintModule命令来卸载驱动,也是通过dmesg来查看内核驱动信息(也可通过输出调试信息的函数printk来进行调试):
Linux内核模块驱动加载与dmesg调试的更多相关文章
- linux 设备驱动加载的先后顺序
Linux驱动先注册总线,总线上可以先挂device,也可以先挂driver,那么究竟怎么控制先后的顺序呢. 1.初始化宏 Linux系统使用两种方式去加载系统中的模块:动态和静态. 静态加载:将所有 ...
- linux 内核驱动加载过程中 向文件系统中的文件进行读写操作
utils.h 文件: #ifndef __UTILS_H__ #define __UTILS_H__ void a2f(const char *s, ...); #endif utils.c 文件: ...
- linux设备和驱动加载的先后顺序
点击打开链接 Linux驱动先注册总线,总线上可以先挂device,也可以先挂driver,那么究竟怎么控制先后的顺序呢. Linux系统使用两种方式去加载系统中的模块:动态和静态. 静态加载:将所有 ...
- 如何调整Linux内核启动中的驱动初始化顺序-驱动加载优先级
Linux内核为不同驱动的加载顺序对应不同的优先级,定义了一些宏: include\linux\init.h #define pure_initcall(fn) __define_initcall(& ...
- (DT系列四)驱动加载中, 如何取得device tree中的属性
本文以At91rm9200平台为例,从源码实现的角度来分析驱动加载时,Device tree的属性是如何取得的.一:系统级初始化DT_MACHINE_START 主要是定义"struct m ...
- 【转】(DT系列四)驱动加载中, 如何取得device tree中的属性
原文网址:http://www.cnblogs.com/biglucky/p/4057488.html 本文以At91rm9200平台为例,从源码实现的角度来分析驱动加载时,Device tree的属 ...
- linux动态库加载RPATH, RUNPATH
摘自http://gotowqj.iteye.com/blog/1926771 linux动态库加载RPATH, RUNPATH 链接动态库 如何程序在连接时使用了共享库,就必须在运行的时候能够找到共 ...
- 有关Linux ipv6模块加载失败的问题
有关Linux ipv6模块加载失败的问题 同事一个SUSE11sp3环境配置ipv6地址失败,提示不支持IPv6,请求帮助,第一反应是应该ipv6相关内核模块没有加载. 主要检查内容: ...
- linux内核被加载的过程
二,linux内核被加载的过程 一,linux安装时遇到的概念解析 内核必须模块vmlinz(5M左右)不认识硬盘,原本是需要写跟loader中一样的内容,来加载非必要模块. 内核非必要的功能被编译为 ...
随机推荐
- Leetcode(198)-打家劫舍
你是一个专业的小偷,计划偷窃沿街的房屋.每间房内都藏有一定的现金,影响你偷窃的唯一制约因素就是相邻的房屋装有相互连通的防盗系统,如果两间相邻的房屋在同一晚上被小偷闯入,系统会自动报警. 给定一个代表每 ...
- Linux 驱动框架---i2c驱动框架
i2c驱动在Linux通过一个周的学习后发现i2c总线的驱动框架还是和Linux整体的驱动框架是相同的,思想并不特殊比较复杂的内容如i2c核心的内容都是内核驱动框架实现完成的,今天我们暂时只分析驱动开 ...
- vue & this.$router.resolve
vue & this.$router.resolve gotoAutoUpdate (query = {}) { const { href } = this.$router.resolve({ ...
- React Refs All In One
React Refs All In One https://reactjs.org/docs/react-api.html#refs Ref https://reactjs.org/docs/refs ...
- 最新 Apple iPhone 12 价格 All In One
最新 Apple iPhone 12 价格 All In One 美版价格 Apple iPhone 12 mini $699 Apple iPhone 12 $799 Apple iPhone 12 ...
- windows10 WSL
搭建WSL linux下的home目录,映射windows的目录地址 用户家目录 ➜ ~ pwd /home/ajanuw C:\Users\ajanuw\AppData\Local\Packages ...
- CSS 阴影效果
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...
- Baccarat凭什么吸引做市商?2021年将如何发展?
在过去的一年里,基于资金池的AMM自动化做市商几乎统治了所有DeFi活动,他们没有订单簿,而是根据算法曲线提供资产.尽管在流动性和交易方面取得了令人惊叹的成绩,但是其自身具有无常损失.多代币敞口以及低 ...
- RocketMq灰皮书(一)------选型&RocketMQ名词
RocketMq灰皮书(一)------选型&RocketMQ名词 一. MQ选型对比 目前业内常用的MQ框架有一下几种: Kafka RabbitMQ RocketMQ 除此之外,还有Act ...
- 【commons-pool2源码】写前思考
写作的初衷 工作4年多, 一直没有系统的阅读过优秀的开源代码, 所以从今年开始做一些尝试, 阅读源码并且试着将自己的理解以文章的形式输出, 从而达到以下目的: 通过阅读源码提升自身的技术水准, 通过写 ...