文档概述
此文档参考以下开源项目,描述了如何构建RISC-V架构的Fedora 39系统镜像,以 QEMU 平台为例,分阶段讲解了根文件系统构建、引导加载器(U-Boot)与内核编译、磁盘分区与镜像打包等关键步骤,并配以命令示例和自动化脚本模板。希望通过描述这个构建流程,能对系统的启动流程与原理有更深入的理解,并依次为参考,扩展开来构建各种不同系统与架构的镜像。
参考开源项目链接:GitHub - chainsx/fedora-riscv-builder

  1. QEMU平台下的镜像构建流程
  2. 构建根文件系统(阶段一)

此文档描述的OS镜像构建方式中,最局限性的一点既是根文件系统的构建不是从零起步的(即从所有组件源码编译开始)。我们需要构建什么系统的镜像,就先得需要有一个这个系统的环境,在此环境下再创建出此系统的最小根文件系统rootfs。故接下来的操作是在Fedora 39 riscv系统环境下以root权限用户进行的。

  1. 具体步骤:
    选择一个合适的工作目录。
    使用mkdir命令创建”rootfs”目录:
mkdir rootfs

这个目录将成为镜像里”/”(根文件系统)的挂载点和容器。
在”rootfs”目录下“虚拟”地创建一个空的RPM数据库,主要涉及的操作:

mkdir -p rootfs/var/lib/rpm

RPM包管理器需要一个数据库目录来记录已安装的包信息。这里手动提前创建RPM数据库的存放路径,避免后面”rpm –initdb”命令报错。

rpm --root $WORKDIR/rootfs/ --initdb

使用RPM自带的初始化命令来创建数据库。这样做是为了后续能往这个“假”系统里安全rpm包。
让rootfs拥有Fedora标准的仓库源配置:

rpm -ivh --nodeps --root $WORKDIR/rootfs/ http://fedora.riscv.rocks/repos-dist/f39/latest/riscv64/Packages/f/fedora-release-39-0.21.noarch.rpm
往rootfs里安装”fedora-release”包,它会在目标系统里放置一系列默认的repo配置文件。“—nodeps”用来跳过依赖环境,因为当前空的rootfs里还没有任何依赖环境。
如果是构建其他系统,就灵活地换成目标系统的release包。


如果嫌弃Fedora默认的仓库源配置链接有困难,之后可以自定义修改rootfs/etc/yum.repos.d/目录中的内容。
在rootfs中里再安装一次dnf包本身:

dnf --installroot=$WORKDIR/rootfs/ install dnf --nogpgcheck -y
这样做的原因是:最开始只有rpm可用,dnf并没有被安装进目标rootfs。安装dnf后,就可以在这个隔离的环境里方便地通过dnf拉取更多软件包、更新元数据、解决依赖。


把rootfs目录打包成tarball:

cd $WORKDIR/rootfstar -zcvf fedora-39-core-rootfs.tar.gz .
生成的fedora-39-core-rootfs.tar.gz就是一个“最小“Fedora 39 RISC-V根文件系统,后续可以:直接导入Docker作为镜像层解包到QEMU/实际机器的分区里也可以在此基础上再用”dnf --installroot“安装其他软件
  1. 整体思路回顾
  2. 从空目录搭建一个RPM数据库;
  3. 安装release包,把官方repo文件放进来;
  4. 可选地对于源配置的修改;
  5. 安装DNF,以便可复用的包管理;
  6. 打包成tarball,得到一个rootfs镜像。

Figure 1 构建根文件系统阶段一

  1. 思考
安装DNF的意义?
在一个刚初始化、只有 RPM 数据库但没有包管理工具的空 rootfs 里,把 DNF 安装进去。只有装上 DNF,后面才能在这个 chroot 环境里通过它来一键安装和管理网络、SSH、dracut、驱动等所有系统组件,而不会影响到宿主机系统。
rootfs中何时拥有了完整FHS(Filesystem Hierarchy Standard)结构?
在安装了 fedora-release 包(建立基本目录骨架)并通过 DNF 安装了 filesystem、coreutils、bash、glibc 等基础软件包后,rootfs 才具备完整的 FHS 结构。
  1. 构建根文件系统(阶段二)
    1. 具体步骤
      把rootfs的tarball转移到一个新的Linux系统下完成接下来的整体OS镜像构建任务。该构建环境应该支持apt包管理器,且和架构无关。故此文档使用x86架构下的Ubuntu较新版本系统来进行构建任务。
      首先,要在此环境下安装一些必要的包:
