#include <common.h>
#include <div64.h>
#include <efi_loader.h>
-#include <environment.h>
#include <malloc.h>
#include <linux/libfdt_env.h>
#include <u-boot/crc.h>
LIST_HEAD(efi_obj_list);
/* List of all events */
-LIST_HEAD(efi_events);
+__efi_runtime_data LIST_HEAD(efi_events);
/* List of queued events */
LIST_HEAD(efi_event_queue);
/* Handle of the currently executing image */
static efi_handle_t current_image;
-/*
- * If we're running on nasty systems (32bit ARM booting into non-EFI Linux)
- * we need to do trickery with caches. Since we don't want to break the EFI
- * aware boot path, only apply hacks when loading exiting directly (breaking
- * direct Linux EFI booting along the way - oh well).
- */
-static bool efi_is_direct_boot = true;
-
#ifdef CONFIG_ARM
/*
* The "gd" pointer lives in a register on ARM and AArch64 that we declare
/**
* efi_delete_handle() - delete handle
*
- * @obj: handle to delete
+ * @handle: handle to delete
*/
void efi_delete_handle(efi_handle_t handle)
{
/**
* efi_create_event() - create an event
+ *
* @type: type of the event to create
* @notify_tpl: task priority level of the event
* @notify_function: notification function of the event
struct efi_event **event)
{
struct efi_event *evt;
+ efi_status_t ret;
+ int pool_type;
if (event == NULL)
return EFI_INVALID_PARAMETER;
case EVT_NOTIFY_WAIT:
case EVT_TIMER | EVT_NOTIFY_WAIT:
case EVT_SIGNAL_EXIT_BOOT_SERVICES:
+ pool_type = EFI_BOOT_SERVICES_DATA;
+ break;
case EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE:
+ pool_type = EFI_RUNTIME_SERVICES_DATA;
break;
default:
return EFI_INVALID_PARAMETER;
(!notify_function || is_valid_tpl(notify_tpl) != EFI_SUCCESS))
return EFI_INVALID_PARAMETER;
- evt = calloc(1, sizeof(struct efi_event));
- if (!evt)
- return EFI_OUT_OF_RESOURCES;
+ ret = efi_allocate_pool(pool_type, sizeof(struct efi_event),
+ (void **)&evt);
+ if (ret != EFI_SUCCESS)
+ return ret;
+ memset(evt, 0, sizeof(struct efi_event));
evt->type = type;
evt->notify_tpl = notify_tpl;
evt->notify_function = notify_function;
list_del(&event->queue_link);
list_del(&event->link);
- free(event);
+ efi_free_pool(event);
return EFI_EXIT(EFI_SUCCESS);
}
/**
* efi_search() - determine if an EFI handle implements a protocol
+ *
* @search_type: selection criterion
* @protocol: GUID of the protocol
- * @search_key: registration key
* @handle: handle
*
* See the documentation of the LocateHandle service in the UEFI specification.
* Initialize a loaded_image_info and loaded_image_info object with correct
* protocols, boot-device, etc.
*
- * In case of an error *handle_ptr and *info_ptr are set to NULL and an error
+ * In case of an error \*handle_ptr and \*info_ptr are set to NULL and an error
* code is returned.
*
* @device_path: device path of the loaded image
*/
static void efi_exit_caches(void)
{
-#if defined(CONFIG_ARM) && !defined(CONFIG_ARM64)
+#if defined(CONFIG_EFI_GRUB_ARM32_WORKAROUND)
/*
- * Grub on 32bit ARM needs to have caches disabled before jumping into
- * a zImage, but does not know of all cache layers. Give it a hand.
+ * Boooting Linux via GRUB prior to version 2.04 fails on 32bit ARM if
+ * caches are enabled.
+ *
+ * TODO:
+ * According to the UEFI spec caches that can be managed via CP15
+ * operations should be enabled. Caches requiring platform information
+ * to manage should be disabled. This should not happen in
+ * ExitBootServices() but before invoking any UEFI binary is invoked.
+ *
+ * We want to keep the current workaround while GRUB prior to version
+ * 2.04 is still in use.
*/
- if (efi_is_direct_boot)
- cleanup_before_linux();
+ cleanup_before_linux();
#endif
}
static efi_status_t EFIAPI efi_exit_boot_services(efi_handle_t image_handle,
efi_uintn_t map_key)
{
- struct efi_event *evt;
+ struct efi_event *evt, *next_event;
efi_status_t ret = EFI_SUCCESS;
EFI_ENTRY("%p, %zx", image_handle, map_key);
/* Make sure that notification functions are not called anymore */
efi_tpl = TPL_HIGH_LEVEL;
- /* TODO: Should persist EFI variables here */
+ /* Notify variable services */
+ efi_variables_boot_exit_notify();
+
+ /* Remove all events except EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE */
+ list_for_each_entry_safe(evt, next_event, &efi_events, link) {
+ if (evt->type != EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE)
+ list_del(&evt->link);
+ }
board_quiesce_devices();
+ /* Patch out unsupported runtime function */
+ efi_runtime_detach();
+
/* Fix up caches for EFI payloads if necessary */
efi_exit_caches();
if (ret != EFI_SUCCESS)
return EFI_EXIT(EFI_INVALID_PARAMETER);
- efi_is_direct_boot = false;
-
image_obj->exit_data_size = exit_data_size;
image_obj->exit_data = exit_data;
/**
* efi_update_exit_data() - fill exit data parameters of StartImage()
*
- * @image_obj image handle
- * @exit_data_size size of the exit data buffer
- * @exit_data buffer with data returned by UEFI payload
+ * @image_obj: image handle
+ * @exit_data_size: size of the exit data buffer
+ * @exit_data: buffer with data returned by UEFI payload
* Return: status code
*/
static efi_status_t efi_update_exit_data(struct efi_loaded_image_obj *image_obj,