[PATCH 0/4] efi_loader: enable running the debug UEFI shell

Currently running the SCT fails on x86. The EFI shell overrides U-Boot's Simple Text Output Protocol. When ConsoleLoggerPrintWithPageBreak() is invoked with ConsoleInfo == NULL a crash occurs.
Debugging requires running the debug version of the UEFI shell. We can use `add-symbol-file` in gdb to point to Build/Shell/DEBUG_GCC/X64/ShellPkg/Application/Shell/Shell/DEBUG/Shell.dll and the load address of Shell.efi.
The debug version of the UEFI shell checks several requirements and fails to run without them:
* HOB list (only on x86) * HII configuration protocol * DXE services table
Implement the missing requirements.
When starting image add the image load address to the debug output.
Heinrich Schuchardt (4): efi_loader: implement a HOB list efi_loader: build with HII configuration protocol efi_loader: install DXE services table efi_loader: print image load address in StartImage
include/efi_dxe.h | 54 ++++++++++ include/efi_hob.h | 32 ++++++ include/efi_loader.h | 16 +++ lib/efi_loader/Kconfig | 15 +++ lib/efi_loader/Makefile | 4 +- lib/efi_loader/efi_boottime.c | 7 +- lib/efi_loader/efi_dxe.c | 176 ++++++++++++++++++++++++++++++++ lib/efi_loader/efi_hii_config.c | 4 - lib/efi_loader/efi_hob.c | 33 ++++++ lib/efi_loader/efi_root_node.c | 3 + lib/efi_loader/efi_setup.c | 13 +++ 11 files changed, 349 insertions(+), 8 deletions(-) create mode 100644 include/efi_dxe.h create mode 100644 include/efi_hob.h create mode 100644 lib/efi_loader/efi_dxe.c create mode 100644 lib/efi_loader/efi_hob.c