apt updateapt install parted zstd make bison bc flex kpartx xz-utils qemu-user-static libssl-dev gcc-riscv64-linux-gnu -y
此处安装的是后续构建所需的工具和依赖,下面针对每个包的作用做个简要说明:parted:用来操作磁盘镜像的分区表后面会把打包好的rootfs镜像写入到分区中。zstd:支持zstd压缩/解压格式。make:各种开源项目(Linux内核、U-Boot、OpenSBI)的标准构建工具。bison和flex:在编译一些底层工具时,需要生成词法/语法分析器。bc:在Linux内核的Makefile中,用于计算内核版本号等小数运算。kpartx:将镜像文件中的分区映射为/dev/loopXpY设备,方便在宿主机上直接挂载、写入文件。zx-utils:支持XZ(.xz)格式的压缩/解压。qemu-user-static:提供静态编译的QEMU用户态模拟器(比如qemu-riscv64-static),可以让你在x86宿主机上chroot进RISC-V的rootfs,自动用QEMU转译执行里面的二进制,从而在宿主机上安装RISC-V架构的包、运行脚本。libssl-dev:OpenSSL的开发头文件/库。gcc-riscv64-linux-gnu:RISC-V 64位架构的交叉编译器,用于在x86机器上编译生成RISC-V的内核、U-Boot、OpenSBI等二进制。


在新的构建环境下,解压rootfs.tar.gz到rootfs目录:

tar -zxvf rootfs.tar.gz -C ${rootfs_dir}


复制宿主机的DNS配置到rootfs内,保证chroot之后能正确做域名解析:

cp -b /etc/resolv.conf ${rootfs_dir}/etc/resolv.conf


挂载虚拟文件系统,为chroot保证运行环境

mount --bind /dev ${rootfs_dir}/devmount -t proc /proc ${rootfs_dir}/procmount -t sysfs /sys ${rootfs_dir}/sys
把宿主机的/dev、/proc、/sys挂载到rootfs中对应位置,使得在chroot里能访问设备文件、进程信息和内核接口。这是常见的chroot准备工作,否则很多系统工具(尤其是dnf、systemctl、udev脚本)会因为“找不到/proc或/sys“而报错。


在chroot中更新系统并安装额外软件包

chroot ${rootfs_dir} dnf update -y
进入chroot,更新系统,把基础系统包都升级到最新。
chroot ${rootfs_dir} dnf install alsa-utils haveged wpa_supplicant vim net-tools iproute iputils NetworkManager bluez fedora-release-server passwd hostname -ychroot ${rootfs_dir} dnf install wget openssh-server openssh-clients parted realtek-firmware chkconfig e2fsprogs dracut NetworkManager-wifi -y
安装一系列常用和必须的软件:音频和随机数:alas-utils(音频工具),haveged(用户态熵守护进程,提升系统随机数池);网络管理:wpa_supplicant(Wi-Fi安全握手),NetworkManager及其Wi-Fi插件,bluez(蓝牙支持),net-tools/iproute/iputils(各种网络命令);编辑与下载:vim、wget;SSH远程访问:openssh-server/openssh-client;分区与文件系统:parted、e2fsprogs;引导与初始化:dracut(生成initramfs)、chkconfig(SysV init服务管理);固件支持:realtek-firmware(常见网卡固件);系统基础:passwd(设置密码)、hostname。


配置系统基础信息和启动脚本

