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