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