Hi,

I tested this with a small x86/64 config in libvirt /‌ Virt Manager on Fedora. It boots up fine in a virtual machine with UEFI enabled and secure boot disabled.

Systemd-boot is smaller than grub, sizes:
openwrt-x86-64-generic-squashfs-rootfs.img.gz with grub2-efi: 4371163
openwrt-x86-64-generic-squashfs-rootfs.img.gz with systemd-boot: 4124862 (-5.6%, -240.5kB)
openwrt-x86-64-generic-squashfs-combined-efi.img.gz: 10761442
openwrt-x86-64-generic-squashfs-systemd-boot.img.gz: 9964810 (-7.4%, -778kB)

=> Nice! But probably doesn't matter on x86 :-)

But: sysupgrade the virtual machine to the same image fails:

# sysupgrade /tmp/openwrt-x86-64-generic-squashfs-systemd-boot.img.gz
Tue Dec 30 17:45:38 CET 2025 upgrade: Image metadata not present
Tue Dec 30 17:45:38 CET 2025 upgrade: Invalid image type
Image check failed.

sysupgrade to the grub2-efi Image is ok:

# sysupgrade /tmp/openwrt-x86-64-generic-squashfs-combined-efi.img.gz
Tue Dec 30 18:14:42 CET 2025 upgrade: Image metadata not present
Tue Dec 30 18:14:42 CET 2025 upgrade: with offset=0 devname=vda
Tue Dec 30 18:14:42 CET 2025 upgrade: Reading partition table from bootdisk...
Tue Dec 30 18:14:42 CET 2025 upgrade: Extract boot sector from the image
Tue Dec 30 18:14:42 CET 2025 upgrade: Reading partition table from image...
Tue Dec 30 18:14:42 CET 2025 upgrade: Saving config files...
Tue Dec 30 18:14:42 CET 2025 upgrade: Commencing upgrade. Closing all shell sessions. Tue Dec 30 18:14:42 CET 2025 upgrade: Sending TERM to remaining processes ... Tue Dec 30 18:14:46 CET 2025 upgrade: Sending KILL to remaining processes ...
stage2 (3617): drop_caches: 3
Tue Dec 30 18:14:52 CET 2025 upgrade: Switching to ramdisk...
EXT4-fs (loop0): unmounting filesystem d13e0cae-a45a-42aa-a617-60f90bd2a9b1.
Tue Dec 30 17:14:52 UTC 2025 upgrade: Performing system upgrade...
[...]


Compiling entire systemd to get systemd-boot seems a bit wasteful to me, but my patch to prevent this is bad. I removed Build/Install, since it kept compiling everything.

diff --git a/package/boot/systemd-boot/Makefile b/package/boot/systemd-boot/Makefile
index 425f53561d..18a5c095b0 100644
--- a/package/boot/systemd-boot/Makefile
+++ b/package/boot/systemd-boot/Makefile
@@ -19,7 +19,6 @@ PKG_CPE_ID:=cpe:/a:systemd_project:systemd:259:-
 PKG_LICENSE:=LGPL-2.1-or-later
 PKG_LICENSE_FILES:=LICENSES/README.md
 PKG_BUILD_DEPENDS:=python-pyelftools/host python-jinja2/host gperf/host
-PKG_INSTALL:=1

 MESON_USE_STAGING_PYTHON:=1

@@ -47,9 +46,16 @@ MESON_ARGS += \
        -Dbootloader=enabled \
        --auto-features=disabled

+define Build/Compile
+       $(call Build/Compile/Meson,src/boot/systemd-bootx64.efi)
+endef
+
+# removing PKG_INSTALL:=1 is not enough
+undefine Build/Install
+
 define Package/systemd-boot/install
        $(INSTALL_DIR) $(1)/usr/sbin $(1)/usr/lib/systemd-boot
-       $(INSTALL_DATA) $(PKG_INSTALL_DIR)/usr/lib/systemd/boot/efi/systemd-bootx64.efi $(1)/usr/lib/systemd-boot/ +       $(INSTALL_DATA) $(MESON_BUILD_DIR)/src/boot/systemd-bootx64.efi $(1)/usr/lib/systemd-boot/
 endef

 $(eval $(call BuildPackage,systemd-boot))

