From patchwork Tue Oct 10 12:23:03 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Rob Clark X-Patchwork-Id: 823812 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=) Authentication-Results: ozlabs.org; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=gmail.com header.i=@gmail.com header.b="buEk9c1Y"; dkim-atps=neutral Received: from lists.denx.de (dione.denx.de [81.169.180.215]) by ozlabs.org (Postfix) with ESMTP id 3yBGd40pnPz9tY3 for ; Tue, 10 Oct 2017 23:29:12 +1100 (AEDT) Received: by lists.denx.de (Postfix, from userid 105) id C9D69C21DCA; Tue, 10 Oct 2017 12:27:26 +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.0 required=5.0 tests=FREEMAIL_FROM, RCVD_IN_MSPIKE_H3, RCVD_IN_MSPIKE_WL, T_DKIM_INVALID 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 7B1C6C21DE4; Tue, 10 Oct 2017 12:24:54 +0000 (UTC) Received: by lists.denx.de (Postfix, from userid 105) id A09C0C21E0E; Tue, 10 Oct 2017 12:23:49 +0000 (UTC) Received: from mail-qt0-f196.google.com (mail-qt0-f196.google.com [209.85.216.196]) by lists.denx.de (Postfix) with ESMTPS id 101E6C21CB3 for ; Tue, 10 Oct 2017 12:23:44 +0000 (UTC) Received: by mail-qt0-f196.google.com with SMTP id 34so33400747qtb.13 for ; Tue, 10 Oct 2017 05:23:44 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=1WC17aJ2zvJd/en+RfLiKYZjF94F8EGxQtHeXh3KoE4=; b=buEk9c1Y9N/0mJIDTFhe/sULRmulahHjPaKsXHkByTEWkLijDjTPoS2XWcAQhhR74C Fm5kFwclK5ZOzXyngQ6cfSXvLh9bl3BXES+8Zemw497TB+1wJx/w3SHLksoa4RMUC5PN AfN1P8RbY++G3a/qXwFc6sHYL1C1yuVhz5h8l4urlIdT/njrtfRMkKma4OUmwrQTAYbr 3i4lsDEgJ3jXYMlfcVOX3Cf4kf9haSurfzrufXx1rjFBxa3+lyhcb2N/ht7V06ICkKsr HlCKdkDKOhEVTAsfV4ure8w+SzS8Wtsxv3NQXmRoP+PaOBCADPZy6bEz6LujBWlEirQu DjAg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=1WC17aJ2zvJd/en+RfLiKYZjF94F8EGxQtHeXh3KoE4=; b=SMp6e3ZQPveMzf5KjAq7v1whB7NMrCkrwjNfT/ItENxI1eNnM4m+BqmMuEpniT+MfP sf6xVwQD9mRo8QJYXWwDaG+t6vet/q/CCn7CJMqDFkDdv64FYY4gihAS1Vp2GI5WuooD 9P4UUGaMH5KGc0A3XxKky2hgBaf8fEdLuf1SzZfefxhj8n05NvvKm4wi5nRSPvgIBkWR fcv/WCzbYcTRUTu3E4NXTWcNcG2VZo0xBLT+c/1sCWv1WHYHs6t59OdcqyPINrwloHoE J9VRRo+ZRpoBMFhVF3i3ewnZFB60FfOfmscyVc7YIN2T63wrTzUYolT4trdPmirnrF6B wBog== X-Gm-Message-State: AMCzsaXbYTYBGBSBxhQqAxCG3hQYsOo0XZw5YN4vFzgJ5jvRnrCjxe/x KY+kc8q7E6pzcr35sOwd2d3BUMc6 X-Google-Smtp-Source: AOwi7QC7SURC/i91CVR4iOv+6Z6MeJHrfNlOsXvwYPvT+Kfdp+vFx6LcyJ9roRIa6lS/lcD6Yf083Q== X-Received: by 10.237.61.49 with SMTP id g46mr18240590qtf.239.1507638222647; Tue, 10 Oct 2017 05:23:42 -0700 (PDT) Received: from localhost ([144.121.20.162]) by smtp.gmail.com with ESMTPSA id d25sm74467qtc.7.2017.10.10.05.23.41 (version=TLS1_2 cipher=ECDHE-RSA-CHACHA20-POLY1305 bits=256/256); Tue, 10 Oct 2017 05:23:41 -0700 (PDT) From: Rob Clark To: U-Boot Mailing List Date: Tue, 10 Oct 2017 08:23:03 -0400 Message-Id: <20171010122309.25313-8-robdclark@gmail.com> X-Mailer: git-send-email 2.13.6 In-Reply-To: <20171010122309.25313-1-robdclark@gmail.com> References: <20171010122309.25313-1-robdclark@gmail.com> MIME-Version: 1.0 Cc: Heinrich Schuchardt , Leif Lindholm Subject: [U-Boot] [PATCH 07/11] efi_loader: fix events 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: , Errors-To: u-boot-bounces@lists.denx.de Sender: "U-Boot" An event can be created with type==0, Shell.efi does this for an event that is set when Ctrl-C is typed. So our current approach of having a fixed set of timer slots, and determining which slots are unused by type==0 doesn't work so well. But we don't have any particularly good reason to have a fixed table of events, so just dynamically allocate them and keep a list. Also fixes an incorrect implementation of CheckEvent() which was (a) incorrectly returning an error if type==0, and (b) didn't handle the case of an unsignaled event with a notify callback. With these fixes (plus implementation of SIMPLE_TEXT_INPUT_EX protocol), Ctrl-C works in Shell.efi. Signed-off-by: Rob Clark Tested-by: Heinrich Schuchardt Acked-by: Heinrich Schuchardt --- include/efi_loader.h | 1 + lib/efi_loader/efi_boottime.c | 217 +++++++++++++++++++++--------------------- 2 files changed, 111 insertions(+), 107 deletions(-) diff --git a/include/efi_loader.h b/include/efi_loader.h index e6e55d2cb4..2232caca44 100644 --- a/include/efi_loader.h +++ b/include/efi_loader.h @@ -154,6 +154,7 @@ struct efi_event { enum efi_timer_delay trigger_type; bool is_queued; bool is_signaled; + struct list_head link; }; diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c index 39dcc72648..19fafe546c 100644 --- a/lib/efi_loader/efi_boottime.c +++ b/lib/efi_loader/efi_boottime.c @@ -350,11 +350,26 @@ static efi_status_t efi_create_handle(void **handle) return r; } +static LIST_HEAD(efi_events); + /* - * Our event capabilities are very limited. Only a small limited - * number of events is allowed to coexist. + * Check if a pointer is a valid event. + * + * It might be nice at some point to extend this to a more general + * mechanism to check if pointers passed from the EFI world are + * valid objects of a particular type. */ -static struct efi_event efi_events[16]; +static bool efi_is_event(const void *obj) +{ + struct efi_event *evt; + + list_for_each_entry(evt, &efi_events, link) { + if (evt == obj) + return true; + } + + return false; +} /* * Create an event. @@ -377,7 +392,7 @@ efi_status_t efi_create_event(uint32_t type, UINTN notify_tpl, void *context), void *notify_context, struct efi_event **event) { - int i; + struct efi_event *evt; if (event == NULL) return EFI_INVALID_PARAMETER; @@ -389,21 +404,24 @@ efi_status_t efi_create_event(uint32_t type, UINTN notify_tpl, notify_function == NULL) return EFI_INVALID_PARAMETER; - 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].is_queued = false; - efi_events[i].is_signaled = false; - *event = &efi_events[i]; - return EFI_SUCCESS; - } - return EFI_OUT_OF_RESOURCES; + evt = calloc(1, sizeof(*evt)); + if (!evt) + return EFI_OUT_OF_RESOURCES; + + evt->type = type; + evt->notify_tpl = notify_tpl; + evt->notify_function = notify_function; + evt->notify_context = notify_context; + /* Disable timers on bootup */ + evt->trigger_next = -1ULL; + evt->is_queued = false; + evt->is_signaled = false; + + list_add_tail(&evt->link, &efi_events); + + *event = evt; + + return EFI_SUCCESS; } /* @@ -443,30 +461,31 @@ static efi_status_t EFIAPI efi_create_event_ext( */ void efi_timer_check(void) { - int i; + struct efi_event *evt; u64 now = timer_get_us(); - for (i = 0; i < ARRAY_SIZE(efi_events); ++i) { - if (!efi_events[i].type) - continue; - if (efi_events[i].is_queued) - efi_signal_event(&efi_events[i]); - if (!(efi_events[i].type & EVT_TIMER) || - now < efi_events[i].trigger_next) + /* + * TODO perhaps optimize a bit and track the time of next + * timer to expire? + */ + list_for_each_entry(evt, &efi_events, link) { + if (evt->is_queued) + efi_signal_event(evt); + if (!(evt->type & EVT_TIMER) || + now < evt->trigger_next) continue; - switch (efi_events[i].trigger_type) { + switch (evt->trigger_type) { case EFI_TIMER_RELATIVE: - efi_events[i].trigger_type = EFI_TIMER_STOP; + evt->trigger_type = EFI_TIMER_STOP; break; case EFI_TIMER_PERIODIC: - efi_events[i].trigger_next += - efi_events[i].trigger_time; + evt->trigger_next += evt->trigger_time; break; default: continue; } - efi_events[i].is_signaled = true; - efi_signal_event(&efi_events[i]); + evt->is_signaled = true; + efi_signal_event(evt); } WATCHDOG_RESET(); } @@ -485,7 +504,8 @@ void efi_timer_check(void) efi_status_t efi_set_timer(struct efi_event *event, enum efi_timer_delay type, uint64_t trigger_time) { - int i; + if (!efi_is_event(event)) + return EFI_INVALID_PARAMETER; /* * The parameter defines a multiple of 100ns. @@ -493,30 +513,25 @@ efi_status_t efi_set_timer(struct efi_event *event, enum efi_timer_delay type, */ do_div(trigger_time, 10); - for (i = 0; i < ARRAY_SIZE(efi_events); ++i) { - if (event != &efi_events[i]) - continue; + if (!(event->type & EVT_TIMER)) + return 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() + trigger_time; - break; - default: - return EFI_INVALID_PARAMETER; - } - event->trigger_type = type; - event->trigger_time = trigger_time; - event->is_signaled = false; - return EFI_SUCCESS; + 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() + trigger_time; + break; + default: + return EFI_INVALID_PARAMETER; } - return EFI_INVALID_PARAMETER; + event->trigger_type = type; + event->trigger_time = trigger_time; + event->is_signaled = false; + + return EFI_SUCCESS; } /* @@ -555,7 +570,7 @@ static efi_status_t EFIAPI efi_wait_for_event(unsigned long num_events, struct efi_event **event, size_t *index) { - int i, j; + int i; EFI_ENTRY("%ld, %p, %p", num_events, event, index); @@ -566,12 +581,8 @@ static efi_status_t EFIAPI efi_wait_for_event(unsigned long num_events, if (efi_tpl != TPL_APPLICATION) return EFI_EXIT(EFI_UNSUPPORTED); 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 (!efi_is_event(event[i])) + return EFI_EXIT(EFI_INVALID_PARAMETER); if (!event[i]->type || event[i]->type & EVT_NOTIFY_SIGNAL) return EFI_EXIT(EFI_INVALID_PARAMETER); if (!event[i]->is_signaled) @@ -614,19 +625,12 @@ out: */ 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; - if (event->is_signaled) - break; - event->is_signaled = true; - if (event->type & EVT_NOTIFY_SIGNAL) - efi_signal_event(event); - break; - } + if (!efi_is_event(event)) + return EFI_EXIT(EFI_INVALID_PARAMETER); + event->is_signaled = true; + if (event->type & EVT_NOTIFY_SIGNAL) + efi_signal_event(event); return EFI_EXIT(EFI_SUCCESS); } @@ -642,19 +646,10 @@ static efi_status_t EFIAPI efi_signal_event_ext(struct efi_event *event) */ static efi_status_t EFIAPI efi_close_event(struct efi_event *event) { - int i; - EFI_ENTRY("%p", event); - for (i = 0; i < ARRAY_SIZE(efi_events); ++i) { - if (event == &efi_events[i]) { - event->type = 0; - event->trigger_next = -1ULL; - event->is_queued = false; - event->is_signaled = false; - return EFI_EXIT(EFI_SUCCESS); - } - } - return EFI_EXIT(EFI_INVALID_PARAMETER); + list_del(&event->link); + free(event); + return EFI_EXIT(EFI_SUCCESS); } /* @@ -664,29 +659,37 @@ static efi_status_t EFIAPI efi_close_event(struct efi_event *event) * See the Unified Extensible Firmware Interface (UEFI) specification * for details. * - * If an event is not signaled yet the notification function is queued. + * - If Event is in the signaled state, it is cleared and EFI_SUCCESS + * is returned. + * + * - If Event is not in the signaled state and has no notification + * function, EFI_NOT_READY is returned. + * + * - If Event is not in the signaled state but does have a notification + * function, the notification function is queued at the event’s + * notification task priority level. If the execution of the + * notification function causes Event to be signaled, then the signaled + * state is cleared and EFI_SUCCESS is returned; if the Event is not + * signaled, then EFI_NOT_READY is returned. * * @event event to check * @return status code */ -static efi_status_t EFIAPI efi_check_event(struct efi_event *event) +/* + */ +static efi_status_t EFIAPI efi_check_event(struct efi_event *evt) { - int i; - - EFI_ENTRY("%p", event); + EFI_ENTRY("%p", evt); 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->is_signaled) - efi_signal_event(event); - if (event->is_signaled) - return EFI_EXIT(EFI_SUCCESS); - return EFI_EXIT(EFI_NOT_READY); + if (!efi_is_event(evt) || (evt->type & EVT_NOTIFY_SIGNAL)) + return EFI_EXIT(EFI_INVALID_PARAMETER); + if (!evt->is_signaled && evt->notify_function) + EFI_CALL_VOID(evt->notify_function(evt, evt->notify_context)); + if (evt->is_signaled) { + evt->is_signaled = true; + return EFI_EXIT(EFI_SUCCESS); } - return EFI_EXIT(EFI_INVALID_PARAMETER); + return EFI_EXIT(EFI_NOT_READY); } /* @@ -1440,15 +1443,15 @@ static void efi_exit_caches(void) static efi_status_t EFIAPI efi_exit_boot_services(void *image_handle, unsigned long map_key) { - int i; + struct efi_event *evt; EFI_ENTRY("%p, %ld", image_handle, map_key); /* Notify that ExitBootServices is invoked. */ - for (i = 0; i < ARRAY_SIZE(efi_events); ++i) { - if (efi_events[i].type != EVT_SIGNAL_EXIT_BOOT_SERVICES) + list_for_each_entry(evt, &efi_events, link) { + if (evt->type != EVT_SIGNAL_EXIT_BOOT_SERVICES) continue; - efi_signal_event(&efi_events[i]); + efi_signal_event(evt); } /* Make sure that notification functions are not called anymore */ efi_tpl = TPL_HIGH_LEVEL;