第四章 Linux内核移植:从源码到跑起来
好,咱们进入正题。这一章讲的是Linux内核移植,说白了就是让Linux内核在你的海思芯片上跑起来。我刚开始做BSP时,觉得这步特别神秘,后来发现其实就是几个关键步骤:拿源码、改配置、写设备树、裁剪、编译、烧录。嗯,一步步来。
4.1 内核源码获取与配置
先说说源码从哪来。我个人习惯直接从kernel.org拉主线代码,但海思平台嘛,官方SDK里通常会带一份打过补丁的内核。我建议你用SDK里的那份,省得自己打一堆补丁,踩坑概率小很多。
拿到源码后,第一件事就是配置。配置有两种方式:
- make menuconfig:图形化界面,适合新手,我早期全靠它
- make defconfig:用默认配置,然后手动改
我个人更推荐第二种。为什么?因为menuconfig里选项太多,你很容易漏掉关键项。我有个血的教训——有一次忘了开串口驱动,内核跑起来后控制台一片黑,查了两天才发现。
4.2 设备树(DTS)概念与编写
设备树,英文叫Device Tree,缩写DTS。这玩意儿说白了就是描述硬件信息的配置文件。你想想看,内核要驱动一个外设,总得知道它挂在哪条总线上、中断号是多少、寄存器地址在哪吧?这些信息就写在DTS里。
DTS的基本结构是这样的:
/dts-v1/;
#include "hi3559av100.dtsi"
/ {
model = "HiSilicon HI3559AV100 DEMO Board";
compatible = "hisilicon,hi3559av100";
chosen {
stdout-path = &uart0;
};
memory@80000000 {
device_type = "memory";
reg = <0x0 0x80000000 0x0 0x80000000>;
};
&uart0 {
status = "okay";
clocks = <&clk_uart0>;
};
};
这里有几个关键点:
- compatible:告诉内核这个板子是什么型号,内核靠它匹配驱动
- memory:内存布局,地址和大小必须和硬件一致
- chosen:启动参数,比如控制台用哪个串口
我在项目中遇到过最坑的事,就是DTS里内存地址写错了。板子有2GB内存,我写成了1GB,结果系统只认一半内存,跑起来各种OOM。查了两天才发现是DTS的问题。
dtc -I dts -O dtb -o test.dtb test.dts
4.3 海思平台内核裁剪
内核裁剪,说白了就是去掉你用不到的功能。为什么要做?因为海思芯片的Flash空间有限,一个完整的内核动辄几十MB,裁剪后能压到几MB。
裁剪的核心思路:
- 关掉不用的驱动:比如你的板子没有WiFi,就把WiFi驱动全关了
- 去掉调试选项:生产环境不需要printk调试,关掉能省不少空间
- 模块化:把不常用的驱动编译成模块,按需加载
我曾经给一个客户做项目,他们要求内核必须小于4MB。我花了三天时间,把能关的全关了,最后压到3.8MB。嗯,刚好达标。那几天我做梦都在看menuconfig的选项。
这里给个裁剪清单参考:
| 功能模块 | 裁剪建议 | 节省空间 |
|---|---|---|
| 网络协议栈 | 只保留IPv4,关掉IPv6 | 约200KB |
| 文件系统 | 只保留ext4和squashfs | 约500KB |
| 调试选项 | 关掉所有DEBUG选项 | 约1MB |
| 不用的驱动 | 按硬件实际需求裁剪 | 视情况而定 |
4.4 内核编译与烧录
编译这一步,其实没什么花头。就是执行几条命令:
export ARCH=arm64
export CROSS_COMPILE=aarch64-linux-gnu-
make menuconfig
make -j4 Image dtbs
这里要注意几个点:
- 交叉编译器:必须用海思提供的工具链,版本不对会编译失败
- -j参数:根据你的CPU核心数来设,我一般用-j4或-j8
- Image vs zImage:海思平台一般用Image,因为bootloader支持
编译完成后,你会得到两个关键文件:
- Image:内核镜像
- xxx.dtb:设备树二进制文件
烧录方式取决于你的bootloader。如果是uboot,我一般用tftp下载:
tftp 0x80000000 Image
tftp 0x82000000 xxx.dtb
booti 0x80000000 - 0x82000000
嗯,这里有个坑。我记得有一次烧录后系统起不来,查了半天发现是dtb地址和内核地址重叠了。内核加载时会覆盖dtb的数据,导致设备树损坏。后来我把dtb放到0x82000000,问题解决。
printenv检查bootargs是否正确。特别是console参数,写错了就看不到任何输出。
最后说一句,内核移植不是一次就能成功的。我做过几十次移植,每次都会遇到新问题。但只要你掌握了这几个步骤——源码、配置、DTS、裁剪、编译、烧录——剩下的就是耐心调试了。嗯,慢慢来,总会跑起来的。