stub: load previous initrd that is already configured, too
This changes the initrd combination logic to also include any initrd already configured via the "LINUX_INITRD_MEDIA_GUID" device in the initrd we pass to the linux kernel. Or in other words: with this systemd-stub starts operating purely incremental: it will extend any previously installed initrd with its own stuff, so that both the previous initrd(s) and systemd-stub's are in effect.
This commit is contained in:
@@ -171,3 +171,47 @@ EFI_STATUS initrd_unregister(EFI_HANDLE initrd_handle) {
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -13,3 +13,5 @@ static inline void cleanup_initrd(EFI_HANDLE *initrd_handle) {
|
||||
(void) initrd_unregister(*initrd_handle);
|
||||
*initrd_handle = NULL;
|
||||
}
|
||||
|
||||
EFI_STATUS initrd_read_previous(struct iovec *ret_initrd);
|
||||
|
||||
+31
-13
@@ -10,6 +10,7 @@
|
||||
#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"
|
||||
@@ -32,13 +33,10 @@
|
||||
|
||||
/* 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,
|
||||
@@ -52,6 +50,8 @@ enum {
|
||||
_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 " ####");
|
||||
|
||||
@@ -550,6 +550,21 @@ static void extend_initrds(
|
||||
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,
|
||||
@@ -821,10 +836,11 @@ static void cmdline_append_and_measure_smbios(char16_t **cmdline, int *parameter
|
||||
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(
|
||||
@@ -1309,6 +1325,7 @@ static EFI_STATUS run(EFI_HANDLE image) {
|
||||
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);
|
||||
@@ -1319,9 +1336,10 @@ static EFI_STATUS run(EFI_HANDLE image) {
|
||||
* 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);
|
||||
|
||||
Reference in New Issue
Block a user