玩式草子─ソフトウェアとたわむれる日々

第78回 Plamo LinuxのGPT/UEFI対応[その2]

この記事を読むのに必要な時間:およそ 4 分

前回最近のマザーボードが採用しているUEFIと3TB以上のHDDを使う際に必要となるGPTの概要を説明し,UEFIではOSを起動するためのブートローダの扱いも従来のSystem BIOSとは異なっていることを紹介しました。

今回はUEFIがGPT形式のHDDからOSを起動する手順についてより具体的に説明し,Plamo Linuxがどういう形でUEFIに対応したかを紹介してみます。

ESPとブートローダ

前回,GPT形式のHDDでは,伝統的なMBR形式とは異なり,OSを起動するためのブートローダ用に専用のパーティションが用意されていることを紹介しました。このパーティションはEFIシステムパーティション(ESP)と呼ばれ,専用のパーティションIDが割り当てられ,FAT32形式でフォーマットするように規定されています。

たとえば,Windows8がインストールされたGPT HDDをLinuxのcfdiskで調べると図1のように見えます。この例では/dev/sda2が100MBのESPになっています。

図1 GPT HDD上のESP

図1 GPT HDD上のESP

UEFIは接続されたHDD上にESPがあるかを調べ,ESPが見つかればそのパーティション上の\EFI\BOOT\ディレクトリ以下にあるブートローダを探します。UEFI用のブートローダは,.EFIという拡張子を持つ,PE形式のバイナリファイルです。

PE(Portable Executable)形式はWindowsが採用しているバイナリ形式で,現在のLinuxが採用しているELF(Executable and Linkable Format)形式と同様,System-V UnixのCOFF(Common Object File Format)形式を発展させたバイナリ形式です。

UEFIの仕様では,x86_64環境の場合は\EFI\BOOT\BOOTX64.EFI32ビットのx86環境の場合は\EFI\BOOT\BOOTIA32.EFIがデフォルトのブートローダと見なされます。しかし,ブートローダが1つしか使えないとOSを切り替えるにも不便なので,たいていのUEFIの実装では\EFI\以下のサブディレクトリにあるPE形式の.EFIファイルをブートローダと見なして,それらを選択できるようになっているようです。

さて,実際の環境ではどのようにブートローダが配置されているのか,LinuxとWindowsがデュアル・ブートできる環境で,ESPを/boot/efi/にマウントして調べてみました。

$ find /boot/efi/EFI/ -name "*efi" -a -exec file {} \; 
/boot/efi/EFI/Boot/bootx64.efi: PE32+ executable (DLL) (EFI application) x86-64, for MS Windows
/boot/efi/EFI/Microsoft/Boot/bootmgfw.efi: PE32+ executable (DLL) (EFI application) x86-64, for MS Windows
/boot/efi/EFI/Microsoft/Boot/bootmgr.efi: PE32+ executable x86-64, for MS Windows
/boot/efi/EFI/Microsoft/Boot/memtest.efi: PE32+ executable x86-64, for MS Windows
/boot/efi/EFI/grub/grubx64.efi: PE32+ executable (EFI application) x86-64 (stripped to external PDB), for MS Windows

ESPの\EFIディレクトリ以下には.efiの拡張子を持つファイルが5つあり,そのうちの"EFI application"と認識されているbootmgfw.efiとgrubx64.efiがそれぞれWindowsとLinux用のブートローダです。もう一つのEFI applicationであるbootx64.efiはサイズから見てbootmgfw.efiのコピーのようです。

EFI applicationと認識されないbootmgr.efiとmemtest.efiは,恐らく,UEFIからではなくbootmgfw.efiから呼び出されるコマンドなのでしょう。

これらのブートローダを読み込んだASUS B85M-EのUEFIは起動デバイスの選択肢として,"grub"と"Windows Boot Manager"を表示し,指定に応じてそれぞれのOSを起動することができます。

図2 ASUS B85M-EのUEFIメニュー画面

図2 ASUS B85M-EのUEFIメニュー画面

一方,同様の設定を作ってもVirtualBoxのUEFIにはブートローダを選ぶ機能はなく,BOOTX64.EFIしかブートローダと認識しませんでした。VirtualBoxのような仮想環境の場合,複数のブートローダを使い分ける必要はまず無いので,このあたりは割り切った実装になっているようです。

Linux用UEFIブートローダ

前節では説明の都合上grubx64.efiもまとめて紹介したものの,本節では改めてこのブートローダの出所について説明することにします。

前節で紹介したように,UEFIで起動するためには

  • マザーボードのファームウェアがUEFIに対応していること

