目次
背景
- 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 を外した引数で、カーネルを直接起動してみた。
| |
- これでも黒画面のまま
- ただし、通常の
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 側で何も認識されなかった。原因はケーブル(充電専用)で、データ通信できるケーブルに替えたら認識された。
ログを見る
| |
/dev/ttyACM*はroot:dialoutの660なので、グループに入っていないと開けない- ログは
/tmp以外に保存する(PC を再起動したら消えてしまった)
ログでわかったこと
通常起動のログに、以下が出ていた。
| |
- 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 をマウントして調べた。
| |
裏でアップデートが走っていた
dpkg のログを見ると、以下がわかった。
- 当日 09:43 に、ソフトウェア更新(
packagekit update-packages)が自動で動いていた - L4T が 36.5.0 から 36.5.2 に更新されている途中だった
nvidia-l4t-kernel:5.15.185 → 5.15.199nvidia-l4t-initrd、nvidia-l4t-bootloaderなど L4T パッケージ一式
- その途中で、
cma=2048Mを反映するために再起動していた - 304個のパッケージが「展開済み・未設定」(unpacked)のまま止まっていた
/etc/nv-update-initrd/list.d/に*.dpkg-newが残っていた
initrd が空っぽだった
本来は、パッケージの設定の工程で nv-update-initrd が実行され、initrd にカーネルモジュールが組み込まれる。これが実行されていなかった。
| |
- 新しい
/boot/initrdには、カーネルモジュールが1つも入っていなかった - そのため、新しいカーネルは
pcie-tegra194.ko、phy-tegra194-p2u.ko、nvme.koを読み込めない - 結果として NVMe が見えず、rootfs をマウントできなかった
cma=2048M は原因ではなく、アップデート後はじめての再起動のきっかけになっただけだった。
もう一つの問題:UEFI が Recovery で起動し続ける
initrd を直しても、UEFI が Recovery のカーネルを選び続ける状態になっていた。UEFI 変数を見ると、以下の2つが原因だった。
| UEFI 変数 | 値 | 意味 |
|---|---|---|
L4TDefaultBootMode | 3 | Recovery Partition(調査中に自分で設定したもの) |
RootfsStatusSlotA | 0xFF | Unbootable(通常起動に3回失敗したため、UEFI が自動で設定したもの) |
- どちらか一方でもこの値だと、L4TLauncher は必ず Recovery のカーネルで起動する
- edk2-nvidia の
L4TLauncher.cとL4TRootfsValidation.cのソースで確認した
復旧手順
1. initrd を作り直す
Recovery 環境の root シェルで、rootfs に chroot して nv-update-initrd を実行する。
| |
念のため、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. 止まっていたアップデートを完了させる
| |
エラーなく完了し、再起動しても正常に起動することを確認した。
ハマりどころ
調査中に引っかかったことを並べておく。
- シリアルでコマンドを送ったら、UEFI の設定画面に入力されてしまった
- Jetson が UEFI メニューを出しているときは、キー操作として受け取られる
- 送る前に、ログで今どの画面にいるかを確かめる
- Reset ボタンを3回押しても Recovery に切り替わらなかった
- Reset での再起動は、失敗回数として数えられないようだった
- 確実に Recovery で起動したいときは、UEFI で L4T Boot Mode を Recovery Partition にする
- initrd で「Press [ENTER] to start bash」と出ても操作できなかった
- bash は最後に指定された
console=tty0(HDMI)側で起動する - 表示ドライバが読み込まれていないと画面は真っ黒で、シリアルからも操作できない
- bash は最後に指定された
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)の意味。
| 変数 | 値の意味 |
|---|---|
L4TDefaultBootMode | 0 = GRUB、1 = ExtLinux、2 = Kernel Partition、3 = Recovery、0xFF = Application Default |
RootfsStatusSlotA / RootfsStatusSlotB | 0 = 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つ
