2014年9月13日土曜日

GUIDパーティションとMBRブート


  • GUIDパーティションのディスクからGRUBで通常(MBR)起動する際のメモ。
  • なんとなくやってできていたので気にしていませんでしたが、UEFIでのブートを試した際に今まで勘違いしていたことが分かったのでその点のまとめ

GUIDパーティションディスクからの起動

  GUIDパーティションテーブル(GPT)の規格はUEFI(EFI)の規格とセットであるが、GUIDパーティションテーブルのディスクからの起動にはEFIブートが必須というわけではない。
  Windowsの場合は無理な場合が多いが、LinuxではGPTのディスクからも従来通りの方法(MBRを利用した方法)での起動は可能。

GUIDパーティションテーブル

  GUIDパーティションテーブルの先頭のセクタ(LBA0)は従来のMBRと同じものになっている。これは互換性や安全性のため。GPTに対応していない機器にディスクを接続してしまったときに、ディスクと認識されなかったり、さらには初期化のされていないディスクと勘違いされていきなり初期化されたりしないようにするため。
  従来のMBRパーティションでは、MBR内にパーティション情報を格納してたが、GPTではここにはパーティションを情報を格納しない。MBRにつづく第2セクタ(LBA1)にあるパーティションテーブルヘッダおよび第3セクタからはじまるパーティションエントリに情報を格納する。
  MBRパーテョンでは基本パーテョションが4つまでであったり、大きなサイズ(2TB以上)のディスクを扱えなかったりしたのは、MBR内のパーティション情報を格納する領域の大きさ的にそれが限界であったため。
  GPTではこのパーテョション情報を格納する領域は十分に広い。パーティションは128個まで、ディスクサイズは8ZiB(ゼビバイト)まで扱える(もちろん、情報が格納できるというだけで実際に使えるかどうかはOSなどの対応による)

MBRブート

  MBRブートでのブートローダはMBR内に格納する。MBRのサイズは全体で512B(1セクタ)であるが上記のパーティションテーブル情報分があるのでブートローダに利用できる領域は446Bしか用意されていない。
  このサイズでは多機能なブートローダは格納できない。そこでGRUBなどの多機能なブートローダでは、MBR内には多機能なブートローダの本体を読み出すだけのブートローダをインストールして、本体は別の(もっと大きなサイズのプログラムを置ける)場所から読み込むようになっている。

MBRの第1パーテョション

  MBRパーティションでは第1パーティションは第1シリンダ(63セクタ)以降から始まるというルールがあった。このルールのためMBRの第2セクタから62セクタまでの61セクタ(約31KB)は必ず空きになっていた(MBR Gap)
  GRUBではこの領域にブートローダの本体を置き、MBR上のブートローダがこれをロードして本体が実行されるようになっている。
  この領域に本体を置いておく利点は、OSの管理外の領域であるために、一度書き込んだデータのディスク上の物理的な位置(セクタ位置)は変化しない。本体のインストール時にそのセクタ位置を記録しておけば、それをもとにMBRのブートローダが本体の位置を確定することができる。
  OSの管理するファイルシステム上に書き込んだ場合、OS側のファイルシステムの調整によって本体のファイルそのものは消去されなくてもディスク上の物理的な位置は変化する可能性がある。そうなった場合、最初に記録したセクタ位置から本体のファイルが移動して読み込めなくなる(MBR上のブートローダはファイルシステムを理解できないので本体の移動に追従できない)

  パーティションツールによってはMBRパーティションであっても、第2セクタからすぐに第1パーティションを切ることが可能であるが、そのようなことをするとGRUBなどのブートローダはうまくインストールできない可能性がある。

GUIDパーティションテーブルとMBRブート

  GRUB2はGPTでのMBRブートに対応している。ただし、GPTでは先頭のMBRの次の第2セクタからパーティション情報の領域がすぐに始まってしまう(MBR Gapがない)のでMBRの場合と同じ場所にGRUBの本体をインストールすることができない。そこでGPTでGRUB2のMBRブートを利用する場合、GRUBの本体をインストールするための専用の領域を確保する必要がある。

bios_grub領域

  linuxのpartd(GNU Parted)の場合パーティションにbios_grubオプションを設定することによってGRUBの本体をインストールする領域にすることが可能。その他のGPT対応のパーティションニングツールではパーティションタイプをEF02に設定する。
  GRUB(GRUB2)はGPTディスクへのインストール時にこの領域をみつけるとそこに本体を自動的にインストールする。GRUB2の説明を読むとこの領域は最低31KB必要とかかれているがこれはMBR Gapが最低31KBだったことに対応している。

  GRUB2はこのbios_grub領域がない場合でも、/bootディレクトリ以下に本体(ファイル)をインストールして起動するようにすることができる。この場合、そのファイルのディスク上の物理的なセクタ位置をインストール時に記録して、その情報をもとにMBRのブートローダが本体の位置を特定して読み込む。ただし、何からの原因で/bootのファイルシステムが調整されてファイルの物理的なセクタ位置が変更されてしまうと起動できなくなる。bios_grub領域を利用することを推奨。

  • MBRのブートローダは他の場所にあるブートローダを読み込むだけ。
  • OSはその読み込まれたブートローダによって起動される。

