技术知识库

扩展: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-V virt 使用 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 实验对比

项目ARM64RISC-V
Debian12 bookworm13 trixie;bookworm 主仓库无 riscv64 索引
内核架构ARCH=arm64ARCH=riscv
工具链前缀aarch64-linux-gnu-旧 Buildroot riscv64-buildroot-linux-gnu-
QEMU 程序qemu-system-aarch64qemu-system-riscv64
Linux 控制台ttyAMA0ttyS0
固件QEMU 可直接加载 Linux ImageOpenSBI M-mode 后跳转 Linux S-mode
Linux 装载-kernel Imageloader 将 Image 放到 0x80200000
固件地址本实验不单独加载OpenSBI 位于 0x80000000
QEMU 兼容参数常规 -machine virtaclint=off、priv v1.10、关闭 H
块/网卡/RNGvirtio-*-pcivirtio-*-device(MMIO)
SSH 转发端口22222223
rootfs 设备/dev/vda/dev/vda
跨架构 chrootqemu-aarch64 + binfmtqemu-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 正常。

关联