RT-Thread BSP qemu-virt64-riscv的编译环境搭建步骤

前言
最近需要使用 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
建议手动搭建一个 qemu-virt64-riscv 的独立工程,修改一下构建与配置脚本的路径即可。
scons 构建
进入 rt-thread/bsp/qemu-virt64-riscv,直接 scons编译,如果第一次,可能提示 scons 找不到,找不到就安装一下 scons
$ scons
command '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 工程里面,需要手动创建一个
备注:可以在 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 teamspdx-license-identifier: gpl-2.0change logs:date author notes2022-02-1 bernard the first versionimport os
import sys
import platform
from ci import ci
toolchains_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/' + zfile
except:
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 teamspdx-license-identifier: gpl-2.0change logs:date author notes2022-02-1 bernard the first versionimport os
import sys
import shutil
import platform
import requests
import time
import zipfile
class 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 = 0
count_tmp = 0
time1 = 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 * 100
speed = (count - count_tmp) / 1024 / 1024 / 2
count_tmp = count
print(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))
return
def 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()
return
def 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 = folder
cwd = 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)
return
def pkgsupdate(self, env_folder):
self.touchdir(env_folder)
self.installenv(env_folder)
os.environ['pkgs_dir'] = env_folder
os.system('python %s package --update' % (os.path.join(env_folder, 'tools', 'script', 'env.py')))
return
def 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 == '':
continue
if item[0] == '-':
os.system(item[1:].lstrip())
keep current directoryos.chdir(cwd)
return
if name == ' main ':
ci = ci()
env_folder = os.path.abspath(os.path.join('.', 'env_test'))
ci.pkgsupdate(env_folder)cmds = '''
testdirdir tools
'''
ci.run(cmds)
下载gcc 交叉编译工具链: qemu-virt64-riscv 是 riscv64 平台
$ 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 # armexample: source smart-env.sh aarch64 # aarch64supported arch listsupported_arch=arm aarch64 riscv64 i386
def_arch=unknown
find arch in arch listif [ -z $1 ]
then
def_arch=arm # default arch is arm
else
for arch in $supported_arch
do
if [ $arch = $1 ]
then
def_arch=$arch
break
fi
done
fi
set envcase $def_arch in
arm)
export rtt_cc=gcc
export rtt_exec_path=$(pwd)/tools/gnu_gcc/arm-linux-musleabi_for_x86_64-pc-linux-gnu/bin
export rtt_cc_prefix=arm-linux-musleabi-
;;
aarch64)
export rtt_cc=gcc
export rtt_exec_path=$(pwd)/tools/gnu_gcc/aarch64-linux-musleabi_for_x86_64-pc-linux-gnu/bin
export rtt_cc_prefix=aarch64-linux-musleabi-
;;
riscv64)
export rtt_cc=gcc
export rtt_exec_path=$(pwd)/tools/gnu_gcc/riscv64-linux-musleabi_for_x86_64-pc-linux-gnu/bin
export rtt_cc_prefix=riscv64-unknown-linux-musl-
;;
i386)
export rtt_cc=gcc
export rtt_exec_path=$(pwd)/tools/gnu_gcc/i386-linux-musleabi_for_x86_64-pc-linux-gnu/bin
export rtt_cc_prefix=i386-unknown-linux-musl-
;;
*) echo unknown arch!
return 1
esac
export rtt_exec_pathexport path=**path:**rtt_exec_path
echo 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.sh
opensbi 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.0
domain0 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 : yes
boot 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:43
2006 - 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 的文件系统中,运行用户态程序。

气动电磁阀是什么_气动电磁阀工作原理_气动电磁阀的分类
工业物联网监控系统的主控装置——主控柜
智能咖啡机整体解决方案
vivoX20将推出黑金配色, 再没人敢说你丑了!
选AC-DC电源适配器还有这么多门道?看完才知道
RT-Thread BSP qemu-virt64-riscv的编译环境搭建步骤
富勒G900S机械键盘评测 值不值得买
从人工智能与数据分析的角度,能看到什么呢?
基于XC2V1000 FPGA和DM9000A实现OQPSK全数字接收机的设计
马来西亚封城后6吋硅晶圆产能紧张
ADI收购HITTITE微波公司
谷歌推出一款新的AR应用,任何支持AR Core的设备上均可用
欢乐兔rabbit公排双轨APP开发
采用路径成组分离技术优化FIR设计
镭拓科普透明塑料激光焊接机在塑料加工的优势
全英最便宜智能手机 4英寸“展讯芯”华为Y3开卖
高通即将推出加强版骁龙888 Plus
为使消费者重拾信心 三星Galaxy S8旗舰或有打算提前发布
示波器上的频域分析利器,Spectrum View测试分析(基础篇)
电池级碳酸锂市场紧缺的根本原因在哪