[PATCH 00/20] efi: App and devicetree improvements

From: Simon Glass <sjg@chromium.org> This series improves U-Boot's EFI app support and adds new functionality for managing devicetree reserved-memory regions. The main focus is on enhancing memory management when running as an EFI application. A new mechanism is introduced to sync EFI reserved-memory regions (such as runtime services and ACPI tables) with the devicetree's /reserved-memory nodes. This ensures that Linux doesn't inadvertently use memory regions that EFI firmware has reserved. The main improvements are: - New 'fdt reserved' command to display devicetree reserved-memory regions - New 'efi memsync' command to synchronize EFI memory map with devicetree - Enhance EFI application support with better memory region handling - Improve EFI debugging commands and device path handling - Better integrate EFI boot services and devicetree setup There are a few other minor thigns: - Enhance efidebug commands with media device and driver information - Expose EFI device-paths in a few places in bootstd - Improve bootflow device reporting - ARM-specific fixes for exception level handling This series addresses many of the issues found in booting Linux on Qualcomm X-Elite laptops using the EFI app. Simon Glass (20): efi: Set the efi_media device name when binding efi: app: Avoid switching exception levels on ARM efi: app: Avoid freeing memory on exit efi: Add a way to show media devices efi: Add all messaging types for device paths efi: Convert a device-path to a uclass and name efi: Add a uclass column to efidebug media command efi: Implement efidebug show drivers in the app boot: Correct filename in bootmeth_common_read_file() boot: Show the device path for EFI bootflows boot: Show the underlying bootflow device in the app efi: Use abuf when reading EFI variables efi: Add a command to help with shim efi: Add an efi subcommand to show the loaded image fdt: Add a function to show the reserved-memory nodes fdt: Add a command to show reserved-memory regions efi: Provide a way to sync EFI reserved-memory to fdt fdt: Provide a command to sync the reserve-memory node efi: app: Add a simple-framebuffer node if enabled efi: app: Sync EFI reserved-memory to the devicetree boot/bootmeth-uclass.c | 2 +- boot/fdt_support.c | 54 ++++++++ cmd/Kconfig | 9 ++ cmd/Makefile | 1 + cmd/bootflow.c | 38 +++++- cmd/efi.c | 37 ++++- cmd/efidebug.c | 73 +++++++--- cmd/fdt.c | 7 +- cmd/nvedit_efi.c | 62 ++++++--- cmd/shim.c | 65 +++++++++ doc/usage/cmd/efi.rst | 50 +++++++ doc/usage/cmd/efidebug.rst | 24 +++- doc/usage/cmd/fdt.rst | 26 ++++ doc/usage/cmd/shim.rst | 101 ++++++++++++++ doc/usage/index.rst | 1 + include/efi.h | 51 +++++++ include/efi_api.h | 20 ++- include/efi_device_path.h | 25 ++++ include/fdt_support.h | 7 + include/shim.h | 13 ++ lib/efi/device_path.c | 125 +++++++++++++++++ lib/efi_client/app_run.c | 21 ++- lib/efi_client/efi.c | 249 +++++++++++++++++++++++++++++++++- lib/efi_client/efi_app.c | 12 +- lib/efi_client/efi_app_init.c | 21 ++- test/cmd/fdt.c | 40 ++++++ 26 files changed, 1072 insertions(+), 62 deletions(-) create mode 100644 cmd/shim.c create mode 100644 doc/usage/cmd/shim.rst create mode 100644 include/shim.h -- 2.43.0 base-commit: 88123cd086d8999443f84e8311913b7e94b6aa9b branch: apb

