写一个 Linux 内核 hello world 模块

本文介绍如何一步步写一个 Linux 内核 hello world 模块.

内核模块分类

分为如下2类:

  1. Builtin modules 内置模块, 包含在 Linux image 里面
  2. External modules 外部模块, 可以随时加载/卸载的内核模块.
    本文例子中的模块属于 外部模块.

Kernel Build System

更多 Linux 内核 Kbuild 系统的更多信息, 参看官方文档.

hello world 内核模块

创建一个 hello.c 文件. 源代码如下:

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

static int __init hello_init(void)
{
    printk(KERN_ALERT "hello world\n");
    return 0;
}

static void __exit hello_exit(void)
{
    printk(KERN_ALERT "goodbye\n");
}

module_init(hello_init);
module_exit(hello_exit);

MODULE_DESCRIPTION("my first module");
MODULE_LICENSE("free");
MODULE_AUTHOR("Eric Tian");

设置内核 build 环境

安装 Kernel header: 找到对应的包, 然后安装, 然后查看安装的包.

$ apt search linux-headers-$(uname -r)
$ sudo apt install linux-headers-$(uname -r)

$ file /lib/modules/$(uname -r)/build
/lib/modules/5.15.92/build: symbolic link to /home/supra/work/jammy/jammy-Ubuntu-5.15.0-70.77-test

Makefile

在 hello.c 相同的目录, 创建一个新文件 Makefile. 内容如下, 缩进符号使用 tab.

obj-m += hello.o

tag ?= `uname -r`
KDIR := /lib/modules/${tag}/build/

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

clean:
    make -C $(KDIR) M=$(PWD) clean

编译运行

$ make clean
$ make all
make -C /lib/modules/`uname -r`/build/ M=/home/supra/work/c/kernel modules
make[1]: Entering directory '/usr/src/linux-headers-5.15.0-76-generic'
  CC [M]  /home/supra/work/c/kernel/hello.o
  MODPOST /home/supra/work/c/kernel/Module.symvers
  CC [M]  /home/supra/work/c/kernel/hello.mod.o
  LD [M]  /home/supra/work/c/kernel/hello.ko
  BTF [M] /home/supra/work/c/kernel/hello.ko
Skipping BTF generation for /home/supra/work/c/kernel/hello.ko due to unavailability of vmlinux
make[1]: Leaving directory '/usr/src/linux-headers-5.15.0-76-generic'

查看模块信息

$ modinfo hello.ko
modinfo hello.ko
filename:       /home/supra/work/c/kernel/hello.ko
author:         Eric Tian
license:        free
description:    my first module
srcversion:     01F8F75DC7D8708707AA062
depends:
retpoline:      Y
name:           hello
vermagic:       5.15.0-76-generic SMP mod_unload modversions

运行模块

$ sudo insmod hello.ko
insmod: ERROR: could not insert module hello.ko: Operation not permitted

虽然你用了 sudo, 仍然得到上面的错误, 原因很可能是: Check if your system has secure boot enabled, which can prevent loading unsigned kernel modules. Disable secure boot in your system's BIOS/UEFI settings and try again.

解决上述问题后, 执行 insmod 然后通过 dmesg 查看日志信息.

$ sudo insmod hello.ko
$ sudo dmesg 

[  176.149789] hello: loading out-of-tree module taints kernel.
[  176.149794] hello: module license 'free' taints kernel.
[  176.149794] Disabling lock debugging due to kernel taint
[  176.149815] hello: module verification failed: signature and/or required key missing - tainting kernel
[  176.150529] hello world

查看加载的模块信息

$ lsmod | grep hello
Module                    Size   Used by
hello                  16384  0

$ sudo cat /proc/modules | grep hello
hello 16384 0 - Live 0xffffffffc0797000 (POE)

卸载模块 并查看 exit 日志

$ sudo rmmod hello
$ tail -n 10 /var/log/syslog
Jul 10 12:16:14 supra kernel: [  596.219986] goodbye

标签: none

添加新评论