RT-Thread BSP qemu-virt64-riscv 的编译环境搭建
创始人
2025-05-30 19:13:05
0

前言

  • 最近需要使用 RT-Thread smart 开发调试一些软件功能,由于软件功能平台无关,使用实际硬件操作,会耗费较多的时间在程序烧写环节。

  • 打算使用 BSP qemu-virt64-aarch64 搭建一个 RT-Thread smart 的开发调试环境,可以开发验证一些平台无关的软件功能,但是当前的 RT-Thread smart 开放出来的 userapps 不支持 aarch64 平台。

  • 所以选择 qemu-virt64-riscv 平台进行编译环境的搭建,搭建的流程跟 qemu-virt64-aarch64 基本一致。

环境搭建

  • Win10 64位

  • VMware Workstation Pro

  • VS Code (ssh 远程)

  • ubuntu 20.04

  • RT-Thread master 最新分支: BSP qemu-virt64-riscv

下载 RT-Thread

  • 这里使用 gitee 的 RT-Thread 仓库,先通过 fork 的方式,把 RT-Thread fork 到自己的账号下

  • ubuntu 中安装好 git qemu,通过 git 克隆一份 RT-Thread 最新代码

  • 可以直接克隆 RT-Thread 官方的 git clone https://gitee.com/rtthread/rt-thread.git

scons 构建

  • 进入 rt-thread/bsp/qemu-virt64-riscv,直接 scons 可能会提示 scons 找不到,如果找不到,就安装一下 scons
zhangsz@zhangsz:~/rtt/smart/rt-thread/bsp/qemu-virt64-aarch64$ sconsCommand 'scons' not found, but can be installed with:sudo apt install scons
  • 安装 scons 的方法: $ sudo apt install scons

  • 运行 $ scons --menuconfig,进入Kconfig 图形配置界面,初步运行,会克隆 Linux 下的 RT-Thread env 工具 与 packages 软件包

在这里插入图片描述

交叉编译工具链

  • 再次运行 scons 后,发现提示找不到 gcc 交叉编译工具链, riscv64-unknown-linux-musl-gcc: not found

  • 下载工具链:可以使用 get_toolchain.py 下载,不过这个脚本默认没有在 RT-Thread 工程里面,需要手动创建一个,也可以在 userapps 仓库中 copy 一份出来,地址 https://github.com/RT-Thread/userapps

  • rt-thread/bsp/qemu-virt64-riscv 目录下,新建一个 tools 目录,然后进入这个 rt-thread/bsp/qemu-virt64-riscv/tools 目录,创建 get_toolchain.py

#!/usr/bin/env python
# -*- coding: utf-8 -*-#
# Copyright (c) 2022, RT-Thread Development Team
#
# SPDX-License-Identifier: GPL-2.0
#
# Change Logs:
# Date           Author       Notes
# 2022-02-1      Bernard      The first version
#import os
import sys
import platformfrom ci import CItoolchains_config = {'arm':{'Linux': 'arm-linux-musleabi_for_x86_64-pc-linux-gnu_latest.tar.bz2','Windows': 'arm-linux-musleabi_for_i686-w64-mingw32_latest.zip'},'aarch64':{'Linux' : 'aarch64-linux-musleabi_for_x86_64-pc-linux-gnu_latest.tar.bz2','Windows' : 'aarch64-linux-musleabi_for_i686-w64-mingw32_latest.zip'},'riscv64':{'Linux': 'riscv64-linux-musleabi_for_x86_64-pc-linux-gnu_latest.tar.bz2','Windows': 'riscv64-linux-musleabi_for_i686-w64-mingw32_latest.zip'}
}if __name__ == '__main__':# download toolchainif len(sys.argv) > 1:target = sys.argv[1]else:target = 'arm'ci = CI()toolchain_path = os.path.join(os.path.abspath('.'), 'gnu_gcc')platform = platform.system()try:zfile = toolchains_config[target][platform]URL = 'http://117.143.63.254:9012/www/rt-smart/' + zfileexcept:print('not found target')exit(0)ci.downloadFile(zfile, URL)ci.extractZipFile(zfile, toolchain_path)ci.delFile(zfile)
  • rt-thread/bsp/qemu-virt64-riscv/tools目录下,创建一个 ci.py 脚本,因为 get_toolchain.py 依赖这个ci.py 脚本
