--- /dev/null
+/** @file \r
+\r
+ UEFI Event support functions implemented in this file.\r
+\r
+Copyright (c) 2006 - 2008, Intel Corporation\r
+All rights reserved. This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+\r
+#include <DxeMain.h>\r
+\r
+//\r
+// Enumerate the valid types\r
+//\r
+UINT32 mEventTable[] = {\r
+ //\r
+ // 0x80000200 Timer event with a notification function that is\r
+ // queue when the event is signaled with SignalEvent()\r
+ //\r
+ EVT_TIMER | EVT_NOTIFY_SIGNAL,\r
+ //\r
+ // 0x80000000 Timer event without a notification function. It can be\r
+ // signaled with SignalEvent() and checked with CheckEvent() or WaitForEvent().\r
+ //\r
+ EVT_TIMER,\r
+ //\r
+ // 0x00000100 Generic event with a notification function that\r
+ // can be waited on with CheckEvent() or WaitForEvent()\r
+ //\r
+ EVT_NOTIFY_WAIT,\r
+ //\r
+ // 0x00000200 Generic event with a notification function that\r
+ // is queue when the event is signaled with SignalEvent()\r
+ //\r
+ EVT_NOTIFY_SIGNAL,\r
+ //\r
+ // 0x00000201 ExitBootServicesEvent.\r
+ //\r
+ EVT_SIGNAL_EXIT_BOOT_SERVICES,\r
+ //\r
+ // 0x60000202 SetVirtualAddressMapEvent.\r
+ //\r
+ EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE,\r
+\r
+ //\r
+ // 0x00000000 Generic event without a notification function.\r
+ // It can be signaled with SignalEvent() and checked with CheckEvent()\r
+ // or WaitForEvent().\r
+ //\r
+ 0x00000000,\r
+ //\r
+ // 0x80000100 Timer event with a notification function that can be\r
+ // waited on with CheckEvent() or WaitForEvent()\r
+ //\r
+ EVT_TIMER | EVT_NOTIFY_WAIT,\r
+};\r
+\r
+\r
+/**\r
+ Enter critical section by acquiring the lock on gEventQueueLock.\r
+\r
+**/\r
+STATIC\r
+VOID\r
+CoreAcquireEventLock (\r
+ VOID\r
+ )\r
+{\r
+ CoreAcquireLock (&gEventQueueLock);\r
+}\r
+\r
+\r
+/**\r
+ Exit critical section by releasing the lock on gEventQueueLock.\r
+\r
+**/\r
+STATIC\r
+VOID\r
+CoreReleaseEventLock (\r
+ VOID\r
+ )\r
+{\r
+ CoreReleaseLock (&gEventQueueLock);\r
+}\r
+\r
+\r
+\r
+/**\r
+ Initializes "event" support and populates parts of the System and Runtime Table.\r
+\r
+\r
+ @retval EFI_SUCCESS Always return success\r
+\r
+**/\r
+EFI_STATUS\r
+CoreInitializeEventServices (\r
+ VOID\r
+ )\r
+{\r
+ UINTN Index;\r
+\r
+ for (Index=0; Index <= TPL_HIGH_LEVEL; Index++) {\r
+ InitializeListHead (&gEventQueue[Index]);\r
+ }\r
+\r
+ CoreInitializeTimer ();\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+\r
+\r
+/**\r
+ Dispatches all pending events.\r
+\r
+ @param Priority The task priority level of event notifications \r
+ to dispatch\r
+\r
+**/\r
+VOID\r
+CoreDispatchEventNotifies (\r
+ IN EFI_TPL Priority\r
+ )\r
+{\r
+ IEVENT *Event;\r
+ LIST_ENTRY *Head;\r
+\r
+ CoreAcquireEventLock ();\r
+ ASSERT (gEventQueueLock.OwnerTpl == Priority);\r
+ Head = &gEventQueue[Priority];\r
+\r
+ //\r
+ // Dispatch all the pending notifications\r
+ //\r
+ while (!IsListEmpty (Head)) {\r
+\r
+ Event = CR (Head->ForwardLink, IEVENT, NotifyLink, EVENT_SIGNATURE);\r
+ RemoveEntryList (&Event->NotifyLink);\r
+\r
+ Event->NotifyLink.ForwardLink = NULL;\r
+\r
+ //\r
+ // Only clear the SIGNAL status if it is a SIGNAL type event.\r
+ // WAIT type events are only cleared in CheckEvent()\r
+ //\r
+ if (Event->Type & EVT_NOTIFY_SIGNAL) {\r
+ Event->SignalCount = 0;\r
+ }\r
+\r
+ CoreReleaseEventLock ();\r
+\r
+ //\r
+ // Notify this event\r
+ //\r
+ ASSERT (Event->NotifyFunction != NULL);\r
+ Event->NotifyFunction (Event, Event->NotifyContext);\r
+\r
+ //\r
+ // Check for next pending event\r
+ //\r
+ CoreAcquireEventLock ();\r
+ }\r
+\r
+ gEventPending &= ~(1 << Priority);\r
+ CoreReleaseEventLock ();\r
+}\r
+\r
+\r
+\r
+/**\r
+ Queues the event's notification function to fire.\r
+\r
+ @param Event The Event to notify\r
+\r
+**/\r
+STATIC\r
+VOID\r
+CoreNotifyEvent (\r
+ IN IEVENT *Event\r
+ )\r
+{\r
+\r
+ //\r
+ // Event database must be locked\r
+ //\r
+ ASSERT_LOCKED (&gEventQueueLock);\r
+\r
+ //\r
+ // If the event is queued somewhere, remove it\r
+ //\r
+\r
+ if (Event->NotifyLink.ForwardLink != NULL) {\r
+ RemoveEntryList (&Event->NotifyLink);\r
+ Event->NotifyLink.ForwardLink = NULL;\r
+ }\r
+\r
+ //\r
+ // Queue the event to the pending notification list\r
+ //\r
+\r
+ InsertTailList (&gEventQueue[Event->NotifyTpl], &Event->NotifyLink);\r
+ gEventPending |= (UINTN)(1 << Event->NotifyTpl);\r
+}\r
+\r
+\r
+\r
+\r
+/**\r
+ Signals all events in the EventGroup.\r
+\r
+ @param EventGroup The list to signal\r
+\r
+**/\r
+VOID\r
+CoreNotifySignalList (\r
+ IN EFI_GUID *EventGroup\r
+ )\r
+{\r
+ LIST_ENTRY *Link;\r
+ LIST_ENTRY *Head;\r
+ IEVENT *Event;\r
+\r
+ CoreAcquireEventLock ();\r
+\r
+ Head = &gEventSignalQueue;\r
+ for (Link = Head->ForwardLink; Link != Head; Link = Link->ForwardLink) {\r
+ Event = CR (Link, IEVENT, SignalLink, EVENT_SIGNATURE);\r
+ if (CompareGuid (&Event->EventGroup, EventGroup)) {\r
+ CoreNotifyEvent (Event);\r
+ }\r
+ }\r
+\r
+ CoreReleaseEventLock ();\r
+}\r
+\r
+\r
+/**\r
+ Creates a general-purpose event structure.\r
+\r
+ @param Type The type of event to create and its mode and \r
+ attributes \r
+ @param NotifyTpl The task priority level of event notifications \r
+ @param NotifyFunction Pointer to the events notification function \r
+ @param NotifyContext Pointer to the notification functions context; \r
+ corresponds to parameter "Context" in the \r
+ notification function \r
+ @param Event Pointer to the newly created event if the call \r
+ succeeds; undefined otherwise \r
+\r
+ @retval EFI_SUCCESS The event structure was created \r
+ @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value \r
+ @retval EFI_OUT_OF_RESOURCES The event could not be allocated\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+CoreCreateEvent (\r
+ IN UINT32 Type,\r
+ IN EFI_TPL NotifyTpl,\r
+ IN EFI_EVENT_NOTIFY NotifyFunction, OPTIONAL\r
+ IN VOID *NotifyContext, OPTIONAL\r
+ OUT EFI_EVENT *Event\r
+ )\r
+{\r
+ return CoreCreateEventEx (Type, NotifyTpl, NotifyFunction, NotifyContext, NULL, Event);\r
+}\r
+\r
+\r
+\r
+/**\r
+ Creates a general-purpose event structure\r
+\r
+ @param Type The type of event to create and its mode and \r
+ attributes \r
+ @param NotifyTpl The task priority level of event notifications \r
+ @param NotifyFunction Pointer to the events notification function \r
+ @param NotifyContext Pointer to the notification functions context; \r
+ corresponds to parameter "Context" in the \r
+ notification function \r
+ @param EventGroup GUID for EventGroup if NULL act the same as \r
+ gBS->CreateEvent(). \r
+ @param Event Pointer to the newly created event if the call \r
+ succeeds; undefined otherwise \r
+\r
+ @retval EFI_SUCCESS The event structure was created \r
+ @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value \r
+ @retval EFI_OUT_OF_RESOURCES The event could not be allocated\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+CoreCreateEventEx (\r
+ IN UINT32 Type,\r
+ IN EFI_TPL NotifyTpl,\r
+ IN EFI_EVENT_NOTIFY NotifyFunction, OPTIONAL\r
+ IN CONST VOID *NotifyContext, OPTIONAL\r
+ IN CONST EFI_GUID *EventGroup, OPTIONAL\r
+ OUT EFI_EVENT *Event\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ IEVENT *IEvent;\r
+ INTN Index;\r
+\r
+\r
+ if ((Event == NULL) || (NotifyTpl == TPL_APPLICATION)) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ //\r
+ // Check to make sure no reserved flags are set\r
+ //\r
+ Status = EFI_INVALID_PARAMETER;\r
+ for (Index = 0; Index < (sizeof (mEventTable) / sizeof (UINT32)); Index++) {\r
+ if (Type == mEventTable[Index]) {\r
+ Status = EFI_SUCCESS;\r
+ break;\r
+ }\r
+ }\r
+ if(EFI_ERROR (Status)) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ //\r
+ // Convert Event type for pre-defined Event groups\r
+ //\r
+ if (EventGroup != NULL) {\r
+ //\r
+ // For event group, type EVT_SIGNAL_EXIT_BOOT_SERVICES and EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE\r
+ // are not valid\r
+ //\r
+ if ((Type == EVT_SIGNAL_EXIT_BOOT_SERVICES) || (Type == EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE)) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+ if (CompareGuid (EventGroup, &gEfiEventExitBootServicesGuid)) {\r
+ Type = EVT_SIGNAL_EXIT_BOOT_SERVICES;\r
+ } else if (CompareGuid (EventGroup, &gEfiEventVirtualAddressChangeGuid)) {\r
+ Type = EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE;\r
+ }\r
+ } else {\r
+ //\r
+ // Convert EFI 1.10 Events to their UEFI 2.0 CreateEventEx mapping\r
+ //\r
+ if (Type == EVT_SIGNAL_EXIT_BOOT_SERVICES) {\r
+ EventGroup = &gEfiEventExitBootServicesGuid;\r
+ } else if (Type == EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE) {\r
+ EventGroup = &gEfiEventVirtualAddressChangeGuid;\r
+ }\r
+ }\r
+\r
+ //\r
+ // If it's a notify type of event, check its parameters\r
+ //\r
+ if ((Type & (EVT_NOTIFY_WAIT | EVT_NOTIFY_SIGNAL)) != 0) {\r
+ //\r
+ // Check for an invalid NotifyFunction or NotifyTpl\r
+ //\r
+ if ((NotifyFunction == NULL) ||\r
+ (NotifyTpl < TPL_APPLICATION) ||\r
+ (NotifyTpl >= TPL_HIGH_LEVEL)) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ } else {\r
+ //\r
+ // No notification needed, zero ignored values\r
+ //\r
+ NotifyTpl = 0;\r
+ NotifyFunction = NULL;\r
+ NotifyContext = NULL;\r
+ }\r
+\r
+ //\r
+ // Allcoate and initialize a new event structure.\r
+ //\r
+ Status = CoreAllocatePool (\r
+ ((Type & EVT_RUNTIME) != 0) ? EfiRuntimeServicesData: EfiBootServicesData,\r
+ sizeof (IEVENT),\r
+ (VOID **)&IEvent\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ SetMem (IEvent, sizeof (IEVENT), 0);\r
+\r
+ IEvent->Signature = EVENT_SIGNATURE;\r
+ IEvent->Type = Type;\r
+\r
+ IEvent->NotifyTpl = NotifyTpl;\r
+ IEvent->NotifyFunction = NotifyFunction;\r
+ IEvent->NotifyContext = (VOID *)NotifyContext;\r
+ if (EventGroup != NULL) {\r
+ CopyGuid (&IEvent->EventGroup, EventGroup);\r
+ IEvent->ExFlag = TRUE;\r
+ }\r
+\r
+ *Event = IEvent;\r
+\r
+ if ((Type & EVT_RUNTIME) != 0) {\r
+ //\r
+ // Keep a list of all RT events so we can tell the RT AP.\r
+ //\r
+ IEvent->RuntimeData.Type = Type;\r
+ IEvent->RuntimeData.NotifyTpl = NotifyTpl;\r
+ IEvent->RuntimeData.NotifyFunction = NotifyFunction;\r
+ IEvent->RuntimeData.NotifyContext = (VOID *) NotifyContext;\r
+ IEvent->RuntimeData.Event = (EFI_EVENT *) IEvent;\r
+ InsertTailList (&gRuntime->EventHead, &IEvent->RuntimeData.Link);\r
+ }\r
+\r
+ CoreAcquireEventLock ();\r
+\r
+ if ((Type & EVT_NOTIFY_SIGNAL) != 0x00000000) {\r
+ //\r
+ // The Event's NotifyFunction must be queued whenever the event is signaled\r
+ //\r
+ InsertHeadList (&gEventSignalQueue, &IEvent->SignalLink);\r
+ }\r
+\r
+ CoreReleaseEventLock ();\r
+\r
+ //\r
+ // Done\r
+ //\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+\r
+\r
+\r
+/**\r
+ Signals the event. Queues the event to be notified if needed\r
+\r
+ @param UserEvent The event to signal \r
+\r
+ @retval EFI_INVALID_PARAMETER Parameters are not valid. \r
+ @retval EFI_SUCCESS The event was signaled.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+CoreSignalEvent (\r
+ IN EFI_EVENT UserEvent\r
+ )\r
+{\r
+ IEVENT *Event;\r
+\r
+ Event = UserEvent;\r
+\r
+ if (Event == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ if (Event->Signature != EVENT_SIGNATURE) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ CoreAcquireEventLock ();\r
+\r
+ //\r
+ // If the event is not already signalled, do so\r
+ //\r
+\r
+ if (Event->SignalCount == 0x00000000) {\r
+ Event->SignalCount++;\r
+\r
+ //\r
+ // If signalling type is a notify function, queue it\r
+ //\r
+ if (Event->Type & EVT_NOTIFY_SIGNAL) {\r
+ if (Event->ExFlag) {\r
+ //\r
+ // The CreateEventEx() style requires all members of the Event Group\r
+ // to be signaled.\r
+ //\r
+ CoreReleaseEventLock ();\r
+ CoreNotifySignalList (&Event->EventGroup);\r
+ CoreAcquireEventLock ();\r
+ } else {\r
+ CoreNotifyEvent (Event);\r
+ }\r
+ }\r
+ }\r
+\r
+ CoreReleaseEventLock ();\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+\r
+\r
+/**\r
+ Check the status of an event.\r
+\r
+ @param UserEvent The event to check \r
+\r
+ @retval EFI_SUCCESS The event is in the signaled state \r
+ @retval EFI_NOT_READY The event is not in the signaled state \r
+ @retval EFI_INVALID_PARAMETER Event is of type EVT_NOTIFY_SIGNAL\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+CoreCheckEvent (\r
+ IN EFI_EVENT UserEvent\r
+ )\r
+{\r
+ IEVENT *Event;\r
+ EFI_STATUS Status;\r
+\r
+ Event = UserEvent;\r
+\r
+ if (Event == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ if (Event->Signature != EVENT_SIGNATURE) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ if (Event->Type & EVT_NOTIFY_SIGNAL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ Status = EFI_NOT_READY;\r
+\r
+ if (!Event->SignalCount && (Event->Type & EVT_NOTIFY_WAIT)) {\r
+\r
+ //\r
+ // Queue the wait notify function\r
+ //\r
+\r
+ CoreAcquireEventLock ();\r
+ if (!Event->SignalCount) {\r
+ CoreNotifyEvent (Event);\r
+ }\r
+ CoreReleaseEventLock ();\r
+ }\r
+\r
+ //\r
+ // If the even looks signalled, get the lock and clear it\r
+ //\r
+\r
+ if (Event->SignalCount) {\r
+ CoreAcquireEventLock ();\r
+\r
+ if (Event->SignalCount) {\r
+ Event->SignalCount = 0;\r
+ Status = EFI_SUCCESS;\r
+ }\r
+\r
+ CoreReleaseEventLock ();\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+\r
+\r
+\r
+/**\r
+ Stops execution until an event is signaled.\r
+\r
+ @param NumberOfEvents The number of events in the UserEvents array \r
+ @param UserEvents An array of EFI_EVENT \r
+ @param UserIndex Pointer to the index of the event which \r
+ satisfied the wait condition \r
+\r
+ @retval EFI_SUCCESS The event indicated by Index was signaled. \r
+ @retval EFI_INVALID_PARAMETER The event indicated by Index has a notification \r
+ function or Event was not a valid type \r
+ @retval EFI_UNSUPPORTED The current TPL is not TPL_APPLICATION\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+CoreWaitForEvent (\r
+ IN UINTN NumberOfEvents,\r
+ IN EFI_EVENT *UserEvents,\r
+ OUT UINTN *UserIndex\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINTN Index;\r
+\r
+ //\r
+ // Can only WaitForEvent at TPL_APPLICATION\r
+ //\r
+ if (gEfiCurrentTpl != TPL_APPLICATION) {\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+\r
+ for(;;) {\r
+\r
+ for(Index = 0; Index < NumberOfEvents; Index++) {\r
+\r
+ Status = CoreCheckEvent (UserEvents[Index]);\r
+\r
+ //\r
+ // provide index of event that caused problem\r
+ //\r
+ if (Status != EFI_NOT_READY) {\r
+ *UserIndex = Index;\r
+ return Status;\r
+ }\r
+ }\r
+\r
+ //\r
+ // This was the location of the Idle loop callback in EFI 1.x reference\r
+ // code. We don't have that concept in this base at this point.\r
+ //\r
+ }\r
+}\r
+\r
+\r
+\r
+/**\r
+ Closes an event and frees the event structure.\r
+\r
+ @param UserEvent Event to close \r
+\r
+ @retval EFI_INVALID_PARAMETER Parameters are not valid. \r
+ @retval EFI_SUCCESS The event has been closed\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+CoreCloseEvent (\r
+ IN EFI_EVENT UserEvent\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ IEVENT *Event;\r
+\r
+ Event = UserEvent;\r
+\r
+ if (Event == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ if (Event->Signature != EVENT_SIGNATURE) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ //\r
+ // If it's a timer event, make sure it's not pending\r
+ //\r
+ if (Event->Type & EVT_TIMER) {\r
+ CoreSetTimer (Event, TimerCancel, 0);\r
+ }\r
+\r
+ CoreAcquireEventLock ();\r
+\r
+ //\r
+ // If the event is queued somewhere, remove it\r
+ //\r
+\r
+ if (Event->RuntimeData.Link.ForwardLink != NULL) {\r
+ RemoveEntryList (&Event->RuntimeData.Link);\r
+ }\r
+\r
+ if (Event->NotifyLink.ForwardLink != NULL) {\r
+ RemoveEntryList (&Event->NotifyLink);\r
+ }\r
+\r
+ if (Event->SignalLink.ForwardLink != NULL) {\r
+ RemoveEntryList (&Event->SignalLink);\r
+ }\r
+\r
+ CoreReleaseEventLock ();\r
+\r
+ //\r
+ // If the event is registered on a protocol notify, then remove it from the protocol database\r
+ //\r
+ CoreUnregisterProtocolNotify (Event);\r
+\r
+ Status = CoreFreePool (Event);\r
+ ASSERT_EFI_ERROR (Status);\r
+\r
+ return Status;\r
+}\r
+++ /dev/null
-/** @file \r
-\r
- UEFI Event support functions implemented in this file.\r
-\r
-Copyright (c) 2006 - 2008, Intel Corporation\r
-All rights reserved. This program and the accompanying materials\r
-are licensed and made available under the terms and conditions of the BSD License\r
-which accompanies this distribution. The full text of the license may be found at\r
-http://opensource.org/licenses/bsd-license.php\r
-\r
-THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
-WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
-\r
-**/\r
-\r
-\r
-#include <DxeMain.h>\r
-\r
-//\r
-// Enumerate the valid types\r
-//\r
-UINT32 mEventTable[] = {\r
- //\r
- // 0x80000200 Timer event with a notification function that is\r
- // queue when the event is signaled with SignalEvent()\r
- //\r
- EVT_TIMER | EVT_NOTIFY_SIGNAL,\r
- //\r
- // 0x80000000 Timer event without a notification function. It can be\r
- // signaled with SignalEvent() and checked with CheckEvent() or WaitForEvent().\r
- //\r
- EVT_TIMER,\r
- //\r
- // 0x00000100 Generic event with a notification function that\r
- // can be waited on with CheckEvent() or WaitForEvent()\r
- //\r
- EVT_NOTIFY_WAIT,\r
- //\r
- // 0x00000200 Generic event with a notification function that\r
- // is queue when the event is signaled with SignalEvent()\r
- //\r
- EVT_NOTIFY_SIGNAL,\r
- //\r
- // 0x00000201 ExitBootServicesEvent.\r
- //\r
- EVT_SIGNAL_EXIT_BOOT_SERVICES,\r
- //\r
- // 0x60000202 SetVirtualAddressMapEvent.\r
- //\r
- EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE,\r
-\r
- //\r
- // 0x00000000 Generic event without a notification function.\r
- // It can be signaled with SignalEvent() and checked with CheckEvent()\r
- // or WaitForEvent().\r
- //\r
- 0x00000000,\r
- //\r
- // 0x80000100 Timer event with a notification function that can be\r
- // waited on with CheckEvent() or WaitForEvent()\r
- //\r
- EVT_TIMER | EVT_NOTIFY_WAIT,\r
-};\r
-\r
-\r
-/**\r
- Enter critical section by acquiring the lock on gEventQueueLock.\r
-\r
-**/\r
-STATIC\r
-VOID\r
-CoreAcquireEventLock (\r
- VOID\r
- )\r
-{\r
- CoreAcquireLock (&gEventQueueLock);\r
-}\r
-\r
-\r
-/**\r
- Exit critical section by releasing the lock on gEventQueueLock.\r
-\r
-**/\r
-STATIC\r
-VOID\r
-CoreReleaseEventLock (\r
- VOID\r
- )\r
-{\r
- CoreReleaseLock (&gEventQueueLock);\r
-}\r
-\r
-\r
-\r
-/**\r
- Initializes "event" support and populates parts of the System and Runtime Table.\r
-\r
-\r
- @retval EFI_SUCCESS Always return success\r
-\r
-**/\r
-EFI_STATUS\r
-CoreInitializeEventServices (\r
- VOID\r
- )\r
-{\r
- UINTN Index;\r
-\r
- for (Index=0; Index <= TPL_HIGH_LEVEL; Index++) {\r
- InitializeListHead (&gEventQueue[Index]);\r
- }\r
-\r
- CoreInitializeTimer ();\r
-\r
- return EFI_SUCCESS;\r
-}\r
-\r
-\r
-\r
-/**\r
- Dispatches all pending events.\r
-\r
- @param Priority The task priority level of event notifications \r
- to dispatch\r
-\r
-**/\r
-VOID\r
-CoreDispatchEventNotifies (\r
- IN EFI_TPL Priority\r
- )\r
-{\r
- IEVENT *Event;\r
- LIST_ENTRY *Head;\r
-\r
- CoreAcquireEventLock ();\r
- ASSERT (gEventQueueLock.OwnerTpl == Priority);\r
- Head = &gEventQueue[Priority];\r
-\r
- //\r
- // Dispatch all the pending notifications\r
- //\r
- while (!IsListEmpty (Head)) {\r
-\r
- Event = CR (Head->ForwardLink, IEVENT, NotifyLink, EVENT_SIGNATURE);\r
- RemoveEntryList (&Event->NotifyLink);\r
-\r
- Event->NotifyLink.ForwardLink = NULL;\r
-\r
- //\r
- // Only clear the SIGNAL status if it is a SIGNAL type event.\r
- // WAIT type events are only cleared in CheckEvent()\r
- //\r
- if (Event->Type & EVT_NOTIFY_SIGNAL) {\r
- Event->SignalCount = 0;\r
- }\r
-\r
- CoreReleaseEventLock ();\r
-\r
- //\r
- // Notify this event\r
- //\r
- ASSERT (Event->NotifyFunction != NULL);\r
- Event->NotifyFunction (Event, Event->NotifyContext);\r
-\r
- //\r
- // Check for next pending event\r
- //\r
- CoreAcquireEventLock ();\r
- }\r
-\r
- gEventPending &= ~(1 << Priority);\r
- CoreReleaseEventLock ();\r
-}\r
-\r
-\r
-\r
-/**\r
- Queues the event's notification function to fire.\r
-\r
- @param Event The Event to notify\r
-\r
-**/\r
-STATIC\r
-VOID\r
-CoreNotifyEvent (\r
- IN IEVENT *Event\r
- )\r
-{\r
-\r
- //\r
- // Event database must be locked\r
- //\r
- ASSERT_LOCKED (&gEventQueueLock);\r
-\r
- //\r
- // If the event is queued somewhere, remove it\r
- //\r
-\r
- if (Event->NotifyLink.ForwardLink != NULL) {\r
- RemoveEntryList (&Event->NotifyLink);\r
- Event->NotifyLink.ForwardLink = NULL;\r
- }\r
-\r
- //\r
- // Queue the event to the pending notification list\r
- //\r
-\r
- InsertTailList (&gEventQueue[Event->NotifyTpl], &Event->NotifyLink);\r
- gEventPending |= (UINTN)(1 << Event->NotifyTpl);\r
-}\r
-\r
-\r
-\r
-\r
-/**\r
- Signals all events in the EventGroup.\r
-\r
- @param EventGroup The list to signal\r
-\r
-**/\r
-VOID\r
-CoreNotifySignalList (\r
- IN EFI_GUID *EventGroup\r
- )\r
-{\r
- LIST_ENTRY *Link;\r
- LIST_ENTRY *Head;\r
- IEVENT *Event;\r
-\r
- CoreAcquireEventLock ();\r
-\r
- Head = &gEventSignalQueue;\r
- for (Link = Head->ForwardLink; Link != Head; Link = Link->ForwardLink) {\r
- Event = CR (Link, IEVENT, SignalLink, EVENT_SIGNATURE);\r
- if (CompareGuid (&Event->EventGroup, EventGroup)) {\r
- CoreNotifyEvent (Event);\r
- }\r
- }\r
-\r
- CoreReleaseEventLock ();\r
-}\r
-\r
-\r
-/**\r
- Creates a general-purpose event structure.\r
-\r
- @param Type The type of event to create and its mode and \r
- attributes \r
- @param NotifyTpl The task priority level of event notifications \r
- @param NotifyFunction Pointer to the events notification function \r
- @param NotifyContext Pointer to the notification functions context; \r
- corresponds to parameter "Context" in the \r
- notification function \r
- @param Event Pointer to the newly created event if the call \r
- succeeds; undefined otherwise \r
-\r
- @retval EFI_SUCCESS The event structure was created \r
- @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value \r
- @retval EFI_OUT_OF_RESOURCES The event could not be allocated\r
-\r
-**/\r
-EFI_STATUS\r
-EFIAPI\r
-CoreCreateEvent (\r
- IN UINT32 Type,\r
- IN EFI_TPL NotifyTpl,\r
- IN EFI_EVENT_NOTIFY NotifyFunction, OPTIONAL\r
- IN VOID *NotifyContext, OPTIONAL\r
- OUT EFI_EVENT *Event\r
- )\r
-{\r
- return CoreCreateEventEx (Type, NotifyTpl, NotifyFunction, NotifyContext, NULL, Event);\r
-}\r
-\r
-\r
-\r
-/**\r
- Creates a general-purpose event structure\r
-\r
- @param Type The type of event to create and its mode and \r
- attributes \r
- @param NotifyTpl The task priority level of event notifications \r
- @param NotifyFunction Pointer to the events notification function \r
- @param NotifyContext Pointer to the notification functions context; \r
- corresponds to parameter "Context" in the \r
- notification function \r
- @param EventGroup GUID for EventGroup if NULL act the same as \r
- gBS->CreateEvent(). \r
- @param Event Pointer to the newly created event if the call \r
- succeeds; undefined otherwise \r
-\r
- @retval EFI_SUCCESS The event structure was created \r
- @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value \r
- @retval EFI_OUT_OF_RESOURCES The event could not be allocated\r
-\r
-**/\r
-EFI_STATUS\r
-EFIAPI\r
-CoreCreateEventEx (\r
- IN UINT32 Type,\r
- IN EFI_TPL NotifyTpl,\r
- IN EFI_EVENT_NOTIFY NotifyFunction, OPTIONAL\r
- IN CONST VOID *NotifyContext, OPTIONAL\r
- IN CONST EFI_GUID *EventGroup, OPTIONAL\r
- OUT EFI_EVENT *Event\r
- )\r
-{\r
- EFI_STATUS Status;\r
- IEVENT *IEvent;\r
- INTN Index;\r
-\r
-\r
- if ((Event == NULL) || (NotifyTpl == TPL_APPLICATION)) {\r
- return EFI_INVALID_PARAMETER;\r
- }\r
-\r
- //\r
- // Check to make sure no reserved flags are set\r
- //\r
- Status = EFI_INVALID_PARAMETER;\r
- for (Index = 0; Index < (sizeof (mEventTable) / sizeof (UINT32)); Index++) {\r
- if (Type == mEventTable[Index]) {\r
- Status = EFI_SUCCESS;\r
- break;\r
- }\r
- }\r
- if(EFI_ERROR (Status)) {\r
- return EFI_INVALID_PARAMETER;\r
- }\r
-\r
- //\r
- // Convert Event type for pre-defined Event groups\r
- //\r
- if (EventGroup != NULL) {\r
- //\r
- // For event group, type EVT_SIGNAL_EXIT_BOOT_SERVICES and EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE\r
- // are not valid\r
- //\r
- if ((Type == EVT_SIGNAL_EXIT_BOOT_SERVICES) || (Type == EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE)) {\r
- return EFI_INVALID_PARAMETER;\r
- }\r
- if (CompareGuid (EventGroup, &gEfiEventExitBootServicesGuid)) {\r
- Type = EVT_SIGNAL_EXIT_BOOT_SERVICES;\r
- } else if (CompareGuid (EventGroup, &gEfiEventVirtualAddressChangeGuid)) {\r
- Type = EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE;\r
- }\r
- } else {\r
- //\r
- // Convert EFI 1.10 Events to their UEFI 2.0 CreateEventEx mapping\r
- //\r
- if (Type == EVT_SIGNAL_EXIT_BOOT_SERVICES) {\r
- EventGroup = &gEfiEventExitBootServicesGuid;\r
- } else if (Type == EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE) {\r
- EventGroup = &gEfiEventVirtualAddressChangeGuid;\r
- }\r
- }\r
-\r
- //\r
- // If it's a notify type of event, check its parameters\r
- //\r
- if ((Type & (EVT_NOTIFY_WAIT | EVT_NOTIFY_SIGNAL)) != 0) {\r
- //\r
- // Check for an invalid NotifyFunction or NotifyTpl\r
- //\r
- if ((NotifyFunction == NULL) ||\r
- (NotifyTpl < TPL_APPLICATION) ||\r
- (NotifyTpl >= TPL_HIGH_LEVEL)) {\r
- return EFI_INVALID_PARAMETER;\r
- }\r
-\r
- } else {\r
- //\r
- // No notification needed, zero ignored values\r
- //\r
- NotifyTpl = 0;\r
- NotifyFunction = NULL;\r
- NotifyContext = NULL;\r
- }\r
-\r
- //\r
- // Allcoate and initialize a new event structure.\r
- //\r
- Status = CoreAllocatePool (\r
- ((Type & EVT_RUNTIME) != 0) ? EfiRuntimeServicesData: EfiBootServicesData,\r
- sizeof (IEVENT),\r
- (VOID **)&IEvent\r
- );\r
- if (EFI_ERROR (Status)) {\r
- return EFI_OUT_OF_RESOURCES;\r
- }\r
-\r
- SetMem (IEvent, sizeof (IEVENT), 0);\r
-\r
- IEvent->Signature = EVENT_SIGNATURE;\r
- IEvent->Type = Type;\r
-\r
- IEvent->NotifyTpl = NotifyTpl;\r
- IEvent->NotifyFunction = NotifyFunction;\r
- IEvent->NotifyContext = (VOID *)NotifyContext;\r
- if (EventGroup != NULL) {\r
- CopyGuid (&IEvent->EventGroup, EventGroup);\r
- IEvent->ExFlag = TRUE;\r
- }\r
-\r
- *Event = IEvent;\r
-\r
- if ((Type & EVT_RUNTIME) != 0) {\r
- //\r
- // Keep a list of all RT events so we can tell the RT AP.\r
- //\r
- IEvent->RuntimeData.Type = Type;\r
- IEvent->RuntimeData.NotifyTpl = NotifyTpl;\r
- IEvent->RuntimeData.NotifyFunction = NotifyFunction;\r
- IEvent->RuntimeData.NotifyContext = (VOID *) NotifyContext;\r
- IEvent->RuntimeData.Event = (EFI_EVENT *) IEvent;\r
- InsertTailList (&gRuntime->EventHead, &IEvent->RuntimeData.Link);\r
- }\r
-\r
- CoreAcquireEventLock ();\r
-\r
- if ((Type & EVT_NOTIFY_SIGNAL) != 0x00000000) {\r
- //\r
- // The Event's NotifyFunction must be queued whenever the event is signaled\r
- //\r
- InsertHeadList (&gEventSignalQueue, &IEvent->SignalLink);\r
- }\r
-\r
- CoreReleaseEventLock ();\r
-\r
- //\r
- // Done\r
- //\r
- return EFI_SUCCESS;\r
-}\r
-\r
-\r
-\r
-\r
-/**\r
- Signals the event. Queues the event to be notified if needed\r
-\r
- @param UserEvent The event to signal \r
-\r
- @retval EFI_INVALID_PARAMETER Parameters are not valid. \r
- @retval EFI_SUCCESS The event was signaled.\r
-\r
-**/\r
-EFI_STATUS\r
-EFIAPI\r
-CoreSignalEvent (\r
- IN EFI_EVENT UserEvent\r
- )\r
-{\r
- IEVENT *Event;\r
-\r
- Event = UserEvent;\r
-\r
- if (Event == NULL) {\r
- return EFI_INVALID_PARAMETER;\r
- }\r
-\r
- if (Event->Signature != EVENT_SIGNATURE) {\r
- return EFI_INVALID_PARAMETER;\r
- }\r
-\r
- CoreAcquireEventLock ();\r
-\r
- //\r
- // If the event is not already signalled, do so\r
- //\r
-\r
- if (Event->SignalCount == 0x00000000) {\r
- Event->SignalCount++;\r
-\r
- //\r
- // If signalling type is a notify function, queue it\r
- //\r
- if (Event->Type & EVT_NOTIFY_SIGNAL) {\r
- if (Event->ExFlag) {\r
- //\r
- // The CreateEventEx() style requires all members of the Event Group\r
- // to be signaled.\r
- //\r
- CoreReleaseEventLock ();\r
- CoreNotifySignalList (&Event->EventGroup);\r
- CoreAcquireEventLock ();\r
- } else {\r
- CoreNotifyEvent (Event);\r
- }\r
- }\r
- }\r
-\r
- CoreReleaseEventLock ();\r
- return EFI_SUCCESS;\r
-}\r
-\r
-\r
-\r
-/**\r
- Check the status of an event.\r
-\r
- @param UserEvent The event to check \r
-\r
- @retval EFI_SUCCESS The event is in the signaled state \r
- @retval EFI_NOT_READY The event is not in the signaled state \r
- @retval EFI_INVALID_PARAMETER Event is of type EVT_NOTIFY_SIGNAL\r
-\r
-**/\r
-EFI_STATUS\r
-EFIAPI\r
-CoreCheckEvent (\r
- IN EFI_EVENT UserEvent\r
- )\r
-{\r
- IEVENT *Event;\r
- EFI_STATUS Status;\r
-\r
- Event = UserEvent;\r
-\r
- if (Event == NULL) {\r
- return EFI_INVALID_PARAMETER;\r
- }\r
-\r
- if (Event->Signature != EVENT_SIGNATURE) {\r
- return EFI_INVALID_PARAMETER;\r
- }\r
-\r
- if (Event->Type & EVT_NOTIFY_SIGNAL) {\r
- return EFI_INVALID_PARAMETER;\r
- }\r
-\r
- Status = EFI_NOT_READY;\r
-\r
- if (!Event->SignalCount && (Event->Type & EVT_NOTIFY_WAIT)) {\r
-\r
- //\r
- // Queue the wait notify function\r
- //\r
-\r
- CoreAcquireEventLock ();\r
- if (!Event->SignalCount) {\r
- CoreNotifyEvent (Event);\r
- }\r
- CoreReleaseEventLock ();\r
- }\r
-\r
- //\r
- // If the even looks signalled, get the lock and clear it\r
- //\r
-\r
- if (Event->SignalCount) {\r
- CoreAcquireEventLock ();\r
-\r
- if (Event->SignalCount) {\r
- Event->SignalCount = 0;\r
- Status = EFI_SUCCESS;\r
- }\r
-\r
- CoreReleaseEventLock ();\r
- }\r
-\r
- return Status;\r
-}\r
-\r
-\r
-\r
-\r
-/**\r
- Stops execution until an event is signaled.\r
-\r
- @param NumberOfEvents The number of events in the UserEvents array \r
- @param UserEvents An array of EFI_EVENT \r
- @param UserIndex Pointer to the index of the event which \r
- satisfied the wait condition \r
-\r
- @retval EFI_SUCCESS The event indicated by Index was signaled. \r
- @retval EFI_INVALID_PARAMETER The event indicated by Index has a notification \r
- function or Event was not a valid type \r
- @retval EFI_UNSUPPORTED The current TPL is not TPL_APPLICATION\r
-\r
-**/\r
-EFI_STATUS\r
-EFIAPI\r
-CoreWaitForEvent (\r
- IN UINTN NumberOfEvents,\r
- IN EFI_EVENT *UserEvents,\r
- OUT UINTN *UserIndex\r
- )\r
-{\r
- EFI_STATUS Status;\r
- UINTN Index;\r
-\r
- //\r
- // Can only WaitForEvent at TPL_APPLICATION\r
- //\r
- if (gEfiCurrentTpl != TPL_APPLICATION) {\r
- return EFI_UNSUPPORTED;\r
- }\r
-\r
- for(;;) {\r
-\r
- for(Index = 0; Index < NumberOfEvents; Index++) {\r
-\r
- Status = CoreCheckEvent (UserEvents[Index]);\r
-\r
- //\r
- // provide index of event that caused problem\r
- //\r
- if (Status != EFI_NOT_READY) {\r
- *UserIndex = Index;\r
- return Status;\r
- }\r
- }\r
-\r
- //\r
- // This was the location of the Idle loop callback in EFI 1.x reference\r
- // code. We don't have that concept in this base at this point.\r
- //\r
- }\r
-}\r
-\r
-\r
-\r
-/**\r
- Closes an event and frees the event structure.\r
-\r
- @param UserEvent Event to close \r
-\r
- @retval EFI_INVALID_PARAMETER Parameters are not valid. \r
- @retval EFI_SUCCESS The event has been closed\r
-\r
-**/\r
-EFI_STATUS\r
-EFIAPI\r
-CoreCloseEvent (\r
- IN EFI_EVENT UserEvent\r
- )\r
-{\r
- EFI_STATUS Status;\r
- IEVENT *Event;\r
-\r
- Event = UserEvent;\r
-\r
- if (Event == NULL) {\r
- return EFI_INVALID_PARAMETER;\r
- }\r
-\r
- if (Event->Signature != EVENT_SIGNATURE) {\r
- return EFI_INVALID_PARAMETER;\r
- }\r
-\r
- //\r
- // If it's a timer event, make sure it's not pending\r
- //\r
- if (Event->Type & EVT_TIMER) {\r
- CoreSetTimer (Event, TimerCancel, 0);\r
- }\r
-\r
- CoreAcquireEventLock ();\r
-\r
- //\r
- // If the event is queued somewhere, remove it\r
- //\r
-\r
- if (Event->RuntimeData.Link.ForwardLink != NULL) {\r
- RemoveEntryList (&Event->RuntimeData.Link);\r
- }\r
-\r
- if (Event->NotifyLink.ForwardLink != NULL) {\r
- RemoveEntryList (&Event->NotifyLink);\r
- }\r
-\r
- if (Event->SignalLink.ForwardLink != NULL) {\r
- RemoveEntryList (&Event->SignalLink);\r
- }\r
-\r
- CoreReleaseEventLock ();\r
-\r
- //\r
- // If the event is registered on a protocol notify, then remove it from the protocol database\r
- //\r
- CoreUnregisterProtocolNotify (Event);\r
-\r
- Status = CoreFreePool (Event);\r
- ASSERT_EFI_ERROR (Status);\r
-\r
- return Status;\r
-}\r