🐡

Kria KV260 環境構築メモ(Ubuntu24.04 版)

に公開

概要

Kria KV260 にて 認定Ubuntu の 24.04 LTS にて構築した際の個人的メモです。

その他にも KV260/KR260の初期セットアップ にも初心者向けの内容を書いておりますので、そちらも参考にしてください。

なお古いバージョン用には

にあります。

環境構築

ファームウェアのアップデート

場合によっては古いファームウェアの KV260 だとうまく起動しないケースもあるようです。
必要に応じて、まずKV260のファームウェアバージョンアップを先に検討ください。

ファームウェアバージョンアップについてはこちらを参照ください。

既に Ubuntu が入っている場合は、こちらの別記事で紹介しています。

Ubuntu の SDカード作成

イメージはこちらから取得して、SDカードに書き込むことになります。

私が使ったバージョンは iot-limerick-kria-classic-server-2404-classic-24.04-x07-20250423.img でした。

Linux なら dd コマンド、Windows や Mac なら Balena EtcherWin32 DiskImager などを用いて書き込めばよいようです。

SDが出来上がったら、ボードに差し込んで電源を入れれば起動します。

キーボードやモニタを繋いでも良いかと思いますが、私の場合は USB を接続して、とりあえず TeraTerm からシリアル(UART)接続することが多いです。

初期アカウント ubuntu の 初期パスワードは ubuntu のようです。ログインするとパスワードを変えるように促されるので設定します。

以降の説明は基本的に CLI での操作を想定していますので、GUI から利用する場合もターミナルを起動して同様にコマンドを実行してください。

ネットワークに繋いで、ターミナルから

ip address

などとすると IP アドレスがわかるので、以降を ssh で接続することも可能です。

CUI/GUI の切り替え(お好みで)

GUI使わないという人は若干の起動高速化の為に CUI に切り替えてしまう手もあるかもしれません。お好みで設定ください。

# CUIにする
sudo systemctl set-default multi-user.target

# GUIにする
sudo systemctl set-default graphical.target

最新版にしておく

念のためネットワークに繋いで最新版にしておくとよいかもしれません。

sudo apt update
sudo apt upgrade 

再起動が必要な場合は

sudo poweroff

として一度電源を落としてから再度起動してください。

なお私の今の環境ではカーネルバージョンが 6.8.0-1017-xilinx となっていました。

日本時間にする

SDカードのイメージは UTC のようだったので JST にします。

sudo timedatectl set-timezone Asia/Tokyo

ホスト名の変更(お好みで)

デフォルトの kria のままでも良いのですが、複数ボードを持っていたり、どのSDカードで起動してるかわかりやすくしたい場合などホスト名を変えるのもありかと思います。

sudo hostnamectl set-hostname ubuntu24-kv260

のように変更できるようです。

ユーザーを作る(お好みで)

デフォルトのユーザー(ubuntu)をそのまま使ってもよいのですが、新規に作る場合は。

sudo adduser <username>

でユーザーを作って

sudo gpasswd -a <username> sudo

で sudo 権限を付けておきましょう。

NFSなどでマウントする(お好みで)

以前こちらで書きましたが、NFSマウント等を使うと便利ですので、NASなどお持ちの方はお好みでどうぞ。

特に home を NAS などに置く場合、設定初期に行った方が良い為、先に書いておきます。

/etc/fstab でも良いのですが、ネットワーク環境次第でこちらの方が便利なので autofs を使っています。

sudo apt update
sudo apt -y install nfs-common
sudo apt -y install autofs

でインストールして

sudo nano /etc/auto.master

として末尾に

/etc/auto.master
/-    /etc/auto.mount

を追加

sudo mkdir /mnt/nfs
sudo nano /etc/auto.mount

/etc/auto.mount
/mnt/nfs -fstype=nfs,rw,nfsvers=3 XX.XX.XX.XX:/nfsshare

みたいな感じで、共有ディレクトリを指定

sudo systemctl restart autofs

で完了。

なお、私は auto.mount にさらにもう一行追加して、自分のホームディレクトリを丸々 NAS にマウントしています。
そうするとSDカード壊れてもダメージが小さいです。

基本的なパッケージのインストール

これからいろいろな開発環境を入れるにあたって、基本的なパッケージを入れておきます。

sudo apt update
sudo apt install build-essential

また、当方の開発は gRPC や OpenCV も利用するので用途によっては

sudo apt install protobuf-compiler
sudo apt install libopencv-dev
sudo apt install llvm-dev clang libclang-dev

なども入れておくと良いかと思います。

u-dma-buf のインストール

ZynqMP開発の定番となっている ikwzm氏の u-dma-buf をインストールします。

git clone --recursive --depth=1 -b v5.3.0 https://github.com/ikwzm/u-dma-buf-kmod-dpkg
cd u-dma-buf-kmod-dpkg
sudo debian/rules binary
cd ..
sudo dpkg -i u-dma-buf-*.deb

なお、この手順は apt upgrade などのカーネルのバージョンアップに伴って再度実行する必要がある場合がありますのでご注意ください。