#!/usr/bin/env python
# -*- coding: utf-8 -*-#
# Copyright (c) 2022, RT-Thread Development Team
#
# SPDX-License-Identifier: GPL-2.0
#
# Change Logs:
# Date           Author       Notes
# 2022-02-1      Bernard      The first version
#import os
import sys
import shutil
import platform
import requests
import time
import zipfileclass CI:def downloadFile(self, name, url):headers = {'Proxy-Connection':'keep-alive'}r = requests.get(url, stream=True, headers=headers)length = float(r.headers['content-length'])f = open(name, 'wb')count = 0count_tmp = 0time1 = time.time()for chunk in r.iter_content(chunk_size = 512):if chunk:f.write(chunk)count += len(chunk)if time.time() - time1 > 2:p = count / length * 100speed = (count - count_tmp) / 1024 / 1024 / 2count_tmp = countprint(name + ': ' + '{:.2f}'.format(p) + '%')time1 = time.time()print(name + ': 100%')f.close()def extractZipFile(self, zfile, folder):# self.delTree(folder)if not os.path.exists(folder):os.makedirs(folder)if platform.system() == 'Windows':zip_file = zipfile.ZipFile(zfile)zip_list = zip_file.namelist()for item in zip_list:print(item)zip_file.extract(item, folder)zip_file.close()elif platform.system() == 'Linux':if zfile.endswith('tar.gz'):os.system('tar zxvf %s -C %s' % (zfile, folder))elif zfile.endswith('tar.bz2'):os.system('tar jxvf %s -C %s' % (zfile, folder))elif zfile.endswith('.zip'):os.system('unzip %s -d %s' % (zfile, folder))returndef zipFolder(self, folder, zfile):zip_filename = os.path.join(folder)zip = zipfile.ZipFile(zfile, 'w', compression=zipfile.ZIP_BZIP2)pre_len = len(os.path.dirname(folder))for parent, dirnames, filenames in os.walk(folder):for filename in filenames:pathfile = os.path.join(parent, filename)arcname = pathfile[pre_len:].strip(os.path.sep)zip.write(pathfile, arcname)zip.close()returndef touchDir(self, d):if not os.path.exists(d):os.makedirs(d)def gitUpdate(self, url, folder, branch = 'master'):cwd = os.getcwd()if os.path.exists(folder):os.chdir(folder)os.system('git pull origin')if branch != 'master':os.system('git checkout -b %s origin/%s' % (branch, branch))os.system('git submodule init')os.system('git submodule update')else:os.system('git clone %s %s' % (url, folder))os.chdir(folder)os.system('git submodule init')os.system('git submodule update')os.chdir(cwd)def installEnv(self, folder):env_path = foldercwd = os.getcwd()os.chdir(env_path)self.touchDir(os.path.join(env_path, 'local_pkgs'))self.touchDir(os.path.join(env_path, 'packages'))self.touchDir(os.path.join(env_path, 'tools'))self.gitUpdate('https://gitee.com/RT-Thread-Mirror/env.git', 'tools/script')self.gitUpdate('https://gitee.com/RT-Thread-Mirror/packages.git', 'packages/packages')kconfig = open(os.path.join(env_path, 'packages', 'Kconfig'), 'w')kconfig.write('source "$PKGS_DIR/packages/Kconfig"')kconfig.close()os.chdir(cwd)returndef pkgsUpdate(self, env_folder):self.touchDir(env_folder)self.installEnv(env_folder)os.environ['PKGS_DIR'] = env_folderos.system('python %s package --update' % (os.path.join(env_folder, 'tools', 'script', 'env.py')))returndef delTree(self, folder):if os.path.exists(folder):shutil.rmtree(folder)def delFile(self, file):if os.path.exists(file):os.remove(file)def appendFile(self, srcFile, otherFile):f = open(otherFile, 'r')s = f.read()f.close()f = open(srcFile, 'a')f.write(s)f.close()def copyTree(self, srcTree, dstTree):if os.path.exists(dstTree):shutil.rmtree(dstTree)shutil.copytree(srcTree, dstTree)def run(self, cmds):cwd = os.getcwd()cmds = cmds.split('\n')for item in cmds:item = item.lstrip()if item == '':continueif item[0] == '-':os.system(item[1:].lstrip())# keep current directoryos.chdir(cwd)returnif __name__ == '__main__':ci = CI()env_folder = os.path.abspath(os.path.join('.', 'env_test'))# ci.pkgsUpdate(env_folder)cmds = '''# test- dir- dir tools'''ci.run(cmds)
  • 下载gcc 交叉编译工具链: qemu-virt64-riscvriscv64 平台

