diff options
| author | kx <kx@radix.pro> | 2024-06-04 06:43:08 +0300 |
|---|---|---|
| committer | kx <kx@radix.pro> | 2024-06-04 06:43:08 +0300 |
| commit | 7e2ccccace24636f29ddc210b94606abd4c7e42b (patch) | |
| tree | 545d43ea12671048956cafeb12303e84d601e571 /MdeModulePkg/Core/Dxe/Event/Event.c | |
| parent | 27b044605cd5f6b33a3d231576003850b3fe305b (diff) | |
| download | edk2-trunk.tar.xz | |
Renormalized end-of-lines from master@27b044605cd5f6b33a3d231576003850b3fe305btrunk
Diffstat (limited to 'MdeModulePkg/Core/Dxe/Event/Event.c')
| -rw-r--r-- | MdeModulePkg/Core/Dxe/Event/Event.c | 1520 |
1 files changed, 760 insertions, 760 deletions
diff --git a/MdeModulePkg/Core/Dxe/Event/Event.c b/MdeModulePkg/Core/Dxe/Event/Event.c index dc82abb021..21f562ea95 100644 --- a/MdeModulePkg/Core/Dxe/Event/Event.c +++ b/MdeModulePkg/Core/Dxe/Event/Event.c @@ -1,760 +1,760 @@ -/** @file
- UEFI Event support functions implemented in this file.
-
-Copyright (c) 2006 - 2017, Intel Corporation. All rights reserved.<BR>
-(C) Copyright 2015 Hewlett Packard Enterprise Development LP<BR>
-SPDX-License-Identifier: BSD-2-Clause-Patent
-
-**/
-
-#include "DxeMain.h"
-#include "Event.h"
-
-///
-/// gEfiCurrentTpl - Current Task priority level
-///
-EFI_TPL gEfiCurrentTpl = TPL_APPLICATION;
-
-///
-/// gEventQueueLock - Protects the event queues
-///
-EFI_LOCK gEventQueueLock = EFI_INITIALIZE_LOCK_VARIABLE (TPL_HIGH_LEVEL);
-
-///
-/// gEventQueue - A list of event's to notify for each priority level
-///
-LIST_ENTRY gEventQueue[TPL_HIGH_LEVEL + 1];
-
-///
-/// gEventPending - A bitmask of the EventQueues that are pending
-///
-UINTN gEventPending = 0;
-
-///
-/// gEventSignalQueue - A list of events to signal based on EventGroup type
-///
-LIST_ENTRY gEventSignalQueue = INITIALIZE_LIST_HEAD_VARIABLE (gEventSignalQueue);
-
-///
-/// Enumerate the valid types
-///
-UINT32 mEventTable[] = {
- ///
- /// 0x80000200 Timer event with a notification function that is
- /// queue when the event is signaled with SignalEvent()
- ///
- EVT_TIMER | EVT_NOTIFY_SIGNAL,
- ///
- /// 0x80000000 Timer event without a notification function. It can be
- /// signaled with SignalEvent() and checked with CheckEvent() or WaitForEvent().
- ///
- EVT_TIMER,
- ///
- /// 0x00000100 Generic event with a notification function that
- /// can be waited on with CheckEvent() or WaitForEvent()
- ///
- EVT_NOTIFY_WAIT,
- ///
- /// 0x00000200 Generic event with a notification function that
- /// is queue when the event is signaled with SignalEvent()
- ///
- EVT_NOTIFY_SIGNAL,
- ///
- /// 0x00000201 ExitBootServicesEvent.
- ///
- EVT_SIGNAL_EXIT_BOOT_SERVICES,
- ///
- /// 0x60000202 SetVirtualAddressMapEvent.
- ///
- EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE,
-
- ///
- /// 0x00000000 Generic event without a notification function.
- /// It can be signaled with SignalEvent() and checked with CheckEvent()
- /// or WaitForEvent().
- ///
- 0x00000000,
- ///
- /// 0x80000100 Timer event with a notification function that can be
- /// waited on with CheckEvent() or WaitForEvent()
- ///
- EVT_TIMER | EVT_NOTIFY_WAIT,
-};
-
-///
-/// gIdleLoopEvent - Event which is signalled when the core is idle
-///
-EFI_EVENT gIdleLoopEvent = NULL;
-
-/**
- Enter critical section by acquiring the lock on gEventQueueLock.
-
-**/
-VOID
-CoreAcquireEventLock (
- VOID
- )
-{
- CoreAcquireLock (&gEventQueueLock);
-}
-
-/**
- Exit critical section by releasing the lock on gEventQueueLock.
-
-**/
-VOID
-CoreReleaseEventLock (
- VOID
- )
-{
- CoreReleaseLock (&gEventQueueLock);
-}
-
-/**
- Initializes "event" support.
-
- @retval EFI_SUCCESS Always return success
-
-**/
-EFI_STATUS
-CoreInitializeEventServices (
- VOID
- )
-{
- UINTN Index;
-
- for (Index = 0; Index <= TPL_HIGH_LEVEL; Index++) {
- InitializeListHead (&gEventQueue[Index]);
- }
-
- CoreInitializeTimer ();
-
- CoreCreateEventEx (
- EVT_NOTIFY_SIGNAL,
- TPL_NOTIFY,
- EfiEventEmptyFunction,
- NULL,
- &gIdleLoopEventGuid,
- &gIdleLoopEvent
- );
-
- return EFI_SUCCESS;
-}
-
-/**
- Dispatches all pending events.
-
- @param Priority The task priority level of event notifications
- to dispatch
-
-**/
-VOID
-CoreDispatchEventNotifies (
- IN EFI_TPL Priority
- )
-{
- IEVENT *Event;
- LIST_ENTRY *Head;
-
- CoreAcquireEventLock ();
- ASSERT (gEventQueueLock.OwnerTpl == Priority);
- Head = &gEventQueue[Priority];
-
- //
- // Dispatch all the pending notifications
- //
- while (!IsListEmpty (Head)) {
- Event = CR (Head->ForwardLink, IEVENT, NotifyLink, EVENT_SIGNATURE);
- RemoveEntryList (&Event->NotifyLink);
-
- Event->NotifyLink.ForwardLink = NULL;
-
- //
- // Only clear the SIGNAL status if it is a SIGNAL type event.
- // WAIT type events are only cleared in CheckEvent()
- //
- if ((Event->Type & EVT_NOTIFY_SIGNAL) != 0) {
- Event->SignalCount = 0;
- }
-
- CoreReleaseEventLock ();
-
- //
- // Notify this event
- //
- ASSERT (Event->NotifyFunction != NULL);
- Event->NotifyFunction (Event, Event->NotifyContext);
-
- //
- // Check for next pending event
- //
- CoreAcquireEventLock ();
- }
-
- gEventPending &= ~(UINTN)(1 << Priority);
- CoreReleaseEventLock ();
-}
-
-/**
- Queues the event's notification function to fire.
-
- @param Event The Event to notify
-
-**/
-VOID
-CoreNotifyEvent (
- IN IEVENT *Event
- )
-{
- //
- // Event database must be locked
- //
- ASSERT_LOCKED (&gEventQueueLock);
-
- //
- // If the event is queued somewhere, remove it
- //
-
- if (Event->NotifyLink.ForwardLink != NULL) {
- RemoveEntryList (&Event->NotifyLink);
- Event->NotifyLink.ForwardLink = NULL;
- }
-
- //
- // Queue the event to the pending notification list
- //
-
- InsertTailList (&gEventQueue[Event->NotifyTpl], &Event->NotifyLink);
- gEventPending |= (UINTN)(1 << Event->NotifyTpl);
-}
-
-/**
- Signals all events in the EventGroup.
-
- @param EventGroup The list to signal
-
-**/
-VOID
-CoreNotifySignalList (
- IN EFI_GUID *EventGroup
- )
-{
- LIST_ENTRY *Link;
- LIST_ENTRY *Head;
- IEVENT *Event;
-
- CoreAcquireEventLock ();
-
- Head = &gEventSignalQueue;
- for (Link = Head->ForwardLink; Link != Head; Link = Link->ForwardLink) {
- Event = CR (Link, IEVENT, SignalLink, EVENT_SIGNATURE);
- if (CompareGuid (&Event->EventGroup, EventGroup)) {
- CoreNotifyEvent (Event);
- }
- }
-
- CoreReleaseEventLock ();
-}
-
-/**
- Creates an event.
-
- @param Type The type of event to create and its mode and
- attributes
- @param NotifyTpl The task priority level of event notifications
- @param NotifyFunction Pointer to the events notification function
- @param NotifyContext Pointer to the notification functions context;
- corresponds to parameter "Context" in the
- notification function
- @param Event Pointer to the newly created event if the call
- succeeds; undefined otherwise
-
- @retval EFI_SUCCESS The event structure was created
- @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value
- @retval EFI_OUT_OF_RESOURCES The event could not be allocated
-
-**/
-EFI_STATUS
-EFIAPI
-CoreCreateEvent (
- IN UINT32 Type,
- IN EFI_TPL NotifyTpl,
- IN EFI_EVENT_NOTIFY NotifyFunction OPTIONAL,
- IN VOID *NotifyContext OPTIONAL,
- OUT EFI_EVENT *Event
- )
-{
- return CoreCreateEventEx (Type, NotifyTpl, NotifyFunction, NotifyContext, NULL, Event);
-}
-
-/**
- Creates an event in a group.
-
- @param Type The type of event to create and its mode and
- attributes
- @param NotifyTpl The task priority level of event notifications
- @param NotifyFunction Pointer to the events notification function
- @param NotifyContext Pointer to the notification functions context;
- corresponds to parameter "Context" in the
- notification function
- @param EventGroup GUID for EventGroup if NULL act the same as
- gBS->CreateEvent().
- @param Event Pointer to the newly created event if the call
- succeeds; undefined otherwise
-
- @retval EFI_SUCCESS The event structure was created
- @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value
- @retval EFI_OUT_OF_RESOURCES The event could not be allocated
-
-**/
-EFI_STATUS
-EFIAPI
-CoreCreateEventEx (
- IN UINT32 Type,
- IN EFI_TPL NotifyTpl,
- IN EFI_EVENT_NOTIFY NotifyFunction OPTIONAL,
- IN CONST VOID *NotifyContext OPTIONAL,
- IN CONST EFI_GUID *EventGroup OPTIONAL,
- OUT EFI_EVENT *Event
- )
-{
- //
- // If it's a notify type of event, check for invalid NotifyTpl
- //
- if ((Type & (EVT_NOTIFY_WAIT | EVT_NOTIFY_SIGNAL)) != 0) {
- if ((NotifyTpl != TPL_APPLICATION) &&
- (NotifyTpl != TPL_CALLBACK) &&
- (NotifyTpl != TPL_NOTIFY))
- {
- return EFI_INVALID_PARAMETER;
- }
- }
-
- return CoreCreateEventInternal (Type, NotifyTpl, NotifyFunction, NotifyContext, EventGroup, Event);
-}
-
-/**
- Creates a general-purpose event structure
-
- @param Type The type of event to create and its mode and
- attributes
- @param NotifyTpl The task priority level of event notifications
- @param NotifyFunction Pointer to the events notification function
- @param NotifyContext Pointer to the notification functions context;
- corresponds to parameter "Context" in the
- notification function
- @param EventGroup GUID for EventGroup if NULL act the same as
- gBS->CreateEvent().
- @param Event Pointer to the newly created event if the call
- succeeds; undefined otherwise
-
- @retval EFI_SUCCESS The event structure was created
- @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value
- @retval EFI_OUT_OF_RESOURCES The event could not be allocated
-
-**/
-EFI_STATUS
-EFIAPI
-CoreCreateEventInternal (
- IN UINT32 Type,
- IN EFI_TPL NotifyTpl,
- IN EFI_EVENT_NOTIFY NotifyFunction OPTIONAL,
- IN CONST VOID *NotifyContext OPTIONAL,
- IN CONST EFI_GUID *EventGroup OPTIONAL,
- OUT EFI_EVENT *Event
- )
-{
- EFI_STATUS Status;
- IEVENT *IEvent;
- INTN Index;
-
- if (Event == NULL) {
- return EFI_INVALID_PARAMETER;
- }
-
- //
- // Check to make sure no reserved flags are set
- //
- Status = EFI_INVALID_PARAMETER;
- for (Index = 0; Index < (sizeof (mEventTable) / sizeof (UINT32)); Index++) {
- if (Type == mEventTable[Index]) {
- Status = EFI_SUCCESS;
- break;
- }
- }
-
- if (EFI_ERROR (Status)) {
- return EFI_INVALID_PARAMETER;
- }
-
- //
- // Convert Event type for pre-defined Event groups
- //
- if (EventGroup != NULL) {
- //
- // For event group, type EVT_SIGNAL_EXIT_BOOT_SERVICES and EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE
- // are not valid
- //
- if ((Type == EVT_SIGNAL_EXIT_BOOT_SERVICES) || (Type == EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE)) {
- return EFI_INVALID_PARAMETER;
- }
-
- if (CompareGuid (EventGroup, &gEfiEventExitBootServicesGuid)) {
- Type = EVT_SIGNAL_EXIT_BOOT_SERVICES;
- } else if (CompareGuid (EventGroup, &gEfiEventVirtualAddressChangeGuid)) {
- Type = EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE;
- }
- } else {
- //
- // Convert EFI 1.10 Events to their UEFI 2.0 CreateEventEx mapping
- //
- if (Type == EVT_SIGNAL_EXIT_BOOT_SERVICES) {
- EventGroup = &gEfiEventExitBootServicesGuid;
- } else if (Type == EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE) {
- EventGroup = &gEfiEventVirtualAddressChangeGuid;
- }
- }
-
- //
- // If it's a notify type of event, check its parameters
- //
- if ((Type & (EVT_NOTIFY_WAIT | EVT_NOTIFY_SIGNAL)) != 0) {
- //
- // Check for an invalid NotifyFunction or NotifyTpl
- //
- if ((NotifyFunction == NULL) ||
- (NotifyTpl <= TPL_APPLICATION) ||
- (NotifyTpl >= TPL_HIGH_LEVEL))
- {
- return EFI_INVALID_PARAMETER;
- }
- } else {
- //
- // No notification needed, zero ignored values
- //
- NotifyTpl = 0;
- NotifyFunction = NULL;
- NotifyContext = NULL;
- }
-
- //
- // Allocate and initialize a new event structure.
- //
- if ((Type & EVT_RUNTIME) != 0) {
- IEvent = AllocateRuntimeZeroPool (sizeof (IEVENT));
- } else {
- IEvent = AllocateZeroPool (sizeof (IEVENT));
- }
-
- if (IEvent == NULL) {
- return EFI_OUT_OF_RESOURCES;
- }
-
- IEvent->Signature = EVENT_SIGNATURE;
- IEvent->Type = Type;
-
- IEvent->NotifyTpl = NotifyTpl;
- IEvent->NotifyFunction = NotifyFunction;
- IEvent->NotifyContext = (VOID *)NotifyContext;
- if (EventGroup != NULL) {
- CopyGuid (&IEvent->EventGroup, EventGroup);
- IEvent->ExFlag |= EVT_EXFLAG_EVENT_GROUP;
- }
-
- *Event = IEvent;
-
- if ((Type & EVT_RUNTIME) != 0) {
- //
- // Keep a list of all RT events so we can tell the RT AP.
- //
- IEvent->RuntimeData.Type = Type;
- IEvent->RuntimeData.NotifyTpl = NotifyTpl;
- IEvent->RuntimeData.NotifyFunction = NotifyFunction;
- IEvent->RuntimeData.NotifyContext = (VOID *)NotifyContext;
- //
- // Work around the bug in the Platform Init specification (v1.7), reported
- // as Mantis#2017: "EFI_RUNTIME_EVENT_ENTRY.Event" should have type
- // EFI_EVENT, not (EFI_EVENT*). The PI spec documents the field correctly
- // as "The EFI_EVENT returned by CreateEvent()", but the type of the field
- // doesn't match the natural language description. Therefore we need an
- // explicit cast here.
- //
- IEvent->RuntimeData.Event = (EFI_EVENT *)IEvent;
- InsertTailList (&gRuntime->EventHead, &IEvent->RuntimeData.Link);
- }
-
- CoreAcquireEventLock ();
-
- if ((Type & EVT_NOTIFY_SIGNAL) != 0x00000000) {
- //
- // The Event's NotifyFunction must be queued whenever the event is signaled
- //
- InsertHeadList (&gEventSignalQueue, &IEvent->SignalLink);
- }
-
- CoreReleaseEventLock ();
-
- //
- // Done
- //
- return EFI_SUCCESS;
-}
-
-/**
- Signals the event. Queues the event to be notified if needed.
-
- @param UserEvent The event to signal .
-
- @retval EFI_INVALID_PARAMETER Parameters are not valid.
- @retval EFI_SUCCESS The event was signaled.
-
-**/
-EFI_STATUS
-EFIAPI
-CoreSignalEvent (
- IN EFI_EVENT UserEvent
- )
-{
- IEVENT *Event;
-
- Event = UserEvent;
-
- if (Event == NULL) {
- return EFI_INVALID_PARAMETER;
- }
-
- if (Event->Signature != EVENT_SIGNATURE) {
- return EFI_INVALID_PARAMETER;
- }
-
- CoreAcquireEventLock ();
-
- //
- // If the event is not already signalled, do so
- //
-
- if (Event->SignalCount == 0x00000000) {
- Event->SignalCount++;
-
- //
- // If signalling type is a notify function, queue it
- //
- if ((Event->Type & EVT_NOTIFY_SIGNAL) != 0) {
- if ((Event->ExFlag & EVT_EXFLAG_EVENT_GROUP) != 0) {
- //
- // The CreateEventEx() style requires all members of the Event Group
- // to be signaled.
- //
- CoreReleaseEventLock ();
- CoreNotifySignalList (&Event->EventGroup);
- CoreAcquireEventLock ();
- } else {
- CoreNotifyEvent (Event);
- }
- }
- }
-
- CoreReleaseEventLock ();
- return EFI_SUCCESS;
-}
-
-/**
- Check the status of an event.
-
- @param UserEvent The event to check
-
- @retval EFI_SUCCESS The event is in the signaled state
- @retval EFI_NOT_READY The event is not in the signaled state
- @retval EFI_INVALID_PARAMETER Event is of type EVT_NOTIFY_SIGNAL
-
-**/
-EFI_STATUS
-EFIAPI
-CoreCheckEvent (
- IN EFI_EVENT UserEvent
- )
-{
- IEVENT *Event;
- EFI_STATUS Status;
-
- Event = UserEvent;
-
- if (Event == NULL) {
- return EFI_INVALID_PARAMETER;
- }
-
- if (Event->Signature != EVENT_SIGNATURE) {
- return EFI_INVALID_PARAMETER;
- }
-
- if ((Event->Type & EVT_NOTIFY_SIGNAL) != 0) {
- return EFI_INVALID_PARAMETER;
- }
-
- Status = EFI_NOT_READY;
-
- if ((Event->SignalCount == 0) && ((Event->Type & EVT_NOTIFY_WAIT) != 0)) {
- //
- // Queue the wait notify function
- //
- CoreAcquireEventLock ();
- if (Event->SignalCount == 0) {
- CoreNotifyEvent (Event);
- }
-
- CoreReleaseEventLock ();
- }
-
- //
- // If the even looks signalled, get the lock and clear it
- //
-
- if (Event->SignalCount != 0) {
- CoreAcquireEventLock ();
-
- if (Event->SignalCount != 0) {
- Event->SignalCount = 0;
- Status = EFI_SUCCESS;
- }
-
- CoreReleaseEventLock ();
- }
-
- return Status;
-}
-
-/**
- Stops execution until an event is signaled.
-
- @param NumberOfEvents The number of events in the UserEvents array
- @param UserEvents An array of EFI_EVENT
- @param UserIndex Pointer to the index of the event which
- satisfied the wait condition
-
- @retval EFI_SUCCESS The event indicated by Index was signaled.
- @retval EFI_INVALID_PARAMETER The event indicated by Index has a notification
- function or Event was not a valid type
- @retval EFI_UNSUPPORTED The current TPL is not TPL_APPLICATION
-
-**/
-EFI_STATUS
-EFIAPI
-CoreWaitForEvent (
- IN UINTN NumberOfEvents,
- IN EFI_EVENT *UserEvents,
- OUT UINTN *UserIndex
- )
-{
- EFI_STATUS Status;
- UINTN Index;
-
- //
- // Can only WaitForEvent at TPL_APPLICATION
- //
- if (gEfiCurrentTpl != TPL_APPLICATION) {
- return EFI_UNSUPPORTED;
- }
-
- if (NumberOfEvents == 0) {
- return EFI_INVALID_PARAMETER;
- }
-
- if (UserEvents == NULL) {
- return EFI_INVALID_PARAMETER;
- }
-
- for ( ; ;) {
- for (Index = 0; Index < NumberOfEvents; Index++) {
- Status = CoreCheckEvent (UserEvents[Index]);
-
- //
- // provide index of event that caused problem
- //
- if (Status != EFI_NOT_READY) {
- if (UserIndex != NULL) {
- *UserIndex = Index;
- }
-
- return Status;
- }
- }
-
- //
- // Signal the Idle event
- //
- CoreSignalEvent (gIdleLoopEvent);
- }
-}
-
-/**
- Closes an event and frees the event structure.
-
- @param UserEvent Event to close
-
- @retval EFI_INVALID_PARAMETER Parameters are not valid.
- @retval EFI_SUCCESS The event has been closed
-
-**/
-EFI_STATUS
-EFIAPI
-CoreCloseEvent (
- IN EFI_EVENT UserEvent
- )
-{
- EFI_STATUS Status;
- IEVENT *Event;
-
- Event = UserEvent;
-
- if (Event == NULL) {
- return EFI_INVALID_PARAMETER;
- }
-
- if (Event->Signature != EVENT_SIGNATURE) {
- return EFI_INVALID_PARAMETER;
- }
-
- //
- // If it's a timer event, make sure it's not pending
- //
- if ((Event->Type & EVT_TIMER) != 0) {
- CoreSetTimer (Event, TimerCancel, 0);
- }
-
- CoreAcquireEventLock ();
-
- //
- // If the event is queued somewhere, remove it
- //
-
- if (Event->RuntimeData.Link.ForwardLink != NULL) {
- RemoveEntryList (&Event->RuntimeData.Link);
- }
-
- if (Event->NotifyLink.ForwardLink != NULL) {
- RemoveEntryList (&Event->NotifyLink);
- }
-
- if (Event->SignalLink.ForwardLink != NULL) {
- RemoveEntryList (&Event->SignalLink);
- }
-
- CoreReleaseEventLock ();
-
- //
- // If the event is registered on a protocol notify, then remove it from the protocol database
- //
- if ((Event->ExFlag & EVT_EXFLAG_EVENT_PROTOCOL_NOTIFICATION) != 0) {
- CoreUnregisterProtocolNotify (Event);
- }
-
- //
- // To avoid the Event to be signalled wrongly after closed,
- // clear the Signature of Event before free pool.
- //
- Event->Signature = 0;
- Status = CoreFreePool (Event);
- ASSERT_EFI_ERROR (Status);
-
- return Status;
-}
+/** @file + UEFI Event support functions implemented in this file. + +Copyright (c) 2006 - 2017, Intel Corporation. All rights reserved.<BR> +(C) Copyright 2015 Hewlett Packard Enterprise Development LP<BR> +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "DxeMain.h" +#include "Event.h" + +/// +/// gEfiCurrentTpl - Current Task priority level +/// +EFI_TPL gEfiCurrentTpl = TPL_APPLICATION; + +/// +/// gEventQueueLock - Protects the event queues +/// +EFI_LOCK gEventQueueLock = EFI_INITIALIZE_LOCK_VARIABLE (TPL_HIGH_LEVEL); + +/// +/// gEventQueue - A list of event's to notify for each priority level +/// +LIST_ENTRY gEventQueue[TPL_HIGH_LEVEL + 1]; + +/// +/// gEventPending - A bitmask of the EventQueues that are pending +/// +UINTN gEventPending = 0; + +/// +/// gEventSignalQueue - A list of events to signal based on EventGroup type +/// +LIST_ENTRY gEventSignalQueue = INITIALIZE_LIST_HEAD_VARIABLE (gEventSignalQueue); + +/// +/// Enumerate the valid types +/// +UINT32 mEventTable[] = { + /// + /// 0x80000200 Timer event with a notification function that is + /// queue when the event is signaled with SignalEvent() + /// + EVT_TIMER | EVT_NOTIFY_SIGNAL, + /// + /// 0x80000000 Timer event without a notification function. It can be + /// signaled with SignalEvent() and checked with CheckEvent() or WaitForEvent(). + /// + EVT_TIMER, + /// + /// 0x00000100 Generic event with a notification function that + /// can be waited on with CheckEvent() or WaitForEvent() + /// + EVT_NOTIFY_WAIT, + /// + /// 0x00000200 Generic event with a notification function that + /// is queue when the event is signaled with SignalEvent() + /// + EVT_NOTIFY_SIGNAL, + /// + /// 0x00000201 ExitBootServicesEvent. + /// + EVT_SIGNAL_EXIT_BOOT_SERVICES, + /// + /// 0x60000202 SetVirtualAddressMapEvent. + /// + EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE, + + /// + /// 0x00000000 Generic event without a notification function. + /// It can be signaled with SignalEvent() and checked with CheckEvent() + /// or WaitForEvent(). + /// + 0x00000000, + /// + /// 0x80000100 Timer event with a notification function that can be + /// waited on with CheckEvent() or WaitForEvent() + /// + EVT_TIMER | EVT_NOTIFY_WAIT, +}; + +/// +/// gIdleLoopEvent - Event which is signalled when the core is idle +/// +EFI_EVENT gIdleLoopEvent = NULL; + +/** + Enter critical section by acquiring the lock on gEventQueueLock. + +**/ +VOID +CoreAcquireEventLock ( + VOID + ) +{ + CoreAcquireLock (&gEventQueueLock); +} + +/** + Exit critical section by releasing the lock on gEventQueueLock. + +**/ +VOID +CoreReleaseEventLock ( + VOID + ) +{ + CoreReleaseLock (&gEventQueueLock); +} + +/** + Initializes "event" support. + + @retval EFI_SUCCESS Always return success + +**/ +EFI_STATUS +CoreInitializeEventServices ( + VOID + ) +{ + UINTN Index; + + for (Index = 0; Index <= TPL_HIGH_LEVEL; Index++) { + InitializeListHead (&gEventQueue[Index]); + } + + CoreInitializeTimer (); + + CoreCreateEventEx ( + EVT_NOTIFY_SIGNAL, + TPL_NOTIFY, + EfiEventEmptyFunction, + NULL, + &gIdleLoopEventGuid, + &gIdleLoopEvent + ); + + return EFI_SUCCESS; +} + +/** + Dispatches all pending events. + + @param Priority The task priority level of event notifications + to dispatch + +**/ +VOID +CoreDispatchEventNotifies ( + IN EFI_TPL Priority + ) +{ + IEVENT *Event; + LIST_ENTRY *Head; + + CoreAcquireEventLock (); + ASSERT (gEventQueueLock.OwnerTpl == Priority); + Head = &gEventQueue[Priority]; + + // + // Dispatch all the pending notifications + // + while (!IsListEmpty (Head)) { + Event = CR (Head->ForwardLink, IEVENT, NotifyLink, EVENT_SIGNATURE); + RemoveEntryList (&Event->NotifyLink); + + Event->NotifyLink.ForwardLink = NULL; + + // + // Only clear the SIGNAL status if it is a SIGNAL type event. + // WAIT type events are only cleared in CheckEvent() + // + if ((Event->Type & EVT_NOTIFY_SIGNAL) != 0) { + Event->SignalCount = 0; + } + + CoreReleaseEventLock (); + + // + // Notify this event + // + ASSERT (Event->NotifyFunction != NULL); + Event->NotifyFunction (Event, Event->NotifyContext); + + // + // Check for next pending event + // + CoreAcquireEventLock (); + } + + gEventPending &= ~(UINTN)(1 << Priority); + CoreReleaseEventLock (); +} + +/** + Queues the event's notification function to fire. + + @param Event The Event to notify + +**/ +VOID +CoreNotifyEvent ( + IN IEVENT *Event + ) +{ + // + // Event database must be locked + // + ASSERT_LOCKED (&gEventQueueLock); + + // + // If the event is queued somewhere, remove it + // + + if (Event->NotifyLink.ForwardLink != NULL) { + RemoveEntryList (&Event->NotifyLink); + Event->NotifyLink.ForwardLink = NULL; + } + + // + // Queue the event to the pending notification list + // + + InsertTailList (&gEventQueue[Event->NotifyTpl], &Event->NotifyLink); + gEventPending |= (UINTN)(1 << Event->NotifyTpl); +} + +/** + Signals all events in the EventGroup. + + @param EventGroup The list to signal + +**/ +VOID +CoreNotifySignalList ( + IN EFI_GUID *EventGroup + ) +{ + LIST_ENTRY *Link; + LIST_ENTRY *Head; + IEVENT *Event; + + CoreAcquireEventLock (); + + Head = &gEventSignalQueue; + for (Link = Head->ForwardLink; Link != Head; Link = Link->ForwardLink) { + Event = CR (Link, IEVENT, SignalLink, EVENT_SIGNATURE); + if (CompareGuid (&Event->EventGroup, EventGroup)) { + CoreNotifyEvent (Event); + } + } + + CoreReleaseEventLock (); +} + +/** + Creates an event. + + @param Type The type of event to create and its mode and + attributes + @param NotifyTpl The task priority level of event notifications + @param NotifyFunction Pointer to the events notification function + @param NotifyContext Pointer to the notification functions context; + corresponds to parameter "Context" in the + notification function + @param Event Pointer to the newly created event if the call + succeeds; undefined otherwise + + @retval EFI_SUCCESS The event structure was created + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value + @retval EFI_OUT_OF_RESOURCES The event could not be allocated + +**/ +EFI_STATUS +EFIAPI +CoreCreateEvent ( + IN UINT32 Type, + IN EFI_TPL NotifyTpl, + IN EFI_EVENT_NOTIFY NotifyFunction OPTIONAL, + IN VOID *NotifyContext OPTIONAL, + OUT EFI_EVENT *Event + ) +{ + return CoreCreateEventEx (Type, NotifyTpl, NotifyFunction, NotifyContext, NULL, Event); +} + +/** + Creates an event in a group. + + @param Type The type of event to create and its mode and + attributes + @param NotifyTpl The task priority level of event notifications + @param NotifyFunction Pointer to the events notification function + @param NotifyContext Pointer to the notification functions context; + corresponds to parameter "Context" in the + notification function + @param EventGroup GUID for EventGroup if NULL act the same as + gBS->CreateEvent(). + @param Event Pointer to the newly created event if the call + succeeds; undefined otherwise + + @retval EFI_SUCCESS The event structure was created + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value + @retval EFI_OUT_OF_RESOURCES The event could not be allocated + +**/ +EFI_STATUS +EFIAPI +CoreCreateEventEx ( + IN UINT32 Type, + IN EFI_TPL NotifyTpl, + IN EFI_EVENT_NOTIFY NotifyFunction OPTIONAL, + IN CONST VOID *NotifyContext OPTIONAL, + IN CONST EFI_GUID *EventGroup OPTIONAL, + OUT EFI_EVENT *Event + ) +{ + // + // If it's a notify type of event, check for invalid NotifyTpl + // + if ((Type & (EVT_NOTIFY_WAIT | EVT_NOTIFY_SIGNAL)) != 0) { + if ((NotifyTpl != TPL_APPLICATION) && + (NotifyTpl != TPL_CALLBACK) && + (NotifyTpl != TPL_NOTIFY)) + { + return EFI_INVALID_PARAMETER; + } + } + + return CoreCreateEventInternal (Type, NotifyTpl, NotifyFunction, NotifyContext, EventGroup, Event); +} + +/** + Creates a general-purpose event structure + + @param Type The type of event to create and its mode and + attributes + @param NotifyTpl The task priority level of event notifications + @param NotifyFunction Pointer to the events notification function + @param NotifyContext Pointer to the notification functions context; + corresponds to parameter "Context" in the + notification function + @param EventGroup GUID for EventGroup if NULL act the same as + gBS->CreateEvent(). + @param Event Pointer to the newly created event if the call + succeeds; undefined otherwise + + @retval EFI_SUCCESS The event structure was created + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value + @retval EFI_OUT_OF_RESOURCES The event could not be allocated + +**/ +EFI_STATUS +EFIAPI +CoreCreateEventInternal ( + IN UINT32 Type, + IN EFI_TPL NotifyTpl, + IN EFI_EVENT_NOTIFY NotifyFunction OPTIONAL, + IN CONST VOID *NotifyContext OPTIONAL, + IN CONST EFI_GUID *EventGroup OPTIONAL, + OUT EFI_EVENT *Event + ) +{ + EFI_STATUS Status; + IEVENT *IEvent; + INTN Index; + + if (Event == NULL) { + return EFI_INVALID_PARAMETER; + } + + // + // Check to make sure no reserved flags are set + // + Status = EFI_INVALID_PARAMETER; + for (Index = 0; Index < (sizeof (mEventTable) / sizeof (UINT32)); Index++) { + if (Type == mEventTable[Index]) { + Status = EFI_SUCCESS; + break; + } + } + + if (EFI_ERROR (Status)) { + return EFI_INVALID_PARAMETER; + } + + // + // Convert Event type for pre-defined Event groups + // + if (EventGroup != NULL) { + // + // For event group, type EVT_SIGNAL_EXIT_BOOT_SERVICES and EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE + // are not valid + // + if ((Type == EVT_SIGNAL_EXIT_BOOT_SERVICES) || (Type == EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE)) { + return EFI_INVALID_PARAMETER; + } + + if (CompareGuid (EventGroup, &gEfiEventExitBootServicesGuid)) { + Type = EVT_SIGNAL_EXIT_BOOT_SERVICES; + } else if (CompareGuid (EventGroup, &gEfiEventVirtualAddressChangeGuid)) { + Type = EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE; + } + } else { + // + // Convert EFI 1.10 Events to their UEFI 2.0 CreateEventEx mapping + // + if (Type == EVT_SIGNAL_EXIT_BOOT_SERVICES) { + EventGroup = &gEfiEventExitBootServicesGuid; + } else if (Type == EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE) { + EventGroup = &gEfiEventVirtualAddressChangeGuid; + } + } + + // + // If it's a notify type of event, check its parameters + // + if ((Type & (EVT_NOTIFY_WAIT | EVT_NOTIFY_SIGNAL)) != 0) { + // + // Check for an invalid NotifyFunction or NotifyTpl + // + if ((NotifyFunction == NULL) || + (NotifyTpl <= TPL_APPLICATION) || + (NotifyTpl >= TPL_HIGH_LEVEL)) + { + return EFI_INVALID_PARAMETER; + } + } else { + // + // No notification needed, zero ignored values + // + NotifyTpl = 0; + NotifyFunction = NULL; + NotifyContext = NULL; + } + + // + // Allocate and initialize a new event structure. + // + if ((Type & EVT_RUNTIME) != 0) { + IEvent = AllocateRuntimeZeroPool (sizeof (IEVENT)); + } else { + IEvent = AllocateZeroPool (sizeof (IEVENT)); + } + + if (IEvent == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + IEvent->Signature = EVENT_SIGNATURE; + IEvent->Type = Type; + + IEvent->NotifyTpl = NotifyTpl; + IEvent->NotifyFunction = NotifyFunction; + IEvent->NotifyContext = (VOID *)NotifyContext; + if (EventGroup != NULL) { + CopyGuid (&IEvent->EventGroup, EventGroup); + IEvent->ExFlag |= EVT_EXFLAG_EVENT_GROUP; + } + + *Event = IEvent; + + if ((Type & EVT_RUNTIME) != 0) { + // + // Keep a list of all RT events so we can tell the RT AP. + // + IEvent->RuntimeData.Type = Type; + IEvent->RuntimeData.NotifyTpl = NotifyTpl; + IEvent->RuntimeData.NotifyFunction = NotifyFunction; + IEvent->RuntimeData.NotifyContext = (VOID *)NotifyContext; + // + // Work around the bug in the Platform Init specification (v1.7), reported + // as Mantis#2017: "EFI_RUNTIME_EVENT_ENTRY.Event" should have type + // EFI_EVENT, not (EFI_EVENT*). The PI spec documents the field correctly + // as "The EFI_EVENT returned by CreateEvent()", but the type of the field + // doesn't match the natural language description. Therefore we need an + // explicit cast here. + // + IEvent->RuntimeData.Event = (EFI_EVENT *)IEvent; + InsertTailList (&gRuntime->EventHead, &IEvent->RuntimeData.Link); + } + + CoreAcquireEventLock (); + + if ((Type & EVT_NOTIFY_SIGNAL) != 0x00000000) { + // + // The Event's NotifyFunction must be queued whenever the event is signaled + // + InsertHeadList (&gEventSignalQueue, &IEvent->SignalLink); + } + + CoreReleaseEventLock (); + + // + // Done + // + return EFI_SUCCESS; +} + +/** + Signals the event. Queues the event to be notified if needed. + + @param UserEvent The event to signal . + + @retval EFI_INVALID_PARAMETER Parameters are not valid. + @retval EFI_SUCCESS The event was signaled. + +**/ +EFI_STATUS +EFIAPI +CoreSignalEvent ( + IN EFI_EVENT UserEvent + ) +{ + IEVENT *Event; + + Event = UserEvent; + + if (Event == NULL) { + return EFI_INVALID_PARAMETER; + } + + if (Event->Signature != EVENT_SIGNATURE) { + return EFI_INVALID_PARAMETER; + } + + CoreAcquireEventLock (); + + // + // If the event is not already signalled, do so + // + + if (Event->SignalCount == 0x00000000) { + Event->SignalCount++; + + // + // If signalling type is a notify function, queue it + // + if ((Event->Type & EVT_NOTIFY_SIGNAL) != 0) { + if ((Event->ExFlag & EVT_EXFLAG_EVENT_GROUP) != 0) { + // + // The CreateEventEx() style requires all members of the Event Group + // to be signaled. + // + CoreReleaseEventLock (); + CoreNotifySignalList (&Event->EventGroup); + CoreAcquireEventLock (); + } else { + CoreNotifyEvent (Event); + } + } + } + + CoreReleaseEventLock (); + return EFI_SUCCESS; +} + +/** + Check the status of an event. + + @param UserEvent The event to check + + @retval EFI_SUCCESS The event is in the signaled state + @retval EFI_NOT_READY The event is not in the signaled state + @retval EFI_INVALID_PARAMETER Event is of type EVT_NOTIFY_SIGNAL + +**/ +EFI_STATUS +EFIAPI +CoreCheckEvent ( + IN EFI_EVENT UserEvent + ) +{ + IEVENT *Event; + EFI_STATUS Status; + + Event = UserEvent; + + if (Event == NULL) { + return EFI_INVALID_PARAMETER; + } + + if (Event->Signature != EVENT_SIGNATURE) { + return EFI_INVALID_PARAMETER; + } + + if ((Event->Type & EVT_NOTIFY_SIGNAL) != 0) { + return EFI_INVALID_PARAMETER; + } + + Status = EFI_NOT_READY; + + if ((Event->SignalCount == 0) && ((Event->Type & EVT_NOTIFY_WAIT) != 0)) { + // + // Queue the wait notify function + // + CoreAcquireEventLock (); + if (Event->SignalCount == 0) { + CoreNotifyEvent (Event); + } + + CoreReleaseEventLock (); + } + + // + // If the even looks signalled, get the lock and clear it + // + + if (Event->SignalCount != 0) { + CoreAcquireEventLock (); + + if (Event->SignalCount != 0) { + Event->SignalCount = 0; + Status = EFI_SUCCESS; + } + + CoreReleaseEventLock (); + } + + return Status; +} + +/** + Stops execution until an event is signaled. + + @param NumberOfEvents The number of events in the UserEvents array + @param UserEvents An array of EFI_EVENT + @param UserIndex Pointer to the index of the event which + satisfied the wait condition + + @retval EFI_SUCCESS The event indicated by Index was signaled. + @retval EFI_INVALID_PARAMETER The event indicated by Index has a notification + function or Event was not a valid type + @retval EFI_UNSUPPORTED The current TPL is not TPL_APPLICATION + +**/ +EFI_STATUS +EFIAPI +CoreWaitForEvent ( + IN UINTN NumberOfEvents, + IN EFI_EVENT *UserEvents, + OUT UINTN *UserIndex + ) +{ + EFI_STATUS Status; + UINTN Index; + + // + // Can only WaitForEvent at TPL_APPLICATION + // + if (gEfiCurrentTpl != TPL_APPLICATION) { + return EFI_UNSUPPORTED; + } + + if (NumberOfEvents == 0) { + return EFI_INVALID_PARAMETER; + } + + if (UserEvents == NULL) { + return EFI_INVALID_PARAMETER; + } + + for ( ; ;) { + for (Index = 0; Index < NumberOfEvents; Index++) { + Status = CoreCheckEvent (UserEvents[Index]); + + // + // provide index of event that caused problem + // + if (Status != EFI_NOT_READY) { + if (UserIndex != NULL) { + *UserIndex = Index; + } + + return Status; + } + } + + // + // Signal the Idle event + // + CoreSignalEvent (gIdleLoopEvent); + } +} + +/** + Closes an event and frees the event structure. + + @param UserEvent Event to close + + @retval EFI_INVALID_PARAMETER Parameters are not valid. + @retval EFI_SUCCESS The event has been closed + +**/ +EFI_STATUS +EFIAPI +CoreCloseEvent ( + IN EFI_EVENT UserEvent + ) +{ + EFI_STATUS Status; + IEVENT *Event; + + Event = UserEvent; + + if (Event == NULL) { + return EFI_INVALID_PARAMETER; + } + + if (Event->Signature != EVENT_SIGNATURE) { + return EFI_INVALID_PARAMETER; + } + + // + // If it's a timer event, make sure it's not pending + // + if ((Event->Type & EVT_TIMER) != 0) { + CoreSetTimer (Event, TimerCancel, 0); + } + + CoreAcquireEventLock (); + + // + // If the event is queued somewhere, remove it + // + + if (Event->RuntimeData.Link.ForwardLink != NULL) { + RemoveEntryList (&Event->RuntimeData.Link); + } + + if (Event->NotifyLink.ForwardLink != NULL) { + RemoveEntryList (&Event->NotifyLink); + } + + if (Event->SignalLink.ForwardLink != NULL) { + RemoveEntryList (&Event->SignalLink); + } + + CoreReleaseEventLock (); + + // + // If the event is registered on a protocol notify, then remove it from the protocol database + // + if ((Event->ExFlag & EVT_EXFLAG_EVENT_PROTOCOL_NOTIFICATION) != 0) { + CoreUnregisterProtocolNotify (Event); + } + + // + // To avoid the Event to be signalled wrongly after closed, + // clear the Signature of Event before free pool. + // + Event->Signature = 0; + Status = CoreFreePool (Event); + ASSERT_EFI_ERROR (Status); + + return Status; +} |
