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