Am 30.12.25 um 12:54 schrieb Jonas Lochmann:
grub2 has many features, including different implementations for loading
the linux kernel. At one machine, the "linux" command cannot start
OpenWrt while the "chainloader" command for the same kernel file works.

Both commands use the same UEFI API, but the surrounding steps are
slightly different. An UEFI native bootloader seems to be similar to
"chainloader" in grub while avoiding a ton of extra features. One of
those bootloaders is systemd-boot, formerly known as gummiboot.
While it contains the name "systemd" and is part of the systemd
codebase, the resulting efi executable can be used independent of
systemd. systemd contains bootctl for managing a systemd-boot
installation, but systemd-boot uses simple text configuration files
so that this is not needed at all.

Signed-off-by: Jonas Lochmann <[email protected]>
---
  config/Config-images.in                       | 18 ++++--
  package/boot/systemd-boot/Makefile            | 55 +++++++++++++++++++
  .../x86/base-files/lib/upgrade/platform.sh    |  1 +
  target/linux/x86/image/Makefile               | 28 ++++++++++
  target/linux/x86/image/systemdboot-entry.cfg  |  4 ++
  .../linux/x86/image/systemdboot-loader.conf   |  1 +
  6 files changed, 101 insertions(+), 6 deletions(-)
  create mode 100644 package/boot/systemd-boot/Makefile
  create mode 100644 target/linux/x86/image/systemdboot-entry.cfg
  create mode 100644 target/linux/x86/image/systemdboot-loader.conf

diff --git a/config/Config-images.in b/config/Config-images.in
index fcc5fa52cb..ff93990834 100644
--- a/config/Config-images.in
+++ b/config/Config-images.in
@@ -229,6 +229,12 @@ menu "Target Images"
                        prompt "journal size" if TARGET_ROOTFS_UBIFS
                        default ""
+ config SYSTEMDBOOT_IMAGES
+               bool "Build systemd-boot images (EFI x86_64 targets only)"
+               depends on TARGET_x86_64
+               depends on TARGET_ROOTFS_EXT4FS || TARGET_ROOTFS_JFFS2 || 
TARGET_ROOTFS_SQUASHFS || TARGET_ROOTFS_EROFS
+               select PACKAGE_systemd-boot
+
        config GRUB_IMAGES
                bool "Build GRUB images (Linux x86 or x86_64 host only)"
                depends on TARGET_x86
@@ -251,23 +257,23 @@ menu "Target Images"
config GRUB_CONSOLE
                bool "Use Console Terminal (in addition to Serial)"
-               depends on GRUB_IMAGES || GRUB_EFI_IMAGES
+               depends on GRUB_IMAGES || GRUB_EFI_IMAGES || SYSTEMDBOOT_IMAGES
                default y
config GRUB_BAUDRATE
                int "Serial port baud rate"
-               depends on GRUB_IMAGES || GRUB_EFI_IMAGES
+               depends on GRUB_IMAGES || GRUB_EFI_IMAGES || SYSTEMDBOOT_IMAGES
                default 38400 if TARGET_x86_generic
                default 115200
config GRUB_FLOWCONTROL
                bool "Use RTE/CTS on serial console"
-               depends on GRUB_IMAGES || GRUB_EFI_IMAGES
+               depends on GRUB_IMAGES || GRUB_EFI_IMAGES || SYSTEMDBOOT_IMAGES
                depends on TARGET_SERIAL != ""
config GRUB_BOOTOPTS
                string "Extra kernel boot options"
-               depends on GRUB_IMAGES || GRUB_EFI_IMAGES
+               depends on GRUB_IMAGES || GRUB_EFI_IMAGES || SYSTEMDBOOT_IMAGES
                help
                  If you don't know, just leave it blank.
@@ -279,8 +285,8 @@ menu "Target Images"
                  If you don't know, 5 seconds is a reasonable default.
