組込み

【ZynqMP】4. 1. 認定UbuntuでOpenAMPを試す【CR5Split】

1.記事一覧

記事は複数回に分けて投稿する予定です。AMD/XilinxのARM SoC(ZynqMP Kria K26 SOM)で動作する、AMD/Xilinx公式認定Ubuntuやベアメタル開発を勉強していく覚書きです。

Zynq7000(armv7)版はこちら

2.前回に引き続き、Splitモード(2コア)を試す

注:この記事の内容は2024/7頃の内容になります。情報が古い場合はご了承ください。

前回、OpenAMPでCR5のLockstepモード(冗長1コア)での動作を試しました。今回はSplitモード(2コア)での動作を試したいと思います。

2-1. 参考情報

前回のものを転載します。貴重な情報に感謝です。

  1. 実践的!FPGA開発セミナー vol.12 フィックスターズ様
  2. Kria KV260 環境構築メモ(Ubuntu22.04 版) Ryuz88様
  3. Understanding OpenAMP On Zynq+ZynqMP AVNET
  4. Building RPU Split Mode Applications AVNET
  5. support.xilinx.com : Usage of the remoteproc functionality via Ubuntu 22.04 (5.15.0-1025-xilinx-zynqmp) on a KR260 board.

2-2. 環境条件

前回と同じです。

開発PCUbuntu20.04 LTS
開発ツールAMD/Xilinx社 Vivado・Vitis Classic v2024.1.1
ターゲットOSXilinx認定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 testGithub : 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回目の実行不可. 原因もわからず

前回の始めに記載した、結果のまとめをこちらにも転載します。

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.CR5のSplitモード(2コア)でOpenAMP Echo testを試す

ここでやること
  • DevicetreeをCR5 Splitモード版に変更する
  • CR5-1コア用のEcho testサンプルを作成する
  • CR5-0、CR5-1の2テストを実行
  • 2回目のEcho test実行は不可

3-1. Splitモード版のDevicetree

Splitモード版のDevicetreeを作成していきます。といっても中身を理解しているわけでは無いので、Web上の先駆者の方の知識を借りながら見様見真似で作ってみます。

特にAVNETさんの公開情報が参考になります。DevicetreeとCR5側ファームウェアの両方の設定が一致しないと動作しません。両方の修正内容が載っていて参考になります。

最終的に完成したものが以下になります。

  • zynqmp_openamp_r5_split.dtsi
  • 5.15.0-1031-xilinx-zynqmp
  • この後説明するEcho test用CR5ファームウェアにもdtsiに一致した設定が必要
