]> git.ipfire.org Git - thirdparty/u-boot.git/commitdiff
Merge tag 'efi-2019-07-rc5' of git://git.denx.de/u-boot-efi
authorTom Rini <trini@konsulko.com>
Wed, 12 Jun 2019 11:15:38 +0000 (07:15 -0400)
committerTom Rini <trini@konsulko.com>
Wed, 12 Jun 2019 11:15:38 +0000 (07:15 -0400)
Pull request for UEFI sub-system for v2019.07-rc5

This pull request provides fixes for event services.

include/efi_loader.h
lib/efi_loader/efi_boottime.c
lib/efi_loader/efi_console.c
lib/efi_loader/efi_memory.c
lib/efi_loader/efi_runtime.c
lib/efi_selftest/efi_selftest_event_groups.c

index 23ce732267620b3346b7f3b96f574f7f1a6cf27a..f0e1313f9345025b86d74ed7a06cd2f4c4df29d8 100644 (file)
@@ -256,6 +256,7 @@ struct efi_loaded_image_obj {
  * struct efi_event
  *
  * @link:              Link to list of all events
+ * @queue_link:                Link to the list of queued events
  * @type:              Type of event, see efi_create_event
  * @notify_tpl:                Task priority level of notifications
  * @nofify_function:   Function to call when the event is triggered
@@ -264,11 +265,11 @@ struct efi_loaded_image_obj {
  * @trigger_time:      Period of the timer
  * @trigger_next:      Next time to trigger the timer
  * @trigger_type:      Type of timer, see efi_set_timer
- * @is_queued:         The notification function is queued
  * @is_signaled:       The event occurred. The event is in the signaled state.
  */
 struct efi_event {
        struct list_head link;
+       struct list_head queue_link;
        uint32_t type;
        efi_uintn_t notify_tpl;
        void (EFIAPI *notify_function)(struct efi_event *event, void *context);
@@ -277,7 +278,6 @@ struct efi_event {
        u64 trigger_next;
        u64 trigger_time;
        enum efi_timer_delay trigger_type;
-       bool is_queued;
        bool is_signaled;
 };
 
@@ -432,7 +432,7 @@ efi_status_t efi_create_event(uint32_t type, efi_uintn_t notify_tpl,
 efi_status_t efi_set_timer(struct efi_event *event, enum efi_timer_delay type,
                           uint64_t trigger_time);
 /* Call this to signal an event */
-void efi_signal_event(struct efi_event *event, bool check_tpl);
+void efi_signal_event(struct efi_event *event);
 
 /* open file system: */
 struct efi_simple_file_system_protocol *efi_simple_file_system(
index 7d1d6e92138ed297251104b5d2f91cdd888875ab..fa01bbda700b0da243e07c3a0d13d7ec45fe1be3 100644 (file)
@@ -27,6 +27,12 @@ LIST_HEAD(efi_obj_list);
 /* List of all events */
 LIST_HEAD(efi_events);
 
+/* List of queued events */
+LIST_HEAD(efi_event_queue);
+
+/* Flag to disable timer activity in ExitBootServices() */
+static bool timers_enabled = true;
+
 /* List of all events registered by RegisterProtocolNotify() */
 LIST_HEAD(efi_register_notify_events);
 
@@ -160,33 +166,76 @@ const char *__efi_nesting_dec(void)
        return indent_string(--nesting_level);
 }
 
+/**
+ * efi_event_is_queued() - check if an event is queued
+ *
+ * @event:     event
+ * Return:     true if event is queued
+ */
+static bool efi_event_is_queued(struct efi_event *event)
+{
+       return !!event->queue_link.next;
+}
+
+/**
+ * efi_process_event_queue() - process event queue
+ */
+static void efi_process_event_queue(void)
+{
+       while (!list_empty(&efi_event_queue)) {
+               struct efi_event *event;
+               efi_uintn_t old_tpl;
+
+               event = list_first_entry(&efi_event_queue, struct efi_event,
+                                        queue_link);
+               if (efi_tpl >= event->notify_tpl)
+                       return;
+               list_del(&event->queue_link);
+               event->queue_link.next = NULL;
+               event->queue_link.prev = NULL;
+               /* Events must be executed at the event's TPL */
+               old_tpl = efi_tpl;
+               efi_tpl = event->notify_tpl;
+               EFI_CALL_VOID(event->notify_function(event,
+                                                    event->notify_context));
+               efi_tpl = old_tpl;
+               if (event->type == EVT_NOTIFY_SIGNAL)
+                       event->is_signaled = 0;
+       }
+}
+
 /**
  * efi_queue_event() - queue an EFI event
  * @event:     event to signal
- * @check_tpl: check the TPL level
  *
  * This function queues the notification function of the event for future
  * execution.
  *
- * The notification function is called if the task priority level of the event
- * is higher than the current task priority level.
- *
- * For the SignalEvent service see efi_signal_event_ext.
- *
  */
-static void efi_queue_event(struct efi_event *event, bool check_tpl)
+static void efi_queue_event(struct efi_event *event)
 {
-       if (event->notify_function) {
-               event->is_queued = true;
-               /* Check TPL */
-               if (check_tpl && efi_tpl >= event->notify_tpl)
-                       return;
-               event->is_queued = false;
-               EFI_CALL_VOID(event->notify_function(event,
-                                                    event->notify_context));
-       } else {
-               event->is_queued = false;
+       struct efi_event *item = NULL;
+
+       if (!event->notify_function)
+               return;
+
+       if (!efi_event_is_queued(event)) {
+               /*
+                * Events must be notified in order of decreasing task priority
+                * level. Insert the new event accordingly.
+                */
+               list_for_each_entry(item, &efi_event_queue, queue_link) {
+                       if (item->notify_tpl < event->notify_tpl) {
+                               list_add_tail(&event->queue_link,
+                                             &item->queue_link);
+                               event = NULL;
+                               break;
+                       }
+               }
+               if (event)
+                       list_add_tail(&event->queue_link, &efi_event_queue);
        }
+       efi_process_event_queue();
 }
 
 /**
@@ -211,7 +260,6 @@ efi_status_t is_valid_tpl(efi_uintn_t tpl)
 /**
  * efi_signal_event() - signal an EFI event
  * @event:     event to signal
- * @check_tpl: check the TPL level
  *
  * This function signals an event. If the event belongs to an event group all
  * events of the group are signaled. If they are of type EVT_NOTIFY_SIGNAL
@@ -219,8 +267,10 @@ efi_status_t is_valid_tpl(efi_uintn_t tpl)
  *
  * For the SignalEvent service see efi_signal_event_ext.
  */
-void efi_signal_event(struct efi_event *event, bool check_tpl)
+void efi_signal_event(struct efi_event *event)
 {
+       if (event->is_signaled)
+               return;
        if (event->group) {
                struct efi_event *evt;
 
@@ -234,20 +284,15 @@ void efi_signal_event(struct efi_event *event, bool check_tpl)
                        if (evt->is_signaled)
                                continue;
                        evt->is_signaled = true;
-                       if (evt->type & EVT_NOTIFY_SIGNAL &&
-                           evt->notify_function)
-                               evt->is_queued = true;
                }
                list_for_each_entry(evt, &efi_events, link) {
                        if (!evt->group || guidcmp(evt->group, event->group))
                                continue;
-                       if (evt->is_queued)
-                               efi_queue_event(evt, check_tpl);
+                       efi_queue_event(evt);
                }
        } else {
                event->is_signaled = true;
-               if (event->type & EVT_NOTIFY_SIGNAL)
-                       efi_queue_event(event, check_tpl);
+               efi_queue_event(event);
        }
 }
 
@@ -637,8 +682,6 @@ efi_status_t efi_create_event(uint32_t type, efi_uintn_t notify_tpl,
        evt->group = group;
        /* Disable timers on boot up */
        evt->trigger_next = -1ULL;
-       evt->is_queued = false;
-       evt->is_signaled = false;
        list_add_tail(&evt->link, &efi_events);
        *event = evt;
        return EFI_SUCCESS;
@@ -733,8 +776,8 @@ void efi_timer_check(void)
        u64 now = timer_get_us();
 
        list_for_each_entry(evt, &efi_events, link) {
-               if (evt->is_queued)
-                       efi_queue_event(evt, true);
+               if (!timers_enabled)
+                       continue;
                if (!(evt->type & EVT_TIMER) || now < evt->trigger_next)
                        continue;
                switch (evt->trigger_type) {
@@ -748,8 +791,9 @@ void efi_timer_check(void)
                        continue;
                }
                evt->is_signaled = false;
-               efi_signal_event(evt, true);
+               efi_signal_event(evt);
        }
+       efi_process_event_queue();
        WATCHDOG_RESET();
 }
 
@@ -850,7 +894,7 @@ static efi_status_t EFIAPI efi_wait_for_event(efi_uintn_t num_events,
                if (!event[i]->type || event[i]->type & EVT_NOTIFY_SIGNAL)
                        return EFI_EXIT(EFI_INVALID_PARAMETER);
                if (!event[i]->is_signaled)
-                       efi_queue_event(event[i], true);
+                       efi_queue_event(event[i]);
        }
 
        /* Wait for signal */
@@ -894,7 +938,7 @@ static efi_status_t EFIAPI efi_signal_event_ext(struct efi_event *event)
        EFI_ENTRY("%p", event);
        if (efi_is_event(event) != EFI_SUCCESS)
                return EFI_EXIT(EFI_INVALID_PARAMETER);
-       efi_signal_event(event, true);
+       efi_signal_event(event);
        return EFI_EXIT(EFI_SUCCESS);
 }
 
@@ -933,6 +977,9 @@ static efi_status_t EFIAPI efi_close_event(struct efi_event *event)
                        free(item);
                }
        }
+       /* Remove event from queue */
+       if (efi_event_is_queued(event))
+               list_del(&event->queue_link);
 
        list_del(&event->link);
        free(event);
@@ -961,7 +1008,7 @@ static efi_status_t EFIAPI efi_check_event(struct efi_event *event)
            event->type & EVT_NOTIFY_SIGNAL)
                return EFI_EXIT(EFI_INVALID_PARAMETER);
        if (!event->is_signaled)