From: Simon Glass <sjg@chromium.org> Binding a new efi_media device uses a placeholder name which is then changed after the device is bound. But binding the device immediately causes a child block device to be bound, which uses this placeholder name as its base, rather than the eventual name of the efi_media device. To fix, decide on the name earlier (based on the number of existing devices), then pass that name to device_bind() Signed-off-by: Simon Glass <sjg@chromium.org> --- lib/efi_client/efi_app_init.c | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/lib/efi_client/efi_app_init.c b/lib/efi_client/efi_app_init.c index 7d30e79528f..b5421dc5a91 100644 --- a/lib/efi_client/efi_app_init.c +++ b/lib/efi_client/efi_app_init.c @@ -50,7 +50,7 @@ int efi_bind_block(efi_handle_t handle, struct efi_block_io *blkio, { struct efi_media_plat *plat; struct udevice *dev; - char name[18]; + char name[18], *str; int ret; size_t device_path_len = device_path_length(device_path); @@ -63,13 +63,20 @@ int efi_bind_block(efi_handle_t handle, struct efi_block_io *blkio, if (!plat->device_path) return log_msg_ret("path", -ENOMEM); memcpy(plat->device_path, device_path, device_path_len); - ret = device_bind(dm_root(), DM_DRIVER_GET(efi_media), "efi_media", - plat, ofnode_null(), &dev); - if (ret) - return log_msg_ret("bind", ret); - snprintf(name, sizeof(name), "efi_media_%x", dev_seq(dev)); - device_set_name(dev, name); + snprintf(name, sizeof(name), "efi_media_%x", + uclass_id_count(UCLASS_EFI_MEDIA)); + str = strdup(name); + if (!str) + return -ENOMEM; + + ret = device_bind(dm_root(), DM_DRIVER_GET(efi_media), str, plat, + ofnode_null(), &dev); + if (ret) { + free(str); + return log_msg_ret("bind", ret); + } + device_set_name_alloced(dev); *devp = dev; return 0; -- 2.43.0

From: Simon Glass <sjg@chromium.org> The EFI app runs under the environment provided to it and is not allowed to change the exception level. Remove this call for the app. Signed-off-by: Simon Glass <sjg@chromium.org> --- lib/efi_client/app_run.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/efi_client/app_run.c b/lib/efi_client/app_run.c index d2519985c87..03cc29778d8 100644 --- a/lib/efi_client/app_run.c +++ b/lib/efi_client/app_run.c @@ -31,7 +31,8 @@ static efi_status_t do_bootefi_exec(efi_handle_t handle, void *load_options) efi_status_t ret; /* On ARM switch from EL3 or secure mode to EL2 or non-secure mode */ - switch_to_non_secure_mode(); + if (!IS_ENABLED(CONFIG_EFI_APP)) + switch_to_non_secure_mode(); /* TODO(sjg@chromium.org): Set watchdog */ -- 2.43.0

From: Simon Glass <sjg@chromium.org> The private data is used to perform the exit, so freeing anything used by the app may cause a hang or crash. The underlying EFI system should be able to free any memory allocated by the app, so just skip the call to free_memory() Signed-off-by: Simon Glass <sjg@chromium.org> --- lib/efi_client/efi_app.c | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/efi_client/efi_app.c b/lib/efi_client/efi_app.c index 7c9c156e006..f67973dbb85 100644 --- a/lib/efi_client/efi_app.c +++ b/lib/efi_client/efi_app.c @@ -245,7 +245,6 @@ static void efi_exit(void) struct efi_priv *priv = efi_get_priv(); printf("U-Boot EFI exiting\n"); - free_memory(priv); priv->boot->exit(priv->parent_image, EFI_SUCCESS, 0, NULL); } -- 2.43.0

From: Simon Glass <sjg@chromium.org> Add a new 'efidebug media' subcommand to show media devices and their device-paths. Signed-off-by: Simon Glass <sjg@chromium.org> --- cmd/efidebug.c | 43 ++++++++++++++++++++++++++++++++++++++ doc/usage/cmd/efidebug.rst | 21 ++++++++++++++++++- 2 files changed, 63 insertions(+), 1 deletion(-) diff --git a/cmd/efidebug.c b/cmd/efidebug.c index 1515a508e2d..1d943113054 100644 --- a/cmd/efidebug.c +++ b/cmd/efidebug.c @@ -8,6 +8,8 @@ #include <charset.h> #include <command.h> #include <dm/device.h> +#include <dm/uclass.h> +#include <efi.h> #include <efi_device_path.h> #include <efi_dt_fixup.h> #include <efi_load_initrd.h> @@ -1604,6 +1606,43 @@ static int do_efi_test(struct cmd_tbl *cmdtp, int flag, return cp->cmd(cmdtp, flag, argc, argv); } +/** + * do_efi_show_media() - show EFI media devices + * + * @cmdtp: Command table + * @flag: Command flag + * @argc: Number of arguments + * @argv: Argument array + * Return: CMD_RET_SUCCESS on success, CMD_RET_FAILURE on failure + * + * Implement efidebug "media" sub-command. + * Show all EFI media devices and their device paths. + */ +static int do_efi_show_media(struct cmd_tbl *cmdtp, int flag, + int argc, char *const argv[]) +{ + struct udevice *dev; + struct uclass *uc; + int ret; + + ret = uclass_get(UCLASS_EFI_MEDIA, &uc); + if (ret) { + printf("Cannot get EFI media uclass: (err=%dE)\n", ret); + return CMD_RET_FAILURE; + } + + printf("Device Device Path\n"); + printf("------------------- -----------\n"); + + uclass_foreach_dev(dev, uc) { + struct efi_media_plat *plat = dev_get_plat(dev); + + printf("%-20s %pD\n", dev->name, plat->device_path); + } + + return CMD_RET_SUCCESS; +} + /** * do_efi_query_info() - QueryVariableInfo EFI service * @@ -1670,6 +1709,8 @@ static struct cmd_tbl cmd_efidebug_sub[] = { U_BOOT_CMD_MKENT(images, CONFIG_SYS_MAXARGS, 1, do_efi_show_images, "", ""), U_BOOT_CMD_MKENT(log, CONFIG_SYS_MAXARGS, 1, do_efi_show_log, "", ""), + U_BOOT_CMD_MKENT(media, CONFIG_SYS_MAXARGS, 1, do_efi_show_media, + "", ""), U_BOOT_CMD_MKENT(memmap, CONFIG_SYS_MAXARGS, 1, do_efi_show_memmap, "", ""), U_BOOT_CMD_MKENT(tables, CONFIG_SYS_MAXARGS, 1, do_efi_show_tables, @@ -1772,6 +1813,8 @@ U_BOOT_LONGHELP(efidebug, " - show loaded images\n" "efidebug log\n" " - show UEFI log\n" + "efidebug media\n" + " - show EFI media devices\n" "efidebug memmap\n" " - show UEFI memory map\n" "efidebug tables\n" diff --git a/doc/usage/cmd/efidebug.rst b/doc/usage/cmd/efidebug.rst index 5eca4079f82..90e0b9c4546 100644 --- a/doc/usage/cmd/efidebug.rst +++ b/doc/usage/cmd/efidebug.rst @@ -14,6 +14,7 @@ Synopsis :: efidebug log + efidebug media Description ----------- @@ -21,7 +22,7 @@ Description The *efidebug* command provides access to debugging features for the EFI-loader subsystem. -Only one of the subcommands are documented at present. +Only two of the subcommands are documented at present. efidebug log ~~~~~~~~~~~~ @@ -30,10 +31,28 @@ This shows a log of EFI boot-services calls which have been handled since U-Boot started. This can be useful to see what the app is doing, or even what U-Boot itself has called. +efidebug media +~~~~~~~~~~~~~~ + +This shows a list of all EFI media devices and their corresponding device paths. +Each EFI media device represents a block device that was discovered through EFI +boot services, such as hard drives, USB storage, or other bootable media. The +device path shows the EFI device path for each device, which can be useful for +debugging boot issues or understanding the system topology. + Example ------- +This shows checking the EFI media devices:: + + => efidebug media + Device Device Path + ------ ----------- + efi_media_1 PciRoot(0x0)/Pci(0x3,0x0)/Sata(0x0,0xFFFF,0x0) + efi_media_2 PciRoot(0x0)/Pci(0x5,0x0) + + This shows checking the log, then using 'efidebug tables' to fully set up the EFI-loader subsystem, then checking the log again:: -- 2.43.0

From: Simon Glass <sjg@chromium.org> Fill out the rest of these values from the spec, so that we can (later) provide a more useful summary for the user. Co-developed-by: Claude <noreply@anthropic.com> Signed-off-by: Simon Glass <sjg@chromium.org> --- include/efi_api.h | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/include/efi_api.h b/include/efi_api.h index 876c1ac2bbe..b3f6172e97a 100644 --- a/include/efi_api.h +++ b/include/efi_api.h @@ -643,20 +643,34 @@ struct efi_device_path_acpi_path { u32 uid; } __packed; -#define DEVICE_PATH_TYPE_MESSAGING_DEVICE 0x03 +# define DEVICE_PATH_TYPE_MESSAGING_DEVICE 0x03 # define DEVICE_PATH_SUB_TYPE_MSG_ATAPI 0x01 # define DEVICE_PATH_SUB_TYPE_MSG_SCSI 0x02 +# define DEVICE_PATH_SUB_TYPE_MSG_FIREWIRE 0x03 +# define DEVICE_PATH_SUB_TYPE_MSG_1394 0x04 # define DEVICE_PATH_SUB_TYPE_MSG_USB 0x05 +# define DEVICE_PATH_SUB_TYPE_MSG_I2O 0x06 +# define DEVICE_PATH_SUB_TYPE_MSG_INFINIBAND 0x09 +# define DEVICE_PATH_SUB_TYPE_MSG_VENDOR 0x0a # define DEVICE_PATH_SUB_TYPE_MSG_MAC_ADDR 0x0b # define DEVICE_PATH_SUB_TYPE_MSG_IPV4 0x0c +# define DEVICE_PATH_SUB_TYPE_MSG_IPV6 0x0d # define DEVICE_PATH_SUB_TYPE_MSG_UART 0x0e # define DEVICE_PATH_SUB_TYPE_MSG_USB_CLASS 0x0f # define DEVICE_PATH_SUB_TYPE_MSG_USB_WWI 0x10 # define DEVICE_PATH_SUB_TYPE_MSG_SATA 0x12 +# define DEVICE_PATH_SUB_TYPE_MSG_ISCSI 0x13 +# define DEVICE_PATH_SUB_TYPE_MSG_VLAN 0x14 +# define DEVICE_PATH_SUB_TYPE_MSG_FIBRECHAN 0x15 +# define DEVICE_PATH_SUB_TYPE_MSG_FIBRECHAN_EX 0x16 # define DEVICE_PATH_SUB_TYPE_MSG_NVME 0x17 # define DEVICE_PATH_SUB_TYPE_MSG_URI 0x18 # define DEVICE_PATH_SUB_TYPE_MSG_SD 0x1a # define DEVICE_PATH_SUB_TYPE_MSG_MMC 0x1d +# define DEVICE_PATH_SUB_TYPE_MSG_SAS 0x22 +# define DEVICE_PATH_SUB_TYPE_MSG_SAS_EX 0x23 +# define DEVICE_PATH_SUB_TYPE_MSG_UFS 0x19 +# define DEVICE_PATH_SUB_TYPE_MSG_EMMC 0x1c struct efi_device_path_atapi { struct efi_device_path dp; -- 2.43.0

From: Simon Glass <sjg@chromium.org> Add a function which looks through a device path and tries to figure out the corresponding name (e.g. 'nvme' and uclass ID. This can be useful for showing a short summary of the device path. Co-developed-by: Claude <noreply@anthropic.com> Signed-off-by: Simon Glass <sjg@chromium.org> --- include/efi_device_path.h | 11 +++++ lib/efi/device_path.c | 86 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 97 insertions(+) diff --git a/include/efi_device_path.h b/include/efi_device_path.h index 41b59367762..2e425a6d82b 100644 --- a/include/efi_device_path.h +++ b/include/efi_device_path.h @@ -10,6 +10,7 @@ #include <efi.h> +enum uclass_id; struct blk_desc; struct efi_load_option; struct udevice; @@ -418,4 +419,14 @@ struct efi_device_path *search_gpt_dp_node(struct efi_device_path *device_path); struct efi_device_path *efi_dp_from_http(const char *server, struct udevice *dev); +/** + * efi_dp_guess_uclass() - get the guessed name and uclass from EFI device path + * + * @device_path: EFI device path + * @guessp: Returns the U-Boot uclass ID + * Return: name string + */ +const char *efi_dp_guess_uclass(struct efi_device_path *device_path, + enum uclass_id *guessp); + #endif /* EFI_DEVICE_PATH_H */ diff --git a/lib/efi/device_path.c b/lib/efi/device_path.c index 1dc28f81146..191d58bbd2d 100644 --- a/lib/efi/device_path.c +++ b/lib/efi/device_path.c @@ -1290,3 +1290,89 @@ struct efi_device_path *search_gpt_dp_node(struct efi_device_path *device_path) return NULL; } + +const char *efi_dp_guess_uclass(struct efi_device_path *device_path, + enum uclass_id *guessp) +{ + struct efi_device_path *dp = device_path; + enum uclass_id best_guess = UCLASS_BLK; + const char *best_name = "blk"; + + while (dp) { + if (dp->type == DEVICE_PATH_TYPE_MESSAGING_DEVICE) { + switch (dp->sub_type) { + case DEVICE_PATH_SUB_TYPE_MSG_ATAPI: + *guessp = UCLASS_IDE; + return "ide"; + case DEVICE_PATH_SUB_TYPE_MSG_SCSI: + case DEVICE_PATH_SUB_TYPE_MSG_ISCSI: + *guessp = UCLASS_SCSI; + return "scsi"; + case DEVICE_PATH_SUB_TYPE_MSG_FIREWIRE: + case DEVICE_PATH_SUB_TYPE_MSG_1394: + *guessp = UCLASS_BLK; + return "firewire"; + case DEVICE_PATH_SUB_TYPE_MSG_USB: + case DEVICE_PATH_SUB_TYPE_MSG_USB_CLASS: + case DEVICE_PATH_SUB_TYPE_MSG_USB_WWI: + *guessp = UCLASS_USB; + return "usb"; + case DEVICE_PATH_SUB_TYPE_MSG_I2O: + *guessp = UCLASS_BLK; + return "i2o"; + case DEVICE_PATH_SUB_TYPE_MSG_INFINIBAND: + *guessp = UCLASS_ETH; + return "infiniband"; + case DEVICE_PATH_SUB_TYPE_MSG_VENDOR: + *guessp = UCLASS_MISC; + return "vendor"; + case DEVICE_PATH_SUB_TYPE_MSG_MAC_ADDR: + case DEVICE_PATH_SUB_TYPE_MSG_IPV4: + case DEVICE_PATH_SUB_TYPE_MSG_IPV6: + case DEVICE_PATH_SUB_TYPE_MSG_VLAN: + *guessp = UCLASS_ETH; + return "eth"; + case DEVICE_PATH_SUB_TYPE_MSG_UART: + *guessp = UCLASS_SERIAL; + return "serial"; + case DEVICE_PATH_SUB_TYPE_MSG_SATA: + *guessp = UCLASS_AHCI; + return "ahci"; + case DEVICE_PATH_SUB_TYPE_MSG_FIBRECHAN: + case DEVICE_PATH_SUB_TYPE_MSG_FIBRECHAN_EX: + *guessp = UCLASS_SCSI; + return "fibrechan"; + case DEVICE_PATH_SUB_TYPE_MSG_SAS: + case DEVICE_PATH_SUB_TYPE_MSG_SAS_EX: + *guessp = UCLASS_SCSI; + return "sas"; + case DEVICE_PATH_SUB_TYPE_MSG_NVME: + *guessp = UCLASS_NVME; + return "nvme"; + case DEVICE_PATH_SUB_TYPE_MSG_URI: + *guessp = UCLASS_ETH; + return "uri"; + case DEVICE_PATH_SUB_TYPE_MSG_UFS: + *guessp = UCLASS_UFS; + return "ufs"; + case DEVICE_PATH_SUB_TYPE_MSG_SD: + case DEVICE_PATH_SUB_TYPE_MSG_MMC: + case DEVICE_PATH_SUB_TYPE_MSG_EMMC: + *guessp = UCLASS_MMC; + return "mmc"; + default: + break; + } + } else if (dp->type == DEVICE_PATH_TYPE_HARDWARE_DEVICE) { + /* PCI devices could be many things, keep as fallback */ + best_guess = UCLASS_PCI; + best_name = "pci"; + } + dp = efi_dp_next(dp); + } + + *guessp = best_guess; + + return best_name; +} + -- 2.43.0

From: Simon Glass <sjg@chromium.org> Add a new column to the 'efidebug media' command that shows the likely uclass for each EFI media device based on its device path. This uses the new efi_dp_guess_uclass() function which looks through an EFI device-path to determine the corresponding uclass. Co-developed-by: Claude <noreply@anthropic.com> Signed-off-by: Simon Glass <sjg@chromium.org> --- cmd/efidebug.c | 10 +++++++--- doc/usage/cmd/efidebug.rst | 21 ++++++++++++--------- 2 files changed, 19 insertions(+), 12 deletions(-) diff --git a/cmd/efidebug.c b/cmd/efidebug.c index 1d943113054..9c0b6b084cb 100644 --- a/cmd/efidebug.c +++ b/cmd/efidebug.c @@ -1606,6 +1606,7 @@ static int do_efi_test(struct cmd_tbl *cmdtp, int flag, return cp->cmd(cmdtp, flag, argc, argv); } + /** * do_efi_show_media() - show EFI media devices * @@ -1631,13 +1632,16 @@ static int do_efi_show_media(struct cmd_tbl *cmdtp, int flag, return CMD_RET_FAILURE; } - printf("Device Device Path\n"); - printf("------------------- -----------\n"); + printf("Device Media type Device Path\n"); + printf("------------------- --------------- -----------\n"); uclass_foreach_dev(dev, uc) { struct efi_media_plat *plat = dev_get_plat(dev); + enum uclass_id id; + const char *name = efi_dp_guess_uclass(plat->device_path, &id); - printf("%-20s %pD\n", dev->name, plat->device_path); + printf("%-20s %-15s %pD\n", dev->name, name, + plat->device_path); } return CMD_RET_SUCCESS; diff --git a/doc/usage/cmd/efidebug.rst b/doc/usage/cmd/efidebug.rst index 90e0b9c4546..903293ad3d8 100644 --- a/doc/usage/cmd/efidebug.rst +++ b/doc/usage/cmd/efidebug.rst @@ -34,11 +34,14 @@ itself has called. efidebug media ~~~~~~~~~~~~~~ -This shows a list of all EFI media devices and their corresponding device paths. -Each EFI media device represents a block device that was discovered through EFI -boot services, such as hard drives, USB storage, or other bootable media. The -device path shows the EFI device path for each device, which can be useful for -debugging boot issues or understanding the system topology. +This shows a list of all EFI media devices, their likely U-Boot uclass, and +their corresponding device paths. Each EFI media device represents a block +device that was discovered through EFI boot services, such as hard drives, USB +storage, or other bootable media. The U-Boot Class column shows which U-Boot +driver subsystem would likely handle the device (e.g., "ahci" for SATA drives, +"usb" for USB storage). The device path shows the EFI device path for each +device, which can be useful for debugging boot issues or understanding the +system topology. Example @@ -47,10 +50,10 @@ Example This shows checking the EFI media devices:: => efidebug media - Device Device Path - ------ ----------- - efi_media_1 PciRoot(0x0)/Pci(0x3,0x0)/Sata(0x0,0xFFFF,0x0) - efi_media_2 PciRoot(0x0)/Pci(0x5,0x0) + Device U-Boot Class Device Path + ------------------- --------------- ----------- + efi_media_1 ahci PciRoot(0x0)/Pci(0x3,0x0)/Sata(0x0,0xFFFF,0x0) + efi_media_2 pci PciRoot(0x0)/Pci(0x5,0x0) This shows checking the log, then using 'efidebug tables' to fully set up the -- 2.43.0

From: Simon Glass <sjg@chromium.org> Adjust the code slightly to support the final subcommand in efidebug that is currently unavailable in the app: 'efidebug drivers'. Drop the now-unused app_not_supported() function. Signed-off-by: Simon Glass <sjg@chromium.org> --- cmd/efidebug.c | 26 +++++++------------------- 1 file changed, 7 insertions(+), 19 deletions(-) diff --git a/cmd/efidebug.c b/cmd/efidebug.c index 9c0b6b084cb..f88da42c2c4 100644 --- a/cmd/efidebug.c +++ b/cmd/efidebug.c @@ -28,16 +28,6 @@ #include <linux/ctype.h> #include <linux/err.h> -static bool app_not_supported(const char *cmd) -{ - if (!IS_ENABLED(CONFIG_EFI_APP)) - return false; - - printf("Command '%s' is not yet supported in the app\n", cmd); - - return true; -} - #ifdef CONFIG_EFI_HAVE_CAPSULE_SUPPORT /** * do_efi_capsule_update() - process a capsule update @@ -372,7 +362,7 @@ static const char sep[] = "================"; static int efi_get_driver_handle_info(efi_handle_t handle, u16 **driver_name, u16 **image_path) { - struct efi_handler *handler; + struct efi_boot_services *boot = efi_get_boot(); struct efi_loaded_image *image; efi_status_t ret; @@ -383,13 +373,13 @@ static int efi_get_driver_handle_info(efi_handle_t handle, u16 **driver_name, *driver_name = NULL; /* image name */ - ret = efi_search_protocol(handle, &efi_guid_loaded_image, &handler); + ret = boot->handle_protocol(handle, &efi_guid_loaded_image, + (void **)&image); if (ret != EFI_SUCCESS) { *image_path = NULL; return 0; } - image = handler->protocol_interface; *image_path = efi_dp_str(image->file_path); return 0; @@ -410,17 +400,15 @@ static int efi_get_driver_handle_info(efi_handle_t handle, u16 **driver_name, static int do_efi_show_drivers(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]) { + struct efi_boot_services *boot = efi_get_boot(); efi_handle_t *handles; efi_uintn_t num, i; u16 *driver_name, *image_path_text; efi_status_t ret; - if (app_not_supported("show_drivers")) - return CMD_RET_FAILURE; - - ret = EFI_CALL(efi_locate_handle_buffer( - BY_PROTOCOL, &efi_guid_driver_binding_protocol, - NULL, &num, &handles)); + ret = boot->locate_handle_buffer(BY_PROTOCOL, + &efi_guid_driver_binding_protocol, + NULL, &num, &handles); if (ret != EFI_SUCCESS) return CMD_RET_FAILURE; -- 2.43.0

From: Simon Glass <sjg@chromium.org> This should add the filename provided to the image, not the original bootflow filename. Fix it. Signed-off-by: Simon Glass <sjg@chromium.org> Fixes: 114dd14e38d ("bootmeth: Update the read_file() method to...") --- boot/bootmeth-uclass.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/boot/bootmeth-uclass.c b/boot/bootmeth-uclass.c index 6c0eff7579d..8c191082cf3 100644 --- a/boot/bootmeth-uclass.c +++ b/boot/bootmeth-uclass.c @@ -437,7 +437,7 @@ int bootmeth_common_read_file(struct udevice *dev, struct bootflow *bflow, return ret; *sizep = len_read; - if (!bootflow_img_add(bflow, bflow->fname, type, *addrp, size)) + if (!bootflow_img_add(bflow, file_path, type, *addrp, size)) return log_msg_ret("bci", -ENOMEM); return 0; -- 2.43.0

From: Simon Glass <sjg@chromium.org> If the bootflow relates to the EFI bootmeth, show the device path along with the other info. Signed-off-by: Simon Glass <sjg@chromium.org> --- cmd/bootflow.c | 17 +++++++++++++++++ include/efi.h | 15 +++++++++++++++ include/efi_device_path.h | 14 ++++++++++++++ lib/efi/device_path.c | 37 +++++++++++++++++++++++++++++++++++++ lib/efi_client/app_run.c | 18 ++++++++++++++++++ 5 files changed, 101 insertions(+) diff --git a/cmd/bootflow.c b/cmd/bootflow.c index 464c3e40475..ae692cf521b 100644 --- a/cmd/bootflow.c +++ b/cmd/bootflow.c @@ -13,6 +13,7 @@ #include <command.h> #include <console.h> #include <dm.h> +#include <efi_device_path.h> #include <expo.h> #include <log.h> #include <mapmem.h> @@ -453,6 +454,22 @@ static int do_bootflow_info(struct cmd_tbl *cmdtp, int flag, int argc, printf("FDT addr: %lx\n", bflow->fdt_addr); } printf("Error: %d\n", bflow->err); + if (IS_ENABLED(CONFIG_BOOTMETH_EFI) && + bflow->method->driver == DM_DRIVER_GET(bootmeth_4efi)) { + struct efi_device_path *dp; + bool alloced; + + ret = efi_dp_from_bootflow(bflow, &dp, &alloced); + printf("EFI path "); + if (!ret) { + printf("%pD\n", dp); + if (alloced) + efi_free_pool(dp); + } else { + printf("(err %dE)\n", ret); + } + } + if (dump && bflow->buf) { /* Set some sort of maximum on the size */ int size = min(bflow->size, 10 << 10); diff --git a/include/efi.h b/include/efi.h index 3558c03db23..c07717811da 100644 --- a/include/efi.h +++ b/include/efi.h @@ -23,6 +23,8 @@ #include <net.h> #endif +struct udevice; + /* Type INTN in UEFI specification */ #define efi_intn_t ssize_t /* Type UINTN in UEFI specification*/ @@ -848,4 +850,17 @@ efi_status_t efi_run_image(void *source_buffer, efi_uintn_t source_size, struct efi_device_path *dp_dev, struct efi_device_path *dp_img); +/** + * efi_dp_from_bootdev() - Get the device path from a bootdev + * + * This is only available in the app. It looks up the bootdev and returns the + * assocated device path (attached to its sibling block device) + * + * @dev: UCLASS_BOOTDEV device to check + * @dpp: Returns device path on success + * Returns: 0 if OK, -ve on error + */ +int efi_dp_from_bootdev(const struct udevice *dev, + const struct efi_device_path **dpp); + #endif /* _LINUX_EFI_H */ diff --git a/include/efi_device_path.h b/include/efi_device_path.h index 2e425a6d82b..d030674d6bd 100644 --- a/include/efi_device_path.h +++ b/include/efi_device_path.h @@ -12,6 +12,7 @@ enum uclass_id; struct blk_desc; +struct bootflow; struct efi_load_option; struct udevice; @@ -429,4 +430,17 @@ struct efi_device_path *efi_dp_from_http(const char *server, const char *efi_dp_guess_uclass(struct efi_device_path *device_path, enum uclass_id *guessp); +/** + * efi_dp_from_bootflow() - Get the device path for a bootflow + * + * @bflow: Bootflow to check + * @dpp: Returns the device path + * @allocedp: if NULL, no allocation is permitted, otherwise retrusn true if + * efi_free_pool() must be called to free the device path + * Return: 0 if OK, -EINVAL if @allocedp is NULL and allocation is needed, + * -ve on error + */ +int efi_dp_from_bootflow(const struct bootflow *bflow, + struct efi_device_path **dpp, bool *allocedp); + #endif /* EFI_DEVICE_PATH_H */ diff --git a/lib/efi/device_path.c b/lib/efi/device_path.c index 191d58bbd2d..bae9e5c537a 100644 --- a/lib/efi/device_path.c +++ b/lib/efi/device_path.c @@ -8,6 +8,7 @@ #define LOG_CATEGORY LOGC_EFI #include <blk.h> +#include <bootflow.h> #include <dm.h> #include <dm/root.h> #include <efi_device_path.h> @@ -1376,3 +1377,39 @@ const char *efi_dp_guess_uclass(struct efi_device_path *device_path, return best_name; } +int efi_dp_from_bootflow(const struct bootflow *bflow, + struct efi_device_path **dpp, bool *allocedp) +{ + struct udevice *bdev = bflow->dev; + struct blk_desc *desc; + struct udevice *blk; + int ret; + + if (IS_ENABLED(CONFIG_EFI_APP)) { + const struct efi_device_path *dpc; + + ret = efi_dp_from_bootdev(bflow->dev, &dpc); + if (ret) + return log_msg_ret("dfa", ret); + *dpp = (struct efi_device_path *)dpc; + if (allocedp) + *allocedp = false; + } else { + struct efi_device_path *dp; + + if (!allocedp) + return log_msg_ret("dfb", -EINVAL); + ret = bootdev_get_sibling_blk(bdev, &blk); + if (ret) + return log_msg_ret("dfc", ret); + + desc = dev_get_uclass_plat(blk); + dp = efi_dp_from_part(desc, bflow->part); + if (!dp) + return log_msg_ret("dfd", -ENOMEM); + *allocedp = true; + *dpp = dp; + } + + return 0; +} diff --git a/lib/efi_client/app_run.c b/lib/efi_client/app_run.c index 03cc29778d8..9fc753ceed8 100644 --- a/lib/efi_client/app_run.c +++ b/lib/efi_client/app_run.c @@ -7,6 +7,7 @@ */ #include <bootm.h> +#include <dm.h> #include <efi.h> #include <efi_api.h> #include <efi_device_path.h> @@ -89,3 +90,20 @@ efi_status_t efi_binary_run_dp(void *image, size_t size, void *fdt, { return efi_run_image(image, size, dp_dev, dp_img); } + +int efi_dp_from_bootdev(const struct udevice *dev, + const struct efi_device_path **dpp) +{ + const struct udevice *media = dev_get_parent(dev); + const struct efi_media_plat *plat; + + log_debug("dev '%s': uclass ID %d\n", media->name, + device_get_uclass_id(media)); + if (device_get_uclass_id(media) != UCLASS_EFI_MEDIA) + return log_msg_ret("efb", -ENOTSUPP); + + plat = dev_get_plat(media); + *dpp = plat->device_path; + + return 0; +} -- 2.43.0

From: Simon Glass <sjg@chromium.org> Within the app all media devices are 'efi' so it isn't useful to show that as the media. Look up the media-type of the underlying device, e.g. 'usb' or 'nvme'. This is a lot more helpful, and can make it easy to see which bootflows relates to internal media and which to external, for example. Signed-off-by: Simon Glass <sjg@chromium.org> --- cmd/bootflow.c | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/cmd/bootflow.c b/cmd/bootflow.c index ae692cf521b..20fc04bdda3 100644 --- a/cmd/bootflow.c +++ b/cmd/bootflow.c @@ -70,11 +70,26 @@ static void report_bootflow_err(struct bootflow *bflow, int err) */ static void show_bootflow(int index, struct bootflow *bflow, bool errors) { + const char *name = NULL; + + if (IS_ENABLED(CONFIG_EFI_APP)) { + struct efi_device_path *dp; + enum uclass_id id; + int ret; + + ret = efi_dp_from_bootflow(bflow, &dp, NULL); + if (!ret) + name = efi_dp_guess_uclass(dp, &id); + } else if (bflow->dev) { + name = dev_get_uclass_name(dev_get_parent(bflow->dev)); + } + if (!name) + name = "(none)"; + printf("%3x %-11s %-6s %-9.9s %4x %-25.25s %s\n", index, bflow->method ? bflow->method->name : "(none)", - bootflow_state_get_name(bflow->state), - bflow->dev ? dev_get_uclass_name(dev_get_parent(bflow->dev)) : - "(none)", bflow->part, bflow->name, bflow->fname ?: ""); + bootflow_state_get_name(bflow->state), name, bflow->part, + bflow->name, bflow->fname ?: ""); if (errors) report_bootflow_err(bflow, bflow->err); } -- 2.43.0

From: Simon Glass <sjg@chromium.org> The abuf interface provides a nicer abstraction of the data and size of EFI variables. Create a new efi_read_var() function and export it so it can be used elsewhere. Adjust the existing efi_dump_single_var() to use it. Signed-off-by: Simon Glass <sjg@chromium.org> --- cmd/nvedit_efi.c | 62 ++++++++++++++++++++++++++++++++---------------- include/efi.h | 15 ++++++++++++ 2 files changed, 56 insertions(+), 21 deletions(-) diff --git a/cmd/nvedit_efi.c b/cmd/nvedit_efi.c index 5616e73bcfd..45d6a8ef67a 100644 --- a/cmd/nvedit_efi.c +++ b/cmd/nvedit_efi.c @@ -5,6 +5,7 @@ * Copyright (c) 2018 AKASHI Takahiro, Linaro Limited */ +#include <abuf.h> #include <charset.h> #include <command.h> #include <efi_loader.h> @@ -50,6 +51,36 @@ struct var_info { efi_guid_t guid; }; +int efi_read_var(const u16 *name, const efi_guid_t *guid, u32 *attrp, + struct abuf *buf, u64 *timep) +{ + efi_uintn_t size; + efi_status_t eret; + u32 attr; + u64 time; + + abuf_init(buf); + size = 0; + eret = efi_get_variable_int(name, guid, &attr, &size, NULL, &time); + if (eret == EFI_BUFFER_TOO_SMALL) { + if (!abuf_realloc(buf, size)) + return -ENOMEM; + + eret = efi_get_variable_int(name, guid, &attr, &size, buf->data, + &time); + } + if (eret == EFI_NOT_FOUND) + return -ENOENT; + if (eret != EFI_SUCCESS) + return -EBADF; + if (attrp) + *attrp = attr; + if (timep) + *timep = time; + + return 0; +} + /** * efi_dump_single_var() - show information about a UEFI variable * @@ -63,30 +94,19 @@ struct var_info { static void efi_dump_single_var(u16 *name, const efi_guid_t *guid, bool verbose, bool nodump) { - u32 attributes; - u8 *data; - u64 time; struct rtc_time tm; - efi_uintn_t size; + u32 attributes; + struct abuf buf; int count, i; - efi_status_t ret; - - data = NULL; - size = 0; - ret = efi_get_variable_int(name, guid, &attributes, &size, data, &time); - if (ret == EFI_BUFFER_TOO_SMALL) { - data = malloc(size); - if (!data) - goto out; + u64 time; + int ret; - ret = efi_get_variable_int(name, guid, &attributes, &size, - data, &time); - } - if (ret == EFI_NOT_FOUND) { + ret = efi_read_var(name, guid, &attributes, &buf, &time); + if (ret == -ENOENT) { printf("Error: \"%ls\" not defined\n", name); goto out; } - if (ret != EFI_SUCCESS) + if (ret) goto out; if (verbose) { @@ -103,16 +123,16 @@ static void efi_dump_single_var(u16 *name, const efi_guid_t *guid, count++; puts(efi_var_attrs[i].text); } - printf(", DataSize = 0x%zx\n", size); + printf(", DataSize = 0x%zx\n", buf.size); if (!nodump) print_hex_dump(" ", DUMP_PREFIX_OFFSET, 16, 1, - data, size, true); + buf.data, buf.size, true); } else { printf("%ls\n", name); } out: - free(data); + abuf_uninit(&buf); } static bool match_name(int argc, char *const argv[], u16 *var_name16) diff --git a/include/efi.h b/include/efi.h index c07717811da..07d07050c01 100644 --- a/include/efi.h +++ b/include/efi.h @@ -23,6 +23,7 @@ #include <net.h> #endif +struct abuf; struct udevice; /* Type INTN in UEFI specification */ @@ -863,4 +864,18 @@ efi_status_t efi_run_image(void *source_buffer, efi_uintn_t source_size, int efi_dp_from_bootdev(const struct udevice *dev, const struct efi_device_path **dpp); +/** + * efi_read_var() - Read an EFI variable + * + * @name: Name of variable to read + * @guid: GUID for the variable + * @attrp: Returns variable attributes if non-NULL, on success + * @buf: Returns allocated buffer containing the value + * @timep: Returns the timestamp for the variable if non_NULL + * Return: 0 if OK, -ENOENT if the variable was not found, -EBADF if something + * went wrong when reading + */ +int efi_read_var(const u16 *name, const efi_guid_t *guid, u32 *attrp, + struct abuf *buf, u64 *timep); + #endif /* _LINUX_EFI_H */ -- 2.43.0

From: Simon Glass <sjg@chromium.org> Shim is a program which normally comes before U-Boot in the boot process. But when the app runs first, it can sometimes chain Shim since that is what is contained within the bootaa64.efi file, for example. Add a simple command for dealing with shim. For now it only supports enabling verbosity. Co-developed-by: Claude <noreply@anthropic.com> Signed-off-by: Simon Glass <sjg@chromium.org> --- cmd/Kconfig | 9 ++++ cmd/Makefile | 1 + cmd/shim.c | 65 ++++++++++++++++++++++++++ doc/usage/cmd/shim.rst | 101 +++++++++++++++++++++++++++++++++++++++++ doc/usage/index.rst | 1 + include/efi.h | 3 ++ include/efi_api.h | 4 ++ include/shim.h | 13 ++++++ lib/efi/device_path.c | 2 + 9 files changed, 199 insertions(+) create mode 100644 cmd/shim.c create mode 100644 doc/usage/cmd/shim.rst create mode 100644 include/shim.h diff --git a/cmd/Kconfig b/cmd/Kconfig index 99101ff6c82..6a3ef56b3b9 100644 --- a/cmd/Kconfig +++ b/cmd/Kconfig @@ -547,6 +547,15 @@ config SYS_XIMG_LEN It should be large enough to fit uncompressed size of FIT piece we are extracting. +config CMD_SHIM + bool "shim" + depends on CMD_NVEDIT_EFI + default y if SANDBOX || EFI_APP + help + Provides a few commands for dealing with Shim being in the boot + chain. This can be useful when debugging booting, particularly on + x86 machines. + config CMD_SPL bool "spl export - Export boot information for Falcon boot" depends on SPL diff --git a/cmd/Makefile b/cmd/Makefile index 407056b778b..bc381905729 100644 --- a/cmd/Makefile +++ b/cmd/Makefile @@ -174,6 +174,7 @@ obj-$(CONFIG_CMD_SHA1SUM) += sha1sum.o obj-$(CONFIG_CMD_SEAMA) += seama.o obj-$(CONFIG_CMD_SETEXPR) += setexpr.o obj-$(CONFIG_CMD_SETEXPR_FMT) += printf.o +obj-$(CONFIG_CMD_SHIM) += shim.o obj-$(CONFIG_CMD_SPI) += spi.o obj-$(CONFIG_CMD_STRINGS) += strings.o obj-$(CONFIG_CMD_SMBIOS) += smbios.o diff --git a/cmd/shim.c b/cmd/shim.c new file mode 100644 index 00000000000..903f1823f19 --- /dev/null +++ b/cmd/shim.c @@ -0,0 +1,65 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Control of settings for Shim + * + * Copyright 2025 Simon Glass <sjg@chromium.org> + */ + +#define __efi_runtime + +#include <abuf.h> +#include <command.h> +#include <efi.h> +#include <efi_variable.h> +#include <errno.h> +#include <shim.h> +#include <vsprintf.h> + +static int do_shim_debug(struct cmd_tbl *cmdtp, int flag, int argc, + char *const argv[]) +{ + efi_status_t eret; + struct abuf buf; + const char *sub; + u32 value; + int ret; + + sub = cmd_arg1(argc, argv); + if (!sub) { + ret = efi_read_var(SHIM_VERBOSE_VAR_NAME, &efi_shim_lock, NULL, + &buf, NULL); + if (ret == -ENOENT) { + value = 0; + } else if (ret) { + printf("Failed to read variable (err=%dE)\n", ret); + goto fail; + } else if (buf.size != sizeof(value)) { + printf("Invalid value size %zd\n", buf.size); + goto fail; + } else { + value = *(typeof(value) *)buf.data; + } + printf("%d\n", value); + } else { + value = hextoul(sub, NULL) ? 1 : 0; + eret = efi_set_variable_int(SHIM_VERBOSE_VAR_NAME, + &efi_shim_lock, + EFI_VARIABLE_BOOTSERVICE_ACCESS, + sizeof(value), &value, false); + if (eret) { + printf("Failed to write variable (err=%lx)\n", eret); + goto fail; + } + } + + return 0; + +fail: + return 1; +} + +U_BOOT_LONGHELP(shim, + "debug [<0/1>] - Enable / disable debug verbose mode"); + +U_BOOT_CMD_WITH_SUBCMDS(shim, "Shim utilities", shim_help_text, + U_BOOT_SUBCMD_MKENT(debug, 3, 1, do_shim_debug)); diff --git a/doc/usage/cmd/shim.rst b/doc/usage/cmd/shim.rst new file mode 100644 index 00000000000..285dd200558 --- /dev/null +++ b/doc/usage/cmd/shim.rst @@ -0,0 +1,101 @@ +.. SPDX-License-Identifier: GPL-2.0+ + +shim command +============ + +Synopsis +-------- + +:: + + shim debug [<0/1>] + +Description +----------- + +The ``shim`` command provides utilities for controlling and configuring the +UEFI Shim bootloader when U-Boot is running as an EFI application. Shim is a +UEFI bootloader that is used to verify and boot signed operating system +loaders, commonly used in secure boot environments. + +The ``shim debug`` subcommand manages the Shim verbose debugging mode through +the ``SHIM_VERBOSE`` EFI variable. + +Subcommands +~~~~~~~~~~~ + +shim debug +^^^^^^^^^^ + +Controls the Shim verbose debugging mode. + +**Usage:** + +:: + + shim debug # Display current debug state (0 or 1) + shim debug 0 # Disable verbose debugging + shim debug 1 # Enable verbose debugging + +The command reads from or writes to the ``SHIM_VERBOSE`` EFI variable in the +Shim Lock GUID namespace. When verbose mode is enabled (value = 1), Shim will +output additional debugging information during the boot process. When disabled +(value = 0 or variable doesn't exist), Shim operates silently. + +**Parameters:** + +* ``<0/1>`` - Optional parameter to set debug mode: + + * ``0`` - Disable verbose debugging + * ``1`` - Enable verbose debugging + * If omitted, displays current debug state + +**Return value:** + +The command returns 0 on success, 1 on failure. + +**Examples:** + +Check current debug state:: + + => shim debug + 0 + +Enable verbose debugging:: + + => shim debug 1 + +Disable verbose debugging:: + + => shim debug 0 + +Configuration +~~~~~~~~~~~~~ + +The shim command is available when: + +* ``CONFIG_CMD_SHIM`` is enabled +* U-Boot is running as an EFI application +* EFI-variable support is available + +Implementation Details +~~~~~~~~~~~~~~~~~~~~~~ + +The command uses the EFI variable services to read and write the +``SHIM_VERBOSE`` variable with the following characteristics: + +* **Variable Name:** ``SHIM_VERBOSE`` (Unicode string) +* **GUID:** EFI Shim Lock GUID (``605dab50-e046-4300-abb6-3dd810dd8b23``) +* **Attributes:** ``EFI_VARIABLE_BOOTSERVICE_ACCESS`` +* **Data Type:** 32-bit unsigned integer (4 bytes) +* **Values:** 0 (disabled) or 1 (enabled) + +The variable is stored in the EFI variable store and persists across reboots +until explicitly changed or the variable store is cleared. + +See Also +~~~~~~~~ + +* :doc:`efidebug` - EFI debugging utilities +* :doc:`bootefi` - Boot EFI applications +* :doc:`/develop/uefi/u-boot_on_efi` diff --git a/doc/usage/index.rst b/doc/usage/index.rst index 585aa3f9784..3b45d443d5c 100644 --- a/doc/usage/index.rst +++ b/doc/usage/index.rst @@ -115,6 +115,7 @@ Shell commands cmd/seama cmd/setexpr cmd/sf + cmd/shim cmd/size cmd/sleep cmd/sm diff --git a/include/efi.h b/include/efi.h index 07d07050c01..2ca7cc30d52 100644 --- a/include/efi.h +++ b/include/efi.h @@ -163,6 +163,9 @@ extern const efi_guid_t efi_guid_component_name2; /* GUIDs for authentication - most of these are still in efi_loader.h */ extern const efi_guid_t efi_guid_image_security_database; +/* Access to Shim variables */ +extern const efi_guid_t efi_shim_lock; + /* Generic EFI table header */ struct efi_table_hdr { u64 signature; diff --git a/include/efi_api.h b/include/efi_api.h index b3f6172e97a..00a9d29b8fe 100644 --- a/include/efi_api.h +++ b/include/efi_api.h @@ -487,6 +487,10 @@ struct efi_runtime_services { EFI_GUID(0x6a7a5cff, 0xe8d9, 0x4f70, \ 0xba, 0xda, 0x75, 0xab, 0x30, 0x25, 0xce, 0x14) +#define EFI_SHIM_LOCK_GUID \ + EFI_GUID(0x605dab50, 0xe046, 0x4300, \ + 0xab, 0xb6, 0x3d, 0xd8, 0x10, 0xdd, 0x8b, 0x23) + /** * struct efi_configuration_table - EFI Configuration Table * diff --git a/include/shim.h b/include/shim.h new file mode 100644 index 00000000000..23061398933 --- /dev/null +++ b/include/shim.h @@ -0,0 +1,13 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Shim features and settings + * + * Copyright 2025 Simon Glass <sjg@chromium.org> + */ + +#ifndef __SHIM_H +#define __SHIM_H + +#define SHIM_VERBOSE_VAR_NAME L"SHIM_VERBOSE" + +#endif diff --git a/lib/efi/device_path.c b/lib/efi/device_path.c index bae9e5c537a..b09ea030341 100644 --- a/lib/efi/device_path.c +++ b/lib/efi/device_path.c @@ -43,6 +43,8 @@ const efi_guid_t efi_guid_component_name2 = EFI_COMPONENT_NAME2_PROTOCOL_GUID; const efi_guid_t efi_guid_image_security_database = EFI_IMAGE_SECURITY_DATABASE_GUID; +const efi_guid_t efi_shim_lock = EFI_SHIM_LOCK_GUID; + /* template EFI_DP_END node: */ const struct efi_device_path EFI_DP_END = { .type = DEVICE_PATH_TYPE_END, -- 2.43.0

From: Simon Glass <sjg@chromium.org> Sometimes it is useful to see the device-path of the app itself. Add a new 'efi image' command for this. Signed-off-by: Simon Glass <sjg@chromium.org> --- cmd/efi.c | 15 +++++++++++++++ doc/usage/cmd/efi.rst | 14 ++++++++++++++ include/efi.h | 2 ++ 3 files changed, 31 insertions(+) diff --git a/cmd/efi.c b/cmd/efi.c index 91feec1c051..c59219ddf01 100644 --- a/cmd/efi.c +++ b/cmd/efi.c @@ -17,6 +17,19 @@ DECLARE_GLOBAL_DATA_PTR; +static int do_efi_image(struct cmd_tbl *cmdtp, int flag, int argc, + char *const argv[]) +{ + struct efi_priv *priv = efi_get_priv(); + struct efi_loaded_image *lim = priv->loaded_image; + u16 *path; + + path = efi_dp_str(lim->file_path); + printf("Loaded-image path: %ls\n", path); + + return 0; +} + static int h_cmp_entry(const void *v1, const void *v2) { const struct efi_mem_desc *desc1 = v1; @@ -186,6 +199,7 @@ static int do_efi_tables(struct cmd_tbl *cmdtp, int flag, int argc, } static struct cmd_tbl efi_commands[] = { + U_BOOT_CMD_MKENT(image, 1, 1, do_efi_image, "", ""), U_BOOT_CMD_MKENT(mem, 1, 1, do_efi_mem, "", ""), U_BOOT_CMD_MKENT(tables, 1, 1, do_efi_tables, "", ""), }; @@ -211,6 +225,7 @@ static int do_efi(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]) U_BOOT_CMD( efi, 3, 1, do_efi, "EFI access", + "image Dump loaded-image info\n" "mem [all] Dump memory information [include boot services]\n" "tables Dump tables" ); diff --git a/doc/usage/cmd/efi.rst b/doc/usage/cmd/efi.rst index b19d36188a9..e5d8913c94b 100644 --- a/doc/usage/cmd/efi.rst +++ b/doc/usage/cmd/efi.rst @@ -12,6 +12,7 @@ Synopsis :: + efi image efi mem [all] efi tables @@ -26,6 +27,16 @@ information. When running as an EFI payload, EFI boot services have been stopped, so it uses the information collected by the boot stub before that happened. +efi image +~~~~~~~~~ + +This shows the loaded image path information for the currently running EFI +application. The loaded image protocol provides access to the device path +from which the image was loaded. + +The output shows the file path in EFI device path format, displayed as a +human-readable Unicode string. + efi mem ~~~~~~~ @@ -71,6 +82,9 @@ Example :: + => efi image + Loaded-image path: u-boot-app.efi + => efi mem EFI table at 0, memory map 000000001ad38b60, size 1260, key a79, version 1, descr. size 0x30 # Type Physical Virtual Size Attributes diff --git a/include/efi.h b/include/efi.h index 2ca7cc30d52..530b127bde4 100644 --- a/include/efi.h +++ b/include/efi.h @@ -881,4 +881,6 @@ int efi_dp_from_bootdev(const struct udevice *dev, int efi_read_var(const u16 *name, const efi_guid_t *guid, u32 *attrp, struct abuf *buf, u64 *timep); +uint16_t *efi_dp_str(struct efi_device_path *dp); + #endif /* _LINUX_EFI_H */ -- 2.43.0

From: Simon Glass <sjg@chromium.org> Add a new helper which lists the subnodes of the reserved-memory node. This can be helpful when checking the devicetree before booting. Co-developed-by: Claude <noreply@anthropic.com> Signed-off-by: Simon Glass <sjg@chromium.org> --- boot/fdt_support.c | 54 +++++++++++++++++++++++++++++++++++++++++++ include/fdt_support.h | 7 ++++++ 2 files changed, 61 insertions(+) diff --git a/boot/fdt_support.c b/boot/fdt_support.c index 92f2f534ee0..f42eaa488de 100644 --- a/boot/fdt_support.c +++ b/boot/fdt_support.c @@ -2259,3 +2259,57 @@ int fdt_fixup_pmem_region(void *fdt, u64 pmem_start, u64 pmem_size) return 0; } + +void fdt_print_reserved(void *fdt) +{ + int node, reserved, id; + int addr_cells, size_cells; + + printf("%-4s %-20s %-18s %-18s\n", "ID", "Name", "Start", "Size"); + printf("--------------------------------------------------------" + "--------\n"); + + reserved = fdt_path_offset(fdt, "/reserved-memory"); + if (reserved < 0) { + printf("No /reserved-memory node found in device tree\n"); + return; + } + + /* Get #address-cells and #size-cells from reserved-memory node */ + fdt_support_default_count_cells(fdt, reserved, &addr_cells, + &size_cells); + + id = 0; + fdt_for_each_subnode(node, fdt, reserved) { + const char *name = fdt_get_name(fdt, node, NULL); + const fdt32_t *reg; + u64 rsv_start = 0, rsv_size = 0; + int len; + + reg = fdt_getprop(fdt, node, "reg", &len); + if (reg && len >= (addr_cells + size_cells) * sizeof(fdt32_t)) { + int cells = 0; + + /* Parse address */ + for (int i = 0; i < addr_cells; i++) + rsv_start = (rsv_start << 32) | + fdt32_to_cpu(reg[cells++]); + + /* Parse size */ + for (int i = 0; i < size_cells; i++) + rsv_size = (rsv_size << 32) | + fdt32_to_cpu(reg[cells++]); + + printf("%-4d %-20s 0x%-16llx 0x%-16llx\n", + id++, name ? name : "(unnamed)", rsv_start, + rsv_size); + } else { + printf("%-4d %-20s %-18s %-18s\n", + id++, name ? name : "(unnamed)", "(no reg)", + "(no reg)"); + } + } + + if (!id) + printf("No reserved-memory regions found\n"); +} diff --git a/include/fdt_support.h b/include/fdt_support.h index eca9e7e3ac3..abd7504ad9b 100644 --- a/include/fdt_support.h +++ b/include/fdt_support.h @@ -529,4 +529,11 @@ int fdt_print(const void *fdt, int nodeoffset, int depth); */ int fdt_print_path(const char *pathp, char *prop, int depth); +/** + * fdt_print_reserved() - Print all device tree reserved-memory nodes + * + * @fdt: Device tree blob + */ +void fdt_print_reserved(void *fdt); + #endif /* ifndef __FDT_SUPPORT_H */ -- 2.43.0

From: Simon Glass <sjg@chromium.org> Add a new 'fdt reserved' subcommand that displays all reserved memory regions defined in the device tree's /reserved-memory node. This command provides a formatted table showing the ID, name, start address, and size of each reserved memory region. Avoid a conflict with the existing 'fdt resize' command. Update the docs and add a test. Co-developed-by: Claude <noreply@anthropic.com> Signed-off-by: Simon Glass <sjg@chromium.org> --- cmd/fdt.c | 7 ++++++- doc/usage/cmd/fdt.rst | 26 ++++++++++++++++++++++++++ test/cmd/fdt.c | 40 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 72 insertions(+), 1 deletion(-) diff --git a/cmd/fdt.c b/cmd/fdt.c index 4aedac6116e..7fe0d9dc22c 100644 --- a/cmd/fdt.c +++ b/cmd/fdt.c @@ -768,8 +768,12 @@ static int do_fdt(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]) return CMD_RET_FAILURE; } #endif + /* print reserved memory regions */ + else if (strncmp(argv[1], "rese", 4) == 0) { + fdt_print_reserved(working_fdt); + /* resize the fdt */ - else if (strncmp(argv[1], "re", 2) == 0) { + } else if (strncmp(argv[1], "re", 2) == 0) { uint extrasize; if (argc > 2) extrasize = hextoul(argv[2], NULL); @@ -902,6 +906,7 @@ U_BOOT_LONGHELP(fdt, #endif "fdt move <fdt> <newaddr> <length> - Copy the fdt to <addr> and make it active\n" "fdt resize [<extrasize>] - Resize fdt to size + padding to 4k addr + some optional <extrasize> if needed\n" + "fdt reserved - Print reserved-memory regions\n" "fdt print <path> [<prop>] - Recursive print starting at <path>\n" "fdt list <path> [<prop>] - Print one level starting at <path>\n" "fdt get value <var> <path> <prop> [<index>] - Get <property> and store in <var>\n" diff --git a/doc/usage/cmd/fdt.rst b/doc/usage/cmd/fdt.rst index 71a9fc627e5..2fbb50e5013 100644 --- a/doc/usage/cmd/fdt.rst +++ b/doc/usage/cmd/fdt.rst @@ -12,6 +12,7 @@ Synopsis :: fdt addr [-cq] [addr [len]] + fdt reserved Description ----------- @@ -48,6 +49,22 @@ If the `len` argument is provided, then the device tree is expanded to that size. This can be used to make space for more nodes and properties. It is assumed that there is enough space in memory for this expansion. +fdt reserved +~~~~~~~~~~~~ + +This command prints all reserved memory regions defined in the device tree's +`/reserved-memory` node. The output shows a formatted table with the following +columns: + +- **ID**: Sequential number for each region +- **Name**: Node name of the reserved memory region +- **Start**: Start address of the reserved memory region in hexadecimal +- **Size**: Size of the reserved memory region in hexadecimal + +If no `/reserved-memory` node exists in the device tree, the command will +display an appropriate message. This command is useful for debugging memory +layout issues and verifying that reserved memory regions are properly defined. + Example ------- @@ -67,6 +84,15 @@ address and expand it to 0xf000 in size:: => md 10000 4 00010000: edfe0dd0 00f00000 78000000 7c270000 ...........x..'| +Print all reserved memory regions:: + + => fdt reserved + ID Name Start Size + ---------------------------------------------------------------- + 0 secmon@1f000000 0x000000001f000000 0x0000000001000000 + 1 atf@40000000 0x0000000040000000 0x0000000000200000 + 2 linux,cma 0x0000000050000000 0x0000000008000000 + Return value ------------ diff --git a/test/cmd/fdt.c b/test/cmd/fdt.c index 9de79870c40..10a2f309a45 100644 --- a/test/cmd/fdt.c +++ b/test/cmd/fdt.c @@ -1464,3 +1464,43 @@ static int fdt_test_apply(struct unit_test_state *uts) return 0; } FDT_TEST(fdt_test_apply, UTF_CONSOLE); + +/* Test 'fdt reserved' reading reserved-memory nodes */ +static int fdt_test_reserved(struct unit_test_state *uts) +{ + struct fdt_header *old_working_fdt; + char fdt[8192]; + ulong addr; + + if (!IS_ENABLED(CONFIG_SANDBOX)) + return -EAGAIN; + + /* Save the original working_fdt */ + old_working_fdt = working_fdt; + + /* Set working_fdt to control FDT (sandbox has reserved memory) */ + working_fdt = (struct fdt_header *)gd->fdt_blob; + + ut_assertok(run_command("fdt reserved", 0)); + + /* Just verify we get the header */ + ut_assert_nextlinen("ID"); + ut_assert_nextlinen("------"); + + /* Verify we get a tcg_event_log entry with correct address/size */ + ut_assert_nextline("0 tcg_event_log 0x100000 0x2000 "); + + /* Test with FDT that has no reserved-memory node */ + ut_assertok(make_test_fdt(uts, fdt, sizeof(fdt), &addr)); + ut_assertok(run_command("fdt reserved", 0)); + ut_assert_nextlinen("ID Name Start Size"); + ut_assert_nextline("----------------------------------------------------------------"); + ut_assert_nextline("No /reserved-memory node found in device tree"); + ut_assert_console_end(); + + /* Restore the original working_fdt */ + working_fdt = old_working_fdt; + + return 0; +} +FDT_TEST(fdt_test_reserved, UTF_CONSOLE); -- 2.43.0

From: Simon Glass <sjg@chromium.org> When booting Linux with EFI the devicetree memory-map is ignored and Linux calls through EFI to obtain the real memory map. When booting Linux from the EFI app, without EFI, we must pass the reserved memory onto Linux using the devicetree. Add a function to support this. It reads the EFI memory-map and adds any missing regions to the reserved-memory node. Co-developed-by: Claude <noreply@anthropic.com> Signed-off-by: Simon Glass <sjg@chromium.org> --- include/efi.h | 16 +++ lib/efi_client/efi.c | 249 ++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 263 insertions(+), 2 deletions(-) diff --git a/include/efi.h b/include/efi.h index 530b127bde4..b3f9c0b694f 100644 --- a/include/efi.h +++ b/include/efi.h @@ -794,6 +794,22 @@ static inline bool efi_mem_is_boot_services(int type) */ const char *efi_mem_type_name(enum efi_memory_type type); +/** + * efi_mem_reserved_sync() - Sync EFI memory map with DT reserved-memory nodes + * + * This function compares the EFI memory map with the device tree's reserved-memory + * nodes and prints out regions that are reserved in EFI but not mentioned in the + * device tree's /reserved-memory node. This helps identify memory regions that + * EFI considers reserved but which Linux might try to use. + * + * Note: This only works with #address-cells and #size-cells of 2 + * + * @fdt: Pointer to the device tree blob + * @verbose: If true, show detailed output; if false, only show errors + * Return: Number of regions synced, or -ve on error + */ +int efi_mem_reserved_sync(void *fdt, bool verbose); + /** * efi_dump_mem_table() - Dump out the EFI memory map * diff --git a/lib/efi_client/efi.c b/lib/efi_client/efi.c index 12a646a36b7..9d064484dbf 100644 --- a/lib/efi_client/efi.c +++ b/lib/efi_client/efi.c @@ -13,10 +13,13 @@ #include <debug_uart.h> #include <errno.h> #include <malloc.h> -#include <linux/err.h> -#include <linux/types.h> #include <efi.h> #include <efi_api.h> +#include <mapmem.h> +#include <linux/err.h> +#include <linux/libfdt.h> +#include <linux/types.h> +#include <fdt_support.h> enum { /* magic number to trigger gdb breakpoint */ @@ -213,3 +216,245 @@ uint16_t *efi_dp_str(struct efi_device_path *dp) return val; } + +/** + * is_reserved() - Check if EFI memory type should be preserved + * + * @type: EFI memory type + * Return: true if memory type should be preserved, false otherwise + */ +static bool is_reserved(u32 type) +{ + switch (type) { + case EFI_RESERVED_MEMORY_TYPE: + case EFI_RUNTIME_SERVICES_CODE: + case EFI_RUNTIME_SERVICES_DATA: + case EFI_UNUSABLE_MEMORY: + case EFI_ACPI_RECLAIM_MEMORY: + case EFI_ACPI_MEMORY_NVS: + return true; + default: + return false; + } +} + +/** + * dt_region_exists() - Check if memory region is covered by DT reserved-memory + * + * @fdt: Device tree blob + * @start: Start address of region to check + * @end: End address of region to check + * Return: true if region overlaps with any reserved-memory node, else false + */ +static bool dt_region_exists(void *fdt, u64 start, u64 end) +{ + int node, reserved; + + reserved = fdt_path_offset(fdt, "/reserved-memory"); + if (reserved < 0) + return false; + + fdt_for_each_subnode(node, fdt, reserved) { + const fdt32_t *reg; + u64 start, size, end; + int len; + + reg = fdt_getprop(fdt, node, "reg", &len); + if (!reg || len < sizeof(u32) * 2) + continue; + + /* Parse reg property - assuming #address-cells=2, #size-cells=2 */ + start = fdt64_to_cpu(*(fdt64_t *)reg); + size = fdt64_to_cpu(*((fdt64_t *)reg + 1)); + end = start + size - 1; + + /* Check for overlap */ + if (!(end < start || start > end)) + return true; + } + + return false; +} + +/** + * dt_add_reserved() - Add EFI reserved region to device tree reserved-memory + * + * @fdt: Device tree blob + * @start: Start address of region + * @size: Size of region + * @type_name: EFI memory type name for node naming + * Return: 0 on success, negative error code on failure + */ +static int dt_add_reserved(void *fdt, u64 start, u64 size, + const char *type_name) +{ + int reserved, node; + char node_name[64]; + fdt32_t reg_prop[4]; + char *p; + int ret; + + /* Find or create /reserved-memory node */ + reserved = fdt_path_offset(fdt, "/reserved-memory"); + if (reserved < 0) { + /* Create /reserved-memory node */ + reserved = fdt_add_subnode(fdt, 0, "reserved-memory"); + if (reserved < 0) { + printf("Failed to create /reserved-memory node: %s\n", + fdt_strerror(reserved)); + return reserved; + } + + ret = fdt_setprop_u64(fdt, reserved, "#address-cells", 2); + if (ret) + return ret; + + ret = fdt_setprop_u64(fdt, reserved, "#size-cells", 2); + if (ret) + return ret; + + ret = fdt_setprop(fdt, reserved, "ranges", NULL, 0); + if (ret) + return ret; + } + + /* Create node name based on type and address */ + snprintf(node_name, sizeof(node_name), "efi-%s@%llx", type_name, start); + + /* Convert spaces and underscores to hyphens for a valid node name */ + for (p = node_name; *p; p++) { + if (*p == ' ' || *p == '_') + *p = '-'; + } + + /* Add new subnode */ + node = fdt_add_subnode(fdt, reserved, node_name); + if (node < 0) { + printf("Failed to create node %s: %s\n", node_name, + fdt_strerror(node)); + return node; + } + + /* Set reg property - #address-cells=2, #size-cells=2 */ + reg_prop[0] = cpu_to_fdt32(start >> 32); + reg_prop[1] = cpu_to_fdt32(start & 0xffffffff); + reg_prop[2] = cpu_to_fdt32(size >> 32); + reg_prop[3] = cpu_to_fdt32(size & 0xffffffff); + + ret = fdt_setprop(fdt, node, "reg", reg_prop, sizeof(reg_prop)); + if (ret) { + printf("Failed to set reg property: %s\n", fdt_strerror(ret)); + return ret; + } + + /* Add no-map property to prevent Linux from using this memory */ + ret = fdt_setprop(fdt, node, "no-map", NULL, 0); + if (ret) { + printf("Failed to set no-map property: %s\n", + fdt_strerror(ret)); + return ret; + } + + printf("added reserved-memory node: %s (0x%llx - 0x%llx)\n", + node_name, start, start + size - 1); + + return 0; +} + +/** + * sync_to_dt() - Print EFI reserved regions and add missing ones to DT + * + * @fdt: Device tree blob + * Return: true if any uncovered regions found, false otherwise + */ +static int sync_to_dt(void *fdt, bool verbose) +{ + struct efi_mem_desc *map, *desc, *end; + int desc_size, size, upto; + uint version, key; + int synced = 0; + int ret; + + /* Get the EFI memory map */ + ret = efi_get_mmap(&map, &size, &key, &desc_size, &version); + if (ret) { + printf("Failed to get EFI memory map: %d\n", ret); + return ret; + } + + if (verbose) { + printf("EFI Memory Map Analysis:\n"); + printf("%-4s %-18s %-18s %-18s %s\n", "ID", "Type", "Start", + "End", "In DT?"); + printf("-------------------------------------------------------" + "-----------------\n"); + } + + end = (void *)map + size; + for (upto = 0, desc = map; desc < end; + desc = efi_get_next_mem_desc(desc, desc_size), upto++) { + u64 start = desc->physical_start; + u64 end_addr = start + (desc->num_pages << EFI_PAGE_SHIFT) - 1; + u64 region_size = desc->num_pages << EFI_PAGE_SHIFT; + bool present; + + if (!is_reserved(desc->type)) + continue; + + present = dt_region_exists(fdt, start, end_addr); + + /* Print the region */ + if (verbose) { + printf("%-4d %-18s 0x%-16llx 0x%-16llx %s", upto, + efi_mem_type_name(desc->type), start, end_addr, + present ? "yes" : "no"); + } + + if (!present) { + const char *type_name; + int ret; + + if (verbose) + printf(" -> adding\n"); + + /* Add this region to device tree */ + type_name = efi_mem_type_name(desc->type); + ret = dt_add_reserved(fdt, start, region_size, + type_name); + if (ret) { + printf("Failed to add region: %s\n", + fdt_strerror(ret)); + free(map); + return ret; + } + synced++; + } else if (verbose) { + printf("\n"); + } + } + free(map); + + return synced; +} + +int efi_mem_reserved_sync(void *fdt, bool verbose) +{ + int synced; + + if (verbose) + printf("Comparing EFI memory-map with reserved-memory\n"); + + synced = sync_to_dt(fdt, verbose); + if (synced < 0) { + printf("Failed to sync EFI reserved regions: error %d\n", + synced); + return synced; + } + + if (verbose) { + printf("Regions added: %d\n", synced); + fdt_print_reserved(fdt); + } + + return synced; +} -- 2.43.0

From: Simon Glass <sjg@chromium.org> Provide a command to sync reserved-memory with EFI's version of reserved memory. Co-developed-by: Claude <noreply@anthropic.com> Signed-off-by: Simon Glass <sjg@chromium.org> --- cmd/efi.c | 22 ++++++++++++++++++++-- doc/usage/cmd/efi.rst | 36 ++++++++++++++++++++++++++++++++++++ 2 files changed, 56 insertions(+), 2 deletions(-) diff --git a/cmd/efi.c b/cmd/efi.c index c59219ddf01..c329e6eede8 100644 --- a/cmd/efi.c +++ b/cmd/efi.c @@ -198,9 +198,26 @@ static int do_efi_tables(struct cmd_tbl *cmdtp, int flag, int argc, return 0; } +static int do_efi_memsync(struct cmd_tbl *cmdtp, int flag, int argc, + char *const argv[]) +{ + bool verbose = false; + int ret; + + if (argc > 1 && !strcmp(argv[1], "-v")) + verbose = true; + + ret = efi_mem_reserved_sync(working_fdt, verbose); + if (ret < 0) + return CMD_RET_FAILURE; + + return 0; +} + static struct cmd_tbl efi_commands[] = { U_BOOT_CMD_MKENT(image, 1, 1, do_efi_image, "", ""), U_BOOT_CMD_MKENT(mem, 1, 1, do_efi_mem, "", ""), + U_BOOT_CMD_MKENT(memsync, 2, 1, do_efi_memsync, "", ""), U_BOOT_CMD_MKENT(tables, 1, 1, do_efi_tables, "", ""), }; @@ -223,9 +240,10 @@ static int do_efi(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]) } U_BOOT_CMD( - efi, 3, 1, do_efi, + efi, 4, 1, do_efi, "EFI access", "image Dump loaded-image info\n" "mem [all] Dump memory information [include boot services]\n" - "tables Dump tables" + "memsync [-v] Sync EFI memory map with DT reserved-memory\n" + "tables Dump tables" ); diff --git a/doc/usage/cmd/efi.rst b/doc/usage/cmd/efi.rst index e5d8913c94b..f91a2bd7bec 100644 --- a/doc/usage/cmd/efi.rst +++ b/doc/usage/cmd/efi.rst @@ -14,6 +14,7 @@ Synopsis efi image efi mem [all] + efi memsync [-v] efi tables Description @@ -69,6 +70,24 @@ Attributes Shows a code for memory attributes. The key for this is shown below the table. +efi memsync +~~~~~~~~~~~ + +This synchronizes EFI reserved memory regions with the device tree's +reserved-memory nodes. When running as an EFI application, U-Boot can access +the EFI memory map to identify regions that EFI considers reserved (such as +runtime services code/data, ACPI tables, etc.). This command compares these +EFI reserved regions with the device tree's /reserved-memory nodes and adds +any missing regions to prevent Linux from using memory that EFI has reserved. + +Use the optional '-v' flag for verbose output showing the detailed memory +map analysis. Without this flag, only errors are displayed. + +This is useful for ensuring proper memory management when transitioning from +EFI boot services to the operating system, particularly in complex firmware +environments where EFI may have reserved memory regions not explicitly +documented in the device tree. + efi tables ~~~~~~~~~~ @@ -234,3 +253,20 @@ Example 000000001fb7e000 eb9d2d30-2d88-11d3-9a16-0090273fc14d EFI_GUID_EFI_ACPI1 000000001fb7e014 8868e871-e4f1-11d3-bc22-0080c73c8881 ACPI table 000000001e654018 dcfa911d-26eb-469f-a220-38b7dc461220 (unknown) + + => efi memsync + Regions added: 2 + + => efi memsync -v + Comparing EFI memory-map with reserved-memory + EFI Memory Map Analysis: + ID Type Start End In DT? + ------------------------------------------------------------------------ + 0 EFI_RUNTIME_SERVICES_CODE 0x001f9ef000 0x001faef000 no -> adding + 1 EFI_ACPI_RECLAIM_MEMORY 0x001fb6f000 0x001fb7f000 no -> adding + 2 EFI_ACPI_MEMORY_NVS 0x001fb7f000 0x001fbff000 yes + Regions added: 2 + Reserved memory regions: + 0 tcg_event_log 0x100000 0x2000 + 1 efi-runtime-services-code@1f9ef000 0x1f9ef000 0x100000 + 2 efi-acpi-reclaim@1fb6f000 0x1fb6f000 0x10000 -- 2.43.0

From: Simon Glass <sjg@chromium.org> The EFI app cannot make the EFI GOP available to Linux directly, since it calls exit-boot-services before booting Linux. The easiest way to provide an early console is with the simple-framebuffer feature. Add this node to the devicetree if the feature is enabled. Co-developed-by: Claude <noreply@anthropic.com> Signed-off-by: Simon Glass <sjg@chromium.org> --- lib/efi_client/efi_app.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/lib/efi_client/efi_app.c b/lib/efi_client/efi_app.c index f67973dbb85..33ed3f2a874 100644 --- a/lib/efi_client/efi_app.c +++ b/lib/efi_client/efi_app.c @@ -348,9 +348,11 @@ int ft_system_setup(void *fdt, struct bd_info *bd) return ret; } - ret = fdt_simplefb_add_node(fdt); - if (ret) - log_warning("failed to set up simplefb\n"); + if (IS_ENABLED(CONFIG_FDT_SIMPLEFB)) { + ret = fdt_simplefb_add_node(fdt); + if (ret) + log_warning("failed to set up simplefb\n"); + } free(map); -- 2.43.0

From: Simon Glass <sjg@chromium.org> Obtain EFI's view of reserved memory and ensure that everything mentioned there is present in a devicetree reserved-memory node. This ensures that the OS doesn't try to access memory it shouldn't. Signed-off-by: Simon Glass <sjg@chromium.org> --- lib/efi_client/efi_app.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/lib/efi_client/efi_app.c b/lib/efi_client/efi_app.c index 33ed3f2a874..6b8b53fbb41 100644 --- a/lib/efi_client/efi_app.c +++ b/lib/efi_client/efi_app.c @@ -354,6 +354,11 @@ int ft_system_setup(void *fdt, struct bd_info *bd) log_warning("failed to set up simplefb\n"); } + /* Compare EFI memory map with device tree reserved regions */ + ret = efi_mem_reserved_sync(fdt, true); + if (ret) + log_warning("failed to set up reserved memory\n"); + free(map); return 0; -- 2.43.0
participants (1)
-
Simon Glass