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