RISC-V 64位环境下从源码编译 gem5、编译 U-Boot 并用 gem5 运行 U-Boot的操作指南。
环境准备
1. 安装系统依赖
bash
# Ubuntu/Debian
sudo apt update
sudo apt install -y build-essential git m4 scons zlib1g zlib1g-dev \
libprotobuf-dev protobuf-compiler libprotoc-dev \
libgoogle-perftools-dev python3-dev python3-six \
python-is-python3 libboost-all-dev pkg-config \
libncurses5-dev libssl-dev bc flex bison \
autoconf automake libtool curl gawk \
libmpc-dev libmpfr-dev libgmp-dev texinfo \
gperf patchutils zlib1g-dev libexpat-dev
2. 安装 RISC-V 64位交叉编译工具链
有两种方式:apt 直接安装 (推荐,简单)或从源码编译。
方式一:apt 直接安装(推荐)
bash
sudo apt install -y gcc-riscv64-linux-gnu g++-riscv64-linux-gnu \
binutils-riscv64-linux-gnu gdb-multiarch
验证安装:
bash
riscv64-linux-gnu-gcc --version
# 应显示版本信息,如 gcc 13.x.x
方式二:从源码编译工具链
bash
# 下载源码(约6.65GB)
git clone https://github.com/riscv-collab/riscv-gnu-toolchain
cd riscv-gnu-toolchain
# 编译 Linux 工具链(支持 glibc)
./configure --prefix=/opt/riscv
make linux -j$(nproc)
# 添加到环境变量
echo 'export PATH=/opt/riscv/bin:$PATH' >> ~/.bashrc
source ~/.bashrc
# 验证
riscv64-unknown-linux-gnu-gcc --version
第一步:从源码编译 gem5
bash
# 下载 gem5 源码
git clone https://github.com/gem5/gem5.git
cd gem5
# 编译 RISC-V 版本的 gem5(推荐使用 opt 版本,支持调试符号且速度较快)
scons build/RISCV/gem5.opt -j$(nproc)
# 如需更快的仿真速度,可编译 fast 版本(但不支持调试)
# scons build/RISCV/gem5.fast -j$(nproc)
编译完成后,gem5 可执行文件位于 build/RISCV/gem5.opt。
验证 gem5 安装:
bash
./build/RISCV/gem5.opt --version
第二步:从源码编译 U-Boot
1. 下载 U-Boot 源码
bash
git clone https://github.com/u-boot/u-boot.git
cd u-boot
2. 编译 U-Boot
U-Boot 有多种 RISC-V 配置选项,根据需求选择:
选项 A:Machine 模式 U-Boot(最简配置,适合 baremetal)
U-Boot 直接运行在 Machine 模式,不需要 OpenSBI。
bash
# 配置为 RISC-V 64位 QEMU virt 平台的 Machine 模式
make ARCH=riscv CROSS_COMPILE=riscv64-linux-gnu- qemu-riscv64_defconfig
关于EFI CAPSULE
并且在配置中关闭 EFI 胶囊工具
方法一:通过 menuconfig 禁用
bash
make ARCH=riscv CROSS_COMPILE=riscv64-linux-gnu- menuconfig
按 / 打开搜索,输入 MKEFICAPSULE
定位到 CONFIG_TOOLS_MKEFICAPSULE,将其设为 n(即取消勾选)
或者更彻底地:搜索 EFI_CAPSULE,关闭 CONFIG_EFI_CAPSULE 及其子项
编译
bash
make ARCH=riscv CROSS_COMPILE=riscv64-linux-gnu- -j$(nproc)
编译产物:
u-boot--- ELF 格式u-boot.bin--- 二进制格式
选项 B:Supervisor 模式 U-Boot(需要 OpenSBI)
U-Boot 运行在 S-mode,需要 M-mode 的 OpenSBI 固件提供 SBI 接口。
bash
# 配置为 S-mode
make ARCH=riscv CROSS_COMPILE=riscv64-linux-gnu- qemu-riscv64_smode_defconfig
# 编译
make ARCH=riscv CROSS_COMPILE=riscv64-linux-gnu- -j$(nproc)
如需配合 OpenSBI,还需编译 OpenSBI 并将 U-Boot 打包进去:
bash
# 编译 OpenSBI
cd ..
git clone https://github.com/riscv-software-src/opensbi.git
cd opensbi
make CROSS_COMPILE=riscv64-linux-gnu- PLATFORM=generic \
FW_PAYLOAD_PATH=../u-boot/u-boot.bin -j$(nproc)
# 产物在 build/platform/generic/firmware/fw_payload.elf
第三步:使用 gem5 运行 U-Boot
gem5 运行 RISC-V 全系统仿真使用自己编写的 run_uboot_riscv.py 脚本,直接存储在 gem5/ 下 。
方案一:运行 Machine 模式 U-Boot(Baremetal 方式)
对于 Machine 模式的 U-Boot,使用 --bare-metal 参数直接运行:
bash
$ cd gem5/
$ ./build/RISCV/gem5.opt run_uboot_riscv.py \
--kernel=/home/hipper/ex_gem5_/tmp7/u-boot/u-boot \
--cpu-type=atomic \
--mem-size=256MB
参数说明:
| 参数 | 说明 |
|---|---|
--kernel |
指定 U-Boot ELF 文件路径 |
--bare-metal |
使用裸机模式运行(RiscvBareMetal workload) |
--cpu-type |
CPU 类型(AtomicSimpleCPU/TimingSimpleCPU/O3CPU) |
--mem-size |
内存大小 |
--num-cpus |
CPU 核心数 |
效果 :
其中 run_uboot_riscv.py 脚本内容如下:
python
#!/usr/bin/env python3
"""
使用 gem5 Standard Library 运行 RISC-V U-Boot (Baremetal)
关键修复: 手动设置 _is_fullsystem 标记,使 _setup_board() 能正常执行
"""
import argparse
import m5
from gem5.components.boards.riscv_board import RiscvBoard
from gem5.components.cachehierarchies.classic.no_cache import NoCache
from gem5.components.memory import SingleChannelDDR3_1600
from gem5.components.processors.simple_processor import SimpleProcessor
from gem5.components.processors.cpu_types import CPUTypes
from gem5.isas import ISA
from gem5.simulate.simulator import Simulator
from gem5.utils.requires import requires
from m5.objects import CowDiskImage, RawDiskImage
import tempfile
import os
requires(isa_required=ISA.RISCV)
# ========== 命令行参数 ==========
parser = argparse.ArgumentParser(description="Run U-Boot on RISC-V with gem5 stdlib")
parser.add_argument(
"--kernel", required=True, type=str,
help="Path to U-Boot ELF file (e.g., /path/to/u-boot/u-boot)"
)
parser.add_argument(
"--bootloader", default=None, type=str,
help="Path to OpenSBI bootloader (optional, e.g., fw_jump.elf)"
)
parser.add_argument(
"--cpu-type", default="atomic", type=str,
choices=["atomic", "timing", "o3"],
help="CPU type: atomic, timing, or o3"
)
parser.add_argument(
"--num-cores", default=1, type=int,
help="Number of CPU cores"
)
parser.add_argument(
"--mem-size", default="256MB", type=str,
help="Memory size (e.g., 256MB, 1GB)"
)
args = parser.parse_args()
# ========== 系统组件配置 ==========
cpu_type_map = {
"atomic": CPUTypes.ATOMIC,
"timing": CPUTypes.TIMING,
"o3": CPUTypes.O3,
}
cpu_type = cpu_type_map[args.cpu_type]
processor = SimpleProcessor(
cpu_type=cpu_type,
isa=ISA.RISCV,
num_cores=args.num_cores,
)
cache_hierarchy = NoCache()
memory = SingleChannelDDR3_1600(size=args.mem_size)
# RISC-V 主板
board = RiscvBoard(
clk_freq="1GHz",
processor=processor,
memory=memory,
cache_hierarchy=cache_hierarchy,
)
# ========== 关键修复: 正确初始化 Full System 模式 ==========
# _set_fullsystem(True) 会设置 _is_fs=True,并自动调用 _setup_board()
# _setup_board() 会创建 RiscvBootloaderKernelWorkload 和 HiFive 平台
board._set_fullsystem(True)
# _pre_instantiate() 会检查 self._bootloader,但它是 set_kernel_disk_workload 的私有属性
# 对于 baremetal 模式,手动初始化为空列表
board._bootloader = []
# 标记 workload 已设置(某些 board 或 simulator 会检查)
board.set_is_workload_set(True)
# ========== 设置 workload 属性 ==========
if args.bootloader:
# 方式 A: OpenSBI + U-Boot
# _pre_instantiate 会检测到 _bootloader 非空并自动设置 bootloader_addr/kernel_addr/entry_point
board._bootloader = [args.bootloader]
board.workload.object_file = args.kernel
print(f"[INFO] Running with OpenSBI bootloader: {args.bootloader}")
print(f"[INFO] U-Boot (kernel) at: {args.kernel}")
else:
# 方式 B: 纯 U-Boot Baremetal(推荐)
# _pre_instantiate 会检测到 _bootloader 为空并设置 kernel_addr=0x80000000, entry_point=0x80000000
board.workload.object_file = args.kernel
# generate_device_tree 需要 command_line 不为空,否则 FdtPropertyStrings 会抛异常
board.workload.command_line = "console=ttyS0"
print(f"[INFO] Running U-Boot in bare-metal mode: {args.kernel}")
# ========== 提供 dummy disk image 以满足 VirtIOBlock 要求 ==========
# RiscvBoard._setup_board() 总是创建 virtio disk,其 image 参数是必需的
# 对于 baremetal U-Boot,我们不需要真正的 disk,但 gem5 实例化时需要这个参数
dummy_disk_path = os.path.join(tempfile.gettempdir(), "gem5_uboot_dummy.img")
if not os.path.exists(dummy_disk_path):
with open(dummy_disk_path, "wb") as f:
f.write(b"\x00" * 512)
dummy_image = CowDiskImage(child=RawDiskImage(read_only=True), read_only=False)
dummy_image.child.image_file = dummy_disk_path
board.disk.vio.image = dummy_image
# 连接 I/O 设备到总线并设置 PMA(正常由 set_kernel_disk_workload -> _add_disk_to_board 完成)
board._setup_io_devices()
board._setup_pma()
# ========== 运行仿真 ==========
simulator = Simulator(board=board)
print("[INFO] Starting simulation...")
simulator.run()
print("[INFO] Simulation finished")
方案二:运行 S-mode U-Boot + OpenSBI
如果编译了 fw_payload.elf(OpenSBI + U-Boot 打包),可以这样运行:
bash
./build/RISCV/gem5.opt configs/example/riscv/fs_linux.py \
--kernel=/path/to/opensbi/build/platform/generic/firmware/fw_payload.elf \
--bare-metal \
--cpu-type=AtomicSimpleCPU \
--mem-size=256MB
或者分别指定 bootloader(OpenSBI)和 kernel(U-Boot):
bash
./build/RISCV/gem5.opt configs/example/riscv/fs_linux.py \
--bootloader=/path/to/opensbi/build/platform/generic/firmware/fw_jump.elf \
--kernel=/path/to/u-boot/u-boot.bin \
--cpu-type=AtomicSimpleCPU \
--mem-size=256MB
查看仿真输出
方式一:使用 telnet 连接终端
gem5 默认在 3456 端口监听终端连接:
bash
# 新开一个终端
telnet localhost 3456
方式二:使用 m5term(推荐)
bash
# 编译 m5term
cd gem5/util/term
make
# 连接
./gem5term localhost 3456

