|
現: 2023-04-23 (日) 07:33:52 yuji  |
| + | * U-Bootでネットワークブート [#bfc56539] |
| + | Raspberry Piでネットワークブートする場合に全モデルで共通に使用できる方法としては,汎用ブートローダである [[U-Boot>http://www.denx.de/wiki/U-Boot/]] を使う方法がある。~ |
| | | |
| + | 実際にRaspberry Piで利用できるRaspbian以外のいくつかのOSでU-Bootが使われています。これには理由があり,RaspbianのブートローダーはRaspberry Pi Foundation(ラズベリーパイ財団)により開発された非公開プログラムなので,他のOSのブートに利用しにくいため。~ |
| + | |
| + | ネットワークブートする方法としては,通常の[[ブートシーケンス>../../ブートシーケンス]]でSD/MicroSDカードのFAT/FAT32パーテーションにあるLinux kernelをロード・実行する代わりにU-Bootをロード・起動して,ネットワーク越しにブートファイル(Linux kernel)をロードして起動するようにする。~ |
| + | |
| + | Raspberry PiにはRAMがあまり実装されていないので,直接ネットワーク越しにルートファイルシステムをマウントする必要がある。このためにnfsサーバーを利用する。 |
| + | |
| + | ローカルネットワークのサーバーにRaspberry Piがロードするファイル(Kernelやルートファイルシステム)を置いて,それを使って[[初代Raspberry Pi B>../../スペック#pdd72445]]でRaspbian Baster Liteを起動してみる。 |
| + | |
| + | * U-Bootの用意 [#def4f8a2] |
| + | ブート時に本来最後にKernelをロードする代わりにU-Bootをロードして実行し,そこからネットワーク上にあるKernelをロードするようにするために,Raspbianが入ったSD/MicroSDカードの第1パーテーション(FAT/FAT32パーテーション)に,[[こちらでビルドしたu-boot.bin>./RPi用U-Bootをビルド]] をコピーする。~ |
| + | |
| + | SD/MicroSDカードの''/boot/config.txt''を編集して,u-boot.binを使うように変更する。~ |
| + | これには,/boot/config.txtの最後のあたりに, |
| + | kernel=u-boot.bin |
| + | と追加する。~ |
| + | |
| + | これでRaspberry Piをブートすると,start.elfによるkernel.img(Raspberry Pi Bの場合)をロードする代わりに,u-boot.binがロードされネットワーク上のKernelをロードするブートローダーとして起動するようになる。~ |
| + | |
| + | この時のブートシーケンスは以下のようになると思われる。~ |
| + | - ROMブートローダが起動し,L2 Cacheに2番目のブートローダーbootcode.binをロードする。~ |
| + | - 2番目のブートローダbootcode.binが起動し,SDRAMを有効にし,start.elfをロードする。~ |
| + | - start.elfが起動し,SD/MicroSDカードにあるDevice Tree xxxxx.dtbを読み込んでFlattened Device Tree(FDT)を作成する。~ |
| + | -- Displayに虹色画面(テスト画像)を表示する。~ |
| + | -- config.txtを読み込んでoverlay情報をFDTに適用する。~ |
| + | -- FDT情報をパラメータとしてu-bootをロードする。~ |
| + | cmdline.txtもKernelパラメータとして渡されると思う。しかしu-bootがKernelを起動する時のパラメーターとしては使われない。~ |
| + | - start.elfがkernel.imgの代わりにu-boot.binをロードする。~ |
| + | - u-bootを起動し,ネットワーク上のKernelをRAMにロードする。~ |
| + | boot.scr.uimgに記載されている処理を行っていく。~ |
| + | -- Ethernetの初期化を行う。~ |
| + | -- DHCPを使ってネットワークの初期化を行う。~ |
| + | -- Kernelをロードする。~ |
| + | -- FDTをロードする。~ |
| + | ロードしたDevice Tree xxxxx.dtbとstart.elfでロードされたconfig.txtとともにFlattened Device Tree(FDT)を作成しているようだ。~ |
| + | つまりSD/MicroSDカードのconfig.txtで設定を行っておく必要があるので注意する。Kernelパラメーターでも設定できると思うが・・・~ |
| + | //start.elfによってSD/MicroSDカードからロードし作成したFDTをオプションとしてKernelをロードする。~ |
| + | //本来,u-bootはxxxxx.dtbとoverlay情報をダウンロードしてFDTを作成出来るのだが,どうもRaspberry PiのDevice Treeは標準ルールで作成されていないみたいで,FDT_ERR_NOTFOUNDで失敗してしまうようだ。~ |
| + | //このためstart.elfがロード・作成したFDTをダウンロードしたKernelに渡すようにしている。~ |
| + | //つまりSD/MicroSDカードのxxxxx.dtbとoverlay情報が使われる(config.txtで設定を行っておく)ことになるので注意する。~ |
| + | -- Kernelパラメータを用意する。~ |
| + | - u-bootがKernelを起動する。~ |
| + | FDT情報とKernelパラメータを指定してKernelを起動する。~ |
| + | - Kernelがルートファイルシステムをマウントする。~ |
| + | initramfs等を使用せずnfsを使用して直接ルートファイルシステムをマウントしている。~ |
| + | - /sbin/initを起動する。~ |
| + | |
| + | ** U-Bootスクリプトファイルを作成 [#h234f4f2] |
| + | U-Bootの処理を自動化するために,''boot.txt''を作成する。~ |
| + | #code(bash,,nonumber){{ |
| + | setenv serverip 192.168.XXX.xxx |
| + | setenv rootpath /var/exports/raspbian |
| + | setenv kernelfile kernel.img |
| + | setenv fdtfile bcm2708-rpi-b.dtb |
| + | setenv fbwidth 1824 |
| + | setenv fbheight 984 |
| + | |
| + | setenv bootarg_def "dma.dmachans=0x7f35 bcm2708_fb.fbwidth=${fbwidth} bcm2708_fb.fbheight=${fbheight} bcm2708.boardrev=0x10 bcm2708.serial=0x12345678 smsc95xx.macaddr=${usbethaddr} bcm2708.disk_led_gpio=47 bcm2708.disk_led_active_low=0 sdhci-bcm2708.emmc_clock_freq=250000000 vc_mem.mem_base=0x1ec00000 vc_mem.mem_size=0x20000000" |
| + | setenv bootarg_opt "dwc_otg.lpm_enable=0 console=ttyAMA0,115200 console=tty1 kgdboc=ttyAMA0,115200 root=/dev/nfs nfsroot=${serverip}:${rootpath},rsize=32768,wsize=32768,proto=tcp,vers=4.1 rw ip=dhcp rootfstype=nfs smsc95xx.turbo_mode=N elevator=deadline rootwait" |
| + | setenv bootargs "${bootarg_def} ${bootarg_opt}" |
| + | |
| + | usb start |
| + | dhcp ${kernel_addr_r} ${kernelfile} |
| + | tftp ${fdt_addr_r} ${fdtfile} |
| + | bootz ${kernel_addr_r} - ${fdt_addr_r} |
| + | }} |
| + | usb startはEthernetの初期化を行う。Raspberry PiのEthernetコントローラが内部USBで接続されているため。~ |
| + | dhcpコマンドで,ネットワークの設定を行いkernel.img(Kernel)をRAMにロードする。~ |
| + | tftpコマンドで,tftpサーバーからdevice treeファイルをRAMにロードする。~ |
| + | Kernelに渡すoptionで,ルートファイルシステムの場所とnfsを使って直接マウントするように指定している。~ |
| + | kernel.imgとdevice treeもnfsを使ってロードすることも出来るが,今回はtftpを使っている。~ |
| + | |
| + | serverip(tftpサーバーのIP Address)やrootpath(ルートファイルシステムがあるディレクトリ)は,dhcpサーバーからoptionで渡すようにした方が良いかも。~ |
| + | 最後にbootzコマンドでKernelを起動している。~ |
| + | |
| + | 作成した''boot.txt''を&ref(mkimage.zip,mkimageコマンド);を使って,U-Bootが認識できるファイルに変換する。~ |
| + | $ mkimage -A arm -O linux -T script -C none -a 0 -e 0 -n "Network Boot" -d boot.txt boot.scr.uimg |
| + | |
| + | 作成された''boot.scr.uimg''をSD/MicroSDカードの第1パーテーション(/boot)にコピーする。~ |
| + | |
| + | これで,Raspberry Pi側の設定は完了。~ |
| + | |
| + | * サーバー側の設定 [#d27b3582] |
| + | tftpを使ってブートファイルをダウンロード出来るようにして,nfsを使ってルートファイルシステムをマウント出来るようにする。~ |
| + | |
| + | Raspbianのブートファイルやルートファイルシステムを用意する必要があるが,これらはRaspbianのOSイメージファイルから抜き出している。~ |
| + | |
| + | またサーバーマシンには,このWEBサービスも行っているCentOSのローカルサーバーマシンを使用している。 |
| + | |
| + | ** dhcpdの設定 [#gdf4bce5] |
| + | ローカルネットワークでのDHCPサーバーを使って,ネットワークブートするRaspberry PiへIP Addressをアサインし,tftpサーバーのIP Addressとルートファイルシステムがあるディレクトリを通知するようにした。~ |
| + | |
| + | ''/etc/dhcp/dhcpd.conf''ファイルの編集。 |
| + | #code(bash,,nonumber){{ |
| + | : |
| + | host rpi { |
| + | hardware ethernet B8:27:EB:XX:XX:XX; # RPiのEthernetのMAC Address |
| + | fixed-address 192.168.xx.yyy; # RPiへ割り当てるIP Address |
| + | next-server 192.168.xx.xxx # tftpサーバーのIP Address |
| + | option root-path "/var/exports/raspbian"; # nfsサーバーのexportsディレクトリ |
| + | } |
| + | : |
| + | }} |
| + | このように編集した。~ |
| + | |
| + | DHCPサーバーを再起動する。~ |
| + | # systemctl restart dhcpd |
| + | |
| + | ** tftpサーバーの用意 [#u2378cec] |
| + | [[tftp>https://ja.wikipedia.org/wiki/Trivial_File_Transfer_Protocol]]サーバーをパッケージ管理ツールでインストールする。 |
| + | # yum install tftp-server |
| + | |
| + | /etc/xinetd.d/tftpを編集する。~ |
| + | server_args = -s /var/exports/raspbian/boot |
| + | disable no |
| + | tftpサーバーはxinet経由でサービスされる。~ |
| + | server_argsでtftpサーバーのファイル場所のルートを設定している。~ |
| + | これは,nfsでマウントするルートファイルシステムの/bootと同じディレクトリになるように設定している。Raspbianのaptによるブートファイルの更新と同期するようにするため。~ |
| + | |
| + | xinetdを再起動しtftpサーバを起動する。~ |
| + | # systemctl restart xinetd |
| + | # systemctl enable xinetd |
| + | |
| + | ** tftpサーバーにファイルを用意する [#x1a0a58e] |
| + | /var/exports/raspbian/bootに,Raspbianのkernelファイル(ブート)を用意する。 |
| + | |
| + | *** ブートファイル類 [#o2d659fe] |
| + | 上記で設定した''/var/exports/raspbian/boot''に,ブートファイル(第1パーテーションのファイル)のすべてをコピーする。~ |
| + | |
| + | とりあえず以下のようにした。~ |
| + | # mkdir -p /var/exports/raspbian/boot |
| + | |
| + | 公式のraspbianのimgファイルをmountしてコピーしてみた。~ |
| + | |
| + | まずraspbianのimgファイルを確認する。~ |
| + | # fdisk -l -u 2020-02-13-raspbian-buster-lite.img |
| + | Disk 2020-02-13-raspbian-buster-lite.img: 1849 MB, 1849688064 bytes, 3612672 sectors |
| + | Units = sectors of 1 * 512 = 512 bytes |
| + | Sector size (logical/physical): 512 bytes / 512 bytes |
| + | I/O サイズ (最小 / 推奨): 512 バイト / 512 バイト |
| + | Disk label type: dos |
| + | ディスク識別子: 0x738a4d67 |
| + | |
| + | デバイス ブート 始点 終点 ブロック Id システム |
| + | 2020-02-13-raspbian-buster-lite.img1 8192 532479 262144 c W95 FAT32 (LBA) |
| + | 2020-02-13-raspbian-buster-lite.img2 532480 3612671 1540096 83 Linux |
| + | 2つのパーテーションがあり,始点がオフセットになっている。(8192 * 512 = 4194304)~ |
| + | なので,そのオフセット分を追加すれば,mountコマンドでマウントできる。~ |
| + | # mount -t vfat -o loop,offset=4194304 2020-02-13-raspbian-buster-lite.img /mnt/rpi |
| + | # cp -rp /mnt/rpi/* /var/exports/raspbian/boot |
| + | # umount /mnt/rpi |
| + | // # scp -r yuji@192.168.24.xxx0:/boot/* /var/lib/tftpboot/ |
| + | |
| + | このようにファイルを用意した |
| + | // /var/lib/tftpboot |
| + | // /start.elf |
| + | // : |
| + | // /bootcode.bin |
| + | |
| + | ** nfsサーバーの用意 [#q82ea898] |
| + | [[nfs>https://ja.wikipedia.org/wiki/Network_File_System]]サーバーは,既にインストールされていた。~ |
| + | インストールされていなければ, |
| + | yum install nfs-utils |
| + | として,パッケージ管理ツールでインストールできる。 |
| + | |
| + | nfsの共有ディレクトリを作成する。 |
| + | # chown -R nfsnobody:nfsnobody /var/exports |
| + | |
| + | nfs設定ファイル''/etc/exports''を編集する。~ |
| + | /var/exports/raspbian 192.168.XXX.0/255.255.255.0(rw,no_root_squash,sync,no_subtree_check) |
| + | ローカルネットワークに限定している。~ |
| + | |
| + | nfsを再起動する。 |
| + | # systemctl restart nfs |
| + | # systemctl enable nfs |
| + | |
| + | *** ルートファイルシステムをnfsでexportする場所に用意する [#tf03800a] |
| + | 上記で設定した/var/exports/raspbianに,ルートファイルシステム(第2パーテーションのファイル)の全てをコピーする。~ |
| + | |
| + | 今回はブートファイルと同様に,公式のraspbianのimgファイルをmountしてコピーしてみた。~ |
| + | オフセット値は,532480 * 512 = 272629760。~ |
| + | # mount -t ext4 -o loop,offset=272629760 2020-02-13-raspbian-buster-lite.img /mnt/rpi |
| + | # cp -rp /mnt/rpi/* /var/exports/raspbian |
| + | # umount /mnt/rpi |
| + | //イメージファイルからコピーする場合は,以下のようにする。~ |
| + | //現在のRPiのSDカードを,ディスクイメージにバックアップする。 |
| + | // backupxxxx.img |
| + | //これをNFSサーバにコピーする。 |
| + | // |
| + | //NFSのexportするディレクトリを作成する。 |
| + | // # mkdir /var/exports/raspbian |
| + | // |
| + | //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/raspbian |
| + | // |
| + | ///mnt/raspberrypiをアンマウントする。 |
| + | // # umount /mnt/raspberrypi |
| + | // |
| + | //次に,/dev/loop0p1を,/mnt/raspberrypiにマウントする。 |
| + | // # mount /dev/loop0p1 /mnt/raspberrypi |
| + | // |
| + | ///mnt/raspberrypiの中身をrsyncでコピーする。 |
| + | // # rsync -xa /mnt/raspberrypi /var/exports/raspbian/boot |
| + | // |
| + | ///mnt/raspberrypiをアンマウントする。 |
| + | // # umount /mnt/raspberrypi |
| + | // |
| + | ///dev/loop0を削除する。 |
| + | // # kpartx -d /dev/loop0 |
| + | // # losetup -d /dev/loop0 |
| + | // # losetup -a |
| + | |
| + | *** コピーしたRaspbianの中身を少し書き換える [#s1d8329f] |
| + | Kernelが起動時にブートとルートファイルシステムを直接nfsマウントしているため,SD/MicroSDカードのパーテーションをマウントしているところをコメント化してマウントしないように設定する。~ |
| + | ''/var/exports/raspbian/etc/fstab''ファイルを編集する。~ |
| + | proc /proc proc defaults 0 0 |
| + | #/dev/mmcblk0p1 /boot vfat defaults 0 2 |
| + | #/dev/mmcblk0p2 / ext4 defaults,noatime 0 1 |
| + | //192.168.xxx.xxx:/var/exports/raspbian/boot /boot nfs defaults,vers=4.1,proto=tcp 0 0 |
| + | ///dev/nfs / nfs defaults,vers=4.1,proto=tcp,rw 0 0 |
| + | |
| + | * Raspbianを起動 [#e9d4257d] |
| + | Raspberry Piを電源ONすると,U-Bootが起動してkernelがロードされた後,kernelを起動し,その後ルートファイルシステムがマウントされて,無事Raspbianのログインプロンプトが表示された。~ |