4. Linux系统移植总览
在嵌入式RISC-V开发中,把Linux运行到一块新板子上,并不是简单地把内核复制进去。所谓Linux系统移植,是指针对特定处理器架构和具体硬件板卡,对启动引导程序、Linux内核、设备树和根文件系统进行配置、编译、适配与烧写,使操作系统能够正确识别硬件、挂载文件系统并最终进入用户空间的过程。它解决的是“通用Linux如何变成这块板子专属的Linux”这一问题。
理解移植,关键是理解它的层次划分。一个可启动的嵌入式Linux系统通常由四部分构成:Bootloader、设备树、Linux内核、根文件系统。它们按启动顺序层层接力,任何一层不匹配,系统都无法正常进入用户态。
一、移植的核心原理
Linux内核本身是高度可移植的,它通过架构层与板级层分离来支持不同硬件。RISC-V架构代码位于 arch/riscv,负责异常入口、页表、时钟中断等通用机制;而具体板卡的内存地址、外设寄存器、中断号等信息,则通过设备树在启动时动态传入。这样同一份内核镜像,配合不同设备树,就能运行在不同板子上。
Bootloader的作用是“把系统带起来”。它完成最底层的DDR初始化后,从存储介质读取内核镜像和设备树到内存,设置好启动参数,最后跳转到内核入口。内核启动后解析设备树,匹配并加载驱动,再根据 bootargs 中的 root= 参数找到并挂载根文件系统,执行 /sbin/init,系统才算真正可用。
二、移植的方法流程
一次完整的移植通常遵循以下步骤,顺序不可颠倒:
- 确认硬件资源:整理CPU型号、DDR容量与地址、串口、存储介质(eMMC/SD/NAND)、网络PHY等。
- 准备工具链:安装RISC-V交叉编译器,如
riscv64-linux-gnu-gcc。 - 移植Bootloader:配置板级文件,编译SPL与U-Boot,确认串口有输出。
- 编写设备树:在
arch/riscv/boot/dts下新增或修改板级.dts,描述内存与外设。 - 配置并编译内核:选择默认配置,打开所需驱动,生成
Image与dtb。 - 制作根文件系统:用BusyBox或Buildroot生成最小RootFS,放入SD卡或打包进镜像。
- 烧写与联调:通过串口观察启动日志,逐层定位问题。
# 典型编译与启动命令
make ARCH=riscv CROSS_COMPILE=riscv64-linux-gnu- defconfig
make ARCH=riscv CROSS_COMPILE=riscv64-linux-gnu- -j8 Image dtbs
# U-Boot 中加载并启动
setenv bootargs "console=ttyS0,115200 root=/dev/mmcblk0p2 rw"
fatload mmc 0:1 0x84000000 Image
fatload mmc 0:1 0x83000000 board.dtb
booti 0x84000000 - 0x83000000
三、典型场景:一块新RISC-V开发板上电
假设拿到一块基于RISC-V SoC的开发板,串口无任何输出。首先检查Bootloader是否烧写正确,若SPL阶段就无打印,多半是DDR初始化参数或时钟配置错误。若U-Boot能启动但内核卡住,常见原因是设备树中 memory 节点地址与真实DDR不符,或 bootargs 里 root= 指向错误分区。若内核启动到最后提示 Kernel panic - not syncing: VFS: Unable to mount root fs,则说明根文件系统未找到或格式不被支持。
下表总结了四层组件的职责与常见故障点,便于排障时快速定位:
| 层次 | 核心职责 | 关键产物 | 常见故障 |
|---|---|---|---|
| Bootloader | 初始化硬件、加载内核与设备树、传参 | SPL、u-boot.bin | 无串口输出、DDR初始化失败 |
| 设备树 | 描述硬件资源与连接关系 | board.dtb | 内存地址错、外设不识别 |
| Linux内核 | 管理资源、加载驱动、挂载根文件系统 | Image | 驱动缺失、启动卡死 |
| 根文件系统 | 提供用户空间程序与init | rootfs.ext4 / initramfs | 无法挂载、init找不到 |
四、误区与复盘
常见误区二:只改内核不改Bootloader。启动参数、加载地址、机器码匹配都依赖Bootloader,二者必须协同。
常见误区三:忽略根文件系统的init权限与库依赖,导致内核已启动却停在
No init found。