1 // SPDX-License-Identifier: GPL-2.0+ 2 /* 3 * efi_selftest_event_groups 4 * 5 * Copyright (c) 2018 Heinrich Schuchardt <xypron.glpk@gmx.de> 6 * 7 * This test checks the notification of group events and the 8 * following services: 9 * CreateEventEx, CloseEvent, SignalEvent, CheckEvent. 10 */ 11 12 #include <efi_selftest.h> 13 14 #define GROUP_SIZE 16 15 16 static struct efi_boot_services *boottime; 17 static efi_guid_t event_group = 18 EFI_GUID(0x2335905b, 0xc3b9, 0x4221, 0xa3, 0x71, 19 0x0e, 0x5b, 0x45, 0xc0, 0x56, 0x91); 20 21 /* 22 * Notification function, increments the notification count if parameter 23 * context is provided. 24 * 25 * @event notified event 26 * @context pointer to the notification count 27 */ 28 static void EFIAPI notify(struct efi_event *event, void *context) 29 { 30 unsigned int *count = context; 31 32 if (count) 33 ++*count; 34 } 35 36 /* 37 * Setup unit test. 38 * 39 * @handle: handle of the loaded image 40 * @systable: system table 41 * @return: EFI_ST_SUCCESS for success 42 */ 43 static int setup(const efi_handle_t handle, 44 const struct efi_system_table *systable) 45 { 46 boottime = systable->boottime; 47 48 return EFI_ST_SUCCESS; 49 } 50 51 /* 52 * Execute unit test. 53 * 54 * Create multiple events in an event group. Signal each event once and check 55 * that all events are notified once in each round. 56 * 57 * @return: EFI_ST_SUCCESS for success 58 */ 59 static int execute(void) 60 { 61 unsigned int counter[GROUP_SIZE] = {0}; 62 struct efi_event *events[GROUP_SIZE]; 63 size_t i, j; 64 efi_status_t ret; 65 66 for (i = 0; i < GROUP_SIZE; ++i) { 67 ret = boottime->create_event_ex(0, TPL_NOTIFY, 68 notify, (void *)&counter[i], 69 &event_group, &events[i]); 70 if (ret != EFI_SUCCESS) { 71 efi_st_error("Failed to create event\n"); 72 return EFI_ST_FAILURE; 73 } 74 } 75 76 for (i = 0; i < GROUP_SIZE; ++i) { 77 ret = boottime->signal_event(events[i]); 78 if (ret != EFI_SUCCESS) { 79 efi_st_error("Failed to signal event\n"); 80 return EFI_ST_FAILURE; 81 } 82 for (j = 0; j < GROUP_SIZE; ++j) { 83 if (counter[j] != i) { 84 efi_st_printf("i %u, j %u, count %u\n", 85 (unsigned int)i, (unsigned int)j, 86 (unsigned int)counter[j]); 87 efi_st_error( 88 "Notification function was called\n"); 89 return EFI_ST_FAILURE; 90 } 91 /* Clear signaled state */ 92 ret = boottime->check_event(events[j]); 93 if (ret != EFI_SUCCESS) { 94 efi_st_error("Event was not signaled\n"); 95 return EFI_ST_FAILURE; 96 } 97 if (counter[j] != i) { 98 efi_st_printf("i %u, j %u, count %u\n", 99 (unsigned int)i, (unsigned int)j, 100 (unsigned int)counter[j]); 101 efi_st_error( 102 "Notification function was called\n"); 103 return EFI_ST_FAILURE; 104 } 105 /* Call notification function */ 106 ret = boottime->check_event(events[j]); 107 if (ret != EFI_NOT_READY) { 108 efi_st_error( 109 "Signaled state not cleared\n"); 110 return EFI_ST_FAILURE; 111 } 112 if (counter[j] != i + 1) { 113 efi_st_printf("i %u, j %u, count %u\n", 114 (unsigned int)i, (unsigned int)j, 115 (unsigned int)counter[j]); 116 efi_st_error( 117 "Notification function not called\n"); 118 return EFI_ST_FAILURE; 119 } 120 } 121 } 122 123 for (i = 0; i < GROUP_SIZE; ++i) { 124 ret = boottime->close_event(events[i]); 125 if (ret != EFI_SUCCESS) { 126 efi_st_error("Failed to close event\n"); 127 return EFI_ST_FAILURE; 128 } 129 } 130 131 return EFI_ST_SUCCESS; 132 } 133 134 EFI_UNIT_TEST(eventgoups) = { 135 .name = "event groups", 136 .phase = EFI_EXECUTE_BEFORE_BOOTTIME_EXIT, 137 .setup = setup, 138 .execute = execute, 139 }; 140