Ubuntu 18.04をインストールしたUEFIのPCでブート可能なUSBメモリを作成する

同様の記事（例えば下記）がありますが、多少手順が違うので情報共有としてまとめておきます。

https://qiita.com/tchofu/items/6e6e0b243f45526b3a20

以下の手順は、インストーラのISOイメージを組み込んだ Live CD/DVD を作るのではなく、
Ubuntuをインストールした、BIOSに[UEFI](https://ja.wikipedia.org/wiki/Unified_Extensible_Firmware_Interface)を採用しているPCでブート可能なUSBメモリを作成するための手順です。

USBメモリのみを持ち運んでいろんなPCに刺して利用したいので、PCのメインのドライブにブートローダを入れるのではなく、USBのEFIシステムパーティションにブートローダ（Grub2）を書き込みます。

EFIシステムパーティションは自前で作成する必要がありますので、作成する手順はできるだけスクリプトにして確実に実行する形で進めます。

## 作業環境

今回動作確認をした環境は以下のとおりです。

* インストールするOSのISOイメージ: [Ubuntu 18.04.5 LTS (64bit版 ISOイメージ)](https://releases.ubuntu.com/18.04/ubuntu-18.04.5-desktop-amd64.iso)
* インストールするPC:
    * ハードウェア: ASUS TUF Gaming FX505DT
    * OS: Windows 10 Home (10.0.19042)
* 作業に使うVirtual Machine: VMware Workstation Player 16.1.1 build-17801498
* インストール対象のUSBメモリ（今回は32GBのものを利用）

## 手順

1. VMWare Playerで適当にUbuntu向けのVMを作成し、上記ISOイメージをマウントして立ち上げる。
   <br />仮想マシン設定 > CD/DVD(STAT) > ISOイメージファイルを利用する
1. 起動した Ubuntu Live CD で、Try Ubuntuを選択する
1. インストール対象のUSBメモリを Virtual Machine (VM) にマウントする
   <br />Player > 取り外し可能デバイス > [該当デバイス] > 接続（ホストから切断）
1. GParted を起動し、上記の USB メモリのパーティションを作成
    1. Device > Create Partition Table > Select new partition table type: gpt を選択
        <br />※msdosでも良いですが、gptを今回は選んでいます。
    1. fat32 の Primary Partition（サイズは128MB程度）を先頭に作成
        <br />※これがEFIシステムパーティションになります。
        1. Partition name: EFI
        1. Label: EFI
    1. 残りを ext4 に設定
        <br />※ブート時に検索キーとして Label を使うので、**ユニークな値にしてください**
        1. Partition name (例): Ubuntu-XXXXXX
        1. Label (例): Ubuntu-XXXXXX
1. VM のデスクトップにある「Ubuntu 18.04.05 LTSのインストール」アイコンからインストーラを起動し、インストールを行います。<br />
   その際、以下に注意してください：
    1. 「アップデートと他のソフトウェア」では以下を選択:
        1. [選択] 最小インストール<br />
            ※USBメモリは容量が少ないため。
        1. [選択] グラフィックスとWi-Fiハードウェア追加のメディアフォーマットのサードパーティ製ソフトウェアをインストールする
    1. 「インストールの種類」のインストール方法の選択画面では以下を選択：
        1. [選択] それ以外
    1. 「インストールの種類」のインストール先デバイス設定の画面では以下を実施：
        1. 前述のEFIシステムパーティションの利用方法を「予約済みBIOSブート領域」に設定<br />
            ※これは特に指定しなくても多分問題ありません。
        1. 前述のext4パーティションの利用方法を「ext4ジャーナリングファイルシステム」、マウントポイントを「/」に設定
        1. 「ブートローダをインストールするデバイス」を今回のUSBメモリに設定
1. EFIシステムパーティションに Grub をインストールします:
    1. 「Disks」アプリを開いて前述のEFIシステムパーティションをマウントします。<br />
        ※通常 `/media/ubuntu/EFI` にマウントされます。
    1. 後述のスクリプトを /media/ubuntu/EFI/prep.sh に配置し、Terminal 上で以下を実行します。<br />
       `cd /media/ubuntu/EFI && bash prep.sh`

## EFIシステムパーティションにGrubを配置するスクリプト

```bash
#!/bin/bash
VOL_LABEL=Ubuntu-XXXXXX
GRUB_ARCH=x86_64-efi
BOOT_IMAGE=BOOTx64.EFI
PRELOAD_MODULES="echo test search part_gpt part_msdos ntfs ntfscomp hfsplus fat ext2 normal chain boot configfile linux multiboot"

# 1. Install Grub package.
if [ ${GRUB_ARCH} = 'x86_64-efi' ]; then
if [ ! -d /usr/lib/grub/x86_64-efi ]; then
sudo apt install -y grub-efi-amd64-bin
fi
fi

[ -d ./EFI/BOOT ] || mkdir -p ./EFI/BOOT

pushd ./EFI/BOOT

# 2. Generate grub.cfg
cat <<EOI>grub.cfg
search --no-floppy --label ${VOL_LABEL} --set root
configfile (\$root)/boot/grub/grub.cfg
EOI

# 3. Generate Boot Image, with memdisk
grub-mkstandalone -d /usr/lib/grub/${GRUB_ARCH}/ -o ${BOOT_IMAGE} -O ${GRUB_ARCH} --modules="$PRELOAD_MODULES" -v /boot/grub/grub.cfg=grub.cfg;;

rm grub.cfg

popd
```

1. 今回の場合、64bit EFI 対応の Grub パッケージが必要なので、ない場合はインストールします。
2. `grub.cfg` は、`search` コマンドにより先ほど作成した `Ubuntu-XXXXXX` というラベルを持つパーティションを探して、そこにある `grub.cfg` を読み込んで実行するというだけの内容です。
    <br />※参考: GNU GRUB manual > [search](https://www.gnu.org/software/grub/manual/grub/html_node/search.html)
3. `grub-mkstandalone` は、`-O x86_64-efi` のように指定したフォーマットにしたがうブートイメージを作成してくれるコマンドです。これを使うと grub の依存ファイル群は memdisk としてブートイメージの中に保存されるため、ファイルを一つ配置するだけでよくなります。<br />
    オプションについての補足:
    1. `--modules="$PRELOAD_MODULES"` - Grub 起動時に自動的にロードされるモジュールを指定します。
        上記の例では以下のアイテムが列挙されています。
        ※実際にはこれより少ないモジュールで十分起動しますが、安全のために多めに入れています。
        1. `grub.cfg` で使っているコマンドに必要なモジュール: search configfile
        1. デバッグをするときに欲しい物: echo test
        1. パーティションテーブルを読むために必要なモジュール: part_gpt part_msdos
        1. ファイルシステムを読むために必要なモジュール: ntfs ntfscomp hfsplus fat ext2 
        1. ブートローダとして最低限必要そうな機能: normal chain boot linux multiboot
            <br />※参考: Ubuntu documentation > [UEFIBooting](https://help.ubuntu.com/community/UEFIBooting)
    1. `/boot/grub/grub.cfg=grub.cfg` - memdisk 上に配置するファイルを通常のものと置き換えたい場合にこの書き方をします。
        この場合、/boot/grub/grub.cfg をスクリプト中で作っている `grub.cfg` と差し替えます。

## 結果

手元の環境ではこの手順でブート可能になりました。
前述のASUSの環境の場合、以下のような手順になります。

1. ブート時にF2を押下して、UEFIの画面を表示。
1. F8を押下してブートドライブとして作成したUSBメモリを選択

以上でとりあえず無事ブートしました。

## 参考になったもの

https://bellbind.tumblr.com/post/45757405213/usb-hdd%E3%81%ABmbrefi%E4%B8%A1%E3%83%96%E3%83%BC%E3%83%88%E5%8F%AF%E8%83%BD%E3%81%AAubuntu%E3%82%A4%E3%83%A1%E3%83%BC%E3%82%B8%E3%82%92%E4%BD%9C%E3%82%8B%E6%96%B9%E6%B3%95

https://qiita.com/sushichop/items/346ca7ec92df8faa54be

https://help.ubuntu.com/community/UEFIBooting

## 最後に

今回利用しているブートローダは [GRUB 2](https://www.gnu.org/software/grub/) です。

ダイナミックにロードされるモジュール郡にどんな機能があるかの文書があまり整備されていないようで、手探りでやっているところがありますのでなにか間違っていたら教えて下さい。