训练营学员

傲来操作系统训练营报告

RISC-V Toolchain And QEMU9.0源码编译

Chen Miao 发布于 # 2024 年第一期

RISC-V Toolchain源码构建

RISC-V是一个基于精简指令集原则的开源指令集架构,目前随着越来越多的开发者参与到RISC-V社区的开发中,RISC-V的热度逐年高涨。如何构建一个属于自己的RISC-V GNU交叉编译工具链用来使用就显得十分有必要了。

源码获取

RISC-V的源码地址有两种方式获取:

  • 第一种则是放置在GITHUB上的仓库riscv-gnu-toolchain中,比较推荐网络状况良好的读者使用
  • 第二种则是放置在GITEE上的镜像仓库riscv-gnu-toolchain比较推荐网络状况不是那么良好的读者使用

在这里,我便以第一种方式进行演示。如果读者在进入GITHUB或GITEE镜像网页进行克隆时,应该能够注意到README中的构建提示:--recursive但是需要注意的是,这是不需要的选项;或者说,构建RISC-V工具链不强制需要

如果读者选择--recursive,那么请您至少预留40G的磁盘空间,谨防磁盘爆炸

git clone https://github.com/riscv-collab/riscv-gnu-toolchain

依赖获取

对于不同版本的系统,需要的安装的依赖有些许差异。

我当前的版本是Ubuntu22.04 LTS,当然,我也会将其他主流发行版本的依赖配置给出。

对于Ubuntu而言:

 sudo apt-get install autoconf automake autotools-dev curl python3 python3-pip libmpc-dev libmpfr-dev libgmp-dev gawk build-essential bison flex texinfo gperf libtool patchutils bc zlib1g-dev libexpat-dev ninja-build git cmake libglib2.0-dev libslirp-dev

对于RPM系(Fedora、CentOS和RHEL OS)而言:

 sudo yum install autoconf automake python3 libmpc-devel mpfr-devel gmp-devel gawk  bison flex texinfo patchutils gcc gcc-c++ zlib-devel expat-devel libslirp-devel

对于Arch系:

 sudo pacman -Syyu autoconf automake curl python3 libmpc mpfr gmp gawk base-devel bison flex texinfo gperf libtool patchutils bc zlib expat libslirp

编译

目前我的环境为:Ubuntu22.04 LTS,为了编译时不会报错,我选择了一个较为稳定的版本:2024.04.12,并且只下载了部分模块:

cd riscv-gnu-toolchain
git checkout 2024.04.12

git submodule init gcc gdb musl binutils
git submodule update --remote gcc gdb musl binutils

对于一般需求而言,我们通常只需要构建LinuxMultilib即可,如果需要构建Newlib,其大致流程和前两种几乎一致。

在选择其他功能前,我们需要设置一下riscv-gnu-toolchain将要安装的位置,通过--prefix来进行设置:

--prefix=PREFIX         install architecture-independent files in PREFIX [/usr/local]

在构建Linux时,有两种版本和一些小的组件可以选择:rv32rv64这两种版本。同时这两种版本对应的一些小组件,使用--with-arch--with-abi进行选择。

  • --with-arch支持的有必须的(i)(a)tomics(m)ultiplication and division(f)loat(d)ouble、 or (g)eneral for MAFD.
  • --with-abi支持的有ilp32ilp32dilp32flp64lp64flp64d.
--with-arch=rv64imafdc  Sets the base RISC-V ISA, defaults to rv64imafdc
--with-abi=lp64d        Sets the base RISC-V ABI, defaults to lp64d

通常而言,遵循默认设置或如下设置即可(如有特殊需求,则需要自行添加):

./configure --prefix=/opt/riscv --with-arch=rv32gc --with-abi=ilp32d # 构建RV32(选择其中一个即可)
./configure --prefix=/opt/riscv --with-arch=rv64gc --with-abi=lp64d  # 构建RV64
sudo make linux -j(nproc)

在构建Multilib时,参数几乎一致,直接运行即可:

./configure --prefix=/opt/riscv --enable-multilib
sudo make linux -j(nproc)
sudo make musl -j(nproc)

至此,构建就结束了。

测试

riscv64-unknown-linux-gnu-gcc --print-multi-lib
.;
lib32/ilp32;@march=rv32imac@mabi=ilp32
lib32/ilp32d;@march=rv32imafdc@mabi=ilp32d
lib64/lp64;@march=rv64imac@mabi=lp64
lib64/lp64d;@march=rv64imafdc@mabi=lp64d

riscv64-unknown-linux-gnu-g++ --print-multi-lib
.;
lib32/ilp32;@march=rv32imac@mabi=ilp32
lib32/ilp32d;@march=rv32imafdc@mabi=ilp32d
lib64/lp64;@march=rv64imac@mabi=lp64
lib64/lp64d;@march=rv64imafdc@mabi=lp64d

QEMU9.0源码编译

QEMU(Quick Emulator)是一款免费开源模拟器,其与Bochs,PearPC类似,但拥有高速(配合KVM)、跨平台的特性。

QEMU是一个托管的虚拟机,它使用动态二进制转换技术来模拟处理器,并且提供多种硬件和外设模型,这使它能够运行多种未修改的客户机操作系统,能与KVM配合以接近本地速度运行虚拟机(接近真实电脑的速度)。

源码获取

源码获取依旧有两种方式:

  • QEMU官网直接下载
  • 通过wget在终端上下载(推荐)
wget https://download.qemu.org/qemu-9.0.0.tar.xz
tar xvJf qemu-9.0.0.tar.xz

依赖获取

当前我的环境为Ubuntu22.04 LTS,其他发行版可以在构建时通过报错下载所缺少的依赖。

