From patchwork Tue Jul 18 18:17:18 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Heinrich Schuchardt X-Patchwork-Id: 790460 X-Patchwork-Delegate: agraf@suse.de Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=none (mailfrom) smtp.mailfrom=lists.denx.de (client-ip=81.169.180.215; helo=lists.denx.de; envelope-from=u-boot-bounces@lists.denx.de; receiver=) Received: from lists.denx.de (dione.denx.de [81.169.180.215]) by ozlabs.org (Postfix) with ESMTP id 3xBpP95NVLz9t1G for ; Wed, 19 Jul 2017 04:20:29 +1000 (AEST) Received: by lists.denx.de (Postfix, from userid 105) id 61354C21E06; Tue, 18 Jul 2017 18:19:59 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on lists.denx.de X-Spam-Level: X-Spam-Status: No, score=-0.7 required=5.0 tests=FREEMAIL_FROM, RCVD_IN_DNSWL_LOW, RCVD_IN_MSPIKE_H3, RCVD_IN_MSPIKE_WL autolearn=unavailable autolearn_force=no version=3.4.0 Received: from lists.denx.de (localhost [IPv6:::1]) by lists.denx.de (Postfix) with ESMTP id B9107C21DC1; Tue, 18 Jul 2017 18:18:51 +0000 (UTC) Received: by lists.denx.de (Postfix, from userid 105) id C2C39C21DA4; Tue, 18 Jul 2017 18:18:25 +0000 (UTC) Received: from mout.gmx.net (mout.gmx.net [212.227.15.19]) by lists.denx.de (Postfix) with ESMTPS id EE4E4C21DF7 for ; Tue, 18 Jul 2017 18:18:20 +0000 (UTC) Received: from localhost.localdomain ([84.118.154.110]) by mail.gmx.com (mrgmx001 [212.227.17.190]) with ESMTPSA (Nemesis) id 0MA9Yv-1dMqsG1Nqz-00BOPu; Tue, 18 Jul 2017 20:17:33 +0200 From: Heinrich Schuchardt To: Alexander Graf Date: Tue, 18 Jul 2017 20:17:18 +0200 Message-Id: <20170718181723.1780-3-xypron.glpk@gmx.de> X-Mailer: git-send-email 2.13.2 In-Reply-To: <20170718181723.1780-1-xypron.glpk@gmx.de> References: <20170718181723.1780-1-xypron.glpk@gmx.de> X-Provags-ID: V03:K0:Y/IB+efJL9Y/KmQ4gvUFhMAGtOnVKmAiR8cvdZBnxlpobwRsZM3 r7FohFeNemKe56DBj0tnRLIQgF+UTjWpPfF0pXg8yOtFFRHLCM9FMVtbjyV325nmHcuzBx4 Gp/RS01bOW6i1ByJRSgKo6/8Es2COMClw1mtM8g3jd+ueyQdgW43qgtAFGzj1L27G3qYKpT i8APSmMyEU16M7pZQmsfw== X-UI-Out-Filterresults: notjunk:1; V01:K0:w6D0QFn6UW4=:RquumK0IJyL/q8iwx/Eq0v 5/FP/ucuDeue81IMlBc/ZEDmTZRjfGkxlV6/5kRR8SHeryc5uV/lWiT6Ps6nh0QFAmS2XMH5J XHEte0ivkRAUR4CDoMGfNajZ7b/CyeYxtGrTcnAKU0qd5HF2/Y3pw5PjjjUxuqKOwyCQY2ogx eo/U5IfLvq8BG+iJQfHZd9/ESLIKIKGDlqMuBTigMwbKgvnOQ3UYkymDGK2XaN9ilc30ooMk3 VO6w5AEL5k4IcbEfDpW1WC+/gpZK13XinSkpPzGweRN9jbRHJ/DLUMapM6I6b/2ML7UhdJvpK vgQU8FI/wb2Qwwk23Bmfd5ZHdV+eT/rGx1NaCGh303HnxggdK3D75tzB9xCcQWpwVNa2RsULS poIDt4/fQCvT31jy3IPSexZmYw7HJ6NL3N5kJB+5SHeMODKeDsr1xAssVayWKs0RTzP89+BUB wSTx8oZsGrRuvPmqEnwf9QMhFDBOPj2ApaFyjPgKJeTcUC94csvNIS6aYozKWmpfuQfUrAK76 R5QbA9l9rxbCR55VF7eBoCtBakgG4Mz36tU7hCz+GPyIjPHMCv0m3vomyfrfditX1RtjCbJPB J6hxkvHO6d3xWefzCIYdNN1NrkOtvO/H877IlWASPKy+SwJ6OwA/WWNIiwBGMT1UJwdT0JPll C9YTMj5UqEwGnJNRA/sepZVzoDZ6oEOfPxL68RttZaAH9nHOwDBuk29LUNbxuKjb+0y+sl7L2 yPxWsgeax3td7katCMkZKGn9g4Tgj8tKaTPvo+nfy8v4cxHoc+ZNOvlhiPgoFRRJRJm8fqijw BdV5rA98ZffyGN1PMhV4PmF5vPtHA== Cc: Heinrich Schuchardt , u-boot@lists.denx.de Subject: [U-Boot] [PATCH v2 2/7] efi_loader: implement multiple event support X-BeenThere: u-boot@lists.denx.de X-Mailman-Version: 2.1.18 Precedence: list List-Id: U-Boot discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: u-boot-bounces@lists.denx.de Sender: "U-Boot" Up to now the boot time supported only a single event. This patch now allows four events. Signed-off-by: Heinrich Schuchardt --- v2 add TPL constants consider multiple events in efi_wait_for_event move notification to new function efi_signal_event --- include/efi_api.h | 13 ++- include/efi_loader.h | 24 ++++++ lib/efi_loader/efi_boottime.c | 195 ++++++++++++++++++++++++++++-------------- 3 files changed, 168 insertions(+), 64 deletions(-) diff --git a/include/efi_api.h b/include/efi_api.h index a1f8221111..a3b8e04576 100644 --- a/include/efi_api.h +++ b/include/efi_api.h @@ -28,8 +28,17 @@ enum efi_event_type { EFI_TIMER_RELATIVE = 2 }; -#define EVT_NOTIFY_WAIT 0x00000100 -#define EVT_NOTIFY_SIGNAL 0x00000200 +#define EVT_TIMER 0x80000000 +#define EVT_RUNTIME 0x40000000 +#define EVT_NOTIFY_WAIT 0x00000100 +#define EVT_NOTIFY_SIGNAL 0x00000200 +#define EVT_SIGNAL_EXIT_BOOT_SERVICES 0x00000201 +#define EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE 0x60000202 + +#define TPL_APPLICATION 0x04 +#define TPL_CALLBACK 0x08 +#define TPL_NOTIFY 0x10 +#define TPL_HIGH_LEVEL 0x1F struct efi_event; diff --git a/include/efi_loader.h b/include/efi_loader.h index d7847d23e5..3d18bfbd2e 100644 --- a/include/efi_loader.h +++ b/include/efi_loader.h @@ -63,6 +63,30 @@ struct efi_object { void *handle; }; +/** + * struct efi_event + * + * @type: Type of event, see efi_create_event + * @notify_tpl: Task priority level of notifications + * @trigger_time: Period of the timer + * @trigger_next: Next time to trigger the timer + * @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 + */ +struct efi_event { + u32 type; + unsigned long notify_tpl; + void (EFIAPI *notify_function)(struct efi_event *event, void *context); + void *notify_context; + u64 trigger_next; + u64 trigger_time; + enum efi_event_type trigger_type; + int signaled; +}; + + /* This list contains all UEFI objects we know of */ extern struct list_head efi_obj_list; diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c index 0eda465359..a49acc8693 100644 --- a/lib/efi_loader/efi_boottime.c +++ b/lib/efi_loader/efi_boottime.c @@ -82,6 +82,18 @@ efi_status_t efi_exit_func(efi_status_t ret) return ret; } +static void efi_signal_event(struct efi_event *event) +{ + if (event->signaled) + return; + event->signaled = 1; + if (event->type & EVT_NOTIFY_SIGNAL) { + EFI_EXIT(EFI_SUCCESS); + event->notify_function(event, event->notify_context); + EFI_ENTRY("returning from notification function"); + } +} + static efi_status_t efi_unsupported(const char *funcname) { debug("EFI: App called into unimplemented function %s\n", funcname); @@ -163,22 +175,10 @@ static efi_status_t EFIAPI efi_free_pool_ext(void *buffer) } /* - * Our event capabilities are very limited. Only support a single - * event to exist, so we don't need to maintain lists. + * Our event capabilities are very limited. Only a small limited + * number of events is allowed to coexist. */ -static struct efi_event { - enum efi_event_type type; - u32 trigger_type; - u32 trigger_time; - u64 trigger_next; - unsigned long notify_tpl; - void (EFIAPI *notify_function) (struct efi_event *event, - void *context); - void *notify_context; -} efi_event = { - /* Disable timers on bootup */ - .trigger_next = -1ULL, -}; +static struct efi_event efi_events[16]; static efi_status_t EFIAPI efi_create_event( enum efi_event_type type, ulong notify_tpl, @@ -187,13 +187,10 @@ static efi_status_t EFIAPI efi_create_event( void *context), void *notify_context, struct efi_event **event) { + int i; + EFI_ENTRY("%d, 0x%lx, %p, %p", type, notify_tpl, notify_function, notify_context); - if (efi_event.notify_function) { - /* We only support one event at a time */ - return EFI_EXIT(EFI_OUT_OF_RESOURCES); - } - if (event == NULL) return EFI_EXIT(EFI_INVALID_PARAMETER); @@ -204,13 +201,20 @@ static efi_status_t EFIAPI efi_create_event( 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; - efi_event.notify_context = notify_context; - *event = &efi_event; - - return EFI_EXIT(EFI_SUCCESS); + for (i = 0; i < ARRAY_SIZE(efi_events); ++i) { + if (efi_events[i].type) + continue; + efi_events[i].type = type; + efi_events[i].notify_tpl = notify_tpl; + efi_events[i].notify_function = notify_function; + efi_events[i].notify_context = notify_context; + /* Disable timers on bootup */ + efi_events[i].trigger_next = -1ULL; + efi_events[i].signaled = 0; + *event = &efi_events[i]; + return EFI_EXIT(EFI_SUCCESS); + } + return EFI_EXIT(EFI_OUT_OF_RESOURCES); } /* @@ -219,17 +223,22 @@ static efi_status_t EFIAPI efi_create_event( */ void efi_timer_check(void) { + int i; u64 now = timer_get_us(); - if (now >= efi_event.trigger_next) { - /* Triggering! */ - if (efi_event.trigger_type == EFI_TIMER_PERIODIC) - efi_event.trigger_next += efi_event.trigger_time / 10; - if (efi_event.type & (EVT_NOTIFY_WAIT | EVT_NOTIFY_SIGNAL)) - efi_event.notify_function(&efi_event, - efi_event.notify_context); + 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 || + now < efi_events[i].trigger_next) + continue; + if (efi_events[i].trigger_type == EFI_TIMER_PERIODIC) { + efi_events[i].trigger_next += + efi_events[i].trigger_time / 10; + efi_events[i].signaled = 0; + } + efi_signal_event(&efi_events[i]); } - WATCHDOG_RESET(); } @@ -239,6 +248,7 @@ static efi_status_t EFIAPI efi_set_timer(struct efi_event *event, int type, /* We don't have 64bit division available everywhere, so limit timer * distances to 32bit bits. */ u32 trigger32 = trigger_time; + int i; EFI_ENTRY("%p, %d, %"PRIx64, event, type, trigger_time); @@ -247,60 +257,121 @@ static efi_status_t EFIAPI efi_set_timer(struct efi_event *event, int type, trigger_time, trigger32); } - if (event != &efi_event) { - /* We only support one event at a time */ - return EFI_EXIT(EFI_INVALID_PARAMETER); - } + for (i = 0; i < ARRAY_SIZE(efi_events); ++i) { + if (event != &efi_events[i]) + continue; - switch (type) { - case EFI_TIMER_STOP: - efi_event.trigger_next = -1ULL; - break; - case EFI_TIMER_PERIODIC: - case EFI_TIMER_RELATIVE: - efi_event.trigger_next = timer_get_us() + (trigger32 / 10); - break; - default: - return EFI_EXIT(EFI_INVALID_PARAMETER); + if (!(event->type & EVT_TIMER)) + break; + switch (type) { + case EFI_TIMER_STOP: + event->trigger_next = -1ULL; + break; + case EFI_TIMER_PERIODIC: + case EFI_TIMER_RELATIVE: + event->trigger_next = + timer_get_us() + (trigger32 / 10); + break; + default: + return EFI_EXIT(EFI_INVALID_PARAMETER); + } + event->trigger_type = type; + event->trigger_time = trigger_time; + return EFI_EXIT(EFI_SUCCESS); } - efi_event.trigger_type = type; - efi_event.trigger_time = trigger_time; - - return EFI_EXIT(EFI_SUCCESS); + return EFI_EXIT(EFI_INVALID_PARAMETER); } static efi_status_t EFIAPI efi_wait_for_event(unsigned long num_events, struct efi_event **event, unsigned long *index) { - u64 now; + int i, j; EFI_ENTRY("%ld, %p, %p", num_events, event, index); - now = timer_get_us(); - while (now < efi_event.trigger_next) { } - efi_timer_check(); + /* Check parameters */ + if (!num_events || !event) + return EFI_EXIT(EFI_INVALID_PARAMETER); + for (i = 0; i < num_events; ++i) { + for (j = 0; j < ARRAY_SIZE(efi_events); ++j) { + if (event[i] == &efi_events[j]) + goto known_event; + } + return EFI_EXIT(EFI_INVALID_PARAMETER); +known_event: + if (!event[i]->type || event[i]->type & EVT_NOTIFY_SIGNAL) + return EFI_EXIT(EFI_INVALID_PARAMETER); + } + + /* Wait for signal */ + for (;;) { + for (i = 0; i < num_events; ++i) { + if (event[i]->signaled) + goto out; + } + /* Allow events to occur. */ + efi_timer_check(); + } + +out: + /* + * Reset the signal which is passed to the caller to allow periodic + * events to occur. + */ + event[i]->signaled = 0; + if (index) + *index = i; return EFI_EXIT(EFI_SUCCESS); } -static efi_status_t EFIAPI efi_signal_event(struct efi_event *event) +static efi_status_t EFIAPI efi_signal_event_ext(struct efi_event *event) { + int i; + EFI_ENTRY("%p", event); + for (i = 0; i < ARRAY_SIZE(efi_events); ++i) { + if (event != &efi_events[i]) + continue; + efi_signal_event(event); + break; + } return EFI_EXIT(EFI_SUCCESS); } static efi_status_t EFIAPI efi_close_event(struct efi_event *event) { + int i; + EFI_ENTRY("%p", event); - efi_event.trigger_next = -1ULL; - return EFI_EXIT(EFI_SUCCESS); + for (i = 0; i < ARRAY_SIZE(efi_events); ++i) { + if (event == &efi_events[i]) { + event->type = 0; + event->trigger_next = -1ULL; + event->signaled = 0; + return EFI_EXIT(EFI_SUCCESS); + } + } + return EFI_EXIT(EFI_INVALID_PARAMETER); } static efi_status_t EFIAPI efi_check_event(struct efi_event *event) { + int i; + EFI_ENTRY("%p", event); - return EFI_EXIT(EFI_NOT_READY); + efi_timer_check(); + for (i = 0; i < ARRAY_SIZE(efi_events); ++i) { + if (event != &efi_events[i]) + continue; + if (!event->type || event->type & EVT_NOTIFY_SIGNAL) + break; + if (event->signaled) + return EFI_EXIT(EFI_SUCCESS); + return EFI_EXIT(EFI_NOT_READY); + } + return EFI_EXIT(EFI_INVALID_PARAMETER); } static efi_status_t EFIAPI efi_install_protocol_interface(void **handle, @@ -1032,7 +1103,7 @@ static const struct efi_boot_services efi_boot_services = { .create_event = efi_create_event, .set_timer = efi_set_timer, .wait_for_event = efi_wait_for_event, - .signal_event = efi_signal_event, + .signal_event = efi_signal_event_ext, .close_event = efi_close_event, .check_event = efi_check_event, .install_protocol_interface = efi_install_protocol_interface_ext,