EFI ブートスタブ

提供: ArchWiki
2015年1月12日 (月) 19:47時点におけるKusakata (トーク | 投稿記録)による版 (1版 をインポートしました)
ナビゲーションに移動 検索に移動

関連記事

警告: カーネルバージョンとマザーボードのモデルによっては EFISTUB の起動が失敗するというバグが報告されています。詳しくは [1][2] を見て下さい。

Linux カーネル (linux>=3.3) は EFISTUB (EFI BOOT STUB) ブートをサポートしています。カーネル設定で CONFIG_EFI_STUB=y を設定することで有効にすることができ、Arch Linux のカーネルではデフォルトで有効にされています (詳しくは EFI Boot Stub を参照してください)。

EFISTUB カーネルだけでは他のカーネルを起動することはできません。よってブートメニューエントリごとに EFISTUB カーネル + Initramfs のペアが必要です。このため、複数のカーネルを使う場合は、UEFI Boot Manager を使うことが推奨されています。

EFISTUB の設定

  1. EFI System Partition を作成してください。
  2. /boot (推奨) かどこか他の好きなところに (他のディストロやツールは大抵 /boot/efi を使っています) EFI System Partition をマウントしてください。以後このマウントポイントは $esp として示します。

カーネルと initramfs を ESP にコピーする

警告: この手順は EFISYS のマウントポイントとして /boot を使っていない場合にのみ必要です。マウントポイントとして /boot を選んだ時は、#EFISTUB の起動 に進むことができます。
  1. $esp/EFI/arch/ を作成してください
  2. 以下のファイルを移動元から移動先にコピーしてください
ブートファイルの移動元 UEFI の移動先
/boot/vmlinuz-linux $esp/EFI/arch/vmlinuz-arch.efi
/boot/initramfs-linux.img $esp/EFI/arch/initramfs-arch.img
/boot/initramfs-linux-fallback.img $esp/EFI/arch/initramfs-arch-fallback.img
警告: カーネルがアップデートされる度に EFISTUB カーネルを更新する必要があります。また、以下の方法のどれか一つを使うことで EFISTUB カーネルを自動で更新することができます:

systemd

Systemd にはイベントトリガータスク機能があります。これで、パス上の変更を検知する能力を使って、boot にある EFISTUB カーネルと initramfs のファイルが更新されたときにそれらを同期させることが可能です。

警告: mkinitcpio がカーネルスタブと initramfs を作成するのには時間がかかるので、以下の systemd サービスが新しいカーネルスタブと initramfs の代わりに古いものをコピーしてしまう可能性があります。このエラーの可能性を減らすために、(mkinitcpio によって最後に作成される) initramfs-linux-fallback.img が更新されたか確認する efistub のコピーサービスをバインドすると良いでしょう。
/etc/systemd/system/efistub-update.path
[Unit]
Description=Copy EFISTUB Kernel to UEFISYS Partition

[Path]
PathChanged=/boot/initramfs-linux-fallback.img

[Install]
WantedBy=multi-user.target
/etc/systemd/system/efistub-update.service
[Unit]
Description=Copy EFISTUB Kernel to UEFISYS Partition

[Service]
Type=oneshot
ExecStart=/usr/bin/cp -f /boot/vmlinuz-linux $esp/EFI/arch/vmlinuz-arch.efi
ExecStart=/usr/bin/cp -f /boot/initramfs-linux.img $esp/EFI/arch/initramfs-arch.img
ExecStart=/usr/bin/cp -f /boot/initramfs-linux-fallback.img $esp/EFI/arch/initramfs-arch-fallback.img

次のコマンドでサービスを有効にしてください:

# systemctl enable efistub-update.path

Incron

incron を使って更新後に EFISTUB カーネルを同期するスクリプトを実行することができます。

ヒント: 下のスクリプトを /usr/local/bin/efistub-update.sh として保存してください
#!/usr/bin/env bash
/usr/bin/cp -f /boot/vmlinuz-linux $esp/EFI/arch/vmlinuz-arch.efi
/usr/bin/cp -f /boot/initramfs-linux.img $esp/EFI/arch/initramfs-arch.img
/usr/bin/cp -f /boot/initramfs-linux-fallback.img $esp/EFI/arch/initramfs-arch-fallback.img
ヒント: 下のスクリプトを /etc/incron.d/efistub-update.conf として保存してください
ノート: 最初のパラメータ /boot/initramfs-linux-fallback.img は監視するファイルです。2番目のパラメータ IN_CLOSE_WRITE は監視するイベントです。3番目のパラメータ /usr/local/bin/efistub-update.sh は起動するスクリプトです。
/boot/initramfs-linux-fallback.img IN_CLOSE_WRITE /usr/local/bin/efistub-update.sh
ヒント: この方法を使うには、incron が有効になっている必要があります。有効になっていない場合は次を実行してください
# systemctl enable incrond.service

Mkinitcpio フック

Mkinitcpio はフックを生成することができシステムレベルデーモンを機能させる必要はありません。ファイルをコピーする前にバックグラウンドプロセスを生成して vm-linuz, initramfs-linux.img, initramfs-linux-fallback.img の生成を待ちます。

ヒント: 下のスクリプトを /usr/lib/initcpio/install/efistub-update として保存してください
#!/usr/bin/env bash

build() {
	/root/watch.sh &
}

help() {
	cat <<HELPEOF
This hook waits for mkinitcpio to finish and copies the finished ramdisk and kernel to the ESP
HELPEOF
}
ヒント: 下のスクリプトを /root/watch.sh として保存し実行可能にしてください
#!/usr/bin/env bash