echo fedora-riscv > ${rootfs_dir}/etc/hostname
写入主机名为”fedora-riscv”。
cp $build_dir/config/extend-root.sh ${rootfs_dir}/etc/rc.d/init.d/extend-root.shchmod +x ${rootfs_dir}/etc/rc.d/init.d/extend-root.sh
把项目提供的extend-root.sh(通常是用来首次启动时扩展根文件分区到整盘大小的脚本)拷贝到SysV init目录,并设为可执行。


修改SSH配置,允许以root登录:

sed -i "s|#PermitRootLogin prohibit-password|PermitRootLogin yes|g" ${rootfs_dir}/etc/ssh/sshd_config


在chroot下设置密码、启用脚本并生成initramfs:

cat << EOF | chroot ${rootfs_dir} /bin/bash echo 'fedora' | passwd --stdin root chkconfig --add extend-root.sh chkconfig extend-root.sh on dracut --no-kernel /boot/initrd.imgEOF
这段通过here-doc批量在chroot里执行:设置root密码为”fedora”;添加并打开SysV init脚本extend-root.sh,保证每次启动时自动运行;重建initramfs(dracut --no-kernel 表示只更新initramfs,不替换内核本身),生成新的/boot/initrd.img,让启动时能正确挂载、扩展分区等。
    1. 整体思路回顾

  1. rootfs tarball解包:在新构建环境里还原rootfs;
  2. chroot环境挂载:确保包管理和脚本能在chroot中正常运行;
  3. 更新 & 安装:补齐常用服务与实用工具;
  4. 系统配置:设置主机名、SSH root登录、初始化脚本;
  5. 初始化脚本 & initramfs:让首次启动后自动扩展分区并重新打包initramfs镜像。

Figure 2 构建根文件系统阶段二

  1. 思考
mount --bind /dev ${rootfs_dir}/devmount -t proc /proc ${rootfs_dir}/procmount -t sysfs /sys ${rootfs_dir}/sys此类挂载命令的具体解释和意义,chroot需要和这些操作打配合?
这些挂载操作的目的都是在新的 rootfs 环境中,暴露出宿主机已有的特殊文件系统,让 chroot 进去后的进程能正常访问硬件设备、进程信息和内核接口——否则很多命令(包括 DNF 安装、udev 规则执行、模块加载脚本等)都会因为找不到 /dev、/proc 或 /sys 而报错。只有在这些特殊文件系统都挂好之后,再执行 chroot ${rootfs_dir},进入那个环境的 shell 或脚本才能像在“真正的”系统里一样工作,正确识别和管理设备、加载模块、执行服务安装。
dracut以及initrd.img之间的关系?
dracut是一个生成 initrd.img (或 initramfs)的工具,根据系统当前驱动和配置打包出启动时的临时根文件系统。 initrd.img是由 dracut (或其他同类工具)创建的初始内存盘镜像,内核在启动时加载它来完成早期驱动加载和根文件系统挂载。
  1. 编译Linux Kernel镜像
    1. 具体步骤
      克隆源码:
git clone --depth=1 https://github.com/torvalds/linux.git -b v6.6
只拉取Linux仓库中v6.6这个标签(版本)的最新提交,并且用--depth=1做浅克隆,节省时间和磁盘空间。


进入项目源码,安装定制的内核配置:

cp $build_dir/config/linux-qemu-current.config arch/riscv/configs/linux-qemu-current_defconfig
将此项目事先准备好的config文件复制到内核源码中RISC-V架构的配置目录,这样接下来可以以这份配置为基础生成.config。


生成 .config文件:

make ARCH=riscv CROSS_COMPILE=riscv64-linux-gnu- linux-qemu-current_defconfig
交叉编译


编译内核和内核模块:

make ARCH=riscv CROSS_COMPILE=riscv64-linux-gnu- -j$(nproc)


安装内核模块到临时目录:

make ARCH=riscv CROSS_COMPILE=riscv64-linux-gnu- modules_install INSTALL_MOD_PATH=kmod


拷贝模块到rootfs:

