编译LINUX内核驱动程序

转载:https://zhuanlan.zhihu.com/p/434163532

实际操作一下:如何把一个最简单的驱动程序(hello),按照 2 种方式进行编译:

编译进内核;
编译为一个独立的驱动模块;

实践环境

为了便于测试,以下操作都是在 Ubuntu16.04 操作系统里完成的。

编译Linux驱动程序,肯定需要内核源码,这里选择的是 linux-4.15 版本,可以在官网下载。

文末有下载方式。

下载之后,把linux-4.15.tar.gz解压到Ubuntu中任意目录即可,例如:解压到~/tmp/目录下:

$ tar -zxvf linux-4.15.tar.gz -C ~/tmp/

编译进内核
创建驱动程序目录

linux中的驱动,一般都放在 linux-4.15/drivers/ 目录下,因此在这个目录中创建一个hello文件夹。

$ mkdir linux-4.15/drivers/hello

对于一个驱动来说,最重要的就是3个文件:

源代码
Kconfig
Makefile

只要按照固定的格式来编写这3个文件,linux内核的编译脚本就可以确保把我们的驱动程序编译进去。
创建源文件

首先是源码,在hello文件夹中创建源文件hello.c:

$ cd linux-4.15/drivers/hello
$ touch hello.c

源文件hello.c的内容是:

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

// 当驱动被加载的时候,执行此函数
static int __init hello_init(void)
{
printk(KERN_ALERT “welcome, hello”\n");
return 0;
}

// 当驱动被卸载的时候,执行此函数
static void __exit hello_exit(void)
{
printk(KERN_ALERT “bye, hello\n”);
}

// 版权声明
MODULE_LICENSE(“GPL”);

// 以下两个函数属于 Linux 的驱动框架,只要把驱动两个函数地址注册进去即可。
module_init(hello_init);
module_exit(hello_exit);

有两个小地方注意一下:

在内核中,打印函数是 printk,而不是 printf;
打印信息的级别有好几个,从 DEBUG 到 EMERG,这里使用的是 KERN_ALERT,方便查看打印信息。

创建 Kconfig 文件

这个文件是用来对内核进行配置的,当执行 make menuconfig 指令的时候,这个文件就被解析。

先创建文件:

$ cd linux-4.15/drivers/hello
$ touch Kconfig

添加如下内容:

config HELLO
tristate “hello driver”
help
just a simplest driver.
default y

第一行内容 config HELLO ,在执行配置的时候,将会生成一个变量 CONFIG_HELLO ,而这个变量,将会在编译的时候,被 Makefile 引用。

最后一行的 default y ,就表示把 CONFIG_HELLO 的值设置成 y,从而让这个驱动被编译到内核中。

现在,hello驱动中的KConfig配置文件已经准备好了,但是还需要这个配置文件登记到 Linux内核的整体配置文件中。

也就是把它登记在 linux-4.15/drivers/Kconfig 文件的末尾:

source “drivers/hello/Kconfig”

endmenu // 加在这一句的上面

现在,可以来执行下面指令,看一下具体的配置界面:

$ cd linux-4.15/
$ make distclean
$ make ARCH=x86_64 defconfig
$ make ARCH=x86_64 menuconfig

第2条指令,是用来把默认的配置保存到当前目录下的 .config 配置文件,也就是把一个默认的配置文件复制过来,作为我们自己的配置文件。

以后再修改配置参数时,修改的内容就会存储在 .config 文件中,

第3条指令,是用来配置内核的,可以进入 Device Drivers 菜单,然后在最底层看到我们的 hello driver 被标记成星号, 这表示被编译进内核。

按向下方向键,把高亮定位到 Device Drivers —> ,然后敲回车键,进入到 Device Drivers 的配置界面。

按向下方向键,一直到最后一个条目,就可以看到我们的 hello 驱动了,如下:

可以看到 hello driver 前面显示的是型号 *,这表示:该驱动将会编译进内核。

我们可以按下空格键试一下,会在三种标记中切换:型号,M,空值。M 标记意思是编译成驱动模块。

我们这里选择星号(编译进内核),然后按下右方向键,最下方的几个按键的焦点移动到 按钮上:

按下回车键,就会弹出保存对话框,选择默认保存文件 .config 即可,然后在 按钮高亮的时候,按下回车键即可保存。

此时,在弹出的确认窗口中,选择,按下回车键即可:

此时,返回到 Device Drivers 的配置界面,在最下面的按钮中,选择让高亮,然后一路退出即可。
创建 Makefile 文件

Makefile文件是make工具的脚本,首先创建它:

$ cd linux-4.15/drivers/hello
$ touch Makefile

其中的内容只有一行:

obj-$(CONFIG_HELLO) += hello.o

CONFIG_HELLO 可以看做一个变量,在编译的时候,这个变量的值可能是:y, n 或者 m。
在刚才的 Kconfig 参数配置中,CONFIG_HELLO 被设置为 y,于是这句话就被翻译成: obj-y += hello,表示把 hello 驱动编译进内核。

现在,hello驱动程序的Makefile已经创建好了,我们还要让linux内核的编译框架知道这个文件才行。

在文件 linux-4.15/drivers/Makefile 中的末尾,添加如下内容:

obj-$(CONFIG_HELLO) += hello/

编译

万事俱备,只欠编译!依次执行如下指令:

$ cd linux-4.15/
$ make -j4

make指令执行结束之后,编译得到的内核中(vmlinux)就包含了我们的hello驱动。
编译为驱动模块

编译为驱动模块,也有两种 操作方式:
编译所有的驱动模块

在执行 make ARCH=x86_64 menuconfig 指令的时候,把 hello 配置成 M;
然后在 linux-4.15 中执行编译模块指令:make -j4 modules。

编译成功之后,就可以得到文件: linux-4.15/drivers/hello/hello.ko。

这样的编译指令,是把所有的模块都编译了一次(在输出信息中,可以看到编译了很多模块)。
只编译 hello 这一个驱动模块

另外一种编译驱动模块的方式是:进入hello目录,只编译这一个驱动模块。

这种编译方法,就需要修改hello目录下的Makefile文件了,内容如下:

可以把 hello 目录下的所有文件删除,只保留源文件 hello.c,然后新建 Makefile 文件。

ifneq ( ( K E R N E L R E L E A S E ) , ) o b j − m : = h e l l o . o e l s e K E R N E L D I R ? = / l i b / m o d u l e s / (KERNELRELEASE),) obj-m := hello.o else KERNELDIR ?= /lib/modules/ (KERNELRELEASE),)objm:=hello.oelseKERNELDIR?=/lib/modules/(shell uname -r)/build
PWD := $(shell pwd)
default:
$(MAKE) -C ( K E R N E L D I R ) M = (KERNELDIR) M= (KERNELDIR)M=(PWD) modules
clean:
$(MAKE) -C ( K E R N E L P A T H ) M = (KERNEL_PATH) M= (KERNELPATH)M=(PWD) clean
endif

然后,在hello文件夹中执行make指令,即可得到驱动模块 hello.ko 。
验证一下

加载驱动:

$ cd linux-4.15/drivers/hello
$ sudo insmod ./hello.ko

此时终端窗口是没有任何输出的,需要输入指令 dmesg | tail ,可以看到 hello_init 函数的输出内容:

卸载驱动:

$ sudo rmmod hello

再次输入 dmesg | tail ,可以看到 hello_exit 函数的输出内容:

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值