@@ -1604,6 +1604,106 @@ def _add_efistub_bootloader(
16041604
16051605 self ._helper_flags ['bootloader' ] = 'efistub'
16061606
1607+ def _add_refind_bootloader (
1608+ self ,
1609+ boot_partition : PartitionModification ,
1610+ efi_partition : PartitionModification | None ,
1611+ root : PartitionModification | LvmVolume ,
1612+ uki_enabled : bool = False ,
1613+ ) -> None :
1614+ debug ('Installing rEFInd bootloader' )
1615+
1616+ self .pacman .strap ('refind' )
1617+
1618+ if not SysInfo .has_uefi ():
1619+ raise HardwareIncompatibilityError
1620+
1621+ info (f'rEFInd boot partition: { boot_partition .dev_path } ' )
1622+
1623+ if not efi_partition :
1624+ raise ValueError ('Could not detect EFI system partition' )
1625+ elif not efi_partition .mountpoint :
1626+ raise ValueError ('EFI system partition is not mounted' )
1627+
1628+ info (f'rEFInd EFI partition: { efi_partition .dev_path } ' )
1629+
1630+ try :
1631+ self .arch_chroot ('refind-install' )
1632+ except SysCallError as err :
1633+ raise DiskError (f'Could not install rEFInd to { self .target } { efi_partition .mountpoint } : { err } ' )
1634+
1635+ if not boot_partition .mountpoint :
1636+ raise ValueError ('Boot partition is not mounted, cannot write rEFInd config' )
1637+
1638+ boot_is_separate = boot_partition != efi_partition and boot_partition .dev_path != efi_partition .dev_path
1639+
1640+ if boot_is_separate :
1641+ # Separate boot partition (not ESP, not root)
1642+ config_path = self .target / boot_partition .mountpoint .relative_to ('/' ) / 'refind_linux.conf'
1643+ boot_on_root = False
1644+ elif efi_partition .mountpoint == Path ('/boot' ):
1645+ # ESP is mounted at /boot, kernels are on ESP
1646+ config_path = self .target / 'boot' / 'refind_linux.conf'
1647+ boot_on_root = False
1648+ else :
1649+ # ESP is elsewhere (/efi, /boot/efi, etc.), kernels are on root filesystem at /boot
1650+ config_path = self .target / 'boot' / 'refind_linux.conf'
1651+ boot_on_root = True
1652+
1653+ config_contents = []
1654+
1655+ kernel_params = ' ' .join (self ._get_kernel_params (root ))
1656+
1657+ for kernel in self .kernels :
1658+ for variant in ('' , '-fallback' ):
1659+ if uki_enabled :
1660+ entry = f'"Arch Linux ({ kernel } { variant } ) UKI" "{ kernel_params } "'
1661+ else :
1662+ if boot_on_root :
1663+ # Kernels are in /boot subdirectory of root filesystem
1664+ if hasattr (root , 'btrfs_subvols' ) and root .btrfs_subvols :
1665+ # Root is btrfs with subvolume, find the root subvolume
1666+ root_subvol = next ((sv for sv in root .btrfs_subvols if sv .is_root ()), None )
1667+ if root_subvol :
1668+ subvol_name = root_subvol .name
1669+ initrd_path = f'initrd={ subvol_name } \\ boot\\ initramfs-{ kernel } { variant } .img'
1670+ else :
1671+ initrd_path = f'initrd=\\ boot\\ initramfs-{ kernel } { variant } .img'
1672+ else :
1673+ # Root without btrfs subvolume
1674+ initrd_path = f'initrd=\\ boot\\ initramfs-{ kernel } { variant } .img'
1675+ else :
1676+ # Kernels are at root of their partition (ESP or separate boot partition)
1677+ initrd_path = f'initrd=\\ initramfs-{ kernel } { variant } .img'
1678+ entry = f'"Arch Linux ({ kernel } { variant } )" "{ kernel_params } { initrd_path } "'
1679+
1680+ config_contents .append (entry )
1681+
1682+ config_path .write_text ('\n ' .join (config_contents ) + '\n ' )
1683+
1684+ hook_contents = textwrap .dedent (
1685+ """\
1686+ [Trigger]
1687+ Operation = Install
1688+ Operation = Upgrade
1689+ Type = Package
1690+ Target = refind
1691+
1692+ [Action]
1693+ Description = Updating rEFInd on ESP
1694+ When = PostTransaction
1695+ Exec = /usr/bin/refind-install
1696+ """
1697+ )
1698+
1699+ hooks_dir = self .target / 'etc' / 'pacman.d' / 'hooks'
1700+ hooks_dir .mkdir (parents = True , exist_ok = True )
1701+
1702+ hook_path = hooks_dir / '99-refind.hook'
1703+ hook_path .write_text (hook_contents )
1704+
1705+ self ._helper_flags ['bootloader' ] = 'refind'
1706+
16071707 def _config_uki (
16081708 self ,
16091709 root : PartitionModification | LvmVolume ,
@@ -1657,11 +1757,12 @@ def _config_uki(
16571757 def add_bootloader (self , bootloader : Bootloader , uki_enabled : bool = False , bootloader_removable : bool = False ) -> None :
16581758 """
16591759 Adds a bootloader to the installation instance.
1660- Archinstall supports one of three types:
1760+ Archinstall supports one of five types:
16611761 * systemd-bootctl
16621762 * grub
16631763 * limine
16641764 * efistub (beta)
1765+ * refnd (beta)
16651766
16661767 :param bootloader: Type of bootloader to be added
16671768 :param uki_enabled: Whether to use unified kernel images
@@ -1713,6 +1814,8 @@ def add_bootloader(self, bootloader: Bootloader, uki_enabled: bool = False, boot
17131814 self ._add_efistub_bootloader (boot_partition , root , uki_enabled )
17141815 case Bootloader .Limine :
17151816 self ._add_limine_bootloader (boot_partition , efi_partition , root , uki_enabled , bootloader_removable )
1817+ case Bootloader .Refind :
1818+ self ._add_refind_bootloader (boot_partition , efi_partition , root , uki_enabled )
17161819
17171820 def add_additional_packages (self , packages : str | list [str ]) -> None :
17181821 return self .pacman .strap (packages )
0 commit comments