-/*++
-
-Copyright (c) 2006, Intel Corporation
-All rights reserved. This program and the accompanying materials
-are licensed and made available under the terms and conditions of the BSD License
-which accompanies this distribution. The full text of the license may be found at
-http://opensource.org/licenses/bsd-license.php
-
-THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
-WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
-
-Module Name:
-
- event.c
-
-Abstract:
-
- EFI Event support
-
---*/
-
-
-#include <DxeMain.h>
-
-//
-// Enumerate the valid types
-//
-UINT32 mEventTable[] = {
- //
- // 0x80000200 Timer event with a notification function that is
- // queue when the event is signaled with SignalEvent()
- //
- EFI_EVENT_TIMER | EFI_EVENT_NOTIFY_SIGNAL,
- //
- // 0x80000000 Timer event without a notification function. It can be
- // signaled with SignalEvent() and checked with CheckEvent() or WaitForEvent().
- //
- EFI_EVENT_TIMER,
- //
- // 0x00000100 Generic event with a notification function that
- // can be waited on with CheckEvent() or WaitForEvent()
- //
- EFI_EVENT_NOTIFY_WAIT,
- //
- // 0x00000200 Generic event with a notification function that
- // is queue when the event is signaled with SignalEvent()
- //
- EFI_EVENT_NOTIFY_SIGNAL,
- //
- // 0x00000201 ExitBootServicesEvent.
- //
- EFI_EVENT_SIGNAL_EXIT_BOOT_SERVICES,
- //
- // 0x60000202 SetVirtualAddressMapEvent.
- //
- EFI_EVENT_SIGNAL_VIRTUAL_ADDRESS_CHANGE,
-
-#if (EFI_SPECIFICATION_VERSION < 0x00020000)
- //
- // 0x00000203 ReadyToBootEvent.
- //
- EFI_EVENT_SIGNAL_READY_TO_BOOT,
- //
- // 0x00000204 LegacyBootEvent.
- //
- EFI_EVENT_SIGNAL_LEGACY_BOOT,
- //
- // 0x00000603 Signal all ReadyToBootEvents.
- //
- EFI_EVENT_NOTIFY_SIGNAL_ALL | EFI_EVENT_SIGNAL_READY_TO_BOOT,
- //
- // 0x00000604 Signal all LegacyBootEvents.
- //
- EFI_EVENT_NOTIFY_SIGNAL_ALL | EFI_EVENT_SIGNAL_LEGACY_BOOT,
-#endif
-
- //
- // 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()
- //
- EFI_EVENT_TIMER | EFI_EVENT_NOTIFY_WAIT,
-};
-
-
-VOID
-CoreAcquireEventLock (
- VOID
- )
-/*++
-
-Routine Description:
-
- Enter critical section by acquiring the lock on gEventQueueLock.
-
-Arguments:
-
- None
-
-Returns:
-
- None
-
---*/
-{
- CoreAcquireLock (&gEventQueueLock);
-}
-
-
-VOID
-CoreReleaseEventLock (
- VOID
- )
-/*++
-
-Routine Description:
-
- Exit critical section by releasing the lock on gEventQueueLock.
-
-Arguments:
-
- None
-
-Returns:
-
- None
-
---*/
-{
- CoreReleaseLock (&gEventQueueLock);
-}
-
-
-EFI_STATUS
-CoreInitializeEventServices (
- VOID
- )
-/*++
-
-Routine Description:
-
- Initializes "event" support and populates parts of the System and Runtime Table.
-
-Arguments:
-
- None
-
-Returns:
-
- EFI_SUCCESS - Always return success
-
---*/
-{
- UINTN Index;
-
- for (Index=0; Index <= EFI_TPL_HIGH_LEVEL; Index++) {
- InitializeListHead (&gEventQueue[Index]);
- }
-
- CoreInitializeTimer ();
-
- return EFI_SUCCESS;
-}
-
-
-EFI_STATUS
-CoreShutdownEventServices (
- VOID
- )
-/*++
-
-Routine Description:
-
- Register all runtime events to make sure they are still available after ExitBootService.
-
-Arguments:
-
- None
-
-Returns:
-
- EFI_SUCCESS - Always return success.
-
---*/
-{
- LIST_ENTRY *Link;
- IEVENT *Event;
-
- //
- // The Runtime AP is required for the core to function!
- //
- ASSERT (gRuntime != NULL);
-
- for (Link = mRuntimeEventList.ForwardLink; Link != &mRuntimeEventList; Link = Link->ForwardLink) {
- Event = CR (Link, IEVENT, RuntimeLink, EVENT_SIGNATURE);
- gRuntime->RegisterEvent (
- gRuntime,
- Event->Type,
- Event->NotifyTpl,
- Event->NotifyFunction,
- Event->NotifyContext,
- (VOID **)Event
- );
- }
-
- return EFI_SUCCESS;
-}
-
-
-VOID
-CoreDispatchEventNotifies (
- IN EFI_TPL Priority
- )
-/*++
-
-Routine Description:
-
- Dispatches all pending events.
-
-Arguments:
-
- Priority - The task priority level of event notifications to dispatch
-
-Returns:
-
- None
-
---*/
-{
- 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 & EFI_EVENT_NOTIFY_SIGNAL) {
- Event->SignalCount = 0;
- }
-
- CoreReleaseEventLock ();
-
- //
- // Notify this event
- //
- ASSERT (Event->NotifyFunction != NULL);
- Event->NotifyFunction (Event, Event->NotifyContext);
-
- //
- // Check for next pending event
- //
- CoreAcquireEventLock ();
- }
-
- gEventPending &= ~(1 << Priority);
- CoreReleaseEventLock ();
-}
-
-
-VOID
-STATIC
-CoreNotifyEvent (
- IN IEVENT *Event
- )
-/*++
-
-Routine Description:
-
- Queues the event's notification function to fire
-
-Arguments:
-
- Event - The Event to notify
-
-Returns:
-
- None
-
---*/
-{
-
- //
- // 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);
-}
-
-
-
-VOID
-CoreNotifySignalList (
- IN EFI_GUID *EventGroup
- )
-/*++
-
-Routine Description:
- Signals all events in the EventGroup
-
-Arguments:
- EventGroup - The list to signal
-
-Returns:
-
- None
-
---*/
-{
- 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 ();
-}
-
-
-#if (EFI_SPECIFICATION_VERSION < 0x00020000)
-
-static
-VOID
-EFIAPI
-EventNofitySignalAllNullEvent (
- IN EFI_EVENT Event,
- IN VOID *Context
- )
-{
- //
- // This null event is a size efficent way to enusre that
- // EFI_EVENT_NOTIFY_SIGNAL_ALL is error checked correctly.
- // EFI_EVENT_NOTIFY_SIGNAL_ALL is now mapped into
- // CreateEventEx() and this function is used to make the
- // old error checking in CreateEvent() for Tiano extensions
- // function.
- //
- return;
-}
-
-#endif
-
-
-
-
-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
- )
-/*++
-
-Routine Description:
- Creates a general-purpose event structure
-
-Arguments:
- Type - The type of event to create and its mode and attributes
- NotifyTpl - The task priority level of event notifications
- NotifyFunction - Pointer to the events notification function
- NotifyContext - Pointer to the notification functions context; corresponds to
- parameter "Context" in the notification function
- Event - Pointer to the newly created event if the call succeeds; undefined otherwise
-
-Returns:
- EFI_SUCCESS - The event structure was created
- EFI_INVALID_PARAMETER - One of the parameters has an invalid value
- EFI_OUT_OF_RESOURCES - The event could not be allocated
-
---*/
-{
- EFI_GUID *GuidPtr;
- EFI_EVENT_NOTIFY Function;
-
- GuidPtr = NULL;
- Function = NotifyFunction;
-
-#if (EFI_SPECIFICATION_VERSION < 0x00020000)
- //
- // Clear EFI_EVENT_NOFITY_SIGNAL_ALL (Tiano extension) as all events in the
- // EventGroup now have this property. So we need to filter it out.
- //
- if (Type & EFI_EVENT_NOTIFY_SIGNAL_ALL) {
- Type &= ~EFI_EVENT_NOTIFY_SIGNAL_ALL;
- Function = EventNofitySignalAllNullEvent;
- }
-
- //
- // Map the Tiano extensions Events to CreateEventEx form
- //
- if (Type == EFI_EVENT_SIGNAL_READY_TO_BOOT) {
- GuidPtr = &gEfiEventReadyToBootGuid;
- } else if (Type == EFI_EVENT_SIGNAL_LEGACY_BOOT) {
- GuidPtr = &gEfiEventLegacyBootGuid
- }
-#endif
-
- //
- // Convert EFI 1.10 Events to thier UEFI 2.0 CreateEventEx mapping
- //
- if (Type == EVENT_SIGNAL_EXIT_BOOT_SERVICES) {
- GuidPtr = &gEfiEventExitBootServicesGuid;
- } else if (Type == EVENT_SIGNAL_VIRTUAL_ADDRESS_CHANGE) {
- GuidPtr = &gEfiEventVirtualAddressChangeGuid;
- }
-
- return CoreCreateEventEx (Type, NotifyTpl, Function, NotifyContext, GuidPtr, Event);
-}
-
-
-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
- )
-/*++
-
-Routine Description:
- Creates a general-purpose event structure
-
-Arguments:
- Type - The type of event to create and its mode and attributes
- NotifyTpl - The task priority level of event notifications
- NotifyFunction - Pointer to the events notification function
- NotifyContext - Pointer to the notification functions context; corresponds to
- parameter "Context" in the notification function
- EventGrout - GUID for EventGroup if NULL act the same as gBS->CreateEvent().
- Event - Pointer to the newly created event if the call succeeds; undefined otherwise
-
-Returns:
- EFI_SUCCESS - The event structure was created
- EFI_INVALID_PARAMETER - One of the parameters has an invalid value
- EFI_OUT_OF_RESOURCES - The event could not be allocated
-
---*/
-{
- EFI_STATUS Status;
- IEVENT *IEvent;
- INTN Index;
-
-
- if ((Event == NULL) || (NotifyTpl == EFI_TPL_APPLICATION)) {
- 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;
- }
-
- //
- // If it's a notify type of event, check its parameters
- //
- if ((Type & (EFI_EVENT_NOTIFY_WAIT | EFI_EVENT_NOTIFY_SIGNAL))) {
- //
- // Check for an invalid NotifyFunction or NotifyTpl
- //
- if ((NotifyFunction == NULL) ||
- (NotifyTpl < EFI_TPL_APPLICATION) ||
- (NotifyTpl >= EFI_TPL_HIGH_LEVEL)) {
- return EFI_INVALID_PARAMETER;
- }
-
- } else {
- //
- // No notification needed, zero ignored values
- //
- NotifyTpl = 0;
- NotifyFunction = NULL;
- NotifyContext = NULL;
- }
-
- //
- // Allcoate and initialize a new event structure.
- //
- Status = CoreAllocatePool (
- (Type & EFI_EVENT_RUNTIME) ? EfiRuntimeServicesData: EfiBootServicesData,
- sizeof (IEVENT),
- (VOID **)&IEvent
- );
- if (EFI_ERROR (Status)) {
- return EFI_OUT_OF_RESOURCES;
- }
-
- SetMem (IEvent, sizeof (IEVENT), 0);
-
- 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 = TRUE;
- }
-
- *Event = IEvent;
-
- if (Type & EFI_EVENT_RUNTIME) {
- //
- // Keep a list of all RT events so we can tell the RT AP.
- //
- InsertTailList (&mRuntimeEventList, &IEvent->RuntimeLink);
- }
-
- CoreAcquireEventLock ();
-
- if ((Type & EFI_EVENT_NOTIFY_SIGNAL) != 0x00000000) {
- //
- // The Event's NotifyFunction must be queued whenever the event is signaled
- //
- InsertHeadList (&gEventSignalQueue, &IEvent->SignalLink);
- }
-
- CoreReleaseEventLock ();
-
- //
- // Done
- //
- return EFI_SUCCESS;
-}
-
-
-
-EFI_STATUS
-EFIAPI
-CoreSignalEvent (
- IN EFI_EVENT UserEvent
- )
-/*++
-
-Routine Description:
-
- Signals the event. Queues the event to be notified if needed
-
-Arguments:
-
- UserEvent - The event to signal
-
-Returns:
-
- EFI_INVALID_PARAMETER - Parameters are not valid.
-
- EFI_SUCCESS - The event was signaled.
-
---*/
-{
- 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 & EFI_EVENT_NOTIFY_SIGNAL) {
- if (Event->ExFlag) {
- //
- // 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;
-}
-
-
-EFI_STATUS
-EFIAPI
-CoreCheckEvent (
- IN EFI_EVENT UserEvent
- )
-/*++
-
-Routine Description:
-
- Check the status of an event
-
-Arguments:
-
- UserEvent - The event to check
-
-Returns:
-
- EFI_SUCCESS - The event is in the signaled state
- EFI_NOT_READY - The event is not in the signaled state
- EFI_INVALID_PARAMETER - Event is of type EVT_NOTIFY_SIGNAL
-
---*/
-
-{
- 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 & EFI_EVENT_NOTIFY_SIGNAL) {
- return EFI_INVALID_PARAMETER;
- }
-
- Status = EFI_NOT_READY;
-
- if (!Event->SignalCount && (Event->Type & EFI_EVENT_NOTIFY_WAIT)) {
-
- //
- // Queue the wait notify function
- //
-
- CoreAcquireEventLock ();
- if (!Event->SignalCount) {
- CoreNotifyEvent (Event);
- }
- CoreReleaseEventLock ();
- }
-
- //
- // If the even looks signalled, get the lock and clear it
- //
-
- if (Event->SignalCount) {
- CoreAcquireEventLock ();
-
- if (Event->SignalCount) {
- Event->SignalCount = 0;
- Status = EFI_SUCCESS;
- }
-
- CoreReleaseEventLock ();
- }
-
- return Status;
-}
-
-
-
-EFI_STATUS
-EFIAPI
-CoreWaitForEvent (
- IN UINTN NumberOfEvents,
- IN EFI_EVENT *UserEvents,
- OUT UINTN *UserIndex
- )
-/*++
-
-Routine Description:
-
- Stops execution until an event is signaled.
-
-Arguments:
-
- NumberOfEvents - The number of events in the UserEvents array
- UserEvents - An array of EFI_EVENT
- UserIndex - Pointer to the index of the event which satisfied the wait condition
-
-Returns:
-
- EFI_SUCCESS - The event indicated by Index was signaled.
- EFI_INVALID_PARAMETER - The event indicated by Index has a notification function or
- Event was not a valid type
- EFI_UNSUPPORTED - The current TPL is not TPL_APPLICATION
-
---*/
-
-{
- EFI_STATUS Status;
- UINTN Index;
-
- //
- // Can only WaitForEvent at TPL_APPLICATION
- //
- if (gEfiCurrentTpl != EFI_TPL_APPLICATION) {
- return EFI_UNSUPPORTED;
- }
-
- for(;;) {
-
- for(Index = 0; Index < NumberOfEvents; Index++) {
-
- Status = CoreCheckEvent (UserEvents[Index]);
-
- //
- // provide index of event that caused problem
- //
- if (Status != EFI_NOT_READY) {
- *UserIndex = Index;
- return Status;
- }
- }
-
- //
- // This was the location of the Idle loop callback in EFI 1.x reference
- // code. We don't have that concept in this base at this point.
- //
- }
-}
-
-
-EFI_STATUS
-EFIAPI
-CoreCloseEvent (
- IN EFI_EVENT UserEvent
- )
-/*++
-
-Routine Description:
-
- Closes an event and frees the event structure.
-
-Arguments:
-
- UserEvent - Event to close
-
-Returns:
-
- EFI_INVALID_PARAMETER - Parameters are not valid.
-
- EFI_SUCCESS - The event has been closed
-
---*/
-
-{
- 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 & EFI_EVENT_TIMER) {
- CoreSetTimer (Event, TimerCancel, 0);
- }
-
- CoreAcquireEventLock ();
-
- //
- // If the event is queued somewhere, remove it
- //
-
- if (Event->RuntimeLink.ForwardLink != NULL) {
- RemoveEntryList (&Event->RuntimeLink);
- }
-
- 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
- //
- CoreUnregisterProtocolNotify (Event);
-
- Status = CoreFreePool (Event);
- ASSERT_EFI_ERROR (Status);
-
- return Status;
-}
+/*++\r
+\r
+Copyright (c) 2006, 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
+Module Name:\r
+\r
+ event.c\r
+\r
+Abstract:\r
+\r
+ EFI Event support\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
+ EFI_EVENT_TIMER | EFI_EVENT_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
+ EFI_EVENT_TIMER,\r
+ //\r
+ // 0x00000100 Generic event with a notification function that \r
+ // can be waited on with CheckEvent() or WaitForEvent()\r
+ //\r
+ EFI_EVENT_NOTIFY_WAIT,\r
+ //\r
+ // 0x00000200 Generic event with a notification function that \r
+ // is queue when the event is signaled with SignalEvent()\r
+ //\r
+ EFI_EVENT_NOTIFY_SIGNAL,\r
+ //\r
+ // 0x00000201 ExitBootServicesEvent. \r
+ //\r
+ EFI_EVENT_SIGNAL_EXIT_BOOT_SERVICES,\r
+ //\r
+ // 0x60000202 SetVirtualAddressMapEvent.\r
+ //\r
+ EFI_EVENT_SIGNAL_VIRTUAL_ADDRESS_CHANGE,\r
+\r
+#if (EFI_SPECIFICATION_VERSION < 0x00020000)\r
+ //\r
+ // 0x00000203 ReadyToBootEvent.\r
+ //\r
+ EFI_EVENT_SIGNAL_READY_TO_BOOT,\r
+ //\r
+ // 0x00000204 LegacyBootEvent.\r
+ //\r
+ EFI_EVENT_SIGNAL_LEGACY_BOOT,\r
+ //\r
+ // 0x00000603 Signal all ReadyToBootEvents.\r
+ //\r
+ EFI_EVENT_NOTIFY_SIGNAL_ALL | EFI_EVENT_SIGNAL_READY_TO_BOOT,\r
+ //\r
+ // 0x00000604 Signal all LegacyBootEvents.\r
+ //\r
+ EFI_EVENT_NOTIFY_SIGNAL_ALL | EFI_EVENT_SIGNAL_LEGACY_BOOT,\r
+#endif\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
+ EFI_EVENT_TIMER | EFI_EVENT_NOTIFY_WAIT,\r
+};\r
+\r
+\r
+VOID\r
+CoreAcquireEventLock (\r
+ VOID\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Enter critical section by acquiring the lock on gEventQueueLock.\r
+\r
+Arguments:\r
+\r
+ None\r
+\r
+Returns:\r
+\r
+ None\r
+\r
+--*/\r
+{\r
+ CoreAcquireLock (&gEventQueueLock);\r
+}\r
+\r
+\r
+VOID\r
+CoreReleaseEventLock (\r
+ VOID\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Exit critical section by releasing the lock on gEventQueueLock.\r
+\r
+Arguments:\r
+\r
+ None\r
+\r
+Returns:\r
+\r
+ None\r
+\r
+--*/\r
+{\r
+ CoreReleaseLock (&gEventQueueLock);\r
+}\r
+\r
+\r
+EFI_STATUS\r
+CoreInitializeEventServices (\r
+ VOID\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Initializes "event" support and populates parts of the System and Runtime Table.\r
+\r
+Arguments:\r
+\r
+ None\r
+ \r
+Returns:\r
+\r
+ EFI_SUCCESS - Always return success\r
+\r
+--*/\r
+{\r
+ UINTN Index;\r
+\r
+ for (Index=0; Index <= EFI_TPL_HIGH_LEVEL; Index++) {\r
+ InitializeListHead (&gEventQueue[Index]);\r
+ }\r
+\r
+ CoreInitializeTimer ();\r
+ \r
+ return EFI_SUCCESS;\r
+}\r
+\r
+\r
+EFI_STATUS\r
+CoreShutdownEventServices (\r
+ VOID\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Register all runtime events to make sure they are still available after ExitBootService.\r
+\r
+Arguments:\r
+\r
+ None\r
+ \r
+Returns:\r
+\r
+ EFI_SUCCESS - Always return success.\r
+\r
+--*/\r
+{\r
+ LIST_ENTRY *Link;\r
+ IEVENT *Event;\r
+\r
+ //\r
+ // The Runtime AP is required for the core to function!\r
+ //\r
+ ASSERT (gRuntime != NULL);\r
+\r
+ for (Link = mRuntimeEventList.ForwardLink; Link != &mRuntimeEventList; Link = Link->ForwardLink) {\r
+ Event = CR (Link, IEVENT, RuntimeLink, EVENT_SIGNATURE);\r
+ gRuntime->RegisterEvent (\r
+ gRuntime, \r
+ Event->Type, \r
+ Event->NotifyTpl, \r
+ Event->NotifyFunction, \r
+ Event->NotifyContext, \r
+ (VOID **)Event\r
+ );\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+\r
+VOID\r
+CoreDispatchEventNotifies (\r
+ IN EFI_TPL Priority\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Dispatches all pending events. \r
+\r
+Arguments:\r
+\r
+ Priority - The task priority level of event notifications to dispatch\r
+ \r
+Returns:\r
+\r
+ None\r
+\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 & EFI_EVENT_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
+VOID\r
+STATIC\r
+CoreNotifyEvent (\r
+ IN IEVENT *Event\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Queues the event's notification function to fire\r
+\r
+Arguments:\r
+\r
+ Event - The Event to notify\r
+ \r
+Returns:\r
+\r
+ None\r
+\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
+VOID\r
+CoreNotifySignalList (\r
+ IN EFI_GUID *EventGroup\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+ Signals all events in the EventGroup\r
+\r
+Arguments:\r
+ EventGroup - The list to signal\r
+ \r
+Returns:\r
+\r
+ None\r
+\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
+#if (EFI_SPECIFICATION_VERSION < 0x00020000)\r
+\r
+static\r
+VOID\r
+EFIAPI\r
+EventNofitySignalAllNullEvent (\r
+ IN EFI_EVENT Event,\r
+ IN VOID *Context\r
+ )\r
+{\r
+ //\r
+ // This null event is a size efficent way to enusre that \r
+ // EFI_EVENT_NOTIFY_SIGNAL_ALL is error checked correctly.\r
+ // EFI_EVENT_NOTIFY_SIGNAL_ALL is now mapped into \r
+ // CreateEventEx() and this function is used to make the\r
+ // old error checking in CreateEvent() for Tiano extensions\r
+ // function.\r
+ //\r
+ return;\r
+}\r
+\r
+#endif\r
+\r
+\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
+\r
+Routine Description:\r
+ Creates a general-purpose event structure\r
+\r
+Arguments:\r
+ Type - The type of event to create and its mode and attributes\r
+ NotifyTpl - The task priority level of event notifications\r
+ NotifyFunction - Pointer to the events notification function\r
+ NotifyContext - Pointer to the notification functions context; corresponds to\r
+ parameter "Context" in the notification function\r
+ Event - Pointer to the newly created event if the call succeeds; undefined otherwise\r
+\r
+Returns:\r
+ EFI_SUCCESS - The event structure was created\r
+ EFI_INVALID_PARAMETER - One of the parameters has an invalid value\r
+ EFI_OUT_OF_RESOURCES - The event could not be allocated\r
+\r
+--*/\r
+{ \r
+ EFI_GUID *GuidPtr;\r
+ EFI_EVENT_NOTIFY Function;\r
+ \r
+ GuidPtr = NULL;\r
+ Function = NotifyFunction;\r
+\r
+#if (EFI_SPECIFICATION_VERSION < 0x00020000)\r
+ //\r
+ // Clear EFI_EVENT_NOFITY_SIGNAL_ALL (Tiano extension) as all events in the \r
+ // EventGroup now have this property. So we need to filter it out.\r
+ //\r
+ if (Type & EFI_EVENT_NOTIFY_SIGNAL_ALL) {\r
+ Type &= ~EFI_EVENT_NOTIFY_SIGNAL_ALL;\r
+ Function = EventNofitySignalAllNullEvent;\r
+ }\r
+\r
+ //\r
+ // Map the Tiano extensions Events to CreateEventEx form\r
+ //\r
+ if (Type == EFI_EVENT_SIGNAL_READY_TO_BOOT) {\r
+ GuidPtr = &gEfiEventReadyToBootGuid;\r
+ } else if (Type == EFI_EVENT_SIGNAL_LEGACY_BOOT) {\r
+ GuidPtr = &gEfiEventLegacyBootGuid\r
+ }\r
+#endif\r
+\r
+ //\r
+ // Convert EFI 1.10 Events to thier UEFI 2.0 CreateEventEx mapping\r
+ // \r
+ if (Type == EVENT_SIGNAL_EXIT_BOOT_SERVICES) {\r
+ GuidPtr = &gEfiEventExitBootServicesGuid;\r
+ } else if (Type == EVENT_SIGNAL_VIRTUAL_ADDRESS_CHANGE) {\r
+ GuidPtr = &gEfiEventVirtualAddressChangeGuid;\r
+ }\r
+ \r
+ return CoreCreateEventEx (Type, NotifyTpl, Function, NotifyContext, GuidPtr, Event);\r
+}\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
+\r
+Routine Description:\r
+ Creates a general-purpose event structure\r
+\r
+Arguments:\r
+ Type - The type of event to create and its mode and attributes\r
+ NotifyTpl - The task priority level of event notifications\r
+ NotifyFunction - Pointer to the events notification function\r
+ NotifyContext - Pointer to the notification functions context; corresponds to\r
+ parameter "Context" in the notification function\r
+ EventGrout - GUID for EventGroup if NULL act the same as gBS->CreateEvent().\r
+ Event - Pointer to the newly created event if the call succeeds; undefined otherwise\r
+\r
+Returns:\r
+ EFI_SUCCESS - The event structure was created\r
+ EFI_INVALID_PARAMETER - One of the parameters has an invalid value\r
+ EFI_OUT_OF_RESOURCES - The event could not be allocated\r
+\r
+--*/\r
+{\r
+ EFI_STATUS Status;\r
+ IEVENT *IEvent;\r
+ INTN Index;\r
+\r
+\r
+ if ((Event == NULL) || (NotifyTpl == EFI_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
+ // If it's a notify type of event, check its parameters\r
+ //\r
+ if ((Type & (EFI_EVENT_NOTIFY_WAIT | EFI_EVENT_NOTIFY_SIGNAL))) {\r
+ //\r
+ // Check for an invalid NotifyFunction or NotifyTpl\r
+ //\r
+ if ((NotifyFunction == NULL) || \r
+ (NotifyTpl < EFI_TPL_APPLICATION) || \r
+ (NotifyTpl >= EFI_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 & EFI_EVENT_RUNTIME) ? 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 & EFI_EVENT_RUNTIME) {\r
+ //\r
+ // Keep a list of all RT events so we can tell the RT AP.\r
+ //\r
+ InsertTailList (&mRuntimeEventList, &IEvent->RuntimeLink);\r
+ }\r
+\r
+ CoreAcquireEventLock ();\r
+ \r
+ if ((Type & EFI_EVENT_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
+EFI_STATUS\r
+EFIAPI\r
+CoreSignalEvent (\r
+ IN EFI_EVENT UserEvent\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Signals the event. Queues the event to be notified if needed\r
+ \r
+Arguments:\r
+\r
+ UserEvent - The event to signal\r
+ \r
+Returns:\r
+\r
+ EFI_INVALID_PARAMETER - Parameters are not valid.\r
+ \r
+ EFI_SUCCESS - The event was signaled.\r
+\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 & EFI_EVENT_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
+EFI_STATUS\r
+EFIAPI\r
+CoreCheckEvent (\r
+ IN EFI_EVENT UserEvent\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Check the status of an event\r
+ \r
+Arguments:\r
+\r
+ UserEvent - The event to check\r
+ \r
+Returns:\r
+\r
+ EFI_SUCCESS - The event is in the signaled state\r
+ EFI_NOT_READY - The event is not in the signaled state\r
+ EFI_INVALID_PARAMETER - Event is of type EVT_NOTIFY_SIGNAL\r
+\r
+--*/\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 & EFI_EVENT_NOTIFY_SIGNAL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ Status = EFI_NOT_READY;\r
+\r
+ if (!Event->SignalCount && (Event->Type & EFI_EVENT_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
+EFI_STATUS\r
+EFIAPI\r
+CoreWaitForEvent (\r
+ IN UINTN NumberOfEvents,\r
+ IN EFI_EVENT *UserEvents,\r
+ OUT UINTN *UserIndex\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Stops execution until an event is signaled.\r
+ \r
+Arguments:\r
+\r
+ NumberOfEvents - The number of events in the UserEvents array\r
+ UserEvents - An array of EFI_EVENT\r
+ UserIndex - Pointer to the index of the event which satisfied the wait condition\r
+ \r
+Returns:\r
+\r
+ EFI_SUCCESS - The event indicated by Index was signaled.\r
+ EFI_INVALID_PARAMETER - The event indicated by Index has a notification function or \r
+ Event was not a valid type\r
+ EFI_UNSUPPORTED - The current TPL is not TPL_APPLICATION\r
+\r
+--*/\r
+\r
+{\r
+ EFI_STATUS Status;\r
+ UINTN Index;\r
+\r
+ //\r
+ // Can only WaitForEvent at TPL_APPLICATION\r
+ //\r
+ if (gEfiCurrentTpl != EFI_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
+EFI_STATUS\r
+EFIAPI\r
+CoreCloseEvent (\r
+ IN EFI_EVENT UserEvent\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Closes an event and frees the event structure.\r
+ \r
+Arguments:\r
+\r
+ UserEvent - Event to close\r
+ \r
+Returns:\r
+\r
+ EFI_INVALID_PARAMETER - Parameters are not valid.\r
+ \r
+ EFI_SUCCESS - The event has been closed\r
+\r
+--*/\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 & EFI_EVENT_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->RuntimeLink.ForwardLink != NULL) {\r
+ RemoveEntryList (&Event->RuntimeLink);\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