$ python3 get_toolchain.py riscv64 就可以下载 riscv64 的 gcc 交叉编译工具链了

  • rt-thread/bsp/qemu-virt64-riscv 目录下创建 一个设置环境变量的 shell 脚本,如 smart_env.sh
#!/bin/bash# usage:
# source smart-env.sh [arch]
# example: source smart-env.sh          # arm
# example: source smart-env.sh aarch64  # aarch64# supported arch list
supported_arch="arm aarch64 riscv64 i386"def_arch="unknown"# find arch in arch list
if [ -z $1 ]
thendef_arch="arm" # default arch is arm
elsefor arch in $supported_archdoif [ $arch = $1 ]thendef_arch=$archbreakfidone
fi# set env
case $def_arch in "arm")export RTT_CC=gccexport RTT_EXEC_PATH=$(pwd)/tools/gnu_gcc/arm-linux-musleabi_for_x86_64-pc-linux-gnu/binexport RTT_CC_PREFIX=arm-linux-musleabi-;;"aarch64")export RTT_CC=gccexport RTT_EXEC_PATH=$(pwd)/tools/gnu_gcc/aarch64-linux-musleabi_for_x86_64-pc-linux-gnu/binexport RTT_CC_PREFIX=aarch64-linux-musleabi-;;"riscv64")export RTT_CC=gccexport RTT_EXEC_PATH=$(pwd)/tools/gnu_gcc/riscv64-linux-musleabi_for_x86_64-pc-linux-gnu/binexport RTT_CC_PREFIX=riscv64-unknown-linux-musl-;;"i386")export RTT_CC=gccexport RTT_EXEC_PATH=$(pwd)/tools/gnu_gcc/i386-linux-musleabi_for_x86_64-pc-linux-gnu/binexport RTT_CC_PREFIX=i386-unknown-linux-musl-;;*)  echo "unknown arch!"return 1
esac# export RTT_EXEC_PATH
export PATH=$PATH:$RTT_EXEC_PATHecho "Arch      => ${def_arch}"
echo "CC        => ${RTT_CC}"
echo "PREFIX    => ${RTT_CC_PREFIX}"
echo "EXEC_PATH => ${RTT_EXEC_PATH}"
  • 设置 smart_env.sh 的执行权限 $ chmod +x smart_env.sh

  • 下载 gcc 交叉编译工具链后, 在 rt-thread/bsp/qemu-virt64-riscv 运行

$ source smart_env.sh riscv64,即可设置 qemu-virt64-riscv 的 gcc 交叉编译工具链

编译 qemu-virt64-aarch64

  • 配置好 gcc 交叉编译工具链后,就可以 scons 编译了

运行 qemu

  • qemu-virt64-riscv 目录下有个 qemu-nographic.sh,可以在 Linux shell 里面直接运行

在这里插入图片描述

  • 当前 qemu 启动失败,报如下的错误
