File 2001-systemd-boot-load-addons-from-type-1-and-expose-them.patch of Package systemd

From d6007941d29bd68d9f6794172f55d280c9fc7281 Mon Sep 17 00:00:00 2001
From: Raito Bezarius <masterancpp@gmail.com>
Date: Fri, 16 Jun 2023 14:03:35 +0200
Subject: [PATCH 2001/2007] systemd-boot: load addons from type 1 and expose
 them via EFI protocol

This make it possible to attach addons to any Type #1 entry
and get them back in the next bootable stage via an EFI protocol.
---
 src/boot/addon-util.c | 48 +++++++++++++++++++++++++++++++++++++++++++
 src/boot/addon-util.h | 12 +++++++++++
 src/boot/boot.c       | 30 ++++++++++++++++++++++++---
 src/boot/meson.build  |  1 +
 4 files changed, 88 insertions(+), 3 deletions(-)
 create mode 100644 src/boot/addon-util.c
 create mode 100644 src/boot/addon-util.h

diff --git a/src/boot/addon-util.c b/src/boot/addon-util.c
new file mode 100644
index 0000000000..3b99855c93
--- /dev/null
+++ b/src/boot/addon-util.c
@@ -0,0 +1,48 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+
+#include "addon-util.h"
+#include "proto/device-path.h"
+#include "util.h"
+#include "log.h"
+
+EFI_STATUS addons_install_proto(EFI_LOADED_IMAGE_PROTOCOL *stub_image, char16_t * const *addons) {
+        EFI_STATUS err;
+        EFI_DEVICE_PATH **dps;
+
+        assert(stub_image);
+
+        err = make_multiple_file_device_path(stub_image->DeviceHandle, addons, &dps);
+        if (err != EFI_SUCCESS || dps == NULL)
+                return err;
+
+        return BS->InstallMultipleProtocolInterfaces(&stub_image->DeviceHandle,
+                                            MAKE_GUID_PTR(SYSTEMD_ADDON_MEDIA),
+                                            dps, NULL);
+}
+
+EFI_STATUS addons_unload_proto(EFI_HANDLE *addons)
+{
+        EFI_STATUS err;
+        EFI_DEVICE_PATH *dps;
+
+        assert(addons);
+
+        if (!*addons)
+                return EFI_SUCCESS;
+
+        /* get the EFI_DEVICE_PATH* interface that we allocated earlier */
+        err = BS->HandleProtocol(*addons, MAKE_GUID_PTR(SYSTEMD_ADDON_MEDIA),
+                        (void **) &dps);
+        if (err != EFI_SUCCESS)
+                return err;
+
+        err = BS->UninstallMultipleProtocolInterfaces(*addons,
+                        MAKE_GUID_PTR(SYSTEMD_ADDON_MEDIA),
+                        &dps, NULL);
+
+        if (err != EFI_SUCCESS)
+                return err;
+
+        *addons = NULL;
+        return EFI_SUCCESS;
+}
diff --git a/src/boot/addon-util.h b/src/boot/addon-util.h
new file mode 100644
index 0000000000..f1883fdcdb
--- /dev/null
+++ b/src/boot/addon-util.h
@@ -0,0 +1,12 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+#pragma once
+
+#include "proto/loaded-image.h"
+#include "device-path-util.h"
+#include "util.h"
+
+#define SYSTEMD_ADDON_MEDIA_GUID \
+        GUID_DEF(0x97ac68bf, 0xc741, 0x4bbb, 0xb7, 0xbf, 0x7f, 0x6c, 0xcc, 0x00, 0x8a, 0x7e)
+
+EFI_STATUS addons_install_proto(EFI_LOADED_IMAGE_PROTOCOL *loaded_image, char16_t * const *addons);
+EFI_STATUS addons_unload_proto(EFI_HANDLE *addons);
diff --git a/src/boot/boot.c b/src/boot/boot.c
index e0a30d0184..ea6b8b150e 100644
--- a/src/boot/boot.c
+++ b/src/boot/boot.c
@@ -1,5 +1,6 @@
 /* SPDX-License-Identifier: LGPL-2.1-or-later */
 
+#include "addon-util.h"
 #include "bcd.h"
 #include "bootspec-fundamental.h"
 #include "console.h"