config GRUB_TITLE
-               string "Title for the menu entry in GRUB"
-               depends on GRUB_IMAGES || GRUB_EFI_IMAGES
+               string "Title for the menu entry in GRUB and systemd-boot"
+               depends on GRUB_IMAGES || GRUB_EFI_IMAGES || SYSTEMDBOOT_IMAGES
                default "OpenWrt"
                help
                  This is the title of the GRUB menu entry.
diff --git a/package/boot/systemd-boot/Makefile 
b/package/boot/systemd-boot/Makefile
new file mode 100644
index 0000000000..425f53561d
--- /dev/null
+++ b/package/boot/systemd-boot/Makefile
@@ -0,0 +1,55 @@
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=systemd-boot
+PKG_VERSION:=259
+PKG_RELEASE:=1
+
+PKG_SOURCE_PROTO:=git
+PKG_SOURCE_URL:=https://github.com/systemd/systemd.git
+PKG_MIRROR_HASH:=1671487dc511d60d3c50070e8f5c6dec228a1d97cdedd7f5508a966bb06ba614
+PKG_SOURCE_DATE:=2025-12-17
+PKG_SOURCE_VERSION:=9ca433482f2281d71718718705ca8cd3bf562ad6
+PKG_CPE_ID:=cpe:/a:systemd_project:systemd:259:-
+
+PKG_LICENSE:=LGPL-2.1-or-later
+PKG_LICENSE_FILES:=LICENSES/README.md
+PKG_BUILD_DEPENDS:=python-pyelftools/host python-jinja2/host gperf/host
+PKG_INSTALL:=1
+
+MESON_USE_STAGING_PYTHON:=1
+
+include $(INCLUDE_DIR)/package.mk
+include $(INCLUDE_DIR)/meson.mk
+
+define Package/systemd-boot
+  SECTION:=boot
+  CATEGORY:=Boot Loaders
+  TITLE:=Simple UEFI boot manager
+  DEPENDS:=@TARGET_x86_64 +libblkid
+  URL:=https://github.com/systemd/systemd/tree/main/src/boot
+endef
+
+define Package/systemd-boot/description
+  systemd-boot Simple UEFI boot manager
+
+  systemd-boot executes EFI images. The default entry is selected by a 
configured
+  pattern (glob) or an on-screen menu.
+endef
+
+MESON_ARGS += \
+       -Dmode=release \
+       -Dlibc=musl \
+       -Dbootloader=enabled \
+       --auto-features=disabled
+
+define Package/systemd-boot/install
+       $(INSTALL_DIR) $(1)/usr/sbin $(1)/usr/lib/systemd-boot
+       $(INSTALL_DATA) 
$(PKG_INSTALL_DIR)/usr/lib/systemd/boot/efi/systemd-bootx64.efi 
$(1)/usr/lib/systemd-boot/
+endef
+
+$(eval $(call BuildPackage,systemd-boot))
diff --git a/target/linux/x86/base-files/lib/upgrade/platform.sh 
b/target/linux/x86/base-files/lib/upgrade/platform.sh
index 5dad7a538a..bca3d0426f 100644
--- a/target/linux/x86/base-files/lib/upgrade/platform.sh
+++ b/target/linux/x86/base-files/lib/upgrade/platform.sh
@@ -125,6 +125,7 @@ platform_do_upgrade() {
                mount -t $parttype -o rw,noatime "/dev/$partdev" /mnt
                set -- $(dd if="/dev/$diskdev" bs=1 skip=1168 count=16 2>/dev/null | hexdump -v -e '8/1 "%02x "" 
"2/1 "%02x""-"6/1 "%02x"')
                sed -i "s/\(PARTUUID=\)[a-f0-9-]\+/\1$4$3$2$1-$6$5-$8$7-$9/ig" 
/mnt/boot/grub/grub.cfg
+               sed -i "s/\(PARTUUID=\)[a-f0-9-]\+/\1$4$3$2$1-$6$5-$8$7-$9/ig" 
/mnt/loader/entries/main.conf
                umount /mnt
        fi
  }
diff --git a/target/linux/x86/image/Makefile b/target/linux/x86/image/Makefile
index 29bebeb748..6f11712e87 100644
--- a/target/linux/x86/image/Makefile
+++ b/target/linux/x86/image/Makefile
@@ -52,6 +52,30 @@ define Build/combined
                256
  endef
+define Build/systemd-boot
+       rm -fR [email protected]
+       $(INSTALL_DIR) [email protected]/boot [email protected]/efi/boot [email protected]/loader/entries
+
+       $(CP) $(KDIR)/$(KERNEL_NAME) [email protected]/boot/vmlinuz
+       -$(CP) $(STAGING_DIR_ROOT)/boot/. [email protected]/boot/
+       $(CP) $(STAGING_DIR_ROOT)/usr/lib/systemd-boot/systemd-bootx64.efi 
[email protected]/efi/boot/bootx64.efi
+
+       sed \
+               -e 's#@GPT_ROOTPART@#root=$(GPT_ROOTPART) rootwait#g' \
+               -e 's#@CMDLINE@#$(BOOTOPTS) $(GRUB_CONSOLE_CMDLINE)#g' \
+               -e 's#@TITLE@#$(GRUB_TITLE)#g' \
+               ./systemdboot-entry.cfg > [email protected]/loader/entries/main.conf
+
+       $(CP) ./systemdboot-loader.conf [email protected]/loader/loader.conf
+
+       PADDING="1" SIGNATURE="$(IMG_PART_SIGNATURE)" \
+               GUID="$(IMG_PART_DISKGUID)" $(SCRIPT_DIR)/gen_image_generic.sh \
+               $@ \
+               $(CONFIG_TARGET_KERNEL_PARTSIZE) [email protected] \
+               $(CONFIG_TARGET_ROOTFS_PARTSIZE) $(IMAGE_ROOTFS) \
+               256
+endef
+
  define Build/grub-config
        rm -fR [email protected]
        $(INSTALL_DIR) [email protected]/boot/grub
@@ -114,14 +138,18 @@ define Device/Default
    IMAGE/combined-efi.vdi := grub-config efi | combined efi | grub-install efi 
| qemu-image vdi
    IMAGE/combined-efi.vmdk := grub-config efi | combined efi | grub-install 
efi | qemu-image vmdk
    IMAGE/combined-efi.vhdx := grub-config efi | combined efi | grub-install 
efi | qemu-image vhdx -o subformat=dynamic
+  IMAGE/systemd-boot.img := systemd-boot | append-metadata
+  IMAGE/systemd-boot.img.gz := systemd-boot | gzip | append-metadata
    ifeq ($(CONFIG_TARGET_IMAGES_GZIP),y)
      IMAGES-y := rootfs.img.gz
      IMAGES-$$(CONFIG_GRUB_IMAGES) += combined.img.gz
      IMAGES-$$(CONFIG_GRUB_EFI_IMAGES) += combined-efi.img.gz
+    IMAGES-$$(CONFIG_SYSTEMDBOOT_IMAGES) += systemd-boot.img.gz
    else
      IMAGES-y := rootfs.img
      IMAGES-$$(CONFIG_GRUB_IMAGES) += combined.img
      IMAGES-$$(CONFIG_GRUB_EFI_IMAGES) += combined-efi.img
+    IMAGES-$$(CONFIG_SYSTEMDBOOT_IMAGES) += systemd-boot.img
    endif
    KERNEL := kernel-bin
    KERNEL_INSTALL := 1
diff --git a/target/linux/x86/image/systemdboot-entry.cfg 
b/target/linux/x86/image/systemdboot-entry.cfg
new file mode 100644
index 0000000000..cf6bc659d0
--- /dev/null
+++ b/target/linux/x86/image/systemdboot-entry.cfg
@@ -0,0 +1,4 @@
+title @TITLE@
+linux /boot/vmlinuz
+options @GPT_ROOTPART@ @CMDLINE@ noinitrd
+architecture x64
diff --git a/target/linux/x86/image/systemdboot-loader.conf 
b/target/linux/x86/image/systemdboot-loader.conf
new file mode 100644
index 0000000000..533d233153
--- /dev/null
+++ b/target/linux/x86/image/systemdboot-loader.conf
@@ -0,0 +1 @@
+timeout menu-disabled

_______________________________________________
openwrt-devel mailing list
[email protected]
https://lists.openwrt.org/mailman/listinfo/openwrt-devel

Reply via email to