From patchwork Tue Sep 12 16:35:33 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Rob Clark X-Patchwork-Id: 812967 X-Patchwork-Delegate: trini@ti.com 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="ay9Yg9B4"; dkim-atps=neutral Received: from lists.denx.de (dione.denx.de [81.169.180.215]) by ozlabs.org (Postfix) with ESMTP id 3xs9R81Z3Bz9s7g for ; Wed, 13 Sep 2017 02:35:48 +1000 (AEST) Received: by lists.denx.de (Postfix, from userid 105) id 2973EC21FE8; Tue, 12 Sep 2017 16:35:44 +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_DNSWL_NONE, 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 D84EFC21E39; Tue, 12 Sep 2017 16:35:40 +0000 (UTC) Received: by lists.denx.de (Postfix, from userid 105) id 24310C21E39; Tue, 12 Sep 2017 16:35:40 +0000 (UTC) Received: from mail-qk0-f193.google.com (mail-qk0-f193.google.com [209.85.220.193]) by lists.denx.de (Postfix) with ESMTPS id A0085C21D78 for ; Tue, 12 Sep 2017 16:35:39 +0000 (UTC) Received: by mail-qk0-f193.google.com with SMTP id o77so7495335qke.2 for ; Tue, 12 Sep 2017 09:35:39 -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:mime-version :content-transfer-encoding; bh=vy+LxKooAEsAARec017+tNMNGEBI2cCqijDYhHbZS7s=; b=ay9Yg9B4yjowzei2Ts3M0/SmurWpaS2rYhXSas0g4WZc78+HZCGUvfr801XF6Z7did rfFisL3FS7B78hO0HR1wg7iLF5LkOok254Pz40M7JmT/x3vLaZ/CJIkz7VtTA4RNp9N/ occvtvABTgO3LTI7HzT1Pi2cCLgMx8i0dmgRaJSG6Lc0RUwCxIgq4Ir//7SBJK/P8Gdn 6Q7+YlvstVEf+0jTDtuYPJk6XG17FTN8zE1lqMDJQ0/YiP1BxV/HZ3fVqaKZVfD4it+9 7imltclVn3ktx9xQyi11y/yo2XU1QtZ6tteO39M6Hv92qB4EF/3byNxRqIR6qPeiTaCm qAZQ== 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:mime-version :content-transfer-encoding; bh=vy+LxKooAEsAARec017+tNMNGEBI2cCqijDYhHbZS7s=; b=OqbUazL1U+TcSuHIaF7kR1j3d8usmTIq89lLHy4X41nyJjEe/JVy4yIbLamPcimi6G dtmIebnglEghKFoT5NrWSRwyrZ0Z1186Ek7Pavq0cosPMZYt+CagzxsQKCm58Bg3zQeN OGsA+ChqF7N1orkdQWXD1wuEI3739TTAQZQkh91bjRpa3GxNNM1Zez8uPd/Az5KUyXg4 XFOKY2mB/Xa6h81qIkCtw+bfWKMwwFoF3cJbPX9EHDunEiEBQlLFwie6dOG6ubErfhX7 FrzikXPnkw25tfBvlS3O7Ts5+JXOo9cUhcA6An9RLysvxNt47lnp/ssiLGGWc5KkuYdS iBEQ== X-Gm-Message-State: AHPjjUiOXduUYECpRZkGzWs+F/G5g5RHoaXSqxEghXJlRXvmtsjmv9Yu xwc205nRZ2iUJt2KCec= X-Google-Smtp-Source: AOwi7QBwpWCLytDXg1r2dNW6pe+vQ7lYrjDzIiO/nQYOu0kcCA2YMUKzjHxNdGkoDm1Aj+ktoiKtag== X-Received: by 10.55.116.134 with SMTP id p128mr19842112qkc.50.1505234138163; Tue, 12 Sep 2017 09:35:38 -0700 (PDT) Received: from localhost ([144.121.20.162]) by smtp.gmail.com with ESMTPSA id y18sm8058771qth.33.2017.09.12.09.35.36 (version=TLS1_2 cipher=ECDHE-RSA-CHACHA20-POLY1305 bits=256/256); Tue, 12 Sep 2017 09:35:36 -0700 (PDT) From: Rob Clark To: U-Boot Mailing List Date: Tue, 12 Sep 2017 12:35:33 -0400 Message-Id: <20170912163536.7349-1-robdclark@gmail.com> X-Mailer: git-send-email 2.13.5 MIME-Version: 1.0 Subject: [U-Boot] [PATCH] 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 --- include/efi_loader.h | 1 + lib/efi_loader/efi_boottime.c | 167 +++++++++++++++++++----------------------- 2 files changed, 78 insertions(+), 90 deletions(-) diff --git a/include/efi_loader.h b/include/efi_loader.h index 291ea86568..9dc1ea4b88 100644 --- a/include/efi_loader.h +++ b/include/efi_loader.h @@ -149,6 +149,7 @@ struct efi_event { u64 trigger_time; enum efi_timer_delay trigger_type; int signaled; + struct list_head link; }; diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c index 5db8ea9090..be3c34b9e0 100644 --- a/lib/efi_loader/efi_boottime.c +++ b/lib/efi_loader/efi_boottime.c @@ -255,11 +255,7 @@ static efi_status_t efi_create_handle(void **handle) return r; } -/* - * Our event capabilities are very limited. Only a small limited - * number of events is allowed to coexist. - */ -static struct efi_event efi_events[16]; +static LIST_HEAD(efi_events); efi_status_t efi_create_event(uint32_t type, UINTN notify_tpl, void (EFIAPI *notify_function) ( @@ -267,7 +263,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; @@ -279,20 +275,23 @@ 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].signaled = 0; - *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->signaled = 0; + + list_add_tail(&evt->link, &efi_events); + + *event = evt; + + return EFI_SUCCESS; } static efi_status_t EFIAPI efi_create_event_ext( @@ -315,21 +314,24 @@ 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 || - !(efi_events[i].type & EVT_TIMER) || - efi_events[i].trigger_type == EFI_TIMER_STOP || - now < efi_events[i].trigger_next) + /* + * TODO perhaps optimize a bit and track the time of next + * timer expiration? + */ + list_for_each_entry(evt, &efi_events, link) { + if (!evt->type || !(evt->type & EVT_TIMER) || + evt->trigger_type == EFI_TIMER_STOP || + now < evt->trigger_next) continue; - if (efi_events[i].trigger_type == EFI_TIMER_PERIODIC) { - efi_events[i].trigger_next += - efi_events[i].trigger_time; - efi_events[i].signaled = 0; + if (evt->trigger_type == EFI_TIMER_PERIODIC) { + evt->trigger_next += + evt->trigger_time; + evt->signaled = 0; } - efi_signal_event(&efi_events[i]); + efi_signal_event(evt); } WATCHDOG_RESET(); } @@ -337,37 +339,32 @@ 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; - /* * The parameter defines a multiple of 100ns. * We use multiples of 1000ns. So divide by 10. */ trigger_time = efi_div10(trigger_time); - 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 = + 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; - return EFI_SUCCESS; + break; + default: + return EFI_INVALID_PARAMETER; } - return EFI_INVALID_PARAMETER; + + event->trigger_type = type; + event->trigger_time = trigger_time; + + return EFI_SUCCESS; } static efi_status_t EFIAPI efi_set_timer_ext(struct efi_event *event, @@ -382,7 +379,7 @@ static efi_status_t EFIAPI efi_wait_for_event(unsigned long num_events, struct efi_event **event, unsigned long *index) { - int i, j; + int i; EFI_ENTRY("%ld, %p, %p", num_events, event, index); @@ -390,12 +387,6 @@ static efi_status_t EFIAPI efi_wait_for_event(unsigned long num_events, 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); } @@ -424,50 +415,46 @@ 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; - efi_signal_event(event); - break; - } + efi_signal_event(event); return EFI_EXIT(EFI_SUCCESS); } 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->signaled = 0; - return EFI_EXIT(EFI_SUCCESS); - } - } - return EFI_EXIT(EFI_INVALID_PARAMETER); + list_del(&event->link); + free(event); + return EFI_EXIT(EFI_SUCCESS); } +/* + * - 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. + */ static efi_status_t EFIAPI efi_check_event(struct efi_event *event) { - int i; - EFI_ENTRY("%p", event); 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); + if (event->type & EVT_NOTIFY_SIGNAL) + return EFI_EXIT(EFI_INVALID_PARAMETER); + if (!event->signaled && event->notify_function) + EFI_CALL(event->notify_function(event, event->notify_context)); + if (event->signaled) { + event->signaled = 0; + return EFI_EXIT(EFI_SUCCESS); } - return EFI_EXIT(EFI_INVALID_PARAMETER); + return EFI_EXIT(EFI_NOT_READY); } static efi_status_t EFIAPI efi_install_protocol_interface(void **handle,