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