Raspberry Pi で簡単にネットワークブートができるようになったよ,という話

Raspberry Pi Advent Calendar 2017 2日目です.

結論

SDカードにbootcode.binというファイルを置いておくだけで,全バージョンのRaspberry Piで

  • ネットワークブート
  • USBストレージブート

ができます.

経緯

まずRaspberry Piのブートは,おおまかには3段階からなります.

  • 1段目
    Raspberry PiのSoCにはROMが載っており,ここにファームウェアが書き込まれています.
    Raspberry Piに電源が投入されると,まずこのROM内のファームウェアがメモリに読み込まれます.
    読み込まれたコードはGPUにあるVPUというプロセッサによって実行されます.
  • 2段目
    ROM内のファームウェアによってSDカードが検出され,
    SDカード内の設定ファイル (config.txtcmdline.txt) と,
    ファームウェアがメモリにロードされます.
    このコードもVPUによって実行されます.
  • 3段目
    SDカード内のファームウェアがSDカード内のLinuxカーネル等を検出し,メモリにロードします.
    また,同時にCPUの初期化も行われ,LinuxカーネルはCPUによって実行されます.



「Raspberry Piにネットワークブートの機能を追加したい」となったときに初めに考えられたのは,3段目でネットワークブートを行う方法です.
この方法は,例えばLinuxカーネルのNFS root機能を使うことで実現されます.
NFS rootはカーネルの引数に設定を追加するだけなので,比較的容易に行えますが,CPUを起動するためのファームウェアとLinuxカーネルはSDカードに入れなければなりません.
これだと,ファームウェアとカーネルをアップデートするたびにSDカードへの書き込みが発生するので,SDカードの寿命が縮んでしまいます.
U-Bootを使う方法もありますが,結局SDカード上にファームウェアが必要なので,アップデートによるSDカードへの負荷は避けられません.



そこで考えられたのが,2段目でネットワークブートする方法です.
元々のRaspberry Piのファームウェアにはネットワークブート機能がなく,かつRaspberry Piのファームウェアはクローズドソースなので,2段目でネットワークブートするためには,別途VPU向けのファームウェアを書かなければなりません.
VPUの命令セットは非公開なのですが,実は有志によって解析されており,これを基にオープンソース版のファームウェアが開発されています
こちらのファームウェアを使うことでネットワークブートすることは可能なようですが,公式のファームウェアの一部の機能しか対応していなかったり,Raspberry Piの一部のバージョンに対応していなかったりするなど,動作が不安定なところがあるようです.
また,この方法にも,結局アップデート時にSDカード上のファームウェアを書き換える必要があるという欠点があります.



そこで考えられたのが,1段目でネットワークブートする方法です.
実は,Raspberry Pi 3からROM内のファームウェアに変更が施されており,SDカード無しでネットワークブートやUSBストレージブートなどができるようになっています.
(参考: Boot flow - Raspberry Pi Documentation)
ROMの内容を変更するのはRaspberry PiおよびそのSoCを開発する組織にしかできないので,ROMのファームウェアは中の人であるGordon Hollingworthを中心としたエンジニアによって開発されたようです.
この方法はSDカードさえ不要になるので画期的に思われましたが,ROM内のファームウェアにバグがあり,LAN内で他のマシンがbroadcast addressにpingし続けないとRaspberry Piがうまくネットワークを認識できないなど,ネットワークブートできない環境がありました.
OTP (one-time programmable) メモリのビットを立ててROMのファームウェアの挙動を制御するなどの対策が取られましたが,ROMの内容は後から変更できないため,バグを完全に取り除くことはできなかったようです.



ここでどうしようもなくなったので,公式のファームウェア (2段目) にネットワークブート機能が追加されました.
Raspberry Pi 3のROMに書いたコードを,バグを修正して移植したようです.

Raspberry Piを通常の方法で起動させる場合,SDカードには bootcode.binfixup.datstart.elfconfig.txtkernel.img などのファイルが必要です.
しかし,ネットワークブート機能は bootcode.bin に実装されたので,SDカードにbootcode.bin だけを入れれば,ネットワークブートができるようになります.
この際,残りのファイルは bootcode.bin がTFTPサーバ経由で持ってきてくれます.
さらに,bootcode.bin はアーキテクチャ特有の処理しかしないので,動くバージョンがあれば,基本的にそれを使い続けて大丈夫です(多分).
よって,bootcode.bin 以外のファームウェアや設定ファイルやLinuxカーネル,rootfsなどは全てSDカードでなくサーバ側に置いておくだけで良い のです.
これで,全バージョンのRaspberry PiでネットワークブートとUSBストレージブートができるようになり,アップデートによってSDカードに負荷がかかることもなくなりました.



サーバ側の設定などは
Network Boot Your Raspberry Pi - Raspberry Pi Documentation
を参考にしてください.

最後に

私は単なるアルバイトで雇用に関わる権限はありませんが紹介だけさせていただきます.
Idein Inc.では一緒に働ける人を常時募集しています

1473711706
B2 at Univ. of Tsukuba. Engineer at Idein Inc.