]> git.sur5r.net Git - u-boot/blobdiff - lib/efi_loader/efi_boottime.c
efi_loader: efi_open_protocol: parameter checks
[u-boot] / lib / efi_loader / efi_boottime.c
index 9daca50a72fc1b7c92212c30bcbb7aed5d34e6b0..22e9e6001d1b6efc07e162bf6fadb619645a9939 100644 (file)
@@ -6,8 +6,6 @@
  *  SPDX-License-Identifier:     GPL-2.0+
  */
 
-/* #define DEBUG_EFI */
-
 #include <common.h>
 #include <efi_loader.h>
 #include <malloc.h>
@@ -39,8 +37,9 @@ static bool efi_is_direct_boot = true;
  * In most cases we want to pass an FDT to the payload, so reserve one slot of
  * config table space for it. The pointer gets populated by do_bootefi_exec().
  */
-static struct efi_configuration_table EFI_RUNTIME_DATA efi_conf_table[1];
+static struct efi_configuration_table __efi_runtime_data efi_conf_table[2];
 
+#ifdef CONFIG_ARM
 /*
  * The "gd" pointer lives in a register on ARM and AArch64 that we declare
  * fixed when compiling U-Boot. However, the payload does not know about that
@@ -48,16 +47,20 @@ static struct efi_configuration_table EFI_RUNTIME_DATA efi_conf_table[1];
  * EFI callback entry/exit.
  */
 static volatile void *efi_gd, *app_gd;
+#endif
 
 /* Called from do_bootefi_exec() */
 void efi_save_gd(void)
 {
+#ifdef CONFIG_ARM
        efi_gd = gd;
+#endif
 }
 
 /* Called on every callback entry */
 void efi_restore_gd(void)
 {
+#ifdef CONFIG_ARM
        /* Only restore if we're already in EFI context */
        if (!efi_gd)
                return;
@@ -65,20 +68,22 @@ void efi_restore_gd(void)
        if (gd != efi_gd)
                app_gd = gd;
        gd = efi_gd;
+#endif
 }
 
 /* Called on every callback exit */
 efi_status_t efi_exit_func(efi_status_t ret)
 {
+#ifdef CONFIG_ARM
        gd = app_gd;
+#endif
+
        return ret;
 }
 
 static efi_status_t efi_unsupported(const char *funcname)
 {
-#ifdef DEBUG_EFI
-       printf("EFI: App called into unimplemented function %s\n", funcname);
-#endif
+       debug("EFI: App called into unimplemented function %s\n", funcname);
        return EFI_EXIT(EFI_UNSUPPORTED);
 }
 
@@ -99,9 +104,9 @@ static void EFIAPI efi_restore_tpl(unsigned long old_tpl)
        EFI_EXIT(efi_unsupported(__func__));
 }
 
