Toggle navigation
首页
问答
文章
积分商城
专家
专区
更多专区...
文档中心
返回主站
搜索
提问
会员
中心
登录
注册
QEMU
环境搭建
RT-Thread BSP qemu-virt64-riscv 的编译环境搭建
发布于 2023-03-19 17:53:26 浏览:759
订阅该版
[tocm] ## 前言 - 最近需要使用 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` ```c $ 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` 软件包 ![2023-03-19_174543.png](https://oss-club.rt-thread.org/uploads/20230319/9e974242c881d817723b1c73a2c12855.png) ## 交叉编译工具链 - 再次运行 `scons` 后,发现提示找不到 gcc 交叉编译工具链, `riscv64-unknown-linux-musl-gcc: not found` - 下载工具链:可以使用 `get_toolchain.py` 下载,不过这个脚本默认没有在 RT-Thread 工程里面,需要手动创建一个 - 备注:可以在 RT-Thread `userapps` 仓库中 copy 一份出来,地址 [https://github.com/RT-Thread/userapps](https://github.com/RT-Thread/userapps) - 在 `rt-thread/bsp/qemu-virt64-riscv` 目录下,新建一个 `tools` 目录,然后进入这个 `rt-thread/bsp/qemu-virt64-riscv/tools` 目录,创建 `get_toolchain.py` ```c #!/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 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 toolchain if 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` 脚本 ```c #!/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 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 directory os.chdir(cwd) return if __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-riscv` 是 `riscv64` 平台 `$ python3 get_toolchain.py riscv64` 就可以下载 `riscv64` 的 gcc 交叉编译工具链了 - 在 `rt-thread/bsp/qemu-virt64-riscv` 目录下创建 一个设置环境变量的 shell 脚本,如 `smart_env.sh` ```c #!/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 ] 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 env case $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_PATH export 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 里面直接运行 ![2023-03-19_170515.png](https://oss-club.rt-thread.org/uploads/20230319/1f005f0f0a669b9804849c6aa948bc9b.png) - 当前 qemu 启动失败,报如下的错误 ```c 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 的方法 ```c 进入 qemu 目录 $ mkdir build $ cd build $ ../configure $ make -j8 ``` ![2023-03-19_171444.png](https://oss-club.rt-thread.org/uploads/20230319/e4d0f134f299c0297349ddf3893c44fa.png) - 编译完 qemu 后,会在 生成目录,如 `build` 目录下,生成新版本的 `qemu` 系列工具,就是有点耗时。 ```c 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 ``` ![2023-03-19_171719.png](https://oss-club.rt-thread.org/uploads/20230319/00f24b422f1e295552842c5e9fa41af7.png) - 把 qemu 新版本 `qemu-system-riscv64` 的执行路径,替换 `qemu-virt64-riscv` 中 qemu 的执行脚本中的 `qemu-system-riscv64` 即可。 - 我当前可以运行的脚本,把 `qemu-system-riscv64` 替换为 `/home/zhangsz/rtt/qemu/build/qemu-system-riscv64`,由于提示 网络设备部分参数不支持,我暂时先把网络设备部分去掉了 ```c 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 ``` ![2023-03-19_171942.png](https://oss-club.rt-thread.org/uploads/20230319/17d2d48476f90fd763687bb656aa7cd3.png) ## 运行 qemu 效果 ```c 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 ``` ![2023-03-19_172645.png](https://oss-club.rt-thread.org/uploads/20230319/a9a17403d4d3b81ab1f876bbfd80890f.png) ![2023-03-19_172659.png](https://oss-club.rt-thread.org/uploads/20230319/28fa59ed9344b885f8ff2eb78a6a52b6.png) ## 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 配置选项即可! ![2023-03-19_173045.png](https://oss-club.rt-thread.org/uploads/20230319/120afe873b077fc0b715c08da5b3195b.png) - 后面尝试 把 RT-Thread 提供的 `userapps` 编译后,放到 qemu 中 `RT-Smart` 的文件系统中,运行用户态程序。
0
条评论
默认排序
按发布时间排序
登录
注册新账号
关于作者
张世争
学以致用
文章
131
回答
805
被采纳
174
关注TA
发私信
相关文章
1
Linux下的Qemu mini2440虚拟机(32位和64位)
2
有qemu Linux的rt-thread开发环境建立吗?
3
qemu+mini2440+bootloader问题
4
QEMU gdbstub 在Win7下的bug
5
请教如何在windows下使用qemu测试rrt0.31中的例子
6
QEMU运行os问题
7
QEMU-mini2440 模拟环境上运行RT-thread这篇
8
在Ubuntu上执行qemu的configure命令checkzlib失败
9
求大舅:telnet-连接QEMU时,QEMU segmentation fault 结束
10
RealTouch打算出QEMU模拟器吗
推荐文章
1
RT-Thread应用项目汇总
2
玩转RT-Thread系列教程
3
国产MCU移植系列教程汇总,欢迎查看!
4
机器人操作系统 (ROS2) 和 RT-Thread 通信
5
五分钟玩转RT-Thread新社区
6
【技术三千问】之《玩转ART-Pi》,看这篇就够了!干货汇总
7
关于STM32H7开发板上使用SDIO接口驱动SD卡挂载文件系统的问题总结
8
STM32的“GPU”——DMA2D实例详解
9
RT-Thread隐藏的宝藏之completion
10
【ART-PI】RT-Thread 开启RTC 与 Alarm组件
热门标签
RT-Thread Studio
串口
Env
LWIP
SPI
AT
Bootloader
Hardfault
CAN总线
FinSH
ART-Pi
USB
DMA
文件系统
RT-Thread
SCons
RT-Thread Nano
线程
MQTT
STM32
RTC
FAL
rt-smart
ESP8266
I2C_IIC
UART
WIZnet_W5500
ota在线升级
PWM
cubemx
freemodbus
flash
packages_软件包
BSP
潘多拉开发板_Pandora
定时器
ADC
GD32
flashDB
socket
中断
编译报错
Debug
SFUD
msh
rt_mq_消息队列_msg_queue
keil_MDK
ulog
MicroPython
C++_cpp
本月问答贡献
出出啊
1517
个答案
342
次被采纳
小小李sunny
1443
个答案
289
次被采纳
张世争
805
个答案
174
次被采纳
crystal266
547
个答案
161
次被采纳
whj467467222
1222
个答案
148
次被采纳
本月文章贡献
出出啊
1
篇文章
4
次点赞
小小李sunny
1
篇文章
1
次点赞
张世争
1
篇文章
1
次点赞
crystal266
2
篇文章
2
次点赞
whj467467222
2
篇文章
1
次点赞
回到
顶部
发布
问题
投诉
建议
回到
底部