YAML
/*
 * 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;
        rproc_0_reserved: rproc@3ed00000 {
            no-map;
            reg = <0x0 0x3ed00000 0x0 0x40000>;
        };
        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_1_reserved: rproc@3ef00000 {
            no-map;
            reg = <0x0 0x3ef00000 0x0 0x40000>;
        };
        rpu1vdev0vring0: rpu0vdev0vring0@3ef40000 {
            no-map;
            reg = <0x0 0x3ef40000 0x0 0x4000>;
        };
        rpu1vdev0vring1: rpu0vdev0vring1@3ef44000 {
            no-map;
            reg = <0x0 0x3ef44000 0x0 0x4000>;
        };
        rpu1vdev0buffer: rpu0vdev0buffer@3ef48000 {
            no-map;
            reg = <0x0 0x3ef48000 0x0 0x100000>;
        };

    };

    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>;
    };

    tcm_1a: tcm_0a@ffe90000 {
        no-map;
        reg = <0x0 0xffe90000 0x0 0x10000>;
        status = "okay";
        compatible = "mmio-sram";
        power-domain = <&zynqmp_firmware 17>;
    };

    tcm_1b: tcm_0b@ffeb0000 {
        no-map;
        reg = <0x0 0xffeb0000 0x0 0x10000>;
        status = "okay";
        compatible = "mmio-sram";
        power-domain = <&zynqmp_firmware 18>;
    };

    rf5ss@ff9a0000 {
        compatible = "xlnx,zynqmp-r5-remoteproc";
        xlnx,cluster-mode = <1>;
        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";
        };
        r5f_1: r5f@1 {
            compatible = "xilinx,r5f";
            #address-cells = <2>;
            #size-cells = <2>;
            ranges;
            sram = <&tcm_1a>, <&tcm_1b>;
            memory-region = <&rproc_1_reserved>, <&rpu1vdev0buffer>, <&rpu1vdev0vring0>, <&rpu1vdev0vring1>;
            power-domain = <&zynqmp_firmware 8>;
            mboxes = <&ipi_mailbox_rpu1 0>, <&ipi_mailbox_rpu1 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;

        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>;
        };
    };
    zynqmp_ipi2 {
        compatible = "xlnx,zynqmp-ipi-mailbox";
        interrupt-parent = <&gic>;
        interrupts = <0 30 4>;
        xlnx,ipi-id = <8>;
        #address-cells = <1>;
        #size-cells = <1>;
        ranges;

        ipi_mailbox_rpu1: mailbox@ff990400 {
            reg = <0xff990400 0x20>,
                  <0xff990420 0x20>,
                  <0xff990040 0x20>,
                  <0xff990060 0x20>;
            reg-names = "local_request_region",
                        "local_response_region",
                        "remote_request_region",
                        "remote_response_region";
            #mbox-cells = <1>;
            xlnx,ipi-id = <2>;
        };
    };
};


3-2. Devicetreeの予約メモリ領域

予約メモリで定義されているのはLinux側とCR5側で情報のやり取りをするための、共有メモリです。

“rproc_0_reserved”は0x3ed00000から始まるDRAM領域です。これをずらして重ならないように、”rproc_1_reserved”を定義します。

  • rproc_0_reserved: 0x3ED00000
  • rproc_1_reserved: 0x3EF00000

他の領域(vring0,vring1,buffer)もおなじく定義します。

領域の用途ですが、正直よくわかっていません。重要なのはCR5の各コアでメモリ領域がオーバーラップしてはだめなことです。ただし、あとで触れますが、サンプルで使われている0x3ED00000付近はCMAメモリアロケータと干渉します。

rproc_N_reserved
(N = 0,1)
CR5の一部のセクションがここに置かれる。
.text
.bss
.resource_table <-RPMsg用に必要な情報ヘッダ
rpuNvdev0vring0
(N = 0,1)
VirtIOのリングバッファに見えるが実際はわからない。そうだとしたら送受信のどちらか。IPIのMailboxとどう役割分担しているのかもわからない
rpuNvdev0vring1
(N = 0,1)
↑に同じ
rpuNvdev0buffer
(N = 0,1)
debugfsに出力するためのトレースバッファ。
“/sys/kernel/debug/remoteproc/remoteprocN/trace0 “をcatして読める。
CR5の出力するメッセージを記録する。

3-3. DevicetreeのTCM(密結合メモリ)

CR5にはTCMと呼ばれる1サイクルアクセスが可能な低レイテンシメモリが搭載されています。CR5は0番地から実行を開始し、かつ、TCMも0番地から割当てのため、CA53側からバイナリをロードする必要があります。

TCMはATCMとBTCMの領域に分かれていて、バスもそれぞれ分かれています。

ここでポイントとなるのは3つです。

  • SplitモードはATCMとBTCMが各64KB
  • LockstepモードはATCMとBTCMが各128KB
  • TCMはCA53から見えるようにアドレス空間に割当てられている

TCMはCR5から見て0番地から割当てられているのですが、バイナリを外部からロードできるようにCA53のアドレス空間では別アドレスからアクセスできるようになっています。DevicetreeではCA53から見える(Global Address)、TCMアドレスを定義します。

<引用:UG1085 Ch.4 Real-time Processing Unit>

3-4. DevicetreeのCR5コア

CR5コアのELFロード、起動停止管理を行う、Remoteprocドライバのための設定を定義します。Webで検索すると様々な記述方法がありますが、おそらくKernel v5.10系とv5.15系で仕様が変更されたことが要因の一つかもしれません。

注意点として以下をまず認定UbuntuのKernelのVerを確認します。

Bash
Xilinx Ubuntu22.04
$ uname -r
5.15.0-1031-xilinx-zynqmp

v5.15系ですね。次にデバイスドライバ(zynqmp_r5_remoteproc.c)のコンパチを見ると以下のようになります。Ubuntuの場合、Linux kernelのソースコードをgit cloneできます。詳しくは以前の記事を参照

  • v5.10以下 : compatible = “xlnx,zynqmp-r5-remoteproc-1.0”;
  • v5.15以上 : compatible = “xlnx,zynqmp-r5-remoteproc”;

Webの検索でv5.10系は読み飛ばすと混乱しなくなります。

次にSplit、Lockstepモードの切替ですが、”1″と”0″で指定します。これもWeb上でどっちがどっちだ論争が繰り広げられていました。本環境では以下となります。

Xilinx認定Ubuntu22.04
5.15.0-1031-xilinx-zynqmp

  • Splitモード(2コア):xlnx,cluster-mode = <1>;
  • Lockstepモード(冗長1コア):xlnx,cluster-mode = <0>;

確認方法はKernelのドライバのソースコードを確認するしかないと思います。以前カーネルビルド記事を作成したのでリンクを貼っておきます。同じ5.15.0-1031-xilinx-zynqmpのソースを取得して、zynqmp_r5_remoteproc.cを確認します。

【ZynqMP】2. 認定Ubuntuのカーネルビルド

イメージ掴めないと思いますので、参考にXilinxのKernelを貼っておきます。認定Ubuntuで使用されているLinux Kernelではありませんので、あくまでも参考程度になります。

xlnx,cluster-mode = <>;を読み出しているドライバの箇所からたどります。

3-5. DevicetreeのIPIとMailbox

IPIはコア間割込み機能(inter processor interrupts)で、Mailbox機能向けのバッファメモリ機能もあります。

Mailboxは正直難解で、まだよくわかっていません。

試行錯誤した結果、AVNETさんが公開されている情報で動かすことが出来ました。

“xlnx,ipi-id”を指定する箇所がIPI1つにつき2箇所あり、どちらかがCA53のIPIチャネル番号でもう一方がCR5のチャネル番号と思われます。しかし、Web検索するとばらばらで、明らかにCHが違う場合もあり、結局わかりませんでした。RPMsgドライバを読むのも諦めました。ちなみに、CR5ファームウェアもこのDevicetreeに一致した設定にする必要があり、これもデバッグの難しさを増す要因になりました。

“reg”の項目はMailboxに使用する、メッセージバッファの先頭アドレスです。

<引用:UG1085 Ch.13 Interrupts>

メッセージバッファはアドレス0xFF990000から割当てられています。Lockstep版(冗長1コア)Devicetreeの例では、CA53(APU)がチャネル7、CR5(RPU)がチャネル1に割当てられています。

各チャネルには32byteのRequestバッファとResponseバッファを8つ(SI Agent Nunberの数分)持っていています。

Lockstep版(冗長1コア)Devicetreeの例では以下のようになっています。

CA53->CR5 RequestCh7,0xFF990600,32byteslocal_request_region
CA53->CR5 ResponseCh7,0xFF990620,32byteslocal_response_region
CR5->CA53 RequestCh1,0xFF9900c0,32bytesremote_request_region
CA5->CA53 ResponseCh1,0xFF9900e0,32bytesremote_response_region

メッセージバッファのオフセットアドレスは以下のようになっているはずです…(ここは自信ありません)。TRMを見ても私の頭ではよく理解できませんでした。

Ch NumberAgent NumberMessageBuffer Offset
Ch0Agent1Request=0x00
Response=0x20
Ch1Agent2Request=0x40
Response=0x60
Ch2Agent3Request=0x80
Response=0xA0
Ch3Agent8Request=0x1C0
Response=0x1E0
Ch4Agent8Request=0x1C0
Response=0x1E0
Ch5Agent8Request=0x1C0
Response=0x1E0
Ch6Agent8Request=0x1C0
Response=0x1E0
Ch7Agent4Request=0xC0
Response=0xE0
Ch8Agent5Request=0x100
Response=0x120
Ch9Agent6Request=0x140
Response=0x160
Ch10Agent7Request=0x180
Response=0x1A0

この表を元に、Mailboxのアドレス設定を読み解くと、

CA53->CR5 Request(local_request_region)はCh7のMessagebuffer(0xFF990600)を割当て、”Requestオフセット=0x00″はCh0へのRequestを示していることになっています。Ch7ではなくなぜCh0なのか?と思いますが、意図はわかりません。

結局、設計意図が読み取れなかったので、解読は諦めました。

Split(2コア)の場合、Lockstep版のチャネルをCR5-0コアに設定し、CR5-1コアは新たなチャネルを割当てます。CR5Lockstep版のDevicetree設計意図が不明なので、Web上から動作する記述を探し、トライアンドエラーで実験しました。

Devicetreeのビルドとインストール方法は前章で説明したとおりです。

結果、先程記載したとおり、AVNETさんの公開情報で動かすことが出来ました。

3-6. CR5-0、CR5-1コアのEcho testファームウェア

CR5側もファームウェアのコードに修正を入れる必要があります。CR5-0コアはCR5Lockstep版をそのまま流用できます。CR5-1は修正が必要です。

まず、CR5-1用のプラットフォームプロジェクトと、アプリケーションプロジェクトを前回の記事と同じ様に追加で作成します。”Cortex-r5_1″で作成します。

リンカスクリプトの変更

リンカスクリプトでDRAMに配置するセクションがCR5-0コアと重ならないようにずらします。MEMORY定義でDDRの開始アドレスを変更します。

CR5-0 : DRAM開始アドレス 0x3ED00000
CR5-1 : DRAM開始アドレス 0x3EF00000

lscript.ldの該当箇所

YAML
(...)
_DDR_START = DEFINED(LINKER_DDR_BASE) ? LINKER_DDR_BASE : 0x3EF00000;

(...)

MEMORY
{
   psu_ddr_S_AXI_BASEADDR : ORIGIN = _DDR_START, LENGTH = 0x00040000
   psu_ocm_ram_1_S_AXI_BASEADDR : ORIGIN = 0xFFFF0000, LENGTH = 0x00010000
   psu_r5_tcm_ram_0_S_AXI_BASEADDR : ORIGIN = 0x00000000, LENGTH = 0x00010000
   psu_r5_tcm_ram_1_S_AXI_BASEADDR : ORIGIN = 0x00020000, LENGTH = 0x00010000
}
(...)

DRAMに配置するセクションは主に次の3つです。

  • .text
  • .bss
  • .resource_table

resource_tableはRPMsgの情報ヘッダになっているので、DRAMに配置する必要があります。RemoteprocドライバがELFを解析する際に読み取るようです。デフォルトではDRAM開始アドレス+0x20000に配置されますので、特に修正する必要はありません。

IPI(コア間割込み)の設定変更

platform_info.hにIPI割込みの定数が定義されています。以下のマクロに変更が必要です。

  • IPI_IRQ_VECT_ID
  • POLL_BASE_ADDR
  • IPI_CHN_BITMASK

該当箇所は”VERSAL_NET”、”versal”、”ZynqMP”の3環境分あるので、注意が必要です。今回は”ZynqMP”の部分を変更します。

C
//plarform_info.h
(...)
#else /* ZynqMP case */

