From: Achin Gupta <achin.gupta@arm.com>
To: Ard Biesheuvel <ard.biesheuvel@linaro.org>
Cc: Laszlo Ersek <lersek@redhat.com>,
"Kinney, Michael D" <michael.d.kinney@intel.com>,
Leif Lindholm <leif.lindholm@linaro.org>,
Andrew Fish <afish@apple.com>,
Supreeth Venkatesh <supreeth.venkatesh@arm.com>,
"edk2-devel@lists.01.org" <edk2-devel@lists.01.org>,
"Gao, Liming" <liming.gao@intel.com>,
"Yao, Jiewen" <jiewen.yao@intel.com>, nd <nd@arm.com>
Subject: Re: [PATCH v1 13/18] StandaloneMmPkg/Core: Implementation of Standalone MM Core Module.
Date: Mon, 30 Apr 2018 21:17:55 +0100 [thread overview]
Message-ID: <20180430201753.GC663@e104320-lin> (raw)
In-Reply-To: <CAKv+Gu-9aHsM6wxycF4mkWS6p-bc5ZkytUupGpbGCVDpAVs46g@mail.gmail.com>
On Mon, Apr 30, 2018 at 09:28:57PM +0200, Ard Biesheuvel wrote:
> On 30 April 2018 at 21:19, Achin Gupta <achin.gupta@arm.com> wrote:
> > Hi Supreeth,
> >
> > I think it is worth adding a signed off by Jiewen since he originally
> > contributed the code and it has not changed much since.
>
> I disagree. A signoff does not assert authorship, it only means that
> the contributor asserts that the license permits him to contribute
> this code under the tianocore contribution agreement. Adding a signoff
> on behalf of someone else should be avoided in my opinion, because it
> suggests that code can only be contributed by the original author.
> Also, even if the author made the code available under a compatible
> license, it does not mean he subscribes to the Tianocore contribution
> agreement, and adding a signoff on behalf of someone else does imply
> that (although this should not be a problem in this particular case)
>
> Anyone can contribute code that is available under a compatible
> license, and it is not generally possible to decide who should be
> credited as authors for code that originates in other projects.
>
> If you want to credit the author, you can do that in the commit log.
Thanks for the clarification. I am fine with that.
cheers,
Achin
>
>
>
> > Please update the
> > correct year in the copyright headers too.
> >
> > Acked-by: Achin Gupta <achin.gupta@arm.com>
> >
> > cheers,
> > Achin
> >
> > On Fri, Apr 06, 2018 at 03:42:18PM +0100, Supreeth Venkatesh wrote:
> >> Management Mode (MM) is a generic term used to describe a secure
> >> execution environment provided by the CPU and related silicon that is
> >> entered when the CPU detects a MMI. For x86 systems, this can be
> >> implemented with System Management Mode (SMM). For ARM systems, this can
> >> be implemented with TrustZone (TZ).
> >> A MMI can be a CPU instruction or interrupt. Upon detection of a MMI, a
> >> CPU will jump to the MM Entry Point and save some portion of its state
> >> (the "save state") such that execution can be resumed.
> >> The MMI can be generated synchronously by software or asynchronously by
> >> a hardware event. Each MMI source can be detected, cleared and disabled.
> >> Some systems provide for special memory (Management Mode RAM or MMRAM)
> >> which is set aside for software running in MM. Usually the MMRAM is
> >> hidden during normal CPU execution, but this is not required. Usually,
> >> after MMRAM is hidden it cannot be exposed until the next system reset.
> >>
> >> The MM Core Interface Specification describes three pieces of the PI
> >> Management Mode architecture:
> >> 1. MM Dispatch
> >> During DXE, the DXE Foundation works with the MM Foundation to
> >> schedule MM drivers for execution in the discovered firmware volumes.
> >> 2. MM Initialization
> >> MM related code opens MMRAM, creates the MMRAM memory map, and
> >> launches the MM Foundation, which provides the necessary services to
> >> launch MM-related drivers. Then, sometime before boot, MMRAM is
> >> closed and locked. This piece may be completed during the
> >> SEC, PEI or DXE phases.
> >> 3. MMI Management
> >> When an MMI generated, the MM environment is created and then the MMI
> >>
> >> sources are detected and MMI handlers called.
> >>
> >> This patch implements the MM Core.
> >>
> >> Contributed-under: TianoCore Contribution Agreement 1.1
> >> Signed-off-by: Achin Gupta <achin.gupta@arm.com>
> >> Signed-off-by: Supreeth Venkatesh <supreeth.venkatesh@arm.com>
> >> ---
> >> StandaloneMmPkg/Core/Dependency.c | 389 +++++++
> >> StandaloneMmPkg/Core/Dispatcher.c | 1071 ++++++++++++++++++++
> >> StandaloneMmPkg/Core/FwVol.c | 104 ++
> >> StandaloneMmPkg/Core/Handle.c | 533 ++++++++++
> >> StandaloneMmPkg/Core/InstallConfigurationTable.c | 178 ++++
> >> StandaloneMmPkg/Core/Locate.c | 496 +++++++++
> >> StandaloneMmPkg/Core/Mmi.c | 337 ++++++
> >> StandaloneMmPkg/Core/Notify.c | 203 ++++
> >> StandaloneMmPkg/Core/Page.c | 384 +++++++
> >> StandaloneMmPkg/Core/Pool.c | 287 ++++++
> >> StandaloneMmPkg/Core/StandaloneMmCore.c | 708 +++++++++++++
> >> StandaloneMmPkg/Core/StandaloneMmCore.h | 903 +++++++++++++++++
> >> StandaloneMmPkg/Core/StandaloneMmCore.inf | 80 ++
> >> StandaloneMmPkg/Core/StandaloneMmCorePrivateData.h | 66 ++
> >> StandaloneMmPkg/Include/Guid/MmFvDispatch.h | 38 +
> >> StandaloneMmPkg/Include/StandaloneMm.h | 36 +
> >> 16 files changed, 5813 insertions(+)
> >> create mode 100644 StandaloneMmPkg/Core/Dependency.c
> >> create mode 100644 StandaloneMmPkg/Core/Dispatcher.c
> >> create mode 100644 StandaloneMmPkg/Core/FwVol.c
> >> create mode 100644 StandaloneMmPkg/Core/Handle.c
> >> create mode 100644 StandaloneMmPkg/Core/InstallConfigurationTable.c
> >> create mode 100644 StandaloneMmPkg/Core/Locate.c
> >> create mode 100644 StandaloneMmPkg/Core/Mmi.c
> >> create mode 100644 StandaloneMmPkg/Core/Notify.c
> >> create mode 100644 StandaloneMmPkg/Core/Page.c
> >> create mode 100644 StandaloneMmPkg/Core/Pool.c
> >> create mode 100644 StandaloneMmPkg/Core/StandaloneMmCore.c
> >> create mode 100644 StandaloneMmPkg/Core/StandaloneMmCore.h
> >> create mode 100644 StandaloneMmPkg/Core/StandaloneMmCore.inf
> >> create mode 100644 StandaloneMmPkg/Core/StandaloneMmCorePrivateData.h
> >> create mode 100644 StandaloneMmPkg/Include/Guid/MmFvDispatch.h
> >> create mode 100644 StandaloneMmPkg/Include/StandaloneMm.h
> >>
> >> diff --git a/StandaloneMmPkg/Core/Dependency.c b/StandaloneMmPkg/Core/Dependency.c
> >> new file mode 100644
> >> index 0000000000..e501369130
> >> --- /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 - 2017, 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..af18fa7eaa
> >> --- /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 - 2017, 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)); // &Image->ImageContext.PdbPointer[StartIndex]));
> >> + }
> >> + 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);
> >> +
> >> + /*REPORT_STATUS_CODE_WITH_EXTENDED_DATA (
> >> + EFI_PROGRESS_CODE,
> >> + EFI_SOFTWARE_MM_DRIVER | EFI_SW_PC_INIT_BEGIN,
> >> + &DriverEntry->ImageHandle,
> >> + sizeof (DriverEntry->ImageHandle)
> >> + );*/
> >> +
> >> + //
> >> + // 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);
> >> + }
> >> +
> >> + /*REPORT_STATUS_CODE_WITH_EXTENDED_DATA (
> >> + EFI_PROGRESS_CODE,
> >> + EFI_SOFTWARE_MM_DRIVER | EFI_SW_PC_INIT_END,
> >> + &DriverEntry->ImageHandle,
> >> + sizeof (DriverEntry->ImageHandle)
> >> + );*/
> >> +
> >> + 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..901c58bc53
> >> --- /dev/null
> >> +++ b/StandaloneMmPkg/Core/FwVol.c
> >> @@ -0,0 +1,104 @@
> >> +/**@file
> >> +
> >> +Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
> >> +Copyright (c) 2016 - 2017, 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..01832f4bbe
> >> --- /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 - 2017, 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..3a31c63f94
> >> --- /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 - 2017, 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..6a90575f99
> >> --- /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 - 2017, 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..29aba7b53d
> >> --- /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 - 2017, 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..d5fc8f50d1
> >> --- /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 - 2017, 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..ba3e7cea74
> >> --- /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 - 2017, 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..bdf1258381
> >> --- /dev/null
> >> +++ b/StandaloneMmPkg/Core/Pool.c
> >> @@ -0,0 +1,287 @@
> >> +/** @file
> >> + SMM Memory pool management functions.
> >> +
> >> + Copyright (c) 2009 - 2014, Intel Corporation. All rights reserved.<BR>
> >> + Copyright (c) 2016 - 2017, 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..0bb99b9710
> >> --- /dev/null
> >> +++ b/StandaloneMmPkg/Core/StandaloneMmCore.c
> >> @@ -0,0 +1,708 @@
> >> +/** @file
> >> + MM Core Main Entry Point
> >> +
> >> + Copyright (c) 2009 - 2014, Intel Corporation. All rights reserved.<BR>
> >> + Copyright (c) 2016 - 2017, 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);
> >> + //DEBUG ((DEBUG_INFO, "CommunicateHeader->HeaderGuid - %g\n", &CommunicateHeader->HeaderGuid));
> >> + 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..53921b7844
> >> --- /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 - 2017, 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/MmCoreStandaloneEntryPoint.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/MmCorePlatformHookLib.h>
> >> +#include <Library/MemLib.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..c5eaa14ba3
> >> --- /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 - 2017, 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..faedf3ff2d
> >> --- /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 - 2017, 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..fb194d3474
> >> --- /dev/null
> >> +++ b/StandaloneMmPkg/Include/Guid/MmFvDispatch.h
> >> @@ -0,0 +1,38 @@
> >> +/** @file
> >> + GUIDs for MM Event.
> >> +
> >> +Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
> >> +Copyright (c) 2016 - 2017, 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/StandaloneMm.h b/StandaloneMmPkg/Include/StandaloneMm.h
> >> new file mode 100644
> >> index 0000000000..0e420315bb
> >> --- /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 - 2017, 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
> >> --
> >> 2.16.2
> >>
next prev parent reply other threads:[~2018-04-30 20:16 UTC|newest]
Thread overview: 70+ messages / expand[flat|nested] mbox.gz Atom feed top
2018-04-06 14:42 [PATCH v1 00/18] *** Standalone Management Mode Core Interface for AARCH64 Platforms *** Supreeth Venkatesh
2018-04-06 14:42 ` [PATCH v1 01/18] ArmPkg: Add PCDs needed for MM communication driver Supreeth Venkatesh
2018-04-11 14:43 ` Achin Gupta
[not found] ` <AM4PR0802MB23063743A3B2F5A552BE320580870@AM4PR0802MB2306.eurprd08.prod.outlook.com>
2018-05-04 23:13 ` Supreeth Venkatesh
2018-05-04 23:17 ` Supreeth Venkatesh
2018-04-06 14:42 ` [PATCH v1 02/18] ArmPkg/Drivers: Add EFI_MM_COMMUNICATION_PROTOCOL DXE driver Supreeth Venkatesh
2018-04-11 14:00 ` Achin Gupta
2018-05-04 23:18 ` Supreeth Venkatesh
2018-04-06 14:42 ` [PATCH v1 03/18] ArmPkg/Include: Add MM interface SVC return codes Supreeth Venkatesh
2018-04-11 14:38 ` Achin Gupta
2018-05-04 23:19 ` Supreeth Venkatesh
2018-04-06 14:42 ` [PATCH v1 04/18] ArmPkg/ArmMmuLib: Add MMU Library suitable for use in S-EL0 Supreeth Venkatesh
2018-04-11 19:21 ` Achin Gupta
2018-05-04 23:19 ` Supreeth Venkatesh
2018-04-06 14:42 ` [PATCH v1 05/18] ArmPkg/ArmMmuLib: Add MMU library inf file " Supreeth Venkatesh
2018-04-11 19:24 ` Achin Gupta
2018-05-04 23:19 ` Supreeth Venkatesh
2018-04-06 14:42 ` [PATCH v1 06/18] StandaloneMmPkg: Add an AArch64 specific entry point library Supreeth Venkatesh
2018-04-16 14:04 ` Achin Gupta
2018-05-04 23:20 ` Supreeth Venkatesh
2018-04-06 14:42 ` [PATCH v1 07/18] StandaloneMmPkg/FvLib: Add a common FV Library for management mode Supreeth Venkatesh
2018-04-16 14:44 ` Achin Gupta
2018-05-04 23:21 ` Supreeth Venkatesh
2018-04-06 14:42 ` [PATCH v1 08/18] StandaloneMmPkg/MemLib: AARCH64 Specific instance of memory check library Supreeth Venkatesh
2018-04-16 15:12 ` Achin Gupta
2018-04-16 22:30 ` Yao, Jiewen
2018-04-25 10:35 ` Achin Gupta
2018-04-26 13:02 ` Yao, Jiewen
2018-05-04 23:21 ` Supreeth Venkatesh
2018-04-06 14:42 ` [PATCH v1 09/18] StandaloneMmPkg/MemoryAllocationLib: Add MM memory allocation library Supreeth Venkatesh
2018-04-25 14:33 ` Achin Gupta
2018-04-26 13:05 ` Yao, Jiewen
2018-05-04 23:23 ` Supreeth Venkatesh
2018-05-04 23:21 ` Supreeth Venkatesh
2018-04-06 14:42 ` [PATCH v1 10/18] StandaloneMmPkg/HobLib: Add AARCH64 Specific HOB Library for management mode Supreeth Venkatesh
2018-04-25 14:50 ` Achin Gupta
2018-04-26 13:04 ` Yao, Jiewen
2018-05-04 23:22 ` Supreeth Venkatesh
2018-05-04 23:25 ` Supreeth Venkatesh
2018-04-06 14:42 ` [PATCH v1 11/18] StandaloneMmPkg: MM driver entry point library Supreeth Venkatesh
2018-04-30 14:29 ` Achin Gupta
2018-05-04 23:24 ` Supreeth Venkatesh
2018-04-06 14:42 ` [PATCH v1 12/18] StandaloneMmPkg/CpuMm: Add CPU driver suitable for ARM Platforms Supreeth Venkatesh
2018-04-18 22:09 ` Daniil Egranov
2018-05-04 23:25 ` Supreeth Venkatesh
2018-04-30 15:50 ` Achin Gupta
2018-05-04 23:24 ` Supreeth Venkatesh
2018-04-06 14:42 ` [PATCH v1 13/18] StandaloneMmPkg/Core: Implementation of Standalone MM Core Module Supreeth Venkatesh
2018-04-30 19:19 ` Achin Gupta
2018-04-30 19:28 ` Ard Biesheuvel
2018-04-30 20:17 ` Achin Gupta [this message]
2018-05-01 8:18 ` Laszlo Ersek
2018-05-04 23:28 ` Supreeth Venkatesh
2018-04-06 14:42 ` [PATCH v1 14/18] StandaloneMmPkg: Describe the declaration, definition and fdf files Supreeth Venkatesh
2018-04-18 19:50 ` Daniil Egranov
2018-05-04 23:29 ` Supreeth Venkatesh
2018-04-30 19:32 ` Achin Gupta
2018-05-04 23:28 ` Supreeth Venkatesh
2018-04-06 14:42 ` [PATCH v1 15/18] ArmPkg: Extra action to update permissions for S-ELO MM Image Supreeth Venkatesh
2018-04-30 19:49 ` Achin Gupta
2018-05-04 23:30 ` Supreeth Venkatesh
2018-04-06 14:42 ` [PATCH v1 16/18] BaseTools/AutoGen: Update header file for MM modules Supreeth Venkatesh
2018-04-30 19:52 ` Achin Gupta
2018-05-04 23:30 ` Supreeth Venkatesh
2018-04-06 14:42 ` [PATCH v1 17/18] StandaloneMmPkg: Add application to test MM communication protocol Supreeth Venkatesh
2018-04-30 20:02 ` Achin Gupta
2018-05-04 23:31 ` Supreeth Venkatesh
2018-04-06 14:42 ` [PATCH v1 18/18] StandaloneMmPkg: Add handler to handle event received from Normal World Supreeth Venkatesh
2018-04-08 6:01 ` [PATCH v1 00/18] *** Standalone Management Mode Core Interface for AARCH64 Platforms *** Yao, Jiewen
2018-05-04 23:15 ` Supreeth Venkatesh
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-list from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20180430201753.GC663@e104320-lin \
--to=devel@edk2.groups.io \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox