Raspberry Pi3Bでは,GPUのROMの 1stステージ・ブートローダー にPXEブートが実装されているようだ。*1
それを利用してPXEブートが出来るようにしてみる。(この機能は,Pi3Bのみの機能)
PXEブートを使ってシステムをブートするには,Pi3BのROM設定をPXEブート出来るようにしておく必要がある。
ブートシーケンスは,
という手順になる。
Pi3Bのraspbianを最新にしておく
# apt-get update # apt-get upgrade # apt-get dist-upgrade # rpi-update
PXEブートできるように,USBブートモードをイネーブルにします。おそらく,Raspberry Pi3のGPUのOTP-ROMの設定を書き換えているんだと思います。
PXEブート以外にも,USBに接続したMass Strageからブートすることも出来るようになる。
Raspberry Piでは,EthernetやUSBの機能もLANチップ経由で行っており,SoCとLANチップ間は内部にあるUSB接続されているので,NetworkブートもUSBブートモードの機能の内ということになります。
ブート選択するモードに2つの設定ができます。
/boot/config.txtの最後に,program_usb_boot_mode=1を追加する。
# echo program_usb_boot_mode=1 | tee -a /boot/config.txt
リブートして,USBブートモードに設定されたかどうかを確認する。
# vcgencmd otp_dump | grep 17: 17:3020000a
0x3020000a が出力されれば正常。 program_usb_boot_mode=1 する前は,17:1020000a になっている。
/boot/config.txtを,
program_usb_boot_mode=1
を削除して,元の状態に戻しておきます。
なお,program_usb_boot_mode=1でUSBブートモードをイネーブルにした場合は,元に戻す事は出来なくなる。(OTP領域を書き換えるため)
ブートに関しては,program_gpio_boot_mode=1 という設定も出来るようになった。この場合も,元に戻す事は出来なくなる。(OTP領域を書き換えるため)
注意することとして,program_gpio_boot_mode=1をイネーブルにした場合,5個のGPIOをどこからbootさせるかの選択に使うので,他の目的のためにこの5つのGPIOを使用することが出来なくなる。
bit20の設定により,ブートデバイスの選択にGPIO22-26を使用するか,GPIO39-43を使用するかを設定できるが,GPIO39-43を使用できるのはCompute Moduleしか使用できないのに注意。
また,古いPi3のfirmwareでは設定するところでバグが有り,firmwareが4.9.60以前の場合,program_gpio_boot_modeを使うとOTP-ROMにbit20=1がセットされてしまいます。
このバグがある古いfirmwareの場合,
# vcgencmd otp_dump | grep 17: 17:1030000a
になる。表示から,bit20=1になっていて,GPIO39-43を使用するための設定になっている。
ただし,このバグが有る場合でも,結果的にはprogram_gpio_bootmodeにするためのbit19が0のままのため,GPIOでのブートの制御が実質使用できない状態で,program_usb_boot_modeは使用できるので,まったくブートしないというどうしょうもないことにはならない。
firmwareが4.9.60以降の場合では,program_gpio_bootmode=1とprogram_usb_boot_mode=1を同時に設定した場合,
17:3028000a
にOTP領域が設定されます。
bit19=1になり,正しくprogram_gpio_bootmodeとprogram_usb_boot_modeが使用できる設定になったということになります。
program_gpio_bootmodeでのブートの流れ
このprogram_gpio_bootmodeは5つのGPIOを別の用途に使えなくなるので,このモードは使用しないほうが良いと思う。
dhcpサーバをインストールする。
yum install dhcp
設定のサンプルがあるので,それをコピーして編集する。
# cp /usr/share/doc/dhcp-3.0.1/dhcpd.conf.sample /etc/dhcpd.conf
IP アドレスはネットワーク環境に合わせる。
filename
クライアントに読み込ませるブートローダーファイルを指定する。~
指定するパスは,tftpサーバのルートに対してのパスになるので注意。
next-server
filenameで指定するファイルをホストするサーバのアドレスを指定する。
next-serverを指定しない場合,dhcpサーバのアドレスが使用される。(と思う)~
dhcpサーバとtftpサーバを別にする場合などに使うのだと思う。
/etc/dhcp/dhcpd.confの編集(RPi3Bに対して追加する)
|
このように編集します。
dhcpサーバを起動しなおす。
# systemctl restart dhcpd
起動ディスクイメージやブートローダを転送するため,tftpサーバをインストールする。
# yum install tftp-server
/etc/xinetd.d/tftpを編集する。
disable no
にするとTFTPサービスが有効になる。 server_argsで指定しているディレクトリが TFTPサーバのルートになる。
server_args = -s /var/lib/tftpboot disable = no
xinetdを再起動し,tftpサーバを有効にする。
# systemctl restart xinetd
SDカードの/boot(最初のパーテーション)にあるすべてのファイルを,/var/lib/tftpbootにコピーする。
/var/lib/tftpboot/pxeboot
/start.elf : (bootcode.bin以外の/boot以下のファイル全部) : /bootcode.bin
このようにファイルを用意する。
# mkdir /var/lib/tftpboot/pxeboot # scp -r yuji@192.168.1.xxx:/boot/* /var/lib/tftpboot/pxeboot/
これでRPi3Bの/bootがコピーできた。
起動した後のルートファイル(NFSでマウントして使用)を指示するのはcmdline.txtを使用する。
/var/lib/tftpboot/pxeboot/cmdline.txtを編集する。
root=/dev/nfs nfsroot=192.168.1.xxx:/var/exports/pi3-netboot,vers=3 rw ip=dhcp rootwait elevator=deadline
ルートファイルシステムはNFSサーバを用いて用意し,Rpi3Bではネットワーク越しにマウントして使用する。
NFSサーバ側で,/etc/exportsでNFSエクスポートの設定をする。
/etc/exports
/var/exports/pi3-netboot *(rw,no_root_squash,no_subtree_check)
/var/exports/pi3-netbootには,Raspbianで言うところのmmcblk0p2の中身を置く。
mmcblk0p2は,raspbianのルートファイルシステムが入っている。どうにかして,Pi3のmmcblk0p2を/var/exports/pi3-netbootにコピーする。
現在のPi3BのMicroSDカードを,ディスクイメージにバックアップする。
backupxxxx.img
これをNFSサーバにコピーする。
NFSのexportするディレクトリを作成する。
# mkdir /var/exports/pi3-netboot
loopデバイスで空いているループバックデバイスを探す。
# losetup -a # losetup -f /dev/loop0
/dev/loop0が空いているのがわかる。空きが無い場合は,modprobeコマンドで増やす。
# modprobe loop max_loop=32
/dev/loop0にイメージファイルを割り当てる。
# losetup /dev/loop0 /temp/backupxxxx.img
kpartx -aを使って,イメージファイルのパーティションを識別する。
#kpartx -a /dev/loop0
/dev/mapperに,loop0p1とloop0p2が出来ている。
/dev/loop0p2を,/mnt/raspberrypiにマウントする。
# mount /dev/loop0p2 /mnt/raspberrypi
/mnt/raspberrypiの中身をrsyncでコピーする。
# rsync -xa /mnt/raspberrypi /var/exports/pi3-netboot
/mnt/raspberrypiをアンマウントする。
# umount /mnt/raspberrypi
/dev/loop0を削除する。
# kpartx -d /dev/loop0 # losetup -d /dev/loop0 # losetup -a
新しくコメントをつける