aboutsummaryrefslogtreecommitdiffstats
path: root/roms/edk2/MdeModulePkg/Core/Dxe
diff options
context:
space:
mode:
Diffstat (limited to 'roms/edk2/MdeModulePkg/Core/Dxe')
-rw-r--r--roms/edk2/MdeModulePkg/Core/Dxe/Dispatcher/Dependency.c436
-rw-r--r--roms/edk2/MdeModulePkg/Core/Dxe/Dispatcher/Dispatcher.c1488
-rw-r--r--roms/edk2/MdeModulePkg/Core/Dxe/DxeCore.uni16
-rw-r--r--roms/edk2/MdeModulePkg/Core/Dxe/DxeCoreExtra.uni14
-rw-r--r--roms/edk2/MdeModulePkg/Core/Dxe/DxeMain.h2940
-rw-r--r--roms/edk2/MdeModulePkg/Core/Dxe/DxeMain.inf201
-rw-r--r--roms/edk2/MdeModulePkg/Core/Dxe/DxeMain/DxeMain.c938
-rw-r--r--roms/edk2/MdeModulePkg/Core/Dxe/DxeMain/DxeProtocolNotify.c279
-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
-rw-r--r--roms/edk2/MdeModulePkg/Core/Dxe/FwVol/Ffs.c227
-rw-r--r--roms/edk2/MdeModulePkg/Core/Dxe/FwVol/FwVol.c729
-rw-r--r--roms/edk2/MdeModulePkg/Core/Dxe/FwVol/FwVolAttrib.c129
-rw-r--r--roms/edk2/MdeModulePkg/Core/Dxe/FwVol/FwVolDriver.h402
-rw-r--r--roms/edk2/MdeModulePkg/Core/Dxe/FwVol/FwVolRead.c536
-rw-r--r--roms/edk2/MdeModulePkg/Core/Dxe/FwVol/FwVolWrite.c46
-rw-r--r--roms/edk2/MdeModulePkg/Core/Dxe/FwVolBlock/FwVolBlock.c719
-rw-r--r--roms/edk2/MdeModulePkg/Core/Dxe/FwVolBlock/FwVolBlock.h238
-rw-r--r--roms/edk2/MdeModulePkg/Core/Dxe/Gcd/Gcd.c2675
-rw-r--r--roms/edk2/MdeModulePkg/Core/Dxe/Gcd/Gcd.h40
-rw-r--r--roms/edk2/MdeModulePkg/Core/Dxe/Hand/DriverSupport.c958
-rw-r--r--roms/edk2/MdeModulePkg/Core/Dxe/Hand/Handle.c1576
-rw-r--r--roms/edk2/MdeModulePkg/Core/Dxe/Hand/Handle.h264
-rw-r--r--roms/edk2/MdeModulePkg/Core/Dxe/Hand/Locate.c702
-rw-r--r--roms/edk2/MdeModulePkg/Core/Dxe/Hand/Notify.c285
-rw-r--r--roms/edk2/MdeModulePkg/Core/Dxe/Image/Image.c1909
-rw-r--r--roms/edk2/MdeModulePkg/Core/Dxe/Image/Image.h24
-rw-r--r--roms/edk2/MdeModulePkg/Core/Dxe/Library/Library.c100
-rw-r--r--roms/edk2/MdeModulePkg/Core/Dxe/Mem/HeapGuard.c1746
-rw-r--r--roms/edk2/MdeModulePkg/Core/Dxe/Mem/HeapGuard.h467
-rw-r--r--roms/edk2/MdeModulePkg/Core/Dxe/Mem/Imem.h182
-rw-r--r--roms/edk2/MdeModulePkg/Core/Dxe/Mem/MemData.c20
-rw-r--r--roms/edk2/MdeModulePkg/Core/Dxe/Mem/MemoryProfileRecord.c1759
-rw-r--r--roms/edk2/MdeModulePkg/Core/Dxe/Mem/Page.c2105
-rw-r--r--roms/edk2/MdeModulePkg/Core/Dxe/Mem/Pool.c857
-rw-r--r--roms/edk2/MdeModulePkg/Core/Dxe/Misc/DebugImageInfo.c282
-rwxr-xr-xroms/edk2/MdeModulePkg/Core/Dxe/Misc/InstallConfigurationTable.c181
-rw-r--r--roms/edk2/MdeModulePkg/Core/Dxe/Misc/MemoryAttributesTable.c1514
-rw-r--r--roms/edk2/MdeModulePkg/Core/Dxe/Misc/MemoryProtection.c1284
-rw-r--r--roms/edk2/MdeModulePkg/Core/Dxe/Misc/SetWatchdogTimer.c66
-rw-r--r--roms/edk2/MdeModulePkg/Core/Dxe/Misc/Stall.c107
-rw-r--r--roms/edk2/MdeModulePkg/Core/Dxe/SectionExtraction/CoreSectionExtraction.c1601
44 files changed, 31360 insertions, 0 deletions
diff --git a/roms/edk2/MdeModulePkg/Core/Dxe/Dispatcher/Dependency.c b/roms/edk2/MdeModulePkg/Core/Dxe/Dispatcher/Dependency.c
new file mode 100644
index 000000000..89e540ba7
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Core/Dxe/Dispatcher/Dependency.c
@@ -0,0 +1,436 @@
+/** @file
+ DXE Dispatcher Dependency Evaluator.
+
+ This routine evaluates a dependency expression (DEPENDENCY_EXPRESSION) to determine
+ if a driver can be scheduled for execution. The criteria for
+ schedulability is that the dependency expression is satisfied.
+
+Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "DxeMain.h"
+
+//
+// Global stack used to evaluate dependency expressions
+//
+BOOLEAN *mDepexEvaluationStack = NULL;
+BOOLEAN *mDepexEvaluationStackEnd = NULL;
+BOOLEAN *mDepexEvaluationStackPointer = NULL;
+
+//
+// Worker functions
+//
+
+
+/**
+ Grow size of the Depex stack
+
+ @retval EFI_SUCCESS Stack successfully growed.
+ @retval EFI_OUT_OF_RESOURCES There is not enough system memory to grow the stack.
+
+**/
+EFI_STATUS
+GrowDepexStack (
+ VOID
+ )
+{
+ BOOLEAN *NewStack;
+ UINTN Size;
+
+ Size = DEPEX_STACK_SIZE_INCREMENT;
+ if (mDepexEvaluationStack != NULL) {
+ Size = Size + (mDepexEvaluationStackEnd - mDepexEvaluationStack);
+ }
+
+ NewStack = AllocatePool (Size * sizeof (BOOLEAN));
+ if (NewStack == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ if (mDepexEvaluationStack != NULL) {
+ //
+ // Copy to Old Stack to the New Stack
+ //
+ CopyMem (
+ NewStack,
+ mDepexEvaluationStack,
+ (mDepexEvaluationStackEnd - mDepexEvaluationStack) * sizeof (BOOLEAN)
+ );
+
+ //
+ // Free The Old Stack
+ //
+ FreePool (mDepexEvaluationStack);
+ }
+
+ //
+ // Make the Stack pointer point to the old data in the new stack
+ //
+ mDepexEvaluationStackPointer = NewStack + (mDepexEvaluationStackPointer - mDepexEvaluationStack);
+ mDepexEvaluationStack = NewStack;
+ mDepexEvaluationStackEnd = NewStack + Size;
+
+ return EFI_SUCCESS;
+}
+
+
+
+/**
+ Push an element onto the Boolean Stack.
+
+ @param Value BOOLEAN to push.
+
+ @retval EFI_SUCCESS The value was pushed onto the stack.
+ @retval EFI_OUT_OF_RESOURCES There is not enough system memory to grow the stack.
+
+**/
+EFI_STATUS
+PushBool (
+ IN BOOLEAN Value
+ )
+{
+ EFI_STATUS Status;
+
+ //
+ // Check for a stack overflow condition
+ //
+ if (mDepexEvaluationStackPointer == mDepexEvaluationStackEnd) {
+ //
+ // Grow the stack
+ //
+ Status = GrowDepexStack ();
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+
+ //
+ // Push the item onto the stack
+ //
+ *mDepexEvaluationStackPointer = Value;
+ mDepexEvaluationStackPointer++;
+
+ return EFI_SUCCESS;
+}
+
+
+
+/**
+ Pop an element from the Boolean stack.
+
+ @param Value BOOLEAN to pop.
+
+ @retval EFI_SUCCESS The value was popped onto the stack.
+ @retval EFI_ACCESS_DENIED The pop operation underflowed the stack.
+
+**/
+EFI_STATUS
+PopBool (
+ OUT BOOLEAN *Value
+ )
+{
+ //
+ // Check for a stack underflow condition
+ //
+ if (mDepexEvaluationStackPointer == mDepexEvaluationStack) {
+ return EFI_ACCESS_DENIED;
+ }
+
+ //
+ // Pop the item off the stack
+ //
+ mDepexEvaluationStackPointer--;
+ *Value = *mDepexEvaluationStackPointer;
+ return EFI_SUCCESS;
+}
+
+
+
+/**
+ Preprocess dependency expression and update DriverEntry to reflect the
+ state of Before, After, and SOR dependencies. If DriverEntry->Before
+ or DriverEntry->After is set it will never be cleared. If SOR is set
+ it will be cleared by CoreSchedule(), and then the driver can be
+ dispatched.
+
+ @param DriverEntry DriverEntry element to update .
+
+ @retval EFI_SUCCESS It always works.
+
+**/
+EFI_STATUS
+CorePreProcessDepex (
+ IN EFI_CORE_DRIVER_ENTRY *DriverEntry
+ )
+{
+ UINT8 *Iterator;
+
+ Iterator = DriverEntry->Depex;
+ if (*Iterator == EFI_DEP_SOR) {
+ DriverEntry->Unrequested = TRUE;
+ } else {
+ DriverEntry->Dependent = TRUE;
+ }
+
+ if (*Iterator == EFI_DEP_BEFORE) {
+ DriverEntry->Before = TRUE;
+ } else if (*Iterator == EFI_DEP_AFTER) {
+ DriverEntry->After = TRUE;
+ }
+
+ if (DriverEntry->Before || DriverEntry->After) {
+ CopyMem (&DriverEntry->BeforeAfterGuid, Iterator + 1, sizeof (EFI_GUID));
+ }
+
+ return EFI_SUCCESS;
+}
+
+
+
+/**
+ This is the POSTFIX version of the dependency evaluator. This code does
+ not need to handle Before or After, as it is not valid to call this
+ routine in this case. The SOR is just ignored and is a nop in the grammer.
+ POSTFIX means all the math is done on top of the stack.
+
+ @param DriverEntry DriverEntry element to update.
+
+ @retval TRUE If driver is ready to run.
+ @retval FALSE If driver is not ready to run or some fatal error
+ was found.
+
+**/
+BOOLEAN
+CoreIsSchedulable (
+ IN EFI_CORE_DRIVER_ENTRY *DriverEntry
+ )
+{
+ EFI_STATUS Status;
+ UINT8 *Iterator;
+ BOOLEAN Operator;
+ BOOLEAN Operator2;
+ EFI_GUID DriverGuid;
+ VOID *Interface;
+
+ Operator = FALSE;
+ Operator2 = FALSE;
+
+ if (DriverEntry->After || DriverEntry->Before) {
+ //
+ // If Before or After Depex skip as CoreInsertOnScheduledQueueWhileProcessingBeforeAndAfter ()
+ // processes them.
+ //
+ return FALSE;
+ }
+
+ DEBUG ((DEBUG_DISPATCH, "Evaluate DXE DEPEX for FFS(%g)\n", &DriverEntry->FileName));
+
+ if (DriverEntry->Depex == NULL) {
+ //
+ // A NULL Depex means treat the driver like an UEFI 2.0 thing.
+ //
+ Status = CoreAllEfiServicesAvailable ();
+ DEBUG ((DEBUG_DISPATCH, " All UEFI Services Available = "));
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_DISPATCH, "FALSE\n RESULT = FALSE\n"));
+ return FALSE;
+ }
+ DEBUG ((DEBUG_DISPATCH, "TRUE\n RESULT = TRUE\n"));
+ return TRUE;
+ }
+
+ //
+ // Clean out memory leaks in Depex Boolean stack. Leaks are only caused by
+ // incorrectly formed DEPEX expressions
+ //
+ mDepexEvaluationStackPointer = mDepexEvaluationStack;
+
+
+ Iterator = DriverEntry->Depex;
+
+ while (TRUE) {
+ //
+ // Check to see if we are attempting to fetch dependency expression instructions
+ // past the end of the dependency expression.
+ //
+ if (((UINTN)Iterator - (UINTN)DriverEntry->Depex) >= DriverEntry->DepexSize) {
+ DEBUG ((DEBUG_DISPATCH, " RESULT = FALSE (Attempt to fetch past end of depex)\n"));
+ return FALSE;
+ }
+
+ //
+ // Look at the opcode of the dependency expression instruction.
+ //
+ switch (*Iterator) {
+ case EFI_DEP_BEFORE:
+ case EFI_DEP_AFTER:
+ //
+ // For a well-formed Dependency Expression, the code should never get here.
+ // The BEFORE and AFTER are processed prior to this routine's invocation.
+ // If the code flow arrives at this point, there was a BEFORE or AFTER
+ // that were not the first opcodes.
+ //
+ DEBUG ((DEBUG_DISPATCH, " RESULT = FALSE (Unexpected BEFORE or AFTER opcode)\n"));
+ ASSERT (FALSE);
+ case EFI_DEP_SOR:
+ //
+ // These opcodes can only appear once as the first opcode. If it is found
+ // at any other location, then the dependency expression evaluates to FALSE
+ //
+ if (Iterator != DriverEntry->Depex) {
+ DEBUG ((DEBUG_DISPATCH, " SOR\n"));
+ DEBUG ((DEBUG_DISPATCH, " RESULT = FALSE (Unexpected SOR opcode)\n"));
+ return FALSE;
+ }
+ DEBUG ((DEBUG_DISPATCH, " SOR = Requested\n"));
+ //
+ // Otherwise, it is the first opcode and should be treated as a NOP.
+ //
+ break;
+
+ case EFI_DEP_PUSH:
+ //
+ // Push operator is followed by a GUID. Test to see if the GUID protocol
+ // is installed and push the boolean result on the stack.
+ //
+ CopyMem (&DriverGuid, Iterator + 1, sizeof (EFI_GUID));
+
+ Status = CoreLocateProtocol (&DriverGuid, NULL, &Interface);
+
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_DISPATCH, " PUSH GUID(%g) = FALSE\n", &DriverGuid));
+ Status = PushBool (FALSE);
+ } else {
+ DEBUG ((DEBUG_DISPATCH, " PUSH GUID(%g) = TRUE\n", &DriverGuid));
+ *Iterator = EFI_DEP_REPLACE_TRUE;
+ Status = PushBool (TRUE);
+ }
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_DISPATCH, " RESULT = FALSE (Unexpected error)\n"));
+ return FALSE;
+ }
+
+ Iterator += sizeof (EFI_GUID);
+ break;
+
+ case EFI_DEP_AND:
+ DEBUG ((DEBUG_DISPATCH, " AND\n"));
+ Status = PopBool (&Operator);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_DISPATCH, " RESULT = FALSE (Unexpected error)\n"));
+ return FALSE;
+ }
+
+ Status = PopBool (&Operator2);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_DISPATCH, " RESULT = FALSE (Unexpected error)\n"));
+ return FALSE;
+ }
+
+ Status = PushBool ((BOOLEAN)(Operator && Operator2));
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_DISPATCH, " RESULT = FALSE (Unexpected error)\n"));
+ return FALSE;
+ }
+ break;
+
+ case EFI_DEP_OR:
+ DEBUG ((DEBUG_DISPATCH, " OR\n"));
+ Status = PopBool (&Operator);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_DISPATCH, " RESULT = FALSE (Unexpected error)\n"));
+ return FALSE;
+ }
+
+ Status = PopBool (&Operator2);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_DISPATCH, " RESULT = FALSE (Unexpected error)\n"));
+ return FALSE;
+ }
+
+ Status = PushBool ((BOOLEAN)(Operator || Operator2));
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_DISPATCH, " RESULT = FALSE (Unexpected error)\n"));
+ return FALSE;
+ }
+ break;
+
+ case EFI_DEP_NOT:
+ DEBUG ((DEBUG_DISPATCH, " NOT\n"));
+ Status = PopBool (&Operator);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_DISPATCH, " RESULT = FALSE (Unexpected error)\n"));
+ return FALSE;
+ }
+
+ Status = PushBool ((BOOLEAN)(!Operator));
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_DISPATCH, " RESULT = FALSE (Unexpected error)\n"));
+ return FALSE;
+ }
+ break;
+
+ case EFI_DEP_TRUE:
+ DEBUG ((DEBUG_DISPATCH, " TRUE\n"));
+ Status = PushBool (TRUE);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_DISPATCH, " RESULT = FALSE (Unexpected error)\n"));
+ return FALSE;
+ }
+ break;
+
+ case EFI_DEP_FALSE:
+ DEBUG ((DEBUG_DISPATCH, " FALSE\n"));
+ Status = PushBool (FALSE);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_DISPATCH, " RESULT = FALSE (Unexpected error)\n"));
+ return FALSE;
+ }
+ break;
+
+ case EFI_DEP_END:
+ DEBUG ((DEBUG_DISPATCH, " END\n"));
+ Status = PopBool (&Operator);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_DISPATCH, " RESULT = FALSE (Unexpected error)\n"));
+ return FALSE;
+ }
+ DEBUG ((DEBUG_DISPATCH, " RESULT = %a\n", Operator ? "TRUE" : "FALSE"));
+ return Operator;
+
+ case EFI_DEP_REPLACE_TRUE:
+ CopyMem (&DriverGuid, Iterator + 1, sizeof (EFI_GUID));
+ DEBUG ((DEBUG_DISPATCH, " PUSH GUID(%g) = TRUE\n", &DriverGuid));
+
+ Status = PushBool (TRUE);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_DISPATCH, " RESULT = FALSE (Unexpected error)\n"));
+ return FALSE;
+ }
+
+ Iterator += sizeof (EFI_GUID);
+ break;
+
+ default:
+ DEBUG ((DEBUG_DISPATCH, " RESULT = FALSE (Unknown opcode)\n"));
+ goto Done;
+ }
+
+ //
+ // Skip over the Dependency Op Code we just processed in the switch.
+ // The math is done out of order, but it should not matter. That is
+ // we may add in the sizeof (EFI_GUID) before we account for the OP Code.
+ // This is not an issue, since we just need the correct end result. You
+ // need to be careful using Iterator in the loop as it's intermediate value
+ // may be strange.
+ //
+ Iterator++;
+ }
+
+Done:
+ return FALSE;
+}
+
+
diff --git a/roms/edk2/MdeModulePkg/Core/Dxe/Dispatcher/Dispatcher.c b/roms/edk2/MdeModulePkg/Core/Dxe/Dispatcher/Dispatcher.c
new file mode 100644
index 000000000..fed60c488
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Core/Dxe/Dispatcher/Dispatcher.c
@@ -0,0 +1,1488 @@
+/** @file
+ DXE Dispatcher.
+
+ Step #1 - When a FV protocol is added to the system every driver in the FV
+ is added to the mDiscoveredList. The SOR, Before, and After Depex are
+ pre-processed as drivers are added to the mDiscoveredList. If an Apriori
+ file exists in the FV those drivers are addeded to the
+ mScheduledQueue. The mFvHandleList is used to make sure a
+ FV is only processed once.
+
+ Step #2 - Dispatch. Remove driver from the mScheduledQueue and load and
+ start it. After mScheduledQueue is drained check the
+ mDiscoveredList to see if any item has a Depex that is ready to
+ be placed on the mScheduledQueue.
+
+ Step #3 - Adding to the mScheduledQueue requires that you process Before
+ and After dependencies. This is done recursively as the call to add
+ to the mScheduledQueue checks for Before and recursively adds
+ all Befores. It then addes the item that was passed in and then
+ processess the After dependecies by recursively calling the routine.
+
+ Dispatcher Rules:
+ The rules for the dispatcher are in chapter 10 of the DXE CIS. Figure 10-3
+ is the state diagram for the DXE dispatcher
+
+ Depex - Dependency Expresion.
+ SOR - Schedule On Request - Don't schedule if this bit is set.
+
+Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "DxeMain.h"
+
+//
+// The Driver List contains one copy of every driver that has been discovered.
+// Items are never removed from the driver list. List of EFI_CORE_DRIVER_ENTRY
+//
+LIST_ENTRY mDiscoveredList = INITIALIZE_LIST_HEAD_VARIABLE (mDiscoveredList);
+
+//
+// Queue of drivers that are ready to dispatch. This queue is a subset of the
+// mDiscoveredList.list of EFI_CORE_DRIVER_ENTRY.
+//
+LIST_ENTRY mScheduledQueue = INITIALIZE_LIST_HEAD_VARIABLE (mScheduledQueue);
+
+//
+// List of handles who's Fv's have been parsed and added to the mFwDriverList.
+//
+LIST_ENTRY mFvHandleList = INITIALIZE_LIST_HEAD_VARIABLE (mFvHandleList); // list of KNOWN_HANDLE
+
+//
+// Lock for mDiscoveredList, mScheduledQueue, gDispatcherRunning.
+//
+EFI_LOCK mDispatcherLock = EFI_INITIALIZE_LOCK_VARIABLE (TPL_HIGH_LEVEL);
+
+
+//
+// Flag for the DXE Dispacher. TRUE if dispatcher is execuing.
+//
+BOOLEAN gDispatcherRunning = FALSE;
+
+//
+// Module globals to manage the FwVol registration notification event
+//
+EFI_EVENT mFwVolEvent;
+VOID *mFwVolEventRegistration;
+
+//
+// List of file types supported by dispatcher
+//
+EFI_FV_FILETYPE mDxeFileTypes[] = {
+ EFI_FV_FILETYPE_DRIVER,
+ EFI_FV_FILETYPE_COMBINED_SMM_DXE,
+ EFI_FV_FILETYPE_COMBINED_PEIM_DRIVER,
+ EFI_FV_FILETYPE_DXE_CORE,
+ EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE
+};
+
+typedef struct {
+ MEDIA_FW_VOL_FILEPATH_DEVICE_PATH File;
+ EFI_DEVICE_PATH_PROTOCOL End;
+} FV_FILEPATH_DEVICE_PATH;
+
+FV_FILEPATH_DEVICE_PATH mFvDevicePath;
+
+//
+// Function Prototypes
+//
+/**
+ Insert InsertedDriverEntry onto the mScheduledQueue. To do this you
+ must add any driver with a before dependency on InsertedDriverEntry first.
+ You do this by recursively calling this routine. After all the Befores are
+ processed you can add InsertedDriverEntry to the mScheduledQueue.
+ Then you can add any driver with an After dependency on InsertedDriverEntry
+ by recursively calling this routine.
+
+ @param InsertedDriverEntry The driver to insert on the ScheduledLink Queue
+
+**/
+VOID
+CoreInsertOnScheduledQueueWhileProcessingBeforeAndAfter (
+ IN EFI_CORE_DRIVER_ENTRY *InsertedDriverEntry
+ );
+
+/**
+ Event notification that is fired every time a FV dispatch protocol is added.
+ More than one protocol may have been added when this event is fired, so you
+ must loop on CoreLocateHandle () to see how many protocols were added and
+ do the following to each FV:
+ If the Fv has already been processed, skip it. If the Fv has not been
+ processed then mark it as being processed, as we are about to process it.
+ Read the Fv and add any driver in the Fv to the mDiscoveredList.The
+ mDiscoveredList is never free'ed and contains variables that define
+ the other states the DXE driver transitions to..
+ While you are at it read the A Priori file into memory.
+ Place drivers in the A Priori list onto the mScheduledQueue.
+
+ @param Event The Event that is being processed, not used.
+ @param Context Event Context, not used.
+
+**/
+VOID
+EFIAPI
+CoreFwVolEventProtocolNotify (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ );
+
+/**
+ Convert FvHandle and DriverName into an EFI device path
+
+ @param Fv Fv protocol, needed to read Depex info out of
+ FLASH.
+ @param FvHandle Handle for Fv, needed in the
+ EFI_CORE_DRIVER_ENTRY so that the PE image can be
+ read out of the FV at a later time.
+ @param DriverName Name of driver to add to mDiscoveredList.
+
+ @return Pointer to device path constructed from FvHandle and DriverName
+
+**/
+EFI_DEVICE_PATH_PROTOCOL *
+CoreFvToDevicePath (
+ IN EFI_FIRMWARE_VOLUME2_PROTOCOL *Fv,
+ IN EFI_HANDLE FvHandle,
+ IN EFI_GUID *DriverName
+ );
+
+/**
+ Add an entry to the mDiscoveredList. Allocate memory to store the DriverEntry,
+ and initilize any state variables. Read the Depex from the FV and store it
+ in DriverEntry. Pre-process the Depex to set the SOR, Before and After state.
+ The Discovered list is never free'ed and contains booleans that represent the
+ other possible DXE driver states.
+
+ @param Fv Fv protocol, needed to read Depex info out of
+ FLASH.
+ @param FvHandle Handle for Fv, needed in the
+ EFI_CORE_DRIVER_ENTRY so that the PE image can be
+ read out of the FV at a later time.
+ @param DriverName Name of driver to add to mDiscoveredList.
+ @param Type Fv File Type of file to add to mDiscoveredList.
+
+ @retval EFI_SUCCESS If driver was added to the mDiscoveredList.
+ @retval EFI_ALREADY_STARTED The driver has already been started. Only one
+ DriverName may be active in the system at any one
+ time.
+
+**/
+EFI_STATUS
+CoreAddToDriverList (
+ IN EFI_FIRMWARE_VOLUME2_PROTOCOL *Fv,
+ IN EFI_HANDLE FvHandle,
+ IN EFI_GUID *DriverName,
+ IN EFI_FV_FILETYPE Type
+ );
+
+/**
+ Get Fv image(s) from the FV through file name, and produce FVB protocol for every Fv image(s).
+
+ @param Fv The FIRMWARE_VOLUME protocol installed on the FV.
+ @param FvHandle The handle which FVB protocol installed on.
+ @param FileName The file name guid specified.
+
+ @retval EFI_OUT_OF_RESOURCES No enough memory or other resource.
+ @retval EFI_SUCCESS Function successfully returned.
+
+**/
+EFI_STATUS
+CoreProcessFvImageFile (
+ IN EFI_FIRMWARE_VOLUME2_PROTOCOL *Fv,
+ IN EFI_HANDLE FvHandle,
+ IN EFI_GUID *FileName
+ );
+
+
+/**
+ Enter critical section by gaining lock on mDispatcherLock.
+
+**/
+VOID
+CoreAcquireDispatcherLock (
+ VOID
+ )
+{
+ CoreAcquireLock (&mDispatcherLock);
+}
+
+
+/**
+ Exit critical section by releasing lock on mDispatcherLock.
+
+**/
+VOID
+CoreReleaseDispatcherLock (
+ VOID
+ )
+{
+ CoreReleaseLock (&mDispatcherLock);
+}
+
+
+/**
+ Read Depex and pre-process the Depex for Before and After. If Section Extraction
+ protocol returns an error via ReadSection defer the reading of the Depex.
+
+ @param DriverEntry Driver to work on.
+
+ @retval EFI_SUCCESS Depex read and preprossesed
+ @retval EFI_PROTOCOL_ERROR The section extraction protocol returned an error
+ and Depex reading needs to be retried.
+ @retval Error DEPEX not found.
+
+**/
+EFI_STATUS
+CoreGetDepexSectionAndPreProccess (
+ IN EFI_CORE_DRIVER_ENTRY *DriverEntry
+ )
+{
+ EFI_STATUS Status;
+ EFI_SECTION_TYPE SectionType;
+ UINT32 AuthenticationStatus;
+ EFI_FIRMWARE_VOLUME2_PROTOCOL *Fv;
+
+
+ Fv = DriverEntry->Fv;
+
+ //
+ // Grab Depex info, it will never be free'ed.
+ //
+ SectionType = EFI_SECTION_DXE_DEPEX;
+ Status = Fv->ReadSection (
+ DriverEntry->Fv,
+ &DriverEntry->FileName,
+ SectionType,
+ 0,
+ &DriverEntry->Depex,
+ (UINTN *)&DriverEntry->DepexSize,
+ &AuthenticationStatus
+ );
+ if (EFI_ERROR (Status)) {
+ if (Status == EFI_PROTOCOL_ERROR) {
+ //
+ // The section extraction protocol failed so set protocol error flag
+ //
+ DriverEntry->DepexProtocolError = TRUE;
+ } else {
+ //
+ // If no Depex assume UEFI 2.0 driver model
+ //
+ DriverEntry->Depex = NULL;
+ DriverEntry->Dependent = TRUE;
+ DriverEntry->DepexProtocolError = FALSE;
+ }
+ } else {
+ //
+ // Set Before, After, and Unrequested state information based on Depex
+ // Driver will be put in Dependent or Unrequested state
+ //
+ CorePreProcessDepex (DriverEntry);
+ DriverEntry->DepexProtocolError = FALSE;
+ }
+
+ return Status;
+}
+
+
+/**
+ Check every driver and locate a matching one. If the driver is found, the Unrequested
+ state flag is cleared.
+
+ @param FirmwareVolumeHandle The handle of the Firmware Volume that contains
+ the firmware file specified by DriverName.
+ @param DriverName The Driver name to put in the Dependent state.
+
+ @retval EFI_SUCCESS The DriverName was found and it's SOR bit was
+ cleared
+ @retval EFI_NOT_FOUND The DriverName does not exist or it's SOR bit was
+ not set.
+
+**/
+EFI_STATUS
+EFIAPI
+CoreSchedule (
+ IN EFI_HANDLE FirmwareVolumeHandle,
+ IN EFI_GUID *DriverName
+ )
+{
+ LIST_ENTRY *Link;
+ EFI_CORE_DRIVER_ENTRY *DriverEntry;
+
+ //
+ // Check every driver
+ //
+ for (Link = mDiscoveredList.ForwardLink; Link != &mDiscoveredList; Link = Link->ForwardLink) {
+ DriverEntry = CR(Link, EFI_CORE_DRIVER_ENTRY, Link, EFI_CORE_DRIVER_ENTRY_SIGNATURE);
+ if (DriverEntry->FvHandle == FirmwareVolumeHandle &&
+ DriverEntry->Unrequested &&
+ CompareGuid (DriverName, &DriverEntry->FileName)) {
+ //
+ // Move the driver from the Unrequested to the Dependent state
+ //
+ CoreAcquireDispatcherLock ();
+ DriverEntry->Unrequested = FALSE;
+ DriverEntry->Dependent = TRUE;
+ CoreReleaseDispatcherLock ();
+
+ DEBUG ((DEBUG_DISPATCH, "Schedule FFS(%g) - EFI_SUCCESS\n", DriverName));
+
+ return EFI_SUCCESS;
+ }
+ }
+
+ DEBUG ((DEBUG_DISPATCH, "Schedule FFS(%g) - EFI_NOT_FOUND\n", DriverName));
+
+ return EFI_NOT_FOUND;
+}
+
+
+
+/**
+ Convert a driver from the Untrused back to the Scheduled state.
+
+ @param FirmwareVolumeHandle The handle of the Firmware Volume that contains
+ the firmware file specified by DriverName.
+ @param DriverName The Driver name to put in the Scheduled state
+
+ @retval EFI_SUCCESS The file was found in the untrusted state, and it
+ was promoted to the trusted state.
+ @retval EFI_NOT_FOUND The file was not found in the untrusted state.
+
+**/
+EFI_STATUS
+EFIAPI
+CoreTrust (
+ IN EFI_HANDLE FirmwareVolumeHandle,
+ IN EFI_GUID *DriverName
+ )
+{
+ LIST_ENTRY *Link;
+ EFI_CORE_DRIVER_ENTRY *DriverEntry;
+
+ //
+ // Check every driver
+ //
+ for (Link = mDiscoveredList.ForwardLink; Link != &mDiscoveredList; Link = Link->ForwardLink) {
+ DriverEntry = CR(Link, EFI_CORE_DRIVER_ENTRY, Link, EFI_CORE_DRIVER_ENTRY_SIGNATURE);
+ if (DriverEntry->FvHandle == FirmwareVolumeHandle &&
+ DriverEntry->Untrusted &&
+ CompareGuid (DriverName, &DriverEntry->FileName)) {
+ //
+ // Transition driver from Untrusted to Scheduled state.
+ //
+ CoreAcquireDispatcherLock ();
+ DriverEntry->Untrusted = FALSE;
+ DriverEntry->Scheduled = TRUE;
+ InsertTailList (&mScheduledQueue, &DriverEntry->ScheduledLink);
+ CoreReleaseDispatcherLock ();
+
+ return EFI_SUCCESS;
+ }
+ }
+ return EFI_NOT_FOUND;
+}
+
+/**
+ This is the main Dispatcher for DXE and it exits when there are no more
+ drivers to run. Drain the mScheduledQueue and load and start a PE
+ image for each driver. Search the mDiscoveredList to see if any driver can
+ be placed on the mScheduledQueue. If no drivers are placed on the
+ mScheduledQueue exit the function. On exit it is assumed the Bds()
+ will be called, and when the Bds() exits the Dispatcher will be called
+ again.
+
+ @retval EFI_ALREADY_STARTED The DXE Dispatcher is already running
+ @retval EFI_NOT_FOUND No DXE Drivers were dispatched
+ @retval EFI_SUCCESS One or more DXE Drivers were dispatched
+
+**/
+EFI_STATUS
+EFIAPI
+CoreDispatcher (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ EFI_STATUS ReturnStatus;
+ LIST_ENTRY *Link;
+ EFI_CORE_DRIVER_ENTRY *DriverEntry;
+ BOOLEAN ReadyToRun;
+ EFI_EVENT DxeDispatchEvent;
+
+ PERF_FUNCTION_BEGIN ();
+
+ if (gDispatcherRunning) {
+ //
+ // If the dispatcher is running don't let it be restarted.
+ //
+ return EFI_ALREADY_STARTED;
+ }
+
+ gDispatcherRunning = TRUE;
+
+ Status = CoreCreateEventEx (
+ EVT_NOTIFY_SIGNAL,
+ TPL_NOTIFY,
+ EfiEventEmptyFunction,
+ NULL,
+ &gEfiEventDxeDispatchGuid,
+ &DxeDispatchEvent
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ ReturnStatus = EFI_NOT_FOUND;
+ do {
+ //
+ // Drain the Scheduled Queue
+ //
+ while (!IsListEmpty (&mScheduledQueue)) {
+ DriverEntry = CR (
+ mScheduledQueue.ForwardLink,
+ EFI_CORE_DRIVER_ENTRY,
+ ScheduledLink,
+ EFI_CORE_DRIVER_ENTRY_SIGNATURE
+ );
+
+ //
+ // Load the DXE Driver image into memory. If the Driver was transitioned from
+ // Untrused to Scheduled it would have already been loaded so we may need to
+ // skip the LoadImage
+ //
+ if (DriverEntry->ImageHandle == NULL && !DriverEntry->IsFvImage) {
+ DEBUG ((DEBUG_INFO, "Loading driver %g\n", &DriverEntry->FileName));
+ Status = CoreLoadImage (
+ FALSE,
+ gDxeCoreImageHandle,
+ DriverEntry->FvFileDevicePath,
+ NULL,
+ 0,
+ &DriverEntry->ImageHandle
+ );
+
+ //
+ // Update the driver state to reflect that it's been loaded
+ //
+ if (EFI_ERROR (Status)) {
+ CoreAcquireDispatcherLock ();
+
+ if (Status == EFI_SECURITY_VIOLATION) {
+ //
+ // Take driver from Scheduled to Untrused state
+ //
+ DriverEntry->Untrusted = TRUE;
+ } else {
+ //
+ // The DXE Driver could not be loaded, and do not attempt to load or start it again.
+ // Take driver from Scheduled to Initialized.
+ //
+ // This case include the Never Trusted state if EFI_ACCESS_DENIED is returned
+ //
+ DriverEntry->Initialized = TRUE;
+ }
+
+ DriverEntry->Scheduled = FALSE;
+ RemoveEntryList (&DriverEntry->ScheduledLink);
+
+ CoreReleaseDispatcherLock ();
+
+ //
+ // If it's an error don't try the StartImage
+ //
+ continue;
+ }
+ }
+
+ CoreAcquireDispatcherLock ();
+
+ DriverEntry->Scheduled = FALSE;
+ DriverEntry->Initialized = TRUE;
+ RemoveEntryList (&DriverEntry->ScheduledLink);
+
+ CoreReleaseDispatcherLock ();
+
+
+ if (DriverEntry->IsFvImage) {
+ //
+ // Produce a firmware volume block protocol for FvImage so it gets dispatched from.
+ //
+ Status = CoreProcessFvImageFile (DriverEntry->Fv, DriverEntry->FvHandle, &DriverEntry->FileName);
+ } else {
+ REPORT_STATUS_CODE_WITH_EXTENDED_DATA (
+ EFI_PROGRESS_CODE,
+ (EFI_SOFTWARE_DXE_CORE | EFI_SW_PC_INIT_BEGIN),
+ &DriverEntry->ImageHandle,
+ sizeof (DriverEntry->ImageHandle)
+ );
+ ASSERT (DriverEntry->ImageHandle != NULL);
+
+ Status = CoreStartImage (DriverEntry->ImageHandle, NULL, NULL);
+
+ REPORT_STATUS_CODE_WITH_EXTENDED_DATA (
+ EFI_PROGRESS_CODE,
+ (EFI_SOFTWARE_DXE_CORE | EFI_SW_PC_INIT_END),
+ &DriverEntry->ImageHandle,
+ sizeof (DriverEntry->ImageHandle)
+ );
+ }
+
+ ReturnStatus = EFI_SUCCESS;
+ }
+
+ //
+ // Now DXE Dispatcher finished one round of dispatch, signal an event group
+ // so that SMM Dispatcher get chance to dispatch SMM Drivers which depend
+ // on UEFI protocols
+ //
+ if (!EFI_ERROR (ReturnStatus)) {
+ CoreSignalEvent (DxeDispatchEvent);
+ }
+
+ //
+ // Search DriverList for items to place on Scheduled Queue
+ //
+ ReadyToRun = FALSE;
+ for (Link = mDiscoveredList.ForwardLink; Link != &mDiscoveredList; Link = Link->ForwardLink) {
+ DriverEntry = CR (Link, EFI_CORE_DRIVER_ENTRY, Link, EFI_CORE_DRIVER_ENTRY_SIGNATURE);
+
+ if (DriverEntry->DepexProtocolError){
+ //
+ // If Section Extraction Protocol did not let the Depex be read before retry the read
+ //
+ Status = CoreGetDepexSectionAndPreProccess (DriverEntry);
+ }
+
+ if (DriverEntry->Dependent) {
+ if (CoreIsSchedulable (DriverEntry)) {
+ CoreInsertOnScheduledQueueWhileProcessingBeforeAndAfter (DriverEntry);
+ ReadyToRun = TRUE;
+ }
+ } else {
+ if (DriverEntry->Unrequested) {
+ DEBUG ((DEBUG_DISPATCH, "Evaluate DXE DEPEX for FFS(%g)\n", &DriverEntry->FileName));
+ DEBUG ((DEBUG_DISPATCH, " SOR = Not Requested\n"));
+ DEBUG ((DEBUG_DISPATCH, " RESULT = FALSE\n"));
+ }
+ }
+ }
+ } while (ReadyToRun);
+
+ //
+ // Close DXE dispatch Event
+ //
+ CoreCloseEvent (DxeDispatchEvent);
+
+ gDispatcherRunning = FALSE;
+
+ PERF_FUNCTION_END ();
+
+ return ReturnStatus;
+}
+
+
+/**
+ Insert InsertedDriverEntry onto the mScheduledQueue. To do this you
+ must add any driver with a before dependency on InsertedDriverEntry first.
+ You do this by recursively calling this routine. After all the Befores are
+ processed you can add InsertedDriverEntry to the mScheduledQueue.
+ Then you can add any driver with an After dependency on InsertedDriverEntry
+ by recursively calling this routine.
+
+ @param InsertedDriverEntry The driver to insert on the ScheduledLink Queue
+
+**/
+VOID
+CoreInsertOnScheduledQueueWhileProcessingBeforeAndAfter (
+ IN EFI_CORE_DRIVER_ENTRY *InsertedDriverEntry
+ )
+{
+ LIST_ENTRY *Link;
+ EFI_CORE_DRIVER_ENTRY *DriverEntry;
+
+ //
+ // Process Before Dependency
+ //
+ for (Link = mDiscoveredList.ForwardLink; Link != &mDiscoveredList; Link = Link->ForwardLink) {
+ DriverEntry = CR(Link, EFI_CORE_DRIVER_ENTRY, Link, EFI_CORE_DRIVER_ENTRY_SIGNATURE);
+ if (DriverEntry->Before && DriverEntry->Dependent && DriverEntry != InsertedDriverEntry) {
+ DEBUG ((DEBUG_DISPATCH, "Evaluate DXE DEPEX for FFS(%g)\n", &DriverEntry->FileName));
+ DEBUG ((DEBUG_DISPATCH, " BEFORE FFS(%g) = ", &DriverEntry->BeforeAfterGuid));
+ if (CompareGuid (&InsertedDriverEntry->FileName, &DriverEntry->BeforeAfterGuid)) {
+ //
+ // Recursively process BEFORE
+ //
+ DEBUG ((DEBUG_DISPATCH, "TRUE\n END\n RESULT = TRUE\n"));
+ CoreInsertOnScheduledQueueWhileProcessingBeforeAndAfter (DriverEntry);
+ } else {
+ DEBUG ((DEBUG_DISPATCH, "FALSE\n END\n RESULT = FALSE\n"));
+ }
+ }
+ }
+
+ //
+ // Convert driver from Dependent to Scheduled state
+ //
+ CoreAcquireDispatcherLock ();
+
+ InsertedDriverEntry->Dependent = FALSE;
+ InsertedDriverEntry->Scheduled = TRUE;
+ InsertTailList (&mScheduledQueue, &InsertedDriverEntry->ScheduledLink);
+
+ CoreReleaseDispatcherLock ();
+
+ //
+ // Process After Dependency
+ //
+ for (Link = mDiscoveredList.ForwardLink; Link != &mDiscoveredList; Link = Link->ForwardLink) {
+ DriverEntry = CR(Link, EFI_CORE_DRIVER_ENTRY, Link, EFI_CORE_DRIVER_ENTRY_SIGNATURE);
+ if (DriverEntry->After && DriverEntry->Dependent && DriverEntry != InsertedDriverEntry) {
+ DEBUG ((DEBUG_DISPATCH, "Evaluate DXE DEPEX for FFS(%g)\n", &DriverEntry->FileName));
+ DEBUG ((DEBUG_DISPATCH, " AFTER FFS(%g) = ", &DriverEntry->BeforeAfterGuid));
+ if (CompareGuid (&InsertedDriverEntry->FileName, &DriverEntry->BeforeAfterGuid)) {
+ //
+ // Recursively process AFTER
+ //
+ DEBUG ((DEBUG_DISPATCH, "TRUE\n END\n RESULT = TRUE\n"));
+ CoreInsertOnScheduledQueueWhileProcessingBeforeAndAfter (DriverEntry);
+ } else {
+ DEBUG ((DEBUG_DISPATCH, "FALSE\n END\n RESULT = FALSE\n"));
+ }
+ }
+ }
+}
+
+
+/**
+ Return TRUE if the Fv has been processed, FALSE if not.
+
+ @param FvHandle The handle of a FV that's being tested
+
+ @retval TRUE Fv protocol on FvHandle has been processed
+ @retval FALSE Fv protocol on FvHandle has not yet been processed
+
+**/
+BOOLEAN
+FvHasBeenProcessed (
+ IN EFI_HANDLE FvHandle
+ )
+{
+ LIST_ENTRY *Link;
+ KNOWN_HANDLE *KnownHandle;
+
+ for (Link = mFvHandleList.ForwardLink; Link != &mFvHandleList; Link = Link->ForwardLink) {
+ KnownHandle = CR(Link, KNOWN_HANDLE, Link, KNOWN_HANDLE_SIGNATURE);
+ if (KnownHandle->Handle == FvHandle) {
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+
+/**
+ Remember that Fv protocol on FvHandle has had it's drivers placed on the
+ mDiscoveredList. This fucntion adds entries on the mFvHandleList if new
+ entry is different from one in mFvHandleList by checking FvImage Guid.
+ Items are never removed/freed from the mFvHandleList.
+
+ @param FvHandle The handle of a FV that has been processed
+
+ @return A point to new added FvHandle entry. If FvHandle with the same FvImage guid
+ has been added, NULL will return.
+
+**/
+KNOWN_HANDLE *
+FvIsBeingProcessed (
+ IN EFI_HANDLE FvHandle
+ )
+{
+ EFI_STATUS Status;
+ EFI_GUID FvNameGuid;
+ BOOLEAN FvNameGuidIsFound;
+ UINT32 ExtHeaderOffset;
+ EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb;
+ EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader;
+ EFI_FV_BLOCK_MAP_ENTRY *BlockMap;
+ UINTN LbaOffset;
+ UINTN Index;
+ EFI_LBA LbaIndex;
+ LIST_ENTRY *Link;
+ KNOWN_HANDLE *KnownHandle;
+
+ FwVolHeader = NULL;
+
+ //
+ // Get the FirmwareVolumeBlock protocol on that handle
+ //
+ FvNameGuidIsFound = FALSE;
+ Status = CoreHandleProtocol (FvHandle, &gEfiFirmwareVolumeBlockProtocolGuid, (VOID **)&Fvb);
+ if (!EFI_ERROR (Status)) {
+ //
+ // Get the full FV header based on FVB protocol.
+ //
+ ASSERT (Fvb != NULL);
+ Status = GetFwVolHeader (Fvb, &FwVolHeader);
+ if (!EFI_ERROR (Status)) {
+ ASSERT (FwVolHeader != NULL);
+ if (VerifyFvHeaderChecksum (FwVolHeader) && FwVolHeader->ExtHeaderOffset != 0) {
+ ExtHeaderOffset = (UINT32) FwVolHeader->ExtHeaderOffset;
+ BlockMap = FwVolHeader->BlockMap;
+ LbaIndex = 0;
+ LbaOffset = 0;
+ //
+ // Find LbaIndex and LbaOffset for FV extension header based on BlockMap.
+ //
+ while ((BlockMap->NumBlocks != 0) || (BlockMap->Length != 0)) {
+ for (Index = 0; Index < BlockMap->NumBlocks && ExtHeaderOffset >= BlockMap->Length; Index ++) {
+ ExtHeaderOffset -= BlockMap->Length;
+ LbaIndex ++;
+ }
+ //
+ // Check whether FvExtHeader is crossing the multi block range.
+ //
+ if (Index < BlockMap->NumBlocks) {
+ LbaOffset = ExtHeaderOffset;
+ break;
+ }
+ BlockMap++;
+ }
+ //
+ // Read FvNameGuid from FV extension header.
+ //
+ Status = ReadFvbData (Fvb, &LbaIndex, &LbaOffset, sizeof (FvNameGuid), (UINT8 *) &FvNameGuid);
+ if (!EFI_ERROR (Status)) {
+ FvNameGuidIsFound = TRUE;
+ }
+ }
+ CoreFreePool (FwVolHeader);
+ }
+ }
+
+ if (FvNameGuidIsFound) {
+ //
+ // Check whether the FV image with the found FvNameGuid has been processed.
+ //
+ for (Link = mFvHandleList.ForwardLink; Link != &mFvHandleList; Link = Link->ForwardLink) {
+ KnownHandle = CR(Link, KNOWN_HANDLE, Link, KNOWN_HANDLE_SIGNATURE);
+ if (CompareGuid (&FvNameGuid, &KnownHandle->FvNameGuid)) {
+ DEBUG ((EFI_D_ERROR, "FvImage on FvHandle %p and %p has the same FvNameGuid %g.\n", FvHandle, KnownHandle->Handle, &FvNameGuid));
+ return NULL;
+ }
+ }
+ }
+
+ KnownHandle = AllocateZeroPool (sizeof (KNOWN_HANDLE));
+ ASSERT (KnownHandle != NULL);
+
+ KnownHandle->Signature = KNOWN_HANDLE_SIGNATURE;
+ KnownHandle->Handle = FvHandle;
+ if (FvNameGuidIsFound) {
+ CopyGuid (&KnownHandle->FvNameGuid, &FvNameGuid);
+ }
+ InsertTailList (&mFvHandleList, &KnownHandle->Link);
+ return KnownHandle;
+}
+
+
+
+
+/**
+ Convert FvHandle and DriverName into an EFI device path
+
+ @param Fv Fv protocol, needed to read Depex info out of
+ FLASH.
+ @param FvHandle Handle for Fv, needed in the
+ EFI_CORE_DRIVER_ENTRY so that the PE image can be
+ read out of the FV at a later time.
+ @param DriverName Name of driver to add to mDiscoveredList.
+
+ @return Pointer to device path constructed from FvHandle and DriverName
+
+**/
+EFI_DEVICE_PATH_PROTOCOL *
+CoreFvToDevicePath (
+ IN EFI_FIRMWARE_VOLUME2_PROTOCOL *Fv,
+ IN EFI_HANDLE FvHandle,
+ IN EFI_GUID *DriverName
+ )
+{
+ EFI_STATUS Status;
+ EFI_DEVICE_PATH_PROTOCOL *FvDevicePath;
+ EFI_DEVICE_PATH_PROTOCOL *FileNameDevicePath;
+
+ //
+ // Remember the device path of the FV
+ //
+ Status = CoreHandleProtocol (FvHandle, &gEfiDevicePathProtocolGuid, (VOID **)&FvDevicePath);
+ if (EFI_ERROR (Status)) {
+ FileNameDevicePath = NULL;
+ } else {
+ //
+ // Build a device path to the file in the FV to pass into gBS->LoadImage
+ //
+ EfiInitializeFwVolDevicepathNode (&mFvDevicePath.File, DriverName);
+ SetDevicePathEndNode (&mFvDevicePath.End);
+
+ FileNameDevicePath = AppendDevicePath (
+ FvDevicePath,
+ (EFI_DEVICE_PATH_PROTOCOL *)&mFvDevicePath
+ );
+ }
+
+ return FileNameDevicePath;
+}
+
+
+
+/**
+ Add an entry to the mDiscoveredList. Allocate memory to store the DriverEntry,
+ and initilize any state variables. Read the Depex from the FV and store it
+ in DriverEntry. Pre-process the Depex to set the SOR, Before and After state.
+ The Discovered list is never free'ed and contains booleans that represent the
+ other possible DXE driver states.
+
+ @param Fv Fv protocol, needed to read Depex info out of
+ FLASH.
+ @param FvHandle Handle for Fv, needed in the
+ EFI_CORE_DRIVER_ENTRY so that the PE image can be
+ read out of the FV at a later time.
+ @param DriverName Name of driver to add to mDiscoveredList.
+ @param Type Fv File Type of file to add to mDiscoveredList.
+
+ @retval EFI_SUCCESS If driver was added to the mDiscoveredList.
+ @retval EFI_ALREADY_STARTED The driver has already been started. Only one
+ DriverName may be active in the system at any one
+ time.
+
+**/
+EFI_STATUS
+CoreAddToDriverList (
+ IN EFI_FIRMWARE_VOLUME2_PROTOCOL *Fv,
+ IN EFI_HANDLE FvHandle,
+ IN EFI_GUID *DriverName,
+ IN EFI_FV_FILETYPE Type
+ )
+{
+ EFI_CORE_DRIVER_ENTRY *DriverEntry;
+
+
+ //
+ // Create the Driver Entry for the list. ZeroPool initializes lots of variables to
+ // NULL or FALSE.
+ //
+ DriverEntry = AllocateZeroPool (sizeof (EFI_CORE_DRIVER_ENTRY));
+ ASSERT (DriverEntry != NULL);
+ if (Type == EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE) {
+ DriverEntry->IsFvImage = TRUE;
+ }
+
+ DriverEntry->Signature = EFI_CORE_DRIVER_ENTRY_SIGNATURE;
+ CopyGuid (&DriverEntry->FileName, DriverName);
+ DriverEntry->FvHandle = FvHandle;
+ DriverEntry->Fv = Fv;
+ DriverEntry->FvFileDevicePath = CoreFvToDevicePath (Fv, FvHandle, DriverName);
+
+ CoreGetDepexSectionAndPreProccess (DriverEntry);
+
+ CoreAcquireDispatcherLock ();
+
+ InsertTailList (&mDiscoveredList, &DriverEntry->Link);
+
+ CoreReleaseDispatcherLock ();
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Check if a FV Image type file (EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE) is
+ described by a EFI_HOB_FIRMWARE_VOLUME2 Hob.
+
+ @param FvNameGuid The FV image guid specified.
+ @param DriverName The driver guid specified.
+
+ @retval TRUE This file is found in a EFI_HOB_FIRMWARE_VOLUME2
+ Hob.
+ @retval FALSE Not found.
+
+**/
+BOOLEAN
+FvFoundInHobFv2 (
+ IN CONST EFI_GUID *FvNameGuid,
+ IN CONST EFI_GUID *DriverName
+ )
+{
+ EFI_PEI_HOB_POINTERS HobFv2;
+
+ HobFv2.Raw = GetHobList ();
+
+ while ((HobFv2.Raw = GetNextHob (EFI_HOB_TYPE_FV2, HobFv2.Raw)) != NULL) {
+ //
+ // Compare parent FvNameGuid and FileGuid both.
+ //
+ if (CompareGuid (DriverName, &HobFv2.FirmwareVolume2->FileName) &&
+ CompareGuid (FvNameGuid, &HobFv2.FirmwareVolume2->FvName)) {
+ return TRUE;
+ }
+ HobFv2.Raw = GET_NEXT_HOB (HobFv2);
+ }
+
+ return FALSE;
+}
+
+/**
+ Find USED_SIZE FV_EXT_TYPE entry in FV extension header and get the FV used size.
+
+ @param[in] FvHeader Pointer to FV header.
+ @param[out] FvUsedSize Pointer to FV used size returned,
+ only valid if USED_SIZE FV_EXT_TYPE entry is found.
+ @param[out] EraseByte Pointer to erase byte returned,
+ only valid if USED_SIZE FV_EXT_TYPE entry is found.
+
+ @retval TRUE USED_SIZE FV_EXT_TYPE entry is found,
+ FV used size and erase byte are returned.
+ @retval FALSE No USED_SIZE FV_EXT_TYPE entry found.
+
+**/
+BOOLEAN
+GetFvUsedSize (
+ IN EFI_FIRMWARE_VOLUME_HEADER *FvHeader,
+ OUT UINT32 *FvUsedSize,
+ OUT UINT8 *EraseByte
+ )
+{
+ UINT16 ExtHeaderOffset;
+ EFI_FIRMWARE_VOLUME_EXT_HEADER *ExtHeader;
+ EFI_FIRMWARE_VOLUME_EXT_ENTRY *ExtEntryList;
+ EFI_FIRMWARE_VOLUME_EXT_ENTRY_USED_SIZE_TYPE *ExtEntryUsedSize;
+
+ ExtHeaderOffset = ReadUnaligned16 (&FvHeader->ExtHeaderOffset);
+ if (ExtHeaderOffset != 0) {
+ ExtHeader = (EFI_FIRMWARE_VOLUME_EXT_HEADER *) ((UINT8 *) FvHeader + ExtHeaderOffset);
+ ExtEntryList = (EFI_FIRMWARE_VOLUME_EXT_ENTRY *) (ExtHeader + 1);
+ while ((UINTN) ExtEntryList < ((UINTN) ExtHeader + ReadUnaligned32 (&ExtHeader->ExtHeaderSize))) {
+ if (ReadUnaligned16 (&ExtEntryList->ExtEntryType) == EFI_FV_EXT_TYPE_USED_SIZE_TYPE) {
+ //
+ // USED_SIZE FV_EXT_TYPE entry is found.
+ //
+ ExtEntryUsedSize = (EFI_FIRMWARE_VOLUME_EXT_ENTRY_USED_SIZE_TYPE *) ExtEntryList;
+ *FvUsedSize = ReadUnaligned32 (&ExtEntryUsedSize->UsedSize);
+ if ((ReadUnaligned32 (&FvHeader->Attributes) & EFI_FVB2_ERASE_POLARITY) != 0) {
+ *EraseByte = 0xFF;
+ } else {
+ *EraseByte = 0;
+ }
+ DEBUG ((
+ DEBUG_INFO,
+ "FV at 0x%x has 0x%x used size, and erase byte is 0x%02x\n",
+ FvHeader,
+ *FvUsedSize,
+ *EraseByte
+ ));
+ return TRUE;
+ }
+ ExtEntryList = (EFI_FIRMWARE_VOLUME_EXT_ENTRY *)
+ ((UINT8 *) ExtEntryList + ReadUnaligned16 (&ExtEntryList->ExtEntrySize));
+ }
+ }
+
+ //
+ // No USED_SIZE FV_EXT_TYPE entry found.
+ //
+ return FALSE;
+}
+
+/**
+ Get Fv image(s) from the FV through file name, and produce FVB protocol for every Fv image(s).
+
+ @param Fv The FIRMWARE_VOLUME protocol installed on the FV.
+ @param FvHandle The handle which FVB protocol installed on.
+ @param FileName The file name guid specified.
+
+ @retval EFI_OUT_OF_RESOURCES No enough memory or other resource.
+ @retval EFI_SUCCESS Function successfully returned.
+
+**/
+EFI_STATUS
+CoreProcessFvImageFile (
+ IN EFI_FIRMWARE_VOLUME2_PROTOCOL *Fv,
+ IN EFI_HANDLE FvHandle,
+ IN EFI_GUID *FileName
+ )
+{
+ EFI_STATUS Status;
+ EFI_SECTION_TYPE SectionType;
+ UINT32 AuthenticationStatus;
+ VOID *Buffer;
+ VOID *AlignedBuffer;
+ UINTN BufferSize;
+ EFI_FIRMWARE_VOLUME_HEADER *FvHeader;
+ UINT32 FvAlignment;
+ EFI_DEVICE_PATH_PROTOCOL *FvFileDevicePath;
+ UINT32 FvUsedSize;
+ UINT8 EraseByte;
+ UINTN Index;
+
+ //
+ // Read firmware volume section(s)
+ //
+ SectionType = EFI_SECTION_FIRMWARE_VOLUME_IMAGE;
+
+ Index = 0;
+ do {
+ FvHeader = NULL;
+ FvAlignment = 0;
+ Buffer = NULL;
+ BufferSize = 0;
+ AlignedBuffer = NULL;
+ Status = Fv->ReadSection (
+ Fv,
+ FileName,
+ SectionType,
+ Index,
+ &Buffer,
+ &BufferSize,
+ &AuthenticationStatus
+ );
+ if (!EFI_ERROR (Status)) {
+ //
+ // Evaluate the authentication status of the Firmware Volume through
+ // Security Architectural Protocol
+ //
+ if (gSecurity != NULL) {
+ FvFileDevicePath = CoreFvToDevicePath (Fv, FvHandle, FileName);
+ Status = gSecurity->FileAuthenticationState (
+ gSecurity,
+ AuthenticationStatus,
+ FvFileDevicePath
+ );
+ if (FvFileDevicePath != NULL) {
+ FreePool (FvFileDevicePath);
+ }
+
+ if (Status != EFI_SUCCESS) {
+ //
+ // Security check failed. The firmware volume should not be used for any purpose.
+ //
+ if (Buffer != NULL) {
+ FreePool (Buffer);
+ }
+ break;
+ }
+ }
+
+ //
+ // FvImage should be at its required alignment.
+ //
+ FvHeader = (EFI_FIRMWARE_VOLUME_HEADER *) Buffer;
+ //
+ // If EFI_FVB2_WEAK_ALIGNMENT is set in the volume header then the first byte of the volume
+ // can be aligned on any power-of-two boundary. A weakly aligned volume can not be moved from
+ // its initial linked location and maintain its alignment.
+ //
+ if ((ReadUnaligned32 (&FvHeader->Attributes) & EFI_FVB2_WEAK_ALIGNMENT) != EFI_FVB2_WEAK_ALIGNMENT) {
+ //
+ // Get FvHeader alignment
+ //
+ FvAlignment = 1 << ((ReadUnaligned32 (&FvHeader->Attributes) & EFI_FVB2_ALIGNMENT) >> 16);
+ //
+ // FvAlignment must be greater than or equal to 8 bytes of the minimum FFS alignment value.
+ //
+ if (FvAlignment < 8) {
+ FvAlignment = 8;
+ }
+
+ DEBUG ((
+ DEBUG_INFO,
+ "%a() FV at 0x%x, FvAlignment required is 0x%x\n",
+ __FUNCTION__,
+ FvHeader,
+ FvAlignment
+ ));
+
+ //
+ // Check FvImage alignment.
+ //
+ if ((UINTN) FvHeader % FvAlignment != 0) {
+ //
+ // Allocate the aligned buffer for the FvImage.
+ //
+ AlignedBuffer = AllocateAlignedPages (EFI_SIZE_TO_PAGES (BufferSize), (UINTN) FvAlignment);
+ if (AlignedBuffer == NULL) {
+ FreePool (Buffer);
+ Status = EFI_OUT_OF_RESOURCES;
+ break;
+ } else {
+ //
+ // Move FvImage into the aligned buffer and release the original buffer.
+ //
+ if (GetFvUsedSize (FvHeader, &FvUsedSize, &EraseByte)) {
+ //
+ // Copy the used bytes and fill the rest with the erase value.
+ //
+ CopyMem (AlignedBuffer, FvHeader, (UINTN) FvUsedSize);
+ SetMem (
+ (UINT8 *) AlignedBuffer + FvUsedSize,
+ (UINTN) (BufferSize - FvUsedSize),
+ EraseByte
+ );
+ } else {
+ CopyMem (AlignedBuffer, Buffer, BufferSize);
+ }
+ FvHeader = (EFI_FIRMWARE_VOLUME_HEADER *) AlignedBuffer;
+ FreePool (Buffer);
+ Buffer = NULL;
+ }
+ }
+ }
+ //
+ // Produce a FVB protocol for the file
+ //
+ Status = ProduceFVBProtocolOnBuffer (
+ (EFI_PHYSICAL_ADDRESS) (UINTN) FvHeader,
+ (UINT64)BufferSize,
+ FvHandle,
+ AuthenticationStatus,
+ NULL
+ );
+ }
+
+ if (EFI_ERROR (Status)) {
+ //
+ // ReadSection or Produce FVB failed, Free data buffer
+ //
+ if (Buffer != NULL) {
+ FreePool (Buffer);
+ }
+
+ if (AlignedBuffer != NULL) {
+ FreeAlignedPages (AlignedBuffer, EFI_SIZE_TO_PAGES (BufferSize));
+ }
+
+ break;
+ } else {
+ Index++;
+ }
+ } while (TRUE);
+
+ if (Index > 0) {
+ //
+ // At least one FvImage has been processed successfully.
+ //
+ return EFI_SUCCESS;
+ } else {
+ return Status;
+ }
+}
+
+
+/**
+ Event notification that is fired every time a FV dispatch protocol is added.
+ More than one protocol may have been added when this event is fired, so you
+ must loop on CoreLocateHandle () to see how many protocols were added and
+ do the following to each FV:
+ If the Fv has already been processed, skip it. If the Fv has not been
+ processed then mark it as being processed, as we are about to process it.
+ Read the Fv and add any driver in the Fv to the mDiscoveredList.The
+ mDiscoveredList is never free'ed and contains variables that define
+ the other states the DXE driver transitions to..
+ While you are at it read the A Priori file into memory.
+ Place drivers in the A Priori list onto the mScheduledQueue.
+
+ @param Event The Event that is being processed, not used.
+ @param Context Event Context, not used.
+
+**/
+VOID
+EFIAPI
+CoreFwVolEventProtocolNotify (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ EFI_STATUS Status;
+ EFI_STATUS GetNextFileStatus;
+ EFI_FIRMWARE_VOLUME2_PROTOCOL *Fv;
+ EFI_DEVICE_PATH_PROTOCOL *FvDevicePath;
+ EFI_HANDLE FvHandle;
+ UINTN BufferSize;
+ EFI_GUID NameGuid;
+ UINTN Key;
+ EFI_FV_FILETYPE Type;
+ EFI_FV_FILE_ATTRIBUTES Attributes;
+ UINTN Size;
+ EFI_CORE_DRIVER_ENTRY *DriverEntry;
+ EFI_GUID *AprioriFile;
+ UINTN AprioriEntryCount;
+ UINTN Index;
+ LIST_ENTRY *Link;
+ UINT32 AuthenticationStatus;
+ UINTN SizeOfBuffer;
+ VOID *DepexBuffer;
+ KNOWN_HANDLE *KnownHandle;
+
+ FvHandle = NULL;
+
+ while (TRUE) {
+ BufferSize = sizeof (EFI_HANDLE);
+ Status = CoreLocateHandle (
+ ByRegisterNotify,
+ NULL,
+ mFwVolEventRegistration,
+ &BufferSize,
+ &FvHandle
+ );
+ if (EFI_ERROR (Status)) {
+ //
+ // If no more notification events exit
+ //
+ return;
+ }
+
+ if (FvHasBeenProcessed (FvHandle)) {
+ //
+ // This Fv has already been processed so lets skip it!
+ //
+ continue;
+ }
+
+ //
+ // Since we are about to process this Fv mark it as processed.
+ //
+ KnownHandle = FvIsBeingProcessed (FvHandle);
+ if (KnownHandle == NULL) {
+ //
+ // The FV with the same FV name guid has already been processed.
+ // So lets skip it!
+ //
+ continue;
+ }
+
+ Status = CoreHandleProtocol (FvHandle, &gEfiFirmwareVolume2ProtocolGuid, (VOID **)&Fv);
+ if (EFI_ERROR (Status) || Fv == NULL) {
+ //
+ // FvHandle must have Firmware Volume2 protocol thus we should never get here.
+ //
+ ASSERT (FALSE);
+ continue;
+ }
+
+ Status = CoreHandleProtocol (FvHandle, &gEfiDevicePathProtocolGuid, (VOID **)&FvDevicePath);
+ if (EFI_ERROR (Status)) {
+ //
+ // The Firmware volume doesn't have device path, can't be dispatched.
+ //
+ continue;
+ }
+
+ //
+ // Discover Drivers in FV and add them to the Discovered Driver List.
+ // Process EFI_FV_FILETYPE_DRIVER type and then EFI_FV_FILETYPE_COMBINED_PEIM_DRIVER
+ // EFI_FV_FILETYPE_DXE_CORE is processed to produce a Loaded Image protocol for the core
+ // EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE is processed to create a Fvb
+ //
+ for (Index = 0; Index < sizeof (mDxeFileTypes) / sizeof (EFI_FV_FILETYPE); Index++) {
+ //
+ // Initialize the search key
+ //
+ Key = 0;
+ do {
+ Type = mDxeFileTypes[Index];
+ GetNextFileStatus = Fv->GetNextFile (
+ Fv,
+ &Key,
+ &Type,
+ &NameGuid,
+ &Attributes,
+ &Size
+ );
+ if (!EFI_ERROR (GetNextFileStatus)) {
+ if (Type == EFI_FV_FILETYPE_DXE_CORE) {
+ //
+ // If this is the DXE core fill in it's DevicePath & DeviceHandle
+ //
+ if (gDxeCoreLoadedImage->FilePath == NULL) {
+ if (CompareGuid (&NameGuid, gDxeCoreFileName)) {
+ //
+ // Maybe One specail Fv cantains only one DXE_CORE module, so its device path must
+ // be initialized completely.
+ //
+ EfiInitializeFwVolDevicepathNode (&mFvDevicePath.File, &NameGuid);
+ SetDevicePathEndNode (&mFvDevicePath.End);
+
+ gDxeCoreLoadedImage->FilePath = DuplicateDevicePath (
+ (EFI_DEVICE_PATH_PROTOCOL *)&mFvDevicePath
+ );
+ gDxeCoreLoadedImage->DeviceHandle = FvHandle;
+ }
+ }
+ } else if (Type == EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE) {
+ //
+ // Check if this EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE file has already
+ // been extracted.
+ //
+ if (FvFoundInHobFv2 (&KnownHandle->FvNameGuid, &NameGuid)) {
+ continue;
+ }
+
+ //
+ // Check if this EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE file has SMM depex section.
+ //
+ DepexBuffer = NULL;
+ SizeOfBuffer = 0;
+ Status = Fv->ReadSection (
+ Fv,
+ &NameGuid,
+ EFI_SECTION_SMM_DEPEX,
+ 0,
+ &DepexBuffer,
+ &SizeOfBuffer,
+ &AuthenticationStatus
+ );
+ if (!EFI_ERROR (Status)) {
+ //
+ // If SMM depex section is found, this FV image is invalid to be supported.
+ // ASSERT FALSE to report this FV image.
+ //
+ FreePool (DepexBuffer);
+ ASSERT (FALSE);
+ }
+
+ //
+ // Check if this EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE file has DXE depex section.
+ //
+ DepexBuffer = NULL;
+ SizeOfBuffer = 0;
+ Status = Fv->ReadSection (
+ Fv,
+ &NameGuid,
+ EFI_SECTION_DXE_DEPEX,
+ 0,
+ &DepexBuffer,
+ &SizeOfBuffer,
+ &AuthenticationStatus
+ );
+ if (EFI_ERROR (Status)) {
+ //
+ // If no depex section, produce a firmware volume block protocol for it so it gets dispatched from.
+ //
+ CoreProcessFvImageFile (Fv, FvHandle, &NameGuid);
+ } else {
+ //
+ // If depex section is found, this FV image will be dispatched until its depex is evaluated to TRUE.
+ //
+ FreePool (DepexBuffer);
+ CoreAddToDriverList (Fv, FvHandle, &NameGuid, Type);
+ }
+ } else {
+ //
+ // Transition driver from Undiscovered to Discovered state
+ //
+ CoreAddToDriverList (Fv, FvHandle, &NameGuid, Type);
+ }
+ }
+ } while (!EFI_ERROR (GetNextFileStatus));
+ }
+
+ //
+ // Read the array of GUIDs from the Apriori file if it is present in the firmware volume
+ //
+ AprioriFile = NULL;
+ Status = Fv->ReadSection (
+ Fv,
+ &gAprioriGuid,
+ EFI_SECTION_RAW,
+ 0,
+ (VOID **)&AprioriFile,
+ &SizeOfBuffer,
+ &AuthenticationStatus
+ );
+ if (!EFI_ERROR (Status)) {
+ AprioriEntryCount = SizeOfBuffer / sizeof (EFI_GUID);
+ } else {
+ AprioriEntryCount = 0;
+ }
+
+ //
+ // Put drivers on Apriori List on the Scheduled queue. The Discovered List includes
+ // drivers not in the current FV and these must be skipped since the a priori list
+ // is only valid for the FV that it resided in.
+ //
+
+ for (Index = 0; Index < AprioriEntryCount; Index++) {
+ for (Link = mDiscoveredList.ForwardLink; Link != &mDiscoveredList; Link = Link->ForwardLink) {
+ DriverEntry = CR(Link, EFI_CORE_DRIVER_ENTRY, Link, EFI_CORE_DRIVER_ENTRY_SIGNATURE);
+ if (CompareGuid (&DriverEntry->FileName, &AprioriFile[Index]) &&
+ (FvHandle == DriverEntry->FvHandle)) {
+ CoreAcquireDispatcherLock ();
+ DriverEntry->Dependent = FALSE;
+ DriverEntry->Scheduled = TRUE;
+ InsertTailList (&mScheduledQueue, &DriverEntry->ScheduledLink);
+ CoreReleaseDispatcherLock ();
+ DEBUG ((DEBUG_DISPATCH, "Evaluate DXE DEPEX for FFS(%g)\n", &DriverEntry->FileName));
+ DEBUG ((DEBUG_DISPATCH, " RESULT = TRUE (Apriori)\n"));
+ break;
+ }
+ }
+ }
+
+ //
+ // Free data allocated by Fv->ReadSection ()
+ //
+ CoreFreePool (AprioriFile);
+ }
+}
+
+
+
+/**
+ Initialize the dispatcher. Initialize the notification function that runs when
+ an FV2 protocol is added to the system.
+
+**/
+VOID
+CoreInitializeDispatcher (
+ VOID
+ )
+{
+ PERF_FUNCTION_BEGIN ();
+
+ mFwVolEvent = EfiCreateProtocolNotifyEvent (
+ &gEfiFirmwareVolume2ProtocolGuid,
+ TPL_CALLBACK,
+ CoreFwVolEventProtocolNotify,
+ NULL,
+ &mFwVolEventRegistration
+ );
+
+ PERF_FUNCTION_END ();
+}
+
+//
+// Function only used in debug builds
+//
+
+/**
+ Traverse the discovered list for any drivers that were discovered but not loaded
+ because the dependency experessions evaluated to false.
+
+**/
+VOID
+CoreDisplayDiscoveredNotDispatched (
+ VOID
+ )
+{
+ LIST_ENTRY *Link;
+ EFI_CORE_DRIVER_ENTRY *DriverEntry;
+
+ for (Link = mDiscoveredList.ForwardLink;Link !=&mDiscoveredList; Link = Link->ForwardLink) {
+ DriverEntry = CR(Link, EFI_CORE_DRIVER_ENTRY, Link, EFI_CORE_DRIVER_ENTRY_SIGNATURE);
+ if (DriverEntry->Dependent) {
+ DEBUG ((DEBUG_LOAD, "Driver %g was discovered but not loaded!!\n", &DriverEntry->FileName));
+ }
+ }
+}
diff --git a/roms/edk2/MdeModulePkg/Core/Dxe/DxeCore.uni b/roms/edk2/MdeModulePkg/Core/Dxe/DxeCore.uni
new file mode 100644
index 000000000..54b855281
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Core/Dxe/DxeCore.uni
@@ -0,0 +1,16 @@
+// /** @file
+// This is core module in DXE phase.
+//
+// It provides an implementation of DXE Core that is compliant with DXE CIS.
+//
+// Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "The core module in DXE phase"
+
+#string STR_MODULE_DESCRIPTION #language en-US "It provides an implementation of DXE Core that is compliant with DXE CIS."
+
diff --git a/roms/edk2/MdeModulePkg/Core/Dxe/DxeCoreExtra.uni b/roms/edk2/MdeModulePkg/Core/Dxe/DxeCoreExtra.uni
new file mode 100644
index 000000000..c9abba4f6
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Core/Dxe/DxeCoreExtra.uni
@@ -0,0 +1,14 @@
+// /** @file
+// DxeCore Localized Strings and Content
+//
+// Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+#string STR_PROPERTIES_MODULE_NAME
+#language en-US
+"Core DXE Services Driver"
+
+
diff --git a/roms/edk2/MdeModulePkg/Core/Dxe/DxeMain.h b/roms/edk2/MdeModulePkg/Core/Dxe/DxeMain.h
new file mode 100644
index 000000000..9bd3c0d08
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Core/Dxe/DxeMain.h
@@ -0,0 +1,2940 @@
+/** @file
+ The internal header file includes the common header files, defines
+ internal structure and functions used by DxeCore module.
+
+Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _DXE_MAIN_H_
+#define _DXE_MAIN_H_
+
+
+
+#include <PiDxe.h>
+
+#include <Protocol/LoadedImage.h>
+#include <Protocol/GuidedSectionExtraction.h>
+#include <Protocol/DevicePath.h>
+#include <Protocol/Runtime.h>
+#include <Protocol/LoadFile.h>
+#include <Protocol/LoadFile2.h>
+#include <Protocol/DriverBinding.h>
+#include <Protocol/VariableWrite.h>
+#include <Protocol/PlatformDriverOverride.h>
+#include <Protocol/Variable.h>
+#include <Protocol/Timer.h>
+#include <Protocol/SimpleFileSystem.h>
+#include <Protocol/Bds.h>
+#include <Protocol/RealTimeClock.h>
+#include <Protocol/WatchdogTimer.h>
+#include <Protocol/FirmwareVolume2.h>
+#include <Protocol/MonotonicCounter.h>
+#include <Protocol/StatusCode.h>
+#include <Protocol/Decompress.h>
+#include <Protocol/LoadPe32Image.h>
+#include <Protocol/Security.h>
+#include <Protocol/Security2.h>
+#include <Protocol/Reset.h>
+#include <Protocol/Cpu.h>
+#include <Protocol/Metronome.h>
+#include <Protocol/FirmwareVolumeBlock.h>
+#include <Protocol/Capsule.h>
+#include <Protocol/BusSpecificDriverOverride.h>
+#include <Protocol/DriverFamilyOverride.h>
+#include <Protocol/TcgService.h>
+#include <Protocol/HiiPackageList.h>
+#include <Protocol/SmmBase2.h>
+#include <Protocol/PeCoffImageEmulator.h>
+#include <Guid/MemoryTypeInformation.h>
+#include <Guid/FirmwareFileSystem2.h>
+#include <Guid/FirmwareFileSystem3.h>
+#include <Guid/HobList.h>
+#include <Guid/DebugImageInfoTable.h>
+#include <Guid/FileInfo.h>
+#include <Guid/Apriori.h>
+#include <Guid/DxeServices.h>
+#include <Guid/MemoryAllocationHob.h>
+#include <Guid/EventLegacyBios.h>
+#include <Guid/EventGroup.h>
+#include <Guid/EventExitBootServiceFailed.h>
+#include <Guid/LoadModuleAtFixedAddress.h>
+#include <Guid/IdleLoopEvent.h>
+#include <Guid/VectorHandoffTable.h>
+#include <Ppi/VectorHandoffInfo.h>
+#include <Guid/MemoryProfile.h>
+
+#include <Library/DxeCoreEntryPoint.h>
+#include <Library/DebugLib.h>
+#include <Library/UefiLib.h>
+#include <Library/BaseLib.h>
+#include <Library/HobLib.h>
+#include <Library/PerformanceLib.h>
+#include <Library/UefiDecompressLib.h>
+#include <Library/ExtractGuidedSectionLib.h>
+#include <Library/CacheMaintenanceLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/PeCoffLib.h>
+#include <Library/PeCoffGetEntryPointLib.h>
+#include <Library/PeCoffExtraActionLib.h>
+#include <Library/PcdLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/DevicePathLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/ReportStatusCodeLib.h>
+#include <Library/DxeServicesLib.h>
+#include <Library/DebugAgentLib.h>
+#include <Library/CpuExceptionHandlerLib.h>
+
+
+//
+// attributes for reserved memory before it is promoted to system memory
+//
+#define EFI_MEMORY_PRESENT 0x0100000000000000ULL
+#define EFI_MEMORY_INITIALIZED 0x0200000000000000ULL
+#define EFI_MEMORY_TESTED 0x0400000000000000ULL
+
+//
+// range for memory mapped port I/O on IPF
+//
+#define EFI_MEMORY_PORT_IO 0x4000000000000000ULL
+
+
+///
+/// EFI_DEP_REPLACE_TRUE - Used to dynamically patch the dependency expression
+/// to save time. A EFI_DEP_PUSH is evaluated one an
+/// replaced with EFI_DEP_REPLACE_TRUE. If PI spec's Vol 2
+/// Driver Execution Environment Core Interface use 0xff
+/// as new DEPEX opcode. EFI_DEP_REPLACE_TRUE should be
+/// defined to a new value that is not conflicting with PI spec.
+///
+#define EFI_DEP_REPLACE_TRUE 0xff
+
+///
+/// Define the initial size of the dependency expression evaluation stack
+///
+#define DEPEX_STACK_SIZE_INCREMENT 0x1000
+
+typedef struct {
+ EFI_GUID *ProtocolGuid;
+ VOID **Protocol;
+ EFI_EVENT Event;
+ VOID *Registration;
+ BOOLEAN Present;
+} EFI_CORE_PROTOCOL_NOTIFY_ENTRY;
+
+//
+// DXE Dispatcher Data structures
+//
+
+#define KNOWN_HANDLE_SIGNATURE SIGNATURE_32('k','n','o','w')
+typedef struct {
+ UINTN Signature;
+ LIST_ENTRY Link; // mFvHandleList
+ EFI_HANDLE Handle;
+ EFI_GUID FvNameGuid;
+} KNOWN_HANDLE;
+
+
+#define EFI_CORE_DRIVER_ENTRY_SIGNATURE SIGNATURE_32('d','r','v','r')
+typedef struct {
+ UINTN Signature;
+ LIST_ENTRY Link; // mDriverList
+
+ LIST_ENTRY ScheduledLink; // mScheduledQueue
+
+ EFI_HANDLE FvHandle;
+ EFI_GUID FileName;
+ EFI_DEVICE_PATH_PROTOCOL *FvFileDevicePath;
+ EFI_FIRMWARE_VOLUME2_PROTOCOL *Fv;
+
+ VOID *Depex;
+ UINTN DepexSize;
+
+ BOOLEAN Before;
+ BOOLEAN After;
+ EFI_GUID BeforeAfterGuid;
+
+ BOOLEAN Dependent;
+ BOOLEAN Unrequested;
+ BOOLEAN Scheduled;
+ BOOLEAN Untrusted;
+ BOOLEAN Initialized;
+ BOOLEAN DepexProtocolError;
+
+ EFI_HANDLE ImageHandle;
+ BOOLEAN IsFvImage;
+
+} EFI_CORE_DRIVER_ENTRY;
+
+//
+//The data structure of GCD memory map entry
+//
+#define EFI_GCD_MAP_SIGNATURE SIGNATURE_32('g','c','d','m')
+typedef struct {
+ UINTN Signature;
+ LIST_ENTRY Link;
+ EFI_PHYSICAL_ADDRESS BaseAddress;
+ UINT64 EndAddress;
+ UINT64 Capabilities;
+ UINT64 Attributes;
+ EFI_GCD_MEMORY_TYPE GcdMemoryType;
+ EFI_GCD_IO_TYPE GcdIoType;
+ EFI_HANDLE ImageHandle;
+ EFI_HANDLE DeviceHandle;
+} EFI_GCD_MAP_ENTRY;
+
+
+#define LOADED_IMAGE_PRIVATE_DATA_SIGNATURE SIGNATURE_32('l','d','r','i')
+
+typedef struct {
+ UINTN Signature;
+ /// Image handle
+ EFI_HANDLE Handle;
+ /// Image type
+ UINTN Type;
+ /// If entrypoint has been called
+ BOOLEAN Started;
+ /// The image's entry point
+ EFI_IMAGE_ENTRY_POINT EntryPoint;
+ /// loaded image protocol
+ EFI_LOADED_IMAGE_PROTOCOL Info;
+ /// Location in memory
+ EFI_PHYSICAL_ADDRESS ImageBasePage;
+ /// Number of pages
+ UINTN NumberOfPages;
+ /// Original fixup data
+ CHAR8 *FixupData;
+ /// Tpl of started image
+ EFI_TPL Tpl;
+ /// Status returned by started image
+ EFI_STATUS Status;
+ /// Size of ExitData from started image
+ UINTN ExitDataSize;
+ /// Pointer to exit data from started image
+ VOID *ExitData;
+ /// Pointer to pool allocation for context save/restore
+ VOID *JumpBuffer;
+ /// Pointer to buffer for context save/restore
+ BASE_LIBRARY_JUMP_BUFFER *JumpContext;
+ /// Machine type from PE image
+ UINT16 Machine;
+ /// PE/COFF Image Emulator Protocol pointer
+ EDKII_PECOFF_IMAGE_EMULATOR_PROTOCOL *PeCoffEmu;
+ /// Runtime image list
+ EFI_RUNTIME_IMAGE_ENTRY *RuntimeData;
+ /// Pointer to Loaded Image Device Path Protocol
+ EFI_DEVICE_PATH_PROTOCOL *LoadedImageDevicePath;
+ /// PeCoffLoader ImageContext
+ PE_COFF_LOADER_IMAGE_CONTEXT ImageContext;
+ /// Status returned by LoadImage() service.
+ EFI_STATUS LoadImageStatus;
+} LOADED_IMAGE_PRIVATE_DATA;
+
+#define LOADED_IMAGE_PRIVATE_DATA_FROM_THIS(a) \
+ CR(a, LOADED_IMAGE_PRIVATE_DATA, Info, LOADED_IMAGE_PRIVATE_DATA_SIGNATURE)
+
+#define IMAGE_PROPERTIES_RECORD_CODE_SECTION_SIGNATURE SIGNATURE_32 ('I','P','R','C')
+
+typedef struct {
+ UINT32 Signature;
+ LIST_ENTRY Link;
+ EFI_PHYSICAL_ADDRESS CodeSegmentBase;
+ UINT64 CodeSegmentSize;
+} IMAGE_PROPERTIES_RECORD_CODE_SECTION;
+
+#define IMAGE_PROPERTIES_RECORD_SIGNATURE SIGNATURE_32 ('I','P','R','D')
+
+typedef struct {
+ UINT32 Signature;
+ LIST_ENTRY Link;
+ EFI_PHYSICAL_ADDRESS ImageBase;
+ UINT64 ImageSize;
+ UINTN CodeSegmentCount;
+ LIST_ENTRY CodeSegmentList;
+} IMAGE_PROPERTIES_RECORD;
+
+//
+// DXE Core Global Variables
+//
+extern EFI_SYSTEM_TABLE *gDxeCoreST;
+extern EFI_RUNTIME_SERVICES *gDxeCoreRT;
+extern EFI_DXE_SERVICES *gDxeCoreDS;
+extern EFI_HANDLE gDxeCoreImageHandle;
+
+extern BOOLEAN gMemoryMapTerminated;
+
+extern EFI_DECOMPRESS_PROTOCOL gEfiDecompress;
+
+extern EFI_RUNTIME_ARCH_PROTOCOL *gRuntime;
+extern EFI_CPU_ARCH_PROTOCOL *gCpu;
+extern EFI_WATCHDOG_TIMER_ARCH_PROTOCOL *gWatchdogTimer;
+extern EFI_METRONOME_ARCH_PROTOCOL *gMetronome;
+extern EFI_TIMER_ARCH_PROTOCOL *gTimer;
+extern EFI_SECURITY_ARCH_PROTOCOL *gSecurity;
+extern EFI_SECURITY2_ARCH_PROTOCOL *gSecurity2;
+extern EFI_BDS_ARCH_PROTOCOL *gBds;
+extern EFI_SMM_BASE2_PROTOCOL *gSmmBase2;
+
+extern EFI_TPL gEfiCurrentTpl;
+
+extern EFI_GUID *gDxeCoreFileName;
+extern EFI_LOADED_IMAGE_PROTOCOL *gDxeCoreLoadedImage;
+
+extern EFI_MEMORY_TYPE_INFORMATION gMemoryTypeInformation[EfiMaxMemoryType + 1];
+
+extern BOOLEAN gDispatcherRunning;
+extern EFI_RUNTIME_ARCH_PROTOCOL gRuntimeTemplate;
+
+extern EFI_LOAD_FIXED_ADDRESS_CONFIGURATION_TABLE gLoadModuleAtFixAddressConfigurationTable;
+extern BOOLEAN gLoadFixedAddressCodeMemoryReady;
+//
+// Service Initialization Functions
+//
+
+
+
+/**
+ Called to initialize the pool.
+
+**/
+VOID
+CoreInitializePool (
+ VOID
+ );
+
+
+/**
+ Called to initialize the memory map and add descriptors to
+ the current descriptor list.
+ The first descriptor that is added must be general usable
+ memory as the addition allocates heap.
+
+ @param Type The type of memory to add
+ @param Start The starting address in the memory range Must be
+ page aligned
+ @param NumberOfPages The number of pages in the range
+ @param Attribute Attributes of the memory to add
+
+ @return None. The range is added to the memory map
+
+**/
+VOID
+CoreAddMemoryDescriptor (
+ IN EFI_MEMORY_TYPE Type,
+ IN EFI_PHYSICAL_ADDRESS Start,
+ IN UINT64 NumberOfPages,
+ IN UINT64 Attribute
+ );
+
+
+/**
+ Release memory lock on mGcdMemorySpaceLock.
+
+**/
+VOID
+CoreReleaseGcdMemoryLock (
+ VOID
+ );
+
+
+/**
+ Acquire memory lock on mGcdMemorySpaceLock.
+
+**/
+VOID
+CoreAcquireGcdMemoryLock (
+ VOID
+ );
+
+
+/**
+ External function. Initializes memory services based on the memory
+ descriptor HOBs. This function is responsible for priming the memory
+ map, so memory allocations and resource allocations can be made.
+ The first part of this function can not depend on any memory services
+ until at least one memory descriptor is provided to the memory services.
+
+ @param HobStart The start address of the HOB.
+ @param MemoryBaseAddress Start address of memory region found to init DXE
+ core.
+ @param MemoryLength Length of memory region found to init DXE core.
+
+ @retval EFI_SUCCESS Memory services successfully initialized.
+
+**/
+EFI_STATUS
+CoreInitializeMemoryServices (
+ IN VOID **HobStart,
+ OUT EFI_PHYSICAL_ADDRESS *MemoryBaseAddress,
+ OUT UINT64 *MemoryLength
+ );
+
+
+
+/**
+ External function. Initializes the GCD and memory services based on the memory
+ descriptor HOBs. This function is responsible for priming the GCD map and the
+ memory map, so memory allocations and resource allocations can be made. The
+ HobStart will be relocated to a pool buffer.
+
+ @param HobStart The start address of the HOB
+ @param MemoryBaseAddress Start address of memory region found to init DXE
+ core.
+ @param MemoryLength Length of memory region found to init DXE core.
+
+ @retval EFI_SUCCESS GCD services successfully initialized.
+
+**/
+EFI_STATUS
+CoreInitializeGcdServices (
+ IN OUT VOID **HobStart,
+ IN EFI_PHYSICAL_ADDRESS MemoryBaseAddress,
+ IN UINT64 MemoryLength
+ );
+
+
+/**
+ Initializes "event" support.
+
+ @retval EFI_SUCCESS Always return success
+
+**/
+EFI_STATUS
+CoreInitializeEventServices (
+ VOID
+ );
+
+
+/**
+ Add the Image Services to EFI Boot Services Table and install the protocol
+ interfaces for this image.
+
+ @param HobStart The HOB to initialize
+
+ @return Status code.
+
+**/
+EFI_STATUS
+CoreInitializeImageServices (
+ IN VOID *HobStart
+ );
+
+
+/**
+ Creates an event that is fired everytime a Protocol of a specific type is installed.
+
+**/
+VOID
+CoreNotifyOnProtocolInstallation (
+ VOID
+ );
+
+
+/**
+ Return TRUE if all AP services are available.
+
+ @retval EFI_SUCCESS All AP services are available
+ @retval EFI_NOT_FOUND At least one AP service is not available
+
+**/
+EFI_STATUS
+CoreAllEfiServicesAvailable (
+ VOID
+ );
+
+
+/**
+ Calcualte the 32-bit CRC in a EFI table using the service provided by the
+ gRuntime service.
+
+ @param Hdr Pointer to an EFI standard header
+
+**/
+VOID
+CalculateEfiHdrCrc (
+ IN OUT EFI_TABLE_HEADER *Hdr
+ );
+
+
+/**
+ 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
+ );
+
+
+/**
+ Initialize the dispatcher. Initialize the notification function that runs when
+ an FV2 protocol is added to the system.
+
+**/
+VOID
+CoreInitializeDispatcher (
+ VOID
+ );
+
+
+/**
+ This is the POSTFIX version of the dependency evaluator. This code does
+ not need to handle Before or After, as it is not valid to call this
+ routine in this case. The SOR is just ignored and is a nop in the grammer.
+ POSTFIX means all the math is done on top of the stack.
+
+ @param DriverEntry DriverEntry element to update.
+
+ @retval TRUE If driver is ready to run.
+ @retval FALSE If driver is not ready to run or some fatal error
+ was found.
+
+**/
+BOOLEAN
+CoreIsSchedulable (
+ IN EFI_CORE_DRIVER_ENTRY *DriverEntry
+ );
+
+
+/**
+ Preprocess dependency expression and update DriverEntry to reflect the
+ state of Before, After, and SOR dependencies. If DriverEntry->Before
+ or DriverEntry->After is set it will never be cleared. If SOR is set
+ it will be cleared by CoreSchedule(), and then the driver can be
+ dispatched.
+
+ @param DriverEntry DriverEntry element to update .
+
+ @retval EFI_SUCCESS It always works.
+
+**/
+EFI_STATUS
+CorePreProcessDepex (
+ IN EFI_CORE_DRIVER_ENTRY *DriverEntry
+ );
+
+
+
+/**
+ Terminates all boot services.
+
+ @param ImageHandle Handle that identifies the exiting image.
+ @param MapKey Key to the latest memory map.
+
+ @retval EFI_SUCCESS Boot Services terminated
+ @retval EFI_INVALID_PARAMETER MapKey is incorrect.
+
+**/
+EFI_STATUS
+EFIAPI
+CoreExitBootServices (
+ IN EFI_HANDLE ImageHandle,
+ IN UINTN MapKey
+ );
+
+
+/**
+ Make sure the memory map is following all the construction rules,
+ it is the last time to check memory map error before exit boot services.
+
+ @param MapKey Memory map key
+
+ @retval EFI_INVALID_PARAMETER Memory map not consistent with construction
+ rules.
+ @retval EFI_SUCCESS Valid memory map.
+
+**/
+EFI_STATUS
+CoreTerminateMemoryMap (
+ IN UINTN MapKey
+ );
+
+
+/**
+ Signals all events in the EventGroup.
+
+ @param EventGroup The list to signal
+
+**/
+VOID
+CoreNotifySignalList (
+ IN EFI_GUID *EventGroup
+ );
+
+
+
+/**
+ Boot Service called to add, modify, or remove a system configuration table from
+ the EFI System Table.
+
+ @param Guid Pointer to the GUID for the entry to add, update, or
+ remove
+ @param Table Pointer to the configuration table for the entry to add,
+ update, or remove, may be NULL.
+
+ @return EFI_SUCCESS Guid, Table pair added, updated, or removed.
+ @return EFI_INVALID_PARAMETER Input GUID not valid.
+ @return EFI_NOT_FOUND Attempted to delete non-existant entry
+ @return EFI_OUT_OF_RESOURCES Not enough memory available
+
+**/
+EFI_STATUS
+EFIAPI
+CoreInstallConfigurationTable (
+ IN EFI_GUID *Guid,
+ IN VOID *Table
+ );
+
+
+
+/**
+ 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
+ );
+
+
+
+/**
+ 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
+ );
+
+
+
+/**
+ Introduces a fine-grained stall.
+
+ @param Microseconds The number of microseconds to stall execution.
+
+ @retval EFI_SUCCESS Execution was stalled for at least the requested
+ amount of microseconds.
+ @retval EFI_NOT_AVAILABLE_YET gMetronome is not available yet
+
+**/
+EFI_STATUS
+EFIAPI
+CoreStall (
+ IN UINTN Microseconds
+ );
+
+
+
+/**
+ Sets the system's watchdog timer.
+
+ @param Timeout The number of seconds to set the watchdog timer to.
+ A value of zero disables the timer.
+ @param WatchdogCode The numeric code to log on a watchdog timer timeout
+ event. The firmware reserves codes 0x0000 to 0xFFFF.
+ Loaders and operating systems may use other timeout
+ codes.
+ @param DataSize The size, in bytes, of WatchdogData.
+ @param WatchdogData A data buffer that includes a Null-terminated Unicode
+ string, optionally followed by additional binary data.
+ The string is a description that the call may use to
+ further indicate the reason to be logged with a
+ watchdog event.
+
+ @return EFI_SUCCESS Timeout has been set
+ @return EFI_NOT_AVAILABLE_YET WatchdogTimer is not available yet
+ @return EFI_UNSUPPORTED System does not have a timer (currently not used)
+ @return EFI_DEVICE_ERROR Could not complete due to hardware error
+
+**/
+EFI_STATUS
+EFIAPI
+CoreSetWatchdogTimer (
+ IN UINTN Timeout,
+ IN UINT64 WatchdogCode,
+ IN UINTN DataSize,
+ IN CHAR16 *WatchdogData OPTIONAL
+ );
+
+
+
+/**
+ Wrapper function to CoreInstallProtocolInterfaceNotify. This is the public API which
+ Calls the private one which contains a BOOLEAN parameter for notifications
+
+ @param UserHandle The handle to install the protocol handler on,
+ or NULL if a new handle is to be allocated
+ @param Protocol The protocol to add to the handle
+ @param InterfaceType Indicates whether Interface is supplied in
+ native form.
+ @param Interface The interface for the protocol being added
+
+ @return Status code
+
+**/
+EFI_STATUS
+EFIAPI
+CoreInstallProtocolInterface (
+ IN OUT EFI_HANDLE *UserHandle,
+ IN EFI_GUID *Protocol,
+ IN EFI_INTERFACE_TYPE InterfaceType,
+ IN VOID *Interface
+ );
+
+
+/**
+ Installs a protocol interface into the boot services environment.
+
+ @param UserHandle The handle to install the protocol handler on,
+ or NULL if a new handle is to be allocated
+ @param Protocol The protocol to add to the handle
+ @param InterfaceType Indicates whether Interface is supplied in
+ native form.
+ @param Interface The interface for the protocol being added
+ @param Notify indicates whether notify the notification list
+ for this protocol
+
+ @retval EFI_INVALID_PARAMETER Invalid parameter
+ @retval EFI_OUT_OF_RESOURCES No enough buffer to allocate
+ @retval EFI_SUCCESS Protocol interface successfully installed
+
+**/
+EFI_STATUS
+CoreInstallProtocolInterfaceNotify (
+ IN OUT EFI_HANDLE *UserHandle,
+ IN EFI_GUID *Protocol,
+ IN EFI_INTERFACE_TYPE InterfaceType,
+ IN VOID *Interface,
+ IN BOOLEAN Notify
+ );
+
+
+
+/**
+ Installs a list of protocol interface into the boot services environment.
+ This function calls InstallProtocolInterface() in a loop. If any error
+ occures all the protocols added by this function are removed. This is
+ basically a lib function to save space.
+
+ @param Handle The handle to install the protocol handlers on,
+ or NULL if a new handle is to be allocated
+ @param ... EFI_GUID followed by protocol instance. A NULL
+ terminates the list. The pairs are the
+ arguments to InstallProtocolInterface(). All the
+ protocols are added to Handle.
+
+ @retval EFI_SUCCESS All the protocol interface was installed.
+ @retval EFI_OUT_OF_RESOURCES There was not enough memory in pool to install all the protocols.
+ @retval EFI_ALREADY_STARTED A Device Path Protocol instance was passed in that is already present in
+ the handle database.
+ @retval EFI_INVALID_PARAMETER Handle is NULL.
+ @retval EFI_INVALID_PARAMETER Protocol is already installed on the handle specified by Handle.
+
+**/
+EFI_STATUS
+EFIAPI
+CoreInstallMultipleProtocolInterfaces (
+ IN OUT EFI_HANDLE *Handle,
+ ...
+ );
+
+
+
+/**
+ Uninstalls a list of protocol interface in the boot services environment.
+ This function calls UnisatllProtocolInterface() in a loop. This is
+ basically a lib function to save space.
+
+ @param Handle The handle to uninstall the protocol
+ @param ... EFI_GUID followed by protocol instance. A NULL
+ terminates the list. The pairs are the
+ arguments to UninstallProtocolInterface(). All
+ the protocols are added to Handle.
+
+ @return Status code
+
+**/
+EFI_STATUS
+EFIAPI
+CoreUninstallMultipleProtocolInterfaces (
+ IN EFI_HANDLE Handle,
+ ...
+ );
+
+
+
+/**
+ Reinstall a protocol interface on a device handle. The OldInterface for Protocol is replaced by the NewInterface.
+
+ @param UserHandle Handle on which the interface is to be
+ reinstalled
+ @param Protocol The numeric ID of the interface
+ @param OldInterface A pointer to the old interface
+ @param NewInterface A pointer to the new interface
+
+ @retval EFI_SUCCESS The protocol interface was installed
+ @retval EFI_NOT_FOUND The OldInterface on the handle was not found
+ @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value
+
+**/
+EFI_STATUS
+EFIAPI
+CoreReinstallProtocolInterface (
+ IN EFI_HANDLE UserHandle,
+ IN EFI_GUID *Protocol,
+ IN VOID *OldInterface,
+ IN VOID *NewInterface
+ );
+
+
+
+/**
+ Uninstalls all instances of a protocol:interfacer from a handle.
+ If the last protocol interface is remove from the handle, the
+ handle is freed.
+
+ @param UserHandle The handle to remove the protocol handler from
+ @param Protocol The protocol, of protocol:interface, to remove
+ @param Interface The interface, of protocol:interface, to remove
+
+ @retval EFI_INVALID_PARAMETER Protocol is NULL.
+ @retval EFI_SUCCESS Protocol interface successfully uninstalled.
+
+**/
+EFI_STATUS
+EFIAPI
+CoreUninstallProtocolInterface (
+ IN EFI_HANDLE UserHandle,
+ IN EFI_GUID *Protocol,
+ IN VOID *Interface
+ );
+
+
+
+/**
+ Queries a handle to determine if it supports a specified protocol.
+
+ @param UserHandle The handle being queried.
+ @param Protocol The published unique identifier of the protocol.
+ @param Interface Supplies the address where a pointer to the
+ corresponding Protocol Interface is returned.
+
+ @return The requested protocol interface for the handle
+
+**/
+EFI_STATUS
+EFIAPI
+CoreHandleProtocol (
+ IN EFI_HANDLE UserHandle,
+ IN EFI_GUID *Protocol,
+ OUT VOID **Interface
+ );
+
+
+
+/**
+ Locates the installed protocol handler for the handle, and
+ invokes it to obtain the protocol interface. Usage information
+ is registered in the protocol data base.
+
+ @param UserHandle The handle to obtain the protocol interface on
+ @param Protocol The ID of the protocol
+ @param Interface The location to return the protocol interface
+ @param ImageHandle The handle of the Image that is opening the
+ protocol interface specified by Protocol and
+ Interface.
+ @param ControllerHandle The controller handle that is requiring this
+ interface.
+ @param Attributes The open mode of the protocol interface
+ specified by Handle and Protocol.
+
+ @retval EFI_INVALID_PARAMETER Protocol is NULL.
+ @retval EFI_SUCCESS Get the protocol interface.
+
+**/
+EFI_STATUS
+EFIAPI
+CoreOpenProtocol (
+ IN EFI_HANDLE UserHandle,
+ IN EFI_GUID *Protocol,
+ OUT VOID **Interface OPTIONAL,
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_HANDLE ControllerHandle,
+ IN UINT32 Attributes
+ );
+
+
+
+/**
+ Return information about Opened protocols in the system
+
+ @param UserHandle The handle to close the protocol interface on
+ @param Protocol The ID of the protocol
+ @param EntryBuffer A pointer to a buffer of open protocol
+ information in the form of
+ EFI_OPEN_PROTOCOL_INFORMATION_ENTRY structures.
+ @param EntryCount Number of EntryBuffer entries
+
+**/
+EFI_STATUS
+EFIAPI
+CoreOpenProtocolInformation (
+ IN EFI_HANDLE UserHandle,
+ IN EFI_GUID *Protocol,
+ OUT EFI_OPEN_PROTOCOL_INFORMATION_ENTRY **EntryBuffer,
+ OUT UINTN *EntryCount
+ );
+
+
+
+/**
+ Closes a protocol on a handle that was opened using OpenProtocol().
+
+ @param UserHandle The handle for the protocol interface that was
+ previously opened with OpenProtocol(), and is
+ now being closed.
+ @param Protocol The published unique identifier of the protocol.
+ It is the caller's responsibility to pass in a
+ valid GUID.
+ @param AgentHandle The handle of the agent that is closing the
+ protocol interface.
+ @param ControllerHandle If the agent that opened a protocol is a driver
+ that follows the EFI Driver Model, then this
+ parameter is the controller handle that required
+ the protocol interface. If the agent does not
+ follow the EFI Driver Model, then this parameter
+ is optional and may be NULL.
+
+ @retval EFI_SUCCESS The protocol instance was closed.
+ @retval EFI_INVALID_PARAMETER Handle, AgentHandle or ControllerHandle is not a
+ valid EFI_HANDLE.
+ @retval EFI_NOT_FOUND Can not find the specified protocol or
+ AgentHandle.
+
+**/
+EFI_STATUS
+EFIAPI
+CoreCloseProtocol (
+ IN EFI_HANDLE UserHandle,
+ IN EFI_GUID *Protocol,
+ IN EFI_HANDLE AgentHandle,
+ IN EFI_HANDLE ControllerHandle
+ );
+
+
+
+/**
+ Retrieves the list of protocol interface GUIDs that are installed on a handle in a buffer allocated
+ from pool.
+
+ @param UserHandle The handle from which to retrieve the list of
+ protocol interface GUIDs.
+ @param ProtocolBuffer A pointer to the list of protocol interface GUID
+ pointers that are installed on Handle.
+ @param ProtocolBufferCount A pointer to the number of GUID pointers present
+ in ProtocolBuffer.
+
+ @retval EFI_SUCCESS The list of protocol interface GUIDs installed
+ on Handle was returned in ProtocolBuffer. The
+ number of protocol interface GUIDs was returned
+ in ProtocolBufferCount.
+ @retval EFI_INVALID_PARAMETER Handle is NULL.
+ @retval EFI_INVALID_PARAMETER Handle is not a valid EFI_HANDLE.
+ @retval EFI_INVALID_PARAMETER ProtocolBuffer is NULL.
+ @retval EFI_INVALID_PARAMETER ProtocolBufferCount is NULL.
+ @retval EFI_OUT_OF_RESOURCES There is not enough pool memory to store the
+ results.
+
+**/
+EFI_STATUS
+EFIAPI
+CoreProtocolsPerHandle (
+ IN EFI_HANDLE UserHandle,
+ OUT EFI_GUID ***ProtocolBuffer,
+ OUT UINTN *ProtocolBufferCount
+ );
+
+
+
+/**
+ Add a new protocol notification record for the request protocol.
+
+ @param Protocol The requested protocol to add the notify
+ registration
+ @param Event The event to signal
+ @param Registration Returns the registration record
+
+ @retval EFI_INVALID_PARAMETER Invalid parameter
+ @retval EFI_SUCCESS Successfully returned the registration record
+ that has been added
+
+**/
+EFI_STATUS
+EFIAPI
+CoreRegisterProtocolNotify (
+ IN EFI_GUID *Protocol,
+ IN EFI_EVENT Event,
+ OUT VOID **Registration
+ );
+
+
+/**
+ Removes all the events in the protocol database that match Event.
+
+ @param Event The event to search for in the protocol
+ database.
+
+ @return EFI_SUCCESS when done searching the entire database.
+
+**/
+EFI_STATUS
+CoreUnregisterProtocolNotify (
+ IN EFI_EVENT Event
+ );
+
+
+/**
+ Locates the requested handle(s) and returns them in Buffer.
+
+ @param SearchType The type of search to perform to locate the
+ handles
+ @param Protocol The protocol to search for
+ @param SearchKey Dependant on SearchType
+ @param BufferSize On input the size of Buffer. On output the
+ size of data returned.
+ @param Buffer The buffer to return the results in
+
+ @retval EFI_BUFFER_TOO_SMALL Buffer too small, required buffer size is
+ returned in BufferSize.
+ @retval EFI_INVALID_PARAMETER Invalid parameter
+ @retval EFI_SUCCESS Successfully found the requested handle(s) and
+ returns them in Buffer.
+
+**/
+EFI_STATUS
+EFIAPI
+CoreLocateHandle (
+ IN EFI_LOCATE_SEARCH_TYPE SearchType,
+ IN EFI_GUID *Protocol OPTIONAL,
+ IN VOID *SearchKey OPTIONAL,
+ IN OUT UINTN *BufferSize,
+ OUT EFI_HANDLE *Buffer
+ );
+
+
+
+/**
+ Locates the handle to a device on the device path that best matches the specified protocol.
+
+ @param Protocol The protocol to search for.
+ @param DevicePath On input, a pointer to a pointer to the device
+ path. On output, the device path pointer is
+ modified to point to the remaining part of the
+ devicepath.
+ @param Device A pointer to the returned device handle.
+
+ @retval EFI_SUCCESS The resulting handle was returned.
+ @retval EFI_NOT_FOUND No handles matched the search.
+ @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
+
+**/
+EFI_STATUS
+EFIAPI
+CoreLocateDevicePath (
+ IN EFI_GUID *Protocol,
+ IN OUT EFI_DEVICE_PATH_PROTOCOL **DevicePath,
+ OUT EFI_HANDLE *Device
+ );
+
+
+
+/**
+ Function returns an array of handles that support the requested protocol
+ in a buffer allocated from pool. This is a version of CoreLocateHandle()
+ that allocates a buffer for the caller.
+
+ @param SearchType Specifies which handle(s) are to be returned.
+ @param Protocol Provides the protocol to search by. This
+ parameter is only valid for SearchType
+ ByProtocol.
+ @param SearchKey Supplies the search key depending on the
+ SearchType.
+ @param NumberHandles The number of handles returned in Buffer.
+ @param Buffer A pointer to the buffer to return the requested
+ array of handles that support Protocol.
+
+ @retval EFI_SUCCESS The result array of handles was returned.
+ @retval EFI_NOT_FOUND No handles match the search.
+ @retval EFI_OUT_OF_RESOURCES There is not enough pool memory to store the
+ matching results.
+ @retval EFI_INVALID_PARAMETER One or more parameters are not valid.
+
+**/
+EFI_STATUS
+EFIAPI
+CoreLocateHandleBuffer (
+ IN EFI_LOCATE_SEARCH_TYPE SearchType,
+ IN EFI_GUID *Protocol OPTIONAL,
+ IN VOID *SearchKey OPTIONAL,
+ IN OUT UINTN *NumberHandles,
+ OUT EFI_HANDLE **Buffer
+ );
+
+
+
+/**
+ Return the first Protocol Interface that matches the Protocol GUID. If
+ Registration is passed in, return a Protocol Instance that was just add
+ to the system. If Registration is NULL return the first Protocol Interface
+ you find.
+
+ @param Protocol The protocol to search for
+ @param Registration Optional Registration Key returned from
+ RegisterProtocolNotify()
+ @param Interface Return the Protocol interface (instance).
+
+ @retval EFI_SUCCESS If a valid Interface is returned
+ @retval EFI_INVALID_PARAMETER Invalid parameter
+ @retval EFI_NOT_FOUND Protocol interface not found
+
+**/
+EFI_STATUS
+EFIAPI
+CoreLocateProtocol (
+ IN EFI_GUID *Protocol,
+ IN VOID *Registration OPTIONAL,
+ OUT VOID **Interface
+ );
+
+
+/**
+ return handle database key.
+
+
+ @return Handle database key.
+
+**/
+UINT64
+CoreGetHandleDatabaseKey (
+ VOID
+ );
+
+
+/**
+ Go connect any handles that were created or modified while a image executed.
+
+ @param Key The Key to show that the handle has been
+ created/modified
+
+**/
+VOID
+CoreConnectHandlesByKey (
+ UINT64 Key
+ );
+
+
+
+/**
+ Connects one or more drivers to a controller.
+
+ @param ControllerHandle The handle of the controller to which driver(s) are to be connected.
+ @param DriverImageHandle A pointer to an ordered list handles that support the
+ EFI_DRIVER_BINDING_PROTOCOL.
+ @param RemainingDevicePath A pointer to the device path that specifies a child of the
+ controller specified by ControllerHandle.
+ @param Recursive If TRUE, then ConnectController() is called recursively
+ until the entire tree of controllers below the controller specified
+ by ControllerHandle have been created. If FALSE, then
+ the tree of controllers is only expanded one level.
+
+ @retval EFI_SUCCESS 1) One or more drivers were connected to ControllerHandle.
+ 2) No drivers were connected to ControllerHandle, but
+ RemainingDevicePath is not NULL, and it is an End Device
+ Path Node.
+ @retval EFI_INVALID_PARAMETER ControllerHandle is NULL.
+ @retval EFI_NOT_FOUND 1) There are no EFI_DRIVER_BINDING_PROTOCOL instances
+ present in the system.
+ 2) No drivers were connected to ControllerHandle.
+ @retval EFI_SECURITY_VIOLATION
+ The user has no permission to start UEFI device drivers on the device path
+ associated with the ControllerHandle or specified by the RemainingDevicePath.
+
+**/
+EFI_STATUS
+EFIAPI
+CoreConnectController (
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_HANDLE *DriverImageHandle OPTIONAL,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL,
+ IN BOOLEAN Recursive
+ );
+
+
+
+/**
+ Disonnects a controller from a driver
+
+ @param ControllerHandle ControllerHandle The handle of
+ the controller from which
+ driver(s) are to be
+ disconnected.
+ @param DriverImageHandle DriverImageHandle The driver to
+ disconnect from ControllerHandle.
+ @param ChildHandle ChildHandle The handle of the
+ child to destroy.
+
+ @retval EFI_SUCCESS One or more drivers were
+ disconnected from the controller.
+ @retval EFI_SUCCESS On entry, no drivers are managing
+ ControllerHandle.
+ @retval EFI_SUCCESS DriverImageHandle is not NULL,
+ and on entry DriverImageHandle is
+ not managing ControllerHandle.
+ @retval EFI_INVALID_PARAMETER ControllerHandle is NULL.
+ @retval EFI_INVALID_PARAMETER DriverImageHandle is not NULL,
+ and it is not a valid EFI_HANDLE.
+ @retval EFI_INVALID_PARAMETER ChildHandle is not NULL, and it
+ is not a valid EFI_HANDLE.
+ @retval EFI_OUT_OF_RESOURCES There are not enough resources
+ available to disconnect any
+ drivers from ControllerHandle.
+ @retval EFI_DEVICE_ERROR The controller could not be
+ disconnected because of a device
+ error.
+
+**/
+EFI_STATUS
+EFIAPI
+CoreDisconnectController (
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_HANDLE DriverImageHandle OPTIONAL,
+ IN EFI_HANDLE ChildHandle OPTIONAL
+ );
+
+
+
+/**
+ Allocates pages from the memory map.
+
+ @param Type The type of allocation to perform
+ @param MemoryType The type of memory to turn the allocated pages
+ into
+ @param NumberOfPages The number of pages to allocate
+ @param Memory A pointer to receive the base allocated memory
+ address
+
+ @return Status. On success, Memory is filled in with the base address allocated
+ @retval EFI_INVALID_PARAMETER Parameters violate checking rules defined in
+ spec.
+ @retval EFI_NOT_FOUND Could not allocate pages match the requirement.
+ @retval EFI_OUT_OF_RESOURCES No enough pages to allocate.
+ @retval EFI_SUCCESS Pages successfully allocated.
+
+**/
+EFI_STATUS
+EFIAPI
+CoreAllocatePages (
+ IN EFI_ALLOCATE_TYPE Type,
+ IN EFI_MEMORY_TYPE MemoryType,
+ IN UINTN NumberOfPages,
+ IN OUT EFI_PHYSICAL_ADDRESS *Memory
+ );
+
+/**
+ Frees previous allocated pages.
+
+ @param Memory Base address of memory being freed
+ @param NumberOfPages The number of pages to free
+
+ @retval EFI_NOT_FOUND Could not find the entry that covers the range
+ @retval EFI_INVALID_PARAMETER Address not aligned
+ @return EFI_SUCCESS -Pages successfully freed.
+
+**/
+EFI_STATUS
+EFIAPI
+CoreFreePages (
+ IN EFI_PHYSICAL_ADDRESS Memory,
+ IN UINTN NumberOfPages
+ );
+
+/**
+ This function returns a copy of the current memory map. The map is an array of
+ memory descriptors, each of which describes a contiguous block of memory.
+
+ @param MemoryMapSize A pointer to the size, in bytes, of the
+ MemoryMap buffer. On input, this is the size of
+ the buffer allocated by the caller. On output,
+ it is the size of the buffer returned by the
+ firmware if the buffer was large enough, or the
+ size of the buffer needed to contain the map if
+ the buffer was too small.
+ @param MemoryMap A pointer to the buffer in which firmware places
+ the current memory map.
+ @param MapKey A pointer to the location in which firmware
+ returns the key for the current memory map.
+ @param DescriptorSize A pointer to the location in which firmware
+ returns the size, in bytes, of an individual
+ EFI_MEMORY_DESCRIPTOR.
+ @param DescriptorVersion A pointer to the location in which firmware
+ returns the version number associated with the
+ EFI_MEMORY_DESCRIPTOR.
+
+ @retval EFI_SUCCESS The memory map was returned in the MemoryMap
+ buffer.
+ @retval EFI_BUFFER_TOO_SMALL The MemoryMap buffer was too small. The current
+ buffer size needed to hold the memory map is
+ returned in MemoryMapSize.
+ @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
+
+**/
+EFI_STATUS
+EFIAPI
+CoreGetMemoryMap (
+ IN OUT UINTN *MemoryMapSize,
+ IN OUT EFI_MEMORY_DESCRIPTOR *MemoryMap,
+ OUT UINTN *MapKey,
+ OUT UINTN *DescriptorSize,
+ OUT UINT32 *DescriptorVersion
+ );
+
+
+
+/**
+ Allocate pool of a particular type.
+
+ @param PoolType Type of pool to allocate
+ @param Size The amount of pool to allocate
+ @param Buffer The address to return a pointer to the allocated
+ pool
+
+ @retval EFI_INVALID_PARAMETER PoolType not valid or Buffer is NULL
+ @retval EFI_OUT_OF_RESOURCES Size exceeds max pool size or allocation failed.
+ @retval EFI_SUCCESS Pool successfully allocated.
+
+**/
+EFI_STATUS
+EFIAPI
+CoreAllocatePool (
+ IN EFI_MEMORY_TYPE PoolType,
+ IN UINTN Size,
+ OUT VOID **Buffer
+ );
+
+/**
+ Allocate pool of a particular type.
+
+ @param PoolType Type of pool to allocate
+ @param Size The amount of pool to allocate
+ @param Buffer The address to return a pointer to the allocated
+ pool
+
+ @retval EFI_INVALID_PARAMETER PoolType not valid or Buffer is NULL
+ @retval EFI_OUT_OF_RESOURCES Size exceeds max pool size or allocation failed.
+ @retval EFI_SUCCESS Pool successfully allocated.
+
+**/
+EFI_STATUS
+EFIAPI
+CoreInternalAllocatePool (
+ IN EFI_MEMORY_TYPE PoolType,
+ IN UINTN Size,
+ OUT VOID **Buffer
+ );
+
+/**
+ Frees pool.
+
+ @param Buffer The allocated pool entry to free
+
+ @retval EFI_INVALID_PARAMETER Buffer is not a valid value.
+ @retval EFI_SUCCESS Pool successfully freed.
+
+**/
+EFI_STATUS
+EFIAPI
+CoreFreePool (
+ IN VOID *Buffer
+ );
+
+/**
+ Frees pool.
+
+ @param Buffer The allocated pool entry to free
+ @param PoolType Pointer to pool type
+
+ @retval EFI_INVALID_PARAMETER Buffer is not a valid value.
+ @retval EFI_SUCCESS Pool successfully freed.
+
+**/
+EFI_STATUS
+EFIAPI
+CoreInternalFreePool (
+ IN VOID *Buffer,
+ OUT EFI_MEMORY_TYPE *PoolType OPTIONAL
+ );
+
+/**
+ Loads an EFI image into memory and returns a handle to the image.
+
+ @param BootPolicy If TRUE, indicates that the request originates
+ from the boot manager, and that the boot
+ manager is attempting to load FilePath as a
+ boot selection.
+ @param ParentImageHandle The caller's image handle.
+ @param FilePath The specific file path from which the image is
+ loaded.
+ @param SourceBuffer If not NULL, a pointer to the memory location
+ containing a copy of the image to be loaded.
+ @param SourceSize The size in bytes of SourceBuffer.
+ @param ImageHandle Pointer to the returned image handle that is
+ created when the image is successfully loaded.
+
+ @retval EFI_SUCCESS The image was loaded into memory.
+ @retval EFI_NOT_FOUND The FilePath was not found.
+ @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
+ @retval EFI_UNSUPPORTED The image type is not supported, or the device
+ path cannot be parsed to locate the proper
+ protocol for loading the file.
+ @retval EFI_OUT_OF_RESOURCES Image was not loaded due to insufficient
+ resources.
+ @retval EFI_LOAD_ERROR Image was not loaded because the image format was corrupt or not
+ understood.
+ @retval EFI_DEVICE_ERROR Image was not loaded because the device returned a read error.
+ @retval EFI_ACCESS_DENIED Image was not loaded because the platform policy prohibits the
+ image from being loaded. NULL is returned in *ImageHandle.
+ @retval EFI_SECURITY_VIOLATION Image was loaded and an ImageHandle was created with a
+ valid EFI_LOADED_IMAGE_PROTOCOL. However, the current
+ platform policy specifies that the image should not be started.
+
+**/
+EFI_STATUS
+EFIAPI
+CoreLoadImage (
+ IN BOOLEAN BootPolicy,
+ IN EFI_HANDLE ParentImageHandle,
+ IN EFI_DEVICE_PATH_PROTOCOL *FilePath,
+ IN VOID *SourceBuffer OPTIONAL,
+ IN UINTN SourceSize,
+ OUT EFI_HANDLE *ImageHandle
+ );
+
+
+
+/**
+ Unloads an image.
+
+ @param ImageHandle Handle that identifies the image to be
+ unloaded.
+
+ @retval EFI_SUCCESS The image has been unloaded.
+ @retval EFI_UNSUPPORTED The image has been started, and does not support
+ unload.
+ @retval EFI_INVALID_PARAMPETER ImageHandle is not a valid image handle.
+
+**/
+EFI_STATUS
+EFIAPI
+CoreUnloadImage (
+ IN EFI_HANDLE ImageHandle
+ );
+
+
+
+/**
+ Transfer control to a loaded image's entry point.
+
+ @param ImageHandle Handle of image to be started.
+ @param ExitDataSize Pointer of the size to ExitData
+ @param ExitData Pointer to a pointer to a data buffer that
+ includes a Null-terminated string,
+ optionally followed by additional binary data.
+ The string is a description that the caller may
+ use to further indicate the reason for the
+ image's exit.
+
+ @retval EFI_INVALID_PARAMETER Invalid parameter
+ @retval EFI_OUT_OF_RESOURCES No enough buffer to allocate
+ @retval EFI_SECURITY_VIOLATION The current platform policy specifies that the image should not be started.
+ @retval EFI_SUCCESS Successfully transfer control to the image's
+ entry point.
+
+**/
+EFI_STATUS
+EFIAPI
+CoreStartImage (
+ IN EFI_HANDLE ImageHandle,
+ OUT UINTN *ExitDataSize,
+ OUT CHAR16 **ExitData OPTIONAL
+ );
+
+
+
+/**
+ Terminates the currently loaded EFI image and returns control to boot services.
+
+ @param ImageHandle Handle that identifies the image. This
+ parameter is passed to the image on entry.
+ @param Status The image's exit code.
+ @param ExitDataSize The size, in bytes, of ExitData. Ignored if
+ ExitStatus is EFI_SUCCESS.
+ @param ExitData Pointer to a data buffer that includes a
+ Null-terminated Unicode string, optionally
+ followed by additional binary data. The string
+ is a description that the caller may use to
+ further indicate the reason for the image's
+ exit.
+
+ @retval EFI_INVALID_PARAMETER Image handle is NULL or it is not current
+ image.
+ @retval EFI_SUCCESS Successfully terminates the currently loaded
+ EFI image.
+ @retval EFI_ACCESS_DENIED Should never reach there.
+ @retval EFI_OUT_OF_RESOURCES Could not allocate pool
+
+**/
+EFI_STATUS
+EFIAPI
+CoreExit (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_STATUS Status,
+ IN UINTN ExitDataSize,
+ IN CHAR16 *ExitData OPTIONAL
+ );
+
+
+
+/**
+ 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
+ );
+
+
+
+/**
+ 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
+ );
+
+/**
+ 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
+ );
+
+/**
+ 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
+ );
+
+
+
+/**
+ 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
+ );
+
+
+
+/**
+ 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
+ );
+
+
+
+/**
+ 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
+ );
+
+
+
+/**
+ 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
+ );
+
+
+/**
+ Adds reserved memory, system memory, or memory-mapped I/O resources to the
+ global coherency domain of the processor.
+
+ @param GcdMemoryType Memory type of the memory space.
+ @param BaseAddress Base address of the memory space.
+ @param Length Length of the memory space.
+ @param Capabilities alterable attributes of the memory space.
+
+ @retval EFI_SUCCESS Merged this memory space into GCD map.
+
+**/
+EFI_STATUS
+EFIAPI
+CoreAddMemorySpace (
+ IN EFI_GCD_MEMORY_TYPE GcdMemoryType,
+ IN EFI_PHYSICAL_ADDRESS BaseAddress,
+ IN UINT64 Length,
+ IN UINT64 Capabilities
+ );
+
+
+/**
+ Allocates nonexistent memory, reserved memory, system memory, or memorymapped
+ I/O resources from the global coherency domain of the processor.
+
+ @param GcdAllocateType The type of allocate operation
+ @param GcdMemoryType The desired memory type
+ @param Alignment Align with 2^Alignment
+ @param Length Length to allocate
+ @param BaseAddress Base address to allocate
+ @param ImageHandle The image handle consume the allocated space.
+ @param DeviceHandle The device handle consume the allocated space.
+
+ @retval EFI_INVALID_PARAMETER Invalid parameter.
+ @retval EFI_NOT_FOUND No descriptor contains the desired space.
+ @retval EFI_SUCCESS Memory space successfully allocated.
+
+**/
+EFI_STATUS
+EFIAPI
+CoreAllocateMemorySpace (
+ IN EFI_GCD_ALLOCATE_TYPE GcdAllocateType,
+ IN EFI_GCD_MEMORY_TYPE GcdMemoryType,
+ IN UINTN Alignment,
+ IN UINT64 Length,
+ IN OUT EFI_PHYSICAL_ADDRESS *BaseAddress,
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_HANDLE DeviceHandle OPTIONAL
+ );
+
+
+/**
+ Frees nonexistent memory, reserved memory, system memory, or memory-mapped
+ I/O resources from the global coherency domain of the processor.
+
+ @param BaseAddress Base address of the memory space.
+ @param Length Length of the memory space.
+
+ @retval EFI_SUCCESS Space successfully freed.
+
+**/
+EFI_STATUS
+EFIAPI
+CoreFreeMemorySpace (
+ IN EFI_PHYSICAL_ADDRESS BaseAddress,
+ IN UINT64 Length
+ );
+
+
+/**
+ Removes reserved memory, system memory, or memory-mapped I/O resources from
+ the global coherency domain of the processor.
+
+ @param BaseAddress Base address of the memory space.
+ @param Length Length of the memory space.
+
+ @retval EFI_SUCCESS Successfully remove a segment of memory space.
+
+**/
+EFI_STATUS
+EFIAPI
+CoreRemoveMemorySpace (
+ IN EFI_PHYSICAL_ADDRESS BaseAddress,
+ IN UINT64 Length
+ );
+
+
+/**
+ Retrieves the descriptor for a memory region containing a specified address.
+
+ @param BaseAddress Specified start address
+ @param Descriptor Specified length
+
+ @retval EFI_INVALID_PARAMETER Invalid parameter
+ @retval EFI_SUCCESS Successfully get memory space descriptor.
+
+**/
+EFI_STATUS
+EFIAPI
+CoreGetMemorySpaceDescriptor (
+ IN EFI_PHYSICAL_ADDRESS BaseAddress,
+ OUT EFI_GCD_MEMORY_SPACE_DESCRIPTOR *Descriptor
+ );
+
+
+/**
+ Modifies the attributes for a memory region in the global coherency domain of the
+ processor.
+
+ @param BaseAddress Specified start address
+ @param Length Specified length
+ @param Attributes Specified attributes
+
+ @retval EFI_SUCCESS The attributes were set for the memory region.
+ @retval EFI_INVALID_PARAMETER Length is zero.
+ @retval EFI_UNSUPPORTED The processor does not support one or more bytes of the memory
+ resource range specified by BaseAddress and Length.
+ @retval EFI_UNSUPPORTED The bit mask of attributes is not support for the memory resource
+ range specified by BaseAddress and Length.
+ @retval EFI_ACCESS_DENIED The attributes for the memory resource range specified by
+ BaseAddress and Length cannot be modified.
+ @retval EFI_OUT_OF_RESOURCES There are not enough system resources to modify the attributes of
+ the memory resource range.
+ @retval EFI_NOT_AVAILABLE_YET The attributes cannot be set because CPU architectural protocol is
+ not available yet.
+
+**/
+EFI_STATUS
+EFIAPI
+CoreSetMemorySpaceAttributes (
+ IN EFI_PHYSICAL_ADDRESS BaseAddress,
+ IN UINT64 Length,
+ IN UINT64 Attributes
+ );
+
+
+/**
+ Modifies the capabilities for a memory region in the global coherency domain of the
+ processor.
+
+ @param BaseAddress The physical address that is the start address of a memory region.
+ @param Length The size in bytes of the memory region.
+ @param Capabilities The bit mask of capabilities that the memory region supports.
+
+ @retval EFI_SUCCESS The capabilities were set for the memory region.
+ @retval EFI_INVALID_PARAMETER Length is zero.
+ @retval EFI_UNSUPPORTED The capabilities specified by Capabilities do not include the
+ memory region attributes currently in use.
+ @retval EFI_ACCESS_DENIED The capabilities for the memory resource range specified by
+ BaseAddress and Length cannot be modified.
+ @retval EFI_OUT_OF_RESOURCES There are not enough system resources to modify the capabilities
+ of the memory resource range.
+**/
+EFI_STATUS
+EFIAPI
+CoreSetMemorySpaceCapabilities (
+ IN EFI_PHYSICAL_ADDRESS BaseAddress,
+ IN UINT64 Length,
+ IN UINT64 Capabilities
+ );
+
+
+/**
+ Returns a map of the memory resources in the global coherency domain of the
+ processor.
+
+ @param NumberOfDescriptors Number of descriptors.
+ @param MemorySpaceMap Descriptor array
+
+ @retval EFI_INVALID_PARAMETER Invalid parameter
+ @retval EFI_OUT_OF_RESOURCES No enough buffer to allocate
+ @retval EFI_SUCCESS Successfully get memory space map.
+
+**/
+EFI_STATUS
+EFIAPI
+CoreGetMemorySpaceMap (
+ OUT UINTN *NumberOfDescriptors,
+ OUT EFI_GCD_MEMORY_SPACE_DESCRIPTOR **MemorySpaceMap
+ );
+
+
+/**
+ Adds reserved I/O or I/O resources to the global coherency domain of the processor.
+
+ @param GcdIoType IO type of the segment.
+ @param BaseAddress Base address of the segment.
+ @param Length Length of the segment.
+
+ @retval EFI_SUCCESS Merged this segment into GCD map.
+ @retval EFI_INVALID_PARAMETER Parameter not valid
+
+**/
+EFI_STATUS
+EFIAPI
+CoreAddIoSpace (
+ IN EFI_GCD_IO_TYPE GcdIoType,
+ IN EFI_PHYSICAL_ADDRESS BaseAddress,
+ IN UINT64 Length
+ );
+
+
+/**
+ Allocates nonexistent I/O, reserved I/O, or I/O resources from the global coherency
+ domain of the processor.
+
+ @param GcdAllocateType The type of allocate operation
+ @param GcdIoType The desired IO type
+ @param Alignment Align with 2^Alignment
+ @param Length Length to allocate
+ @param BaseAddress Base address to allocate
+ @param ImageHandle The image handle consume the allocated space.
+ @param DeviceHandle The device handle consume the allocated space.
+
+ @retval EFI_INVALID_PARAMETER Invalid parameter.
+ @retval EFI_NOT_FOUND No descriptor contains the desired space.
+ @retval EFI_SUCCESS IO space successfully allocated.
+
+**/
+EFI_STATUS
+EFIAPI
+CoreAllocateIoSpace (
+ IN EFI_GCD_ALLOCATE_TYPE GcdAllocateType,
+ IN EFI_GCD_IO_TYPE GcdIoType,
+ IN UINTN Alignment,
+ IN UINT64 Length,
+ IN OUT EFI_PHYSICAL_ADDRESS *BaseAddress,
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_HANDLE DeviceHandle OPTIONAL
+ );
+
+
+/**
+ Frees nonexistent I/O, reserved I/O, or I/O resources from the global coherency
+ domain of the processor.
+
+ @param BaseAddress Base address of the segment.
+ @param Length Length of the segment.
+
+ @retval EFI_SUCCESS Space successfully freed.
+
+**/
+EFI_STATUS
+EFIAPI
+CoreFreeIoSpace (
+ IN EFI_PHYSICAL_ADDRESS BaseAddress,
+ IN UINT64 Length
+ );
+
+
+/**
+ Removes reserved I/O or I/O resources from the global coherency domain of the
+ processor.
+
+ @param BaseAddress Base address of the segment.
+ @param Length Length of the segment.
+
+ @retval EFI_SUCCESS Successfully removed a segment of IO space.
+
+**/
+EFI_STATUS
+EFIAPI
+CoreRemoveIoSpace (
+ IN EFI_PHYSICAL_ADDRESS BaseAddress,
+ IN UINT64 Length
+ );
+
+
+/**
+ Retrieves the descriptor for an I/O region containing a specified address.
+
+ @param BaseAddress Specified start address
+ @param Descriptor Specified length
+
+ @retval EFI_INVALID_PARAMETER Descriptor is NULL.
+ @retval EFI_SUCCESS Successfully get the IO space descriptor.
+
+**/
+EFI_STATUS
+EFIAPI
+CoreGetIoSpaceDescriptor (
+ IN EFI_PHYSICAL_ADDRESS BaseAddress,
+ OUT EFI_GCD_IO_SPACE_DESCRIPTOR *Descriptor
+ );
+
+
+/**
+ Returns a map of the I/O resources in the global coherency domain of the processor.
+
+ @param NumberOfDescriptors Number of descriptors.
+ @param IoSpaceMap Descriptor array
+
+ @retval EFI_INVALID_PARAMETER Invalid parameter
+ @retval EFI_OUT_OF_RESOURCES No enough buffer to allocate
+ @retval EFI_SUCCESS Successfully get IO space map.
+
+**/
+EFI_STATUS
+EFIAPI
+CoreGetIoSpaceMap (
+ OUT UINTN *NumberOfDescriptors,
+ OUT EFI_GCD_IO_SPACE_DESCRIPTOR **IoSpaceMap
+ );
+
+
+/**
+ This is the main Dispatcher for DXE and it exits when there are no more
+ drivers to run. Drain the mScheduledQueue and load and start a PE
+ image for each driver. Search the mDiscoveredList to see if any driver can
+ be placed on the mScheduledQueue. If no drivers are placed on the
+ mScheduledQueue exit the function. On exit it is assumed the Bds()
+ will be called, and when the Bds() exits the Dispatcher will be called
+ again.
+
+ @retval EFI_ALREADY_STARTED The DXE Dispatcher is already running
+ @retval EFI_NOT_FOUND No DXE Drivers were dispatched
+ @retval EFI_SUCCESS One or more DXE Drivers were dispatched
+
+**/
+EFI_STATUS
+EFIAPI
+CoreDispatcher (
+ VOID
+ );
+
+/**
+ Check every driver and locate a matching one. If the driver is found, the Unrequested
+ state flag is cleared.
+
+ @param FirmwareVolumeHandle The handle of the Firmware Volume that contains
+ the firmware file specified by DriverName.
+ @param DriverName The Driver name to put in the Dependent state.
+
+ @retval EFI_SUCCESS The DriverName was found and it's SOR bit was
+ cleared
+ @retval EFI_NOT_FOUND The DriverName does not exist or it's SOR bit was
+ not set.
+
+**/
+EFI_STATUS
+EFIAPI
+CoreSchedule (
+ IN EFI_HANDLE FirmwareVolumeHandle,
+ IN EFI_GUID *DriverName
+ );
+
+
+/**
+ Convert a driver from the Untrused back to the Scheduled state.
+
+ @param FirmwareVolumeHandle The handle of the Firmware Volume that contains
+ the firmware file specified by DriverName.
+ @param DriverName The Driver name to put in the Scheduled state
+
+ @retval EFI_SUCCESS The file was found in the untrusted state, and it
+ was promoted to the trusted state.
+ @retval EFI_NOT_FOUND The file was not found in the untrusted state.
+
+**/
+EFI_STATUS
+EFIAPI
+CoreTrust (
+ IN EFI_HANDLE FirmwareVolumeHandle,
+ IN EFI_GUID *DriverName
+ );
+
+
+/**
+ This routine is the driver initialization entry point. It initializes the
+ libraries, and registers two notification functions. These notification
+ functions are responsible for building the FV stack dynamically.
+
+ @param ImageHandle The image handle.
+ @param SystemTable The system table.
+
+ @retval EFI_SUCCESS Function successfully returned.
+
+**/
+EFI_STATUS
+EFIAPI
+FwVolDriverInit (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ );
+
+
+/**
+ Entry point of the section extraction code. Initializes an instance of the
+ section extraction interface and installs it on a new handle.
+
+ @param ImageHandle A handle for the image that is initializing this driver
+ @param SystemTable A pointer to the EFI system table
+
+ @retval EFI_SUCCESS Driver initialized successfully
+ @retval EFI_OUT_OF_RESOURCES Could not allocate needed resources
+
+**/
+EFI_STATUS
+EFIAPI
+InitializeSectionExtraction (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ );
+
+
+/**
+ This DXE service routine is used to process a firmware volume. In
+ particular, it can be called by BDS to process a single firmware
+ volume found in a capsule.
+
+ @param FvHeader pointer to a firmware volume header
+ @param Size the size of the buffer pointed to by FvHeader
+ @param FVProtocolHandle the handle on which a firmware volume protocol
+ was produced for the firmware volume passed in.
+
+ @retval EFI_OUT_OF_RESOURCES if an FVB could not be produced due to lack of
+ system resources
+ @retval EFI_VOLUME_CORRUPTED if the volume was corrupted
+ @retval EFI_SUCCESS a firmware volume protocol was produced for the
+ firmware volume
+
+**/
+EFI_STATUS
+EFIAPI
+CoreProcessFirmwareVolume (
+ IN VOID *FvHeader,
+ IN UINTN Size,
+ OUT EFI_HANDLE *FVProtocolHandle
+ );
+
+//
+//Functions used during debug buils
+//
+
+/**
+ Displays Architectural protocols that were not loaded and are required for DXE
+ core to function. Only used in Debug Builds.
+
+**/
+VOID
+CoreDisplayMissingArchProtocols (
+ VOID
+ );
+
+
+/**
+ Traverse the discovered list for any drivers that were discovered but not loaded
+ because the dependency experessions evaluated to false.
+
+**/
+VOID
+CoreDisplayDiscoveredNotDispatched (
+ VOID
+ );
+
+
+
+/**
+ Place holder function until all the Boot Services and Runtime Services are
+ available.
+
+ @param Arg1 Undefined
+
+ @return EFI_NOT_AVAILABLE_YET
+
+**/
+EFI_STATUS
+EFIAPI
+CoreEfiNotAvailableYetArg1 (
+ UINTN Arg1
+ );
+
+
+/**
+ Place holder function until all the Boot Services and Runtime Services are available.
+
+ @param Arg1 Undefined
+ @param Arg2 Undefined
+
+ @return EFI_NOT_AVAILABLE_YET
+
+**/
+EFI_STATUS
+EFIAPI
+CoreEfiNotAvailableYetArg2 (
+ UINTN Arg1,
+ UINTN Arg2
+ );
+
+
+/**
+ Place holder function until all the Boot Services and Runtime Services are available.
+
+ @param Arg1 Undefined
+ @param Arg2 Undefined
+ @param Arg3 Undefined
+
+ @return EFI_NOT_AVAILABLE_YET
+
+**/
+EFI_STATUS
+EFIAPI
+CoreEfiNotAvailableYetArg3 (
+ UINTN Arg1,
+ UINTN Arg2,
+ UINTN Arg3
+ );
+
+
+/**
+ Place holder function until all the Boot Services and Runtime Services are available.
+
+ @param Arg1 Undefined
+ @param Arg2 Undefined
+ @param Arg3 Undefined
+ @param Arg4 Undefined
+
+ @return EFI_NOT_AVAILABLE_YET
+
+**/
+EFI_STATUS
+EFIAPI
+CoreEfiNotAvailableYetArg4 (
+ UINTN Arg1,
+ UINTN Arg2,
+ UINTN Arg3,
+ UINTN Arg4
+ );
+
+
+/**
+ Place holder function until all the Boot Services and Runtime Services are available.
+
+ @param Arg1 Undefined
+ @param Arg2 Undefined
+ @param Arg3 Undefined
+ @param Arg4 Undefined
+ @param Arg5 Undefined
+
+ @return EFI_NOT_AVAILABLE_YET
+
+**/
+EFI_STATUS
+EFIAPI
+CoreEfiNotAvailableYetArg5 (
+ UINTN Arg1,
+ UINTN Arg2,
+ UINTN Arg3,
+ UINTN Arg4,
+ UINTN Arg5
+ );
+
+
+/**
+ Given a compressed source buffer, this function retrieves the size of the
+ uncompressed buffer and the size of the scratch buffer required to decompress
+ the compressed source buffer.
+
+ The GetInfo() function retrieves the size of the uncompressed buffer and the
+ temporary scratch buffer required to decompress the buffer specified by Source
+ and SourceSize. If the size of the uncompressed buffer or the size of the
+ scratch buffer cannot be determined from the compressed data specified by
+ Source and SourceData, then EFI_INVALID_PARAMETER is returned. Otherwise, the
+ size of the uncompressed buffer is returned in DestinationSize, the size of
+ the scratch buffer is returned in ScratchSize, and EFI_SUCCESS is returned.
+ The GetInfo() function does not have scratch buffer available to perform a
+ thorough checking of the validity of the source data. It just retrieves the
+ "Original Size" field from the beginning bytes of the source data and output
+ it as DestinationSize. And ScratchSize is specific to the decompression
+ implementation.
+
+ @param This A pointer to the EFI_DECOMPRESS_PROTOCOL instance.
+ @param Source The source buffer containing the compressed data.
+ @param SourceSize The size, in bytes, of the source buffer.
+ @param DestinationSize A pointer to the size, in bytes, of the
+ uncompressed buffer that will be generated when the
+ compressed buffer specified by Source and
+ SourceSize is decompressed.
+ @param ScratchSize A pointer to the size, in bytes, of the scratch
+ buffer that is required to decompress the
+ compressed buffer specified by Source and
+ SourceSize.
+
+ @retval EFI_SUCCESS The size of the uncompressed data was returned in
+ DestinationSize and the size of the scratch buffer
+ was returned in ScratchSize.
+ @retval EFI_INVALID_PARAMETER The size of the uncompressed data or the size of
+ the scratch buffer cannot be determined from the
+ compressed data specified by Source and
+ SourceSize.
+
+**/
+EFI_STATUS
+EFIAPI
+DxeMainUefiDecompressGetInfo (
+ IN EFI_DECOMPRESS_PROTOCOL *This,
+ IN VOID *Source,
+ IN UINT32 SourceSize,
+ OUT UINT32 *DestinationSize,
+ OUT UINT32 *ScratchSize
+ );
+
+
+/**
+ Decompresses a compressed source buffer.
+
+ The Decompress() function extracts decompressed data to its original form.
+ This protocol is designed so that the decompression algorithm can be
+ implemented without using any memory services. As a result, the Decompress()
+ Function is not allowed to call AllocatePool() or AllocatePages() in its
+ implementation. It is the caller's responsibility to allocate and free the
+ Destination and Scratch buffers.
+ If the compressed source data specified by Source and SourceSize is
+ sucessfully decompressed into Destination, then EFI_SUCCESS is returned. If
+ the compressed source data specified by Source and SourceSize is not in a
+ valid compressed data format, then EFI_INVALID_PARAMETER is returned.
+
+ @param This A pointer to the EFI_DECOMPRESS_PROTOCOL instance.
+ @param Source The source buffer containing the compressed data.
+ @param SourceSize SourceSizeThe size of source data.
+ @param Destination On output, the destination buffer that contains
+ the uncompressed data.
+ @param DestinationSize The size of the destination buffer. The size of
+ the destination buffer needed is obtained from
+ EFI_DECOMPRESS_PROTOCOL.GetInfo().
+ @param Scratch A temporary scratch buffer that is used to perform
+ the decompression.
+ @param ScratchSize The size of scratch buffer. The size of the
+ scratch buffer needed is obtained from GetInfo().
+
+ @retval EFI_SUCCESS Decompression completed successfully, and the
+ uncompressed buffer is returned in Destination.
+ @retval EFI_INVALID_PARAMETER The source buffer specified by Source and
+ SourceSize is corrupted (not in a valid
+ compressed format).
+
+**/
+EFI_STATUS
+EFIAPI
+DxeMainUefiDecompress (
+ IN EFI_DECOMPRESS_PROTOCOL *This,
+ IN VOID *Source,
+ IN UINT32 SourceSize,
+ IN OUT VOID *Destination,
+ IN UINT32 DestinationSize,
+ IN OUT VOID *Scratch,
+ IN UINT32 ScratchSize
+ );
+
+/**
+ SEP member function. This function creates and returns a new section stream
+ handle to represent the new section stream.
+
+ @param SectionStreamLength Size in bytes of the section stream.
+ @param SectionStream Buffer containing the new section stream.
+ @param SectionStreamHandle A pointer to a caller allocated UINTN that on
+ output contains the new section stream handle.
+
+ @retval EFI_SUCCESS The section stream is created successfully.
+ @retval EFI_OUT_OF_RESOURCES memory allocation failed.
+ @retval EFI_INVALID_PARAMETER Section stream does not end concident with end
+ of last section.
+
+**/
+EFI_STATUS
+EFIAPI
+OpenSectionStream (
+ IN UINTN SectionStreamLength,
+ IN VOID *SectionStream,
+ OUT UINTN *SectionStreamHandle
+ );
+
+
+
+/**
+ SEP member function. Retrieves requested section from section stream.
+
+ @param SectionStreamHandle The section stream from which to extract the
+ requested section.
+ @param SectionType A pointer to the type of section to search for.
+ @param SectionDefinitionGuid If the section type is EFI_SECTION_GUID_DEFINED,
+ then SectionDefinitionGuid indicates which of
+ these types of sections to search for.
+ @param SectionInstance Indicates which instance of the requested
+ section to return.
+ @param Buffer Double indirection to buffer. If *Buffer is
+ non-null on input, then the buffer is caller
+ allocated. If Buffer is NULL, then the buffer
+ is callee allocated. In either case, the
+ required buffer size is returned in *BufferSize.
+ @param BufferSize On input, indicates the size of *Buffer if
+ *Buffer is non-null on input. On output,
+ indicates the required size (allocated size if
+ callee allocated) of *Buffer.
+ @param AuthenticationStatus A pointer to a caller-allocated UINT32 that
+ indicates the authentication status of the
+ output buffer. If the input section's
+ GuidedSectionHeader.Attributes field
+ has the EFI_GUIDED_SECTION_AUTH_STATUS_VALID
+ bit as clear, AuthenticationStatus must return
+ zero. Both local bits (19:16) and aggregate
+ bits (3:0) in AuthenticationStatus are returned
+ by ExtractSection(). These bits reflect the
+ status of the extraction operation. The bit
+ pattern in both regions must be the same, as
+ the local and aggregate authentication statuses
+ have equivalent meaning at this level. If the
+ function returns anything other than
+ EFI_SUCCESS, the value of *AuthenticationStatus
+ is undefined.
+ @param IsFfs3Fv Indicates the FV format.
+
+ @retval EFI_SUCCESS Section was retrieved successfully
+ @retval EFI_PROTOCOL_ERROR A GUID defined section was encountered in the
+ section stream with its
+ EFI_GUIDED_SECTION_PROCESSING_REQUIRED bit set,
+ but there was no corresponding GUIDed Section
+ Extraction Protocol in the handle database.
+ *Buffer is unmodified.
+ @retval EFI_NOT_FOUND An error was encountered when parsing the
+ SectionStream. This indicates the SectionStream
+ is not correctly formatted.
+ @retval EFI_NOT_FOUND The requested section does not exist.
+ @retval EFI_OUT_OF_RESOURCES The system has insufficient resources to process
+ the request.
+ @retval EFI_INVALID_PARAMETER The SectionStreamHandle does not exist.
+ @retval EFI_WARN_TOO_SMALL The size of the caller allocated input buffer is
+ insufficient to contain the requested section.
+ The input buffer is filled and section contents
+ are truncated.
+
+**/
+EFI_STATUS
+EFIAPI
+GetSection (
+ IN UINTN SectionStreamHandle,
+ IN EFI_SECTION_TYPE *SectionType,
+ IN EFI_GUID *SectionDefinitionGuid,
+ IN UINTN SectionInstance,
+ IN VOID **Buffer,
+ IN OUT UINTN *BufferSize,
+ OUT UINT32 *AuthenticationStatus,
+ IN BOOLEAN IsFfs3Fv
+ );
+
+
+/**
+ SEP member function. Deletes an existing section stream
+
+ @param StreamHandleToClose Indicates the stream to close
+ @param FreeStreamBuffer TRUE - Need to free stream buffer;
+ FALSE - No need to free stream buffer.
+
+ @retval EFI_SUCCESS The section stream is closed sucessfully.
+ @retval EFI_OUT_OF_RESOURCES Memory allocation failed.
+ @retval EFI_INVALID_PARAMETER Section stream does not end concident with end
+ of last section.
+
+**/
+EFI_STATUS
+EFIAPI
+CloseSectionStream (
+ IN UINTN StreamHandleToClose,
+ IN BOOLEAN FreeStreamBuffer
+ );
+
+/**
+ Creates and initializes the DebugImageInfo Table. Also creates the configuration
+ table and registers it into the system table.
+
+ Note:
+ This function allocates memory, frees it, and then allocates memory at an
+ address within the initial allocation. Since this function is called early
+ in DXE core initialization (before drivers are dispatched), this should not
+ be a problem.
+
+**/
+VOID
+CoreInitializeDebugImageInfoTable (
+ VOID
+ );
+
+
+/**
+ Update the CRC32 in the Debug Table.
+ Since the CRC32 service is made available by the Runtime driver, we have to
+ wait for the Runtime Driver to be installed before the CRC32 can be computed.
+ This function is called elsewhere by the core when the runtime architectural
+ protocol is produced.
+
+**/
+VOID
+CoreUpdateDebugTableCrc32 (
+ VOID
+ );
+
+
+/**
+ Adds a new DebugImageInfo structure to the DebugImageInfo Table. Re-Allocates
+ the table if it's not large enough to accomidate another entry.
+
+ @param ImageInfoType type of debug image information
+ @param LoadedImage pointer to the loaded image protocol for the image being
+ loaded
+ @param ImageHandle image handle for the image being loaded
+
+**/
+VOID
+CoreNewDebugImageInfoEntry (
+ IN UINT32 ImageInfoType,
+ IN EFI_LOADED_IMAGE_PROTOCOL *LoadedImage,
+ IN EFI_HANDLE ImageHandle
+ );
+
+
+/**
+ Removes and frees an entry from the DebugImageInfo Table.
+
+ @param ImageHandle image handle for the image being unloaded
+
+**/
+VOID
+CoreRemoveDebugImageInfoEntry (
+ EFI_HANDLE ImageHandle
+ );
+
+
+/**
+ This routine consumes FV hobs and produces instances of FW_VOL_BLOCK_PROTOCOL as appropriate.
+
+ @param ImageHandle The image handle.
+ @param SystemTable The system table.
+
+ @retval EFI_SUCCESS Successfully initialized firmware volume block
+ driver.
+
+**/
+EFI_STATUS
+EFIAPI
+FwVolBlockDriverInit (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ );
+
+/**
+
+ Get FVB authentication status
+
+ @param FvbProtocol FVB protocol.
+
+ @return Authentication status.
+
+**/
+UINT32
+GetFvbAuthenticationStatus (
+ IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *FvbProtocol
+ );
+
+/**
+ This routine produces a firmware volume block protocol on a given
+ buffer.
+
+ @param BaseAddress base address of the firmware volume image
+ @param Length length of the firmware volume image
+ @param ParentHandle handle of parent firmware volume, if this image
+ came from an FV image file and section in another firmware
+ volume (ala capsules)
+ @param AuthenticationStatus Authentication status inherited, if this image
+ came from an FV image file and section in another firmware volume.
+ @param FvProtocol Firmware volume block protocol produced.
+
+ @retval EFI_VOLUME_CORRUPTED Volume corrupted.
+ @retval EFI_OUT_OF_RESOURCES No enough buffer to be allocated.
+ @retval EFI_SUCCESS Successfully produced a FVB protocol on given
+ buffer.
+
+**/
+EFI_STATUS
+ProduceFVBProtocolOnBuffer (
+ IN EFI_PHYSICAL_ADDRESS BaseAddress,
+ IN UINT64 Length,
+ IN EFI_HANDLE ParentHandle,
+ IN UINT32 AuthenticationStatus,
+ OUT EFI_HANDLE *FvProtocol OPTIONAL
+ );
+
+
+/**
+ Raising to the task priority level of the mutual exclusion
+ lock, and then acquires ownership of the lock.
+
+ @param Lock The lock to acquire
+
+ @return Lock owned
+
+**/
+VOID
+CoreAcquireLock (
+ IN EFI_LOCK *Lock
+ );
+
+
+/**
+ Initialize a basic mutual exclusion lock. Each lock
+ provides mutual exclusion access at it's task priority
+ level. Since there is no-premption (at any TPL) or
+ multiprocessor support, acquiring the lock only consists
+ of raising to the locks TPL.
+
+ @param Lock The EFI_LOCK structure to initialize
+
+ @retval EFI_SUCCESS Lock Owned.
+ @retval EFI_ACCESS_DENIED Reentrant Lock Acquisition, Lock not Owned.
+
+**/
+EFI_STATUS
+CoreAcquireLockOrFail (
+ IN EFI_LOCK *Lock
+ );
+
+
+/**
+ Releases ownership of the mutual exclusion lock, and
+ restores the previous task priority level.
+
+ @param Lock The lock to release
+
+ @return Lock unowned
+
+**/
+VOID
+CoreReleaseLock (
+ IN EFI_LOCK *Lock
+ );
+
+/**
+ Read data from Firmware Block by FVB protocol Read.
+ The data may cross the multi block ranges.
+
+ @param Fvb The FW_VOL_BLOCK_PROTOCOL instance from which to read data.
+ @param StartLba Pointer to StartLba.
+ On input, the start logical block index from which to read.
+ On output,the end logical block index after reading.
+ @param Offset Pointer to Offset
+ On input, offset into the block at which to begin reading.
+ On output, offset into the end block after reading.
+ @param DataSize Size of data to be read.
+ @param Data Pointer to Buffer that the data will be read into.
+
+ @retval EFI_SUCCESS Successfully read data from firmware block.
+ @retval others
+**/
+EFI_STATUS
+ReadFvbData (
+ IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb,
+ IN OUT EFI_LBA *StartLba,
+ IN OUT UINTN *Offset,
+ IN UINTN DataSize,
+ OUT UINT8 *Data
+ );
+
+/**
+ Given the supplied FW_VOL_BLOCK_PROTOCOL, allocate a buffer for output and
+ copy the real length volume header into it.
+
+ @param Fvb The FW_VOL_BLOCK_PROTOCOL instance from which to
+ read the volume header
+ @param FwVolHeader Pointer to pointer to allocated buffer in which
+ the volume header is returned.
+
+ @retval EFI_OUT_OF_RESOURCES No enough buffer could be allocated.
+ @retval EFI_SUCCESS Successfully read volume header to the allocated
+ buffer.
+ @retval EFI_INVALID_PARAMETER The FV Header signature is not as expected or
+ the file system could not be understood.
+
+**/
+EFI_STATUS
+GetFwVolHeader (
+ IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb,
+ OUT EFI_FIRMWARE_VOLUME_HEADER **FwVolHeader
+ );
+
+/**
+ Verify checksum of the firmware volume header.
+
+ @param FvHeader Points to the firmware volume header to be checked
+
+ @retval TRUE Checksum verification passed
+ @retval FALSE Checksum verification failed
+
+**/
+BOOLEAN
+VerifyFvHeaderChecksum (
+ IN EFI_FIRMWARE_VOLUME_HEADER *FvHeader
+ );
+
+/**
+ Initialize memory profile.
+
+ @param HobStart The start address of the HOB.
+
+**/
+VOID
+MemoryProfileInit (
+ IN VOID *HobStart
+ );
+
+/**
+ Install memory profile protocol.
+
+**/
+VOID
+MemoryProfileInstallProtocol (
+ VOID
+ );
+
+/**
+ Register image to memory profile.
+
+ @param DriverEntry Image info.
+ @param FileType Image file type.
+
+ @return EFI_SUCCESS Register successfully.
+ @return EFI_UNSUPPORTED Memory profile unsupported,
+ or memory profile for the image is not required.
+ @return EFI_OUT_OF_RESOURCES No enough resource for this register.
+
+**/
+EFI_STATUS
+RegisterMemoryProfileImage (
+ IN LOADED_IMAGE_PRIVATE_DATA *DriverEntry,
+ IN EFI_FV_FILETYPE FileType
+ );
+
+/**
+ Unregister image from memory profile.
+
+ @param DriverEntry Image info.
+
+ @return EFI_SUCCESS Unregister successfully.
+ @return EFI_UNSUPPORTED Memory profile unsupported,
+ or memory profile for the image is not required.
+ @return EFI_NOT_FOUND The image is not found.
+
+**/
+EFI_STATUS
+UnregisterMemoryProfileImage (
+ IN LOADED_IMAGE_PRIVATE_DATA *DriverEntry
+ );
+
+/**
+ Update memory profile information.
+
+ @param CallerAddress Address of caller who call Allocate or Free.
+ @param Action This Allocate or Free action.
+ @param MemoryType Memory type.
+ EfiMaxMemoryType means the MemoryType is unknown.
+ @param Size Buffer size.
+ @param Buffer Buffer address.
+ @param ActionString String for memory profile action.
+ Only needed for user defined allocate action.
+
+ @return EFI_SUCCESS Memory profile is updated.
+ @return EFI_UNSUPPORTED Memory profile is unsupported,
+ or memory profile for the image is not required,
+ or memory profile for the memory type is not required.
+ @return EFI_ACCESS_DENIED It is during memory profile data getting.
+ @return EFI_ABORTED Memory profile recording is not enabled.
+ @return EFI_OUT_OF_RESOURCES No enough resource to update memory profile for allocate action.
+ @return EFI_NOT_FOUND No matched allocate info found for free action.
+
+**/
+EFI_STATUS
+EFIAPI
+CoreUpdateProfile (
+ IN EFI_PHYSICAL_ADDRESS CallerAddress,
+ IN MEMORY_PROFILE_ACTION Action,
+ IN EFI_MEMORY_TYPE MemoryType,
+ IN UINTN Size, // Valid for AllocatePages/FreePages/AllocatePool
+ IN VOID *Buffer,
+ IN CHAR8 *ActionString OPTIONAL
+ );
+
+/**
+ Internal function. Converts a memory range to use new attributes.
+
+ @param Start The first address of the range Must be page
+ aligned
+ @param NumberOfPages The number of pages to convert
+ @param NewAttributes The new attributes value for the range.
+
+**/
+VOID
+CoreUpdateMemoryAttributes (
+ IN EFI_PHYSICAL_ADDRESS Start,
+ IN UINT64 NumberOfPages,
+ IN UINT64 NewAttributes
+ );
+
+/**
+ Initialize MemoryAttrubutesTable support.
+**/
+VOID
+EFIAPI
+CoreInitializeMemoryAttributesTable (
+ VOID
+ );
+
+/**
+ Initialize Memory Protection support.
+**/
+VOID
+EFIAPI
+CoreInitializeMemoryProtection (
+ VOID
+ );
+
+/**
+ Install MemoryAttributesTable on memory allocation.
+
+ @param[in] MemoryType EFI memory type.
+**/
+VOID
+InstallMemoryAttributesTableOnMemoryAllocation (
+ IN EFI_MEMORY_TYPE MemoryType
+ );
+
+/**
+ Insert image record.
+
+ @param RuntimeImage Runtime image information
+**/
+VOID
+InsertImageRecord (
+ IN EFI_RUNTIME_IMAGE_ENTRY *RuntimeImage
+ );
+
+/**
+ Remove Image record.
+
+ @param RuntimeImage Runtime image information
+**/
+VOID
+RemoveImageRecord (
+ IN EFI_RUNTIME_IMAGE_ENTRY *RuntimeImage
+ );
+
+/**
+ Protect UEFI image.
+
+ @param[in] LoadedImage The loaded image protocol
+ @param[in] LoadedImageDevicePath The loaded image device path protocol
+**/
+VOID
+ProtectUefiImage (
+ IN EFI_LOADED_IMAGE_PROTOCOL *LoadedImage,
+ IN EFI_DEVICE_PATH_PROTOCOL *LoadedImageDevicePath
+ );
+
+/**
+ Unprotect UEFI image.
+
+ @param[in] LoadedImage The loaded image protocol
+ @param[in] LoadedImageDevicePath The loaded image device path protocol
+**/
+VOID
+UnprotectUefiImage (
+ IN EFI_LOADED_IMAGE_PROTOCOL *LoadedImage,
+ IN EFI_DEVICE_PATH_PROTOCOL *LoadedImageDevicePath
+ );
+
+/**
+ ExitBootServices Callback function for memory protection.
+**/
+VOID
+MemoryProtectionExitBootServicesCallback (
+ VOID
+ );
+
+/**
+ Manage memory permission attributes on a memory range, according to the
+ configured DXE memory protection policy.
+
+ @param OldType The old memory type of the range
+ @param NewType The new memory type of the range
+ @param Memory The base address of the range
+ @param Length The size of the range (in bytes)
+
+ @return EFI_SUCCESS If the the CPU arch protocol is not installed yet
+ @return EFI_SUCCESS If no DXE memory protection policy has been configured
+ @return EFI_SUCCESS If OldType and NewType use the same permission attributes
+ @return other Return value of gCpu->SetMemoryAttributes()
+
+**/
+EFI_STATUS
+EFIAPI
+ApplyMemoryProtectionPolicy (
+ IN EFI_MEMORY_TYPE OldType,
+ IN EFI_MEMORY_TYPE NewType,
+ IN EFI_PHYSICAL_ADDRESS Memory,
+ IN UINT64 Length
+ );
+
+/**
+ Merge continous memory map entries whose have same attributes.
+
+ @param MemoryMap A pointer to the buffer in which firmware places
+ the current memory map.
+ @param MemoryMapSize A pointer to the size, in bytes, of the
+ MemoryMap buffer. On input, this is the size of
+ the current memory map. On output,
+ it is the size of new memory map after merge.
+ @param DescriptorSize Size, in bytes, of an individual EFI_MEMORY_DESCRIPTOR.
+**/
+VOID
+MergeMemoryMap (
+ IN OUT EFI_MEMORY_DESCRIPTOR *MemoryMap,
+ IN OUT UINTN *MemoryMapSize,
+ IN UINTN DescriptorSize
+ );
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Core/Dxe/DxeMain.inf b/roms/edk2/MdeModulePkg/Core/Dxe/DxeMain.inf
new file mode 100644
index 000000000..1d4b11dc7
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Core/Dxe/DxeMain.inf
@@ -0,0 +1,201 @@
+## @file
+# This is core module in DXE phase.
+#
+# It provides an implementation of DXE Core that is compliant with DXE CIS.
+#
+# Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR>
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = DxeCore
+ MODULE_UNI_FILE = DxeCore.uni
+ FILE_GUID = D6A2CB7F-6A18-4e2f-B43B-9920A733700A
+ MODULE_TYPE = DXE_CORE
+ VERSION_STRING = 1.0
+
+
+ ENTRY_POINT = DxeMain
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 EBC (EBC is for build only)
+#
+
+[Sources]
+ DxeMain.h
+ SectionExtraction/CoreSectionExtraction.c
+ Image/Image.c
+ Image/Image.h
+ Misc/DebugImageInfo.c
+ Misc/Stall.c
+ Misc/SetWatchdogTimer.c
+ Misc/InstallConfigurationTable.c
+ Misc/MemoryAttributesTable.c
+ Misc/MemoryProtection.c
+ Library/Library.c
+ Hand/DriverSupport.c
+ Hand/Notify.c
+ Hand/Locate.c
+ Hand/Handle.c
+ Hand/Handle.h
+ Gcd/Gcd.c
+ Gcd/Gcd.h
+ Mem/Pool.c
+ Mem/Page.c
+ Mem/MemData.c
+ Mem/Imem.h
+ Mem/MemoryProfileRecord.c
+ Mem/HeapGuard.c
+ Mem/HeapGuard.h
+ FwVolBlock/FwVolBlock.c
+ FwVolBlock/FwVolBlock.h
+ FwVol/FwVolWrite.c
+ FwVol/FwVolRead.c
+ FwVol/FwVolAttrib.c
+ FwVol/Ffs.c
+ FwVol/FwVol.c
+ FwVol/FwVolDriver.h
+ Event/Tpl.c
+ Event/Timer.c
+ Event/Event.c
+ Event/Event.h
+ Dispatcher/Dependency.c
+ Dispatcher/Dispatcher.c
+ DxeMain/DxeProtocolNotify.c
+ DxeMain/DxeMain.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+ BaseMemoryLib
+ CacheMaintenanceLib
+ UefiDecompressLib
+ PerformanceLib
+ HobLib
+ BaseLib
+ UefiLib
+ DebugLib
+ DxeCoreEntryPoint
+ PeCoffLib
+ PeCoffGetEntryPointLib
+ PeCoffExtraActionLib
+ ExtractGuidedSectionLib
+ MemoryAllocationLib
+ UefiBootServicesTableLib
+ DevicePathLib
+ ReportStatusCodeLib
+ DxeServicesLib
+ DebugAgentLib
+ CpuExceptionHandlerLib
+ PcdLib
+
+[Guids]
+ gEfiEventMemoryMapChangeGuid ## PRODUCES ## Event
+ gEfiEventVirtualAddressChangeGuid ## CONSUMES ## Event
+ ## CONSUMES ## Event
+ ## PRODUCES ## Event
+ gEfiEventExitBootServicesGuid
+ gEfiHobMemoryAllocModuleGuid ## SOMETIMES_CONSUMES ## HOB
+ gEfiFirmwareFileSystem2Guid ## CONSUMES ## GUID # Used to compare with FV's file system guid and get the FV's file system format
+ gEfiFirmwareFileSystem3Guid ## CONSUMES ## GUID # Used to compare with FV's file system guid and get the FV's file system format
+ gAprioriGuid ## SOMETIMES_CONSUMES ## File
+ gEfiDebugImageInfoTableGuid ## PRODUCES ## SystemTable
+ gEfiHobListGuid ## PRODUCES ## SystemTable
+ gEfiDxeServicesTableGuid ## PRODUCES ## SystemTable
+ ## PRODUCES ## SystemTable
+ ## SOMETIMES_CONSUMES ## HOB
+ gEfiMemoryTypeInformationGuid
+ gEfiEventDxeDispatchGuid ## PRODUCES ## Event
+ gLoadFixedAddressConfigurationTableGuid ## SOMETIMES_PRODUCES ## SystemTable
+ ## PRODUCES ## Event
+ ## CONSUMES ## Event
+ gIdleLoopEventGuid
+ gEventExitBootServicesFailedGuid ## SOMETIMES_PRODUCES ## Event
+ gEfiVectorHandoffTableGuid ## SOMETIMES_PRODUCES ## SystemTable
+ gEdkiiMemoryProfileGuid ## SOMETIMES_PRODUCES ## GUID # Install protocol
+ gEfiMemoryAttributesTableGuid ## SOMETIMES_PRODUCES ## SystemTable
+ gEfiEndOfDxeEventGroupGuid ## SOMETIMES_CONSUMES ## Event
+ gEfiHobMemoryAllocStackGuid ## SOMETIMES_CONSUMES ## SystemTable
+
+[Ppis]
+ gEfiVectorHandoffInfoPpiGuid ## UNDEFINED # HOB
+
+[Protocols]
+ ## PRODUCES
+ ## SOMETIMES_CONSUMES
+ gEfiDecompressProtocolGuid
+ gEfiSimpleFileSystemProtocolGuid ## SOMETIMES_CONSUMES
+ gEfiLoadFileProtocolGuid ## SOMETIMES_CONSUMES
+ gEfiLoadFile2ProtocolGuid ## SOMETIMES_CONSUMES
+ gEfiBusSpecificDriverOverrideProtocolGuid ## SOMETIMES_CONSUMES
+ gEfiDriverFamilyOverrideProtocolGuid ## SOMETIMES_CONSUMES
+ gEfiPlatformDriverOverrideProtocolGuid ## SOMETIMES_CONSUMES
+ gEfiDriverBindingProtocolGuid ## SOMETIMES_CONSUMES
+ ## PRODUCES
+ ## CONSUMES
+ ## NOTIFY
+ gEfiFirmwareVolumeBlockProtocolGuid
+ ## PRODUCES
+ ## CONSUMES
+ ## NOTIFY
+ gEfiFirmwareVolume2ProtocolGuid
+ ## PRODUCES
+ ## CONSUMES
+ gEfiDevicePathProtocolGuid
+ gEfiLoadedImageProtocolGuid ## PRODUCES
+ gEfiLoadedImageDevicePathProtocolGuid ## PRODUCES
+ gEfiHiiPackageListProtocolGuid ## SOMETIMES_PRODUCES
+ gEfiSmmBase2ProtocolGuid ## SOMETIMES_CONSUMES
+ gEdkiiPeCoffImageEmulatorProtocolGuid ## SOMETIMES_CONSUMES
+
+ # Arch Protocols
+ gEfiBdsArchProtocolGuid ## CONSUMES
+ gEfiCpuArchProtocolGuid ## CONSUMES
+ gEfiMetronomeArchProtocolGuid ## CONSUMES
+ gEfiMonotonicCounterArchProtocolGuid ## CONSUMES
+ gEfiRealTimeClockArchProtocolGuid ## CONSUMES
+ gEfiResetArchProtocolGuid ## CONSUMES
+ gEfiRuntimeArchProtocolGuid ## CONSUMES
+ gEfiSecurityArchProtocolGuid ## CONSUMES
+ gEfiSecurity2ArchProtocolGuid ## SOMETIMES_CONSUMES
+ gEfiTimerArchProtocolGuid ## CONSUMES
+ gEfiVariableWriteArchProtocolGuid ## CONSUMES
+ gEfiVariableArchProtocolGuid ## CONSUMES
+ gEfiCapsuleArchProtocolGuid ## CONSUMES
+ gEfiWatchdogTimerArchProtocolGuid ## CONSUMES
+
+[Pcd]
+ gEfiMdeModulePkgTokenSpaceGuid.PcdLoadFixAddressBootTimeCodePageNumber ## SOMETIMES_CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdLoadFixAddressRuntimeCodePageNumber ## SOMETIMES_CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdLoadModuleAtFixAddressEnable ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdMaxEfiSystemTablePointerAddress ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdMemoryProfileMemoryType ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdMemoryProfilePropertyMask ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdMemoryProfileDriverPath ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdImageProtectionPolicy ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdDxeNxMemoryProtectionPolicy ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdNullPointerDetectionPropertyMask ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdHeapGuardPageType ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdHeapGuardPoolType ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdHeapGuardPropertyMask ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdCpuStackGuard ## CONSUMES
+
+# [Hob]
+# RESOURCE_DESCRIPTOR ## CONSUMES
+# MEMORY_ALLOCATION ## CONSUMES
+# FIRMWARE_VOLUME ## CONSUMES
+# UNDEFINED ## CONSUMES # CPU
+#
+# [Event]
+# EVENT_TYPE_RELATIVE_TIMER ## PRODUCES # DxeCore signals timer event.
+# EVENT_TYPE_PERIODIC_TIMER ## PRODUCES # DxeCore signals timer event.
+#
+
+[UserExtensions.TianoCore."ExtraFiles"]
+ DxeCoreExtra.uni
diff --git a/roms/edk2/MdeModulePkg/Core/Dxe/DxeMain/DxeMain.c b/roms/edk2/MdeModulePkg/Core/Dxe/DxeMain/DxeMain.c
new file mode 100644
index 000000000..5ee4cd10b
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Core/Dxe/DxeMain/DxeMain.c
@@ -0,0 +1,938 @@
+/** @file
+ DXE Core Main Entry Point
+
+Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "DxeMain.h"
+
+//
+// DXE Core Global Variables for Protocols from PEI
+//
+EFI_HANDLE mDecompressHandle = NULL;
+
+//
+// DXE Core globals for Architecture Protocols
+//
+EFI_SECURITY_ARCH_PROTOCOL *gSecurity = NULL;
+EFI_SECURITY2_ARCH_PROTOCOL *gSecurity2 = NULL;
+EFI_CPU_ARCH_PROTOCOL *gCpu = NULL;
+EFI_METRONOME_ARCH_PROTOCOL *gMetronome = NULL;
+EFI_TIMER_ARCH_PROTOCOL *gTimer = NULL;
+EFI_BDS_ARCH_PROTOCOL *gBds = NULL;
+EFI_WATCHDOG_TIMER_ARCH_PROTOCOL *gWatchdogTimer = NULL;
+
+//
+// DXE Core globals for optional protocol dependencies
+//
+EFI_SMM_BASE2_PROTOCOL *gSmmBase2 = NULL;
+
+//
+// DXE Core Global used to update core loaded image protocol handle
+//
+EFI_GUID *gDxeCoreFileName;
+EFI_LOADED_IMAGE_PROTOCOL *gDxeCoreLoadedImage;
+
+//
+// DXE Core Module Variables
+//
+EFI_BOOT_SERVICES mBootServices = {
+ {
+ EFI_BOOT_SERVICES_SIGNATURE, // Signature
+ EFI_BOOT_SERVICES_REVISION, // Revision
+ sizeof (EFI_BOOT_SERVICES), // HeaderSize
+ 0, // CRC32
+ 0 // Reserved
+ },
+ (EFI_RAISE_TPL) CoreRaiseTpl, // RaiseTPL
+ (EFI_RESTORE_TPL) CoreRestoreTpl, // RestoreTPL
+ (EFI_ALLOCATE_PAGES) CoreAllocatePages, // AllocatePages
+ (EFI_FREE_PAGES) CoreFreePages, // FreePages
+ (EFI_GET_MEMORY_MAP) CoreGetMemoryMap, // GetMemoryMap
+ (EFI_ALLOCATE_POOL) CoreAllocatePool, // AllocatePool
+ (EFI_FREE_POOL) CoreFreePool, // FreePool
+ (EFI_CREATE_EVENT) CoreCreateEvent, // CreateEvent
+ (EFI_SET_TIMER) CoreSetTimer, // SetTimer
+ (EFI_WAIT_FOR_EVENT) CoreWaitForEvent, // WaitForEvent
+ (EFI_SIGNAL_EVENT) CoreSignalEvent, // SignalEvent
+ (EFI_CLOSE_EVENT) CoreCloseEvent, // CloseEvent
+ (EFI_CHECK_EVENT) CoreCheckEvent, // CheckEvent
+ (EFI_INSTALL_PROTOCOL_INTERFACE) CoreInstallProtocolInterface, // InstallProtocolInterface
+ (EFI_REINSTALL_PROTOCOL_INTERFACE) CoreReinstallProtocolInterface, // ReinstallProtocolInterface
+ (EFI_UNINSTALL_PROTOCOL_INTERFACE) CoreUninstallProtocolInterface, // UninstallProtocolInterface
+ (EFI_HANDLE_PROTOCOL) CoreHandleProtocol, // HandleProtocol
+ (VOID *) NULL, // Reserved
+ (EFI_REGISTER_PROTOCOL_NOTIFY) CoreRegisterProtocolNotify, // RegisterProtocolNotify
+ (EFI_LOCATE_HANDLE) CoreLocateHandle, // LocateHandle
+ (EFI_LOCATE_DEVICE_PATH) CoreLocateDevicePath, // LocateDevicePath
+ (EFI_INSTALL_CONFIGURATION_TABLE) CoreInstallConfigurationTable, // InstallConfigurationTable
+ (EFI_IMAGE_LOAD) CoreLoadImage, // LoadImage
+ (EFI_IMAGE_START) CoreStartImage, // StartImage
+ (EFI_EXIT) CoreExit, // Exit
+ (EFI_IMAGE_UNLOAD) CoreUnloadImage, // UnloadImage
+ (EFI_EXIT_BOOT_SERVICES) CoreExitBootServices, // ExitBootServices
+ (EFI_GET_NEXT_MONOTONIC_COUNT) CoreEfiNotAvailableYetArg1, // GetNextMonotonicCount
+ (EFI_STALL) CoreStall, // Stall
+ (EFI_SET_WATCHDOG_TIMER) CoreSetWatchdogTimer, // SetWatchdogTimer
+ (EFI_CONNECT_CONTROLLER) CoreConnectController, // ConnectController
+ (EFI_DISCONNECT_CONTROLLER) CoreDisconnectController, // DisconnectController
+ (EFI_OPEN_PROTOCOL) CoreOpenProtocol, // OpenProtocol
+ (EFI_CLOSE_PROTOCOL) CoreCloseProtocol, // CloseProtocol
+ (EFI_OPEN_PROTOCOL_INFORMATION) CoreOpenProtocolInformation, // OpenProtocolInformation
+ (EFI_PROTOCOLS_PER_HANDLE) CoreProtocolsPerHandle, // ProtocolsPerHandle
+ (EFI_LOCATE_HANDLE_BUFFER) CoreLocateHandleBuffer, // LocateHandleBuffer
+ (EFI_LOCATE_PROTOCOL) CoreLocateProtocol, // LocateProtocol
+ (EFI_INSTALL_MULTIPLE_PROTOCOL_INTERFACES) CoreInstallMultipleProtocolInterfaces, // InstallMultipleProtocolInterfaces
+ (EFI_UNINSTALL_MULTIPLE_PROTOCOL_INTERFACES) CoreUninstallMultipleProtocolInterfaces, // UninstallMultipleProtocolInterfaces
+ (EFI_CALCULATE_CRC32) CoreEfiNotAvailableYetArg3, // CalculateCrc32
+ (EFI_COPY_MEM) CopyMem, // CopyMem
+ (EFI_SET_MEM) SetMem, // SetMem
+ (EFI_CREATE_EVENT_EX) CoreCreateEventEx // CreateEventEx
+};
+
+EFI_DXE_SERVICES mDxeServices = {
+ {
+ DXE_SERVICES_SIGNATURE, // Signature
+ DXE_SERVICES_REVISION, // Revision
+ sizeof (DXE_SERVICES), // HeaderSize
+ 0, // CRC32
+ 0 // Reserved
+ },
+ (EFI_ADD_MEMORY_SPACE) CoreAddMemorySpace, // AddMemorySpace
+ (EFI_ALLOCATE_MEMORY_SPACE) CoreAllocateMemorySpace, // AllocateMemorySpace
+ (EFI_FREE_MEMORY_SPACE) CoreFreeMemorySpace, // FreeMemorySpace
+ (EFI_REMOVE_MEMORY_SPACE) CoreRemoveMemorySpace, // RemoveMemorySpace
+ (EFI_GET_MEMORY_SPACE_DESCRIPTOR) CoreGetMemorySpaceDescriptor, // GetMemorySpaceDescriptor
+ (EFI_SET_MEMORY_SPACE_ATTRIBUTES) CoreSetMemorySpaceAttributes, // SetMemorySpaceAttributes
+ (EFI_GET_MEMORY_SPACE_MAP) CoreGetMemorySpaceMap, // GetMemorySpaceMap
+ (EFI_ADD_IO_SPACE) CoreAddIoSpace, // AddIoSpace
+ (EFI_ALLOCATE_IO_SPACE) CoreAllocateIoSpace, // AllocateIoSpace
+ (EFI_FREE_IO_SPACE) CoreFreeIoSpace, // FreeIoSpace
+ (EFI_REMOVE_IO_SPACE) CoreRemoveIoSpace, // RemoveIoSpace
+ (EFI_GET_IO_SPACE_DESCRIPTOR) CoreGetIoSpaceDescriptor, // GetIoSpaceDescriptor
+ (EFI_GET_IO_SPACE_MAP) CoreGetIoSpaceMap, // GetIoSpaceMap
+ (EFI_DISPATCH) CoreDispatcher, // Dispatch
+ (EFI_SCHEDULE) CoreSchedule, // Schedule
+ (EFI_TRUST) CoreTrust, // Trust
+ (EFI_PROCESS_FIRMWARE_VOLUME) CoreProcessFirmwareVolume, // ProcessFirmwareVolume
+ (EFI_SET_MEMORY_SPACE_CAPABILITIES)CoreSetMemorySpaceCapabilities, // SetMemorySpaceCapabilities
+};
+
+EFI_SYSTEM_TABLE mEfiSystemTableTemplate = {
+ {
+ EFI_SYSTEM_TABLE_SIGNATURE, // Signature
+ EFI_SYSTEM_TABLE_REVISION, // Revision
+ sizeof (EFI_SYSTEM_TABLE), // HeaderSize
+ 0, // CRC32
+ 0 // Reserved
+ },
+ NULL, // FirmwareVendor
+ 0, // FirmwareRevision
+ NULL, // ConsoleInHandle
+ NULL, // ConIn
+ NULL, // ConsoleOutHandle
+ NULL, // ConOut
+ NULL, // StandardErrorHandle
+ NULL, // StdErr
+ NULL, // RuntimeServices
+ &mBootServices, // BootServices
+ 0, // NumberOfConfigurationTableEntries
+ NULL // ConfigurationTable
+};
+
+EFI_RUNTIME_SERVICES mEfiRuntimeServicesTableTemplate = {
+ {
+ EFI_RUNTIME_SERVICES_SIGNATURE, // Signature
+ EFI_RUNTIME_SERVICES_REVISION, // Revision
+ sizeof (EFI_RUNTIME_SERVICES), // HeaderSize
+ 0, // CRC32
+ 0 // Reserved
+ },
+ (EFI_GET_TIME) CoreEfiNotAvailableYetArg2, // GetTime
+ (EFI_SET_TIME) CoreEfiNotAvailableYetArg1, // SetTime
+ (EFI_GET_WAKEUP_TIME) CoreEfiNotAvailableYetArg3, // GetWakeupTime
+ (EFI_SET_WAKEUP_TIME) CoreEfiNotAvailableYetArg2, // SetWakeupTime
+ (EFI_SET_VIRTUAL_ADDRESS_MAP) CoreEfiNotAvailableYetArg4, // SetVirtualAddressMap
+ (EFI_CONVERT_POINTER) CoreEfiNotAvailableYetArg2, // ConvertPointer
+ (EFI_GET_VARIABLE) CoreEfiNotAvailableYetArg5, // GetVariable
+ (EFI_GET_NEXT_VARIABLE_NAME) CoreEfiNotAvailableYetArg3, // GetNextVariableName
+ (EFI_SET_VARIABLE) CoreEfiNotAvailableYetArg5, // SetVariable
+ (EFI_GET_NEXT_HIGH_MONO_COUNT) CoreEfiNotAvailableYetArg1, // GetNextHighMonotonicCount
+ (EFI_RESET_SYSTEM) CoreEfiNotAvailableYetArg4, // ResetSystem
+ (EFI_UPDATE_CAPSULE) CoreEfiNotAvailableYetArg3, // UpdateCapsule
+ (EFI_QUERY_CAPSULE_CAPABILITIES) CoreEfiNotAvailableYetArg4, // QueryCapsuleCapabilities
+ (EFI_QUERY_VARIABLE_INFO) CoreEfiNotAvailableYetArg4 // QueryVariableInfo
+};
+
+EFI_RUNTIME_ARCH_PROTOCOL gRuntimeTemplate = {
+ INITIALIZE_LIST_HEAD_VARIABLE (gRuntimeTemplate.ImageHead),
+ INITIALIZE_LIST_HEAD_VARIABLE (gRuntimeTemplate.EventHead),
+
+ //
+ // Make sure Size != sizeof (EFI_MEMORY_DESCRIPTOR). This will
+ // prevent people from having pointer math bugs in their code.
+ // now you have to use *DescriptorSize to make things work.
+ //
+ sizeof (EFI_MEMORY_DESCRIPTOR) + sizeof (UINT64) - (sizeof (EFI_MEMORY_DESCRIPTOR) % sizeof (UINT64)),
+ EFI_MEMORY_DESCRIPTOR_VERSION,
+ 0,
+ NULL,
+ NULL,
+ FALSE,
+ FALSE
+};
+
+EFI_RUNTIME_ARCH_PROTOCOL *gRuntime = &gRuntimeTemplate;
+
+//
+// DXE Core Global Variables for the EFI System Table, Boot Services Table,
+// DXE Services Table, and Runtime Services Table
+//
+EFI_DXE_SERVICES *gDxeCoreDS = &mDxeServices;
+EFI_SYSTEM_TABLE *gDxeCoreST = NULL;
+
+//
+// For debug initialize gDxeCoreRT to template. gDxeCoreRT must be allocated from RT memory
+// but gDxeCoreRT is used for ASSERT () and DEBUG () type macros so lets give it
+// a value that will not cause debug infrastructure to crash early on.
+//
+EFI_RUNTIME_SERVICES *gDxeCoreRT = &mEfiRuntimeServicesTableTemplate;
+EFI_HANDLE gDxeCoreImageHandle = NULL;
+
+BOOLEAN gMemoryMapTerminated = FALSE;
+
+//
+// EFI Decompress Protocol
+//
+EFI_DECOMPRESS_PROTOCOL gEfiDecompress = {
+ DxeMainUefiDecompressGetInfo,
+ DxeMainUefiDecompress
+};
+
+//
+// For Loading modules at fixed address feature, the configuration table is to cache the top address below which to load
+// Runtime code&boot time code
+//
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_LOAD_FIXED_ADDRESS_CONFIGURATION_TABLE gLoadModuleAtFixAddressConfigurationTable = {0, 0};
+
+// Main entry point to the DXE Core
+//
+
+/**
+ Main entry point to DXE Core.
+
+ @param HobStart Pointer to the beginning of the HOB List from PEI.
+
+ @return This function should never return.
+
+**/
+VOID
+EFIAPI
+DxeMain (
+ IN VOID *HobStart
+ )
+{
+ EFI_STATUS Status;
+ EFI_PHYSICAL_ADDRESS MemoryBaseAddress;
+ UINT64 MemoryLength;
+ PE_COFF_LOADER_IMAGE_CONTEXT ImageContext;
+ UINTN Index;
+ EFI_HOB_GUID_TYPE *GuidHob;
+ EFI_VECTOR_HANDOFF_INFO *VectorInfoList;
+ EFI_VECTOR_HANDOFF_INFO *VectorInfo;
+ VOID *EntryPoint;
+
+ //
+ // Setup the default exception handlers
+ //
+ VectorInfoList = NULL;
+ GuidHob = GetNextGuidHob (&gEfiVectorHandoffInfoPpiGuid, HobStart);
+ if (GuidHob != NULL) {
+ VectorInfoList = (EFI_VECTOR_HANDOFF_INFO *) (GET_GUID_HOB_DATA(GuidHob));
+ }
+ Status = InitializeCpuExceptionHandlersEx (VectorInfoList, NULL);
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Initialize Debug Agent to support source level debug in DXE phase
+ //
+ InitializeDebugAgent (DEBUG_AGENT_INIT_DXE_CORE, HobStart, NULL);
+
+ //
+ // Initialize Memory Services
+ //
+ CoreInitializeMemoryServices (&HobStart, &MemoryBaseAddress, &MemoryLength);
+
+ MemoryProfileInit (HobStart);
+
+ //
+ // Allocate the EFI System Table and EFI Runtime Service Table from EfiRuntimeServicesData
+ // Use the templates to initialize the contents of the EFI System Table and EFI Runtime Services Table
+ //
+ gDxeCoreST = AllocateRuntimeCopyPool (sizeof (EFI_SYSTEM_TABLE), &mEfiSystemTableTemplate);
+ ASSERT (gDxeCoreST != NULL);
+
+ gDxeCoreRT = AllocateRuntimeCopyPool (sizeof (EFI_RUNTIME_SERVICES), &mEfiRuntimeServicesTableTemplate);
+ ASSERT (gDxeCoreRT != NULL);
+
+ gDxeCoreST->RuntimeServices = gDxeCoreRT;
+
+ //
+ // Start the Image Services.
+ //
+ Status = CoreInitializeImageServices (HobStart);
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Initialize the Global Coherency Domain Services
+ //
+ Status = CoreInitializeGcdServices (&HobStart, MemoryBaseAddress, MemoryLength);
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Call constructor for all libraries
+ //
+ ProcessLibraryConstructorList (gDxeCoreImageHandle, gDxeCoreST);
+ PERF_CROSSMODULE_END ("PEI");
+ PERF_CROSSMODULE_BEGIN ("DXE");
+
+ //
+ // Report DXE Core image information to the PE/COFF Extra Action Library
+ //
+ ZeroMem (&ImageContext, sizeof (ImageContext));
+ ImageContext.ImageAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)gDxeCoreLoadedImage->ImageBase;
+ ImageContext.PdbPointer = PeCoffLoaderGetPdbPointer ((VOID*)(UINTN)ImageContext.ImageAddress);
+ ImageContext.SizeOfHeaders = PeCoffGetSizeOfHeaders ((VOID*)(UINTN)ImageContext.ImageAddress);
+ Status = PeCoffLoaderGetEntryPoint ((VOID*)(UINTN)ImageContext.ImageAddress, &EntryPoint);
+ if (Status == EFI_SUCCESS) {
+ ImageContext.EntryPoint = (EFI_PHYSICAL_ADDRESS)(UINTN)EntryPoint;
+ }
+ ImageContext.Handle = (VOID *)(UINTN)gDxeCoreLoadedImage->ImageBase;
+ ImageContext.ImageRead = PeCoffLoaderImageReadFromMemory;
+ PeCoffLoaderRelocateImageExtraAction (&ImageContext);
+
+ //
+ // Install the DXE Services Table into the EFI System Tables's Configuration Table
+ //
+ Status = CoreInstallConfigurationTable (&gEfiDxeServicesTableGuid, gDxeCoreDS);
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Install the HOB List into the EFI System Tables's Configuration Table
+ //
+ Status = CoreInstallConfigurationTable (&gEfiHobListGuid, HobStart);
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Install Memory Type Information Table into the EFI System Tables's Configuration Table
+ //
+ Status = CoreInstallConfigurationTable (&gEfiMemoryTypeInformationGuid, &gMemoryTypeInformation);
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // If Loading modules At fixed address feature is enabled, install Load moduels at fixed address
+ // Configuration Table so that user could easily to retrieve the top address to load Dxe and PEI
+ // Code and Tseg base to load SMM driver.
+ //
+ if (PcdGet64(PcdLoadModuleAtFixAddressEnable) != 0) {
+ Status = CoreInstallConfigurationTable (&gLoadFixedAddressConfigurationTableGuid, &gLoadModuleAtFixAddressConfigurationTable);
+ ASSERT_EFI_ERROR (Status);
+ }
+ //
+ // Report Status Code here for DXE_ENTRY_POINT once it is available
+ //
+ REPORT_STATUS_CODE (
+ EFI_PROGRESS_CODE,
+ (EFI_SOFTWARE_DXE_CORE | EFI_SW_DXE_CORE_PC_ENTRY_POINT)
+ );
+
+ //
+ // Create the aligned system table pointer structure that is used by external
+ // debuggers to locate the system table... Also, install debug image info
+ // configuration table.
+ //
+ CoreInitializeDebugImageInfoTable ();
+ CoreNewDebugImageInfoEntry (
+ EFI_DEBUG_IMAGE_INFO_TYPE_NORMAL,
+ gDxeCoreLoadedImage,
+ gDxeCoreImageHandle
+ );
+
+ DEBUG ((DEBUG_INFO | DEBUG_LOAD, "HOBLIST address in DXE = 0x%p\n", HobStart));
+
+ DEBUG_CODE_BEGIN ();
+ EFI_PEI_HOB_POINTERS Hob;
+
+ for (Hob.Raw = HobStart; !END_OF_HOB_LIST(Hob); Hob.Raw = GET_NEXT_HOB(Hob)) {
+ if (GET_HOB_TYPE (Hob) == EFI_HOB_TYPE_MEMORY_ALLOCATION) {
+ DEBUG ((DEBUG_INFO | DEBUG_LOAD, "Memory Allocation 0x%08x 0x%0lx - 0x%0lx\n", \
+ Hob.MemoryAllocation->AllocDescriptor.MemoryType, \
+ Hob.MemoryAllocation->AllocDescriptor.MemoryBaseAddress, \
+ Hob.MemoryAllocation->AllocDescriptor.MemoryBaseAddress + Hob.MemoryAllocation->AllocDescriptor.MemoryLength - 1));
+ }
+ }
+ for (Hob.Raw = HobStart; !END_OF_HOB_LIST(Hob); Hob.Raw = GET_NEXT_HOB(Hob)) {
+ if (GET_HOB_TYPE (Hob) == EFI_HOB_TYPE_FV) {
+ DEBUG ((
+ DEBUG_INFO | DEBUG_LOAD,
+ "FV Hob 0x%0lx - 0x%0lx\n",
+ Hob.FirmwareVolume->BaseAddress,
+ Hob.FirmwareVolume->BaseAddress + Hob.FirmwareVolume->Length - 1
+ ));
+ } else if (GET_HOB_TYPE (Hob) == EFI_HOB_TYPE_FV2) {
+ DEBUG ((
+ DEBUG_INFO | DEBUG_LOAD,
+ "FV2 Hob 0x%0lx - 0x%0lx\n",
+ Hob.FirmwareVolume2->BaseAddress,
+ Hob.FirmwareVolume2->BaseAddress + Hob.FirmwareVolume2->Length - 1
+ ));
+ DEBUG ((
+ DEBUG_INFO | DEBUG_LOAD,
+ " %g - %g\n",
+ &Hob.FirmwareVolume2->FvName,
+ &Hob.FirmwareVolume2->FileName
+ ));
+ } else if (GET_HOB_TYPE (Hob) == EFI_HOB_TYPE_FV3) {
+ DEBUG ((
+ DEBUG_INFO | DEBUG_LOAD,
+ "FV3 Hob 0x%0lx - 0x%0lx - 0x%x - 0x%x\n",
+ Hob.FirmwareVolume3->BaseAddress,
+ Hob.FirmwareVolume3->BaseAddress + Hob.FirmwareVolume3->Length - 1,
+ Hob.FirmwareVolume3->AuthenticationStatus,
+ Hob.FirmwareVolume3->ExtractedFv
+ ));
+ if (Hob.FirmwareVolume3->ExtractedFv) {
+ DEBUG ((
+ DEBUG_INFO | DEBUG_LOAD,
+ " %g - %g\n",
+ &Hob.FirmwareVolume3->FvName,
+ &Hob.FirmwareVolume3->FileName
+ ));
+ }
+ }
+ }
+ DEBUG_CODE_END ();
+
+ //
+ // Initialize the Event Services
+ //
+ Status = CoreInitializeEventServices ();
+ ASSERT_EFI_ERROR (Status);
+
+ MemoryProfileInstallProtocol ();
+
+ CoreInitializeMemoryAttributesTable ();
+ CoreInitializeMemoryProtection ();
+
+ //
+ // Get persisted vector hand-off info from GUIDeed HOB again due to HobStart may be updated,
+ // and install configuration table
+ //
+ GuidHob = GetNextGuidHob (&gEfiVectorHandoffInfoPpiGuid, HobStart);
+ if (GuidHob != NULL) {
+ VectorInfoList = (EFI_VECTOR_HANDOFF_INFO *) (GET_GUID_HOB_DATA(GuidHob));
+ VectorInfo = VectorInfoList;
+ Index = 1;
+ while (VectorInfo->Attribute != EFI_VECTOR_HANDOFF_LAST_ENTRY) {
+ VectorInfo ++;
+ Index ++;
+ }
+ VectorInfo = AllocateCopyPool (sizeof (EFI_VECTOR_HANDOFF_INFO) * Index, (VOID *) VectorInfoList);
+ ASSERT (VectorInfo != NULL);
+ Status = CoreInstallConfigurationTable (&gEfiVectorHandoffTableGuid, (VOID *) VectorInfo);
+ ASSERT_EFI_ERROR (Status);
+ }
+
+ //
+ // Get the Protocols that were passed in from PEI to DXE through GUIDed HOBs
+ //
+ // These Protocols are not architectural. This implementation is sharing code between
+ // PEI and DXE in order to save FLASH space. These Protocols could also be implemented
+ // as part of the DXE Core. However, that would also require the DXE Core to be ported
+ // each time a different CPU is used, a different Decompression algorithm is used, or a
+ // different Image type is used. By placing these Protocols in PEI, the DXE Core remains
+ // generic, and only PEI and the Arch Protocols need to be ported from Platform to Platform,
+ // and from CPU to CPU.
+ //
+
+ //
+ // Publish the EFI, Tiano, and Custom Decompress protocols for use by other DXE components
+ //
+ Status = CoreInstallMultipleProtocolInterfaces (
+ &mDecompressHandle,
+ &gEfiDecompressProtocolGuid, &gEfiDecompress,
+ NULL
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Register for the GUIDs of the Architectural Protocols, so the rest of the
+ // EFI Boot Services and EFI Runtime Services tables can be filled in.
+ // Also register for the GUIDs of optional protocols.
+ //
+ CoreNotifyOnProtocolInstallation ();
+
+ //
+ // Produce Firmware Volume Protocols, one for each FV in the HOB list.
+ //
+ Status = FwVolBlockDriverInit (gDxeCoreImageHandle, gDxeCoreST);
+ ASSERT_EFI_ERROR (Status);
+
+ Status = FwVolDriverInit (gDxeCoreImageHandle, gDxeCoreST);
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Produce the Section Extraction Protocol
+ //
+ Status = InitializeSectionExtraction (gDxeCoreImageHandle, gDxeCoreST);
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Initialize the DXE Dispatcher
+ //
+ CoreInitializeDispatcher ();
+
+ //
+ // Invoke the DXE Dispatcher
+ //
+ CoreDispatcher ();
+
+ //
+ // Display Architectural protocols that were not loaded if this is DEBUG build
+ //
+ DEBUG_CODE_BEGIN ();
+ CoreDisplayMissingArchProtocols ();
+ DEBUG_CODE_END ();
+
+ //
+ // Display any drivers that were not dispatched because dependency expression
+ // evaluated to false if this is a debug build
+ //
+ DEBUG_CODE_BEGIN ();
+ CoreDisplayDiscoveredNotDispatched ();
+ DEBUG_CODE_END ();
+
+ //
+ // Assert if the Architectural Protocols are not present.
+ //
+ Status = CoreAllEfiServicesAvailable ();
+ if (EFI_ERROR(Status)) {
+ //
+ // Report Status code that some Architectural Protocols are not present.
+ //
+ REPORT_STATUS_CODE (
+ EFI_ERROR_CODE | EFI_ERROR_MAJOR,
+ (EFI_SOFTWARE_DXE_CORE | EFI_SW_DXE_CORE_EC_NO_ARCH)
+ );
+ }
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Report Status code before transfer control to BDS
+ //
+ REPORT_STATUS_CODE (
+ EFI_PROGRESS_CODE,
+ (EFI_SOFTWARE_DXE_CORE | EFI_SW_DXE_CORE_PC_HANDOFF_TO_NEXT)
+ );
+
+ //
+ // Transfer control to the BDS Architectural Protocol
+ //
+ gBds->Entry (gBds);
+
+ //
+ // BDS should never return
+ //
+ ASSERT (FALSE);
+ CpuDeadLoop ();
+
+ UNREACHABLE ();
+}
+
+
+
+
+/**
+ Place holder function until all the Boot Services and Runtime Services are
+ available.
+
+ @param Arg1 Undefined
+
+ @return EFI_NOT_AVAILABLE_YET
+
+**/
+EFI_STATUS
+EFIAPI
+CoreEfiNotAvailableYetArg1 (
+ UINTN Arg1
+ )
+{
+ //
+ // This function should never be executed. If it does, then the architectural protocols
+ // have not been designed correctly. The CpuBreakpoint () is commented out for now until the
+ // DXE Core and all the Architectural Protocols are complete.
+ //
+
+ return EFI_NOT_AVAILABLE_YET;
+}
+
+
+/**
+ Place holder function until all the Boot Services and Runtime Services are available.
+
+ @param Arg1 Undefined
+ @param Arg2 Undefined
+
+ @return EFI_NOT_AVAILABLE_YET
+
+**/
+EFI_STATUS
+EFIAPI
+CoreEfiNotAvailableYetArg2 (
+ UINTN Arg1,
+ UINTN Arg2
+ )
+{
+ //
+ // This function should never be executed. If it does, then the architectural protocols
+ // have not been designed correctly. The CpuBreakpoint () is commented out for now until the
+ // DXE Core and all the Architectural Protocols are complete.
+ //
+
+ return EFI_NOT_AVAILABLE_YET;
+}
+
+
+/**
+ Place holder function until all the Boot Services and Runtime Services are available.
+
+ @param Arg1 Undefined
+ @param Arg2 Undefined
+ @param Arg3 Undefined
+
+ @return EFI_NOT_AVAILABLE_YET
+
+**/
+EFI_STATUS
+EFIAPI
+CoreEfiNotAvailableYetArg3 (
+ UINTN Arg1,
+ UINTN Arg2,
+ UINTN Arg3
+ )
+{
+ //
+ // This function should never be executed. If it does, then the architectural protocols
+ // have not been designed correctly. The CpuBreakpoint () is commented out for now until the
+ // DXE Core and all the Architectural Protocols are complete.
+ //
+
+ return EFI_NOT_AVAILABLE_YET;
+}
+
+
+/**
+ Place holder function until all the Boot Services and Runtime Services are available.
+
+ @param Arg1 Undefined
+ @param Arg2 Undefined
+ @param Arg3 Undefined
+ @param Arg4 Undefined
+
+ @return EFI_NOT_AVAILABLE_YET
+
+**/
+EFI_STATUS
+EFIAPI
+CoreEfiNotAvailableYetArg4 (
+ UINTN Arg1,
+ UINTN Arg2,
+ UINTN Arg3,
+ UINTN Arg4
+ )
+{
+ //
+ // This function should never be executed. If it does, then the architectural protocols
+ // have not been designed correctly. The CpuBreakpoint () is commented out for now until the
+ // DXE Core and all the Architectural Protocols are complete.
+ //
+
+ return EFI_NOT_AVAILABLE_YET;
+}
+
+
+/**
+ Place holder function until all the Boot Services and Runtime Services are available.
+
+ @param Arg1 Undefined
+ @param Arg2 Undefined
+ @param Arg3 Undefined
+ @param Arg4 Undefined
+ @param Arg5 Undefined
+
+ @return EFI_NOT_AVAILABLE_YET
+
+**/
+EFI_STATUS
+EFIAPI
+CoreEfiNotAvailableYetArg5 (
+ UINTN Arg1,
+ UINTN Arg2,
+ UINTN Arg3,
+ UINTN Arg4,
+ UINTN Arg5
+ )
+{
+ //
+ // This function should never be executed. If it does, then the architectural protocols
+ // have not been designed correctly. The CpuBreakpoint () is commented out for now until the
+ // DXE Core and all the Architectural Protocols are complete.
+ //
+
+ return EFI_NOT_AVAILABLE_YET;
+}
+
+
+/**
+ Calcualte the 32-bit CRC in a EFI table using the service provided by the
+ gRuntime service.
+
+ @param Hdr Pointer to an EFI standard header
+
+**/
+VOID
+CalculateEfiHdrCrc (
+ IN OUT EFI_TABLE_HEADER *Hdr
+ )
+{
+ UINT32 Crc;
+
+ Hdr->CRC32 = 0;
+
+ //
+ // If gBS->CalculateCrce32 () == CoreEfiNotAvailableYet () then
+ // Crc will come back as zero if we set it to zero here
+ //
+ Crc = 0;
+ gBS->CalculateCrc32 ((UINT8 *)Hdr, Hdr->HeaderSize, &Crc);
+ Hdr->CRC32 = Crc;
+}
+
+
+/**
+ Terminates all boot services.
+
+ @param ImageHandle Handle that identifies the exiting image.
+ @param MapKey Key to the latest memory map.
+
+ @retval EFI_SUCCESS Boot Services terminated
+ @retval EFI_INVALID_PARAMETER MapKey is incorrect.
+
+**/
+EFI_STATUS
+EFIAPI
+CoreExitBootServices (
+ IN EFI_HANDLE ImageHandle,
+ IN UINTN MapKey
+ )
+{
+ EFI_STATUS Status;
+
+ //
+ // Disable Timer
+ //
+ gTimer->SetTimerPeriod (gTimer, 0);
+
+ //
+ // Terminate memory services if the MapKey matches
+ //
+ Status = CoreTerminateMemoryMap (MapKey);
+ if (EFI_ERROR (Status)) {
+ //
+ // Notify other drivers that ExitBootServices fail
+ //
+ CoreNotifySignalList (&gEventExitBootServicesFailedGuid);
+ return Status;
+ }
+
+ gMemoryMapTerminated = TRUE;
+
+ //
+ // Notify other drivers that we are exiting boot services.
+ //
+ CoreNotifySignalList (&gEfiEventExitBootServicesGuid);
+
+ //
+ // Report that ExitBootServices() has been called
+ //
+ REPORT_STATUS_CODE (
+ EFI_PROGRESS_CODE,
+ (EFI_SOFTWARE_EFI_BOOT_SERVICE | EFI_SW_BS_PC_EXIT_BOOT_SERVICES)
+ );
+
+ MemoryProtectionExitBootServicesCallback();
+
+ //
+ // Disable interrupt of Debug timer.
+ //
+ SaveAndSetDebugTimerInterrupt (FALSE);
+
+ //
+ // Disable CPU Interrupts
+ //
+ gCpu->DisableInterrupt (gCpu);
+
+ //
+ // Clear the non-runtime values of the EFI System Table
+ //
+ gDxeCoreST->BootServices = NULL;
+ gDxeCoreST->ConIn = NULL;
+ gDxeCoreST->ConsoleInHandle = NULL;
+ gDxeCoreST->ConOut = NULL;
+ gDxeCoreST->ConsoleOutHandle = NULL;
+ gDxeCoreST->StdErr = NULL;
+ gDxeCoreST->StandardErrorHandle = NULL;
+
+ //
+ // Recompute the 32-bit CRC of the EFI System Table
+ //
+ CalculateEfiHdrCrc (&gDxeCoreST->Hdr);
+
+ //
+ // Zero out the Boot Service Table
+ //
+ ZeroMem (gBS, sizeof (EFI_BOOT_SERVICES));
+ gBS = NULL;
+
+ //
+ // Update the AtRuntime field in Runtiem AP.
+ //
+ gRuntime->AtRuntime = TRUE;
+
+ return Status;
+}
+
+
+/**
+ Given a compressed source buffer, this function retrieves the size of the
+ uncompressed buffer and the size of the scratch buffer required to decompress
+ the compressed source buffer.
+
+ The GetInfo() function retrieves the size of the uncompressed buffer and the
+ temporary scratch buffer required to decompress the buffer specified by Source
+ and SourceSize. If the size of the uncompressed buffer or the size of the
+ scratch buffer cannot be determined from the compressed data specified by
+ Source and SourceData, then EFI_INVALID_PARAMETER is returned. Otherwise, the
+ size of the uncompressed buffer is returned in DestinationSize, the size of
+ the scratch buffer is returned in ScratchSize, and EFI_SUCCESS is returned.
+ The GetInfo() function does not have scratch buffer available to perform a
+ thorough checking of the validity of the source data. It just retrieves the
+ "Original Size" field from the beginning bytes of the source data and output
+ it as DestinationSize. And ScratchSize is specific to the decompression
+ implementation.
+
+ @param This A pointer to the EFI_DECOMPRESS_PROTOCOL instance.
+ @param Source The source buffer containing the compressed data.
+ @param SourceSize The size, in bytes, of the source buffer.
+ @param DestinationSize A pointer to the size, in bytes, of the
+ uncompressed buffer that will be generated when the
+ compressed buffer specified by Source and
+ SourceSize is decompressed.
+ @param ScratchSize A pointer to the size, in bytes, of the scratch
+ buffer that is required to decompress the
+ compressed buffer specified by Source and
+ SourceSize.
+
+ @retval EFI_SUCCESS The size of the uncompressed data was returned in
+ DestinationSize and the size of the scratch buffer
+ was returned in ScratchSize.
+ @retval EFI_INVALID_PARAMETER The size of the uncompressed data or the size of
+ the scratch buffer cannot be determined from the
+ compressed data specified by Source and
+ SourceSize.
+
+**/
+EFI_STATUS
+EFIAPI
+DxeMainUefiDecompressGetInfo (
+ IN EFI_DECOMPRESS_PROTOCOL *This,
+ IN VOID *Source,
+ IN UINT32 SourceSize,
+ OUT UINT32 *DestinationSize,
+ OUT UINT32 *ScratchSize
+ )
+{
+ if (Source == NULL || DestinationSize == NULL || ScratchSize == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+ return UefiDecompressGetInfo (Source, SourceSize, DestinationSize, ScratchSize);
+}
+
+
+/**
+ Decompresses a compressed source buffer.
+
+ The Decompress() function extracts decompressed data to its original form.
+ This protocol is designed so that the decompression algorithm can be
+ implemented without using any memory services. As a result, the Decompress()
+ Function is not allowed to call AllocatePool() or AllocatePages() in its
+ implementation. It is the caller's responsibility to allocate and free the
+ Destination and Scratch buffers.
+ If the compressed source data specified by Source and SourceSize is
+ successfully decompressed into Destination, then EFI_SUCCESS is returned. If
+ the compressed source data specified by Source and SourceSize is not in a
+ valid compressed data format, then EFI_INVALID_PARAMETER is returned.
+
+ @param This A pointer to the EFI_DECOMPRESS_PROTOCOL instance.
+ @param Source The source buffer containing the compressed data.
+ @param SourceSize SourceSizeThe size of source data.
+ @param Destination On output, the destination buffer that contains
+ the uncompressed data.
+ @param DestinationSize The size of the destination buffer. The size of
+ the destination buffer needed is obtained from
+ EFI_DECOMPRESS_PROTOCOL.GetInfo().
+ @param Scratch A temporary scratch buffer that is used to perform
+ the decompression.
+ @param ScratchSize The size of scratch buffer. The size of the
+ scratch buffer needed is obtained from GetInfo().
+
+ @retval EFI_SUCCESS Decompression completed successfully, and the
+ uncompressed buffer is returned in Destination.
+ @retval EFI_INVALID_PARAMETER The source buffer specified by Source and
+ SourceSize is corrupted (not in a valid
+ compressed format).
+
+**/
+EFI_STATUS
+EFIAPI
+DxeMainUefiDecompress (
+ IN EFI_DECOMPRESS_PROTOCOL *This,
+ IN VOID *Source,
+ IN UINT32 SourceSize,
+ IN OUT VOID *Destination,
+ IN UINT32 DestinationSize,
+ IN OUT VOID *Scratch,
+ IN UINT32 ScratchSize
+ )
+{
+ EFI_STATUS Status;
+ UINT32 TestDestinationSize;
+ UINT32 TestScratchSize;
+
+ if (Source == NULL || Destination== NULL || Scratch == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Status = UefiDecompressGetInfo (Source, SourceSize, &TestDestinationSize, &TestScratchSize);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if (ScratchSize < TestScratchSize || DestinationSize < TestDestinationSize) {
+ return RETURN_INVALID_PARAMETER;
+ }
+
+ return UefiDecompress (Source, Destination, Scratch);
+}
diff --git a/roms/edk2/MdeModulePkg/Core/Dxe/DxeMain/DxeProtocolNotify.c b/roms/edk2/MdeModulePkg/Core/Dxe/DxeMain/DxeProtocolNotify.c
new file mode 100644
index 000000000..29a55d02e
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Core/Dxe/DxeMain/DxeProtocolNotify.c
@@ -0,0 +1,279 @@
+/** @file
+ This file deals with Architecture Protocol (AP) registration in
+ the Dxe Core. The mArchProtocols[] array represents a list of
+ events that represent the Architectural Protocols.
+
+Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "DxeMain.h"
+
+//
+// DXE Core Global Variables for all of the Architectural Protocols.
+// If a protocol is installed mArchProtocols[].Present will be TRUE.
+//
+// CoreNotifyOnArchProtocolInstallation () fills in mArchProtocols[].Event
+// and mArchProtocols[].Registration as it creates events for every array
+// entry.
+//
+EFI_CORE_PROTOCOL_NOTIFY_ENTRY mArchProtocols[] = {
+ { &gEfiSecurityArchProtocolGuid, (VOID **)&gSecurity, NULL, NULL, FALSE },
+ { &gEfiCpuArchProtocolGuid, (VOID **)&gCpu, NULL, NULL, FALSE },
+ { &gEfiMetronomeArchProtocolGuid, (VOID **)&gMetronome, NULL, NULL, FALSE },
+ { &gEfiTimerArchProtocolGuid, (VOID **)&gTimer, NULL, NULL, FALSE },
+ { &gEfiBdsArchProtocolGuid, (VOID **)&gBds, NULL, NULL, FALSE },
+ { &gEfiWatchdogTimerArchProtocolGuid, (VOID **)&gWatchdogTimer, NULL, NULL, FALSE },
+ { &gEfiRuntimeArchProtocolGuid, (VOID **)&gRuntime, NULL, NULL, FALSE },
+ { &gEfiVariableArchProtocolGuid, (VOID **)NULL, NULL, NULL, FALSE },
+ { &gEfiVariableWriteArchProtocolGuid, (VOID **)NULL, NULL, NULL, FALSE },
+ { &gEfiCapsuleArchProtocolGuid, (VOID **)NULL, NULL, NULL, FALSE },
+ { &gEfiMonotonicCounterArchProtocolGuid, (VOID **)NULL, NULL, NULL, FALSE },
+ { &gEfiResetArchProtocolGuid, (VOID **)NULL, NULL, NULL, FALSE },
+ { &gEfiRealTimeClockArchProtocolGuid, (VOID **)NULL, NULL, NULL, FALSE },
+ { NULL, (VOID **)NULL, NULL, NULL, FALSE }
+};
+
+//
+// Optional protocols that the DXE Core will use if they are present
+//
+EFI_CORE_PROTOCOL_NOTIFY_ENTRY mOptionalProtocols[] = {
+ { &gEfiSecurity2ArchProtocolGuid, (VOID **)&gSecurity2, NULL, NULL, FALSE },
+ { &gEfiSmmBase2ProtocolGuid, (VOID **)&gSmmBase2, NULL, NULL, FALSE },
+ { NULL, (VOID **)NULL, NULL, NULL, FALSE }
+};
+
+//
+// Following is needed to display missing architectural protocols in debug builds
+//
+typedef struct {
+ EFI_GUID *ProtocolGuid;
+ CHAR8 *GuidString;
+} GUID_TO_STRING_PROTOCOL_ENTRY;
+
+GLOBAL_REMOVE_IF_UNREFERENCED CONST GUID_TO_STRING_PROTOCOL_ENTRY mMissingProtocols[] = {
+ { &gEfiSecurityArchProtocolGuid, "Security" },
+ { &gEfiCpuArchProtocolGuid, "CPU" },
+ { &gEfiMetronomeArchProtocolGuid, "Metronome" },
+ { &gEfiTimerArchProtocolGuid, "Timer" },
+ { &gEfiBdsArchProtocolGuid, "Bds" },
+ { &gEfiWatchdogTimerArchProtocolGuid, "Watchdog Timer" },
+ { &gEfiRuntimeArchProtocolGuid, "Runtime" },
+ { &gEfiVariableArchProtocolGuid, "Variable" },
+ { &gEfiVariableWriteArchProtocolGuid, "Variable Write" },
+ { &gEfiCapsuleArchProtocolGuid, "Capsule" },
+ { &gEfiMonotonicCounterArchProtocolGuid, "Monotonic Counter" },
+ { &gEfiResetArchProtocolGuid, "Reset" },
+ { &gEfiRealTimeClockArchProtocolGuid, "Real Time Clock" },
+ { NULL, "" }
+};
+
+/**
+ Return TRUE if all AP services are available.
+
+ @retval EFI_SUCCESS All AP services are available
+ @retval EFI_NOT_FOUND At least one AP service is not available
+
+**/
+EFI_STATUS
+CoreAllEfiServicesAvailable (
+ VOID
+ )
+{
+ EFI_CORE_PROTOCOL_NOTIFY_ENTRY *Entry;
+
+ for (Entry = mArchProtocols; Entry->ProtocolGuid != NULL; Entry++) {
+ if (!Entry->Present) {
+ return EFI_NOT_FOUND;
+ }
+ }
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Notification event handler registered by CoreNotifyOnArchProtocolInstallation ().
+ This notify function is registered for every architectural protocol. This handler
+ updates mArchProtocol[] array entry with protocol instance data and sets it's
+ present flag to TRUE. If any constructor is required it is executed. The EFI
+ System Table headers are updated.
+
+ @param Event The Event that is being processed, not used.
+ @param Context Event Context, not used.
+
+**/
+VOID
+EFIAPI
+GenericProtocolNotify (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ EFI_STATUS Status;
+ EFI_CORE_PROTOCOL_NOTIFY_ENTRY *Entry;
+ VOID *Protocol;
+ LIST_ENTRY *Link;
+ LIST_ENTRY TempLinkNode;
+
+ Protocol = NULL;
+
+ //
+ // Get Entry from Context
+ //
+ Entry = (EFI_CORE_PROTOCOL_NOTIFY_ENTRY *)Context;
+
+ //
+ // See if the expected protocol is present in the handle database
+ //
+ Status = CoreLocateProtocol (Entry->ProtocolGuid, Entry->Registration, &Protocol);
+ if (EFI_ERROR (Status)) {
+ return;
+ }
+
+ //
+ // Mark the protocol as present
+ //
+ Entry->Present = TRUE;
+
+ //
+ // Update protocol global variable if one exists. Entry->Protocol points to a global variable
+ // if one exists in the DXE core for this Architectural Protocol
+ //
+ if (Entry->Protocol != NULL) {
+ *(Entry->Protocol) = Protocol;
+ }
+
+ //
+ // Do special operations for Architectural Protocols
+ //
+
+ if (CompareGuid (Entry->ProtocolGuid, &gEfiTimerArchProtocolGuid)) {
+ //
+ // Register the Core timer tick handler with the Timer AP
+ //
+ gTimer->RegisterHandler (gTimer, CoreTimerTick);
+ }
+
+ if (CompareGuid (Entry->ProtocolGuid, &gEfiRuntimeArchProtocolGuid)) {
+ //
+ // When runtime architectural protocol is available, updates CRC32 in the Debug Table
+ //
+ CoreUpdateDebugTableCrc32 ();
+
+ //
+ // Update the Runtime Architectural protocol with the template that the core was
+ // using so there would not need to be a dependency on the Runtime AP
+ //
+
+ //
+ // Copy all the registered Image to new gRuntime protocol
+ //
+ for (Link = gRuntimeTemplate.ImageHead.ForwardLink; Link != &gRuntimeTemplate.ImageHead; Link = TempLinkNode.ForwardLink) {
+ CopyMem (&TempLinkNode, Link, sizeof(LIST_ENTRY));
+ InsertTailList (&gRuntime->ImageHead, Link);
+ }
+ //
+ // Copy all the registered Event to new gRuntime protocol
+ //
+ for (Link = gRuntimeTemplate.EventHead.ForwardLink; Link != &gRuntimeTemplate.EventHead; Link = TempLinkNode.ForwardLink) {
+ CopyMem (&TempLinkNode, Link, sizeof(LIST_ENTRY));
+ InsertTailList (&gRuntime->EventHead, Link);
+ }
+
+ //
+ // Clean up gRuntimeTemplate
+ //
+ gRuntimeTemplate.ImageHead.ForwardLink = &gRuntimeTemplate.ImageHead;
+ gRuntimeTemplate.ImageHead.BackLink = &gRuntimeTemplate.ImageHead;
+ gRuntimeTemplate.EventHead.ForwardLink = &gRuntimeTemplate.EventHead;
+ gRuntimeTemplate.EventHead.BackLink = &gRuntimeTemplate.EventHead;
+ }
+
+ //
+ // It's over kill to do them all every time, but it saves a lot of code.
+ //
+ CalculateEfiHdrCrc (&gDxeCoreRT->Hdr);
+ CalculateEfiHdrCrc (&gBS->Hdr);
+ CalculateEfiHdrCrc (&gDxeCoreST->Hdr);
+ CalculateEfiHdrCrc (&gDxeCoreDS->Hdr);
+}
+
+/**
+ Creates an event for each entry in a table that is fired everytime a Protocol
+ of a specific type is installed.
+
+ @param Entry Pointer to EFI_CORE_PROTOCOL_NOTIFY_ENTRY.
+
+**/
+VOID
+CoreNotifyOnProtocolEntryTable (
+ EFI_CORE_PROTOCOL_NOTIFY_ENTRY *Entry
+ )
+{
+ EFI_STATUS Status;
+
+ for (; Entry->ProtocolGuid != NULL; Entry++) {
+ //
+ // Create the event
+ //
+ Status = CoreCreateEvent (
+ EVT_NOTIFY_SIGNAL,
+ TPL_CALLBACK,
+ GenericProtocolNotify,
+ Entry,
+ &Entry->Event
+ );
+ ASSERT_EFI_ERROR(Status);
+
+ //
+ // Register for protocol notifactions on this event
+ //
+ Status = CoreRegisterProtocolNotify (
+ Entry->ProtocolGuid,
+ Entry->Event,
+ &Entry->Registration
+ );
+ ASSERT_EFI_ERROR(Status);
+ }
+}
+
+/**
+ Creates an events for the Architectural Protocols and the optional protocols
+ that are fired everytime a Protocol of a specific type is installed.
+
+**/
+VOID
+CoreNotifyOnProtocolInstallation (
+ VOID
+ )
+{
+ CoreNotifyOnProtocolEntryTable (mArchProtocols);
+ CoreNotifyOnProtocolEntryTable (mOptionalProtocols);
+}
+
+
+/**
+ Displays Architectural protocols that were not loaded and are required for DXE
+ core to function. Only used in Debug Builds.
+
+**/
+VOID
+CoreDisplayMissingArchProtocols (
+ VOID
+ )
+{
+ EFI_CORE_PROTOCOL_NOTIFY_ENTRY *Entry;
+ CONST GUID_TO_STRING_PROTOCOL_ENTRY *MissingEntry;
+
+ for (Entry = mArchProtocols; Entry->ProtocolGuid != NULL; Entry++) {
+ if (!Entry->Present) {
+ for (MissingEntry = mMissingProtocols; MissingEntry->ProtocolGuid != NULL; MissingEntry++) {
+ if (CompareGuid (Entry->ProtocolGuid, MissingEntry->ProtocolGuid)) {
+ DEBUG ((DEBUG_ERROR, "\n%a Arch Protocol not present!!\n", MissingEntry->GuidString));
+ break;
+ }
+ }
+ }
+ }
+}
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);
+ }
+
+}
diff --git a/roms/edk2/MdeModulePkg/Core/Dxe/FwVol/Ffs.c b/roms/edk2/MdeModulePkg/Core/Dxe/FwVol/Ffs.c
new file mode 100644
index 000000000..199c7f821
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Core/Dxe/FwVol/Ffs.c
@@ -0,0 +1,227 @@
+/** @file
+ FFS file access utilities.
+
+Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+
+#include "DxeMain.h"
+#include "FwVolDriver.h"
+
+
+/**
+ Get the FFS file state by checking the highest bit set in the header's state field.
+
+ @param ErasePolarity Erase polarity attribute of the firmware volume
+ @param FfsHeader Points to the FFS file header
+
+ @return FFS File state
+
+**/
+EFI_FFS_FILE_STATE
+GetFileState (
+ IN UINT8 ErasePolarity,
+ IN EFI_FFS_FILE_HEADER *FfsHeader
+ )
+{
+ EFI_FFS_FILE_STATE FileState;
+ UINT8 HighestBit;
+
+ FileState = FfsHeader->State;
+
+ if (ErasePolarity != 0) {
+ FileState = (EFI_FFS_FILE_STATE)~FileState;
+ }
+
+ HighestBit = 0x80;
+ while (HighestBit != 0 && ((HighestBit & FileState) == 0)) {
+ HighestBit >>= 1;
+ }
+
+ return (EFI_FFS_FILE_STATE) HighestBit;
+}
+
+
+
+/**
+ Check if a block of buffer is erased.
+
+ @param ErasePolarity Erase polarity attribute of the firmware volume
+ @param InBuffer The buffer to be checked
+ @param BufferSize Size of the buffer in bytes
+
+ @retval TRUE The block of buffer is erased
+ @retval FALSE The block of buffer is not erased
+
+**/
+BOOLEAN
+IsBufferErased (
+ IN UINT8 ErasePolarity,
+ IN VOID *InBuffer,
+ IN UINTN BufferSize
+ )
+{
+ UINTN Count;
+ UINT8 EraseByte;
+ UINT8 *Buffer;
+
+ if(ErasePolarity == 1) {
+ EraseByte = 0xFF;
+ } else {
+ EraseByte = 0;
+ }
+
+ Buffer = InBuffer;
+ for (Count = 0; Count < BufferSize; Count++) {
+ if (Buffer[Count] != EraseByte) {
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+}
+
+
+
+/**
+ Verify checksum of the firmware volume header.
+
+ @param FvHeader Points to the firmware volume header to be checked
+
+ @retval TRUE Checksum verification passed
+ @retval FALSE Checksum verification failed
+
+**/
+BOOLEAN
+VerifyFvHeaderChecksum (
+ IN EFI_FIRMWARE_VOLUME_HEADER *FvHeader
+ )
+{
+ UINT16 Checksum;
+
+ Checksum = CalculateSum16 ((UINT16 *) FvHeader, FvHeader->HeaderLength);
+
+ if (Checksum == 0) {
+ return TRUE;
+ } else {
+ return FALSE;
+ }
+}
+
+
+/**
+ Verify checksum of the FFS file header.
+
+ @param FfsHeader Points to the FFS file header to be checked
+
+ @retval TRUE Checksum verification passed
+ @retval FALSE Checksum verification failed
+
+**/
+BOOLEAN
+VerifyHeaderChecksum (
+ IN EFI_FFS_FILE_HEADER *FfsHeader
+ )
+{
+ UINT8 HeaderChecksum;
+
+ if (IS_FFS_FILE2 (FfsHeader)) {
+ HeaderChecksum = CalculateSum8 ((UINT8 *) FfsHeader, sizeof (EFI_FFS_FILE_HEADER2));
+ } else {
+ HeaderChecksum = CalculateSum8 ((UINT8 *) FfsHeader, sizeof (EFI_FFS_FILE_HEADER));
+ }
+ HeaderChecksum = (UINT8) (HeaderChecksum - FfsHeader->State - FfsHeader->IntegrityCheck.Checksum.File);
+
+ if (HeaderChecksum == 0) {
+ return TRUE;
+ } else {
+ return FALSE;
+ }
+}
+
+
+
+/**
+ Check if it's a valid FFS file header.
+
+ @param ErasePolarity Erase polarity attribute of the firmware volume
+ @param FfsHeader Points to the FFS file header to be checked
+ @param FileState FFS file state to be returned
+
+ @retval TRUE Valid FFS file header
+ @retval FALSE Invalid FFS file header
+
+**/
+BOOLEAN
+IsValidFfsHeader (
+ IN UINT8 ErasePolarity,
+ IN EFI_FFS_FILE_HEADER *FfsHeader,
+ OUT EFI_FFS_FILE_STATE *FileState
+ )
+{
+ *FileState = GetFileState (ErasePolarity, FfsHeader);
+
+ switch (*FileState) {
+ case EFI_FILE_HEADER_VALID:
+ case EFI_FILE_DATA_VALID:
+ case EFI_FILE_MARKED_FOR_UPDATE:
+ case EFI_FILE_DELETED:
+ //
+ // Here we need to verify header checksum
+ //
+ return VerifyHeaderChecksum (FfsHeader);
+
+ case EFI_FILE_HEADER_CONSTRUCTION:
+ case EFI_FILE_HEADER_INVALID:
+ default:
+ return FALSE;
+ }
+}
+
+
+/**
+ Check if it's a valid FFS file.
+ Here we are sure that it has a valid FFS file header since we must call IsValidFfsHeader() first.
+
+ @param ErasePolarity Erase polarity attribute of the firmware volume
+ @param FfsHeader Points to the FFS file to be checked
+
+ @retval TRUE Valid FFS file
+ @retval FALSE Invalid FFS file
+
+**/
+BOOLEAN
+IsValidFfsFile (
+ IN UINT8 ErasePolarity,
+ IN EFI_FFS_FILE_HEADER *FfsHeader
+ )
+{
+ EFI_FFS_FILE_STATE FileState;
+ UINT8 DataCheckSum;
+
+ FileState = GetFileState (ErasePolarity, FfsHeader);
+ switch (FileState) {
+
+ case EFI_FILE_DELETED:
+ case EFI_FILE_DATA_VALID:
+ case EFI_FILE_MARKED_FOR_UPDATE:
+ DataCheckSum = FFS_FIXED_CHECKSUM;
+ if ((FfsHeader->Attributes & FFS_ATTRIB_CHECKSUM) == FFS_ATTRIB_CHECKSUM) {
+ if (IS_FFS_FILE2 (FfsHeader)) {
+ DataCheckSum = CalculateCheckSum8 ((CONST UINT8 *) FfsHeader + sizeof (EFI_FFS_FILE_HEADER2), FFS_FILE2_SIZE (FfsHeader) - sizeof(EFI_FFS_FILE_HEADER2));
+ } else {
+ DataCheckSum = CalculateCheckSum8 ((CONST UINT8 *) FfsHeader + sizeof (EFI_FFS_FILE_HEADER), FFS_FILE_SIZE (FfsHeader) - sizeof(EFI_FFS_FILE_HEADER));
+ }
+ }
+ if (FfsHeader->IntegrityCheck.Checksum.File == DataCheckSum) {
+ return TRUE;
+ }
+
+ default:
+ return FALSE;
+ }
+}
+
+
diff --git a/roms/edk2/MdeModulePkg/Core/Dxe/FwVol/FwVol.c b/roms/edk2/MdeModulePkg/Core/Dxe/FwVol/FwVol.c
new file mode 100644
index 000000000..cbf5c1c7b
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Core/Dxe/FwVol/FwVol.c
@@ -0,0 +1,729 @@
+/** @file
+ Firmware File System driver that produce Firmware Volume protocol.
+ Layers on top of Firmware Block protocol to produce a file abstraction
+ of FV based files.
+
+Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "DxeMain.h"
+#include "FwVolDriver.h"
+
+
+//
+// Protocol notify related globals
+//
+VOID *gEfiFwVolBlockNotifyReg;
+EFI_EVENT gEfiFwVolBlockEvent;
+
+FV_DEVICE mFvDevice = {
+ FV2_DEVICE_SIGNATURE,
+ NULL,
+ NULL,
+ {
+ FvGetVolumeAttributes,
+ FvSetVolumeAttributes,
+ FvReadFile,
+ FvReadFileSection,
+ FvWriteFile,
+ FvGetNextFile,
+ sizeof (UINTN),
+ NULL,
+ FvGetVolumeInfo,
+ FvSetVolumeInfo
+ },
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ { NULL, NULL },
+ 0,
+ 0,
+ FALSE,
+ FALSE
+};
+
+
+//
+// FFS helper functions
+//
+/**
+ Read data from Firmware Block by FVB protocol Read.
+ The data may cross the multi block ranges.
+
+ @param Fvb The FW_VOL_BLOCK_PROTOCOL instance from which to read data.
+ @param StartLba Pointer to StartLba.
+ On input, the start logical block index from which to read.
+ On output,the end logical block index after reading.
+ @param Offset Pointer to Offset
+ On input, offset into the block at which to begin reading.
+ On output, offset into the end block after reading.
+ @param DataSize Size of data to be read.
+ @param Data Pointer to Buffer that the data will be read into.
+
+ @retval EFI_SUCCESS Successfully read data from firmware block.
+ @retval others
+**/
+EFI_STATUS
+ReadFvbData (
+ IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb,
+ IN OUT EFI_LBA *StartLba,
+ IN OUT UINTN *Offset,
+ IN UINTN DataSize,
+ OUT UINT8 *Data
+ )
+{
+ UINTN BlockSize;
+ UINTN NumberOfBlocks;
+ UINTN BlockIndex;
+ UINTN ReadDataSize;
+ EFI_STATUS Status;
+
+ //
+ // Try read data in current block
+ //
+ BlockIndex = 0;
+ ReadDataSize = DataSize;
+ Status = Fvb->Read (Fvb, *StartLba, *Offset, &ReadDataSize, Data);
+ if (Status == EFI_SUCCESS) {
+ *Offset += DataSize;
+ return EFI_SUCCESS;
+ } else if (Status != EFI_BAD_BUFFER_SIZE) {
+ //
+ // other error will direct return
+ //
+ return Status;
+ }
+
+ //
+ // Data crosses the blocks, read data from next block
+ //
+ DataSize -= ReadDataSize;
+ Data += ReadDataSize;
+ *StartLba = *StartLba + 1;
+ while (DataSize > 0) {
+ Status = Fvb->GetBlockSize (Fvb, *StartLba, &BlockSize, &NumberOfBlocks);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Read data from the crossing blocks
+ //
+ BlockIndex = 0;
+ while (BlockIndex < NumberOfBlocks && DataSize >= BlockSize) {
+ Status = Fvb->Read (Fvb, *StartLba + BlockIndex, 0, &BlockSize, Data);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ Data += BlockSize;
+ DataSize -= BlockSize;
+ BlockIndex ++;
+ }
+
+ //
+ // Data doesn't exceed the current block range.
+ //
+ if (DataSize < BlockSize) {
+ break;
+ }
+
+ //
+ // Data must be got from the next block range.
+ //
+ *StartLba += NumberOfBlocks;
+ }
+
+ //
+ // read the remaining data
+ //
+ if (DataSize > 0) {
+ Status = Fvb->Read (Fvb, *StartLba + BlockIndex, 0, &DataSize, Data);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+
+ //
+ // Update Lba and Offset used by the following read.
+ //
+ *StartLba += BlockIndex;
+ *Offset = DataSize;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Given the supplied FW_VOL_BLOCK_PROTOCOL, allocate a buffer for output and
+ copy the real length volume header into it.
+
+ @param Fvb The FW_VOL_BLOCK_PROTOCOL instance from which to
+ read the volume header
+ @param FwVolHeader Pointer to pointer to allocated buffer in which
+ the volume header is returned.
+
+ @retval EFI_OUT_OF_RESOURCES No enough buffer could be allocated.
+ @retval EFI_SUCCESS Successfully read volume header to the allocated
+ buffer.
+ @retval EFI_INVALID_PARAMETER The FV Header signature is not as expected or
+ the file system could not be understood.
+
+**/
+EFI_STATUS
+GetFwVolHeader (
+ IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb,
+ OUT EFI_FIRMWARE_VOLUME_HEADER **FwVolHeader
+ )
+{
+ EFI_STATUS Status;
+ EFI_FIRMWARE_VOLUME_HEADER TempFvh;
+ UINTN FvhLength;
+ EFI_LBA StartLba;
+ UINTN Offset;
+ UINT8 *Buffer;
+
+ //
+ // Read the standard FV header
+ //
+ StartLba = 0;
+ Offset = 0;
+ FvhLength = sizeof (EFI_FIRMWARE_VOLUME_HEADER);
+ Status = ReadFvbData (Fvb, &StartLba, &Offset, FvhLength, (UINT8 *)&TempFvh);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Validate FV Header signature, if not as expected, continue.
+ //
+ if (TempFvh.Signature != EFI_FVH_SIGNATURE) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Check to see that the file system is indeed formatted in a way we can
+ // understand it...
+ //
+ if ((!CompareGuid (&TempFvh.FileSystemGuid, &gEfiFirmwareFileSystem2Guid)) &&
+ (!CompareGuid (&TempFvh.FileSystemGuid, &gEfiFirmwareFileSystem3Guid))) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Allocate a buffer for the caller
+ //
+ *FwVolHeader = AllocatePool (TempFvh.HeaderLength);
+ if (*FwVolHeader == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ //
+ // Copy the standard header into the buffer
+ //
+ CopyMem (*FwVolHeader, &TempFvh, sizeof (EFI_FIRMWARE_VOLUME_HEADER));
+
+ //
+ // Read the rest of the header
+ //
+ FvhLength = TempFvh.HeaderLength - sizeof (EFI_FIRMWARE_VOLUME_HEADER);
+ Buffer = (UINT8 *)*FwVolHeader + sizeof (EFI_FIRMWARE_VOLUME_HEADER);
+ Status = ReadFvbData (Fvb, &StartLba, &Offset, FvhLength, Buffer);
+ if (EFI_ERROR (Status)) {
+ //
+ // Read failed so free buffer
+ //
+ CoreFreePool (*FwVolHeader);
+ }
+
+ return Status;
+}
+
+
+
+/**
+ Free FvDevice resource when error happens
+
+ @param FvDevice pointer to the FvDevice to be freed.
+
+**/
+VOID
+FreeFvDeviceResource (
+ IN FV_DEVICE *FvDevice
+ )
+{
+ FFS_FILE_LIST_ENTRY *FfsFileEntry;
+ LIST_ENTRY *NextEntry;
+
+ //
+ // Free File List Entry
+ //
+ FfsFileEntry = (FFS_FILE_LIST_ENTRY *)FvDevice->FfsFileListHeader.ForwardLink;
+ while (&FfsFileEntry->Link != &FvDevice->FfsFileListHeader) {
+ NextEntry = (&FfsFileEntry->Link)->ForwardLink;
+
+ if (FfsFileEntry->StreamHandle != 0) {
+ //
+ // Close stream and free resources from SEP
+ //
+ CloseSectionStream (FfsFileEntry->StreamHandle, FALSE);
+ }
+
+ if (FfsFileEntry->FileCached) {
+ //
+ // Free the cached file buffer.
+ //
+ CoreFreePool (FfsFileEntry->FfsHeader);
+ }
+
+ CoreFreePool (FfsFileEntry);
+
+ FfsFileEntry = (FFS_FILE_LIST_ENTRY *) NextEntry;
+ }
+
+ if (!FvDevice->IsMemoryMapped) {
+ //
+ // Free the cached FV buffer.
+ //
+ CoreFreePool (FvDevice->CachedFv);
+ }
+
+ //
+ // Free Volume Header
+ //
+ CoreFreePool (FvDevice->FwVolHeader);
+
+ return;
+}
+
+
+
+/**
+ Check if an FV is consistent and allocate cache for it.
+
+ @param FvDevice A pointer to the FvDevice to be checked.
+
+ @retval EFI_OUT_OF_RESOURCES No enough buffer could be allocated.
+ @retval EFI_SUCCESS FV is consistent and cache is allocated.
+ @retval EFI_VOLUME_CORRUPTED File system is corrupted.
+
+**/
+EFI_STATUS
+FvCheck (
+ IN OUT FV_DEVICE *FvDevice
+ )
+{
+ EFI_STATUS Status;
+ EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb;
+ EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader;
+ EFI_FIRMWARE_VOLUME_EXT_HEADER *FwVolExtHeader;
+ EFI_FVB_ATTRIBUTES_2 FvbAttributes;
+ EFI_FV_BLOCK_MAP_ENTRY *BlockMap;
+ FFS_FILE_LIST_ENTRY *FfsFileEntry;
+ EFI_FFS_FILE_HEADER *FfsHeader;
+ UINT8 *CacheLocation;
+ UINTN Index;
+ EFI_LBA LbaIndex;
+ UINTN Size;
+ EFI_FFS_FILE_STATE FileState;
+ UINT8 *TopFvAddress;
+ UINTN TestLength;
+ EFI_PHYSICAL_ADDRESS PhysicalAddress;
+ BOOLEAN FileCached;
+ UINTN WholeFileSize;
+ EFI_FFS_FILE_HEADER *CacheFfsHeader;
+
+ FileCached = FALSE;
+ CacheFfsHeader = NULL;
+
+ Fvb = FvDevice->Fvb;
+ FwVolHeader = FvDevice->FwVolHeader;
+
+ Status = Fvb->GetAttributes (Fvb, &FvbAttributes);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Size = (UINTN) FwVolHeader->FvLength;
+ if ((FvbAttributes & EFI_FVB2_MEMORY_MAPPED) != 0) {
+ FvDevice->IsMemoryMapped = TRUE;
+
+ Status = Fvb->GetPhysicalAddress (Fvb, &PhysicalAddress);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Don't cache memory mapped FV really.
+ //
+ FvDevice->CachedFv = (UINT8 *) (UINTN) PhysicalAddress;
+ } else {
+ FvDevice->IsMemoryMapped = FALSE;
+ FvDevice->CachedFv = AllocatePool (Size);
+
+ if (FvDevice->CachedFv == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ }
+
+ //
+ // Remember a pointer to the end of the CachedFv
+ //
+ FvDevice->EndOfCachedFv = FvDevice->CachedFv + Size;
+
+ if (!FvDevice->IsMemoryMapped) {
+ //
+ // Copy FV into memory using the block map.
+ //
+ BlockMap = FwVolHeader->BlockMap;
+ CacheLocation = FvDevice->CachedFv;
+ LbaIndex = 0;
+ while ((BlockMap->NumBlocks != 0) || (BlockMap->Length != 0)) {
+ //
+ // read the FV data
+ //
+ Size = BlockMap->Length;
+ for (Index = 0; Index < BlockMap->NumBlocks; Index++) {
+ Status = Fvb->Read (
+ Fvb,
+ LbaIndex,
+ 0,
+ &Size,
+ CacheLocation
+ );
+
+ //
+ // Not check EFI_BAD_BUFFER_SIZE, for Size = BlockMap->Length
+ //
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ LbaIndex++;
+ CacheLocation += BlockMap->Length;
+ }
+
+ BlockMap++;
+ }
+ }
+
+ //
+ // Scan to check the free space & File list
+ //
+ if ((FvbAttributes & EFI_FVB2_ERASE_POLARITY) != 0) {
+ FvDevice->ErasePolarity = 1;
+ } else {
+ FvDevice->ErasePolarity = 0;
+ }
+
+
+ //
+ // go through the whole FV cache, check the consistence of the FV.
+ // Make a linked list of all the Ffs file headers
+ //
+ Status = EFI_SUCCESS;
+ InitializeListHead (&FvDevice->FfsFileListHeader);
+
+ //
+ // Build FFS list
+ //
+ if (FwVolHeader->ExtHeaderOffset != 0) {
+ //
+ // Searching for files starts on an 8 byte aligned boundary after the end of the Extended Header if it exists.
+ //
+ FwVolExtHeader = (EFI_FIRMWARE_VOLUME_EXT_HEADER *) (FvDevice->CachedFv + FwVolHeader->ExtHeaderOffset);
+ FfsHeader = (EFI_FFS_FILE_HEADER *) ((UINT8 *) FwVolExtHeader + FwVolExtHeader->ExtHeaderSize);
+ } else {
+ FfsHeader = (EFI_FFS_FILE_HEADER *) (FvDevice->CachedFv + FwVolHeader->HeaderLength);
+ }
+ FfsHeader = (EFI_FFS_FILE_HEADER *) ALIGN_POINTER (FfsHeader, 8);
+ TopFvAddress = FvDevice->EndOfCachedFv;
+ while (((UINTN) FfsHeader >= (UINTN) FvDevice->CachedFv) && ((UINTN) FfsHeader <= (UINTN) ((UINTN) TopFvAddress - sizeof (EFI_FFS_FILE_HEADER)))) {
+
+ if (FileCached) {
+ CoreFreePool (CacheFfsHeader);
+ FileCached = FALSE;
+ }
+
+ TestLength = TopFvAddress - ((UINT8 *) FfsHeader);
+ if (TestLength > sizeof (EFI_FFS_FILE_HEADER)) {
+ TestLength = sizeof (EFI_FFS_FILE_HEADER);
+ }
+
+ if (IsBufferErased (FvDevice->ErasePolarity, FfsHeader, TestLength)) {
+ //
+ // We have found the free space so we are done!
+ //
+ goto Done;
+ }
+
+ if (!IsValidFfsHeader (FvDevice->ErasePolarity, FfsHeader, &FileState)) {
+ if ((FileState == EFI_FILE_HEADER_INVALID) ||
+ (FileState == EFI_FILE_HEADER_CONSTRUCTION)) {
+ if (IS_FFS_FILE2 (FfsHeader)) {
+ if (!FvDevice->IsFfs3Fv) {
+ DEBUG ((EFI_D_ERROR, "Found a FFS3 formatted file: %g in a non-FFS3 formatted FV.\n", &FfsHeader->Name));
+ }
+ FfsHeader = (EFI_FFS_FILE_HEADER *) ((UINT8 *) FfsHeader + sizeof (EFI_FFS_FILE_HEADER2));
+ } else {
+ FfsHeader = (EFI_FFS_FILE_HEADER *) ((UINT8 *) FfsHeader + sizeof (EFI_FFS_FILE_HEADER));
+ }
+ continue;
+ } else {
+ //
+ // File system is corrputed
+ //
+ Status = EFI_VOLUME_CORRUPTED;
+ goto Done;
+ }
+ }
+
+ CacheFfsHeader = FfsHeader;
+ if ((CacheFfsHeader->Attributes & FFS_ATTRIB_CHECKSUM) == FFS_ATTRIB_CHECKSUM) {
+ if (FvDevice->IsMemoryMapped) {
+ //
+ // Memory mapped FV has not been cached.
+ // Here is to cache FFS file to memory buffer for following checksum calculating.
+ // And then, the cached file buffer can be also used for FvReadFile.
+ //
+ WholeFileSize = IS_FFS_FILE2 (CacheFfsHeader) ? FFS_FILE2_SIZE (CacheFfsHeader): FFS_FILE_SIZE (CacheFfsHeader);
+ CacheFfsHeader = AllocateCopyPool (WholeFileSize, CacheFfsHeader);
+ if (CacheFfsHeader == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Done;
+ }
+ FileCached = TRUE;
+ }
+ }
+
+ if (!IsValidFfsFile (FvDevice->ErasePolarity, CacheFfsHeader)) {
+ //
+ // File system is corrupted
+ //
+ Status = EFI_VOLUME_CORRUPTED;
+ goto Done;
+ }
+
+ if (IS_FFS_FILE2 (CacheFfsHeader)) {
+ ASSERT (FFS_FILE2_SIZE (CacheFfsHeader) > 0x00FFFFFF);
+ if (!FvDevice->IsFfs3Fv) {
+ DEBUG ((EFI_D_ERROR, "Found a FFS3 formatted file: %g in a non-FFS3 formatted FV.\n", &CacheFfsHeader->Name));
+ FfsHeader = (EFI_FFS_FILE_HEADER *) ((UINT8 *) FfsHeader + FFS_FILE2_SIZE (CacheFfsHeader));
+ //
+ // Adjust pointer to the next 8-byte aligned boundary.
+ //
+ FfsHeader = (EFI_FFS_FILE_HEADER *) (((UINTN) FfsHeader + 7) & ~0x07);
+ continue;
+ }
+ }
+
+ FileState = GetFileState (FvDevice->ErasePolarity, CacheFfsHeader);
+
+ //
+ // check for non-deleted file
+ //
+ if (FileState != EFI_FILE_DELETED) {
+ //
+ // Create a FFS list entry for each non-deleted file
+ //
+ FfsFileEntry = AllocateZeroPool (sizeof (FFS_FILE_LIST_ENTRY));
+ if (FfsFileEntry == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Done;
+ }
+
+ FfsFileEntry->FfsHeader = CacheFfsHeader;
+ FfsFileEntry->FileCached = FileCached;
+ FileCached = FALSE;
+ InsertTailList (&FvDevice->FfsFileListHeader, &FfsFileEntry->Link);
+ }
+
+ if (IS_FFS_FILE2 (CacheFfsHeader)) {
+ FfsHeader = (EFI_FFS_FILE_HEADER *) ((UINT8 *) FfsHeader + FFS_FILE2_SIZE (CacheFfsHeader));
+ } else {
+ FfsHeader = (EFI_FFS_FILE_HEADER *) ((UINT8 *) FfsHeader + FFS_FILE_SIZE (CacheFfsHeader));
+ }
+
+ //
+ // Adjust pointer to the next 8-byte aligned boundary.
+ //
+ FfsHeader = (EFI_FFS_FILE_HEADER *)(((UINTN)FfsHeader + 7) & ~0x07);
+
+ }
+
+Done:
+ if (EFI_ERROR (Status)) {
+ if (FileCached) {
+ CoreFreePool (CacheFfsHeader);
+ FileCached = FALSE;
+ }
+ FreeFvDeviceResource (FvDevice);
+ }
+
+ return Status;
+}
+
+
+
+/**
+ This notification function is invoked when an instance of the
+ EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL is produced. It layers an instance of the
+ EFI_FIRMWARE_VOLUME2_PROTOCOL on the same handle. This is the function where
+ the actual initialization of the EFI_FIRMWARE_VOLUME2_PROTOCOL is done.
+
+ @param Event The event that occurred
+ @param Context For EFI compatiblity. Not used.
+
+**/
+VOID
+EFIAPI
+NotifyFwVolBlock (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ EFI_HANDLE Handle;
+ EFI_STATUS Status;
+ UINTN BufferSize;
+ EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb;
+ EFI_FIRMWARE_VOLUME2_PROTOCOL *Fv;
+ FV_DEVICE *FvDevice;
+ EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader;
+ //
+ // Examine all new handles
+ //
+ for (;;) {
+ //
+ // Get the next handle
+ //
+ BufferSize = sizeof (Handle);
+ Status = CoreLocateHandle (
+ ByRegisterNotify,
+ NULL,
+ gEfiFwVolBlockNotifyReg,
+ &BufferSize,
+ &Handle
+ );
+
+ //
+ // If not found, we're done
+ //
+ if (EFI_NOT_FOUND == Status) {
+ break;
+ }
+
+ if (EFI_ERROR (Status)) {
+ continue;
+ }
+
+ //
+ // Get the FirmwareVolumeBlock protocol on that handle
+ //
+ Status = CoreHandleProtocol (Handle, &gEfiFirmwareVolumeBlockProtocolGuid, (VOID **)&Fvb);
+ ASSERT_EFI_ERROR (Status);
+ ASSERT (Fvb != NULL);
+
+ //
+ // Make sure the Fv Header is O.K.
+ //
+ Status = GetFwVolHeader (Fvb, &FwVolHeader);
+ if (EFI_ERROR (Status)) {
+ continue;
+ }
+ ASSERT (FwVolHeader != NULL);
+
+ if (!VerifyFvHeaderChecksum (FwVolHeader)) {
+ CoreFreePool (FwVolHeader);
+ continue;
+ }
+
+ //
+ // Check if there is an FV protocol already installed in that handle
+ //
+ Status = CoreHandleProtocol (Handle, &gEfiFirmwareVolume2ProtocolGuid, (VOID **)&Fv);
+ if (!EFI_ERROR (Status)) {
+ //
+ // Update Fv to use a new Fvb
+ //
+ FvDevice = BASE_CR (Fv, FV_DEVICE, Fv);
+ if (FvDevice->Signature == FV2_DEVICE_SIGNATURE) {
+ //
+ // Only write into our device structure if it's our device structure
+ //
+ FvDevice->Fvb = Fvb;
+ }
+
+ } else {
+ //
+ // No FwVol protocol on the handle so create a new one
+ //
+ FvDevice = AllocateCopyPool (sizeof (FV_DEVICE), &mFvDevice);
+ if (FvDevice == NULL) {
+ return;
+ }
+
+ FvDevice->Fvb = Fvb;
+ FvDevice->Handle = Handle;
+ FvDevice->FwVolHeader = FwVolHeader;
+ FvDevice->IsFfs3Fv = CompareGuid (&FwVolHeader->FileSystemGuid, &gEfiFirmwareFileSystem3Guid);
+ FvDevice->Fv.ParentHandle = Fvb->ParentHandle;
+ //
+ // Inherit the authentication status from FVB.
+ //
+ FvDevice->AuthenticationStatus = GetFvbAuthenticationStatus (Fvb);
+
+ if (!EFI_ERROR (FvCheck (FvDevice))) {
+ //
+ // Install an New FV protocol on the existing handle
+ //
+ Status = CoreInstallProtocolInterface (
+ &Handle,
+ &gEfiFirmwareVolume2ProtocolGuid,
+ EFI_NATIVE_INTERFACE,
+ &FvDevice->Fv
+ );
+ ASSERT_EFI_ERROR (Status);
+ } else {
+ //
+ // Free FvDevice Buffer for the corrupt FV image.
+ //
+ CoreFreePool (FvDevice);
+ }
+ }
+ }
+
+ return;
+}
+
+
+
+/**
+ This routine is the driver initialization entry point. It registers
+ a notification function. This notification function are responsible
+ for building the FV stack dynamically.
+
+ @param ImageHandle The image handle.
+ @param SystemTable The system table.
+
+ @retval EFI_SUCCESS Function successfully returned.
+
+**/
+EFI_STATUS
+EFIAPI
+FwVolDriverInit (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ gEfiFwVolBlockEvent = EfiCreateProtocolNotifyEvent (
+ &gEfiFirmwareVolumeBlockProtocolGuid,
+ TPL_CALLBACK,
+ NotifyFwVolBlock,
+ NULL,
+ &gEfiFwVolBlockNotifyReg
+ );
+ return EFI_SUCCESS;
+}
+
+
diff --git a/roms/edk2/MdeModulePkg/Core/Dxe/FwVol/FwVolAttrib.c b/roms/edk2/MdeModulePkg/Core/Dxe/FwVol/FwVolAttrib.c
new file mode 100644
index 000000000..ab7b3feff
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Core/Dxe/FwVol/FwVolAttrib.c
@@ -0,0 +1,129 @@
+/** @file
+ Implements get/set firmware volume attributes
+
+Copyright (c) 2006 - 2012, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "DxeMain.h"
+#include "FwVolDriver.h"
+
+
+/**
+ Retrieves attributes, insures positive polarity of attribute bits, returns
+ resulting attributes in output parameter.
+
+ @param This Calling context
+ @param Attributes output buffer which contains attributes
+
+ @retval EFI_SUCCESS Successfully got volume attributes
+
+**/
+EFI_STATUS
+EFIAPI
+FvGetVolumeAttributes (
+ IN CONST EFI_FIRMWARE_VOLUME2_PROTOCOL *This,
+ OUT EFI_FV_ATTRIBUTES *Attributes
+ )
+{
+ EFI_STATUS Status;
+ FV_DEVICE *FvDevice;
+ EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb;
+ EFI_FVB_ATTRIBUTES_2 FvbAttributes;
+
+ FvDevice = FV_DEVICE_FROM_THIS (This);
+ Fvb = FvDevice->Fvb;
+
+ //
+ // First get the Firmware Volume Block Attributes
+ //
+ Status = Fvb->GetAttributes (Fvb, &FvbAttributes);
+
+ //
+ // Mask out Fvb bits that are not defined in FV
+ //
+ FvbAttributes &= 0xfffff0ff;
+
+ *Attributes = (EFI_FV_ATTRIBUTES)FvbAttributes;
+
+ return Status;
+}
+
+
+
+/**
+ Sets current attributes for volume
+
+ @param This Calling context
+ @param Attributes At input, contains attributes to be set. At output
+ contains new value of FV
+
+ @retval EFI_UNSUPPORTED Could not be set.
+
+**/
+EFI_STATUS
+EFIAPI
+FvSetVolumeAttributes (
+ IN CONST EFI_FIRMWARE_VOLUME2_PROTOCOL *This,
+ IN OUT EFI_FV_ATTRIBUTES *Attributes
+ )
+{
+ return EFI_UNSUPPORTED;
+}
+
+
+/**
+ Return information of type InformationType for the requested firmware
+ volume.
+
+ @param This Pointer to EFI_FIRMWARE_VOLUME2_PROTOCOL.
+ @param InformationType InformationType for requested.
+ @param BufferSize On input, size of Buffer.On output, the amount of data
+ returned in Buffer.
+ @param Buffer A poniter to the data buffer to return.
+
+ @retval EFI_SUCCESS Successfully got volume Information.
+
+**/
+EFI_STATUS
+EFIAPI
+FvGetVolumeInfo (
+ IN CONST EFI_FIRMWARE_VOLUME2_PROTOCOL *This,
+ IN CONST EFI_GUID *InformationType,
+ IN OUT UINTN *BufferSize,
+ OUT VOID *Buffer
+ )
+{
+ return EFI_UNSUPPORTED;
+}
+
+
+
+/**
+ Set information of type InformationType for the requested firmware
+ volume.
+
+ @param This Pointer to EFI_FIRMWARE_VOLUME2_PROTOCOL.
+ @param InformationType InformationType for requested.
+ @param BufferSize On input, size of Buffer.On output, the amount of data
+ returned in Buffer.
+ @param Buffer A poniter to the data buffer to return.
+
+ @retval EFI_SUCCESS Successfully set volume Information.
+
+**/
+EFI_STATUS
+EFIAPI
+FvSetVolumeInfo (
+ IN CONST EFI_FIRMWARE_VOLUME2_PROTOCOL *This,
+ IN CONST EFI_GUID *InformationType,
+ IN UINTN BufferSize,
+ IN CONST VOID *Buffer
+ )
+{
+ return EFI_UNSUPPORTED;
+}
+
+
+
diff --git a/roms/edk2/MdeModulePkg/Core/Dxe/FwVol/FwVolDriver.h b/roms/edk2/MdeModulePkg/Core/Dxe/FwVol/FwVolDriver.h
new file mode 100644
index 000000000..19ad39871
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Core/Dxe/FwVol/FwVolDriver.h
@@ -0,0 +1,402 @@
+/** @file
+ Firmware File System protocol. Layers on top of Firmware
+ Block protocol to produce a file abstraction of FV based files.
+
+Copyright (c) 2006 - 2014, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef __FW_VOL_DRIVER_H_
+#define __FW_VOL_DRIVER_H_
+
+
+#define FV2_DEVICE_SIGNATURE SIGNATURE_32 ('_', 'F', 'V', '2')
+
+//
+// Used to track all non-deleted files
+//
+typedef struct {
+ LIST_ENTRY Link;
+ EFI_FFS_FILE_HEADER *FfsHeader;
+ UINTN StreamHandle;
+ BOOLEAN FileCached;
+} FFS_FILE_LIST_ENTRY;
+
+typedef struct {
+ UINTN Signature;
+ EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb;
+ EFI_HANDLE Handle;
+ EFI_FIRMWARE_VOLUME2_PROTOCOL Fv;
+
+ EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader;
+ UINT8 *CachedFv;
+ UINT8 *EndOfCachedFv;
+
+ FFS_FILE_LIST_ENTRY *LastKey;
+
+ LIST_ENTRY FfsFileListHeader;
+
+ UINT32 AuthenticationStatus;
+ UINT8 ErasePolarity;
+ BOOLEAN IsFfs3Fv;
+ BOOLEAN IsMemoryMapped;
+} FV_DEVICE;
+
+#define FV_DEVICE_FROM_THIS(a) CR(a, FV_DEVICE, Fv, FV2_DEVICE_SIGNATURE)
+
+/**
+ Retrieves attributes, insures positive polarity of attribute bits, returns
+ resulting attributes in output parameter.
+
+ @param This Pointer to EFI_FIRMWARE_VOLUME2_PROTOCOL.
+ @param Attributes output buffer which contains attributes.
+
+ @retval EFI_SUCCESS Successfully got volume attributes.
+
+**/
+EFI_STATUS
+EFIAPI
+FvGetVolumeAttributes (
+ IN CONST EFI_FIRMWARE_VOLUME2_PROTOCOL *This,
+ OUT EFI_FV_ATTRIBUTES *Attributes
+ );
+
+
+/**
+ Sets current attributes for volume
+
+ @param This Pointer to EFI_FIRMWARE_VOLUME2_PROTOCOL.
+ @param Attributes At input, contains attributes to be set. At output
+ contains new value of FV.
+
+ @retval EFI_UNSUPPORTED Could not be set.
+
+**/
+EFI_STATUS
+EFIAPI
+FvSetVolumeAttributes (
+ IN CONST EFI_FIRMWARE_VOLUME2_PROTOCOL *This,
+ IN OUT EFI_FV_ATTRIBUTES *Attributes
+ );
+
+
+/**
+ Given the input key, search for the next matching file in the volume.
+
+ @param This Pointer to EFI_FIRMWARE_VOLUME2_PROTOCOL.
+ @param Key Key is a pointer to a caller allocated
+ buffer that contains implementation specific
+ data that is used to track where to begin
+ the search for the next file. The size of
+ the buffer must be at least This->KeySize
+ bytes long. To reinitialize the search and
+ begin from the beginning of the firmware
+ volume, the entire buffer must be cleared to
+ zero. Other than clearing the buffer to
+ initiate a new search, the caller must not
+ modify the data in the buffer between calls
+ to GetNextFile().
+ @param FileType FileType is a pointer to a caller allocated
+ EFI_FV_FILETYPE. The GetNextFile() API can
+ filter it's search for files based on the
+ value of *FileType input. A *FileType input
+ of 0 causes GetNextFile() to search for
+ files of all types. If a file is found, the
+ file's type is returned in *FileType.
+ *FileType is not modified if no file is
+ found.
+ @param NameGuid NameGuid is a pointer to a caller allocated
+ EFI_GUID. If a file is found, the file's
+ name is returned in *NameGuid. *NameGuid is
+ not modified if no file is found.
+ @param Attributes Attributes is a pointer to a caller
+ allocated EFI_FV_FILE_ATTRIBUTES. If a file
+ is found, the file's attributes are returned
+ in *Attributes. *Attributes is not modified
+ if no file is found.
+ @param Size Size is a pointer to a caller allocated
+ UINTN. If a file is found, the file's size
+ is returned in *Size. *Size is not modified
+ if no file is found.
+
+ @retval EFI_SUCCESS Successfully find the file.
+ @retval EFI_DEVICE_ERROR Device error.
+ @retval EFI_ACCESS_DENIED Fv could not read.
+ @retval EFI_NOT_FOUND No matching file found.
+ @retval EFI_INVALID_PARAMETER Invalid parameter
+
+**/
+EFI_STATUS
+EFIAPI
+FvGetNextFile (
+ IN CONST EFI_FIRMWARE_VOLUME2_PROTOCOL *This,
+ IN OUT VOID *Key,
+ IN OUT EFI_FV_FILETYPE *FileType,
+ OUT EFI_GUID *NameGuid,
+ OUT EFI_FV_FILE_ATTRIBUTES *Attributes,
+ OUT UINTN *Size
+ );
+
+
+
+/**
+ Locates a file in the firmware volume and
+ copies it to the supplied buffer.
+
+ @param This Pointer to EFI_FIRMWARE_VOLUME2_PROTOCOL.
+ @param NameGuid Pointer to an EFI_GUID, which is the
+ filename.
+ @param Buffer Buffer is a pointer to pointer to a buffer
+ in which the file or section contents or are
+ returned.
+ @param BufferSize BufferSize is a pointer to caller allocated
+ UINTN. On input *BufferSize indicates the
+ size in bytes of the memory region pointed
+ to by Buffer. On output, *BufferSize
+ contains the number of bytes required to
+ read the file.
+ @param FoundType FoundType is a pointer to a caller allocated
+ EFI_FV_FILETYPE that on successful return
+ from Read() contains the type of file read.
+ This output reflects the file type
+ irrespective of the value of the SectionType
+ input.
+ @param FileAttributes FileAttributes is a pointer to a caller
+ allocated EFI_FV_FILE_ATTRIBUTES. On
+ successful return from Read(),
+ *FileAttributes contains the attributes of
+ the file read.
+ @param AuthenticationStatus AuthenticationStatus is a pointer to a
+ caller allocated UINTN in which the
+ authentication status is returned.
+
+ @retval EFI_SUCCESS Successfully read to memory buffer.
+ @retval EFI_WARN_BUFFER_TOO_SMALL Buffer too small.
+ @retval EFI_NOT_FOUND Not found.
+ @retval EFI_DEVICE_ERROR Device error.
+ @retval EFI_ACCESS_DENIED Could not read.
+ @retval EFI_INVALID_PARAMETER Invalid parameter.
+ @retval EFI_OUT_OF_RESOURCES Not enough buffer to be allocated.
+
+**/
+EFI_STATUS
+EFIAPI
+FvReadFile (
+ IN CONST EFI_FIRMWARE_VOLUME2_PROTOCOL *This,
+ IN CONST EFI_GUID *NameGuid,
+ IN OUT VOID **Buffer,
+ IN OUT UINTN *BufferSize,
+ OUT EFI_FV_FILETYPE *FoundType,
+ OUT EFI_FV_FILE_ATTRIBUTES *FileAttributes,
+ OUT UINT32 *AuthenticationStatus
+ );
+
+
+/**
+ Locates a section in a given FFS File and
+ copies it to the supplied buffer (not including section header).
+
+ @param This Pointer to EFI_FIRMWARE_VOLUME2_PROTOCOL.
+ @param NameGuid Pointer to an EFI_GUID, which is the
+ filename.
+ @param SectionType Indicates the section type to return.
+ @param SectionInstance Indicates which instance of sections with a
+ type of SectionType to return.
+ @param Buffer Buffer is a pointer to pointer to a buffer
+ in which the file or section contents or are
+ returned.
+ @param BufferSize BufferSize is a pointer to caller allocated
+ UINTN.
+ @param AuthenticationStatus AuthenticationStatus is a pointer to a
+ caller allocated UINT32 in which the
+ authentication status is returned.
+
+ @retval EFI_SUCCESS Successfully read the file section into
+ buffer.
+ @retval EFI_WARN_BUFFER_TOO_SMALL Buffer too small.
+ @retval EFI_NOT_FOUND Section not found.
+ @retval EFI_DEVICE_ERROR Device error.
+ @retval EFI_ACCESS_DENIED Could not read.
+ @retval EFI_INVALID_PARAMETER Invalid parameter.
+
+**/
+EFI_STATUS
+EFIAPI
+FvReadFileSection (
+ IN CONST EFI_FIRMWARE_VOLUME2_PROTOCOL *This,
+ IN CONST EFI_GUID *NameGuid,
+ IN EFI_SECTION_TYPE SectionType,
+ IN UINTN SectionInstance,
+ IN OUT VOID **Buffer,
+ IN OUT UINTN *BufferSize,
+ OUT UINT32 *AuthenticationStatus
+ );
+
+
+/**
+ Writes one or more files to the firmware volume.
+
+ @param This Pointer to EFI_FIRMWARE_VOLUME2_PROTOCOL.
+ @param NumberOfFiles Number of files.
+ @param WritePolicy WritePolicy indicates the level of reliability
+ for the write in the event of a power failure or
+ other system failure during the write operation.
+ @param FileData FileData is an pointer to an array of
+ EFI_FV_WRITE_DATA. Each element of array
+ FileData represents a file to be written.
+
+ @retval EFI_SUCCESS Files successfully written to firmware volume
+ @retval EFI_OUT_OF_RESOURCES Not enough buffer to be allocated.
+ @retval EFI_DEVICE_ERROR Device error.
+ @retval EFI_WRITE_PROTECTED Write protected.
+ @retval EFI_NOT_FOUND Not found.
+ @retval EFI_INVALID_PARAMETER Invalid parameter.
+ @retval EFI_UNSUPPORTED This function not supported.
+
+**/
+EFI_STATUS
+EFIAPI
+FvWriteFile (
+ IN CONST EFI_FIRMWARE_VOLUME2_PROTOCOL *This,
+ IN UINT32 NumberOfFiles,
+ IN EFI_FV_WRITE_POLICY WritePolicy,
+ IN EFI_FV_WRITE_FILE_DATA *FileData
+ );
+
+
+/**
+ Return information of type InformationType for the requested firmware
+ volume.
+
+ @param This Pointer to EFI_FIRMWARE_VOLUME2_PROTOCOL.
+ @param InformationType InformationType for requested.
+ @param BufferSize On input, size of Buffer.On output, the amount of data
+ returned in Buffer.
+ @param Buffer A poniter to the data buffer to return.
+
+ @retval EFI_SUCCESS Successfully got volume Information.
+
+**/
+EFI_STATUS
+EFIAPI
+FvGetVolumeInfo (
+ IN CONST EFI_FIRMWARE_VOLUME2_PROTOCOL *This,
+ IN CONST EFI_GUID *InformationType,
+ IN OUT UINTN *BufferSize,
+ OUT VOID *Buffer
+ );
+
+
+
+/**
+ Set information of type InformationType for the requested firmware
+ volume.
+
+ @param This Pointer to EFI_FIRMWARE_VOLUME2_PROTOCOL.
+ @param InformationType InformationType for requested.
+ @param BufferSize On input, size of Buffer.On output, the amount of data
+ returned in Buffer.
+ @param Buffer A poniter to the data buffer to return.
+
+ @retval EFI_SUCCESS Successfully set volume Information.
+
+**/
+EFI_STATUS
+EFIAPI
+FvSetVolumeInfo (
+ IN CONST EFI_FIRMWARE_VOLUME2_PROTOCOL *This,
+ IN CONST EFI_GUID *InformationType,
+ IN UINTN BufferSize,
+ IN CONST VOID *Buffer
+ );
+
+
+
+/**
+ Check if a block of buffer is erased.
+
+ @param ErasePolarity Erase polarity attribute of the firmware volume
+ @param InBuffer The buffer to be checked
+ @param BufferSize Size of the buffer in bytes
+
+ @retval TRUE The block of buffer is erased
+ @retval FALSE The block of buffer is not erased
+
+**/
+BOOLEAN
+IsBufferErased (
+ IN UINT8 ErasePolarity,
+ IN VOID *InBuffer,
+ IN UINTN BufferSize
+ );
+
+
+/**
+ Get the FFS file state by checking the highest bit set in the header's state field.
+
+ @param ErasePolarity Erase polarity attribute of the firmware volume
+ @param FfsHeader Points to the FFS file header
+
+ @return FFS File state
+
+**/
+EFI_FFS_FILE_STATE
+GetFileState (
+ IN UINT8 ErasePolarity,
+ IN EFI_FFS_FILE_HEADER *FfsHeader
+ );
+
+
+/**
+ Set the FFS file state.
+
+ @param State The state to be set.
+ @param FfsHeader Points to the FFS file header
+
+ @return None.
+
+**/
+VOID
+SetFileState (
+ IN UINT8 State,
+ IN EFI_FFS_FILE_HEADER *FfsHeader
+ );
+
+/**
+ Check if it's a valid FFS file header.
+
+ @param ErasePolarity Erase polarity attribute of the firmware volume
+ @param FfsHeader Points to the FFS file header to be checked
+ @param FileState FFS file state to be returned
+
+ @retval TRUE Valid FFS file header
+ @retval FALSE Invalid FFS file header
+
+**/
+BOOLEAN
+IsValidFfsHeader (
+ IN UINT8 ErasePolarity,
+ IN EFI_FFS_FILE_HEADER *FfsHeader,
+ OUT EFI_FFS_FILE_STATE *FileState
+ );
+
+
+/**
+ Check if it's a valid FFS file.
+ Here we are sure that it has a valid FFS file header since we must call IsValidFfsHeader() first.
+
+ @param ErasePolarity Erase polarity attribute of the firmware volume
+ @param FfsHeader Points to the FFS file to be checked
+
+ @retval TRUE Valid FFS file
+ @retval FALSE Invalid FFS file
+
+**/
+BOOLEAN
+IsValidFfsFile (
+ IN UINT8 ErasePolarity,
+ IN EFI_FFS_FILE_HEADER *FfsHeader
+ );
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Core/Dxe/FwVol/FwVolRead.c b/roms/edk2/MdeModulePkg/Core/Dxe/FwVol/FwVolRead.c
new file mode 100644
index 000000000..2861cbf67
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Core/Dxe/FwVol/FwVolRead.c
@@ -0,0 +1,536 @@
+/** @file
+ Implements functions to read firmware file
+
+Copyright (c) 2006 - 2017, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "DxeMain.h"
+#include "FwVolDriver.h"
+
+/**
+Required Alignment Alignment Value in FFS FFS_ATTRIB_DATA_ALIGNMENT2 Alignment Value in
+(bytes) Attributes Field in FFS Attributes Field Firmware Volume Interfaces
+1 0 0 0
+16 1 0 4
+128 2 0 7
+512 3 0 9
+1 KB 4 0 10
+4 KB 5 0 12
+32 KB 6 0 15
+64 KB 7 0 16
+128 KB 0 1 17
+256 KB 1 1 18
+512 KB 2 1 19
+1 MB 3 1 20
+2 MB 4 1 21
+4 MB 5 1 22
+8 MB 6 1 23
+16 MB 7 1 24
+**/
+UINT8 mFvAttributes[] = {0, 4, 7, 9, 10, 12, 15, 16};
+UINT8 mFvAttributes2[] = {17, 18, 19, 20, 21, 22, 23, 24};
+
+/**
+ Convert the FFS File Attributes to FV File Attributes
+
+ @param FfsAttributes The attributes of UINT8 type.
+
+ @return The attributes of EFI_FV_FILE_ATTRIBUTES
+
+**/
+EFI_FV_FILE_ATTRIBUTES
+FfsAttributes2FvFileAttributes (
+ IN EFI_FFS_FILE_ATTRIBUTES FfsAttributes
+ )
+{
+ UINT8 DataAlignment;
+ EFI_FV_FILE_ATTRIBUTES FileAttribute;
+
+ DataAlignment = (UINT8) ((FfsAttributes & FFS_ATTRIB_DATA_ALIGNMENT) >> 3);
+ ASSERT (DataAlignment < 8);
+
+ if ((FfsAttributes & FFS_ATTRIB_DATA_ALIGNMENT_2) != 0) {
+ FileAttribute = (EFI_FV_FILE_ATTRIBUTES) mFvAttributes2[DataAlignment];
+ } else {
+ FileAttribute = (EFI_FV_FILE_ATTRIBUTES) mFvAttributes[DataAlignment];
+ }
+
+ if ((FfsAttributes & FFS_ATTRIB_FIXED) == FFS_ATTRIB_FIXED) {
+ FileAttribute |= EFI_FV_FILE_ATTRIB_FIXED;
+ }
+
+ return FileAttribute;
+}
+
+/**
+ Given the input key, search for the next matching file in the volume.
+
+ @param This Indicates the calling context.
+ @param Key Key is a pointer to a caller allocated
+ buffer that contains implementation specific
+ data that is used to track where to begin
+ the search for the next file. The size of
+ the buffer must be at least This->KeySize
+ bytes long. To reinitialize the search and
+ begin from the beginning of the firmware
+ volume, the entire buffer must be cleared to
+ zero. Other than clearing the buffer to
+ initiate a new search, the caller must not
+ modify the data in the buffer between calls
+ to GetNextFile().
+ @param FileType FileType is a pointer to a caller allocated
+ EFI_FV_FILETYPE. The GetNextFile() API can
+ filter it's search for files based on the
+ value of *FileType input. A *FileType input
+ of 0 causes GetNextFile() to search for
+ files of all types. If a file is found, the
+ file's type is returned in *FileType.
+ *FileType is not modified if no file is
+ found.
+ @param NameGuid NameGuid is a pointer to a caller allocated
+ EFI_GUID. If a file is found, the file's
+ name is returned in *NameGuid. *NameGuid is
+ not modified if no file is found.
+ @param Attributes Attributes is a pointer to a caller
+ allocated EFI_FV_FILE_ATTRIBUTES. If a file
+ is found, the file's attributes are returned
+ in *Attributes. *Attributes is not modified
+ if no file is found.
+ @param Size Size is a pointer to a caller allocated
+ UINTN. If a file is found, the file's size
+ is returned in *Size. *Size is not modified
+ if no file is found.
+
+ @retval EFI_SUCCESS Successfully find the file.
+ @retval EFI_DEVICE_ERROR Device error.
+ @retval EFI_ACCESS_DENIED Fv could not read.
+ @retval EFI_NOT_FOUND No matching file found.
+ @retval EFI_INVALID_PARAMETER Invalid parameter
+
+**/
+EFI_STATUS
+EFIAPI
+FvGetNextFile (
+ IN CONST EFI_FIRMWARE_VOLUME2_PROTOCOL *This,
+ IN OUT VOID *Key,
+ IN OUT EFI_FV_FILETYPE *FileType,
+ OUT EFI_GUID *NameGuid,
+ OUT EFI_FV_FILE_ATTRIBUTES *Attributes,
+ OUT UINTN *Size
+ )
+{
+ EFI_STATUS Status;
+ FV_DEVICE *FvDevice;
+ EFI_FV_ATTRIBUTES FvAttributes;
+ EFI_FFS_FILE_HEADER *FfsFileHeader;
+ UINTN *KeyValue;
+ LIST_ENTRY *Link;
+ FFS_FILE_LIST_ENTRY *FfsFileEntry;
+
+ FvDevice = FV_DEVICE_FROM_THIS (This);
+
+ Status = FvGetVolumeAttributes (This, &FvAttributes);
+ if (EFI_ERROR (Status)){
+ return Status;
+ }
+
+ //
+ // Check if read operation is enabled
+ //
+ if ((FvAttributes & EFI_FV2_READ_STATUS) == 0) {
+ return EFI_ACCESS_DENIED;
+ }
+
+ if (*FileType > EFI_FV_FILETYPE_SMM_CORE) {
+ //
+ // File type needs to be in 0 - 0x0D
+ //
+ return EFI_NOT_FOUND;
+ }
+
+ KeyValue = (UINTN *)Key;
+ for (;;) {
+ if (*KeyValue == 0) {
+ //
+ // Search for 1st matching file
+ //
+ Link = &FvDevice->FfsFileListHeader;
+ } else {
+ //
+ // Key is pointer to FFsFileEntry, so get next one
+ //
+ Link = (LIST_ENTRY *)(*KeyValue);
+ }
+
+ if (Link->ForwardLink == &FvDevice->FfsFileListHeader) {
+ //
+ // Next is end of list so we did not find data
+ //
+ return EFI_NOT_FOUND;
+ }
+
+ FfsFileEntry = (FFS_FILE_LIST_ENTRY *)Link->ForwardLink;
+ FfsFileHeader = (EFI_FFS_FILE_HEADER *)FfsFileEntry->FfsHeader;
+
+ //
+ // remember the key
+ //
+ *KeyValue = (UINTN)FfsFileEntry;
+
+ if (FfsFileHeader->Type == EFI_FV_FILETYPE_FFS_PAD) {
+ //
+ // we ignore pad files
+ //
+ continue;
+ }
+
+ if (*FileType == EFI_FV_FILETYPE_ALL) {
+ //
+ // Process all file types so we have a match
+ //
+ break;
+ }
+
+ if (*FileType == FfsFileHeader->Type) {
+ //
+ // Found a matching file type
+ //
+ break;
+ }
+
+ }
+
+ //
+ // Return FileType, NameGuid, and Attributes
+ //
+ *FileType = FfsFileHeader->Type;
+ CopyGuid (NameGuid, &FfsFileHeader->Name);
+ *Attributes = FfsAttributes2FvFileAttributes (FfsFileHeader->Attributes);
+ if ((FvDevice->FwVolHeader->Attributes & EFI_FVB2_MEMORY_MAPPED) == EFI_FVB2_MEMORY_MAPPED) {
+ *Attributes |= EFI_FV_FILE_ATTRIB_MEMORY_MAPPED;
+ }
+
+ //
+ // we need to substract the header size
+ //
+ if (IS_FFS_FILE2 (FfsFileHeader)) {
+ *Size = FFS_FILE2_SIZE (FfsFileHeader) - sizeof (EFI_FFS_FILE_HEADER2);
+ } else {
+ *Size = FFS_FILE_SIZE (FfsFileHeader) - sizeof (EFI_FFS_FILE_HEADER);
+ }
+
+ return EFI_SUCCESS;
+}
+
+
+
+/**
+ Locates a file in the firmware volume and
+ copies it to the supplied buffer.
+
+ @param This Indicates the calling context.
+ @param NameGuid Pointer to an EFI_GUID, which is the
+ filename.
+ @param Buffer Buffer is a pointer to pointer to a buffer
+ in which the file or section contents or are
+ returned.
+ @param BufferSize BufferSize is a pointer to caller allocated
+ UINTN. On input *BufferSize indicates the
+ size in bytes of the memory region pointed
+ to by Buffer. On output, *BufferSize
+ contains the number of bytes required to
+ read the file.
+ @param FoundType FoundType is a pointer to a caller allocated
+ EFI_FV_FILETYPE that on successful return
+ from Read() contains the type of file read.
+ This output reflects the file type
+ irrespective of the value of the SectionType
+ input.
+ @param FileAttributes FileAttributes is a pointer to a caller
+ allocated EFI_FV_FILE_ATTRIBUTES. On
+ successful return from Read(),
+ *FileAttributes contains the attributes of
+ the file read.
+ @param AuthenticationStatus AuthenticationStatus is a pointer to a
+ caller allocated UINTN in which the
+ authentication status is returned.
+
+ @retval EFI_SUCCESS Successfully read to memory buffer.
+ @retval EFI_WARN_BUFFER_TOO_SMALL Buffer too small.
+ @retval EFI_NOT_FOUND Not found.
+ @retval EFI_DEVICE_ERROR Device error.
+ @retval EFI_ACCESS_DENIED Could not read.
+ @retval EFI_INVALID_PARAMETER Invalid parameter.
+ @retval EFI_OUT_OF_RESOURCES Not enough buffer to be allocated.
+
+**/
+EFI_STATUS
+EFIAPI
+FvReadFile (
+ IN CONST EFI_FIRMWARE_VOLUME2_PROTOCOL *This,
+ IN CONST EFI_GUID *NameGuid,
+ IN OUT VOID **Buffer,
+ IN OUT UINTN *BufferSize,
+ OUT EFI_FV_FILETYPE *FoundType,
+ OUT EFI_FV_FILE_ATTRIBUTES *FileAttributes,
+ OUT UINT32 *AuthenticationStatus
+ )
+{
+ EFI_STATUS Status;
+ FV_DEVICE *FvDevice;
+ EFI_GUID SearchNameGuid;
+ EFI_FV_FILETYPE LocalFoundType;
+ EFI_FV_FILE_ATTRIBUTES LocalAttributes;
+ UINTN FileSize;
+ UINT8 *SrcPtr;
+ EFI_FFS_FILE_HEADER *FfsHeader;
+ UINTN InputBufferSize;
+ UINTN WholeFileSize;
+
+ if (NameGuid == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ FvDevice = FV_DEVICE_FROM_THIS (This);
+
+
+ //
+ // Keep looking until we find the matching NameGuid.
+ // The Key is really a FfsFileEntry
+ //
+ FvDevice->LastKey = 0;
+ do {
+ LocalFoundType = 0;
+ Status = FvGetNextFile (
+ This,
+ &FvDevice->LastKey,
+ &LocalFoundType,
+ &SearchNameGuid,
+ &LocalAttributes,
+ &FileSize
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_NOT_FOUND;
+ }
+ } while (!CompareGuid (&SearchNameGuid, NameGuid));
+
+ //
+ // Get a pointer to the header
+ //
+ FfsHeader = FvDevice->LastKey->FfsHeader;
+ if (FvDevice->IsMemoryMapped) {
+ //
+ // Memory mapped FV has not been cached, so here is to cache by file.
+ //
+ if (!FvDevice->LastKey->FileCached) {
+ //
+ // Cache FFS file to memory buffer.
+ //
+ WholeFileSize = IS_FFS_FILE2 (FfsHeader) ? FFS_FILE2_SIZE (FfsHeader): FFS_FILE_SIZE (FfsHeader);
+ FfsHeader = AllocateCopyPool (WholeFileSize, FfsHeader);
+ if (FfsHeader == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ //
+ // Let FfsHeader in FfsFileEntry point to the cached file buffer.
+ //
+ FvDevice->LastKey->FfsHeader = FfsHeader;
+ FvDevice->LastKey->FileCached = TRUE;
+ }
+ }
+
+ //
+ // Remember callers buffer size
+ //
+ InputBufferSize = *BufferSize;
+
+ //
+ // Calculate return values
+ //
+ *FoundType = FfsHeader->Type;
+ *FileAttributes = FfsAttributes2FvFileAttributes (FfsHeader->Attributes);
+ if ((FvDevice->FwVolHeader->Attributes & EFI_FVB2_MEMORY_MAPPED) == EFI_FVB2_MEMORY_MAPPED) {
+ *FileAttributes |= EFI_FV_FILE_ATTRIB_MEMORY_MAPPED;
+ }
+ //
+ // Inherit the authentication status.
+ //
+ *AuthenticationStatus = FvDevice->AuthenticationStatus;
+ *BufferSize = FileSize;
+
+ if (Buffer == NULL) {
+ //
+ // If Buffer is NULL, we only want to get the information collected so far
+ //
+ return EFI_SUCCESS;
+ }
+
+ //
+ // Skip over file header
+ //
+ if (IS_FFS_FILE2 (FfsHeader)) {
+ SrcPtr = ((UINT8 *) FfsHeader) + sizeof (EFI_FFS_FILE_HEADER2);
+ } else {
+ SrcPtr = ((UINT8 *) FfsHeader) + sizeof (EFI_FFS_FILE_HEADER);
+ }
+
+ Status = EFI_SUCCESS;
+ if (*Buffer == NULL) {
+ //
+ // Caller passed in a pointer so allocate buffer for them
+ //
+ *Buffer = AllocatePool (FileSize);
+ if (*Buffer == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ } else if (FileSize > InputBufferSize) {
+ //
+ // Callers buffer was not big enough
+ //
+ Status = EFI_WARN_BUFFER_TOO_SMALL;
+ FileSize = InputBufferSize;
+ }
+
+ //
+ // Copy data into callers buffer
+ //
+ CopyMem (*Buffer, SrcPtr, FileSize);
+
+ return Status;
+}
+
+
+
+/**
+ Locates a section in a given FFS File and
+ copies it to the supplied buffer (not including section header).
+
+ @param This Indicates the calling context.
+ @param NameGuid Pointer to an EFI_GUID, which is the
+ filename.
+ @param SectionType Indicates the section type to return.
+ @param SectionInstance Indicates which instance of sections with a
+ type of SectionType to return.
+ @param Buffer Buffer is a pointer to pointer to a buffer
+ in which the file or section contents or are
+ returned.
+ @param BufferSize BufferSize is a pointer to caller allocated
+ UINTN.
+ @param AuthenticationStatus AuthenticationStatus is a pointer to a
+ caller allocated UINT32 in which the
+ authentication status is returned.
+
+ @retval EFI_SUCCESS Successfully read the file section into
+ buffer.
+ @retval EFI_WARN_BUFFER_TOO_SMALL Buffer too small.
+ @retval EFI_NOT_FOUND Section not found.
+ @retval EFI_DEVICE_ERROR Device error.
+ @retval EFI_ACCESS_DENIED Could not read.
+ @retval EFI_INVALID_PARAMETER Invalid parameter.
+
+**/
+EFI_STATUS
+EFIAPI
+FvReadFileSection (
+ IN CONST EFI_FIRMWARE_VOLUME2_PROTOCOL *This,
+ IN CONST EFI_GUID *NameGuid,
+ IN EFI_SECTION_TYPE SectionType,
+ IN UINTN SectionInstance,
+ IN OUT VOID **Buffer,
+ IN OUT UINTN *BufferSize,
+ OUT UINT32 *AuthenticationStatus
+ )
+{
+ EFI_STATUS Status;
+ FV_DEVICE *FvDevice;
+ EFI_FV_FILETYPE FileType;
+ EFI_FV_FILE_ATTRIBUTES FileAttributes;
+ UINTN FileSize;
+ UINT8 *FileBuffer;
+ FFS_FILE_LIST_ENTRY *FfsEntry;
+
+ if (NameGuid == NULL || Buffer == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ FvDevice = FV_DEVICE_FROM_THIS (This);
+
+ //
+ // Read the file
+ //
+ Status = FvReadFile (
+ This,
+ NameGuid,
+ NULL,
+ &FileSize,
+ &FileType,
+ &FileAttributes,
+ AuthenticationStatus
+ );
+ //
+ // Get the last key used by our call to FvReadFile as it is the FfsEntry for this file.
+ //
+ FfsEntry = (FFS_FILE_LIST_ENTRY *) FvDevice->LastKey;
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ if (IS_FFS_FILE2 (FfsEntry->FfsHeader)) {
+ FileBuffer = ((UINT8 *) FfsEntry->FfsHeader) + sizeof (EFI_FFS_FILE_HEADER2);
+ } else {
+ FileBuffer = ((UINT8 *) FfsEntry->FfsHeader) + sizeof (EFI_FFS_FILE_HEADER);
+ }
+ //
+ // Check to see that the file actually HAS sections before we go any further.
+ //
+ if (FileType == EFI_FV_FILETYPE_RAW) {
+ Status = EFI_NOT_FOUND;
+ goto Done;
+ }
+
+ //
+ // Use FfsEntry to cache Section Extraction Protocol Information
+ //
+ if (FfsEntry->StreamHandle == 0) {
+ Status = OpenSectionStream (
+ FileSize,
+ FileBuffer,
+ &FfsEntry->StreamHandle
+ );
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+ }
+
+ //
+ // If SectionType == 0 We need the whole section stream
+ //
+ Status = GetSection (
+ FfsEntry->StreamHandle,
+ (SectionType == 0) ? NULL : &SectionType,
+ NULL,
+ (SectionType == 0) ? 0 : SectionInstance,
+ Buffer,
+ BufferSize,
+ AuthenticationStatus,
+ FvDevice->IsFfs3Fv
+ );
+
+ if (!EFI_ERROR (Status)) {
+ //
+ // Inherit the authentication status.
+ //
+ *AuthenticationStatus |= FvDevice->AuthenticationStatus;
+ }
+
+ //
+ // Close of stream defered to close of FfsHeader list to allow SEP to cache data
+ //
+
+Done:
+ return Status;
+}
+
+
diff --git a/roms/edk2/MdeModulePkg/Core/Dxe/FwVol/FwVolWrite.c b/roms/edk2/MdeModulePkg/Core/Dxe/FwVol/FwVolWrite.c
new file mode 100644
index 000000000..3a3b569b7
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Core/Dxe/FwVol/FwVolWrite.c
@@ -0,0 +1,46 @@
+/** @file
+ Implements functions to write firmware file
+
+Copyright (c) 2006 - 2008, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "DxeMain.h"
+#include "FwVolDriver.h"
+
+
+/**
+ Writes one or more files to the firmware volume.
+
+ @param This Indicates the calling context.
+ @param NumberOfFiles Number of files.
+ @param WritePolicy WritePolicy indicates the level of reliability
+ for the write in the event of a power failure or
+ other system failure during the write operation.
+ @param FileData FileData is an pointer to an array of
+ EFI_FV_WRITE_DATA. Each element of array
+ FileData represents a file to be written.
+
+ @retval EFI_SUCCESS Files successfully written to firmware volume
+ @retval EFI_OUT_OF_RESOURCES Not enough buffer to be allocated.
+ @retval EFI_DEVICE_ERROR Device error.
+ @retval EFI_WRITE_PROTECTED Write protected.
+ @retval EFI_NOT_FOUND Not found.
+ @retval EFI_INVALID_PARAMETER Invalid parameter.
+ @retval EFI_UNSUPPORTED This function not supported.
+
+**/
+EFI_STATUS
+EFIAPI
+FvWriteFile (
+ IN CONST EFI_FIRMWARE_VOLUME2_PROTOCOL *This,
+ IN UINT32 NumberOfFiles,
+ IN EFI_FV_WRITE_POLICY WritePolicy,
+ IN EFI_FV_WRITE_FILE_DATA *FileData
+ )
+{
+ return EFI_UNSUPPORTED;
+}
+
+
diff --git a/roms/edk2/MdeModulePkg/Core/Dxe/FwVolBlock/FwVolBlock.c b/roms/edk2/MdeModulePkg/Core/Dxe/FwVolBlock/FwVolBlock.c
new file mode 100644
index 000000000..95174c1e4
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Core/Dxe/FwVolBlock/FwVolBlock.c
@@ -0,0 +1,719 @@
+/** @file
+ Implementations for Firmware Volume Block protocol.
+
+ It consumes FV HOBs and creates read-only Firmare Volume Block protocol
+ instances for each of them.
+
+Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "DxeMain.h"
+#include "FwVolBlock.h"
+
+FV_MEMMAP_DEVICE_PATH mFvMemmapDevicePathTemplate = {
+ {
+ {
+ HARDWARE_DEVICE_PATH,
+ HW_MEMMAP_DP,
+ {
+ (UINT8)(sizeof (MEMMAP_DEVICE_PATH)),
+ (UINT8)(sizeof (MEMMAP_DEVICE_PATH) >> 8)
+ }
+ },
+ EfiMemoryMappedIO,
+ (EFI_PHYSICAL_ADDRESS) 0,
+ (EFI_PHYSICAL_ADDRESS) 0,
+ },
+ {
+ END_DEVICE_PATH_TYPE,
+ END_ENTIRE_DEVICE_PATH_SUBTYPE,
+ {
+ END_DEVICE_PATH_LENGTH,
+ 0
+ }
+ }
+};
+
+FV_PIWG_DEVICE_PATH mFvPIWGDevicePathTemplate = {
+ {
+ {
+ MEDIA_DEVICE_PATH,
+ MEDIA_PIWG_FW_VOL_DP,
+ {
+ (UINT8)(sizeof (MEDIA_FW_VOL_DEVICE_PATH)),
+ (UINT8)(sizeof (MEDIA_FW_VOL_DEVICE_PATH) >> 8)
+ }
+ },
+ { 0 }
+ },
+ {
+ END_DEVICE_PATH_TYPE,
+ END_ENTIRE_DEVICE_PATH_SUBTYPE,
+ {
+ END_DEVICE_PATH_LENGTH,
+ 0
+ }
+ }
+};
+
+EFI_FW_VOL_BLOCK_DEVICE mFwVolBlock = {
+ FVB_DEVICE_SIGNATURE,
+ NULL,
+ NULL,
+ {
+ FwVolBlockGetAttributes,
+ (EFI_FVB_SET_ATTRIBUTES)FwVolBlockSetAttributes,
+ FwVolBlockGetPhysicalAddress,
+ FwVolBlockGetBlockSize,
+ FwVolBlockReadBlock,
+ (EFI_FVB_WRITE)FwVolBlockWriteBlock,
+ (EFI_FVB_ERASE_BLOCKS)FwVolBlockEraseBlock,
+ NULL
+ },
+ 0,
+ NULL,
+ 0,
+ 0,
+ 0
+};
+
+
+
+/**
+ Retrieves Volume attributes. No polarity translations are done.
+
+ @param This Calling context
+ @param Attributes output buffer which contains attributes
+
+ @retval EFI_SUCCESS The firmware volume attributes were returned.
+
+**/
+EFI_STATUS
+EFIAPI
+FwVolBlockGetAttributes (
+ IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,
+ OUT EFI_FVB_ATTRIBUTES_2 *Attributes
+ )
+{
+ EFI_FW_VOL_BLOCK_DEVICE *FvbDevice;
+
+ FvbDevice = FVB_DEVICE_FROM_THIS (This);
+
+ //
+ // Since we are read only, it's safe to get attributes data from our in-memory copy.
+ //
+ *Attributes = FvbDevice->FvbAttributes & ~EFI_FVB2_WRITE_STATUS;
+
+ return EFI_SUCCESS;
+}
+
+
+
+/**
+ Modifies the current settings of the firmware volume according to the input parameter.
+
+ @param This Calling context
+ @param Attributes input buffer which contains attributes
+
+ @retval EFI_SUCCESS The firmware volume attributes were returned.
+ @retval EFI_INVALID_PARAMETER The attributes requested are in conflict with
+ the capabilities as declared in the firmware
+ volume header.
+ @retval EFI_UNSUPPORTED Not supported.
+
+**/
+EFI_STATUS
+EFIAPI
+FwVolBlockSetAttributes (
+ IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,
+ IN CONST EFI_FVB_ATTRIBUTES_2 *Attributes
+ )
+{
+ return EFI_UNSUPPORTED;
+}
+
+
+
+/**
+ The EraseBlock() function erases one or more blocks as denoted by the
+ variable argument list. The entire parameter list of blocks must be verified
+ prior to erasing any blocks. If a block is requested that does not exist
+ within the associated firmware volume (it has a larger index than the last
+ block of the firmware volume), the EraseBlock() function must return
+ EFI_INVALID_PARAMETER without modifying the contents of the firmware volume.
+
+ @param This Calling context
+ @param ... Starting LBA followed by Number of Lba to erase.
+ a -1 to terminate the list.
+
+ @retval EFI_SUCCESS The erase request was successfully completed.
+ @retval EFI_ACCESS_DENIED The firmware volume is in the WriteDisabled
+ state.
+ @retval EFI_DEVICE_ERROR The block device is not functioning correctly
+ and could not be written. The firmware device
+ may have been partially erased.
+ @retval EFI_INVALID_PARAMETER One or more of the LBAs listed in the variable
+ argument list do
+ @retval EFI_UNSUPPORTED Not supported.
+
+**/
+EFI_STATUS
+EFIAPI
+FwVolBlockEraseBlock (
+ IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,
+ ...
+ )
+{
+ return EFI_UNSUPPORTED;
+}
+
+
+
+/**
+ Read the specified number of bytes from the block to the input buffer.
+
+ @param This Indicates the calling context.
+ @param Lba The starting logical block index to read.
+ @param Offset Offset into the block at which to begin reading.
+ @param NumBytes Pointer to a UINT32. At entry, *NumBytes
+ contains the total size of the buffer. At exit,
+ *NumBytes contains the total number of bytes
+ actually read.
+ @param Buffer Pinter to a caller-allocated buffer that
+ contains the destine for the read.
+
+ @retval EFI_SUCCESS The firmware volume was read successfully.
+ @retval EFI_BAD_BUFFER_SIZE The read was attempted across an LBA boundary.
+ @retval EFI_ACCESS_DENIED Access denied.
+ @retval EFI_DEVICE_ERROR The block device is malfunctioning and could not
+ be read.
+
+**/
+EFI_STATUS
+EFIAPI
+FwVolBlockReadBlock (
+ IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,
+ IN CONST EFI_LBA Lba,
+ IN CONST UINTN Offset,
+ IN OUT UINTN *NumBytes,
+ IN OUT UINT8 *Buffer
+ )
+{
+ EFI_FW_VOL_BLOCK_DEVICE *FvbDevice;
+ EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader;
+ UINT8 *LbaOffset;
+ UINTN LbaStart;
+ UINTN NumOfBytesRead;
+ UINTN LbaIndex;
+
+ FvbDevice = FVB_DEVICE_FROM_THIS (This);
+
+ //
+ // Check if This FW can be read
+ //
+ if ((FvbDevice->FvbAttributes & EFI_FVB2_READ_STATUS) == 0) {
+ return EFI_ACCESS_DENIED;
+ }
+
+ LbaIndex = (UINTN) Lba;
+ if (LbaIndex >= FvbDevice->NumBlocks) {
+ //
+ // Invalid Lba, read nothing.
+ //
+ *NumBytes = 0;
+ return EFI_BAD_BUFFER_SIZE;
+ }
+
+ if (Offset > FvbDevice->LbaCache[LbaIndex].Length) {
+ //
+ // all exceed boundary, read nothing.
+ //
+ *NumBytes = 0;
+ return EFI_BAD_BUFFER_SIZE;
+ }
+
+ NumOfBytesRead = *NumBytes;
+ if (Offset + NumOfBytesRead > FvbDevice->LbaCache[LbaIndex].Length) {
+ //
+ // partial exceed boundary, read data from current postion to end.
+ //
+ NumOfBytesRead = FvbDevice->LbaCache[LbaIndex].Length - Offset;
+ }
+
+ LbaStart = FvbDevice->LbaCache[LbaIndex].Base;
+ FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *)((UINTN) FvbDevice->BaseAddress);
+ LbaOffset = (UINT8 *) FwVolHeader + LbaStart + Offset;
+
+ //
+ // Perform read operation
+ //
+ CopyMem (Buffer, LbaOffset, NumOfBytesRead);
+
+ if (NumOfBytesRead == *NumBytes) {
+ return EFI_SUCCESS;
+ }
+
+ *NumBytes = NumOfBytesRead;
+ return EFI_BAD_BUFFER_SIZE;
+}
+
+
+
+/**
+ Writes the specified number of bytes from the input buffer to the block.
+
+ @param This Indicates the calling context.
+ @param Lba The starting logical block index to write to.
+ @param Offset Offset into the block at which to begin writing.
+ @param NumBytes Pointer to a UINT32. At entry, *NumBytes
+ contains the total size of the buffer. At exit,
+ *NumBytes contains the total number of bytes
+ actually written.
+ @param Buffer Pinter to a caller-allocated buffer that
+ contains the source for the write.
+
+ @retval EFI_SUCCESS The firmware volume was written successfully.
+ @retval EFI_BAD_BUFFER_SIZE The write was attempted across an LBA boundary.
+ On output, NumBytes contains the total number of
+ bytes actually written.
+ @retval EFI_ACCESS_DENIED The firmware volume is in the WriteDisabled
+ state.
+ @retval EFI_DEVICE_ERROR The block device is malfunctioning and could not
+ be written.
+ @retval EFI_UNSUPPORTED Not supported.
+
+**/
+EFI_STATUS
+EFIAPI
+FwVolBlockWriteBlock (
+ IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,
+ IN EFI_LBA Lba,
+ IN UINTN Offset,
+ IN OUT UINTN *NumBytes,
+ IN UINT8 *Buffer
+ )
+{
+ return EFI_UNSUPPORTED;
+}
+
+
+
+/**
+ Get Fvb's base address.
+
+ @param This Indicates the calling context.
+ @param Address Fvb device base address.
+
+ @retval EFI_SUCCESS Successfully got Fvb's base address.
+ @retval EFI_UNSUPPORTED Not supported.
+
+**/
+EFI_STATUS
+EFIAPI
+FwVolBlockGetPhysicalAddress (
+ IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,
+ OUT EFI_PHYSICAL_ADDRESS *Address
+ )
+{
+ EFI_FW_VOL_BLOCK_DEVICE *FvbDevice;
+
+ FvbDevice = FVB_DEVICE_FROM_THIS (This);
+
+ if ((FvbDevice->FvbAttributes & EFI_FVB2_MEMORY_MAPPED) != 0) {
+ *Address = FvbDevice->BaseAddress;
+ return EFI_SUCCESS;
+ }
+
+ return EFI_UNSUPPORTED;
+}
+
+
+
+/**
+ Retrieves the size in bytes of a specific block within a firmware volume.
+
+ @param This Indicates the calling context.
+ @param Lba Indicates the block for which to return the
+ size.
+ @param BlockSize Pointer to a caller-allocated UINTN in which the
+ size of the block is returned.
+ @param NumberOfBlocks Pointer to a caller-allocated UINTN in which the
+ number of consecutive blocks starting with Lba
+ is returned. All blocks in this range have a
+ size of BlockSize.
+
+ @retval EFI_SUCCESS The firmware volume base address is returned.
+ @retval EFI_INVALID_PARAMETER The requested LBA is out of range.
+
+**/
+EFI_STATUS
+EFIAPI
+FwVolBlockGetBlockSize (
+ IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,
+ IN CONST EFI_LBA Lba,
+ IN OUT UINTN *BlockSize,
+ IN OUT UINTN *NumberOfBlocks
+ )
+{
+ UINTN TotalBlocks;
+ EFI_FW_VOL_BLOCK_DEVICE *FvbDevice;
+ EFI_FV_BLOCK_MAP_ENTRY *PtrBlockMapEntry;
+ EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader;
+
+ FvbDevice = FVB_DEVICE_FROM_THIS (This);
+
+ //
+ // Do parameter checking
+ //
+ if (Lba >= FvbDevice->NumBlocks) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *)((UINTN)FvbDevice->BaseAddress);
+
+ PtrBlockMapEntry = FwVolHeader->BlockMap;
+
+ //
+ // Search the block map for the given block
+ //
+ TotalBlocks = 0;
+ while ((PtrBlockMapEntry->NumBlocks != 0) || (PtrBlockMapEntry->Length !=0 )) {
+ TotalBlocks += PtrBlockMapEntry->NumBlocks;
+ if (Lba < TotalBlocks) {
+ //
+ // We find the range
+ //
+ break;
+ }
+
+ PtrBlockMapEntry++;
+ }
+
+ *BlockSize = PtrBlockMapEntry->Length;
+ *NumberOfBlocks = TotalBlocks - (UINTN)Lba;
+
+ return EFI_SUCCESS;
+}
+
+/**
+
+ Get FVB authentication status
+
+ @param FvbProtocol FVB protocol.
+
+ @return Authentication status.
+
+**/
+UINT32
+GetFvbAuthenticationStatus (
+ IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *FvbProtocol
+ )
+{
+ EFI_FW_VOL_BLOCK_DEVICE *FvbDevice;
+ UINT32 AuthenticationStatus;
+
+ AuthenticationStatus = 0;
+ FvbDevice = BASE_CR (FvbProtocol, EFI_FW_VOL_BLOCK_DEVICE, FwVolBlockInstance);
+ if (FvbDevice->Signature == FVB_DEVICE_SIGNATURE) {
+ AuthenticationStatus = FvbDevice->AuthenticationStatus;
+ }
+
+ return AuthenticationStatus;
+}
+
+/**
+ This routine produces a firmware volume block protocol on a given
+ buffer.
+
+ @param BaseAddress base address of the firmware volume image
+ @param Length length of the firmware volume image
+ @param ParentHandle handle of parent firmware volume, if this image
+ came from an FV image file and section in another firmware
+ volume (ala capsules)
+ @param AuthenticationStatus Authentication status inherited, if this image
+ came from an FV image file and section in another firmware volume.
+ @param FvProtocol Firmware volume block protocol produced.
+
+ @retval EFI_VOLUME_CORRUPTED Volume corrupted.
+ @retval EFI_OUT_OF_RESOURCES No enough buffer to be allocated.
+ @retval EFI_SUCCESS Successfully produced a FVB protocol on given
+ buffer.
+
+**/
+EFI_STATUS
+ProduceFVBProtocolOnBuffer (
+ IN EFI_PHYSICAL_ADDRESS BaseAddress,
+ IN UINT64 Length,
+ IN EFI_HANDLE ParentHandle,
+ IN UINT32 AuthenticationStatus,
+ OUT EFI_HANDLE *FvProtocol OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+ EFI_FW_VOL_BLOCK_DEVICE *FvbDev;
+ EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader;
+ UINTN BlockIndex;
+ UINTN BlockIndex2;
+ UINTN LinearOffset;
+ UINT32 FvAlignment;
+ EFI_FV_BLOCK_MAP_ENTRY *PtrBlockMapEntry;
+
+ FvAlignment = 0;
+ FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *)(UINTN) BaseAddress;
+ //
+ // Validate FV Header, if not as expected, return
+ //
+ if (FwVolHeader->Signature != EFI_FVH_SIGNATURE) {
+ return EFI_VOLUME_CORRUPTED;
+ }
+
+ //
+ // If EFI_FVB2_WEAK_ALIGNMENT is set in the volume header then the first byte of the volume
+ // can be aligned on any power-of-two boundary. A weakly aligned volume can not be moved from
+ // its initial linked location and maintain its alignment.
+ //
+ if ((FwVolHeader->Attributes & EFI_FVB2_WEAK_ALIGNMENT) != EFI_FVB2_WEAK_ALIGNMENT) {
+ //
+ // Get FvHeader alignment
+ //
+ FvAlignment = 1 << ((FwVolHeader->Attributes & EFI_FVB2_ALIGNMENT) >> 16);
+ //
+ // FvAlignment must be greater than or equal to 8 bytes of the minimum FFS alignment value.
+ //
+ if (FvAlignment < 8) {
+ FvAlignment = 8;
+ }
+ if ((UINTN)BaseAddress % FvAlignment != 0) {
+ //
+ // FvImage buffer is not at its required alignment.
+ //
+ DEBUG ((
+ DEBUG_ERROR,
+ "Unaligned FvImage found at 0x%lx:0x%lx, the required alignment is 0x%x\n",
+ BaseAddress,
+ Length,
+ FvAlignment
+ ));
+ return EFI_VOLUME_CORRUPTED;
+ }
+ }
+
+ //
+ // Allocate EFI_FW_VOL_BLOCK_DEVICE
+ //
+ FvbDev = AllocateCopyPool (sizeof (EFI_FW_VOL_BLOCK_DEVICE), &mFwVolBlock);
+ if (FvbDev == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ FvbDev->BaseAddress = BaseAddress;
+ FvbDev->FvbAttributes = FwVolHeader->Attributes;
+ FvbDev->FwVolBlockInstance.ParentHandle = ParentHandle;
+ FvbDev->AuthenticationStatus = AuthenticationStatus;
+
+ //
+ // Init the block caching fields of the device
+ // First, count the number of blocks
+ //
+ FvbDev->NumBlocks = 0;
+ for (PtrBlockMapEntry = FwVolHeader->BlockMap;
+ PtrBlockMapEntry->NumBlocks != 0;
+ PtrBlockMapEntry++) {
+ FvbDev->NumBlocks += PtrBlockMapEntry->NumBlocks;
+ }
+
+ //
+ // Second, allocate the cache
+ //
+ if (FvbDev->NumBlocks >= (MAX_ADDRESS / sizeof (LBA_CACHE))) {
+ CoreFreePool (FvbDev);
+ return EFI_OUT_OF_RESOURCES;
+ }
+ FvbDev->LbaCache = AllocatePool (FvbDev->NumBlocks * sizeof (LBA_CACHE));
+ if (FvbDev->LbaCache == NULL) {
+ CoreFreePool (FvbDev);
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ //
+ // Last, fill in the cache with the linear address of the blocks
+ //
+ BlockIndex = 0;
+ LinearOffset = 0;
+ for (PtrBlockMapEntry = FwVolHeader->BlockMap;
+ PtrBlockMapEntry->NumBlocks != 0; PtrBlockMapEntry++) {
+ for (BlockIndex2 = 0; BlockIndex2 < PtrBlockMapEntry->NumBlocks; BlockIndex2++) {
+ FvbDev->LbaCache[BlockIndex].Base = LinearOffset;
+ FvbDev->LbaCache[BlockIndex].Length = PtrBlockMapEntry->Length;
+ LinearOffset += PtrBlockMapEntry->Length;
+ BlockIndex++;
+ }
+ }
+
+ //
+ // Judget whether FV name guid is produced in Fv extension header
+ //
+ if (FwVolHeader->ExtHeaderOffset == 0) {
+ //
+ // FV does not contains extension header, then produce MEMMAP_DEVICE_PATH
+ //
+ FvbDev->DevicePath = (EFI_DEVICE_PATH_PROTOCOL *) AllocateCopyPool (sizeof (FV_MEMMAP_DEVICE_PATH), &mFvMemmapDevicePathTemplate);
+ if (FvbDev->DevicePath == NULL) {
+ FreePool (FvbDev);
+ return EFI_OUT_OF_RESOURCES;
+ }
+ ((FV_MEMMAP_DEVICE_PATH *) FvbDev->DevicePath)->MemMapDevPath.StartingAddress = BaseAddress;
+ ((FV_MEMMAP_DEVICE_PATH *) FvbDev->DevicePath)->MemMapDevPath.EndingAddress = BaseAddress + FwVolHeader->FvLength - 1;
+ } else {
+ //
+ // FV contains extension header, then produce MEDIA_FW_VOL_DEVICE_PATH
+ //
+ FvbDev->DevicePath = (EFI_DEVICE_PATH_PROTOCOL *) AllocateCopyPool (sizeof (FV_PIWG_DEVICE_PATH), &mFvPIWGDevicePathTemplate);
+ if (FvbDev->DevicePath == NULL) {
+ FreePool (FvbDev);
+ return EFI_OUT_OF_RESOURCES;
+ }
+ CopyGuid (
+ &((FV_PIWG_DEVICE_PATH *)FvbDev->DevicePath)->FvDevPath.FvName,
+ (GUID *)(UINTN)(BaseAddress + FwVolHeader->ExtHeaderOffset)
+ );
+ }
+
+ //
+ //
+ // Attach FvVolBlock Protocol to new handle
+ //
+ Status = CoreInstallMultipleProtocolInterfaces (
+ &FvbDev->Handle,
+ &gEfiFirmwareVolumeBlockProtocolGuid, &FvbDev->FwVolBlockInstance,
+ &gEfiDevicePathProtocolGuid, FvbDev->DevicePath,
+ NULL
+ );
+
+ //
+ // If they want the handle back, set it.
+ //
+ if (FvProtocol != NULL) {
+ *FvProtocol = FvbDev->Handle;
+ }
+
+ return Status;
+}
+
+
+
+/**
+ This routine consumes FV hobs and produces instances of FW_VOL_BLOCK_PROTOCOL as appropriate.
+
+ @param ImageHandle The image handle.
+ @param SystemTable The system table.
+
+ @retval EFI_SUCCESS Successfully initialized firmware volume block
+ driver.
+
+**/
+EFI_STATUS
+EFIAPI
+FwVolBlockDriverInit (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_PEI_HOB_POINTERS FvHob;
+ EFI_PEI_HOB_POINTERS Fv3Hob;
+ UINT32 AuthenticationStatus;
+
+ //
+ // Core Needs Firmware Volumes to function
+ //
+ FvHob.Raw = GetHobList ();
+ while ((FvHob.Raw = GetNextHob (EFI_HOB_TYPE_FV, FvHob.Raw)) != NULL) {
+ AuthenticationStatus = 0;
+ //
+ // Get the authentication status propagated from PEI-phase to DXE.
+ //
+ Fv3Hob.Raw = GetHobList ();
+ while ((Fv3Hob.Raw = GetNextHob (EFI_HOB_TYPE_FV3, Fv3Hob.Raw)) != NULL) {
+ if ((Fv3Hob.FirmwareVolume3->BaseAddress == FvHob.FirmwareVolume->BaseAddress) &&
+ (Fv3Hob.FirmwareVolume3->Length == FvHob.FirmwareVolume->Length)) {
+ AuthenticationStatus = Fv3Hob.FirmwareVolume3->AuthenticationStatus;
+ break;
+ }
+ Fv3Hob.Raw = GET_NEXT_HOB (Fv3Hob);
+ }
+ //
+ // Produce an FVB protocol for it
+ //
+ ProduceFVBProtocolOnBuffer (FvHob.FirmwareVolume->BaseAddress, FvHob.FirmwareVolume->Length, NULL, AuthenticationStatus, NULL);
+ FvHob.Raw = GET_NEXT_HOB (FvHob);
+ }
+
+ return EFI_SUCCESS;
+}
+
+
+
+/**
+ This DXE service routine is used to process a firmware volume. In
+ particular, it can be called by BDS to process a single firmware
+ volume found in a capsule.
+
+ Caution: The caller need validate the input firmware volume to follow
+ PI specification.
+ DxeCore will trust the input data and process firmware volume directly.
+
+ @param FvHeader pointer to a firmware volume header
+ @param Size the size of the buffer pointed to by FvHeader
+ @param FVProtocolHandle the handle on which a firmware volume protocol
+ was produced for the firmware volume passed in.
+
+ @retval EFI_OUT_OF_RESOURCES if an FVB could not be produced due to lack of
+ system resources
+ @retval EFI_VOLUME_CORRUPTED if the volume was corrupted
+ @retval EFI_SUCCESS a firmware volume protocol was produced for the
+ firmware volume
+
+**/
+EFI_STATUS
+EFIAPI
+CoreProcessFirmwareVolume (
+ IN VOID *FvHeader,
+ IN UINTN Size,
+ OUT EFI_HANDLE *FVProtocolHandle
+ )
+{
+ VOID *Ptr;
+ EFI_STATUS Status;
+
+ *FVProtocolHandle = NULL;
+ Status = ProduceFVBProtocolOnBuffer (
+ (EFI_PHYSICAL_ADDRESS) (UINTN) FvHeader,
+ (UINT64)Size,
+ NULL,
+ 0,
+ FVProtocolHandle
+ );
+ //
+ // Since in our implementation we use register-protocol-notify to put a
+ // FV protocol on the FVB protocol handle, we can't directly verify that
+ // the FV protocol was produced. Therefore here we will check the handle
+ // and make sure an FV protocol is on it. This indicates that all went
+ // well. Otherwise we have to assume that the volume was corrupted
+ // somehow.
+ //
+ if (!EFI_ERROR(Status)) {
+ ASSERT (*FVProtocolHandle != NULL);
+ Ptr = NULL;
+ Status = CoreHandleProtocol (*FVProtocolHandle, &gEfiFirmwareVolume2ProtocolGuid, (VOID **) &Ptr);
+ if (EFI_ERROR(Status) || (Ptr == NULL)) {
+ return EFI_VOLUME_CORRUPTED;
+ }
+ return EFI_SUCCESS;
+ }
+ return Status;
+}
+
+
+
diff --git a/roms/edk2/MdeModulePkg/Core/Dxe/FwVolBlock/FwVolBlock.h b/roms/edk2/MdeModulePkg/Core/Dxe/FwVolBlock/FwVolBlock.h
new file mode 100644
index 000000000..2205e9e77
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Core/Dxe/FwVolBlock/FwVolBlock.h
@@ -0,0 +1,238 @@
+/** @file
+ Firmware Volume Block protocol functions.
+ Consumes FV hobs and creates appropriate block protocols.
+
+Copyright (c) 2006 - 2012, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _FWVOL_BLOCK_H_
+#define _FWVOL_BLOCK_H_
+
+
+#define FVB_DEVICE_SIGNATURE SIGNATURE_32('_','F','V','B')
+
+
+typedef struct {
+ UINTN Base;
+ UINTN Length;
+} LBA_CACHE;
+
+typedef struct {
+ MEMMAP_DEVICE_PATH MemMapDevPath;
+ EFI_DEVICE_PATH_PROTOCOL EndDevPath;
+} FV_MEMMAP_DEVICE_PATH;
+
+//
+// UEFI Specification define FV device path format if FV provide name guid in extension header
+//
+typedef struct {
+ MEDIA_FW_VOL_DEVICE_PATH FvDevPath;
+ EFI_DEVICE_PATH_PROTOCOL EndDevPath;
+} FV_PIWG_DEVICE_PATH;
+
+typedef struct {
+ UINTN Signature;
+ EFI_HANDLE Handle;
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;
+ EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL FwVolBlockInstance;
+ UINTN NumBlocks;
+ LBA_CACHE *LbaCache;
+ UINT32 FvbAttributes;
+ EFI_PHYSICAL_ADDRESS BaseAddress;
+ UINT32 AuthenticationStatus;
+} EFI_FW_VOL_BLOCK_DEVICE;
+
+
+#define FVB_DEVICE_FROM_THIS(a) \
+ CR(a, EFI_FW_VOL_BLOCK_DEVICE, FwVolBlockInstance, FVB_DEVICE_SIGNATURE)
+
+
+/**
+ Retrieves Volume attributes. No polarity translations are done.
+
+ @param This Calling context
+ @param Attributes output buffer which contains attributes
+
+ @retval EFI_SUCCESS The firmware volume attributes were returned.
+
+**/
+EFI_STATUS
+EFIAPI
+FwVolBlockGetAttributes (
+ IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,
+ OUT EFI_FVB_ATTRIBUTES_2 *Attributes
+ );
+
+
+
+/**
+ Modifies the current settings of the firmware volume according to the input parameter.
+
+ @param This Calling context
+ @param Attributes input buffer which contains attributes
+
+ @retval EFI_SUCCESS The firmware volume attributes were returned.
+ @retval EFI_INVALID_PARAMETER The attributes requested are in conflict with
+ the capabilities as declared in the firmware
+ volume header.
+ @retval EFI_UNSUPPORTED Not supported.
+
+**/
+EFI_STATUS
+EFIAPI
+FwVolBlockSetAttributes (
+ IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,
+ IN CONST EFI_FVB_ATTRIBUTES_2 *Attributes
+ );
+
+
+
+/**
+ The EraseBlock() function erases one or more blocks as denoted by the
+ variable argument list. The entire parameter list of blocks must be verified
+ prior to erasing any blocks. If a block is requested that does not exist
+ within the associated firmware volume (it has a larger index than the last
+ block of the firmware volume), the EraseBlock() function must return
+ EFI_INVALID_PARAMETER without modifying the contents of the firmware volume.
+
+ @param This Calling context
+ @param ... Starting LBA followed by Number of Lba to erase.
+ a -1 to terminate the list.
+
+ @retval EFI_SUCCESS The erase request was successfully completed.
+ @retval EFI_ACCESS_DENIED The firmware volume is in the WriteDisabled
+ state.
+ @retval EFI_DEVICE_ERROR The block device is not functioning correctly
+ and could not be written. The firmware device
+ may have been partially erased.
+ @retval EFI_INVALID_PARAMETER One or more of the LBAs listed in the variable
+ argument list do
+ @retval EFI_UNSUPPORTED Not supported.
+
+**/
+EFI_STATUS
+EFIAPI
+FwVolBlockEraseBlock (
+ IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,
+ ...
+ );
+
+
+
+/**
+ Read the specified number of bytes from the block to the input buffer.
+
+ @param This Indicates the calling context.
+ @param Lba The starting logical block index to read.
+ @param Offset Offset into the block at which to begin reading.
+ @param NumBytes Pointer to a UINT32. At entry, *NumBytes
+ contains the total size of the buffer. At exit,
+ *NumBytes contains the total number of bytes
+ actually read.
+ @param Buffer Pinter to a caller-allocated buffer that
+ contains the destine for the read.
+
+ @retval EFI_SUCCESS The firmware volume was read successfully.
+ @retval EFI_BAD_BUFFER_SIZE The read was attempted across an LBA boundary.
+ @retval EFI_ACCESS_DENIED Access denied.
+ @retval EFI_DEVICE_ERROR The block device is malfunctioning and could not
+ be read.
+
+**/
+EFI_STATUS
+EFIAPI
+FwVolBlockReadBlock (
+ IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,
+ IN CONST EFI_LBA Lba,
+ IN CONST UINTN Offset,
+ IN OUT UINTN *NumBytes,
+ IN OUT UINT8 *Buffer
+ );
+
+
+
+/**
+ Writes the specified number of bytes from the input buffer to the block.
+
+ @param This Indicates the calling context.
+ @param Lba The starting logical block index to write to.
+ @param Offset Offset into the block at which to begin writing.
+ @param NumBytes Pointer to a UINT32. At entry, *NumBytes
+ contains the total size of the buffer. At exit,
+ *NumBytes contains the total number of bytes
+ actually written.
+ @param Buffer Pinter to a caller-allocated buffer that
+ contains the source for the write.
+
+ @retval EFI_SUCCESS The firmware volume was written successfully.
+ @retval EFI_BAD_BUFFER_SIZE The write was attempted across an LBA boundary.
+ On output, NumBytes contains the total number of
+ bytes actually written.
+ @retval EFI_ACCESS_DENIED The firmware volume is in the WriteDisabled
+ state.
+ @retval EFI_DEVICE_ERROR The block device is malfunctioning and could not
+ be written.
+ @retval EFI_UNSUPPORTED Not supported.
+
+**/
+EFI_STATUS
+EFIAPI
+FwVolBlockWriteBlock (
+ IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,
+ IN EFI_LBA Lba,
+ IN UINTN Offset,
+ IN OUT UINTN *NumBytes,
+ IN UINT8 *Buffer
+ );
+
+
+
+/**
+ Get Fvb's base address.
+
+ @param This Indicates the calling context.
+ @param Address Fvb device base address.
+
+ @retval EFI_SUCCESS Successfully got Fvb's base address.
+ @retval EFI_UNSUPPORTED Not supported.
+
+**/
+EFI_STATUS
+EFIAPI
+FwVolBlockGetPhysicalAddress (
+ IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,
+ OUT EFI_PHYSICAL_ADDRESS *Address
+ );
+
+
+
+/**
+ Retrieves the size in bytes of a specific block within a firmware volume.
+
+ @param This Indicates the calling context.
+ @param Lba Indicates the block for which to return the
+ size.
+ @param BlockSize Pointer to a caller-allocated UINTN in which the
+ size of the block is returned.
+ @param NumberOfBlocks Pointer to a caller-allocated UINTN in which the
+ number of consecutive blocks starting with Lba
+ is returned. All blocks in this range have a
+ size of BlockSize.
+
+ @retval EFI_SUCCESS The firmware volume base address is returned.
+ @retval EFI_INVALID_PARAMETER The requested LBA is out of range.
+
+**/
+EFI_STATUS
+EFIAPI
+FwVolBlockGetBlockSize (
+ IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,
+ IN CONST EFI_LBA Lba,
+ IN OUT UINTN *BlockSize,
+ IN OUT UINTN *NumberOfBlocks
+ );
+
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Core/Dxe/Gcd/Gcd.c b/roms/edk2/MdeModulePkg/Core/Dxe/Gcd/Gcd.c
new file mode 100644
index 000000000..2d8c076f7
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Core/Dxe/Gcd/Gcd.c
@@ -0,0 +1,2675 @@
+/** @file
+ The file contains the GCD related services in the EFI Boot Services Table.
+ The GCD services are used to manage the memory and I/O regions that
+ are accessible to the CPU that is executing the DXE core.
+
+Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "DxeMain.h"
+#include "Gcd.h"
+#include "Mem/HeapGuard.h"
+
+#define MINIMUM_INITIAL_MEMORY_SIZE 0x10000
+
+#define MEMORY_ATTRIBUTE_MASK (EFI_RESOURCE_ATTRIBUTE_PRESENT | \
+ EFI_RESOURCE_ATTRIBUTE_INITIALIZED | \
+ EFI_RESOURCE_ATTRIBUTE_TESTED | \
+ EFI_RESOURCE_ATTRIBUTE_READ_PROTECTED | \
+ EFI_RESOURCE_ATTRIBUTE_WRITE_PROTECTED | \
+ EFI_RESOURCE_ATTRIBUTE_EXECUTION_PROTECTED | \
+ EFI_RESOURCE_ATTRIBUTE_READ_ONLY_PROTECTED | \
+ EFI_RESOURCE_ATTRIBUTE_16_BIT_IO | \
+ EFI_RESOURCE_ATTRIBUTE_32_BIT_IO | \
+ EFI_RESOURCE_ATTRIBUTE_64_BIT_IO | \
+ EFI_RESOURCE_ATTRIBUTE_PERSISTENT )
+
+#define TESTED_MEMORY_ATTRIBUTES (EFI_RESOURCE_ATTRIBUTE_PRESENT | \
+ EFI_RESOURCE_ATTRIBUTE_INITIALIZED | \
+ EFI_RESOURCE_ATTRIBUTE_TESTED )
+
+#define INITIALIZED_MEMORY_ATTRIBUTES (EFI_RESOURCE_ATTRIBUTE_PRESENT | \
+ EFI_RESOURCE_ATTRIBUTE_INITIALIZED )
+
+#define PRESENT_MEMORY_ATTRIBUTES (EFI_RESOURCE_ATTRIBUTE_PRESENT)
+
+//
+// Module Variables
+//
+EFI_LOCK mGcdMemorySpaceLock = EFI_INITIALIZE_LOCK_VARIABLE (TPL_NOTIFY);
+EFI_LOCK mGcdIoSpaceLock = EFI_INITIALIZE_LOCK_VARIABLE (TPL_NOTIFY);
+LIST_ENTRY mGcdMemorySpaceMap = INITIALIZE_LIST_HEAD_VARIABLE (mGcdMemorySpaceMap);
+LIST_ENTRY mGcdIoSpaceMap = INITIALIZE_LIST_HEAD_VARIABLE (mGcdIoSpaceMap);
+
+EFI_GCD_MAP_ENTRY mGcdMemorySpaceMapEntryTemplate = {
+ EFI_GCD_MAP_SIGNATURE,
+ {
+ NULL,
+ NULL
+ },
+ 0,
+ 0,
+ 0,
+ 0,
+ EfiGcdMemoryTypeNonExistent,
+ (EFI_GCD_IO_TYPE) 0,
+ NULL,
+ NULL
+};
+
+EFI_GCD_MAP_ENTRY mGcdIoSpaceMapEntryTemplate = {
+ EFI_GCD_MAP_SIGNATURE,
+ {
+ NULL,
+ NULL
+ },
+ 0,
+ 0,
+ 0,
+ 0,
+ (EFI_GCD_MEMORY_TYPE) 0,
+ EfiGcdIoTypeNonExistent,
+ NULL,
+ NULL
+};
+
+GCD_ATTRIBUTE_CONVERSION_ENTRY mAttributeConversionTable[] = {
+ { EFI_RESOURCE_ATTRIBUTE_UNCACHEABLE, EFI_MEMORY_UC, TRUE },
+ { EFI_RESOURCE_ATTRIBUTE_UNCACHED_EXPORTED, EFI_MEMORY_UCE, TRUE },
+ { EFI_RESOURCE_ATTRIBUTE_WRITE_COMBINEABLE, EFI_MEMORY_WC, TRUE },
+ { EFI_RESOURCE_ATTRIBUTE_WRITE_THROUGH_CACHEABLE, EFI_MEMORY_WT, TRUE },
+ { EFI_RESOURCE_ATTRIBUTE_WRITE_BACK_CACHEABLE, EFI_MEMORY_WB, TRUE },
+ { EFI_RESOURCE_ATTRIBUTE_READ_PROTECTABLE, EFI_MEMORY_RP, TRUE },
+ { EFI_RESOURCE_ATTRIBUTE_WRITE_PROTECTABLE, EFI_MEMORY_WP, TRUE },
+ { EFI_RESOURCE_ATTRIBUTE_EXECUTION_PROTECTABLE, EFI_MEMORY_XP, TRUE },
+ { EFI_RESOURCE_ATTRIBUTE_READ_ONLY_PROTECTABLE, EFI_MEMORY_RO, TRUE },
+ { EFI_RESOURCE_ATTRIBUTE_PRESENT, EFI_MEMORY_PRESENT, FALSE },
+ { EFI_RESOURCE_ATTRIBUTE_INITIALIZED, EFI_MEMORY_INITIALIZED, FALSE },
+ { EFI_RESOURCE_ATTRIBUTE_TESTED, EFI_MEMORY_TESTED, FALSE },
+ { EFI_RESOURCE_ATTRIBUTE_PERSISTABLE, EFI_MEMORY_NV, TRUE },
+ { EFI_RESOURCE_ATTRIBUTE_MORE_RELIABLE, EFI_MEMORY_MORE_RELIABLE, TRUE },
+ { 0, 0, FALSE }
+};
+
+///
+/// Lookup table used to print GCD Memory Space Map
+///
+GLOBAL_REMOVE_IF_UNREFERENCED CONST CHAR8 *mGcdMemoryTypeNames[] = {
+ "NonExist ", // EfiGcdMemoryTypeNonExistent
+ "Reserved ", // EfiGcdMemoryTypeReserved
+ "SystemMem", // EfiGcdMemoryTypeSystemMemory
+ "MMIO ", // EfiGcdMemoryTypeMemoryMappedIo
+ "PersisMem", // EfiGcdMemoryTypePersistent
+ "MoreRelia", // EfiGcdMemoryTypeMoreReliable
+ "Unknown " // EfiGcdMemoryTypeMaximum
+};
+
+///
+/// Lookup table used to print GCD I/O Space Map
+///
+GLOBAL_REMOVE_IF_UNREFERENCED CONST CHAR8 *mGcdIoTypeNames[] = {
+ "NonExist", // EfiGcdIoTypeNonExistent
+ "Reserved", // EfiGcdIoTypeReserved
+ "I/O ", // EfiGcdIoTypeIo
+ "Unknown " // EfiGcdIoTypeMaximum
+};
+
+///
+/// Lookup table used to print GCD Allocation Types
+///
+GLOBAL_REMOVE_IF_UNREFERENCED CONST CHAR8 *mGcdAllocationTypeNames[] = {
+ "AnySearchBottomUp ", // EfiGcdAllocateAnySearchBottomUp
+ "MaxAddressSearchBottomUp ", // EfiGcdAllocateMaxAddressSearchBottomUp
+ "AtAddress ", // EfiGcdAllocateAddress
+ "AnySearchTopDown ", // EfiGcdAllocateAnySearchTopDown
+ "MaxAddressSearchTopDown ", // EfiGcdAllocateMaxAddressSearchTopDown
+ "Unknown " // EfiGcdMaxAllocateType
+};
+
+/**
+ Dump the entire contents if the GCD Memory Space Map using DEBUG() macros when
+ PcdDebugPrintErrorLevel has the DEBUG_GCD bit set.
+
+ @param InitialMap TRUE if the initial GCD Memory Map is being dumped. Otherwise, FALSE.
+
+**/
+VOID
+EFIAPI
+CoreDumpGcdMemorySpaceMap (
+ BOOLEAN InitialMap
+ )
+{
+ DEBUG_CODE (
+ EFI_STATUS Status;
+ UINTN NumberOfDescriptors;
+ EFI_GCD_MEMORY_SPACE_DESCRIPTOR *MemorySpaceMap;
+ UINTN Index;
+
+ Status = CoreGetMemorySpaceMap (&NumberOfDescriptors, &MemorySpaceMap);
+ ASSERT (Status == EFI_SUCCESS && MemorySpaceMap != NULL);
+
+ if (InitialMap) {
+ DEBUG ((DEBUG_GCD, "GCD:Initial GCD Memory Space Map\n"));
+ }
+ DEBUG ((DEBUG_GCD, "GCDMemType Range Capabilities Attributes \n"));
+ DEBUG ((DEBUG_GCD, "========== ================================= ================ ================\n"));
+ for (Index = 0; Index < NumberOfDescriptors; Index++) {
+ DEBUG ((DEBUG_GCD, "%a %016lx-%016lx %016lx %016lx%c\n",
+ mGcdMemoryTypeNames[MIN (MemorySpaceMap[Index].GcdMemoryType, EfiGcdMemoryTypeMaximum)],
+ MemorySpaceMap[Index].BaseAddress,
+ MemorySpaceMap[Index].BaseAddress + MemorySpaceMap[Index].Length - 1,
+ MemorySpaceMap[Index].Capabilities,
+ MemorySpaceMap[Index].Attributes,
+ MemorySpaceMap[Index].ImageHandle == NULL ? ' ' : '*'
+ ));
+ }
+ DEBUG ((DEBUG_GCD, "\n"));
+ FreePool (MemorySpaceMap);
+ );
+}
+
+/**
+ Dump the entire contents if the GCD I/O Space Map using DEBUG() macros when
+ PcdDebugPrintErrorLevel has the DEBUG_GCD bit set.
+
+ @param InitialMap TRUE if the initial GCD I/O Map is being dumped. Otherwise, FALSE.
+
+**/
+VOID
+EFIAPI
+CoreDumpGcdIoSpaceMap (
+ BOOLEAN InitialMap
+ )
+{
+ DEBUG_CODE (
+ EFI_STATUS Status;
+ UINTN NumberOfDescriptors;
+ EFI_GCD_IO_SPACE_DESCRIPTOR *IoSpaceMap;
+ UINTN Index;
+
+ Status = CoreGetIoSpaceMap (&NumberOfDescriptors, &IoSpaceMap);
+ ASSERT (Status == EFI_SUCCESS && IoSpaceMap != NULL);
+
+ if (InitialMap) {
+ DEBUG ((DEBUG_GCD, "GCD:Initial GCD I/O Space Map\n"));
+ }
+
+ DEBUG ((DEBUG_GCD, "GCDIoType Range \n"));
+ DEBUG ((DEBUG_GCD, "========== =================================\n"));
+ for (Index = 0; Index < NumberOfDescriptors; Index++) {
+ DEBUG ((DEBUG_GCD, "%a %016lx-%016lx%c\n",
+ mGcdIoTypeNames[MIN (IoSpaceMap[Index].GcdIoType, EfiGcdIoTypeMaximum)],
+ IoSpaceMap[Index].BaseAddress,
+ IoSpaceMap[Index].BaseAddress + IoSpaceMap[Index].Length - 1,
+ IoSpaceMap[Index].ImageHandle == NULL ? ' ' : '*'
+ ));
+ }
+ DEBUG ((DEBUG_GCD, "\n"));
+ FreePool (IoSpaceMap);
+ );
+}
+
+/**
+ Validate resource descriptor HOB's attributes.
+
+ If Attributes includes some memory resource's settings, it should include
+ the corresponding capabilites also.
+
+ @param Attributes Resource descriptor HOB attributes.
+
+**/
+VOID
+CoreValidateResourceDescriptorHobAttributes (
+ IN UINT64 Attributes
+ )
+{
+ ASSERT (((Attributes & EFI_RESOURCE_ATTRIBUTE_READ_PROTECTED) == 0) ||
+ ((Attributes & EFI_RESOURCE_ATTRIBUTE_READ_PROTECTABLE) != 0));
+ ASSERT (((Attributes & EFI_RESOURCE_ATTRIBUTE_WRITE_PROTECTED) == 0) ||
+ ((Attributes & EFI_RESOURCE_ATTRIBUTE_WRITE_PROTECTABLE) != 0));
+ ASSERT (((Attributes & EFI_RESOURCE_ATTRIBUTE_EXECUTION_PROTECTED) == 0) ||
+ ((Attributes & EFI_RESOURCE_ATTRIBUTE_EXECUTION_PROTECTABLE) != 0));
+ ASSERT (((Attributes & EFI_RESOURCE_ATTRIBUTE_READ_ONLY_PROTECTED) == 0) ||
+ ((Attributes & EFI_RESOURCE_ATTRIBUTE_READ_ONLY_PROTECTABLE) != 0));
+ ASSERT (((Attributes & EFI_RESOURCE_ATTRIBUTE_PERSISTENT) == 0) ||
+ ((Attributes & EFI_RESOURCE_ATTRIBUTE_PERSISTABLE) != 0));
+}
+
+/**
+ Acquire memory lock on mGcdMemorySpaceLock.
+
+**/
+VOID
+CoreAcquireGcdMemoryLock (
+ VOID
+ )
+{
+ CoreAcquireLock (&mGcdMemorySpaceLock);
+}
+
+
+
+/**
+ Release memory lock on mGcdMemorySpaceLock.
+
+**/
+VOID
+CoreReleaseGcdMemoryLock (
+ VOID
+ )
+{
+ CoreReleaseLock (&mGcdMemorySpaceLock);
+}
+
+
+
+/**
+ Acquire memory lock on mGcdIoSpaceLock.
+
+**/
+VOID
+CoreAcquireGcdIoLock (
+ VOID
+ )
+{
+ CoreAcquireLock (&mGcdIoSpaceLock);
+}
+
+
+/**
+ Release memory lock on mGcdIoSpaceLock.
+
+**/
+VOID
+CoreReleaseGcdIoLock (
+ VOID
+ )
+{
+ CoreReleaseLock (&mGcdIoSpaceLock);
+}
+
+
+
+//
+// GCD Initialization Worker Functions
+//
+/**
+ Aligns a value to the specified boundary.
+
+ @param Value 64 bit value to align
+ @param Alignment Log base 2 of the boundary to align Value to
+ @param RoundUp TRUE if Value is to be rounded up to the nearest
+ aligned boundary. FALSE is Value is to be
+ rounded down to the nearest aligned boundary.
+
+ @return A 64 bit value is the aligned to the value nearest Value with an alignment by Alignment.
+
+**/
+UINT64
+AlignValue (
+ IN UINT64 Value,
+ IN UINTN Alignment,
+ IN BOOLEAN RoundUp
+ )
+{
+ UINT64 AlignmentMask;
+
+ AlignmentMask = LShiftU64 (1, Alignment) - 1;
+ if (RoundUp) {
+ Value += AlignmentMask;
+ }
+ return Value & (~AlignmentMask);
+}
+
+
+/**
+ Aligns address to the page boundary.
+
+ @param Value 64 bit address to align
+
+ @return A 64 bit value is the aligned to the value nearest Value with an alignment by Alignment.
+
+**/
+UINT64
+PageAlignAddress (
+ IN UINT64 Value
+ )
+{
+ return AlignValue (Value, EFI_PAGE_SHIFT, TRUE);
+}
+
+
+/**
+ Aligns length to the page boundary.
+
+ @param Value 64 bit length to align
+
+ @return A 64 bit value is the aligned to the value nearest Value with an alignment by Alignment.
+
+**/
+UINT64
+PageAlignLength (
+ IN UINT64 Value
+ )
+{
+ return AlignValue (Value, EFI_PAGE_SHIFT, FALSE);
+}
+
+//
+// GCD Memory Space Worker Functions
+//
+
+/**
+ Allocate pool for two entries.
+
+ @param TopEntry An entry of GCD map
+ @param BottomEntry An entry of GCD map
+
+ @retval EFI_OUT_OF_RESOURCES No enough buffer to be allocated.
+ @retval EFI_SUCCESS Both entries successfully allocated.
+
+**/
+EFI_STATUS
+CoreAllocateGcdMapEntry (
+ IN OUT EFI_GCD_MAP_ENTRY **TopEntry,
+ IN OUT EFI_GCD_MAP_ENTRY **BottomEntry
+ )
+{
+ //
+ // Set to mOnGuarding to TRUE before memory allocation. This will make sure
+ // that the entry memory is not "guarded" by HeapGuard. Otherwise it might
+ // cause problem when it's freed (if HeapGuard is enabled).
+ //
+ mOnGuarding = TRUE;
+ *TopEntry = AllocateZeroPool (sizeof (EFI_GCD_MAP_ENTRY));
+ mOnGuarding = FALSE;
+ if (*TopEntry == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ mOnGuarding = TRUE;
+ *BottomEntry = AllocateZeroPool (sizeof (EFI_GCD_MAP_ENTRY));
+ mOnGuarding = FALSE;
+ if (*BottomEntry == NULL) {
+ CoreFreePool (*TopEntry);
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Internal function. Inserts a new descriptor into a sorted list
+
+ @param Link The linked list to insert the range BaseAddress
+ and Length into
+ @param Entry A pointer to the entry that is inserted
+ @param BaseAddress The base address of the new range
+ @param Length The length of the new range in bytes
+ @param TopEntry Top pad entry to insert if needed.
+ @param BottomEntry Bottom pad entry to insert if needed.
+
+ @retval EFI_SUCCESS The new range was inserted into the linked list
+
+**/
+EFI_STATUS
+CoreInsertGcdMapEntry (
+ IN LIST_ENTRY *Link,
+ IN EFI_GCD_MAP_ENTRY *Entry,
+ IN EFI_PHYSICAL_ADDRESS BaseAddress,
+ IN UINT64 Length,
+ IN EFI_GCD_MAP_ENTRY *TopEntry,
+ IN EFI_GCD_MAP_ENTRY *BottomEntry
+ )
+{
+ ASSERT (Length != 0);
+
+ if (BaseAddress > Entry->BaseAddress) {
+ ASSERT (BottomEntry->Signature == 0);
+
+ CopyMem (BottomEntry, Entry, sizeof (EFI_GCD_MAP_ENTRY));
+ Entry->BaseAddress = BaseAddress;
+ BottomEntry->EndAddress = BaseAddress - 1;
+ InsertTailList (Link, &BottomEntry->Link);
+ }
+
+ if ((BaseAddress + Length - 1) < Entry->EndAddress) {
+ ASSERT (TopEntry->Signature == 0);
+
+ CopyMem (TopEntry, Entry, sizeof (EFI_GCD_MAP_ENTRY));
+ TopEntry->BaseAddress = BaseAddress + Length;
+ Entry->EndAddress = BaseAddress + Length - 1;
+ InsertHeadList (Link, &TopEntry->Link);
+ }
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Merge the Gcd region specified by Link and its adjacent entry.
+
+ @param Link Specify the entry to be merged (with its
+ adjacent entry).
+ @param Forward Direction (forward or backward).
+ @param Map Boundary.
+
+ @retval EFI_SUCCESS Successfully returned.
+ @retval EFI_UNSUPPORTED These adjacent regions could not merge.
+
+**/
+EFI_STATUS
+CoreMergeGcdMapEntry (
+ IN LIST_ENTRY *Link,
+ IN BOOLEAN Forward,
+ IN LIST_ENTRY *Map
+ )
+{
+ LIST_ENTRY *AdjacentLink;
+ EFI_GCD_MAP_ENTRY *Entry;
+ EFI_GCD_MAP_ENTRY *AdjacentEntry;
+
+ //
+ // Get adjacent entry
+ //
+ if (Forward) {
+ AdjacentLink = Link->ForwardLink;
+ } else {
+ AdjacentLink = Link->BackLink;
+ }
+
+ //
+ // If AdjacentLink is the head of the list, then no merge can be performed
+ //
+ if (AdjacentLink == Map) {
+ return EFI_SUCCESS;
+ }
+
+ Entry = CR (Link, EFI_GCD_MAP_ENTRY, Link, EFI_GCD_MAP_SIGNATURE);
+ AdjacentEntry = CR (AdjacentLink, EFI_GCD_MAP_ENTRY, Link, EFI_GCD_MAP_SIGNATURE);
+
+ if (Entry->Capabilities != AdjacentEntry->Capabilities) {
+ return EFI_UNSUPPORTED;
+ }
+ if (Entry->Attributes != AdjacentEntry->Attributes) {
+ return EFI_UNSUPPORTED;
+ }
+ if (Entry->GcdMemoryType != AdjacentEntry->GcdMemoryType) {
+ return EFI_UNSUPPORTED;
+ }
+ if (Entry->GcdIoType != AdjacentEntry->GcdIoType) {
+ return EFI_UNSUPPORTED;
+ }
+ if (Entry->ImageHandle != AdjacentEntry->ImageHandle) {
+ return EFI_UNSUPPORTED;
+ }
+ if (Entry->DeviceHandle != AdjacentEntry->DeviceHandle) {
+ return EFI_UNSUPPORTED;
+ }
+
+ if (Forward) {
+ Entry->EndAddress = AdjacentEntry->EndAddress;
+ } else {
+ Entry->BaseAddress = AdjacentEntry->BaseAddress;
+ }
+ RemoveEntryList (AdjacentLink);
+ CoreFreePool (AdjacentEntry);
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Merge adjacent entries on total chain.
+
+ @param TopEntry Top entry of GCD map.
+ @param BottomEntry Bottom entry of GCD map.
+ @param StartLink Start link of the list for this loop.
+ @param EndLink End link of the list for this loop.
+ @param Map Boundary.
+
+ @retval EFI_SUCCESS GCD map successfully cleaned up.
+
+**/
+EFI_STATUS
+CoreCleanupGcdMapEntry (
+ IN EFI_GCD_MAP_ENTRY *TopEntry,
+ IN EFI_GCD_MAP_ENTRY *BottomEntry,
+ IN LIST_ENTRY *StartLink,
+ IN LIST_ENTRY *EndLink,
+ IN LIST_ENTRY *Map
+ )
+{
+ LIST_ENTRY *Link;
+
+ if (TopEntry->Signature == 0) {
+ CoreFreePool (TopEntry);
+ }
+ if (BottomEntry->Signature == 0) {
+ CoreFreePool (BottomEntry);
+ }
+
+ Link = StartLink;
+ while (Link != EndLink->ForwardLink) {
+ CoreMergeGcdMapEntry (Link, FALSE, Map);
+ Link = Link->ForwardLink;
+ }
+ CoreMergeGcdMapEntry (EndLink, TRUE, Map);
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Search a segment of memory space in GCD map. The result is a range of GCD entry list.
+
+ @param BaseAddress The start address of the segment.
+ @param Length The length of the segment.
+ @param StartLink The first GCD entry involves this segment of
+ memory space.
+ @param EndLink The first GCD entry involves this segment of
+ memory space.
+ @param Map Points to the start entry to search.
+
+ @retval EFI_SUCCESS Successfully found the entry.
+ @retval EFI_NOT_FOUND Not found.
+
+**/
+EFI_STATUS
+CoreSearchGcdMapEntry (
+ IN EFI_PHYSICAL_ADDRESS BaseAddress,
+ IN UINT64 Length,
+ OUT LIST_ENTRY **StartLink,
+ OUT LIST_ENTRY **EndLink,
+ IN LIST_ENTRY *Map
+ )
+{
+ LIST_ENTRY *Link;
+ EFI_GCD_MAP_ENTRY *Entry;
+
+ ASSERT (Length != 0);
+
+ *StartLink = NULL;
+ *EndLink = NULL;
+
+ Link = Map->ForwardLink;
+ while (Link != Map) {
+ Entry = CR (Link, EFI_GCD_MAP_ENTRY, Link, EFI_GCD_MAP_SIGNATURE);
+ if (BaseAddress >= Entry->BaseAddress && BaseAddress <= Entry->EndAddress) {
+ *StartLink = Link;
+ }
+ if (*StartLink != NULL) {
+ if ((BaseAddress + Length - 1) >= Entry->BaseAddress &&
+ (BaseAddress + Length - 1) <= Entry->EndAddress ) {
+ *EndLink = Link;
+ return EFI_SUCCESS;
+ }
+ }
+ Link = Link->ForwardLink;
+ }
+
+ return EFI_NOT_FOUND;
+}
+
+
+/**
+ Count the amount of GCD map entries.
+
+ @param Map Points to the start entry to do the count loop.
+
+ @return The count.
+
+**/
+UINTN
+CoreCountGcdMapEntry (
+ IN LIST_ENTRY *Map
+ )
+{
+ UINTN Count;
+ LIST_ENTRY *Link;
+
+ Count = 0;
+ Link = Map->ForwardLink;
+ while (Link != Map) {
+ Count++;
+ Link = Link->ForwardLink;
+ }
+
+ return Count;
+}
+
+
+
+/**
+ Return the memory attribute specified by Attributes
+
+ @param Attributes A num with some attribute bits on.
+
+ @return The enum value of memory attribute.
+
+**/
+UINT64
+ConverToCpuArchAttributes (
+ UINT64 Attributes
+ )
+{
+ UINT64 CpuArchAttributes;
+
+ CpuArchAttributes = Attributes & EFI_MEMORY_ATTRIBUTE_MASK;
+
+ if ( (Attributes & EFI_MEMORY_UC) == EFI_MEMORY_UC) {
+ CpuArchAttributes |= EFI_MEMORY_UC;
+ } else if ( (Attributes & EFI_MEMORY_WC ) == EFI_MEMORY_WC) {
+ CpuArchAttributes |= EFI_MEMORY_WC;
+ } else if ( (Attributes & EFI_MEMORY_WT ) == EFI_MEMORY_WT) {
+ CpuArchAttributes |= EFI_MEMORY_WT;
+ } else if ( (Attributes & EFI_MEMORY_WB) == EFI_MEMORY_WB) {
+ CpuArchAttributes |= EFI_MEMORY_WB;
+ } else if ( (Attributes & EFI_MEMORY_UCE) == EFI_MEMORY_UCE) {
+ CpuArchAttributes |= EFI_MEMORY_UCE;
+ } else if ( (Attributes & EFI_MEMORY_WP) == EFI_MEMORY_WP) {
+ CpuArchAttributes |= EFI_MEMORY_WP;
+ }
+
+ return CpuArchAttributes;
+}
+
+
+/**
+ Do operation on a segment of memory space specified (add, free, remove, change attribute ...).
+
+ @param Operation The type of the operation
+ @param GcdMemoryType Additional information for the operation
+ @param GcdIoType Additional information for the operation
+ @param BaseAddress Start address of the segment
+ @param Length length of the segment
+ @param Capabilities The alterable attributes of a newly added entry
+ @param Attributes The attributes needs to be set
+
+ @retval EFI_INVALID_PARAMETER Length is 0 or address (length) not aligned when
+ setting attribute.
+ @retval EFI_SUCCESS Action successfully done.
+ @retval EFI_UNSUPPORTED Could not find the proper descriptor on this
+ segment or set an upsupported attribute.
+ @retval EFI_ACCESS_DENIED Operate on an space non-exist or is used for an
+ image.
+ @retval EFI_NOT_FOUND Free a non-using space or remove a non-exist
+ space, and so on.
+ @retval EFI_OUT_OF_RESOURCES No buffer could be allocated.
+ @retval EFI_NOT_AVAILABLE_YET The attributes cannot be set because CPU architectural protocol
+ is not available yet.
+**/
+EFI_STATUS
+CoreConvertSpace (
+ IN UINTN Operation,
+ IN EFI_GCD_MEMORY_TYPE GcdMemoryType,
+ IN EFI_GCD_IO_TYPE GcdIoType,
+ IN EFI_PHYSICAL_ADDRESS BaseAddress,
+ IN UINT64 Length,
+ IN UINT64 Capabilities,
+ IN UINT64 Attributes
+ )
+{
+ EFI_STATUS Status;
+ LIST_ENTRY *Map;
+ LIST_ENTRY *Link;
+ EFI_GCD_MAP_ENTRY *Entry;
+ EFI_GCD_MAP_ENTRY *TopEntry;
+ EFI_GCD_MAP_ENTRY *BottomEntry;
+ LIST_ENTRY *StartLink;
+ LIST_ENTRY *EndLink;
+ UINT64 CpuArchAttributes;
+
+ if (Length == 0) {
+ DEBUG ((DEBUG_GCD, " Status = %r\n", EFI_INVALID_PARAMETER));
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Map = NULL;
+ if ((Operation & GCD_MEMORY_SPACE_OPERATION) != 0) {
+ CoreAcquireGcdMemoryLock ();
+ Map = &mGcdMemorySpaceMap;
+ } else if ((Operation & GCD_IO_SPACE_OPERATION) != 0) {
+ CoreAcquireGcdIoLock ();
+ Map = &mGcdIoSpaceMap;
+ } else {
+ ASSERT (FALSE);
+ }
+
+ //
+ // Search for the list of descriptors that cover the range BaseAddress to BaseAddress+Length
+ //
+ Status = CoreSearchGcdMapEntry (BaseAddress, Length, &StartLink, &EndLink, Map);
+ if (EFI_ERROR (Status)) {
+ Status = EFI_UNSUPPORTED;
+
+ goto Done;
+ }
+ ASSERT (StartLink != NULL && EndLink != NULL);
+
+ //
+ // Verify that the list of descriptors are unallocated non-existent memory.
+ //
+ Link = StartLink;
+ while (Link != EndLink->ForwardLink) {
+ Entry = CR (Link, EFI_GCD_MAP_ENTRY, Link, EFI_GCD_MAP_SIGNATURE);
+ switch (Operation) {
+ //
+ // Add operations
+ //
+ case GCD_ADD_MEMORY_OPERATION:
+ if (Entry->GcdMemoryType != EfiGcdMemoryTypeNonExistent ||
+ Entry->ImageHandle != NULL ) {
+ Status = EFI_ACCESS_DENIED;
+ goto Done;
+ }
+ break;
+ case GCD_ADD_IO_OPERATION:
+ if (Entry->GcdIoType != EfiGcdIoTypeNonExistent ||
+ Entry->ImageHandle != NULL ) {
+ Status = EFI_ACCESS_DENIED;
+ goto Done;
+ }
+ break;
+ //
+ // Free operations
+ //
+ case GCD_FREE_MEMORY_OPERATION:
+ case GCD_FREE_IO_OPERATION:
+ if (Entry->ImageHandle == NULL) {
+ Status = EFI_NOT_FOUND;
+ goto Done;
+ }
+ break;
+ //
+ // Remove operations
+ //
+ case GCD_REMOVE_MEMORY_OPERATION:
+ if (Entry->GcdMemoryType == EfiGcdMemoryTypeNonExistent) {
+ Status = EFI_NOT_FOUND;
+ goto Done;
+ }
+ if (Entry->ImageHandle != NULL) {
+ Status = EFI_ACCESS_DENIED;
+ goto Done;
+ }
+ break;
+ case GCD_REMOVE_IO_OPERATION:
+ if (Entry->GcdIoType == EfiGcdIoTypeNonExistent) {
+ Status = EFI_NOT_FOUND;
+ goto Done;
+ }
+ if (Entry->ImageHandle != NULL) {
+ Status = EFI_ACCESS_DENIED;
+ goto Done;
+ }
+ break;
+ //
+ // Set attributes operation
+ //
+ case GCD_SET_ATTRIBUTES_MEMORY_OPERATION:
+ if ((Attributes & EFI_MEMORY_RUNTIME) != 0) {
+ if ((BaseAddress & EFI_PAGE_MASK) != 0 || (Length & EFI_PAGE_MASK) != 0) {
+ Status = EFI_INVALID_PARAMETER;
+ goto Done;
+ }
+ }
+ if ((Entry->Capabilities & Attributes) != Attributes) {
+ Status = EFI_UNSUPPORTED;
+ goto Done;
+ }
+ break;
+ //
+ // Set capabilities operation
+ //
+ case GCD_SET_CAPABILITIES_MEMORY_OPERATION:
+ if ((BaseAddress & EFI_PAGE_MASK) != 0 || (Length & EFI_PAGE_MASK) != 0) {
+ Status = EFI_INVALID_PARAMETER;
+
+ goto Done;
+ }
+ //
+ // Current attributes must still be supported with new capabilities
+ //
+ if ((Capabilities & Entry->Attributes) != Entry->Attributes) {
+ Status = EFI_UNSUPPORTED;
+ goto Done;
+ }
+ break;
+ }
+ Link = Link->ForwardLink;
+ }
+
+ //
+ // Allocate work space to perform this operation
+ //
+ Status = CoreAllocateGcdMapEntry (&TopEntry, &BottomEntry);
+ if (EFI_ERROR (Status)) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Done;
+ }
+ ASSERT (TopEntry != NULL && BottomEntry != NULL);
+
+ //
+ // Initialize CpuArchAttributes to suppress incorrect compiler/analyzer warnings.
+ //
+ CpuArchAttributes = 0;
+ if (Operation == GCD_SET_ATTRIBUTES_MEMORY_OPERATION) {
+ //
+ // Call CPU Arch Protocol to attempt to set attributes on the range
+ //
+ CpuArchAttributes = ConverToCpuArchAttributes (Attributes);
+ //
+ // CPU arch attributes include page attributes and cache attributes.
+ // Only page attributes supports to be cleared, but not cache attributes.
+ // Caller is expected to use GetMemorySpaceDescriptor() to get the current
+ // attributes, AND/OR attributes, and then calls SetMemorySpaceAttributes()
+ // to set the new attributes.
+ // So 0 CPU arch attributes should not happen as memory should always have
+ // a cache attribute (no matter UC or WB, etc).
+ //
+ // Here, 0 CPU arch attributes will be filtered to be compatible with the
+ // case that caller just calls SetMemorySpaceAttributes() with none CPU
+ // arch attributes (for example, RUNTIME) as the purpose of the case is not
+ // to clear CPU arch attributes.
+ //
+ if (CpuArchAttributes != 0) {
+ if (gCpu == NULL) {
+ Status = EFI_NOT_AVAILABLE_YET;
+ } else {
+ Status = gCpu->SetMemoryAttributes (
+ gCpu,
+ BaseAddress,
+ Length,
+ CpuArchAttributes
+ );
+ }
+ if (EFI_ERROR (Status)) {
+ CoreFreePool (TopEntry);
+ CoreFreePool (BottomEntry);
+ goto Done;
+ }
+ }
+ }
+
+ //
+ // Convert/Insert the list of descriptors from StartLink to EndLink
+ //
+ Link = StartLink;
+ while (Link != EndLink->ForwardLink) {
+ Entry = CR (Link, EFI_GCD_MAP_ENTRY, Link, EFI_GCD_MAP_SIGNATURE);
+ CoreInsertGcdMapEntry (Link, Entry, BaseAddress, Length, TopEntry, BottomEntry);
+ switch (Operation) {
+ //
+ // Add operations
+ //
+ case GCD_ADD_MEMORY_OPERATION:
+ Entry->GcdMemoryType = GcdMemoryType;
+ if (GcdMemoryType == EfiGcdMemoryTypeMemoryMappedIo) {
+ Entry->Capabilities = Capabilities | EFI_MEMORY_RUNTIME | EFI_MEMORY_PORT_IO;
+ } else {
+ Entry->Capabilities = Capabilities | EFI_MEMORY_RUNTIME;
+ }
+ break;
+ case GCD_ADD_IO_OPERATION:
+ Entry->GcdIoType = GcdIoType;
+ break;
+ //
+ // Free operations
+ //
+ case GCD_FREE_MEMORY_OPERATION:
+ case GCD_FREE_IO_OPERATION:
+ Entry->ImageHandle = NULL;
+ Entry->DeviceHandle = NULL;
+ break;
+ //
+ // Remove operations
+ //
+ case GCD_REMOVE_MEMORY_OPERATION:
+ Entry->GcdMemoryType = EfiGcdMemoryTypeNonExistent;
+ Entry->Capabilities = 0;
+ break;
+ case GCD_REMOVE_IO_OPERATION:
+ Entry->GcdIoType = EfiGcdIoTypeNonExistent;
+ break;
+ //
+ // Set attributes operation
+ //
+ case GCD_SET_ATTRIBUTES_MEMORY_OPERATION:
+ if (CpuArchAttributes == 0) {
+ //
+ // Keep original CPU arch attributes when caller just calls
+ // SetMemorySpaceAttributes() with none CPU arch attributes (for example, RUNTIME).
+ //
+ Attributes |= (Entry->Attributes & (EFI_CACHE_ATTRIBUTE_MASK | EFI_MEMORY_ATTRIBUTE_MASK));
+ }
+ Entry->Attributes = Attributes;
+ break;
+ //
+ // Set capabilities operation
+ //
+ case GCD_SET_CAPABILITIES_MEMORY_OPERATION:
+ Entry->Capabilities = Capabilities;
+ break;
+ }
+ Link = Link->ForwardLink;
+ }
+
+ //
+ // Cleanup
+ //
+ Status = CoreCleanupGcdMapEntry (TopEntry, BottomEntry, StartLink, EndLink, Map);
+
+Done:
+ DEBUG ((DEBUG_GCD, " Status = %r\n", Status));
+
+ if ((Operation & GCD_MEMORY_SPACE_OPERATION) != 0) {
+ CoreReleaseGcdMemoryLock ();
+ CoreDumpGcdMemorySpaceMap (FALSE);
+ }
+ if ((Operation & GCD_IO_SPACE_OPERATION) != 0) {
+ CoreReleaseGcdIoLock ();
+ CoreDumpGcdIoSpaceMap (FALSE);
+ }
+
+ return Status;
+}
+
+
+/**
+ Check whether an entry could be used to allocate space.
+
+ @param Operation Allocate memory or IO
+ @param Entry The entry to be tested
+ @param GcdMemoryType The desired memory type
+ @param GcdIoType The desired IO type
+
+ @retval EFI_NOT_FOUND The memory type does not match or there's an
+ image handle on the entry.
+ @retval EFI_UNSUPPORTED The operation unsupported.
+ @retval EFI_SUCCESS It's ok for this entry to be used to allocate
+ space.
+
+**/
+EFI_STATUS
+CoreAllocateSpaceCheckEntry (
+ IN UINTN Operation,
+ IN EFI_GCD_MAP_ENTRY *Entry,
+ IN EFI_GCD_MEMORY_TYPE GcdMemoryType,
+ IN EFI_GCD_IO_TYPE GcdIoType
+ )
+{
+ if (Entry->ImageHandle != NULL) {
+ return EFI_NOT_FOUND;
+ }
+ switch (Operation) {
+ case GCD_ALLOCATE_MEMORY_OPERATION:
+ if (Entry->GcdMemoryType != GcdMemoryType) {
+ return EFI_NOT_FOUND;
+ }
+ break;
+ case GCD_ALLOCATE_IO_OPERATION:
+ if (Entry->GcdIoType != GcdIoType) {
+ return EFI_NOT_FOUND;
+ }
+ break;
+ default:
+ return EFI_UNSUPPORTED;
+ }
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Allocate space on specified address and length.
+
+ @param Operation The type of operation (memory or IO)
+ @param GcdAllocateType The type of allocate operation
+ @param GcdMemoryType The desired memory type
+ @param GcdIoType The desired IO type
+ @param Alignment Align with 2^Alignment
+ @param Length Length to allocate
+ @param BaseAddress Base address to allocate
+ @param ImageHandle The image handle consume the allocated space.
+ @param DeviceHandle The device handle consume the allocated space.
+
+ @retval EFI_INVALID_PARAMETER Invalid parameter.
+ @retval EFI_NOT_FOUND No descriptor for the desired space exists.
+ @retval EFI_SUCCESS Space successfully allocated.
+
+**/
+EFI_STATUS
+CoreAllocateSpace (
+ IN UINTN Operation,
+ IN EFI_GCD_ALLOCATE_TYPE GcdAllocateType,
+ IN EFI_GCD_MEMORY_TYPE GcdMemoryType,
+ IN EFI_GCD_IO_TYPE GcdIoType,
+ IN UINTN Alignment,
+ IN UINT64 Length,
+ IN OUT EFI_PHYSICAL_ADDRESS *BaseAddress,
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_HANDLE DeviceHandle OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+ EFI_PHYSICAL_ADDRESS AlignmentMask;
+ EFI_PHYSICAL_ADDRESS MaxAddress;
+ LIST_ENTRY *Map;
+ LIST_ENTRY *Link;
+ LIST_ENTRY *SubLink;
+ EFI_GCD_MAP_ENTRY *Entry;
+ EFI_GCD_MAP_ENTRY *TopEntry;
+ EFI_GCD_MAP_ENTRY *BottomEntry;
+ LIST_ENTRY *StartLink;
+ LIST_ENTRY *EndLink;
+ BOOLEAN Found;
+
+ //
+ // Make sure parameters are valid
+ //
+ if ((UINT32)GcdAllocateType >= EfiGcdMaxAllocateType) {
+ DEBUG ((DEBUG_GCD, " Status = %r\n", EFI_INVALID_PARAMETER));
+ return EFI_INVALID_PARAMETER;
+ }
+ if ((UINT32)GcdMemoryType >= EfiGcdMemoryTypeMaximum) {
+ DEBUG ((DEBUG_GCD, " Status = %r\n", EFI_INVALID_PARAMETER));
+ return EFI_INVALID_PARAMETER;
+ }
+ if ((UINT32)GcdIoType >= EfiGcdIoTypeMaximum) {
+ DEBUG ((DEBUG_GCD, " Status = %r\n", EFI_INVALID_PARAMETER));
+ return EFI_INVALID_PARAMETER;
+ }
+ if (BaseAddress == NULL) {
+ DEBUG ((DEBUG_GCD, " Status = %r\n", EFI_INVALID_PARAMETER));
+ return EFI_INVALID_PARAMETER;
+ }
+ if (ImageHandle == NULL) {
+ DEBUG ((DEBUG_GCD, " Status = %r\n", EFI_INVALID_PARAMETER));
+ return EFI_INVALID_PARAMETER;
+ }
+ if (Alignment >= 64) {
+ DEBUG ((DEBUG_GCD, " Status = %r\n", EFI_NOT_FOUND));
+ return EFI_NOT_FOUND;
+ }
+ if (Length == 0) {
+ DEBUG ((DEBUG_GCD, " Status = %r\n", EFI_INVALID_PARAMETER));
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Map = NULL;
+ if ((Operation & GCD_MEMORY_SPACE_OPERATION) != 0) {
+ CoreAcquireGcdMemoryLock ();
+ Map = &mGcdMemorySpaceMap;
+ } else if ((Operation & GCD_IO_SPACE_OPERATION) != 0) {
+ CoreAcquireGcdIoLock ();
+ Map = &mGcdIoSpaceMap;
+ } else {
+ ASSERT (FALSE);
+ }
+
+ Found = FALSE;
+ StartLink = NULL;
+ EndLink = NULL;
+ //
+ // Compute alignment bit mask
+ //
+ AlignmentMask = LShiftU64 (1, Alignment) - 1;
+
+ if (GcdAllocateType == EfiGcdAllocateAddress) {
+ //
+ // Verify that the BaseAddress passed in is aligned correctly
+ //
+ if ((*BaseAddress & AlignmentMask) != 0) {
+ Status = EFI_NOT_FOUND;
+ goto Done;
+ }
+
+ //
+ // Search for the list of descriptors that cover the range BaseAddress to BaseAddress+Length
+ //
+ Status = CoreSearchGcdMapEntry (*BaseAddress, Length, &StartLink, &EndLink, Map);
+ if (EFI_ERROR (Status)) {
+ Status = EFI_NOT_FOUND;
+ goto Done;
+ }
+ ASSERT (StartLink != NULL && EndLink != NULL);
+
+ //
+ // Verify that the list of descriptors are unallocated memory matching GcdMemoryType.
+ //
+ Link = StartLink;
+ while (Link != EndLink->ForwardLink) {
+ Entry = CR (Link, EFI_GCD_MAP_ENTRY, Link, EFI_GCD_MAP_SIGNATURE);
+ Link = Link->ForwardLink;
+ Status = CoreAllocateSpaceCheckEntry (Operation, Entry, GcdMemoryType, GcdIoType);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+ }
+ Found = TRUE;
+ } else {
+
+ Entry = CR (Map->BackLink, EFI_GCD_MAP_ENTRY, Link, EFI_GCD_MAP_SIGNATURE);
+
+ //
+ // Compute the maximum address to use in the search algorithm
+ //
+ if (GcdAllocateType == EfiGcdAllocateMaxAddressSearchBottomUp ||
+ GcdAllocateType == EfiGcdAllocateMaxAddressSearchTopDown ) {
+ MaxAddress = *BaseAddress;
+ } else {
+ MaxAddress = Entry->EndAddress;
+ }
+
+ //
+ // Verify that the list of descriptors are unallocated memory matching GcdMemoryType.
+ //
+ if (GcdAllocateType == EfiGcdAllocateMaxAddressSearchTopDown ||
+ GcdAllocateType == EfiGcdAllocateAnySearchTopDown ) {
+ Link = Map->BackLink;
+ } else {
+ Link = Map->ForwardLink;
+ }
+ while (Link != Map) {
+ Entry = CR (Link, EFI_GCD_MAP_ENTRY, Link, EFI_GCD_MAP_SIGNATURE);
+
+ if (GcdAllocateType == EfiGcdAllocateMaxAddressSearchTopDown ||
+ GcdAllocateType == EfiGcdAllocateAnySearchTopDown ) {
+ Link = Link->BackLink;
+ } else {
+ Link = Link->ForwardLink;
+ }
+
+ Status = CoreAllocateSpaceCheckEntry (Operation, Entry, GcdMemoryType, GcdIoType);
+ if (EFI_ERROR (Status)) {
+ continue;
+ }
+
+ if (GcdAllocateType == EfiGcdAllocateMaxAddressSearchTopDown ||
+ GcdAllocateType == EfiGcdAllocateAnySearchTopDown) {
+ if ((Entry->BaseAddress + Length) > MaxAddress) {
+ continue;
+ }
+ if (Length > (Entry->EndAddress + 1)) {
+ Status = EFI_NOT_FOUND;
+ goto Done;
+ }
+ if (Entry->EndAddress > MaxAddress) {
+ *BaseAddress = MaxAddress;
+ } else {
+ *BaseAddress = Entry->EndAddress;
+ }
+ *BaseAddress = (*BaseAddress + 1 - Length) & (~AlignmentMask);
+ } else {
+ *BaseAddress = (Entry->BaseAddress + AlignmentMask) & (~AlignmentMask);
+ if ((*BaseAddress + Length - 1) > MaxAddress) {
+ Status = EFI_NOT_FOUND;
+ goto Done;
+ }
+ }
+
+ //
+ // Search for the list of descriptors that cover the range BaseAddress to BaseAddress+Length
+ //
+ Status = CoreSearchGcdMapEntry (*BaseAddress, Length, &StartLink, &EndLink, Map);
+ if (EFI_ERROR (Status)) {
+ Status = EFI_NOT_FOUND;
+ goto Done;
+ }
+ ASSERT (StartLink != NULL && EndLink != NULL);
+
+ Link = StartLink;
+ //
+ // Verify that the list of descriptors are unallocated memory matching GcdMemoryType.
+ //
+ Found = TRUE;
+ SubLink = StartLink;
+ while (SubLink != EndLink->ForwardLink) {
+ Entry = CR (SubLink, EFI_GCD_MAP_ENTRY, Link, EFI_GCD_MAP_SIGNATURE);
+ Status = CoreAllocateSpaceCheckEntry (Operation, Entry, GcdMemoryType, GcdIoType);
+ if (EFI_ERROR (Status)) {
+ Link = SubLink;
+ Found = FALSE;
+ break;
+ }
+ SubLink = SubLink->ForwardLink;
+ }
+ if (Found) {
+ break;
+ }
+ }
+ }
+ if (!Found) {
+ Status = EFI_NOT_FOUND;
+ goto Done;
+ }
+
+ //
+ // Allocate work space to perform this operation
+ //
+ Status = CoreAllocateGcdMapEntry (&TopEntry, &BottomEntry);
+ if (EFI_ERROR (Status)) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Done;
+ }
+ ASSERT (TopEntry != NULL && BottomEntry != NULL);
+
+ //
+ // Convert/Insert the list of descriptors from StartLink to EndLink
+ //
+ Link = StartLink;
+ while (Link != EndLink->ForwardLink) {
+ Entry = CR (Link, EFI_GCD_MAP_ENTRY, Link, EFI_GCD_MAP_SIGNATURE);
+ CoreInsertGcdMapEntry (Link, Entry, *BaseAddress, Length, TopEntry, BottomEntry);
+ Entry->ImageHandle = ImageHandle;
+ Entry->DeviceHandle = DeviceHandle;
+ Link = Link->ForwardLink;
+ }
+
+ //
+ // Cleanup
+ //
+ Status = CoreCleanupGcdMapEntry (TopEntry, BottomEntry, StartLink, EndLink, Map);
+
+Done:
+ DEBUG ((DEBUG_GCD, " Status = %r", Status));
+ if (!EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_GCD, " (BaseAddress = %016lx)", *BaseAddress));
+ }
+ DEBUG ((DEBUG_GCD, "\n"));
+
+ if ((Operation & GCD_MEMORY_SPACE_OPERATION) != 0) {
+ CoreReleaseGcdMemoryLock ();
+ CoreDumpGcdMemorySpaceMap (FALSE);
+ }
+ if ((Operation & GCD_IO_SPACE_OPERATION) !=0) {
+ CoreReleaseGcdIoLock ();
+ CoreDumpGcdIoSpaceMap (FALSE);
+ }
+
+ return Status;
+}
+
+
+/**
+ Add a segment of memory to GCD map.
+
+ @param GcdMemoryType Memory type of the segment.
+ @param BaseAddress Base address of the segment.
+ @param Length Length of the segment.
+ @param Capabilities alterable attributes of the segment.
+
+ @retval EFI_INVALID_PARAMETER Invalid parameters.
+ @retval EFI_SUCCESS Successfully add a segment of memory space.
+
+**/
+EFI_STATUS
+CoreInternalAddMemorySpace (
+ IN EFI_GCD_MEMORY_TYPE GcdMemoryType,
+ IN EFI_PHYSICAL_ADDRESS BaseAddress,
+ IN UINT64 Length,
+ IN UINT64 Capabilities
+ )
+{
+ DEBUG ((DEBUG_GCD, "GCD:AddMemorySpace(Base=%016lx,Length=%016lx)\n", BaseAddress, Length));
+ DEBUG ((DEBUG_GCD, " GcdMemoryType = %a\n", mGcdMemoryTypeNames[MIN (GcdMemoryType, EfiGcdMemoryTypeMaximum)]));
+ DEBUG ((DEBUG_GCD, " Capabilities = %016lx\n", Capabilities));
+
+ //
+ // Make sure parameters are valid
+ //
+ if (GcdMemoryType <= EfiGcdMemoryTypeNonExistent || GcdMemoryType >= EfiGcdMemoryTypeMaximum) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ return CoreConvertSpace (GCD_ADD_MEMORY_OPERATION, GcdMemoryType, (EFI_GCD_IO_TYPE) 0, BaseAddress, Length, Capabilities, 0);
+}
+
+//
+// GCD Core Services
+//
+
+/**
+ Allocates nonexistent memory, reserved memory, system memory, or memorymapped
+ I/O resources from the global coherency domain of the processor.
+
+ @param GcdAllocateType The type of allocate operation
+ @param GcdMemoryType The desired memory type
+ @param Alignment Align with 2^Alignment
+ @param Length Length to allocate
+ @param BaseAddress Base address to allocate
+ @param ImageHandle The image handle consume the allocated space.
+ @param DeviceHandle The device handle consume the allocated space.
+
+ @retval EFI_INVALID_PARAMETER Invalid parameter.
+ @retval EFI_NOT_FOUND No descriptor contains the desired space.
+ @retval EFI_SUCCESS Memory space successfully allocated.
+
+**/
+EFI_STATUS
+EFIAPI
+CoreAllocateMemorySpace (
+ IN EFI_GCD_ALLOCATE_TYPE GcdAllocateType,
+ IN EFI_GCD_MEMORY_TYPE GcdMemoryType,
+ IN UINTN Alignment,
+ IN UINT64 Length,
+ IN OUT EFI_PHYSICAL_ADDRESS *BaseAddress,
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_HANDLE DeviceHandle OPTIONAL
+ )
+{
+ if (BaseAddress != NULL) {
+ DEBUG ((DEBUG_GCD, "GCD:AllocateMemorySpace(Base=%016lx,Length=%016lx)\n", *BaseAddress, Length));
+ } else {
+ DEBUG ((DEBUG_GCD, "GCD:AllocateMemorySpace(Base=<NULL>,Length=%016lx)\n", Length));
+ }
+ DEBUG ((DEBUG_GCD, " GcdAllocateType = %a\n", mGcdAllocationTypeNames[MIN (GcdAllocateType, EfiGcdMaxAllocateType)]));
+ DEBUG ((DEBUG_GCD, " GcdMemoryType = %a\n", mGcdMemoryTypeNames[MIN (GcdMemoryType, EfiGcdMemoryTypeMaximum)]));
+ DEBUG ((DEBUG_GCD, " Alignment = %016lx\n", LShiftU64 (1, Alignment)));
+ DEBUG ((DEBUG_GCD, " ImageHandle = %p\n", ImageHandle));
+ DEBUG ((DEBUG_GCD, " DeviceHandle = %p\n", DeviceHandle));
+
+ return CoreAllocateSpace (
+ GCD_ALLOCATE_MEMORY_OPERATION,
+ GcdAllocateType,
+ GcdMemoryType,
+ (EFI_GCD_IO_TYPE) 0,
+ Alignment,
+ Length,
+ BaseAddress,
+ ImageHandle,
+ DeviceHandle
+ );
+}
+
+
+/**
+ Adds reserved memory, system memory, or memory-mapped I/O resources to the
+ global coherency domain of the processor.
+
+ @param GcdMemoryType Memory type of the memory space.
+ @param BaseAddress Base address of the memory space.
+ @param Length Length of the memory space.
+ @param Capabilities alterable attributes of the memory space.
+
+ @retval EFI_SUCCESS Merged this memory space into GCD map.
+
+**/
+EFI_STATUS
+EFIAPI
+CoreAddMemorySpace (
+ IN EFI_GCD_MEMORY_TYPE GcdMemoryType,
+ IN EFI_PHYSICAL_ADDRESS BaseAddress,
+ IN UINT64 Length,
+ IN UINT64 Capabilities
+ )
+{
+ EFI_STATUS Status;
+ EFI_PHYSICAL_ADDRESS PageBaseAddress;
+ UINT64 PageLength;
+
+ Status = CoreInternalAddMemorySpace (GcdMemoryType, BaseAddress, Length, Capabilities);
+
+ if (!EFI_ERROR (Status) && ((GcdMemoryType == EfiGcdMemoryTypeSystemMemory) || (GcdMemoryType == EfiGcdMemoryTypeMoreReliable))) {
+
+ PageBaseAddress = PageAlignAddress (BaseAddress);
+ PageLength = PageAlignLength (BaseAddress + Length - PageBaseAddress);
+
+ Status = CoreAllocateMemorySpace (
+ EfiGcdAllocateAddress,
+ GcdMemoryType,
+ EFI_PAGE_SHIFT,
+ PageLength,
+ &PageBaseAddress,
+ gDxeCoreImageHandle,
+ NULL
+ );
+
+ if (!EFI_ERROR (Status)) {
+ CoreAddMemoryDescriptor (
+ EfiConventionalMemory,
+ PageBaseAddress,
+ RShiftU64 (PageLength, EFI_PAGE_SHIFT),
+ Capabilities
+ );
+ } else {
+ for (; PageLength != 0; PageLength -= EFI_PAGE_SIZE, PageBaseAddress += EFI_PAGE_SIZE) {
+ Status = CoreAllocateMemorySpace (
+ EfiGcdAllocateAddress,
+ GcdMemoryType,
+ EFI_PAGE_SHIFT,
+ EFI_PAGE_SIZE,
+ &PageBaseAddress,
+ gDxeCoreImageHandle,
+ NULL
+ );
+
+ if (!EFI_ERROR (Status)) {
+ CoreAddMemoryDescriptor (
+ EfiConventionalMemory,
+ PageBaseAddress,
+ 1,
+ Capabilities
+ );
+ }
+ }
+ }
+ }
+ return Status;
+}
+
+
+/**
+ Frees nonexistent memory, reserved memory, system memory, or memory-mapped
+ I/O resources from the global coherency domain of the processor.
+
+ @param BaseAddress Base address of the memory space.
+ @param Length Length of the memory space.
+
+ @retval EFI_SUCCESS Space successfully freed.
+
+**/
+EFI_STATUS
+EFIAPI
+CoreFreeMemorySpace (
+ IN EFI_PHYSICAL_ADDRESS BaseAddress,
+ IN UINT64 Length
+ )
+{
+ DEBUG ((DEBUG_GCD, "GCD:FreeMemorySpace(Base=%016lx,Length=%016lx)\n", BaseAddress, Length));
+
+ return CoreConvertSpace (GCD_FREE_MEMORY_OPERATION, (EFI_GCD_MEMORY_TYPE) 0, (EFI_GCD_IO_TYPE) 0, BaseAddress, Length, 0, 0);
+}
+
+
+/**
+ Removes reserved memory, system memory, or memory-mapped I/O resources from
+ the global coherency domain of the processor.
+
+ @param BaseAddress Base address of the memory space.
+ @param Length Length of the memory space.
+
+ @retval EFI_SUCCESS Successfully remove a segment of memory space.
+
+**/
+EFI_STATUS
+EFIAPI
+CoreRemoveMemorySpace (
+ IN EFI_PHYSICAL_ADDRESS BaseAddress,
+ IN UINT64 Length
+ )
+{
+ DEBUG ((DEBUG_GCD, "GCD:RemoveMemorySpace(Base=%016lx,Length=%016lx)\n", BaseAddress, Length));
+
+ return CoreConvertSpace (GCD_REMOVE_MEMORY_OPERATION, (EFI_GCD_MEMORY_TYPE) 0, (EFI_GCD_IO_TYPE) 0, BaseAddress, Length, 0, 0);
+}
+
+
+/**
+ Build a memory descriptor according to an entry.
+
+ @param Descriptor The descriptor to be built
+ @param Entry According to this entry
+
+**/
+VOID
+BuildMemoryDescriptor (
+ IN OUT EFI_GCD_MEMORY_SPACE_DESCRIPTOR *Descriptor,
+ IN EFI_GCD_MAP_ENTRY *Entry
+ )
+{
+ Descriptor->BaseAddress = Entry->BaseAddress;
+ Descriptor->Length = Entry->EndAddress - Entry->BaseAddress + 1;
+ Descriptor->Capabilities = Entry->Capabilities;
+ Descriptor->Attributes = Entry->Attributes;
+ Descriptor->GcdMemoryType = Entry->GcdMemoryType;
+ Descriptor->ImageHandle = Entry->ImageHandle;
+ Descriptor->DeviceHandle = Entry->DeviceHandle;
+}
+
+
+/**
+ Retrieves the descriptor for a memory region containing a specified address.
+
+ @param BaseAddress Specified start address
+ @param Descriptor Specified length
+
+ @retval EFI_INVALID_PARAMETER Invalid parameter
+ @retval EFI_SUCCESS Successfully get memory space descriptor.
+
+**/
+EFI_STATUS
+EFIAPI
+CoreGetMemorySpaceDescriptor (
+ IN EFI_PHYSICAL_ADDRESS BaseAddress,
+ OUT EFI_GCD_MEMORY_SPACE_DESCRIPTOR *Descriptor
+ )
+{
+ EFI_STATUS Status;
+ LIST_ENTRY *StartLink;
+ LIST_ENTRY *EndLink;
+ EFI_GCD_MAP_ENTRY *Entry;
+
+ //
+ // Make sure parameters are valid
+ //
+ if (Descriptor == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ CoreAcquireGcdMemoryLock ();
+
+ //
+ // Search for the list of descriptors that contain BaseAddress
+ //
+ Status = CoreSearchGcdMapEntry (BaseAddress, 1, &StartLink, &EndLink, &mGcdMemorySpaceMap);
+ if (EFI_ERROR (Status)) {
+ Status = EFI_NOT_FOUND;
+ } else {
+ ASSERT (StartLink != NULL && EndLink != NULL);
+ //
+ // Copy the contents of the found descriptor into Descriptor
+ //
+ Entry = CR (StartLink, EFI_GCD_MAP_ENTRY, Link, EFI_GCD_MAP_SIGNATURE);
+ BuildMemoryDescriptor (Descriptor, Entry);
+ }
+
+ CoreReleaseGcdMemoryLock ();
+
+ return Status;
+}
+
+
+/**
+ Modifies the attributes for a memory region in the global coherency domain of the
+ processor.
+
+ @param BaseAddress Specified start address
+ @param Length Specified length
+ @param Attributes Specified attributes
+
+ @retval EFI_SUCCESS The attributes were set for the memory region.
+ @retval EFI_INVALID_PARAMETER Length is zero.
+ @retval EFI_UNSUPPORTED The processor does not support one or more bytes of the memory
+ resource range specified by BaseAddress and Length.
+ @retval EFI_UNSUPPORTED The bit mask of attributes is not support for the memory resource
+ range specified by BaseAddress and Length.
+ @retval EFI_ACCESS_DEFINED The attributes for the memory resource range specified by
+ BaseAddress and Length cannot be modified.
+ @retval EFI_OUT_OF_RESOURCES There are not enough system resources to modify the attributes of
+ the memory resource range.
+ @retval EFI_NOT_AVAILABLE_YET The attributes cannot be set because CPU architectural protocol is
+ not available yet.
+
+**/
+EFI_STATUS
+EFIAPI
+CoreSetMemorySpaceAttributes (
+ IN EFI_PHYSICAL_ADDRESS BaseAddress,
+ IN UINT64 Length,
+ IN UINT64 Attributes
+ )
+{
+ DEBUG ((DEBUG_GCD, "GCD:SetMemorySpaceAttributes(Base=%016lx,Length=%016lx)\n", BaseAddress, Length));
+ DEBUG ((DEBUG_GCD, " Attributes = %016lx\n", Attributes));
+
+ return CoreConvertSpace (GCD_SET_ATTRIBUTES_MEMORY_OPERATION, (EFI_GCD_MEMORY_TYPE) 0, (EFI_GCD_IO_TYPE) 0, BaseAddress, Length, 0, Attributes);
+}
+
+
+/**
+ Modifies the capabilities for a memory region in the global coherency domain of the
+ processor.
+
+ @param BaseAddress The physical address that is the start address of a memory region.
+ @param Length The size in bytes of the memory region.
+ @param Capabilities The bit mask of capabilities that the memory region supports.
+
+ @retval EFI_SUCCESS The capabilities were set for the memory region.
+ @retval EFI_INVALID_PARAMETER Length is zero.
+ @retval EFI_UNSUPPORTED The capabilities specified by Capabilities do not include the
+ memory region attributes currently in use.
+ @retval EFI_ACCESS_DENIED The capabilities for the memory resource range specified by
+ BaseAddress and Length cannot be modified.
+ @retval EFI_OUT_OF_RESOURCES There are not enough system resources to modify the capabilities
+ of the memory resource range.
+**/
+EFI_STATUS
+EFIAPI
+CoreSetMemorySpaceCapabilities (
+ IN EFI_PHYSICAL_ADDRESS BaseAddress,
+ IN UINT64 Length,
+ IN UINT64 Capabilities
+ )
+{
+ EFI_STATUS Status;
+
+ DEBUG ((DEBUG_GCD, "GCD:CoreSetMemorySpaceCapabilities(Base=%016lx,Length=%016lx)\n", BaseAddress, Length));
+ DEBUG ((DEBUG_GCD, " Capabilities = %016lx\n", Capabilities));
+
+ Status = CoreConvertSpace (GCD_SET_CAPABILITIES_MEMORY_OPERATION, (EFI_GCD_MEMORY_TYPE) 0, (EFI_GCD_IO_TYPE) 0, BaseAddress, Length, Capabilities, 0);
+ if (!EFI_ERROR(Status)) {
+ CoreUpdateMemoryAttributes(BaseAddress, RShiftU64(Length, EFI_PAGE_SHIFT), Capabilities & (~EFI_MEMORY_RUNTIME));
+ }
+
+ return Status;
+}
+
+
+/**
+ Returns a map of the memory resources in the global coherency domain of the
+ processor.
+
+ @param NumberOfDescriptors Number of descriptors.
+ @param MemorySpaceMap Descriptor array
+
+ @retval EFI_INVALID_PARAMETER Invalid parameter
+ @retval EFI_OUT_OF_RESOURCES No enough buffer to allocate
+ @retval EFI_SUCCESS Successfully get memory space map.
+
+**/
+EFI_STATUS
+EFIAPI
+CoreGetMemorySpaceMap (
+ OUT UINTN *NumberOfDescriptors,
+ OUT EFI_GCD_MEMORY_SPACE_DESCRIPTOR **MemorySpaceMap
+ )
+{
+ LIST_ENTRY *Link;
+ EFI_GCD_MAP_ENTRY *Entry;
+ EFI_GCD_MEMORY_SPACE_DESCRIPTOR *Descriptor;
+ UINTN DescriptorCount;
+
+ //
+ // Make sure parameters are valid
+ //
+ if (NumberOfDescriptors == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+ if (MemorySpaceMap == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ *NumberOfDescriptors = 0;
+ *MemorySpaceMap = NULL;
+
+ //
+ // Take the lock, for entering the loop with the lock held.
+ //
+ CoreAcquireGcdMemoryLock ();
+ while (TRUE) {
+ //
+ // Count descriptors. It might be done more than once because the
+ // AllocatePool() called below has to be running outside the GCD lock.
+ //
+ DescriptorCount = CoreCountGcdMapEntry (&mGcdMemorySpaceMap);
+ if (DescriptorCount == *NumberOfDescriptors && *MemorySpaceMap != NULL) {
+ //
+ // Fill in the MemorySpaceMap if no memory space map change.
+ //
+ Descriptor = *MemorySpaceMap;
+ Link = mGcdMemorySpaceMap.ForwardLink;
+ while (Link != &mGcdMemorySpaceMap) {
+ Entry = CR (Link, EFI_GCD_MAP_ENTRY, Link, EFI_GCD_MAP_SIGNATURE);
+ BuildMemoryDescriptor (Descriptor, Entry);
+ Descriptor++;
+ Link = Link->ForwardLink;
+ }
+ //
+ // We're done; exit the loop with the lock held.
+ //
+ break;
+ }
+
+ //
+ // Release the lock before memory allocation, because it might cause
+ // GCD lock conflict in one of calling path in AllocatPool().
+ //
+ CoreReleaseGcdMemoryLock ();
+
+ //
+ // Allocate memory to store the MemorySpaceMap. Note it might be already
+ // allocated if there's map descriptor change during memory allocation at
+ // last time.
+ //
+ if (*MemorySpaceMap != NULL) {
+ FreePool (*MemorySpaceMap);
+ }
+
+ *MemorySpaceMap = AllocatePool (DescriptorCount *
+ sizeof (EFI_GCD_MEMORY_SPACE_DESCRIPTOR));
+ if (*MemorySpaceMap == NULL) {
+ *NumberOfDescriptors = 0;
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ //
+ // Save the descriptor count got before for another round of check to make
+ // sure we won't miss any, since we have code running outside the GCD lock.
+ //
+ *NumberOfDescriptors = DescriptorCount;
+ //
+ // Re-acquire the lock, for the next iteration.
+ //
+ CoreAcquireGcdMemoryLock ();
+ }
+ //
+ // We exited the loop with the lock held, release it.
+ //
+ CoreReleaseGcdMemoryLock ();
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Adds reserved I/O or I/O resources to the global coherency domain of the processor.
+
+ @param GcdIoType IO type of the segment.
+ @param BaseAddress Base address of the segment.
+ @param Length Length of the segment.
+
+ @retval EFI_SUCCESS Merged this segment into GCD map.
+ @retval EFI_INVALID_PARAMETER Parameter not valid
+
+**/
+EFI_STATUS
+EFIAPI
+CoreAddIoSpace (
+ IN EFI_GCD_IO_TYPE GcdIoType,
+ IN EFI_PHYSICAL_ADDRESS BaseAddress,
+ IN UINT64 Length
+ )
+{
+ DEBUG ((DEBUG_GCD, "GCD:AddIoSpace(Base=%016lx,Length=%016lx)\n", BaseAddress, Length));
+ DEBUG ((DEBUG_GCD, " GcdIoType = %a\n", mGcdIoTypeNames[MIN (GcdIoType, EfiGcdIoTypeMaximum)]));
+
+ //
+ // Make sure parameters are valid
+ //
+ if (GcdIoType <= EfiGcdIoTypeNonExistent || GcdIoType >= EfiGcdIoTypeMaximum) {
+ return EFI_INVALID_PARAMETER;
+ }
+ return CoreConvertSpace (GCD_ADD_IO_OPERATION, (EFI_GCD_MEMORY_TYPE) 0, GcdIoType, BaseAddress, Length, 0, 0);
+}
+
+
+/**
+ Allocates nonexistent I/O, reserved I/O, or I/O resources from the global coherency
+ domain of the processor.
+
+ @param GcdAllocateType The type of allocate operation
+ @param GcdIoType The desired IO type
+ @param Alignment Align with 2^Alignment
+ @param Length Length to allocate
+ @param BaseAddress Base address to allocate
+ @param ImageHandle The image handle consume the allocated space.
+ @param DeviceHandle The device handle consume the allocated space.
+
+ @retval EFI_INVALID_PARAMETER Invalid parameter.
+ @retval EFI_NOT_FOUND No descriptor contains the desired space.
+ @retval EFI_SUCCESS IO space successfully allocated.
+
+**/
+EFI_STATUS
+EFIAPI
+CoreAllocateIoSpace (
+ IN EFI_GCD_ALLOCATE_TYPE GcdAllocateType,
+ IN EFI_GCD_IO_TYPE GcdIoType,
+ IN UINTN Alignment,
+ IN UINT64 Length,
+ IN OUT EFI_PHYSICAL_ADDRESS *BaseAddress,
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_HANDLE DeviceHandle OPTIONAL
+ )
+{
+ if (BaseAddress != NULL) {
+ DEBUG ((DEBUG_GCD, "GCD:AllocateIoSpace(Base=%016lx,Length=%016lx)\n", *BaseAddress, Length));
+ } else {
+ DEBUG ((DEBUG_GCD, "GCD:AllocateIoSpace(Base=<NULL>,Length=%016lx)\n", Length));
+ }
+ DEBUG ((DEBUG_GCD, " GcdAllocateType = %a\n", mGcdAllocationTypeNames[MIN (GcdAllocateType, EfiGcdMaxAllocateType)]));
+ DEBUG ((DEBUG_GCD, " GcdIoType = %a\n", mGcdIoTypeNames[MIN (GcdIoType, EfiGcdIoTypeMaximum)]));
+ DEBUG ((DEBUG_GCD, " Alignment = %016lx\n", LShiftU64 (1, Alignment)));
+ DEBUG ((DEBUG_GCD, " ImageHandle = %p\n", ImageHandle));
+ DEBUG ((DEBUG_GCD, " DeviceHandle = %p\n", DeviceHandle));
+
+ return CoreAllocateSpace (
+ GCD_ALLOCATE_IO_OPERATION,
+ GcdAllocateType,
+ (EFI_GCD_MEMORY_TYPE) 0,
+ GcdIoType,
+ Alignment,
+ Length,
+ BaseAddress,
+ ImageHandle,
+ DeviceHandle
+ );
+}
+
+
+/**
+ Frees nonexistent I/O, reserved I/O, or I/O resources from the global coherency
+ domain of the processor.
+
+ @param BaseAddress Base address of the segment.
+ @param Length Length of the segment.
+
+ @retval EFI_SUCCESS Space successfully freed.
+
+**/
+EFI_STATUS
+EFIAPI
+CoreFreeIoSpace (
+ IN EFI_PHYSICAL_ADDRESS BaseAddress,
+ IN UINT64 Length
+ )
+{
+ DEBUG ((DEBUG_GCD, "GCD:FreeIoSpace(Base=%016lx,Length=%016lx)\n", BaseAddress, Length));
+
+ return CoreConvertSpace (GCD_FREE_IO_OPERATION, (EFI_GCD_MEMORY_TYPE) 0, (EFI_GCD_IO_TYPE) 0, BaseAddress, Length, 0, 0);
+}
+
+
+/**
+ Removes reserved I/O or I/O resources from the global coherency domain of the
+ processor.
+
+ @param BaseAddress Base address of the segment.
+ @param Length Length of the segment.
+
+ @retval EFI_SUCCESS Successfully removed a segment of IO space.
+
+**/
+EFI_STATUS
+EFIAPI
+CoreRemoveIoSpace (
+ IN EFI_PHYSICAL_ADDRESS BaseAddress,
+ IN UINT64 Length
+ )
+{
+ DEBUG ((DEBUG_GCD, "GCD:RemoveIoSpace(Base=%016lx,Length=%016lx)\n", BaseAddress, Length));
+
+ return CoreConvertSpace (GCD_REMOVE_IO_OPERATION, (EFI_GCD_MEMORY_TYPE) 0, (EFI_GCD_IO_TYPE) 0, BaseAddress, Length, 0, 0);
+}
+
+
+/**
+ Build a IO descriptor according to an entry.
+
+ @param Descriptor The descriptor to be built
+ @param Entry According to this entry
+
+**/
+VOID
+BuildIoDescriptor (
+ IN EFI_GCD_IO_SPACE_DESCRIPTOR *Descriptor,
+ IN EFI_GCD_MAP_ENTRY *Entry
+ )
+{
+ Descriptor->BaseAddress = Entry->BaseAddress;
+ Descriptor->Length = Entry->EndAddress - Entry->BaseAddress + 1;
+ Descriptor->GcdIoType = Entry->GcdIoType;
+ Descriptor->ImageHandle = Entry->ImageHandle;
+ Descriptor->DeviceHandle = Entry->DeviceHandle;
+}
+
+
+/**
+ Retrieves the descriptor for an I/O region containing a specified address.
+
+ @param BaseAddress Specified start address
+ @param Descriptor Specified length
+
+ @retval EFI_INVALID_PARAMETER Descriptor is NULL.
+ @retval EFI_SUCCESS Successfully get the IO space descriptor.
+
+**/
+EFI_STATUS
+EFIAPI
+CoreGetIoSpaceDescriptor (
+ IN EFI_PHYSICAL_ADDRESS BaseAddress,
+ OUT EFI_GCD_IO_SPACE_DESCRIPTOR *Descriptor
+ )
+{
+ EFI_STATUS Status;
+ LIST_ENTRY *StartLink;
+ LIST_ENTRY *EndLink;
+ EFI_GCD_MAP_ENTRY *Entry;
+
+ //
+ // Make sure parameters are valid
+ //
+ if (Descriptor == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ CoreAcquireGcdIoLock ();
+
+ //
+ // Search for the list of descriptors that contain BaseAddress
+ //
+ Status = CoreSearchGcdMapEntry (BaseAddress, 1, &StartLink, &EndLink, &mGcdIoSpaceMap);
+ if (EFI_ERROR (Status)) {
+ Status = EFI_NOT_FOUND;
+ } else {
+ ASSERT (StartLink != NULL && EndLink != NULL);
+ //
+ // Copy the contents of the found descriptor into Descriptor
+ //
+ Entry = CR (StartLink, EFI_GCD_MAP_ENTRY, Link, EFI_GCD_MAP_SIGNATURE);
+ BuildIoDescriptor (Descriptor, Entry);
+ }
+
+ CoreReleaseGcdIoLock ();
+
+ return Status;
+}
+
+
+/**
+ Returns a map of the I/O resources in the global coherency domain of the processor.
+
+ @param NumberOfDescriptors Number of descriptors.
+ @param IoSpaceMap Descriptor array
+
+ @retval EFI_INVALID_PARAMETER Invalid parameter
+ @retval EFI_OUT_OF_RESOURCES No enough buffer to allocate
+ @retval EFI_SUCCESS Successfully get IO space map.
+
+**/
+EFI_STATUS
+EFIAPI
+CoreGetIoSpaceMap (
+ OUT UINTN *NumberOfDescriptors,
+ OUT EFI_GCD_IO_SPACE_DESCRIPTOR **IoSpaceMap
+ )
+{
+ EFI_STATUS Status;
+ LIST_ENTRY *Link;
+ EFI_GCD_MAP_ENTRY *Entry;
+ EFI_GCD_IO_SPACE_DESCRIPTOR *Descriptor;
+
+ //
+ // Make sure parameters are valid
+ //
+ if (NumberOfDescriptors == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+ if (IoSpaceMap == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ CoreAcquireGcdIoLock ();
+
+ //
+ // Count the number of descriptors
+ //
+ *NumberOfDescriptors = CoreCountGcdMapEntry (&mGcdIoSpaceMap);
+
+ //
+ // Allocate the IoSpaceMap
+ //
+ *IoSpaceMap = AllocatePool (*NumberOfDescriptors * sizeof (EFI_GCD_IO_SPACE_DESCRIPTOR));
+ if (*IoSpaceMap == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Done;
+ }
+
+ //
+ // Fill in the IoSpaceMap
+ //
+ Descriptor = *IoSpaceMap;
+ Link = mGcdIoSpaceMap.ForwardLink;
+ while (Link != &mGcdIoSpaceMap) {
+ Entry = CR (Link, EFI_GCD_MAP_ENTRY, Link, EFI_GCD_MAP_SIGNATURE);
+ BuildIoDescriptor (Descriptor, Entry);
+ Descriptor++;
+ Link = Link->ForwardLink;
+ }
+ Status = EFI_SUCCESS;
+
+Done:
+ CoreReleaseGcdIoLock ();
+ return Status;
+}
+
+
+/**
+ Converts a Resource Descriptor HOB attributes mask to an EFI Memory Descriptor
+ capabilities mask
+
+ @param GcdMemoryType Type of resource in the GCD memory map.
+ @param Attributes The attribute mask in the Resource Descriptor
+ HOB.
+
+ @return The capabilities mask for an EFI Memory Descriptor.
+
+**/
+UINT64
+CoreConvertResourceDescriptorHobAttributesToCapabilities (
+ EFI_GCD_MEMORY_TYPE GcdMemoryType,
+ UINT64 Attributes
+ )
+{
+ UINT64 Capabilities;
+ GCD_ATTRIBUTE_CONVERSION_ENTRY *Conversion;
+
+ //
+ // Convert the Resource HOB Attributes to an EFI Memory Capabilities mask
+ //
+ for (Capabilities = 0, Conversion = mAttributeConversionTable; Conversion->Attribute != 0; Conversion++) {
+ if (Conversion->Memory || ((GcdMemoryType != EfiGcdMemoryTypeSystemMemory) && (GcdMemoryType != EfiGcdMemoryTypeMoreReliable))) {
+ if (Attributes & Conversion->Attribute) {
+ Capabilities |= Conversion->Capability;
+ }
+ }
+ }
+
+ return Capabilities;
+}
+
+/**
+ Calculate total memory bin size neeeded.
+
+ @return The total memory bin size neeeded.
+
+**/
+UINT64
+CalculateTotalMemoryBinSizeNeeded (
+ VOID
+ )
+{
+ UINTN Index;
+ UINT64 TotalSize;
+
+ //
+ // Loop through each memory type in the order specified by the gMemoryTypeInformation[] array
+ //
+ TotalSize = 0;
+ for (Index = 0; gMemoryTypeInformation[Index].Type != EfiMaxMemoryType; Index++) {
+ TotalSize += LShiftU64 (gMemoryTypeInformation[Index].NumberOfPages, EFI_PAGE_SHIFT);
+ }
+
+ return TotalSize;
+}
+
+/**
+ External function. Initializes memory services based on the memory
+ descriptor HOBs. This function is responsible for priming the memory
+ map, so memory allocations and resource allocations can be made.
+ The first part of this function can not depend on any memory services
+ until at least one memory descriptor is provided to the memory services.
+
+ @param HobStart The start address of the HOB.
+ @param MemoryBaseAddress Start address of memory region found to init DXE
+ core.
+ @param MemoryLength Length of memory region found to init DXE core.
+
+ @retval EFI_SUCCESS Memory services successfully initialized.
+
+**/
+EFI_STATUS
+CoreInitializeMemoryServices (
+ IN VOID **HobStart,
+ OUT EFI_PHYSICAL_ADDRESS *MemoryBaseAddress,
+ OUT UINT64 *MemoryLength
+ )
+{
+ EFI_PEI_HOB_POINTERS Hob;
+ EFI_MEMORY_TYPE_INFORMATION *EfiMemoryTypeInformation;
+ UINTN DataSize;
+ BOOLEAN Found;
+ EFI_HOB_HANDOFF_INFO_TABLE *PhitHob;
+ EFI_HOB_RESOURCE_DESCRIPTOR *ResourceHob;
+ EFI_HOB_RESOURCE_DESCRIPTOR *PhitResourceHob;
+ EFI_PHYSICAL_ADDRESS BaseAddress;
+ UINT64 Length;
+ UINT64 Attributes;
+ UINT64 Capabilities;
+ EFI_PHYSICAL_ADDRESS TestedMemoryBaseAddress;
+ UINT64 TestedMemoryLength;
+ EFI_PHYSICAL_ADDRESS HighAddress;
+ EFI_HOB_GUID_TYPE *GuidHob;
+ UINT32 ReservedCodePageNumber;
+ UINT64 MinimalMemorySizeNeeded;
+
+ //
+ // Point at the first HOB. This must be the PHIT HOB.
+ //
+ Hob.Raw = *HobStart;
+ ASSERT (GET_HOB_TYPE (Hob) == EFI_HOB_TYPE_HANDOFF);
+
+ //
+ // Initialize the spin locks and maps in the memory services.
+ // Also fill in the memory services into the EFI Boot Services Table
+ //
+ CoreInitializePool ();
+
+ //
+ // Initialize Local Variables
+ //
+ PhitResourceHob = NULL;
+ ResourceHob = NULL;
+ BaseAddress = 0;
+ Length = 0;
+ Attributes = 0;
+
+ //
+ // Cache the PHIT HOB for later use
+ //
+ PhitHob = Hob.HandoffInformationTable;
+
+ if (PcdGet64(PcdLoadModuleAtFixAddressEnable) != 0) {
+ ReservedCodePageNumber = PcdGet32(PcdLoadFixAddressRuntimeCodePageNumber);
+ ReservedCodePageNumber += PcdGet32(PcdLoadFixAddressBootTimeCodePageNumber);
+
+ //
+ // cache the Top address for loading modules at Fixed Address
+ //
+ gLoadModuleAtFixAddressConfigurationTable.DxeCodeTopAddress = PhitHob->EfiMemoryTop
+ + EFI_PAGES_TO_SIZE(ReservedCodePageNumber);
+ }
+ //
+ // See if a Memory Type Information HOB is available
+ //
+ GuidHob = GetFirstGuidHob (&gEfiMemoryTypeInformationGuid);
+ if (GuidHob != NULL) {
+ EfiMemoryTypeInformation = GET_GUID_HOB_DATA (GuidHob);
+ DataSize = GET_GUID_HOB_DATA_SIZE (GuidHob);
+ if (EfiMemoryTypeInformation != NULL && DataSize > 0 && DataSize <= (EfiMaxMemoryType + 1) * sizeof (EFI_MEMORY_TYPE_INFORMATION)) {
+ CopyMem (&gMemoryTypeInformation, EfiMemoryTypeInformation, DataSize);
+ }
+ }
+
+ //
+ // Include the total memory bin size needed to make sure memory bin could be allocated successfully.
+ //
+ MinimalMemorySizeNeeded = MINIMUM_INITIAL_MEMORY_SIZE + CalculateTotalMemoryBinSizeNeeded ();
+
+ //
+ // Find the Resource Descriptor HOB that contains PHIT range EfiFreeMemoryBottom..EfiFreeMemoryTop
+ //
+ Found = FALSE;
+ for (Hob.Raw = *HobStart; !END_OF_HOB_LIST(Hob); Hob.Raw = GET_NEXT_HOB(Hob)) {
+ //
+ // Skip all HOBs except Resource Descriptor HOBs
+ //
+ if (GET_HOB_TYPE (Hob) != EFI_HOB_TYPE_RESOURCE_DESCRIPTOR) {
+ continue;
+ }
+
+ //
+ // Skip Resource Descriptor HOBs that do not describe tested system memory
+ //
+ ResourceHob = Hob.ResourceDescriptor;
+ if (ResourceHob->ResourceType != EFI_RESOURCE_SYSTEM_MEMORY) {
+ continue;
+ }
+ if ((ResourceHob->ResourceAttribute & MEMORY_ATTRIBUTE_MASK) != TESTED_MEMORY_ATTRIBUTES) {
+ continue;
+ }
+
+ //
+ // Skip Resource Descriptor HOBs that do not contain the PHIT range EfiFreeMemoryBottom..EfiFreeMemoryTop
+ //
+ if (PhitHob->EfiFreeMemoryBottom < ResourceHob->PhysicalStart) {
+ continue;
+ }
+ if (PhitHob->EfiFreeMemoryTop > (ResourceHob->PhysicalStart + ResourceHob->ResourceLength)) {
+ continue;
+ }
+
+ //
+ // Cache the resource descriptor HOB for the memory region described by the PHIT HOB
+ //
+ PhitResourceHob = ResourceHob;
+ Found = TRUE;
+
+ //
+ // Compute range between PHIT EfiMemoryTop and the end of the Resource Descriptor HOB
+ //
+ Attributes = PhitResourceHob->ResourceAttribute;
+ BaseAddress = PageAlignAddress (PhitHob->EfiMemoryTop);
+ Length = PageAlignLength (ResourceHob->PhysicalStart + ResourceHob->ResourceLength - BaseAddress);
+ if (Length < MinimalMemorySizeNeeded) {
+ //
+ // If that range is not large enough to intialize the DXE Core, then
+ // Compute range between PHIT EfiFreeMemoryBottom and PHIT EfiFreeMemoryTop
+ //
+ BaseAddress = PageAlignAddress (PhitHob->EfiFreeMemoryBottom);
+ Length = PageAlignLength (PhitHob->EfiFreeMemoryTop - BaseAddress);
+ if (Length < MinimalMemorySizeNeeded) {
+ //
+ // If that range is not large enough to intialize the DXE Core, then
+ // Compute range between the start of the Resource Descriptor HOB and the start of the HOB List
+ //
+ BaseAddress = PageAlignAddress (ResourceHob->PhysicalStart);
+ Length = PageAlignLength ((UINT64)((UINTN)*HobStart - BaseAddress));
+ }
+ }
+ break;
+ }
+
+ //
+ // Assert if a resource descriptor HOB for the memory region described by the PHIT was not found
+ //
+ ASSERT (Found);
+
+ //
+ // Take the range in the resource descriptor HOB for the memory region described
+ // by the PHIT as higher priority if it is big enough. It can make the memory bin
+ // allocated to be at the same memory region with PHIT that has more better compatibility
+ // to avoid memory fragmentation for some code practices assume and allocate <4G ACPI memory.
+ //
+ if (Length < MinimalMemorySizeNeeded) {
+ //
+ // Search all the resource descriptor HOBs from the highest possible addresses down for a memory
+ // region that is big enough to initialize the DXE core. Always skip the PHIT Resource HOB.
+ // The max address must be within the physically addressible range for the processor.
+ //
+ HighAddress = MAX_ALLOC_ADDRESS;
+ for (Hob.Raw = *HobStart; !END_OF_HOB_LIST(Hob); Hob.Raw = GET_NEXT_HOB(Hob)) {
+ //
+ // Skip the Resource Descriptor HOB that contains the PHIT
+ //
+ if (Hob.ResourceDescriptor == PhitResourceHob) {
+ continue;
+ }
+ //
+ // Skip all HOBs except Resource Descriptor HOBs
+ //
+ if (GET_HOB_TYPE (Hob) != EFI_HOB_TYPE_RESOURCE_DESCRIPTOR) {
+ continue;
+ }
+
+ //
+ // Skip Resource Descriptor HOBs that do not describe tested system memory below MAX_ALLOC_ADDRESS
+ //
+ ResourceHob = Hob.ResourceDescriptor;
+ if (ResourceHob->ResourceType != EFI_RESOURCE_SYSTEM_MEMORY) {
+ continue;
+ }
+ if ((ResourceHob->ResourceAttribute & MEMORY_ATTRIBUTE_MASK) != TESTED_MEMORY_ATTRIBUTES) {
+ continue;
+ }
+ if ((ResourceHob->PhysicalStart + ResourceHob->ResourceLength) > (EFI_PHYSICAL_ADDRESS)MAX_ALLOC_ADDRESS) {
+ continue;
+ }
+
+ //
+ // Skip Resource Descriptor HOBs that are below a previously found Resource Descriptor HOB
+ //
+ if (HighAddress != (EFI_PHYSICAL_ADDRESS)MAX_ALLOC_ADDRESS && ResourceHob->PhysicalStart <= HighAddress) {
+ continue;
+ }
+
+ //
+ // Skip Resource Descriptor HOBs that are not large enough to initilize the DXE Core
+ //
+ TestedMemoryBaseAddress = PageAlignAddress (ResourceHob->PhysicalStart);
+ TestedMemoryLength = PageAlignLength (ResourceHob->PhysicalStart + ResourceHob->ResourceLength - TestedMemoryBaseAddress);
+ if (TestedMemoryLength < MinimalMemorySizeNeeded) {
+ continue;
+ }
+
+ //
+ // Save the range described by the Resource Descriptor that is large enough to initilize the DXE Core
+ //
+ BaseAddress = TestedMemoryBaseAddress;
+ Length = TestedMemoryLength;
+ Attributes = ResourceHob->ResourceAttribute;
+ HighAddress = ResourceHob->PhysicalStart;
+ }
+ }
+
+ DEBUG ((EFI_D_INFO, "CoreInitializeMemoryServices:\n"));
+ DEBUG ((EFI_D_INFO, " BaseAddress - 0x%lx Length - 0x%lx MinimalMemorySizeNeeded - 0x%lx\n", BaseAddress, Length, MinimalMemorySizeNeeded));
+
+ //
+ // If no memory regions are found that are big enough to initialize the DXE core, then ASSERT().
+ //
+ ASSERT (Length >= MinimalMemorySizeNeeded);
+
+ //
+ // Convert the Resource HOB Attributes to an EFI Memory Capabilities mask
+ //
+ if ((Attributes & EFI_RESOURCE_ATTRIBUTE_MORE_RELIABLE) == EFI_RESOURCE_ATTRIBUTE_MORE_RELIABLE) {
+ Capabilities = CoreConvertResourceDescriptorHobAttributesToCapabilities (EfiGcdMemoryTypeMoreReliable, Attributes);
+ } else {
+ Capabilities = CoreConvertResourceDescriptorHobAttributesToCapabilities (EfiGcdMemoryTypeSystemMemory, Attributes);
+ }
+
+ //
+ // Declare the very first memory region, so the EFI Memory Services are available.
+ //
+ CoreAddMemoryDescriptor (
+ EfiConventionalMemory,
+ BaseAddress,
+ RShiftU64 (Length, EFI_PAGE_SHIFT),
+ Capabilities
+ );
+
+ *MemoryBaseAddress = BaseAddress;
+ *MemoryLength = Length;
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ External function. Initializes the GCD and memory services based on the memory
+ descriptor HOBs. This function is responsible for priming the GCD map and the
+ memory map, so memory allocations and resource allocations can be made. The
+ HobStart will be relocated to a pool buffer.
+
+ @param HobStart The start address of the HOB
+ @param MemoryBaseAddress Start address of memory region found to init DXE
+ core.
+ @param MemoryLength Length of memory region found to init DXE core.
+
+ @retval EFI_SUCCESS GCD services successfully initialized.
+
+**/
+EFI_STATUS
+CoreInitializeGcdServices (
+ IN OUT VOID **HobStart,
+ IN EFI_PHYSICAL_ADDRESS MemoryBaseAddress,
+ IN UINT64 MemoryLength
+ )
+{
+ EFI_PEI_HOB_POINTERS Hob;
+ VOID *NewHobList;
+ EFI_HOB_HANDOFF_INFO_TABLE *PhitHob;
+ UINT8 SizeOfMemorySpace;
+ UINT8 SizeOfIoSpace;
+ EFI_HOB_RESOURCE_DESCRIPTOR *ResourceHob;
+ EFI_PHYSICAL_ADDRESS BaseAddress;
+ UINT64 Length;
+ EFI_STATUS Status;
+ EFI_GCD_MAP_ENTRY *Entry;
+ EFI_GCD_MEMORY_TYPE GcdMemoryType;
+ EFI_GCD_IO_TYPE GcdIoType;
+ EFI_GCD_MEMORY_SPACE_DESCRIPTOR Descriptor;
+ EFI_HOB_MEMORY_ALLOCATION *MemoryHob;
+ EFI_HOB_FIRMWARE_VOLUME *FirmwareVolumeHob;
+ UINTN NumberOfDescriptors;
+ EFI_GCD_MEMORY_SPACE_DESCRIPTOR *MemorySpaceMap;
+ UINTN Index;
+ UINT64 Capabilities;
+ EFI_HOB_CPU * CpuHob;
+ EFI_GCD_MEMORY_SPACE_DESCRIPTOR *MemorySpaceMapHobList;
+
+ //
+ // Cache the PHIT HOB for later use
+ //
+ PhitHob = (EFI_HOB_HANDOFF_INFO_TABLE *)(*HobStart);
+
+ //
+ // Get the number of address lines in the I/O and Memory space for the CPU
+ //
+ CpuHob = GetFirstHob (EFI_HOB_TYPE_CPU);
+ ASSERT (CpuHob != NULL);
+ SizeOfMemorySpace = CpuHob->SizeOfMemorySpace;
+ SizeOfIoSpace = CpuHob->SizeOfIoSpace;
+
+ //
+ // Initialize the GCD Memory Space Map
+ //
+ Entry = AllocateCopyPool (sizeof (EFI_GCD_MAP_ENTRY), &mGcdMemorySpaceMapEntryTemplate);
+ ASSERT (Entry != NULL);
+
+ Entry->EndAddress = LShiftU64 (1, SizeOfMemorySpace) - 1;
+
+ InsertHeadList (&mGcdMemorySpaceMap, &Entry->Link);
+
+ CoreDumpGcdMemorySpaceMap (TRUE);
+
+ //
+ // Initialize the GCD I/O Space Map
+ //
+ Entry = AllocateCopyPool (sizeof (EFI_GCD_MAP_ENTRY), &mGcdIoSpaceMapEntryTemplate);
+ ASSERT (Entry != NULL);
+
+ Entry->EndAddress = LShiftU64 (1, SizeOfIoSpace) - 1;
+
+ InsertHeadList (&mGcdIoSpaceMap, &Entry->Link);
+
+ CoreDumpGcdIoSpaceMap (TRUE);
+
+ //
+ // Walk the HOB list and add all resource descriptors to the GCD
+ //
+ for (Hob.Raw = *HobStart; !END_OF_HOB_LIST(Hob); Hob.Raw = GET_NEXT_HOB(Hob)) {
+
+ GcdMemoryType = EfiGcdMemoryTypeNonExistent;
+ GcdIoType = EfiGcdIoTypeNonExistent;
+
+ if (GET_HOB_TYPE (Hob) == EFI_HOB_TYPE_RESOURCE_DESCRIPTOR) {
+
+ ResourceHob = Hob.ResourceDescriptor;
+
+ switch (ResourceHob->ResourceType) {
+ case EFI_RESOURCE_SYSTEM_MEMORY:
+ if ((ResourceHob->ResourceAttribute & MEMORY_ATTRIBUTE_MASK) == TESTED_MEMORY_ATTRIBUTES) {
+ if ((ResourceHob->ResourceAttribute & EFI_RESOURCE_ATTRIBUTE_MORE_RELIABLE) == EFI_RESOURCE_ATTRIBUTE_MORE_RELIABLE) {
+ GcdMemoryType = EfiGcdMemoryTypeMoreReliable;
+ } else {
+ GcdMemoryType = EfiGcdMemoryTypeSystemMemory;
+ }
+ }
+ if ((ResourceHob->ResourceAttribute & MEMORY_ATTRIBUTE_MASK) == INITIALIZED_MEMORY_ATTRIBUTES) {
+ GcdMemoryType = EfiGcdMemoryTypeReserved;
+ }
+ if ((ResourceHob->ResourceAttribute & MEMORY_ATTRIBUTE_MASK) == PRESENT_MEMORY_ATTRIBUTES) {
+ GcdMemoryType = EfiGcdMemoryTypeReserved;
+ }
+ if ((ResourceHob->ResourceAttribute & EFI_RESOURCE_ATTRIBUTE_PERSISTENT) == EFI_RESOURCE_ATTRIBUTE_PERSISTENT) {
+ GcdMemoryType = EfiGcdMemoryTypePersistent;
+ }
+ break;
+ case EFI_RESOURCE_MEMORY_MAPPED_IO:
+ case EFI_RESOURCE_FIRMWARE_DEVICE:
+ GcdMemoryType = EfiGcdMemoryTypeMemoryMappedIo;
+ break;
+ case EFI_RESOURCE_MEMORY_MAPPED_IO_PORT:
+ case EFI_RESOURCE_MEMORY_RESERVED:
+ GcdMemoryType = EfiGcdMemoryTypeReserved;
+ break;
+ case EFI_RESOURCE_IO:
+ GcdIoType = EfiGcdIoTypeIo;
+ break;
+ case EFI_RESOURCE_IO_RESERVED:
+ GcdIoType = EfiGcdIoTypeReserved;
+ break;
+ }
+
+ if (GcdMemoryType != EfiGcdMemoryTypeNonExistent) {
+ //
+ // Validate the Resource HOB Attributes
+ //
+ CoreValidateResourceDescriptorHobAttributes (ResourceHob->ResourceAttribute);
+
+ //
+ // Convert the Resource HOB Attributes to an EFI Memory Capabilities mask
+ //
+ Capabilities = CoreConvertResourceDescriptorHobAttributesToCapabilities (
+ GcdMemoryType,
+ ResourceHob->ResourceAttribute
+ );
+
+ Status = CoreInternalAddMemorySpace (
+ GcdMemoryType,
+ ResourceHob->PhysicalStart,
+ ResourceHob->ResourceLength,
+ Capabilities
+ );
+ }
+
+ if (GcdIoType != EfiGcdIoTypeNonExistent) {
+ Status = CoreAddIoSpace (
+ GcdIoType,
+ ResourceHob->PhysicalStart,
+ ResourceHob->ResourceLength
+ );
+ }
+ }
+ }
+
+ //
+ // Allocate first memory region from the GCD by the DXE core
+ //
+ Status = CoreGetMemorySpaceDescriptor (MemoryBaseAddress, &Descriptor);
+ if (!EFI_ERROR (Status)) {
+ ASSERT ((Descriptor.GcdMemoryType == EfiGcdMemoryTypeSystemMemory) ||
+ (Descriptor.GcdMemoryType == EfiGcdMemoryTypeMoreReliable));
+ Status = CoreAllocateMemorySpace (
+ EfiGcdAllocateAddress,
+ Descriptor.GcdMemoryType,
+ 0,
+ MemoryLength,
+ &MemoryBaseAddress,
+ gDxeCoreImageHandle,
+ NULL
+ );
+ }
+
+ //
+ // Walk the HOB list and allocate all memory space that is consumed by memory allocation HOBs,
+ // and Firmware Volume HOBs. Also update the EFI Memory Map with the memory allocation HOBs.
+ //
+ for (Hob.Raw = *HobStart; !END_OF_HOB_LIST(Hob); Hob.Raw = GET_NEXT_HOB(Hob)) {
+ if (GET_HOB_TYPE (Hob) == EFI_HOB_TYPE_MEMORY_ALLOCATION) {
+ MemoryHob = Hob.MemoryAllocation;
+ BaseAddress = MemoryHob->AllocDescriptor.MemoryBaseAddress;
+ Status = CoreGetMemorySpaceDescriptor (BaseAddress, &Descriptor);
+ if (!EFI_ERROR (Status)) {
+ Status = CoreAllocateMemorySpace (
+ EfiGcdAllocateAddress,
+ Descriptor.GcdMemoryType,
+ 0,
+ MemoryHob->AllocDescriptor.MemoryLength,
+ &BaseAddress,
+ gDxeCoreImageHandle,
+ NULL
+ );
+ if (!EFI_ERROR (Status) &&
+ ((Descriptor.GcdMemoryType == EfiGcdMemoryTypeSystemMemory) ||
+ (Descriptor.GcdMemoryType == EfiGcdMemoryTypeMoreReliable))) {
+ CoreAddMemoryDescriptor (
+ MemoryHob->AllocDescriptor.MemoryType,
+ MemoryHob->AllocDescriptor.MemoryBaseAddress,
+ RShiftU64 (MemoryHob->AllocDescriptor.MemoryLength, EFI_PAGE_SHIFT),
+ Descriptor.Capabilities & (~EFI_MEMORY_RUNTIME)
+ );
+ }
+ }
+ }
+
+ if (GET_HOB_TYPE (Hob) == EFI_HOB_TYPE_FV) {
+ FirmwareVolumeHob = Hob.FirmwareVolume;
+ BaseAddress = FirmwareVolumeHob->BaseAddress;
+ Status = CoreAllocateMemorySpace (
+ EfiGcdAllocateAddress,
+ EfiGcdMemoryTypeMemoryMappedIo,
+ 0,
+ FirmwareVolumeHob->Length,
+ &BaseAddress,
+ gDxeCoreImageHandle,
+ NULL
+ );
+ }
+ }
+
+ //
+ // Add and allocate the remaining unallocated system memory to the memory services.
+ //
+ Status = CoreGetMemorySpaceMap (&NumberOfDescriptors, &MemorySpaceMap);
+ ASSERT (Status == EFI_SUCCESS);
+
+ MemorySpaceMapHobList = NULL;
+ for (Index = 0; Index < NumberOfDescriptors; Index++) {
+ if ((MemorySpaceMap[Index].GcdMemoryType == EfiGcdMemoryTypeSystemMemory) ||
+ (MemorySpaceMap[Index].GcdMemoryType == EfiGcdMemoryTypeMoreReliable)) {
+ if (MemorySpaceMap[Index].ImageHandle == NULL) {
+ BaseAddress = PageAlignAddress (MemorySpaceMap[Index].BaseAddress);
+ Length = PageAlignLength (MemorySpaceMap[Index].BaseAddress + MemorySpaceMap[Index].Length - BaseAddress);
+ if (Length == 0 || MemorySpaceMap[Index].BaseAddress + MemorySpaceMap[Index].Length < BaseAddress) {
+ continue;
+ }
+ if (((UINTN) MemorySpaceMap[Index].BaseAddress <= (UINTN) (*HobStart)) &&
+ ((UINTN) (MemorySpaceMap[Index].BaseAddress + MemorySpaceMap[Index].Length) >= (UINTN) PhitHob->EfiFreeMemoryBottom)) {
+ //
+ // Skip the memory space that covers HOB List, it should be processed
+ // after HOB List relocation to avoid the resources allocated by others
+ // to corrupt HOB List before its relocation.
+ //
+ MemorySpaceMapHobList = &MemorySpaceMap[Index];
+ continue;
+ }
+ CoreAddMemoryDescriptor (
+ EfiConventionalMemory,
+ BaseAddress,
+ RShiftU64 (Length, EFI_PAGE_SHIFT),
+ MemorySpaceMap[Index].Capabilities & (~EFI_MEMORY_RUNTIME)
+ );
+ Status = CoreAllocateMemorySpace (
+ EfiGcdAllocateAddress,
+ MemorySpaceMap[Index].GcdMemoryType,
+ 0,
+ Length,
+ &BaseAddress,
+ gDxeCoreImageHandle,
+ NULL
+ );
+ }
+ }
+ }
+
+ //
+ // Relocate HOB List to an allocated pool buffer.
+ // The relocation should be at after all the tested memory resources added
+ // (except the memory space that covers HOB List) to the memory services,
+ // because the memory resource found in CoreInitializeMemoryServices()
+ // may have not enough remaining resource for HOB List.
+ //
+ NewHobList = AllocateCopyPool (
+ (UINTN) PhitHob->EfiFreeMemoryBottom - (UINTN) (*HobStart),
+ *HobStart
+ );
+ ASSERT (NewHobList != NULL);
+
+ *HobStart = NewHobList;
+ gHobList = NewHobList;
+
+ if (MemorySpaceMapHobList != NULL) {
+ //
+ // Add and allocate the memory space that covers HOB List to the memory services
+ // after HOB List relocation.
+ //
+ BaseAddress = PageAlignAddress (MemorySpaceMapHobList->BaseAddress);
+ Length = PageAlignLength (MemorySpaceMapHobList->BaseAddress + MemorySpaceMapHobList->Length - BaseAddress);
+ CoreAddMemoryDescriptor (
+ EfiConventionalMemory,
+ BaseAddress,
+ RShiftU64 (Length, EFI_PAGE_SHIFT),
+ MemorySpaceMapHobList->Capabilities & (~EFI_MEMORY_RUNTIME)
+ );
+ Status = CoreAllocateMemorySpace (
+ EfiGcdAllocateAddress,
+ MemorySpaceMapHobList->GcdMemoryType,
+ 0,
+ Length,
+ &BaseAddress,
+ gDxeCoreImageHandle,
+ NULL
+ );
+ }
+
+ CoreFreePool (MemorySpaceMap);
+
+ return EFI_SUCCESS;
+}
diff --git a/roms/edk2/MdeModulePkg/Core/Dxe/Gcd/Gcd.h b/roms/edk2/MdeModulePkg/Core/Dxe/Gcd/Gcd.h
new file mode 100644
index 000000000..715687b92
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Core/Dxe/Gcd/Gcd.h
@@ -0,0 +1,40 @@
+/** @file
+ GCD Operations and data structure used to
+ convert from GCD attributes to EFI Memory Map attributes.
+
+Copyright (c) 2006 - 2014, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _GCD_H_
+#define _GCD_H_
+
+//
+// GCD Operations
+//
+#define GCD_MEMORY_SPACE_OPERATION 0x20
+#define GCD_IO_SPACE_OPERATION 0x40
+
+#define GCD_ADD_MEMORY_OPERATION (GCD_MEMORY_SPACE_OPERATION | 0)
+#define GCD_ALLOCATE_MEMORY_OPERATION (GCD_MEMORY_SPACE_OPERATION | 1)
+#define GCD_FREE_MEMORY_OPERATION (GCD_MEMORY_SPACE_OPERATION | 2)
+#define GCD_REMOVE_MEMORY_OPERATION (GCD_MEMORY_SPACE_OPERATION | 3)
+#define GCD_SET_ATTRIBUTES_MEMORY_OPERATION (GCD_MEMORY_SPACE_OPERATION | 4)
+#define GCD_SET_CAPABILITIES_MEMORY_OPERATION (GCD_MEMORY_SPACE_OPERATION | 5)
+
+#define GCD_ADD_IO_OPERATION (GCD_IO_SPACE_OPERATION | 0)
+#define GCD_ALLOCATE_IO_OPERATION (GCD_IO_SPACE_OPERATION | 1)
+#define GCD_FREE_IO_OPERATION (GCD_IO_SPACE_OPERATION | 2)
+#define GCD_REMOVE_IO_OPERATION (GCD_IO_SPACE_OPERATION | 3)
+
+//
+// The data structure used to convert from GCD attributes to EFI Memory Map attributes
+//
+typedef struct {
+ UINT64 Attribute;
+ UINT64 Capability;
+ BOOLEAN Memory;
+} GCD_ATTRIBUTE_CONVERSION_ENTRY;
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Core/Dxe/Hand/DriverSupport.c b/roms/edk2/MdeModulePkg/Core/Dxe/Hand/DriverSupport.c
new file mode 100644
index 000000000..feabf12fa
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Core/Dxe/Hand/DriverSupport.c
@@ -0,0 +1,958 @@
+/** @file
+ Support functions to connect/disconnect UEFI Driver model Protocol
+
+Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "DxeMain.h"
+#include "Handle.h"
+
+
+//
+// Driver Support Functions
+//
+/**
+ Connects one or more drivers to a controller.
+
+ @param ControllerHandle The handle of the controller to which driver(s) are to be connected.
+ @param DriverImageHandle A pointer to an ordered list handles that support the
+ EFI_DRIVER_BINDING_PROTOCOL.
+ @param RemainingDevicePath A pointer to the device path that specifies a child of the
+ controller specified by ControllerHandle.
+ @param Recursive If TRUE, then ConnectController() is called recursively
+ until the entire tree of controllers below the controller specified
+ by ControllerHandle have been created. If FALSE, then
+ the tree of controllers is only expanded one level.
+
+ @retval EFI_SUCCESS 1) One or more drivers were connected to ControllerHandle.
+ 2) No drivers were connected to ControllerHandle, but
+ RemainingDevicePath is not NULL, and it is an End Device
+ Path Node.
+ @retval EFI_INVALID_PARAMETER ControllerHandle is NULL.
+ @retval EFI_NOT_FOUND 1) There are no EFI_DRIVER_BINDING_PROTOCOL instances
+ present in the system.
+ 2) No drivers were connected to ControllerHandle.
+ @retval EFI_SECURITY_VIOLATION
+ The user has no permission to start UEFI device drivers on the device path
+ associated with the ControllerHandle or specified by the RemainingDevicePath.
+
+**/
+EFI_STATUS
+EFIAPI
+CoreConnectController (
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_HANDLE *DriverImageHandle OPTIONAL,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL,
+ IN BOOLEAN Recursive
+ )
+{
+ EFI_STATUS Status;
+ EFI_STATUS ReturnStatus;
+ IHANDLE *Handle;
+ PROTOCOL_INTERFACE *Prot;
+ LIST_ENTRY *Link;
+ LIST_ENTRY *ProtLink;
+ OPEN_PROTOCOL_DATA *OpenData;
+ EFI_DEVICE_PATH_PROTOCOL *AlignedRemainingDevicePath;
+ EFI_HANDLE *ChildHandleBuffer;
+ UINTN ChildHandleCount;
+ UINTN Index;
+ UINTN HandleFilePathSize;
+ UINTN RemainingDevicePathSize;
+ EFI_DEVICE_PATH_PROTOCOL *HandleFilePath;
+ EFI_DEVICE_PATH_PROTOCOL *FilePath;
+ EFI_DEVICE_PATH_PROTOCOL *TempFilePath;
+
+ //
+ // Make sure ControllerHandle is valid
+ //
+ Status = CoreValidateHandle (ControllerHandle);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if (gSecurity2 != NULL) {
+ //
+ // Check whether the user has permission to start UEFI device drivers.
+ //
+ Status = CoreHandleProtocol (ControllerHandle, &gEfiDevicePathProtocolGuid, (VOID **)&HandleFilePath);
+ if (!EFI_ERROR (Status)) {
+ ASSERT (HandleFilePath != NULL);
+ FilePath = HandleFilePath;
+ TempFilePath = NULL;
+ if (RemainingDevicePath != NULL && !Recursive) {
+ HandleFilePathSize = GetDevicePathSize (HandleFilePath) - sizeof (EFI_DEVICE_PATH_PROTOCOL);
+ RemainingDevicePathSize = GetDevicePathSize (RemainingDevicePath);
+ TempFilePath = AllocateZeroPool (HandleFilePathSize + RemainingDevicePathSize);
+ ASSERT (TempFilePath != NULL);
+ CopyMem (TempFilePath, HandleFilePath, HandleFilePathSize);
+ CopyMem ((UINT8 *) TempFilePath + HandleFilePathSize, RemainingDevicePath, RemainingDevicePathSize);
+ FilePath = TempFilePath;
+ }
+ Status = gSecurity2->FileAuthentication (
+ gSecurity2,
+ FilePath,
+ NULL,
+ 0,
+ FALSE
+ );
+ if (TempFilePath != NULL) {
+ FreePool (TempFilePath);
+ }
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+ }
+
+ Handle = ControllerHandle;
+
+ //
+ // Make a copy of RemainingDevicePath to guanatee it is aligned
+ //
+ AlignedRemainingDevicePath = NULL;
+ if (RemainingDevicePath != NULL) {
+ AlignedRemainingDevicePath = DuplicateDevicePath (RemainingDevicePath);
+
+ if (AlignedRemainingDevicePath == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ }
+
+ //
+ // Connect all drivers to ControllerHandle
+ // If CoreConnectSingleController returns EFI_NOT_READY, then the number of
+ // Driver Binding Protocols in the handle database has increased during the call
+ // so the connect operation must be restarted
+ //
+ do {
+ ReturnStatus = CoreConnectSingleController (
+ ControllerHandle,
+ DriverImageHandle,
+ AlignedRemainingDevicePath
+ );
+ } while (ReturnStatus == EFI_NOT_READY);
+
+ //
+ // Free the aligned copy of RemainingDevicePath
+ //
+ if (AlignedRemainingDevicePath != NULL) {
+ CoreFreePool (AlignedRemainingDevicePath);
+ }
+
+ //
+ // If recursive, then connect all drivers to all of ControllerHandle's children
+ //
+ if (Recursive) {
+ //
+ // Acquire the protocol lock on the handle database so the child handles can be collected
+ //
+ CoreAcquireProtocolLock ();
+
+ //
+ // Make sure the DriverBindingHandle is valid
+ //
+ Status = CoreValidateHandle (ControllerHandle);
+ if (EFI_ERROR (Status)) {
+ //
+ // Release the protocol lock on the handle database
+ //
+ CoreReleaseProtocolLock ();
+
+ return ReturnStatus;
+ }
+
+
+ //
+ // Count ControllerHandle's children
+ //
+ for (Link = Handle->Protocols.ForwardLink, ChildHandleCount = 0; Link != &Handle->Protocols; Link = Link->ForwardLink) {
+ Prot = CR(Link, PROTOCOL_INTERFACE, Link, PROTOCOL_INTERFACE_SIGNATURE);
+ for (ProtLink = Prot->OpenList.ForwardLink;
+ ProtLink != &Prot->OpenList;
+ ProtLink = ProtLink->ForwardLink) {
+ OpenData = CR (ProtLink, OPEN_PROTOCOL_DATA, Link, OPEN_PROTOCOL_DATA_SIGNATURE);
+ if ((OpenData->Attributes & EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER) != 0) {
+ ChildHandleCount++;
+ }
+ }
+ }
+
+ //
+ // Allocate a handle buffer for ControllerHandle's children
+ //
+ ChildHandleBuffer = AllocatePool (ChildHandleCount * sizeof(EFI_HANDLE));
+ if (ChildHandleBuffer == NULL) {
+ CoreReleaseProtocolLock ();
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ //
+ // Fill in a handle buffer with ControllerHandle's children
+ //
+ for (Link = Handle->Protocols.ForwardLink, ChildHandleCount = 0; Link != &Handle->Protocols; Link = Link->ForwardLink) {
+ Prot = CR(Link, PROTOCOL_INTERFACE, Link, PROTOCOL_INTERFACE_SIGNATURE);
+ for (ProtLink = Prot->OpenList.ForwardLink;
+ ProtLink != &Prot->OpenList;
+ ProtLink = ProtLink->ForwardLink) {
+ OpenData = CR (ProtLink, OPEN_PROTOCOL_DATA, Link, OPEN_PROTOCOL_DATA_SIGNATURE);
+ if ((OpenData->Attributes & EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER) != 0) {
+ ChildHandleBuffer[ChildHandleCount] = OpenData->ControllerHandle;
+ ChildHandleCount++;
+ }
+ }
+ }
+
+ //
+ // Release the protocol lock on the handle database
+ //
+ CoreReleaseProtocolLock ();
+
+ //
+ // Recursively connect each child handle
+ //
+ for (Index = 0; Index < ChildHandleCount; Index++) {
+ CoreConnectController (
+ ChildHandleBuffer[Index],
+ NULL,
+ NULL,
+ TRUE
+ );
+ }
+
+ //
+ // Free the handle buffer of ControllerHandle's children
+ //
+ CoreFreePool (ChildHandleBuffer);
+ }
+
+ return ReturnStatus;
+}
+
+
+/**
+ Add Driver Binding Protocols from Context Driver Image Handles to sorted
+ Driver Binding Protocol list.
+
+ @param DriverBindingHandle Handle of the driver binding
+ protocol.
+ @param NumberOfSortedDriverBindingProtocols Number Of sorted driver binding
+ protocols
+ @param SortedDriverBindingProtocols The sorted protocol list.
+ @param DriverBindingHandleCount Driver Binding Handle Count.
+ @param DriverBindingHandleBuffer The buffer of driver binding
+ protocol to be modified.
+ @param IsImageHandle Indicate whether
+ DriverBindingHandle is an image
+ handle
+
+ @return None.
+
+**/
+VOID
+AddSortedDriverBindingProtocol (
+ IN EFI_HANDLE DriverBindingHandle,
+ IN OUT UINTN *NumberOfSortedDriverBindingProtocols,
+ IN OUT EFI_DRIVER_BINDING_PROTOCOL **SortedDriverBindingProtocols,
+ IN UINTN DriverBindingHandleCount,
+ IN OUT EFI_HANDLE *DriverBindingHandleBuffer,
+ IN BOOLEAN IsImageHandle
+ )
+{
+ EFI_STATUS Status;
+ EFI_DRIVER_BINDING_PROTOCOL *DriverBinding;
+ UINTN Index;
+
+ //
+ // Make sure the DriverBindingHandle is valid
+ //
+ Status = CoreValidateHandle (DriverBindingHandle);
+ if (EFI_ERROR (Status)) {
+ return;
+ }
+
+ //
+ // If IsImageHandle is TRUE, then DriverBindingHandle is an image handle
+ // Find all the DriverBindingHandles associated with that image handle and add them to the sorted list
+ //
+ if (IsImageHandle) {
+ //
+ // Loop through all the Driver Binding Handles
+ //
+ for (Index = 0; Index < DriverBindingHandleCount; Index++) {
+ //
+ // Retrieve the Driver Binding Protocol associated with each Driver Binding Handle
+ //
+ Status = CoreHandleProtocol (
+ DriverBindingHandleBuffer[Index],
+ &gEfiDriverBindingProtocolGuid,
+ (VOID **) &DriverBinding
+ );
+ if (EFI_ERROR (Status) || DriverBinding == NULL) {
+ continue;
+ }
+
+ //
+ // If the ImageHandle associated with DriverBinding matches DriverBindingHandle,
+ // then add the DriverBindingProtocol[Index] to the sorted list
+ //
+ if (DriverBinding->ImageHandle == DriverBindingHandle) {
+ AddSortedDriverBindingProtocol (
+ DriverBindingHandleBuffer[Index],
+ NumberOfSortedDriverBindingProtocols,
+ SortedDriverBindingProtocols,
+ DriverBindingHandleCount,
+ DriverBindingHandleBuffer,
+ FALSE
+ );
+ }
+ }
+ return;
+ }
+
+ //
+ // Retrieve the Driver Binding Protocol from DriverBindingHandle
+ //
+ Status = CoreHandleProtocol(
+ DriverBindingHandle,
+ &gEfiDriverBindingProtocolGuid,
+ (VOID **) &DriverBinding
+ );
+ //
+ // If DriverBindingHandle does not support the Driver Binding Protocol then return
+ //
+ if (EFI_ERROR (Status) || DriverBinding == NULL) {
+ return;
+ }
+
+ //
+ // See if DriverBinding is already in the sorted list
+ //
+ for (Index = 0; Index < *NumberOfSortedDriverBindingProtocols && Index < DriverBindingHandleCount; Index++) {
+ if (DriverBinding == SortedDriverBindingProtocols[Index]) {
+ return;
+ }
+ }
+
+ //
+ // Add DriverBinding to the end of the list
+ //
+ if (*NumberOfSortedDriverBindingProtocols < DriverBindingHandleCount) {
+ SortedDriverBindingProtocols[*NumberOfSortedDriverBindingProtocols] = DriverBinding;
+ }
+ *NumberOfSortedDriverBindingProtocols = *NumberOfSortedDriverBindingProtocols + 1;
+
+ //
+ // Mark the cooresponding handle in DriverBindingHandleBuffer as used
+ //
+ for (Index = 0; Index < DriverBindingHandleCount; Index++) {
+ if (DriverBindingHandleBuffer[Index] == DriverBindingHandle) {
+ DriverBindingHandleBuffer[Index] = NULL;
+ }
+ }
+}
+
+
+/**
+ Connects a controller to a driver.
+
+ @param ControllerHandle Handle of the controller to be
+ connected.
+ @param ContextDriverImageHandles DriverImageHandle A pointer to an
+ ordered list of driver image
+ handles.
+ @param RemainingDevicePath RemainingDevicePath A pointer to
+ the device path that specifies a
+ child of the controller
+ specified by ControllerHandle.
+
+ @retval EFI_SUCCESS One or more drivers were
+ connected to ControllerHandle.
+ @retval EFI_OUT_OF_RESOURCES No enough system resources to
+ complete the request.
+ @retval EFI_NOT_FOUND No drivers were connected to
+ ControllerHandle.
+
+**/
+EFI_STATUS
+CoreConnectSingleController (
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_HANDLE *ContextDriverImageHandles OPTIONAL,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+ UINTN Index;
+ EFI_HANDLE DriverImageHandle;
+ EFI_PLATFORM_DRIVER_OVERRIDE_PROTOCOL *PlatformDriverOverride;
+ EFI_BUS_SPECIFIC_DRIVER_OVERRIDE_PROTOCOL *BusSpecificDriverOverride;
+ UINTN DriverBindingHandleCount;
+ EFI_HANDLE *DriverBindingHandleBuffer;
+ UINTN NewDriverBindingHandleCount;
+ EFI_HANDLE *NewDriverBindingHandleBuffer;
+ EFI_DRIVER_BINDING_PROTOCOL *DriverBinding;
+ EFI_DRIVER_FAMILY_OVERRIDE_PROTOCOL *DriverFamilyOverride;
+ UINTN NumberOfSortedDriverBindingProtocols;
+ EFI_DRIVER_BINDING_PROTOCOL **SortedDriverBindingProtocols;
+ UINT32 DriverFamilyOverrideVersion;
+ UINT32 HighestVersion;
+ UINTN HighestIndex;
+ UINTN SortIndex;
+ BOOLEAN OneStarted;
+ BOOLEAN DriverFound;
+
+ //
+ // Initialize local variables
+ //
+ DriverBindingHandleCount = 0;
+ DriverBindingHandleBuffer = NULL;
+ NumberOfSortedDriverBindingProtocols = 0;
+ SortedDriverBindingProtocols = NULL;
+ PlatformDriverOverride = NULL;
+ NewDriverBindingHandleBuffer = NULL;
+
+ //
+ // Get list of all Driver Binding Protocol Instances
+ //
+ Status = CoreLocateHandleBuffer (
+ ByProtocol,
+ &gEfiDriverBindingProtocolGuid,
+ NULL,
+ &DriverBindingHandleCount,
+ &DriverBindingHandleBuffer
+ );
+ if (EFI_ERROR (Status) || (DriverBindingHandleCount == 0)) {
+ return EFI_NOT_FOUND;
+ }
+
+ //
+ // Allocate a duplicate array for the sorted Driver Binding Protocol Instances
+ //
+ SortedDriverBindingProtocols = AllocatePool (sizeof (VOID *) * DriverBindingHandleCount);
+ if (SortedDriverBindingProtocols == NULL) {
+ CoreFreePool (DriverBindingHandleBuffer);
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ //
+ // Add Driver Binding Protocols from Context Driver Image Handles first
+ //
+ if (ContextDriverImageHandles != NULL) {
+ for (Index = 0; ContextDriverImageHandles[Index] != NULL; Index++) {
+ AddSortedDriverBindingProtocol (
+ ContextDriverImageHandles[Index],
+ &NumberOfSortedDriverBindingProtocols,
+ SortedDriverBindingProtocols,
+ DriverBindingHandleCount,
+ DriverBindingHandleBuffer,
+ FALSE
+ );
+ }
+ }
+
+ //
+ // Add the Platform Driver Override Protocol drivers for ControllerHandle next
+ //
+ Status = CoreLocateProtocol (
+ &gEfiPlatformDriverOverrideProtocolGuid,
+ NULL,
+ (VOID **) &PlatformDriverOverride
+ );
+ if (!EFI_ERROR (Status) && (PlatformDriverOverride != NULL)) {
+ DriverImageHandle = NULL;
+ do {
+ Status = PlatformDriverOverride->GetDriver (
+ PlatformDriverOverride,
+ ControllerHandle,
+ &DriverImageHandle
+ );
+ if (!EFI_ERROR (Status)) {
+ AddSortedDriverBindingProtocol (
+ DriverImageHandle,
+ &NumberOfSortedDriverBindingProtocols,
+ SortedDriverBindingProtocols,
+ DriverBindingHandleCount,
+ DriverBindingHandleBuffer,
+ TRUE
+ );
+ }
+ } while (!EFI_ERROR (Status));
+ }
+
+ //
+ // Add the Driver Family Override Protocol drivers for ControllerHandle
+ //
+ while (TRUE) {
+ HighestIndex = DriverBindingHandleCount;
+ HighestVersion = 0;
+ for (Index = 0; Index < DriverBindingHandleCount; Index++) {
+ Status = CoreHandleProtocol (
+ DriverBindingHandleBuffer[Index],
+ &gEfiDriverFamilyOverrideProtocolGuid,
+ (VOID **) &DriverFamilyOverride
+ );
+ if (!EFI_ERROR (Status) && (DriverFamilyOverride != NULL)) {
+ DriverFamilyOverrideVersion = DriverFamilyOverride->GetVersion (DriverFamilyOverride);
+ if ((HighestIndex == DriverBindingHandleCount) || (DriverFamilyOverrideVersion > HighestVersion)) {
+ HighestVersion = DriverFamilyOverrideVersion;
+ HighestIndex = Index;
+ }
+ }
+ }
+
+ if (HighestIndex == DriverBindingHandleCount) {
+ break;
+ }
+
+ AddSortedDriverBindingProtocol (
+ DriverBindingHandleBuffer[HighestIndex],
+ &NumberOfSortedDriverBindingProtocols,
+ SortedDriverBindingProtocols,
+ DriverBindingHandleCount,
+ DriverBindingHandleBuffer,
+ FALSE
+ );
+ }
+
+ //
+ // Get the Bus Specific Driver Override Protocol instance on the Controller Handle
+ //
+ Status = CoreHandleProtocol (
+ ControllerHandle,
+ &gEfiBusSpecificDriverOverrideProtocolGuid,
+ (VOID **) &BusSpecificDriverOverride
+ );
+ if (!EFI_ERROR (Status) && (BusSpecificDriverOverride != NULL)) {
+ DriverImageHandle = NULL;
+ do {
+ Status = BusSpecificDriverOverride->GetDriver (
+ BusSpecificDriverOverride,
+ &DriverImageHandle
+ );
+ if (!EFI_ERROR (Status)) {
+ AddSortedDriverBindingProtocol (
+ DriverImageHandle,
+ &NumberOfSortedDriverBindingProtocols,
+ SortedDriverBindingProtocols,
+ DriverBindingHandleCount,
+ DriverBindingHandleBuffer,
+ TRUE
+ );
+ }
+ } while (!EFI_ERROR (Status));
+ }
+
+ //
+ // Then add all the remaining Driver Binding Protocols
+ //
+ SortIndex = NumberOfSortedDriverBindingProtocols;
+ for (Index = 0; Index < DriverBindingHandleCount; Index++) {
+ AddSortedDriverBindingProtocol (
+ DriverBindingHandleBuffer[Index],
+ &NumberOfSortedDriverBindingProtocols,
+ SortedDriverBindingProtocols,
+ DriverBindingHandleCount,
+ DriverBindingHandleBuffer,
+ FALSE
+ );
+ }
+
+ //
+ // Free the Driver Binding Handle Buffer
+ //
+ CoreFreePool (DriverBindingHandleBuffer);
+
+ //
+ // If the number of Driver Binding Protocols has increased since this function started, then return
+ // EFI_NOT_READY, so it will be restarted
+ //
+ Status = CoreLocateHandleBuffer (
+ ByProtocol,
+ &gEfiDriverBindingProtocolGuid,
+ NULL,
+ &NewDriverBindingHandleCount,
+ &NewDriverBindingHandleBuffer
+ );
+ CoreFreePool (NewDriverBindingHandleBuffer);
+ if (NewDriverBindingHandleCount > DriverBindingHandleCount) {
+ //
+ // Free any buffers that were allocated with AllocatePool()
+ //
+ CoreFreePool (SortedDriverBindingProtocols);
+
+ return EFI_NOT_READY;
+ }
+
+ //
+ // Sort the remaining DriverBinding Protocol based on their Version field from
+ // highest to lowest.
+ //
+ for ( ; SortIndex < NumberOfSortedDriverBindingProtocols; SortIndex++) {
+ HighestVersion = SortedDriverBindingProtocols[SortIndex]->Version;
+ HighestIndex = SortIndex;
+ for (Index = SortIndex + 1; Index < NumberOfSortedDriverBindingProtocols; Index++) {
+ if (SortedDriverBindingProtocols[Index]->Version > HighestVersion) {
+ HighestVersion = SortedDriverBindingProtocols[Index]->Version;
+ HighestIndex = Index;
+ }
+ }
+ if (SortIndex != HighestIndex) {
+ DriverBinding = SortedDriverBindingProtocols[SortIndex];
+ SortedDriverBindingProtocols[SortIndex] = SortedDriverBindingProtocols[HighestIndex];
+ SortedDriverBindingProtocols[HighestIndex] = DriverBinding;
+ }
+ }
+
+ //
+ // Loop until no more drivers can be started on ControllerHandle
+ //
+ OneStarted = FALSE;
+ do {
+
+ //
+ // Loop through the sorted Driver Binding Protocol Instances in order, and see if
+ // any of the Driver Binding Protocols support the controller specified by
+ // ControllerHandle.
+ //
+ DriverBinding = NULL;
+ DriverFound = FALSE;
+ for (Index = 0; (Index < NumberOfSortedDriverBindingProtocols) && !DriverFound; Index++) {
+ if (SortedDriverBindingProtocols[Index] != NULL) {
+ DriverBinding = SortedDriverBindingProtocols[Index];
+ PERF_DRIVER_BINDING_SUPPORT_BEGIN (DriverBinding->DriverBindingHandle, ControllerHandle);
+ Status = DriverBinding->Supported(
+ DriverBinding,
+ ControllerHandle,
+ RemainingDevicePath
+ );
+ PERF_DRIVER_BINDING_SUPPORT_END (DriverBinding->DriverBindingHandle, ControllerHandle);
+ if (!EFI_ERROR (Status)) {
+ SortedDriverBindingProtocols[Index] = NULL;
+ DriverFound = TRUE;
+
+ //
+ // A driver was found that supports ControllerHandle, so attempt to start the driver
+ // on ControllerHandle.
+ //
+ PERF_DRIVER_BINDING_START_BEGIN (DriverBinding->DriverBindingHandle, ControllerHandle);
+ Status = DriverBinding->Start (
+ DriverBinding,
+ ControllerHandle,
+ RemainingDevicePath
+ );
+ PERF_DRIVER_BINDING_START_END (DriverBinding->DriverBindingHandle, ControllerHandle);
+
+ if (!EFI_ERROR (Status)) {
+ //
+ // The driver was successfully started on ControllerHandle, so set a flag
+ //
+ OneStarted = TRUE;
+ }
+ }
+ }
+ }
+ } while (DriverFound);
+
+ //
+ // Free any buffers that were allocated with AllocatePool()
+ //
+ CoreFreePool (SortedDriverBindingProtocols);
+
+ //
+ // If at least one driver was started on ControllerHandle, then return EFI_SUCCESS.
+ //
+ if (OneStarted) {
+ return EFI_SUCCESS;
+ }
+
+ //
+ // If no drivers started and RemainingDevicePath is an End Device Path Node, then return EFI_SUCCESS
+ //
+ if (RemainingDevicePath != NULL) {
+ if (IsDevicePathEnd (RemainingDevicePath)) {
+ return EFI_SUCCESS;
+ }
+ }
+
+ //
+ // Otherwise, no drivers were started on ControllerHandle, so return EFI_NOT_FOUND
+ //
+ return EFI_NOT_FOUND;
+}
+
+
+
+/**
+ Disonnects a controller from a driver
+
+ @param ControllerHandle ControllerHandle The handle of
+ the controller from which
+ driver(s) are to be
+ disconnected.
+ @param DriverImageHandle DriverImageHandle The driver to
+ disconnect from ControllerHandle.
+ @param ChildHandle ChildHandle The handle of the
+ child to destroy.
+
+ @retval EFI_SUCCESS One or more drivers were
+ disconnected from the controller.
+ @retval EFI_SUCCESS On entry, no drivers are managing
+ ControllerHandle.
+ @retval EFI_SUCCESS DriverImageHandle is not NULL,
+ and on entry DriverImageHandle is
+ not managing ControllerHandle.
+ @retval EFI_INVALID_PARAMETER ControllerHandle is NULL.
+ @retval EFI_INVALID_PARAMETER DriverImageHandle is not NULL,
+ and it is not a valid EFI_HANDLE.
+ @retval EFI_INVALID_PARAMETER ChildHandle is not NULL, and it
+ is not a valid EFI_HANDLE.
+ @retval EFI_OUT_OF_RESOURCES There are not enough resources
+ available to disconnect any
+ drivers from ControllerHandle.
+ @retval EFI_DEVICE_ERROR The controller could not be
+ disconnected because of a device
+ error.
+
+**/
+EFI_STATUS
+EFIAPI
+CoreDisconnectController (
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_HANDLE DriverImageHandle OPTIONAL,
+ IN EFI_HANDLE ChildHandle OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+ IHANDLE *Handle;
+ EFI_HANDLE *DriverImageHandleBuffer;
+ EFI_HANDLE *ChildBuffer;
+ UINTN Index;
+ UINTN HandleIndex;
+ UINTN DriverImageHandleCount;
+ UINTN ChildrenToStop;
+ UINTN ChildBufferCount;
+ UINTN StopCount;
+ BOOLEAN Duplicate;
+ BOOLEAN ChildHandleValid;
+ BOOLEAN DriverImageHandleValid;
+ LIST_ENTRY *Link;
+ LIST_ENTRY *ProtLink;
+ OPEN_PROTOCOL_DATA *OpenData;
+ PROTOCOL_INTERFACE *Prot;
+ EFI_DRIVER_BINDING_PROTOCOL *DriverBinding;
+
+ //
+ // Make sure ControllerHandle is valid
+ //
+ Status = CoreValidateHandle (ControllerHandle);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Make sure ChildHandle is valid if it is not NULL
+ //
+ if (ChildHandle != NULL) {
+ Status = CoreValidateHandle (ChildHandle);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+
+ Handle = ControllerHandle;
+
+ //
+ // Get list of drivers that are currently managing ControllerHandle
+ //
+ DriverImageHandleBuffer = NULL;
+ DriverImageHandleCount = 1;
+
+ if (DriverImageHandle == NULL) {
+ //
+ // Look at each protocol interface for a match
+ //
+ DriverImageHandleCount = 0;
+
+ CoreAcquireProtocolLock ();
+ for (Link = Handle->Protocols.ForwardLink; Link != &Handle->Protocols; Link = Link->ForwardLink) {
+ Prot = CR(Link, PROTOCOL_INTERFACE, Link, PROTOCOL_INTERFACE_SIGNATURE);
+ for (ProtLink = Prot->OpenList.ForwardLink;
+ ProtLink != &Prot->OpenList;
+ ProtLink = ProtLink->ForwardLink) {
+ OpenData = CR (ProtLink, OPEN_PROTOCOL_DATA, Link, OPEN_PROTOCOL_DATA_SIGNATURE);
+ if ((OpenData->Attributes & EFI_OPEN_PROTOCOL_BY_DRIVER) != 0) {
+ DriverImageHandleCount++;
+ }
+ }
+ }
+ CoreReleaseProtocolLock ();
+
+ //
+ // If there are no drivers managing this controller, then return EFI_SUCCESS
+ //
+ if (DriverImageHandleCount == 0) {
+ Status = EFI_SUCCESS;
+ goto Done;
+ }
+
+ DriverImageHandleBuffer = AllocatePool (sizeof (EFI_HANDLE) * DriverImageHandleCount);
+ if (DriverImageHandleBuffer == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Done;
+ }
+
+ DriverImageHandleCount = 0;
+
+ CoreAcquireProtocolLock ();
+ for (Link = Handle->Protocols.ForwardLink; Link != &Handle->Protocols; Link = Link->ForwardLink) {
+ Prot = CR(Link, PROTOCOL_INTERFACE, Link, PROTOCOL_INTERFACE_SIGNATURE);
+ for (ProtLink = Prot->OpenList.ForwardLink;
+ ProtLink != &Prot->OpenList;
+ ProtLink = ProtLink->ForwardLink) {
+ OpenData = CR (ProtLink, OPEN_PROTOCOL_DATA, Link, OPEN_PROTOCOL_DATA_SIGNATURE);
+ if ((OpenData->Attributes & EFI_OPEN_PROTOCOL_BY_DRIVER) != 0) {
+ Duplicate = FALSE;
+ for (Index = 0; Index< DriverImageHandleCount; Index++) {
+ if (DriverImageHandleBuffer[Index] == OpenData->AgentHandle) {
+ Duplicate = TRUE;
+ break;
+ }
+ }
+ if (!Duplicate) {
+ DriverImageHandleBuffer[DriverImageHandleCount] = OpenData->AgentHandle;
+ DriverImageHandleCount++;
+ }
+ }
+ }
+ }
+ CoreReleaseProtocolLock ();
+ }
+
+ StopCount = 0;
+ for (HandleIndex = 0; HandleIndex < DriverImageHandleCount; HandleIndex++) {
+
+ if (DriverImageHandleBuffer != NULL) {
+ DriverImageHandle = DriverImageHandleBuffer[HandleIndex];
+ }
+
+ //
+ // Get the Driver Binding Protocol of the driver that is managing this controller
+ //
+ Status = CoreHandleProtocol (
+ DriverImageHandle,
+ &gEfiDriverBindingProtocolGuid,
+ (VOID **)&DriverBinding
+ );
+ if (EFI_ERROR (Status) || DriverBinding == NULL) {
+ Status = EFI_INVALID_PARAMETER;
+ goto Done;
+ }
+
+ //
+ // Look at each protocol interface for a match
+ //
+ DriverImageHandleValid = FALSE;
+ ChildBufferCount = 0;
+
+ CoreAcquireProtocolLock ();
+ for (Link = Handle->Protocols.ForwardLink; Link != &Handle->Protocols; Link = Link->ForwardLink) {
+ Prot = CR(Link, PROTOCOL_INTERFACE, Link, PROTOCOL_INTERFACE_SIGNATURE);
+ for (ProtLink = Prot->OpenList.ForwardLink;
+ ProtLink != &Prot->OpenList;
+ ProtLink = ProtLink->ForwardLink) {
+ OpenData = CR (ProtLink, OPEN_PROTOCOL_DATA, Link, OPEN_PROTOCOL_DATA_SIGNATURE);
+ if (OpenData->AgentHandle == DriverImageHandle) {
+ if ((OpenData->Attributes & EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER) != 0) {
+ ChildBufferCount++;
+ }
+ if ((OpenData->Attributes & EFI_OPEN_PROTOCOL_BY_DRIVER) != 0) {
+ DriverImageHandleValid = TRUE;
+ }
+ }
+ }
+ }
+ CoreReleaseProtocolLock ();
+
+ if (DriverImageHandleValid) {
+ ChildHandleValid = FALSE;
+ ChildBuffer = NULL;
+ if (ChildBufferCount != 0) {
+ ChildBuffer = AllocatePool (sizeof (EFI_HANDLE) * ChildBufferCount);
+ if (ChildBuffer == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Done;
+ }
+
+ ChildBufferCount = 0;
+
+ CoreAcquireProtocolLock ();
+ for (Link = Handle->Protocols.ForwardLink; Link != &Handle->Protocols; Link = Link->ForwardLink) {
+ Prot = CR(Link, PROTOCOL_INTERFACE, Link, PROTOCOL_INTERFACE_SIGNATURE);
+ for (ProtLink = Prot->OpenList.ForwardLink;
+ ProtLink != &Prot->OpenList;
+ ProtLink = ProtLink->ForwardLink) {
+ OpenData = CR (ProtLink, OPEN_PROTOCOL_DATA, Link, OPEN_PROTOCOL_DATA_SIGNATURE);
+ if ((OpenData->AgentHandle == DriverImageHandle) &&
+ ((OpenData->Attributes & EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER) != 0)) {
+ Duplicate = FALSE;
+ for (Index = 0; Index < ChildBufferCount; Index++) {
+ if (ChildBuffer[Index] == OpenData->ControllerHandle) {
+ Duplicate = TRUE;
+ break;
+ }
+ }
+ if (!Duplicate) {
+ ChildBuffer[ChildBufferCount] = OpenData->ControllerHandle;
+ if (ChildHandle == ChildBuffer[ChildBufferCount]) {
+ ChildHandleValid = TRUE;
+ }
+ ChildBufferCount++;
+ }
+ }
+ }
+ }
+ CoreReleaseProtocolLock ();
+ }
+
+ if (ChildHandle == NULL || ChildHandleValid) {
+ ChildrenToStop = 0;
+ Status = EFI_SUCCESS;
+ if (ChildBufferCount > 0) {
+ if (ChildHandle != NULL) {
+ ChildrenToStop = 1;
+ Status = DriverBinding->Stop (DriverBinding, ControllerHandle, ChildrenToStop, &ChildHandle);
+ } else {
+ ChildrenToStop = ChildBufferCount;
+ Status = DriverBinding->Stop (DriverBinding, ControllerHandle, ChildrenToStop, ChildBuffer);
+ }
+ }
+ if (!EFI_ERROR (Status) && ((ChildHandle == NULL) || (ChildBufferCount == ChildrenToStop))) {
+ Status = DriverBinding->Stop (DriverBinding, ControllerHandle, 0, NULL);
+ }
+ if (!EFI_ERROR (Status)) {
+ StopCount++;
+ }
+ }
+
+ if (ChildBuffer != NULL) {
+ CoreFreePool (ChildBuffer);
+ }
+ }
+ }
+
+ if (StopCount > 0) {
+ Status = EFI_SUCCESS;
+ } else {
+ Status = EFI_NOT_FOUND;
+ }
+
+Done:
+
+ if (DriverImageHandleBuffer != NULL) {
+ CoreFreePool (DriverImageHandleBuffer);
+ }
+
+ return Status;
+}
diff --git a/roms/edk2/MdeModulePkg/Core/Dxe/Hand/Handle.c b/roms/edk2/MdeModulePkg/Core/Dxe/Hand/Handle.c
new file mode 100644
index 000000000..6eccb41ec
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Core/Dxe/Hand/Handle.c
@@ -0,0 +1,1576 @@
+/** @file
+ UEFI handle & protocol handling.
+
+Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "DxeMain.h"
+#include "Handle.h"
+
+
+//
+// mProtocolDatabase - A list of all protocols in the system. (simple list for now)
+// gHandleList - A list of all the handles in the system
+// gProtocolDatabaseLock - Lock to protect the mProtocolDatabase
+// gHandleDatabaseKey - The Key to show that the handle has been created/modified
+//
+LIST_ENTRY mProtocolDatabase = INITIALIZE_LIST_HEAD_VARIABLE (mProtocolDatabase);
+LIST_ENTRY gHandleList = INITIALIZE_LIST_HEAD_VARIABLE (gHandleList);
+EFI_LOCK gProtocolDatabaseLock = EFI_INITIALIZE_LOCK_VARIABLE (TPL_NOTIFY);
+UINT64 gHandleDatabaseKey = 0;
+
+
+
+/**
+ Acquire lock on gProtocolDatabaseLock.
+
+**/
+VOID
+CoreAcquireProtocolLock (
+ VOID
+ )
+{
+ CoreAcquireLock (&gProtocolDatabaseLock);
+}
+
+
+
+/**
+ Release lock on gProtocolDatabaseLock.
+
+**/
+VOID
+CoreReleaseProtocolLock (
+ VOID
+ )
+{
+ CoreReleaseLock (&gProtocolDatabaseLock);
+}
+
+
+
+/**
+ Check whether a handle is a valid EFI_HANDLE
+
+ @param UserHandle The handle to check
+
+ @retval EFI_INVALID_PARAMETER The handle is NULL or not a valid EFI_HANDLE.
+ @retval EFI_SUCCESS The handle is valid EFI_HANDLE.
+
+**/
+EFI_STATUS
+CoreValidateHandle (
+ IN EFI_HANDLE UserHandle
+ )
+{
+ IHANDLE *Handle;
+ LIST_ENTRY *Link;
+
+ if (UserHandle == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ for (Link = gHandleList.BackLink; Link != &gHandleList; Link = Link->BackLink) {
+ Handle = CR (Link, IHANDLE, AllHandles, EFI_HANDLE_SIGNATURE);
+ if (Handle == (IHANDLE *) UserHandle) {
+ return EFI_SUCCESS;
+ }
+ }
+
+ return EFI_INVALID_PARAMETER;
+}
+
+
+
+/**
+ Finds the protocol entry for the requested protocol.
+ The gProtocolDatabaseLock must be owned
+
+ @param Protocol The ID of the protocol
+ @param Create Create a new entry if not found
+
+ @return Protocol entry
+
+**/
+PROTOCOL_ENTRY *
+CoreFindProtocolEntry (
+ IN EFI_GUID *Protocol,
+ IN BOOLEAN Create
+ )
+{
+ LIST_ENTRY *Link;
+ PROTOCOL_ENTRY *Item;
+ PROTOCOL_ENTRY *ProtEntry;
+
+ ASSERT_LOCKED(&gProtocolDatabaseLock);
+
+ //
+ // Search the database for the matching GUID
+ //
+
+ ProtEntry = NULL;
+ for (Link = mProtocolDatabase.ForwardLink;
+ Link != &mProtocolDatabase;
+ Link = Link->ForwardLink) {
+
+ Item = CR(Link, PROTOCOL_ENTRY, AllEntries, PROTOCOL_ENTRY_SIGNATURE);
+ if (CompareGuid (&Item->ProtocolID, Protocol)) {
+
+ //
+ // This is the protocol entry
+ //
+
+ ProtEntry = Item;
+ break;
+ }
+ }
+
+ //
+ // If the protocol entry was not found and Create is TRUE, then
+ // allocate a new entry
+ //
+ if ((ProtEntry == NULL) && Create) {
+ ProtEntry = AllocatePool (sizeof(PROTOCOL_ENTRY));
+
+ if (ProtEntry != NULL) {
+ //
+ // Initialize new protocol entry structure
+ //
+ ProtEntry->Signature = PROTOCOL_ENTRY_SIGNATURE;
+ CopyGuid ((VOID *)&ProtEntry->ProtocolID, Protocol);
+ InitializeListHead (&ProtEntry->Protocols);
+ InitializeListHead (&ProtEntry->Notify);
+
+ //
+ // Add it to protocol database
+ //
+ InsertTailList (&mProtocolDatabase, &ProtEntry->AllEntries);
+ }
+ }
+
+ return ProtEntry;
+}
+
+
+
+/**
+ Finds the protocol instance for the requested handle and protocol.
+ Note: This function doesn't do parameters checking, it's caller's responsibility
+ to pass in valid parameters.
+
+ @param Handle The handle to search the protocol on
+ @param Protocol GUID of the protocol
+ @param Interface The interface for the protocol being searched
+
+ @return Protocol instance (NULL: Not found)
+
+**/
+PROTOCOL_INTERFACE *
+CoreFindProtocolInterface (
+ IN IHANDLE *Handle,
+ IN EFI_GUID *Protocol,
+ IN VOID *Interface
+ )
+{
+ PROTOCOL_INTERFACE *Prot;
+ PROTOCOL_ENTRY *ProtEntry;
+ LIST_ENTRY *Link;
+
+ ASSERT_LOCKED(&gProtocolDatabaseLock);
+ Prot = NULL;
+
+ //
+ // Lookup the protocol entry for this protocol ID
+ //
+
+ ProtEntry = CoreFindProtocolEntry (Protocol, FALSE);
+ if (ProtEntry != NULL) {
+
+ //
+ // Look at each protocol interface for any matches
+ //
+ for (Link = Handle->Protocols.ForwardLink; Link != &Handle->Protocols; Link=Link->ForwardLink) {
+
+ //
+ // If this protocol interface matches, remove it
+ //
+ Prot = CR(Link, PROTOCOL_INTERFACE, Link, PROTOCOL_INTERFACE_SIGNATURE);
+ if (Prot->Interface == Interface && Prot->Protocol == ProtEntry) {
+ break;
+ }
+
+ Prot = NULL;
+ }
+ }
+
+ return Prot;
+}
+
+
+/**
+ Removes an event from a register protocol notify list on a protocol.
+
+ @param Event The event to search for in the protocol
+ database.
+
+ @return EFI_SUCCESS if the event was found and removed.
+ @return EFI_NOT_FOUND if the event was not found in the protocl database.
+
+**/
+EFI_STATUS
+CoreUnregisterProtocolNotifyEvent (
+ IN EFI_EVENT Event
+ )
+{
+ LIST_ENTRY *Link;
+ PROTOCOL_ENTRY *ProtEntry;
+ LIST_ENTRY *NotifyLink;
+ PROTOCOL_NOTIFY *ProtNotify;
+
+ CoreAcquireProtocolLock ();
+
+ for ( Link = mProtocolDatabase.ForwardLink;
+ Link != &mProtocolDatabase;
+ Link = Link->ForwardLink) {
+
+ ProtEntry = CR(Link, PROTOCOL_ENTRY, AllEntries, PROTOCOL_ENTRY_SIGNATURE);
+
+ for ( NotifyLink = ProtEntry->Notify.ForwardLink;
+ NotifyLink != &ProtEntry->Notify;
+ NotifyLink = NotifyLink->ForwardLink) {
+
+ ProtNotify = CR(NotifyLink, PROTOCOL_NOTIFY, Link, PROTOCOL_NOTIFY_SIGNATURE);
+
+ if (ProtNotify->Event == Event) {
+ RemoveEntryList(&ProtNotify->Link);
+ CoreFreePool(ProtNotify);
+ CoreReleaseProtocolLock ();
+ return EFI_SUCCESS;
+ }
+ }
+ }
+
+ CoreReleaseProtocolLock ();
+ return EFI_NOT_FOUND;
+}
+
+
+
+/**
+ Removes all the events in the protocol database that match Event.
+
+ @param Event The event to search for in the protocol
+ database.
+
+ @return EFI_SUCCESS when done searching the entire database.
+
+**/
+EFI_STATUS
+CoreUnregisterProtocolNotify (
+ IN EFI_EVENT Event
+ )
+{
+ EFI_STATUS Status;
+
+ do {
+ Status = CoreUnregisterProtocolNotifyEvent (Event);
+ } while (!EFI_ERROR (Status));
+
+ return EFI_SUCCESS;
+}
+
+
+
+
+/**
+ Wrapper function to CoreInstallProtocolInterfaceNotify. This is the public API which
+ Calls the private one which contains a BOOLEAN parameter for notifications
+
+ @param UserHandle The handle to install the protocol handler on,
+ or NULL if a new handle is to be allocated
+ @param Protocol The protocol to add to the handle
+ @param InterfaceType Indicates whether Interface is supplied in
+ native form.
+ @param Interface The interface for the protocol being added
+
+ @return Status code
+
+**/
+EFI_STATUS
+EFIAPI
+CoreInstallProtocolInterface (
+ IN OUT EFI_HANDLE *UserHandle,
+ IN EFI_GUID *Protocol,
+ IN EFI_INTERFACE_TYPE InterfaceType,
+ IN VOID *Interface
+ )
+{
+ return CoreInstallProtocolInterfaceNotify (
+ UserHandle,
+ Protocol,
+ InterfaceType,
+ Interface,
+ TRUE
+ );
+}
+
+
+/**
+ Installs a protocol interface into the boot services environment.
+
+ @param UserHandle The handle to install the protocol handler on,
+ or NULL if a new handle is to be allocated
+ @param Protocol The protocol to add to the handle
+ @param InterfaceType Indicates whether Interface is supplied in
+ native form.
+ @param Interface The interface for the protocol being added
+ @param Notify indicates whether notify the notification list
+ for this protocol
+
+ @retval EFI_INVALID_PARAMETER Invalid parameter
+ @retval EFI_OUT_OF_RESOURCES No enough buffer to allocate
+ @retval EFI_SUCCESS Protocol interface successfully installed
+
+**/
+EFI_STATUS
+CoreInstallProtocolInterfaceNotify (
+ IN OUT EFI_HANDLE *UserHandle,
+ IN EFI_GUID *Protocol,
+ IN EFI_INTERFACE_TYPE InterfaceType,
+ IN VOID *Interface,
+ IN BOOLEAN Notify
+ )
+{
+ PROTOCOL_INTERFACE *Prot;
+ PROTOCOL_ENTRY *ProtEntry;
+ IHANDLE *Handle;
+ EFI_STATUS Status;
+ VOID *ExistingInterface;
+
+ //
+ // returns EFI_INVALID_PARAMETER if InterfaceType is invalid.
+ // Also added check for invalid UserHandle and Protocol pointers.
+ //
+ if (UserHandle == NULL || Protocol == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (InterfaceType != EFI_NATIVE_INTERFACE) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Print debug message
+ //
+ DEBUG((DEBUG_INFO, "InstallProtocolInterface: %g %p\n", Protocol, Interface));
+
+ Status = EFI_OUT_OF_RESOURCES;
+ Prot = NULL;
+ Handle = NULL;
+
+ if (*UserHandle != NULL) {
+ Status = CoreHandleProtocol (*UserHandle, Protocol, (VOID **)&ExistingInterface);
+ if (!EFI_ERROR (Status)) {
+ return EFI_INVALID_PARAMETER;
+ }
+ }
+
+ //
+ // Lock the protocol database
+ //
+ CoreAcquireProtocolLock ();
+
+ //
+ // Lookup the Protocol Entry for the requested protocol
+ //
+ ProtEntry = CoreFindProtocolEntry (Protocol, TRUE);
+ if (ProtEntry == NULL) {
+ goto Done;
+ }
+
+ //
+ // Allocate a new protocol interface structure
+ //
+ Prot = AllocateZeroPool (sizeof(PROTOCOL_INTERFACE));
+ if (Prot == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Done;
+ }
+
+ //
+ // If caller didn't supply a handle, allocate a new one
+ //
+ Handle = (IHANDLE *)*UserHandle;
+ if (Handle == NULL) {
+ Handle = AllocateZeroPool (sizeof(IHANDLE));
+ if (Handle == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Done;
+ }
+
+ //
+ // Initialize new handler structure
+ //
+ Handle->Signature = EFI_HANDLE_SIGNATURE;
+ InitializeListHead (&Handle->Protocols);
+
+ //
+ // Initialize the Key to show that the handle has been created/modified
+ //
+ gHandleDatabaseKey++;
+ Handle->Key = gHandleDatabaseKey;
+
+ //
+ // Add this handle to the list global list of all handles
+ // in the system
+ //
+ InsertTailList (&gHandleList, &Handle->AllHandles);
+ } else {
+ Status = CoreValidateHandle (Handle);
+ if (EFI_ERROR (Status)) {
+ DEBUG((DEBUG_ERROR, "InstallProtocolInterface: input handle at 0x%x is invalid\n", Handle));
+ goto Done;
+ }
+ }
+
+ //
+ // Each interface that is added must be unique
+ //
+ ASSERT (CoreFindProtocolInterface (Handle, Protocol, Interface) == NULL);
+
+ //
+ // Initialize the protocol interface structure
+ //
+ Prot->Signature = PROTOCOL_INTERFACE_SIGNATURE;
+ Prot->Handle = Handle;
+ Prot->Protocol = ProtEntry;
+ Prot->Interface = Interface;
+
+ //
+ // Initalize OpenProtocol Data base
+ //
+ InitializeListHead (&Prot->OpenList);
+ Prot->OpenListCount = 0;
+
+ //
+ // Add this protocol interface to the head of the supported
+ // protocol list for this handle
+ //
+ InsertHeadList (&Handle->Protocols, &Prot->Link);
+
+ //
+ // Add this protocol interface to the tail of the
+ // protocol entry
+ //
+ InsertTailList (&ProtEntry->Protocols, &Prot->ByProtocol);
+
+ //
+ // Notify the notification list for this protocol
+ //
+ if (Notify) {
+ CoreNotifyProtocolEntry (ProtEntry);
+ }
+ Status = EFI_SUCCESS;
+
+Done:
+ //
+ // Done, unlock the database and return
+ //
+ CoreReleaseProtocolLock ();
+ if (!EFI_ERROR (Status)) {
+ //
+ // Return the new handle back to the caller
+ //
+ *UserHandle = Handle;
+ } else {
+ //
+ // There was an error, clean up
+ //
+ if (Prot != NULL) {
+ CoreFreePool (Prot);
+ }
+ DEBUG((DEBUG_ERROR, "InstallProtocolInterface: %g %p failed with %r\n", Protocol, Interface, Status));
+ }
+
+ return Status;
+}
+
+
+
+
+/**
+ Installs a list of protocol interface into the boot services environment.
+ This function calls InstallProtocolInterface() in a loop. If any error
+ occures all the protocols added by this function are removed. This is
+ basically a lib function to save space.
+
+ @param Handle The pointer to a handle to install the new
+ protocol interfaces on, or a pointer to NULL
+ if a new handle is to be allocated.
+ @param ... EFI_GUID followed by protocol instance. A NULL
+ terminates the list. The pairs are the
+ arguments to InstallProtocolInterface(). All the
+ protocols are added to Handle.
+
+ @retval EFI_SUCCESS All the protocol interface was installed.
+ @retval EFI_OUT_OF_RESOURCES There was not enough memory in pool to install all the protocols.
+ @retval EFI_ALREADY_STARTED A Device Path Protocol instance was passed in that is already present in
+ the handle database.
+ @retval EFI_INVALID_PARAMETER Handle is NULL.
+ @retval EFI_INVALID_PARAMETER Protocol is already installed on the handle specified by Handle.
+
+**/
+EFI_STATUS
+EFIAPI
+CoreInstallMultipleProtocolInterfaces (
+ IN OUT EFI_HANDLE *Handle,
+ ...
+ )
+{
+ VA_LIST Args;
+ EFI_STATUS Status;
+ EFI_GUID *Protocol;
+ VOID *Interface;
+ EFI_TPL OldTpl;
+ UINTN Index;
+ EFI_HANDLE OldHandle;
+ EFI_HANDLE DeviceHandle;
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;
+
+ if (Handle == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Syncronize with notifcations.
+ //
+ OldTpl = CoreRaiseTpl (TPL_NOTIFY);
+ OldHandle = *Handle;
+
+ //
+ // Check for duplicate device path and install the protocol interfaces
+ //
+ VA_START (Args, Handle);
+ for (Index = 0, Status = EFI_SUCCESS; !EFI_ERROR (Status); Index++) {
+ //
+ // If protocol is NULL, then it's the end of the list
+ //
+ Protocol = VA_ARG (Args, EFI_GUID *);
+ if (Protocol == NULL) {
+ break;
+ }
+
+ Interface = VA_ARG (Args, VOID *);
+
+ //
+ // Make sure you are installing on top a device path that has already been added.
+ //
+ if (CompareGuid (Protocol, &gEfiDevicePathProtocolGuid)) {
+ DeviceHandle = NULL;
+ DevicePath = Interface;
+ Status = CoreLocateDevicePath (&gEfiDevicePathProtocolGuid, &DevicePath, &DeviceHandle);
+ if (!EFI_ERROR (Status) && (DeviceHandle != NULL) && IsDevicePathEnd(DevicePath)) {
+ Status = EFI_ALREADY_STARTED;
+ continue;
+ }
+ }
+
+ //
+ // Install it
+ //
+ Status = CoreInstallProtocolInterface (Handle, Protocol, EFI_NATIVE_INTERFACE, Interface);
+ }
+ VA_END (Args);
+
+ //
+ // If there was an error, remove all the interfaces that were installed without any errors
+ //
+ if (EFI_ERROR (Status)) {
+ //
+ // Reset the va_arg back to the first argument.
+ //
+ VA_START (Args, Handle);
+ for (; Index > 1; Index--) {
+ Protocol = VA_ARG (Args, EFI_GUID *);
+ Interface = VA_ARG (Args, VOID *);
+ CoreUninstallProtocolInterface (*Handle, Protocol, Interface);
+ }
+ VA_END (Args);
+
+ *Handle = OldHandle;
+ }
+
+ //
+ // Done
+ //
+ CoreRestoreTpl (OldTpl);
+ return Status;
+}
+
+
+/**
+ Attempts to disconnect all drivers that are using the protocol interface being queried.
+ If failed, reconnect all drivers disconnected.
+ Note: This function doesn't do parameters checking, it's caller's responsibility
+ to pass in valid parameters.
+
+ @param UserHandle The handle on which the protocol is installed
+ @param Prot The protocol to disconnect drivers from
+
+ @retval EFI_SUCCESS Drivers using the protocol interface are all
+ disconnected
+ @retval EFI_ACCESS_DENIED Failed to disconnect one or all of the drivers
+
+**/
+EFI_STATUS
+CoreDisconnectControllersUsingProtocolInterface (
+ IN EFI_HANDLE UserHandle,
+ IN PROTOCOL_INTERFACE *Prot
+ )
+{
+ EFI_STATUS Status;
+ BOOLEAN ItemFound;
+ LIST_ENTRY *Link;
+ OPEN_PROTOCOL_DATA *OpenData;
+
+ Status = EFI_SUCCESS;
+
+ //
+ // Attempt to disconnect all drivers from this protocol interface
+ //
+ do {
+ ItemFound = FALSE;
+ for (Link = Prot->OpenList.ForwardLink; Link != &Prot->OpenList; Link = Link->ForwardLink) {
+ OpenData = CR (Link, OPEN_PROTOCOL_DATA, Link, OPEN_PROTOCOL_DATA_SIGNATURE);
+ if ((OpenData->Attributes & EFI_OPEN_PROTOCOL_BY_DRIVER) != 0) {
+ CoreReleaseProtocolLock ();
+ Status = CoreDisconnectController (UserHandle, OpenData->AgentHandle, NULL);
+ CoreAcquireProtocolLock ();
+ if (!EFI_ERROR (Status)) {
+ ItemFound = TRUE;
+ }
+ break;
+ }
+ }
+ } while (ItemFound);
+
+ if (!EFI_ERROR (Status)) {
+ //
+ // Attempt to remove BY_HANDLE_PROTOOCL and GET_PROTOCOL and TEST_PROTOCOL Open List items
+ //
+ for (Link = Prot->OpenList.ForwardLink; Link != &Prot->OpenList;) {
+ OpenData = CR (Link, OPEN_PROTOCOL_DATA, Link, OPEN_PROTOCOL_DATA_SIGNATURE);
+ if ((OpenData->Attributes &
+ (EFI_OPEN_PROTOCOL_BY_HANDLE_PROTOCOL | EFI_OPEN_PROTOCOL_GET_PROTOCOL | EFI_OPEN_PROTOCOL_TEST_PROTOCOL)) != 0) {
+ Link = RemoveEntryList (&OpenData->Link);
+ Prot->OpenListCount--;
+ CoreFreePool (OpenData);
+ } else {
+ Link = Link->ForwardLink;
+ }
+ }
+ }
+
+ //
+ // If there are errors or still has open items in the list, then reconnect all the drivers and return an error
+ //
+ if (EFI_ERROR (Status) || (Prot->OpenListCount > 0)) {
+ CoreReleaseProtocolLock ();
+ CoreConnectController (UserHandle, NULL, NULL, TRUE);
+ CoreAcquireProtocolLock ();
+ Status = EFI_ACCESS_DENIED;
+ }
+
+ return Status;
+}
+
+
+
+/**
+ Uninstalls all instances of a protocol:interfacer from a handle.
+ If the last protocol interface is remove from the handle, the
+ handle is freed.
+
+ @param UserHandle The handle to remove the protocol handler from
+ @param Protocol The protocol, of protocol:interface, to remove
+ @param Interface The interface, of protocol:interface, to remove
+
+ @retval EFI_INVALID_PARAMETER Protocol is NULL.
+ @retval EFI_SUCCESS Protocol interface successfully uninstalled.
+
+**/
+EFI_STATUS
+EFIAPI
+CoreUninstallProtocolInterface (
+ IN EFI_HANDLE UserHandle,
+ IN EFI_GUID *Protocol,
+ IN VOID *Interface
+ )
+{
+ EFI_STATUS Status;
+ IHANDLE *Handle;
+ PROTOCOL_INTERFACE *Prot;
+
+ //
+ // Check that Protocol is valid
+ //
+ if (Protocol == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Check that UserHandle is a valid handle
+ //
+ Status = CoreValidateHandle (UserHandle);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Lock the protocol database
+ //
+ CoreAcquireProtocolLock ();
+
+ //
+ // Check that Protocol exists on UserHandle, and Interface matches the interface in the database
+ //
+ Prot = CoreFindProtocolInterface (UserHandle, Protocol, Interface);
+ if (Prot == NULL) {
+ Status = EFI_NOT_FOUND;
+ goto Done;
+ }
+
+ //
+ // Attempt to disconnect all drivers that are using the protocol interface that is about to be removed
+ //
+ Status = CoreDisconnectControllersUsingProtocolInterface (
+ UserHandle,
+ Prot
+ );
+ if (EFI_ERROR (Status)) {
+ //
+ // One or more drivers refused to release, so return the error
+ //
+ goto Done;
+ }
+
+ //
+ // Remove the protocol interface from the protocol
+ //
+ Status = EFI_NOT_FOUND;
+ Handle = (IHANDLE *)UserHandle;
+ Prot = CoreRemoveInterfaceFromProtocol (Handle, Protocol, Interface);
+
+ if (Prot != NULL) {
+ //
+ // Update the Key to show that the handle has been created/modified
+ //
+ gHandleDatabaseKey++;
+ Handle->Key = gHandleDatabaseKey;
+
+ //
+ // Remove the protocol interface from the handle
+ //
+ RemoveEntryList (&Prot->Link);
+
+ //
+ // Free the memory
+ //
+ Prot->Signature = 0;
+ CoreFreePool (Prot);
+ Status = EFI_SUCCESS;
+ }
+
+ //
+ // If there are no more handlers for the handle, free the handle
+ //
+ if (IsListEmpty (&Handle->Protocols)) {
+ Handle->Signature = 0;
+ RemoveEntryList (&Handle->AllHandles);
+ CoreFreePool (Handle);
+ }
+
+Done:
+ //
+ // Done, unlock the database and return
+ //
+ CoreReleaseProtocolLock ();
+ return Status;
+}
+
+
+
+/**
+ Uninstalls a list of protocol interface in the boot services environment.
+ This function calls UninstallProtocolInterface() in a loop. This is
+ basically a lib function to save space.
+
+ If any errors are generated while the protocol interfaces are being
+ uninstalled, then the protocol interfaces uninstalled prior to the error will
+ be reinstalled and EFI_INVALID_PARAMETER will be returned.
+
+ @param Handle The handle to uninstall the protocol interfaces
+ from.
+ @param ... EFI_GUID followed by protocol instance. A NULL
+ terminates the list. The pairs are the
+ arguments to UninstallProtocolInterface(). All
+ the protocols are added to Handle.
+
+ @retval EFI_SUCCESS if all protocol interfaces where uninstalled.
+ @retval EFI_INVALID_PARAMETER if any protocol interface could not be
+ uninstalled and an attempt was made to
+ reinstall previously uninstalled protocol
+ interfaces.
+**/
+EFI_STATUS
+EFIAPI
+CoreUninstallMultipleProtocolInterfaces (
+ IN EFI_HANDLE Handle,
+ ...
+ )
+{
+ EFI_STATUS Status;
+ VA_LIST Args;
+ EFI_GUID *Protocol;
+ VOID *Interface;
+ UINTN Index;
+
+ VA_START (Args, Handle);
+ for (Index = 0, Status = EFI_SUCCESS; !EFI_ERROR (Status); Index++) {
+ //
+ // If protocol is NULL, then it's the end of the list
+ //
+ Protocol = VA_ARG (Args, EFI_GUID *);
+ if (Protocol == NULL) {
+ break;
+ }
+
+ Interface = VA_ARG (Args, VOID *);
+
+ //
+ // Uninstall it
+ //
+ Status = CoreUninstallProtocolInterface (Handle, Protocol, Interface);
+ }
+ VA_END (Args);
+
+ //
+ // If there was an error, add all the interfaces that were
+ // uninstalled without any errors
+ //
+ if (EFI_ERROR (Status)) {
+ //
+ // Reset the va_arg back to the first argument.
+ //
+ VA_START (Args, Handle);
+ for (; Index > 1; Index--) {
+ Protocol = VA_ARG(Args, EFI_GUID *);
+ Interface = VA_ARG(Args, VOID *);
+ CoreInstallProtocolInterface (&Handle, Protocol, EFI_NATIVE_INTERFACE, Interface);
+ }
+ VA_END (Args);
+ Status = EFI_INVALID_PARAMETER;
+ }
+
+ return Status;
+}
+
+
+/**
+ Locate a certain GUID protocol interface in a Handle's protocols.
+
+ @param UserHandle The handle to obtain the protocol interface on
+ @param Protocol The GUID of the protocol
+
+ @return The requested protocol interface for the handle
+
+**/
+PROTOCOL_INTERFACE *
+CoreGetProtocolInterface (
+ IN EFI_HANDLE UserHandle,
+ IN EFI_GUID *Protocol
+ )
+{
+ EFI_STATUS Status;
+ PROTOCOL_ENTRY *ProtEntry;
+ PROTOCOL_INTERFACE *Prot;
+ IHANDLE *Handle;
+ LIST_ENTRY *Link;
+
+ Status = CoreValidateHandle (UserHandle);
+ if (EFI_ERROR (Status)) {
+ return NULL;
+ }
+
+ Handle = (IHANDLE *)UserHandle;
+
+ //
+ // Look at each protocol interface for a match
+ //
+ for (Link = Handle->Protocols.ForwardLink; Link != &Handle->Protocols; Link = Link->ForwardLink) {
+ Prot = CR(Link, PROTOCOL_INTERFACE, Link, PROTOCOL_INTERFACE_SIGNATURE);
+ ProtEntry = Prot->Protocol;
+ if (CompareGuid (&ProtEntry->ProtocolID, Protocol)) {
+ return Prot;
+ }
+ }
+ return NULL;
+}
+
+
+
+/**
+ Queries a handle to determine if it supports a specified protocol.
+
+ @param UserHandle The handle being queried.
+ @param Protocol The published unique identifier of the protocol.
+ @param Interface Supplies the address where a pointer to the
+ corresponding Protocol Interface is returned.
+
+ @retval EFI_SUCCESS The interface information for the specified protocol was returned.
+ @retval EFI_UNSUPPORTED The device does not support the specified protocol.
+ @retval EFI_INVALID_PARAMETER Handle is NULL..
+ @retval EFI_INVALID_PARAMETER Protocol is NULL.
+ @retval EFI_INVALID_PARAMETER Interface is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+CoreHandleProtocol (
+ IN EFI_HANDLE UserHandle,
+ IN EFI_GUID *Protocol,
+ OUT VOID **Interface
+ )
+{
+ return CoreOpenProtocol (
+ UserHandle,
+ Protocol,
+ Interface,
+ gDxeCoreImageHandle,
+ NULL,
+ EFI_OPEN_PROTOCOL_BY_HANDLE_PROTOCOL
+ );
+}
+
+
+
+/**
+ Locates the installed protocol handler for the handle, and
+ invokes it to obtain the protocol interface. Usage information
+ is registered in the protocol data base.
+
+ @param UserHandle The handle to obtain the protocol interface on
+ @param Protocol The ID of the protocol
+ @param Interface The location to return the protocol interface
+ @param ImageHandle The handle of the Image that is opening the
+ protocol interface specified by Protocol and
+ Interface.
+ @param ControllerHandle The controller handle that is requiring this
+ interface.
+ @param Attributes The open mode of the protocol interface
+ specified by Handle and Protocol.
+
+ @retval EFI_INVALID_PARAMETER Protocol is NULL.
+ @retval EFI_SUCCESS Get the protocol interface.
+
+**/
+EFI_STATUS
+EFIAPI
+CoreOpenProtocol (
+ IN EFI_HANDLE UserHandle,
+ IN EFI_GUID *Protocol,
+ OUT VOID **Interface OPTIONAL,
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_HANDLE ControllerHandle,
+ IN UINT32 Attributes
+ )
+{
+ EFI_STATUS Status;
+ PROTOCOL_INTERFACE *Prot;
+ LIST_ENTRY *Link;
+ OPEN_PROTOCOL_DATA *OpenData;
+ BOOLEAN ByDriver;
+ BOOLEAN Exclusive;
+ BOOLEAN Disconnect;
+ BOOLEAN ExactMatch;
+
+ //
+ // Check for invalid Protocol
+ //
+ if (Protocol == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Check for invalid Interface
+ //
+ if ((Attributes != EFI_OPEN_PROTOCOL_TEST_PROTOCOL) && (Interface == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Check for invalid UserHandle
+ //
+ Status = CoreValidateHandle (UserHandle);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Check for invalid Attributes
+ //
+ switch (Attributes) {
+ case EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER :
+ Status = CoreValidateHandle (ImageHandle);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ Status = CoreValidateHandle (ControllerHandle);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ if (UserHandle == ControllerHandle) {
+ return EFI_INVALID_PARAMETER;
+ }
+ break;
+ case EFI_OPEN_PROTOCOL_BY_DRIVER :
+ case EFI_OPEN_PROTOCOL_BY_DRIVER | EFI_OPEN_PROTOCOL_EXCLUSIVE :
+ Status = CoreValidateHandle (ImageHandle);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ Status = CoreValidateHandle (ControllerHandle);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ break;
+ case EFI_OPEN_PROTOCOL_EXCLUSIVE :
+ Status = CoreValidateHandle (ImageHandle);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ break;
+ case EFI_OPEN_PROTOCOL_BY_HANDLE_PROTOCOL :
+ case EFI_OPEN_PROTOCOL_GET_PROTOCOL :
+ case EFI_OPEN_PROTOCOL_TEST_PROTOCOL :
+ break;
+ default:
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Lock the protocol database
+ //
+ CoreAcquireProtocolLock ();
+
+ //
+ // Look at each protocol interface for a match
+ //
+ Prot = CoreGetProtocolInterface (UserHandle, Protocol);
+ if (Prot == NULL) {
+ Status = EFI_UNSUPPORTED;
+ goto Done;
+ }
+
+ Status = EFI_SUCCESS;
+
+ ByDriver = FALSE;
+ Exclusive = FALSE;
+ for ( Link = Prot->OpenList.ForwardLink; Link != &Prot->OpenList; Link = Link->ForwardLink) {
+ OpenData = CR (Link, OPEN_PROTOCOL_DATA, Link, OPEN_PROTOCOL_DATA_SIGNATURE);
+ ExactMatch = (BOOLEAN)((OpenData->AgentHandle == ImageHandle) &&
+ (OpenData->Attributes == Attributes) &&
+ (OpenData->ControllerHandle == ControllerHandle));
+ if ((OpenData->Attributes & EFI_OPEN_PROTOCOL_BY_DRIVER) != 0) {
+ ByDriver = TRUE;
+ if (ExactMatch) {
+ Status = EFI_ALREADY_STARTED;
+ goto Done;
+ }
+ }
+ if ((OpenData->Attributes & EFI_OPEN_PROTOCOL_EXCLUSIVE) != 0) {
+ Exclusive = TRUE;
+ } else if (ExactMatch) {
+ OpenData->OpenCount++;
+ Status = EFI_SUCCESS;
+ goto Done;
+ }
+ }
+
+ //
+ // ByDriver TRUE -> A driver is managing (UserHandle, Protocol)
+ // ByDriver FALSE -> There are no drivers managing (UserHandle, Protocol)
+ // Exclusive TRUE -> Something has exclusive access to (UserHandle, Protocol)
+ // Exclusive FALSE -> Nothing has exclusive access to (UserHandle, Protocol)
+ //
+
+ switch (Attributes) {
+ case EFI_OPEN_PROTOCOL_BY_DRIVER :
+ if (Exclusive || ByDriver) {
+ Status = EFI_ACCESS_DENIED;
+ goto Done;
+ }
+ break;
+ case EFI_OPEN_PROTOCOL_BY_DRIVER | EFI_OPEN_PROTOCOL_EXCLUSIVE :
+ case EFI_OPEN_PROTOCOL_EXCLUSIVE :
+ if (Exclusive) {
+ Status = EFI_ACCESS_DENIED;
+ goto Done;
+ }
+ if (ByDriver) {
+ do {
+ Disconnect = FALSE;
+ for (Link = Prot->OpenList.ForwardLink; Link != &Prot->OpenList; Link = Link->ForwardLink) {
+ OpenData = CR (Link, OPEN_PROTOCOL_DATA, Link, OPEN_PROTOCOL_DATA_SIGNATURE);
+ if ((OpenData->Attributes & EFI_OPEN_PROTOCOL_BY_DRIVER) != 0) {
+ Disconnect = TRUE;
+ CoreReleaseProtocolLock ();
+ Status = CoreDisconnectController (UserHandle, OpenData->AgentHandle, NULL);
+ CoreAcquireProtocolLock ();
+ if (EFI_ERROR (Status)) {
+ Status = EFI_ACCESS_DENIED;
+ goto Done;
+ } else {
+ break;
+ }
+ }
+ }
+ } while (Disconnect);
+ }
+ break;
+ case EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER :
+ case EFI_OPEN_PROTOCOL_BY_HANDLE_PROTOCOL :
+ case EFI_OPEN_PROTOCOL_GET_PROTOCOL :
+ case EFI_OPEN_PROTOCOL_TEST_PROTOCOL :
+ break;
+ }
+
+ if (ImageHandle == NULL) {
+ Status = EFI_SUCCESS;
+ goto Done;
+ }
+ //
+ // Create new entry
+ //
+ OpenData = AllocatePool (sizeof(OPEN_PROTOCOL_DATA));
+ if (OpenData == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ } else {
+ OpenData->Signature = OPEN_PROTOCOL_DATA_SIGNATURE;
+ OpenData->AgentHandle = ImageHandle;
+ OpenData->ControllerHandle = ControllerHandle;
+ OpenData->Attributes = Attributes;
+ OpenData->OpenCount = 1;
+ InsertTailList (&Prot->OpenList, &OpenData->Link);
+ Prot->OpenListCount++;
+ Status = EFI_SUCCESS;
+ }
+
+Done:
+
+ if (Attributes != EFI_OPEN_PROTOCOL_TEST_PROTOCOL) {
+ //
+ // Keep Interface unmodified in case of any Error
+ // except EFI_ALREADY_STARTED and EFI_UNSUPPORTED.
+ //
+ if (!EFI_ERROR (Status) || Status == EFI_ALREADY_STARTED) {
+ //
+ // According to above logic, if 'Prot' is NULL, then the 'Status' must be
+ // EFI_UNSUPPORTED. Here the 'Status' is not EFI_UNSUPPORTED, so 'Prot'
+ // must be not NULL.
+ //
+ // The ASSERT here is for addressing a false positive NULL pointer
+ // dereference issue raised from static analysis.
+ //
+ ASSERT (Prot != NULL);
+ //
+ // EFI_ALREADY_STARTED is not an error for bus driver.
+ // Return the corresponding protocol interface.
+ //
+ *Interface = Prot->Interface;
+ } else if (Status == EFI_UNSUPPORTED) {
+ //
+ // Return NULL Interface if Unsupported Protocol.
+ //
+ *Interface = NULL;
+ }
+ }
+
+ //
+ // Done. Release the database lock and return
+ //
+ CoreReleaseProtocolLock ();
+ return Status;
+}
+
+
+
+/**
+ Closes a protocol on a handle that was opened using OpenProtocol().
+
+ @param UserHandle The handle for the protocol interface that was
+ previously opened with OpenProtocol(), and is
+ now being closed.
+ @param Protocol The published unique identifier of the protocol.
+ It is the caller's responsibility to pass in a
+ valid GUID.
+ @param AgentHandle The handle of the agent that is closing the
+ protocol interface.
+ @param ControllerHandle If the agent that opened a protocol is a driver
+ that follows the EFI Driver Model, then this
+ parameter is the controller handle that required
+ the protocol interface. If the agent does not
+ follow the EFI Driver Model, then this parameter
+ is optional and may be NULL.
+
+ @retval EFI_SUCCESS The protocol instance was closed.
+ @retval EFI_INVALID_PARAMETER Handle, AgentHandle or ControllerHandle is not a
+ valid EFI_HANDLE.
+ @retval EFI_NOT_FOUND Can not find the specified protocol or
+ AgentHandle.
+
+**/
+EFI_STATUS
+EFIAPI
+CoreCloseProtocol (
+ IN EFI_HANDLE UserHandle,
+ IN EFI_GUID *Protocol,
+ IN EFI_HANDLE AgentHandle,
+ IN EFI_HANDLE ControllerHandle
+ )
+{
+ EFI_STATUS Status;
+ PROTOCOL_INTERFACE *ProtocolInterface;
+ LIST_ENTRY *Link;
+ OPEN_PROTOCOL_DATA *OpenData;
+
+ //
+ // Check for invalid parameters
+ //
+ Status = CoreValidateHandle (UserHandle);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ Status = CoreValidateHandle (AgentHandle);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ if (ControllerHandle != NULL) {
+ Status = CoreValidateHandle (ControllerHandle);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+ if (Protocol == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Lock the protocol database
+ //
+ CoreAcquireProtocolLock ();
+
+ //
+ // Look at each protocol interface for a match
+ //
+ Status = EFI_NOT_FOUND;
+ ProtocolInterface = CoreGetProtocolInterface (UserHandle, Protocol);
+ if (ProtocolInterface == NULL) {
+ goto Done;
+ }
+
+ //
+ // Walk the Open data base looking for AgentHandle
+ //
+ Link = ProtocolInterface->OpenList.ForwardLink;
+ while (Link != &ProtocolInterface->OpenList) {
+ OpenData = CR (Link, OPEN_PROTOCOL_DATA, Link, OPEN_PROTOCOL_DATA_SIGNATURE);
+ Link = Link->ForwardLink;
+ if ((OpenData->AgentHandle == AgentHandle) && (OpenData->ControllerHandle == ControllerHandle)) {
+ RemoveEntryList (&OpenData->Link);
+ ProtocolInterface->OpenListCount--;
+ CoreFreePool (OpenData);
+ Status = EFI_SUCCESS;
+ }
+ }
+
+Done:
+ //
+ // Done. Release the database lock and return.
+ //
+ CoreReleaseProtocolLock ();
+ return Status;
+}
+
+
+
+
+/**
+ Return information about Opened protocols in the system
+
+ @param UserHandle The handle to close the protocol interface on
+ @param Protocol The ID of the protocol
+ @param EntryBuffer A pointer to a buffer of open protocol information in the
+ form of EFI_OPEN_PROTOCOL_INFORMATION_ENTRY structures.
+ @param EntryCount Number of EntryBuffer entries
+
+ @retval EFI_SUCCESS The open protocol information was returned in EntryBuffer,
+ and the number of entries was returned EntryCount.
+ @retval EFI_NOT_FOUND Handle does not support the protocol specified by Protocol.
+ @retval EFI_OUT_OF_RESOURCES There are not enough resources available to allocate EntryBuffer.
+
+**/
+EFI_STATUS
+EFIAPI
+CoreOpenProtocolInformation (
+ IN EFI_HANDLE UserHandle,
+ IN EFI_GUID *Protocol,
+ OUT EFI_OPEN_PROTOCOL_INFORMATION_ENTRY **EntryBuffer,
+ OUT UINTN *EntryCount
+ )
+{
+ EFI_STATUS Status;
+ PROTOCOL_INTERFACE *ProtocolInterface;
+ LIST_ENTRY *Link;
+ OPEN_PROTOCOL_DATA *OpenData;
+ EFI_OPEN_PROTOCOL_INFORMATION_ENTRY *Buffer;
+ UINTN Count;
+ UINTN Size;
+
+ *EntryBuffer = NULL;
+ *EntryCount = 0;
+
+ //
+ // Lock the protocol database
+ //
+ CoreAcquireProtocolLock ();
+
+ //
+ // Look at each protocol interface for a match
+ //
+ Status = EFI_NOT_FOUND;
+ ProtocolInterface = CoreGetProtocolInterface (UserHandle, Protocol);
+ if (ProtocolInterface == NULL) {
+ goto Done;
+ }
+
+ //
+ // Count the number of Open Entries
+ //
+ for ( Link = ProtocolInterface->OpenList.ForwardLink, Count = 0;
+ (Link != &ProtocolInterface->OpenList) ;
+ Link = Link->ForwardLink ) {
+ Count++;
+ }
+
+ ASSERT (Count == ProtocolInterface->OpenListCount);
+
+ if (Count == 0) {
+ Size = sizeof(EFI_OPEN_PROTOCOL_INFORMATION_ENTRY);
+ } else {
+ Size = Count * sizeof(EFI_OPEN_PROTOCOL_INFORMATION_ENTRY);
+ }
+
+ Buffer = AllocatePool (Size);
+ if (Buffer == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Done;
+ }
+
+ Status = EFI_SUCCESS;
+ for ( Link = ProtocolInterface->OpenList.ForwardLink, Count = 0;
+ (Link != &ProtocolInterface->OpenList);
+ Link = Link->ForwardLink, Count++ ) {
+ OpenData = CR (Link, OPEN_PROTOCOL_DATA, Link, OPEN_PROTOCOL_DATA_SIGNATURE);
+
+ Buffer[Count].AgentHandle = OpenData->AgentHandle;
+ Buffer[Count].ControllerHandle = OpenData->ControllerHandle;
+ Buffer[Count].Attributes = OpenData->Attributes;
+ Buffer[Count].OpenCount = OpenData->OpenCount;
+ }
+
+ *EntryBuffer = Buffer;
+ *EntryCount = Count;
+
+Done:
+ //
+ // Done. Release the database lock.
+ //
+ CoreReleaseProtocolLock ();
+ return Status;
+}
+
+
+
+
+/**
+ Retrieves the list of protocol interface GUIDs that are installed on a handle in a buffer allocated
+ from pool.
+
+ @param UserHandle The handle from which to retrieve the list of
+ protocol interface GUIDs.
+ @param ProtocolBuffer A pointer to the list of protocol interface GUID
+ pointers that are installed on Handle.
+ @param ProtocolBufferCount A pointer to the number of GUID pointers present
+ in ProtocolBuffer.
+
+ @retval EFI_SUCCESS The list of protocol interface GUIDs installed
+ on Handle was returned in ProtocolBuffer. The
+ number of protocol interface GUIDs was returned
+ in ProtocolBufferCount.
+ @retval EFI_INVALID_PARAMETER Handle is NULL.
+ @retval EFI_INVALID_PARAMETER Handle is not a valid EFI_HANDLE.
+ @retval EFI_INVALID_PARAMETER ProtocolBuffer is NULL.
+ @retval EFI_INVALID_PARAMETER ProtocolBufferCount is NULL.
+ @retval EFI_OUT_OF_RESOURCES There is not enough pool memory to store the
+ results.
+
+**/
+EFI_STATUS
+EFIAPI
+CoreProtocolsPerHandle (
+ IN EFI_HANDLE UserHandle,
+ OUT EFI_GUID ***ProtocolBuffer,
+ OUT UINTN *ProtocolBufferCount
+ )
+{
+ EFI_STATUS Status;
+ IHANDLE *Handle;
+ PROTOCOL_INTERFACE *Prot;
+ LIST_ENTRY *Link;
+ UINTN ProtocolCount;
+ EFI_GUID **Buffer;
+
+ Status = CoreValidateHandle (UserHandle);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Handle = (IHANDLE *)UserHandle;
+
+ if (ProtocolBuffer == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (ProtocolBufferCount == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ *ProtocolBufferCount = 0;
+
+ ProtocolCount = 0;
+
+ CoreAcquireProtocolLock ();
+
+ for (Link = Handle->Protocols.ForwardLink; Link != &Handle->Protocols; Link = Link->ForwardLink) {
+ ProtocolCount++;
+ }
+
+ //
+ // If there are no protocol interfaces installed on Handle, then Handle is not a valid EFI_HANDLE
+ //
+ if (ProtocolCount == 0) {
+ Status = EFI_INVALID_PARAMETER;
+ goto Done;
+ }
+
+ Buffer = AllocatePool (sizeof (EFI_GUID *) * ProtocolCount);
+ if (Buffer == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Done;
+ }
+
+ *ProtocolBuffer = Buffer;
+ *ProtocolBufferCount = ProtocolCount;
+
+ for ( Link = Handle->Protocols.ForwardLink, ProtocolCount = 0;
+ Link != &Handle->Protocols;
+ Link = Link->ForwardLink, ProtocolCount++) {
+ Prot = CR(Link, PROTOCOL_INTERFACE, Link, PROTOCOL_INTERFACE_SIGNATURE);
+ Buffer[ProtocolCount] = &(Prot->Protocol->ProtocolID);
+ }
+ Status = EFI_SUCCESS;
+
+Done:
+ CoreReleaseProtocolLock ();
+ return Status;
+}
+
+
+
+/**
+ return handle database key.
+
+
+ @return Handle database key.
+
+**/
+UINT64
+CoreGetHandleDatabaseKey (
+ VOID
+ )
+{
+ return gHandleDatabaseKey;
+}
+
+
+
+/**
+ Go connect any handles that were created or modified while a image executed.
+
+ @param Key The Key to show that the handle has been
+ created/modified
+
+**/
+VOID
+CoreConnectHandlesByKey (
+ UINT64 Key
+ )
+{
+ UINTN Count;
+ LIST_ENTRY *Link;
+ EFI_HANDLE *HandleBuffer;
+ IHANDLE *Handle;
+ UINTN Index;
+
+ //
+ // Lock the protocol database
+ //
+ CoreAcquireProtocolLock ();
+
+ for (Link = gHandleList.ForwardLink, Count = 0; Link != &gHandleList; Link = Link->ForwardLink) {
+ Handle = CR (Link, IHANDLE, AllHandles, EFI_HANDLE_SIGNATURE);
+ if (Handle->Key > Key) {
+ Count++;
+ }
+ }
+
+ HandleBuffer = AllocatePool (Count * sizeof (EFI_HANDLE));
+ if (HandleBuffer == NULL) {
+ CoreReleaseProtocolLock ();
+ return;
+ }
+
+ for (Link = gHandleList.ForwardLink, Count = 0; Link != &gHandleList; Link = Link->ForwardLink) {
+ Handle = CR (Link, IHANDLE, AllHandles, EFI_HANDLE_SIGNATURE);
+ if (Handle->Key > Key) {
+ HandleBuffer[Count++] = Handle;
+ }
+ }
+
+ //
+ // Unlock the protocol database
+ //
+ CoreReleaseProtocolLock ();
+
+ //
+ // Connect all handles whose Key value is greater than Key
+ //
+ for (Index = 0; Index < Count; Index++) {
+ CoreConnectController (HandleBuffer[Index], NULL, NULL, TRUE);
+ }
+
+ CoreFreePool(HandleBuffer);
+}
diff --git a/roms/edk2/MdeModulePkg/Core/Dxe/Hand/Handle.h b/roms/edk2/MdeModulePkg/Core/Dxe/Hand/Handle.h
new file mode 100644
index 000000000..83eb2b9f3
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Core/Dxe/Hand/Handle.h
@@ -0,0 +1,264 @@
+/** @file
+ Support functions for managing protocol.
+
+Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _HAND_H_
+#define _HAND_H_
+
+
+#define EFI_HANDLE_SIGNATURE SIGNATURE_32('h','n','d','l')
+
+///
+/// IHANDLE - contains a list of protocol handles
+///
+typedef struct {
+ UINTN Signature;
+ /// All handles list of IHANDLE
+ LIST_ENTRY AllHandles;
+ /// List of PROTOCOL_INTERFACE's for this handle
+ LIST_ENTRY Protocols;
+ UINTN LocateRequest;
+ /// The Handle Database Key value when this handle was last created or modified
+ UINT64 Key;
+} IHANDLE;
+
+#define ASSERT_IS_HANDLE(a) ASSERT((a)->Signature == EFI_HANDLE_SIGNATURE)
+
+#define PROTOCOL_ENTRY_SIGNATURE SIGNATURE_32('p','r','t','e')
+
+///
+/// PROTOCOL_ENTRY - each different protocol has 1 entry in the protocol
+/// database. Each handler that supports this protocol is listed, along
+/// with a list of registered notifies.
+///
+typedef struct {
+ UINTN Signature;
+ /// Link Entry inserted to mProtocolDatabase
+ LIST_ENTRY AllEntries;
+ /// ID of the protocol
+ EFI_GUID ProtocolID;
+ /// All protocol interfaces
+ LIST_ENTRY Protocols;
+ /// Registerd notification handlers
+ LIST_ENTRY Notify;
+} PROTOCOL_ENTRY;
+
+
+#define PROTOCOL_INTERFACE_SIGNATURE SIGNATURE_32('p','i','f','c')
+
+///
+/// PROTOCOL_INTERFACE - each protocol installed on a handle is tracked
+/// with a protocol interface structure
+///
+typedef struct {
+ UINTN Signature;
+ /// Link on IHANDLE.Protocols
+ LIST_ENTRY Link;
+ /// Back pointer
+ IHANDLE *Handle;
+ /// Link on PROTOCOL_ENTRY.Protocols
+ LIST_ENTRY ByProtocol;
+ /// The protocol ID
+ PROTOCOL_ENTRY *Protocol;
+ /// The interface value
+ VOID *Interface;
+ /// OPEN_PROTOCOL_DATA list
+ LIST_ENTRY OpenList;
+ UINTN OpenListCount;
+
+} PROTOCOL_INTERFACE;
+
+#define OPEN_PROTOCOL_DATA_SIGNATURE SIGNATURE_32('p','o','d','l')
+
+typedef struct {
+ UINTN Signature;
+ ///Link on PROTOCOL_INTERFACE.OpenList
+ LIST_ENTRY Link;
+
+ EFI_HANDLE AgentHandle;
+ EFI_HANDLE ControllerHandle;
+ UINT32 Attributes;
+ UINT32 OpenCount;
+} OPEN_PROTOCOL_DATA;
+
+
+#define PROTOCOL_NOTIFY_SIGNATURE SIGNATURE_32('p','r','t','n')
+
+///
+/// PROTOCOL_NOTIFY - used for each register notification for a protocol
+///
+typedef struct {
+ UINTN Signature;
+ PROTOCOL_ENTRY *Protocol;
+ /// All notifications for this protocol
+ LIST_ENTRY Link;
+ /// Event to notify
+ EFI_EVENT Event;
+ /// Last position notified
+ LIST_ENTRY *Position;
+} PROTOCOL_NOTIFY;
+
+
+
+/**
+ Finds the protocol entry for the requested protocol.
+ The gProtocolDatabaseLock must be owned
+
+ @param Protocol The ID of the protocol
+ @param Create Create a new entry if not found
+
+ @return Protocol entry
+
+**/
+PROTOCOL_ENTRY *
+CoreFindProtocolEntry (
+ IN EFI_GUID *Protocol,
+ IN BOOLEAN Create
+ );
+
+
+/**
+ Signal event for every protocol in protocol entry.
+
+ @param ProtEntry Protocol entry
+
+**/
+VOID
+CoreNotifyProtocolEntry (
+ IN PROTOCOL_ENTRY *ProtEntry
+ );
+
+
+/**
+ Finds the protocol instance for the requested handle and protocol.
+ Note: This function doesn't do parameters checking, it's caller's responsibility
+ to pass in valid parameters.
+
+ @param Handle The handle to search the protocol on
+ @param Protocol GUID of the protocol
+ @param Interface The interface for the protocol being searched
+
+ @return Protocol instance (NULL: Not found)
+
+**/
+PROTOCOL_INTERFACE *
+CoreFindProtocolInterface (
+ IN IHANDLE *Handle,
+ IN EFI_GUID *Protocol,
+ IN VOID *Interface
+ );
+
+
+/**
+ Removes Protocol from the protocol list (but not the handle list).
+
+ @param Handle The handle to remove protocol on.
+ @param Protocol GUID of the protocol to be moved
+ @param Interface The interface of the protocol
+
+ @return Protocol Entry
+
+**/
+PROTOCOL_INTERFACE *
+CoreRemoveInterfaceFromProtocol (
+ IN IHANDLE *Handle,
+ IN EFI_GUID *Protocol,
+ IN VOID *Interface
+ );
+
+
+/**
+ Connects a controller to a driver.
+
+ @param ControllerHandle Handle of the controller to be
+ connected.
+ @param ContextDriverImageHandles DriverImageHandle A pointer to an
+ ordered list of driver image
+ handles.
+ @param RemainingDevicePath RemainingDevicePath A pointer to
+ the device path that specifies a
+ child of the controller
+ specified by ControllerHandle.
+
+ @retval EFI_SUCCESS One or more drivers were
+ connected to ControllerHandle.
+ @retval EFI_OUT_OF_RESOURCES No enough system resources to
+ complete the request.
+ @retval EFI_NOT_FOUND No drivers were connected to
+ ControllerHandle.
+
+**/
+EFI_STATUS
+CoreConnectSingleController (
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_HANDLE *ContextDriverImageHandles OPTIONAL,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL
+ );
+
+/**
+ Attempts to disconnect all drivers that are using the protocol interface being queried.
+ If failed, reconnect all drivers disconnected.
+ Note: This function doesn't do parameters checking, it's caller's responsibility
+ to pass in valid parameters.
+
+ @param UserHandle The handle on which the protocol is installed
+ @param Prot The protocol to disconnect drivers from
+
+ @retval EFI_SUCCESS Drivers using the protocol interface are all
+ disconnected
+ @retval EFI_ACCESS_DENIED Failed to disconnect one or all of the drivers
+
+**/
+EFI_STATUS
+CoreDisconnectControllersUsingProtocolInterface (
+ IN EFI_HANDLE UserHandle,
+ IN PROTOCOL_INTERFACE *Prot
+ );
+
+
+/**
+ Acquire lock on gProtocolDatabaseLock.
+
+**/
+VOID
+CoreAcquireProtocolLock (
+ VOID
+ );
+
+
+/**
+ Release lock on gProtocolDatabaseLock.
+
+**/
+VOID
+CoreReleaseProtocolLock (
+ VOID
+ );
+
+
+/**
+ Check whether a handle is a valid EFI_HANDLE
+
+ @param UserHandle The handle to check
+
+ @retval EFI_INVALID_PARAMETER The handle is NULL or not a valid EFI_HANDLE.
+ @retval EFI_SUCCESS The handle is valid EFI_HANDLE.
+
+**/
+EFI_STATUS
+CoreValidateHandle (
+ IN EFI_HANDLE UserHandle
+ );
+
+//
+// Externs
+//
+extern EFI_LOCK gProtocolDatabaseLock;
+extern LIST_ENTRY gHandleList;
+extern UINT64 gHandleDatabaseKey;
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Core/Dxe/Hand/Locate.c b/roms/edk2/MdeModulePkg/Core/Dxe/Hand/Locate.c
new file mode 100644
index 000000000..be17f4cbc
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Core/Dxe/Hand/Locate.c
@@ -0,0 +1,702 @@
+/** @file
+ Locate handle functions
+
+Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "DxeMain.h"
+#include "Handle.h"
+
+//
+// ProtocolRequest - Last LocateHandle request ID
+//
+UINTN mEfiLocateHandleRequest = 0;
+
+//
+// Internal prototypes
+//
+
+typedef struct {
+ EFI_GUID *Protocol;
+ VOID *SearchKey;
+ LIST_ENTRY *Position;
+ PROTOCOL_ENTRY *ProtEntry;
+} LOCATE_POSITION;
+
+typedef
+IHANDLE *
+(* CORE_GET_NEXT) (
+ IN OUT LOCATE_POSITION *Position,
+ OUT VOID **Interface
+ );
+
+/**
+ Routine to get the next Handle, when you are searching for all handles.
+
+ @param Position Information about which Handle to seach for.
+ @param Interface Return the interface structure for the matching
+ protocol.
+
+ @return An pointer to IHANDLE if the next Position is not the end of the list.
+ Otherwise,NULL is returned.
+
+**/
+IHANDLE *
+CoreGetNextLocateAllHandles (
+ IN OUT LOCATE_POSITION *Position,
+ OUT VOID **Interface
+ );
+
+/**
+ Routine to get the next Handle, when you are searching for register protocol
+ notifies.
+
+ @param Position Information about which Handle to seach for.
+ @param Interface Return the interface structure for the matching
+ protocol.
+
+ @return An pointer to IHANDLE if the next Position is not the end of the list.
+ Otherwise,NULL is returned.
+
+**/
+IHANDLE *
+CoreGetNextLocateByRegisterNotify (
+ IN OUT LOCATE_POSITION *Position,
+ OUT VOID **Interface
+ );
+
+/**
+ Routine to get the next Handle, when you are searching for a given protocol.
+
+ @param Position Information about which Handle to seach for.
+ @param Interface Return the interface structure for the matching
+ protocol.
+
+ @return An pointer to IHANDLE if the next Position is not the end of the list.
+ Otherwise,NULL is returned.
+
+**/
+IHANDLE *
+CoreGetNextLocateByProtocol (
+ IN OUT LOCATE_POSITION *Position,
+ OUT VOID **Interface
+ );
+
+
+/**
+ Locates the requested handle(s) and returns them in Buffer.
+
+ @param SearchType The type of search to perform to locate the
+ handles
+ @param Protocol The protocol to search for
+ @param SearchKey Dependant on SearchType
+ @param BufferSize On input the size of Buffer. On output the
+ size of data returned.
+ @param Buffer The buffer to return the results in
+
+ @retval EFI_BUFFER_TOO_SMALL Buffer too small, required buffer size is
+ returned in BufferSize.
+ @retval EFI_INVALID_PARAMETER Invalid parameter
+ @retval EFI_SUCCESS Successfully found the requested handle(s) and
+ returns them in Buffer.
+
+**/
+EFI_STATUS
+EFIAPI
+CoreLocateHandle (
+ IN EFI_LOCATE_SEARCH_TYPE SearchType,
+ IN EFI_GUID *Protocol OPTIONAL,
+ IN VOID *SearchKey OPTIONAL,
+ IN OUT UINTN *BufferSize,
+ OUT EFI_HANDLE *Buffer
+ )
+{
+ EFI_STATUS Status;
+ LOCATE_POSITION Position;
+ PROTOCOL_NOTIFY *ProtNotify;
+ CORE_GET_NEXT GetNext;
+ UINTN ResultSize;
+ IHANDLE *Handle;
+ IHANDLE **ResultBuffer;
+ VOID *Interface;
+
+ if (BufferSize == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if ((*BufferSize > 0) && (Buffer == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ GetNext = NULL;
+
+ //
+ // Set initial position
+ //
+ Position.Protocol = Protocol;
+ Position.SearchKey = SearchKey;
+ Position.Position = &gHandleList;
+
+ ResultSize = 0;
+ ResultBuffer = (IHANDLE **) Buffer;
+ Status = EFI_SUCCESS;
+
+ //
+ // Lock the protocol database
+ //
+ CoreAcquireProtocolLock ();
+
+ //
+ // Get the search function based on type
+ //
+ switch (SearchType) {
+ case AllHandles:
+ GetNext = CoreGetNextLocateAllHandles;
+ break;
+
+ case ByRegisterNotify:
+ //
+ // Must have SearchKey for locate ByRegisterNotify
+ //
+ if (SearchKey == NULL) {
+ Status = EFI_INVALID_PARAMETER;
+ break;
+ }
+ GetNext = CoreGetNextLocateByRegisterNotify;
+ break;
+
+ case ByProtocol:
+ GetNext = CoreGetNextLocateByProtocol;
+ if (Protocol == NULL) {
+ Status = EFI_INVALID_PARAMETER;
+ break;
+ }
+ //
+ // Look up the protocol entry and set the head pointer
+ //
+ Position.ProtEntry = CoreFindProtocolEntry (Protocol, FALSE);
+ if (Position.ProtEntry == NULL) {
+ Status = EFI_NOT_FOUND;
+ break;
+ }
+ Position.Position = &Position.ProtEntry->Protocols;
+ break;
+
+ default:
+ Status = EFI_INVALID_PARAMETER;
+ break;
+ }
+
+ if (EFI_ERROR(Status)) {
+ CoreReleaseProtocolLock ();
+ return Status;
+ }
+
+ ASSERT (GetNext != NULL);
+ //
+ // Enumerate out the matching handles
+ //
+ mEfiLocateHandleRequest += 1;
+ for (; ;) {
+ //
+ // Get the next handle. If no more handles, stop
+ //
+ Handle = GetNext (&Position, &Interface);
+ if (NULL == Handle) {
+ break;
+ }
+
+ //
+ // Increase the resulting buffer size, and if this handle
+ // fits return it
+ //
+ ResultSize += sizeof(Handle);
+ if (ResultSize <= *BufferSize) {
+ *ResultBuffer = Handle;
+ ResultBuffer += 1;
+ }
+ }
+
+ //
+ // If the result is a zero length buffer, then there were no
+ // matching handles
+ //
+ if (ResultSize == 0) {
+ Status = EFI_NOT_FOUND;
+ } else {
+ //
+ // Return the resulting buffer size. If it's larger than what
+ // was passed, then set the error code
+ //
+ if (ResultSize > *BufferSize) {
+ Status = EFI_BUFFER_TOO_SMALL;
+ }
+
+ *BufferSize = ResultSize;
+
+ if (SearchType == ByRegisterNotify && !EFI_ERROR(Status)) {
+ //
+ // If this is a search by register notify and a handle was
+ // returned, update the register notification position
+ //
+ ASSERT (SearchKey != NULL);
+ ProtNotify = SearchKey;
+ ProtNotify->Position = ProtNotify->Position->ForwardLink;
+ }
+ }
+
+ CoreReleaseProtocolLock ();
+ return Status;
+}
+
+
+
+/**
+ Routine to get the next Handle, when you are searching for all handles.
+
+ @param Position Information about which Handle to seach for.
+ @param Interface Return the interface structure for the matching
+ protocol.
+
+ @return An pointer to IHANDLE if the next Position is not the end of the list.
+ Otherwise,NULL is returned.
+
+**/
+IHANDLE *
+CoreGetNextLocateAllHandles (
+ IN OUT LOCATE_POSITION *Position,
+ OUT VOID **Interface
+ )
+{
+ IHANDLE *Handle;
+
+ //
+ // Next handle
+ //
+ Position->Position = Position->Position->ForwardLink;
+
+ //
+ // If not at the end of the list, get the handle
+ //
+ Handle = NULL;
+ *Interface = NULL;
+ if (Position->Position != &gHandleList) {
+ Handle = CR (Position->Position, IHANDLE, AllHandles, EFI_HANDLE_SIGNATURE);
+ }
+
+ return Handle;
+}
+
+
+
+/**
+ Routine to get the next Handle, when you are searching for register protocol
+ notifies.
+
+ @param Position Information about which Handle to seach for.
+ @param Interface Return the interface structure for the matching
+ protocol.
+
+ @return An pointer to IHANDLE if the next Position is not the end of the list.
+ Otherwise,NULL is returned.
+
+**/
+IHANDLE *
+CoreGetNextLocateByRegisterNotify (
+ IN OUT LOCATE_POSITION *Position,
+ OUT VOID **Interface
+ )
+{
+ IHANDLE *Handle;
+ PROTOCOL_NOTIFY *ProtNotify;
+ PROTOCOL_INTERFACE *Prot;
+ LIST_ENTRY *Link;
+
+ Handle = NULL;
+ *Interface = NULL;
+ ProtNotify = Position->SearchKey;
+
+ //
+ // If this is the first request, get the next handle
+ //
+ if (ProtNotify != NULL) {
+ ASSERT(ProtNotify->Signature == PROTOCOL_NOTIFY_SIGNATURE);
+ Position->SearchKey = NULL;
+
+ //
+ // If not at the end of the list, get the next handle
+ //
+ Link = ProtNotify->Position->ForwardLink;
+ if (Link != &ProtNotify->Protocol->Protocols) {
+ Prot = CR (Link, PROTOCOL_INTERFACE, ByProtocol, PROTOCOL_INTERFACE_SIGNATURE);
+ Handle = Prot->Handle;
+ *Interface = Prot->Interface;
+ }
+ }
+
+ return Handle;
+}
+
+
+/**
+ Routine to get the next Handle, when you are searching for a given protocol.
+
+ @param Position Information about which Handle to seach for.
+ @param Interface Return the interface structure for the matching
+ protocol.
+
+ @return An pointer to IHANDLE if the next Position is not the end of the list.
+ Otherwise,NULL is returned.
+
+**/
+IHANDLE *
+CoreGetNextLocateByProtocol (
+ IN OUT LOCATE_POSITION *Position,
+ OUT VOID **Interface
+ )
+{
+ IHANDLE *Handle;
+ LIST_ENTRY *Link;
+ PROTOCOL_INTERFACE *Prot;
+
+ Handle = NULL;
+ *Interface = NULL;
+ for (; ;) {
+ //
+ // Next entry
+ //
+ Link = Position->Position->ForwardLink;
+ Position->Position = Link;
+
+ //
+ // If not at the end, return the handle
+ //
+ if (Link == &Position->ProtEntry->Protocols) {
+ Handle = NULL;
+ break;
+ }
+
+ //
+ // Get the handle
+ //
+ Prot = CR(Link, PROTOCOL_INTERFACE, ByProtocol, PROTOCOL_INTERFACE_SIGNATURE);
+ Handle = Prot->Handle;
+ *Interface = Prot->Interface;
+
+ //
+ // If this handle has not been returned this request, then
+ // return it now
+ //
+ if (Handle->LocateRequest != mEfiLocateHandleRequest) {
+ Handle->LocateRequest = mEfiLocateHandleRequest;
+ break;
+ }
+ }
+
+ return Handle;
+}
+
+
+/**
+ Locates the handle to a device on the device path that supports the specified protocol.
+
+ @param Protocol Specifies the protocol to search for.
+ @param DevicePath On input, a pointer to a pointer to the device path. On output, the device
+ path pointer is modified to point to the remaining part of the device
+ path.
+ @param Device A pointer to the returned device handle.
+
+ @retval EFI_SUCCESS The resulting handle was returned.
+ @retval EFI_NOT_FOUND No handles match the search.
+ @retval EFI_INVALID_PARAMETER Protocol is NULL.
+ @retval EFI_INVALID_PARAMETER DevicePath is NULL.
+ @retval EFI_INVALID_PARAMETER A handle matched the search and Device is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+CoreLocateDevicePath (
+ IN EFI_GUID *Protocol,
+ IN OUT EFI_DEVICE_PATH_PROTOCOL **DevicePath,
+ OUT EFI_HANDLE *Device
+ )
+{
+ INTN SourceSize;
+ INTN Size;
+ INTN BestMatch;
+ UINTN HandleCount;
+ UINTN Index;
+ EFI_STATUS Status;
+ EFI_HANDLE *Handles;
+ EFI_HANDLE Handle;
+ EFI_HANDLE BestDevice;
+ EFI_DEVICE_PATH_PROTOCOL *SourcePath;
+ EFI_DEVICE_PATH_PROTOCOL *TmpDevicePath;
+
+ if (Protocol == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if ((DevicePath == NULL) || (*DevicePath == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Handles = NULL;
+ BestDevice = NULL;
+ SourcePath = *DevicePath;
+ TmpDevicePath = SourcePath;
+ while (!IsDevicePathEnd (TmpDevicePath)) {
+ if (IsDevicePathEndInstance (TmpDevicePath)) {
+ //
+ // If DevicePath is a multi-instance device path,
+ // the function will operate on the first instance
+ //
+ break;
+ }
+ TmpDevicePath = NextDevicePathNode (TmpDevicePath);
+ }
+
+ SourceSize = (UINTN) TmpDevicePath - (UINTN) SourcePath;
+
+ //
+ // Get a list of all handles that support the requested protocol
+ //
+ Status = CoreLocateHandleBuffer (ByProtocol, Protocol, NULL, &HandleCount, &Handles);
+ if (EFI_ERROR (Status) || HandleCount == 0) {
+ return EFI_NOT_FOUND;
+ }
+
+ BestMatch = -1;
+ for(Index = 0; Index < HandleCount; Index += 1) {
+ Handle = Handles[Index];
+ Status = CoreHandleProtocol (Handle, &gEfiDevicePathProtocolGuid, (VOID **)&TmpDevicePath);
+ if (EFI_ERROR (Status)) {
+ //
+ // If this handle doesn't support device path, then skip it
+ //
+ continue;
+ }
+
+ //
+ // Check if DevicePath is first part of SourcePath
+ //
+ Size = GetDevicePathSize (TmpDevicePath) - sizeof(EFI_DEVICE_PATH_PROTOCOL);
+ ASSERT (Size >= 0);
+ if ((Size <= SourceSize) && CompareMem (SourcePath, TmpDevicePath, (UINTN) Size) == 0) {
+ //
+ // If the size is equal to the best match, then we
+ // have a duplicate device path for 2 different device
+ // handles
+ //
+ ASSERT (Size != BestMatch);
+
+ //
+ // We've got a match, see if it's the best match so far
+ //
+ if (Size > BestMatch) {
+ BestMatch = Size;
+ BestDevice = Handle;
+ }
+ }
+ }
+
+ CoreFreePool (Handles);
+
+ //
+ // If there wasn't any match, then no parts of the device path was found.
+ // Which is strange since there is likely a "root level" device path in the system.
+ //
+ if (BestMatch == -1) {
+ return EFI_NOT_FOUND;
+ }
+
+ if (Device == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+ *Device = BestDevice;
+
+ //
+ // Return the remaining part of the device path
+ //
+ *DevicePath = (EFI_DEVICE_PATH_PROTOCOL *) (((UINT8 *) SourcePath) + BestMatch);
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Return the first Protocol Interface that matches the Protocol GUID. If
+ Registration is passed in, return a Protocol Instance that was just add
+ to the system. If Registration is NULL return the first Protocol Interface
+ you find.
+
+ @param Protocol The protocol to search for
+ @param Registration Optional Registration Key returned from
+ RegisterProtocolNotify()
+ @param Interface Return the Protocol interface (instance).
+
+ @retval EFI_SUCCESS If a valid Interface is returned
+ @retval EFI_INVALID_PARAMETER Invalid parameter
+ @retval EFI_NOT_FOUND Protocol interface not found
+
+**/
+EFI_STATUS
+EFIAPI
+CoreLocateProtocol (
+ IN EFI_GUID *Protocol,
+ IN VOID *Registration OPTIONAL,
+ OUT VOID **Interface
+ )
+{
+ EFI_STATUS Status;
+ LOCATE_POSITION Position;
+ PROTOCOL_NOTIFY *ProtNotify;
+ IHANDLE *Handle;
+
+ if ((Interface == NULL) || (Protocol == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ *Interface = NULL;
+ Status = EFI_SUCCESS;
+
+ //
+ // Set initial position
+ //
+ Position.Protocol = Protocol;
+ Position.SearchKey = Registration;
+ Position.Position = &gHandleList;
+
+ //
+ // Lock the protocol database
+ //
+ Status = CoreAcquireLockOrFail (&gProtocolDatabaseLock);
+ if (EFI_ERROR (Status)) {
+ return EFI_NOT_FOUND;
+ }
+
+ mEfiLocateHandleRequest += 1;
+
+ if (Registration == NULL) {
+ //
+ // Look up the protocol entry and set the head pointer
+ //
+ Position.ProtEntry = CoreFindProtocolEntry (Protocol, FALSE);
+ if (Position.ProtEntry == NULL) {
+ Status = EFI_NOT_FOUND;
+ goto Done;
+ }
+ Position.Position = &Position.ProtEntry->Protocols;
+
+ Handle = CoreGetNextLocateByProtocol (&Position, Interface);
+ } else {
+ Handle = CoreGetNextLocateByRegisterNotify (&Position, Interface);
+ }
+
+ if (Handle == NULL) {
+ Status = EFI_NOT_FOUND;
+ } else if (Registration != NULL) {
+ //
+ // If this is a search by register notify and a handle was
+ // returned, update the register notification position
+ //
+ ProtNotify = Registration;
+ ProtNotify->Position = ProtNotify->Position->ForwardLink;
+ }
+
+Done:
+ CoreReleaseProtocolLock ();
+ return Status;
+}
+
+
+/**
+ Function returns an array of handles that support the requested protocol
+ in a buffer allocated from pool. This is a version of CoreLocateHandle()
+ that allocates a buffer for the caller.
+
+ @param SearchType Specifies which handle(s) are to be returned.
+ @param Protocol Provides the protocol to search by. This
+ parameter is only valid for SearchType
+ ByProtocol.
+ @param SearchKey Supplies the search key depending on the
+ SearchType.
+ @param NumberHandles The number of handles returned in Buffer.
+ @param Buffer A pointer to the buffer to return the requested
+ array of handles that support Protocol.
+
+ @retval EFI_SUCCESS The result array of handles was returned.
+ @retval EFI_NOT_FOUND No handles match the search.
+ @retval EFI_OUT_OF_RESOURCES There is not enough pool memory to store the
+ matching results.
+ @retval EFI_INVALID_PARAMETER One or more parameters are not valid.
+
+**/
+EFI_STATUS
+EFIAPI
+CoreLocateHandleBuffer (
+ IN EFI_LOCATE_SEARCH_TYPE SearchType,
+ IN EFI_GUID *Protocol OPTIONAL,
+ IN VOID *SearchKey OPTIONAL,
+ IN OUT UINTN *NumberHandles,
+ OUT EFI_HANDLE **Buffer
+ )
+{
+ EFI_STATUS Status;
+ UINTN BufferSize;
+
+ if (NumberHandles == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (Buffer == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ BufferSize = 0;
+ *NumberHandles = 0;
+ *Buffer = NULL;
+ Status = CoreLocateHandle (
+ SearchType,
+ Protocol,
+ SearchKey,
+ &BufferSize,
+ *Buffer
+ );
+ //
+ // LocateHandleBuffer() returns incorrect status code if SearchType is
+ // invalid.
+ //
+ // Add code to correctly handle expected errors from CoreLocateHandle().
+ //
+ if (EFI_ERROR(Status) && Status != EFI_BUFFER_TOO_SMALL) {
+ if (Status != EFI_INVALID_PARAMETER) {
+ Status = EFI_NOT_FOUND;
+ }
+ return Status;
+ }
+
+ *Buffer = AllocatePool (BufferSize);
+ if (*Buffer == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ Status = CoreLocateHandle (
+ SearchType,
+ Protocol,
+ SearchKey,
+ &BufferSize,
+ *Buffer
+ );
+
+ *NumberHandles = BufferSize / sizeof(EFI_HANDLE);
+ if (EFI_ERROR(Status)) {
+ *NumberHandles = 0;
+ }
+
+ return Status;
+}
+
+
+
diff --git a/roms/edk2/MdeModulePkg/Core/Dxe/Hand/Notify.c b/roms/edk2/MdeModulePkg/Core/Dxe/Hand/Notify.c
new file mode 100644
index 000000000..553413a35
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Core/Dxe/Hand/Notify.c
@@ -0,0 +1,285 @@
+/** @file
+ Support functions for UEFI protocol notification infrastructure.
+
+Copyright (c) 2006 - 2008, 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 "Handle.h"
+#include "Event.h"
+
+/**
+ Signal event for every protocol in protocol entry.
+
+ @param ProtEntry Protocol entry
+
+**/
+VOID
+CoreNotifyProtocolEntry (
+ IN PROTOCOL_ENTRY *ProtEntry
+ )
+{
+ PROTOCOL_NOTIFY *ProtNotify;
+ LIST_ENTRY *Link;
+
+ ASSERT_LOCKED (&gProtocolDatabaseLock);
+
+ for (Link=ProtEntry->Notify.ForwardLink; Link != &ProtEntry->Notify; Link=Link->ForwardLink) {
+ ProtNotify = CR(Link, PROTOCOL_NOTIFY, Link, PROTOCOL_NOTIFY_SIGNATURE);
+ CoreSignalEvent (ProtNotify->Event);
+ }
+}
+
+
+
+/**
+ Removes Protocol from the protocol list (but not the handle list).
+
+ @param Handle The handle to remove protocol on.
+ @param Protocol GUID of the protocol to be moved
+ @param Interface The interface of the protocol
+
+ @return Protocol Entry
+
+**/
+PROTOCOL_INTERFACE *
+CoreRemoveInterfaceFromProtocol (
+ IN IHANDLE *Handle,
+ IN EFI_GUID *Protocol,
+ IN VOID *Interface
+ )
+{
+ PROTOCOL_INTERFACE *Prot;
+ PROTOCOL_NOTIFY *ProtNotify;
+ PROTOCOL_ENTRY *ProtEntry;
+ LIST_ENTRY *Link;
+
+ ASSERT_LOCKED (&gProtocolDatabaseLock);
+
+ Prot = CoreFindProtocolInterface (Handle, Protocol, Interface);
+ if (Prot != NULL) {
+
+ ProtEntry = Prot->Protocol;
+
+ //
+ // If there's a protocol notify location pointing to this entry, back it up one
+ //
+ for(Link = ProtEntry->Notify.ForwardLink; Link != &ProtEntry->Notify; Link=Link->ForwardLink) {
+ ProtNotify = CR(Link, PROTOCOL_NOTIFY, Link, PROTOCOL_NOTIFY_SIGNATURE);
+
+ if (ProtNotify->Position == &Prot->ByProtocol) {
+ ProtNotify->Position = Prot->ByProtocol.BackLink;
+ }
+ }
+
+ //
+ // Remove the protocol interface entry
+ //
+ RemoveEntryList (&Prot->ByProtocol);
+ }
+
+ return Prot;
+}
+
+
+/**
+ Add a new protocol notification record for the request protocol.
+
+ @param Protocol The requested protocol to add the notify
+ registration
+ @param Event The event to signal
+ @param Registration Returns the registration record
+
+ @retval EFI_INVALID_PARAMETER Invalid parameter
+ @retval EFI_SUCCESS Successfully returned the registration record
+ that has been added
+
+**/
+EFI_STATUS
+EFIAPI
+CoreRegisterProtocolNotify (
+ IN EFI_GUID *Protocol,
+ IN EFI_EVENT Event,
+ OUT VOID **Registration
+ )
+{
+ PROTOCOL_ENTRY *ProtEntry;
+ PROTOCOL_NOTIFY *ProtNotify;
+ EFI_STATUS Status;
+
+ if ((Protocol == NULL) || (Event == NULL) || (Registration == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ CoreAcquireProtocolLock ();
+
+ ProtNotify = NULL;
+
+ //
+ // Get the protocol entry to add the notification too
+ //
+
+ ProtEntry = CoreFindProtocolEntry (Protocol, TRUE);
+ if (ProtEntry != NULL) {
+
+ //
+ // Allocate a new notification record
+ //
+ ProtNotify = AllocatePool (sizeof(PROTOCOL_NOTIFY));
+ if (ProtNotify != NULL) {
+ ((IEVENT *)Event)->ExFlag |= EVT_EXFLAG_EVENT_PROTOCOL_NOTIFICATION;
+ ProtNotify->Signature = PROTOCOL_NOTIFY_SIGNATURE;
+ ProtNotify->Protocol = ProtEntry;
+ ProtNotify->Event = Event;
+ //
+ // start at the begining
+ //
+ ProtNotify->Position = &ProtEntry->Protocols;
+
+ InsertTailList (&ProtEntry->Notify, &ProtNotify->Link);
+ }
+ }
+
+ CoreReleaseProtocolLock ();
+
+ //
+ // Done. If we have a protocol notify entry, then return it.
+ // Otherwise, we must have run out of resources trying to add one
+ //
+
+ Status = EFI_OUT_OF_RESOURCES;
+ if (ProtNotify != NULL) {
+ *Registration = ProtNotify;
+ Status = EFI_SUCCESS;
+ }
+
+ return Status;
+}
+
+
+/**
+ Reinstall a protocol interface on a device handle. The OldInterface for Protocol is replaced by the NewInterface.
+
+ @param UserHandle Handle on which the interface is to be
+ reinstalled
+ @param Protocol The numeric ID of the interface
+ @param OldInterface A pointer to the old interface
+ @param NewInterface A pointer to the new interface
+
+ @retval EFI_SUCCESS The protocol interface was installed
+ @retval EFI_NOT_FOUND The OldInterface on the handle was not found
+ @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value
+
+**/
+EFI_STATUS
+EFIAPI
+CoreReinstallProtocolInterface (
+ IN EFI_HANDLE UserHandle,
+ IN EFI_GUID *Protocol,
+ IN VOID *OldInterface,
+ IN VOID *NewInterface
+ )
+{
+ EFI_STATUS Status;
+ IHANDLE *Handle;
+ PROTOCOL_INTERFACE *Prot;
+ PROTOCOL_ENTRY *ProtEntry;
+
+ Status = CoreValidateHandle (UserHandle);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if (Protocol == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Handle = (IHANDLE *) UserHandle;
+
+ //
+ // Lock the protocol database
+ //
+ CoreAcquireProtocolLock ();
+
+ //
+ // Check that Protocol exists on UserHandle, and Interface matches the interface in the database
+ //
+ Prot = CoreFindProtocolInterface (UserHandle, Protocol, OldInterface);
+ if (Prot == NULL) {
+ Status = EFI_NOT_FOUND;
+ goto Done;
+ }
+
+ //
+ // Attempt to disconnect all drivers that are using the protocol interface that is about to be reinstalled
+ //
+ Status = CoreDisconnectControllersUsingProtocolInterface (
+ UserHandle,
+ Prot
+ );
+ if (EFI_ERROR (Status)) {
+ //
+ // One or more drivers refused to release, so return the error
+ //
+ goto Done;
+ }
+
+ //
+ // Remove the protocol interface from the protocol
+ //
+ Prot = CoreRemoveInterfaceFromProtocol (Handle, Protocol, OldInterface);
+
+ if (Prot == NULL) {
+ Status = EFI_NOT_FOUND;
+ goto Done;
+ }
+
+ ProtEntry = Prot->Protocol;
+
+ //
+ // Update the interface on the protocol
+ //
+ Prot->Interface = NewInterface;
+
+ //
+ // Add this protocol interface to the tail of the
+ // protocol entry
+ //
+ InsertTailList (&ProtEntry->Protocols, &Prot->ByProtocol);
+
+ //
+ // Update the Key to show that the handle has been created/modified
+ //
+ gHandleDatabaseKey++;
+ Handle->Key = gHandleDatabaseKey;
+
+ //
+ // Release the lock and connect all drivers to UserHandle
+ //
+ CoreReleaseProtocolLock ();
+ //
+ // Return code is ignored on purpose.
+ //
+ CoreConnectController (
+ UserHandle,
+ NULL,
+ NULL,
+ TRUE
+ );
+ CoreAcquireProtocolLock ();
+
+ //
+ // Notify the notification list for this protocol
+ //
+ CoreNotifyProtocolEntry (ProtEntry);
+
+ Status = EFI_SUCCESS;
+
+Done:
+ CoreReleaseProtocolLock ();
+
+ return Status;
+}
diff --git a/roms/edk2/MdeModulePkg/Core/Dxe/Image/Image.c b/roms/edk2/MdeModulePkg/Core/Dxe/Image/Image.c
new file mode 100644
index 000000000..d86da89ee
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Core/Dxe/Image/Image.c
@@ -0,0 +1,1909 @@
+/** @file
+ Core image handling services to load and unload PeImage.
+
+Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "DxeMain.h"
+#include "Image.h"
+
+//
+// Module Globals
+//
+LOADED_IMAGE_PRIVATE_DATA *mCurrentImage = NULL;
+
+typedef struct {
+ LIST_ENTRY Link;
+ EDKII_PECOFF_IMAGE_EMULATOR_PROTOCOL *Emulator;
+ UINT16 MachineType;
+} EMULATOR_ENTRY;
+
+STATIC LIST_ENTRY mAvailableEmulators;
+STATIC EFI_EVENT mPeCoffEmuProtocolRegistrationEvent;
+STATIC VOID *mPeCoffEmuProtocolNotifyRegistration;
+
+//
+// This code is needed to build the Image handle for the DXE Core
+//
+LOADED_IMAGE_PRIVATE_DATA mCorePrivateImage = {
+ LOADED_IMAGE_PRIVATE_DATA_SIGNATURE, // Signature
+ NULL, // Image handle
+ EFI_IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER, // Image type
+ TRUE, // If entrypoint has been called
+ NULL, // EntryPoint
+ {
+ EFI_LOADED_IMAGE_INFORMATION_REVISION, // Revision
+ NULL, // Parent handle
+ NULL, // System handle
+
+ NULL, // Device handle
+ NULL, // File path
+ NULL, // Reserved
+
+ 0, // LoadOptionsSize
+ NULL, // LoadOptions
+
+ NULL, // ImageBase
+ 0, // ImageSize
+ EfiBootServicesCode, // ImageCodeType
+ EfiBootServicesData // ImageDataType
+ },
+ (EFI_PHYSICAL_ADDRESS)0, // ImageBasePage
+ 0, // NumberOfPages
+ NULL, // FixupData
+ 0, // Tpl
+ EFI_SUCCESS, // Status
+ 0, // ExitDataSize
+ NULL, // ExitData
+ NULL, // JumpBuffer
+ NULL, // JumpContext
+ 0, // Machine
+ NULL, // PeCoffEmu
+ NULL, // RuntimeData
+ NULL // LoadedImageDevicePath
+};
+//
+// The field is define for Loading modules at fixed address feature to tracker the PEI code
+// memory range usage. It is a bit mapped array in which every bit indicates the correspoding memory page
+// available or not.
+//
+GLOBAL_REMOVE_IF_UNREFERENCED UINT64 *mDxeCodeMemoryRangeUsageBitMap=NULL;
+
+typedef struct {
+ UINT16 MachineType;
+ CHAR16 *MachineTypeName;
+} MACHINE_TYPE_INFO;
+
+GLOBAL_REMOVE_IF_UNREFERENCED MACHINE_TYPE_INFO mMachineTypeInfo[] = {
+ {EFI_IMAGE_MACHINE_IA32, L"IA32"},
+ {EFI_IMAGE_MACHINE_IA64, L"IA64"},
+ {EFI_IMAGE_MACHINE_X64, L"X64"},
+ {EFI_IMAGE_MACHINE_ARMTHUMB_MIXED, L"ARM"},
+ {EFI_IMAGE_MACHINE_AARCH64, L"AARCH64"}
+};
+
+UINT16 mDxeCoreImageMachineType = 0;
+
+/**
+ Return machine type name.
+
+ @param MachineType The machine type
+
+ @return machine type name
+**/
+CHAR16 *
+GetMachineTypeName (
+ UINT16 MachineType
+ )
+{
+ UINTN Index;
+
+ for (Index = 0; Index < sizeof(mMachineTypeInfo)/sizeof(mMachineTypeInfo[0]); Index++) {
+ if (mMachineTypeInfo[Index].MachineType == MachineType) {
+ return mMachineTypeInfo[Index].MachineTypeName;
+ }
+ }
+
+ return L"<Unknown>";
+}
+
+/**
+ Notification event handler registered by CoreInitializeImageServices () to
+ keep track of which PE/COFF image emulators are available.
+
+ @param Event The Event that is being processed, not used.
+ @param Context Event Context, not used.
+
+**/
+STATIC
+VOID
+EFIAPI
+PeCoffEmuProtocolNotify (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ EFI_STATUS Status;
+ UINTN BufferSize;
+ EFI_HANDLE EmuHandle;
+ EDKII_PECOFF_IMAGE_EMULATOR_PROTOCOL *Emulator;
+ EMULATOR_ENTRY *Entry;
+
+ EmuHandle = NULL;
+ Emulator = NULL;
+
+ while (TRUE) {
+ BufferSize = sizeof (EmuHandle);
+ Status = CoreLocateHandle (
+ ByRegisterNotify,
+ NULL,
+ mPeCoffEmuProtocolNotifyRegistration,
+ &BufferSize,
+ &EmuHandle
+ );
+ if (EFI_ERROR (Status)) {
+ //
+ // If no more notification events exit
+ //
+ return;
+ }
+
+ Status = CoreHandleProtocol (
+ EmuHandle,
+ &gEdkiiPeCoffImageEmulatorProtocolGuid,
+ (VOID **)&Emulator
+ );
+ if (EFI_ERROR (Status) || Emulator == NULL) {
+ continue;
+ }
+
+ Entry = AllocateZeroPool (sizeof (*Entry));
+ ASSERT (Entry != NULL);
+
+ Entry->Emulator = Emulator;
+ Entry->MachineType = Entry->Emulator->MachineType;
+
+ InsertTailList (&mAvailableEmulators, &Entry->Link);
+ }
+}
+
+/**
+ Add the Image Services to EFI Boot Services Table and install the protocol
+ interfaces for this image.
+
+ @param HobStart The HOB to initialize
+
+ @return Status code.
+
+**/
+EFI_STATUS
+CoreInitializeImageServices (
+ IN VOID *HobStart
+ )
+{
+ EFI_STATUS Status;
+ LOADED_IMAGE_PRIVATE_DATA *Image;
+ EFI_PHYSICAL_ADDRESS DxeCoreImageBaseAddress;
+ UINT64 DxeCoreImageLength;
+ VOID *DxeCoreEntryPoint;
+ EFI_PEI_HOB_POINTERS DxeCoreHob;
+
+ //
+ // Searching for image hob
+ //
+ DxeCoreHob.Raw = HobStart;
+ while ((DxeCoreHob.Raw = GetNextHob (EFI_HOB_TYPE_MEMORY_ALLOCATION, DxeCoreHob.Raw)) != NULL) {
+ if (CompareGuid (&DxeCoreHob.MemoryAllocationModule->MemoryAllocationHeader.Name, &gEfiHobMemoryAllocModuleGuid)) {
+ //
+ // Find Dxe Core HOB
+ //
+ break;
+ }
+ DxeCoreHob.Raw = GET_NEXT_HOB (DxeCoreHob);
+ }
+ ASSERT (DxeCoreHob.Raw != NULL);
+
+ DxeCoreImageBaseAddress = DxeCoreHob.MemoryAllocationModule->MemoryAllocationHeader.MemoryBaseAddress;
+ DxeCoreImageLength = DxeCoreHob.MemoryAllocationModule->MemoryAllocationHeader.MemoryLength;
+ DxeCoreEntryPoint = (VOID *) (UINTN) DxeCoreHob.MemoryAllocationModule->EntryPoint;
+ gDxeCoreFileName = &DxeCoreHob.MemoryAllocationModule->ModuleName;
+
+ //
+ // Initialize the fields for an internal driver
+ //
+ Image = &mCorePrivateImage;
+
+ Image->EntryPoint = (EFI_IMAGE_ENTRY_POINT)(UINTN)DxeCoreEntryPoint;
+ Image->ImageBasePage = DxeCoreImageBaseAddress;
+ Image->NumberOfPages = (UINTN)(EFI_SIZE_TO_PAGES((UINTN)(DxeCoreImageLength)));
+ Image->Tpl = gEfiCurrentTpl;
+ Image->Info.SystemTable = gDxeCoreST;
+ Image->Info.ImageBase = (VOID *)(UINTN)DxeCoreImageBaseAddress;
+ Image->Info.ImageSize = DxeCoreImageLength;
+
+ //
+ // Install the protocol interfaces for this image
+ //
+ Status = CoreInstallProtocolInterface (
+ &Image->Handle,
+ &gEfiLoadedImageProtocolGuid,
+ EFI_NATIVE_INTERFACE,
+ &Image->Info
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ mCurrentImage = Image;
+
+ //
+ // Fill in DXE globals
+ //
+ mDxeCoreImageMachineType = PeCoffLoaderGetMachineType (Image->Info.ImageBase);
+ gDxeCoreImageHandle = Image->Handle;
+ gDxeCoreLoadedImage = &Image->Info;
+
+ //
+ // Create the PE/COFF emulator protocol registration event
+ //
+ Status = CoreCreateEvent (
+ EVT_NOTIFY_SIGNAL,
+ TPL_CALLBACK,
+ PeCoffEmuProtocolNotify,
+ NULL,
+ &mPeCoffEmuProtocolRegistrationEvent
+ );
+ ASSERT_EFI_ERROR(Status);
+
+ //
+ // Register for protocol notifications on this event
+ //
+ Status = CoreRegisterProtocolNotify (
+ &gEdkiiPeCoffImageEmulatorProtocolGuid,
+ mPeCoffEmuProtocolRegistrationEvent,
+ &mPeCoffEmuProtocolNotifyRegistration
+ );
+ ASSERT_EFI_ERROR(Status);
+
+ InitializeListHead (&mAvailableEmulators);
+
+ ProtectUefiImage (&Image->Info, Image->LoadedImageDevicePath);
+
+ return Status;
+}
+
+/**
+ Read image file (specified by UserHandle) into user specified buffer with specified offset
+ and length.
+
+ @param UserHandle Image file handle
+ @param Offset Offset to the source file
+ @param ReadSize For input, pointer of size to read; For output,
+ pointer of size actually read.
+ @param Buffer Buffer to write into
+
+ @retval EFI_SUCCESS Successfully read the specified part of file
+ into buffer.
+
+**/
+EFI_STATUS
+EFIAPI
+CoreReadImageFile (
+ IN VOID *UserHandle,
+ IN UINTN Offset,
+ IN OUT UINTN *ReadSize,
+ OUT VOID *Buffer
+ )
+{
+ UINTN EndPosition;
+ IMAGE_FILE_HANDLE *FHand;
+
+ if (UserHandle == NULL || ReadSize == NULL || Buffer == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (MAX_ADDRESS - Offset < *ReadSize) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ FHand = (IMAGE_FILE_HANDLE *)UserHandle;
+ ASSERT (FHand->Signature == IMAGE_FILE_HANDLE_SIGNATURE);
+
+ //
+ // Move data from our local copy of the file
+ //
+ EndPosition = Offset + *ReadSize;
+ if (EndPosition > FHand->SourceSize) {
+ *ReadSize = (UINT32)(FHand->SourceSize - Offset);
+ }
+ if (Offset >= FHand->SourceSize) {
+ *ReadSize = 0;
+ }
+
+ CopyMem (Buffer, (CHAR8 *)FHand->Source + Offset, *ReadSize);
+ return EFI_SUCCESS;
+}
+/**
+ To check memory usage bit map array to figure out if the memory range the image will be loaded in is available or not. If
+ memory range is available, the function will mark the corresponding bits to 1 which indicates the memory range is used.
+ The function is only invoked when load modules at fixed address feature is enabled.
+
+ @param ImageBase The base address the image will be loaded at.
+ @param ImageSize The size of the image
+
+ @retval EFI_SUCCESS The memory range the image will be loaded in is available
+ @retval EFI_NOT_FOUND The memory range the image will be loaded in is not available
+**/
+EFI_STATUS
+CheckAndMarkFixLoadingMemoryUsageBitMap (
+ IN EFI_PHYSICAL_ADDRESS ImageBase,
+ IN UINTN ImageSize
+ )
+{
+ UINT32 DxeCodePageNumber;
+ UINT64 DxeCodeSize;
+ EFI_PHYSICAL_ADDRESS DxeCodeBase;
+ UINTN BaseOffsetPageNumber;
+ UINTN TopOffsetPageNumber;
+ UINTN Index;
+ //
+ // The DXE code range includes RuntimeCodePage range and Boot time code range.
+ //
+ DxeCodePageNumber = PcdGet32(PcdLoadFixAddressRuntimeCodePageNumber);
+ DxeCodePageNumber += PcdGet32(PcdLoadFixAddressBootTimeCodePageNumber);
+ DxeCodeSize = EFI_PAGES_TO_SIZE(DxeCodePageNumber);
+ DxeCodeBase = gLoadModuleAtFixAddressConfigurationTable.DxeCodeTopAddress - DxeCodeSize;
+
+ //
+ // If the memory usage bit map is not initialized, do it. Every bit in the array
+ // indicate the status of the corresponding memory page, available or not
+ //
+ if (mDxeCodeMemoryRangeUsageBitMap == NULL) {
+ mDxeCodeMemoryRangeUsageBitMap = AllocateZeroPool(((DxeCodePageNumber/64) + 1)*sizeof(UINT64));
+ }
+ //
+ // If the Dxe code memory range is not allocated or the bit map array allocation failed, return EFI_NOT_FOUND
+ //
+ if (!gLoadFixedAddressCodeMemoryReady || mDxeCodeMemoryRangeUsageBitMap == NULL) {
+ return EFI_NOT_FOUND;
+ }
+ //
+ // Test the memory range for loading the image in the DXE code range.
+ //
+ if (gLoadModuleAtFixAddressConfigurationTable.DxeCodeTopAddress < ImageBase + ImageSize ||
+ DxeCodeBase > ImageBase) {
+ return EFI_NOT_FOUND;
+ }
+ //
+ // Test if the memory is avalaible or not.
+ //
+ BaseOffsetPageNumber = EFI_SIZE_TO_PAGES((UINT32)(ImageBase - DxeCodeBase));
+ TopOffsetPageNumber = EFI_SIZE_TO_PAGES((UINT32)(ImageBase + ImageSize - DxeCodeBase));
+ for (Index = BaseOffsetPageNumber; Index < TopOffsetPageNumber; Index ++) {
+ if ((mDxeCodeMemoryRangeUsageBitMap[Index / 64] & LShiftU64(1, (Index % 64))) != 0) {
+ //
+ // This page is already used.
+ //
+ return EFI_NOT_FOUND;
+ }
+ }
+
+ //
+ // Being here means the memory range is available. So mark the bits for the memory range
+ //
+ for (Index = BaseOffsetPageNumber; Index < TopOffsetPageNumber; Index ++) {
+ mDxeCodeMemoryRangeUsageBitMap[Index / 64] |= LShiftU64(1, (Index % 64));
+ }
+ return EFI_SUCCESS;
+}
+/**
+
+ Get the fixed loading address from image header assigned by build tool. This function only be called
+ when Loading module at Fixed address feature enabled.
+
+ @param ImageContext Pointer to the image context structure that describes the PE/COFF
+ image that needs to be examined by this function.
+ @retval EFI_SUCCESS An fixed loading address is assigned to this image by build tools .
+ @retval EFI_NOT_FOUND The image has no assigned fixed loading address.
+
+**/
+EFI_STATUS
+GetPeCoffImageFixLoadingAssignedAddress(
+ IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext
+ )
+{
+ UINTN SectionHeaderOffset;
+ EFI_STATUS Status;
+ EFI_IMAGE_SECTION_HEADER SectionHeader;
+ EFI_IMAGE_OPTIONAL_HEADER_UNION *ImgHdr;
+ UINT16 Index;
+ UINTN Size;
+ UINT16 NumberOfSections;
+ IMAGE_FILE_HANDLE *Handle;
+ UINT64 ValueInSectionHeader;
+
+
+ Status = EFI_NOT_FOUND;
+
+ //
+ // Get PeHeader pointer
+ //
+ Handle = (IMAGE_FILE_HANDLE*)ImageContext->Handle;
+ ImgHdr = (EFI_IMAGE_OPTIONAL_HEADER_UNION *)((CHAR8* )Handle->Source + ImageContext->PeCoffHeaderOffset);
+ SectionHeaderOffset = ImageContext->PeCoffHeaderOffset +
+ sizeof (UINT32) +
+ sizeof (EFI_IMAGE_FILE_HEADER) +
+ ImgHdr->Pe32.FileHeader.SizeOfOptionalHeader;
+ NumberOfSections = ImgHdr->Pe32.FileHeader.NumberOfSections;
+
+ //
+ // Get base address from the first section header that doesn't point to code section.
+ //
+ for (Index = 0; Index < NumberOfSections; Index++) {
+ //
+ // Read section header from file
+ //
+ Size = sizeof (EFI_IMAGE_SECTION_HEADER);
+ Status = ImageContext->ImageRead (
+ ImageContext->Handle,
+ SectionHeaderOffset,
+ &Size,
+ &SectionHeader
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ if (Size != sizeof (EFI_IMAGE_SECTION_HEADER)) {
+ return EFI_NOT_FOUND;
+ }
+
+ Status = EFI_NOT_FOUND;
+
+ if ((SectionHeader.Characteristics & EFI_IMAGE_SCN_CNT_CODE) == 0) {
+ //
+ // Build tool will save the address in PointerToRelocations & PointerToLineNumbers fields in the first section header
+ // that doesn't point to code section in image header, as well as ImageBase field of image header. And there is an
+ // assumption that when the feature is enabled, if a module is assigned a loading address by tools, PointerToRelocations
+ // & PointerToLineNumbers fields should NOT be Zero, or else, these 2 fields should be set to Zero
+ //
+ ValueInSectionHeader = ReadUnaligned64((UINT64*)&SectionHeader.PointerToRelocations);
+ if (ValueInSectionHeader != 0) {
+ //
+ // When the feature is configured as load module at fixed absolute address, the ImageAddress field of ImageContext
+ // hold the spcified address. If the feature is configured as load module at fixed offset, ImageAddress hold an offset
+ // relative to top address
+ //
+ if ((INT64)PcdGet64(PcdLoadModuleAtFixAddressEnable) < 0) {
+ ImageContext->ImageAddress = gLoadModuleAtFixAddressConfigurationTable.DxeCodeTopAddress + (INT64)(INTN)ImageContext->ImageAddress;
+ }
+ //
+ // Check if the memory range is available.
+ //
+ Status = CheckAndMarkFixLoadingMemoryUsageBitMap (ImageContext->ImageAddress, (UINTN)(ImageContext->ImageSize + ImageContext->SectionAlignment));
+ }
+ break;
+ }
+ SectionHeaderOffset += sizeof (EFI_IMAGE_SECTION_HEADER);
+ }
+ DEBUG ((EFI_D_INFO|EFI_D_LOAD, "LOADING MODULE FIXED INFO: Loading module at fixed address 0x%11p. Status = %r \n", (VOID *)(UINTN)(ImageContext->ImageAddress), Status));
+ return Status;
+}
+
+/**
+ Decides whether a PE/COFF image can execute on this system, either natively
+ or via emulation/interpretation. In the latter case, the PeCoffEmu member
+ of the LOADED_IMAGE_PRIVATE_DATA struct pointer is populated with a pointer
+ to the emulator protocol that supports this image.
+
+ @param[in, out] Image LOADED_IMAGE_PRIVATE_DATA struct pointer
+
+ @retval TRUE The image is supported
+ @retval FALSE The image is not supported
+
+**/
+STATIC
+BOOLEAN
+CoreIsImageTypeSupported (
+ IN OUT LOADED_IMAGE_PRIVATE_DATA *Image
+ )
+{
+ LIST_ENTRY *Link;
+ EMULATOR_ENTRY *Entry;
+
+ for (Link = GetFirstNode (&mAvailableEmulators);
+ !IsNull (&mAvailableEmulators, Link);
+ Link = GetNextNode (&mAvailableEmulators, Link)) {
+
+ Entry = BASE_CR (Link, EMULATOR_ENTRY, Link);
+ if (Entry->MachineType != Image->ImageContext.Machine) {
+ continue;
+ }
+
+ if (Entry->Emulator->IsImageSupported (Entry->Emulator,
+ Image->ImageContext.ImageType,
+ Image->Info.FilePath)) {
+ Image->PeCoffEmu = Entry->Emulator;
+ return TRUE;
+ }
+ }
+
+ return EFI_IMAGE_MACHINE_TYPE_SUPPORTED (Image->ImageContext.Machine) ||
+ EFI_IMAGE_MACHINE_CROSS_TYPE_SUPPORTED (Image->ImageContext.Machine);
+}
+
+/**
+ Loads, relocates, and invokes a PE/COFF image
+
+ @param BootPolicy If TRUE, indicates that the request originates
+ from the boot manager, and that the boot
+ manager is attempting to load FilePath as a
+ boot selection.
+ @param Pe32Handle The handle of PE32 image
+ @param Image PE image to be loaded
+ @param DstBuffer The buffer to store the image
+ @param EntryPoint A pointer to the entry point
+ @param Attribute The bit mask of attributes to set for the load
+ PE image
+
+ @retval EFI_SUCCESS The file was loaded, relocated, and invoked
+ @retval EFI_OUT_OF_RESOURCES There was not enough memory to load and
+ relocate the PE/COFF file
+ @retval EFI_INVALID_PARAMETER Invalid parameter
+ @retval EFI_BUFFER_TOO_SMALL Buffer for image is too small
+
+**/
+EFI_STATUS
+CoreLoadPeImage (
+ IN BOOLEAN BootPolicy,
+ IN VOID *Pe32Handle,
+ IN LOADED_IMAGE_PRIVATE_DATA *Image,
+ IN EFI_PHYSICAL_ADDRESS DstBuffer OPTIONAL,
+ OUT EFI_PHYSICAL_ADDRESS *EntryPoint OPTIONAL,
+ IN UINT32 Attribute
+ )
+{
+ EFI_STATUS Status;
+ BOOLEAN DstBufAlocated;
+ UINTN Size;
+
+ ZeroMem (&Image->ImageContext, sizeof (Image->ImageContext));
+
+ Image->ImageContext.Handle = Pe32Handle;
+ Image->ImageContext.ImageRead = (PE_COFF_LOADER_READ_FILE)CoreReadImageFile;
+
+ //
+ // Get information about the image being loaded
+ //
+ Status = PeCoffLoaderGetImageInfo (&Image->ImageContext);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if (!CoreIsImageTypeSupported (Image)) {
+ //
+ // The PE/COFF loader can support loading image types that can be executed.
+ // If we loaded an image type that we can not execute return EFI_UNSUPPORTED.
+ //
+ DEBUG ((DEBUG_ERROR, "Image type %s can't be loaded on %s UEFI system.\n",
+ GetMachineTypeName (Image->ImageContext.Machine),
+ GetMachineTypeName (mDxeCoreImageMachineType)));
+ return EFI_UNSUPPORTED;
+ }
+
+ //
+ // Set EFI memory type based on ImageType
+ //
+ switch (Image->ImageContext.ImageType) {
+ case EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION:
+ Image->ImageContext.ImageCodeMemoryType = EfiLoaderCode;
+ Image->ImageContext.ImageDataMemoryType = EfiLoaderData;
+ break;
+ case EFI_IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER:
+ Image->ImageContext.ImageCodeMemoryType = EfiBootServicesCode;
+ Image->ImageContext.ImageDataMemoryType = EfiBootServicesData;
+ break;
+ case EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER:
+ case EFI_IMAGE_SUBSYSTEM_SAL_RUNTIME_DRIVER:
+ Image->ImageContext.ImageCodeMemoryType = EfiRuntimeServicesCode;
+ Image->ImageContext.ImageDataMemoryType = EfiRuntimeServicesData;
+ break;
+ default:
+ Image->ImageContext.ImageError = IMAGE_ERROR_INVALID_SUBSYSTEM;
+ return EFI_UNSUPPORTED;
+ }
+
+ //
+ // Allocate memory of the correct memory type aligned on the required image boundary
+ //
+ DstBufAlocated = FALSE;
+ if (DstBuffer == 0) {
+ //
+ // Allocate Destination Buffer as caller did not pass it in
+ //
+
+ if (Image->ImageContext.SectionAlignment > EFI_PAGE_SIZE) {
+ Size = (UINTN)Image->ImageContext.ImageSize + Image->ImageContext.SectionAlignment;
+ } else {
+ Size = (UINTN)Image->ImageContext.ImageSize;
+ }
+
+ Image->NumberOfPages = EFI_SIZE_TO_PAGES (Size);
+
+ //
+ // If the image relocations have not been stripped, then load at any address.
+ // Otherwise load at the address at which it was linked.
+ //
+ // Memory below 1MB should be treated reserved for CSM and there should be
+ // no modules whose preferred load addresses are below 1MB.
+ //
+ Status = EFI_OUT_OF_RESOURCES;
+ //
+ // If Loading Module At Fixed Address feature is enabled, the module should be loaded to
+ // a specified address.
+ //
+ if (PcdGet64(PcdLoadModuleAtFixAddressEnable) != 0 ) {
+ Status = GetPeCoffImageFixLoadingAssignedAddress (&(Image->ImageContext));
+
+ if (EFI_ERROR (Status)) {
+ //
+ // If the code memory is not ready, invoke CoreAllocatePage with AllocateAnyPages to load the driver.
+ //
+ DEBUG ((EFI_D_INFO|EFI_D_LOAD, "LOADING MODULE FIXED ERROR: Loading module at fixed address failed since specified memory is not available.\n"));
+
+ Status = CoreAllocatePages (
+ AllocateAnyPages,
+ (EFI_MEMORY_TYPE) (Image->ImageContext.ImageCodeMemoryType),
+ Image->NumberOfPages,
+ &Image->ImageContext.ImageAddress
+ );
+ }
+ } else {
+ if (Image->ImageContext.ImageAddress >= 0x100000 || Image->ImageContext.RelocationsStripped) {
+ Status = CoreAllocatePages (
+ AllocateAddress,
+ (EFI_MEMORY_TYPE) (Image->ImageContext.ImageCodeMemoryType),
+ Image->NumberOfPages,
+ &Image->ImageContext.ImageAddress
+ );
+ }
+ if (EFI_ERROR (Status) && !Image->ImageContext.RelocationsStripped) {
+ Status = CoreAllocatePages (
+ AllocateAnyPages,
+ (EFI_MEMORY_TYPE) (Image->ImageContext.ImageCodeMemoryType),
+ Image->NumberOfPages,
+ &Image->ImageContext.ImageAddress
+ );
+ }
+ }
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ DstBufAlocated = TRUE;
+ } else {
+ //
+ // Caller provided the destination buffer
+ //
+
+ if (Image->ImageContext.RelocationsStripped && (Image->ImageContext.ImageAddress != DstBuffer)) {
+ //
+ // If the image relocations were stripped, and the caller provided a
+ // destination buffer address that does not match the address that the
+ // image is linked at, then the image cannot be loaded.
+ //
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (Image->NumberOfPages != 0 &&
+ Image->NumberOfPages <
+ (EFI_SIZE_TO_PAGES ((UINTN)Image->ImageContext.ImageSize + Image->ImageContext.SectionAlignment))) {
+ Image->NumberOfPages = EFI_SIZE_TO_PAGES ((UINTN)Image->ImageContext.ImageSize + Image->ImageContext.SectionAlignment);
+ return EFI_BUFFER_TOO_SMALL;
+ }
+
+ Image->NumberOfPages = EFI_SIZE_TO_PAGES ((UINTN)Image->ImageContext.ImageSize + Image->ImageContext.SectionAlignment);
+ Image->ImageContext.ImageAddress = DstBuffer;
+ }
+
+ Image->ImageBasePage = Image->ImageContext.ImageAddress;
+ if (!Image->ImageContext.IsTeImage) {
+ Image->ImageContext.ImageAddress =
+ (Image->ImageContext.ImageAddress + Image->ImageContext.SectionAlignment - 1) &
+ ~((UINTN)Image->ImageContext.SectionAlignment - 1);
+ }
+
+ //
+ // Load the image from the file into the allocated memory
+ //
+ Status = PeCoffLoaderLoadImage (&Image->ImageContext);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ //
+ // If this is a Runtime Driver, then allocate memory for the FixupData that
+ // is used to relocate the image when SetVirtualAddressMap() is called. The
+ // relocation is done by the Runtime AP.
+ //
+ if ((Attribute & EFI_LOAD_PE_IMAGE_ATTRIBUTE_RUNTIME_REGISTRATION) != 0) {
+ if (Image->ImageContext.ImageType == EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER) {
+ Image->ImageContext.FixupData = AllocateRuntimePool ((UINTN)(Image->ImageContext.FixupDataSize));
+ if (Image->ImageContext.FixupData == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Done;
+ }
+ }
+ }
+
+ //
+ // Relocate the image in memory
+ //
+ Status = PeCoffLoaderRelocateImage (&Image->ImageContext);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ //
+ // Flush the Instruction Cache
+ //
+ InvalidateInstructionCacheRange ((VOID *)(UINTN)Image->ImageContext.ImageAddress, (UINTN)Image->ImageContext.ImageSize);
+
+ //
+ // Copy the machine type from the context to the image private data.
+ //
+ Image->Machine = Image->ImageContext.Machine;
+
+ //
+ // Get the image entry point.
+ //
+ Image->EntryPoint = (EFI_IMAGE_ENTRY_POINT)(UINTN)Image->ImageContext.EntryPoint;
+
+ //
+ // Fill in the image information for the Loaded Image Protocol
+ //
+ Image->Type = Image->ImageContext.ImageType;
+ Image->Info.ImageBase = (VOID *)(UINTN)Image->ImageContext.ImageAddress;
+ Image->Info.ImageSize = Image->ImageContext.ImageSize;
+ Image->Info.ImageCodeType = (EFI_MEMORY_TYPE) (Image->ImageContext.ImageCodeMemoryType);
+ Image->Info.ImageDataType = (EFI_MEMORY_TYPE) (Image->ImageContext.ImageDataMemoryType);
+ if ((Attribute & EFI_LOAD_PE_IMAGE_ATTRIBUTE_RUNTIME_REGISTRATION) != 0) {
+ if (Image->ImageContext.ImageType == EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER) {
+ //
+ // Make a list off all the RT images so we can let the RT AP know about them.
+ //
+ Image->RuntimeData = AllocateRuntimePool (sizeof(EFI_RUNTIME_IMAGE_ENTRY));
+ if (Image->RuntimeData == NULL) {
+ goto Done;
+ }
+ Image->RuntimeData->ImageBase = Image->Info.ImageBase;
+ Image->RuntimeData->ImageSize = (UINT64) (Image->Info.ImageSize);
+ Image->RuntimeData->RelocationData = Image->ImageContext.FixupData;
+ Image->RuntimeData->Handle = Image->Handle;
+ InsertTailList (&gRuntime->ImageHead, &Image->RuntimeData->Link);
+ InsertImageRecord (Image->RuntimeData);
+ }
+ }
+
+ //
+ // Fill in the entry point of the image if it is available
+ //
+ if (EntryPoint != NULL) {
+ *EntryPoint = Image->ImageContext.EntryPoint;
+ }
+
+ //
+ // Print the load address and the PDB file name if it is available
+ //
+
+ DEBUG_CODE_BEGIN ();
+
+ UINTN Index;
+ UINTN StartIndex;
+ CHAR8 EfiFileName[256];
+
+
+ DEBUG ((DEBUG_INFO | DEBUG_LOAD,
+ "Loading driver at 0x%11p EntryPoint=0x%11p ",
+ (VOID *)(UINTN) Image->ImageContext.ImageAddress,
+ FUNCTION_ENTRY_POINT (Image->ImageContext.EntryPoint)));
+
+
+ //
+ // Print Module Name by Pdb file path.
+ // Windows and Unix style file path are all trimmed correctly.
+ //
+ if (Image->ImageContext.PdbPointer != NULL) {
+ StartIndex = 0;
+ for (Index = 0; Image->ImageContext.PdbPointer[Index] != 0; Index++) {
+ if ((Image->ImageContext.PdbPointer[Index] == '\\') || (Image->ImageContext.PdbPointer[Index] == '/')) {
+ StartIndex = Index + 1;
+ }
+ }
+ //
+ // Copy the PDB file name to our temporary string, and replace .pdb with .efi
+ // The PDB file name is limited in the range of 0~255.
+ // If the length is bigger than 255, trim the redudant characters to avoid overflow in array boundary.
+ //
+ for (Index = 0; Index < sizeof (EfiFileName) - 4; Index++) {
+ EfiFileName[Index] = Image->ImageContext.PdbPointer[Index + StartIndex];
+ if (EfiFileName[Index] == 0) {
+ EfiFileName[Index] = '.';
+ }
+ if (EfiFileName[Index] == '.') {
+ EfiFileName[Index + 1] = 'e';
+ EfiFileName[Index + 2] = 'f';
+ EfiFileName[Index + 3] = 'i';
+ EfiFileName[Index + 4] = 0;
+ break;
+ }
+ }
+
+ if (Index == sizeof (EfiFileName) - 4) {
+ EfiFileName[Index] = 0;
+ }
+ DEBUG ((DEBUG_INFO | DEBUG_LOAD, "%a", EfiFileName)); // &Image->ImageContext.PdbPointer[StartIndex]));
+ }
+ DEBUG ((DEBUG_INFO | DEBUG_LOAD, "\n"));
+
+ DEBUG_CODE_END ();
+
+ return EFI_SUCCESS;
+
+Done:
+
+ //
+ // Free memory.
+ //
+
+ if (DstBufAlocated) {
+ CoreFreePages (Image->ImageContext.ImageAddress, Image->NumberOfPages);
+ Image->ImageContext.ImageAddress = 0;
+ Image->ImageBasePage = 0;
+ }
+
+ if (Image->ImageContext.FixupData != NULL) {
+ CoreFreePool (Image->ImageContext.FixupData);
+ }
+
+ return Status;
+}
+
+
+
+/**
+ Get the image's private data from its handle.
+
+ @param ImageHandle The image handle
+
+ @return Return the image private data associated with ImageHandle.
+
+**/
+LOADED_IMAGE_PRIVATE_DATA *
+CoreLoadedImageInfo (
+ IN EFI_HANDLE ImageHandle
+ )
+{
+ EFI_STATUS Status;
+ EFI_LOADED_IMAGE_PROTOCOL *LoadedImage;
+ LOADED_IMAGE_PRIVATE_DATA *Image;
+
+ Status = CoreHandleProtocol (
+ ImageHandle,
+ &gEfiLoadedImageProtocolGuid,
+ (VOID **)&LoadedImage
+ );
+ if (!EFI_ERROR (Status)) {
+ Image = LOADED_IMAGE_PRIVATE_DATA_FROM_THIS (LoadedImage);
+ } else {
+ DEBUG ((DEBUG_LOAD, "CoreLoadedImageInfo: Not an ImageHandle %p\n", ImageHandle));
+ Image = NULL;
+ }
+
+ return Image;
+}
+
+
+/**
+ Unloads EFI image from memory.
+
+ @param Image EFI image
+ @param FreePage Free allocated pages
+
+**/
+VOID
+CoreUnloadAndCloseImage (
+ IN LOADED_IMAGE_PRIVATE_DATA *Image,
+ IN BOOLEAN FreePage
+ )
+{
+ EFI_STATUS Status;
+ UINTN HandleCount;
+ EFI_HANDLE *HandleBuffer;
+ UINTN HandleIndex;
+ EFI_GUID **ProtocolGuidArray;
+ UINTN ArrayCount;
+ UINTN ProtocolIndex;
+ EFI_OPEN_PROTOCOL_INFORMATION_ENTRY *OpenInfo;
+ UINTN OpenInfoCount;
+ UINTN OpenInfoIndex;
+
+ HandleBuffer = NULL;
+ ProtocolGuidArray = NULL;
+
+ if (Image->Started) {
+ UnregisterMemoryProfileImage (Image);
+ }
+
+ UnprotectUefiImage (&Image->Info, Image->LoadedImageDevicePath);
+
+ if (Image->PeCoffEmu != NULL) {
+ //
+ // If the PE/COFF Emulator protocol exists we must unregister the image.
+ //
+ Image->PeCoffEmu->UnregisterImage (Image->PeCoffEmu, Image->ImageBasePage);
+ }
+
+ //
+ // Unload image, free Image->ImageContext->ModHandle
+ //
+ PeCoffLoaderUnloadImage (&Image->ImageContext);
+
+ //
+ // Free our references to the image handle
+ //
+ if (Image->Handle != NULL) {
+
+ Status = CoreLocateHandleBuffer (
+ AllHandles,
+ NULL,
+ NULL,
+ &HandleCount,
+ &HandleBuffer
+ );
+ if (!EFI_ERROR (Status)) {
+ for (HandleIndex = 0; HandleIndex < HandleCount; HandleIndex++) {
+ Status = CoreProtocolsPerHandle (
+ HandleBuffer[HandleIndex],
+ &ProtocolGuidArray,
+ &ArrayCount
+ );
+ if (!EFI_ERROR (Status)) {
+ for (ProtocolIndex = 0; ProtocolIndex < ArrayCount; ProtocolIndex++) {
+ Status = CoreOpenProtocolInformation (
+ HandleBuffer[HandleIndex],
+ ProtocolGuidArray[ProtocolIndex],
+ &OpenInfo,
+ &OpenInfoCount
+ );
+ if (!EFI_ERROR (Status)) {
+ for (OpenInfoIndex = 0; OpenInfoIndex < OpenInfoCount; OpenInfoIndex++) {
+ if (OpenInfo[OpenInfoIndex].AgentHandle == Image->Handle) {
+ Status = CoreCloseProtocol (
+ HandleBuffer[HandleIndex],
+ ProtocolGuidArray[ProtocolIndex],
+ Image->Handle,
+ OpenInfo[OpenInfoIndex].ControllerHandle
+ );
+ }
+ }
+ if (OpenInfo != NULL) {
+ CoreFreePool(OpenInfo);
+ }
+ }
+ }
+ if (ProtocolGuidArray != NULL) {
+ CoreFreePool(ProtocolGuidArray);
+ }
+ }
+ }
+ if (HandleBuffer != NULL) {
+ CoreFreePool (HandleBuffer);
+ }
+ }
+
+ CoreRemoveDebugImageInfoEntry (Image->Handle);
+
+ Status = CoreUninstallProtocolInterface (
+ Image->Handle,
+ &gEfiLoadedImageDevicePathProtocolGuid,
+ Image->LoadedImageDevicePath
+ );
+
+ Status = CoreUninstallProtocolInterface (
+ Image->Handle,
+ &gEfiLoadedImageProtocolGuid,
+ &Image->Info
+ );
+
+ if (Image->ImageContext.HiiResourceData != 0) {
+ Status = CoreUninstallProtocolInterface (
+ Image->Handle,
+ &gEfiHiiPackageListProtocolGuid,
+ (VOID *) (UINTN) Image->ImageContext.HiiResourceData
+ );
+ }
+
+ }
+
+ if (Image->RuntimeData != NULL) {
+ if (Image->RuntimeData->Link.ForwardLink != NULL) {
+ //
+ // Remove the Image from the Runtime Image list as we are about to Free it!
+ //
+ RemoveEntryList (&Image->RuntimeData->Link);
+ RemoveImageRecord (Image->RuntimeData);
+ }
+ CoreFreePool (Image->RuntimeData);
+ }
+
+ //
+ // Free the Image from memory
+ //
+ if ((Image->ImageBasePage != 0) && FreePage) {
+ CoreFreePages (Image->ImageBasePage, Image->NumberOfPages);
+ }
+
+ //
+ // Done with the Image structure
+ //
+ if (Image->Info.FilePath != NULL) {
+ CoreFreePool (Image->Info.FilePath);
+ }
+
+ if (Image->LoadedImageDevicePath != NULL) {
+ CoreFreePool (Image->LoadedImageDevicePath);
+ }
+
+ if (Image->FixupData != NULL) {
+ CoreFreePool (Image->FixupData);
+ }
+
+ CoreFreePool (Image);
+}
+
+
+/**
+ Loads an EFI image into memory and returns a handle to the image.
+
+ @param BootPolicy If TRUE, indicates that the request originates
+ from the boot manager, and that the boot
+ manager is attempting to load FilePath as a
+ boot selection.
+ @param ParentImageHandle The caller's image handle.
+ @param FilePath The specific file path from which the image is
+ loaded.
+ @param SourceBuffer If not NULL, a pointer to the memory location
+ containing a copy of the image to be loaded.
+ @param SourceSize The size in bytes of SourceBuffer.
+ @param DstBuffer The buffer to store the image
+ @param NumberOfPages If not NULL, it inputs a pointer to the page
+ number of DstBuffer and outputs a pointer to
+ the page number of the image. If this number is
+ not enough, return EFI_BUFFER_TOO_SMALL and
+ this parameter contains the required number.
+ @param ImageHandle Pointer to the returned image handle that is
+ created when the image is successfully loaded.
+ @param EntryPoint A pointer to the entry point
+ @param Attribute The bit mask of attributes to set for the load
+ PE image
+
+ @retval EFI_SUCCESS The image was loaded into memory.
+ @retval EFI_NOT_FOUND The FilePath was not found.
+ @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
+ @retval EFI_BUFFER_TOO_SMALL The buffer is too small
+ @retval EFI_UNSUPPORTED The image type is not supported, or the device
+ path cannot be parsed to locate the proper
+ protocol for loading the file.
+ @retval EFI_OUT_OF_RESOURCES Image was not loaded due to insufficient
+ resources.
+ @retval EFI_LOAD_ERROR Image was not loaded because the image format was corrupt or not
+ understood.
+ @retval EFI_DEVICE_ERROR Image was not loaded because the device returned a read error.
+ @retval EFI_ACCESS_DENIED Image was not loaded because the platform policy prohibits the
+ image from being loaded. NULL is returned in *ImageHandle.
+ @retval EFI_SECURITY_VIOLATION Image was loaded and an ImageHandle was created with a
+ valid EFI_LOADED_IMAGE_PROTOCOL. However, the current
+ platform policy specifies that the image should not be started.
+
+**/
+EFI_STATUS
+CoreLoadImageCommon (
+ IN BOOLEAN BootPolicy,
+ IN EFI_HANDLE ParentImageHandle,
+ IN EFI_DEVICE_PATH_PROTOCOL *FilePath,
+ IN VOID *SourceBuffer OPTIONAL,
+ IN UINTN SourceSize,
+ IN EFI_PHYSICAL_ADDRESS DstBuffer OPTIONAL,
+ IN OUT UINTN *NumberOfPages OPTIONAL,
+ OUT EFI_HANDLE *ImageHandle,
+ OUT EFI_PHYSICAL_ADDRESS *EntryPoint OPTIONAL,
+ IN UINT32 Attribute
+ )
+{
+ LOADED_IMAGE_PRIVATE_DATA *Image;
+ LOADED_IMAGE_PRIVATE_DATA *ParentImage;
+ IMAGE_FILE_HANDLE FHand;
+ EFI_STATUS Status;
+ EFI_STATUS SecurityStatus;
+ EFI_HANDLE DeviceHandle;
+ UINT32 AuthenticationStatus;
+ EFI_DEVICE_PATH_PROTOCOL *OriginalFilePath;
+ EFI_DEVICE_PATH_PROTOCOL *HandleFilePath;
+ EFI_DEVICE_PATH_PROTOCOL *InputFilePath;
+ EFI_DEVICE_PATH_PROTOCOL *Node;
+ UINTN FilePathSize;
+ BOOLEAN ImageIsFromFv;
+ BOOLEAN ImageIsFromLoadFile;
+
+ SecurityStatus = EFI_SUCCESS;
+
+ ASSERT (gEfiCurrentTpl < TPL_NOTIFY);
+ ParentImage = NULL;
+
+ //
+ // The caller must pass in a valid ParentImageHandle
+ //
+ if (ImageHandle == NULL || ParentImageHandle == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ ParentImage = CoreLoadedImageInfo (ParentImageHandle);
+ if (ParentImage == NULL) {
+ DEBUG((DEBUG_LOAD|DEBUG_ERROR, "LoadImageEx: Parent handle not an image handle\n"));
+ return EFI_INVALID_PARAMETER;
+ }
+
+ ZeroMem (&FHand, sizeof (IMAGE_FILE_HANDLE));
+ FHand.Signature = IMAGE_FILE_HANDLE_SIGNATURE;
+ OriginalFilePath = FilePath;
+ InputFilePath = FilePath;
+ HandleFilePath = FilePath;
+ DeviceHandle = NULL;
+ Status = EFI_SUCCESS;
+ AuthenticationStatus = 0;
+ ImageIsFromFv = FALSE;
+ ImageIsFromLoadFile = FALSE;
+
+ //
+ // If the caller passed a copy of the file, then just use it
+ //
+ if (SourceBuffer != NULL) {
+ FHand.Source = SourceBuffer;
+ FHand.SourceSize = SourceSize;
+ Status = CoreLocateDevicePath (&gEfiDevicePathProtocolGuid, &HandleFilePath, &DeviceHandle);
+ if (EFI_ERROR (Status)) {
+ DeviceHandle = NULL;
+ }
+ if (SourceSize > 0) {
+ Status = EFI_SUCCESS;
+ } else {
+ Status = EFI_LOAD_ERROR;
+ }
+ } else {
+ if (FilePath == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Try to get the image device handle by checking the match protocol.
+ //
+ Node = NULL;
+ Status = CoreLocateDevicePath (&gEfiFirmwareVolume2ProtocolGuid, &HandleFilePath, &DeviceHandle);
+ if (!EFI_ERROR (Status)) {
+ ImageIsFromFv = TRUE;
+ } else {
+ HandleFilePath = FilePath;
+ Status = CoreLocateDevicePath (&gEfiSimpleFileSystemProtocolGuid, &HandleFilePath, &DeviceHandle);
+ if (EFI_ERROR (Status)) {
+ if (!BootPolicy) {
+ HandleFilePath = FilePath;
+ Status = CoreLocateDevicePath (&gEfiLoadFile2ProtocolGuid, &HandleFilePath, &DeviceHandle);
+ }
+ if (EFI_ERROR (Status)) {
+ HandleFilePath = FilePath;
+ Status = CoreLocateDevicePath (&gEfiLoadFileProtocolGuid, &HandleFilePath, &DeviceHandle);
+ if (!EFI_ERROR (Status)) {
+ ImageIsFromLoadFile = TRUE;
+ Node = HandleFilePath;
+ }
+ }
+ }
+ }
+
+ //
+ // Get the source file buffer by its device path.
+ //
+ FHand.Source = GetFileBufferByFilePath (
+ BootPolicy,
+ FilePath,
+ &FHand.SourceSize,
+ &AuthenticationStatus
+ );
+ if (FHand.Source == NULL) {
+ Status = EFI_NOT_FOUND;
+ } else {
+ FHand.FreeBuffer = TRUE;
+ if (ImageIsFromLoadFile) {
+ //
+ // LoadFile () may cause the device path of the Handle be updated.
+ //
+ OriginalFilePath = AppendDevicePath (DevicePathFromHandle (DeviceHandle), Node);
+ }
+ }
+ }
+
+ if (EFI_ERROR (Status)) {
+ Image = NULL;
+ goto Done;
+ }
+
+ if (gSecurity2 != NULL) {
+ //
+ // Verify File Authentication through the Security2 Architectural Protocol
+ //
+ SecurityStatus = gSecurity2->FileAuthentication (
+ gSecurity2,
+ OriginalFilePath,
+ FHand.Source,
+ FHand.SourceSize,
+ BootPolicy
+ );
+ if (!EFI_ERROR (SecurityStatus) && ImageIsFromFv) {
+ //
+ // When Security2 is installed, Security Architectural Protocol must be published.
+ //
+ ASSERT (gSecurity != NULL);
+
+ //
+ // Verify the Authentication Status through the Security Architectural Protocol
+ // Only on images that have been read using Firmware Volume protocol.
+ //
+ SecurityStatus = gSecurity->FileAuthenticationState (
+ gSecurity,
+ AuthenticationStatus,
+ OriginalFilePath
+ );
+ }
+ } else if ((gSecurity != NULL) && (OriginalFilePath != NULL)) {
+ //
+ // Verify the Authentication Status through the Security Architectural Protocol
+ //
+ SecurityStatus = gSecurity->FileAuthenticationState (
+ gSecurity,
+ AuthenticationStatus,
+ OriginalFilePath
+ );
+ }
+
+ //
+ // Check Security Status.
+ //
+ if (EFI_ERROR (SecurityStatus) && SecurityStatus != EFI_SECURITY_VIOLATION) {
+ if (SecurityStatus == EFI_ACCESS_DENIED) {
+ //
+ // Image was not loaded because the platform policy prohibits the image from being loaded.
+ // It's the only place we could meet EFI_ACCESS_DENIED.
+ //
+ *ImageHandle = NULL;
+ }
+ Status = SecurityStatus;
+ Image = NULL;
+ goto Done;
+ }
+
+ //
+ // Allocate a new image structure
+ //
+ Image = AllocateZeroPool (sizeof(LOADED_IMAGE_PRIVATE_DATA));
+ if (Image == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Done;
+ }
+
+ //
+ // Pull out just the file portion of the DevicePath for the LoadedImage FilePath
+ //
+ FilePath = OriginalFilePath;
+ if (DeviceHandle != NULL) {
+ Status = CoreHandleProtocol (DeviceHandle, &gEfiDevicePathProtocolGuid, (VOID **)&HandleFilePath);
+ if (!EFI_ERROR (Status)) {
+ FilePathSize = GetDevicePathSize (HandleFilePath) - sizeof(EFI_DEVICE_PATH_PROTOCOL);
+ FilePath = (EFI_DEVICE_PATH_PROTOCOL *) (((UINT8 *)FilePath) + FilePathSize );
+ }
+ }
+ //
+ // Initialize the fields for an internal driver
+ //
+ Image->Signature = LOADED_IMAGE_PRIVATE_DATA_SIGNATURE;
+ Image->Info.SystemTable = gDxeCoreST;
+ Image->Info.DeviceHandle = DeviceHandle;
+ Image->Info.Revision = EFI_LOADED_IMAGE_PROTOCOL_REVISION;
+ Image->Info.FilePath = DuplicateDevicePath (FilePath);
+ Image->Info.ParentHandle = ParentImageHandle;
+
+
+ if (NumberOfPages != NULL) {
+ Image->NumberOfPages = *NumberOfPages ;
+ } else {
+ Image->NumberOfPages = 0 ;
+ }
+
+ //
+ // Install the protocol interfaces for this image
+ // don't fire notifications yet
+ //
+ Status = CoreInstallProtocolInterfaceNotify (
+ &Image->Handle,
+ &gEfiLoadedImageProtocolGuid,
+ EFI_NATIVE_INTERFACE,
+ &Image->Info,
+ FALSE
+ );
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ //
+ // Load the image. If EntryPoint is Null, it will not be set.
+ //
+ Status = CoreLoadPeImage (BootPolicy, &FHand, Image, DstBuffer, EntryPoint, Attribute);
+ if (EFI_ERROR (Status)) {
+ if ((Status == EFI_BUFFER_TOO_SMALL) || (Status == EFI_OUT_OF_RESOURCES)) {
+ if (NumberOfPages != NULL) {
+ *NumberOfPages = Image->NumberOfPages;
+ }
+ }
+ goto Done;
+ }
+
+ if (NumberOfPages != NULL) {
+ *NumberOfPages = Image->NumberOfPages;
+ }
+
+ //
+ // Register the image in the Debug Image Info Table if the attribute is set
+ //
+ if ((Attribute & EFI_LOAD_PE_IMAGE_ATTRIBUTE_DEBUG_IMAGE_INFO_TABLE_REGISTRATION) != 0) {
+ CoreNewDebugImageInfoEntry (EFI_DEBUG_IMAGE_INFO_TYPE_NORMAL, &Image->Info, Image->Handle);
+ }
+
+ //
+ //Reinstall loaded image protocol to fire any notifications
+ //
+ Status = CoreReinstallProtocolInterface (
+ Image->Handle,
+ &gEfiLoadedImageProtocolGuid,
+ &Image->Info,
+ &Image->Info
+ );
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ //
+ // If DevicePath parameter to the LoadImage() is not NULL, then make a copy of DevicePath,
+ // otherwise Loaded Image Device Path Protocol is installed with a NULL interface pointer.
+ //
+ if (OriginalFilePath != NULL) {
+ Image->LoadedImageDevicePath = DuplicateDevicePath (OriginalFilePath);
+ }
+
+ //
+ // Install Loaded Image Device Path Protocol onto the image handle of a PE/COFE image
+ //
+ Status = CoreInstallProtocolInterface (
+ &Image->Handle,
+ &gEfiLoadedImageDevicePathProtocolGuid,
+ EFI_NATIVE_INTERFACE,
+ Image->LoadedImageDevicePath
+ );
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ //
+ // Install HII Package List Protocol onto the image handle
+ //
+ if (Image->ImageContext.HiiResourceData != 0) {
+ Status = CoreInstallProtocolInterface (
+ &Image->Handle,
+ &gEfiHiiPackageListProtocolGuid,
+ EFI_NATIVE_INTERFACE,
+ (VOID *) (UINTN) Image->ImageContext.HiiResourceData
+ );
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+ }
+ ProtectUefiImage (&Image->Info, Image->LoadedImageDevicePath);
+
+ //
+ // Success. Return the image handle
+ //
+ *ImageHandle = Image->Handle;
+
+Done:
+ //
+ // All done accessing the source file
+ // If we allocated the Source buffer, free it
+ //
+ if (FHand.FreeBuffer) {
+ CoreFreePool (FHand.Source);
+ }
+ if (OriginalFilePath != InputFilePath) {
+ CoreFreePool (OriginalFilePath);
+ }
+
+ //
+ // There was an error. If there's an Image structure, free it
+ //
+ if (EFI_ERROR (Status)) {
+ if (Image != NULL) {
+ CoreUnloadAndCloseImage (Image, (BOOLEAN)(DstBuffer == 0));
+ Image = NULL;
+ }
+ } else if (EFI_ERROR (SecurityStatus)) {
+ Status = SecurityStatus;
+ }
+
+ //
+ // Track the return status from LoadImage.
+ //
+ if (Image != NULL) {
+ Image->LoadImageStatus = Status;
+ }
+
+ return Status;
+}
+
+
+
+
+/**
+ Loads an EFI image into memory and returns a handle to the image.
+
+ @param BootPolicy If TRUE, indicates that the request originates
+ from the boot manager, and that the boot
+ manager is attempting to load FilePath as a
+ boot selection.
+ @param ParentImageHandle The caller's image handle.
+ @param FilePath The specific file path from which the image is
+ loaded.
+ @param SourceBuffer If not NULL, a pointer to the memory location
+ containing a copy of the image to be loaded.
+ @param SourceSize The size in bytes of SourceBuffer.
+ @param ImageHandle Pointer to the returned image handle that is
+ created when the image is successfully loaded.
+
+ @retval EFI_SUCCESS The image was loaded into memory.
+ @retval EFI_NOT_FOUND The FilePath was not found.
+ @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
+ @retval EFI_UNSUPPORTED The image type is not supported, or the device
+ path cannot be parsed to locate the proper
+ protocol for loading the file.
+ @retval EFI_OUT_OF_RESOURCES Image was not loaded due to insufficient
+ resources.
+ @retval EFI_LOAD_ERROR Image was not loaded because the image format was corrupt or not
+ understood.
+ @retval EFI_DEVICE_ERROR Image was not loaded because the device returned a read error.
+ @retval EFI_ACCESS_DENIED Image was not loaded because the platform policy prohibits the
+ image from being loaded. NULL is returned in *ImageHandle.
+ @retval EFI_SECURITY_VIOLATION Image was loaded and an ImageHandle was created with a
+ valid EFI_LOADED_IMAGE_PROTOCOL. However, the current
+ platform policy specifies that the image should not be started.
+
+**/
+EFI_STATUS
+EFIAPI
+CoreLoadImage (
+ IN BOOLEAN BootPolicy,
+ IN EFI_HANDLE ParentImageHandle,
+ IN EFI_DEVICE_PATH_PROTOCOL *FilePath,
+ IN VOID *SourceBuffer OPTIONAL,
+ IN UINTN SourceSize,
+ OUT EFI_HANDLE *ImageHandle
+ )
+{
+ EFI_STATUS Status;
+ EFI_HANDLE Handle;
+
+ PERF_LOAD_IMAGE_BEGIN (NULL);
+
+ Status = CoreLoadImageCommon (
+ BootPolicy,
+ ParentImageHandle,
+ FilePath,
+ SourceBuffer,
+ SourceSize,
+ (EFI_PHYSICAL_ADDRESS) (UINTN) NULL,
+ NULL,
+ ImageHandle,
+ NULL,
+ EFI_LOAD_PE_IMAGE_ATTRIBUTE_RUNTIME_REGISTRATION | EFI_LOAD_PE_IMAGE_ATTRIBUTE_DEBUG_IMAGE_INFO_TABLE_REGISTRATION
+ );
+
+ Handle = NULL;
+ if (!EFI_ERROR (Status)) {
+ //
+ // ImageHandle will be valid only Status is success.
+ //
+ Handle = *ImageHandle;
+ }
+
+ PERF_LOAD_IMAGE_END (Handle);
+
+ return Status;
+}
+
+/**
+ Transfer control to a loaded image's entry point.
+
+ @param ImageHandle Handle of image to be started.
+ @param ExitDataSize Pointer of the size to ExitData
+ @param ExitData Pointer to a pointer to a data buffer that
+ includes a Null-terminated string,
+ optionally followed by additional binary data.
+ The string is a description that the caller may
+ use to further indicate the reason for the
+ image's exit.
+
+ @retval EFI_INVALID_PARAMETER Invalid parameter
+ @retval EFI_OUT_OF_RESOURCES No enough buffer to allocate
+ @retval EFI_SECURITY_VIOLATION The current platform policy specifies that the image should not be started.
+ @retval EFI_SUCCESS Successfully transfer control to the image's
+ entry point.
+
+**/
+EFI_STATUS
+EFIAPI
+CoreStartImage (
+ IN EFI_HANDLE ImageHandle,
+ OUT UINTN *ExitDataSize,
+ OUT CHAR16 **ExitData OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+ LOADED_IMAGE_PRIVATE_DATA *Image;
+ LOADED_IMAGE_PRIVATE_DATA *LastImage;
+ UINT64 HandleDatabaseKey;
+ UINTN SetJumpFlag;
+ EFI_HANDLE Handle;
+
+ Handle = ImageHandle;
+
+ Image = CoreLoadedImageInfo (ImageHandle);
+ if (Image == NULL || Image->Started) {
+ return EFI_INVALID_PARAMETER;
+ }
+ if (EFI_ERROR (Image->LoadImageStatus)) {
+ return Image->LoadImageStatus;
+ }
+
+ //
+ // The image to be started must have the machine type supported by DxeCore.
+ //
+ if (!EFI_IMAGE_MACHINE_TYPE_SUPPORTED (Image->Machine) &&
+ Image->PeCoffEmu == NULL) {
+ //
+ // Do not ASSERT here, because image might be loaded via EFI_IMAGE_MACHINE_CROSS_TYPE_SUPPORTED
+ // But it can not be started.
+ //
+ DEBUG ((EFI_D_ERROR, "Image type %s can't be started ", GetMachineTypeName(Image->Machine)));
+ DEBUG ((EFI_D_ERROR, "on %s UEFI system.\n", GetMachineTypeName(mDxeCoreImageMachineType)));
+ return EFI_UNSUPPORTED;
+ }
+
+ if (Image->PeCoffEmu != NULL) {
+ Status = Image->PeCoffEmu->RegisterImage (Image->PeCoffEmu,
+ Image->ImageBasePage,
+ EFI_PAGES_TO_SIZE (Image->NumberOfPages),
+ &Image->EntryPoint);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_LOAD | DEBUG_ERROR,
+ "CoreLoadPeImage: Failed to register foreign image with emulator - %r\n",
+ Status));
+ return Status;
+ }
+ }
+
+ PERF_START_IMAGE_BEGIN (Handle);
+
+
+ //
+ // Push the current start image context, and
+ // link the current image to the head. This is the
+ // only image that can call Exit()
+ //
+ HandleDatabaseKey = CoreGetHandleDatabaseKey ();
+ LastImage = mCurrentImage;
+ mCurrentImage = Image;
+ Image->Tpl = gEfiCurrentTpl;
+
+ //
+ // Set long jump for Exit() support
+ // JumpContext must be aligned on a CPU specific boundary.
+ // Overallocate the buffer and force the required alignment
+ //
+ Image->JumpBuffer = AllocatePool (sizeof (BASE_LIBRARY_JUMP_BUFFER) + BASE_LIBRARY_JUMP_BUFFER_ALIGNMENT);
+ if (Image->JumpBuffer == NULL) {
+ //
+ // Image may be unloaded after return with failure,
+ // then ImageHandle may be invalid, so use NULL handle to record perf log.
+ //
+ PERF_START_IMAGE_END (NULL);
+
+ //
+ // Pop the current start image context
+ //
+ mCurrentImage = LastImage;
+
+ return EFI_OUT_OF_RESOURCES;
+ }
+ Image->JumpContext = ALIGN_POINTER (Image->JumpBuffer, BASE_LIBRARY_JUMP_BUFFER_ALIGNMENT);
+
+ SetJumpFlag = SetJump (Image->JumpContext);
+ //
+ // The initial call to SetJump() must always return 0.
+ // Subsequent calls to LongJump() cause a non-zero value to be returned by SetJump().
+ //
+ if (SetJumpFlag == 0) {
+ RegisterMemoryProfileImage (Image, (Image->ImageContext.ImageType == EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION ? EFI_FV_FILETYPE_APPLICATION : EFI_FV_FILETYPE_DRIVER));
+ //
+ // Call the image's entry point
+ //
+ Image->Started = TRUE;
+ Image->Status = Image->EntryPoint (ImageHandle, Image->Info.SystemTable);
+
+ //
+ // Add some debug information if the image returned with error.
+ // This make the user aware and check if the driver image have already released
+ // all the resource in this situation.
+ //
+ DEBUG_CODE_BEGIN ();
+ if (EFI_ERROR (Image->Status)) {
+ DEBUG ((DEBUG_ERROR, "Error: Image at %11p start failed: %r\n", Image->Info.ImageBase, Image->Status));
+ }
+ DEBUG_CODE_END ();
+
+ //
+ // If the image returns, exit it through Exit()
+ //
+ CoreExit (ImageHandle, Image->Status, 0, NULL);
+ }
+
+ //
+ // Image has completed. Verify the tpl is the same
+ //
+ ASSERT (Image->Tpl == gEfiCurrentTpl);
+ CoreRestoreTpl (Image->Tpl);
+
+ CoreFreePool (Image->JumpBuffer);
+
+ //
+ // Pop the current start image context
+ //
+ mCurrentImage = LastImage;
+
+ //
+ // UEFI Specification - StartImage() - EFI 1.10 Extension
+ // To maintain compatibility with UEFI drivers that are written to the EFI
+ // 1.02 Specification, StartImage() must monitor the handle database before
+ // and after each image is started. If any handles are created or modified
+ // when an image is started, then EFI_BOOT_SERVICES.ConnectController() must
+ // be called with the Recursive parameter set to TRUE for each of the newly
+ // created or modified handles before StartImage() returns.
+ //
+ if (Image->Type != EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION) {
+ CoreConnectHandlesByKey (HandleDatabaseKey);
+ }
+
+ //
+ // Handle the image's returned ExitData
+ //
+ DEBUG_CODE_BEGIN ();
+ if (Image->ExitDataSize != 0 || Image->ExitData != NULL) {
+
+ DEBUG ((DEBUG_LOAD, "StartImage: ExitDataSize %d, ExitData %p", (UINT32)Image->ExitDataSize, Image->ExitData));
+ if (Image->ExitData != NULL) {
+ DEBUG ((DEBUG_LOAD, " (%hs)", Image->ExitData));
+ }
+ DEBUG ((DEBUG_LOAD, "\n"));
+ }
+ DEBUG_CODE_END ();
+
+ //
+ // Return the exit data to the caller
+ //
+ if (ExitData != NULL && ExitDataSize != NULL) {
+ *ExitDataSize = Image->ExitDataSize;
+ *ExitData = Image->ExitData;
+ } else {
+ //
+ // Caller doesn't want the exit data, free it
+ //
+ CoreFreePool (Image->ExitData);
+ Image->ExitData = NULL;
+ }
+
+ //
+ // Save the Status because Image will get destroyed if it is unloaded.
+ //
+ Status = Image->Status;
+
+ //
+ // If the image returned an error, or if the image is an application
+ // unload it
+ //
+ if (EFI_ERROR (Image->Status) || Image->Type == EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION) {
+ CoreUnloadAndCloseImage (Image, TRUE);
+ //
+ // ImageHandle may be invalid after the image is unloaded, so use NULL handle to record perf log.
+ //
+ Handle = NULL;
+ }
+
+ //
+ // Done
+ //
+ PERF_START_IMAGE_END (Handle);
+ return Status;
+}
+
+/**
+ Terminates the currently loaded EFI image and returns control to boot services.
+
+ @param ImageHandle Handle that identifies the image. This
+ parameter is passed to the image on entry.
+ @param Status The image's exit code.
+ @param ExitDataSize The size, in bytes, of ExitData. Ignored if
+ ExitStatus is EFI_SUCCESS.
+ @param ExitData Pointer to a data buffer that includes a
+ Null-terminated Unicode string, optionally
+ followed by additional binary data. The string
+ is a description that the caller may use to
+ further indicate the reason for the image's
+ exit.
+
+ @retval EFI_INVALID_PARAMETER Image handle is NULL or it is not current
+ image.
+ @retval EFI_SUCCESS Successfully terminates the currently loaded
+ EFI image.
+ @retval EFI_ACCESS_DENIED Should never reach there.
+ @retval EFI_OUT_OF_RESOURCES Could not allocate pool
+
+**/
+EFI_STATUS
+EFIAPI
+CoreExit (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_STATUS Status,
+ IN UINTN ExitDataSize,
+ IN CHAR16 *ExitData OPTIONAL
+ )
+{
+ LOADED_IMAGE_PRIVATE_DATA *Image;
+ EFI_TPL OldTpl;
+
+ //
+ // Prevent possible reentrance to this function
+ // for the same ImageHandle
+ //
+ OldTpl = CoreRaiseTpl (TPL_NOTIFY);
+
+ Image = CoreLoadedImageInfo (ImageHandle);
+ if (Image == NULL) {
+ Status = EFI_INVALID_PARAMETER;
+ goto Done;
+ }
+
+ if (!Image->Started) {
+ //
+ // The image has not been started so just free its resources
+ //
+ CoreUnloadAndCloseImage (Image, TRUE);
+ Status = EFI_SUCCESS;
+ goto Done;
+ }
+
+ //
+ // Image has been started, verify this image can exit
+ //
+ if (Image != mCurrentImage) {
+ DEBUG ((DEBUG_LOAD|DEBUG_ERROR, "Exit: Image is not exitable image\n"));
+ Status = EFI_INVALID_PARAMETER;
+ goto Done;
+ }
+
+ //
+ // Set status
+ //
+ Image->Status = Status;
+
+ //
+ // If there's ExitData info, move it
+ //
+ if (ExitData != NULL) {
+ Image->ExitDataSize = ExitDataSize;
+ Image->ExitData = AllocatePool (Image->ExitDataSize);
+ if (Image->ExitData == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Done;
+ }
+ CopyMem (Image->ExitData, ExitData, Image->ExitDataSize);
+ }
+
+ CoreRestoreTpl (OldTpl);
+ //
+ // return to StartImage
+ //
+ LongJump (Image->JumpContext, (UINTN)-1);
+
+ //
+ // If we return from LongJump, then it is an error
+ //
+ ASSERT (FALSE);
+ Status = EFI_ACCESS_DENIED;
+Done:
+ CoreRestoreTpl (OldTpl);
+ return Status;
+}
+
+
+
+
+/**
+ Unloads an image.
+
+ @param ImageHandle Handle that identifies the image to be
+ unloaded.
+
+ @retval EFI_SUCCESS The image has been unloaded.
+ @retval EFI_UNSUPPORTED The image has been started, and does not support
+ unload.
+ @retval EFI_INVALID_PARAMPETER ImageHandle is not a valid image handle.
+
+**/
+EFI_STATUS
+EFIAPI
+CoreUnloadImage (
+ IN EFI_HANDLE ImageHandle
+ )
+{
+ EFI_STATUS Status;
+ LOADED_IMAGE_PRIVATE_DATA *Image;
+
+ Image = CoreLoadedImageInfo (ImageHandle);
+ if (Image == NULL ) {
+ //
+ // The image handle is not valid
+ //
+ Status = EFI_INVALID_PARAMETER;
+ goto Done;
+ }
+
+ if (Image->Started) {
+ //
+ // The image has been started, request it to unload.
+ //
+ Status = EFI_UNSUPPORTED;
+ if (Image->Info.Unload != NULL) {
+ Status = Image->Info.Unload (ImageHandle);
+ }
+
+ } else {
+ //
+ // This Image hasn't been started, thus it can be unloaded
+ //
+ Status = EFI_SUCCESS;
+ }
+
+
+ if (!EFI_ERROR (Status)) {
+ //
+ // if the Image was not started or Unloaded O.K. then clean up
+ //
+ CoreUnloadAndCloseImage (Image, TRUE);
+ }
+
+Done:
+ return Status;
+}
diff --git a/roms/edk2/MdeModulePkg/Core/Dxe/Image/Image.h b/roms/edk2/MdeModulePkg/Core/Dxe/Image/Image.h
new file mode 100644
index 000000000..e9c44ab2a
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Core/Dxe/Image/Image.h
@@ -0,0 +1,24 @@
+/** @file
+ Data structure and functions to load and unload PeImage.
+
+Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+
+#ifndef _IMAGE_H_
+#define _IMAGE_H_
+
+//
+// Private Data Types
+//
+#define IMAGE_FILE_HANDLE_SIGNATURE SIGNATURE_32('i','m','g','f')
+typedef struct {
+ UINTN Signature;
+ BOOLEAN FreeBuffer;
+ VOID *Source;
+ UINTN SourceSize;
+} IMAGE_FILE_HANDLE;
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Core/Dxe/Library/Library.c b/roms/edk2/MdeModulePkg/Core/Dxe/Library/Library.c
new file mode 100644
index 000000000..b7f0781ed
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Core/Dxe/Library/Library.c
@@ -0,0 +1,100 @@
+/** @file
+ DXE Core library services.
+
+Copyright (c) 2006 - 2008, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "DxeMain.h"
+
+//
+// Lock Stuff
+//
+/**
+ Initialize a basic mutual exclusion lock. Each lock
+ provides mutual exclusion access at it's task priority
+ level. Since there is no-premption (at any TPL) or
+ multiprocessor support, acquiring the lock only consists
+ of raising to the locks TPL.
+
+ @param Lock The EFI_LOCK structure to initialize
+
+ @retval EFI_SUCCESS Lock Owned.
+ @retval EFI_ACCESS_DENIED Reentrant Lock Acquisition, Lock not Owned.
+
+**/
+EFI_STATUS
+CoreAcquireLockOrFail (
+ IN EFI_LOCK *Lock
+ )
+{
+ ASSERT (Lock != NULL);
+ ASSERT (Lock->Lock != EfiLockUninitialized);
+
+ if (Lock->Lock == EfiLockAcquired) {
+ //
+ // Lock is already owned, so bail out
+ //
+ return EFI_ACCESS_DENIED;
+ }
+
+ Lock->OwnerTpl = CoreRaiseTpl (Lock->Tpl);
+
+ Lock->Lock = EfiLockAcquired;
+ return EFI_SUCCESS;
+}
+
+
+
+/**
+ Raising to the task priority level of the mutual exclusion
+ lock, and then acquires ownership of the lock.
+
+ @param Lock The lock to acquire
+
+ @return Lock owned
+
+**/
+VOID
+CoreAcquireLock (
+ IN EFI_LOCK *Lock
+ )
+{
+ ASSERT (Lock != NULL);
+ ASSERT (Lock->Lock == EfiLockReleased);
+
+ Lock->OwnerTpl = CoreRaiseTpl (Lock->Tpl);
+ Lock->Lock = EfiLockAcquired;
+}
+
+
+
+/**
+ Releases ownership of the mutual exclusion lock, and
+ restores the previous task priority level.
+
+ @param Lock The lock to release
+
+ @return Lock unowned
+
+**/
+VOID
+CoreReleaseLock (
+ IN EFI_LOCK *Lock
+ )
+{
+ EFI_TPL Tpl;
+
+ ASSERT (Lock != NULL);
+ ASSERT (Lock->Lock == EfiLockAcquired);
+
+ Tpl = Lock->OwnerTpl;
+
+ Lock->Lock = EfiLockReleased;
+
+ CoreRestoreTpl (Tpl);
+}
+
+
+
diff --git a/roms/edk2/MdeModulePkg/Core/Dxe/Mem/HeapGuard.c b/roms/edk2/MdeModulePkg/Core/Dxe/Mem/HeapGuard.c
new file mode 100644
index 000000000..b4cb48843
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Core/Dxe/Mem/HeapGuard.c
@@ -0,0 +1,1746 @@
+/** @file
+ UEFI Heap Guard functions.
+
+Copyright (c) 2017-2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "DxeMain.h"
+#include "Imem.h"
+#include "HeapGuard.h"
+
+//
+// Global to avoid infinite reentrance of memory allocation when updating
+// page table attributes, which may need allocate pages for new PDE/PTE.
+//
+GLOBAL_REMOVE_IF_UNREFERENCED BOOLEAN mOnGuarding = FALSE;
+
+//
+// Pointer to table tracking the Guarded memory with bitmap, in which '1'
+// is used to indicate memory guarded. '0' might be free memory or Guard
+// page itself, depending on status of memory adjacent to it.
+//
+GLOBAL_REMOVE_IF_UNREFERENCED UINT64 mGuardedMemoryMap = 0;
+
+//
+// Current depth level of map table pointed by mGuardedMemoryMap.
+// mMapLevel must be initialized at least by 1. It will be automatically
+// updated according to the address of memory just tracked.
+//
+GLOBAL_REMOVE_IF_UNREFERENCED UINTN mMapLevel = 1;
+
+//
+// Shift and mask for each level of map table
+//
+GLOBAL_REMOVE_IF_UNREFERENCED UINTN mLevelShift[GUARDED_HEAP_MAP_TABLE_DEPTH]
+ = GUARDED_HEAP_MAP_TABLE_DEPTH_SHIFTS;
+GLOBAL_REMOVE_IF_UNREFERENCED UINTN mLevelMask[GUARDED_HEAP_MAP_TABLE_DEPTH]
+ = GUARDED_HEAP_MAP_TABLE_DEPTH_MASKS;
+
+//
+// Used for promoting freed but not used pages.
+//
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_PHYSICAL_ADDRESS mLastPromotedPage = BASE_4GB;
+
+/**
+ Set corresponding bits in bitmap table to 1 according to the address.
+
+ @param[in] Address Start address to set for.
+ @param[in] BitNumber Number of bits to set.
+ @param[in] BitMap Pointer to bitmap which covers the Address.
+
+ @return VOID.
+**/
+STATIC
+VOID
+SetBits (
+ IN EFI_PHYSICAL_ADDRESS Address,
+ IN UINTN BitNumber,
+ IN UINT64 *BitMap
+ )
+{
+ UINTN Lsbs;
+ UINTN Qwords;
+ UINTN Msbs;
+ UINTN StartBit;
+ UINTN EndBit;
+
+ StartBit = (UINTN)GUARDED_HEAP_MAP_ENTRY_BIT_INDEX (Address);
+ EndBit = (StartBit + BitNumber - 1) % GUARDED_HEAP_MAP_ENTRY_BITS;
+
+ if ((StartBit + BitNumber) >= GUARDED_HEAP_MAP_ENTRY_BITS) {
+ Msbs = (GUARDED_HEAP_MAP_ENTRY_BITS - StartBit) %
+ GUARDED_HEAP_MAP_ENTRY_BITS;
+ Lsbs = (EndBit + 1) % GUARDED_HEAP_MAP_ENTRY_BITS;
+ Qwords = (BitNumber - Msbs) / GUARDED_HEAP_MAP_ENTRY_BITS;
+ } else {
+ Msbs = BitNumber;
+ Lsbs = 0;
+ Qwords = 0;
+ }
+
+ if (Msbs > 0) {
+ *BitMap |= LShiftU64 (LShiftU64 (1, Msbs) - 1, StartBit);
+ BitMap += 1;
+ }
+
+ if (Qwords > 0) {
+ SetMem64 ((VOID *)BitMap, Qwords * GUARDED_HEAP_MAP_ENTRY_BYTES,
+ (UINT64)-1);
+ BitMap += Qwords;
+ }
+
+ if (Lsbs > 0) {
+ *BitMap |= (LShiftU64 (1, Lsbs) - 1);
+ }
+}
+
+/**
+ Set corresponding bits in bitmap table to 0 according to the address.
+
+ @param[in] Address Start address to set for.
+ @param[in] BitNumber Number of bits to set.
+ @param[in] BitMap Pointer to bitmap which covers the Address.
+
+ @return VOID.
+**/
+STATIC
+VOID
+ClearBits (
+ IN EFI_PHYSICAL_ADDRESS Address,
+ IN UINTN BitNumber,
+ IN UINT64 *BitMap
+ )
+{
+ UINTN Lsbs;
+ UINTN Qwords;
+ UINTN Msbs;
+ UINTN StartBit;
+ UINTN EndBit;
+
+ StartBit = (UINTN)GUARDED_HEAP_MAP_ENTRY_BIT_INDEX (Address);
+ EndBit = (StartBit + BitNumber - 1) % GUARDED_HEAP_MAP_ENTRY_BITS;
+
+ if ((StartBit + BitNumber) >= GUARDED_HEAP_MAP_ENTRY_BITS) {
+ Msbs = (GUARDED_HEAP_MAP_ENTRY_BITS - StartBit) %
+ GUARDED_HEAP_MAP_ENTRY_BITS;
+ Lsbs = (EndBit + 1) % GUARDED_HEAP_MAP_ENTRY_BITS;
+ Qwords = (BitNumber - Msbs) / GUARDED_HEAP_MAP_ENTRY_BITS;
+ } else {
+ Msbs = BitNumber;
+ Lsbs = 0;
+ Qwords = 0;
+ }
+
+ if (Msbs > 0) {
+ *BitMap &= ~LShiftU64 (LShiftU64 (1, Msbs) - 1, StartBit);
+ BitMap += 1;
+ }
+
+ if (Qwords > 0) {
+ SetMem64 ((VOID *)BitMap, Qwords * GUARDED_HEAP_MAP_ENTRY_BYTES, 0);
+ BitMap += Qwords;
+ }
+
+ if (Lsbs > 0) {
+ *BitMap &= ~(LShiftU64 (1, Lsbs) - 1);
+ }
+}
+
+/**
+ Get corresponding bits in bitmap table according to the address.
+
+ The value of bit 0 corresponds to the status of memory at given Address.
+ No more than 64 bits can be retrieved in one call.
+
+ @param[in] Address Start address to retrieve bits for.
+ @param[in] BitNumber Number of bits to get.
+ @param[in] BitMap Pointer to bitmap which covers the Address.
+
+ @return An integer containing the bits information.
+**/
+STATIC
+UINT64
+GetBits (
+ IN EFI_PHYSICAL_ADDRESS Address,
+ IN UINTN BitNumber,
+ IN UINT64 *BitMap
+ )
+{
+ UINTN StartBit;
+ UINTN EndBit;
+ UINTN Lsbs;
+ UINTN Msbs;
+ UINT64 Result;
+
+ ASSERT (BitNumber <= GUARDED_HEAP_MAP_ENTRY_BITS);
+
+ StartBit = (UINTN)GUARDED_HEAP_MAP_ENTRY_BIT_INDEX (Address);
+ EndBit = (StartBit + BitNumber - 1) % GUARDED_HEAP_MAP_ENTRY_BITS;
+
+ if ((StartBit + BitNumber) > GUARDED_HEAP_MAP_ENTRY_BITS) {
+ Msbs = GUARDED_HEAP_MAP_ENTRY_BITS - StartBit;
+ Lsbs = (EndBit + 1) % GUARDED_HEAP_MAP_ENTRY_BITS;
+ } else {
+ Msbs = BitNumber;
+ Lsbs = 0;
+ }
+
+ if (StartBit == 0 && BitNumber == GUARDED_HEAP_MAP_ENTRY_BITS) {
+ Result = *BitMap;
+ } else {
+ Result = RShiftU64((*BitMap), StartBit) & (LShiftU64(1, Msbs) - 1);
+ if (Lsbs > 0) {
+ BitMap += 1;
+ Result |= LShiftU64 ((*BitMap) & (LShiftU64 (1, Lsbs) - 1), Msbs);
+ }
+ }
+
+ return Result;
+}
+
+/**
+ Locate the pointer of bitmap from the guarded memory bitmap tables, which
+ covers the given Address.
+
+ @param[in] Address Start address to search the bitmap for.
+ @param[in] AllocMapUnit Flag to indicate memory allocation for the table.
+ @param[out] BitMap Pointer to bitmap which covers the Address.
+
+ @return The bit number from given Address to the end of current map table.
+**/
+UINTN
+FindGuardedMemoryMap (
+ IN EFI_PHYSICAL_ADDRESS Address,
+ IN BOOLEAN AllocMapUnit,
+ OUT UINT64 **BitMap
+ )
+{
+ UINTN Level;
+ UINT64 *GuardMap;
+ UINT64 MapMemory;
+ UINTN Index;
+ UINTN Size;
+ UINTN BitsToUnitEnd;
+ EFI_STATUS Status;
+
+ MapMemory = 0;
+
+ //
+ // Adjust current map table depth according to the address to access
+ //
+ while (AllocMapUnit &&
+ mMapLevel < GUARDED_HEAP_MAP_TABLE_DEPTH &&
+ RShiftU64 (
+ Address,
+ mLevelShift[GUARDED_HEAP_MAP_TABLE_DEPTH - mMapLevel - 1]
+ ) != 0) {
+
+ if (mGuardedMemoryMap != 0) {
+ Size = (mLevelMask[GUARDED_HEAP_MAP_TABLE_DEPTH - mMapLevel - 1] + 1)
+ * GUARDED_HEAP_MAP_ENTRY_BYTES;
+ Status = CoreInternalAllocatePages (
+ AllocateAnyPages,
+ EfiBootServicesData,
+ EFI_SIZE_TO_PAGES (Size),
+ &MapMemory,
+ FALSE
+ );
+ ASSERT_EFI_ERROR (Status);
+ ASSERT (MapMemory != 0);
+
+ SetMem ((VOID *)(UINTN)MapMemory, Size, 0);
+
+ *(UINT64 *)(UINTN)MapMemory = mGuardedMemoryMap;
+ mGuardedMemoryMap = MapMemory;
+ }
+
+ mMapLevel++;
+
+ }
+
+ GuardMap = &mGuardedMemoryMap;
+ for (Level = GUARDED_HEAP_MAP_TABLE_DEPTH - mMapLevel;
+ Level < GUARDED_HEAP_MAP_TABLE_DEPTH;
+ ++Level) {
+
+ if (*GuardMap == 0) {
+ if (!AllocMapUnit) {
+ GuardMap = NULL;
+ break;
+ }
+
+ Size = (mLevelMask[Level] + 1) * GUARDED_HEAP_MAP_ENTRY_BYTES;
+ Status = CoreInternalAllocatePages (
+ AllocateAnyPages,
+ EfiBootServicesData,
+ EFI_SIZE_TO_PAGES (Size),
+ &MapMemory,
+ FALSE
+ );
+ ASSERT_EFI_ERROR (Status);
+ ASSERT (MapMemory != 0);
+
+ SetMem ((VOID *)(UINTN)MapMemory, Size, 0);
+ *GuardMap = MapMemory;
+ }
+
+ Index = (UINTN)RShiftU64 (Address, mLevelShift[Level]);
+ Index &= mLevelMask[Level];
+ GuardMap = (UINT64 *)(UINTN)((*GuardMap) + Index * sizeof (UINT64));
+
+ }
+
+ BitsToUnitEnd = GUARDED_HEAP_MAP_BITS - GUARDED_HEAP_MAP_BIT_INDEX (Address);
+ *BitMap = GuardMap;
+
+ return BitsToUnitEnd;
+}
+
+/**
+ Set corresponding bits in bitmap table to 1 according to given memory range.
+
+ @param[in] Address Memory address to guard from.
+ @param[in] NumberOfPages Number of pages to guard.
+
+ @return VOID.
+**/
+VOID
+EFIAPI
+SetGuardedMemoryBits (
+ IN EFI_PHYSICAL_ADDRESS Address,
+ IN UINTN NumberOfPages
+ )
+{
+ UINT64 *BitMap;
+ UINTN Bits;
+ UINTN BitsToUnitEnd;
+
+ while (NumberOfPages > 0) {
+ BitsToUnitEnd = FindGuardedMemoryMap (Address, TRUE, &BitMap);
+ ASSERT (BitMap != NULL);
+
+ if (NumberOfPages > BitsToUnitEnd) {
+ // Cross map unit
+ Bits = BitsToUnitEnd;
+ } else {
+ Bits = NumberOfPages;
+ }
+
+ SetBits (Address, Bits, BitMap);
+
+ NumberOfPages -= Bits;
+ Address += EFI_PAGES_TO_SIZE (Bits);
+ }
+}
+
+/**
+ Clear corresponding bits in bitmap table according to given memory range.
+
+ @param[in] Address Memory address to unset from.
+ @param[in] NumberOfPages Number of pages to unset guard.
+
+ @return VOID.
+**/
+VOID
+EFIAPI
+ClearGuardedMemoryBits (
+ IN EFI_PHYSICAL_ADDRESS Address,
+ IN UINTN NumberOfPages
+ )
+{
+ UINT64 *BitMap;
+ UINTN Bits;
+ UINTN BitsToUnitEnd;
+
+ while (NumberOfPages > 0) {
+ BitsToUnitEnd = FindGuardedMemoryMap (Address, TRUE, &BitMap);
+ ASSERT (BitMap != NULL);
+
+ if (NumberOfPages > BitsToUnitEnd) {
+ // Cross map unit
+ Bits = BitsToUnitEnd;
+ } else {
+ Bits = NumberOfPages;
+ }
+
+ ClearBits (Address, Bits, BitMap);
+
+ NumberOfPages -= Bits;
+ Address += EFI_PAGES_TO_SIZE (Bits);
+ }
+}
+
+/**
+ Retrieve corresponding bits in bitmap table according to given memory range.
+
+ @param[in] Address Memory address to retrieve from.
+ @param[in] NumberOfPages Number of pages to retrieve.
+
+ @return An integer containing the guarded memory bitmap.
+**/
+UINT64
+GetGuardedMemoryBits (
+ IN EFI_PHYSICAL_ADDRESS Address,
+ IN UINTN NumberOfPages
+ )
+{
+ UINT64 *BitMap;
+ UINTN Bits;
+ UINT64 Result;
+ UINTN Shift;
+ UINTN BitsToUnitEnd;
+
+ ASSERT (NumberOfPages <= GUARDED_HEAP_MAP_ENTRY_BITS);
+
+ Result = 0;
+ Shift = 0;
+ while (NumberOfPages > 0) {
+ BitsToUnitEnd = FindGuardedMemoryMap (Address, FALSE, &BitMap);
+
+ if (NumberOfPages > BitsToUnitEnd) {
+ // Cross map unit
+ Bits = BitsToUnitEnd;
+ } else {
+ Bits = NumberOfPages;
+ }
+
+ if (BitMap != NULL) {
+ Result |= LShiftU64 (GetBits (Address, Bits, BitMap), Shift);
+ }
+
+ Shift += Bits;
+ NumberOfPages -= Bits;
+ Address += EFI_PAGES_TO_SIZE (Bits);
+ }
+
+ return Result;
+}
+
+/**
+ Get bit value in bitmap table for the given address.
+
+ @param[in] Address The address to retrieve for.
+
+ @return 1 or 0.
+**/
+UINTN
+EFIAPI
+GetGuardMapBit (
+ IN EFI_PHYSICAL_ADDRESS Address
+ )
+{
+ UINT64 *GuardMap;
+
+ FindGuardedMemoryMap (Address, FALSE, &GuardMap);
+ if (GuardMap != NULL) {
+ if (RShiftU64 (*GuardMap,
+ GUARDED_HEAP_MAP_ENTRY_BIT_INDEX (Address)) & 1) {
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+
+/**
+ Check to see if the page at the given address is a Guard page or not.
+
+ @param[in] Address The address to check for.
+
+ @return TRUE The page at Address is a Guard page.
+ @return FALSE The page at Address is not a Guard page.
+**/
+BOOLEAN
+EFIAPI
+IsGuardPage (
+ IN EFI_PHYSICAL_ADDRESS Address
+ )
+{
+ UINT64 BitMap;
+
+ //
+ // There must be at least one guarded page before and/or after given
+ // address if it's a Guard page. The bitmap pattern should be one of
+ // 001, 100 and 101
+ //
+ BitMap = GetGuardedMemoryBits (Address - EFI_PAGE_SIZE, 3);
+ return ((BitMap == BIT0) || (BitMap == BIT2) || (BitMap == (BIT2 | BIT0)));
+}
+
+
+/**
+ Check to see if the page at the given address is guarded or not.
+
+ @param[in] Address The address to check for.
+
+ @return TRUE The page at Address is guarded.
+ @return FALSE The page at Address is not guarded.
+**/
+BOOLEAN
+EFIAPI
+IsMemoryGuarded (
+ IN EFI_PHYSICAL_ADDRESS Address
+ )
+{
+ return (GetGuardMapBit (Address) == 1);
+}
+
+/**
+ Set the page at the given address to be a Guard page.
+
+ This is done by changing the page table attribute to be NOT PRSENT.
+
+ @param[in] BaseAddress Page address to Guard at
+
+ @return VOID
+**/
+VOID
+EFIAPI
+SetGuardPage (
+ IN EFI_PHYSICAL_ADDRESS BaseAddress
+ )
+{
+ EFI_STATUS Status;
+
+ if (gCpu == NULL) {
+ return;
+ }
+
+ //
+ // Set flag to make sure allocating memory without GUARD for page table
+ // operation; otherwise infinite loops could be caused.
+ //
+ mOnGuarding = TRUE;
+ //
+ // Note: This might overwrite other attributes needed by other features,
+ // such as NX memory protection.
+ //
+ Status = gCpu->SetMemoryAttributes (gCpu, BaseAddress, EFI_PAGE_SIZE, EFI_MEMORY_RP);
+ ASSERT_EFI_ERROR (Status);
+ mOnGuarding = FALSE;
+}
+
+/**
+ Unset the Guard page at the given address to the normal memory.
+
+ This is done by changing the page table attribute to be PRSENT.
+
+ @param[in] BaseAddress Page address to Guard at.
+
+ @return VOID.
+**/
+VOID
+EFIAPI
+UnsetGuardPage (
+ IN EFI_PHYSICAL_ADDRESS BaseAddress
+ )
+{
+ UINT64 Attributes;
+ EFI_STATUS Status;
+
+ if (gCpu == NULL) {
+ return;
+ }
+
+ //
+ // Once the Guard page is unset, it will be freed back to memory pool. NX
+ // memory protection must be restored for this page if NX is enabled for free
+ // memory.
+ //
+ Attributes = 0;
+ if ((PcdGet64 (PcdDxeNxMemoryProtectionPolicy) & (1 << EfiConventionalMemory)) != 0) {
+ Attributes |= EFI_MEMORY_XP;
+ }
+
+ //
+ // Set flag to make sure allocating memory without GUARD for page table
+ // operation; otherwise infinite loops could be caused.
+ //
+ mOnGuarding = TRUE;
+ //
+ // Note: This might overwrite other attributes needed by other features,
+ // such as memory protection (NX). Please make sure they are not enabled
+ // at the same time.
+ //
+ Status = gCpu->SetMemoryAttributes (gCpu, BaseAddress, EFI_PAGE_SIZE, Attributes);
+ ASSERT_EFI_ERROR (Status);
+ mOnGuarding = FALSE;
+}
+
+/**
+ Check to see if the memory at the given address should be guarded or not.
+
+ @param[in] MemoryType Memory type to check.
+ @param[in] AllocateType Allocation type to check.
+ @param[in] PageOrPool Indicate a page allocation or pool allocation.
+
+
+ @return TRUE The given type of memory should be guarded.
+ @return FALSE The given type of memory should not be guarded.
+**/
+BOOLEAN
+IsMemoryTypeToGuard (
+ IN EFI_MEMORY_TYPE MemoryType,
+ IN EFI_ALLOCATE_TYPE AllocateType,
+ IN UINT8 PageOrPool
+ )
+{
+ UINT64 TestBit;
+ UINT64 ConfigBit;
+
+ if (AllocateType == AllocateAddress) {
+ return FALSE;
+ }
+
+ if ((PcdGet8 (PcdHeapGuardPropertyMask) & PageOrPool) == 0) {
+ return FALSE;
+ }
+
+ if (PageOrPool == GUARD_HEAP_TYPE_POOL) {
+ ConfigBit = PcdGet64 (PcdHeapGuardPoolType);
+ } else if (PageOrPool == GUARD_HEAP_TYPE_PAGE) {
+ ConfigBit = PcdGet64 (PcdHeapGuardPageType);
+ } else {
+ ConfigBit = (UINT64)-1;
+ }
+
+ if ((UINT32)MemoryType >= MEMORY_TYPE_OS_RESERVED_MIN) {
+ TestBit = BIT63;
+ } else if ((UINT32) MemoryType >= MEMORY_TYPE_OEM_RESERVED_MIN) {
+ TestBit = BIT62;
+ } else if (MemoryType < EfiMaxMemoryType) {
+ TestBit = LShiftU64 (1, MemoryType);
+ } else if (MemoryType == EfiMaxMemoryType) {
+ TestBit = (UINT64)-1;
+ } else {
+ TestBit = 0;
+ }
+
+ return ((ConfigBit & TestBit) != 0);
+}
+
+/**
+ Check to see if the pool at the given address should be guarded or not.
+
+ @param[in] MemoryType Pool type to check.
+
+
+ @return TRUE The given type of pool should be guarded.
+ @return FALSE The given type of pool should not be guarded.
+**/
+BOOLEAN
+IsPoolTypeToGuard (
+ IN EFI_MEMORY_TYPE MemoryType
+ )
+{
+ return IsMemoryTypeToGuard (MemoryType, AllocateAnyPages,
+ GUARD_HEAP_TYPE_POOL);
+}
+
+/**
+ Check to see if the page at the given address should be guarded or not.
+
+ @param[in] MemoryType Page type to check.
+ @param[in] AllocateType Allocation type to check.
+
+ @return TRUE The given type of page should be guarded.
+ @return FALSE The given type of page should not be guarded.
+**/
+BOOLEAN
+IsPageTypeToGuard (
+ IN EFI_MEMORY_TYPE MemoryType,
+ IN EFI_ALLOCATE_TYPE AllocateType
+ )
+{
+ return IsMemoryTypeToGuard (MemoryType, AllocateType, GUARD_HEAP_TYPE_PAGE);
+}
+
+/**
+ Check to see if the heap guard is enabled for page and/or pool allocation.
+
+ @param[in] GuardType Specify the sub-type(s) of Heap Guard.
+
+ @return TRUE/FALSE.
+**/
+BOOLEAN
+IsHeapGuardEnabled (
+ UINT8 GuardType
+ )
+{
+ return IsMemoryTypeToGuard (EfiMaxMemoryType, AllocateAnyPages, GuardType);
+}
+
+/**
+ Set head Guard and tail Guard for the given memory range.
+
+ @param[in] Memory Base address of memory to set guard for.
+ @param[in] NumberOfPages Memory size in pages.
+
+ @return VOID
+**/
+VOID
+SetGuardForMemory (
+ IN EFI_PHYSICAL_ADDRESS Memory,
+ IN UINTN NumberOfPages
+ )
+{
+ EFI_PHYSICAL_ADDRESS GuardPage;
+
+ //
+ // Set tail Guard
+ //
+ GuardPage = Memory + EFI_PAGES_TO_SIZE (NumberOfPages);
+ if (!IsGuardPage (GuardPage)) {
+ SetGuardPage (GuardPage);
+ }
+
+ // Set head Guard
+ GuardPage = Memory - EFI_PAGES_TO_SIZE (1);
+ if (!IsGuardPage (GuardPage)) {
+ SetGuardPage (GuardPage);
+ }
+
+ //
+ // Mark the memory range as Guarded
+ //
+ SetGuardedMemoryBits (Memory, NumberOfPages);
+}
+
+/**
+ Unset head Guard and tail Guard for the given memory range.
+
+ @param[in] Memory Base address of memory to unset guard for.
+ @param[in] NumberOfPages Memory size in pages.
+
+ @return VOID
+**/
+VOID
+UnsetGuardForMemory (
+ IN EFI_PHYSICAL_ADDRESS Memory,
+ IN UINTN NumberOfPages
+ )
+{
+ EFI_PHYSICAL_ADDRESS GuardPage;
+ UINT64 GuardBitmap;
+
+ if (NumberOfPages == 0) {
+ return;
+ }
+
+ //
+ // Head Guard must be one page before, if any.
+ //
+ // MSB-> 1 0 <-LSB
+ // -------------------
+ // Head Guard -> 0 1 -> Don't free Head Guard (shared Guard)
+ // Head Guard -> 0 0 -> Free Head Guard either (not shared Guard)
+ // 1 X -> Don't free first page (need a new Guard)
+ // (it'll be turned into a Guard page later)
+ // -------------------
+ // Start -> -1 -2
+ //
+ GuardPage = Memory - EFI_PAGES_TO_SIZE (1);
+ GuardBitmap = GetGuardedMemoryBits (Memory - EFI_PAGES_TO_SIZE (2), 2);
+ if ((GuardBitmap & BIT1) == 0) {
+ //
+ // Head Guard exists.
+ //
+ if ((GuardBitmap & BIT0) == 0) {
+ //
+ // If the head Guard is not a tail Guard of adjacent memory block,
+ // unset it.
+ //
+ UnsetGuardPage (GuardPage);
+ }
+ } else {
+ //
+ // Pages before memory to free are still in Guard. It's a partial free
+ // case. Turn first page of memory block to free into a new Guard.
+ //
+ SetGuardPage (Memory);
+ }
+
+ //
+ // Tail Guard must be the page after this memory block to free, if any.
+ //
+ // MSB-> 1 0 <-LSB
+ // --------------------
+ // 1 0 <- Tail Guard -> Don't free Tail Guard (shared Guard)
+ // 0 0 <- Tail Guard -> Free Tail Guard either (not shared Guard)
+ // X 1 -> Don't free last page (need a new Guard)
+ // (it'll be turned into a Guard page later)
+ // --------------------
+ // +1 +0 <- End
+ //
+ GuardPage = Memory + EFI_PAGES_TO_SIZE (NumberOfPages);
+ GuardBitmap = GetGuardedMemoryBits (GuardPage, 2);
+ if ((GuardBitmap & BIT0) == 0) {
+ //
+ // Tail Guard exists.
+ //
+ if ((GuardBitmap & BIT1) == 0) {
+ //
+ // If the tail Guard is not a head Guard of adjacent memory block,
+ // free it; otherwise, keep it.
+ //
+ UnsetGuardPage (GuardPage);
+ }
+ } else {
+ //
+ // Pages after memory to free are still in Guard. It's a partial free
+ // case. We need to keep one page to be a head Guard.
+ //
+ SetGuardPage (GuardPage - EFI_PAGES_TO_SIZE (1));
+ }
+
+ //
+ // No matter what, we just clear the mark of the Guarded memory.
+ //
+ ClearGuardedMemoryBits(Memory, NumberOfPages);
+}
+
+/**
+ Adjust address of free memory according to existing and/or required Guard.
+
+ This function will check if there're existing Guard pages of adjacent
+ memory blocks, and try to use it as the Guard page of the memory to be
+ allocated.
+
+ @param[in] Start Start address of free memory block.
+ @param[in] Size Size of free memory block.
+ @param[in] SizeRequested Size of memory to allocate.
+
+ @return The end address of memory block found.
+ @return 0 if no enough space for the required size of memory and its Guard.
+**/
+UINT64
+AdjustMemoryS (
+ IN UINT64 Start,
+ IN UINT64 Size,
+ IN UINT64 SizeRequested
+ )
+{
+ UINT64 Target;
+
+ //
+ // UEFI spec requires that allocated pool must be 8-byte aligned. If it's
+ // indicated to put the pool near the Tail Guard, we need extra bytes to
+ // make sure alignment of the returned pool address.
+ //
+ if ((PcdGet8 (PcdHeapGuardPropertyMask) & BIT7) == 0) {
+ SizeRequested = ALIGN_VALUE(SizeRequested, 8);
+ }
+
+ Target = Start + Size - SizeRequested;
+ ASSERT (Target >= Start);
+ if (Target == 0) {
+ return 0;
+ }
+
+ if (!IsGuardPage (Start + Size)) {
+ // No Guard at tail to share. One more page is needed.
+ Target -= EFI_PAGES_TO_SIZE (1);
+ }
+
+ // Out of range?
+ if (Target < Start) {
+ return 0;
+ }
+
+ // At the edge?
+ if (Target == Start) {
+ if (!IsGuardPage (Target - EFI_PAGES_TO_SIZE (1))) {
+ // No enough space for a new head Guard if no Guard at head to share.
+ return 0;
+ }
+ }
+
+ // OK, we have enough pages for memory and its Guards. Return the End of the
+ // free space.
+ return Target + SizeRequested - 1;
+}
+
+/**
+ Adjust the start address and number of pages to free according to Guard.
+
+ The purpose of this function is to keep the shared Guard page with adjacent
+ memory block if it's still in guard, or free it if no more sharing. Another
+ is to reserve pages as Guard pages in partial page free situation.
+
+ @param[in,out] Memory Base address of memory to free.
+ @param[in,out] NumberOfPages Size of memory to free.
+
+ @return VOID.
+**/
+VOID
+AdjustMemoryF (
+ IN OUT EFI_PHYSICAL_ADDRESS *Memory,
+ IN OUT UINTN *NumberOfPages
+ )
+{
+ EFI_PHYSICAL_ADDRESS Start;
+ EFI_PHYSICAL_ADDRESS MemoryToTest;
+ UINTN PagesToFree;
+ UINT64 GuardBitmap;
+
+ if (Memory == NULL || NumberOfPages == NULL || *NumberOfPages == 0) {
+ return;
+ }
+
+ Start = *Memory;
+ PagesToFree = *NumberOfPages;
+
+ //
+ // Head Guard must be one page before, if any.
+ //
+ // MSB-> 1 0 <-LSB
+ // -------------------
+ // Head Guard -> 0 1 -> Don't free Head Guard (shared Guard)
+ // Head Guard -> 0 0 -> Free Head Guard either (not shared Guard)
+ // 1 X -> Don't free first page (need a new Guard)
+ // (it'll be turned into a Guard page later)
+ // -------------------
+ // Start -> -1 -2
+ //
+ MemoryToTest = Start - EFI_PAGES_TO_SIZE (2);
+ GuardBitmap = GetGuardedMemoryBits (MemoryToTest, 2);
+ if ((GuardBitmap & BIT1) == 0) {
+ //
+ // Head Guard exists.
+ //
+ if ((GuardBitmap & BIT0) == 0) {
+ //
+ // If the head Guard is not a tail Guard of adjacent memory block,
+ // free it; otherwise, keep it.
+ //
+ Start -= EFI_PAGES_TO_SIZE (1);
+ PagesToFree += 1;
+ }
+ } else {
+ //
+ // No Head Guard, and pages before memory to free are still in Guard. It's a
+ // partial free case. We need to keep one page to be a tail Guard.
+ //
+ Start += EFI_PAGES_TO_SIZE (1);
+ PagesToFree -= 1;
+ }
+
+ //
+ // Tail Guard must be the page after this memory block to free, if any.
+ //
+ // MSB-> 1 0 <-LSB
+ // --------------------
+ // 1 0 <- Tail Guard -> Don't free Tail Guard (shared Guard)
+ // 0 0 <- Tail Guard -> Free Tail Guard either (not shared Guard)
+ // X 1 -> Don't free last page (need a new Guard)
+ // (it'll be turned into a Guard page later)
+ // --------------------
+ // +1 +0 <- End
+ //
+ MemoryToTest = Start + EFI_PAGES_TO_SIZE (PagesToFree);
+ GuardBitmap = GetGuardedMemoryBits (MemoryToTest, 2);
+ if ((GuardBitmap & BIT0) == 0) {
+ //
+ // Tail Guard exists.
+ //
+ if ((GuardBitmap & BIT1) == 0) {
+ //
+ // If the tail Guard is not a head Guard of adjacent memory block,
+ // free it; otherwise, keep it.
+ //
+ PagesToFree += 1;
+ }
+ } else if (PagesToFree > 0) {
+ //
+ // No Tail Guard, and pages after memory to free are still in Guard. It's a
+ // partial free case. We need to keep one page to be a head Guard.
+ //
+ PagesToFree -= 1;
+ }
+
+ *Memory = Start;
+ *NumberOfPages = PagesToFree;
+}
+
+/**
+ Adjust the base and number of pages to really allocate according to Guard.
+
+ @param[in,out] Memory Base address of free memory.
+ @param[in,out] NumberOfPages Size of memory to allocate.
+
+ @return VOID.
+**/
+VOID
+AdjustMemoryA (
+ IN OUT EFI_PHYSICAL_ADDRESS *Memory,
+ IN OUT UINTN *NumberOfPages
+ )
+{
+ //
+ // FindFreePages() has already taken the Guard into account. It's safe to
+ // adjust the start address and/or number of pages here, to make sure that
+ // the Guards are also "allocated".
+ //
+ if (!IsGuardPage (*Memory + EFI_PAGES_TO_SIZE (*NumberOfPages))) {
+ // No tail Guard, add one.
+ *NumberOfPages += 1;
+ }
+
+ if (!IsGuardPage (*Memory - EFI_PAGE_SIZE)) {
+ // No head Guard, add one.
+ *Memory -= EFI_PAGE_SIZE;
+ *NumberOfPages += 1;
+ }
+}
+
+/**
+ Adjust the pool head position to make sure the Guard page is adjavent to
+ pool tail or pool head.
+
+ @param[in] Memory Base address of memory allocated.
+ @param[in] NoPages Number of pages actually allocated.
+ @param[in] Size Size of memory requested.
+ (plus pool head/tail overhead)
+
+ @return Address of pool head.
+**/
+VOID *
+AdjustPoolHeadA (
+ IN EFI_PHYSICAL_ADDRESS Memory,
+ IN UINTN NoPages,
+ IN UINTN Size
+ )
+{
+ if (Memory == 0 || (PcdGet8 (PcdHeapGuardPropertyMask) & BIT7) != 0) {
+ //
+ // Pool head is put near the head Guard
+ //
+ return (VOID *)(UINTN)Memory;
+ }
+
+ //
+ // Pool head is put near the tail Guard
+ //
+ Size = ALIGN_VALUE (Size, 8);
+ return (VOID *)(UINTN)(Memory + EFI_PAGES_TO_SIZE (NoPages) - Size);
+}
+
+/**
+ Get the page base address according to pool head address.
+
+ @param[in] Memory Head address of pool to free.
+
+ @return Address of pool head.
+**/
+VOID *
+AdjustPoolHeadF (
+ IN EFI_PHYSICAL_ADDRESS Memory
+ )
+{
+ if (Memory == 0 || (PcdGet8 (PcdHeapGuardPropertyMask) & BIT7) != 0) {
+ //
+ // Pool head is put near the head Guard
+ //
+ return (VOID *)(UINTN)Memory;
+ }
+
+ //
+ // Pool head is put near the tail Guard
+ //
+ return (VOID *)(UINTN)(Memory & ~EFI_PAGE_MASK);
+}
+
+/**
+ Allocate or free guarded memory.
+
+ @param[in] Start Start address of memory to allocate or free.
+ @param[in] NumberOfPages Memory size in pages.
+ @param[in] NewType Memory type to convert to.
+
+ @return VOID.
+**/
+EFI_STATUS
+CoreConvertPagesWithGuard (
+ IN UINT64 Start,
+ IN UINTN NumberOfPages,
+ IN EFI_MEMORY_TYPE NewType
+ )
+{
+ UINT64 OldStart;
+ UINTN OldPages;
+
+ if (NewType == EfiConventionalMemory) {
+ OldStart = Start;
+ OldPages = NumberOfPages;
+
+ AdjustMemoryF (&Start, &NumberOfPages);
+ //
+ // It's safe to unset Guard page inside memory lock because there should
+ // be no memory allocation occurred in updating memory page attribute at
+ // this point. And unsetting Guard page before free will prevent Guard
+ // page just freed back to pool from being allocated right away before
+ // marking it usable (from non-present to present).
+ //
+ UnsetGuardForMemory (OldStart, OldPages);
+ if (NumberOfPages == 0) {
+ return EFI_SUCCESS;
+ }
+ } else {
+ AdjustMemoryA (&Start, &NumberOfPages);
+ }
+
+ return CoreConvertPages (Start, NumberOfPages, NewType);
+}
+
+/**
+ Set all Guard pages which cannot be set before CPU Arch Protocol installed.
+**/
+VOID
+SetAllGuardPages (
+ VOID
+ )
+{
+ UINTN Entries[GUARDED_HEAP_MAP_TABLE_DEPTH];
+ UINTN Shifts[GUARDED_HEAP_MAP_TABLE_DEPTH];
+ UINTN Indices[GUARDED_HEAP_MAP_TABLE_DEPTH];
+ UINT64 Tables[GUARDED_HEAP_MAP_TABLE_DEPTH];
+ UINT64 Addresses[GUARDED_HEAP_MAP_TABLE_DEPTH];
+ UINT64 TableEntry;
+ UINT64 Address;
+ UINT64 GuardPage;
+ INTN Level;
+ UINTN Index;
+ BOOLEAN OnGuarding;
+
+ if (mGuardedMemoryMap == 0 ||
+ mMapLevel == 0 ||
+ mMapLevel > GUARDED_HEAP_MAP_TABLE_DEPTH) {
+ return;
+ }
+
+ CopyMem (Entries, mLevelMask, sizeof (Entries));
+ CopyMem (Shifts, mLevelShift, sizeof (Shifts));
+
+ SetMem (Tables, sizeof(Tables), 0);
+ SetMem (Addresses, sizeof(Addresses), 0);
+ SetMem (Indices, sizeof(Indices), 0);
+
+ Level = GUARDED_HEAP_MAP_TABLE_DEPTH - mMapLevel;
+ Tables[Level] = mGuardedMemoryMap;
+ Address = 0;
+ OnGuarding = FALSE;
+
+ DEBUG_CODE (
+ DumpGuardedMemoryBitmap ();
+ );
+
+ while (TRUE) {
+ if (Indices[Level] > Entries[Level]) {
+ Tables[Level] = 0;
+ Level -= 1;
+ } else {
+
+ TableEntry = ((UINT64 *)(UINTN)(Tables[Level]))[Indices[Level]];
+ Address = Addresses[Level];
+
+ if (TableEntry == 0) {
+
+ OnGuarding = FALSE;
+
+ } else if (Level < GUARDED_HEAP_MAP_TABLE_DEPTH - 1) {
+
+ Level += 1;
+ Tables[Level] = TableEntry;
+ Addresses[Level] = Address;
+ Indices[Level] = 0;
+
+ continue;
+
+ } else {
+
+ Index = 0;
+ while (Index < GUARDED_HEAP_MAP_ENTRY_BITS) {
+ if ((TableEntry & 1) == 1) {
+ if (OnGuarding) {
+ GuardPage = 0;
+ } else {
+ GuardPage = Address - EFI_PAGE_SIZE;
+ }
+ OnGuarding = TRUE;
+ } else {
+ if (OnGuarding) {
+ GuardPage = Address;
+ } else {
+ GuardPage = 0;
+ }
+ OnGuarding = FALSE;
+ }
+
+ if (GuardPage != 0) {
+ SetGuardPage (GuardPage);
+ }
+
+ if (TableEntry == 0) {
+ break;
+ }
+
+ TableEntry = RShiftU64 (TableEntry, 1);
+ Address += EFI_PAGE_SIZE;
+ Index += 1;
+ }
+ }
+ }
+
+ if (Level < (GUARDED_HEAP_MAP_TABLE_DEPTH - (INTN)mMapLevel)) {
+ break;
+ }
+
+ Indices[Level] += 1;
+ Address = (Level == 0) ? 0 : Addresses[Level - 1];
+ Addresses[Level] = Address | LShiftU64(Indices[Level], Shifts[Level]);
+
+ }
+}
+
+/**
+ Find the address of top-most guarded free page.
+
+ @param[out] Address Start address of top-most guarded free page.
+
+ @return VOID.
+**/
+VOID
+GetLastGuardedFreePageAddress (
+ OUT EFI_PHYSICAL_ADDRESS *Address
+ )
+{
+ EFI_PHYSICAL_ADDRESS AddressGranularity;
+ EFI_PHYSICAL_ADDRESS BaseAddress;
+ UINTN Level;
+ UINT64 Map;
+ INTN Index;
+
+ ASSERT (mMapLevel >= 1);
+
+ BaseAddress = 0;
+ Map = mGuardedMemoryMap;
+ for (Level = GUARDED_HEAP_MAP_TABLE_DEPTH - mMapLevel;
+ Level < GUARDED_HEAP_MAP_TABLE_DEPTH;
+ ++Level) {
+ AddressGranularity = LShiftU64 (1, mLevelShift[Level]);
+
+ //
+ // Find the non-NULL entry at largest index.
+ //
+ for (Index = (INTN)mLevelMask[Level]; Index >= 0 ; --Index) {
+ if (((UINT64 *)(UINTN)Map)[Index] != 0) {
+ BaseAddress += MultU64x32 (AddressGranularity, (UINT32)Index);
+ Map = ((UINT64 *)(UINTN)Map)[Index];
+ break;
+ }
+ }
+ }
+
+ //
+ // Find the non-zero MSB then get the page address.
+ //
+ while (Map != 0) {
+ Map = RShiftU64 (Map, 1);
+ BaseAddress += EFI_PAGES_TO_SIZE (1);
+ }
+
+ *Address = BaseAddress;
+}
+
+/**
+ Record freed pages.
+
+ @param[in] BaseAddress Base address of just freed pages.
+ @param[in] Pages Number of freed pages.
+
+ @return VOID.
+**/
+VOID
+MarkFreedPages (
+ IN EFI_PHYSICAL_ADDRESS BaseAddress,
+ IN UINTN Pages
+ )
+{
+ SetGuardedMemoryBits (BaseAddress, Pages);
+}
+
+/**
+ Record freed pages as well as mark them as not-present.
+
+ @param[in] BaseAddress Base address of just freed pages.
+ @param[in] Pages Number of freed pages.
+
+ @return VOID.
+**/
+VOID
+EFIAPI
+GuardFreedPages (
+ IN EFI_PHYSICAL_ADDRESS BaseAddress,
+ IN UINTN Pages
+ )
+{
+ EFI_STATUS Status;
+
+ //
+ // Legacy memory lower than 1MB might be accessed with no allocation. Leave
+ // them alone.
+ //
+ if (BaseAddress < BASE_1MB) {
+ return;
+ }
+
+ MarkFreedPages (BaseAddress, Pages);
+ if (gCpu != NULL) {
+ //
+ // Set flag to make sure allocating memory without GUARD for page table
+ // operation; otherwise infinite loops could be caused.
+ //
+ mOnGuarding = TRUE;
+ //
+ // Note: This might overwrite other attributes needed by other features,
+ // such as NX memory protection.
+ //
+ Status = gCpu->SetMemoryAttributes (
+ gCpu,
+ BaseAddress,
+ EFI_PAGES_TO_SIZE (Pages),
+ EFI_MEMORY_RP
+ );
+ //
+ // Normally we should ASSERT the returned Status. But there might be memory
+ // alloc/free involved in SetMemoryAttributes(), which might fail this
+ // calling. It's rare case so it's OK to let a few tiny holes be not-guarded.
+ //
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_WARN, "Failed to guard freed pages: %p (%lu)\n", BaseAddress, (UINT64)Pages));
+ }
+ mOnGuarding = FALSE;
+ }
+}
+
+/**
+ Record freed pages as well as mark them as not-present, if enabled.
+
+ @param[in] BaseAddress Base address of just freed pages.
+ @param[in] Pages Number of freed pages.
+
+ @return VOID.
+**/
+VOID
+EFIAPI
+GuardFreedPagesChecked (
+ IN EFI_PHYSICAL_ADDRESS BaseAddress,
+ IN UINTN Pages
+ )
+{
+ if (IsHeapGuardEnabled (GUARD_HEAP_TYPE_FREED)) {
+ GuardFreedPages (BaseAddress, Pages);
+ }
+}
+
+/**
+ Mark all pages freed before CPU Arch Protocol as not-present.
+
+**/
+VOID
+GuardAllFreedPages (
+ VOID
+ )
+{
+ UINTN Entries[GUARDED_HEAP_MAP_TABLE_DEPTH];
+ UINTN Shifts[GUARDED_HEAP_MAP_TABLE_DEPTH];
+ UINTN Indices[GUARDED_HEAP_MAP_TABLE_DEPTH];
+ UINT64 Tables[GUARDED_HEAP_MAP_TABLE_DEPTH];
+ UINT64 Addresses[GUARDED_HEAP_MAP_TABLE_DEPTH];
+ UINT64 TableEntry;
+ UINT64 Address;
+ UINT64 GuardPage;
+ INTN Level;
+ UINT64 BitIndex;
+ UINTN GuardPageNumber;
+
+ if (mGuardedMemoryMap == 0 ||
+ mMapLevel == 0 ||
+ mMapLevel > GUARDED_HEAP_MAP_TABLE_DEPTH) {
+ return;
+ }
+
+ CopyMem (Entries, mLevelMask, sizeof (Entries));
+ CopyMem (Shifts, mLevelShift, sizeof (Shifts));
+
+ SetMem (Tables, sizeof(Tables), 0);
+ SetMem (Addresses, sizeof(Addresses), 0);
+ SetMem (Indices, sizeof(Indices), 0);
+
+ Level = GUARDED_HEAP_MAP_TABLE_DEPTH - mMapLevel;
+ Tables[Level] = mGuardedMemoryMap;
+ Address = 0;
+ GuardPage = (UINT64)-1;
+ GuardPageNumber = 0;
+
+ while (TRUE) {
+ if (Indices[Level] > Entries[Level]) {
+ Tables[Level] = 0;
+ Level -= 1;
+ } else {
+ TableEntry = ((UINT64 *)(UINTN)(Tables[Level]))[Indices[Level]];
+ Address = Addresses[Level];
+
+ if (Level < GUARDED_HEAP_MAP_TABLE_DEPTH - 1) {
+ Level += 1;
+ Tables[Level] = TableEntry;
+ Addresses[Level] = Address;
+ Indices[Level] = 0;
+
+ continue;
+ } else {
+ BitIndex = 1;
+ while (BitIndex != 0) {
+ if ((TableEntry & BitIndex) != 0) {
+ if (GuardPage == (UINT64)-1) {
+ GuardPage = Address;
+ }
+ ++GuardPageNumber;
+ } else if (GuardPageNumber > 0) {
+ GuardFreedPages (GuardPage, GuardPageNumber);
+ GuardPageNumber = 0;
+ GuardPage = (UINT64)-1;
+ }
+
+ if (TableEntry == 0) {
+ break;
+ }
+
+ Address += EFI_PAGES_TO_SIZE (1);
+ BitIndex = LShiftU64 (BitIndex, 1);
+ }
+ }
+ }
+
+ if (Level < (GUARDED_HEAP_MAP_TABLE_DEPTH - (INTN)mMapLevel)) {
+ break;
+ }
+
+ Indices[Level] += 1;
+ Address = (Level == 0) ? 0 : Addresses[Level - 1];
+ Addresses[Level] = Address | LShiftU64 (Indices[Level], Shifts[Level]);
+
+ }
+
+ //
+ // Update the maximum address of freed page which can be used for memory
+ // promotion upon out-of-memory-space.
+ //
+ GetLastGuardedFreePageAddress (&Address);
+ if (Address != 0) {
+ mLastPromotedPage = Address;
+ }
+}
+
+/**
+ This function checks to see if the given memory map descriptor in a memory map
+ can be merged with any guarded free pages.
+
+ @param MemoryMapEntry A pointer to a descriptor in MemoryMap.
+ @param MaxAddress Maximum address to stop the merge.
+
+ @return VOID
+
+**/
+VOID
+MergeGuardPages (
+ IN EFI_MEMORY_DESCRIPTOR *MemoryMapEntry,
+ IN EFI_PHYSICAL_ADDRESS MaxAddress
+ )
+{
+ EFI_PHYSICAL_ADDRESS EndAddress;
+ UINT64 Bitmap;
+ INTN Pages;
+
+ if (!IsHeapGuardEnabled (GUARD_HEAP_TYPE_FREED) ||
+ MemoryMapEntry->Type >= EfiMemoryMappedIO) {
+ return;
+ }
+
+ Bitmap = 0;
+ Pages = EFI_SIZE_TO_PAGES ((UINTN)(MaxAddress - MemoryMapEntry->PhysicalStart));
+ Pages -= (INTN)MemoryMapEntry->NumberOfPages;
+ while (Pages > 0) {
+ if (Bitmap == 0) {
+ EndAddress = MemoryMapEntry->PhysicalStart +
+ EFI_PAGES_TO_SIZE ((UINTN)MemoryMapEntry->NumberOfPages);
+ Bitmap = GetGuardedMemoryBits (EndAddress, GUARDED_HEAP_MAP_ENTRY_BITS);
+ }
+
+ if ((Bitmap & 1) == 0) {
+ break;
+ }
+
+ Pages--;
+ MemoryMapEntry->NumberOfPages++;
+ Bitmap = RShiftU64 (Bitmap, 1);
+ }
+}
+
+/**
+ Put part (at most 64 pages a time) guarded free pages back to free page pool.
+
+ Freed memory guard is used to detect Use-After-Free (UAF) memory issue, which
+ makes use of 'Used then throw away' way to detect any illegal access to freed
+ memory. The thrown-away memory will be marked as not-present so that any access
+ to those memory (after free) will be caught by page-fault exception.
+
+ The problem is that this will consume lots of memory space. Once no memory
+ left in pool to allocate, we have to restore part of the freed pages to their
+ normal function. Otherwise the whole system will stop functioning.
+
+ @param StartAddress Start address of promoted memory.
+ @param EndAddress End address of promoted memory.
+
+ @return TRUE Succeeded to promote memory.
+ @return FALSE No free memory found.
+
+**/
+BOOLEAN
+PromoteGuardedFreePages (
+ OUT EFI_PHYSICAL_ADDRESS *StartAddress,
+ OUT EFI_PHYSICAL_ADDRESS *EndAddress
+ )
+{
+ EFI_STATUS Status;
+ UINTN AvailablePages;
+ UINT64 Bitmap;
+ EFI_PHYSICAL_ADDRESS Start;
+
+ if (!IsHeapGuardEnabled (GUARD_HEAP_TYPE_FREED)) {
+ return FALSE;
+ }
+
+ //
+ // Similar to memory allocation service, always search the freed pages in
+ // descending direction.
+ //
+ Start = mLastPromotedPage;
+ AvailablePages = 0;
+ while (AvailablePages == 0) {
+ Start -= EFI_PAGES_TO_SIZE (GUARDED_HEAP_MAP_ENTRY_BITS);
+ //
+ // If the address wraps around, try the really freed pages at top.
+ //
+ if (Start > mLastPromotedPage) {
+ GetLastGuardedFreePageAddress (&Start);
+ ASSERT (Start != 0);
+ Start -= EFI_PAGES_TO_SIZE (GUARDED_HEAP_MAP_ENTRY_BITS);
+ }
+
+ Bitmap = GetGuardedMemoryBits (Start, GUARDED_HEAP_MAP_ENTRY_BITS);
+ while (Bitmap > 0) {
+ if ((Bitmap & 1) != 0) {
+ ++AvailablePages;
+ } else if (AvailablePages == 0) {
+ Start += EFI_PAGES_TO_SIZE (1);
+ } else {
+ break;
+ }
+
+ Bitmap = RShiftU64 (Bitmap, 1);
+ }
+ }
+
+ if (AvailablePages != 0) {
+ DEBUG ((DEBUG_INFO, "Promoted pages: %lX (%lx)\r\n", Start, (UINT64)AvailablePages));
+ ClearGuardedMemoryBits (Start, AvailablePages);
+
+ if (gCpu != NULL) {
+ //
+ // Set flag to make sure allocating memory without GUARD for page table
+ // operation; otherwise infinite loops could be caused.
+ //
+ mOnGuarding = TRUE;
+ Status = gCpu->SetMemoryAttributes (gCpu, Start, EFI_PAGES_TO_SIZE(AvailablePages), 0);
+ ASSERT_EFI_ERROR (Status);
+ mOnGuarding = FALSE;
+ }
+
+ mLastPromotedPage = Start;
+ *StartAddress = Start;
+ *EndAddress = Start + EFI_PAGES_TO_SIZE (AvailablePages) - 1;
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+/**
+ Notify function used to set all Guard pages before CPU Arch Protocol installed.
+**/
+VOID
+HeapGuardCpuArchProtocolNotify (
+ VOID
+ )
+{
+ ASSERT (gCpu != NULL);
+
+ if (IsHeapGuardEnabled (GUARD_HEAP_TYPE_PAGE|GUARD_HEAP_TYPE_POOL) &&
+ IsHeapGuardEnabled (GUARD_HEAP_TYPE_FREED)) {
+ DEBUG ((DEBUG_ERROR, "Heap guard and freed memory guard cannot be enabled at the same time.\n"));
+ CpuDeadLoop ();
+ }
+
+ if (IsHeapGuardEnabled (GUARD_HEAP_TYPE_PAGE|GUARD_HEAP_TYPE_POOL)) {
+ SetAllGuardPages ();
+ }
+
+ if (IsHeapGuardEnabled (GUARD_HEAP_TYPE_FREED)) {
+ GuardAllFreedPages ();
+ }
+}
+
+/**
+ Helper function to convert a UINT64 value in binary to a string.
+
+ @param[in] Value Value of a UINT64 integer.
+ @param[out] BinString String buffer to contain the conversion result.
+
+ @return VOID.
+**/
+VOID
+Uint64ToBinString (
+ IN UINT64 Value,
+ OUT CHAR8 *BinString
+ )
+{
+ UINTN Index;
+
+ if (BinString == NULL) {
+ return;
+ }
+
+ for (Index = 64; Index > 0; --Index) {
+ BinString[Index - 1] = '0' + (Value & 1);
+ Value = RShiftU64 (Value, 1);
+ }
+ BinString[64] = '\0';
+}
+
+/**
+ Dump the guarded memory bit map.
+**/
+VOID
+EFIAPI
+DumpGuardedMemoryBitmap (
+ VOID
+ )
+{
+ UINTN Entries[GUARDED_HEAP_MAP_TABLE_DEPTH];
+ UINTN Shifts[GUARDED_HEAP_MAP_TABLE_DEPTH];
+ UINTN Indices[GUARDED_HEAP_MAP_TABLE_DEPTH];
+ UINT64 Tables[GUARDED_HEAP_MAP_TABLE_DEPTH];
+ UINT64 Addresses[GUARDED_HEAP_MAP_TABLE_DEPTH];
+ UINT64 TableEntry;
+ UINT64 Address;
+ INTN Level;
+ UINTN RepeatZero;
+ CHAR8 String[GUARDED_HEAP_MAP_ENTRY_BITS + 1];
+ CHAR8 *Ruler1;
+ CHAR8 *Ruler2;
+
+ if (!IsHeapGuardEnabled (GUARD_HEAP_TYPE_ALL)) {
+ return;
+ }
+
+ if (mGuardedMemoryMap == 0 ||
+ mMapLevel == 0 ||
+ mMapLevel > GUARDED_HEAP_MAP_TABLE_DEPTH) {
+ return;
+ }
+
+ Ruler1 = " 3 2 1 0";
+ Ruler2 = "FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210";
+
+ DEBUG ((HEAP_GUARD_DEBUG_LEVEL, "============================="
+ " Guarded Memory Bitmap "
+ "==============================\r\n"));
+ DEBUG ((HEAP_GUARD_DEBUG_LEVEL, " %a\r\n", Ruler1));
+ DEBUG ((HEAP_GUARD_DEBUG_LEVEL, " %a\r\n", Ruler2));
+
+ CopyMem (Entries, mLevelMask, sizeof (Entries));
+ CopyMem (Shifts, mLevelShift, sizeof (Shifts));
+
+ SetMem (Indices, sizeof(Indices), 0);
+ SetMem (Tables, sizeof(Tables), 0);
+ SetMem (Addresses, sizeof(Addresses), 0);
+
+ Level = GUARDED_HEAP_MAP_TABLE_DEPTH - mMapLevel;
+ Tables[Level] = mGuardedMemoryMap;
+ Address = 0;
+ RepeatZero = 0;
+
+ while (TRUE) {
+ if (Indices[Level] > Entries[Level]) {
+
+ Tables[Level] = 0;
+ Level -= 1;
+ RepeatZero = 0;
+
+ DEBUG ((
+ HEAP_GUARD_DEBUG_LEVEL,
+ "========================================="
+ "=========================================\r\n"
+ ));
+
+ } else {
+
+ TableEntry = ((UINT64 *)(UINTN)Tables[Level])[Indices[Level]];
+ Address = Addresses[Level];
+
+ if (TableEntry == 0) {
+
+ if (Level == GUARDED_HEAP_MAP_TABLE_DEPTH - 1) {
+ if (RepeatZero == 0) {
+ Uint64ToBinString(TableEntry, String);
+ DEBUG ((HEAP_GUARD_DEBUG_LEVEL, "%016lx: %a\r\n", Address, String));
+ } else if (RepeatZero == 1) {
+ DEBUG ((HEAP_GUARD_DEBUG_LEVEL, "... : ...\r\n"));
+ }
+ RepeatZero += 1;
+ }
+
+ } else if (Level < GUARDED_HEAP_MAP_TABLE_DEPTH - 1) {
+
+ Level += 1;
+ Tables[Level] = TableEntry;
+ Addresses[Level] = Address;
+ Indices[Level] = 0;
+ RepeatZero = 0;
+
+ continue;
+
+ } else {
+
+ RepeatZero = 0;
+ Uint64ToBinString(TableEntry, String);
+ DEBUG ((HEAP_GUARD_DEBUG_LEVEL, "%016lx: %a\r\n", Address, String));
+
+ }
+ }
+
+ if (Level < (GUARDED_HEAP_MAP_TABLE_DEPTH - (INTN)mMapLevel)) {
+ break;
+ }
+
+ Indices[Level] += 1;
+ Address = (Level == 0) ? 0 : Addresses[Level - 1];
+ Addresses[Level] = Address | LShiftU64(Indices[Level], Shifts[Level]);
+
+ }
+}
+
diff --git a/roms/edk2/MdeModulePkg/Core/Dxe/Mem/HeapGuard.h b/roms/edk2/MdeModulePkg/Core/Dxe/Mem/HeapGuard.h
new file mode 100644
index 000000000..d6e4ed39d
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Core/Dxe/Mem/HeapGuard.h
@@ -0,0 +1,467 @@
+/** @file
+ Data type, macros and function prototypes of heap guard feature.
+
+Copyright (c) 2017-2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _HEAPGUARD_H_
+#define _HEAPGUARD_H_
+
+//
+// Following macros are used to define and access the guarded memory bitmap
+// table.
+//
+// To simplify the access and reduce the memory used for this table, the
+// table is constructed in the similar way as page table structure but in
+// reverse direction, i.e. from bottom growing up to top.
+//
+// - 1-bit tracks 1 page (4KB)
+// - 1-UINT64 map entry tracks 256KB memory
+// - 1K-UINT64 map table tracks 256MB memory
+// - Five levels of tables can track any address of memory of 64-bit
+// system, like below.
+//
+// 512 * 512 * 512 * 512 * 1K * 64b * 4K
+// 111111111 111111111 111111111 111111111 1111111111 111111 111111111111
+// 63 54 45 36 27 17 11 0
+// 9b 9b 9b 9b 10b 6b 12b
+// L0 -> L1 -> L2 -> L3 -> L4 -> bits -> page
+// 1FF 1FF 1FF 1FF 3FF 3F FFF
+//
+// L4 table has 1K * sizeof(UINT64) = 8K (2-page), which can track 256MB
+// memory. Each table of L0-L3 will be allocated when its memory address
+// range is to be tracked. Only 1-page will be allocated each time. This
+// can save memories used to establish this map table.
+//
+// For a normal configuration of system with 4G memory, two levels of tables
+// can track the whole memory, because two levels (L3+L4) of map tables have
+// already coverred 37-bit of memory address. And for a normal UEFI BIOS,
+// less than 128M memory would be consumed during boot. That means we just
+// need
+//
+// 1-page (L3) + 2-page (L4)
+//
+// memory (3 pages) to track the memory allocation works. In this case,
+// there's no need to setup L0-L2 tables.
+//
+
+//
+// Each entry occupies 8B/64b. 1-page can hold 512 entries, which spans 9
+// bits in address. (512 = 1 << 9)
+//
+#define BYTE_LENGTH_SHIFT 3 // (8 = 1 << 3)
+
+#define GUARDED_HEAP_MAP_TABLE_ENTRY_SHIFT \
+ (EFI_PAGE_SHIFT - BYTE_LENGTH_SHIFT)
+
+#define GUARDED_HEAP_MAP_TABLE_DEPTH 5
+
+// Use UINT64_index + bit_index_of_UINT64 to locate the bit in may
+#define GUARDED_HEAP_MAP_ENTRY_BIT_SHIFT 6 // (64 = 1 << 6)
+
+#define GUARDED_HEAP_MAP_ENTRY_BITS \
+ (1 << GUARDED_HEAP_MAP_ENTRY_BIT_SHIFT)
+
+#define GUARDED_HEAP_MAP_ENTRY_BYTES \
+ (GUARDED_HEAP_MAP_ENTRY_BITS / 8)
+
+// L4 table address width: 64 - 9 * 4 - 6 - 12 = 10b
+#define GUARDED_HEAP_MAP_ENTRY_SHIFT \
+ (GUARDED_HEAP_MAP_ENTRY_BITS \
+ - GUARDED_HEAP_MAP_TABLE_ENTRY_SHIFT * 4 \
+ - GUARDED_HEAP_MAP_ENTRY_BIT_SHIFT \
+ - EFI_PAGE_SHIFT)
+
+// L4 table address mask: (1 << 10 - 1) = 0x3FF
+#define GUARDED_HEAP_MAP_ENTRY_MASK \
+ ((1 << GUARDED_HEAP_MAP_ENTRY_SHIFT) - 1)
+
+// Size of each L4 table: (1 << 10) * 8 = 8KB = 2-page
+#define GUARDED_HEAP_MAP_SIZE \
+ ((1 << GUARDED_HEAP_MAP_ENTRY_SHIFT) * GUARDED_HEAP_MAP_ENTRY_BYTES)
+
+// Memory size tracked by one L4 table: 8KB * 8 * 4KB = 256MB
+#define GUARDED_HEAP_MAP_UNIT_SIZE \
+ (GUARDED_HEAP_MAP_SIZE * 8 * EFI_PAGE_SIZE)
+
+// L4 table entry number: 8KB / 8 = 1024
+#define GUARDED_HEAP_MAP_ENTRIES_PER_UNIT \
+ (GUARDED_HEAP_MAP_SIZE / GUARDED_HEAP_MAP_ENTRY_BYTES)
+
+// L4 table entry indexing
+#define GUARDED_HEAP_MAP_ENTRY_INDEX(Address) \
+ (RShiftU64 (Address, EFI_PAGE_SHIFT \
+ + GUARDED_HEAP_MAP_ENTRY_BIT_SHIFT) \
+ & GUARDED_HEAP_MAP_ENTRY_MASK)
+
+// L4 table entry bit indexing
+#define GUARDED_HEAP_MAP_ENTRY_BIT_INDEX(Address) \
+ (RShiftU64 (Address, EFI_PAGE_SHIFT) \
+ & ((1 << GUARDED_HEAP_MAP_ENTRY_BIT_SHIFT) - 1))
+
+//
+// Total bits (pages) tracked by one L4 table (65536-bit)
+//
+#define GUARDED_HEAP_MAP_BITS \
+ (1 << (GUARDED_HEAP_MAP_ENTRY_SHIFT \
+ + GUARDED_HEAP_MAP_ENTRY_BIT_SHIFT))
+
+//
+// Bit indexing inside the whole L4 table (0 - 65535)
+//
+#define GUARDED_HEAP_MAP_BIT_INDEX(Address) \
+ (RShiftU64 (Address, EFI_PAGE_SHIFT) \
+ & ((1 << (GUARDED_HEAP_MAP_ENTRY_SHIFT \
+ + GUARDED_HEAP_MAP_ENTRY_BIT_SHIFT)) - 1))
+
+//
+// Memory address bit width tracked by L4 table: 10 + 6 + 12 = 28
+//
+#define GUARDED_HEAP_MAP_TABLE_SHIFT \
+ (GUARDED_HEAP_MAP_ENTRY_SHIFT + GUARDED_HEAP_MAP_ENTRY_BIT_SHIFT \
+ + EFI_PAGE_SHIFT)
+
+//
+// Macro used to initialize the local array variable for map table traversing
+// {55, 46, 37, 28, 18}
+//
+#define GUARDED_HEAP_MAP_TABLE_DEPTH_SHIFTS \
+ { \
+ GUARDED_HEAP_MAP_TABLE_SHIFT + GUARDED_HEAP_MAP_TABLE_ENTRY_SHIFT * 3, \
+ GUARDED_HEAP_MAP_TABLE_SHIFT + GUARDED_HEAP_MAP_TABLE_ENTRY_SHIFT * 2, \
+ GUARDED_HEAP_MAP_TABLE_SHIFT + GUARDED_HEAP_MAP_TABLE_ENTRY_SHIFT, \
+ GUARDED_HEAP_MAP_TABLE_SHIFT, \
+ EFI_PAGE_SHIFT + GUARDED_HEAP_MAP_ENTRY_BIT_SHIFT \
+ }
+
+//
+// Masks used to extract address range of each level of table
+// {0x1FF, 0x1FF, 0x1FF, 0x1FF, 0x3FF}
+//
+#define GUARDED_HEAP_MAP_TABLE_DEPTH_MASKS \
+ { \
+ (1 << GUARDED_HEAP_MAP_TABLE_ENTRY_SHIFT) - 1, \
+ (1 << GUARDED_HEAP_MAP_TABLE_ENTRY_SHIFT) - 1, \
+ (1 << GUARDED_HEAP_MAP_TABLE_ENTRY_SHIFT) - 1, \
+ (1 << GUARDED_HEAP_MAP_TABLE_ENTRY_SHIFT) - 1, \
+ (1 << GUARDED_HEAP_MAP_ENTRY_SHIFT) - 1 \
+ }
+
+//
+// Memory type to guard (matching the related PCD definition)
+//
+#define GUARD_HEAP_TYPE_PAGE BIT0
+#define GUARD_HEAP_TYPE_POOL BIT1
+#define GUARD_HEAP_TYPE_FREED BIT4
+#define GUARD_HEAP_TYPE_ALL \
+ (GUARD_HEAP_TYPE_PAGE|GUARD_HEAP_TYPE_POOL|GUARD_HEAP_TYPE_FREED)
+
+//
+// Debug message level
+//
+#define HEAP_GUARD_DEBUG_LEVEL (DEBUG_POOL|DEBUG_PAGE)
+
+typedef struct {
+ UINT32 TailMark;
+ UINT32 HeadMark;
+ EFI_PHYSICAL_ADDRESS Address;
+ LIST_ENTRY Link;
+} HEAP_GUARD_NODE;
+
+/**
+ Internal function. Converts a memory range to the specified type.
+ The range must exist in the memory map.
+
+ @param Start The first address of the range Must be page
+ aligned.
+ @param NumberOfPages The number of pages to convert.
+ @param NewType The new type for the memory range.
+
+ @retval EFI_INVALID_PARAMETER Invalid parameter.
+ @retval EFI_NOT_FOUND Could not find a descriptor cover the specified
+ range or convertion not allowed.
+ @retval EFI_SUCCESS Successfully converts the memory range to the
+ specified type.
+
+**/
+EFI_STATUS
+CoreConvertPages (
+ IN UINT64 Start,
+ IN UINT64 NumberOfPages,
+ IN EFI_MEMORY_TYPE NewType
+ );
+
+/**
+ Allocate or free guarded memory.
+
+ @param[in] Start Start address of memory to allocate or free.
+ @param[in] NumberOfPages Memory size in pages.
+ @param[in] NewType Memory type to convert to.
+
+ @return VOID.
+**/
+EFI_STATUS
+CoreConvertPagesWithGuard (
+ IN UINT64 Start,
+ IN UINTN NumberOfPages,
+ IN EFI_MEMORY_TYPE NewType
+ );
+
+/**
+ Set head Guard and tail Guard for the given memory range.
+
+ @param[in] Memory Base address of memory to set guard for.
+ @param[in] NumberOfPages Memory size in pages.
+
+ @return VOID.
+**/
+VOID
+SetGuardForMemory (
+ IN EFI_PHYSICAL_ADDRESS Memory,
+ IN UINTN NumberOfPages
+ );
+
+/**
+ Unset head Guard and tail Guard for the given memory range.
+
+ @param[in] Memory Base address of memory to unset guard for.
+ @param[in] NumberOfPages Memory size in pages.
+
+ @return VOID.
+**/
+VOID
+UnsetGuardForMemory (
+ IN EFI_PHYSICAL_ADDRESS Memory,
+ IN UINTN NumberOfPages
+ );
+
+/**
+ Adjust the base and number of pages to really allocate according to Guard.
+
+ @param[in,out] Memory Base address of free memory.
+ @param[in,out] NumberOfPages Size of memory to allocate.
+
+ @return VOID.
+**/
+VOID
+AdjustMemoryA (
+ IN OUT EFI_PHYSICAL_ADDRESS *Memory,
+ IN OUT UINTN *NumberOfPages
+ );
+
+/**
+ Adjust the start address and number of pages to free according to Guard.
+
+ The purpose of this function is to keep the shared Guard page with adjacent
+ memory block if it's still in guard, or free it if no more sharing. Another
+ is to reserve pages as Guard pages in partial page free situation.
+
+ @param[in,out] Memory Base address of memory to free.
+ @param[in,out] NumberOfPages Size of memory to free.
+
+ @return VOID.
+**/
+VOID
+AdjustMemoryF (
+ IN OUT EFI_PHYSICAL_ADDRESS *Memory,
+ IN OUT UINTN *NumberOfPages
+ );
+
+/**
+ Adjust address of free memory according to existing and/or required Guard.
+
+ This function will check if there're existing Guard pages of adjacent
+ memory blocks, and try to use it as the Guard page of the memory to be
+ allocated.
+
+ @param[in] Start Start address of free memory block.
+ @param[in] Size Size of free memory block.
+ @param[in] SizeRequested Size of memory to allocate.
+
+ @return The end address of memory block found.
+ @return 0 if no enough space for the required size of memory and its Guard.
+**/
+UINT64
+AdjustMemoryS (
+ IN UINT64 Start,
+ IN UINT64 Size,
+ IN UINT64 SizeRequested
+ );
+
+/**
+ Check to see if the pool at the given address should be guarded or not.
+
+ @param[in] MemoryType Pool type to check.
+
+
+ @return TRUE The given type of pool should be guarded.
+ @return FALSE The given type of pool should not be guarded.
+**/
+BOOLEAN
+IsPoolTypeToGuard (
+ IN EFI_MEMORY_TYPE MemoryType
+ );
+
+/**
+ Check to see if the page at the given address should be guarded or not.
+
+ @param[in] MemoryType Page type to check.
+ @param[in] AllocateType Allocation type to check.
+
+ @return TRUE The given type of page should be guarded.
+ @return FALSE The given type of page should not be guarded.
+**/
+BOOLEAN
+IsPageTypeToGuard (
+ IN EFI_MEMORY_TYPE MemoryType,
+ IN EFI_ALLOCATE_TYPE AllocateType
+ );
+
+/**
+ Check to see if the page at the given address is guarded or not.
+
+ @param[in] Address The address to check for.
+
+ @return TRUE The page at Address is guarded.
+ @return FALSE The page at Address is not guarded.
+**/
+BOOLEAN
+EFIAPI
+IsMemoryGuarded (
+ IN EFI_PHYSICAL_ADDRESS Address
+ );
+
+/**
+ Check to see if the page at the given address is a Guard page or not.
+
+ @param[in] Address The address to check for.
+
+ @return TRUE The page at Address is a Guard page.
+ @return FALSE The page at Address is not a Guard page.
+**/
+BOOLEAN
+EFIAPI
+IsGuardPage (
+ IN EFI_PHYSICAL_ADDRESS Address
+ );
+
+/**
+ Dump the guarded memory bit map.
+**/
+VOID
+EFIAPI
+DumpGuardedMemoryBitmap (
+ VOID
+ );
+
+/**
+ Adjust the pool head position to make sure the Guard page is adjavent to
+ pool tail or pool head.
+
+ @param[in] Memory Base address of memory allocated.
+ @param[in] NoPages Number of pages actually allocated.
+ @param[in] Size Size of memory requested.
+ (plus pool head/tail overhead)
+
+ @return Address of pool head.
+**/
+VOID *
+AdjustPoolHeadA (
+ IN EFI_PHYSICAL_ADDRESS Memory,
+ IN UINTN NoPages,
+ IN UINTN Size
+ );
+
+/**
+ Get the page base address according to pool head address.
+
+ @param[in] Memory Head address of pool to free.
+
+ @return Address of pool head.
+**/
+VOID *
+AdjustPoolHeadF (
+ IN EFI_PHYSICAL_ADDRESS Memory
+ );
+
+/**
+ Check to see if the heap guard is enabled for page and/or pool allocation.
+
+ @param[in] GuardType Specify the sub-type(s) of Heap Guard.
+
+ @return TRUE/FALSE.
+**/
+BOOLEAN
+IsHeapGuardEnabled (
+ UINT8 GuardType
+ );
+
+/**
+ Notify function used to set all Guard pages after CPU Arch Protocol installed.
+**/
+VOID
+HeapGuardCpuArchProtocolNotify (
+ VOID
+ );
+
+/**
+ This function checks to see if the given memory map descriptor in a memory map
+ can be merged with any guarded free pages.
+
+ @param MemoryMapEntry A pointer to a descriptor in MemoryMap.
+ @param MaxAddress Maximum address to stop the merge.
+
+ @return VOID
+
+**/
+VOID
+MergeGuardPages (
+ IN EFI_MEMORY_DESCRIPTOR *MemoryMapEntry,
+ IN EFI_PHYSICAL_ADDRESS MaxAddress
+ );
+
+/**
+ Record freed pages as well as mark them as not-present, if enabled.
+
+ @param[in] BaseAddress Base address of just freed pages.
+ @param[in] Pages Number of freed pages.
+
+ @return VOID.
+**/
+VOID
+EFIAPI
+GuardFreedPagesChecked (
+ IN EFI_PHYSICAL_ADDRESS BaseAddress,
+ IN UINTN Pages
+ );
+
+/**
+ Put part (at most 64 pages a time) guarded free pages back to free page pool.
+
+ Freed memory guard is used to detect Use-After-Free (UAF) memory issue, which
+ makes use of 'Used then throw away' way to detect any illegal access to freed
+ memory. The thrown-away memory will be marked as not-present so that any access
+ to those memory (after free) will be caught by page-fault exception.
+
+ The problem is that this will consume lots of memory space. Once no memory
+ left in pool to allocate, we have to restore part of the freed pages to their
+ normal function. Otherwise the whole system will stop functioning.
+
+ @param StartAddress Start address of promoted memory.
+ @param EndAddress End address of promoted memory.
+
+ @return TRUE Succeeded to promote memory.
+ @return FALSE No free memory found.
+
+**/
+BOOLEAN
+PromoteGuardedFreePages (
+ OUT EFI_PHYSICAL_ADDRESS *StartAddress,
+ OUT EFI_PHYSICAL_ADDRESS *EndAddress
+ );
+
+extern BOOLEAN mOnGuarding;
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Core/Dxe/Mem/Imem.h b/roms/edk2/MdeModulePkg/Core/Dxe/Mem/Imem.h
new file mode 100644
index 000000000..090f3f089
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Core/Dxe/Mem/Imem.h
@@ -0,0 +1,182 @@
+/** @file
+ Data structure and functions to allocate and free memory space.
+
+Copyright (c) 2006 - 2017, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _IMEM_H_
+#define _IMEM_H_
+
+//
+// +---------------------------------------------------+
+// | 0..(EfiMaxMemoryType - 1) - Normal memory type |
+// +---------------------------------------------------+
+// | EfiMaxMemoryType..0x6FFFFFFF - Invalid |
+// +---------------------------------------------------+
+// | 0x70000000..0x7FFFFFFF - OEM reserved |
+// +---------------------------------------------------+
+// | 0x80000000..0xFFFFFFFF - OS reserved |
+// +---------------------------------------------------+
+//
+#define MEMORY_TYPE_OS_RESERVED_MIN 0x80000000
+#define MEMORY_TYPE_OS_RESERVED_MAX 0xFFFFFFFF
+#define MEMORY_TYPE_OEM_RESERVED_MIN 0x70000000
+#define MEMORY_TYPE_OEM_RESERVED_MAX 0x7FFFFFFF
+
+//
+// MEMORY_MAP_ENTRY
+//
+
+#define MEMORY_MAP_SIGNATURE SIGNATURE_32('m','m','a','p')
+typedef struct {
+ UINTN Signature;
+ LIST_ENTRY Link;
+ BOOLEAN FromPages;
+
+ EFI_MEMORY_TYPE Type;
+ UINT64 Start;
+ UINT64 End;
+
+ UINT64 VirtualStart;
+ UINT64 Attribute;
+} MEMORY_MAP;
+
+//
+// Internal prototypes
+//
+
+
+/**
+ Internal function. Used by the pool functions to allocate pages
+ to back pool allocation requests.
+
+ @param PoolType The type of memory for the new pool pages
+ @param NumberOfPages No of pages to allocate
+ @param Alignment Bits to align.
+ @param NeedGuard Flag to indicate Guard page is needed or not
+
+ @return The allocated memory, or NULL
+
+**/
+VOID *
+CoreAllocatePoolPages (
+ IN EFI_MEMORY_TYPE PoolType,
+ IN UINTN NumberOfPages,
+ IN UINTN Alignment,
+ IN BOOLEAN NeedGuard
+ );
+
+
+
+/**
+ Internal function. Frees pool pages allocated via AllocatePoolPages ()
+
+ @param Memory The base address to free
+ @param NumberOfPages The number of pages to free
+
+**/
+VOID
+CoreFreePoolPages (
+ IN EFI_PHYSICAL_ADDRESS Memory,
+ IN UINTN NumberOfPages
+ );
+
+
+
+/**
+ Internal function to allocate pool of a particular type.
+ Caller must have the memory lock held
+
+ @param PoolType Type of pool to allocate
+ @param Size The amount of pool to allocate
+ @param NeedGuard Flag to indicate Guard page is needed or not
+
+ @return The allocate pool, or NULL
+
+**/
+VOID *
+CoreAllocatePoolI (
+ IN EFI_MEMORY_TYPE PoolType,
+ IN UINTN Size,
+ IN BOOLEAN NeedGuard
+ );
+
+
+
+/**
+ Internal function to free a pool entry.
+ Caller must have the memory lock held
+
+ @param Buffer The allocated pool entry to free
+ @param PoolType Pointer to pool type
+
+ @retval EFI_INVALID_PARAMETER Buffer not valid
+ @retval EFI_SUCCESS Buffer successfully freed.
+
+**/
+EFI_STATUS
+CoreFreePoolI (
+ IN VOID *Buffer,
+ OUT EFI_MEMORY_TYPE *PoolType OPTIONAL
+ );
+
+
+
+/**
+ Enter critical section by gaining lock on gMemoryLock.
+
+**/
+VOID
+CoreAcquireMemoryLock (
+ VOID
+ );
+
+
+/**
+ Exit critical section by releasing lock on gMemoryLock.
+
+**/
+VOID
+CoreReleaseMemoryLock (
+ VOID
+ );
+
+/**
+ Allocates pages from the memory map.
+
+ @param Type The type of allocation to perform
+ @param MemoryType The type of memory to turn the allocated pages
+ into
+ @param NumberOfPages The number of pages to allocate
+ @param Memory A pointer to receive the base allocated memory
+ address
+ @param NeedGuard Flag to indicate Guard page is needed or not
+
+ @return Status. On success, Memory is filled in with the base address allocated
+ @retval EFI_INVALID_PARAMETER Parameters violate checking rules defined in
+ spec.
+ @retval EFI_NOT_FOUND Could not allocate pages match the requirement.
+ @retval EFI_OUT_OF_RESOURCES No enough pages to allocate.
+ @retval EFI_SUCCESS Pages successfully allocated.
+
+**/
+EFI_STATUS
+EFIAPI
+CoreInternalAllocatePages (
+ IN EFI_ALLOCATE_TYPE Type,
+ IN EFI_MEMORY_TYPE MemoryType,
+ IN UINTN NumberOfPages,
+ IN OUT EFI_PHYSICAL_ADDRESS *Memory,
+ IN BOOLEAN NeedGuard
+ );
+
+//
+// Internal Global data
+//
+
+extern EFI_LOCK gMemoryLock;
+extern LIST_ENTRY gMemoryMap;
+extern LIST_ENTRY mGcdMemorySpaceMap;
+#endif
diff --git a/roms/edk2/MdeModulePkg/Core/Dxe/Mem/MemData.c b/roms/edk2/MdeModulePkg/Core/Dxe/Mem/MemData.c
new file mode 100644
index 000000000..67d886832
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Core/Dxe/Mem/MemData.c
@@ -0,0 +1,20 @@
+/** @file
+ Global data used in memory service
+
+Copyright (c) 2006 - 2008, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "DxeMain.h"
+
+
+//
+// MemoryLock - synchronizes access to the memory map and pool lists
+//
+EFI_LOCK gMemoryLock = EFI_INITIALIZE_LOCK_VARIABLE (TPL_NOTIFY);
+
+//
+// MemoryMap - the current memory map
+//
+LIST_ENTRY gMemoryMap = INITIALIZE_LIST_HEAD_VARIABLE (gMemoryMap);
diff --git a/roms/edk2/MdeModulePkg/Core/Dxe/Mem/MemoryProfileRecord.c b/roms/edk2/MdeModulePkg/Core/Dxe/Mem/MemoryProfileRecord.c
new file mode 100644
index 000000000..2ca0417b0
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Core/Dxe/Mem/MemoryProfileRecord.c
@@ -0,0 +1,1759 @@
+/** @file
+ Support routines for UEFI memory profile.
+
+ Copyright (c) 2014 - 2018, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "DxeMain.h"
+#include "Imem.h"
+
+#define IS_UEFI_MEMORY_PROFILE_ENABLED ((PcdGet8 (PcdMemoryProfilePropertyMask) & BIT0) != 0)
+
+#define GET_OCCUPIED_SIZE(ActualSize, Alignment) \
+ ((ActualSize) + (((Alignment) - ((ActualSize) & ((Alignment) - 1))) & ((Alignment) - 1)))
+
+typedef struct {
+ UINT32 Signature;
+ MEMORY_PROFILE_CONTEXT Context;
+ LIST_ENTRY *DriverInfoList;
+} MEMORY_PROFILE_CONTEXT_DATA;
+
+typedef struct {
+ UINT32 Signature;
+ MEMORY_PROFILE_DRIVER_INFO DriverInfo;
+ LIST_ENTRY *AllocInfoList;
+ CHAR8 *PdbString;
+ LIST_ENTRY Link;
+} MEMORY_PROFILE_DRIVER_INFO_DATA;
+
+typedef struct {
+ UINT32 Signature;
+ MEMORY_PROFILE_ALLOC_INFO AllocInfo;
+ CHAR8 *ActionString;
+ LIST_ENTRY Link;
+} MEMORY_PROFILE_ALLOC_INFO_DATA;
+
+
+GLOBAL_REMOVE_IF_UNREFERENCED LIST_ENTRY mImageQueue = INITIALIZE_LIST_HEAD_VARIABLE (mImageQueue);
+GLOBAL_REMOVE_IF_UNREFERENCED MEMORY_PROFILE_CONTEXT_DATA mMemoryProfileContext = {
+ MEMORY_PROFILE_CONTEXT_SIGNATURE,
+ {
+ {
+ MEMORY_PROFILE_CONTEXT_SIGNATURE,
+ sizeof (MEMORY_PROFILE_CONTEXT),
+ MEMORY_PROFILE_CONTEXT_REVISION
+ },
+ 0,
+ 0,
+ {0},
+ {0},
+ 0,
+ 0,
+ 0
+ },
+ &mImageQueue,
+};
+GLOBAL_REMOVE_IF_UNREFERENCED MEMORY_PROFILE_CONTEXT_DATA *mMemoryProfileContextPtr = NULL;
+
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_LOCK mMemoryProfileLock = EFI_INITIALIZE_LOCK_VARIABLE (TPL_NOTIFY);
+GLOBAL_REMOVE_IF_UNREFERENCED BOOLEAN mMemoryProfileGettingStatus = FALSE;
+GLOBAL_REMOVE_IF_UNREFERENCED BOOLEAN mMemoryProfileRecordingEnable = MEMORY_PROFILE_RECORDING_DISABLE;
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_DEVICE_PATH_PROTOCOL *mMemoryProfileDriverPath;
+GLOBAL_REMOVE_IF_UNREFERENCED UINTN mMemoryProfileDriverPathSize;
+
+/**
+ Get memory profile data.
+
+ @param[in] This The EDKII_MEMORY_PROFILE_PROTOCOL instance.
+ @param[in, out] ProfileSize On entry, points to the size in bytes of the ProfileBuffer.
+ On return, points to the size of the data returned in ProfileBuffer.
+ @param[out] ProfileBuffer Profile buffer.
+
+ @return EFI_SUCCESS Get the memory profile data successfully.
+ @return EFI_UNSUPPORTED Memory profile is unsupported.
+ @return EFI_BUFFER_TO_SMALL The ProfileSize is too small for the resulting data.
+ ProfileSize is updated with the size required.
+
+**/
+EFI_STATUS
+EFIAPI
+ProfileProtocolGetData (
+ IN EDKII_MEMORY_PROFILE_PROTOCOL *This,
+ IN OUT UINT64 *ProfileSize,
+ OUT VOID *ProfileBuffer
+ );
+
+/**
+ Register image to memory profile.
+
+ @param[in] This The EDKII_MEMORY_PROFILE_PROTOCOL instance.
+ @param[in] FilePath File path of the image.
+ @param[in] ImageBase Image base address.
+ @param[in] ImageSize Image size.
+ @param[in] FileType File type of the image.
+
+ @return EFI_SUCCESS Register successfully.
+ @return EFI_UNSUPPORTED Memory profile is unsupported,
+ or memory profile for the image is not required.
+ @return EFI_OUT_OF_RESOURCE No enough resource for this register.
+
+**/
+EFI_STATUS
+EFIAPI
+ProfileProtocolRegisterImage (
+ IN EDKII_MEMORY_PROFILE_PROTOCOL *This,
+ IN EFI_DEVICE_PATH_PROTOCOL *FilePath,
+ IN PHYSICAL_ADDRESS ImageBase,
+ IN UINT64 ImageSize,
+ IN EFI_FV_FILETYPE FileType
+ );
+
+/**
+ Unregister image from memory profile.
+
+ @param[in] This The EDKII_MEMORY_PROFILE_PROTOCOL instance.
+ @param[in] FilePath File path of the image.
+ @param[in] ImageBase Image base address.
+ @param[in] ImageSize Image size.
+
+ @return EFI_SUCCESS Unregister successfully.
+ @return EFI_UNSUPPORTED Memory profile is unsupported,
+ or memory profile for the image is not required.
+ @return EFI_NOT_FOUND The image is not found.
+
+**/
+EFI_STATUS
+EFIAPI
+ProfileProtocolUnregisterImage (
+ IN EDKII_MEMORY_PROFILE_PROTOCOL *This,
+ IN EFI_DEVICE_PATH_PROTOCOL *FilePath,
+ IN PHYSICAL_ADDRESS ImageBase,
+ IN UINT64 ImageSize
+ );
+
+/**
+ Get memory profile recording state.
+
+ @param[in] This The EDKII_MEMORY_PROFILE_PROTOCOL instance.
+ @param[out] RecordingState Recording state.
+
+ @return EFI_SUCCESS Memory profile recording state is returned.
+ @return EFI_UNSUPPORTED Memory profile is unsupported.
+ @return EFI_INVALID_PARAMETER RecordingState is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+ProfileProtocolGetRecordingState (
+ IN EDKII_MEMORY_PROFILE_PROTOCOL *This,
+ OUT BOOLEAN *RecordingState
+ );
+
+/**
+ Set memory profile recording state.
+
+ @param[in] This The EDKII_MEMORY_PROFILE_PROTOCOL instance.
+ @param[in] RecordingState Recording state.
+
+ @return EFI_SUCCESS Set memory profile recording state successfully.
+ @return EFI_UNSUPPORTED Memory profile is unsupported.
+
+**/
+EFI_STATUS
+EFIAPI
+ProfileProtocolSetRecordingState (
+ IN EDKII_MEMORY_PROFILE_PROTOCOL *This,
+ IN BOOLEAN RecordingState
+ );
+
+/**
+ Record memory profile of multilevel caller.
+
+ @param[in] This The EDKII_MEMORY_PROFILE_PROTOCOL instance.
+ @param[in] CallerAddress Address of caller.
+ @param[in] Action Memory profile action.
+ @param[in] MemoryType Memory type.
+ EfiMaxMemoryType means the MemoryType is unknown.
+ @param[in] Buffer Buffer address.
+ @param[in] Size Buffer size.
+ @param[in] ActionString String for memory profile action.
+ Only needed for user defined allocate action.
+
+ @return EFI_SUCCESS Memory profile is updated.
+ @return EFI_UNSUPPORTED Memory profile is unsupported,
+ or memory profile for the image is not required,
+ or memory profile for the memory type is not required.
+ @return EFI_ACCESS_DENIED It is during memory profile data getting.
+ @return EFI_ABORTED Memory profile recording is not enabled.
+ @return EFI_OUT_OF_RESOURCES No enough resource to update memory profile for allocate action.
+ @return EFI_NOT_FOUND No matched allocate info found for free action.
+
+**/
+EFI_STATUS
+EFIAPI
+ProfileProtocolRecord (
+ IN EDKII_MEMORY_PROFILE_PROTOCOL *This,
+ IN PHYSICAL_ADDRESS CallerAddress,
+ IN MEMORY_PROFILE_ACTION Action,
+ IN EFI_MEMORY_TYPE MemoryType,
+ IN VOID *Buffer,
+ IN UINTN Size,
+ IN CHAR8 *ActionString OPTIONAL
+ );
+
+GLOBAL_REMOVE_IF_UNREFERENCED EDKII_MEMORY_PROFILE_PROTOCOL mProfileProtocol = {
+ ProfileProtocolGetData,
+ ProfileProtocolRegisterImage,
+ ProfileProtocolUnregisterImage,
+ ProfileProtocolGetRecordingState,
+ ProfileProtocolSetRecordingState,
+ ProfileProtocolRecord,
+};
+
+/**
+ Acquire lock on mMemoryProfileLock.
+**/
+VOID
+CoreAcquireMemoryProfileLock (
+ VOID
+ )
+{
+ CoreAcquireLock (&mMemoryProfileLock);
+}
+
+/**
+ Release lock on mMemoryProfileLock.
+**/
+VOID
+CoreReleaseMemoryProfileLock (
+ VOID
+ )
+{
+ CoreReleaseLock (&mMemoryProfileLock);
+}
+
+/**
+ Return memory profile context.
+
+ @return Memory profile context.
+
+**/
+MEMORY_PROFILE_CONTEXT_DATA *
+GetMemoryProfileContext (
+ VOID
+ )
+{
+ return mMemoryProfileContextPtr;
+}
+
+/**
+ Retrieves and returns the Subsystem of a PE/COFF image that has been loaded into system memory.
+ If Pe32Data is NULL, then ASSERT().
+
+ @param Pe32Data The pointer to the PE/COFF image that is loaded in system memory.
+
+ @return The Subsystem of the PE/COFF image.
+
+**/
+UINT16
+InternalPeCoffGetSubsystem (
+ IN VOID *Pe32Data
+ )
+{
+ EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr;
+ EFI_IMAGE_DOS_HEADER *DosHdr;
+ UINT16 Magic;
+
+ ASSERT (Pe32Data != NULL);
+
+ DosHdr = (EFI_IMAGE_DOS_HEADER *) Pe32Data;
+ if (DosHdr->e_magic == EFI_IMAGE_DOS_SIGNATURE) {
+ //
+ // DOS image header is present, so read the PE header after the DOS image header.
+ //
+ Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *) ((UINTN) Pe32Data + (UINTN) ((DosHdr->e_lfanew) & 0x0ffff));
+ } else {
+ //
+ // DOS image header is not present, so PE header is at the image base.
+ //
+ Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *) Pe32Data;
+ }
+
+ if (Hdr.Te->Signature == EFI_TE_IMAGE_HEADER_SIGNATURE) {
+ return Hdr.Te->Subsystem;
+ } else if (Hdr.Pe32->Signature == EFI_IMAGE_NT_SIGNATURE) {
+ Magic = Hdr.Pe32->OptionalHeader.Magic;
+ if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
+ return Hdr.Pe32->OptionalHeader.Subsystem;
+ } else if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC) {
+ return Hdr.Pe32Plus->OptionalHeader.Subsystem;
+ }
+ }
+
+ return 0x0000;
+}
+
+/**
+ Retrieves and returns a pointer to the entry point to a PE/COFF image that has been loaded
+ into system memory with the PE/COFF Loader Library functions.
+
+ Retrieves the entry point to the PE/COFF image specified by Pe32Data and returns this entry
+ point in EntryPoint. If the entry point could not be retrieved from the PE/COFF image, then
+ return RETURN_INVALID_PARAMETER. Otherwise return RETURN_SUCCESS.
+ If Pe32Data is NULL, then ASSERT().
+ If EntryPoint is NULL, then ASSERT().
+
+ @param Pe32Data The pointer to the PE/COFF image that is loaded in system memory.
+ @param EntryPoint The pointer to entry point to the PE/COFF image to return.
+
+ @retval RETURN_SUCCESS EntryPoint was returned.
+ @retval RETURN_INVALID_PARAMETER The entry point could not be found in the PE/COFF image.
+
+**/
+RETURN_STATUS
+InternalPeCoffGetEntryPoint (
+ IN VOID *Pe32Data,
+ OUT VOID **EntryPoint
+ )
+{
+ EFI_IMAGE_DOS_HEADER *DosHdr;
+ EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr;
+
+ ASSERT (Pe32Data != NULL);
+ ASSERT (EntryPoint != NULL);
+
+ DosHdr = (EFI_IMAGE_DOS_HEADER *) Pe32Data;
+ if (DosHdr->e_magic == EFI_IMAGE_DOS_SIGNATURE) {
+ //
+ // DOS image header is present, so read the PE header after the DOS image header.
+ //
+ Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *) ((UINTN) Pe32Data + (UINTN) ((DosHdr->e_lfanew) & 0x0ffff));
+ } else {
+ //
+ // DOS image header is not present, so PE header is at the image base.
+ //
+ Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *) Pe32Data;
+ }
+
+ //
+ // Calculate the entry point relative to the start of the image.
+ // AddressOfEntryPoint is common for PE32 & PE32+
+ //
+ if (Hdr.Te->Signature == EFI_TE_IMAGE_HEADER_SIGNATURE) {
+ *EntryPoint = (VOID *) ((UINTN) Pe32Data + (UINTN) (Hdr.Te->AddressOfEntryPoint & 0x0ffffffff) + sizeof (EFI_TE_IMAGE_HEADER) - Hdr.Te->StrippedSize);
+ return RETURN_SUCCESS;
+ } else if (Hdr.Pe32->Signature == EFI_IMAGE_NT_SIGNATURE) {
+ *EntryPoint = (VOID *) ((UINTN) Pe32Data + (UINTN) (Hdr.Pe32->OptionalHeader.AddressOfEntryPoint & 0x0ffffffff));
+ return RETURN_SUCCESS;
+ }
+
+ return RETURN_UNSUPPORTED;
+}
+
+/**
+ Build driver info.
+
+ @param ContextData Memory profile context.
+ @param FileName File name of the image.
+ @param ImageBase Image base address.
+ @param ImageSize Image size.
+ @param EntryPoint Entry point of the image.
+ @param ImageSubsystem Image subsystem of the image.
+ @param FileType File type of the image.
+
+ @return Pointer to memory profile driver info.
+
+**/
+MEMORY_PROFILE_DRIVER_INFO_DATA *
+BuildDriverInfo (
+ IN MEMORY_PROFILE_CONTEXT_DATA *ContextData,
+ IN EFI_GUID *FileName,
+ IN PHYSICAL_ADDRESS ImageBase,
+ IN UINT64 ImageSize,
+ IN PHYSICAL_ADDRESS EntryPoint,
+ IN UINT16 ImageSubsystem,
+ IN EFI_FV_FILETYPE FileType
+ )
+{
+ EFI_STATUS Status;
+ MEMORY_PROFILE_DRIVER_INFO *DriverInfo;
+ MEMORY_PROFILE_DRIVER_INFO_DATA *DriverInfoData;
+ VOID *EntryPointInImage;
+ CHAR8 *PdbString;
+ UINTN PdbSize;
+ UINTN PdbOccupiedSize;
+
+ PdbSize = 0;
+ PdbOccupiedSize = 0;
+ PdbString = NULL;
+ if (ImageBase != 0) {
+ PdbString = PeCoffLoaderGetPdbPointer ((VOID*) (UINTN) ImageBase);
+ if (PdbString != NULL) {
+ PdbSize = AsciiStrSize (PdbString);
+ PdbOccupiedSize = GET_OCCUPIED_SIZE (PdbSize, sizeof (UINT64));
+ }
+ }
+
+ //
+ // Use CoreInternalAllocatePool() that will not update profile for this AllocatePool action.
+ //
+ Status = CoreInternalAllocatePool (
+ EfiBootServicesData,
+ sizeof (*DriverInfoData) + sizeof (LIST_ENTRY) + PdbSize,
+ (VOID **) &DriverInfoData
+ );
+ if (EFI_ERROR (Status)) {
+ return NULL;
+ }
+ ASSERT (DriverInfoData != NULL);
+
+ ZeroMem (DriverInfoData, sizeof (*DriverInfoData));
+
+ DriverInfo = &DriverInfoData->DriverInfo;
+ DriverInfoData->Signature = MEMORY_PROFILE_DRIVER_INFO_SIGNATURE;
+ DriverInfo->Header.Signature = MEMORY_PROFILE_DRIVER_INFO_SIGNATURE;
+ DriverInfo->Header.Length = (UINT16) (sizeof (MEMORY_PROFILE_DRIVER_INFO) + PdbOccupiedSize);
+ DriverInfo->Header.Revision = MEMORY_PROFILE_DRIVER_INFO_REVISION;
+ if (FileName != NULL) {
+ CopyMem (&DriverInfo->FileName, FileName, sizeof (EFI_GUID));
+ }
+ DriverInfo->ImageBase = ImageBase;
+ DriverInfo->ImageSize = ImageSize;
+ DriverInfo->EntryPoint = EntryPoint;
+ DriverInfo->ImageSubsystem = ImageSubsystem;
+ if ((EntryPoint != 0) && ((EntryPoint < ImageBase) || (EntryPoint >= (ImageBase + ImageSize)))) {
+ //
+ // If the EntryPoint is not in the range of image buffer, it should come from emulation environment.
+ // So patch ImageBuffer here to align the EntryPoint.
+ //
+ Status = InternalPeCoffGetEntryPoint ((VOID *) (UINTN) ImageBase, &EntryPointInImage);
+ ASSERT_EFI_ERROR (Status);
+ DriverInfo->ImageBase = ImageBase + EntryPoint - (PHYSICAL_ADDRESS) (UINTN) EntryPointInImage;
+ }
+ DriverInfo->FileType = FileType;
+ DriverInfoData->AllocInfoList = (LIST_ENTRY *) (DriverInfoData + 1);
+ InitializeListHead (DriverInfoData->AllocInfoList);
+ DriverInfo->CurrentUsage = 0;
+ DriverInfo->PeakUsage = 0;
+ DriverInfo->AllocRecordCount = 0;
+ if (PdbSize != 0) {
+ DriverInfo->PdbStringOffset = (UINT16) sizeof (MEMORY_PROFILE_DRIVER_INFO);
+ DriverInfoData->PdbString = (CHAR8 *) (DriverInfoData->AllocInfoList + 1);
+ CopyMem (DriverInfoData->PdbString, PdbString, PdbSize);
+ } else {
+ DriverInfo->PdbStringOffset = 0;
+ DriverInfoData->PdbString = NULL;
+ }
+
+ InsertTailList (ContextData->DriverInfoList, &DriverInfoData->Link);
+ ContextData->Context.ImageCount ++;
+ ContextData->Context.TotalImageSize += DriverInfo->ImageSize;
+
+ return DriverInfoData;
+}
+
+/**
+ Return if record for this driver is needed..
+
+ @param DriverFilePath Driver file path.
+
+ @retval TRUE Record for this driver is needed.
+ @retval FALSE Record for this driver is not needed.
+
+**/
+BOOLEAN
+NeedRecordThisDriver (
+ IN EFI_DEVICE_PATH_PROTOCOL *DriverFilePath
+ )
+{
+ EFI_DEVICE_PATH_PROTOCOL *TmpDevicePath;
+ EFI_DEVICE_PATH_PROTOCOL *DevicePathInstance;
+ UINTN DevicePathSize;
+ UINTN FilePathSize;
+
+ if (!IsDevicePathValid (mMemoryProfileDriverPath, mMemoryProfileDriverPathSize)) {
+ //
+ // Invalid Device Path means record all.
+ //
+ return TRUE;
+ }
+
+ //
+ // Record FilePath without END node.
+ //
+ FilePathSize = GetDevicePathSize (DriverFilePath) - sizeof(EFI_DEVICE_PATH_PROTOCOL);
+
+ DevicePathInstance = mMemoryProfileDriverPath;
+ do {
+ //
+ // Find END node (it might be END_ENTIRE or END_INSTANCE).
+ //
+ TmpDevicePath = DevicePathInstance;
+ while (!IsDevicePathEndType (TmpDevicePath)) {
+ TmpDevicePath = NextDevicePathNode (TmpDevicePath);
+ }
+
+ //
+ // Do not compare END node.
+ //
+ DevicePathSize = (UINTN)TmpDevicePath - (UINTN)DevicePathInstance;
+ if ((FilePathSize == DevicePathSize) &&
+ (CompareMem (DriverFilePath, DevicePathInstance, DevicePathSize) == 0)) {
+ return TRUE;
+ }
+
+ //
+ // Get next instance.
+ //
+ DevicePathInstance = (EFI_DEVICE_PATH_PROTOCOL *)((UINTN)DevicePathInstance + DevicePathSize + DevicePathNodeLength(TmpDevicePath));
+ } while (DevicePathSubType (TmpDevicePath) != END_ENTIRE_DEVICE_PATH_SUBTYPE);
+
+ return FALSE;
+}
+
+/**
+ Register DXE Core to memory profile.
+
+ @param HobStart The start address of the HOB.
+ @param ContextData Memory profile context.
+
+ @retval TRUE Register success.
+ @retval FALSE Register fail.
+
+**/
+BOOLEAN
+RegisterDxeCore (
+ IN VOID *HobStart,
+ IN MEMORY_PROFILE_CONTEXT_DATA *ContextData
+ )
+{
+ EFI_PEI_HOB_POINTERS DxeCoreHob;
+ MEMORY_PROFILE_DRIVER_INFO_DATA *DriverInfoData;
+ PHYSICAL_ADDRESS ImageBase;
+ UINT8 TempBuffer[sizeof(MEDIA_FW_VOL_FILEPATH_DEVICE_PATH) + sizeof(EFI_DEVICE_PATH_PROTOCOL)];
+ MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *FilePath;
+
+ ASSERT (ContextData != NULL);
+
+ //
+ // Searching for image hob
+ //
+ DxeCoreHob.Raw = HobStart;
+ while ((DxeCoreHob.Raw = GetNextHob (EFI_HOB_TYPE_MEMORY_ALLOCATION, DxeCoreHob.Raw)) != NULL) {
+ if (CompareGuid (&DxeCoreHob.MemoryAllocationModule->MemoryAllocationHeader.Name, &gEfiHobMemoryAllocModuleGuid)) {
+ //
+ // Find Dxe Core HOB
+ //
+ break;
+ }
+ DxeCoreHob.Raw = GET_NEXT_HOB (DxeCoreHob);
+ }
+ ASSERT (DxeCoreHob.Raw != NULL);
+
+ FilePath = (MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *) TempBuffer;
+ EfiInitializeFwVolDevicepathNode (FilePath, &DxeCoreHob.MemoryAllocationModule->ModuleName);
+ SetDevicePathEndNode (FilePath + 1);
+
+ if (!NeedRecordThisDriver ((EFI_DEVICE_PATH_PROTOCOL *) FilePath)) {
+ return FALSE;
+ }
+
+ ImageBase = DxeCoreHob.MemoryAllocationModule->MemoryAllocationHeader.MemoryBaseAddress;
+ DriverInfoData = BuildDriverInfo (
+ ContextData,
+ &DxeCoreHob.MemoryAllocationModule->ModuleName,
+ ImageBase,
+ DxeCoreHob.MemoryAllocationModule->MemoryAllocationHeader.MemoryLength,
+ DxeCoreHob.MemoryAllocationModule->EntryPoint,
+ InternalPeCoffGetSubsystem ((VOID *) (UINTN) ImageBase),
+ EFI_FV_FILETYPE_DXE_CORE
+ );
+ if (DriverInfoData == NULL) {
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+/**
+ Initialize memory profile.
+
+ @param HobStart The start address of the HOB.
+
+**/
+VOID
+MemoryProfileInit (
+ IN VOID *HobStart
+ )
+{
+ MEMORY_PROFILE_CONTEXT_DATA *ContextData;
+
+ if (!IS_UEFI_MEMORY_PROFILE_ENABLED) {
+ return;
+ }
+
+ ContextData = GetMemoryProfileContext ();
+ if (ContextData != NULL) {
+ return;
+ }
+
+ mMemoryProfileGettingStatus = FALSE;
+ if ((PcdGet8 (PcdMemoryProfilePropertyMask) & BIT7) != 0) {
+ mMemoryProfileRecordingEnable = MEMORY_PROFILE_RECORDING_DISABLE;
+ } else {
+ mMemoryProfileRecordingEnable = MEMORY_PROFILE_RECORDING_ENABLE;
+ }
+ mMemoryProfileDriverPathSize = PcdGetSize (PcdMemoryProfileDriverPath);
+ mMemoryProfileDriverPath = AllocateCopyPool (mMemoryProfileDriverPathSize, PcdGetPtr (PcdMemoryProfileDriverPath));
+ mMemoryProfileContextPtr = &mMemoryProfileContext;
+
+ RegisterDxeCore (HobStart, &mMemoryProfileContext);
+
+ DEBUG ((EFI_D_INFO, "MemoryProfileInit MemoryProfileContext - 0x%x\n", &mMemoryProfileContext));
+}
+
+/**
+ Install memory profile protocol.
+
+**/
+VOID
+MemoryProfileInstallProtocol (
+ VOID
+ )
+{
+ EFI_HANDLE Handle;
+ EFI_STATUS Status;
+
+ if (!IS_UEFI_MEMORY_PROFILE_ENABLED) {
+ return;
+ }
+
+ Handle = NULL;
+ Status = CoreInstallMultipleProtocolInterfaces (
+ &Handle,
+ &gEdkiiMemoryProfileGuid,
+ &mProfileProtocol,
+ NULL
+ );
+ ASSERT_EFI_ERROR (Status);
+}
+
+/**
+ Get the GUID file name from the file path.
+
+ @param FilePath File path.
+
+ @return The GUID file name from the file path.
+
+**/
+EFI_GUID *
+GetFileNameFromFilePath (
+ IN EFI_DEVICE_PATH_PROTOCOL *FilePath
+ )
+{
+ MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *ThisFilePath;
+ EFI_GUID *FileName;
+
+ FileName = NULL;
+ if (FilePath != NULL) {
+ ThisFilePath = (MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *) FilePath;
+ while (!IsDevicePathEnd (ThisFilePath)) {
+ FileName = EfiGetNameGuidFromFwVolDevicePathNode (ThisFilePath);
+ if (FileName != NULL) {
+ break;
+ }
+ ThisFilePath = (MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *) NextDevicePathNode (ThisFilePath);
+ }
+ }
+
+ return FileName;
+}
+
+/**
+ Register image to memory profile.
+
+ @param DriverEntry Image info.
+ @param FileType Image file type.
+
+ @return EFI_SUCCESS Register successfully.
+ @return EFI_UNSUPPORTED Memory profile is unsupported,
+ or memory profile for the image is not required.
+ @return EFI_OUT_OF_RESOURCES No enough resource for this register.
+
+**/
+EFI_STATUS
+RegisterMemoryProfileImage (
+ IN LOADED_IMAGE_PRIVATE_DATA *DriverEntry,
+ IN EFI_FV_FILETYPE FileType
+ )
+{
+ MEMORY_PROFILE_CONTEXT_DATA *ContextData;
+ MEMORY_PROFILE_DRIVER_INFO_DATA *DriverInfoData;
+
+ if (!IS_UEFI_MEMORY_PROFILE_ENABLED) {
+ return EFI_UNSUPPORTED;
+ }
+
+ if (!NeedRecordThisDriver (DriverEntry->Info.FilePath)) {
+ return EFI_UNSUPPORTED;
+ }
+
+ ContextData = GetMemoryProfileContext ();
+ if (ContextData == NULL) {
+ return EFI_UNSUPPORTED;
+ }
+
+ DriverInfoData = BuildDriverInfo (
+ ContextData,
+ GetFileNameFromFilePath (DriverEntry->Info.FilePath),
+ DriverEntry->ImageContext.ImageAddress,
+ DriverEntry->ImageContext.ImageSize,
+ DriverEntry->ImageContext.EntryPoint,
+ DriverEntry->ImageContext.ImageType,
+ FileType
+ );
+ if (DriverInfoData == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Search image from memory profile.
+
+ @param ContextData Memory profile context.
+ @param FileName Image file name.
+ @param Address Image Address.
+
+ @return Pointer to memory profile driver info.
+
+**/
+MEMORY_PROFILE_DRIVER_INFO_DATA *
+GetMemoryProfileDriverInfoByFileNameAndAddress (
+ IN MEMORY_PROFILE_CONTEXT_DATA *ContextData,
+ IN EFI_GUID *FileName,
+ IN PHYSICAL_ADDRESS Address
+ )
+{
+ MEMORY_PROFILE_DRIVER_INFO *DriverInfo;
+ MEMORY_PROFILE_DRIVER_INFO_DATA *DriverInfoData;
+ LIST_ENTRY *DriverLink;
+ LIST_ENTRY *DriverInfoList;
+
+ DriverInfoList = ContextData->DriverInfoList;
+
+ for (DriverLink = DriverInfoList->ForwardLink;
+ DriverLink != DriverInfoList;
+ DriverLink = DriverLink->ForwardLink) {
+ DriverInfoData = CR (
+ DriverLink,
+ MEMORY_PROFILE_DRIVER_INFO_DATA,
+ Link,
+ MEMORY_PROFILE_DRIVER_INFO_SIGNATURE
+ );
+ DriverInfo = &DriverInfoData->DriverInfo;
+ if ((CompareGuid (&DriverInfo->FileName, FileName)) &&
+ (Address >= DriverInfo->ImageBase) &&
+ (Address < (DriverInfo->ImageBase + DriverInfo->ImageSize))) {
+ return DriverInfoData;
+ }
+ }
+
+ return NULL;
+}
+
+/**
+ Search image from memory profile.
+ It will return image, if (Address >= ImageBuffer) AND (Address < ImageBuffer + ImageSize).
+
+ @param ContextData Memory profile context.
+ @param Address Image or Function address.
+
+ @return Pointer to memory profile driver info.
+
+**/
+MEMORY_PROFILE_DRIVER_INFO_DATA *
+GetMemoryProfileDriverInfoFromAddress (
+ IN MEMORY_PROFILE_CONTEXT_DATA *ContextData,
+ IN PHYSICAL_ADDRESS Address
+ )
+{
+ MEMORY_PROFILE_DRIVER_INFO *DriverInfo;
+ MEMORY_PROFILE_DRIVER_INFO_DATA *DriverInfoData;
+ LIST_ENTRY *DriverLink;
+ LIST_ENTRY *DriverInfoList;
+
+ DriverInfoList = ContextData->DriverInfoList;
+
+ for (DriverLink = DriverInfoList->ForwardLink;
+ DriverLink != DriverInfoList;
+ DriverLink = DriverLink->ForwardLink) {
+ DriverInfoData = CR (
+ DriverLink,
+ MEMORY_PROFILE_DRIVER_INFO_DATA,
+ Link,
+ MEMORY_PROFILE_DRIVER_INFO_SIGNATURE
+ );
+ DriverInfo = &DriverInfoData->DriverInfo;
+ if ((Address >= DriverInfo->ImageBase) &&
+ (Address < (DriverInfo->ImageBase + DriverInfo->ImageSize))) {
+ return DriverInfoData;
+ }
+ }
+
+ return NULL;
+}
+
+/**
+ Unregister image from memory profile.
+
+ @param DriverEntry Image info.
+
+ @return EFI_SUCCESS Unregister successfully.
+ @return EFI_UNSUPPORTED Memory profile is unsupported,
+ or memory profile for the image is not required.
+ @return EFI_NOT_FOUND The image is not found.
+
+**/
+EFI_STATUS
+UnregisterMemoryProfileImage (
+ IN LOADED_IMAGE_PRIVATE_DATA *DriverEntry
+ )
+{
+ EFI_STATUS Status;
+ MEMORY_PROFILE_CONTEXT_DATA *ContextData;
+ MEMORY_PROFILE_DRIVER_INFO_DATA *DriverInfoData;
+ EFI_GUID *FileName;
+ PHYSICAL_ADDRESS ImageAddress;
+ VOID *EntryPointInImage;
+
+ if (!IS_UEFI_MEMORY_PROFILE_ENABLED) {
+ return EFI_UNSUPPORTED;
+ }
+
+ if (!NeedRecordThisDriver (DriverEntry->Info.FilePath)) {
+ return EFI_UNSUPPORTED;
+ }
+
+ ContextData = GetMemoryProfileContext ();
+ if (ContextData == NULL) {
+ return EFI_UNSUPPORTED;
+ }
+
+ DriverInfoData = NULL;
+ FileName = GetFileNameFromFilePath (DriverEntry->Info.FilePath);
+ ImageAddress = DriverEntry->ImageContext.ImageAddress;
+ if ((DriverEntry->ImageContext.EntryPoint < ImageAddress) || (DriverEntry->ImageContext.EntryPoint >= (ImageAddress + DriverEntry->ImageContext.ImageSize))) {
+ //
+ // If the EntryPoint is not in the range of image buffer, it should come from emulation environment.
+ // So patch ImageAddress here to align the EntryPoint.
+ //
+ Status = InternalPeCoffGetEntryPoint ((VOID *) (UINTN) ImageAddress, &EntryPointInImage);
+ ASSERT_EFI_ERROR (Status);
+ ImageAddress = ImageAddress + (UINTN) DriverEntry->ImageContext.EntryPoint - (UINTN) EntryPointInImage;
+ }
+ if (FileName != NULL) {
+ DriverInfoData = GetMemoryProfileDriverInfoByFileNameAndAddress (ContextData, FileName, ImageAddress);
+ }
+ if (DriverInfoData == NULL) {
+ DriverInfoData = GetMemoryProfileDriverInfoFromAddress (ContextData, ImageAddress);
+ }
+ if (DriverInfoData == NULL) {
+ return EFI_NOT_FOUND;
+ }
+
+ ContextData->Context.TotalImageSize -= DriverInfoData->DriverInfo.ImageSize;
+
+ // Keep the ImageBase for RVA calculation in Application.
+ //DriverInfoData->DriverInfo.ImageBase = 0;
+ DriverInfoData->DriverInfo.ImageSize = 0;
+
+ if (DriverInfoData->DriverInfo.PeakUsage == 0) {
+ ContextData->Context.ImageCount --;
+ RemoveEntryList (&DriverInfoData->Link);
+ //
+ // Use CoreInternalFreePool() that will not update profile for this FreePool action.
+ //
+ CoreInternalFreePool (DriverInfoData, NULL);
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Return if this memory type needs to be recorded into memory profile.
+ If BIOS memory type (0 ~ EfiMaxMemoryType - 1), it checks bit (1 << MemoryType).
+ If OS memory type (0x80000000 ~ 0xFFFFFFFF), it checks bit63 - 0x8000000000000000.
+ If OEM memory type (0x70000000 ~ 0x7FFFFFFF), it checks bit62 - 0x4000000000000000.
+
+ @param MemoryType Memory type.
+
+ @retval TRUE This memory type need to be recorded.
+ @retval FALSE This memory type need not to be recorded.
+
+**/
+BOOLEAN
+CoreNeedRecordProfile (
+ IN EFI_MEMORY_TYPE MemoryType
+ )
+{
+ UINT64 TestBit;
+
+ if ((UINT32) MemoryType >= MEMORY_TYPE_OS_RESERVED_MIN) {
+ TestBit = BIT63;
+ } else if ((UINT32) MemoryType >= MEMORY_TYPE_OEM_RESERVED_MIN) {
+ TestBit = BIT62;
+ } else {
+ TestBit = LShiftU64 (1, MemoryType);
+ }
+
+ if ((PcdGet64 (PcdMemoryProfileMemoryType) & TestBit) != 0) {
+ return TRUE;
+ } else {
+ return FALSE;
+ }
+}
+
+/**
+ Convert EFI memory type to profile memory index. The rule is:
+ If BIOS memory type (0 ~ EfiMaxMemoryType - 1), ProfileMemoryIndex = MemoryType.
+ If OS memory type (0x80000000 ~ 0xFFFFFFFF), ProfileMemoryIndex = EfiMaxMemoryType.
+ If OEM memory type (0x70000000 ~ 0x7FFFFFFF), ProfileMemoryIndex = EfiMaxMemoryType + 1.
+
+ @param MemoryType Memory type.
+
+ @return Profile memory index.
+
+**/
+UINTN
+GetProfileMemoryIndex (
+ IN EFI_MEMORY_TYPE MemoryType
+ )
+{
+ if ((UINT32) MemoryType >= MEMORY_TYPE_OS_RESERVED_MIN) {
+ return EfiMaxMemoryType;
+ } else if ((UINT32) MemoryType >= MEMORY_TYPE_OEM_RESERVED_MIN) {
+ return EfiMaxMemoryType + 1;
+ } else {
+ return MemoryType;
+ }
+}
+
+/**
+ Update memory profile Allocate information.
+
+ @param CallerAddress Address of caller who call Allocate.
+ @param Action This Allocate action.
+ @param MemoryType Memory type.
+ @param Size Buffer size.
+ @param Buffer Buffer address.
+ @param ActionString String for memory profile action.
+
+ @return EFI_SUCCESS Memory profile is updated.
+ @return EFI_UNSUPPORTED Memory profile is unsupported,
+ or memory profile for the image is not required.
+ @return EFI_OUT_OF_RESOURCES No enough resource to update memory profile for allocate action.
+
+**/
+EFI_STATUS
+CoreUpdateProfileAllocate (
+ IN PHYSICAL_ADDRESS CallerAddress,
+ IN MEMORY_PROFILE_ACTION Action,
+ IN EFI_MEMORY_TYPE MemoryType,
+ IN UINTN Size,
+ IN VOID *Buffer,
+ IN CHAR8 *ActionString OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+ MEMORY_PROFILE_CONTEXT *Context;
+ MEMORY_PROFILE_DRIVER_INFO *DriverInfo;
+ MEMORY_PROFILE_ALLOC_INFO *AllocInfo;
+ MEMORY_PROFILE_CONTEXT_DATA *ContextData;
+ MEMORY_PROFILE_DRIVER_INFO_DATA *DriverInfoData;
+ MEMORY_PROFILE_ALLOC_INFO_DATA *AllocInfoData;
+ UINTN ProfileMemoryIndex;
+ MEMORY_PROFILE_ACTION BasicAction;
+ UINTN ActionStringSize;
+ UINTN ActionStringOccupiedSize;
+
+ BasicAction = Action & MEMORY_PROFILE_ACTION_BASIC_MASK;
+
+ ContextData = GetMemoryProfileContext ();
+ if (ContextData == NULL) {
+ return EFI_UNSUPPORTED;
+ }
+
+ DriverInfoData = GetMemoryProfileDriverInfoFromAddress (ContextData, CallerAddress);
+ if (DriverInfoData == NULL) {
+ return EFI_UNSUPPORTED;
+ }
+
+ ActionStringSize = 0;
+ ActionStringOccupiedSize = 0;
+ if (ActionString != NULL) {
+ ActionStringSize = AsciiStrSize (ActionString);
+ ActionStringOccupiedSize = GET_OCCUPIED_SIZE (ActionStringSize, sizeof (UINT64));
+ }
+
+ //
+ // Use CoreInternalAllocatePool() that will not update profile for this AllocatePool action.
+ //
+ AllocInfoData = NULL;
+ Status = CoreInternalAllocatePool (
+ EfiBootServicesData,
+ sizeof (*AllocInfoData) + ActionStringSize,
+ (VOID **) &AllocInfoData
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ ASSERT (AllocInfoData != NULL);
+
+ //
+ // Only update SequenceCount if and only if it is basic action.
+ //
+ if (Action == BasicAction) {
+ ContextData->Context.SequenceCount ++;
+ }
+
+ AllocInfo = &AllocInfoData->AllocInfo;
+ AllocInfoData->Signature = MEMORY_PROFILE_ALLOC_INFO_SIGNATURE;
+ AllocInfo->Header.Signature = MEMORY_PROFILE_ALLOC_INFO_SIGNATURE;
+ AllocInfo->Header.Length = (UINT16) (sizeof (MEMORY_PROFILE_ALLOC_INFO) + ActionStringOccupiedSize);
+ AllocInfo->Header.Revision = MEMORY_PROFILE_ALLOC_INFO_REVISION;
+ AllocInfo->CallerAddress = CallerAddress;
+ AllocInfo->SequenceId = ContextData->Context.SequenceCount;
+ AllocInfo->Action = Action;
+ AllocInfo->MemoryType = MemoryType;
+ AllocInfo->Buffer = (PHYSICAL_ADDRESS) (UINTN) Buffer;
+ AllocInfo->Size = Size;
+ if (ActionString != NULL) {
+ AllocInfo->ActionStringOffset = (UINT16) sizeof (MEMORY_PROFILE_ALLOC_INFO);
+ AllocInfoData->ActionString = (CHAR8 *) (AllocInfoData + 1);
+ CopyMem (AllocInfoData->ActionString, ActionString, ActionStringSize);
+ } else {
+ AllocInfo->ActionStringOffset = 0;
+ AllocInfoData->ActionString = NULL;
+ }
+
+ InsertTailList (DriverInfoData->AllocInfoList, &AllocInfoData->Link);
+
+ Context = &ContextData->Context;
+ DriverInfo = &DriverInfoData->DriverInfo;
+ DriverInfo->AllocRecordCount ++;
+
+ //
+ // Update summary if and only if it is basic action.
+ //
+ if (Action == BasicAction) {
+ ProfileMemoryIndex = GetProfileMemoryIndex (MemoryType);
+
+ DriverInfo->CurrentUsage += Size;
+ if (DriverInfo->PeakUsage < DriverInfo->CurrentUsage) {
+ DriverInfo->PeakUsage = DriverInfo->CurrentUsage;
+ }
+ DriverInfo->CurrentUsageByType[ProfileMemoryIndex] += Size;
+ if (DriverInfo->PeakUsageByType[ProfileMemoryIndex] < DriverInfo->CurrentUsageByType[ProfileMemoryIndex]) {
+ DriverInfo->PeakUsageByType[ProfileMemoryIndex] = DriverInfo->CurrentUsageByType[ProfileMemoryIndex];
+ }
+
+ Context->CurrentTotalUsage += Size;
+ if (Context->PeakTotalUsage < Context->CurrentTotalUsage) {
+ Context->PeakTotalUsage = Context->CurrentTotalUsage;
+ }
+ Context->CurrentTotalUsageByType[ProfileMemoryIndex] += Size;
+ if (Context->PeakTotalUsageByType[ProfileMemoryIndex] < Context->CurrentTotalUsageByType[ProfileMemoryIndex]) {
+ Context->PeakTotalUsageByType[ProfileMemoryIndex] = Context->CurrentTotalUsageByType[ProfileMemoryIndex];
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Get memory profile alloc info from memory profile.
+
+ @param DriverInfoData Driver info.
+ @param BasicAction This Free basic action.
+ @param Size Buffer size.
+ @param Buffer Buffer address.
+
+ @return Pointer to memory profile alloc info.
+
+**/
+MEMORY_PROFILE_ALLOC_INFO_DATA *
+GetMemoryProfileAllocInfoFromAddress (
+ IN MEMORY_PROFILE_DRIVER_INFO_DATA *DriverInfoData,
+ IN MEMORY_PROFILE_ACTION BasicAction,
+ IN UINTN Size,
+ IN VOID *Buffer
+ )
+{
+ LIST_ENTRY *AllocInfoList;
+ LIST_ENTRY *AllocLink;
+ MEMORY_PROFILE_ALLOC_INFO *AllocInfo;
+ MEMORY_PROFILE_ALLOC_INFO_DATA *AllocInfoData;
+
+ AllocInfoList = DriverInfoData->AllocInfoList;
+
+ for (AllocLink = AllocInfoList->ForwardLink;
+ AllocLink != AllocInfoList;
+ AllocLink = AllocLink->ForwardLink) {
+ AllocInfoData = CR (
+ AllocLink,
+ MEMORY_PROFILE_ALLOC_INFO_DATA,
+ Link,
+ MEMORY_PROFILE_ALLOC_INFO_SIGNATURE
+ );
+ AllocInfo = &AllocInfoData->AllocInfo;
+ if ((AllocInfo->Action & MEMORY_PROFILE_ACTION_BASIC_MASK) != BasicAction) {
+ continue;
+ }
+ switch (BasicAction) {
+ case MemoryProfileActionAllocatePages:
+ if ((AllocInfo->Buffer <= (PHYSICAL_ADDRESS) (UINTN) Buffer) &&
+ ((AllocInfo->Buffer + AllocInfo->Size) >= ((PHYSICAL_ADDRESS) (UINTN) Buffer + Size))) {
+ return AllocInfoData;
+ }
+ break;
+ case MemoryProfileActionAllocatePool:
+ if (AllocInfo->Buffer == (PHYSICAL_ADDRESS) (UINTN) Buffer) {
+ return AllocInfoData;
+ }
+ break;
+ default:
+ ASSERT (FALSE);
+ break;
+ }
+ }
+
+ return NULL;
+}
+
+/**
+ Update memory profile Free information.
+
+ @param CallerAddress Address of caller who call Free.
+ @param Action This Free action.
+ @param Size Buffer size.
+ @param Buffer Buffer address.
+
+ @return EFI_SUCCESS Memory profile is updated.
+ @return EFI_UNSUPPORTED Memory profile is unsupported.
+ @return EFI_NOT_FOUND No matched allocate info found for free action.
+
+**/
+EFI_STATUS
+CoreUpdateProfileFree (
+ IN PHYSICAL_ADDRESS CallerAddress,
+ IN MEMORY_PROFILE_ACTION Action,
+ IN UINTN Size,
+ IN VOID *Buffer
+ )
+{
+ MEMORY_PROFILE_CONTEXT *Context;
+ MEMORY_PROFILE_DRIVER_INFO *DriverInfo;
+ MEMORY_PROFILE_ALLOC_INFO *AllocInfo;
+ MEMORY_PROFILE_CONTEXT_DATA *ContextData;
+ MEMORY_PROFILE_DRIVER_INFO_DATA *DriverInfoData;
+ LIST_ENTRY *DriverLink;
+ LIST_ENTRY *DriverInfoList;
+ MEMORY_PROFILE_DRIVER_INFO_DATA *ThisDriverInfoData;
+ MEMORY_PROFILE_ALLOC_INFO_DATA *AllocInfoData;
+ UINTN ProfileMemoryIndex;
+ MEMORY_PROFILE_ACTION BasicAction;
+ BOOLEAN Found;
+
+ BasicAction = Action & MEMORY_PROFILE_ACTION_BASIC_MASK;
+
+ ContextData = GetMemoryProfileContext ();
+ if (ContextData == NULL) {
+ return EFI_UNSUPPORTED;
+ }
+
+ DriverInfoData = GetMemoryProfileDriverInfoFromAddress (ContextData, CallerAddress);
+
+ //
+ // Do not return if DriverInfoData == NULL here,
+ // because driver A might free memory allocated by driver B.
+ //
+
+ //
+ // Need use do-while loop to find all possible records,
+ // because one address might be recorded multiple times.
+ //
+ Found = FALSE;
+ AllocInfoData = NULL;
+ do {
+ if (DriverInfoData != NULL) {
+ switch (BasicAction) {
+ case MemoryProfileActionFreePages:
+ AllocInfoData = GetMemoryProfileAllocInfoFromAddress (DriverInfoData, MemoryProfileActionAllocatePages, Size, Buffer);
+ break;
+ case MemoryProfileActionFreePool:
+ AllocInfoData = GetMemoryProfileAllocInfoFromAddress (DriverInfoData, MemoryProfileActionAllocatePool, 0, Buffer);
+ break;
+ default:
+ ASSERT (FALSE);
+ AllocInfoData = NULL;
+ break;
+ }
+ }
+ if (AllocInfoData == NULL) {
+ //
+ // Legal case, because driver A might free memory allocated by driver B, by some protocol.
+ //
+ DriverInfoList = ContextData->DriverInfoList;
+
+ for (DriverLink = DriverInfoList->ForwardLink;
+ DriverLink != DriverInfoList;
+ DriverLink = DriverLink->ForwardLink) {
+ ThisDriverInfoData = CR (
+ DriverLink,
+ MEMORY_PROFILE_DRIVER_INFO_DATA,
+ Link,
+ MEMORY_PROFILE_DRIVER_INFO_SIGNATURE
+ );
+ switch (BasicAction) {
+ case MemoryProfileActionFreePages:
+ AllocInfoData = GetMemoryProfileAllocInfoFromAddress (ThisDriverInfoData, MemoryProfileActionAllocatePages, Size, Buffer);
+ break;
+ case MemoryProfileActionFreePool:
+ AllocInfoData = GetMemoryProfileAllocInfoFromAddress (ThisDriverInfoData, MemoryProfileActionAllocatePool, 0, Buffer);
+ break;
+ default:
+ ASSERT (FALSE);
+ AllocInfoData = NULL;
+ break;
+ }
+ if (AllocInfoData != NULL) {
+ DriverInfoData = ThisDriverInfoData;
+ break;
+ }
+ }
+
+ if (AllocInfoData == NULL) {
+ //
+ // If (!Found), no matched allocate info is found for this free action.
+ // It is because the specified memory type allocate actions have been filtered by
+ // CoreNeedRecordProfile(), but free actions may have no memory type information,
+ // they can not be filtered by CoreNeedRecordProfile(). Then, they will be
+ // filtered here.
+ //
+ // If (Found), it is normal exit path.
+ return (Found ? EFI_SUCCESS : EFI_NOT_FOUND);
+ }
+ }
+
+ ASSERT (DriverInfoData != NULL);
+ ASSERT (AllocInfoData != NULL);
+
+ Found = TRUE;
+
+ Context = &ContextData->Context;
+ DriverInfo = &DriverInfoData->DriverInfo;
+ AllocInfo = &AllocInfoData->AllocInfo;
+
+ DriverInfo->AllocRecordCount --;
+ //
+ // Update summary if and only if it is basic action.
+ //
+ if (AllocInfo->Action == (AllocInfo->Action & MEMORY_PROFILE_ACTION_BASIC_MASK)) {
+ ProfileMemoryIndex = GetProfileMemoryIndex (AllocInfo->MemoryType);
+
+ Context->CurrentTotalUsage -= AllocInfo->Size;
+ Context->CurrentTotalUsageByType[ProfileMemoryIndex] -= AllocInfo->Size;
+
+ DriverInfo->CurrentUsage -= AllocInfo->Size;
+ DriverInfo->CurrentUsageByType[ProfileMemoryIndex] -= AllocInfo->Size;
+ }
+
+ RemoveEntryList (&AllocInfoData->Link);
+
+ if (BasicAction == MemoryProfileActionFreePages) {
+ if (AllocInfo->Buffer != (PHYSICAL_ADDRESS) (UINTN) Buffer) {
+ CoreUpdateProfileAllocate (
+ AllocInfo->CallerAddress,
+ AllocInfo->Action,
+ AllocInfo->MemoryType,
+ (UINTN) ((PHYSICAL_ADDRESS) (UINTN) Buffer - AllocInfo->Buffer),
+ (VOID *) (UINTN) AllocInfo->Buffer,
+ AllocInfoData->ActionString
+ );
+ }
+ if (AllocInfo->Buffer + AllocInfo->Size != ((PHYSICAL_ADDRESS) (UINTN) Buffer + Size)) {
+ CoreUpdateProfileAllocate (
+ AllocInfo->CallerAddress,
+ AllocInfo->Action,
+ AllocInfo->MemoryType,
+ (UINTN) ((AllocInfo->Buffer + AllocInfo->Size) - ((PHYSICAL_ADDRESS) (UINTN) Buffer + Size)),
+ (VOID *) ((UINTN) Buffer + Size),
+ AllocInfoData->ActionString
+ );
+ }
+ }
+
+ //
+ // Use CoreInternalFreePool() that will not update profile for this FreePool action.
+ //
+ CoreInternalFreePool (AllocInfoData, NULL);
+ } while (TRUE);
+}
+
+/**
+ Update memory profile information.
+
+ @param CallerAddress Address of caller who call Allocate or Free.
+ @param Action This Allocate or Free action.
+ @param MemoryType Memory type.
+ EfiMaxMemoryType means the MemoryType is unknown.
+ @param Size Buffer size.
+ @param Buffer Buffer address.
+ @param ActionString String for memory profile action.
+ Only needed for user defined allocate action.
+
+ @return EFI_SUCCESS Memory profile is updated.
+ @return EFI_UNSUPPORTED Memory profile is unsupported,
+ or memory profile for the image is not required,
+ or memory profile for the memory type is not required.
+ @return EFI_ACCESS_DENIED It is during memory profile data getting.
+ @return EFI_ABORTED Memory profile recording is not enabled.
+ @return EFI_OUT_OF_RESOURCES No enough resource to update memory profile for allocate action.
+ @return EFI_NOT_FOUND No matched allocate info found for free action.
+
+**/
+EFI_STATUS
+EFIAPI
+CoreUpdateProfile (
+ IN PHYSICAL_ADDRESS CallerAddress,
+ IN MEMORY_PROFILE_ACTION Action,
+ IN EFI_MEMORY_TYPE MemoryType,
+ IN UINTN Size, // Valid for AllocatePages/FreePages/AllocatePool
+ IN VOID *Buffer,
+ IN CHAR8 *ActionString OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+ MEMORY_PROFILE_CONTEXT_DATA *ContextData;
+ MEMORY_PROFILE_ACTION BasicAction;
+
+ if (!IS_UEFI_MEMORY_PROFILE_ENABLED) {
+ return EFI_UNSUPPORTED;
+ }
+
+ if (mMemoryProfileGettingStatus) {
+ return EFI_ACCESS_DENIED;
+ }
+
+ if (!mMemoryProfileRecordingEnable) {
+ return EFI_ABORTED;
+ }
+
+ //
+ // Get the basic action to know how to process the record
+ //
+ BasicAction = Action & MEMORY_PROFILE_ACTION_BASIC_MASK;
+
+ //
+ // EfiMaxMemoryType means the MemoryType is unknown.
+ //
+ if (MemoryType != EfiMaxMemoryType) {
+ //
+ // Only record limited MemoryType.
+ //
+ if (!CoreNeedRecordProfile (MemoryType)) {
+ return EFI_UNSUPPORTED;
+ }
+ }
+
+ ContextData = GetMemoryProfileContext ();
+ if (ContextData == NULL) {
+ return EFI_UNSUPPORTED;
+ }
+
+ CoreAcquireMemoryProfileLock ();
+ switch (BasicAction) {
+ case MemoryProfileActionAllocatePages:
+ Status = CoreUpdateProfileAllocate (CallerAddress, Action, MemoryType, Size, Buffer, ActionString);
+ break;
+ case MemoryProfileActionFreePages:
+ Status = CoreUpdateProfileFree (CallerAddress, Action, Size, Buffer);
+ break;
+ case MemoryProfileActionAllocatePool:
+ Status = CoreUpdateProfileAllocate (CallerAddress, Action, MemoryType, Size, Buffer, ActionString);
+ break;
+ case MemoryProfileActionFreePool:
+ Status = CoreUpdateProfileFree (CallerAddress, Action, 0, Buffer);
+ break;
+ default:
+ ASSERT (FALSE);
+ Status = EFI_UNSUPPORTED;
+ break;
+ }
+ CoreReleaseMemoryProfileLock ();
+
+ return Status;
+}
+
+////////////////////
+
+/**
+ Get memory profile data size.
+
+ @return Memory profile data size.
+
+**/
+UINTN
+MemoryProfileGetDataSize (
+ VOID
+ )
+{
+ MEMORY_PROFILE_CONTEXT_DATA *ContextData;
+ MEMORY_PROFILE_DRIVER_INFO_DATA *DriverInfoData;
+ MEMORY_PROFILE_ALLOC_INFO_DATA *AllocInfoData;
+ LIST_ENTRY *DriverInfoList;
+ LIST_ENTRY *DriverLink;
+ LIST_ENTRY *AllocInfoList;
+ LIST_ENTRY *AllocLink;
+ UINTN TotalSize;
+
+
+ ContextData = GetMemoryProfileContext ();
+ if (ContextData == NULL) {
+ return 0;
+ }
+
+ TotalSize = sizeof (MEMORY_PROFILE_CONTEXT);
+
+ DriverInfoList = ContextData->DriverInfoList;
+ for (DriverLink = DriverInfoList->ForwardLink;
+ DriverLink != DriverInfoList;
+ DriverLink = DriverLink->ForwardLink) {
+ DriverInfoData = CR (
+ DriverLink,
+ MEMORY_PROFILE_DRIVER_INFO_DATA,
+ Link,
+ MEMORY_PROFILE_DRIVER_INFO_SIGNATURE
+ );
+ TotalSize += DriverInfoData->DriverInfo.Header.Length;
+
+ AllocInfoList = DriverInfoData->AllocInfoList;
+ for (AllocLink = AllocInfoList->ForwardLink;
+ AllocLink != AllocInfoList;
+ AllocLink = AllocLink->ForwardLink) {
+ AllocInfoData = CR (
+ AllocLink,
+ MEMORY_PROFILE_ALLOC_INFO_DATA,
+ Link,
+ MEMORY_PROFILE_ALLOC_INFO_SIGNATURE
+ );
+ TotalSize += AllocInfoData->AllocInfo.Header.Length;
+ }
+ }
+
+ return TotalSize;
+}
+
+/**
+ Copy memory profile data.
+
+ @param ProfileBuffer The buffer to hold memory profile data.
+
+**/
+VOID
+MemoryProfileCopyData (
+ IN VOID *ProfileBuffer
+ )
+{
+ MEMORY_PROFILE_CONTEXT *Context;
+ MEMORY_PROFILE_DRIVER_INFO *DriverInfo;
+ MEMORY_PROFILE_ALLOC_INFO *AllocInfo;
+ MEMORY_PROFILE_CONTEXT_DATA *ContextData;
+ MEMORY_PROFILE_DRIVER_INFO_DATA *DriverInfoData;
+ MEMORY_PROFILE_ALLOC_INFO_DATA *AllocInfoData;
+ LIST_ENTRY *DriverInfoList;
+ LIST_ENTRY *DriverLink;
+ LIST_ENTRY *AllocInfoList;
+ LIST_ENTRY *AllocLink;
+ UINTN PdbSize;
+ UINTN ActionStringSize;
+
+ ContextData = GetMemoryProfileContext ();
+ if (ContextData == NULL) {
+ return ;
+ }
+
+ Context = ProfileBuffer;
+ CopyMem (Context, &ContextData->Context, sizeof (MEMORY_PROFILE_CONTEXT));
+ DriverInfo = (MEMORY_PROFILE_DRIVER_INFO *) (Context + 1);
+
+ DriverInfoList = ContextData->DriverInfoList;
+ for (DriverLink = DriverInfoList->ForwardLink;
+ DriverLink != DriverInfoList;
+ DriverLink = DriverLink->ForwardLink) {
+ DriverInfoData = CR (
+ DriverLink,
+ MEMORY_PROFILE_DRIVER_INFO_DATA,
+ Link,
+ MEMORY_PROFILE_DRIVER_INFO_SIGNATURE
+ );
+ CopyMem (DriverInfo, &DriverInfoData->DriverInfo, sizeof (MEMORY_PROFILE_DRIVER_INFO));
+ if (DriverInfo->PdbStringOffset != 0) {
+ PdbSize = AsciiStrSize (DriverInfoData->PdbString);
+ CopyMem ((VOID *) ((UINTN) DriverInfo + DriverInfo->PdbStringOffset), DriverInfoData->PdbString, PdbSize);
+ }
+ AllocInfo = (MEMORY_PROFILE_ALLOC_INFO *) ((UINTN) DriverInfo + DriverInfo->Header.Length);
+
+ AllocInfoList = DriverInfoData->AllocInfoList;
+ for (AllocLink = AllocInfoList->ForwardLink;
+ AllocLink != AllocInfoList;
+ AllocLink = AllocLink->ForwardLink) {
+ AllocInfoData = CR (
+ AllocLink,
+ MEMORY_PROFILE_ALLOC_INFO_DATA,
+ Link,
+ MEMORY_PROFILE_ALLOC_INFO_SIGNATURE
+ );
+ CopyMem (AllocInfo, &AllocInfoData->AllocInfo, sizeof (MEMORY_PROFILE_ALLOC_INFO));
+ if (AllocInfo->ActionStringOffset != 0) {
+ ActionStringSize = AsciiStrSize (AllocInfoData->ActionString);
+ CopyMem ((VOID *) ((UINTN) AllocInfo + AllocInfo->ActionStringOffset), AllocInfoData->ActionString, ActionStringSize);
+ }
+ AllocInfo = (MEMORY_PROFILE_ALLOC_INFO *) ((UINTN) AllocInfo + AllocInfo->Header.Length);
+ }
+
+ DriverInfo = (MEMORY_PROFILE_DRIVER_INFO *) AllocInfo;
+ }
+}
+
+/**
+ Get memory profile data.
+
+ @param[in] This The EDKII_MEMORY_PROFILE_PROTOCOL instance.
+ @param[in, out] ProfileSize On entry, points to the size in bytes of the ProfileBuffer.
+ On return, points to the size of the data returned in ProfileBuffer.
+ @param[out] ProfileBuffer Profile buffer.
+
+ @return EFI_SUCCESS Get the memory profile data successfully.
+ @return EFI_UNSUPPORTED Memory profile is unsupported.
+ @return EFI_BUFFER_TO_SMALL The ProfileSize is too small for the resulting data.
+ ProfileSize is updated with the size required.
+
+**/
+EFI_STATUS
+EFIAPI
+ProfileProtocolGetData (
+ IN EDKII_MEMORY_PROFILE_PROTOCOL *This,
+ IN OUT UINT64 *ProfileSize,
+ OUT VOID *ProfileBuffer
+ )
+{
+ UINTN Size;
+ MEMORY_PROFILE_CONTEXT_DATA *ContextData;
+ BOOLEAN MemoryProfileGettingStatus;
+
+ ContextData = GetMemoryProfileContext ();
+ if (ContextData == NULL) {
+ return EFI_UNSUPPORTED;
+ }
+
+ MemoryProfileGettingStatus = mMemoryProfileGettingStatus;
+ mMemoryProfileGettingStatus = TRUE;
+
+ Size = MemoryProfileGetDataSize ();
+
+ if (*ProfileSize < Size) {
+ *ProfileSize = Size;
+ mMemoryProfileGettingStatus = MemoryProfileGettingStatus;
+ return EFI_BUFFER_TOO_SMALL;
+ }
+
+ *ProfileSize = Size;
+ MemoryProfileCopyData (ProfileBuffer);
+
+ mMemoryProfileGettingStatus = MemoryProfileGettingStatus;
+ return EFI_SUCCESS;
+}
+
+/**
+ Register image to memory profile.
+
+ @param[in] This The EDKII_MEMORY_PROFILE_PROTOCOL instance.
+ @param[in] FilePath File path of the image.
+ @param[in] ImageBase Image base address.
+ @param[in] ImageSize Image size.
+ @param[in] FileType File type of the image.
+
+ @return EFI_SUCCESS Register successfully.
+ @return EFI_UNSUPPORTED Memory profile is unsupported,
+ or memory profile for the image is not required.
+ @return EFI_OUT_OF_RESOURCES No enough resource for this register.
+
+**/
+EFI_STATUS
+EFIAPI
+ProfileProtocolRegisterImage (
+ IN EDKII_MEMORY_PROFILE_PROTOCOL *This,
+ IN EFI_DEVICE_PATH_PROTOCOL *FilePath,
+ IN PHYSICAL_ADDRESS ImageBase,
+ IN UINT64 ImageSize,
+ IN EFI_FV_FILETYPE FileType
+ )
+{
+ EFI_STATUS Status;
+ LOADED_IMAGE_PRIVATE_DATA DriverEntry;
+ VOID *EntryPointInImage;
+
+ ZeroMem (&DriverEntry, sizeof (DriverEntry));
+ DriverEntry.Info.FilePath = FilePath;
+ DriverEntry.ImageContext.ImageAddress = ImageBase;
+ DriverEntry.ImageContext.ImageSize = ImageSize;
+ Status = InternalPeCoffGetEntryPoint ((VOID *) (UINTN) ImageBase, &EntryPointInImage);
+ ASSERT_EFI_ERROR (Status);
+ DriverEntry.ImageContext.EntryPoint = (PHYSICAL_ADDRESS) (UINTN) EntryPointInImage;
+ DriverEntry.ImageContext.ImageType = InternalPeCoffGetSubsystem ((VOID *) (UINTN) ImageBase);
+
+ return RegisterMemoryProfileImage (&DriverEntry, FileType);
+}
+
+/**
+ Unregister image from memory profile.
+
+ @param[in] This The EDKII_MEMORY_PROFILE_PROTOCOL instance.
+ @param[in] FilePath File path of the image.
+ @param[in] ImageBase Image base address.
+ @param[in] ImageSize Image size.
+
+ @return EFI_SUCCESS Unregister successfully.
+ @return EFI_UNSUPPORTED Memory profile is unsupported,
+ or memory profile for the image is not required.
+ @return EFI_NOT_FOUND The image is not found.
+
+**/
+EFI_STATUS
+EFIAPI
+ProfileProtocolUnregisterImage (
+ IN EDKII_MEMORY_PROFILE_PROTOCOL *This,
+ IN EFI_DEVICE_PATH_PROTOCOL *FilePath,
+ IN PHYSICAL_ADDRESS ImageBase,
+ IN UINT64 ImageSize
+ )
+{
+ EFI_STATUS Status;
+ LOADED_IMAGE_PRIVATE_DATA DriverEntry;
+ VOID *EntryPointInImage;
+
+ ZeroMem (&DriverEntry, sizeof (DriverEntry));
+ DriverEntry.Info.FilePath = FilePath;
+ DriverEntry.ImageContext.ImageAddress = ImageBase;
+ DriverEntry.ImageContext.ImageSize = ImageSize;
+ Status = InternalPeCoffGetEntryPoint ((VOID *) (UINTN) ImageBase, &EntryPointInImage);
+ ASSERT_EFI_ERROR (Status);
+ DriverEntry.ImageContext.EntryPoint = (PHYSICAL_ADDRESS) (UINTN) EntryPointInImage;
+
+ return UnregisterMemoryProfileImage (&DriverEntry);
+}
+
+/**
+ Get memory profile recording state.
+
+ @param[in] This The EDKII_MEMORY_PROFILE_PROTOCOL instance.
+ @param[out] RecordingState Recording state.
+
+ @return EFI_SUCCESS Memory profile recording state is returned.
+ @return EFI_UNSUPPORTED Memory profile is unsupported.
+ @return EFI_INVALID_PARAMETER RecordingState is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+ProfileProtocolGetRecordingState (
+ IN EDKII_MEMORY_PROFILE_PROTOCOL *This,
+ OUT BOOLEAN *RecordingState
+ )
+{
+ MEMORY_PROFILE_CONTEXT_DATA *ContextData;
+
+ ContextData = GetMemoryProfileContext ();
+ if (ContextData == NULL) {
+ return EFI_UNSUPPORTED;
+ }
+
+ if (RecordingState == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+ *RecordingState = mMemoryProfileRecordingEnable;
+ return EFI_SUCCESS;
+}
+
+/**
+ Set memory profile recording state.
+
+ @param[in] This The EDKII_MEMORY_PROFILE_PROTOCOL instance.
+ @param[in] RecordingState Recording state.
+
+ @return EFI_SUCCESS Set memory profile recording state successfully.
+ @return EFI_UNSUPPORTED Memory profile is unsupported.
+
+**/
+EFI_STATUS
+EFIAPI
+ProfileProtocolSetRecordingState (
+ IN EDKII_MEMORY_PROFILE_PROTOCOL *This,
+ IN BOOLEAN RecordingState
+ )
+{
+ MEMORY_PROFILE_CONTEXT_DATA *ContextData;
+
+ ContextData = GetMemoryProfileContext ();
+ if (ContextData == NULL) {
+ return EFI_UNSUPPORTED;
+ }
+
+ mMemoryProfileRecordingEnable = RecordingState;
+ return EFI_SUCCESS;
+}
+
+/**
+ Record memory profile of multilevel caller.
+
+ @param[in] This The EDKII_MEMORY_PROFILE_PROTOCOL instance.
+ @param[in] CallerAddress Address of caller.
+ @param[in] Action Memory profile action.
+ @param[in] MemoryType Memory type.
+ EfiMaxMemoryType means the MemoryType is unknown.
+ @param[in] Buffer Buffer address.
+ @param[in] Size Buffer size.
+ @param[in] ActionString String for memory profile action.
+ Only needed for user defined allocate action.
+
+ @return EFI_SUCCESS Memory profile is updated.
+ @return EFI_UNSUPPORTED Memory profile is unsupported,
+ or memory profile for the image is not required,
+ or memory profile for the memory type is not required.
+ @return EFI_ACCESS_DENIED It is during memory profile data getting.
+ @return EFI_ABORTED Memory profile recording is not enabled.
+ @return EFI_OUT_OF_RESOURCES No enough resource to update memory profile for allocate action.
+ @return EFI_NOT_FOUND No matched allocate info found for free action.
+
+**/
+EFI_STATUS
+EFIAPI
+ProfileProtocolRecord (
+ IN EDKII_MEMORY_PROFILE_PROTOCOL *This,
+ IN PHYSICAL_ADDRESS CallerAddress,
+ IN MEMORY_PROFILE_ACTION Action,
+ IN EFI_MEMORY_TYPE MemoryType,
+ IN VOID *Buffer,
+ IN UINTN Size,
+ IN CHAR8 *ActionString OPTIONAL
+ )
+{
+ return CoreUpdateProfile (CallerAddress, Action, MemoryType, Size, Buffer, ActionString);
+}
+
+////////////////////
diff --git a/roms/edk2/MdeModulePkg/Core/Dxe/Mem/Page.c b/roms/edk2/MdeModulePkg/Core/Dxe/Mem/Page.c
new file mode 100644
index 000000000..2c2c9cd6c
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Core/Dxe/Mem/Page.c
@@ -0,0 +1,2105 @@
+/** @file
+ UEFI Memory page management functions.
+
+Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "DxeMain.h"
+#include "Imem.h"
+#include "HeapGuard.h"
+
+//
+// Entry for tracking the memory regions for each memory type to coalesce similar memory types
+//
+typedef struct {
+ EFI_PHYSICAL_ADDRESS BaseAddress;
+ EFI_PHYSICAL_ADDRESS MaximumAddress;
+ UINT64 CurrentNumberOfPages;
+ UINT64 NumberOfPages;
+ UINTN InformationIndex;
+ BOOLEAN Special;
+ BOOLEAN Runtime;
+} EFI_MEMORY_TYPE_STATISTICS;
+
+//
+// MemoryMap - The current memory map
+//
+UINTN mMemoryMapKey = 0;
+
+#define MAX_MAP_DEPTH 6
+
+///
+/// mMapDepth - depth of new descriptor stack
+///
+UINTN mMapDepth = 0;
+///
+/// mMapStack - space to use as temp storage to build new map descriptors
+///
+MEMORY_MAP mMapStack[MAX_MAP_DEPTH];
+UINTN mFreeMapStack = 0;
+///
+/// This list maintain the free memory map list
+///
+LIST_ENTRY mFreeMemoryMapEntryList = INITIALIZE_LIST_HEAD_VARIABLE (mFreeMemoryMapEntryList);
+BOOLEAN mMemoryTypeInformationInitialized = FALSE;
+
+EFI_MEMORY_TYPE_STATISTICS mMemoryTypeStatistics[EfiMaxMemoryType + 1] = {
+ { 0, MAX_ALLOC_ADDRESS, 0, 0, EfiMaxMemoryType, TRUE, FALSE }, // EfiReservedMemoryType
+ { 0, MAX_ALLOC_ADDRESS, 0, 0, EfiMaxMemoryType, FALSE, FALSE }, // EfiLoaderCode
+ { 0, MAX_ALLOC_ADDRESS, 0, 0, EfiMaxMemoryType, FALSE, FALSE }, // EfiLoaderData
+ { 0, MAX_ALLOC_ADDRESS, 0, 0, EfiMaxMemoryType, FALSE, FALSE }, // EfiBootServicesCode
+ { 0, MAX_ALLOC_ADDRESS, 0, 0, EfiMaxMemoryType, FALSE, FALSE }, // EfiBootServicesData
+ { 0, MAX_ALLOC_ADDRESS, 0, 0, EfiMaxMemoryType, TRUE, TRUE }, // EfiRuntimeServicesCode
+ { 0, MAX_ALLOC_ADDRESS, 0, 0, EfiMaxMemoryType, TRUE, TRUE }, // EfiRuntimeServicesData
+ { 0, MAX_ALLOC_ADDRESS, 0, 0, EfiMaxMemoryType, FALSE, FALSE }, // EfiConventionalMemory
+ { 0, MAX_ALLOC_ADDRESS, 0, 0, EfiMaxMemoryType, FALSE, FALSE }, // EfiUnusableMemory
+ { 0, MAX_ALLOC_ADDRESS, 0, 0, EfiMaxMemoryType, TRUE, FALSE }, // EfiACPIReclaimMemory
+ { 0, MAX_ALLOC_ADDRESS, 0, 0, EfiMaxMemoryType, TRUE, FALSE }, // EfiACPIMemoryNVS
+ { 0, MAX_ALLOC_ADDRESS, 0, 0, EfiMaxMemoryType, FALSE, FALSE }, // EfiMemoryMappedIO
+ { 0, MAX_ALLOC_ADDRESS, 0, 0, EfiMaxMemoryType, FALSE, FALSE }, // EfiMemoryMappedIOPortSpace
+ { 0, MAX_ALLOC_ADDRESS, 0, 0, EfiMaxMemoryType, TRUE, TRUE }, // EfiPalCode
+ { 0, MAX_ALLOC_ADDRESS, 0, 0, EfiMaxMemoryType, FALSE, FALSE }, // EfiPersistentMemory
+ { 0, MAX_ALLOC_ADDRESS, 0, 0, EfiMaxMemoryType, FALSE, FALSE } // EfiMaxMemoryType
+};
+
+EFI_PHYSICAL_ADDRESS mDefaultMaximumAddress = MAX_ALLOC_ADDRESS;
+EFI_PHYSICAL_ADDRESS mDefaultBaseAddress = MAX_ALLOC_ADDRESS;
+
+EFI_MEMORY_TYPE_INFORMATION gMemoryTypeInformation[EfiMaxMemoryType + 1] = {
+ { EfiReservedMemoryType, 0 },
+ { EfiLoaderCode, 0 },
+ { EfiLoaderData, 0 },
+ { EfiBootServicesCode, 0 },
+ { EfiBootServicesData, 0 },
+ { EfiRuntimeServicesCode, 0 },
+ { EfiRuntimeServicesData, 0 },
+ { EfiConventionalMemory, 0 },
+ { EfiUnusableMemory, 0 },
+ { EfiACPIReclaimMemory, 0 },
+ { EfiACPIMemoryNVS, 0 },
+ { EfiMemoryMappedIO, 0 },
+ { EfiMemoryMappedIOPortSpace, 0 },
+ { EfiPalCode, 0 },
+ { EfiPersistentMemory, 0 },
+ { EfiMaxMemoryType, 0 }
+};
+//
+// Only used when load module at fixed address feature is enabled. True means the memory is alreay successfully allocated
+// and ready to load the module in to specified address.or else, the memory is not ready and module will be loaded at a
+// address assigned by DXE core.
+//
+GLOBAL_REMOVE_IF_UNREFERENCED BOOLEAN gLoadFixedAddressCodeMemoryReady = FALSE;
+
+/**
+ Enter critical section by gaining lock on gMemoryLock.
+
+**/
+VOID
+CoreAcquireMemoryLock (
+ VOID
+ )
+{
+ CoreAcquireLock (&gMemoryLock);
+}
+
+
+
+/**
+ Exit critical section by releasing lock on gMemoryLock.
+
+**/
+VOID
+CoreReleaseMemoryLock (
+ VOID
+ )
+{
+ CoreReleaseLock (&gMemoryLock);
+}
+
+
+
+
+/**
+ Internal function. Removes a descriptor entry.
+
+ @param Entry The entry to remove
+
+**/
+VOID
+RemoveMemoryMapEntry (
+ IN OUT MEMORY_MAP *Entry
+ )
+{
+ RemoveEntryList (&Entry->Link);
+ Entry->Link.ForwardLink = NULL;
+
+ if (Entry->FromPages) {
+ //
+ // Insert the free memory map descriptor to the end of mFreeMemoryMapEntryList
+ //
+ InsertTailList (&mFreeMemoryMapEntryList, &Entry->Link);
+ }
+}
+
+/**
+ Internal function. Adds a ranges to the memory map.
+ The range must not already exist in the map.
+
+ @param Type The type of memory range to add
+ @param Start The starting address in the memory range Must be
+ paged aligned
+ @param End The last address in the range Must be the last
+ byte of a page
+ @param Attribute The attributes of the memory range to add
+
+**/
+VOID
+CoreAddRange (
+ IN EFI_MEMORY_TYPE Type,
+ IN EFI_PHYSICAL_ADDRESS Start,
+ IN EFI_PHYSICAL_ADDRESS End,
+ IN UINT64 Attribute
+ )
+{
+ LIST_ENTRY *Link;
+ MEMORY_MAP *Entry;
+
+ ASSERT ((Start & EFI_PAGE_MASK) == 0);
+ ASSERT (End > Start) ;
+
+ ASSERT_LOCKED (&gMemoryLock);
+
+ DEBUG ((DEBUG_PAGE, "AddRange: %lx-%lx to %d\n", Start, End, Type));
+
+ //
+ // If memory of type EfiConventionalMemory is being added that includes the page
+ // starting at address 0, then zero the page starting at address 0. This has
+ // two benifits. It helps find NULL pointer bugs and it also maximizes
+ // compatibility with operating systems that may evaluate memory in this page
+ // for legacy data structures. If memory of any other type is added starting
+ // at address 0, then do not zero the page at address 0 because the page is being
+ // used for other purposes.
+ //
+ if (Type == EfiConventionalMemory && Start == 0 && (End >= EFI_PAGE_SIZE - 1)) {
+ if ((PcdGet8 (PcdNullPointerDetectionPropertyMask) & BIT0) == 0) {
+ SetMem ((VOID *)(UINTN)Start, EFI_PAGE_SIZE, 0);
+ }
+ }
+
+ //
+ // Memory map being altered so updated key
+ //
+ mMemoryMapKey += 1;
+
+ //
+ // UEFI 2.0 added an event group for notificaiton on memory map changes.
+ // So we need to signal this Event Group every time the memory map changes.
+ // If we are in EFI 1.10 compatability mode no event groups will be
+ // found and nothing will happen we we call this function. These events
+ // will get signaled but since a lock is held around the call to this
+ // function the notificaiton events will only be called after this function
+ // returns and the lock is released.
+ //
+ CoreNotifySignalList (&gEfiEventMemoryMapChangeGuid);
+
+ //
+ // Look for adjoining memory descriptor
+ //
+
+ // Two memory descriptors can only be merged if they have the same Type
+ // and the same Attribute
+ //
+
+ Link = gMemoryMap.ForwardLink;
+ while (Link != &gMemoryMap) {
+ Entry = CR (Link, MEMORY_MAP, Link, MEMORY_MAP_SIGNATURE);
+ Link = Link->ForwardLink;
+
+ if (Entry->Type != Type) {
+ continue;
+ }
+
+ if (Entry->Attribute != Attribute) {
+ continue;
+ }
+
+ if (Entry->End + 1 == Start) {
+
+ Start = Entry->Start;
+ RemoveMemoryMapEntry (Entry);
+
+ } else if (Entry->Start == End + 1) {
+
+ End = Entry->End;
+ RemoveMemoryMapEntry (Entry);
+ }
+ }
+
+ //
+ // Add descriptor
+ //
+
+ mMapStack[mMapDepth].Signature = MEMORY_MAP_SIGNATURE;
+ mMapStack[mMapDepth].FromPages = FALSE;
+ mMapStack[mMapDepth].Type = Type;
+ mMapStack[mMapDepth].Start = Start;
+ mMapStack[mMapDepth].End = End;
+ mMapStack[mMapDepth].VirtualStart = 0;
+ mMapStack[mMapDepth].Attribute = Attribute;
+ InsertTailList (&gMemoryMap, &mMapStack[mMapDepth].Link);
+
+ mMapDepth += 1;
+ ASSERT (mMapDepth < MAX_MAP_DEPTH);
+
+ return ;
+}
+
+/**
+ Internal function. Deque a descriptor entry from the mFreeMemoryMapEntryList.
+ If the list is emtry, then allocate a new page to refuel the list.
+ Please Note this algorithm to allocate the memory map descriptor has a property
+ that the memory allocated for memory entries always grows, and will never really be freed
+ For example, if the current boot uses 2000 memory map entries at the maximum point, but
+ ends up with only 50 at the time the OS is booted, then the memory associated with the 1950
+ memory map entries is still allocated from EfiBootServicesMemory.
+
+
+ @return The Memory map descriptor dequed from the mFreeMemoryMapEntryList
+
+**/
+MEMORY_MAP *
+AllocateMemoryMapEntry (
+ VOID
+ )
+{
+ MEMORY_MAP* FreeDescriptorEntries;
+ MEMORY_MAP* Entry;
+ UINTN Index;
+
+ if (IsListEmpty (&mFreeMemoryMapEntryList)) {
+ //
+ // The list is empty, to allocate one page to refuel the list
+ //
+ FreeDescriptorEntries = CoreAllocatePoolPages (
+ EfiBootServicesData,
+ EFI_SIZE_TO_PAGES (DEFAULT_PAGE_ALLOCATION_GRANULARITY),
+ DEFAULT_PAGE_ALLOCATION_GRANULARITY,
+ FALSE
+ );
+ if (FreeDescriptorEntries != NULL) {
+ //
+ // Enque the free memmory map entries into the list
+ //
+ for (Index = 0; Index < DEFAULT_PAGE_ALLOCATION_GRANULARITY / sizeof(MEMORY_MAP); Index++) {
+ FreeDescriptorEntries[Index].Signature = MEMORY_MAP_SIGNATURE;
+ InsertTailList (&mFreeMemoryMapEntryList, &FreeDescriptorEntries[Index].Link);
+ }
+ } else {
+ return NULL;
+ }
+ }
+ //
+ // dequeue the first descriptor from the list
+ //
+ Entry = CR (mFreeMemoryMapEntryList.ForwardLink, MEMORY_MAP, Link, MEMORY_MAP_SIGNATURE);
+ RemoveEntryList (&Entry->Link);
+
+ return Entry;
+}
+
+
+/**
+ Internal function. Moves any memory descriptors that are on the
+ temporary descriptor stack to heap.
+
+**/
+VOID
+CoreFreeMemoryMapStack (
+ VOID
+ )
+{
+ MEMORY_MAP *Entry;
+ MEMORY_MAP *Entry2;
+ LIST_ENTRY *Link2;
+
+ ASSERT_LOCKED (&gMemoryLock);
+
+ //
+ // If already freeing the map stack, then return
+ //
+ if (mFreeMapStack != 0) {
+ return ;
+ }
+
+ //
+ // Move the temporary memory descriptor stack into pool
+ //
+ mFreeMapStack += 1;
+
+ while (mMapDepth != 0) {
+ //
+ // Deque an memory map entry from mFreeMemoryMapEntryList
+ //
+ Entry = AllocateMemoryMapEntry ();
+
+ ASSERT (Entry);
+
+ //
+ // Update to proper entry
+ //
+ mMapDepth -= 1;
+
+ if (mMapStack[mMapDepth].Link.ForwardLink != NULL) {
+
+ //
+ // Move this entry to general memory
+ //
+ RemoveEntryList (&mMapStack[mMapDepth].Link);
+ mMapStack[mMapDepth].Link.ForwardLink = NULL;
+
+ CopyMem (Entry , &mMapStack[mMapDepth], sizeof (MEMORY_MAP));
+ Entry->FromPages = TRUE;
+
+ //
+ // Find insertion location
+ //
+ for (Link2 = gMemoryMap.ForwardLink; Link2 != &gMemoryMap; Link2 = Link2->ForwardLink) {
+ Entry2 = CR (Link2, MEMORY_MAP, Link, MEMORY_MAP_SIGNATURE);
+ if (Entry2->FromPages && Entry2->Start > Entry->Start) {
+ break;
+ }
+ }
+
+ InsertTailList (Link2, &Entry->Link);
+
+ } else {
+ //
+ // This item of mMapStack[mMapDepth] has already been dequeued from gMemoryMap list,
+ // so here no need to move it to memory.
+ //
+ InsertTailList (&mFreeMemoryMapEntryList, &Entry->Link);
+ }
+ }
+
+ mFreeMapStack -= 1;
+}
+
+/**
+ Find untested but initialized memory regions in GCD map and convert them to be DXE allocatable.
+
+**/
+BOOLEAN
+PromoteMemoryResource (
+ VOID
+ )
+{
+ LIST_ENTRY *Link;
+ EFI_GCD_MAP_ENTRY *Entry;
+ BOOLEAN Promoted;
+ EFI_PHYSICAL_ADDRESS StartAddress;
+ EFI_PHYSICAL_ADDRESS EndAddress;
+ EFI_GCD_MEMORY_SPACE_DESCRIPTOR Descriptor;
+
+ DEBUG ((DEBUG_PAGE, "Promote the memory resource\n"));
+
+ CoreAcquireGcdMemoryLock ();
+
+ Promoted = FALSE;
+ Link = mGcdMemorySpaceMap.ForwardLink;
+ while (Link != &mGcdMemorySpaceMap) {
+
+ Entry = CR (Link, EFI_GCD_MAP_ENTRY, Link, EFI_GCD_MAP_SIGNATURE);
+
+ if (Entry->GcdMemoryType == EfiGcdMemoryTypeReserved &&
+ Entry->EndAddress < MAX_ALLOC_ADDRESS &&
+ (Entry->Capabilities & (EFI_MEMORY_PRESENT | EFI_MEMORY_INITIALIZED | EFI_MEMORY_TESTED)) ==
+ (EFI_MEMORY_PRESENT | EFI_MEMORY_INITIALIZED)) {
+ //
+ // Update the GCD map
+ //
+ if ((Entry->Capabilities & EFI_MEMORY_MORE_RELIABLE) == EFI_MEMORY_MORE_RELIABLE) {
+ Entry->GcdMemoryType = EfiGcdMemoryTypeMoreReliable;
+ } else {
+ Entry->GcdMemoryType = EfiGcdMemoryTypeSystemMemory;
+ }
+ Entry->Capabilities |= EFI_MEMORY_TESTED;
+ Entry->ImageHandle = gDxeCoreImageHandle;
+ Entry->DeviceHandle = NULL;
+
+ //
+ // Add to allocable system memory resource
+ //
+
+ CoreAddRange (
+ EfiConventionalMemory,
+ Entry->BaseAddress,
+ Entry->EndAddress,
+ Entry->Capabilities & ~(EFI_MEMORY_PRESENT | EFI_MEMORY_INITIALIZED | EFI_MEMORY_TESTED | EFI_MEMORY_RUNTIME)
+ );
+ CoreFreeMemoryMapStack ();
+
+ Promoted = TRUE;
+ }
+
+ Link = Link->ForwardLink;
+ }
+
+ CoreReleaseGcdMemoryLock ();
+
+ if (!Promoted) {
+ //
+ // If freed-memory guard is enabled, we could promote pages from
+ // guarded free pages.
+ //
+ Promoted = PromoteGuardedFreePages (&StartAddress, &EndAddress);
+ if (Promoted) {
+ CoreGetMemorySpaceDescriptor (StartAddress, &Descriptor);
+ CoreAddRange (
+ EfiConventionalMemory,
+ StartAddress,
+ EndAddress,
+ Descriptor.Capabilities & ~(EFI_MEMORY_PRESENT | EFI_MEMORY_INITIALIZED |
+ EFI_MEMORY_TESTED | EFI_MEMORY_RUNTIME)
+ );
+ }
+ }
+
+ return Promoted;
+}
+/**
+ This function try to allocate Runtime code & Boot time code memory range. If LMFA enabled, 2 patchable PCD
+ PcdLoadFixAddressRuntimeCodePageNumber & PcdLoadFixAddressBootTimeCodePageNumber which are set by tools will record the
+ size of boot time and runtime code.
+
+**/
+VOID
+CoreLoadingFixedAddressHook (
+ VOID
+ )
+{
+ UINT32 RuntimeCodePageNumber;
+ UINT32 BootTimeCodePageNumber;
+ EFI_PHYSICAL_ADDRESS RuntimeCodeBase;
+ EFI_PHYSICAL_ADDRESS BootTimeCodeBase;
+ EFI_STATUS Status;
+
+ //
+ // Make sure these 2 areas are not initialzied.
+ //
+ if (!gLoadFixedAddressCodeMemoryReady) {
+ RuntimeCodePageNumber = PcdGet32(PcdLoadFixAddressRuntimeCodePageNumber);
+ BootTimeCodePageNumber= PcdGet32(PcdLoadFixAddressBootTimeCodePageNumber);
+ RuntimeCodeBase = (EFI_PHYSICAL_ADDRESS)(gLoadModuleAtFixAddressConfigurationTable.DxeCodeTopAddress - EFI_PAGES_TO_SIZE (RuntimeCodePageNumber));
+ BootTimeCodeBase = (EFI_PHYSICAL_ADDRESS)(RuntimeCodeBase - EFI_PAGES_TO_SIZE (BootTimeCodePageNumber));
+ //
+ // Try to allocate runtime memory.
+ //
+ Status = CoreAllocatePages (
+ AllocateAddress,
+ EfiRuntimeServicesCode,
+ RuntimeCodePageNumber,
+ &RuntimeCodeBase
+ );
+ if (EFI_ERROR(Status)) {
+ //
+ // Runtime memory allocation failed
+ //
+ return;
+ }
+ //
+ // Try to allocate boot memory.
+ //
+ Status = CoreAllocatePages (
+ AllocateAddress,
+ EfiBootServicesCode,
+ BootTimeCodePageNumber,
+ &BootTimeCodeBase
+ );
+ if (EFI_ERROR(Status)) {
+ //
+ // boot memory allocation failed. Free Runtime code range and will try the allocation again when
+ // new memory range is installed.
+ //
+ CoreFreePages (
+ RuntimeCodeBase,
+ RuntimeCodePageNumber
+ );
+ return;
+ }
+ gLoadFixedAddressCodeMemoryReady = TRUE;
+ }
+ return;
+}
+
+/**
+ Called to initialize the memory map and add descriptors to
+ the current descriptor list.
+ The first descriptor that is added must be general usable
+ memory as the addition allocates heap.
+
+ @param Type The type of memory to add
+ @param Start The starting address in the memory range Must be
+ page aligned
+ @param NumberOfPages The number of pages in the range
+ @param Attribute Attributes of the memory to add
+
+ @return None. The range is added to the memory map
+
+**/
+VOID
+CoreAddMemoryDescriptor (
+ IN EFI_MEMORY_TYPE Type,
+ IN EFI_PHYSICAL_ADDRESS Start,
+ IN UINT64 NumberOfPages,
+ IN UINT64 Attribute
+ )
+{
+ EFI_PHYSICAL_ADDRESS End;
+ EFI_STATUS Status;
+ UINTN Index;
+ UINTN FreeIndex;
+
+ if ((Start & EFI_PAGE_MASK) != 0) {
+ return;
+ }
+
+ if (Type >= EfiMaxMemoryType && Type < MEMORY_TYPE_OEM_RESERVED_MIN) {
+ return;
+ }
+ CoreAcquireMemoryLock ();
+ End = Start + LShiftU64 (NumberOfPages, EFI_PAGE_SHIFT) - 1;
+ CoreAddRange (Type, Start, End, Attribute);
+ CoreFreeMemoryMapStack ();
+ CoreReleaseMemoryLock ();
+
+ ApplyMemoryProtectionPolicy (EfiMaxMemoryType, Type, Start,
+ LShiftU64 (NumberOfPages, EFI_PAGE_SHIFT));
+
+ //
+ // If Loading Module At Fixed Address feature is enabled. try to allocate memory with Runtime code & Boot time code type
+ //
+ if (PcdGet64(PcdLoadModuleAtFixAddressEnable) != 0) {
+ CoreLoadingFixedAddressHook();
+ }
+
+ //
+ // Check to see if the statistics for the different memory types have already been established
+ //
+ if (mMemoryTypeInformationInitialized) {
+ return;
+ }
+
+
+ //
+ // Loop through each memory type in the order specified by the gMemoryTypeInformation[] array
+ //
+ for (Index = 0; gMemoryTypeInformation[Index].Type != EfiMaxMemoryType; Index++) {
+ //
+ // Make sure the memory type in the gMemoryTypeInformation[] array is valid
+ //
+ Type = (EFI_MEMORY_TYPE) (gMemoryTypeInformation[Index].Type);
+ if ((UINT32)Type > EfiMaxMemoryType) {
+ continue;
+ }
+ if (gMemoryTypeInformation[Index].NumberOfPages != 0) {
+ //
+ // Allocate pages for the current memory type from the top of available memory
+ //
+ Status = CoreAllocatePages (
+ AllocateAnyPages,
+ Type,
+ gMemoryTypeInformation[Index].NumberOfPages,
+ &mMemoryTypeStatistics[Type].BaseAddress
+ );
+ if (EFI_ERROR (Status)) {
+ //
+ // If an error occurs allocating the pages for the current memory type, then
+ // free all the pages allocates for the previous memory types and return. This
+ // operation with be retied when/if more memory is added to the system
+ //
+ for (FreeIndex = 0; FreeIndex < Index; FreeIndex++) {
+ //
+ // Make sure the memory type in the gMemoryTypeInformation[] array is valid
+ //
+ Type = (EFI_MEMORY_TYPE) (gMemoryTypeInformation[FreeIndex].Type);
+ if ((UINT32)Type > EfiMaxMemoryType) {
+ continue;
+ }
+
+ if (gMemoryTypeInformation[FreeIndex].NumberOfPages != 0) {
+ CoreFreePages (
+ mMemoryTypeStatistics[Type].BaseAddress,
+ gMemoryTypeInformation[FreeIndex].NumberOfPages
+ );
+ mMemoryTypeStatistics[Type].BaseAddress = 0;
+ mMemoryTypeStatistics[Type].MaximumAddress = MAX_ALLOC_ADDRESS;
+ }
+ }
+ return;
+ }
+
+ //
+ // Compute the address at the top of the current statistics
+ //
+ mMemoryTypeStatistics[Type].MaximumAddress =
+ mMemoryTypeStatistics[Type].BaseAddress +
+ LShiftU64 (gMemoryTypeInformation[Index].NumberOfPages, EFI_PAGE_SHIFT) - 1;
+
+ //
+ // If the current base address is the lowest address so far, then update the default
+ // maximum address
+ //
+ if (mMemoryTypeStatistics[Type].BaseAddress < mDefaultMaximumAddress) {
+ mDefaultMaximumAddress = mMemoryTypeStatistics[Type].BaseAddress - 1;
+ }
+ }
+ }
+
+ //
+ // There was enough system memory for all the the memory types were allocated. So,
+ // those memory areas can be freed for future allocations, and all future memory
+ // allocations can occur within their respective bins
+ //
+ for (Index = 0; gMemoryTypeInformation[Index].Type != EfiMaxMemoryType; Index++) {
+ //
+ // Make sure the memory type in the gMemoryTypeInformation[] array is valid
+ //
+ Type = (EFI_MEMORY_TYPE) (gMemoryTypeInformation[Index].Type);
+ if ((UINT32)Type > EfiMaxMemoryType) {
+ continue;
+ }
+ if (gMemoryTypeInformation[Index].NumberOfPages != 0) {
+ CoreFreePages (
+ mMemoryTypeStatistics[Type].BaseAddress,
+ gMemoryTypeInformation[Index].NumberOfPages
+ );
+ mMemoryTypeStatistics[Type].NumberOfPages = gMemoryTypeInformation[Index].NumberOfPages;
+ gMemoryTypeInformation[Index].NumberOfPages = 0;
+ }
+ }
+
+ //
+ // If the number of pages reserved for a memory type is 0, then all allocations for that type
+ // should be in the default range.
+ //
+ for (Type = (EFI_MEMORY_TYPE) 0; Type < EfiMaxMemoryType; Type++) {
+ for (Index = 0; gMemoryTypeInformation[Index].Type != EfiMaxMemoryType; Index++) {
+ if (Type == (EFI_MEMORY_TYPE)gMemoryTypeInformation[Index].Type) {
+ mMemoryTypeStatistics[Type].InformationIndex = Index;
+ }
+ }
+ mMemoryTypeStatistics[Type].CurrentNumberOfPages = 0;
+ if (mMemoryTypeStatistics[Type].MaximumAddress == MAX_ALLOC_ADDRESS) {
+ mMemoryTypeStatistics[Type].MaximumAddress = mDefaultMaximumAddress;
+ }
+ }
+
+ mMemoryTypeInformationInitialized = TRUE;
+}
+
+
+/**
+ Internal function. Converts a memory range to the specified type or attributes.
+ The range must exist in the memory map. Either ChangingType or
+ ChangingAttributes must be set, but not both.
+
+ @param Start The first address of the range Must be page
+ aligned
+ @param NumberOfPages The number of pages to convert
+ @param ChangingType Boolean indicating that type value should be changed
+ @param NewType The new type for the memory range
+ @param ChangingAttributes Boolean indicating that attributes value should be changed
+ @param NewAttributes The new attributes for the memory range
+
+ @retval EFI_INVALID_PARAMETER Invalid parameter
+ @retval EFI_NOT_FOUND Could not find a descriptor cover the specified
+ range or convertion not allowed.
+ @retval EFI_SUCCESS Successfully converts the memory range to the
+ specified type.
+
+**/
+EFI_STATUS
+CoreConvertPagesEx (
+ IN UINT64 Start,
+ IN UINT64 NumberOfPages,
+ IN BOOLEAN ChangingType,
+ IN EFI_MEMORY_TYPE NewType,
+ IN BOOLEAN ChangingAttributes,
+ IN UINT64 NewAttributes
+ )
+{
+
+ UINT64 NumberOfBytes;
+ UINT64 End;
+ UINT64 RangeEnd;
+ UINT64 Attribute;
+ EFI_MEMORY_TYPE MemType;
+ LIST_ENTRY *Link;
+ MEMORY_MAP *Entry;
+
+ Entry = NULL;
+ NumberOfBytes = LShiftU64 (NumberOfPages, EFI_PAGE_SHIFT);
+ End = Start + NumberOfBytes - 1;
+
+ ASSERT (NumberOfPages);
+ ASSERT ((Start & EFI_PAGE_MASK) == 0);
+ ASSERT (End > Start) ;
+ ASSERT_LOCKED (&gMemoryLock);
+ ASSERT ( (ChangingType == FALSE) || (ChangingAttributes == FALSE) );
+
+ if (NumberOfPages == 0 || ((Start & EFI_PAGE_MASK) != 0) || (Start >= End)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Convert the entire range
+ //
+
+ while (Start < End) {
+
+ //
+ // Find the entry that the covers the range
+ //
+ for (Link = gMemoryMap.ForwardLink; Link != &gMemoryMap; Link = Link->ForwardLink) {
+ Entry = CR (Link, MEMORY_MAP, Link, MEMORY_MAP_SIGNATURE);
+
+ if (Entry->Start <= Start && Entry->End > Start) {
+ break;
+ }
+ }
+
+ if (Link == &gMemoryMap) {
+ DEBUG ((DEBUG_ERROR | DEBUG_PAGE, "ConvertPages: failed to find range %lx - %lx\n", Start, End));
+ return EFI_NOT_FOUND;
+ }
+
+ //
+ // If we are converting the type of the range from EfiConventionalMemory to
+ // another type, we have to ensure that the entire range is covered by a
+ // single entry.
+ //
+ if (ChangingType && (NewType != EfiConventionalMemory)) {
+ if (Entry->End < End) {
+ DEBUG ((DEBUG_ERROR | DEBUG_PAGE, "ConvertPages: range %lx - %lx covers multiple entries\n", Start, End));
+ return EFI_NOT_FOUND;
+ }
+ }
+ //
+ // Convert range to the end, or to the end of the descriptor
+ // if that's all we've got
+ //
+ RangeEnd = End;
+
+ ASSERT (Entry != NULL);
+ if (Entry->End < End) {
+ RangeEnd = Entry->End;
+ }
+
+ if (ChangingType) {
+ DEBUG ((DEBUG_PAGE, "ConvertRange: %lx-%lx to type %d\n", Start, RangeEnd, NewType));
+ }
+ if (ChangingAttributes) {
+ DEBUG ((DEBUG_PAGE, "ConvertRange: %lx-%lx to attr %lx\n", Start, RangeEnd, NewAttributes));
+ }
+
+ if (ChangingType) {
+ //
+ // Debug code - verify conversion is allowed
+ //
+ if (!(NewType == EfiConventionalMemory ? 1 : 0) ^ (Entry->Type == EfiConventionalMemory ? 1 : 0)) {
+ DEBUG ((DEBUG_ERROR | DEBUG_PAGE, "ConvertPages: Incompatible memory types, "));
+ if (Entry->Type == EfiConventionalMemory) {
+ DEBUG ((DEBUG_ERROR | DEBUG_PAGE, "the pages to free have been freed\n"));
+ } else {
+ DEBUG ((DEBUG_ERROR | DEBUG_PAGE, "the pages to allocate have been allocated\n"));
+ }
+ return EFI_NOT_FOUND;
+ }
+
+ //
+ // Update counters for the number of pages allocated to each memory type
+ //
+ if ((UINT32)Entry->Type < EfiMaxMemoryType) {
+ if ((Start >= mMemoryTypeStatistics[Entry->Type].BaseAddress && Start <= mMemoryTypeStatistics[Entry->Type].MaximumAddress) ||
+ (Start >= mDefaultBaseAddress && Start <= mDefaultMaximumAddress) ) {
+ if (NumberOfPages > mMemoryTypeStatistics[Entry->Type].CurrentNumberOfPages) {
+ mMemoryTypeStatistics[Entry->Type].CurrentNumberOfPages = 0;
+ } else {
+ mMemoryTypeStatistics[Entry->Type].CurrentNumberOfPages -= NumberOfPages;
+ }
+ }
+ }
+
+ if ((UINT32)NewType < EfiMaxMemoryType) {
+ if ((Start >= mMemoryTypeStatistics[NewType].BaseAddress && Start <= mMemoryTypeStatistics[NewType].MaximumAddress) ||
+ (Start >= mDefaultBaseAddress && Start <= mDefaultMaximumAddress) ) {
+ mMemoryTypeStatistics[NewType].CurrentNumberOfPages += NumberOfPages;
+ if (mMemoryTypeStatistics[NewType].CurrentNumberOfPages > gMemoryTypeInformation[mMemoryTypeStatistics[NewType].InformationIndex].NumberOfPages) {
+ gMemoryTypeInformation[mMemoryTypeStatistics[NewType].InformationIndex].NumberOfPages = (UINT32)mMemoryTypeStatistics[NewType].CurrentNumberOfPages;
+ }
+ }
+ }
+ }
+
+ //
+ // Pull range out of descriptor
+ //
+ if (Entry->Start == Start) {
+
+ //
+ // Clip start
+ //
+ Entry->Start = RangeEnd + 1;
+
+ } else if (Entry->End == RangeEnd) {
+
+ //
+ // Clip end
+ //
+ Entry->End = Start - 1;
+
+ } else {
+
+ //
+ // Pull it out of the center, clip current
+ //
+
+ //
+ // Add a new one
+ //
+ mMapStack[mMapDepth].Signature = MEMORY_MAP_SIGNATURE;
+ mMapStack[mMapDepth].FromPages = FALSE;
+ mMapStack[mMapDepth].Type = Entry->Type;
+ mMapStack[mMapDepth].Start = RangeEnd+1;
+ mMapStack[mMapDepth].End = Entry->End;
+
+ //
+ // Inherit Attribute from the Memory Descriptor that is being clipped
+ //
+ mMapStack[mMapDepth].Attribute = Entry->Attribute;
+
+ Entry->End = Start - 1;
+ ASSERT (Entry->Start < Entry->End);
+
+ Entry = &mMapStack[mMapDepth];
+ InsertTailList (&gMemoryMap, &Entry->Link);
+
+ mMapDepth += 1;
+ ASSERT (mMapDepth < MAX_MAP_DEPTH);
+ }
+
+ //
+ // The new range inherits the same Attribute as the Entry
+ // it is being cut out of unless attributes are being changed
+ //
+ if (ChangingType) {
+ Attribute = Entry->Attribute;
+ MemType = NewType;
+ } else {
+ Attribute = NewAttributes;
+ MemType = Entry->Type;
+ }
+
+ //
+ // If the descriptor is empty, then remove it from the map
+ //
+ if (Entry->Start == Entry->End + 1) {
+ RemoveMemoryMapEntry (Entry);
+ Entry = NULL;
+ }
+
+ //
+ // Add our new range in. Don't do this for freed pages if freed-memory
+ // guard is enabled.
+ //
+ if (!IsHeapGuardEnabled (GUARD_HEAP_TYPE_FREED) ||
+ !ChangingType ||
+ MemType != EfiConventionalMemory) {
+ CoreAddRange (MemType, Start, RangeEnd, Attribute);
+ }
+
+ if (ChangingType && (MemType == EfiConventionalMemory)) {
+ //
+ // Avoid calling DEBUG_CLEAR_MEMORY() for an address of 0 because this
+ // macro will ASSERT() if address is 0. Instead, CoreAddRange() guarantees
+ // that the page starting at address 0 is always filled with zeros.
+ //
+ if (Start == 0) {
+ if (RangeEnd > EFI_PAGE_SIZE) {
+ DEBUG_CLEAR_MEMORY ((VOID *)(UINTN) EFI_PAGE_SIZE, (UINTN) (RangeEnd - EFI_PAGE_SIZE + 1));
+ }
+ } else {
+ DEBUG_CLEAR_MEMORY ((VOID *)(UINTN) Start, (UINTN) (RangeEnd - Start + 1));
+ }
+ }
+
+ //
+ // Move any map descriptor stack to general pool
+ //
+ CoreFreeMemoryMapStack ();
+
+ //
+ // Bump the starting address, and convert the next range
+ //
+ Start = RangeEnd + 1;
+ }
+
+ //
+ // Converted the whole range, done
+ //
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Internal function. Converts a memory range to the specified type.
+ The range must exist in the memory map.
+
+ @param Start The first address of the range Must be page
+ aligned
+ @param NumberOfPages The number of pages to convert
+ @param NewType The new type for the memory range
+
+ @retval EFI_INVALID_PARAMETER Invalid parameter
+ @retval EFI_NOT_FOUND Could not find a descriptor cover the specified
+ range or convertion not allowed.
+ @retval EFI_SUCCESS Successfully converts the memory range to the
+ specified type.
+
+**/
+EFI_STATUS
+CoreConvertPages (
+ IN UINT64 Start,
+ IN UINT64 NumberOfPages,
+ IN EFI_MEMORY_TYPE NewType
+ )
+{
+ return CoreConvertPagesEx(Start, NumberOfPages, TRUE, NewType, FALSE, 0);
+}
+
+
+/**
+ Internal function. Converts a memory range to use new attributes.
+
+ @param Start The first address of the range Must be page
+ aligned
+ @param NumberOfPages The number of pages to convert
+ @param NewAttributes The new attributes value for the range.
+
+**/
+VOID
+CoreUpdateMemoryAttributes (
+ IN EFI_PHYSICAL_ADDRESS Start,
+ IN UINT64 NumberOfPages,
+ IN UINT64 NewAttributes
+ )
+{
+ CoreAcquireMemoryLock ();
+
+ //
+ // Update the attributes to the new value
+ //
+ CoreConvertPagesEx(Start, NumberOfPages, FALSE, (EFI_MEMORY_TYPE)0, TRUE, NewAttributes);
+
+ CoreReleaseMemoryLock ();
+}
+
+
+/**
+ Internal function. Finds a consecutive free page range below
+ the requested address.
+
+ @param MaxAddress The address that the range must be below
+ @param MinAddress The address that the range must be above
+ @param NumberOfPages Number of pages needed
+ @param NewType The type of memory the range is going to be
+ turned into
+ @param Alignment Bits to align with
+ @param NeedGuard Flag to indicate Guard page is needed or not
+
+ @return The base address of the range, or 0 if the range was not found
+
+**/
+UINT64
+CoreFindFreePagesI (
+ IN UINT64 MaxAddress,
+ IN UINT64 MinAddress,
+ IN UINT64 NumberOfPages,
+ IN EFI_MEMORY_TYPE NewType,
+ IN UINTN Alignment,
+ IN BOOLEAN NeedGuard
+ )
+{
+ UINT64 NumberOfBytes;
+ UINT64 Target;
+ UINT64 DescStart;
+ UINT64 DescEnd;
+ UINT64 DescNumberOfBytes;
+ LIST_ENTRY *Link;
+ MEMORY_MAP *Entry;
+
+ if ((MaxAddress < EFI_PAGE_MASK) ||(NumberOfPages == 0)) {
+ return 0;
+ }
+
+ if ((MaxAddress & EFI_PAGE_MASK) != EFI_PAGE_MASK) {
+
+ //
+ // If MaxAddress is not aligned to the end of a page
+ //
+
+ //
+ // Change MaxAddress to be 1 page lower
+ //
+ MaxAddress -= (EFI_PAGE_MASK + 1);
+
+ //
+ // Set MaxAddress to a page boundary
+ //
+ MaxAddress &= ~(UINT64)EFI_PAGE_MASK;
+
+ //
+ // Set MaxAddress to end of the page
+ //
+ MaxAddress |= EFI_PAGE_MASK;
+ }
+
+ NumberOfBytes = LShiftU64 (NumberOfPages, EFI_PAGE_SHIFT);
+ Target = 0;
+
+ for (Link = gMemoryMap.ForwardLink; Link != &gMemoryMap; Link = Link->ForwardLink) {
+ Entry = CR (Link, MEMORY_MAP, Link, MEMORY_MAP_SIGNATURE);
+
+ //
+ // If it's not a free entry, don't bother with it
+ //
+ if (Entry->Type != EfiConventionalMemory) {
+ continue;
+ }
+
+ DescStart = Entry->Start;
+ DescEnd = Entry->End;
+
+ //
+ // If desc is past max allowed address or below min allowed address, skip it
+ //
+ if ((DescStart >= MaxAddress) || (DescEnd < MinAddress)) {
+ continue;
+ }
+
+ //
+ // If desc ends past max allowed address, clip the end
+ //
+ if (DescEnd >= MaxAddress) {
+ DescEnd = MaxAddress;
+ }
+
+ DescEnd = ((DescEnd + 1) & (~(Alignment - 1))) - 1;
+
+ // Skip if DescEnd is less than DescStart after alignment clipping
+ if (DescEnd < DescStart) {
+ continue;
+ }
+
+ //
+ // Compute the number of bytes we can used from this
+ // descriptor, and see it's enough to satisfy the request
+ //
+ DescNumberOfBytes = DescEnd - DescStart + 1;
+
+ if (DescNumberOfBytes >= NumberOfBytes) {
+ //
+ // If the start of the allocated range is below the min address allowed, skip it
+ //
+ if ((DescEnd - NumberOfBytes + 1) < MinAddress) {
+ continue;
+ }
+
+ //
+ // If this is the best match so far remember it
+ //
+ if (DescEnd > Target) {
+ if (NeedGuard) {
+ DescEnd = AdjustMemoryS (
+ DescEnd + 1 - DescNumberOfBytes,
+ DescNumberOfBytes,
+ NumberOfBytes
+ );
+ if (DescEnd == 0) {
+ continue;
+ }
+ }
+
+ Target = DescEnd;
+ }
+ }
+ }
+
+ //
+ // If this is a grow down, adjust target to be the allocation base
+ //
+ Target -= NumberOfBytes - 1;
+
+ //
+ // If we didn't find a match, return 0
+ //
+ if ((Target & EFI_PAGE_MASK) != 0) {
+ return 0;
+ }
+
+ return Target;
+}
+
+
+/**
+ Internal function. Finds a consecutive free page range below
+ the requested address
+
+ @param MaxAddress The address that the range must be below
+ @param NoPages Number of pages needed
+ @param NewType The type of memory the range is going to be
+ turned into
+ @param Alignment Bits to align with
+ @param NeedGuard Flag to indicate Guard page is needed or not
+
+ @return The base address of the range, or 0 if the range was not found.
+
+**/
+UINT64
+FindFreePages (
+ IN UINT64 MaxAddress,
+ IN UINT64 NoPages,
+ IN EFI_MEMORY_TYPE NewType,
+ IN UINTN Alignment,
+ IN BOOLEAN NeedGuard
+ )
+{
+ UINT64 Start;
+
+ //
+ // Attempt to find free pages in the preferred bin based on the requested memory type
+ //
+ if ((UINT32)NewType < EfiMaxMemoryType && MaxAddress >= mMemoryTypeStatistics[NewType].MaximumAddress) {
+ Start = CoreFindFreePagesI (
+ mMemoryTypeStatistics[NewType].MaximumAddress,
+ mMemoryTypeStatistics[NewType].BaseAddress,
+ NoPages,
+ NewType,
+ Alignment,
+ NeedGuard
+ );
+ if (Start != 0) {
+ return Start;
+ }
+ }
+
+ //
+ // Attempt to find free pages in the default allocation bin
+ //
+ if (MaxAddress >= mDefaultMaximumAddress) {
+ Start = CoreFindFreePagesI (mDefaultMaximumAddress, 0, NoPages, NewType,
+ Alignment, NeedGuard);
+ if (Start != 0) {
+ if (Start < mDefaultBaseAddress) {
+ mDefaultBaseAddress = Start;
+ }
+ return Start;
+ }
+ }
+
+ //
+ // The allocation did not succeed in any of the prefered bins even after
+ // promoting resources. Attempt to find free pages anywhere is the requested
+ // address range. If this allocation fails, then there are not enough
+ // resources anywhere to satisfy the request.
+ //
+ Start = CoreFindFreePagesI (MaxAddress, 0, NoPages, NewType, Alignment,
+ NeedGuard);
+ if (Start != 0) {
+ return Start;
+ }
+
+ //
+ // If allocations from the preferred bins fail, then attempt to promote memory resources.
+ //
+ if (!PromoteMemoryResource ()) {
+ return 0;
+ }
+
+ //
+ // If any memory resources were promoted, then re-attempt the allocation
+ //
+ return FindFreePages (MaxAddress, NoPages, NewType, Alignment, NeedGuard);
+}
+
+
+/**
+ Allocates pages from the memory map.
+
+ @param Type The type of allocation to perform
+ @param MemoryType The type of memory to turn the allocated pages
+ into
+ @param NumberOfPages The number of pages to allocate
+ @param Memory A pointer to receive the base allocated memory
+ address
+ @param NeedGuard Flag to indicate Guard page is needed or not
+
+ @return Status. On success, Memory is filled in with the base address allocated
+ @retval EFI_INVALID_PARAMETER Parameters violate checking rules defined in
+ spec.
+ @retval EFI_NOT_FOUND Could not allocate pages match the requirement.
+ @retval EFI_OUT_OF_RESOURCES No enough pages to allocate.
+ @retval EFI_SUCCESS Pages successfully allocated.
+
+**/
+EFI_STATUS
+EFIAPI
+CoreInternalAllocatePages (
+ IN EFI_ALLOCATE_TYPE Type,
+ IN EFI_MEMORY_TYPE MemoryType,
+ IN UINTN NumberOfPages,
+ IN OUT EFI_PHYSICAL_ADDRESS *Memory,
+ IN BOOLEAN NeedGuard
+ )
+{
+ EFI_STATUS Status;
+ UINT64 Start;
+ UINT64 NumberOfBytes;
+ UINT64 End;
+ UINT64 MaxAddress;
+ UINTN Alignment;
+ EFI_MEMORY_TYPE CheckType;
+
+ if ((UINT32)Type >= MaxAllocateType) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if ((MemoryType >= EfiMaxMemoryType && MemoryType < MEMORY_TYPE_OEM_RESERVED_MIN) ||
+ (MemoryType == EfiConventionalMemory) || (MemoryType == EfiPersistentMemory)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (Memory == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Alignment = DEFAULT_PAGE_ALLOCATION_GRANULARITY;
+
+ if (MemoryType == EfiACPIReclaimMemory ||
+ MemoryType == EfiACPIMemoryNVS ||
+ MemoryType == EfiRuntimeServicesCode ||
+ MemoryType == EfiRuntimeServicesData) {
+
+ Alignment = RUNTIME_PAGE_ALLOCATION_GRANULARITY;
+ }
+
+ if (Type == AllocateAddress) {
+ if ((*Memory & (Alignment - 1)) != 0) {
+ return EFI_NOT_FOUND;
+ }
+ }
+
+ NumberOfPages += EFI_SIZE_TO_PAGES (Alignment) - 1;
+ NumberOfPages &= ~(EFI_SIZE_TO_PAGES (Alignment) - 1);
+
+ //
+ // If this is for below a particular address, then
+ //
+ Start = *Memory;
+
+ //
+ // The max address is the max natively addressable address for the processor
+ //
+ MaxAddress = MAX_ALLOC_ADDRESS;
+
+ //
+ // Check for Type AllocateAddress,
+ // if NumberOfPages is 0 or
+ // if (NumberOfPages << EFI_PAGE_SHIFT) is above MAX_ALLOC_ADDRESS or
+ // if (Start + NumberOfBytes) rolls over 0 or
+ // if Start is above MAX_ALLOC_ADDRESS or
+ // if End is above MAX_ALLOC_ADDRESS,
+ // if Start..End overlaps any tracked MemoryTypeStatistics range
+ // return EFI_NOT_FOUND.
+ //
+ if (Type == AllocateAddress) {
+ if ((NumberOfPages == 0) ||
+ (NumberOfPages > RShiftU64 (MaxAddress, EFI_PAGE_SHIFT))) {
+ return EFI_NOT_FOUND;
+ }
+ NumberOfBytes = LShiftU64 (NumberOfPages, EFI_PAGE_SHIFT);
+ End = Start + NumberOfBytes - 1;
+
+ if ((Start >= End) ||
+ (Start > MaxAddress) ||
+ (End > MaxAddress)) {
+ return EFI_NOT_FOUND;
+ }
+
+ //
+ // A driver is allowed to call AllocatePages using an AllocateAddress type. This type of
+ // AllocatePage request the exact physical address if it is not used. The existing code
+ // will allow this request even in 'special' pages. The problem with this is that the
+ // reason to have 'special' pages for OS hibernate/resume is defeated as memory is
+ // fragmented.
+ //
+
+ for (CheckType = (EFI_MEMORY_TYPE) 0; CheckType < EfiMaxMemoryType; CheckType++) {
+ if (MemoryType != CheckType &&
+ mMemoryTypeStatistics[CheckType].Special &&
+ mMemoryTypeStatistics[CheckType].NumberOfPages > 0) {
+ if (Start >= mMemoryTypeStatistics[CheckType].BaseAddress &&
+ Start <= mMemoryTypeStatistics[CheckType].MaximumAddress) {
+ return EFI_NOT_FOUND;
+ }
+ if (End >= mMemoryTypeStatistics[CheckType].BaseAddress &&
+ End <= mMemoryTypeStatistics[CheckType].MaximumAddress) {
+ return EFI_NOT_FOUND;
+ }
+ if (Start < mMemoryTypeStatistics[CheckType].BaseAddress &&
+ End > mMemoryTypeStatistics[CheckType].MaximumAddress) {
+ return EFI_NOT_FOUND;
+ }
+ }
+ }
+ }
+
+ if (Type == AllocateMaxAddress) {
+ MaxAddress = Start;
+ }
+
+ CoreAcquireMemoryLock ();
+
+ //
+ // If not a specific address, then find an address to allocate
+ //
+ if (Type != AllocateAddress) {
+ Start = FindFreePages (MaxAddress, NumberOfPages, MemoryType, Alignment,
+ NeedGuard);
+ if (Start == 0) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Done;
+ }
+ }
+
+ //
+ // Convert pages from FreeMemory to the requested type
+ //
+ if (NeedGuard) {
+ Status = CoreConvertPagesWithGuard(Start, NumberOfPages, MemoryType);
+ } else {
+ Status = CoreConvertPages(Start, NumberOfPages, MemoryType);
+ }
+
+Done:
+ CoreReleaseMemoryLock ();
+
+ if (!EFI_ERROR (Status)) {
+ if (NeedGuard) {
+ SetGuardForMemory (Start, NumberOfPages);
+ }
+ *Memory = Start;
+ }
+
+ return Status;
+}
+
+/**
+ Allocates pages from the memory map.
+
+ @param Type The type of allocation to perform
+ @param MemoryType The type of memory to turn the allocated pages
+ into
+ @param NumberOfPages The number of pages to allocate
+ @param Memory A pointer to receive the base allocated memory
+ address
+
+ @return Status. On success, Memory is filled in with the base address allocated
+ @retval EFI_INVALID_PARAMETER Parameters violate checking rules defined in
+ spec.
+ @retval EFI_NOT_FOUND Could not allocate pages match the requirement.
+ @retval EFI_OUT_OF_RESOURCES No enough pages to allocate.
+ @retval EFI_SUCCESS Pages successfully allocated.
+
+**/
+EFI_STATUS
+EFIAPI
+CoreAllocatePages (
+ IN EFI_ALLOCATE_TYPE Type,
+ IN EFI_MEMORY_TYPE MemoryType,
+ IN UINTN NumberOfPages,
+ OUT EFI_PHYSICAL_ADDRESS *Memory
+ )
+{
+ EFI_STATUS Status;
+ BOOLEAN NeedGuard;
+
+ NeedGuard = IsPageTypeToGuard (MemoryType, Type) && !mOnGuarding;
+ Status = CoreInternalAllocatePages (Type, MemoryType, NumberOfPages, Memory,
+ NeedGuard);
+ if (!EFI_ERROR (Status)) {
+ CoreUpdateProfile (
+ (EFI_PHYSICAL_ADDRESS) (UINTN) RETURN_ADDRESS (0),
+ MemoryProfileActionAllocatePages,
+ MemoryType,
+ EFI_PAGES_TO_SIZE (NumberOfPages),
+ (VOID *) (UINTN) *Memory,
+ NULL
+ );
+ InstallMemoryAttributesTableOnMemoryAllocation (MemoryType);
+ ApplyMemoryProtectionPolicy (EfiConventionalMemory, MemoryType, *Memory,
+ EFI_PAGES_TO_SIZE (NumberOfPages));
+ }
+ return Status;
+}
+
+/**
+ Frees previous allocated pages.
+
+ @param Memory Base address of memory being freed
+ @param NumberOfPages The number of pages to free
+ @param MemoryType Pointer to memory type
+
+ @retval EFI_NOT_FOUND Could not find the entry that covers the range
+ @retval EFI_INVALID_PARAMETER Address not aligned
+ @return EFI_SUCCESS -Pages successfully freed.
+
+**/
+EFI_STATUS
+EFIAPI
+CoreInternalFreePages (
+ IN EFI_PHYSICAL_ADDRESS Memory,
+ IN UINTN NumberOfPages,
+ OUT EFI_MEMORY_TYPE *MemoryType OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+ LIST_ENTRY *Link;
+ MEMORY_MAP *Entry;
+ UINTN Alignment;
+ BOOLEAN IsGuarded;
+
+ //
+ // Free the range
+ //
+ CoreAcquireMemoryLock ();
+
+ //
+ // Find the entry that the covers the range
+ //
+ IsGuarded = FALSE;
+ Entry = NULL;
+ for (Link = gMemoryMap.ForwardLink; Link != &gMemoryMap; Link = Link->ForwardLink) {
+ Entry = CR(Link, MEMORY_MAP, Link, MEMORY_MAP_SIGNATURE);
+ if (Entry->Start <= Memory && Entry->End > Memory) {
+ break;
+ }
+ }
+ if (Link == &gMemoryMap) {
+ Status = EFI_NOT_FOUND;
+ goto Done;
+ }
+
+ Alignment = DEFAULT_PAGE_ALLOCATION_GRANULARITY;
+
+ ASSERT (Entry != NULL);
+ if (Entry->Type == EfiACPIReclaimMemory ||
+ Entry->Type == EfiACPIMemoryNVS ||
+ Entry->Type == EfiRuntimeServicesCode ||
+ Entry->Type == EfiRuntimeServicesData) {
+
+ Alignment = RUNTIME_PAGE_ALLOCATION_GRANULARITY;
+
+ }
+
+ if ((Memory & (Alignment - 1)) != 0) {
+ Status = EFI_INVALID_PARAMETER;
+ goto Done;
+ }
+
+ NumberOfPages += EFI_SIZE_TO_PAGES (Alignment) - 1;
+ NumberOfPages &= ~(EFI_SIZE_TO_PAGES (Alignment) - 1);
+
+ if (MemoryType != NULL) {
+ *MemoryType = Entry->Type;
+ }
+
+ IsGuarded = IsPageTypeToGuard (Entry->Type, AllocateAnyPages) &&
+ IsMemoryGuarded (Memory);
+ if (IsGuarded) {
+ Status = CoreConvertPagesWithGuard (Memory, NumberOfPages,
+ EfiConventionalMemory);
+ } else {
+ Status = CoreConvertPages (Memory, NumberOfPages, EfiConventionalMemory);
+ }
+
+Done:
+ CoreReleaseMemoryLock ();
+ return Status;
+}
+
+/**
+ Frees previous allocated pages.
+
+ @param Memory Base address of memory being freed
+ @param NumberOfPages The number of pages to free
+
+ @retval EFI_NOT_FOUND Could not find the entry that covers the range
+ @retval EFI_INVALID_PARAMETER Address not aligned
+ @return EFI_SUCCESS -Pages successfully freed.
+
+**/
+EFI_STATUS
+EFIAPI
+CoreFreePages (
+ IN EFI_PHYSICAL_ADDRESS Memory,
+ IN UINTN NumberOfPages
+ )
+{
+ EFI_STATUS Status;
+ EFI_MEMORY_TYPE MemoryType;
+
+ Status = CoreInternalFreePages (Memory, NumberOfPages, &MemoryType);
+ if (!EFI_ERROR (Status)) {
+ GuardFreedPagesChecked (Memory, NumberOfPages);
+ CoreUpdateProfile (
+ (EFI_PHYSICAL_ADDRESS) (UINTN) RETURN_ADDRESS (0),
+ MemoryProfileActionFreePages,
+ MemoryType,
+ EFI_PAGES_TO_SIZE (NumberOfPages),
+ (VOID *) (UINTN) Memory,
+ NULL
+ );
+ InstallMemoryAttributesTableOnMemoryAllocation (MemoryType);
+ ApplyMemoryProtectionPolicy (MemoryType, EfiConventionalMemory, Memory,
+ EFI_PAGES_TO_SIZE (NumberOfPages));
+ }
+ return Status;
+}
+
+/**
+ This function checks to see if the last memory map descriptor in a memory map
+ can be merged with any of the other memory map descriptors in a memorymap.
+ Memory descriptors may be merged if they are adjacent and have the same type
+ and attributes.
+
+ @param MemoryMap A pointer to the start of the memory map.
+ @param MemoryMapDescriptor A pointer to the last descriptor in MemoryMap.
+ @param DescriptorSize The size, in bytes, of an individual
+ EFI_MEMORY_DESCRIPTOR.
+
+ @return A pointer to the next available descriptor in MemoryMap
+
+**/
+EFI_MEMORY_DESCRIPTOR *
+MergeMemoryMapDescriptor (
+ IN EFI_MEMORY_DESCRIPTOR *MemoryMap,
+ IN EFI_MEMORY_DESCRIPTOR *MemoryMapDescriptor,
+ IN UINTN DescriptorSize
+ )
+{
+ //
+ // Traverse the array of descriptors in MemoryMap
+ //
+ for (; MemoryMap != MemoryMapDescriptor; MemoryMap = NEXT_MEMORY_DESCRIPTOR (MemoryMap, DescriptorSize)) {
+ //
+ // Check to see if the Type fields are identical.
+ //
+ if (MemoryMap->Type != MemoryMapDescriptor->Type) {
+ continue;
+ }
+
+ //
+ // Check to see if the Attribute fields are identical.
+ //
+ if (MemoryMap->Attribute != MemoryMapDescriptor->Attribute) {
+ continue;
+ }
+
+ //
+ // Check to see if MemoryMapDescriptor is immediately above MemoryMap
+ //
+ if (MemoryMap->PhysicalStart + EFI_PAGES_TO_SIZE ((UINTN)MemoryMap->NumberOfPages) == MemoryMapDescriptor->PhysicalStart) {
+ //
+ // Merge MemoryMapDescriptor into MemoryMap
+ //
+ MemoryMap->NumberOfPages += MemoryMapDescriptor->NumberOfPages;
+
+ //
+ // Return MemoryMapDescriptor as the next available slot int he MemoryMap array
+ //
+ return MemoryMapDescriptor;
+ }
+
+ //
+ // Check to see if MemoryMapDescriptor is immediately below MemoryMap
+ //
+ if (MemoryMap->PhysicalStart - EFI_PAGES_TO_SIZE ((UINTN)MemoryMapDescriptor->NumberOfPages) == MemoryMapDescriptor->PhysicalStart) {
+ //
+ // Merge MemoryMapDescriptor into MemoryMap
+ //
+ MemoryMap->PhysicalStart = MemoryMapDescriptor->PhysicalStart;
+ MemoryMap->VirtualStart = MemoryMapDescriptor->VirtualStart;
+ MemoryMap->NumberOfPages += MemoryMapDescriptor->NumberOfPages;
+
+ //
+ // Return MemoryMapDescriptor as the next available slot int he MemoryMap array
+ //
+ return MemoryMapDescriptor;
+ }
+ }
+
+ //
+ // MemoryMapDescrtiptor could not be merged with any descriptors in MemoryMap.
+ //
+ // Return the slot immediately after MemoryMapDescriptor as the next available
+ // slot in the MemoryMap array
+ //
+ return NEXT_MEMORY_DESCRIPTOR (MemoryMapDescriptor, DescriptorSize);
+}
+
+/**
+ This function returns a copy of the current memory map. The map is an array of
+ memory descriptors, each of which describes a contiguous block of memory.
+
+ @param MemoryMapSize A pointer to the size, in bytes, of the
+ MemoryMap buffer. On input, this is the size of
+ the buffer allocated by the caller. On output,
+ it is the size of the buffer returned by the
+ firmware if the buffer was large enough, or the
+ size of the buffer needed to contain the map if
+ the buffer was too small.
+ @param MemoryMap A pointer to the buffer in which firmware places
+ the current memory map.
+ @param MapKey A pointer to the location in which firmware
+ returns the key for the current memory map.
+ @param DescriptorSize A pointer to the location in which firmware
+ returns the size, in bytes, of an individual
+ EFI_MEMORY_DESCRIPTOR.
+ @param DescriptorVersion A pointer to the location in which firmware
+ returns the version number associated with the
+ EFI_MEMORY_DESCRIPTOR.
+
+ @retval EFI_SUCCESS The memory map was returned in the MemoryMap
+ buffer.
+ @retval EFI_BUFFER_TOO_SMALL The MemoryMap buffer was too small. The current
+ buffer size needed to hold the memory map is
+ returned in MemoryMapSize.
+ @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
+
+**/
+EFI_STATUS
+EFIAPI
+CoreGetMemoryMap (
+ IN OUT UINTN *MemoryMapSize,
+ IN OUT EFI_MEMORY_DESCRIPTOR *MemoryMap,
+ OUT UINTN *MapKey,
+ OUT UINTN *DescriptorSize,
+ OUT UINT32 *DescriptorVersion
+ )
+{
+ EFI_STATUS Status;
+ UINTN Size;
+ UINTN BufferSize;
+ UINTN NumberOfEntries;
+ LIST_ENTRY *Link;
+ MEMORY_MAP *Entry;
+ EFI_GCD_MAP_ENTRY *GcdMapEntry;
+ EFI_GCD_MAP_ENTRY MergeGcdMapEntry;
+ EFI_MEMORY_TYPE Type;
+ EFI_MEMORY_DESCRIPTOR *MemoryMapStart;
+ EFI_MEMORY_DESCRIPTOR *MemoryMapEnd;
+
+ //
+ // Make sure the parameters are valid
+ //
+ if (MemoryMapSize == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ CoreAcquireGcdMemoryLock ();
+
+ //
+ // Count the number of Reserved and runtime MMIO entries
+ // And, count the number of Persistent entries.
+ //
+ NumberOfEntries = 0;
+ for (Link = mGcdMemorySpaceMap.ForwardLink; Link != &mGcdMemorySpaceMap; Link = Link->ForwardLink) {
+ GcdMapEntry = CR (Link, EFI_GCD_MAP_ENTRY, Link, EFI_GCD_MAP_SIGNATURE);
+ if ((GcdMapEntry->GcdMemoryType == EfiGcdMemoryTypePersistent) ||
+ (GcdMapEntry->GcdMemoryType == EfiGcdMemoryTypeReserved) ||
+ ((GcdMapEntry->GcdMemoryType == EfiGcdMemoryTypeMemoryMappedIo) &&
+ ((GcdMapEntry->Attributes & EFI_MEMORY_RUNTIME) == EFI_MEMORY_RUNTIME))) {
+ NumberOfEntries ++;
+ }
+ }
+
+ Size = sizeof (EFI_MEMORY_DESCRIPTOR);
+
+ //
+ // Make sure Size != sizeof(EFI_MEMORY_DESCRIPTOR). This will
+ // prevent people from having pointer math bugs in their code.
+ // now you have to use *DescriptorSize to make things work.
+ //
+ Size += sizeof(UINT64) - (Size % sizeof (UINT64));
+
+ if (DescriptorSize != NULL) {
+ *DescriptorSize = Size;
+ }
+
+ if (DescriptorVersion != NULL) {
+ *DescriptorVersion = EFI_MEMORY_DESCRIPTOR_VERSION;
+ }
+
+ CoreAcquireMemoryLock ();
+
+ //
+ // Compute the buffer size needed to fit the entire map
+ //
+ BufferSize = Size * NumberOfEntries;
+ for (Link = gMemoryMap.ForwardLink; Link != &gMemoryMap; Link = Link->ForwardLink) {
+ BufferSize += Size;
+ }
+
+ if (*MemoryMapSize < BufferSize) {
+ Status = EFI_BUFFER_TOO_SMALL;
+ goto Done;
+ }
+
+ if (MemoryMap == NULL) {
+ Status = EFI_INVALID_PARAMETER;
+ goto Done;
+ }
+
+ //
+ // Build the map
+ //
+ ZeroMem (MemoryMap, BufferSize);
+ MemoryMapStart = MemoryMap;
+ for (Link = gMemoryMap.ForwardLink; Link != &gMemoryMap; Link = Link->ForwardLink) {
+ Entry = CR (Link, MEMORY_MAP, Link, MEMORY_MAP_SIGNATURE);
+ ASSERT (Entry->VirtualStart == 0);
+
+ //
+ // Convert internal map into an EFI_MEMORY_DESCRIPTOR
+ //
+ MemoryMap->Type = Entry->Type;
+ MemoryMap->PhysicalStart = Entry->Start;
+ MemoryMap->VirtualStart = Entry->VirtualStart;
+ MemoryMap->NumberOfPages = RShiftU64 (Entry->End - Entry->Start + 1, EFI_PAGE_SHIFT);
+ //
+ // If the memory type is EfiConventionalMemory, then determine if the range is part of a
+ // memory type bin and needs to be converted to the same memory type as the rest of the
+ // memory type bin in order to minimize EFI Memory Map changes across reboots. This
+ // improves the chances for a successful S4 resume in the presence of minor page allocation
+ // differences across reboots.
+ //
+ if (MemoryMap->Type == EfiConventionalMemory) {
+ for (Type = (EFI_MEMORY_TYPE) 0; Type < EfiMaxMemoryType; Type++) {
+ if (mMemoryTypeStatistics[Type].Special &&
+ mMemoryTypeStatistics[Type].NumberOfPages > 0 &&
+ Entry->Start >= mMemoryTypeStatistics[Type].BaseAddress &&
+ Entry->End <= mMemoryTypeStatistics[Type].MaximumAddress) {
+ MemoryMap->Type = Type;
+ }
+ }
+ }
+ MemoryMap->Attribute = Entry->Attribute;
+ if (MemoryMap->Type < EfiMaxMemoryType) {
+ if (mMemoryTypeStatistics[MemoryMap->Type].Runtime) {
+ MemoryMap->Attribute |= EFI_MEMORY_RUNTIME;
+ }
+ }
+
+ //
+ // Check to see if the new Memory Map Descriptor can be merged with an
+ // existing descriptor if they are adjacent and have the same attributes
+ //
+ MemoryMap = MergeMemoryMapDescriptor (MemoryMapStart, MemoryMap, Size);
+ }
+
+
+ ZeroMem (&MergeGcdMapEntry, sizeof (MergeGcdMapEntry));
+ GcdMapEntry = NULL;
+ for (Link = mGcdMemorySpaceMap.ForwardLink; ; Link = Link->ForwardLink) {
+ if (Link != &mGcdMemorySpaceMap) {
+ //
+ // Merge adjacent same type and attribute GCD memory range
+ //
+ GcdMapEntry = CR (Link, EFI_GCD_MAP_ENTRY, Link, EFI_GCD_MAP_SIGNATURE);
+
+ if ((MergeGcdMapEntry.Capabilities == GcdMapEntry->Capabilities) &&
+ (MergeGcdMapEntry.Attributes == GcdMapEntry->Attributes) &&
+ (MergeGcdMapEntry.GcdMemoryType == GcdMapEntry->GcdMemoryType) &&
+ (MergeGcdMapEntry.GcdIoType == GcdMapEntry->GcdIoType)) {
+ MergeGcdMapEntry.EndAddress = GcdMapEntry->EndAddress;
+ continue;
+ }
+ }
+
+ if ((MergeGcdMapEntry.GcdMemoryType == EfiGcdMemoryTypeReserved) ||
+ ((MergeGcdMapEntry.GcdMemoryType == EfiGcdMemoryTypeMemoryMappedIo) &&
+ ((MergeGcdMapEntry.Attributes & EFI_MEMORY_RUNTIME) == EFI_MEMORY_RUNTIME))) {
+ //
+ // Page Align GCD range is required. When it is converted to EFI_MEMORY_DESCRIPTOR,
+ // it will be recorded as page PhysicalStart and NumberOfPages.
+ //
+ ASSERT ((MergeGcdMapEntry.BaseAddress & EFI_PAGE_MASK) == 0);
+ ASSERT (((MergeGcdMapEntry.EndAddress - MergeGcdMapEntry.BaseAddress + 1) & EFI_PAGE_MASK) == 0);
+
+ //
+ // Create EFI_MEMORY_DESCRIPTOR for every Reserved and runtime MMIO GCD entries
+ //
+ MemoryMap->PhysicalStart = MergeGcdMapEntry.BaseAddress;
+ MemoryMap->VirtualStart = 0;
+ MemoryMap->NumberOfPages = RShiftU64 ((MergeGcdMapEntry.EndAddress - MergeGcdMapEntry.BaseAddress + 1), EFI_PAGE_SHIFT);
+ MemoryMap->Attribute = (MergeGcdMapEntry.Attributes & ~EFI_MEMORY_PORT_IO) |
+ (MergeGcdMapEntry.Capabilities & (EFI_CACHE_ATTRIBUTE_MASK | EFI_MEMORY_ATTRIBUTE_MASK));
+
+ if (MergeGcdMapEntry.GcdMemoryType == EfiGcdMemoryTypeReserved) {
+ MemoryMap->Type = EfiReservedMemoryType;
+ } else if (MergeGcdMapEntry.GcdMemoryType == EfiGcdMemoryTypeMemoryMappedIo) {
+ if ((MergeGcdMapEntry.Attributes & EFI_MEMORY_PORT_IO) == EFI_MEMORY_PORT_IO) {
+ MemoryMap->Type = EfiMemoryMappedIOPortSpace;
+ } else {
+ MemoryMap->Type = EfiMemoryMappedIO;
+ }
+ }
+
+ //
+ // Check to see if the new Memory Map Descriptor can be merged with an
+ // existing descriptor if they are adjacent and have the same attributes
+ //
+ MemoryMap = MergeMemoryMapDescriptor (MemoryMapStart, MemoryMap, Size);
+ }
+
+ if (MergeGcdMapEntry.GcdMemoryType == EfiGcdMemoryTypePersistent) {
+ //
+ // Page Align GCD range is required. When it is converted to EFI_MEMORY_DESCRIPTOR,
+ // it will be recorded as page PhysicalStart and NumberOfPages.
+ //
+ ASSERT ((MergeGcdMapEntry.BaseAddress & EFI_PAGE_MASK) == 0);
+ ASSERT (((MergeGcdMapEntry.EndAddress - MergeGcdMapEntry.BaseAddress + 1) & EFI_PAGE_MASK) == 0);
+
+ //
+ // Create EFI_MEMORY_DESCRIPTOR for every Persistent GCD entries
+ //
+ MemoryMap->PhysicalStart = MergeGcdMapEntry.BaseAddress;
+ MemoryMap->VirtualStart = 0;
+ MemoryMap->NumberOfPages = RShiftU64 ((MergeGcdMapEntry.EndAddress - MergeGcdMapEntry.BaseAddress + 1), EFI_PAGE_SHIFT);
+ MemoryMap->Attribute = MergeGcdMapEntry.Attributes | EFI_MEMORY_NV |
+ (MergeGcdMapEntry.Capabilities & (EFI_CACHE_ATTRIBUTE_MASK | EFI_MEMORY_ATTRIBUTE_MASK));
+ MemoryMap->Type = EfiPersistentMemory;
+
+ //
+ // Check to see if the new Memory Map Descriptor can be merged with an
+ // existing descriptor if they are adjacent and have the same attributes
+ //
+ MemoryMap = MergeMemoryMapDescriptor (MemoryMapStart, MemoryMap, Size);
+ }
+ if (Link == &mGcdMemorySpaceMap) {
+ //
+ // break loop when arrive at head.
+ //
+ break;
+ }
+ if (GcdMapEntry != NULL) {
+ //
+ // Copy new GCD map entry for the following GCD range merge
+ //
+ CopyMem (&MergeGcdMapEntry, GcdMapEntry, sizeof (MergeGcdMapEntry));
+ }
+ }
+
+ //
+ // Compute the size of the buffer actually used after all memory map descriptor merge operations
+ //
+ BufferSize = ((UINT8 *)MemoryMap - (UINT8 *)MemoryMapStart);
+
+ //
+ // Note: Some OSs will treat EFI_MEMORY_DESCRIPTOR.Attribute as really
+ // set attributes and change memory paging attribute accordingly.
+ // But current EFI_MEMORY_DESCRIPTOR.Attribute is assigned by
+ // value from Capabilities in GCD memory map. This might cause
+ // boot problems. Clearing all paging related capabilities can
+ // workaround it. Following code is supposed to be removed once
+ // the usage of EFI_MEMORY_DESCRIPTOR.Attribute is clarified in
+ // UEFI spec and adopted by both EDK-II Core and all supported
+ // OSs.
+ //
+ MemoryMapEnd = MemoryMap;
+ MemoryMap = MemoryMapStart;
+ while (MemoryMap < MemoryMapEnd) {
+ MemoryMap->Attribute &= ~(UINT64)EFI_MEMORY_ATTRIBUTE_MASK;
+ MemoryMap = NEXT_MEMORY_DESCRIPTOR (MemoryMap, Size);
+ }
+ MergeMemoryMap (MemoryMapStart, &BufferSize, Size);
+ MemoryMapEnd = (EFI_MEMORY_DESCRIPTOR *)((UINT8 *)MemoryMapStart + BufferSize);
+
+ Status = EFI_SUCCESS;
+
+Done:
+ //
+ // Update the map key finally
+ //
+ if (MapKey != NULL) {
+ *MapKey = mMemoryMapKey;
+ }
+
+ CoreReleaseMemoryLock ();
+
+ CoreReleaseGcdMemoryLock ();
+
+ *MemoryMapSize = BufferSize;
+
+ DEBUG_CODE (
+ DumpGuardedMemoryBitmap ();
+ );
+
+ return Status;
+}
+
+
+/**
+ Internal function. Used by the pool functions to allocate pages
+ to back pool allocation requests.
+
+ @param PoolType The type of memory for the new pool pages
+ @param NumberOfPages No of pages to allocate
+ @param Alignment Bits to align.
+ @param NeedGuard Flag to indicate Guard page is needed or not
+
+ @return The allocated memory, or NULL
+
+**/
+VOID *
+CoreAllocatePoolPages (
+ IN EFI_MEMORY_TYPE PoolType,
+ IN UINTN NumberOfPages,
+ IN UINTN Alignment,
+ IN BOOLEAN NeedGuard
+ )
+{
+ UINT64 Start;
+
+ //
+ // Find the pages to convert
+ //
+ Start = FindFreePages (MAX_ALLOC_ADDRESS, NumberOfPages, PoolType, Alignment,
+ NeedGuard);
+
+ //
+ // Convert it to boot services data
+ //
+ if (Start == 0) {
+ DEBUG ((DEBUG_ERROR | DEBUG_PAGE, "AllocatePoolPages: failed to allocate %d pages\n", (UINT32)NumberOfPages));
+ } else {
+ if (NeedGuard) {
+ CoreConvertPagesWithGuard (Start, NumberOfPages, PoolType);
+ } else {
+ CoreConvertPages (Start, NumberOfPages, PoolType);
+ }
+ }
+
+ return (VOID *)(UINTN) Start;
+}
+
+
+/**
+ Internal function. Frees pool pages allocated via AllocatePoolPages ()
+
+ @param Memory The base address to free
+ @param NumberOfPages The number of pages to free
+
+**/
+VOID
+CoreFreePoolPages (
+ IN EFI_PHYSICAL_ADDRESS Memory,
+ IN UINTN NumberOfPages
+ )
+{
+ CoreConvertPages (Memory, NumberOfPages, EfiConventionalMemory);
+}
+
+
+
+/**
+ Make sure the memory map is following all the construction rules,
+ it is the last time to check memory map error before exit boot services.
+
+ @param MapKey Memory map key
+
+ @retval EFI_INVALID_PARAMETER Memory map not consistent with construction
+ rules.
+ @retval EFI_SUCCESS Valid memory map.
+
+**/
+EFI_STATUS
+CoreTerminateMemoryMap (
+ IN UINTN MapKey
+ )
+{
+ EFI_STATUS Status;
+ LIST_ENTRY *Link;
+ MEMORY_MAP *Entry;
+
+ Status = EFI_SUCCESS;
+
+ CoreAcquireMemoryLock ();
+
+ if (MapKey == mMemoryMapKey) {
+
+ //
+ // Make sure the memory map is following all the construction rules
+ // This is the last chance we will be able to display any messages on
+ // the console devices.
+ //
+
+ for (Link = gMemoryMap.ForwardLink; Link != &gMemoryMap; Link = Link->ForwardLink) {
+ Entry = CR(Link, MEMORY_MAP, Link, MEMORY_MAP_SIGNATURE);
+ if (Entry->Type < EfiMaxMemoryType) {
+ if (mMemoryTypeStatistics[Entry->Type].Runtime) {
+ ASSERT (Entry->Type != EfiACPIReclaimMemory);
+ ASSERT (Entry->Type != EfiACPIMemoryNVS);
+ if ((Entry->Start & (RUNTIME_PAGE_ALLOCATION_GRANULARITY - 1)) != 0) {
+ DEBUG((DEBUG_ERROR | DEBUG_PAGE, "ExitBootServices: A RUNTIME memory entry is not on a proper alignment.\n"));
+ Status = EFI_INVALID_PARAMETER;
+ goto Done;
+ }
+ if (((Entry->End + 1) & (RUNTIME_PAGE_ALLOCATION_GRANULARITY - 1)) != 0) {
+ DEBUG((DEBUG_ERROR | DEBUG_PAGE, "ExitBootServices: A RUNTIME memory entry is not on a proper alignment.\n"));
+ Status = EFI_INVALID_PARAMETER;
+ goto Done;
+ }
+ }
+ }
+ }
+
+ //
+ // The map key they gave us matches what we expect. Fall through and
+ // return success. In an ideal world we would clear out all of
+ // EfiBootServicesCode and EfiBootServicesData. However this function
+ // is not the last one called by ExitBootServices(), so we have to
+ // preserve the memory contents.
+ //
+ } else {
+ Status = EFI_INVALID_PARAMETER;
+ }
+
+Done:
+ CoreReleaseMemoryLock ();
+
+ return Status;
+}
+
+
+
+
+
+
+
+
+
diff --git a/roms/edk2/MdeModulePkg/Core/Dxe/Mem/Pool.c b/roms/edk2/MdeModulePkg/Core/Dxe/Mem/Pool.c
new file mode 100644
index 000000000..734fc94bf
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Core/Dxe/Mem/Pool.c
@@ -0,0 +1,857 @@
+/** @file
+ UEFI Memory pool management functions.
+
+Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "DxeMain.h"
+#include "Imem.h"
+#include "HeapGuard.h"
+
+STATIC EFI_LOCK mPoolMemoryLock = EFI_INITIALIZE_LOCK_VARIABLE (TPL_NOTIFY);
+
+#define POOL_FREE_SIGNATURE SIGNATURE_32('p','f','r','0')
+typedef struct {
+ UINT32 Signature;
+ UINT32 Index;
+ LIST_ENTRY Link;
+} POOL_FREE;
+
+
+#define POOL_HEAD_SIGNATURE SIGNATURE_32('p','h','d','0')
+#define POOLPAGE_HEAD_SIGNATURE SIGNATURE_32('p','h','d','1')
+typedef struct {
+ UINT32 Signature;
+ UINT32 Reserved;
+ EFI_MEMORY_TYPE Type;
+ UINTN Size;
+ CHAR8 Data[1];
+} POOL_HEAD;
+
+#define SIZE_OF_POOL_HEAD OFFSET_OF(POOL_HEAD,Data)
+
+#define POOL_TAIL_SIGNATURE SIGNATURE_32('p','t','a','l')
+typedef struct {
+ UINT32 Signature;
+ UINT32 Reserved;
+ UINTN Size;
+} POOL_TAIL;
+
+#define POOL_OVERHEAD (SIZE_OF_POOL_HEAD + sizeof(POOL_TAIL))
+
+#define HEAD_TO_TAIL(a) \
+ ((POOL_TAIL *) (((CHAR8 *) (a)) + (a)->Size - sizeof(POOL_TAIL)));
+
+//
+// Each element is the sum of the 2 previous ones: this allows us to migrate
+// blocks between bins by splitting them up, while not wasting too much memory
+// as we would in a strict power-of-2 sequence
+//
+STATIC CONST UINT16 mPoolSizeTable[] = {
+ 128, 256, 384, 640, 1024, 1664, 2688, 4352, 7040, 11392, 18432, 29824
+};
+
+#define SIZE_TO_LIST(a) (GetPoolIndexFromSize (a))
+#define LIST_TO_SIZE(a) (mPoolSizeTable [a])
+
+#define MAX_POOL_LIST (ARRAY_SIZE (mPoolSizeTable))
+
+#define MAX_POOL_SIZE (MAX_ADDRESS - POOL_OVERHEAD)
+
+//
+// Globals
+//
+
+#define POOL_SIGNATURE SIGNATURE_32('p','l','s','t')
+typedef struct {
+ INTN Signature;
+ UINTN Used;
+ EFI_MEMORY_TYPE MemoryType;
+ LIST_ENTRY FreeList[MAX_POOL_LIST];
+ LIST_ENTRY Link;
+} POOL;
+
+//
+// Pool header for each memory type.
+//
+POOL mPoolHead[EfiMaxMemoryType];
+
+//
+// List of pool header to search for the appropriate memory type.
+//
+LIST_ENTRY mPoolHeadList = INITIALIZE_LIST_HEAD_VARIABLE (mPoolHeadList);
+
+/**
+ Get pool size table index from the specified size.
+
+ @param Size The specified size to get index from pool table.
+
+ @return The index of pool size table.
+
+**/
+STATIC
+UINTN
+GetPoolIndexFromSize (
+ UINTN Size
+ )
+{
+ UINTN Index;
+
+ for (Index = 0; Index < MAX_POOL_LIST; Index++) {
+ if (mPoolSizeTable [Index] >= Size) {
+ return Index;
+ }
+ }
+ return MAX_POOL_LIST;
+}
+
+/**
+ Called to initialize the pool.
+
+**/
+VOID
+CoreInitializePool (
+ VOID
+ )
+{
+ UINTN Type;
+ UINTN Index;
+
+ for (Type=0; Type < EfiMaxMemoryType; Type++) {
+ mPoolHead[Type].Signature = 0;
+ mPoolHead[Type].Used = 0;
+ mPoolHead[Type].MemoryType = (EFI_MEMORY_TYPE) Type;
+ for (Index=0; Index < MAX_POOL_LIST; Index++) {
+ InitializeListHead (&mPoolHead[Type].FreeList[Index]);
+ }
+ }
+}
+
+
+/**
+ Look up pool head for specified memory type.
+
+ @param MemoryType Memory type of which pool head is looked for
+
+ @return Pointer of Corresponding pool head.
+
+**/
+POOL *
+LookupPoolHead (
+ IN EFI_MEMORY_TYPE MemoryType
+ )
+{
+ LIST_ENTRY *Link;
+ POOL *Pool;
+ UINTN Index;
+
+ if ((UINT32)MemoryType < EfiMaxMemoryType) {
+ return &mPoolHead[MemoryType];
+ }
+
+ //
+ // MemoryType values in the range 0x80000000..0xFFFFFFFF are reserved for use by UEFI
+ // OS loaders that are provided by operating system vendors.
+ // MemoryType values in the range 0x70000000..0x7FFFFFFF are reserved for OEM use.
+ //
+ if ((UINT32) MemoryType >= MEMORY_TYPE_OEM_RESERVED_MIN) {
+
+ for (Link = mPoolHeadList.ForwardLink; Link != &mPoolHeadList; Link = Link->ForwardLink) {
+ Pool = CR(Link, POOL, Link, POOL_SIGNATURE);
+ if (Pool->MemoryType == MemoryType) {
+ return Pool;
+ }
+ }
+
+ Pool = CoreAllocatePoolI (EfiBootServicesData, sizeof (POOL), FALSE);
+ if (Pool == NULL) {
+ return NULL;
+ }
+
+ Pool->Signature = POOL_SIGNATURE;
+ Pool->Used = 0;
+ Pool->MemoryType = MemoryType;
+ for (Index=0; Index < MAX_POOL_LIST; Index++) {
+ InitializeListHead (&Pool->FreeList[Index]);
+ }
+
+ InsertHeadList (&mPoolHeadList, &Pool->Link);
+
+ return Pool;
+ }
+
+ return NULL;
+}
+
+
+
+/**
+ Allocate pool of a particular type.
+
+ @param PoolType Type of pool to allocate
+ @param Size The amount of pool to allocate
+ @param Buffer The address to return a pointer to the allocated
+ pool
+
+ @retval EFI_INVALID_PARAMETER Buffer is NULL.
+ PoolType is in the range EfiMaxMemoryType..0x6FFFFFFF.
+ PoolType is EfiPersistentMemory.
+ @retval EFI_OUT_OF_RESOURCES Size exceeds max pool size or allocation failed.
+ @retval EFI_SUCCESS Pool successfully allocated.
+
+**/
+EFI_STATUS
+EFIAPI
+CoreInternalAllocatePool (
+ IN EFI_MEMORY_TYPE PoolType,
+ IN UINTN Size,
+ OUT VOID **Buffer
+ )
+{
+ EFI_STATUS Status;
+ BOOLEAN NeedGuard;
+
+ //
+ // If it's not a valid type, fail it
+ //
+ if ((PoolType >= EfiMaxMemoryType && PoolType < MEMORY_TYPE_OEM_RESERVED_MIN) ||
+ (PoolType == EfiConventionalMemory) || (PoolType == EfiPersistentMemory)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (Buffer == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ *Buffer = NULL;
+
+ //
+ // If size is too large, fail it
+ // Base on the EFI spec, return status of EFI_OUT_OF_RESOURCES
+ //
+ if (Size > MAX_POOL_SIZE) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ NeedGuard = IsPoolTypeToGuard (PoolType) && !mOnGuarding;
+
+ //
+ // Acquire the memory lock and make the allocation
+ //
+ Status = CoreAcquireLockOrFail (&mPoolMemoryLock);
+ if (EFI_ERROR (Status)) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ *Buffer = CoreAllocatePoolI (PoolType, Size, NeedGuard);
+ CoreReleaseLock (&mPoolMemoryLock);
+ return (*Buffer != NULL) ? EFI_SUCCESS : EFI_OUT_OF_RESOURCES;
+}
+
+/**
+ Allocate pool of a particular type.
+
+ @param PoolType Type of pool to allocate
+ @param Size The amount of pool to allocate
+ @param Buffer The address to return a pointer to the allocated
+ pool
+
+ @retval EFI_INVALID_PARAMETER Buffer is NULL.
+ PoolType is in the range EfiMaxMemoryType..0x6FFFFFFF.
+ PoolType is EfiPersistentMemory.
+ @retval EFI_OUT_OF_RESOURCES Size exceeds max pool size or allocation failed.
+ @retval EFI_SUCCESS Pool successfully allocated.
+
+**/
+EFI_STATUS
+EFIAPI
+CoreAllocatePool (
+ IN EFI_MEMORY_TYPE PoolType,
+ IN UINTN Size,
+ OUT VOID **Buffer
+ )
+{
+ EFI_STATUS Status;
+
+ Status = CoreInternalAllocatePool (PoolType, Size, Buffer);
+ if (!EFI_ERROR (Status)) {
+ CoreUpdateProfile (
+ (EFI_PHYSICAL_ADDRESS) (UINTN) RETURN_ADDRESS (0),
+ MemoryProfileActionAllocatePool,
+ PoolType,
+ Size,
+ *Buffer,
+ NULL
+ );
+ InstallMemoryAttributesTableOnMemoryAllocation (PoolType);
+ }
+ return Status;
+}
+
+/**
+ Internal function. Used by the pool functions to allocate pages
+ to back pool allocation requests.
+
+ @param PoolType The type of memory for the new pool pages
+ @param NoPages No of pages to allocate
+ @param Granularity Bits to align.
+ @param NeedGuard Flag to indicate Guard page is needed or not
+
+ @return The allocated memory, or NULL
+
+**/
+STATIC
+VOID *
+CoreAllocatePoolPagesI (
+ IN EFI_MEMORY_TYPE PoolType,
+ IN UINTN NoPages,
+ IN UINTN Granularity,
+ IN BOOLEAN NeedGuard
+ )
+{
+ VOID *Buffer;
+ EFI_STATUS Status;
+
+ Status = CoreAcquireLockOrFail (&gMemoryLock);
+ if (EFI_ERROR (Status)) {
+ return NULL;
+ }
+
+ Buffer = CoreAllocatePoolPages (PoolType, NoPages, Granularity, NeedGuard);
+ CoreReleaseMemoryLock ();
+
+ if (Buffer != NULL) {
+ if (NeedGuard) {
+ SetGuardForMemory ((EFI_PHYSICAL_ADDRESS)(UINTN)Buffer, NoPages);
+ }
+ ApplyMemoryProtectionPolicy(EfiConventionalMemory, PoolType,
+ (EFI_PHYSICAL_ADDRESS)(UINTN)Buffer, EFI_PAGES_TO_SIZE (NoPages));
+ }
+ return Buffer;
+}
+
+/**
+ Internal function to allocate pool of a particular type.
+ Caller must have the memory lock held
+
+ @param PoolType Type of pool to allocate
+ @param Size The amount of pool to allocate
+ @param NeedGuard Flag to indicate Guard page is needed or not
+
+ @return The allocate pool, or NULL
+
+**/
+VOID *
+CoreAllocatePoolI (
+ IN EFI_MEMORY_TYPE PoolType,
+ IN UINTN Size,
+ IN BOOLEAN NeedGuard
+ )
+{
+ POOL *Pool;
+ POOL_FREE *Free;
+ POOL_HEAD *Head;
+ POOL_TAIL *Tail;
+ CHAR8 *NewPage;
+ VOID *Buffer;
+ UINTN Index;
+ UINTN FSize;
+ UINTN Offset, MaxOffset;
+ UINTN NoPages;
+ UINTN Granularity;
+ BOOLEAN HasPoolTail;
+ BOOLEAN PageAsPool;
+
+ ASSERT_LOCKED (&mPoolMemoryLock);
+
+ if (PoolType == EfiACPIReclaimMemory ||
+ PoolType == EfiACPIMemoryNVS ||
+ PoolType == EfiRuntimeServicesCode ||
+ PoolType == EfiRuntimeServicesData) {
+
+ Granularity = RUNTIME_PAGE_ALLOCATION_GRANULARITY;
+ } else {
+ Granularity = DEFAULT_PAGE_ALLOCATION_GRANULARITY;
+ }
+
+ //
+ // Adjust the size by the pool header & tail overhead
+ //
+
+ HasPoolTail = !(NeedGuard &&
+ ((PcdGet8 (PcdHeapGuardPropertyMask) & BIT7) == 0));
+ PageAsPool = (IsHeapGuardEnabled (GUARD_HEAP_TYPE_FREED) && !mOnGuarding);
+
+ //
+ // Adjusting the Size to be of proper alignment so that
+ // we don't get an unaligned access fault later when
+ // pool_Tail is being initialized
+ //
+ Size = ALIGN_VARIABLE (Size);
+
+ Size += POOL_OVERHEAD;
+ Index = SIZE_TO_LIST(Size);
+ Pool = LookupPoolHead (PoolType);
+ if (Pool== NULL) {
+ return NULL;
+ }
+ Head = NULL;
+
+ //
+ // If allocation is over max size, just allocate pages for the request
+ // (slow)
+ //
+ if (Index >= SIZE_TO_LIST (Granularity) || NeedGuard || PageAsPool) {
+ if (!HasPoolTail) {
+ Size -= sizeof (POOL_TAIL);
+ }
+ NoPages = EFI_SIZE_TO_PAGES (Size) + EFI_SIZE_TO_PAGES (Granularity) - 1;
+ NoPages &= ~(UINTN)(EFI_SIZE_TO_PAGES (Granularity) - 1);
+ Head = CoreAllocatePoolPagesI (PoolType, NoPages, Granularity, NeedGuard);
+ if (NeedGuard) {
+ Head = AdjustPoolHeadA ((EFI_PHYSICAL_ADDRESS)(UINTN)Head, NoPages, Size);
+ }
+ goto Done;
+ }
+
+ //
+ // If there's no free pool in the proper list size, go get some more pages
+ //
+ if (IsListEmpty (&Pool->FreeList[Index])) {
+
+ Offset = LIST_TO_SIZE (Index);
+ MaxOffset = Granularity;
+
+ //
+ // Check the bins holding larger blocks, and carve one up if needed
+ //
+ while (++Index < SIZE_TO_LIST (Granularity)) {
+ if (!IsListEmpty (&Pool->FreeList[Index])) {
+ Free = CR (Pool->FreeList[Index].ForwardLink, POOL_FREE, Link, POOL_FREE_SIGNATURE);
+ RemoveEntryList (&Free->Link);
+ NewPage = (VOID *) Free;
+ MaxOffset = LIST_TO_SIZE (Index);
+ goto Carve;
+ }
+ }
+
+ //
+ // Get another page
+ //
+ NewPage = CoreAllocatePoolPagesI (PoolType, EFI_SIZE_TO_PAGES (Granularity),
+ Granularity, NeedGuard);
+ if (NewPage == NULL) {
+ goto Done;
+ }
+
+ //
+ // Serve the allocation request from the head of the allocated block
+ //
+Carve:
+ Head = (POOL_HEAD *) NewPage;
+
+ //
+ // Carve up remaining space into free pool blocks
+ //
+ Index--;
+ while (Offset < MaxOffset) {
+ ASSERT (Index < MAX_POOL_LIST);
+ FSize = LIST_TO_SIZE(Index);
+
+ while (Offset + FSize <= MaxOffset) {
+ Free = (POOL_FREE *) &NewPage[Offset];
+ Free->Signature = POOL_FREE_SIGNATURE;
+ Free->Index = (UINT32)Index;
+ InsertHeadList (&Pool->FreeList[Index], &Free->Link);
+ Offset += FSize;
+ }
+ Index -= 1;
+ }
+
+ ASSERT (Offset == MaxOffset);
+ goto Done;
+ }
+
+ //
+ // Remove entry from free pool list
+ //
+ Free = CR (Pool->FreeList[Index].ForwardLink, POOL_FREE, Link, POOL_FREE_SIGNATURE);
+ RemoveEntryList (&Free->Link);
+
+ Head = (POOL_HEAD *) Free;
+
+Done:
+ Buffer = NULL;
+
+ if (Head != NULL) {
+
+ //
+ // Account the allocation
+ //
+ Pool->Used += Size;
+
+ //
+ // If we have a pool buffer, fill in the header & tail info
+ //
+ Head->Signature = (PageAsPool) ? POOLPAGE_HEAD_SIGNATURE : POOL_HEAD_SIGNATURE;
+ Head->Size = Size;
+ Head->Type = (EFI_MEMORY_TYPE) PoolType;
+ Buffer = Head->Data;
+
+ if (HasPoolTail) {
+ Tail = HEAD_TO_TAIL (Head);
+ Tail->Signature = POOL_TAIL_SIGNATURE;
+ Tail->Size = Size;
+
+ Size -= POOL_OVERHEAD;
+ } else {
+ Size -= SIZE_OF_POOL_HEAD;
+ }
+
+ DEBUG_CLEAR_MEMORY (Buffer, Size);
+
+ DEBUG ((
+ DEBUG_POOL,
+ "AllocatePoolI: Type %x, Addr %p (len %lx) %,ld\n", PoolType,
+ Buffer,
+ (UINT64)Size,
+ (UINT64) Pool->Used
+ ));
+
+
+ } else {
+ DEBUG ((DEBUG_ERROR | DEBUG_POOL, "AllocatePool: failed to allocate %ld bytes\n", (UINT64) Size));
+ }
+
+ return Buffer;
+}
+
+
+
+/**
+ Frees pool.
+
+ @param Buffer The allocated pool entry to free
+ @param PoolType Pointer to pool type
+
+ @retval EFI_INVALID_PARAMETER Buffer is not a valid value.
+ @retval EFI_SUCCESS Pool successfully freed.
+
+**/
+EFI_STATUS
+EFIAPI
+CoreInternalFreePool (
+ IN VOID *Buffer,
+ OUT EFI_MEMORY_TYPE *PoolType OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+
+ if (Buffer == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ CoreAcquireLock (&mPoolMemoryLock);
+ Status = CoreFreePoolI (Buffer, PoolType);
+ CoreReleaseLock (&mPoolMemoryLock);
+ return Status;
+}
+
+/**
+ Frees pool.
+
+ @param Buffer The allocated pool entry to free
+
+ @retval EFI_INVALID_PARAMETER Buffer is not a valid value.
+ @retval EFI_SUCCESS Pool successfully freed.
+
+**/
+EFI_STATUS
+EFIAPI
+CoreFreePool (
+ IN VOID *Buffer
+ )
+{
+ EFI_STATUS Status;
+ EFI_MEMORY_TYPE PoolType;
+
+ Status = CoreInternalFreePool (Buffer, &PoolType);
+ if (!EFI_ERROR (Status)) {
+ CoreUpdateProfile (
+ (EFI_PHYSICAL_ADDRESS) (UINTN) RETURN_ADDRESS (0),
+ MemoryProfileActionFreePool,
+ PoolType,
+ 0,
+ Buffer,
+ NULL
+ );
+ InstallMemoryAttributesTableOnMemoryAllocation (PoolType);
+ }
+ return Status;
+}
+
+/**
+ Internal function. Frees pool pages allocated via CoreAllocatePoolPagesI().
+
+ @param PoolType The type of memory for the pool pages
+ @param Memory The base address to free
+ @param NoPages The number of pages to free
+
+**/
+STATIC
+VOID
+CoreFreePoolPagesI (
+ IN EFI_MEMORY_TYPE PoolType,
+ IN EFI_PHYSICAL_ADDRESS Memory,
+ IN UINTN NoPages
+ )
+{
+ CoreAcquireMemoryLock ();
+ CoreFreePoolPages (Memory, NoPages);
+ CoreReleaseMemoryLock ();
+
+ GuardFreedPagesChecked (Memory, NoPages);
+ ApplyMemoryProtectionPolicy (PoolType, EfiConventionalMemory,
+ (EFI_PHYSICAL_ADDRESS)(UINTN)Memory, EFI_PAGES_TO_SIZE (NoPages));
+}
+
+/**
+ Internal function. Frees guarded pool pages.
+
+ @param PoolType The type of memory for the pool pages
+ @param Memory The base address to free
+ @param NoPages The number of pages to free
+
+**/
+STATIC
+VOID
+CoreFreePoolPagesWithGuard (
+ IN EFI_MEMORY_TYPE PoolType,
+ IN EFI_PHYSICAL_ADDRESS Memory,
+ IN UINTN NoPages
+ )
+{
+ EFI_PHYSICAL_ADDRESS MemoryGuarded;
+ UINTN NoPagesGuarded;
+
+ MemoryGuarded = Memory;
+ NoPagesGuarded = NoPages;
+
+ AdjustMemoryF (&Memory, &NoPages);
+ //
+ // It's safe to unset Guard page inside memory lock because there should
+ // be no memory allocation occurred in updating memory page attribute at
+ // this point. And unsetting Guard page before free will prevent Guard
+ // page just freed back to pool from being allocated right away before
+ // marking it usable (from non-present to present).
+ //
+ UnsetGuardForMemory (MemoryGuarded, NoPagesGuarded);
+ if (NoPages > 0) {
+ CoreFreePoolPagesI (PoolType, Memory, NoPages);
+ }
+}
+
+/**
+ Internal function to free a pool entry.
+ Caller must have the memory lock held
+
+ @param Buffer The allocated pool entry to free
+ @param PoolType Pointer to pool type
+
+ @retval EFI_INVALID_PARAMETER Buffer not valid
+ @retval EFI_SUCCESS Buffer successfully freed.
+
+**/
+EFI_STATUS
+CoreFreePoolI (
+ IN VOID *Buffer,
+ OUT EFI_MEMORY_TYPE *PoolType OPTIONAL
+ )
+{
+ POOL *Pool;
+ POOL_HEAD *Head;
+ POOL_TAIL *Tail;
+ POOL_FREE *Free;
+ UINTN Index;
+ UINTN NoPages;
+ UINTN Size;
+ CHAR8 *NewPage;
+ UINTN Offset;
+ BOOLEAN AllFree;
+ UINTN Granularity;
+ BOOLEAN IsGuarded;
+ BOOLEAN HasPoolTail;
+ BOOLEAN PageAsPool;
+
+ ASSERT(Buffer != NULL);
+ //
+ // Get the head & tail of the pool entry
+ //
+ Head = BASE_CR (Buffer, POOL_HEAD, Data);
+ ASSERT(Head != NULL);
+
+ if (Head->Signature != POOL_HEAD_SIGNATURE &&
+ Head->Signature != POOLPAGE_HEAD_SIGNATURE) {
+ ASSERT (Head->Signature == POOL_HEAD_SIGNATURE ||
+ Head->Signature == POOLPAGE_HEAD_SIGNATURE);
+ return EFI_INVALID_PARAMETER;
+ }
+
+ IsGuarded = IsPoolTypeToGuard (Head->Type) &&
+ IsMemoryGuarded ((EFI_PHYSICAL_ADDRESS)(UINTN)Head);
+ HasPoolTail = !(IsGuarded &&
+ ((PcdGet8 (PcdHeapGuardPropertyMask) & BIT7) == 0));
+ PageAsPool = (Head->Signature == POOLPAGE_HEAD_SIGNATURE);
+
+ if (HasPoolTail) {
+ Tail = HEAD_TO_TAIL (Head);
+ ASSERT (Tail != NULL);
+
+ //
+ // Debug
+ //
+ ASSERT (Tail->Signature == POOL_TAIL_SIGNATURE);
+ ASSERT (Head->Size == Tail->Size);
+
+ if (Tail->Signature != POOL_TAIL_SIGNATURE) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (Head->Size != Tail->Size) {
+ return EFI_INVALID_PARAMETER;
+ }
+ }
+
+ ASSERT_LOCKED (&mPoolMemoryLock);
+
+ //
+ // Determine the pool type and account for it
+ //
+ Size = Head->Size;
+ Pool = LookupPoolHead (Head->Type);
+ if (Pool == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+ Pool->Used -= Size;
+ DEBUG ((DEBUG_POOL, "FreePool: %p (len %lx) %,ld\n", Head->Data, (UINT64)(Head->Size - POOL_OVERHEAD), (UINT64) Pool->Used));
+
+ if (Head->Type == EfiACPIReclaimMemory ||
+ Head->Type == EfiACPIMemoryNVS ||
+ Head->Type == EfiRuntimeServicesCode ||
+ Head->Type == EfiRuntimeServicesData) {
+
+ Granularity = RUNTIME_PAGE_ALLOCATION_GRANULARITY;
+ } else {
+ Granularity = DEFAULT_PAGE_ALLOCATION_GRANULARITY;
+ }
+
+ if (PoolType != NULL) {
+ *PoolType = Head->Type;
+ }
+
+ //
+ // Determine the pool list
+ //
+ Index = SIZE_TO_LIST(Size);
+ DEBUG_CLEAR_MEMORY (Head, Size);
+
+ //
+ // If it's not on the list, it must be pool pages
+ //
+ if (Index >= SIZE_TO_LIST (Granularity) || IsGuarded || PageAsPool) {
+
+ //
+ // Return the memory pages back to free memory
+ //
+ NoPages = EFI_SIZE_TO_PAGES (Size) + EFI_SIZE_TO_PAGES (Granularity) - 1;
+ NoPages &= ~(UINTN)(EFI_SIZE_TO_PAGES (Granularity) - 1);
+ if (IsGuarded) {
+ Head = AdjustPoolHeadF ((EFI_PHYSICAL_ADDRESS)(UINTN)Head);
+ CoreFreePoolPagesWithGuard (
+ Pool->MemoryType,
+ (EFI_PHYSICAL_ADDRESS)(UINTN)Head,
+ NoPages
+ );
+ } else {
+ CoreFreePoolPagesI (
+ Pool->MemoryType,
+ (EFI_PHYSICAL_ADDRESS)(UINTN)Head,
+ NoPages
+ );
+ }
+
+ } else {
+
+ //
+ // Put the pool entry onto the free pool list
+ //
+ Free = (POOL_FREE *) Head;
+ ASSERT(Free != NULL);
+ Free->Signature = POOL_FREE_SIGNATURE;
+ Free->Index = (UINT32)Index;
+ InsertHeadList (&Pool->FreeList[Index], &Free->Link);
+
+ //
+ // See if all the pool entries in the same page as Free are freed pool
+ // entries
+ //
+ NewPage = (CHAR8 *)((UINTN)Free & ~(Granularity - 1));
+ Free = (POOL_FREE *) &NewPage[0];
+ ASSERT(Free != NULL);
+
+ if (Free->Signature == POOL_FREE_SIGNATURE) {
+
+ AllFree = TRUE;
+ Offset = 0;
+
+ while ((Offset < Granularity) && (AllFree)) {
+ Free = (POOL_FREE *) &NewPage[Offset];
+ ASSERT(Free != NULL);
+ if (Free->Signature != POOL_FREE_SIGNATURE) {
+ AllFree = FALSE;
+ }
+ Offset += LIST_TO_SIZE(Free->Index);
+ }
+
+ if (AllFree) {
+
+ //
+ // All of the pool entries in the same page as Free are free pool
+ // entries
+ // Remove all of these pool entries from the free loop lists.
+ //
+ Free = (POOL_FREE *) &NewPage[0];
+ ASSERT(Free != NULL);
+ Offset = 0;
+
+ while (Offset < Granularity) {
+ Free = (POOL_FREE *) &NewPage[Offset];
+ ASSERT(Free != NULL);
+ RemoveEntryList (&Free->Link);
+ Offset += LIST_TO_SIZE(Free->Index);
+ }
+
+ //
+ // Free the page
+ //
+ CoreFreePoolPagesI (Pool->MemoryType, (EFI_PHYSICAL_ADDRESS) (UINTN)NewPage,
+ EFI_SIZE_TO_PAGES (Granularity));
+ }
+ }
+ }
+
+ //
+ // If this is an OS/OEM specific memory type, then check to see if the last
+ // portion of that memory type has been freed. If it has, then free the
+ // list entry for that memory type
+ //
+ if (((UINT32) Pool->MemoryType >= MEMORY_TYPE_OEM_RESERVED_MIN) && Pool->Used == 0) {
+ RemoveEntryList (&Pool->Link);
+ CoreFreePoolI (Pool, NULL);
+ }
+
+ return EFI_SUCCESS;
+}
+
diff --git a/roms/edk2/MdeModulePkg/Core/Dxe/Misc/DebugImageInfo.c b/roms/edk2/MdeModulePkg/Core/Dxe/Misc/DebugImageInfo.c
new file mode 100644
index 000000000..a75d41582
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Core/Dxe/Misc/DebugImageInfo.c
@@ -0,0 +1,282 @@
+/** @file
+ Support functions for managing debug image info table when loading and unloading
+ images.
+
+Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "DxeMain.h"
+
+
+EFI_DEBUG_IMAGE_INFO_TABLE_HEADER mDebugInfoTableHeader = {
+ 0, // volatile UINT32 UpdateStatus;
+ 0, // UINT32 TableSize;
+ NULL // EFI_DEBUG_IMAGE_INFO *EfiDebugImageInfoTable;
+};
+
+UINTN mMaxTableEntries = 0;
+
+EFI_SYSTEM_TABLE_POINTER *mDebugTable = NULL;
+
+#define EFI_DEBUG_TABLE_ENTRY_SIZE (sizeof (VOID *))
+
+/**
+ Creates and initializes the DebugImageInfo Table. Also creates the configuration
+ table and registers it into the system table.
+
+**/
+VOID
+CoreInitializeDebugImageInfoTable (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ UINTN Pages;
+ EFI_PHYSICAL_ADDRESS Memory;
+ UINTN AlignedMemory;
+ UINTN AlignmentMask;
+ UINTN UnalignedPages;
+ UINTN RealPages;
+
+ //
+ // Allocate 4M aligned page for the structure and fill in the data.
+ // Ideally we would update the CRC now as well, but the service may not yet be available.
+ // See comments in the CoreUpdateDebugTableCrc32() function below for details.
+ //
+ Pages = EFI_SIZE_TO_PAGES (sizeof (EFI_SYSTEM_TABLE_POINTER));
+ AlignmentMask = SIZE_4MB - 1;
+ RealPages = Pages + EFI_SIZE_TO_PAGES (SIZE_4MB);
+
+ //
+ // Attempt to allocate memory below PcdMaxEfiSystemTablePointerAddress
+ // If PcdMaxEfiSystemTablePointerAddress is 0, then allocate memory below
+ // MAX_ADDRESS
+ //
+ Memory = PcdGet64 (PcdMaxEfiSystemTablePointerAddress);
+ if (Memory == 0) {
+ Memory = MAX_ADDRESS;
+ }
+ Status = CoreAllocatePages (
+ AllocateMaxAddress,
+ EfiBootServicesData,
+ RealPages,
+ &Memory
+ );
+ if (EFI_ERROR (Status)) {
+ if (PcdGet64 (PcdMaxEfiSystemTablePointerAddress) != 0) {
+ DEBUG ((EFI_D_INFO, "Allocate memory for EFI_SYSTEM_TABLE_POINTER below PcdMaxEfiSystemTablePointerAddress failed. \
+ Retry to allocate memroy as close to the top of memory as feasible.\n"));
+ }
+ //
+ // If the initial memory allocation fails, then reattempt allocation
+ // as close to the top of memory as feasible.
+ //
+ Status = CoreAllocatePages (
+ AllocateAnyPages,
+ EfiBootServicesData,
+ RealPages,
+ &Memory
+ );
+ ASSERT_EFI_ERROR (Status);
+ if (EFI_ERROR (Status)) {
+ return;
+ }
+ }
+
+ //
+ // Free overallocated pages
+ //
+ AlignedMemory = ((UINTN) Memory + AlignmentMask) & ~AlignmentMask;
+ UnalignedPages = EFI_SIZE_TO_PAGES (AlignedMemory - (UINTN)Memory);
+ if (UnalignedPages > 0) {
+ //
+ // Free first unaligned page(s).
+ //
+ Status = CoreFreePages (Memory, UnalignedPages);
+ ASSERT_EFI_ERROR (Status);
+ }
+ Memory = AlignedMemory + EFI_PAGES_TO_SIZE (Pages);
+ UnalignedPages = RealPages - Pages - UnalignedPages;
+ if (UnalignedPages > 0) {
+ //
+ // Free last unaligned page(s).
+ //
+ Status = CoreFreePages (Memory, UnalignedPages);
+ ASSERT_EFI_ERROR (Status);
+ }
+
+ //
+ // Set mDebugTable to the 4MB aligned allocated pages
+ //
+ mDebugTable = (EFI_SYSTEM_TABLE_POINTER *)(AlignedMemory);
+ ASSERT (mDebugTable != NULL);
+
+ //
+ // Initialize EFI_SYSTEM_TABLE_POINTER structure
+ //
+ mDebugTable->Signature = EFI_SYSTEM_TABLE_SIGNATURE;
+ mDebugTable->EfiSystemTableBase = (EFI_PHYSICAL_ADDRESS) (UINTN) gDxeCoreST;
+ mDebugTable->Crc32 = 0;
+
+ //
+ // Install the EFI_SYSTEM_TABLE_POINTER structure in the EFI System
+ // Configuration Table
+ //
+ Status = CoreInstallConfigurationTable (&gEfiDebugImageInfoTableGuid, &mDebugInfoTableHeader);
+ ASSERT_EFI_ERROR (Status);
+}
+
+
+/**
+ Update the CRC32 in the Debug Table.
+ Since the CRC32 service is made available by the Runtime driver, we have to
+ wait for the Runtime Driver to be installed before the CRC32 can be computed.
+ This function is called elsewhere by the core when the runtime architectural
+ protocol is produced.
+
+**/
+VOID
+CoreUpdateDebugTableCrc32 (
+ VOID
+ )
+{
+ ASSERT(mDebugTable != NULL);
+ mDebugTable->Crc32 = 0;
+ gBS->CalculateCrc32 ((VOID *)mDebugTable, sizeof (EFI_SYSTEM_TABLE_POINTER), &mDebugTable->Crc32);
+}
+
+
+/**
+ Adds a new DebugImageInfo structure to the DebugImageInfo Table. Re-Allocates
+ the table if it's not large enough to accomidate another entry.
+
+ @param ImageInfoType type of debug image information
+ @param LoadedImage pointer to the loaded image protocol for the image being
+ loaded
+ @param ImageHandle image handle for the image being loaded
+
+**/
+VOID
+CoreNewDebugImageInfoEntry (
+ IN UINT32 ImageInfoType,
+ IN EFI_LOADED_IMAGE_PROTOCOL *LoadedImage,
+ IN EFI_HANDLE ImageHandle
+ )
+{
+ EFI_DEBUG_IMAGE_INFO *Table;
+ EFI_DEBUG_IMAGE_INFO *NewTable;
+ UINTN Index;
+ UINTN TableSize;
+
+ //
+ // Set the flag indicating that we're in the process of updating the table.
+ //
+ mDebugInfoTableHeader.UpdateStatus |= EFI_DEBUG_IMAGE_INFO_UPDATE_IN_PROGRESS;
+
+ Table = mDebugInfoTableHeader.EfiDebugImageInfoTable;
+
+ if (mDebugInfoTableHeader.TableSize < mMaxTableEntries) {
+ //
+ // We still have empty entires in the Table, find the first empty entry.
+ //
+ Index = 0;
+ while (Table[Index].NormalImage != NULL) {
+ Index++;
+ }
+ //
+ // There must be an empty entry in the in the table.
+ //
+ ASSERT (Index < mMaxTableEntries);
+ } else {
+ //
+ // Table is full, so re-allocate another page for a larger table...
+ //
+ TableSize = mMaxTableEntries * EFI_DEBUG_TABLE_ENTRY_SIZE;
+ NewTable = AllocateZeroPool (TableSize + EFI_PAGE_SIZE);
+ if (NewTable == NULL) {
+ mDebugInfoTableHeader.UpdateStatus &= ~EFI_DEBUG_IMAGE_INFO_UPDATE_IN_PROGRESS;
+ return;
+ }
+ //
+ // Copy the old table into the new one
+ //
+ CopyMem (NewTable, Table, TableSize);
+ //
+ // Free the old table
+ //
+ CoreFreePool (Table);
+ //
+ // Update the table header
+ //
+ Table = NewTable;
+ mDebugInfoTableHeader.EfiDebugImageInfoTable = NewTable;
+ //
+ // Enlarge the max table entries and set the first empty entry index to
+ // be the original max table entries.
+ //
+ Index = mMaxTableEntries;
+ mMaxTableEntries += EFI_PAGE_SIZE / EFI_DEBUG_TABLE_ENTRY_SIZE;
+ }
+
+ //
+ // Allocate data for new entry
+ //
+ Table[Index].NormalImage = AllocateZeroPool (sizeof (EFI_DEBUG_IMAGE_INFO_NORMAL));
+ if (Table[Index].NormalImage != NULL) {
+ //
+ // Update the entry
+ //
+ Table[Index].NormalImage->ImageInfoType = (UINT32) ImageInfoType;
+ Table[Index].NormalImage->LoadedImageProtocolInstance = LoadedImage;
+ Table[Index].NormalImage->ImageHandle = ImageHandle;
+ //
+ // Increase the number of EFI_DEBUG_IMAGE_INFO elements and set the mDebugInfoTable in modified status.
+ //
+ mDebugInfoTableHeader.TableSize++;
+ mDebugInfoTableHeader.UpdateStatus |= EFI_DEBUG_IMAGE_INFO_TABLE_MODIFIED;
+ }
+ mDebugInfoTableHeader.UpdateStatus &= ~EFI_DEBUG_IMAGE_INFO_UPDATE_IN_PROGRESS;
+}
+
+
+
+/**
+ Removes and frees an entry from the DebugImageInfo Table.
+
+ @param ImageHandle image handle for the image being unloaded
+
+**/
+VOID
+CoreRemoveDebugImageInfoEntry (
+ EFI_HANDLE ImageHandle
+ )
+{
+ EFI_DEBUG_IMAGE_INFO *Table;
+ UINTN Index;
+
+ mDebugInfoTableHeader.UpdateStatus |= EFI_DEBUG_IMAGE_INFO_UPDATE_IN_PROGRESS;
+
+ Table = mDebugInfoTableHeader.EfiDebugImageInfoTable;
+
+ for (Index = 0; Index < mMaxTableEntries; Index++) {
+ if (Table[Index].NormalImage != NULL && Table[Index].NormalImage->ImageHandle == ImageHandle) {
+ //
+ // Found a match. Free up the record, then NULL the pointer to indicate the slot
+ // is free.
+ //
+ CoreFreePool (Table[Index].NormalImage);
+ Table[Index].NormalImage = NULL;
+ //
+ // Decrease the number of EFI_DEBUG_IMAGE_INFO elements and set the mDebugInfoTable in modified status.
+ //
+ mDebugInfoTableHeader.TableSize--;
+ mDebugInfoTableHeader.UpdateStatus |= EFI_DEBUG_IMAGE_INFO_TABLE_MODIFIED;
+ break;
+ }
+ }
+ mDebugInfoTableHeader.UpdateStatus &= ~EFI_DEBUG_IMAGE_INFO_UPDATE_IN_PROGRESS;
+}
+
+
diff --git a/roms/edk2/MdeModulePkg/Core/Dxe/Misc/InstallConfigurationTable.c b/roms/edk2/MdeModulePkg/Core/Dxe/Misc/InstallConfigurationTable.c
new file mode 100755
index 000000000..ba4e55fcd
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Core/Dxe/Misc/InstallConfigurationTable.c
@@ -0,0 +1,181 @@
+/** @file
+ UEFI Miscellaneous boot Services InstallConfigurationTable service
+
+Copyright (c) 2006 - 2017, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "DxeMain.h"
+
+#define CONFIG_TABLE_SIZE_INCREASED 0x10
+
+UINTN mSystemTableAllocateSize = 0;
+
+/**
+ Boot Service called to add, modify, or remove a system configuration table from
+ the EFI System Table.
+
+ @param Guid Pointer to the GUID for the entry to add, update, or
+ remove
+ @param Table Pointer to the configuration table for the entry to add,
+ update, or remove, may be NULL.
+
+ @return EFI_SUCCESS Guid, Table pair added, updated, or removed.
+ @return EFI_INVALID_PARAMETER Input GUID is NULL.
+ @return EFI_NOT_FOUND Attempted to delete non-existant entry
+ @return EFI_OUT_OF_RESOURCES Not enough memory available
+
+**/
+EFI_STATUS
+EFIAPI
+CoreInstallConfigurationTable (
+ IN EFI_GUID *Guid,
+ IN VOID *Table
+ )
+{
+ UINTN Index;
+ EFI_CONFIGURATION_TABLE *EfiConfigurationTable;
+ EFI_CONFIGURATION_TABLE *OldTable;
+
+ //
+ // If Guid is NULL, then this operation cannot be performed
+ //
+ if (Guid == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ EfiConfigurationTable = gDxeCoreST->ConfigurationTable;
+
+ //
+ // Search all the table for an entry that matches Guid
+ //
+ for (Index = 0; Index < gDxeCoreST->NumberOfTableEntries; Index++) {
+ if (CompareGuid (Guid, &(gDxeCoreST->ConfigurationTable[Index].VendorGuid))) {
+ break;
+ }
+ }
+
+ if (Index < gDxeCoreST->NumberOfTableEntries) {
+ //
+ // A match was found, so this is either a modify or a delete operation
+ //
+ if (Table != NULL) {
+ //
+ // If Table is not NULL, then this is a modify operation.
+ // Modify the table entry and return.
+ //
+ gDxeCoreST->ConfigurationTable[Index].VendorTable = Table;
+
+ //
+ // Signal Configuration Table change
+ //
+ CoreNotifySignalList (Guid);
+
+ return EFI_SUCCESS;
+ }
+
+ //
+ // A match was found and Table is NULL, so this is a delete operation.
+ //
+ gDxeCoreST->NumberOfTableEntries--;
+
+ //
+ // Copy over deleted entry
+ //
+ CopyMem (
+ &(EfiConfigurationTable[Index]),
+ &(gDxeCoreST->ConfigurationTable[Index + 1]),
+ (gDxeCoreST->NumberOfTableEntries - Index) * sizeof (EFI_CONFIGURATION_TABLE)
+ );
+
+ } else {
+
+ //
+ // No matching GUIDs were found, so this is an add operation.
+ //
+
+ if (Table == NULL) {
+ //
+ // If Table is NULL on an add operation, then return an error.
+ //
+ return EFI_NOT_FOUND;
+ }
+
+ //
+ // Assume that Index == gDxeCoreST->NumberOfTableEntries
+ //
+ if ((Index * sizeof (EFI_CONFIGURATION_TABLE)) >= mSystemTableAllocateSize) {
+ //
+ // Allocate a table with one additional entry.
+ //
+ mSystemTableAllocateSize += (CONFIG_TABLE_SIZE_INCREASED * sizeof (EFI_CONFIGURATION_TABLE));
+ EfiConfigurationTable = AllocateRuntimePool (mSystemTableAllocateSize);
+ if (EfiConfigurationTable == NULL) {
+ //
+ // If a new table could not be allocated, then return an error.
+ //
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ if (gDxeCoreST->ConfigurationTable != NULL) {
+ //
+ // Copy the old table to the new table.
+ //
+ CopyMem (
+ EfiConfigurationTable,
+ gDxeCoreST->ConfigurationTable,
+ Index * sizeof (EFI_CONFIGURATION_TABLE)
+ );
+
+ //
+ // Record the old table pointer.
+ //
+ OldTable = gDxeCoreST->ConfigurationTable;
+
+ //
+ // As the CoreInstallConfigurationTable() may be re-entered by CoreFreePool()
+ // in its calling stack, updating System table to the new table pointer must
+ // be done before calling CoreFreePool() to free the old table.
+ // It can make sure the gDxeCoreST->ConfigurationTable point to the new table
+ // and avoid the errors of use-after-free to the old table by the reenter of
+ // CoreInstallConfigurationTable() in CoreFreePool()'s calling stack.
+ //
+ gDxeCoreST->ConfigurationTable = EfiConfigurationTable;
+
+ //
+ // Free the old table after updating System Table to the new table pointer.
+ //
+ CoreFreePool (OldTable);
+ } else {
+ //
+ // Update System Table
+ //
+ gDxeCoreST->ConfigurationTable = EfiConfigurationTable;
+ }
+ }
+
+ //
+ // Fill in the new entry
+ //
+ CopyGuid ((VOID *)&EfiConfigurationTable[Index].VendorGuid, Guid);
+ EfiConfigurationTable[Index].VendorTable = Table;
+
+ //
+ // This is an add operation, so increment the number of table entries
+ //
+ gDxeCoreST->NumberOfTableEntries++;
+ }
+
+ //
+ // Fix up the CRC-32 in the EFI System Table
+ //
+ CalculateEfiHdrCrc (&gDxeCoreST->Hdr);
+
+ //
+ // Signal Configuration Table change
+ //
+ CoreNotifySignalList (Guid);
+
+ return EFI_SUCCESS;
+}
diff --git a/roms/edk2/MdeModulePkg/Core/Dxe/Misc/MemoryAttributesTable.c b/roms/edk2/MdeModulePkg/Core/Dxe/Misc/MemoryAttributesTable.c
new file mode 100644
index 000000000..45356130b
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Core/Dxe/Misc/MemoryAttributesTable.c
@@ -0,0 +1,1514 @@
+/** @file
+ UEFI MemoryAttributesTable support
+
+Copyright (c) 2016 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <PiDxe.h>
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/DxeServicesTableLib.h>
+#include <Library/DebugLib.h>
+#include <Library/UefiLib.h>
+
+#include <Guid/EventGroup.h>
+
+#include <Guid/MemoryAttributesTable.h>
+
+#include "DxeMain.h"
+#include "HeapGuard.h"
+
+/**
+ This function for GetMemoryMap() with properties table capability.
+
+ It calls original GetMemoryMap() to get the original memory map information. Then
+ plus the additional memory map entries for PE Code/Data seperation.
+
+ @param MemoryMapSize A pointer to the size, in bytes, of the
+ MemoryMap buffer. On input, this is the size of
+ the buffer allocated by the caller. On output,
+ it is the size of the buffer returned by the
+ firmware if the buffer was large enough, or the
+ size of the buffer needed to contain the map if
+ the buffer was too small.
+ @param MemoryMap A pointer to the buffer in which firmware places
+ the current memory map.
+ @param MapKey A pointer to the location in which firmware
+ returns the key for the current memory map.
+ @param DescriptorSize A pointer to the location in which firmware
+ returns the size, in bytes, of an individual
+ EFI_MEMORY_DESCRIPTOR.
+ @param DescriptorVersion A pointer to the location in which firmware
+ returns the version number associated with the
+ EFI_MEMORY_DESCRIPTOR.
+
+ @retval EFI_SUCCESS The memory map was returned in the MemoryMap
+ buffer.
+ @retval EFI_BUFFER_TOO_SMALL The MemoryMap buffer was too small. The current
+ buffer size needed to hold the memory map is
+ returned in MemoryMapSize.
+ @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
+
+**/
+EFI_STATUS
+EFIAPI
+CoreGetMemoryMapWithSeparatedImageSection (
+ IN OUT UINTN *MemoryMapSize,
+ IN OUT EFI_MEMORY_DESCRIPTOR *MemoryMap,
+ OUT UINTN *MapKey,
+ OUT UINTN *DescriptorSize,
+ OUT UINT32 *DescriptorVersion
+ );
+
+#define PREVIOUS_MEMORY_DESCRIPTOR(MemoryDescriptor, Size) \
+ ((EFI_MEMORY_DESCRIPTOR *)((UINT8 *)(MemoryDescriptor) - (Size)))
+
+#define IMAGE_PROPERTIES_PRIVATE_DATA_SIGNATURE SIGNATURE_32 ('I','P','P','D')
+
+typedef struct {
+ UINT32 Signature;
+ UINTN ImageRecordCount;
+ UINTN CodeSegmentCountMax;
+ LIST_ENTRY ImageRecordList;
+} IMAGE_PROPERTIES_PRIVATE_DATA;
+
+STATIC IMAGE_PROPERTIES_PRIVATE_DATA mImagePropertiesPrivateData = {
+ IMAGE_PROPERTIES_PRIVATE_DATA_SIGNATURE,
+ 0,
+ 0,
+ INITIALIZE_LIST_HEAD_VARIABLE (mImagePropertiesPrivateData.ImageRecordList)
+};
+
+STATIC EFI_LOCK mMemoryAttributesTableLock = EFI_INITIALIZE_LOCK_VARIABLE (TPL_NOTIFY);
+
+BOOLEAN mMemoryAttributesTableEnable = TRUE;
+BOOLEAN mMemoryAttributesTableEndOfDxe = FALSE;
+EFI_MEMORY_ATTRIBUTES_TABLE *mMemoryAttributesTable = NULL;
+BOOLEAN mMemoryAttributesTableReadyToBoot = FALSE;
+
+/**
+ Install MemoryAttributesTable.
+
+**/
+VOID
+InstallMemoryAttributesTable (
+ VOID
+ )
+{
+ UINTN MemoryMapSize;
+ EFI_MEMORY_DESCRIPTOR *MemoryMap;
+ EFI_MEMORY_DESCRIPTOR *MemoryMapStart;
+ UINTN MapKey;
+ UINTN DescriptorSize;
+ UINT32 DescriptorVersion;
+ UINTN Index;
+ EFI_STATUS Status;
+ UINT32 RuntimeEntryCount;
+ EFI_MEMORY_ATTRIBUTES_TABLE *MemoryAttributesTable;
+ EFI_MEMORY_DESCRIPTOR *MemoryAttributesEntry;
+
+ if (gMemoryMapTerminated) {
+ //
+ // Directly return after MemoryMap terminated.
+ //
+ return;
+ }
+
+ if (!mMemoryAttributesTableEnable) {
+ DEBUG ((DEBUG_VERBOSE, "Cannot install Memory Attributes Table "));
+ DEBUG ((EFI_D_VERBOSE, "because Runtime Driver Section Alignment is not %dK.\n", RUNTIME_PAGE_ALLOCATION_GRANULARITY >> 10));
+ return ;
+ }
+
+ if (mMemoryAttributesTable == NULL) {
+ //
+ // InstallConfigurationTable here to occupy one entry for MemoryAttributesTable
+ // before GetMemoryMap below, as InstallConfigurationTable may allocate runtime
+ // memory for the new entry.
+ //
+ Status = gBS->InstallConfigurationTable (&gEfiMemoryAttributesTableGuid, (VOID *) (UINTN) MAX_ADDRESS);
+ ASSERT_EFI_ERROR (Status);
+ }
+
+ MemoryMapSize = 0;
+ MemoryMap = NULL;
+ Status = CoreGetMemoryMapWithSeparatedImageSection (
+ &MemoryMapSize,
+ MemoryMap,
+ &MapKey,
+ &DescriptorSize,
+ &DescriptorVersion
+ );
+ ASSERT (Status == EFI_BUFFER_TOO_SMALL);
+
+ do {
+ MemoryMap = AllocatePool (MemoryMapSize);
+ ASSERT (MemoryMap != NULL);
+
+ Status = CoreGetMemoryMapWithSeparatedImageSection (
+ &MemoryMapSize,
+ MemoryMap,
+ &MapKey,
+ &DescriptorSize,
+ &DescriptorVersion
+ );
+ if (EFI_ERROR (Status)) {
+ FreePool (MemoryMap);
+ }
+ } while (Status == EFI_BUFFER_TOO_SMALL);
+
+ MemoryMapStart = MemoryMap;
+ RuntimeEntryCount = 0;
+ for (Index = 0; Index < MemoryMapSize/DescriptorSize; Index++) {
+ switch (MemoryMap->Type) {
+ case EfiRuntimeServicesCode:
+ case EfiRuntimeServicesData:
+ RuntimeEntryCount ++;
+ break;
+ }
+ MemoryMap = NEXT_MEMORY_DESCRIPTOR(MemoryMap, DescriptorSize);
+ }
+
+ //
+ // Allocate MemoryAttributesTable
+ //
+ MemoryAttributesTable = AllocatePool (sizeof(EFI_MEMORY_ATTRIBUTES_TABLE) + DescriptorSize * RuntimeEntryCount);
+ ASSERT (MemoryAttributesTable != NULL);
+ MemoryAttributesTable->Version = EFI_MEMORY_ATTRIBUTES_TABLE_VERSION;
+ MemoryAttributesTable->NumberOfEntries = RuntimeEntryCount;
+ MemoryAttributesTable->DescriptorSize = (UINT32)DescriptorSize;
+ MemoryAttributesTable->Reserved = 0;
+ DEBUG ((EFI_D_VERBOSE, "MemoryAttributesTable:\n"));
+ DEBUG ((EFI_D_VERBOSE, " Version - 0x%08x\n", MemoryAttributesTable->Version));
+ DEBUG ((EFI_D_VERBOSE, " NumberOfEntries - 0x%08x\n", MemoryAttributesTable->NumberOfEntries));
+ DEBUG ((EFI_D_VERBOSE, " DescriptorSize - 0x%08x\n", MemoryAttributesTable->DescriptorSize));
+ MemoryAttributesEntry = (EFI_MEMORY_DESCRIPTOR *)(MemoryAttributesTable + 1);
+ MemoryMap = MemoryMapStart;
+ for (Index = 0; Index < MemoryMapSize/DescriptorSize; Index++) {
+ switch (MemoryMap->Type) {
+ case EfiRuntimeServicesCode:
+ case EfiRuntimeServicesData:
+ CopyMem (MemoryAttributesEntry, MemoryMap, DescriptorSize);
+ MemoryAttributesEntry->Attribute &= (EFI_MEMORY_RO|EFI_MEMORY_XP|EFI_MEMORY_RUNTIME);
+ DEBUG ((EFI_D_VERBOSE, "Entry (0x%x)\n", MemoryAttributesEntry));
+ DEBUG ((EFI_D_VERBOSE, " Type - 0x%x\n", MemoryAttributesEntry->Type));
+ DEBUG ((EFI_D_VERBOSE, " PhysicalStart - 0x%016lx\n", MemoryAttributesEntry->PhysicalStart));
+ DEBUG ((EFI_D_VERBOSE, " VirtualStart - 0x%016lx\n", MemoryAttributesEntry->VirtualStart));
+ DEBUG ((EFI_D_VERBOSE, " NumberOfPages - 0x%016lx\n", MemoryAttributesEntry->NumberOfPages));
+ DEBUG ((EFI_D_VERBOSE, " Attribute - 0x%016lx\n", MemoryAttributesEntry->Attribute));
+ MemoryAttributesEntry = NEXT_MEMORY_DESCRIPTOR(MemoryAttributesEntry, DescriptorSize);
+ break;
+ }
+ MemoryMap = NEXT_MEMORY_DESCRIPTOR(MemoryMap, DescriptorSize);
+ }
+ MemoryMap = MemoryMapStart;
+ FreePool (MemoryMap);
+
+ //
+ // Update configuratoin table for MemoryAttributesTable.
+ //
+ Status = gBS->InstallConfigurationTable (&gEfiMemoryAttributesTableGuid, MemoryAttributesTable);
+ ASSERT_EFI_ERROR (Status);
+
+ if (mMemoryAttributesTable != NULL) {
+ FreePool (mMemoryAttributesTable);
+ }
+ mMemoryAttributesTable = MemoryAttributesTable;
+}
+
+/**
+ Install MemoryAttributesTable on memory allocation.
+
+ @param[in] MemoryType EFI memory type.
+**/
+VOID
+InstallMemoryAttributesTableOnMemoryAllocation (
+ IN EFI_MEMORY_TYPE MemoryType
+ )
+{
+ //
+ // Install MemoryAttributesTable after ReadyToBoot on runtime memory allocation.
+ //
+ if (mMemoryAttributesTableReadyToBoot &&
+ ((MemoryType == EfiRuntimeServicesCode) || (MemoryType == EfiRuntimeServicesData))) {
+ InstallMemoryAttributesTable ();
+ }
+}
+
+/**
+ Install MemoryAttributesTable on ReadyToBoot.
+
+ @param[in] Event The Event this notify function registered to.
+ @param[in] Context Pointer to the context data registered to the Event.
+**/
+VOID
+EFIAPI
+InstallMemoryAttributesTableOnReadyToBoot (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ InstallMemoryAttributesTable ();
+ mMemoryAttributesTableReadyToBoot = TRUE;
+}
+
+/**
+ Install initial MemoryAttributesTable on EndOfDxe.
+ Then SMM can consume this information.
+
+ @param[in] Event The Event this notify function registered to.
+ @param[in] Context Pointer to the context data registered to the Event.
+**/
+VOID
+EFIAPI
+InstallMemoryAttributesTableOnEndOfDxe (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ mMemoryAttributesTableEndOfDxe = TRUE;
+ InstallMemoryAttributesTable ();
+}
+
+/**
+ Initialize MemoryAttrubutesTable support.
+**/
+VOID
+EFIAPI
+CoreInitializeMemoryAttributesTable (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ EFI_EVENT ReadyToBootEvent;
+ EFI_EVENT EndOfDxeEvent;
+
+ //
+ // Construct the table at ReadyToBoot.
+ //
+ Status = CoreCreateEventInternal (
+ EVT_NOTIFY_SIGNAL,
+ TPL_CALLBACK,
+ InstallMemoryAttributesTableOnReadyToBoot,
+ NULL,
+ &gEfiEventReadyToBootGuid,
+ &ReadyToBootEvent
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Construct the initial table at EndOfDxe,
+ // then SMM can consume this information.
+ // Use TPL_NOTIFY here, as such SMM code (TPL_CALLBACK)
+ // can run after it.
+ //
+ Status = CoreCreateEventInternal (
+ EVT_NOTIFY_SIGNAL,
+ TPL_NOTIFY,
+ InstallMemoryAttributesTableOnEndOfDxe,
+ NULL,
+ &gEfiEndOfDxeEventGroupGuid,
+ &EndOfDxeEvent
+ );
+ ASSERT_EFI_ERROR (Status);
+ return ;
+}
+
+//
+// Below functions are for MemoryMap
+//
+
+/**
+ Converts a number of EFI_PAGEs to a size in bytes.
+
+ NOTE: Do not use EFI_PAGES_TO_SIZE because it handles UINTN only.
+
+ @param Pages The number of EFI_PAGES.
+
+ @return The number of bytes associated with the number of EFI_PAGEs specified
+ by Pages.
+**/
+STATIC
+UINT64
+EfiPagesToSize (
+ IN UINT64 Pages
+ )
+{
+ return LShiftU64 (Pages, EFI_PAGE_SHIFT);
+}
+
+/**
+ Converts a size, in bytes, to a number of EFI_PAGESs.
+
+ NOTE: Do not use EFI_SIZE_TO_PAGES because it handles UINTN only.
+
+ @param Size A size in bytes.
+
+ @return The number of EFI_PAGESs associated with the number of bytes specified
+ by Size.
+
+**/
+STATIC
+UINT64
+EfiSizeToPages (
+ IN UINT64 Size
+ )
+{
+ return RShiftU64 (Size, EFI_PAGE_SHIFT) + ((((UINTN)Size) & EFI_PAGE_MASK) ? 1 : 0);
+}
+
+/**
+ Acquire memory lock on mMemoryAttributesTableLock.
+**/
+STATIC
+VOID
+CoreAcquiremMemoryAttributesTableLock (
+ VOID
+ )
+{
+ CoreAcquireLock (&mMemoryAttributesTableLock);
+}
+
+/**
+ Release memory lock on mMemoryAttributesTableLock.
+**/
+STATIC
+VOID
+CoreReleasemMemoryAttributesTableLock (
+ VOID
+ )
+{
+ CoreReleaseLock (&mMemoryAttributesTableLock);
+}
+
+/**
+ Sort memory map entries based upon PhysicalStart, from low to high.
+
+ @param MemoryMap A pointer to the buffer in which firmware places
+ the current memory map.
+ @param MemoryMapSize Size, in bytes, of the MemoryMap buffer.
+ @param DescriptorSize Size, in bytes, of an individual EFI_MEMORY_DESCRIPTOR.
+**/
+STATIC
+VOID
+SortMemoryMap (
+ IN OUT EFI_MEMORY_DESCRIPTOR *MemoryMap,
+ IN UINTN MemoryMapSize,
+ IN UINTN DescriptorSize
+ )
+{
+ EFI_MEMORY_DESCRIPTOR *MemoryMapEntry;
+ EFI_MEMORY_DESCRIPTOR *NextMemoryMapEntry;
+ EFI_MEMORY_DESCRIPTOR *MemoryMapEnd;
+ EFI_MEMORY_DESCRIPTOR TempMemoryMap;
+
+ MemoryMapEntry = MemoryMap;
+ NextMemoryMapEntry = NEXT_MEMORY_DESCRIPTOR (MemoryMapEntry, DescriptorSize);
+ MemoryMapEnd = (EFI_MEMORY_DESCRIPTOR *) ((UINT8 *) MemoryMap + MemoryMapSize);
+ while (MemoryMapEntry < MemoryMapEnd) {
+ while (NextMemoryMapEntry < MemoryMapEnd) {
+ if (MemoryMapEntry->PhysicalStart > NextMemoryMapEntry->PhysicalStart) {
+ CopyMem (&TempMemoryMap, MemoryMapEntry, sizeof(EFI_MEMORY_DESCRIPTOR));
+ CopyMem (MemoryMapEntry, NextMemoryMapEntry, sizeof(EFI_MEMORY_DESCRIPTOR));
+ CopyMem (NextMemoryMapEntry, &TempMemoryMap, sizeof(EFI_MEMORY_DESCRIPTOR));
+ }
+
+ NextMemoryMapEntry = NEXT_MEMORY_DESCRIPTOR (NextMemoryMapEntry, DescriptorSize);
+ }
+
+ MemoryMapEntry = NEXT_MEMORY_DESCRIPTOR (MemoryMapEntry, DescriptorSize);
+ NextMemoryMapEntry = NEXT_MEMORY_DESCRIPTOR (MemoryMapEntry, DescriptorSize);
+ }
+
+ return ;
+}
+
+/**
+ Merge continous memory map entries whose have same attributes.
+
+ @param MemoryMap A pointer to the buffer in which firmware places
+ the current memory map.
+ @param MemoryMapSize A pointer to the size, in bytes, of the
+ MemoryMap buffer. On input, this is the size of
+ the current memory map. On output,
+ it is the size of new memory map after merge.
+ @param DescriptorSize Size, in bytes, of an individual EFI_MEMORY_DESCRIPTOR.
+**/
+VOID
+MergeMemoryMap (
+ IN OUT EFI_MEMORY_DESCRIPTOR *MemoryMap,
+ IN OUT UINTN *MemoryMapSize,
+ IN UINTN DescriptorSize
+ )
+{
+ EFI_MEMORY_DESCRIPTOR *MemoryMapEntry;
+ EFI_MEMORY_DESCRIPTOR *MemoryMapEnd;
+ UINT64 MemoryBlockLength;
+ EFI_MEMORY_DESCRIPTOR *NewMemoryMapEntry;
+ EFI_MEMORY_DESCRIPTOR *NextMemoryMapEntry;
+
+ MemoryMapEntry = MemoryMap;
+ NewMemoryMapEntry = MemoryMap;
+ MemoryMapEnd = (EFI_MEMORY_DESCRIPTOR *) ((UINT8 *) MemoryMap + *MemoryMapSize);
+ while ((UINTN)MemoryMapEntry < (UINTN)MemoryMapEnd) {
+ CopyMem (NewMemoryMapEntry, MemoryMapEntry, sizeof(EFI_MEMORY_DESCRIPTOR));
+ NextMemoryMapEntry = NEXT_MEMORY_DESCRIPTOR (MemoryMapEntry, DescriptorSize);
+
+ do {
+ MergeGuardPages (NewMemoryMapEntry, NextMemoryMapEntry->PhysicalStart);
+ MemoryBlockLength = (UINT64) (EfiPagesToSize (NewMemoryMapEntry->NumberOfPages));
+ if (((UINTN)NextMemoryMapEntry < (UINTN)MemoryMapEnd) &&
+ (NewMemoryMapEntry->Type == NextMemoryMapEntry->Type) &&
+ (NewMemoryMapEntry->Attribute == NextMemoryMapEntry->Attribute) &&
+ ((NewMemoryMapEntry->PhysicalStart + MemoryBlockLength) == NextMemoryMapEntry->PhysicalStart)) {
+ NewMemoryMapEntry->NumberOfPages += NextMemoryMapEntry->NumberOfPages;
+ NextMemoryMapEntry = NEXT_MEMORY_DESCRIPTOR (NextMemoryMapEntry, DescriptorSize);
+ continue;
+ } else {
+ MemoryMapEntry = PREVIOUS_MEMORY_DESCRIPTOR (NextMemoryMapEntry, DescriptorSize);
+ break;
+ }
+ } while (TRUE);
+
+ MemoryMapEntry = NEXT_MEMORY_DESCRIPTOR (MemoryMapEntry, DescriptorSize);
+ NewMemoryMapEntry = NEXT_MEMORY_DESCRIPTOR (NewMemoryMapEntry, DescriptorSize);
+ }
+
+ *MemoryMapSize = (UINTN)NewMemoryMapEntry - (UINTN)MemoryMap;
+
+ return ;
+}
+
+/**
+ Enforce memory map attributes.
+ This function will set EfiRuntimeServicesData/EfiMemoryMappedIO/EfiMemoryMappedIOPortSpace to be EFI_MEMORY_XP.
+
+ @param MemoryMap A pointer to the buffer in which firmware places
+ the current memory map.
+ @param MemoryMapSize Size, in bytes, of the MemoryMap buffer.
+ @param DescriptorSize Size, in bytes, of an individual EFI_MEMORY_DESCRIPTOR.
+**/
+STATIC
+VOID
+EnforceMemoryMapAttribute (
+ IN OUT EFI_MEMORY_DESCRIPTOR *MemoryMap,
+ IN UINTN MemoryMapSize,
+ IN UINTN DescriptorSize
+ )
+{
+ EFI_MEMORY_DESCRIPTOR *MemoryMapEntry;
+ EFI_MEMORY_DESCRIPTOR *MemoryMapEnd;
+
+ MemoryMapEntry = MemoryMap;
+ MemoryMapEnd = (EFI_MEMORY_DESCRIPTOR *) ((UINT8 *) MemoryMap + MemoryMapSize);
+ while ((UINTN)MemoryMapEntry < (UINTN)MemoryMapEnd) {
+ switch (MemoryMapEntry->Type) {
+ case EfiRuntimeServicesCode:
+ // do nothing
+ break;
+ case EfiRuntimeServicesData:
+ case EfiMemoryMappedIO:
+ case EfiMemoryMappedIOPortSpace:
+ MemoryMapEntry->Attribute |= EFI_MEMORY_XP;
+ break;
+ case EfiReservedMemoryType:
+ case EfiACPIMemoryNVS:
+ break;
+ }
+
+ MemoryMapEntry = NEXT_MEMORY_DESCRIPTOR (MemoryMapEntry, DescriptorSize);
+ }
+
+ return ;
+}
+
+/**
+ Return the first image record, whose [ImageBase, ImageSize] covered by [Buffer, Length].
+
+ @param Buffer Start Address
+ @param Length Address length
+
+ @return first image record covered by [buffer, length]
+**/
+STATIC
+IMAGE_PROPERTIES_RECORD *
+GetImageRecordByAddress (
+ IN EFI_PHYSICAL_ADDRESS Buffer,
+ IN UINT64 Length
+ )
+{
+ IMAGE_PROPERTIES_RECORD *ImageRecord;
+ LIST_ENTRY *ImageRecordLink;
+ LIST_ENTRY *ImageRecordList;
+
+ ImageRecordList = &mImagePropertiesPrivateData.ImageRecordList;
+
+ for (ImageRecordLink = ImageRecordList->ForwardLink;
+ ImageRecordLink != ImageRecordList;
+ ImageRecordLink = ImageRecordLink->ForwardLink) {
+ ImageRecord = CR (
+ ImageRecordLink,
+ IMAGE_PROPERTIES_RECORD,
+ Link,
+ IMAGE_PROPERTIES_RECORD_SIGNATURE
+ );
+
+ if ((Buffer <= ImageRecord->ImageBase) &&
+ (Buffer + Length >= ImageRecord->ImageBase + ImageRecord->ImageSize)) {
+ return ImageRecord;
+ }
+ }
+
+ return NULL;
+}
+
+/**
+ Set the memory map to new entries, according to one old entry,
+ based upon PE code section and data section in image record
+
+ @param ImageRecord An image record whose [ImageBase, ImageSize] covered
+ by old memory map entry.
+ @param NewRecord A pointer to several new memory map entries.
+ The caller gurantee the buffer size be 1 +
+ (SplitRecordCount * DescriptorSize) calculated
+ below.
+ @param OldRecord A pointer to one old memory map entry.
+ @param DescriptorSize Size, in bytes, of an individual EFI_MEMORY_DESCRIPTOR.
+**/
+STATIC
+UINTN
+SetNewRecord (
+ IN IMAGE_PROPERTIES_RECORD *ImageRecord,
+ IN OUT EFI_MEMORY_DESCRIPTOR *NewRecord,
+ IN EFI_MEMORY_DESCRIPTOR *OldRecord,
+ IN UINTN DescriptorSize
+ )
+{
+ EFI_MEMORY_DESCRIPTOR TempRecord;
+ IMAGE_PROPERTIES_RECORD_CODE_SECTION *ImageRecordCodeSection;
+ LIST_ENTRY *ImageRecordCodeSectionLink;
+ LIST_ENTRY *ImageRecordCodeSectionEndLink;
+ LIST_ENTRY *ImageRecordCodeSectionList;
+ UINTN NewRecordCount;
+ UINT64 PhysicalEnd;
+ UINT64 ImageEnd;
+
+ CopyMem (&TempRecord, OldRecord, sizeof(EFI_MEMORY_DESCRIPTOR));
+ PhysicalEnd = TempRecord.PhysicalStart + EfiPagesToSize(TempRecord.NumberOfPages);
+ NewRecordCount = 0;
+
+ ImageRecordCodeSectionList = &ImageRecord->CodeSegmentList;
+
+ ImageRecordCodeSectionLink = ImageRecordCodeSectionList->ForwardLink;
+ ImageRecordCodeSectionEndLink = ImageRecordCodeSectionList;
+ while (ImageRecordCodeSectionLink != ImageRecordCodeSectionEndLink) {
+ ImageRecordCodeSection = CR (
+ ImageRecordCodeSectionLink,
+ IMAGE_PROPERTIES_RECORD_CODE_SECTION,
+ Link,
+ IMAGE_PROPERTIES_RECORD_CODE_SECTION_SIGNATURE
+ );
+ ImageRecordCodeSectionLink = ImageRecordCodeSectionLink->ForwardLink;
+
+ if (TempRecord.PhysicalStart <= ImageRecordCodeSection->CodeSegmentBase) {
+ //
+ // DATA
+ //
+ NewRecord->Type = TempRecord.Type;
+ NewRecord->PhysicalStart = TempRecord.PhysicalStart;
+ NewRecord->VirtualStart = 0;
+ NewRecord->NumberOfPages = EfiSizeToPages(ImageRecordCodeSection->CodeSegmentBase - NewRecord->PhysicalStart);
+ NewRecord->Attribute = TempRecord.Attribute | EFI_MEMORY_XP;
+ if (NewRecord->NumberOfPages != 0) {
+ NewRecord = NEXT_MEMORY_DESCRIPTOR (NewRecord, DescriptorSize);
+ NewRecordCount ++;
+ }
+
+ //
+ // CODE
+ //
+ NewRecord->Type = TempRecord.Type;
+ NewRecord->PhysicalStart = ImageRecordCodeSection->CodeSegmentBase;
+ NewRecord->VirtualStart = 0;
+ NewRecord->NumberOfPages = EfiSizeToPages(ImageRecordCodeSection->CodeSegmentSize);
+ NewRecord->Attribute = (TempRecord.Attribute & (~EFI_MEMORY_XP)) | EFI_MEMORY_RO;
+ if (NewRecord->NumberOfPages != 0) {
+ NewRecord = NEXT_MEMORY_DESCRIPTOR (NewRecord, DescriptorSize);
+ NewRecordCount ++;
+ }
+
+ TempRecord.PhysicalStart = ImageRecordCodeSection->CodeSegmentBase + EfiPagesToSize (EfiSizeToPages(ImageRecordCodeSection->CodeSegmentSize));
+ TempRecord.NumberOfPages = EfiSizeToPages(PhysicalEnd - TempRecord.PhysicalStart);
+ if (TempRecord.NumberOfPages == 0) {
+ break;
+ }
+ }
+ }
+
+ ImageEnd = ImageRecord->ImageBase + ImageRecord->ImageSize;
+
+ //
+ // Final DATA
+ //
+ if (TempRecord.PhysicalStart < ImageEnd) {
+ NewRecord->Type = TempRecord.Type;
+ NewRecord->PhysicalStart = TempRecord.PhysicalStart;
+ NewRecord->VirtualStart = 0;
+ NewRecord->NumberOfPages = EfiSizeToPages (ImageEnd - TempRecord.PhysicalStart);
+ NewRecord->Attribute = TempRecord.Attribute | EFI_MEMORY_XP;
+ NewRecordCount ++;
+ }
+
+ return NewRecordCount;
+}
+
+/**
+ Return the max number of new splitted entries, according to one old entry,
+ based upon PE code section and data section.
+
+ @param OldRecord A pointer to one old memory map entry.
+
+ @retval 0 no entry need to be splitted.
+ @return the max number of new splitted entries
+**/
+STATIC
+UINTN
+GetMaxSplitRecordCount (
+ IN EFI_MEMORY_DESCRIPTOR *OldRecord
+ )
+{
+ IMAGE_PROPERTIES_RECORD *ImageRecord;
+ UINTN SplitRecordCount;
+ UINT64 PhysicalStart;
+ UINT64 PhysicalEnd;
+
+ SplitRecordCount = 0;
+ PhysicalStart = OldRecord->PhysicalStart;
+ PhysicalEnd = OldRecord->PhysicalStart + EfiPagesToSize(OldRecord->NumberOfPages);
+
+ do {
+ ImageRecord = GetImageRecordByAddress (PhysicalStart, PhysicalEnd - PhysicalStart);
+ if (ImageRecord == NULL) {
+ break;
+ }
+ SplitRecordCount += (2 * ImageRecord->CodeSegmentCount + 1);
+ PhysicalStart = ImageRecord->ImageBase + ImageRecord->ImageSize;
+ } while ((ImageRecord != NULL) && (PhysicalStart < PhysicalEnd));
+
+ if (SplitRecordCount != 0) {
+ SplitRecordCount--;
+ }
+
+ return SplitRecordCount;
+}
+
+/**
+ Split the memory map to new entries, according to one old entry,
+ based upon PE code section and data section.
+
+ @param OldRecord A pointer to one old memory map entry.
+ @param NewRecord A pointer to several new memory map entries.
+ The caller gurantee the buffer size be 1 +
+ (SplitRecordCount * DescriptorSize) calculated
+ below.
+ @param MaxSplitRecordCount The max number of splitted entries
+ @param DescriptorSize Size, in bytes, of an individual EFI_MEMORY_DESCRIPTOR.
+
+ @retval 0 no entry is splitted.
+ @return the real number of splitted record.
+**/
+STATIC
+UINTN
+SplitRecord (
+ IN EFI_MEMORY_DESCRIPTOR *OldRecord,
+ IN OUT EFI_MEMORY_DESCRIPTOR *NewRecord,
+ IN UINTN MaxSplitRecordCount,
+ IN UINTN DescriptorSize
+ )
+{
+ EFI_MEMORY_DESCRIPTOR TempRecord;
+ IMAGE_PROPERTIES_RECORD *ImageRecord;
+ IMAGE_PROPERTIES_RECORD *NewImageRecord;
+ UINT64 PhysicalStart;
+ UINT64 PhysicalEnd;
+ UINTN NewRecordCount;
+ UINTN TotalNewRecordCount;
+ BOOLEAN IsLastRecordData;
+
+ if (MaxSplitRecordCount == 0) {
+ CopyMem (NewRecord, OldRecord, DescriptorSize);
+ return 0;
+ }
+
+ TotalNewRecordCount = 0;
+
+ //
+ // Override previous record
+ //
+ CopyMem (&TempRecord, OldRecord, sizeof(EFI_MEMORY_DESCRIPTOR));
+ PhysicalStart = TempRecord.PhysicalStart;
+ PhysicalEnd = TempRecord.PhysicalStart + EfiPagesToSize(TempRecord.NumberOfPages);
+
+ ImageRecord = NULL;
+ do {
+ NewImageRecord = GetImageRecordByAddress (PhysicalStart, PhysicalEnd - PhysicalStart);
+ if (NewImageRecord == NULL) {
+ //
+ // No more image covered by this range, stop
+ //
+ if ((PhysicalEnd > PhysicalStart) && (ImageRecord != NULL)) {
+ //
+ // If this is still address in this record, need record.
+ //
+ NewRecord = PREVIOUS_MEMORY_DESCRIPTOR (NewRecord, DescriptorSize);
+ IsLastRecordData = FALSE;
+ if ((NewRecord->Attribute & EFI_MEMORY_XP) != 0) {
+ IsLastRecordData = TRUE;
+ }
+ if (IsLastRecordData) {
+ //
+ // Last record is DATA, just merge it.
+ //
+ NewRecord->NumberOfPages = EfiSizeToPages(PhysicalEnd - NewRecord->PhysicalStart);
+ } else {
+ //
+ // Last record is CODE, create a new DATA entry.
+ //
+ NewRecord = NEXT_MEMORY_DESCRIPTOR (NewRecord, DescriptorSize);
+ NewRecord->Type = TempRecord.Type;
+ NewRecord->PhysicalStart = TempRecord.PhysicalStart;
+ NewRecord->VirtualStart = 0;
+ NewRecord->NumberOfPages = TempRecord.NumberOfPages;
+ NewRecord->Attribute = TempRecord.Attribute | EFI_MEMORY_XP;
+ TotalNewRecordCount ++;
+ }
+ }
+ break;
+ }
+ ImageRecord = NewImageRecord;
+
+ //
+ // Set new record
+ //
+ NewRecordCount = SetNewRecord (ImageRecord, NewRecord, &TempRecord, DescriptorSize);
+ TotalNewRecordCount += NewRecordCount;
+ NewRecord = (EFI_MEMORY_DESCRIPTOR *)((UINT8 *)NewRecord + NewRecordCount * DescriptorSize);
+
+ //
+ // Update PhysicalStart, in order to exclude the image buffer already splitted.
+ //
+ PhysicalStart = ImageRecord->ImageBase + ImageRecord->ImageSize;
+ TempRecord.PhysicalStart = PhysicalStart;
+ TempRecord.NumberOfPages = EfiSizeToPages (PhysicalEnd - PhysicalStart);
+ } while ((ImageRecord != NULL) && (PhysicalStart < PhysicalEnd));
+
+ //
+ // The logic in function SplitTable() ensures that TotalNewRecordCount will not be zero if the
+ // code reaches here.
+ //
+ ASSERT (TotalNewRecordCount != 0);
+ return TotalNewRecordCount - 1;
+}
+
+/**
+ Split the original memory map, and add more entries to describe PE code section and data section.
+ This function will set EfiRuntimeServicesData to be EFI_MEMORY_XP.
+ This function will merge entries with same attributes finally.
+
+ NOTE: It assumes PE code/data section are page aligned.
+ NOTE: It assumes enough entry is prepared for new memory map.
+
+ Split table:
+ +---------------+
+ | Record X |
+ +---------------+
+ | Record RtCode |
+ +---------------+
+ | Record Y |
+ +---------------+
+ ==>
+ +---------------+
+ | Record X |
+ +---------------+ ----
+ | Record RtData | |
+ +---------------+ |
+ | Record RtCode | |-> PE/COFF1
+ +---------------+ |
+ | Record RtData | |
+ +---------------+ ----
+ | Record RtData | |
+ +---------------+ |
+ | Record RtCode | |-> PE/COFF2
+ +---------------+ |
+ | Record RtData | |
+ +---------------+ ----
+ | Record Y |
+ +---------------+
+
+ @param MemoryMapSize A pointer to the size, in bytes, of the
+ MemoryMap buffer. On input, this is the size of
+ old MemoryMap before split. The actual buffer
+ size of MemoryMap is MemoryMapSize +
+ (AdditionalRecordCount * DescriptorSize) calculated
+ below. On output, it is the size of new MemoryMap
+ after split.
+ @param MemoryMap A pointer to the buffer in which firmware places
+ the current memory map.
+ @param DescriptorSize Size, in bytes, of an individual EFI_MEMORY_DESCRIPTOR.
+**/
+STATIC
+VOID
+SplitTable (
+ IN OUT UINTN *MemoryMapSize,
+ IN OUT EFI_MEMORY_DESCRIPTOR *MemoryMap,
+ IN UINTN DescriptorSize
+ )
+{
+ INTN IndexOld;
+ INTN IndexNew;
+ UINTN MaxSplitRecordCount;
+ UINTN RealSplitRecordCount;
+ UINTN TotalSplitRecordCount;
+ UINTN AdditionalRecordCount;
+
+ AdditionalRecordCount = (2 * mImagePropertiesPrivateData.CodeSegmentCountMax + 1) * mImagePropertiesPrivateData.ImageRecordCount;
+
+ TotalSplitRecordCount = 0;
+ //
+ // Let old record point to end of valid MemoryMap buffer.
+ //
+ IndexOld = ((*MemoryMapSize) / DescriptorSize) - 1;
+ //
+ // Let new record point to end of full MemoryMap buffer.
+ //
+ IndexNew = ((*MemoryMapSize) / DescriptorSize) - 1 + AdditionalRecordCount;
+ for (; IndexOld >= 0; IndexOld--) {
+ MaxSplitRecordCount = GetMaxSplitRecordCount ((EFI_MEMORY_DESCRIPTOR *)((UINT8 *)MemoryMap + IndexOld * DescriptorSize));
+ //
+ // Split this MemoryMap record
+ //
+ IndexNew -= MaxSplitRecordCount;
+ RealSplitRecordCount = SplitRecord (
+ (EFI_MEMORY_DESCRIPTOR *)((UINT8 *)MemoryMap + IndexOld * DescriptorSize),
+ (EFI_MEMORY_DESCRIPTOR *)((UINT8 *)MemoryMap + IndexNew * DescriptorSize),
+ MaxSplitRecordCount,
+ DescriptorSize
+ );
+ //
+ // Adjust IndexNew according to real split.
+ //
+ CopyMem (
+ ((UINT8 *)MemoryMap + (IndexNew + MaxSplitRecordCount - RealSplitRecordCount) * DescriptorSize),
+ ((UINT8 *)MemoryMap + IndexNew * DescriptorSize),
+ RealSplitRecordCount * DescriptorSize
+ );
+ IndexNew = IndexNew + MaxSplitRecordCount - RealSplitRecordCount;
+ TotalSplitRecordCount += RealSplitRecordCount;
+ IndexNew --;
+ }
+ //
+ // Move all records to the beginning.
+ //
+ CopyMem (
+ MemoryMap,
+ (UINT8 *)MemoryMap + (AdditionalRecordCount - TotalSplitRecordCount) * DescriptorSize,
+ (*MemoryMapSize) + TotalSplitRecordCount * DescriptorSize
+ );
+
+ *MemoryMapSize = (*MemoryMapSize) + DescriptorSize * TotalSplitRecordCount;
+
+ //
+ // Sort from low to high (Just in case)
+ //
+ SortMemoryMap (MemoryMap, *MemoryMapSize, DescriptorSize);
+
+ //
+ // Set RuntimeData to XP
+ //
+ EnforceMemoryMapAttribute (MemoryMap, *MemoryMapSize, DescriptorSize);
+
+ //
+ // Merge same type to save entry size
+ //
+ MergeMemoryMap (MemoryMap, MemoryMapSize, DescriptorSize);
+
+ return ;
+}
+
+/**
+ This function for GetMemoryMap() with properties table capability.
+
+ It calls original GetMemoryMap() to get the original memory map information. Then
+ plus the additional memory map entries for PE Code/Data seperation.
+
+ @param MemoryMapSize A pointer to the size, in bytes, of the
+ MemoryMap buffer. On input, this is the size of
+ the buffer allocated by the caller. On output,
+ it is the size of the buffer returned by the
+ firmware if the buffer was large enough, or the
+ size of the buffer needed to contain the map if
+ the buffer was too small.
+ @param MemoryMap A pointer to the buffer in which firmware places
+ the current memory map.
+ @param MapKey A pointer to the location in which firmware
+ returns the key for the current memory map.
+ @param DescriptorSize A pointer to the location in which firmware
+ returns the size, in bytes, of an individual
+ EFI_MEMORY_DESCRIPTOR.
+ @param DescriptorVersion A pointer to the location in which firmware
+ returns the version number associated with the
+ EFI_MEMORY_DESCRIPTOR.
+
+ @retval EFI_SUCCESS The memory map was returned in the MemoryMap
+ buffer.
+ @retval EFI_BUFFER_TOO_SMALL The MemoryMap buffer was too small. The current
+ buffer size needed to hold the memory map is
+ returned in MemoryMapSize.
+ @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
+
+**/
+EFI_STATUS
+EFIAPI
+CoreGetMemoryMapWithSeparatedImageSection (
+ IN OUT UINTN *MemoryMapSize,
+ IN OUT EFI_MEMORY_DESCRIPTOR *MemoryMap,
+ OUT UINTN *MapKey,
+ OUT UINTN *DescriptorSize,
+ OUT UINT32 *DescriptorVersion
+ )
+{
+ EFI_STATUS Status;
+ UINTN OldMemoryMapSize;
+ UINTN AdditionalRecordCount;
+
+ //
+ // If PE code/data is not aligned, just return.
+ //
+ if (!mMemoryAttributesTableEnable) {
+ return CoreGetMemoryMap (MemoryMapSize, MemoryMap, MapKey, DescriptorSize, DescriptorVersion);
+ }
+
+ if (MemoryMapSize == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ CoreAcquiremMemoryAttributesTableLock ();
+
+ AdditionalRecordCount = (2 * mImagePropertiesPrivateData.CodeSegmentCountMax + 1) * mImagePropertiesPrivateData.ImageRecordCount;
+
+ OldMemoryMapSize = *MemoryMapSize;
+ Status = CoreGetMemoryMap (MemoryMapSize, MemoryMap, MapKey, DescriptorSize, DescriptorVersion);
+ if (Status == EFI_BUFFER_TOO_SMALL) {
+ *MemoryMapSize = *MemoryMapSize + (*DescriptorSize) * AdditionalRecordCount;
+ } else if (Status == EFI_SUCCESS) {
+ ASSERT (MemoryMap != NULL);
+ if (OldMemoryMapSize - *MemoryMapSize < (*DescriptorSize) * AdditionalRecordCount) {
+ *MemoryMapSize = *MemoryMapSize + (*DescriptorSize) * AdditionalRecordCount;
+ //
+ // Need update status to buffer too small
+ //
+ Status = EFI_BUFFER_TOO_SMALL;
+ } else {
+ //
+ // Split PE code/data
+ //
+ SplitTable (MemoryMapSize, MemoryMap, *DescriptorSize);
+ }
+ }
+
+ CoreReleasemMemoryAttributesTableLock ();
+ return Status;
+}
+
+//
+// Below functions are for ImageRecord
+//
+
+/**
+ Set MemoryAttributesTable according to PE/COFF image section alignment.
+
+ @param SectionAlignment PE/COFF section alignment
+**/
+STATIC
+VOID
+SetMemoryAttributesTableSectionAlignment (
+ IN UINT32 SectionAlignment
+ )
+{
+ if (((SectionAlignment & (RUNTIME_PAGE_ALLOCATION_GRANULARITY - 1)) != 0) &&
+ mMemoryAttributesTableEnable) {
+ DEBUG ((DEBUG_VERBOSE, "SetMemoryAttributesTableSectionAlignment - Clear\n"));
+ mMemoryAttributesTableEnable = FALSE;
+ }
+}
+
+/**
+ Swap two code sections in image record.
+
+ @param FirstImageRecordCodeSection first code section in image record
+ @param SecondImageRecordCodeSection second code section in image record
+**/
+STATIC
+VOID
+SwapImageRecordCodeSection (
+ IN IMAGE_PROPERTIES_RECORD_CODE_SECTION *FirstImageRecordCodeSection,
+ IN IMAGE_PROPERTIES_RECORD_CODE_SECTION *SecondImageRecordCodeSection
+ )
+{
+ IMAGE_PROPERTIES_RECORD_CODE_SECTION TempImageRecordCodeSection;
+
+ TempImageRecordCodeSection.CodeSegmentBase = FirstImageRecordCodeSection->CodeSegmentBase;
+ TempImageRecordCodeSection.CodeSegmentSize = FirstImageRecordCodeSection->CodeSegmentSize;
+
+ FirstImageRecordCodeSection->CodeSegmentBase = SecondImageRecordCodeSection->CodeSegmentBase;
+ FirstImageRecordCodeSection->CodeSegmentSize = SecondImageRecordCodeSection->CodeSegmentSize;
+
+ SecondImageRecordCodeSection->CodeSegmentBase = TempImageRecordCodeSection.CodeSegmentBase;
+ SecondImageRecordCodeSection->CodeSegmentSize = TempImageRecordCodeSection.CodeSegmentSize;
+}
+
+/**
+ Sort code section in image record, based upon CodeSegmentBase from low to high.
+
+ @param ImageRecord image record to be sorted
+**/
+VOID
+SortImageRecordCodeSection (
+ IN IMAGE_PROPERTIES_RECORD *ImageRecord
+ )
+{
+ IMAGE_PROPERTIES_RECORD_CODE_SECTION *ImageRecordCodeSection;
+ IMAGE_PROPERTIES_RECORD_CODE_SECTION *NextImageRecordCodeSection;
+ LIST_ENTRY *ImageRecordCodeSectionLink;
+ LIST_ENTRY *NextImageRecordCodeSectionLink;
+ LIST_ENTRY *ImageRecordCodeSectionEndLink;
+ LIST_ENTRY *ImageRecordCodeSectionList;
+
+ ImageRecordCodeSectionList = &ImageRecord->CodeSegmentList;
+
+ ImageRecordCodeSectionLink = ImageRecordCodeSectionList->ForwardLink;
+ NextImageRecordCodeSectionLink = ImageRecordCodeSectionLink->ForwardLink;
+ ImageRecordCodeSectionEndLink = ImageRecordCodeSectionList;
+ while (ImageRecordCodeSectionLink != ImageRecordCodeSectionEndLink) {
+ ImageRecordCodeSection = CR (
+ ImageRecordCodeSectionLink,
+ IMAGE_PROPERTIES_RECORD_CODE_SECTION,
+ Link,
+ IMAGE_PROPERTIES_RECORD_CODE_SECTION_SIGNATURE
+ );
+ while (NextImageRecordCodeSectionLink != ImageRecordCodeSectionEndLink) {
+ NextImageRecordCodeSection = CR (
+ NextImageRecordCodeSectionLink,
+ IMAGE_PROPERTIES_RECORD_CODE_SECTION,
+ Link,
+ IMAGE_PROPERTIES_RECORD_CODE_SECTION_SIGNATURE
+ );
+ if (ImageRecordCodeSection->CodeSegmentBase > NextImageRecordCodeSection->CodeSegmentBase) {
+ SwapImageRecordCodeSection (ImageRecordCodeSection, NextImageRecordCodeSection);
+ }
+ NextImageRecordCodeSectionLink = NextImageRecordCodeSectionLink->ForwardLink;
+ }
+
+ ImageRecordCodeSectionLink = ImageRecordCodeSectionLink->ForwardLink;
+ NextImageRecordCodeSectionLink = ImageRecordCodeSectionLink->ForwardLink;
+ }
+}
+
+/**
+ Check if code section in image record is valid.
+
+ @param ImageRecord image record to be checked
+
+ @retval TRUE image record is valid
+ @retval FALSE image record is invalid
+**/
+BOOLEAN
+IsImageRecordCodeSectionValid (
+ IN IMAGE_PROPERTIES_RECORD *ImageRecord
+ )
+{
+ IMAGE_PROPERTIES_RECORD_CODE_SECTION *ImageRecordCodeSection;
+ IMAGE_PROPERTIES_RECORD_CODE_SECTION *LastImageRecordCodeSection;
+ LIST_ENTRY *ImageRecordCodeSectionLink;
+ LIST_ENTRY *ImageRecordCodeSectionEndLink;
+ LIST_ENTRY *ImageRecordCodeSectionList;
+
+ DEBUG ((DEBUG_VERBOSE, "ImageCode SegmentCount - 0x%x\n", ImageRecord->CodeSegmentCount));
+
+ ImageRecordCodeSectionList = &ImageRecord->CodeSegmentList;
+
+ ImageRecordCodeSectionLink = ImageRecordCodeSectionList->ForwardLink;
+ ImageRecordCodeSectionEndLink = ImageRecordCodeSectionList;
+ LastImageRecordCodeSection = NULL;
+ while (ImageRecordCodeSectionLink != ImageRecordCodeSectionEndLink) {
+ ImageRecordCodeSection = CR (
+ ImageRecordCodeSectionLink,
+ IMAGE_PROPERTIES_RECORD_CODE_SECTION,
+ Link,
+ IMAGE_PROPERTIES_RECORD_CODE_SECTION_SIGNATURE
+ );
+ if (ImageRecordCodeSection->CodeSegmentSize == 0) {
+ return FALSE;
+ }
+ if (ImageRecordCodeSection->CodeSegmentBase < ImageRecord->ImageBase) {
+ return FALSE;
+ }
+ if (ImageRecordCodeSection->CodeSegmentBase >= MAX_ADDRESS - ImageRecordCodeSection->CodeSegmentSize) {
+ return FALSE;
+ }
+ if ((ImageRecordCodeSection->CodeSegmentBase + ImageRecordCodeSection->CodeSegmentSize) > (ImageRecord->ImageBase + ImageRecord->ImageSize)) {
+ return FALSE;
+ }
+ if (LastImageRecordCodeSection != NULL) {
+ if ((LastImageRecordCodeSection->CodeSegmentBase + LastImageRecordCodeSection->CodeSegmentSize) > ImageRecordCodeSection->CodeSegmentBase) {
+ return FALSE;
+ }
+ }
+
+ LastImageRecordCodeSection = ImageRecordCodeSection;
+ ImageRecordCodeSectionLink = ImageRecordCodeSectionLink->ForwardLink;
+ }
+
+ return TRUE;
+}
+
+/**
+ Swap two image records.
+
+ @param FirstImageRecord first image record.
+ @param SecondImageRecord second image record.
+**/
+STATIC
+VOID
+SwapImageRecord (
+ IN IMAGE_PROPERTIES_RECORD *FirstImageRecord,
+ IN IMAGE_PROPERTIES_RECORD *SecondImageRecord
+ )
+{
+ IMAGE_PROPERTIES_RECORD TempImageRecord;
+
+ TempImageRecord.ImageBase = FirstImageRecord->ImageBase;
+ TempImageRecord.ImageSize = FirstImageRecord->ImageSize;
+ TempImageRecord.CodeSegmentCount = FirstImageRecord->CodeSegmentCount;
+
+ FirstImageRecord->ImageBase = SecondImageRecord->ImageBase;
+ FirstImageRecord->ImageSize = SecondImageRecord->ImageSize;
+ FirstImageRecord->CodeSegmentCount = SecondImageRecord->CodeSegmentCount;
+
+ SecondImageRecord->ImageBase = TempImageRecord.ImageBase;
+ SecondImageRecord->ImageSize = TempImageRecord.ImageSize;
+ SecondImageRecord->CodeSegmentCount = TempImageRecord.CodeSegmentCount;
+
+ SwapListEntries (&FirstImageRecord->CodeSegmentList, &SecondImageRecord->CodeSegmentList);
+}
+
+/**
+ Sort image record based upon the ImageBase from low to high.
+**/
+STATIC
+VOID
+SortImageRecord (
+ VOID
+ )
+{
+ IMAGE_PROPERTIES_RECORD *ImageRecord;
+ IMAGE_PROPERTIES_RECORD *NextImageRecord;
+ LIST_ENTRY *ImageRecordLink;
+ LIST_ENTRY *NextImageRecordLink;
+ LIST_ENTRY *ImageRecordEndLink;
+ LIST_ENTRY *ImageRecordList;
+
+ ImageRecordList = &mImagePropertiesPrivateData.ImageRecordList;
+
+ ImageRecordLink = ImageRecordList->ForwardLink;
+ NextImageRecordLink = ImageRecordLink->ForwardLink;
+ ImageRecordEndLink = ImageRecordList;
+ while (ImageRecordLink != ImageRecordEndLink) {
+ ImageRecord = CR (
+ ImageRecordLink,
+ IMAGE_PROPERTIES_RECORD,
+ Link,
+ IMAGE_PROPERTIES_RECORD_SIGNATURE
+ );
+ while (NextImageRecordLink != ImageRecordEndLink) {
+ NextImageRecord = CR (
+ NextImageRecordLink,
+ IMAGE_PROPERTIES_RECORD,
+ Link,
+ IMAGE_PROPERTIES_RECORD_SIGNATURE
+ );
+ if (ImageRecord->ImageBase > NextImageRecord->ImageBase) {
+ SwapImageRecord (ImageRecord, NextImageRecord);
+ }
+ NextImageRecordLink = NextImageRecordLink->ForwardLink;
+ }
+
+ ImageRecordLink = ImageRecordLink->ForwardLink;
+ NextImageRecordLink = ImageRecordLink->ForwardLink;
+ }
+}
+
+/**
+ Insert image record.
+
+ @param RuntimeImage Runtime image information
+**/
+VOID
+InsertImageRecord (
+ IN EFI_RUNTIME_IMAGE_ENTRY *RuntimeImage
+ )
+{
+ VOID *ImageAddress;
+ EFI_IMAGE_DOS_HEADER *DosHdr;
+ UINT32 PeCoffHeaderOffset;
+ UINT32 SectionAlignment;
+ EFI_IMAGE_SECTION_HEADER *Section;
+ EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr;
+ UINT8 *Name;
+ UINTN Index;
+ IMAGE_PROPERTIES_RECORD *ImageRecord;
+ CHAR8 *PdbPointer;
+ IMAGE_PROPERTIES_RECORD_CODE_SECTION *ImageRecordCodeSection;
+
+ DEBUG ((DEBUG_VERBOSE, "InsertImageRecord - 0x%x\n", RuntimeImage));
+ DEBUG ((DEBUG_VERBOSE, "InsertImageRecord - 0x%016lx - 0x%016lx\n", (EFI_PHYSICAL_ADDRESS)(UINTN)RuntimeImage->ImageBase, RuntimeImage->ImageSize));
+
+ if (mMemoryAttributesTableEndOfDxe) {
+ DEBUG ((DEBUG_INFO, "Do not insert runtime image record after EndOfDxe\n"));
+ return ;
+ }
+
+ ImageRecord = AllocatePool (sizeof(*ImageRecord));
+ if (ImageRecord == NULL) {
+ return ;
+ }
+ ImageRecord->Signature = IMAGE_PROPERTIES_RECORD_SIGNATURE;
+
+ DEBUG ((DEBUG_VERBOSE, "ImageRecordCount - 0x%x\n", mImagePropertiesPrivateData.ImageRecordCount));
+
+ //
+ // Step 1: record whole region
+ //
+ ImageRecord->ImageBase = (EFI_PHYSICAL_ADDRESS)(UINTN)RuntimeImage->ImageBase;
+ ImageRecord->ImageSize = RuntimeImage->ImageSize;
+
+ ImageAddress = RuntimeImage->ImageBase;
+
+ PdbPointer = PeCoffLoaderGetPdbPointer ((VOID*) (UINTN) ImageAddress);
+ if (PdbPointer != NULL) {
+ DEBUG ((DEBUG_VERBOSE, " Image - %a\n", PdbPointer));
+ }
+
+ //
+ // Check PE/COFF image
+ //
+ DosHdr = (EFI_IMAGE_DOS_HEADER *) (UINTN) ImageAddress;
+ PeCoffHeaderOffset = 0;
+ if (DosHdr->e_magic == EFI_IMAGE_DOS_SIGNATURE) {
+ PeCoffHeaderOffset = DosHdr->e_lfanew;
+ }
+
+ Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *)((UINT8 *) (UINTN) ImageAddress + PeCoffHeaderOffset);
+ if (Hdr.Pe32->Signature != EFI_IMAGE_NT_SIGNATURE) {
+ DEBUG ((DEBUG_VERBOSE, "Hdr.Pe32->Signature invalid - 0x%x\n", Hdr.Pe32->Signature));
+ // It might be image in SMM.
+ goto Finish;
+ }
+
+ //
+ // Get SectionAlignment
+ //
+ if (Hdr.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
+ SectionAlignment = Hdr.Pe32->OptionalHeader.SectionAlignment;
+ } else {
+ SectionAlignment = Hdr.Pe32Plus->OptionalHeader.SectionAlignment;
+ }
+
+ SetMemoryAttributesTableSectionAlignment (SectionAlignment);
+ if ((SectionAlignment & (RUNTIME_PAGE_ALLOCATION_GRANULARITY - 1)) != 0) {
+ DEBUG ((DEBUG_WARN, "!!!!!!!! InsertImageRecord - Section Alignment(0x%x) is not %dK !!!!!!!!\n",
+ SectionAlignment, RUNTIME_PAGE_ALLOCATION_GRANULARITY >> 10));
+ PdbPointer = PeCoffLoaderGetPdbPointer ((VOID*) (UINTN) ImageAddress);
+ if (PdbPointer != NULL) {
+ DEBUG ((DEBUG_WARN, "!!!!!!!! Image - %a !!!!!!!!\n", PdbPointer));
+ }
+ goto Finish;
+ }
+
+ Section = (EFI_IMAGE_SECTION_HEADER *) (
+ (UINT8 *) (UINTN) ImageAddress +
+ PeCoffHeaderOffset +
+ sizeof(UINT32) +
+ sizeof(EFI_IMAGE_FILE_HEADER) +
+ Hdr.Pe32->FileHeader.SizeOfOptionalHeader
+ );
+ ImageRecord->CodeSegmentCount = 0;
+ InitializeListHead (&ImageRecord->CodeSegmentList);
+ for (Index = 0; Index < Hdr.Pe32->FileHeader.NumberOfSections; Index++) {
+ Name = Section[Index].Name;
+ DEBUG ((
+ DEBUG_VERBOSE,
+ " Section - '%c%c%c%c%c%c%c%c'\n",
+ Name[0],
+ Name[1],
+ Name[2],
+ Name[3],
+ Name[4],
+ Name[5],
+ Name[6],
+ Name[7]
+ ));
+
+ if ((Section[Index].Characteristics & EFI_IMAGE_SCN_CNT_CODE) != 0) {
+ DEBUG ((DEBUG_VERBOSE, " VirtualSize - 0x%08x\n", Section[Index].Misc.VirtualSize));
+ DEBUG ((DEBUG_VERBOSE, " VirtualAddress - 0x%08x\n", Section[Index].VirtualAddress));
+ DEBUG ((DEBUG_VERBOSE, " SizeOfRawData - 0x%08x\n", Section[Index].SizeOfRawData));
+ DEBUG ((DEBUG_VERBOSE, " PointerToRawData - 0x%08x\n", Section[Index].PointerToRawData));
+ DEBUG ((DEBUG_VERBOSE, " PointerToRelocations - 0x%08x\n", Section[Index].PointerToRelocations));
+ DEBUG ((DEBUG_VERBOSE, " PointerToLinenumbers - 0x%08x\n", Section[Index].PointerToLinenumbers));
+ DEBUG ((DEBUG_VERBOSE, " NumberOfRelocations - 0x%08x\n", Section[Index].NumberOfRelocations));
+ DEBUG ((DEBUG_VERBOSE, " NumberOfLinenumbers - 0x%08x\n", Section[Index].NumberOfLinenumbers));
+ DEBUG ((DEBUG_VERBOSE, " Characteristics - 0x%08x\n", Section[Index].Characteristics));
+
+ //
+ // Step 2: record code section
+ //
+ ImageRecordCodeSection = AllocatePool (sizeof(*ImageRecordCodeSection));
+ if (ImageRecordCodeSection == NULL) {
+ return ;
+ }
+ ImageRecordCodeSection->Signature = IMAGE_PROPERTIES_RECORD_CODE_SECTION_SIGNATURE;
+
+ ImageRecordCodeSection->CodeSegmentBase = (UINTN)ImageAddress + Section[Index].VirtualAddress;
+ ImageRecordCodeSection->CodeSegmentSize = Section[Index].SizeOfRawData;
+
+ DEBUG ((DEBUG_VERBOSE, "ImageCode: 0x%016lx - 0x%016lx\n", ImageRecordCodeSection->CodeSegmentBase, ImageRecordCodeSection->CodeSegmentSize));
+
+ InsertTailList (&ImageRecord->CodeSegmentList, &ImageRecordCodeSection->Link);
+ ImageRecord->CodeSegmentCount++;
+ }
+ }
+
+ if (ImageRecord->CodeSegmentCount == 0) {
+ SetMemoryAttributesTableSectionAlignment (1);
+ DEBUG ((DEBUG_ERROR, "!!!!!!!! InsertImageRecord - CodeSegmentCount is 0 !!!!!!!!\n"));
+ PdbPointer = PeCoffLoaderGetPdbPointer ((VOID*) (UINTN) ImageAddress);
+ if (PdbPointer != NULL) {
+ DEBUG ((DEBUG_ERROR, "!!!!!!!! Image - %a !!!!!!!!\n", PdbPointer));
+ }
+ goto Finish;
+ }
+
+ //
+ // Final
+ //
+ SortImageRecordCodeSection (ImageRecord);
+ //
+ // Check overlap all section in ImageBase/Size
+ //
+ if (!IsImageRecordCodeSectionValid (ImageRecord)) {
+ DEBUG ((DEBUG_ERROR, "IsImageRecordCodeSectionValid - FAIL\n"));
+ goto Finish;
+ }
+
+ InsertTailList (&mImagePropertiesPrivateData.ImageRecordList, &ImageRecord->Link);
+ mImagePropertiesPrivateData.ImageRecordCount++;
+
+ if (mImagePropertiesPrivateData.CodeSegmentCountMax < ImageRecord->CodeSegmentCount) {
+ mImagePropertiesPrivateData.CodeSegmentCountMax = ImageRecord->CodeSegmentCount;
+ }
+
+ SortImageRecord ();
+
+Finish:
+ return ;
+}
+
+/**
+ Find image record according to image base and size.
+
+ @param ImageBase Base of PE image
+ @param ImageSize Size of PE image
+
+ @return image record
+**/
+STATIC
+IMAGE_PROPERTIES_RECORD *
+FindImageRecord (
+ IN EFI_PHYSICAL_ADDRESS ImageBase,
+ IN UINT64 ImageSize
+ )
+{
+ IMAGE_PROPERTIES_RECORD *ImageRecord;
+ LIST_ENTRY *ImageRecordLink;
+ LIST_ENTRY *ImageRecordList;
+
+ ImageRecordList = &mImagePropertiesPrivateData.ImageRecordList;
+
+ for (ImageRecordLink = ImageRecordList->ForwardLink;
+ ImageRecordLink != ImageRecordList;
+ ImageRecordLink = ImageRecordLink->ForwardLink) {
+ ImageRecord = CR (
+ ImageRecordLink,
+ IMAGE_PROPERTIES_RECORD,
+ Link,
+ IMAGE_PROPERTIES_RECORD_SIGNATURE
+ );
+
+ if ((ImageBase == ImageRecord->ImageBase) &&
+ (ImageSize == ImageRecord->ImageSize)) {
+ return ImageRecord;
+ }
+ }
+
+ return NULL;
+}
+
+/**
+ Remove Image record.
+
+ @param RuntimeImage Runtime image information
+**/
+VOID
+RemoveImageRecord (
+ IN EFI_RUNTIME_IMAGE_ENTRY *RuntimeImage
+ )
+{
+ IMAGE_PROPERTIES_RECORD *ImageRecord;
+ LIST_ENTRY *CodeSegmentListHead;
+ IMAGE_PROPERTIES_RECORD_CODE_SECTION *ImageRecordCodeSection;
+
+ DEBUG ((DEBUG_VERBOSE, "RemoveImageRecord - 0x%x\n", RuntimeImage));
+ DEBUG ((DEBUG_VERBOSE, "RemoveImageRecord - 0x%016lx - 0x%016lx\n", (EFI_PHYSICAL_ADDRESS)(UINTN)RuntimeImage->ImageBase, RuntimeImage->ImageSize));
+
+ if (mMemoryAttributesTableEndOfDxe) {
+ DEBUG ((DEBUG_INFO, "Do not remove runtime image record after EndOfDxe\n"));
+ return ;
+ }
+
+ ImageRecord = FindImageRecord ((EFI_PHYSICAL_ADDRESS)(UINTN)RuntimeImage->ImageBase, RuntimeImage->ImageSize);
+ if (ImageRecord == NULL) {
+ DEBUG ((DEBUG_ERROR, "!!!!!!!! ImageRecord not found !!!!!!!!\n"));
+ return ;
+ }
+
+ CodeSegmentListHead = &ImageRecord->CodeSegmentList;
+ while (!IsListEmpty (CodeSegmentListHead)) {
+ ImageRecordCodeSection = CR (
+ CodeSegmentListHead->ForwardLink,
+ IMAGE_PROPERTIES_RECORD_CODE_SECTION,
+ Link,
+ IMAGE_PROPERTIES_RECORD_CODE_SECTION_SIGNATURE
+ );
+ RemoveEntryList (&ImageRecordCodeSection->Link);
+ FreePool (ImageRecordCodeSection);
+ }
+
+ RemoveEntryList (&ImageRecord->Link);
+ FreePool (ImageRecord);
+ mImagePropertiesPrivateData.ImageRecordCount--;
+}
diff --git a/roms/edk2/MdeModulePkg/Core/Dxe/Misc/MemoryProtection.c b/roms/edk2/MdeModulePkg/Core/Dxe/Misc/MemoryProtection.c
new file mode 100644
index 000000000..7d1daf0b1
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Core/Dxe/Misc/MemoryProtection.c
@@ -0,0 +1,1284 @@
+/** @file
+ UEFI Memory Protection support.
+
+ If the UEFI image is page aligned, the image code section is set to read only
+ and the image data section is set to non-executable.
+
+ 1) This policy is applied for all UEFI image including boot service driver,
+ runtime driver or application.
+ 2) This policy is applied only if the UEFI image meets the page alignment
+ requirement.
+ 3) This policy is applied only if the Source UEFI image matches the
+ PcdImageProtectionPolicy definition.
+ 4) This policy is not applied to the non-PE image region.
+
+ The DxeCore calls CpuArchProtocol->SetMemoryAttributes() to protect
+ the image. If the CpuArch protocol is not installed yet, the DxeCore
+ enqueues the protection request. Once the CpuArch is installed, the
+ DxeCore dequeues the protection request and applies policy.
+
+ Once the image is unloaded, the protection is removed automatically.
+
+Copyright (c) 2017 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <PiDxe.h>
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/DxeServicesTableLib.h>
+#include <Library/DebugLib.h>
+#include <Library/UefiLib.h>
+
+#include <Guid/EventGroup.h>
+#include <Guid/MemoryAttributesTable.h>
+
+#include <Protocol/FirmwareVolume2.h>
+#include <Protocol/SimpleFileSystem.h>
+
+#include "DxeMain.h"
+#include "Mem/HeapGuard.h"
+
+//
+// Image type definitions
+//
+#define IMAGE_UNKNOWN 0x00000001
+#define IMAGE_FROM_FV 0x00000002
+
+//
+// Protection policy bit definition
+//
+#define DO_NOT_PROTECT 0x00000000
+#define PROTECT_IF_ALIGNED_ELSE_ALLOW 0x00000001
+
+#define MEMORY_TYPE_OS_RESERVED_MIN 0x80000000
+#define MEMORY_TYPE_OEM_RESERVED_MIN 0x70000000
+
+#define PREVIOUS_MEMORY_DESCRIPTOR(MemoryDescriptor, Size) \
+ ((EFI_MEMORY_DESCRIPTOR *)((UINT8 *)(MemoryDescriptor) - (Size)))
+
+UINT32 mImageProtectionPolicy;
+
+extern LIST_ENTRY mGcdMemorySpaceMap;
+
+STATIC LIST_ENTRY mProtectedImageRecordList;
+
+/**
+ Sort code section in image record, based upon CodeSegmentBase from low to high.
+
+ @param ImageRecord image record to be sorted
+**/
+VOID
+SortImageRecordCodeSection (
+ IN IMAGE_PROPERTIES_RECORD *ImageRecord
+ );
+
+/**
+ Check if code section in image record is valid.
+
+ @param ImageRecord image record to be checked
+
+ @retval TRUE image record is valid
+ @retval FALSE image record is invalid
+**/
+BOOLEAN
+IsImageRecordCodeSectionValid (
+ IN IMAGE_PROPERTIES_RECORD *ImageRecord
+ );
+
+/**
+ Get the image type.
+
+ @param[in] File This is a pointer to the device path of the file that is
+ being dispatched.
+
+ @return UINT32 Image Type
+**/
+UINT32
+GetImageType (
+ IN CONST EFI_DEVICE_PATH_PROTOCOL *File
+ )
+{
+ EFI_STATUS Status;
+ EFI_HANDLE DeviceHandle;
+ EFI_DEVICE_PATH_PROTOCOL *TempDevicePath;
+
+ if (File == NULL) {
+ return IMAGE_UNKNOWN;
+ }
+
+ //
+ // First check to see if File is from a Firmware Volume
+ //
+ DeviceHandle = NULL;
+ TempDevicePath = (EFI_DEVICE_PATH_PROTOCOL *) File;
+ Status = gBS->LocateDevicePath (
+ &gEfiFirmwareVolume2ProtocolGuid,
+ &TempDevicePath,
+ &DeviceHandle
+ );
+ if (!EFI_ERROR (Status)) {
+ Status = gBS->OpenProtocol (
+ DeviceHandle,
+ &gEfiFirmwareVolume2ProtocolGuid,
+ NULL,
+ NULL,
+ NULL,
+ EFI_OPEN_PROTOCOL_TEST_PROTOCOL
+ );
+ if (!EFI_ERROR (Status)) {
+ return IMAGE_FROM_FV;
+ }
+ }
+ return IMAGE_UNKNOWN;
+}
+
+/**
+ Get UEFI image protection policy based upon image type.
+
+ @param[in] ImageType The UEFI image type
+
+ @return UEFI image protection policy
+**/
+UINT32
+GetProtectionPolicyFromImageType (
+ IN UINT32 ImageType
+ )
+{
+ if ((ImageType & mImageProtectionPolicy) == 0) {
+ return DO_NOT_PROTECT;
+ } else {
+ return PROTECT_IF_ALIGNED_ELSE_ALLOW;
+ }
+}
+
+/**
+ Get UEFI image protection policy based upon loaded image device path.
+
+ @param[in] LoadedImage The loaded image protocol
+ @param[in] LoadedImageDevicePath The loaded image device path protocol
+
+ @return UEFI image protection policy
+**/
+UINT32
+GetUefiImageProtectionPolicy (
+ IN EFI_LOADED_IMAGE_PROTOCOL *LoadedImage,
+ IN EFI_DEVICE_PATH_PROTOCOL *LoadedImageDevicePath
+ )
+{
+ BOOLEAN InSmm;
+ UINT32 ImageType;
+ UINT32 ProtectionPolicy;
+
+ //
+ // Check SMM
+ //
+ InSmm = FALSE;
+ if (gSmmBase2 != NULL) {
+ gSmmBase2->InSmm (gSmmBase2, &InSmm);
+ }
+ if (InSmm) {
+ return FALSE;
+ }
+
+ //
+ // Check DevicePath
+ //
+ if (LoadedImage == gDxeCoreLoadedImage) {
+ ImageType = IMAGE_FROM_FV;
+ } else {
+ ImageType = GetImageType (LoadedImageDevicePath);
+ }
+ ProtectionPolicy = GetProtectionPolicyFromImageType (ImageType);
+ return ProtectionPolicy;
+}
+
+
+/**
+ Set UEFI image memory attributes.
+
+ @param[in] BaseAddress Specified start address
+ @param[in] Length Specified length
+ @param[in] Attributes Specified attributes
+**/
+VOID
+SetUefiImageMemoryAttributes (
+ IN UINT64 BaseAddress,
+ IN UINT64 Length,
+ IN UINT64 Attributes
+ )
+{
+ EFI_STATUS Status;
+ EFI_GCD_MEMORY_SPACE_DESCRIPTOR Descriptor;
+ UINT64 FinalAttributes;
+
+ Status = CoreGetMemorySpaceDescriptor(BaseAddress, &Descriptor);
+ ASSERT_EFI_ERROR(Status);
+
+ FinalAttributes = (Descriptor.Attributes & EFI_CACHE_ATTRIBUTE_MASK) | (Attributes & EFI_MEMORY_ATTRIBUTE_MASK);
+
+ DEBUG ((DEBUG_INFO, "SetUefiImageMemoryAttributes - 0x%016lx - 0x%016lx (0x%016lx)\n", BaseAddress, Length, FinalAttributes));
+
+ ASSERT(gCpu != NULL);
+ gCpu->SetMemoryAttributes (gCpu, BaseAddress, Length, FinalAttributes);
+}
+
+/**
+ Set UEFI image protection attributes.
+
+ @param[in] ImageRecord A UEFI image record
+**/
+VOID
+SetUefiImageProtectionAttributes (
+ IN IMAGE_PROPERTIES_RECORD *ImageRecord
+ )
+{
+ IMAGE_PROPERTIES_RECORD_CODE_SECTION *ImageRecordCodeSection;
+ LIST_ENTRY *ImageRecordCodeSectionLink;
+ LIST_ENTRY *ImageRecordCodeSectionEndLink;
+ LIST_ENTRY *ImageRecordCodeSectionList;
+ UINT64 CurrentBase;
+ UINT64 ImageEnd;
+
+ ImageRecordCodeSectionList = &ImageRecord->CodeSegmentList;
+
+ CurrentBase = ImageRecord->ImageBase;
+ ImageEnd = ImageRecord->ImageBase + ImageRecord->ImageSize;
+
+ ImageRecordCodeSectionLink = ImageRecordCodeSectionList->ForwardLink;
+ ImageRecordCodeSectionEndLink = ImageRecordCodeSectionList;
+ while (ImageRecordCodeSectionLink != ImageRecordCodeSectionEndLink) {
+ ImageRecordCodeSection = CR (
+ ImageRecordCodeSectionLink,
+ IMAGE_PROPERTIES_RECORD_CODE_SECTION,
+ Link,
+ IMAGE_PROPERTIES_RECORD_CODE_SECTION_SIGNATURE
+ );
+ ImageRecordCodeSectionLink = ImageRecordCodeSectionLink->ForwardLink;
+
+ ASSERT (CurrentBase <= ImageRecordCodeSection->CodeSegmentBase);
+ if (CurrentBase < ImageRecordCodeSection->CodeSegmentBase) {
+ //
+ // DATA
+ //
+ SetUefiImageMemoryAttributes (
+ CurrentBase,
+ ImageRecordCodeSection->CodeSegmentBase - CurrentBase,
+ EFI_MEMORY_XP
+ );
+ }
+ //
+ // CODE
+ //
+ SetUefiImageMemoryAttributes (
+ ImageRecordCodeSection->CodeSegmentBase,
+ ImageRecordCodeSection->CodeSegmentSize,
+ EFI_MEMORY_RO
+ );
+ CurrentBase = ImageRecordCodeSection->CodeSegmentBase + ImageRecordCodeSection->CodeSegmentSize;
+ }
+ //
+ // Last DATA
+ //
+ ASSERT (CurrentBase <= ImageEnd);
+ if (CurrentBase < ImageEnd) {
+ //
+ // DATA
+ //
+ SetUefiImageMemoryAttributes (
+ CurrentBase,
+ ImageEnd - CurrentBase,
+ EFI_MEMORY_XP
+ );
+ }
+ return ;
+}
+
+/**
+ Return if the PE image section is aligned.
+
+ @param[in] SectionAlignment PE/COFF section alignment
+ @param[in] MemoryType PE/COFF image memory type
+
+ @retval TRUE The PE image section is aligned.
+ @retval FALSE The PE image section is not aligned.
+**/
+BOOLEAN
+IsMemoryProtectionSectionAligned (
+ IN UINT32 SectionAlignment,
+ IN EFI_MEMORY_TYPE MemoryType
+ )
+{
+ UINT32 PageAlignment;
+
+ switch (MemoryType) {
+ case EfiRuntimeServicesCode:
+ case EfiACPIMemoryNVS:
+ PageAlignment = RUNTIME_PAGE_ALLOCATION_GRANULARITY;
+ break;
+ case EfiRuntimeServicesData:
+ case EfiACPIReclaimMemory:
+ ASSERT (FALSE);
+ PageAlignment = RUNTIME_PAGE_ALLOCATION_GRANULARITY;
+ break;
+ case EfiBootServicesCode:
+ case EfiLoaderCode:
+ case EfiReservedMemoryType:
+ PageAlignment = EFI_PAGE_SIZE;
+ break;
+ default:
+ ASSERT (FALSE);
+ PageAlignment = EFI_PAGE_SIZE;
+ break;
+ }
+
+ if ((SectionAlignment & (PageAlignment - 1)) != 0) {
+ return FALSE;
+ } else {
+ return TRUE;
+ }
+}
+
+/**
+ Free Image record.
+
+ @param[in] ImageRecord A UEFI image record
+**/
+VOID
+FreeImageRecord (
+ IN IMAGE_PROPERTIES_RECORD *ImageRecord
+ )
+{
+ LIST_ENTRY *CodeSegmentListHead;
+ IMAGE_PROPERTIES_RECORD_CODE_SECTION *ImageRecordCodeSection;
+
+ CodeSegmentListHead = &ImageRecord->CodeSegmentList;
+ while (!IsListEmpty (CodeSegmentListHead)) {
+ ImageRecordCodeSection = CR (
+ CodeSegmentListHead->ForwardLink,
+ IMAGE_PROPERTIES_RECORD_CODE_SECTION,
+ Link,
+ IMAGE_PROPERTIES_RECORD_CODE_SECTION_SIGNATURE
+ );
+ RemoveEntryList (&ImageRecordCodeSection->Link);
+ FreePool (ImageRecordCodeSection);
+ }
+
+ if (ImageRecord->Link.ForwardLink != NULL) {
+ RemoveEntryList (&ImageRecord->Link);
+ }
+ FreePool (ImageRecord);
+}
+
+/**
+ Protect UEFI PE/COFF image.
+
+ @param[in] LoadedImage The loaded image protocol
+ @param[in] LoadedImageDevicePath The loaded image device path protocol
+**/
+VOID
+ProtectUefiImage (
+ IN EFI_LOADED_IMAGE_PROTOCOL *LoadedImage,
+ IN EFI_DEVICE_PATH_PROTOCOL *LoadedImageDevicePath
+ )
+{
+ VOID *ImageAddress;
+ EFI_IMAGE_DOS_HEADER *DosHdr;
+ UINT32 PeCoffHeaderOffset;
+ UINT32 SectionAlignment;
+ EFI_IMAGE_SECTION_HEADER *Section;
+ EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr;
+ UINT8 *Name;
+ UINTN Index;
+ IMAGE_PROPERTIES_RECORD *ImageRecord;
+ CHAR8 *PdbPointer;
+ IMAGE_PROPERTIES_RECORD_CODE_SECTION *ImageRecordCodeSection;
+ BOOLEAN IsAligned;
+ UINT32 ProtectionPolicy;
+
+ DEBUG ((DEBUG_INFO, "ProtectUefiImageCommon - 0x%x\n", LoadedImage));
+ DEBUG ((DEBUG_INFO, " - 0x%016lx - 0x%016lx\n", (EFI_PHYSICAL_ADDRESS)(UINTN)LoadedImage->ImageBase, LoadedImage->ImageSize));
+
+ if (gCpu == NULL) {
+ return ;
+ }
+
+ ProtectionPolicy = GetUefiImageProtectionPolicy (LoadedImage, LoadedImageDevicePath);
+ switch (ProtectionPolicy) {
+ case DO_NOT_PROTECT:
+ return ;
+ case PROTECT_IF_ALIGNED_ELSE_ALLOW:
+ break;
+ default:
+ ASSERT(FALSE);
+ return ;
+ }
+
+ ImageRecord = AllocateZeroPool (sizeof(*ImageRecord));
+ if (ImageRecord == NULL) {
+ return ;
+ }
+ ImageRecord->Signature = IMAGE_PROPERTIES_RECORD_SIGNATURE;
+
+ //
+ // Step 1: record whole region
+ //
+ ImageRecord->ImageBase = (EFI_PHYSICAL_ADDRESS)(UINTN)LoadedImage->ImageBase;
+ ImageRecord->ImageSize = LoadedImage->ImageSize;
+
+ ImageAddress = LoadedImage->ImageBase;
+
+ PdbPointer = PeCoffLoaderGetPdbPointer ((VOID*) (UINTN) ImageAddress);
+ if (PdbPointer != NULL) {
+ DEBUG ((DEBUG_VERBOSE, " Image - %a\n", PdbPointer));
+ }
+
+ //
+ // Check PE/COFF image
+ //
+ DosHdr = (EFI_IMAGE_DOS_HEADER *) (UINTN) ImageAddress;
+ PeCoffHeaderOffset = 0;
+ if (DosHdr->e_magic == EFI_IMAGE_DOS_SIGNATURE) {
+ PeCoffHeaderOffset = DosHdr->e_lfanew;
+ }
+
+ Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *)((UINT8 *) (UINTN) ImageAddress + PeCoffHeaderOffset);
+ if (Hdr.Pe32->Signature != EFI_IMAGE_NT_SIGNATURE) {
+ DEBUG ((DEBUG_VERBOSE, "Hdr.Pe32->Signature invalid - 0x%x\n", Hdr.Pe32->Signature));
+ // It might be image in SMM.
+ goto Finish;
+ }
+
+ //
+ // Get SectionAlignment
+ //
+ if (Hdr.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
+ SectionAlignment = Hdr.Pe32->OptionalHeader.SectionAlignment;
+ } else {
+ SectionAlignment = Hdr.Pe32Plus->OptionalHeader.SectionAlignment;
+ }
+
+ IsAligned = IsMemoryProtectionSectionAligned (SectionAlignment, LoadedImage->ImageCodeType);
+ if (!IsAligned) {
+ DEBUG ((DEBUG_VERBOSE, "!!!!!!!! ProtectUefiImageCommon - Section Alignment(0x%x) is incorrect !!!!!!!!\n",
+ SectionAlignment));
+ PdbPointer = PeCoffLoaderGetPdbPointer ((VOID*) (UINTN) ImageAddress);
+ if (PdbPointer != NULL) {
+ DEBUG ((DEBUG_VERBOSE, "!!!!!!!! Image - %a !!!!!!!!\n", PdbPointer));
+ }
+ goto Finish;
+ }
+
+ Section = (EFI_IMAGE_SECTION_HEADER *) (
+ (UINT8 *) (UINTN) ImageAddress +
+ PeCoffHeaderOffset +
+ sizeof(UINT32) +
+ sizeof(EFI_IMAGE_FILE_HEADER) +
+ Hdr.Pe32->FileHeader.SizeOfOptionalHeader
+ );
+ ImageRecord->CodeSegmentCount = 0;
+ InitializeListHead (&ImageRecord->CodeSegmentList);
+ for (Index = 0; Index < Hdr.Pe32->FileHeader.NumberOfSections; Index++) {
+ Name = Section[Index].Name;
+ DEBUG ((
+ DEBUG_VERBOSE,
+ " Section - '%c%c%c%c%c%c%c%c'\n",
+ Name[0],
+ Name[1],
+ Name[2],
+ Name[3],
+ Name[4],
+ Name[5],
+ Name[6],
+ Name[7]
+ ));
+
+ //
+ // Instead of assuming that a PE/COFF section of type EFI_IMAGE_SCN_CNT_CODE
+ // can always be mapped read-only, classify a section as a code section only
+ // if it has the executable attribute set and the writable attribute cleared.
+ //
+ // This adheres more closely to the PE/COFF spec, and avoids issues with
+ // Linux OS loaders that may consist of a single read/write/execute section.
+ //
+ if ((Section[Index].Characteristics & (EFI_IMAGE_SCN_MEM_WRITE | EFI_IMAGE_SCN_MEM_EXECUTE)) == EFI_IMAGE_SCN_MEM_EXECUTE) {
+ DEBUG ((DEBUG_VERBOSE, " VirtualSize - 0x%08x\n", Section[Index].Misc.VirtualSize));
+ DEBUG ((DEBUG_VERBOSE, " VirtualAddress - 0x%08x\n", Section[Index].VirtualAddress));
+ DEBUG ((DEBUG_VERBOSE, " SizeOfRawData - 0x%08x\n", Section[Index].SizeOfRawData));
+ DEBUG ((DEBUG_VERBOSE, " PointerToRawData - 0x%08x\n", Section[Index].PointerToRawData));
+ DEBUG ((DEBUG_VERBOSE, " PointerToRelocations - 0x%08x\n", Section[Index].PointerToRelocations));
+ DEBUG ((DEBUG_VERBOSE, " PointerToLinenumbers - 0x%08x\n", Section[Index].PointerToLinenumbers));
+ DEBUG ((DEBUG_VERBOSE, " NumberOfRelocations - 0x%08x\n", Section[Index].NumberOfRelocations));
+ DEBUG ((DEBUG_VERBOSE, " NumberOfLinenumbers - 0x%08x\n", Section[Index].NumberOfLinenumbers));
+ DEBUG ((DEBUG_VERBOSE, " Characteristics - 0x%08x\n", Section[Index].Characteristics));
+
+ //
+ // Step 2: record code section
+ //
+ ImageRecordCodeSection = AllocatePool (sizeof(*ImageRecordCodeSection));
+ if (ImageRecordCodeSection == NULL) {
+ return ;
+ }
+ ImageRecordCodeSection->Signature = IMAGE_PROPERTIES_RECORD_CODE_SECTION_SIGNATURE;
+
+ ImageRecordCodeSection->CodeSegmentBase = (UINTN)ImageAddress + Section[Index].VirtualAddress;
+ ImageRecordCodeSection->CodeSegmentSize = ALIGN_VALUE(Section[Index].SizeOfRawData, SectionAlignment);
+
+ DEBUG ((DEBUG_VERBOSE, "ImageCode: 0x%016lx - 0x%016lx\n", ImageRecordCodeSection->CodeSegmentBase, ImageRecordCodeSection->CodeSegmentSize));
+
+ InsertTailList (&ImageRecord->CodeSegmentList, &ImageRecordCodeSection->Link);
+ ImageRecord->CodeSegmentCount++;
+ }
+ }
+
+ if (ImageRecord->CodeSegmentCount == 0) {
+ //
+ // If a UEFI executable consists of a single read+write+exec PE/COFF
+ // section, that isn't actually an error. The image can be launched
+ // alright, only image protection cannot be applied to it fully.
+ //
+ // One example that elicits this is (some) Linux kernels (with the EFI stub
+ // of course).
+ //
+ DEBUG ((DEBUG_WARN, "!!!!!!!! ProtectUefiImageCommon - CodeSegmentCount is 0 !!!!!!!!\n"));
+ PdbPointer = PeCoffLoaderGetPdbPointer ((VOID*) (UINTN) ImageAddress);
+ if (PdbPointer != NULL) {
+ DEBUG ((DEBUG_WARN, "!!!!!!!! Image - %a !!!!!!!!\n", PdbPointer));
+ }
+ goto Finish;
+ }
+
+ //
+ // Final
+ //
+ SortImageRecordCodeSection (ImageRecord);
+ //
+ // Check overlap all section in ImageBase/Size
+ //
+ if (!IsImageRecordCodeSectionValid (ImageRecord)) {
+ DEBUG ((DEBUG_ERROR, "IsImageRecordCodeSectionValid - FAIL\n"));
+ goto Finish;
+ }
+
+ //
+ // Round up the ImageSize, some CPU arch may return EFI_UNSUPPORTED if ImageSize is not aligned.
+ // Given that the loader always allocates full pages, we know the space after the image is not used.
+ //
+ ImageRecord->ImageSize = ALIGN_VALUE(LoadedImage->ImageSize, EFI_PAGE_SIZE);
+
+ //
+ // CPU ARCH present. Update memory attribute directly.
+ //
+ SetUefiImageProtectionAttributes (ImageRecord);
+
+ //
+ // Record the image record in the list so we can undo the protections later
+ //
+ InsertTailList (&mProtectedImageRecordList, &ImageRecord->Link);
+
+Finish:
+ return ;
+}
+
+/**
+ Unprotect UEFI image.
+
+ @param[in] LoadedImage The loaded image protocol
+ @param[in] LoadedImageDevicePath The loaded image device path protocol
+**/
+VOID
+UnprotectUefiImage (
+ IN EFI_LOADED_IMAGE_PROTOCOL *LoadedImage,
+ IN EFI_DEVICE_PATH_PROTOCOL *LoadedImageDevicePath
+ )
+{
+ IMAGE_PROPERTIES_RECORD *ImageRecord;
+ LIST_ENTRY *ImageRecordLink;
+
+ if (PcdGet32(PcdImageProtectionPolicy) != 0) {
+ for (ImageRecordLink = mProtectedImageRecordList.ForwardLink;
+ ImageRecordLink != &mProtectedImageRecordList;
+ ImageRecordLink = ImageRecordLink->ForwardLink) {
+ ImageRecord = CR (
+ ImageRecordLink,
+ IMAGE_PROPERTIES_RECORD,
+ Link,
+ IMAGE_PROPERTIES_RECORD_SIGNATURE
+ );
+
+ if (ImageRecord->ImageBase == (EFI_PHYSICAL_ADDRESS)(UINTN)LoadedImage->ImageBase) {
+ SetUefiImageMemoryAttributes (ImageRecord->ImageBase,
+ ImageRecord->ImageSize,
+ 0);
+ FreeImageRecord (ImageRecord);
+ return;
+ }
+ }
+ }
+}
+
+/**
+ Return the EFI memory permission attribute associated with memory
+ type 'MemoryType' under the configured DXE memory protection policy.
+
+ @param MemoryType Memory type.
+**/
+STATIC
+UINT64
+GetPermissionAttributeForMemoryType (
+ IN EFI_MEMORY_TYPE MemoryType
+ )
+{
+ UINT64 TestBit;
+
+ if ((UINT32)MemoryType >= MEMORY_TYPE_OS_RESERVED_MIN) {
+ TestBit = BIT63;
+ } else if ((UINT32)MemoryType >= MEMORY_TYPE_OEM_RESERVED_MIN) {
+ TestBit = BIT62;
+ } else {
+ TestBit = LShiftU64 (1, MemoryType);
+ }
+
+ if ((PcdGet64 (PcdDxeNxMemoryProtectionPolicy) & TestBit) != 0) {
+ return EFI_MEMORY_XP;
+ } else {
+ return 0;
+ }
+}
+
+/**
+ Sort memory map entries based upon PhysicalStart, from low to high.
+
+ @param MemoryMap A pointer to the buffer in which firmware places
+ the current memory map.
+ @param MemoryMapSize Size, in bytes, of the MemoryMap buffer.
+ @param DescriptorSize Size, in bytes, of an individual EFI_MEMORY_DESCRIPTOR.
+**/
+STATIC
+VOID
+SortMemoryMap (
+ IN OUT EFI_MEMORY_DESCRIPTOR *MemoryMap,
+ IN UINTN MemoryMapSize,
+ IN UINTN DescriptorSize
+ )
+{
+ EFI_MEMORY_DESCRIPTOR *MemoryMapEntry;
+ EFI_MEMORY_DESCRIPTOR *NextMemoryMapEntry;
+ EFI_MEMORY_DESCRIPTOR *MemoryMapEnd;
+ EFI_MEMORY_DESCRIPTOR TempMemoryMap;
+
+ MemoryMapEntry = MemoryMap;
+ NextMemoryMapEntry = NEXT_MEMORY_DESCRIPTOR (MemoryMapEntry, DescriptorSize);
+ MemoryMapEnd = (EFI_MEMORY_DESCRIPTOR *) ((UINT8 *) MemoryMap + MemoryMapSize);
+ while (MemoryMapEntry < MemoryMapEnd) {
+ while (NextMemoryMapEntry < MemoryMapEnd) {
+ if (MemoryMapEntry->PhysicalStart > NextMemoryMapEntry->PhysicalStart) {
+ CopyMem (&TempMemoryMap, MemoryMapEntry, sizeof(EFI_MEMORY_DESCRIPTOR));
+ CopyMem (MemoryMapEntry, NextMemoryMapEntry, sizeof(EFI_MEMORY_DESCRIPTOR));
+ CopyMem (NextMemoryMapEntry, &TempMemoryMap, sizeof(EFI_MEMORY_DESCRIPTOR));
+ }
+
+ NextMemoryMapEntry = NEXT_MEMORY_DESCRIPTOR (NextMemoryMapEntry, DescriptorSize);
+ }
+
+ MemoryMapEntry = NEXT_MEMORY_DESCRIPTOR (MemoryMapEntry, DescriptorSize);
+ NextMemoryMapEntry = NEXT_MEMORY_DESCRIPTOR (MemoryMapEntry, DescriptorSize);
+ }
+}
+
+/**
+ Merge adjacent memory map entries if they use the same memory protection policy
+
+ @param[in, out] MemoryMap A pointer to the buffer in which firmware places
+ the current memory map.
+ @param[in, out] MemoryMapSize A pointer to the size, in bytes, of the
+ MemoryMap buffer. On input, this is the size of
+ the current memory map. On output,
+ it is the size of new memory map after merge.
+ @param[in] DescriptorSize Size, in bytes, of an individual EFI_MEMORY_DESCRIPTOR.
+**/
+STATIC
+VOID
+MergeMemoryMapForProtectionPolicy (
+ IN OUT EFI_MEMORY_DESCRIPTOR *MemoryMap,
+ IN OUT UINTN *MemoryMapSize,
+ IN UINTN DescriptorSize
+ )
+{
+ EFI_MEMORY_DESCRIPTOR *MemoryMapEntry;
+ EFI_MEMORY_DESCRIPTOR *MemoryMapEnd;
+ UINT64 MemoryBlockLength;
+ EFI_MEMORY_DESCRIPTOR *NewMemoryMapEntry;
+ EFI_MEMORY_DESCRIPTOR *NextMemoryMapEntry;
+ UINT64 Attributes;
+
+ SortMemoryMap (MemoryMap, *MemoryMapSize, DescriptorSize);
+
+ MemoryMapEntry = MemoryMap;
+ NewMemoryMapEntry = MemoryMap;
+ MemoryMapEnd = (EFI_MEMORY_DESCRIPTOR *) ((UINT8 *) MemoryMap + *MemoryMapSize);
+ while ((UINTN)MemoryMapEntry < (UINTN)MemoryMapEnd) {
+ CopyMem (NewMemoryMapEntry, MemoryMapEntry, sizeof(EFI_MEMORY_DESCRIPTOR));
+ NextMemoryMapEntry = NEXT_MEMORY_DESCRIPTOR (MemoryMapEntry, DescriptorSize);
+
+ do {
+ MemoryBlockLength = (UINT64) (EFI_PAGES_TO_SIZE((UINTN)MemoryMapEntry->NumberOfPages));
+ Attributes = GetPermissionAttributeForMemoryType (MemoryMapEntry->Type);
+
+ if (((UINTN)NextMemoryMapEntry < (UINTN)MemoryMapEnd) &&
+ Attributes == GetPermissionAttributeForMemoryType (NextMemoryMapEntry->Type) &&
+ ((MemoryMapEntry->PhysicalStart + MemoryBlockLength) == NextMemoryMapEntry->PhysicalStart)) {
+ MemoryMapEntry->NumberOfPages += NextMemoryMapEntry->NumberOfPages;
+ if (NewMemoryMapEntry != MemoryMapEntry) {
+ NewMemoryMapEntry->NumberOfPages += NextMemoryMapEntry->NumberOfPages;
+ }
+
+ NextMemoryMapEntry = NEXT_MEMORY_DESCRIPTOR (NextMemoryMapEntry, DescriptorSize);
+ continue;
+ } else {
+ MemoryMapEntry = PREVIOUS_MEMORY_DESCRIPTOR (NextMemoryMapEntry, DescriptorSize);
+ break;
+ }
+ } while (TRUE);
+
+ MemoryMapEntry = NEXT_MEMORY_DESCRIPTOR (MemoryMapEntry, DescriptorSize);
+ NewMemoryMapEntry = NEXT_MEMORY_DESCRIPTOR (NewMemoryMapEntry, DescriptorSize);
+ }
+
+ *MemoryMapSize = (UINTN)NewMemoryMapEntry - (UINTN)MemoryMap;
+
+ return ;
+}
+
+
+/**
+ Remove exec permissions from all regions whose type is identified by
+ PcdDxeNxMemoryProtectionPolicy.
+**/
+STATIC
+VOID
+InitializeDxeNxMemoryProtectionPolicy (
+ VOID
+ )
+{
+ UINTN MemoryMapSize;
+ UINTN MapKey;
+ UINTN DescriptorSize;
+ UINT32 DescriptorVersion;
+ EFI_MEMORY_DESCRIPTOR *MemoryMap;
+ EFI_MEMORY_DESCRIPTOR *MemoryMapEntry;
+ EFI_MEMORY_DESCRIPTOR *MemoryMapEnd;
+ EFI_STATUS Status;
+ UINT64 Attributes;
+ LIST_ENTRY *Link;
+ EFI_GCD_MAP_ENTRY *Entry;
+ EFI_PEI_HOB_POINTERS Hob;
+ EFI_HOB_MEMORY_ALLOCATION *MemoryHob;
+ EFI_PHYSICAL_ADDRESS StackBase;
+
+ //
+ // Get the EFI memory map.
+ //
+ MemoryMapSize = 0;
+ MemoryMap = NULL;
+
+ Status = gBS->GetMemoryMap (
+ &MemoryMapSize,
+ MemoryMap,
+ &MapKey,
+ &DescriptorSize,
+ &DescriptorVersion
+ );
+ ASSERT (Status == EFI_BUFFER_TOO_SMALL);
+ do {
+ MemoryMap = (EFI_MEMORY_DESCRIPTOR *) AllocatePool (MemoryMapSize);
+ ASSERT (MemoryMap != NULL);
+ Status = gBS->GetMemoryMap (
+ &MemoryMapSize,
+ MemoryMap,
+ &MapKey,
+ &DescriptorSize,
+ &DescriptorVersion
+ );
+ if (EFI_ERROR (Status)) {
+ FreePool (MemoryMap);
+ }
+ } while (Status == EFI_BUFFER_TOO_SMALL);
+ ASSERT_EFI_ERROR (Status);
+
+ StackBase = 0;
+ if (PcdGetBool (PcdCpuStackGuard)) {
+ //
+ // Get the base of stack from Hob.
+ //
+ Hob.Raw = GetHobList ();
+ while ((Hob.Raw = GetNextHob (EFI_HOB_TYPE_MEMORY_ALLOCATION, Hob.Raw)) != NULL) {
+ MemoryHob = Hob.MemoryAllocation;
+ if (CompareGuid(&gEfiHobMemoryAllocStackGuid, &MemoryHob->AllocDescriptor.Name)) {
+ DEBUG ((
+ DEBUG_INFO,
+ "%a: StackBase = 0x%016lx StackSize = 0x%016lx\n",
+ __FUNCTION__,
+ MemoryHob->AllocDescriptor.MemoryBaseAddress,
+ MemoryHob->AllocDescriptor.MemoryLength
+ ));
+
+ StackBase = MemoryHob->AllocDescriptor.MemoryBaseAddress;
+ //
+ // Ensure the base of the stack is page-size aligned.
+ //
+ ASSERT ((StackBase & EFI_PAGE_MASK) == 0);
+ break;
+ }
+ Hob.Raw = GET_NEXT_HOB (Hob);
+ }
+
+ //
+ // Ensure the base of stack can be found from Hob when stack guard is
+ // enabled.
+ //
+ ASSERT (StackBase != 0);
+ }
+
+ DEBUG ((
+ DEBUG_INFO,
+ "%a: applying strict permissions to active memory regions\n",
+ __FUNCTION__
+ ));
+
+ MergeMemoryMapForProtectionPolicy (MemoryMap, &MemoryMapSize, DescriptorSize);
+
+ MemoryMapEntry = MemoryMap;
+ MemoryMapEnd = (EFI_MEMORY_DESCRIPTOR *) ((UINT8 *) MemoryMap + MemoryMapSize);
+ while ((UINTN) MemoryMapEntry < (UINTN) MemoryMapEnd) {
+
+ Attributes = GetPermissionAttributeForMemoryType (MemoryMapEntry->Type);
+ if (Attributes != 0) {
+ SetUefiImageMemoryAttributes (
+ MemoryMapEntry->PhysicalStart,
+ LShiftU64 (MemoryMapEntry->NumberOfPages, EFI_PAGE_SHIFT),
+ Attributes);
+
+ //
+ // Add EFI_MEMORY_RP attribute for page 0 if NULL pointer detection is
+ // enabled.
+ //
+ if (MemoryMapEntry->PhysicalStart == 0 &&
+ PcdGet8 (PcdNullPointerDetectionPropertyMask) != 0) {
+
+ ASSERT (MemoryMapEntry->NumberOfPages > 0);
+ SetUefiImageMemoryAttributes (
+ 0,
+ EFI_PAGES_TO_SIZE (1),
+ EFI_MEMORY_RP | Attributes);
+ }
+
+ //
+ // Add EFI_MEMORY_RP attribute for the first page of the stack if stack
+ // guard is enabled.
+ //
+ if (StackBase != 0 &&
+ (StackBase >= MemoryMapEntry->PhysicalStart &&
+ StackBase < MemoryMapEntry->PhysicalStart +
+ LShiftU64 (MemoryMapEntry->NumberOfPages, EFI_PAGE_SHIFT)) &&
+ PcdGetBool (PcdCpuStackGuard)) {
+
+ SetUefiImageMemoryAttributes (
+ StackBase,
+ EFI_PAGES_TO_SIZE (1),
+ EFI_MEMORY_RP | Attributes);
+ }
+
+ }
+ MemoryMapEntry = NEXT_MEMORY_DESCRIPTOR (MemoryMapEntry, DescriptorSize);
+ }
+ FreePool (MemoryMap);
+
+ //
+ // Apply the policy for RAM regions that we know are present and
+ // accessible, but have not been added to the UEFI memory map (yet).
+ //
+ if (GetPermissionAttributeForMemoryType (EfiConventionalMemory) != 0) {
+ DEBUG ((
+ DEBUG_INFO,
+ "%a: applying strict permissions to inactive memory regions\n",
+ __FUNCTION__
+ ));
+
+ CoreAcquireGcdMemoryLock ();
+
+ Link = mGcdMemorySpaceMap.ForwardLink;
+ while (Link != &mGcdMemorySpaceMap) {
+
+ Entry = CR (Link, EFI_GCD_MAP_ENTRY, Link, EFI_GCD_MAP_SIGNATURE);
+
+ if (Entry->GcdMemoryType == EfiGcdMemoryTypeReserved &&
+ Entry->EndAddress < MAX_ADDRESS &&
+ (Entry->Capabilities & (EFI_MEMORY_PRESENT | EFI_MEMORY_INITIALIZED | EFI_MEMORY_TESTED)) ==
+ (EFI_MEMORY_PRESENT | EFI_MEMORY_INITIALIZED)) {
+
+ Attributes = GetPermissionAttributeForMemoryType (EfiConventionalMemory) |
+ (Entry->Attributes & EFI_CACHE_ATTRIBUTE_MASK);
+
+ DEBUG ((DEBUG_INFO,
+ "Untested GCD memory space region: - 0x%016lx - 0x%016lx (0x%016lx)\n",
+ Entry->BaseAddress, Entry->EndAddress - Entry->BaseAddress + 1,
+ Attributes));
+
+ ASSERT(gCpu != NULL);
+ gCpu->SetMemoryAttributes (gCpu, Entry->BaseAddress,
+ Entry->EndAddress - Entry->BaseAddress + 1, Attributes);
+ }
+
+ Link = Link->ForwardLink;
+ }
+ CoreReleaseGcdMemoryLock ();
+ }
+}
+
+
+/**
+ A notification for CPU_ARCH protocol.
+
+ @param[in] Event Event whose notification function is being invoked.
+ @param[in] Context Pointer to the notification function's context,
+ which is implementation-dependent.
+
+**/
+VOID
+EFIAPI
+MemoryProtectionCpuArchProtocolNotify (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ EFI_STATUS Status;
+ EFI_LOADED_IMAGE_PROTOCOL *LoadedImage;
+ EFI_DEVICE_PATH_PROTOCOL *LoadedImageDevicePath;
+ UINTN NoHandles;
+ EFI_HANDLE *HandleBuffer;
+ UINTN Index;
+
+ DEBUG ((DEBUG_INFO, "MemoryProtectionCpuArchProtocolNotify:\n"));
+ Status = CoreLocateProtocol (&gEfiCpuArchProtocolGuid, NULL, (VOID **)&gCpu);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ //
+ // Apply the memory protection policy on non-BScode/RTcode regions.
+ //
+ if (PcdGet64 (PcdDxeNxMemoryProtectionPolicy) != 0) {
+ InitializeDxeNxMemoryProtectionPolicy ();
+ }
+
+ //
+ // Call notify function meant for Heap Guard.
+ //
+ HeapGuardCpuArchProtocolNotify ();
+
+ if (mImageProtectionPolicy == 0) {
+ goto Done;
+ }
+
+ Status = gBS->LocateHandleBuffer (
+ ByProtocol,
+ &gEfiLoadedImageProtocolGuid,
+ NULL,
+ &NoHandles,
+ &HandleBuffer
+ );
+ if (EFI_ERROR (Status) && (NoHandles == 0)) {
+ goto Done;
+ }
+
+ for (Index = 0; Index < NoHandles; Index++) {
+ Status = gBS->HandleProtocol (
+ HandleBuffer[Index],
+ &gEfiLoadedImageProtocolGuid,
+ (VOID **)&LoadedImage
+ );
+ if (EFI_ERROR(Status)) {
+ continue;
+ }
+ Status = gBS->HandleProtocol (
+ HandleBuffer[Index],
+ &gEfiLoadedImageDevicePathProtocolGuid,
+ (VOID **)&LoadedImageDevicePath
+ );
+ if (EFI_ERROR(Status)) {
+ LoadedImageDevicePath = NULL;
+ }
+
+ ProtectUefiImage (LoadedImage, LoadedImageDevicePath);
+ }
+ FreePool (HandleBuffer);
+
+Done:
+ CoreCloseEvent (Event);
+}
+
+/**
+ ExitBootServices Callback function for memory protection.
+**/
+VOID
+MemoryProtectionExitBootServicesCallback (
+ VOID
+ )
+{
+ EFI_RUNTIME_IMAGE_ENTRY *RuntimeImage;
+ LIST_ENTRY *Link;
+
+ //
+ // We need remove the RT protection, because RT relocation need write code segment
+ // at SetVirtualAddressMap(). We cannot assume OS/Loader has taken over page table at that time.
+ //
+ // Firmware does not own page tables after ExitBootServices(), so the OS would
+ // have to relax protection of RT code pages across SetVirtualAddressMap(), or
+ // delay setting protections on RT code pages until after SetVirtualAddressMap().
+ // OS may set protection on RT based upon EFI_MEMORY_ATTRIBUTES_TABLE later.
+ //
+ if (mImageProtectionPolicy != 0) {
+ for (Link = gRuntime->ImageHead.ForwardLink; Link != &gRuntime->ImageHead; Link = Link->ForwardLink) {
+ RuntimeImage = BASE_CR (Link, EFI_RUNTIME_IMAGE_ENTRY, Link);
+ SetUefiImageMemoryAttributes ((UINT64)(UINTN)RuntimeImage->ImageBase, ALIGN_VALUE(RuntimeImage->ImageSize, EFI_PAGE_SIZE), 0);
+ }
+ }
+}
+
+/**
+ Disable NULL pointer detection after EndOfDxe. This is a workaround resort in
+ order to skip unfixable NULL pointer access issues detected in OptionROM or
+ boot loaders.
+
+ @param[in] Event The Event this notify function registered to.
+ @param[in] Context Pointer to the context data registered to the Event.
+**/
+VOID
+EFIAPI
+DisableNullDetectionAtTheEndOfDxe (
+ EFI_EVENT Event,
+ VOID *Context
+ )
+{
+ EFI_STATUS Status;
+ EFI_GCD_MEMORY_SPACE_DESCRIPTOR Desc;
+
+ DEBUG ((DEBUG_INFO, "DisableNullDetectionAtTheEndOfDxe(): start\r\n"));
+ //
+ // Disable NULL pointer detection by enabling first 4K page
+ //
+ Status = CoreGetMemorySpaceDescriptor (0, &Desc);
+ ASSERT_EFI_ERROR (Status);
+
+ if ((Desc.Capabilities & EFI_MEMORY_RP) == 0) {
+ Status = CoreSetMemorySpaceCapabilities (
+ 0,
+ EFI_PAGE_SIZE,
+ Desc.Capabilities | EFI_MEMORY_RP
+ );
+ ASSERT_EFI_ERROR (Status);
+ }
+
+ Status = CoreSetMemorySpaceAttributes (
+ 0,
+ EFI_PAGE_SIZE,
+ Desc.Attributes & ~EFI_MEMORY_RP
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Page 0 might have be allocated to avoid misuses. Free it here anyway.
+ //
+ CoreFreePages (0, 1);
+
+ CoreCloseEvent (Event);
+ DEBUG ((DEBUG_INFO, "DisableNullDetectionAtTheEndOfDxe(): end\r\n"));
+
+ return;
+}
+
+/**
+ Initialize Memory Protection support.
+**/
+VOID
+EFIAPI
+CoreInitializeMemoryProtection (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ EFI_EVENT Event;
+ EFI_EVENT EndOfDxeEvent;
+ VOID *Registration;
+
+ mImageProtectionPolicy = PcdGet32(PcdImageProtectionPolicy);
+
+ InitializeListHead (&mProtectedImageRecordList);
+
+ //
+ // Sanity check the PcdDxeNxMemoryProtectionPolicy setting:
+ // - code regions should have no EFI_MEMORY_XP attribute
+ // - EfiConventionalMemory and EfiBootServicesData should use the
+ // same attribute
+ //
+ ASSERT ((GetPermissionAttributeForMemoryType (EfiBootServicesCode) & EFI_MEMORY_XP) == 0);
+ ASSERT ((GetPermissionAttributeForMemoryType (EfiRuntimeServicesCode) & EFI_MEMORY_XP) == 0);
+ ASSERT ((GetPermissionAttributeForMemoryType (EfiLoaderCode) & EFI_MEMORY_XP) == 0);
+ ASSERT (GetPermissionAttributeForMemoryType (EfiBootServicesData) ==
+ GetPermissionAttributeForMemoryType (EfiConventionalMemory));
+
+ Status = CoreCreateEvent (
+ EVT_NOTIFY_SIGNAL,
+ TPL_CALLBACK,
+ MemoryProtectionCpuArchProtocolNotify,
+ NULL,
+ &Event
+ );
+ ASSERT_EFI_ERROR(Status);
+
+ //
+ // Register for protocol notifactions on this event
+ //
+ Status = CoreRegisterProtocolNotify (
+ &gEfiCpuArchProtocolGuid,
+ Event,
+ &Registration
+ );
+ ASSERT_EFI_ERROR(Status);
+
+ //
+ // Register a callback to disable NULL pointer detection at EndOfDxe
+ //
+ if ((PcdGet8 (PcdNullPointerDetectionPropertyMask) & (BIT0|BIT7))
+ == (BIT0|BIT7)) {
+ Status = CoreCreateEventEx (
+ EVT_NOTIFY_SIGNAL,
+ TPL_NOTIFY,
+ DisableNullDetectionAtTheEndOfDxe,
+ NULL,
+ &gEfiEndOfDxeEventGroupGuid,
+ &EndOfDxeEvent
+ );
+ ASSERT_EFI_ERROR (Status);
+ }
+
+ return ;
+}
+
+/**
+ Returns whether we are currently executing in SMM mode.
+**/
+STATIC
+BOOLEAN
+IsInSmm (
+ VOID
+ )
+{
+ BOOLEAN InSmm;
+
+ InSmm = FALSE;
+ if (gSmmBase2 != NULL) {
+ gSmmBase2->InSmm (gSmmBase2, &InSmm);
+ }
+ return InSmm;
+}
+
+/**
+ Manage memory permission attributes on a memory range, according to the
+ configured DXE memory protection policy.
+
+ @param OldType The old memory type of the range
+ @param NewType The new memory type of the range
+ @param Memory The base address of the range
+ @param Length The size of the range (in bytes)
+
+ @return EFI_SUCCESS If we are executing in SMM mode. No permission attributes
+ are updated in this case
+ @return EFI_SUCCESS If the the CPU arch protocol is not installed yet
+ @return EFI_SUCCESS If no DXE memory protection policy has been configured
+ @return EFI_SUCCESS If OldType and NewType use the same permission attributes
+ @return other Return value of gCpu->SetMemoryAttributes()
+
+**/
+EFI_STATUS
+EFIAPI
+ApplyMemoryProtectionPolicy (
+ IN EFI_MEMORY_TYPE OldType,
+ IN EFI_MEMORY_TYPE NewType,
+ IN EFI_PHYSICAL_ADDRESS Memory,
+ IN UINT64 Length
+ )
+{
+ UINT64 OldAttributes;
+ UINT64 NewAttributes;
+
+ //
+ // The policy configured in PcdDxeNxMemoryProtectionPolicy
+ // does not apply to allocations performed in SMM mode.
+ //
+ if (IsInSmm ()) {
+ return EFI_SUCCESS;
+ }
+
+ //
+ // If the CPU arch protocol is not installed yet, we cannot manage memory
+ // permission attributes, and it is the job of the driver that installs this
+ // protocol to set the permissions on existing allocations.
+ //
+ if (gCpu == NULL) {
+ return EFI_SUCCESS;
+ }
+
+ //
+ // Check if a DXE memory protection policy has been configured
+ //
+ if (PcdGet64 (PcdDxeNxMemoryProtectionPolicy) == 0) {
+ return EFI_SUCCESS;
+ }
+
+ //
+ // Don't overwrite Guard pages, which should be the first and/or last page,
+ // if any.
+ //
+ if (IsHeapGuardEnabled (GUARD_HEAP_TYPE_PAGE|GUARD_HEAP_TYPE_POOL)) {
+ if (IsGuardPage (Memory)) {
+ Memory += EFI_PAGE_SIZE;
+ Length -= EFI_PAGE_SIZE;
+ if (Length == 0) {
+ return EFI_SUCCESS;
+ }
+ }
+
+ if (IsGuardPage (Memory + Length - EFI_PAGE_SIZE)) {
+ Length -= EFI_PAGE_SIZE;
+ if (Length == 0) {
+ return EFI_SUCCESS;
+ }
+ }
+ }
+
+ //
+ // Update the executable permissions according to the DXE memory
+ // protection policy, but only if
+ // - the policy is different between the old and the new type, or
+ // - this is a newly added region (OldType == EfiMaxMemoryType)
+ //
+ NewAttributes = GetPermissionAttributeForMemoryType (NewType);
+
+ if (OldType != EfiMaxMemoryType) {
+ OldAttributes = GetPermissionAttributeForMemoryType (OldType);
+ if (OldAttributes == NewAttributes) {
+ // policy is the same between OldType and NewType
+ return EFI_SUCCESS;
+ }
+ } else if (NewAttributes == 0) {
+ // newly added region of a type that does not require protection
+ return EFI_SUCCESS;
+ }
+
+ return gCpu->SetMemoryAttributes (gCpu, Memory, Length, NewAttributes);
+}
diff --git a/roms/edk2/MdeModulePkg/Core/Dxe/Misc/SetWatchdogTimer.c b/roms/edk2/MdeModulePkg/Core/Dxe/Misc/SetWatchdogTimer.c
new file mode 100644
index 000000000..a9bf1284f
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Core/Dxe/Misc/SetWatchdogTimer.c
@@ -0,0 +1,66 @@
+/** @file
+ UEFI Miscellaneous boot Services SetWatchdogTimer service implementation
+
+Copyright (c) 2006 - 2008, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "DxeMain.h"
+
+#define WATCHDOG_TIMER_CALIBRATE_PER_SECOND 10000000
+
+/**
+ Sets the system's watchdog timer.
+
+ @param Timeout The number of seconds to set the watchdog timer to.
+ A value of zero disables the timer.
+ @param WatchdogCode The numeric code to log on a watchdog timer timeout
+ event. The firmware reserves codes 0x0000 to 0xFFFF.
+ Loaders and operating systems may use other timeout
+ codes.
+ @param DataSize The size, in bytes, of WatchdogData.
+ @param WatchdogData A data buffer that includes a Null-terminated Unicode
+ string, optionally followed by additional binary data.
+ The string is a description that the call may use to
+ further indicate the reason to be logged with a
+ watchdog event.
+
+ @return EFI_SUCCESS Timeout has been set
+ @return EFI_NOT_AVAILABLE_YET WatchdogTimer is not available yet
+ @return EFI_UNSUPPORTED System does not have a timer (currently not used)
+ @return EFI_DEVICE_ERROR Could not complete due to hardware error
+
+**/
+EFI_STATUS
+EFIAPI
+CoreSetWatchdogTimer (
+ IN UINTN Timeout,
+ IN UINT64 WatchdogCode,
+ IN UINTN DataSize,
+ IN CHAR16 *WatchdogData OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+
+ //
+ // Check our architectural protocol
+ //
+ if (gWatchdogTimer == NULL) {
+ return EFI_NOT_AVAILABLE_YET;
+ }
+
+ //
+ // Attempt to set the timeout
+ //
+ Status = gWatchdogTimer->SetTimerPeriod (gWatchdogTimer, MultU64x32 (Timeout, WATCHDOG_TIMER_CALIBRATE_PER_SECOND));
+
+ //
+ // Check for errors
+ //
+ if (EFI_ERROR (Status)) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ return EFI_SUCCESS;
+}
diff --git a/roms/edk2/MdeModulePkg/Core/Dxe/Misc/Stall.c b/roms/edk2/MdeModulePkg/Core/Dxe/Misc/Stall.c
new file mode 100644
index 000000000..6ecc708ac
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Core/Dxe/Misc/Stall.c
@@ -0,0 +1,107 @@
+/** @file
+ UEFI Miscellaneous boot Services Stall service implementation
+
+Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+//
+// Include statements
+//
+
+#include "DxeMain.h"
+
+/**
+ Internal worker function to call the Metronome Architectural Protocol for
+ the number of ticks specified by the UINT64 Counter value. WaitForTick()
+ service of the Metronome Architectural Protocol uses a UINT32 for the number
+ of ticks to wait, so this function loops when Counter is larger than 0xffffffff.
+
+ @param Counter Number of ticks to wait.
+
+**/
+VOID
+CoreInternalWaitForTick (
+ IN UINT64 Counter
+ )
+{
+ while (RShiftU64 (Counter, 32) > 0) {
+ gMetronome->WaitForTick (gMetronome, 0xffffffff);
+ Counter -= 0xffffffff;
+ }
+ gMetronome->WaitForTick (gMetronome, (UINT32)Counter);
+}
+
+/**
+ Introduces a fine-grained stall.
+
+ @param Microseconds The number of microseconds to stall execution.
+
+ @retval EFI_SUCCESS Execution was stalled for at least the requested
+ amount of microseconds.
+ @retval EFI_NOT_AVAILABLE_YET gMetronome is not available yet
+
+**/
+EFI_STATUS
+EFIAPI
+CoreStall (
+ IN UINTN Microseconds
+ )
+{
+ UINT64 Counter;
+ UINT32 Remainder;
+ UINTN Index;
+
+ if (gMetronome == NULL) {
+ return EFI_NOT_AVAILABLE_YET;
+ }
+
+ //
+ // Counter = Microseconds * 10 / gMetronome->TickPeriod
+ // 0x1999999999999999 = (2^64 - 1) / 10
+ //
+ if ((UINT64) Microseconds > 0x1999999999999999ULL) {
+ //
+ // Microseconds is too large to multiple by 10 first. Perform the divide
+ // operation first and loop 10 times to avoid 64-bit math overflow.
+ //
+ Counter = DivU64x32Remainder (
+ Microseconds,
+ gMetronome->TickPeriod,
+ &Remainder
+ );
+ for (Index = 0; Index < 10; Index++) {
+ CoreInternalWaitForTick (Counter);
+ }
+
+ if (Remainder != 0) {
+ //
+ // If Remainder was not zero, then normally, Counter would be rounded
+ // up by 1 tick. In this case, since a loop for 10 counts was used
+ // to emulate the multiply by 10 operation, Counter needs to be rounded
+ // up by 10 counts.
+ //
+ CoreInternalWaitForTick (10);
+ }
+ } else {
+ //
+ // Calculate the number of ticks by dividing the number of microseconds by
+ // the TickPeriod. Calculation is based on 100ns unit.
+ //
+ Counter = DivU64x32Remainder (
+ MultU64x32 (Microseconds, 10),
+ gMetronome->TickPeriod,
+ &Remainder
+ );
+ if (Remainder != 0) {
+ //
+ // If Remainder is not zero, then round Counter up by one tick.
+ //
+ Counter++;
+ }
+ CoreInternalWaitForTick (Counter);
+ }
+
+ return EFI_SUCCESS;
+}
diff --git a/roms/edk2/MdeModulePkg/Core/Dxe/SectionExtraction/CoreSectionExtraction.c b/roms/edk2/MdeModulePkg/Core/Dxe/SectionExtraction/CoreSectionExtraction.c
new file mode 100644
index 000000000..d678166db
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Core/Dxe/SectionExtraction/CoreSectionExtraction.c
@@ -0,0 +1,1601 @@
+/** @file
+ Section Extraction Protocol implementation.
+
+ Stream database is implemented as a linked list of section streams,
+ where each stream contains a linked list of children, which may be leaves or
+ encapsulations.
+
+ Children that are encapsulations generate new stream entries
+ when they are created. Streams can also be created by calls to
+ SEP->OpenSectionStream().
+
+ The database is only created far enough to return the requested data from
+ any given stream, or to determine that the requested data is not found.
+
+ If a GUIDed encapsulation is encountered, there are three possiblilites.
+
+ 1) A support protocol is found, in which the stream is simply processed with
+ the support protocol.
+
+ 2) A support protocol is not found, but the data is available to be read
+ without processing. In this case, the database is built up through the
+ recursions to return the data, and a RPN event is set that will enable
+ the stream in question to be refreshed if and when the required section
+ extraction protocol is published.This insures the AuthenticationStatus
+ does not become stale in the cache.
+
+ 3) A support protocol is not found, and the data is not available to be read
+ without it. This results in EFI_PROTOCOL_ERROR.
+
+Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "DxeMain.h"
+
+//
+// Local defines and typedefs
+//
+#define CORE_SECTION_CHILD_SIGNATURE SIGNATURE_32('S','X','C','S')
+#define CHILD_SECTION_NODE_FROM_LINK(Node) \
+ CR (Node, CORE_SECTION_CHILD_NODE, Link, CORE_SECTION_CHILD_SIGNATURE)
+
+typedef struct {
+ UINT32 Signature;
+ LIST_ENTRY Link;
+ UINT32 Type;
+ UINT32 Size;
+ //
+ // StreamBase + OffsetInStream == pointer to section header in stream. The
+ // stream base is always known when walking the sections within.
+ //
+ UINT32 OffsetInStream;
+ //
+ // Then EncapsulatedStreamHandle below is always 0 if the section is NOT an
+ // encapsulating section. Otherwise, it contains the stream handle
+ // of the encapsulated stream. This handle is ALWAYS produced any time an
+ // encapsulating child is encountered, irrespective of whether the
+ // encapsulated stream is processed further.
+ //
+ UINTN EncapsulatedStreamHandle;
+ EFI_GUID *EncapsulationGuid;
+ //
+ // If the section REQUIRES an extraction protocol, register for RPN
+ // when the required GUIDed extraction protocol becomes available.
+ //
+ EFI_EVENT Event;
+} CORE_SECTION_CHILD_NODE;
+
+#define CORE_SECTION_STREAM_SIGNATURE SIGNATURE_32('S','X','S','S')
+#define STREAM_NODE_FROM_LINK(Node) \
+ CR (Node, CORE_SECTION_STREAM_NODE, Link, CORE_SECTION_STREAM_SIGNATURE)
+
+typedef struct {
+ UINT32 Signature;
+ LIST_ENTRY Link;
+ UINTN StreamHandle;
+ UINT8 *StreamBuffer;
+ UINTN StreamLength;
+ LIST_ENTRY Children;
+ //
+ // Authentication status is from GUIDed encapsulations.
+ //
+ UINT32 AuthenticationStatus;
+} CORE_SECTION_STREAM_NODE;
+
+#define NULL_STREAM_HANDLE 0
+
+typedef struct {
+ CORE_SECTION_CHILD_NODE *ChildNode;
+ CORE_SECTION_STREAM_NODE *ParentStream;
+ VOID *Registration;
+} RPN_EVENT_CONTEXT;
+
+
+/**
+ The ExtractSection() function processes the input section and
+ allocates a buffer from the pool in which it returns the section
+ contents. If the section being extracted contains
+ authentication information (the section's
+ GuidedSectionHeader.Attributes field has the
+ EFI_GUIDED_SECTION_AUTH_STATUS_VALID bit set), the values
+ returned in AuthenticationStatus must reflect the results of
+ the authentication operation. Depending on the algorithm and
+ size of the encapsulated data, the time that is required to do
+ a full authentication may be prohibitively long for some
+ classes of systems. To indicate this, use
+ EFI_SECURITY_POLICY_PROTOCOL_GUID, which may be published by
+ the security policy driver (see the Platform Initialization
+ Driver Execution Environment Core Interface Specification for
+ more details and the GUID definition). If the
+ EFI_SECURITY_POLICY_PROTOCOL_GUID exists in the handle
+ database, then, if possible, full authentication should be
+ skipped and the section contents simply returned in the
+ OutputBuffer. In this case, the
+ EFI_AUTH_STATUS_PLATFORM_OVERRIDE bit AuthenticationStatus
+ must be set on return. ExtractSection() is callable only from
+ TPL_NOTIFY and below. Behavior of ExtractSection() at any
+ EFI_TPL above TPL_NOTIFY is undefined. Type EFI_TPL is
+ defined in RaiseTPL() in the UEFI 2.0 specification.
+
+
+ @param This Indicates the
+ EFI_GUIDED_SECTION_EXTRACTION_PROTOCOL instance.
+ @param InputSection Buffer containing the input GUIDed section
+ to be processed. OutputBuffer OutputBuffer
+ is allocated from boot services pool
+ memory and contains the new section
+ stream. The caller is responsible for
+ freeing this buffer.
+ @param OutputBuffer *OutputBuffer is allocated from boot services
+ pool memory and contains the new section stream.
+ The caller is responsible for freeing this buffer.
+ @param OutputSize A pointer to a caller-allocated UINTN in
+ which the size of OutputBuffer allocation
+ is stored. If the function returns
+ anything other than EFI_SUCCESS, the value
+ of OutputSize is undefined.
+
+ @param AuthenticationStatus A pointer to a caller-allocated
+ UINT32 that indicates the
+ authentication status of the
+ output buffer. If the input
+ section's
+ GuidedSectionHeader.Attributes
+ field has the
+ EFI_GUIDED_SECTION_AUTH_STATUS_VAL
+ bit as clear, AuthenticationStatus
+ must return zero. Both local bits
+ (19:16) and aggregate bits (3:0)
+ in AuthenticationStatus are
+ returned by ExtractSection().
+ These bits reflect the status of
+ the extraction operation. The bit
+ pattern in both regions must be
+ the same, as the local and
+ aggregate authentication statuses
+ have equivalent meaning at this
+ level. If the function returns
+ anything other than EFI_SUCCESS,
+ the value of AuthenticationStatus
+ is undefined.
+
+
+ @retval EFI_SUCCESS The InputSection was successfully
+ processed and the section contents were
+ returned.
+
+ @retval EFI_OUT_OF_RESOURCES The system has insufficient
+ resources to process the
+ request.
+
+ @retval EFI_INVALID_PARAMETER The GUID in InputSection does
+ not match this instance of the
+ GUIDed Section Extraction
+ Protocol.
+
+**/
+EFI_STATUS
+EFIAPI
+CustomGuidedSectionExtract (
+ IN CONST EFI_GUIDED_SECTION_EXTRACTION_PROTOCOL *This,
+ IN CONST VOID *InputSection,
+ OUT VOID **OutputBuffer,
+ OUT UINTN *OutputSize,
+ OUT UINT32 *AuthenticationStatus
+ );
+
+//
+// Module globals
+//
+LIST_ENTRY mStreamRoot = INITIALIZE_LIST_HEAD_VARIABLE (mStreamRoot);
+
+EFI_HANDLE mSectionExtractionHandle = NULL;
+
+EFI_GUIDED_SECTION_EXTRACTION_PROTOCOL mCustomGuidedSectionExtractionProtocol = {
+ CustomGuidedSectionExtract
+};
+
+
+/**
+ Entry point of the section extraction code. Initializes an instance of the
+ section extraction interface and installs it on a new handle.
+
+ @param ImageHandle A handle for the image that is initializing this driver
+ @param SystemTable A pointer to the EFI system table
+
+ @retval EFI_SUCCESS Driver initialized successfully
+ @retval EFI_OUT_OF_RESOURCES Could not allocate needed resources
+
+**/
+EFI_STATUS
+EFIAPI
+InitializeSectionExtraction (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+ EFI_GUID *ExtractHandlerGuidTable;
+ UINTN ExtractHandlerNumber;
+
+ //
+ // Get custom extract guided section method guid list
+ //
+ ExtractHandlerNumber = ExtractGuidedSectionGetGuidList (&ExtractHandlerGuidTable);
+
+ Status = EFI_SUCCESS;
+ //
+ // Install custom guided extraction protocol
+ //
+ while (ExtractHandlerNumber-- > 0) {
+ Status = CoreInstallProtocolInterface (
+ &mSectionExtractionHandle,
+ &ExtractHandlerGuidTable [ExtractHandlerNumber],
+ EFI_NATIVE_INTERFACE,
+ &mCustomGuidedSectionExtractionProtocol
+ );
+ ASSERT_EFI_ERROR (Status);
+ }
+
+ return Status;
+}
+
+
+/**
+ Check if a stream is valid.
+
+ @param SectionStream The section stream to be checked
+ @param SectionStreamLength The length of section stream
+
+ @return A boolean value indicating the validness of the section stream.
+
+**/
+BOOLEAN
+IsValidSectionStream (
+ IN VOID *SectionStream,
+ IN UINTN SectionStreamLength
+ )
+{
+ UINTN TotalLength;
+ UINTN SectionLength;
+ EFI_COMMON_SECTION_HEADER *SectionHeader;
+ EFI_COMMON_SECTION_HEADER *NextSectionHeader;
+
+ TotalLength = 0;
+ SectionHeader = (EFI_COMMON_SECTION_HEADER *)SectionStream;
+
+ while (TotalLength < SectionStreamLength) {
+ if (IS_SECTION2 (SectionHeader)) {
+ SectionLength = SECTION2_SIZE (SectionHeader);
+ } else {
+ SectionLength = SECTION_SIZE (SectionHeader);
+ }
+ TotalLength += SectionLength;
+
+ if (TotalLength == SectionStreamLength) {
+ return TRUE;
+ }
+
+ //
+ // Move to the next byte following the section...
+ //
+ SectionHeader = (EFI_COMMON_SECTION_HEADER *) ((UINT8 *) SectionHeader + SectionLength);
+
+ //
+ // Figure out where the next section begins
+ //
+ NextSectionHeader = ALIGN_POINTER(SectionHeader, 4);
+ TotalLength += (UINTN) NextSectionHeader - (UINTN) SectionHeader;
+ SectionHeader = NextSectionHeader;
+ }
+
+ ASSERT (FALSE);
+ return FALSE;
+}
+
+
+/**
+ Worker function. Constructor for section streams.
+
+ @param SectionStreamLength Size in bytes of the section stream.
+ @param SectionStream Buffer containing the new section stream.
+ @param AllocateBuffer Indicates whether the stream buffer is to be
+ copied or the input buffer is to be used in
+ place. AuthenticationStatus- Indicates the
+ default authentication status for the new
+ stream.
+ @param AuthenticationStatus A pointer to a caller-allocated UINT32 that
+ indicates the authentication status of the
+ output buffer. If the input section's
+ GuidedSectionHeader.Attributes field
+ has the EFI_GUIDED_SECTION_AUTH_STATUS_VALID
+ bit as clear, AuthenticationStatus must return
+ zero. Both local bits (19:16) and aggregate
+ bits (3:0) in AuthenticationStatus are returned
+ by ExtractSection(). These bits reflect the
+ status of the extraction operation. The bit
+ pattern in both regions must be the same, as
+ the local and aggregate authentication statuses
+ have equivalent meaning at this level. If the
+ function returns anything other than
+ EFI_SUCCESS, the value of *AuthenticationStatus
+ is undefined.
+ @param SectionStreamHandle A pointer to a caller allocated section stream
+ handle.
+
+ @retval EFI_SUCCESS Stream was added to stream database.
+ @retval EFI_OUT_OF_RESOURCES memory allocation failed.
+
+**/
+EFI_STATUS
+OpenSectionStreamEx (
+ IN UINTN SectionStreamLength,
+ IN VOID *SectionStream,
+ IN BOOLEAN AllocateBuffer,
+ IN UINT32 AuthenticationStatus,
+ OUT UINTN *SectionStreamHandle
+ )
+{
+ CORE_SECTION_STREAM_NODE *NewStream;
+ EFI_TPL OldTpl;
+
+ //
+ // Allocate a new stream
+ //
+ NewStream = AllocatePool (sizeof (CORE_SECTION_STREAM_NODE));
+ if (NewStream == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ if (AllocateBuffer) {
+ //
+ // if we're here, we're double buffering, allocate the buffer and copy the
+ // data in
+ //
+ if (SectionStreamLength > 0) {
+ NewStream->StreamBuffer = AllocatePool (SectionStreamLength);
+ if (NewStream->StreamBuffer == NULL) {
+ CoreFreePool (NewStream);
+ return EFI_OUT_OF_RESOURCES;
+ }
+ //
+ // Copy in stream data
+ //
+ CopyMem (NewStream->StreamBuffer, SectionStream, SectionStreamLength);
+ } else {
+ //
+ // It's possible to have a zero length section stream.
+ //
+ NewStream->StreamBuffer = NULL;
+ }
+ } else {
+ //
+ // If were here, the caller has supplied the buffer (it's an internal call)
+ // so just assign the buffer. This happens when we open section streams
+ // as a result of expanding an encapsulating section.
+ //
+ NewStream->StreamBuffer = SectionStream;
+ }
+
+ //
+ // Initialize the rest of the section stream
+ //
+ NewStream->Signature = CORE_SECTION_STREAM_SIGNATURE;
+ NewStream->StreamHandle = (UINTN) NewStream;
+ NewStream->StreamLength = SectionStreamLength;
+ InitializeListHead (&NewStream->Children);
+ NewStream->AuthenticationStatus = AuthenticationStatus;
+
+ //
+ // Add new stream to stream list
+ //
+ OldTpl = CoreRaiseTpl (TPL_NOTIFY);
+ InsertTailList (&mStreamRoot, &NewStream->Link);
+ CoreRestoreTpl (OldTpl);
+
+ *SectionStreamHandle = NewStream->StreamHandle;
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ SEP member function. This function creates and returns a new section stream
+ handle to represent the new section stream.
+
+ @param SectionStreamLength Size in bytes of the section stream.
+ @param SectionStream Buffer containing the new section stream.
+ @param SectionStreamHandle A pointer to a caller allocated UINTN that on
+ output contains the new section stream handle.
+
+ @retval EFI_SUCCESS The section stream is created successfully.
+ @retval EFI_OUT_OF_RESOURCES memory allocation failed.
+ @retval EFI_INVALID_PARAMETER Section stream does not end concident with end
+ of last section.
+
+**/
+EFI_STATUS
+EFIAPI
+OpenSectionStream (
+ IN UINTN SectionStreamLength,
+ IN VOID *SectionStream,
+ OUT UINTN *SectionStreamHandle
+ )
+{
+ //
+ // Check to see section stream looks good...
+ //
+ if (!IsValidSectionStream (SectionStream, SectionStreamLength)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ return OpenSectionStreamEx (
+ SectionStreamLength,
+ SectionStream,
+ FALSE,
+ 0,
+ SectionStreamHandle
+ );
+}
+
+
+
+/**
+ Worker function. Determine if the input stream:child matches the input type.
+
+ @param Stream Indicates the section stream associated with the
+ child
+ @param Child Indicates the child to check
+ @param SearchType Indicates the type of section to check against
+ for
+ @param SectionDefinitionGuid Indicates the GUID to check against if the type
+ is EFI_SECTION_GUID_DEFINED
+
+ @retval TRUE The child matches
+ @retval FALSE The child doesn't match
+
+**/
+BOOLEAN
+ChildIsType (
+ IN CORE_SECTION_STREAM_NODE *Stream,
+ IN CORE_SECTION_CHILD_NODE *Child,
+ IN EFI_SECTION_TYPE SearchType,
+ IN EFI_GUID *SectionDefinitionGuid
+ )
+{
+ EFI_GUID_DEFINED_SECTION *GuidedSection;
+
+ if (SearchType == EFI_SECTION_ALL) {
+ return TRUE;
+ }
+ if (Child->Type != SearchType) {
+ return FALSE;
+ }
+ if ((SearchType != EFI_SECTION_GUID_DEFINED) || (SectionDefinitionGuid == NULL)) {
+ return TRUE;
+ }
+ GuidedSection = (EFI_GUID_DEFINED_SECTION * )(Stream->StreamBuffer + Child->OffsetInStream);
+ if (IS_SECTION2 (GuidedSection)) {
+ return CompareGuid (&(((EFI_GUID_DEFINED_SECTION2 *) GuidedSection)->SectionDefinitionGuid), SectionDefinitionGuid);
+ } else {
+ return CompareGuid (&GuidedSection->SectionDefinitionGuid, SectionDefinitionGuid);
+ }
+}
+
+/**
+ Verify the Guided Section GUID by checking if there is the Guided Section GUID configuration table recorded the GUID itself.
+
+ @param GuidedSectionGuid The Guided Section GUID.
+ @param GuidedSectionExtraction A pointer to the pointer to the supported Guided Section Extraction Protocol
+ for the Guided Section.
+
+ @return TRUE The GuidedSectionGuid could be identified, and the pointer to
+ the Guided Section Extraction Protocol will be returned to *GuidedSectionExtraction.
+ @return FALSE The GuidedSectionGuid could not be identified, or
+ the Guided Section Extraction Protocol has not been installed yet.
+
+**/
+BOOLEAN
+VerifyGuidedSectionGuid (
+ IN EFI_GUID *GuidedSectionGuid,
+ OUT EFI_GUIDED_SECTION_EXTRACTION_PROTOCOL **GuidedSectionExtraction
+ )
+{
+ EFI_GUID *GuidRecorded;
+ VOID *Interface;
+ EFI_STATUS Status;
+
+ Interface = NULL;
+
+ //
+ // Check if there is the Guided Section GUID configuration table recorded the GUID itself.
+ //
+ Status = EfiGetSystemConfigurationTable (GuidedSectionGuid, (VOID **) &GuidRecorded);
+ if (Status == EFI_SUCCESS) {
+ if (CompareGuid (GuidRecorded, GuidedSectionGuid)) {
+ //
+ // Found the recorded GuidedSectionGuid.
+ //
+ Status = CoreLocateProtocol (GuidedSectionGuid, NULL, (VOID **) &Interface);
+ if (!EFI_ERROR (Status) && Interface != NULL) {
+ //
+ // Found the supported Guided Section Extraction Porotocol for the Guided Section.
+ //
+ *GuidedSectionExtraction = (EFI_GUIDED_SECTION_EXTRACTION_PROTOCOL *) Interface;
+ return TRUE;
+ }
+ return FALSE;
+ }
+ }
+
+ return FALSE;
+}
+
+/**
+ RPN callback function. Initializes the section stream
+ when GUIDED_SECTION_EXTRACTION_PROTOCOL is installed.
+
+ @param Event The event that fired
+ @param RpnContext A pointer to the context that allows us to identify
+ the relevent encapsulation.
+**/
+VOID
+EFIAPI
+NotifyGuidedExtraction (
+ IN EFI_EVENT Event,
+ IN VOID *RpnContext
+ )
+{
+ EFI_STATUS Status;
+ EFI_GUID_DEFINED_SECTION *GuidedHeader;
+ EFI_GUIDED_SECTION_EXTRACTION_PROTOCOL *GuidedExtraction;
+ VOID *NewStreamBuffer;
+ UINTN NewStreamBufferSize;
+ UINT32 AuthenticationStatus;
+ RPN_EVENT_CONTEXT *Context;
+
+ Context = RpnContext;
+
+ GuidedHeader = (EFI_GUID_DEFINED_SECTION *) (Context->ParentStream->StreamBuffer + Context->ChildNode->OffsetInStream);
+ ASSERT (GuidedHeader->CommonHeader.Type == EFI_SECTION_GUID_DEFINED);
+
+ if (!VerifyGuidedSectionGuid (Context->ChildNode->EncapsulationGuid, &GuidedExtraction)) {
+ return;
+ }
+
+ Status = GuidedExtraction->ExtractSection (
+ GuidedExtraction,
+ GuidedHeader,
+ &NewStreamBuffer,
+ &NewStreamBufferSize,
+ &AuthenticationStatus
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Make sure we initialize the new stream with the correct
+ // authentication status for both aggregate and local status fields.
+ //
+ if ((GuidedHeader->Attributes & EFI_GUIDED_SECTION_AUTH_STATUS_VALID) != 0) {
+ //
+ // OR in the parent stream's aggregate status.
+ //
+ AuthenticationStatus |= Context->ParentStream->AuthenticationStatus & EFI_AUTH_STATUS_ALL;
+ } else {
+ //
+ // since there's no authentication data contributed by the section,
+ // just inherit the full value from our immediate parent.
+ //
+ AuthenticationStatus = Context->ParentStream->AuthenticationStatus;
+ }
+
+ Status = OpenSectionStreamEx (
+ NewStreamBufferSize,
+ NewStreamBuffer,
+ FALSE,
+ AuthenticationStatus,
+ &Context->ChildNode->EncapsulatedStreamHandle
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Close the event when done.
+ //
+ gBS->CloseEvent (Event);
+ Context->ChildNode->Event = NULL;
+ FreePool (Context);
+}
+
+/**
+ Constructor for RPN event when a missing GUIDED_SECTION_EXTRACTION_PROTOCOL appears...
+
+ @param ParentStream Indicates the parent of the ecnapsulation section (child)
+ @param ChildNode Indicates the child node that is the encapsulation section.
+
+**/
+VOID
+CreateGuidedExtractionRpnEvent (
+ IN CORE_SECTION_STREAM_NODE *ParentStream,
+ IN CORE_SECTION_CHILD_NODE *ChildNode
+ )
+{
+ RPN_EVENT_CONTEXT *Context;
+
+ //
+ // Allocate new event structure and context
+ //
+ Context = AllocatePool (sizeof (RPN_EVENT_CONTEXT));
+ ASSERT (Context != NULL);
+
+ Context->ChildNode = ChildNode;
+ Context->ParentStream = ParentStream;
+
+ Context->ChildNode->Event = EfiCreateProtocolNotifyEvent (
+ Context->ChildNode->EncapsulationGuid,
+ TPL_NOTIFY,
+ NotifyGuidedExtraction,
+ Context,
+ &Context->Registration
+ );
+}
+
+/**
+ Worker function. Constructor for new child nodes.
+
+ @param Stream Indicates the section stream in which to add the
+ child.
+ @param ChildOffset Indicates the offset in Stream that is the
+ beginning of the child section.
+ @param ChildNode Indicates the Callee allocated and initialized
+ child.
+
+ @retval EFI_SUCCESS Child node was found and returned.
+ EFI_OUT_OF_RESOURCES- Memory allocation failed.
+ @retval EFI_PROTOCOL_ERROR Encapsulation sections produce new stream
+ handles when the child node is created. If the
+ section type is GUID defined, and the extraction
+ GUID does not exist, and producing the stream
+ requires the GUID, then a protocol error is
+ generated and no child is produced. Values
+ returned by OpenSectionStreamEx.
+
+**/
+EFI_STATUS
+CreateChildNode (
+ IN CORE_SECTION_STREAM_NODE *Stream,
+ IN UINT32 ChildOffset,
+ OUT CORE_SECTION_CHILD_NODE **ChildNode
+ )
+{
+ EFI_STATUS Status;
+ EFI_COMMON_SECTION_HEADER *SectionHeader;
+ EFI_COMPRESSION_SECTION *CompressionHeader;
+ EFI_GUID_DEFINED_SECTION *GuidedHeader;
+ EFI_DECOMPRESS_PROTOCOL *Decompress;
+ EFI_GUIDED_SECTION_EXTRACTION_PROTOCOL *GuidedExtraction;
+ VOID *NewStreamBuffer;
+ VOID *ScratchBuffer;
+ UINT32 ScratchSize;
+ UINTN NewStreamBufferSize;
+ UINT32 AuthenticationStatus;
+ VOID *CompressionSource;
+ UINT32 CompressionSourceSize;
+ UINT32 UncompressedLength;
+ UINT8 CompressionType;
+ UINT16 GuidedSectionAttributes;
+
+ CORE_SECTION_CHILD_NODE *Node;
+
+ SectionHeader = (EFI_COMMON_SECTION_HEADER *) (Stream->StreamBuffer + ChildOffset);
+
+ //
+ // Allocate a new node
+ //
+ *ChildNode = AllocateZeroPool (sizeof (CORE_SECTION_CHILD_NODE));
+ Node = *ChildNode;
+ if (Node == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ //
+ // Now initialize it
+ //
+ Node->Signature = CORE_SECTION_CHILD_SIGNATURE;
+ Node->Type = SectionHeader->Type;
+ if (IS_SECTION2 (SectionHeader)) {
+ Node->Size = SECTION2_SIZE (SectionHeader);
+ } else {
+ Node->Size = SECTION_SIZE (SectionHeader);
+ }
+ Node->OffsetInStream = ChildOffset;
+ Node->EncapsulatedStreamHandle = NULL_STREAM_HANDLE;
+ Node->EncapsulationGuid = NULL;
+
+ //
+ // If it's an encapsulating section, then create the new section stream also
+ //
+ switch (Node->Type) {
+ case EFI_SECTION_COMPRESSION:
+ //
+ // Get the CompressionSectionHeader
+ //
+ if (Node->Size < sizeof (EFI_COMPRESSION_SECTION)) {
+ CoreFreePool (Node);
+ return EFI_NOT_FOUND;
+ }
+
+ CompressionHeader = (EFI_COMPRESSION_SECTION *) SectionHeader;
+
+ if (IS_SECTION2 (CompressionHeader)) {
+ CompressionSource = (VOID *) ((UINT8 *) CompressionHeader + sizeof (EFI_COMPRESSION_SECTION2));
+ CompressionSourceSize = (UINT32) (SECTION2_SIZE (CompressionHeader) - sizeof (EFI_COMPRESSION_SECTION2));
+ UncompressedLength = ((EFI_COMPRESSION_SECTION2 *) CompressionHeader)->UncompressedLength;
+ CompressionType = ((EFI_COMPRESSION_SECTION2 *) CompressionHeader)->CompressionType;
+ } else {
+ CompressionSource = (VOID *) ((UINT8 *) CompressionHeader + sizeof (EFI_COMPRESSION_SECTION));
+ CompressionSourceSize = (UINT32) (SECTION_SIZE (CompressionHeader) - sizeof (EFI_COMPRESSION_SECTION));
+ UncompressedLength = CompressionHeader->UncompressedLength;
+ CompressionType = CompressionHeader->CompressionType;
+ }
+
+ //
+ // Allocate space for the new stream
+ //
+ if (UncompressedLength > 0) {
+ NewStreamBufferSize = UncompressedLength;
+ NewStreamBuffer = AllocatePool (NewStreamBufferSize);
+ if (NewStreamBuffer == NULL) {
+ CoreFreePool (Node);
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ if (CompressionType == EFI_NOT_COMPRESSED) {
+ //
+ // stream is not actually compressed, just encapsulated. So just copy it.
+ //
+ CopyMem (NewStreamBuffer, CompressionSource, NewStreamBufferSize);
+ } else if (CompressionType == EFI_STANDARD_COMPRESSION) {
+ //
+ // Only support the EFI_SATNDARD_COMPRESSION algorithm.
+ //
+
+ //
+ // Decompress the stream
+ //
+ Status = CoreLocateProtocol (&gEfiDecompressProtocolGuid, NULL, (VOID **)&Decompress);
+ ASSERT_EFI_ERROR (Status);
+ ASSERT (Decompress != NULL);
+
+ Status = Decompress->GetInfo (
+ Decompress,
+ CompressionSource,
+ CompressionSourceSize,
+ (UINT32 *)&NewStreamBufferSize,
+ &ScratchSize
+ );
+ if (EFI_ERROR (Status) || (NewStreamBufferSize != UncompressedLength)) {
+ CoreFreePool (Node);
+ CoreFreePool (NewStreamBuffer);
+ if (!EFI_ERROR (Status)) {
+ Status = EFI_BAD_BUFFER_SIZE;
+ }
+ return Status;
+ }
+
+ ScratchBuffer = AllocatePool (ScratchSize);
+ if (ScratchBuffer == NULL) {
+ CoreFreePool (Node);
+ CoreFreePool (NewStreamBuffer);
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ Status = Decompress->Decompress (
+ Decompress,
+ CompressionSource,
+ CompressionSourceSize,
+ NewStreamBuffer,
+ (UINT32)NewStreamBufferSize,
+ ScratchBuffer,
+ ScratchSize
+ );
+ CoreFreePool (ScratchBuffer);
+ if (EFI_ERROR (Status)) {
+ CoreFreePool (Node);
+ CoreFreePool (NewStreamBuffer);
+ return Status;
+ }
+ }
+ } else {
+ NewStreamBuffer = NULL;
+ NewStreamBufferSize = 0;
+ }
+
+ Status = OpenSectionStreamEx (
+ NewStreamBufferSize,
+ NewStreamBuffer,
+ FALSE,
+ Stream->AuthenticationStatus,
+ &Node->EncapsulatedStreamHandle
+ );
+ if (EFI_ERROR (Status)) {
+ CoreFreePool (Node);
+ CoreFreePool (NewStreamBuffer);
+ return Status;
+ }
+ break;
+
+ case EFI_SECTION_GUID_DEFINED:
+ GuidedHeader = (EFI_GUID_DEFINED_SECTION *) SectionHeader;
+ if (IS_SECTION2 (GuidedHeader)) {
+ Node->EncapsulationGuid = &(((EFI_GUID_DEFINED_SECTION2 *) GuidedHeader)->SectionDefinitionGuid);
+ GuidedSectionAttributes = ((EFI_GUID_DEFINED_SECTION2 *) GuidedHeader)->Attributes;
+ } else {
+ Node->EncapsulationGuid = &GuidedHeader->SectionDefinitionGuid;
+ GuidedSectionAttributes = GuidedHeader->Attributes;
+ }
+ if (VerifyGuidedSectionGuid (Node->EncapsulationGuid, &GuidedExtraction)) {
+ //
+ // NewStreamBuffer is always allocated by ExtractSection... No caller
+ // allocation here.
+ //
+ Status = GuidedExtraction->ExtractSection (
+ GuidedExtraction,
+ GuidedHeader,
+ &NewStreamBuffer,
+ &NewStreamBufferSize,
+ &AuthenticationStatus
+ );
+ if (EFI_ERROR (Status)) {
+ CoreFreePool (*ChildNode);
+ return EFI_PROTOCOL_ERROR;
+ }
+
+ //
+ // Make sure we initialize the new stream with the correct
+ // authentication status for both aggregate and local status fields.
+ //
+ if ((GuidedSectionAttributes & EFI_GUIDED_SECTION_AUTH_STATUS_VALID) != 0) {
+ //
+ // OR in the parent stream's aggregate status.
+ //
+ AuthenticationStatus |= Stream->AuthenticationStatus & EFI_AUTH_STATUS_ALL;
+ } else {
+ //
+ // since there's no authentication data contributed by the section,
+ // just inherit the full value from our immediate parent.
+ //
+ AuthenticationStatus = Stream->AuthenticationStatus;
+ }
+
+ Status = OpenSectionStreamEx (
+ NewStreamBufferSize,
+ NewStreamBuffer,
+ FALSE,
+ AuthenticationStatus,
+ &Node->EncapsulatedStreamHandle
+ );
+ if (EFI_ERROR (Status)) {
+ CoreFreePool (*ChildNode);
+ CoreFreePool (NewStreamBuffer);
+ return Status;
+ }
+ } else {
+ //
+ // There's no GUIDed section extraction protocol available.
+ //
+ if ((GuidedSectionAttributes & EFI_GUIDED_SECTION_PROCESSING_REQUIRED) != 0) {
+ //
+ // If the section REQUIRES an extraction protocol, register for RPN
+ // when the required GUIDed extraction protocol becomes available.
+ //
+ CreateGuidedExtractionRpnEvent (Stream, Node);
+ } else {
+ //
+ // Figure out the proper authentication status
+ //
+ AuthenticationStatus = Stream->AuthenticationStatus;
+
+ if ((GuidedSectionAttributes & EFI_GUIDED_SECTION_AUTH_STATUS_VALID) == EFI_GUIDED_SECTION_AUTH_STATUS_VALID) {
+ AuthenticationStatus |= EFI_AUTH_STATUS_IMAGE_SIGNED | EFI_AUTH_STATUS_NOT_TESTED;
+ }
+
+ if (IS_SECTION2 (GuidedHeader)) {
+ Status = OpenSectionStreamEx (
+ SECTION2_SIZE (GuidedHeader) - ((EFI_GUID_DEFINED_SECTION2 *) GuidedHeader)->DataOffset,
+ (UINT8 *) GuidedHeader + ((EFI_GUID_DEFINED_SECTION2 *) GuidedHeader)->DataOffset,
+ TRUE,
+ AuthenticationStatus,
+ &Node->EncapsulatedStreamHandle
+ );
+ } else {
+ Status = OpenSectionStreamEx (
+ SECTION_SIZE (GuidedHeader) - ((EFI_GUID_DEFINED_SECTION *) GuidedHeader)->DataOffset,
+ (UINT8 *) GuidedHeader + ((EFI_GUID_DEFINED_SECTION *) GuidedHeader)->DataOffset,
+ TRUE,
+ AuthenticationStatus,
+ &Node->EncapsulatedStreamHandle
+ );
+ }
+ if (EFI_ERROR (Status)) {
+ CoreFreePool (Node);
+ return Status;
+ }
+ }
+ }
+
+ break;
+
+ default:
+
+ //
+ // Nothing to do if it's a leaf
+ //
+ break;
+ }
+
+ //
+ // Last, add the new child node to the stream
+ //
+ InsertTailList (&Stream->Children, &Node->Link);
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Worker function Recursively searches / builds section stream database
+ looking for requested section.
+
+ @param SourceStream Indicates the section stream in which to do the
+ search.
+ @param SearchType Indicates the type of section to search for.
+ @param SectionInstance Indicates which instance of section to find.
+ This is an in/out parameter to deal with
+ recursions.
+ @param SectionDefinitionGuid Guid of section definition
+ @param FoundChild Output indicating the child node that is found.
+ @param FoundStream Output indicating which section stream the child
+ was found in. If this stream was generated as a
+ result of an encapsulation section, the
+ streamhandle is visible within the SEP driver
+ only.
+ @param AuthenticationStatus Indicates the authentication status of the found section.
+
+ @retval EFI_SUCCESS Child node was found and returned.
+ EFI_OUT_OF_RESOURCES- Memory allocation failed.
+ @retval EFI_NOT_FOUND Requested child node does not exist.
+ @retval EFI_PROTOCOL_ERROR a required GUIDED section extraction protocol
+ does not exist
+
+**/
+EFI_STATUS
+FindChildNode (
+ IN CORE_SECTION_STREAM_NODE *SourceStream,
+ IN EFI_SECTION_TYPE SearchType,
+ IN OUT UINTN *SectionInstance,
+ IN EFI_GUID *SectionDefinitionGuid,
+ OUT CORE_SECTION_CHILD_NODE **FoundChild,
+ OUT CORE_SECTION_STREAM_NODE **FoundStream,
+ OUT UINT32 *AuthenticationStatus
+ )
+{
+ CORE_SECTION_CHILD_NODE *CurrentChildNode;
+ CORE_SECTION_CHILD_NODE *RecursedChildNode;
+ CORE_SECTION_STREAM_NODE *RecursedFoundStream;
+ UINT32 NextChildOffset;
+ EFI_STATUS ErrorStatus;
+ EFI_STATUS Status;
+
+ CurrentChildNode = NULL;
+ ErrorStatus = EFI_NOT_FOUND;
+
+ if (SourceStream->StreamLength == 0) {
+ return EFI_NOT_FOUND;
+ }
+
+ if (IsListEmpty (&SourceStream->Children) &&
+ SourceStream->StreamLength >= sizeof (EFI_COMMON_SECTION_HEADER)) {
+ //
+ // This occurs when a section stream exists, but no child sections
+ // have been parsed out yet. Therefore, extract the first child and add it
+ // to the list of children so we can get started.
+ // Section stream may contain an array of zero or more bytes.
+ // So, its size should be >= the size of commen section header.
+ //
+ Status = CreateChildNode (SourceStream, 0, &CurrentChildNode);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+
+ //
+ // At least one child has been parsed out of the section stream. So, walk
+ // through the sections that have already been parsed out looking for the
+ // requested section, if necessary, continue parsing section stream and
+ // adding children until either the requested section is found, or we run
+ // out of data
+ //
+ CurrentChildNode = CHILD_SECTION_NODE_FROM_LINK (GetFirstNode(&SourceStream->Children));
+
+ for (;;) {
+ ASSERT (CurrentChildNode != NULL);
+ if (ChildIsType (SourceStream, CurrentChildNode, SearchType, SectionDefinitionGuid)) {
+ //
+ // The type matches, so check the instance count to see if it's the one we want
+ //
+ (*SectionInstance)--;
+ if (*SectionInstance == 0) {
+ //
+ // Got it!
+ //
+ *FoundChild = CurrentChildNode;
+ *FoundStream = SourceStream;
+ *AuthenticationStatus = SourceStream->AuthenticationStatus;
+ return EFI_SUCCESS;
+ }
+ }
+
+ if (CurrentChildNode->EncapsulatedStreamHandle != NULL_STREAM_HANDLE) {
+ //
+ // If the current node is an encapsulating node, recurse into it...
+ //
+ Status = FindChildNode (
+ (CORE_SECTION_STREAM_NODE *)CurrentChildNode->EncapsulatedStreamHandle,
+ SearchType,
+ SectionInstance,
+ SectionDefinitionGuid,
+ &RecursedChildNode,
+ &RecursedFoundStream,
+ AuthenticationStatus
+ );
+ //
+ // If the status is not EFI_SUCCESS, just save the error code and continue
+ // to find the request child node in the rest stream.
+ //
+ if (*SectionInstance == 0) {
+ ASSERT_EFI_ERROR (Status);
+ *FoundChild = RecursedChildNode;
+ *FoundStream = RecursedFoundStream;
+ return EFI_SUCCESS;
+ } else {
+ ErrorStatus = Status;
+ }
+ } else if ((CurrentChildNode->Type == EFI_SECTION_GUID_DEFINED) && (SearchType != EFI_SECTION_GUID_DEFINED)) {
+ //
+ // When Node Type is GUIDED section, but Node has no encapsulated data, Node data should not be parsed
+ // because a required GUIDED section extraction protocol does not exist.
+ // If SearchType is not GUIDED section, EFI_PROTOCOL_ERROR should return.
+ //
+ ErrorStatus = EFI_PROTOCOL_ERROR;
+ }
+
+ if (!IsNodeAtEnd (&SourceStream->Children, &CurrentChildNode->Link)) {
+ //
+ // We haven't found the child node we're interested in yet, but there's
+ // still more nodes that have already been parsed so get the next one
+ // and continue searching..
+ //
+ CurrentChildNode = CHILD_SECTION_NODE_FROM_LINK (GetNextNode (&SourceStream->Children, &CurrentChildNode->Link));
+ } else {
+ //
+ // We've exhausted children that have already been parsed, so see if
+ // there's any more data and continue parsing out more children if there
+ // is.
+ //
+ NextChildOffset = CurrentChildNode->OffsetInStream + CurrentChildNode->Size;
+ //
+ // Round up to 4 byte boundary
+ //
+ NextChildOffset += 3;
+ NextChildOffset &= ~(UINTN) 3;
+ if (NextChildOffset <= SourceStream->StreamLength - sizeof (EFI_COMMON_SECTION_HEADER)) {
+ //
+ // There's an unparsed child remaining in the stream, so create a new child node
+ //
+ Status = CreateChildNode (SourceStream, NextChildOffset, &CurrentChildNode);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ } else {
+ ASSERT (EFI_ERROR (ErrorStatus));
+ return ErrorStatus;
+ }
+ }
+ }
+}
+
+
+/**
+ Worker function. Search stream database for requested stream handle.
+
+ @param SearchHandle Indicates which stream to look for.
+ @param FoundStream Output pointer to the found stream.
+
+ @retval EFI_SUCCESS StreamHandle was found and *FoundStream contains
+ the stream node.
+ @retval EFI_NOT_FOUND SearchHandle was not found in the stream
+ database.
+
+**/
+EFI_STATUS
+FindStreamNode (
+ IN UINTN SearchHandle,
+ OUT CORE_SECTION_STREAM_NODE **FoundStream
+ )
+{
+ CORE_SECTION_STREAM_NODE *StreamNode;
+
+ if (!IsListEmpty (&mStreamRoot)) {
+ StreamNode = STREAM_NODE_FROM_LINK (GetFirstNode (&mStreamRoot));
+ for (;;) {
+ if (StreamNode->StreamHandle == SearchHandle) {
+ *FoundStream = StreamNode;
+ return EFI_SUCCESS;
+ } else if (IsNodeAtEnd (&mStreamRoot, &StreamNode->Link)) {
+ break;
+ } else {
+ StreamNode = STREAM_NODE_FROM_LINK (GetNextNode (&mStreamRoot, &StreamNode->Link));
+ }
+ }
+ }
+
+ return EFI_NOT_FOUND;
+}
+
+
+/**
+ SEP member function. Retrieves requested section from section stream.
+
+ @param SectionStreamHandle The section stream from which to extract the
+ requested section.
+ @param SectionType A pointer to the type of section to search for.
+ @param SectionDefinitionGuid If the section type is EFI_SECTION_GUID_DEFINED,
+ then SectionDefinitionGuid indicates which of
+ these types of sections to search for.
+ @param SectionInstance Indicates which instance of the requested
+ section to return.
+ @param Buffer Double indirection to buffer. If *Buffer is
+ non-null on input, then the buffer is caller
+ allocated. If Buffer is NULL, then the buffer
+ is callee allocated. In either case, the
+ required buffer size is returned in *BufferSize.
+ @param BufferSize On input, indicates the size of *Buffer if
+ *Buffer is non-null on input. On output,
+ indicates the required size (allocated size if
+ callee allocated) of *Buffer.
+ @param AuthenticationStatus A pointer to a caller-allocated UINT32 that
+ indicates the authentication status of the
+ output buffer. If the input section's
+ GuidedSectionHeader.Attributes field
+ has the EFI_GUIDED_SECTION_AUTH_STATUS_VALID
+ bit as clear, AuthenticationStatus must return
+ zero. Both local bits (19:16) and aggregate
+ bits (3:0) in AuthenticationStatus are returned
+ by ExtractSection(). These bits reflect the
+ status of the extraction operation. The bit
+ pattern in both regions must be the same, as
+ the local and aggregate authentication statuses
+ have equivalent meaning at this level. If the
+ function returns anything other than
+ EFI_SUCCESS, the value of *AuthenticationStatus
+ is undefined.
+ @param IsFfs3Fv Indicates the FV format.
+
+ @retval EFI_SUCCESS Section was retrieved successfully
+ @retval EFI_PROTOCOL_ERROR A GUID defined section was encountered in the
+ section stream with its
+ EFI_GUIDED_SECTION_PROCESSING_REQUIRED bit set,
+ but there was no corresponding GUIDed Section
+ Extraction Protocol in the handle database.
+ *Buffer is unmodified.
+ @retval EFI_NOT_FOUND An error was encountered when parsing the
+ SectionStream. This indicates the SectionStream
+ is not correctly formatted.
+ @retval EFI_NOT_FOUND The requested section does not exist.
+ @retval EFI_OUT_OF_RESOURCES The system has insufficient resources to process
+ the request.
+ @retval EFI_INVALID_PARAMETER The SectionStreamHandle does not exist.
+ @retval EFI_WARN_TOO_SMALL The size of the caller allocated input buffer is
+ insufficient to contain the requested section.
+ The input buffer is filled and section contents
+ are truncated.
+
+**/
+EFI_STATUS
+EFIAPI
+GetSection (
+ IN UINTN SectionStreamHandle,
+ IN EFI_SECTION_TYPE *SectionType,
+ IN EFI_GUID *SectionDefinitionGuid,
+ IN UINTN SectionInstance,
+ IN VOID **Buffer,
+ IN OUT UINTN *BufferSize,
+ OUT UINT32 *AuthenticationStatus,
+ IN BOOLEAN IsFfs3Fv
+ )
+{
+ CORE_SECTION_STREAM_NODE *StreamNode;
+ EFI_TPL OldTpl;
+ EFI_STATUS Status;
+ CORE_SECTION_CHILD_NODE *ChildNode;
+ CORE_SECTION_STREAM_NODE *ChildStreamNode;
+ UINTN CopySize;
+ UINT32 ExtractedAuthenticationStatus;
+ UINTN Instance;
+ UINT8 *CopyBuffer;
+ UINTN SectionSize;
+ EFI_COMMON_SECTION_HEADER *Section;
+
+
+ ChildStreamNode = NULL;
+ OldTpl = CoreRaiseTpl (TPL_NOTIFY);
+ Instance = SectionInstance + 1;
+
+ //
+ // Locate target stream
+ //
+ Status = FindStreamNode (SectionStreamHandle, &StreamNode);
+ if (EFI_ERROR (Status)) {
+ Status = EFI_INVALID_PARAMETER;
+ goto GetSection_Done;
+ }
+
+ //
+ // Found the stream, now locate and return the appropriate section
+ //
+ if (SectionType == NULL) {
+ //
+ // SectionType == NULL means return the WHOLE section stream...
+ //
+ CopySize = StreamNode->StreamLength;
+ CopyBuffer = StreamNode->StreamBuffer;
+ *AuthenticationStatus = StreamNode->AuthenticationStatus;
+ } else {
+ //
+ // There's a requested section type, so go find it and return it...
+ //
+ Status = FindChildNode (
+ StreamNode,
+ *SectionType,
+ &Instance,
+ SectionDefinitionGuid,
+ &ChildNode,
+ &ChildStreamNode,
+ &ExtractedAuthenticationStatus
+ );
+ if (EFI_ERROR (Status)) {
+ goto GetSection_Done;
+ }
+
+ Section = (EFI_COMMON_SECTION_HEADER *) (ChildStreamNode->StreamBuffer + ChildNode->OffsetInStream);
+
+ if (IS_SECTION2 (Section)) {
+ ASSERT (SECTION2_SIZE (Section) > 0x00FFFFFF);
+ if (!IsFfs3Fv) {
+ DEBUG ((DEBUG_ERROR, "It is a FFS3 formatted section in a non-FFS3 formatted FV.\n"));
+ Status = EFI_NOT_FOUND;
+ goto GetSection_Done;
+ }
+ CopySize = SECTION2_SIZE (Section) - sizeof (EFI_COMMON_SECTION_HEADER2);
+ CopyBuffer = (UINT8 *) Section + sizeof (EFI_COMMON_SECTION_HEADER2);
+ } else {
+ CopySize = SECTION_SIZE (Section) - sizeof (EFI_COMMON_SECTION_HEADER);
+ CopyBuffer = (UINT8 *) Section + sizeof (EFI_COMMON_SECTION_HEADER);
+ }
+ *AuthenticationStatus = ExtractedAuthenticationStatus;
+ }
+
+ SectionSize = CopySize;
+ if (*Buffer != NULL) {
+ //
+ // Caller allocated buffer. Fill to size and return required size...
+ //
+ if (*BufferSize < CopySize) {
+ Status = EFI_WARN_BUFFER_TOO_SMALL;
+ CopySize = *BufferSize;
+ }
+ } else {
+ //
+ // Callee allocated buffer. Allocate buffer and return size.
+ //
+ *Buffer = AllocatePool (CopySize);
+ if (*Buffer == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto GetSection_Done;
+ }
+ }
+ CopyMem (*Buffer, CopyBuffer, CopySize);
+ *BufferSize = SectionSize;
+
+GetSection_Done:
+ CoreRestoreTpl (OldTpl);
+
+ return Status;
+}
+
+
+/**
+ Worker function. Destructor for child nodes.
+
+ @param ChildNode Indicates the node to destroy
+
+**/
+VOID
+FreeChildNode (
+ IN CORE_SECTION_CHILD_NODE *ChildNode
+ )
+{
+ ASSERT (ChildNode->Signature == CORE_SECTION_CHILD_SIGNATURE);
+ //
+ // Remove the child from it's list
+ //
+ RemoveEntryList (&ChildNode->Link);
+
+ if (ChildNode->EncapsulatedStreamHandle != NULL_STREAM_HANDLE) {
+ //
+ // If it's an encapsulating section, we close the resulting section stream.
+ // CloseSectionStream will free all memory associated with the stream.
+ //
+ CloseSectionStream (ChildNode->EncapsulatedStreamHandle, TRUE);
+ }
+
+ if (ChildNode->Event != NULL) {
+ gBS->CloseEvent (ChildNode->Event);
+ }
+
+ //
+ // Last, free the child node itself
+ //
+ CoreFreePool (ChildNode);
+}
+
+
+/**
+ SEP member function. Deletes an existing section stream
+
+ @param StreamHandleToClose Indicates the stream to close
+ @param FreeStreamBuffer TRUE - Need to free stream buffer;
+ FALSE - No need to free stream buffer.
+
+ @retval EFI_SUCCESS The section stream is closed sucessfully.
+ @retval EFI_OUT_OF_RESOURCES Memory allocation failed.
+ @retval EFI_INVALID_PARAMETER Section stream does not end concident with end
+ of last section.
+
+**/
+EFI_STATUS
+EFIAPI
+CloseSectionStream (
+ IN UINTN StreamHandleToClose,
+ IN BOOLEAN FreeStreamBuffer
+ )
+{
+ CORE_SECTION_STREAM_NODE *StreamNode;
+ EFI_TPL OldTpl;
+ EFI_STATUS Status;
+ LIST_ENTRY *Link;
+ CORE_SECTION_CHILD_NODE *ChildNode;
+
+ OldTpl = CoreRaiseTpl (TPL_NOTIFY);
+
+ //
+ // Locate target stream
+ //
+ Status = FindStreamNode (StreamHandleToClose, &StreamNode);
+ if (!EFI_ERROR (Status)) {
+ //
+ // Found the stream, so close it
+ //
+ RemoveEntryList (&StreamNode->Link);
+ while (!IsListEmpty (&StreamNode->Children)) {
+ Link = GetFirstNode (&StreamNode->Children);
+ ChildNode = CHILD_SECTION_NODE_FROM_LINK (Link);
+ FreeChildNode (ChildNode);
+ }
+ if (FreeStreamBuffer) {
+ CoreFreePool (StreamNode->StreamBuffer);
+ }
+ CoreFreePool (StreamNode);
+ Status = EFI_SUCCESS;
+ } else {
+ Status = EFI_INVALID_PARAMETER;
+ }
+
+ CoreRestoreTpl (OldTpl);
+ return Status;
+}
+
+
+/**
+ The ExtractSection() function processes the input section and
+ allocates a buffer from the pool in which it returns the section
+ contents. If the section being extracted contains
+ authentication information (the section's
+ GuidedSectionHeader.Attributes field has the
+ EFI_GUIDED_SECTION_AUTH_STATUS_VALID bit set), the values
+ returned in AuthenticationStatus must reflect the results of
+ the authentication operation. Depending on the algorithm and
+ size of the encapsulated data, the time that is required to do
+ a full authentication may be prohibitively long for some
+ classes of systems. To indicate this, use
+ EFI_SECURITY_POLICY_PROTOCOL_GUID, which may be published by
+ the security policy driver (see the Platform Initialization
+ Driver Execution Environment Core Interface Specification for
+ more details and the GUID definition). If the
+ EFI_SECURITY_POLICY_PROTOCOL_GUID exists in the handle
+ database, then, if possible, full authentication should be
+ skipped and the section contents simply returned in the
+ OutputBuffer. In this case, the
+ EFI_AUTH_STATUS_PLATFORM_OVERRIDE bit AuthenticationStatus
+ must be set on return. ExtractSection() is callable only from
+ TPL_NOTIFY and below. Behavior of ExtractSection() at any
+ EFI_TPL above TPL_NOTIFY is undefined. Type EFI_TPL is
+ defined in RaiseTPL() in the UEFI 2.0 specification.
+
+
+ @param This Indicates the
+ EFI_GUIDED_SECTION_EXTRACTION_PROTOCOL instance.
+ @param InputSection Buffer containing the input GUIDed section
+ to be processed. OutputBuffer OutputBuffer
+ is allocated from boot services pool
+ memory and contains the new section
+ stream. The caller is responsible for
+ freeing this buffer.
+ @param OutputBuffer *OutputBuffer is allocated from boot services
+ pool memory and contains the new section stream.
+ The caller is responsible for freeing this buffer.
+ @param OutputSize A pointer to a caller-allocated UINTN in
+ which the size of OutputBuffer allocation
+ is stored. If the function returns
+ anything other than EFI_SUCCESS, the value
+ of OutputSize is undefined.
+
+ @param AuthenticationStatus A pointer to a caller-allocated
+ UINT32 that indicates the
+ authentication status of the
+ output buffer. If the input
+ section's
+ GuidedSectionHeader.Attributes
+ field has the
+ EFI_GUIDED_SECTION_AUTH_STATUS_VAL
+ bit as clear, AuthenticationStatus
+ must return zero. Both local bits
+ (19:16) and aggregate bits (3:0)
+ in AuthenticationStatus are
+ returned by ExtractSection().
+ These bits reflect the status of
+ the extraction operation. The bit
+ pattern in both regions must be
+ the same, as the local and
+ aggregate authentication statuses
+ have equivalent meaning at this
+ level. If the function returns
+ anything other than EFI_SUCCESS,
+ the value of AuthenticationStatus
+ is undefined.
+
+
+ @retval EFI_SUCCESS The InputSection was successfully
+ processed and the section contents were
+ returned.
+
+ @retval EFI_OUT_OF_RESOURCES The system has insufficient
+ resources to process the
+ request.
+
+ @retval EFI_INVALID_PARAMETER The GUID in InputSection does
+ not match this instance of the
+ GUIDed Section Extraction
+ Protocol.
+
+**/
+EFI_STATUS
+EFIAPI
+CustomGuidedSectionExtract (
+ IN CONST EFI_GUIDED_SECTION_EXTRACTION_PROTOCOL *This,
+ IN CONST VOID *InputSection,
+ OUT VOID **OutputBuffer,
+ OUT UINTN *OutputSize,
+ OUT UINT32 *AuthenticationStatus
+ )
+{
+ EFI_STATUS Status;
+ VOID *ScratchBuffer;
+ VOID *AllocatedOutputBuffer;
+ UINT32 OutputBufferSize;
+ UINT32 ScratchBufferSize;
+ UINT16 SectionAttribute;
+
+ //
+ // Init local variable
+ //
+ ScratchBuffer = NULL;
+ AllocatedOutputBuffer = NULL;
+
+ //
+ // Call GetInfo to get the size and attribute of input guided section data.
+ //
+ Status = ExtractGuidedSectionGetInfo (
+ InputSection,
+ &OutputBufferSize,
+ &ScratchBufferSize,
+ &SectionAttribute
+ );
+
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "GetInfo from guided section Failed - %r\n", Status));
+ return Status;
+ }
+
+ if (ScratchBufferSize > 0) {
+ //
+ // Allocate scratch buffer
+ //
+ ScratchBuffer = AllocatePool (ScratchBufferSize);
+ if (ScratchBuffer == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ }
+
+ if (OutputBufferSize > 0) {
+ //
+ // Allocate output buffer
+ //
+ AllocatedOutputBuffer = AllocatePool (OutputBufferSize);
+ if (AllocatedOutputBuffer == NULL) {
+ if (ScratchBuffer != NULL) {
+ FreePool (ScratchBuffer);
+ }
+ return EFI_OUT_OF_RESOURCES;
+ }
+ *OutputBuffer = AllocatedOutputBuffer;
+ }
+
+ //
+ // Call decode function to extract raw data from the guided section.
+ //
+ Status = ExtractGuidedSectionDecode (
+ InputSection,
+ OutputBuffer,
+ ScratchBuffer,
+ AuthenticationStatus
+ );
+ if (EFI_ERROR (Status)) {
+ //
+ // Decode failed
+ //
+ if (AllocatedOutputBuffer != NULL) {
+ CoreFreePool (AllocatedOutputBuffer);
+ }
+ if (ScratchBuffer != NULL) {
+ CoreFreePool (ScratchBuffer);
+ }
+ DEBUG ((DEBUG_ERROR, "Extract guided section Failed - %r\n", Status));
+ return Status;
+ }
+
+ if (*OutputBuffer != AllocatedOutputBuffer) {
+ //
+ // OutputBuffer was returned as a different value,
+ // so copy section contents to the allocated memory buffer.
+ //
+ CopyMem (AllocatedOutputBuffer, *OutputBuffer, OutputBufferSize);
+ *OutputBuffer = AllocatedOutputBuffer;
+ }
+
+ //
+ // Set real size of output buffer.
+ //
+ *OutputSize = (UINTN) OutputBufferSize;
+
+ //
+ // Free unused scratch buffer.
+ //
+ if (ScratchBuffer != NULL) {
+ CoreFreePool (ScratchBuffer);
+ }
+
+ return EFI_SUCCESS;
+}