Featured image of post Jetson AGX Orinが再起動後に起動しなくなった問題

Jetson AGX Orinが再起動後に起動しなくなった問題

目次

背景

  • Jetson AGX Orin(rootfs は NVMe、UEFI は 36.5.0)で、CUDA / cuBLAS の初期化失敗を調べていた
  • 調べると CmaFree が約 1MB しかなく、CMA(物理的に連続したメモリを確保するための領域)が枯渇していた
  • そこで /boot/extlinux/extlinux.conf の APPEND 行末に cma=2048M を追加して再起動した
  • すると、Linux が起動しなくなった
  • 最初は cma=2048M が原因だと思っていたが、実際はまったく別の原因だった
  • 原因にたどり着くまでの流れと、復旧手順を残しておく

症状

再起動後の挙動は以下の通り。

  • NVIDIA ロゴと UEFI のメニューまでは出る
  • 通常起動に進むと、画面が黒いまま再起動を繰り返す
  • UEFI Shell から /boot/Image を直接起動しても、黒画面のまま
  • しばらくすると L4TLauncher: Attempting Recovery Boot と出て、Recovery 用のカーネルでしか起動しなくなる

UEFI Shell からは、NVMe のパーティションも extlinux.conf も読めていた。つまり、ストレージは生きていて、UEFI も壊れていない状態。

最初の仮説:cma=2048M が悪い

直前に変えたのは cma=2048M だけなので、まずはこれを疑った。

UEFI Shell から直そうとした

  • UEFI Shell の type fs2:\boot\extlinux\extlinux.conf で、cma=2048M が残っていることは確認できた
  • しかし、UEFI の ext4 ドライバは読み取り専用なので、edit も cp も失敗する
  • UEFI からは rootfs を直せない

UEFI Shell から cma なしで直接起動した

cma=2048M を外した引数で、カーネルを直接起動してみた。

1
\boot\Image initrd=\boot\initrd root=/dev/nvme0n1p1 rw rootwait rootfstype=ext4 console=tty0 console=ttyTCU0,115200 efi=runtime
  • これでも黒画面のまま
  • ただし、通常の extlinux.conf では先頭に ${cbootargs} が入っていて、Shell からはこれを再現しきれない
  • なので「cma を外してもダメ」とは言い切れず、この時点では切り分けられなかった

画面が黒いままだと、何が起きているのかまったくわからない。ここで、シリアルでログを見ることにした。

Debug UART で起動ログを取る

接続

  • PC と Jetson の J26(micro-B、Debug UART) を USB ケーブルでつなぐ
  • Force Recovery ボタンは押さない
  • 正しく認識されると、lsusb に 0955:7045 NVIDIA Tegra On-Platform Operator が出て、/dev/ttyACM0〜3 ができる

最初は PC 側で何も認識されなかった。原因はケーブル(充電専用)で、データ通信できるケーブルに替えたら認識された。

ログを見る

1
2
sudo usermod -aG dialout $USER   # ログインし直すと sudo なしで開ける
picocom -b 115200 /dev/ttyACM0
  • /dev/ttyACM* は root:dialout の 660 なので、グループに入っていないと開けない
  • ログは /tmp 以外に保存する(PC を再起動したら消えてしまった)

ログでわかったこと

通常起動のログに、以下が出ていた。

1
2
3
[    2.328236] Root device found: nvme0n1p1
[   12.875707] ERROR: nvme0n1p1 not found
[   33.758955] VDD_3V3_PCIE: disabling
  • initrd が rootfs の NVMe を見つけられていない
  • VDD_3V3_PCIE: disabling は、PCIe のドライバが動いていないため、使われていない PCIe の電源が自動で切られたという意味
  • つまり、PCIe と NVMe のドライバが読み込まれていない
  • cma= はメモリの予約量を変えるだけなので、この症状とはつながらない
  • さらに、Linux version が以前の 5.15.185 ではなく 5.15.199 になっていた

いつの間にかカーネルが新しくなっている。ここで原因の見当がついた。

Recovery 環境から rootfs を調べる

Recovery 用のカーネル(5.15.185)では NVMe が見えるので、そこから rootfs をマウントして調べた。

1
mount /dev/nvme0n1p1 /mnt/r

裏でアップデートが走っていた

dpkg のログを見ると、以下がわかった。

  • 当日 09:43 に、ソフトウェア更新(packagekit update-packages)が自動で動いていた
  • L4T が 36.5.0 から 36.5.2 に更新されている途中だった
    • nvidia-l4t-kernel:5.15.185 → 5.15.199
    • nvidia-l4t-initrd、nvidia-l4t-bootloader など L4T パッケージ一式
  • その途中で、cma=2048M を反映するために再起動していた
  • 304個のパッケージが「展開済み・未設定」(unpacked)のまま止まっていた
  • /etc/nv-update-initrd/list.d/ に *.dpkg-new が残っていた

initrd が空っぽだった

本来は、パッケージの設定の工程で nv-update-initrd が実行され、initrd にカーネルモジュールが組み込まれる。これが実行されていなかった。

1
2
gzip -dc /mnt/r/boot/initrd | cpio -t | grep -c lib/modules
# 0
  • 新しい /boot/initrd には、カーネルモジュールが1つも入っていなかった
  • そのため、新しいカーネルは pcie-tegra194.ko、phy-tegra194-p2u.ko、nvme.ko を読み込めない
  • 結果として NVMe が見えず、rootfs をマウントできなかった

cma=2048M は原因ではなく、アップデート後はじめての再起動のきっかけになっただけだった。

もう一つの問題:UEFI が Recovery で起動し続ける

initrd を直しても、UEFI が Recovery のカーネルを選び続ける状態になっていた。UEFI 変数を見ると、以下の2つが原因だった。

