uboot/lib/efi_selftest/efi_selftest_tpl.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 handling of
   8 * task priority levels.
   9 */
  10
  11#include <efi_selftest.h>
  12
  13static struct efi_event *event_notify;
  14static struct efi_event *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                                     &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_HIGH_LEVEL, notify, NULL, &event_wait);
  59        if (ret != EFI_SUCCESS) {
  60                efi_st_error("could not create event\n");
  61                return EFI_ST_FAILURE;
  62        }
  63        return EFI_ST_SUCCESS;
  64}
  65
  66/*
  67 * Tear down unit test.
  68 *
  69 * Close the events created in setup.
  70 *
  71 * @return:     EFI_ST_SUCCESS for success
  72 */
  73static int teardown(void)
  74{
  75        efi_status_t ret;
  76
  77        if (event_notify) {
  78                ret = boottime->close_event(event_notify);
  79                event_notify = NULL;
  80                if (ret != EFI_SUCCESS) {
  81                        efi_st_error("could not close event\n");
  82                        return EFI_ST_FAILURE;
  83                }
  84        }
  85        if (event_wait) {
  86                ret = boottime->close_event(event_wait);
  87                event_wait = NULL;
  88                if (ret != EFI_SUCCESS) {
  89                        efi_st_error("could not close event\n");
  90                        return EFI_ST_FAILURE;
  91                }
  92        }
  93        boottime->restore_tpl(TPL_APPLICATION);
  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 * Raise the TPL level to the level of the 10 ms timer and observe
 104 * that the notification function is not called again.
 105 *
 106 * Lower the TPL level and check that the queued notification
 107 * function is called.
 108 *
 109 * @return:     EFI_ST_SUCCESS for success
 110 */
 111static int execute(void)
 112{
 113        efi_uintn_t index;
 114        efi_status_t ret;
 115        efi_uintn_t old_tpl;
 116
 117        /* Set 10 ms timer */
 118        notification_count = 0;
 119        ret = boottime->set_timer(event_notify, EFI_TIMER_PERIODIC, 100000);
 120        if (ret != EFI_SUCCESS) {
 121                efi_st_error("Could not set timer\n");
 122                return EFI_ST_FAILURE;
 123        }
 124        /* Set 100 ms timer */
 125        ret = boottime->set_timer(event_wait, EFI_TIMER_RELATIVE, 1000000);
 126        if (ret != EFI_SUCCESS) {
 127                efi_st_error("Could not set timer\n");
 128                return EFI_ST_FAILURE;
 129        }
 130        index = 5;
 131        ret = boottime->wait_for_event(1, &event_wait, &index);
 132        if (ret != EFI_SUCCESS) {
 133                efi_st_error("Could not wait for event\n");
 134                return EFI_ST_FAILURE;
 135        }
 136        ret = boottime->check_event(event_wait);
 137        if (ret != EFI_NOT_READY) {
 138                efi_st_error("Signaled state was not cleared.\n");
 139                efi_st_printf("ret = %u\n", (unsigned int)ret);
 140                return EFI_ST_FAILURE;
 141        }
 142        if (index != 0) {
 143                efi_st_error("WaitForEvent returned wrong index\n");
 144                return EFI_ST_FAILURE;
 145        }
 146        if (notification_count < 8 || notification_count > 12) {
 147                efi_st_printf(
 148                    "Notification count with TPL level TPL_APPLICATION: %u\n",
 149                    notification_count);
 150                efi_st_error("Incorrect timing of events\n");
 151                return EFI_ST_FAILURE;
 152        }
 153        ret = boottime->set_timer(event_notify, EFI_TIMER_STOP, 0);
 154        if (index != 0) {
 155                efi_st_error("Could not cancel timer\n");
 156                return EFI_ST_FAILURE;
 157        }
 158        /* Raise TPL level */
 159        old_tpl = boottime->raise_tpl(TPL_CALLBACK);
 160        if (old_tpl != TPL_APPLICATION) {
 161                efi_st_error("Initial TPL level was not TPL_APPLICATION");
 162                return EFI_ST_FAILURE;
 163        }
 164        /* Set 10 ms timer */
 165        notification_count = 0;
 166        ret = boottime->set_timer(event_notify, EFI_TIMER_PERIODIC, 100000);
 167        if (index != 0) {
 168                efi_st_error("Could not set timer\n");
 169                return EFI_ST_FAILURE;
 170        }
 171        /* Set 100 ms timer */
 172        ret = boottime->set_timer(event_wait, EFI_TIMER_RELATIVE, 1000000);
 173        if (ret != EFI_SUCCESS) {
 174                efi_st_error("Could not set timer\n");
 175                return EFI_ST_FAILURE;
 176        }
 177        do {
 178                ret = boottime->check_event(event_wait);
 179        } while (ret == EFI_NOT_READY);
 180        if (ret != EFI_SUCCESS) {
 181                efi_st_error("Could not check event\n");
 182                return EFI_ST_FAILURE;
 183        }
 184        if (notification_count != 0) {
 185                efi_st_printf(
 186                        "Notification count with TPL level TPL_CALLBACK: %u\n",
 187                        notification_count);
 188                efi_st_error("Suppressed timer fired\n");
 189                return EFI_ST_FAILURE;
 190        }
 191        /* Set 1 ms timer */
 192        ret = boottime->set_timer(event_wait, EFI_TIMER_RELATIVE, 1000);
 193        if (ret != EFI_SUCCESS) {
 194                efi_st_error("Could not set timer\n");
 195                return EFI_ST_FAILURE;
 196        }
 197        /* Restore the old TPL level */
 198        boottime->restore_tpl(TPL_APPLICATION);
 199        ret = boottime->wait_for_event(1, &event_wait, &index);
 200        if (ret != EFI_SUCCESS) {
 201                efi_st_error("Could not wait for event\n");
 202                return EFI_ST_FAILURE;
 203        }
 204        if (notification_count < 1) {
 205                efi_st_printf(
 206                    "Notification count with TPL level TPL_APPLICATION: %u\n",
 207                    notification_count);
 208                efi_st_error("Queued timer event did not fire\n");
 209                return EFI_ST_FAILURE;
 210        }
 211        ret = boottime->set_timer(event_wait, EFI_TIMER_STOP, 0);
 212        if (ret != EFI_SUCCESS) {
 213                efi_st_error("Could not cancel timer\n");
 214                return EFI_ST_FAILURE;
 215        }
 216
 217        return EFI_ST_SUCCESS;
 218}
 219
 220EFI_UNIT_TEST(tpl) = {
 221        .name = "task priority levels",
 222        .phase = EFI_EXECUTE_BEFORE_BOOTTIME_EXIT,
 223        .setup = setup,
 224        .execute = execute,
 225        .teardown = teardown,
 226};
 227