2. RISC-V基础

做嵌入式开发,环境搭建往往是第一道坎。很多人兴致勃勃地看完了课程介绍,结果卡在装工具链这一步,一卡就是半天。我个人习惯是先把整个流程在脑子里过一遍,再动手。说白了,就是先画个地图再上路。

这一章,我会带你把这四个核心组件全部装好:QEMU(模拟器)、RISC-V交叉编译工具链(编译器)、OpenSBI(底层固件)、Linux内核源码(我们要跑的系统)。最后再跑一个简单的验证,确保环境没毛病。

本章核心目标:搭建一个可复现的、干净的RISC-V开发环境。所有操作都在Ubuntu 22.04 LTS上验证过,其他发行版大同小异,注意包名可能略有差异。

开发环境核心组件关系图 宿主机(Ubuntu 22.04 x86_64) 交叉编译工具链(riscv64-linux-gnu-*) QEMU RISC-V 系统模拟器(qemu-system-riscv64) 模拟硬件:CPU、内存、UART、CLINT、PLIC 目标软件栈(RISC-V 64位) OpenSBI(M模式固件) 提供SBI接口,引导下一阶段 Linux内核(S模式) 设备树驱动、进程调度、文件系统 验证输出:内核启动日志 + Shell交互

2.1 安装QEMU

QEMU是我们这整套实验的基石。没有它,你手头得有块RISC-V开发板才能跑。我个人建议直接装最新稳定版,别用系统自带的旧版本——我在项目中遇到过因为QEMU版本太老,导致某些RISC-V扩展指令模拟不出来的情况,排查了半天。

2.1.1 从源码编译安装(推荐)

为什么推荐源码编译?因为你可以精确控制开启哪些特性。比如我们后面要用到的设备树动态加载、GDB调试支持,这些在发行版自带的QEMU里可能被阉割了。

# 安装编译依赖
sudo apt-get update
sudo apt-get install -y ninja-build libglib2.0-dev libpixman-1-dev libslirp-dev

# 下载QEMU 8.2.0(写稿时最新稳定版)
wget https://download.qemu.org/qemu-8.2.0.tar.xz
tar -xf qemu-8.2.0.tar.xz
cd qemu-8.2.0

# 配置——只编译RISC-V目标,节省时间
./configure --target-list=riscv64-softmmu --enable-slirp

# 编译(-j后面的数字是你的CPU核心数)
make -j$(nproc)

# 安装到系统路径
sudo make install

小技巧:如果你不想污染系统目录,可以加 --prefix=/opt/qemu-riscv 参数,然后手动把 /opt/qemu-riscv/bin 加入 PATH。我自己的开发机就是这么干的,方便切换不同版本。

2.1.2 验证安装

qemu-system-riscv64 --version

看到类似 QEMU emulator version 8.2.0 的输出,说明安装成功。

2.2 配置RISC-V交叉编译工具链

你想想看,你的宿主机是x86架构,但我们要编译的是RISC-V架构的代码。没有交叉编译工具链,就像让一个只懂中文的人去写英文合同——根本没法干。

2.2.1 方案选择

方案 优点 缺点 推荐场景
发行版包管理器安装 简单快捷,一条命令搞定 版本可能较旧,缺少GDB等组件 快速验证、初学者
Bootlin工具链(预编译) 版本新,开箱即用,包含完整工具集 需要手动下载配置 大多数开发场景
crosstool-NG自编译 完全定制化,可开启特定CPU扩展 编译耗时,配置复杂 生产环境、特殊优化需求

我个人最常用的是Bootlin预编译工具链。为什么?因为省时间。我曾经花了一整天用crosstool-NG编译工具链,结果发现Bootlin已经帮我做好了,而且版本更新、优化更好。从那以后,除非有特殊需求,我都是直接下载Bootlin的。

2.2.2 安装Bootlin工具链

# 下载RISC-V 64位 glibc工具链(2023.11版本)
wget https://toolchains.bootlin.com/downloads/releases/toolchains/riscv64-lp64d/tarballs/riscv64-lp64d--glibc--stable-2023.11-1.tar.bz2

# 解压到指定目录
sudo mkdir -p /opt/toolchains
sudo tar -xf riscv64-lp64d--glibc--stable-2023.11-1.tar.bz2 -C /opt/toolchains/

# 添加环境变量(建议写入 ~/.bashrc)
export PATH="/opt/toolchains/riscv64-lp64d--glibc--stable-2023.11-1/bin:$PATH"