UEFI 変数値意味
L4TDefaultBootMode3Recovery Partition(調査中に自分で設定したもの)
RootfsStatusSlotA0xFFUnbootable(通常起動に3回失敗したため、UEFI が自動で設定したもの)
  • どちらか一方でもこの値だと、L4TLauncher は必ず Recovery のカーネルで起動する
  • edk2-nvidia の L4TLauncher.c と L4TRootfsValidation.c のソースで確認した

復旧手順

1. initrd を作り直す

Recovery 環境の root シェルで、rootfs に chroot して nv-update-initrd を実行する。

1
2
3
4
5
6
mount /dev/nvme0n1p1 /mnt/r
for d in proc sys dev; do mount --bind /$d /mnt/r/$d; done
cp -a /mnt/r/boot/initrd /mnt/r/boot/initrd.bak-before-nvupdate
chroot /mnt/r /usr/sbin/nv-update-initrd
for d in dev sys proc; do umount /mnt/r/$d; done
sync; umount /mnt/r

念のため、extlinux.conf から cma=2048M も外しておいた(バックアップは extlinux.conf.bak-before-cma)。

2. UEFI の設定を戻す

起動時に ESC を押して、Device Manager → NVIDIA Configuration → L4T Configuration を開く。

  • L4T Boot Mode を ExtLinux にする
  • OS chain A status を Normal にする

L4T Boot Mode の Application Default は、edk2-nvidia のソースではいったん GRUB 扱いになる。確実に extlinux.conf を使いたいなら ExtLinux を選ぶ。

ここまでで、Ubuntu 22.04.5 LTS ubuntu ttyTCU0 のログインプロンプトまで起動した。

3. 止まっていたアップデートを完了させる

1
2
3
sudo dpkg --configure -a
sudo apt -f install
dpkg -l | grep -c -E '^(iU|iF)'   # 0 になれば完了

エラーなく完了し、再起動しても正常に起動することを確認した。

ハマりどころ

調査中に引っかかったことを並べておく。

  • シリアルでコマンドを送ったら、UEFI の設定画面に入力されてしまった
    • Jetson が UEFI メニューを出しているときは、キー操作として受け取られる
    • 送る前に、ログで今どの画面にいるかを確かめる
  • Reset ボタンを3回押しても Recovery に切り替わらなかった
    • Reset での再起動は、失敗回数として数えられないようだった
    • 確実に Recovery で起動したいときは、UEFI で L4T Boot Mode を Recovery Partition にする
  • initrd で「Press [ENTER] to start bash」と出ても操作できなかった
    • bash は最後に指定された console=tty0(HDMI)側で起動する
    • 表示ドライバが読み込まれていないと画面は真っ黒で、シリアルからも操作できない
  • extlinux.conf に FDT 行(DTB の指定)を足しても直らなかった
    • 原因は DTB ではなく initrd だった
  • Recovery 環境には od、hexdump がない
    • chroot、cpio、gzip はある
    • UEFI 変数は mount -t efivarfs none /sys/firmware/efi/efivars で読める
    • efivarfs のファイルは、先頭 4 バイトが属性で、その後に値が続く(例:07 00 00 00 | 03 00 00 00 は値 3)

参考として、主な UEFI 変数(GUID 781e084c-a330-417c-b678-38e696380cb9)の意味。

変数値の意味
L4TDefaultBootMode0 = GRUB、1 = ExtLinux、2 = Kernel Partition、3 = Recovery、0xFF = Application Default
RootfsStatusSlotA / RootfsStatusSlotB0 = Normal、0xFF = Unbootable
RootfsRetryCountMax何回失敗したら Unbootable にするか(今回は 3)

再発防止

同じことを起こさないために、以下をやることにした。

  • L4T の自動アップデートを止める
    • sudo apt-mark hold 'nvidia-l4t-*'
    • カーネル・initrd・ブートローダの更新は、時間のあるときに手動で行う
  • 再起動の前に、アップデート中でないか確認する
    • pgrep -a -f 'apt|dpkg|packagekit|unattended'
    • dpkg -l | grep -c -E '^(iU|iF)' が 0 以外なら、先に sudo dpkg --configure -a
  • 起動に関わる設定は、1回に1つだけ変える
  • CMA を増やすときは、cma=1024M など控えめな値から試す
  • extlinux.conf に、cma= なしのバックアップ用の起動エントリを用意しておく
  • Debug UART(J26)をすぐ使えるようにしておく
    • データ通信できる micro-B ケーブル
    • dialout グループへの追加

残っていること

  • OS は 36.5.2 になったが、ファームウェア(ブートローダ)は 36.5.0 のまま
    • 今のところ起動も動作も正常
    • Capsule Update でのファームウェア更新は後日行う
  • dpkg --configure -a 後の最初の再起動で、Unhandled Exception in EL3.(SError)が1回出た
    • 電源を入れ直したら正常に起動した
    • 何度も起きるようなら、ファームウェアやハードウェアを疑う
  • 元々の問題(CMA 不足と cuBLAS の初期化失敗)の調査はこれから

まとめ

  • 「最後に変えた設定が原因」とは限らない。今回は、裏で動いていた自動アップデートを再起動で中断したことが原因だった
  • 黒画面で何もわからないときは、まず Debug UART でログを取る。ログを見た時点で原因の見当がついた
  • Linux version が変わっているのに nvme0n1p1 not found が出たら、initrd にモジュールが入っていないことを疑う
  • 復旧は、Recovery 環境から chroot して nv-update-initrd、UEFI の Boot Mode と Rootfs Status を戻す、アップデートを完了させる、の3つ
Built with Hugo
テーマ Stack は Jimmy によって設計されています。