昨今のFreeBSDにおける「パーティショニング」は、ディスクサイズによらず、GPT(GUID Partition Table)で構成するの一択と言っても過言ではない。しかし、いわゆる「BIOSからのブート」と「UEFIからのブート」では、パーティション構成に若干の違いが発生してしまう1。ここでは両者の違いを示し、ブートが可能なパーティション構成例を示す。
前提条件
ここではSATAディスクでの操作を前提とし、デバイス名は (/dev/)ada0 と表現する。SAS/USBディスクを対象とする場合は dan を、NVMeでは nvdn、eMMCでは mmcsdn と読み替えること(nは0以上の整数)。
共通事項
GPTパーティションなので、いずれの手順においても、実行しなければいけないコマンドがある2。
gpart create -s GPT ada0
なお話をシンプルにするために、以下のようなパーティションを切るものとする。
デバイス名 | パーティションタイプ | 用途 |
---|---|---|
ada0p1 | freebsd-boot ないしは efi | ブート領域 |
ada0p2 | freebsd-ufs3 | FreeBSD領域 |
ada0p3 | freebsd-swap | スワップ領域 |
今回の話で言うところの ada0p2 と ada0p3 は同じく共通手順となる。つまり「今この瞬間では実用性の無い」下記のコマンドの実行である456。
gpart add -t freebsd-ufs ada0
gpart add -t freebsd-swap ada0
BIOSブートの場合
gpart add -t freebsd-boot -b 40 -s 984 ada0
- ブートパーティションとして「freebsd-boot」パーティションを定義する。「freebsd-boot」でない場合、ブートローダーはこの領域を発見できない。
- 開始位置の指定(
-b
)を40セクタ(LBA40)から開始するものとする。- GPTパーティションのヘッダーサイズ(GPTヘッダーサイズ)は34セクタ7であるが、4KiBセクタ対応ディスクの場合、セクタ開始位置が8の倍数に丸められるられてしまう。
- それを見越してか最近、GPTヘッダーサイズが40セクタになってたりする(いつのバージョンからかは未確認)。
- 領域サイズの指定(
-s
)は984セクタを個人的に推奨する。- 次の領域(freebsd-ufs)の開始位置が512KiB境界から始まるというメリットがある8。
- ブートローダーの制限により545KiB未満のサイズに抑えなければならない(今回のサイズは492KiB)。
- よって小さくする意味も無ければ、これ以上大きくする余地も無い。
gpart bootcode -b /boot/pmbr -p /boot/gptboot -i 1 ada0
または
gpart bootcode -b /boot/pmbr -p /boot/gptzfsboot -i 1 ada0
以上でブートローダーのインストールが完了する。ブートローダーはFreeBSD領域910を探して /boot/loader または /boot/zfsloader に処理を引き渡す。
UEFIブートの場合
gpart add -t efi -b 40 -s 409560 ada0
- ブートパーティションとして「efi」パーティションを定義する。「efi」でない場合、UEFIはこの領域を発見できない。
- 開始位置の指定(
-b
)を40セクタ(LBA40)から開始するものとする。- GPTパーティションのヘッダーサイズ(GPTヘッダーサイズ)は34セクタ7であるが、4KiBセクタ対応ディスクの場合、セクタ開始位置が8の倍数に丸められるられてしまう。
- それを見越してか最近、GPTヘッダーサイズが40セクタになってたりする(いつのバージョンからかは未確認)。
- 領域サイズの指定(
-s
)は推奨に合わせて409560セクタを指定する。- この指定の場合、次の領域(freebsd-ufs)の開始位置が200MiB境界から始まる8。
- 領域サイズは、厳密には、200MiBより若干小さい(40セクタ分=20KB)が、まぁ誤差である。
- なお 11.2-R 現在のブート領域(/boot/boot1.efifat)のサイズは800KiBである。
- 10.4-R ないしは 11.1-R ではこの領域を200MiB確保することが推奨されているが、他のOS(macOSなど)との互換性を考慮しての設定なので、単体でFreeBSDを起動するならこの800KiBでも現時点では問題無い。
- bsdinstall: increase EFI partition size to 200MBの議論では、ファームウェアアップデートツールのようなEFIアプリケーションのための領域も必要とあるので流石に800KiBは少なすぎるという認識である。
newfs_msdos -F 32 -c 1 -L EFISYS /dev/ada0p1
mount -t msdosfs /dev/ada0p1 /mnt
mkdir -p /mnt/EFI/BOOT
cp /boot/loader.efi /mnt/EFI/BOOT/BOOTX64.efi
umount /mnt
または
gpart bootcode -p /boot/boot1.efifat -i 1 ada0
以上でブートローダーのインストールが完了する。ブートローダーはFreeBSD領域11を探してブート処理を進める。
よくある質問とその答え
Q.Bootable UEFI memory stick or Hard Diskに書いてある手順と違うぢゃないかー。
A.大丈夫だ。問題無い。時代が我に追いついていた。
Q.色々調べてみると /boot/boot1.efifat の、領域への書き込み方法に色々な手順があるようだが、何が正しいんだ?
A.大丈夫だ。どれも問題無い。が、どの手順もお勧めしない。
/boot/boot1.efifat はパーティションイメージそのものである。極端に言えば dd if=/dev/ada0p1 of=/boot/boot1.efifat
したものと思えばいい。実際ビルド時に似たようなことをしている。
よって、dd(8) で書き込むのも gpart(8) で書き込むのも同じである。が、どちらがよりスマートであるかは言うまでも無く gpart(8) である。
ただできれば /boot/boot1.efifat は使用しない方がよい。先の200MiB拡張の話になるが、これを使用すると200MiBの領域の内800KiBにしかアクセスできない領域になるからである。
せっかく200MiBの領域を確保したにもかかわらずEFIアプリケ-ションが全く動かせない環境となる。
また新規インストールでは問題無いが、更新したい場合、必要以上に消えてしまう手順でもある。
Q.OSアップデート時にブートパーティションの更新は必要ですか?
A.常にでは無いが必要。ただし…
- UFSから起動する場合、UFS自体のフォーマットの安定性から、ブートローダーのコードに変更が無いため、ほぼしくじることが無い。問題があったとしたら、おそらくUFS1→UFS2の時くらいと思われる。よって更新されてなかったとしても問題が起きることが無い、ないしは発覚しない。
- ZFSから起動する場合、ZFS自体のフォーマットの不安定性から、ブートローダーのコードに変更が発生するため、こまめにメンテしてやらないと、起動しない可能性がある。この辺りは
/usr/src/UPDATING
のZFS notes
に「ブートするZFSプールのバージョンを新しくするときはブートローダーを更新しろ」という記述がある。
この事から更新手順とは別にブートローダーの更新も手順化しておくべきである。
freebsd-boot パーティションに対しては gpart bootcode -p
で上書きしてやればよいが、efi パーティションに対してはマウントの上、cp
で上書きすることになる(後述)。
Q.パーティション番号が1でなくても良いならなんでもありぢゃないかー。
A.大丈夫じゃない、やめとけ。
MBRには2TiB制限があるので、後の領域を使うと、BIOSがブートローダー(freebsd-boot)を見つけてくれない可能性がある。
またパーティション番号と領域の順番が不一致の場合、管理が面倒になること請け合いである。
Q.我々はGPTを扱ってるのであってMBRは関係ないはず。
A.残念だ。GPTはMBRの上位互換なので諦めろ。
UEFIブートに関して言えば、GPTはGPTとして解釈されるので「関係ない」と言い切ってかまわない。
しかしBIOSブートに関して言えば、GPTはMBRとして振る舞う形になる。よって先頭から2TiBまので領域にブートローダー(freebsd-boot)が存在する必要がある。ただし、存在だけが問題なだけであって、パーティション番号がいくつであるかは問題とされない。
Q.システムがUEFIブートなのかBIOSブートなのか分かりません!
A.めーk(ちゅどーん)。インストールCDをLiveCDとして立ち上げた後 sysctl machdep.bootmethod
コマンドを事項して、UEFIならUEFIブート、BIOSならBIOSブートであることを確認することができる。
【付録】ブートローダーの更新
BIOSブートの場合
gpart bootcode -p /boot/gptboot -i 1 ada0
または
gpart bootcode -p /boot/gptzfsboot -i 1 ada0
UEFIブートの場合
まずは /etc/fstab に以下の設定を追加する。
# Device Mountpoint FStype Options Dump Pass #
/dev/ada0p1 /boot/efi msdosfs rw 0 0
次に /boot/efi ディレクトリを作成する。
mkdir -p /boot/efi
一度は手動でマウントを実行しておく。もちろん再起動して気にしないのもあり。
mount /boot/efi
以後の更新は下記の通り。
cp /boot/loader.efi /boot/efi/EFI/BOOT/BOOTX64.efi
参考文献
- gpart(8)のマニュアル
- FreeBSDのブートプロセス
- UEFI - FreeBSD Wiki
- FreeBSD 10.4 Release Notes
- FreeBSD 11.1 Release Notes
- bsdinstall: increase EFI partition size to 200MB
- GPTとMBRはどのように違うのか?
- コマンドラインによるFreeBSD起動パーティションの作成など
- FreeBSD/UEFIについて
-
BIOSではいわゆる「MBR(Master Boot Record)ブート」となるが、2TiB制限のキツさと、マルチブートの要求がほぼ無くなっていることから、GPTブート(?)に一本化されている ↩
-
このコマンドの実行に過不足は無い。むしろデフォルト値に手を入れる余地は(互換性的な観点から)全く無い。 ↩
-
freebsd-ufs は freebsd-zfs にしたい場合もあるだろうが、今回の話ではこの程度で省略しておく。 ↩
-
実際には
-s サイズ
オプションを使用してサイズを指定する必要がある。指定が無い場合は残り全てを意味する。つまりこのまま実行するとスワップ領域が確保できない。 ↩ -
実行順序に注意。このまま進めるとブート領域が割り当てられない(パーティション番号が一つずれる)。 ↩
-
-i パーティション番号
ないしは-b 開始位置 -i パーティション番号
オプションを使用して制御可能ではあるが、エッセンシャルな説明としては却下したいところ。 ↩ -
昨今の様々メディア(4KiBセクタHDDはもちろんのことNANDフラッシュなど)における境界の最小公倍数(512KiBもあればどのメディアでも境界に該当する)としては、そう悪くない数字である(はず)。 ↩ ↩2
-
gptboot は freebsd-ufs 領域の /boot/loader を、gptzfsboot は freebsd-zfs 領域の /boot/zfsloader を探す。 ↩
-
あくまでも「/boot/(zfs)loader」が収容されている領域のファイルシステムに紐付くため、ブート時はUFS、ルートはZFSと言ったハイブリッド環境の場合「UFS」として解釈する。 ↩
-
freebsd-ufs または freebsd-zfs 領域を探すが、その優先順位と制御はここでは説明しにくいので、参考文献を参考にしてもらうこととする。いや難しくないんだけどね。ファイルシステムレベルの調整が必須なのでもちっと踏み込む必要がある。 ↩