155714Skris// SPDX-License-Identifier: GPL-2.0+ 255714Skris/* 355714Skris * efi_selftest_event_groups 455714Skris * 555714Skris * Copyright (c) 2018 Heinrich Schuchardt <xypron.glpk@gmx.de> 655714Skris * 755714Skris * This test checks the notification of group events and the 855714Skris * following services: 955714Skris * CreateEventEx, CloseEvent, SignalEvent, CheckEvent. 1055714Skris */ 1155714Skris 1255714Skris#include <efi_selftest.h> 1355714Skris 1455714Skris#define GROUP_SIZE 16 1555714Skris 1655714Skrisstatic struct efi_boot_services *boottime; 1755714Skrisstatic efi_guid_t event_group = 1855714Skris EFI_GUID(0x2335905b, 0xc3b9, 0x4221, 0xa3, 0x71, 1955714Skris 0x0e, 0x5b, 0x45, 0xc0, 0x56, 0x91); 2055714Skris 2155714Skris/* 2255714Skris * Notification function, increments the notification count if parameter 2355714Skris * context is provided. 2455714Skris * 2555714Skris * @event notified event 2655714Skris * @context pointer to the notification count 2755714Skris */ 2855714Skrisstatic void EFIAPI notify(struct efi_event *event, void *context) 2955714Skris{ 3055714Skris unsigned int *count = context; 3155714Skris 3255714Skris if (count) 3355714Skris ++*count; 3455714Skris} 3555714Skris 3655714Skris/* 3755714Skris * Setup unit test. 3855714Skris * 3955714Skris * @handle: handle of the loaded image 4055714Skris * @systable: system table 4155714Skris * Return: EFI_ST_SUCCESS for success 4255714Skris */ 4355714Skrisstatic int setup(const efi_handle_t handle, 4455714Skris const struct efi_system_table *systable) 4555714Skris{ 4655714Skris boottime = systable->boottime; 4755714Skris 4855714Skris return EFI_ST_SUCCESS; 4955714Skris} 5055714Skris 5155714Skris/* 5255714Skris * Execute unit test. 5355714Skris * 5455714Skris * Create multiple events in an event group. Signal each event once and check 5555714Skris * that all events are notified once in each round. 5655714Skris * 5755714Skris * Return: EFI_ST_SUCCESS for success 5855714Skris */ 5955714Skrisstatic int execute(void) 6055714Skris{ 6155714Skris unsigned int counter[GROUP_SIZE] = {0}; 6255714Skris struct efi_event *events[GROUP_SIZE]; 6355714Skris size_t i, j; 6455714Skris efi_status_t ret; 6555714Skris 6655714Skris for (i = 0; i < GROUP_SIZE; ++i) { 6755714Skris ret = boottime->create_event_ex(0, TPL_NOTIFY, 6855714Skris notify, (void *)&counter[i], 6955714Skris &event_group, &events[i]); 7055714Skris if (ret != EFI_SUCCESS) { 7155714Skris efi_st_error("Failed to create event\n"); 7255714Skris return EFI_ST_FAILURE; 7355714Skris } 7455714Skris } 7555714Skris 7655714Skris for (i = 0; i < GROUP_SIZE; ++i) { 7755714Skris ret = boottime->signal_event(events[i]); 7855714Skris if (ret != EFI_SUCCESS) { 7955714Skris efi_st_error("Failed to signal event\n"); 8055714Skris return EFI_ST_FAILURE; 8155714Skris } 8255714Skris for (j = 0; j < GROUP_SIZE; ++j) { 8355714Skris if (counter[j] != 2 * i + 1) { 8455714Skris efi_st_printf("i %u, j %u, count %u\n", 8555714Skris (unsigned int)i, (unsigned int)j, 8655714Skris (unsigned int)counter[j]); 8755714Skris efi_st_error("Notification function was not called\n"); 8855714Skris return EFI_ST_FAILURE; 8955714Skris } 9055714Skris /* Clear signaled state */ 9155714Skris ret = boottime->check_event(events[j]); 9255714Skris if (ret != EFI_SUCCESS) { 9355714Skris efi_st_error("Event was not signaled\n"); 9455714Skris return EFI_ST_FAILURE; 9555714Skris } 9655714Skris if (counter[j] != 2 * i + 1) { 9755714Skris efi_st_printf("i %u, j %u, count %u\n", 9855714Skris (unsigned int)i, (unsigned int)j, 9955714Skris (unsigned int)counter[j]); 10055714Skris efi_st_error( 10155714Skris "Notification function was called\n"); 10255714Skris return EFI_ST_FAILURE; 10355714Skris } 10455714Skris /* Call notification function */ 10555714Skris ret = boottime->check_event(events[j]); 10655714Skris if (ret != EFI_NOT_READY) { 10755714Skris efi_st_error( 10855714Skris "Signaled state not cleared\n"); 10955714Skris return EFI_ST_FAILURE; 11055714Skris } 11155714Skris if (counter[j] != 2 * i + 2) { 11255714Skris efi_st_printf("i %u, j %u, count %u\n", 11355714Skris (unsigned int)i, (unsigned int)j, 11455714Skris (unsigned int)counter[j]); 11555714Skris efi_st_error( 11655714Skris "Notification function not called\n"); 11755714Skris return EFI_ST_FAILURE; 11855714Skris } 11955714Skris } 12055714Skris } 12155714Skris 12255714Skris for (i = 0; i < GROUP_SIZE; ++i) { 12355714Skris ret = boottime->close_event(events[i]); 12455714Skris if (ret != EFI_SUCCESS) { 12555714Skris efi_st_error("Failed to close event\n"); 12655714Skris return EFI_ST_FAILURE; 12755714Skris } 12855714Skris } 12955714Skris 13055714Skris return EFI_ST_SUCCESS; 13155714Skris} 13255714Skris 13355714SkrisEFI_UNIT_TEST(eventgoups) = { 13455714Skris .name = "event groups", 13555714Skris .phase = EFI_EXECUTE_BEFORE_BOOTTIME_EXIT, 13655714Skris .setup = setup, 13755714Skris .execute = execute, 13855714Skris}; 13955714Skris