free(loader);
return EFI_SUCCESS;
}
+
+EFI_STATUS initrd_read_previous(struct iovec *ret_initrd) {
+ EFI_STATUS err;
+
+ /* If there's already an initrd registered, read it out, so that we can incorporate it in ours */
+
+ assert(ret_initrd);
+
+ /* Get from the device path to the handle */
+ EFI_DEVICE_PATH *dp = (EFI_DEVICE_PATH *) &efi_initrd_device_path;
+ EFI_HANDLE handle;
+ err = BS->LocateDevicePath(MAKE_GUID_PTR(EFI_LOAD_FILE2_PROTOCOL), &dp, &handle);
+ if (err != EFI_SUCCESS)
+ return err;
+
+ /* Get from the handle to the protocol */
+ EFI_LOAD_FILE2_PROTOCOL *protocol = NULL;
+ err = BS->HandleProtocol(handle, MAKE_GUID_PTR(EFI_LOAD_FILE2_PROTOCOL), (void**) &protocol);
+ if (err != EFI_SUCCESS)
+ return err;
+
+ size_t size = 0;
+ err = protocol->LoadFile(protocol, dp, /* bootPolicy= */ false, &size, /* Buffer= */ NULL);
+ if (err == EFI_SUCCESS) /* Success? Kinda unexpected given we set Buffer to NULL, but it probably
+ * means, that the file is zero-sized, let's treat it as such. */
+ size = 0;
+ else if (err != EFI_BUFFER_TOO_SMALL)
+ return err;
+
+ if (size == 0)
+ return EFI_NOT_FOUND; /* Treat empty initrds like missing ones */
+
+ _cleanup_free_ void *data = xmalloc(size);
+ err = protocol->LoadFile(protocol, dp, /* bootPolicy= */ false, &size, data);
+ if (err != EFI_SUCCESS)
+ return err;
+
+ *ret_initrd = (struct iovec) {
+ .iov_base = TAKE_PTR(data),
+ .iov_len = size,
+ };
+
+ return EFI_SUCCESS;
+}
#include "efi-string.h"
#include "export-vars.h"
#include "graphics.h"
+#include "initrd.h"
#include "iovec-util-fundamental.h"
#include "linux.h"
#include "measure.h"
/* The list of initrds we combine into one, in the order we want to merge them */
enum {
- /* The first two are part of the PE binary */
- INITRD_UCODE,
- INITRD_BASE,
-
- /* The rest are dynamically generated, and hence in dynamic memory */
- _INITRD_DYNAMIC_FIRST,
- INITRD_CREDENTIAL = _INITRD_DYNAMIC_FIRST,
+ INITRD_UCODE, /* Part of the PE binary */
+ INITRD_PREVIOUS, /* initrd already configured via the EFI protocol before we were invoked */
+ INITRD_BASE, /* Part of the PE binary */
+ INITRD_CREDENTIAL,
INITRD_GLOBAL_CREDENTIAL,
INITRD_SYSEXT,
INITRD_GLOBAL_SYSEXT,
_INITRD_MAX,
};
+#define INITRD_IS_STATIC(idx) IN_SET(idx, INITRD_UCODE, INITRD_BASE)
+
/* magic string to find in the binary image */
DECLARE_NOALLOC_SECTION(".sdmagic", "#### LoaderInfo: systemd-stub " GIT_VERSION " ####");
iovec_array_extend(all_initrds, n_all_initrds, *i);
}
+static void acquire_previous_initrd(struct iovec initrds[static _INITRD_MAX]) {
+ EFI_STATUS err;
+
+ /* NB: the assumption here is that any previously installed initrd are measured by whatever
+ * registered them, and we just pass them on here. */
+
+ err = initrd_read_previous(initrds + INITRD_PREVIOUS);
+ if (err == EFI_NOT_FOUND)
+ log_debug_status(err, "No previous initrd registered.");
+ else if (err != EFI_SUCCESS)
+ log_warning_status(err, "Failed to read previously registered initrd, ignoring.");
+ else
+ log_debug("Successfully loaded previously registered initrd (%zu bytes).", initrds[INITRD_PREVIOUS].iov_len);
+}
+
static EFI_STATUS load_addons(
EFI_HANDLE stub_image,
EFI_LOADED_IMAGE_PROTOCOL *loaded_image,
static void initrds_free(struct iovec (*initrds)[_INITRD_MAX]) {
assert(initrds);
- /* Free the dynamic initrds, but leave the non-dynamic ones around */
+ /* Free the non-static initrds, but leave the static (i.e. PE embedded) ones around */
- for (size_t i = _INITRD_DYNAMIC_FIRST; i < _INITRD_MAX; i++)
- iovec_done((*initrds) + i);
+ for (size_t i = 0; i < _INITRD_MAX; i++)
+ if (!INITRD_IS_STATIC(i))
+ iovec_done((*initrds) + i);
}
static void generate_sidecar_initrds(
install_addon_devicetrees(&dt_state, dt_addons, n_dt_addons, ¶meters_measured);
/* Generate & find all initrds */
+ acquire_previous_initrd(initrds);
generate_sidecar_initrds(loaded_image, initrds, ¶meters_measured, &sysext_measured, &confext_measured);
generate_embedded_initrds(loaded_image, sections, initrds);
generate_boot_secret_initrd(boot_secret, initrds);
* We want addons to take precedence over the base initrds, so the order is:
* 1. Ucode addons
* 2. UKI ucode
- * 3. UKI initrd
- * 4. Generated initrds
- * 5. initrd addons */
+ * 3. Previous initrds
+ * 4. UKI initrd
+ * 5. Generated initrds
+ * 6. initrd addons */
measure_and_append_ucode_addons(&all_initrds, &n_all_initrds, ucode_addons, n_ucode_addons, ¶meters_measured);
extend_initrds(initrds, &all_initrds, &n_all_initrds);
measure_and_append_initrd_addons(&all_initrds, &n_all_initrds, initrd_addons, n_initrd_addons, ¶meters_measured);