while [[ -d "/proc/$PPID" ]]; do
	sleep 1
done

/usr/bin/cp -f /boot/vmlinuz-linux $esp/EFI/arch/vmlinuz-arch.efi
/usr/bin/cp -f /boot/initramfs-linux.img $esp/EFI/arch/initramfs-arch.img
/usr/bin/cp -f /boot/initramfs-linux-fallback.img $esp/EFI/arch/initramfs-arch-fallback.img

echo "Synced kernel with ESP"
ヒント: efistub-update/etc/mkinitcpio.conf 内の hook のリストに加えて下さい

バインドマウント

ESP を /boot にマウントする代わりに、バインドマウントを使うことで ESP のディレクトリを /boot にマウントすることができます (mount(8) を参照)。これによって ESP を自由に扱えるようにしつつ pacman が直接カーネルを更新できるようにすることができます。ファイルをコピーする他の方法よりもずっとシンプルな方法になります。

ノート: バインドマウントを利用するには FAT32 に対応するカーネルとブートローダーが必要です。通常の Arch のインストールでは問題になりませんが、他のディストリビューションでは問題になることがあります (つまり /boot にシンボリックリンクを必要とするディストリビューション)。フォーラムのこの投稿を見て下さい。

に書かれているように、ESP のディレクトリに全てのブートファイルをコピーしますが、ESP は /boot の外にマウントします (例: /esp)。そしてディレクトリをバインドマウントします:

# mount --bind /esp/EFI/arch/ /boot

ファイルが /boot に現れるようにしたい場合、fstab を編集して永続化させます:

/etc/fstab
/esp/EFI/arch /boot none defaults,bind 0 0
警告: この方法を使って起動するには root=system_root カーネルパラメータを使う必要があります。

EFISTUB の起動

警告: Linux Kernel EFISTUB initramfs のパスは EFI System Partition のルートからの相対パスでなければなりません。例えば、initramfs が $esp/EFI/arch/initramfs-linux.img にあったとしたら、適切な UEFI 行は initrd=/EFI/arch/initramfs-linux.imginitrd=\EFI\arch\initramfs-linux.img になります。

以下の方法のどれか一つを使うことで EFISTUB カーネルを起動することができます:

gummiboot を使う

Gummiboot は EFISTUB カーネルのナイスなメニューを提供する UEFI Boot Manager です。EFISTUB ブートの推奨ブートマネージャです。詳細は gummiboot を見て下さい。

rEFInd を使う

rEFInd は (Intel Mac で使われている) rEFIt Boot Manager の Rod Smith (GPT-fdisk の作者) によるフォークです。rEFInd は Mac 以外の UEFI ブートについて rEFIt の多くの問題を修正してあり EFISTUB カーネルをサポートしています。詳しくは rEFInd を見て下さい。

UEFI Shell を使う

通常の UEFI アプリケーションのように UEFI Shell から EFISTUB カーネルを起動することが可能です。この場合カーネルパラメータは通常のパラメータとして起動する EFISTUB カーネルファイルに渡します。

> fs0:
> cd \EFI\arch
> vmlinuz-arch.efi root=PARTUUID=3518bb68-d01e-45c9-b973-0b5d918aae96 rootfstype=ext4 add_efi_memmap initrd=EFI/arch/initramfs-arch.img

また、ブートパラメータを記述したシンプルな archlinux.nsh ファイルを書いて UEFI System Partition に置き、それを実行することもできます:

> fs0:
> archlinux

スクリプト例:

$ESP/archlinux.nsh
echo -on
\EFI\arch\vmlinuz-arch.efi root=PARTUUID=3518bb68-d01e-45c9-b973-0b5d918aae96 rootfstype=ext4 add_efi_memmap initrd=/EFI/arch/initramfs-arch.img

この方法では名前をメモしておいたり20-30文字も入力せずとも UUID を指定することができます。

ブートマネージャを使わずに直接起動する

警告: カーネルと efibootmgr の組み合わせによっては手動で調整しないと動かないことがあります [3]。ブートエントリを削除することはできますが作成することは出来なくなります。
ノート: UEFI ファームウェアによってはブートエントリの uefi アプリケーションにコマンドラインパラメータを埋め込むことができません。

UEFI ブートエントリに直接カーネルパラメータを埋め込むことが可能です。つまりあなたの UEFI ブートオーダー・GUI を使って GRUB など他のブートローダーを使わずに直接 Arch Linux を起動することができます (下のコマンドの XY は EFI System Partition があるディスクとパーティションに置き換えてください、root= パラメータは root にあわせて変更してください)。

# mount -t efivarfs efivarfs /sys/firmware/efi/efivars              # 既にマウントされている場合は無視して下さい
# efibootmgr -d /dev/sdX -p Y -c -L "Arch Linux" -l /vmlinuz-linux -u "root=/dev/sda2 rw initrd=/initramfs-linux.img"

作成されたエントリが問題ないか確認するために次のコマンドを実行すると良いでしょう:

# efibootmgr -v

ブートの順番を設定するには、次を実行します:

# efibootmgr -o XXXX,XXXX

XXXX は `efibootmgr` コマンドによって出力されるそれぞれのエントリの番号に置き換えてください。

ヒント: シェルスクリプトでブートエントリを作成するコマンドをどこかに保存しておけば、修正 (例えばカーネルパラメータの変更) が楽になります。

efibootmgr の詳細は UEFI#efibootmgr で説明しています。フォーラムの投稿 https://bbs.archlinux.org/viewtopic.php?pid=1090040#p1090040