インストールが終わったら clone してきたファイルは削除しても構いません。

bootgenを入れる

PLを使うアプリで必要となるので bootgenも入れておきます。

最近のカーネルでは bit ファイルの bootgen での処理は必須でないようなのですが、bootgen 処理しておいた方が、コンフィギュレーション時間が短いなどの事例もあるようです。

sudo apt update
sudo apt install libssl-dev
 
git clone https://github.com/Xilinx/bootgen
cd bootgen/
make
sudo cp bootgen /usr/local/bin/

Rust のインストール(お好みで)

当方のツールが Rust を使うためインストールを推奨しておきます。

これはユーザー環境にインストールされるので、利用したいユーザーで実行してください。

curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
source $HOME/.cargo/env
rustup default stable
rustup update

さらに、この後でバイナリインストールを使いたい場合は cargo-binstall もインストールしておきます。

curl -L --proto '=https' --tlsv1.2 -sSf https://raw.githubusercontent.com/cargo-bins/cargo-binstall/main/install-from-binstall-release.sh | bash

jelly-fpga-server と jelly-fpga-loadr のインストール(お好みで)

よろしければ拙作の jelly-fpga-server をインストールしてみてください。

curl -LsSf https://raw.githubusercontent.com/ryuz/jelly-fpga-server/master/binst.sh | sudo bash

インストールするとサービスとして起動して ポート 8051 で待ち受けるようになります。

sudo systemctl status jelly-fpga-server

とすると状態が確認できます。

この機能を使うには jelly-fpga-loadr をインストールします。

先に cargo-binstall をインストールしていれば、バイナリインストールも可能です。

cargo-binstall --git https://github.com/ryuz/jelly-fpga-loader.git jelly-fpga-loader

X-Window を使えるようにする

ssh 経由で X アプリを使いたい場合は xauth が必要です。
動作確認用に x11-apps を入れておくと xclock や xeyes などが利用できます。

sudo apt update
sudo apt install xauth
sudo apt install x11-apps

デバイスファイルの権限

DeviceTree に uio や i2c、udmabuf を使う設定を入れた場合に、デフォルトのままだと root 権限でしかアクセスできないため、一般ユーザーでアクセスできるようにします。

sudo nano /etc/udev/rules.d/99-local-device.rules
/etc/udev/rules.d/99-local-device.rules
KERNEL=="uio[0-9]*", SUBSYSTEM=="uio", MODE="0666"
KERNEL=="i2c-[0-9]*", SUBSYSTEM=="i2c-dev", MODE="0666"
KERNEL=="udmabuf*", SUBSYSTEM=="u-dma-buf", MODE="0666"

JTAG の為の設定

ここでは bootargs に関連する 2点を変更します。

デフォルトでは

$ cat /proc/cmdline
root=LABEL=writable rootwait earlycon console=ttyPS1,115200 console=tty1 clk_ignore_unused uio_pdrv_genirq.of_id=generic-uio xilinx_tsn_ep.st_pcp=4 cma=800M

となっていました。

動作中に ILA など使うために JTAGを接続すると固まることがあるのですが cpuidle.off=1 を指定すると回避できるようです(ただし、アイドル時のCPU消費電力は増えるかもしれません)。

sudo nano /etc/default/flash-kernel

のように開いて、私の場合下記のようにしました。

/etc/default/flash-kernel
LINUX_KERNEL_CMDLINE="cpuidle.off=1"
LINUX_KERNEL_CMDLINE_DEFAULTS=""

続けて

sudo flash-kernel

とすれば設定できるようです。

なお、現在の設定を見るには

cat /proc/cmdline

とすればよいようです。

CMAのサイズ指定などを変更したいときも同様に設定を追加できそうです。

RPU (Cortex-R5) を認識させる

関連する記事はこちらなどにもあります(少し古いですが)。

まず KV260 にログインして下記の方法で現状のデバイスツリーを取得します。

sudo dtc /sys/firmware/fdt 2> /dev/null > system.dts

これを編集していきます。

