Home | History | Annotate | Download | only in Event
      1 /** @file
      2   Core Timer Services
      3 
      4 Copyright (c) 2006 - 2013, Intel Corporation. All rights reserved.<BR>
      5 This program and the accompanying materials
      6 are licensed and made available under the terms and conditions of the BSD License
      7 which accompanies this distribution.  The full text of the license may be found at
      8 http://opensource.org/licenses/bsd-license.php
      9 
     10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
     11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     12 
     13 **/
     14 
     15 
     16 #include "DxeMain.h"
     17 #include "Event.h"
     18 
     19 //
     20 // Internal data
     21 //
     22 
     23 LIST_ENTRY       mEfiTimerList = INITIALIZE_LIST_HEAD_VARIABLE (mEfiTimerList);
     24 EFI_LOCK         mEfiTimerLock = EFI_INITIALIZE_LOCK_VARIABLE (TPL_HIGH_LEVEL - 1);
     25 EFI_EVENT        mEfiCheckTimerEvent = NULL;
     26 
     27 EFI_LOCK         mEfiSystemTimeLock = EFI_INITIALIZE_LOCK_VARIABLE (TPL_HIGH_LEVEL);
     28 UINT64           mEfiSystemTime = 0;
     29 
     30 //
     31 // Timer functions
     32 //
     33 /**
     34   Inserts the timer event.
     35 
     36   @param  Event                  Points to the internal structure of timer event
     37                                  to be installed
     38 
     39 **/
     40 VOID
     41 CoreInsertEventTimer (
     42   IN IEVENT   *Event
     43   )
     44 {
     45   UINT64          TriggerTime;
     46   LIST_ENTRY      *Link;
     47   IEVENT          *Event2;
     48 
     49   ASSERT_LOCKED (&mEfiTimerLock);
     50 
     51   //
     52   // Get the timer's trigger time
     53   //
     54   TriggerTime = Event->Timer.TriggerTime;
     55 
     56   //
     57   // Insert the timer into the timer database in assending sorted order
     58   //
     59   for (Link = mEfiTimerList.ForwardLink; Link != &mEfiTimerList; Link = Link->ForwardLink) {
     60     Event2 = CR (Link, IEVENT, Timer.Link, EVENT_SIGNATURE);
     61 
     62     if (Event2->Timer.TriggerTime > TriggerTime) {
     63       break;
     64     }
     65   }
     66 
     67   InsertTailList (Link, &Event->Timer.Link);
     68 }
     69 
     70 /**
     71   Returns the current system time.
     72 
     73   @return The current system time
     74 
     75 **/
     76 UINT64
     77 CoreCurrentSystemTime (
     78   VOID
     79   )
     80 {
     81   UINT64          SystemTime;
     82 
     83   CoreAcquireLock (&mEfiSystemTimeLock);
     84   SystemTime = mEfiSystemTime;
     85   CoreReleaseLock (&mEfiSystemTimeLock);
     86 
     87   return SystemTime;
     88 }
     89 
     90 /**
     91   Checks the sorted timer list against the current system time.
     92   Signals any expired event timer.
     93 
     94   @param  CheckEvent             Not used
     95   @param  Context                Not used
     96 
     97 **/
     98 VOID
     99 EFIAPI
    100 CoreCheckTimers (
    101   IN EFI_EVENT            CheckEvent,
    102   IN VOID                 *Context
    103   )
    104 {
    105   UINT64                  SystemTime;
    106   IEVENT                  *Event;
    107 
    108   //
    109   // Check the timer database for expired timers
    110   //
    111   CoreAcquireLock (&mEfiTimerLock);
    112   SystemTime = CoreCurrentSystemTime ();
    113 
    114   while (!IsListEmpty (&mEfiTimerList)) {
    115     Event = CR (mEfiTimerList.ForwardLink, IEVENT, Timer.Link, EVENT_SIGNATURE);
    116 
    117     //
    118     // If this timer is not expired, then we're done
    119     //
    120     if (Event->Timer.TriggerTime > SystemTime) {
    121       break;
    122     }
    123 
    124     //
    125     // Remove this timer from the timer queue
    126     //
    127 
    128     RemoveEntryList (&Event->Timer.Link);
    129     Event->Timer.Link.ForwardLink = NULL;
    130 
    131     //
    132     // Signal it
    133     //
    134     CoreSignalEvent (Event);
    135 
    136     //
    137     // If this is a periodic timer, set it
    138     //
    139     if (Event->Timer.Period != 0) {
    140       //
    141       // Compute the timers new trigger time
    142       //
    143       Event->Timer.TriggerTime = Event->Timer.TriggerTime + Event->Timer.Period;
    144 
    145       //
    146       // If that's before now, then reset the timer to start from now
    147       //
    148       if (Event->Timer.TriggerTime <= SystemTime) {
    149         Event->Timer.TriggerTime = SystemTime;
    150         CoreSignalEvent (mEfiCheckTimerEvent);
    151       }
    152 
    153       //
    154       // Add the timer
    155       //
    156       CoreInsertEventTimer (Event);
    157     }
    158   }
    159 
    160   CoreReleaseLock (&mEfiTimerLock);
    161 }
    162 
    163 
    164 /**
    165   Initializes timer support.
    166 
    167 **/
    168 VOID
    169 CoreInitializeTimer (
    170   VOID
    171   )
    172 {
    173   EFI_STATUS  Status;
    174 
    175   Status = CoreCreateEventInternal (
    176              EVT_NOTIFY_SIGNAL,
    177              TPL_HIGH_LEVEL - 1,
    178              CoreCheckTimers,
    179              NULL,
    180              NULL,
    181              &mEfiCheckTimerEvent
    182              );
    183   ASSERT_EFI_ERROR (Status);
    184 }
    185 
    186 
    187 /**
    188   Called by the platform code to process a tick.
    189 
    190   @param  Duration               The number of 100ns elasped since the last call
    191                                  to TimerTick
    192 
    193 **/
    194 VOID
    195 EFIAPI
    196 CoreTimerTick (
    197   IN UINT64   Duration
    198   )
    199 {
    200   IEVENT          *Event;
    201 
    202   //
    203   // Check runtiem flag in case there are ticks while exiting boot services
    204   //
    205   CoreAcquireLock (&mEfiSystemTimeLock);
    206 
    207   //
    208   // Update the system time
    209   //
    210   mEfiSystemTime += Duration;
    211 
    212   //
    213   // If the head of the list is expired, fire the timer event
    214   // to process it
    215   //
    216   if (!IsListEmpty (&mEfiTimerList)) {
    217     Event = CR (mEfiTimerList.ForwardLink, IEVENT, Timer.Link, EVENT_SIGNATURE);
    218 
    219     if (Event->Timer.TriggerTime <= mEfiSystemTime) {
    220       CoreSignalEvent (mEfiCheckTimerEvent);
    221     }
    222   }
    223 
    224   CoreReleaseLock (&mEfiSystemTimeLock);
    225 }
    226 
    227 
    228 
    229 /**
    230   Sets the type of timer and the trigger time for a timer event.
    231 
    232   @param  UserEvent              The timer event that is to be signaled at the
    233                                  specified time
    234   @param  Type                   The type of time that is specified in
    235                                  TriggerTime
    236   @param  TriggerTime            The number of 100ns units until the timer
    237                                  expires
    238 
    239   @retval EFI_SUCCESS            The event has been set to be signaled at the
    240                                  requested time
    241   @retval EFI_INVALID_PARAMETER  Event or Type is not valid
    242 
    243 **/
    244 EFI_STATUS
    245 EFIAPI
    246 CoreSetTimer (
    247   IN EFI_EVENT            UserEvent,
    248   IN EFI_TIMER_DELAY      Type,
    249   IN UINT64               TriggerTime
    250   )
    251 {
    252   IEVENT      *Event;
    253 
    254   Event = UserEvent;
    255 
    256   if (Event == NULL) {
    257     return EFI_INVALID_PARAMETER;
    258   }
    259 
    260   if (Event->Signature != EVENT_SIGNATURE) {
    261     return EFI_INVALID_PARAMETER;
    262   }
    263 
    264   if ((UINT32)Type > TimerRelative  || (Event->Type & EVT_TIMER) == 0) {
    265     return EFI_INVALID_PARAMETER;
    266   }
    267 
    268   CoreAcquireLock (&mEfiTimerLock);
    269 
    270   //
    271   // If the timer is queued to the timer database, remove it
    272   //
    273   if (Event->Timer.Link.ForwardLink != NULL) {
    274     RemoveEntryList (&Event->Timer.Link);
    275     Event->Timer.Link.ForwardLink = NULL;
    276   }
    277 
    278   Event->Timer.TriggerTime = 0;
    279   Event->Timer.Period = 0;
    280 
    281   if (Type != TimerCancel) {
    282 
    283     if (Type == TimerPeriodic) {
    284       if (TriggerTime == 0) {
    285         gTimer->GetTimerPeriod (gTimer, &TriggerTime);
    286       }
    287       Event->Timer.Period = TriggerTime;
    288     }
    289 
    290     Event->Timer.TriggerTime = CoreCurrentSystemTime () + TriggerTime;
    291     CoreInsertEventTimer (Event);
    292 
    293     if (TriggerTime == 0) {
    294       CoreSignalEvent (mEfiCheckTimerEvent);
    295     }
    296   }
    297 
    298   CoreReleaseLock (&mEfiTimerLock);
    299 
    300   return EFI_SUCCESS;
    301 }
    302