#ifndef IPI_IRQ_VECT_ID
#define IPI_IRQ_VECT_ID     XPAR_XIPIPSU_0_INT_ID
#endif /* IPI_IRQ_VECT_ID */

#ifndef POLL_BASE_ADDR
#define POLL_BASE_ADDR      XPAR_XIPIPSU_0_BASE_ADDRESS
#endif /* POLL_BASE_ADDR */

#ifndef IPI_CHN_BITMASK
#define IPI_CHN_BITMASK     0x01000000
#endif /* IPI_CHN_BITMASK */

#endif /* VERSAL_NET */
(...)

表にまとめてみました。

マクロCR5-0CR5-1
IPI_IRQ_VECT_IDXPAR_XIPIPSU_0_INT_ID
->XPAR_PSU_IPI_1_INT_ID
->->65U
説明:IPI_Ch1 GIC IRQ番号
XPAR_XIPIPSU_0_INT_ID
->XPAR_PSU_IPI_2_INT_ID
->->66U
説明:IPI_Ch2 GIC IRQ番号
POLL_BASE_ADDRXPAR_XIPIPSU_0_BASE_ADDRESS
->XPAR_PSU_IPI_1_S_AXI_BASEADDR
->->0xFF310000U
説明:IPI Ch1(RPU0)
XPAR_XIPIPSU_0_BASE_ADDRESS
->XPAR_PSU_IPI_2_S_AXI_BASEADDR
->->0xFF320000U
説明:IPI Ch2(RPU1)
IPI_CHN_BITMASK0x01000000
IPI RPU_0_IERレジスタ
説明:割込み許可
bit24 : Ch 7
0x02000000
IPI RPU_1_IERレジスタ
説明:割込み許可
bit25 : Ch 8

