summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHeinrich Schuchardt <xypron.glpk@gmx.de>2017-09-15 10:06:13 +0200
committerAlexander Graf <agraf@suse.de>2017-09-18 23:53:57 +0200
commitca62a4f53e82d4877e3b5fb7d7cd5c1ecc485e32 (patch)
treef56a15bbba9eb6d66f8d345f9277e1a7dee1fb78
parent38b1b79021418709bcc55504d1fec31d8a365f56 (diff)
efi_loader: implement queueing of the notification function
For the correct implementation of the task priority level (TPL) calling the notification function must be queued. Add a status field 'queued' to events. In function efi_signal_event set status queued if a notification function exists and reset it after we have called the function. A later patch will add a check of the TPL here. In efi_create_event and efi_close_event unset the queued status. In function efi_wait_for_event and efi_check_event queue the notification function. In efi_timer_check call the efi_notify_event if the status queued is set. For all timer events set status signaled. In efi_console_timer_notify set the signaled state of the WaitForKey event. Signed-off-by: Heinrich Schuchardt <xypron.glpk@gmx.de> Signed-off-by: Alexander Graf <agraf@suse.de>
-rw-r--r--include/efi_loader.h4
-rw-r--r--lib/efi_loader/efi_boottime.c40
-rw-r--r--lib/efi_loader/efi_console.c4
3 files changed, 36 insertions, 12 deletions
diff --git a/include/efi_loader.h b/include/efi_loader.h
index f74b33d589..25398ba40c 100644
--- a/include/efi_loader.h
+++ b/include/efi_loader.h
@@ -131,7 +131,8 @@ struct efi_object {
* @nofify_function: Function to call when the event is triggered
* @notify_context: Data to be passed to the notify function
* @trigger_type: Type of timer, see efi_set_timer
- * @signaled: The notify function was already called
+ * @queued: The notification functionis queued
+ * @signaled: The event occured
*/
struct efi_event {
uint32_t type;
@@ -141,6 +142,7 @@ struct efi_event {
u64 trigger_next;
u64 trigger_time;
enum efi_timer_delay trigger_type;
+ int queued;
int signaled;
};
diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c
index 2c9379a8ae..408b4a9097 100644
--- a/lib/efi_loader/efi_boottime.c
+++ b/lib/efi_loader/efi_boottime.c
@@ -159,13 +159,13 @@ static u64 efi_div10(u64 a)
void efi_signal_event(struct efi_event *event)
{
- if (event->signaled)
- return;
- event->signaled = 1;
- if (event->type & EVT_NOTIFY_SIGNAL) {
+ if (event->notify_function) {
+ event->queued = 1;
+ /* Put missing TPL check here */
EFI_CALL_VOID(event->notify_function(event,
event->notify_context));
}
+ event->queued = 0;
}
static efi_status_t efi_unsupported(const char *funcname)
@@ -276,6 +276,7 @@ efi_status_t efi_create_event(uint32_t type, UINTN notify_tpl,
efi_events[i].notify_context = notify_context;
/* Disable timers on bootup */
efi_events[i].trigger_next = -1ULL;
+ efi_events[i].queued = 0;
efi_events[i].signaled = 0;
*event = &efi_events[i];
return EFI_SUCCESS;
@@ -307,16 +308,25 @@ void efi_timer_check(void)
u64 now = timer_get_us();
for (i = 0; i < ARRAY_SIZE(efi_events); ++i) {
- if (!efi_events[i].type ||
- !(efi_events[i].type & EVT_TIMER) ||
- efi_events[i].trigger_type == EFI_TIMER_STOP ||
+ if (!efi_events[i].type)
+ continue;
+ if (efi_events[i].queued)
+ efi_signal_event(&efi_events[i]);
+ if (!(efi_events[i].type & EVT_TIMER) ||
now < efi_events[i].trigger_next)
continue;
- if (efi_events[i].trigger_type == EFI_TIMER_PERIODIC) {
+ switch (efi_events[i].trigger_type) {
+ case EFI_TIMER_RELATIVE:
+ efi_events[i].trigger_type = EFI_TIMER_STOP;
+ break;
+ case EFI_TIMER_PERIODIC:
efi_events[i].trigger_next +=
efi_events[i].trigger_time;
- efi_events[i].signaled = 0;
+ break;
+ default:
+ continue;
}
+ efi_events[i].signaled = 1;
efi_signal_event(&efi_events[i]);
}
WATCHDOG_RESET();
@@ -377,6 +387,7 @@ static efi_status_t EFIAPI efi_wait_for_event(unsigned long num_events,
/* Check parameters */
if (!num_events || !event)
return EFI_EXIT(EFI_INVALID_PARAMETER);
+ /* Put missing TPL check here */
for (i = 0; i < num_events; ++i) {
for (j = 0; j < ARRAY_SIZE(efi_events); ++j) {
if (event[i] == &efi_events[j])
@@ -386,6 +397,8 @@ static efi_status_t EFIAPI efi_wait_for_event(unsigned long num_events,
known_event:
if (!event[i]->type || event[i]->type & EVT_NOTIFY_SIGNAL)
return EFI_EXIT(EFI_INVALID_PARAMETER);
+ if (!event[i]->signaled)
+ efi_signal_event(event[i]);
}
/* Wait for signal */
@@ -418,7 +431,11 @@ static efi_status_t EFIAPI efi_signal_event_ext(struct efi_event *event)
for (i = 0; i < ARRAY_SIZE(efi_events); ++i) {
if (event != &efi_events[i])
continue;
- efi_signal_event(event);
+ if (event->signaled)
+ break;
+ event->signaled = 1;
+ if (event->type & EVT_NOTIFY_SIGNAL)
+ efi_signal_event(event);
break;
}
return EFI_EXIT(EFI_SUCCESS);
@@ -433,6 +450,7 @@ static efi_status_t EFIAPI efi_close_event(struct efi_event *event)
if (event == &efi_events[i]) {
event->type = 0;
event->trigger_next = -1ULL;
+ event->queued = 0;
event->signaled = 0;
return EFI_EXIT(EFI_SUCCESS);
}
@@ -451,6 +469,8 @@ static efi_status_t EFIAPI efi_check_event(struct efi_event *event)
continue;
if (!event->type || event->type & EVT_NOTIFY_SIGNAL)
break;
+ if (!event->signaled)
+ efi_signal_event(event);
if (event->signaled)
return EFI_EXIT(EFI_SUCCESS);
return EFI_EXIT(EFI_NOT_READY);
diff --git a/lib/efi_loader/efi_console.c b/lib/efi_loader/efi_console.c
index 3fc82b8726..65c07fdf37 100644
--- a/lib/efi_loader/efi_console.c
+++ b/lib/efi_loader/efi_console.c
@@ -426,8 +426,10 @@ static void EFIAPI efi_console_timer_notify(struct efi_event *event,
void *context)
{
EFI_ENTRY("%p, %p", event, context);
- if (tstc())
+ if (tstc()) {
+ efi_con_in.wait_for_key->signaled = 1;
efi_signal_event(efi_con_in.wait_for_key);
+ }
EFI_EXIT(EFI_SUCCESS);
}