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