From 28a00297189c323096aae8e2975de94e8549613c Mon Sep 17 00:00:00 2001 From: yshang1 Date: Wed, 4 Jul 2007 10:51:54 +0000 Subject: Check in DxeCore for Nt32 platform. Currently, it does not follow PI/UEFI2.1. git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@3045 6f19259b-4bc3-4df7-8a09-765794883524 --- MdeModulePkg/Core/Dxe/Event/event.c | 757 +++++++++++++++++++++++++++++++++ MdeModulePkg/Core/Dxe/Event/execdata.c | 51 +++ MdeModulePkg/Core/Dxe/Event/timer.c | 388 +++++++++++++++++ MdeModulePkg/Core/Dxe/Event/tpl.c | 198 +++++++++ 4 files changed, 1394 insertions(+) create mode 100644 MdeModulePkg/Core/Dxe/Event/event.c create mode 100644 MdeModulePkg/Core/Dxe/Event/execdata.c create mode 100644 MdeModulePkg/Core/Dxe/Event/timer.c create mode 100644 MdeModulePkg/Core/Dxe/Event/tpl.c (limited to 'MdeModulePkg/Core/Dxe/Event') diff --git a/MdeModulePkg/Core/Dxe/Event/event.c b/MdeModulePkg/Core/Dxe/Event/event.c new file mode 100644 index 0000000000..b3ba71de81 --- /dev/null +++ b/MdeModulePkg/Core/Dxe/Event/event.c @@ -0,0 +1,757 @@ +/*++ + +Copyright (c) 2006 - 2007, 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() + // + EVT_TIMER | EVT_NOTIFY_SIGNAL, + // + // 0x80000000 Timer event without a notification function. It can be + // signaled with SignalEvent() and checked with CheckEvent() or WaitForEvent(). + // + EVT_TIMER, + // + // 0x00000100 Generic event with a notification function that + // can be waited on with CheckEvent() or WaitForEvent() + // + EVT_NOTIFY_WAIT, + // + // 0x00000200 Generic event with a notification function that + // is queue when the event is signaled with SignalEvent() + // + EVT_NOTIFY_SIGNAL, + // + // 0x00000201 ExitBootServicesEvent. + // + EVT_SIGNAL_EXIT_BOOT_SERVICES, + // + // 0x60000202 SetVirtualAddressMapEvent. + // + EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE, + + // + // 0x00000000 Generic event without a notification function. + // It can be signaled with SignalEvent() and checked with CheckEvent() + // or WaitForEvent(). + // + 0x00000000, + // + // 0x80000100 Timer event with a notification function that can be + // waited on with CheckEvent() or WaitForEvent() + // + EVT_TIMER | EVT_NOTIFY_WAIT, +}; + +STATIC +VOID +CoreAcquireEventLock ( + VOID + ) +/*++ + +Routine Description: + + Enter critical section by acquiring the lock on gEventQueueLock. + +Arguments: + + None + +Returns: + + None + +--*/ +{ + CoreAcquireLock (&gEventQueueLock); +} + +STATIC +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 <= TPL_HIGH_LEVEL; Index++) { + InitializeListHead (&gEventQueue[Index]); + } + + CoreInitializeTimer (); + + 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 & EVT_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 (); +} + + +STATIC +VOID +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 (); +} + +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; + + // + // Convert EFI 1.10 Events to thier UEFI 2.0 CreateEventEx mapping + // + if (Type == EVT_SIGNAL_EXIT_BOOT_SERVICES) { + GuidPtr = &gEfiEventExitBootServicesGuid; + } else if (Type == EVT_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 == 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 & (EVT_NOTIFY_WAIT | EVT_NOTIFY_SIGNAL))) { + // + // Check for an invalid NotifyFunction or NotifyTpl + // + if ((NotifyFunction == NULL) || + (NotifyTpl < TPL_APPLICATION) || + (NotifyTpl >= TPL_HIGH_LEVEL)) { + return EFI_INVALID_PARAMETER; + } + + } else { + // + // No notification needed, zero ignored values + // + NotifyTpl = 0; + NotifyFunction = NULL; + NotifyContext = NULL; + } + + // + // Allcoate and initialize a new event structure. + // + Status = CoreAllocatePool ( + (Type & EVT_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 & EVT_RUNTIME) { + // + // Keep a list of all RT events so we can tell the RT AP. + // + IEvent->RuntimeData.Type = Type; + IEvent->RuntimeData.NotifyTpl = NotifyTpl; + IEvent->RuntimeData.NotifyFunction = NotifyFunction; + IEvent->RuntimeData.NotifyContext = (VOID *) NotifyContext; + IEvent->RuntimeData.Event = (EFI_EVENT *) IEvent; + InsertTailList (&gRuntime->EventHead, &IEvent->RuntimeData.Link); + } + + CoreAcquireEventLock (); + + if ((Type & EVT_NOTIFY_SIGNAL) != 0x00000000) { + // + // The Event's NotifyFunction must be queued whenever the event is signaled + // + InsertHeadList (&gEventSignalQueue, &IEvent->SignalLink); + } + + CoreReleaseEventLock (); + + // + // Done + // + return EFI_SUCCESS; +} + + + +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 & EVT_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 & EVT_NOTIFY_SIGNAL) { + return EFI_INVALID_PARAMETER; + } + + Status = EFI_NOT_READY; + + if (!Event->SignalCount && (Event->Type & EVT_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 != 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 & EVT_TIMER) { + CoreSetTimer (Event, TimerCancel, 0); + } + + CoreAcquireEventLock (); + + // + // If the event is queued somewhere, remove it + // + + if (Event->RuntimeData.Link.ForwardLink != NULL) { + RemoveEntryList (&Event->RuntimeData.Link); + } + + if (Event->NotifyLink.ForwardLink != NULL) { + RemoveEntryList (&Event->NotifyLink); + } + + if (Event->SignalLink.ForwardLink != NULL) { + RemoveEntryList (&Event->SignalLink); + } + + CoreReleaseEventLock (); + + // + // If the event is registered on a protocol notify, then remove it from the protocol database + // + CoreUnregisterProtocolNotify (Event); + + Status = CoreFreePool (Event); + ASSERT_EFI_ERROR (Status); + + return Status; +} diff --git a/MdeModulePkg/Core/Dxe/Event/execdata.c b/MdeModulePkg/Core/Dxe/Event/execdata.c new file mode 100644 index 0000000000..a6d388ac21 --- /dev/null +++ b/MdeModulePkg/Core/Dxe/Event/execdata.c @@ -0,0 +1,51 @@ +/*++ + +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: + + execdata.c + +Abstract: + + + + +Revision History + +--*/ + +#include + + +// +// gTpl - Task priority level +// +EFI_TPL gEfiCurrentTpl = TPL_APPLICATION; + + +// +// gEventQueueLock - Protects the event queus +// +EFI_LOCK gEventQueueLock = EFI_INITIALIZE_LOCK_VARIABLE (TPL_HIGH_LEVEL); + +// +// gEventQueue - A list of event's to notify for each priority level +// gEventPending - A bitmask of the EventQueues that are pending +// +LIST_ENTRY gEventQueue[TPL_HIGH_LEVEL + 1]; +UINTN gEventPending = 0; + + +// +// gEventSignalQueue - A list of events to signal based on EventGroup type +// +LIST_ENTRY gEventSignalQueue = INITIALIZE_LIST_HEAD_VARIABLE (gEventSignalQueue); + diff --git a/MdeModulePkg/Core/Dxe/Event/timer.c b/MdeModulePkg/Core/Dxe/Event/timer.c new file mode 100644 index 0000000000..0f886f96d3 --- /dev/null +++ b/MdeModulePkg/Core/Dxe/Event/timer.c @@ -0,0 +1,388 @@ +/*++ + +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: + + timer.c + +Abstract: + + EFI Event support + +Revision History + +--*/ + + +#include + +// +// Internal prototypes +// +STATIC +UINT64 +CoreCurrentSystemTime ( + VOID + ); + +STATIC +VOID +EFIAPI +CoreCheckTimers ( + IN EFI_EVENT Event, + IN VOID *Context + ); + +STATIC +VOID +CoreInsertEventTimer ( + IN IEVENT *Event + ); + +// +// Internal data +// + +static LIST_ENTRY mEfiTimerList = INITIALIZE_LIST_HEAD_VARIABLE (mEfiTimerList); +static EFI_LOCK mEfiTimerLock = EFI_INITIALIZE_LOCK_VARIABLE (TPL_HIGH_LEVEL - 1); +static EFI_EVENT mEfiCheckTimerEvent; + +static EFI_LOCK mEfiSystemTimeLock = EFI_INITIALIZE_LOCK_VARIABLE (TPL_HIGH_LEVEL); +static UINT64 mEfiSystemTime = 0; + +// +// Timer functions +// + +VOID +CoreInitializeTimer ( + VOID + ) +/*++ + +Routine Description: + + Initializes timer support + +Arguments: + + None + +Returns: + + None + +--*/ +{ + EFI_STATUS Status; + + Status = CoreCreateEvent ( + EVT_NOTIFY_SIGNAL, + TPL_HIGH_LEVEL - 1, + CoreCheckTimers, + NULL, + &mEfiCheckTimerEvent + ); + ASSERT_EFI_ERROR (Status); +} + +STATIC +UINT64 +CoreCurrentSystemTime ( + VOID + ) +/*++ + +Routine Description: + + Returns the current system time + +Arguments: + + None + +Returns: + + Returns the current system time + +--*/ +{ + UINT64 SystemTime; + + CoreAcquireLock (&mEfiSystemTimeLock); + SystemTime = mEfiSystemTime; + CoreReleaseLock (&mEfiSystemTimeLock); + return SystemTime; +} + +VOID +EFIAPI +CoreTimerTick ( + IN UINT64 Duration + ) +/*++ + +Routine Description: + + Called by the platform code to process a tick. + +Arguments: + + Duration - The number of 100ns elasped since the last call to TimerTick + +Returns: + + None + +--*/ +{ + IEVENT *Event; + + // + // Check runtiem flag in case there are ticks while exiting boot services + // + + CoreAcquireLock (&mEfiSystemTimeLock); + + // + // Update the system time + // + + mEfiSystemTime += Duration; + + // + // If the head of the list is expired, fire the timer event + // to process it + // + + if (!IsListEmpty (&mEfiTimerList)) { + Event = CR (mEfiTimerList.ForwardLink, IEVENT, u.Timer.Link, EVENT_SIGNATURE); + + if (Event->u.Timer.TriggerTime <= mEfiSystemTime) { + CoreSignalEvent (mEfiCheckTimerEvent); + } + } + + CoreReleaseLock (&mEfiSystemTimeLock); +} + +STATIC +VOID +EFIAPI +CoreCheckTimers ( + IN EFI_EVENT CheckEvent, + IN VOID *Context + ) +/*++ + +Routine Description: + + Checks the sorted timer list against the current system time. + Signals any expired event timer. + +Arguments: + + CheckEvent - Not used + + Context - Not used + +Returns: + + None + +--*/ +{ + UINT64 SystemTime; + IEVENT *Event; + + // + // Check the timer database for expired timers + // + + CoreAcquireLock (&mEfiTimerLock); + SystemTime = CoreCurrentSystemTime (); + + while (!IsListEmpty (&mEfiTimerList)) { + Event = CR (mEfiTimerList.ForwardLink, IEVENT, u.Timer.Link, EVENT_SIGNATURE); + + // + // If this timer is not expired, then we're done + // + + if (Event->u.Timer.TriggerTime > SystemTime) { + break; + } + + // + // Remove this timer from the timer queue + // + + RemoveEntryList (&Event->u.Timer.Link); + Event->u.Timer.Link.ForwardLink = NULL; + + // + // Signal it + // + CoreSignalEvent (Event); + + // + // If this is a periodic timer, set it + // + if (Event->u.Timer.Period) { + + // + // Compute the timers new trigger time + // + + Event->u.Timer.TriggerTime = Event->u.Timer.TriggerTime + Event->u.Timer.Period; + + // + // If that's before now, then reset the timer to start from now + // + if (Event->u.Timer.TriggerTime <= SystemTime) { + Event->u.Timer.TriggerTime = SystemTime; + CoreSignalEvent (mEfiCheckTimerEvent); + } + + // + // Add the timer + // + + CoreInsertEventTimer (Event); + } + } + + CoreReleaseLock (&mEfiTimerLock); +} + +STATIC +VOID +CoreInsertEventTimer ( + IN IEVENT *Event + ) +/*++ + +Routine Description: + + Inserts the timer event + +Arguments: + + Event - Points to the internal structure of timer event to be installed + +Returns: + + None + +--*/ +{ + UINT64 TriggerTime; + LIST_ENTRY *Link; + IEVENT *Event2; + + ASSERT_LOCKED (&mEfiTimerLock); + + // + // Get the timer's trigger time + // + + TriggerTime = Event->u.Timer.TriggerTime; + + // + // Insert the timer into the timer database in assending sorted order + // + + for (Link = mEfiTimerList.ForwardLink; Link != &mEfiTimerList; Link = Link->ForwardLink) { + Event2 = CR (Link, IEVENT, u.Timer.Link, EVENT_SIGNATURE); + + if (Event2->u.Timer.TriggerTime > TriggerTime) { + break; + } + } + + InsertTailList (Link, &Event->u.Timer.Link); +} + + + +EFI_STATUS +EFIAPI +CoreSetTimer ( + IN EFI_EVENT UserEvent, + IN EFI_TIMER_DELAY Type, + IN UINT64 TriggerTime + ) +/*++ + +Routine Description: + + Sets the type of timer and the trigger time for a timer event. + +Arguments: + + UserEvent - The timer event that is to be signaled at the specified time + Type - The type of time that is specified in TriggerTime + TriggerTime - The number of 100ns units until the timer expires + +Returns: + + EFI_SUCCESS - The event has been set to be signaled at the requested time + EFI_INVALID_PARAMETER - Event or Type is not valid + +--*/ +{ + IEVENT *Event; + + Event = UserEvent; + + if (Event == NULL) { + return EFI_INVALID_PARAMETER; + } + + if (Event->Signature != EVENT_SIGNATURE) { + return EFI_INVALID_PARAMETER; + } + + if (Type < 0 || Type > TimerRelative || !(Event->Type & EVT_TIMER)) { + return EFI_INVALID_PARAMETER; + } + + CoreAcquireLock (&mEfiTimerLock); + + // + // If the timer is queued to the timer database, remove it + // + + if (Event->u.Timer.Link.ForwardLink != NULL) { + RemoveEntryList (&Event->u.Timer.Link); + Event->u.Timer.Link.ForwardLink = NULL; + } + + Event->u.Timer.TriggerTime = 0; + Event->u.Timer.Period = 0; + + if (Type != TimerCancel) { + + if (Type == TimerPeriodic) { + Event->u.Timer.Period = TriggerTime; + } + + Event->u.Timer.TriggerTime = CoreCurrentSystemTime () + TriggerTime; + CoreInsertEventTimer (Event); + + if (TriggerTime == 0) { + CoreSignalEvent (mEfiCheckTimerEvent); + } + } + + CoreReleaseLock (&mEfiTimerLock); + return EFI_SUCCESS; +} diff --git a/MdeModulePkg/Core/Dxe/Event/tpl.c b/MdeModulePkg/Core/Dxe/Event/tpl.c new file mode 100644 index 0000000000..437665faed --- /dev/null +++ b/MdeModulePkg/Core/Dxe/Event/tpl.c @@ -0,0 +1,198 @@ +/*++ + +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: + + tpl.c + +Abstract: + + Task priority function + +--*/ + +#include + +STATIC +VOID +CoreSetInterruptState ( + IN BOOLEAN Enable + ) +/*++ + +Routine Description: + + Set Interrupt State + +Arguments: + + Enable - The state of enable or disable interrupt + +Returns: + + None + +--*/ + +{ + if (gCpu != NULL) { + if (Enable) { + gCpu->EnableInterrupt(gCpu); + } else { + gCpu->DisableInterrupt(gCpu); + } + } +} + +// +// Return the highest set bit +// +UINTN +CoreHighestSetBit ( + IN UINTN Number + ) +/*++ + +Routine Description: + + Return the highest set bit + +Arguments: + + Number - The value to check + +Returns: + + Bit position of the highest set bit + +--*/ +{ + UINTN msb; + + msb = 31; + while ((msb > 0) && ((Number & (UINTN)(1 << msb)) == 0)) { + msb--; + } + + return msb; +} + + + +EFI_TPL +EFIAPI +CoreRaiseTpl ( + IN EFI_TPL NewTpl + ) +/*++ + +Routine Description: + + Raise the task priority level to the new level. + High level is implemented by disabling processor interrupts. + +Arguments: + + NewTpl - New task priority level + +Returns: + + The previous task priority level + +--*/ +{ + EFI_TPL OldTpl; + + OldTpl = gEfiCurrentTpl; + ASSERT (OldTpl <= NewTpl); + ASSERT (VALID_TPL (NewTpl)); + + // + // If raising to high level, disable interrupts + // + if (NewTpl >= TPL_HIGH_LEVEL && OldTpl < TPL_HIGH_LEVEL) { + CoreSetInterruptState (FALSE); + } + + // + // Set the new value + // + gEfiCurrentTpl = NewTpl; + + return OldTpl; +} + + + +VOID +EFIAPI +CoreRestoreTpl ( + IN EFI_TPL NewTpl + ) +/*++ + +Routine Description: + + Lowers the task priority to the previous value. If the new + priority unmasks events at a higher priority, they are dispatched. + +Arguments: + + NewTpl - New, lower, task priority + +Returns: + + None + +--*/ +{ + EFI_TPL OldTpl; + + OldTpl = gEfiCurrentTpl; + ASSERT (NewTpl <= OldTpl); + ASSERT (VALID_TPL (NewTpl)); + + // + // If lowering below HIGH_LEVEL, make sure + // interrupts are enabled + // + + if (OldTpl >= TPL_HIGH_LEVEL && NewTpl < TPL_HIGH_LEVEL) { + gEfiCurrentTpl = TPL_HIGH_LEVEL; + } + + // + // Dispatch any pending events + // + + while ((-2 << NewTpl) & gEventPending) { + gEfiCurrentTpl = CoreHighestSetBit (gEventPending); + if (gEfiCurrentTpl < TPL_HIGH_LEVEL) { + CoreSetInterruptState (TRUE); + } + CoreDispatchEventNotifies (gEfiCurrentTpl); + } + + // + // Set the new value + // + + gEfiCurrentTpl = NewTpl; + + // + // If lowering below HIGH_LEVEL, make sure + // interrupts are enabled + // + if (gEfiCurrentTpl < TPL_HIGH_LEVEL) { + CoreSetInterruptState (TRUE); + } + +} -- cgit v1.2.3