IPI_IRQ_VECT_IDとPOLL_BASE_ADDRマクロはCR5-1用のプラットフォームプロジェクトとアプリケーションプロジェクトを作成していれば、xparameters.hの内容が対応するので、変更の必要がありません。ただし、一応実装を確認したほうが良いと思います。

AVNETさんの例ではCA53->CR5-1のIPI割込みのうち、CR5-1側はCh8を使用するようです。Devicetreeの”xlnx,ipi-id = <8>;”の記述はおそらくCR5-1側のIPI-Ch番号を指定していると思われます。

以上の修正が終わったらビルドします。

ビルドしたELFでセクションを確認してみます。

Bash
# CR5-0 FW
$ readelf -S app_echo_test_r5_0.elf 
There are 31 section headers, starting at offset 0xcb818:

Section Headers:
  [Nr] Name              Type            Addr     Off    Size   ES Flg Lk Inf Al
  [ 0]                   NULL            00000000 000000 000000 00      0   0  0
  [ 1] .vectors          PROGBITS        00000000 010000 000638 00  AX  0   0  8
  [ 2] .text             PROGBITS        3ed00000 020000 012fd4 00  AX  0   0  8
  [ 3] .init             PROGBITS        00000638 010638 00000c 00  AX  0   0  4
  [ 4] .fini             PROGBITS        00000644 010644 00000c 00  AX  0   0  4
  [ 5] .rodata           PROGBITS        00000650 010650 001fad 00   A  0   0  8
  [ 6] .data             PROGBITS        00002600 012600 001100 00  WA  0   0  8
  [ 7] .bootdata         PROGBITS        00003700 013700 000180 00  WA  0   0  8
  [ 8] .eh_frame         PROGBITS        00003880 013880 000004 00   A  0   0  4
  [ 9] .ARM.exidx        ARM_EXIDX       00003884 013884 000008 00  AL  2   0  4
  [10] .init_array       INIT_ARRAY      0000388c 01388c 000004 04  WA  0   0  4
  [11] .fini_array       FINI_ARRAY      00003890 013890 000004 04  WA  0   0  4
  [12] .ARM.attributes   ARM_ATTRIBUTES  00003894 040100 00002f 00      0   0  1
  [13] .bss              NOBITS          3ed20100 040100 00175c 00  WA  0   0  4
  [14] .heap             NOBITS          00003894 013894 00400c 00  WA  0   0  1
  [15] .stack            NOBITS          000078a0 013894 003800 00  WA  0   0  1
  [16] .resource_table   PROGBITS        3ed20000 040000 000100 00  WA  0   0 256
  [17] .comment          PROGBITS        00000000 04012f 000012 01  MS  0   0  1
  [18] .debug_line       PROGBITS        00000000 040141 018149 00      0   0  1
  [19] .debug_line_str   PROGBITS        00000000 05828a 000138 01  MS  0   0  1
  [20] .debug_info       PROGBITS        00000000 0583c2 0258ad 00      0   0  1
  [21] .debug_abbrev     PROGBITS        00000000 07dc6f 007800 00      0   0  1
  [22] .debug_aranges    PROGBITS        00000000 085470 000708 00      0   0  8
  [23] .debug_str        PROGBITS        00000000 085b78 0230e3 01  MS  0   0  1
  [24] .debug_loclists   PROGBITS        00000000 0a8c5b 00fcb5 00      0   0  1
  [25] .debug_rnglists   PROGBITS        00000000 0b8910 00180d 00      0   0  1
  [26] .debug_macro      PROGBITS        00000000 0ba11d 008012 00      0   0  1
  [27] .debug_frame      PROGBITS        00000000 0c2130 0022b0 00      0   0  4
  [28] .symtab           SYMTAB          00000000 0c43e0 004690 10     29 640  4
  [29] .strtab           STRTAB          00000000 0c8a70 002c66 00      0   0  1
  [30] .shstrtab         STRTAB          00000000 0cb6d6 000140 00      0   0  1