EFI専用パーティション

 GPTディスクでのブートで関連してくるパーティションにEFI専用パーティション(EFIシステムパーティション)というものがある。
 これはGPTディスクでEFIブートする場合にEFI形式のブートローダを格納しておくためFAT32でフォーマットされた領域であって、前述のbios_grub領域とは全くの別物である。bios_grub領域はフォーマットをする必要はない。
 GPTディスクであってもMBRブートのみする場合にはこの領域は必要ない。

MBRブートとEFIブート

  従来のBIOSのMBRブートでは起動時に初めに読み込むブートローダの位置は第1セクタで決め打ちされていて、BIOSではどの機器(ディスクやCDROM,USBメモリ)の第1セクタのブートローダを読み込むかくらいしか選択できなかった。
  EFI BIOSでは、EFI BIOSがFAT32でフォーマットされたEFI専用パーティションを"理解"できるので、パーティション内に格納されているEFI形式のブートローダのファイルの位置を確定して直接読み込むことができる。
  つまりEFI BIOSでEFIブートする場合、BIOSでの設定では起動する機器ではなく起動に利用するブートローダファイルを選択することができる。
  ファイルは通常のファイルシステムにおけるファイルパスで指定される。
  デフォルトのブートローダのファイルパスも決められているのでEFIブート時に"機器"しか選択しなかった場合はその機器上にあるEFI専用パーティションのデフォルトのファイルパスにあるブートローダが選択される。

実際の手順

 ディスクにpartedでパーティションを作成する。そんなには必要ないがbios_grub領域は100MB(2048セクタ)確保している。

# parted /dev/sda
(parted) u s 
(parted) mklabel gpt
(parted) mkpart primary 2048 4095
(parted) set 1 bios_grub on
(parted) mkpart primary 4096  234441614
(parted) p                                              

Sector size (logical/physical): 512B/4096B
Partition Table: gpt

Number  Start  End         Size        File system  Name     Flags
 1      2048s  4095s       2048s                    primary  bios_grub
 2      4096s  234441614s  234437519s               primary

  linuxをインストールする。今回はdebootstrapで上記で作成した領域2にインストールした。OSをインストールする領域は2番目(/dev/sda2)になる点に注意。bios_grub領域は確保しておくだけでフォーマットなどをする必要はない。

# mkfs.ext4 /dev/sda2 # mount /dev/sda2 /mnt/disk 
# debootstrap --arch amd64 jessie /mnt/disk http://ftp.jp.debian.org/debian
# mount -o bind /dev /mnt/disk/dev
# LANG=C chroot /mnt/disk /bin/bash
(以下chroot下で)
# proc proc /proc
# apt-get update
# apt-get install grub-pc
(apt-getでのgrubのデバイスへのインストールは実行しないでおく)

bios_grub領域の中身をチェック。なにも入っていない。
# dd if=/dev/sda1 of=./bios_grub.img bs=512 count=64
# od bios_grub.img
0000000 000000 000000 000000 000000 000000 000000 000000 000000
*
0100000

GRUB2を/dev/sdaにインストールすると、bios_grub領域に書き込まれていることが分かる。
# grub-install /dev/sda
# dd if=/dev/sda1 of=./bios_grub_after.img bs=512 count=64
# od bios_grub_after.img | head
0000000 164122 000450 004164 137126 100463 046350 057001 172277
0000020 063201 026613 076603 000010 102017 000351 076200 000377
0000040 043164 105546 063035 046613 063004 140061 077660 042471
...
...

カーネルをインストールして起動できるか確認する。ログインするためのパスワードを設定しておくこと。

# apt-get install linux-image-amd64
# update-grub
# passwd

(chroot環境から抜けて再起動)

 MBRブートなので起動する機器(起動するディスク)をBIOSで選択すると、その第一セクタにあるブートローダが読み込まれ、それがbios_grub領域にあるGRUB本体をロードしてGRUBがファイルシステム上にあるカーネルを起動する。

まとめ

  •  Linuxの場合、GUIDパーティションディスクでもMBRブートは可能。
  •  GRUB2の場合bios_grub領域を作成しておく必要がある。
  •  EFI専用パーティションはGPTであってもMBRブートする場合には必要はない。