Linux内核编程与驱动开发实战指南:从入门到精通的完整学习路径
Orion K Lv6

Linux内核编程与驱动开发实战指南:从入门到精通的完整学习路径

Linux内核编程和驱动开发是系统级编程的核心技能,对于嵌入式开发、系统优化和硬件控制具有重要意义。1 3 本文将系统性地介绍Linux内核编程的核心概念、驱动开发技术和实战经验,帮助开发者掌握这一重要技能。

一、Linux内核编程基础

1.1 内核架构概述

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
#!/bin/bash
# Linux内核架构分析脚本

echo "=== Linux内核架构分析 ==="

# 内核版本信息
kernel_info() {
echo "1. 内核版本信息"

# 当前内核版本
echo "当前内核版本:"
uname -r

# 内核编译信息
echo "内核编译信息:"
cat /proc/version

# 内核配置信息
echo "内核配置文件位置:"
ls -la /boot/config-$(uname -r) 2>/dev/null || echo "配置文件不存在"

# 内核模块目录
echo "内核模块目录:"
ls /lib/modules/$(uname -r)/
}

# 内核子系统分析
kernel_subsystems() {
echo "2. 内核子系统分析"

# 进程管理
echo "进程管理信息:"
echo "当前进程数: $(ps aux | wc -l)"
echo "内核线程: $(ps aux | grep '\[.*\]' | wc -l)"

# 内存管理
echo "内存管理信息:"
cat /proc/meminfo | head -10

# 文件系统
echo "已挂载的文件系统:"
mount | grep -E '^/dev' | head -5

# 网络子系统
echo "网络接口信息:"
ip link show | grep -E '^[0-9]+:'

# 设备管理
echo "设备信息:"
echo "字符设备数量: $(ls /dev | grep -v '/' | wc -l)"
echo "块设备数量: $(lsblk | wc -l)"
}

# 内核参数配置
kernel_parameters() {
echo "3. 内核参数配置"

# 重要的内核参数
echo "重要内核参数:"

# 内存相关参数
echo "内存相关参数:"
sysctl vm.swappiness vm.dirty_ratio vm.dirty_background_ratio

# 网络相关参数
echo "网络相关参数:"
sysctl net.core.rmem_max net.core.wmem_max net.ipv4.tcp_congestion_control

# 文件系统相关参数
echo "文件系统相关参数:"
sysctl fs.file-max fs.inotify.max_user_watches

# 内核安全参数
echo "安全相关参数:"
sysctl kernel.randomize_va_space kernel.kptr_restrict
}

kernel_info
kernel_subsystems
kernel_parameters

1.2 内核模块开发基础

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
// hello_module.c - 简单的内核模块示例
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/proc_fs.h>
#include <linux/uaccess.h>
#include <linux/slab.h>

// 模块信息
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Your Name");
MODULE_DESCRIPTION("A simple Linux kernel module");
MODULE_VERSION("1.0");

// 模块参数
static int debug_level = 0;
module_param(debug_level, int, 0644);
MODULE_PARM_DESC(debug_level, "Debug level (0=off, 1=info, 2=debug)");

static char *device_name = "hello_device";
module_param(device_name, charp, 0644);
MODULE_PARM_DESC(device_name, "Device name");

// proc文件系统接口
static struct proc_dir_entry *proc_entry;

/**
* proc_read - proc文件读取函数
* @file: 文件指针
* @buffer: 用户空间缓冲区
* @count: 读取字节数
* @pos: 文件位置
*
* 返回值: 读取的字节数
*/
static ssize_t proc_read(struct file *file, char __user *buffer,
size_t count, loff_t *pos)
{
char *msg;
int len;

if (*pos > 0) {
return 0; // 已经读取完毕
}

msg = kmalloc(256, GFP_KERNEL);
if (!msg) {
return -ENOMEM;
}

len = snprintf(msg, 256,
"Hello from kernel module!\n"
"Device name: %s\n"
"Debug level: %d\n"
"Module loaded at: %lu\n",
device_name, debug_level, jiffies);

if (count < len) {
kfree(msg);
return -EINVAL;
}

if (copy_to_user(buffer, msg, len)) {
kfree(msg);
return -EFAULT;
}

*pos += len;
kfree(msg);

if (debug_level >= 1) {
printk(KERN_INFO "hello_module: proc_read called, returned %d bytes\n", len);
}

return len;
}

/**
* proc_write - proc文件写入函数
* @file: 文件指针
* @buffer: 用户空间缓冲区
* @count: 写入字节数
* @pos: 文件位置
*
* 返回值: 写入的字节数
*/
static ssize_t proc_write(struct file *file, const char __user *buffer,
size_t count, loff_t *pos)
{
char *data;

if (count > 256) {
return -EINVAL;
}

data = kmalloc(count + 1, GFP_KERNEL);
if (!data) {
return -ENOMEM;
}

if (copy_from_user(data, buffer, count)) {
kfree(data);
return -EFAULT;
}

data[count] = '\0';

if (debug_level >= 1) {
printk(KERN_INFO "hello_module: received data: %s\n", data);
}

// 简单的命令处理
if (strncmp(data, "debug=", 6) == 0) {
int new_level;
if (kstrtoint(data + 6, 10, &new_level) == 0) {
debug_level = new_level;
printk(KERN_INFO "hello_module: debug level set to %d\n", debug_level);
}
}

kfree(data);
return count;
}

// proc文件操作结构
static const struct proc_ops proc_fops = {
.proc_read = proc_read,
.proc_write = proc_write,
};

/**
* hello_init - 模块初始化函数
*
* 返回值: 0表示成功,负值表示失败
*/
static int __init hello_init(void)
{
printk(KERN_INFO "hello_module: Loading module...\n");
printk(KERN_INFO "hello_module: Device name: %s\n", device_name);
printk(KERN_INFO "hello_module: Debug level: %d\n", debug_level);

// 创建proc文件
proc_entry = proc_create("hello_module", 0666, NULL, &proc_fops);
if (!proc_entry) {
printk(KERN_ERR "hello_module: Failed to create proc entry\n");
return -ENOMEM;
}

printk(KERN_INFO "hello_module: Module loaded successfully\n");
printk(KERN_INFO "hello_module: Use 'cat /proc/hello_module' to read\n");
printk(KERN_INFO "hello_module: Use 'echo data > /proc/hello_module' to write\n");

return 0;
}

/**
* hello_exit - 模块清理函数
*/
static void __exit hello_exit(void)
{
printk(KERN_INFO "hello_module: Unloading module...\n");

// 删除proc文件
if (proc_entry) {
proc_remove(proc_entry);
printk(KERN_INFO "hello_module: Proc entry removed\n");
}

printk(KERN_INFO "hello_module: Module unloaded successfully\n");
}

// 注册模块初始化和清理函数
module_init(hello_init);
module_exit(hello_exit);

1.3 内核模块编译和管理

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
# Makefile for hello_module

# 内核模块对象
obj-m := hello_module.o

# 内核源码目录
KDIR := /lib/modules/$(shell uname -r)/build

# 当前目录
PWD := $(shell pwd)

# 默认目标
all:
$(MAKE) -C $(KDIR) M=$(PWD) modules

# 清理目标
clean:
$(MAKE) -C $(KDIR) M=$(PWD) clean

# 安装模块
install:
$(MAKE) -C $(KDIR) M=$(PWD) modules_install

# 加载模块
load:
insmod hello_module.ko

# 卸载模块
unload:
rmmod hello_module

# 查看模块信息
info:
modinfo hello_module.ko

# 查看内核日志
log:
dmesg | tail -20

.PHONY: all clean install load unload info log
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
#!/bin/bash
# 内核模块管理脚本

echo "=== 内核模块管理工具 ==="

# 模块编译函数
compile_module() {
echo "1. 编译内核模块"

if [ ! -f "Makefile" ]; then
echo "错误: 未找到Makefile"
return 1
fi

echo "开始编译模块..."
make clean
make

if [ $? -eq 0 ]; then
echo "模块编译成功"
ls -la *.ko 2>/dev/null
else
echo "模块编译失败"
return 1
fi
}

# 模块加载函数
load_module() {
local module_name=$1

if [ -z "$module_name" ]; then
echo "用法: load_module <模块名>"
return 1
fi

echo "2. 加载内核模块: $module_name"

# 检查模块文件是否存在
if [ ! -f "${module_name}.ko" ]; then
echo "错误: 模块文件 ${module_name}.ko 不存在"
return 1
fi

# 检查模块是否已加载
if lsmod | grep -q "^${module_name} "; then
echo "模块 $module_name 已经加载"
return 0
fi

# 加载模块
echo "正在加载模块 $module_name..."
sudo insmod "${module_name}.ko"

if [ $? -eq 0 ]; then
echo "模块加载成功"
lsmod | grep "^${module_name} "
else
echo "模块加载失败"
return 1
fi
}

# 模块卸载函数
unload_module() {
local module_name=$1

if [ -z "$module_name" ]; then
echo "用法: unload_module <模块名>"
return 1
fi

echo "3. 卸载内核模块: $module_name"

# 检查模块是否已加载
if ! lsmod | grep -q "^${module_name} "; then
echo "模块 $module_name 未加载"
return 0
fi

# 卸载模块
echo "正在卸载模块 $module_name..."
sudo rmmod "$module_name"

if [ $? -eq 0 ]; then
echo "模块卸载成功"
else
echo "模块卸载失败"
return 1
fi
}

# 模块信息查看
module_info() {
local module_name=$1

if [ -z "$module_name" ]; then
echo "用法: module_info <模块名>"
return 1
fi

echo "4. 模块信息查看: $module_name"

# 模块文件信息
if [ -f "${module_name}.ko" ]; then
echo "模块文件信息:"
modinfo "${module_name}.ko"
fi

# 已加载模块信息
if lsmod | grep -q "^${module_name} "; then
echo "已加载模块信息:"
lsmod | grep "^${module_name} "

# 模块参数
if [ -d "/sys/module/${module_name}/parameters" ]; then
echo "模块参数:"
ls -la "/sys/module/${module_name}/parameters/"
fi
fi
}

# 内核日志查看
view_kernel_log() {
echo "5. 内核日志查看"

echo "最近的内核消息:"
dmesg | tail -20

echo "模块相关消息:"
dmesg | grep -i "module\|insmod\|rmmod" | tail -10
}

# 主函数
main() {
case $1 in
"compile")
compile_module
;;
"load")
load_module $2
;;
"unload")
unload_module $2
;;
"info")
module_info $2
;;
"log")
view_kernel_log
;;
"all")
compile_module
load_module hello_module
module_info hello_module
view_kernel_log
;;
*)
echo "用法: $0 {compile|load|unload|info|log|all} [模块名]"
echo "示例:"
echo " $0 compile # 编译模块"
echo " $0 load hello_module # 加载模块"
echo " $0 unload hello_module # 卸载模块"
echo " $0 info hello_module # 查看模块信息"
echo " $0 log # 查看内核日志"
echo " $0 all # 执行完整流程"
;;
esac
}

main $@

二、字符设备驱动开发

2.1 字符设备驱动框架

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
// char_device.c - 字符设备驱动示例
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/uaccess.h>
#include <linux/slab.h>
#include <linux/mutex.h>
#include <linux/wait.h>
#include <linux/sched.h>

// 模块信息
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Your Name");
MODULE_DESCRIPTION("Character device driver example");
MODULE_VERSION("1.0");

// 设备相关定义
#define DEVICE_NAME "char_dev"
#define CLASS_NAME "char_class"
#define BUFFER_SIZE 1024

// 设备结构体
struct char_device {
dev_t dev_num; // 设备号
struct cdev cdev; // 字符设备结构
struct class *dev_class; // 设备类
struct device *device; // 设备
char *buffer; // 数据缓冲区
size_t buffer_size; // 缓冲区大小
size_t data_size; // 当前数据大小
struct mutex mutex; // 互斥锁
wait_queue_head_t read_queue; // 读等待队列
wait_queue_head_t write_queue; // 写等待队列
bool data_available; // 数据可用标志
};

static struct char_device *char_dev;

/**
* char_dev_open - 设备打开函数
* @inode: inode结构指针
* @file: 文件结构指针
*
* 返回值: 0表示成功,负值表示失败
*/
static int char_dev_open(struct inode *inode, struct file *file)
{
struct char_device *dev;

printk(KERN_INFO "char_dev: Device opened\n");

// 获取设备结构
dev = container_of(inode->i_cdev, struct char_device, cdev);
file->private_data = dev;

return 0;
}

