「Linux」- 内核模块编程

问题描述

我们将要学习 Linux Kernel Module 的开发方法,以为学习 Linux Kernel 做准备。

该笔记将记录:Linux Kernel Module 的开发方法,旨在快速入门,以及常见问题处理方案。

解决方案

Kernel Module 是已编译的二进制程序,直接插入到 Linux Kernle 中运行。

Kernel Module 运行在 RING0 中,在 x86 CPU 中最低且受保护最少的运行级别。这里的代码完全不受检查地运行,但运行速度令人难以置信,并且可以访问系统的所有内容。

准备工作

1)操作系统:虚拟机或独立运行的 Linux 发行版,用于内核代码测试;应避免在当前系统中直接测试内容,否则可能会导致系统崩溃、数据丢失等等问题;
2)编程语言:需要懂得些 C 语言编程;懂得 Linux Shell 命令行等等工具的使用方法;如果懂得硬件知识或汇编语言会更加的有帮助;

安装开发环境

我们使用 Eclipse 作为开发工具,

我们在 Ubuntu 20.04 TLS 中进行开发工作,需要安装如下包:

apt-get install build-essential                    # 安装编译器、调试器、库、其他工具
                                                   # Depends: libc6-dev | libc-dev, gcc (>= 4:9.2), g++ (>= 4:9.2), make, dpkg-dev (>= 1.17.11)
apt-get install linux-headers-`uname -r`           # 安装内核头文件

模块开发

第一步、编写代码

lkm_example.c

// 用于模块开发的头文件
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>

// 模块描述信息
MODULE_LICENSE("GPL");
MODULE_AUTHOR("k4nz@d3rm.org");
MODULE_DESCRIPTION("A simple example Linux module.");
MODULE_VERSION("0.01");

// 模块初始函数
static int __init lkm_example_init(void) {
	printk(KERN_INFO "Hello, World!\n");
	return 0;
}

// 模块退出函数
static void __exit lkm_example_exit(void) {
	printk(KERN_INFO "Goodbye, World!\n");
}

// 模块加载与卸载
module_init(lkm_example_init);
module_exit(lkm_example_exit);

第二步、编写 Makefile 文件

obj-m += lkm_example.o

all:
	make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules

clean:
	make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean
	
test:
	dmesg -C
	insmod lkm_example.ko
	rmmod lkm_example.ko
	dmesg

第三步、编译调试

# make test
dmesg -C
insmod lkm_example.ko
rmmod lkm_example.ko
dmesg
[ 1692.496320] Hello, World!
[ 1692.502960] Goodbye, World!

参考文献

How to Install GCC (build-essential) on Ubuntu 20.04 | Linuxize
Writing a Simple Linux Kernel Module | by Robert W. Oliver II | Sourcerer Blog