2022年10月6日 星期四

支援 UEFI 光碟的開機載入程式 rEFInd

refind boot loader 的開機畫面 開機管理員我一直偏好用 extlinux 因為它的設定比 grub 簡單, 錯誤訊息也很清楚, 採用 UEFI模式從硬碟或隨身碟開機 也沒有問題。 唯一的問題是: 想要用 extlinux 做 UEFI 版的 iso 開機映象檔, 卻一直失敗。 看了 這一頁比較表, 決定試試看 rEFInd。 成功的用它製作 g22B 版的貴哥實驗室 iso 檔, 趕快筆記大推一下。 注意: rEFInd 只有 64 bit 版, 沒有 32 bit 版!

一、 把 refind 安裝在隨身碟上

第一個重點是: 不要用 debian 系列提供的套件。 不知道為什麼, 用 apt install refind 安裝的版本一直失敗。

  1. [2024/3] 保護好你的 UEFI 的 nvram!
  2. [2024/3] 到 官網 下載最新版 (我下載的是 refind-bin-0.14.0.2.zip ) 並解壓縮。 如果你下載的是 .deb 版, 而且你的 debian 系統較舊, 那就可能需要 把新版 zst 壓縮改成舊版 xz 壓縮
  3. 下載我打包的 refind-example.tgz 並且在隨身碟的根目錄解壓縮。 其中最重要的就是 EFI/BOOT/startup.nsh 跟 EFI/BOOT/refind.conf 兩個文字檔, 以及 EFI/BOOT/bootx64.efi 這個二進位檔 (其實就是官網版解壓縮裡面的 refind/refind_x64.efi )
  4. 把官網版解壓縮裡面的 refind/icons/ 子目錄也整個 copy 到 EFI/BOOT/ 底下。
  5. 下載 CorePure64slitaz-rolling-core64、 grml64-small 等等幾個 iso 檔其中至少一個, 都必須選 64 bit 的版本。 幫每個 distro 在隨身碟的根目錄底下各自建一個獨立的目錄, 並且把各自的最重要兩個或三個檔案複製過去。

最後隨身碟上面的檔案長得像以下這樣。 其中比較大的幾個二進位檔, 我列出他們的 md5sum 前6位, 方便檢查確認。 又, grml64-small.squashfs 被我改名為 root.squashfs 。

V       ./EFI/BOOT/startup.nsh
V       ./EFI/BOOT/refind.conf
f4fab7  ./EFI/BOOT/bootx64.efi
        ./EFI/BOOT/icons/arrow_left.png
        ./EFI/BOOT/icons/arrow_right.png
        ./EFI/BOOT/icons/boot_linux.png
        ./EFI/BOOT/icons/...
        ./EFI/BOOT/bg/alien-city.jpg
        ./EFI/BOOT/bg/...
ab7181  ./core/vmlinuz64
3bf1a8  ./core/corepure64.gz
a575a4  ./slitaz/bzImage64
b4c21b  ./slitaz/rootfs.gz
afd887  ./grml/vmlinuz
49e7ef  ./grml/initrd.img
c38c97  ./grml/root.squashfs

然後就可以 用 kvm 開 uefi 虛擬機測試 啦!

設定檔 refind.conf 裡面的 log_level 1 這一句的目的是要在 bootx64.efi 的同一目錄底下產生 log 檔 refind.log、 協助除錯。 例如我曾經試著用 refind 啟動 32bit 版的 core linux 跟 slitaz, 就是靠著這個 log 檔裡面抱怨 「invalid loader file」 之類的訊息而發現問題的。 要注意的是: 開機失敗之後所產生的 log 檔採用 utf16 編碼, 所以必須這樣閱讀: iconv -f UTF-16LE -t UTF-8 refind.log 。 成功開機之後, 可以把 log_level 1 那一句註解掉或是改成 log_level 0