zhangsz@zhangsz:~/rtt/smart/rtt_qemu_aarch64/qemu-virt64-riscv$ ./qemu-nographic.sh
qemu-system-riscv64: warning: No -bios option specified. Not loading a firmware.
qemu-system-riscv64: warning: This default will change in a future QEMU release. Please use the -bios option to avoid breakages when this happens.
qemu-system-riscv64: warning: See QEMU's deprecation documentation for details.
QEMU: Terminated
  • 退出 qemu 的方法: CTRL + a 组合按一下,松开按键,再 按一下 x 键即可退出 qemu

qemu 更新解决启动问题

  • 经过验证,确认 ubuntu 20.04 默认安装的 qemu 版本比较的老,需要更新最新的 qemu 版本,直接使用 sudo apt install qemu-system-riscv64 无法更新,只能手动更新。

  • 解决方法:下载 qemu 的代码,手动编译更新 qemu,使用新版本的 qemu-system-riscv64

  • qemu 下载地址:可以再 github 上下载,注意拉取更新 git 子仓库

  • 下载 qemu : $ git clone https://github.com/qemu/qemu.git

  • qemu 编译依赖: $ sudo apt-get install git libglib2.0-dev libfdt-dev libpixman-1-dev zlib1g-dev ninja-build

  • qemu git 子仓库 : $ git submodule update --init --force --recursive

  • 编译 qemu 的方法

进入 qemu 目录$ mkdir build
$ cd build
$ ../configure
$ make -j8

