BitVisor を UEFI 環境にインストールするときの EFI エントリーの設定手順

# はじめに

BitVisor を UEFI 環境にインストールする機会があったので、その手順をまとめます。 内容は EFI のブートエントリーの設定をしているだけで真新しいことは特にないですが、いつかまた自分が同じことをする時のために書き残そうと思います。


<a id="org3dd6a05"></a>

# 目標

UEFI 環境で以下のように BitVisor の起動ができるようにする。

-   OS の再起動前に何かしらの操作(コマンドを実行)をした場合にだけ、再起動後に BitVisor が起動する。
-   何も指定せずに再起動した際には、BitVisor なしで OS が起動する。

このようにしたいのは、壊れた BitVisor のバイナリをインストールしてしまった時でもマシンを再起動すれば復帰できるようにしたいためです。リモートマシンで BitVisor の開発をする際に、このようになっていると非常に便利です。


<a id="org7f0b939"></a>

# 対象環境

-   CentOS 8
-   UEFI ブート
-   `/boot/efi` 以下に EFI パーティションをマウント


<a id="orgb87d37e"></a>

# 問題

UEFI + Grub 環境で BitVisor を起動する方法や BIOS + Grub 環境で上記条件を満たす設定の方法については、既に解説記事があります。

-   **BitVisorをUbuntu 18.04.1でビルドしてUEFIブートする(GRUB2) by @morimolymoly:** <https://qiita.com/morimolymoly/items/a571942880d8ba55f037>
-   **BitVisor を Grub 経由で起動するときの便利設定 by @deep_tkkn:** <https://qiita.com/deep_tkkn/items/30b44f89321d414d6a30>

しかし、これらを組み合わせようとしても上記の目標はうまく達せられませんでした&#x2026; 
(詳細はあまり調べていませんが、おそらく UEFI 環境の GRUB で `chainload loadvmm.efi` とすると、その後 GRUB に戻って来ずに別の UEFI エントリーを起動しようとしてしまうためにうまくいかないのだと思います。) 

そこで、今回は Grub ではなく EFI の boot entry を設定することで解決したいと思います。


<a id="org4460ba0"></a>

# 設定方法


<a id="orgf9cf9f4"></a>

## BitVisor の準備