@@ -69,6 +70,7 @@ typedef struct {
         char16_t *options;
         bool options_implied; /* If true, these options are implied if we invoke the PE binary without any parameters (as in: UKI). If false we must specify these options explicitly. */
         char16_t **initrd;
+        char16_t **addons; /* systemd-addons for this entry */
         char16_t key;
         EFI_STATUS (*call)(void);
         int tries_done;
@@ -610,6 +612,8 @@ static void print_status(Config *config, char16_t *loaded_image_path) {
                         printf("        loader: %ls\n", entry->loader);
                 STRV_FOREACH(initrd, entry->initrd)
                         printf("        initrd: %ls\n", *initrd);
+                STRV_FOREACH(addon, entry->addons)
+                        printf("         addon: %ls\n", *addon);
                 if (entry->devicetree)
                         printf("    devicetree: %ls\n", entry->devicetree);
                 if (entry->options)
@@ -1203,6 +1207,7 @@ static BootEntry* boot_entry_free(BootEntry *entry) {
         free(entry->devicetree);
         free(entry->options);
         strv_free(entry->initrd);
+        strv_free(entry->addons);
         free(entry->path);
         free(entry->current_name);
         free(entry->next_name);
@@ -1439,7 +1444,7 @@ static void boot_entry_add_type1(
 
         _cleanup_(boot_entry_freep) BootEntry *entry = NULL;
         char *line;
-        size_t pos = 0, n_initrd = 0;
+        size_t pos = 0, n_initrd = 0, n_addons = 0;
         char *key, *value;
         EFI_STATUS err;
 
@@ -1508,7 +1513,13 @@ static void boot_entry_add_type1(
                                 (n_initrd + 2) * sizeof(uint16_t *));
                         entry->initrd[n_initrd++] = xstr8_to_path(value);
                         entry->initrd[n_initrd] = NULL;
-
+                } else if (streq8(key, "add-on")) {
+                        entry->addons = xrealloc(
+                                entry->addons,
+                                n_addons == 0 ? 0 : (n_addons + 1) * sizeof(uint16_t *),
+                                (n_addons + 2) * sizeof(uint16_t *));
+                        entry->addons[n_addons++] = xstr8_to_path(value);
+                        entry->addons[n_addons] = NULL;
                 } else if (streq8(key, "options")) {
                         _cleanup_free_ char16_t *new = NULL;
 
@@ -2524,6 +2535,13 @@ static EFI_STATUS initrd_prepare(
         return EFI_SUCCESS;
 }
 
+static void cleanup_loaded_image(EFI_LOADED_IMAGE_PROTOCOL **loaded_image) {
+        assert(loaded_image);
+
+        (void) addons_unload_proto((EFI_HANDLE *)*loaded_image);
+        *loaded_image = NULL;
+}
+
 static EFI_STATUS image_start(
                 EFI_HANDLE parent_image,
                 const BootEntry *entry) {
@@ -2573,7 +2591,7 @@ static EFI_STATUS image_start(
         if (err != EFI_SUCCESS)
                 return log_error_status(err, "Error registering initrd: %m");
 
-        EFI_LOADED_IMAGE_PROTOCOL *loaded_image;
+        _cleanup_(cleanup_loaded_image) EFI_LOADED_IMAGE_PROTOCOL *loaded_image = NULL;
         err = BS->HandleProtocol(image, MAKE_GUID_PTR(EFI_LOADED_IMAGE_PROTOCOL), (void **) &loaded_image);
         if (err != EFI_SUCCESS)
                 return log_error_status(err, "Error getting LoadedImageProtocol handle: %m");
@@ -2611,6 +2629,12 @@ static EFI_STATUS image_start(
                 (void) tpm_log_load_options(options, NULL);
         }
 
+        if (entry->addons) {
+                err = addons_install_proto(loaded_image, entry->addons);
+                if (err != EFI_SUCCESS)
+                        return log_error_status(err, "Error installing addons protocol: %m");
+        }
+
         efivar_set_time_usec(MAKE_GUID_PTR(LOADER), u"LoaderTimeExecUSec", 0);
         err = BS->StartImage(image, NULL, NULL);
         graphics_mode(false);
diff --git a/src/boot/meson.build b/src/boot/meson.build
index 9370274d96..da0790a25e 100644
--- a/src/boot/meson.build
+++ b/src/boot/meson.build
@@ -254,6 +254,7 @@ endif
 ############################################################
 
 libefi_sources = files(
+        'addon-util.c',
         'chid.c',
         'console.c',
         'device-path-util.c',
-- 
2.49.0

openSUSE Build Service is sponsored by