在这里插入图片描述

  • 编译完 qemu 后,会在 生成目录,如 build 目录下,生成新版本的 `qemu
zhangsz@zhangsz:~/rtt/qemu/build$ ./qemu-system-riscv64 --version
QEMU emulator version 7.2.90 (v8.0.0-rc0-27-g74c581b645-dirty)
Copyright (c) 2003-2022 Fabrice Bellard and the QEMU Project developers

在这里插入图片描述

  • 把 qemu 新版本 qemu-system-riscv64 的执行路径,替换 qemu-virt64-riscv 中 qemu 的执行脚本中的 qemu-system-riscv64 即可。

  • 我当前可以运行的脚本,把 qemu-system-riscv64 替换为 /home/zhangsz/rtt/qemu/build/qemu-system-riscv64,由于提示 网络设备部分参数不支持,我暂时先把网络设备部分去掉了

if [ ! -f "sd.bin" ]; then
dd if=/dev/zero of=sd.bin bs=1024 count=65536
fi/home/zhangsz/rtt/qemu/build/qemu-system-riscv64 -nographic -machine virt -m 256M -kernel rtthread.bin \
-drive if=none,file=sd.bin,format=raw,id=blk0 -device virtio-blk-device,drive=blk0,bus=virtio-mmio-bus.0 \
-device virtio-serial-device -chardev socket,host=127.0.0.1,port=4321,server=on,wait=off,telnet=on,id=console0 -device virtserialport,chardev=console0

运行 qemu 效果

zhangsz@zhangsz:~/rtt/smart/rtt_qemu_aarch64/qemu-virt64-riscv$ ./qemu-nographic.shOpenSBI v1.2____                    _____ ____ _____/ __ \                  / ____|  _ \_   _|| |  | |_ __   ___ _ __ | (___ | |_) || || |  | | '_ \ / _ \ '_ \ \___ \|  _ < | || |__| | |_) |  __/ | | |____) | |_) || |_\____/| .__/ \___|_| |_|_____/|____/_____|| ||_|Platform Name             : riscv-virtio,qemu
Platform Features         : medeleg
Platform HART Count       : 1
Platform IPI Device       : aclint-mswi
Platform Timer Device     : aclint-mtimer @ 10000000Hz
Platform Console Device   : uart8250
Platform HSM Device       : ---
Platform PMU Device       : ---
Platform Reboot Device    : sifive_test
Platform Shutdown Device  : sifive_test
Firmware Base             : 0x80000000
Firmware Size             : 212 KB
Runtime SBI Version       : 1.0Domain0 Name              : root
Domain0 Boot HART         : 0
Domain0 HARTs             : 0*
Domain0 Region00          : 0x0000000002000000-0x000000000200ffff (I)
Domain0 Region01          : 0x0000000080000000-0x000000008003ffff ()
Domain0 Region02          : 0x0000000000000000-0xffffffffffffffff (R,W,X)
Domain0 Next Address      : 0x0000000080200000
Domain0 Next Arg1         : 0x000000008fe00000
Domain0 Next Mode         : S-mode
Domain0 SysReset          : yesBoot HART ID              : 0
Boot HART Domain          : root
Boot HART Priv Version    : v1.12
Boot HART Base ISA        : rv64imafdch
Boot HART ISA Extensions  : time,sstc
Boot HART PMP Count       : 16
Boot HART PMP Granularity : 4
Boot HART PMP Address Bits: 54
Boot HART MHPM Count      : 16
Boot HART MIDELEG         : 0x0000000000001666
Boot HART MEDELEG         : 0x0000000000f0b509
heap: [0x802bbcb8 - 0x842bbcb8]\ | /
- RT -     Thread Smart Operating System/ | \     5.0.0 build Mar 19 2023 16:40:432006 - 2022 Copyright by RT-Thread team
lwIP-2.0.3 initialized!
[I/sal.skt] Socket Abstraction Layer initialize success.
[I/utest] utest is initialize success.
[I/utest] total utest testcase num: (0)
file system initialization done!
Hello RISC-V

qemu 支持 elm fat 文件系统

  • 运行 qemu 后,发现 ls 提示找不到文件,查看代码,发现没有 mnt 文件挂载的操作,所以从其他的bsp 中,如 qemu-virt64-aarch64 copy 过来一份 mnt.c,重新编译。

  • 第一次运行 qemu 会生成 sd.bin,这个 sd.bin 为 RAW 格式的,可以使用 Linux shell 命令:mkfs.fat sd.bin,格式化为 fat 格式,这样就可以正常的在RT-Thread 中挂载了

  • 就可以支持 elm fat 格式的文件系统了。

在这里插入图片描述

在这里插入图片描述

小结

  • 由于 ubuntu 20.04 默认安装的 qemu qemu-system-riscv64 版本较低,所以需要手动更新 qemu-system-riscv64 版本到最新,可以通过 qemu git 仓库手动编译

  • 当前 RT-Thread master 分支的 qemu-virt64-riscv 跑的是 RT-Thread,而不是 RT-Thread Smart,切换为 RT-Thread Smart,当前只需要配置使用 RT-Thread Smart 配置选项即可!

在这里插入图片描述

  • 后面尝试 把 RT-Thread 提供的 userapps 编译后,放到 qemu 中 RT-Smart 的文件系统中,运行用户态程序。

相关内容

热门资讯

LaTeX插入图片 基本语法 常用选项[htbp]是浮动格式(参考《LaTeX2e插图指南》16.2节和《...
摸索graphQL在前端vue... 上回说到,那个请求拦截的一个过程,我上次不会看官网教程,这...
使用Shell传参解决Data... 使用Shell传参解决DataPhin中PySpark不支持中文的问题 背景 笔者开发PySpark...
10个杀手级应用的Python... 10个杀手级应用的Python自动化脚本 重复的任务总是耗费时间和枯燥的。想象一下,逐...
在Clion开发工具上使用ND... 1. 前言         因为工作需要,我要将一份C语言代码编译成可执行文件传送到某...
day36_jdbc 今日内容 上课同步视频:CuteN饕餮的个人空间_哔哩哔哩_bilibili 同步笔记沐沐霸的博客...
Opengl ES之矩阵变换(... 前言 在上一节 《Opengl ES之矩阵变换(上)》 中,我们通过矩阵变换实现一个一些形变的效果。...
案例分享 | 金融微服务场景下... ​云原生环境下金融业务的微服务化改造以及分布式架构的部署,使得业务与开发部门的关联更为...
0.01秒险胜!广东名将莫家蝶... 5月31日,2025年亚洲田径锦标赛迎来最后一个比赛日的争夺,广东跨栏名将莫家蝶在女子400米栏决赛...
JAVA学习和应用,刷题,cf 目录 Java 枚举 IO流  File类  文件字节流 文件字符流 缓冲流 vju cf Ja...