summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--StandaloneMmPkg/Core/Dependency.c389
-rw-r--r--StandaloneMmPkg/Core/Dispatcher.c1071
-rw-r--r--StandaloneMmPkg/Core/FwVol.c104
-rw-r--r--StandaloneMmPkg/Core/Handle.c533
-rw-r--r--StandaloneMmPkg/Core/InstallConfigurationTable.c178
-rw-r--r--StandaloneMmPkg/Core/Locate.c496
-rw-r--r--StandaloneMmPkg/Core/Mmi.c337
-rw-r--r--StandaloneMmPkg/Core/Notify.c203
-rw-r--r--StandaloneMmPkg/Core/Page.c384
-rw-r--r--StandaloneMmPkg/Core/Pool.c293
-rw-r--r--StandaloneMmPkg/Core/StandaloneMmCore.c712
-rw-r--r--StandaloneMmPkg/Core/StandaloneMmCore.h903
-rw-r--r--StandaloneMmPkg/Core/StandaloneMmCore.inf80
-rw-r--r--StandaloneMmPkg/Core/StandaloneMmCorePrivateData.h66
-rw-r--r--StandaloneMmPkg/Include/Guid/MmFvDispatch.h39
-rw-r--r--StandaloneMmPkg/Include/Library/StandaloneMmCoreEntryPoint.h101
-rw-r--r--StandaloneMmPkg/Include/StandaloneMm.h36
17 files changed, 5925 insertions, 0 deletions
diff --git a/StandaloneMmPkg/Core/Dependency.c b/StandaloneMmPkg/Core/Dependency.c
new file mode 100644
index 0000000000..365007d8ae
--- /dev/null
+++ b/StandaloneMmPkg/Core/Dependency.c
@@ -0,0 +1,389 @@
+/** @file
+ MM Driver 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) 2009 - 2010, Intel Corporation. All rights reserved.<BR>
+ Copyright (c) 2016 - 2018, ARM Limited. All rights reserved.<BR>
+ This program and the accompanying materials are licensed and made available
+ under the terms and conditions of the BSD License which accompanies this
+ distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "StandaloneMmCore.h"
+
+///
+/// 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
+
+//
+// Global stack used to evaluate dependency expressions
+//
+BOOLEAN *mDepexEvaluationStack = NULL;
+BOOLEAN *mDepexEvaluationStackEnd = NULL;
+BOOLEAN *mDepexEvaluationStackPointer = NULL;
+
+/**
+ 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;
+}
+
+/**
+ 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. 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
+MmIsSchedulable (
+ IN EFI_MM_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 MmInsertOnScheduledQueueWhileProcessingBeforeAndAfter ()
+ // processes them.
+ //
+ return FALSE;
+ }
+
+ DEBUG ((DEBUG_DISPATCH, "Evaluate MM DEPEX for FFS(%g)\n", &DriverEntry->FileName));
+
+ if (DriverEntry->Depex == NULL) {
+ //
+ // A NULL Depex means that the MM driver is not built correctly.
+ // All MM drivers must have a valid depex expressiion.
+ //
+ DEBUG ((DEBUG_DISPATCH, " RESULT = FALSE (Depex is empty)\n"));
+ ASSERT (FALSE);
+ return FALSE;
+ }
+
+ //
+ // 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_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 = MmLocateProtocol (&DriverGuid, NULL, &Interface);
+ if (EFI_ERROR (Status) && (mEfiSystemTable != NULL)) {
+ //
+ // For MM Driver, it may depend on uefi protocols
+ //
+ Status = mEfiSystemTable->BootServices->LocateProtocol (&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/StandaloneMmPkg/Core/Dispatcher.c b/StandaloneMmPkg/Core/Dispatcher.c
new file mode 100644
index 0000000000..8d009b4f80
--- /dev/null
+++ b/StandaloneMmPkg/Core/Dispatcher.c
@@ -0,0 +1,1071 @@
+/** @file
+ MM Driver Dispatcher.
+
+ Step #1 - When a FV protocol is added to the system every driver in the FV
+ is added to the mDiscoveredList. The 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 similar to the DXE dispatcher.
+
+ The rules for DXE dispatcher are in chapter 10 of the DXE CIS. Figure 10-3
+ is the state diagram for the DXE dispatcher
+
+ Depex - Dependency Expresion.
+
+ Copyright (c) 2014, Hewlett-Packard Development Company, L.P.
+ Copyright (c) 2009 - 2014, Intel Corporation. All rights reserved.<BR>
+ Copyright (c) 2016 - 2018, ARM Limited. All rights reserved.<BR>
+
+ This program and the accompanying materials are licensed and made available
+ under the terms and conditions of the BSD License which accompanies this
+ distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "StandaloneMmCore.h"
+
+//
+// MM Dispatcher Data structures
+//
+#define KNOWN_HANDLE_SIGNATURE SIGNATURE_32('k','n','o','w')
+
+typedef struct {
+ UINTN Signature;
+ LIST_ENTRY Link; // mFvHandleList
+ EFI_HANDLE Handle;
+} KNOWN_HANDLE;
+
+//
+// Function Prototypes
+//
+
+EFI_STATUS
+MmCoreFfsFindMmDriver (
+ IN EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader
+ );
+
+/**
+ 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
+MmInsertOnScheduledQueueWhileProcessingBeforeAndAfter (
+ IN EFI_MM_DRIVER_ENTRY *InsertedDriverEntry
+ );
+
+//
+// The Driver List contains one copy of every driver that has been discovered.
+// Items are never removed from the driver list. List of EFI_MM_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_MM_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);
+
+//
+// Flag for the MM Dispacher. TRUE if dispatcher is execuing.
+//
+BOOLEAN gDispatcherRunning = FALSE;
+
+//
+// Flag for the MM Dispacher. TRUE if there is one or more MM drivers ready to be dispatched
+//
+BOOLEAN gRequestDispatch = FALSE;
+
+//
+// The global variable is defined for Loading modules at fixed address feature to track the MM 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 *mMmCodeMemoryRangeUsageBitMap=NULL;
+
+/**
+ To check memory usage bit map array to figure out if the memory range in which the image will be loaded
+ is available or not. If memory range is avaliable, the function will mark the correponding 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 addres 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 MmCodePageNumber;
+ UINT64 MmCodeSize;
+ EFI_PHYSICAL_ADDRESS MmCodeBase;
+ UINTN BaseOffsetPageNumber;
+ UINTN TopOffsetPageNumber;
+ UINTN Index;
+
+ //
+ // Build tool will calculate the smm code size and then patch the PcdLoadFixAddressMmCodePageNumber
+ //
+ MmCodePageNumber = 0;
+ MmCodeSize = EFI_PAGES_TO_SIZE (MmCodePageNumber);
+ MmCodeBase = gLoadModuleAtFixAddressMmramBase;
+
+ //
+ // 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 (mMmCodeMemoryRangeUsageBitMap == NULL) {
+ mMmCodeMemoryRangeUsageBitMap = AllocateZeroPool (((MmCodePageNumber / 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 (mMmCodeMemoryRangeUsageBitMap == NULL) {
+ return EFI_NOT_FOUND;
+ }
+
+ //
+ // see if the memory range for loading the image is in the MM code range.
+ //
+ if (MmCodeBase + MmCodeSize < ImageBase + ImageSize || MmCodeBase > ImageBase) {
+ return EFI_NOT_FOUND;
+ }
+
+ //
+ // Test if the memory is avalaible or not.
+ //
+ BaseOffsetPageNumber = (UINTN)EFI_SIZE_TO_PAGES ((UINT32)(ImageBase - MmCodeBase));
+ TopOffsetPageNumber = (UINTN)EFI_SIZE_TO_PAGES ((UINT32)(ImageBase + ImageSize - MmCodeBase));
+ for (Index = BaseOffsetPageNumber; Index < TopOffsetPageNumber; Index ++) {
+ if ((mMmCodeMemoryRangeUsageBitMap[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 ++) {
+ mMmCodeMemoryRangeUsageBitMap[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 loadding 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;
+ EFI_PHYSICAL_ADDRESS FixLoadingAddress;
+ UINT16 Index;
+ UINTN Size;
+ UINT16 NumberOfSections;
+ UINT64 ValueInSectionHeader;
+
+ FixLoadingAddress = 0;
+ Status = EFI_NOT_FOUND;
+
+ //
+ // Get PeHeader pointer
+ //
+ ImgHdr = (EFI_IMAGE_OPTIONAL_HEADER_UNION *)((CHAR8* )ImageContext->Handle + 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;
+ }
+
+ 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. So there
+ // is an assumption that when the feature is enabled, if a module with a loading address
+ // assigned by tools, the 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) {
+ //
+ // Found first section header that doesn't point to code section in which build tool saves the
+ // offset to SMRAM base as image base in PointerToRelocations & PointerToLineNumbers fields
+ //
+ FixLoadingAddress = (EFI_PHYSICAL_ADDRESS)(gLoadModuleAtFixAddressMmramBase + (INT64)ValueInSectionHeader);
+ //
+ // Check if the memory range is available.
+ //
+ Status = CheckAndMarkFixLoadingMemoryUsageBitMap (FixLoadingAddress, (UINTN)(ImageContext->ImageSize + ImageContext->SectionAlignment));
+ if (!EFI_ERROR(Status)) {
+ //
+ // The assigned address is valid. Return the specified loading address
+ //
+ ImageContext->ImageAddress = FixLoadingAddress;
+ }
+ }
+ break;
+ }
+ SectionHeaderOffset += sizeof (EFI_IMAGE_SECTION_HEADER);
+ }
+ DEBUG ((DEBUG_INFO|DEBUG_LOAD, "LOADING MODULE FIXED INFO: Loading module at fixed address %x, Status = %r\n",
+ FixLoadingAddress, Status));
+ return Status;
+}
+/**
+ Loads an EFI image into SMRAM.
+
+ @param DriverEntry EFI_MM_DRIVER_ENTRY instance
+
+ @return EFI_STATUS
+
+**/
+EFI_STATUS
+EFIAPI
+MmLoadImage (
+ IN OUT EFI_MM_DRIVER_ENTRY *DriverEntry
+ )
+{
+ VOID *Buffer;
+ UINTN PageCount;
+ EFI_STATUS Status;
+ EFI_PHYSICAL_ADDRESS DstBuffer;
+ PE_COFF_LOADER_IMAGE_CONTEXT ImageContext;
+
+ DEBUG ((DEBUG_INFO, "MmLoadImage - %g\n", &DriverEntry->FileName));
+
+ Buffer = AllocateCopyPool (DriverEntry->Pe32DataSize, DriverEntry->Pe32Data);
+ if (Buffer == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ Status = EFI_SUCCESS;
+
+ //
+ // Initialize ImageContext
+ //
+ ImageContext.Handle = Buffer;
+ ImageContext.ImageRead = PeCoffLoaderImageReadFromMemory;
+
+ //
+ // Get information about the image being loaded
+ //
+ Status = PeCoffLoaderGetImageInfo (&ImageContext);
+ if (EFI_ERROR (Status)) {
+ if (Buffer != NULL) {
+ MmFreePool (Buffer);
+ }
+ return Status;
+ }
+
+ PageCount = (UINTN)EFI_SIZE_TO_PAGES ((UINTN)ImageContext.ImageSize + ImageContext.SectionAlignment);
+ DstBuffer = (UINTN)(-1);
+
+ Status = MmAllocatePages (
+ AllocateMaxAddress,
+ EfiRuntimeServicesCode,
+ PageCount,
+ &DstBuffer
+ );
+ if (EFI_ERROR (Status)) {
+ if (Buffer != NULL) {
+ MmFreePool (Buffer);
+ }
+ return Status;
+ }
+
+ ImageContext.ImageAddress = (EFI_PHYSICAL_ADDRESS)DstBuffer;
+
+ //
+ // Align buffer on section boundry
+ //
+ ImageContext.ImageAddress += ImageContext.SectionAlignment - 1;
+ ImageContext.ImageAddress &= ~((EFI_PHYSICAL_ADDRESS)(ImageContext.SectionAlignment - 1));
+
+ //
+ // Load the image to our new buffer
+ //
+ Status = PeCoffLoaderLoadImage (&ImageContext);
+ if (EFI_ERROR (Status)) {
+ if (Buffer != NULL) {
+ MmFreePool (Buffer);
+ }
+ MmFreePages (DstBuffer, PageCount);
+ return Status;
+ }
+
+ //
+ // Relocate the image in our new buffer
+ //
+ Status = PeCoffLoaderRelocateImage (&ImageContext);
+ if (EFI_ERROR (Status)) {
+ if (Buffer != NULL) {
+ MmFreePool (Buffer);
+ }
+ MmFreePages (DstBuffer, PageCount);
+ return Status;
+ }
+
+ //
+ // Flush the instruction cache so the image data are written before we execute it
+ //
+ InvalidateInstructionCacheRange ((VOID *)(UINTN) ImageContext.ImageAddress, (UINTN) ImageContext.ImageSize);
+
+ //
+ // Save Image EntryPoint in DriverEntry
+ //
+ DriverEntry->ImageEntryPoint = ImageContext.EntryPoint;
+ DriverEntry->ImageBuffer = DstBuffer;
+ DriverEntry->NumberOfPage = PageCount;
+
+ if (mEfiSystemTable != NULL) {
+ Status = mEfiSystemTable->BootServices->AllocatePool (
+ EfiBootServicesData,
+ sizeof (EFI_LOADED_IMAGE_PROTOCOL),
+ (VOID **)&DriverEntry->LoadedImage
+ );
+ if (EFI_ERROR (Status)) {
+ if (Buffer != NULL) {
+ MmFreePool (Buffer);
+ }
+ MmFreePages (DstBuffer, PageCount);
+ return Status;
+ }
+
+ ZeroMem (DriverEntry->LoadedImage, sizeof (EFI_LOADED_IMAGE_PROTOCOL));
+ //
+ // Fill in the remaining fields of the Loaded Image Protocol instance.
+ // Note: ImageBase is an SMRAM address that can not be accessed outside of SMRAM if SMRAM window is closed.
+ //
+ DriverEntry->LoadedImage->Revision = EFI_LOADED_IMAGE_PROTOCOL_REVISION;
+ DriverEntry->LoadedImage->ParentHandle = NULL;
+ DriverEntry->LoadedImage->SystemTable = mEfiSystemTable;
+ DriverEntry->LoadedImage->DeviceHandle = NULL;
+ DriverEntry->LoadedImage->FilePath = NULL;
+
+ DriverEntry->LoadedImage->ImageBase = (VOID *)(UINTN)DriverEntry->ImageBuffer;
+ DriverEntry->LoadedImage->ImageSize = ImageContext.ImageSize;
+ DriverEntry->LoadedImage->ImageCodeType = EfiRuntimeServicesCode;
+ DriverEntry->LoadedImage->ImageDataType = EfiRuntimeServicesData;
+
+ //
+ // Create a new image handle in the UEFI handle database for the MM Driver
+ //
+ DriverEntry->ImageHandle = NULL;
+ Status = mEfiSystemTable->BootServices->InstallMultipleProtocolInterfaces (
+ &DriverEntry->ImageHandle,
+ &gEfiLoadedImageProtocolGuid,
+ DriverEntry->LoadedImage,
+ NULL
+ );
+ }
+
+ //
+ // 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 MM driver at 0x%11p EntryPoint=0x%11p ",
+ (VOID *)(UINTN) ImageContext.ImageAddress,
+ FUNCTION_ENTRY_POINT (ImageContext.EntryPoint)));
+
+ //
+ // Print Module Name by Pdb file path.
+ // Windows and Unix style file path are all trimmed correctly.
+ //
+ if (ImageContext.PdbPointer != NULL) {
+ StartIndex = 0;
+ for (Index = 0; ImageContext.PdbPointer[Index] != 0; Index++) {
+ if ((ImageContext.PdbPointer[Index] == '\\') || (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] = 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));
+ }
+ DEBUG ((DEBUG_INFO | DEBUG_LOAD, "\n"));
+
+ DEBUG_CODE_END ();
+
+ //
+ // Free buffer allocated by Fv->ReadSection.
+ //
+ // The UEFI Boot Services FreePool() function must be used because Fv->ReadSection
+ // used the UEFI Boot Services AllocatePool() function
+ //
+ MmFreePool (Buffer);
+ return Status;
+}
+
+/**
+ Preprocess dependency expression and update DriverEntry to reflect the
+ state of Before and After dependencies. If DriverEntry->Before
+ or DriverEntry->After is set it will never be cleared.
+
+ @param DriverEntry DriverEntry element to update .
+
+ @retval EFI_SUCCESS It always works.
+
+**/
+EFI_STATUS
+MmPreProcessDepex (
+ IN EFI_MM_DRIVER_ENTRY *DriverEntry
+ )
+{
+ UINT8 *Iterator;
+
+ Iterator = DriverEntry->Depex;
+ 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;
+}
+
+/**
+ 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
+MmGetDepexSectionAndPreProccess (
+ IN EFI_MM_DRIVER_ENTRY *DriverEntry
+ )
+{
+ EFI_STATUS Status;
+
+ //
+ // Data already read
+ //
+ if (DriverEntry->Depex == NULL) {
+ Status = EFI_NOT_FOUND;
+ } else {
+ Status = EFI_SUCCESS;
+ }
+ 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 depend on all architectural protocols
+ //
+ DriverEntry->Depex = NULL;
+ DriverEntry->Dependent = TRUE;
+ DriverEntry->DepexProtocolError = FALSE;
+ }
+ } else {
+ //
+ // Set Before and After state information based on Depex
+ // Driver will be put in Dependent state
+ //
+ MmPreProcessDepex (DriverEntry);
+ DriverEntry->DepexProtocolError = FALSE;
+ }
+
+ return Status;
+}
+
+/**
+ This is the main Dispatcher for MM 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.
+
+ @retval EFI_SUCCESS All of the MM Drivers that could be dispatched
+ have been run and the MM Entry Point has been
+ registered.
+ @retval EFI_NOT_READY The MM Driver that registered the MM Entry Point
+ was just dispatched.
+ @retval EFI_NOT_FOUND There are no MM Drivers available to be dispatched.
+ @retval EFI_ALREADY_STARTED The MM Dispatcher is already running
+
+**/
+EFI_STATUS
+MmDispatcher (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ LIST_ENTRY *Link;
+ EFI_MM_DRIVER_ENTRY *DriverEntry;
+ BOOLEAN ReadyToRun;
+ BOOLEAN PreviousMmEntryPointRegistered;
+
+ DEBUG ((DEBUG_INFO, "MmDispatcher\n"));
+
+ if (!gRequestDispatch) {
+ DEBUG ((DEBUG_INFO, " !gRequestDispatch\n"));
+ return EFI_NOT_FOUND;
+ }
+
+ if (gDispatcherRunning) {
+ DEBUG ((DEBUG_INFO, " gDispatcherRunning\n"));
+ //
+ // If the dispatcher is running don't let it be restarted.
+ //
+ return EFI_ALREADY_STARTED;
+ }
+
+ gDispatcherRunning = TRUE;
+
+ do {
+ //
+ // Drain the Scheduled Queue
+ //
+ DEBUG ((DEBUG_INFO, " Drain the Scheduled Queue\n"));
+ while (!IsListEmpty (&mScheduledQueue)) {
+ DriverEntry = CR (
+ mScheduledQueue.ForwardLink,
+ EFI_MM_DRIVER_ENTRY,
+ ScheduledLink,
+ EFI_MM_DRIVER_ENTRY_SIGNATURE
+ );
+ DEBUG ((DEBUG_INFO, " DriverEntry (Scheduled) - %g\n", &DriverEntry->FileName));
+
+ //
+ // Load the MM 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) {
+ Status = MmLoadImage (DriverEntry);
+
+ //
+ // Update the driver state to reflect that it's been loaded
+ //
+ if (EFI_ERROR (Status)) {
+ //
+ // The MM Driver could not be loaded, and do not attempt to load or start it again.
+ // Take driver from Scheduled to Initialized.
+ //
+ DriverEntry->Initialized = TRUE;
+ DriverEntry->Scheduled = FALSE;
+ RemoveEntryList (&DriverEntry->ScheduledLink);
+
+ //
+ // If it's an error don't try the StartImage
+ //
+ continue;
+ }
+ }
+
+ DriverEntry->Scheduled = FALSE;
+ DriverEntry->Initialized = TRUE;
+ RemoveEntryList (&DriverEntry->ScheduledLink);
+
+ //
+ // Cache state of MmEntryPointRegistered before calling entry point
+ //
+ PreviousMmEntryPointRegistered = gMmCorePrivate->MmEntryPointRegistered;
+
+ //
+ // For each MM driver, pass NULL as ImageHandle
+ //
+ if (mEfiSystemTable == NULL) {
+ DEBUG ((DEBUG_INFO, "StartImage - 0x%x (Standalone Mode)\n", DriverEntry->ImageEntryPoint));
+ Status = ((MM_IMAGE_ENTRY_POINT)(UINTN)DriverEntry->ImageEntryPoint) (DriverEntry->ImageHandle, &gMmCoreMmst);
+ } else {
+ DEBUG ((DEBUG_INFO, "StartImage - 0x%x (Tradition Mode)\n", DriverEntry->ImageEntryPoint));
+ Status = ((EFI_IMAGE_ENTRY_POINT)(UINTN)DriverEntry->ImageEntryPoint) (
+ DriverEntry->ImageHandle,
+ mEfiSystemTable
+ );
+ }
+ if (EFI_ERROR(Status)) {
+ DEBUG ((DEBUG_INFO, "StartImage Status - %r\n", Status));
+ MmFreePages(DriverEntry->ImageBuffer, DriverEntry->NumberOfPage);
+ }
+
+ if (!PreviousMmEntryPointRegistered && gMmCorePrivate->MmEntryPointRegistered) {
+ //
+ // Return immediately if the MM Entry Point was registered by the MM
+ // Driver that was just dispatched. The MM IPL will reinvoke the MM
+ // Core Dispatcher. This is required so MM Mode may be enabled as soon
+ // as all the dependent MM Drivers for MM Mode have been dispatched.
+ // Once the MM Entry Point has been registered, then MM Mode will be
+ // used.
+ //
+ gRequestDispatch = TRUE;
+ gDispatcherRunning = FALSE;
+ return EFI_NOT_READY;
+ }
+ }
+
+ //
+ // Search DriverList for items to place on Scheduled Queue
+ //
+ DEBUG ((DEBUG_INFO, " Search DriverList for items to place on Scheduled Queue\n"));
+ ReadyToRun = FALSE;
+ for (Link = mDiscoveredList.ForwardLink; Link != &mDiscoveredList; Link = Link->ForwardLink) {
+ DriverEntry = CR (Link, EFI_MM_DRIVER_ENTRY, Link, EFI_MM_DRIVER_ENTRY_SIGNATURE);
+ DEBUG ((DEBUG_INFO, " DriverEntry (Discovered) - %g\n", &DriverEntry->FileName));
+
+ if (DriverEntry->DepexProtocolError) {
+ //
+ // If Section Extraction Protocol did not let the Depex be read before retry the read
+ //
+ Status = MmGetDepexSectionAndPreProccess (DriverEntry);
+ }
+
+ if (DriverEntry->Dependent) {
+ if (MmIsSchedulable (DriverEntry)) {
+ MmInsertOnScheduledQueueWhileProcessingBeforeAndAfter (DriverEntry);
+ ReadyToRun = TRUE;
+ }
+ }
+ }
+ } while (ReadyToRun);
+
+ //
+ // If there is no more MM driver to dispatch, stop the dispatch request
+ //
+ DEBUG ((DEBUG_INFO, " no more MM driver to dispatch, stop the dispatch request\n"));
+ gRequestDispatch = FALSE;
+ for (Link = mDiscoveredList.ForwardLink; Link != &mDiscoveredList; Link = Link->ForwardLink) {
+ DriverEntry = CR (Link, EFI_MM_DRIVER_ENTRY, Link, EFI_MM_DRIVER_ENTRY_SIGNATURE);
+ DEBUG ((DEBUG_INFO, " DriverEntry (Discovered) - %g\n", &DriverEntry->FileName));
+
+ if (!DriverEntry->Initialized) {
+ //
+ // We have MM driver pending to dispatch
+ //
+ gRequestDispatch = TRUE;
+ break;
+ }
+ }
+
+ gDispatcherRunning = FALSE;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ 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
+MmInsertOnScheduledQueueWhileProcessingBeforeAndAfter (
+ IN EFI_MM_DRIVER_ENTRY *InsertedDriverEntry
+ )
+{
+ LIST_ENTRY *Link;
+ EFI_MM_DRIVER_ENTRY *DriverEntry;
+
+ //
+ // Process Before Dependency
+ //
+ for (Link = mDiscoveredList.ForwardLink; Link != &mDiscoveredList; Link = Link->ForwardLink) {
+ DriverEntry = CR(Link, EFI_MM_DRIVER_ENTRY, Link, EFI_MM_DRIVER_ENTRY_SIGNATURE);
+ if (DriverEntry->Before && DriverEntry->Dependent && DriverEntry != InsertedDriverEntry) {
+ DEBUG ((DEBUG_DISPATCH, "Evaluate MM 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"));
+ MmInsertOnScheduledQueueWhileProcessingBeforeAndAfter (DriverEntry);
+ } else {
+ DEBUG ((DEBUG_DISPATCH, "FALSE\n END\n RESULT = FALSE\n"));
+ }
+ }
+ }
+
+ //
+ // Convert driver from Dependent to Scheduled state
+ //
+
+ InsertedDriverEntry->Dependent = FALSE;
+ InsertedDriverEntry->Scheduled = TRUE;
+ InsertTailList (&mScheduledQueue, &InsertedDriverEntry->ScheduledLink);
+
+
+ //
+ // Process After Dependency
+ //
+ for (Link = mDiscoveredList.ForwardLink; Link != &mDiscoveredList; Link = Link->ForwardLink) {
+ DriverEntry = CR(Link, EFI_MM_DRIVER_ENTRY, Link, EFI_MM_DRIVER_ENTRY_SIGNATURE);
+ if (DriverEntry->After && DriverEntry->Dependent && DriverEntry != InsertedDriverEntry) {
+ DEBUG ((DEBUG_DISPATCH, "Evaluate MM 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"));
+ MmInsertOnScheduledQueueWhileProcessingBeforeAndAfter (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. Items are
+ never removed/freed from the mFvHandleList.
+
+ @param FvHandle The handle of a FV that has been processed
+
+**/
+VOID
+FvIsBeingProcesssed (
+ IN EFI_HANDLE FvHandle
+ )
+{
+ KNOWN_HANDLE *KnownHandle;
+
+ DEBUG ((DEBUG_INFO, "FvIsBeingProcesssed - 0x%08x\n", FvHandle));
+
+ KnownHandle = AllocatePool (sizeof (KNOWN_HANDLE));
+ ASSERT (KnownHandle != NULL);
+
+ KnownHandle->Signature = KNOWN_HANDLE_SIGNATURE;
+ KnownHandle->Handle = FvHandle;
+ InsertTailList (&mFvHandleList, &KnownHandle->Link);
+}
+
+/**
+ 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 Before and After state.
+ The Discovered list is never free'ed and contains booleans that represent the
+ other possible MM driver states.
+
+ @param Fv Fv protocol, needed to read Depex info out of
+ FLASH.
+ @param FvHandle Handle for Fv, needed in the
+ EFI_MM_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.
+
+ @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
+MmAddToDriverList (
+ IN EFI_HANDLE FvHandle,
+ IN VOID *Pe32Data,
+ IN UINTN Pe32DataSize,
+ IN VOID *Depex,
+ IN UINTN DepexSize,
+ IN EFI_GUID *DriverName
+ )
+{
+ EFI_MM_DRIVER_ENTRY *DriverEntry;
+
+ DEBUG ((DEBUG_INFO, "MmAddToDriverList - %g (0x%08x)\n", DriverName, Pe32Data));
+
+ //
+ // Create the Driver Entry for the list. ZeroPool initializes lots of variables to
+ // NULL or FALSE.
+ //
+ DriverEntry = AllocateZeroPool (sizeof (EFI_MM_DRIVER_ENTRY));
+ ASSERT (DriverEntry != NULL);
+
+ DriverEntry->Signature = EFI_MM_DRIVER_ENTRY_SIGNATURE;
+ CopyGuid (&DriverEntry->FileName, DriverName);
+ DriverEntry->FvHandle = FvHandle;
+ DriverEntry->Pe32Data = Pe32Data;
+ DriverEntry->Pe32DataSize = Pe32DataSize;
+ DriverEntry->Depex = Depex;
+ DriverEntry->DepexSize = DepexSize;
+
+ MmGetDepexSectionAndPreProccess (DriverEntry);
+
+ InsertTailList (&mDiscoveredList, &DriverEntry->Link);
+ gRequestDispatch = TRUE;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ This function is the main entry point for an MM handler dispatch
+ or communicate-based callback.
+
+ 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 MmLocateHandle () 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 MM 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 DispatchHandle The unique handle assigned to this handler by SmiHandlerRegister().
+ @param Context Points to an optional handler context which was specified when the handler was registered.
+ @param CommBuffer A pointer to a collection of data in memory that will
+ be conveyed from a non-MM environment into an MM environment.
+ @param CommBufferSize The size of the CommBuffer.
+
+ @return Status Code
+
+**/
+EFI_STATUS
+EFIAPI
+MmDriverDispatchHandler (
+ IN EFI_HANDLE DispatchHandle,
+ IN CONST VOID *Context, OPTIONAL
+ IN OUT VOID *CommBuffer, OPTIONAL
+ IN OUT UINTN *CommBufferSize OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+
+ DEBUG ((DEBUG_INFO, "MmDriverDispatchHandler\n"));
+
+ //
+ // Execute the MM Dispatcher on any newly discovered FVs and previously
+ // discovered MM drivers that have been discovered but not dispatched.
+ //
+ Status = MmDispatcher ();
+
+ //
+ // Check to see if CommBuffer and CommBufferSize are valid
+ //
+ if (CommBuffer != NULL && CommBufferSize != NULL) {
+ if (*CommBufferSize > 0) {
+ if (Status == EFI_NOT_READY) {
+ //
+ // If a the MM Core Entry Point was just registered, then set flag to
+ // request the MM Dispatcher to be restarted.
+ //
+ *(UINT8 *)CommBuffer = COMM_BUFFER_MM_DISPATCH_RESTART;
+ } else if (!EFI_ERROR (Status)) {
+ //
+ // Set the flag to show that the MM Dispatcher executed without errors
+ //
+ *(UINT8 *)CommBuffer = COMM_BUFFER_MM_DISPATCH_SUCCESS;
+ } else {
+ //
+ // Set the flag to show that the MM Dispatcher encountered an error
+ //
+ *(UINT8 *)CommBuffer = COMM_BUFFER_MM_DISPATCH_ERROR;
+ }
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ This function is the main entry point for an MM handler dispatch
+ or communicate-based callback.
+
+ @param DispatchHandle The unique handle assigned to this handler by SmiHandlerRegister().
+ @param Context Points to an optional handler context which was specified when the handler was registered.
+ @param CommBuffer A pointer to a collection of data in memory that will
+ be conveyed from a non-MM environment into an MM environment.
+ @param CommBufferSize The size of the CommBuffer.
+
+ @return Status Code
+
+**/
+EFI_STATUS
+EFIAPI
+MmFvDispatchHandler (
+ IN EFI_HANDLE DispatchHandle,
+ IN CONST VOID *Context, OPTIONAL
+ IN OUT VOID *CommBuffer, OPTIONAL
+ IN OUT UINTN *CommBufferSize OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+ EFI_MM_COMMUNICATE_FV_DISPATCH_DATA *CommunicationFvDispatchData;
+ EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader;
+
+ DEBUG ((DEBUG_INFO, "MmFvDispatchHandler\n"));
+
+ CommunicationFvDispatchData = CommBuffer;
+
+ DEBUG ((DEBUG_INFO, " Dispatch - 0x%016lx - 0x%016lx\n", CommunicationFvDispatchData->Address,
+ CommunicationFvDispatchData->Size));
+
+ FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *)(UINTN)CommunicationFvDispatchData->Address;
+
+ MmCoreFfsFindMmDriver (FwVolHeader);
+
+ //
+ // Execute the MM Dispatcher on any newly discovered FVs and previously
+ // discovered MM drivers that have been discovered but not dispatched.
+ //
+ Status = MmDispatcher ();
+
+ return Status;
+}
+
+/**
+ Traverse the discovered list for any drivers that were discovered but not loaded
+ because the dependency experessions evaluated to false.
+
+**/
+VOID
+MmDisplayDiscoveredNotDispatched (
+ VOID
+ )
+{
+ LIST_ENTRY *Link;
+ EFI_MM_DRIVER_ENTRY *DriverEntry;
+
+ for (Link = mDiscoveredList.ForwardLink;Link !=&mDiscoveredList; Link = Link->ForwardLink) {
+ DriverEntry = CR (Link, EFI_MM_DRIVER_ENTRY, Link, EFI_MM_DRIVER_ENTRY_SIGNATURE);
+ if (DriverEntry->Dependent) {
+ DEBUG ((DEBUG_LOAD, "MM Driver %g was discovered but not loaded!!\n", &DriverEntry->FileName));
+ }
+ }
+}
diff --git a/StandaloneMmPkg/Core/FwVol.c b/StandaloneMmPkg/Core/FwVol.c
new file mode 100644
index 0000000000..5abf98c247
--- /dev/null
+++ b/StandaloneMmPkg/Core/FwVol.c
@@ -0,0 +1,104 @@
+/**@file
+
+Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
+Copyright (c) 2016 - 2018, ARM Limited. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "StandaloneMmCore.h"
+#include <Library/FvLib.h>
+
+//
+// List of file types supported by dispatcher
+//
+EFI_FV_FILETYPE mMmFileTypes[] = {
+ EFI_FV_FILETYPE_MM,
+ 0xE, //EFI_FV_FILETYPE_MM_STANDALONE,
+ //
+ // Note: DXE core will process the FV image file, so skip it in MM core
+ // EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE
+ //
+};
+
+EFI_STATUS
+MmAddToDriverList (
+ IN EFI_HANDLE FvHandle,
+ IN VOID *Pe32Data,
+ IN UINTN Pe32DataSize,
+ IN VOID *Depex,
+ IN UINTN DepexSize,
+ IN EFI_GUID *DriverName
+ );
+
+BOOLEAN
+FvHasBeenProcessed (
+ IN EFI_HANDLE FvHandle
+ );
+
+VOID
+FvIsBeingProcesssed (
+ IN EFI_HANDLE FvHandle
+ );
+
+EFI_STATUS
+MmCoreFfsFindMmDriver (
+ IN EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader
+ )
+/*++
+
+Routine Description:
+ Given the pointer to the Firmware Volume Header find the
+ MM driver and return it's PE32 image.
+
+Arguments:
+ FwVolHeader - Pointer to memory mapped FV
+
+Returns:
+ other - Failure
+
+--*/
+{
+ EFI_STATUS Status;
+ EFI_STATUS DepexStatus;
+ EFI_FFS_FILE_HEADER *FileHeader;
+ EFI_FV_FILETYPE FileType;
+ VOID *Pe32Data;
+ UINTN Pe32DataSize;
+ VOID *Depex;
+ UINTN DepexSize;
+ UINTN Index;
+
+ DEBUG ((DEBUG_INFO, "MmCoreFfsFindMmDriver - 0x%x\n", FwVolHeader));
+
+ if (FvHasBeenProcessed (FwVolHeader)) {
+ return EFI_SUCCESS;
+ }
+
+ FvIsBeingProcesssed (FwVolHeader);
+
+ for (Index = 0; Index < sizeof (mMmFileTypes) / sizeof (mMmFileTypes[0]); Index++) {
+ DEBUG ((DEBUG_INFO, "Check MmFileTypes - 0x%x\n", mMmFileTypes[Index]));
+ FileType = mMmFileTypes[Index];
+ FileHeader = NULL;
+ do {
+ Status = FfsFindNextFile (FileType, FwVolHeader, &FileHeader);
+ if (!EFI_ERROR (Status)) {
+ Status = FfsFindSectionData (EFI_SECTION_PE32, FileHeader, &Pe32Data, &Pe32DataSize);
+ DEBUG ((DEBUG_INFO, "Find PE data - 0x%x\n", Pe32Data));
+ DepexStatus = FfsFindSectionData (EFI_SECTION_MM_DEPEX, FileHeader, &Depex, &DepexSize);
+ if (!EFI_ERROR (DepexStatus)) {
+ MmAddToDriverList (FwVolHeader, Pe32Data, Pe32DataSize, Depex, DepexSize, &FileHeader->Name);
+ }
+ }
+ } while (!EFI_ERROR (Status));
+ }
+
+ return Status;
+}
diff --git a/StandaloneMmPkg/Core/Handle.c b/StandaloneMmPkg/Core/Handle.c
new file mode 100644
index 0000000000..70d59fe15d
--- /dev/null
+++ b/StandaloneMmPkg/Core/Handle.c
@@ -0,0 +1,533 @@
+/** @file
+ SMM handle & protocol handling.
+
+ Copyright (c) 2009 - 2010, Intel Corporation. All rights reserved.<BR>
+ Copyright (c) 2016 - 2018, ARM Limited. All rights reserved.<BR>
+ This program and the accompanying materials are licensed and made available
+ under the terms and conditions of the BSD License which accompanies this
+ distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "StandaloneMmCore.h"
+
+//
+// mProtocolDatabase - A list of all protocols in the system. (simple list for now)
+// gHandleList - A list of all the handles in the system
+//
+LIST_ENTRY mProtocolDatabase = INITIALIZE_LIST_HEAD_VARIABLE (mProtocolDatabase);
+LIST_ENTRY gHandleList = INITIALIZE_LIST_HEAD_VARIABLE (gHandleList);
+
+/**
+ 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
+MmValidateHandle (
+ IN EFI_HANDLE UserHandle
+ )
+{
+ IHANDLE *Handle;
+
+ Handle = (IHANDLE *)UserHandle;
+ if (Handle == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+ if (Handle->Signature != EFI_HANDLE_SIGNATURE) {
+ return EFI_INVALID_PARAMETER;
+ }
+ return EFI_SUCCESS;
+}
+
+/**
+ Finds the protocol entry for the requested protocol.
+
+ @param Protocol The ID of the protocol
+ @param Create Create a new entry if not found
+
+ @return Protocol entry
+
+**/
+PROTOCOL_ENTRY *
+MmFindProtocolEntry (
+ IN EFI_GUID *Protocol,
+ IN BOOLEAN Create
+ )
+{
+ LIST_ENTRY *Link;
+ PROTOCOL_ENTRY *Item;
+ PROTOCOL_ENTRY *ProtEntry;
+
+ //
+ // 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 *
+MmFindProtocolInterface (
+ IN IHANDLE *Handle,
+ IN EFI_GUID *Protocol,
+ IN VOID *Interface
+ )
+{
+ PROTOCOL_INTERFACE *Prot;
+ PROTOCOL_ENTRY *ProtEntry;
+ LIST_ENTRY *Link;
+
+ Prot = NULL;
+
+ //
+ // Lookup the protocol entry for this protocol ID
+ //
+ ProtEntry = MmFindProtocolEntry (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;
+}
+
+/**
+ Wrapper function to MmInstallProtocolInterfaceNotify. 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
+MmInstallProtocolInterface (
+ IN OUT EFI_HANDLE *UserHandle,
+ IN EFI_GUID *Protocol,
+ IN EFI_INTERFACE_TYPE InterfaceType,
+ IN VOID *Interface
+ )
+{
+ return MmInstallProtocolInterfaceNotify (
+ 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
+MmInstallProtocolInterfaceNotify (
+ 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_LOAD | DEBUG_INFO, "MmInstallProtocolInterface: %g %p\n", Protocol, Interface));
+
+ Status = EFI_OUT_OF_RESOURCES;
+ Prot = NULL;
+ Handle = NULL;
+
+ if (*UserHandle != NULL) {
+ Status = MmHandleProtocol (*UserHandle, Protocol, (VOID **)&ExistingInterface);
+ if (!EFI_ERROR (Status)) {
+ return EFI_INVALID_PARAMETER;
+ }
+ }
+
+ //
+ // Lookup the Protocol Entry for the requested protocol
+ //
+ ProtEntry = MmFindProtocolEntry (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);
+
+ //
+ // Add this handle to the list global list of all handles
+ // in the system
+ //
+ InsertTailList (&gHandleList, &Handle->AllHandles);
+ }
+
+ Status = MmValidateHandle (Handle);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ //
+ // Each interface that is added must be unique
+ //
+ ASSERT (MmFindProtocolInterface (Handle, Protocol, Interface) == NULL);
+
+ //
+ // Initialize the protocol interface structure
+ //
+ Prot->Signature = PROTOCOL_INTERFACE_SIGNATURE;
+ Prot->Handle = Handle;
+ Prot->Protocol = ProtEntry;
+ Prot->Interface = Interface;
+
+ //
+ // 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) {
+ MmNotifyProtocol (Prot);
+ }
+ Status = EFI_SUCCESS;
+
+Done:
+ if (!EFI_ERROR (Status)) {
+ //
+ // Return the new handle back to the caller
+ //
+ *UserHandle = Handle;
+ } else {
+ //
+ // There was an error, clean up
+ //
+ if (Prot != NULL) {
+ FreePool (Prot);
+ }
+ }
+ 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
+MmUninstallProtocolInterface (
+ 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 = MmValidateHandle (UserHandle);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Check that Protocol exists on UserHandle, and Interface matches the interface in the database
+ //
+ Prot = MmFindProtocolInterface (UserHandle, Protocol, Interface);
+ if (Prot == NULL) {
+ return EFI_NOT_FOUND;
+ }
+
+ //
+ // Remove the protocol interface from the protocol
+ //
+ Status = EFI_NOT_FOUND;
+ Handle = (IHANDLE *)UserHandle;
+ Prot = MmRemoveInterfaceFromProtocol (Handle, Protocol, Interface);
+
+ if (Prot != NULL) {
+ //
+ // Remove the protocol interface from the handle
+ //
+ RemoveEntryList (&Prot->Link);
+
+ //
+ // Free the memory
+ //
+ Prot->Signature = 0;
+ FreePool (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);
+ FreePool (Handle);
+ }
+ 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 *
+MmGetProtocolInterface (
+ IN EFI_HANDLE UserHandle,
+ IN EFI_GUID *Protocol
+ )
+{
+ EFI_STATUS Status;
+ PROTOCOL_ENTRY *ProtEntry;
+ PROTOCOL_INTERFACE *Prot;
+ IHANDLE *Handle;
+ LIST_ENTRY *Link;
+
+ Status = MmValidateHandle (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 not a valid EFI_HANDLE..
+ @retval EFI_INVALID_PARAMETER Protocol is NULL.
+ @retval EFI_INVALID_PARAMETER Interface is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+MmHandleProtocol (
+ IN EFI_HANDLE UserHandle,
+ IN EFI_GUID *Protocol,
+ OUT VOID **Interface
+ )
+{
+ EFI_STATUS Status;
+ PROTOCOL_INTERFACE *Prot;
+
+ //
+ // Check for invalid Protocol
+ //
+ if (Protocol == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Check for invalid Interface
+ //
+ if (Interface == NULL) {
+ return EFI_INVALID_PARAMETER;
+ } else {
+ *Interface = NULL;
+ }
+
+ //
+ // Check for invalid UserHandle
+ //
+ Status = MmValidateHandle (UserHandle);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Look at each protocol interface for a match
+ //
+ Prot = MmGetProtocolInterface (UserHandle, Protocol);
+ if (Prot == NULL) {
+ return EFI_UNSUPPORTED;
+ }
+
+ //
+ // This is the protocol interface entry for this protocol
+ //
+ *Interface = Prot->Interface;
+
+ return EFI_SUCCESS;
+}
diff --git a/StandaloneMmPkg/Core/InstallConfigurationTable.c b/StandaloneMmPkg/Core/InstallConfigurationTable.c
new file mode 100644
index 0000000000..2392be9958
--- /dev/null
+++ b/StandaloneMmPkg/Core/InstallConfigurationTable.c
@@ -0,0 +1,178 @@
+/** @file
+ System Management System Table Services MmInstallConfigurationTable service
+
+ Copyright (c) 2009 - 2017, Intel Corporation. All rights reserved.<BR>
+ Copyright (c) 2016 - 2018, ARM Limited. All rights reserved.<BR>
+ This program and the accompanying materials are licensed and made available
+ under the terms and conditions of the BSD License which accompanies this
+ distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "StandaloneMmCore.h"
+
+#define CONFIG_TABLE_SIZE_INCREASED 0x10
+
+UINTN mMmSystemTableAllocateSize = 0;
+
+/**
+ The MmInstallConfigurationTable() function is used to maintain the list
+ of configuration tables that are stored in the System Management System
+ Table. The list is stored as an array of (GUID, Pointer) pairs. The list
+ must be allocated from pool memory with PoolType set to EfiRuntimeServicesData.
+
+ @param SystemTable A pointer to the SMM System Table (SMST).
+ @param Guid A pointer to the GUID for the entry to add, update, or remove.
+ @param Table A pointer to the buffer of the table to add.
+ @param TableSize The size of the table to install.
+
+ @retval EFI_SUCCESS The (Guid, Table) pair was added, updated, or removed.
+ @retval EFI_INVALID_PARAMETER Guid is not valid.
+ @retval EFI_NOT_FOUND An attempt was made to delete a non-existent entry.
+ @retval EFI_OUT_OF_RESOURCES There is not enough memory available to complete the operation.
+
+**/
+EFI_STATUS
+EFIAPI
+MmInstallConfigurationTable (
+ IN CONST EFI_MM_SYSTEM_TABLE *SystemTable,
+ IN CONST EFI_GUID *Guid,
+ IN VOID *Table,
+ IN UINTN TableSize
+ )
+{
+ UINTN Index;
+ EFI_CONFIGURATION_TABLE *ConfigurationTable;
+ EFI_CONFIGURATION_TABLE *OldTable;
+
+ //
+ // If Guid is NULL, then this operation cannot be performed
+ //
+ if (Guid == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ ConfigurationTable = gMmCoreMmst.MmConfigurationTable;
+
+ //
+ // Search all the table for an entry that matches Guid
+ //
+ for (Index = 0; Index < gMmCoreMmst.NumberOfTableEntries; Index++) {
+ if (CompareGuid (Guid, &(ConfigurationTable[Index].VendorGuid))) {
+ break;
+ }
+ }
+
+ if (Index < gMmCoreMmst.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.
+ //
+ ConfigurationTable[Index].VendorTable = Table;
+ return EFI_SUCCESS;
+ }
+
+ //
+ // A match was found and Table is NULL, so this is a delete operation.
+ //
+ gMmCoreMmst.NumberOfTableEntries--;
+
+ //
+ // Copy over deleted entry
+ //
+ CopyMem (
+ &(ConfigurationTable[Index]),
+ &(ConfigurationTable[Index + 1]),
+ (gMmCoreMmst.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 == gMmCoreMmst.NumberOfTableEntries
+ //
+ if ((Index * sizeof (EFI_CONFIGURATION_TABLE)) >= mMmSystemTableAllocateSize) {
+ //
+ // Allocate a table with one additional entry.
+ //
+ mMmSystemTableAllocateSize += (CONFIG_TABLE_SIZE_INCREASED * sizeof (EFI_CONFIGURATION_TABLE));
+ ConfigurationTable = AllocatePool (mMmSystemTableAllocateSize);
+ if (ConfigurationTable == NULL) {
+ //
+ // If a new table could not be allocated, then return an error.
+ //
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ if (gMmCoreMmst.MmConfigurationTable != NULL) {
+ //
+ // Copy the old table to the new table.
+ //
+ CopyMem (
+ ConfigurationTable,
+ gMmCoreMmst.MmConfigurationTable,
+ Index * sizeof (EFI_CONFIGURATION_TABLE)
+ );
+
+ //
+ // Record the old table pointer.
+ //
+ OldTable = gMmCoreMmst.MmConfigurationTable;
+
+ //
+ // As the MmInstallConfigurationTable() may be re-entered by FreePool() in
+ // its calling stack, updating System table to the new table pointer must
+ // be done before calling FreePool() to free the old table.
+ // It can make sure the gMmCoreMmst.MmConfigurationTable point to the new
+ // table and avoid the errors of use-after-free to the old table by the
+ // reenter of MmInstallConfigurationTable() in FreePool()'s calling stack.
+ //
+ gMmCoreMmst.MmConfigurationTable = ConfigurationTable;
+
+ //
+ // Free the old table after updating System Table to the new table pointer.
+ //
+ FreePool (OldTable);
+ } else {
+ //
+ // Update System Table
+ //
+ gMmCoreMmst.MmConfigurationTable = ConfigurationTable;
+ }
+ }
+
+ //
+ // Fill in the new entry
+ //
+ CopyGuid ((VOID *)&ConfigurationTable[Index].VendorGuid, Guid);
+ ConfigurationTable[Index].VendorTable = Table;
+
+ //
+ // This is an add operation, so increment the number of table entries
+ //
+ gMmCoreMmst.NumberOfTableEntries++;
+ }
+
+ //
+ // CRC-32 field is ignorable for SMM System Table and should be set to zero
+ //
+
+ return EFI_SUCCESS;
+}
diff --git a/StandaloneMmPkg/Core/Locate.c b/StandaloneMmPkg/Core/Locate.c
new file mode 100644
index 0000000000..9129718723
--- /dev/null
+++ b/StandaloneMmPkg/Core/Locate.c
@@ -0,0 +1,496 @@
+/** @file
+ Locate handle functions
+
+ Copyright (c) 2009 - 2017, Intel Corporation. All rights reserved.<BR>
+ Copyright (c) 2016 - 2018, ARM Limited. All rights reserved.<BR>
+ This program and the accompanying materials are licensed and made available
+ under the terms and conditions of the BSD License which accompanies this
+ distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "StandaloneMmCore.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 *
+MmGetNextLocateAllHandles (
+ 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 *
+MmGetNextLocateByRegisterNotify (
+ 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 *
+MmGetNextLocateByProtocol (
+ 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;
+}
+
+/**
+ Return the first Protocol Interface that matches the Protocol GUID. If
+ Registration is pasased in return a Protocol Instance that was just add
+ to the system. If Retistration 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
+MmLocateProtocol (
+ 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;
+
+ mEfiLocateHandleRequest += 1;
+
+ if (Registration == NULL) {
+ //
+ // Look up the protocol entry and set the head pointer
+ //
+ Position.ProtEntry = MmFindProtocolEntry (Protocol, FALSE);
+ if (Position.ProtEntry == NULL) {
+ return EFI_NOT_FOUND;
+ }
+ Position.Position = &Position.ProtEntry->Protocols;
+
+ Handle = MmGetNextLocateByProtocol (&Position, Interface);
+ } else {
+ Handle = MmGetNextLocateByRegisterNotify (&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;
+ }
+
+ return Status;
+}
+
+/**
+ 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
+MmLocateHandle (
+ 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;
+
+ //
+ // Get the search function based on type
+ //
+ switch (SearchType) {
+ case AllHandles:
+ GetNext = MmGetNextLocateAllHandles;
+ break;
+
+ case ByRegisterNotify:
+ GetNext = MmGetNextLocateByRegisterNotify;
+ //
+ // Must have SearchKey for locate ByRegisterNotify
+ //
+ if (SearchKey == NULL) {
+ Status = EFI_INVALID_PARAMETER;
+ }
+ break;
+
+ case ByProtocol:
+ GetNext = MmGetNextLocateByProtocol;
+ if (Protocol == NULL) {
+ Status = EFI_INVALID_PARAMETER;
+ break;
+ }
+ //
+ // Look up the protocol entry and set the head pointer
+ //
+ Position.ProtEntry = MmFindProtocolEntry (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)) {
+ return Status;
+ }
+
+ //
+ // 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)) {
+ ASSERT (SearchKey != NULL);
+ //
+ // If this is a search by register notify and a handle was
+ // returned, update the register notification position
+ //
+ ProtNotify = SearchKey;
+ ProtNotify->Position = ProtNotify->Position->ForwardLink;
+ }
+ }
+
+ return Status;
+}
+
+/**
+ Function returns an array of handles that support the requested protocol
+ in a buffer allocated from pool. This is a version of MmLocateHandle()
+ 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
+MmLocateHandleBuffer (
+ 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 = MmLocateHandle (
+ SearchType,
+ Protocol,
+ SearchKey,
+ &BufferSize,
+ *Buffer
+ );
+ //
+ // LocateHandleBuffer() returns incorrect status code if SearchType is
+ // invalid.
+ //
+ // Add code to correctly handle expected errors from MmLocateHandle().
+ //
+ 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 = MmLocateHandle (
+ SearchType,
+ Protocol,
+ SearchKey,
+ &BufferSize,
+ *Buffer
+ );
+
+ *NumberHandles = BufferSize / sizeof(EFI_HANDLE);
+ if (EFI_ERROR (Status)) {
+ *NumberHandles = 0;
+ }
+
+ return Status;
+}
diff --git a/StandaloneMmPkg/Core/Mmi.c b/StandaloneMmPkg/Core/Mmi.c
new file mode 100644
index 0000000000..7193ebcd15
--- /dev/null
+++ b/StandaloneMmPkg/Core/Mmi.c
@@ -0,0 +1,337 @@
+/** @file
+ MMI management.
+
+ Copyright (c) 2009 - 2013, Intel Corporation. All rights reserved.<BR>
+ Copyright (c) 2016 - 2018, ARM Limited. All rights reserved.<BR>
+ This program and the accompanying materials are licensed and made available
+ under the terms and conditions of the BSD License which accompanies this
+ distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "StandaloneMmCore.h"
+
+//
+// MM_HANDLER_STATE_NOTIFIER
+//
+
+//
+// MM_HANDLER - used for each MM handler
+//
+
+#define MMI_ENTRY_SIGNATURE SIGNATURE_32('m','m','i','e')
+
+typedef struct {
+ UINTN Signature;
+ LIST_ENTRY AllEntries; // All entries
+
+ EFI_GUID HandlerType; // Type of interrupt
+ LIST_ENTRY MmiHandlers; // All handlers
+} MMI_ENTRY;
+
+#define MMI_HANDLER_SIGNATURE SIGNATURE_32('m','m','i','h')
+
+typedef struct {
+ UINTN Signature;
+ LIST_ENTRY Link; // Link on MMI_ENTRY.MmiHandlers
+ EFI_MM_HANDLER_ENTRY_POINT Handler; // The mm handler's entry point
+ MMI_ENTRY *MmiEntry;
+} MMI_HANDLER;
+
+LIST_ENTRY mRootMmiHandlerList = INITIALIZE_LIST_HEAD_VARIABLE (mRootMmiHandlerList);
+LIST_ENTRY mMmiEntryList = INITIALIZE_LIST_HEAD_VARIABLE (mMmiEntryList);
+
+/**
+ Finds the MMI entry for the requested handler type.
+
+ @param HandlerType The type of the interrupt
+ @param Create Create a new entry if not found
+
+ @return MMI entry
+
+**/
+MMI_ENTRY *
+EFIAPI
+MmCoreFindMmiEntry (
+ IN EFI_GUID *HandlerType,
+ IN BOOLEAN Create
+ )
+{
+ LIST_ENTRY *Link;
+ MMI_ENTRY *Item;
+ MMI_ENTRY *MmiEntry;
+
+ //
+ // Search the MMI entry list for the matching GUID
+ //
+ MmiEntry = NULL;
+ for (Link = mMmiEntryList.ForwardLink;
+ Link != &mMmiEntryList;
+ Link = Link->ForwardLink) {
+
+ Item = CR (Link, MMI_ENTRY, AllEntries, MMI_ENTRY_SIGNATURE);
+ if (CompareGuid (&Item->HandlerType, HandlerType)) {
+ //
+ // This is the MMI entry
+ //
+ MmiEntry = Item;
+ break;
+ }
+ }
+
+ //
+ // If the protocol entry was not found and Create is TRUE, then
+ // allocate a new entry
+ //
+ if ((MmiEntry == NULL) && Create) {
+ MmiEntry = AllocatePool (sizeof (MMI_ENTRY));
+ if (MmiEntry != NULL) {
+ //
+ // Initialize new MMI entry structure
+ //
+ MmiEntry->Signature = MMI_ENTRY_SIGNATURE;
+ CopyGuid ((VOID *)&MmiEntry->HandlerType, HandlerType);
+ InitializeListHead (&MmiEntry->MmiHandlers);
+
+ //
+ // Add it to MMI entry list
+ //
+ InsertTailList (&mMmiEntryList, &MmiEntry->AllEntries);
+ }
+ }
+ return MmiEntry;
+}
+
+/**
+ Manage MMI of a particular type.
+
+ @param HandlerType Points to the handler type or NULL for root MMI handlers.
+ @param Context Points to an optional context buffer.
+ @param CommBuffer Points to the optional communication buffer.
+ @param CommBufferSize Points to the size of the optional communication buffer.
+
+ @retval EFI_WARN_INTERRUPT_SOURCE_PENDING Interrupt source was processed successfully but not quiesced.
+ @retval EFI_INTERRUPT_PENDING One or more MMI sources could not be quiesced.
+ @retval EFI_NOT_FOUND Interrupt source was not handled or quiesced.
+ @retval EFI_SUCCESS Interrupt source was handled and quiesced.
+
+**/
+EFI_STATUS
+EFIAPI
+MmiManage (
+ IN CONST EFI_GUID *HandlerType,
+ IN CONST VOID *Context OPTIONAL,
+ IN OUT VOID *CommBuffer OPTIONAL,
+ IN OUT UINTN *CommBufferSize OPTIONAL
+ )
+{
+ LIST_ENTRY *Link;
+ LIST_ENTRY *Head;
+ MMI_ENTRY *MmiEntry;
+ MMI_HANDLER *MmiHandler;
+ BOOLEAN SuccessReturn;
+ EFI_STATUS Status;
+
+ Status = EFI_NOT_FOUND;
+ SuccessReturn = FALSE;
+ if (HandlerType == NULL) {
+ //
+ // Root MMI handler
+ //
+
+ Head = &mRootMmiHandlerList;
+ } else {
+ //
+ // Non-root MMI handler
+ //
+ MmiEntry = MmCoreFindMmiEntry ((EFI_GUID *) HandlerType, FALSE);
+ if (MmiEntry == NULL) {
+ //
+ // There is no handler registered for this interrupt source
+ //
+ return Status;
+ }
+
+ Head = &MmiEntry->MmiHandlers;
+ }
+
+ for (Link = Head->ForwardLink; Link != Head; Link = Link->ForwardLink) {
+ MmiHandler = CR (Link, MMI_HANDLER, Link, MMI_HANDLER_SIGNATURE);
+
+ Status = MmiHandler->Handler (
+ (EFI_HANDLE) MmiHandler,
+ Context,
+ CommBuffer,
+ CommBufferSize
+ );
+
+ switch (Status) {
+ case EFI_INTERRUPT_PENDING:
+ //
+ // If a handler returns EFI_INTERRUPT_PENDING and HandlerType is not NULL then
+ // no additional handlers will be processed and EFI_INTERRUPT_PENDING will be returned.
+ //
+ if (HandlerType != NULL) {
+ return EFI_INTERRUPT_PENDING;
+ }
+ break;
+
+ case EFI_SUCCESS:
+ //
+ // If at least one of the handlers returns EFI_SUCCESS then the function will return
+ // EFI_SUCCESS. If a handler returns EFI_SUCCESS and HandlerType is not NULL then no
+ // additional handlers will be processed.
+ //
+ if (HandlerType != NULL) {
+ return EFI_SUCCESS;
+ }
+ SuccessReturn = TRUE;
+ break;
+
+ case EFI_WARN_INTERRUPT_SOURCE_QUIESCED:
+ //
+ // If at least one of the handlers returns EFI_WARN_INTERRUPT_SOURCE_QUIESCED
+ // then the function will return EFI_SUCCESS.
+ //
+ SuccessReturn = TRUE;
+ break;
+
+ case EFI_WARN_INTERRUPT_SOURCE_PENDING:
+ //
+ // If all the handlers returned EFI_WARN_INTERRUPT_SOURCE_PENDING
+ // then EFI_WARN_INTERRUPT_SOURCE_PENDING will be returned.
+ //
+ break;
+
+ default:
+ //
+ // Unexpected status code returned.
+ //
+ ASSERT (FALSE);
+ break;
+ }
+ }
+
+ if (SuccessReturn) {
+ Status = EFI_SUCCESS;
+ }
+
+ return Status;
+}
+
+/**
+ Registers a handler to execute within MM.
+
+ @param Handler Handler service funtion pointer.
+ @param HandlerType Points to the handler type or NULL for root MMI handlers.
+ @param DispatchHandle On return, contains a unique handle which can be used to later unregister the handler function.
+
+ @retval EFI_SUCCESS Handler register success.
+ @retval EFI_INVALID_PARAMETER Handler or DispatchHandle is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+MmiHandlerRegister (
+ IN EFI_MM_HANDLER_ENTRY_POINT Handler,
+ IN CONST EFI_GUID *HandlerType OPTIONAL,
+ OUT EFI_HANDLE *DispatchHandle
+ )
+{
+ MMI_HANDLER *MmiHandler;
+ MMI_ENTRY *MmiEntry;
+ LIST_ENTRY *List;
+
+ if (Handler == NULL || DispatchHandle == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ MmiHandler = AllocateZeroPool (sizeof (MMI_HANDLER));
+ if (MmiHandler == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ MmiHandler->Signature = MMI_HANDLER_SIGNATURE;
+ MmiHandler->Handler = Handler;
+
+ if (HandlerType == NULL) {
+ //
+ // This is root MMI handler
+ //
+ MmiEntry = NULL;
+ List = &mRootMmiHandlerList;
+ } else {
+ //
+ // None root MMI handler
+ //
+ MmiEntry = MmCoreFindMmiEntry ((EFI_GUID *) HandlerType, TRUE);
+ if (MmiEntry == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ List = &MmiEntry->MmiHandlers;
+ }
+
+ MmiHandler->MmiEntry = MmiEntry;
+ InsertTailList (List, &MmiHandler->Link);
+
+ *DispatchHandle = (EFI_HANDLE) MmiHandler;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Unregister a handler in MM.
+
+ @param DispatchHandle The handle that was specified when the handler was registered.
+
+ @retval EFI_SUCCESS Handler function was successfully unregistered.
+ @retval EFI_INVALID_PARAMETER DispatchHandle does not refer to a valid handle.
+
+**/
+EFI_STATUS
+EFIAPI
+MmiHandlerUnRegister (
+ IN EFI_HANDLE DispatchHandle
+ )
+{
+ MMI_HANDLER *MmiHandler;
+ MMI_ENTRY *MmiEntry;
+
+ MmiHandler = (MMI_HANDLER *) DispatchHandle;
+
+ if (MmiHandler == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (MmiHandler->Signature != MMI_HANDLER_SIGNATURE) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ MmiEntry = MmiHandler->MmiEntry;
+
+ RemoveEntryList (&MmiHandler->Link);
+ FreePool (MmiHandler);
+
+ if (MmiEntry == NULL) {
+ //
+ // This is root MMI handler
+ //
+ return EFI_SUCCESS;
+ }
+
+ if (IsListEmpty (&MmiEntry->MmiHandlers)) {
+ //
+ // No handler registered for this interrupt now, remove the MMI_ENTRY
+ //
+ RemoveEntryList (&MmiEntry->AllEntries);
+
+ FreePool (MmiEntry);
+ }
+
+ return EFI_SUCCESS;
+}
diff --git a/StandaloneMmPkg/Core/Notify.c b/StandaloneMmPkg/Core/Notify.c
new file mode 100644
index 0000000000..57a03fed5b
--- /dev/null
+++ b/StandaloneMmPkg/Core/Notify.c
@@ -0,0 +1,203 @@
+/** @file
+ Support functions for UEFI protocol notification infrastructure.
+
+ Copyright (c) 2009 - 2015, Intel Corporation. All rights reserved.<BR>
+ Copyright (c) 2016 - 2018, ARM Limited. All rights reserved.<BR>
+ This program and the accompanying materials are licensed and made available
+ under the terms and conditions of the BSD License which accompanies this
+ distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "StandaloneMmCore.h"
+
+/**
+ Signal event for every protocol in protocol entry.
+
+ @param Prot Protocol interface
+
+**/
+VOID
+MmNotifyProtocol (
+ IN PROTOCOL_INTERFACE *Prot
+ )
+{
+ PROTOCOL_ENTRY *ProtEntry;
+ PROTOCOL_NOTIFY *ProtNotify;
+ LIST_ENTRY *Link;
+
+ ProtEntry = Prot->Protocol;
+ for (Link=ProtEntry->Notify.ForwardLink; Link != &ProtEntry->Notify; Link=Link->ForwardLink) {
+ ProtNotify = CR (Link, PROTOCOL_NOTIFY, Link, PROTOCOL_NOTIFY_SIGNATURE);
+ ProtNotify->Function (&ProtEntry->ProtocolID, Prot->Interface, Prot->Handle);
+ }
+}
+
+/**
+ 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 *
+MmRemoveInterfaceFromProtocol (
+ IN IHANDLE *Handle,
+ IN EFI_GUID *Protocol,
+ IN VOID *Interface
+ )
+{
+ PROTOCOL_INTERFACE *Prot;
+ PROTOCOL_NOTIFY *ProtNotify;
+ PROTOCOL_ENTRY *ProtEntry;
+ LIST_ENTRY *Link;
+
+ Prot = MmFindProtocolInterface (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 Function Points to the notification function
+ @param Registration Returns the registration record
+
+ @retval EFI_SUCCESS Successfully returned the registration record
+ that has been added or unhooked
+ @retval EFI_INVALID_PARAMETER Protocol is NULL or Registration is NULL
+ @retval EFI_OUT_OF_RESOURCES Not enough memory resource to finish the request
+ @retval EFI_NOT_FOUND If the registration is not found when Function == NULL
+
+**/
+EFI_STATUS
+EFIAPI
+MmRegisterProtocolNotify (
+ IN CONST EFI_GUID *Protocol,
+ IN EFI_MM_NOTIFY_FN Function,
+ OUT VOID **Registration
+ )
+{
+ PROTOCOL_ENTRY *ProtEntry;
+ PROTOCOL_NOTIFY *ProtNotify;
+ LIST_ENTRY *Link;
+ EFI_STATUS Status;
+
+ if (Protocol == NULL || Registration == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (Function == NULL) {
+ //
+ // Get the protocol entry per Protocol
+ //
+ ProtEntry = MmFindProtocolEntry ((EFI_GUID *) Protocol, FALSE);
+ if (ProtEntry != NULL) {
+ ProtNotify = (PROTOCOL_NOTIFY * )*Registration;
+ for (Link = ProtEntry->Notify.ForwardLink;
+ Link != &ProtEntry->Notify;
+ Link = Link->ForwardLink) {
+ //
+ // Compare the notification record
+ //
+ if (ProtNotify == (CR (Link, PROTOCOL_NOTIFY, Link, PROTOCOL_NOTIFY_SIGNATURE))) {
+ //
+ // If Registration is an existing registration, then unhook it
+ //
+ ProtNotify->Signature = 0;
+ RemoveEntryList (&ProtNotify->Link);
+ FreePool (ProtNotify);
+ return EFI_SUCCESS;
+ }
+ }
+ }
+ //
+ // If the registration is not found
+ //
+ return EFI_NOT_FOUND;
+ }
+
+ ProtNotify = NULL;
+
+ //
+ // Get the protocol entry to add the notification too
+ //
+ ProtEntry = MmFindProtocolEntry ((EFI_GUID *) Protocol, TRUE);
+ if (ProtEntry != NULL) {
+ //
+ // Find whether notification already exist
+ //
+ for (Link = ProtEntry->Notify.ForwardLink;
+ Link != &ProtEntry->Notify;
+ Link = Link->ForwardLink) {
+
+ ProtNotify = CR (Link, PROTOCOL_NOTIFY, Link, PROTOCOL_NOTIFY_SIGNATURE);
+ if (CompareGuid (&ProtNotify->Protocol->ProtocolID, Protocol) &&
+ (ProtNotify->Function == Function)) {
+
+ //
+ // Notification already exist
+ //
+ *Registration = ProtNotify;
+
+ return EFI_SUCCESS;
+ }
+ }
+
+ //
+ // Allocate a new notification record
+ //
+ ProtNotify = AllocatePool (sizeof (PROTOCOL_NOTIFY));
+ if (ProtNotify != NULL) {
+ ProtNotify->Signature = PROTOCOL_NOTIFY_SIGNATURE;
+ ProtNotify->Protocol = ProtEntry;
+ ProtNotify->Function = Function;
+ //
+ // Start at the ending
+ //
+ ProtNotify->Position = ProtEntry->Protocols.BackLink;
+
+ InsertTailList (&ProtEntry->Notify, &ProtNotify->Link);
+ }
+ }
+
+ //
+ // 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;
+}
diff --git a/StandaloneMmPkg/Core/Page.c b/StandaloneMmPkg/Core/Page.c
new file mode 100644
index 0000000000..8250f8c729
--- /dev/null
+++ b/StandaloneMmPkg/Core/Page.c
@@ -0,0 +1,384 @@
+/** @file
+ MM Memory page management functions.
+
+ Copyright (c) 2009 - 2014, Intel Corporation. All rights reserved.<BR>
+ Copyright (c) 2016 - 2018, ARM Limited. All rights reserved.<BR>
+ This program and the accompanying materials are licensed and made available
+ under the terms and conditions of the BSD License which accompanies this
+ distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "StandaloneMmCore.h"
+
+#define NEXT_MEMORY_DESCRIPTOR(MemoryDescriptor, Size) \
+ ((EFI_MEMORY_DESCRIPTOR *)((UINT8 *)(MemoryDescriptor) + (Size)))
+
+#define TRUNCATE_TO_PAGES(a) ((a) >> EFI_PAGE_SHIFT)
+
+LIST_ENTRY mMmMemoryMap = INITIALIZE_LIST_HEAD_VARIABLE (mMmMemoryMap);
+
+UINTN mMapKey;
+
+/**
+ Internal Function. Allocate n pages from given free page node.
+
+ @param Pages The free page node.
+ @param NumberOfPages Number of pages to be allocated.
+ @param MaxAddress Request to allocate memory below this address.
+
+ @return Memory address of allocated pages.
+
+**/
+UINTN
+InternalAllocPagesOnOneNode (
+ IN OUT FREE_PAGE_LIST *Pages,
+ IN UINTN NumberOfPages,
+ IN UINTN MaxAddress
+ )
+{
+ UINTN Top;
+ UINTN Bottom;
+ FREE_PAGE_LIST *Node;
+
+ Top = TRUNCATE_TO_PAGES (MaxAddress + 1 - (UINTN)Pages);
+ if (Top > Pages->NumberOfPages) {
+ Top = Pages->NumberOfPages;
+ }
+ Bottom = Top - NumberOfPages;
+
+ if (Top < Pages->NumberOfPages) {
+ Node = (FREE_PAGE_LIST*)((UINTN)Pages + EFI_PAGES_TO_SIZE (Top));
+ Node->NumberOfPages = Pages->NumberOfPages - Top;
+ InsertHeadList (&Pages->Link, &Node->Link);
+ }
+
+ if (Bottom > 0) {
+ Pages->NumberOfPages = Bottom;
+ } else {
+ RemoveEntryList (&Pages->Link);
+ }
+
+ return (UINTN)Pages + EFI_PAGES_TO_SIZE (Bottom);
+}
+
+/**
+ Internal Function. Allocate n pages from free page list below MaxAddress.
+
+ @param FreePageList The free page node.
+ @param NumberOfPages Number of pages to be allocated.
+ @param MaxAddress Request to allocate memory below this address.
+
+ @return Memory address of allocated pages.
+
+**/
+UINTN
+InternalAllocMaxAddress (
+ IN OUT LIST_ENTRY *FreePageList,
+ IN UINTN NumberOfPages,
+ IN UINTN MaxAddress
+ )
+{
+ LIST_ENTRY *Node;
+ FREE_PAGE_LIST *Pages;
+
+ for (Node = FreePageList->BackLink; Node != FreePageList; Node = Node->BackLink) {
+ Pages = BASE_CR (Node, FREE_PAGE_LIST, Link);
+ if (Pages->NumberOfPages >= NumberOfPages &&
+ (UINTN)Pages + EFI_PAGES_TO_SIZE (NumberOfPages) - 1 <= MaxAddress) {
+ return InternalAllocPagesOnOneNode (Pages, NumberOfPages, MaxAddress);
+ }
+ }
+ return (UINTN)(-1);
+}
+
+/**
+ Internal Function. Allocate n pages from free page list at given address.
+
+ @param FreePageList The free page node.
+ @param NumberOfPages Number of pages to be allocated.
+ @param MaxAddress Request to allocate memory below this address.
+
+ @return Memory address of allocated pages.
+
+**/
+UINTN
+InternalAllocAddress (
+ IN OUT LIST_ENTRY *FreePageList,
+ IN UINTN NumberOfPages,
+ IN UINTN Address
+ )
+{
+ UINTN EndAddress;
+ LIST_ENTRY *Node;
+ FREE_PAGE_LIST *Pages;
+
+ if ((Address & EFI_PAGE_MASK) != 0) {
+ return ~Address;
+ }
+
+ EndAddress = Address + EFI_PAGES_TO_SIZE (NumberOfPages);
+ for (Node = FreePageList->BackLink; Node!= FreePageList; Node = Node->BackLink) {
+ Pages = BASE_CR (Node, FREE_PAGE_LIST, Link);
+ if ((UINTN)Pages <= Address) {
+ if ((UINTN)Pages + EFI_PAGES_TO_SIZE (Pages->NumberOfPages) < EndAddress) {
+ break;
+ }
+ return InternalAllocPagesOnOneNode (Pages, NumberOfPages, EndAddress);
+ }
+ }
+ return ~Address;
+}
+
+/**
+ 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.
+
+ @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
+MmInternalAllocatePages (
+ IN EFI_ALLOCATE_TYPE Type,
+ IN EFI_MEMORY_TYPE MemoryType,
+ IN UINTN NumberOfPages,
+ OUT EFI_PHYSICAL_ADDRESS *Memory
+ )
+{
+ UINTN RequestedAddress;
+
+ if (MemoryType != EfiRuntimeServicesCode &&
+ MemoryType != EfiRuntimeServicesData) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (NumberOfPages > TRUNCATE_TO_PAGES ((UINTN)-1) + 1) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ //
+ // We don't track memory type in MM
+ //
+ RequestedAddress = (UINTN)*Memory;
+ switch (Type) {
+ case AllocateAnyPages:
+ RequestedAddress = (UINTN)(-1);
+ case AllocateMaxAddress:
+ *Memory = InternalAllocMaxAddress (
+ &mMmMemoryMap,
+ NumberOfPages,
+ RequestedAddress
+ );
+ if (*Memory == (UINTN)-1) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ break;
+ case AllocateAddress:
+ *Memory = InternalAllocAddress (
+ &mMmMemoryMap,
+ NumberOfPages,
+ RequestedAddress
+ );
+ if (*Memory != RequestedAddress) {
+ return EFI_NOT_FOUND;
+ }
+ break;
+ default:
+ return EFI_INVALID_PARAMETER;
+ }
+ return EFI_SUCCESS;
+}
+
+/**
+ 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.
+
+ @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
+MmAllocatePages (
+ IN EFI_ALLOCATE_TYPE Type,
+ IN EFI_MEMORY_TYPE MemoryType,
+ IN UINTN NumberOfPages,
+ OUT EFI_PHYSICAL_ADDRESS *Memory
+ )
+{
+ EFI_STATUS Status;
+
+ Status = MmInternalAllocatePages (Type, MemoryType, NumberOfPages, Memory);
+ return Status;
+}
+
+/**
+ Internal Function. Merge two adjacent nodes.
+
+ @param First The first of two nodes to merge.
+
+ @return Pointer to node after merge (if success) or pointer to next node (if fail).
+
+**/
+FREE_PAGE_LIST *
+InternalMergeNodes (
+ IN FREE_PAGE_LIST *First
+ )
+{
+ FREE_PAGE_LIST *Next;
+
+ Next = BASE_CR (First->Link.ForwardLink, FREE_PAGE_LIST, Link);
+ ASSERT (
+ TRUNCATE_TO_PAGES ((UINTN)Next - (UINTN)First) >= First->NumberOfPages);
+
+ if (TRUNCATE_TO_PAGES ((UINTN)Next - (UINTN)First) == First->NumberOfPages) {
+ First->NumberOfPages += Next->NumberOfPages;
+ RemoveEntryList (&Next->Link);
+ Next = First;
+ }
+ return Next;
+}
+
+/**
+ 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
+MmInternalFreePages (
+ IN EFI_PHYSICAL_ADDRESS Memory,
+ IN UINTN NumberOfPages
+ )
+{
+ LIST_ENTRY *Node;
+ FREE_PAGE_LIST *Pages;
+
+ if ((Memory & EFI_PAGE_MASK) != 0) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Pages = NULL;
+ Node = mMmMemoryMap.ForwardLink;
+ while (Node != &mMmMemoryMap) {
+ Pages = BASE_CR (Node, FREE_PAGE_LIST, Link);
+ if (Memory < (UINTN)Pages) {
+ break;
+ }
+ Node = Node->ForwardLink;
+ }
+
+ if (Node != &mMmMemoryMap &&
+ Memory + EFI_PAGES_TO_SIZE (NumberOfPages) > (UINTN)Pages) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (Node->BackLink != &mMmMemoryMap) {
+ Pages = BASE_CR (Node->BackLink, FREE_PAGE_LIST, Link);
+ if ((UINTN)Pages + EFI_PAGES_TO_SIZE (Pages->NumberOfPages) > Memory) {
+ return EFI_INVALID_PARAMETER;
+ }
+ }
+
+ Pages = (FREE_PAGE_LIST*)(UINTN)Memory;
+ Pages->NumberOfPages = NumberOfPages;
+ InsertTailList (Node, &Pages->Link);
+
+ if (Pages->Link.BackLink != &mMmMemoryMap) {
+ Pages = InternalMergeNodes (
+ BASE_CR (Pages->Link.BackLink, FREE_PAGE_LIST, Link)
+ );
+ }
+
+ if (Node != &mMmMemoryMap) {
+ InternalMergeNodes (Pages);
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ 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
+MmFreePages (
+ IN EFI_PHYSICAL_ADDRESS Memory,
+ IN UINTN NumberOfPages
+ )
+{
+ EFI_STATUS Status;
+
+ Status = MmInternalFreePages (Memory, NumberOfPages);
+ return Status;
+}
+
+/**
+ Add free MMRAM region for use by memory service.
+
+ @param MemBase Base address of memory region.
+ @param MemLength Length of the memory region.
+ @param Type Memory type.
+ @param Attributes Memory region state.
+
+**/
+VOID
+MmAddMemoryRegion (
+ IN EFI_PHYSICAL_ADDRESS MemBase,
+ IN UINT64 MemLength,
+ IN EFI_MEMORY_TYPE Type,
+ IN UINT64 Attributes
+ )
+{
+ UINTN AlignedMemBase;
+
+ //
+ // Do not add memory regions that is already allocated, needs testing, or needs ECC initialization
+ //
+ if ((Attributes & (EFI_ALLOCATED | EFI_NEEDS_TESTING | EFI_NEEDS_ECC_INITIALIZATION)) != 0) {
+ return;
+ }
+
+ //
+ // Align range on an EFI_PAGE_SIZE boundary
+ //
+ AlignedMemBase = (UINTN)(MemBase + EFI_PAGE_MASK) & ~EFI_PAGE_MASK;
+ MemLength -= AlignedMemBase - MemBase;
+ MmFreePages (AlignedMemBase, TRUNCATE_TO_PAGES ((UINTN)MemLength));
+}
diff --git a/StandaloneMmPkg/Core/Pool.c b/StandaloneMmPkg/Core/Pool.c
new file mode 100644
index 0000000000..ce6cfcb9a4
--- /dev/null
+++ b/StandaloneMmPkg/Core/Pool.c
@@ -0,0 +1,293 @@
+/** @file
+ SMM Memory pool management functions.
+
+ Copyright (c) 2009 - 2014, Intel Corporation. All rights reserved.<BR>
+ Copyright (c) 2016 - 2018, ARM Limited. All rights reserved.<BR>
+ This program and the accompanying materials are licensed and made available
+ under the terms and conditions of the BSD License which accompanies this
+ distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "StandaloneMmCore.h"
+
+LIST_ENTRY mMmPoolLists[MAX_POOL_INDEX];
+//
+// To cache the MMRAM base since when Loading modules At fixed address feature is enabled,
+// all module is assigned an offset relative the MMRAM base in build time.
+//
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_PHYSICAL_ADDRESS gLoadModuleAtFixAddressMmramBase = 0;
+
+/**
+ Called to initialize the memory service.
+
+ @param MmramRangeCount Number of MMRAM Regions
+ @param MmramRanges Pointer to MMRAM Descriptors
+
+**/
+VOID
+MmInitializeMemoryServices (
+ IN UINTN MmramRangeCount,
+ IN EFI_MMRAM_DESCRIPTOR *MmramRanges
+ )
+{
+ UINTN Index;
+
+ //
+ // Initialize Pool list
+ //
+ for (Index = sizeof (mMmPoolLists) / sizeof (*mMmPoolLists); Index > 0;) {
+ InitializeListHead (&mMmPoolLists[--Index]);
+ }
+
+
+ //
+ // Initialize free MMRAM regions
+ //
+ for (Index = 0; Index < MmramRangeCount; Index++) {
+ //
+ // BUGBUG: Add legacy MMRAM region is buggy.
+ //
+ if (MmramRanges[Index].CpuStart < BASE_1MB) {
+ continue;
+ }
+ DEBUG ((DEBUG_INFO, "MmAddMemoryRegion %d : 0x%016lx - 0x%016lx\n",
+ Index, MmramRanges[Index].CpuStart, MmramRanges[Index].PhysicalSize));
+ MmAddMemoryRegion (
+ MmramRanges[Index].CpuStart,
+ MmramRanges[Index].PhysicalSize,
+ EfiConventionalMemory,
+ MmramRanges[Index].RegionState
+ );
+ }
+
+}
+
+/**
+ Internal Function. Allocate a pool by specified PoolIndex.
+
+ @param PoolIndex Index which indicate the Pool size.
+ @param FreePoolHdr The returned Free pool.
+
+ @retval EFI_OUT_OF_RESOURCES Allocation failed.
+ @retval EFI_SUCCESS Pool successfully allocated.
+
+**/
+EFI_STATUS
+InternalAllocPoolByIndex (
+ IN UINTN PoolIndex,
+ OUT FREE_POOL_HEADER **FreePoolHdr
+ )
+{
+ EFI_STATUS Status;
+ FREE_POOL_HEADER *Hdr;
+ EFI_PHYSICAL_ADDRESS Address;
+
+ ASSERT (PoolIndex <= MAX_POOL_INDEX);
+ Status = EFI_SUCCESS;
+ Hdr = NULL;
+ if (PoolIndex == MAX_POOL_INDEX) {
+ Status = MmInternalAllocatePages (
+ AllocateAnyPages,
+ EfiRuntimeServicesData,
+ EFI_SIZE_TO_PAGES (MAX_POOL_SIZE << 1),
+ &Address
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ Hdr = (FREE_POOL_HEADER *) (UINTN) Address;
+ } else if (!IsListEmpty (&mMmPoolLists[PoolIndex])) {
+ Hdr = BASE_CR (GetFirstNode (&mMmPoolLists[PoolIndex]), FREE_POOL_HEADER, Link);
+ RemoveEntryList (&Hdr->Link);
+ } else {
+ Status = InternalAllocPoolByIndex (PoolIndex + 1, &Hdr);
+ if (!EFI_ERROR (Status)) {
+ Hdr->Header.Size >>= 1;
+ Hdr->Header.Available = TRUE;
+ InsertHeadList (&mMmPoolLists[PoolIndex], &Hdr->Link);
+ Hdr = (FREE_POOL_HEADER*)((UINT8*)Hdr + Hdr->Header.Size);
+ }
+ }
+
+ if (!EFI_ERROR (Status)) {
+ Hdr->Header.Size = MIN_POOL_SIZE << PoolIndex;
+ Hdr->Header.Available = FALSE;
+ }
+
+ *FreePoolHdr = Hdr;
+ return Status;
+}
+
+/**
+ Internal Function. Free a pool by specified PoolIndex.
+
+ @param FreePoolHdr The pool to free.
+
+ @retval EFI_SUCCESS Pool successfully freed.
+
+**/
+EFI_STATUS
+InternalFreePoolByIndex (
+ IN FREE_POOL_HEADER *FreePoolHdr
+ )
+{
+ UINTN PoolIndex;
+
+ ASSERT ((FreePoolHdr->Header.Size & (FreePoolHdr->Header.Size - 1)) == 0);
+ ASSERT (((UINTN)FreePoolHdr & (FreePoolHdr->Header.Size - 1)) == 0);
+ ASSERT (FreePoolHdr->Header.Size >= MIN_POOL_SIZE);
+
+ PoolIndex = (UINTN) (HighBitSet32 ((UINT32)FreePoolHdr->Header.Size) - MIN_POOL_SHIFT);
+ FreePoolHdr->Header.Available = TRUE;
+ ASSERT (PoolIndex < MAX_POOL_INDEX);
+ InsertHeadList (&mMmPoolLists[PoolIndex], &FreePoolHdr->Link);
+ return EFI_SUCCESS;
+}
+
+/**
+ 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.
+ @retval EFI_OUT_OF_RESOURCES Size exceeds max pool size or allocation failed.
+ @retval EFI_SUCCESS Pool successfully allocated.
+
+**/
+EFI_STATUS
+EFIAPI
+MmInternalAllocatePool (
+ IN EFI_MEMORY_TYPE PoolType,
+ IN UINTN Size,
+ OUT VOID **Buffer
+ )
+{
+ POOL_HEADER *PoolHdr;
+ FREE_POOL_HEADER *FreePoolHdr;
+ EFI_STATUS Status;
+ EFI_PHYSICAL_ADDRESS Address;
+ UINTN PoolIndex;
+
+ if (PoolType != EfiRuntimeServicesCode &&
+ PoolType != EfiRuntimeServicesData) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Size += sizeof (*PoolHdr);
+ if (Size > MAX_POOL_SIZE) {
+ Size = EFI_SIZE_TO_PAGES (Size);
+ Status = MmInternalAllocatePages (AllocateAnyPages, PoolType, Size, &Address);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ PoolHdr = (POOL_HEADER*)(UINTN)Address;
+ PoolHdr->Size = EFI_PAGES_TO_SIZE (Size);
+ PoolHdr->Available = FALSE;
+ *Buffer = PoolHdr + 1;
+ return Status;
+ }
+
+ Size = (Size + MIN_POOL_SIZE - 1) >> MIN_POOL_SHIFT;
+ PoolIndex = (UINTN) HighBitSet32 ((UINT32)Size);
+ if ((Size & (Size - 1)) != 0) {
+ PoolIndex++;
+ }
+
+ Status = InternalAllocPoolByIndex (PoolIndex, &FreePoolHdr);
+ if (!EFI_ERROR (Status)) {
+ *Buffer = &FreePoolHdr->Header + 1;
+ }
+ return Status;
+}
+
+/**
+ 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.
+ @retval EFI_OUT_OF_RESOURCES Size exceeds max pool size or allocation failed.
+ @retval EFI_SUCCESS Pool successfully allocated.
+
+**/
+EFI_STATUS
+EFIAPI
+MmAllocatePool (
+ IN EFI_MEMORY_TYPE PoolType,
+ IN UINTN Size,
+ OUT VOID **Buffer
+ )
+{
+ EFI_STATUS Status;
+
+ Status = MmInternalAllocatePool (PoolType, Size, Buffer);
+ 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
+MmInternalFreePool (
+ IN VOID *Buffer
+ )
+{
+ FREE_POOL_HEADER *FreePoolHdr;
+
+ if (Buffer == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ FreePoolHdr = (FREE_POOL_HEADER*)((POOL_HEADER*)Buffer - 1);
+ ASSERT (!FreePoolHdr->Header.Available);
+
+ if (FreePoolHdr->Header.Size > MAX_POOL_SIZE) {
+ ASSERT (((UINTN)FreePoolHdr & EFI_PAGE_MASK) == 0);
+ ASSERT ((FreePoolHdr->Header.Size & EFI_PAGE_MASK) == 0);
+ return MmInternalFreePages (
+ (EFI_PHYSICAL_ADDRESS)(UINTN)FreePoolHdr,
+ EFI_SIZE_TO_PAGES (FreePoolHdr->Header.Size)
+ );
+ }
+ return InternalFreePoolByIndex (FreePoolHdr);
+}
+
+/**
+ 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
+MmFreePool (
+ IN VOID *Buffer
+ )
+{
+ EFI_STATUS Status;
+
+ Status = MmInternalFreePool (Buffer);
+ return Status;
+}
diff --git a/StandaloneMmPkg/Core/StandaloneMmCore.c b/StandaloneMmPkg/Core/StandaloneMmCore.c
new file mode 100644
index 0000000000..74432320bf
--- /dev/null
+++ b/StandaloneMmPkg/Core/StandaloneMmCore.c
@@ -0,0 +1,712 @@
+/** @file
+ MM Core Main Entry Point
+
+ Copyright (c) 2009 - 2014, Intel Corporation. All rights reserved.<BR>
+ Copyright (c) 2016 - 2018, ARM Limited. All rights reserved.<BR>
+ This program and the accompanying materials are licensed and made available
+ under the terms and conditions of the BSD License which accompanies this
+ distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "StandaloneMmCore.h"
+
+EFI_STATUS
+MmCoreFfsFindMmDriver (
+ IN EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader
+ );
+
+EFI_STATUS
+MmDispatcher (
+ VOID
+ );
+
+//
+// Globals used to initialize the protocol
+//
+EFI_HANDLE mMmCpuHandle = NULL;
+
+//
+// Physical pointer to private structure shared between MM IPL and the MM Core
+//
+MM_CORE_PRIVATE_DATA *gMmCorePrivate;
+
+//
+// MM Core global variable for MM System Table. Only accessed as a physical structure in MMRAM.
+//
+EFI_MM_SYSTEM_TABLE gMmCoreMmst = {
+
+ // The table header for the MMST.
+ {
+ MM_MMST_SIGNATURE,
+ EFI_MM_SYSTEM_TABLE_REVISION,
+ sizeof (gMmCoreMmst.Hdr)
+ },
+ // MmFirmwareVendor
+ NULL,
+ // MmFirmwareRevision
+ 0,
+ // MmInstallConfigurationTable
+ MmInstallConfigurationTable,
+ // I/O Service
+ {
+ {
+ (EFI_MM_CPU_IO) MmEfiNotAvailableYetArg5, // MmMemRead
+ (EFI_MM_CPU_IO) MmEfiNotAvailableYetArg5 // MmMemWrite
+ },
+ {
+ (EFI_MM_CPU_IO) MmEfiNotAvailableYetArg5, // MmIoRead
+ (EFI_MM_CPU_IO) MmEfiNotAvailableYetArg5 // MmIoWrite
+ }
+ },
+ // Runtime memory services
+ MmAllocatePool,
+ MmFreePool,
+ MmAllocatePages,
+ MmFreePages,
+ // MP service
+ NULL, // MmStartupThisAp
+ 0, // CurrentlyExecutingCpu
+ 0, // NumberOfCpus
+ NULL, // CpuSaveStateSize
+ NULL, // CpuSaveState
+ 0, // NumberOfTableEntries
+ NULL, // MmConfigurationTable
+ MmInstallProtocolInterface,
+ MmUninstallProtocolInterface,
+ MmHandleProtocol,
+ MmRegisterProtocolNotify,
+ MmLocateHandle,
+ MmLocateProtocol,
+ MmiManage,
+ MmiHandlerRegister,
+ MmiHandlerUnRegister
+};
+
+//
+// Flag to determine if the platform has performed a legacy boot.
+// If this flag is TRUE, then the runtime code and runtime data associated with the
+// MM IPL are converted to free memory, so the MM Core must guarantee that is
+// does not touch of the code/data associated with the MM IPL if this flag is TRUE.
+//
+BOOLEAN mInLegacyBoot = FALSE;
+
+//
+// Table of MMI Handlers that are registered by the MM Core when it is initialized
+//
+MM_CORE_MMI_HANDLERS mMmCoreMmiHandlers[] = {
+ { MmFvDispatchHandler, &gMmFvDispatchGuid, NULL, TRUE },
+ { MmDriverDispatchHandler, &gEfiEventDxeDispatchGuid, NULL, TRUE },
+ { MmReadyToLockHandler, &gEfiDxeMmReadyToLockProtocolGuid, NULL, TRUE },
+ { MmEndOfDxeHandler, &gEfiEndOfDxeEventGroupGuid, NULL, FALSE },
+ { MmLegacyBootHandler, &gEfiEventLegacyBootGuid, NULL, FALSE },
+ { MmExitBootServiceHandler,&gEfiEventExitBootServicesGuid, NULL, FALSE },
+ { MmReadyToBootHandler, &gEfiEventReadyToBootGuid, NULL, FALSE },
+ { NULL, NULL, NULL, FALSE },
+};
+
+EFI_SYSTEM_TABLE *mEfiSystemTable;
+UINTN mMmramRangeCount;
+EFI_MMRAM_DESCRIPTOR *mMmramRanges;
+
+/**
+ Place holder function until all the MM System Table Service are available.
+
+ Note: This function is only used by MMRAM invocation. It is never used by DXE invocation.
+
+ @param Arg1 Undefined
+ @param Arg2 Undefined
+ @param Arg3 Undefined
+ @param Arg4 Undefined
+ @param Arg5 Undefined
+
+ @return EFI_NOT_AVAILABLE_YET
+
+**/
+EFI_STATUS
+EFIAPI
+MmEfiNotAvailableYetArg5 (
+ 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.
+ //
+ return EFI_NOT_AVAILABLE_YET;
+}
+
+/**
+ Software MMI handler that is called when a Legacy Boot event is signaled. The MM
+ Core uses this signal to know that a Legacy Boot has been performed and that
+ gMmCorePrivate that is shared between the UEFI and MM execution environments can
+ not be accessed from MM anymore since that structure is considered free memory by
+ a legacy OS.
+
+ @param DispatchHandle The unique handle assigned to this handler by MmiHandlerRegister().
+ @param Context Points to an optional handler context which was specified when the handler was registered.
+ @param CommBuffer A pointer to a collection of data in memory that will
+ be conveyed from a non-MM environment into an MM environment.
+ @param CommBufferSize The size of the CommBuffer.
+
+ @return Status Code
+
+**/
+EFI_STATUS
+EFIAPI
+MmLegacyBootHandler (
+ IN EFI_HANDLE DispatchHandle,
+ IN CONST VOID *Context, OPTIONAL
+ IN OUT VOID *CommBuffer, OPTIONAL
+ IN OUT UINTN *CommBufferSize OPTIONAL
+ )
+{
+ EFI_HANDLE MmHandle;
+ EFI_STATUS Status = EFI_SUCCESS;
+
+ if (!mInLegacyBoot) {
+ MmHandle = NULL;
+ Status = MmInstallProtocolInterface (
+ &MmHandle,
+ &gEfiEventLegacyBootGuid,
+ EFI_NATIVE_INTERFACE,
+ NULL
+ );
+ }
+ mInLegacyBoot = TRUE;
+ return Status;
+}
+
+/**
+ Software MMI handler that is called when a ExitBoot Service event is signaled.
+
+ @param DispatchHandle The unique handle assigned to this handler by MmiHandlerRegister().
+ @param Context Points to an optional handler context which was specified when the handler was registered.
+ @param CommBuffer A pointer to a collection of data in memory that will
+ be conveyed from a non-MM environment into an MM environment.
+ @param CommBufferSize The size of the CommBuffer.
+
+ @return Status Code
+
+**/
+EFI_STATUS
+EFIAPI
+MmExitBootServiceHandler (
+ IN EFI_HANDLE DispatchHandle,
+ IN CONST VOID *Context, OPTIONAL
+ IN OUT VOID *CommBuffer, OPTIONAL
+ IN OUT UINTN *CommBufferSize OPTIONAL
+ )
+{
+ EFI_HANDLE MmHandle;
+ EFI_STATUS Status = EFI_SUCCESS;
+ STATIC BOOLEAN mInExitBootServices = FALSE;
+
+ if (!mInExitBootServices) {
+ MmHandle = NULL;
+ Status = MmInstallProtocolInterface (
+ &MmHandle,
+ &gEfiEventExitBootServicesGuid,
+ EFI_NATIVE_INTERFACE,
+ NULL
+ );
+ }
+ mInExitBootServices = TRUE;
+ return Status;
+}
+
+/**
+ Software MMI handler that is called when a ExitBoot Service event is signaled.
+
+ @param DispatchHandle The unique handle assigned to this handler by MmiHandlerRegister().
+ @param Context Points to an optional handler context which was specified when the handler was registered.
+ @param CommBuffer A pointer to a collection of data in memory that will
+ be conveyed from a non-MM environment into an MM environment.
+ @param CommBufferSize The size of the CommBuffer.
+
+ @return Status Code
+
+**/
+EFI_STATUS
+EFIAPI
+MmReadyToBootHandler (
+ IN EFI_HANDLE DispatchHandle,
+ IN CONST VOID *Context, OPTIONAL
+ IN OUT VOID *CommBuffer, OPTIONAL
+ IN OUT UINTN *CommBufferSize OPTIONAL
+ )
+{
+ EFI_HANDLE MmHandle;
+ EFI_STATUS Status = EFI_SUCCESS;
+ STATIC BOOLEAN mInReadyToBoot = FALSE;
+
+ if (!mInReadyToBoot) {
+ MmHandle = NULL;
+ Status = MmInstallProtocolInterface (
+ &MmHandle,
+ &gEfiEventReadyToBootGuid,
+ EFI_NATIVE_INTERFACE,
+ NULL
+ );
+ }
+ mInReadyToBoot = TRUE;
+ return Status;
+}
+
+/**
+ Software MMI handler that is called when the DxeMmReadyToLock protocol is added
+ or if gEfiEventReadyToBootGuid is signaled. This function unregisters the
+ Software SMIs that are nor required after MMRAM is locked and installs the
+ MM Ready To Lock Protocol so MM Drivers are informed that MMRAM is about
+ to be locked.
+
+ @param DispatchHandle The unique handle assigned to this handler by MmiHandlerRegister().
+ @param Context Points to an optional handler context which was specified when the handler was registered.
+ @param CommBuffer A pointer to a collection of data in memory that will
+ be conveyed from a non-MM environment into an MM environment.
+ @param CommBufferSize The size of the CommBuffer.
+
+ @return Status Code
+
+**/
+EFI_STATUS
+EFIAPI
+MmReadyToLockHandler (
+ IN EFI_HANDLE DispatchHandle,
+ IN CONST VOID *Context, OPTIONAL
+ IN OUT VOID *CommBuffer, OPTIONAL
+ IN OUT UINTN *CommBufferSize OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+ UINTN Index;
+ EFI_HANDLE MmHandle;
+
+ DEBUG ((DEBUG_INFO, "MmReadyToLockHandler\n"));
+
+ //
+ // Unregister MMI Handlers that are no longer required after the MM driver dispatch is stopped
+ //
+ for (Index = 0; mMmCoreMmiHandlers[Index].HandlerType != NULL; Index++) {
+ if (mMmCoreMmiHandlers[Index].UnRegister) {
+ MmiHandlerUnRegister (mMmCoreMmiHandlers[Index].DispatchHandle);
+ }
+ }
+
+ //
+ // Install MM Ready to lock protocol
+ //
+ MmHandle = NULL;
+ Status = MmInstallProtocolInterface (
+ &MmHandle,
+ &gEfiMmReadyToLockProtocolGuid,
+ EFI_NATIVE_INTERFACE,
+ NULL
+ );
+
+ //
+ // Make sure MM CPU I/O 2 Protocol has been installed into the handle database
+ //
+ //Status = MmLocateProtocol (&EFI_MM_CPU_IO_PROTOCOL_GUID, NULL, &Interface);
+
+ //
+ // Print a message on a debug build if the MM CPU I/O 2 Protocol is not installed
+ //
+ //if (EFI_ERROR (Status)) {
+ //DEBUG ((DEBUG_ERROR, "\nSMM: SmmCpuIo Arch Protocol not present!!\n"));
+ //}
+
+
+ //
+ // Assert if the CPU I/O 2 Protocol is not installed
+ //
+ //ASSERT_EFI_ERROR (Status);
+
+ //
+ // Display any drivers that were not dispatched because dependency expression
+ // evaluated to false if this is a debug build
+ //
+ //MmDisplayDiscoveredNotDispatched ();
+
+ return Status;
+}
+
+/**
+ Software MMI handler that is called when the EndOfDxe event is signaled.
+ This function installs the MM EndOfDxe Protocol so MM Drivers are informed that
+ platform code will invoke 3rd part code.
+
+ @param DispatchHandle The unique handle assigned to this handler by MmiHandlerRegister().
+ @param Context Points to an optional handler context which was specified when the handler was registered.
+ @param CommBuffer A pointer to a collection of data in memory that will
+ be conveyed from a non-MM environment into an MM environment.
+ @param CommBufferSize The size of the CommBuffer.
+
+ @return Status Code
+
+**/
+EFI_STATUS
+EFIAPI
+MmEndOfDxeHandler (
+ IN EFI_HANDLE DispatchHandle,
+ IN CONST VOID *Context, OPTIONAL
+ IN OUT VOID *CommBuffer, OPTIONAL
+ IN OUT UINTN *CommBufferSize OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+ EFI_HANDLE MmHandle;
+
+ DEBUG ((DEBUG_INFO, "MmEndOfDxeHandler\n"));
+ //
+ // Install MM EndOfDxe protocol
+ //
+ MmHandle = NULL;
+ Status = MmInstallProtocolInterface (
+ &MmHandle,
+ &gEfiMmEndOfDxeProtocolGuid,
+ EFI_NATIVE_INTERFACE,
+ NULL
+ );
+ return Status;
+}
+
+
+
+/**
+ The main entry point to MM Foundation.
+
+ Note: This function is only used by MMRAM invocation. It is never used by DXE invocation.
+
+ @param MmEntryContext Processor information and functionality
+ needed by MM Foundation.
+
+**/
+VOID
+EFIAPI
+MmEntryPoint (
+ IN CONST EFI_MM_ENTRY_CONTEXT *MmEntryContext
+)
+{
+ EFI_STATUS Status;
+ EFI_MM_COMMUNICATE_HEADER *CommunicateHeader;
+ BOOLEAN InLegacyBoot;
+
+ DEBUG ((DEBUG_INFO, "MmEntryPoint ...\n"));
+
+ //
+ // Update MMST using the context
+ //
+ CopyMem (&gMmCoreMmst.MmStartupThisAp, MmEntryContext, sizeof (EFI_MM_ENTRY_CONTEXT));
+
+ //
+ // Call platform hook before Mm Dispatch
+ //
+ //PlatformHookBeforeMmDispatch ();
+
+ //
+ // If a legacy boot has occured, then make sure gMmCorePrivate is not accessed
+ //
+ InLegacyBoot = mInLegacyBoot;
+ if (!InLegacyBoot) {
+ //
+ // TBD: Mark the InMm flag as TRUE
+ //
+ gMmCorePrivate->InMm = TRUE;
+
+ //
+ // Check to see if this is a Synchronous MMI sent through the MM Communication
+ // Protocol or an Asynchronous MMI
+ //
+ if (gMmCorePrivate->CommunicationBuffer != 0) {
+ //
+ // Synchronous MMI for MM Core or request from Communicate protocol
+ //
+ if (!MmIsBufferOutsideMmValid ((UINTN)gMmCorePrivate->CommunicationBuffer, gMmCorePrivate->BufferSize)) {
+ //
+ // If CommunicationBuffer is not in valid address scope, return EFI_INVALID_PARAMETER
+ //
+ gMmCorePrivate->CommunicationBuffer = 0;
+ gMmCorePrivate->ReturnStatus = EFI_INVALID_PARAMETER;
+ } else {
+ CommunicateHeader = (EFI_MM_COMMUNICATE_HEADER *)(UINTN)gMmCorePrivate->CommunicationBuffer;
+ gMmCorePrivate->BufferSize -= OFFSET_OF (EFI_MM_COMMUNICATE_HEADER, Data);
+ Status = MmiManage (
+ &CommunicateHeader->HeaderGuid,
+ NULL,
+ CommunicateHeader->Data,
+ (UINTN *)&gMmCorePrivate->BufferSize
+ );
+ //
+ // Update CommunicationBuffer, BufferSize and ReturnStatus
+ // Communicate service finished, reset the pointer to CommBuffer to NULL
+ //
+ gMmCorePrivate->BufferSize += OFFSET_OF (EFI_MM_COMMUNICATE_HEADER, Data);
+ gMmCorePrivate->CommunicationBuffer = 0;
+ gMmCorePrivate->ReturnStatus = (Status == EFI_SUCCESS) ? EFI_SUCCESS : EFI_NOT_FOUND;
+ }
+ }
+ }
+
+ //
+ // Process Asynchronous MMI sources
+ //
+ MmiManage (NULL, NULL, NULL, NULL);
+
+ //
+ // TBD: Do not use private data structure ?
+ //
+
+ //
+ // If a legacy boot has occured, then make sure gMmCorePrivate is not accessed
+ //
+ if (!InLegacyBoot) {
+ //
+ // Clear the InMm flag as we are going to leave MM
+ //
+ gMmCorePrivate->InMm = FALSE;
+ }
+
+ DEBUG ((DEBUG_INFO, "MmEntryPoint Done\n"));
+}
+
+EFI_STATUS
+EFIAPI
+MmConfigurationMmNotify (
+ IN CONST EFI_GUID *Protocol,
+ IN VOID *Interface,
+ IN EFI_HANDLE Handle
+ )
+{
+ EFI_STATUS Status;
+ EFI_MM_CONFIGURATION_PROTOCOL *MmConfiguration;
+
+ DEBUG ((DEBUG_INFO, "MmConfigurationMmNotify(%g) - %x\n", Protocol, Interface));
+
+ MmConfiguration = Interface;
+
+ //
+ // Register the MM Entry Point provided by the MM Core with the MM COnfiguration protocol
+ //
+ Status = MmConfiguration->RegisterMmEntry (MmConfiguration, (EFI_MM_ENTRY_POINT)(UINTN)gMmCorePrivate->MmEntryPoint);
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Set flag to indicate that the MM Entry Point has been registered which
+ // means that MMIs are now fully operational.
+ //
+ gMmCorePrivate->MmEntryPointRegistered = TRUE;
+
+ //
+ // Print debug message showing MM Core entry point address.
+ //
+ DEBUG ((DEBUG_INFO, "MM Core registered MM Entry Point address %p\n", (VOID *)(UINTN)gMmCorePrivate->MmEntryPoint));
+ return EFI_SUCCESS;
+}
+
+UINTN
+GetHobListSize (
+ IN VOID *HobStart
+ )
+{
+ EFI_PEI_HOB_POINTERS Hob;
+
+ ASSERT (HobStart != NULL);
+
+ Hob.Raw = (UINT8 *) HobStart;
+ while (!END_OF_HOB_LIST (Hob)) {
+ Hob.Raw = GET_NEXT_HOB (Hob);
+ }
+ //
+ // Need plus END_OF_HOB_LIST
+ //
+ return (UINTN)Hob.Raw - (UINTN)HobStart + sizeof (EFI_HOB_GENERIC_HEADER);
+}
+
+/**
+ The Entry Point for MM Core
+
+ Install DXE Protocols and reload MM Core into MMRAM and register MM Core
+ EntryPoint on the MMI vector.
+
+ Note: This function is called for both DXE invocation and MMRAM invocation.
+
+ @param ImageHandle The firmware allocated handle for the EFI image.
+ @param SystemTable A pointer to the EFI System Table.
+
+ @retval EFI_SUCCESS The entry point is executed successfully.
+ @retval Other Some error occurred when executing this entry point.
+
+**/
+EFI_STATUS
+EFIAPI
+StandaloneMmMain (
+ IN VOID *HobStart
+ )
+{
+ EFI_STATUS Status;
+ UINTN Index;
+ VOID *MmHobStart;
+ UINTN HobSize;
+ VOID *Registration;
+ EFI_HOB_GUID_TYPE *GuidHob;
+ MM_CORE_DATA_HOB_DATA *DataInHob;
+ EFI_HOB_GUID_TYPE *MmramRangesHob;
+ EFI_MMRAM_HOB_DESCRIPTOR_BLOCK *MmramRangesHobData;
+ EFI_MMRAM_DESCRIPTOR *MmramRanges;
+ UINT32 MmramRangeCount;
+ EFI_HOB_FIRMWARE_VOLUME *BfvHob;
+
+ ProcessLibraryConstructorList (HobStart, &gMmCoreMmst);
+
+ DEBUG ((DEBUG_INFO, "MmMain - 0x%x\n", HobStart));
+
+ //
+ // Determine if the caller has passed a reference to a MM_CORE_PRIVATE_DATA
+ // structure in the Hoblist. This choice will govern how boot information is
+ // extracted later.
+ //
+ GuidHob = GetNextGuidHob (&gMmCoreDataHobGuid, HobStart);
+ if (GuidHob == NULL) {
+ //
+ // Allocate and zero memory for a MM_CORE_PRIVATE_DATA table and then
+ // initialise it
+ //
+ gMmCorePrivate = (MM_CORE_PRIVATE_DATA *) AllocateRuntimePages(EFI_SIZE_TO_PAGES(sizeof (MM_CORE_PRIVATE_DATA)));
+ SetMem ((VOID *)(UINTN)gMmCorePrivate, sizeof (MM_CORE_PRIVATE_DATA), 0);
+ gMmCorePrivate->Signature = MM_CORE_PRIVATE_DATA_SIGNATURE;
+ gMmCorePrivate->MmEntryPointRegistered = FALSE;
+ gMmCorePrivate->InMm = FALSE;
+ gMmCorePrivate->ReturnStatus = EFI_SUCCESS;
+
+ //
+ // Extract the MMRAM ranges from the MMRAM descriptor HOB
+ //
+ MmramRangesHob = GetNextGuidHob (&gEfiMmPeiMmramMemoryReserveGuid, HobStart);
+ if (MmramRangesHob == NULL)
+ return EFI_UNSUPPORTED;
+
+ MmramRangesHobData = GET_GUID_HOB_DATA (MmramRangesHob);
+ ASSERT (MmramRangesHobData != NULL);
+ MmramRanges = MmramRangesHobData->Descriptor;
+ MmramRangeCount = MmramRangesHobData->NumberOfMmReservedRegions;
+ ASSERT (MmramRanges);
+ ASSERT (MmramRangeCount);
+
+ //
+ // Copy the MMRAM ranges into MM_CORE_PRIVATE_DATA table just in case any
+ // code relies on them being present there
+ //
+ gMmCorePrivate->MmramRangeCount = MmramRangeCount;
+ gMmCorePrivate->MmramRanges =
+ (EFI_PHYSICAL_ADDRESS)(UINTN)AllocatePool (MmramRangeCount * sizeof (EFI_MMRAM_DESCRIPTOR));
+ ASSERT (gMmCorePrivate->MmramRanges != 0);
+ CopyMem (
+ (VOID *)(UINTN)gMmCorePrivate->MmramRanges,
+ MmramRanges,
+ MmramRangeCount * sizeof (EFI_MMRAM_DESCRIPTOR)
+ );
+ } else {
+ DataInHob = GET_GUID_HOB_DATA (GuidHob);
+ gMmCorePrivate = (MM_CORE_PRIVATE_DATA *)(UINTN)DataInHob->Address;
+ MmramRanges = (EFI_MMRAM_DESCRIPTOR *)(UINTN)gMmCorePrivate->MmramRanges;
+ MmramRangeCount = gMmCorePrivate->MmramRangeCount;
+ }
+
+ //
+ // Print the MMRAM ranges passed by the caller
+ //
+ DEBUG ((DEBUG_INFO, "MmramRangeCount - 0x%x\n", MmramRangeCount));
+ for (Index = 0; Index < MmramRangeCount; Index++) {
+ DEBUG ((DEBUG_INFO, "MmramRanges[%d]: 0x%016lx - 0x%lx\n", Index,
+ MmramRanges[Index].CpuStart,
+ MmramRanges[Index].PhysicalSize));
+ }
+
+ //
+ // Copy the MMRAM ranges into private MMRAM
+ //
+ mMmramRangeCount = MmramRangeCount;
+ DEBUG ((DEBUG_INFO, "mMmramRangeCount - 0x%x\n", mMmramRangeCount));
+ mMmramRanges = AllocatePool (mMmramRangeCount * sizeof (EFI_MMRAM_DESCRIPTOR));
+ DEBUG ((DEBUG_INFO, "mMmramRanges - 0x%x\n", mMmramRanges));
+ ASSERT (mMmramRanges != NULL);
+ CopyMem (mMmramRanges, (VOID *)(UINTN)MmramRanges, mMmramRangeCount * sizeof (EFI_MMRAM_DESCRIPTOR));
+
+ //
+ // Get Boot Firmware Volume address from the BFV Hob
+ //
+ BfvHob = GetFirstHob (EFI_HOB_TYPE_FV);
+ if (BfvHob != NULL) {
+ DEBUG ((DEBUG_INFO, "BFV address - 0x%x\n", BfvHob->BaseAddress));
+ DEBUG ((DEBUG_INFO, "BFV size - 0x%x\n", BfvHob->Length));
+ gMmCorePrivate->StandaloneBfvAddress = BfvHob->BaseAddress;
+ }
+
+ gMmCorePrivate->Mmst = (EFI_PHYSICAL_ADDRESS)(UINTN)&gMmCoreMmst;
+ gMmCorePrivate->MmEntryPoint = (EFI_PHYSICAL_ADDRESS)(UINTN)MmEntryPoint;
+
+ //
+ // No need to initialize memory service.
+ // It is done in constructor of StandaloneMmCoreMemoryAllocationLib(),
+ // so that the library linked with StandaloneMmCore can use AllocatePool() in constuctor.
+ //
+
+ DEBUG ((DEBUG_INFO, "MmInstallConfigurationTable For HobList\n"));
+ //
+ // Install HobList
+ //
+ HobSize = GetHobListSize (HobStart);
+ DEBUG ((DEBUG_INFO, "HobSize - 0x%x\n", HobSize));
+ MmHobStart = AllocatePool (HobSize);
+ DEBUG ((DEBUG_INFO, "MmHobStart - 0x%x\n", MmHobStart));
+ ASSERT (MmHobStart != NULL);
+ CopyMem (MmHobStart, HobStart, HobSize);
+ Status = MmInstallConfigurationTable (&gMmCoreMmst, &gEfiHobListGuid, MmHobStart, HobSize);
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Register notification for EFI_MM_CONFIGURATION_PROTOCOL registration and
+ // use it to register the MM Foundation entrypoint
+ //
+ DEBUG ((DEBUG_INFO, "MmRegisterProtocolNotify - MmConfigurationMmProtocol\n"));
+ Status = MmRegisterProtocolNotify (
+ &gEfiMmConfigurationProtocolGuid,
+ MmConfigurationMmNotify,
+ &Registration
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Dispatch standalone BFV
+ //
+ DEBUG ((DEBUG_INFO, "Mm Dispatch StandaloneBfvAddress - 0x%08x\n", gMmCorePrivate->StandaloneBfvAddress));
+ if (gMmCorePrivate->StandaloneBfvAddress != 0) {
+ MmCoreFfsFindMmDriver ((EFI_FIRMWARE_VOLUME_HEADER *)(UINTN)gMmCorePrivate->StandaloneBfvAddress);
+ MmDispatcher ();
+ }
+
+ //
+ // Register all handlers in the core table
+ //
+ for (Index = 0; mMmCoreMmiHandlers[Index].HandlerType != NULL; Index++) {
+ Status = MmiHandlerRegister (
+ mMmCoreMmiHandlers[Index].Handler,
+ mMmCoreMmiHandlers[Index].HandlerType,
+ &mMmCoreMmiHandlers[Index].DispatchHandle
+ );
+ DEBUG ((DEBUG_INFO, "MmiHandlerRegister - GUID %g - Status %d\n", mMmCoreMmiHandlers[Index].HandlerType, Status));
+ }
+
+ DEBUG ((DEBUG_INFO, "MmMain Done!\n"));
+
+ return EFI_SUCCESS;
+}
diff --git a/StandaloneMmPkg/Core/StandaloneMmCore.h b/StandaloneMmPkg/Core/StandaloneMmCore.h
new file mode 100644
index 0000000000..0d20bcaa6b
--- /dev/null
+++ b/StandaloneMmPkg/Core/StandaloneMmCore.h
@@ -0,0 +1,903 @@
+/** @file
+ The internal header file includes the common header files, defines
+ internal structure and functions used by MmCore module.
+
+ Copyright (c) 2009 - 2014, Intel Corporation. All rights reserved.<BR>
+ Copyright (c) 2016 - 2018, ARM Limited. All rights reserved.<BR>
+
+ This program and the accompanying materials are licensed and made available
+ under the terms and conditions of the BSD License which accompanies this
+ distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef _MM_CORE_H_
+#define _MM_CORE_H_
+
+#include <PiMm.h>
+#include <StandaloneMm.h>
+
+#include <Protocol/DxeMmReadyToLock.h>
+#include <Protocol/MmReadyToLock.h>
+#include <Protocol/MmEndOfDxe.h>
+#include <Protocol/MmCommunication.h>
+#include <Protocol/LoadedImage.h>
+#include <Protocol/MmConfiguration.h>
+
+#include <Guid/Apriori.h>
+#include <Guid/EventGroup.h>
+#include <Guid/EventLegacyBios.h>
+#include <Guid/ZeroGuid.h>
+#include <Guid/MemoryProfile.h>
+#include <Guid/HobList.h>
+#include <Guid/MmFvDispatch.h>
+#include <Guid/MmramMemoryReserve.h>
+
+#include <Library/StandaloneMmCoreEntryPoint.h>
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/PeCoffLib.h>
+#include <Library/CacheMaintenanceLib.h>
+#include <Library/DebugLib.h>
+#include <Library/ReportStatusCodeLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/PcdLib.h>
+
+#include <Library/StandaloneMmMemLib.h>
+#include <Library/HobLib.h>
+
+#include "StandaloneMmCorePrivateData.h"
+
+//
+// Used to build a table of MMI Handlers that the MM Core registers
+//
+typedef struct {
+ EFI_MM_HANDLER_ENTRY_POINT Handler;
+ EFI_GUID *HandlerType;
+ EFI_HANDLE DispatchHandle;
+ BOOLEAN UnRegister;
+} MM_CORE_MMI_HANDLERS;
+
+//
+// Structure for recording the state of an MM Driver
+//
+#define EFI_MM_DRIVER_ENTRY_SIGNATURE SIGNATURE_32('s', 'd','r','v')
+
+typedef struct {
+ UINTN Signature;
+ LIST_ENTRY Link; // mDriverList
+
+ LIST_ENTRY ScheduledLink; // mScheduledQueue
+
+ EFI_HANDLE FvHandle;
+ EFI_GUID FileName;
+ VOID *Pe32Data;
+ UINTN Pe32DataSize;
+
+ VOID *Depex;
+ UINTN DepexSize;
+
+ BOOLEAN Before;
+ BOOLEAN After;
+ EFI_GUID BeforeAfterGuid;
+
+ BOOLEAN Dependent;
+ BOOLEAN Scheduled;
+ BOOLEAN Initialized;
+ BOOLEAN DepexProtocolError;
+
+ EFI_HANDLE ImageHandle;
+ EFI_LOADED_IMAGE_PROTOCOL *LoadedImage;
+ //
+ // Image EntryPoint in MMRAM
+ //
+ PHYSICAL_ADDRESS ImageEntryPoint;
+ //
+ // Image Buffer in MMRAM
+ //
+ PHYSICAL_ADDRESS ImageBuffer;
+ //
+ // Image Page Number
+ //
+ UINTN NumberOfPage;
+} EFI_MM_DRIVER_ENTRY;
+
+#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;
+} 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;
+} PROTOCOL_INTERFACE;
+
+#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;
+ /// Notification function
+ EFI_MM_NOTIFY_FN Function;
+ /// Last position notified
+ LIST_ENTRY *Position;
+} PROTOCOL_NOTIFY;
+
+//
+// MM Core Global Variables
+//
+extern MM_CORE_PRIVATE_DATA *gMmCorePrivate;
+extern EFI_MM_SYSTEM_TABLE gMmCoreMmst;
+extern LIST_ENTRY gHandleList;
+extern EFI_PHYSICAL_ADDRESS gLoadModuleAtFixAddressMmramBase;
+
+/**
+ Called to initialize the memory service.
+
+ @param MmramRangeCount Number of MMRAM Regions
+ @param MmramRanges Pointer to MMRAM Descriptors
+
+**/
+VOID
+MmInitializeMemoryServices (
+ IN UINTN MmramRangeCount,
+ IN EFI_MMRAM_DESCRIPTOR *MmramRanges
+ );
+
+/**
+ The MmInstallConfigurationTable() function is used to maintain the list
+ of configuration tables that are stored in the System Management System
+ Table. The list is stored as an array of (GUID, Pointer) pairs. The list
+ must be allocated from pool memory with PoolType set to EfiRuntimeServicesData.
+
+ @param SystemTable A pointer to the MM System Table (SMST).
+ @param Guid A pointer to the GUID for the entry to add, update, or remove.
+ @param Table A pointer to the buffer of the table to add.
+ @param TableSize The size of the table to install.
+
+ @retval EFI_SUCCESS The (Guid, Table) pair was added, updated, or removed.
+ @retval EFI_INVALID_PARAMETER Guid is not valid.
+ @retval EFI_NOT_FOUND An attempt was made to delete a non-existent entry.
+ @retval EFI_OUT_OF_RESOURCES There is not enough memory available to complete the operation.
+
+**/
+EFI_STATUS
+EFIAPI
+MmInstallConfigurationTable (
+ IN CONST EFI_MM_SYSTEM_TABLE *SystemTable,
+ IN CONST EFI_GUID *Guid,
+ IN VOID *Table,
+ IN UINTN TableSize
+ );
+
+/**
+ Wrapper function to MmInstallProtocolInterfaceNotify. 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
+MmInstallProtocolInterface (
+ IN OUT EFI_HANDLE *UserHandle,
+ IN EFI_GUID *Protocol,
+ IN EFI_INTERFACE_TYPE InterfaceType,
+ IN VOID *Interface
+ );
+
+/**
+ 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
+
+ @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
+MmAllocatePages (
+ IN EFI_ALLOCATE_TYPE Type,
+ IN EFI_MEMORY_TYPE MemoryType,
+ IN UINTN NumberOfPages,
+ OUT EFI_PHYSICAL_ADDRESS *Memory
+ );
+
+/**
+ 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
+
+ @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
+MmInternalAllocatePages (
+ IN EFI_ALLOCATE_TYPE Type,
+ IN EFI_MEMORY_TYPE MemoryType,
+ IN UINTN NumberOfPages,
+ 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, Address is zero or NumberOfPages is zero.
+ @return EFI_SUCCESS Pages successfully freed.
+
+**/
+EFI_STATUS
+EFIAPI
+MmFreePages (
+ IN EFI_PHYSICAL_ADDRESS Memory,
+ IN UINTN NumberOfPages
+ );
+
+/**
+ 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, Address is zero or NumberOfPages is zero.
+ @return EFI_SUCCESS Pages successfully freed.
+
+**/
+EFI_STATUS
+EFIAPI
+MmInternalFreePages (
+ IN EFI_PHYSICAL_ADDRESS Memory,
+ IN UINTN NumberOfPages
+ );
+
+/**
+ 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
+ @retval EFI_OUT_OF_RESOURCES Size exceeds max pool size or allocation failed.
+ @retval EFI_SUCCESS Pool successfully allocated.
+
+**/
+EFI_STATUS
+EFIAPI
+MmAllocatePool (
+ 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
+ @retval EFI_OUT_OF_RESOURCES Size exceeds max pool size or allocation failed.
+ @retval EFI_SUCCESS Pool successfully allocated.
+
+**/
+EFI_STATUS
+EFIAPI
+MmInternalAllocatePool (
+ 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
+MmFreePool (
+ IN 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
+MmInternalFreePool (
+ IN VOID *Buffer
+ );
+
+/**
+ 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
+MmInstallProtocolInterfaceNotify (
+ IN OUT EFI_HANDLE *UserHandle,
+ IN EFI_GUID *Protocol,
+ IN EFI_INTERFACE_TYPE InterfaceType,
+ IN VOID *Interface,
+ IN BOOLEAN Notify
+ );
+
+/**
+ 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
+MmUninstallProtocolInterface (
+ 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
+MmHandleProtocol (
+ IN EFI_HANDLE UserHandle,
+ IN EFI_GUID *Protocol,
+ OUT VOID **Interface
+ );
+
+/**
+ Add a new protocol notification record for the request protocol.
+
+ @param Protocol The requested protocol to add the notify
+ registration
+ @param Function Points to the notification function
+ @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
+MmRegisterProtocolNotify (
+ IN CONST EFI_GUID *Protocol,
+ IN EFI_MM_NOTIFY_FN Function,
+ OUT VOID **Registration
+ );
+
+/**
+ 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
+MmLocateHandle (
+ IN EFI_LOCATE_SEARCH_TYPE SearchType,
+ IN EFI_GUID *Protocol OPTIONAL,
+ IN VOID *SearchKey OPTIONAL,
+ IN OUT UINTN *BufferSize,
+ OUT EFI_HANDLE *Buffer
+ );
+
+/**
+ Return the first Protocol Interface that matches the Protocol GUID. If
+ Registration is pasased in return a Protocol Instance that was just add
+ to the system. If Retistration 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
+MmLocateProtocol (
+ IN EFI_GUID *Protocol,
+ IN VOID *Registration OPTIONAL,
+ OUT VOID **Interface
+ );
+
+/**
+ Manage MMI of a particular type.
+
+ @param HandlerType Points to the handler type or NULL for root MMI handlers.
+ @param Context Points to an optional context buffer.
+ @param CommBuffer Points to the optional communication buffer.
+ @param CommBufferSize Points to the size of the optional communication buffer.
+
+ @retval EFI_SUCCESS Interrupt source was processed successfully but not quiesced.
+ @retval EFI_INTERRUPT_PENDING One or more MMI sources could not be quiesced.
+ @retval EFI_WARN_INTERRUPT_SOURCE_PENDING Interrupt source was not handled or quiesced.
+ @retval EFI_WARN_INTERRUPT_SOURCE_QUIESCED Interrupt source was handled and quiesced.
+
+**/
+EFI_STATUS
+EFIAPI
+MmiManage (
+ IN CONST EFI_GUID *HandlerType,
+ IN CONST VOID *Context OPTIONAL,
+ IN OUT VOID *CommBuffer OPTIONAL,
+ IN OUT UINTN *CommBufferSize OPTIONAL
+ );
+
+/**
+ Registers a handler to execute within MM.
+
+ @param Handler Handler service funtion pointer.
+ @param HandlerType Points to the handler type or NULL for root MMI handlers.
+ @param DispatchHandle On return, contains a unique handle which can be used to later unregister the handler function.
+
+ @retval EFI_SUCCESS Handler register success.
+ @retval EFI_INVALID_PARAMETER Handler or DispatchHandle is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+MmiHandlerRegister (
+ IN EFI_MM_HANDLER_ENTRY_POINT Handler,
+ IN CONST EFI_GUID *HandlerType OPTIONAL,
+ OUT EFI_HANDLE *DispatchHandle
+ );
+
+/**
+ Unregister a handler in MM.
+
+ @param DispatchHandle The handle that was specified when the handler was registered.
+
+ @retval EFI_SUCCESS Handler function was successfully unregistered.
+ @retval EFI_INVALID_PARAMETER DispatchHandle does not refer to a valid handle.
+
+**/
+EFI_STATUS
+EFIAPI
+MmiHandlerUnRegister (
+ IN EFI_HANDLE DispatchHandle
+ );
+
+/**
+ This function is the main entry point for an MM handler dispatch
+ or communicate-based callback.
+
+ @param DispatchHandle The unique handle assigned to this handler by MmiHandlerRegister().
+ @param Context Points to an optional handler context which was specified when the handler was registered.
+ @param CommBuffer A pointer to a collection of data in memory that will
+ be conveyed from a non-MM environment into an MM environment.
+ @param CommBufferSize The size of the CommBuffer.
+
+ @return Status Code
+
+**/
+EFI_STATUS
+EFIAPI
+MmDriverDispatchHandler (
+ IN EFI_HANDLE DispatchHandle,
+ IN CONST VOID *Context, OPTIONAL
+ IN OUT VOID *CommBuffer, OPTIONAL
+ IN OUT UINTN *CommBufferSize OPTIONAL
+ );
+
+/**
+ This function is the main entry point for an MM handler dispatch
+ or communicate-based callback.
+
+ @param DispatchHandle The unique handle assigned to this handler by MmiHandlerRegister().
+ @param Context Points to an optional handler context which was specified when the handler was registered.
+ @param CommBuffer A pointer to a collection of data in memory that will
+ be conveyed from a non-MM environment into an MM environment.
+ @param CommBufferSize The size of the CommBuffer.
+
+ @return Status Code
+
+**/
+EFI_STATUS
+EFIAPI
+MmFvDispatchHandler (
+ IN EFI_HANDLE DispatchHandle,
+ IN CONST VOID *Context, OPTIONAL
+ IN OUT VOID *CommBuffer, OPTIONAL
+ IN OUT UINTN *CommBufferSize OPTIONAL
+ );
+
+/**
+ This function is the main entry point for an MM handler dispatch
+ or communicate-based callback.
+
+ @param DispatchHandle The unique handle assigned to this handler by MmiHandlerRegister().
+ @param Context Points to an optional handler context which was specified when the handler was registered.
+ @param CommBuffer A pointer to a collection of data in memory that will
+ be conveyed from a non-MM environment into an MM environment.
+ @param CommBufferSize The size of the CommBuffer.
+
+ @return Status Code
+
+**/
+EFI_STATUS
+EFIAPI
+MmLegacyBootHandler (
+ IN EFI_HANDLE DispatchHandle,
+ IN CONST VOID *Context, OPTIONAL
+ IN OUT VOID *CommBuffer, OPTIONAL
+ IN OUT UINTN *CommBufferSize OPTIONAL
+ );
+
+/**
+ This function is the main entry point for an MM handler dispatch
+ or communicate-based callback.
+
+ @param DispatchHandle The unique handle assigned to this handler by MmiHandlerRegister().
+ @param Context Points to an optional handler context which was specified when the handler was registered.
+ @param CommBuffer A pointer to a collection of data in memory that will
+ be conveyed from a non-MM environment into an MM environment.
+ @param CommBufferSize The size of the CommBuffer.
+
+ @return Status Code
+
+**/
+EFI_STATUS
+EFIAPI
+MmExitBootServiceHandler (
+ IN EFI_HANDLE DispatchHandle,
+ IN CONST VOID *Context, OPTIONAL
+ IN OUT VOID *CommBuffer, OPTIONAL
+ IN OUT UINTN *CommBufferSize OPTIONAL
+ );
+
+/**
+ This function is the main entry point for an MM handler dispatch
+ or communicate-based callback.
+
+ @param DispatchHandle The unique handle assigned to this handler by MmiHandlerRegister().
+ @param Context Points to an optional handler context which was specified when the handler was registered.
+ @param CommBuffer A pointer to a collection of data in memory that will
+ be conveyed from a non-MM environment into an MM environment.
+ @param CommBufferSize The size of the CommBuffer.
+
+ @return Status Code
+
+**/
+EFI_STATUS
+EFIAPI
+MmReadyToBootHandler (
+ IN EFI_HANDLE DispatchHandle,
+ IN CONST VOID *Context, OPTIONAL
+ IN OUT VOID *CommBuffer, OPTIONAL
+ IN OUT UINTN *CommBufferSize OPTIONAL
+ );
+
+/**
+ This function is the main entry point for an MM handler dispatch
+ or communicate-based callback.
+
+ @param DispatchHandle The unique handle assigned to this handler by MmiHandlerRegister().
+ @param Context Points to an optional handler context which was specified when the handler was registered.
+ @param CommBuffer A pointer to a collection of data in memory that will
+ be conveyed from a non-MM environment into an MM environment.
+ @param CommBufferSize The size of the CommBuffer.
+
+ @return Status Code
+
+**/
+EFI_STATUS
+EFIAPI
+MmReadyToLockHandler (
+ IN EFI_HANDLE DispatchHandle,
+ IN CONST VOID *Context, OPTIONAL
+ IN OUT VOID *CommBuffer, OPTIONAL
+ IN OUT UINTN *CommBufferSize OPTIONAL
+ );
+
+/**
+ This function is the main entry point for an MM handler dispatch
+ or communicate-based callback.
+
+ @param DispatchHandle The unique handle assigned to this handler by MmiHandlerRegister().
+ @param Context Points to an optional handler context which was specified when the handler was registered.
+ @param CommBuffer A pointer to a collection of data in memory that will
+ be conveyed from a non-MM environment into an MM environment.
+ @param CommBufferSize The size of the CommBuffer.
+
+ @return Status Code
+
+**/
+EFI_STATUS
+EFIAPI
+MmEndOfDxeHandler (
+ IN EFI_HANDLE DispatchHandle,
+ IN CONST VOID *Context, OPTIONAL
+ IN OUT VOID *CommBuffer, OPTIONAL
+ IN OUT UINTN *CommBufferSize OPTIONAL
+ );
+
+/**
+ Place holder function until all the MM System Table Service 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
+MmEfiNotAvailableYetArg5 (
+ UINTN Arg1,
+ UINTN Arg2,
+ UINTN Arg3,
+ UINTN Arg4,
+ UINTN Arg5
+ );
+
+//
+//Functions used during debug buils
+//
+
+/**
+ Traverse the discovered list for any drivers that were discovered but not loaded
+ because the dependency expressions evaluated to false.
+
+**/
+VOID
+MmDisplayDiscoveredNotDispatched (
+ VOID
+ );
+
+/**
+ Add free MMRAM region for use by memory service.
+
+ @param MemBase Base address of memory region.
+ @param MemLength Length of the memory region.
+ @param Type Memory type.
+ @param Attributes Memory region state.
+
+**/
+VOID
+MmAddMemoryRegion (
+ IN EFI_PHYSICAL_ADDRESS MemBase,
+ IN UINT64 MemLength,
+ IN EFI_MEMORY_TYPE Type,
+ IN UINT64 Attributes
+ );
+
+/**
+ Finds the protocol entry for the requested protocol.
+
+ @param Protocol The ID of the protocol
+ @param Create Create a new entry if not found
+
+ @return Protocol entry
+
+**/
+PROTOCOL_ENTRY *
+MmFindProtocolEntry (
+ IN EFI_GUID *Protocol,
+ IN BOOLEAN Create
+ );
+
+/**
+ Signal event for every protocol in protocol entry.
+
+ @param Prot Protocol interface
+
+**/
+VOID
+MmNotifyProtocol (
+ IN PROTOCOL_INTERFACE *Prot
+ );
+
+/**
+ 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 *
+MmFindProtocolInterface (
+ 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 *
+MmRemoveInterfaceFromProtocol (
+ IN IHANDLE *Handle,
+ IN EFI_GUID *Protocol,
+ IN VOID *Interface
+ );
+
+/**
+ 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. 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
+MmIsSchedulable (
+ IN EFI_MM_DRIVER_ENTRY *DriverEntry
+ );
+
+/**
+ Dump MMRAM information.
+
+**/
+VOID
+DumpMmramInfo (
+ VOID
+ );
+
+extern UINTN mMmramRangeCount;
+extern EFI_MMRAM_DESCRIPTOR *mMmramRanges;
+extern EFI_SYSTEM_TABLE *mEfiSystemTable;
+
+#endif
diff --git a/StandaloneMmPkg/Core/StandaloneMmCore.inf b/StandaloneMmPkg/Core/StandaloneMmCore.inf
new file mode 100644
index 0000000000..ff2b8b9cef
--- /dev/null
+++ b/StandaloneMmPkg/Core/StandaloneMmCore.inf
@@ -0,0 +1,80 @@
+## @file
+# This module provide an SMM CIS compliant implementation of SMM Core.
+#
+# Copyright (c) 2009 - 2015, Intel Corporation. All rights reserved.<BR>
+# Copyright (c) 2016 - 2018, ARM Limited. All rights reserved.<BR>
+#
+# This program and the accompanying materials
+# are licensed and made available under the terms and conditions of the BSD License
+# which accompanies this distribution. The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+##
+
+[Defines]
+ INF_VERSION = 0x0001001A
+ BASE_NAME = StandaloneMmCore
+ FILE_GUID = 6E14B6FD-3600-4DD6-A17A-206B3B6DCE16
+ MODULE_TYPE = MM_CORE_STANDALONE
+ VERSION_STRING = 1.0
+ PI_SPECIFICATION_VERSION = 0x00010032
+ ENTRY_POINT = StandaloneMmMain
+
+# VALID_ARCHITECTURES = IA32 X64 AARCH64
+
+[Sources]
+ StandaloneMmCore.c
+ StandaloneMmCore.h
+ StandaloneMmCorePrivateData.h
+ Page.c
+ Pool.c
+ Handle.c
+ Locate.c
+ Notify.c
+ Dependency.c
+ Dispatcher.c
+ Mmi.c
+ InstallConfigurationTable.c
+ FwVol.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+ StandaloneMmPkg/StandaloneMmPkg.dec
+
+[LibraryClasses]
+ BaseLib
+ BaseMemoryLib
+ CacheMaintenanceLib
+ DebugLib
+ FvLib
+ HobLib
+ MemoryAllocationLib
+ MemLib
+ PeCoffLib
+ ReportStatusCodeLib
+ StandaloneMmCoreEntryPoint
+
+[Protocols]
+ gEfiDxeMmReadyToLockProtocolGuid ## UNDEFINED # SmiHandlerRegister
+ gEfiMmReadyToLockProtocolGuid ## PRODUCES
+ gEfiMmEndOfDxeProtocolGuid ## PRODUCES
+ gEfiLoadedImageProtocolGuid ## PRODUCES
+ gEfiMmConfigurationProtocolGuid ## CONSUMES
+
+[Guids]
+ gAprioriGuid ## SOMETIMES_CONSUMES ## File
+ gEfiEventDxeDispatchGuid ## PRODUCES ## GUID # SmiHandlerRegister
+ gEfiEndOfDxeEventGroupGuid ## PRODUCES ## GUID # SmiHandlerRegister
+ ## SOMETIMES_CONSUMES ## GUID # Locate protocol
+ ## SOMETIMES_PRODUCES ## GUID # SmiHandlerRegister
+ gEdkiiMemoryProfileGuid
+ gZeroGuid ## SOMETIMES_CONSUMES ## GUID
+ gEfiHobListGuid
+ gMmCoreDataHobGuid
+ gMmFvDispatchGuid
+ gEfiEventLegacyBootGuid
+ gEfiEventExitBootServicesGuid
+ gEfiEventReadyToBootGuid
diff --git a/StandaloneMmPkg/Core/StandaloneMmCorePrivateData.h b/StandaloneMmPkg/Core/StandaloneMmCorePrivateData.h
new file mode 100644
index 0000000000..d9598937cf
--- /dev/null
+++ b/StandaloneMmPkg/Core/StandaloneMmCorePrivateData.h
@@ -0,0 +1,66 @@
+/** @file
+ The internal header file that declared a data structure that is shared
+ between the MM IPL and the MM Core.
+
+ Copyright (c) 2009 - 2014, Intel Corporation. All rights reserved.<BR>
+ Copyright (c) 2016 - 2018, ARM Limited. All rights reserved.<BR>
+ This program and the accompanying materials are licensed and made available
+ under the terms and conditions of the BSD License which accompanies this
+ distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef _STANDALONE_MM_CORE_PRIVATE_DATA_H_
+#define _STANDALONE_MM_CORE_PRIVATE_DATA_H_
+
+#include <Guid/MmCoreData.h>
+
+//
+// Page management
+//
+
+typedef struct {
+ LIST_ENTRY Link;
+ UINTN NumberOfPages;
+} FREE_PAGE_LIST;
+
+extern LIST_ENTRY mMmMemoryMap;
+
+//
+// Pool management
+//
+
+//
+// MIN_POOL_SHIFT must not be less than 5
+//
+#define MIN_POOL_SHIFT 6
+#define MIN_POOL_SIZE (1 << MIN_POOL_SHIFT)
+
+//
+// MAX_POOL_SHIFT must not be less than EFI_PAGE_SHIFT - 1
+//
+#define MAX_POOL_SHIFT (EFI_PAGE_SHIFT - 1)
+#define MAX_POOL_SIZE (1 << MAX_POOL_SHIFT)
+
+//
+// MAX_POOL_INDEX are calculated by maximum and minimum pool sizes
+//
+#define MAX_POOL_INDEX (MAX_POOL_SHIFT - MIN_POOL_SHIFT + 1)
+
+typedef struct {
+ UINTN Size;
+ BOOLEAN Available;
+} POOL_HEADER;
+
+typedef struct {
+ POOL_HEADER Header;
+ LIST_ENTRY Link;
+} FREE_POOL_HEADER;
+
+extern LIST_ENTRY mMmPoolLists[MAX_POOL_INDEX];
+
+#endif
diff --git a/StandaloneMmPkg/Include/Guid/MmFvDispatch.h b/StandaloneMmPkg/Include/Guid/MmFvDispatch.h
new file mode 100644
index 0000000000..d141d40d8d
--- /dev/null
+++ b/StandaloneMmPkg/Include/Guid/MmFvDispatch.h
@@ -0,0 +1,39 @@
+/** @file
+ GUIDs for MM Event.
+
+Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
+Copyright (c) 2016 - 2018, ARM Limited. All rights reserved.<BR>
+
+This program and the accompanying materials are licensed and made available under
+the terms and conditions of the BSD License that accompanies this distribution.
+The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php.
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef __MM_FV_DISPATCH_H__
+#define __MM_FV_DISPATCH_H__
+
+#define MM_FV_DISPATCH_GUID \
+ { 0xb65694cc, 0x9e3, 0x4c3b, { 0xb5, 0xcd, 0x5, 0xf4, 0x4d, 0x3c, 0xdb, 0xff }}
+
+extern EFI_GUID gMmFvDispatchGuid;
+
+#pragma pack(1)
+
+typedef struct {
+ EFI_PHYSICAL_ADDRESS Address;
+ UINT64 Size;
+} EFI_MM_COMMUNICATE_FV_DISPATCH_DATA;
+
+typedef struct {
+ EFI_GUID HeaderGuid;
+ UINTN MessageLength;
+ EFI_MM_COMMUNICATE_FV_DISPATCH_DATA Data;
+} EFI_MM_COMMUNICATE_FV_DISPATCH;
+#pragma pack()
+
+#endif
diff --git a/StandaloneMmPkg/Include/Library/StandaloneMmCoreEntryPoint.h b/StandaloneMmPkg/Include/Library/StandaloneMmCoreEntryPoint.h
new file mode 100644
index 0000000000..f53094bfc3
--- /dev/null
+++ b/StandaloneMmPkg/Include/Library/StandaloneMmCoreEntryPoint.h
@@ -0,0 +1,101 @@
+/** @file
+ Module entry point library for STANDALONE MM core.
+
+Copyright (c) 2006 - 2008, Intel Corporation. All rights reserved.<BR>
+Copyright (c) 2016 - 2018, ARM Limited. All rights reserved.<BR>
+
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef __MODULE_ENTRY_POINT_H__
+#define __MODULE_ENTRY_POINT_H__
+
+///
+/// Global variable that contains a pointer to the Hob List passed into the STANDALONE MM Core entry point.
+///
+extern VOID *gHobList;
+
+
+/**
+ The entry point of PE/COFF Image for the STANDALONE MM Core.
+
+ This function is the entry point for the STANDALONE MM Core. This function is required to call
+ ProcessModuleEntryPointList() and ProcessModuleEntryPointList() is never expected to return.
+ The STANDALONE MM Core is responsible for calling ProcessLibraryConstructorList() as soon as the EFI
+ System Table and the image handle for the STANDALONE MM Core itself have been established.
+ If ProcessModuleEntryPointList() returns, then ASSERT() and halt the system.
+
+ @param HobStart Pointer to the beginning of the HOB List passed in from the PEI Phase.
+
+**/
+VOID
+EFIAPI
+_ModuleEntryPoint (
+ IN VOID *HobStart
+ );
+
+
+/**
+ Required by the EBC compiler and identical in functionality to _ModuleEntryPoint().
+
+ This function is required to call _ModuleEntryPoint() passing in HobStart.
+
+ @param HobStart Pointer to the beginning of the HOB List passed in from the PEI Phase.
+
+**/
+VOID
+EFIAPI
+EfiMain (
+ IN VOID *HobStart
+ );
+
+
+/**
+ Auto generated function that calls the library constructors for all of the module's dependent libraries.
+
+ This function must be called by _ModuleEntryPoint().
+ This function calls the set of library constructors for the set of library instances
+ that a module depends on. This includes library instances that a module depends on
+ directly and library instances that a module depends on indirectly through other
+ libraries. This function is auto generated by build tools and those build tools are
+ responsible for collecting the set of library instances, determine which ones have
+ constructors, and calling the library constructors in the proper order based upon
+ each of the library instances own dependencies.
+
+ @param ImageHandle The image handle of the STANDALONE MM Core.
+ @param SystemTable A pointer to the EFI System Table.
+
+**/
+VOID
+EFIAPI
+ProcessLibraryConstructorList (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_MM_SYSTEM_TABLE *MmSystemTable
+ );
+
+
+/**
+ Autogenerated function that calls a set of module entry points.
+
+ This function must be called by _ModuleEntryPoint().
+ This function calls the set of module entry points.
+ This function is auto generated by build tools and those build tools are responsible
+ for collecting the module entry points and calling them in a specified order.
+
+ @param HobStart Pointer to the beginning of the HOB List passed in from the PEI Phase.
+
+**/
+VOID
+EFIAPI
+ProcessModuleEntryPointList (
+ IN VOID *HobStart
+ );
+
+#endif
diff --git a/StandaloneMmPkg/Include/StandaloneMm.h b/StandaloneMmPkg/Include/StandaloneMm.h
new file mode 100644
index 0000000000..2517d41e74
--- /dev/null
+++ b/StandaloneMmPkg/Include/StandaloneMm.h
@@ -0,0 +1,36 @@
+/** @file
+ Standalone MM.
+
+Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
+Copyright (c) 2016 - 2018, ARM Limited. All rights reserved.<BR>
+
+This program and the accompanying materials
+are licensed and made available under the terms and conditions
+of the BSD License which accompanies this distribution. The
+full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef _STANDALONE_MM_H_
+#define _STANDALONE_MM_H_
+
+#include <PiMm.h>
+
+typedef
+EFI_STATUS
+(EFIAPI *MM_IMAGE_ENTRY_POINT) (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_MM_SYSTEM_TABLE *MmSystemTable
+ );
+
+typedef
+EFI_STATUS
+(EFIAPI *STANDALONE_MM_FOUNDATION_ENTRY_POINT) (
+ IN VOID *HobStart
+ );
+
+#endif