*/
#include <common.h>
+#include <bootm.h>
#include <div64.h>
+#include <dm/device.h>
+#include <dm/root.h>
#include <efi_loader.h>
#include <irq_func.h>
#include <log.h>
#include <malloc.h>
-#include <time.h>
-#include <linux/libfdt_env.h>
-#include <u-boot/crc.h>
-#include <bootm.h>
#include <pe.h>
+#include <time.h>
#include <u-boot/crc.h>
+#include <usb.h>
#include <watchdog.h>
+#include <linux/libfdt_env.h>
DECLARE_GLOBAL_DATA_PTR;
/* Flag to disable timer activity in ExitBootServices() */
static bool timers_enabled = true;
+/* Flag used by the selftest to avoid detaching devices in ExitBootServices() */
+bool efi_st_keep_devices;
+
/* List of all events registered by RegisterProtocolNotify() */
LIST_HEAD(efi_register_notify_events);
/* Handle of the currently executing image */
static efi_handle_t current_image;
-#ifdef CONFIG_ARM
+#if defined(CONFIG_ARM) || defined(CONFIG_RISCV)
/*
- * The "gd" pointer lives in a register on ARM and AArch64 that we declare
+ * The "gd" pointer lives in a register on ARM and RISC-V that we declare
* fixed when compiling U-Boot. However, the payload does not know about that
* restriction so we need to manually swap its and our view of that register on
* EFI callback entry/exit.
int __efi_entry_check(void)
{
int ret = entry_count++ == 0;
-#ifdef CONFIG_ARM
+#if defined(CONFIG_ARM) || defined(CONFIG_RISCV)
assert(efi_gd);
app_gd = gd;
set_gd(efi_gd);
int __efi_exit_check(void)
{
int ret = --entry_count == 0;
-#ifdef CONFIG_ARM
+#if defined(CONFIG_ARM) || defined(CONFIG_RISCV)
set_gd(app_gd);
#endif
return ret;
}
-/* Called from do_bootefi_exec() */
+/**
+ * efi_save_gd() - save global data register
+ *
+ * On the ARM and RISC-V architectures gd is mapped to a fixed register.
+ * As this register may be overwritten by an EFI payload we save it here
+ * and restore it on every callback entered.
+ *
+ * This function is called after relocation from initr_reloc_global_data().
+ */
void efi_save_gd(void)
{
-#ifdef CONFIG_ARM
+#if defined(CONFIG_ARM) || defined(CONFIG_RISCV)
efi_gd = gd;
#endif
}
-/*
- * Special case handler for error/abort that just forces things back to u-boot
- * world so we can dump out an abort message, without any care about returning
- * back to UEFI world.
+/**
+ * efi_restore_gd() - restore global data register
+ *
+ * On the ARM and RISC-V architectures gd is mapped to a fixed register.
+ * Restore it after returning from the UEFI world to the value saved via
+ * efi_save_gd().
*/
void efi_restore_gd(void)
{
-#ifdef CONFIG_ARM
+#if defined(CONFIG_ARM) || defined(CONFIG_RISCV)
/* Only restore if we're already in EFI context */
if (!efi_gd)
return;
if (ret != EFI_SUCCESS)
goto error;
} else {
- if (!source_size) {
- ret = EFI_LOAD_ERROR;
- goto error;
- }
dest_buffer = source_buffer;
}
/* split file_path which contains both the device and file parts */
list_del(&evt->link);
}
- board_quiesce_devices();
+ if (!efi_st_keep_devices) {
+ if IS_ENABLED(CONFIG_USB_DEVICE)
+ udc_disconnect();
+ board_quiesce_devices();
+ dm_remove_devices_flags(DM_REMOVE_ACTIVE_ALL);
+ }
/* Patch out unsupported runtime function */
efi_runtime_detach();
* us to the current line. This implies that the second half
* of the EFI_CALL macro has not been executed.
*/
-#ifdef CONFIG_ARM
+#if defined(CONFIG_ARM) || defined(CONFIG_RISCV)
/*
* efi_exit() called efi_restore_gd(). We have to undo this
* otherwise __efi_entry_check() will put the wrong value into
* the buffer will be too large. But that does not harm.
*/
*number_of_children = 0;
+ if (!count)
+ return EFI_SUCCESS;
*child_handle_buffer = calloc(count, sizeof(efi_handle_t));
if (!*child_handle_buffer)
return EFI_OUT_OF_RESOURCES;
size_t number_of_children = 0;
efi_status_t r;
struct efi_object *efiobj;
+ bool sole_child;
EFI_ENTRY("%p, %p, %p", controller_handle, driver_image_handle,
child_handle);
}
/* Create list of child handles */
+ r = efi_get_child_controllers(efiobj,
+ driver_image_handle,
+ &number_of_children,
+ &child_handle_buffer);
+ if (r != EFI_SUCCESS)
+ return r;
+ sole_child = (number_of_children == 1);
+
if (child_handle) {
number_of_children = 1;
+ free(child_handle_buffer);
child_handle_buffer = &child_handle;
- } else {
- efi_get_child_controllers(efiobj,
- driver_image_handle,
- &number_of_children,
- &child_handle_buffer);
}
/* Get the driver binding protocol */
}
}
/* Remove the driver */
- if (!child_handle) {
+ if (!child_handle || sole_child) {
r = EFI_CALL(binding_protocol->stop(binding_protocol,
controller_handle,
0, NULL));