]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Core/Dxe/Event/Event.c
Update to fix minor coding style issues.
[mirror_edk2.git] / MdeModulePkg / Core / Dxe / Event / Event.c
CommitLineData
23c98c94 1/** @file\r
504214c4
LG
2 UEFI Event support functions implemented in this file.\r
3\r
23c98c94 4Copyright (c) 2006 - 2008, Intel Corporation. <BR>\r
28a00297 5All rights reserved. This program and the accompanying materials\r
6are licensed and made available under the terms and conditions of the BSD License\r
7which accompanies this distribution. The full text of the license may be found at\r
8http://opensource.org/licenses/bsd-license.php\r
9\r
10THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
11WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
12\r
504214c4 13**/\r
28a00297 14\r
15\r
16#include <DxeMain.h>\r
17\r
18//\r
19// Enumerate the valid types\r
20//\r
21UINT32 mEventTable[] = {\r
22 //\r
23 // 0x80000200 Timer event with a notification function that is\r
24 // queue when the event is signaled with SignalEvent()\r
25 //\r
26 EVT_TIMER | EVT_NOTIFY_SIGNAL,\r
27 //\r
28 // 0x80000000 Timer event without a notification function. It can be\r
29 // signaled with SignalEvent() and checked with CheckEvent() or WaitForEvent().\r
30 //\r
31 EVT_TIMER,\r
32 //\r
33 // 0x00000100 Generic event with a notification function that\r
34 // can be waited on with CheckEvent() or WaitForEvent()\r
35 //\r
36 EVT_NOTIFY_WAIT,\r
37 //\r
38 // 0x00000200 Generic event with a notification function that\r
39 // is queue when the event is signaled with SignalEvent()\r
40 //\r
41 EVT_NOTIFY_SIGNAL,\r
42 //\r
43 // 0x00000201 ExitBootServicesEvent.\r
44 //\r
45 EVT_SIGNAL_EXIT_BOOT_SERVICES,\r
46 //\r
47 // 0x60000202 SetVirtualAddressMapEvent.\r
48 //\r
49 EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE,\r
50\r
51 //\r
52 // 0x00000000 Generic event without a notification function.\r
53 // It can be signaled with SignalEvent() and checked with CheckEvent()\r
54 // or WaitForEvent().\r
55 //\r
56 0x00000000,\r
57 //\r
58 // 0x80000100 Timer event with a notification function that can be\r
59 // waited on with CheckEvent() or WaitForEvent()\r
60 //\r
61 EVT_TIMER | EVT_NOTIFY_WAIT,\r
62};\r
63\r
162ed594 64\r
65/**\r
66 Enter critical section by acquiring the lock on gEventQueueLock.\r
67\r
68**/\r
28a00297 69VOID\r
70CoreAcquireEventLock (\r
71 VOID\r
72 )\r
28a00297 73{\r
74 CoreAcquireLock (&gEventQueueLock);\r
75}\r
76\r
162ed594 77\r
78/**\r
79 Exit critical section by releasing the lock on gEventQueueLock.\r
80\r
81**/\r
28a00297 82VOID\r
83CoreReleaseEventLock (\r
84 VOID\r
85 )\r
28a00297 86{\r
87 CoreReleaseLock (&gEventQueueLock);\r
88}\r
89\r
90\r
28a00297 91\r
162ed594 92/**\r
28a00297 93 Initializes "event" support and populates parts of the System and Runtime Table.\r
94\r
28a00297 95\r
162ed594 96 @retval EFI_SUCCESS Always return success\r
28a00297 97\r
162ed594 98**/\r
99EFI_STATUS\r
100CoreInitializeEventServices (\r
101 VOID\r
102 )\r
28a00297 103{\r
104 UINTN Index;\r
105\r
106 for (Index=0; Index <= TPL_HIGH_LEVEL; Index++) {\r
107 InitializeListHead (&gEventQueue[Index]);\r
108 }\r
109\r
110 CoreInitializeTimer ();\r
111\r
112 return EFI_SUCCESS;\r
113}\r
114\r
115\r
28a00297 116\r
162ed594 117/**\r
28a00297 118 Dispatches all pending events.\r
119\r
162ed594 120 @param Priority The task priority level of event notifications \r
121 to dispatch\r
28a00297 122\r
162ed594 123**/\r
124VOID\r
125CoreDispatchEventNotifies (\r
126 IN EFI_TPL Priority\r
127 )\r
28a00297 128{\r
129 IEVENT *Event;\r
130 LIST_ENTRY *Head;\r
131\r
132 CoreAcquireEventLock ();\r
133 ASSERT (gEventQueueLock.OwnerTpl == Priority);\r
134 Head = &gEventQueue[Priority];\r
135\r
136 //\r
137 // Dispatch all the pending notifications\r
138 //\r
139 while (!IsListEmpty (Head)) {\r
140\r
141 Event = CR (Head->ForwardLink, IEVENT, NotifyLink, EVENT_SIGNATURE);\r
142 RemoveEntryList (&Event->NotifyLink);\r
143\r
144 Event->NotifyLink.ForwardLink = NULL;\r
145\r
146 //\r
147 // Only clear the SIGNAL status if it is a SIGNAL type event.\r
148 // WAIT type events are only cleared in CheckEvent()\r
149 //\r
150 if (Event->Type & EVT_NOTIFY_SIGNAL) {\r
151 Event->SignalCount = 0;\r
152 }\r
153\r
154 CoreReleaseEventLock ();\r
155\r
156 //\r
157 // Notify this event\r
158 //\r
159 ASSERT (Event->NotifyFunction != NULL);\r
160 Event->NotifyFunction (Event, Event->NotifyContext);\r
161\r
162 //\r
163 // Check for next pending event\r
164 //\r
165 CoreAcquireEventLock ();\r
166 }\r
167\r
168 gEventPending &= ~(1 << Priority);\r
169 CoreReleaseEventLock ();\r
170}\r
171\r
172\r
162ed594 173\r
174/**\r
175 Queues the event's notification function to fire.\r
176\r
177 @param Event The Event to notify\r
178\r
179**/\r
28a00297 180VOID\r
181CoreNotifyEvent (\r
182 IN IEVENT *Event\r
183 )\r
28a00297 184{\r
185\r
186 //\r
187 // Event database must be locked\r
188 //\r
189 ASSERT_LOCKED (&gEventQueueLock);\r
190\r
191 //\r
192 // If the event is queued somewhere, remove it\r
193 //\r
194\r
195 if (Event->NotifyLink.ForwardLink != NULL) {\r
196 RemoveEntryList (&Event->NotifyLink);\r
197 Event->NotifyLink.ForwardLink = NULL;\r
198 }\r
199\r
200 //\r
201 // Queue the event to the pending notification list\r
202 //\r
203\r
204 InsertTailList (&gEventQueue[Event->NotifyTpl], &Event->NotifyLink);\r
205 gEventPending |= (UINTN)(1 << Event->NotifyTpl);\r
206}\r
207\r
208\r
209\r
162ed594 210\r
211/**\r
212 Signals all events in the EventGroup.\r
213\r
214 @param EventGroup The list to signal\r
215\r
216**/\r
28a00297 217VOID\r
218CoreNotifySignalList (\r
219 IN EFI_GUID *EventGroup\r
220 )\r
28a00297 221{\r
222 LIST_ENTRY *Link;\r
223 LIST_ENTRY *Head;\r
224 IEVENT *Event;\r
225\r
226 CoreAcquireEventLock ();\r
227\r
228 Head = &gEventSignalQueue;\r
229 for (Link = Head->ForwardLink; Link != Head; Link = Link->ForwardLink) {\r
230 Event = CR (Link, IEVENT, SignalLink, EVENT_SIGNATURE);\r
231 if (CompareGuid (&Event->EventGroup, EventGroup)) {\r
232 CoreNotifyEvent (Event);\r
233 }\r
234 }\r
235\r
236 CoreReleaseEventLock ();\r
237}\r
238\r
162ed594 239\r
240/**\r
241 Creates a general-purpose event structure.\r
242\r
243 @param Type The type of event to create and its mode and \r
244 attributes \r
245 @param NotifyTpl The task priority level of event notifications \r
246 @param NotifyFunction Pointer to the events notification function \r
247 @param NotifyContext Pointer to the notification functions context; \r
248 corresponds to parameter "Context" in the \r
249 notification function \r
250 @param Event Pointer to the newly created event if the call \r
251 succeeds; undefined otherwise \r
252\r
253 @retval EFI_SUCCESS The event structure was created \r
254 @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value \r
255 @retval EFI_OUT_OF_RESOURCES The event could not be allocated\r
256\r
257**/\r
28a00297 258EFI_STATUS\r
259EFIAPI\r
260CoreCreateEvent (\r
261 IN UINT32 Type,\r
262 IN EFI_TPL NotifyTpl,\r
263 IN EFI_EVENT_NOTIFY NotifyFunction, OPTIONAL\r
264 IN VOID *NotifyContext, OPTIONAL\r
265 OUT EFI_EVENT *Event\r
266 )\r
28a00297 267{\r
bb8ffffd 268 return CoreCreateEventEx (Type, NotifyTpl, NotifyFunction, NotifyContext, NULL, Event);\r
28a00297 269}\r
270\r
271\r
162ed594 272\r
273/**\r
274 Creates a general-purpose event structure\r
275\r
276 @param Type The type of event to create and its mode and \r
277 attributes \r
278 @param NotifyTpl The task priority level of event notifications \r
279 @param NotifyFunction Pointer to the events notification function \r
280 @param NotifyContext Pointer to the notification functions context; \r
281 corresponds to parameter "Context" in the \r
282 notification function \r
283 @param EventGroup GUID for EventGroup if NULL act the same as \r
284 gBS->CreateEvent(). \r
285 @param Event Pointer to the newly created event if the call \r
286 succeeds; undefined otherwise \r
287\r
288 @retval EFI_SUCCESS The event structure was created \r
289 @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value \r
290 @retval EFI_OUT_OF_RESOURCES The event could not be allocated\r
291\r
292**/\r
28a00297 293EFI_STATUS\r
294EFIAPI\r
295CoreCreateEventEx (\r
296 IN UINT32 Type,\r
297 IN EFI_TPL NotifyTpl,\r
298 IN EFI_EVENT_NOTIFY NotifyFunction, OPTIONAL\r
299 IN CONST VOID *NotifyContext, OPTIONAL\r
300 IN CONST EFI_GUID *EventGroup, OPTIONAL\r
301 OUT EFI_EVENT *Event\r
302 )\r
28a00297 303{\r
304 EFI_STATUS Status;\r
305 IEVENT *IEvent;\r
306 INTN Index;\r
307\r
308\r
309 if ((Event == NULL) || (NotifyTpl == TPL_APPLICATION)) {\r
310 return EFI_INVALID_PARAMETER;\r
311 }\r
312\r
313 //\r
314 // Check to make sure no reserved flags are set\r
315 //\r
316 Status = EFI_INVALID_PARAMETER;\r
317 for (Index = 0; Index < (sizeof (mEventTable) / sizeof (UINT32)); Index++) {\r
318 if (Type == mEventTable[Index]) {\r
319 Status = EFI_SUCCESS;\r
320 break;\r
321 }\r
322 }\r
323 if(EFI_ERROR (Status)) {\r
324 return EFI_INVALID_PARAMETER;\r
325 }\r
326\r
bb8ffffd 327 //\r
328 // Convert Event type for pre-defined Event groups\r
329 //\r
330 if (EventGroup != NULL) {\r
331 //\r
332 // For event group, type EVT_SIGNAL_EXIT_BOOT_SERVICES and EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE\r
333 // are not valid\r
334 //\r
335 if ((Type == EVT_SIGNAL_EXIT_BOOT_SERVICES) || (Type == EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE)) {\r
336 return EFI_INVALID_PARAMETER;\r
337 }\r
338 if (CompareGuid (EventGroup, &gEfiEventExitBootServicesGuid)) {\r
339 Type = EVT_SIGNAL_EXIT_BOOT_SERVICES;\r
340 } else if (CompareGuid (EventGroup, &gEfiEventVirtualAddressChangeGuid)) {\r
341 Type = EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE;\r
342 }\r
343 } else {\r
344 //\r
345 // Convert EFI 1.10 Events to their UEFI 2.0 CreateEventEx mapping\r
346 //\r
347 if (Type == EVT_SIGNAL_EXIT_BOOT_SERVICES) {\r
348 EventGroup = &gEfiEventExitBootServicesGuid;\r
349 } else if (Type == EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE) {\r
350 EventGroup = &gEfiEventVirtualAddressChangeGuid;\r
351 }\r
352 }\r
353\r
28a00297 354 //\r
355 // If it's a notify type of event, check its parameters\r
356 //\r
71f68914 357 if ((Type & (EVT_NOTIFY_WAIT | EVT_NOTIFY_SIGNAL)) != 0) {\r
28a00297 358 //\r
359 // Check for an invalid NotifyFunction or NotifyTpl\r
360 //\r
361 if ((NotifyFunction == NULL) ||\r
362 (NotifyTpl < TPL_APPLICATION) ||\r
363 (NotifyTpl >= TPL_HIGH_LEVEL)) {\r
364 return EFI_INVALID_PARAMETER;\r
365 }\r
366\r
367 } else {\r
368 //\r
369 // No notification needed, zero ignored values\r
370 //\r
371 NotifyTpl = 0;\r
372 NotifyFunction = NULL;\r
373 NotifyContext = NULL;\r
374 }\r
375\r
376 //\r
377 // Allcoate and initialize a new event structure.\r
378 //\r
379 Status = CoreAllocatePool (\r
71f68914 380 ((Type & EVT_RUNTIME) != 0) ? EfiRuntimeServicesData: EfiBootServicesData,\r
28a00297 381 sizeof (IEVENT),\r
382 (VOID **)&IEvent\r
383 );\r
384 if (EFI_ERROR (Status)) {\r
385 return EFI_OUT_OF_RESOURCES;\r
386 }\r
387\r
388 SetMem (IEvent, sizeof (IEVENT), 0);\r
389\r
390 IEvent->Signature = EVENT_SIGNATURE;\r
391 IEvent->Type = Type;\r
392\r
393 IEvent->NotifyTpl = NotifyTpl;\r
394 IEvent->NotifyFunction = NotifyFunction;\r
395 IEvent->NotifyContext = (VOID *)NotifyContext;\r
396 if (EventGroup != NULL) {\r
397 CopyGuid (&IEvent->EventGroup, EventGroup);\r
398 IEvent->ExFlag = TRUE;\r
399 }\r
400\r
401 *Event = IEvent;\r
402\r
71f68914 403 if ((Type & EVT_RUNTIME) != 0) {\r
28a00297 404 //\r
405 // Keep a list of all RT events so we can tell the RT AP.\r
406 //\r
407 IEvent->RuntimeData.Type = Type;\r
408 IEvent->RuntimeData.NotifyTpl = NotifyTpl;\r
409 IEvent->RuntimeData.NotifyFunction = NotifyFunction;\r
410 IEvent->RuntimeData.NotifyContext = (VOID *) NotifyContext;\r
411 IEvent->RuntimeData.Event = (EFI_EVENT *) IEvent;\r
412 InsertTailList (&gRuntime->EventHead, &IEvent->RuntimeData.Link);\r
413 }\r
414\r
415 CoreAcquireEventLock ();\r
416\r
417 if ((Type & EVT_NOTIFY_SIGNAL) != 0x00000000) {\r
418 //\r
419 // The Event's NotifyFunction must be queued whenever the event is signaled\r
420 //\r
421 InsertHeadList (&gEventSignalQueue, &IEvent->SignalLink);\r
422 }\r
423\r
424 CoreReleaseEventLock ();\r
425\r
426 //\r
427 // Done\r
428 //\r
429 return EFI_SUCCESS;\r
430}\r
431\r
432\r
433\r
28a00297 434\r
162ed594 435/**\r
28a00297 436 Signals the event. Queues the event to be notified if needed\r
437\r
162ed594 438 @param UserEvent The event to signal \r
28a00297 439\r
162ed594 440 @retval EFI_INVALID_PARAMETER Parameters are not valid. \r
441 @retval EFI_SUCCESS The event was signaled.\r
28a00297 442\r
162ed594 443**/\r
444EFI_STATUS\r
445EFIAPI\r
446CoreSignalEvent (\r
447 IN EFI_EVENT UserEvent\r
448 )\r
28a00297 449{\r
450 IEVENT *Event;\r
451\r
452 Event = UserEvent;\r
453\r
454 if (Event == NULL) {\r
455 return EFI_INVALID_PARAMETER;\r
456 }\r
457\r
458 if (Event->Signature != EVENT_SIGNATURE) {\r
459 return EFI_INVALID_PARAMETER;\r
460 }\r
461\r
462 CoreAcquireEventLock ();\r
463\r
464 //\r
465 // If the event is not already signalled, do so\r
466 //\r
467\r
468 if (Event->SignalCount == 0x00000000) {\r
469 Event->SignalCount++;\r
470\r
471 //\r
472 // If signalling type is a notify function, queue it\r
473 //\r
474 if (Event->Type & EVT_NOTIFY_SIGNAL) {\r
475 if (Event->ExFlag) {\r
476 //\r
477 // The CreateEventEx() style requires all members of the Event Group\r
478 // to be signaled.\r
479 //\r
480 CoreReleaseEventLock ();\r
481 CoreNotifySignalList (&Event->EventGroup);\r
482 CoreAcquireEventLock ();\r
483 } else {\r
484 CoreNotifyEvent (Event);\r
485 }\r
486 }\r
487 }\r
488\r
489 CoreReleaseEventLock ();\r
490 return EFI_SUCCESS;\r
491}\r
492\r
493\r
162ed594 494\r
495/**\r
496 Check the status of an event.\r
497\r
498 @param UserEvent The event to check \r
499\r
500 @retval EFI_SUCCESS The event is in the signaled state \r
501 @retval EFI_NOT_READY The event is not in the signaled state \r
502 @retval EFI_INVALID_PARAMETER Event is of type EVT_NOTIFY_SIGNAL\r
503\r
504**/\r
28a00297 505EFI_STATUS\r
506EFIAPI\r
507CoreCheckEvent (\r
508 IN EFI_EVENT UserEvent\r
509 )\r
28a00297 510{\r
511 IEVENT *Event;\r
512 EFI_STATUS Status;\r
513\r
514 Event = UserEvent;\r
515\r
516 if (Event == NULL) {\r
517 return EFI_INVALID_PARAMETER;\r
518 }\r
519\r
520 if (Event->Signature != EVENT_SIGNATURE) {\r
521 return EFI_INVALID_PARAMETER;\r
522 }\r
523\r
524 if (Event->Type & EVT_NOTIFY_SIGNAL) {\r
525 return EFI_INVALID_PARAMETER;\r
526 }\r
527\r
528 Status = EFI_NOT_READY;\r
529\r
530 if (!Event->SignalCount && (Event->Type & EVT_NOTIFY_WAIT)) {\r
531\r
532 //\r
533 // Queue the wait notify function\r
534 //\r
535\r
536 CoreAcquireEventLock ();\r
537 if (!Event->SignalCount) {\r
538 CoreNotifyEvent (Event);\r
539 }\r
540 CoreReleaseEventLock ();\r
541 }\r
542\r
543 //\r
544 // If the even looks signalled, get the lock and clear it\r
545 //\r
546\r
547 if (Event->SignalCount) {\r
548 CoreAcquireEventLock ();\r
549\r
550 if (Event->SignalCount) {\r
551 Event->SignalCount = 0;\r
552 Status = EFI_SUCCESS;\r
553 }\r
554\r
555 CoreReleaseEventLock ();\r
556 }\r
557\r
558 return Status;\r
559}\r
560\r
561\r
562\r
162ed594 563\r
564/**\r
565 Stops execution until an event is signaled.\r
566\r
567 @param NumberOfEvents The number of events in the UserEvents array \r
568 @param UserEvents An array of EFI_EVENT \r
569 @param UserIndex Pointer to the index of the event which \r
570 satisfied the wait condition \r
571\r
572 @retval EFI_SUCCESS The event indicated by Index was signaled. \r
573 @retval EFI_INVALID_PARAMETER The event indicated by Index has a notification \r
574 function or Event was not a valid type \r
575 @retval EFI_UNSUPPORTED The current TPL is not TPL_APPLICATION\r
576\r
577**/\r
28a00297 578EFI_STATUS\r
579EFIAPI\r
580CoreWaitForEvent (\r
581 IN UINTN NumberOfEvents,\r
582 IN EFI_EVENT *UserEvents,\r
583 OUT UINTN *UserIndex\r
584 )\r
28a00297 585{\r
586 EFI_STATUS Status;\r
587 UINTN Index;\r
588\r
589 //\r
590 // Can only WaitForEvent at TPL_APPLICATION\r
591 //\r
592 if (gEfiCurrentTpl != TPL_APPLICATION) {\r
593 return EFI_UNSUPPORTED;\r
594 }\r
595\r
596 for(;;) {\r
597\r
598 for(Index = 0; Index < NumberOfEvents; Index++) {\r
599\r
600 Status = CoreCheckEvent (UserEvents[Index]);\r
601\r
602 //\r
603 // provide index of event that caused problem\r
604 //\r
605 if (Status != EFI_NOT_READY) {\r
606 *UserIndex = Index;\r
607 return Status;\r
608 }\r
609 }\r
610\r
611 //\r
612 // This was the location of the Idle loop callback in EFI 1.x reference\r
613 // code. We don't have that concept in this base at this point.\r
614 //\r
615 }\r
616}\r
617\r
618\r
28a00297 619\r
162ed594 620/**\r
28a00297 621 Closes an event and frees the event structure.\r
622\r
162ed594 623 @param UserEvent Event to close \r
28a00297 624\r
162ed594 625 @retval EFI_INVALID_PARAMETER Parameters are not valid. \r
626 @retval EFI_SUCCESS The event has been closed\r
28a00297 627\r
162ed594 628**/\r
629EFI_STATUS\r
630EFIAPI\r
631CoreCloseEvent (\r
632 IN EFI_EVENT UserEvent\r
633 )\r
28a00297 634{\r
635 EFI_STATUS Status;\r
636 IEVENT *Event;\r
637\r
638 Event = UserEvent;\r
639\r
640 if (Event == NULL) {\r
641 return EFI_INVALID_PARAMETER;\r
642 }\r
643\r
644 if (Event->Signature != EVENT_SIGNATURE) {\r
645 return EFI_INVALID_PARAMETER;\r
646 }\r
647\r
648 //\r
649 // If it's a timer event, make sure it's not pending\r
650 //\r
651 if (Event->Type & EVT_TIMER) {\r
652 CoreSetTimer (Event, TimerCancel, 0);\r
653 }\r
654\r
655 CoreAcquireEventLock ();\r
656\r
657 //\r
658 // If the event is queued somewhere, remove it\r
659 //\r
660\r
661 if (Event->RuntimeData.Link.ForwardLink != NULL) {\r
662 RemoveEntryList (&Event->RuntimeData.Link);\r
663 }\r
664\r
665 if (Event->NotifyLink.ForwardLink != NULL) {\r
666 RemoveEntryList (&Event->NotifyLink);\r
667 }\r
668\r
669 if (Event->SignalLink.ForwardLink != NULL) {\r
670 RemoveEntryList (&Event->SignalLink);\r
671 }\r
672\r
673 CoreReleaseEventLock ();\r
674\r
675 //\r
676 // If the event is registered on a protocol notify, then remove it from the protocol database\r
677 //\r
678 CoreUnregisterProtocolNotify (Event);\r
679\r
680 Status = CoreFreePool (Event);\r
681 ASSERT_EFI_ERROR (Status);\r
682\r
683 return Status;\r
684}\r