mirror of
https://git.launchpad.net/livecd-rootfs
synced 2026-02-17 15:33:32 +00:00
Add architecture-specific boot configurators that translate the debian-cd boot shell scripts (boot-amd64, boot-arm64, boot-ppc64el, boot-riscv64, boot-s390x) into Python. The package uses a class hierarchy: - BaseBootConfigurator: abstract base with common functionality - GrubBootConfigurator: shared GRUB config generation - UEFIBootConfigurator: UEFI-specific shim/ESP handling - Architecture classes: AMD64, ARM64, PPC64EL, RISCV64, S390X A factory function make_boot_configurator_for_arch() creates the appropriate configurator for each architecture. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
169 lines
5.4 KiB
Python
169 lines
5.4 KiB
Python
"""UEFI boot configuration for AMD64 and ARM64 architectures."""
|
|
|
|
import pathlib
|
|
import shutil
|
|
|
|
from ..builder import Logger
|
|
from .grub import GrubBootConfigurator
|
|
|
|
|
|
def copy_signed_shim_grub_to_boot_tree(
|
|
shim_dir: pathlib.Path,
|
|
grub_dir: pathlib.Path,
|
|
efi_suffix: str,
|
|
grub_target: str,
|
|
boot_tree: pathlib.Path,
|
|
) -> None:
|
|
efi_boot_dir = boot_tree.joinpath("EFI", "boot")
|
|
efi_boot_dir.mkdir(parents=True, exist_ok=True)
|
|
|
|
shutil.copy(
|
|
shim_dir.joinpath("usr", "lib", "shim", f"shim{efi_suffix}.efi.signed.latest"),
|
|
efi_boot_dir.joinpath(f"boot{efi_suffix}.efi"),
|
|
)
|
|
shutil.copy(
|
|
shim_dir.joinpath("usr", "lib", "shim", f"mm{efi_suffix}.efi"),
|
|
efi_boot_dir.joinpath(f"mm{efi_suffix}.efi"),
|
|
)
|
|
shutil.copy(
|
|
grub_dir.joinpath(
|
|
"usr",
|
|
"lib",
|
|
"grub",
|
|
f"{grub_target}-efi-signed",
|
|
f"gcd{efi_suffix}.efi.signed",
|
|
),
|
|
efi_boot_dir.joinpath(f"grub{efi_suffix}.efi"),
|
|
)
|
|
|
|
grub_boot_dir = boot_tree.joinpath("boot", "grub", f"{grub_target}-efi")
|
|
grub_boot_dir.mkdir(parents=True, exist_ok=True)
|
|
|
|
src_grub_dir = grub_dir.joinpath("usr", "lib", "grub", f"{grub_target}-efi")
|
|
for mod_file in src_grub_dir.glob("*.mod"):
|
|
shutil.copy(mod_file, grub_boot_dir)
|
|
for lst_file in src_grub_dir.glob("*.lst"):
|
|
shutil.copy(lst_file, grub_boot_dir)
|
|
|
|
|
|
def create_eltorito_esp_image(
|
|
logger: Logger, boot_tree: pathlib.Path, target_file: pathlib.Path
|
|
) -> None:
|
|
logger.log("creating El Torito ESP image")
|
|
efi_dir = boot_tree.joinpath("EFI")
|
|
|
|
# Calculate size: du -s --apparent-size --block-size=1024 + 1024
|
|
result = logger.run(
|
|
["du", "-s", "--apparent-size", "--block-size=1024", efi_dir],
|
|
capture_output=True,
|
|
text=True,
|
|
check=True,
|
|
)
|
|
size_kb = int(result.stdout.split()[0]) + 1024
|
|
|
|
# Create filesystem: mkfs.msdos -n ESP -C -v
|
|
logger.run(
|
|
["mkfs.msdos", "-n", "ESP", "-C", "-v", target_file, str(size_kb)],
|
|
check=True,
|
|
)
|
|
|
|
# Copy files: mcopy -s -i target_file EFI ::/.
|
|
logger.run(["mcopy", "-s", "-i", target_file, efi_dir, "::/."], check=True)
|
|
|
|
|
|
class UEFIBootConfigurator(GrubBootConfigurator):
|
|
"""Base class for UEFI-based architectures (AMD64, ARM64).
|
|
|
|
Subclasses should set:
|
|
- efi_suffix: EFI binary suffix (e.g., "x64", "aa64")
|
|
- grub_target: GRUB target name (e.g., "x86_64", "arm64")
|
|
"""
|
|
|
|
# Subclasses must override these
|
|
efi_suffix: str = ""
|
|
grub_target: str = ""
|
|
arch: str = ""
|
|
|
|
def create_dirs(self, workdir):
|
|
super().create_dirs(workdir)
|
|
self.shim_dir = self.boot_tree.joinpath("shim")
|
|
|
|
def get_uefi_grub_packages(self) -> list[str]:
|
|
"""Return list of UEFI GRUB packages to download."""
|
|
return [
|
|
"grub2-common",
|
|
f"grub-efi-{self.arch}-bin",
|
|
f"grub-efi-{self.arch}-signed",
|
|
]
|
|
|
|
def extract_uefi_files(self) -> None:
|
|
"""Extract common UEFI files to boot tree."""
|
|
# Download UEFI packages
|
|
self.download_and_extract_package("shim-signed", self.shim_dir)
|
|
for pkg in self.get_uefi_grub_packages():
|
|
self.download_and_extract_package(pkg, self.grub_dir)
|
|
|
|
# Add common files for GRUB to tree
|
|
self.setup_grub_common_files()
|
|
|
|
# Add EFI GRUB to tree
|
|
copy_signed_shim_grub_to_boot_tree(
|
|
self.shim_dir,
|
|
self.grub_dir,
|
|
self.efi_suffix,
|
|
self.grub_target,
|
|
self.boot_tree,
|
|
)
|
|
|
|
# Create ESP image for El-Torito catalog and hybrid boot
|
|
create_eltorito_esp_image(
|
|
self.logger, self.boot_tree, self.scratch.joinpath("cd-boot-efi.img")
|
|
)
|
|
|
|
def write_uefi_menu_entries(self, grub_cfg: pathlib.Path) -> None:
|
|
"""Write UEFI firmware menu entries."""
|
|
with grub_cfg.open("a") as f:
|
|
f.write(
|
|
"""menuentry 'Boot from next volume' {
|
|
\texit 1
|
|
}
|
|
menuentry 'UEFI Firmware Settings' {
|
|
\tfwsetup
|
|
}
|
|
"""
|
|
)
|
|
|
|
def get_uefi_mkisofs_opts(self) -> list[str | pathlib.Path]:
|
|
"""Return common UEFI mkisofs options."""
|
|
# To make our ESP / El-Torito image compliant with MBR/GPT standards,
|
|
# we first append it as a partition and then point the El Torito at
|
|
# it. See https://lists.debian.org/debian-cd/2019/07/msg00007.html
|
|
opts: list[str | pathlib.Path] = [
|
|
"-append_partition",
|
|
"2",
|
|
"0xef",
|
|
self.scratch.joinpath("cd-boot-efi.img"),
|
|
"-appended_part_as_gpt",
|
|
]
|
|
|
|
# Some BIOSes ignore removable disks with no partitions marked bootable
|
|
# in the MBR. Make sure our protective MBR partition is marked bootable.
|
|
opts.append("--mbr-force-bootable")
|
|
|
|
# Start a new entry in the el torito boot catalog
|
|
opts.append("-eltorito-alt-boot")
|
|
|
|
# Specify where the el torito UEFI boot image "name". We use a special
|
|
# syntax available in latest xorriso to point at our newly-created
|
|
# partition.
|
|
opts.extend(["-e", "--interval:appended_partition_2:all::"])
|
|
|
|
# Whether to emulate a floppy or not is a per-boot-catalog-entry
|
|
# thing, so we need to say it again.
|
|
opts.append("-no-emul-boot")
|
|
|
|
# Create a partition table entry that covers the iso9660 filesystem
|
|
opts.extend(["-partition_offset", "16"])
|
|
|
|
return opts
|