-efi_status_t EFIAPI efi_allocate_pages_ext(int type, int memory_type,
-                                          unsigned long pages,
-                                          uint64_t *memory)
+static efi_status_t EFIAPI efi_allocate_pages_ext(int type, int memory_type,
+                                                 unsigned long pages,
+                                                 uint64_t *memory)
 {
        efi_status_t r;
 
@@ -110,7 +115,8 @@ efi_status_t EFIAPI efi_allocate_pages_ext(int type, int memory_type,
        return EFI_EXIT(r);
 }
 
-efi_status_t EFIAPI efi_free_pages_ext(uint64_t memory, unsigned long pages)
+static efi_status_t EFIAPI efi_free_pages_ext(uint64_t memory,
+                                             unsigned long pages)
 {
        efi_status_t r;
 
@@ -119,11 +125,12 @@ efi_status_t EFIAPI efi_free_pages_ext(uint64_t memory, unsigned long pages)
        return EFI_EXIT(r);
 }
 
-efi_status_t EFIAPI efi_get_memory_map_ext(unsigned long *memory_map_size,
-                                          struct efi_mem_desc *memory_map,
-                                          unsigned long *map_key,
-                                          unsigned long *descriptor_size,
-                                          uint32_t *descriptor_version)
+static efi_status_t EFIAPI efi_get_memory_map_ext(
+                                       unsigned long *memory_map_size,
+                                       struct efi_mem_desc *memory_map,
+                                       unsigned long *map_key,
+                                       unsigned long *descriptor_size,
+                                       uint32_t *descriptor_version)
 {
        efi_status_t r;
 
@@ -134,22 +141,23 @@ efi_status_t EFIAPI efi_get_memory_map_ext(unsigned long *memory_map_size,
        return EFI_EXIT(r);
 }
 
-static efi_status_t EFIAPI efi_allocate_pool(int pool_type, unsigned long size,
-                                            void **buffer)
+static efi_status_t EFIAPI efi_allocate_pool_ext(int pool_type,
+                                                unsigned long size,
+                                                void **buffer)
 {
        efi_status_t r;
 
        EFI_ENTRY("%d, %ld, %p", pool_type, size, buffer);
-       r = efi_allocate_pages(0, pool_type, (size + 0xfff) >> 12, (void*)buffer);
+       r = efi_allocate_pool(pool_type, size, buffer);
        return EFI_EXIT(r);
 }
 
-static efi_status_t EFIAPI efi_free_pool(void *buffer)
+static efi_status_t EFIAPI efi_free_pool_ext(void *buffer)
 {
        efi_status_t r;
 
        EFI_ENTRY("%p", buffer);
-       r = efi_free_pages((ulong)buffer, 0);
+       r = efi_free_pool(buffer);
        return EFI_EXIT(r);
 }
 
@@ -163,7 +171,7 @@ static struct {
        u32 trigger_time;
        u64 trigger_next;
        unsigned long notify_tpl;
-       void (*notify_function) (void *event, void *context);
+       void (EFIAPI *notify_function) (void *event, void *context);
        void *notify_context;
 } efi_event = {
        /* Disable timers on bootup */
@@ -172,7 +180,8 @@ static struct {
 
 static efi_status_t EFIAPI efi_create_event(
                        enum efi_event_type type, ulong notify_tpl,
-                       void (*notify_function) (void *event, void *context),
+                       void (EFIAPI *notify_function) (void *event,
+                                                       void *context),
                        void *notify_context, void **event)
 {
        EFI_ENTRY("%d, 0x%lx, %p, %p", type, notify_tpl, notify_function,
@@ -182,6 +191,16 @@ static efi_status_t EFIAPI efi_create_event(
                return EFI_EXIT(EFI_OUT_OF_RESOURCES);
        }
 
+       if (event == NULL)
+               return EFI_EXIT(EFI_INVALID_PARAMETER);
+
+       if ((type & EVT_NOTIFY_SIGNAL) && (type & EVT_NOTIFY_WAIT))
+               return EFI_EXIT(EFI_INVALID_PARAMETER);
+
+       if ((type & (EVT_NOTIFY_SIGNAL|EVT_NOTIFY_WAIT)) &&
+           notify_function == NULL)
+               return EFI_EXIT(EFI_INVALID_PARAMETER);
+
        efi_event.type = type;
        efi_event.notify_tpl = notify_tpl;
        efi_event.notify_function = notify_function;
@@ -203,7 +222,9 @@ void efi_timer_check(void)
                /* Triggering! */
                if (efi_event.trigger_type == EFI_TIMER_PERIODIC)
                        efi_event.trigger_next += efi_event.trigger_time / 10;
-               efi_event.notify_function(&efi_event, efi_event.notify_context);
+               if (efi_event.type & (EVT_NOTIFY_WAIT | EVT_NOTIFY_SIGNAL))
+                       efi_event.notify_function(&efi_event,
+                                                 efi_event.notify_context);
        }
 
        WATCHDOG_RESET();
@@ -379,31 +400,35 @@ static efi_status_t EFIAPI efi_locate_device_path(efi_guid_t *protocol,
        return EFI_EXIT(EFI_NOT_FOUND);
 }
 
-static efi_status_t EFIAPI efi_install_configuration_table(efi_guid_t *guid,
-                                                          void *table)
+efi_status_t efi_install_configuration_table(const efi_guid_t *guid, void *table)
 {
        int i;
 
-       EFI_ENTRY("%p, %p", guid, table);
-
        /* Check for guid override */
        for (i = 0; i < systab.nr_tables; i++) {
                if (!guidcmp(guid, &efi_conf_table[i].guid)) {
                        efi_conf_table[i].table = table;
-                       return EFI_EXIT(EFI_SUCCESS);
+                       return EFI_SUCCESS;
                }
        }
 
        /* No override, check for overflow */
        if (i >= ARRAY_SIZE(efi_conf_table))
-               return EFI_EXIT(EFI_OUT_OF_RESOURCES);
+               return EFI_OUT_OF_RESOURCES;
 
        /* Add a new entry */
        memcpy(&efi_conf_table[i].guid, guid, sizeof(*guid));
        efi_conf_table[i].table = table;
-       systab.nr_tables = i;
+       systab.nr_tables = i + 1;
 
-       return EFI_EXIT(EFI_SUCCESS);
+       return EFI_SUCCESS;
+}
+
+static efi_status_t EFIAPI efi_install_configuration_table_ext(efi_guid_t *guid,
+                                                              void *table)
+{
+       EFI_ENTRY("%p, %p", guid, table);
+       return EFI_EXIT(efi_install_configuration_table(guid, table));
 }
 
 static efi_status_t EFIAPI efi_load_image(bool boot_policy,
@@ -417,7 +442,6 @@ static efi_status_t EFIAPI efi_load_image(bool boot_policy,
                .protocols = {
                        {
                                .guid = &efi_guid_loaded_image,
-                               .open = &efi_return_handle,
                        },
                },
        };
@@ -427,6 +451,7 @@ static efi_status_t EFIAPI efi_load_image(bool boot_policy,
        EFI_ENTRY("%d, %p, %p, %p, %ld, %p", boot_policy, parent_image,
                  file_path, source_buffer, source_size, image_handle);
        info = malloc(sizeof(*info));
+       loaded_image_info_obj.protocols[0].protocol_interface = info;
        obj = malloc(sizeof(loaded_image_info_obj));
        memset(info, 0, sizeof(*info));
        memcpy(obj, &loaded_image_info_obj, sizeof(loaded_image_info_obj));
@@ -458,19 +483,30 @@ static efi_status_t EFIAPI efi_start_image(efi_handle_t image_handle,
        efi_is_direct_boot = false;
 
        /* call the image! */
+       if (setjmp(&info->exit_jmp)) {
+               /* We returned from the child image */
+               return EFI_EXIT(info->exit_status);
+       }
+
        entry(image_handle, &systab);
 
        /* Should usually never get here */
        return EFI_EXIT(EFI_SUCCESS);
 }
 
-static efi_status_t EFIAPI efi_exit(void *image_handle, long exit_status,
-                                   unsigned long exit_data_size,
-                                   uint16_t *exit_data)
+static efi_status_t EFIAPI efi_exit(efi_handle_t image_handle,
+                       efi_status_t exit_status, unsigned long exit_data_size,
+                       int16_t *exit_data)
 {
+       struct efi_loaded_image *loaded_image_info = (void*)image_handle;
+
        EFI_ENTRY("%p, %ld, %ld, %p", image_handle, exit_status,
                  exit_data_size, exit_data);
-       return EFI_EXIT(efi_unsupported(__func__));
+
+       loaded_image_info->exit_status = exit_status;
+       longjmp(&loaded_image_info->exit_jmp, 1);
+
+       panic("EFI application exited");
 }
 
 static struct efi_object *efi_search_obj(void *handle)
@@ -516,6 +552,8 @@ static efi_status_t EFIAPI efi_exit_boot_services(void *image_handle,
 {
        EFI_ENTRY("%p, %ld", image_handle, map_key);
 
+       board_quiesce_devices();
+
        /* Fix up caches for EFI payloads if necessary */
        efi_exit_caches();
 
@@ -680,11 +718,38 @@ static efi_status_t EFIAPI efi_open_protocol(
 {
        struct list_head *lhandle;
        int i;
-       efi_status_t r = EFI_UNSUPPORTED;
+       efi_status_t r = EFI_INVALID_PARAMETER;
 
        EFI_ENTRY("%p, %p, %p, %p, %p, 0x%x", handle, protocol,
                  protocol_interface, agent_handle, controller_handle,
                  attributes);
+
+       if (!handle || !protocol ||
+           (!protocol_interface && attributes !=
+            EFI_OPEN_PROTOCOL_TEST_PROTOCOL)) {
+               goto out;
+       }
+
+       switch (attributes) {
+       case EFI_OPEN_PROTOCOL_BY_HANDLE_PROTOCOL:
+       case EFI_OPEN_PROTOCOL_GET_PROTOCOL:
+       case EFI_OPEN_PROTOCOL_TEST_PROTOCOL:
+               break;
+       case EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER:
+               if (controller_handle == handle)
+                       goto out;
+       case EFI_OPEN_PROTOCOL_BY_DRIVER:
+       case EFI_OPEN_PROTOCOL_BY_DRIVER | EFI_OPEN_PROTOCOL_EXCLUSIVE:
+               if (controller_handle == NULL)
+                       goto out;
+       case EFI_OPEN_PROTOCOL_EXCLUSIVE:
+               if (agent_handle == NULL)
+                       goto out;
+               break;
+       default:
+               goto out;
+       }
+
        list_for_each(lhandle, &efi_obj_list) {
                struct efi_object *efiobj;
                efiobj = list_entry(lhandle, struct efi_object, link);
@@ -698,14 +763,20 @@ static efi_status_t EFIAPI efi_open_protocol(
                        if (!hprotocol)
                                break;
                        if (!guidcmp(hprotocol, protocol)) {
-                               r = handler->open(handle, protocol,
-                                   protocol_interface, agent_handle,
-                                   controller_handle, attributes);
+                               if (attributes !=
+                                   EFI_OPEN_PROTOCOL_TEST_PROTOCOL) {
+                                       *protocol_interface =
+                                               handler->protocol_interface;
+                               }
+                               r = EFI_SUCCESS;
                                goto out;
                        }
                }
+               goto unsupported;
        }
 
+unsupported:
+       r = EFI_UNSUPPORTED;
 out:
        return EFI_EXIT(r);
 }
@@ -714,8 +785,8 @@ static efi_status_t EFIAPI efi_handle_protocol(void *handle,
                                               efi_guid_t *protocol,
                                               void **protocol_interface)
 {
-       return efi_open_protocol(handle, protocol, protocol_interface,
-                                NULL, NULL, 0);
+       return efi_open_protocol(handle, protocol, protocol_interface, NULL,
+                                NULL, EFI_OPEN_PROTOCOL_BY_HANDLE_PROTOCOL);
 }
 
 static const struct efi_boot_services efi_boot_services = {
@@ -727,8 +798,8 @@ static const struct efi_boot_services efi_boot_services = {
        .allocate_pages = efi_allocate_pages_ext,
        .free_pages = efi_free_pages_ext,
        .get_memory_map = efi_get_memory_map_ext,
-       .allocate_pool = efi_allocate_pool,
-       .free_pool = efi_free_pool,
+       .allocate_pool = efi_allocate_pool_ext,
+       .free_pool = efi_free_pool_ext,
        .create_event = efi_create_event,
        .set_timer = efi_set_timer,
        .wait_for_event = efi_wait_for_event,
@@ -743,10 +814,10 @@ static const struct efi_boot_services efi_boot_services = {
        .register_protocol_notify = efi_register_protocol_notify,
        .locate_handle = efi_locate_handle,
        .locate_device_path = efi_locate_device_path,
-       .install_configuration_table = efi_install_configuration_table,
+       .install_configuration_table = efi_install_configuration_table_ext,
        .load_image = efi_load_image,
        .start_image = efi_start_image,
-       .exit = (void*)efi_exit,
+       .exit = efi_exit,
        .unload_image = efi_unload_image,
        .exit_boot_services = efi_exit_boot_services,
        .get_next_monotonic_count = efi_get_next_monotonic_count,
@@ -768,10 +839,10 @@ static const struct efi_boot_services efi_boot_services = {
 };
 
 
-static uint16_t EFI_RUNTIME_DATA firmware_vendor[] =
+static uint16_t __efi_runtime_data firmware_vendor[] =
        { 'D','a','s',' ','U','-','b','o','o','t',0 };
 
-struct efi_system_table EFI_RUNTIME_DATA systab = {
+struct efi_system_table __efi_runtime_data systab = {
        .hdr = {
                .signature = EFI_SYSTEM_TABLE_SIGNATURE,
                .revision = 0x20005, /* 2.5 */