/**
* char_dev_release - 设备关闭函数
* @inode: inode结构指针
* @file: 文件结构指针
*
* 返回值: 0表示成功
*/
static int char_dev_release(struct inode *inode, struct file *file)
{
printk(KERN_INFO "char_dev: Device closed\n");
return 0;
}

/**
* char_dev_read - 设备读取函数
* @file: 文件结构指针
* @buffer: 用户空间缓冲区
* @count: 读取字节数
* @pos: 文件位置指针
*
* 返回值: 实际读取的字节数,负值表示错误
*/
static ssize_t char_dev_read(struct file *file, char __user *buffer,
size_t count, loff_t *pos)
{
struct char_device *dev = file->private_data;
ssize_t bytes_read = 0;

printk(KERN_INFO "char_dev: Read request for %zu bytes\n", count);

// 获取互斥锁
if (mutex_lock_interruptible(&dev->mutex)) {
return -ERESTARTSYS;
}

// 等待数据可用
while (!dev->data_available) {
mutex_unlock(&dev->mutex);

if (file->f_flags & O_NONBLOCK) {
return -EAGAIN;
}

printk(KERN_INFO "char_dev: Waiting for data...\n");
if (wait_event_interruptible(dev->read_queue, dev->data_available)) {
return -ERESTARTSYS;
}

if (mutex_lock_interruptible(&dev->mutex)) {
return -ERESTARTSYS;
}
}

// 计算实际读取字节数
bytes_read = min(count, dev->data_size);

// 复制数据到用户空间
if (copy_to_user(buffer, dev->buffer, bytes_read)) {
mutex_unlock(&dev->mutex);
return -EFAULT;
}

// 更新缓冲区
if (bytes_read < dev->data_size) {
memmove(dev->buffer, dev->buffer + bytes_read,
dev->data_size - bytes_read);
dev->data_size -= bytes_read;
} else {
dev->data_size = 0;
dev->data_available = false;
}

mutex_unlock(&dev->mutex);

// 唤醒写等待队列
wake_up_interruptible(&dev->write_queue);

printk(KERN_INFO "char_dev: Read %zd bytes\n", bytes_read);
return bytes_read;
}

/**
* char_dev_write - 设备写入函数
* @file: 文件结构指针
* @buffer: 用户空间缓冲区
* @count: 写入字节数
* @pos: 文件位置指针
*
* 返回值: 实际写入的字节数,负值表示错误
*/
static ssize_t char_dev_write(struct file *file, const char __user *buffer,
size_t count, loff_t *pos)
{
struct char_device *dev = file->private_data;
ssize_t bytes_written = 0;

printk(KERN_INFO "char_dev: Write request for %zu bytes\n", count);

// 获取互斥锁
if (mutex_lock_interruptible(&dev->mutex)) {
return -ERESTARTSYS;
}

// 等待缓冲区有空间
while (dev->data_size >= dev->buffer_size) {
mutex_unlock(&dev->mutex);

if (file->f_flags & O_NONBLOCK) {
return -EAGAIN;
}

printk(KERN_INFO "char_dev: Waiting for buffer space...\n");
if (wait_event_interruptible(dev->write_queue,
dev->data_size < dev->buffer_size)) {
return -ERESTARTSYS;
}

if (mutex_lock_interruptible(&dev->mutex)) {
return -ERESTARTSYS;
}
}

// 计算实际写入字节数
bytes_written = min(count, dev->buffer_size - dev->data_size);

// 从用户空间复制数据
if (copy_from_user(dev->buffer + dev->data_size, buffer, bytes_written)) {
mutex_unlock(&dev->mutex);
return -EFAULT;
}

// 更新数据大小和状态
dev->data_size += bytes_written;
dev->data_available = true;

mutex_unlock(&dev->mutex);

// 唤醒读等待队列
wake_up_interruptible(&dev->read_queue);

printk(KERN_INFO "char_dev: Written %zd bytes\n", bytes_written);
return bytes_written;
}

/**
* char_dev_ioctl - 设备控制函数
* @file: 文件结构指针
* @cmd: 控制命令
* @arg: 命令参数
*
* 返回值: 0表示成功,负值表示失败
*/
static long char_dev_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
struct char_device *dev = file->private_data;

printk(KERN_INFO "char_dev: IOCTL command: %u\n", cmd);

switch (cmd) {
case 0: // 清空缓冲区
if (mutex_lock_interruptible(&dev->mutex)) {
return -ERESTARTSYS;
}
dev->data_size = 0;
dev->data_available = false;
mutex_unlock(&dev->mutex);
wake_up_interruptible(&dev->write_queue);
printk(KERN_INFO "char_dev: Buffer cleared\n");
break;

case 1: // 获取缓冲区大小
if (copy_to_user((void __user *)arg, &dev->buffer_size, sizeof(size_t))) {
return -EFAULT;
}
break;

case 2: // 获取当前数据大小
if (copy_to_user((void __user *)arg, &dev->data_size, sizeof(size_t))) {
return -EFAULT;
}
break;

default:
return -ENOTTY;
}

return 0;
}

// 文件操作结构
static const struct file_operations char_dev_fops = {
.owner = THIS_MODULE,
.open = char_dev_open,
.release = char_dev_release,
.read = char_dev_read,
.write = char_dev_write,
.unlocked_ioctl = char_dev_ioctl,
};

/**
* char_dev_init - 模块初始化函数
*
* 返回值: 0表示成功,负值表示失败
*/
static int __init char_dev_init(void)
{
int ret;

printk(KERN_INFO "char_dev: Initializing character device driver\n");

// 分配设备结构
char_dev = kzalloc(sizeof(struct char_device), GFP_KERNEL);
if (!char_dev) {
printk(KERN_ERR "char_dev: Failed to allocate device structure\n");
return -ENOMEM;
}

// 分配缓冲区
char_dev->buffer = kzalloc(BUFFER_SIZE, GFP_KERNEL);
if (!char_dev->buffer) {
printk(KERN_ERR "char_dev: Failed to allocate buffer\n");
ret = -ENOMEM;
goto err_buffer;
}

char_dev->buffer_size = BUFFER_SIZE;
char_dev->data_size = 0;
char_dev->data_available = false;

// 初始化同步原语
mutex_init(&char_dev->mutex);
init_waitqueue_head(&char_dev->read_queue);
init_waitqueue_head(&char_dev->write_queue);

// 分配设备号
ret = alloc_chrdev_region(&char_dev->dev_num, 0, 1, DEVICE_NAME);
if (ret < 0) {
printk(KERN_ERR "char_dev: Failed to allocate device number\n");
goto err_chrdev;
}

printk(KERN_INFO "char_dev: Device number allocated: %d:%d\n",
MAJOR(char_dev->dev_num), MINOR(char_dev->dev_num));

// 初始化字符设备
cdev_init(&char_dev->cdev, &char_dev_fops);
char_dev->cdev.owner = THIS_MODULE;

// 添加字符设备
ret = cdev_add(&char_dev->cdev, char_dev->dev_num, 1);
if (ret < 0) {
printk(KERN_ERR "char_dev: Failed to add character device\n");
goto err_cdev;
}

// 创建设备类
char_dev->dev_class = class_create(THIS_MODULE, CLASS_NAME);
if (IS_ERR(char_dev->dev_class)) {
printk(KERN_ERR "char_dev: Failed to create device class\n");
ret = PTR_ERR(char_dev->dev_class);
goto err_class;
}

// 创建设备文件
char_dev->device = device_create(char_dev->dev_class, NULL,
char_dev->dev_num, NULL, DEVICE_NAME);
if (IS_ERR(char_dev->device)) {
printk(KERN_ERR "char_dev: Failed to create device\n");
ret = PTR_ERR(char_dev->device);
goto err_device;
}

printk(KERN_INFO "char_dev: Character device driver loaded successfully\n");
printk(KERN_INFO "char_dev: Device file: /dev/%s\n", DEVICE_NAME);

return 0;

err_device:
class_destroy(char_dev->dev_class);
err_class:
cdev_del(&char_dev->cdev);
err_cdev:
unregister_chrdev_region(char_dev->dev_num, 1);
err_chrdev:
kfree(char_dev->buffer);
err_buffer:
kfree(char_dev);
return ret;
}

/**
* char_dev_exit - 模块清理函数
*/
static void __exit char_dev_exit(void)
{
printk(KERN_INFO "char_dev: Unloading character device driver\n");

if (char_dev) {
// 删除设备文件
if (char_dev->device) {
device_destroy(char_dev->dev_class, char_dev->dev_num);
}

// 删除设备类
if (char_dev->dev_class) {
class_destroy(char_dev->dev_class);
}

// 删除字符设备
cdev_del(&char_dev->cdev);

// 释放设备号
unregister_chrdev_region(char_dev->dev_num, 1);

// 释放缓冲区
if (char_dev->buffer) {
kfree(char_dev->buffer);
}

// 释放设备结构
kfree(char_dev);
}

printk(KERN_INFO "char_dev: Character device driver unloaded\n");
}

module_init(char_dev_init);
module_exit(char_dev_exit);

2.2 设备测试程序

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
// test_char_dev.c - 字符设备测试程序
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <errno.h>
#include <pthread.h>

#define DEVICE_PATH "/dev/char_dev"
#define BUFFER_SIZE 1024

/**
* 读取线程函数
* @arg: 线程参数(文件描述符)
*
* 返回值: NULL
*/
void *read_thread(void *arg)
{
int fd = *(int *)arg;
char buffer[BUFFER_SIZE];
ssize_t bytes_read;
int count = 0;

printf("读取线程启动\n");

while (count < 5) {
bytes_read = read(fd, buffer, sizeof(buffer) - 1);
if (bytes_read > 0) {
buffer[bytes_read] = '\0';
printf("读取线程: 读取了 %zd 字节: %s\n", bytes_read, buffer);
count++;
} else if (bytes_read == 0) {
printf("读取线程: 到达文件末尾\n");
break;
} else {
perror("读取线程: 读取失败");
break;
}

sleep(1);
}

printf("读取线程结束\n");
return NULL;
}

/**
* 写入线程函数
* @arg: 线程参数(文件描述符)
*
* 返回值: NULL
*/
void *write_thread(void *arg)
{
int fd = *(int *)arg;
char buffer[256];
ssize_t bytes_written;
int i;

printf("写入线程启动\n");

for (i = 0; i < 5; i++) {
snprintf(buffer, sizeof(buffer), "消息 %d: 这是来自写入线程的测试数据\n", i + 1);

bytes_written = write(fd, buffer, strlen(buffer));
if (bytes_written > 0) {
printf("写入线程: 写入了 %zd 字节\n", bytes_written);
} else {
perror("写入线程: 写入失败");
break;
}

sleep(2);
}

printf("写入线程结束\n");
return NULL;
}

/**
* 测试基本读写功能
* @fd: 设备文件描述符
*/
void test_basic_io(int fd)
{
char write_buffer[] = "Hello, Character Device!";
char read_buffer[BUFFER_SIZE];
ssize_t bytes_written, bytes_read;

printf("\n=== 基本读写测试 ===\n");

// 写入测试
printf("写入数据: %s\n", write_buffer);
bytes_written = write(fd, write_buffer, strlen(write_buffer));
if (bytes_written > 0) {
printf("成功写入 %zd 字节\n", bytes_written);
} else {
perror("写入失败");
return;
}

// 读取测试
printf("读取数据...\n");
bytes_read = read(fd, read_buffer, sizeof(read_buffer) - 1);
if (bytes_read > 0) {
read_buffer[bytes_read] = '\0';
printf("成功读取 %zd 字节: %s\n", bytes_read, read_buffer);
} else {
perror("读取失败");
}
}

