Skip to content

Commit

Permalink
systemd-boot support
Browse files Browse the repository at this point in the history
  • Loading branch information
schubi2 committed Jun 28, 2023
1 parent 95007e7 commit 90a05bf
Show file tree
Hide file tree
Showing 30 changed files with 3,028 additions and 982 deletions.
1 change: 1 addition & 0 deletions README.md
Expand Up @@ -38,6 +38,7 @@ that holds and also can propose the bootloader implementation. So now let's expl

- [GRUB2](https://www.rubydoc.info/github/yast/yast-bootloader/master/Bootloader/Grub2) for legacy booting or emulated grub2 boot like s390x.
- [GRUB2-EFI](https://www.rubydoc.info/github/yast/yast-bootloader/master/Bootloader/Grub2EFI) for EFI variant of GRUB2 bootloader
- [systemd-boot](https://www.rubydoc.info/github/yast/yast-bootloader/master/Bootloader/SystemdBoot) systemd bootloader (for EFI only)
- [None](https://www.rubydoc.info/github/yast/yast-bootloader/master/Bootloader/NoneBootloader) when YaST does not manage booting
- [GRUB2 base](https://www.rubydoc.info/github/yast/yast-bootloader/master/Bootloader/Grub2Base) is the shared functionality for both GRUB2 implementations
- [GRUB password](https://www.rubydoc.info/github/yast/yast-bootloader/master/Bootloader/GRUB2Pwd) is a specific class that manages password protection of grub2
Expand Down
6 changes: 6 additions & 0 deletions SUPPORTED_SCENARIOS.md
Expand Up @@ -8,6 +8,8 @@ The goal of this document is to have a single source of information which scena
* grub2-efi
* only for UEFI boot
* only with GPT (see [bug](https://bugzilla.novell.com/show_bug.cgi?id=889733#c8))
* systemd-boot
* only for UEFI boot
* none

# Partition table
Expand Down Expand Up @@ -77,5 +79,9 @@ This option requires packages based on the architecture of the system:
* arm architecture requires: <b>grub2-arm-efi</b>.
* aarch64 architecture requires: <b>grub2-arm64-efi</b>.

## systemd-boot
If you're running a multiboot EFI system, systemd-boot can provide easier boot management and may even reduce your boot times.
Systemd-boot will be supported on x86_64 EFI architecture only.

## none
This option has no additional package requirement.
1,045 changes: 1,044 additions & 1 deletion doc/bootloader_backend.svg
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
54 changes: 36 additions & 18 deletions src/lib/bootloader/autoyast_converter.rb
Expand Up @@ -33,19 +33,28 @@ def import(data)
bootloader = bootloader_from_data(data)
return bootloader if bootloader.name == "none"

import_grub2(data, bootloader)
import_grub2efi(data, bootloader)
import_stage1(data, bootloader)
import_default(data, bootloader.grub_default)
import_device_map(data, bootloader)
import_password(data, bootloader)
# always nil pmbr as autoyast does not support it yet,
# so use nil to always use proposed value (bsc#1081967)
bootloader.pmbr_action = nil
cpu_mitigations = data.global.cpu_mitigations
bootloader.cpu_mitigations = CpuMitigations.from_string(cpu_mitigations) if cpu_mitigations
case bootloader.name
when "grub2", "grub2-efi"
import_grub2(data, bootloader)
import_grub2efi(data, bootloader)
import_stage1(data, bootloader)
import_default(data, bootloader.grub_default)
import_device_map(data, bootloader)
import_password(data, bootloader)
# always nil pmbr as autoyast does not support it yet,
# so use nil to always use proposed value (bsc#1081967)
bootloader.pmbr_action = nil
cpu_mitigations = data.global.cpu_mitigations
if cpu_mitigations
bootloader.cpu_mitigations = CpuMitigations.from_string(cpu_mitigations)
end
when "systemd-boot"
bootloader.menue_timeout = data.global.timeout
bootloader.secure_boot = data.global.secure_boot
else
raise UnsupportedBootloader, bootloader.name
end
# TODO: import Initrd

log.warn "autoyast profile contain sections which won't be processed" if data.sections

bootloader
Expand All @@ -61,12 +70,21 @@ def export(config)
return res if bootloader_type == "none"

res["global"] = {}
global = res["global"]
export_grub2(global, config) if config.name == "grub2"
export_grub2efi(global, config) if config.name == "grub2-efi"
export_default(global, config.grub_default)
export_password(global, config.password)
res["global"]["cpu_mitigations"] = config.cpu_mitigations.value.to_s

case config.name
when "grub2", "grub2-efi"
global = res["global"]
export_grub2(global, config) if config.name == "grub2"
export_grub2efi(global, config) if config.name == "grub2-efi"
export_default(global, config.grub_default)
export_password(global, config.password)
res["global"]["cpu_mitigations"] = config.cpu_mitigations.value.to_s
when "systemd-boot"
res["global"]["timeout"] = config.menue_timeout
res["global"]["secure_boot"] = config.secure_boot
else
raise UnsupportedBootloader, bootloader.name
end
# Do not export device map as device name are very unpredictable and is used only as
# work-around when automatic ones do not work for what-ever reasons ( it can really safe
# your day in L3 )
Expand Down
8 changes: 7 additions & 1 deletion src/lib/bootloader/bootloader_base.rb
Expand Up @@ -38,7 +38,13 @@ def prepare
# writes configuration to target disk
# @param etc_only [Boolean] true on transactional systems
# because /boot is read-only there
def write(etc_only: false); end
def write(etc_only: false)
return if etc_only

# reset eventl. already installed systemd bootloader
systemd_boot = BootloaderFactory.bootloader_by_name("systemd-boot")
systemd_boot&.delete
end

# reads configuration from target disk
def read
Expand Down
18 changes: 17 additions & 1 deletion src/lib/bootloader/bootloader_factory.rb
Expand Up @@ -5,10 +5,12 @@
require "bootloader/none_bootloader"
require "bootloader/grub2"
require "bootloader/grub2efi"
require "bootloader/systemdboot"
require "bootloader/exceptions"

Yast.import "Arch"
Yast.import "Mode"
Yast.import "ProductFeatures"

module Bootloader
# Factory to get instance of bootloader
Expand All @@ -21,6 +23,7 @@ class BootloaderFactory

# Keyword used in autoyast for default bootloader used for given system.
DEFAULT_KEYWORD = "default"
SYSTEMDBOOT = "systemd-boot"

class << self
include Yast::Logger
Expand Down Expand Up @@ -50,7 +53,13 @@ def clear_cache
def supported_names
if Yast::Mode.config
# default means bootloader use what it think is the best
return BootloaderFactory::SUPPORTED_BOOTLOADERS + [DEFAULT_KEYWORD]
result = BootloaderFactory::SUPPORTED_BOOTLOADERS.clone
if Yast::ProductFeatures.GetBooleanFeature("globals", "enable_systemd_boot") &&
Yast::Arch.x86_64 # only x86_64 is supported
result << SYSTEMDBOOT
end
result << DEFAULT_KEYWORD
return result
end

begin
Expand All @@ -63,11 +72,15 @@ def supported_names
# grub2 everywhere except aarch64 or riscv64
ret << "grub2" unless Systeminfo.efi_mandatory?
ret << "grub2-efi" if Systeminfo.efi_supported?
ret << SYSTEMDBOOT if Systeminfo.efi_supported? && Yast::ProductFeatures.GetBooleanFeature(
"globals", "enable_systemd_boot"
)
ret << "none"
# avoid double entry for selected one
ret.uniq
end

# rubocop:disable Metrics/CyclomaticComplexity
def bootloader_by_name(name)
# needed to be able to store settings when moving between bootloaders
@cached_bootloaders ||= {}
Expand All @@ -76,6 +89,8 @@ def bootloader_by_name(name)
@cached_bootloaders["grub2"] ||= Grub2.new
when "grub2-efi"
@cached_bootloaders["grub2-efi"] ||= Grub2EFI.new
when "systemd-boot"
@cached_bootloaders["systemd-boot"] ||= SystemdBoot.new
when "none"
@cached_bootloaders["none"] ||= NoneBootloader.new
when String
Expand All @@ -86,6 +101,7 @@ def bootloader_by_name(name)
nil # in other cases it means that read failed
end
end
# rubocop:enable Metrics/CyclomaticComplexity

private

Expand Down
13 changes: 10 additions & 3 deletions src/lib/bootloader/config_dialog.rb
Expand Up @@ -5,6 +5,7 @@
require "bootloader/bootloader_factory"
require "bootloader/none_bootloader"
require "bootloader/grub2_widgets"
require "bootloader/systemdboot_widgets"

Yast.import "BootStorage"
Yast.import "CWMTab"
Expand Down Expand Up @@ -88,9 +89,15 @@ def guarded_run
def contents
return VBox(LoaderTypeWidget.new) if BootloaderFactory.current.is_a?(NoneBootloader)

boot_code_tab = BootCodeTab.new
kernel_tab = KernelTab.new
bootloader_tab = BootloaderTab.new
if BootloaderFactory.current.is_a?(SystemdBoot)
boot_code_tab = ::Bootloader::SystemdBootWidget::BootCodeTab.new
kernel_tab = ::Bootloader::SystemdBootWidget::KernelTab.new
bootloader_tab = ::Bootloader::SystemdBootWidget::BootloaderTab.new
else
boot_code_tab = ::Bootloader::Grub2Widget::BootCodeTab.new
kernel_tab = ::Bootloader::Grub2Widget::KernelTab.new
bootloader_tab = ::Bootloader::Grub2Widget::BootloaderTab.new
end
case @initial_tab
when :boot_code then boot_code_tab.initial = true
when :kernel then kernel_tab.initial = true
Expand Down
23 changes: 19 additions & 4 deletions src/lib/bootloader/generic_widgets.rb
Expand Up @@ -40,11 +40,12 @@ def items

def localized_names(name)
names = {
"grub2" => _("GRUB2"),
"grub2-efi" => _("GRUB2 for EFI"),
"grub2" => _("GRUB2"),
"grub2-efi" => _("GRUB2 for EFI"),
# Translators: option in combo box when bootloader is not managed by yast2
"none" => _("Not Managed"),
"default" => _("Default")
"systemd-boot" => _("Systemd Boot"),
"none" => _("Not Managed"),
"default" => _("Default")
}

names[name] or raise "Unknown supported bootloader '#{name}'"
Expand All @@ -69,6 +70,20 @@ def handle
return :redraw if !Yast::Popup.ContinueCancel(popup_msg)
end

if new_bl == "systemd-boot"
# popup - Continue/Cancel
popup_msg = _(
"\n" \
"Systemd-boot support is currently work in progress and\n" \
"may not work as expected. Use at your own risk.\n" \
"\n" \
"Currently we do not provide official maintenance or support.\n" \
"Proceed?\n"
)

return :redraw if !Yast::Popup.ContinueCancel(popup_msg)
end

BootloaderFactory.current_name = new_bl
BootloaderFactory.current.propose

Expand Down

0 comments on commit 90a05bf

Please sign in to comment.