uboot/lib/efi_selftest/efi_selftest_events.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2/*
   3 * efi_selftest_events
   4 *
   5 * Copyright (c) 2017 Heinrich Schuchardt <xypron.glpk@gmx.de>
   6 *
   7 * This unit test uses timer events to check the implementation
   8 * of the following boottime services:
   9 * CreateEvent, CloseEvent, WaitForEvent, CheckEvent, SetTimer.
  10 */
  11
  12#include <efi_selftest.h>
  13
  14static struct efi_event *event_notify;
  15static struct efi_event *event_wait;
  16static unsigned int timer_ticks;
  17static struct efi_boot_services *boottime;
  18
  19/*
  20 * Notification function, increments the notification count if parameter
  21 * context is provided.
  22 *
  23 * @event       notified event
  24 * @context     pointer to the notification count
  25 */
  26static void EFIAPI notify(struct efi_event *event, void *context)
  27{
  28        unsigned int *count = context;
  29
  30        if (count)
  31                ++*count;
  32}
  33
  34/*
  35 * Setup unit test.
  36 *
  37 * Create two timer events.
  38 * One with EVT_NOTIFY_SIGNAL, the other with EVT_NOTIFY_WAIT.
  39 *
  40 * @handle:     handle of the loaded image
  41 * @systable:   system table
  42 * @return:     EFI_ST_SUCCESS for success
  43 */
  44static int setup(const efi_handle_t handle,
  45                 const struct efi_system_table *systable)
  46{
  47        efi_status_t ret;
  48
  49        boottime = systable->boottime;
  50
  51        ret = boottime->create_event(EVT_TIMER | EVT_NOTIFY_SIGNAL,
  52                                     TPL_CALLBACK, notify, (void *)&timer_ticks,
  53                                     &event_notify);
  54        if (ret != EFI_SUCCESS) {
  55                efi_st_error("could not create event\n");
  56                return EFI_ST_FAILURE;
  57        }
  58        ret = boottime->create_event(EVT_TIMER | EVT_NOTIFY_WAIT,
  59                                     TPL_CALLBACK, notify, NULL, &event_wait);
  60        if (ret != EFI_SUCCESS) {
  61                efi_st_error("could not create event\n");
  62                return EFI_ST_FAILURE;
  63        }
  64        return EFI_ST_SUCCESS;
  65}
  66
  67/*
  68 * Tear down unit test.
  69 *
  70 * Close the events created in setup.
  71 *
  72 * @return:     EFI_ST_SUCCESS for success
  73 */
  74static int teardown(void)
  75{
  76        efi_status_t ret;
  77
  78        if (event_notify) {
  79                ret = boottime->close_event(event_notify);
  80                event_notify = NULL;
  81                if (ret != EFI_SUCCESS) {
  82                        efi_st_error("could not close event\n");
  83                        return EFI_ST_FAILURE;
  84                }
  85        }
  86        if (event_wait) {
  87                ret = boottime->close_event(event_wait);
  88                event_wait = NULL;
  89                if (ret != EFI_SUCCESS) {
  90                        efi_st_error("could not close event\n");
  91                        return EFI_ST_FAILURE;
  92                }
  93        }
  94        return EFI_ST_SUCCESS;
  95}
  96
  97/*
  98 * Execute unit test.
  99 *
 100 * Run a 10 ms periodic timer and check that it is called 10 times
 101 * while waiting for 100 ms single shot timer.
 102 *
 103 * Run a 100 ms single shot timer and check that it is called once
 104 * while waiting for 100 ms periodic timer for two periods.
 105 *
 106 * @return:     EFI_ST_SUCCESS for success
 107 */
 108static int execute(void)
 109{
 110        efi_uintn_t index;
 111        efi_status_t ret;
 112
 113        /* Set 10 ms timer */
 114        timer_ticks = 0;
 115        ret = boottime->set_timer(event_notify, EFI_TIMER_PERIODIC, 100000);
 116        if (ret != EFI_SUCCESS) {
 117                efi_st_error("Could not set timer\n");
 118                return EFI_ST_FAILURE;
 119        }
 120        /* Set 100 ms timer */
 121        ret = boottime->set_timer(event_wait, EFI_TIMER_RELATIVE, 1000000);
 122        if (ret != EFI_SUCCESS) {
 123                efi_st_error("Could not set timer\n");
 124                return EFI_ST_FAILURE;
 125        }
 126
 127        /* Set some arbitrary non-zero value to make change detectable. */
 128        index = 5;
 129        ret = boottime->wait_for_event(1, &event_wait, &index);
 130        if (ret != EFI_SUCCESS) {
 131                efi_st_error("Could not wait for event\n");
 132                return EFI_ST_FAILURE;
 133        }
 134        ret = boottime->check_event(event_wait);
 135        if (ret != EFI_NOT_READY) {
 136                efi_st_error("Signaled state was not cleared.\n");
 137                efi_st_printf("ret = %u\n", (unsigned int)ret);
 138                return EFI_ST_FAILURE;
 139        }
 140        if (index != 0) {
 141                efi_st_error("WaitForEvent returned wrong index\n");
 142                return EFI_ST_FAILURE;
 143        }
 144        if (timer_ticks < 8 || timer_ticks > 12) {
 145                efi_st_printf("Notification count periodic: %u\n", timer_ticks);
 146                efi_st_error("Incorrect timing of events\n");
 147                return EFI_ST_FAILURE;
 148        }
 149        ret = boottime->set_timer(event_notify, EFI_TIMER_STOP, 0);
 150        if (ret != EFI_SUCCESS) {
 151                efi_st_error("Could not cancel timer\n");
 152                return EFI_ST_FAILURE;
 153        }
 154        /* Set 10 ms timer */
 155        timer_ticks = 0;
 156        ret = boottime->set_timer(event_notify, EFI_TIMER_RELATIVE, 100000);
 157        if (ret != EFI_SUCCESS) {
 158                efi_st_error("Could not set timer\n");
 159                return EFI_ST_FAILURE;
 160        }
 161        /* Set 100 ms timer */
 162        ret = boottime->set_timer(event_wait, EFI_TIMER_PERIODIC, 1000000);
 163        if (ret != EFI_SUCCESS) {
 164                efi_st_error("Could not set timer\n");
 165                return EFI_ST_FAILURE;
 166        }
 167        ret = boottime->wait_for_event(1, &event_wait, &index);
 168        if (ret != EFI_SUCCESS) {
 169                efi_st_error("Could not wait for event\n");
 170                return EFI_ST_FAILURE;
 171        }
 172        if (timer_ticks != 1) {
 173                efi_st_printf("Notification count single shot: %u\n",
 174                              timer_ticks);
 175                efi_st_error("Single shot timer failed\n");
 176                return EFI_ST_FAILURE;
 177        }
 178        ret = boottime->wait_for_event(1, &event_wait, &index);
 179        if (ret != EFI_SUCCESS) {
 180                efi_st_error("Could not wait for event\n");
 181                return EFI_ST_FAILURE;
 182        }
 183        if (timer_ticks != 1) {
 184                efi_st_printf("Notification count stopped timer: %u\n",
 185                              timer_ticks);
 186                efi_st_error("Stopped timer fired\n");
 187                return EFI_ST_FAILURE;
 188        }
 189        ret = boottime->set_timer(event_wait, EFI_TIMER_STOP, 0);
 190        if (ret != EFI_SUCCESS) {
 191                efi_st_error("Could not cancel timer\n");
 192                return EFI_ST_FAILURE;
 193        }
 194
 195        return EFI_ST_SUCCESS;
 196}
 197
 198EFI_UNIT_TEST(events) = {
 199        .name = "event services",
 200        .phase = EFI_EXECUTE_BEFORE_BOOTTIME_EXIT,
 201        .setup = setup,
 202        .execute = execute,
 203        .teardown = teardown,
 204};
 205