mirror of https://github.com/acidanthera/audk.git
387 lines
7.4 KiB
C
387 lines
7.4 KiB
C
|
/*++
|
||
|
|
||
|
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 <DxeMain.h>
|
||
|
|
||
|
//
|
||
|
// Internal prototypes
|
||
|
//
|
||
|
STATIC
|
||
|
UINT64
|
||
|
CoreCurrentSystemTime (
|
||
|
VOID
|
||
|
);
|
||
|
|
||
|
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 (EFI_TPL_HIGH_LEVEL - 1);
|
||
|
static EFI_EVENT mEfiCheckTimerEvent;
|
||
|
|
||
|
static EFI_LOCK mEfiSystemTimeLock = EFI_INITIALIZE_LOCK_VARIABLE (EFI_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 (
|
||
|
EFI_EVENT_NOTIFY_SIGNAL,
|
||
|
EFI_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);
|
||
|
}
|
||
|
|
||
|
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 & EFI_EVENT_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;
|
||
|
}
|