📜  可加载内核模块 - Linux 设备驱动程序开发(1)

📅  最后修改于: 2023-12-03 14:50:38.449000             🧑  作者: Mango

可加载内核模块 - Linux 设备驱动程序开发

什么是可加载内核模块?

可加载内核模块,简称内核模块(kernel module),是 Linux 系统中能够在运行时动态加载和卸载的内核对象。内核模块包含了系统的某些功能,例如驱动程序,文件系统等等。

内核模块的优点在于减小了内核的大小,并且可以在运行时根据需要加载和卸载,从而灵活地扩展系统的功能。内核模块的开发需要使用 C 语言,并且需要对内核的各个模块有一定的了解。

如何编写可加载内核模块?

编写内核模块的步骤如下所示:

  1. 创建模块源文件 *.c。此文件应该包含与模块有关的定义、变量、函数、结构等信息。
  2. 使用 Makefile 构建模块。Makefile 文件通常包含编译内核模块所需的指令和编译参数。
  3. 使用 insmod 命令加载模块。该命令会在内核中加载模块,并提供与其交互的接口。
  4. 使用 rmmod 命令卸载模块。该命令将从内核中卸载模块,以释放系统资源。

下面是一个简单的例子,用于向系统的 /proc 文件系统中写入 HelloWorld 消息:

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/proc_fs.h>

static struct proc_dir_entry *proc_entry; // proc 文件系统条目

/**
 * 将此函数绑定到 /proc/helloworld 中
 */ 
static int my_proc_show(struct seq_file *m, void *v)
{
    seq_printf(m, "Hello World!\n");
    return 0;
}

/**
 * 模块加载函数:注册 HelloWorld 到 /proc
 */ 
static int __init my_module_init(void)
{
    proc_entry = proc_create("helloworld", 0644, NULL, &my_proc_show);
    printk(KERN_INFO "Hello World module loaded\n");
    return 0;
}

/**
 * 模块卸载函数:从 /proc 中移除 HelloWorld
 */ 
static void __exit my_module_exit(void)
{
    proc_remove(proc_entry);
    printk(KERN_INFO "Hello World module unloaded\n");
}

module_init(my_module_init);
module_exit(my_module_exit);

MODULE_AUTHOR("Your Name");
MODULE_LICENSE("GPL"); // 模块授权类型

使用以下 Makefile 文件编译此内核模块:

obj-m := helloworld.o
KERNEL_DIR ?= /lib/modules/$(shell uname -r)/build
PWD := $(shell pwd)

all:
    make -C $(KERNEL_DIR) M=$(PWD) modules

clean:
    make -C $(KERNEL_DIR) M=$(PWD) clean
如何使用内核模块?

当加载完成内核模块后,可以使用 lsmod 命令列出当前加载的模块。例如,使用以下命令加载 helloworld 模块:

sudo insmod helloworld.ko

然后可以使用以下命令卸载该模块:

sudo rmmod helloworld

可以使用以下命令访问 /proc/helloworld 文件,获取我们之前编写的 HelloWorld 消息:

cat /proc/helloworld
结论

可加载内核模块是内核的重要组成部分,可以用于扩展和定制系统的功能。本文介绍了如何编写、构建和加载内核模块,并提供了示例代码和 Makefile 文件。