* [PATCH v2 1/2] xen/efi: Handle cases where file didn't come from ESP
2025-06-24 14:27 [PATCH v2 0/2] xen/efi: Make boot more flexible, especially with GRUB2 Frediano Ziglio
@ 2025-06-24 14:27 ` Frediano Ziglio
2025-06-24 14:39 ` Marek Marczykowski-Górecki
2025-06-24 14:27 ` [PATCH v2 2/2] xen/efi: Support loading initrd using GRUB2 LoadFile2 protocol Frediano Ziglio
1 sibling, 1 reply; 4+ messages in thread
From: Frediano Ziglio @ 2025-06-24 14:27 UTC (permalink / raw)
To: xen-devel
Cc: Frediano Ziglio, Daniel P. Smith, Marek Marczykowski-Górecki,
Jan Beulich
A boot loader can load files from outside ESP.
In these cases device could be not provided or path could
be something not supported.
In these cases allows to boot anyway, all information
could be provided using UKI or using other boot loader
features.
Signed-off-by: Frediano Ziglio <frediano.ziglio@cloud.com>
---
Changes since v1:
- set "leaf" to NULL instead of a buffer with an empty string;
- keep read_file fatal if cannot load file (except configuration).
---
xen/common/efi/boot.c | 34 +++++++++++++++++++++++++++++-----
1 file changed, 29 insertions(+), 5 deletions(-)
diff --git a/xen/common/efi/boot.c b/xen/common/efi/boot.c
index 1a9b4e7dae..b18af2f1f4 100644
--- a/xen/common/efi/boot.c
+++ b/xen/common/efi/boot.c
@@ -443,6 +443,18 @@ static EFI_FILE_HANDLE __init get_parent_handle(const EFI_LOADED_IMAGE *loaded_i
CHAR16 *pathend, *ptr;
EFI_STATUS ret;
+ /*
+ * In some cases the image could not come from a specific device.
+ * For instance this can happen if Xen was loaded using GRUB2 "linux"
+ * command.
+ */
+ *leaf = NULL;
+ if ( !loaded_image->DeviceHandle )
+ {
+ PrintStr(L"Xen image loaded without providing a device\r\n");
+ return NULL;
+ }
+
do {
EFI_FILE_IO_INTERFACE *fio;
@@ -466,7 +478,15 @@ static EFI_FILE_HANDLE __init get_parent_handle(const EFI_LOADED_IMAGE *loaded_i
if ( DevicePathType(dp) != MEDIA_DEVICE_PATH ||
DevicePathSubType(dp) != MEDIA_FILEPATH_DP )
- blexit(L"Unsupported device path component");
+ {
+ /*
+ * The image could come from an unsupported device.
+ * For instance this can happen if Xen was loaded using GRUB2
+ * "chainloader" command and the file was not from ESP.
+ */
+ PrintStr(L"Unsupported device path component\r\n");
+ return NULL;
+ }
if ( *buffer )
{
@@ -772,8 +792,11 @@ static bool __init read_file(EFI_FILE_HANDLE dir_handle, CHAR16 *name,
if ( !name )
PrintErrMesg(L"No filename", EFI_OUT_OF_RESOURCES);
- ret = dir_handle->Open(dir_handle, &FileHandle, name,
- EFI_FILE_MODE_READ, 0);
+ if ( dir_handle )
+ ret = dir_handle->Open(dir_handle, &FileHandle, name,
+ EFI_FILE_MODE_READ, 0);
+ else
+ ret = EFI_NOT_FOUND;
if ( file == &cfg && ret == EFI_NOT_FOUND )
return false;
if ( EFI_ERROR(ret) )
@@ -1404,7 +1427,7 @@ void EFIAPI __init noreturn efi_start(EFI_HANDLE ImageHandle,
/* Read and parse the config file. */
if ( read_section(loaded_image, L"config", &cfg, NULL) )
PrintStr(L"Using builtin config file\r\n");
- else if ( !cfg_file_name )
+ else if ( !cfg_file_name && file_name)
{
CHAR16 *tail;
@@ -1515,7 +1538,8 @@ void EFIAPI __init noreturn efi_start(EFI_HANDLE ImageHandle,
efi_bs->FreePages(cfg.addr, PFN_UP(cfg.size));
cfg.addr = 0;
- dir_handle->Close(dir_handle);
+ if ( dir_handle )
+ dir_handle->Close(dir_handle);
if ( gop && !base_video )
{
--
2.43.0
^ permalink raw reply related [flat|nested] 4+ messages in thread* [PATCH v2 2/2] xen/efi: Support loading initrd using GRUB2 LoadFile2 protocol
2025-06-24 14:27 [PATCH v2 0/2] xen/efi: Make boot more flexible, especially with GRUB2 Frediano Ziglio
2025-06-24 14:27 ` [PATCH v2 1/2] xen/efi: Handle cases where file didn't come from ESP Frediano Ziglio
@ 2025-06-24 14:27 ` Frediano Ziglio
1 sibling, 0 replies; 4+ messages in thread
From: Frediano Ziglio @ 2025-06-24 14:27 UTC (permalink / raw)
To: xen-devel
Cc: Frediano Ziglio, Daniel P. Smith, Marek Marczykowski-Górecki,
Jan Beulich
Allows to load Xen using "linux" and "initrd" GRUB2 commands.
This can be used with UKI to separate initrd in a different module
instead of bundling all together.
Bundling all together can be a problem with Secure Boot where
we need to sign the bundle making harder to change it.
As initrd content does not need to be signed for Secure Boot
bundling it force it to be signed too.
Signed-off-by: Frediano Ziglio <frediano.ziglio@cloud.com>
---
Changes since v1:
- attempt to use LoadFile2 protocol after embedded section.
---
xen/common/efi/boot.c | 71 ++++++++++++++++++++++++++++++++++++++-
xen/include/efi/efidevp.h | 21 ++++++++++++
2 files changed, 91 insertions(+), 1 deletion(-)
diff --git a/xen/common/efi/boot.c b/xen/common/efi/boot.c
index b18af2f1f4..b6ce3a0257 100644
--- a/xen/common/efi/boot.c
+++ b/xen/common/efi/boot.c
@@ -850,6 +850,74 @@ static bool __init read_file(EFI_FILE_HANDLE dir_handle, CHAR16 *name,
return true;
}
+#pragma pack(1)
+typedef struct {
+ VENDOR_DEVICE_PATH VenMediaNode;
+ EFI_DEVICE_PATH EndNode;
+} SINGLE_NODE_VENDOR_MEDIA_DEVPATH;
+#pragma pack()
+
+static bool __init initrd_load_file2(const CHAR16 *name, struct file *file)
+{
+ static const SINGLE_NODE_VENDOR_MEDIA_DEVPATH __initconst initrd_dev_path = {
+ {
+ {
+ MEDIA_DEVICE_PATH, MEDIA_VENDOR_DP, { sizeof (VENDOR_DEVICE_PATH) }
+ },
+ LINUX_EFI_INITRD_MEDIA_GUID
+ },
+ {
+ END_DEVICE_PATH_TYPE, END_ENTIRE_DEVICE_PATH_SUBTYPE,
+ { sizeof (EFI_DEVICE_PATH) }
+ }
+ };
+ static EFI_GUID __initdata lf2_proto_guid = EFI_LOAD_FILE2_PROTOCOL_GUID;
+ EFI_DEVICE_PATH *dp;
+ EFI_LOAD_FILE2_PROTOCOL *lf2;
+ EFI_HANDLE handle;
+ EFI_STATUS ret;
+ UINTN size;
+
+ dp = (EFI_DEVICE_PATH *)&initrd_dev_path;
+ ret = efi_bs->LocateDevicePath(&lf2_proto_guid, &dp, &handle);
+ if ( EFI_ERROR(ret) )
+ {
+ if ( ret == EFI_NOT_FOUND)
+ return false;
+ PrintErrMesg(L"Error getting file with LoadFile2 interface", ret);
+ }
+
+ ret = efi_bs->HandleProtocol(handle, &lf2_proto_guid, (void **)&lf2);
+ if ( EFI_ERROR(ret) )
+ PrintErrMesg(L"LoadFile2 file does not provide correct protocol", ret);
+
+ size = 0;
+ ret = lf2->LoadFile(lf2, dp, false, &size, NULL);
+ if ( ret != EFI_BUFFER_TOO_SMALL )
+ PrintErrMesg(L"Loading failed", ret);
+
+ file->addr = min(1UL << (32 + PAGE_SHIFT),
+ HYPERVISOR_VIRT_END - DIRECTMAP_VIRT_START);
+ ret = efi_bs->AllocatePages(AllocateMaxAddress, EfiLoaderData,
+ PFN_UP(size), &file->addr);
+ if ( EFI_ERROR(ret) )
+ PrintErrMesg(L"Allocation failed", ret);
+
+ file->need_to_free = true;
+ file->size = size;
+
+ ret = lf2->LoadFile(lf2, dp, false, &size, file->str);
+ if ( EFI_ERROR(ret) )
+ {
+ efi_bs->FreePages(file->addr, PFN_UP(size));
+ PrintErrMesg(L"Loading failed", ret);
+ }
+
+ efi_arch_handle_module(file, name, NULL);
+
+ return true;
+}
+
static bool __init read_section(const EFI_LOADED_IMAGE *image,
const CHAR16 *name, struct file *file,
const char *options)
@@ -1493,7 +1561,8 @@ void EFIAPI __init noreturn efi_start(EFI_HANDLE ImageHandle,
kernel_verified = true;
}
- if ( !read_section(loaded_image, L"ramdisk", &ramdisk, NULL) )
+ if ( !read_section(loaded_image, L"ramdisk", &ramdisk, NULL) &&
+ !initrd_load_file2(L"ramdisk", &ramdisk) )
{
name.s = get_value(&cfg, section.s, "ramdisk");
if ( name.s )
diff --git a/xen/include/efi/efidevp.h b/xen/include/efi/efidevp.h
index beb5785a45..b240c15d2a 100644
--- a/xen/include/efi/efidevp.h
+++ b/xen/include/efi/efidevp.h
@@ -398,5 +398,26 @@ typedef union {
} EFI_DEV_PATH_PTR;
+#define EFI_LOAD_FILE2_PROTOCOL_GUID \
+ { 0x4006c0c1, 0xfcb3, 0x403e, {0x99, 0x6d, 0x4a, 0x6c, 0x87, 0x24, 0xe0, 0x6d } }
+
+typedef struct EFI_LOAD_FILE2_PROTOCOL EFI_LOAD_FILE2_PROTOCOL;
+
+typedef
+EFI_STATUS
+(EFIAPI *EFI_LOAD_FILE2)(
+ IN EFI_LOAD_FILE2_PROTOCOL *This,
+ IN EFI_DEVICE_PATH *FilePath,
+ IN BOOLEAN BootPolicy,
+ IN OUT UINTN *BufferSize,
+ IN VOID *Buffer OPTIONAL
+ );
+
+struct EFI_LOAD_FILE2_PROTOCOL {
+ EFI_LOAD_FILE2 LoadFile;
+};
+
+#define LINUX_EFI_INITRD_MEDIA_GUID \
+ { 0x5568e427, 0x68fc, 0x4f3d, {0xac, 0x74, 0xca, 0x55, 0x52, 0x31, 0xcc, 0x68} }
#endif
--
2.43.0
^ permalink raw reply related [flat|nested] 4+ messages in thread