Send patches - preferably formatted by git format-patch - to patches at archlinux32 dot org.
summaryrefslogtreecommitdiff
path: root/archinstall/lib
diff options
context:
space:
mode:
authorczapek <32851089+48cf@users.noreply.github.com>2023-11-21 10:19:17 +0100
committerGitHub <noreply@github.com>2023-11-21 10:19:17 +0100
commite6344f93f7e476d05bbcd642f2ed91fdde545870 (patch)
tree244045a4d9696abe0875ac73b955ef87d061b1cd /archinstall/lib
parentf16af43949085b06478d2e4c45ed61fa8e595171 (diff)
Fix Limine bootloader deployment (#2216)
* Add `get_unique_path_for_device` to `DeviceHandler` * Fix Limine bootloader deployment * Fail if UKI is enabled with Limine * Support more configuration options with Limine * Fix linter errors * Fix boot partition fs_type check for Limine
Diffstat (limited to 'archinstall/lib')
-rw-r--r--archinstall/lib/disk/device_handler.py14
-rw-r--r--archinstall/lib/global_menu.py7
-rw-r--r--archinstall/lib/installer.py135
3 files changed, 81 insertions, 75 deletions
diff --git a/archinstall/lib/disk/device_handler.py b/archinstall/lib/disk/device_handler.py
index 50e8c59c..fcf52013 100644
--- a/archinstall/lib/disk/device_handler.py
+++ b/archinstall/lib/disk/device_handler.py
@@ -133,6 +133,20 @@ class DeviceHandler(object):
lsblk = get_lsblk_info(dev_path)
return Path(f'/dev/{lsblk.pkname}')
+ def get_unique_path_for_device(self, dev_path: Path) -> Optional[Path]:
+ paths = Path('/dev/disk/by-id').glob('*')
+ linked_targets = {p.resolve(): p for p in paths}
+ linked_wwn_targets = {p: linked_targets[p] for p in linked_targets
+ if p.name.startswith('wwn-') or p.name.startswith('nvme-eui.')}
+
+ if dev_path in linked_wwn_targets:
+ return linked_wwn_targets[dev_path]
+
+ if dev_path in linked_targets:
+ return linked_targets[dev_path]
+
+ return None
+
def get_uuid_for_path(self, path: Path) -> Optional[str]:
partition = self.find_partition(path)
return partition.partuuid if partition else None
diff --git a/archinstall/lib/global_menu.py b/archinstall/lib/global_menu.py
index e4aa1235..d3d87603 100644
--- a/archinstall/lib/global_menu.py
+++ b/archinstall/lib/global_menu.py
@@ -363,8 +363,11 @@ class GlobalMenu(AbstractMenu):
if boot_partition is None:
return "Boot partition not found"
- if bootloader == Bootloader.Limine and boot_partition.fs_type == disk.FilesystemType.Btrfs:
- return "Limine bootloader does not support booting from BTRFS filesystem"
+ if bootloader == Bootloader.Limine:
+ if boot_partition.fs_type != disk.FilesystemType.Fat32:
+ return "Limine does not support booting from filesystems other than FAT32"
+ elif self._menu_options['uki'].current_selection:
+ return "Limine does not support booting UKIs"
return None
diff --git a/archinstall/lib/installer.py b/archinstall/lib/installer.py
index 2aa0d9dd..e2ca5e2b 100644
--- a/archinstall/lib/installer.py
+++ b/archinstall/lib/installer.py
@@ -972,70 +972,54 @@ class Installer:
def _add_limine_bootloader(
self,
boot_partition: disk.PartitionModification,
+ efi_partition: Optional[disk.PartitionModification],
root_partition: disk.PartitionModification
):
self.pacman.strap('limine')
- info(f"Limine boot partition: {boot_partition.dev_path}")
- root_uuid = root_partition.uuid
+ info(f"Limine boot partition: {boot_partition.dev_path}")
- def create_pacman_hook(contents: str):
- HOOK_DIR = "/etc/pacman.d/hooks"
- SysCommand(f"/usr/bin/arch-chroot {self.target} mkdir -p {HOOK_DIR}")
- SysCommand(f"/usr/bin/arch-chroot {self.target} sh -c \"echo '{contents}' > {HOOK_DIR}/liminedeploy.hook\"")
+ limine_path = self.target / 'usr' / 'share' / 'limine'
+ hook_command = None
if SysInfo.has_uefi():
+ if not efi_partition:
+ raise ValueError('Could not detect efi partition')
+ elif not efi_partition.mountpoint:
+ raise ValueError('EFI partition is not mounted')
+
+ info(f"Limine EFI partition: {efi_partition.dev_path}")
+
try:
- # The `limine.sys` file, contains stage 3 code.
- cmd = f'/usr/bin/arch-chroot' \
- f' {self.target}' \
- f' cp' \
- f' /usr/share/limine/BOOTX64.EFI' \
- f' /boot/EFI/BOOT/'
-
- SysCommand(cmd, peek_output=True)
- except SysCallError as err:
- raise DiskError(f"Failed to install Limine BOOTX64.EFI on {boot_partition.dev_path}: {err}")
+ efi_dir_path = self.target / efi_partition.mountpoint.relative_to('/') / 'EFI' / 'BOOT'
+ efi_dir_path.mkdir(parents=True, exist_ok=True)
- # Create the EFI limine pacman hook.
- create_pacman_hook("""
-[Trigger]
-Operation = Install
-Operation = Upgrade
-Type = Package
-Target = limine
+ for file in ('BOOTIA32.EFI', 'BOOTX64.EFI'):
+ shutil.copy(limine_path / file, efi_dir_path)
+ except Exception as err:
+ raise DiskError(f'Failed to install Limine in {self.target}{efi_partition.mountpoint}: {err}')
-[Action]
-Description = Deploying Limine after upgrade...
-When = PostTransaction
-Exec = /usr/bin/cp /usr/share/limine/BOOTX64.EFI /boot/EFI/BOOT/
- """)
+ hook_command = f'/usr/bin/cp /usr/share/limine/BOOTIA32.EFI {efi_partition.mountpoint}/EFI/BOOT/' \
+ f' && /usr/bin/cp /usr/share/limine/BOOTX64.EFI {efi_partition.mountpoint}/EFI/BOOT/'
else:
parent_dev_path = disk.device_handler.get_parent_device_path(boot_partition.safe_dev_path)
- try:
- # The `limine.sys` file, contains stage 3 code.
- cmd = f'/usr/bin/arch-chroot' \
- f' {self.target}' \
- f' cp' \
- f' /usr/share/limine/limine-bios.sys' \
- f' /boot/limine-bios.sys'
+ if unique_path := disk.device_handler.get_unique_path_for_device(parent_dev_path):
+ parent_dev_path = unique_path
- SysCommand(cmd, peek_output=True)
+ try:
+ # The `limine-bios.sys` file contains stage 3 code.
+ shutil.copy(limine_path / 'limine-bios.sys', self.target / 'boot')
# `limine bios-install` deploys the stage 1 and 2 to the disk.
- cmd = f'/usr/bin/arch-chroot' \
- f' {self.target}' \
- f' limine' \
- f' bios-install' \
- f' {parent_dev_path}'
+ SysCommand(f'/usr/bin/arch-chroot {self.target} limine bios-install {parent_dev_path}', peek_output=True)
+ except Exception as err:
+ raise DiskError(f'Failed to install Limine on {parent_dev_path}: {err}')
- SysCommand(cmd, peek_output=True)
- except SysCallError as err:
- raise DiskError(f"Failed to install Limine on {boot_partition.dev_path}: {err}")
+ hook_command = f'/usr/bin/limine bios-install {parent_dev_path}' \
+ f' && /usr/bin/cp /usr/share/limine/limine-bios.sys /boot/'
- create_pacman_hook(f"""
-[Trigger]
+ hook_contents = f'''[Trigger]
Operation = Install
Operation = Upgrade
Type = Package
@@ -1044,33 +1028,38 @@ Target = limine
[Action]
Description = Deploying Limine after upgrade...
When = PostTransaction
-# XXX: Kernel name descriptors cannot be used since they are not persistent and
-# can change after each boot.
-Exec = /bin/sh -c \\"/usr/bin/limine bios-install /dev/disk/by-uuid/{root_uuid} && /usr/bin/cp /usr/share/limine/limine-bios.sys /boot/\\"
- """)
+Exec = /bin/sh -c "{hook_command}"
+'''
- # Limine does not ship with a default configuration file. We are going to
- # create a basic one that is similar to the one GRUB generates.
- try:
- config = f"""
-TIMEOUT=5
-
-:Arch Linux
- PROTOCOL=linux
- KERNEL_PATH=boot:///vmlinuz-linux
- CMDLINE=root=UUID={root_uuid} rw rootfstype={root_partition.safe_fs_type.value} loglevel=3
- MODULE_PATH=boot:///initramfs-linux.img
-
-:Arch Linux (fallback)
- PROTOCOL=linux
- KERNEL_PATH=boot:///vmlinuz-linux
- CMDLINE=root=UUID={root_uuid} rw rootfstype={root_partition.safe_fs_type.value} loglevel=3
- MODULE_PATH=boot:///initramfs-linux-fallback.img
- """
-
- SysCommand(f"/usr/bin/arch-chroot {self.target} sh -c \"echo '{config}' > /boot/limine.cfg\"")
- except SysCallError as err:
- raise DiskError(f"Could not configure Limine: {err}")
+ hooks_dir = self.target / 'etc' / 'pacman.d' / 'hooks'
+ hooks_dir.mkdir(parents=True, exist_ok=True)
+
+ hook_path = hooks_dir / '99-limine.hook'
+ hook_path.write_text(hook_contents)
+
+ microcode = []
+
+ if ucode := self._get_microcode():
+ microcode = [f'MODULE_PATH=boot:///{ucode}']
+
+ kernel_params = ' '.join(self._get_kernel_params(root_partition))
+ config_contents = 'TIMEOUT=5\n'
+
+ for kernel in self.kernels:
+ for variant in ('', '-fallback'):
+ entry = [
+ f'PROTOCOL=linux',
+ f'KERNEL_PATH=boot:///vmlinuz-{kernel}',
+ *microcode,
+ f'MODULE_PATH=boot:///initramfs-{kernel}{variant}.img',
+ f'CMDLINE={kernel_params}',
+ ]
+
+ config_contents += f'\n:Arch Linux ({kernel}{variant})\n'
+ config_contents += '\n'.join([f' {it}' for it in entry]) + '\n'
+
+ config_path = self.target / 'boot' / 'limine.cfg'
+ config_path.write_text(config_contents)
self.helper_flags['bootloader'] = "limine"
@@ -1227,7 +1216,7 @@ TIMEOUT=5
case Bootloader.Efistub:
self._add_efistub_bootloader(boot_partition, root_partition, uki_enabled)
case Bootloader.Limine:
- self._add_limine_bootloader(boot_partition, root_partition)
+ self._add_limine_bootloader(boot_partition, efi_partition, root_partition)
def add_additional_packages(self, packages: Union[str, List[str]]) -> bool:
return self.pacman.strap(packages)