From 6652e7be388d5383ee889dbb09353baa8fb22656 Mon Sep 17 00:00:00 2001 From: alfred Date: Tue, 6 Jun 2006 06:28:47 +0000 Subject: [PATCH] git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@430 6f19259b-4bc3-4df7-8a09-765794883524 --- EdkModulePkg/Core/Dxe/Event/event.c | 1724 +++++++++++++-------------- 1 file changed, 862 insertions(+), 862 deletions(-) diff --git a/EdkModulePkg/Core/Dxe/Event/event.c b/EdkModulePkg/Core/Dxe/Event/event.c index 6751b18e6f..ae6b0a849d 100644 --- a/EdkModulePkg/Core/Dxe/Event/event.c +++ b/EdkModulePkg/Core/Dxe/Event/event.c @@ -1,862 +1,862 @@ -/*++ - -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 - -// -// 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; -} +/*++ + +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 + +// +// 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; +}