]> git.proxmox.com Git - mirror_edk2.git/blobdiff - EdkModulePkg/Core/Dxe/Event/event.c
git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@430 6f19259b...
[mirror_edk2.git] / EdkModulePkg / Core / Dxe / Event / event.c
index 6751b18e6f9c90358eb5bb0bf16f8af537eb6d5c..ae6b0a849d297c7270e5e46e6f0e742ced7f1a0d 100644 (file)
-/*++
-
-Copyright (c) 2006, Intel Corporation                                                         
-All rights reserved. This program and the accompanying materials                          
-are licensed and made available under the terms and conditions of the BSD License         
-which accompanies this distribution.  The full text of the license may be found at        
-http://opensource.org/licenses/bsd-license.php                                            
-                                                                                          
-THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,                     
-WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.             
-
-Module Name:
-
-    event.c
-
-Abstract:
-
-    EFI Event support
---*/
-
-
-#include <DxeMain.h>
-
-//
-// Enumerate the valid types
-//
-UINT32 mEventTable[] = {
-  //
-  // 0x80000200       Timer event with a notification function that is
-  // queue when the event is signaled with SignalEvent()
-  //
-  EFI_EVENT_TIMER | EFI_EVENT_NOTIFY_SIGNAL,
-  //
-  // 0x80000000       Timer event without a notification function. It can be
-  // signaled with SignalEvent() and checked with CheckEvent() or WaitForEvent().
-  //
-  EFI_EVENT_TIMER,
-  //
-  // 0x00000100       Generic event with a notification function that 
-  // can be waited on with CheckEvent() or WaitForEvent()
-  //
-  EFI_EVENT_NOTIFY_WAIT,
-  //
-  // 0x00000200       Generic event with a notification function that 
-  // is queue when the event is signaled with SignalEvent()
-  //
-  EFI_EVENT_NOTIFY_SIGNAL,
-  //
-  // 0x00000201       ExitBootServicesEvent.  
-  //
-  EFI_EVENT_SIGNAL_EXIT_BOOT_SERVICES,
-  //
-  // 0x60000202       SetVirtualAddressMapEvent.
-  //
-  EFI_EVENT_SIGNAL_VIRTUAL_ADDRESS_CHANGE,
-
-#if (EFI_SPECIFICATION_VERSION < 0x00020000)
-  //
-  // 0x00000203       ReadyToBootEvent.
-  //
-  EFI_EVENT_SIGNAL_READY_TO_BOOT,
-  //
-  // 0x00000204       LegacyBootEvent.
-  //
-  EFI_EVENT_SIGNAL_LEGACY_BOOT,
-  //
-  // 0x00000603       Signal all ReadyToBootEvents.
-  //
-  EFI_EVENT_NOTIFY_SIGNAL_ALL | EFI_EVENT_SIGNAL_READY_TO_BOOT,
-  //
-  // 0x00000604       Signal all LegacyBootEvents.
-  //
-  EFI_EVENT_NOTIFY_SIGNAL_ALL | EFI_EVENT_SIGNAL_LEGACY_BOOT,
-#endif
-
-  //
-  // 0x00000000       Generic event without a notification function. 
-  // It can be signaled with SignalEvent() and checked with CheckEvent() 
-  // or WaitForEvent().
-  //
-  0x00000000,
-  //
-  // 0x80000100       Timer event with a notification function that can be 
-  // waited on with CheckEvent() or WaitForEvent()
-  //
-  EFI_EVENT_TIMER | EFI_EVENT_NOTIFY_WAIT,
-};
-
-
-VOID
-CoreAcquireEventLock (
-  VOID
-  )
-/*++
-
-Routine Description:
-
-  Enter critical section by acquiring the lock on gEventQueueLock.
-
-Arguments:
-
-  None
-
-Returns:
-
-  None
-
---*/
-{
-  CoreAcquireLock (&gEventQueueLock);
-}
-
-
-VOID
-CoreReleaseEventLock (
-  VOID
-  )
-/*++
-
-Routine Description:
-
-  Exit critical section by releasing the lock on gEventQueueLock.
-
-Arguments:
-
-  None
-
-Returns:
-
-  None
-
---*/
-{
-  CoreReleaseLock (&gEventQueueLock);
-}
-
-
-EFI_STATUS
-CoreInitializeEventServices (
-  VOID
-  )
-/*++
-
-Routine Description:
-
-  Initializes "event" support and populates parts of the System and Runtime Table.
-
-Arguments:
-
-  None
-    
-Returns:
-
-  EFI_SUCCESS - Always return success
-
---*/
-{
-  UINTN        Index;
-
-  for (Index=0; Index <= EFI_TPL_HIGH_LEVEL; Index++) {
-    InitializeListHead (&gEventQueue[Index]);
-  }
-
-  CoreInitializeTimer ();
-  
-  return EFI_SUCCESS;
-}
-
-
-EFI_STATUS
-CoreShutdownEventServices (
-  VOID
-  )
-/*++
-
-Routine Description:
-
-  Register all runtime events to make sure they are still available after ExitBootService.
-
-Arguments:
-
-  None
-    
-Returns:
-
-  EFI_SUCCESS - Always return success.
-
---*/
-{
-  LIST_ENTRY        *Link;
-  IEVENT            *Event;
-
-  //
-  // The Runtime AP is required for the core to function!
-  //
-  ASSERT (gRuntime != NULL);
-
-  for (Link = mRuntimeEventList.ForwardLink; Link != &mRuntimeEventList; Link = Link->ForwardLink) {
-    Event = CR (Link, IEVENT, RuntimeLink, EVENT_SIGNATURE);
-    gRuntime->RegisterEvent (
-                gRuntime, 
-                Event->Type, 
-                Event->NotifyTpl, 
-                Event->NotifyFunction, 
-                Event->NotifyContext, 
-                (VOID **)Event
-                );
-  }
-
-  return EFI_SUCCESS;
-}
-
-
-VOID
-CoreDispatchEventNotifies (
-  IN EFI_TPL      Priority
-  )
-/*++
-
-Routine Description:
-
-  Dispatches all pending events. 
-
-Arguments:
-
-  Priority - The task priority level of event notifications to dispatch
-    
-Returns:
-
-  None
-
---*/
-{
-  IEVENT          *Event;
-  LIST_ENTRY      *Head;
-  
-  CoreAcquireEventLock ();
-  ASSERT (gEventQueueLock.OwnerTpl == Priority);
-  Head = &gEventQueue[Priority];
-
-  //
-  // Dispatch all the pending notifications
-  //
-  while (!IsListEmpty (Head)) {
-      
-    Event = CR (Head->ForwardLink, IEVENT, NotifyLink, EVENT_SIGNATURE);
-    RemoveEntryList (&Event->NotifyLink);
-
-    Event->NotifyLink.ForwardLink = NULL;
-
-    //
-    // Only clear the SIGNAL status if it is a SIGNAL type event.
-    // WAIT type events are only cleared in CheckEvent()
-    //
-    if (Event->Type & EFI_EVENT_NOTIFY_SIGNAL) {
-      Event->SignalCount = 0;
-    }
-
-    CoreReleaseEventLock ();
-      
-    //
-    // Notify this event
-    //
-    ASSERT (Event->NotifyFunction != NULL);
-    Event->NotifyFunction (Event, Event->NotifyContext);
-
-    //
-    // Check for next pending event
-    //
-    CoreAcquireEventLock ();
-  }
-
-  gEventPending &= ~(1 << Priority);
-  CoreReleaseEventLock ();
-}
-
-
-VOID
-STATIC
-CoreNotifyEvent (
-  IN  IEVENT      *Event
-  )
-/*++
-
-Routine Description:
-
-  Queues the event's notification function to fire
-
-Arguments:
-
-  Event       - The Event to notify
-    
-Returns:
-
-  None
-
---*/
-{
-
-  //
-  // Event database must be locked
-  //
-  ASSERT_LOCKED (&gEventQueueLock);
-
-  //
-  // If the event is queued somewhere, remove it
-  //
-
-  if (Event->NotifyLink.ForwardLink != NULL) {
-    RemoveEntryList (&Event->NotifyLink);
-    Event->NotifyLink.ForwardLink = NULL;
-  }
-
-  // 
-  // Queue the event to the pending notification list
-  //
-
-  InsertTailList (&gEventQueue[Event->NotifyTpl], &Event->NotifyLink);
-  gEventPending |= (UINTN)(1 << Event->NotifyTpl);
-}
-
-
-
-VOID
-CoreNotifySignalList (
-  IN EFI_GUID     *EventGroup
-  )
-/*++
-
-Routine Description:
-  Signals all events in the EventGroup
-
-Arguments:
-  EventGroup - The list to signal
-    
-Returns:
-
-  None
-
---*/
-{
-  LIST_ENTRY              *Link;
-  LIST_ENTRY              *Head;
-  IEVENT                  *Event;
-
-  CoreAcquireEventLock ();
-
-  Head = &gEventSignalQueue;
-  for (Link = Head->ForwardLink; Link != Head; Link = Link->ForwardLink) {
-    Event = CR (Link, IEVENT, SignalLink, EVENT_SIGNATURE);
-    if (CompareGuid (&Event->EventGroup, EventGroup)) {
-      CoreNotifyEvent (Event);
-    }
-  }
-
-  CoreReleaseEventLock ();
-}
-
-
-#if (EFI_SPECIFICATION_VERSION < 0x00020000)
-
-static
-VOID
-EFIAPI
-EventNofitySignalAllNullEvent (
-  IN EFI_EVENT                Event,
-  IN VOID                     *Context
-  )
-{
-  //
-  // This null event is a size efficent way to enusre that 
-  // EFI_EVENT_NOTIFY_SIGNAL_ALL is error checked correctly.
-  // EFI_EVENT_NOTIFY_SIGNAL_ALL is now mapped into 
-  // CreateEventEx() and this function is used to make the
-  // old error checking in CreateEvent() for Tiano extensions
-  // function.
-  //
-  return;
-}
-
-#endif
-
-
-
-
-EFI_STATUS
-EFIAPI
-CoreCreateEvent (
-  IN UINT32                   Type,
-  IN EFI_TPL                  NotifyTpl,
-  IN EFI_EVENT_NOTIFY         NotifyFunction, OPTIONAL
-  IN VOID                     *NotifyContext, OPTIONAL
-  OUT EFI_EVENT               *Event
-  )
-/*++
-
-Routine Description:
-  Creates a general-purpose event structure
-
-Arguments:
-  Type                - The type of event to create and its mode and attributes
-  NotifyTpl           - The task priority level of event notifications
-  NotifyFunction      - Pointer to the events notification function
-  NotifyContext       - Pointer to the notification functions context; corresponds to
-                        parameter "Context" in the notification function
-  Event               - Pointer to the newly created event if the call succeeds; undefined otherwise
-
-Returns:
-  EFI_SUCCESS           - The event structure was created
-  EFI_INVALID_PARAMETER - One of the parameters has an invalid value
-  EFI_OUT_OF_RESOURCES  - The event could not be allocated
-
---*/
-{ 
-  EFI_GUID            *GuidPtr;
-  EFI_EVENT_NOTIFY    Function;
-  
-  GuidPtr = NULL;
-  Function = NotifyFunction;
-
-#if (EFI_SPECIFICATION_VERSION < 0x00020000)
-  //
-  // Clear EFI_EVENT_NOFITY_SIGNAL_ALL (Tiano extension) as all events in the 
-  //  EventGroup now have this property. So we need to filter it out.
-  //
-  if (Type & EFI_EVENT_NOTIFY_SIGNAL_ALL) {
-    Type &= ~EFI_EVENT_NOTIFY_SIGNAL_ALL;
-    Function = EventNofitySignalAllNullEvent;
-  }
-
-  //
-  // Map the Tiano extensions Events to CreateEventEx form
-  //
-  if (Type == EFI_EVENT_SIGNAL_READY_TO_BOOT) {
-    GuidPtr = &gEfiEventReadyToBootGuid;
-  } else if (Type == EFI_EVENT_SIGNAL_LEGACY_BOOT) {
-    GuidPtr = &gEfiEventLegacyBootGuid
-  }
-#endif
-
-  //
-  // Convert EFI 1.10 Events to thier UEFI 2.0 CreateEventEx mapping
-  // 
-  if (Type == EVENT_SIGNAL_EXIT_BOOT_SERVICES) {
-    GuidPtr = &gEfiEventExitBootServicesGuid;
-  } else if (Type == EVENT_SIGNAL_VIRTUAL_ADDRESS_CHANGE) {
-    GuidPtr = &gEfiEventVirtualAddressChangeGuid;
-  }
-  
-  return CoreCreateEventEx (Type, NotifyTpl, Function, NotifyContext, GuidPtr, Event);
-}
-
-
-EFI_STATUS
-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
-  )
-/*++
-
-Routine Description:
-  Creates a general-purpose event structure
-
-Arguments:
-  Type                - The type of event to create and its mode and attributes
-  NotifyTpl           - The task priority level of event notifications
-  NotifyFunction      - Pointer to the events notification function
-  NotifyContext       - Pointer to the notification functions context; corresponds to
-                        parameter "Context" in the notification function
-  EventGrout          - GUID for EventGroup if NULL act the same as gBS->CreateEvent().
-  Event               - Pointer to the newly created event if the call succeeds; undefined otherwise
-
-Returns:
-  EFI_SUCCESS           - The event structure was created
-  EFI_INVALID_PARAMETER - One of the parameters has an invalid value
-  EFI_OUT_OF_RESOURCES  - The event could not be allocated
-
---*/
-{
-  EFI_STATUS      Status;
-  IEVENT          *IEvent;
-  INTN            Index;
-
-
-  if ((Event == NULL) || (NotifyTpl == EFI_TPL_APPLICATION)) {
-    return EFI_INVALID_PARAMETER;
-  }
-
-  //
-  // Check to make sure no reserved flags are set
-  //
-  Status = EFI_INVALID_PARAMETER;
-  for (Index = 0; Index < (sizeof (mEventTable) / sizeof (UINT32)); Index++) {
-     if (Type == mEventTable[Index]) {
-       Status = EFI_SUCCESS;
-       break;
-     }
-  }
-  if(EFI_ERROR (Status)) {
-    return EFI_INVALID_PARAMETER;
-  }
-
-  //
-  // If it's a notify type of event, check its parameters
-  //
-  if ((Type & (EFI_EVENT_NOTIFY_WAIT | EFI_EVENT_NOTIFY_SIGNAL))) {
-    //
-    // Check for an invalid NotifyFunction or NotifyTpl
-    //
-    if ((NotifyFunction == NULL) || 
-        (NotifyTpl < EFI_TPL_APPLICATION) || 
-       (NotifyTpl >= EFI_TPL_HIGH_LEVEL)) {
-      return EFI_INVALID_PARAMETER;
-    }
-
-  } else {
-    //
-    // No notification needed, zero ignored values
-    //
-    NotifyTpl = 0;
-    NotifyFunction = NULL;
-    NotifyContext = NULL;
-  }
-
-  //
-  // Allcoate and initialize a new event structure.
-  //
-  Status = CoreAllocatePool (
-             (Type & EFI_EVENT_RUNTIME) ? EfiRuntimeServicesData: EfiBootServicesData, 
-             sizeof (IEVENT),
-             (VOID **)&IEvent
-             );
-  if (EFI_ERROR (Status)) {
-    return EFI_OUT_OF_RESOURCES;
-  }
-
-  SetMem (IEvent, sizeof (IEVENT), 0);
-
-  IEvent->Signature = EVENT_SIGNATURE;
-  IEvent->Type = Type;
-  
-  IEvent->NotifyTpl      = NotifyTpl;
-  IEvent->NotifyFunction = NotifyFunction;
-  IEvent->NotifyContext  = (VOID *)NotifyContext;
-  if (EventGroup != NULL) {
-    CopyGuid (&IEvent->EventGroup, EventGroup);
-    IEvent->ExFlag = TRUE;
-  }
-
-  *Event = IEvent;
-
-  if (Type & EFI_EVENT_RUNTIME) {
-    //
-    // Keep a list of all RT events so we can tell the RT AP.
-    //
-    InsertTailList (&mRuntimeEventList, &IEvent->RuntimeLink);
-  }
-
-  CoreAcquireEventLock ();
-  
-  if ((Type & EFI_EVENT_NOTIFY_SIGNAL) != 0x00000000) {
-    //
-    // The Event's NotifyFunction must be queued whenever the event is signaled
-    //
-    InsertHeadList (&gEventSignalQueue, &IEvent->SignalLink);
-  }
-  
-  CoreReleaseEventLock ();
-  
-  //
-  // Done
-  //
-  return EFI_SUCCESS;
-}
-
-
-
-EFI_STATUS
-EFIAPI
-CoreSignalEvent (
-  IN EFI_EVENT    UserEvent
-  )
-/*++
-
-Routine Description:
-
-  Signals the event.  Queues the event to be notified if needed
-    
-Arguments:
-
-  UserEvent - The event to signal
-    
-Returns:
-
-  EFI_INVALID_PARAMETER - Parameters are not valid.
-  
-  EFI_SUCCESS - The event was signaled.
-
---*/
-{
-  IEVENT          *Event;
-
-  Event = UserEvent;
-
-  if (Event == NULL) {
-    return EFI_INVALID_PARAMETER;
-  }
-
-  if (Event->Signature != EVENT_SIGNATURE) {
-    return EFI_INVALID_PARAMETER;
-  }
-
-  CoreAcquireEventLock ();
-
-  //
-  // If the event is not already signalled, do so
-  //
-
-  if (Event->SignalCount == 0x00000000) {
-    Event->SignalCount++;
-
-    //
-    // If signalling type is a notify function, queue it
-    //
-    if (Event->Type & EFI_EVENT_NOTIFY_SIGNAL) {
-      if (Event->ExFlag) {
-        //
-        // The CreateEventEx() style requires all members of the Event Group 
-        //  to be signaled. 
-        //
-        CoreReleaseEventLock ();
-        CoreNotifySignalList (&Event->EventGroup);
-        CoreAcquireEventLock ();
-       } else {
-        CoreNotifyEvent (Event);
-      }
-    }
-  }
-
-  CoreReleaseEventLock ();
-  return EFI_SUCCESS;
-}
-
-
-EFI_STATUS
-EFIAPI
-CoreCheckEvent (
-  IN EFI_EVENT        UserEvent
-  )
-/*++
-
-Routine Description:
-
-  Check the status of an event
-    
-Arguments:
-
-  UserEvent - The event to check
-    
-Returns:
-
-  EFI_SUCCESS           - The event is in the signaled state
-  EFI_NOT_READY         - The event is not in the signaled state
-  EFI_INVALID_PARAMETER - Event is of type EVT_NOTIFY_SIGNAL
-
---*/
-
-{
-  IEVENT      *Event;
-  EFI_STATUS  Status;
-
-  Event = UserEvent;
-
-  if (Event == NULL) {
-    return EFI_INVALID_PARAMETER;
-  }
-
-  if (Event->Signature != EVENT_SIGNATURE) {
-    return EFI_INVALID_PARAMETER;
-  }
-
-  if (Event->Type & EFI_EVENT_NOTIFY_SIGNAL) {
-    return EFI_INVALID_PARAMETER;
-  }
-
-  Status = EFI_NOT_READY;
-
-  if (!Event->SignalCount && (Event->Type & EFI_EVENT_NOTIFY_WAIT)) {
-
-    //
-    // Queue the wait notify function
-    //
-
-    CoreAcquireEventLock ();
-    if (!Event->SignalCount) {
-      CoreNotifyEvent (Event);
-    }
-    CoreReleaseEventLock ();
-  }
-
-  //
-  // If the even looks signalled, get the lock and clear it
-  //
-
-  if (Event->SignalCount) {
-    CoreAcquireEventLock ();
-
-    if (Event->SignalCount) {
-      Event->SignalCount = 0;
-      Status = EFI_SUCCESS;
-    }
-
-    CoreReleaseEventLock ();
-  }
-
-  return Status;
-}
-
-
-
-EFI_STATUS
-EFIAPI
-CoreWaitForEvent (
-  IN UINTN        NumberOfEvents,
-  IN EFI_EVENT    *UserEvents,
-  OUT UINTN       *UserIndex
-  )
-/*++
-
-Routine Description:
-
-  Stops execution until an event is signaled.
-    
-Arguments:
-
-  NumberOfEvents  - The number of events in the UserEvents array
-  UserEvents      - An array of EFI_EVENT
-  UserIndex       - Pointer to the index of the event which satisfied the wait condition
-    
-Returns:
-
-  EFI_SUCCESS           - The event indicated by Index was signaled.
-  EFI_INVALID_PARAMETER - The event indicated by Index has a notification function or 
-                          Event was not a valid type
-  EFI_UNSUPPORTED       - The current TPL is not TPL_APPLICATION
-
---*/
-
-{
-  EFI_STATUS      Status;
-  UINTN           Index;
-
-  //
-  // Can only WaitForEvent at TPL_APPLICATION
-  //
-  if (gEfiCurrentTpl != EFI_TPL_APPLICATION) {
-    return EFI_UNSUPPORTED;
-  }
-
-  for(;;) {
-      
-    for(Index = 0; Index < NumberOfEvents; Index++) {
-
-      Status = CoreCheckEvent (UserEvents[Index]);
-
-      //
-      // provide index of event that caused problem
-      //
-      if (Status != EFI_NOT_READY) {
-        *UserIndex = Index;
-        return Status;
-      }
-    }
-
-    //
-    // This was the location of the Idle loop callback in EFI 1.x reference
-    // code. We don't have that concept in this base at this point.
-    // 
-  }
-}
-
-
-EFI_STATUS
-EFIAPI
-CoreCloseEvent (
-  IN EFI_EVENT    UserEvent
-  )
-/*++
-
-Routine Description:
-
-  Closes an event and frees the event structure.
-    
-Arguments:
-
-  UserEvent - Event to close
-    
-Returns:
-
-  EFI_INVALID_PARAMETER - Parameters are not valid.
-  
-  EFI_SUCCESS - The event has been closed
-
---*/
-
-{
-  EFI_STATUS  Status;
-  IEVENT      *Event;
-
-  Event = UserEvent;
-
-  if (Event == NULL) {
-    return EFI_INVALID_PARAMETER;
-  }
-
-  if (Event->Signature != EVENT_SIGNATURE) {
-    return EFI_INVALID_PARAMETER;
-  }
-
-  //
-  // If it's a timer event, make sure it's not pending
-  //
-  if (Event->Type & EFI_EVENT_TIMER) {
-    CoreSetTimer (Event, TimerCancel, 0);
-  }
-
-  CoreAcquireEventLock ();
-
-  //
-  // If the event is queued somewhere, remove it
-  //
-
-  if (Event->RuntimeLink.ForwardLink != NULL) {
-    RemoveEntryList (&Event->RuntimeLink);
-  }
-
-  if (Event->NotifyLink.ForwardLink != NULL) {
-    RemoveEntryList (&Event->NotifyLink);
-  }
-
-  if (Event->SignalLink.ForwardLink != NULL) {
-    RemoveEntryList (&Event->SignalLink);
-  }
-
-  CoreReleaseEventLock ();
-
-  //
-  // If the event is registered on a protocol notify, then remove it from the protocol database
-  //
-  CoreUnregisterProtocolNotify (Event);
-
-  Status = CoreFreePool (Event);
-  ASSERT_EFI_ERROR (Status);
-
-  return Status;
-}
+/*++\r
+\r
+Copyright (c) 2006, Intel Corporation                                                         \r
+All rights reserved. This program and the accompanying materials                          \r
+are licensed and made available under the terms and conditions of the BSD License         \r
+which accompanies this distribution.  The full text of the license may be found at        \r
+http://opensource.org/licenses/bsd-license.php                                            \r
+                                                                                          \r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,                     \r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.             \r
+\r
+Module Name:\r
+\r
+    event.c\r
+\r
+Abstract:\r
+\r
+    EFI Event support\r
\r
+--*/\r
+\r
+\r
+#include <DxeMain.h>\r
+\r
+//\r
+// Enumerate the valid types\r
+//\r
+UINT32 mEventTable[] = {\r
+  //\r
+  // 0x80000200       Timer event with a notification function that is\r
+  // queue when the event is signaled with SignalEvent()\r
+  //\r
+  EFI_EVENT_TIMER | EFI_EVENT_NOTIFY_SIGNAL,\r
+  //\r
+  // 0x80000000       Timer event without a notification function. It can be\r
+  // signaled with SignalEvent() and checked with CheckEvent() or WaitForEvent().\r
+  //\r
+  EFI_EVENT_TIMER,\r
+  //\r
+  // 0x00000100       Generic event with a notification function that \r
+  // can be waited on with CheckEvent() or WaitForEvent()\r
+  //\r
+  EFI_EVENT_NOTIFY_WAIT,\r
+  //\r
+  // 0x00000200       Generic event with a notification function that \r
+  // is queue when the event is signaled with SignalEvent()\r
+  //\r
+  EFI_EVENT_NOTIFY_SIGNAL,\r
+  //\r
+  // 0x00000201       ExitBootServicesEvent.  \r
+  //\r
+  EFI_EVENT_SIGNAL_EXIT_BOOT_SERVICES,\r
+  //\r
+  // 0x60000202       SetVirtualAddressMapEvent.\r
+  //\r
+  EFI_EVENT_SIGNAL_VIRTUAL_ADDRESS_CHANGE,\r
+\r
+#if (EFI_SPECIFICATION_VERSION < 0x00020000)\r
+  //\r
+  // 0x00000203       ReadyToBootEvent.\r
+  //\r
+  EFI_EVENT_SIGNAL_READY_TO_BOOT,\r
+  //\r
+  // 0x00000204       LegacyBootEvent.\r
+  //\r
+  EFI_EVENT_SIGNAL_LEGACY_BOOT,\r
+  //\r
+  // 0x00000603       Signal all ReadyToBootEvents.\r
+  //\r
+  EFI_EVENT_NOTIFY_SIGNAL_ALL | EFI_EVENT_SIGNAL_READY_TO_BOOT,\r
+  //\r
+  // 0x00000604       Signal all LegacyBootEvents.\r
+  //\r
+  EFI_EVENT_NOTIFY_SIGNAL_ALL | EFI_EVENT_SIGNAL_LEGACY_BOOT,\r
+#endif\r
+\r
+  //\r
+  // 0x00000000       Generic event without a notification function. \r
+  // It can be signaled with SignalEvent() and checked with CheckEvent() \r
+  // or WaitForEvent().\r
+  //\r
+  0x00000000,\r
+  //\r
+  // 0x80000100       Timer event with a notification function that can be \r
+  // waited on with CheckEvent() or WaitForEvent()\r
+  //\r
+  EFI_EVENT_TIMER | EFI_EVENT_NOTIFY_WAIT,\r
+};\r
+\r
+\r
+VOID\r
+CoreAcquireEventLock (\r
+  VOID\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Enter critical section by acquiring the lock on gEventQueueLock.\r
+\r
+Arguments:\r
+\r
+  None\r
+\r
+Returns:\r
+\r
+  None\r
+\r
+--*/\r
+{\r
+  CoreAcquireLock (&gEventQueueLock);\r
+}\r
+\r
+\r
+VOID\r
+CoreReleaseEventLock (\r
+  VOID\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Exit critical section by releasing the lock on gEventQueueLock.\r
+\r
+Arguments:\r
+\r
+  None\r
+\r
+Returns:\r
+\r
+  None\r
+\r
+--*/\r
+{\r
+  CoreReleaseLock (&gEventQueueLock);\r
+}\r
+\r
+\r
+EFI_STATUS\r
+CoreInitializeEventServices (\r
+  VOID\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Initializes "event" support and populates parts of the System and Runtime Table.\r
+\r
+Arguments:\r
+\r
+  None\r
+    \r
+Returns:\r
+\r
+  EFI_SUCCESS - Always return success\r
+\r
+--*/\r
+{\r
+  UINTN        Index;\r
+\r
+  for (Index=0; Index <= EFI_TPL_HIGH_LEVEL; Index++) {\r
+    InitializeListHead (&gEventQueue[Index]);\r
+  }\r
+\r
+  CoreInitializeTimer ();\r
+  \r
+  return EFI_SUCCESS;\r
+}\r
+\r
+\r
+EFI_STATUS\r
+CoreShutdownEventServices (\r
+  VOID\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Register all runtime events to make sure they are still available after ExitBootService.\r
+\r
+Arguments:\r
+\r
+  None\r
+    \r
+Returns:\r
+\r
+  EFI_SUCCESS - Always return success.\r
+\r
+--*/\r
+{\r
+  LIST_ENTRY        *Link;\r
+  IEVENT            *Event;\r
+\r
+  //\r
+  // The Runtime AP is required for the core to function!\r
+  //\r
+  ASSERT (gRuntime != NULL);\r
+\r
+  for (Link = mRuntimeEventList.ForwardLink; Link != &mRuntimeEventList; Link = Link->ForwardLink) {\r
+    Event = CR (Link, IEVENT, RuntimeLink, EVENT_SIGNATURE);\r
+    gRuntime->RegisterEvent (\r
+                gRuntime, \r
+                Event->Type, \r
+                Event->NotifyTpl, \r
+                Event->NotifyFunction, \r
+                Event->NotifyContext, \r
+                (VOID **)Event\r
+                );\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+\r
+VOID\r
+CoreDispatchEventNotifies (\r
+  IN EFI_TPL      Priority\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Dispatches all pending events. \r
+\r
+Arguments:\r
+\r
+  Priority - The task priority level of event notifications to dispatch\r
+    \r
+Returns:\r
+\r
+  None\r
+\r
+--*/\r
+{\r
+  IEVENT          *Event;\r
+  LIST_ENTRY      *Head;\r
+  \r
+  CoreAcquireEventLock ();\r
+  ASSERT (gEventQueueLock.OwnerTpl == Priority);\r
+  Head = &gEventQueue[Priority];\r
+\r
+  //\r
+  // Dispatch all the pending notifications\r
+  //\r
+  while (!IsListEmpty (Head)) {\r
+      \r
+    Event = CR (Head->ForwardLink, IEVENT, NotifyLink, EVENT_SIGNATURE);\r
+    RemoveEntryList (&Event->NotifyLink);\r
+\r
+    Event->NotifyLink.ForwardLink = NULL;\r
+\r
+    //\r
+    // Only clear the SIGNAL status if it is a SIGNAL type event.\r
+    // WAIT type events are only cleared in CheckEvent()\r
+    //\r
+    if (Event->Type & EFI_EVENT_NOTIFY_SIGNAL) {\r
+      Event->SignalCount = 0;\r
+    }\r
+\r
+    CoreReleaseEventLock ();\r
+      \r
+    //\r
+    // Notify this event\r
+    //\r
+    ASSERT (Event->NotifyFunction != NULL);\r
+    Event->NotifyFunction (Event, Event->NotifyContext);\r
+\r
+    //\r
+    // Check for next pending event\r
+    //\r
+    CoreAcquireEventLock ();\r
+  }\r
+\r
+  gEventPending &= ~(1 << Priority);\r
+  CoreReleaseEventLock ();\r
+}\r
+\r
+\r
+VOID\r
+STATIC\r
+CoreNotifyEvent (\r
+  IN  IEVENT      *Event\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Queues the event's notification function to fire\r
+\r
+Arguments:\r
+\r
+  Event       - The Event to notify\r
+    \r
+Returns:\r
+\r
+  None\r
+\r
+--*/\r
+{\r
+\r
+  //\r
+  // Event database must be locked\r
+  //\r
+  ASSERT_LOCKED (&gEventQueueLock);\r
+\r
+  //\r
+  // If the event is queued somewhere, remove it\r
+  //\r
+\r
+  if (Event->NotifyLink.ForwardLink != NULL) {\r
+    RemoveEntryList (&Event->NotifyLink);\r
+    Event->NotifyLink.ForwardLink = NULL;\r
+  }\r
+\r
+  // \r
+  // Queue the event to the pending notification list\r
+  //\r
+\r
+  InsertTailList (&gEventQueue[Event->NotifyTpl], &Event->NotifyLink);\r
+  gEventPending |= (UINTN)(1 << Event->NotifyTpl);\r
+}\r
+\r
+\r
+\r
+VOID\r
+CoreNotifySignalList (\r
+  IN EFI_GUID     *EventGroup\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+  Signals all events in the EventGroup\r
+\r
+Arguments:\r
+  EventGroup - The list to signal\r
+    \r
+Returns:\r
+\r
+  None\r
+\r
+--*/\r
+{\r
+  LIST_ENTRY              *Link;\r
+  LIST_ENTRY              *Head;\r
+  IEVENT                  *Event;\r
+\r
+  CoreAcquireEventLock ();\r
+\r
+  Head = &gEventSignalQueue;\r
+  for (Link = Head->ForwardLink; Link != Head; Link = Link->ForwardLink) {\r
+    Event = CR (Link, IEVENT, SignalLink, EVENT_SIGNATURE);\r
+    if (CompareGuid (&Event->EventGroup, EventGroup)) {\r
+      CoreNotifyEvent (Event);\r
+    }\r
+  }\r
+\r
+  CoreReleaseEventLock ();\r
+}\r
+\r
+\r
+#if (EFI_SPECIFICATION_VERSION < 0x00020000)\r
+\r
+static\r
+VOID\r
+EFIAPI\r
+EventNofitySignalAllNullEvent (\r
+  IN EFI_EVENT                Event,\r
+  IN VOID                     *Context\r
+  )\r
+{\r
+  //\r
+  // This null event is a size efficent way to enusre that \r
+  // EFI_EVENT_NOTIFY_SIGNAL_ALL is error checked correctly.\r
+  // EFI_EVENT_NOTIFY_SIGNAL_ALL is now mapped into \r
+  // CreateEventEx() and this function is used to make the\r
+  // old error checking in CreateEvent() for Tiano extensions\r
+  // function.\r
+  //\r
+  return;\r
+}\r
+\r
+#endif\r
+\r
+\r
+\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+CoreCreateEvent (\r
+  IN UINT32                   Type,\r
+  IN EFI_TPL                  NotifyTpl,\r
+  IN EFI_EVENT_NOTIFY         NotifyFunction, OPTIONAL\r
+  IN VOID                     *NotifyContext, OPTIONAL\r
+  OUT EFI_EVENT               *Event\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+  Creates a general-purpose event structure\r
+\r
+Arguments:\r
+  Type                - The type of event to create and its mode and attributes\r
+  NotifyTpl           - The task priority level of event notifications\r
+  NotifyFunction      - Pointer to the events notification function\r
+  NotifyContext       - Pointer to the notification functions context; corresponds to\r
+                        parameter "Context" in the notification function\r
+  Event               - Pointer to the newly created event if the call succeeds; undefined otherwise\r
+\r
+Returns:\r
+  EFI_SUCCESS           - The event structure was created\r
+  EFI_INVALID_PARAMETER - One of the parameters has an invalid value\r
+  EFI_OUT_OF_RESOURCES  - The event could not be allocated\r
+\r
+--*/\r
+{ \r
+  EFI_GUID            *GuidPtr;\r
+  EFI_EVENT_NOTIFY    Function;\r
+  \r
+  GuidPtr = NULL;\r
+  Function = NotifyFunction;\r
+\r
+#if (EFI_SPECIFICATION_VERSION < 0x00020000)\r
+  //\r
+  // Clear EFI_EVENT_NOFITY_SIGNAL_ALL (Tiano extension) as all events in the \r
+  //  EventGroup now have this property. So we need to filter it out.\r
+  //\r
+  if (Type & EFI_EVENT_NOTIFY_SIGNAL_ALL) {\r
+    Type &= ~EFI_EVENT_NOTIFY_SIGNAL_ALL;\r
+    Function = EventNofitySignalAllNullEvent;\r
+  }\r
+\r
+  //\r
+  // Map the Tiano extensions Events to CreateEventEx form\r
+  //\r
+  if (Type == EFI_EVENT_SIGNAL_READY_TO_BOOT) {\r
+    GuidPtr = &gEfiEventReadyToBootGuid;\r
+  } else if (Type == EFI_EVENT_SIGNAL_LEGACY_BOOT) {\r
+    GuidPtr = &gEfiEventLegacyBootGuid\r
+  }\r
+#endif\r
+\r
+  //\r
+  // Convert EFI 1.10 Events to thier UEFI 2.0 CreateEventEx mapping\r
+  // \r
+  if (Type == EVENT_SIGNAL_EXIT_BOOT_SERVICES) {\r
+    GuidPtr = &gEfiEventExitBootServicesGuid;\r
+  } else if (Type == EVENT_SIGNAL_VIRTUAL_ADDRESS_CHANGE) {\r
+    GuidPtr = &gEfiEventVirtualAddressChangeGuid;\r
+  }\r
+  \r
+  return CoreCreateEventEx (Type, NotifyTpl, Function, NotifyContext, GuidPtr, Event);\r
+}\r
+\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+CoreCreateEventEx (\r
+  IN UINT32                   Type,\r
+  IN EFI_TPL                  NotifyTpl,\r
+  IN EFI_EVENT_NOTIFY         NotifyFunction, OPTIONAL\r
+  IN CONST VOID               *NotifyContext, OPTIONAL\r
+  IN CONST EFI_GUID           *EventGroup,    OPTIONAL\r
+  OUT EFI_EVENT               *Event\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+  Creates a general-purpose event structure\r
+\r
+Arguments:\r
+  Type                - The type of event to create and its mode and attributes\r
+  NotifyTpl           - The task priority level of event notifications\r
+  NotifyFunction      - Pointer to the events notification function\r
+  NotifyContext       - Pointer to the notification functions context; corresponds to\r
+                        parameter "Context" in the notification function\r
+  EventGrout          - GUID for EventGroup if NULL act the same as gBS->CreateEvent().\r
+  Event               - Pointer to the newly created event if the call succeeds; undefined otherwise\r
+\r
+Returns:\r
+  EFI_SUCCESS           - The event structure was created\r
+  EFI_INVALID_PARAMETER - One of the parameters has an invalid value\r
+  EFI_OUT_OF_RESOURCES  - The event could not be allocated\r
+\r
+--*/\r
+{\r
+  EFI_STATUS      Status;\r
+  IEVENT          *IEvent;\r
+  INTN            Index;\r
+\r
+\r
+  if ((Event == NULL) || (NotifyTpl == EFI_TPL_APPLICATION)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  //\r
+  // Check to make sure no reserved flags are set\r
+  //\r
+  Status = EFI_INVALID_PARAMETER;\r
+  for (Index = 0; Index < (sizeof (mEventTable) / sizeof (UINT32)); Index++) {\r
+     if (Type == mEventTable[Index]) {\r
+       Status = EFI_SUCCESS;\r
+       break;\r
+     }\r
+  }\r
+  if(EFI_ERROR (Status)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  //\r
+  // If it's a notify type of event, check its parameters\r
+  //\r
+  if ((Type & (EFI_EVENT_NOTIFY_WAIT | EFI_EVENT_NOTIFY_SIGNAL))) {\r
+    //\r
+    // Check for an invalid NotifyFunction or NotifyTpl\r
+    //\r
+    if ((NotifyFunction == NULL) || \r
+        (NotifyTpl < EFI_TPL_APPLICATION) || \r
+       (NotifyTpl >= EFI_TPL_HIGH_LEVEL)) {\r
+      return EFI_INVALID_PARAMETER;\r
+    }\r
+\r
+  } else {\r
+    //\r
+    // No notification needed, zero ignored values\r
+    //\r
+    NotifyTpl = 0;\r
+    NotifyFunction = NULL;\r
+    NotifyContext = NULL;\r
+  }\r
+\r
+  //\r
+  // Allcoate and initialize a new event structure.\r
+  //\r
+  Status = CoreAllocatePool (\r
+             (Type & EFI_EVENT_RUNTIME) ? EfiRuntimeServicesData: EfiBootServicesData, \r
+             sizeof (IEVENT),\r
+             (VOID **)&IEvent\r
+             );\r
+  if (EFI_ERROR (Status)) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  SetMem (IEvent, sizeof (IEVENT), 0);\r
+\r
+  IEvent->Signature = EVENT_SIGNATURE;\r
+  IEvent->Type = Type;\r
+  \r
+  IEvent->NotifyTpl      = NotifyTpl;\r
+  IEvent->NotifyFunction = NotifyFunction;\r
+  IEvent->NotifyContext  = (VOID *)NotifyContext;\r
+  if (EventGroup != NULL) {\r
+    CopyGuid (&IEvent->EventGroup, EventGroup);\r
+    IEvent->ExFlag = TRUE;\r
+  }\r
+\r
+  *Event = IEvent;\r
+\r
+  if (Type & EFI_EVENT_RUNTIME) {\r
+    //\r
+    // Keep a list of all RT events so we can tell the RT AP.\r
+    //\r
+    InsertTailList (&mRuntimeEventList, &IEvent->RuntimeLink);\r
+  }\r
+\r
+  CoreAcquireEventLock ();\r
+  \r
+  if ((Type & EFI_EVENT_NOTIFY_SIGNAL) != 0x00000000) {\r
+    //\r
+    // The Event's NotifyFunction must be queued whenever the event is signaled\r
+    //\r
+    InsertHeadList (&gEventSignalQueue, &IEvent->SignalLink);\r
+  }\r
+  \r
+  CoreReleaseEventLock ();\r
+  \r
+  //\r
+  // Done\r
+  //\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+CoreSignalEvent (\r
+  IN EFI_EVENT    UserEvent\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Signals the event.  Queues the event to be notified if needed\r
+    \r
+Arguments:\r
+\r
+  UserEvent - The event to signal\r
+    \r
+Returns:\r
+\r
+  EFI_INVALID_PARAMETER - Parameters are not valid.\r
+  \r
+  EFI_SUCCESS - The event was signaled.\r
+\r
+--*/\r
+{\r
+  IEVENT          *Event;\r
+\r
+  Event = UserEvent;\r
+\r
+  if (Event == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  if (Event->Signature != EVENT_SIGNATURE) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  CoreAcquireEventLock ();\r
+\r
+  //\r
+  // If the event is not already signalled, do so\r
+  //\r
+\r
+  if (Event->SignalCount == 0x00000000) {\r
+    Event->SignalCount++;\r
+\r
+    //\r
+    // If signalling type is a notify function, queue it\r
+    //\r
+    if (Event->Type & EFI_EVENT_NOTIFY_SIGNAL) {\r
+      if (Event->ExFlag) {\r
+        //\r
+        // The CreateEventEx() style requires all members of the Event Group \r
+        //  to be signaled. \r
+        //\r
+        CoreReleaseEventLock ();\r
+        CoreNotifySignalList (&Event->EventGroup);\r
+        CoreAcquireEventLock ();\r
+       } else {\r
+        CoreNotifyEvent (Event);\r
+      }\r
+    }\r
+  }\r
+\r
+  CoreReleaseEventLock ();\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+CoreCheckEvent (\r
+  IN EFI_EVENT        UserEvent\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Check the status of an event\r
+    \r
+Arguments:\r
+\r
+  UserEvent - The event to check\r
+    \r
+Returns:\r
+\r
+  EFI_SUCCESS           - The event is in the signaled state\r
+  EFI_NOT_READY         - The event is not in the signaled state\r
+  EFI_INVALID_PARAMETER - Event is of type EVT_NOTIFY_SIGNAL\r
+\r
+--*/\r
+\r
+{\r
+  IEVENT      *Event;\r
+  EFI_STATUS  Status;\r
+\r
+  Event = UserEvent;\r
+\r
+  if (Event == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  if (Event->Signature != EVENT_SIGNATURE) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  if (Event->Type & EFI_EVENT_NOTIFY_SIGNAL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  Status = EFI_NOT_READY;\r
+\r
+  if (!Event->SignalCount && (Event->Type & EFI_EVENT_NOTIFY_WAIT)) {\r
+\r
+    //\r
+    // Queue the wait notify function\r
+    //\r
+\r
+    CoreAcquireEventLock ();\r
+    if (!Event->SignalCount) {\r
+      CoreNotifyEvent (Event);\r
+    }\r
+    CoreReleaseEventLock ();\r
+  }\r
+\r
+  //\r
+  // If the even looks signalled, get the lock and clear it\r
+  //\r
+\r
+  if (Event->SignalCount) {\r
+    CoreAcquireEventLock ();\r
+\r
+    if (Event->SignalCount) {\r
+      Event->SignalCount = 0;\r
+      Status = EFI_SUCCESS;\r
+    }\r
+\r
+    CoreReleaseEventLock ();\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+CoreWaitForEvent (\r
+  IN UINTN        NumberOfEvents,\r
+  IN EFI_EVENT    *UserEvents,\r
+  OUT UINTN       *UserIndex\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Stops execution until an event is signaled.\r
+    \r
+Arguments:\r
+\r
+  NumberOfEvents  - The number of events in the UserEvents array\r
+  UserEvents      - An array of EFI_EVENT\r
+  UserIndex       - Pointer to the index of the event which satisfied the wait condition\r
+    \r
+Returns:\r
+\r
+  EFI_SUCCESS           - The event indicated by Index was signaled.\r
+  EFI_INVALID_PARAMETER - The event indicated by Index has a notification function or \r
+                          Event was not a valid type\r
+  EFI_UNSUPPORTED       - The current TPL is not TPL_APPLICATION\r
+\r
+--*/\r
+\r
+{\r
+  EFI_STATUS      Status;\r
+  UINTN           Index;\r
+\r
+  //\r
+  // Can only WaitForEvent at TPL_APPLICATION\r
+  //\r
+  if (gEfiCurrentTpl != EFI_TPL_APPLICATION) {\r
+    return EFI_UNSUPPORTED;\r
+  }\r
+\r
+  for(;;) {\r
+      \r
+    for(Index = 0; Index < NumberOfEvents; Index++) {\r
+\r
+      Status = CoreCheckEvent (UserEvents[Index]);\r
+\r
+      //\r
+      // provide index of event that caused problem\r
+      //\r
+      if (Status != EFI_NOT_READY) {\r
+        *UserIndex = Index;\r
+        return Status;\r
+      }\r
+    }\r
+\r
+    //\r
+    // This was the location of the Idle loop callback in EFI 1.x reference\r
+    // code. We don't have that concept in this base at this point.\r
+    // \r
+  }\r
+}\r
+\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+CoreCloseEvent (\r
+  IN EFI_EVENT    UserEvent\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Closes an event and frees the event structure.\r
+    \r
+Arguments:\r
+\r
+  UserEvent - Event to close\r
+    \r
+Returns:\r
+\r
+  EFI_INVALID_PARAMETER - Parameters are not valid.\r
+  \r
+  EFI_SUCCESS - The event has been closed\r
+\r
+--*/\r
+\r
+{\r
+  EFI_STATUS  Status;\r
+  IEVENT      *Event;\r
+\r
+  Event = UserEvent;\r
+\r
+  if (Event == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  if (Event->Signature != EVENT_SIGNATURE) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  //\r
+  // If it's a timer event, make sure it's not pending\r
+  //\r
+  if (Event->Type & EFI_EVENT_TIMER) {\r
+    CoreSetTimer (Event, TimerCancel, 0);\r
+  }\r
+\r
+  CoreAcquireEventLock ();\r
+\r
+  //\r
+  // If the event is queued somewhere, remove it\r
+  //\r
+\r
+  if (Event->RuntimeLink.ForwardLink != NULL) {\r
+    RemoveEntryList (&Event->RuntimeLink);\r
+  }\r
+\r
+  if (Event->NotifyLink.ForwardLink != NULL) {\r
+    RemoveEntryList (&Event->NotifyLink);\r
+  }\r
+\r
+  if (Event->SignalLink.ForwardLink != NULL) {\r
+    RemoveEntryList (&Event->SignalLink);\r
+  }\r
+\r
+  CoreReleaseEventLock ();\r
+\r
+  //\r
+  // If the event is registered on a protocol notify, then remove it from the protocol database\r
+  //\r
+  CoreUnregisterProtocolNotify (Event);\r
+\r
+  Status = CoreFreePool (Event);\r
+  ASSERT_EFI_ERROR (Status);\r
+\r
+  return Status;\r
+}\r