Key to Flags:
  W (write), A (alloc), X (execute), M (merge), S (strings), I (info),
  L (link order), O (extra OS processing required), G (group), T (TLS),
  C (compressed), x (unknown), o (OS specific), E (exclude),
  D (mbind), y (purecode), p (processor specific)



# CR5-1 FW
$ readelf -S app_echo_test_r5_1.elf 
There are 30 section headers, starting at offset 0x982c4:

Section Headers:
  [Nr] Name              Type            Addr     Off    Size   ES Flg Lk Inf Al
  [ 0]                   NULL            00000000 000000 000000 00      0   0  0
  [ 1] .vectors          PROGBITS        00000000 010000 000638 00  AX  0   0  8
  [ 2] .text             PROGBITS        3ef00000 020000 012fd4 00  AX  0   0  8
  [ 3] .init             PROGBITS        00000638 010638 00000c 00  AX  0   0  4
  [ 4] .fini             PROGBITS        00000644 010644 00000c 00  AX  0   0  4
  [ 5] .rodata           PROGBITS        00000650 010650 001fad 00   A  0   0  8
  [ 6] .data             PROGBITS        00002600 012600 001100 00  WA  0   0  8
  [ 7] .bootdata         PROGBITS        00003700 013700 000180 00  WA  0   0  8
  [ 8] .eh_frame         PROGBITS        00003880 013880 000004 00   A  0   0  4
  [ 9] .ARM.exidx        ARM_EXIDX       00003884 013884 000008 00  AL  2   0  4
  [10] .init_array       INIT_ARRAY      0000388c 01388c 000004 04  WA  0   0  4
  [11] .fini_array       FINI_ARRAY      00003890 013890 000004 04  WA  0   0  4
  [12] .ARM.attributes   ARM_ATTRIBUTES  00003894 040100 00002f 00      0   0  1
  [13] .bss              NOBITS          3ef20100 040100 00175c 00  WA  0   0  4
  [14] .heap             NOBITS          00003894 013894 00400c 00  WA  0   0  1
  [15] .stack            NOBITS          000078a0 013894 003800 00  WA  0   0  1
  [16] .resource_table   PROGBITS        3ef20000 040000 000100 00  WA  0   0 256
  [17] .comment          PROGBITS        00000000 04012f 000012 01  MS  0   0  1
  [18] .debug_line       PROGBITS        00000000 040141 013602 00      0   0  1
  [19] .debug_line_str   PROGBITS        00000000 053743 000138 01  MS  0   0  1
  [20] .debug_info       PROGBITS        00000000 05387b 01fb87 00      0   0  1
  [21] .debug_abbrev     PROGBITS        00000000 073402 006622 00      0   0  1
  [22] .debug_aranges    PROGBITS        00000000 079a28 000660 00      0   0  8
  [23] .debug_str        PROGBITS        00000000 07a088 004b9e 01  MS  0   0  1
  [24] .debug_loclists   PROGBITS        00000000 07ec26 00ec12 00      0   0  1
  [25] .debug_rnglists   PROGBITS        00000000 08d838 0016c8 00      0   0  1
  [26] .debug_frame      PROGBITS        00000000 08ef00 001fa8 00      0   0  4
  [27] .symtab           SYMTAB          00000000 090ea8 004680 10     28 639  4
  [28] .strtab           STRTAB          00000000 095528 002c66 00      0   0  1
  [29] .shstrtab         STRTAB          00000000 09818e 000133 00      0   0  1
