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