備忘録 blog

Docker/Machine Learning/Linux

UEFI環境下でのgrubでLinuxとWindows 10をデュアルブートする

Windowsでのブートの制約

Dual boot with Windows - ArchWiki

上記より、Windows 10ではUEFI-GPTあるいはBIOS-MBRの組合せでしかブート出来ません。ところで旧来のBIOSブートに比べてUEFIブートは高速であることが知られています。またMBRに比べてGPTでは基本パーティション数の制限が緩和されているというように、UEFI-GPTブートがモダンなブート環境であることは間違いないでしょう。特にWindows 10をクリーンインストールするとき、デフォルトでパーティションを切ろうとするとEFI System Partition (ESP) を作る挙動がみられるように、UEFI-GPTでのブートを推奨しているようです。

ここでは、もともとLinuxを起動する際に用いていた従来のBIOS-MBR型で定義されていたgrubのブートをUEFIブートにリフトし、Windows 10とのデュアルブート環境を構築することを目論みます。grub2.02 rc2を用いました。

予めWindows 10の高速スタートアップ機能は無効にしておきましょう。

grub2の仕様

デュアルブート対象のLinux上で作業します。まずは既存のgrubから、UEFIWindowsをチェインして呼び出すことを考えます。そのためにはUEFIWindowsを認識させなければなりません。しかしos-proberを行っても、Windows Boot Managerを発見できません。そこでwikiを参照して/etc/grub.d/40_customに書き込んで、grub-mkconfigしました。

GRUB - ArchWiki

# grub-mkconfig -o /boot/grub/grub.cfg

こうしてgrubのエントリを追加すればもうWindows 10を起動できるようになったのかというとそうではなく、grubのメニューから追加したエントリを選択するとInvalid signatureと言って怒られます。これはBIOS型のgrubからUEFIブートローダーをチェインして起動することが出来ないためであると考えられます。

後で試してわかるのですが、LinuxBIOSブートで起動している場合はUEFIブートのOSを検出してくれませんが、UEFIブートで起動した場合はos-proberWindows Boot Managerを検出でき、systemd-bootやrEFIndと同様にgrub-mkconfigで自動でUEFIWindowsを探してくれます。そこで上記の手順を省略し、下記の方法でUEFIブートによって起動してからgrub-mkconfigを行えば、手動でWindowsのエントリを追加する必要はないと考えられます。

そこで次に、UEFIモードでgrubをインストールすることを考えます。UEFIの大きな特徴として、一つのESP内に複数のブートローダーを共存させることができます。 ここでは既存のMBRブートのパーティションを残し、Windows 10インストール時に生成したESPにWindows Boot Managerと共存させる形でgrubをインストールすることにしました。/dev/sda1がESPであったとします。

# mount /dev/sda1 /mnt
# grub-install --target=x86_64-efi --efi-directory=/mnt --bootloader-id=grub

としたいのですが、このコマンドを実行するとUEFI経由で起動しろと怒られます。

efibootmgr: EFI variables are not supported on this system.

この状況でUEFIブートを行ったとしても、このgrubは起動できません。ブートエントリにgrubが追記されていないためです。しかしUEFIのブートエントリに追加しようにも、内部的にはefibootmgrを用いているようですが、従来のBIOSブートで起動したlinux側からはそれを編集することができません。UEFIシェル上でbcfgコマンドでブートローダーを追記してもよいのですが、失敗するのが怖いのでgrubの機能を用いて自動でやってもらいたいと思います。そのためにはUEFI経由で起動する必要があります。

UEFIシェルを触る

先述の理由からUEFI経由で起動したいのですが、BIOSからUEFIの設定を変えてgrubから起動しようとしても、今grub-installしたブートローダーはエントリには表示されないので、UEFIシェルを叩いて直接起動するしかありません。BIOSのブートオプションでUEFI shellを選択します。このシェル画面で先ほどgrub-installしたefiファイルを実行します。

> fs1:
> cd EFI
> cd grub
> grubx64.efi

こうしてから起動すると、grubのブート画面が立ち上がります。この画面でLinuxを選択するとEFI経由で起動したことになるので、再びgrub-installすることでファームウェアのブートエントリにgrubを追記することができます。こうすると、再起動した時にUEFI経由でgrubの画面が表示され、Windows 10を選択するとgrub経由で起動できるようになります。

以上のようにして、grubによるWindows 10とLinuxのマルチブートを行いました。ただしこの場合、BIOSブートでインストールされたWindows 7などを今までのgrub経由でブートしていた場合は、UEFI経由のgrubからでは起動できなくなります。

関連URL

uefi

Unified Extensible Firmware Interface - ArchWiki

EFI システムパーティション - ArchWiki