Send patches - preferably formatted by git format-patch - to patches at archlinux32 dot org.
summaryrefslogtreecommitdiff
path: root/archinstall/lib/installer.py
diff options
context:
space:
mode:
authorcodefiles <11915375+codefiles@users.noreply.github.com>2023-10-17 05:23:09 -0400
committerGitHub <noreply@github.com>2023-10-17 11:23:09 +0200
commitbc3b3a35e6408144587f8c2ace95c4ac68d53bcc (patch)
treeae878156a279466146893bfa0fcc7d19a9438278 /archinstall/lib/installer.py
parent332ec0d6236ca863cb6a2101849555935066549f (diff)
Add support for unified kernel image (#1519)
Diffstat (limited to 'archinstall/lib/installer.py')
-rw-r--r--archinstall/lib/installer.py166
1 files changed, 121 insertions, 45 deletions
diff --git a/archinstall/lib/installer.py b/archinstall/lib/installer.py
index 39298204..4d6c65b3 100644
--- a/archinstall/lib/installer.py
+++ b/archinstall/lib/installer.py
@@ -542,18 +542,13 @@ class Installer:
return True
- def mkinitcpio(self, flags: List[str], locale_config: LocaleConfiguration) -> bool:
+ def mkinitcpio(self, flags: List[str]) -> bool:
for plugin in plugins.values():
if hasattr(plugin, 'on_mkinitcpio'):
# Allow plugins to override the usage of mkinitcpio altogether.
if plugin.on_mkinitcpio(self):
return True
- # mkinitcpio will error out if there's no vconsole.
- if (vconsole := Path(f"{self.target}/etc/vconsole.conf")).exists() is False:
- with vconsole.open('w') as fh:
- fh.write(f"KEYMAP={locale_config.kb_layout}\n")
-
with open(f'{self.target}/etc/mkinitcpio.conf', 'w') as mkinit:
mkinit.write(f"MODULES=({' '.join(self.modules)})\n")
mkinit.write(f"BINARIES=({' '.join(self._binaries)})\n")
@@ -587,6 +582,7 @@ class Installer:
self,
testing: bool = False,
multilib: bool = False,
+ mkinitcpio: bool = True,
hostname: str = 'archinstall',
locale_config: LocaleConfiguration = LocaleConfiguration.default()
):
@@ -674,7 +670,7 @@ class Installer:
# TODO: Use python functions for this
SysCommand(f'/usr/bin/arch-chroot {self.target} chmod 700 /root')
- if not self.mkinitcpio(['-P'], locale_config):
+ if mkinitcpio and not self.mkinitcpio(['-P']):
error(f"Error generating initramfs (continuing anyway)")
self.helper_flags['base'] = True
@@ -783,7 +779,8 @@ class Installer:
self,
boot_partition: disk.PartitionModification,
root_partition: disk.PartitionModification,
- efi_partition: Optional[disk.PartitionModification]
+ efi_partition: Optional[disk.PartitionModification],
+ uki_enabled: bool = False
):
self.pacman.strap('efibootmgr')
@@ -815,11 +812,18 @@ class Installer:
loader_dir = self.target / 'boot/loader'
loader_dir.mkdir(parents=True, exist_ok=True)
+ default_kernel = self.kernels[0]
+ if uki_enabled:
+ default_entry = f'arch-{default_kernel}.efi'
+ else:
+ entry_name = self.init_time + '_{kernel}{variant}.conf'
+ default_entry = entry_name.format(kernel=default_kernel, variant='')
+
+ default = f'default {default_entry}'
+
# Modify or create a loader.conf
loader_conf = loader_dir / 'loader.conf'
- default = f'default {self.init_time}_{self.kernels[0]}.conf'
-
try:
loader_data = loader_conf.read_text().splitlines()
except FileNotFoundError:
@@ -837,6 +841,9 @@ class Installer:
loader_conf.write_text('\n'.join(loader_data) + '\n')
+ if uki_enabled:
+ return
+
# Ensure that the $BOOT/loader/entries/ directory exists before we try to create files in it
entries_dir = loader_dir / 'entries'
entries_dir.mkdir(parents=True, exist_ok=True)
@@ -867,7 +874,8 @@ class Installer:
options,
]
- entry_conf = entries_dir / f'{self.init_time}_{kernel}{variant}.conf'
+ name = entry_name.format(kernel=kernel, variant=variant)
+ entry_conf = entries_dir / name
entry_conf.write_text('\n'.join(entry) + '\n')
self.helper_flags['bootloader'] = 'systemd'
@@ -876,17 +884,19 @@ class Installer:
self,
boot_partition: disk.PartitionModification,
root_partition: disk.PartitionModification,
- efi_partition: Optional[disk.PartitionModification]
+ efi_partition: Optional[disk.PartitionModification],
+ uki_enabled: bool = False
):
self.pacman.strap('grub') # no need?
- grub_default = self.target / 'etc/default/grub'
- config = grub_default.read_text()
+ if not uki_enabled:
+ grub_default = self.target / 'etc/default/grub'
+ config = grub_default.read_text()
- kernel_parameters = ' '.join(self._get_kernel_params(root_partition, False, False))
- config = re.sub(r'(GRUB_CMDLINE_LINUX=")("\n)', rf'\1{kernel_parameters}\2', config, 1)
+ kernel_parameters = ' '.join(self._get_kernel_params(root_partition, False, False))
+ config = re.sub(r'(GRUB_CMDLINE_LINUX=")("\n)', rf'\1{kernel_parameters}\2', config, 1)
- grub_default.write_text(config)
+ grub_default.write_text(config)
info(f"GRUB boot partition: {boot_partition.dev_path}")
@@ -1067,7 +1077,8 @@ TIMEOUT=5
def _add_efistub_bootloader(
self,
boot_partition: disk.PartitionModification,
- root_partition: disk.PartitionModification
+ root_partition: disk.PartitionModification,
+ uki_enabled: bool = False
):
self.pacman.strap('efibootmgr')
@@ -1078,41 +1089,103 @@ TIMEOUT=5
# points towards the same disk and/or partition.
# And in which case we should do some clean up.
- microcode = []
+ if not uki_enabled:
+ loader = '/vmlinuz-{kernel}'
- if ucode := self._get_microcode():
- microcode.append(f'initrd=\\{ucode}')
- else:
- debug('Archinstall will not add any ucode to firmware boot entry.')
+ microcode = []
+
+ if ucode := self._get_microcode():
+ microcode.append(f'initrd=/{ucode}')
+ else:
+ debug('Archinstall will not add any ucode to firmware boot entry.')
- kernel_parameters = self._get_kernel_params(root_partition)
+ entries = (
+ *microcode,
+ 'initrd=/initramfs-{kernel}.img',
+ *self._get_kernel_params(root_partition)
+ )
+
+ cmdline = tuple(' '.join(entries))
+ else:
+ loader = '/EFI/Linux/arch-{kernel}.efi'
+ cmdline = tuple()
parent_dev_path = disk.device_handler.get_parent_device_path(boot_partition.safe_dev_path)
+ cmd_template = (
+ 'efibootmgr',
+ '--create',
+ '--disk', str(parent_dev_path),
+ '--part', str(boot_partition.partn),
+ '--label', 'Arch Linux ({kernel})',
+ '--loader', loader,
+ '--unicode', *cmdline,
+ '--verbose'
+ )
+
for kernel in self.kernels:
# Setup the firmware entry
- cmdline = [
- *microcode,
- f"initrd=\\initramfs-{kernel}.img",
- *kernel_parameters,
- ]
-
- cmd = [
- 'efibootmgr',
- '--disk', str(parent_dev_path),
- '--part', str(boot_partition.partn),
- '--create',
- '--label', f'Arch Linux ({kernel})',
- '--loader', f"/vmlinuz-{kernel}",
- '--unicode', ' '.join(cmdline),
- '--verbose'
- ]
-
+ cmd = [arg.format(kernel=kernel) for arg in cmd_template]
SysCommand(cmd)
self.helper_flags['bootloader'] = "efistub"
- def add_bootloader(self, bootloader: Bootloader):
+ def _config_uki(
+ self,
+ root_partition: disk.PartitionModification,
+ efi_partition: Optional[disk.PartitionModification]
+ ):
+ if not efi_partition or not efi_partition.mountpoint:
+ raise ValueError(f'Could not detect ESP at mountpoint {self.target}')
+
+ # Set up kernel command line
+ with open(self.target / 'etc/kernel/cmdline', 'w') as cmdline:
+ kernel_parameters = self._get_kernel_params(root_partition)
+ cmdline.write(' '.join(kernel_parameters) + '\n')
+
+ ucode = self._get_microcode()
+
+ esp = efi_partition.mountpoint
+
+ diff_mountpoint = None
+ if esp != Path('/efi'):
+ diff_mountpoint = str(esp)
+
+ image_re = re.compile('(.+_image="/([^"]+).+\n)')
+ uki_re = re.compile('#((.+_uki=")/[^/]+(.+\n))')
+
+ # Modify .preset files
+ for kernel in self.kernels:
+ preset = self.target / 'etc/mkinitcpio.d' / (kernel + '.preset')
+ config = preset.read_text().splitlines(True)
+
+ for index, line in enumerate(config):
+ if not ucode and line.startswith('ALL_microcode='):
+ config[index] = '#' + line
+ # Avoid storing redundant image file
+ elif m := image_re.match(line):
+ image = self.target / m.group(2)
+ image.unlink(missing_ok=True)
+ config[index] = '#' + m.group(1)
+ elif m := uki_re.match(line):
+ if diff_mountpoint:
+ config[index] = m.group(2) + diff_mountpoint + m.group(3)
+ else:
+ config[index] = m.group(1)
+ elif line.startswith('#default_options='):
+ config[index] = line.removeprefix('#')
+
+ preset.write_text(''.join(config))
+
+ # Directory for the UKIs
+ uki_dir = self.target / esp.relative_to(Path('/')) / 'EFI/Linux'
+ uki_dir.mkdir(parents=True, exist_ok=True)
+
+ # Build the UKIs
+ if not self.mkinitcpio(['-P']):
+ error(f"Error generating initramfs (continuing anyway)")
+
+ def add_bootloader(self, bootloader: Bootloader, uki_enabled: bool = False):
"""
Adds a bootloader to the installation instance.
Archinstall supports one of three types:
@@ -1143,13 +1216,16 @@ TIMEOUT=5
info(f'Adding bootloader {bootloader.value} to {boot_partition.dev_path}')
+ if uki_enabled:
+ self._config_uki(root_partition, efi_partition)
+
match bootloader:
case Bootloader.Systemd:
- self._add_systemd_bootloader(boot_partition, root_partition, efi_partition)
+ self._add_systemd_bootloader(boot_partition, root_partition, efi_partition, uki_enabled)
case Bootloader.Grub:
- self._add_grub_bootloader(boot_partition, root_partition, efi_partition)
+ self._add_grub_bootloader(boot_partition, root_partition, efi_partition, uki_enabled)
case Bootloader.Efistub:
- self._add_efistub_bootloader(boot_partition, root_partition)
+ self._add_efistub_bootloader(boot_partition, root_partition, uki_enabled)
case Bootloader.Limine:
self._add_limine_bootloader(boot_partition, root_partition)