From 4402b4b372d658b68869fc2fff529bea7153a876 Mon Sep 17 00:00:00 2001 From: "zhongling.h" Date: Wed, 9 Mar 2022 11:01:17 +0800 Subject: [PATCH] Support UEFI boot for metal and dvd Refer to commit 0a3a4da2aa,5bed36f33d9 from https://github.com/coreos/coreos-assembler.git ----- buildextend-live: drop shim fallback.efi from ISO; simplify EFI image UEFI boots from removable media via the arch-specific default EFI application in /EFI/BOOT. When booted that way, shim chains to fallback.efi if it exists, and fallback.efi creates an EFI boot entry. That's not appropriate for removable media boot, since the media will probably never be present again. If a TPM is present, fallback.efi will additionally reboot the machine, and on some machines this leads to boot loops. Instead of all this, we just want shim to chain directly to GRUB. The EFI boot image currently looks like this: EFI/BOOT/BOOTX64.EFI EFI/BOOT/fbx64.efi EFI/fedora/BOOTX64.CSV EFI/fedora/fonts/ EFI/fedora/grub.cfg EFI/fedora/grubx64.efi EFI/fedora/mmx64.efi EFI/fedora/shim.efi EFI/fedora/shimx64.efi Refactor the EFI boot image under the expectation that we never want to create or boot from an EFI boot entry. Consolidate /EFI/ into /EFI/BOOT and delete things we don't need: fallback.efi, its associated CSV, and extra copies of shim. The result is this: EFI/BOOT/BOOTX64.EFI EFI/BOOT/fonts/ EFI/BOOT/grub.cfg EFI/BOOT/grubx64.efi EFI/BOOT/mmx64.efi This also saves a couple MB of space. ----- buildextend-live: add stub grub.cfg to efiboot.img 05ba856 added an ESP to the ISO's hybrid GPT to help EFI systems that won't boot El Torito from a hard disk. However, when booting from the ESP, GRUB won't read the grub.cfg from the main ISO image, and just drops to a grub prompt. Add a stub grub.cfg that points GRUB to the right place. ----- Signed-off-by: zhongling.h --- src/cmd-buildextend-live | 60 ++++++++++++++++++++++++++++++++++++++++ src/create_disk.sh | 20 ++++++++------ 2 files changed, 71 insertions(+), 9 deletions(-) diff --git a/src/cmd-buildextend-live b/src/cmd-buildextend-live index 6d271bad..eba391c7 100755 --- a/src/cmd-buildextend-live +++ b/src/cmd-buildextend-live @@ -23,6 +23,12 @@ from cosalib.cmdlib import run_verbose, sha256sum_file from cosalib.cmdlib import import_ostree_commit, get_basearch from cosalib.meta import GenericBuildMeta +def ensure_glob(pathname, **kwargs): + '''Call glob.glob(), and fail if there are no results.''' + ret = glob.glob(pathname, **kwargs) + if not ret: + raise Exception(f'No matches for {pathname}') + return ret def ostree_extract_efi(repo, commit, destdir): """Given an OSTree commit, extract the EFI parts""" @@ -483,6 +489,60 @@ def generate_iso(): tmpimageefidir = os.path.join(tmpdir, "efi") ostree_extract_efi(repo, buildmeta_commit, tmpimageefidir) + # Find name of vendor directory + vendor_ids = [n for n in os.listdir(tmpimageefidir) if n != "BOOT"] + if len(vendor_ids) != 1: + raise Exception(f"did not find exactly one EFI vendor ID: {vendor_ids}") + + # Delete fallback and its CSV file. Its purpose is to create + # EFI boot variables, which we don't want when booting from + # removable media. + # + # A future shim release will merge fallback.efi into the main + # shim binary and enable the fallback behavior when the CSV + # exists. But for now, fail if fallback.efi is missing. + for path in ensure_glob(os.path.join(tmpimageefidir, "BOOT", "fb*.efi")): + os.unlink(path) + for path in ensure_glob(os.path.join(tmpimageefidir, vendor_ids[0], "BOOT*.CSV")): + os.unlink(path) + + # Drop vendor copies of shim; we already have it in BOOT*.EFI in + # BOOT + for path in ensure_glob(os.path.join(tmpimageefidir, vendor_ids[0], "shim*.efi")): + os.unlink(path) + + # Consolidate remaining files into BOOT. shim needs GRUB to be + # there, and the rest doesn't hurt. + for path in ensure_glob(os.path.join(tmpimageefidir, vendor_ids[0], "*")): + shutil.move(path, os.path.join(tmpimageefidir, "BOOT")) + os.rmdir(os.path.join(tmpimageefidir, vendor_ids[0])) + + # Inject a stub grub.cfg pointing to the one in the main ISO image. + # + # When booting via El Torito, this stub is not used; GRUB reads + # the ISO image directly using its own ISO support. This + # happens when booting from a CD device, or when the ISO is + # copied to a USB stick and booted on EFI firmware which prefers + # to boot a hard disk from an El Torito image if it has one. + # EDK II in QEMU behaves this way. + # + # This stub is used with EFI firmware which prefers to boot a + # hard disk from an ESP, or which cannot boot a hard disk via El + # Torito at all. In that case, GRUB thinks it booted from a + # partition of the disk (a fake ESP created by isohybrid, + # pointing to efiboot.img) and needs a grub.cfg there. + # + # IMPORTANT: For successful boot, please check exact path for + # grub.cfg in the first partition and change $prefix here. + # In most of the cases, like Fedora CoreOS, ($root)/EFI/{vendor[0]} + # will give you the right path, but there are exceptions. + with open(os.path.join(tmpimageefidir, "BOOT", "grub.cfg"), "w") as fh: + fh.write(f'''search --label "{volid}" --set root --no-floppy +set prefix=($root)/EFI/anolis +echo "Booting via ESP..." +configfile $prefix/grub.cfg +boot +''') # Install binaries from boot partition # Manually construct the tarball to ensure proper permissions and ownership efitarfile = tempfile.NamedTemporaryFile(suffix=".tar") diff --git a/src/create_disk.sh b/src/create_disk.sh index d5237e6d..996eb874 100755 --- a/src/create_disk.sh +++ b/src/create_disk.sh @@ -317,15 +317,17 @@ install_grub_cfg() { # Other arch-specific bootloader changes case "$arch" in x86_64) - install_grub_cfg - # And BIOS grub in addition. See also - # https://github.com/coreos/fedora-coreos-tracker/issues/32 - grub2-install \ - --fonts ascii \ - --target i386-pc \ - --install-modules 'test blscfg linux search configfile all_video serial gzio' \ - --boot-directory $rootfs/boot \ - $disk + install_uefi + if [ "${x86_bios_bootloader}" = 1 ]; then + # And BIOS grub in addition. See also + # https://github.com/coreos/fedora-coreos-tracker/issues/32 + grub2-install \ + --target i386-pc \ + --boot-directory $rootfs/boot \ + --modules mdraid1x \ + $disk + fi + ;; aarch64) # Our aarch64 is UEFI only. -- Gitee