-               efi_queue_event(event, true);
+               efi_queue_event(event);
        if (event->is_signaled) {
                event->is_signaled = false;
                return EFI_EXIT(EFI_SUCCESS);
@@ -1068,7 +1115,8 @@ efi_status_t efi_add_protocol(const efi_handle_t handle,
                        }
                        notif->handle = handle;
                        list_add_tail(&notif->link, &event->handles);
-                       efi_signal_event(event->event, true);
+                       event->event->is_signaled = false;
+                       efi_signal_event(event->event);
                }
        }
 
@@ -1593,7 +1641,7 @@ out:
        /* Notify that the configuration table was changed */
        list_for_each_entry(evt, &efi_events, link) {
                if (evt->group && !guidcmp(evt->group, guid)) {
-                       efi_signal_event(evt, false);
+                       efi_signal_event(evt);
                        break;
                }
        }
@@ -1899,13 +1947,13 @@ static efi_status_t EFIAPI efi_exit_boot_services(efi_handle_t image_handle,
        if (map_key != efi_memory_map_key)
                return EFI_INVALID_PARAMETER;
 
-       /* 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);
 
+       /* 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 == EVT_SIGNAL_EXIT_BOOT_SERVICES)
@@ -1916,11 +1964,14 @@ static efi_status_t EFIAPI efi_exit_boot_services(efi_handle_t image_handle,
                if (evt->group &&
                    !guidcmp(evt->group,
                             &efi_guid_event_group_exit_boot_services)) {
-                       efi_signal_event(evt, false);
+                       efi_signal_event(evt);
                        break;
                }
        }
 
+       /* Make sure that notification functions are not called anymore */
+       efi_tpl = TPL_HIGH_LEVEL;
+
        /* TODO: Should persist EFI variables here */
 
        board_quiesce_devices();
index 3b7578f3aa4f6d7c218afd3cd3c398f0ec3199a3..2fc25e118f2ddb07141b6895326defba89888882 100644 (file)
@@ -704,7 +704,7 @@ static void efi_cin_check(void)
        efi_status_t ret;
 
        if (key_available) {
-               efi_signal_event(efi_con_in.wait_for_key, true);
+               efi_signal_event(efi_con_in.wait_for_key);
                return;
        }
 
@@ -718,7 +718,7 @@ static void efi_cin_check(void)
 
                        /* Queue the wait for key event */
                        if (key_available)
-                               efi_signal_event(efi_con_in.wait_for_key, true);
+                               efi_signal_event(efi_con_in.wait_for_key);
                }
        }
 }
