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