The debug version of the UEFI shell on x86 requires a HOB list. This implementation allows to generate an empty HOB list.
Generate the HOB list on the sandbox and on x86 by default.
Signed-off-by: Heinrich Schuchardt heinrich.schuchardt@canonical.com --- include/efi_hob.h | 32 ++++++++++++++++++++++++++++++++ include/efi_loader.h | 9 +++++++++ lib/efi_loader/Kconfig | 8 ++++++++ lib/efi_loader/Makefile | 1 + lib/efi_loader/efi_hob.c | 33 +++++++++++++++++++++++++++++++++ lib/efi_loader/efi_setup.c | 7 +++++++ 6 files changed, 90 insertions(+) create mode 100644 include/efi_hob.h create mode 100644 lib/efi_loader/efi_hob.c
diff --git a/include/efi_hob.h b/include/efi_hob.h new file mode 100644 index 00000000000..b401e6c2fa1 --- /dev/null +++ b/include/efi_hob.h @@ -0,0 +1,32 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * HOB list + * + * Copyright (c) 2025 Heinrich Schuchardt + */ + +#ifndef _EFI_HOB_H +#define _EFI_HOB_H 1 + +#include <efi.h> + +/** + * define EFI_HOB_TYPE_END_OF_HOB_LIST - end of hob list + */ +#define EFI_HOB_TYPE_END_OF_HOB_LIST 0xFFFF + +/** + * struct efi_hob_header - EFI_HOB_GENERIC_HEADER + */ +struct efi_hob_header { + /** @hob_type: type of HOB data structure */ + u16 hob_type; + /** @hob_length: HOB length including header in bytes */ + u16 hob_length; + /** @reserved: always 0 */ + u32 reserved; +}; + +extern const efi_guid_t efi_guid_hob_list; + +#endif /* _EFI_HOB_H */ diff --git a/include/efi_loader.h b/include/efi_loader.h index 9afbec35ebf..c1258098217 100644 --- a/include/efi_loader.h +++ b/include/efi_loader.h @@ -654,6 +654,15 @@ efi_status_t efi_acpi_register(void); */ efi_status_t efi_smbios_register(void);
+/** + * efi_hob_list_register() - install HOB list + * + * The EFI shell on X86 requires a HOB list + * + * Return: status code + */ +efi_status_t efi_hob_list_register(void); + struct efi_simple_file_system_protocol * efi_fs_from_path(struct efi_device_path *fp);
diff --git a/lib/efi_loader/Kconfig b/lib/efi_loader/Kconfig index c46ffe3a9d8..ec38a0ea352 100644 --- a/lib/efi_loader/Kconfig +++ b/lib/efi_loader/Kconfig @@ -395,6 +395,14 @@ config EFI_LOADER_HII U-Boot implements enough of its features to be able to run the UEFI Shell, but not more than that.
+config EFI_HOB + bool 'HOB list' + default y if SANDBOX || X86 + help + Install a HOB list. The UEFI shell on x86 requires a HOB list + to be present. Our list is empty as we don't implement the + UEFI Platform Initialization Specification. + config EFI_UNICODE_COLLATION_PROTOCOL2 bool "Unicode collation protocol" default y diff --git a/lib/efi_loader/Makefile b/lib/efi_loader/Makefile index 2a0b4172bd7..7d1f04e9fbd 100644 --- a/lib/efi_loader/Makefile +++ b/lib/efi_loader/Makefile @@ -37,6 +37,7 @@ obj-y += efi_dt_fixup.o obj-y += efi_fdt.o obj-y += efi_file.o obj-$(CONFIG_EFI_LOADER_HII) += efi_hii.o +obj-$(CONFIG_EFI_HOB) += efi_hob.o obj-y += efi_image_loader.o obj-y += efi_load_options.o obj-y += efi_memory.o diff --git a/lib/efi_loader/efi_hob.c b/lib/efi_loader/efi_hob.c new file mode 100644 index 00000000000..6a1365bd817 --- /dev/null +++ b/lib/efi_loader/efi_hob.c @@ -0,0 +1,33 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Provide HOB list + * + * Copyright (c) 2025 Heinrich Schuchardt + */ + +#include <efi_hob.h> +#include <efi_loader.h> + +const efi_guid_t efi_guid_hob_list = EFI_HOB_LIST; + +/** + * efi_hob_list_register() - install HOB list + * + * The EFI shell on X86 requires a HOB list + * + * Return: status code + */ +efi_status_t efi_hob_list_register(void) +{ + struct efi_hob_header *hob; + + hob = efi_alloc(sizeof(struct efi_hob_header)); + if (!hob) + return EFI_OUT_OF_RESOURCES; + + hob->hob_type = EFI_HOB_TYPE_END_OF_HOB_LIST; + hob->hob_length = sizeof(struct efi_hob_header); + hob->reserved = 0; + + return efi_install_configuration_table(&efi_guid_hob_list, hob); +} diff --git a/lib/efi_loader/efi_setup.c b/lib/efi_loader/efi_setup.c index aa59bc7779d..393b690c3ee 100644 --- a/lib/efi_loader/efi_setup.c +++ b/lib/efi_loader/efi_setup.c @@ -7,6 +7,7 @@
#define LOG_CATEGORY LOGC_EFI
+#include <efi_hob.h> #include <efi_loader.h> #include <efi_variable.h> #include <log.h> @@ -271,6 +272,12 @@ efi_status_t efi_init_obj_list(void) goto out; }
+ if (IS_ENABLED(CONFIG_EFI_HOB)) { + ret = efi_hob_list_register(); + if (ret != EFI_SUCCESS) + goto out; + } + if (IS_ENABLED(CONFIG_EFI_TCG2_PROTOCOL)) { ret = efi_tcg2_register(); if (ret != EFI_SUCCESS)

Hi Heinrich,
[...]
+/**
- efi_hob_list_register() - install HOB list
- The EFI shell on X86 requires a HOB list
- Return: status code
- */
+efi_status_t efi_hob_list_register(void) +{
struct efi_hob_header *hob;
hob = efi_alloc(sizeof(struct efi_hob_header));
if (!hob)
return EFI_OUT_OF_RESOURCES;
hob->hob_type = EFI_HOB_TYPE_END_OF_HOB_LIST;
hob->hob_length = sizeof(struct efi_hob_header);
hob->reserved = 0;
return efi_install_configuration_table(&efi_guid_hob_list, hob);\
If this fails no one frees the 'hob' allocated memory
+} diff --git a/lib/efi_loader/efi_setup.c b/lib/efi_loader/efi_setup.c index aa59bc7779d..393b690c3ee 100644 --- a/lib/efi_loader/efi_setup.c +++ b/lib/efi_loader/efi_setup.c @@ -7,6 +7,7 @@
#define LOG_CATEGORY LOGC_EFI
+#include <efi_hob.h> #include <efi_loader.h> #include <efi_variable.h> #include <log.h> @@ -271,6 +272,12 @@ efi_status_t efi_init_obj_list(void) goto out; }
if (IS_ENABLED(CONFIG_EFI_HOB)) {
ret = efi_hob_list_register();
if (ret != EFI_SUCCESS)
goto out;
}
if (IS_ENABLED(CONFIG_EFI_TCG2_PROTOCOL)) { ret = efi_tcg2_register(); if (ret != EFI_SUCCESS)
-- 2.47.1
Cheers /Ilias

Without the HII configuration protocol the debug version of the UEFI shell cannot be used.
Signed-off-by: Heinrich Schuchardt heinrich.schuchardt@canonical.com --- lib/efi_loader/Makefile | 2 +- lib/efi_loader/efi_hii_config.c | 4 ---- lib/efi_loader/efi_root_node.c | 3 +++ 3 files changed, 4 insertions(+), 5 deletions(-)
diff --git a/lib/efi_loader/Makefile b/lib/efi_loader/Makefile index 7d1f04e9fbd..195ed8667fe 100644 --- a/lib/efi_loader/Makefile +++ b/lib/efi_loader/Makefile @@ -36,7 +36,7 @@ obj-$(CONFIG_EFI_DEVICE_PATH_UTIL) += efi_device_path_utilities.o obj-y += efi_dt_fixup.o obj-y += efi_fdt.o obj-y += efi_file.o -obj-$(CONFIG_EFI_LOADER_HII) += efi_hii.o +obj-$(CONFIG_EFI_LOADER_HII) += efi_hii.o efi_hii_config.o obj-$(CONFIG_EFI_HOB) += efi_hob.o obj-y += efi_image_loader.o obj-y += efi_load_options.o diff --git a/lib/efi_loader/efi_hii_config.c b/lib/efi_loader/efi_hii_config.c index ae0f3ecd3b1..54a72d573be 100644 --- a/lib/efi_loader/efi_hii_config.c +++ b/lib/efi_loader/efi_hii_config.c @@ -4,10 +4,6 @@ * * Copyright (c) 2017 Leif Lindholm * Copyright (c) 2018 AKASHI Takahiro, Linaro Limited - * - * As this is still a non-working stub and the protocol is neither required - * by the EFI shell nor by the UEFI SCT this module has been removed from - * the Makefile. */
#include <efi_loader.h> diff --git a/lib/efi_loader/efi_root_node.c b/lib/efi_loader/efi_root_node.c index 4d7fb74b5d6..426f77cb2ad 100644 --- a/lib/efi_loader/efi_root_node.c +++ b/lib/efi_loader/efi_root_node.c @@ -78,6 +78,9 @@ efi_status_t efi_root_node_register(void) /* HII database protocol */ &efi_guid_hii_database_protocol, &efi_hii_database, + /* EFI HII Configuration Routing Protocol */ + &efi_guid_hii_config_routing_protocol, + &efi_hii_config_routing, #endif NULL); efi_root->type = EFI_OBJECT_TYPE_U_BOOT_FIRMWARE;

On Thu, 2 Jan 2025 at 20:11, Heinrich Schuchardt heinrich.schuchardt@canonical.com wrote:
Without the HII configuration protocol the debug version of the UEFI shell cannot be used.
Signed-off-by: Heinrich Schuchardt heinrich.schuchardt@canonical.com
lib/efi_loader/Makefile | 2 +- lib/efi_loader/efi_hii_config.c | 4 ---- lib/efi_loader/efi_root_node.c | 3 +++ 3 files changed, 4 insertions(+), 5 deletions(-)
diff --git a/lib/efi_loader/Makefile b/lib/efi_loader/Makefile index 7d1f04e9fbd..195ed8667fe 100644 --- a/lib/efi_loader/Makefile +++ b/lib/efi_loader/Makefile @@ -36,7 +36,7 @@ obj-$(CONFIG_EFI_DEVICE_PATH_UTIL) += efi_device_path_utilities.o obj-y += efi_dt_fixup.o obj-y += efi_fdt.o obj-y += efi_file.o -obj-$(CONFIG_EFI_LOADER_HII) += efi_hii.o +obj-$(CONFIG_EFI_LOADER_HII) += efi_hii.o efi_hii_config.o obj-$(CONFIG_EFI_HOB) += efi_hob.o obj-y += efi_image_loader.o obj-y += efi_load_options.o diff --git a/lib/efi_loader/efi_hii_config.c b/lib/efi_loader/efi_hii_config.c index ae0f3ecd3b1..54a72d573be 100644 --- a/lib/efi_loader/efi_hii_config.c +++ b/lib/efi_loader/efi_hii_config.c @@ -4,10 +4,6 @@
- Copyright (c) 2017 Leif Lindholm
- Copyright (c) 2018 AKASHI Takahiro, Linaro Limited
- As this is still a non-working stub and the protocol is neither required
- by the EFI shell nor by the UEFI SCT this module has been removed from
*/
- the Makefile.
#include <efi_loader.h> diff --git a/lib/efi_loader/efi_root_node.c b/lib/efi_loader/efi_root_node.c index 4d7fb74b5d6..426f77cb2ad 100644 --- a/lib/efi_loader/efi_root_node.c +++ b/lib/efi_loader/efi_root_node.c @@ -78,6 +78,9 @@ efi_status_t efi_root_node_register(void) /* HII database protocol */ &efi_guid_hii_database_protocol, &efi_hii_database,
/* EFI HII Configuration Routing Protocol */
&efi_guid_hii_config_routing_protocol,
&efi_hii_config_routing,
#endif NULL); efi_root->type = EFI_OBJECT_TYPE_U_BOOT_FIRMWARE; -- 2.47.1
Acked-by: Ilias Apalodimas ilias.apalodimas@linaro.org

The debug version of the UEFI shell requires a DXE services table to exist.
Implement the table and let all DXE functions return EFI_UNSUPPORTED.
Signed-off-by: Heinrich Schuchardt heinrich.schuchardt@canonical.com --- include/efi_dxe.h | 54 ++++++++++++ include/efi_loader.h | 7 ++ lib/efi_loader/Kconfig | 7 ++ lib/efi_loader/Makefile | 1 + lib/efi_loader/efi_dxe.c | 176 +++++++++++++++++++++++++++++++++++++ lib/efi_loader/efi_setup.c | 6 ++ 6 files changed, 251 insertions(+) create mode 100644 include/efi_dxe.h create mode 100644 lib/efi_loader/efi_dxe.c
diff --git a/include/efi_dxe.h b/include/efi_dxe.h new file mode 100644 index 00000000000..5623189de0c --- /dev/null +++ b/include/efi_dxe.h @@ -0,0 +1,54 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * DXE services table + * + * Copyright (c) 2025 Heinrich Schuchardt + */ + +#ifndef _EFI_DXE_H +#define _EFI_DXE_H 1 + +#include <efi.h> + +/** + * define DXE_SERVICES_SIGNATURE - DXE services signature ('DXE_SERV') + */ +#define DXE_SERVICES_SIGNATURE 0x565245535f455844 +/** + * define DXE_SERVICES_REVISION - DXE services revision (1.8) + */ +#define DXE_SERVICES_REVISION 0x00010050 + +/** + * define EFI_DXE_SERVICES_TABLE_GUID - GUID of the EFI DXE services table + */ +#define EFI_DXE_SERVICES_TABLE_GUID \ + EFI_GUID(0x5ad34ba, 0x6f02, 0x4214, \ + 0x95, 0x2e, 0x4d, 0xa0, 0x39, 0x8e, 0x2b, 0xb9) + +struct efi_dxe_services { + struct efi_table_hdr hdr; + + efi_status_t (EFIAPI *add_memory_space)(void); + efi_status_t (EFIAPI *allocate_memory_space)(void); + efi_status_t (EFIAPI *free_memory_space)(void); + efi_status_t (EFIAPI *remove_memory_space)(void); + efi_status_t (EFIAPI *get_memory_space_descriptor)(void); + efi_status_t (EFIAPI *set_memory_space_attributes)(void); + efi_status_t (EFIAPI *get_memory_space_map)(void); + efi_status_t (EFIAPI *add_io_space)(void); + efi_status_t (EFIAPI *allocate_io_space)(void); + efi_status_t (EFIAPI *free_io_space)(void); + efi_status_t (EFIAPI *remove_io_space)(void); + efi_status_t (EFIAPI *get_io_space_descriptor)(void); + efi_status_t (EFIAPI *get_io_space_map)(void); + efi_status_t (EFIAPI *dispatch)(void); + efi_status_t (EFIAPI *schedule)(void); + efi_status_t (EFIAPI *trust)(void); + efi_status_t (EFIAPI *process_firmware_volume)(void); + efi_status_t (EFIAPI *set_memory_space_capabilities)(void); +}; + +extern efi_guid_t efi_dxe_services_table_guid; + +#endif /* _EFI_DXE_H */ diff --git a/include/efi_loader.h b/include/efi_loader.h index c1258098217..d474866184f 100644 --- a/include/efi_loader.h +++ b/include/efi_loader.h @@ -663,6 +663,13 @@ efi_status_t efi_smbios_register(void); */ efi_status_t efi_hob_list_register(void);
+/** + * efi_dxe_services_register() - install DXE services table + * + * Return: status code + */ +efi_status_t efi_dxe_services_register(void); + struct efi_simple_file_system_protocol * efi_fs_from_path(struct efi_device_path *fp);
diff --git a/lib/efi_loader/Kconfig b/lib/efi_loader/Kconfig index ec38a0ea352..ed3470508ff 100644 --- a/lib/efi_loader/Kconfig +++ b/lib/efi_loader/Kconfig @@ -384,6 +384,13 @@ config EFI_DT_FIXUP The EFI device-tree fix-up protocol provides a function to let the firmware apply fix-ups. This may be used by boot loaders.
+config EFI_DXE + bool 'DXE services table' + default y + help + Install the DXE services table. The debug version of the UEFI shell + requires it. + config EFI_LOADER_HII bool "HII protocols" default y diff --git a/lib/efi_loader/Makefile b/lib/efi_loader/Makefile index 195ed8667fe..4f250f21811 100644 --- a/lib/efi_loader/Makefile +++ b/lib/efi_loader/Makefile @@ -33,6 +33,7 @@ obj-y += efi_console.o obj-y += efi_device_path.o obj-$(CONFIG_EFI_DEVICE_PATH_TO_TEXT) += efi_device_path_to_text.o obj-$(CONFIG_EFI_DEVICE_PATH_UTIL) += efi_device_path_utilities.o +obj-$(CONFIG_EFI_DXE) += efi_dxe.o obj-y += efi_dt_fixup.o obj-y += efi_fdt.o obj-y += efi_file.o diff --git a/lib/efi_loader/efi_dxe.c b/lib/efi_loader/efi_dxe.c new file mode 100644 index 00000000000..f8920575b0c --- /dev/null +++ b/lib/efi_loader/efi_dxe.c @@ -0,0 +1,176 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * DXE services table + * + * Copyright (c) 2025 Heinrich Schuchardt + */ + +#include <efi_dxe.h> +#include <efi_loader.h> + +efi_guid_t efi_dxe_services_table_guid = EFI_DXE_SERVICES_TABLE_GUID; + +static efi_status_t EFIAPI add_memory_space(void) +{ + EFI_ENTRY(); + + return EFI_EXIT(EFI_UNSUPPORTED); +} + +static efi_status_t EFIAPI allocate_memory_space(void) +{ + EFI_ENTRY(); + + return EFI_EXIT(EFI_UNSUPPORTED); +} + +static efi_status_t EFIAPI free_memory_space(void) +{ + EFI_ENTRY(); + + return EFI_EXIT(EFI_UNSUPPORTED); +} + +static efi_status_t EFIAPI remove_memory_space(void) +{ + EFI_ENTRY(); + + return EFI_EXIT(EFI_UNSUPPORTED); +} + +static efi_status_t EFIAPI get_memory_space_descriptor(void) +{ + EFI_ENTRY(); + + return EFI_EXIT(EFI_UNSUPPORTED); +} + +static efi_status_t EFIAPI set_memory_space_attributes(void) +{ + EFI_ENTRY(); + + return EFI_EXIT(EFI_UNSUPPORTED); +} + +static efi_status_t EFIAPI get_memory_space_map(void) +{ + EFI_ENTRY(); + + return EFI_EXIT(EFI_UNSUPPORTED); +} + +static efi_status_t EFIAPI add_io_space(void) +{ + EFI_ENTRY(); + + return EFI_EXIT(EFI_UNSUPPORTED); +} + +static efi_status_t EFIAPI allocate_io_space(void) +{ + EFI_ENTRY(); + + return EFI_EXIT(EFI_UNSUPPORTED); +} + +static efi_status_t EFIAPI free_io_space(void) +{ + EFI_ENTRY(); + + return EFI_EXIT(EFI_UNSUPPORTED); +} + +static efi_status_t EFIAPI remove_io_space(void) +{ + EFI_ENTRY(); + + return EFI_EXIT(EFI_UNSUPPORTED); +} + +static efi_status_t EFIAPI get_io_space_descriptor(void) +{ + EFI_ENTRY(); + + return EFI_EXIT(EFI_UNSUPPORTED); +} + +static efi_status_t EFIAPI get_io_space_map(void) +{ + EFI_ENTRY(); + + return EFI_EXIT(EFI_UNSUPPORTED); +} + +static efi_status_t EFIAPI dispatch(void) +{ + EFI_ENTRY(); + + return EFI_EXIT(EFI_UNSUPPORTED); +} + +static efi_status_t EFIAPI schedule(void) +{ + EFI_ENTRY(); + + return EFI_EXIT(EFI_UNSUPPORTED); +} + +static efi_status_t EFIAPI trust(void) +{ + EFI_ENTRY(); + + return EFI_EXIT(EFI_UNSUPPORTED); +} + +static efi_status_t EFIAPI process_firmware_volume(void) +{ + EFI_ENTRY(); + + return EFI_EXIT(EFI_UNSUPPORTED); +} + +static efi_status_t EFIAPI set_memory_space_capabilities(void) +{ + EFI_ENTRY(); + + return EFI_EXIT(EFI_UNSUPPORTED); +} + +static struct efi_dxe_services efi_dxe_services = { + .hdr = { + .signature = DXE_SERVICES_SIGNATURE, + .revision = DXE_SERVICES_REVISION, + .headersize = sizeof(struct efi_dxe_services), + }, + .add_memory_space = add_memory_space, + .allocate_memory_space = allocate_memory_space, + .free_memory_space = free_memory_space, + .remove_memory_space = remove_memory_space, + .get_memory_space_descriptor = get_memory_space_descriptor, + .set_memory_space_attributes = set_memory_space_attributes, + .get_memory_space_map = get_memory_space_map, + .add_io_space = add_io_space, + .allocate_io_space = allocate_io_space, + .free_io_space = free_io_space, + .remove_io_space = remove_io_space, + .get_io_space_descriptor = get_io_space_descriptor, + .get_io_space_map = get_io_space_map, + .dispatch = dispatch, + .schedule = schedule, + .trust = trust, + .process_firmware_volume = process_firmware_volume, + .set_memory_space_capabilities = set_memory_space_capabilities, +}; + +efi_status_t efi_dxe_services_register(void) +{ + struct efi_dxe_services *dxe; + + dxe = efi_alloc(sizeof(struct efi_dxe_services)); + if (!dxe) + return EFI_OUT_OF_RESOURCES; + + memcpy(dxe, &efi_dxe_services, sizeof(struct efi_dxe_services)); + + return efi_install_configuration_table(&efi_dxe_services_table_guid, dxe); +} diff --git a/lib/efi_loader/efi_setup.c b/lib/efi_loader/efi_setup.c index 393b690c3ee..796da5d5678 100644 --- a/lib/efi_loader/efi_setup.c +++ b/lib/efi_loader/efi_setup.c @@ -260,6 +260,12 @@ efi_status_t efi_init_obj_list(void) if (ret != EFI_SUCCESS) goto out;
+ if (IS_ENABLED(CONFIG_EFI_DXE)) { + ret = efi_dxe_services_register(); + if (ret != EFI_SUCCESS) + goto out; + } + if (IS_ENABLED(CONFIG_EFI_ECPT)) { ret = efi_ecpt_register(); if (ret != EFI_SUCCESS)

On Thu, 2 Jan 2025 at 20:11, Heinrich Schuchardt heinrich.schuchardt@canonical.com wrote:
The debug version of the UEFI shell requires a DXE services table to exist.
Implement the table and let all DXE functions return EFI_UNSUPPORTED.
Signed-off-by: Heinrich Schuchardt heinrich.schuchardt@canonical.com
include/efi_dxe.h | 54 ++++++++++++ include/efi_loader.h | 7 ++ lib/efi_loader/Kconfig | 7 ++ lib/efi_loader/Makefile | 1 + lib/efi_loader/efi_dxe.c | 176 +++++++++++++++++++++++++++++++++++++ lib/efi_loader/efi_setup.c | 6 ++ 6 files changed, 251 insertions(+) create mode 100644 include/efi_dxe.h create mode 100644 lib/efi_loader/efi_dxe.c
diff --git a/include/efi_dxe.h b/include/efi_dxe.h new file mode 100644 index 00000000000..5623189de0c --- /dev/null +++ b/include/efi_dxe.h @@ -0,0 +1,54 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/*
- DXE services table
- Copyright (c) 2025 Heinrich Schuchardt
- */
+#ifndef _EFI_DXE_H +#define _EFI_DXE_H 1
+#include <efi.h>
+/**
- define DXE_SERVICES_SIGNATURE - DXE services signature ('DXE_SERV')
- */
+#define DXE_SERVICES_SIGNATURE 0x565245535f455844 +/**
- define DXE_SERVICES_REVISION - DXE services revision (1.8)
- */
+#define DXE_SERVICES_REVISION 0x00010050
+/**
- define EFI_DXE_SERVICES_TABLE_GUID - GUID of the EFI DXE services table
- */
+#define EFI_DXE_SERVICES_TABLE_GUID \
EFI_GUID(0x5ad34ba, 0x6f02, 0x4214, \
0x95, 0x2e, 0x4d, 0xa0, 0x39, 0x8e, 0x2b, 0xb9)
+struct efi_dxe_services {
struct efi_table_hdr hdr;
efi_status_t (EFIAPI *add_memory_space)(void);
efi_status_t (EFIAPI *allocate_memory_space)(void);
efi_status_t (EFIAPI *free_memory_space)(void);
efi_status_t (EFIAPI *remove_memory_space)(void);
efi_status_t (EFIAPI *get_memory_space_descriptor)(void);
efi_status_t (EFIAPI *set_memory_space_attributes)(void);
efi_status_t (EFIAPI *get_memory_space_map)(void);
efi_status_t (EFIAPI *add_io_space)(void);
efi_status_t (EFIAPI *allocate_io_space)(void);
efi_status_t (EFIAPI *free_io_space)(void);
efi_status_t (EFIAPI *remove_io_space)(void);
efi_status_t (EFIAPI *get_io_space_descriptor)(void);
efi_status_t (EFIAPI *get_io_space_map)(void);
efi_status_t (EFIAPI *dispatch)(void);
efi_status_t (EFIAPI *schedule)(void);
efi_status_t (EFIAPI *trust)(void);
efi_status_t (EFIAPI *process_firmware_volume)(void);
efi_status_t (EFIAPI *set_memory_space_capabilities)(void);
+};
+extern efi_guid_t efi_dxe_services_table_guid;
+#endif /* _EFI_DXE_H */ diff --git a/include/efi_loader.h b/include/efi_loader.h index c1258098217..d474866184f 100644 --- a/include/efi_loader.h +++ b/include/efi_loader.h @@ -663,6 +663,13 @@ efi_status_t efi_smbios_register(void); */ efi_status_t efi_hob_list_register(void);
+/**
- efi_dxe_services_register() - install DXE services table
- Return: status code
- */
+efi_status_t efi_dxe_services_register(void);
struct efi_simple_file_system_protocol * efi_fs_from_path(struct efi_device_path *fp);
diff --git a/lib/efi_loader/Kconfig b/lib/efi_loader/Kconfig index ec38a0ea352..ed3470508ff 100644 --- a/lib/efi_loader/Kconfig +++ b/lib/efi_loader/Kconfig @@ -384,6 +384,13 @@ config EFI_DT_FIXUP The EFI device-tree fix-up protocol provides a function to let the firmware apply fix-ups. This may be used by boot loaders.
+config EFI_DXE
bool 'DXE services table'
default y
help
Install the DXE services table. The debug version of the UEFI shell
requires it.
config EFI_LOADER_HII bool "HII protocols" default y diff --git a/lib/efi_loader/Makefile b/lib/efi_loader/Makefile index 195ed8667fe..4f250f21811 100644 --- a/lib/efi_loader/Makefile +++ b/lib/efi_loader/Makefile @@ -33,6 +33,7 @@ obj-y += efi_console.o obj-y += efi_device_path.o obj-$(CONFIG_EFI_DEVICE_PATH_TO_TEXT) += efi_device_path_to_text.o obj-$(CONFIG_EFI_DEVICE_PATH_UTIL) += efi_device_path_utilities.o +obj-$(CONFIG_EFI_DXE) += efi_dxe.o obj-y += efi_dt_fixup.o obj-y += efi_fdt.o obj-y += efi_file.o diff --git a/lib/efi_loader/efi_dxe.c b/lib/efi_loader/efi_dxe.c new file mode 100644 index 00000000000..f8920575b0c --- /dev/null +++ b/lib/efi_loader/efi_dxe.c @@ -0,0 +1,176 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/*
- DXE services table
- Copyright (c) 2025 Heinrich Schuchardt
- */
+#include <efi_dxe.h> +#include <efi_loader.h>
+efi_guid_t efi_dxe_services_table_guid = EFI_DXE_SERVICES_TABLE_GUID;
+static efi_status_t EFIAPI add_memory_space(void) +{
EFI_ENTRY();
return EFI_EXIT(EFI_UNSUPPORTED);
+}
+static efi_status_t EFIAPI allocate_memory_space(void) +{
EFI_ENTRY();
return EFI_EXIT(EFI_UNSUPPORTED);
+}
+static efi_status_t EFIAPI free_memory_space(void) +{
EFI_ENTRY();
return EFI_EXIT(EFI_UNSUPPORTED);
+}
+static efi_status_t EFIAPI remove_memory_space(void) +{
EFI_ENTRY();
return EFI_EXIT(EFI_UNSUPPORTED);
+}
+static efi_status_t EFIAPI get_memory_space_descriptor(void) +{
EFI_ENTRY();
return EFI_EXIT(EFI_UNSUPPORTED);
+}
+static efi_status_t EFIAPI set_memory_space_attributes(void) +{
EFI_ENTRY();
return EFI_EXIT(EFI_UNSUPPORTED);
+}
+static efi_status_t EFIAPI get_memory_space_map(void) +{
EFI_ENTRY();
return EFI_EXIT(EFI_UNSUPPORTED);
+}
+static efi_status_t EFIAPI add_io_space(void) +{
EFI_ENTRY();
return EFI_EXIT(EFI_UNSUPPORTED);
+}
+static efi_status_t EFIAPI allocate_io_space(void) +{
EFI_ENTRY();
return EFI_EXIT(EFI_UNSUPPORTED);
+}
+static efi_status_t EFIAPI free_io_space(void) +{
EFI_ENTRY();
return EFI_EXIT(EFI_UNSUPPORTED);
+}
+static efi_status_t EFIAPI remove_io_space(void) +{
EFI_ENTRY();
return EFI_EXIT(EFI_UNSUPPORTED);
+}
+static efi_status_t EFIAPI get_io_space_descriptor(void) +{
EFI_ENTRY();
return EFI_EXIT(EFI_UNSUPPORTED);
+}
+static efi_status_t EFIAPI get_io_space_map(void) +{
EFI_ENTRY();
return EFI_EXIT(EFI_UNSUPPORTED);
+}
+static efi_status_t EFIAPI dispatch(void) +{
EFI_ENTRY();
return EFI_EXIT(EFI_UNSUPPORTED);
+}
+static efi_status_t EFIAPI schedule(void) +{
EFI_ENTRY();
return EFI_EXIT(EFI_UNSUPPORTED);
+}
+static efi_status_t EFIAPI trust(void) +{
EFI_ENTRY();
return EFI_EXIT(EFI_UNSUPPORTED);
+}
+static efi_status_t EFIAPI process_firmware_volume(void) +{
EFI_ENTRY();
return EFI_EXIT(EFI_UNSUPPORTED);
+}
+static efi_status_t EFIAPI set_memory_space_capabilities(void) +{
EFI_ENTRY();
return EFI_EXIT(EFI_UNSUPPORTED);
+}
+static struct efi_dxe_services efi_dxe_services = {
.hdr = {
.signature = DXE_SERVICES_SIGNATURE,
.revision = DXE_SERVICES_REVISION,
.headersize = sizeof(struct efi_dxe_services),
},
.add_memory_space = add_memory_space,
.allocate_memory_space = allocate_memory_space,
.free_memory_space = free_memory_space,
.remove_memory_space = remove_memory_space,
.get_memory_space_descriptor = get_memory_space_descriptor,
.set_memory_space_attributes = set_memory_space_attributes,
.get_memory_space_map = get_memory_space_map,
.add_io_space = add_io_space,
.allocate_io_space = allocate_io_space,
.free_io_space = free_io_space,
.remove_io_space = remove_io_space,
.get_io_space_descriptor = get_io_space_descriptor,
.get_io_space_map = get_io_space_map,
.dispatch = dispatch,
.schedule = schedule,
.trust = trust,
.process_firmware_volume = process_firmware_volume,
.set_memory_space_capabilities = set_memory_space_capabilities,
Do we plan on ever implementing those? If not we could use a single function returning EFI_UNSUPPORTED instead of all of them for code size reasons
Cheers /Ilias
+};
+efi_status_t efi_dxe_services_register(void) +{
struct efi_dxe_services *dxe;
dxe = efi_alloc(sizeof(struct efi_dxe_services));
if (!dxe)
return EFI_OUT_OF_RESOURCES;
memcpy(dxe, &efi_dxe_services, sizeof(struct efi_dxe_services));
return efi_install_configuration_table(&efi_dxe_services_table_guid, dxe);
+} diff --git a/lib/efi_loader/efi_setup.c b/lib/efi_loader/efi_setup.c index 393b690c3ee..796da5d5678 100644 --- a/lib/efi_loader/efi_setup.c +++ b/lib/efi_loader/efi_setup.c @@ -260,6 +260,12 @@ efi_status_t efi_init_obj_list(void) if (ret != EFI_SUCCESS) goto out;
if (IS_ENABLED(CONFIG_EFI_DXE)) {
ret = efi_dxe_services_register();
if (ret != EFI_SUCCESS)
goto out;
}
if (IS_ENABLED(CONFIG_EFI_ECPT)) { ret = efi_ecpt_register(); if (ret != EFI_SUCCESS)
-- 2.47.1

On 07.01.25 14:30, Ilias Apalodimas wrote:
On Thu, 2 Jan 2025 at 20:11, Heinrich Schuchardt heinrich.schuchardt@canonical.com wrote:
The debug version of the UEFI shell requires a DXE services table to exist.
Implement the table and let all DXE functions return EFI_UNSUPPORTED.
Signed-off-by: Heinrich Schuchardt heinrich.schuchardt@canonical.com
include/efi_dxe.h | 54 ++++++++++++ include/efi_loader.h | 7 ++ lib/efi_loader/Kconfig | 7 ++ lib/efi_loader/Makefile | 1 + lib/efi_loader/efi_dxe.c | 176 +++++++++++++++++++++++++++++++++++++ lib/efi_loader/efi_setup.c | 6 ++ 6 files changed, 251 insertions(+) create mode 100644 include/efi_dxe.h create mode 100644 lib/efi_loader/efi_dxe.c
diff --git a/include/efi_dxe.h b/include/efi_dxe.h new file mode 100644 index 00000000000..5623189de0c --- /dev/null +++ b/include/efi_dxe.h @@ -0,0 +1,54 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/*
- DXE services table
- Copyright (c) 2025 Heinrich Schuchardt
- */
+#ifndef _EFI_DXE_H +#define _EFI_DXE_H 1
+#include <efi.h>
+/**
- define DXE_SERVICES_SIGNATURE - DXE services signature ('DXE_SERV')
- */
+#define DXE_SERVICES_SIGNATURE 0x565245535f455844 +/**
- define DXE_SERVICES_REVISION - DXE services revision (1.8)
- */
+#define DXE_SERVICES_REVISION 0x00010050
+/**
- define EFI_DXE_SERVICES_TABLE_GUID - GUID of the EFI DXE services table
- */
+#define EFI_DXE_SERVICES_TABLE_GUID \
EFI_GUID(0x5ad34ba, 0x6f02, 0x4214, \
0x95, 0x2e, 0x4d, 0xa0, 0x39, 0x8e, 0x2b, 0xb9)
+struct efi_dxe_services {
struct efi_table_hdr hdr;
efi_status_t (EFIAPI *add_memory_space)(void);
efi_status_t (EFIAPI *allocate_memory_space)(void);
efi_status_t (EFIAPI *free_memory_space)(void);
efi_status_t (EFIAPI *remove_memory_space)(void);
efi_status_t (EFIAPI *get_memory_space_descriptor)(void);
efi_status_t (EFIAPI *set_memory_space_attributes)(void);
efi_status_t (EFIAPI *get_memory_space_map)(void);
efi_status_t (EFIAPI *add_io_space)(void);
efi_status_t (EFIAPI *allocate_io_space)(void);
efi_status_t (EFIAPI *free_io_space)(void);
efi_status_t (EFIAPI *remove_io_space)(void);
efi_status_t (EFIAPI *get_io_space_descriptor)(void);
efi_status_t (EFIAPI *get_io_space_map)(void);
efi_status_t (EFIAPI *dispatch)(void);
efi_status_t (EFIAPI *schedule)(void);
efi_status_t (EFIAPI *trust)(void);
efi_status_t (EFIAPI *process_firmware_volume)(void);
efi_status_t (EFIAPI *set_memory_space_capabilities)(void);
+};
+extern efi_guid_t efi_dxe_services_table_guid;
+#endif /* _EFI_DXE_H */ diff --git a/include/efi_loader.h b/include/efi_loader.h index c1258098217..d474866184f 100644 --- a/include/efi_loader.h +++ b/include/efi_loader.h @@ -663,6 +663,13 @@ efi_status_t efi_smbios_register(void); */ efi_status_t efi_hob_list_register(void);
+/**
- efi_dxe_services_register() - install DXE services table
- Return: status code
- */
+efi_status_t efi_dxe_services_register(void);
- struct efi_simple_file_system_protocol * efi_fs_from_path(struct efi_device_path *fp);
diff --git a/lib/efi_loader/Kconfig b/lib/efi_loader/Kconfig index ec38a0ea352..ed3470508ff 100644 --- a/lib/efi_loader/Kconfig +++ b/lib/efi_loader/Kconfig @@ -384,6 +384,13 @@ config EFI_DT_FIXUP The EFI device-tree fix-up protocol provides a function to let the firmware apply fix-ups. This may be used by boot loaders.
+config EFI_DXE
bool 'DXE services table'
default y
help
Install the DXE services table. The debug version of the UEFI shell
requires it.
- config EFI_LOADER_HII bool "HII protocols" default y
diff --git a/lib/efi_loader/Makefile b/lib/efi_loader/Makefile index 195ed8667fe..4f250f21811 100644 --- a/lib/efi_loader/Makefile +++ b/lib/efi_loader/Makefile @@ -33,6 +33,7 @@ obj-y += efi_console.o obj-y += efi_device_path.o obj-$(CONFIG_EFI_DEVICE_PATH_TO_TEXT) += efi_device_path_to_text.o obj-$(CONFIG_EFI_DEVICE_PATH_UTIL) += efi_device_path_utilities.o +obj-$(CONFIG_EFI_DXE) += efi_dxe.o obj-y += efi_dt_fixup.o obj-y += efi_fdt.o obj-y += efi_file.o diff --git a/lib/efi_loader/efi_dxe.c b/lib/efi_loader/efi_dxe.c new file mode 100644 index 00000000000..f8920575b0c --- /dev/null +++ b/lib/efi_loader/efi_dxe.c @@ -0,0 +1,176 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/*
- DXE services table
- Copyright (c) 2025 Heinrich Schuchardt
- */
+#include <efi_dxe.h> +#include <efi_loader.h>
+efi_guid_t efi_dxe_services_table_guid = EFI_DXE_SERVICES_TABLE_GUID;
+static efi_status_t EFIAPI add_memory_space(void) +{
EFI_ENTRY();
return EFI_EXIT(EFI_UNSUPPORTED);
+}
+static efi_status_t EFIAPI allocate_memory_space(void) +{
EFI_ENTRY();
return EFI_EXIT(EFI_UNSUPPORTED);
+}
+static efi_status_t EFIAPI free_memory_space(void) +{
EFI_ENTRY();
return EFI_EXIT(EFI_UNSUPPORTED);
+}
+static efi_status_t EFIAPI remove_memory_space(void) +{
EFI_ENTRY();
return EFI_EXIT(EFI_UNSUPPORTED);
+}
+static efi_status_t EFIAPI get_memory_space_descriptor(void) +{
EFI_ENTRY();
return EFI_EXIT(EFI_UNSUPPORTED);
+}
+static efi_status_t EFIAPI set_memory_space_attributes(void) +{
EFI_ENTRY();
return EFI_EXIT(EFI_UNSUPPORTED);
+}
+static efi_status_t EFIAPI get_memory_space_map(void) +{
EFI_ENTRY();
return EFI_EXIT(EFI_UNSUPPORTED);
+}
+static efi_status_t EFIAPI add_io_space(void) +{
EFI_ENTRY();
return EFI_EXIT(EFI_UNSUPPORTED);
+}
+static efi_status_t EFIAPI allocate_io_space(void) +{
EFI_ENTRY();
return EFI_EXIT(EFI_UNSUPPORTED);
+}
+static efi_status_t EFIAPI free_io_space(void) +{
EFI_ENTRY();
return EFI_EXIT(EFI_UNSUPPORTED);
+}
+static efi_status_t EFIAPI remove_io_space(void) +{
EFI_ENTRY();
return EFI_EXIT(EFI_UNSUPPORTED);
+}
+static efi_status_t EFIAPI get_io_space_descriptor(void) +{
EFI_ENTRY();
return EFI_EXIT(EFI_UNSUPPORTED);
+}
+static efi_status_t EFIAPI get_io_space_map(void) +{
EFI_ENTRY();
return EFI_EXIT(EFI_UNSUPPORTED);
+}
+static efi_status_t EFIAPI dispatch(void) +{
EFI_ENTRY();
return EFI_EXIT(EFI_UNSUPPORTED);
+}
+static efi_status_t EFIAPI schedule(void) +{
EFI_ENTRY();
return EFI_EXIT(EFI_UNSUPPORTED);
+}
+static efi_status_t EFIAPI trust(void) +{
EFI_ENTRY();
return EFI_EXIT(EFI_UNSUPPORTED);
+}
+static efi_status_t EFIAPI process_firmware_volume(void) +{
EFI_ENTRY();
return EFI_EXIT(EFI_UNSUPPORTED);
+}
+static efi_status_t EFIAPI set_memory_space_capabilities(void) +{
EFI_ENTRY();
return EFI_EXIT(EFI_UNSUPPORTED);
+}
+static struct efi_dxe_services efi_dxe_services = {
.hdr = {
.signature = DXE_SERVICES_SIGNATURE,
.revision = DXE_SERVICES_REVISION,
.headersize = sizeof(struct efi_dxe_services),
},
.add_memory_space = add_memory_space,
.allocate_memory_space = allocate_memory_space,
.free_memory_space = free_memory_space,
.remove_memory_space = remove_memory_space,
.get_memory_space_descriptor = get_memory_space_descriptor,
.set_memory_space_attributes = set_memory_space_attributes,
.get_memory_space_map = get_memory_space_map,
.add_io_space = add_io_space,
.allocate_io_space = allocate_io_space,
.free_io_space = free_io_space,
.remove_io_space = remove_io_space,
.get_io_space_descriptor = get_io_space_descriptor,
.get_io_space_map = get_io_space_map,
.dispatch = dispatch,
.schedule = schedule,
.trust = trust,
.process_firmware_volume = process_firmware_volume,
.set_memory_space_capabilities = set_memory_space_capabilities,
Do we plan on ever implementing those? If not we could use a single function returning EFI_UNSUPPORTED instead of all of them for code size reasons
Currently I don't plan to implement these. But I wanted to be able to add
#define _DEBUG 1
to find out which of the functions is possibly used.
On x86 and sandbox I don't think our memory restrictions are very tight.
Best regards
Heinrich
Cheers /Ilias
+};
+efi_status_t efi_dxe_services_register(void) +{
struct efi_dxe_services *dxe;
dxe = efi_alloc(sizeof(struct efi_dxe_services));
if (!dxe)
return EFI_OUT_OF_RESOURCES;
memcpy(dxe, &efi_dxe_services, sizeof(struct efi_dxe_services));
return efi_install_configuration_table(&efi_dxe_services_table_guid, dxe);
+} diff --git a/lib/efi_loader/efi_setup.c b/lib/efi_loader/efi_setup.c index 393b690c3ee..796da5d5678 100644 --- a/lib/efi_loader/efi_setup.c +++ b/lib/efi_loader/efi_setup.c @@ -260,6 +260,12 @@ efi_status_t efi_init_obj_list(void) if (ret != EFI_SUCCESS) goto out;
if (IS_ENABLED(CONFIG_EFI_DXE)) {
ret = efi_dxe_services_register();
if (ret != EFI_SUCCESS)
goto out;
}
if (IS_ENABLED(CONFIG_EFI_ECPT)) { ret = efi_ecpt_register(); if (ret != EFI_SUCCESS)
-- 2.47.1

On Tue, 7 Jan 2025 at 19:19, Heinrich Schuchardt heinrich.schuchardt@canonical.com wrote:
On 07.01.25 14:30, Ilias Apalodimas wrote:
On Thu, 2 Jan 2025 at 20:11, Heinrich Schuchardt heinrich.schuchardt@canonical.com wrote:
The debug version of the UEFI shell requires a DXE services table to exist.
Implement the table and let all DXE functions return EFI_UNSUPPORTED.
Signed-off-by: Heinrich Schuchardt heinrich.schuchardt@canonical.com
include/efi_dxe.h | 54 ++++++++++++ include/efi_loader.h | 7 ++ lib/efi_loader/Kconfig | 7 ++ lib/efi_loader/Makefile | 1 + lib/efi_loader/efi_dxe.c | 176 +++++++++++++++++++++++++++++++++++++ lib/efi_loader/efi_setup.c | 6 ++ 6 files changed, 251 insertions(+) create mode 100644 include/efi_dxe.h create mode 100644 lib/efi_loader/efi_dxe.c
diff --git a/include/efi_dxe.h b/include/efi_dxe.h new file mode 100644 index 00000000000..5623189de0c --- /dev/null +++ b/include/efi_dxe.h @@ -0,0 +1,54 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/*
- DXE services table
- Copyright (c) 2025 Heinrich Schuchardt
- */
+#ifndef _EFI_DXE_H +#define _EFI_DXE_H 1
+#include <efi.h>
+/**
- define DXE_SERVICES_SIGNATURE - DXE services signature ('DXE_SERV')
- */
+#define DXE_SERVICES_SIGNATURE 0x565245535f455844 +/**
- define DXE_SERVICES_REVISION - DXE services revision (1.8)
- */
+#define DXE_SERVICES_REVISION 0x00010050
+/**
- define EFI_DXE_SERVICES_TABLE_GUID - GUID of the EFI DXE services table
- */
+#define EFI_DXE_SERVICES_TABLE_GUID \
EFI_GUID(0x5ad34ba, 0x6f02, 0x4214, \
0x95, 0x2e, 0x4d, 0xa0, 0x39, 0x8e, 0x2b, 0xb9)
+struct efi_dxe_services {
struct efi_table_hdr hdr;
efi_status_t (EFIAPI *add_memory_space)(void);
efi_status_t (EFIAPI *allocate_memory_space)(void);
efi_status_t (EFIAPI *free_memory_space)(void);
efi_status_t (EFIAPI *remove_memory_space)(void);
efi_status_t (EFIAPI *get_memory_space_descriptor)(void);
efi_status_t (EFIAPI *set_memory_space_attributes)(void);
efi_status_t (EFIAPI *get_memory_space_map)(void);
efi_status_t (EFIAPI *add_io_space)(void);
efi_status_t (EFIAPI *allocate_io_space)(void);
efi_status_t (EFIAPI *free_io_space)(void);
efi_status_t (EFIAPI *remove_io_space)(void);
efi_status_t (EFIAPI *get_io_space_descriptor)(void);
efi_status_t (EFIAPI *get_io_space_map)(void);
efi_status_t (EFIAPI *dispatch)(void);
efi_status_t (EFIAPI *schedule)(void);
efi_status_t (EFIAPI *trust)(void);
efi_status_t (EFIAPI *process_firmware_volume)(void);
efi_status_t (EFIAPI *set_memory_space_capabilities)(void);
+};
+extern efi_guid_t efi_dxe_services_table_guid;
+#endif /* _EFI_DXE_H */ diff --git a/include/efi_loader.h b/include/efi_loader.h index c1258098217..d474866184f 100644 --- a/include/efi_loader.h +++ b/include/efi_loader.h @@ -663,6 +663,13 @@ efi_status_t efi_smbios_register(void); */ efi_status_t efi_hob_list_register(void);
+/**
- efi_dxe_services_register() - install DXE services table
- Return: status code
- */
+efi_status_t efi_dxe_services_register(void);
- struct efi_simple_file_system_protocol * efi_fs_from_path(struct efi_device_path *fp);
diff --git a/lib/efi_loader/Kconfig b/lib/efi_loader/Kconfig index ec38a0ea352..ed3470508ff 100644 --- a/lib/efi_loader/Kconfig +++ b/lib/efi_loader/Kconfig @@ -384,6 +384,13 @@ config EFI_DT_FIXUP The EFI device-tree fix-up protocol provides a function to let the firmware apply fix-ups. This may be used by boot loaders.
+config EFI_DXE
bool 'DXE services table'
default y
help
Install the DXE services table. The debug version of the UEFI shell
requires it.
- config EFI_LOADER_HII bool "HII protocols" default y
diff --git a/lib/efi_loader/Makefile b/lib/efi_loader/Makefile index 195ed8667fe..4f250f21811 100644 --- a/lib/efi_loader/Makefile +++ b/lib/efi_loader/Makefile @@ -33,6 +33,7 @@ obj-y += efi_console.o obj-y += efi_device_path.o obj-$(CONFIG_EFI_DEVICE_PATH_TO_TEXT) += efi_device_path_to_text.o obj-$(CONFIG_EFI_DEVICE_PATH_UTIL) += efi_device_path_utilities.o +obj-$(CONFIG_EFI_DXE) += efi_dxe.o obj-y += efi_dt_fixup.o obj-y += efi_fdt.o obj-y += efi_file.o diff --git a/lib/efi_loader/efi_dxe.c b/lib/efi_loader/efi_dxe.c new file mode 100644 index 00000000000..f8920575b0c --- /dev/null +++ b/lib/efi_loader/efi_dxe.c @@ -0,0 +1,176 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/*
- DXE services table
- Copyright (c) 2025 Heinrich Schuchardt
- */
+#include <efi_dxe.h> +#include <efi_loader.h>
+efi_guid_t efi_dxe_services_table_guid = EFI_DXE_SERVICES_TABLE_GUID;
+static efi_status_t EFIAPI add_memory_space(void) +{
EFI_ENTRY();
return EFI_EXIT(EFI_UNSUPPORTED);
+}
+static efi_status_t EFIAPI allocate_memory_space(void) +{
EFI_ENTRY();
return EFI_EXIT(EFI_UNSUPPORTED);
+}
+static efi_status_t EFIAPI free_memory_space(void) +{
EFI_ENTRY();
return EFI_EXIT(EFI_UNSUPPORTED);
+}
+static efi_status_t EFIAPI remove_memory_space(void) +{
EFI_ENTRY();
return EFI_EXIT(EFI_UNSUPPORTED);
+}
+static efi_status_t EFIAPI get_memory_space_descriptor(void) +{
EFI_ENTRY();
return EFI_EXIT(EFI_UNSUPPORTED);
+}
+static efi_status_t EFIAPI set_memory_space_attributes(void) +{
EFI_ENTRY();
return EFI_EXIT(EFI_UNSUPPORTED);
+}
+static efi_status_t EFIAPI get_memory_space_map(void) +{
EFI_ENTRY();
return EFI_EXIT(EFI_UNSUPPORTED);
+}
+static efi_status_t EFIAPI add_io_space(void) +{
EFI_ENTRY();
return EFI_EXIT(EFI_UNSUPPORTED);
+}
+static efi_status_t EFIAPI allocate_io_space(void) +{
EFI_ENTRY();
return EFI_EXIT(EFI_UNSUPPORTED);
+}
+static efi_status_t EFIAPI free_io_space(void) +{
EFI_ENTRY();
return EFI_EXIT(EFI_UNSUPPORTED);
+}
+static efi_status_t EFIAPI remove_io_space(void) +{
EFI_ENTRY();
return EFI_EXIT(EFI_UNSUPPORTED);
+}
+static efi_status_t EFIAPI get_io_space_descriptor(void) +{
EFI_ENTRY();
return EFI_EXIT(EFI_UNSUPPORTED);
+}
+static efi_status_t EFIAPI get_io_space_map(void) +{
EFI_ENTRY();
return EFI_EXIT(EFI_UNSUPPORTED);
+}
+static efi_status_t EFIAPI dispatch(void) +{
EFI_ENTRY();
return EFI_EXIT(EFI_UNSUPPORTED);
+}
+static efi_status_t EFIAPI schedule(void) +{
EFI_ENTRY();
return EFI_EXIT(EFI_UNSUPPORTED);
+}
+static efi_status_t EFIAPI trust(void) +{
EFI_ENTRY();
return EFI_EXIT(EFI_UNSUPPORTED);
+}
+static efi_status_t EFIAPI process_firmware_volume(void) +{
EFI_ENTRY();
return EFI_EXIT(EFI_UNSUPPORTED);
+}
+static efi_status_t EFIAPI set_memory_space_capabilities(void) +{
EFI_ENTRY();
return EFI_EXIT(EFI_UNSUPPORTED);
+}
+static struct efi_dxe_services efi_dxe_services = {
.hdr = {
.signature = DXE_SERVICES_SIGNATURE,
.revision = DXE_SERVICES_REVISION,
.headersize = sizeof(struct efi_dxe_services),
},
.add_memory_space = add_memory_space,
.allocate_memory_space = allocate_memory_space,
.free_memory_space = free_memory_space,
.remove_memory_space = remove_memory_space,
.get_memory_space_descriptor = get_memory_space_descriptor,
.set_memory_space_attributes = set_memory_space_attributes,
.get_memory_space_map = get_memory_space_map,
.add_io_space = add_io_space,
.allocate_io_space = allocate_io_space,
.free_io_space = free_io_space,
.remove_io_space = remove_io_space,
.get_io_space_descriptor = get_io_space_descriptor,
.get_io_space_map = get_io_space_map,
.dispatch = dispatch,
.schedule = schedule,
.trust = trust,
.process_firmware_volume = process_firmware_volume,
.set_memory_space_capabilities = set_memory_space_capabilities,
Do we plan on ever implementing those? If not we could use a single function returning EFI_UNSUPPORTED instead of all of them for code size reasons
Currently I don't plan to implement these. But I wanted to be able to add
#define _DEBUG 1
to find out which of the functions is possibly used.
On x86 and sandbox I don't think our memory restrictions are very tight.
Best regards
Heinrich
Fair enough Reviewed-by: Ilias Apalodimas ilias.apalodimas@linaro.org
Cheers /Ilias
+};
+efi_status_t efi_dxe_services_register(void) +{
struct efi_dxe_services *dxe;
dxe = efi_alloc(sizeof(struct efi_dxe_services));
if (!dxe)
return EFI_OUT_OF_RESOURCES;
memcpy(dxe, &efi_dxe_services, sizeof(struct efi_dxe_services));
return efi_install_configuration_table(&efi_dxe_services_table_guid, dxe);
+} diff --git a/lib/efi_loader/efi_setup.c b/lib/efi_loader/efi_setup.c index 393b690c3ee..796da5d5678 100644 --- a/lib/efi_loader/efi_setup.c +++ b/lib/efi_loader/efi_setup.c @@ -260,6 +260,12 @@ efi_status_t efi_init_obj_list(void) if (ret != EFI_SUCCESS) goto out;
if (IS_ENABLED(CONFIG_EFI_DXE)) {
ret = efi_dxe_services_register();
if (ret != EFI_SUCCESS)
goto out;
}
if (IS_ENABLED(CONFIG_EFI_ECPT)) { ret = efi_ecpt_register(); if (ret != EFI_SUCCESS)
-- 2.47.1

When starting image add the image load address to the debug output.
Signed-off-by: Heinrich Schuchardt heinrich.schuchardt@canonical.com --- lib/efi_loader/efi_boottime.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-)
diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c index 080e7f78ae3..bc0cbd96e74 100644 --- a/lib/efi_loader/efi_boottime.c +++ b/lib/efi_loader/efi_boottime.c @@ -3194,7 +3194,7 @@ efi_status_t EFIAPI efi_start_image(efi_handle_t image_handle, struct efi_loaded_image_obj *image_obj = (struct efi_loaded_image_obj *)image_handle; efi_status_t ret; - void *info; + struct efi_loaded_image *info; efi_handle_t parent_image = current_image; efi_status_t exit_status; struct jmp_buf_data exit_jmp; @@ -3212,7 +3212,7 @@ efi_status_t EFIAPI efi_start_image(efi_handle_t image_handle, return EFI_EXIT(EFI_SECURITY_VIOLATION);
ret = EFI_CALL(efi_open_protocol(image_handle, &efi_guid_loaded_image, - &info, NULL, NULL, + (void **)&info, NULL, NULL, EFI_OPEN_PROTOCOL_GET_PROTOCOL)); if (ret != EFI_SUCCESS) return EFI_EXIT(EFI_INVALID_PARAMETER); @@ -3266,7 +3266,8 @@ efi_status_t EFIAPI efi_start_image(efi_handle_t image_handle,
current_image = image_handle; image_obj->header.type = EFI_OBJECT_TYPE_STARTED_IMAGE; - EFI_PRINT("Jumping into 0x%p\n", image_obj->entry); + EFI_PRINT("Starting image loaded at 0x%p, entry point 0x%p\n", + info->image_base, image_obj->entry); ret = EFI_CALL(image_obj->entry(image_handle, &systab));
/*

On Thu, 2 Jan 2025 at 20:11, Heinrich Schuchardt heinrich.schuchardt@canonical.com wrote:
When starting image add the image load address to the debug output.
Signed-off-by: Heinrich Schuchardt heinrich.schuchardt@canonical.com
lib/efi_loader/efi_boottime.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-)
diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c index 080e7f78ae3..bc0cbd96e74 100644 --- a/lib/efi_loader/efi_boottime.c +++ b/lib/efi_loader/efi_boottime.c @@ -3194,7 +3194,7 @@ efi_status_t EFIAPI efi_start_image(efi_handle_t image_handle, struct efi_loaded_image_obj *image_obj = (struct efi_loaded_image_obj *)image_handle; efi_status_t ret;
void *info;
struct efi_loaded_image *info; efi_handle_t parent_image = current_image; efi_status_t exit_status; struct jmp_buf_data exit_jmp;
@@ -3212,7 +3212,7 @@ efi_status_t EFIAPI efi_start_image(efi_handle_t image_handle, return EFI_EXIT(EFI_SECURITY_VIOLATION);
ret = EFI_CALL(efi_open_protocol(image_handle, &efi_guid_loaded_image,
&info, NULL, NULL,
(void **)&info, NULL, NULL,
We don't really need the cast here
EFI_OPEN_PROTOCOL_GET_PROTOCOL)); if (ret != EFI_SUCCESS) return EFI_EXIT(EFI_INVALID_PARAMETER);
@@ -3266,7 +3266,8 @@ efi_status_t EFIAPI efi_start_image(efi_handle_t image_handle,
current_image = image_handle; image_obj->header.type = EFI_OBJECT_TYPE_STARTED_IMAGE;
EFI_PRINT("Jumping into 0x%p\n", image_obj->entry);
EFI_PRINT("Starting image loaded at 0x%p, entry point 0x%p\n",
info->image_base, image_obj->entry); ret = EFI_CALL(image_obj->entry(image_handle, &systab)); /*
-- 2.47.1
With or without the cast removed Reviewed-by: Ilias Apalodimas ilias.apalodimas@linaro.org

On 07.01.25 14:32, Ilias Apalodimas wrote:
On Thu, 2 Jan 2025 at 20:11, Heinrich Schuchardt heinrich.schuchardt@canonical.com wrote:
When starting image add the image load address to the debug output.
Signed-off-by: Heinrich Schuchardt heinrich.schuchardt@canonical.com
lib/efi_loader/efi_boottime.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-)
diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c index 080e7f78ae3..bc0cbd96e74 100644 --- a/lib/efi_loader/efi_boottime.c +++ b/lib/efi_loader/efi_boottime.c @@ -3194,7 +3194,7 @@ efi_status_t EFIAPI efi_start_image(efi_handle_t image_handle, struct efi_loaded_image_obj *image_obj = (struct efi_loaded_image_obj *)image_handle; efi_status_t ret;
void *info;
struct efi_loaded_image *info; efi_handle_t parent_image = current_image; efi_status_t exit_status; struct jmp_buf_data exit_jmp;
@@ -3212,7 +3212,7 @@ efi_status_t EFIAPI efi_start_image(efi_handle_t image_handle, return EFI_EXIT(EFI_SECURITY_VIOLATION);
ret = EFI_CALL(efi_open_protocol(image_handle, &efi_guid_loaded_image,
&info, NULL, NULL,
(void **)&info, NULL, NULL,
We don't really need the cast here
Without the cast building fails.
Best regards
Heinrich
EFI_OPEN_PROTOCOL_GET_PROTOCOL)); if (ret != EFI_SUCCESS) return EFI_EXIT(EFI_INVALID_PARAMETER);
@@ -3266,7 +3266,8 @@ efi_status_t EFIAPI efi_start_image(efi_handle_t image_handle,
current_image = image_handle; image_obj->header.type = EFI_OBJECT_TYPE_STARTED_IMAGE;
EFI_PRINT("Jumping into 0x%p\n", image_obj->entry);
EFI_PRINT("Starting image loaded at 0x%p, entry point 0x%p\n",
info->image_base, image_obj->entry); ret = EFI_CALL(image_obj->entry(image_handle, &systab)); /*
-- 2.47.1
With or without the cast removed Reviewed-by: Ilias Apalodimas ilias.apalodimas@linaro.org

Hi Heinrich,
On Fri, 3 Jan 2025 at 07:11, Heinrich Schuchardt heinrich.schuchardt@canonical.com wrote:
Currently running the SCT fails on x86. The EFI shell overrides U-Boot's Simple Text Output Protocol. When ConsoleLoggerPrintWithPageBreak() is invoked with ConsoleInfo == NULL a crash occurs.
Debugging requires running the debug version of the UEFI shell. We can use `add-symbol-file` in gdb to point to Build/Shell/DEBUG_GCC/X64/ShellPkg/Application/Shell/Shell/DEBUG/Shell.dll and the load address of Shell.efi.
The debug version of the UEFI shell checks several requirements and fails to run without them:
- HOB list (only on x86)
- HII configuration protocol
- DXE services table
Implement the missing requirements.
When starting image add the image load address to the debug output.
Heinrich Schuchardt (4): efi_loader: implement a HOB list efi_loader: build with HII configuration protocol efi_loader: install DXE services table efi_loader: print image load address in StartImage
include/efi_dxe.h | 54 ++++++++++ include/efi_hob.h | 32 ++++++ include/efi_loader.h | 16 +++ lib/efi_loader/Kconfig | 15 +++ lib/efi_loader/Makefile | 4 +- lib/efi_loader/efi_boottime.c | 7 +- lib/efi_loader/efi_dxe.c | 176 ++++++++++++++++++++++++++++++++ lib/efi_loader/efi_hii_config.c | 4 - lib/efi_loader/efi_hob.c | 33 ++++++ lib/efi_loader/efi_root_node.c | 3 + lib/efi_loader/efi_setup.c | 13 +++ 11 files changed, 349 insertions(+), 8 deletions(-) create mode 100644 include/efi_dxe.h create mode 100644 include/efi_hob.h create mode 100644 lib/efi_loader/efi_dxe.c create mode 100644 lib/efi_loader/efi_hob.c
Please can you document how to actually run UEFI like this? Also, is it possible to add a test for this new code?
Regards, Simon

Simon Glass sjg@chromium.org schrieb am Fr., 3. Jan. 2025, 02:40:
Hi Heinrich,
On Fri, 3 Jan 2025 at 07:11, Heinrich Schuchardt heinrich.schuchardt@canonical.com wrote:
Currently running the SCT fails on x86. The EFI shell overrides U-Boot's Simple Text Output Protocol. When ConsoleLoggerPrintWithPageBreak() is invoked with ConsoleInfo == NULL a crash occurs.
Debugging requires running the debug version of the UEFI shell. We can use `add-symbol-file` in gdb to point to
Build/Shell/DEBUG_GCC/X64/ShellPkg/Application/Shell/Shell/DEBUG/Shell.dll
and the load address of Shell.efi.
The debug version of the UEFI shell checks several requirements and fails to run without them:
- HOB list (only on x86)
- HII configuration protocol
- DXE services table
Implement the missing requirements.
When starting image add the image load address to the debug output.
Heinrich Schuchardt (4): efi_loader: implement a HOB list efi_loader: build with HII configuration protocol efi_loader: install DXE services table efi_loader: print image load address in StartImage
include/efi_dxe.h | 54 ++++++++++ include/efi_hob.h | 32 ++++++ include/efi_loader.h | 16 +++ lib/efi_loader/Kconfig | 15 +++ lib/efi_loader/Makefile | 4 +- lib/efi_loader/efi_boottime.c | 7 +- lib/efi_loader/efi_dxe.c | 176 ++++++++++++++++++++++++++++++++ lib/efi_loader/efi_hii_config.c | 4 - lib/efi_loader/efi_hob.c | 33 ++++++ lib/efi_loader/efi_root_node.c | 3 + lib/efi_loader/efi_setup.c | 13 +++ 11 files changed, 349 insertions(+), 8 deletions(-) create mode 100644 include/efi_dxe.h create mode 100644 include/efi_hob.h create mode 100644 lib/efi_loader/efi_dxe.c create mode 100644 lib/efi_loader/efi_hob.c
Please can you document how to actually run UEFI like this? Also, is it possible to add a test for this new code?
Building the EFI Shell is documented in the EDK II project. U-Boot's bootefi command is already documented. What documentation are you missing?
The HII config protocol just returns EFI_OUT_OF_RESOURCES in each function. So there is not much functionality to be tested. We could verify that the protocol as well as the HOB and DXE tables are available.
Best regards
Heinrich

Hi Heinrich,
On Fri, 3 Jan 2025 at 16:35, Heinrich Schuchardt heinrich.schuchardt@canonical.com wrote:
Simon Glass sjg@chromium.org schrieb am Fr., 3. Jan. 2025, 02:40:
Hi Heinrich,
On Fri, 3 Jan 2025 at 07:11, Heinrich Schuchardt heinrich.schuchardt@canonical.com wrote:
Currently running the SCT fails on x86. The EFI shell overrides U-Boot's Simple Text Output Protocol. When ConsoleLoggerPrintWithPageBreak() is invoked with ConsoleInfo == NULL a crash occurs.
Debugging requires running the debug version of the UEFI shell. We can use `add-symbol-file` in gdb to point to Build/Shell/DEBUG_GCC/X64/ShellPkg/Application/Shell/Shell/DEBUG/Shell.dll and the load address of Shell.efi.
The debug version of the UEFI shell checks several requirements and fails to run without them:
- HOB list (only on x86)
- HII configuration protocol
- DXE services table
Implement the missing requirements.
When starting image add the image load address to the debug output.
Heinrich Schuchardt (4): efi_loader: implement a HOB list efi_loader: build with HII configuration protocol efi_loader: install DXE services table efi_loader: print image load address in StartImage
include/efi_dxe.h | 54 ++++++++++ include/efi_hob.h | 32 ++++++ include/efi_loader.h | 16 +++ lib/efi_loader/Kconfig | 15 +++ lib/efi_loader/Makefile | 4 +- lib/efi_loader/efi_boottime.c | 7 +- lib/efi_loader/efi_dxe.c | 176 ++++++++++++++++++++++++++++++++ lib/efi_loader/efi_hii_config.c | 4 - lib/efi_loader/efi_hob.c | 33 ++++++ lib/efi_loader/efi_root_node.c | 3 + lib/efi_loader/efi_setup.c | 13 +++ 11 files changed, 349 insertions(+), 8 deletions(-) create mode 100644 include/efi_dxe.h create mode 100644 include/efi_hob.h create mode 100644 lib/efi_loader/efi_dxe.c create mode 100644 lib/efi_loader/efi_hob.c
Please can you document how to actually run UEFI like this? Also, is it possible to add a test for this new code?
Building the EFI Shell is documented in the EDK II project. U-Boot's bootefi command is already documented. What documentation are you missing?
How about this:
Mention ACTIVE_PLATFORM = ShellPkg/ShellPkg.dsc
How to run U-Boot (presumably with gdb?)
How to figure out the load address when the .dll is loaded
Perhaps where to set a breakpoint, etc?
I think it could take the form of an example showing the commands to do the debugging would be helpful. Probably 'history' will do some of the work for you.
The HII config protocol just returns EFI_OUT_OF_RESOURCES in each function. So there is not much functionality to be tested. We could verify that the protocol as well as the HOB and DXE tables are available.
Yes I think that would be good.
Regards, Simon
participants (3)
-
Heinrich Schuchardt
-
Ilias Apalodimas
-
Simon Glass