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 Etcher や Win32 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.mount
を追加
sudo mkdir /mnt/nfs
sudo nano /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
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
のように開いて、私の場合下記のようにしました。
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-domains が power-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
Discussion