3. 内核编译与烧录:获取源码、配置、编译与烧录
这一章,我们正式进入动手环节。说白了,就是要把 Linux 内核从源码变成能在 T113 上跑起来的二进制镜像,然后烧进板子。很多初学者觉得这步就是敲几条命令,其实不然。我在项目里见过太多人卡在“编译不过”或者“烧进去起不来”的坑里,最后发现是配置错了或者设备树没改对。
好,我们一步步来。
3.1 获取 Linux 内核源码
全志官方维护的 Linux 内核分支通常基于 linux-5.4 或 linux-5.10。我个人习惯用 5.4,因为社区资料多,踩过的坑基本都有解决方案。
获取源码有两种方式:
- 从全志官方 SDK 获取:通常是一个 tar.gz 压缩包,解压即可。
- 从 GitHub 拉取:全志有公开的仓库,但分支可能不完整。
我建议你用 SDK 里的源码,因为全志在发布 SDK 时已经验证过该内核版本与 T113 的硬件匹配度。我自己就吃过亏——从 GitHub 拉了个“最新”分支,结果网卡驱动死活不工作,折腾了两天才发现是 DMA 地址映射改了。
关键路径:解压后的源码目录结构大致如下:
linux-5.4/
├── arch/ # 架构相关代码(arm32/arm64)
├── drivers/ # 设备驱动
├── dts/ # 设备树源文件
├── include/ # 头文件
├── init/ # 内核初始化
├── kernel/ # 核心调度/进程管理
├── Makefile # 顶层编译脚本
└── scripts/ # 编译辅助脚本
3.2 配置内核(menuconfig)
拿到源码后,第一件事不是直接编译,而是配置。配置决定了哪些驱动被编译进内核、哪些作为模块、哪些干脆不编译。
T113 的默认配置通常在 arch/arm/configs/ 或 arch/arm64/configs/ 下,文件名类似 sun8iw20p1_defconfig。加载它:
make ARCH=arm sun8iw20p1_defconfig
然后打开图形化配置界面:
make ARCH=arm menuconfig
你会看到一个蓝底黄字的菜单。这里我分享一个经验:不要试图一次性配完所有选项。你只需要关注几个关键区域:
| 配置路径 | 说明 | 我的建议 |
|---|---|---|
| System Type → ARM system type | 选择 ARM 架构类型 | 默认即可,全志已预置 |
| Device Drivers → <*> DMA Engine support | DMA 引擎,外设高速传输必备 | 建议编入内核,不要模块 |
| Device Drivers → Network device support | 网卡驱动(如 GMAC) | 根据你的板载 PHY 芯片选择 |
| File systems → <*> ext4 | 根文件系统类型 | 如果 rootfs 是 ext4,必须编入 |
| Boot options → Kernel command line | 内核启动参数 | console=ttyS0,115200 等 |
小技巧:在 menuconfig 里按 / 可以搜索符号。比如你想找“GPIO”相关的配置,按 / 输入 GPIO,它会列出所有包含 GPIO 的选项和路径。这比手动翻菜单快得多。
配置完成后,保存退出。配置会写入 .config 文件。我建议你备份一份:
cp .config config-my-t113-board
为什么?因为如果你后面改了配置导致编译失败,可以快速回退。我曾经在一次调试中连续改了 20 多次配置,每次都要重新选,后来学乖了——每次改之前先备份。
3.3 编译内核与设备树
配置搞定,接下来就是编译。T113 是双核 Cortex-A7,我一般用 -j4 并行编译:
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- -j4 zImage
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- -j4 dtbs
这里解释一下:
zImage:压缩后的内核镜像,U-Boot 能直接加载。dtbs:设备树二进制文件,描述硬件拓扑。
编译完成后,在 arch/arm/boot/ 下会生成 zImage,在 arch/arm/boot/dts/ 下生成 *.dtb 文件。
注意:如果你的 T113 是 64 位模式(ARMv8),ARCH 要改成 arm64,交叉编译器也要换成 aarch64-linux-gnu-。32 位和 64 位的设备树文件不通用,千万别搞混。
编译过程中如果报错,90% 的情况是以下原因:
- 交叉编译器版本不对:全志推荐 gcc 7.x 或 8.x,太新的版本可能不兼容。
- 缺少依赖库:比如
ncurses-dev没装,menuconfig 打不开。 - .config 里有未解析的符号:通常是某个驱动依赖了另一个没选的驱动。
遇到错误别慌,先看最后几行报错信息。我一般用 2>&1 | tail -50 把错误重定向出来,定位很快。
3.4 烧录镜像到 T113 开发板
编译出 zImage 和 .dtb 后,下一步就是烧录。T113 的启动方式通常是从 SD 卡 或 NAND Flash 启动。我以 SD 卡为例,因为调试最方便。
烧录流程分三步:
- 准备 SD 卡:分区、格式化。
- 复制镜像:把 zImage、dtb、U-Boot、rootfs 拷进去。
- 插卡上电:看串口输出。
具体命令如下(假设 SD 卡设备是 /dev/sdb):
# 1. 分区(用 fdisk 或 parted)
sudo fdisk /dev/sdb
# 创建两个分区:第一个 64MB 放 boot,第二个放 rootfs
# 2. 格式化
sudo mkfs.vfat /dev/sdb1 # boot 分区用 FAT32
sudo mkfs.ext4 /dev/sdb2 # rootfs 分区用 ext4
# 3. 挂载并复制
sudo mount /dev/sdb1 /mnt/boot
sudo cp arch/arm/boot/zImage /mnt/boot/
sudo cp arch/arm/boot/dts/sun8i-t113.dtb /mnt/boot/
sudo umount /mnt/boot
# 4. 烧录 U-Boot(如果 SD 卡没有)
sudo dd if=u-boot-sunxi-with-spl.bin of=/dev/sdb bs=1024 seek=8
关键点:U-Boot 的烧录位置是固定的。全志 T113 的 SPL(Secondary Program Loader)从 SD 卡的 第 8KB 偏移 开始读取。如果你烧错位置,板子根本不会启动。
烧完后,插卡上电,串口连接(波特率 115200),你会看到类似这样的输出:
U-Boot SPL 2020.01 (Jan 10 2024 - 15:30:00 +0800)
DRAM: 512 MiB
Trying to boot from MMC1
U-Boot 2020.01 (Jan 10 2024 - 15:30:00 +0800)
CPU: Allwinner T113 (SUN8I)
...
Loading kernel from MMC: zImage ...
Starting kernel ...
[ 0.000000] Booting Linux on physical CPU 0x0
[ 0.000000] Linux version 5.4.61
...
看到 Booting Linux on physical CPU 0x0,说明内核已经跑起来了。如果卡在某一步不动,比如停在 Starting kernel ... 之后没反应,通常是设备树和内核不匹配,或者根文件系统没挂上。
3.5 知识结构图
下面这张图总结了本章的核心流程:
3.6 避坑指南
最后,我把自己踩过的几个坑列出来,你遇到了可以直接对号入座:
- 烧录后串口无输出:检查 U-Boot 是否烧对位置。我曾经把
seek=8写成了seek=8K,结果板子一直黑屏。 - 内核启动到一半卡死:多半是设备树里的
reg地址和实际硬件不匹配。用cat /proc/iomem对比一下。 - 根文件系统挂载失败:检查内核是否编译了对应的文件系统驱动。比如你用 ext4,但内核里没编入 ext4 支持,那肯定挂不上。
- 网络不通:PHY 芯片的复位时序可能不对。在设备树里加个
reset-gpios属性试试。
嗯,这一章的内容就到这里。配置和编译看似枯燥,但它是后续所有驱动开发的基础。你只要把这一步跑通,后面写驱动、调外设都会顺畅很多。