7. 编译驱动进内核¶
7.1. 分析内核源码的Kconfig和Makefile¶
关于Kconfig和Makefile文件的作用,在前面的 《kernel menuconfig》 章节中做了介绍,这里就简单概述一下。
Kconfig 文件主要是用来提供menuconfig菜单选项的。
Makefile 文件用于源码编译的。
下面将以下面这几个文件进行分析:
/kernel/Makefile
/kernel/Kconfig
/kernel/drivers/Makefile
/kernel/drivers/Kconfig
/kernel/drivers/char/Makefile
/kernel/drivers/char/Kconfig
/kernel/drivers/tty/Makefile
/kernel/drivers/tty/Kconfig
7.1.1. 分析内核源码的Kconfig¶
在上述所列文件基础上添加Kconfig调用关系,简化后可以表示成:
1 2 3 4 5 6 7 8 9 10 11 12 | kernel
├── drivers
| ├── char
| | ├── Makefile
| | └── Kconfig ─────┐ <────┐
| ├── tty | |
| | ├── Makefile |(3) |(2)
| | └── Kconfig <────┘ |
| ├── Makefile |
| └── Kconfig <────┐ ───────────┘
├── Makefile |(1)
└── Kconfig ──────────┘
|
下面以源码目录为例,针对性分析各Kconfig文件内容。
1 2 3 | ……
source "drivers/Kconfig"
……
|
1 2 3 4 5 | # SPDX-License-Identifier: GPL-2.0
menu "Device Drivers"
……
source "drivers/char/Kconfig"
……
|
1 2 3 4 | ……
menu "Character devices"
source "drivers/tty/Kconfig"
……
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | # SPDX-License-Identifier: GPL-2.0
config TTY
bool "Enable TTY" if EXPERT
default y
---help---
Allows you to remove TTY support which can save space, and
blocks features that require TTY from inclusion in the kernel.
TTY is required for any text terminals or serial port
communication. Most users should leave this enabled.
if TTY
config VT
bool "Virtual terminal" if EXPERT
depends on !UML
select INPUT
default y
---help---
……
……
endif # TTY
|
注意
上述文件中 menu "xxx"
可以理解为该文件的菜单名, config xxx
可以理解成菜单选项。drivers/tty/Kconfig文件中的 if TTY
和 endif
之间包含的选项表示当前面 TTY
这个选项被选中之后,被包含的选项才使能。
小练习:
在内核源码目录下 make ARCH=arm64 menuconfig
打开menuconfig配置界面,找到 tty
相关配置在哪个目录层级下,并思考menuconfig中选项名和Kconfig有什么关系。
7.1.2. 分析内核源码的Makefile¶
下面将以下面这几个文件进行分析:
/kernel/Makefile
/kernel/drivers/Makefile
/kernel/drivers/tty/Makefile
下面以源码目录为例,针对性分析各Makefile文件内容。
7.1.2.1. 顶层Makefile¶
/kernel/Makefile
为顶层Makefile,用于内核源码编译。当“make”执行时,会调用.config配置文件,根据里面的配置对内核进行编译,这里就不详细列举其内容了。
7.1.2.2. drivers/Makefile¶
1 2 3 4 5 6 | ……
# tty/ comes before char/ so that the VT console is the boot-time
# default.
obj-y += tty/
obj-y += char/
……
|
obj-y += tty/
:将当前目录的tty/文件夹下的内容编译进内核具体编译tty/下的哪些内容需要查看tty/下的Makefile
7.1.2.3. drivers/tty/Makefile¶
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | # SPDX-License-Identifier: GPL-2.0
obj-$(CONFIG_TTY) += tty_io.o n_tty.o tty_ioctl.o tty_ldisc.o \
tty_buffer.o tty_port.o tty_mutex.o \
tty_ldsem.o tty_baudrate.o tty_jobctrl.o \
n_null.o
obj-$(CONFIG_LEGACY_PTYS) += pty.o
obj-$(CONFIG_UNIX98_PTYS) += pty.o
obj-$(CONFIG_AUDIT) += tty_audit.o
obj-$(CONFIG_MAGIC_SYSRQ) += sysrq.o
obj-$(CONFIG_N_HDLC) += n_hdlc.o
obj-$(CONFIG_N_GSM) += n_gsm.o
obj-$(CONFIG_TRACE_ROUTER) += n_tracerouter.o
obj-$(CONFIG_TRACE_SINK) += n_tracesink.o
obj-$(CONFIG_R3964) += n_r3964.o
……
|
注意
以 obj-$(CONFIG_TTY) += tty_io.o ...
为例,$(CONFIG_TTY)是根据.config文件确定的,而这个文件可以由menuconfig配置界面生成,而menuconfig配置界面的选项是根据各Kconfig的选项决定的。
下面是形象的描述,以CONFIG_TTY为例。
1 2 | Kconfig ────────> menuconfig ────────> .config ────────> Makefile
config TTY 选项被调用 手动配置 生成配置 CONFIG_TTY=y 根据配置编译
|
7.2. 将helloworld例程驱动编译进内核¶
看了上述的描述,关于如何实现“编译驱动到内核”,相信你心里已经有想法了。下面就以先前的helloworld例程进行演示一下。
进入内核源码同级目录,将案例的helloworld例程文件夹复制到内核源码的drivers/char路径下。
7.2.1. 新建Kconfig文件¶
的内核源码目录下的drivers/char/helloworld路径(刚刚复制的)下,新建Kconfig文件。
文件内容如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | #
# Helloworld test configuration
#
menu "Helloworld test"
config HELLOWORLD
tristate "Helloworld option"
default y
help
helloworld 测试选项
endmenu
#endmenu后一定要加空行
|
第5行:菜单名
第7行:声明config选项
第8行:声明选项的类型,选项的名称,
第9行:默认配置,default y表示默认配置是编译进内核
第10-11行:帮助信息
第13行:菜单结束
第14行:endmenu后需要加空行
选项支持的类型:tristate和bool。
tristate支持三个选项:
< >不编译
<*>编译到内核
<M>编译成模块
bool支持两个选项:
< >不编译
<*>编译到内核
7.2.2. 将Kconfig加到另一个Kconfig¶
首先,我们要有一个概念,除了主Kconfig,其他Kconfig都需要被加载才能起效。
以drivers/char/Kconfig中添加为例,添加以下内容。
1 | source "drivers/char/helloworld/Kconfig"
|
添加后如下:
1 2 3 4 5 6 7 8 9 | # SPDX-License-Identifier: GPL-2.0
#
# Character device configuration
#
menu "Character devices"
source "drivers/tty/Kconfig"
source "drivers/char/helloworld/Kconfig"
|
此时我们就可以打开menuconfig配置界面查看选项信息了,可以看到helloworld选项的路径在:
主界面 --> Device Drivers --> Character devices --> Helloworld test
7.2.4. 修改Makefile文件¶
7.2.4.1. 修改例程下的Makefile文件¶
此处修改 drivers/char/helloworld/Makefile
文件,修改后内容如下:
1 | obj-$(CONFIG_HELLOWORLD) += helloworld.o
|
7.2.4.2. 修改例程上一级Makefile文件¶
此处需要修改 drivers/char/Makefile
文件。
文件原内容为:
1 2 3 4 5 6 7 8 9 10 11 | # SPDX-License-Identifier: GPL-2.0
#
# Makefile for the kernel character device drivers.
#
obj-y += mem.o random.o
obj-$(CONFIG_TTY_PRINTK) += ttyprintk.o
obj-y += misc.o
obj-$(CONFIG_ATARI_DSP56K) += dsp56k.o
obj-$(CONFIG_VIRTIO_CONSOLE) += virtio_console.o
……
|
在第4行和第6之间加上如下内容:
1 | obj-y += helloworld/
|
提示
这里演示的是相对路径,表示编译该文件同级的helloworld文件夹里的内容。
7.2.6. 重新编译内核¶
1 2 3 4 5 6 7 8 9 | #清除之前生成的所有文件和配置
make mrproper
# 加载linux_h618_defconfig配置文件
# 这步执行之后,会将linux_h618_defconfig配置加载到.config
make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- linux_h618_defconfig
# 编译内核,指定平台,指定交叉编译工具,使用16线程进行编译,线程可根据电脑性能自行确定
make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- -j16
|
7.2.7. 查看编译结果¶
进入“drivers/char/helloworld”文件夹,查看编译生成的文件。
注意
如果编译完发现并没有生成文件,请检查操作步骤和文件修改是否正确。
可以通过以下命令查看配置里是否有选项信息。
1 | cat .config | grep HELLO
|
如果生成了如图的文件,恭喜你,说明你编译进内核的操作成功了。