summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorHeinrich Schuchardt <xypron.glpk@gmx.de>2018-01-19 22:24:52 +0300
committerAlexander Graf <agraf@suse.de>2018-01-23 01:09:14 +0300
commitcc20ed03f9887b45c834a066d0ecd098934fa43b (patch)
tree122578a2724df77182c15da98018922ef4f98f0e /lib
parent9bc9664d5ee16155b42baf92282ba7198ef4e873 (diff)
downloadu-boot-cc20ed03f9887b45c834a066d0ecd098934fa43b.tar.xz
efi_loader: fix ExitBootServices
This patch lets the implementation of ExitBootServices conform to the UEFI standard. The timer events must be disabled before calling the notification functions of the exit boot services events. The boot services must be disabled in the system table. The handles in the system table should be defined as efi_handle_t. Signed-off-by: Heinrich Schuchardt <xypron.glpk@gmx.de> Signed-off-by: Alexander Graf <agraf@suse.de>
Diffstat (limited to 'lib')
-rw-r--r--lib/efi_loader/efi_boottime.c34
1 files changed, 29 insertions, 5 deletions
diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c
index 8e5480ac17..39d8511fe3 100644
--- a/lib/efi_loader/efi_boottime.c
+++ b/lib/efi_loader/efi_boottime.c
@@ -1665,12 +1665,16 @@ static void efi_exit_caches(void)
}
/*
- * Stop boot services.
+ * Stop all boot services.
*
* This function implements the ExitBootServices service.
* See the Unified Extensible Firmware Interface (UEFI) specification
* for details.
*
+ * All timer events are disabled.
+ * For exit boot services events the notification function is called.
+ * The boot services are disabled in the system table.
+ *
* @image_handle handle of the loaded image
* @map_key key of the memory map
* @return status code
@@ -1682,16 +1686,22 @@ static efi_status_t EFIAPI efi_exit_boot_services(efi_handle_t image_handle,
EFI_ENTRY("%p, %ld", image_handle, map_key);
+ /* Make sure that notification functions are not called anymore */
+ efi_tpl = TPL_HIGH_LEVEL;
+
+ /* Check if ExitBootServices has already been called */
+ if (!systab.boottime)
+ return EFI_EXIT(EFI_SUCCESS);
+
/* Notify that ExitBootServices is invoked. */
for (i = 0; i < ARRAY_SIZE(efi_events); ++i) {
if (efi_events[i].type != EVT_SIGNAL_EXIT_BOOT_SERVICES)
continue;
- efi_signal_event(&efi_events[i]);
+ efi_events[i].is_signaled = true;
+ efi_signal_event(&efi_events[i], false);
}
- /* Make sure that notification functions are not called anymore */
- efi_tpl = TPL_HIGH_LEVEL;
- /* XXX Should persist EFI variables here */
+ /* TODO Should persist EFI variables here */
board_quiesce_devices();
@@ -1701,6 +1711,20 @@ static efi_status_t EFIAPI efi_exit_boot_services(efi_handle_t image_handle,
/* This stops all lingering devices */
bootm_disable_interrupts();
+ /* Disable boottime services */
+ systab.con_in_handle = NULL;
+ systab.con_in = NULL;
+ systab.con_out_handle = NULL;
+ systab.con_out = NULL;
+ systab.stderr_handle = NULL;
+ systab.std_err = NULL;
+ systab.boottime = NULL;
+
+ /* Recalculate CRC32 */
+ systab.hdr.crc32 = 0;
+ systab.hdr.crc32 = crc32(0, (const unsigned char *)&systab,
+ sizeof(struct efi_system_table));
+
/* Give the payload some time to boot */
efi_set_watchdog(0);
WATCHDOG_RESET();