From a3ffdf2370899d060f6f708e2d6e31ae5b7b54bc Mon Sep 17 00:00:00 2001 From: Alejandro Sirgo Rica Date: Thu, 7 Mar 2024 13:27:09 +0100 Subject: utils: implement BIOS boot for Linux Create a bios.py file to hold all the BIOS specific functions. Implement the _boot_bios_linux in Python. The new boot process tries to find the vmlinuz and initrd binaries at the desired partition. Then it tries to load them with kexec with the proper Grub boot params. One step closer to the removal of the boot legacy script. --- src/utils/bios.py | 53 +++++++++++++++++++++++++++++++++++++++++++++++++++++ src/utils/boot.py | 18 +++++++++++++++++- 2 files changed, 70 insertions(+), 1 deletion(-) create mode 100644 src/utils/bios.py diff --git a/src/utils/bios.py b/src/utils/bios.py new file mode 100644 index 0000000..e064ca0 --- /dev/null +++ b/src/utils/bios.py @@ -0,0 +1,53 @@ +# +# Copyright (C) 2023 Soleta Networks +# +# This program is free software: you can redistribute it and/or modify it under +# the terms of the GNU Affero General Public License as published by the +# Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. + +import logging +import os + + +def get_grub_boot_params(mountpoint, device): + grub_conf = f'{mountpoint}/etc/default/grub' + res = [] + + with open(grub_conf, 'r') as f: + for line in f: + if line.find('=') == -1: + continue + key, value = line.split('=', 1) + if key == 'GRUB_CMDLINE_LINUX' or key == 'GRUB_CMDLINE_LINUE_DEFAULT': + value = value.replace('\n', '') + value = value.strip('"') + res.append(value) + res.append(f'root={device}') + return " ".join(res) + +def get_vmlinuz_path(mountpoint): + linuz_dir = os.path.join(mountpoint, 'boot') + target_file = None + + for file in sorted(os.listdir(linuz_dir)): + if file.startswith('vmlinuz-'): + target_file = file + + if not target_file: + raise FileNotFoundError('vmlinuz not found in {initrd_dir}') + + return os.path.join(linuz_dir, target_file) + +def get_initrd_path(mountpoint): + initrd_dir = os.path.join(mountpoint, 'boot') + target_file = None + + for file in sorted(os.listdir(initrd_dir)): + if file.startswith('initrd.img-') or file.startswith('initramfs-') and file.endswith('.img'): + target_file = file + + if not target_file: + raise FileNotFoundError('initrd not found in {initrd_dir}') + + return os.path.join(initrd_dir, target_file) diff --git a/src/utils/boot.py b/src/utils/boot.py index 07a29ba..724fc06 100644 --- a/src/utils/boot.py +++ b/src/utils/boot.py @@ -14,6 +14,7 @@ import subprocess from src.utils.probe import OSFamily, get_os_family, get_linux_distro_id, os_probe from src.utils.disk import get_partition_device, get_efi_partition +from src.utils.bios import * from src.utils.uefi import * from src.utils.fs import * @@ -27,7 +28,22 @@ def _boot_bios_linux(disk, part, mountpoint): if not get_linux_distro_id(mountpoint) == 'ubuntu': raise NotImplementedError(f'{os_probe(mountpoint)} detected, only Ubuntu is supported for legacy BIOS boot') - _boot_bios_legacy(disk, part, mountpoint) + kernel_path = get_vmlinuz_path(mountpoint) + initrd_path = get_initrd_path(mountpoint) + + device = get_partition_device(disk, part) + grub_boot_params = get_grub_boot_params(mountpoint, device) + + kexec_cmd = f'kexec -l {kernel_path} --append="{grub_boot_params}" --initrd="{initrd_path}"' + kexec_reboot_cmd = 'kexec -e' + + logging.info(f'Booting with: {kexec_cmd}') + try: + subprocess.run(shlex.split(kexec_cmd), check=True, text=True) + subprocess.run(shlex.split(kexec_reboot_cmd), check=True, text=True) + except subprocess.CalledProcessError as e: + logging.error(f'Error processing kexec: {e}') + raise e def _boot_bios_windows(disk, part, mountpoint): logging.info(f'Booting Windows system') -- cgit v1.2.3-18-g5258