Key to Flags:
  W (write), A (alloc), X (execute), M (merge), S (strings), I (info),
  L (link order), O (extra OS processing required), G (group), T (TLS),
  C (compressed), x (unknown), o (OS specific), E (exclude),
  D (mbind), y (purecode), p (processor specific)
  

3-7. Echo testを実行する

前回同様、Devicetreeをインストールして再起動します。remoteprocが2つ出現すれば成功です。

Bash
$ ls -1 /sys/class/remoteproc/
remoteproc0
remoteproc1

CR5-0、CR5-1のELFをZynqMPの/lib/firmwareに移動しておきます。

CR5の両コアを起動します。ELFのファイル名は適宜変えてください。

Bash
$ sudo sh -c "echo app_echo_test_r5_0.elf > /sys/class/remoteproc/remoteproc0/firmware"
$ sudo sh -c "echo app_echo_test_r5_1.elf > /sys/class/remoteproc/remoteproc1/firmware"
$ sudo sh -c "echo start > /sys/class/remoteproc/remoteproc0/state"
$ sudo sh -c "echo start > /sys/class/remoteproc/remoteproc1/state"

$ ls -1 /sys/bus/rpmsg/devices/
virtio0.rpmsg-openamp-demo-channel.-1.1024
virtio0.rpmsg_ctrl.0.0
virtio0.rpmsg_ns.53.53
virtio1.rpmsg-openamp-demo-channel.-1.1024
virtio1.rpmsg_ctrl.0.0
virtio1.rpmsg_ns.53.53

