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