aboutsummaryrefslogtreecommitdiffstats
path: root/roms/edk2/MdeModulePkg/Core/Dxe/Event
diff options
context:
space:
mode:
Diffstat (limited to 'roms/edk2/MdeModulePkg/Core/Dxe/Event')
-rw-r--r--roms/edk2/MdeModulePkg/Core/Dxe/Event/Event.c784
-rw-r--r--roms/edk2/MdeModulePkg/Core/Dxe/Event/Event.h91
-rw-r--r--roms/edk2/MdeModulePkg/Core/Dxe/Event/Timer.c295
-rw-r--r--roms/edk2/MdeModulePkg/Core/Dxe/Event/Tpl.c148
4 files changed, 1318 insertions, 0 deletions
diff --git a/roms/edk2/MdeModulePkg/Core/Dxe/Event/Event.c b/roms/edk2/MdeModulePkg/Core/Dxe/Event/Event.c
new file mode 100644
index 000000000..c83c572c8
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Core/Dxe/Event/Event.c
@@ -0,0 +1,784 @@
+/** @file
+ UEFI Event support functions implemented in this file.
+
+Copyright (c) 2006 - 2017, Intel Corporation. All rights reserved.<BR>
+(C) Copyright 2015 Hewlett Packard Enterprise Development LP<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+
+#include "DxeMain.h"
+#include "Event.h"
+
+///
+/// gEfiCurrentTpl - Current Task priority level
+///
+EFI_TPL gEfiCurrentTpl = TPL_APPLICATION;
+
+///
+/// gEventQueueLock - Protects the event queues
+///
+EFI_LOCK gEventQueueLock = EFI_INITIALIZE_LOCK_VARIABLE (TPL_HIGH_LEVEL);
+
+///
+/// gEventQueue - A list of event's to notify for each priority level
+///
+LIST_ENTRY gEventQueue[TPL_HIGH_LEVEL + 1];
+
+///
+/// gEventPending - A bitmask of the EventQueues that are pending
+///
+UINTN gEventPending = 0;
+
+///
+/// gEventSignalQueue - A list of events to signal based on EventGroup type
+///
+LIST_ENTRY gEventSignalQueue = INITIALIZE_LIST_HEAD_VARIABLE (gEventSignalQueue);
+
+///
+/// Enumerate the valid types
+///
+UINT32 mEventTable[] = {
+ ///
+ /// 0x80000200 Timer event with a notification function that is
+ /// queue when the event is signaled with SignalEvent()
+ ///
+ EVT_TIMER | EVT_NOTIFY_SIGNAL,
+ ///
+ /// 0x80000000 Timer event without a notification function. It can be
+ /// signaled with SignalEvent() and checked with CheckEvent() or WaitForEvent().
+ ///
+ EVT_TIMER,
+ ///
+ /// 0x00000100 Generic event with a notification function that
+ /// can be waited on with CheckEvent() or WaitForEvent()
+ ///
+ EVT_NOTIFY_WAIT,
+ ///
+ /// 0x00000200 Generic event with a notification function that
+ /// is queue when the event is signaled with SignalEvent()
+ ///
+ EVT_NOTIFY_SIGNAL,
+ ///
+ /// 0x00000201 ExitBootServicesEvent.
+ ///
+ EVT_SIGNAL_EXIT_BOOT_SERVICES,
+ ///
+ /// 0x60000202 SetVirtualAddressMapEvent.
+ ///
+ EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE,
+
+ ///
+ /// 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()
+ ///
+ EVT_TIMER | EVT_NOTIFY_WAIT,
+};
+
+///
+/// gIdleLoopEvent - Event which is signalled when the core is idle
+///
+EFI_EVENT gIdleLoopEvent = NULL;
+
+
+/**
+ Enter critical section by acquiring the lock on gEventQueueLock.
+
+**/
+VOID
+CoreAcquireEventLock (
+ VOID
+ )
+{
+ CoreAcquireLock (&gEventQueueLock);
+}
+
+
+/**
+ Exit critical section by releasing the lock on gEventQueueLock.
+
+**/
+VOID
+CoreReleaseEventLock (
+ VOID
+ )
+{
+ CoreReleaseLock (&gEventQueueLock);
+}
+
+
+
+/**
+ Initializes "event" support.
+
+ @retval EFI_SUCCESS Always return success
+
+**/
+EFI_STATUS
+CoreInitializeEventServices (
+ VOID
+ )
+{
+ UINTN Index;
+
+ for (Index=0; Index <= TPL_HIGH_LEVEL; Index++) {
+ InitializeListHead (&gEventQueue[Index]);
+ }
+
+ CoreInitializeTimer ();
+
+ CoreCreateEventEx (
+ EVT_NOTIFY_SIGNAL,
+ TPL_NOTIFY,
+ EfiEventEmptyFunction,
+ NULL,
+ &gIdleLoopEventGuid,
+ &gIdleLoopEvent
+ );
+
+ return EFI_SUCCESS;
+}
+
+
+
+/**
+ Dispatches all pending events.
+
+ @param Priority The task priority level of event notifications
+ to dispatch
+
+**/
+VOID
+CoreDispatchEventNotifies (
+ IN EFI_TPL Priority
+ )
+{
+ 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 & EVT_NOTIFY_SIGNAL) != 0) {
+ Event->SignalCount = 0;
+ }
+
+ CoreReleaseEventLock ();
+
+ //
+ // Notify this event
+ //
+ ASSERT (Event->NotifyFunction != NULL);
+ Event->NotifyFunction (Event, Event->NotifyContext);
+
+ //
+ // Check for next pending event
+ //
+ CoreAcquireEventLock ();
+ }
+
+ gEventPending &= ~(UINTN)(1 << Priority);
+ CoreReleaseEventLock ();
+}
+
+
+
+/**
+ Queues the event's notification function to fire.
+
+ @param Event The Event to notify
+
+**/
+VOID
+CoreNotifyEvent (
+ IN IEVENT *Event
+ )
+{
+
+ //
+ // 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);
+}
+
+
+
+
+/**
+ Signals all events in the EventGroup.
+
+ @param EventGroup The list to signal
+
+**/
+VOID
+CoreNotifySignalList (
+ IN EFI_GUID *EventGroup
+ )
+{
+ 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 ();
+}
+
+
+/**
+ Creates an event.
+
+ @param Type The type of event to create and its mode and
+ attributes
+ @param NotifyTpl The task priority level of event notifications
+ @param NotifyFunction Pointer to the events notification function
+ @param NotifyContext Pointer to the notification functions context;
+ corresponds to parameter "Context" in the
+ notification function
+ @param Event Pointer to the newly created event if the call
+ succeeds; undefined otherwise
+
+ @retval EFI_SUCCESS The event structure was created
+ @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value
+ @retval EFI_OUT_OF_RESOURCES The event could not be allocated
+
+**/
+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
+ )
+{
+ return CoreCreateEventEx (Type, NotifyTpl, NotifyFunction, NotifyContext, NULL, Event);
+}
+
+
+
+/**
+ Creates an event in a group.
+
+ @param Type The type of event to create and its mode and
+ attributes
+ @param NotifyTpl The task priority level of event notifications
+ @param NotifyFunction Pointer to the events notification function
+ @param NotifyContext Pointer to the notification functions context;
+ corresponds to parameter "Context" in the
+ notification function
+ @param EventGroup GUID for EventGroup if NULL act the same as
+ gBS->CreateEvent().
+ @param Event Pointer to the newly created event if the call
+ succeeds; undefined otherwise
+
+ @retval EFI_SUCCESS The event structure was created
+ @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value
+ @retval EFI_OUT_OF_RESOURCES The event could not be allocated
+
+**/
+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
+ )
+{
+ //
+ // If it's a notify type of event, check for invalid NotifyTpl
+ //
+ if ((Type & (EVT_NOTIFY_WAIT | EVT_NOTIFY_SIGNAL)) != 0) {
+ if (NotifyTpl != TPL_APPLICATION &&
+ NotifyTpl != TPL_CALLBACK &&
+ NotifyTpl != TPL_NOTIFY) {
+ return EFI_INVALID_PARAMETER;
+ }
+ }
+
+ return CoreCreateEventInternal (Type, NotifyTpl, NotifyFunction, NotifyContext, EventGroup, Event);
+}
+
+/**
+ Creates a general-purpose event structure
+
+ @param Type The type of event to create and its mode and
+ attributes
+ @param NotifyTpl The task priority level of event notifications
+ @param NotifyFunction Pointer to the events notification function
+ @param NotifyContext Pointer to the notification functions context;
+ corresponds to parameter "Context" in the
+ notification function
+ @param EventGroup GUID for EventGroup if NULL act the same as
+ gBS->CreateEvent().
+ @param Event Pointer to the newly created event if the call
+ succeeds; undefined otherwise
+
+ @retval EFI_SUCCESS The event structure was created
+ @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value
+ @retval EFI_OUT_OF_RESOURCES The event could not be allocated
+
+**/
+EFI_STATUS
+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
+ )
+{
+ EFI_STATUS Status;
+ IEVENT *IEvent;
+ INTN Index;
+
+
+ if (Event == NULL) {
+ 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;
+ }
+
+ //
+ // Convert Event type for pre-defined Event groups
+ //
+ if (EventGroup != NULL) {
+ //
+ // For event group, type EVT_SIGNAL_EXIT_BOOT_SERVICES and EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE
+ // are not valid
+ //
+ if ((Type == EVT_SIGNAL_EXIT_BOOT_SERVICES) || (Type == EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE)) {
+ return EFI_INVALID_PARAMETER;
+ }
+ if (CompareGuid (EventGroup, &gEfiEventExitBootServicesGuid)) {
+ Type = EVT_SIGNAL_EXIT_BOOT_SERVICES;
+ } else if (CompareGuid (EventGroup, &gEfiEventVirtualAddressChangeGuid)) {
+ Type = EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE;
+ }
+ } else {
+ //
+ // Convert EFI 1.10 Events to their UEFI 2.0 CreateEventEx mapping
+ //
+ if (Type == EVT_SIGNAL_EXIT_BOOT_SERVICES) {
+ EventGroup = &gEfiEventExitBootServicesGuid;
+ } else if (Type == EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE) {
+ EventGroup = &gEfiEventVirtualAddressChangeGuid;
+ }
+ }
+
+ //
+ // If it's a notify type of event, check its parameters
+ //
+ if ((Type & (EVT_NOTIFY_WAIT | EVT_NOTIFY_SIGNAL)) != 0) {
+ //
+ // Check for an invalid NotifyFunction or NotifyTpl
+ //
+ if ((NotifyFunction == NULL) ||
+ (NotifyTpl <= TPL_APPLICATION) ||
+ (NotifyTpl >= TPL_HIGH_LEVEL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ } else {
+ //
+ // No notification needed, zero ignored values
+ //
+ NotifyTpl = 0;
+ NotifyFunction = NULL;
+ NotifyContext = NULL;
+ }
+
+ //
+ // Allocate and initialize a new event structure.
+ //
+ if ((Type & EVT_RUNTIME) != 0) {
+ IEvent = AllocateRuntimeZeroPool (sizeof (IEVENT));
+ } else {
+ IEvent = AllocateZeroPool (sizeof (IEVENT));
+ }
+ if (IEvent == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ 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 |= EVT_EXFLAG_EVENT_GROUP;
+ }
+
+ *Event = IEvent;
+
+ if ((Type & EVT_RUNTIME) != 0) {
+ //
+ // Keep a list of all RT events so we can tell the RT AP.
+ //
+ IEvent->RuntimeData.Type = Type;
+ IEvent->RuntimeData.NotifyTpl = NotifyTpl;
+ IEvent->RuntimeData.NotifyFunction = NotifyFunction;
+ IEvent->RuntimeData.NotifyContext = (VOID *) NotifyContext;
+ //
+ // Work around the bug in the Platform Init specification (v1.7), reported
+ // as Mantis#2017: "EFI_RUNTIME_EVENT_ENTRY.Event" should have type
+ // EFI_EVENT, not (EFI_EVENT*). The PI spec documents the field correctly
+ // as "The EFI_EVENT returned by CreateEvent()", but the type of the field
+ // doesn't match the natural language description. Therefore we need an
+ // explicit cast here.
+ //
+ IEvent->RuntimeData.Event = (EFI_EVENT *) IEvent;
+ InsertTailList (&gRuntime->EventHead, &IEvent->RuntimeData.Link);
+ }
+
+ CoreAcquireEventLock ();
+
+ if ((Type & EVT_NOTIFY_SIGNAL) != 0x00000000) {
+ //
+ // The Event's NotifyFunction must be queued whenever the event is signaled
+ //
+ InsertHeadList (&gEventSignalQueue, &IEvent->SignalLink);
+ }
+
+ CoreReleaseEventLock ();
+
+ //
+ // Done
+ //
+ return EFI_SUCCESS;
+}
+
+
+
+
+/**
+ Signals the event. Queues the event to be notified if needed.
+
+ @param UserEvent The event to signal .
+
+ @retval EFI_INVALID_PARAMETER Parameters are not valid.
+ @retval EFI_SUCCESS The event was signaled.
+
+**/
+EFI_STATUS
+EFIAPI
+CoreSignalEvent (
+ IN EFI_EVENT UserEvent
+ )
+{
+ 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 & EVT_NOTIFY_SIGNAL) != 0) {
+ if ((Event->ExFlag & EVT_EXFLAG_EVENT_GROUP) != 0) {
+ //
+ // 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;
+}
+
+
+
+/**
+ Check the status of an event.
+
+ @param UserEvent The event to check
+
+ @retval EFI_SUCCESS The event is in the signaled state
+ @retval EFI_NOT_READY The event is not in the signaled state
+ @retval EFI_INVALID_PARAMETER Event is of type EVT_NOTIFY_SIGNAL
+
+**/
+EFI_STATUS
+EFIAPI
+CoreCheckEvent (
+ IN EFI_EVENT UserEvent
+ )
+{
+ 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 & EVT_NOTIFY_SIGNAL) != 0) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Status = EFI_NOT_READY;
+
+ if ((Event->SignalCount == 0) && ((Event->Type & EVT_NOTIFY_WAIT) != 0)) {
+
+ //
+ // Queue the wait notify function
+ //
+ CoreAcquireEventLock ();
+ if (Event->SignalCount == 0) {
+ CoreNotifyEvent (Event);
+ }
+ CoreReleaseEventLock ();
+ }
+
+ //
+ // If the even looks signalled, get the lock and clear it
+ //
+
+ if (Event->SignalCount != 0) {
+ CoreAcquireEventLock ();
+
+ if (Event->SignalCount != 0) {
+ Event->SignalCount = 0;
+ Status = EFI_SUCCESS;
+ }
+
+ CoreReleaseEventLock ();
+ }
+
+ return Status;
+}
+
+
+
+/**
+ Stops execution until an event is signaled.
+
+ @param NumberOfEvents The number of events in the UserEvents array
+ @param UserEvents An array of EFI_EVENT
+ @param UserIndex Pointer to the index of the event which
+ satisfied the wait condition
+
+ @retval EFI_SUCCESS The event indicated by Index was signaled.
+ @retval EFI_INVALID_PARAMETER The event indicated by Index has a notification
+ function or Event was not a valid type
+ @retval EFI_UNSUPPORTED The current TPL is not TPL_APPLICATION
+
+**/
+EFI_STATUS
+EFIAPI
+CoreWaitForEvent (
+ IN UINTN NumberOfEvents,
+ IN EFI_EVENT *UserEvents,
+ OUT UINTN *UserIndex
+ )
+{
+ EFI_STATUS Status;
+ UINTN Index;
+
+ //
+ // Can only WaitForEvent at TPL_APPLICATION
+ //
+ if (gEfiCurrentTpl != TPL_APPLICATION) {
+ return EFI_UNSUPPORTED;
+ }
+
+ if (NumberOfEvents == 0) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (UserEvents == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ for(;;) {
+
+ for(Index = 0; Index < NumberOfEvents; Index++) {
+
+ Status = CoreCheckEvent (UserEvents[Index]);
+
+ //
+ // provide index of event that caused problem
+ //
+ if (Status != EFI_NOT_READY) {
+ if (UserIndex != NULL) {
+ *UserIndex = Index;
+ }
+ return Status;
+ }
+ }
+
+ //
+ // Signal the Idle event
+ //
+ CoreSignalEvent (gIdleLoopEvent);
+ }
+}
+
+
+/**
+ Closes an event and frees the event structure.
+
+ @param UserEvent Event to close
+
+ @retval EFI_INVALID_PARAMETER Parameters are not valid.
+ @retval EFI_SUCCESS The event has been closed
+
+**/
+EFI_STATUS
+EFIAPI
+CoreCloseEvent (
+ IN EFI_EVENT UserEvent
+ )
+{
+ 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 & EVT_TIMER) != 0) {
+ CoreSetTimer (Event, TimerCancel, 0);
+ }
+
+ CoreAcquireEventLock ();
+
+ //
+ // If the event is queued somewhere, remove it
+ //
+
+ if (Event->RuntimeData.Link.ForwardLink != NULL) {
+ RemoveEntryList (&Event->RuntimeData.Link);
+ }
+
+ 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
+ //
+ if ((Event->ExFlag & EVT_EXFLAG_EVENT_PROTOCOL_NOTIFICATION) != 0) {
+ CoreUnregisterProtocolNotify (Event);
+ }
+
+ //
+ // To avoid the Event to be signalled wrongly after closed,
+ // clear the Signature of Event before free pool.
+ //
+ Event->Signature = 0;
+ Status = CoreFreePool (Event);
+ ASSERT_EFI_ERROR (Status);
+
+ return Status;
+}
+
diff --git a/roms/edk2/MdeModulePkg/Core/Dxe/Event/Event.h b/roms/edk2/MdeModulePkg/Core/Dxe/Event/Event.h
new file mode 100644
index 000000000..8141c5003
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Core/Dxe/Event/Event.h
@@ -0,0 +1,91 @@
+/** @file
+ UEFI Event support functions and structure.
+
+Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.<BR>
+(C) Copyright 2015 Hewlett Packard Enterprise Development LP<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef __EVENT_H__
+#define __EVENT_H__
+
+
+#define VALID_TPL(a) ((a) <= TPL_HIGH_LEVEL)
+extern UINTN gEventPending;
+
+///
+/// Set if Event is part of an event group
+///
+#define EVT_EXFLAG_EVENT_GROUP 0x01
+///
+/// Set if Event is registered on a protocol notify
+///
+#define EVT_EXFLAG_EVENT_PROTOCOL_NOTIFICATION 0x02
+
+//
+// EFI_EVENT
+//
+
+///
+/// Timer event information
+///
+typedef struct {
+ LIST_ENTRY Link;
+ UINT64 TriggerTime;
+ UINT64 Period;
+} TIMER_EVENT_INFO;
+
+#define EVENT_SIGNATURE SIGNATURE_32('e','v','n','t')
+typedef struct {
+ UINTN Signature;
+ UINT32 Type;
+ UINT32 SignalCount;
+ ///
+ /// Entry if the event is registered to be signalled
+ ///
+ LIST_ENTRY SignalLink;
+ ///
+ /// Notification information for this event
+ ///
+ EFI_TPL NotifyTpl;
+ EFI_EVENT_NOTIFY NotifyFunction;
+ VOID *NotifyContext;
+ EFI_GUID EventGroup;
+ LIST_ENTRY NotifyLink;
+ UINT8 ExFlag;
+ ///
+ /// A list of all runtime events
+ ///
+ EFI_RUNTIME_EVENT_ENTRY RuntimeData;
+ TIMER_EVENT_INFO Timer;
+} IEVENT;
+
+//
+// Internal prototypes
+//
+
+
+/**
+ Dispatches all pending events.
+
+ @param Priority The task priority level of event notifications
+ to dispatch
+
+**/
+VOID
+CoreDispatchEventNotifies (
+ IN EFI_TPL Priority
+ );
+
+
+/**
+ Initializes timer support.
+
+**/
+VOID
+CoreInitializeTimer (
+ VOID
+ );
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Core/Dxe/Event/Timer.c b/roms/edk2/MdeModulePkg/Core/Dxe/Event/Timer.c
new file mode 100644
index 000000000..7a94712d8
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Core/Dxe/Event/Timer.c
@@ -0,0 +1,295 @@
+/** @file
+ Core Timer Services
+
+Copyright (c) 2006 - 2013, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+
+#include "DxeMain.h"
+#include "Event.h"
+
+//
+// Internal data
+//
+
+LIST_ENTRY mEfiTimerList = INITIALIZE_LIST_HEAD_VARIABLE (mEfiTimerList);
+EFI_LOCK mEfiTimerLock = EFI_INITIALIZE_LOCK_VARIABLE (TPL_HIGH_LEVEL - 1);
+EFI_EVENT mEfiCheckTimerEvent = NULL;
+
+EFI_LOCK mEfiSystemTimeLock = EFI_INITIALIZE_LOCK_VARIABLE (TPL_HIGH_LEVEL);
+UINT64 mEfiSystemTime = 0;
+
+//
+// Timer functions
+//
+/**
+ Inserts the timer event.
+
+ @param Event Points to the internal structure of timer event
+ to be installed
+
+**/
+VOID
+CoreInsertEventTimer (
+ IN IEVENT *Event
+ )
+{
+ UINT64 TriggerTime;
+ LIST_ENTRY *Link;
+ IEVENT *Event2;
+
+ ASSERT_LOCKED (&mEfiTimerLock);
+
+ //
+ // Get the timer's trigger time
+ //
+ TriggerTime = Event->Timer.TriggerTime;
+
+ //
+ // Insert the timer into the timer database in assending sorted order
+ //
+ for (Link = mEfiTimerList.ForwardLink; Link != &mEfiTimerList; Link = Link->ForwardLink) {
+ Event2 = CR (Link, IEVENT, Timer.Link, EVENT_SIGNATURE);
+
+ if (Event2->Timer.TriggerTime > TriggerTime) {
+ break;
+ }
+ }
+
+ InsertTailList (Link, &Event->Timer.Link);
+}
+
+/**
+ Returns the current system time.
+
+ @return The current system time
+
+**/
+UINT64
+CoreCurrentSystemTime (
+ VOID
+ )
+{
+ UINT64 SystemTime;
+
+ CoreAcquireLock (&mEfiSystemTimeLock);
+ SystemTime = mEfiSystemTime;
+ CoreReleaseLock (&mEfiSystemTimeLock);
+
+ return SystemTime;
+}
+
+/**
+ Checks the sorted timer list against the current system time.
+ Signals any expired event timer.
+
+ @param CheckEvent Not used
+ @param Context Not used
+
+**/
+VOID
+EFIAPI
+CoreCheckTimers (
+ IN EFI_EVENT CheckEvent,
+ IN VOID *Context
+ )
+{
+ UINT64 SystemTime;
+ IEVENT *Event;
+
+ //
+ // Check the timer database for expired timers
+ //
+ CoreAcquireLock (&mEfiTimerLock);
+ SystemTime = CoreCurrentSystemTime ();
+
+ while (!IsListEmpty (&mEfiTimerList)) {
+ Event = CR (mEfiTimerList.ForwardLink, IEVENT, Timer.Link, EVENT_SIGNATURE);
+
+ //
+ // If this timer is not expired, then we're done
+ //
+ if (Event->Timer.TriggerTime > SystemTime) {
+ break;
+ }
+
+ //
+ // Remove this timer from the timer queue
+ //
+
+ RemoveEntryList (&Event->Timer.Link);
+ Event->Timer.Link.ForwardLink = NULL;
+
+ //
+ // Signal it
+ //
+ CoreSignalEvent (Event);
+
+ //
+ // If this is a periodic timer, set it
+ //
+ if (Event->Timer.Period != 0) {
+ //
+ // Compute the timers new trigger time
+ //
+ Event->Timer.TriggerTime = Event->Timer.TriggerTime + Event->Timer.Period;
+
+ //
+ // If that's before now, then reset the timer to start from now
+ //
+ if (Event->Timer.TriggerTime <= SystemTime) {
+ Event->Timer.TriggerTime = SystemTime;
+ CoreSignalEvent (mEfiCheckTimerEvent);
+ }
+
+ //
+ // Add the timer
+ //
+ CoreInsertEventTimer (Event);
+ }
+ }
+
+ CoreReleaseLock (&mEfiTimerLock);
+}
+
+
+/**
+ Initializes timer support.
+
+**/
+VOID
+CoreInitializeTimer (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+
+ Status = CoreCreateEventInternal (
+ EVT_NOTIFY_SIGNAL,
+ TPL_HIGH_LEVEL - 1,
+ CoreCheckTimers,
+ NULL,
+ NULL,
+ &mEfiCheckTimerEvent
+ );
+ ASSERT_EFI_ERROR (Status);
+}
+
+
+/**
+ Called by the platform code to process a tick.
+
+ @param Duration The number of 100ns elapsed since the last call
+ to TimerTick
+
+**/
+VOID
+EFIAPI
+CoreTimerTick (
+ IN UINT64 Duration
+ )
+{
+ IEVENT *Event;
+
+ //
+ // Check runtiem flag in case there are ticks while exiting boot services
+ //
+ CoreAcquireLock (&mEfiSystemTimeLock);
+
+ //
+ // Update the system time
+ //
+ mEfiSystemTime += Duration;
+
+ //
+ // If the head of the list is expired, fire the timer event
+ // to process it
+ //
+ if (!IsListEmpty (&mEfiTimerList)) {
+ Event = CR (mEfiTimerList.ForwardLink, IEVENT, Timer.Link, EVENT_SIGNATURE);
+
+ if (Event->Timer.TriggerTime <= mEfiSystemTime) {
+ CoreSignalEvent (mEfiCheckTimerEvent);
+ }
+ }
+
+ CoreReleaseLock (&mEfiSystemTimeLock);
+}
+
+
+
+/**
+ Sets the type of timer and the trigger time for a timer event.
+
+ @param UserEvent The timer event that is to be signaled at the
+ specified time
+ @param Type The type of time that is specified in
+ TriggerTime
+ @param TriggerTime The number of 100ns units until the timer
+ expires
+
+ @retval EFI_SUCCESS The event has been set to be signaled at the
+ requested time
+ @retval EFI_INVALID_PARAMETER Event or Type is not valid
+
+**/
+EFI_STATUS
+EFIAPI
+CoreSetTimer (
+ IN EFI_EVENT UserEvent,
+ IN EFI_TIMER_DELAY Type,
+ IN UINT64 TriggerTime
+ )
+{
+ IEVENT *Event;
+
+ Event = UserEvent;
+
+ if (Event == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (Event->Signature != EVENT_SIGNATURE) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if ((UINT32)Type > TimerRelative || (Event->Type & EVT_TIMER) == 0) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ CoreAcquireLock (&mEfiTimerLock);
+
+ //
+ // If the timer is queued to the timer database, remove it
+ //
+ if (Event->Timer.Link.ForwardLink != NULL) {
+ RemoveEntryList (&Event->Timer.Link);
+ Event->Timer.Link.ForwardLink = NULL;
+ }
+
+ Event->Timer.TriggerTime = 0;
+ Event->Timer.Period = 0;
+
+ if (Type != TimerCancel) {
+
+ if (Type == TimerPeriodic) {
+ if (TriggerTime == 0) {
+ gTimer->GetTimerPeriod (gTimer, &TriggerTime);
+ }
+ Event->Timer.Period = TriggerTime;
+ }
+
+ Event->Timer.TriggerTime = CoreCurrentSystemTime () + TriggerTime;
+ CoreInsertEventTimer (Event);
+
+ if (TriggerTime == 0) {
+ CoreSignalEvent (mEfiCheckTimerEvent);
+ }
+ }
+
+ CoreReleaseLock (&mEfiTimerLock);
+
+ return EFI_SUCCESS;
+}
diff --git a/roms/edk2/MdeModulePkg/Core/Dxe/Event/Tpl.c b/roms/edk2/MdeModulePkg/Core/Dxe/Event/Tpl.c
new file mode 100644
index 000000000..5ff8eb55b
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Core/Dxe/Event/Tpl.c
@@ -0,0 +1,148 @@
+/** @file
+ Task priority (TPL) functions.
+
+Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "DxeMain.h"
+#include "Event.h"
+
+/**
+ Set Interrupt State.
+
+ @param Enable The state of enable or disable interrupt
+
+**/
+VOID
+CoreSetInterruptState (
+ IN BOOLEAN Enable
+ )
+{
+ EFI_STATUS Status;
+ BOOLEAN InSmm;
+
+ if (gCpu == NULL) {
+ return;
+ }
+ if (!Enable) {
+ gCpu->DisableInterrupt (gCpu);
+ return;
+ }
+ if (gSmmBase2 == NULL) {
+ gCpu->EnableInterrupt (gCpu);
+ return;
+ }
+ Status = gSmmBase2->InSmm (gSmmBase2, &InSmm);
+ if (!EFI_ERROR (Status) && !InSmm) {
+ gCpu->EnableInterrupt(gCpu);
+ }
+}
+
+
+/**
+ Raise the task priority level to the new level.
+ High level is implemented by disabling processor interrupts.
+
+ @param NewTpl New task priority level
+
+ @return The previous task priority level
+
+**/
+EFI_TPL
+EFIAPI
+CoreRaiseTpl (
+ IN EFI_TPL NewTpl
+ )
+{
+ EFI_TPL OldTpl;
+
+ OldTpl = gEfiCurrentTpl;
+ if (OldTpl > NewTpl) {
+ DEBUG ((EFI_D_ERROR, "FATAL ERROR - RaiseTpl with OldTpl(0x%x) > NewTpl(0x%x)\n", OldTpl, NewTpl));
+ ASSERT (FALSE);
+ }
+ ASSERT (VALID_TPL (NewTpl));
+
+ //
+ // If raising to high level, disable interrupts
+ //
+ if (NewTpl >= TPL_HIGH_LEVEL && OldTpl < TPL_HIGH_LEVEL) {
+ CoreSetInterruptState (FALSE);
+ }
+
+ //
+ // Set the new value
+ //
+ gEfiCurrentTpl = NewTpl;
+
+ return OldTpl;
+}
+
+
+
+
+/**
+ Lowers the task priority to the previous value. If the new
+ priority unmasks events at a higher priority, they are dispatched.
+
+ @param NewTpl New, lower, task priority
+
+**/
+VOID
+EFIAPI
+CoreRestoreTpl (
+ IN EFI_TPL NewTpl
+ )
+{
+ EFI_TPL OldTpl;
+ EFI_TPL PendingTpl;
+
+ OldTpl = gEfiCurrentTpl;
+ if (NewTpl > OldTpl) {
+ DEBUG ((EFI_D_ERROR, "FATAL ERROR - RestoreTpl with NewTpl(0x%x) > OldTpl(0x%x)\n", NewTpl, OldTpl));
+ ASSERT (FALSE);
+ }
+ ASSERT (VALID_TPL (NewTpl));
+
+ //
+ // If lowering below HIGH_LEVEL, make sure
+ // interrupts are enabled
+ //
+
+ if (OldTpl >= TPL_HIGH_LEVEL && NewTpl < TPL_HIGH_LEVEL) {
+ gEfiCurrentTpl = TPL_HIGH_LEVEL;
+ }
+
+ //
+ // Dispatch any pending events
+ //
+ while (gEventPending != 0) {
+ PendingTpl = (UINTN) HighBitSet64 (gEventPending);
+ if (PendingTpl <= NewTpl) {
+ break;
+ }
+
+ gEfiCurrentTpl = PendingTpl;
+ if (gEfiCurrentTpl < TPL_HIGH_LEVEL) {
+ CoreSetInterruptState (TRUE);
+ }
+ CoreDispatchEventNotifies (gEfiCurrentTpl);
+ }
+
+ //
+ // Set the new value
+ //
+
+ gEfiCurrentTpl = NewTpl;
+
+ //
+ // If lowering below HIGH_LEVEL, make sure
+ // interrupts are enabled
+ //
+ if (gEfiCurrentTpl < TPL_HIGH_LEVEL) {
+ CoreSetInterruptState (TRUE);
+ }
+
+}