完整流程汇总
bash
# ============ 1. 安装依赖 ============
sudo apt install -y build-essential git m4 scons zlib1g zlib1g-dev \
libprotobuf-dev protobuf-compiler libprotoc-dev \
libgoogle-perftools-dev python3-dev python3-six \
python-is-python3 libboost-all-dev pkg-config \
libncurses5-dev libssl-dev bc flex bison \
gcc-riscv64-linux-gnu g++-riscv64-linux-gnu \
binutils-riscv64-linux-gnu
# ============ 2. 编译 gem5 ============
git clone https://github.com/gem5/gem5.git
cd gem5
scons build/RISCV/gem5.opt -j$(nproc)
# ============ 3. 编译 U-Boot ============
cd ..
git clone https://github.com/u-boot/u-boot.git
cd u-boot
make ARCH=riscv CROSS_COMPILE=riscv64-linux-gnu- qemu-riscv64_defconfig
make ARCH=riscv CROSS_COMPILE=riscv64-linux-gnu- -j$(nproc)
# ============ 4. 运行 U-Boot ============
cd ../gem5
./build/RISCV/gem5.opt configs/example/riscv/fs_linux.py \
--kernel=../u-boot/u-boot \
--bare-metal \
--cpu-type=AtomicSimpleCPU \
--mem-size=256MB
# ============ 5. 查看输出(另开终端) ============
telnet localhost 3456
# 或
# ./util/term/m5term localhost 3456
注意事项
| 问题 | 解决方案 |
|---|---|
| gem5 编译报错缺少 zlib | sudo apt install zlib1g-dev |
| U-Boot 编译报错缺少 ncurses | sudo apt install libncurses5-dev |
| gem5 运行后终端无输出 | 确认使用了 --bare-metal 参数,检查 --kernel 路径正确 |
| 内存太小 U-Boot 启动失败 | 增大 --mem-size,建议至少 128MB |
| 需要调试信息 | 编译 gem5.opt(而非 fast),加 --debug-flags=Exec |
如果你需要在 U-Boot 中加载 Linux 内核,还需要准备 Linux 内核镜像和根文件系统,并通过 gem5 的 --kernel 和 --disk-image 参数指定。