6. Linux内核的编译

6.1. 下载安装编译镜像系统

使用平台:Ubuntu 18.04 LTS 版本

可以使用我们提供的虚拟机镜像 https://doc.embedfire.com/products/link/zh/latest/linux/ebf_i.mx6ull.html#id4

也可以自己下载ubuntu 18.04 LTS官方镜像搭建 https://mirrors.aliyun.com/ubuntu-releases/bionic

6.2. 安装编译工具和依赖

编译内核之前需要安装必要的环境工具。

1
sudo apt install make gcc-arm-linux-gnueabihf gcc bison flex libssl-dev dpkg-dev lzop vim

6.3. 获取kernel

6.3.1. 下载源代码

有三个方法获取Kernel源码,一个是Kernel官方内核源码,一个是NXP官方的kernel源码,一个是经过我们修改适配我们板子的kernel源码, 我们这里使用我们提供的源码为例,对官方源码感兴趣的小伙伴也可以下载来学习配置。我们的kernel是根据NXP官方提供的kernel定制的, NXP的kernel是根据kernel官方某一版本进行芯片适配的。我们作为嵌入式开发者,一般只需要使用芯片厂商适配好的kernel进行开发即可, 对于从kernel官方下载新版本来配置这是芯片厂商做的事情,感兴趣的伙伴也可以根据NXP官方提供的芯片手册进行适配新版本的kernel。 由于imx6ull这款芯片较为常用所以NXP官方将适配补丁提交给了kernel官方, 这样kernel官方基本每一个版本都适配了这款芯片新版本的kernel官方的kernel也是可以直接编译来使用的。

而野火OpenWrt固件使用的Kernel源码(以下简称OP-Kernel)是在野火Kernel源码的基础上,针对OpenWrt系统进行优化的版本。

Kernel官方内核源码:

NXP内核源码:

OP-kernel内核源码:

通常一个内核仓库往往维护着不同分支的内核源码,进入仓库目录下可通过命令查看及切换内核分支

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#克隆野火OP-kernel源码
git clone http://gitlab.ebf.local/openwrt/gateway/ebf_gateway_linux_kernel.git

#查看uboot分支
git branch -a

#打印消息如下
* ebf_4.19.35_imx6ul
  remotes/origin/HEAD -> origin/ebf_4.19.35_imx6ul
  remotes/origin/ebf_4.19.35_imx6ul

#切换ebf_4.19.35_imx6ul分支
git checkout ebf_4.19.35_imx6ul

#打印消息如下
Checking out files: 100% (63998/63998), done.
Branch 'ebf_4.19.35_imx6ul' set up to track remote branch 'ebf_4.19.35_imx6ul' from 'origin'.
Switched to a new branch 'ebf_4.19.35_imx6ul'

#重新查看当前分支
git branch

#打印消息如下,成功切换分支到 ebf_4.19.35_imx6ul
* ebf_4.19.35_imx6ul

也可以在下载时指定分支,如下所示

1
git clone -b ebf_4.19.35_imx6ul http://gitlab.ebf.local/openwrt/gateway/ebf_gateway_linux_kernel.git

6.4. kernel工程结构分析

OP-Kernel内核源码目录如下

arch         COPYING        drivers   init     kernel       make_deb.sh  README    sound
block        CREDITS        firmware  ipc      lib          Makefile     samples   tools
build_image  crypto         fs        Kbuild   LICENSES     mm           scripts   usr
certs        Documentation  include   Kconfig  MAINTAINERS  net          security  virt

