]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Core/Dxe/Event/event.c
Check in DxeCore for Nt32 platform. Currently, it does not follow PI/UEFI2.1.
[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
326 EFI_GUID *GuidPtr;\r
327 EFI_EVENT_NOTIFY Function;\r
328\r
329 GuidPtr = NULL;\r
330 Function = NotifyFunction;\r
331\r
332 //\r
333 // Convert EFI 1.10 Events to thier UEFI 2.0 CreateEventEx mapping\r
334 //\r
335 if (Type == EVT_SIGNAL_EXIT_BOOT_SERVICES) {\r
336 GuidPtr = &gEfiEventExitBootServicesGuid;\r
337 } else if (Type == EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE) {\r
338 GuidPtr = &gEfiEventVirtualAddressChangeGuid;\r
339 }\r
340\r
341 return CoreCreateEventEx (Type, NotifyTpl, Function, NotifyContext, GuidPtr, Event);\r
342}\r
343\r
344\r
345EFI_STATUS\r
346EFIAPI\r
347CoreCreateEventEx (\r
348 IN UINT32 Type,\r
349 IN EFI_TPL NotifyTpl,\r
350 IN EFI_EVENT_NOTIFY NotifyFunction, OPTIONAL\r
351 IN CONST VOID *NotifyContext, OPTIONAL\r
352 IN CONST EFI_GUID *EventGroup, OPTIONAL\r
353 OUT EFI_EVENT *Event\r
354 )\r
355/*++\r
356\r
357Routine Description:\r
358 Creates a general-purpose event structure\r
359\r
360Arguments:\r
361 Type - The type of event to create and its mode and attributes\r
362 NotifyTpl - The task priority level of event notifications\r
363 NotifyFunction - Pointer to the events notification function\r
364 NotifyContext - Pointer to the notification functions context; corresponds to\r
365 parameter "Context" in the notification function\r
366 EventGrout - GUID for EventGroup if NULL act the same as gBS->CreateEvent().\r
367 Event - Pointer to the newly created event if the call succeeds; undefined otherwise\r
368\r
369Returns:\r
370 EFI_SUCCESS - The event structure was created\r
371 EFI_INVALID_PARAMETER - One of the parameters has an invalid value\r
372 EFI_OUT_OF_RESOURCES - The event could not be allocated\r
373\r
374--*/\r
375{\r
376 EFI_STATUS Status;\r
377 IEVENT *IEvent;\r
378 INTN Index;\r
379\r
380\r
381 if ((Event == NULL) || (NotifyTpl == TPL_APPLICATION)) {\r
382 return EFI_INVALID_PARAMETER;\r
383 }\r
384\r
385 //\r
386 // Check to make sure no reserved flags are set\r
387 //\r
388 Status = EFI_INVALID_PARAMETER;\r
389 for (Index = 0; Index < (sizeof (mEventTable) / sizeof (UINT32)); Index++) {\r
390 if (Type == mEventTable[Index]) {\r
391 Status = EFI_SUCCESS;\r
392 break;\r
393 }\r
394 }\r
395 if(EFI_ERROR (Status)) {\r
396 return EFI_INVALID_PARAMETER;\r
397 }\r
398\r
399 //\r
400 // If it's a notify type of event, check its parameters\r
401 //\r
402 if ((Type & (EVT_NOTIFY_WAIT | EVT_NOTIFY_SIGNAL))) {\r
403 //\r
404 // Check for an invalid NotifyFunction or NotifyTpl\r
405 //\r
406 if ((NotifyFunction == NULL) ||\r
407 (NotifyTpl < TPL_APPLICATION) ||\r
408 (NotifyTpl >= TPL_HIGH_LEVEL)) {\r
409 return EFI_INVALID_PARAMETER;\r
410 }\r
411\r
412 } else {\r
413 //\r
414 // No notification needed, zero ignored values\r
415 //\r
416 NotifyTpl = 0;\r
417 NotifyFunction = NULL;\r
418 NotifyContext = NULL;\r
419 }\r
420\r
421 //\r
422 // Allcoate and initialize a new event structure.\r
423 //\r
424 Status = CoreAllocatePool (\r
425 (Type & EVT_RUNTIME) ? EfiRuntimeServicesData: EfiBootServicesData,\r
426 sizeof (IEVENT),\r
427 (VOID **)&IEvent\r
428 );\r
429 if (EFI_ERROR (Status)) {\r
430 return EFI_OUT_OF_RESOURCES;\r
431 }\r
432\r
433 SetMem (IEvent, sizeof (IEVENT), 0);\r
434\r
435 IEvent->Signature = EVENT_SIGNATURE;\r
436 IEvent->Type = Type;\r
437\r
438 IEvent->NotifyTpl = NotifyTpl;\r
439 IEvent->NotifyFunction = NotifyFunction;\r
440 IEvent->NotifyContext = (VOID *)NotifyContext;\r
441 if (EventGroup != NULL) {\r
442 CopyGuid (&IEvent->EventGroup, EventGroup);\r
443 IEvent->ExFlag = TRUE;\r
444 }\r
445\r
446 *Event = IEvent;\r
447\r
448 if (Type & EVT_RUNTIME) {\r
449 //\r
450 // Keep a list of all RT events so we can tell the RT AP.\r
451 //\r
452 IEvent->RuntimeData.Type = Type;\r
453 IEvent->RuntimeData.NotifyTpl = NotifyTpl;\r
454 IEvent->RuntimeData.NotifyFunction = NotifyFunction;\r
455 IEvent->RuntimeData.NotifyContext = (VOID *) NotifyContext;\r
456 IEvent->RuntimeData.Event = (EFI_EVENT *) IEvent;\r
457 InsertTailList (&gRuntime->EventHead, &IEvent->RuntimeData.Link);\r
458 }\r
459\r
460 CoreAcquireEventLock ();\r
461\r
462 if ((Type & EVT_NOTIFY_SIGNAL) != 0x00000000) {\r
463 //\r
464 // The Event's NotifyFunction must be queued whenever the event is signaled\r
465 //\r
466 InsertHeadList (&gEventSignalQueue, &IEvent->SignalLink);\r
467 }\r
468\r
469 CoreReleaseEventLock ();\r
470\r
471 //\r
472 // Done\r
473 //\r
474 return EFI_SUCCESS;\r
475}\r
476\r
477\r
478\r
479EFI_STATUS\r
480EFIAPI\r
481CoreSignalEvent (\r
482 IN EFI_EVENT UserEvent\r
483 )\r
484/*++\r
485\r
486Routine Description:\r
487\r
488 Signals the event. Queues the event to be notified if needed\r
489\r
490Arguments:\r
491\r
492 UserEvent - The event to signal\r
493\r
494Returns:\r
495\r
496 EFI_INVALID_PARAMETER - Parameters are not valid.\r
497\r
498 EFI_SUCCESS - The event was signaled.\r
499\r
500--*/\r
501{\r
502 IEVENT *Event;\r
503\r
504 Event = UserEvent;\r
505\r
506 if (Event == NULL) {\r
507 return EFI_INVALID_PARAMETER;\r
508 }\r
509\r
510 if (Event->Signature != EVENT_SIGNATURE) {\r
511 return EFI_INVALID_PARAMETER;\r
512 }\r
513\r
514 CoreAcquireEventLock ();\r
515\r
516 //\r
517 // If the event is not already signalled, do so\r
518 //\r
519\r
520 if (Event->SignalCount == 0x00000000) {\r
521 Event->SignalCount++;\r
522\r
523 //\r
524 // If signalling type is a notify function, queue it\r
525 //\r
526 if (Event->Type & EVT_NOTIFY_SIGNAL) {\r
527 if (Event->ExFlag) {\r
528 //\r
529 // The CreateEventEx() style requires all members of the Event Group\r
530 // to be signaled.\r
531 //\r
532 CoreReleaseEventLock ();\r
533 CoreNotifySignalList (&Event->EventGroup);\r
534 CoreAcquireEventLock ();\r
535 } else {\r
536 CoreNotifyEvent (Event);\r
537 }\r
538 }\r
539 }\r
540\r
541 CoreReleaseEventLock ();\r
542 return EFI_SUCCESS;\r
543}\r
544\r
545\r
546EFI_STATUS\r
547EFIAPI\r
548CoreCheckEvent (\r
549 IN EFI_EVENT UserEvent\r
550 )\r
551/*++\r
552\r
553Routine Description:\r
554\r
555 Check the status of an event\r
556\r
557Arguments:\r
558\r
559 UserEvent - The event to check\r
560\r
561Returns:\r
562\r
563 EFI_SUCCESS - The event is in the signaled state\r
564 EFI_NOT_READY - The event is not in the signaled state\r
565 EFI_INVALID_PARAMETER - Event is of type EVT_NOTIFY_SIGNAL\r
566\r
567--*/\r
568\r
569{\r
570 IEVENT *Event;\r
571 EFI_STATUS Status;\r
572\r
573 Event = UserEvent;\r
574\r
575 if (Event == NULL) {\r
576 return EFI_INVALID_PARAMETER;\r
577 }\r
578\r
579 if (Event->Signature != EVENT_SIGNATURE) {\r
580 return EFI_INVALID_PARAMETER;\r
581 }\r
582\r
583 if (Event->Type & EVT_NOTIFY_SIGNAL) {\r
584 return EFI_INVALID_PARAMETER;\r
585 }\r
586\r
587 Status = EFI_NOT_READY;\r
588\r
589 if (!Event->SignalCount && (Event->Type & EVT_NOTIFY_WAIT)) {\r
590\r
591 //\r
592 // Queue the wait notify function\r
593 //\r
594\r
595 CoreAcquireEventLock ();\r
596 if (!Event->SignalCount) {\r
597 CoreNotifyEvent (Event);\r
598 }\r
599 CoreReleaseEventLock ();\r
600 }\r
601\r
602 //\r
603 // If the even looks signalled, get the lock and clear it\r
604 //\r
605\r
606 if (Event->SignalCount) {\r
607 CoreAcquireEventLock ();\r
608\r
609 if (Event->SignalCount) {\r
610 Event->SignalCount = 0;\r
611 Status = EFI_SUCCESS;\r
612 }\r
613\r
614 CoreReleaseEventLock ();\r
615 }\r
616\r
617 return Status;\r
618}\r
619\r
620\r
621\r
622EFI_STATUS\r
623EFIAPI\r
624CoreWaitForEvent (\r
625 IN UINTN NumberOfEvents,\r
626 IN EFI_EVENT *UserEvents,\r
627 OUT UINTN *UserIndex\r
628 )\r
629/*++\r
630\r
631Routine Description:\r
632\r
633 Stops execution until an event is signaled.\r
634\r
635Arguments:\r
636\r
637 NumberOfEvents - The number of events in the UserEvents array\r
638 UserEvents - An array of EFI_EVENT\r
639 UserIndex - Pointer to the index of the event which satisfied the wait condition\r
640\r
641Returns:\r
642\r
643 EFI_SUCCESS - The event indicated by Index was signaled.\r
644 EFI_INVALID_PARAMETER - The event indicated by Index has a notification function or\r
645 Event was not a valid type\r
646 EFI_UNSUPPORTED - The current TPL is not TPL_APPLICATION\r
647\r
648--*/\r
649\r
650{\r
651 EFI_STATUS Status;\r
652 UINTN Index;\r
653\r
654 //\r
655 // Can only WaitForEvent at TPL_APPLICATION\r
656 //\r
657 if (gEfiCurrentTpl != TPL_APPLICATION) {\r
658 return EFI_UNSUPPORTED;\r
659 }\r
660\r
661 for(;;) {\r
662\r
663 for(Index = 0; Index < NumberOfEvents; Index++) {\r
664\r
665 Status = CoreCheckEvent (UserEvents[Index]);\r
666\r
667 //\r
668 // provide index of event that caused problem\r
669 //\r
670 if (Status != EFI_NOT_READY) {\r
671 *UserIndex = Index;\r
672 return Status;\r
673 }\r
674 }\r
675\r
676 //\r
677 // This was the location of the Idle loop callback in EFI 1.x reference\r
678 // code. We don't have that concept in this base at this point.\r
679 //\r
680 }\r
681}\r
682\r
683\r
684EFI_STATUS\r
685EFIAPI\r
686CoreCloseEvent (\r
687 IN EFI_EVENT UserEvent\r
688 )\r
689/*++\r
690\r
691Routine Description:\r
692\r
693 Closes an event and frees the event structure.\r
694\r
695Arguments:\r
696\r
697 UserEvent - Event to close\r
698\r
699Returns:\r
700\r
701 EFI_INVALID_PARAMETER - Parameters are not valid.\r
702\r
703 EFI_SUCCESS - The event has been closed\r
704\r
705--*/\r
706\r
707{\r
708 EFI_STATUS Status;\r
709 IEVENT *Event;\r
710\r
711 Event = UserEvent;\r
712\r
713 if (Event == NULL) {\r
714 return EFI_INVALID_PARAMETER;\r
715 }\r
716\r
717 if (Event->Signature != EVENT_SIGNATURE) {\r
718 return EFI_INVALID_PARAMETER;\r
719 }\r
720\r
721 //\r
722 // If it's a timer event, make sure it's not pending\r
723 //\r
724 if (Event->Type & EVT_TIMER) {\r
725 CoreSetTimer (Event, TimerCancel, 0);\r
726 }\r
727\r
728 CoreAcquireEventLock ();\r
729\r
730 //\r
731 // If the event is queued somewhere, remove it\r
732 //\r
733\r
734 if (Event->RuntimeData.Link.ForwardLink != NULL) {\r
735 RemoveEntryList (&Event->RuntimeData.Link);\r
736 }\r
737\r
738 if (Event->NotifyLink.ForwardLink != NULL) {\r
739 RemoveEntryList (&Event->NotifyLink);\r
740 }\r
741\r
742 if (Event->SignalLink.ForwardLink != NULL) {\r
743 RemoveEntryList (&Event->SignalLink);\r
744 }\r
745\r
746 CoreReleaseEventLock ();\r
747\r
748 //\r
749 // If the event is registered on a protocol notify, then remove it from the protocol database\r
750 //\r
751 CoreUnregisterProtocolNotify (Event);\r
752\r
753 Status = CoreFreePool (Event);\r
754 ASSERT_EFI_ERROR (Status);\r
755\r
756 return Status;\r
757}\r