因为近期用到了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调试的更多相关文章

  1. linux 设备驱动加载的先后顺序

    Linux驱动先注册总线,总线上可以先挂device,也可以先挂driver,那么究竟怎么控制先后的顺序呢. 1.初始化宏 Linux系统使用两种方式去加载系统中的模块:动态和静态. 静态加载:将所有 ...

  2. linux 内核驱动加载过程中 向文件系统中的文件进行读写操作

    utils.h 文件: #ifndef __UTILS_H__ #define __UTILS_H__ void a2f(const char *s, ...); #endif utils.c 文件: ...

  3. linux设备和驱动加载的先后顺序

    点击打开链接 Linux驱动先注册总线,总线上可以先挂device,也可以先挂driver,那么究竟怎么控制先后的顺序呢. Linux系统使用两种方式去加载系统中的模块:动态和静态. 静态加载:将所有 ...

  4. 如何调整Linux内核启动中的驱动初始化顺序-驱动加载优先级

    Linux内核为不同驱动的加载顺序对应不同的优先级,定义了一些宏: include\linux\init.h #define pure_initcall(fn) __define_initcall(& ...

  5. (DT系列四)驱动加载中, 如何取得device tree中的属性

    本文以At91rm9200平台为例,从源码实现的角度来分析驱动加载时,Device tree的属性是如何取得的.一:系统级初始化DT_MACHINE_START 主要是定义"struct m ...

  6. 【转】(DT系列四)驱动加载中, 如何取得device tree中的属性

    原文网址:http://www.cnblogs.com/biglucky/p/4057488.html 本文以At91rm9200平台为例,从源码实现的角度来分析驱动加载时,Device tree的属 ...

  7. linux动态库加载RPATH, RUNPATH

    摘自http://gotowqj.iteye.com/blog/1926771 linux动态库加载RPATH, RUNPATH 链接动态库 如何程序在连接时使用了共享库,就必须在运行的时候能够找到共 ...

  8. 有关Linux ipv6模块加载失败的问题

    有关Linux ipv6模块加载失败的问题 同事一个SUSE11sp3环境配置ipv6地址失败,提示不支持IPv6,请求帮助,第一反应是应该ipv6相关内核模块没有加载.     主要检查内容:   ...

  9. linux内核被加载的过程

    二,linux内核被加载的过程 一,linux安装时遇到的概念解析 内核必须模块vmlinz(5M左右)不认识硬盘,原本是需要写跟loader中一样的内容,来加载非必要模块. 内核非必要的功能被编译为 ...

随机推荐

  1. JS编程练习:封装insertAfter函数(功能类似于系统insertBefor)

    那么insertAfter()要实现的功能: 在指定的子节点后面插入新的子节点: 1 <body> 2 <div> 3 <p></p> 4 <sp ...

  2. 攻防世界ctf bug

    bug 考查: 逻辑漏洞.文件内容检测绕过 ,文件头是位于文件开头的一段承担一定任务的数据,一般开头标记文件类型,如gif的gif89a,或gif87a, png的x89PNG\x0d\x0a,等等 ...

  3. Apple Watch Series 6 字母图案 (图解教程)

    Apple Watch Series 6 字母图案 (图解教程) Apple Watch Series 6 自定义文字 如何开启 字母图案 solution 1 选择 彩色 表盘️ PS: 该复杂功能 ...

  4. how HTTPS works

    How HTTPS works HTTPS comic tutorials How HTTPS works ...in a comic! https://howhttps.works/ A cat e ...

  5. API 授权 All In One

    API 授权 All In One 身份验证 授权类型 身份验证类型 继承认证 没有认证 API密钥 不记名令牌 基本认证 摘要授权 OAuth 1.0 OAuth 2.0 授权码 隐含的 密码凭证 ...

  6. image cache service

    image cache service 图床 https://images.weserv.nl/ https://github.com/weserv/images meta & referre ...

  7. how to find jobs in the website codes

    how to find jobs in the website codes X-Custom-Heade https://developer.mozilla.org/en-US/docs/Web/AP ...

  8. Make one your own Online Video Recorder by using WebRTC & vanilla javascript

    Make one your own Online Video Recorder by using WebRTC & vanilla javascript Online Video Record ...

  9. React Hooks & react forwardRef hooks & useReducer

    React Hooks & react forwardref hooks & useReducer react how to call child component method i ...

  10. linux cd root directory

    linux cd root directory https://www.cyberciti.biz/faq/how-to-change-directory-in-linux-terminal/ htt ...