透过 QEMU 初步体验龙架构

透过 QEMU 初步体验龙架构

发布日期:2022-09-17

QEMU、GCC 上游最近正式宣布支持龙架构,它是龙芯中科基于 MIPS 国产自主研发的指令集,也在某程度上受到 RISC-V 启发:

  • QEMU 7.1.0+
  • GCC 12.1.0+

据说上游 Linux 内核至 5.19 起也初步支持龙架构(源:LoongArch CPU Support Merged For Linux 5.19 - But It Won’t Work For A Booting System Yet - Phoronix),可是很遗憾,这初步支持并不足以在龙架构上启动一个完整的 Linux 系统。

这代表着您即便没有购买龙芯 SoC 也可以透过 QEMU 用户空间模拟器 有限度地体验龙架构,这也正是本文章的焦点。

先决条件

您必须熟悉 Linux 操作。本文章中的说明及命令适用于 Ubuntu 22.04。这并不代表您不能使用别的 Linux 发行版完成该文章所描述的操作,但您极有可能需要因应您的发行版调整您所输入的命令。本文章的作者将不会对您因误操作损坏系统承担任何责任。

为免对您日常使用的系统造成破坏,建议您在新建的 Ubuntu 22.04 虚拟机内进行相关操作。当然,如果您的操作系统不是 Linux(如 Windows、macOS)或您使用的 UOS 系统禁用了开发者模式,这或许是您唯一可行的选项。

事前准备

因为 QEMU、GCC 也是最近才正式支持龙架构,所以您并不能透过 Ubuntu 默认的仓库直接下载安装相应的软件包。因此,我们需要获取并自行编译最新稳定版本 QEMU、GCC 的源代码。

下载 QEMU、GCC 前,我们先建好一些目录:

$ mkdir -p $HOME/opt/qemu $HOME/opt/cross $HOME/src

把工作目录设置为 $HOME/src

$ pushd $HOME/src

我们将把 QEMU 安装在 $HOME/opt/qemu 下,GCC 在 $HOME/opt/cross 下,把源代码存放在 $HOME/src 下。当然,您也可以选择别的目录。

QEMU

参考文章:Hosts/Linux - QEMU、GCC Cross-Compiler - OSDev Wiki

截至 2022-09-17,最新的 QEMU 版本是 7.1.0,因此我们以 QEMU 7.1.0 为准。

更新仓库元数据:

$ sudo apt update

下载编译 QEMU 所需的依赖包:

$ sudo apt install -y build-essential \
    git \
    libglib2.0-dev \
    libfdt-dev \
    libpixman-1-dev \
    zlib1g-dev \
    ninja-build

从 QEMU 官方网站下载 7.1.0 版本源代码:

$ wget https://download.qemu.org/qemu-7.1.0.tar.xz

解压缩:

$ tar xvf qemu-7.1.0.tar.xz

创建一个编译用的新目录 build-qemu

$ mkdir build-qemu/

进去:

$ pushd build-qemu/

出口环境变量:

$ export PREFIX="$HOME/opt/qemu"
$ export TARGET_LIST="loongarch64-linux-user"
$ export PATH="$PREFIX/bin:$PATH"

配置 QEMU:

$ ../qemu-7.1.0/configure --prefix="$PREFIX" \
    --target-list="$TARGET_LIST" \
    --static

编译 QEMU:

$ make -j$(nproc)

安装 QEMU:

$ make install

现在来验证以下我们的安装:

$ which -- qemu-loongarch64 || \
    echo qemu-loongarch64 is not in the PATH

看到类似 /home/dsleung/opt/qemu/bin/qemu-loongarch64 的输出为成功。倘若看到 qemu-loongarch64 is not in the PATH,那代表失败了,请自行修正、重新编译安装 QEMU 哦 ~

倘若以后需要再编译 QEMU,大可留下源代码,但需要清理 build 文档:

$ make clean

离开 build 目录:

$ popd

为了以后能直接调用 qemu-loongarch64,把 PATH 写进 profile 内:

$ echo "export PATH=\"\$HOME/opt/qemu/bin:\$PATH\"" >> ~/.profile
$ source ~/.profile

GCC

参考文章:GCC Cross-Compiler - OSDev Wiki、How to Build a GCC Cross-Compiler

更新仓库元数据:

$ sudo apt update

下载编译 GCC、Binutils、Glibc、Linux 所需的依赖包:

$ sudo apt install -y build-essential \
    bison \
    flex \
    libgmp3-dev \
    libmpc-dev \
    libmpfr-dev \
    texinfo

从官方网站下载 GCC、Binutils、Glibc、Linux 最新版本源代码 - 截至 2022-09-17,最新 GCC 版本为 12.2.0、Binutils 版本为 2.39、Glibc 版本为 2.36、Linux 版本为 6.0-rc5:

$ wget https://ftp.gnu.org/gnu/gcc/gcc-12.2.0/gcc-12.2.0.tar.xz
$ wget https://ftp.gnu.org/gnu/binutils/binutils-2.39.tar.xz
$ wget https://ftp.gnu.org/gnu/libc/glibc-2.36.tar.xz
$ wget https://git.kernel.org/torvalds/t/linux-6.0-rc5.tar.gz

解压缩:

