3. 内核编译

3.1. 内核概念

内核,是一个操作系统的核心。是基于硬件的第一层软件扩充,提供操作系统的最基本的功能, 是操作系统工作的基础,决定着整个操作系统的性能和稳定性。

内核按照体系结构分为: 微内核(Micro Kernel)宏内核(Monolithic Kernel) 混合内核(Hybrid Kernel) 等。

下面是微内核和宏内核的简易对照图(图片来自于网络):

../../../_images/kernel.png

3.1.1. 微内核架构

在微内核架构中,内核只提供操作系统核心功能,如

  • 进程管理、存储器管理、进程间通信、I/O设备管理等

而下面这些则不被包含到内核功能中,属于微内核之外的模块,所以针对这些模块的修改不会影响到微内核的核心功能。

  • 应用层IPC、文件系统功能、设备驱动模块。

微内核具有动态扩展性强的优点。Windows操作系统、华为的鸿蒙操作系统就属于这类微内核架构。

3.1.2. 宏内核架构

宏内核架构是将上述包括微内核以及微内核之外的应用层IPC、文件系统功能、设备驱动模块都编译成一个整体。

  • 优点:执行效率非常高

  • 缺点:一旦我们想要修改、增加内核某个功能时(如增加设备驱动程序)都需要重新编译一遍内核。

Linux操作系统正是采用了宏内核结构,但是它也区分内核空间和用户空间。

3.2. 获取内核源码

板卡使用的内核版本,可以使用命令 uname -a 查看。

获取内核源码,建议直接git克隆野火官方提供的内核源码,或者下载Lubancat-SDK源码,SDK源码中包含内核源码。

3.2.1. 直接克隆野火官方提供的内核源码

创建SDK文件夹,以H618为例:

mkdir LubanCat_H618_SDK && cd LubanCat_H618_SDK/

H618系列板卡用户执行以下命令获取内核源码:

#GitHub获取,-b参数指定linux-5.4.125分支
git clone -b linux-5.4.125 https://github.com/LubanCat/kernel-allwinner.git

#Gitee获取,-b参数指定linux-5.4.125分支
git clone -b linux-5.4.125 https://gitee.com/LubanCat/kernel-allwinner.git

重命名内核源码目录名称(也可以不重命名,不影响后续实验):

mv kernel-allwinner/ kernel

3.2.2. aw-image-build获取

aw-image-build是野火科技基于armbian镜像构建脚本修改并定制的一套专用于LubanCat-AW系列板卡的镜像构建工具。

可以参考快速使用手册 《aw-image-build介绍》 章节进行源码获取。内核源码位于:

1
2
3
4
5
# 内核源码目录如下所示
.
└── source
    └── kernel
        └── linux-5.4-h618

修改成统一学习环境,以H618为例:

# 创建SDK文件夹
mkdir LubanCat_H618_SDK && cd LubanCat_H618_SDK/
# 复制aw-image-build获取的源码,默认aw-image-build和LubanCat_H618_SDK同级
cp -r ../aw-image-build/source/kernel/linux-5.4-h618/ kernel

3.3. 编译内核

重要

编译内核前必须完成 《编译环境的搭建》

按照前面小节搭建编译环境并下载源码之后,进入内核源码根目录( kernel ),根据具体的板卡设置配置文件。

H618系列板卡用户执行以下命令编译内核源码:

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

注意

如果内核编译报错,很大可能是编译器的问题,请参考 《交叉编译器工具包》 内容更换编译器。

3.4. linux内核源码目录结构

../../../_images/kernel-catalog.png

注意

linux内核源码目录下文件夹较多,在此仅挑部分进行分析。

linux内核源码目录

文件夹

作用

arch

这个文件夹包含了一个Kconfig文件,用于设置这个目录里的源代码编译所需的一系列设定。

支持的处理器架构都在它相应的文件夹中,如arm64、x86、riscv等。

/boot:内核需要的特定平台代码

/boot/dts:设备树文件

/configs:存放专用配置文件

/include:特定体系的头文件

/lib:通用函数在特定体系结构的文件