2.2.3 验证工具链

riscv64-linux-gcc --version
riscv64-linux-gdb --version

能正常输出版本信息,说明工具链可用。再写个简单的C程序测试一下:

echo '#include <stdio.h>
int main() { printf("Hello RISC-V!\n"); return 0; }' > test.c
riscv64-linux-gcc -o test test.c
file test

输出应该包含 ELF 64-bit LSB executable, UCB RISC-V 字样。

注意:如果你用的是发行版自带的 gcc-riscv64-linux-gnu,记得确认它是否包含 riscv64-linux-gnu-gdb。有些发行版把GDB单独拆包了,需要额外安装。没有GDB,后面调试设备树和SBI时会非常痛苦。

2.3 安装OpenSBI与Linux内核源码

OpenSBI是运行在机器模式(M-mode)下的底层固件,负责引导Linux内核。你可以把它理解成RISC-V世界的BIOS。Linux内核则是我们要移植和调试的主角。

2.3.1 获取OpenSBI源码

# 克隆官方仓库(使用稳定分支)
git clone https://github.com/riscv-software-src/opensbi.git -b v1.4
cd opensbi

# 快速编译一次,验证环境
make CROSS_COMPILE=riscv64-linux- PLATFORM=generic
ls build/platform/generic/firmware/fw_dynamic.bin

看到 fw_dynamic.bin 文件,说明OpenSBI编译成功。这个文件就是后面QEMU启动时要加载的固件。

2.3.2 获取Linux内核源码

# 下载LTS版本(6.6.x系列)
wget https://cdn.kernel.org/pub/linux/kernel/v6.x/linux-6.6.8.tar.xz
tar -xf linux-6.6.8.tar.xz
cd linux-6.6.8

# 配置RISC-V默认配置
make ARCH=riscv CROSS_COMPILE=riscv64-linux- defconfig

# 编译内核(第一次编译较慢,耐心等待)
make ARCH=riscv CROSS_COMPILE=riscv64-linux- -j$(nproc)

避坑指南:我曾经在编译内核时遇到 openssl/xxx.h: No such file or directory 错误。这是因为内核签名功能需要OpenSSL开发库。解决方法很简单:sudo apt-get install libssl-dev。如果你不需要模块签名,也可以在 make menuconfig 里关掉 CONFIG_MODULE_SIG。

2.4 验证环境:启动最小系统

所有组件都装好了,是骡子是马,拉出来遛遛。我们用QEMU加载OpenSBI和Linux内核,看看能不能跑起来。

2.4.1 准备设备树文件

QEMU RISC-V机器默认会生成一个设备树,我们可以把它dump出来看看:

qemu-system-riscv64 -machine virt -machine dumpdtb=qemu-virt.dtb
dtc -I dtb -O dts qemu-virt.dtb -o qemu-virt.dts
head -50 qemu-virt.dts

你会看到CPU、内存、UART、CLINT等设备节点。这就是后面我们要修改和定制的基础。

2.4.2 启动系统

qemu-system-riscv64 \
  -machine virt \
  -m 512M \
  -kernel /path/to/opensbi/build/platform/generic/firmware/fw_dynamic.bin \
  -device loader,file=/path/to/linux-6.6.8/arch/riscv/boot/Image,addr=0x80200000 \
  -append "console=ttyS0 root=/dev/ram" \
  -nographic

如果一切顺利,你会看到OpenSBI的启动信息,然后是Linux内核的启动日志,最后停在 Kernel panic - not syncing: VFS: Unable to mount root fs。别慌!这其实是好消息——说明内核已经成功启动,只是找不到根文件系统而已。我们后面会专门讲怎么制作根文件系统。

验证成功的标志:看到OpenSBI打印的版本信息(如 OpenSBI v1.4)以及Linux内核的启动横幅(如 Linux version 6.6.8),说明你的开发环境已经搭建完毕,可以开始后续的设备树配置和SBI移植工作了。

2.5 本章小结

到这一步,你的开发环境已经具备了:

  • QEMU 8.2.0:RISC-V系统模拟器,能跑完整的软件栈
  • RISC-V交叉编译工具链:能把C代码编译成RISC-V指令
  • OpenSBI v1.4:M模式固件源码,已编译验证
  • Linux 6.6.8:内核源码,已编译出Image文件

嗯,环境搭好了,后面的事情就好办了。接下来我们会深入设备树的每一个节点,看看它们到底是怎么工作的。