index 386cf924fe26a3c457c60878de55d5dfcb60e544..8d7685123438f05aeffaadc15e7912cfd84f560a 100644 (file)
@@ -321,7 +321,7 @@ uint64_t efi_add_memory_map(uint64_t start, uint64_t pages, int memory_type,
                if (evt->group &&
                    !guidcmp(evt->group,
                             &efi_guid_event_group_memory_map_change)) {
-                       efi_signal_event(evt, false);
+                       efi_signal_event(evt);
                        break;
                }
        }
index 9c50955c9bd096d4dccdf2c08f8a702051612212..432551d0c8ca6a4ee64984324a0b6f4ffe43377c 100644 (file)
@@ -130,7 +130,7 @@ static void EFIAPI efi_reset_system_boottime(
                if (evt->group &&
                    !guidcmp(evt->group,
                             &efi_guid_event_group_reset_system)) {
-                       efi_signal_event(evt, false);
+                       efi_signal_event(evt);
                        break;
                }
        }
index 5a7980c5d0b853fe8c93710f9bf6f42931c43da0..6dcde50648b8da1c55289f826257891f7ccc7a3c 100644 (file)
@@ -80,12 +80,11 @@ static int execute(void)
                        return EFI_ST_FAILURE;
                }
                for (j = 0; j < GROUP_SIZE; ++j) {
-                       if (counter[j] != i) {
+                       if (counter[j] != 2 * i + 1) {
                                efi_st_printf("i %u, j %u, count %u\n",
                                              (unsigned int)i, (unsigned int)j,
                                              (unsigned int)counter[j]);
-                               efi_st_error(
-                                       "Notification function was called\n");
+                               efi_st_error("Notification function was not called\n");
                                return EFI_ST_FAILURE;
                        }
                        /* Clear signaled state */
@@ -94,7 +93,7 @@ static int execute(void)
                                efi_st_error("Event was not signaled\n");
                                return EFI_ST_FAILURE;
                        }
-                       if (counter[j] != i) {
+                       if (counter[j] != 2 * i + 1) {
                                efi_st_printf("i %u, j %u, count %u\n",
                                              (unsigned int)i, (unsigned int)j,
                                              (unsigned int)counter[j]);
@@ -109,7 +108,7 @@ static int execute(void)
                                        "Signaled state not cleared\n");
                                return EFI_ST_FAILURE;
                        }
-                       if (counter[j] != i + 1) {
+                       if (counter[j] != 2 * i + 2) {
                                efi_st_printf("i %u, j %u, count %u\n",
                                              (unsigned int)i, (unsigned int)j,
                                              (unsigned int)counter[j]);