]> git.proxmox.com Git - mirror_edk2.git/blame - EdkModulePkg/Core/Dxe/Event/timer.c
Add some definitions for efi event in Uefi/UefiSpec.h to follow spec.
[mirror_edk2.git] / EdkModulePkg / Core / Dxe / Event / timer.c
CommitLineData
878ddf1f 1/*++\r
2\r
93b0fbc8 3Copyright (c) 2006, Intel Corporation\r
4All rights reserved. This program and the accompanying materials\r
5are licensed and made available under the terms and conditions of the BSD License\r
6which accompanies this distribution. The full text of the license may be found at\r
7http://opensource.org/licenses/bsd-license.php\r
8\r
9THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
10WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
878ddf1f 11\r
12Module Name:\r
93b0fbc8 13\r
878ddf1f 14 timer.c\r
15\r
16Abstract:\r
17\r
18 EFI Event support\r
19\r
20Revision History\r
21\r
22--*/\r
23\r
24\r
25#include <DxeMain.h>\r
26\r
27//\r
28// Internal prototypes\r
29//\r
30STATIC\r
31UINT64\r
32CoreCurrentSystemTime (\r
33 VOID\r
34 );\r
35\r
92dda53e 36STATIC\r
878ddf1f 37VOID\r
38EFIAPI\r
39CoreCheckTimers (\r
40 IN EFI_EVENT Event,\r
41 IN VOID *Context\r
42 );\r
43\r
44STATIC\r
45VOID\r
46CoreInsertEventTimer (\r
47 IN IEVENT *Event\r
48 );\r
49\r
50//\r
51// Internal data\r
52//\r
53\r
54static LIST_ENTRY mEfiTimerList = INITIALIZE_LIST_HEAD_VARIABLE (mEfiTimerList);\r
93b0fbc8 55static EFI_LOCK mEfiTimerLock = EFI_INITIALIZE_LOCK_VARIABLE (TPL_HIGH_LEVEL - 1);\r
878ddf1f 56static EFI_EVENT mEfiCheckTimerEvent;\r
57\r
93b0fbc8 58static EFI_LOCK mEfiSystemTimeLock = EFI_INITIALIZE_LOCK_VARIABLE (TPL_HIGH_LEVEL);\r
878ddf1f 59static UINT64 mEfiSystemTime = 0;\r
60\r
61//\r
62// Timer functions\r
63//\r
64\r
65VOID\r
66CoreInitializeTimer (\r
67 VOID\r
68 )\r
69/*++\r
70\r
71Routine Description:\r
72\r
73 Initializes timer support\r
74\r
75Arguments:\r
76\r
77 None\r
93b0fbc8 78\r
878ddf1f 79Returns:\r
80\r
81 None\r
82\r
83--*/\r
84{\r
85 EFI_STATUS Status;\r
86\r
87 Status = CoreCreateEvent (\r
93b0fbc8 88 EVT_NOTIFY_SIGNAL,\r
89 TPL_HIGH_LEVEL - 1,\r
878ddf1f 90 CoreCheckTimers,\r
91 NULL,\r
92 &mEfiCheckTimerEvent\r
93 );\r
94 ASSERT_EFI_ERROR (Status);\r
95}\r
96\r
97STATIC\r
98UINT64\r
99CoreCurrentSystemTime (\r
100 VOID\r
101 )\r
102/*++\r
103\r
104Routine Description:\r
105\r
106 Returns the current system time\r
107\r
108Arguments:\r
109\r
110 None\r
93b0fbc8 111\r
878ddf1f 112Returns:\r
113\r
114 Returns the current system time\r
115\r
116--*/\r
117{\r
118 UINT64 SystemTime;\r
119\r
120 CoreAcquireLock (&mEfiSystemTimeLock);\r
121 SystemTime = mEfiSystemTime;\r
122 CoreReleaseLock (&mEfiSystemTimeLock);\r
123 return SystemTime;\r
124}\r
125\r
126VOID\r
127EFIAPI\r
128CoreTimerTick (\r
129 IN UINT64 Duration\r
130 )\r
131/*++\r
132\r
133Routine Description:\r
134\r
135 Called by the platform code to process a tick.\r
136\r
137Arguments:\r
138\r
139 Duration - The number of 100ns elasped since the last call to TimerTick\r
93b0fbc8 140\r
878ddf1f 141Returns:\r
142\r
143 None\r
144\r
145--*/\r
146{\r
147 IEVENT *Event;\r
148\r
149 //\r
150 // Check runtiem flag in case there are ticks while exiting boot services\r
151 //\r
152\r
153 CoreAcquireLock (&mEfiSystemTimeLock);\r
154\r
155 //\r
156 // Update the system time\r
157 //\r
158\r
159 mEfiSystemTime += Duration;\r
160\r
161 //\r
162 // If the head of the list is expired, fire the timer event\r
163 // to process it\r
164 //\r
165\r
166 if (!IsListEmpty (&mEfiTimerList)) {\r
167 Event = CR (mEfiTimerList.ForwardLink, IEVENT, u.Timer.Link, EVENT_SIGNATURE);\r
168\r
169 if (Event->u.Timer.TriggerTime <= mEfiSystemTime) {\r
170 CoreSignalEvent (mEfiCheckTimerEvent);\r
171 }\r
172 }\r
173\r
174 CoreReleaseLock (&mEfiSystemTimeLock);\r
175}\r
176\r
92dda53e 177STATIC\r
878ddf1f 178VOID\r
179EFIAPI\r
180CoreCheckTimers (\r
181 IN EFI_EVENT CheckEvent,\r
182 IN VOID *Context\r
183 )\r
184/*++\r
185\r
186Routine Description:\r
187\r
188 Checks the sorted timer list against the current system time.\r
189 Signals any expired event timer.\r
190\r
191Arguments:\r
192\r
193 CheckEvent - Not used\r
194\r
195 Context - Not used\r
196\r
197Returns:\r
198\r
199 None\r
200\r
201--*/\r
202{\r
203 UINT64 SystemTime;\r
204 IEVENT *Event;\r
205\r
206 //\r
207 // Check the timer database for expired timers\r
208 //\r
209\r
210 CoreAcquireLock (&mEfiTimerLock);\r
211 SystemTime = CoreCurrentSystemTime ();\r
212\r
213 while (!IsListEmpty (&mEfiTimerList)) {\r
214 Event = CR (mEfiTimerList.ForwardLink, IEVENT, u.Timer.Link, EVENT_SIGNATURE);\r
215\r
216 //\r
217 // If this timer is not expired, then we're done\r
218 //\r
219\r
220 if (Event->u.Timer.TriggerTime > SystemTime) {\r
221 break;\r
222 }\r
223\r
224 //\r
225 // Remove this timer from the timer queue\r
226 //\r
227\r
228 RemoveEntryList (&Event->u.Timer.Link);\r
229 Event->u.Timer.Link.ForwardLink = NULL;\r
230\r
231 //\r
232 // Signal it\r
233 //\r
234 CoreSignalEvent (Event);\r
235\r
236 //\r
237 // If this is a periodic timer, set it\r
238 //\r
239 if (Event->u.Timer.Period) {\r
240\r
241 //\r
242 // Compute the timers new trigger time\r
243 //\r
244\r
245 Event->u.Timer.TriggerTime = Event->u.Timer.TriggerTime + Event->u.Timer.Period;\r
246\r
247 //\r
248 // If that's before now, then reset the timer to start from now\r
249 //\r
250 if (Event->u.Timer.TriggerTime <= SystemTime) {\r
251 Event->u.Timer.TriggerTime = SystemTime;\r
252 CoreSignalEvent (mEfiCheckTimerEvent);\r
253 }\r
254\r
255 //\r
256 // Add the timer\r
257 //\r
258\r
259 CoreInsertEventTimer (Event);\r
260 }\r
261 }\r
262\r
263 CoreReleaseLock (&mEfiTimerLock);\r
264}\r
265\r
266STATIC\r
267VOID\r
268CoreInsertEventTimer (\r
269 IN IEVENT *Event\r
270 )\r
271/*++\r
272\r
273Routine Description:\r
274\r
275 Inserts the timer event\r
276\r
277Arguments:\r
278\r
279 Event - Points to the internal structure of timer event to be installed\r
280\r
281Returns:\r
282\r
283 None\r
284\r
285--*/\r
286{\r
287 UINT64 TriggerTime;\r
288 LIST_ENTRY *Link;\r
289 IEVENT *Event2;\r
290\r
291 ASSERT_LOCKED (&mEfiTimerLock);\r
292\r
293 //\r
294 // Get the timer's trigger time\r
295 //\r
296\r
297 TriggerTime = Event->u.Timer.TriggerTime;\r
298\r
299 //\r
300 // Insert the timer into the timer database in assending sorted order\r
301 //\r
302\r
303 for (Link = mEfiTimerList.ForwardLink; Link != &mEfiTimerList; Link = Link->ForwardLink) {\r
304 Event2 = CR (Link, IEVENT, u.Timer.Link, EVENT_SIGNATURE);\r
305\r
306 if (Event2->u.Timer.TriggerTime > TriggerTime) {\r
307 break;\r
308 }\r
309 }\r
310\r
311 InsertTailList (Link, &Event->u.Timer.Link);\r
312}\r
313\r
314\r
315\r
316EFI_STATUS\r
317EFIAPI\r
318CoreSetTimer (\r
319 IN EFI_EVENT UserEvent,\r
320 IN EFI_TIMER_DELAY Type,\r
321 IN UINT64 TriggerTime\r
322 )\r
323/*++\r
324\r
325Routine Description:\r
326\r
327 Sets the type of timer and the trigger time for a timer event.\r
328\r
329Arguments:\r
330\r
331 UserEvent - The timer event that is to be signaled at the specified time\r
332 Type - The type of time that is specified in TriggerTime\r
333 TriggerTime - The number of 100ns units until the timer expires\r
93b0fbc8 334\r
878ddf1f 335Returns:\r
336\r
337 EFI_SUCCESS - The event has been set to be signaled at the requested time\r
338 EFI_INVALID_PARAMETER - Event or Type is not valid\r
339\r
93b0fbc8 340--*/\r
878ddf1f 341{\r
342 IEVENT *Event;\r
93b0fbc8 343\r
878ddf1f 344 Event = UserEvent;\r
345\r
346 if (Event == NULL) {\r
347 return EFI_INVALID_PARAMETER;\r
348 }\r
349\r
350 if (Event->Signature != EVENT_SIGNATURE) {\r
351 return EFI_INVALID_PARAMETER;\r
352 }\r
353\r
93b0fbc8 354 if (Type < 0 || Type > TimerRelative || !(Event->Type & EVT_TIMER)) {\r
878ddf1f 355 return EFI_INVALID_PARAMETER;\r
356 }\r
93b0fbc8 357\r
878ddf1f 358 CoreAcquireLock (&mEfiTimerLock);\r
359\r
360 //\r
361 // If the timer is queued to the timer database, remove it\r
362 //\r
363\r
364 if (Event->u.Timer.Link.ForwardLink != NULL) {\r
365 RemoveEntryList (&Event->u.Timer.Link);\r
366 Event->u.Timer.Link.ForwardLink = NULL;\r
367 }\r
368\r
369 Event->u.Timer.TriggerTime = 0;\r
370 Event->u.Timer.Period = 0;\r
371\r
372 if (Type != TimerCancel) {\r
373\r
374 if (Type == TimerPeriodic) {\r
375 Event->u.Timer.Period = TriggerTime;\r
376 }\r
377\r
378 Event->u.Timer.TriggerTime = CoreCurrentSystemTime () + TriggerTime;\r
379 CoreInsertEventTimer (Event);\r
380\r
381 if (TriggerTime == 0) {\r
382 CoreSignalEvent (mEfiCheckTimerEvent);\r
383 }\r
384 }\r
385\r
386 CoreReleaseLock (&mEfiTimerLock);\r
387 return EFI_SUCCESS;\r
388}\r