1.記事一覧
記事は複数回に分けて投稿する予定です。AMD/XilinxのARM SoC(ZynqMP Kria K26 SOM)で動作する、AMD/Xilinx公式認定Ubuntuやベアメタル開発を勉強していく覚書きです。
ZynqMP(APU:Cortex-A53,Arm64) 組込みLinux入門編
- 【ZynqMP】1. 認定UbuntuでPLのGPIOを使う
- 【ZynqMP】2. 認定Ubuntuのカーネルビルド
- 【ZynqMP】3. 認定UbuntuのDeviceTree変更
- 【ZynqMP】4. 認定UbuntuでOpenAMPを試す【CR5Lockstep】←本記事
- 【ZynqMP】5. UARTでAMP【コア間通信】
- 【Linux】6. crash toolでカーネルメモリを見る
ZynqMP(RPU:Cortex-R5,Arm32) RPU入門編
2.認定UbuntuでOpenAMPを試してみよう
注:この記事の内容は2024/7頃の内容になります。情報が古い場合はご了承ください。
最近、JTAG起動のRPU(Cortex-R5=CR5)で遊びはじめました。一通り開発が終わったらROM化したいところですが、ZynqMPでLinuxを動作させる場合はOpenAMPの仕組みを使って、ELF実行ファイルをロードさせることが出来ます。
この認定UbuntuでOpenAMPを試す記事は2回に分けて書きました。
- CR5をLockstep(冗長1コア)で動かす←本記事
- CR5をSplit(2コア)で動かす
2-1. OpenAMPとは
本家のページは以下にあります。
ざっくり説明してみます。
ヘテロコアを搭載するSoCで、Linuxを動かすアプリケーション用コアとリアルタイム制御用にベアメタルやRTOSを載せて動かすサブコアを持っているとします。その場合、OpenAMPは以下の機能を提供してくれます。
- サブコアのファームウェアをLinux側からロードする(Remoteproc)
- サブコアの起動・停止管理を行う(Remoteproc)
- サブコアとIPC(コア間通信)するI/Fを提供する(RPMsg)
便利そうですね。様々なSoCデバイスに載せられるようにオープンソースとして誕生したのがOpenAMPです。
2-2. 認定UbuntuのOpenAMPサポート状況
PetaLinuxでやっている例はあるのですが、2024/7現在、Xilinx認定Ubuntu22.04でのOpenAMPサポートはないようです(私が見つけられないだけかも…)。
- Xilinx-Wiki:Canonical Ubuntu
- Xilinx-Wiki:OpenAMP
- Getting Started with Kria KR260 Robotics Starter Kit
- SOM Landing Page
- Libmetal and OpenAMP User Guide (UG1186)
OpenAMPは内部のLibmetalライブラリをユーザ空間+UIOで動かすか、カーネル空間のドライバとして動かすかの2種類の実装方法があり、PetaLinuxで提供されているのは後者のカーネル空間の方になります。
2-3. 環境条件
開発PC | Ubuntu20.04 LTS |
開発ツール | AMD/Xilinx社 Vivado・Vitis Classic v2024.1.1 |
ターゲットOS | Xilinx認定Ubuntu22.04 Linux Kernel : 5.15.0-1031-xilinx-zynqmp |
ターゲットボード | Xilinx社製 Kria KR260 ロボティクススターターキット(SK-KR260-G) SOM : Xilinx社 Kria K26 SOM (Zynq UltraScale+ MPSoCベース) APU : Arm CA53x4 1333MHz arm64 RPU : Arm CR5x2 533MHz armv7-R SDRAM : DDR4 4GB |
OpenAMP Echo test | Github : https://github.com/OpenAMP/openamp-system-reference/tree/v2024.05/examples/linux/rpmsg-echo-test branch=v2024.05 |
この記事で使用したソースコード類 | Github : https://github.com/kern-gt/ZynqMP-OpenAMP |
2-3. 先に結論:動いたが再接続不可。原因もわからず
2記事分の長い内容なので、先にこのチャレンジの結果を記載します。
- Splitモード、LockstepモードでCR5のELFロード・起動・停止は出来た
- ECHOサンプルのみを試した。詳細は↓
- CR5のベアメタルファームウェアサンプルは正常動作したが、再接続不可
- 上記の原因は不明・今後も調査を続ける
CR5はSplitモード、Lockstepモードの起動方法があり、前者は2コア、後者は1コア(2コアを冗長構成で使用)になります。
結果はもやもやする内容となりました。一度Echo testを実行するとVirtIOがbusy状態に入り、デバイスファイルがOpenできなくなって再接続不可となる症状がでました。一度CR5コアを停止して再起動する必要があります。原因は今も不明です。
原因を突き止められなかったのは、自分の実力不足が根本原因ですが、今後も調査を続けたいと思います。特にLinuxとCR5を動作させた状態でデバッグする技術が私に足りないので、まずはもう少しZynqMPと開発ツールをを使いこなせるようになってからになりそうです。(Linux動作させた状態でJtag接続するとCA53がハングしてしまう…)←追記:現在は解決済
また、認定Ubuntuはkernel v5.15系を使っていますが、XilinxのGithubのKernelリポジトリを見ても最近のコミット履歴が見受けられますし、Kernel v6.x系でRPMesgドライバがいくつか機能分割された新設計?になりそうな予感です。XilinxのOpenAMPのサポート状況の内情を知らないのでわかりませんが、何かの過渡期なのかもしれません。
リリースされるかどうかわかりませんが、認定Ubuntu24.04はKernel v6.x系になると予想されるので、いま本腰入れて原因調査しても意味が薄くなるかもしれません。とりあえず本件は様子見したいと思います。
OpenAMPの代替となる方法について
OpenAMPでELFロードと起動管理は出来ましたが、コア間通信が使えないと、今後CR5開発の幅が狭まってしまうので、変わりの方法を考えてみます。せっかくPL(FPGA)が載っているのでここを活用してみたいですね。
代替AMP案としては今思いつくのは以下2つくらいです。
- PLにAXI UARTLite IPを載っけてUARTをFIFOとして使う
- PLにAXI QSPI IPを載っけてSPIをFIFOとして使う
基本はコマンドを送り合う用途を想定しているので、この場合は通信速度を出す必要は無いです。だとするとこんなもので十分ではないかと思います。気が向いたらやってみます。
SPIはクロック同期なので比較的高速ですが、スレーブ側の開発がネックになりそうです。転送タイミングを自身で決められませんからね…。CTS、RTS信号をAXI GPIOで用意してフロー制御やるか…いやシンプルに出来ないならOpenAMP代替のメリットが薄くなるな…
3. OpenAMPを動かしてみよう
3-1. まずは情報収集から
Petalinuxではカーネルのドライバが使われているので、少なくともドライバが存在します。問題はDevicetreeの記述ですが、なんとかなるかもしれません。Webで探すと、参考にできそうな情報が見つかりました。
- 実践的!FPGA開発セミナー vol.12 フィックスターズ様
- Kria KV260 環境構築メモ(Ubuntu22.04 版) Ryuz88様
- Understanding OpenAMP On Zynq+ZynqMP AVNET
- Building RPU Split Mode Applications AVNET
- support.xilinx.com : Usage of the remoteproc functionality via Ubuntu 22.04 (5.15.0-1025-xilinx-zynqmp) on a KR260 board.
こうして参考となる情報を公開していただけるのはとてもありがたいです。
3-2. Remoteproc、RPMsgドライバの有無
参考情報1番目のフィックススターズさんのスライドによると認定Ubuntuにドライバは既に入っているようです。
調べてみましょう。ありましたね。
# 認定Ubuntu22.04
# まずはRPMSG
$ find /lib/modules/5.15.0-1031-xilinx-zynqmp/kernel/drivers/ -name "*rpmsg*"
/lib/modules/5.15.0-1031-xilinx-zynqmp/kernel/drivers/rpmsg
/lib/modules/5.15.0-1031-xilinx-zynqmp/kernel/drivers/rpmsg/virtio_rpmsg_bus.ko
/lib/modules/5.15.0-1031-xilinx-zynqmp/kernel/drivers/rpmsg/rpmsg_ns.ko
/lib/modules/5.15.0-1031-xilinx-zynqmp/kernel/drivers/rpmsg/rpmsg_core.ko
/lib/modules/5.15.0-1031-xilinx-zynqmp/kernel/drivers/rpmsg/rpmsg_char.ko
# Remoteproc
$ find /lib/modules/5.15.0-1031-xilinx-zynqmp/kernel/drivers/ -name "*remoteproc*"
/lib/modules/5.15.0-1031-xilinx-zynqmp/kernel/drivers/remoteproc
/lib/modules/5.15.0-1031-xilinx-zynqmp/kernel/drivers/remoteproc/zynqmp_r5_remoteproc.ko
3-2. Devicetreeの記述方法
どのWeb記事のDevicetreeも一見記述は同じに見えますが、細かい部分が異なります。
主な差異は以下の感じです。特にドライバVerの違いで微妙に記述が異なるのが厄介でした。
- CR5の動作モードの違い(LockstepとSplit)
- Remoteproc、RPMsgドライバのVer違い
- IPI(コア間割込みとmailbox)のmailboxの設定
認定Ubuntu22.04はKernel v5.15系ですが、v5.10系と記述方法が違うようです。
参考情報5番目のXilinxサポートのページで、AMDのaravindb氏がDevicetree DTSIソースとECHOテストの実行ファイルを公開してくれています。Lockstepモード版の単コアですが、私の環境ではELFをロードしてコアの起動停止とECHOテストもPASSしました。
aravindb氏の(zynqmp_openamp.dtsi)をこちらにも残しておきます。
/*
* SPDX-License-Identifier: MIT
*
* dts file for ZynqMP OpenAMP
*
* Copyright (C) 2022, Advanced Micro Devices, Inc. All rights reserved.
*
*/
&{/} {
reserved-memory {
#address-cells = <2>;
#size-cells = <2>;
ranges;
rpu0vdev0vring0: rpu0vdev0vring0@3ed40000 {
no-map;
reg = <0x0 0x3ed40000 0x0 0x4000>;
};
rpu0vdev0vring1: rpu0vdev0vring1@3ed44000 {
no-map;
reg = <0x0 0x3ed44000 0x0 0x4000>;
};
rpu0vdev0buffer: rpu0vdev0buffer@3ed48000 {
no-map;
reg = <0x0 0x3ed48000 0x0 0x100000>;
};
rproc_0_reserved: rproc@3ed00000 {
no-map;
reg = <0x0 0x3ed00000 0x0 0x40000>;
};
};
tcm_0a: tcm_0a@ffe00000 {
no-map;
reg = <0x0 0xffe00000 0x0 0x10000>;
status = "okay";
compatible = "mmio-sram";
power-domain = <&zynqmp_firmware 15>;
};
tcm_0b: tcm_0b@ffe20000 {
no-map;
reg = <0x0 0xffe20000 0x0 0x10000>;
status = "okay";
compatible = "mmio-sram";
power-domain = <&zynqmp_firmware 16>;
};
rf5ss@ff9a0000 {
compatible = "xlnx,zynqmp-r5-remoteproc";
xlnx,cluster-mode = <0>;
ranges;
reg = <0x0 0xFF9A0000 0x0 0x10000>;
#address-cells = <0x2>;
#size-cells = <0x2>;
r5f_0: r5f@0 {
compatible = "xilinx,r5f";
#address-cells = <2>;
#size-cells = <2>;
ranges;
sram = <&tcm_0a>, <&tcm_0b>;
memory-region = <&rproc_0_reserved>, <&rpu0vdev0buffer>, <&rpu0vdev0vring0>, <&rpu0vdev0vring1>;
power-domain = <&zynqmp_firmware 7>;
mboxes = <&ipi_mailbox_rpu0 0>, <&ipi_mailbox_rpu0 1>;
mbox-names = "tx", "rx";
};
};
zynqmp_ipi1 {
compatible = "xlnx,zynqmp-ipi-mailbox";
interrupt-parent = <&gic>;
interrupts = <0 29 4>;
xlnx,ipi-id = <7>;
#address-cells = <1>;
#size-cells = <1>;
ranges;
/* APU<->RPU0 IPI mailbox controller */
ipi_mailbox_rpu0: mailbox@ff990600 {
reg = <0xff990600 0x20>,
<0xff990620 0x20>,
<0xff9900c0 0x20>,
<0xff9900e0 0x20>;
reg-names = "local_request_region",
"local_response_region",
"remote_request_region",
"remote_response_region";
#mbox-cells = <1>;
xlnx,ipi-id = <1>;
};
};
};
4. CR5のLockstepモードでOpenAMP Echo testを試す
- DevicetreeのOpenAMP対応(CR5 Lockstep版)
- Echo testサンプルのビルド(Linuxアプリ側)
- Echo testサンプルのビルド(CR5ファーム側、ベアメタル)
- Echo testの実行
- 2回目のEcho testの実行はVirtIOがbusyになり、実行不可
先程のデバイスツリーのインストール方法ですが、参考情報2番目のRyuz88様の記事にあるように、認定Ubuntuの現在のDTSをデコンパイルして読み出してから、includeを加えてコンパイルし直す必要があります。
認定Ubuntu内で以下のコマンドでデコンパイルして読み出せます。
sudo dtc /sys/firmware/fdt 2> /dev/null > system.dts
system.dtsを開いて、末尾でincludeをします。
/include/ "zynqmp_openamp.dtsi"
再コンパイルしてuser-override.dtbに名前を変えます。
$ dtc -@ -O dtb system.dts -o user-override.dtb
認定Ubuntuでは以下のフォルダに配置するとデフォルトのDevicetreeではなくこちらを読み込んでくれます。名前はuser-override.dtbにしないといけません。
$ sudo cp user-override.dtb /boot/firmware/
ZynqMPを再起動します。以下にOpenAMPのRemoteproc0が現れればOKです。
$ ls /sys/class/remoteproc/
remoteproc0
4-1. OpenAMPが提供するサンプル
公式のOpenAMPは3つのサンプルを提供しています。
- Echo test
- 行列乗算
- リモートプロシージャコール(RPC)
今回単純そうなEcho testをやってみます。Linux側のアプリとCR5ファームウェアの両方を用意します。
4-2. Echo test(Linux側実行ファイル)の準備
ソースコードがOpenAMP公式よりGithubで提供されていました。
https://github.com/OpenAMP/openamp-system-reference/tree/v2024.05/examples/linux/rpmsg-echo-test
ブランチv2024.05で最新のコミットが1年前と最近まであります。ZynqMP専用ですので、Xilinxの方がメンテしていると思われます。
ちなみにXilinxのGithubリポジトリにもEcho testのソースがあるのですが、rel-v2022.2ブランチまで存在して、rel-v2023.1から削除されています。おそらく上記のOpenAMP本家に移ったということかと思います。ちなみにmasterブランチのソースは最新コミットが8年前のかなり古いものでした。
ZynqMP上でビルドします。
$ git clone -b v2024.05 https://github.com/OpenAMP/openamp-system-reference.git
$ cd openamp-system-reference/examples/linux/rpmsg-echo-test/
$ ls -1
Makefile
README.md
echo_test.c
$ make
$ ls -1
Makefile
README.md
echo_test # <--これ
echo_test.c
echo_test.o
4-3. Echo test(CR5 firmware)の準備
VitisでCR5のファームウェアを作成していきます。新Vitis(VItis Unified IDE)を使いたいところですが、理由があって今回はVitis Classicを使います。
新Vitisを使わない理由
- Echo testや行列乗算などの複数のサンプルコードが入ったソースフォルダが生成され、CMakeでビルド対象のコードをコンパイルスイッチしていて、ぱっと見てどれがビルド対象なのかがかなり分かりづらい
- 複数あるリンカスクリプトはもはやどれを使っているのかわからない
- FreeRTOS版は未対応で、ベアメタル版のみ
サンプルなのに分かりづらくてそっと閉じました(笑)。OpenAMPで重要なリンカスクリプトがすぐ見たいのに…
Vitis Classicを起動してプラットフォームプロジェクトを作成します。ハードウェアエクスポートXSAは適当なものを流用しました。今回はPLは使いません。
- standalone
- psu_cortexr5_0
上記の条件で作成します。変更点はBSPです。
- Libmetalを追加
- openampを追加
ビルドします。終わったらアプリケーションプロジェクトを作成します。
最後のTemplatesで”OpenAMP echo-test”を選択します。
作成できたら、Releaseビルドします。
VScodeのRemoteSSHでZynqMPと接続しているのならば、ドラッグ&ドロップでELFをコピーできます。(ちなみにファイルコピーとフォルダごとコピーもドラッグ&ドロップで行けることを最近知りました…もうSCPを使うことは無いでしょう)
ZynqMP上で作業します。ELFをロードしてCR5を起動してみましょう。
$ sudo cp ./app_echo_test_r5_0.elf /lib/firmware/
#ELFのロード
$ sudo sh -c "echo app_echo_test_r5_0.elf > /sys/class/remoteproc/remoteproc0/firmware"
#CR5-0の状態
$ cat /sys/class/remoteproc/remoteproc0/state
offline
#CR5-0を起動
$ sudo sh -c "echo start > /sys/class/remoteproc/remoteproc0/state"
$ cat /sys/class/remoteproc/remoteproc0/state
running
DevicetreeとCR5ファームウェアの設定が正常であれば、RPMSG用のVirtIOポートが出現します。
$ ls -1 /sys/bus/rpmsg/devices/
virtio0.rpmsg-openamp-demo-channel.-1.1024
virtio0.rpmsg_ctrl.0.0
virtio0.rpmsg_ns.53.53
4-4. Echo testを実行する
#ドライバのロード
$ sudo modprobe rpmsg_char
# Echo test実行
$ cd openamp-system-reference/examples/linux/rpmsg-echo-test/
$ sudo ./echo_test
Echo test start
using dev file: virtio0.rpmsg-openamp-demo-channel.-1.1024
open /sys/bus/rpmsg/devices/virtio0.rpmsg-openamp-demo-channel.-1.1024/driver_override
write virtio0.rpmsg-openamp-demo-channel.-1.1024 to /sys/bus/rpmsg/drivers/rpmsg_chrdev/bind
opendir /sys/bus/rpmsg/devices/virtio0.rpmsg_ctrl.0.0/rpmsg
opendir /sys/bus/rpmsg/devices/virtio0.rpmsg-openamp-demo-channel.-1.1024/rpmsg
open /dev/rpmsg_ctrl0
main():137 app_rpmsg_create_ept: rpmsg-openamp-demo-channel[src=0,dst=0x400]
checking /sys/class/rpmsg/rpmsg_ctrl0/rpmsg0/name
svc_name: rpmsg-openamp-demo-channel
.
open /dev/rpmsg0
**************************************
Echo Test Round 0
**************************************
sending payload number 0 of size 17
echo test: sent : 17
received payload number 0 of size 17
sending payload number 1 of size 18
echo test: sent : 18
received payload number 1 of size 18
sending payload number 2 of size 19
echo test: sent : 19
(...)
sending payload number 469 of size 486
echo test: sent : 486
received payload number 469 of size 486
sending payload number 470 of size 487
echo test: sent : 487
received payload number 470 of size 487
sending payload number 471 of size 488
echo test: sent : 488
received payload number 471 of size 488
**************************************
Echo Test Round 0 Test Results: Error count = 0
**************************************
$
無事完走できました。しかし、再度実行しようとすると、VertIOがbusy状態になって実行できませんでした。長時間待ってもだめで、CR5を停止->起動で再起動する必要があります。
# Try 2nd run.
$ sudo ./echo_test
Echo test start
using dev file: virtio0.rpmsg-openamp-demo-channel.-1.1024
open /sys/bus/rpmsg/devices/virtio0.rpmsg-openamp-demo-channel.-1.1024/driver_override
write virtio0.rpmsg-openamp-demo-channel.-1.1024 to /sys/bus/rpmsg/drivers/rpmsg_chrdev/bind
Failed to write virtio0.rpmsg-openamp-demo-channel.-1.1024 to /sys/bus/rpmsg/drivers/rpmsg_chrdev/bind, Device or resource busy
5.まとめ
OpenAMPを以下の条件で動かすことが出来ました。
- CR5 Lockstep動作でELFのロード及びコアの起動、停止
- Echo testサンプルを実行し、完走
- CR5側のファームウェアはベアメタル版で作成
- Echo testサンプルの2回目の実行はVirtIO busyのため不可
Echo testサンプルの2回目の実行は一度も成功せず、原因もまだわかっていません。もう一度動かしたい場合はCR5を一度停止して再起動する必要がありました。
この記事のコード類は私のGithubに残しておきます。
次回はCR5を2コアで使用する、CR5 Splitを試してみます。