/mm:特定体系结构的内存管理文件

block

块设备,是一些linux存储体系中关于块设备管理的代码,譬如说SD卡、iNand、Nand、硬盘等都是块设备。

crypto

这个目录下放了一些各种常见的加密算法的源代码。

drivers

驱动目录,里面分门别类的列出了linux内核支持的所有硬件设备的驱动源代码。

firmware

固件目录,保存用于驱动第三方设备的固件。

Documentation

存放相关说明文档,很多实用文档,包括驱动编写等

include

存放内核所需、与平台无关的头文件,与平台相关的头文件已经被移动到 arch 平台的include 目录

kernel

这个文件夹中的代码控制内核本身,在该文件夹下有个”power”文件夹,这里的代码可以使计算机重新启动、关机和挂起。

lib

这个文件夹包含了内核需要引用的一系列内核库文件代码。

……

其余的文件夹作用请自行了解。

3.5. kernel menuconfig

menuconfig是linux里面的一个软件,可以配置uboot,kernel,rootf,这里以kernel为例来配置,其他的配置menuconfig的使用是一样的。

在命令行进入内核根目录,执行以下命令进入menuconfig配置主界面

1
2
# 打开menuconfig配置界面
make ARCH=arm64 menuconfig

注意事项:

  • 执行上述命令时,会读取内核目录下.config文件和/arch/arm64目录下的Kconfig文件。

  • Kconfig文件用于决定配置界面会有哪些配置选项

  • .config文件用于决定每个配置项的值(Y、M、N)

  • 当.config文件存在时,它会根据.config文件设定默认项.

  • 若不存在.config文件,则根据各级Kconfig文件来设定菜单项

  • 使用菜单配置完成并保存后,会将配置的结果保存到.config文件

打开后menuconfig界面如下图所示:

../../../_images/menuconfig-menu.png

下面分析一下defconfig、 .config 、kconfig 与makefile文件作用。

3.5.1. defconfig文件

一般由平台厂商提供,内核编译用做.config的参考。

  • 文件位于:/kernel/arch/$(SRCARCH)/configs/xxx_defconfig

  • 上述编译内核中的 linux_h618_defconfig 就是一个defconfig文件,

  • make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- linux_h618_defconfig 指令的作用是将linux_h618_defconfig文件加载到.config文件

3.5.2. .config 文件

在内核编译时,主Makefile调用这个.config,用于的内核编译配置。

  • 文件位于 :kernel/.config

  • 可以通过defconfig文件进行加载/生成

  • 可以通过kernel menuconfig进行配置/生成

3.5.3. Makefile 文件

  • 路径:kernel/Makefile

顶层Makefile,用于内核源码编译,建议好好阅读一下此文件。

  • 路径:kernel/arch/arm64/Makefile

该文件包含在顶层makefile中,因此用户可以添加自己的特定于体系结构的标志和依赖项。

3.5.4. Kconfig 文件

分布在各目录下的Kconfig构成了一个分布式的内核配置数据库,每个Kconfig分别描述了所属目录源文件相关的内核配置菜单。Kconfig是各种配置界面的源文件,内核的配置工具读取各个Kconfig文件,生成配置界面供开发人员配置内核。

  • 文件位于:/kernel/arch/$(SRCARCH)/Kconfig

在内核配置make menuconfig(或xconfig等)时,从Kconfig中读出配置菜单,用户配置完后保存到.config(在顶层目录下生成)中。

3.6. make menuconfig 配置演示

以下操作在内核源码根目录下进行。

1
2
3
4
5
6
7
# 加载defconfig到.config
make ARCH=arm64 linux_h618_defconfig
# 打开menuconfig配置界面,会加载.config
make ARCH=arm64 menuconfig

# 将配置好的.config保存为defconfig
cp .config arch/arm64/configs/linux_h618_defconfig

注意

最后的 .config保存为defconfig 的操作会覆盖原先的 linux_h618_defconfig 文件,请谨慎操作;不放心的也可以提前备份,或者起别名复制。

关于各SDK模块/外设的menuconfig配置流程,请参考芯片厂提供的开发指南文档。