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
CoreInsertEventTimer(IN IEVENT * Event)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
CoreCurrentSystemTime(VOID)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
CoreCheckTimers(IN EFI_EVENT CheckEvent,IN VOID * Context)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
CoreInitializeTimer(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
CoreTimerTick(IN UINT64 Duration)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
CoreSetTimer(IN EFI_EVENT UserEvent,IN EFI_TIMER_DELAY Type,IN UINT64 TriggerTime)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