$ tar xvf gcc-12.2.0.tar.xz
$ tar xvf binutils-2.39.tar.xz
$ tar xvf glibc-2.36.tar.xz
$ tar xvf linux-6.0-rc5.tar.gz

出口环境变量:

$ export PREFIX="$HOME/opt/cross"
$ export TARGET="loongarch64-linux-gnu"
$ export PATH="$PREFIX/bin:$PATH"

1. 编译 Binutils

$ mkdir build-binutils/
$ pushd build-binutils/
$ ../binutils-2.39/configure --prefix="$PREFIX" \
    --target="$TARGET" \
    --disable-multilib
$ make -j$(nproc)
$ make install
$ make clean
$ popd

2. 编译 Linux 内核标头档

$ pushd linux-6.0-rc5/
$ make mrproper
$ make ARCH=loongarch INSTALL_HDR_PATH="$PREFIX/$TARGET" headers_install
$ popd

在安装 Linux 内核标头档前执行 make mrproper 能确保我们的 build 不会受遗留的 build 文档影响,相当于其他 Make 项目的 make clean

3. 编译 C/C++ 交叉编译器

$ mkdir -p build-gcc/
$ pushd build-gcc/
$ ../gcc-12.2.0/configure --prefix="$PREFIX" \
    --target="$TARGET" \
    --enable-languages=c,c++ \
    --disable-multilib
$ make -j$(nproc) all-gcc
$ make install-gcc
$ make clean
$ popd

4. 编译 Glibc 标头档及启动文档

$ mkdir -p build-glibc
$ pushd build-glibc/
$ ../glibc-2.36/configure --prefix="$PREFIX/$TARGET" \
    --build=$MACHTYPE \
    --host="$TARGET" \
    --target="$TARGET" \
    --with-headers="$PREFIX/$TARGET/include" \
    --disable-multilib \
    libc_cv_forced_unwind=yes
$ make install-bootstrap-headers=yes install-headers
$ make -j$(nproc) csu/subdir_lib
$ install csu/crt1.o csu/crti.o csu/crtn.o "$PREFIX/$TARGET/lib"
$ $TARGET-gcc -nostdlib \
    -nostartfiles \
    -shared \
    -x c /dev/null \
    -o "$PREFIX/$TARGET/lib/libc.so"
$ touch "$PREFIX/$TARGET/include/gnu/stubs.h"
$ popd

5. 编译支持函式库

$ pushd build-gcc/
$ make -j$(nproc) all-target-libgcc
$ make install-target-libgcc
$ make clean
$ popd

6. 编译 C 标准函式库

$ pushd build-glibc/
$ make -j$(nproc)
$ make install
$ popd

7. 编译 C++ 标准函式库

$ pushd build-gcc/
$ make -j$(nproc)
$ make install
$ make clean
$ popd

验证 GCC 安装

$ which -- $TARGET-gcc || \
    echo $TARGET-gcc is not in the PATH

$HOME/opt/cross/bin 加到 profile 的 PATH

$ echo "export PATH=\"\$HOME/opt/cross/bin:\$PATH\"" >> ~/.profile
$ source ~/.profile

要编译的都编译好了,可以离开 $HOME/src

$ popd

Hello LoongArch World!

打开您最喜爱的文字编辑器(本人的为 Vim),写个 C 程序,并保存为 hello.c

#include 

int main(void) {
  printf("Hello LoongArch World!\n");
  return 0;
}

使用交叉编译器编译:

$ loongarch64-linux-gnu-gcc -O2 --static hello.c -o hello

查看可执行文档 hello 的属性:

$ file hello

输出为:hello: ELF 64-bit LSB executable, LoongArch, version 1 (SYSV), statically linked, for GNU/Linux 5.19.0, with debug_info, not stripped

除非您电脑 CPU 架构为龙架构(当前绝大部分民用计算机为 x86_64、ARM 架构),不然您不能直接运行该文档。幸好,我们能透过 qemu-loongarch64 间接运行该文档:

$ qemu-loongarch64 ./hello

输出为 Hello LoongArch World!

结语

上游 QEMU、GCC 对龙架构的支持尚处于早期阶段,龙架构本身也如此。当龙架构及它的生态逐渐成熟,安装龙架构模拟器及交叉编译器将会大为简化,如 sudo apt install -y qemu-user-loongarch64 loongarch64-linux-gnu-binutils loongarch64-linux-gnu-gcc

或许在不太久的将来,随着龙架构向民用计算机普及化,我们或许不用再透过交叉编译及模拟器体验龙架构,而是在日常使用的台式机及笔记本电脑上直接体验龙架构。但在这一天的到来之前,我们还是有许多的办法探索龙架构,即便因为各种原因无法直接购买相关硬件。

其实我这篇文章原本打算编译上游的 Linux 6.0-rc5 内核及 BusyBox 1.35.0,并运行在 QEMU 龙架构系统模拟器 上,但上游 Linux 内核对龙架构的支持似乎还不够成熟,不能直接运行在龙架构上。

本文章到此为止吧,下次希望能透过 QEMU 龙架构系统模拟器继续探索龙架构并分享一些龙架构入门内核编程的心得。

你可能感兴趣的:(linux,ubuntu,bash)