が必要です。加えて,

  • HDDがGPT形式になっていること
  • HDD上にFAT32形式でフォーマットされたESPが存在し,
  • ESPの\EFI\BOOT\以下に.EFIという拡張子を持ったPE形式のブートローダがあること

が必要になります。

インストーラとしては,前者のハードウェア的な条件はユーザに用意してもらうことにして,それらの上で後者の環境を作る,ということになります。後者のうち,HDDのディスクラベルやESPを作る作業は既存のインストーラを改造すれば対応できそうなので,残る条件はLinux環境で使えるEFI用のPE形式のブートローダということになります。

ざっと調べたところ,Linuxの代表的なブートローダであるliloとgrubそれぞれにUEFI対応版が存在していることがわかりました。さて,どっちがいいかな…,としばし考えたものの,メンテナの名倉さんがしばらく前からUEFI対応のgrubをPlamo-testに上げてくれていることを思い出し,その作業を元にgrubのUEFI対応版を作ってみることにしました。

ftp.gnu.org等で公開されているgrubの公式版は2012年の2.00で止まったままで,最新の開発版はgit経由で取り寄せることになっています。しかしながら,あまり新しい開発版を使うのもトラブルの元になりそうなので,Debian方面で公開されている2.02_28というバージョンを使うことにしました。

grubでUEFI対応版を作るためには--with-platform=efiというオプションを指定する必要があります。

$ ./configure --prefix=/usr --with-platform=efi 
checking build system type... x86_64-unknown-linux-gnu
checking host system type... x86_64-unknown-linux-gnu
checking target system type... x86_64-unknown-linux-gnu
...
*******************************************************
GRUB2 will be compiled with following components:
Platform: x86_64-efi
With devmapper support: Yes
With memory debugging: No
...

このオプション指定でビルドして,試しにローカルにインストールしてみると,モジュール類のインストール先が/usr/lib/grub/x86_64-efi/に変わりました。

$ make ; make install DESTDIR=`pwd`/work
....
$ ls ./work/usr/lib/grub/x86_64-efi/
acpi.mod                  gcry_whirlpool.mod            part_plan.mod
acpi.module*              gcry_whirlpool.module*        part_plan.module*
adler32.mod               gdb_grub*                     part_sun.mod
...

--with-platform=efiオプションを付けない場合,grubのモジュールは/usr/lib/grub/i386-pc/にインストールされるので,これらのモジュールはUEFI用と考えてよさそうです。しかしながら,これらのモジュールを確認するとPE形式ではなくLinuxネイティブのELF形式です。

$ file ./work/usr/lib/grub/x86_64-efi/acpi.mod
work/usr/lib/grub/x86_64-efi/acpi.mod: ELF 64-bit LSB relocatable, x86-64, version 1 (SYSV), not stripped

あれれ,PE形式じゃないとUEFIは認識してくれないはずでは…,とgrubのドキュメントやソースコードをざっと眺めたところ,grub-installgrub-mkimageなど実際に動作するブートローダを用意する際に,これらモジュールのヘッダ部分等を切り貼りして,異なるバイナリ形式に変換する機能が用意されているようです。

$ grub-mkimage  --help
使い方: grub-mkimage [OPTION...] [OPTION]... [MODULES]
Make a bootable image of GRUB.

  -c, --config=FILE          embed FILE as an early config
  -C, --compression=(xz|none|auto)
                             choose the compression to use for core image
...
  -o, --output=FILE          output a generated image to FILE [default=stdout]
  -O, --format=FORMAT        generate an image in FORMAT
                             available formats: i386-coreboot, i386-multiboot,
                             i386-pc, i386-pc-pxe, i386-pc-eltorito, i386-efi,
                             i386-ieee1275, i386-qemu, x86_64-efi, i386-xen,
                             x86_64-xen, mipsel-yeeloong-flash,
...

確かにgrubはさまざまなOSを起動するMultiboot specificationの考え方で開発され,Linuxのみならず,GNU HURDやBSD系UNIXも起動できるブートローダだから,さまざまなCPUやバイナリ形式に対応する必要があるものの,自前でバイナリ形式を変換する機能まで持っているのにはちょっと驚きました。

著者プロフィール

こじまみつひろ

Plamo Linuxとりまとめ役。もともとは人類学的にハッカー文化を研究しようとしていたものの,いつの間にかミイラ取りがミイラになってOSSの世界にどっぷりと漬かってしまいました。最近は田舎に隠棲して半農半自営な生活をしながらソフトウェアと戯れています。

URLhttp://www.linet.gr.jp/~kojima/Plamo/index.html

コメント

コメントの記入