取得した system.dts に対して、まず interrupt-controller@f9010000 のセクションを探して "gic:" を追記しました。

    gic: interrupt-controller@f9010000 {

次に zynqmp-firmware のセクションを探して "zynqmp_firmware:" を追記しました。

    zynqmp_firmware: zynqmp-firmware {

次に reserved-memory の項目を追加するのですが、既に

	reserved-memory {
		#address-cells = <0x02>;
		#size-cells = <0x02>;
		ranges;

		pmu@7ff00000 {
			reg = <0x00 0x7ff00000 0x00 0x100000>;
			no-map;
			phandle = <0x7a>;
		};
	};

という定義が存在したので、ここに追記します。結果この部分は下記のようになりました。

	reserved-memory {
		#address-cells = <0x02>;
		#size-cells = <0x02>;
		ranges;

		pmu@7ff00000 {
			reg = <0x00 0x7ff00000 0x00 0x100000>;
			no-map;
			phandle = <0x7a>;
		};

        // ------ ここから追記 --------
        rpu0vdev0vring0: rpu0vdev0vring0@7ed40000 {
            no-map;
            reg = <0x0 0x7ed40000 0x0 0x4000>;
        };
        rpu0vdev0vring1: rpu0vdev0vring1@7ed44000 {
            no-map;
            reg = <0x0 0x7ed44000 0x0 0x4000>;
        };
        rpu0vdev0buffer: rpu0vdev0buffer@7ed48000 {
            no-map;
            reg = <0x0 0x7ed48000 0x0 0x100000>;
        };
        rproc_0_reserved: rproc_0_reserved@7ed00000 {
            no-map;
            reg = <0x0 0x7ed00000 0x0 0x40000>;
        };
        
        rpu1vdev0vring0: rpu1vdev0vring0@7ef40000 {
            no-map;
            reg = <0x0 0x7ef40000 0x0 0x4000>;
        };
        rpu1vdev0vring1: rpu1vdev0vring1@7ef44000 {
            no-map;
            reg = <0x0 0x7ef44000 0x0 0x4000>;
        };
        rpu1vdev0buffer: rpu1vdev0buffer@7ef48000 {
            no-map;
            reg = <0x0 0x7ef48000 0x0 0x100000>;
        };
        rproc_1_reserved: rproc_1_reserved@7ef00000 {
            no-map;
            reg = <0x0 0x7ef00000 0x0 0x40000>;
        };
        // ------ ここまで --------
    };

最後に __symbols__ の直前に下記を追記しました。

    tcm_0a: tcm_0a@ffe00000 {
        no-map;
        reg = <0x0 0xffe00000 0x0 0x10000>;
        status = "okay";
        compatible = "mmio-sram";
        power-domains = <&zynqmp_firmware 15>;
    };

    tcm_0b: tcm_0b@ffe20000 {
        no-map;
        reg = <0x0 0xffe20000 0x0 0x10000>;
        status = "okay";
        compatible = "mmio-sram";
        power-domains = <&zynqmp_firmware 16>;
    };

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

    zynqmp-rpu@ff9a0000 {
        compatible = "xlnx,zynqmp-r5-remoteproc";
        xlnx,cluster-mode = <1>;
        ranges;
        reg = <0x0 0xff9a0000 0x0 0x10000>;
        #address-cells = <0x2>;
        #size-cells = <0x2>;
        
        r5_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-domains = <&zynqmp_firmware 7>;
        };
        r5_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-domains = <&zynqmp_firmware 8>;
        };
    };
    
    zynqmp_ipi1 {
        compatible = "xlnx,zynqmp-ipi-mailbox";
        interrupt-parent = <&gic>;
        interrupts = <0 29 4>;
        xlnx,ipi-id = <7>;
        #address-cells = <2>;
        #size-cells = <2>;
        ranges;

        ipi_mailbox_rpu0: mailbox@0xff990000 {
            reg = <0x00 0xff990600 0x00 0x20>,
                  <0x00 0xff990620 0x00 0x20>,
                  <0x00 0xff9900c0 0x00 0x20>,
                  <0x00 0xff9900e0 0x00 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 = <2>;
        #size-cells = <2>;
        ranges;

        ipi_mailbox_rpu1: mailbox@ff3f0b00 {
            reg = <0x00 0xff3f0b00 0x00 0x20>,
                  <0x00 0xff3f0b20 0x00 0x20>,
                  <0x00 0xff3f0940 0x00 0x20>,
                  <0x00 0xff3f0960 0x00 0x20>;
            reg-names = "local_request_region",
                    "local_response_region",
                    "remote_request_region",
                    "remote_response_region";
            #mbox-cells = <1>;
            xlnx,ipi-id = <2>;
        };
    };

なお、reserved-memory については既に元の dts に存在する場合があり、その時は既にある中に追記するなどマージしてください。

上記を構築するにあたって、OpenaAMPのWiki や、 UG1186 を参考にさせていただきましたが、これでいいのかどうか正直あまり自信はないです。

また、power-domain の番号についてはこちらのソースコードを参考にしました。

また参考元などで power-domainspower-domain の typo となっていると思われる箇所があったため修正しています。

下記のように dtc でコンパイルして、FAT領域にコピーすれば完了です。

dtc -I dts -O dtb system.dts -o user-override.dtb
sudo cp user-override.dtb /boot/firmware/

リブートして /sys/class/remoteproc/ の下にプロセッサが2つ見えていれば成功です。

$ ls -l /sys/class/remoteproc/
total 0
lrwxrwxrwx 1 root root 0 Nov  2 11:18 remoteproc0 -> ../../devices/platform/ff9a0000.zynqmp-rpu/ff9a0000.zynqmp-rpu:r5_0/remoteproc/remoteproc0
lrwxrwxrwx 1 root root 0 Nov  2 11:18 remoteproc1 -> ../../devices/platform/ff9a0000.zynqmp-rpu/ff9a0000.zynqmp-rpu:r5_1/remoteproc/remoteproc1
GitHubで編集を提案

Discussion