]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Core/Dxe/Event/Event.c
MdeModulePkg: document workaround for EFI_RUNTIME_EVENT_ENTRY PI spec bug
[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
ac72474d 4Copyright (c) 2006 - 2017, Intel Corporation. All rights reserved.<BR>\r
82f3edf2 5(C) Copyright 2015 Hewlett Packard Enterprise Development LP<BR>\r
9d510e61 6SPDX-License-Identifier: BSD-2-Clause-Patent\r
28a00297 7\r
504214c4 8**/\r
28a00297 9\r
10\r
9c4ac31c 11#include "DxeMain.h"\r
ec90508b 12#include "Event.h"\r
28a00297 13\r
1947c70c 14///\r
15/// gEfiCurrentTpl - Current Task priority level\r
16///\r
17EFI_TPL gEfiCurrentTpl = TPL_APPLICATION;\r
18\r
19///\r
d613c2a8 20/// gEventQueueLock - Protects the event queues\r
1947c70c 21///\r
22EFI_LOCK gEventQueueLock = EFI_INITIALIZE_LOCK_VARIABLE (TPL_HIGH_LEVEL);\r
23\r
24///\r
25/// gEventQueue - A list of event's to notify for each priority level\r
26///\r
27LIST_ENTRY gEventQueue[TPL_HIGH_LEVEL + 1];\r
28\r
29///\r
30/// gEventPending - A bitmask of the EventQueues that are pending\r
31///\r
32UINTN gEventPending = 0;\r
33\r
34///\r
35/// gEventSignalQueue - A list of events to signal based on EventGroup type\r
36///\r
37LIST_ENTRY gEventSignalQueue = INITIALIZE_LIST_HEAD_VARIABLE (gEventSignalQueue);\r
38\r
39///\r
40/// Enumerate the valid types\r
41///\r
28a00297 42UINT32 mEventTable[] = {\r
1947c70c 43 ///\r
44 /// 0x80000200 Timer event with a notification function that is\r
45 /// queue when the event is signaled with SignalEvent()\r
46 ///\r
28a00297 47 EVT_TIMER | EVT_NOTIFY_SIGNAL,\r
1947c70c 48 ///\r
49 /// 0x80000000 Timer event without a notification function. It can be\r
50 /// signaled with SignalEvent() and checked with CheckEvent() or WaitForEvent().\r
51 ///\r
28a00297 52 EVT_TIMER,\r
1947c70c 53 ///\r
54 /// 0x00000100 Generic event with a notification function that\r
55 /// can be waited on with CheckEvent() or WaitForEvent()\r
56 ///\r
28a00297 57 EVT_NOTIFY_WAIT,\r
1947c70c 58 ///\r
59 /// 0x00000200 Generic event with a notification function that\r
60 /// is queue when the event is signaled with SignalEvent()\r
61 ///\r
28a00297 62 EVT_NOTIFY_SIGNAL,\r
1947c70c 63 ///\r
64 /// 0x00000201 ExitBootServicesEvent.\r
65 ///\r
28a00297 66 EVT_SIGNAL_EXIT_BOOT_SERVICES,\r
1947c70c 67 ///\r
68 /// 0x60000202 SetVirtualAddressMapEvent.\r
69 ///\r
28a00297 70 EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE,\r
71\r
1947c70c 72 ///\r
73 /// 0x00000000 Generic event without a notification function.\r
74 /// It can be signaled with SignalEvent() and checked with CheckEvent()\r
75 /// or WaitForEvent().\r
76 ///\r
28a00297 77 0x00000000,\r
1947c70c 78 ///\r
79 /// 0x80000100 Timer event with a notification function that can be\r
80 /// waited on with CheckEvent() or WaitForEvent()\r
81 ///\r
28a00297 82 EVT_TIMER | EVT_NOTIFY_WAIT,\r
83};\r
84\r
54cd17e9 85///\r
86/// gIdleLoopEvent - Event which is signalled when the core is idle\r
87///\r
88EFI_EVENT gIdleLoopEvent = NULL;\r
89\r
162ed594 90\r
91/**\r
92 Enter critical section by acquiring the lock on gEventQueueLock.\r
93\r
94**/\r
28a00297 95VOID\r
96CoreAcquireEventLock (\r
97 VOID\r
98 )\r
28a00297 99{\r
100 CoreAcquireLock (&gEventQueueLock);\r
101}\r
102\r
162ed594 103\r
104/**\r
105 Exit critical section by releasing the lock on gEventQueueLock.\r
106\r
107**/\r
28a00297 108VOID\r
109CoreReleaseEventLock (\r
110 VOID\r
111 )\r
28a00297 112{\r
113 CoreReleaseLock (&gEventQueueLock);\r
114}\r
115\r
116\r
28a00297 117\r
162ed594 118/**\r
c18f12d3 119 Initializes "event" support.\r
28a00297 120\r
162ed594 121 @retval EFI_SUCCESS Always return success\r
28a00297 122\r
162ed594 123**/\r
124EFI_STATUS\r
125CoreInitializeEventServices (\r
126 VOID\r
127 )\r
28a00297 128{\r
129 UINTN Index;\r
130\r
131 for (Index=0; Index <= TPL_HIGH_LEVEL; Index++) {\r
132 InitializeListHead (&gEventQueue[Index]);\r
133 }\r
134\r
135 CoreInitializeTimer ();\r
136\r
54cd17e9 137 CoreCreateEventEx (\r
138 EVT_NOTIFY_SIGNAL,\r
139 TPL_NOTIFY,\r
ac72474d 140 EfiEventEmptyFunction,\r
54cd17e9 141 NULL,\r
142 &gIdleLoopEventGuid,\r
143 &gIdleLoopEvent\r
144 );\r
145\r
28a00297 146 return EFI_SUCCESS;\r
147}\r
148\r
149\r
28a00297 150\r
162ed594 151/**\r
28a00297 152 Dispatches all pending events.\r
153\r
022c6d45 154 @param Priority The task priority level of event notifications\r
162ed594 155 to dispatch\r
28a00297 156\r
162ed594 157**/\r
158VOID\r
159CoreDispatchEventNotifies (\r
160 IN EFI_TPL Priority\r
161 )\r
28a00297 162{\r
163 IEVENT *Event;\r
164 LIST_ENTRY *Head;\r
165\r
166 CoreAcquireEventLock ();\r
167 ASSERT (gEventQueueLock.OwnerTpl == Priority);\r
168 Head = &gEventQueue[Priority];\r
169\r
170 //\r
171 // Dispatch all the pending notifications\r
172 //\r
173 while (!IsListEmpty (Head)) {\r
174\r
175 Event = CR (Head->ForwardLink, IEVENT, NotifyLink, EVENT_SIGNATURE);\r
176 RemoveEntryList (&Event->NotifyLink);\r
177\r
178 Event->NotifyLink.ForwardLink = NULL;\r
179\r
180 //\r
181 // Only clear the SIGNAL status if it is a SIGNAL type event.\r
182 // WAIT type events are only cleared in CheckEvent()\r
183 //\r
6e536468 184 if ((Event->Type & EVT_NOTIFY_SIGNAL) != 0) {\r
28a00297 185 Event->SignalCount = 0;\r
186 }\r
187\r
188 CoreReleaseEventLock ();\r
189\r
190 //\r
191 // Notify this event\r
192 //\r
193 ASSERT (Event->NotifyFunction != NULL);\r
194 Event->NotifyFunction (Event, Event->NotifyContext);\r
195\r
196 //\r
197 // Check for next pending event\r
198 //\r
199 CoreAcquireEventLock ();\r
200 }\r
201\r
6e1e5405 202 gEventPending &= ~(UINTN)(1 << Priority);\r
28a00297 203 CoreReleaseEventLock ();\r
204}\r
205\r
206\r
162ed594 207\r
208/**\r
209 Queues the event's notification function to fire.\r
210\r
211 @param Event The Event to notify\r
212\r
213**/\r
28a00297 214VOID\r
215CoreNotifyEvent (\r
216 IN IEVENT *Event\r
217 )\r
28a00297 218{\r
219\r
220 //\r
221 // Event database must be locked\r
222 //\r
223 ASSERT_LOCKED (&gEventQueueLock);\r
224\r
225 //\r
226 // If the event is queued somewhere, remove it\r
227 //\r
228\r
229 if (Event->NotifyLink.ForwardLink != NULL) {\r
230 RemoveEntryList (&Event->NotifyLink);\r
231 Event->NotifyLink.ForwardLink = NULL;\r
232 }\r
233\r
234 //\r
235 // Queue the event to the pending notification list\r
236 //\r
237\r
238 InsertTailList (&gEventQueue[Event->NotifyTpl], &Event->NotifyLink);\r
239 gEventPending |= (UINTN)(1 << Event->NotifyTpl);\r
240}\r
241\r
242\r
243\r
162ed594 244\r
245/**\r
246 Signals all events in the EventGroup.\r
247\r
248 @param EventGroup The list to signal\r
249\r
250**/\r
28a00297 251VOID\r
252CoreNotifySignalList (\r
253 IN EFI_GUID *EventGroup\r
254 )\r
28a00297 255{\r
256 LIST_ENTRY *Link;\r
257 LIST_ENTRY *Head;\r
258 IEVENT *Event;\r
259\r
260 CoreAcquireEventLock ();\r
261\r
262 Head = &gEventSignalQueue;\r
263 for (Link = Head->ForwardLink; Link != Head; Link = Link->ForwardLink) {\r
264 Event = CR (Link, IEVENT, SignalLink, EVENT_SIGNATURE);\r
265 if (CompareGuid (&Event->EventGroup, EventGroup)) {\r
266 CoreNotifyEvent (Event);\r
267 }\r
268 }\r
269\r
270 CoreReleaseEventLock ();\r
271}\r
272\r
162ed594 273\r
274/**\r
670d4d88 275 Creates an event.\r
162ed594 276\r
022c6d45 277 @param Type The type of event to create and its mode and\r
278 attributes\r
279 @param NotifyTpl The task priority level of event notifications\r
280 @param NotifyFunction Pointer to the events notification function\r
281 @param NotifyContext Pointer to the notification functions context;\r
282 corresponds to parameter "Context" in the\r
283 notification function\r
284 @param Event Pointer to the newly created event if the call\r
285 succeeds; undefined otherwise\r
286\r
287 @retval EFI_SUCCESS The event structure was created\r
288 @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value\r
162ed594 289 @retval EFI_OUT_OF_RESOURCES The event could not be allocated\r
290\r
291**/\r
28a00297 292EFI_STATUS\r
293EFIAPI\r
294CoreCreateEvent (\r
295 IN UINT32 Type,\r
296 IN EFI_TPL NotifyTpl,\r
297 IN EFI_EVENT_NOTIFY NotifyFunction, OPTIONAL\r
298 IN VOID *NotifyContext, OPTIONAL\r
299 OUT EFI_EVENT *Event\r
300 )\r
28a00297 301{\r
bb8ffffd 302 return CoreCreateEventEx (Type, NotifyTpl, NotifyFunction, NotifyContext, NULL, Event);\r
28a00297 303}\r
304\r
305\r
162ed594 306\r
307/**\r
670d4d88 308 Creates an event in a group.\r
162ed594 309\r
022c6d45 310 @param Type The type of event to create and its mode and\r
311 attributes\r
312 @param NotifyTpl The task priority level of event notifications\r
313 @param NotifyFunction Pointer to the events notification function\r
314 @param NotifyContext Pointer to the notification functions context;\r
315 corresponds to parameter "Context" in the\r
316 notification function\r
317 @param EventGroup GUID for EventGroup if NULL act the same as\r
318 gBS->CreateEvent().\r
319 @param Event Pointer to the newly created event if the call\r
320 succeeds; undefined otherwise\r
321\r
322 @retval EFI_SUCCESS The event structure was created\r
323 @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value\r
162ed594 324 @retval EFI_OUT_OF_RESOURCES The event could not be allocated\r
325\r
326**/\r
28a00297 327EFI_STATUS\r
328EFIAPI\r
329CoreCreateEventEx (\r
330 IN UINT32 Type,\r
331 IN EFI_TPL NotifyTpl,\r
332 IN EFI_EVENT_NOTIFY NotifyFunction, OPTIONAL\r
333 IN CONST VOID *NotifyContext, OPTIONAL\r
334 IN CONST EFI_GUID *EventGroup, OPTIONAL\r
335 OUT EFI_EVENT *Event\r
336 )\r
670d4d88
SZ
337{\r
338 //\r
339 // If it's a notify type of event, check for invalid NotifyTpl\r
340 //\r
341 if ((Type & (EVT_NOTIFY_WAIT | EVT_NOTIFY_SIGNAL)) != 0) {\r
342 if (NotifyTpl != TPL_APPLICATION &&\r
343 NotifyTpl != TPL_CALLBACK &&\r
344 NotifyTpl != TPL_NOTIFY) {\r
345 return EFI_INVALID_PARAMETER;\r
346 }\r
347 }\r
348\r
349 return CoreCreateEventInternal (Type, NotifyTpl, NotifyFunction, NotifyContext, EventGroup, Event);\r
350}\r
351\r
352/**\r
353 Creates a general-purpose event structure\r
354\r
355 @param Type The type of event to create and its mode and\r
356 attributes\r
357 @param NotifyTpl The task priority level of event notifications\r
358 @param NotifyFunction Pointer to the events notification function\r
359 @param NotifyContext Pointer to the notification functions context;\r
360 corresponds to parameter "Context" in the\r
361 notification function\r
362 @param EventGroup GUID for EventGroup if NULL act the same as\r
363 gBS->CreateEvent().\r
364 @param Event Pointer to the newly created event if the call\r
365 succeeds; undefined otherwise\r
366\r
367 @retval EFI_SUCCESS The event structure was created\r
368 @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value\r
369 @retval EFI_OUT_OF_RESOURCES The event could not be allocated\r
370\r
371**/\r
372EFI_STATUS\r
373EFIAPI\r
374CoreCreateEventInternal (\r
375 IN UINT32 Type,\r
376 IN EFI_TPL NotifyTpl,\r
377 IN EFI_EVENT_NOTIFY NotifyFunction, OPTIONAL\r
378 IN CONST VOID *NotifyContext, OPTIONAL\r
379 IN CONST EFI_GUID *EventGroup, OPTIONAL\r
380 OUT EFI_EVENT *Event\r
381 )\r
28a00297 382{\r
383 EFI_STATUS Status;\r
384 IEVENT *IEvent;\r
385 INTN Index;\r
386\r
387\r
51b02d81 388 if (Event == NULL) {\r
28a00297 389 return EFI_INVALID_PARAMETER;\r
390 }\r
391\r
392 //\r
393 // Check to make sure no reserved flags are set\r
394 //\r
395 Status = EFI_INVALID_PARAMETER;\r
396 for (Index = 0; Index < (sizeof (mEventTable) / sizeof (UINT32)); Index++) {\r
397 if (Type == mEventTable[Index]) {\r
398 Status = EFI_SUCCESS;\r
399 break;\r
400 }\r
401 }\r
402 if(EFI_ERROR (Status)) {\r
403 return EFI_INVALID_PARAMETER;\r
404 }\r
405\r
bb8ffffd 406 //\r
407 // Convert Event type for pre-defined Event groups\r
408 //\r
409 if (EventGroup != NULL) {\r
410 //\r
411 // For event group, type EVT_SIGNAL_EXIT_BOOT_SERVICES and EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE\r
412 // are not valid\r
413 //\r
414 if ((Type == EVT_SIGNAL_EXIT_BOOT_SERVICES) || (Type == EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE)) {\r
415 return EFI_INVALID_PARAMETER;\r
416 }\r
417 if (CompareGuid (EventGroup, &gEfiEventExitBootServicesGuid)) {\r
418 Type = EVT_SIGNAL_EXIT_BOOT_SERVICES;\r
419 } else if (CompareGuid (EventGroup, &gEfiEventVirtualAddressChangeGuid)) {\r
420 Type = EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE;\r
421 }\r
422 } else {\r
423 //\r
424 // Convert EFI 1.10 Events to their UEFI 2.0 CreateEventEx mapping\r
425 //\r
426 if (Type == EVT_SIGNAL_EXIT_BOOT_SERVICES) {\r
427 EventGroup = &gEfiEventExitBootServicesGuid;\r
428 } else if (Type == EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE) {\r
429 EventGroup = &gEfiEventVirtualAddressChangeGuid;\r
430 }\r
431 }\r
432\r
28a00297 433 //\r
434 // If it's a notify type of event, check its parameters\r
435 //\r
71f68914 436 if ((Type & (EVT_NOTIFY_WAIT | EVT_NOTIFY_SIGNAL)) != 0) {\r
28a00297 437 //\r
438 // Check for an invalid NotifyFunction or NotifyTpl\r
439 //\r
440 if ((NotifyFunction == NULL) ||\r
51b02d81 441 (NotifyTpl <= TPL_APPLICATION) ||\r
28a00297 442 (NotifyTpl >= TPL_HIGH_LEVEL)) {\r
443 return EFI_INVALID_PARAMETER;\r
444 }\r
445\r
446 } else {\r
447 //\r
448 // No notification needed, zero ignored values\r
449 //\r
450 NotifyTpl = 0;\r
451 NotifyFunction = NULL;\r
452 NotifyContext = NULL;\r
453 }\r
454\r
455 //\r
b364eeb0 456 // Allocate and initialize a new event structure.\r
28a00297 457 //\r
b364eeb0 458 if ((Type & EVT_RUNTIME) != 0) {\r
459 IEvent = AllocateRuntimeZeroPool (sizeof (IEVENT));\r
460 } else {\r
461 IEvent = AllocateZeroPool (sizeof (IEVENT));\r
462 }\r
463 if (IEvent == NULL) {\r
28a00297 464 return EFI_OUT_OF_RESOURCES;\r
465 }\r
466\r
28a00297 467 IEvent->Signature = EVENT_SIGNATURE;\r
468 IEvent->Type = Type;\r
469\r
470 IEvent->NotifyTpl = NotifyTpl;\r
471 IEvent->NotifyFunction = NotifyFunction;\r
472 IEvent->NotifyContext = (VOID *)NotifyContext;\r
473 if (EventGroup != NULL) {\r
474 CopyGuid (&IEvent->EventGroup, EventGroup);\r
82f3edf2 475 IEvent->ExFlag |= EVT_EXFLAG_EVENT_GROUP;\r
28a00297 476 }\r
477\r
478 *Event = IEvent;\r
479\r
71f68914 480 if ((Type & EVT_RUNTIME) != 0) {\r
28a00297 481 //\r
482 // Keep a list of all RT events so we can tell the RT AP.\r
483 //\r
484 IEvent->RuntimeData.Type = Type;\r
485 IEvent->RuntimeData.NotifyTpl = NotifyTpl;\r
486 IEvent->RuntimeData.NotifyFunction = NotifyFunction;\r
487 IEvent->RuntimeData.NotifyContext = (VOID *) NotifyContext;\r
d342d318
LE
488 //\r
489 // Work around the bug in the Platform Init specification (v1.7), reported\r
490 // as Mantis#2017: "EFI_RUNTIME_EVENT_ENTRY.Event" should have type\r
491 // EFI_EVENT, not (EFI_EVENT*). The PI spec documents the field correctly\r
492 // as "The EFI_EVENT returned by CreateEvent()", but the type of the field\r
493 // doesn't match the natural language description. Therefore we need an\r
494 // explicit cast here.\r
495 //\r
28a00297 496 IEvent->RuntimeData.Event = (EFI_EVENT *) IEvent;\r
497 InsertTailList (&gRuntime->EventHead, &IEvent->RuntimeData.Link);\r
498 }\r
499\r
500 CoreAcquireEventLock ();\r
501\r
502 if ((Type & EVT_NOTIFY_SIGNAL) != 0x00000000) {\r
503 //\r
504 // The Event's NotifyFunction must be queued whenever the event is signaled\r
505 //\r
506 InsertHeadList (&gEventSignalQueue, &IEvent->SignalLink);\r
507 }\r
508\r
509 CoreReleaseEventLock ();\r
510\r
511 //\r
512 // Done\r
513 //\r
514 return EFI_SUCCESS;\r
515}\r
516\r
517\r
518\r
28a00297 519\r
162ed594 520/**\r
e94a9ff7 521 Signals the event. Queues the event to be notified if needed.\r
28a00297 522\r
e94a9ff7 523 @param UserEvent The event to signal .\r
28a00297 524\r
022c6d45 525 @retval EFI_INVALID_PARAMETER Parameters are not valid.\r
162ed594 526 @retval EFI_SUCCESS The event was signaled.\r
28a00297 527\r
162ed594 528**/\r
529EFI_STATUS\r
530EFIAPI\r
531CoreSignalEvent (\r
532 IN EFI_EVENT UserEvent\r
533 )\r
28a00297 534{\r
535 IEVENT *Event;\r
536\r
537 Event = UserEvent;\r
538\r
539 if (Event == NULL) {\r
540 return EFI_INVALID_PARAMETER;\r
541 }\r
542\r
543 if (Event->Signature != EVENT_SIGNATURE) {\r
544 return EFI_INVALID_PARAMETER;\r
545 }\r
546\r
547 CoreAcquireEventLock ();\r
548\r
549 //\r
550 // If the event is not already signalled, do so\r
551 //\r
552\r
553 if (Event->SignalCount == 0x00000000) {\r
554 Event->SignalCount++;\r
555\r
556 //\r
557 // If signalling type is a notify function, queue it\r
558 //\r
6e536468 559 if ((Event->Type & EVT_NOTIFY_SIGNAL) != 0) {\r
82f3edf2 560 if ((Event->ExFlag & EVT_EXFLAG_EVENT_GROUP) != 0) {\r
28a00297 561 //\r
562 // The CreateEventEx() style requires all members of the Event Group\r
563 // to be signaled.\r
564 //\r
565 CoreReleaseEventLock ();\r
566 CoreNotifySignalList (&Event->EventGroup);\r
567 CoreAcquireEventLock ();\r
568 } else {\r
569 CoreNotifyEvent (Event);\r
570 }\r
571 }\r
572 }\r
573\r
574 CoreReleaseEventLock ();\r
575 return EFI_SUCCESS;\r
576}\r
577\r
578\r
162ed594 579\r
580/**\r
581 Check the status of an event.\r
582\r
022c6d45 583 @param UserEvent The event to check\r
162ed594 584\r
022c6d45 585 @retval EFI_SUCCESS The event is in the signaled state\r
586 @retval EFI_NOT_READY The event is not in the signaled state\r
162ed594 587 @retval EFI_INVALID_PARAMETER Event is of type EVT_NOTIFY_SIGNAL\r
588\r
589**/\r
28a00297 590EFI_STATUS\r
591EFIAPI\r
592CoreCheckEvent (\r
593 IN EFI_EVENT UserEvent\r
594 )\r
28a00297 595{\r
596 IEVENT *Event;\r
597 EFI_STATUS Status;\r
598\r
599 Event = UserEvent;\r
600\r
601 if (Event == NULL) {\r
602 return EFI_INVALID_PARAMETER;\r
603 }\r
604\r
605 if (Event->Signature != EVENT_SIGNATURE) {\r
606 return EFI_INVALID_PARAMETER;\r
607 }\r
608\r
e94a9ff7 609 if ((Event->Type & EVT_NOTIFY_SIGNAL) != 0) {\r
28a00297 610 return EFI_INVALID_PARAMETER;\r
611 }\r
612\r
613 Status = EFI_NOT_READY;\r
614\r
6e536468 615 if ((Event->SignalCount == 0) && ((Event->Type & EVT_NOTIFY_WAIT) != 0)) {\r
28a00297 616\r
617 //\r
618 // Queue the wait notify function\r
619 //\r
28a00297 620 CoreAcquireEventLock ();\r
6e536468 621 if (Event->SignalCount == 0) {\r
28a00297 622 CoreNotifyEvent (Event);\r
623 }\r
624 CoreReleaseEventLock ();\r
625 }\r
626\r
627 //\r
628 // If the even looks signalled, get the lock and clear it\r
629 //\r
630\r
6e536468 631 if (Event->SignalCount != 0) {\r
28a00297 632 CoreAcquireEventLock ();\r
633\r
6e536468 634 if (Event->SignalCount != 0) {\r
28a00297 635 Event->SignalCount = 0;\r
636 Status = EFI_SUCCESS;\r
637 }\r
638\r
639 CoreReleaseEventLock ();\r
640 }\r
641\r
642 return Status;\r
643}\r
644\r
645\r
646\r
162ed594 647/**\r
648 Stops execution until an event is signaled.\r
649\r
022c6d45 650 @param NumberOfEvents The number of events in the UserEvents array\r
651 @param UserEvents An array of EFI_EVENT\r
652 @param UserIndex Pointer to the index of the event which\r
653 satisfied the wait condition\r
162ed594 654\r
022c6d45 655 @retval EFI_SUCCESS The event indicated by Index was signaled.\r
656 @retval EFI_INVALID_PARAMETER The event indicated by Index has a notification\r
657 function or Event was not a valid type\r
162ed594 658 @retval EFI_UNSUPPORTED The current TPL is not TPL_APPLICATION\r
659\r
660**/\r
28a00297 661EFI_STATUS\r
662EFIAPI\r
663CoreWaitForEvent (\r
664 IN UINTN NumberOfEvents,\r
665 IN EFI_EVENT *UserEvents,\r
666 OUT UINTN *UserIndex\r
667 )\r
28a00297 668{\r
669 EFI_STATUS Status;\r
670 UINTN Index;\r
671\r
672 //\r
673 // Can only WaitForEvent at TPL_APPLICATION\r
674 //\r
675 if (gEfiCurrentTpl != TPL_APPLICATION) {\r
676 return EFI_UNSUPPORTED;\r
677 }\r
678\r
720f84a9
OM
679 if (NumberOfEvents == 0) {\r
680 return EFI_INVALID_PARAMETER;\r
681 }\r
682\r
683 if (UserEvents == NULL) {\r
684 return EFI_INVALID_PARAMETER;\r
685 }\r
686\r
28a00297 687 for(;;) {\r
688\r
689 for(Index = 0; Index < NumberOfEvents; Index++) {\r
690\r
691 Status = CoreCheckEvent (UserEvents[Index]);\r
692\r
693 //\r
694 // provide index of event that caused problem\r
695 //\r
696 if (Status != EFI_NOT_READY) {\r
720f84a9
OM
697 if (UserIndex != NULL) {\r
698 *UserIndex = Index;\r
699 }\r
28a00297 700 return Status;\r
701 }\r
702 }\r
703\r
704 //\r
54cd17e9 705 // Signal the Idle event\r
28a00297 706 //\r
54cd17e9 707 CoreSignalEvent (gIdleLoopEvent);\r
28a00297 708 }\r
709}\r
710\r
711\r
162ed594 712/**\r
28a00297 713 Closes an event and frees the event structure.\r
714\r
022c6d45 715 @param UserEvent Event to close\r
28a00297 716\r
022c6d45 717 @retval EFI_INVALID_PARAMETER Parameters are not valid.\r
162ed594 718 @retval EFI_SUCCESS The event has been closed\r
28a00297 719\r
162ed594 720**/\r
721EFI_STATUS\r
722EFIAPI\r
723CoreCloseEvent (\r
724 IN EFI_EVENT UserEvent\r
725 )\r
28a00297 726{\r
727 EFI_STATUS Status;\r
728 IEVENT *Event;\r
729\r
730 Event = UserEvent;\r
731\r
732 if (Event == NULL) {\r
733 return EFI_INVALID_PARAMETER;\r
734 }\r
735\r
736 if (Event->Signature != EVENT_SIGNATURE) {\r
737 return EFI_INVALID_PARAMETER;\r
738 }\r
739\r
740 //\r
741 // If it's a timer event, make sure it's not pending\r
742 //\r
e94a9ff7 743 if ((Event->Type & EVT_TIMER) != 0) {\r
28a00297 744 CoreSetTimer (Event, TimerCancel, 0);\r
745 }\r
746\r
747 CoreAcquireEventLock ();\r
748\r
749 //\r
750 // If the event is queued somewhere, remove it\r
751 //\r
752\r
753 if (Event->RuntimeData.Link.ForwardLink != NULL) {\r
754 RemoveEntryList (&Event->RuntimeData.Link);\r
755 }\r
756\r
757 if (Event->NotifyLink.ForwardLink != NULL) {\r
758 RemoveEntryList (&Event->NotifyLink);\r
759 }\r
760\r
761 if (Event->SignalLink.ForwardLink != NULL) {\r
762 RemoveEntryList (&Event->SignalLink);\r
763 }\r
764\r
765 CoreReleaseEventLock ();\r
766\r
767 //\r
768 // If the event is registered on a protocol notify, then remove it from the protocol database\r
769 //\r
82f3edf2
SEHM
770 if ((Event->ExFlag & EVT_EXFLAG_EVENT_PROTOCOL_NOTIFICATION) != 0) {\r
771 CoreUnregisterProtocolNotify (Event);\r
772 }\r
28a00297 773\r
1a4acc11
SZ
774 //\r
775 // To avoid the Event to be signalled wrongly after closed,\r
776 // clear the Signature of Event before free pool.\r
777 //\r
778 Event->Signature = 0;\r
28a00297 779 Status = CoreFreePool (Event);\r
780 ASSERT_EFI_ERROR (Status);\r
781\r
782 return Status;\r
783}\r
54cd17e9 784\r