RPMsgのVirtIOが2つ出現したら成功です。

Echo test(Linux)を実行する

前回OpenAMP公式のGithubリポジトリでソースビルドして実行しました。v2024.05ブランチの最新のものであれば、SysfsのVirtIOファイルを検索してくれるので、CR5-0、CR5-1コア用の修正は必要ありません。ただし、VirtIOが2つあると判別できないようなので、CR5-0を停止します。

Bash
$ sudo sh -c "echo stop > /sys/class/remoteproc/remoteproc0/state"

$ ls -1 /sys/bus/rpmsg/devices/
virtio1.rpmsg-openamp-demo-channel.-1.1024
virtio1.rpmsg_ctrl.0.0
virtio1.rpmsg_ns.53.53

Echo testを実行します。

Bash
#ドライバのロード
$ sudo modprobe rpmsg_char
# Echo test実行
$ sudo ./openamp-system-reference/examples/linux/rpmsg-echo-test/echo_test

 Echo test start 
using dev file: virtio1.rpmsg-openamp-demo-channel.-1.1024
open /sys/bus/rpmsg/devices/virtio1.rpmsg-openamp-demo-channel.-1.1024/driver_override
write virtio1.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/virtio1.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 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

 **************************************

VirtIO1側がOpenされ、テストが通りました。CR5-0側も同様にクリアしました。

しかし、再起動は前回と同じくVirtIO busyになってしまい、2コアともに不可能でした。

4.まとめ

続編となる今回は、CR5 Split(2コア)動作をやってみました。

  • CR5 Split動作でELFのロード及びコアの起動、停止
  • Echo testサンプルを実行し、Pass
  • CR5側のファームウェアはベアメタル版で作成
  • Echo testサンプルの2回目の実行はVirtIO busyのため不可

今回もEcho testサンプルの2回目の実行は一度も成功せず、原因もまだわかっていません。もう一度動かしたい場合はLockstepの場合と同じく、CR5を一度停止して再起動する必要がありました。

この記事のコード類は私のGithubに残しておきます。

ABOUT ME
sh-goto
低レイヤで遊んでいます
関連記事