RT-Thread Smart qemu-virt64-riscv 用户态 userapps 的编译与运行

时间:2022-02-18 01:03:20


前言

  • 经过这两天的折腾,在 qemu-virt64-riscv上,终于把 RT-Thread Smart(简称 rt-smart)跑起来了,这里做个记录,记录下整个流程的搭建,遇到问题的解决
  • rt-smart 当前支持的 bsp 不多,经过尝试,可以在 qemu 上运行,这方便了一些简单软件的开发与调试
  • rt-smart 开发,分为两个部分:内核态与用户态,内核态注重设备驱动开发,用户态注重实际的开发应用功能的实现
  • 前面文章:RT-Thread BSP qemu-virt64-riscv 的编译环境搭建 已经把 rt-smart 跑起来了,本篇继续把 用户态 userapps 跑起来。

userapps 的获取

  • 下载地址 https://github.com/RT-Thread/userapps,可以使用 git clone https://github.com/RT-Thread/userapps.git
  • rt-smart 上,为了实现用户态与内核态的分离,使用了【系统调用】,这个系统调用可以认为是个 sdk,当前 userapps 提供了 armriscv 的 sdk(编译好的二进制)文件与头文件,所以用户态的程序开发,只需要开发 app 即可。

userapps 的编译环境

  • 编译 userapps 的方法:下载 userapps 后,进入 tools 目录,然后把 运行平台的 交叉编译工具链拉取下来,qemu-virt64-riscv 使用的是 riscv64,在 ubuntu 20.04 shell 中运行: $ python3 get_toolchain.py riscv64 即可拉取 riscv64 的 gcc 交叉编译工具链 riscv64-linux-musleabi_for_x86_64-pc-linux-gnu_latest.tar.bz2,并解压到 userapps/tools/gnu_gcc/riscv64-linux-musleabi_for_x86_64-pc-linux-gnu
  • 设置 riscv64 gcc 交叉编译链的 环境变量:ubuntu 20.04 下,在 userapps 目录下,直接运行 $ source smart-env.sh riscv64 即可
zhangsz@zhangsz:~/rtt/smart/userapps$ source smart-env.sh riscv64
/home/zhangsz/rtt/smart/userapps
Arch      => riscv64
CC        => gcc
PREFIX    => riscv64-unknown-linux-musl-
EXEC_PATH => /home/zhangsz/rtt/smart/userapps/tools/gnu_gcc/riscv64-linux-musleabi_for_x86_64-pc-linux-gnu/bin
  • 可以运行 $ riscv64-unknown-linux-musl-gcc -v 验证 riscv64 gcc 交叉编译工具链生效

RT-Thread Smart qemu-virt64-riscv 用户态 userapps 的编译与运行

userapps 的编译

  • 编译 userapps,可以在 userapps 目录直接使用 scons 进行编译,也可以进入 userapps/apps/xxx 目录下,单独编译某个 app。
  • 如单独编译 userapps/apps/hello 的方法,进入 userapps/apps/hello,运行 scons 编译,生成 hello.elf 文件,这个 elf 就是用户态的可执行文件,可以放进 rt-smart 文件系统中,运行执行。
zhangsz@zhangsz:~/rtt/smart/userapps/apps/hello$ scons
scons: Reading SConscript files ...
scons: done reading SConscript files.
scons: Building targets ...
scons: building associated VariantDir targets: build/hello
CC build/hello/main.o
LINK hello.elf
scons: done building targets.
  • userapps 目录下,默认是全部编译,生成的产物在 userapps/root/bin
zhangsz@zhangsz:~/rtt/smart/userapps$ cd root/bin/
zhangsz@zhangsz:~/rtt/smart/userapps/root/bin$ ls
hello.elf  ping.elf  pong.elf  umailbox.elf  vi.elf  webclient.elf  webserver.elf
zhangsz@zhangsz:~/rtt/smart/userapps/root/bin$
  • 可以把 userapps 的编译产物 userapps/root/bin 目录下的所有 elf 文件等,全部 拷贝到 qemu-virt64-riscv 的 sd.bin 镜像文件中

sd.bin 镜像文件

  • ubuntu 20.04 下,有各种文件系统镜像文件的制作工具,如 fatext4 等文件系统类型
  • 如当前 RT-Thread 支持 elm 文件系统,也就是 fat 文件系统,制作方法如下:
  • 进入 qemu-virt64-riscv 的内核目录,注意 userappsqemu-virt64-riscv 是独立的
$ dd if=/dev/zero of=sd.bin bs=1024 count=65536   /* 64MB 大小,可以根据需要更改大小 */

$ mkfs.fat sd.bin  /* 格式化为 fat 文件类型 */

$ mkdir sdcard  /* 镜像文件 sd.bin mount 挂载目录,挂载后可往镜像文件里面拷贝或删除文件 */

$ sudo mount sd.bin sdcard/    /* 挂载到 sdcard 目录下,这样就可以拷贝文件了 */

$ sudo cp -r /home/zhangsz/rtt/smart/userapps/root/bin sdcard/  /* userapps 产物拷贝到 镜像文件 */

$ ls sdcard/   /* 文件拷贝进去了 */
bin

$ sudo umount sdcard  /* 取消镜像文件 sd.bin 的挂载, userapps 的产物已经在里面了 */

运行 qemu

  • qemu-virt64-riscv 下 运行 $ ./qemu-nographic.sh 即可
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: [0x802e7078 - 0x842e7078]

 \ | /
- RT -     Thread Smart Operating System
 / | \     5.0.0 build Mar 19 2023 20:34:47
 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
msh />
msh />ls
Directory /:
bin                 <DIR>
msh />cd bi
msh />cd bin/
msh /bin>ls
Directory /bin:
hello.elf           341224
ping.elf            347336
pong.elf            342152
umailbox.elf        357440
vi.elf              517448
webclient.elf       393016
webserver.elf       489320
msh /bin>./h
msh /bin>./hello.elf
msh /bin>hello world!
  • 可以进入 /bin 目录下,运行 elf 用户态的程序了

进程间通信例程

  • 当前用户态程序 ping.elf pong.elf ,可以用于验证 线程通信
  • 首先后台方式运行 pong.elf ,运行命令: ./pong.elf &,注意后面的 & 代表后台线程,这样 shell 不会被占用,否则无法再运行其他的 elf 文件
msh /bin>./pong.elf &
msh /bin>
Pong: wait on the IPC channel: 3
  • 接下来运行 ping.elf,看下效果 ./ping.elf

RT-Thread Smart qemu-virt64-riscv 用户态 userapps 的编译与运行

  • 用户态的线程可以正常的运行

小结

  • rt-smart 的内核态与用户态分离,与 嵌入式Linux开发方法相似, rt-smart 在不断的完善,后期会适配到更多的平台上
  • 除了运行 RT-Thread userapps 下的app,用户可以根据需要,设计自己的 app,当前如果需要内核设备驱动支持,还需要在 内核部分编写设备驱动等。