其實也可以省略設定檔裡面的各個 menuentry, 把子目錄裡面的 drivers_x64/ext4_x64.efi 連同子目錄 一起複製到 EFI/BOOT:

...
f4fab7  ./EFI/BOOT/bootx64.efi
81b517  ./EFI/BOOT/drivers_x64/ext4_x64.efi
...

如此 refind 便會自動尋找每個 ext4 分割區上面某些特定目錄底下所安裝的 linux。 不過官網建議: 沒打算用到的檔案系統驅動程式最好不要複製過來, 以免浪費開機偵測時間, 甚至造成當機。 因為我現在都把系統根目錄放在 btrfs 的 subvolume 裡面, 覺得 refind 不太可能找得到 (還沒測試過) 所以還是習慣只用寫死的 menuentry 比較清楚簡單。

二、 把 refind 安裝在 .iso 映象檔裡

再來就拿 grml64-small_2021.07.iso 作練習, 把它原本 (內含 EFI 版 grub boot loader) 的 boot/efi.img 換掉。 請先檢視 vmlinuz 跟 initr.img 的大小, 自行決定要留多少空間(例如60M?)給映象檔。 以 root 的身份:

fallocate -l 60M refind.img
mkfs -t vfat refind.img
mount refind.img /mnt/t1
cp ... /mnt/t1
umount /mnt/t1

其中 cp 那一句代表要複製以下檔案:

V       ./EFI/BOOT/startup.nsh
V       ./EFI/BOOT/refind.conf
f4fab7  ./EFI/BOOT/bootx64.efi
        ./EFI/BOOT/bg/alien-city.jpg
        ./EFI/BOOT/icons/arrow_left.png
        ./EFI/BOOT/icons/...
49e7ef  ./grml/initrd.img
afd887  ./grml/vmlinuz

而 refind.conf 的內容如下:

timeout 20
banner bg/alien-city.jpg

menuentry "grml to RAM" {
    icon /EFI/BOOT/icons/os_grml.png
    loader /grml/vmlinuz
    initrd /grml/initrd.img
    options "boot=live live-media-path=/live/grml64-small/ toram=grml64-small.squashfs ignore_bootid"
}

最後把 refind.img 包進 iso 檔裡面:
export GRML_PATH=...
export OUT_PATH=...
cp refind.img $GRML_PATH/boot/
xorriso -as mkisofs -o $OUT_PATH/grml64-new.iso -b boot/isolinux/isolinux.bin -c boot/isolinux/boot.cat -no-emul-boot -boot-load-size 4 -boot-info-table -isohybrid-mbr /usr/lib/ISOLINUX/isohdpfx.bin -eltorito-alt-boot -e boot/refind.img -no-emul-boot $GRML_PATH

其中 $GRML_PATH 子目錄底下包含的就是從 grml64-small_2021.07.iso 裡面 copy 過來的所有檔案。 或是也可以採用 overlayfs 的方式, 在原始的 iso 檔上面架一層薄薄的可寫檔案系統。 如果這樣測試: kvm -m 2048 -pflash /usr/share/qemu/OVMF.fd -cdrom $OUT_PATH/grml64-new.iso 就會看到 refind 的開機選單; 如果這樣測試: kvm -m 2048 -cdrom $OUT_PATH/grml64-new.iso 則會看到原始的 isolinux 的開機選單。

特別注意: UEFI 光碟的開機途徑必須有自己的 vmlinuz 與 initrd.img 放在 refind.img 裡面, 因為 refind 的程式碼看不到外面對應的這兩個檔案。 至於作為 root file system 的 *.squashfs 則是由 initrd.img 所載入的, 所以只需要放一份。 我把 drivers_x64/iso9660_x64.efi 加到 refind.img 裡面去, 仍舊無法看到外面的這幾個開機檔案。 沒關係, 至少現在已經知道如何客製化 UEFI 開機光碟了, 耶!

沒有留言:

張貼留言

因為垃圾留言太多,現在改為審核後才發佈,請耐心等候一兩天。