まずは BitVisor をダウンロードして、 `bitvisor.elf` と `loadvmm.efi` をビルドします。 これらの方法は、[先出の解説記事](https://qiita.com/morimolymoly/items/a571942880d8ba55f037) に詳しく解説されていますので，ここではコマンドリストだけ載せます。

```shell
yum install mercurial gcc make mingw64-gcc #mingw64-gcc は loadvmm.efi のビルドに必要
hg clone http://hg.code.sf.net/p/bitvisor/code bitvisor
cd bitvisor
make config # 適当にオプションを指定
make -j3 #並列数はコアの数などに合わせてお好みでどうぞ
make -C boot/uefi-loader
popd
sudo cp bitvisor.elf boot/uefi-loader/loadvmm.efi /boot/efi/EFI/BOOT/
```


<a id="orgc97aeb7"></a>

## EFI ブートエントリーの設定

基本的には `efibootmgr` を使ってブートエントリーの設定をするだけで設定できます。 手順は以下の3つ

1.  ブートエントリーの追加
2.  エントリーの優先順位の設定
3.  (BitVisor の起動前) 次回起動するエントリーの指定

コマンドとしては以下の3つだけです。

```shell
efibootmgr --create --disk /dev/sdX --part 1  --loader \\EFI\\BOOT\\loadvmm.efi --label BitVisor #エントリー追加
efibootmgr -o 0003,0004,0000,0005,0001,0002 #OS のエントリーが優先されるように変更
efibootmgr -n $(efibootmgr | grep BitVisor | cut -c 5-8) #BitVisor を起動したい時のみ実行
```

詳しくは以下で説明します。


<a id="orgd81ef98"></a>

### ブートエントリーの追加

まずは `efibootmgr` で現在のブートエントリーの状態を確認しておきます。

    # efibootmgr
    BootCurrent: 0003
    Timeout: 1 seconds
    BootOrder: 0003,0000,0005,0001,0002
    Boot0000* CentOS Linux
    Boot0001* Hard Drive
    Boot0002* USB
    Boot0003* CentOS Linux
    Boot0005* UEFI OS
    #

この `BootOrder: 0003,0000,0005,0001,0002` というところをメモしておくと、あとで起動順序を設定するときに迷わなくて済むと思います。 次にブートエントリーを追加します。以下のコマンドでエントリーを追加できます。

```shell
efibootmgr --create --disk /dev/sdX --part 1  --loader \\EFI\\BOOT\\loadvmm.efi --label BitVisor
```

オプションの意味は以下の通りです。

-   **`--disk /dev/sdX`:** EFI パーティションのあるブロックデバイスを指定。UUID で指定しなくても `efibootmgr` 側でよしなにやってくれます。
-   **`--part 1`:** パーティション番号を指定。例えば `/dev/sda2` に EFI パーティションがある場合は `2` を指定してください。
-   **`--loader \\EFI\\BOOT\\loadvmm.efi`:** ブートローダーの EFI ファイルのパスを指定。パーティション内のルートからのパスを Windows 風 (`\` 区切り)で指定します。エスケープのために区切り文字が `\\` になる点に注意してください。
-   **`--label BitVisor`:** ブートエントリーにつけるラベル (名前) を指定。お好みで分かり易い名前をつけましょう。


<a id="org359648a"></a>

### エントリーの優先順位の変更

エントリーの追加後、再度ブートエントリーの状態を確認します。

    # efibootmgr
    BootCurrent: 0003
    Timeout: 1 seconds
    BootOrder: 0004,0003,0005,0001,0002
    Boot0001* Hard Drive
    Boot0002* USB
    Boot0003* CentOS Linux
    Boot0004* BitVisor
    Boot0005* UEFI OS

ここでは、0004 に BitVisor のエントリーが追加されています。 また、BootOrder は 0004 が最優先になっているため、このまま再起動すると BitVisor が常に起動指定します。 これは避けたいので、以下のコマンドで起動順序の設定を行います。

```shell
efibootmgr -o 0003,0004,0000,0005,0001,0002   
```

見ての通り `efibootmgr -o` の後にカンマ区切りでブートエントリーの番号を指定すれば OK です。 今回は元々最優先だったエントリー 0003 を最初に持ってきて、それ以外は変更なしという風にしました。 これで、普通に再起動すれば BitVisor ではなく CentOS が起動するようになります。


<a id="org324a1de"></a>

### 次回起動時に選択するエントリーの指定

efibootmgr で次回起動時に選択する EFI ブートエントリーを一時的に変更することができます。 再起動前に以下のコマンドで BitVisor のエントリーを一時的に選択するようにすれば、BitVisor の起動もできます。

```shell
efibootmgr -n $(efibootmgr | grep BitVisor | cut -c 5-8)
# reboot で再起動後 BitVisor --> CentOS の順で起動
```


<a id="orgf2068a2"></a>

### efibootmgr に関して参考にしたページ

-   **efibootmgr その2 - UEFIブートマネージャーにブートローダーを登録する:** <https://kledgeb.blogspot.com/2015/11/efibootmgr-2-uefi.html>
-   **efibootmgr その4 - エントリーの起動順を変更する・重複したエントリーの起動順を削除する・エントリーの起動順を削除する:** <https://kledgeb.blogspot.com/2015/11/efibootmgr-4.html>
-   **efibootmgr その5 - PCの次回起動時に1度だけ実行するエントリーを設定する・PCの次回起動時に1度だけ実行するエントリーを削除する:** <https://kledgeb.blogspot.com/2015/11/efibootmgr-5-pc1pc1.html>


<a id="orgb539153"></a>

# おわりに

上記設定で、

-   BitVisor を起動したいときには `efibootmgr -n $(efibootmgr | grep BitVisor | cut -c 5-8)` 実行後に再起動
-   BitVisor なしで再起動したいときにはなにもせずに再起動

という風に使えます。 ssh 越しでも BitVisor を起動したりしなかったりの制御ができるため便利かと思います。