/**
* 测试IOCTL功能
* @fd: 设备文件描述符
*/
void test_ioctl(int fd)
{
size_t buffer_size, data_size;
int ret;

printf("\n=== IOCTL测试 ===\n");

// 获取缓冲区大小
ret = ioctl(fd, 1, &buffer_size);
if (ret == 0) {
printf("缓冲区大小: %zu 字节\n", buffer_size);
} else {
perror("获取缓冲区大小失败");
}

// 获取当前数据大小
ret = ioctl(fd, 2, &data_size);
if (ret == 0) {
printf("当前数据大小: %zu 字节\n", data_size);
} else {
perror("获取数据大小失败");
}

// 清空缓冲区
ret = ioctl(fd, 0, 0);
if (ret == 0) {
printf("缓冲区已清空\n");
} else {
perror("清空缓冲区失败");
}

// 再次获取数据大小
ret = ioctl(fd, 2, &data_size);
if (ret == 0) {
printf("清空后数据大小: %zu 字节\n", data_size);
} else {
perror("获取数据大小失败");
}
}

/**
* 测试多线程访问
* @fd: 设备文件描述符
*/
void test_multithreaded(int fd)
{
pthread_t read_tid, write_tid;
int ret;

printf("\n=== 多线程测试 ===\n");

// 创建读取线程
ret = pthread_create(&read_tid, NULL, read_thread, &fd);
if (ret != 0) {
fprintf(stderr, "创建读取线程失败: %s\n", strerror(ret));
return;
}

// 创建写入线程
ret = pthread_create(&write_tid, NULL, write_thread, &fd);
if (ret != 0) {
fprintf(stderr, "创建写入线程失败: %s\n", strerror(ret));
pthread_cancel(read_tid);
return;
}

// 等待线程结束
pthread_join(write_tid, NULL);
pthread_join(read_tid, NULL);

printf("多线程测试完成\n");
}

/**
* 主函数
*/
int main(int argc, char *argv[])
{
int fd;

printf("字符设备驱动测试程序\n");
printf("设备路径: %s\n", DEVICE_PATH);

// 打开设备文件
fd = open(DEVICE_PATH, O_RDWR);
if (fd < 0) {
perror("打开设备文件失败");
printf("请确保:\n");
printf("1. 内核模块已加载 (lsmod | grep char_dev)\n");
printf("2. 设备文件存在 (ls -l %s)\n", DEVICE_PATH);
printf("3. 有足够的权限访问设备文件\n");
return EXIT_FAILURE;
}

printf("设备文件打开成功\n");

// 执行各种测试
test_basic_io(fd);
test_ioctl(fd);
test_multithreaded(fd);

// 关闭设备文件
close(fd);
printf("\n测试完成,设备文件已关闭\n");

return EXIT_SUCCESS;
}

三、平台驱动框架

3.1 Platform设备和驱动

4 5 Platform驱动框架是Linux内核中用于管理不能被自动发现的设备的重要机制,特别适用于嵌入式系统中的片上设备。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
// platform_driver.c - Platform驱动示例
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/platform_device.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/io.h>
#include <linux/interrupt.h>
#include <linux/gpio.h>
#include <linux/clk.h>
#include <linux/regulator/consumer.h>

// 模块信息
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Your Name");
MODULE_DESCRIPTION("Platform driver example");
MODULE_VERSION("1.0");

// 设备私有数据结构
struct my_platform_device {
void __iomem *base; // 内存映射基地址
struct clk *clk; // 时钟
struct regulator *regulator; // 电源调节器
int irq; // 中断号
int gpio_pin; // GPIO引脚
struct device *dev; // 设备指针
};

/**
* my_platform_irq_handler - 中断处理函数
* @irq: 中断号
* @dev_id: 设备ID
*
* 返回值: IRQ_HANDLED表示中断已处理
*/
static irqreturn_t my_platform_irq_handler(int irq, void *dev_id)
{
struct my_platform_device *pdev = dev_id;

dev_info(pdev->dev, "Interrupt %d received\n", irq);

// 处理中断逻辑
// ...

return IRQ_HANDLED;
}

/**
* my_platform_probe - 设备探测函数
* @pdev: platform设备指针
*
* 返回值: 0表示成功,负值表示失败
*/
static int my_platform_probe(struct platform_device *pdev)
{
struct my_platform_device *my_dev;
struct resource *res;
int ret;

dev_info(&pdev->dev, "Probing platform device\n");

// 分配私有数据结构
my_dev = devm_kzalloc(&pdev->dev, sizeof(*my_dev), GFP_KERNEL);
if (!my_dev) {
dev_err(&pdev->dev, "Failed to allocate memory\n");
return -ENOMEM;
}

my_dev->dev = &pdev->dev;
platform_set_drvdata(pdev, my_dev);

// 获取内存资源
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res) {
dev_err(&pdev->dev, "No memory resource found\n");
return -ENODEV;
}

// 映射内存
my_dev->base = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(my_dev->base)) {
dev_err(&pdev->dev, "Failed to map memory\n");
return PTR_ERR(my_dev->base);
}

dev_info(&pdev->dev, "Memory mapped at 0x%px (physical: 0x%llx)\n",
my_dev->base, (unsigned long long)res->start);

// 获取中断资源
my_dev->irq = platform_get_irq(pdev, 0);
if (my_dev->irq > 0) {
ret = devm_request_irq(&pdev->dev, my_dev->irq,
my_platform_irq_handler,
IRQF_TRIGGER_RISING,
dev_name(&pdev->dev), my_dev);
if (ret) {
dev_err(&pdev->dev, "Failed to request IRQ %d\n", my_dev->irq);
return ret;
}
dev_info(&pdev->dev, "IRQ %d registered\n", my_dev->irq);
} else {
dev_info(&pdev->dev, "No IRQ resource found\n");
}

// 获取时钟
my_dev->clk = devm_clk_get(&pdev->dev, "my_clk");
if (IS_ERR(my_dev->clk)) {
if (PTR_ERR(my_dev->clk) == -EPROBE_DEFER) {
dev_info(&pdev->dev, "Clock not ready, deferring probe\n");
return -EPROBE_DEFER;
}
dev_warn(&pdev->dev, "Failed to get clock: %ld\n", PTR_ERR(my_dev->clk));
my_dev->clk = NULL;
} else {
ret = clk_prepare_enable(my_dev->clk);
if (ret) {
dev_err(&pdev->dev, "Failed to enable clock\n");
return ret;
}
dev_info(&pdev->dev, "Clock enabled\n");
}

// 获取电源调节器
my_dev->regulator = devm_regulator_get(&pdev->dev, "vdd");
if (IS_ERR(my_dev->regulator)) {
if (PTR_ERR(my_dev->regulator) == -EPROBE_DEFER) {
dev_info(&pdev->dev, "Regulator not ready, deferring probe\n");
ret = -EPROBE_DEFER;
goto err_clk;
}
dev_warn(&pdev->dev, "Failed to get regulator: %ld\n",
PTR_ERR(my_dev->regulator));
my_dev->regulator = NULL;
} else {
ret = regulator_enable(my_dev->regulator);
if (ret) {
dev_err(&pdev->dev, "Failed to enable regulator\n");
goto err_clk;
}
dev_info(&pdev->dev, "Regulator enabled\n");
}

// 获取GPIO
my_dev->gpio_pin = of_get_named_gpio(pdev->dev.of_node, "control-gpios", 0);
if (gpio_is_valid(my_dev->gpio_pin)) {
ret = devm_gpio_request_one(&pdev->dev, my_dev->gpio_pin,
GPIOF_OUT_INIT_LOW, "my_platform_gpio");
if (ret) {
dev_err(&pdev->dev, "Failed to request GPIO %d\n", my_dev->gpio_pin);
goto err_regulator;
}
dev_info(&pdev->dev, "GPIO %d configured\n", my_dev->gpio_pin);
} else {
dev_info(&pdev->dev, "No valid GPIO found\n");
}

// 设备初始化完成
dev_info(&pdev->dev, "Platform device probed successfully\n");

return 0;

err_regulator:
if (my_dev->regulator)
regulator_disable(my_dev->regulator);
err_clk:
if (my_dev->clk)
clk_disable_unprepare(my_dev->clk);

return ret;
}

/**
* my_platform_remove - 设备移除函数
* @pdev: platform设备指针
*
* 返回值: 0表示成功
*/
static int my_platform_remove(struct platform_device *pdev)
{
struct my_platform_device *my_dev = platform_get_drvdata(pdev);

dev_info(&pdev->dev, "Removing platform device\n");

// 禁用GPIO
if (gpio_is_valid(my_dev->gpio_pin)) {
gpio_set_value(my_dev->gpio_pin, 0);
dev_info(&pdev->dev, "GPIO %d disabled\n", my_dev->gpio_pin);
}

// 禁用电源调节器
if (my_dev->regulator) {
regulator_disable(my_dev->regulator);
dev_info(&pdev->dev, "Regulator disabled\n");
}

// 禁用时钟
if (my_dev->clk) {
clk_disable_unprepare(my_dev->clk);
dev_info(&pdev->dev, "Clock disabled\n");
}

dev_info(&pdev->dev, "Platform device removed successfully\n");

return 0;
}

// 设备树匹配表
static const struct of_device_id my_platform_of_match[] = {
{ .compatible = "my-company,my-platform-device" },
{ .compatible = "my-company,my-platform-device-v2" },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, my_platform_of_match);

// Platform驱动结构
static struct platform_driver my_platform_driver = {
.probe = my_platform_probe,
.remove = my_platform_remove,
.driver = {
.name = "my-platform-driver",
.of_match_table = my_platform_of_match,
},
};

/**
* my_platform_init - 模块初始化函数
*
* 返回值: 0表示成功,负值表示失败
*/
static int __init my_platform_init(void)
{
int ret;

printk(KERN_INFO "my_platform: Registering platform driver\n");

ret = platform_driver_register(&my_platform_driver);
if (ret) {
printk(KERN_ERR "my_platform: Failed to register platform driver\n");
return ret;
}

printk(KERN_INFO "my_platform: Platform driver registered successfully\n");
return 0;
}

/**
* my_platform_exit - 模块清理函数
*/
static void __exit my_platform_exit(void)
{
printk(KERN_INFO "my_platform: Unregistering platform driver\n");
platform_driver_unregister(&my_platform_driver);
printk(KERN_INFO "my_platform: Platform driver unregistered\n");
}

module_init(my_platform_init);
module_exit(my_platform_exit);

3.2 设备树配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
// my-platform-device.dts - 设备树配置示例
/dts-v1/;

/ {
model = "My Platform Device Example";
compatible = "my-company,my-board";

// 时钟定义
clocks {
my_clk: my_clock {
compatible = "fixed-clock";
#clock-cells = <0>;
clock-frequency = <100000000>; // 100MHz
clock-output-names = "my_clk";
};
};

// 电源调节器定义
regulators {
vdd_supply: vdd_regulator {
compatible = "regulator-fixed";
regulator-name = "vdd";
regulator-min-microvolt = <3300000>;
regulator-max-microvolt = <3300000>;
regulator-always-on;
regulator-boot-on;
};
};

// 平台设备定义
my_platform_device: my-device@40000000 {
compatible = "my-company,my-platform-device";
reg = <0x40000000 0x1000>; // 内存映射地址和大小
interrupts = <0 32 4>; // 中断配置
clocks = <&my_clk>;
clock-names = "my_clk";
vdd-supply = <&vdd_supply>;
control-gpios = <&gpio1 10 0>; // GPIO配置

// 设备特定属性
my-property = <42>;
my-string-property = "example";
my-boolean-property;

status = "okay";
};

// GPIO控制器定义(示例)
gpio1: gpio@40020000 {
compatible = "my-company,gpio-controller";
reg = <0x40020000 0x1000>;
gpio-controller;
#gpio-cells = <2>;
ngpios = <32>;
};
};

3.3 设备树解析工具

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
#!/bin/bash
# 设备树分析和调试脚本

echo "=== 设备树分析工具 ==="

# 设备树信息查看
device_tree_info() {
echo "1. 设备树基本信息"

# 设备树文件位置
echo "设备树文件位置:"
ls -la /sys/firmware/devicetree/base/ 2>/dev/null || echo "设备树不可用"

# 设备树模型信息
if [ -f "/sys/firmware/devicetree/base/model" ]; then
echo "设备模型: $(cat /sys/firmware/devicetree/base/model)"
fi

if [ -f "/sys/firmware/devicetree/base/compatible" ]; then
echo "兼容性: $(cat /sys/firmware/devicetree/base/compatible | tr '\0' ' ')"
fi

# 内存信息
if [ -d "/sys/firmware/devicetree/base/memory" ]; then
echo "内存节点存在"
find /sys/firmware/devicetree/base/memory* -name "reg" -exec xxd {} \;
fi
}

