uboot/lib/efi_selftest/efi_selftest_tpl.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2/*
   3 * efi_selftest_tpl
   4 *
   5 * Copyright (c) 2017 Heinrich Schuchardt <xypron.glpk@gmx.de>
   6 *
   7 * This unit test uses timer events to check the handling of
   8 * task priority levels.
   9 */
  10
  11#include <efi_selftest.h>
  12
  13static struct efi_event *efi_st_event_notify;
  14static struct efi_event *efi_st_event_wait;
  15static unsigned int notification_count;
  16static struct efi_boot_services *boottime;
  17
  18/*
  19 * Notification function, increments the notification count.
  20 *
  21 * @event       notified event
  22 * @context     pointer to the notification count
  23 */
  24static void EFIAPI notify(struct efi_event *event, void *context)
  25{
  26        unsigned int *count = context;
  27
  28        if (count)
  29                ++*count;
  30}
  31
  32/*
  33 * Setup unit test.
  34 *
  35 * Create two timer events.
  36 * One with EVT_NOTIFY_SIGNAL, the other with EVT_NOTIFY_WAIT.
  37 *
  38 * @handle:     handle of the loaded image
  39 * @systable:   system table
  40 * Return:      EFI_ST_SUCCESS for success
  41 */
  42static int setup(const efi_handle_t handle,
  43                 const struct efi_system_table *systable)
  44{
  45        efi_status_t ret;
  46
  47        boottime = systable->boottime;
  48
  49        ret = boottime->create_event(EVT_TIMER | EVT_NOTIFY_SIGNAL,
  50                                     TPL_CALLBACK, notify,
  51                                     (void *)&notification_count,
  52                                     &efi_st_event_notify);
  53        if (ret != EFI_SUCCESS) {
  54                efi_st_error("could not create event\n");
  55                return EFI_ST_FAILURE;
  56        }
  57        ret = boottime->create_event(EVT_TIMER | EVT_NOTIFY_WAIT,
  58                                     TPL_NOTIFY, notify, NULL,
  59                                     &efi_st_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 (efi_st_event_notify) {
  79                ret = boottime->close_event(efi_st_event_notify);
  80                efi_st_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 (efi_st_event_wait) {
  87                ret = boottime->close_event(efi_st_event_wait);
  88                efi_st_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        boottime->restore_tpl(TPL_APPLICATION);
  95        return EFI_ST_SUCCESS;
  96}
  97
  98/*
  99 * Execute unit test.
 100 *
 101 * Run a 10 ms periodic timer and check that it is called 10 times
 102 * while waiting for 100 ms single shot timer.
 103 *
 104 * Raise the TPL level to the level of the 10 ms timer and observe
 105 * that the notification function is not called again.
 106 *
 107 * Lower the TPL level and check that the queued notification
 108 * function is called.
 109 *
 110 * Return:      EFI_ST_SUCCESS for success
 111 */
 112static int execute(void)
 113{
 114        efi_uintn_t index;
 115        efi_status_t ret;
 116        efi_uintn_t old_tpl;
 117
 118        /* Set 10 ms timer */
 119        notification_count = 0;
 120        ret = boottime->set_timer(efi_st_event_notify, EFI_TIMER_PERIODIC,
 121                                  100000);
 122        if (ret != EFI_SUCCESS) {
 123                efi_st_error("Could not set timer\n");
 124                return EFI_ST_FAILURE;
 125        }
 126        /* Set 100 ms timer */
 127        ret = boottime->set_timer(efi_st_event_wait, EFI_TIMER_RELATIVE,
 128                                  1000000);
 129        if (ret != EFI_SUCCESS) {
 130                efi_st_error("Could not set timer\n");
 131                return EFI_ST_FAILURE;
 132        }
 133        index = 5;
 134        ret = boottime->wait_for_event(1, &efi_st_event_wait, &index);
 135        if (ret != EFI_SUCCESS) {
 136                efi_st_error("Could not wait for event\n");
 137                return EFI_ST_FAILURE;
 138        }
 139        ret = boottime->check_event(efi_st_event_wait);
 140        if (ret != EFI_NOT_READY) {
 141                efi_st_error("Signaled state was not cleared.\n");
 142                efi_st_printf("ret = %u\n", (unsigned int)ret);
 143                return EFI_ST_FAILURE;
 144        }
 145        if (index != 0) {
 146                efi_st_error("WaitForEvent returned wrong index\n");
 147                return EFI_ST_FAILURE;
 148        }
 149        if (notification_count < 8 || notification_count > 12) {
 150                efi_st_printf(
 151                    "Notification count with TPL level TPL_APPLICATION: %u\n",
 152                    notification_count);
 153                efi_st_error("Incorrect timing of events\n");
 154                return EFI_ST_FAILURE;
 155        }
 156        ret = boottime->set_timer(efi_st_event_notify, EFI_TIMER_STOP, 0);
 157        if (ret != EFI_SUCCESS) {
 158                efi_st_error("Could not cancel timer\n");
 159                return EFI_ST_FAILURE;
 160        }
 161        /* Raise TPL level */
 162        old_tpl = boottime->raise_tpl(TPL_CALLBACK);
 163        if (old_tpl != TPL_APPLICATION) {
 164                efi_st_error("Initial TPL level was not TPL_APPLICATION");
 165                return EFI_ST_FAILURE;
 166        }
 167        /* Set 10 ms timer */
 168        notification_count = 0;
 169        ret = boottime->set_timer(efi_st_event_notify, EFI_TIMER_PERIODIC,
 170                                  100000);
 171        if (ret != EFI_SUCCESS) {
 172                efi_st_error("Could not set timer\n");
 173                return EFI_ST_FAILURE;
 174        }
 175        /* Set 100 ms timer */
 176        ret = boottime->set_timer(efi_st_event_wait, EFI_TIMER_RELATIVE,
 177                                  1000000);
 178        if (ret != EFI_SUCCESS) {
 179                efi_st_error("Could not set timer\n");
 180                return EFI_ST_FAILURE;
 181        }
 182        do {
 183                ret = boottime->check_event(efi_st_event_wait);
 184        } while (ret == EFI_NOT_READY);
 185        if (ret != EFI_SUCCESS) {
 186                efi_st_error("Could not check event\n");
 187                return EFI_ST_FAILURE;
 188        }
 189        if (notification_count != 0) {
 190                efi_st_printf(
 191                        "Notification count with TPL level TPL_CALLBACK: %u\n",
 192                        notification_count);
 193                efi_st_error("Suppressed timer fired\n");
 194                return EFI_ST_FAILURE;
 195        }
 196        /* Set 1 ms timer */
 197        ret = boottime->set_timer(efi_st_event_wait, EFI_TIMER_RELATIVE, 1000);
 198        if (ret != EFI_SUCCESS) {
 199                efi_st_error("Could not set timer\n");
 200                return EFI_ST_FAILURE;
 201        }
 202        /* Restore the old TPL level */
 203        boottime->restore_tpl(TPL_APPLICATION);
 204        ret = boottime->wait_for_event(1, &efi_st_event_wait, &index);
 205        if (ret != EFI_SUCCESS) {
 206                efi_st_error("Could not wait for event\n");
 207                return EFI_ST_FAILURE;
 208        }
 209        if (notification_count < 1) {
 210                efi_st_printf(
 211                    "Notification count with TPL level TPL_APPLICATION: %u\n",
 212                    notification_count);
 213                efi_st_error("Queued timer event did not fire\n");
 214                return EFI_ST_FAILURE;
 215        }
 216        ret = boottime->set_timer(efi_st_event_wait, EFI_TIMER_STOP, 0);
 217        if (ret != EFI_SUCCESS) {
 218                efi_st_error("Could not cancel timer\n");
 219                return EFI_ST_FAILURE;
 220        }
 221
 222        return EFI_ST_SUCCESS;
 223}
 224
 225EFI_UNIT_TEST(tpl) = {
 226        .name = "task priority levels",
 227        .phase = EFI_EXECUTE_BEFORE_BOOTTIME_EXIT,
 228        .setup = setup,
 229        .execute = execute,
 230        .teardown = teardown,
 231};
 232