関連記事
- Raspberry Pi 3B (U-Boot)の場合は こちら
- Raspberry Pi 4Bの場合は こちら
概要
Raspberry Pi 3 Model BからLinuxカーネル (Raspbian)をネットワークブートするための環境を構築する方法を解説する。
Raspberry Pi 3Bは、SDカードを挿入せずにネットワーク上にあるネットワークサーバからブートイメージとルートファイルシステムを取得する。
また、ネットワークブート用のサーバとして、Ubuntu 18.04 LTS上にdnsmasqとnfs-kernel-serverをインストールした。
はじめに
組込みシステムの開発段階やデバッグ段階では、ネットワーク経由でシステムを起動(ネットワークブート)できることが理想的である。
ネットワークブートができる環境が構築されていれば、組込みシステムのファームウェアに再書き込みせずにデータを共有することができる。
Raspberry Pi はARMプロセッサを搭載したシングルボードコンピュータの一つで、手軽に入手できる点や世の中に情報が多い点から組込みシステムの入門として用いられることが多い。
Raspberry Pi 3Bについて
Raspberry Pi 3 Model B(Raspberry Pi 3B)は複数のブートモードがある。下記は、Raspberry Pi 3Bの起動シーケンスを示している。
Raspberry Pi 3B では、電源投入されるとOne-Time Programmable (OTP) メモリをロードする。
OTPメモリにはブートモードを決定するフラグが保存されており、Raspberry Pi 3B のGPUはこのフラグを基にブートを試みる。
各ブートモードは、ブートに必要なファイル (ブートイメージ) をそれぞれの方法でメモリにロードする。
Raspberry Pi 3B のブートイメージは下記のファイルがある。
状態 | 概要 |
---|---|
config.txt | システム構成パラメータ |
start.elf | 一般的なRaspberry Piのファームウェア |
fixup.dat | start.elfのリンカファイル |
bcm2710-rpi-3-b.dtb | ハードウェアの構成情報(デバイスツリーファイル) |
cmdline.txt | カーネルコマンドライン |
kernel7.img | カーネルイメージ |
bootcode.bin | ブートローダ |
Raspberry Pi 3Bのネットワークブートでは、TFTPでブートイメージを取得する。 ネットワークブートを用いたRaspberry Pi 3Bの起動シーケンスを下記に示す。
- Raspberry Pi 3BではオンボードのEthernetドライバの初期化をした後、LAN内にDHCPリクエストをブロードキャストする。
- DHCPリクエストを受け取ったネットワークブートサーバは、TFTPサーバのIPアドレスを送信する。
- Raspberry Pi 3Bは、TFTPサーバのIPアドレスからブートイメージを取得し、カーネルをブートする。
しかし、Raspberry Pi 3Bのネットワークブートには幾つかのバグが報告されている。
Known problems
このため、Raspberry Pi 3Bでネットワークブートを試している人は少ない。*1 そこで本記事では、Raspberry Pi 3BからRaspbianをネットワークブートするための環境を構築する方法を紹介する。
実行環境
実験環境として、セグメントが二つに分かれている下記のネットワーク構成のものを使用する。
ホームセグメントは、一般的なPCや家電製品などが接続されており家庭用ルータによって管理されている。 開発用セグメントは、Raspberry Pi 3B が接続されておりネットワークブートサーバによって管理されている。
本運用では、ホームセグメントにあるクライアントPC (Windows 10 Home) からネットワークブートサーバ(Ubuntu 18.04 LTS) にSSH経由でアクセスする。 また、ネットワークブートサーバとRaspberry Pi 3Bはシリアル接続されている。
ネットワークブートサーバの詳細は下記のとおりである。
名前 | 詳細 |
---|---|
OS | Ubuntu 18.04 LTS |
Kernel | 5.3.0-40-generic |
NIC (ホームセグメント側) | eth0 |
NIC (開発側セグメント) | eth1 |
IPアドレス (eth0) | 192.168.1.11 |
IPアドレス (eth1) | 172.16.1.1 |
ホスト名 | server |
Raspberry Pi 3Bのブートイメージ格納予定 | /srv/boot |
Raspberry Pi 3Bのルートファイルシステム格納予定 | /srv/rootfs |
シリアルデバイスファイル | /dev/ttyUSB0 |
シリアルポートのボーレート | 115200 |
また、使用するRaspberry Pi 3Bの詳細は下記のとおりである。
名前 | 詳細 |
---|---|
ファームウェア | 4.19.97-v7+ |
NIC | eth0 |
IPアドレス | 172.16.1.2 (DHCP) |
ホスト名 | raspberry |
ストレージ | なし |
Raspberry Pi 3Bの初期セットアップ
本記事が目標とするネットワークブートの構成は下記のとおりである。
Raspberry Pi 3BのUSBブートフラグをONにし、ネットワークブートで起動できるように設定をする。
- 注意: USBブートフラグをONにするために、Raspbianの入ったSDカードが必要になる。
ネットワークブートサーバには、DockerコンテナとしてDHCP/TFTPサーバを構築しブートイメージを格納しておく。
また、ホストにNFSサーバを構築しルートファイルシステムを格納しておく。
今回は、Raspbian Buster Liteのブートイメージとルートファイルシステムを利用する。
この状態で、SDカードからRaspbianを起動する
現在のブートフラグを確認する (OPT bitより、Bit29がネットワークブートのフラグとなっている)
pi@raspberry:~$ vcgencmd otp_dump | grep 17: > 17:1020000a # 現在はOFFになっている
/boot/config.txtを修正する
pi@raspberry:~$ echo "program_usb_boot_mode=1" | sudo tee -a /boot/config.txt
再起動する
pi@raspberry:~$ sudo reboot
再度、ブートフラグを確認する
pi@raspberry:~$ vcgencmd otp_dump | grep 17: > 17:3020000a # 現在はONになっている
上記の設定により、OTPメモリにUSBブートフラグが設定された。
これ以降ネットワークブートが可能になったので、Raspberry Pi 3BからSDカードを抜いておく。
ネットワークブートサーバの設定
ネットワークブートサーバの設定は、「ブートイメージとルートファイルシステムの取得」と「DHCP/TFTPサーバの構築」、「NFSサーバの構築」の3ステップ必要になる。
ブートイメージとルートファイルシステムの取得
Raspbianのイメージを取得する
user@server:~$ wget https://downloads.raspberrypi.org/raspbian_lite/images/raspbian_lite-2020-02-14/2020-02-13-raspbian-buster-lite.zip user@server:~$ unzip 2020-02-13-raspbian-buster-lite.zip
取得したディスクイメージをマウントする
user@server:~$ sudo kpartx -a 2020-02-13-raspbian-buster-lite.img user@server:~$ sudo mount /dev/mapper/loop0p1 /mnt/boot user@server:~$ sudo mount /dev/mapper/loop0p2 /mnt/rootfs
ディスクイメージをTFTPサーバとNFSサーバの公開先ディレクトリにコピーする
user@server:~$ sudo rsync -av /mnt/boot /srv/tftpboot/ user@server:~$ sudo rsync -av /mnt/rootfs /srv/rootfs
ディスクイメージをアンマウントする
user@server:~$ sudo umount /mnt/rootfs user@server:~$ sudo umount /mnt/boot user@server:~$ sudo kpartx -d 2020-02-13-raspbian-buster-lite.img
カーネルコマンドラインを修正し、NFSルートとシリアルコンソールを設定する
user@server:~$ sudo mv /srv/tftpboot/cmdline.txt /srv/tftpboot/cmdline.txt.old user@server:~$ echo "console=serial0,115200 console=tty1 root=/dev/nfs nfsroot=172.16.1.1:/srv/rootfs,vers=3,proto=tcp rw ip=dhcp rootwait elevator=deadline" | sudo tee /srv/tftpboot/cmdline.txt
UARTを有効にする
user@server:~$ echo "enable_uart=1" | sudo tee -a /srv/tftpboot/config.txt
Raspberry Pi 3B側のファイルシステムテーブルを修正する
user@server:~$ sudo mv /srv/rootfs/etc/fstab /srv/rootfs/etc/fstab.old user@server:~$ echo "proc /proc proc defaults 0 0" | sudo tee /srv/rootfs/etc/fstab
DHCP/TFTPサーバの構築
著者が使用しているDockerイメージはGitHubにて公開しているので、構築が手間な方はそちらを使用してほしい。
ベースとして使用するAlpine Linuxのイメージを取得する
user@server:~$ docker pull alpine:3.11.3
Dockerコンテナを起動させる
user@server:~$ docker run --privileged --net=host -v /srv/tftpboot:/srv -it alpine:3.11.3 /bin/sh
dnsmasqをインストールする
/ # apk update / # apk add dnsmasq
dnsmasqの設定ファイルを修正する (修正箇所は下記のとおり)
@@ -10 +10 @@ -#port=5353 +port=0 @@ -21 +21 @@ -#bogus-priv +bogus-priv @@ -106 +106 @@ -#interface= +interface=eth1 @@ -157 +157 @@ -#dhcp-range=192.168.0.50,192.168.0.150,12h +dhcp-range=172.16.1.2, 172.16.1.65, 12h @@ -477 +477 @@ -#pxe-service=x86PC, "Boot from local disk" +pxe-service=0, "Raspberry Pi Boot" @@ -499 +499 @@ -#enable-tftp +enable-tftp @@ -502 +502 @@ -#tftp-root=/var/ftpd +tftp-root=/srv @@ -664 +664 @@ -#log-dhcp +log-dhcp
dnsmasqを起動させる
/ # dnsmasq
dockerコンテナからデタッチする
/ # <Ctrl-p> <Ctrl-q>
NFSサーバの構築
NFSサーバもDockerコンテナとして管理しても良いが、ディレクトリ共有のオーバーヘッドを懸念して、ホストに直接立てることにした。
NFSサーバのnfs-kernel-serverをインストールする
user@server:~$ sudo apt install nfs-kernel-server
-
user@server:~$ echo "/srv/rootfs 172.16.1.0/255.255.255.0(rw,sync,no_root_squash,no_subtree_check)" | sudo tee -a /etc/exports user@server:~$ sudo exportfs -ra
実行結果
minicom経由でアクセスする。
user@server:~$ sudo minicom /dev/ttyUSB0
<--snip-->
Raspbian GNU/Linux 10 raspberrypi ttyS0
raspberrypi login:
おわりに
本記事では、Raspberry Pi 3BにSDカードを挿入せずブートすることができるネットワークブートの方法を紹介した。
このように、バグが報告されているRaspberry Pi 3Bでもネットワークブートすることができた。
今回は、ネットワークブートサーバにdnsmasqとnfs-kernel-serverをインストールする手法を紹介したが、その他のパッケージ (isc-dhcp-serverやtftpd-hpa)を用いても構築することができる。
また、公開されているRaspbian Buster Liteのディスクイメージのルートファイルシステムをそのまま使用しているので、SSHホストキーの再生成は実施しておくとよい。
変更履歴
- 2020/03/15: 記事公開
- 2022/06/07: 章構成の修正
参考
SDカードを使わず、network bootでRaspberry Pi 3Bを起動する
- Raspberry Pi Documentation - Raspberry Pi hardware
- らずぱい3で、ネットワークブート(SDなし) - Qiita
- Raspberry PI でNetwork Bootに挑戦 - Qiita
- Raspberry Pi Documentation - Raspberry Pi hardware
- Raspberry Pi 3でPXEネットワークブート - あっきぃ日誌
SDカードにU-Bootのみ格納し、network bootでRaspberry Pi 3Bを起動する
- 上野家のホームページ - 資料室 : PC/RaspberryPi/ネットワークブートネットワークブート
- Raspberry Pi を Network boot (with LANDISK NFS) | ず@沖縄
SDカードを使わず、network bootでRaspberry Pi 3B+を起動する
Raspberry Pi の起動シーケンス
- Raspberry Pi Documentation - Raspberry Pi hardware
- Raspberry Pi Documentation - Raspberry Pi hardware
- Raspberry Pi Documentation - Raspberry Pi hardware
Raspberry Pi のブートで必要なファイル郡
付録
Dockerで使用したオプションは以下のとおりである。
オプション名 | 詳細 | 指定理由 |
---|---|---|
--privileged |
コンテナを特権モードで動作させる | DHCPリレーサービスで物理ノードを参照するため。 指定しないと、 ARP-cache injection failed: Operation not permitted docker とエラーになってしまう |
--net=host |
ホスト側のネットワークスタックをコンテナに接続する | ホスト側のネットワークセグメントでDHCPを公開する範囲を制限するため。 |
-v /srv/tftpboot:/srv |
ホスト側のブートイメージ格納先をマウントする | コンテナ内のTFTPサービスからブートイメージを参照するため。 |
dnsmasqで指定したオプションは以下のとおりである。
パラメータ | 値 | 詳細 |
---|---|---|
port |
0 |
DNS サーバーは不要なので無効化しておく |
bogus-priv |
プライベートIPの逆引きは上位DNSに転送しない | |
interface |
eth1 |
開発用セグメントを指定する |
dhcp-range |
172.16.1.2, 172.16.1.65, 12h |
DHCPで払い出すIPアドレスの範囲を指定する |
pxe-service |
Raspberry Pi Boot |
Raspberry Pi では「Raspberry Pi Boot」と指定されているパケットのみ受け付ける |
enable-tftp |
TFTPサーバを有効化する | |
tftp-root |
/srv |
TFTPサーバが提供するルートディレクトリをコンテナ起動時にマウントしたディレクトリを指定する。 |
log-dhcp |
dhcp関連の詳細なログを出力する |
*1:Raspberry Pi 3 Model B+ではバグが修正されているので、そちらで実施している人が多い