# Platform设备查看
platform_devices_info() {
echo "2. Platform设备信息"

# 已注册的platform设备
echo "已注册的Platform设备:"
ls /sys/bus/platform/devices/ 2>/dev/null | head -10

# Platform驱动
echo "已注册的Platform驱动:"
ls /sys/bus/platform/drivers/ 2>/dev/null | head -10

# 设备和驱动的绑定关系
echo "设备驱动绑定关系:"
for device in /sys/bus/platform/devices/*; do
if [ -L "$device/driver" ]; then
device_name=$(basename "$device")
driver_name=$(basename $(readlink "$device/driver"))
echo " $device_name -> $driver_name"
fi
done | head -5
}

# 设备树属性查看
device_tree_properties() {
local device_path=$1

if [ -z "$device_path" ]; then
echo "用法: device_tree_properties <设备路径>"
return 1
fi

echo "3. 设备树属性查看: $device_path"

if [ ! -d "$device_path" ]; then
echo "错误: 设备路径不存在"
return 1
fi

echo "设备属性:"
for prop in "$device_path"/*; do
if [ -f "$prop" ]; then
prop_name=$(basename "$prop")
echo -n " $prop_name: "

# 尝试以字符串形式读取
if cat "$prop" 2>/dev/null | tr -d '\0' | grep -q '^[[:print:]]*$'; then
cat "$prop" | tr '\0' ' '
else
echo "(binary data)"
fi
fi
done
}

device_tree_info
platform_devices_info
echo "设备树属性查看函数已定义:"
echo "device_tree_properties /sys/firmware/devicetree/base/<设备名>"

四、中断处理与定时器

4.1 中断处理机制

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
// interrupt_handler.c - 中断处理示例
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/interrupt.h>
#include <linux/gpio.h>
#include <linux/timer.h>
#include <linux/workqueue.h>
#include <linux/spinlock.h>
#include <linux/atomic.h>

// 模块信息
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Your Name");
MODULE_DESCRIPTION("Interrupt handling example");
MODULE_VERSION("1.0");

// GPIO引脚定义
#define GPIO_PIN 18
#define GPIO_LABEL "interrupt_gpio"

// 中断统计结构
struct interrupt_stats {
atomic_t count; // 中断计数
unsigned long last_jiffies; // 最后中断时间
spinlock_t lock; // 自旋锁
struct timer_list timer; // 定时器
struct work_struct work; // 工作队列
bool timer_active; // 定时器状态
};

static struct interrupt_stats irq_stats;
static int irq_number;

/**
* interrupt_work_handler - 工作队列处理函数
* @work: 工作结构指针
*
* 在进程上下文中处理中断的后半部分工作
*/
static void interrupt_work_handler(struct work_struct *work)
{
struct interrupt_stats *stats = container_of(work, struct interrupt_stats, work);
unsigned long flags;
int count;

// 获取当前中断计数
count = atomic_read(&stats->count);

printk(KERN_INFO "interrupt_handler: Work queue processing interrupt #%d\n", count);

// 模拟一些耗时的处理工作
msleep(10);

// 在这里可以进行需要睡眠或分配内存的操作
// 例如:与用户空间通信、文件操作等

spin_lock_irqsave(&stats->lock, flags);
// 更新统计信息
printk(KERN_INFO "interrupt_handler: Work completed for interrupt #%d\n", count);
spin_unlock_irqrestore(&stats->lock, flags);
}

/**
* interrupt_timer_handler - 定时器处理函数
* @timer: 定时器结构指针
*
* 定时器到期时的处理函数
*/
static void interrupt_timer_handler(struct timer_list *timer)
{
struct interrupt_stats *stats = container_of(timer, struct interrupt_stats, timer);
unsigned long flags;
int count;

spin_lock_irqsave(&stats->lock, flags);
count = atomic_read(&stats->count);
stats->timer_active = false;
spin_unlock_irqrestore(&stats->lock, flags);

printk(KERN_INFO "interrupt_handler: Timer expired, total interrupts: %d\n", count);
}

/**
* gpio_interrupt_handler - GPIO中断处理函数
* @irq: 中断号
* @dev_id: 设备ID
*
* 返回值: IRQ_HANDLED表示中断已处理
*/
static irqreturn_t gpio_interrupt_handler(int irq, void *dev_id)
{
struct interrupt_stats *stats = (struct interrupt_stats *)dev_id;
unsigned long flags;
unsigned long current_jiffies = jiffies;

// 增加中断计数
atomic_inc(&stats->count);

spin_lock_irqsave(&stats->lock, flags);

// 检查中断间隔,防止抖动
if (time_after(current_jiffies, stats->last_jiffies + HZ/100)) { // 10ms防抖
stats->last_jiffies = current_jiffies;

// 启动定时器(如果未激活)
if (!stats->timer_active) {
mod_timer(&stats->timer, jiffies + HZ); // 1秒后到期
stats->timer_active = true;
}

// 调度工作队列
schedule_work(&stats->work);

spin_unlock_irqrestore(&stats->lock, flags);

printk(KERN_INFO "interrupt_handler: GPIO interrupt #%d at jiffies %lu\n",
atomic_read(&stats->count), current_jiffies);

return IRQ_HANDLED;
}

spin_unlock_irqrestore(&stats->lock, flags);

// 忽略抖动中断
printk(KERN_DEBUG "interrupt_handler: Debounced interrupt ignored\n");
return IRQ_HANDLED;
}

/**
* setup_gpio_interrupt - 设置GPIO中断
*
* 返回值: 0表示成功,负值表示失败
*/
static int setup_gpio_interrupt(void)
{
int ret;

printk(KERN_INFO "interrupt_handler: Setting up GPIO interrupt\n");

// 检查GPIO是否有效
if (!gpio_is_valid(GPIO_PIN)) {
printk(KERN_ERR "interrupt_handler: Invalid GPIO pin %d\n", GPIO_PIN);
return -EINVAL;
}

// 请求GPIO
ret = gpio_request(GPIO_PIN, GPIO_LABEL);
if (ret) {
printk(KERN_ERR "interrupt_handler: Failed to request GPIO %d\n", GPIO_PIN);
return ret;
}

// 设置GPIO为输入
ret = gpio_direction_input(GPIO_PIN);
if (ret) {
printk(KERN_ERR "interrupt_handler: Failed to set GPIO direction\n");
goto err_gpio;
}

// 获取中断号
irq_number = gpio_to_irq(GPIO_PIN);
if (irq_number < 0) {
printk(KERN_ERR "interrupt_handler: Failed to get IRQ number\n");
ret = irq_number;
goto err_gpio;
}

printk(KERN_INFO "interrupt_handler: GPIO %d mapped to IRQ %d\n",
GPIO_PIN, irq_number);

// 请求中断
ret = request_irq(irq_number, gpio_interrupt_handler,
IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
"gpio_interrupt", &irq_stats);
if (ret) {
printk(KERN_ERR "interrupt_handler: Failed to request IRQ %d\n", irq_number);
goto err_gpio;
}

printk(KERN_INFO "interrupt_handler: IRQ %d registered successfully\n", irq_number);
return 0;

err_gpio:
gpio_free(GPIO_PIN);
return ret;
}

/**
* cleanup_gpio_interrupt - 清理GPIO中断
*/
static void cleanup_gpio_interrupt(void)
{
printk(KERN_INFO "interrupt_handler: Cleaning up GPIO interrupt\n");

// 释放中断
if (irq_number >= 0) {
free_irq(irq_number, &irq_stats);
printk(KERN_INFO "interrupt_handler: IRQ %d freed\n", irq_number);
}

// 释放GPIO
gpio_free(GPIO_PIN);
printk(KERN_INFO "interrupt_handler: GPIO %d freed\n", GPIO_PIN);
}

/**
* interrupt_handler_init - 模块初始化函数
*
* 返回值: 0表示成功,负值表示失败
*/
static int __init interrupt_handler_init(void)
{
int ret;

printk(KERN_INFO "interrupt_handler: Loading interrupt handler module\n");

// 初始化中断统计结构
atomic_set(&irq_stats.count, 0);
irq_stats.last_jiffies = 0;
spin_lock_init(&irq_stats.lock);
irq_stats.timer_active = false;

// 初始化定时器
timer_setup(&irq_stats.timer, interrupt_timer_handler, 0);

// 初始化工作队列
INIT_WORK(&irq_stats.work, interrupt_work_handler);

// 设置GPIO中断
ret = setup_gpio_interrupt();
if (ret) {
printk(KERN_ERR "interrupt_handler: Failed to setup GPIO interrupt\n");
return ret;
}

printk(KERN_INFO "interrupt_handler: Module loaded successfully\n");
printk(KERN_INFO "interrupt_handler: Monitoring GPIO %d for interrupts\n", GPIO_PIN);

return 0;
}

/**
* interrupt_handler_exit - 模块清理函数
*/
static void __exit interrupt_handler_exit(void)
{
printk(KERN_INFO "interrupt_handler: Unloading interrupt handler module\n");

// 清理GPIO中断
cleanup_gpio_interrupt();

// 删除定时器
del_timer_sync(&irq_stats.timer);

// 刷新工作队列
flush_work(&irq_stats.work);

printk(KERN_INFO "interrupt_handler: Final interrupt count: %d\n",
atomic_read(&irq_stats.count));

printk(KERN_INFO "interrupt_handler: Module unloaded successfully\n");
}

module_init(interrupt_handler_init);
module_exit(interrupt_handler_exit);

4.2 内核定时器和延迟工作

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
// timer_example.c - 内核定时器示例
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/timer.h>
#include <linux/jiffies.h>
#include <linux/workqueue.h>
#include <linux/delay.h>
#include <linux/kthread.h>
#include <linux/sched.h>

// 模块信息
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Your Name");
MODULE_DESCRIPTION("Kernel timer and delayed work example");
MODULE_VERSION("1.0");

// 定时器和工作队列结构
struct timer_example {
struct timer_list periodic_timer; // 周期性定时器
struct timer_list oneshot_timer; // 单次定时器
struct delayed_work delayed_work; // 延迟工作
struct workqueue_struct *workqueue; // 专用工作队列
struct task_struct *kthread; // 内核线程
atomic_t timer_count; // 定时器计数
atomic_t work_count; // 工作计数
bool thread_running; // 线程运行状态
};

static struct timer_example timer_ex;

/**
* delayed_work_handler - 延迟工作处理函数
* @work: 延迟工作结构指针
*/
static void delayed_work_handler(struct work_struct *work)
{
struct delayed_work *dwork = to_delayed_work(work);
struct timer_example *tex = container_of(dwork, struct timer_example, delayed_work);
int count;

count = atomic_inc_return(&tex->work_count);

printk(KERN_INFO "timer_example: Delayed work executed #%d at jiffies %lu\n",
count, jiffies);

// 模拟一些工作
msleep(100);

// 重新调度延迟工作(每5秒执行一次)
if (tex->thread_running) {
queue_delayed_work(tex->workqueue, &tex->delayed_work, 5 * HZ);
}
}

/**
* periodic_timer_handler - 周期性定时器处理函数
* @timer: 定时器结构指针
*/
static void periodic_timer_handler(struct timer_list *timer)
{
struct timer_example *tex = container_of(timer, struct timer_example, periodic_timer);
int count;

count = atomic_inc_return(&tex->timer_count);

printk(KERN_INFO "timer_example: Periodic timer fired #%d at jiffies %lu\n",
count, jiffies);

// 重新设置定时器(每2秒触发一次)
if (tex->thread_running) {
mod_timer(&tex->periodic_timer, jiffies + 2 * HZ);
}
}

/**
* oneshot_timer_handler - 单次定时器处理函数
* @timer: 定时器结构指针
*/
static void oneshot_timer_handler(struct timer_list *timer)
{
struct timer_example *tex = container_of(timer, struct timer_example, oneshot_timer);

printk(KERN_INFO "timer_example: One-shot timer fired at jiffies %lu\n", jiffies);

// 启动延迟工作
queue_delayed_work(tex->workqueue, &tex->delayed_work, HZ);
}

/**
* timer_thread - 内核线程函数
* @data: 线程参数
*
* 返回值: 0表示正常退出
*/
static int timer_thread(void *data)
{
struct timer_example *tex = (struct timer_example *)data;
unsigned long timeout;

printk(KERN_INFO "timer_example: Kernel thread started\n");

while (!kthread_should_stop()) {
// 设置超时时间(10秒)
timeout = jiffies + 10 * HZ;

// 等待超时或停止信号
while (time_before(jiffies, timeout) && !kthread_should_stop()) {
schedule_timeout_interruptible(HZ); // 1秒检查一次
}

if (!kthread_should_stop()) {
printk(KERN_INFO "timer_example: Thread periodic check at jiffies %lu\n", jiffies);

// 触发单次定时器
mod_timer(&tex->oneshot_timer, jiffies + HZ/2);
}
}

printk(KERN_INFO "timer_example: Kernel thread stopping\n");
return 0;
}

/**
* timer_example_init - 模块初始化函数
*
* 返回值: 0表示成功,负值表示失败
*/
static int __init timer_example_init(void)
{
printk(KERN_INFO "timer_example: Loading timer example module\n");

// 初始化计数器
atomic_set(&timer_ex.timer_count, 0);
atomic_set(&timer_ex.work_count, 0);
timer_ex.thread_running = true;

// 创建专用工作队列
timer_ex.workqueue = create_singlethread_workqueue("timer_example_wq");
if (!timer_ex.workqueue) {
printk(KERN_ERR "timer_example: Failed to create workqueue\n");
return -ENOMEM;
}

// 初始化定时器
timer_setup(&timer_ex.periodic_timer, periodic_timer_handler, 0);
timer_setup(&timer_ex.oneshot_timer, oneshot_timer_handler, 0);

// 初始化延迟工作
INIT_DELAYED_WORK(&timer_ex.delayed_work, delayed_work_handler);

// 启动周期性定时器
mod_timer(&timer_ex.periodic_timer, jiffies + HZ);

// 创建内核线程
timer_ex.kthread = kthread_run(timer_thread, &timer_ex, "timer_example_thread");
if (IS_ERR(timer_ex.kthread)) {
printk(KERN_ERR "timer_example: Failed to create kernel thread\n");
del_timer_sync(&timer_ex.periodic_timer);
destroy_workqueue(timer_ex.workqueue);
return PTR_ERR(timer_ex.kthread);
}

printk(KERN_INFO "timer_example: Module loaded successfully\n");
printk(KERN_INFO "timer_example: Periodic timer started\n");
printk(KERN_INFO "timer_example: Kernel thread created\n");

return 0;
}

/**
* timer_example_exit - 模块清理函数
*/
static void __exit timer_example_exit(void)
{
printk(KERN_INFO "timer_example: Unloading timer example module\n");

// 停止线程
timer_ex.thread_running = false;
if (timer_ex.kthread) {
kthread_stop(timer_ex.kthread);
printk(KERN_INFO "timer_example: Kernel thread stopped\n");
}

// 删除定时器
del_timer_sync(&timer_ex.periodic_timer);
del_timer_sync(&timer_ex.oneshot_timer);
printk(KERN_INFO "timer_example: Timers deleted\n");

// 取消延迟工作并销毁工作队列
if (timer_ex.workqueue) {
cancel_delayed_work_sync(&timer_ex.delayed_work);
destroy_workqueue(timer_ex.workqueue);
printk(KERN_INFO "timer_example: Workqueue destroyed\n");
}

printk(KERN_INFO "timer_example: Final counts - Timer: %d, Work: %d\n",
atomic_read(&timer_ex.timer_count), atomic_read(&timer_ex.work_count));

printk(KERN_INFO "timer_example: Module unloaded successfully\n");
}

module_init(timer_example_init);
module_exit(timer_example_exit);

五、内存管理与同步机制

5.1 内核内存分配

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
// memory_management.c - 内核内存管理示例
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/vmalloc.h>
#include <linux/mm.h>
#include <linux/gfp.h>
#include <linux/dma-mapping.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <linux/uaccess.h>

// 模块信息
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Your Name");
MODULE_DESCRIPTION("Kernel memory management example");
MODULE_VERSION("1.0");

// 内存管理结构
struct memory_example {
void *kmalloc_ptr; // kmalloc分配的内存
void *vmalloc_ptr; // vmalloc分配的内存
void *dma_coherent_ptr; // DMA一致性内存
dma_addr_t dma_handle; // DMA物理地址
struct kmem_cache *cache; // slab缓存
void *cache_obj; // 缓存对象
struct page *pages; // 页面分配
unsigned long page_order; // 页面阶数
size_t total_allocated; // 总分配内存
};

static struct memory_example mem_ex;
static struct proc_dir_entry *proc_entry;

// 自定义结构用于slab缓存
struct custom_object {
int id;
char name[32];
unsigned long timestamp;
struct list_head list;
};

/**
* cache_constructor - slab缓存构造函数
* @obj: 对象指针
*/
static void cache_constructor(void *obj)
{
struct custom_object *custom = (struct custom_object *)obj;

custom->id = 0;
memset(custom->name, 0, sizeof(custom->name));
custom->timestamp = 0;
INIT_LIST_HEAD(&custom->list);
}

/**
* allocate_memory - 分配各种类型的内存
*
* 返回值: 0表示成功,负值表示失败
*/
static int allocate_memory(void)
{
printk(KERN_INFO "memory_example: Allocating memory\n");

// 1. kmalloc分配 - 物理连续内存
mem_ex.kmalloc_ptr = kmalloc(4096, GFP_KERNEL);
if (!mem_ex.kmalloc_ptr) {
printk(KERN_ERR "memory_example: kmalloc failed\n");
return -ENOMEM;
}
mem_ex.total_allocated += 4096;
printk(KERN_INFO "memory_example: kmalloc allocated 4KB at %p\n", mem_ex.kmalloc_ptr);

// 2. vmalloc分配 - 虚拟连续内存
mem_ex.vmalloc_ptr = vmalloc(64 * 1024);
if (!mem_ex.vmalloc_ptr) {
printk(KERN_ERR "memory_example: vmalloc failed\n");
goto err_vmalloc;
}
mem_ex.total_allocated += 64 * 1024;
printk(KERN_INFO "memory_example: vmalloc allocated 64KB at %p\n", mem_ex.vmalloc_ptr);

// 3. DMA一致性内存分配
mem_ex.dma_coherent_ptr = dma_alloc_coherent(NULL, PAGE_SIZE,
&mem_ex.dma_handle, GFP_KERNEL);
if (!mem_ex.dma_coherent_ptr) {
printk(KERN_WARNING "memory_example: DMA coherent allocation failed\n");
} else {
mem_ex.total_allocated += PAGE_SIZE;
printk(KERN_INFO "memory_example: DMA coherent allocated %lu bytes at %p (DMA: %pad)\n",
PAGE_SIZE, mem_ex.dma_coherent_ptr, &mem_ex.dma_handle);
}

// 4. 创建slab缓存
mem_ex.cache = kmem_cache_create("custom_object_cache",
sizeof(struct custom_object),
0, SLAB_HWCACHE_ALIGN,
cache_constructor);
if (!mem_ex.cache) {
printk(KERN_ERR "memory_example: Failed to create slab cache\n");
goto err_cache;
}
printk(KERN_INFO "memory_example: Slab cache created\n");

// 5. 从slab缓存分配对象
mem_ex.cache_obj = kmem_cache_alloc(mem_ex.cache, GFP_KERNEL);
if (!mem_ex.cache_obj) {
printk(KERN_ERR "memory_example: Failed to allocate from cache\n");
goto err_cache_alloc;
}
mem_ex.total_allocated += sizeof(struct custom_object);
printk(KERN_INFO "memory_example: Object allocated from cache at %p\n", mem_ex.cache_obj);

// 6. 页面分配
mem_ex.page_order = 2; // 分配4个页面 (2^2)
mem_ex.pages = alloc_pages(GFP_KERNEL, mem_ex.page_order);
if (!mem_ex.pages) {
printk(KERN_ERR "memory_example: Failed to allocate pages\n");
goto err_pages;
}
mem_ex.total_allocated += PAGE_SIZE << mem_ex.page_order;
printk(KERN_INFO "memory_example: Allocated %lu pages (order %lu) at %p\n",
1UL << mem_ex.page_order, mem_ex.page_order, page_address(mem_ex.pages));

printk(KERN_INFO "memory_example: Total allocated memory: %zu bytes\n", mem_ex.total_allocated);
return 0;

err_pages:
kmem_cache_free(mem_ex.cache, mem_ex.cache_obj);
err_cache_alloc:
kmem_cache_destroy(mem_ex.cache);
err_cache:
if (mem_ex.dma_coherent_ptr) {
dma_free_coherent(NULL, PAGE_SIZE, mem_ex.dma_coherent_ptr, mem_ex.dma_handle);
}
vfree(mem_ex.vmalloc_ptr);
err_vmalloc:
kfree(mem_ex.kmalloc_ptr);
return -ENOMEM;
}

/**
* free_memory - 释放所有分配的内存
*/
static void free_memory(void)
{
printk(KERN_INFO "memory_example: Freeing memory\n");

// 释放页面
if (mem_ex.pages) {
__free_pages(mem_ex.pages, mem_ex.page_order);
printk(KERN_INFO "memory_example: Pages freed\n");
}

// 释放slab缓存对象
if (mem_ex.cache_obj) {
kmem_cache_free(mem_ex.cache, mem_ex.cache_obj);
printk(KERN_INFO "memory_example: Cache object freed\n");
}

// 销毁slab缓存
if (mem_ex.cache) {
kmem_cache_destroy(mem_ex.cache);
printk(KERN_INFO "memory_example: Slab cache destroyed\n");
}

// 释放DMA一致性内存
if (mem_ex.dma_coherent_ptr) {
dma_free_coherent(NULL, PAGE_SIZE, mem_ex.dma_coherent_ptr, mem_ex.dma_handle);
printk(KERN_INFO "memory_example: DMA coherent memory freed\n");
}

// 释放vmalloc内存
if (mem_ex.vmalloc_ptr) {
vfree(mem_ex.vmalloc_ptr);
printk(KERN_INFO "memory_example: vmalloc memory freed\n");
}

// 释放kmalloc内存
if (mem_ex.kmalloc_ptr) {
kfree(mem_ex.kmalloc_ptr);
printk(KERN_INFO "memory_example: kmalloc memory freed\n");
}

printk(KERN_INFO "memory_example: All memory freed\n");
}

/**
* memory_proc_show - proc文件显示函数
* @m: seq_file结构指针
* @v: 私有数据
*
* 返回值: 0表示成功
*/
static int memory_proc_show(struct seq_file *m, void *v)
{
seq_printf(m, "Memory Example Module Status\n");
seq_printf(m, "===========================\n");
seq_printf(m, "Total allocated: %zu bytes\n", mem_ex.total_allocated);
seq_printf(m, "\nMemory allocations:\n");
seq_printf(m, " kmalloc: %p (4KB)\n", mem_ex.kmalloc_ptr);
seq_printf(m, " vmalloc: %p (64KB)\n", mem_ex.vmalloc_ptr);
seq_printf(m, " DMA coherent: %p (%luB, DMA: %pad)\n",
mem_ex.dma_coherent_ptr, PAGE_SIZE, &mem_ex.dma_handle);
seq_printf(m, " Slab cache: %p\n", mem_ex.cache);
seq_printf(m, " Cache object: %p\n", mem_ex.cache_obj);
seq_printf(m, " Pages: %p (order %lu)\n",
mem_ex.pages ? page_address(mem_ex.pages) : NULL, mem_ex.page_order);

return 0;
}

/**
* memory_proc_open - proc文件打开函数
* @inode: inode结构指针
* @file: file结构指针
*
* 返回值: 0表示成功,负值表示失败
*/
static int memory_proc_open(struct inode *inode, struct file *file)
{
return single_open(file, memory_proc_show, NULL);
}

// proc文件操作结构
static const struct proc_ops memory_proc_ops = {
.proc_open = memory_proc_open,
.proc_read = seq_read,
.proc_lseek = seq_lseek,
.proc_release = single_release,
};

/**
* memory_example_init - 模块初始化函数
*
* 返回值: 0表示成功,负值表示失败
*/
static int __init memory_example_init(void)
{
int ret;

printk(KERN_INFO "memory_example: Loading memory management module\n");

// 初始化内存管理结构
memset(&mem_ex, 0, sizeof(mem_ex));

// 分配内存
ret = allocate_memory();
if (ret) {
printk(KERN_ERR "memory_example: Failed to allocate memory\n");
return ret;
}

// 创建proc文件
proc_entry = proc_create("memory_example", 0444, NULL, &memory_proc_ops);
if (!proc_entry) {
printk(KERN_WARNING "memory_example: Failed to create proc entry\n");
} else {
printk(KERN_INFO "memory_example: Created /proc/memory_example\n");
}

printk(KERN_INFO "memory_example: Module loaded successfully\n");
return 0;
}

/**
* memory_example_exit - 模块清理函数
*/
static void __exit memory_example_exit(void)
{
printk(KERN_INFO "memory_example: Unloading memory management module\n");

// 删除proc文件
if (proc_entry) {
proc_remove(proc_entry);
printk(KERN_INFO "memory_example: Removed /proc/memory_example\n");
}

// 释放内存
free_memory();

printk(KERN_INFO "memory_example: Module unloaded successfully\n");
}

module_init(memory_example_init);
module_exit(memory_example_exit);

5.2 同步机制实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
// synchronization.c - 内核同步机制示例
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/kthread.h>
#include <linux/delay.h>
#include <linux/mutex.h>
#include <linux/spinlock.h>
#include <linux/rwlock.h>
#include <linux/semaphore.h>
#include <linux/completion.h>
#include <linux/atomic.h>
#include <linux/sched.h>
#include <linux/random.h>

// 模块信息
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Your Name");
MODULE_DESCRIPTION("Kernel synchronization mechanisms example");
MODULE_VERSION("1.0");

// 同步机制结构
struct sync_example {
// 互斥锁
struct mutex mutex;

// 自旋锁
spinlock_t spinlock;

// 读写锁
rwlock_t rwlock;

// 信号量
struct semaphore semaphore;

// 完成量
struct completion completion;

// 原子变量
atomic_t atomic_counter;
atomic_long_t atomic_long_counter;

// 共享数据
int shared_data;
unsigned long shared_flags;

// 线程控制
struct task_struct *producer_thread;
struct task_struct *consumer_thread;
struct task_struct *reader_threads[3];
struct task_struct *writer_thread;

bool threads_running;
};

static struct sync_example sync_ex;

/**
* producer_thread_fn - 生产者线程函数
* @data: 线程参数
*
* 返回值: 0表示正常退出
*/
static int producer_thread_fn(void *data)
{
struct sync_example *sync = (struct sync_example *)data;
int count = 0;

printk(KERN_INFO "sync_example: Producer thread started\n");

while (!kthread_should_stop() && sync->threads_running) {
// 使用互斥锁保护共享数据
mutex_lock(&sync->mutex);

sync->shared_data = ++count;
printk(KERN_INFO "sync_example: Producer: shared_data = %d\n", sync->shared_data);

// 增加原子计数器
atomic_inc(&sync->atomic_counter);

mutex_unlock(&sync->mutex);

// 通知完成量
complete(&sync->completion);

// 释放信号量
up(&sync->semaphore);

msleep(1000); // 1秒间隔
}

printk(KERN_INFO "sync_example: Producer thread stopping\n");
return 0;
}

/**
* consumer_thread_fn - 消费者线程函数
* @data: 线程参数
*
* 返回值: 0表示正常退出
*/
static int consumer_thread_fn(void *data)
{
struct sync_example *sync = (struct sync_example *)data;
int local_data;

printk(KERN_INFO "sync_example: Consumer thread started\n");

while (!kthread_should_stop() && sync->threads_running) {
// 等待信号量
if (down_interruptible(&sync->semaphore)) {
break; // 被信号中断
}

// 等待完成量
if (wait_for_completion_interruptible(&sync->completion)) {
up(&sync->semaphore); // 恢复信号量
break; // 被信号中断
}

// 使用互斥锁读取共享数据
mutex_lock(&sync->mutex);
local_data = sync->shared_data;
mutex_unlock(&sync->mutex);

printk(KERN_INFO "sync_example: Consumer: read shared_data = %d, atomic = %d\n",
local_data, atomic_read(&sync->atomic_counter));
}

printk(KERN_INFO "sync_example: Consumer thread stopping\n");
return 0;
}

/**
* reader_thread_fn - 读者线程函数
* @data: 线程参数
*
* 返回值: 0表示正常退出
*/
static int reader_thread_fn(void *data)
{
struct sync_example *sync = (struct sync_example *)data;
int thread_id = (int)(long)data;
unsigned long flags;
int local_data;

printk(KERN_INFO "sync_example: Reader thread %d started\n", thread_id);

while (!kthread_should_stop() && sync->threads_running) {
// 使用读锁
read_lock_irqsave(&sync->rwlock, flags);

local_data = sync->shared_data;

// 模拟读取操作
msleep(100);

read_unlock_irqrestore(&sync->rwlock, flags);

printk(KERN_INFO "sync_example: Reader %d: read data = %d\n", thread_id, local_data);

msleep(2000 + (thread_id * 500)); // 不同的读取间隔
}

printk(KERN_INFO "sync_example: Reader thread %d stopping\n", thread_id);
return 0;
}

/**
* writer_thread_fn - 写者线程函数
* @data: 线程参数
*
* 返回值: 0表示正常退出
*/
static int writer_thread_fn(void *data)
{
struct sync_example *sync = (struct sync_example *)data;
unsigned long flags;
int count = 1000;

printk(KERN_INFO "sync_example: Writer thread started\n");

while (!kthread_should_stop() && sync->threads_running) {
// 使用写锁
write_lock_irqsave(&sync->rwlock, flags);

sync->shared_data = ++count;

// 模拟写入操作
msleep(50);

write_unlock_irqrestore(&sync->rwlock, flags);

printk(KERN_INFO "sync_example: Writer: wrote data = %d\n", count);

// 增加原子长整型计数器
atomic_long_inc(&sync->atomic_long_counter);

msleep(3000); // 3秒间隔
}

printk(KERN_INFO "sync_example: Writer thread stopping\n");
return 0;
}

/**
* spinlock_test - 自旋锁测试函数
*/
static void spinlock_test(void)
{
unsigned long flags;
int i;

printk(KERN_INFO "sync_example: Testing spinlock\n");

for (i = 0; i < 5; i++) {
spin_lock_irqsave(&sync_ex.spinlock, flags);

// 临界区 - 快速操作
sync_ex.shared_flags |= (1 << i);

spin_unlock_irqrestore(&sync_ex.spinlock, flags);

printk(KERN_INFO "sync_example: Spinlock test %d, flags = 0x%lx\n",
i, sync_ex.shared_flags);
}
}

/**
* atomic_operations_test - 原子操作测试函数
*/
static void atomic_operations_test(void)
{
int old_val, new_val;

printk(KERN_INFO "sync_example: Testing atomic operations\n");

// 原子增加
atomic_add(10, &sync_ex.atomic_counter);
printk(KERN_INFO "sync_example: After atomic_add(10): %d\n",
atomic_read(&sync_ex.atomic_counter));

// 原子减少
atomic_sub(5, &sync_ex.atomic_counter);
printk(KERN_INFO "sync_example: After atomic_sub(5): %d\n",
atomic_read(&sync_ex.atomic_counter));

// 原子比较并交换
old_val = atomic_read(&sync_ex.atomic_counter);
new_val = old_val + 100;
if (atomic_cmpxchg(&sync_ex.atomic_counter, old_val, new_val) == old_val) {
printk(KERN_INFO "sync_example: atomic_cmpxchg succeeded: %d -> %d\n",
old_val, new_val);
}

// 原子测试并设置位
if (!test_and_set_bit(0, &sync_ex.shared_flags)) {
printk(KERN_INFO "sync_example: Bit 0 was clear, now set\n");
}

// 原子清除位
if (test_and_clear_bit(1, &sync_ex.shared_flags)) {
printk(KERN_INFO "sync_example: Bit 1 was set, now clear\n");
}
}

/**
* sync_example_init - 模块初始化函数
*
* 返回值: 0表示成功,负值表示失败
*/
static int __init sync_example_init(void)
{
int i;

printk(KERN_INFO "sync_example: Loading synchronization example module\n");

// 初始化同步机制
mutex_init(&sync_ex.mutex);
spin_lock_init(&sync_ex.spinlock);
rwlock_init(&sync_ex.rwlock);
sema_init(&sync_ex.semaphore, 0); // 初始值为0
init_completion(&sync_ex.completion);

// 初始化原子变量
atomic_set(&sync_ex.atomic_counter, 0);
atomic_long_set(&sync_ex.atomic_long_counter, 0);

// 初始化共享数据
sync_ex.shared_data = 0;
sync_ex.shared_flags = 0;
sync_ex.threads_running = true;

// 测试自旋锁和原子操作
spinlock_test();
atomic_operations_test();

// 创建生产者线程
sync_ex.producer_thread = kthread_run(producer_thread_fn, &sync_ex, "sync_producer");
if (IS_ERR(sync_ex.producer_thread)) {
printk(KERN_ERR "sync_example: Failed to create producer thread\n");
return PTR_ERR(sync_ex.producer_thread);
}

// 创建消费者线程
sync_ex.consumer_thread = kthread_run(consumer_thread_fn, &sync_ex, "sync_consumer");
if (IS_ERR(sync_ex.consumer_thread)) {
printk(KERN_ERR "sync_example: Failed to create consumer thread\n");
kthread_stop(sync_ex.producer_thread);
return PTR_ERR(sync_ex.consumer_thread);
}

// 创建读者线程
for (i = 0; i < 3; i++) {
sync_ex.reader_threads[i] = kthread_run(reader_thread_fn, (void *)(long)i,
"sync_reader_%d", i);
if (IS_ERR(sync_ex.reader_threads[i])) {
printk(KERN_ERR "sync_example: Failed to create reader thread %d\n", i);
// 清理已创建的线程
sync_ex.threads_running = false;
while (--i >= 0) {
kthread_stop(sync_ex.reader_threads[i]);
}
kthread_stop(sync_ex.consumer_thread);
kthread_stop(sync_ex.producer_thread);
return PTR_ERR(sync_ex.reader_threads[i]);
}
}

// 创建写者线程
sync_ex.writer_thread = kthread_run(writer_thread_fn, &sync_ex, "sync_writer");
if (IS_ERR(sync_ex.writer_thread)) {
printk(KERN_ERR "sync_example: Failed to create writer thread\n");
sync_ex.threads_running = false;
for (i = 0; i < 3; i++) {
kthread_stop(sync_ex.reader_threads[i]);
}
kthread_stop(sync_ex.consumer_thread);
kthread_stop(sync_ex.producer_thread);
return PTR_ERR(sync_ex.writer_thread);
}

printk(KERN_INFO "sync_example: Module loaded successfully\n");
printk(KERN_INFO "sync_example: All threads created and running\n");

return 0;
}

/**
* sync_example_exit - 模块清理函数
*/
static void __exit sync_example_exit(void)
{
int i;

printk(KERN_INFO "sync_example: Unloading synchronization example module\n");

// 停止所有线程
sync_ex.threads_running = false;

// 停止写者线程
if (sync_ex.writer_thread) {
kthread_stop(sync_ex.writer_thread);
printk(KERN_INFO "sync_example: Writer thread stopped\n");
}

// 停止读者线程
for (i = 0; i < 3; i++) {
if (sync_ex.reader_threads[i]) {
kthread_stop(sync_ex.reader_threads[i]);
printk(KERN_INFO "sync_example: Reader thread %d stopped\n", i);
}
}

// 停止消费者线程
if (sync_ex.consumer_thread) {
// 唤醒可能等待的消费者
complete(&sync_ex.completion);
up(&sync_ex.semaphore);
kthread_stop(sync_ex.consumer_thread);
printk(KERN_INFO "sync_example: Consumer thread stopped\n");
}

// 停止生产者线程
if (sync_ex.producer_thread) {
kthread_stop(sync_ex.producer_thread);
printk(KERN_INFO "sync_example: Producer thread stopped\n");
}

printk(KERN_INFO "sync_example: Final atomic counter: %d\n",
atomic_read(&sync_ex.atomic_counter));
printk(KERN_INFO "sync_example: Final atomic long counter: %ld\n",
atomic_long_read(&sync_ex.atomic_long_counter));
printk(KERN_INFO "sync_example: Final shared flags: 0x%lx\n", sync_ex.shared_flags);

printk(KERN_INFO "sync_example: Module unloaded successfully\n");
}

module_init(sync_example_init);
module_exit(sync_example_exit);

六、内核调试技巧与工具

6.1 内核调试方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
#!/bin/bash
# kernel_debug_tools.sh - 内核调试工具脚本

# 内核调试工具集合

# 1. 内核日志分析
kernel_log_analysis() {
echo "=== 内核日志分析 ==="

# 查看内核环形缓冲区
echo "1. 内核环形缓冲区 (dmesg):"
dmesg | tail -20

# 查看系统日志
echo "\n2. 系统日志:"
journalctl -k --since "1 hour ago" | tail -10

# 查看内核模块信息
echo "\n3. 已加载的内核模块:"
lsmod | head -10

# 查看内核版本和编译信息
echo "\n4. 内核版本信息:"
uname -a
cat /proc/version
}

# 2. 内核符号表分析
kernel_symbols_analysis() {
echo "=== 内核符号表分析 ==="

# 查看内核符号表
echo "1. 内核符号表 (部分):"
if [ -r /proc/kallsyms ]; then
head -20 /proc/kallsyms
else
echo "无法读取 /proc/kallsyms (需要root权限)"
fi

# 查看模块符号
echo "\n2. 模块符号信息:"
if [ -d /sys/module ]; then
for module in /sys/module/*/; do
module_name=$(basename "$module")
if [ -f "$module/srcversion" ]; then
echo " $module_name: $(cat $module/srcversion 2>/dev/null)"
fi
done | head -5
fi
}

# 3. 内存调试信息
memory_debug_info() {
echo "=== 内存调试信息 ==="

# 内存使用情况
echo "1. 内存使用情况:"
cat /proc/meminfo | grep -E "(MemTotal|MemFree|MemAvailable|Buffers|Cached|Slab)"

# slab分配器信息
echo "\n2. Slab分配器信息 (前10个):"
if [ -r /proc/slabinfo ]; then
head -11 /proc/slabinfo
else
echo "无法读取 /proc/slabinfo"
fi

# 虚拟内存统计
echo "\n3. 虚拟内存统计:"
cat /proc/vmstat | grep -E "(nr_free_pages|nr_alloc_batch|nr_inactive|nr_active)"
}

# 4. 进程和调度信息
process_debug_info() {
echo "=== 进程和调度信息 ==="

# 进程状态
echo "1. 进程状态统计:"
ps aux --no-headers | awk '{print $8}' | sort | uniq -c | sort -nr

# 内核线程
echo "\n2. 内核线程 (前10个):"
ps -eo pid,ppid,comm,stat | grep "\[.*\]" | head -10

# 调度信息
echo "\n3. 调度统计:"
if [ -r /proc/schedstat ]; then
head -5 /proc/schedstat
else
echo "无法读取 /proc/schedstat"
fi
}

# 5. 中断和软中断信息
interrupt_debug_info() {
echo "=== 中断调试信息 ==="

# 硬件中断
echo "1. 硬件中断统计:"
cat /proc/interrupts | head -10

# 软中断
echo "\n2. 软中断统计:"
cat /proc/softirqs | head -5

# 中断负载
echo "\n3. 中断负载 (每秒):"
awk '/^cpu/ {print $1, $6+$7}' /proc/stat
}

# 6. 文件系统调试
filesystem_debug_info() {
echo "=== 文件系统调试信息 ==="

# 挂载信息
echo "1. 挂载的文件系统:"
mount | grep -v tmpfs | head -5

# 文件系统统计
echo "\n2. 文件系统使用情况:"
df -h | head -5

# inode使用情况
echo "\n3. inode使用情况:"
df -i | head -5
}

# 7. 网络调试信息
network_debug_info() {
echo "=== 网络调试信息 ==="

# 网络接口统计
echo "1. 网络接口统计:"
cat /proc/net/dev | head -5

# 网络连接
echo "\n2. 网络连接统计:"
ss -s

# 网络协议统计
echo "\n3. 网络协议统计:"
cat /proc/net/snmp | grep -E "(Tcp|Udp|Ip):" | head -4
}

# 8. 内核配置检查
kernel_config_check() {
echo "=== 内核配置检查 ==="

# 检查内核配置文件
if [ -r /proc/config.gz ]; then
echo "1. 内核配置可用 (/proc/config.gz)"
zcat /proc/config.gz | grep -E "CONFIG_(DEBUG|KASAN|LOCKDEP)" | head -5
elif [ -r "/boot/config-$(uname -r)" ]; then
echo "1. 内核配置可用 (/boot/config-$(uname -r))"
grep -E "CONFIG_(DEBUG|KASAN|LOCKDEP)" "/boot/config-$(uname -r)" | head -5
else
echo "1. 内核配置文件不可用"
fi

# 检查调试功能
echo "\n2. 调试功能检查:"
if [ -d /sys/kernel/debug ]; then
echo " debugfs: 已挂载"
ls /sys/kernel/debug/ | head -5
else
echo " debugfs: 未挂载"
fi
}

# 9. 性能分析工具
performance_analysis() {
echo "=== 性能分析工具 ==="

# CPU使用情况
echo "1. CPU使用情况:"
top -bn1 | head -5

# 负载平均值
echo "\n2. 系统负载:"
uptime

# I/O统计
echo "\n3. I/O统计:"
if command -v iostat >/dev/null 2>&1; then
iostat -x 1 1 | tail -5
else
echo " iostat 未安装"
fi
}

# 10. 内核崩溃分析
kernel_crash_analysis() {
echo "=== 内核崩溃分析 ==="

# 检查内核崩溃转储
echo "1. 内核崩溃转储检查:"
if [ -d /var/crash ]; then
echo " 崩溃转储目录存在: /var/crash"
ls -la /var/crash/ 2>/dev/null | head -5
else
echo " 崩溃转储目录不存在"
fi

# 检查系统重启原因
echo "\n2. 系统重启历史:"
last reboot | head -5

# 检查内核panic信息
echo "\n3. 内核panic信息:"
dmesg | grep -i "panic\|oops\|bug" | tail -3
}

# 主函数
main() {
echo "Linux内核调试工具集"
echo "==================="
echo "开始时间: $(date)"
echo

kernel_log_analysis
echo
kernel_symbols_analysis
echo
memory_debug_info
echo
process_debug_info
echo
interrupt_debug_info
echo
filesystem_debug_info
echo
network_debug_info
echo
kernel_config_check
echo
performance_analysis
echo
kernel_crash_analysis

echo
echo "调试信息收集完成: $(date)"
}

# 如果直接运行脚本
if [ "${BASH_SOURCE[0]}" = "${0}" ]; then
main "$@"
fi

6.2 GDB内核调试

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
#!/bin/bash
# gdb_kernel_debug.sh - GDB内核调试脚本

# GDB内核调试配置和使用

# 1. 准备调试环境
setup_debug_environment() {
echo "=== 设置内核调试环境 ==="

# 检查内核调试符号
echo "1. 检查内核调试符号:"
if [ -f "/usr/lib/debug/boot/vmlinux-$(uname -r)" ]; then
echo " 调试符号文件存在: /usr/lib/debug/boot/vmlinux-$(uname -r)"
elif [ -f "/boot/vmlinux-$(uname -r)" ]; then
echo " 内核镜像存在: /boot/vmlinux-$(uname -r)"
else
echo " 警告: 未找到内核调试符号"
fi

# 检查GDB
echo "\n2. 检查GDB版本:"
if command -v gdb >/dev/null 2>&1; then
gdb --version | head -1
else
echo " 错误: GDB未安装"
return 1
fi

# 检查KGDB支持
echo "\n3. 检查KGDB支持:"
if grep -q "CONFIG_KGDB=y" "/boot/config-$(uname -r)" 2>/dev/null; then
echo " KGDB: 已启用"
else
echo " KGDB: 未启用或配置文件不可用"
fi
}

# 2. 创建GDB脚本
create_gdb_scripts() {
echo "=== 创建GDB调试脚本 ==="

# 创建基本的GDB脚本
cat > kernel_debug.gdb << 'EOF'
# GDB内核调试脚本

# 设置架构
set architecture i386:x86-64

# 连接到内核
# target remote /dev/ttyS0 # 串口调试
# target remote localhost:1234 # QEMU调试

# 有用的内核调试命令
define ps
set $tasks_off = ((size_t)&((struct task_struct *)0)->tasks)
set $pid_off = ((size_t)&((struct task_struct *)0)->pid)
set $comm_off = ((size_t)&((struct task_struct *)0)->comm)
set $init_t = &init_task
set $next_t = (struct task_struct *)((char *)($init_t->tasks.next) - $tasks_off)
while ($next_t != $init_t)
printf "PID: %d COMM: %s\n", *((int *)((char *)$next_t + $pid_off)), ((char *)$next_t + $comm_off)
set $next_t = (struct task_struct *)((char *)($next_t->tasks.next) - $tasks_off)
end
end

# 显示当前进程
define current_task
p *((struct task_struct *)$lx_current())
end

# 显示内核栈
define kstack
bt
end

# 显示寄存器
define kregs
info registers
end

# 内存映射
define vmmap
info proc mappings
end

EOF

echo "GDB脚本已创建: kernel_debug.gdb"

# 创建内核模块调试脚本
cat > module_debug.gdb << 'EOF'
# 内核模块调试脚本

# 加载模块符号
define load_module_symbols
if $argc != 1
help load_module_symbols
else
add-symbol-file $arg0
end
end

document load_module_symbols
加载内核模块的调试符号
用法: load_module_symbols <module.ko>
end

# 显示模块信息
define module_info
set $mod = modules.next
while ($mod != &modules)
set $m = (struct module *)$mod
printf "Module: %s, State: %d, Base: 0x%lx\n", $m->name, $m->state, $m->module_core
set $mod = $mod->next
end
end

EOF

echo "模块调试脚本已创建: module_debug.gdb"
}

# 3. QEMU内核调试
qemu_kernel_debug() {
echo "=== QEMU内核调试设置 ==="

cat << 'EOF'
QEMU内核调试步骤:

1. 启动QEMU时添加调试选项:
qemu-system-x86_64 -kernel vmlinuz -initrd initrd.img \
-append "console=ttyS0 kgdboc=ttyS0,115200 kgdbwait" \
-serial stdio -s -S

2. 在另一个终端启动GDB:
gdb vmlinux
(gdb) target remote localhost:1234
(gdb) continue

3. 常用调试命令:
(gdb) break start_kernel # 在内核启动函数设置断点
(gdb) break do_fork # 在进程创建函数设置断点
(gdb) info threads # 显示所有线程
(gdb) thread 2 # 切换到线程2
(gdb) bt # 显示调用栈
(gdb) info registers # 显示寄存器
(gdb) x/10i $pc # 显示当前指令
(gdb) watch variable # 监视变量变化
EOF
}

# 4. 内核模块调试
module_debugging() {
echo "=== 内核模块调试 ==="

cat << 'EOF'
内核模块调试方法:

1. 编译时启用调试信息:
EXTRA_CFLAGS += -g -DDEBUG

2. 使用printk调试:
printk(KERN_DEBUG "Debug: %s\n", __func__);

3. 使用动态调试:
echo 'module mymodule +p' > /sys/kernel/debug/dynamic_debug/control

4. 使用ftrace:
echo function > /sys/kernel/debug/tracing/current_tracer
echo mymodule_function > /sys/kernel/debug/tracing/set_ftrace_filter

5. 使用kprobe:
echo 'p:myprobe mymodule_function' > /sys/kernel/debug/tracing/kprobe_events
echo 1 > /sys/kernel/debug/tracing/events/kprobes/myprobe/enable
EOF
}

# 5. 内核崩溃调试
crash_debugging() {
echo "=== 内核崩溃调试 ==="

cat << 'EOF'
内核崩溃调试工具:

1. 使用crash工具分析vmcore:
crash /usr/lib/debug/boot/vmlinux-$(uname -r) /var/crash/vmcore

2. crash常用命令:
crash> bt # 显示调用栈
crash> ps # 显示进程列表
crash> log # 显示内核日志
crash> mod # 显示模块信息
crash> files # 显示文件信息
crash> net # 显示网络信息
crash> vm # 显示虚拟内存信息

3. 分析oops信息:
- 查找RIP地址对应的函数
- 分析调用栈
- 检查寄存器状态
- 查看内存转储
EOF
}

# 主函数
main() {
echo "GDB内核调试指南"
echo "==============="
echo

setup_debug_environment
echo
create_gdb_scripts
echo
qemu_kernel_debug
echo
module_debugging
echo
crash_debugging
}

# 如果直接运行脚本
if [ "${BASH_SOURCE[0]}" = "${0}" ]; then
main "$@"
fi

七、最佳实践与总结

7.1 内核编程最佳实践

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
// best_practices.c - 内核编程最佳实践示例
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/errno.h>
#include <linux/mutex.h>
#include <linux/completion.h>
#include <linux/workqueue.h>

// 模块信息 - 必须包含
MODULE_LICENSE("GPL"); // 许可证
MODULE_AUTHOR("Your Name <email@domain.com>"); // 作者
MODULE_DESCRIPTION("Best practices example"); // 描述
MODULE_VERSION("1.0.0"); // 版本
MODULE_ALIAS("best_practices"); // 别名

// 最佳实践1: 使用适当的错误码
#define BP_SUCCESS 0
#define BP_ERROR_NOMEM -ENOMEM
#define BP_ERROR_INVALID -EINVAL
#define BP_ERROR_BUSY -EBUSY

// 最佳实践2: 定义清晰的数据结构
struct best_practices_device {
struct mutex lock; // 互斥锁保护
struct completion ready; // 完成量
struct workqueue_struct *wq; // 工作队列
void *buffer; // 数据缓冲区
size_t buffer_size; // 缓冲区大小
atomic_t ref_count; // 引用计数
bool initialized; // 初始化标志
};

static struct best_practices_device *bp_device;

// 最佳实践3: 使用内联函数提高性能
static inline bool bp_device_is_ready(struct best_practices_device *dev)
{
return dev && dev->initialized;
}

static inline void bp_device_get(struct best_practices_device *dev)
{
if (dev)
atomic_inc(&dev->ref_count);
}

static inline void bp_device_put(struct best_practices_device *dev)
{
if (dev && atomic_dec_and_test(&dev->ref_count)) {
// 引用计数为0时的清理工作
complete(&dev->ready);
}
}

// 最佳实践4: 错误处理和资源清理
/**
* bp_allocate_buffer - 分配缓冲区
* @dev: 设备结构指针
* @size: 缓冲区大小
*
* 返回值: 0表示成功,负值表示错误码
*/
static int bp_allocate_buffer(struct best_practices_device *dev, size_t size)
{
void *buffer;

// 参数验证
if (!dev || size == 0 || size > PAGE_SIZE * 16) {
pr_err("bp: Invalid parameters for buffer allocation\n");
return BP_ERROR_INVALID;
}

// 检查设备状态
if (!bp_device_is_ready(dev)) {
pr_err("bp: Device not ready\n");
return BP_ERROR_BUSY;
}

// 获取锁
if (mutex_lock_interruptible(&dev->lock)) {
pr_debug("bp: Buffer allocation interrupted\n");
return -ERESTARTSYS;
}

// 检查是否已分配
if (dev->buffer) {
pr_warn("bp: Buffer already allocated\n");
mutex_unlock(&dev->lock);
return BP_ERROR_BUSY;
}

// 分配内存
buffer = kzalloc(size, GFP_KERNEL);
if (!buffer) {
pr_err("bp: Failed to allocate buffer of size %zu\n", size);
mutex_unlock(&dev->lock);
return BP_ERROR_NOMEM;
}

// 设置设备状态
dev->buffer = buffer;
dev->buffer_size = size;

mutex_unlock(&dev->lock);

pr_info("bp: Buffer allocated successfully, size: %zu\n", size);
return BP_SUCCESS;
}

/**
* bp_free_buffer - 释放缓冲区
* @dev: 设备结构指针
*/
static void bp_free_buffer(struct best_practices_device *dev)
{
if (!dev)
return;

mutex_lock(&dev->lock);

if (dev->buffer) {
kfree(dev->buffer);
dev->buffer = NULL;
dev->buffer_size = 0;
pr_info("bp: Buffer freed\n");
}

mutex_unlock(&dev->lock);
}

// 最佳实践5: 工作队列处理
static void bp_work_handler(struct work_struct *work)
{
struct best_practices_device *dev = bp_device;

if (!bp_device_is_ready(dev)) {
pr_err("bp: Device not ready in work handler\n");
return;
}

bp_device_get(dev);

// 执行实际工作
pr_info("bp: Work handler executing\n");

// 模拟一些工作
msleep(100);

bp_device_put(dev);
pr_info("bp: Work handler completed\n");
}

static DECLARE_WORK(bp_work, bp_work_handler);

// 最佳实践6: 设备初始化和清理
/**
* bp_device_create - 创建设备
*
* 返回值: 设备指针或错误指针
*/
static struct best_practices_device *bp_device_create(void)
{
struct best_practices_device *dev;
int ret;

// 分配设备结构
dev = kzalloc(sizeof(*dev), GFP_KERNEL);
if (!dev) {
pr_err("bp: Failed to allocate device structure\n");
return ERR_PTR(BP_ERROR_NOMEM);
}

// 初始化同步原语
mutex_init(&dev->lock);
init_completion(&dev->ready);
atomic_set(&dev->ref_count, 1);

// 创建工作队列
dev->wq = create_singlethread_workqueue("bp_workqueue");
if (!dev->wq) {
pr_err("bp: Failed to create workqueue\n");
ret = BP_ERROR_NOMEM;
goto err_free_dev;
}

// 分配默认缓冲区
ret = bp_allocate_buffer(dev, PAGE_SIZE);
if (ret) {
pr_err("bp: Failed to allocate default buffer\n");
goto err_destroy_wq;
}

dev->initialized = true;
complete(&dev->ready);

pr_info("bp: Device created successfully\n");
return dev;

err_destroy_wq:
destroy_workqueue(dev->wq);
err_free_dev:
kfree(dev);
return ERR_PTR(ret);
}

/**
* bp_device_destroy - 销毁设备
* @dev: 设备结构指针
*/
static void bp_device_destroy(struct best_practices_device *dev)
{
if (!dev)
return;

pr_info("bp: Destroying device\n");

// 标记设备为未初始化
dev->initialized = false;

// 取消所有工作
if (dev->wq) {
cancel_work_sync(&bp_work);
destroy_workqueue(dev->wq);
pr_info("bp: Workqueue destroyed\n");
}

// 释放缓冲区
bp_free_buffer(dev);

// 等待所有引用释放
bp_device_put(dev);
wait_for_completion(&dev->ready);

// 释放设备结构
kfree(dev);
pr_info("bp: Device destroyed\n");
}

// 最佳实践7: 模块参数
static int buffer_size = PAGE_SIZE;
module_param(buffer_size, int, 0644);
MODULE_PARM_DESC(buffer_size, "Default buffer size (default: PAGE_SIZE)");

static bool enable_work = true;
module_param(enable_work, bool, 0644);
MODULE_PARM_DESC(enable_work, "Enable work queue processing (default: true)");

/**
* best_practices_init - 模块初始化函数
*
* 返回值: 0表示成功,负值表示失败
*/
static int __init best_practices_init(void)
{
int ret;

pr_info("bp: Loading best practices module\n");
pr_info("bp: Buffer size: %d, Enable work: %s\n",
buffer_size, enable_work ? "yes" : "no");

// 验证模块参数
if (buffer_size <= 0 || buffer_size > PAGE_SIZE * 16) {
pr_err("bp: Invalid buffer size: %d\n", buffer_size);
return BP_ERROR_INVALID;
}

// 创建设备
bp_device = bp_device_create();
if (IS_ERR(bp_device)) {
ret = PTR_ERR(bp_device);
pr_err("bp: Failed to create device: %d\n", ret);
return ret;
}

// 调度工作(如果启用)
if (enable_work) {
queue_work(bp_device->wq, &bp_work);
pr_info("bp: Work scheduled\n");
}

pr_info("bp: Module loaded successfully\n");
return BP_SUCCESS;
}

/**
* best_practices_exit - 模块清理函数
*/
static void __exit best_practices_exit(void)
{
pr_info("bp: Unloading best practices module\n");

// 销毁设备
bp_device_destroy(bp_device);
bp_device = NULL;

pr_info("bp: Module unloaded successfully\n");
}

// 最佳实践8: 使用适当的初始化和清理宏
module_init(best_practices_init);
module_exit(best_practices_exit);

7.2 开发总结与建议

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
# Linux内核编程开发总结

## 核心要点

### 1. 安全编程原则
- **永远检查返回值**: 所有函数调用都要检查返回值
- **正确的错误处理**: 使用标准错误码,确保资源正确释放
- **边界检查**: 防止缓冲区溢出和数组越界
- **空指针检查**: 在解引用前检查指针有效性

### 2. 内存管理
- **配对使用**: kmalloc/kfree, vmalloc/vfree, get_page/put_page
- **避免内存泄漏**: 确保所有分配的内存都被释放
- **使用合适的分配函数**: 根据需求选择kmalloc、vmalloc或页面分配
- **DMA内存**: 使用dma_alloc_coherent进行DMA内存分配

### 3. 同步机制
- **选择合适的锁**: 根据临界区大小选择自旋锁或互斥锁
- **避免死锁**: 按固定顺序获取多个锁
- **最小化锁持有时间**: 减少锁竞争
- **使用原子操作**: 简单操作优先使用原子操作

### 4. 中断处理
- **快速处理**: 中断处理程序要尽可能快
- **使用工作队列**: 耗时操作放到工作队列中
- **正确的中断标志**: 使用IRQF_SHARED等适当标志
- **中断安全**: 在中断上下文中不能睡眠

### 5. 调试技巧
- **使用printk**: 合理使用不同级别的printk
- **动态调试**: 利用dynamic debug功能
- **内核调试器**: 掌握GDB和crash工具
- **静态分析**: 使用sparse等静态分析工具

## 常见陷阱

### 1. 上下文错误
- 在原子上下文中调用可能睡眠的函数
- 在中断处理程序中使用GFP_KERNEL
- 在持有自旋锁时调用schedule()

### 2. 竞态条件
- 未正确保护共享数据
- 检查后使用(TOCTOU)问题
- 不正确的引用计数

### 3. 资源泄漏
- 忘记释放分配的内存
- 未正确清理定时器和工作队列
- 中断未正确释放

## 性能优化

### 1. 内存优化
- 使用slab分配器进行频繁的小对象分配
- 避免内存碎片
- 合理使用缓存对齐

### 2. CPU优化
- 减少上下文切换
- 使用per-CPU变量
- 避免不必要的内存屏障

### 3. I/O优化
- 使用异步I/O
- 批量处理请求
- 合理使用缓存

## 代码质量

### 1. 编码规范
- 遵循Linux内核编码风格
- 使用有意义的变量和函数名
- 添加适当的注释

### 2. 模块化设计
- 功能单一原则
- 清晰的接口定义
- 合理的抽象层次

### 3. 测试
- 单元测试
- 压力测试
- 边界条件测试

## 学习建议

### 1. 理论基础
- 深入理解操作系统原理
- 掌握计算机体系结构
- 学习并发编程理论

### 2. 实践经验
- 阅读内核源码
- 参与开源项目
- 编写实际的驱动程序

### 3. 持续学习
- 关注内核发展动态
- 学习新的内核特性
- 参加技术会议和讨论

## 总结

Linux内核编程是一个复杂而富有挑战性的领域,需要扎实的理论基础和丰富的实践经验。通过本指南的学习,你应该已经掌握了内核编程的基本概念、核心技术和最佳实践。

记住,内核编程的关键在于:
- **安全第一**: 确保代码的稳定性和安全性
- **性能优化**: 追求高效的代码实现
- **代码质量**: 编写可维护和可扩展的代码
- **持续学习**: 跟上内核技术的发展步伐

希望这个指南能够帮助你在Linux内核编程的道路上取得成功!

通过本文的学习,我们全面掌握了Linux内核编程与驱动开发的核心技能,从基础的内核模块开发到高级的同步机制,从设备驱动框架到调试技巧,为深入理解Linux内核奠定了坚实的基础。内核编程需要严谨的态度和持续的实践,希望这个完整的学习路径能够帮助你成为优秀的内核开发者。

本站由 提供部署服务