はじめに
Kria KV260 Vision AIスターターキットを今更ながら購入し、心を躍らせながらUbuntuを起動しつつVivadoからPLへ簡単なLチカ用回路を書き込んでいたところ、その後Ubuntuが正常に起動しなくなりました。(壊れたかと思った...)
症状は一定せず、あるときはSDカードのタイムアウト、あるときはLinuxのsoft lockup、さらに別の起動ではカーネル初期化直後数十ミリ秒で完全停止しました。
当初は以下を疑いました。
- Ubuntu 22.04イメージとBootファームウェアの不整合
(ファームウェアだけ「KV260 BootFW v1.07.bin」にしたら起動しなくなったように錯覚した) - SDカードの破損
(OSを書き換えた後SDタイムアウトが出たように見え、SDも壊れたかと思った) - KV260本体や電源の故障
(届いて数時間でこれだととても悲しい...)
しかし最終的には、Vivado Hardware ManagerでOpen targetした瞬間にLinux全体が停止することを再現できました。回避策は、LinuxのCPU idleを無効にするcpuidle.off=1をカーネル引数に入れる事でした。
いつか記事を書こうと考えつつなかなか書けておらず、いい機会と感じて投稿しました。
今後何か良いネタがあったら書いていこうと思います。
なお、本記事は問題解決から執筆までChatGPT5.6を多用しています。私としては下記合っているつもりではありますが、原因分析等誤りがあるかもしれずご了承ください。
使用環境
- ボード:Kria KV260 Vision AIスターターキット
- Bootファームウェア:K26-BootFW-01.02-06140626
AMD Kria Boot Firmware Update - SDイメージ: Ubuntu 22.04, Ubuntu 24.04
Install Ubuntu on AMD - 開発環境:Vivado 2025.2(Vitis 2025.2 Unified Installerからインストール)
最初の症状:SDカードのタイムアウト
Ubuntu 22.04 SDイメージを書き込み、LAN等の接続とパッケージアップデート等は問題なく動作しました。
また、ファームウェア更新もこのタイミングで行っていて、再起動は後回しにしていました。
私としてはFPGAに興味があるので、PL側でLチカコードを書いて書き込みました。
この時、書き込みのためにJ4 microUSBコネクタからUSBケーブル経由でJTAG接続を行います。これが後のトラブルを引き起こしていたとは想像もしていませんでした。
PLでのLチカに満足してUbuntu側に戻ってくるとフリーズしていて、不審に思いながらも電源投入したところ起動が途中で止まるようになっていました。
その時には、このようなエラーが発生していました。
SDのタイムアウト:
mmc1: Timeout waiting for hardware interrupt.
mmc1: Timeout waiting for hardware cmd interrupt.
SDHCIのレジスタダンプも出ていました:
mmc1: sdhci: ============ SDHCI REGISTER DUMP ===========
mmc1: sdhci: ADMA Err: 0x00000000
このログだけを見ると、SDカードやSDHCIコントローラの問題に見えます。
ここでフリーズ後の再起動でのイメージ破損やSD故障を疑い、
- SDカードイメージの再書込みとベリファイ(SD故障ならエラーで止まると想像)
- 別のSDカードへの同一イメージ書込み
- Ubuntu 22.04から24.04への変更
を試しました。
しかし、別のSDカードでも起動できず、またU-Bootは約70 MBのimage.fitを正常に読み込み、FIT内のカーネル、ramdisk、Device Treeのハッシュ検証にも成功していました。
Loading image.fit
67433124 bytes read in 4878 ms (13.2 MiB/s)
Verifying Hash Integrity ... sha1+ OK
Linuxのsoft lockup
Ubuntu 22.04では、MMCエラーとは別にCPUのsoft lockupも発生していました
watchdog: BUG: soft lockup
スタックトレースには、繰り返し以下が現れていました。
smp_call_function_many_cond
kick_all_cpus_sync
flush_icache_range
bpf_int_jit_compile
smp_call_function_many_cond()は、複数CPU間の要求待ち関連の処理のようです。
そのため、単なるSDカード障害ではなく、他CPUが割込みに応答していないといった可能性も出てきました。
(→もし本当にそうなら、ファームウェアの相性、ファームウェア破損、ボードの故障等があるかと思います。)
keep_bootconとinitcall_debugで停止位置を調べる
別の起動では、Linuxが以下で停止しました。
printk: bootconsole [cdns0] disabled
これはearly consoleから通常のconsoleへ切り替わる位置とのことで、本当にそこで停止したのか、単にUART出力が消えただけなのか判別できないとのことでした。
そこでU-Bootから手動起動し、以下のカーネル引数を追加しました。
keep_bootcon ignore_loglevel initcall_debug
実際には下記のような引数になりました。
setenv bootargs '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 keep_bootcon ignore_loglevel initcall_debug'
これによりearly consoleが維持され、停止直前までログが得られました。
calling init_osnoise_tracer+0x0/0x170 @ 1
ログがinit_osnoise_tracer()の呼出し後で止まったことから、その初期化処理中、または直後のCPU間同期処理で停止した可能性があります。スタックトレースでもflush_icache_range()やsmp_call_function_many_cond()が現れていたため、複数CPU間の同期処理が関係しているという仮説が強くなりそうです。
決定的だったmaxcpus=1
カーネル引数に以下を追加したところUbuntu 24.04が正常に起動しました。
maxcpus=1
つまり、
- SDカードからカーネルを読める
- rootfsをマウントできる
- Ubuntuのユーザー空間まで到達できる
- CPUを1コアに制限すれば動く
ということになります。
少なくともこのSDカードとUbuntu 24.04の組合せでは、カーネル読込み、rootfsのマウント、ユーザー空間の起動まで成功しました。
そのため、SDカードやファイルシステムが主原因である可能性は大きく下がりました。一方で、通常の4コア起動時に止まることから、問題の中心はSMP、IPIなど深い部分にある可能性が残りました。(そして私の理解の範囲外でかなり苦しい部分でもあります...)
Vivado Hardware Managerとの相関に気付く
トラブルが始まったタイミングを振り返ると、ちょうどVivadoを立ち上げ、Hardware ManagerからPLへLチカ用イメージを書き込んだ直後でした。また、KV260の電源投入時にTera Termが一度シリアルデバイスから切断される(アクセス拒否)点も気になりました。
そこでJ4 USBを外して起動すると、カーネル引数を何も追加しなくても正常起動するではありませんか!
J4はUARTとJTAGの複合デバイスへつながっています。USB接続そのものが原因なのか、Vivado/hw_serverによるJTAG操作が原因なのかを分ける必要がありました。以下の順番で確認してみました。
| 条件 | 結果 |
|---|---|
| J4 USB接続のみ | 正常 |
| Tera Termのみ起動 | 正常 |
| 完全電源断後、通常起動 | 正常 |
| Vivado起動、Hardware Manager未起動 | 正常 |
| Hardware Manager起動、ターゲット未接続 | 正常 |
Open target実行 |
Linux停止 |
| PL書込み | 戻らず |
Linux側ではSSH上で次のループを実行し、同時に別PCからpingを送って監視しました。
while true; do
echo ok
date
sleep 1
done
Open targetを実行した瞬間に、
- シェルのループ出力停止
- ping応答停止
- UARTコンソール応答停止
- Heartbeat LEDが停止 → その後Heartbeatが不安定に点滅
という状態になり、PL側に接続しLチカ回路で駆動される無関係なLEDだけが悲しそうに点滅していました。
さらにLinuxログには、SDカードアクセスでタイムアウトが出ました。
mmc1: Timeout waiting for hardware interrupt.
JTAG接続を契機にCPU間同期または割込み処理が停止し、SDHCIの割込みを処理できなくなった結果、MMC timeoutとして表面化した可能性があります。
原因についての結論
※この部分裏取り出来ていない部分ではあります
今回の直接的なトリガーは、Vivado Hardware ManagerのOpen targetでした。
より具体的には、以下の組合せで問題が発生していた可能性が高いようです。
- Linuxが複数のA53コアを使用
- 使用していないコアがCPU idle状態へ移行
- Vivado Hardware ManagerがJTAGターゲットを開く
- JTAGデバッグアクセスとCPU低電力状態が競合
- 一部CPUがIPIやキャッシュ同期要求に応答できなくなる
- Linux全体がCPU間同期待ちで停止
- SPI・SDHCI等も割込み待ちでタイムアウトする
内部でどのデバッグレジスタや低電力遷移が競合したかまでは確認できていないものの、
-
maxcpus=1なら起動する - 複数CPU時は
smp_call_function_many_cond()で止まる - J4接続だけ(jtag使用なし)なら問題ない
-
Open targetで再現する - Vivado/XSDB/hw_server終了後の再起動は正常
という観測結果から、上記のような形になりそうでした。
AMDサポートにも「Ubuntu 22.04 hangs when trying to connect to KV260 via Vivado Hardware Manager」という同種の事例があります。
解決方法:cpuidle.off=1
PYNQ community:cpuidle.off=1による回避例
こちらの方法を採用します。
回避策として、カーネル引数へ以下を追加します。
cpuidle.off=1
これによりLinuxのcpuidleサブシステムが無効化され、cpuidleが管理するアイドル状態への遷移が行われなくなります。
アイドル時の消費電力や温度が上がる可能性があり、一般的な運用で無条件に使用する設定ではありませんが、Vivado Hardware Managerを使用する開発環境では現実的な回避策でしょう。
下記間に合わせで対応した手順を備考として載せます。
私はやっていませんが、AMD公式では、Kria Ubuntuのカーネル引数は/etc/default/flash-kernelに設定し、flash-kernelで反映する方法が案内されているようです。Getting Started with Certified Ubuntu 22.04 LTS for Xilinx Devices
非公式な手順 ※リスクがあるかもしれません
KV260の/boot/firmware内のboot.scr.uimgから、先頭72バイトを除去してスクリプト本文を取り出し、bootargs生成部分へ追記しました。
cp boot.scr.uimg boot.scr.uimg.bak
tail -c +73 boot.scr.uimg > boot.scr
nano boot.scr
変更前:
if test "${card1_name}" = "SCK-KR-G" || test "${card1_name}" = "SCK-KV-G" || test "${card1_name}" = "SCK-KD-G"; then
setenv bootargs "${bootargs} earlycon console=ttyPS1,115200 console=tty1 clk_ignore_unused uio_pdrv_genirq.of_id=generic-uio xilinx_tsn_ep.st_pcp=4"
fi
変更後:
if test "${card1_name}" = "SCK-KR-G" || test "${card1_name}" = "SCK-KV-G" || test "${card1_name}" = "SCK-KD-G"; then
setenv bootargs "${bootargs} earlycon console=ttyPS1,115200 console=tty1 clk_ignore_unused uio_pdrv_genirq.of_id=generic-uio xilinx_tsn_ep.st_pcp=4 cpuidle.off=1"
fi
なお、/boot/firmwareは権限上root以外はlsすら出来ないため、私はsudo suしてから入り編集しました。
編集後、mkimageで再生成します。
mkimage -C none -A arm -T script -d boot.scr boot.scr.uimg.new
生成したファイルをboot.scr.uimgへ書き戻します。
上記どちらかの方法でカーネル引数を追加し、起動後、次で反映を確認します。
cat /proc/cmdline
出力に以下が含まれていれば反映されています。
cpuidle.off=1
設定後は4コアを有効にした通常構成のまま、Vivado Hardware Managerで
Open Targetを実行してもLinuxは停止せず、無事PLの書込みまで完了しました。