前言

  • Linux内核架构非常庞大,为了避免修改轮子要重新造车的情况,诞生了模块(module),也叫驱动,驱动文件一般以ko结尾,所以也被写作“驱动ko”,详细内容这里不介绍
  • 本文主要列出一个简单的demo

源文件

  • 驱动相关的源文件最简单的结构需要两个,一个c代码文件,另一个是makefile
  • 一般情况下,两个文件在同一个目录下,至于放在哪里,这个无所谓

hello work c code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#include <linux/kernel.h>
#include <linux/module.h>

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

static void __exit hello_exit(void)
{
printk("hello world rmmod \n ");
}

module_init(hello_init);
module_exit(hello_exit);

MODULE_AUTHOR("zhuizhutime");
MODULE_VERSION("0.1");
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("test hello world");
  • 模块加载
    当模块被加载的时候会执行init函数,也就是通过module_init()方法注册的函数,而且函数需要有__init标记,一般用来做模块的初始化,这里如果卡住,则会导致驱动加载命令卡住,返回0表示加载成功。
  • 模块卸载
    模块被卸载的时候会执行exit函数,也就是通过module_exit()方法注册的函数,函数需要有__exit标记,一般用来做资源释放和一些打印信息等
  • 模块声明
    可以通过标记的形式进行声明一些信息:
    声明 说明
    MODULE_LICENSE 声明许可证:一般包括 “GPL”、“GPL v2”、“GPLand additional rights”、“Dual BSD/GPL”、“Dual
    MODULE_AUTHOR 作者信息,姓名,邮箱等
    MODULE_DESCRIPTION 驱动说明
    MODULE_VERSION 版本号
    MODULE_DEVICE_TABLE 设备列表
    MODULE_ALIAS 别名

makefile

Ubuntu 24.04 x86_64平台

1
2
3
4
5
6
7
8
9
10
11
KVERS := /lib/modules/$(shell uname -r)/build
CURDIR := $(shell pwd)

# 这里的hello.o是对应c文件hello.c
obj-m := hello.o

build:
make -C $(KVERS) M=$(CURDIR) modules

clean:
make -C $(KVERS) M=$(CURDIR) clean
  • 该Makefile文件中,buildclean下的内容行开头的空隙必须为<tab>,否则编译会出错
  • -C选项将工作目录转到$(KVERS)指定的目录下,该目录下有内核顶层的Makefile
  • M=选项是把当前路径,传递到内核顶层的Makefile,要求在建立内核模块前,回到指定的路径

编译

直接使用make命令就可以进行编译,如果是普通用户,需要使用sudo进行提权
create module

使用

  • 通过insmod或者modprobe进行驱动的加载
  • 通过rmmod或者modprobe -r进行驱动的卸载

load module

使用时可能会报错

  • Key was rejected by service
    load module fail
    这是因为做出的驱动默认是没有签名的,如果环境开了强制签名校验,则不允许通过
    我这里是因为bios中开启了Secure Boot,重启进入BIOS将其关闭就可以了
    当然如果给该驱动进行签名,也可以解决问题,可以参考这篇文章:Ubuntu下给驱动签名

参考