sudo apt install autoconf automake autotools-dev curl libmpc-dev libmpfr-dev libgmp-dev \
                 gawk build-essential bison flex texinfo gperf libtool patchutils bc \
                 zlib1g-dev libexpat-dev git \
                 libglib2.0-dev libfdt-dev libpixman-1-dev \
                 libncurses5-dev libncursesw5-dev

编译

新版本的(Qemu9.0.0)的编译时直接全部架构编译安装。

--target-list=LIST       set target list (default: build all)
                           Available targets: aarch64-linux-user 
                           aarch64_be-linux-user alpha-linux-user 
                           arm-linux-user armeb-linux-user cris-linux-user 
                           hexagon-linux-user hppa-linux-user i386-linux-user 
                           loongarch64-linux-user m68k-linux-user 
                           microblaze-linux-user microblazeel-linux-user 
                           mips-linux-user mips64-linux-user 
                           mips64el-linux-user mipsel-linux-user 
                           mipsn32-linux-user mipsn32el-linux-user 
                           nios2-linux-user or1k-linux-user ppc-linux-user 
                           ppc64-linux-user ppc64le-linux-user 
                           riscv32-linux-user riscv64-linux-user 
                           s390x-linux-user sh4-linux-user sh4eb-linux-user 
                           sparc-linux-user sparc32plus-linux-user 
                           sparc64-linux-user x86_64-linux-user 
                           xtensa-linux-user xtensaeb-linux-user 
                           aarch64-softmmu alpha-softmmu arm-softmmu 
                           avr-softmmu cris-softmmu hppa-softmmu i386-softmmu 
                           loongarch64-softmmu m68k-softmmu microblaze-softmmu 
                           microblazeel-softmmu mips-softmmu mips64-softmmu 
                           mips64el-softmmu mipsel-softmmu nios2-softmmu 
                           or1k-softmmu ppc-softmmu ppc64-softmmu 
                           riscv32-softmmu riscv64-softmmu rx-softmmu 
                           s390x-softmmu sh4-softmmu sh4eb-softmmu 
                           sparc-softmmu sparc64-softmmu tricore-softmmu 
                           x86_64-softmmu xtensa-softmmu xtensaeb-softmmu

因此,我们可以做出选择:

./configure --prefix=/opt/qemu --target-list=riscv64-softmmu,riscv64-linux-user
make -j $(nproc)
sudo make install

测试

qemu-riscv64 -version
qemu-riscv64 version 9.0.0

qemu-system-riscv64 -version
QEMU emulator version 9.0.0

QEMU部分参数解析

基于阶段一和阶段二中使用的qemu命令做出简要解释:

  • -m 或 —m:指定虚拟机的内存大小。例如,-m 2G 表示分配2GB的内存给虚拟机。
  • -smp:指定虚拟机的处理器数量和拓扑结构。例如,-smp 4 表示使用4个处理器。
  • -cpu:指定虚拟机使用的CPU型号或架构。例如,-cpu host 表示使用宿主机的CPU。
  • -device:指定虚拟机添加和配置虚拟设备。例如,-device virtio-net表示添加一个VirtIO网络设备。
  • -bios:指定虚拟机的BIOS文件。例如,-bios /usr/lib/riscv64-linux-gnu/opensbi/generic/fw_jump.elf
  • -kernel:指定要用作虚拟机内核的镜像文件。例如,-kernel /usr/lib/u-boot/qemu-riscv64_smode/uboot.elf
  • -virtfs:-virtfs [tag|mount_tag][,driver[,mount_options]], 用于配置虚拟文件系统,virtfs允许将主机文件系统的目录或文件与虚拟机进行共享,以便虚拟机可以访问和操作这些文件
  • -hda 或 -drive:指定虚拟机的硬盘镜像文件或设备。例如,-hda disk.img 表示使用名为 disk.img 的硬盘镜像文件作为虚拟机的主硬盘。
  • -cdrom:指定虚拟机的光驱设备,可以用于加载ISO镜像文件。例如,-cdrom os.iso 表示使用名为 os.iso 的ISO镜像文件作为光驱。
  • -boot:指定虚拟机的启动顺序。例如,-boot c 表示从硬盘启动,-boot d 表示从光驱启动。
  • -net:配置虚拟机的网络设置。例如,-net nic 表示为虚拟机添加一个网络适配器,-net user 表示使用用户模式网络栈。
  • -vnc:启用VNC远程访问功能。例如,-vnc :1 表示在端口5901上启动VNC服务器。
  • -usb:启用虚拟机的USB支持。例如,-usb 表示启用USB控制器。
  • -snapshot:启用快照模式,允许创建和恢复虚拟机的快照。 -monitor:启动一个与虚拟机交互的监控控制台。例如,-monitor stdio 表示将监控控制台输出重定向到标准输入/输出。
  • -nographic:参数用于在无图形化界面的模式下运行虚拟机
  • -name:为虚拟机指定一个名称
qemu-system-riscv64 \
    -machine 'virt' \
    -cpu 'rv64' \
    -m 1G \
    -device virtio-blk-device,drive=hd \
    -drive file=qcow2镜像路径,if=none,id=hd \
    -virtfs local,id=lee,path=实验工程路径,mount_tag=lee,security_model=passthrough \
    -bios /usr/lib/riscv64-linux-gnu/opensbi/generic/fw_jump.elf \
    -kernel /usr/lib/u-boot/qemu-riscv64_smode/uboot.elf \
    -object rng-random,filename=/dev/urandom,id=rng \
    -device virtio-rng-device,rng=rng \
    -nographic \
    -append "root=LABEL=rootfs console=ttyS0"