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