技术知识库
扩展:RISC-V Debian 根文件系统与 OpenSBI 启动
扩展:RISC-V Debian 根文件系统与 OpenSBI 启动
摘要
本篇是 ARM64 Debian rootfs 主线 的 RISC-V 扩展:在 x86_64 Ubuntu 主机上编译 Linux 5.0 RISC-V 和 OpenSBI v0.3,通过两阶段 debootstrap 构建 Debian 13 trixie riscv64,安装内核模块、制作可写 ext4 镜像,并在 QEMU 10.2 上完成 systemd、网络、SSH 与 APT 验收。
路径约定
KERNEL=/home/martin-zou/workspace/runninglinuxkernel_5.0
TOOLCHAIN=/home/martin-zou/workspace/toolchains/riscv64--glibc--bleeding-edge-2018.11-1
ROOTFS=/home/martin-zou/workspace/debian-riscv64-rootfs
IMAGE=/home/martin-zou/workspace/debian-riscv64.ext4
OPENSBI=/home/martin-zou/workspace/opensbi-v0.3
1. 准备 RISC-V 交叉工具链
Linux 5.0 RISC-V 不能直接使用本机 GCC 15/Binutils 2.46;本轮使用实验平台提供的 Buildroot GCC 8.2 工具链。故障原因见 Linux 5.0 RISC-V 无法使用 GCC 15 和 Binutils 2.46 编译。
export RISCV_TOOLCHAIN=/home/martin-zou/workspace/toolchains/riscv64--glibc--bleeding-edge-2018.11-1/bin/riscv64-buildroot-linux-gnu-
"${RISCV_TOOLCHAIN}gcc" --version
"${RISCV_TOOLCHAIN}as" --version
CROSS_COMPILE 接收的是包含结尾连字符的程序名前缀,而不是目录或某个 gcc 文件。
2. 配置并编译 Linux 5.0 RISC-V
cd /home/martin-zou/workspace/runninglinuxkernel_5.0
make ARCH=riscv \
CROSS_COMPILE="$RISCV_TOOLCHAIN" \
O=build/riscv \
defconfig
确认启动 Debian ext4 所需配置。若需要修改配置,使用 make ... menuconfig 或内核 scripts/config,修改后运行 olddefconfig;不要只改 .config 而跳过依赖解析。
grep -E \
'^(CONFIG_DEVTMPFS|CONFIG_VIRTIO|CONFIG_VIRTIO_MMIO|CONFIG_VIRTIO_BLK|CONFIG_VIRTIO_NET|CONFIG_EXT4_FS|CONFIG_SERIAL_8250|CONFIG_SERIAL_8250_CONSOLE|CONFIG_HW_RANDOM|CONFIG_HW_RANDOM_VIRTIO)=' \
build/riscv/.config
本轮使用 MMIO virtio 设备,不依赖 CONFIG_VIRTIO_PCI。编译:
make ARCH=riscv \
CROSS_COMPILE="$RISCV_TOOLCHAIN" \
O=build/riscv \
-j"$(nproc)"
file build/riscv/arch/riscv/boot/Image
make -s ARCH=riscv \
CROSS_COMPILE="$RISCV_TOOLCHAIN" \
O=build/riscv \
kernelrelease
预期 kernelrelease 为 5.0.0+。Image 和 vmlinux 是 Linux 内核;OpenSBI 是另一个项目,不会由内核构建产生。
3. 安装 debootstrap 与跨架构执行环境
sudo apt update
sudo apt install \
debootstrap debian-archive-keyring \
qemu-user-binfmt \
e2fsprogs
debootstrap --version
qemu-riscv64 --version
cat /proc/sys/fs/binfmt_misc/qemu-riscv64
Ubuntu 26.04 的 qemu-user-static 是虚拟包,应显式安装提供者 qemu-user-binfmt。机制见 binfmt_misc 与 QEMU user-mode 如何支持跨架构 chroot。
4. Bootstrap Debian 13 riscv64
Debian 12 bookworm 主仓库没有 riscv64 软件包索引,因此本轮使用正式支持 riscv64 的 Debian 13 trixie;见 Debian bookworm 主仓库没有 riscv64 软件包索引。
第一阶段:
cd /home/martin-zou/workspace
sudo debootstrap \
--arch=riscv64 \
--foreign \
--variant=minbase \
trixie \
/home/martin-zou/workspace/debian-riscv64-rootfs \
https://deb.debian.org/debian
验证:
file /home/martin-zou/workspace/debian-riscv64-rootfs/bin/dash
sudo du -sh /home/martin-zou/workspace/debian-riscv64-rootfs
ls /home/martin-zou/workspace/debian-riscv64-rootfs/debootstrap
第二阶段:
sudo chroot \
/home/martin-zou/workspace/debian-riscv64-rootfs \
/debootstrap/debootstrap --second-stage
sudo chroot \
/home/martin-zou/workspace/debian-riscv64-rootfs \
/bin/bash -c '
dpkg --print-architecture
cat /etc/os-release
'
预期架构为 riscv64,系统为 Debian 13 trixie。debootstrap 两阶段的目的见 debootstrap 为什么分成两个阶段。
5. 配置 APT 与 chroot 运行环境
sudo vim /home/martin-zou/workspace/debian-riscv64-rootfs/etc/apt/sources.list
写入:
deb https://deb.debian.org/debian trixie main
deb https://deb.debian.org/debian trixie-updates main
deb https://security.debian.org/debian-security trixie-security main
挂载运行时接口:
sudo mount --rbind \
/dev \
/home/martin-zou/workspace/debian-riscv64-rootfs/dev
sudo mount --make-rslave \
/home/martin-zou/workspace/debian-riscv64-rootfs/dev
sudo mount -t proc proc \
/home/martin-zou/workspace/debian-riscv64-rootfs/proc
sudo mount -t sysfs sysfs \
/home/martin-zou/workspace/debian-riscv64-rootfs/sys
sudo mount -t tmpfs tmpfs \
/home/martin-zou/workspace/debian-riscv64-rootfs/run
sudo chroot \
/home/martin-zou/workspace/debian-riscv64-rootfs \
/bin/bash
6. 在 chroot 中配置 Debian
以下命令在 chroot 内执行:
export LANG=C
export DEBIAN_FRONTEND=noninteractive
apt update
apt install \
systemd-sysv udev kmod \
ifupdown isc-dhcp-client iproute2 net-tools \
openssh-server sudo vim file \
build-essential ca-certificates locales
设置主机名:
vim /etc/hostname
写入:
Dreamasfishmartin
vim /etc/hosts
写入并保证主机名与 /etc/hostname 完全一致:
127.0.0.1 localhost
127.0.1.1 Dreamasfishmartin
::1 localhost ip6-localhost ip6-loopback
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters
若两处分别写成 Dreamasfishmartin 与 Dreamasfish-martin,sudo 会报告 unable to resolve host。
创建用户:
passwd root
useradd -m -s /bin/bash -u 1000 martin
passwd martin
usermod -aG sudo,users martin
配置文件系统:
vim /etc/fstab
/dev/vda / ext4 defaults 0 1
proc /proc proc defaults 0 0
配置 QEMU user networking 的静态 IPv4:
vim /etc/network/interfaces
source /etc/network/interfaces.d/*
auto lo
iface lo inet loopback
auto eth0
iface eth0 inet static
address 10.0.2.15/24
gateway 10.0.2.2
vim /etc/resolv.conf
nameserver 10.0.2.3
启用服务并只保留 UART 登录终端:
systemctl enable networking.service
systemctl enable serial-getty@ttyS0.service
systemctl enable ssh.service
systemctl disable serial-getty@hvc0.service
systemctl mask serial-getty@hvc0.service
getent passwd root martin
id martin
ls -l /sbin/init
exit
hvc0 是 Linux 通过 SBI 使用的虚拟控制台,ttyS0 是 QEMU 模拟的 8250 UART。内核可以同时保留两种驱动,但两个 getty 最终争用同一个宿主终端会造成重复登录提示和大量 ^@;这里仅屏蔽 hvc0 的登录服务,并未关闭 CONFIG_HVC_RISCV_SBI。
7. 卸载 chroot 临时挂载
sudo umount /home/martin-zou/workspace/debian-riscv64-rootfs/run
sudo umount /home/martin-zou/workspace/debian-riscv64-rootfs/sys
sudo umount /home/martin-zou/workspace/debian-riscv64-rootfs/proc
sudo umount -R /home/martin-zou/workspace/debian-riscv64-rootfs/dev
findmnt -R /home/martin-zou/workspace/debian-riscv64-rootfs
8. 安装 RISC-V 内核模块
cd /home/martin-zou/workspace/runninglinuxkernel_5.0
sudo make ARCH=riscv \
CROSS_COMPILE="$RISCV_TOOLCHAIN" \
O=build/riscv \
INSTALL_MOD_PATH=/home/martin-zou/workspace/debian-riscv64-rootfs \
modules_install
depmod 缺少 modules.builtin.modinfo 是 Linux 5.0 构建产物与新 kmod 的非阻断警告。验证模块确实属于 RISC-V:
find \
/home/martin-zou/workspace/debian-riscv64-rootfs/lib/modules/5.0.0+ \
-name '*.ko' |
head -n 1 |
xargs file
预期包含 UCB RISC-V。
9. 制作 ext4 镜像
cd /home/martin-zou/workspace
truncate -s 2G debian-riscv64.ext4
sudo mkfs.ext4 \
-F \
-L rlk-rootfs \
-O '^orphan_file' \
-d /home/martin-zou/workspace/debian-riscv64-rootfs \
/home/martin-zou/workspace/debian-riscv64.ext4
注意 -d 的源目录必须是实际使用的 debian-riscv64-rootfs,镜像必须先由 truncate 创建并指定大小;每行反斜杠后不能有空格。
ls -lh /home/martin-zou/workspace/debian-riscv64.ext4
sudo tune2fs -l /home/martin-zou/workspace/debian-riscv64.ext4 |
grep -E 'Filesystem volume name|Filesystem features|Block count|Free blocks'
10. 编译 OpenSBI v0.3
ARM64 可以由 QEMU 直接准备 Linux 启动环境;RISC-V Linux 通常运行在 S-mode,需要先由 M-mode 固件 OpenSBI 初始化并提供 SBI 服务。
cd /home/martin-zou/workspace
git clone \
--branch v0.3 \
--depth 1 \
https://github.com/riscv-software-src/opensbi.git \
opensbi-v0.3
cd /home/martin-zou/workspace/opensbi-v0.3
make CROSS_COMPILE="$RISCV_TOOLCHAIN" \
PLATFORM=qemu/virt \
-j"$(nproc)"
验证:
file build/platform/qemu/virt/firmware/fw_jump.elf
"${RISCV_TOOLCHAIN}readelf" \
-h \
build/platform/qemu/virt/firmware/fw_jump.elf
应为 RISC-V ELF,入口地址为 0x80000000。启动时使用 .elf 而不是不带装载地址元数据的 .bin。
11. 使用 QEMU 10.2 启动
qemu-system-riscv64 \
-machine virt,aclint=off \
-cpu rv64,priv_spec=v1.10.0,h=false \
-smp 2 \
-m 1024 \
-bios none \
-kernel /home/martin-zou/workspace/opensbi-v0.3/build/platform/qemu/virt/firmware/fw_jump.elf \
-device loader,file=/home/martin-zou/workspace/runninglinuxkernel_5.0/build/riscv/arch/riscv/boot/Image,addr=0x80200000 \
-append "console=ttyS0 root=/dev/vda rootfstype=ext4 rw rootwait net.ifnames=0 loglevel=8" \
-drive if=none,file=/home/martin-zou/workspace/debian-riscv64.ext4,format=raw,id=hd0 \
-device virtio-blk-device,drive=hd0 \
-netdev user,id=net0,hostfwd=tcp::2223-:22 \
-device virtio-net-device,netdev=net0 \
-object rng-random,filename=/dev/urandom,id=rng0 \
-device virtio-rng-device,rng=rng0 \
-nographic
内存与特权级关系:
0x80000000 自行编译的 OpenSBI v0.3,M-mode
0x80200000 自行编译的 Linux 5.0 Image,S-mode
Debian 用户进程,U-mode
关键兼容参数:
aclint=off:向旧内核/固件提供兼容的 CLINT 布局。priv_spec=v1.10.0:避免 QEMU 10.2 默认 v1.12 与 OpenSBI v0.3 不兼容。h=false:H 扩展要求 v1.12,必须在模拟 v1.10 时关闭。-bios none:禁止 QEMU 自动加入 OpenSBI v1.8。virtio-*-device:匹配本内核的CONFIG_VIRTIO_MMIO=y;不使用未启用的 PCI virtio 驱动。console=ttyS0:RISC-Vvirt使用 8250 UART;ttyAMA0是 ARM PrimeCell UART。
若尚未在镜像中永久 mask hvc0 getty,可临时追加:
systemd.mask=serial-getty@hvc0.service
12. 验收
使用用户 martin 登录后执行:
uname -a
cat /etc/os-release
hostname
findmnt /
systemctl is-system-running
systemctl --failed
cat /proc/sys/kernel/random/entropy_avail
ip -4 addr show eth0
ip route
systemctl status ssh --no-pager
sudo apt-get update
本轮验证结果:
架构与内核:riscv64,Linux 5.0.0+
用户空间:Debian GNU/Linux 13 (trixie)
根文件系统:/dev/vda,ext4,rw
systemd:running,0 failed units
网络:eth0 10.0.2.15/24,默认网关 10.0.2.2
SSH:active (running)
APT:trixie、trixie-updates、trixie-security 更新成功
随机熵:约 1100
主机 SSH:
ssh -p 2223 martin@127.0.0.1
13. 与 ARM64 实验对比
| 项目 | ARM64 | RISC-V |
|---|---|---|
| Debian | 12 bookworm | 13 trixie;bookworm 主仓库无 riscv64 索引 |
| 内核架构 | ARCH=arm64 | ARCH=riscv |
| 工具链前缀 | aarch64-linux-gnu- | 旧 Buildroot riscv64-buildroot-linux-gnu- |
| QEMU 程序 | qemu-system-aarch64 | qemu-system-riscv64 |
| Linux 控制台 | ttyAMA0 | ttyS0 |
| 固件 | QEMU 可直接加载 Linux Image | OpenSBI M-mode 后跳转 Linux S-mode |
| Linux 装载 | -kernel Image | loader 将 Image 放到 0x80200000 |
| 固件地址 | 本实验不单独加载 | OpenSBI 位于 0x80000000 |
| QEMU 兼容参数 | 常规 -machine virt | aclint=off、priv v1.10、关闭 H |
| 块/网卡/RNG | virtio-*-pci | virtio-*-device(MMIO) |
| SSH 转发端口 | 2222 | 2223 |
| rootfs 设备 | /dev/vda | /dev/vda |
| 跨架构 chroot | qemu-aarch64 + binfmt | qemu-riscv64 + binfmt |
两者相同的主线是:debootstrap 两阶段、chroot 配置、安装匹配内核模块、关闭 ext4 orphan_file、QEMU user networking、virtio RNG、systemd/SSH/APT 验收。主要差异集中在 Debian 版本、工具链、固件启动链、串口类型和 QEMU 设备模型。
完成标准
- 自行编译的 OpenSBI v0.3 显示本次构建时间。
- 自行编译的 Linux
5.0.0+启动并报告riscv64。 - Debian 13 从
/dev/vda以可写 ext4 挂载。 - systemd 为
running且无失败单元。 - 只有 ttyS0 getty,控制台无重复提示和
^@干扰。 - SSH、IPv4、DNS 和
apt-get update正常。