我们可以看到Linux内核源码目录下是有非常多的目录,且目录下也有非常多的文件, 下面我们简单分析一下这些目录的主要作用。

  • arch :主要包含和硬件体系结构相关的代码,如arm、x86、MIPS,PPC,每种CPU平台占一个相应的目录,例如我们使用的imx系列CPU就在 arch/arm/mach-imx 目录下,Linux内核目前已经支持30种左右的CPU体系结构。arch中的目录下存放的是各个平台以及各个平台的芯片对Linux内核进程调度、内存管理、 中断等的支持,以及每个具体的SoC和电路板的板级支持代码。

  • block :在Linux中block表示块设备(以块(多个字节组成的整体,类似于扇区)为单位来整体访问),譬如说SD卡、Nand、硬盘等都是块设备,block目录下放的是一些Linux存储体系中关于块设备管理的代码。

  • crypto :这个目录下存放的是常用加密和散列算法(如md5、AES、 SHA等),还有一些压缩和CRC校验算法。

  • Documentation:内核各部分的文档描述。

  • drivers :设备驱动程序,里面列出了linux内核支持的所有硬件设备的驱动源代码,每个不同的驱动占用一个子目录,如char、block、 net、 mtd、 i2c等。

  • fs :fs就是file system,里面包含Linux所支持的各种文件系统,如EXT、FAT、 NTFS、 JFFS2等。

  • include :目录包括编译核心所需要的大部分头文件,例如与平台无关的头文件在 include/linux 子目录下,与cpu架构相关的头文件在include目录下对应的子目录中。

  • init :内核初始化代码,这个目录下的代码就是linux内核启动时初始化内核的代码。

  • ipc :ipc就是 inter process commuication ,进程间通信,该目录下都是linux进程间通信的代码。

  • kernel :kernel就是Linux内核,是Linux中最核心的部分,包括进程调度、定时器等,而和平台相关的一部分代码放在arch/*/kernel目录下。

  • lib :lib是库的意思,lib目录下存放的都是一些公用的有用的库函数,注意这里的库函数和C语言的库函数不一样的,因为在内核编程中是不能用C语言标准库函数的,所以需要使用lib中的库函数,除此之外与处理器结构相关的库函数代码被放在 arch/*/lib/ 目录下。

  • mm : 目录包含了所有独立于 cpu 体系结构的内存管理代码,如页式存储管理内存的分配和释放等,而与具体硬件体系结构相关的内存管理代码位于 arch/*/mm 目录下,例如 arch/arm/mm/fault.c

  • net : 网络协议栈相关代码,net目录下实现各种常见的网络协议。

  • scripts :这个目录下全部是脚本文件,这些脚本文件不是linux内核工作时使用的,而是用了配置编译linux内核的。

  • security :内核安全模型相关的代码,例如最有名的SELINUX。

  • sound : ALSA、 OSS音频设备的驱动核心代码和常用设备驱动。

  • usr : 实现用于打包和压缩的cpio等。

此处仅列出一些常见的目录。

6.5. 内核配置选项

Linux内核的配置系统由三个部分组成,分别是:

  • Makefile:分布在 Linux内核源代码根目录及各层目录中,定义 Linux 内核的编译规则;

  • 配置文件:给用户提供配置选择的功能,如Kconfig文件定义了配置项,在OpenWrt系统的编译过程中,所使用的配置文件在OpenWrt工程中。

  • 配置工具:包括配置命令解释器和配置用户界面,在OpenWrt系统的编译过程中,配置工具由OpenWrt工程提供。

6.6. kernel编译

在OpenWrt工程中,我们无需手动编译内核源码,在OpenWrt的构建过程中会自动编译。

但是为了让大家对内核zImage文件的构建有一个初步的了解,仍然添加了手动编译内核的部分,以下内容与OpenWrt构建过程无关。

6.6.1. 手动编译内核zImage

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
#清除之前编译环境
make mrproper

#编译内核
make ARCH=arm npi_v7_defconfig
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- -j8

#编译成功后将打印以下信息。
.......
LD [M]  sound/soc/fsl/snd-soc-fsl-esai.ko
LD [M]  sound/soc/fsl/snd-soc-fsl-micfil.ko
LD [M]  sound/soc/fsl/snd-soc-fsl-rpmsg-i2s.ko
LD [M]  sound/soc/fsl/snd-soc-fsl-sai.ko
LD [M]  sound/soc/fsl/snd-soc-fsl-ssi.ko
LD [M]  sound/soc/fsl/snd-soc-imx-audmux.ko
LD [M]  sound/soc/fsl/snd-soc-imx-wm8960.ko
LD [M]  sound/soc/fsl/snd-soc-fsl-utils.ko
LD [M]  sound/soc/generic/snd-soc-simple-card-utils.ko
LD [M]  sound/soc/generic/snd-soc-simple-card.ko
LD [M]  sound/soc/generic/snd-soc-simple-scu-card.ko
LD [M]  sound/soc/snd-soc-core.ko
LD [M]  sound/usb/snd-usbmidi-lib.ko
LD [M]  sound/usb/snd-usb-audio.ko
AS      arch/arm/boot/compressed/bswapsdi2.o
AS      arch/arm/boot/compressed/piggy.o
LD      arch/arm/boot/compressed/vmlinux
OBJCOPY arch/arm/boot/zImage
Kernel: arch/arm/boot/zImage is ready

6.6.2. zImage生成简述

通过arm-linux-gnueabihf-ld命令将 vmlinux.lds head.o piggy.o misc.o decompress.o string.o hyp-stub.o lib1funcs.o ashldi3.o bswapsdi2.o 链接成vmlinux

再通过arm-linux-gnueabihf-objcopy命令将vmlinux 以bin格式输出到zImage,期间删去了comment等信息