前回 はUEFIがGPT形式のHDDからOSを起動する仕組みを解説し、Plamo Linux 6.0をGPT形式のHDDにインストールする手順を紹介しました。前回は省略したものの、UEFI環境にインストールするにはもう一つ越えなければならない壁があります。それは「UEFIにインストールするにはUEFIから起動しなければいけない 」という条件です。
従来のSystem BIOSではHDDの起動順序等の設定はBIOSのメニュー画面からしか操作できなかったのに対し、UEFIではさまざまな設定をOSから操作する機能が提供され、起動順序等をより柔軟に設定できるようになりました。
一方、この機能を使うにはOSがUEFIモードで起動している必要があります。たとえばLinuxの場合、UEFIの設定はefivarfs という専用のファイルシステム経由で利用するようになっており、このファイルシステムはカーネルがUEFIモードで起動しないと有効になりません。
すなわち、GPT/UEFI環境にインストールするにはインストーラをGPT/UEFI対応にするだけではなく、インストーラ自身をUEFIから起動する 必要があるわけで、そのための方法をあれこれ調べることになりました。
USBメモリからUEFI起動
前回紹介したように、UEFIはHDDからOSを起動する場合、専用のパーティションIDを持ったFAT32形式のEFIシステムパーティション(ESP)にあるブートローダを調べます。一方、USBメモリのように通常は一つのパーティションしか持たないリムーバブルメディアから起動する場合、ESPとは関係なくメディアのルートディレクトリにある\EFI\BOOT\ディレクトリを探します。このディレクトリに置くブートローダは、x86_64アーキテクチャの場合BOOTX64.EFI 、32ビットのx86アーキテクチャの場合はBOOTIA32.EFI という名前にすることになっています。
前回紹介したように、--with-platform=efiオプションを指定してビルドすればUEFI用のgrubはビルドできるものの、この状態のgrubは機能が細かく分割されたモジュール群 でしかありません。
$ ls -l /usr/lib64/grub/x86_64-efi/
合計 20,307,968
-rw-r--r-- 1 root root 16,432 10月 30日 17:11 acpi.mod
-rwxr-xr-x 1 root root 102,088 10月 30日 17:11 acpi.module*
-rw-r--r-- 1 root root 1,928 10月 30日 17:11 adler32.mod
-rwxr-xr-x 1 root root 13,328 10月 30日 17:11 adler32.module*
-rw-r--r-- 1 root root 8,272 10月 30日 17:11 affs.mod
-rwxr-xr-x 1 root root 48,344 10月 30日 17:11 affs.module*
-rw-r--r-- 1 root root 9,016 10月 30日 17:11 afs.mod
-rwxr-xr-x 1 root root 57,488 10月 30日 17:11 afs.module*
...
grubがブートローダとして機能するためには、これらモジュールのうち必要なものをgrubコアに組み込む必要があります。grub-install コマンドを使ってインストールする場合、grub-mkconfig コマンドが自動的に起動され、インストールする環境に応じたモジュールを組み込むための設定ファイル(grub.cfg )を生成してくれます。
骨組みだけしかないgrubコアにgrub.cfgで必要なモジュールを組み込むという仕組みは、さまざまな環境に柔軟かつ効率的に対応できる利点はあるものの、どのような環境で使われるかが事前には分からないインストーラでは使えません。
そのような場合のために用意されているのがgrub-mkimage コマンドです。このコマンドは、指定したモジュールをgrubコアに組み込んで、モジュールを追加ロードしなくても動作するバイナリファイルを生成します。
$ 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
-d, --directory=DIR use images and modules under DIR
[default=/usr/lib64/grub/<platform>]
-k, --pubkey=FILE embed FILE as public key for signature checking
-m, --memdisk=FILE embed FILE as a memdisk image
Implies `-p (memdisk)/boot/grub' and overrides
any prefix supplied previously, but the prefix
itself can be overridden by later options
-n, --note add NOTE segment for CHRP IEEE1275
-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,
...
grubには250近いモジュールが用意されており、どのモジュールを組み込むかを考えるのも一苦労なものの、今回はUSBメモリと後述するDVDからの起動に限定して以下のようなモジュールを組み込むことにしました。
$ grub-mkimage -v -p '' -o bootx64.efi -O x86_64-efi fat part_msdos iso9660 gzio \
all_video gfxterm font terminal normal linux echo test search configfile cpuid minicmd
grub-mkimage: 情報: the total module size is 0x6ffb8.
grub-mkimage: 情報: reading /usr/lib64/grub/x86_64-efi/kernel.img.
grub-mkimage: 情報: locating the section .text at 0x0.
grub-mkimage: 情報: locating the section .rodata at 0x9600.
grub-mkimage: 情報: locating the section .rodata.str1.1 at 0x9798.
...
grub-mkimage: 情報: kernel_img=0x7fcad3119010, kernel_size=0x18200.
grub-mkimage: 情報: the core size is 0x881b8.
grub-mkimage: 情報: writing 0x89400 bytes.
今回組み込んだモジュールは、FATファイルシステム用のfat 、DOSパーティション用のpart_msdos 、CD/DVD用のiso9660 、圧縮ファイル用のgzio 、各種ビデオカードに対応するためのall_video 、グラフィカルターミナル用のgfxterm 、フォント回りを扱うfont 、ターミナル表示用のterminal 、通常モード用のnormal 、カーネルをロードするためのlinux 、スクリプト中で各機能を有効にするecho とtest 、指定されたファイルシステムを探すsearch 、設定ファイルを操作するconfigfile 、CPUの種類を調べるcpuid 、最低限のコマンドを実装するminicmd 、ということになります。
-p ''は起動時に必要なファイルを探すディレクトリを変更するための指定で、EFI版のgrubでは -p '' と指定すると/EFI/BOOT/以下にある設定ファイルを読みこむことになります。この指定をしないとデフォルトである/boot/grub/以下を探します。
grub-mkimageはgrubコアにこれらのモジュールを組み込み、バイナリ形式もPE32+に変更してEFIアプリケーションを生成します。
$ ls -lh bootx64.efi
-rw-r--r-- 1 kojima users 549K 2月 23日 23:12 bootx64.efi
$ file bootx64.efi
bootx64.efi: PE32+ executable (EFI application) x86-64 (stripped to external PDB), for MS Windows
次に、grub.cfg でこのgrubから読み込むカーネルとinitrd.gzを指定します。initrd.gzにはインストーラを動かすための小規模なLinux環境が入っています。Plamo Linuxのインストールメディアではカーネルとinitrd.gzはisolinuxディレクトリに置いているので、USBメモリから起動するための最小限の設定はこうなりました。
1: menuentry "UEFI Plamo Linux install from USB memory" {
2: linux (hd0)/isolinux/vmlinuz root=/dev/ram0 rw nomodeset vga16 unicon=eucjp vt.default_utf8=0 kbd=usbkbd
3: initrd (hd0)/isolinux/initrd.gz
4: }
2行目が読み込むカーネルと起動時のオプションの指定、3行目がinitrd.gzの指定です。なお、この設定はパーテイションを切らずにフォーマットしたUSBメモリの例で、パーティションを切ってフォーマットしたUSBメモリでは(hd0)
の部分が(hd0,msdos1)
のようになります。
こうして作成したbootx64.efiとgrub.cfgをUSBメモリの\EFI\BOOTディレクトリに、カーネルとinitrd.gzを\isolinuxディレクトリに置けば、UEFIはUSBメモリをUEFI対応メディアとして認識し、そこから起動できるようになりました。
図1 UEFIが起動メディアとして認識したUSBメモリ
DVDからのUEFI起動
USBメモリは小さなHDDと見なせるのでUEFIへの対応は比較的簡単なものの、CDやDVDからUEFIモードで起動するにはもう一工夫が必要です。というのも、Plamo Linuxのインストール用DVDでは、syslinux由来のisolinux.bin を使ってSystem BIOSから起動する形にしており、そのままではUEFIに対応できないためです。
さてどうしたものか、とあれこれ調べたところ、mkisofsでDVDイメージを作成する際に-eltorito-alt-boot オプションで複数のブートイメージを指定できることに気づきました。
El ToritoはISO9660形式のメディアからブートするために定められた規格です。この規格では一枚のCDでさまざまなOSに対応するため、CD中に複数のブートイメージを置くことが可能になっており、-eltorito-alt-bootはデフォルトとは異なるブートイメージを指定するオプションです。
UEFIから起動する場合、この-eltorito-alt-bootオプションで指定したブートイメージがESPとして認識されるので、このブートイメージの中に\EFI\BOOTディレクトリを作ってbootx64.efiを置けばUEFIはそれをOSのブートローダとして認識してくれそうです。
El Torito用のブートイメージは仮想的なFD として作成するので、まずはddコマンドでFDサイズ(1.44MB)のファイルを作り、そのファイルをFAT形式にフォーマットします。
$ dd if=/dev/zero of=efiboot.img bs=1k count=1440
$ /usr/sbin/mkfs.msdos -F 12 -M 0xf8 efiboot.img
mkfs.fat 3.0.26 (2014-03-07)
$
次にこのefiboot.imgをループバックでマウントし、必要なディレクトリを作ってブートローダをコピーします。
$ mkdir /tmp/loop
$ sudo mount efiboot.img /tmp/loop -o loop
$ sudo mkdir -p /tmp/loop/EFI/BOOT
$ sudo cp bootx64.efi /tmp/loop/EFI/BOOT
$ sudo umount /tmp/loop
DVDイメージはmkisofs を用いて作成します。mkisofsは指定したディレクトリにある全てのファイルをDVDイメージに書き込むので、作業用ディレクトリ(DVD_contents)にPlamo-6.x用のisolinuxディレクトリを持ってきて、そこに先ほど作ったefiboot.imgを置くことにします。
$ mkdir DVD_contents
$ cp -av /mnt2/Plamo-6.x/x86_64/isolinux ./DVD_contents/
$ cp efiboot.img ./DVD_contents/isolinux/
今回利用しているbootx64.efiはUSBメモリ用に作成したものを流用しているので、設定ファイルは/EFI/BOOT/grub.cfg を読むことになります。bootx64.efiはefiboot.img中の/EFI/BOOT/ディレクトリに置くものの、この仮想FDはUEFIがブートローダを探すためにのみ用いられbootx64.efiからは見えません。そのためgrub.cfgはDVDイメージの中の/EFI/BOOT/ に置く必要があります。
$ mkdir -p ./DVD_contents/EFI/BOOT
$ cat << 'EOF' > ./DVD_contents/EFI/BOOT/grub.cfg
menuentry "UEFI Plamo Linux install from DVD" {
linux (cd0)/isolinux/vmlinuz root=/dev/ram0 rw nomodeset vga16 unicon=eucjp vt.default_utf8=0 kbd=usbkbd
initrd (cd0)/isolinux/initrd.gz
}
EOF
必要なファイルが揃ったのでmkisofsを実行します。最初の2行がデフォルト(1つめ)のブートイメージの指定で、System BIOSから起動すると、ここで指定したisolinux.bin を利用します。3行目が2つめのブートイメージの指定で、UEFIから起動するとefiboot.img を用いることになります。
$ sudo mkisofs -v -J -r -b isolinux/isolinux.bin -c isolinux/boot.cat \
-no-emul-boot -boot-load-size 4 -boot-info-table \
-eltorito-alt-boot -eltorito-platform efi -eltorito-boot isolinux/efiboot.img \
-V UEFI-test -o UEFI-test.iso DVD_contents
Setting input-charset to 'UTF-8' from locale.
3.01 (x86_64-unknown-linux-gnu)
Scanning DVD_contents
Scanning DVD_contents/isolinux
Excluded by match: DVD_contents/isolinux/boot.cat
Writing: Initial Padblock Start Block 0
Done with: Initial Padblock Block(s) 16
...
75.29% done, estimate finish Wed Feb 24 16:29:21 2016
94.12% done, estimate finish Wed Feb 24 16:29:21 2016
Total translation table size: 2048
Total rockridge attributes bytes: 1690
Total directory bytes: 4096
Path table size(bytes): 26
Done with: The File(s) Block(s) 26390
Writing: Ending Padblock Start Block 26425
Done with: Ending Padblock Block(s) 150
Max brk space used 0
26575 extents written (51 MB)
$
なお、手元のisolinuxディレクトリにはefiboot.img以外にも下記のようなファイルを置いています。これらのうち、isolinux.bin とc32の拡張子を持つファイル はsyslinuxに由来し、isolinux.binの起動を補助します。isolinux.cfg はisolinux.bin用の設定ファイルです。その他はPlamo Linuxで作成したファイルで、vmlinuz とSystem.map はカーネルとシンボルテーブル、initrd.gz がインストーラの入ったミニLinux環境、plamo[46]1.lss はisolinux起動時に表示されるスプラッシュイメージ、sample.msg は起動時に表示されるメッセージ、boot.cat はmkisofsが生成するEl Torito用のカタログファイルになります。
$ ls DVD_cotents/isolinux/
System.map efiboot.img isolinux.bin ldlinux.c32 libutil.c32 plamo61.lss vesamenu.c32
boot.cat initrd.gz isolinux.cfg libcom32.c32 plamo41.lss sample.msg vmlinuz
こうして作ったDVDイメージ(UEFI-test.iso)は、UEFI環境から起動するとgrubが、System BIOS環境から起動するとisolinuxがそれぞれ起動し、起動環境に応じてインストールできるようになりました。
図2 UEFIから起動したgrub.cfgの起動画面
図3 System BIOSから起動したisolinux.cfgの起動画面
今回紹介したような形で、Plamo-6.xは一枚のDVDでUEFIとSystem BIOSに対応できるようになったものの、DVDイメージをベタ書きしたUSBメモリはSystem BIOSからしか起動できないようです。DVDイメージの中身をUSBメモリにコピーしてやればUEFIからも起動できるものの、USBメモリからUEFIブートする場合のみ手順が異なるのは気になるところです。DVDイメージには--uefiオプションを指定してisohybrid処理をしているので、本来はUEFIからでもベタ書きしたUSBメモリを起動できるはずですが、このあたりはもう少し修行が必要なようです。