1 环境
1.0 系统
1.1 依赖列
1.2 安装依赖
sudo apt-get build-essential kernel-package kernek-source libncurses5-dev libssl-dev libelf-dev
2 源文件获取与安装
2.1 获取
# 查看系统内核版本
uname -r
4.15.0-39-generic
# 获取源文件包
sudo apt-get install linux-source-4.15.0
# 文件包默认在/usr/src中
cd /usr/src
linux-source-4.15.0.bz2
# 解压至指定目录
sudo tar -jxvf linux-source-4.15.0.bz2 -C /path
# 进入源码包目录
cd path/linux-source-4.15.0
2.2 安装
# 编译
sudo make oldconfig
# 最耗时
sudo make
# 生成设备树
sudo make modules
sudo make modules_install
# 在lib/modules目录中生成设备树
cd /lib/modules
# 目录结构
|-- modules
|-- 4.15.0-29-generic
|-- 4.15.0-30-generic
|-- 4.15.0-32-generic
|-- 4.15.0-33-generic
|-- 4.15.0-34-generic
|-- 4.15.0-36-generic
|-- 4.15.0-39-generic
|-- 4.15.0-42-generic
`-- 4.15.18
3 测试
3.1 目录结构
DriverConfig
| `-- linux-source-4.15.0
`-- driverTest
|-- Makefile
`-- hello.c
3.2 hello.c
#include<linux/init.h>
#include<linux/module.h>
#include<linux/kernel.h>
MODULE_LICENSE("Dual BSD/GPL")
# 初始化
# KERN_ALERT设定printk日志级别,但X86无效
static int __init hello_init(void){
printk(KERN_ALERT "Hello, Xin Daqi!");
return 0;
}
# 退出
static void __exit hello_exit(void){
printk(KERN_ALERT "Goodbye!");
}
# 调用函数
module_init(hello_init);
module_exit(hello_exit);
3.3 Makefile V0
# 生成的模块名hello.o
obj-m:=hello.o
# 生成这个模块名需要的目标文件
# modules-objs:=hello.o
# 生成的设备树路径/lib/modules
# 其中$(shell uname -r)即获取内核版本,同uname -r
KERNELDIR:=/lib/modules/$(shell uname -r)/build
# 获取当前文件路径
# pwd即是获取路劲命令
PWD:=$(shell pwd)
# 编译
modules:
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules
3.4 Makefile V1
ifneq ($(KERNELRELEASE),)
mymodule-bojs := hello.o
obj-m := hello.o
else
PWD := $(shell pwd)
KERNELDIR = /lib/modules/$(shell uname -r)/build
all:
$(MAKE) -C $(KERNELDIR) M=$(PWD)
clean:
rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c
endif
3.5 编译
# 在driverTest目录下
make
# 提示信息
make -C /lib/modules/4.15.0-39-generic/build M=/home/xdq/xinPrj/Linux/driverTest modules
make[1]: 进入目录“/usr/src/linux-headers-4.15.0-39-generic”
CC [M] /home/xdq/xinPrj/Linux/driverTest/hello.o
Building modules, stage 2.
MODPOST 1 modules
CC /home/xdq/xinPrj/Linux/driverTest/hello.mod.o
LD [M] /home/xdq/xinPrj/Linux/driverTest/hello.ko
make[1]: 离开目录“/usr/src/linux-headers-4.15.0-39-generic”
# 生成文件目录结构
|-- DriverConfig
| `-- linux-source-4.15.0
`-- driverTest
|-- Makefile
|-- Module.symvers
|-- hello.c
|-- hello.ko
|-- hello.mod.c
|-- hello.mod.o
|-- hello.o
`-- modules.order
3.6 测试
# 加载驱动
sudo insmod hello.ko
# 终端输出
无输出
# 日志查看
/var/log/kern.log或dmesg
GoodBye!
# 查看加载的驱动
lsmod
# 卸载驱动
rmmod hello
Hello, Xin Daqi!
4 内核日志
4.1 日志级别
序号 | 描述 | 等级 | 说明 |
---|
1 | KERN_EMERG | 0 | 突发性事件消息,通常在系统崩溃之前报告此类信息 |
2 | KERN_ALERT | 1 | 需要立即操作的情况下使用此消息 |
3 | KERN_CRIT | 2 | 临界条件,遇到严重软硬件错误时使用 |
4 | KERN_ERR | 3 | 报告错误条件,设备驱动经常使用该级别报告硬件问题 |
5 | KERN_WARNING | 4 | 问题警告,一般不会引起系统严重问题 |
6 | KERN_NOTICE | 5 | 普通通知,许多安全性相关的情况会使用这个级别报告 |
7 | KERN_INFO | 6 | 信息,驱动程序启动时获取硬件信息 |
8 | KERN_DEBUG | 7 | 调试信息 |
4.2 打印日志配置
# 日志级别目录
/proc/sys/kernel/printk
# 查看级别
cat /proc/sys/kernel/printk
4 4 1 7
序号 | 级别 | 说明 |
---|
1 | 4 | 内核打印函数printk的打印级别,只有级别比他高的信息才能在控制台打印,即0-3级别 |
2 | 4 | 默认消息日志级别,该优先级打印没有优先级的消息 |
3 | 1 | 最低的控制台日志级别,控制台日志级别可别设置的最小值(最高优先级) |
4 | 7 | 默认的控制台日志级别,控制台日志级别的缺省值 |
# 修改日志级别
dmesg -n 8
# 权限不够
echo 8 >/proc/sys/kernel/printk
# 使用sudo依旧权限不够
sudo echo 8 > printk
# 终极大招
sudo sh -c 'echo 8 > printk'
# X86_64机器依旧不能显示printk信息
# 只能通过日志文件了dmesg最方便
dmesg
GoogBye!
Hello, Xin Daqi!
5 问题
scripts/sign-file.c:25:10: fatal error: openssl/opensslv.h: 没有那个文件或目录
#include <openssl/opensslv.h>
sudo apt-get install libssl-dev
scripts/Makefile.build:504: recipe for target 'scripts/basic/modules.order' failed
make[1]: *** [scripts/basic/modules.order] Error 2
Makefile:488: recipe for target 'scripts_basic' failed
make: *** [scripts_basic] Error 2
sudo apt-get install libelf-dev
cannot create scripts/basic/modules.order: Permission denied
sudo make modules
arch/x86/Makefile:156: CONFIG_X86_X32 enabled but no binutils support
sudo make modules
make-C /lib/models/4.15.0-39-generic/build M=/home/xdq/xinPrj/Linux/driverTest modules
make: make-C: Command not found
Makefile:5: recipe for target 'modules' failed
make: *** [modules] Error 127
Makefile:2: *** 遗漏分隔符 (null)。 停止。
- 解决
查找Makefile中ifneq后是否有空格,及其他语句空格
6 总结
- 明确部署系统的配置,安装相应依赖及核心文件;
- 日志信息在X86平台不能终端输出,需查看日志文件;
- 调试过程注意语法格式,规范编码;
- 记录异常信息,做好笔记,方便后续查阅;
- 积累,就是练本事。
[参考文献]
[1]https://blog.csdn.net/liufei191010/article/details/80826906
[2]https://blog.csdn.net/wr132/article/details/73825888
[3]https://www.cnblogs.com/wmx-learn/p/5344821.html