With everything now in place, let's support ExitBootServices, so a
kernel can startup and communicate to barebox acting as EFI runtime.

Signed-off-by: Ahmad Fatoum <[email protected]>
---
 efi/loader/boot.c | 67 ++++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 66 insertions(+), 1 deletion(-)

diff --git a/efi/loader/boot.c b/efi/loader/boot.c
index 29cab7acd1c0..93a3412f5794 100644
--- a/efi/loader/boot.c
+++ b/efi/loader/boot.c
@@ -27,7 +27,9 @@
 #include <efi/error.h>
 #include <efi/variable.h>
 #include <efi/devicepath.h>
+#include <efi/mode.h>
 #include <efi/loader/trace.h>
+#include <efi/runtime.h>
 #include <malloc.h>
 #include <pe.h>
 #include <asm/cache.h>
@@ -2049,9 +2051,72 @@ efi_status_t EFIAPI efiloader_load_image(bool 
boot_policy,
 static efi_status_t EFIAPI efi_exit_boot_services(efi_handle_t image_handle,
                                                  efi_uintn_t map_key)
 {
+       struct efi_event *evt, *next_event;
+       efi_status_t ret = EFI_SUCCESS;
+
        EFI_ENTRY("%p, %zx", image_handle, map_key);
 
-       return EFI_EXIT(EFI_UNSUPPORTED);
+       /* Check that the caller has read the current memory map */
+       if (map_key != efi_memory_map_key) {
+               ret = EFI_INVALID_PARAMETER;
+               goto out;
+       }
+
+       /* Check if ExitBootServices has already been called */
+       if (!systab.boottime)
+               goto out;
+
+       /* Notify EFI_EVENT_GROUP_BEFORE_EXIT_BOOT_SERVICES event group. */
+       list_for_each_entry(evt, &efi_events, link) {
+               if (evt->group &&
+                   !efi_guidcmp(*evt->group,
+                                
efi_guid_event_group_before_exit_boot_services)) {
+                       efi_signal_event(evt);
+                       break;
+               }
+       }
+
+       /* Stop all timer related activities */
+       timers_enabled = false;
+
+       /* Add related events to the event group */
+       list_for_each_entry(evt, &efi_events, link) {
+               if (evt->type == EFI_EVT_SIGNAL_EXIT_BOOT_SERVICES)
+                       evt->group = &efi_guid_event_group_exit_boot_services;
+       }
+       /* Notify that ExitBootServices is invoked. */
+       list_for_each_entry(evt, &efi_events, link) {
+               if (evt->group &&
+                   !efi_guidcmp(*evt->group,
+                            efi_guid_event_group_exit_boot_services)) {
+                       efi_signal_event(evt);
+                       break;
+               }
+       }
+
+       /* Make sure that notification functions are not called anymore */
+       efi_tpl = EFI_TPL_HIGH_LEVEL;
+
+       /* Remove all events except EFI_EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE */
+       list_for_each_entry_safe(evt, next_event, &efi_events, link) {
+               if (evt->type != EFI_EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE)
+                       list_del(&evt->link);
+       }
+
+       /* Patch out unsupported runtime function */
+       efi_runtime_detach(&systab);
+
+       efi_loader_set_state(EFI_LOADER_RUNTIME);
+
+       resched();
+
+       shutdown_barebox();
+
+       /* Give the payload some time to boot */
+       efi_set_watchdog(0);
+out:
+
+       return EFI_EXIT(ret);
 }
 
 /**
-- 
2.47.3


Reply via email to