Skip to content

Commit 71cd6d4

Browse files
committed
Fix Limine install with ESP mounted outside /boot
Place limine.conf next to the EFI binary on the ESP so it is found regardless of ESP mountpoint, and block unbootable layouts (non-UKI Limine with ESP not at /boot and no separate /boot partition) in GlobalMenu validation, guided.main() and _add_limine_bootloader(). Fixes #4333
1 parent cd62eff commit 71cd6d4

3 files changed

Lines changed: 53 additions & 5 deletions

File tree

archinstall/lib/global_menu.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
from pathlib import Path
12
from typing import override
23

34
from archinstall.default_profiles.profile import GreeterType
@@ -492,6 +493,11 @@ def _validate_bootloader(self) -> str | None:
492493
if bootloader == Bootloader.Limine:
493494
if boot_partition.fs_type not in [FilesystemType.FAT12, FilesystemType.FAT16, FilesystemType.FAT32]:
494495
return 'Limine does not support booting with a non-FAT boot partition'
496+
if self._uefi and efi_partition and boot_partition == efi_partition and efi_partition.mountpoint != Path('/boot') and not bootloader_config.uki:
497+
return (
498+
f'Limine requires kernels on a FAT partition. The ESP is mounted at {efi_partition.mountpoint}, '
499+
'enable UKI or add a separate /boot partition'
500+
)
495501

496502
elif bootloader == Bootloader.Refind:
497503
if not self._uefi:

archinstall/lib/installer.py

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1466,6 +1466,16 @@ def _add_limine_bootloader(
14661466
elif not efi_partition.mountpoint:
14671467
raise ValueError('EFI partition is not mounted')
14681468

1469+
# Limine can only read FAT filesystems. When the ESP doubles as
1470+
# the boot partition but is mounted outside /boot (e.g. /efi,
1471+
# /boot/efi) and UKI is disabled, kernels end up on the root
1472+
# filesystem under /boot/ which Limine cannot access.
1473+
if boot_partition == efi_partition and efi_partition.mountpoint != Path('/boot') and not uki_enabled:
1474+
raise DiskError(
1475+
f'Limine requires kernels on a FAT partition. The ESP is mounted at {efi_partition.mountpoint}, '
1476+
'so enable UKI or add a separate /boot partition to install Limine.',
1477+
)
1478+
14691479
info(f'Limine EFI partition: {efi_partition.dev_path}')
14701480

14711481
parent_dev_path = get_parent_device_path(efi_partition.safe_dev_path)
@@ -1476,15 +1486,11 @@ def _add_limine_bootloader(
14761486
if bootloader_removable:
14771487
efi_dir_path = efi_dir_path / 'BOOT'
14781488
efi_dir_path_target = efi_dir_path_target / 'BOOT'
1479-
1480-
boot_limine_path = self.target / 'boot' / 'limine'
1481-
boot_limine_path.mkdir(parents=True, exist_ok=True)
1482-
config_path = boot_limine_path / 'limine.conf'
14831489
else:
14841490
efi_dir_path = efi_dir_path / 'arch-limine'
14851491
efi_dir_path_target = efi_dir_path_target / 'arch-limine'
14861492

1487-
config_path = efi_dir_path / 'limine.conf'
1493+
config_path = efi_dir_path / 'limine.conf'
14881494

14891495
efi_dir_path.mkdir(parents=True, exist_ok=True)
14901496

archinstall/scripts/guided.py

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import os
22
import sys
33
import time
4+
from pathlib import Path
45

56
from archinstall.lib.applications.application_handler import ApplicationHandler
67
from archinstall.lib.args import ArchConfig, ArchConfigHandler
@@ -195,6 +196,35 @@ def perform_installation(
195196
pass
196197

197198

199+
def _check_bootloader_layout(config: ArchConfig) -> str | None:
200+
"""Validate bootloader configuration against disk layout.
201+
202+
Returns an error message if the configuration would produce an
203+
unbootable system, or None if it is valid.
204+
"""
205+
# Limine can only read FAT. When the ESP is the boot partition but
206+
# mounted outside /boot and UKI is disabled, the kernel ends up on the
207+
# root filesystem which Limine cannot access.
208+
if not (config.bootloader_config and config.bootloader_config.bootloader == Bootloader.Limine and not config.bootloader_config.uki and config.disk_config):
209+
return None
210+
211+
efi_part = next(
212+
(p for m in config.disk_config.device_modifications if (p := m.get_efi_partition())),
213+
None,
214+
)
215+
boot_part = next(
216+
(p for m in config.disk_config.device_modifications if (p := m.get_boot_partition())),
217+
None,
218+
)
219+
220+
if efi_part and boot_part == efi_part and efi_part.mountpoint != Path('/boot'):
221+
return (
222+
f'Limine requires kernels on a FAT partition. The ESP is mounted at {efi_part.mountpoint}, '
223+
'enable UKI or add a separate /boot partition to install Limine.'
224+
)
225+
return None
226+
227+
198228
def main(arch_config_handler: ArchConfigHandler | None = None) -> None:
199229
if arch_config_handler is None:
200230
arch_config_handler = ArchConfigHandler()
@@ -211,6 +241,12 @@ def main(arch_config_handler: ArchConfigHandler | None = None) -> None:
211241
config.write_debug()
212242
config.save()
213243

244+
# Safety net for silent/config-file flow. The TUI menu blocks Install via
245+
# GlobalMenu._validate_bootloader() before reaching this point.
246+
if err_msg := _check_bootloader_layout(arch_config_handler.config):
247+
error(err_msg)
248+
return
249+
214250
if arch_config_handler.args.dry_run:
215251
return
216252

0 commit comments

Comments
 (0)