cp -rfp linux/kmod/lib/modules/* rootfs/lib/modules
    1. 整体思路回顾

  1. 拉取指定版本的内核源码;
  2. 用定制的defconfig生成内核配置.confgi,保证编译出来的内核满足QEMU或开发板上对设备、文件系统、网络等的需求。
  3. 交叉编译 生成针对RISC-V架构的内核映像和模块。
  4. 安装模块到临时目录再拷贝到rootfs,让新内核在启动时能够加载到所有必要的模块。
  5. 编译U-Boot
    1. 具体步骤
      克隆U-Boot源码:
git clone --depth=1 https://github.com/u-boot/u-boot.git -b v2022.04


进入源码目录,加载默认配置:

make ARCH=riscv CROSS_COMPILE=riscv64-linux-gnu- qemu-riscv64_smode_defconfig


编译U-Boot

make ARCH=riscv CROSS_COMPILE=riscv64-linux-gnu- -j$(nproc)
编译流程会生成:SPL(二级引导加载器,用于板级最初启动)u-boot.bin(主引导程序,可解析设备树并加载Linux)设备树二进制(.dtb文件)


拷贝输出固件:

cp u-boot-nodtb.bin $build_dir/firmware
u-boot-nodtb.bin是U-Boot主映像(u-boot.bin)与SPL合并后的二进制,但不内嵌任何.dtb;将其复制出来,供后面写入镜像分区或打包镜像时使用。
    1. 整体思路回顾

  1. 浅克隆指定版本;
  2. Defconfig;
  3. 交叉编译;
  4. 分离设备树;
  5. 思考
U-Boot的版本有什么需求吗?需要考虑和内核、opensbi、rootfs以及硬件环境的适配吗?
选择 U-Boot 版本时要注意以下兼容性:硬件平台支持必须选用含有你目标板硬件驱动(SoC、存储、网络控制器等)的 U-Boot 版本。不同板卡的 DeviceTree、驱动补丁各异。RISC-V 架构支持需要包含 RISC-V 相关的 defconfig(如 qemu-riscv64_smode_defconfig 或你板子的专用 defconfig),并且交叉编译工具链要匹配。OpenSBI 协同U-Boot 要和 OpenSBI 约定好的入口点和跳转方式保持一致。常见做法是先用 OpenSBI 加载,然后跳转到 U-Boot;二者版本(API/ABI)应尽量匹配。内核兼容性U-Boot 加载内核时会解析 DeviceTree 和传递启动参数,内核版本更新后要确保 U-Boot 的 DTB 生成脚本或二进制能匹配内核所需的设备描述。RootFS 与文件系统如果你用 extlinux/ext4/VFAT 等做启动分区和根分区,U-Boot 要编译进对对应文件系统的支持(比如对 FAT/ext4 的驱动)。总结:U-Boot 版本选型不仅要看它本身的 RISC-V 能力,还要和 OpenSBI、Linux 内核、DeviceTree、启动分区格式、目标硬件驱动链路紧密配合,才能保证一键无误地加载并启动系统。
  1. 编译opensbi
    1. 具体步骤
      浅克隆指定版本的OpenSBI:
git clone --depth=1 https://github.com/riscv-software-src/opensbi.git -b v1.3


进入源码目录,编译OpenSBI通用平台固件:

make PLATFORM=generic PLATFORM_RISCV_XLEN=64 CROSS_COMPILE=riscv64-linux-gnu- -j$(nproc)
编译结果会在build/platform/generic/firmware/下生成若干固件镜像,其中最常用的是:fw_jump.bin:一个非常精简的OpenSBI固件,执行硬件初始化后直接跳转到下一级引导(通常是U-Boot);fw_dynamic.bin:包含更复杂功能(如动态补丁、可选模块),体积更大、用于更完整的固件场景。


拷贝输出固件:

cp build/platform/generic/firmware/fw_jump.bin $build_dir/firmware
    1. 思考
opensbi是什么,作用为何?
OpenSBI(Open Supervisor Binary Interface)是 RISC-V 平台上运行在机器模式(M-mode)的一段固件,实现了 SBI(监督二进制接口)标准。作用硬件初始化:上电后在 M-mode 下完成中断控制器、定时器、串口等底层外设的配置。提供 SBI 服务:为运行在监督模式(S-mode)的操作系统(如 Linux)暴露统一的调用接口(例如启动其他核、读写时钟、系统重启等),屏蔽不同硬件的实现差异。模式切换:在完成 M-mode 初始化后,将控制权安全地传递给引导加载程序(如 U-Boot)或直接进入操作系统的 S-mode,确保系统可在标准化环境下启动。

  1. 生成并组装OS镜像
    1. 具体步骤
      计算镜像大小并创建空镜像:
size=`du -sh --block-size=1MiB ${build_dir}/rootfs | cut -f 1 | xargs`size=$(($size+720))losetup -Dimg_file=${build_dir}/rootfs.imgdd if=/dev/zero of=${img_file} bs=1MiB count=$size status=progress && sync
计算所需空间du -sh --block-size=1MiB ${build_dir}/rootfs:统计已经准备好的rootfs目录在目标镜像中解包后所占空间(以MiB为单位)。size=$(($size+720)):在rootfs大小基础上多加720MiB,预留给/boot、日志、升级等空间。清理所有loop设备losetup -D:将宿主机上所有losetup设备先解除绑定,防止后面创建失败或冲突。用零填充创建镜像文件dd if=/dev/zero of=${img_file} bs=1MiB count=$size:生成一个大小为$size MiB的空白镜像文件;status=progress:实时显示写入进度,sync确保磁盘缓存刷新。


在镜像上创建分区表与分区:

parted ${img_file} mklabel gpt mkpart primary fat32 32768s 524287sparted ${img_file} mkpart primary ext4 524288s 100%
mklabel gpt:给镜像文件打GPT分区表,支持大容量和多分区。第一分区:类型fat32,起始扇区32768s(通常是16MiB处,留足对齐空间)、结束扇区524287s(大约为256MiB);用作/boot或引导分区,格式化成VFAT方便U-Boot/extlinux读取。(why)第二个分区:类型ext4,从524288s(256MiB对齐)到镜像末尾,用作根文件系统。注意:在有些环境下,对一镜像文件执行上述的两次parted,最后结果可能不符合预期中的生成两个分区,也许会只生产了一个。建议尝试使用parted进入它的命令行模式下执行打分区表和创建两个分区的操作。


挂载镜像分区为loop设备

device=`losetup -f --show -P ${img_file}`trap 'LOSETUP_D_IMG' EXITkpartx -va ${device}loopX=${device##*\/}partprobe ${device}
关联loop设备losetup -f --show -P rootfs.img:自动寻找空闲 loop 设备(如 /dev/loop0),把整个镜像映射到该设备,并用 -P 自动扫描分区;返回值 device 如 /dev/loop0。创建设备映射节点kpartx -va /dev/loop0:为其中的 GPT 分区创建设备映射 /dev/mapper/loop0p1、loop0p2;partprobe:告诉内核重新读取分区表,确保后续工具能识别。


格式化并挂载分区:

sdbootp=/dev/mapper/${loopX}p1sdrootp=/dev/mapper/${loopX}p2mkfs.vfat -n fedora-boot ${sdbootp}mkfs.ext4 -L fedora-root ${sdrootp}mkdir -p ${root_mnt} ${boot_mnt}mount ${sdbootp} ${boot_mnt}mount ${sdrootp} ${root_mnt}
设置环境变量sdbootp、sdrootp 分别指向引导与根分区映射设备格式化mkfs.vfat -n fedora-boot:把 p1 做成 VFAT 并打 label;mkfs.ext4 -L fedora-root:把 p2 做成 ext4 并打 label。挂载创建并分别挂载到自定义的 ${boot_mnt}、${root_mnt}目录,后续把内容写入这两个挂载点。


配置引导加载器:

mkdir -p $boot_mnt/extlinux
extlinux(Syslinux的一部分)用于U-Boot/extlinux模式下读取extlinux.conf来启动内核。
line=$(blkid | grep $sdrootp)uuid=${line#*UUID=\"}uuid=${uuid%%\"*}
用blkid读取根分区的UUID,并提取出来,保证extlinux.conf中的根文件系统挂载指向正确的标签。
echo "label Fedora kernel /Image initrd /initrd.img append console=ttyS0,115200 root=UUID=${uuid} rootfstype=ext4 rootwait rw earlycon loglevel=7 init=/lib/systemd/systemd" \> $boot_mnt/extlinux/extlinux.conf
生成extlinux.conf引导配置:kernel:指向前面拷贝的Linux内核镜像/Image;initrd:指向initramfs /initrd.img;append:内核命令行,打开串口控制台、指定根分区、文件系统类型、初始化程序等。


拷贝固件、内核和更新fstab:

cp $build_dir/firmware/fw_jump.bin $boot_mntcp $build_dir/linux/arch/riscv/boot/Image $boot_mnt
把OpenSBI固件(fw_jump.bin)和RISC-V内核镜像(Image)复制到引导分区。
echo "LABEL=fedora-root / ext4 defaults,noatime 0 0" > ${build_dir}/rootfs/etc/fstabecho "LABEL=fedora-boot /boot vfat defaults,noatime 0 0" >> ${build_dir}/rootfs/etc/fstab
在根文件系统的fstab中写入两行,确保启动后能正确挂载根和/boot分区。


填充/boot与根文件系统

cp -rfp ${build_dir}/rootfs/boot/* $boot_mntrm -rf ${build_dir}/rootfs/boot/*
移动原先解包并chroot后存放在rootfs/boot下的启动文件(initrd、旧内核等)到实际的boot分区,保持逻辑分离;清空rootfs/boot目录,为后面rsync做准备。
rsync -avHAXq ${build_dir}/rootfs/* ${root_mnt}syncsleep 10
用rsync将整个根文件系统(除了/boot)复制到挂载的根分区,再sync和稍等保证数据完全落盘。


卸载和收尾:

umount $sdrootpumount $sdbootpLOSETUP_D_IMGUMOUNT_ALLlosetup -Dkpartx -d ${img_file}
按照反向顺序卸载根和引导分区;确保所有绑定和挂载被清理;再次losetup -D解除所有loop设备,最后kpartx -d删除为镜像创建的/dev/mapper分区节点。
    1. 整体思路回顾

  1. 创建一个足够大的空白镜像文件;
  2. GPT分区:一个FAT32引导分区 + 一个ext4根分区;
  3. 挂载并格式化分区;
  4. 生成extlinux引导配置,填充固件(OpenSBI),内核和initramfs;
  5. 写入根文件系统并配置fstab;
  6. 卸载和清理,得到一个可直接刷入设备或用于QEMU启动的完整rootfs.img。

Figure 3 生成并组装OS镜像

  1. 思考
losetup命令是什么,作用为何?
losetup 是 Linux 下用来管理 Loop 设备(虚拟块设备)的命令。它的主要作用:将一个常规文件或设备 映射成一个块设备(如 /dev/loop0),使得该文件能像真实磁盘分区一样被挂载、格式化、读写。管理已创建的 Loop 设备,查看、设置、释放映射关系。所以,通过 losetup,你可以在无需真实硬件的情况下,用文件来模拟磁盘分区,这在制作和测试磁盘镜像时非常方便。
extlinux是什么,作用为何?与U-Boot之间的联系?
它的主要作用为在启动分区(格式为 ext2/3/4)上读取并解析一个名为 extlinux.conf 的文本配置文件,根据配置加载指定的内核映像、initrd(初始内存盘)以及传递给内核的启动参数。与U-Boot的联系:在 RISC-V 嵌入式场景中,U-Boot 作为第一阶段引导程序,完成底层硬件初始化后,会去启动分区(通常是 FAT 或 EXT 分区)寻找并加载第二阶段的引导器。如果该分区上安装的是 extlinux(即包含 extlinux/extlinux.conf),U-Boot 会调用其内置的 EXT 驱动来挂载分区,读取并执行 extlinux 配置,进而加载内核和 initrd。换句话说,U-Boot ↔ extlinux 的配合让我们不用在 U-Boot 代码里硬编码内核路径或启动参数,只需通过 extlinux.conf 灵活地管理多个启动项和参数。这样既简化了 U-Boot 配置,又提高了启动流程的可维护性。
fstab是什么,作用为何?
/etc/fstab 是系统启动时自动挂载文件系统的配置文件:内核或 init 系统读取它,根据配置自动将各个分区或远程文件系统挂载到指定位置,无需手动执行 mount。
根文件系统中的/boot,为何要把内容复制到boot分区,还要清空/boot目录?
因为我们把启动相关的文件(内核镜像、initrd、OpenSBI 固件、extlinux 配置等)放在了一个独立的启动分区上,所以要: 复制到启动分区:让 U-Boot 或固件在挂载根分区之前就能直接从启动分区加载这些文件; 清空 rootfs 下的 /boot:避免在真正启动后再挂载启动分区时出现文件冲突或冗余,确保真正的启动文件都只在启动分区中。
rsync命令行工具是什么,为什么不用cp?
在镜像制作和系统部署时,用 rsync -avHAX(递归、保属性、保硬链、保ACL、保扩展属性)能更可靠、高效地将完整的 rootfs 内容复制到挂载点,而不仅仅是机械地拷贝文件。
kpartx命令行工具是什么?
kpartx 是一个基于 Linux Device-Mapper 的工具,用于将磁盘映像文件或块设备中的分区表映射成单独的块设备节点。读取磁盘镜像(如 .img)或裸设备上的分区表(MBR/GPT)。自动为每个分区创建对应的 /dev/mapper/<映射名>p<分区号> 设备节点,便于后续挂载或操作。
  1. 使用QEMU启动镜像

现在,rootfs镜像文件已经包含了VFAT引导分区以及EXT4根分区。还准备好了编译完成的OpenSBI固件以及U-Boot内核镜像。现在可以使用qemu工具来启动此OS镜像,具体命令如下:

qemu-system-riscv64 -machine virt -nographic \-smp 8,core=8,threads=1,socket=1 -m 2G \-bios fw_jump.bin \-kernel u-boot-nodtb.bin \-drive file=rootfs.img,format=raw,id=hd0 \-device virtio-blk-device,drive=hd0 \-audiodev pa,id=snd0 \-object rng-random,filename=/dev/urandom,id=rng0 \-device virtio-rng-device,rng=rng0 \-device virtio-net-device,netdev=usernet \-netdev user,id=usernet \-device qemu-xhci -usb -device usb-kbd -device usb-tablet -device usb-audio,audiodev=snd0
基本机器与控制台设置-machine virt-nographicCPU与内存配置-smp 8,core=8,threads=1,socket=1-m 2G引导链:固件(OpenSBI)-> U-Boot-bios fw_jump.bin把OpenSBI固件当作”BIOS”加载。虚拟机“上电”后,首先执行此文件,完成最底层硬件初始化并提供SBI接口。-kernel u-boot-nodtb.bin在OpenSBI完成后,qemu会把这个文件当作“内核”加载---这里实际上是U-Boot主映像(不带DTB)。U-Boot接管控制台后再去加载真正的Linux。根文件系统:虚拟磁盘-drive file=rootfs.img,format=raw,id=hd0把前面生成的rootfs.img当作一块原始磁盘(raw),标识为hd0。-device virtio-blk-device,drive=hd0在虚拟机里挂载一个Virtio块设备,对应这块磁盘。Linux内核的virtio驱动会识别成/dev/vda,并读取其中的GPT分区、文件系统、fstab。外设模拟启动流程QEMU上电--》加载fw_jump.bin(OpenSBI)OpenSBI初始化后--》跳转至加载的U-Boot(-kernel u-boot-nodtb.bin)U-Boot执行extlinux.conf或手动命令---》把设备树、Linux内核镜像Image、initrd.img加载到内存U-Boot将控制权交给Linux-》Linux内核启动,挂载Virtio块设备(rootfs.img)的根分区
Logo

这里是“一人公司”的成长家园。我们提供从产品曝光、技术变现到法律财税的全栈内容,并连接云服务、办公空间等稀缺资源,助你专注创造,无忧运营。

更多推荐