diff options
| author | kx <kx@radix.pro> | 2024-06-04 06:43:08 +0300 |
|---|---|---|
| committer | kx <kx@radix.pro> | 2024-06-04 06:43:08 +0300 |
| commit | 7e2ccccace24636f29ddc210b94606abd4c7e42b (patch) | |
| tree | 545d43ea12671048956cafeb12303e84d601e571 /MdeModulePkg/Core/PiSmmCore | |
| parent | 27b044605cd5f6b33a3d231576003850b3fe305b (diff) | |
| download | edk2-trunk.tar.xz | |
Renormalized end-of-lines from master@27b044605cd5f6b33a3d231576003850b3fe305btrunk
Diffstat (limited to 'MdeModulePkg/Core/PiSmmCore')
24 files changed, 16561 insertions, 16561 deletions
diff --git a/MdeModulePkg/Core/PiSmmCore/Dependency.c b/MdeModulePkg/Core/PiSmmCore/Dependency.c index c070f4216b..d832a0454d 100644 --- a/MdeModulePkg/Core/PiSmmCore/Dependency.c +++ b/MdeModulePkg/Core/PiSmmCore/Dependency.c @@ -1,388 +1,388 @@ -/** @file
- SMM 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 - 2018, Intel Corporation. All rights reserved.<BR>
- SPDX-License-Identifier: BSD-2-Clause-Patent
-
-**/
-
-#include "PiSmmCore.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
-SmmIsSchedulable (
- IN EFI_SMM_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 SmmInsertOnScheduledQueueWhileProcessingBeforeAndAfter ()
- // processes them.
- //
- return FALSE;
- }
-
- DEBUG ((DEBUG_DISPATCH, "Evaluate SMM DEPEX for FFS(%g)\n", &DriverEntry->FileName));
-
- if (DriverEntry->Depex == NULL) {
- //
- // A NULL Depex means that the SMM driver is not built correctly.
- // All SMM drivers must have a valid depex expression.
- //
- 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 = SmmLocateProtocol (&DriverGuid, NULL, &Interface);
- if (EFI_ERROR (Status)) {
- //
- // For SMM Driver, it may depend on uefi protocols
- //
- Status = gBS->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 its intermediate value
- // may be strange.
- //
- Iterator++;
- }
-
-Done:
- return FALSE;
-}
+/** @file + SMM 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 - 2018, Intel Corporation. All rights reserved.<BR> + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "PiSmmCore.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 +SmmIsSchedulable ( + IN EFI_SMM_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 SmmInsertOnScheduledQueueWhileProcessingBeforeAndAfter () + // processes them. + // + return FALSE; + } + + DEBUG ((DEBUG_DISPATCH, "Evaluate SMM DEPEX for FFS(%g)\n", &DriverEntry->FileName)); + + if (DriverEntry->Depex == NULL) { + // + // A NULL Depex means that the SMM driver is not built correctly. + // All SMM drivers must have a valid depex expression. + // + 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 = SmmLocateProtocol (&DriverGuid, NULL, &Interface); + if (EFI_ERROR (Status)) { + // + // For SMM Driver, it may depend on uefi protocols + // + Status = gBS->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 its intermediate value + // may be strange. + // + Iterator++; + } + +Done: + return FALSE; +} diff --git a/MdeModulePkg/Core/PiSmmCore/Dispatcher.c b/MdeModulePkg/Core/PiSmmCore/Dispatcher.c index bb789e5890..cc2c29ff03 100644 --- a/MdeModulePkg/Core/PiSmmCore/Dispatcher.c +++ b/MdeModulePkg/Core/PiSmmCore/Dispatcher.c @@ -1,1539 +1,1539 @@ -/** @file
- SMM 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
- processes the After dependencies 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 Expression.
-
- Copyright (c) 2014, Hewlett-Packard Development Company, L.P.
- Copyright (c) 2009 - 2023, Intel Corporation. All rights reserved.<BR>
- SPDX-License-Identifier: BSD-2-Clause-Patent
-
-**/
-
-#include "PiSmmCore.h"
-
-//
-// SMM 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
-//
-
-/**
- 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
-SmmInsertOnScheduledQueueWhileProcessingBeforeAndAfter (
- IN EFI_SMM_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_SMM_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_SMM_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 SMM Dispatcher. TRUE if dispatcher is executing.
-//
-BOOLEAN gDispatcherRunning = FALSE;
-
-//
-// Flag for the SMM Dispatcher. TRUE if there is one or more SMM drivers ready to be dispatched
-//
-BOOLEAN gRequestDispatch = FALSE;
-
-//
-// List of file types supported by dispatcher
-//
-EFI_FV_FILETYPE mSmmFileTypes[] = {
- EFI_FV_FILETYPE_SMM,
- EFI_FV_FILETYPE_COMBINED_SMM_DXE,
- EFI_FV_FILETYPE_SMM_CORE,
- //
- // Note: DXE core will process the FV image file, so skip it in SMM core
- // EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE
- //
-};
-
-typedef struct {
- MEDIA_FW_VOL_FILEPATH_DEVICE_PATH File;
- EFI_DEVICE_PATH_PROTOCOL End;
-} FV_FILEPATH_DEVICE_PATH;
-
-FV_FILEPATH_DEVICE_PATH mFvDevicePath;
-
-//
-// DXE Architecture Protocols
-//
-EFI_SECURITY_ARCH_PROTOCOL *mSecurity = NULL;
-EFI_SECURITY2_ARCH_PROTOCOL *mSecurity2 = NULL;
-
-//
-// The global variable is defined for Loading modules at fixed address feature to track the SMM code
-// memory range usage. It is a bit mapped array in which every bit indicates the corresponding
-// memory page available or not.
-//
-GLOBAL_REMOVE_IF_UNREFERENCED UINT64 *mSmmCodeMemoryRangeUsageBitMap = 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 available, the function will mark the corresponding bits to 1 which indicates the memory range is used.
- The function is only invoked when load modules at fixed address feature is enabled.
-
- @param ImageBase The base address the image will be loaded at.
- @param ImageSize The size of the image
-
- @retval EFI_SUCCESS The memory range the image will be loaded in is available
- @retval EFI_NOT_FOUND The memory range the image will be loaded in is not available
-**/
-EFI_STATUS
-CheckAndMarkFixLoadingMemoryUsageBitMap (
- IN EFI_PHYSICAL_ADDRESS ImageBase,
- IN UINTN ImageSize
- )
-{
- UINT32 SmmCodePageNumber;
- UINT64 SmmCodeSize;
- EFI_PHYSICAL_ADDRESS SmmCodeBase;
- UINTN BaseOffsetPageNumber;
- UINTN TopOffsetPageNumber;
- UINTN Index;
-
- //
- // Build tool will calculate the smm code size and then patch the PcdLoadFixAddressSmmCodePageNumber
- //
- SmmCodePageNumber = PcdGet32 (PcdLoadFixAddressSmmCodePageNumber);
- SmmCodeSize = EFI_PAGES_TO_SIZE (SmmCodePageNumber);
- SmmCodeBase = gLoadModuleAtFixAddressSmramBase;
-
- //
- // 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 (mSmmCodeMemoryRangeUsageBitMap == NULL) {
- mSmmCodeMemoryRangeUsageBitMap = AllocateZeroPool (((SmmCodePageNumber / 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 (mSmmCodeMemoryRangeUsageBitMap == NULL) {
- return EFI_NOT_FOUND;
- }
-
- //
- // see if the memory range for loading the image is in the SMM code range.
- //
- if ((SmmCodeBase + SmmCodeSize < ImageBase + ImageSize) || (SmmCodeBase > ImageBase)) {
- return EFI_NOT_FOUND;
- }
-
- //
- // Test if the memory is available or not.
- //
- BaseOffsetPageNumber = EFI_SIZE_TO_PAGES ((UINT32)(ImageBase - SmmCodeBase));
- TopOffsetPageNumber = EFI_SIZE_TO_PAGES ((UINT32)(ImageBase + ImageSize - SmmCodeBase));
- for (Index = BaseOffsetPageNumber; Index < TopOffsetPageNumber; Index++) {
- if ((mSmmCodeMemoryRangeUsageBitMap[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++) {
- mSmmCodeMemoryRangeUsageBitMap[Index / 64] |= LShiftU64 (1, (Index % 64));
- }
-
- return EFI_SUCCESS;
-}
-
-/**
- Get the fixed loading address from image header assigned by build tool. This function only be called
- when Loading module at Fixed address feature enabled.
-
- @param ImageContext Pointer to the image context structure that describes the PE/COFF
- image that needs to be examined by this function.
- @retval EFI_SUCCESS An fixed loading address is assigned to this image by build tools .
- @retval EFI_NOT_FOUND The image has no assigned fixed loading address.
-
-**/
-EFI_STATUS
-GetPeCoffImageFixLoadingAssignedAddress (
- IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext
- )
-{
- UINTN SectionHeaderOffset;
- EFI_STATUS Status;
- EFI_IMAGE_SECTION_HEADER SectionHeader;
- EFI_IMAGE_OPTIONAL_HEADER_UNION *ImgHdr;
- 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)(gLoadModuleAtFixAddressSmramBase + (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_SMM_DRIVER_ENTRY instance
-
- @return EFI_STATUS
-
-**/
-EFI_STATUS
-EFIAPI
-SmmLoadImage (
- IN OUT EFI_SMM_DRIVER_ENTRY *DriverEntry
- )
-{
- UINT32 AuthenticationStatus;
- UINTN FilePathSize;
- VOID *Buffer;
- UINTN Size;
- UINTN PageCount;
- EFI_GUID *NameGuid;
- EFI_STATUS Status;
- EFI_STATUS SecurityStatus;
- EFI_HANDLE DeviceHandle;
- EFI_PHYSICAL_ADDRESS DstBuffer;
- EFI_DEVICE_PATH_PROTOCOL *FilePath;
- EFI_DEVICE_PATH_PROTOCOL *OriginalFilePath;
- EFI_DEVICE_PATH_PROTOCOL *HandleFilePath;
- EFI_FIRMWARE_VOLUME2_PROTOCOL *Fv;
- PE_COFF_LOADER_IMAGE_CONTEXT ImageContext;
-
- PERF_LOAD_IMAGE_BEGIN (DriverEntry->ImageHandle);
-
- Buffer = NULL;
- Size = 0;
- Fv = DriverEntry->Fv;
- NameGuid = &DriverEntry->FileName;
- FilePath = DriverEntry->FvFileDevicePath;
-
- OriginalFilePath = FilePath;
- HandleFilePath = FilePath;
- DeviceHandle = NULL;
- SecurityStatus = EFI_SUCCESS;
- Status = EFI_SUCCESS;
- AuthenticationStatus = 0;
-
- //
- // Try to get the image device handle by checking the match protocol.
- //
- Status = gBS->LocateDevicePath (&gEfiFirmwareVolume2ProtocolGuid, &HandleFilePath, &DeviceHandle);
- if (EFI_ERROR (Status)) {
- return Status;
- }
-
- //
- // If the Security2 and Security Architectural Protocol has not been located yet, then attempt to locate it
- //
- if (mSecurity2 == NULL) {
- gBS->LocateProtocol (&gEfiSecurity2ArchProtocolGuid, NULL, (VOID **)&mSecurity2);
- }
-
- if (mSecurity == NULL) {
- gBS->LocateProtocol (&gEfiSecurityArchProtocolGuid, NULL, (VOID **)&mSecurity);
- }
-
- //
- // When Security2 is installed, Security Architectural Protocol must be published.
- //
- ASSERT (mSecurity2 == NULL || mSecurity != NULL);
-
- //
- // Pull out just the file portion of the DevicePath for the LoadedImage FilePath
- //
- FilePath = OriginalFilePath;
- Status = gBS->HandleProtocol (DeviceHandle, &gEfiDevicePathProtocolGuid, (VOID **)&HandleFilePath);
- if (!EFI_ERROR (Status)) {
- FilePathSize = GetDevicePathSize (HandleFilePath) - sizeof (EFI_DEVICE_PATH_PROTOCOL);
- FilePath = (EFI_DEVICE_PATH_PROTOCOL *)(((UINT8 *)FilePath) + FilePathSize);
- }
-
- //
- // Try reading PE32 section firstly
- //
- Status = Fv->ReadSection (
- Fv,
- NameGuid,
- EFI_SECTION_PE32,
- 0,
- &Buffer,
- &Size,
- &AuthenticationStatus
- );
-
- if (EFI_ERROR (Status)) {
- //
- // Try reading TE section secondly
- //
- Buffer = NULL;
- Size = 0;
- Status = Fv->ReadSection (
- Fv,
- NameGuid,
- EFI_SECTION_TE,
- 0,
- &Buffer,
- &Size,
- &AuthenticationStatus
- );
- }
-
- if (EFI_ERROR (Status)) {
- if (Buffer != NULL) {
- gBS->FreePool (Buffer);
- }
-
- return Status;
- }
-
- //
- // Verify File Authentication through the Security2 Architectural Protocol
- //
- if (mSecurity2 != NULL) {
- SecurityStatus = mSecurity2->FileAuthentication (
- mSecurity2,
- OriginalFilePath,
- Buffer,
- Size,
- FALSE
- );
- }
-
- //
- // Verify the Authentication Status through the Security Architectural Protocol
- // Only on images that have been read using Firmware Volume protocol.
- // All SMM images are from FV protocol.
- //
- if (!EFI_ERROR (SecurityStatus) && (mSecurity != NULL)) {
- SecurityStatus = mSecurity->FileAuthenticationState (
- mSecurity,
- AuthenticationStatus,
- OriginalFilePath
- );
- }
-
- if (EFI_ERROR (SecurityStatus) && (SecurityStatus != EFI_SECURITY_VIOLATION)) {
- Status = SecurityStatus;
- return Status;
- }
-
- //
- // 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) {
- gBS->FreePool (Buffer);
- }
-
- return Status;
- }
-
- //
- // if Loading module at Fixed Address feature is enabled, then cut out a memory range started from TESG BASE
- // to hold the Smm driver code
- //
- if (PcdGet64 (PcdLoadModuleAtFixAddressEnable) != 0) {
- //
- // Get the fixed loading address assigned by Build tool
- //
- Status = GetPeCoffImageFixLoadingAssignedAddress (&ImageContext);
- if (!EFI_ERROR (Status)) {
- //
- // Since the memory range to load Smm core already been cut out, so no need to allocate and free this range
- // following statements is to bypass SmmFreePages
- //
- PageCount = 0;
- DstBuffer = (UINTN)gLoadModuleAtFixAddressSmramBase;
- } else {
- DEBUG ((DEBUG_INFO|DEBUG_LOAD, "LOADING MODULE FIXED ERROR: Failed to load module at fixed address. \n"));
- //
- // allocate the memory to load the SMM driver
- //
- PageCount = (UINTN)EFI_SIZE_TO_PAGES ((UINTN)ImageContext.ImageSize + ImageContext.SectionAlignment);
- DstBuffer = (UINTN)(-1);
-
- Status = SmmAllocatePages (
- AllocateMaxAddress,
- EfiRuntimeServicesCode,
- PageCount,
- &DstBuffer
- );
- if (EFI_ERROR (Status)) {
- if (Buffer != NULL) {
- gBS->FreePool (Buffer);
- }
-
- return Status;
- }
-
- ImageContext.ImageAddress = (EFI_PHYSICAL_ADDRESS)DstBuffer;
- }
- } else {
- PageCount = (UINTN)EFI_SIZE_TO_PAGES ((UINTN)ImageContext.ImageSize + ImageContext.SectionAlignment);
- DstBuffer = (UINTN)(-1);
-
- Status = SmmAllocatePages (
- AllocateMaxAddress,
- EfiRuntimeServicesCode,
- PageCount,
- &DstBuffer
- );
- if (EFI_ERROR (Status)) {
- if (Buffer != NULL) {
- gBS->FreePool (Buffer);
- }
-
- return Status;
- }
-
- ImageContext.ImageAddress = (EFI_PHYSICAL_ADDRESS)DstBuffer;
- }
-
- //
- // Align buffer on section boundary
- //
- 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) {
- gBS->FreePool (Buffer);
- }
-
- SmmFreePages (DstBuffer, PageCount);
- return Status;
- }
-
- //
- // Relocate the image in our new buffer
- //
- Status = PeCoffLoaderRelocateImage (&ImageContext);
- if (EFI_ERROR (Status)) {
- if (Buffer != NULL) {
- gBS->FreePool (Buffer);
- }
-
- SmmFreePages (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;
-
- //
- // Allocate a Loaded Image Protocol in EfiBootServicesData
- //
- Status = gBS->AllocatePool (EfiBootServicesData, sizeof (EFI_LOADED_IMAGE_PROTOCOL), (VOID **)&DriverEntry->LoadedImage);
- if (EFI_ERROR (Status)) {
- if (Buffer != NULL) {
- gBS->FreePool (Buffer);
- }
-
- SmmFreePages (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 = gSmmCorePrivate->SmmIplImageHandle;
- DriverEntry->LoadedImage->SystemTable = gST;
- DriverEntry->LoadedImage->DeviceHandle = DeviceHandle;
-
- DriverEntry->SmmLoadedImage.Revision = EFI_LOADED_IMAGE_PROTOCOL_REVISION;
- DriverEntry->SmmLoadedImage.ParentHandle = gSmmCorePrivate->SmmIplImageHandle;
- DriverEntry->SmmLoadedImage.SystemTable = gST;
- DriverEntry->SmmLoadedImage.DeviceHandle = DeviceHandle;
-
- //
- // Make an EfiBootServicesData buffer copy of FilePath
- //
- Status = gBS->AllocatePool (EfiBootServicesData, GetDevicePathSize (FilePath), (VOID **)&DriverEntry->LoadedImage->FilePath);
- if (EFI_ERROR (Status)) {
- if (Buffer != NULL) {
- gBS->FreePool (Buffer);
- }
-
- SmmFreePages (DstBuffer, PageCount);
- return Status;
- }
-
- CopyMem (DriverEntry->LoadedImage->FilePath, FilePath, GetDevicePathSize (FilePath));
-
- DriverEntry->LoadedImage->ImageBase = (VOID *)(UINTN)ImageContext.ImageAddress;
- DriverEntry->LoadedImage->ImageSize = ImageContext.ImageSize;
- DriverEntry->LoadedImage->ImageCodeType = EfiRuntimeServicesCode;
- DriverEntry->LoadedImage->ImageDataType = EfiRuntimeServicesData;
-
- //
- // Make a buffer copy of FilePath
- //
- Status = SmmAllocatePool (EfiRuntimeServicesData, GetDevicePathSize (FilePath), (VOID **)&DriverEntry->SmmLoadedImage.FilePath);
- if (EFI_ERROR (Status)) {
- if (Buffer != NULL) {
- gBS->FreePool (Buffer);
- }
-
- gBS->FreePool (DriverEntry->LoadedImage->FilePath);
- SmmFreePages (DstBuffer, PageCount);
- return Status;
- }
-
- CopyMem (DriverEntry->SmmLoadedImage.FilePath, FilePath, GetDevicePathSize (FilePath));
-
- DriverEntry->SmmLoadedImage.ImageBase = (VOID *)(UINTN)ImageContext.ImageAddress;
- DriverEntry->SmmLoadedImage.ImageSize = ImageContext.ImageSize;
- DriverEntry->SmmLoadedImage.ImageCodeType = EfiRuntimeServicesCode;
- DriverEntry->SmmLoadedImage.ImageDataType = EfiRuntimeServicesData;
-
- //
- // Create a new image handle in the UEFI handle database for the SMM Driver
- //
- DriverEntry->ImageHandle = NULL;
- Status = gBS->InstallMultipleProtocolInterfaces (
- &DriverEntry->ImageHandle,
- &gEfiLoadedImageProtocolGuid,
- DriverEntry->LoadedImage,
- NULL
- );
-
- //
- // Create a new image handle in the SMM handle database for the SMM Driver
- //
- DriverEntry->SmmImageHandle = NULL;
- Status = SmmInstallProtocolInterface (
- &DriverEntry->SmmImageHandle,
- &gEfiLoadedImageProtocolGuid,
- EFI_NATIVE_INTERFACE,
- &DriverEntry->SmmLoadedImage
- );
-
- PERF_LOAD_IMAGE_END (DriverEntry->ImageHandle);
-
- //
- // 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 SMM 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 redundant 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
- //
- Status = gBS->FreePool (Buffer);
- if (!EFI_ERROR (Status) && EFI_ERROR (SecurityStatus)) {
- Status = SecurityStatus;
- }
-
- 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
-SmmPreProcessDepex (
- IN EFI_SMM_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 preprocessed
- @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
-SmmGetDepexSectionAndPreProccess (
- IN EFI_SMM_DRIVER_ENTRY *DriverEntry
- )
-{
- EFI_STATUS Status;
- EFI_SECTION_TYPE SectionType;
- UINT32 AuthenticationStatus;
- EFI_FIRMWARE_VOLUME2_PROTOCOL *Fv;
-
- Fv = DriverEntry->Fv;
-
- //
- // Grab Depex info, it will never be free'ed.
- // (Note: DriverEntry->Depex is in DXE memory)
- //
- SectionType = EFI_SECTION_SMM_DEPEX;
- Status = Fv->ReadSection (
- DriverEntry->Fv,
- &DriverEntry->FileName,
- SectionType,
- 0,
- &DriverEntry->Depex,
- (UINTN *)&DriverEntry->DepexSize,
- &AuthenticationStatus
- );
- if (EFI_ERROR (Status)) {
- if (Status == EFI_PROTOCOL_ERROR) {
- //
- // The section extraction protocol failed so set protocol error flag
- //
- DriverEntry->DepexProtocolError = TRUE;
- } else {
- //
- // If no Depex assume 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
- //
- SmmPreProcessDepex (DriverEntry);
- DriverEntry->DepexProtocolError = FALSE;
- }
-
- return Status;
-}
-
-/**
- This is the main Dispatcher for SMM 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 SMM Drivers that could be dispatched
- have been run and the SMM Entry Point has been
- registered.
- @retval EFI_NOT_READY The SMM Driver that registered the SMM Entry Point
- was just dispatched.
- @retval EFI_NOT_FOUND There are no SMM Drivers available to be dispatched.
- @retval EFI_ALREADY_STARTED The SMM Dispatcher is already running
-
-**/
-EFI_STATUS
-SmmDispatcher (
- VOID
- )
-{
- EFI_STATUS Status;
- LIST_ENTRY *Link;
- EFI_SMM_DRIVER_ENTRY *DriverEntry;
- BOOLEAN ReadyToRun;
- BOOLEAN PreviousSmmEntryPointRegistered;
-
- if (!gRequestDispatch) {
- return EFI_NOT_FOUND;
- }
-
- if (gDispatcherRunning) {
- //
- // If the dispatcher is running don't let it be restarted.
- //
- return EFI_ALREADY_STARTED;
- }
-
- gDispatcherRunning = TRUE;
-
- do {
- //
- // Drain the Scheduled Queue
- //
- while (!IsListEmpty (&mScheduledQueue)) {
- DriverEntry = CR (
- mScheduledQueue.ForwardLink,
- EFI_SMM_DRIVER_ENTRY,
- ScheduledLink,
- EFI_SMM_DRIVER_ENTRY_SIGNATURE
- );
-
- //
- // Load the SMM 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 = SmmLoadImage (DriverEntry);
-
- //
- // Update the driver state to reflect that it's been loaded
- //
- if (EFI_ERROR (Status)) {
- //
- // The SMM 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_SMM_DRIVER | EFI_SW_PC_INIT_BEGIN,
- &DriverEntry->ImageHandle,
- sizeof (DriverEntry->ImageHandle)
- );
-
- //
- // Cache state of SmmEntryPointRegistered before calling entry point
- //
- PreviousSmmEntryPointRegistered = gSmmCorePrivate->SmmEntryPointRegistered;
-
- //
- // For each SMM driver, pass NULL as ImageHandle
- //
- RegisterSmramProfileImage (DriverEntry, TRUE);
- PERF_START_IMAGE_BEGIN (DriverEntry->ImageHandle);
- Status = ((EFI_IMAGE_ENTRY_POINT)(UINTN)DriverEntry->ImageEntryPoint)(DriverEntry->ImageHandle, gST);
- PERF_START_IMAGE_END (DriverEntry->ImageHandle);
- if (EFI_ERROR (Status)) {
- DEBUG ((
- DEBUG_ERROR,
- "Error: SMM image at %11p start failed: %r\n",
- DriverEntry->SmmLoadedImage.ImageBase,
- Status
- ));
- UnregisterSmramProfileImage (DriverEntry, TRUE);
- SmmFreePages (DriverEntry->ImageBuffer, DriverEntry->NumberOfPage);
- //
- // Uninstall LoadedImage
- //
- Status = gBS->UninstallProtocolInterface (
- DriverEntry->ImageHandle,
- &gEfiLoadedImageProtocolGuid,
- DriverEntry->LoadedImage
- );
- if (!EFI_ERROR (Status)) {
- if (DriverEntry->LoadedImage->FilePath != NULL) {
- gBS->FreePool (DriverEntry->LoadedImage->FilePath);
- }
-
- gBS->FreePool (DriverEntry->LoadedImage);
- }
-
- Status = SmmUninstallProtocolInterface (
- DriverEntry->SmmImageHandle,
- &gEfiLoadedImageProtocolGuid,
- &DriverEntry->SmmLoadedImage
- );
- if (!EFI_ERROR (Status)) {
- if (DriverEntry->SmmLoadedImage.FilePath != NULL) {
- SmmFreePool (DriverEntry->SmmLoadedImage.FilePath);
- }
- }
- }
-
- REPORT_STATUS_CODE_WITH_EXTENDED_DATA (
- EFI_PROGRESS_CODE,
- EFI_SOFTWARE_SMM_DRIVER | EFI_SW_PC_INIT_END,
- &DriverEntry->ImageHandle,
- sizeof (DriverEntry->ImageHandle)
- );
-
- if (!PreviousSmmEntryPointRegistered && gSmmCorePrivate->SmmEntryPointRegistered) {
- //
- // Return immediately if the SMM Entry Point was registered by the SMM
- // Driver that was just dispatched. The SMM IPL will reinvoke the SMM
- // Core Dispatcher. This is required so SMM Mode may be enabled as soon
- // as all the dependent SMM Drivers for SMM Mode have been dispatched.
- // Once the SMM Entry Point has been registered, then SMM Mode will be
- // used.
- //
- gRequestDispatch = TRUE;
- gDispatcherRunning = FALSE;
- return EFI_NOT_READY;
- }
- }
-
- //
- // Search DriverList for items to place on Scheduled Queue
- //
- ReadyToRun = FALSE;
- for (Link = mDiscoveredList.ForwardLink; Link != &mDiscoveredList; Link = Link->ForwardLink) {
- DriverEntry = CR (Link, EFI_SMM_DRIVER_ENTRY, Link, EFI_SMM_DRIVER_ENTRY_SIGNATURE);
-
- if (DriverEntry->DepexProtocolError) {
- //
- // If Section Extraction Protocol did not let the Depex be read before retry the read
- //
- Status = SmmGetDepexSectionAndPreProccess (DriverEntry);
- }
-
- if (DriverEntry->Dependent) {
- if (SmmIsSchedulable (DriverEntry)) {
- SmmInsertOnScheduledQueueWhileProcessingBeforeAndAfter (DriverEntry);
- ReadyToRun = TRUE;
- }
- }
- }
- } while (ReadyToRun);
-
- //
- // If there is no more SMM driver to dispatch, stop the dispatch request
- //
- gRequestDispatch = FALSE;
- for (Link = mDiscoveredList.ForwardLink; Link != &mDiscoveredList; Link = Link->ForwardLink) {
- DriverEntry = CR (Link, EFI_SMM_DRIVER_ENTRY, Link, EFI_SMM_DRIVER_ENTRY_SIGNATURE);
-
- if (!DriverEntry->Initialized) {
- //
- // We have SMM 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
-SmmInsertOnScheduledQueueWhileProcessingBeforeAndAfter (
- IN EFI_SMM_DRIVER_ENTRY *InsertedDriverEntry
- )
-{
- LIST_ENTRY *Link;
- EFI_SMM_DRIVER_ENTRY *DriverEntry;
-
- //
- // Process Before Dependency
- //
- for (Link = mDiscoveredList.ForwardLink; Link != &mDiscoveredList; Link = Link->ForwardLink) {
- DriverEntry = CR (Link, EFI_SMM_DRIVER_ENTRY, Link, EFI_SMM_DRIVER_ENTRY_SIGNATURE);
- if (DriverEntry->Before && DriverEntry->Dependent && (DriverEntry != InsertedDriverEntry)) {
- DEBUG ((DEBUG_DISPATCH, "Evaluate SMM 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"));
- SmmInsertOnScheduledQueueWhileProcessingBeforeAndAfter (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_SMM_DRIVER_ENTRY, Link, EFI_SMM_DRIVER_ENTRY_SIGNATURE);
- if (DriverEntry->After && DriverEntry->Dependent && (DriverEntry != InsertedDriverEntry)) {
- DEBUG ((DEBUG_DISPATCH, "Evaluate SMM 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"));
- SmmInsertOnScheduledQueueWhileProcessingBeforeAndAfter (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 its drivers placed on the
- mDiscoveredList. This function 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
-FvIsBeingProcessed (
- IN EFI_HANDLE FvHandle
- )
-{
- KNOWN_HANDLE *KnownHandle;
-
- KnownHandle = AllocatePool (sizeof (KNOWN_HANDLE));
- ASSERT (KnownHandle != NULL);
-
- KnownHandle->Signature = KNOWN_HANDLE_SIGNATURE;
- KnownHandle->Handle = FvHandle;
- InsertTailList (&mFvHandleList, &KnownHandle->Link);
-}
-
-/**
- Convert FvHandle and DriverName into an EFI device path
-
- @param Fv Fv protocol, needed to read Depex info out of
- FLASH.
- @param FvHandle Handle for Fv, needed in the
- EFI_SMM_DRIVER_ENTRY so that the PE image can be
- read out of the FV at a later time.
- @param DriverName Name of driver to add to mDiscoveredList.
-
- @return Pointer to device path constructed from FvHandle and DriverName
-
-**/
-EFI_DEVICE_PATH_PROTOCOL *
-SmmFvToDevicePath (
- IN EFI_FIRMWARE_VOLUME2_PROTOCOL *Fv,
- IN EFI_HANDLE FvHandle,
- IN EFI_GUID *DriverName
- )
-{
- EFI_STATUS Status;
- EFI_DEVICE_PATH_PROTOCOL *FvDevicePath;
- EFI_DEVICE_PATH_PROTOCOL *FileNameDevicePath;
-
- //
- // Remember the device path of the FV
- //
- Status = gBS->HandleProtocol (FvHandle, &gEfiDevicePathProtocolGuid, (VOID **)&FvDevicePath);
- if (EFI_ERROR (Status)) {
- FileNameDevicePath = NULL;
- } else {
- //
- // Build a device path to the file in the FV to pass into gBS->LoadImage
- //
- EfiInitializeFwVolDevicepathNode (&mFvDevicePath.File, DriverName);
- SetDevicePathEndNode (&mFvDevicePath.End);
-
- //
- // Note: FileNameDevicePath is in DXE memory
- //
- FileNameDevicePath = AppendDevicePath (
- FvDevicePath,
- (EFI_DEVICE_PATH_PROTOCOL *)&mFvDevicePath
- );
- }
-
- return FileNameDevicePath;
-}
-
-/**
- Add an entry to the mDiscoveredList. Allocate memory to store the DriverEntry,
- and initialize 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 SMM driver states.
-
- @param Fv Fv protocol, needed to read Depex info out of
- FLASH.
- @param FvHandle Handle for Fv, needed in the
- EFI_SMM_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
-SmmAddToDriverList (
- IN EFI_FIRMWARE_VOLUME2_PROTOCOL *Fv,
- IN EFI_HANDLE FvHandle,
- IN EFI_GUID *DriverName
- )
-{
- EFI_SMM_DRIVER_ENTRY *DriverEntry;
-
- //
- // Create the Driver Entry for the list. ZeroPool initializes lots of variables to
- // NULL or FALSE.
- //
- DriverEntry = AllocateZeroPool (sizeof (EFI_SMM_DRIVER_ENTRY));
- ASSERT (DriverEntry != NULL);
-
- DriverEntry->Signature = EFI_SMM_DRIVER_ENTRY_SIGNATURE;
- CopyGuid (&DriverEntry->FileName, DriverName);
- DriverEntry->FvHandle = FvHandle;
- DriverEntry->Fv = Fv;
- DriverEntry->FvFileDevicePath = SmmFvToDevicePath (Fv, FvHandle, DriverName);
-
- SmmGetDepexSectionAndPreProccess (DriverEntry);
-
- InsertTailList (&mDiscoveredList, &DriverEntry->Link);
- gRequestDispatch = TRUE;
-
- return EFI_SUCCESS;
-}
-
-/**
- This function is the main entry point for an SMM 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 SmmLocateHandle () 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 SMM 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-SMM environment into an SMM environment.
- @param CommBufferSize The size of the CommBuffer.
-
- @return Status Code
-
-**/
-EFI_STATUS
-EFIAPI
-SmmDriverDispatchHandler (
- IN EFI_HANDLE DispatchHandle,
- IN CONST VOID *Context OPTIONAL,
- IN OUT VOID *CommBuffer OPTIONAL,
- IN OUT UINTN *CommBufferSize OPTIONAL
- )
-{
- EFI_STATUS Status;
- UINTN HandleCount;
- EFI_HANDLE *HandleBuffer;
- EFI_STATUS GetNextFileStatus;
- EFI_FIRMWARE_VOLUME2_PROTOCOL *Fv;
- EFI_DEVICE_PATH_PROTOCOL *FvDevicePath;
- EFI_HANDLE FvHandle;
- EFI_GUID NameGuid;
- UINTN Key;
- EFI_FV_FILETYPE Type;
- EFI_FV_FILE_ATTRIBUTES Attributes;
- UINTN Size;
- EFI_SMM_DRIVER_ENTRY *DriverEntry;
- EFI_GUID *AprioriFile;
- UINTN AprioriEntryCount;
- UINTN HandleIndex;
- UINTN SmmTypeIndex;
- UINTN AprioriIndex;
- LIST_ENTRY *Link;
- UINT32 AuthenticationStatus;
- UINTN SizeOfBuffer;
-
- HandleBuffer = NULL;
- Status = gBS->LocateHandleBuffer (
- ByProtocol,
- &gEfiFirmwareVolume2ProtocolGuid,
- NULL,
- &HandleCount,
- &HandleBuffer
- );
- if (EFI_ERROR (Status)) {
- return EFI_NOT_FOUND;
- }
-
- PERF_CALLBACK_BEGIN (&gEfiEventDxeDispatchGuid);
-
- for (HandleIndex = 0; HandleIndex < HandleCount; HandleIndex++) {
- FvHandle = HandleBuffer[HandleIndex];
-
- if (FvHasBeenProcessed (FvHandle)) {
- //
- // This Fv has already been processed so lets skip it!
- //
- continue;
- }
-
- //
- // Since we are about to process this Fv mark it as processed.
- //
- FvIsBeingProcessed (FvHandle);
-
- Status = gBS->HandleProtocol (FvHandle, &gEfiFirmwareVolume2ProtocolGuid, (VOID **)&Fv);
- if (EFI_ERROR (Status)) {
- //
- // FvHandle must have a Firmware Volume2 Protocol thus we should never get here.
- //
- ASSERT (FALSE);
- continue;
- }
-
- Status = gBS->HandleProtocol (FvHandle, &gEfiDevicePathProtocolGuid, (VOID **)&FvDevicePath);
- if (EFI_ERROR (Status)) {
- //
- // The Firmware volume doesn't have device path, can't be dispatched.
- //
- continue;
- }
-
- //
- // Discover Drivers in FV and add them to the Discovered Driver List.
- // Process EFI_FV_FILETYPE_SMM type and then EFI_FV_FILETYPE_COMBINED_SMM_DXE
- // EFI_FV_FILETYPE_SMM_CORE is processed to produce a Loaded Image protocol for the core
- //
- for (SmmTypeIndex = 0; SmmTypeIndex < sizeof (mSmmFileTypes)/sizeof (EFI_FV_FILETYPE); SmmTypeIndex++) {
- //
- // Initialize the search key
- //
- Key = 0;
- do {
- Type = mSmmFileTypes[SmmTypeIndex];
- GetNextFileStatus = Fv->GetNextFile (
- Fv,
- &Key,
- &Type,
- &NameGuid,
- &Attributes,
- &Size
- );
- if (!EFI_ERROR (GetNextFileStatus)) {
- if (Type == EFI_FV_FILETYPE_SMM_CORE) {
- //
- // If this is the SMM core fill in it's DevicePath & DeviceHandle
- //
- if (mSmmCoreLoadedImage->FilePath == NULL) {
- //
- // Maybe one special FV contains only one SMM_CORE module, so its device path must
- // be initialized completely.
- //
- EfiInitializeFwVolDevicepathNode (&mFvDevicePath.File, &NameGuid);
- SetDevicePathEndNode (&mFvDevicePath.End);
-
- //
- // Make an EfiBootServicesData buffer copy of FilePath
- //
- Status = gBS->AllocatePool (
- EfiBootServicesData,
- GetDevicePathSize ((EFI_DEVICE_PATH_PROTOCOL *)&mFvDevicePath),
- (VOID **)&mSmmCoreLoadedImage->FilePath
- );
- ASSERT_EFI_ERROR (Status);
- CopyMem (mSmmCoreLoadedImage->FilePath, &mFvDevicePath, GetDevicePathSize ((EFI_DEVICE_PATH_PROTOCOL *)&mFvDevicePath));
-
- mSmmCoreLoadedImage->DeviceHandle = FvHandle;
- }
-
- if (mSmmCoreDriverEntry->SmmLoadedImage.FilePath == NULL) {
- //
- // Maybe one special FV contains only one SMM_CORE module, so its device path must
- // be initialized completely.
- //
- EfiInitializeFwVolDevicepathNode (&mFvDevicePath.File, &NameGuid);
- SetDevicePathEndNode (&mFvDevicePath.End);
-
- //
- // Make a buffer copy FilePath
- //
- Status = SmmAllocatePool (
- EfiRuntimeServicesData,
- GetDevicePathSize ((EFI_DEVICE_PATH_PROTOCOL *)&mFvDevicePath),
- (VOID **)&mSmmCoreDriverEntry->SmmLoadedImage.FilePath
- );
- ASSERT_EFI_ERROR (Status);
- CopyMem (mSmmCoreDriverEntry->SmmLoadedImage.FilePath, &mFvDevicePath, GetDevicePathSize ((EFI_DEVICE_PATH_PROTOCOL *)&mFvDevicePath));
-
- mSmmCoreDriverEntry->SmmLoadedImage.DeviceHandle = FvHandle;
- }
- } else {
- SmmAddToDriverList (Fv, FvHandle, &NameGuid);
- }
- }
- } while (!EFI_ERROR (GetNextFileStatus));
- }
-
- //
- // Read the array of GUIDs from the Apriori file if it is present in the firmware volume
- // (Note: AprioriFile is in DXE memory)
- //
- AprioriFile = NULL;
- Status = Fv->ReadSection (
- Fv,
- &gAprioriGuid,
- EFI_SECTION_RAW,
- 0,
- (VOID **)&AprioriFile,
- &SizeOfBuffer,
- &AuthenticationStatus
- );
- if (!EFI_ERROR (Status)) {
- AprioriEntryCount = SizeOfBuffer / sizeof (EFI_GUID);
- } else {
- AprioriEntryCount = 0;
- }
-
- //
- // Put drivers on Apriori List on the Scheduled queue. The Discovered List includes
- // drivers not in the current FV and these must be skipped since the a priori list
- // is only valid for the FV that it resided in.
- //
-
- for (AprioriIndex = 0; AprioriIndex < AprioriEntryCount; AprioriIndex++) {
- for (Link = mDiscoveredList.ForwardLink; Link != &mDiscoveredList; Link = Link->ForwardLink) {
- DriverEntry = CR (Link, EFI_SMM_DRIVER_ENTRY, Link, EFI_SMM_DRIVER_ENTRY_SIGNATURE);
- if (CompareGuid (&DriverEntry->FileName, &AprioriFile[AprioriIndex]) &&
- (FvHandle == DriverEntry->FvHandle))
- {
- DriverEntry->Dependent = FALSE;
- DriverEntry->Scheduled = TRUE;
- InsertTailList (&mScheduledQueue, &DriverEntry->ScheduledLink);
- DEBUG ((DEBUG_DISPATCH, "Evaluate SMM DEPEX for FFS(%g)\n", &DriverEntry->FileName));
- DEBUG ((DEBUG_DISPATCH, " RESULT = TRUE (Apriori)\n"));
- break;
- }
- }
- }
-
- //
- // Free data allocated by Fv->ReadSection ()
- //
- // The UEFI Boot Services FreePool() function must be used because Fv->ReadSection
- // used the UEFI Boot Services AllocatePool() function
- //
- gBS->FreePool (AprioriFile);
- }
-
- //
- // Execute the SMM Dispatcher on any newly discovered FVs and previously
- // discovered SMM drivers that have been discovered but not dispatched.
- //
- Status = SmmDispatcher ();
-
- //
- // 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 SMM Core Entry Point was just registered, then set flag to
- // request the SMM Dispatcher to be restarted.
- //
- *(UINT8 *)CommBuffer = COMM_BUFFER_SMM_DISPATCH_RESTART;
- } else if (!EFI_ERROR (Status)) {
- //
- // Set the flag to show that the SMM Dispatcher executed without errors
- //
- *(UINT8 *)CommBuffer = COMM_BUFFER_SMM_DISPATCH_SUCCESS;
- } else {
- //
- // Set the flag to show that the SMM Dispatcher encountered an error
- //
- *(UINT8 *)CommBuffer = COMM_BUFFER_SMM_DISPATCH_ERROR;
- }
- }
- }
-
- PERF_CALLBACK_END (&gEfiEventDxeDispatchGuid);
- return EFI_SUCCESS;
-}
-
-/**
- Traverse the discovered list for any drivers that were discovered but not loaded
- because the dependency expressions evaluated to false.
-
-**/
-VOID
-SmmDisplayDiscoveredNotDispatched (
- VOID
- )
-{
- LIST_ENTRY *Link;
- EFI_SMM_DRIVER_ENTRY *DriverEntry;
-
- for (Link = mDiscoveredList.ForwardLink; Link != &mDiscoveredList; Link = Link->ForwardLink) {
- DriverEntry = CR (Link, EFI_SMM_DRIVER_ENTRY, Link, EFI_SMM_DRIVER_ENTRY_SIGNATURE);
- if (DriverEntry->Dependent) {
- DEBUG ((DEBUG_LOAD, "SMM Driver %g was discovered but not loaded!!\n", &DriverEntry->FileName));
- }
- }
-}
+/** @file + SMM 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 + processes the After dependencies 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 Expression. + + Copyright (c) 2014, Hewlett-Packard Development Company, L.P. + Copyright (c) 2009 - 2023, Intel Corporation. All rights reserved.<BR> + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "PiSmmCore.h" + +// +// SMM 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 +// + +/** + 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 +SmmInsertOnScheduledQueueWhileProcessingBeforeAndAfter ( + IN EFI_SMM_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_SMM_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_SMM_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 SMM Dispatcher. TRUE if dispatcher is executing. +// +BOOLEAN gDispatcherRunning = FALSE; + +// +// Flag for the SMM Dispatcher. TRUE if there is one or more SMM drivers ready to be dispatched +// +BOOLEAN gRequestDispatch = FALSE; + +// +// List of file types supported by dispatcher +// +EFI_FV_FILETYPE mSmmFileTypes[] = { + EFI_FV_FILETYPE_SMM, + EFI_FV_FILETYPE_COMBINED_SMM_DXE, + EFI_FV_FILETYPE_SMM_CORE, + // + // Note: DXE core will process the FV image file, so skip it in SMM core + // EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE + // +}; + +typedef struct { + MEDIA_FW_VOL_FILEPATH_DEVICE_PATH File; + EFI_DEVICE_PATH_PROTOCOL End; +} FV_FILEPATH_DEVICE_PATH; + +FV_FILEPATH_DEVICE_PATH mFvDevicePath; + +// +// DXE Architecture Protocols +// +EFI_SECURITY_ARCH_PROTOCOL *mSecurity = NULL; +EFI_SECURITY2_ARCH_PROTOCOL *mSecurity2 = NULL; + +// +// The global variable is defined for Loading modules at fixed address feature to track the SMM code +// memory range usage. It is a bit mapped array in which every bit indicates the corresponding +// memory page available or not. +// +GLOBAL_REMOVE_IF_UNREFERENCED UINT64 *mSmmCodeMemoryRangeUsageBitMap = 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 available, the function will mark the corresponding bits to 1 which indicates the memory range is used. + The function is only invoked when load modules at fixed address feature is enabled. + + @param ImageBase The base address the image will be loaded at. + @param ImageSize The size of the image + + @retval EFI_SUCCESS The memory range the image will be loaded in is available + @retval EFI_NOT_FOUND The memory range the image will be loaded in is not available +**/ +EFI_STATUS +CheckAndMarkFixLoadingMemoryUsageBitMap ( + IN EFI_PHYSICAL_ADDRESS ImageBase, + IN UINTN ImageSize + ) +{ + UINT32 SmmCodePageNumber; + UINT64 SmmCodeSize; + EFI_PHYSICAL_ADDRESS SmmCodeBase; + UINTN BaseOffsetPageNumber; + UINTN TopOffsetPageNumber; + UINTN Index; + + // + // Build tool will calculate the smm code size and then patch the PcdLoadFixAddressSmmCodePageNumber + // + SmmCodePageNumber = PcdGet32 (PcdLoadFixAddressSmmCodePageNumber); + SmmCodeSize = EFI_PAGES_TO_SIZE (SmmCodePageNumber); + SmmCodeBase = gLoadModuleAtFixAddressSmramBase; + + // + // 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 (mSmmCodeMemoryRangeUsageBitMap == NULL) { + mSmmCodeMemoryRangeUsageBitMap = AllocateZeroPool (((SmmCodePageNumber / 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 (mSmmCodeMemoryRangeUsageBitMap == NULL) { + return EFI_NOT_FOUND; + } + + // + // see if the memory range for loading the image is in the SMM code range. + // + if ((SmmCodeBase + SmmCodeSize < ImageBase + ImageSize) || (SmmCodeBase > ImageBase)) { + return EFI_NOT_FOUND; + } + + // + // Test if the memory is available or not. + // + BaseOffsetPageNumber = EFI_SIZE_TO_PAGES ((UINT32)(ImageBase - SmmCodeBase)); + TopOffsetPageNumber = EFI_SIZE_TO_PAGES ((UINT32)(ImageBase + ImageSize - SmmCodeBase)); + for (Index = BaseOffsetPageNumber; Index < TopOffsetPageNumber; Index++) { + if ((mSmmCodeMemoryRangeUsageBitMap[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++) { + mSmmCodeMemoryRangeUsageBitMap[Index / 64] |= LShiftU64 (1, (Index % 64)); + } + + return EFI_SUCCESS; +} + +/** + Get the fixed loading address from image header assigned by build tool. This function only be called + when Loading module at Fixed address feature enabled. + + @param ImageContext Pointer to the image context structure that describes the PE/COFF + image that needs to be examined by this function. + @retval EFI_SUCCESS An fixed loading address is assigned to this image by build tools . + @retval EFI_NOT_FOUND The image has no assigned fixed loading address. + +**/ +EFI_STATUS +GetPeCoffImageFixLoadingAssignedAddress ( + IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext + ) +{ + UINTN SectionHeaderOffset; + EFI_STATUS Status; + EFI_IMAGE_SECTION_HEADER SectionHeader; + EFI_IMAGE_OPTIONAL_HEADER_UNION *ImgHdr; + 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)(gLoadModuleAtFixAddressSmramBase + (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_SMM_DRIVER_ENTRY instance + + @return EFI_STATUS + +**/ +EFI_STATUS +EFIAPI +SmmLoadImage ( + IN OUT EFI_SMM_DRIVER_ENTRY *DriverEntry + ) +{ + UINT32 AuthenticationStatus; + UINTN FilePathSize; + VOID *Buffer; + UINTN Size; + UINTN PageCount; + EFI_GUID *NameGuid; + EFI_STATUS Status; + EFI_STATUS SecurityStatus; + EFI_HANDLE DeviceHandle; + EFI_PHYSICAL_ADDRESS DstBuffer; + EFI_DEVICE_PATH_PROTOCOL *FilePath; + EFI_DEVICE_PATH_PROTOCOL *OriginalFilePath; + EFI_DEVICE_PATH_PROTOCOL *HandleFilePath; + EFI_FIRMWARE_VOLUME2_PROTOCOL *Fv; + PE_COFF_LOADER_IMAGE_CONTEXT ImageContext; + + PERF_LOAD_IMAGE_BEGIN (DriverEntry->ImageHandle); + + Buffer = NULL; + Size = 0; + Fv = DriverEntry->Fv; + NameGuid = &DriverEntry->FileName; + FilePath = DriverEntry->FvFileDevicePath; + + OriginalFilePath = FilePath; + HandleFilePath = FilePath; + DeviceHandle = NULL; + SecurityStatus = EFI_SUCCESS; + Status = EFI_SUCCESS; + AuthenticationStatus = 0; + + // + // Try to get the image device handle by checking the match protocol. + // + Status = gBS->LocateDevicePath (&gEfiFirmwareVolume2ProtocolGuid, &HandleFilePath, &DeviceHandle); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // If the Security2 and Security Architectural Protocol has not been located yet, then attempt to locate it + // + if (mSecurity2 == NULL) { + gBS->LocateProtocol (&gEfiSecurity2ArchProtocolGuid, NULL, (VOID **)&mSecurity2); + } + + if (mSecurity == NULL) { + gBS->LocateProtocol (&gEfiSecurityArchProtocolGuid, NULL, (VOID **)&mSecurity); + } + + // + // When Security2 is installed, Security Architectural Protocol must be published. + // + ASSERT (mSecurity2 == NULL || mSecurity != NULL); + + // + // Pull out just the file portion of the DevicePath for the LoadedImage FilePath + // + FilePath = OriginalFilePath; + Status = gBS->HandleProtocol (DeviceHandle, &gEfiDevicePathProtocolGuid, (VOID **)&HandleFilePath); + if (!EFI_ERROR (Status)) { + FilePathSize = GetDevicePathSize (HandleFilePath) - sizeof (EFI_DEVICE_PATH_PROTOCOL); + FilePath = (EFI_DEVICE_PATH_PROTOCOL *)(((UINT8 *)FilePath) + FilePathSize); + } + + // + // Try reading PE32 section firstly + // + Status = Fv->ReadSection ( + Fv, + NameGuid, + EFI_SECTION_PE32, + 0, + &Buffer, + &Size, + &AuthenticationStatus + ); + + if (EFI_ERROR (Status)) { + // + // Try reading TE section secondly + // + Buffer = NULL; + Size = 0; + Status = Fv->ReadSection ( + Fv, + NameGuid, + EFI_SECTION_TE, + 0, + &Buffer, + &Size, + &AuthenticationStatus + ); + } + + if (EFI_ERROR (Status)) { + if (Buffer != NULL) { + gBS->FreePool (Buffer); + } + + return Status; + } + + // + // Verify File Authentication through the Security2 Architectural Protocol + // + if (mSecurity2 != NULL) { + SecurityStatus = mSecurity2->FileAuthentication ( + mSecurity2, + OriginalFilePath, + Buffer, + Size, + FALSE + ); + } + + // + // Verify the Authentication Status through the Security Architectural Protocol + // Only on images that have been read using Firmware Volume protocol. + // All SMM images are from FV protocol. + // + if (!EFI_ERROR (SecurityStatus) && (mSecurity != NULL)) { + SecurityStatus = mSecurity->FileAuthenticationState ( + mSecurity, + AuthenticationStatus, + OriginalFilePath + ); + } + + if (EFI_ERROR (SecurityStatus) && (SecurityStatus != EFI_SECURITY_VIOLATION)) { + Status = SecurityStatus; + return Status; + } + + // + // 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) { + gBS->FreePool (Buffer); + } + + return Status; + } + + // + // if Loading module at Fixed Address feature is enabled, then cut out a memory range started from TESG BASE + // to hold the Smm driver code + // + if (PcdGet64 (PcdLoadModuleAtFixAddressEnable) != 0) { + // + // Get the fixed loading address assigned by Build tool + // + Status = GetPeCoffImageFixLoadingAssignedAddress (&ImageContext); + if (!EFI_ERROR (Status)) { + // + // Since the memory range to load Smm core already been cut out, so no need to allocate and free this range + // following statements is to bypass SmmFreePages + // + PageCount = 0; + DstBuffer = (UINTN)gLoadModuleAtFixAddressSmramBase; + } else { + DEBUG ((DEBUG_INFO|DEBUG_LOAD, "LOADING MODULE FIXED ERROR: Failed to load module at fixed address. \n")); + // + // allocate the memory to load the SMM driver + // + PageCount = (UINTN)EFI_SIZE_TO_PAGES ((UINTN)ImageContext.ImageSize + ImageContext.SectionAlignment); + DstBuffer = (UINTN)(-1); + + Status = SmmAllocatePages ( + AllocateMaxAddress, + EfiRuntimeServicesCode, + PageCount, + &DstBuffer + ); + if (EFI_ERROR (Status)) { + if (Buffer != NULL) { + gBS->FreePool (Buffer); + } + + return Status; + } + + ImageContext.ImageAddress = (EFI_PHYSICAL_ADDRESS)DstBuffer; + } + } else { + PageCount = (UINTN)EFI_SIZE_TO_PAGES ((UINTN)ImageContext.ImageSize + ImageContext.SectionAlignment); + DstBuffer = (UINTN)(-1); + + Status = SmmAllocatePages ( + AllocateMaxAddress, + EfiRuntimeServicesCode, + PageCount, + &DstBuffer + ); + if (EFI_ERROR (Status)) { + if (Buffer != NULL) { + gBS->FreePool (Buffer); + } + + return Status; + } + + ImageContext.ImageAddress = (EFI_PHYSICAL_ADDRESS)DstBuffer; + } + + // + // Align buffer on section boundary + // + 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) { + gBS->FreePool (Buffer); + } + + SmmFreePages (DstBuffer, PageCount); + return Status; + } + + // + // Relocate the image in our new buffer + // + Status = PeCoffLoaderRelocateImage (&ImageContext); + if (EFI_ERROR (Status)) { + if (Buffer != NULL) { + gBS->FreePool (Buffer); + } + + SmmFreePages (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; + + // + // Allocate a Loaded Image Protocol in EfiBootServicesData + // + Status = gBS->AllocatePool (EfiBootServicesData, sizeof (EFI_LOADED_IMAGE_PROTOCOL), (VOID **)&DriverEntry->LoadedImage); + if (EFI_ERROR (Status)) { + if (Buffer != NULL) { + gBS->FreePool (Buffer); + } + + SmmFreePages (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 = gSmmCorePrivate->SmmIplImageHandle; + DriverEntry->LoadedImage->SystemTable = gST; + DriverEntry->LoadedImage->DeviceHandle = DeviceHandle; + + DriverEntry->SmmLoadedImage.Revision = EFI_LOADED_IMAGE_PROTOCOL_REVISION; + DriverEntry->SmmLoadedImage.ParentHandle = gSmmCorePrivate->SmmIplImageHandle; + DriverEntry->SmmLoadedImage.SystemTable = gST; + DriverEntry->SmmLoadedImage.DeviceHandle = DeviceHandle; + + // + // Make an EfiBootServicesData buffer copy of FilePath + // + Status = gBS->AllocatePool (EfiBootServicesData, GetDevicePathSize (FilePath), (VOID **)&DriverEntry->LoadedImage->FilePath); + if (EFI_ERROR (Status)) { + if (Buffer != NULL) { + gBS->FreePool (Buffer); + } + + SmmFreePages (DstBuffer, PageCount); + return Status; + } + + CopyMem (DriverEntry->LoadedImage->FilePath, FilePath, GetDevicePathSize (FilePath)); + + DriverEntry->LoadedImage->ImageBase = (VOID *)(UINTN)ImageContext.ImageAddress; + DriverEntry->LoadedImage->ImageSize = ImageContext.ImageSize; + DriverEntry->LoadedImage->ImageCodeType = EfiRuntimeServicesCode; + DriverEntry->LoadedImage->ImageDataType = EfiRuntimeServicesData; + + // + // Make a buffer copy of FilePath + // + Status = SmmAllocatePool (EfiRuntimeServicesData, GetDevicePathSize (FilePath), (VOID **)&DriverEntry->SmmLoadedImage.FilePath); + if (EFI_ERROR (Status)) { + if (Buffer != NULL) { + gBS->FreePool (Buffer); + } + + gBS->FreePool (DriverEntry->LoadedImage->FilePath); + SmmFreePages (DstBuffer, PageCount); + return Status; + } + + CopyMem (DriverEntry->SmmLoadedImage.FilePath, FilePath, GetDevicePathSize (FilePath)); + + DriverEntry->SmmLoadedImage.ImageBase = (VOID *)(UINTN)ImageContext.ImageAddress; + DriverEntry->SmmLoadedImage.ImageSize = ImageContext.ImageSize; + DriverEntry->SmmLoadedImage.ImageCodeType = EfiRuntimeServicesCode; + DriverEntry->SmmLoadedImage.ImageDataType = EfiRuntimeServicesData; + + // + // Create a new image handle in the UEFI handle database for the SMM Driver + // + DriverEntry->ImageHandle = NULL; + Status = gBS->InstallMultipleProtocolInterfaces ( + &DriverEntry->ImageHandle, + &gEfiLoadedImageProtocolGuid, + DriverEntry->LoadedImage, + NULL + ); + + // + // Create a new image handle in the SMM handle database for the SMM Driver + // + DriverEntry->SmmImageHandle = NULL; + Status = SmmInstallProtocolInterface ( + &DriverEntry->SmmImageHandle, + &gEfiLoadedImageProtocolGuid, + EFI_NATIVE_INTERFACE, + &DriverEntry->SmmLoadedImage + ); + + PERF_LOAD_IMAGE_END (DriverEntry->ImageHandle); + + // + // 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 SMM 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 redundant 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 + // + Status = gBS->FreePool (Buffer); + if (!EFI_ERROR (Status) && EFI_ERROR (SecurityStatus)) { + Status = SecurityStatus; + } + + 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 +SmmPreProcessDepex ( + IN EFI_SMM_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 preprocessed + @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 +SmmGetDepexSectionAndPreProccess ( + IN EFI_SMM_DRIVER_ENTRY *DriverEntry + ) +{ + EFI_STATUS Status; + EFI_SECTION_TYPE SectionType; + UINT32 AuthenticationStatus; + EFI_FIRMWARE_VOLUME2_PROTOCOL *Fv; + + Fv = DriverEntry->Fv; + + // + // Grab Depex info, it will never be free'ed. + // (Note: DriverEntry->Depex is in DXE memory) + // + SectionType = EFI_SECTION_SMM_DEPEX; + Status = Fv->ReadSection ( + DriverEntry->Fv, + &DriverEntry->FileName, + SectionType, + 0, + &DriverEntry->Depex, + (UINTN *)&DriverEntry->DepexSize, + &AuthenticationStatus + ); + if (EFI_ERROR (Status)) { + if (Status == EFI_PROTOCOL_ERROR) { + // + // The section extraction protocol failed so set protocol error flag + // + DriverEntry->DepexProtocolError = TRUE; + } else { + // + // If no Depex assume 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 + // + SmmPreProcessDepex (DriverEntry); + DriverEntry->DepexProtocolError = FALSE; + } + + return Status; +} + +/** + This is the main Dispatcher for SMM 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 SMM Drivers that could be dispatched + have been run and the SMM Entry Point has been + registered. + @retval EFI_NOT_READY The SMM Driver that registered the SMM Entry Point + was just dispatched. + @retval EFI_NOT_FOUND There are no SMM Drivers available to be dispatched. + @retval EFI_ALREADY_STARTED The SMM Dispatcher is already running + +**/ +EFI_STATUS +SmmDispatcher ( + VOID + ) +{ + EFI_STATUS Status; + LIST_ENTRY *Link; + EFI_SMM_DRIVER_ENTRY *DriverEntry; + BOOLEAN ReadyToRun; + BOOLEAN PreviousSmmEntryPointRegistered; + + if (!gRequestDispatch) { + return EFI_NOT_FOUND; + } + + if (gDispatcherRunning) { + // + // If the dispatcher is running don't let it be restarted. + // + return EFI_ALREADY_STARTED; + } + + gDispatcherRunning = TRUE; + + do { + // + // Drain the Scheduled Queue + // + while (!IsListEmpty (&mScheduledQueue)) { + DriverEntry = CR ( + mScheduledQueue.ForwardLink, + EFI_SMM_DRIVER_ENTRY, + ScheduledLink, + EFI_SMM_DRIVER_ENTRY_SIGNATURE + ); + + // + // Load the SMM 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 = SmmLoadImage (DriverEntry); + + // + // Update the driver state to reflect that it's been loaded + // + if (EFI_ERROR (Status)) { + // + // The SMM 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_SMM_DRIVER | EFI_SW_PC_INIT_BEGIN, + &DriverEntry->ImageHandle, + sizeof (DriverEntry->ImageHandle) + ); + + // + // Cache state of SmmEntryPointRegistered before calling entry point + // + PreviousSmmEntryPointRegistered = gSmmCorePrivate->SmmEntryPointRegistered; + + // + // For each SMM driver, pass NULL as ImageHandle + // + RegisterSmramProfileImage (DriverEntry, TRUE); + PERF_START_IMAGE_BEGIN (DriverEntry->ImageHandle); + Status = ((EFI_IMAGE_ENTRY_POINT)(UINTN)DriverEntry->ImageEntryPoint)(DriverEntry->ImageHandle, gST); + PERF_START_IMAGE_END (DriverEntry->ImageHandle); + if (EFI_ERROR (Status)) { + DEBUG (( + DEBUG_ERROR, + "Error: SMM image at %11p start failed: %r\n", + DriverEntry->SmmLoadedImage.ImageBase, + Status + )); + UnregisterSmramProfileImage (DriverEntry, TRUE); + SmmFreePages (DriverEntry->ImageBuffer, DriverEntry->NumberOfPage); + // + // Uninstall LoadedImage + // + Status = gBS->UninstallProtocolInterface ( + DriverEntry->ImageHandle, + &gEfiLoadedImageProtocolGuid, + DriverEntry->LoadedImage + ); + if (!EFI_ERROR (Status)) { + if (DriverEntry->LoadedImage->FilePath != NULL) { + gBS->FreePool (DriverEntry->LoadedImage->FilePath); + } + + gBS->FreePool (DriverEntry->LoadedImage); + } + + Status = SmmUninstallProtocolInterface ( + DriverEntry->SmmImageHandle, + &gEfiLoadedImageProtocolGuid, + &DriverEntry->SmmLoadedImage + ); + if (!EFI_ERROR (Status)) { + if (DriverEntry->SmmLoadedImage.FilePath != NULL) { + SmmFreePool (DriverEntry->SmmLoadedImage.FilePath); + } + } + } + + REPORT_STATUS_CODE_WITH_EXTENDED_DATA ( + EFI_PROGRESS_CODE, + EFI_SOFTWARE_SMM_DRIVER | EFI_SW_PC_INIT_END, + &DriverEntry->ImageHandle, + sizeof (DriverEntry->ImageHandle) + ); + + if (!PreviousSmmEntryPointRegistered && gSmmCorePrivate->SmmEntryPointRegistered) { + // + // Return immediately if the SMM Entry Point was registered by the SMM + // Driver that was just dispatched. The SMM IPL will reinvoke the SMM + // Core Dispatcher. This is required so SMM Mode may be enabled as soon + // as all the dependent SMM Drivers for SMM Mode have been dispatched. + // Once the SMM Entry Point has been registered, then SMM Mode will be + // used. + // + gRequestDispatch = TRUE; + gDispatcherRunning = FALSE; + return EFI_NOT_READY; + } + } + + // + // Search DriverList for items to place on Scheduled Queue + // + ReadyToRun = FALSE; + for (Link = mDiscoveredList.ForwardLink; Link != &mDiscoveredList; Link = Link->ForwardLink) { + DriverEntry = CR (Link, EFI_SMM_DRIVER_ENTRY, Link, EFI_SMM_DRIVER_ENTRY_SIGNATURE); + + if (DriverEntry->DepexProtocolError) { + // + // If Section Extraction Protocol did not let the Depex be read before retry the read + // + Status = SmmGetDepexSectionAndPreProccess (DriverEntry); + } + + if (DriverEntry->Dependent) { + if (SmmIsSchedulable (DriverEntry)) { + SmmInsertOnScheduledQueueWhileProcessingBeforeAndAfter (DriverEntry); + ReadyToRun = TRUE; + } + } + } + } while (ReadyToRun); + + // + // If there is no more SMM driver to dispatch, stop the dispatch request + // + gRequestDispatch = FALSE; + for (Link = mDiscoveredList.ForwardLink; Link != &mDiscoveredList; Link = Link->ForwardLink) { + DriverEntry = CR (Link, EFI_SMM_DRIVER_ENTRY, Link, EFI_SMM_DRIVER_ENTRY_SIGNATURE); + + if (!DriverEntry->Initialized) { + // + // We have SMM 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 +SmmInsertOnScheduledQueueWhileProcessingBeforeAndAfter ( + IN EFI_SMM_DRIVER_ENTRY *InsertedDriverEntry + ) +{ + LIST_ENTRY *Link; + EFI_SMM_DRIVER_ENTRY *DriverEntry; + + // + // Process Before Dependency + // + for (Link = mDiscoveredList.ForwardLink; Link != &mDiscoveredList; Link = Link->ForwardLink) { + DriverEntry = CR (Link, EFI_SMM_DRIVER_ENTRY, Link, EFI_SMM_DRIVER_ENTRY_SIGNATURE); + if (DriverEntry->Before && DriverEntry->Dependent && (DriverEntry != InsertedDriverEntry)) { + DEBUG ((DEBUG_DISPATCH, "Evaluate SMM 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")); + SmmInsertOnScheduledQueueWhileProcessingBeforeAndAfter (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_SMM_DRIVER_ENTRY, Link, EFI_SMM_DRIVER_ENTRY_SIGNATURE); + if (DriverEntry->After && DriverEntry->Dependent && (DriverEntry != InsertedDriverEntry)) { + DEBUG ((DEBUG_DISPATCH, "Evaluate SMM 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")); + SmmInsertOnScheduledQueueWhileProcessingBeforeAndAfter (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 its drivers placed on the + mDiscoveredList. This function 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 +FvIsBeingProcessed ( + IN EFI_HANDLE FvHandle + ) +{ + KNOWN_HANDLE *KnownHandle; + + KnownHandle = AllocatePool (sizeof (KNOWN_HANDLE)); + ASSERT (KnownHandle != NULL); + + KnownHandle->Signature = KNOWN_HANDLE_SIGNATURE; + KnownHandle->Handle = FvHandle; + InsertTailList (&mFvHandleList, &KnownHandle->Link); +} + +/** + Convert FvHandle and DriverName into an EFI device path + + @param Fv Fv protocol, needed to read Depex info out of + FLASH. + @param FvHandle Handle for Fv, needed in the + EFI_SMM_DRIVER_ENTRY so that the PE image can be + read out of the FV at a later time. + @param DriverName Name of driver to add to mDiscoveredList. + + @return Pointer to device path constructed from FvHandle and DriverName + +**/ +EFI_DEVICE_PATH_PROTOCOL * +SmmFvToDevicePath ( + IN EFI_FIRMWARE_VOLUME2_PROTOCOL *Fv, + IN EFI_HANDLE FvHandle, + IN EFI_GUID *DriverName + ) +{ + EFI_STATUS Status; + EFI_DEVICE_PATH_PROTOCOL *FvDevicePath; + EFI_DEVICE_PATH_PROTOCOL *FileNameDevicePath; + + // + // Remember the device path of the FV + // + Status = gBS->HandleProtocol (FvHandle, &gEfiDevicePathProtocolGuid, (VOID **)&FvDevicePath); + if (EFI_ERROR (Status)) { + FileNameDevicePath = NULL; + } else { + // + // Build a device path to the file in the FV to pass into gBS->LoadImage + // + EfiInitializeFwVolDevicepathNode (&mFvDevicePath.File, DriverName); + SetDevicePathEndNode (&mFvDevicePath.End); + + // + // Note: FileNameDevicePath is in DXE memory + // + FileNameDevicePath = AppendDevicePath ( + FvDevicePath, + (EFI_DEVICE_PATH_PROTOCOL *)&mFvDevicePath + ); + } + + return FileNameDevicePath; +} + +/** + Add an entry to the mDiscoveredList. Allocate memory to store the DriverEntry, + and initialize 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 SMM driver states. + + @param Fv Fv protocol, needed to read Depex info out of + FLASH. + @param FvHandle Handle for Fv, needed in the + EFI_SMM_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 +SmmAddToDriverList ( + IN EFI_FIRMWARE_VOLUME2_PROTOCOL *Fv, + IN EFI_HANDLE FvHandle, + IN EFI_GUID *DriverName + ) +{ + EFI_SMM_DRIVER_ENTRY *DriverEntry; + + // + // Create the Driver Entry for the list. ZeroPool initializes lots of variables to + // NULL or FALSE. + // + DriverEntry = AllocateZeroPool (sizeof (EFI_SMM_DRIVER_ENTRY)); + ASSERT (DriverEntry != NULL); + + DriverEntry->Signature = EFI_SMM_DRIVER_ENTRY_SIGNATURE; + CopyGuid (&DriverEntry->FileName, DriverName); + DriverEntry->FvHandle = FvHandle; + DriverEntry->Fv = Fv; + DriverEntry->FvFileDevicePath = SmmFvToDevicePath (Fv, FvHandle, DriverName); + + SmmGetDepexSectionAndPreProccess (DriverEntry); + + InsertTailList (&mDiscoveredList, &DriverEntry->Link); + gRequestDispatch = TRUE; + + return EFI_SUCCESS; +} + +/** + This function is the main entry point for an SMM 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 SmmLocateHandle () 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 SMM 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-SMM environment into an SMM environment. + @param CommBufferSize The size of the CommBuffer. + + @return Status Code + +**/ +EFI_STATUS +EFIAPI +SmmDriverDispatchHandler ( + IN EFI_HANDLE DispatchHandle, + IN CONST VOID *Context OPTIONAL, + IN OUT VOID *CommBuffer OPTIONAL, + IN OUT UINTN *CommBufferSize OPTIONAL + ) +{ + EFI_STATUS Status; + UINTN HandleCount; + EFI_HANDLE *HandleBuffer; + EFI_STATUS GetNextFileStatus; + EFI_FIRMWARE_VOLUME2_PROTOCOL *Fv; + EFI_DEVICE_PATH_PROTOCOL *FvDevicePath; + EFI_HANDLE FvHandle; + EFI_GUID NameGuid; + UINTN Key; + EFI_FV_FILETYPE Type; + EFI_FV_FILE_ATTRIBUTES Attributes; + UINTN Size; + EFI_SMM_DRIVER_ENTRY *DriverEntry; + EFI_GUID *AprioriFile; + UINTN AprioriEntryCount; + UINTN HandleIndex; + UINTN SmmTypeIndex; + UINTN AprioriIndex; + LIST_ENTRY *Link; + UINT32 AuthenticationStatus; + UINTN SizeOfBuffer; + + HandleBuffer = NULL; + Status = gBS->LocateHandleBuffer ( + ByProtocol, + &gEfiFirmwareVolume2ProtocolGuid, + NULL, + &HandleCount, + &HandleBuffer + ); + if (EFI_ERROR (Status)) { + return EFI_NOT_FOUND; + } + + PERF_CALLBACK_BEGIN (&gEfiEventDxeDispatchGuid); + + for (HandleIndex = 0; HandleIndex < HandleCount; HandleIndex++) { + FvHandle = HandleBuffer[HandleIndex]; + + if (FvHasBeenProcessed (FvHandle)) { + // + // This Fv has already been processed so lets skip it! + // + continue; + } + + // + // Since we are about to process this Fv mark it as processed. + // + FvIsBeingProcessed (FvHandle); + + Status = gBS->HandleProtocol (FvHandle, &gEfiFirmwareVolume2ProtocolGuid, (VOID **)&Fv); + if (EFI_ERROR (Status)) { + // + // FvHandle must have a Firmware Volume2 Protocol thus we should never get here. + // + ASSERT (FALSE); + continue; + } + + Status = gBS->HandleProtocol (FvHandle, &gEfiDevicePathProtocolGuid, (VOID **)&FvDevicePath); + if (EFI_ERROR (Status)) { + // + // The Firmware volume doesn't have device path, can't be dispatched. + // + continue; + } + + // + // Discover Drivers in FV and add them to the Discovered Driver List. + // Process EFI_FV_FILETYPE_SMM type and then EFI_FV_FILETYPE_COMBINED_SMM_DXE + // EFI_FV_FILETYPE_SMM_CORE is processed to produce a Loaded Image protocol for the core + // + for (SmmTypeIndex = 0; SmmTypeIndex < sizeof (mSmmFileTypes)/sizeof (EFI_FV_FILETYPE); SmmTypeIndex++) { + // + // Initialize the search key + // + Key = 0; + do { + Type = mSmmFileTypes[SmmTypeIndex]; + GetNextFileStatus = Fv->GetNextFile ( + Fv, + &Key, + &Type, + &NameGuid, + &Attributes, + &Size + ); + if (!EFI_ERROR (GetNextFileStatus)) { + if (Type == EFI_FV_FILETYPE_SMM_CORE) { + // + // If this is the SMM core fill in it's DevicePath & DeviceHandle + // + if (mSmmCoreLoadedImage->FilePath == NULL) { + // + // Maybe one special FV contains only one SMM_CORE module, so its device path must + // be initialized completely. + // + EfiInitializeFwVolDevicepathNode (&mFvDevicePath.File, &NameGuid); + SetDevicePathEndNode (&mFvDevicePath.End); + + // + // Make an EfiBootServicesData buffer copy of FilePath + // + Status = gBS->AllocatePool ( + EfiBootServicesData, + GetDevicePathSize ((EFI_DEVICE_PATH_PROTOCOL *)&mFvDevicePath), + (VOID **)&mSmmCoreLoadedImage->FilePath + ); + ASSERT_EFI_ERROR (Status); + CopyMem (mSmmCoreLoadedImage->FilePath, &mFvDevicePath, GetDevicePathSize ((EFI_DEVICE_PATH_PROTOCOL *)&mFvDevicePath)); + + mSmmCoreLoadedImage->DeviceHandle = FvHandle; + } + + if (mSmmCoreDriverEntry->SmmLoadedImage.FilePath == NULL) { + // + // Maybe one special FV contains only one SMM_CORE module, so its device path must + // be initialized completely. + // + EfiInitializeFwVolDevicepathNode (&mFvDevicePath.File, &NameGuid); + SetDevicePathEndNode (&mFvDevicePath.End); + + // + // Make a buffer copy FilePath + // + Status = SmmAllocatePool ( + EfiRuntimeServicesData, + GetDevicePathSize ((EFI_DEVICE_PATH_PROTOCOL *)&mFvDevicePath), + (VOID **)&mSmmCoreDriverEntry->SmmLoadedImage.FilePath + ); + ASSERT_EFI_ERROR (Status); + CopyMem (mSmmCoreDriverEntry->SmmLoadedImage.FilePath, &mFvDevicePath, GetDevicePathSize ((EFI_DEVICE_PATH_PROTOCOL *)&mFvDevicePath)); + + mSmmCoreDriverEntry->SmmLoadedImage.DeviceHandle = FvHandle; + } + } else { + SmmAddToDriverList (Fv, FvHandle, &NameGuid); + } + } + } while (!EFI_ERROR (GetNextFileStatus)); + } + + // + // Read the array of GUIDs from the Apriori file if it is present in the firmware volume + // (Note: AprioriFile is in DXE memory) + // + AprioriFile = NULL; + Status = Fv->ReadSection ( + Fv, + &gAprioriGuid, + EFI_SECTION_RAW, + 0, + (VOID **)&AprioriFile, + &SizeOfBuffer, + &AuthenticationStatus + ); + if (!EFI_ERROR (Status)) { + AprioriEntryCount = SizeOfBuffer / sizeof (EFI_GUID); + } else { + AprioriEntryCount = 0; + } + + // + // Put drivers on Apriori List on the Scheduled queue. The Discovered List includes + // drivers not in the current FV and these must be skipped since the a priori list + // is only valid for the FV that it resided in. + // + + for (AprioriIndex = 0; AprioriIndex < AprioriEntryCount; AprioriIndex++) { + for (Link = mDiscoveredList.ForwardLink; Link != &mDiscoveredList; Link = Link->ForwardLink) { + DriverEntry = CR (Link, EFI_SMM_DRIVER_ENTRY, Link, EFI_SMM_DRIVER_ENTRY_SIGNATURE); + if (CompareGuid (&DriverEntry->FileName, &AprioriFile[AprioriIndex]) && + (FvHandle == DriverEntry->FvHandle)) + { + DriverEntry->Dependent = FALSE; + DriverEntry->Scheduled = TRUE; + InsertTailList (&mScheduledQueue, &DriverEntry->ScheduledLink); + DEBUG ((DEBUG_DISPATCH, "Evaluate SMM DEPEX for FFS(%g)\n", &DriverEntry->FileName)); + DEBUG ((DEBUG_DISPATCH, " RESULT = TRUE (Apriori)\n")); + break; + } + } + } + + // + // Free data allocated by Fv->ReadSection () + // + // The UEFI Boot Services FreePool() function must be used because Fv->ReadSection + // used the UEFI Boot Services AllocatePool() function + // + gBS->FreePool (AprioriFile); + } + + // + // Execute the SMM Dispatcher on any newly discovered FVs and previously + // discovered SMM drivers that have been discovered but not dispatched. + // + Status = SmmDispatcher (); + + // + // 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 SMM Core Entry Point was just registered, then set flag to + // request the SMM Dispatcher to be restarted. + // + *(UINT8 *)CommBuffer = COMM_BUFFER_SMM_DISPATCH_RESTART; + } else if (!EFI_ERROR (Status)) { + // + // Set the flag to show that the SMM Dispatcher executed without errors + // + *(UINT8 *)CommBuffer = COMM_BUFFER_SMM_DISPATCH_SUCCESS; + } else { + // + // Set the flag to show that the SMM Dispatcher encountered an error + // + *(UINT8 *)CommBuffer = COMM_BUFFER_SMM_DISPATCH_ERROR; + } + } + } + + PERF_CALLBACK_END (&gEfiEventDxeDispatchGuid); + return EFI_SUCCESS; +} + +/** + Traverse the discovered list for any drivers that were discovered but not loaded + because the dependency expressions evaluated to false. + +**/ +VOID +SmmDisplayDiscoveredNotDispatched ( + VOID + ) +{ + LIST_ENTRY *Link; + EFI_SMM_DRIVER_ENTRY *DriverEntry; + + for (Link = mDiscoveredList.ForwardLink; Link != &mDiscoveredList; Link = Link->ForwardLink) { + DriverEntry = CR (Link, EFI_SMM_DRIVER_ENTRY, Link, EFI_SMM_DRIVER_ENTRY_SIGNATURE); + if (DriverEntry->Dependent) { + DEBUG ((DEBUG_LOAD, "SMM Driver %g was discovered but not loaded!!\n", &DriverEntry->FileName)); + } + } +} diff --git a/MdeModulePkg/Core/PiSmmCore/Handle.c b/MdeModulePkg/Core/PiSmmCore/Handle.c index 5a8760a430..61ff3393f4 100644 --- a/MdeModulePkg/Core/PiSmmCore/Handle.c +++ b/MdeModulePkg/Core/PiSmmCore/Handle.c @@ -1,538 +1,538 @@ -/** @file
- SMM handle & protocol handling.
-
- Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.<BR>
- SPDX-License-Identifier: BSD-2-Clause-Patent
-
-**/
-
-#include "PiSmmCore.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
-SmmValidateHandle (
- 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 *
-SmmFindProtocolEntry (
- 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 *
-SmmFindProtocolInterface (
- 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 = SmmFindProtocolEntry (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 SmmInstallProtocolInterfaceNotify. 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
-SmmInstallProtocolInterface (
- IN OUT EFI_HANDLE *UserHandle,
- IN EFI_GUID *Protocol,
- IN EFI_INTERFACE_TYPE InterfaceType,
- IN VOID *Interface
- )
-{
- return SmmInstallProtocolInterfaceNotify (
- 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
-SmmInstallProtocolInterfaceNotify (
- 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, "SmmInstallProtocolInterface: %g %p\n", Protocol, Interface));
-
- Status = EFI_OUT_OF_RESOURCES;
- Prot = NULL;
- Handle = NULL;
-
- if (*UserHandle != NULL) {
- Status = SmmHandleProtocol (*UserHandle, Protocol, (VOID **)&ExistingInterface);
- if (!EFI_ERROR (Status)) {
- return EFI_INVALID_PARAMETER;
- }
- }
-
- //
- // Lookup the Protocol Entry for the requested protocol
- //
- ProtEntry = SmmFindProtocolEntry (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);
- } else {
- Status = SmmValidateHandle (Handle);
- if (EFI_ERROR (Status)) {
- DEBUG ((DEBUG_ERROR, "SmmInstallProtocolInterface: input handle at 0x%x is invalid\n", Handle));
- goto Done;
- }
- }
-
- //
- // Each interface that is added must be unique
- //
- ASSERT (SmmFindProtocolInterface (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) {
- SmmNotifyProtocol (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);
- }
-
- DEBUG ((DEBUG_ERROR, "SmmInstallProtocolInterface: %g %p failed with %r\n", Protocol, Interface, Status));
- }
-
- 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
-SmmUninstallProtocolInterface (
- 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 = SmmValidateHandle (UserHandle);
- if (EFI_ERROR (Status)) {
- return Status;
- }
-
- //
- // Check that Protocol exists on UserHandle, and Interface matches the interface in the database
- //
- Prot = SmmFindProtocolInterface (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 = SmmRemoveInterfaceFromProtocol (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 *
-SmmGetProtocolInterface (
- IN EFI_HANDLE UserHandle,
- IN EFI_GUID *Protocol
- )
-{
- EFI_STATUS Status;
- PROTOCOL_ENTRY *ProtEntry;
- PROTOCOL_INTERFACE *Prot;
- IHANDLE *Handle;
- LIST_ENTRY *Link;
-
- Status = SmmValidateHandle (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
-SmmHandleProtocol (
- 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 = SmmValidateHandle (UserHandle);
- if (EFI_ERROR (Status)) {
- return Status;
- }
-
- //
- // Look at each protocol interface for a match
- //
- Prot = SmmGetProtocolInterface (UserHandle, Protocol);
- if (Prot == NULL) {
- return EFI_UNSUPPORTED;
- }
-
- //
- // This is the protocol interface entry for this protocol
- //
- *Interface = Prot->Interface;
-
- return EFI_SUCCESS;
-}
+/** @file + SMM handle & protocol handling. + + Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.<BR> + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "PiSmmCore.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 +SmmValidateHandle ( + 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 * +SmmFindProtocolEntry ( + 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 * +SmmFindProtocolInterface ( + 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 = SmmFindProtocolEntry (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 SmmInstallProtocolInterfaceNotify. 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 +SmmInstallProtocolInterface ( + IN OUT EFI_HANDLE *UserHandle, + IN EFI_GUID *Protocol, + IN EFI_INTERFACE_TYPE InterfaceType, + IN VOID *Interface + ) +{ + return SmmInstallProtocolInterfaceNotify ( + 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 +SmmInstallProtocolInterfaceNotify ( + 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, "SmmInstallProtocolInterface: %g %p\n", Protocol, Interface)); + + Status = EFI_OUT_OF_RESOURCES; + Prot = NULL; + Handle = NULL; + + if (*UserHandle != NULL) { + Status = SmmHandleProtocol (*UserHandle, Protocol, (VOID **)&ExistingInterface); + if (!EFI_ERROR (Status)) { + return EFI_INVALID_PARAMETER; + } + } + + // + // Lookup the Protocol Entry for the requested protocol + // + ProtEntry = SmmFindProtocolEntry (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); + } else { + Status = SmmValidateHandle (Handle); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "SmmInstallProtocolInterface: input handle at 0x%x is invalid\n", Handle)); + goto Done; + } + } + + // + // Each interface that is added must be unique + // + ASSERT (SmmFindProtocolInterface (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) { + SmmNotifyProtocol (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); + } + + DEBUG ((DEBUG_ERROR, "SmmInstallProtocolInterface: %g %p failed with %r\n", Protocol, Interface, Status)); + } + + 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 +SmmUninstallProtocolInterface ( + 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 = SmmValidateHandle (UserHandle); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Check that Protocol exists on UserHandle, and Interface matches the interface in the database + // + Prot = SmmFindProtocolInterface (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 = SmmRemoveInterfaceFromProtocol (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 * +SmmGetProtocolInterface ( + IN EFI_HANDLE UserHandle, + IN EFI_GUID *Protocol + ) +{ + EFI_STATUS Status; + PROTOCOL_ENTRY *ProtEntry; + PROTOCOL_INTERFACE *Prot; + IHANDLE *Handle; + LIST_ENTRY *Link; + + Status = SmmValidateHandle (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 +SmmHandleProtocol ( + 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 = SmmValidateHandle (UserHandle); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Look at each protocol interface for a match + // + Prot = SmmGetProtocolInterface (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/MdeModulePkg/Core/PiSmmCore/HeapGuard.c b/MdeModulePkg/Core/PiSmmCore/HeapGuard.c index 25310122ca..558944401f 100644 --- a/MdeModulePkg/Core/PiSmmCore/HeapGuard.c +++ b/MdeModulePkg/Core/PiSmmCore/HeapGuard.c @@ -1,1430 +1,1430 @@ -/** @file
- UEFI Heap Guard functions.
-
-Copyright (c) 2017-2018, Intel Corporation. All rights reserved.<BR>
-SPDX-License-Identifier: BSD-2-Clause-Patent
-
-**/
-
-#include "HeapGuard.h"
-
-//
-// Global to avoid infinite reentrance of memory allocation when updating
-// page table attributes, which may need allocating pages for new PDE/PTE.
-//
-GLOBAL_REMOVE_IF_UNREFERENCED BOOLEAN mOnGuarding = FALSE;
-
-//
-// Pointer to table tracking the Guarded memory with bitmap, in which '1'
-// is used to indicate memory guarded. '0' might be free memory or Guard
-// page itself, depending on status of memory adjacent to it.
-//
-GLOBAL_REMOVE_IF_UNREFERENCED UINT64 mGuardedMemoryMap = 0;
-
-//
-// Current depth level of map table pointed by mGuardedMemoryMap.
-// mMapLevel must be initialized at least by 1. It will be automatically
-// updated according to the address of memory just tracked.
-//
-GLOBAL_REMOVE_IF_UNREFERENCED UINTN mMapLevel = 1;
-
-//
-// Shift and mask for each level of map table
-//
-GLOBAL_REMOVE_IF_UNREFERENCED UINTN mLevelShift[GUARDED_HEAP_MAP_TABLE_DEPTH]
- = GUARDED_HEAP_MAP_TABLE_DEPTH_SHIFTS;
-GLOBAL_REMOVE_IF_UNREFERENCED UINTN mLevelMask[GUARDED_HEAP_MAP_TABLE_DEPTH]
- = GUARDED_HEAP_MAP_TABLE_DEPTH_MASKS;
-
-//
-// SMM memory attribute protocol
-//
-EDKII_SMM_MEMORY_ATTRIBUTE_PROTOCOL *mSmmMemoryAttribute = NULL;
-
-/**
- Set corresponding bits in bitmap table to 1 according to the address.
-
- @param[in] Address Start address to set for.
- @param[in] BitNumber Number of bits to set.
- @param[in] BitMap Pointer to bitmap which covers the Address.
-
- @return VOID
-**/
-STATIC
-VOID
-SetBits (
- IN EFI_PHYSICAL_ADDRESS Address,
- IN UINTN BitNumber,
- IN UINT64 *BitMap
- )
-{
- UINTN Lsbs;
- UINTN Qwords;
- UINTN Msbs;
- UINTN StartBit;
- UINTN EndBit;
-
- StartBit = (UINTN)GUARDED_HEAP_MAP_ENTRY_BIT_INDEX (Address);
- EndBit = (StartBit + BitNumber - 1) % GUARDED_HEAP_MAP_ENTRY_BITS;
-
- if ((StartBit + BitNumber) >= GUARDED_HEAP_MAP_ENTRY_BITS) {
- Msbs = (GUARDED_HEAP_MAP_ENTRY_BITS - StartBit) %
- GUARDED_HEAP_MAP_ENTRY_BITS;
- Lsbs = (EndBit + 1) % GUARDED_HEAP_MAP_ENTRY_BITS;
- Qwords = (BitNumber - Msbs) / GUARDED_HEAP_MAP_ENTRY_BITS;
- } else {
- Msbs = BitNumber;
- Lsbs = 0;
- Qwords = 0;
- }
-
- if (Msbs > 0) {
- *BitMap |= LShiftU64 (LShiftU64 (1, Msbs) - 1, StartBit);
- BitMap += 1;
- }
-
- if (Qwords > 0) {
- SetMem64 (
- (VOID *)BitMap,
- Qwords * GUARDED_HEAP_MAP_ENTRY_BYTES,
- (UINT64)-1
- );
- BitMap += Qwords;
- }
-
- if (Lsbs > 0) {
- *BitMap |= (LShiftU64 (1, Lsbs) - 1);
- }
-}
-
-/**
- Set corresponding bits in bitmap table to 0 according to the address.
-
- @param[in] Address Start address to set for.
- @param[in] BitNumber Number of bits to set.
- @param[in] BitMap Pointer to bitmap which covers the Address.
-
- @return VOID.
-**/
-STATIC
-VOID
-ClearBits (
- IN EFI_PHYSICAL_ADDRESS Address,
- IN UINTN BitNumber,
- IN UINT64 *BitMap
- )
-{
- UINTN Lsbs;
- UINTN Qwords;
- UINTN Msbs;
- UINTN StartBit;
- UINTN EndBit;
-
- StartBit = (UINTN)GUARDED_HEAP_MAP_ENTRY_BIT_INDEX (Address);
- EndBit = (StartBit + BitNumber - 1) % GUARDED_HEAP_MAP_ENTRY_BITS;
-
- if ((StartBit + BitNumber) >= GUARDED_HEAP_MAP_ENTRY_BITS) {
- Msbs = (GUARDED_HEAP_MAP_ENTRY_BITS - StartBit) %
- GUARDED_HEAP_MAP_ENTRY_BITS;
- Lsbs = (EndBit + 1) % GUARDED_HEAP_MAP_ENTRY_BITS;
- Qwords = (BitNumber - Msbs) / GUARDED_HEAP_MAP_ENTRY_BITS;
- } else {
- Msbs = BitNumber;
- Lsbs = 0;
- Qwords = 0;
- }
-
- if (Msbs > 0) {
- *BitMap &= ~LShiftU64 (LShiftU64 (1, Msbs) - 1, StartBit);
- BitMap += 1;
- }
-
- if (Qwords > 0) {
- SetMem64 ((VOID *)BitMap, Qwords * GUARDED_HEAP_MAP_ENTRY_BYTES, 0);
- BitMap += Qwords;
- }
-
- if (Lsbs > 0) {
- *BitMap &= ~(LShiftU64 (1, Lsbs) - 1);
- }
-}
-
-/**
- Get corresponding bits in bitmap table according to the address.
-
- The value of bit 0 corresponds to the status of memory at given Address.
- No more than 64 bits can be retrieved in one call.
-
- @param[in] Address Start address to retrieve bits for.
- @param[in] BitNumber Number of bits to get.
- @param[in] BitMap Pointer to bitmap which covers the Address.
-
- @return An integer containing the bits information.
-**/
-STATIC
-UINT64
-GetBits (
- IN EFI_PHYSICAL_ADDRESS Address,
- IN UINTN BitNumber,
- IN UINT64 *BitMap
- )
-{
- UINTN StartBit;
- UINTN EndBit;
- UINTN Lsbs;
- UINTN Msbs;
- UINT64 Result;
-
- ASSERT (BitNumber <= GUARDED_HEAP_MAP_ENTRY_BITS);
-
- StartBit = (UINTN)GUARDED_HEAP_MAP_ENTRY_BIT_INDEX (Address);
- EndBit = (StartBit + BitNumber - 1) % GUARDED_HEAP_MAP_ENTRY_BITS;
-
- if ((StartBit + BitNumber) > GUARDED_HEAP_MAP_ENTRY_BITS) {
- Msbs = GUARDED_HEAP_MAP_ENTRY_BITS - StartBit;
- Lsbs = (EndBit + 1) % GUARDED_HEAP_MAP_ENTRY_BITS;
- } else {
- Msbs = BitNumber;
- Lsbs = 0;
- }
-
- if ((StartBit == 0) && (BitNumber == GUARDED_HEAP_MAP_ENTRY_BITS)) {
- Result = *BitMap;
- } else {
- Result = RShiftU64 ((*BitMap), StartBit) & (LShiftU64 (1, Msbs) - 1);
- if (Lsbs > 0) {
- BitMap += 1;
- Result |= LShiftU64 ((*BitMap) & (LShiftU64 (1, Lsbs) - 1), Msbs);
- }
- }
-
- return Result;
-}
-
-/**
- Helper function to allocate pages without Guard for internal uses.
-
- @param[in] Pages Page number.
-
- @return Address of memory allocated.
-**/
-VOID *
-PageAlloc (
- IN UINTN Pages
- )
-{
- EFI_STATUS Status;
- EFI_PHYSICAL_ADDRESS Memory;
-
- Status = SmmInternalAllocatePages (
- AllocateAnyPages,
- EfiRuntimeServicesData,
- Pages,
- &Memory,
- FALSE
- );
- if (EFI_ERROR (Status)) {
- Memory = 0;
- }
-
- return (VOID *)(UINTN)Memory;
-}
-
-/**
- Locate the pointer of bitmap from the guarded memory bitmap tables, which
- covers the given Address.
-
- @param[in] Address Start address to search the bitmap for.
- @param[in] AllocMapUnit Flag to indicate memory allocation for the table.
- @param[out] BitMap Pointer to bitmap which covers the Address.
-
- @return The bit number from given Address to the end of current map table.
-**/
-UINTN
-FindGuardedMemoryMap (
- IN EFI_PHYSICAL_ADDRESS Address,
- IN BOOLEAN AllocMapUnit,
- OUT UINT64 **BitMap
- )
-{
- UINTN Level;
- UINT64 *GuardMap;
- UINT64 MapMemory;
- UINTN Index;
- UINTN Size;
- UINTN BitsToUnitEnd;
-
- //
- // Adjust current map table depth according to the address to access
- //
- while (AllocMapUnit &&
- mMapLevel < GUARDED_HEAP_MAP_TABLE_DEPTH &&
- RShiftU64 (
- Address,
- mLevelShift[GUARDED_HEAP_MAP_TABLE_DEPTH - mMapLevel - 1]
- ) != 0)
- {
- if (mGuardedMemoryMap != 0) {
- Size = (mLevelMask[GUARDED_HEAP_MAP_TABLE_DEPTH - mMapLevel - 1] + 1)
- * GUARDED_HEAP_MAP_ENTRY_BYTES;
- MapMemory = (UINT64)(UINTN)PageAlloc (EFI_SIZE_TO_PAGES (Size));
- ASSERT (MapMemory != 0);
-
- SetMem ((VOID *)(UINTN)MapMemory, Size, 0);
-
- *(UINT64 *)(UINTN)MapMemory = mGuardedMemoryMap;
- mGuardedMemoryMap = MapMemory;
- }
-
- mMapLevel++;
- }
-
- GuardMap = &mGuardedMemoryMap;
- for (Level = GUARDED_HEAP_MAP_TABLE_DEPTH - mMapLevel;
- Level < GUARDED_HEAP_MAP_TABLE_DEPTH;
- ++Level)
- {
- if (*GuardMap == 0) {
- if (!AllocMapUnit) {
- GuardMap = NULL;
- break;
- }
-
- Size = (mLevelMask[Level] + 1) * GUARDED_HEAP_MAP_ENTRY_BYTES;
- MapMemory = (UINT64)(UINTN)PageAlloc (EFI_SIZE_TO_PAGES (Size));
- ASSERT (MapMemory != 0);
-
- SetMem ((VOID *)(UINTN)MapMemory, Size, 0);
- *GuardMap = MapMemory;
- }
-
- Index = (UINTN)RShiftU64 (Address, mLevelShift[Level]);
- Index &= mLevelMask[Level];
- GuardMap = (UINT64 *)(UINTN)((*GuardMap) + Index * sizeof (UINT64));
- }
-
- BitsToUnitEnd = GUARDED_HEAP_MAP_BITS - GUARDED_HEAP_MAP_BIT_INDEX (Address);
- *BitMap = GuardMap;
-
- return BitsToUnitEnd;
-}
-
-/**
- Set corresponding bits in bitmap table to 1 according to given memory range.
-
- @param[in] Address Memory address to guard from.
- @param[in] NumberOfPages Number of pages to guard.
-
- @return VOID
-**/
-VOID
-EFIAPI
-SetGuardedMemoryBits (
- IN EFI_PHYSICAL_ADDRESS Address,
- IN UINTN NumberOfPages
- )
-{
- UINT64 *BitMap;
- UINTN Bits;
- UINTN BitsToUnitEnd;
-
- while (NumberOfPages > 0) {
- BitsToUnitEnd = FindGuardedMemoryMap (Address, TRUE, &BitMap);
- ASSERT (BitMap != NULL);
-
- if (NumberOfPages > BitsToUnitEnd) {
- // Cross map unit
- Bits = BitsToUnitEnd;
- } else {
- Bits = NumberOfPages;
- }
-
- SetBits (Address, Bits, BitMap);
-
- NumberOfPages -= Bits;
- Address += EFI_PAGES_TO_SIZE (Bits);
- }
-}
-
-/**
- Clear corresponding bits in bitmap table according to given memory range.
-
- @param[in] Address Memory address to unset from.
- @param[in] NumberOfPages Number of pages to unset guard.
-
- @return VOID
-**/
-VOID
-EFIAPI
-ClearGuardedMemoryBits (
- IN EFI_PHYSICAL_ADDRESS Address,
- IN UINTN NumberOfPages
- )
-{
- UINT64 *BitMap;
- UINTN Bits;
- UINTN BitsToUnitEnd;
-
- while (NumberOfPages > 0) {
- BitsToUnitEnd = FindGuardedMemoryMap (Address, TRUE, &BitMap);
- ASSERT (BitMap != NULL);
-
- if (NumberOfPages > BitsToUnitEnd) {
- // Cross map unit
- Bits = BitsToUnitEnd;
- } else {
- Bits = NumberOfPages;
- }
-
- ClearBits (Address, Bits, BitMap);
-
- NumberOfPages -= Bits;
- Address += EFI_PAGES_TO_SIZE (Bits);
- }
-}
-
-/**
- Retrieve corresponding bits in bitmap table according to given memory range.
-
- @param[in] Address Memory address to retrieve from.
- @param[in] NumberOfPages Number of pages to retrieve.
-
- @return An integer containing the guarded memory bitmap.
-**/
-UINTN
-GetGuardedMemoryBits (
- IN EFI_PHYSICAL_ADDRESS Address,
- IN UINTN NumberOfPages
- )
-{
- UINT64 *BitMap;
- UINTN Bits;
- UINTN Result;
- UINTN Shift;
- UINTN BitsToUnitEnd;
-
- ASSERT (NumberOfPages <= GUARDED_HEAP_MAP_ENTRY_BITS);
-
- Result = 0;
- Shift = 0;
- while (NumberOfPages > 0) {
- BitsToUnitEnd = FindGuardedMemoryMap (Address, FALSE, &BitMap);
-
- if (NumberOfPages > BitsToUnitEnd) {
- // Cross map unit
- Bits = BitsToUnitEnd;
- } else {
- Bits = NumberOfPages;
- }
-
- if (BitMap != NULL) {
- Result |= LShiftU64 (GetBits (Address, Bits, BitMap), Shift);
- }
-
- Shift += Bits;
- NumberOfPages -= Bits;
- Address += EFI_PAGES_TO_SIZE (Bits);
- }
-
- return Result;
-}
-
-/**
- Get bit value in bitmap table for the given address.
-
- @param[in] Address The address to retrieve for.
-
- @return 1 or 0.
-**/
-UINTN
-EFIAPI
-GetGuardMapBit (
- IN EFI_PHYSICAL_ADDRESS Address
- )
-{
- UINT64 *GuardMap;
-
- FindGuardedMemoryMap (Address, FALSE, &GuardMap);
- if (GuardMap != NULL) {
- if (RShiftU64 (
- *GuardMap,
- GUARDED_HEAP_MAP_ENTRY_BIT_INDEX (Address)
- ) & 1)
- {
- return 1;
- }
- }
-
- return 0;
-}
-
-/**
- Check to see if the page at the given address is a Guard page or not.
-
- @param[in] Address The address to check for.
-
- @return TRUE The page at Address is a Guard page.
- @return FALSE The page at Address is not a Guard page.
-**/
-BOOLEAN
-EFIAPI
-IsGuardPage (
- IN EFI_PHYSICAL_ADDRESS Address
- )
-{
- UINTN BitMap;
-
- //
- // There must be at least one guarded page before and/or after given
- // address if it's a Guard page. The bitmap pattern should be one of
- // 001, 100 and 101
- //
- BitMap = GetGuardedMemoryBits (Address - EFI_PAGE_SIZE, 3);
- return ((BitMap == BIT0) || (BitMap == BIT2) || (BitMap == (BIT2 | BIT0)));
-}
-
-/**
- Check to see if the page at the given address is guarded or not.
-
- @param[in] Address The address to check for.
-
- @return TRUE The page at Address is guarded.
- @return FALSE The page at Address is not guarded.
-**/
-BOOLEAN
-EFIAPI
-IsMemoryGuarded (
- IN EFI_PHYSICAL_ADDRESS Address
- )
-{
- return (GetGuardMapBit (Address) == 1);
-}
-
-/**
- Set the page at the given address to be a Guard page.
-
- This is done by changing the page table attribute to be NOT PRESENT.
-
- @param[in] BaseAddress Page address to Guard at.
-
- @return VOID.
-**/
-VOID
-EFIAPI
-SetGuardPage (
- IN EFI_PHYSICAL_ADDRESS BaseAddress
- )
-{
- EFI_STATUS Status;
-
- if (mSmmMemoryAttribute != NULL) {
- mOnGuarding = TRUE;
- Status = mSmmMemoryAttribute->SetMemoryAttributes (
- mSmmMemoryAttribute,
- BaseAddress,
- EFI_PAGE_SIZE,
- EFI_MEMORY_RP
- );
- ASSERT_EFI_ERROR (Status);
- mOnGuarding = FALSE;
- }
-}
-
-/**
- Unset the Guard page at the given address to the normal memory.
-
- This is done by changing the page table attribute to be PRESENT.
-
- @param[in] BaseAddress Page address to Guard at.
-
- @return VOID.
-**/
-VOID
-EFIAPI
-UnsetGuardPage (
- IN EFI_PHYSICAL_ADDRESS BaseAddress
- )
-{
- EFI_STATUS Status;
-
- if (mSmmMemoryAttribute != NULL) {
- mOnGuarding = TRUE;
- Status = mSmmMemoryAttribute->ClearMemoryAttributes (
- mSmmMemoryAttribute,
- BaseAddress,
- EFI_PAGE_SIZE,
- EFI_MEMORY_RP|EFI_MEMORY_RO|EFI_MEMORY_XP
- );
- ASSERT_EFI_ERROR (Status);
-
- if (gST == NULL) {
- //
- // Make sure EfiConventionalMemory is NX after SmmReadyToLock
- //
- Status = mSmmMemoryAttribute->SetMemoryAttributes (
- mSmmMemoryAttribute,
- BaseAddress,
- EFI_PAGE_SIZE,
- EFI_MEMORY_XP
- );
- ASSERT_EFI_ERROR (Status);
- }
-
- mOnGuarding = FALSE;
- }
-}
-
-/**
- Check to see if the memory at the given address should be guarded or not.
-
- @param[in] MemoryType Memory type to check.
- @param[in] AllocateType Allocation type to check.
- @param[in] PageOrPool Indicate a page allocation or pool allocation.
-
-
- @return TRUE The given type of memory should be guarded.
- @return FALSE The given type of memory should not be guarded.
-**/
-BOOLEAN
-IsMemoryTypeToGuard (
- IN EFI_MEMORY_TYPE MemoryType,
- IN EFI_ALLOCATE_TYPE AllocateType,
- IN UINT8 PageOrPool
- )
-{
- UINT64 TestBit;
- UINT64 ConfigBit;
-
- if ( ((PcdGet8 (PcdHeapGuardPropertyMask) & PageOrPool) == 0)
- || mOnGuarding
- || (AllocateType == AllocateAddress))
- {
- return FALSE;
- }
-
- ConfigBit = 0;
- if ((PageOrPool & GUARD_HEAP_TYPE_POOL) != 0) {
- ConfigBit |= PcdGet64 (PcdHeapGuardPoolType);
- }
-
- if ((PageOrPool & GUARD_HEAP_TYPE_PAGE) != 0) {
- ConfigBit |= PcdGet64 (PcdHeapGuardPageType);
- }
-
- if ((MemoryType == EfiRuntimeServicesData) ||
- (MemoryType == EfiRuntimeServicesCode))
- {
- TestBit = LShiftU64 (1, MemoryType);
- } else if (MemoryType == EfiMaxMemoryType) {
- TestBit = (UINT64)-1;
- } else {
- TestBit = 0;
- }
-
- return ((ConfigBit & TestBit) != 0);
-}
-
-/**
- Check to see if the pool at the given address should be guarded or not.
-
- @param[in] MemoryType Pool type to check.
-
-
- @return TRUE The given type of pool should be guarded.
- @return FALSE The given type of pool should not be guarded.
-**/
-BOOLEAN
-IsPoolTypeToGuard (
- IN EFI_MEMORY_TYPE MemoryType
- )
-{
- return IsMemoryTypeToGuard (
- MemoryType,
- AllocateAnyPages,
- GUARD_HEAP_TYPE_POOL
- );
-}
-
-/**
- Check to see if the page at the given address should be guarded or not.
-
- @param[in] MemoryType Page type to check.
- @param[in] AllocateType Allocation type to check.
-
- @return TRUE The given type of page should be guarded.
- @return FALSE The given type of page should not be guarded.
-**/
-BOOLEAN
-IsPageTypeToGuard (
- IN EFI_MEMORY_TYPE MemoryType,
- IN EFI_ALLOCATE_TYPE AllocateType
- )
-{
- return IsMemoryTypeToGuard (MemoryType, AllocateType, GUARD_HEAP_TYPE_PAGE);
-}
-
-/**
- Check to see if the heap guard is enabled for page and/or pool allocation.
-
- @return TRUE/FALSE.
-**/
-BOOLEAN
-IsHeapGuardEnabled (
- VOID
- )
-{
- return IsMemoryTypeToGuard (
- EfiMaxMemoryType,
- AllocateAnyPages,
- GUARD_HEAP_TYPE_POOL|GUARD_HEAP_TYPE_PAGE
- );
-}
-
-/**
- Set head Guard and tail Guard for the given memory range.
-
- @param[in] Memory Base address of memory to set guard for.
- @param[in] NumberOfPages Memory size in pages.
-
- @return VOID.
-**/
-VOID
-SetGuardForMemory (
- IN EFI_PHYSICAL_ADDRESS Memory,
- IN UINTN NumberOfPages
- )
-{
- EFI_PHYSICAL_ADDRESS GuardPage;
-
- //
- // Set tail Guard
- //
- GuardPage = Memory + EFI_PAGES_TO_SIZE (NumberOfPages);
- if (!IsGuardPage (GuardPage)) {
- SetGuardPage (GuardPage);
- }
-
- // Set head Guard
- GuardPage = Memory - EFI_PAGES_TO_SIZE (1);
- if (!IsGuardPage (GuardPage)) {
- SetGuardPage (GuardPage);
- }
-
- //
- // Mark the memory range as Guarded
- //
- SetGuardedMemoryBits (Memory, NumberOfPages);
-}
-
-/**
- Unset head Guard and tail Guard for the given memory range.
-
- @param[in] Memory Base address of memory to unset guard for.
- @param[in] NumberOfPages Memory size in pages.
-
- @return VOID.
-**/
-VOID
-UnsetGuardForMemory (
- IN EFI_PHYSICAL_ADDRESS Memory,
- IN UINTN NumberOfPages
- )
-{
- EFI_PHYSICAL_ADDRESS GuardPage;
- UINT64 GuardBitmap;
-
- if (NumberOfPages == 0) {
- return;
- }
-
- //
- // Head Guard must be one page before, if any.
- //
- // MSB-> 1 0 <-LSB
- // -------------------
- // Head Guard -> 0 1 -> Don't free Head Guard (shared Guard)
- // Head Guard -> 0 0 -> Free Head Guard either (not shared Guard)
- // 1 X -> Don't free first page (need a new Guard)
- // (it'll be turned into a Guard page later)
- // -------------------
- // Start -> -1 -2
- //
- GuardPage = Memory - EFI_PAGES_TO_SIZE (1);
- GuardBitmap = GetGuardedMemoryBits (Memory - EFI_PAGES_TO_SIZE (2), 2);
- if ((GuardBitmap & BIT1) == 0) {
- //
- // Head Guard exists.
- //
- if ((GuardBitmap & BIT0) == 0) {
- //
- // If the head Guard is not a tail Guard of adjacent memory block,
- // unset it.
- //
- UnsetGuardPage (GuardPage);
- }
- } else {
- //
- // Pages before memory to free are still in Guard. It's a partial free
- // case. Turn first page of memory block to free into a new Guard.
- //
- SetGuardPage (Memory);
- }
-
- //
- // Tail Guard must be the page after this memory block to free, if any.
- //
- // MSB-> 1 0 <-LSB
- // --------------------
- // 1 0 <- Tail Guard -> Don't free Tail Guard (shared Guard)
- // 0 0 <- Tail Guard -> Free Tail Guard either (not shared Guard)
- // X 1 -> Don't free last page (need a new Guard)
- // (it'll be turned into a Guard page later)
- // --------------------
- // +1 +0 <- End
- //
- GuardPage = Memory + EFI_PAGES_TO_SIZE (NumberOfPages);
- GuardBitmap = GetGuardedMemoryBits (GuardPage, 2);
- if ((GuardBitmap & BIT0) == 0) {
- //
- // Tail Guard exists.
- //
- if ((GuardBitmap & BIT1) == 0) {
- //
- // If the tail Guard is not a head Guard of adjacent memory block,
- // free it; otherwise, keep it.
- //
- UnsetGuardPage (GuardPage);
- }
- } else {
- //
- // Pages after memory to free are still in Guard. It's a partial free
- // case. We need to keep one page to be a head Guard.
- //
- SetGuardPage (GuardPage - EFI_PAGES_TO_SIZE (1));
- }
-
- //
- // No matter what, we just clear the mark of the Guarded memory.
- //
- ClearGuardedMemoryBits (Memory, NumberOfPages);
-}
-
-/**
- Adjust the start address and number of pages to free according to Guard.
-
- The purpose of this function is to keep the shared Guard page with adjacent
- memory block if it's still in guard, or free it if no more sharing. Another
- is to reserve pages as Guard pages in partial page free situation.
-
- @param[in,out] Memory Base address of memory to free.
- @param[in,out] NumberOfPages Size of memory to free.
-
- @return VOID.
-**/
-VOID
-AdjustMemoryF (
- IN OUT EFI_PHYSICAL_ADDRESS *Memory,
- IN OUT UINTN *NumberOfPages
- )
-{
- EFI_PHYSICAL_ADDRESS Start;
- EFI_PHYSICAL_ADDRESS MemoryToTest;
- UINTN PagesToFree;
- UINT64 GuardBitmap;
- UINT64 Attributes;
-
- if ((Memory == NULL) || (NumberOfPages == NULL) || (*NumberOfPages == 0)) {
- return;
- }
-
- Start = *Memory;
- PagesToFree = *NumberOfPages;
-
- //
- // In case the memory to free is marked as read-only (e.g. EfiRuntimeServicesCode).
- //
- if (mSmmMemoryAttribute != NULL) {
- Attributes = 0;
- mSmmMemoryAttribute->GetMemoryAttributes (
- mSmmMemoryAttribute,
- Start,
- EFI_PAGES_TO_SIZE (PagesToFree),
- &Attributes
- );
- if ((Attributes & EFI_MEMORY_RO) != 0) {
- mSmmMemoryAttribute->ClearMemoryAttributes (
- mSmmMemoryAttribute,
- Start,
- EFI_PAGES_TO_SIZE (PagesToFree),
- EFI_MEMORY_RO
- );
- }
- }
-
- //
- // Head Guard must be one page before, if any.
- //
- // MSB-> 1 0 <-LSB
- // -------------------
- // Head Guard -> 0 1 -> Don't free Head Guard (shared Guard)
- // Head Guard -> 0 0 -> Free Head Guard either (not shared Guard)
- // 1 X -> Don't free first page (need a new Guard)
- // (it'll be turned into a Guard page later)
- // -------------------
- // Start -> -1 -2
- //
- MemoryToTest = Start - EFI_PAGES_TO_SIZE (2);
- GuardBitmap = GetGuardedMemoryBits (MemoryToTest, 2);
- if ((GuardBitmap & BIT1) == 0) {
- //
- // Head Guard exists.
- //
- if ((GuardBitmap & BIT0) == 0) {
- //
- // If the head Guard is not a tail Guard of adjacent memory block,
- // free it; otherwise, keep it.
- //
- Start -= EFI_PAGES_TO_SIZE (1);
- PagesToFree += 1;
- }
- } else {
- //
- // No Head Guard, and pages before memory to free are still in Guard. It's a
- // partial free case. We need to keep one page to be a tail Guard.
- //
- Start += EFI_PAGES_TO_SIZE (1);
- PagesToFree -= 1;
- }
-
- //
- // Tail Guard must be the page after this memory block to free, if any.
- //
- // MSB-> 1 0 <-LSB
- // --------------------
- // 1 0 <- Tail Guard -> Don't free Tail Guard (shared Guard)
- // 0 0 <- Tail Guard -> Free Tail Guard either (not shared Guard)
- // X 1 -> Don't free last page (need a new Guard)
- // (it'll be turned into a Guard page later)
- // --------------------
- // +1 +0 <- End
- //
- MemoryToTest = Start + EFI_PAGES_TO_SIZE (PagesToFree);
- GuardBitmap = GetGuardedMemoryBits (MemoryToTest, 2);
- if ((GuardBitmap & BIT0) == 0) {
- //
- // Tail Guard exists.
- //
- if ((GuardBitmap & BIT1) == 0) {
- //
- // If the tail Guard is not a head Guard of adjacent memory block,
- // free it; otherwise, keep it.
- //
- PagesToFree += 1;
- }
- } else if (PagesToFree > 0) {
- //
- // No Tail Guard, and pages after memory to free are still in Guard. It's a
- // partial free case. We need to keep one page to be a head Guard.
- //
- PagesToFree -= 1;
- }
-
- *Memory = Start;
- *NumberOfPages = PagesToFree;
-}
-
-/**
- Adjust the pool head position to make sure the Guard page is adjavent to
- pool tail or pool head.
-
- @param[in] Memory Base address of memory allocated.
- @param[in] NoPages Number of pages actually allocated.
- @param[in] Size Size of memory requested.
- (plus pool head/tail overhead)
-
- @return Address of pool head
-**/
-VOID *
-AdjustPoolHeadA (
- IN EFI_PHYSICAL_ADDRESS Memory,
- IN UINTN NoPages,
- IN UINTN Size
- )
-{
- if ((Memory == 0) || ((PcdGet8 (PcdHeapGuardPropertyMask) & BIT7) != 0)) {
- //
- // Pool head is put near the head Guard
- //
- return (VOID *)(UINTN)Memory;
- }
-
- //
- // Pool head is put near the tail Guard
- //
- Size = ALIGN_VALUE (Size, 8);
- return (VOID *)(UINTN)(Memory + EFI_PAGES_TO_SIZE (NoPages) - Size);
-}
-
-/**
- Get the page base address according to pool head address.
-
- @param[in] Memory Head address of pool to free.
-
- @return Address of pool head.
-**/
-VOID *
-AdjustPoolHeadF (
- IN EFI_PHYSICAL_ADDRESS Memory
- )
-{
- if ((Memory == 0) || ((PcdGet8 (PcdHeapGuardPropertyMask) & BIT7) != 0)) {
- //
- // Pool head is put near the head Guard
- //
- return (VOID *)(UINTN)Memory;
- }
-
- //
- // Pool head is put near the tail Guard
- //
- return (VOID *)(UINTN)(Memory & ~EFI_PAGE_MASK);
-}
-
-/**
- Helper function of memory allocation with Guard pages.
-
- @param FreePageList The free page node.
- @param NumberOfPages Number of pages to be allocated.
- @param MaxAddress Request to allocate memory below this address.
- @param MemoryType Type of memory requested.
-
- @return Memory address of allocated pages.
-**/
-UINTN
-InternalAllocMaxAddressWithGuard (
- IN OUT LIST_ENTRY *FreePageList,
- IN UINTN NumberOfPages,
- IN UINTN MaxAddress,
- IN EFI_MEMORY_TYPE MemoryType
-
- )
-{
- LIST_ENTRY *Node;
- FREE_PAGE_LIST *Pages;
- UINTN PagesToAlloc;
- UINTN HeadGuard;
- UINTN TailGuard;
- UINTN Address;
-
- 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))
- {
- //
- // We may need 1 or 2 more pages for Guard. Check it out.
- //
- PagesToAlloc = NumberOfPages;
- TailGuard = (UINTN)Pages + EFI_PAGES_TO_SIZE (Pages->NumberOfPages);
- if (!IsGuardPage (TailGuard)) {
- //
- // Add one if no Guard at the end of current free memory block.
- //
- PagesToAlloc += 1;
- TailGuard = 0;
- }
-
- HeadGuard = (UINTN)Pages +
- EFI_PAGES_TO_SIZE (Pages->NumberOfPages - PagesToAlloc) -
- EFI_PAGE_SIZE;
- if (!IsGuardPage (HeadGuard)) {
- //
- // Add one if no Guard at the page before the address to allocate
- //
- PagesToAlloc += 1;
- HeadGuard = 0;
- }
-
- if (Pages->NumberOfPages < PagesToAlloc) {
- // Not enough space to allocate memory with Guards? Try next block.
- continue;
- }
-
- Address = InternalAllocPagesOnOneNode (Pages, PagesToAlloc, MaxAddress);
- ConvertSmmMemoryMapEntry (MemoryType, Address, PagesToAlloc, FALSE);
- CoreFreeMemoryMapStack ();
- if (HeadGuard == 0) {
- // Don't pass the Guard page to user.
- Address += EFI_PAGE_SIZE;
- }
-
- SetGuardForMemory (Address, NumberOfPages);
- return Address;
- }
- }
-
- return (UINTN)(-1);
-}
-
-/**
- Helper function of memory free with Guard pages.
-
- @param[in] Memory Base address of memory being freed.
- @param[in] NumberOfPages The number of pages to free.
- @param[in] AddRegion If this memory is new added region.
-
- @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
-SmmInternalFreePagesExWithGuard (
- IN EFI_PHYSICAL_ADDRESS Memory,
- IN UINTN NumberOfPages,
- IN BOOLEAN AddRegion
- )
-{
- EFI_PHYSICAL_ADDRESS MemoryToFree;
- UINTN PagesToFree;
-
- if (((Memory & EFI_PAGE_MASK) != 0) || (Memory == 0) || (NumberOfPages == 0)) {
- return EFI_INVALID_PARAMETER;
- }
-
- MemoryToFree = Memory;
- PagesToFree = NumberOfPages;
-
- AdjustMemoryF (&MemoryToFree, &PagesToFree);
- UnsetGuardForMemory (Memory, NumberOfPages);
- if (PagesToFree == 0) {
- return EFI_SUCCESS;
- }
-
- return SmmInternalFreePagesEx (MemoryToFree, PagesToFree, AddRegion);
-}
-
-/**
- Set all Guard pages which cannot be set during the non-SMM mode time.
-**/
-VOID
-SetAllGuardPages (
- VOID
- )
-{
- UINTN Entries[GUARDED_HEAP_MAP_TABLE_DEPTH];
- UINTN Shifts[GUARDED_HEAP_MAP_TABLE_DEPTH];
- UINTN Indices[GUARDED_HEAP_MAP_TABLE_DEPTH];
- UINT64 Tables[GUARDED_HEAP_MAP_TABLE_DEPTH];
- UINT64 Addresses[GUARDED_HEAP_MAP_TABLE_DEPTH];
- UINT64 TableEntry;
- UINT64 Address;
- UINT64 GuardPage;
- INTN Level;
- UINTN Index;
- BOOLEAN OnGuarding;
-
- if ((mGuardedMemoryMap == 0) ||
- (mMapLevel == 0) ||
- (mMapLevel > GUARDED_HEAP_MAP_TABLE_DEPTH))
- {
- return;
- }
-
- CopyMem (Entries, mLevelMask, sizeof (Entries));
- CopyMem (Shifts, mLevelShift, sizeof (Shifts));
-
- SetMem (Tables, sizeof (Tables), 0);
- SetMem (Addresses, sizeof (Addresses), 0);
- SetMem (Indices, sizeof (Indices), 0);
-
- Level = GUARDED_HEAP_MAP_TABLE_DEPTH - mMapLevel;
- Tables[Level] = mGuardedMemoryMap;
- Address = 0;
- OnGuarding = FALSE;
-
- DEBUG_CODE (
- DumpGuardedMemoryBitmap ();
- );
-
- while (TRUE) {
- if (Indices[Level] > Entries[Level]) {
- Tables[Level] = 0;
- Level -= 1;
- } else {
- TableEntry = ((UINT64 *)(UINTN)(Tables[Level]))[Indices[Level]];
- Address = Addresses[Level];
-
- if (TableEntry == 0) {
- OnGuarding = FALSE;
- } else if (Level < GUARDED_HEAP_MAP_TABLE_DEPTH - 1) {
- Level += 1;
- Tables[Level] = TableEntry;
- Addresses[Level] = Address;
- Indices[Level] = 0;
-
- continue;
- } else {
- Index = 0;
- while (Index < GUARDED_HEAP_MAP_ENTRY_BITS) {
- if ((TableEntry & 1) == 1) {
- if (OnGuarding) {
- GuardPage = 0;
- } else {
- GuardPage = Address - EFI_PAGE_SIZE;
- }
-
- OnGuarding = TRUE;
- } else {
- if (OnGuarding) {
- GuardPage = Address;
- } else {
- GuardPage = 0;
- }
-
- OnGuarding = FALSE;
- }
-
- if (GuardPage != 0) {
- SetGuardPage (GuardPage);
- }
-
- if (TableEntry == 0) {
- break;
- }
-
- TableEntry = RShiftU64 (TableEntry, 1);
- Address += EFI_PAGE_SIZE;
- Index += 1;
- }
- }
- }
-
- if (Level < (GUARDED_HEAP_MAP_TABLE_DEPTH - (INTN)mMapLevel)) {
- break;
- }
-
- Indices[Level] += 1;
- Address = (Level == 0) ? 0 : Addresses[Level - 1];
- Addresses[Level] = Address | LShiftU64 (Indices[Level], Shifts[Level]);
- }
-}
-
-/**
- Hook function used to set all Guard pages after entering SMM mode.
-**/
-VOID
-SmmEntryPointMemoryManagementHook (
- VOID
- )
-{
- EFI_STATUS Status;
-
- if (mSmmMemoryAttribute == NULL) {
- Status = SmmLocateProtocol (
- &gEdkiiSmmMemoryAttributeProtocolGuid,
- NULL,
- (VOID **)&mSmmMemoryAttribute
- );
- if (!EFI_ERROR (Status)) {
- SetAllGuardPages ();
- }
- }
-}
-
-/**
- Helper function to convert a UINT64 value in binary to a string.
-
- @param[in] Value Value of a UINT64 integer.
- @param[out] BinString String buffer to contain the conversion result.
-
- @return VOID.
-**/
-VOID
-Uint64ToBinString (
- IN UINT64 Value,
- OUT CHAR8 *BinString
- )
-{
- UINTN Index;
-
- if (BinString == NULL) {
- return;
- }
-
- for (Index = 64; Index > 0; --Index) {
- BinString[Index - 1] = '0' + (Value & 1);
- Value = RShiftU64 (Value, 1);
- }
-
- BinString[64] = '\0';
-}
-
-/**
- Dump the guarded memory bit map.
-**/
-VOID
-EFIAPI
-DumpGuardedMemoryBitmap (
- VOID
- )
-{
- UINTN Entries[GUARDED_HEAP_MAP_TABLE_DEPTH];
- UINTN Shifts[GUARDED_HEAP_MAP_TABLE_DEPTH];
- UINTN Indices[GUARDED_HEAP_MAP_TABLE_DEPTH];
- UINT64 Tables[GUARDED_HEAP_MAP_TABLE_DEPTH];
- UINT64 Addresses[GUARDED_HEAP_MAP_TABLE_DEPTH];
- UINT64 TableEntry;
- UINT64 Address;
- INTN Level;
- UINTN RepeatZero;
- CHAR8 String[GUARDED_HEAP_MAP_ENTRY_BITS + 1];
- CHAR8 *Ruler1;
- CHAR8 *Ruler2;
-
- if ((mGuardedMemoryMap == 0) ||
- (mMapLevel == 0) ||
- (mMapLevel > GUARDED_HEAP_MAP_TABLE_DEPTH))
- {
- return;
- }
-
- Ruler1 = " 3 2 1 0";
- Ruler2 = "FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210";
-
- DEBUG ((
- HEAP_GUARD_DEBUG_LEVEL,
- "============================="
- " Guarded Memory Bitmap "
- "==============================\r\n"
- ));
- DEBUG ((HEAP_GUARD_DEBUG_LEVEL, " %a\r\n", Ruler1));
- DEBUG ((HEAP_GUARD_DEBUG_LEVEL, " %a\r\n", Ruler2));
-
- CopyMem (Entries, mLevelMask, sizeof (Entries));
- CopyMem (Shifts, mLevelShift, sizeof (Shifts));
-
- SetMem (Indices, sizeof (Indices), 0);
- SetMem (Tables, sizeof (Tables), 0);
- SetMem (Addresses, sizeof (Addresses), 0);
-
- Level = GUARDED_HEAP_MAP_TABLE_DEPTH - mMapLevel;
- Tables[Level] = mGuardedMemoryMap;
- Address = 0;
- RepeatZero = 0;
-
- while (TRUE) {
- if (Indices[Level] > Entries[Level]) {
- Tables[Level] = 0;
- Level -= 1;
- RepeatZero = 0;
-
- DEBUG ((
- HEAP_GUARD_DEBUG_LEVEL,
- "========================================="
- "=========================================\r\n"
- ));
- } else {
- TableEntry = ((UINT64 *)(UINTN)Tables[Level])[Indices[Level]];
- Address = Addresses[Level];
-
- if (TableEntry == 0) {
- if (Level == GUARDED_HEAP_MAP_TABLE_DEPTH - 1) {
- if (RepeatZero == 0) {
- Uint64ToBinString (TableEntry, String);
- DEBUG ((HEAP_GUARD_DEBUG_LEVEL, "%016lx: %a\r\n", Address, String));
- } else if (RepeatZero == 1) {
- DEBUG ((HEAP_GUARD_DEBUG_LEVEL, "... : ...\r\n"));
- }
-
- RepeatZero += 1;
- }
- } else if (Level < GUARDED_HEAP_MAP_TABLE_DEPTH - 1) {
- Level += 1;
- Tables[Level] = TableEntry;
- Addresses[Level] = Address;
- Indices[Level] = 0;
- RepeatZero = 0;
-
- continue;
- } else {
- RepeatZero = 0;
- Uint64ToBinString (TableEntry, String);
- DEBUG ((HEAP_GUARD_DEBUG_LEVEL, "%016lx: %a\r\n", Address, String));
- }
- }
-
- if (Level < (GUARDED_HEAP_MAP_TABLE_DEPTH - (INTN)mMapLevel)) {
- break;
- }
-
- Indices[Level] += 1;
- Address = (Level == 0) ? 0 : Addresses[Level - 1];
- Addresses[Level] = Address | LShiftU64 (Indices[Level], Shifts[Level]);
- }
-}
-
-/**
- Debug function used to verify if the Guard page is well set or not.
-
- @param[in] BaseAddress Address of memory to check.
- @param[in] NumberOfPages Size of memory in pages.
-
- @return TRUE The head Guard and tail Guard are both well set.
- @return FALSE The head Guard and/or tail Guard are not well set.
-**/
-BOOLEAN
-VerifyMemoryGuard (
- IN EFI_PHYSICAL_ADDRESS BaseAddress,
- IN UINTN NumberOfPages
- )
-{
- EFI_STATUS Status;
- UINT64 Attribute;
- EFI_PHYSICAL_ADDRESS Address;
-
- if (mSmmMemoryAttribute == NULL) {
- return TRUE;
- }
-
- Attribute = 0;
- Address = BaseAddress - EFI_PAGE_SIZE;
- Status = mSmmMemoryAttribute->GetMemoryAttributes (
- mSmmMemoryAttribute,
- Address,
- EFI_PAGE_SIZE,
- &Attribute
- );
- if (EFI_ERROR (Status) || ((Attribute & EFI_MEMORY_RP) == 0)) {
- DEBUG ((
- DEBUG_ERROR,
- "Head Guard is not set at: %016lx (%016lX)!!!\r\n",
- Address,
- Attribute
- ));
- DumpGuardedMemoryBitmap ();
- return FALSE;
- }
-
- Attribute = 0;
- Address = BaseAddress + EFI_PAGES_TO_SIZE (NumberOfPages);
- Status = mSmmMemoryAttribute->GetMemoryAttributes (
- mSmmMemoryAttribute,
- Address,
- EFI_PAGE_SIZE,
- &Attribute
- );
- if (EFI_ERROR (Status) || ((Attribute & EFI_MEMORY_RP) == 0)) {
- DEBUG ((
- DEBUG_ERROR,
- "Tail Guard is not set at: %016lx (%016lX)!!!\r\n",
- Address,
- Attribute
- ));
- DumpGuardedMemoryBitmap ();
- return FALSE;
- }
-
- return TRUE;
-}
+/** @file + UEFI Heap Guard functions. + +Copyright (c) 2017-2018, Intel Corporation. All rights reserved.<BR> +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "HeapGuard.h" + +// +// Global to avoid infinite reentrance of memory allocation when updating +// page table attributes, which may need allocating pages for new PDE/PTE. +// +GLOBAL_REMOVE_IF_UNREFERENCED BOOLEAN mOnGuarding = FALSE; + +// +// Pointer to table tracking the Guarded memory with bitmap, in which '1' +// is used to indicate memory guarded. '0' might be free memory or Guard +// page itself, depending on status of memory adjacent to it. +// +GLOBAL_REMOVE_IF_UNREFERENCED UINT64 mGuardedMemoryMap = 0; + +// +// Current depth level of map table pointed by mGuardedMemoryMap. +// mMapLevel must be initialized at least by 1. It will be automatically +// updated according to the address of memory just tracked. +// +GLOBAL_REMOVE_IF_UNREFERENCED UINTN mMapLevel = 1; + +// +// Shift and mask for each level of map table +// +GLOBAL_REMOVE_IF_UNREFERENCED UINTN mLevelShift[GUARDED_HEAP_MAP_TABLE_DEPTH] + = GUARDED_HEAP_MAP_TABLE_DEPTH_SHIFTS; +GLOBAL_REMOVE_IF_UNREFERENCED UINTN mLevelMask[GUARDED_HEAP_MAP_TABLE_DEPTH] + = GUARDED_HEAP_MAP_TABLE_DEPTH_MASKS; + +// +// SMM memory attribute protocol +// +EDKII_SMM_MEMORY_ATTRIBUTE_PROTOCOL *mSmmMemoryAttribute = NULL; + +/** + Set corresponding bits in bitmap table to 1 according to the address. + + @param[in] Address Start address to set for. + @param[in] BitNumber Number of bits to set. + @param[in] BitMap Pointer to bitmap which covers the Address. + + @return VOID +**/ +STATIC +VOID +SetBits ( + IN EFI_PHYSICAL_ADDRESS Address, + IN UINTN BitNumber, + IN UINT64 *BitMap + ) +{ + UINTN Lsbs; + UINTN Qwords; + UINTN Msbs; + UINTN StartBit; + UINTN EndBit; + + StartBit = (UINTN)GUARDED_HEAP_MAP_ENTRY_BIT_INDEX (Address); + EndBit = (StartBit + BitNumber - 1) % GUARDED_HEAP_MAP_ENTRY_BITS; + + if ((StartBit + BitNumber) >= GUARDED_HEAP_MAP_ENTRY_BITS) { + Msbs = (GUARDED_HEAP_MAP_ENTRY_BITS - StartBit) % + GUARDED_HEAP_MAP_ENTRY_BITS; + Lsbs = (EndBit + 1) % GUARDED_HEAP_MAP_ENTRY_BITS; + Qwords = (BitNumber - Msbs) / GUARDED_HEAP_MAP_ENTRY_BITS; + } else { + Msbs = BitNumber; + Lsbs = 0; + Qwords = 0; + } + + if (Msbs > 0) { + *BitMap |= LShiftU64 (LShiftU64 (1, Msbs) - 1, StartBit); + BitMap += 1; + } + + if (Qwords > 0) { + SetMem64 ( + (VOID *)BitMap, + Qwords * GUARDED_HEAP_MAP_ENTRY_BYTES, + (UINT64)-1 + ); + BitMap += Qwords; + } + + if (Lsbs > 0) { + *BitMap |= (LShiftU64 (1, Lsbs) - 1); + } +} + +/** + Set corresponding bits in bitmap table to 0 according to the address. + + @param[in] Address Start address to set for. + @param[in] BitNumber Number of bits to set. + @param[in] BitMap Pointer to bitmap which covers the Address. + + @return VOID. +**/ +STATIC +VOID +ClearBits ( + IN EFI_PHYSICAL_ADDRESS Address, + IN UINTN BitNumber, + IN UINT64 *BitMap + ) +{ + UINTN Lsbs; + UINTN Qwords; + UINTN Msbs; + UINTN StartBit; + UINTN EndBit; + + StartBit = (UINTN)GUARDED_HEAP_MAP_ENTRY_BIT_INDEX (Address); + EndBit = (StartBit + BitNumber - 1) % GUARDED_HEAP_MAP_ENTRY_BITS; + + if ((StartBit + BitNumber) >= GUARDED_HEAP_MAP_ENTRY_BITS) { + Msbs = (GUARDED_HEAP_MAP_ENTRY_BITS - StartBit) % + GUARDED_HEAP_MAP_ENTRY_BITS; + Lsbs = (EndBit + 1) % GUARDED_HEAP_MAP_ENTRY_BITS; + Qwords = (BitNumber - Msbs) / GUARDED_HEAP_MAP_ENTRY_BITS; + } else { + Msbs = BitNumber; + Lsbs = 0; + Qwords = 0; + } + + if (Msbs > 0) { + *BitMap &= ~LShiftU64 (LShiftU64 (1, Msbs) - 1, StartBit); + BitMap += 1; + } + + if (Qwords > 0) { + SetMem64 ((VOID *)BitMap, Qwords * GUARDED_HEAP_MAP_ENTRY_BYTES, 0); + BitMap += Qwords; + } + + if (Lsbs > 0) { + *BitMap &= ~(LShiftU64 (1, Lsbs) - 1); + } +} + +/** + Get corresponding bits in bitmap table according to the address. + + The value of bit 0 corresponds to the status of memory at given Address. + No more than 64 bits can be retrieved in one call. + + @param[in] Address Start address to retrieve bits for. + @param[in] BitNumber Number of bits to get. + @param[in] BitMap Pointer to bitmap which covers the Address. + + @return An integer containing the bits information. +**/ +STATIC +UINT64 +GetBits ( + IN EFI_PHYSICAL_ADDRESS Address, + IN UINTN BitNumber, + IN UINT64 *BitMap + ) +{ + UINTN StartBit; + UINTN EndBit; + UINTN Lsbs; + UINTN Msbs; + UINT64 Result; + + ASSERT (BitNumber <= GUARDED_HEAP_MAP_ENTRY_BITS); + + StartBit = (UINTN)GUARDED_HEAP_MAP_ENTRY_BIT_INDEX (Address); + EndBit = (StartBit + BitNumber - 1) % GUARDED_HEAP_MAP_ENTRY_BITS; + + if ((StartBit + BitNumber) > GUARDED_HEAP_MAP_ENTRY_BITS) { + Msbs = GUARDED_HEAP_MAP_ENTRY_BITS - StartBit; + Lsbs = (EndBit + 1) % GUARDED_HEAP_MAP_ENTRY_BITS; + } else { + Msbs = BitNumber; + Lsbs = 0; + } + + if ((StartBit == 0) && (BitNumber == GUARDED_HEAP_MAP_ENTRY_BITS)) { + Result = *BitMap; + } else { + Result = RShiftU64 ((*BitMap), StartBit) & (LShiftU64 (1, Msbs) - 1); + if (Lsbs > 0) { + BitMap += 1; + Result |= LShiftU64 ((*BitMap) & (LShiftU64 (1, Lsbs) - 1), Msbs); + } + } + + return Result; +} + +/** + Helper function to allocate pages without Guard for internal uses. + + @param[in] Pages Page number. + + @return Address of memory allocated. +**/ +VOID * +PageAlloc ( + IN UINTN Pages + ) +{ + EFI_STATUS Status; + EFI_PHYSICAL_ADDRESS Memory; + + Status = SmmInternalAllocatePages ( + AllocateAnyPages, + EfiRuntimeServicesData, + Pages, + &Memory, + FALSE + ); + if (EFI_ERROR (Status)) { + Memory = 0; + } + + return (VOID *)(UINTN)Memory; +} + +/** + Locate the pointer of bitmap from the guarded memory bitmap tables, which + covers the given Address. + + @param[in] Address Start address to search the bitmap for. + @param[in] AllocMapUnit Flag to indicate memory allocation for the table. + @param[out] BitMap Pointer to bitmap which covers the Address. + + @return The bit number from given Address to the end of current map table. +**/ +UINTN +FindGuardedMemoryMap ( + IN EFI_PHYSICAL_ADDRESS Address, + IN BOOLEAN AllocMapUnit, + OUT UINT64 **BitMap + ) +{ + UINTN Level; + UINT64 *GuardMap; + UINT64 MapMemory; + UINTN Index; + UINTN Size; + UINTN BitsToUnitEnd; + + // + // Adjust current map table depth according to the address to access + // + while (AllocMapUnit && + mMapLevel < GUARDED_HEAP_MAP_TABLE_DEPTH && + RShiftU64 ( + Address, + mLevelShift[GUARDED_HEAP_MAP_TABLE_DEPTH - mMapLevel - 1] + ) != 0) + { + if (mGuardedMemoryMap != 0) { + Size = (mLevelMask[GUARDED_HEAP_MAP_TABLE_DEPTH - mMapLevel - 1] + 1) + * GUARDED_HEAP_MAP_ENTRY_BYTES; + MapMemory = (UINT64)(UINTN)PageAlloc (EFI_SIZE_TO_PAGES (Size)); + ASSERT (MapMemory != 0); + + SetMem ((VOID *)(UINTN)MapMemory, Size, 0); + + *(UINT64 *)(UINTN)MapMemory = mGuardedMemoryMap; + mGuardedMemoryMap = MapMemory; + } + + mMapLevel++; + } + + GuardMap = &mGuardedMemoryMap; + for (Level = GUARDED_HEAP_MAP_TABLE_DEPTH - mMapLevel; + Level < GUARDED_HEAP_MAP_TABLE_DEPTH; + ++Level) + { + if (*GuardMap == 0) { + if (!AllocMapUnit) { + GuardMap = NULL; + break; + } + + Size = (mLevelMask[Level] + 1) * GUARDED_HEAP_MAP_ENTRY_BYTES; + MapMemory = (UINT64)(UINTN)PageAlloc (EFI_SIZE_TO_PAGES (Size)); + ASSERT (MapMemory != 0); + + SetMem ((VOID *)(UINTN)MapMemory, Size, 0); + *GuardMap = MapMemory; + } + + Index = (UINTN)RShiftU64 (Address, mLevelShift[Level]); + Index &= mLevelMask[Level]; + GuardMap = (UINT64 *)(UINTN)((*GuardMap) + Index * sizeof (UINT64)); + } + + BitsToUnitEnd = GUARDED_HEAP_MAP_BITS - GUARDED_HEAP_MAP_BIT_INDEX (Address); + *BitMap = GuardMap; + + return BitsToUnitEnd; +} + +/** + Set corresponding bits in bitmap table to 1 according to given memory range. + + @param[in] Address Memory address to guard from. + @param[in] NumberOfPages Number of pages to guard. + + @return VOID +**/ +VOID +EFIAPI +SetGuardedMemoryBits ( + IN EFI_PHYSICAL_ADDRESS Address, + IN UINTN NumberOfPages + ) +{ + UINT64 *BitMap; + UINTN Bits; + UINTN BitsToUnitEnd; + + while (NumberOfPages > 0) { + BitsToUnitEnd = FindGuardedMemoryMap (Address, TRUE, &BitMap); + ASSERT (BitMap != NULL); + + if (NumberOfPages > BitsToUnitEnd) { + // Cross map unit + Bits = BitsToUnitEnd; + } else { + Bits = NumberOfPages; + } + + SetBits (Address, Bits, BitMap); + + NumberOfPages -= Bits; + Address += EFI_PAGES_TO_SIZE (Bits); + } +} + +/** + Clear corresponding bits in bitmap table according to given memory range. + + @param[in] Address Memory address to unset from. + @param[in] NumberOfPages Number of pages to unset guard. + + @return VOID +**/ +VOID +EFIAPI +ClearGuardedMemoryBits ( + IN EFI_PHYSICAL_ADDRESS Address, + IN UINTN NumberOfPages + ) +{ + UINT64 *BitMap; + UINTN Bits; + UINTN BitsToUnitEnd; + + while (NumberOfPages > 0) { + BitsToUnitEnd = FindGuardedMemoryMap (Address, TRUE, &BitMap); + ASSERT (BitMap != NULL); + + if (NumberOfPages > BitsToUnitEnd) { + // Cross map unit + Bits = BitsToUnitEnd; + } else { + Bits = NumberOfPages; + } + + ClearBits (Address, Bits, BitMap); + + NumberOfPages -= Bits; + Address += EFI_PAGES_TO_SIZE (Bits); + } +} + +/** + Retrieve corresponding bits in bitmap table according to given memory range. + + @param[in] Address Memory address to retrieve from. + @param[in] NumberOfPages Number of pages to retrieve. + + @return An integer containing the guarded memory bitmap. +**/ +UINTN +GetGuardedMemoryBits ( + IN EFI_PHYSICAL_ADDRESS Address, + IN UINTN NumberOfPages + ) +{ + UINT64 *BitMap; + UINTN Bits; + UINTN Result; + UINTN Shift; + UINTN BitsToUnitEnd; + + ASSERT (NumberOfPages <= GUARDED_HEAP_MAP_ENTRY_BITS); + + Result = 0; + Shift = 0; + while (NumberOfPages > 0) { + BitsToUnitEnd = FindGuardedMemoryMap (Address, FALSE, &BitMap); + + if (NumberOfPages > BitsToUnitEnd) { + // Cross map unit + Bits = BitsToUnitEnd; + } else { + Bits = NumberOfPages; + } + + if (BitMap != NULL) { + Result |= LShiftU64 (GetBits (Address, Bits, BitMap), Shift); + } + + Shift += Bits; + NumberOfPages -= Bits; + Address += EFI_PAGES_TO_SIZE (Bits); + } + + return Result; +} + +/** + Get bit value in bitmap table for the given address. + + @param[in] Address The address to retrieve for. + + @return 1 or 0. +**/ +UINTN +EFIAPI +GetGuardMapBit ( + IN EFI_PHYSICAL_ADDRESS Address + ) +{ + UINT64 *GuardMap; + + FindGuardedMemoryMap (Address, FALSE, &GuardMap); + if (GuardMap != NULL) { + if (RShiftU64 ( + *GuardMap, + GUARDED_HEAP_MAP_ENTRY_BIT_INDEX (Address) + ) & 1) + { + return 1; + } + } + + return 0; +} + +/** + Check to see if the page at the given address is a Guard page or not. + + @param[in] Address The address to check for. + + @return TRUE The page at Address is a Guard page. + @return FALSE The page at Address is not a Guard page. +**/ +BOOLEAN +EFIAPI +IsGuardPage ( + IN EFI_PHYSICAL_ADDRESS Address + ) +{ + UINTN BitMap; + + // + // There must be at least one guarded page before and/or after given + // address if it's a Guard page. The bitmap pattern should be one of + // 001, 100 and 101 + // + BitMap = GetGuardedMemoryBits (Address - EFI_PAGE_SIZE, 3); + return ((BitMap == BIT0) || (BitMap == BIT2) || (BitMap == (BIT2 | BIT0))); +} + +/** + Check to see if the page at the given address is guarded or not. + + @param[in] Address The address to check for. + + @return TRUE The page at Address is guarded. + @return FALSE The page at Address is not guarded. +**/ +BOOLEAN +EFIAPI +IsMemoryGuarded ( + IN EFI_PHYSICAL_ADDRESS Address + ) +{ + return (GetGuardMapBit (Address) == 1); +} + +/** + Set the page at the given address to be a Guard page. + + This is done by changing the page table attribute to be NOT PRESENT. + + @param[in] BaseAddress Page address to Guard at. + + @return VOID. +**/ +VOID +EFIAPI +SetGuardPage ( + IN EFI_PHYSICAL_ADDRESS BaseAddress + ) +{ + EFI_STATUS Status; + + if (mSmmMemoryAttribute != NULL) { + mOnGuarding = TRUE; + Status = mSmmMemoryAttribute->SetMemoryAttributes ( + mSmmMemoryAttribute, + BaseAddress, + EFI_PAGE_SIZE, + EFI_MEMORY_RP + ); + ASSERT_EFI_ERROR (Status); + mOnGuarding = FALSE; + } +} + +/** + Unset the Guard page at the given address to the normal memory. + + This is done by changing the page table attribute to be PRESENT. + + @param[in] BaseAddress Page address to Guard at. + + @return VOID. +**/ +VOID +EFIAPI +UnsetGuardPage ( + IN EFI_PHYSICAL_ADDRESS BaseAddress + ) +{ + EFI_STATUS Status; + + if (mSmmMemoryAttribute != NULL) { + mOnGuarding = TRUE; + Status = mSmmMemoryAttribute->ClearMemoryAttributes ( + mSmmMemoryAttribute, + BaseAddress, + EFI_PAGE_SIZE, + EFI_MEMORY_RP|EFI_MEMORY_RO|EFI_MEMORY_XP + ); + ASSERT_EFI_ERROR (Status); + + if (gST == NULL) { + // + // Make sure EfiConventionalMemory is NX after SmmReadyToLock + // + Status = mSmmMemoryAttribute->SetMemoryAttributes ( + mSmmMemoryAttribute, + BaseAddress, + EFI_PAGE_SIZE, + EFI_MEMORY_XP + ); + ASSERT_EFI_ERROR (Status); + } + + mOnGuarding = FALSE; + } +} + +/** + Check to see if the memory at the given address should be guarded or not. + + @param[in] MemoryType Memory type to check. + @param[in] AllocateType Allocation type to check. + @param[in] PageOrPool Indicate a page allocation or pool allocation. + + + @return TRUE The given type of memory should be guarded. + @return FALSE The given type of memory should not be guarded. +**/ +BOOLEAN +IsMemoryTypeToGuard ( + IN EFI_MEMORY_TYPE MemoryType, + IN EFI_ALLOCATE_TYPE AllocateType, + IN UINT8 PageOrPool + ) +{ + UINT64 TestBit; + UINT64 ConfigBit; + + if ( ((PcdGet8 (PcdHeapGuardPropertyMask) & PageOrPool) == 0) + || mOnGuarding + || (AllocateType == AllocateAddress)) + { + return FALSE; + } + + ConfigBit = 0; + if ((PageOrPool & GUARD_HEAP_TYPE_POOL) != 0) { + ConfigBit |= PcdGet64 (PcdHeapGuardPoolType); + } + + if ((PageOrPool & GUARD_HEAP_TYPE_PAGE) != 0) { + ConfigBit |= PcdGet64 (PcdHeapGuardPageType); + } + + if ((MemoryType == EfiRuntimeServicesData) || + (MemoryType == EfiRuntimeServicesCode)) + { + TestBit = LShiftU64 (1, MemoryType); + } else if (MemoryType == EfiMaxMemoryType) { + TestBit = (UINT64)-1; + } else { + TestBit = 0; + } + + return ((ConfigBit & TestBit) != 0); +} + +/** + Check to see if the pool at the given address should be guarded or not. + + @param[in] MemoryType Pool type to check. + + + @return TRUE The given type of pool should be guarded. + @return FALSE The given type of pool should not be guarded. +**/ +BOOLEAN +IsPoolTypeToGuard ( + IN EFI_MEMORY_TYPE MemoryType + ) +{ + return IsMemoryTypeToGuard ( + MemoryType, + AllocateAnyPages, + GUARD_HEAP_TYPE_POOL + ); +} + +/** + Check to see if the page at the given address should be guarded or not. + + @param[in] MemoryType Page type to check. + @param[in] AllocateType Allocation type to check. + + @return TRUE The given type of page should be guarded. + @return FALSE The given type of page should not be guarded. +**/ +BOOLEAN +IsPageTypeToGuard ( + IN EFI_MEMORY_TYPE MemoryType, + IN EFI_ALLOCATE_TYPE AllocateType + ) +{ + return IsMemoryTypeToGuard (MemoryType, AllocateType, GUARD_HEAP_TYPE_PAGE); +} + +/** + Check to see if the heap guard is enabled for page and/or pool allocation. + + @return TRUE/FALSE. +**/ +BOOLEAN +IsHeapGuardEnabled ( + VOID + ) +{ + return IsMemoryTypeToGuard ( + EfiMaxMemoryType, + AllocateAnyPages, + GUARD_HEAP_TYPE_POOL|GUARD_HEAP_TYPE_PAGE + ); +} + +/** + Set head Guard and tail Guard for the given memory range. + + @param[in] Memory Base address of memory to set guard for. + @param[in] NumberOfPages Memory size in pages. + + @return VOID. +**/ +VOID +SetGuardForMemory ( + IN EFI_PHYSICAL_ADDRESS Memory, + IN UINTN NumberOfPages + ) +{ + EFI_PHYSICAL_ADDRESS GuardPage; + + // + // Set tail Guard + // + GuardPage = Memory + EFI_PAGES_TO_SIZE (NumberOfPages); + if (!IsGuardPage (GuardPage)) { + SetGuardPage (GuardPage); + } + + // Set head Guard + GuardPage = Memory - EFI_PAGES_TO_SIZE (1); + if (!IsGuardPage (GuardPage)) { + SetGuardPage (GuardPage); + } + + // + // Mark the memory range as Guarded + // + SetGuardedMemoryBits (Memory, NumberOfPages); +} + +/** + Unset head Guard and tail Guard for the given memory range. + + @param[in] Memory Base address of memory to unset guard for. + @param[in] NumberOfPages Memory size in pages. + + @return VOID. +**/ +VOID +UnsetGuardForMemory ( + IN EFI_PHYSICAL_ADDRESS Memory, + IN UINTN NumberOfPages + ) +{ + EFI_PHYSICAL_ADDRESS GuardPage; + UINT64 GuardBitmap; + + if (NumberOfPages == 0) { + return; + } + + // + // Head Guard must be one page before, if any. + // + // MSB-> 1 0 <-LSB + // ------------------- + // Head Guard -> 0 1 -> Don't free Head Guard (shared Guard) + // Head Guard -> 0 0 -> Free Head Guard either (not shared Guard) + // 1 X -> Don't free first page (need a new Guard) + // (it'll be turned into a Guard page later) + // ------------------- + // Start -> -1 -2 + // + GuardPage = Memory - EFI_PAGES_TO_SIZE (1); + GuardBitmap = GetGuardedMemoryBits (Memory - EFI_PAGES_TO_SIZE (2), 2); + if ((GuardBitmap & BIT1) == 0) { + // + // Head Guard exists. + // + if ((GuardBitmap & BIT0) == 0) { + // + // If the head Guard is not a tail Guard of adjacent memory block, + // unset it. + // + UnsetGuardPage (GuardPage); + } + } else { + // + // Pages before memory to free are still in Guard. It's a partial free + // case. Turn first page of memory block to free into a new Guard. + // + SetGuardPage (Memory); + } + + // + // Tail Guard must be the page after this memory block to free, if any. + // + // MSB-> 1 0 <-LSB + // -------------------- + // 1 0 <- Tail Guard -> Don't free Tail Guard (shared Guard) + // 0 0 <- Tail Guard -> Free Tail Guard either (not shared Guard) + // X 1 -> Don't free last page (need a new Guard) + // (it'll be turned into a Guard page later) + // -------------------- + // +1 +0 <- End + // + GuardPage = Memory + EFI_PAGES_TO_SIZE (NumberOfPages); + GuardBitmap = GetGuardedMemoryBits (GuardPage, 2); + if ((GuardBitmap & BIT0) == 0) { + // + // Tail Guard exists. + // + if ((GuardBitmap & BIT1) == 0) { + // + // If the tail Guard is not a head Guard of adjacent memory block, + // free it; otherwise, keep it. + // + UnsetGuardPage (GuardPage); + } + } else { + // + // Pages after memory to free are still in Guard. It's a partial free + // case. We need to keep one page to be a head Guard. + // + SetGuardPage (GuardPage - EFI_PAGES_TO_SIZE (1)); + } + + // + // No matter what, we just clear the mark of the Guarded memory. + // + ClearGuardedMemoryBits (Memory, NumberOfPages); +} + +/** + Adjust the start address and number of pages to free according to Guard. + + The purpose of this function is to keep the shared Guard page with adjacent + memory block if it's still in guard, or free it if no more sharing. Another + is to reserve pages as Guard pages in partial page free situation. + + @param[in,out] Memory Base address of memory to free. + @param[in,out] NumberOfPages Size of memory to free. + + @return VOID. +**/ +VOID +AdjustMemoryF ( + IN OUT EFI_PHYSICAL_ADDRESS *Memory, + IN OUT UINTN *NumberOfPages + ) +{ + EFI_PHYSICAL_ADDRESS Start; + EFI_PHYSICAL_ADDRESS MemoryToTest; + UINTN PagesToFree; + UINT64 GuardBitmap; + UINT64 Attributes; + + if ((Memory == NULL) || (NumberOfPages == NULL) || (*NumberOfPages == 0)) { + return; + } + + Start = *Memory; + PagesToFree = *NumberOfPages; + + // + // In case the memory to free is marked as read-only (e.g. EfiRuntimeServicesCode). + // + if (mSmmMemoryAttribute != NULL) { + Attributes = 0; + mSmmMemoryAttribute->GetMemoryAttributes ( + mSmmMemoryAttribute, + Start, + EFI_PAGES_TO_SIZE (PagesToFree), + &Attributes + ); + if ((Attributes & EFI_MEMORY_RO) != 0) { + mSmmMemoryAttribute->ClearMemoryAttributes ( + mSmmMemoryAttribute, + Start, + EFI_PAGES_TO_SIZE (PagesToFree), + EFI_MEMORY_RO + ); + } + } + + // + // Head Guard must be one page before, if any. + // + // MSB-> 1 0 <-LSB + // ------------------- + // Head Guard -> 0 1 -> Don't free Head Guard (shared Guard) + // Head Guard -> 0 0 -> Free Head Guard either (not shared Guard) + // 1 X -> Don't free first page (need a new Guard) + // (it'll be turned into a Guard page later) + // ------------------- + // Start -> -1 -2 + // + MemoryToTest = Start - EFI_PAGES_TO_SIZE (2); + GuardBitmap = GetGuardedMemoryBits (MemoryToTest, 2); + if ((GuardBitmap & BIT1) == 0) { + // + // Head Guard exists. + // + if ((GuardBitmap & BIT0) == 0) { + // + // If the head Guard is not a tail Guard of adjacent memory block, + // free it; otherwise, keep it. + // + Start -= EFI_PAGES_TO_SIZE (1); + PagesToFree += 1; + } + } else { + // + // No Head Guard, and pages before memory to free are still in Guard. It's a + // partial free case. We need to keep one page to be a tail Guard. + // + Start += EFI_PAGES_TO_SIZE (1); + PagesToFree -= 1; + } + + // + // Tail Guard must be the page after this memory block to free, if any. + // + // MSB-> 1 0 <-LSB + // -------------------- + // 1 0 <- Tail Guard -> Don't free Tail Guard (shared Guard) + // 0 0 <- Tail Guard -> Free Tail Guard either (not shared Guard) + // X 1 -> Don't free last page (need a new Guard) + // (it'll be turned into a Guard page later) + // -------------------- + // +1 +0 <- End + // + MemoryToTest = Start + EFI_PAGES_TO_SIZE (PagesToFree); + GuardBitmap = GetGuardedMemoryBits (MemoryToTest, 2); + if ((GuardBitmap & BIT0) == 0) { + // + // Tail Guard exists. + // + if ((GuardBitmap & BIT1) == 0) { + // + // If the tail Guard is not a head Guard of adjacent memory block, + // free it; otherwise, keep it. + // + PagesToFree += 1; + } + } else if (PagesToFree > 0) { + // + // No Tail Guard, and pages after memory to free are still in Guard. It's a + // partial free case. We need to keep one page to be a head Guard. + // + PagesToFree -= 1; + } + + *Memory = Start; + *NumberOfPages = PagesToFree; +} + +/** + Adjust the pool head position to make sure the Guard page is adjavent to + pool tail or pool head. + + @param[in] Memory Base address of memory allocated. + @param[in] NoPages Number of pages actually allocated. + @param[in] Size Size of memory requested. + (plus pool head/tail overhead) + + @return Address of pool head +**/ +VOID * +AdjustPoolHeadA ( + IN EFI_PHYSICAL_ADDRESS Memory, + IN UINTN NoPages, + IN UINTN Size + ) +{ + if ((Memory == 0) || ((PcdGet8 (PcdHeapGuardPropertyMask) & BIT7) != 0)) { + // + // Pool head is put near the head Guard + // + return (VOID *)(UINTN)Memory; + } + + // + // Pool head is put near the tail Guard + // + Size = ALIGN_VALUE (Size, 8); + return (VOID *)(UINTN)(Memory + EFI_PAGES_TO_SIZE (NoPages) - Size); +} + +/** + Get the page base address according to pool head address. + + @param[in] Memory Head address of pool to free. + + @return Address of pool head. +**/ +VOID * +AdjustPoolHeadF ( + IN EFI_PHYSICAL_ADDRESS Memory + ) +{ + if ((Memory == 0) || ((PcdGet8 (PcdHeapGuardPropertyMask) & BIT7) != 0)) { + // + // Pool head is put near the head Guard + // + return (VOID *)(UINTN)Memory; + } + + // + // Pool head is put near the tail Guard + // + return (VOID *)(UINTN)(Memory & ~EFI_PAGE_MASK); +} + +/** + Helper function of memory allocation with Guard pages. + + @param FreePageList The free page node. + @param NumberOfPages Number of pages to be allocated. + @param MaxAddress Request to allocate memory below this address. + @param MemoryType Type of memory requested. + + @return Memory address of allocated pages. +**/ +UINTN +InternalAllocMaxAddressWithGuard ( + IN OUT LIST_ENTRY *FreePageList, + IN UINTN NumberOfPages, + IN UINTN MaxAddress, + IN EFI_MEMORY_TYPE MemoryType + + ) +{ + LIST_ENTRY *Node; + FREE_PAGE_LIST *Pages; + UINTN PagesToAlloc; + UINTN HeadGuard; + UINTN TailGuard; + UINTN Address; + + 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)) + { + // + // We may need 1 or 2 more pages for Guard. Check it out. + // + PagesToAlloc = NumberOfPages; + TailGuard = (UINTN)Pages + EFI_PAGES_TO_SIZE (Pages->NumberOfPages); + if (!IsGuardPage (TailGuard)) { + // + // Add one if no Guard at the end of current free memory block. + // + PagesToAlloc += 1; + TailGuard = 0; + } + + HeadGuard = (UINTN)Pages + + EFI_PAGES_TO_SIZE (Pages->NumberOfPages - PagesToAlloc) - + EFI_PAGE_SIZE; + if (!IsGuardPage (HeadGuard)) { + // + // Add one if no Guard at the page before the address to allocate + // + PagesToAlloc += 1; + HeadGuard = 0; + } + + if (Pages->NumberOfPages < PagesToAlloc) { + // Not enough space to allocate memory with Guards? Try next block. + continue; + } + + Address = InternalAllocPagesOnOneNode (Pages, PagesToAlloc, MaxAddress); + ConvertSmmMemoryMapEntry (MemoryType, Address, PagesToAlloc, FALSE); + CoreFreeMemoryMapStack (); + if (HeadGuard == 0) { + // Don't pass the Guard page to user. + Address += EFI_PAGE_SIZE; + } + + SetGuardForMemory (Address, NumberOfPages); + return Address; + } + } + + return (UINTN)(-1); +} + +/** + Helper function of memory free with Guard pages. + + @param[in] Memory Base address of memory being freed. + @param[in] NumberOfPages The number of pages to free. + @param[in] AddRegion If this memory is new added region. + + @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 +SmmInternalFreePagesExWithGuard ( + IN EFI_PHYSICAL_ADDRESS Memory, + IN UINTN NumberOfPages, + IN BOOLEAN AddRegion + ) +{ + EFI_PHYSICAL_ADDRESS MemoryToFree; + UINTN PagesToFree; + + if (((Memory & EFI_PAGE_MASK) != 0) || (Memory == 0) || (NumberOfPages == 0)) { + return EFI_INVALID_PARAMETER; + } + + MemoryToFree = Memory; + PagesToFree = NumberOfPages; + + AdjustMemoryF (&MemoryToFree, &PagesToFree); + UnsetGuardForMemory (Memory, NumberOfPages); + if (PagesToFree == 0) { + return EFI_SUCCESS; + } + + return SmmInternalFreePagesEx (MemoryToFree, PagesToFree, AddRegion); +} + +/** + Set all Guard pages which cannot be set during the non-SMM mode time. +**/ +VOID +SetAllGuardPages ( + VOID + ) +{ + UINTN Entries[GUARDED_HEAP_MAP_TABLE_DEPTH]; + UINTN Shifts[GUARDED_HEAP_MAP_TABLE_DEPTH]; + UINTN Indices[GUARDED_HEAP_MAP_TABLE_DEPTH]; + UINT64 Tables[GUARDED_HEAP_MAP_TABLE_DEPTH]; + UINT64 Addresses[GUARDED_HEAP_MAP_TABLE_DEPTH]; + UINT64 TableEntry; + UINT64 Address; + UINT64 GuardPage; + INTN Level; + UINTN Index; + BOOLEAN OnGuarding; + + if ((mGuardedMemoryMap == 0) || + (mMapLevel == 0) || + (mMapLevel > GUARDED_HEAP_MAP_TABLE_DEPTH)) + { + return; + } + + CopyMem (Entries, mLevelMask, sizeof (Entries)); + CopyMem (Shifts, mLevelShift, sizeof (Shifts)); + + SetMem (Tables, sizeof (Tables), 0); + SetMem (Addresses, sizeof (Addresses), 0); + SetMem (Indices, sizeof (Indices), 0); + + Level = GUARDED_HEAP_MAP_TABLE_DEPTH - mMapLevel; + Tables[Level] = mGuardedMemoryMap; + Address = 0; + OnGuarding = FALSE; + + DEBUG_CODE ( + DumpGuardedMemoryBitmap (); + ); + + while (TRUE) { + if (Indices[Level] > Entries[Level]) { + Tables[Level] = 0; + Level -= 1; + } else { + TableEntry = ((UINT64 *)(UINTN)(Tables[Level]))[Indices[Level]]; + Address = Addresses[Level]; + + if (TableEntry == 0) { + OnGuarding = FALSE; + } else if (Level < GUARDED_HEAP_MAP_TABLE_DEPTH - 1) { + Level += 1; + Tables[Level] = TableEntry; + Addresses[Level] = Address; + Indices[Level] = 0; + + continue; + } else { + Index = 0; + while (Index < GUARDED_HEAP_MAP_ENTRY_BITS) { + if ((TableEntry & 1) == 1) { + if (OnGuarding) { + GuardPage = 0; + } else { + GuardPage = Address - EFI_PAGE_SIZE; + } + + OnGuarding = TRUE; + } else { + if (OnGuarding) { + GuardPage = Address; + } else { + GuardPage = 0; + } + + OnGuarding = FALSE; + } + + if (GuardPage != 0) { + SetGuardPage (GuardPage); + } + + if (TableEntry == 0) { + break; + } + + TableEntry = RShiftU64 (TableEntry, 1); + Address += EFI_PAGE_SIZE; + Index += 1; + } + } + } + + if (Level < (GUARDED_HEAP_MAP_TABLE_DEPTH - (INTN)mMapLevel)) { + break; + } + + Indices[Level] += 1; + Address = (Level == 0) ? 0 : Addresses[Level - 1]; + Addresses[Level] = Address | LShiftU64 (Indices[Level], Shifts[Level]); + } +} + +/** + Hook function used to set all Guard pages after entering SMM mode. +**/ +VOID +SmmEntryPointMemoryManagementHook ( + VOID + ) +{ + EFI_STATUS Status; + + if (mSmmMemoryAttribute == NULL) { + Status = SmmLocateProtocol ( + &gEdkiiSmmMemoryAttributeProtocolGuid, + NULL, + (VOID **)&mSmmMemoryAttribute + ); + if (!EFI_ERROR (Status)) { + SetAllGuardPages (); + } + } +} + +/** + Helper function to convert a UINT64 value in binary to a string. + + @param[in] Value Value of a UINT64 integer. + @param[out] BinString String buffer to contain the conversion result. + + @return VOID. +**/ +VOID +Uint64ToBinString ( + IN UINT64 Value, + OUT CHAR8 *BinString + ) +{ + UINTN Index; + + if (BinString == NULL) { + return; + } + + for (Index = 64; Index > 0; --Index) { + BinString[Index - 1] = '0' + (Value & 1); + Value = RShiftU64 (Value, 1); + } + + BinString[64] = '\0'; +} + +/** + Dump the guarded memory bit map. +**/ +VOID +EFIAPI +DumpGuardedMemoryBitmap ( + VOID + ) +{ + UINTN Entries[GUARDED_HEAP_MAP_TABLE_DEPTH]; + UINTN Shifts[GUARDED_HEAP_MAP_TABLE_DEPTH]; + UINTN Indices[GUARDED_HEAP_MAP_TABLE_DEPTH]; + UINT64 Tables[GUARDED_HEAP_MAP_TABLE_DEPTH]; + UINT64 Addresses[GUARDED_HEAP_MAP_TABLE_DEPTH]; + UINT64 TableEntry; + UINT64 Address; + INTN Level; + UINTN RepeatZero; + CHAR8 String[GUARDED_HEAP_MAP_ENTRY_BITS + 1]; + CHAR8 *Ruler1; + CHAR8 *Ruler2; + + if ((mGuardedMemoryMap == 0) || + (mMapLevel == 0) || + (mMapLevel > GUARDED_HEAP_MAP_TABLE_DEPTH)) + { + return; + } + + Ruler1 = " 3 2 1 0"; + Ruler2 = "FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210"; + + DEBUG (( + HEAP_GUARD_DEBUG_LEVEL, + "=============================" + " Guarded Memory Bitmap " + "==============================\r\n" + )); + DEBUG ((HEAP_GUARD_DEBUG_LEVEL, " %a\r\n", Ruler1)); + DEBUG ((HEAP_GUARD_DEBUG_LEVEL, " %a\r\n", Ruler2)); + + CopyMem (Entries, mLevelMask, sizeof (Entries)); + CopyMem (Shifts, mLevelShift, sizeof (Shifts)); + + SetMem (Indices, sizeof (Indices), 0); + SetMem (Tables, sizeof (Tables), 0); + SetMem (Addresses, sizeof (Addresses), 0); + + Level = GUARDED_HEAP_MAP_TABLE_DEPTH - mMapLevel; + Tables[Level] = mGuardedMemoryMap; + Address = 0; + RepeatZero = 0; + + while (TRUE) { + if (Indices[Level] > Entries[Level]) { + Tables[Level] = 0; + Level -= 1; + RepeatZero = 0; + + DEBUG (( + HEAP_GUARD_DEBUG_LEVEL, + "=========================================" + "=========================================\r\n" + )); + } else { + TableEntry = ((UINT64 *)(UINTN)Tables[Level])[Indices[Level]]; + Address = Addresses[Level]; + + if (TableEntry == 0) { + if (Level == GUARDED_HEAP_MAP_TABLE_DEPTH - 1) { + if (RepeatZero == 0) { + Uint64ToBinString (TableEntry, String); + DEBUG ((HEAP_GUARD_DEBUG_LEVEL, "%016lx: %a\r\n", Address, String)); + } else if (RepeatZero == 1) { + DEBUG ((HEAP_GUARD_DEBUG_LEVEL, "... : ...\r\n")); + } + + RepeatZero += 1; + } + } else if (Level < GUARDED_HEAP_MAP_TABLE_DEPTH - 1) { + Level += 1; + Tables[Level] = TableEntry; + Addresses[Level] = Address; + Indices[Level] = 0; + RepeatZero = 0; + + continue; + } else { + RepeatZero = 0; + Uint64ToBinString (TableEntry, String); + DEBUG ((HEAP_GUARD_DEBUG_LEVEL, "%016lx: %a\r\n", Address, String)); + } + } + + if (Level < (GUARDED_HEAP_MAP_TABLE_DEPTH - (INTN)mMapLevel)) { + break; + } + + Indices[Level] += 1; + Address = (Level == 0) ? 0 : Addresses[Level - 1]; + Addresses[Level] = Address | LShiftU64 (Indices[Level], Shifts[Level]); + } +} + +/** + Debug function used to verify if the Guard page is well set or not. + + @param[in] BaseAddress Address of memory to check. + @param[in] NumberOfPages Size of memory in pages. + + @return TRUE The head Guard and tail Guard are both well set. + @return FALSE The head Guard and/or tail Guard are not well set. +**/ +BOOLEAN +VerifyMemoryGuard ( + IN EFI_PHYSICAL_ADDRESS BaseAddress, + IN UINTN NumberOfPages + ) +{ + EFI_STATUS Status; + UINT64 Attribute; + EFI_PHYSICAL_ADDRESS Address; + + if (mSmmMemoryAttribute == NULL) { + return TRUE; + } + + Attribute = 0; + Address = BaseAddress - EFI_PAGE_SIZE; + Status = mSmmMemoryAttribute->GetMemoryAttributes ( + mSmmMemoryAttribute, + Address, + EFI_PAGE_SIZE, + &Attribute + ); + if (EFI_ERROR (Status) || ((Attribute & EFI_MEMORY_RP) == 0)) { + DEBUG (( + DEBUG_ERROR, + "Head Guard is not set at: %016lx (%016lX)!!!\r\n", + Address, + Attribute + )); + DumpGuardedMemoryBitmap (); + return FALSE; + } + + Attribute = 0; + Address = BaseAddress + EFI_PAGES_TO_SIZE (NumberOfPages); + Status = mSmmMemoryAttribute->GetMemoryAttributes ( + mSmmMemoryAttribute, + Address, + EFI_PAGE_SIZE, + &Attribute + ); + if (EFI_ERROR (Status) || ((Attribute & EFI_MEMORY_RP) == 0)) { + DEBUG (( + DEBUG_ERROR, + "Tail Guard is not set at: %016lx (%016lX)!!!\r\n", + Address, + Attribute + )); + DumpGuardedMemoryBitmap (); + return FALSE; + } + + return TRUE; +} diff --git a/MdeModulePkg/Core/PiSmmCore/HeapGuard.h b/MdeModulePkg/Core/PiSmmCore/HeapGuard.h index 0a447ce2e8..d7c9ba9306 100644 --- a/MdeModulePkg/Core/PiSmmCore/HeapGuard.h +++ b/MdeModulePkg/Core/PiSmmCore/HeapGuard.h @@ -1,392 +1,392 @@ -/** @file
- Data structure and functions to allocate and free memory space.
-
-Copyright (c) 2017, Intel Corporation. All rights reserved.<BR>
-SPDX-License-Identifier: BSD-2-Clause-Patent
-
-**/
-
-#ifndef _HEAPGUARD_H_
-#define _HEAPGUARD_H_
-
-#include "PiSmmCore.h"
-
-//
-// Following macros are used to define and access the guarded memory bitmap
-// table.
-//
-// To simplify the access and reduce the memory used for this table, the
-// table is constructed in the similar way as page table structure but in
-// reverse direction, i.e. from bottom growing up to top.
-//
-// - 1-bit tracks 1 page (4KB)
-// - 1-UINT64 map entry tracks 256KB memory
-// - 1K-UINT64 map table tracks 256MB memory
-// - Five levels of tables can track any address of memory of 64-bit
-// system, like below.
-//
-// 512 * 512 * 512 * 512 * 1K * 64b * 4K
-// 111111111 111111111 111111111 111111111 1111111111 111111 111111111111
-// 63 54 45 36 27 17 11 0
-// 9b 9b 9b 9b 10b 6b 12b
-// L0 -> L1 -> L2 -> L3 -> L4 -> bits -> page
-// 1FF 1FF 1FF 1FF 3FF 3F FFF
-//
-// L4 table has 1K * sizeof(UINT64) = 8K (2-page), which can track 256MB
-// memory. Each table of L0-L3 will be allocated when its memory address
-// range is to be tracked. Only 1-page will be allocated each time. This
-// can save memories used to establish this map table.
-//
-// For a normal configuration of system with 4G memory, two levels of tables
-// can track the whole memory, because two levels (L3+L4) of map tables have
-// already covered 37-bit of memory address. And for a normal UEFI BIOS,
-// less than 128M memory would be consumed during boot. That means we just
-// need
-//
-// 1-page (L3) + 2-page (L4)
-//
-// memory (3 pages) to track the memory allocation works. In this case,
-// there's no need to setup L0-L2 tables.
-//
-
-//
-// Each entry occupies 8B/64b. 1-page can hold 512 entries, which spans 9
-// bits in address. (512 = 1 << 9)
-//
-#define BYTE_LENGTH_SHIFT 3 // (8 = 1 << 3)
-
-#define GUARDED_HEAP_MAP_TABLE_ENTRY_SHIFT \
- (EFI_PAGE_SHIFT - BYTE_LENGTH_SHIFT)
-
-#define GUARDED_HEAP_MAP_TABLE_DEPTH 5
-
-// Use UINT64_index + bit_index_of_UINT64 to locate the bit in may
-#define GUARDED_HEAP_MAP_ENTRY_BIT_SHIFT 6 // (64 = 1 << 6)
-
-#define GUARDED_HEAP_MAP_ENTRY_BITS \
- (1 << GUARDED_HEAP_MAP_ENTRY_BIT_SHIFT)
-
-#define GUARDED_HEAP_MAP_ENTRY_BYTES \
- (GUARDED_HEAP_MAP_ENTRY_BITS / 8)
-
-// L4 table address width: 64 - 9 * 4 - 6 - 12 = 10b
-#define GUARDED_HEAP_MAP_ENTRY_SHIFT \
- (GUARDED_HEAP_MAP_ENTRY_BITS \
- - GUARDED_HEAP_MAP_TABLE_ENTRY_SHIFT * 4 \
- - GUARDED_HEAP_MAP_ENTRY_BIT_SHIFT \
- - EFI_PAGE_SHIFT)
-
-// L4 table address mask: (1 << 10 - 1) = 0x3FF
-#define GUARDED_HEAP_MAP_ENTRY_MASK \
- ((1 << GUARDED_HEAP_MAP_ENTRY_SHIFT) - 1)
-
-// Size of each L4 table: (1 << 10) * 8 = 8KB = 2-page
-#define GUARDED_HEAP_MAP_SIZE \
- ((1 << GUARDED_HEAP_MAP_ENTRY_SHIFT) * GUARDED_HEAP_MAP_ENTRY_BYTES)
-
-// Memory size tracked by one L4 table: 8KB * 8 * 4KB = 256MB
-#define GUARDED_HEAP_MAP_UNIT_SIZE \
- (GUARDED_HEAP_MAP_SIZE * 8 * EFI_PAGE_SIZE)
-
-// L4 table entry number: 8KB / 8 = 1024
-#define GUARDED_HEAP_MAP_ENTRIES_PER_UNIT \
- (GUARDED_HEAP_MAP_SIZE / GUARDED_HEAP_MAP_ENTRY_BYTES)
-
-// L4 table entry indexing
-#define GUARDED_HEAP_MAP_ENTRY_INDEX(Address) \
- (RShiftU64 (Address, EFI_PAGE_SHIFT \
- + GUARDED_HEAP_MAP_ENTRY_BIT_SHIFT) \
- & GUARDED_HEAP_MAP_ENTRY_MASK)
-
-// L4 table entry bit indexing
-#define GUARDED_HEAP_MAP_ENTRY_BIT_INDEX(Address) \
- (RShiftU64 (Address, EFI_PAGE_SHIFT) \
- & ((1 << GUARDED_HEAP_MAP_ENTRY_BIT_SHIFT) - 1))
-
-//
-// Total bits (pages) tracked by one L4 table (65536-bit)
-//
-#define GUARDED_HEAP_MAP_BITS \
- (1 << (GUARDED_HEAP_MAP_ENTRY_SHIFT \
- + GUARDED_HEAP_MAP_ENTRY_BIT_SHIFT))
-
-//
-// Bit indexing inside the whole L4 table (0 - 65535)
-//
-#define GUARDED_HEAP_MAP_BIT_INDEX(Address) \
- (RShiftU64 (Address, EFI_PAGE_SHIFT) \
- & ((1 << (GUARDED_HEAP_MAP_ENTRY_SHIFT \
- + GUARDED_HEAP_MAP_ENTRY_BIT_SHIFT)) - 1))
-
-//
-// Memory address bit width tracked by L4 table: 10 + 6 + 12 = 28
-//
-#define GUARDED_HEAP_MAP_TABLE_SHIFT \
- (GUARDED_HEAP_MAP_ENTRY_SHIFT + GUARDED_HEAP_MAP_ENTRY_BIT_SHIFT \
- + EFI_PAGE_SHIFT)
-
-//
-// Macro used to initialize the local array variable for map table traversing
-// {55, 46, 37, 28, 18}
-//
-#define GUARDED_HEAP_MAP_TABLE_DEPTH_SHIFTS \
- { \
- GUARDED_HEAP_MAP_TABLE_SHIFT + GUARDED_HEAP_MAP_TABLE_ENTRY_SHIFT * 3, \
- GUARDED_HEAP_MAP_TABLE_SHIFT + GUARDED_HEAP_MAP_TABLE_ENTRY_SHIFT * 2, \
- GUARDED_HEAP_MAP_TABLE_SHIFT + GUARDED_HEAP_MAP_TABLE_ENTRY_SHIFT, \
- GUARDED_HEAP_MAP_TABLE_SHIFT, \
- EFI_PAGE_SHIFT + GUARDED_HEAP_MAP_ENTRY_BIT_SHIFT \
- }
-
-//
-// Masks used to extract address range of each level of table
-// {0x1FF, 0x1FF, 0x1FF, 0x1FF, 0x3FF}
-//
-#define GUARDED_HEAP_MAP_TABLE_DEPTH_MASKS \
- { \
- (1 << GUARDED_HEAP_MAP_TABLE_ENTRY_SHIFT) - 1, \
- (1 << GUARDED_HEAP_MAP_TABLE_ENTRY_SHIFT) - 1, \
- (1 << GUARDED_HEAP_MAP_TABLE_ENTRY_SHIFT) - 1, \
- (1 << GUARDED_HEAP_MAP_TABLE_ENTRY_SHIFT) - 1, \
- (1 << GUARDED_HEAP_MAP_ENTRY_SHIFT) - 1 \
- }
-
-//
-// Memory type to guard (matching the related PCD definition)
-//
-#define GUARD_HEAP_TYPE_PAGE BIT2
-#define GUARD_HEAP_TYPE_POOL BIT3
-
-//
-// Debug message level
-//
-#define HEAP_GUARD_DEBUG_LEVEL (DEBUG_POOL|DEBUG_PAGE)
-
-typedef struct {
- UINT32 TailMark;
- UINT32 HeadMark;
- EFI_PHYSICAL_ADDRESS Address;
- LIST_ENTRY Link;
-} HEAP_GUARD_NODE;
-
-/**
- Set head Guard and tail Guard for the given memory range.
-
- @param[in] Memory Base address of memory to set guard for.
- @param[in] NumberOfPages Memory size in pages.
-
- @return VOID.
-**/
-VOID
-SetGuardForMemory (
- IN EFI_PHYSICAL_ADDRESS Memory,
- IN UINTN NumberOfPages
- );
-
-/**
- Unset head Guard and tail Guard for the given memory range.
-
- @param[in] Memory Base address of memory to unset guard for.
- @param[in] NumberOfPages Memory size in pages.
-
- @return VOID.
-**/
-VOID
-UnsetGuardForMemory (
- IN EFI_PHYSICAL_ADDRESS Memory,
- IN UINTN NumberOfPages
- );
-
-/**
- Adjust the base and number of pages to really allocate according to Guard.
-
- @param[in,out] Memory Base address of free memory.
- @param[in,out] NumberOfPages Size of memory to allocate.
-
- @return VOID.
-**/
-VOID
-AdjustMemoryA (
- IN OUT EFI_PHYSICAL_ADDRESS *Memory,
- IN OUT UINTN *NumberOfPages
- );
-
-/**
- Adjust the start address and number of pages to free according to Guard.
-
- The purpose of this function is to keep the shared Guard page with adjacent
- memory block if it's still in guard, or free it if no more sharing. Another
- is to reserve pages as Guard pages in partial page free situation.
-
- @param[in,out] Memory Base address of memory to free.
- @param[in,out] NumberOfPages Size of memory to free.
-
- @return VOID.
-**/
-VOID
-AdjustMemoryF (
- IN OUT EFI_PHYSICAL_ADDRESS *Memory,
- IN OUT UINTN *NumberOfPages
- );
-
-/**
- Check to see if the pool at the given address should be guarded or not.
-
- @param[in] MemoryType Pool type to check.
-
-
- @return TRUE The given type of pool should be guarded.
- @return FALSE The given type of pool should not be guarded.
-**/
-BOOLEAN
-IsPoolTypeToGuard (
- IN EFI_MEMORY_TYPE MemoryType
- );
-
-/**
- Check to see if the page at the given address should be guarded or not.
-
- @param[in] MemoryType Page type to check.
- @param[in] AllocateType Allocation type to check.
-
- @return TRUE The given type of page should be guarded.
- @return FALSE The given type of page should not be guarded.
-**/
-BOOLEAN
-IsPageTypeToGuard (
- IN EFI_MEMORY_TYPE MemoryType,
- IN EFI_ALLOCATE_TYPE AllocateType
- );
-
-/**
- Check to see if the page at the given address is guarded or not.
-
- @param[in] Address The address to check for.
-
- @return TRUE The page at Address is guarded.
- @return FALSE The page at Address is not guarded.
-**/
-BOOLEAN
-EFIAPI
-IsMemoryGuarded (
- IN EFI_PHYSICAL_ADDRESS Address
- );
-
-/**
- Check to see if the page at the given address is a Guard page or not.
-
- @param[in] Address The address to check for.
-
- @return TRUE The page at Address is a Guard page.
- @return FALSE The page at Address is not a Guard page.
-**/
-BOOLEAN
-EFIAPI
-IsGuardPage (
- IN EFI_PHYSICAL_ADDRESS Address
- );
-
-/**
- Dump the guarded memory bit map.
-**/
-VOID
-EFIAPI
-DumpGuardedMemoryBitmap (
- VOID
- );
-
-/**
- Adjust the pool head position to make sure the Guard page is adjavent to
- pool tail or pool head.
-
- @param[in] Memory Base address of memory allocated.
- @param[in] NoPages Number of pages actually allocated.
- @param[in] Size Size of memory requested.
- (plus pool head/tail overhead)
-
- @return Address of pool head.
-**/
-VOID *
-AdjustPoolHeadA (
- IN EFI_PHYSICAL_ADDRESS Memory,
- IN UINTN NoPages,
- IN UINTN Size
- );
-
-/**
- Get the page base address according to pool head address.
-
- @param[in] Memory Head address of pool to free.
-
- @return Address of pool head.
-**/
-VOID *
-AdjustPoolHeadF (
- IN EFI_PHYSICAL_ADDRESS Memory
- );
-
-/**
- Helper function of memory allocation with Guard pages.
-
- @param FreePageList The free page node.
- @param NumberOfPages Number of pages to be allocated.
- @param MaxAddress Request to allocate memory below this address.
- @param MemoryType Type of memory requested.
-
- @return Memory address of allocated pages.
-**/
-UINTN
-InternalAllocMaxAddressWithGuard (
- IN OUT LIST_ENTRY *FreePageList,
- IN UINTN NumberOfPages,
- IN UINTN MaxAddress,
- IN EFI_MEMORY_TYPE MemoryType
- );
-
-/**
- Helper function of memory free with Guard pages.
-
- @param[in] Memory Base address of memory being freed.
- @param[in] NumberOfPages The number of pages to free.
- @param[in] AddRegion If this memory is new added region.
-
- @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
-SmmInternalFreePagesExWithGuard (
- IN EFI_PHYSICAL_ADDRESS Memory,
- IN UINTN NumberOfPages,
- IN BOOLEAN AddRegion
- );
-
-/**
- Check to see if the heap guard is enabled for page and/or pool allocation.
-
- @return TRUE/FALSE.
-**/
-BOOLEAN
-IsHeapGuardEnabled (
- VOID
- );
-
-/**
- Debug function used to verify if the Guard page is well set or not.
-
- @param[in] BaseAddress Address of memory to check.
- @param[in] NumberOfPages Size of memory in pages.
-
- @return TRUE The head Guard and tail Guard are both well set.
- @return FALSE The head Guard and/or tail Guard are not well set.
-**/
-BOOLEAN
-VerifyMemoryGuard (
- IN EFI_PHYSICAL_ADDRESS BaseAddress,
- IN UINTN NumberOfPages
- );
-
-extern BOOLEAN mOnGuarding;
-
-#endif
+/** @file + Data structure and functions to allocate and free memory space. + +Copyright (c) 2017, Intel Corporation. All rights reserved.<BR> +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef _HEAPGUARD_H_ +#define _HEAPGUARD_H_ + +#include "PiSmmCore.h" + +// +// Following macros are used to define and access the guarded memory bitmap +// table. +// +// To simplify the access and reduce the memory used for this table, the +// table is constructed in the similar way as page table structure but in +// reverse direction, i.e. from bottom growing up to top. +// +// - 1-bit tracks 1 page (4KB) +// - 1-UINT64 map entry tracks 256KB memory +// - 1K-UINT64 map table tracks 256MB memory +// - Five levels of tables can track any address of memory of 64-bit +// system, like below. +// +// 512 * 512 * 512 * 512 * 1K * 64b * 4K +// 111111111 111111111 111111111 111111111 1111111111 111111 111111111111 +// 63 54 45 36 27 17 11 0 +// 9b 9b 9b 9b 10b 6b 12b +// L0 -> L1 -> L2 -> L3 -> L4 -> bits -> page +// 1FF 1FF 1FF 1FF 3FF 3F FFF +// +// L4 table has 1K * sizeof(UINT64) = 8K (2-page), which can track 256MB +// memory. Each table of L0-L3 will be allocated when its memory address +// range is to be tracked. Only 1-page will be allocated each time. This +// can save memories used to establish this map table. +// +// For a normal configuration of system with 4G memory, two levels of tables +// can track the whole memory, because two levels (L3+L4) of map tables have +// already covered 37-bit of memory address. And for a normal UEFI BIOS, +// less than 128M memory would be consumed during boot. That means we just +// need +// +// 1-page (L3) + 2-page (L4) +// +// memory (3 pages) to track the memory allocation works. In this case, +// there's no need to setup L0-L2 tables. +// + +// +// Each entry occupies 8B/64b. 1-page can hold 512 entries, which spans 9 +// bits in address. (512 = 1 << 9) +// +#define BYTE_LENGTH_SHIFT 3 // (8 = 1 << 3) + +#define GUARDED_HEAP_MAP_TABLE_ENTRY_SHIFT \ + (EFI_PAGE_SHIFT - BYTE_LENGTH_SHIFT) + +#define GUARDED_HEAP_MAP_TABLE_DEPTH 5 + +// Use UINT64_index + bit_index_of_UINT64 to locate the bit in may +#define GUARDED_HEAP_MAP_ENTRY_BIT_SHIFT 6 // (64 = 1 << 6) + +#define GUARDED_HEAP_MAP_ENTRY_BITS \ + (1 << GUARDED_HEAP_MAP_ENTRY_BIT_SHIFT) + +#define GUARDED_HEAP_MAP_ENTRY_BYTES \ + (GUARDED_HEAP_MAP_ENTRY_BITS / 8) + +// L4 table address width: 64 - 9 * 4 - 6 - 12 = 10b +#define GUARDED_HEAP_MAP_ENTRY_SHIFT \ + (GUARDED_HEAP_MAP_ENTRY_BITS \ + - GUARDED_HEAP_MAP_TABLE_ENTRY_SHIFT * 4 \ + - GUARDED_HEAP_MAP_ENTRY_BIT_SHIFT \ + - EFI_PAGE_SHIFT) + +// L4 table address mask: (1 << 10 - 1) = 0x3FF +#define GUARDED_HEAP_MAP_ENTRY_MASK \ + ((1 << GUARDED_HEAP_MAP_ENTRY_SHIFT) - 1) + +// Size of each L4 table: (1 << 10) * 8 = 8KB = 2-page +#define GUARDED_HEAP_MAP_SIZE \ + ((1 << GUARDED_HEAP_MAP_ENTRY_SHIFT) * GUARDED_HEAP_MAP_ENTRY_BYTES) + +// Memory size tracked by one L4 table: 8KB * 8 * 4KB = 256MB +#define GUARDED_HEAP_MAP_UNIT_SIZE \ + (GUARDED_HEAP_MAP_SIZE * 8 * EFI_PAGE_SIZE) + +// L4 table entry number: 8KB / 8 = 1024 +#define GUARDED_HEAP_MAP_ENTRIES_PER_UNIT \ + (GUARDED_HEAP_MAP_SIZE / GUARDED_HEAP_MAP_ENTRY_BYTES) + +// L4 table entry indexing +#define GUARDED_HEAP_MAP_ENTRY_INDEX(Address) \ + (RShiftU64 (Address, EFI_PAGE_SHIFT \ + + GUARDED_HEAP_MAP_ENTRY_BIT_SHIFT) \ + & GUARDED_HEAP_MAP_ENTRY_MASK) + +// L4 table entry bit indexing +#define GUARDED_HEAP_MAP_ENTRY_BIT_INDEX(Address) \ + (RShiftU64 (Address, EFI_PAGE_SHIFT) \ + & ((1 << GUARDED_HEAP_MAP_ENTRY_BIT_SHIFT) - 1)) + +// +// Total bits (pages) tracked by one L4 table (65536-bit) +// +#define GUARDED_HEAP_MAP_BITS \ + (1 << (GUARDED_HEAP_MAP_ENTRY_SHIFT \ + + GUARDED_HEAP_MAP_ENTRY_BIT_SHIFT)) + +// +// Bit indexing inside the whole L4 table (0 - 65535) +// +#define GUARDED_HEAP_MAP_BIT_INDEX(Address) \ + (RShiftU64 (Address, EFI_PAGE_SHIFT) \ + & ((1 << (GUARDED_HEAP_MAP_ENTRY_SHIFT \ + + GUARDED_HEAP_MAP_ENTRY_BIT_SHIFT)) - 1)) + +// +// Memory address bit width tracked by L4 table: 10 + 6 + 12 = 28 +// +#define GUARDED_HEAP_MAP_TABLE_SHIFT \ + (GUARDED_HEAP_MAP_ENTRY_SHIFT + GUARDED_HEAP_MAP_ENTRY_BIT_SHIFT \ + + EFI_PAGE_SHIFT) + +// +// Macro used to initialize the local array variable for map table traversing +// {55, 46, 37, 28, 18} +// +#define GUARDED_HEAP_MAP_TABLE_DEPTH_SHIFTS \ + { \ + GUARDED_HEAP_MAP_TABLE_SHIFT + GUARDED_HEAP_MAP_TABLE_ENTRY_SHIFT * 3, \ + GUARDED_HEAP_MAP_TABLE_SHIFT + GUARDED_HEAP_MAP_TABLE_ENTRY_SHIFT * 2, \ + GUARDED_HEAP_MAP_TABLE_SHIFT + GUARDED_HEAP_MAP_TABLE_ENTRY_SHIFT, \ + GUARDED_HEAP_MAP_TABLE_SHIFT, \ + EFI_PAGE_SHIFT + GUARDED_HEAP_MAP_ENTRY_BIT_SHIFT \ + } + +// +// Masks used to extract address range of each level of table +// {0x1FF, 0x1FF, 0x1FF, 0x1FF, 0x3FF} +// +#define GUARDED_HEAP_MAP_TABLE_DEPTH_MASKS \ + { \ + (1 << GUARDED_HEAP_MAP_TABLE_ENTRY_SHIFT) - 1, \ + (1 << GUARDED_HEAP_MAP_TABLE_ENTRY_SHIFT) - 1, \ + (1 << GUARDED_HEAP_MAP_TABLE_ENTRY_SHIFT) - 1, \ + (1 << GUARDED_HEAP_MAP_TABLE_ENTRY_SHIFT) - 1, \ + (1 << GUARDED_HEAP_MAP_ENTRY_SHIFT) - 1 \ + } + +// +// Memory type to guard (matching the related PCD definition) +// +#define GUARD_HEAP_TYPE_PAGE BIT2 +#define GUARD_HEAP_TYPE_POOL BIT3 + +// +// Debug message level +// +#define HEAP_GUARD_DEBUG_LEVEL (DEBUG_POOL|DEBUG_PAGE) + +typedef struct { + UINT32 TailMark; + UINT32 HeadMark; + EFI_PHYSICAL_ADDRESS Address; + LIST_ENTRY Link; +} HEAP_GUARD_NODE; + +/** + Set head Guard and tail Guard for the given memory range. + + @param[in] Memory Base address of memory to set guard for. + @param[in] NumberOfPages Memory size in pages. + + @return VOID. +**/ +VOID +SetGuardForMemory ( + IN EFI_PHYSICAL_ADDRESS Memory, + IN UINTN NumberOfPages + ); + +/** + Unset head Guard and tail Guard for the given memory range. + + @param[in] Memory Base address of memory to unset guard for. + @param[in] NumberOfPages Memory size in pages. + + @return VOID. +**/ +VOID +UnsetGuardForMemory ( + IN EFI_PHYSICAL_ADDRESS Memory, + IN UINTN NumberOfPages + ); + +/** + Adjust the base and number of pages to really allocate according to Guard. + + @param[in,out] Memory Base address of free memory. + @param[in,out] NumberOfPages Size of memory to allocate. + + @return VOID. +**/ +VOID +AdjustMemoryA ( + IN OUT EFI_PHYSICAL_ADDRESS *Memory, + IN OUT UINTN *NumberOfPages + ); + +/** + Adjust the start address and number of pages to free according to Guard. + + The purpose of this function is to keep the shared Guard page with adjacent + memory block if it's still in guard, or free it if no more sharing. Another + is to reserve pages as Guard pages in partial page free situation. + + @param[in,out] Memory Base address of memory to free. + @param[in,out] NumberOfPages Size of memory to free. + + @return VOID. +**/ +VOID +AdjustMemoryF ( + IN OUT EFI_PHYSICAL_ADDRESS *Memory, + IN OUT UINTN *NumberOfPages + ); + +/** + Check to see if the pool at the given address should be guarded or not. + + @param[in] MemoryType Pool type to check. + + + @return TRUE The given type of pool should be guarded. + @return FALSE The given type of pool should not be guarded. +**/ +BOOLEAN +IsPoolTypeToGuard ( + IN EFI_MEMORY_TYPE MemoryType + ); + +/** + Check to see if the page at the given address should be guarded or not. + + @param[in] MemoryType Page type to check. + @param[in] AllocateType Allocation type to check. + + @return TRUE The given type of page should be guarded. + @return FALSE The given type of page should not be guarded. +**/ +BOOLEAN +IsPageTypeToGuard ( + IN EFI_MEMORY_TYPE MemoryType, + IN EFI_ALLOCATE_TYPE AllocateType + ); + +/** + Check to see if the page at the given address is guarded or not. + + @param[in] Address The address to check for. + + @return TRUE The page at Address is guarded. + @return FALSE The page at Address is not guarded. +**/ +BOOLEAN +EFIAPI +IsMemoryGuarded ( + IN EFI_PHYSICAL_ADDRESS Address + ); + +/** + Check to see if the page at the given address is a Guard page or not. + + @param[in] Address The address to check for. + + @return TRUE The page at Address is a Guard page. + @return FALSE The page at Address is not a Guard page. +**/ +BOOLEAN +EFIAPI +IsGuardPage ( + IN EFI_PHYSICAL_ADDRESS Address + ); + +/** + Dump the guarded memory bit map. +**/ +VOID +EFIAPI +DumpGuardedMemoryBitmap ( + VOID + ); + +/** + Adjust the pool head position to make sure the Guard page is adjavent to + pool tail or pool head. + + @param[in] Memory Base address of memory allocated. + @param[in] NoPages Number of pages actually allocated. + @param[in] Size Size of memory requested. + (plus pool head/tail overhead) + + @return Address of pool head. +**/ +VOID * +AdjustPoolHeadA ( + IN EFI_PHYSICAL_ADDRESS Memory, + IN UINTN NoPages, + IN UINTN Size + ); + +/** + Get the page base address according to pool head address. + + @param[in] Memory Head address of pool to free. + + @return Address of pool head. +**/ +VOID * +AdjustPoolHeadF ( + IN EFI_PHYSICAL_ADDRESS Memory + ); + +/** + Helper function of memory allocation with Guard pages. + + @param FreePageList The free page node. + @param NumberOfPages Number of pages to be allocated. + @param MaxAddress Request to allocate memory below this address. + @param MemoryType Type of memory requested. + + @return Memory address of allocated pages. +**/ +UINTN +InternalAllocMaxAddressWithGuard ( + IN OUT LIST_ENTRY *FreePageList, + IN UINTN NumberOfPages, + IN UINTN MaxAddress, + IN EFI_MEMORY_TYPE MemoryType + ); + +/** + Helper function of memory free with Guard pages. + + @param[in] Memory Base address of memory being freed. + @param[in] NumberOfPages The number of pages to free. + @param[in] AddRegion If this memory is new added region. + + @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 +SmmInternalFreePagesExWithGuard ( + IN EFI_PHYSICAL_ADDRESS Memory, + IN UINTN NumberOfPages, + IN BOOLEAN AddRegion + ); + +/** + Check to see if the heap guard is enabled for page and/or pool allocation. + + @return TRUE/FALSE. +**/ +BOOLEAN +IsHeapGuardEnabled ( + VOID + ); + +/** + Debug function used to verify if the Guard page is well set or not. + + @param[in] BaseAddress Address of memory to check. + @param[in] NumberOfPages Size of memory in pages. + + @return TRUE The head Guard and tail Guard are both well set. + @return FALSE The head Guard and/or tail Guard are not well set. +**/ +BOOLEAN +VerifyMemoryGuard ( + IN EFI_PHYSICAL_ADDRESS BaseAddress, + IN UINTN NumberOfPages + ); + +extern BOOLEAN mOnGuarding; + +#endif diff --git a/MdeModulePkg/Core/PiSmmCore/InstallConfigurationTable.c b/MdeModulePkg/Core/PiSmmCore/InstallConfigurationTable.c index 0bc51be12b..452e1264b7 100644 --- a/MdeModulePkg/Core/PiSmmCore/InstallConfigurationTable.c +++ b/MdeModulePkg/Core/PiSmmCore/InstallConfigurationTable.c @@ -1,170 +1,170 @@ -/** @file
- System Management System Table Services SmmInstallConfigurationTable service
-
- Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.<BR>
- SPDX-License-Identifier: BSD-2-Clause-Patent
-
-**/
-
-#include "PiSmmCore.h"
-
-#define CONFIG_TABLE_SIZE_INCREASED 0x10
-
-UINTN mSmmSystemTableAllocateSize = 0;
-
-/**
- The SmmInstallConfigurationTable() 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
-SmmInstallConfigurationTable (
- IN CONST EFI_SMM_SYSTEM_TABLE2 *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 = gSmmCoreSmst.SmmConfigurationTable;
-
- //
- // Search all the table for an entry that matches Guid
- //
- for (Index = 0; Index < gSmmCoreSmst.NumberOfTableEntries; Index++) {
- if (CompareGuid (Guid, &(ConfigurationTable[Index].VendorGuid))) {
- break;
- }
- }
-
- if (Index < gSmmCoreSmst.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.
- //
- gSmmCoreSmst.NumberOfTableEntries--;
-
- //
- // Copy over deleted entry
- //
- CopyMem (
- &(ConfigurationTable[Index]),
- &(ConfigurationTable[Index + 1]),
- (gSmmCoreSmst.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 == gSmmCoreSmst.NumberOfTableEntries
- //
- if ((Index * sizeof (EFI_CONFIGURATION_TABLE)) >= mSmmSystemTableAllocateSize) {
- //
- // Allocate a table with one additional entry.
- //
- mSmmSystemTableAllocateSize += (CONFIG_TABLE_SIZE_INCREASED * sizeof (EFI_CONFIGURATION_TABLE));
- ConfigurationTable = AllocatePool (mSmmSystemTableAllocateSize);
- if (ConfigurationTable == NULL) {
- //
- // If a new table could not be allocated, then return an error.
- //
- return EFI_OUT_OF_RESOURCES;
- }
-
- if (gSmmCoreSmst.SmmConfigurationTable != NULL) {
- //
- // Copy the old table to the new table.
- //
- CopyMem (
- ConfigurationTable,
- gSmmCoreSmst.SmmConfigurationTable,
- Index * sizeof (EFI_CONFIGURATION_TABLE)
- );
-
- //
- // Record the old table pointer.
- //
- OldTable = gSmmCoreSmst.SmmConfigurationTable;
-
- //
- // As the SmmInstallConfigurationTable() 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 gSmmCoreSmst.SmmConfigurationTable point to the new
- // table and avoid the errors of use-after-free to the old table by the
- // reenter of SmmInstallConfigurationTable() in FreePool()'s calling stack.
- //
- gSmmCoreSmst.SmmConfigurationTable = ConfigurationTable;
-
- //
- // Free the old table after updating System Table to the new table pointer.
- //
- FreePool (OldTable);
- } else {
- //
- // Update System Table
- //
- gSmmCoreSmst.SmmConfigurationTable = 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
- //
- gSmmCoreSmst.NumberOfTableEntries++;
- }
-
- //
- // CRC-32 field is ignorable for SMM System Table and should be set to zero
- //
-
- return EFI_SUCCESS;
-}
+/** @file + System Management System Table Services SmmInstallConfigurationTable service + + Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.<BR> + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "PiSmmCore.h" + +#define CONFIG_TABLE_SIZE_INCREASED 0x10 + +UINTN mSmmSystemTableAllocateSize = 0; + +/** + The SmmInstallConfigurationTable() 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 +SmmInstallConfigurationTable ( + IN CONST EFI_SMM_SYSTEM_TABLE2 *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 = gSmmCoreSmst.SmmConfigurationTable; + + // + // Search all the table for an entry that matches Guid + // + for (Index = 0; Index < gSmmCoreSmst.NumberOfTableEntries; Index++) { + if (CompareGuid (Guid, &(ConfigurationTable[Index].VendorGuid))) { + break; + } + } + + if (Index < gSmmCoreSmst.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. + // + gSmmCoreSmst.NumberOfTableEntries--; + + // + // Copy over deleted entry + // + CopyMem ( + &(ConfigurationTable[Index]), + &(ConfigurationTable[Index + 1]), + (gSmmCoreSmst.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 == gSmmCoreSmst.NumberOfTableEntries + // + if ((Index * sizeof (EFI_CONFIGURATION_TABLE)) >= mSmmSystemTableAllocateSize) { + // + // Allocate a table with one additional entry. + // + mSmmSystemTableAllocateSize += (CONFIG_TABLE_SIZE_INCREASED * sizeof (EFI_CONFIGURATION_TABLE)); + ConfigurationTable = AllocatePool (mSmmSystemTableAllocateSize); + if (ConfigurationTable == NULL) { + // + // If a new table could not be allocated, then return an error. + // + return EFI_OUT_OF_RESOURCES; + } + + if (gSmmCoreSmst.SmmConfigurationTable != NULL) { + // + // Copy the old table to the new table. + // + CopyMem ( + ConfigurationTable, + gSmmCoreSmst.SmmConfigurationTable, + Index * sizeof (EFI_CONFIGURATION_TABLE) + ); + + // + // Record the old table pointer. + // + OldTable = gSmmCoreSmst.SmmConfigurationTable; + + // + // As the SmmInstallConfigurationTable() 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 gSmmCoreSmst.SmmConfigurationTable point to the new + // table and avoid the errors of use-after-free to the old table by the + // reenter of SmmInstallConfigurationTable() in FreePool()'s calling stack. + // + gSmmCoreSmst.SmmConfigurationTable = ConfigurationTable; + + // + // Free the old table after updating System Table to the new table pointer. + // + FreePool (OldTable); + } else { + // + // Update System Table + // + gSmmCoreSmst.SmmConfigurationTable = 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 + // + gSmmCoreSmst.NumberOfTableEntries++; + } + + // + // CRC-32 field is ignorable for SMM System Table and should be set to zero + // + + return EFI_SUCCESS; +} diff --git a/MdeModulePkg/Core/PiSmmCore/Locate.c b/MdeModulePkg/Core/PiSmmCore/Locate.c index 2d55362580..07c3c1869c 100644 --- a/MdeModulePkg/Core/PiSmmCore/Locate.c +++ b/MdeModulePkg/Core/PiSmmCore/Locate.c @@ -1,497 +1,497 @@ -/** @file
- Locate handle functions
-
- Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.<BR>
- SPDX-License-Identifier: BSD-2-Clause-Patent
-
-**/
-
-#include "PiSmmCore.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 search 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 *
-SmmGetNextLocateAllHandles (
- 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 search 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 *
-SmmGetNextLocateByRegisterNotify (
- 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 search 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 *
-SmmGetNextLocateByProtocol (
- 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 Registration is NULL return the first Protocol Interface
- you find.
-
- @param Protocol The protocol to search for
- @param Registration Optional Registration Key returned from
- RegisterProtocolNotify()
- @param Interface Return the Protocol interface (instance).
-
- @retval EFI_SUCCESS If a valid Interface is returned
- @retval EFI_INVALID_PARAMETER Invalid parameter
- @retval EFI_NOT_FOUND Protocol interface not found
-
-**/
-EFI_STATUS
-EFIAPI
-SmmLocateProtocol (
- 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 = SmmFindProtocolEntry (Protocol, FALSE);
- if (Position.ProtEntry == NULL) {
- return EFI_NOT_FOUND;
- }
-
- Position.Position = &Position.ProtEntry->Protocols;
-
- Handle = SmmGetNextLocateByProtocol (&Position, Interface);
- } else {
- Handle = SmmGetNextLocateByRegisterNotify (&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
-SmmLocateHandle (
- 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 = SmmGetNextLocateAllHandles;
- break;
-
- case ByRegisterNotify:
- GetNext = SmmGetNextLocateByRegisterNotify;
- //
- // Must have SearchKey for locate ByRegisterNotify
- //
- if (SearchKey == NULL) {
- Status = EFI_INVALID_PARAMETER;
- }
-
- break;
-
- case ByProtocol:
- GetNext = SmmGetNextLocateByProtocol;
- if (Protocol == NULL) {
- Status = EFI_INVALID_PARAMETER;
- break;
- }
-
- //
- // Look up the protocol entry and set the head pointer
- //
- Position.ProtEntry = SmmFindProtocolEntry (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 SmmLocateHandle()
- 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
-SmmLocateHandleBuffer (
- 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 = SmmLocateHandle (
- SearchType,
- Protocol,
- SearchKey,
- &BufferSize,
- *Buffer
- );
- //
- // LocateHandleBuffer() returns incorrect status code if SearchType is
- // invalid.
- //
- // Add code to correctly handle expected errors from SmmLocateHandle().
- //
- 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 = SmmLocateHandle (
- SearchType,
- Protocol,
- SearchKey,
- &BufferSize,
- *Buffer
- );
-
- *NumberHandles = BufferSize / sizeof (EFI_HANDLE);
- if (EFI_ERROR (Status)) {
- *NumberHandles = 0;
- }
-
- return Status;
-}
+/** @file + Locate handle functions + + Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.<BR> + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "PiSmmCore.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 search 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 * +SmmGetNextLocateAllHandles ( + 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 search 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 * +SmmGetNextLocateByRegisterNotify ( + 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 search 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 * +SmmGetNextLocateByProtocol ( + 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 Registration is NULL return the first Protocol Interface + you find. + + @param Protocol The protocol to search for + @param Registration Optional Registration Key returned from + RegisterProtocolNotify() + @param Interface Return the Protocol interface (instance). + + @retval EFI_SUCCESS If a valid Interface is returned + @retval EFI_INVALID_PARAMETER Invalid parameter + @retval EFI_NOT_FOUND Protocol interface not found + +**/ +EFI_STATUS +EFIAPI +SmmLocateProtocol ( + 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 = SmmFindProtocolEntry (Protocol, FALSE); + if (Position.ProtEntry == NULL) { + return EFI_NOT_FOUND; + } + + Position.Position = &Position.ProtEntry->Protocols; + + Handle = SmmGetNextLocateByProtocol (&Position, Interface); + } else { + Handle = SmmGetNextLocateByRegisterNotify (&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 +SmmLocateHandle ( + 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 = SmmGetNextLocateAllHandles; + break; + + case ByRegisterNotify: + GetNext = SmmGetNextLocateByRegisterNotify; + // + // Must have SearchKey for locate ByRegisterNotify + // + if (SearchKey == NULL) { + Status = EFI_INVALID_PARAMETER; + } + + break; + + case ByProtocol: + GetNext = SmmGetNextLocateByProtocol; + if (Protocol == NULL) { + Status = EFI_INVALID_PARAMETER; + break; + } + + // + // Look up the protocol entry and set the head pointer + // + Position.ProtEntry = SmmFindProtocolEntry (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 SmmLocateHandle() + 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 +SmmLocateHandleBuffer ( + 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 = SmmLocateHandle ( + SearchType, + Protocol, + SearchKey, + &BufferSize, + *Buffer + ); + // + // LocateHandleBuffer() returns incorrect status code if SearchType is + // invalid. + // + // Add code to correctly handle expected errors from SmmLocateHandle(). + // + 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 = SmmLocateHandle ( + SearchType, + Protocol, + SearchKey, + &BufferSize, + *Buffer + ); + + *NumberHandles = BufferSize / sizeof (EFI_HANDLE); + if (EFI_ERROR (Status)) { + *NumberHandles = 0; + } + + return Status; +} diff --git a/MdeModulePkg/Core/PiSmmCore/MemoryAttributesTable.c b/MdeModulePkg/Core/PiSmmCore/MemoryAttributesTable.c index 28fe74ecc4..f84ca5011d 100644 --- a/MdeModulePkg/Core/PiSmmCore/MemoryAttributesTable.c +++ b/MdeModulePkg/Core/PiSmmCore/MemoryAttributesTable.c @@ -1,533 +1,533 @@ -/** @file
- PI SMM MemoryAttributes support
-
-Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>
-SPDX-License-Identifier: BSD-2-Clause-Patent
-
-**/
-
-#include <PiDxe.h>
-#include <Library/BaseLib.h>
-#include <Library/BaseMemoryLib.h>
-#include <Library/MemoryAllocationLib.h>
-#include <Library/UefiBootServicesTableLib.h>
-#include <Library/SmmServicesTableLib.h>
-#include <Library/DebugLib.h>
-#include <Library/PcdLib.h>
-#include <Library/ImagePropertiesRecordLib.h>
-
-#include <Library/PeCoffLib.h>
-#include <Library/PeCoffGetEntryPointLib.h>
-
-#include <Guid/PiSmmMemoryAttributesTable.h>
-
-#include "PiSmmCore.h"
-
-#define PREVIOUS_MEMORY_DESCRIPTOR(MemoryDescriptor, Size) \
- ((EFI_MEMORY_DESCRIPTOR *)((UINT8 *)(MemoryDescriptor) - (Size)))
-
-#define IMAGE_PROPERTIES_PRIVATE_DATA_SIGNATURE SIGNATURE_32 ('I','P','P','D')
-
-typedef struct {
- UINT32 Signature;
- UINTN ImageRecordCount;
- UINTN CodeSegmentCountMax;
- LIST_ENTRY ImageRecordList;
-} IMAGE_PROPERTIES_PRIVATE_DATA;
-
-IMAGE_PROPERTIES_PRIVATE_DATA mImagePropertiesPrivateData = {
- IMAGE_PROPERTIES_PRIVATE_DATA_SIGNATURE,
- 0,
- 0,
- INITIALIZE_LIST_HEAD_VARIABLE (mImagePropertiesPrivateData.ImageRecordList)
-};
-
-#define EFI_MEMORY_ATTRIBUTES_RUNTIME_MEMORY_PROTECTION_NON_EXECUTABLE_PE_DATA BIT0
-
-UINT64 mMemoryProtectionAttribute = EFI_MEMORY_ATTRIBUTES_RUNTIME_MEMORY_PROTECTION_NON_EXECUTABLE_PE_DATA;
-
-//
-// Below functions are for MemoryMap
-//
-
-/**
- Merge continuous memory map entries whose have same attributes.
-
- @param[in, out] MemoryMap A pointer to the buffer in which firmware places
- the current memory map.
- @param[in, out] MemoryMapSize A pointer to the size, in bytes, of the
- MemoryMap buffer. On input, this is the size of
- the current memory map. On output,
- it is the size of new memory map after merge.
- @param[in] DescriptorSize Size, in bytes, of an individual EFI_MEMORY_DESCRIPTOR.
-**/
-STATIC
-VOID
-MergeMemoryMap (
- IN OUT EFI_MEMORY_DESCRIPTOR *MemoryMap,
- IN OUT UINTN *MemoryMapSize,
- IN UINTN DescriptorSize
- )
-{
- EFI_MEMORY_DESCRIPTOR *MemoryMapEntry;
- EFI_MEMORY_DESCRIPTOR *MemoryMapEnd;
- UINT64 MemoryBlockLength;
- EFI_MEMORY_DESCRIPTOR *NewMemoryMapEntry;
- EFI_MEMORY_DESCRIPTOR *NextMemoryMapEntry;
-
- MemoryMapEntry = MemoryMap;
- NewMemoryMapEntry = MemoryMap;
- MemoryMapEnd = (EFI_MEMORY_DESCRIPTOR *)((UINT8 *)MemoryMap + *MemoryMapSize);
- while ((UINTN)MemoryMapEntry < (UINTN)MemoryMapEnd) {
- CopyMem (NewMemoryMapEntry, MemoryMapEntry, sizeof (EFI_MEMORY_DESCRIPTOR));
- NextMemoryMapEntry = NEXT_MEMORY_DESCRIPTOR (MemoryMapEntry, DescriptorSize);
-
- do {
- MemoryBlockLength = LShiftU64 (MemoryMapEntry->NumberOfPages, EFI_PAGE_SHIFT);
- if (((UINTN)NextMemoryMapEntry < (UINTN)MemoryMapEnd) &&
- (MemoryMapEntry->Type == NextMemoryMapEntry->Type) &&
- (MemoryMapEntry->Attribute == NextMemoryMapEntry->Attribute) &&
- ((MemoryMapEntry->PhysicalStart + MemoryBlockLength) == NextMemoryMapEntry->PhysicalStart))
- {
- MemoryMapEntry->NumberOfPages += NextMemoryMapEntry->NumberOfPages;
- if (NewMemoryMapEntry != MemoryMapEntry) {
- NewMemoryMapEntry->NumberOfPages += NextMemoryMapEntry->NumberOfPages;
- }
-
- NextMemoryMapEntry = NEXT_MEMORY_DESCRIPTOR (NextMemoryMapEntry, DescriptorSize);
- continue;
- } else {
- MemoryMapEntry = PREVIOUS_MEMORY_DESCRIPTOR (NextMemoryMapEntry, DescriptorSize);
- break;
- }
- } while (TRUE);
-
- MemoryMapEntry = NEXT_MEMORY_DESCRIPTOR (MemoryMapEntry, DescriptorSize);
- NewMemoryMapEntry = NEXT_MEMORY_DESCRIPTOR (NewMemoryMapEntry, DescriptorSize);
- }
-
- *MemoryMapSize = (UINTN)NewMemoryMapEntry - (UINTN)MemoryMap;
-
- return;
-}
-
-/**
- Enforce memory map attributes.
- This function will set EfiRuntimeServicesData/EfiMemoryMappedIO/EfiMemoryMappedIOPortSpace to be EFI_MEMORY_XP.
-
- @param[in, out] MemoryMap A pointer to the buffer in which firmware places
- the current memory map.
- @param[in] MemoryMapSize Size, in bytes, of the MemoryMap buffer.
- @param[in] DescriptorSize Size, in bytes, of an individual EFI_MEMORY_DESCRIPTOR.
-**/
-STATIC
-VOID
-EnforceMemoryMapAttribute (
- IN OUT EFI_MEMORY_DESCRIPTOR *MemoryMap,
- IN UINTN MemoryMapSize,
- IN UINTN DescriptorSize
- )
-{
- EFI_MEMORY_DESCRIPTOR *MemoryMapEntry;
- EFI_MEMORY_DESCRIPTOR *MemoryMapEnd;
-
- MemoryMapEntry = MemoryMap;
- MemoryMapEnd = (EFI_MEMORY_DESCRIPTOR *)((UINT8 *)MemoryMap + MemoryMapSize);
- while ((UINTN)MemoryMapEntry < (UINTN)MemoryMapEnd) {
- if (MemoryMapEntry->Attribute != 0) {
- // It is PE image, the attribute is already set.
- } else {
- switch (MemoryMapEntry->Type) {
- case EfiRuntimeServicesCode:
- MemoryMapEntry->Attribute = EFI_MEMORY_RO;
- break;
- case EfiRuntimeServicesData:
- default:
- MemoryMapEntry->Attribute |= EFI_MEMORY_XP;
- break;
- }
- }
-
- MemoryMapEntry = NEXT_MEMORY_DESCRIPTOR (MemoryMapEntry, DescriptorSize);
- }
-
- return;
-}
-
-/**
- This function for GetMemoryMap() with memory attributes table.
-
- It calls original GetMemoryMap() to get the original memory map information. Then
- plus the additional memory map entries for PE Code/Data separation.
-
- @param[in, out] MemoryMapSize A pointer to the size, in bytes, of the
- MemoryMap buffer. On input, this is the size of
- the buffer allocated by the caller. On output,
- it is the size of the buffer returned by the
- firmware if the buffer was large enough, or the
- size of the buffer needed to contain the map if
- the buffer was too small.
- @param[in, out] MemoryMap A pointer to the buffer in which firmware places
- the current memory map.
- @param[out] MapKey A pointer to the location in which firmware
- returns the key for the current memory map.
- @param[out] DescriptorSize A pointer to the location in which firmware
- returns the size, in bytes, of an individual
- EFI_MEMORY_DESCRIPTOR.
- @param[out] DescriptorVersion A pointer to the location in which firmware
- returns the version number associated with the
- EFI_MEMORY_DESCRIPTOR.
-
- @retval EFI_SUCCESS The memory map was returned in the MemoryMap
- buffer.
- @retval EFI_BUFFER_TOO_SMALL The MemoryMap buffer was too small. The current
- buffer size needed to hold the memory map is
- returned in MemoryMapSize.
- @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
-
-**/
-STATIC
-EFI_STATUS
-EFIAPI
-SmmCoreGetMemoryMapMemoryAttributesTable (
- IN OUT UINTN *MemoryMapSize,
- IN OUT EFI_MEMORY_DESCRIPTOR *MemoryMap,
- OUT UINTN *MapKey,
- OUT UINTN *DescriptorSize,
- OUT UINT32 *DescriptorVersion
- )
-{
- EFI_STATUS Status;
- UINTN OldMemoryMapSize;
- UINTN AdditionalRecordCount;
-
- //
- // If PE code/data is not aligned, just return.
- //
- if ((mMemoryProtectionAttribute & EFI_MEMORY_ATTRIBUTES_RUNTIME_MEMORY_PROTECTION_NON_EXECUTABLE_PE_DATA) == 0) {
- return SmmCoreGetMemoryMap (MemoryMapSize, MemoryMap, MapKey, DescriptorSize, DescriptorVersion);
- }
-
- if (MemoryMapSize == NULL) {
- return EFI_INVALID_PARAMETER;
- }
-
- AdditionalRecordCount = (2 * mImagePropertiesPrivateData.CodeSegmentCountMax + 3) * mImagePropertiesPrivateData.ImageRecordCount;
-
- OldMemoryMapSize = *MemoryMapSize;
- Status = SmmCoreGetMemoryMap (MemoryMapSize, MemoryMap, MapKey, DescriptorSize, DescriptorVersion);
- if (Status == EFI_BUFFER_TOO_SMALL) {
- *MemoryMapSize = *MemoryMapSize + (*DescriptorSize) * AdditionalRecordCount;
- } else if (Status == EFI_SUCCESS) {
- if (OldMemoryMapSize - *MemoryMapSize < (*DescriptorSize) * AdditionalRecordCount) {
- *MemoryMapSize = *MemoryMapSize + (*DescriptorSize) * AdditionalRecordCount;
- //
- // Need update status to buffer too small
- //
- Status = EFI_BUFFER_TOO_SMALL;
- } else {
- //
- // Split PE code/data
- //
- ASSERT (MemoryMap != NULL);
- SplitTable (MemoryMapSize, MemoryMap, *DescriptorSize, &mImagePropertiesPrivateData.ImageRecordList, AdditionalRecordCount);
-
- //
- // Set RuntimeData to XP
- //
- EnforceMemoryMapAttribute (MemoryMap, *MemoryMapSize, *DescriptorSize);
-
- //
- // Merge same type to save entry size
- //
- MergeMemoryMap (MemoryMap, MemoryMapSize, *DescriptorSize);
- }
- }
-
- return Status;
-}
-
-//
-// Below functions are for ImageRecord
-//
-
-/**
- Insert image record.
-
- @param[in] DriverEntry Driver information
-**/
-VOID
-SmmInsertImageRecord (
- IN EFI_SMM_DRIVER_ENTRY *DriverEntry
- )
-{
- EFI_STATUS Status;
- IMAGE_PROPERTIES_RECORD *ImageRecord;
- CHAR8 *PdbPointer;
- UINT32 RequiredAlignment;
-
- DEBUG ((DEBUG_VERBOSE, "SMM InsertImageRecord - 0x%x\n", DriverEntry));
-
- ImageRecord = AllocatePool (sizeof (*ImageRecord));
- if (ImageRecord == NULL) {
- return;
- }
-
- InitializeListHead (&ImageRecord->Link);
- InitializeListHead (&ImageRecord->CodeSegmentList);
-
- PdbPointer = PeCoffLoaderGetPdbPointer ((VOID *)(UINTN)DriverEntry->ImageBuffer);
- if (PdbPointer != NULL) {
- DEBUG ((DEBUG_VERBOSE, "SMM Image - %a\n", PdbPointer));
- }
-
- RequiredAlignment = RUNTIME_PAGE_ALLOCATION_GRANULARITY;
- Status = CreateImagePropertiesRecord (
- (VOID *)(UINTN)DriverEntry->ImageBuffer,
- LShiftU64 (DriverEntry->NumberOfPage, EFI_PAGE_SHIFT),
- &RequiredAlignment,
- ImageRecord
- );
-
- if (EFI_ERROR (Status)) {
- if (Status == EFI_ABORTED) {
- mMemoryProtectionAttribute &=
- ~((UINT64)EFI_MEMORY_ATTRIBUTES_RUNTIME_MEMORY_PROTECTION_NON_EXECUTABLE_PE_DATA);
- }
-
- goto Finish;
- }
-
- if (ImageRecord->CodeSegmentCount == 0) {
- mMemoryProtectionAttribute &=
- ~((UINT64)EFI_MEMORY_ATTRIBUTES_RUNTIME_MEMORY_PROTECTION_NON_EXECUTABLE_PE_DATA);
- DEBUG ((DEBUG_ERROR, "SMM !!!!!!!! InsertImageRecord - CodeSegmentCount is 0 !!!!!!!!\n"));
- if (PdbPointer != NULL) {
- DEBUG ((DEBUG_ERROR, "SMM !!!!!!!! Image - %a !!!!!!!!\n", PdbPointer));
- }
-
- Status = EFI_ABORTED;
- goto Finish;
- }
-
- //
- // Check overlap all section in ImageBase/Size
- //
- if (!IsImageRecordCodeSectionValid (ImageRecord)) {
- DEBUG ((DEBUG_ERROR, "SMM IsImageRecordCodeSectionValid - FAIL\n"));
- Status = EFI_ABORTED;
- goto Finish;
- }
-
- InsertTailList (&mImagePropertiesPrivateData.ImageRecordList, &ImageRecord->Link);
- mImagePropertiesPrivateData.ImageRecordCount++;
-
- if (mImagePropertiesPrivateData.CodeSegmentCountMax < ImageRecord->CodeSegmentCount) {
- mImagePropertiesPrivateData.CodeSegmentCountMax = ImageRecord->CodeSegmentCount;
- }
-
- SortImageRecord (&mImagePropertiesPrivateData.ImageRecordList);
-
-Finish:
- if (EFI_ERROR (Status) && (ImageRecord != NULL)) {
- DeleteImagePropertiesRecord (ImageRecord);
- }
-
- return;
-}
-
-/**
- Publish MemoryAttributesTable to SMM configuration table.
-**/
-VOID
-PublishMemoryAttributesTable (
- VOID
- )
-{
- UINTN MemoryMapSize;
- EFI_MEMORY_DESCRIPTOR *MemoryMap;
- UINTN MapKey;
- UINTN DescriptorSize;
- UINT32 DescriptorVersion;
- UINTN Index;
- EFI_STATUS Status;
- UINTN RuntimeEntryCount;
- EDKII_PI_SMM_MEMORY_ATTRIBUTES_TABLE *MemoryAttributesTable;
- EFI_MEMORY_DESCRIPTOR *MemoryAttributesEntry;
- UINTN MemoryAttributesTableSize;
-
- MemoryMapSize = 0;
- MemoryMap = NULL;
- Status = SmmCoreGetMemoryMapMemoryAttributesTable (
- &MemoryMapSize,
- MemoryMap,
- &MapKey,
- &DescriptorSize,
- &DescriptorVersion
- );
- ASSERT (Status == EFI_BUFFER_TOO_SMALL);
-
- do {
- DEBUG ((DEBUG_VERBOSE, "MemoryMapSize - 0x%x\n", MemoryMapSize));
- MemoryMap = AllocatePool (MemoryMapSize);
- ASSERT (MemoryMap != NULL);
- DEBUG ((DEBUG_VERBOSE, "MemoryMap - 0x%x\n", MemoryMap));
-
- Status = SmmCoreGetMemoryMapMemoryAttributesTable (
- &MemoryMapSize,
- MemoryMap,
- &MapKey,
- &DescriptorSize,
- &DescriptorVersion
- );
- if (EFI_ERROR (Status)) {
- FreePool (MemoryMap);
- }
- } while (Status == EFI_BUFFER_TOO_SMALL);
-
- //
- // Allocate MemoryAttributesTable
- //
- RuntimeEntryCount = MemoryMapSize/DescriptorSize;
- MemoryAttributesTableSize = sizeof (EDKII_PI_SMM_MEMORY_ATTRIBUTES_TABLE) + DescriptorSize * RuntimeEntryCount;
- MemoryAttributesTable = AllocatePool (sizeof (EDKII_PI_SMM_MEMORY_ATTRIBUTES_TABLE) + DescriptorSize * RuntimeEntryCount);
- ASSERT (MemoryAttributesTable != NULL);
- MemoryAttributesTable->Version = EDKII_PI_SMM_MEMORY_ATTRIBUTES_TABLE_VERSION;
- MemoryAttributesTable->NumberOfEntries = (UINT32)RuntimeEntryCount;
- MemoryAttributesTable->DescriptorSize = (UINT32)DescriptorSize;
- MemoryAttributesTable->Reserved = 0;
- DEBUG ((DEBUG_VERBOSE, "MemoryAttributesTable:\n"));
- DEBUG ((DEBUG_VERBOSE, " Version - 0x%08x\n", MemoryAttributesTable->Version));
- DEBUG ((DEBUG_VERBOSE, " NumberOfEntries - 0x%08x\n", MemoryAttributesTable->NumberOfEntries));
- DEBUG ((DEBUG_VERBOSE, " DescriptorSize - 0x%08x\n", MemoryAttributesTable->DescriptorSize));
- MemoryAttributesEntry = (EFI_MEMORY_DESCRIPTOR *)(MemoryAttributesTable + 1);
- for (Index = 0; Index < MemoryMapSize/DescriptorSize; Index++) {
- CopyMem (MemoryAttributesEntry, MemoryMap, DescriptorSize);
- DEBUG ((DEBUG_VERBOSE, "Entry (0x%x)\n", MemoryAttributesEntry));
- DEBUG ((DEBUG_VERBOSE, " Type - 0x%x\n", MemoryAttributesEntry->Type));
- DEBUG ((DEBUG_VERBOSE, " PhysicalStart - 0x%016lx\n", MemoryAttributesEntry->PhysicalStart));
- DEBUG ((DEBUG_VERBOSE, " VirtualStart - 0x%016lx\n", MemoryAttributesEntry->VirtualStart));
- DEBUG ((DEBUG_VERBOSE, " NumberOfPages - 0x%016lx\n", MemoryAttributesEntry->NumberOfPages));
- DEBUG ((DEBUG_VERBOSE, " Attribute - 0x%016lx\n", MemoryAttributesEntry->Attribute));
- MemoryAttributesEntry = NEXT_MEMORY_DESCRIPTOR (MemoryAttributesEntry, DescriptorSize);
-
- MemoryMap = NEXT_MEMORY_DESCRIPTOR (MemoryMap, DescriptorSize);
- }
-
- Status = gSmst->SmmInstallConfigurationTable (gSmst, &gEdkiiPiSmmMemoryAttributesTableGuid, MemoryAttributesTable, MemoryAttributesTableSize);
- ASSERT_EFI_ERROR (Status);
-}
-
-/**
- This function installs all SMM image record information.
-**/
-VOID
-SmmInstallImageRecord (
- VOID
- )
-{
- EFI_STATUS Status;
- UINTN NoHandles;
- EFI_HANDLE *HandleBuffer;
- EFI_LOADED_IMAGE_PROTOCOL *LoadedImage;
- UINTN Index;
- EFI_SMM_DRIVER_ENTRY DriverEntry;
-
- Status = SmmLocateHandleBuffer (
- ByProtocol,
- &gEfiLoadedImageProtocolGuid,
- NULL,
- &NoHandles,
- &HandleBuffer
- );
- if (EFI_ERROR (Status)) {
- return;
- }
-
- for (Index = 0; Index < NoHandles; Index++) {
- Status = gSmst->SmmHandleProtocol (
- HandleBuffer[Index],
- &gEfiLoadedImageProtocolGuid,
- (VOID **)&LoadedImage
- );
- if (EFI_ERROR (Status)) {
- continue;
- }
-
- DEBUG ((DEBUG_VERBOSE, "LoadedImage - 0x%x 0x%x ", LoadedImage->ImageBase, LoadedImage->ImageSize));
- {
- VOID *PdbPointer;
- PdbPointer = PeCoffLoaderGetPdbPointer (LoadedImage->ImageBase);
- if (PdbPointer != NULL) {
- DEBUG ((DEBUG_VERBOSE, "(%a) ", PdbPointer));
- }
- }
- DEBUG ((DEBUG_VERBOSE, "\n"));
- ZeroMem (&DriverEntry, sizeof (DriverEntry));
- DriverEntry.ImageBuffer = (UINTN)LoadedImage->ImageBase;
- DriverEntry.NumberOfPage = EFI_SIZE_TO_PAGES ((UINTN)LoadedImage->ImageSize);
- SmmInsertImageRecord (&DriverEntry);
- }
-
- FreePool (HandleBuffer);
-}
-
-/**
- Install MemoryAttributesTable.
-
- @param[in] Protocol Points to the protocol's unique identifier.
- @param[in] Interface Points to the interface instance.
- @param[in] Handle The handle on which the interface was installed.
-
- @retval EFI_SUCCESS Notification runs successfully.
-**/
-EFI_STATUS
-EFIAPI
-SmmInstallMemoryAttributesTable (
- IN CONST EFI_GUID *Protocol,
- IN VOID *Interface,
- IN EFI_HANDLE Handle
- )
-{
- SmmInstallImageRecord ();
-
- DEBUG ((DEBUG_VERBOSE, "SMM MemoryProtectionAttribute - 0x%016lx\n", mMemoryProtectionAttribute));
- if ((mMemoryProtectionAttribute & EFI_MEMORY_ATTRIBUTES_RUNTIME_MEMORY_PROTECTION_NON_EXECUTABLE_PE_DATA) == 0) {
- return EFI_SUCCESS;
- }
-
- DEBUG_CODE_BEGIN ();
- if ( mImagePropertiesPrivateData.ImageRecordCount > 0) {
- DEBUG ((DEBUG_INFO, "SMM - Total Runtime Image Count - 0x%x\n", mImagePropertiesPrivateData.ImageRecordCount));
- DEBUG ((DEBUG_INFO, "SMM - Dump Runtime Image Records:\n"));
- DumpImageRecords (&mImagePropertiesPrivateData.ImageRecordList);
- }
-
- DEBUG_CODE_END ();
-
- PublishMemoryAttributesTable ();
-
- return EFI_SUCCESS;
-}
-
-/**
- Initialize MemoryAttributesTable support.
-**/
-VOID
-EFIAPI
-SmmCoreInitializeMemoryAttributesTable (
- VOID
- )
-{
- EFI_STATUS Status;
- VOID *Registration;
-
- Status = gSmst->SmmRegisterProtocolNotify (
- &gEfiSmmEndOfDxeProtocolGuid,
- SmmInstallMemoryAttributesTable,
- &Registration
- );
- ASSERT_EFI_ERROR (Status);
-
- return;
-}
+/** @file + PI SMM MemoryAttributes support + +Copyright (c) 2016, Intel Corporation. All rights reserved.<BR> +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include <PiDxe.h> +#include <Library/BaseLib.h> +#include <Library/BaseMemoryLib.h> +#include <Library/MemoryAllocationLib.h> +#include <Library/UefiBootServicesTableLib.h> +#include <Library/SmmServicesTableLib.h> +#include <Library/DebugLib.h> +#include <Library/PcdLib.h> +#include <Library/ImagePropertiesRecordLib.h> + +#include <Library/PeCoffLib.h> +#include <Library/PeCoffGetEntryPointLib.h> + +#include <Guid/PiSmmMemoryAttributesTable.h> + +#include "PiSmmCore.h" + +#define PREVIOUS_MEMORY_DESCRIPTOR(MemoryDescriptor, Size) \ + ((EFI_MEMORY_DESCRIPTOR *)((UINT8 *)(MemoryDescriptor) - (Size))) + +#define IMAGE_PROPERTIES_PRIVATE_DATA_SIGNATURE SIGNATURE_32 ('I','P','P','D') + +typedef struct { + UINT32 Signature; + UINTN ImageRecordCount; + UINTN CodeSegmentCountMax; + LIST_ENTRY ImageRecordList; +} IMAGE_PROPERTIES_PRIVATE_DATA; + +IMAGE_PROPERTIES_PRIVATE_DATA mImagePropertiesPrivateData = { + IMAGE_PROPERTIES_PRIVATE_DATA_SIGNATURE, + 0, + 0, + INITIALIZE_LIST_HEAD_VARIABLE (mImagePropertiesPrivateData.ImageRecordList) +}; + +#define EFI_MEMORY_ATTRIBUTES_RUNTIME_MEMORY_PROTECTION_NON_EXECUTABLE_PE_DATA BIT0 + +UINT64 mMemoryProtectionAttribute = EFI_MEMORY_ATTRIBUTES_RUNTIME_MEMORY_PROTECTION_NON_EXECUTABLE_PE_DATA; + +// +// Below functions are for MemoryMap +// + +/** + Merge continuous memory map entries whose have same attributes. + + @param[in, out] MemoryMap A pointer to the buffer in which firmware places + the current memory map. + @param[in, out] MemoryMapSize A pointer to the size, in bytes, of the + MemoryMap buffer. On input, this is the size of + the current memory map. On output, + it is the size of new memory map after merge. + @param[in] DescriptorSize Size, in bytes, of an individual EFI_MEMORY_DESCRIPTOR. +**/ +STATIC +VOID +MergeMemoryMap ( + IN OUT EFI_MEMORY_DESCRIPTOR *MemoryMap, + IN OUT UINTN *MemoryMapSize, + IN UINTN DescriptorSize + ) +{ + EFI_MEMORY_DESCRIPTOR *MemoryMapEntry; + EFI_MEMORY_DESCRIPTOR *MemoryMapEnd; + UINT64 MemoryBlockLength; + EFI_MEMORY_DESCRIPTOR *NewMemoryMapEntry; + EFI_MEMORY_DESCRIPTOR *NextMemoryMapEntry; + + MemoryMapEntry = MemoryMap; + NewMemoryMapEntry = MemoryMap; + MemoryMapEnd = (EFI_MEMORY_DESCRIPTOR *)((UINT8 *)MemoryMap + *MemoryMapSize); + while ((UINTN)MemoryMapEntry < (UINTN)MemoryMapEnd) { + CopyMem (NewMemoryMapEntry, MemoryMapEntry, sizeof (EFI_MEMORY_DESCRIPTOR)); + NextMemoryMapEntry = NEXT_MEMORY_DESCRIPTOR (MemoryMapEntry, DescriptorSize); + + do { + MemoryBlockLength = LShiftU64 (MemoryMapEntry->NumberOfPages, EFI_PAGE_SHIFT); + if (((UINTN)NextMemoryMapEntry < (UINTN)MemoryMapEnd) && + (MemoryMapEntry->Type == NextMemoryMapEntry->Type) && + (MemoryMapEntry->Attribute == NextMemoryMapEntry->Attribute) && + ((MemoryMapEntry->PhysicalStart + MemoryBlockLength) == NextMemoryMapEntry->PhysicalStart)) + { + MemoryMapEntry->NumberOfPages += NextMemoryMapEntry->NumberOfPages; + if (NewMemoryMapEntry != MemoryMapEntry) { + NewMemoryMapEntry->NumberOfPages += NextMemoryMapEntry->NumberOfPages; + } + + NextMemoryMapEntry = NEXT_MEMORY_DESCRIPTOR (NextMemoryMapEntry, DescriptorSize); + continue; + } else { + MemoryMapEntry = PREVIOUS_MEMORY_DESCRIPTOR (NextMemoryMapEntry, DescriptorSize); + break; + } + } while (TRUE); + + MemoryMapEntry = NEXT_MEMORY_DESCRIPTOR (MemoryMapEntry, DescriptorSize); + NewMemoryMapEntry = NEXT_MEMORY_DESCRIPTOR (NewMemoryMapEntry, DescriptorSize); + } + + *MemoryMapSize = (UINTN)NewMemoryMapEntry - (UINTN)MemoryMap; + + return; +} + +/** + Enforce memory map attributes. + This function will set EfiRuntimeServicesData/EfiMemoryMappedIO/EfiMemoryMappedIOPortSpace to be EFI_MEMORY_XP. + + @param[in, out] MemoryMap A pointer to the buffer in which firmware places + the current memory map. + @param[in] MemoryMapSize Size, in bytes, of the MemoryMap buffer. + @param[in] DescriptorSize Size, in bytes, of an individual EFI_MEMORY_DESCRIPTOR. +**/ +STATIC +VOID +EnforceMemoryMapAttribute ( + IN OUT EFI_MEMORY_DESCRIPTOR *MemoryMap, + IN UINTN MemoryMapSize, + IN UINTN DescriptorSize + ) +{ + EFI_MEMORY_DESCRIPTOR *MemoryMapEntry; + EFI_MEMORY_DESCRIPTOR *MemoryMapEnd; + + MemoryMapEntry = MemoryMap; + MemoryMapEnd = (EFI_MEMORY_DESCRIPTOR *)((UINT8 *)MemoryMap + MemoryMapSize); + while ((UINTN)MemoryMapEntry < (UINTN)MemoryMapEnd) { + if (MemoryMapEntry->Attribute != 0) { + // It is PE image, the attribute is already set. + } else { + switch (MemoryMapEntry->Type) { + case EfiRuntimeServicesCode: + MemoryMapEntry->Attribute = EFI_MEMORY_RO; + break; + case EfiRuntimeServicesData: + default: + MemoryMapEntry->Attribute |= EFI_MEMORY_XP; + break; + } + } + + MemoryMapEntry = NEXT_MEMORY_DESCRIPTOR (MemoryMapEntry, DescriptorSize); + } + + return; +} + +/** + This function for GetMemoryMap() with memory attributes table. + + It calls original GetMemoryMap() to get the original memory map information. Then + plus the additional memory map entries for PE Code/Data separation. + + @param[in, out] MemoryMapSize A pointer to the size, in bytes, of the + MemoryMap buffer. On input, this is the size of + the buffer allocated by the caller. On output, + it is the size of the buffer returned by the + firmware if the buffer was large enough, or the + size of the buffer needed to contain the map if + the buffer was too small. + @param[in, out] MemoryMap A pointer to the buffer in which firmware places + the current memory map. + @param[out] MapKey A pointer to the location in which firmware + returns the key for the current memory map. + @param[out] DescriptorSize A pointer to the location in which firmware + returns the size, in bytes, of an individual + EFI_MEMORY_DESCRIPTOR. + @param[out] DescriptorVersion A pointer to the location in which firmware + returns the version number associated with the + EFI_MEMORY_DESCRIPTOR. + + @retval EFI_SUCCESS The memory map was returned in the MemoryMap + buffer. + @retval EFI_BUFFER_TOO_SMALL The MemoryMap buffer was too small. The current + buffer size needed to hold the memory map is + returned in MemoryMapSize. + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value. + +**/ +STATIC +EFI_STATUS +EFIAPI +SmmCoreGetMemoryMapMemoryAttributesTable ( + IN OUT UINTN *MemoryMapSize, + IN OUT EFI_MEMORY_DESCRIPTOR *MemoryMap, + OUT UINTN *MapKey, + OUT UINTN *DescriptorSize, + OUT UINT32 *DescriptorVersion + ) +{ + EFI_STATUS Status; + UINTN OldMemoryMapSize; + UINTN AdditionalRecordCount; + + // + // If PE code/data is not aligned, just return. + // + if ((mMemoryProtectionAttribute & EFI_MEMORY_ATTRIBUTES_RUNTIME_MEMORY_PROTECTION_NON_EXECUTABLE_PE_DATA) == 0) { + return SmmCoreGetMemoryMap (MemoryMapSize, MemoryMap, MapKey, DescriptorSize, DescriptorVersion); + } + + if (MemoryMapSize == NULL) { + return EFI_INVALID_PARAMETER; + } + + AdditionalRecordCount = (2 * mImagePropertiesPrivateData.CodeSegmentCountMax + 3) * mImagePropertiesPrivateData.ImageRecordCount; + + OldMemoryMapSize = *MemoryMapSize; + Status = SmmCoreGetMemoryMap (MemoryMapSize, MemoryMap, MapKey, DescriptorSize, DescriptorVersion); + if (Status == EFI_BUFFER_TOO_SMALL) { + *MemoryMapSize = *MemoryMapSize + (*DescriptorSize) * AdditionalRecordCount; + } else if (Status == EFI_SUCCESS) { + if (OldMemoryMapSize - *MemoryMapSize < (*DescriptorSize) * AdditionalRecordCount) { + *MemoryMapSize = *MemoryMapSize + (*DescriptorSize) * AdditionalRecordCount; + // + // Need update status to buffer too small + // + Status = EFI_BUFFER_TOO_SMALL; + } else { + // + // Split PE code/data + // + ASSERT (MemoryMap != NULL); + SplitTable (MemoryMapSize, MemoryMap, *DescriptorSize, &mImagePropertiesPrivateData.ImageRecordList, AdditionalRecordCount); + + // + // Set RuntimeData to XP + // + EnforceMemoryMapAttribute (MemoryMap, *MemoryMapSize, *DescriptorSize); + + // + // Merge same type to save entry size + // + MergeMemoryMap (MemoryMap, MemoryMapSize, *DescriptorSize); + } + } + + return Status; +} + +// +// Below functions are for ImageRecord +// + +/** + Insert image record. + + @param[in] DriverEntry Driver information +**/ +VOID +SmmInsertImageRecord ( + IN EFI_SMM_DRIVER_ENTRY *DriverEntry + ) +{ + EFI_STATUS Status; + IMAGE_PROPERTIES_RECORD *ImageRecord; + CHAR8 *PdbPointer; + UINT32 RequiredAlignment; + + DEBUG ((DEBUG_VERBOSE, "SMM InsertImageRecord - 0x%x\n", DriverEntry)); + + ImageRecord = AllocatePool (sizeof (*ImageRecord)); + if (ImageRecord == NULL) { + return; + } + + InitializeListHead (&ImageRecord->Link); + InitializeListHead (&ImageRecord->CodeSegmentList); + + PdbPointer = PeCoffLoaderGetPdbPointer ((VOID *)(UINTN)DriverEntry->ImageBuffer); + if (PdbPointer != NULL) { + DEBUG ((DEBUG_VERBOSE, "SMM Image - %a\n", PdbPointer)); + } + + RequiredAlignment = RUNTIME_PAGE_ALLOCATION_GRANULARITY; + Status = CreateImagePropertiesRecord ( + (VOID *)(UINTN)DriverEntry->ImageBuffer, + LShiftU64 (DriverEntry->NumberOfPage, EFI_PAGE_SHIFT), + &RequiredAlignment, + ImageRecord + ); + + if (EFI_ERROR (Status)) { + if (Status == EFI_ABORTED) { + mMemoryProtectionAttribute &= + ~((UINT64)EFI_MEMORY_ATTRIBUTES_RUNTIME_MEMORY_PROTECTION_NON_EXECUTABLE_PE_DATA); + } + + goto Finish; + } + + if (ImageRecord->CodeSegmentCount == 0) { + mMemoryProtectionAttribute &= + ~((UINT64)EFI_MEMORY_ATTRIBUTES_RUNTIME_MEMORY_PROTECTION_NON_EXECUTABLE_PE_DATA); + DEBUG ((DEBUG_ERROR, "SMM !!!!!!!! InsertImageRecord - CodeSegmentCount is 0 !!!!!!!!\n")); + if (PdbPointer != NULL) { + DEBUG ((DEBUG_ERROR, "SMM !!!!!!!! Image - %a !!!!!!!!\n", PdbPointer)); + } + + Status = EFI_ABORTED; + goto Finish; + } + + // + // Check overlap all section in ImageBase/Size + // + if (!IsImageRecordCodeSectionValid (ImageRecord)) { + DEBUG ((DEBUG_ERROR, "SMM IsImageRecordCodeSectionValid - FAIL\n")); + Status = EFI_ABORTED; + goto Finish; + } + + InsertTailList (&mImagePropertiesPrivateData.ImageRecordList, &ImageRecord->Link); + mImagePropertiesPrivateData.ImageRecordCount++; + + if (mImagePropertiesPrivateData.CodeSegmentCountMax < ImageRecord->CodeSegmentCount) { + mImagePropertiesPrivateData.CodeSegmentCountMax = ImageRecord->CodeSegmentCount; + } + + SortImageRecord (&mImagePropertiesPrivateData.ImageRecordList); + +Finish: + if (EFI_ERROR (Status) && (ImageRecord != NULL)) { + DeleteImagePropertiesRecord (ImageRecord); + } + + return; +} + +/** + Publish MemoryAttributesTable to SMM configuration table. +**/ +VOID +PublishMemoryAttributesTable ( + VOID + ) +{ + UINTN MemoryMapSize; + EFI_MEMORY_DESCRIPTOR *MemoryMap; + UINTN MapKey; + UINTN DescriptorSize; + UINT32 DescriptorVersion; + UINTN Index; + EFI_STATUS Status; + UINTN RuntimeEntryCount; + EDKII_PI_SMM_MEMORY_ATTRIBUTES_TABLE *MemoryAttributesTable; + EFI_MEMORY_DESCRIPTOR *MemoryAttributesEntry; + UINTN MemoryAttributesTableSize; + + MemoryMapSize = 0; + MemoryMap = NULL; + Status = SmmCoreGetMemoryMapMemoryAttributesTable ( + &MemoryMapSize, + MemoryMap, + &MapKey, + &DescriptorSize, + &DescriptorVersion + ); + ASSERT (Status == EFI_BUFFER_TOO_SMALL); + + do { + DEBUG ((DEBUG_VERBOSE, "MemoryMapSize - 0x%x\n", MemoryMapSize)); + MemoryMap = AllocatePool (MemoryMapSize); + ASSERT (MemoryMap != NULL); + DEBUG ((DEBUG_VERBOSE, "MemoryMap - 0x%x\n", MemoryMap)); + + Status = SmmCoreGetMemoryMapMemoryAttributesTable ( + &MemoryMapSize, + MemoryMap, + &MapKey, + &DescriptorSize, + &DescriptorVersion + ); + if (EFI_ERROR (Status)) { + FreePool (MemoryMap); + } + } while (Status == EFI_BUFFER_TOO_SMALL); + + // + // Allocate MemoryAttributesTable + // + RuntimeEntryCount = MemoryMapSize/DescriptorSize; + MemoryAttributesTableSize = sizeof (EDKII_PI_SMM_MEMORY_ATTRIBUTES_TABLE) + DescriptorSize * RuntimeEntryCount; + MemoryAttributesTable = AllocatePool (sizeof (EDKII_PI_SMM_MEMORY_ATTRIBUTES_TABLE) + DescriptorSize * RuntimeEntryCount); + ASSERT (MemoryAttributesTable != NULL); + MemoryAttributesTable->Version = EDKII_PI_SMM_MEMORY_ATTRIBUTES_TABLE_VERSION; + MemoryAttributesTable->NumberOfEntries = (UINT32)RuntimeEntryCount; + MemoryAttributesTable->DescriptorSize = (UINT32)DescriptorSize; + MemoryAttributesTable->Reserved = 0; + DEBUG ((DEBUG_VERBOSE, "MemoryAttributesTable:\n")); + DEBUG ((DEBUG_VERBOSE, " Version - 0x%08x\n", MemoryAttributesTable->Version)); + DEBUG ((DEBUG_VERBOSE, " NumberOfEntries - 0x%08x\n", MemoryAttributesTable->NumberOfEntries)); + DEBUG ((DEBUG_VERBOSE, " DescriptorSize - 0x%08x\n", MemoryAttributesTable->DescriptorSize)); + MemoryAttributesEntry = (EFI_MEMORY_DESCRIPTOR *)(MemoryAttributesTable + 1); + for (Index = 0; Index < MemoryMapSize/DescriptorSize; Index++) { + CopyMem (MemoryAttributesEntry, MemoryMap, DescriptorSize); + DEBUG ((DEBUG_VERBOSE, "Entry (0x%x)\n", MemoryAttributesEntry)); + DEBUG ((DEBUG_VERBOSE, " Type - 0x%x\n", MemoryAttributesEntry->Type)); + DEBUG ((DEBUG_VERBOSE, " PhysicalStart - 0x%016lx\n", MemoryAttributesEntry->PhysicalStart)); + DEBUG ((DEBUG_VERBOSE, " VirtualStart - 0x%016lx\n", MemoryAttributesEntry->VirtualStart)); + DEBUG ((DEBUG_VERBOSE, " NumberOfPages - 0x%016lx\n", MemoryAttributesEntry->NumberOfPages)); + DEBUG ((DEBUG_VERBOSE, " Attribute - 0x%016lx\n", MemoryAttributesEntry->Attribute)); + MemoryAttributesEntry = NEXT_MEMORY_DESCRIPTOR (MemoryAttributesEntry, DescriptorSize); + + MemoryMap = NEXT_MEMORY_DESCRIPTOR (MemoryMap, DescriptorSize); + } + + Status = gSmst->SmmInstallConfigurationTable (gSmst, &gEdkiiPiSmmMemoryAttributesTableGuid, MemoryAttributesTable, MemoryAttributesTableSize); + ASSERT_EFI_ERROR (Status); +} + +/** + This function installs all SMM image record information. +**/ +VOID +SmmInstallImageRecord ( + VOID + ) +{ + EFI_STATUS Status; + UINTN NoHandles; + EFI_HANDLE *HandleBuffer; + EFI_LOADED_IMAGE_PROTOCOL *LoadedImage; + UINTN Index; + EFI_SMM_DRIVER_ENTRY DriverEntry; + + Status = SmmLocateHandleBuffer ( + ByProtocol, + &gEfiLoadedImageProtocolGuid, + NULL, + &NoHandles, + &HandleBuffer + ); + if (EFI_ERROR (Status)) { + return; + } + + for (Index = 0; Index < NoHandles; Index++) { + Status = gSmst->SmmHandleProtocol ( + HandleBuffer[Index], + &gEfiLoadedImageProtocolGuid, + (VOID **)&LoadedImage + ); + if (EFI_ERROR (Status)) { + continue; + } + + DEBUG ((DEBUG_VERBOSE, "LoadedImage - 0x%x 0x%x ", LoadedImage->ImageBase, LoadedImage->ImageSize)); + { + VOID *PdbPointer; + PdbPointer = PeCoffLoaderGetPdbPointer (LoadedImage->ImageBase); + if (PdbPointer != NULL) { + DEBUG ((DEBUG_VERBOSE, "(%a) ", PdbPointer)); + } + } + DEBUG ((DEBUG_VERBOSE, "\n")); + ZeroMem (&DriverEntry, sizeof (DriverEntry)); + DriverEntry.ImageBuffer = (UINTN)LoadedImage->ImageBase; + DriverEntry.NumberOfPage = EFI_SIZE_TO_PAGES ((UINTN)LoadedImage->ImageSize); + SmmInsertImageRecord (&DriverEntry); + } + + FreePool (HandleBuffer); +} + +/** + Install MemoryAttributesTable. + + @param[in] Protocol Points to the protocol's unique identifier. + @param[in] Interface Points to the interface instance. + @param[in] Handle The handle on which the interface was installed. + + @retval EFI_SUCCESS Notification runs successfully. +**/ +EFI_STATUS +EFIAPI +SmmInstallMemoryAttributesTable ( + IN CONST EFI_GUID *Protocol, + IN VOID *Interface, + IN EFI_HANDLE Handle + ) +{ + SmmInstallImageRecord (); + + DEBUG ((DEBUG_VERBOSE, "SMM MemoryProtectionAttribute - 0x%016lx\n", mMemoryProtectionAttribute)); + if ((mMemoryProtectionAttribute & EFI_MEMORY_ATTRIBUTES_RUNTIME_MEMORY_PROTECTION_NON_EXECUTABLE_PE_DATA) == 0) { + return EFI_SUCCESS; + } + + DEBUG_CODE_BEGIN (); + if ( mImagePropertiesPrivateData.ImageRecordCount > 0) { + DEBUG ((DEBUG_INFO, "SMM - Total Runtime Image Count - 0x%x\n", mImagePropertiesPrivateData.ImageRecordCount)); + DEBUG ((DEBUG_INFO, "SMM - Dump Runtime Image Records:\n")); + DumpImageRecords (&mImagePropertiesPrivateData.ImageRecordList); + } + + DEBUG_CODE_END (); + + PublishMemoryAttributesTable (); + + return EFI_SUCCESS; +} + +/** + Initialize MemoryAttributesTable support. +**/ +VOID +EFIAPI +SmmCoreInitializeMemoryAttributesTable ( + VOID + ) +{ + EFI_STATUS Status; + VOID *Registration; + + Status = gSmst->SmmRegisterProtocolNotify ( + &gEfiSmmEndOfDxeProtocolGuid, + SmmInstallMemoryAttributesTable, + &Registration + ); + ASSERT_EFI_ERROR (Status); + + return; +} diff --git a/MdeModulePkg/Core/PiSmmCore/Notify.c b/MdeModulePkg/Core/PiSmmCore/Notify.c index 7d5bff2576..5306ce5fc5 100644 --- a/MdeModulePkg/Core/PiSmmCore/Notify.c +++ b/MdeModulePkg/Core/PiSmmCore/Notify.c @@ -1,198 +1,198 @@ -/** @file
- Support functions for UEFI protocol notification infrastructure.
-
- Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.<BR>
- SPDX-License-Identifier: BSD-2-Clause-Patent
-
-**/
-
-#include "PiSmmCore.h"
-
-/**
- Signal event for every protocol in protocol entry.
-
- @param Prot Protocol interface
-
-**/
-VOID
-SmmNotifyProtocol (
- 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 *
-SmmRemoveInterfaceFromProtocol (
- IN IHANDLE *Handle,
- IN EFI_GUID *Protocol,
- IN VOID *Interface
- )
-{
- PROTOCOL_INTERFACE *Prot;
- PROTOCOL_NOTIFY *ProtNotify;
- PROTOCOL_ENTRY *ProtEntry;
- LIST_ENTRY *Link;
-
- Prot = SmmFindProtocolInterface (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
-SmmRegisterProtocolNotify (
- IN CONST EFI_GUID *Protocol,
- IN EFI_SMM_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 = SmmFindProtocolEntry ((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 = SmmFindProtocolEntry ((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;
-}
+/** @file + Support functions for UEFI protocol notification infrastructure. + + Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.<BR> + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "PiSmmCore.h" + +/** + Signal event for every protocol in protocol entry. + + @param Prot Protocol interface + +**/ +VOID +SmmNotifyProtocol ( + 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 * +SmmRemoveInterfaceFromProtocol ( + IN IHANDLE *Handle, + IN EFI_GUID *Protocol, + IN VOID *Interface + ) +{ + PROTOCOL_INTERFACE *Prot; + PROTOCOL_NOTIFY *ProtNotify; + PROTOCOL_ENTRY *ProtEntry; + LIST_ENTRY *Link; + + Prot = SmmFindProtocolInterface (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 +SmmRegisterProtocolNotify ( + IN CONST EFI_GUID *Protocol, + IN EFI_SMM_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 = SmmFindProtocolEntry ((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 = SmmFindProtocolEntry ((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/MdeModulePkg/Core/PiSmmCore/Page.c b/MdeModulePkg/Core/PiSmmCore/Page.c index 255964c23a..9c2fc94456 100644 --- a/MdeModulePkg/Core/PiSmmCore/Page.c +++ b/MdeModulePkg/Core/PiSmmCore/Page.c @@ -1,1099 +1,1099 @@ -/** @file
- SMM Memory page management functions.
-
- Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.<BR>
- SPDX-License-Identifier: BSD-2-Clause-Patent
-
-**/
-
-#include "PiSmmCore.h"
-#include <Library/SmmServicesTableLib.h>
-
-#define TRUNCATE_TO_PAGES(a) ((a) >> EFI_PAGE_SHIFT)
-
-LIST_ENTRY mSmmMemoryMap = INITIALIZE_LIST_HEAD_VARIABLE (mSmmMemoryMap);
-
-//
-// For GetMemoryMap()
-//
-
-#define MEMORY_MAP_SIGNATURE SIGNATURE_32('m','m','a','p')
-typedef struct {
- UINTN Signature;
- LIST_ENTRY Link;
-
- BOOLEAN FromStack;
- EFI_MEMORY_TYPE Type;
- UINT64 Start;
- UINT64 End;
-} MEMORY_MAP;
-
-LIST_ENTRY gMemoryMap = INITIALIZE_LIST_HEAD_VARIABLE (gMemoryMap);
-
-#define MAX_MAP_DEPTH 6
-
-///
-/// mMapDepth - depth of new descriptor stack
-///
-UINTN mMapDepth = 0;
-///
-/// mMapStack - space to use as temp storage to build new map descriptors
-///
-MEMORY_MAP mMapStack[MAX_MAP_DEPTH];
-UINTN mFreeMapStack = 0;
-///
-/// This list maintain the free memory map list
-///
-LIST_ENTRY mFreeMemoryMapEntryList = INITIALIZE_LIST_HEAD_VARIABLE (mFreeMemoryMapEntryList);
-
-/**
- Allocates pages from the memory map.
-
- @param[in] Type The type of allocation to perform.
- @param[in] MemoryType The type of memory to turn the allocated pages
- into.
- @param[in] NumberOfPages The number of pages to allocate.
- @param[out] Memory A pointer to receive the base allocated memory
- address.
- @param[in] AddRegion If this memory is new added region.
- @param[in] NeedGuard Flag to indicate Guard page is needed
- or not
-
- @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
-SmmInternalAllocatePagesEx (
- IN EFI_ALLOCATE_TYPE Type,
- IN EFI_MEMORY_TYPE MemoryType,
- IN UINTN NumberOfPages,
- OUT EFI_PHYSICAL_ADDRESS *Memory,
- IN BOOLEAN AddRegion,
- IN BOOLEAN NeedGuard
- );
-
-/**
- Internal function. Deque a descriptor entry from the mFreeMemoryMapEntryList.
- If the list is emtry, then allocate a new page to refuel the list.
- Please Note this algorithm to allocate the memory map descriptor has a property
- that the memory allocated for memory entries always grows, and will never really be freed.
-
- @return The Memory map descriptor dequeued from the mFreeMemoryMapEntryList
-
-**/
-MEMORY_MAP *
-AllocateMemoryMapEntry (
- VOID
- )
-{
- EFI_PHYSICAL_ADDRESS Mem;
- EFI_STATUS Status;
- MEMORY_MAP *FreeDescriptorEntries;
- MEMORY_MAP *Entry;
- UINTN Index;
-
- // DEBUG((DEBUG_INFO, "AllocateMemoryMapEntry\n"));
-
- if (IsListEmpty (&mFreeMemoryMapEntryList)) {
- // DEBUG((DEBUG_INFO, "mFreeMemoryMapEntryList is empty\n"));
- //
- // The list is empty, to allocate one page to refuel the list
- //
- Status = SmmInternalAllocatePagesEx (
- AllocateAnyPages,
- EfiRuntimeServicesData,
- EFI_SIZE_TO_PAGES (RUNTIME_PAGE_ALLOCATION_GRANULARITY),
- &Mem,
- TRUE,
- FALSE
- );
- ASSERT_EFI_ERROR (Status);
- if (!EFI_ERROR (Status)) {
- FreeDescriptorEntries = (MEMORY_MAP *)(UINTN)Mem;
- // DEBUG((DEBUG_INFO, "New FreeDescriptorEntries - 0x%x\n", FreeDescriptorEntries));
- //
- // Enqueue the free memory map entries into the list
- //
- for (Index = 0; Index < RUNTIME_PAGE_ALLOCATION_GRANULARITY / sizeof (MEMORY_MAP); Index++) {
- FreeDescriptorEntries[Index].Signature = MEMORY_MAP_SIGNATURE;
- InsertTailList (&mFreeMemoryMapEntryList, &FreeDescriptorEntries[Index].Link);
- }
- } else {
- return NULL;
- }
- }
-
- //
- // dequeue the first descriptor from the list
- //
- Entry = CR (mFreeMemoryMapEntryList.ForwardLink, MEMORY_MAP, Link, MEMORY_MAP_SIGNATURE);
- RemoveEntryList (&Entry->Link);
-
- return Entry;
-}
-
-/**
- Internal function. Moves any memory descriptors that are on the
- temporary descriptor stack to heap.
-
-**/
-VOID
-CoreFreeMemoryMapStack (
- VOID
- )
-{
- MEMORY_MAP *Entry;
-
- //
- // If already freeing the map stack, then return
- //
- if (mFreeMapStack != 0) {
- ASSERT (FALSE);
- return;
- }
-
- //
- // Move the temporary memory descriptor stack into pool
- //
- mFreeMapStack += 1;
-
- while (mMapDepth != 0) {
- //
- // Deque an memory map entry from mFreeMemoryMapEntryList
- //
- Entry = AllocateMemoryMapEntry ();
- ASSERT (Entry);
-
- //
- // Update to proper entry
- //
- mMapDepth -= 1;
-
- if (mMapStack[mMapDepth].Link.ForwardLink != NULL) {
- CopyMem (Entry, &mMapStack[mMapDepth], sizeof (MEMORY_MAP));
- Entry->FromStack = FALSE;
-
- //
- // Move this entry to general memory
- //
- InsertTailList (&mMapStack[mMapDepth].Link, &Entry->Link);
- RemoveEntryList (&mMapStack[mMapDepth].Link);
- mMapStack[mMapDepth].Link.ForwardLink = NULL;
- }
- }
-
- mFreeMapStack -= 1;
-}
-
-/**
- Insert new entry from memory map.
-
- @param[in] Link The old memory map entry to be linked.
- @param[in] Start The start address of new memory map entry.
- @param[in] End The end address of new memory map entry.
- @param[in] Type The type of new memory map entry.
- @param[in] Next If new entry is inserted to the next of old entry.
- @param[in] AddRegion If this memory is new added region.
-**/
-VOID
-InsertNewEntry (
- IN LIST_ENTRY *Link,
- IN UINT64 Start,
- IN UINT64 End,
- IN EFI_MEMORY_TYPE Type,
- IN BOOLEAN Next,
- IN BOOLEAN AddRegion
- )
-{
- MEMORY_MAP *Entry;
-
- Entry = &mMapStack[mMapDepth];
- mMapDepth += 1;
- ASSERT (mMapDepth < MAX_MAP_DEPTH);
- Entry->FromStack = TRUE;
-
- Entry->Signature = MEMORY_MAP_SIGNATURE;
- Entry->Type = Type;
- Entry->Start = Start;
- Entry->End = End;
- if (Next) {
- InsertHeadList (Link, &Entry->Link);
- } else {
- InsertTailList (Link, &Entry->Link);
- }
-}
-
-/**
- Remove old entry from memory map.
-
- @param[in] Entry Memory map entry to be removed.
-**/
-VOID
-RemoveOldEntry (
- IN MEMORY_MAP *Entry
- )
-{
- RemoveEntryList (&Entry->Link);
- Entry->Link.ForwardLink = NULL;
-
- if (!Entry->FromStack) {
- InsertTailList (&mFreeMemoryMapEntryList, &Entry->Link);
- }
-}
-
-/**
- Update SMM memory map entry.
-
- @param[in] Type The type of allocation to perform.
- @param[in] Memory The base of memory address.
- @param[in] NumberOfPages The number of pages to allocate.
- @param[in] AddRegion If this memory is new added region.
-**/
-VOID
-ConvertSmmMemoryMapEntry (
- IN EFI_MEMORY_TYPE Type,
- IN EFI_PHYSICAL_ADDRESS Memory,
- IN UINTN NumberOfPages,
- IN BOOLEAN AddRegion
- )
-{
- LIST_ENTRY *Link;
- MEMORY_MAP *Entry;
- MEMORY_MAP *NextEntry;
- LIST_ENTRY *NextLink;
- MEMORY_MAP *PreviousEntry;
- LIST_ENTRY *PreviousLink;
- EFI_PHYSICAL_ADDRESS Start;
- EFI_PHYSICAL_ADDRESS End;
-
- Start = Memory;
- End = Memory + EFI_PAGES_TO_SIZE (NumberOfPages) - 1;
-
- //
- // Exclude memory region
- //
- Link = gMemoryMap.ForwardLink;
- while (Link != &gMemoryMap) {
- Entry = CR (Link, MEMORY_MAP, Link, MEMORY_MAP_SIGNATURE);
- Link = Link->ForwardLink;
-
- //
- // ---------------------------------------------------
- // | +----------+ +------+ +------+ +------+ |
- // ---|gMemoryMep|---|Entry1|---|Entry2|---|Entry3|---
- // +----------+ ^ +------+ +------+ +------+
- // |
- // +------+
- // |EntryX|
- // +------+
- //
- if (Entry->Start > End) {
- if ((Entry->Start == End + 1) && (Entry->Type == Type)) {
- Entry->Start = Start;
- return;
- }
-
- InsertNewEntry (
- &Entry->Link,
- Start,
- End,
- Type,
- FALSE,
- AddRegion
- );
- return;
- }
-
- if ((Entry->Start <= Start) && (Entry->End >= End)) {
- if (Entry->Type != Type) {
- if (Entry->Start < Start) {
- //
- // ---------------------------------------------------
- // | +----------+ +------+ +------+ +------+ |
- // ---|gMemoryMep|---|Entry1|---|EntryX|---|Entry3|---
- // +----------+ +------+ ^ +------+ +------+
- // |
- // +------+
- // |EntryA|
- // +------+
- //
- InsertNewEntry (
- &Entry->Link,
- Entry->Start,
- Start - 1,
- Entry->Type,
- FALSE,
- AddRegion
- );
- }
-
- if (Entry->End > End) {
- //
- // ---------------------------------------------------
- // | +----------+ +------+ +------+ +------+ |
- // ---|gMemoryMep|---|Entry1|---|EntryX|---|Entry3|---
- // +----------+ +------+ +------+ ^ +------+
- // |
- // +------+
- // |EntryZ|
- // +------+
- //
- InsertNewEntry (
- &Entry->Link,
- End + 1,
- Entry->End,
- Entry->Type,
- TRUE,
- AddRegion
- );
- }
-
- //
- // Update this node
- //
- Entry->Start = Start;
- Entry->End = End;
- Entry->Type = Type;
-
- //
- // Check adjacent
- //
- NextLink = Entry->Link.ForwardLink;
- if (NextLink != &gMemoryMap) {
- NextEntry = CR (NextLink, MEMORY_MAP, Link, MEMORY_MAP_SIGNATURE);
- //
- // ---------------------------------------------------
- // | +----------+ +------+ +-----------------+ |
- // ---|gMemoryMep|---|Entry1|---|EntryX Entry3|---
- // +----------+ +------+ +-----------------+
- //
- if ((Entry->Type == NextEntry->Type) && (Entry->End + 1 == NextEntry->Start)) {
- Entry->End = NextEntry->End;
- RemoveOldEntry (NextEntry);
- }
- }
-
- PreviousLink = Entry->Link.BackLink;
- if (PreviousLink != &gMemoryMap) {
- PreviousEntry = CR (PreviousLink, MEMORY_MAP, Link, MEMORY_MAP_SIGNATURE);
- //
- // ---------------------------------------------------
- // | +----------+ +-----------------+ +------+ |
- // ---|gMemoryMep|---|Entry1 EntryX|---|Entry3|---
- // +----------+ +-----------------+ +------+
- //
- if ((PreviousEntry->Type == Entry->Type) && (PreviousEntry->End + 1 == Entry->Start)) {
- PreviousEntry->End = Entry->End;
- RemoveOldEntry (Entry);
- }
- }
- }
-
- return;
- }
- }
-
- //
- // ---------------------------------------------------
- // | +----------+ +------+ +------+ +------+ |
- // ---|gMemoryMep|---|Entry1|---|Entry2|---|Entry3|---
- // +----------+ +------+ +------+ +------+ ^
- // |
- // +------+
- // |EntryX|
- // +------+
- //
- Link = gMemoryMap.BackLink;
- if (Link != &gMemoryMap) {
- Entry = CR (Link, MEMORY_MAP, Link, MEMORY_MAP_SIGNATURE);
- if ((Entry->End + 1 == Start) && (Entry->Type == Type)) {
- Entry->End = End;
- return;
- }
- }
-
- InsertNewEntry (
- &gMemoryMap,
- Start,
- End,
- Type,
- FALSE,
- AddRegion
- );
- return;
-}
-
-/**
- Return the count of Smm memory map entry.
-
- @return The count of Smm memory map entry.
-**/
-UINTN
-GetSmmMemoryMapEntryCount (
- VOID
- )
-{
- LIST_ENTRY *Link;
- UINTN Count;
-
- Count = 0;
- Link = gMemoryMap.ForwardLink;
- while (Link != &gMemoryMap) {
- Link = Link->ForwardLink;
- Count++;
- }
-
- return Count;
-}
-
-/**
- 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[in] Type The type of allocation to perform.
- @param[in] MemoryType The type of memory to turn the allocated pages
- into.
- @param[in] NumberOfPages The number of pages to allocate.
- @param[out] Memory A pointer to receive the base allocated memory
- address.
- @param[in] AddRegion If this memory is new added region.
- @param[in] NeedGuard Flag to indicate Guard page is needed
- or not
-
- @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
-SmmInternalAllocatePagesEx (
- IN EFI_ALLOCATE_TYPE Type,
- IN EFI_MEMORY_TYPE MemoryType,
- IN UINTN NumberOfPages,
- OUT EFI_PHYSICAL_ADDRESS *Memory,
- IN BOOLEAN AddRegion,
- IN BOOLEAN NeedGuard
- )
-{
- 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 SMM
- //
- RequestedAddress = (UINTN)*Memory;
- switch (Type) {
- case AllocateAnyPages:
- RequestedAddress = (UINTN)(-1);
- case AllocateMaxAddress:
- if (NeedGuard) {
- *Memory = InternalAllocMaxAddressWithGuard (
- &mSmmMemoryMap,
- NumberOfPages,
- RequestedAddress,
- MemoryType
- );
- if (*Memory == (UINTN)-1) {
- return EFI_OUT_OF_RESOURCES;
- } else {
- ASSERT (VerifyMemoryGuard (*Memory, NumberOfPages) == TRUE);
- return EFI_SUCCESS;
- }
- }
-
- *Memory = InternalAllocMaxAddress (
- &mSmmMemoryMap,
- NumberOfPages,
- RequestedAddress
- );
- if (*Memory == (UINTN)-1) {
- return EFI_OUT_OF_RESOURCES;
- }
-
- break;
- case AllocateAddress:
- *Memory = InternalAllocAddress (
- &mSmmMemoryMap,
- NumberOfPages,
- RequestedAddress
- );
- if (*Memory != RequestedAddress) {
- return EFI_NOT_FOUND;
- }
-
- break;
- default:
- return EFI_INVALID_PARAMETER;
- }
-
- //
- // Update SmmMemoryMap here.
- //
- ConvertSmmMemoryMapEntry (MemoryType, *Memory, NumberOfPages, AddRegion);
- if (!AddRegion) {
- CoreFreeMemoryMapStack ();
- }
-
- return EFI_SUCCESS;
-}
-
-/**
- Allocates pages from the memory map.
-
- @param[in] Type The type of allocation to perform.
- @param[in] MemoryType The type of memory to turn the allocated pages
- into.
- @param[in] NumberOfPages The number of pages to allocate.
- @param[out] Memory A pointer to receive the base allocated memory
- address.
- @param[in] NeedGuard Flag to indicate Guard page is needed
- or not
-
- @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
-SmmInternalAllocatePages (
- IN EFI_ALLOCATE_TYPE Type,
- IN EFI_MEMORY_TYPE MemoryType,
- IN UINTN NumberOfPages,
- OUT EFI_PHYSICAL_ADDRESS *Memory,
- IN BOOLEAN NeedGuard
- )
-{
- return SmmInternalAllocatePagesEx (
- Type,
- MemoryType,
- NumberOfPages,
- Memory,
- FALSE,
- NeedGuard
- );
-}
-
-/**
- Allocates pages from the memory map.
-
- @param Type The type of allocation to perform.
- @param MemoryType The type of memory to turn the allocated pages
- into.
- @param NumberOfPages The number of pages to allocate.
- @param Memory A pointer to receive the base allocated memory
- address.
-
- @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
-SmmAllocatePages (
- IN EFI_ALLOCATE_TYPE Type,
- IN EFI_MEMORY_TYPE MemoryType,
- IN UINTN NumberOfPages,
- OUT EFI_PHYSICAL_ADDRESS *Memory
- )
-{
- EFI_STATUS Status;
- BOOLEAN NeedGuard;
-
- NeedGuard = IsPageTypeToGuard (MemoryType, Type);
- Status = SmmInternalAllocatePages (
- Type,
- MemoryType,
- NumberOfPages,
- Memory,
- NeedGuard
- );
- if (!EFI_ERROR (Status)) {
- SmmCoreUpdateProfile (
- (EFI_PHYSICAL_ADDRESS)(UINTN)RETURN_ADDRESS (0),
- MemoryProfileActionAllocatePages,
- MemoryType,
- EFI_PAGES_TO_SIZE (NumberOfPages),
- (VOID *)(UINTN)*Memory,
- NULL
- );
- }
-
- 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[in] Memory Base address of memory being freed.
- @param[in] NumberOfPages The number of pages to free.
- @param[in] AddRegion If this memory is new added region.
-
- @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
-SmmInternalFreePagesEx (
- IN EFI_PHYSICAL_ADDRESS Memory,
- IN UINTN NumberOfPages,
- IN BOOLEAN AddRegion
- )
-{
- LIST_ENTRY *Node;
- FREE_PAGE_LIST *Pages;
-
- if (((Memory & EFI_PAGE_MASK) != 0) || (Memory == 0) || (NumberOfPages == 0)) {
- return EFI_INVALID_PARAMETER;
- }
-
- Pages = NULL;
- Node = mSmmMemoryMap.ForwardLink;
- while (Node != &mSmmMemoryMap) {
- Pages = BASE_CR (Node, FREE_PAGE_LIST, Link);
- if (Memory < (UINTN)Pages) {
- break;
- }
-
- Node = Node->ForwardLink;
- }
-
- if ((Node != &mSmmMemoryMap) &&
- (Memory + EFI_PAGES_TO_SIZE (NumberOfPages) > (UINTN)Pages))
- {
- return EFI_INVALID_PARAMETER;
- }
-
- if (Node->BackLink != &mSmmMemoryMap) {
- 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 != &mSmmMemoryMap) {
- Pages = InternalMergeNodes (
- BASE_CR (Pages->Link.BackLink, FREE_PAGE_LIST, Link)
- );
- }
-
- if (Node != &mSmmMemoryMap) {
- InternalMergeNodes (Pages);
- }
-
- //
- // Update SmmMemoryMap here.
- //
- ConvertSmmMemoryMapEntry (EfiConventionalMemory, Memory, NumberOfPages, AddRegion);
- if (!AddRegion) {
- CoreFreeMemoryMapStack ();
- }
-
- return EFI_SUCCESS;
-}
-
-/**
- Frees previous allocated pages.
-
- @param[in] Memory Base address of memory being freed.
- @param[in] NumberOfPages The number of pages to free.
- @param[in] IsGuarded Is the memory to free guarded or not.
-
- @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
-SmmInternalFreePages (
- IN EFI_PHYSICAL_ADDRESS Memory,
- IN UINTN NumberOfPages,
- IN BOOLEAN IsGuarded
- )
-{
- if (IsGuarded) {
- return SmmInternalFreePagesExWithGuard (Memory, NumberOfPages, FALSE);
- }
-
- return SmmInternalFreePagesEx (Memory, NumberOfPages, FALSE);
-}
-
-/**
- Check whether the input range is in memory map.
-
- @param Memory Base address of memory being inputed.
- @param NumberOfPages The number of pages.
-
- @retval TRUE In memory map.
- @retval FALSE Not in memory map.
-
-**/
-BOOLEAN
-InMemMap (
- IN EFI_PHYSICAL_ADDRESS Memory,
- IN UINTN NumberOfPages
- )
-{
- LIST_ENTRY *Link;
- MEMORY_MAP *Entry;
- EFI_PHYSICAL_ADDRESS Last;
-
- Last = Memory + EFI_PAGES_TO_SIZE (NumberOfPages) - 1;
-
- Link = gMemoryMap.ForwardLink;
- while (Link != &gMemoryMap) {
- Entry = CR (Link, MEMORY_MAP, Link, MEMORY_MAP_SIGNATURE);
- Link = Link->ForwardLink;
-
- if ((Entry->Start <= Memory) && (Entry->End >= Last)) {
- return TRUE;
- }
- }
-
- return FALSE;
-}
-
-/**
- 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
-SmmFreePages (
- IN EFI_PHYSICAL_ADDRESS Memory,
- IN UINTN NumberOfPages
- )
-{
- EFI_STATUS Status;
- BOOLEAN IsGuarded;
-
- if (!InMemMap (Memory, NumberOfPages)) {
- return EFI_NOT_FOUND;
- }
-
- IsGuarded = IsHeapGuardEnabled () && IsMemoryGuarded (Memory);
- Status = SmmInternalFreePages (Memory, NumberOfPages, IsGuarded);
- if (!EFI_ERROR (Status)) {
- SmmCoreUpdateProfile (
- (EFI_PHYSICAL_ADDRESS)(UINTN)RETURN_ADDRESS (0),
- MemoryProfileActionFreePages,
- EfiMaxMemoryType,
- EFI_PAGES_TO_SIZE (NumberOfPages),
- (VOID *)(UINTN)Memory,
- NULL
- );
- }
-
- return Status;
-}
-
-/**
- Add free SMRAM 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
-SmmAddMemoryRegion (
- IN EFI_PHYSICAL_ADDRESS MemBase,
- IN UINT64 MemLength,
- IN EFI_MEMORY_TYPE Type,
- IN UINT64 Attributes
- )
-{
- UINTN AlignedMemBase;
-
- //
- // Add EfiRuntimeServicesData for memory regions that is already allocated, needs testing, or needs ECC initialization
- //
- if ((Attributes & (EFI_ALLOCATED | EFI_NEEDS_TESTING | EFI_NEEDS_ECC_INITIALIZATION)) != 0) {
- Type = EfiRuntimeServicesData;
- } else {
- Type = EfiConventionalMemory;
- }
-
- DEBUG ((DEBUG_INFO, "SmmAddMemoryRegion\n"));
- DEBUG ((DEBUG_INFO, " MemBase - 0x%lx\n", MemBase));
- DEBUG ((DEBUG_INFO, " MemLength - 0x%lx\n", MemLength));
- DEBUG ((DEBUG_INFO, " Type - 0x%x\n", Type));
- DEBUG ((DEBUG_INFO, " Attributes - 0x%lx\n", Attributes));
-
- //
- // Align range on an EFI_PAGE_SIZE boundary
- //
- AlignedMemBase = (UINTN)(MemBase + EFI_PAGE_MASK) & ~EFI_PAGE_MASK;
- MemLength -= AlignedMemBase - MemBase;
- if (Type == EfiConventionalMemory) {
- SmmInternalFreePagesEx (AlignedMemBase, TRUNCATE_TO_PAGES ((UINTN)MemLength), TRUE);
- } else {
- ConvertSmmMemoryMapEntry (EfiRuntimeServicesData, AlignedMemBase, TRUNCATE_TO_PAGES ((UINTN)MemLength), TRUE);
- }
-
- CoreFreeMemoryMapStack ();
-}
-
-/**
- This function returns a copy of the current memory map. The map is an array of
- memory descriptors, each of which describes a contiguous block of memory.
-
- @param[in, out] MemoryMapSize A pointer to the size, in bytes, of the
- MemoryMap buffer. On input, this is the size of
- the buffer allocated by the caller. On output,
- it is the size of the buffer returned by the
- firmware if the buffer was large enough, or the
- size of the buffer needed to contain the map if
- the buffer was too small.
- @param[in, out] MemoryMap A pointer to the buffer in which firmware places
- the current memory map.
- @param[out] MapKey A pointer to the location in which firmware
- returns the key for the current memory map.
- @param[out] DescriptorSize A pointer to the location in which firmware
- returns the size, in bytes, of an individual
- EFI_MEMORY_DESCRIPTOR.
- @param[out] DescriptorVersion A pointer to the location in which firmware
- returns the version number associated with the
- EFI_MEMORY_DESCRIPTOR.
-
- @retval EFI_SUCCESS The memory map was returned in the MemoryMap
- buffer.
- @retval EFI_BUFFER_TOO_SMALL The MemoryMap buffer was too small. The current
- buffer size needed to hold the memory map is
- returned in MemoryMapSize.
- @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
-
-**/
-EFI_STATUS
-EFIAPI
-SmmCoreGetMemoryMap (
- IN OUT UINTN *MemoryMapSize,
- IN OUT EFI_MEMORY_DESCRIPTOR *MemoryMap,
- OUT UINTN *MapKey,
- OUT UINTN *DescriptorSize,
- OUT UINT32 *DescriptorVersion
- )
-{
- UINTN Count;
- LIST_ENTRY *Link;
- MEMORY_MAP *Entry;
- UINTN Size;
- UINTN BufferSize;
-
- Size = sizeof (EFI_MEMORY_DESCRIPTOR);
-
- //
- // Make sure Size != sizeof(EFI_MEMORY_DESCRIPTOR). This will
- // prevent people from having pointer math bugs in their code.
- // now you have to use *DescriptorSize to make things work.
- //
- Size += sizeof (UINT64) - (Size % sizeof (UINT64));
-
- if (DescriptorSize != NULL) {
- *DescriptorSize = Size;
- }
-
- if (DescriptorVersion != NULL) {
- *DescriptorVersion = EFI_MEMORY_DESCRIPTOR_VERSION;
- }
-
- Count = GetSmmMemoryMapEntryCount ();
- BufferSize = Size * Count;
- if (*MemoryMapSize < BufferSize) {
- *MemoryMapSize = BufferSize;
- return EFI_BUFFER_TOO_SMALL;
- }
-
- *MemoryMapSize = BufferSize;
- if (MemoryMap == NULL) {
- return EFI_INVALID_PARAMETER;
- }
-
- ZeroMem (MemoryMap, BufferSize);
- Link = gMemoryMap.ForwardLink;
- while (Link != &gMemoryMap) {
- Entry = CR (Link, MEMORY_MAP, Link, MEMORY_MAP_SIGNATURE);
- Link = Link->ForwardLink;
-
- MemoryMap->Type = Entry->Type;
- MemoryMap->PhysicalStart = Entry->Start;
- MemoryMap->NumberOfPages = RShiftU64 (Entry->End - Entry->Start + 1, EFI_PAGE_SHIFT);
-
- MemoryMap = NEXT_MEMORY_DESCRIPTOR (MemoryMap, Size);
- }
-
- return EFI_SUCCESS;
-}
+/** @file + SMM Memory page management functions. + + Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.<BR> + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "PiSmmCore.h" +#include <Library/SmmServicesTableLib.h> + +#define TRUNCATE_TO_PAGES(a) ((a) >> EFI_PAGE_SHIFT) + +LIST_ENTRY mSmmMemoryMap = INITIALIZE_LIST_HEAD_VARIABLE (mSmmMemoryMap); + +// +// For GetMemoryMap() +// + +#define MEMORY_MAP_SIGNATURE SIGNATURE_32('m','m','a','p') +typedef struct { + UINTN Signature; + LIST_ENTRY Link; + + BOOLEAN FromStack; + EFI_MEMORY_TYPE Type; + UINT64 Start; + UINT64 End; +} MEMORY_MAP; + +LIST_ENTRY gMemoryMap = INITIALIZE_LIST_HEAD_VARIABLE (gMemoryMap); + +#define MAX_MAP_DEPTH 6 + +/// +/// mMapDepth - depth of new descriptor stack +/// +UINTN mMapDepth = 0; +/// +/// mMapStack - space to use as temp storage to build new map descriptors +/// +MEMORY_MAP mMapStack[MAX_MAP_DEPTH]; +UINTN mFreeMapStack = 0; +/// +/// This list maintain the free memory map list +/// +LIST_ENTRY mFreeMemoryMapEntryList = INITIALIZE_LIST_HEAD_VARIABLE (mFreeMemoryMapEntryList); + +/** + Allocates pages from the memory map. + + @param[in] Type The type of allocation to perform. + @param[in] MemoryType The type of memory to turn the allocated pages + into. + @param[in] NumberOfPages The number of pages to allocate. + @param[out] Memory A pointer to receive the base allocated memory + address. + @param[in] AddRegion If this memory is new added region. + @param[in] NeedGuard Flag to indicate Guard page is needed + or not + + @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 +SmmInternalAllocatePagesEx ( + IN EFI_ALLOCATE_TYPE Type, + IN EFI_MEMORY_TYPE MemoryType, + IN UINTN NumberOfPages, + OUT EFI_PHYSICAL_ADDRESS *Memory, + IN BOOLEAN AddRegion, + IN BOOLEAN NeedGuard + ); + +/** + Internal function. Deque a descriptor entry from the mFreeMemoryMapEntryList. + If the list is emtry, then allocate a new page to refuel the list. + Please Note this algorithm to allocate the memory map descriptor has a property + that the memory allocated for memory entries always grows, and will never really be freed. + + @return The Memory map descriptor dequeued from the mFreeMemoryMapEntryList + +**/ +MEMORY_MAP * +AllocateMemoryMapEntry ( + VOID + ) +{ + EFI_PHYSICAL_ADDRESS Mem; + EFI_STATUS Status; + MEMORY_MAP *FreeDescriptorEntries; + MEMORY_MAP *Entry; + UINTN Index; + + // DEBUG((DEBUG_INFO, "AllocateMemoryMapEntry\n")); + + if (IsListEmpty (&mFreeMemoryMapEntryList)) { + // DEBUG((DEBUG_INFO, "mFreeMemoryMapEntryList is empty\n")); + // + // The list is empty, to allocate one page to refuel the list + // + Status = SmmInternalAllocatePagesEx ( + AllocateAnyPages, + EfiRuntimeServicesData, + EFI_SIZE_TO_PAGES (RUNTIME_PAGE_ALLOCATION_GRANULARITY), + &Mem, + TRUE, + FALSE + ); + ASSERT_EFI_ERROR (Status); + if (!EFI_ERROR (Status)) { + FreeDescriptorEntries = (MEMORY_MAP *)(UINTN)Mem; + // DEBUG((DEBUG_INFO, "New FreeDescriptorEntries - 0x%x\n", FreeDescriptorEntries)); + // + // Enqueue the free memory map entries into the list + // + for (Index = 0; Index < RUNTIME_PAGE_ALLOCATION_GRANULARITY / sizeof (MEMORY_MAP); Index++) { + FreeDescriptorEntries[Index].Signature = MEMORY_MAP_SIGNATURE; + InsertTailList (&mFreeMemoryMapEntryList, &FreeDescriptorEntries[Index].Link); + } + } else { + return NULL; + } + } + + // + // dequeue the first descriptor from the list + // + Entry = CR (mFreeMemoryMapEntryList.ForwardLink, MEMORY_MAP, Link, MEMORY_MAP_SIGNATURE); + RemoveEntryList (&Entry->Link); + + return Entry; +} + +/** + Internal function. Moves any memory descriptors that are on the + temporary descriptor stack to heap. + +**/ +VOID +CoreFreeMemoryMapStack ( + VOID + ) +{ + MEMORY_MAP *Entry; + + // + // If already freeing the map stack, then return + // + if (mFreeMapStack != 0) { + ASSERT (FALSE); + return; + } + + // + // Move the temporary memory descriptor stack into pool + // + mFreeMapStack += 1; + + while (mMapDepth != 0) { + // + // Deque an memory map entry from mFreeMemoryMapEntryList + // + Entry = AllocateMemoryMapEntry (); + ASSERT (Entry); + + // + // Update to proper entry + // + mMapDepth -= 1; + + if (mMapStack[mMapDepth].Link.ForwardLink != NULL) { + CopyMem (Entry, &mMapStack[mMapDepth], sizeof (MEMORY_MAP)); + Entry->FromStack = FALSE; + + // + // Move this entry to general memory + // + InsertTailList (&mMapStack[mMapDepth].Link, &Entry->Link); + RemoveEntryList (&mMapStack[mMapDepth].Link); + mMapStack[mMapDepth].Link.ForwardLink = NULL; + } + } + + mFreeMapStack -= 1; +} + +/** + Insert new entry from memory map. + + @param[in] Link The old memory map entry to be linked. + @param[in] Start The start address of new memory map entry. + @param[in] End The end address of new memory map entry. + @param[in] Type The type of new memory map entry. + @param[in] Next If new entry is inserted to the next of old entry. + @param[in] AddRegion If this memory is new added region. +**/ +VOID +InsertNewEntry ( + IN LIST_ENTRY *Link, + IN UINT64 Start, + IN UINT64 End, + IN EFI_MEMORY_TYPE Type, + IN BOOLEAN Next, + IN BOOLEAN AddRegion + ) +{ + MEMORY_MAP *Entry; + + Entry = &mMapStack[mMapDepth]; + mMapDepth += 1; + ASSERT (mMapDepth < MAX_MAP_DEPTH); + Entry->FromStack = TRUE; + + Entry->Signature = MEMORY_MAP_SIGNATURE; + Entry->Type = Type; + Entry->Start = Start; + Entry->End = End; + if (Next) { + InsertHeadList (Link, &Entry->Link); + } else { + InsertTailList (Link, &Entry->Link); + } +} + +/** + Remove old entry from memory map. + + @param[in] Entry Memory map entry to be removed. +**/ +VOID +RemoveOldEntry ( + IN MEMORY_MAP *Entry + ) +{ + RemoveEntryList (&Entry->Link); + Entry->Link.ForwardLink = NULL; + + if (!Entry->FromStack) { + InsertTailList (&mFreeMemoryMapEntryList, &Entry->Link); + } +} + +/** + Update SMM memory map entry. + + @param[in] Type The type of allocation to perform. + @param[in] Memory The base of memory address. + @param[in] NumberOfPages The number of pages to allocate. + @param[in] AddRegion If this memory is new added region. +**/ +VOID +ConvertSmmMemoryMapEntry ( + IN EFI_MEMORY_TYPE Type, + IN EFI_PHYSICAL_ADDRESS Memory, + IN UINTN NumberOfPages, + IN BOOLEAN AddRegion + ) +{ + LIST_ENTRY *Link; + MEMORY_MAP *Entry; + MEMORY_MAP *NextEntry; + LIST_ENTRY *NextLink; + MEMORY_MAP *PreviousEntry; + LIST_ENTRY *PreviousLink; + EFI_PHYSICAL_ADDRESS Start; + EFI_PHYSICAL_ADDRESS End; + + Start = Memory; + End = Memory + EFI_PAGES_TO_SIZE (NumberOfPages) - 1; + + // + // Exclude memory region + // + Link = gMemoryMap.ForwardLink; + while (Link != &gMemoryMap) { + Entry = CR (Link, MEMORY_MAP, Link, MEMORY_MAP_SIGNATURE); + Link = Link->ForwardLink; + + // + // --------------------------------------------------- + // | +----------+ +------+ +------+ +------+ | + // ---|gMemoryMep|---|Entry1|---|Entry2|---|Entry3|--- + // +----------+ ^ +------+ +------+ +------+ + // | + // +------+ + // |EntryX| + // +------+ + // + if (Entry->Start > End) { + if ((Entry->Start == End + 1) && (Entry->Type == Type)) { + Entry->Start = Start; + return; + } + + InsertNewEntry ( + &Entry->Link, + Start, + End, + Type, + FALSE, + AddRegion + ); + return; + } + + if ((Entry->Start <= Start) && (Entry->End >= End)) { + if (Entry->Type != Type) { + if (Entry->Start < Start) { + // + // --------------------------------------------------- + // | +----------+ +------+ +------+ +------+ | + // ---|gMemoryMep|---|Entry1|---|EntryX|---|Entry3|--- + // +----------+ +------+ ^ +------+ +------+ + // | + // +------+ + // |EntryA| + // +------+ + // + InsertNewEntry ( + &Entry->Link, + Entry->Start, + Start - 1, + Entry->Type, + FALSE, + AddRegion + ); + } + + if (Entry->End > End) { + // + // --------------------------------------------------- + // | +----------+ +------+ +------+ +------+ | + // ---|gMemoryMep|---|Entry1|---|EntryX|---|Entry3|--- + // +----------+ +------+ +------+ ^ +------+ + // | + // +------+ + // |EntryZ| + // +------+ + // + InsertNewEntry ( + &Entry->Link, + End + 1, + Entry->End, + Entry->Type, + TRUE, + AddRegion + ); + } + + // + // Update this node + // + Entry->Start = Start; + Entry->End = End; + Entry->Type = Type; + + // + // Check adjacent + // + NextLink = Entry->Link.ForwardLink; + if (NextLink != &gMemoryMap) { + NextEntry = CR (NextLink, MEMORY_MAP, Link, MEMORY_MAP_SIGNATURE); + // + // --------------------------------------------------- + // | +----------+ +------+ +-----------------+ | + // ---|gMemoryMep|---|Entry1|---|EntryX Entry3|--- + // +----------+ +------+ +-----------------+ + // + if ((Entry->Type == NextEntry->Type) && (Entry->End + 1 == NextEntry->Start)) { + Entry->End = NextEntry->End; + RemoveOldEntry (NextEntry); + } + } + + PreviousLink = Entry->Link.BackLink; + if (PreviousLink != &gMemoryMap) { + PreviousEntry = CR (PreviousLink, MEMORY_MAP, Link, MEMORY_MAP_SIGNATURE); + // + // --------------------------------------------------- + // | +----------+ +-----------------+ +------+ | + // ---|gMemoryMep|---|Entry1 EntryX|---|Entry3|--- + // +----------+ +-----------------+ +------+ + // + if ((PreviousEntry->Type == Entry->Type) && (PreviousEntry->End + 1 == Entry->Start)) { + PreviousEntry->End = Entry->End; + RemoveOldEntry (Entry); + } + } + } + + return; + } + } + + // + // --------------------------------------------------- + // | +----------+ +------+ +------+ +------+ | + // ---|gMemoryMep|---|Entry1|---|Entry2|---|Entry3|--- + // +----------+ +------+ +------+ +------+ ^ + // | + // +------+ + // |EntryX| + // +------+ + // + Link = gMemoryMap.BackLink; + if (Link != &gMemoryMap) { + Entry = CR (Link, MEMORY_MAP, Link, MEMORY_MAP_SIGNATURE); + if ((Entry->End + 1 == Start) && (Entry->Type == Type)) { + Entry->End = End; + return; + } + } + + InsertNewEntry ( + &gMemoryMap, + Start, + End, + Type, + FALSE, + AddRegion + ); + return; +} + +/** + Return the count of Smm memory map entry. + + @return The count of Smm memory map entry. +**/ +UINTN +GetSmmMemoryMapEntryCount ( + VOID + ) +{ + LIST_ENTRY *Link; + UINTN Count; + + Count = 0; + Link = gMemoryMap.ForwardLink; + while (Link != &gMemoryMap) { + Link = Link->ForwardLink; + Count++; + } + + return Count; +} + +/** + 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[in] Type The type of allocation to perform. + @param[in] MemoryType The type of memory to turn the allocated pages + into. + @param[in] NumberOfPages The number of pages to allocate. + @param[out] Memory A pointer to receive the base allocated memory + address. + @param[in] AddRegion If this memory is new added region. + @param[in] NeedGuard Flag to indicate Guard page is needed + or not + + @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 +SmmInternalAllocatePagesEx ( + IN EFI_ALLOCATE_TYPE Type, + IN EFI_MEMORY_TYPE MemoryType, + IN UINTN NumberOfPages, + OUT EFI_PHYSICAL_ADDRESS *Memory, + IN BOOLEAN AddRegion, + IN BOOLEAN NeedGuard + ) +{ + 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 SMM + // + RequestedAddress = (UINTN)*Memory; + switch (Type) { + case AllocateAnyPages: + RequestedAddress = (UINTN)(-1); + case AllocateMaxAddress: + if (NeedGuard) { + *Memory = InternalAllocMaxAddressWithGuard ( + &mSmmMemoryMap, + NumberOfPages, + RequestedAddress, + MemoryType + ); + if (*Memory == (UINTN)-1) { + return EFI_OUT_OF_RESOURCES; + } else { + ASSERT (VerifyMemoryGuard (*Memory, NumberOfPages) == TRUE); + return EFI_SUCCESS; + } + } + + *Memory = InternalAllocMaxAddress ( + &mSmmMemoryMap, + NumberOfPages, + RequestedAddress + ); + if (*Memory == (UINTN)-1) { + return EFI_OUT_OF_RESOURCES; + } + + break; + case AllocateAddress: + *Memory = InternalAllocAddress ( + &mSmmMemoryMap, + NumberOfPages, + RequestedAddress + ); + if (*Memory != RequestedAddress) { + return EFI_NOT_FOUND; + } + + break; + default: + return EFI_INVALID_PARAMETER; + } + + // + // Update SmmMemoryMap here. + // + ConvertSmmMemoryMapEntry (MemoryType, *Memory, NumberOfPages, AddRegion); + if (!AddRegion) { + CoreFreeMemoryMapStack (); + } + + return EFI_SUCCESS; +} + +/** + Allocates pages from the memory map. + + @param[in] Type The type of allocation to perform. + @param[in] MemoryType The type of memory to turn the allocated pages + into. + @param[in] NumberOfPages The number of pages to allocate. + @param[out] Memory A pointer to receive the base allocated memory + address. + @param[in] NeedGuard Flag to indicate Guard page is needed + or not + + @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 +SmmInternalAllocatePages ( + IN EFI_ALLOCATE_TYPE Type, + IN EFI_MEMORY_TYPE MemoryType, + IN UINTN NumberOfPages, + OUT EFI_PHYSICAL_ADDRESS *Memory, + IN BOOLEAN NeedGuard + ) +{ + return SmmInternalAllocatePagesEx ( + Type, + MemoryType, + NumberOfPages, + Memory, + FALSE, + NeedGuard + ); +} + +/** + Allocates pages from the memory map. + + @param Type The type of allocation to perform. + @param MemoryType The type of memory to turn the allocated pages + into. + @param NumberOfPages The number of pages to allocate. + @param Memory A pointer to receive the base allocated memory + address. + + @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 +SmmAllocatePages ( + IN EFI_ALLOCATE_TYPE Type, + IN EFI_MEMORY_TYPE MemoryType, + IN UINTN NumberOfPages, + OUT EFI_PHYSICAL_ADDRESS *Memory + ) +{ + EFI_STATUS Status; + BOOLEAN NeedGuard; + + NeedGuard = IsPageTypeToGuard (MemoryType, Type); + Status = SmmInternalAllocatePages ( + Type, + MemoryType, + NumberOfPages, + Memory, + NeedGuard + ); + if (!EFI_ERROR (Status)) { + SmmCoreUpdateProfile ( + (EFI_PHYSICAL_ADDRESS)(UINTN)RETURN_ADDRESS (0), + MemoryProfileActionAllocatePages, + MemoryType, + EFI_PAGES_TO_SIZE (NumberOfPages), + (VOID *)(UINTN)*Memory, + NULL + ); + } + + 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[in] Memory Base address of memory being freed. + @param[in] NumberOfPages The number of pages to free. + @param[in] AddRegion If this memory is new added region. + + @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 +SmmInternalFreePagesEx ( + IN EFI_PHYSICAL_ADDRESS Memory, + IN UINTN NumberOfPages, + IN BOOLEAN AddRegion + ) +{ + LIST_ENTRY *Node; + FREE_PAGE_LIST *Pages; + + if (((Memory & EFI_PAGE_MASK) != 0) || (Memory == 0) || (NumberOfPages == 0)) { + return EFI_INVALID_PARAMETER; + } + + Pages = NULL; + Node = mSmmMemoryMap.ForwardLink; + while (Node != &mSmmMemoryMap) { + Pages = BASE_CR (Node, FREE_PAGE_LIST, Link); + if (Memory < (UINTN)Pages) { + break; + } + + Node = Node->ForwardLink; + } + + if ((Node != &mSmmMemoryMap) && + (Memory + EFI_PAGES_TO_SIZE (NumberOfPages) > (UINTN)Pages)) + { + return EFI_INVALID_PARAMETER; + } + + if (Node->BackLink != &mSmmMemoryMap) { + 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 != &mSmmMemoryMap) { + Pages = InternalMergeNodes ( + BASE_CR (Pages->Link.BackLink, FREE_PAGE_LIST, Link) + ); + } + + if (Node != &mSmmMemoryMap) { + InternalMergeNodes (Pages); + } + + // + // Update SmmMemoryMap here. + // + ConvertSmmMemoryMapEntry (EfiConventionalMemory, Memory, NumberOfPages, AddRegion); + if (!AddRegion) { + CoreFreeMemoryMapStack (); + } + + return EFI_SUCCESS; +} + +/** + Frees previous allocated pages. + + @param[in] Memory Base address of memory being freed. + @param[in] NumberOfPages The number of pages to free. + @param[in] IsGuarded Is the memory to free guarded or not. + + @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 +SmmInternalFreePages ( + IN EFI_PHYSICAL_ADDRESS Memory, + IN UINTN NumberOfPages, + IN BOOLEAN IsGuarded + ) +{ + if (IsGuarded) { + return SmmInternalFreePagesExWithGuard (Memory, NumberOfPages, FALSE); + } + + return SmmInternalFreePagesEx (Memory, NumberOfPages, FALSE); +} + +/** + Check whether the input range is in memory map. + + @param Memory Base address of memory being inputed. + @param NumberOfPages The number of pages. + + @retval TRUE In memory map. + @retval FALSE Not in memory map. + +**/ +BOOLEAN +InMemMap ( + IN EFI_PHYSICAL_ADDRESS Memory, + IN UINTN NumberOfPages + ) +{ + LIST_ENTRY *Link; + MEMORY_MAP *Entry; + EFI_PHYSICAL_ADDRESS Last; + + Last = Memory + EFI_PAGES_TO_SIZE (NumberOfPages) - 1; + + Link = gMemoryMap.ForwardLink; + while (Link != &gMemoryMap) { + Entry = CR (Link, MEMORY_MAP, Link, MEMORY_MAP_SIGNATURE); + Link = Link->ForwardLink; + + if ((Entry->Start <= Memory) && (Entry->End >= Last)) { + return TRUE; + } + } + + return FALSE; +} + +/** + 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 +SmmFreePages ( + IN EFI_PHYSICAL_ADDRESS Memory, + IN UINTN NumberOfPages + ) +{ + EFI_STATUS Status; + BOOLEAN IsGuarded; + + if (!InMemMap (Memory, NumberOfPages)) { + return EFI_NOT_FOUND; + } + + IsGuarded = IsHeapGuardEnabled () && IsMemoryGuarded (Memory); + Status = SmmInternalFreePages (Memory, NumberOfPages, IsGuarded); + if (!EFI_ERROR (Status)) { + SmmCoreUpdateProfile ( + (EFI_PHYSICAL_ADDRESS)(UINTN)RETURN_ADDRESS (0), + MemoryProfileActionFreePages, + EfiMaxMemoryType, + EFI_PAGES_TO_SIZE (NumberOfPages), + (VOID *)(UINTN)Memory, + NULL + ); + } + + return Status; +} + +/** + Add free SMRAM 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 +SmmAddMemoryRegion ( + IN EFI_PHYSICAL_ADDRESS MemBase, + IN UINT64 MemLength, + IN EFI_MEMORY_TYPE Type, + IN UINT64 Attributes + ) +{ + UINTN AlignedMemBase; + + // + // Add EfiRuntimeServicesData for memory regions that is already allocated, needs testing, or needs ECC initialization + // + if ((Attributes & (EFI_ALLOCATED | EFI_NEEDS_TESTING | EFI_NEEDS_ECC_INITIALIZATION)) != 0) { + Type = EfiRuntimeServicesData; + } else { + Type = EfiConventionalMemory; + } + + DEBUG ((DEBUG_INFO, "SmmAddMemoryRegion\n")); + DEBUG ((DEBUG_INFO, " MemBase - 0x%lx\n", MemBase)); + DEBUG ((DEBUG_INFO, " MemLength - 0x%lx\n", MemLength)); + DEBUG ((DEBUG_INFO, " Type - 0x%x\n", Type)); + DEBUG ((DEBUG_INFO, " Attributes - 0x%lx\n", Attributes)); + + // + // Align range on an EFI_PAGE_SIZE boundary + // + AlignedMemBase = (UINTN)(MemBase + EFI_PAGE_MASK) & ~EFI_PAGE_MASK; + MemLength -= AlignedMemBase - MemBase; + if (Type == EfiConventionalMemory) { + SmmInternalFreePagesEx (AlignedMemBase, TRUNCATE_TO_PAGES ((UINTN)MemLength), TRUE); + } else { + ConvertSmmMemoryMapEntry (EfiRuntimeServicesData, AlignedMemBase, TRUNCATE_TO_PAGES ((UINTN)MemLength), TRUE); + } + + CoreFreeMemoryMapStack (); +} + +/** + This function returns a copy of the current memory map. The map is an array of + memory descriptors, each of which describes a contiguous block of memory. + + @param[in, out] MemoryMapSize A pointer to the size, in bytes, of the + MemoryMap buffer. On input, this is the size of + the buffer allocated by the caller. On output, + it is the size of the buffer returned by the + firmware if the buffer was large enough, or the + size of the buffer needed to contain the map if + the buffer was too small. + @param[in, out] MemoryMap A pointer to the buffer in which firmware places + the current memory map. + @param[out] MapKey A pointer to the location in which firmware + returns the key for the current memory map. + @param[out] DescriptorSize A pointer to the location in which firmware + returns the size, in bytes, of an individual + EFI_MEMORY_DESCRIPTOR. + @param[out] DescriptorVersion A pointer to the location in which firmware + returns the version number associated with the + EFI_MEMORY_DESCRIPTOR. + + @retval EFI_SUCCESS The memory map was returned in the MemoryMap + buffer. + @retval EFI_BUFFER_TOO_SMALL The MemoryMap buffer was too small. The current + buffer size needed to hold the memory map is + returned in MemoryMapSize. + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value. + +**/ +EFI_STATUS +EFIAPI +SmmCoreGetMemoryMap ( + IN OUT UINTN *MemoryMapSize, + IN OUT EFI_MEMORY_DESCRIPTOR *MemoryMap, + OUT UINTN *MapKey, + OUT UINTN *DescriptorSize, + OUT UINT32 *DescriptorVersion + ) +{ + UINTN Count; + LIST_ENTRY *Link; + MEMORY_MAP *Entry; + UINTN Size; + UINTN BufferSize; + + Size = sizeof (EFI_MEMORY_DESCRIPTOR); + + // + // Make sure Size != sizeof(EFI_MEMORY_DESCRIPTOR). This will + // prevent people from having pointer math bugs in their code. + // now you have to use *DescriptorSize to make things work. + // + Size += sizeof (UINT64) - (Size % sizeof (UINT64)); + + if (DescriptorSize != NULL) { + *DescriptorSize = Size; + } + + if (DescriptorVersion != NULL) { + *DescriptorVersion = EFI_MEMORY_DESCRIPTOR_VERSION; + } + + Count = GetSmmMemoryMapEntryCount (); + BufferSize = Size * Count; + if (*MemoryMapSize < BufferSize) { + *MemoryMapSize = BufferSize; + return EFI_BUFFER_TOO_SMALL; + } + + *MemoryMapSize = BufferSize; + if (MemoryMap == NULL) { + return EFI_INVALID_PARAMETER; + } + + ZeroMem (MemoryMap, BufferSize); + Link = gMemoryMap.ForwardLink; + while (Link != &gMemoryMap) { + Entry = CR (Link, MEMORY_MAP, Link, MEMORY_MAP_SIGNATURE); + Link = Link->ForwardLink; + + MemoryMap->Type = Entry->Type; + MemoryMap->PhysicalStart = Entry->Start; + MemoryMap->NumberOfPages = RShiftU64 (Entry->End - Entry->Start + 1, EFI_PAGE_SHIFT); + + MemoryMap = NEXT_MEMORY_DESCRIPTOR (MemoryMap, Size); + } + + return EFI_SUCCESS; +} diff --git a/MdeModulePkg/Core/PiSmmCore/PiSmmCore.c b/MdeModulePkg/Core/PiSmmCore/PiSmmCore.c index e957cb67f8..66ca24b6ac 100644 --- a/MdeModulePkg/Core/PiSmmCore/PiSmmCore.c +++ b/MdeModulePkg/Core/PiSmmCore/PiSmmCore.c @@ -1,962 +1,962 @@ -/** @file
- SMM Core Main Entry Point
-
- Copyright (c) 2009 - 2023, Intel Corporation. All rights reserved.<BR>
- SPDX-License-Identifier: BSD-2-Clause-Patent
-
-**/
-
-#include "PiSmmCore.h"
-
-//
-// Physical pointer to private structure shared between SMM IPL and the SMM Core
-//
-SMM_CORE_PRIVATE_DATA *gSmmCorePrivate;
-
-//
-// SMM Core global variable for SMM System Table. Only accessed as a physical structure in SMRAM.
-//
-EFI_SMM_SYSTEM_TABLE2 gSmmCoreSmst = {
- {
- SMM_SMST_SIGNATURE,
- EFI_SMM_SYSTEM_TABLE2_REVISION,
- sizeof (gSmmCoreSmst.Hdr)
- },
- NULL, // SmmFirmwareVendor
- 0, // SmmFirmwareRevision
- SmmInstallConfigurationTable,
- {
- {
- (EFI_SMM_CPU_IO2)SmmEfiNotAvailableYetArg5, // SmmMemRead
- (EFI_SMM_CPU_IO2)SmmEfiNotAvailableYetArg5 // SmmMemWrite
- },
- {
- (EFI_SMM_CPU_IO2)SmmEfiNotAvailableYetArg5, // SmmIoRead
- (EFI_SMM_CPU_IO2)SmmEfiNotAvailableYetArg5 // SmmIoWrite
- }
- },
- SmmAllocatePool,
- SmmFreePool,
- SmmAllocatePages,
- SmmFreePages,
- NULL, // SmmStartupThisAp
- 0, // CurrentlyExecutingCpu
- 0, // NumberOfCpus
- NULL, // CpuSaveStateSize
- NULL, // CpuSaveState
- 0, // NumberOfTableEntries
- NULL, // SmmConfigurationTable
- SmmInstallProtocolInterface,
- SmmUninstallProtocolInterface,
- SmmHandleProtocol,
- SmmRegisterProtocolNotify,
- SmmLocateHandle,
- SmmLocateProtocol,
- SmiManage,
- SmiHandlerRegister,
- SmiHandlerUnRegister
-};
-
-//
-// 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
-// SMM IPL are converted to free memory, so the SMM Core must guarantee that is
-// does not touch of the code/data associated with the SMM IPL if this flag is TRUE.
-//
-BOOLEAN mInLegacyBoot = FALSE;
-
-//
-// Flag to determine if it is during S3 resume.
-// It will be set in S3 entry callback and cleared at EndOfS3Resume.
-//
-BOOLEAN mDuringS3Resume = FALSE;
-
-//
-// Flag to determine if platform enabled S3.
-// Get the value from PcdAcpiS3Enable.
-//
-BOOLEAN mAcpiS3Enable = FALSE;
-
-//
-// Table of SMI Handlers that are registered by the SMM Core when it is initialized
-//
-SMM_CORE_SMI_HANDLERS mSmmCoreSmiHandlers[] = {
- { SmmDriverDispatchHandler, &gEfiEventDxeDispatchGuid, NULL, TRUE },
- { SmmReadyToLockHandler, &gEfiDxeSmmReadyToLockProtocolGuid, NULL, TRUE },
- { SmmLegacyBootHandler, &gEfiEventLegacyBootGuid, NULL, FALSE },
- { SmmExitBootServicesHandler, &gEfiEventExitBootServicesGuid, NULL, FALSE },
- { SmmReadyToBootHandler, &gEfiEventReadyToBootGuid, NULL, FALSE },
- { SmmEndOfDxeHandler, &gEfiEndOfDxeEventGroupGuid, NULL, TRUE },
- { NULL, NULL, NULL, FALSE }
-};
-
-//
-// Table of SMI Handlers that are registered by the SMM Core when it is initialized
-//
-SMM_CORE_SMI_HANDLERS mSmmCoreS3SmiHandlers[] = {
- { SmmS3SmmInitDoneHandler, &gEdkiiS3SmmInitDoneGuid, NULL, FALSE },
- { SmmEndOfS3ResumeHandler, &gEdkiiEndOfS3ResumeGuid, NULL, FALSE },
- { NULL, NULL, NULL, FALSE }
-};
-
-UINTN mFullSmramRangeCount;
-EFI_SMRAM_DESCRIPTOR *mFullSmramRanges;
-
-EFI_SMM_DRIVER_ENTRY *mSmmCoreDriverEntry;
-
-EFI_LOADED_IMAGE_PROTOCOL *mSmmCoreLoadedImage;
-
-/**
- Place holder function until all the SMM System Table Service are available.
-
- Note: This function is only used by SMRAM 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
-SmmEfiNotAvailableYetArg5 (
- 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 SMI handler that is called when a Legacy Boot event is signalled. The SMM
- Core uses this signal to know that a Legacy Boot has been performed and that
- gSmmCorePrivate that is shared between the UEFI and SMM execution environments can
- not be accessed from SMM anymore since that structure is considered free memory by
- a legacy OS. Then the SMM Core also install SMM Legacy Boot protocol to notify SMM
- driver that system enter legacy boot.
-
- @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-SMM environment into an SMM environment.
- @param CommBufferSize The size of the CommBuffer.
-
- @return Status Code
-
-**/
-EFI_STATUS
-EFIAPI
-SmmLegacyBootHandler (
- IN EFI_HANDLE DispatchHandle,
- IN CONST VOID *Context OPTIONAL,
- IN OUT VOID *CommBuffer OPTIONAL,
- IN OUT UINTN *CommBufferSize OPTIONAL
- )
-{
- EFI_STATUS Status;
- EFI_HANDLE SmmHandle;
- UINTN Index;
-
- //
- // Install SMM Legacy Boot protocol.
- //
- SmmHandle = NULL;
- Status = SmmInstallProtocolInterface (
- &SmmHandle,
- &gEdkiiSmmLegacyBootProtocolGuid,
- EFI_NATIVE_INTERFACE,
- NULL
- );
-
- mInLegacyBoot = TRUE;
-
- SmiHandlerUnRegister (DispatchHandle);
-
- //
- // It is legacy boot, unregister ExitBootService SMI handler.
- //
- for (Index = 0; mSmmCoreSmiHandlers[Index].HandlerType != NULL; Index++) {
- if (CompareGuid (mSmmCoreSmiHandlers[Index].HandlerType, &gEfiEventExitBootServicesGuid)) {
- SmiHandlerUnRegister (mSmmCoreSmiHandlers[Index].DispatchHandle);
- break;
- }
- }
-
- return Status;
-}
-
-/**
- Software SMI handler that is called when an Exit Boot Services event is signalled.
- Then the SMM Core also install SMM Exit Boot Services protocol to notify SMM driver
- that system enter exit boot services.
-
- @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-SMM environment into an SMM environment.
- @param CommBufferSize The size of the CommBuffer.
-
- @return Status Code
-
-**/
-EFI_STATUS
-EFIAPI
-SmmExitBootServicesHandler (
- IN EFI_HANDLE DispatchHandle,
- IN CONST VOID *Context OPTIONAL,
- IN OUT VOID *CommBuffer OPTIONAL,
- IN OUT UINTN *CommBufferSize OPTIONAL
- )
-{
- EFI_STATUS Status;
- EFI_HANDLE SmmHandle;
- UINTN Index;
-
- //
- // Install SMM Exit Boot Services protocol.
- //
- SmmHandle = NULL;
- Status = SmmInstallProtocolInterface (
- &SmmHandle,
- &gEdkiiSmmExitBootServicesProtocolGuid,
- EFI_NATIVE_INTERFACE,
- NULL
- );
-
- SmiHandlerUnRegister (DispatchHandle);
-
- //
- // It is UEFI boot, unregister LegacyBoot SMI handler.
- //
- for (Index = 0; mSmmCoreSmiHandlers[Index].HandlerType != NULL; Index++) {
- if (CompareGuid (mSmmCoreSmiHandlers[Index].HandlerType, &gEfiEventLegacyBootGuid)) {
- SmiHandlerUnRegister (mSmmCoreSmiHandlers[Index].DispatchHandle);
- break;
- }
- }
-
- return Status;
-}
-
-/**
- Main entry point for an SMM handler dispatch or communicate-based callback.
-
- @param[in] DispatchHandle The unique handle assigned to this handler by SmiHandlerRegister().
- @param[in] Context Points to an optional handler context which was specified when the
- handler was registered.
- @param[in,out] CommBuffer A pointer to a collection of data in memory that will
- be conveyed from a non-SMM environment into an SMM environment.
- @param[in,out] CommBufferSize The size of the CommBuffer.
-
- @retval EFI_SUCCESS The interrupt was handled and quiesced. No other handlers
- should still be called.
- @retval EFI_WARN_INTERRUPT_SOURCE_QUIESCED The interrupt has been quiesced but other handlers should
- still be called.
- @retval EFI_WARN_INTERRUPT_SOURCE_PENDING The interrupt is still pending and other handlers should still
- be called.
- @retval EFI_INTERRUPT_PENDING The interrupt could not be quiesced.
-**/
-EFI_STATUS
-EFIAPI
-SmmS3EntryCallBack (
- IN EFI_HANDLE DispatchHandle,
- IN CONST VOID *Context OPTIONAL,
- IN OUT VOID *CommBuffer OPTIONAL,
- IN OUT UINTN *CommBufferSize OPTIONAL
- )
-{
- mDuringS3Resume = TRUE;
- return EFI_SUCCESS;
-}
-
-/**
- Software SMI handler that is called when an Ready To Boot event is signalled.
- Then the SMM Core also install SMM Ready To Boot protocol to notify SMM driver
- that system enter ready to boot.
-
- @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-SMM environment into an SMM environment.
- @param CommBufferSize The size of the CommBuffer.
-
- @return Status Code
-
-**/
-EFI_STATUS
-EFIAPI
-SmmReadyToBootHandler (
- IN EFI_HANDLE DispatchHandle,
- IN CONST VOID *Context OPTIONAL,
- IN OUT VOID *CommBuffer OPTIONAL,
- IN OUT UINTN *CommBufferSize OPTIONAL
- )
-{
- EFI_STATUS Status;
- EFI_HANDLE SmmHandle;
-
- PERF_CALLBACK_BEGIN (&gEfiEventReadyToBootGuid);
-
- //
- // Install SMM Ready To Boot protocol.
- //
- SmmHandle = NULL;
- Status = SmmInstallProtocolInterface (
- &SmmHandle,
- &gEdkiiSmmReadyToBootProtocolGuid,
- EFI_NATIVE_INTERFACE,
- NULL
- );
-
- SmiHandlerUnRegister (DispatchHandle);
-
- PERF_CALLBACK_END (&gEfiEventReadyToBootGuid);
- return Status;
-}
-
-/**
- Software SMI handler that is called when the DxeSmmReadyToLock protocol is added
- or if gEfiEventReadyToBootGuid is signalled. This function unregisters the
- Software SMIs that are nor required after SMRAM is locked and installs the
- SMM Ready To Lock Protocol so SMM Drivers are informed that SMRAM is about
- to be locked. It also verifies the SMM CPU I/O 2 Protocol has been installed
- and NULLs gBS and gST because they can not longer be used after SMRAM is locked.
-
- @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-SMM environment into an SMM environment.
- @param CommBufferSize The size of the CommBuffer.
-
- @return Status Code
-
-**/
-EFI_STATUS
-EFIAPI
-SmmReadyToLockHandler (
- 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 SmmHandle;
- VOID *Interface;
-
- PERF_CALLBACK_BEGIN (&gEfiDxeSmmReadyToLockProtocolGuid);
-
- //
- // Unregister SMI Handlers that are no required after the SMM driver dispatch is stopped
- //
- for (Index = 0; mSmmCoreSmiHandlers[Index].HandlerType != NULL; Index++) {
- if (mSmmCoreSmiHandlers[Index].UnRegister) {
- SmiHandlerUnRegister (mSmmCoreSmiHandlers[Index].DispatchHandle);
- }
- }
-
- //
- // Install SMM Ready to lock protocol
- //
- SmmHandle = NULL;
- Status = SmmInstallProtocolInterface (
- &SmmHandle,
- &gEfiSmmReadyToLockProtocolGuid,
- EFI_NATIVE_INTERFACE,
- NULL
- );
-
- //
- // Make sure SMM CPU I/O 2 Protocol has been installed into the handle database
- //
- Status = SmmLocateProtocol (&gEfiSmmCpuIo2ProtocolGuid, NULL, &Interface);
-
- //
- // Print a message on a debug build if the SMM CPU I/O 2 Protocol is not installed
- //
- DEBUG_CODE_BEGIN ();
- if (EFI_ERROR (Status)) {
- DEBUG ((DEBUG_ERROR, "\nSMM: SmmCpuIo Arch Protocol not present!!\n"));
- }
-
- DEBUG_CODE_END ();
-
- //
- // 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
- //
- DEBUG_CODE_BEGIN ();
- SmmDisplayDiscoveredNotDispatched ();
- DEBUG_CODE_END ();
-
- //
- // Not allowed to use gST or gBS after lock
- //
- gST = NULL;
- gBS = NULL;
-
- SmramProfileReadyToLock ();
-
- PERF_CALLBACK_END (&gEfiDxeSmmReadyToLockProtocolGuid);
- return Status;
-}
-
-/**
- Software SMI handler that is called when the EndOfDxe event is signalled.
- This function installs the SMM EndOfDxe Protocol so SMM Drivers are informed that
- platform code will invoke 3rd part code.
-
- @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-SMM environment into an SMM environment.
- @param CommBufferSize The size of the CommBuffer.
-
- @return Status Code
-
-**/
-EFI_STATUS
-EFIAPI
-SmmEndOfDxeHandler (
- IN EFI_HANDLE DispatchHandle,
- IN CONST VOID *Context OPTIONAL,
- IN OUT VOID *CommBuffer OPTIONAL,
- IN OUT UINTN *CommBufferSize OPTIONAL
- )
-{
- EFI_STATUS Status;
- EFI_HANDLE SmmHandle;
- EFI_SMM_SX_DISPATCH2_PROTOCOL *SxDispatch;
- EFI_SMM_SX_REGISTER_CONTEXT EntryRegisterContext;
- EFI_HANDLE S3EntryHandle;
-
- DEBUG ((DEBUG_INFO, "SmmEndOfDxeHandler\n"));
-
- PERF_CALLBACK_BEGIN (&gEfiEndOfDxeEventGroupGuid);
-
- //
- // Install SMM EndOfDxe protocol
- //
- SmmHandle = NULL;
- Status = SmmInstallProtocolInterface (
- &SmmHandle,
- &gEfiSmmEndOfDxeProtocolGuid,
- EFI_NATIVE_INTERFACE,
- NULL
- );
-
- if (mAcpiS3Enable) {
- //
- // Locate SmmSxDispatch2 protocol.
- //
- Status = SmmLocateProtocol (
- &gEfiSmmSxDispatch2ProtocolGuid,
- NULL,
- (VOID **)&SxDispatch
- );
- if (!EFI_ERROR (Status) && (SxDispatch != NULL)) {
- //
- // Register a S3 entry callback function to
- // determine if it will be during S3 resume.
- //
- EntryRegisterContext.Type = SxS3;
- EntryRegisterContext.Phase = SxEntry;
- Status = SxDispatch->Register (
- SxDispatch,
- SmmS3EntryCallBack,
- &EntryRegisterContext,
- &S3EntryHandle
- );
- ASSERT_EFI_ERROR (Status);
- }
- }
-
- PERF_CALLBACK_END (&gEfiEndOfDxeEventGroupGuid);
- return EFI_SUCCESS;
-}
-
-/**
- Software SMI handler that is called when the S3SmmInitDone signal is triggered.
- This function installs the SMM S3SmmInitDone Protocol so SMM Drivers are informed that
- S3 SMM initialization has been done.
-
- @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-SMM environment into an SMM environment.
- @param CommBufferSize The size of the CommBuffer.
-
- @return Status Code
-
-**/
-EFI_STATUS
-EFIAPI
-SmmS3SmmInitDoneHandler (
- IN EFI_HANDLE DispatchHandle,
- IN CONST VOID *Context OPTIONAL,
- IN OUT VOID *CommBuffer OPTIONAL,
- IN OUT UINTN *CommBufferSize OPTIONAL
- )
-{
- EFI_STATUS Status;
- EFI_HANDLE SmmHandle;
-
- DEBUG ((DEBUG_INFO, "SmmS3SmmInitDoneHandler\n"));
-
- if (!mDuringS3Resume) {
- DEBUG ((DEBUG_ERROR, "It is not during S3 resume\n"));
- return EFI_SUCCESS;
- }
-
- //
- // Install SMM S3SmmInitDone protocol
- //
- SmmHandle = NULL;
- Status = SmmInstallProtocolInterface (
- &SmmHandle,
- &gEdkiiS3SmmInitDoneGuid,
- EFI_NATIVE_INTERFACE,
- NULL
- );
- ASSERT_EFI_ERROR (Status);
-
- //
- // Uninstall the protocol here because the comsumer just hook the
- // installation event.
- //
- Status = SmmUninstallProtocolInterface (
- SmmHandle,
- &gEdkiiS3SmmInitDoneGuid,
- NULL
- );
- ASSERT_EFI_ERROR (Status);
-
- return Status;
-}
-
-/**
- Software SMI handler that is called when the EndOfS3Resume signal is triggered.
- This function installs the SMM EndOfS3Resume Protocol so SMM Drivers are informed that
- S3 resume has finished.
-
- @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-SMM environment into an SMM environment.
- @param CommBufferSize The size of the CommBuffer.
-
- @return Status Code
-
-**/
-EFI_STATUS
-EFIAPI
-SmmEndOfS3ResumeHandler (
- IN EFI_HANDLE DispatchHandle,
- IN CONST VOID *Context OPTIONAL,
- IN OUT VOID *CommBuffer OPTIONAL,
- IN OUT UINTN *CommBufferSize OPTIONAL
- )
-{
- EFI_STATUS Status;
- EFI_HANDLE SmmHandle;
-
- DEBUG ((DEBUG_INFO, "SmmEndOfS3ResumeHandler\n"));
-
- if (!mDuringS3Resume) {
- DEBUG ((DEBUG_ERROR, "It is not during S3 resume\n"));
- return EFI_SUCCESS;
- }
-
- //
- // Install SMM EndOfS3Resume protocol
- //
- SmmHandle = NULL;
- Status = SmmInstallProtocolInterface (
- &SmmHandle,
- &gEdkiiEndOfS3ResumeGuid,
- EFI_NATIVE_INTERFACE,
- NULL
- );
- ASSERT_EFI_ERROR (Status);
-
- //
- // Uninstall the protocol here because the consumer just hook the
- // installation event.
- //
- Status = SmmUninstallProtocolInterface (
- SmmHandle,
- &gEdkiiEndOfS3ResumeGuid,
- NULL
- );
- ASSERT_EFI_ERROR (Status);
-
- mDuringS3Resume = FALSE;
- return Status;
-}
-
-/**
- Determine if two buffers overlap in memory.
-
- @param[in] Buff1 Pointer to first buffer
- @param[in] Size1 Size of Buff1
- @param[in] Buff2 Pointer to second buffer
- @param[in] Size2 Size of Buff2
-
- @retval TRUE Buffers overlap in memory.
- @retval TRUE Math error. Prevents potential math over and underflows.
- @retval FALSE Buffer doesn't overlap.
-
-**/
-BOOLEAN
-InternalIsBufferOverlapped (
- IN UINT8 *Buff1,
- IN UINTN Size1,
- IN UINT8 *Buff2,
- IN UINTN Size2
- )
-{
- UINTN End1;
- UINTN End2;
- BOOLEAN IsOverUnderflow1;
- BOOLEAN IsOverUnderflow2;
-
- // Check for over or underflow
- IsOverUnderflow1 = EFI_ERROR (SafeUintnAdd ((UINTN)Buff1, Size1, &End1));
- IsOverUnderflow2 = EFI_ERROR (SafeUintnAdd ((UINTN)Buff2, Size2, &End2));
-
- if (IsOverUnderflow1 || IsOverUnderflow2) {
- return TRUE;
- }
-
- //
- // If buff1's end is less than the start of buff2, then it's ok.
- // Also, if buff1's start is beyond buff2's end, then it's ok.
- //
- if ((End1 <= (UINTN)Buff2) || ((UINTN)Buff1 >= End2)) {
- return FALSE;
- }
-
- return TRUE;
-}
-
-/**
- The main entry point to SMM Foundation.
-
- Note: This function is only used by SMRAM invocation. It is never used by DXE invocation.
-
- @param SmmEntryContext Processor information and functionality
- needed by SMM Foundation.
-
-**/
-VOID
-EFIAPI
-SmmEntryPoint (
- IN CONST EFI_SMM_ENTRY_CONTEXT *SmmEntryContext
- )
-{
- EFI_STATUS Status;
- EFI_SMM_COMMUNICATE_HEADER *CommunicateHeader;
- BOOLEAN InLegacyBoot;
- BOOLEAN IsOverlapped;
- BOOLEAN IsOverUnderflow;
- VOID *CommunicationBuffer;
- UINTN BufferSize;
-
- PERF_FUNCTION_BEGIN ();
-
- //
- // Update SMST with contents of the SmmEntryContext structure
- //
- gSmmCoreSmst.SmmStartupThisAp = SmmEntryContext->SmmStartupThisAp;
- gSmmCoreSmst.CurrentlyExecutingCpu = SmmEntryContext->CurrentlyExecutingCpu;
- gSmmCoreSmst.NumberOfCpus = SmmEntryContext->NumberOfCpus;
- gSmmCoreSmst.CpuSaveStateSize = SmmEntryContext->CpuSaveStateSize;
- gSmmCoreSmst.CpuSaveState = SmmEntryContext->CpuSaveState;
-
- //
- // Call platform hook before Smm Dispatch
- //
- PERF_START (NULL, "PlatformHookBeforeSmmDispatch", NULL, 0);
- PlatformHookBeforeSmmDispatch ();
- PERF_END (NULL, "PlatformHookBeforeSmmDispatch", NULL, 0);
-
- //
- // Call memory management hook function
- //
- SmmEntryPointMemoryManagementHook ();
-
- //
- // If a legacy boot has occurred, then make sure gSmmCorePrivate is not accessed
- //
- InLegacyBoot = mInLegacyBoot;
- if (!InLegacyBoot) {
- //
- // Mark the InSmm flag as TRUE, it will be used by SmmBase2 protocol
- //
- gSmmCorePrivate->InSmm = TRUE;
-
- //
- // Check to see if this is a Synchronous SMI sent through the SMM Communication
- // Protocol or an Asynchronous SMI
- //
- CommunicationBuffer = gSmmCorePrivate->CommunicationBuffer;
- BufferSize = gSmmCorePrivate->BufferSize;
- if (CommunicationBuffer != NULL) {
- //
- // Synchronous SMI for SMM Core or request from Communicate protocol
- //
- IsOverlapped = InternalIsBufferOverlapped (
- (UINT8 *)CommunicationBuffer,
- BufferSize,
- (UINT8 *)gSmmCorePrivate,
- sizeof (*gSmmCorePrivate)
- );
- //
- // Check for over or underflows
- //
- IsOverUnderflow = EFI_ERROR (SafeUintnSub (BufferSize, OFFSET_OF (EFI_SMM_COMMUNICATE_HEADER, Data), &BufferSize));
-
- if (!SmmIsBufferOutsideSmmValid ((UINTN)CommunicationBuffer, BufferSize) ||
- IsOverlapped || IsOverUnderflow)
- {
- //
- // If CommunicationBuffer is not in valid address scope,
- // or there is overlap between gSmmCorePrivate and CommunicationBuffer,
- // or there is over or underflow,
- // return EFI_INVALID_PARAMETER
- //
- gSmmCorePrivate->CommunicationBuffer = NULL;
- gSmmCorePrivate->ReturnStatus = EFI_ACCESS_DENIED;
- } else {
- CommunicateHeader = (EFI_SMM_COMMUNICATE_HEADER *)CommunicationBuffer;
- // BufferSize was updated by the SafeUintnSub() call above.
- Status = SmiManage (
- &CommunicateHeader->HeaderGuid,
- NULL,
- CommunicateHeader->Data,
- &BufferSize
- );
- //
- // Update CommunicationBuffer, BufferSize and ReturnStatus
- // Communicate service finished, reset the pointer to CommBuffer to NULL
- //
- gSmmCorePrivate->BufferSize = BufferSize + OFFSET_OF (EFI_SMM_COMMUNICATE_HEADER, Data);
- gSmmCorePrivate->CommunicationBuffer = NULL;
- gSmmCorePrivate->ReturnStatus = (Status == EFI_SUCCESS) ? EFI_SUCCESS : EFI_NOT_FOUND;
- }
- }
- }
-
- //
- // Process Asynchronous SMI sources
- //
- SmiManage (NULL, NULL, NULL, NULL);
-
- //
- // Call platform hook after Smm Dispatch
- //
- PERF_START (NULL, "PlatformHookAfterSmmDispatch", NULL, 0);
- PlatformHookAfterSmmDispatch ();
- PERF_END (NULL, "PlatformHookAfterSmmDispatch", NULL, 0);
-
- //
- // If a legacy boot has occurred, then make sure gSmmCorePrivate is not accessed
- //
- if (!InLegacyBoot) {
- //
- // Clear the InSmm flag as we are going to leave SMM
- //
- gSmmCorePrivate->InSmm = FALSE;
- }
-
- PERF_FUNCTION_END ();
-}
-
-/**
- Install LoadedImage protocol for SMM Core.
-**/
-VOID
-SmmCoreInstallLoadedImage (
- VOID
- )
-{
- EFI_STATUS Status;
- EFI_HANDLE Handle;
-
- //
- // Allocate a Loaded Image Protocol in EfiBootServicesData
- //
- Status = gBS->AllocatePool (EfiBootServicesData, sizeof (EFI_LOADED_IMAGE_PROTOCOL), (VOID **)&mSmmCoreLoadedImage);
- ASSERT_EFI_ERROR (Status);
-
- ZeroMem (mSmmCoreLoadedImage, 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.
- //
- mSmmCoreLoadedImage->Revision = EFI_LOADED_IMAGE_PROTOCOL_REVISION;
- mSmmCoreLoadedImage->ParentHandle = gSmmCorePrivate->SmmIplImageHandle;
- mSmmCoreLoadedImage->SystemTable = gST;
-
- mSmmCoreLoadedImage->ImageBase = (VOID *)(UINTN)gSmmCorePrivate->PiSmmCoreImageBase;
- mSmmCoreLoadedImage->ImageSize = gSmmCorePrivate->PiSmmCoreImageSize;
- mSmmCoreLoadedImage->ImageCodeType = EfiRuntimeServicesCode;
- mSmmCoreLoadedImage->ImageDataType = EfiRuntimeServicesData;
-
- //
- // Create a new image handle in the UEFI handle database for the SMM Driver
- //
- Handle = NULL;
- Status = gBS->InstallMultipleProtocolInterfaces (
- &Handle,
- &gEfiLoadedImageProtocolGuid,
- mSmmCoreLoadedImage,
- NULL
- );
- ASSERT_EFI_ERROR (Status);
-
- //
- // Allocate a Loaded Image Protocol in SMM
- //
- Status = SmmAllocatePool (EfiRuntimeServicesData, sizeof (EFI_SMM_DRIVER_ENTRY), (VOID **)&mSmmCoreDriverEntry);
- ASSERT_EFI_ERROR (Status);
-
- ZeroMem (mSmmCoreDriverEntry, sizeof (EFI_SMM_DRIVER_ENTRY));
- //
- // Fill in the remaining fields of the Loaded Image Protocol instance.
- //
- mSmmCoreDriverEntry->Signature = EFI_SMM_DRIVER_ENTRY_SIGNATURE;
- mSmmCoreDriverEntry->SmmLoadedImage.Revision = EFI_LOADED_IMAGE_PROTOCOL_REVISION;
- mSmmCoreDriverEntry->SmmLoadedImage.ParentHandle = gSmmCorePrivate->SmmIplImageHandle;
- mSmmCoreDriverEntry->SmmLoadedImage.SystemTable = gST;
-
- mSmmCoreDriverEntry->SmmLoadedImage.ImageBase = (VOID *)(UINTN)gSmmCorePrivate->PiSmmCoreImageBase;
- mSmmCoreDriverEntry->SmmLoadedImage.ImageSize = gSmmCorePrivate->PiSmmCoreImageSize;
- mSmmCoreDriverEntry->SmmLoadedImage.ImageCodeType = EfiRuntimeServicesCode;
- mSmmCoreDriverEntry->SmmLoadedImage.ImageDataType = EfiRuntimeServicesData;
-
- mSmmCoreDriverEntry->ImageEntryPoint = gSmmCorePrivate->PiSmmCoreEntryPoint;
- mSmmCoreDriverEntry->ImageBuffer = gSmmCorePrivate->PiSmmCoreImageBase;
- mSmmCoreDriverEntry->NumberOfPage = EFI_SIZE_TO_PAGES ((UINTN)gSmmCorePrivate->PiSmmCoreImageSize);
-
- //
- // Create a new image handle in the SMM handle database for the SMM Driver
- //
- mSmmCoreDriverEntry->SmmImageHandle = NULL;
- Status = SmmInstallProtocolInterface (
- &mSmmCoreDriverEntry->SmmImageHandle,
- &gEfiLoadedImageProtocolGuid,
- EFI_NATIVE_INTERFACE,
- &mSmmCoreDriverEntry->SmmLoadedImage
- );
- ASSERT_EFI_ERROR (Status);
-
- return;
-}
-
-/**
- The Entry Point for SMM Core
-
- Install DXE Protocols and reload SMM Core into SMRAM and register SMM Core
- EntryPoint on the SMI vector.
-
- Note: This function is called for both DXE invocation and SMRAM 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
-SmmMain (
- IN EFI_HANDLE ImageHandle,
- IN EFI_SYSTEM_TABLE *SystemTable
- )
-{
- EFI_STATUS Status;
- UINTN Index;
-
- //
- // Get SMM Core Private context passed in from SMM IPL in ImageHandle.
- //
- gSmmCorePrivate = (SMM_CORE_PRIVATE_DATA *)ImageHandle;
-
- //
- // Fill in SMRAM physical address for the SMM Services Table and the SMM Entry Point.
- //
- gSmmCorePrivate->Smst = &gSmmCoreSmst;
- gSmmCorePrivate->SmmEntryPoint = SmmEntryPoint;
-
- //
- // No need to initialize memory service.
- // It is done in constructor of PiSmmCoreMemoryAllocationLib(),
- // so that the library linked with PiSmmCore can use AllocatePool() in constructor.
- //
-
- SmramProfileInit ();
-
- //
- // Copy FullSmramRanges to SMRAM
- //
- mFullSmramRangeCount = gSmmCorePrivate->SmramRangeCount;
- mFullSmramRanges = AllocatePool (mFullSmramRangeCount * sizeof (EFI_SMRAM_DESCRIPTOR));
- ASSERT (mFullSmramRanges != NULL);
- CopyMem (mFullSmramRanges, gSmmCorePrivate->SmramRanges, mFullSmramRangeCount * sizeof (EFI_SMRAM_DESCRIPTOR));
-
- //
- // Register all SMI Handlers required by the SMM Core
- //
- for (Index = 0; mSmmCoreSmiHandlers[Index].HandlerType != NULL; Index++) {
- Status = SmiHandlerRegister (
- mSmmCoreSmiHandlers[Index].Handler,
- mSmmCoreSmiHandlers[Index].HandlerType,
- &mSmmCoreSmiHandlers[Index].DispatchHandle
- );
- ASSERT_EFI_ERROR (Status);
- }
-
- mAcpiS3Enable = PcdGetBool (PcdAcpiS3Enable);
- if (mAcpiS3Enable) {
- //
- // Register all S3 related SMI Handlers required by the SMM Core
- //
- for (Index = 0; mSmmCoreS3SmiHandlers[Index].HandlerType != NULL; Index++) {
- Status = SmiHandlerRegister (
- mSmmCoreS3SmiHandlers[Index].Handler,
- mSmmCoreS3SmiHandlers[Index].HandlerType,
- &mSmmCoreS3SmiHandlers[Index].DispatchHandle
- );
- ASSERT_EFI_ERROR (Status);
- }
- }
-
- RegisterSmramProfileHandler ();
- SmramProfileInstallProtocol ();
-
- SmmCoreInstallLoadedImage ();
-
- SmmCoreInitializeMemoryAttributesTable ();
-
- SmmCoreInitializeSmiHandlerProfile ();
-
- return EFI_SUCCESS;
-}
+/** @file + SMM Core Main Entry Point + + Copyright (c) 2009 - 2023, Intel Corporation. All rights reserved.<BR> + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "PiSmmCore.h" + +// +// Physical pointer to private structure shared between SMM IPL and the SMM Core +// +SMM_CORE_PRIVATE_DATA *gSmmCorePrivate; + +// +// SMM Core global variable for SMM System Table. Only accessed as a physical structure in SMRAM. +// +EFI_SMM_SYSTEM_TABLE2 gSmmCoreSmst = { + { + SMM_SMST_SIGNATURE, + EFI_SMM_SYSTEM_TABLE2_REVISION, + sizeof (gSmmCoreSmst.Hdr) + }, + NULL, // SmmFirmwareVendor + 0, // SmmFirmwareRevision + SmmInstallConfigurationTable, + { + { + (EFI_SMM_CPU_IO2)SmmEfiNotAvailableYetArg5, // SmmMemRead + (EFI_SMM_CPU_IO2)SmmEfiNotAvailableYetArg5 // SmmMemWrite + }, + { + (EFI_SMM_CPU_IO2)SmmEfiNotAvailableYetArg5, // SmmIoRead + (EFI_SMM_CPU_IO2)SmmEfiNotAvailableYetArg5 // SmmIoWrite + } + }, + SmmAllocatePool, + SmmFreePool, + SmmAllocatePages, + SmmFreePages, + NULL, // SmmStartupThisAp + 0, // CurrentlyExecutingCpu + 0, // NumberOfCpus + NULL, // CpuSaveStateSize + NULL, // CpuSaveState + 0, // NumberOfTableEntries + NULL, // SmmConfigurationTable + SmmInstallProtocolInterface, + SmmUninstallProtocolInterface, + SmmHandleProtocol, + SmmRegisterProtocolNotify, + SmmLocateHandle, + SmmLocateProtocol, + SmiManage, + SmiHandlerRegister, + SmiHandlerUnRegister +}; + +// +// 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 +// SMM IPL are converted to free memory, so the SMM Core must guarantee that is +// does not touch of the code/data associated with the SMM IPL if this flag is TRUE. +// +BOOLEAN mInLegacyBoot = FALSE; + +// +// Flag to determine if it is during S3 resume. +// It will be set in S3 entry callback and cleared at EndOfS3Resume. +// +BOOLEAN mDuringS3Resume = FALSE; + +// +// Flag to determine if platform enabled S3. +// Get the value from PcdAcpiS3Enable. +// +BOOLEAN mAcpiS3Enable = FALSE; + +// +// Table of SMI Handlers that are registered by the SMM Core when it is initialized +// +SMM_CORE_SMI_HANDLERS mSmmCoreSmiHandlers[] = { + { SmmDriverDispatchHandler, &gEfiEventDxeDispatchGuid, NULL, TRUE }, + { SmmReadyToLockHandler, &gEfiDxeSmmReadyToLockProtocolGuid, NULL, TRUE }, + { SmmLegacyBootHandler, &gEfiEventLegacyBootGuid, NULL, FALSE }, + { SmmExitBootServicesHandler, &gEfiEventExitBootServicesGuid, NULL, FALSE }, + { SmmReadyToBootHandler, &gEfiEventReadyToBootGuid, NULL, FALSE }, + { SmmEndOfDxeHandler, &gEfiEndOfDxeEventGroupGuid, NULL, TRUE }, + { NULL, NULL, NULL, FALSE } +}; + +// +// Table of SMI Handlers that are registered by the SMM Core when it is initialized +// +SMM_CORE_SMI_HANDLERS mSmmCoreS3SmiHandlers[] = { + { SmmS3SmmInitDoneHandler, &gEdkiiS3SmmInitDoneGuid, NULL, FALSE }, + { SmmEndOfS3ResumeHandler, &gEdkiiEndOfS3ResumeGuid, NULL, FALSE }, + { NULL, NULL, NULL, FALSE } +}; + +UINTN mFullSmramRangeCount; +EFI_SMRAM_DESCRIPTOR *mFullSmramRanges; + +EFI_SMM_DRIVER_ENTRY *mSmmCoreDriverEntry; + +EFI_LOADED_IMAGE_PROTOCOL *mSmmCoreLoadedImage; + +/** + Place holder function until all the SMM System Table Service are available. + + Note: This function is only used by SMRAM 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 +SmmEfiNotAvailableYetArg5 ( + 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 SMI handler that is called when a Legacy Boot event is signalled. The SMM + Core uses this signal to know that a Legacy Boot has been performed and that + gSmmCorePrivate that is shared between the UEFI and SMM execution environments can + not be accessed from SMM anymore since that structure is considered free memory by + a legacy OS. Then the SMM Core also install SMM Legacy Boot protocol to notify SMM + driver that system enter legacy boot. + + @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-SMM environment into an SMM environment. + @param CommBufferSize The size of the CommBuffer. + + @return Status Code + +**/ +EFI_STATUS +EFIAPI +SmmLegacyBootHandler ( + IN EFI_HANDLE DispatchHandle, + IN CONST VOID *Context OPTIONAL, + IN OUT VOID *CommBuffer OPTIONAL, + IN OUT UINTN *CommBufferSize OPTIONAL + ) +{ + EFI_STATUS Status; + EFI_HANDLE SmmHandle; + UINTN Index; + + // + // Install SMM Legacy Boot protocol. + // + SmmHandle = NULL; + Status = SmmInstallProtocolInterface ( + &SmmHandle, + &gEdkiiSmmLegacyBootProtocolGuid, + EFI_NATIVE_INTERFACE, + NULL + ); + + mInLegacyBoot = TRUE; + + SmiHandlerUnRegister (DispatchHandle); + + // + // It is legacy boot, unregister ExitBootService SMI handler. + // + for (Index = 0; mSmmCoreSmiHandlers[Index].HandlerType != NULL; Index++) { + if (CompareGuid (mSmmCoreSmiHandlers[Index].HandlerType, &gEfiEventExitBootServicesGuid)) { + SmiHandlerUnRegister (mSmmCoreSmiHandlers[Index].DispatchHandle); + break; + } + } + + return Status; +} + +/** + Software SMI handler that is called when an Exit Boot Services event is signalled. + Then the SMM Core also install SMM Exit Boot Services protocol to notify SMM driver + that system enter exit boot services. + + @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-SMM environment into an SMM environment. + @param CommBufferSize The size of the CommBuffer. + + @return Status Code + +**/ +EFI_STATUS +EFIAPI +SmmExitBootServicesHandler ( + IN EFI_HANDLE DispatchHandle, + IN CONST VOID *Context OPTIONAL, + IN OUT VOID *CommBuffer OPTIONAL, + IN OUT UINTN *CommBufferSize OPTIONAL + ) +{ + EFI_STATUS Status; + EFI_HANDLE SmmHandle; + UINTN Index; + + // + // Install SMM Exit Boot Services protocol. + // + SmmHandle = NULL; + Status = SmmInstallProtocolInterface ( + &SmmHandle, + &gEdkiiSmmExitBootServicesProtocolGuid, + EFI_NATIVE_INTERFACE, + NULL + ); + + SmiHandlerUnRegister (DispatchHandle); + + // + // It is UEFI boot, unregister LegacyBoot SMI handler. + // + for (Index = 0; mSmmCoreSmiHandlers[Index].HandlerType != NULL; Index++) { + if (CompareGuid (mSmmCoreSmiHandlers[Index].HandlerType, &gEfiEventLegacyBootGuid)) { + SmiHandlerUnRegister (mSmmCoreSmiHandlers[Index].DispatchHandle); + break; + } + } + + return Status; +} + +/** + Main entry point for an SMM handler dispatch or communicate-based callback. + + @param[in] DispatchHandle The unique handle assigned to this handler by SmiHandlerRegister(). + @param[in] Context Points to an optional handler context which was specified when the + handler was registered. + @param[in,out] CommBuffer A pointer to a collection of data in memory that will + be conveyed from a non-SMM environment into an SMM environment. + @param[in,out] CommBufferSize The size of the CommBuffer. + + @retval EFI_SUCCESS The interrupt was handled and quiesced. No other handlers + should still be called. + @retval EFI_WARN_INTERRUPT_SOURCE_QUIESCED The interrupt has been quiesced but other handlers should + still be called. + @retval EFI_WARN_INTERRUPT_SOURCE_PENDING The interrupt is still pending and other handlers should still + be called. + @retval EFI_INTERRUPT_PENDING The interrupt could not be quiesced. +**/ +EFI_STATUS +EFIAPI +SmmS3EntryCallBack ( + IN EFI_HANDLE DispatchHandle, + IN CONST VOID *Context OPTIONAL, + IN OUT VOID *CommBuffer OPTIONAL, + IN OUT UINTN *CommBufferSize OPTIONAL + ) +{ + mDuringS3Resume = TRUE; + return EFI_SUCCESS; +} + +/** + Software SMI handler that is called when an Ready To Boot event is signalled. + Then the SMM Core also install SMM Ready To Boot protocol to notify SMM driver + that system enter ready to boot. + + @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-SMM environment into an SMM environment. + @param CommBufferSize The size of the CommBuffer. + + @return Status Code + +**/ +EFI_STATUS +EFIAPI +SmmReadyToBootHandler ( + IN EFI_HANDLE DispatchHandle, + IN CONST VOID *Context OPTIONAL, + IN OUT VOID *CommBuffer OPTIONAL, + IN OUT UINTN *CommBufferSize OPTIONAL + ) +{ + EFI_STATUS Status; + EFI_HANDLE SmmHandle; + + PERF_CALLBACK_BEGIN (&gEfiEventReadyToBootGuid); + + // + // Install SMM Ready To Boot protocol. + // + SmmHandle = NULL; + Status = SmmInstallProtocolInterface ( + &SmmHandle, + &gEdkiiSmmReadyToBootProtocolGuid, + EFI_NATIVE_INTERFACE, + NULL + ); + + SmiHandlerUnRegister (DispatchHandle); + + PERF_CALLBACK_END (&gEfiEventReadyToBootGuid); + return Status; +} + +/** + Software SMI handler that is called when the DxeSmmReadyToLock protocol is added + or if gEfiEventReadyToBootGuid is signalled. This function unregisters the + Software SMIs that are nor required after SMRAM is locked and installs the + SMM Ready To Lock Protocol so SMM Drivers are informed that SMRAM is about + to be locked. It also verifies the SMM CPU I/O 2 Protocol has been installed + and NULLs gBS and gST because they can not longer be used after SMRAM is locked. + + @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-SMM environment into an SMM environment. + @param CommBufferSize The size of the CommBuffer. + + @return Status Code + +**/ +EFI_STATUS +EFIAPI +SmmReadyToLockHandler ( + 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 SmmHandle; + VOID *Interface; + + PERF_CALLBACK_BEGIN (&gEfiDxeSmmReadyToLockProtocolGuid); + + // + // Unregister SMI Handlers that are no required after the SMM driver dispatch is stopped + // + for (Index = 0; mSmmCoreSmiHandlers[Index].HandlerType != NULL; Index++) { + if (mSmmCoreSmiHandlers[Index].UnRegister) { + SmiHandlerUnRegister (mSmmCoreSmiHandlers[Index].DispatchHandle); + } + } + + // + // Install SMM Ready to lock protocol + // + SmmHandle = NULL; + Status = SmmInstallProtocolInterface ( + &SmmHandle, + &gEfiSmmReadyToLockProtocolGuid, + EFI_NATIVE_INTERFACE, + NULL + ); + + // + // Make sure SMM CPU I/O 2 Protocol has been installed into the handle database + // + Status = SmmLocateProtocol (&gEfiSmmCpuIo2ProtocolGuid, NULL, &Interface); + + // + // Print a message on a debug build if the SMM CPU I/O 2 Protocol is not installed + // + DEBUG_CODE_BEGIN (); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "\nSMM: SmmCpuIo Arch Protocol not present!!\n")); + } + + DEBUG_CODE_END (); + + // + // 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 + // + DEBUG_CODE_BEGIN (); + SmmDisplayDiscoveredNotDispatched (); + DEBUG_CODE_END (); + + // + // Not allowed to use gST or gBS after lock + // + gST = NULL; + gBS = NULL; + + SmramProfileReadyToLock (); + + PERF_CALLBACK_END (&gEfiDxeSmmReadyToLockProtocolGuid); + return Status; +} + +/** + Software SMI handler that is called when the EndOfDxe event is signalled. + This function installs the SMM EndOfDxe Protocol so SMM Drivers are informed that + platform code will invoke 3rd part code. + + @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-SMM environment into an SMM environment. + @param CommBufferSize The size of the CommBuffer. + + @return Status Code + +**/ +EFI_STATUS +EFIAPI +SmmEndOfDxeHandler ( + IN EFI_HANDLE DispatchHandle, + IN CONST VOID *Context OPTIONAL, + IN OUT VOID *CommBuffer OPTIONAL, + IN OUT UINTN *CommBufferSize OPTIONAL + ) +{ + EFI_STATUS Status; + EFI_HANDLE SmmHandle; + EFI_SMM_SX_DISPATCH2_PROTOCOL *SxDispatch; + EFI_SMM_SX_REGISTER_CONTEXT EntryRegisterContext; + EFI_HANDLE S3EntryHandle; + + DEBUG ((DEBUG_INFO, "SmmEndOfDxeHandler\n")); + + PERF_CALLBACK_BEGIN (&gEfiEndOfDxeEventGroupGuid); + + // + // Install SMM EndOfDxe protocol + // + SmmHandle = NULL; + Status = SmmInstallProtocolInterface ( + &SmmHandle, + &gEfiSmmEndOfDxeProtocolGuid, + EFI_NATIVE_INTERFACE, + NULL + ); + + if (mAcpiS3Enable) { + // + // Locate SmmSxDispatch2 protocol. + // + Status = SmmLocateProtocol ( + &gEfiSmmSxDispatch2ProtocolGuid, + NULL, + (VOID **)&SxDispatch + ); + if (!EFI_ERROR (Status) && (SxDispatch != NULL)) { + // + // Register a S3 entry callback function to + // determine if it will be during S3 resume. + // + EntryRegisterContext.Type = SxS3; + EntryRegisterContext.Phase = SxEntry; + Status = SxDispatch->Register ( + SxDispatch, + SmmS3EntryCallBack, + &EntryRegisterContext, + &S3EntryHandle + ); + ASSERT_EFI_ERROR (Status); + } + } + + PERF_CALLBACK_END (&gEfiEndOfDxeEventGroupGuid); + return EFI_SUCCESS; +} + +/** + Software SMI handler that is called when the S3SmmInitDone signal is triggered. + This function installs the SMM S3SmmInitDone Protocol so SMM Drivers are informed that + S3 SMM initialization has been done. + + @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-SMM environment into an SMM environment. + @param CommBufferSize The size of the CommBuffer. + + @return Status Code + +**/ +EFI_STATUS +EFIAPI +SmmS3SmmInitDoneHandler ( + IN EFI_HANDLE DispatchHandle, + IN CONST VOID *Context OPTIONAL, + IN OUT VOID *CommBuffer OPTIONAL, + IN OUT UINTN *CommBufferSize OPTIONAL + ) +{ + EFI_STATUS Status; + EFI_HANDLE SmmHandle; + + DEBUG ((DEBUG_INFO, "SmmS3SmmInitDoneHandler\n")); + + if (!mDuringS3Resume) { + DEBUG ((DEBUG_ERROR, "It is not during S3 resume\n")); + return EFI_SUCCESS; + } + + // + // Install SMM S3SmmInitDone protocol + // + SmmHandle = NULL; + Status = SmmInstallProtocolInterface ( + &SmmHandle, + &gEdkiiS3SmmInitDoneGuid, + EFI_NATIVE_INTERFACE, + NULL + ); + ASSERT_EFI_ERROR (Status); + + // + // Uninstall the protocol here because the comsumer just hook the + // installation event. + // + Status = SmmUninstallProtocolInterface ( + SmmHandle, + &gEdkiiS3SmmInitDoneGuid, + NULL + ); + ASSERT_EFI_ERROR (Status); + + return Status; +} + +/** + Software SMI handler that is called when the EndOfS3Resume signal is triggered. + This function installs the SMM EndOfS3Resume Protocol so SMM Drivers are informed that + S3 resume has finished. + + @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-SMM environment into an SMM environment. + @param CommBufferSize The size of the CommBuffer. + + @return Status Code + +**/ +EFI_STATUS +EFIAPI +SmmEndOfS3ResumeHandler ( + IN EFI_HANDLE DispatchHandle, + IN CONST VOID *Context OPTIONAL, + IN OUT VOID *CommBuffer OPTIONAL, + IN OUT UINTN *CommBufferSize OPTIONAL + ) +{ + EFI_STATUS Status; + EFI_HANDLE SmmHandle; + + DEBUG ((DEBUG_INFO, "SmmEndOfS3ResumeHandler\n")); + + if (!mDuringS3Resume) { + DEBUG ((DEBUG_ERROR, "It is not during S3 resume\n")); + return EFI_SUCCESS; + } + + // + // Install SMM EndOfS3Resume protocol + // + SmmHandle = NULL; + Status = SmmInstallProtocolInterface ( + &SmmHandle, + &gEdkiiEndOfS3ResumeGuid, + EFI_NATIVE_INTERFACE, + NULL + ); + ASSERT_EFI_ERROR (Status); + + // + // Uninstall the protocol here because the consumer just hook the + // installation event. + // + Status = SmmUninstallProtocolInterface ( + SmmHandle, + &gEdkiiEndOfS3ResumeGuid, + NULL + ); + ASSERT_EFI_ERROR (Status); + + mDuringS3Resume = FALSE; + return Status; +} + +/** + Determine if two buffers overlap in memory. + + @param[in] Buff1 Pointer to first buffer + @param[in] Size1 Size of Buff1 + @param[in] Buff2 Pointer to second buffer + @param[in] Size2 Size of Buff2 + + @retval TRUE Buffers overlap in memory. + @retval TRUE Math error. Prevents potential math over and underflows. + @retval FALSE Buffer doesn't overlap. + +**/ +BOOLEAN +InternalIsBufferOverlapped ( + IN UINT8 *Buff1, + IN UINTN Size1, + IN UINT8 *Buff2, + IN UINTN Size2 + ) +{ + UINTN End1; + UINTN End2; + BOOLEAN IsOverUnderflow1; + BOOLEAN IsOverUnderflow2; + + // Check for over or underflow + IsOverUnderflow1 = EFI_ERROR (SafeUintnAdd ((UINTN)Buff1, Size1, &End1)); + IsOverUnderflow2 = EFI_ERROR (SafeUintnAdd ((UINTN)Buff2, Size2, &End2)); + + if (IsOverUnderflow1 || IsOverUnderflow2) { + return TRUE; + } + + // + // If buff1's end is less than the start of buff2, then it's ok. + // Also, if buff1's start is beyond buff2's end, then it's ok. + // + if ((End1 <= (UINTN)Buff2) || ((UINTN)Buff1 >= End2)) { + return FALSE; + } + + return TRUE; +} + +/** + The main entry point to SMM Foundation. + + Note: This function is only used by SMRAM invocation. It is never used by DXE invocation. + + @param SmmEntryContext Processor information and functionality + needed by SMM Foundation. + +**/ +VOID +EFIAPI +SmmEntryPoint ( + IN CONST EFI_SMM_ENTRY_CONTEXT *SmmEntryContext + ) +{ + EFI_STATUS Status; + EFI_SMM_COMMUNICATE_HEADER *CommunicateHeader; + BOOLEAN InLegacyBoot; + BOOLEAN IsOverlapped; + BOOLEAN IsOverUnderflow; + VOID *CommunicationBuffer; + UINTN BufferSize; + + PERF_FUNCTION_BEGIN (); + + // + // Update SMST with contents of the SmmEntryContext structure + // + gSmmCoreSmst.SmmStartupThisAp = SmmEntryContext->SmmStartupThisAp; + gSmmCoreSmst.CurrentlyExecutingCpu = SmmEntryContext->CurrentlyExecutingCpu; + gSmmCoreSmst.NumberOfCpus = SmmEntryContext->NumberOfCpus; + gSmmCoreSmst.CpuSaveStateSize = SmmEntryContext->CpuSaveStateSize; + gSmmCoreSmst.CpuSaveState = SmmEntryContext->CpuSaveState; + + // + // Call platform hook before Smm Dispatch + // + PERF_START (NULL, "PlatformHookBeforeSmmDispatch", NULL, 0); + PlatformHookBeforeSmmDispatch (); + PERF_END (NULL, "PlatformHookBeforeSmmDispatch", NULL, 0); + + // + // Call memory management hook function + // + SmmEntryPointMemoryManagementHook (); + + // + // If a legacy boot has occurred, then make sure gSmmCorePrivate is not accessed + // + InLegacyBoot = mInLegacyBoot; + if (!InLegacyBoot) { + // + // Mark the InSmm flag as TRUE, it will be used by SmmBase2 protocol + // + gSmmCorePrivate->InSmm = TRUE; + + // + // Check to see if this is a Synchronous SMI sent through the SMM Communication + // Protocol or an Asynchronous SMI + // + CommunicationBuffer = gSmmCorePrivate->CommunicationBuffer; + BufferSize = gSmmCorePrivate->BufferSize; + if (CommunicationBuffer != NULL) { + // + // Synchronous SMI for SMM Core or request from Communicate protocol + // + IsOverlapped = InternalIsBufferOverlapped ( + (UINT8 *)CommunicationBuffer, + BufferSize, + (UINT8 *)gSmmCorePrivate, + sizeof (*gSmmCorePrivate) + ); + // + // Check for over or underflows + // + IsOverUnderflow = EFI_ERROR (SafeUintnSub (BufferSize, OFFSET_OF (EFI_SMM_COMMUNICATE_HEADER, Data), &BufferSize)); + + if (!SmmIsBufferOutsideSmmValid ((UINTN)CommunicationBuffer, BufferSize) || + IsOverlapped || IsOverUnderflow) + { + // + // If CommunicationBuffer is not in valid address scope, + // or there is overlap between gSmmCorePrivate and CommunicationBuffer, + // or there is over or underflow, + // return EFI_INVALID_PARAMETER + // + gSmmCorePrivate->CommunicationBuffer = NULL; + gSmmCorePrivate->ReturnStatus = EFI_ACCESS_DENIED; + } else { + CommunicateHeader = (EFI_SMM_COMMUNICATE_HEADER *)CommunicationBuffer; + // BufferSize was updated by the SafeUintnSub() call above. + Status = SmiManage ( + &CommunicateHeader->HeaderGuid, + NULL, + CommunicateHeader->Data, + &BufferSize + ); + // + // Update CommunicationBuffer, BufferSize and ReturnStatus + // Communicate service finished, reset the pointer to CommBuffer to NULL + // + gSmmCorePrivate->BufferSize = BufferSize + OFFSET_OF (EFI_SMM_COMMUNICATE_HEADER, Data); + gSmmCorePrivate->CommunicationBuffer = NULL; + gSmmCorePrivate->ReturnStatus = (Status == EFI_SUCCESS) ? EFI_SUCCESS : EFI_NOT_FOUND; + } + } + } + + // + // Process Asynchronous SMI sources + // + SmiManage (NULL, NULL, NULL, NULL); + + // + // Call platform hook after Smm Dispatch + // + PERF_START (NULL, "PlatformHookAfterSmmDispatch", NULL, 0); + PlatformHookAfterSmmDispatch (); + PERF_END (NULL, "PlatformHookAfterSmmDispatch", NULL, 0); + + // + // If a legacy boot has occurred, then make sure gSmmCorePrivate is not accessed + // + if (!InLegacyBoot) { + // + // Clear the InSmm flag as we are going to leave SMM + // + gSmmCorePrivate->InSmm = FALSE; + } + + PERF_FUNCTION_END (); +} + +/** + Install LoadedImage protocol for SMM Core. +**/ +VOID +SmmCoreInstallLoadedImage ( + VOID + ) +{ + EFI_STATUS Status; + EFI_HANDLE Handle; + + // + // Allocate a Loaded Image Protocol in EfiBootServicesData + // + Status = gBS->AllocatePool (EfiBootServicesData, sizeof (EFI_LOADED_IMAGE_PROTOCOL), (VOID **)&mSmmCoreLoadedImage); + ASSERT_EFI_ERROR (Status); + + ZeroMem (mSmmCoreLoadedImage, 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. + // + mSmmCoreLoadedImage->Revision = EFI_LOADED_IMAGE_PROTOCOL_REVISION; + mSmmCoreLoadedImage->ParentHandle = gSmmCorePrivate->SmmIplImageHandle; + mSmmCoreLoadedImage->SystemTable = gST; + + mSmmCoreLoadedImage->ImageBase = (VOID *)(UINTN)gSmmCorePrivate->PiSmmCoreImageBase; + mSmmCoreLoadedImage->ImageSize = gSmmCorePrivate->PiSmmCoreImageSize; + mSmmCoreLoadedImage->ImageCodeType = EfiRuntimeServicesCode; + mSmmCoreLoadedImage->ImageDataType = EfiRuntimeServicesData; + + // + // Create a new image handle in the UEFI handle database for the SMM Driver + // + Handle = NULL; + Status = gBS->InstallMultipleProtocolInterfaces ( + &Handle, + &gEfiLoadedImageProtocolGuid, + mSmmCoreLoadedImage, + NULL + ); + ASSERT_EFI_ERROR (Status); + + // + // Allocate a Loaded Image Protocol in SMM + // + Status = SmmAllocatePool (EfiRuntimeServicesData, sizeof (EFI_SMM_DRIVER_ENTRY), (VOID **)&mSmmCoreDriverEntry); + ASSERT_EFI_ERROR (Status); + + ZeroMem (mSmmCoreDriverEntry, sizeof (EFI_SMM_DRIVER_ENTRY)); + // + // Fill in the remaining fields of the Loaded Image Protocol instance. + // + mSmmCoreDriverEntry->Signature = EFI_SMM_DRIVER_ENTRY_SIGNATURE; + mSmmCoreDriverEntry->SmmLoadedImage.Revision = EFI_LOADED_IMAGE_PROTOCOL_REVISION; + mSmmCoreDriverEntry->SmmLoadedImage.ParentHandle = gSmmCorePrivate->SmmIplImageHandle; + mSmmCoreDriverEntry->SmmLoadedImage.SystemTable = gST; + + mSmmCoreDriverEntry->SmmLoadedImage.ImageBase = (VOID *)(UINTN)gSmmCorePrivate->PiSmmCoreImageBase; + mSmmCoreDriverEntry->SmmLoadedImage.ImageSize = gSmmCorePrivate->PiSmmCoreImageSize; + mSmmCoreDriverEntry->SmmLoadedImage.ImageCodeType = EfiRuntimeServicesCode; + mSmmCoreDriverEntry->SmmLoadedImage.ImageDataType = EfiRuntimeServicesData; + + mSmmCoreDriverEntry->ImageEntryPoint = gSmmCorePrivate->PiSmmCoreEntryPoint; + mSmmCoreDriverEntry->ImageBuffer = gSmmCorePrivate->PiSmmCoreImageBase; + mSmmCoreDriverEntry->NumberOfPage = EFI_SIZE_TO_PAGES ((UINTN)gSmmCorePrivate->PiSmmCoreImageSize); + + // + // Create a new image handle in the SMM handle database for the SMM Driver + // + mSmmCoreDriverEntry->SmmImageHandle = NULL; + Status = SmmInstallProtocolInterface ( + &mSmmCoreDriverEntry->SmmImageHandle, + &gEfiLoadedImageProtocolGuid, + EFI_NATIVE_INTERFACE, + &mSmmCoreDriverEntry->SmmLoadedImage + ); + ASSERT_EFI_ERROR (Status); + + return; +} + +/** + The Entry Point for SMM Core + + Install DXE Protocols and reload SMM Core into SMRAM and register SMM Core + EntryPoint on the SMI vector. + + Note: This function is called for both DXE invocation and SMRAM 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 +SmmMain ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + UINTN Index; + + // + // Get SMM Core Private context passed in from SMM IPL in ImageHandle. + // + gSmmCorePrivate = (SMM_CORE_PRIVATE_DATA *)ImageHandle; + + // + // Fill in SMRAM physical address for the SMM Services Table and the SMM Entry Point. + // + gSmmCorePrivate->Smst = &gSmmCoreSmst; + gSmmCorePrivate->SmmEntryPoint = SmmEntryPoint; + + // + // No need to initialize memory service. + // It is done in constructor of PiSmmCoreMemoryAllocationLib(), + // so that the library linked with PiSmmCore can use AllocatePool() in constructor. + // + + SmramProfileInit (); + + // + // Copy FullSmramRanges to SMRAM + // + mFullSmramRangeCount = gSmmCorePrivate->SmramRangeCount; + mFullSmramRanges = AllocatePool (mFullSmramRangeCount * sizeof (EFI_SMRAM_DESCRIPTOR)); + ASSERT (mFullSmramRanges != NULL); + CopyMem (mFullSmramRanges, gSmmCorePrivate->SmramRanges, mFullSmramRangeCount * sizeof (EFI_SMRAM_DESCRIPTOR)); + + // + // Register all SMI Handlers required by the SMM Core + // + for (Index = 0; mSmmCoreSmiHandlers[Index].HandlerType != NULL; Index++) { + Status = SmiHandlerRegister ( + mSmmCoreSmiHandlers[Index].Handler, + mSmmCoreSmiHandlers[Index].HandlerType, + &mSmmCoreSmiHandlers[Index].DispatchHandle + ); + ASSERT_EFI_ERROR (Status); + } + + mAcpiS3Enable = PcdGetBool (PcdAcpiS3Enable); + if (mAcpiS3Enable) { + // + // Register all S3 related SMI Handlers required by the SMM Core + // + for (Index = 0; mSmmCoreS3SmiHandlers[Index].HandlerType != NULL; Index++) { + Status = SmiHandlerRegister ( + mSmmCoreS3SmiHandlers[Index].Handler, + mSmmCoreS3SmiHandlers[Index].HandlerType, + &mSmmCoreS3SmiHandlers[Index].DispatchHandle + ); + ASSERT_EFI_ERROR (Status); + } + } + + RegisterSmramProfileHandler (); + SmramProfileInstallProtocol (); + + SmmCoreInstallLoadedImage (); + + SmmCoreInitializeMemoryAttributesTable (); + + SmmCoreInitializeSmiHandlerProfile (); + + return EFI_SUCCESS; +} diff --git a/MdeModulePkg/Core/PiSmmCore/PiSmmCore.h b/MdeModulePkg/Core/PiSmmCore/PiSmmCore.h index 60073c78b4..295f995b9c 100644 --- a/MdeModulePkg/Core/PiSmmCore/PiSmmCore.h +++ b/MdeModulePkg/Core/PiSmmCore/PiSmmCore.h @@ -1,1355 +1,1355 @@ -/** @file
- The internal header file includes the common header files, defines
- internal structure and functions used by SmmCore module.
-
- Copyright (c) 2009 - 2019, Intel Corporation. All rights reserved.<BR>
- SPDX-License-Identifier: BSD-2-Clause-Patent
-
-**/
-
-#ifndef _SMM_CORE_H_
-#define _SMM_CORE_H_
-
-#include <PiSmm.h>
-
-#include <Protocol/DxeSmmReadyToLock.h>
-#include <Protocol/SmmReadyToLock.h>
-#include <Protocol/SmmEndOfDxe.h>
-#include <Protocol/CpuIo2.h>
-#include <Protocol/SmmCommunication.h>
-#include <Protocol/SmmAccess2.h>
-#include <Protocol/FirmwareVolume2.h>
-#include <Protocol/LoadedImage.h>
-#include <Protocol/DevicePath.h>
-#include <Protocol/Security.h>
-#include <Protocol/Security2.h>
-#include <Protocol/SmmExitBootServices.h>
-#include <Protocol/SmmLegacyBoot.h>
-#include <Protocol/SmmReadyToBoot.h>
-#include <Protocol/SmmMemoryAttribute.h>
-#include <Protocol/SmmSxDispatch2.h>
-
-#include <Guid/Apriori.h>
-#include <Guid/EventGroup.h>
-#include <Guid/EventLegacyBios.h>
-#include <Guid/MemoryProfile.h>
-#include <Guid/LoadModuleAtFixedAddress.h>
-#include <Guid/SmiHandlerProfile.h>
-#include <Guid/EndOfS3Resume.h>
-#include <Guid/S3SmmInitDone.h>
-
-#include <Library/BaseLib.h>
-#include <Library/BaseMemoryLib.h>
-#include <Library/PeCoffLib.h>
-#include <Library/PeCoffGetEntryPointLib.h>
-#include <Library/CacheMaintenanceLib.h>
-#include <Library/DebugLib.h>
-#include <Library/ReportStatusCodeLib.h>
-#include <Library/MemoryAllocationLib.h>
-#include <Library/DevicePathLib.h>
-#include <Library/UefiLib.h>
-#include <Library/UefiBootServicesTableLib.h>
-#include <Library/PcdLib.h>
-#include <Library/SmmCorePlatformHookLib.h>
-#include <Library/PerformanceLib.h>
-#include <Library/HobLib.h>
-#include <Library/SmmMemLib.h>
-#include <Library/SafeIntLib.h>
-
-#include "PiSmmCorePrivateData.h"
-#include "HeapGuard.h"
-
-//
-// Used to build a table of SMI Handlers that the SMM Core registers
-//
-typedef struct {
- EFI_SMM_HANDLER_ENTRY_POINT2 Handler;
- EFI_GUID *HandlerType;
- EFI_HANDLE DispatchHandle;
- BOOLEAN UnRegister;
-} SMM_CORE_SMI_HANDLERS;
-
-//
-// SMM_HANDLER - used for each SMM handler
-//
-
-#define SMI_ENTRY_SIGNATURE SIGNATURE_32('s','m','i','e')
-
-typedef struct {
- UINTN Signature;
- LIST_ENTRY AllEntries; // All entries
-
- EFI_GUID HandlerType; // Type of interrupt
- LIST_ENTRY SmiHandlers; // All handlers
-} SMI_ENTRY;
-
-#define SMI_HANDLER_SIGNATURE SIGNATURE_32('s','m','i','h')
-
-typedef struct {
- UINTN Signature;
- LIST_ENTRY Link; // Link on SMI_ENTRY.SmiHandlers
- EFI_SMM_HANDLER_ENTRY_POINT2 Handler; // The smm handler's entry point
- UINTN CallerAddr; // The address of caller who register the SMI handler.
- SMI_ENTRY *SmiEntry;
- VOID *Context; // for profile
- UINTN ContextSize; // for profile
- BOOLEAN ToRemove; // To remove this SMI_HANDLER later
-} SMI_HANDLER;
-
-//
-// Structure for recording the state of an SMM Driver
-//
-#define EFI_SMM_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;
- EFI_DEVICE_PATH_PROTOCOL *FvFileDevicePath;
- EFI_FIRMWARE_VOLUME2_PROTOCOL *Fv;
-
- 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 SMRAM
- //
- PHYSICAL_ADDRESS ImageEntryPoint;
- //
- // Image Buffer in SMRAM
- //
- PHYSICAL_ADDRESS ImageBuffer;
- //
- // Image Page Number
- //
- UINTN NumberOfPage;
- EFI_HANDLE SmmImageHandle;
- EFI_LOADED_IMAGE_PROTOCOL SmmLoadedImage;
-} EFI_SMM_DRIVER_ENTRY;
-
-#define EFI_HANDLE_SIGNATURE SIGNATURE_32('s','h','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('s','p','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;
- /// Registered notification handlers
- LIST_ENTRY Notify;
-} PROTOCOL_ENTRY;
-
-#define PROTOCOL_INTERFACE_SIGNATURE SIGNATURE_32('s','p','i','f')
-
-///
-/// 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('s','p','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_SMM_NOTIFY_FN Function;
- /// Last position notified
- LIST_ENTRY *Position;
-} PROTOCOL_NOTIFY;
-
-//
-// SMM Core Global Variables
-//
-extern SMM_CORE_PRIVATE_DATA *gSmmCorePrivate;
-extern EFI_SMM_SYSTEM_TABLE2 gSmmCoreSmst;
-extern LIST_ENTRY gHandleList;
-extern EFI_PHYSICAL_ADDRESS gLoadModuleAtFixAddressSmramBase;
-
-/**
- Called to initialize the memory service.
-
- @param SmramRangeCount Number of SMRAM Regions
- @param SmramRanges Pointer to SMRAM Descriptors
-
-**/
-VOID
-SmmInitializeMemoryServices (
- IN UINTN SmramRangeCount,
- IN EFI_SMRAM_DESCRIPTOR *SmramRanges
- );
-
-/**
- The SmmInstallConfigurationTable() 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
-SmmInstallConfigurationTable (
- IN CONST EFI_SMM_SYSTEM_TABLE2 *SystemTable,
- IN CONST EFI_GUID *Guid,
- IN VOID *Table,
- IN UINTN TableSize
- );
-
-/**
- Wrapper function to SmmInstallProtocolInterfaceNotify. 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
-SmmInstallProtocolInterface (
- 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
-SmmAllocatePages (
- 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
- @param NeedGuard Flag to indicate Guard page is needed or not
-
- @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
-SmmInternalAllocatePages (
- IN EFI_ALLOCATE_TYPE Type,
- IN EFI_MEMORY_TYPE MemoryType,
- IN UINTN NumberOfPages,
- OUT EFI_PHYSICAL_ADDRESS *Memory,
- IN BOOLEAN NeedGuard
- );
-
-/**
- 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
-SmmFreePages (
- 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
- @param IsGuarded Flag to indicate if the memory is guarded
- or not
-
- @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
-SmmInternalFreePages (
- IN EFI_PHYSICAL_ADDRESS Memory,
- IN UINTN NumberOfPages,
- IN BOOLEAN IsGuarded
- );
-
-/**
- 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
-SmmAllocatePool (
- 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
-SmmInternalAllocatePool (
- 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
-SmmFreePool (
- 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
-SmmInternalFreePool (
- 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
-SmmInstallProtocolInterfaceNotify (
- 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
-SmmUninstallProtocolInterface (
- 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
-SmmHandleProtocol (
- 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
-SmmRegisterProtocolNotify (
- IN CONST EFI_GUID *Protocol,
- IN EFI_SMM_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
-SmmLocateHandle (
- 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 Registration is NULL return the first Protocol Interface
- you find.
-
- @param Protocol The protocol to search for
- @param Registration Optional Registration Key returned from
- RegisterProtocolNotify()
- @param Interface Return the Protocol interface (instance).
-
- @retval EFI_SUCCESS If a valid Interface is returned
- @retval EFI_INVALID_PARAMETER Invalid parameter
- @retval EFI_NOT_FOUND Protocol interface not found
-
-**/
-EFI_STATUS
-EFIAPI
-SmmLocateProtocol (
- IN EFI_GUID *Protocol,
- IN VOID *Registration OPTIONAL,
- OUT VOID **Interface
- );
-
-/**
- Function returns an array of handles that support the requested protocol
- in a buffer allocated from pool. This is a version of SmmLocateHandle()
- 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
-SmmLocateHandleBuffer (
- IN EFI_LOCATE_SEARCH_TYPE SearchType,
- IN EFI_GUID *Protocol OPTIONAL,
- IN VOID *SearchKey OPTIONAL,
- IN OUT UINTN *NumberHandles,
- OUT EFI_HANDLE **Buffer
- );
-
-/**
- Manage SMI of a particular type.
-
- @param HandlerType Points to the handler type or NULL for root SMI 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 SMI 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
-SmiManage (
- 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 SMM.
-
- @param Handler Handler service function pointer.
- @param HandlerType Points to the handler type or NULL for root SMI 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
-SmiHandlerRegister (
- IN EFI_SMM_HANDLER_ENTRY_POINT2 Handler,
- IN CONST EFI_GUID *HandlerType OPTIONAL,
- OUT EFI_HANDLE *DispatchHandle
- );
-
-/**
- Unregister a handler in SMM.
-
- @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
-SmiHandlerUnRegister (
- IN EFI_HANDLE DispatchHandle
- );
-
-/**
- This function is the main entry point for an SMM 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-SMM environment into an SMM environment.
- @param CommBufferSize The size of the CommBuffer.
-
- @return Status Code
-
-**/
-EFI_STATUS
-EFIAPI
-SmmDriverDispatchHandler (
- 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 SMM 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-SMM environment into an SMM environment.
- @param CommBufferSize The size of the CommBuffer.
-
- @return Status Code
-
-**/
-EFI_STATUS
-EFIAPI
-SmmLegacyBootHandler (
- 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 SMM 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-SMM environment into an SMM environment.
- @param CommBufferSize The size of the CommBuffer.
-
- @return Status Code
-
-**/
-EFI_STATUS
-EFIAPI
-SmmReadyToLockHandler (
- 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 SMM 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-SMM environment into an SMM environment.
- @param CommBufferSize The size of the CommBuffer.
-
- @return Status Code
-
-**/
-EFI_STATUS
-EFIAPI
-SmmEndOfDxeHandler (
- 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 SMM 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-SMM environment into an SMM environment.
- @param CommBufferSize The size of the CommBuffer.
-
- @return Status Code
-
-**/
-EFI_STATUS
-EFIAPI
-SmmExitBootServicesHandler (
- 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 SMM 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-SMM environment into an SMM environment.
- @param CommBufferSize The size of the CommBuffer.
-
- @return Status Code
-
-**/
-EFI_STATUS
-EFIAPI
-SmmReadyToBootHandler (
- IN EFI_HANDLE DispatchHandle,
- IN CONST VOID *Context OPTIONAL,
- IN OUT VOID *CommBuffer OPTIONAL,
- IN OUT UINTN *CommBufferSize OPTIONAL
- );
-
-/**
- Software SMI handler that is called when the S3SmmInitDone signal is triggered.
- This function installs the SMM S3SmmInitDone Protocol so SMM Drivers are informed that
- S3 SMM initialization has been done.
-
- @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-SMM environment into an SMM environment.
- @param CommBufferSize The size of the CommBuffer.
-
- @return Status Code
-
-**/
-EFI_STATUS
-EFIAPI
-SmmS3SmmInitDoneHandler (
- IN EFI_HANDLE DispatchHandle,
- IN CONST VOID *Context OPTIONAL,
- IN OUT VOID *CommBuffer OPTIONAL,
- IN OUT UINTN *CommBufferSize OPTIONAL
- );
-
-/**
- Software SMI handler that is called when the EndOfS3Resume event is trigged.
- This function installs the SMM EndOfS3Resume Protocol so SMM Drivers are informed that
- S3 resume has finished.
-
- @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-SMM environment into an SMM environment.
- @param CommBufferSize The size of the CommBuffer.
-
- @return Status Code
-
-**/
-EFI_STATUS
-EFIAPI
-SmmEndOfS3ResumeHandler (
- 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 SMM 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
-SmmEfiNotAvailableYetArg5 (
- UINTN Arg1,
- UINTN Arg2,
- UINTN Arg3,
- UINTN Arg4,
- UINTN Arg5
- );
-
-//
-// Functions used during debug builds
-//
-
-/**
- Traverse the discovered list for any drivers that were discovered but not loaded
- because the dependency expressions evaluated to false.
-
-**/
-VOID
-SmmDisplayDiscoveredNotDispatched (
- VOID
- );
-
-/**
- Add free SMRAM 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
-SmmAddMemoryRegion (
- 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 *
-SmmFindProtocolEntry (
- IN EFI_GUID *Protocol,
- IN BOOLEAN Create
- );
-
-/**
- Signal event for every protocol in protocol entry.
-
- @param Prot Protocol interface
-
-**/
-VOID
-SmmNotifyProtocol (
- 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 *
-SmmFindProtocolInterface (
- 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 *
-SmmRemoveInterfaceFromProtocol (
- 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
-SmmIsSchedulable (
- IN EFI_SMM_DRIVER_ENTRY *DriverEntry
- );
-
-//
-// SmramProfile
-//
-
-/**
- Initialize SMRAM profile.
-
-**/
-VOID
-SmramProfileInit (
- VOID
- );
-
-/**
- Install SMRAM profile protocol.
-
-**/
-VOID
-SmramProfileInstallProtocol (
- VOID
- );
-
-/**
- Register SMM image to SMRAM profile.
-
- @param DriverEntry SMM image info.
- @param RegisterToDxe Register image to DXE.
-
- @return EFI_SUCCESS Register successfully.
- @return EFI_UNSUPPORTED Memory profile unsupported,
- or memory profile for the image is not required.
- @return EFI_OUT_OF_RESOURCES No enough resource for this register.
-
-**/
-EFI_STATUS
-RegisterSmramProfileImage (
- IN EFI_SMM_DRIVER_ENTRY *DriverEntry,
- IN BOOLEAN RegisterToDxe
- );
-
-/**
- Unregister image from SMRAM profile.
-
- @param DriverEntry SMM image info.
- @param UnregisterToDxe Unregister image from DXE.
-
- @return EFI_SUCCESS Unregister successfully.
- @return EFI_UNSUPPORTED Memory profile unsupported,
- or memory profile for the image is not required.
- @return EFI_NOT_FOUND The image is not found.
-
-**/
-EFI_STATUS
-UnregisterSmramProfileImage (
- IN EFI_SMM_DRIVER_ENTRY *DriverEntry,
- IN BOOLEAN UnregisterToDxe
- );
-
-/**
- Update SMRAM profile information.
-
- @param CallerAddress Address of caller who call Allocate or Free.
- @param Action This Allocate or Free action.
- @param MemoryType Memory type.
- EfiMaxMemoryType means the MemoryType is unknown.
- @param Size Buffer size.
- @param Buffer Buffer address.
- @param ActionString String for memory profile action.
- Only needed for user defined allocate action.
-
- @return EFI_SUCCESS Memory profile is updated.
- @return EFI_UNSUPPORTED Memory profile is unsupported,
- or memory profile for the image is not required,
- or memory profile for the memory type is not required.
- @return EFI_ACCESS_DENIED It is during memory profile data getting.
- @return EFI_ABORTED Memory profile recording is not enabled.
- @return EFI_OUT_OF_RESOURCES No enough resource to update memory profile for allocate action.
- @return EFI_NOT_FOUND No matched allocate info found for free action.
-
-**/
-EFI_STATUS
-EFIAPI
-SmmCoreUpdateProfile (
- IN PHYSICAL_ADDRESS CallerAddress,
- IN MEMORY_PROFILE_ACTION Action,
- IN EFI_MEMORY_TYPE MemoryType, // Valid for AllocatePages/AllocatePool
- IN UINTN Size, // Valid for AllocatePages/FreePages/AllocatePool
- IN VOID *Buffer,
- IN CHAR8 *ActionString OPTIONAL
- );
-
-/**
- Register SMRAM profile handler.
-
-**/
-VOID
-RegisterSmramProfileHandler (
- VOID
- );
-
-/**
- SMRAM profile ready to lock callback function.
-
-**/
-VOID
-SmramProfileReadyToLock (
- VOID
- );
-
-/**
- Initialize MemoryAttributes support.
-**/
-VOID
-EFIAPI
-SmmCoreInitializeMemoryAttributesTable (
- VOID
- );
-
-/**
- This function returns a copy of the current memory map. The map is an array of
- memory descriptors, each of which describes a contiguous block of memory.
-
- @param[in, out] MemoryMapSize A pointer to the size, in bytes, of the
- MemoryMap buffer. On input, this is the size of
- the buffer allocated by the caller. On output,
- it is the size of the buffer returned by the
- firmware if the buffer was large enough, or the
- size of the buffer needed to contain the map if
- the buffer was too small.
- @param[in, out] MemoryMap A pointer to the buffer in which firmware places
- the current memory map.
- @param[out] MapKey A pointer to the location in which firmware
- returns the key for the current memory map.
- @param[out] DescriptorSize A pointer to the location in which firmware
- returns the size, in bytes, of an individual
- EFI_MEMORY_DESCRIPTOR.
- @param[out] DescriptorVersion A pointer to the location in which firmware
- returns the version number associated with the
- EFI_MEMORY_DESCRIPTOR.
-
- @retval EFI_SUCCESS The memory map was returned in the MemoryMap
- buffer.
- @retval EFI_BUFFER_TOO_SMALL The MemoryMap buffer was too small. The current
- buffer size needed to hold the memory map is
- returned in MemoryMapSize.
- @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
-
-**/
-EFI_STATUS
-EFIAPI
-SmmCoreGetMemoryMap (
- IN OUT UINTN *MemoryMapSize,
- IN OUT EFI_MEMORY_DESCRIPTOR *MemoryMap,
- OUT UINTN *MapKey,
- OUT UINTN *DescriptorSize,
- OUT UINT32 *DescriptorVersion
- );
-
-/**
- Initialize SmiHandler profile feature.
-**/
-VOID
-SmmCoreInitializeSmiHandlerProfile (
- VOID
- );
-
-/**
- This function is called by SmmChildDispatcher module to report
- a new SMI handler is registered, to SmmCore.
-
- @param This The protocol instance
- @param HandlerGuid The GUID to identify the type of the handler.
- For the SmmChildDispatch protocol, the HandlerGuid
- must be the GUID of SmmChildDispatch protocol.
- @param Handler The SMI handler.
- @param CallerAddress The address of the module who registers the SMI handler.
- @param Context The context of the SMI handler.
- For the SmmChildDispatch protocol, the Context
- must match the one defined for SmmChildDispatch protocol.
- @param ContextSize The size of the context in bytes.
- For the SmmChildDispatch protocol, the Context
- must match the one defined for SmmChildDispatch protocol.
-
- @retval EFI_SUCCESS The information is recorded.
- @retval EFI_OUT_OF_RESOURCES There is no enough resource to record the information.
-**/
-EFI_STATUS
-EFIAPI
-SmiHandlerProfileRegisterHandler (
- IN SMI_HANDLER_PROFILE_PROTOCOL *This,
- IN EFI_GUID *HandlerGuid,
- IN EFI_SMM_HANDLER_ENTRY_POINT2 Handler,
- IN PHYSICAL_ADDRESS CallerAddress,
- IN VOID *Context OPTIONAL,
- IN UINTN ContextSize OPTIONAL
- );
-
-/**
- This function is called by SmmChildDispatcher module to report
- an existing SMI handler is unregistered, to SmmCore.
-
- @param This The protocol instance
- @param HandlerGuid The GUID to identify the type of the handler.
- For the SmmChildDispatch protocol, the HandlerGuid
- must be the GUID of SmmChildDispatch protocol.
- @param Handler The SMI handler.
- @param Context The context of the SMI handler.
- If it is NOT NULL, it will be used to check what is registered.
- @param ContextSize The size of the context in bytes.
- If Context is NOT NULL, it will be used to check what is registered.
-
- @retval EFI_SUCCESS The original record is removed.
- @retval EFI_NOT_FOUND There is no record for the HandlerGuid and handler.
-**/
-EFI_STATUS
-EFIAPI
-SmiHandlerProfileUnregisterHandler (
- IN SMI_HANDLER_PROFILE_PROTOCOL *This,
- IN EFI_GUID *HandlerGuid,
- IN EFI_SMM_HANDLER_ENTRY_POINT2 Handler,
- IN VOID *Context OPTIONAL,
- IN UINTN ContextSize OPTIONAL
- );
-
-extern UINTN mFullSmramRangeCount;
-extern EFI_SMRAM_DESCRIPTOR *mFullSmramRanges;
-
-extern EFI_SMM_DRIVER_ENTRY *mSmmCoreDriverEntry;
-
-extern EFI_LOADED_IMAGE_PROTOCOL *mSmmCoreLoadedImage;
-
-//
-// Page management
-//
-
-typedef struct {
- LIST_ENTRY Link;
- UINTN NumberOfPages;
-} FREE_PAGE_LIST;
-
-extern LIST_ENTRY mSmmMemoryMap;
-
-//
-// 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)
-
-#define POOL_HEAD_SIGNATURE SIGNATURE_32('s','p','h','d')
-
-typedef struct {
- UINT32 Signature;
- BOOLEAN Available;
- EFI_MEMORY_TYPE Type;
- UINTN Size;
-} POOL_HEADER;
-
-#define POOL_TAIL_SIGNATURE SIGNATURE_32('s','p','t','l')
-
-typedef struct {
- UINT32 Signature;
- UINT32 Reserved;
- UINTN Size;
-} POOL_TAIL;
-
-#define POOL_OVERHEAD (sizeof(POOL_HEADER) + sizeof(POOL_TAIL))
-
-#define HEAD_TO_TAIL(a) \
- ((POOL_TAIL *) (((CHAR8 *) (a)) + (a)->Size - sizeof(POOL_TAIL)));
-
-typedef struct {
- POOL_HEADER Header;
- LIST_ENTRY Link;
-} FREE_POOL_HEADER;
-
-typedef enum {
- SmmPoolTypeCode,
- SmmPoolTypeData,
- SmmPoolTypeMax,
-} SMM_POOL_TYPE;
-
-extern LIST_ENTRY mSmmPoolLists[SmmPoolTypeMax][MAX_POOL_INDEX];
-
-/**
- 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
- );
-
-/**
- Update SMM memory map entry.
-
- @param[in] Type The type of allocation to perform.
- @param[in] Memory The base of memory address.
- @param[in] NumberOfPages The number of pages to allocate.
- @param[in] AddRegion If this memory is new added region.
-**/
-VOID
-ConvertSmmMemoryMapEntry (
- IN EFI_MEMORY_TYPE Type,
- IN EFI_PHYSICAL_ADDRESS Memory,
- IN UINTN NumberOfPages,
- IN BOOLEAN AddRegion
- );
-
-/**
- Internal function. Moves any memory descriptors that are on the
- temporary descriptor stack to heap.
-
-**/
-VOID
-CoreFreeMemoryMapStack (
- VOID
- );
-
-/**
- Frees previous allocated pages.
-
- @param[in] Memory Base address of memory being freed.
- @param[in] NumberOfPages The number of pages to free.
- @param[in] AddRegion If this memory is new added region.
-
- @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
-SmmInternalFreePagesEx (
- IN EFI_PHYSICAL_ADDRESS Memory,
- IN UINTN NumberOfPages,
- IN BOOLEAN AddRegion
- );
-
-/**
- Hook function used to set all Guard pages after entering SMM mode.
-**/
-VOID
-SmmEntryPointMemoryManagementHook (
- VOID
- );
-
-#endif
+/** @file + The internal header file includes the common header files, defines + internal structure and functions used by SmmCore module. + + Copyright (c) 2009 - 2019, Intel Corporation. All rights reserved.<BR> + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef _SMM_CORE_H_ +#define _SMM_CORE_H_ + +#include <PiSmm.h> + +#include <Protocol/DxeSmmReadyToLock.h> +#include <Protocol/SmmReadyToLock.h> +#include <Protocol/SmmEndOfDxe.h> +#include <Protocol/CpuIo2.h> +#include <Protocol/SmmCommunication.h> +#include <Protocol/SmmAccess2.h> +#include <Protocol/FirmwareVolume2.h> +#include <Protocol/LoadedImage.h> +#include <Protocol/DevicePath.h> +#include <Protocol/Security.h> +#include <Protocol/Security2.h> +#include <Protocol/SmmExitBootServices.h> +#include <Protocol/SmmLegacyBoot.h> +#include <Protocol/SmmReadyToBoot.h> +#include <Protocol/SmmMemoryAttribute.h> +#include <Protocol/SmmSxDispatch2.h> + +#include <Guid/Apriori.h> +#include <Guid/EventGroup.h> +#include <Guid/EventLegacyBios.h> +#include <Guid/MemoryProfile.h> +#include <Guid/LoadModuleAtFixedAddress.h> +#include <Guid/SmiHandlerProfile.h> +#include <Guid/EndOfS3Resume.h> +#include <Guid/S3SmmInitDone.h> + +#include <Library/BaseLib.h> +#include <Library/BaseMemoryLib.h> +#include <Library/PeCoffLib.h> +#include <Library/PeCoffGetEntryPointLib.h> +#include <Library/CacheMaintenanceLib.h> +#include <Library/DebugLib.h> +#include <Library/ReportStatusCodeLib.h> +#include <Library/MemoryAllocationLib.h> +#include <Library/DevicePathLib.h> +#include <Library/UefiLib.h> +#include <Library/UefiBootServicesTableLib.h> +#include <Library/PcdLib.h> +#include <Library/SmmCorePlatformHookLib.h> +#include <Library/PerformanceLib.h> +#include <Library/HobLib.h> +#include <Library/SmmMemLib.h> +#include <Library/SafeIntLib.h> + +#include "PiSmmCorePrivateData.h" +#include "HeapGuard.h" + +// +// Used to build a table of SMI Handlers that the SMM Core registers +// +typedef struct { + EFI_SMM_HANDLER_ENTRY_POINT2 Handler; + EFI_GUID *HandlerType; + EFI_HANDLE DispatchHandle; + BOOLEAN UnRegister; +} SMM_CORE_SMI_HANDLERS; + +// +// SMM_HANDLER - used for each SMM handler +// + +#define SMI_ENTRY_SIGNATURE SIGNATURE_32('s','m','i','e') + +typedef struct { + UINTN Signature; + LIST_ENTRY AllEntries; // All entries + + EFI_GUID HandlerType; // Type of interrupt + LIST_ENTRY SmiHandlers; // All handlers +} SMI_ENTRY; + +#define SMI_HANDLER_SIGNATURE SIGNATURE_32('s','m','i','h') + +typedef struct { + UINTN Signature; + LIST_ENTRY Link; // Link on SMI_ENTRY.SmiHandlers + EFI_SMM_HANDLER_ENTRY_POINT2 Handler; // The smm handler's entry point + UINTN CallerAddr; // The address of caller who register the SMI handler. + SMI_ENTRY *SmiEntry; + VOID *Context; // for profile + UINTN ContextSize; // for profile + BOOLEAN ToRemove; // To remove this SMI_HANDLER later +} SMI_HANDLER; + +// +// Structure for recording the state of an SMM Driver +// +#define EFI_SMM_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; + EFI_DEVICE_PATH_PROTOCOL *FvFileDevicePath; + EFI_FIRMWARE_VOLUME2_PROTOCOL *Fv; + + 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 SMRAM + // + PHYSICAL_ADDRESS ImageEntryPoint; + // + // Image Buffer in SMRAM + // + PHYSICAL_ADDRESS ImageBuffer; + // + // Image Page Number + // + UINTN NumberOfPage; + EFI_HANDLE SmmImageHandle; + EFI_LOADED_IMAGE_PROTOCOL SmmLoadedImage; +} EFI_SMM_DRIVER_ENTRY; + +#define EFI_HANDLE_SIGNATURE SIGNATURE_32('s','h','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('s','p','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; + /// Registered notification handlers + LIST_ENTRY Notify; +} PROTOCOL_ENTRY; + +#define PROTOCOL_INTERFACE_SIGNATURE SIGNATURE_32('s','p','i','f') + +/// +/// 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('s','p','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_SMM_NOTIFY_FN Function; + /// Last position notified + LIST_ENTRY *Position; +} PROTOCOL_NOTIFY; + +// +// SMM Core Global Variables +// +extern SMM_CORE_PRIVATE_DATA *gSmmCorePrivate; +extern EFI_SMM_SYSTEM_TABLE2 gSmmCoreSmst; +extern LIST_ENTRY gHandleList; +extern EFI_PHYSICAL_ADDRESS gLoadModuleAtFixAddressSmramBase; + +/** + Called to initialize the memory service. + + @param SmramRangeCount Number of SMRAM Regions + @param SmramRanges Pointer to SMRAM Descriptors + +**/ +VOID +SmmInitializeMemoryServices ( + IN UINTN SmramRangeCount, + IN EFI_SMRAM_DESCRIPTOR *SmramRanges + ); + +/** + The SmmInstallConfigurationTable() 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 +SmmInstallConfigurationTable ( + IN CONST EFI_SMM_SYSTEM_TABLE2 *SystemTable, + IN CONST EFI_GUID *Guid, + IN VOID *Table, + IN UINTN TableSize + ); + +/** + Wrapper function to SmmInstallProtocolInterfaceNotify. 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 +SmmInstallProtocolInterface ( + 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 +SmmAllocatePages ( + 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 + @param NeedGuard Flag to indicate Guard page is needed or not + + @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 +SmmInternalAllocatePages ( + IN EFI_ALLOCATE_TYPE Type, + IN EFI_MEMORY_TYPE MemoryType, + IN UINTN NumberOfPages, + OUT EFI_PHYSICAL_ADDRESS *Memory, + IN BOOLEAN NeedGuard + ); + +/** + 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 +SmmFreePages ( + 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 + @param IsGuarded Flag to indicate if the memory is guarded + or not + + @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 +SmmInternalFreePages ( + IN EFI_PHYSICAL_ADDRESS Memory, + IN UINTN NumberOfPages, + IN BOOLEAN IsGuarded + ); + +/** + 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 +SmmAllocatePool ( + 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 +SmmInternalAllocatePool ( + 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 +SmmFreePool ( + 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 +SmmInternalFreePool ( + 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 +SmmInstallProtocolInterfaceNotify ( + 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 +SmmUninstallProtocolInterface ( + 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 +SmmHandleProtocol ( + 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 +SmmRegisterProtocolNotify ( + IN CONST EFI_GUID *Protocol, + IN EFI_SMM_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 +SmmLocateHandle ( + 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 Registration is NULL return the first Protocol Interface + you find. + + @param Protocol The protocol to search for + @param Registration Optional Registration Key returned from + RegisterProtocolNotify() + @param Interface Return the Protocol interface (instance). + + @retval EFI_SUCCESS If a valid Interface is returned + @retval EFI_INVALID_PARAMETER Invalid parameter + @retval EFI_NOT_FOUND Protocol interface not found + +**/ +EFI_STATUS +EFIAPI +SmmLocateProtocol ( + IN EFI_GUID *Protocol, + IN VOID *Registration OPTIONAL, + OUT VOID **Interface + ); + +/** + Function returns an array of handles that support the requested protocol + in a buffer allocated from pool. This is a version of SmmLocateHandle() + 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 +SmmLocateHandleBuffer ( + IN EFI_LOCATE_SEARCH_TYPE SearchType, + IN EFI_GUID *Protocol OPTIONAL, + IN VOID *SearchKey OPTIONAL, + IN OUT UINTN *NumberHandles, + OUT EFI_HANDLE **Buffer + ); + +/** + Manage SMI of a particular type. + + @param HandlerType Points to the handler type or NULL for root SMI 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 SMI 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 +SmiManage ( + 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 SMM. + + @param Handler Handler service function pointer. + @param HandlerType Points to the handler type or NULL for root SMI 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 +SmiHandlerRegister ( + IN EFI_SMM_HANDLER_ENTRY_POINT2 Handler, + IN CONST EFI_GUID *HandlerType OPTIONAL, + OUT EFI_HANDLE *DispatchHandle + ); + +/** + Unregister a handler in SMM. + + @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 +SmiHandlerUnRegister ( + IN EFI_HANDLE DispatchHandle + ); + +/** + This function is the main entry point for an SMM 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-SMM environment into an SMM environment. + @param CommBufferSize The size of the CommBuffer. + + @return Status Code + +**/ +EFI_STATUS +EFIAPI +SmmDriverDispatchHandler ( + 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 SMM 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-SMM environment into an SMM environment. + @param CommBufferSize The size of the CommBuffer. + + @return Status Code + +**/ +EFI_STATUS +EFIAPI +SmmLegacyBootHandler ( + 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 SMM 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-SMM environment into an SMM environment. + @param CommBufferSize The size of the CommBuffer. + + @return Status Code + +**/ +EFI_STATUS +EFIAPI +SmmReadyToLockHandler ( + 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 SMM 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-SMM environment into an SMM environment. + @param CommBufferSize The size of the CommBuffer. + + @return Status Code + +**/ +EFI_STATUS +EFIAPI +SmmEndOfDxeHandler ( + 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 SMM 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-SMM environment into an SMM environment. + @param CommBufferSize The size of the CommBuffer. + + @return Status Code + +**/ +EFI_STATUS +EFIAPI +SmmExitBootServicesHandler ( + 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 SMM 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-SMM environment into an SMM environment. + @param CommBufferSize The size of the CommBuffer. + + @return Status Code + +**/ +EFI_STATUS +EFIAPI +SmmReadyToBootHandler ( + IN EFI_HANDLE DispatchHandle, + IN CONST VOID *Context OPTIONAL, + IN OUT VOID *CommBuffer OPTIONAL, + IN OUT UINTN *CommBufferSize OPTIONAL + ); + +/** + Software SMI handler that is called when the S3SmmInitDone signal is triggered. + This function installs the SMM S3SmmInitDone Protocol so SMM Drivers are informed that + S3 SMM initialization has been done. + + @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-SMM environment into an SMM environment. + @param CommBufferSize The size of the CommBuffer. + + @return Status Code + +**/ +EFI_STATUS +EFIAPI +SmmS3SmmInitDoneHandler ( + IN EFI_HANDLE DispatchHandle, + IN CONST VOID *Context OPTIONAL, + IN OUT VOID *CommBuffer OPTIONAL, + IN OUT UINTN *CommBufferSize OPTIONAL + ); + +/** + Software SMI handler that is called when the EndOfS3Resume event is trigged. + This function installs the SMM EndOfS3Resume Protocol so SMM Drivers are informed that + S3 resume has finished. + + @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-SMM environment into an SMM environment. + @param CommBufferSize The size of the CommBuffer. + + @return Status Code + +**/ +EFI_STATUS +EFIAPI +SmmEndOfS3ResumeHandler ( + 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 SMM 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 +SmmEfiNotAvailableYetArg5 ( + UINTN Arg1, + UINTN Arg2, + UINTN Arg3, + UINTN Arg4, + UINTN Arg5 + ); + +// +// Functions used during debug builds +// + +/** + Traverse the discovered list for any drivers that were discovered but not loaded + because the dependency expressions evaluated to false. + +**/ +VOID +SmmDisplayDiscoveredNotDispatched ( + VOID + ); + +/** + Add free SMRAM 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 +SmmAddMemoryRegion ( + 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 * +SmmFindProtocolEntry ( + IN EFI_GUID *Protocol, + IN BOOLEAN Create + ); + +/** + Signal event for every protocol in protocol entry. + + @param Prot Protocol interface + +**/ +VOID +SmmNotifyProtocol ( + 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 * +SmmFindProtocolInterface ( + 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 * +SmmRemoveInterfaceFromProtocol ( + 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 +SmmIsSchedulable ( + IN EFI_SMM_DRIVER_ENTRY *DriverEntry + ); + +// +// SmramProfile +// + +/** + Initialize SMRAM profile. + +**/ +VOID +SmramProfileInit ( + VOID + ); + +/** + Install SMRAM profile protocol. + +**/ +VOID +SmramProfileInstallProtocol ( + VOID + ); + +/** + Register SMM image to SMRAM profile. + + @param DriverEntry SMM image info. + @param RegisterToDxe Register image to DXE. + + @return EFI_SUCCESS Register successfully. + @return EFI_UNSUPPORTED Memory profile unsupported, + or memory profile for the image is not required. + @return EFI_OUT_OF_RESOURCES No enough resource for this register. + +**/ +EFI_STATUS +RegisterSmramProfileImage ( + IN EFI_SMM_DRIVER_ENTRY *DriverEntry, + IN BOOLEAN RegisterToDxe + ); + +/** + Unregister image from SMRAM profile. + + @param DriverEntry SMM image info. + @param UnregisterToDxe Unregister image from DXE. + + @return EFI_SUCCESS Unregister successfully. + @return EFI_UNSUPPORTED Memory profile unsupported, + or memory profile for the image is not required. + @return EFI_NOT_FOUND The image is not found. + +**/ +EFI_STATUS +UnregisterSmramProfileImage ( + IN EFI_SMM_DRIVER_ENTRY *DriverEntry, + IN BOOLEAN UnregisterToDxe + ); + +/** + Update SMRAM profile information. + + @param CallerAddress Address of caller who call Allocate or Free. + @param Action This Allocate or Free action. + @param MemoryType Memory type. + EfiMaxMemoryType means the MemoryType is unknown. + @param Size Buffer size. + @param Buffer Buffer address. + @param ActionString String for memory profile action. + Only needed for user defined allocate action. + + @return EFI_SUCCESS Memory profile is updated. + @return EFI_UNSUPPORTED Memory profile is unsupported, + or memory profile for the image is not required, + or memory profile for the memory type is not required. + @return EFI_ACCESS_DENIED It is during memory profile data getting. + @return EFI_ABORTED Memory profile recording is not enabled. + @return EFI_OUT_OF_RESOURCES No enough resource to update memory profile for allocate action. + @return EFI_NOT_FOUND No matched allocate info found for free action. + +**/ +EFI_STATUS +EFIAPI +SmmCoreUpdateProfile ( + IN PHYSICAL_ADDRESS CallerAddress, + IN MEMORY_PROFILE_ACTION Action, + IN EFI_MEMORY_TYPE MemoryType, // Valid for AllocatePages/AllocatePool + IN UINTN Size, // Valid for AllocatePages/FreePages/AllocatePool + IN VOID *Buffer, + IN CHAR8 *ActionString OPTIONAL + ); + +/** + Register SMRAM profile handler. + +**/ +VOID +RegisterSmramProfileHandler ( + VOID + ); + +/** + SMRAM profile ready to lock callback function. + +**/ +VOID +SmramProfileReadyToLock ( + VOID + ); + +/** + Initialize MemoryAttributes support. +**/ +VOID +EFIAPI +SmmCoreInitializeMemoryAttributesTable ( + VOID + ); + +/** + This function returns a copy of the current memory map. The map is an array of + memory descriptors, each of which describes a contiguous block of memory. + + @param[in, out] MemoryMapSize A pointer to the size, in bytes, of the + MemoryMap buffer. On input, this is the size of + the buffer allocated by the caller. On output, + it is the size of the buffer returned by the + firmware if the buffer was large enough, or the + size of the buffer needed to contain the map if + the buffer was too small. + @param[in, out] MemoryMap A pointer to the buffer in which firmware places + the current memory map. + @param[out] MapKey A pointer to the location in which firmware + returns the key for the current memory map. + @param[out] DescriptorSize A pointer to the location in which firmware + returns the size, in bytes, of an individual + EFI_MEMORY_DESCRIPTOR. + @param[out] DescriptorVersion A pointer to the location in which firmware + returns the version number associated with the + EFI_MEMORY_DESCRIPTOR. + + @retval EFI_SUCCESS The memory map was returned in the MemoryMap + buffer. + @retval EFI_BUFFER_TOO_SMALL The MemoryMap buffer was too small. The current + buffer size needed to hold the memory map is + returned in MemoryMapSize. + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value. + +**/ +EFI_STATUS +EFIAPI +SmmCoreGetMemoryMap ( + IN OUT UINTN *MemoryMapSize, + IN OUT EFI_MEMORY_DESCRIPTOR *MemoryMap, + OUT UINTN *MapKey, + OUT UINTN *DescriptorSize, + OUT UINT32 *DescriptorVersion + ); + +/** + Initialize SmiHandler profile feature. +**/ +VOID +SmmCoreInitializeSmiHandlerProfile ( + VOID + ); + +/** + This function is called by SmmChildDispatcher module to report + a new SMI handler is registered, to SmmCore. + + @param This The protocol instance + @param HandlerGuid The GUID to identify the type of the handler. + For the SmmChildDispatch protocol, the HandlerGuid + must be the GUID of SmmChildDispatch protocol. + @param Handler The SMI handler. + @param CallerAddress The address of the module who registers the SMI handler. + @param Context The context of the SMI handler. + For the SmmChildDispatch protocol, the Context + must match the one defined for SmmChildDispatch protocol. + @param ContextSize The size of the context in bytes. + For the SmmChildDispatch protocol, the Context + must match the one defined for SmmChildDispatch protocol. + + @retval EFI_SUCCESS The information is recorded. + @retval EFI_OUT_OF_RESOURCES There is no enough resource to record the information. +**/ +EFI_STATUS +EFIAPI +SmiHandlerProfileRegisterHandler ( + IN SMI_HANDLER_PROFILE_PROTOCOL *This, + IN EFI_GUID *HandlerGuid, + IN EFI_SMM_HANDLER_ENTRY_POINT2 Handler, + IN PHYSICAL_ADDRESS CallerAddress, + IN VOID *Context OPTIONAL, + IN UINTN ContextSize OPTIONAL + ); + +/** + This function is called by SmmChildDispatcher module to report + an existing SMI handler is unregistered, to SmmCore. + + @param This The protocol instance + @param HandlerGuid The GUID to identify the type of the handler. + For the SmmChildDispatch protocol, the HandlerGuid + must be the GUID of SmmChildDispatch protocol. + @param Handler The SMI handler. + @param Context The context of the SMI handler. + If it is NOT NULL, it will be used to check what is registered. + @param ContextSize The size of the context in bytes. + If Context is NOT NULL, it will be used to check what is registered. + + @retval EFI_SUCCESS The original record is removed. + @retval EFI_NOT_FOUND There is no record for the HandlerGuid and handler. +**/ +EFI_STATUS +EFIAPI +SmiHandlerProfileUnregisterHandler ( + IN SMI_HANDLER_PROFILE_PROTOCOL *This, + IN EFI_GUID *HandlerGuid, + IN EFI_SMM_HANDLER_ENTRY_POINT2 Handler, + IN VOID *Context OPTIONAL, + IN UINTN ContextSize OPTIONAL + ); + +extern UINTN mFullSmramRangeCount; +extern EFI_SMRAM_DESCRIPTOR *mFullSmramRanges; + +extern EFI_SMM_DRIVER_ENTRY *mSmmCoreDriverEntry; + +extern EFI_LOADED_IMAGE_PROTOCOL *mSmmCoreLoadedImage; + +// +// Page management +// + +typedef struct { + LIST_ENTRY Link; + UINTN NumberOfPages; +} FREE_PAGE_LIST; + +extern LIST_ENTRY mSmmMemoryMap; + +// +// 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) + +#define POOL_HEAD_SIGNATURE SIGNATURE_32('s','p','h','d') + +typedef struct { + UINT32 Signature; + BOOLEAN Available; + EFI_MEMORY_TYPE Type; + UINTN Size; +} POOL_HEADER; + +#define POOL_TAIL_SIGNATURE SIGNATURE_32('s','p','t','l') + +typedef struct { + UINT32 Signature; + UINT32 Reserved; + UINTN Size; +} POOL_TAIL; + +#define POOL_OVERHEAD (sizeof(POOL_HEADER) + sizeof(POOL_TAIL)) + +#define HEAD_TO_TAIL(a) \ + ((POOL_TAIL *) (((CHAR8 *) (a)) + (a)->Size - sizeof(POOL_TAIL))); + +typedef struct { + POOL_HEADER Header; + LIST_ENTRY Link; +} FREE_POOL_HEADER; + +typedef enum { + SmmPoolTypeCode, + SmmPoolTypeData, + SmmPoolTypeMax, +} SMM_POOL_TYPE; + +extern LIST_ENTRY mSmmPoolLists[SmmPoolTypeMax][MAX_POOL_INDEX]; + +/** + 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 + ); + +/** + Update SMM memory map entry. + + @param[in] Type The type of allocation to perform. + @param[in] Memory The base of memory address. + @param[in] NumberOfPages The number of pages to allocate. + @param[in] AddRegion If this memory is new added region. +**/ +VOID +ConvertSmmMemoryMapEntry ( + IN EFI_MEMORY_TYPE Type, + IN EFI_PHYSICAL_ADDRESS Memory, + IN UINTN NumberOfPages, + IN BOOLEAN AddRegion + ); + +/** + Internal function. Moves any memory descriptors that are on the + temporary descriptor stack to heap. + +**/ +VOID +CoreFreeMemoryMapStack ( + VOID + ); + +/** + Frees previous allocated pages. + + @param[in] Memory Base address of memory being freed. + @param[in] NumberOfPages The number of pages to free. + @param[in] AddRegion If this memory is new added region. + + @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 +SmmInternalFreePagesEx ( + IN EFI_PHYSICAL_ADDRESS Memory, + IN UINTN NumberOfPages, + IN BOOLEAN AddRegion + ); + +/** + Hook function used to set all Guard pages after entering SMM mode. +**/ +VOID +SmmEntryPointMemoryManagementHook ( + VOID + ); + +#endif diff --git a/MdeModulePkg/Core/PiSmmCore/PiSmmCore.inf b/MdeModulePkg/Core/PiSmmCore/PiSmmCore.inf index 75a5934f0c..b31a66d65a 100644 --- a/MdeModulePkg/Core/PiSmmCore/PiSmmCore.inf +++ b/MdeModulePkg/Core/PiSmmCore/PiSmmCore.inf @@ -1,125 +1,125 @@ -## @file
-# This module provide an SMM CIS compliant implementation of SMM Core.
-#
-# Copyright (c) 2009 - 2019, Intel Corporation. All rights reserved.<BR>
-#
-# SPDX-License-Identifier: BSD-2-Clause-Patent
-#
-##
-
-[Defines]
- INF_VERSION = 0x00010005
- BASE_NAME = PiSmmCore
- MODULE_UNI_FILE = PiSmmCore.uni
- FILE_GUID = E94F54CD-81EB-47ed-AEC3-856F5DC157A9
- MODULE_TYPE = SMM_CORE
- VERSION_STRING = 1.0
- PI_SPECIFICATION_VERSION = 0x0001000A
- ENTRY_POINT = SmmMain
-
-# VALID_ARCHITECTURES = IA32 X64
-
-[Sources]
- PiSmmCore.c
- PiSmmCore.h
- PiSmmCorePrivateData.h
- Page.c
- Pool.c
- Handle.c
- Locate.c
- Notify.c
- Dependency.c
- Dispatcher.c
- Smi.c
- InstallConfigurationTable.c
- SmramProfileRecord.c
- MemoryAttributesTable.c
- SmiHandlerProfile.c
- HeapGuard.c
- HeapGuard.h
-
-[Packages]
- MdePkg/MdePkg.dec
- MdeModulePkg/MdeModulePkg.dec
-
-[LibraryClasses]
- UefiDriverEntryPoint
- BaseLib
- BaseMemoryLib
- PeCoffLib
- PeCoffGetEntryPointLib
- CacheMaintenanceLib
- DebugLib
- ReportStatusCodeLib
- DevicePathLib
- UefiLib
- UefiBootServicesTableLib
- MemoryAllocationLib
- PcdLib
- SmmCorePlatformHookLib
- PerformanceLib
- HobLib
- SmmMemLib
- SafeIntLib
- ImagePropertiesRecordLib
-
-[Protocols]
- gEfiDxeSmmReadyToLockProtocolGuid ## UNDEFINED # SmiHandlerRegister
- gEfiSmmReadyToLockProtocolGuid ## PRODUCES
- gEfiSmmCpuIo2ProtocolGuid ## CONSUMES
- gEfiFirmwareVolume2ProtocolGuid ## CONSUMES
- gEfiSmmEndOfDxeProtocolGuid ## PRODUCES
- gEfiSecurityArchProtocolGuid ## SOMETIMES_CONSUMES
- gEfiSecurity2ArchProtocolGuid ## SOMETIMES_CONSUMES
- gEfiLoadedImageProtocolGuid ## PRODUCES
- gEfiDevicePathProtocolGuid ## CONSUMES
- gEdkiiSmmExitBootServicesProtocolGuid ## SOMETIMES_PRODUCES
- gEdkiiSmmLegacyBootProtocolGuid ## SOMETIMES_PRODUCES
- gEdkiiSmmReadyToBootProtocolGuid ## PRODUCES
-
- gEfiSmmSwDispatch2ProtocolGuid ## SOMETIMES_CONSUMES
- gEfiSmmSxDispatch2ProtocolGuid ## SOMETIMES_CONSUMES
- gEfiSmmPowerButtonDispatch2ProtocolGuid ## SOMETIMES_CONSUMES
- gEfiSmmStandbyButtonDispatch2ProtocolGuid ## SOMETIMES_CONSUMES
- gEfiSmmPeriodicTimerDispatch2ProtocolGuid ## SOMETIMES_CONSUMES
- gEfiSmmGpiDispatch2ProtocolGuid ## SOMETIMES_CONSUMES
- gEfiSmmIoTrapDispatch2ProtocolGuid ## SOMETIMES_CONSUMES
- gEfiSmmUsbDispatch2ProtocolGuid ## SOMETIMES_CONSUMES
- gEdkiiSmmMemoryAttributeProtocolGuid ## CONSUMES
- gEfiSmmSxDispatch2ProtocolGuid ## SOMETIMES_CONSUMES
-
-[Pcd]
- gEfiMdeModulePkgTokenSpaceGuid.PcdLoadFixAddressSmmCodePageNumber ## SOMETIMES_CONSUMES
- gEfiMdeModulePkgTokenSpaceGuid.PcdLoadModuleAtFixAddressEnable ## CONSUMES
- gEfiMdeModulePkgTokenSpaceGuid.PcdMemoryProfileMemoryType ## CONSUMES
- gEfiMdeModulePkgTokenSpaceGuid.PcdMemoryProfilePropertyMask ## CONSUMES
- gEfiMdeModulePkgTokenSpaceGuid.PcdMemoryProfileDriverPath ## CONSUMES
- gEfiMdeModulePkgTokenSpaceGuid.PcdSmiHandlerProfilePropertyMask ## CONSUMES
- gEfiMdeModulePkgTokenSpaceGuid.PcdHeapGuardPageType ## CONSUMES
- gEfiMdeModulePkgTokenSpaceGuid.PcdHeapGuardPoolType ## CONSUMES
- gEfiMdeModulePkgTokenSpaceGuid.PcdHeapGuardPropertyMask ## CONSUMES
- gEfiMdeModulePkgTokenSpaceGuid.PcdAcpiS3Enable ## CONSUMES
-
-[Guids]
- gAprioriGuid ## SOMETIMES_CONSUMES ## File
- gEfiEventDxeDispatchGuid ## PRODUCES ## GUID # SmiHandlerRegister
- gEfiEventLegacyBootGuid ## PRODUCES ## GUID # SmiHandlerRegister
- gEfiEventExitBootServicesGuid ## PRODUCES ## GUID # SmiHandlerRegister
- gEfiEventReadyToBootGuid ## PRODUCES ## GUID # SmiHandlerRegister
- gEfiEndOfDxeEventGroupGuid ## PRODUCES ## GUID # SmiHandlerRegister
- ## SOMETIMES_CONSUMES ## GUID # Locate protocol
- ## SOMETIMES_PRODUCES ## GUID # SmiHandlerRegister
- gEdkiiMemoryProfileGuid
- ## SOMETIMES_PRODUCES ## GUID # Install protocol
- gEdkiiSmmMemoryProfileGuid
- gEdkiiPiSmmMemoryAttributesTableGuid ## PRODUCES ## SystemTable
- ## SOMETIMES_CONSUMES ## SystemTable
- gLoadFixedAddressConfigurationTableGuid
- ## SOMETIMES_PRODUCES ## GUID # Install protocol
- ## SOMETIMES_PRODUCES ## GUID # SmiHandlerRegister
- gSmiHandlerProfileGuid
- gEdkiiEndOfS3ResumeGuid ## SOMETIMES_PRODUCES ## GUID # Install protocol
- gEdkiiS3SmmInitDoneGuid ## SOMETIMES_PRODUCES ## GUID # Install protocol
-
-[UserExtensions.TianoCore."ExtraFiles"]
- PiSmmCoreExtra.uni
+## @file +# This module provide an SMM CIS compliant implementation of SMM Core. +# +# Copyright (c) 2009 - 2019, Intel Corporation. All rights reserved.<BR> +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = PiSmmCore + MODULE_UNI_FILE = PiSmmCore.uni + FILE_GUID = E94F54CD-81EB-47ed-AEC3-856F5DC157A9 + MODULE_TYPE = SMM_CORE + VERSION_STRING = 1.0 + PI_SPECIFICATION_VERSION = 0x0001000A + ENTRY_POINT = SmmMain + +# VALID_ARCHITECTURES = IA32 X64 + +[Sources] + PiSmmCore.c + PiSmmCore.h + PiSmmCorePrivateData.h + Page.c + Pool.c + Handle.c + Locate.c + Notify.c + Dependency.c + Dispatcher.c + Smi.c + InstallConfigurationTable.c + SmramProfileRecord.c + MemoryAttributesTable.c + SmiHandlerProfile.c + HeapGuard.c + HeapGuard.h + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + +[LibraryClasses] + UefiDriverEntryPoint + BaseLib + BaseMemoryLib + PeCoffLib + PeCoffGetEntryPointLib + CacheMaintenanceLib + DebugLib + ReportStatusCodeLib + DevicePathLib + UefiLib + UefiBootServicesTableLib + MemoryAllocationLib + PcdLib + SmmCorePlatformHookLib + PerformanceLib + HobLib + SmmMemLib + SafeIntLib + ImagePropertiesRecordLib + +[Protocols] + gEfiDxeSmmReadyToLockProtocolGuid ## UNDEFINED # SmiHandlerRegister + gEfiSmmReadyToLockProtocolGuid ## PRODUCES + gEfiSmmCpuIo2ProtocolGuid ## CONSUMES + gEfiFirmwareVolume2ProtocolGuid ## CONSUMES + gEfiSmmEndOfDxeProtocolGuid ## PRODUCES + gEfiSecurityArchProtocolGuid ## SOMETIMES_CONSUMES + gEfiSecurity2ArchProtocolGuid ## SOMETIMES_CONSUMES + gEfiLoadedImageProtocolGuid ## PRODUCES + gEfiDevicePathProtocolGuid ## CONSUMES + gEdkiiSmmExitBootServicesProtocolGuid ## SOMETIMES_PRODUCES + gEdkiiSmmLegacyBootProtocolGuid ## SOMETIMES_PRODUCES + gEdkiiSmmReadyToBootProtocolGuid ## PRODUCES + + gEfiSmmSwDispatch2ProtocolGuid ## SOMETIMES_CONSUMES + gEfiSmmSxDispatch2ProtocolGuid ## SOMETIMES_CONSUMES + gEfiSmmPowerButtonDispatch2ProtocolGuid ## SOMETIMES_CONSUMES + gEfiSmmStandbyButtonDispatch2ProtocolGuid ## SOMETIMES_CONSUMES + gEfiSmmPeriodicTimerDispatch2ProtocolGuid ## SOMETIMES_CONSUMES + gEfiSmmGpiDispatch2ProtocolGuid ## SOMETIMES_CONSUMES + gEfiSmmIoTrapDispatch2ProtocolGuid ## SOMETIMES_CONSUMES + gEfiSmmUsbDispatch2ProtocolGuid ## SOMETIMES_CONSUMES + gEdkiiSmmMemoryAttributeProtocolGuid ## CONSUMES + gEfiSmmSxDispatch2ProtocolGuid ## SOMETIMES_CONSUMES + +[Pcd] + gEfiMdeModulePkgTokenSpaceGuid.PcdLoadFixAddressSmmCodePageNumber ## SOMETIMES_CONSUMES + gEfiMdeModulePkgTokenSpaceGuid.PcdLoadModuleAtFixAddressEnable ## CONSUMES + gEfiMdeModulePkgTokenSpaceGuid.PcdMemoryProfileMemoryType ## CONSUMES + gEfiMdeModulePkgTokenSpaceGuid.PcdMemoryProfilePropertyMask ## CONSUMES + gEfiMdeModulePkgTokenSpaceGuid.PcdMemoryProfileDriverPath ## CONSUMES + gEfiMdeModulePkgTokenSpaceGuid.PcdSmiHandlerProfilePropertyMask ## CONSUMES + gEfiMdeModulePkgTokenSpaceGuid.PcdHeapGuardPageType ## CONSUMES + gEfiMdeModulePkgTokenSpaceGuid.PcdHeapGuardPoolType ## CONSUMES + gEfiMdeModulePkgTokenSpaceGuid.PcdHeapGuardPropertyMask ## CONSUMES + gEfiMdeModulePkgTokenSpaceGuid.PcdAcpiS3Enable ## CONSUMES + +[Guids] + gAprioriGuid ## SOMETIMES_CONSUMES ## File + gEfiEventDxeDispatchGuid ## PRODUCES ## GUID # SmiHandlerRegister + gEfiEventLegacyBootGuid ## PRODUCES ## GUID # SmiHandlerRegister + gEfiEventExitBootServicesGuid ## PRODUCES ## GUID # SmiHandlerRegister + gEfiEventReadyToBootGuid ## PRODUCES ## GUID # SmiHandlerRegister + gEfiEndOfDxeEventGroupGuid ## PRODUCES ## GUID # SmiHandlerRegister + ## SOMETIMES_CONSUMES ## GUID # Locate protocol + ## SOMETIMES_PRODUCES ## GUID # SmiHandlerRegister + gEdkiiMemoryProfileGuid + ## SOMETIMES_PRODUCES ## GUID # Install protocol + gEdkiiSmmMemoryProfileGuid + gEdkiiPiSmmMemoryAttributesTableGuid ## PRODUCES ## SystemTable + ## SOMETIMES_CONSUMES ## SystemTable + gLoadFixedAddressConfigurationTableGuid + ## SOMETIMES_PRODUCES ## GUID # Install protocol + ## SOMETIMES_PRODUCES ## GUID # SmiHandlerRegister + gSmiHandlerProfileGuid + gEdkiiEndOfS3ResumeGuid ## SOMETIMES_PRODUCES ## GUID # Install protocol + gEdkiiS3SmmInitDoneGuid ## SOMETIMES_PRODUCES ## GUID # Install protocol + +[UserExtensions.TianoCore."ExtraFiles"] + PiSmmCoreExtra.uni diff --git a/MdeModulePkg/Core/PiSmmCore/PiSmmCore.uni b/MdeModulePkg/Core/PiSmmCore/PiSmmCore.uni index 9f11394c40..3345a20d34 100644 --- a/MdeModulePkg/Core/PiSmmCore/PiSmmCore.uni +++ b/MdeModulePkg/Core/PiSmmCore/PiSmmCore.uni @@ -1,16 +1,16 @@ -// /** @file
-// This module provide an SMM CIS compliant implementation of SMM Core.
-//
-// This module provide an SMM CIS compliant implementation of SMM Core.
-//
-// Copyright (c) 2009 - 2014, Intel Corporation. All rights reserved.<BR>
-//
-// SPDX-License-Identifier: BSD-2-Clause-Patent
-//
-// **/
-
-
-#string STR_MODULE_ABSTRACT #language en-US "Provides an SMM CIS compliant implementation of SMM Core"
-
-#string STR_MODULE_DESCRIPTION #language en-US "This module provide an SMM CIS compliant implementation of SMM Core."
-
+// /** @file +// This module provide an SMM CIS compliant implementation of SMM Core. +// +// This module provide an SMM CIS compliant implementation of SMM Core. +// +// Copyright (c) 2009 - 2014, Intel Corporation. All rights reserved.<BR> +// +// SPDX-License-Identifier: BSD-2-Clause-Patent +// +// **/ + + +#string STR_MODULE_ABSTRACT #language en-US "Provides an SMM CIS compliant implementation of SMM Core" + +#string STR_MODULE_DESCRIPTION #language en-US "This module provide an SMM CIS compliant implementation of SMM Core." + diff --git a/MdeModulePkg/Core/PiSmmCore/PiSmmCoreExtra.uni b/MdeModulePkg/Core/PiSmmCore/PiSmmCoreExtra.uni index 44bf418ed7..f6cb0b5023 100644 --- a/MdeModulePkg/Core/PiSmmCore/PiSmmCoreExtra.uni +++ b/MdeModulePkg/Core/PiSmmCore/PiSmmCoreExtra.uni @@ -1,14 +1,14 @@ -// /** @file
-// PiSmmCore Localized Strings and Content
-//
-// Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.<BR>
-//
-// SPDX-License-Identifier: BSD-2-Clause-Patent
-//
-// **/
-
-#string STR_PROPERTIES_MODULE_NAME
-#language en-US
-"Core SMM Services Driver"
-
-
+// /** @file +// PiSmmCore Localized Strings and Content +// +// Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.<BR> +// +// SPDX-License-Identifier: BSD-2-Clause-Patent +// +// **/ + +#string STR_PROPERTIES_MODULE_NAME +#language en-US +"Core SMM Services Driver" + + diff --git a/MdeModulePkg/Core/PiSmmCore/PiSmmCorePrivateData.h b/MdeModulePkg/Core/PiSmmCore/PiSmmCorePrivateData.h index d8fe2dd9b9..6c66b2a248 100644 --- a/MdeModulePkg/Core/PiSmmCore/PiSmmCorePrivateData.h +++ b/MdeModulePkg/Core/PiSmmCore/PiSmmCorePrivateData.h @@ -1,119 +1,119 @@ -/** @file
- The internal header file that declared a data structure that is shared
- between the SMM IPL and the SMM Core.
-
- Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.<BR>
- SPDX-License-Identifier: BSD-2-Clause-Patent
-
-**/
-
-#ifndef _PI_SMM_CORE_PRIVATE_DATA_H_
-#define _PI_SMM_CORE_PRIVATE_DATA_H_
-
-///
-/// Define values for the communications buffer used when gEfiEventDxeDispatchGuid is
-/// event signaled. This event is signaled by the DXE Core each time the DXE Core
-/// dispatcher has completed its work. When this event is signaled, the SMM Core
-/// if notified, so the SMM Core can dispatch SMM drivers. If COMM_BUFFER_SMM_DISPATCH_ERROR
-/// is returned in the communication buffer, then an error occurred dispatching SMM
-/// Drivers. If COMM_BUFFER_SMM_DISPATCH_SUCCESS is returned, then the SMM Core
-/// dispatched all the drivers it could. If COMM_BUFFER_SMM_DISPATCH_RESTART is
-/// returned, then the SMM Core just dispatched the SMM Driver that registered
-/// the SMM Entry Point enabling the use of SMM Mode. In this case, the SMM Core
-/// should be notified again to dispatch more SMM Drivers using SMM Mode.
-///
-#define COMM_BUFFER_SMM_DISPATCH_ERROR 0x00
-#define COMM_BUFFER_SMM_DISPATCH_SUCCESS 0x01
-#define COMM_BUFFER_SMM_DISPATCH_RESTART 0x02
-
-///
-/// Signature for the private structure shared between the SMM IPL and the SMM Core
-///
-#define SMM_CORE_PRIVATE_DATA_SIGNATURE SIGNATURE_32 ('s', 'm', 'm', 'c')
-
-///
-/// Private structure that is used to share information between the SMM IPL and
-/// the SMM Core. This structure is allocated from memory of type EfiRuntimeServicesData.
-/// Since runtime memory types are converted to available memory when a legacy boot
-/// is performed, the SMM Core must not access any fields of this structure if a legacy
-/// boot is performed. As a result, the SMM IPL must create an event notification
-/// for the Legacy Boot event and notify the SMM Core that a legacy boot is being
-/// performed. The SMM Core can then use this information to filter accesses to
-/// thos structure.
-///
-typedef struct {
- UINTN Signature;
-
- ///
- /// The ImageHandle passed into the entry point of the SMM IPL. This ImageHandle
- /// is used by the SMM Core to fill in the ParentImageHandle field of the Loaded
- /// Image Protocol for each SMM Driver that is dispatched by the SMM Core.
- ///
- EFI_HANDLE SmmIplImageHandle;
-
- ///
- /// The number of SMRAM ranges passed from the SMM IPL to the SMM Core. The SMM
- /// Core uses these ranges of SMRAM to initialize the SMM Core memory manager.
- ///
- UINTN SmramRangeCount;
-
- ///
- /// A table of SMRAM ranges passed from the SMM IPL to the SMM Core. The SMM
- /// Core uses these ranges of SMRAM to initialize the SMM Core memory manager.
- ///
- EFI_SMRAM_DESCRIPTOR *SmramRanges;
-
- ///
- /// The SMM Foundation Entry Point. The SMM Core fills in this field when the
- /// SMM Core is initialized. The SMM IPL is responsible for registering this entry
- /// point with the SMM Configuration Protocol. The SMM Configuration Protocol may
- /// not be available at the time the SMM IPL and SMM Core are started, so the SMM IPL
- /// sets up a protocol notification on the SMM Configuration Protocol and registers
- /// the SMM Foundation Entry Point as soon as the SMM Configuration Protocol is
- /// available.
- ///
- EFI_SMM_ENTRY_POINT SmmEntryPoint;
-
- ///
- /// Boolean flag set to TRUE while an SMI is being processed by the SMM Core.
- ///
- BOOLEAN SmmEntryPointRegistered;
-
- ///
- /// Boolean flag set to TRUE while an SMI is being processed by the SMM Core.
- ///
- BOOLEAN InSmm;
-
- ///
- /// This field is set by the SMM Core then the SMM Core is initialized. This field is
- /// used by the SMM Base 2 Protocol and SMM Communication Protocol implementations in
- /// the SMM IPL.
- ///
- EFI_SMM_SYSTEM_TABLE2 *Smst;
-
- ///
- /// This field is used by the SMM Communication Protocol to pass a buffer into
- /// a software SMI handler and for the software SMI handler to pass a buffer back to
- /// the caller of the SMM Communication Protocol.
- ///
- VOID *CommunicationBuffer;
-
- ///
- /// This field is used by the SMM Communication Protocol to pass the size of a buffer,
- /// in bytes, into a software SMI handler and for the software SMI handler to pass the
- /// size, in bytes, of a buffer back to the caller of the SMM Communication Protocol.
- ///
- UINTN BufferSize;
-
- ///
- /// This field is used by the SMM Communication Protocol to pass the return status from
- /// a software SMI handler back to the caller of the SMM Communication Protocol.
- ///
- EFI_STATUS ReturnStatus;
-
- EFI_PHYSICAL_ADDRESS PiSmmCoreImageBase;
- UINT64 PiSmmCoreImageSize;
- EFI_PHYSICAL_ADDRESS PiSmmCoreEntryPoint;
-} SMM_CORE_PRIVATE_DATA;
-
-#endif
+/** @file + The internal header file that declared a data structure that is shared + between the SMM IPL and the SMM Core. + + Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.<BR> + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef _PI_SMM_CORE_PRIVATE_DATA_H_ +#define _PI_SMM_CORE_PRIVATE_DATA_H_ + +/// +/// Define values for the communications buffer used when gEfiEventDxeDispatchGuid is +/// event signaled. This event is signaled by the DXE Core each time the DXE Core +/// dispatcher has completed its work. When this event is signaled, the SMM Core +/// if notified, so the SMM Core can dispatch SMM drivers. If COMM_BUFFER_SMM_DISPATCH_ERROR +/// is returned in the communication buffer, then an error occurred dispatching SMM +/// Drivers. If COMM_BUFFER_SMM_DISPATCH_SUCCESS is returned, then the SMM Core +/// dispatched all the drivers it could. If COMM_BUFFER_SMM_DISPATCH_RESTART is +/// returned, then the SMM Core just dispatched the SMM Driver that registered +/// the SMM Entry Point enabling the use of SMM Mode. In this case, the SMM Core +/// should be notified again to dispatch more SMM Drivers using SMM Mode. +/// +#define COMM_BUFFER_SMM_DISPATCH_ERROR 0x00 +#define COMM_BUFFER_SMM_DISPATCH_SUCCESS 0x01 +#define COMM_BUFFER_SMM_DISPATCH_RESTART 0x02 + +/// +/// Signature for the private structure shared between the SMM IPL and the SMM Core +/// +#define SMM_CORE_PRIVATE_DATA_SIGNATURE SIGNATURE_32 ('s', 'm', 'm', 'c') + +/// +/// Private structure that is used to share information between the SMM IPL and +/// the SMM Core. This structure is allocated from memory of type EfiRuntimeServicesData. +/// Since runtime memory types are converted to available memory when a legacy boot +/// is performed, the SMM Core must not access any fields of this structure if a legacy +/// boot is performed. As a result, the SMM IPL must create an event notification +/// for the Legacy Boot event and notify the SMM Core that a legacy boot is being +/// performed. The SMM Core can then use this information to filter accesses to +/// thos structure. +/// +typedef struct { + UINTN Signature; + + /// + /// The ImageHandle passed into the entry point of the SMM IPL. This ImageHandle + /// is used by the SMM Core to fill in the ParentImageHandle field of the Loaded + /// Image Protocol for each SMM Driver that is dispatched by the SMM Core. + /// + EFI_HANDLE SmmIplImageHandle; + + /// + /// The number of SMRAM ranges passed from the SMM IPL to the SMM Core. The SMM + /// Core uses these ranges of SMRAM to initialize the SMM Core memory manager. + /// + UINTN SmramRangeCount; + + /// + /// A table of SMRAM ranges passed from the SMM IPL to the SMM Core. The SMM + /// Core uses these ranges of SMRAM to initialize the SMM Core memory manager. + /// + EFI_SMRAM_DESCRIPTOR *SmramRanges; + + /// + /// The SMM Foundation Entry Point. The SMM Core fills in this field when the + /// SMM Core is initialized. The SMM IPL is responsible for registering this entry + /// point with the SMM Configuration Protocol. The SMM Configuration Protocol may + /// not be available at the time the SMM IPL and SMM Core are started, so the SMM IPL + /// sets up a protocol notification on the SMM Configuration Protocol and registers + /// the SMM Foundation Entry Point as soon as the SMM Configuration Protocol is + /// available. + /// + EFI_SMM_ENTRY_POINT SmmEntryPoint; + + /// + /// Boolean flag set to TRUE while an SMI is being processed by the SMM Core. + /// + BOOLEAN SmmEntryPointRegistered; + + /// + /// Boolean flag set to TRUE while an SMI is being processed by the SMM Core. + /// + BOOLEAN InSmm; + + /// + /// This field is set by the SMM Core then the SMM Core is initialized. This field is + /// used by the SMM Base 2 Protocol and SMM Communication Protocol implementations in + /// the SMM IPL. + /// + EFI_SMM_SYSTEM_TABLE2 *Smst; + + /// + /// This field is used by the SMM Communication Protocol to pass a buffer into + /// a software SMI handler and for the software SMI handler to pass a buffer back to + /// the caller of the SMM Communication Protocol. + /// + VOID *CommunicationBuffer; + + /// + /// This field is used by the SMM Communication Protocol to pass the size of a buffer, + /// in bytes, into a software SMI handler and for the software SMI handler to pass the + /// size, in bytes, of a buffer back to the caller of the SMM Communication Protocol. + /// + UINTN BufferSize; + + /// + /// This field is used by the SMM Communication Protocol to pass the return status from + /// a software SMI handler back to the caller of the SMM Communication Protocol. + /// + EFI_STATUS ReturnStatus; + + EFI_PHYSICAL_ADDRESS PiSmmCoreImageBase; + UINT64 PiSmmCoreImageSize; + EFI_PHYSICAL_ADDRESS PiSmmCoreEntryPoint; +} SMM_CORE_PRIVATE_DATA; + +#endif diff --git a/MdeModulePkg/Core/PiSmmCore/PiSmmIpl.c b/MdeModulePkg/Core/PiSmmCore/PiSmmIpl.c index fbba868fd0..4ef751f758 100644 --- a/MdeModulePkg/Core/PiSmmCore/PiSmmIpl.c +++ b/MdeModulePkg/Core/PiSmmCore/PiSmmIpl.c @@ -1,1911 +1,1911 @@ -/** @file
- SMM IPL that produces SMM related runtime protocols and load the SMM Core into SMRAM
-
- Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.<BR>
- SPDX-License-Identifier: BSD-2-Clause-Patent
-
-**/
-
-#include <PiDxe.h>
-
-#include <Protocol/SmmBase2.h>
-#include <Protocol/SmmCommunication.h>
-#include <Protocol/MmCommunication2.h>
-#include <Protocol/SmmAccess2.h>
-#include <Protocol/SmmConfiguration.h>
-#include <Protocol/SmmControl2.h>
-#include <Protocol/DxeSmmReadyToLock.h>
-#include <Protocol/Cpu.h>
-
-#include <Guid/EventGroup.h>
-#include <Guid/EventLegacyBios.h>
-#include <Guid/LoadModuleAtFixedAddress.h>
-
-#include <Library/BaseLib.h>
-#include <Library/BaseMemoryLib.h>
-#include <Library/PeCoffLib.h>
-#include <Library/CacheMaintenanceLib.h>
-#include <Library/MemoryAllocationLib.h>
-#include <Library/DebugLib.h>
-#include <Library/UefiBootServicesTableLib.h>
-#include <Library/DxeServicesTableLib.h>
-#include <Library/DxeServicesLib.h>
-#include <Library/UefiLib.h>
-#include <Library/UefiRuntimeLib.h>
-#include <Library/PcdLib.h>
-#include <Library/ReportStatusCodeLib.h>
-#include "PiSmmCorePrivateData.h"
-#include <Library/SafeIntLib.h>
-
-#define SMRAM_CAPABILITIES (EFI_MEMORY_WB | EFI_MEMORY_UC)
-
-//
-// Function prototypes from produced protocols
-//
-
-/**
- Indicate whether the driver is currently executing in the SMM Initialization phase.
-
- @param This The EFI_SMM_BASE2_PROTOCOL instance.
- @param InSmram Pointer to a Boolean which, on return, indicates that the driver is currently executing
- inside of SMRAM (TRUE) or outside of SMRAM (FALSE).
-
- @retval EFI_INVALID_PARAMETER InSmram was NULL.
- @retval EFI_SUCCESS The call returned successfully.
-
-**/
-EFI_STATUS
-EFIAPI
-SmmBase2InSmram (
- IN CONST EFI_SMM_BASE2_PROTOCOL *This,
- OUT BOOLEAN *InSmram
- );
-
-/**
- Retrieves the location of the System Management System Table (SMST).
-
- @param This The EFI_SMM_BASE2_PROTOCOL instance.
- @param Smst On return, points to a pointer to the System Management Service Table (SMST).
-
- @retval EFI_INVALID_PARAMETER Smst or This was invalid.
- @retval EFI_SUCCESS The memory was returned to the system.
- @retval EFI_UNSUPPORTED Not in SMM.
-
-**/
-EFI_STATUS
-EFIAPI
-SmmBase2GetSmstLocation (
- IN CONST EFI_SMM_BASE2_PROTOCOL *This,
- OUT EFI_SMM_SYSTEM_TABLE2 **Smst
- );
-
-/**
- Communicates with a registered handler.
-
- This function provides a service to send and receive messages from a registered
- UEFI service. This function is part of the SMM Communication Protocol that may
- be called in physical mode prior to SetVirtualAddressMap() and in virtual mode
- after SetVirtualAddressMap().
-
- @param[in] This The EFI_SMM_COMMUNICATION_PROTOCOL instance.
- @param[in, out] CommBuffer A pointer to the buffer to convey into SMRAM.
- @param[in, out] CommSize The size of the data buffer being passed in. On exit, the size of data
- being returned. Zero if the handler does not wish to reply with any data.
- This parameter is optional and may be NULL.
-
- @retval EFI_SUCCESS The message was successfully posted.
- @retval EFI_INVALID_PARAMETER The CommBuffer was NULL.
- @retval EFI_BAD_BUFFER_SIZE The buffer is too large for the MM implementation.
- If this error is returned, the MessageLength field
- in the CommBuffer header or the integer pointed by
- CommSize, are updated to reflect the maximum payload
- size the implementation can accommodate.
- @retval EFI_ACCESS_DENIED The CommunicateBuffer parameter or CommSize parameter,
- if not omitted, are in address range that cannot be
- accessed by the MM environment.
-
-**/
-EFI_STATUS
-EFIAPI
-SmmCommunicationCommunicate (
- IN CONST EFI_SMM_COMMUNICATION_PROTOCOL *This,
- IN OUT VOID *CommBuffer,
- IN OUT UINTN *CommSize OPTIONAL
- );
-
-/**
- Communicates with a registered handler.
-
- This function provides a service to send and receive messages from a registered UEFI service.
-
- @param[in] This The EFI_MM_COMMUNICATION_PROTOCOL instance.
- @param[in] CommBufferPhysical Physical address of the MM communication buffer
- @param[in] CommBufferVirtual Virtual address of the MM communication buffer
- @param[in] CommSize The size of the data buffer being passed in. On exit, the size of data
- being returned. Zero if the handler does not wish to reply with any data.
- This parameter is optional and may be NULL.
-
- @retval EFI_SUCCESS The message was successfully posted.
- @retval EFI_INVALID_PARAMETER The CommBuffer was NULL.
- @retval EFI_BAD_BUFFER_SIZE The buffer is too large for the MM implementation.
- If this error is returned, the MessageLength field
- in the CommBuffer header or the integer pointed by
- CommSize, are updated to reflect the maximum payload
- size the implementation can accommodate.
- @retval EFI_ACCESS_DENIED The CommunicateBuffer parameter or CommSize parameter,
- if not omitted, are in address range that cannot be
- accessed by the MM environment.
-
-**/
-EFI_STATUS
-EFIAPI
-SmmCommunicationMmCommunicate2 (
- IN CONST EFI_MM_COMMUNICATION2_PROTOCOL *This,
- IN OUT VOID *CommBufferPhysical,
- IN OUT VOID *CommBufferVirtual,
- IN OUT UINTN *CommSize OPTIONAL
- );
-
-/**
- Event notification that is fired every time a gEfiSmmConfigurationProtocol installs.
-
- @param Event The Event that is being processed, not used.
- @param Context Event Context, not used.
-
-**/
-VOID
-EFIAPI
-SmmIplSmmConfigurationEventNotify (
- IN EFI_EVENT Event,
- IN VOID *Context
- );
-
-/**
- Event notification that is fired every time a DxeSmmReadyToLock protocol is added
- or if gEfiEventReadyToBootGuid is signalled.
-
- @param Event The Event that is being processed, not used.
- @param Context Event Context, not used.
-
-**/
-VOID
-EFIAPI
-SmmIplReadyToLockEventNotify (
- IN EFI_EVENT Event,
- IN VOID *Context
- );
-
-/**
- Event notification that is fired when DxeDispatch Event Group is signaled.
-
- @param Event The Event that is being processed, not used.
- @param Context Event Context, not used.
-
-**/
-VOID
-EFIAPI
-SmmIplDxeDispatchEventNotify (
- IN EFI_EVENT Event,
- IN VOID *Context
- );
-
-/**
- Event notification that is fired when a GUIDed Event Group is signaled.
-
- @param Event The Event that is being processed, not used.
- @param Context Event Context, not used.
-
-**/
-VOID
-EFIAPI
-SmmIplGuidedEventNotify (
- IN EFI_EVENT Event,
- IN VOID *Context
- );
-
-/**
- Event notification that is fired when EndOfDxe Event Group is signaled.
-
- @param Event The Event that is being processed, not used.
- @param Context Event Context, not used.
-
-**/
-VOID
-EFIAPI
-SmmIplEndOfDxeEventNotify (
- IN EFI_EVENT Event,
- IN VOID *Context
- );
-
-/**
- Notification function of EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE.
-
- This is a notification function registered on EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE event.
- It convers pointer to new virtual address.
-
- @param Event Event whose notification function is being invoked.
- @param Context Pointer to the notification function's context.
-
-**/
-VOID
-EFIAPI
-SmmIplSetVirtualAddressNotify (
- IN EFI_EVENT Event,
- IN VOID *Context
- );
-
-//
-// Data structure used to declare a table of protocol notifications and event
-// notifications required by the SMM IPL
-//
-typedef struct {
- BOOLEAN Protocol;
- BOOLEAN CloseOnLock;
- EFI_GUID *Guid;
- EFI_EVENT_NOTIFY NotifyFunction;
- VOID *NotifyContext;
- EFI_TPL NotifyTpl;
- EFI_EVENT Event;
-} SMM_IPL_EVENT_NOTIFICATION;
-
-//
-// Handle to install the SMM Base2 Protocol and the SMM Communication Protocol
-//
-EFI_HANDLE mSmmIplHandle = NULL;
-
-//
-// SMM Base 2 Protocol instance
-//
-EFI_SMM_BASE2_PROTOCOL mSmmBase2 = {
- SmmBase2InSmram,
- SmmBase2GetSmstLocation
-};
-
-//
-// SMM Communication Protocol instance
-//
-EFI_SMM_COMMUNICATION_PROTOCOL mSmmCommunication = {
- SmmCommunicationCommunicate
-};
-
-//
-// PI 1.7 MM Communication Protocol 2 instance
-//
-EFI_MM_COMMUNICATION2_PROTOCOL mMmCommunication2 = {
- SmmCommunicationMmCommunicate2
-};
-
-//
-// SMM Core Private Data structure that contains the data shared between
-// the SMM IPL and the SMM Core.
-//
-SMM_CORE_PRIVATE_DATA mSmmCorePrivateData = {
- SMM_CORE_PRIVATE_DATA_SIGNATURE, // Signature
- NULL, // SmmIplImageHandle
- 0, // SmramRangeCount
- NULL, // SmramRanges
- NULL, // SmmEntryPoint
- FALSE, // SmmEntryPointRegistered
- FALSE, // InSmm
- NULL, // Smst
- NULL, // CommunicationBuffer
- 0, // BufferSize
- EFI_SUCCESS // ReturnStatus
-};
-
-//
-// Global pointer used to access mSmmCorePrivateData from outside and inside SMM
-//
-SMM_CORE_PRIVATE_DATA *gSmmCorePrivate = &mSmmCorePrivateData;
-
-//
-// SMM IPL global variables
-//
-EFI_SMM_CONTROL2_PROTOCOL *mSmmControl2;
-EFI_SMM_ACCESS2_PROTOCOL *mSmmAccess;
-EFI_SMRAM_DESCRIPTOR *mCurrentSmramRange;
-BOOLEAN mSmmLocked = FALSE;
-BOOLEAN mEndOfDxe = FALSE;
-EFI_PHYSICAL_ADDRESS mSmramCacheBase;
-UINT64 mSmramCacheSize;
-
-EFI_SMM_COMMUNICATE_HEADER mCommunicateHeader;
-EFI_LOAD_FIXED_ADDRESS_CONFIGURATION_TABLE *mLMFAConfigurationTable = NULL;
-
-//
-// Table of Protocol notification and GUIDed Event notifications that the SMM IPL requires
-//
-SMM_IPL_EVENT_NOTIFICATION mSmmIplEvents[] = {
- //
- // Declare protocol notification on the SMM Configuration protocol. When this notification is established,
- // the associated event is immediately signalled, so the notification function will be executed and the
- // SMM Configuration Protocol will be found if it is already in the handle database.
- //
- { TRUE, FALSE, &gEfiSmmConfigurationProtocolGuid, SmmIplSmmConfigurationEventNotify, &gEfiSmmConfigurationProtocolGuid, TPL_NOTIFY, NULL },
- //
- // Declare protocol notification on DxeSmmReadyToLock protocols. When this notification is established,
- // the associated event is immediately signalled, so the notification function will be executed and the
- // DXE SMM Ready To Lock Protocol will be found if it is already in the handle database.
- //
- { TRUE, TRUE, &gEfiDxeSmmReadyToLockProtocolGuid, SmmIplReadyToLockEventNotify, &gEfiDxeSmmReadyToLockProtocolGuid, TPL_CALLBACK, NULL },
- //
- // Declare event notification on EndOfDxe event. When this notification is established,
- // the associated event is immediately signalled, so the notification function will be executed and the
- // SMM End Of Dxe Protocol will be found if it is already in the handle database.
- //
- { FALSE, TRUE, &gEfiEndOfDxeEventGroupGuid, SmmIplGuidedEventNotify, &gEfiEndOfDxeEventGroupGuid, TPL_CALLBACK, NULL },
- //
- // Declare event notification on EndOfDxe event. This is used to set EndOfDxe event signaled flag.
- //
- { FALSE, TRUE, &gEfiEndOfDxeEventGroupGuid, SmmIplEndOfDxeEventNotify, &gEfiEndOfDxeEventGroupGuid, TPL_CALLBACK, NULL },
- //
- // Declare event notification on the DXE Dispatch Event Group. This event is signaled by the DXE Core
- // each time the DXE Core dispatcher has completed its work. When this event is signalled, the SMM Core
- // if notified, so the SMM Core can dispatch SMM drivers.
- //
- { FALSE, TRUE, &gEfiEventDxeDispatchGuid, SmmIplDxeDispatchEventNotify, &gEfiEventDxeDispatchGuid, TPL_CALLBACK, NULL },
- //
- // Declare event notification on Ready To Boot Event Group. This is an extra event notification that is
- // used to make sure SMRAM is locked before any boot options are processed.
- //
- { FALSE, TRUE, &gEfiEventReadyToBootGuid, SmmIplReadyToLockEventNotify, &gEfiEventReadyToBootGuid, TPL_CALLBACK, NULL },
- //
- // Declare event notification on Legacy Boot Event Group. This is used to inform the SMM Core that the platform
- // is performing a legacy boot operation, and that the UEFI environment is no longer available and the SMM Core
- // must guarantee that it does not access any UEFI related structures outside of SMRAM.
- // It is also to inform the SMM Core to notify SMM driver that system enter legacy boot.
- //
- { FALSE, FALSE, &gEfiEventLegacyBootGuid, SmmIplGuidedEventNotify, &gEfiEventLegacyBootGuid, TPL_CALLBACK, NULL },
- //
- // Declare event notification on Exit Boot Services Event Group. This is used to inform the SMM Core
- // to notify SMM driver that system enter exit boot services.
- //
- { FALSE, FALSE, &gEfiEventExitBootServicesGuid, SmmIplGuidedEventNotify, &gEfiEventExitBootServicesGuid, TPL_CALLBACK, NULL },
- //
- // Declare event notification on Ready To Boot Event Group. This is used to inform the SMM Core
- // to notify SMM driver that system enter ready to boot.
- //
- { FALSE, FALSE, &gEfiEventReadyToBootGuid, SmmIplGuidedEventNotify, &gEfiEventReadyToBootGuid, TPL_CALLBACK, NULL },
- //
- // Declare event notification on SetVirtualAddressMap() Event Group. This is used to convert gSmmCorePrivate
- // and mSmmControl2 from physical addresses to virtual addresses.
- //
- { FALSE, FALSE, &gEfiEventVirtualAddressChangeGuid, SmmIplSetVirtualAddressNotify, NULL, TPL_CALLBACK, NULL },
- //
- // Terminate the table of event notifications
- //
- { FALSE, FALSE, NULL, NULL, NULL, TPL_CALLBACK, NULL }
-};
-
-/**
- Find the maximum SMRAM cache range that covers the range specified by SmramRange.
-
- This function searches and joins all adjacent ranges of SmramRange into a range to be cached.
-
- @param SmramRange The SMRAM range to search from.
- @param SmramCacheBase The returned cache range base.
- @param SmramCacheSize The returned cache range size.
-
-**/
-VOID
-GetSmramCacheRange (
- IN EFI_SMRAM_DESCRIPTOR *SmramRange,
- OUT EFI_PHYSICAL_ADDRESS *SmramCacheBase,
- OUT UINT64 *SmramCacheSize
- )
-{
- UINTN Index;
- EFI_PHYSICAL_ADDRESS RangeCpuStart;
- UINT64 RangePhysicalSize;
- BOOLEAN FoundAjacentRange;
-
- *SmramCacheBase = SmramRange->CpuStart;
- *SmramCacheSize = SmramRange->PhysicalSize;
-
- do {
- FoundAjacentRange = FALSE;
- for (Index = 0; Index < gSmmCorePrivate->SmramRangeCount; Index++) {
- RangeCpuStart = gSmmCorePrivate->SmramRanges[Index].CpuStart;
- RangePhysicalSize = gSmmCorePrivate->SmramRanges[Index].PhysicalSize;
- if ((RangeCpuStart < *SmramCacheBase) && (*SmramCacheBase == (RangeCpuStart + RangePhysicalSize))) {
- *SmramCacheBase = RangeCpuStart;
- *SmramCacheSize += RangePhysicalSize;
- FoundAjacentRange = TRUE;
- } else if (((*SmramCacheBase + *SmramCacheSize) == RangeCpuStart) && (RangePhysicalSize > 0)) {
- *SmramCacheSize += RangePhysicalSize;
- FoundAjacentRange = TRUE;
- }
- }
- } while (FoundAjacentRange);
-}
-
-/**
- Indicate whether the driver is currently executing in the SMM Initialization phase.
-
- @param This The EFI_SMM_BASE2_PROTOCOL instance.
- @param InSmram Pointer to a Boolean which, on return, indicates that the driver is currently executing
- inside of SMRAM (TRUE) or outside of SMRAM (FALSE).
-
- @retval EFI_INVALID_PARAMETER InSmram was NULL.
- @retval EFI_SUCCESS The call returned successfully.
-
-**/
-EFI_STATUS
-EFIAPI
-SmmBase2InSmram (
- IN CONST EFI_SMM_BASE2_PROTOCOL *This,
- OUT BOOLEAN *InSmram
- )
-{
- if (InSmram == NULL) {
- return EFI_INVALID_PARAMETER;
- }
-
- *InSmram = gSmmCorePrivate->InSmm;
-
- return EFI_SUCCESS;
-}
-
-/**
- Retrieves the location of the System Management System Table (SMST).
-
- @param This The EFI_SMM_BASE2_PROTOCOL instance.
- @param Smst On return, points to a pointer to the System Management Service Table (SMST).
-
- @retval EFI_INVALID_PARAMETER Smst or This was invalid.
- @retval EFI_SUCCESS The memory was returned to the system.
- @retval EFI_UNSUPPORTED Not in SMM.
-
-**/
-EFI_STATUS
-EFIAPI
-SmmBase2GetSmstLocation (
- IN CONST EFI_SMM_BASE2_PROTOCOL *This,
- OUT EFI_SMM_SYSTEM_TABLE2 **Smst
- )
-{
- if ((This == NULL) || (Smst == NULL)) {
- return EFI_INVALID_PARAMETER;
- }
-
- if (!gSmmCorePrivate->InSmm) {
- return EFI_UNSUPPORTED;
- }
-
- *Smst = gSmmCorePrivate->Smst;
-
- return EFI_SUCCESS;
-}
-
-/**
- Communicates with a registered handler.
-
- This function provides a service to send and receive messages from a registered
- UEFI service. This function is part of the SMM Communication Protocol that may
- be called in physical mode prior to SetVirtualAddressMap() and in virtual mode
- after SetVirtualAddressMap().
-
- @param[in] This The EFI_SMM_COMMUNICATION_PROTOCOL instance.
- @param[in, out] CommBuffer A pointer to the buffer to convey into SMRAM.
- @param[in, out] CommSize The size of the data buffer being passed in. On exit, the size of data
- being returned. Zero if the handler does not wish to reply with any data.
- This parameter is optional and may be NULL.
-
- @retval EFI_SUCCESS The message was successfully posted.
- @retval EFI_INVALID_PARAMETER The CommBuffer was NULL.
- @retval EFI_BAD_BUFFER_SIZE The buffer is too large for the MM implementation.
- If this error is returned, the MessageLength field
- in the CommBuffer header or the integer pointed by
- CommSize, are updated to reflect the maximum payload
- size the implementation can accommodate.
- @retval EFI_ACCESS_DENIED The CommunicateBuffer parameter or CommSize parameter,
- if not omitted, are in address range that cannot be
- accessed by the MM environment.
-
-**/
-EFI_STATUS
-EFIAPI
-SmmCommunicationCommunicate (
- IN CONST EFI_SMM_COMMUNICATION_PROTOCOL *This,
- IN OUT VOID *CommBuffer,
- IN OUT UINTN *CommSize OPTIONAL
- )
-{
- EFI_STATUS Status;
- EFI_SMM_COMMUNICATE_HEADER *CommunicateHeader;
- BOOLEAN OldInSmm;
- UINTN TempCommSize;
-
- //
- // Check parameters
- //
- if (CommBuffer == NULL) {
- return EFI_INVALID_PARAMETER;
- }
-
- CommunicateHeader = (EFI_SMM_COMMUNICATE_HEADER *)CommBuffer;
-
- if (CommSize == NULL) {
- TempCommSize = OFFSET_OF (EFI_SMM_COMMUNICATE_HEADER, Data) + CommunicateHeader->MessageLength;
- } else {
- TempCommSize = *CommSize;
- //
- // CommSize must hold HeaderGuid and MessageLength
- //
- if (TempCommSize < OFFSET_OF (EFI_SMM_COMMUNICATE_HEADER, Data)) {
- return EFI_INVALID_PARAMETER;
- }
- }
-
- //
- // If not already in SMM, then generate a Software SMI
- //
- if (!gSmmCorePrivate->InSmm && gSmmCorePrivate->SmmEntryPointRegistered) {
- //
- // Put arguments for Software SMI in gSmmCorePrivate
- //
- gSmmCorePrivate->CommunicationBuffer = CommBuffer;
- gSmmCorePrivate->BufferSize = TempCommSize;
-
- //
- // Generate Software SMI
- //
- Status = mSmmControl2->Trigger (mSmmControl2, NULL, NULL, FALSE, 0);
- if (EFI_ERROR (Status)) {
- return EFI_UNSUPPORTED;
- }
-
- //
- // Return status from software SMI
- //
- if (CommSize != NULL) {
- *CommSize = gSmmCorePrivate->BufferSize;
- }
-
- return gSmmCorePrivate->ReturnStatus;
- }
-
- //
- // If we are in SMM, then the execution mode must be physical, which means that
- // OS established virtual addresses can not be used. If SetVirtualAddressMap()
- // has been called, then a direct invocation of the Software SMI is not allowed,
- // so return EFI_INVALID_PARAMETER.
- //
- if (EfiGoneVirtual ()) {
- return EFI_INVALID_PARAMETER;
- }
-
- //
- // If we are not in SMM, don't allow call SmiManage() directly when SMRAM is closed or locked.
- //
- if ((!gSmmCorePrivate->InSmm) && (!mSmmAccess->OpenState || mSmmAccess->LockState)) {
- return EFI_INVALID_PARAMETER;
- }
-
- //
- // Save current InSmm state and set InSmm state to TRUE
- //
- OldInSmm = gSmmCorePrivate->InSmm;
- gSmmCorePrivate->InSmm = TRUE;
-
- //
- // Before SetVirtualAddressMap(), we are in SMM or SMRAM is open and unlocked, call SmiManage() directly.
- //
- TempCommSize -= OFFSET_OF (EFI_SMM_COMMUNICATE_HEADER, Data);
- Status = gSmmCorePrivate->Smst->SmiManage (
- &CommunicateHeader->HeaderGuid,
- NULL,
- CommunicateHeader->Data,
- &TempCommSize
- );
- TempCommSize += OFFSET_OF (EFI_SMM_COMMUNICATE_HEADER, Data);
- if (CommSize != NULL) {
- *CommSize = TempCommSize;
- }
-
- //
- // Restore original InSmm state
- //
- gSmmCorePrivate->InSmm = OldInSmm;
-
- return (Status == EFI_SUCCESS) ? EFI_SUCCESS : EFI_NOT_FOUND;
-}
-
-/**
- Communicates with a registered handler.
-
- This function provides a service to send and receive messages from a registered UEFI service.
-
- @param[in] This The EFI_MM_COMMUNICATION_PROTOCOL instance.
- @param[in] CommBufferPhysical Physical address of the MM communication buffer
- @param[in] CommBufferVirtual Virtual address of the MM communication buffer
- @param[in] CommSize The size of the data buffer being passed in. On exit, the size of data
- being returned. Zero if the handler does not wish to reply with any data.
- This parameter is optional and may be NULL.
-
- @retval EFI_SUCCESS The message was successfully posted.
- @retval EFI_INVALID_PARAMETER The CommBuffer was NULL.
- @retval EFI_BAD_BUFFER_SIZE The buffer is too large for the MM implementation.
- If this error is returned, the MessageLength field
- in the CommBuffer header or the integer pointed by
- CommSize, are updated to reflect the maximum payload
- size the implementation can accommodate.
- @retval EFI_ACCESS_DENIED The CommunicateBuffer parameter or CommSize parameter,
- if not omitted, are in address range that cannot be
- accessed by the MM environment.
-
-**/
-EFI_STATUS
-EFIAPI
-SmmCommunicationMmCommunicate2 (
- IN CONST EFI_MM_COMMUNICATION2_PROTOCOL *This,
- IN OUT VOID *CommBufferPhysical,
- IN OUT VOID *CommBufferVirtual,
- IN OUT UINTN *CommSize OPTIONAL
- )
-{
- return SmmCommunicationCommunicate (
- &mSmmCommunication,
- CommBufferPhysical,
- CommSize
- );
-}
-
-/**
- Event notification that is fired when GUIDed Event Group is signaled.
-
- @param Event The Event that is being processed, not used.
- @param Context Event Context, not used.
-
-**/
-VOID
-EFIAPI
-SmmIplGuidedEventNotify (
- IN EFI_EVENT Event,
- IN VOID *Context
- )
-{
- UINTN Size;
-
- //
- // Use Guid to initialize EFI_SMM_COMMUNICATE_HEADER structure
- //
- CopyGuid (&mCommunicateHeader.HeaderGuid, (EFI_GUID *)Context);
- mCommunicateHeader.MessageLength = 1;
- mCommunicateHeader.Data[0] = 0;
-
- //
- // Generate the Software SMI and return the result
- //
- Size = sizeof (mCommunicateHeader);
- SmmCommunicationCommunicate (&mSmmCommunication, &mCommunicateHeader, &Size);
-}
-
-/**
- Event notification that is fired when EndOfDxe Event Group is signaled.
-
- @param Event The Event that is being processed, not used.
- @param Context Event Context, not used.
-
-**/
-VOID
-EFIAPI
-SmmIplEndOfDxeEventNotify (
- IN EFI_EVENT Event,
- IN VOID *Context
- )
-{
- mEndOfDxe = TRUE;
-}
-
-/**
- Event notification that is fired when DxeDispatch Event Group is signaled.
-
- @param Event The Event that is being processed, not used.
- @param Context Event Context, not used.
-
-**/
-VOID
-EFIAPI
-SmmIplDxeDispatchEventNotify (
- IN EFI_EVENT Event,
- IN VOID *Context
- )
-{
- UINTN Size;
- EFI_STATUS Status;
-
- //
- // Keep calling the SMM Core Dispatcher until there is no request to restart it.
- //
- while (TRUE) {
- //
- // Use Guid to initialize EFI_SMM_COMMUNICATE_HEADER structure
- // Clear the buffer passed into the Software SMI. This buffer will return
- // the status of the SMM Core Dispatcher.
- //
- CopyGuid (&mCommunicateHeader.HeaderGuid, (EFI_GUID *)Context);
- mCommunicateHeader.MessageLength = 1;
- mCommunicateHeader.Data[0] = 0;
-
- //
- // Generate the Software SMI and return the result
- //
- Size = sizeof (mCommunicateHeader);
- SmmCommunicationCommunicate (&mSmmCommunication, &mCommunicateHeader, &Size);
-
- //
- // Return if there is no request to restart the SMM Core Dispatcher
- //
- if (mCommunicateHeader.Data[0] != COMM_BUFFER_SMM_DISPATCH_RESTART) {
- return;
- }
-
- //
- // Close all SMRAM ranges to protect SMRAM
- // NOTE: SMRR is enabled by CPU SMM driver by calling SmmCpuFeaturesInitializeProcessor() from SmmCpuFeaturesLib
- // so no need to reset the SMRAM to UC in MTRR.
- //
- Status = mSmmAccess->Close (mSmmAccess);
- ASSERT_EFI_ERROR (Status);
-
- //
- // Print debug message that the SMRAM window is now closed.
- //
- DEBUG ((DEBUG_INFO, "SMM IPL closed SMRAM window\n"));
- }
-}
-
-/**
- Event notification that is fired every time a gEfiSmmConfigurationProtocol installs.
-
- @param Event The Event that is being processed, not used.
- @param Context Event Context, not used.
-
-**/
-VOID
-EFIAPI
-SmmIplSmmConfigurationEventNotify (
- IN EFI_EVENT Event,
- IN VOID *Context
- )
-{
- EFI_STATUS Status;
- EFI_SMM_CONFIGURATION_PROTOCOL *SmmConfiguration;
-
- //
- // Make sure this notification is for this handler
- //
- Status = gBS->LocateProtocol (Context, NULL, (VOID **)&SmmConfiguration);
- if (EFI_ERROR (Status)) {
- return;
- }
-
- //
- // Register the SMM Entry Point provided by the SMM Core with the SMM Configuration protocol
- //
- Status = SmmConfiguration->RegisterSmmEntry (SmmConfiguration, gSmmCorePrivate->SmmEntryPoint);
- ASSERT_EFI_ERROR (Status);
-
- //
- // Set flag to indicate that the SMM Entry Point has been registered which
- // means that SMIs are now fully operational.
- //
- gSmmCorePrivate->SmmEntryPointRegistered = TRUE;
-
- //
- // Print debug message showing SMM Core entry point address.
- //
- DEBUG ((DEBUG_INFO, "SMM IPL registered SMM Entry Point address %p\n", (VOID *)(UINTN)gSmmCorePrivate->SmmEntryPoint));
-}
-
-/**
- Event notification that is fired every time a DxeSmmReadyToLock protocol is added
- or if gEfiEventReadyToBootGuid is signaled.
-
- @param Event The Event that is being processed, not used.
- @param Context Event Context, not used.
-
-**/
-VOID
-EFIAPI
-SmmIplReadyToLockEventNotify (
- IN EFI_EVENT Event,
- IN VOID *Context
- )
-{
- EFI_STATUS Status;
- VOID *Interface;
- UINTN Index;
-
- //
- // See if we are already locked
- //
- if (mSmmLocked) {
- return;
- }
-
- //
- // Make sure this notification is for this handler
- //
- if (CompareGuid ((EFI_GUID *)Context, &gEfiDxeSmmReadyToLockProtocolGuid)) {
- Status = gBS->LocateProtocol (&gEfiDxeSmmReadyToLockProtocolGuid, NULL, &Interface);
- if (EFI_ERROR (Status)) {
- return;
- }
- } else {
- //
- // If SMM is not locked yet and we got here from gEfiEventReadyToBootGuid being
- // signaled, then gEfiDxeSmmReadyToLockProtocolGuid was not installed as expected.
- // Print a warning on debug builds.
- //
- DEBUG ((DEBUG_WARN, "SMM IPL! DXE SMM Ready To Lock Protocol not installed before Ready To Boot signal\n"));
- }
-
- if (!mEndOfDxe) {
- DEBUG ((DEBUG_ERROR, "EndOfDxe Event must be signaled before DxeSmmReadyToLock Protocol installation!\n"));
- REPORT_STATUS_CODE (
- EFI_ERROR_CODE | EFI_ERROR_UNRECOVERED,
- (EFI_SOFTWARE_SMM_DRIVER | EFI_SW_EC_ILLEGAL_SOFTWARE_STATE)
- );
- ASSERT (FALSE);
- }
-
- //
- // Lock the SMRAM (Note: Locking SMRAM may not be supported on all platforms)
- //
- mSmmAccess->Lock (mSmmAccess);
-
- //
- // Close protocol and event notification events that do not apply after the
- // DXE SMM Ready To Lock Protocol has been installed or the Ready To Boot
- // event has been signalled.
- //
- for (Index = 0; mSmmIplEvents[Index].NotifyFunction != NULL; Index++) {
- if (mSmmIplEvents[Index].CloseOnLock) {
- gBS->CloseEvent (mSmmIplEvents[Index].Event);
- }
- }
-
- //
- // Inform SMM Core that the DxeSmmReadyToLock protocol was installed
- //
- SmmIplGuidedEventNotify (Event, (VOID *)&gEfiDxeSmmReadyToLockProtocolGuid);
-
- //
- // Print debug message that the SMRAM window is now locked.
- //
- DEBUG ((DEBUG_INFO, "SMM IPL locked SMRAM window\n"));
-
- //
- // Set flag so this operation will not be performed again
- //
- mSmmLocked = TRUE;
-}
-
-/**
- Notification function of EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE.
-
- This is a notification function registered on EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE event.
- It convers pointer to new virtual address.
-
- @param Event Event whose notification function is being invoked.
- @param Context Pointer to the notification function's context.
-
-**/
-VOID
-EFIAPI
-SmmIplSetVirtualAddressNotify (
- IN EFI_EVENT Event,
- IN VOID *Context
- )
-{
- EfiConvertPointer (0x0, (VOID **)&mSmmControl2);
-}
-
-/**
- Get the fixed loading address from image header assigned by build tool. This function only be called
- when Loading module at Fixed address feature enabled.
-
- @param ImageContext Pointer to the image context structure that describes the PE/COFF
- image that needs to be examined by this function.
- @retval EFI_SUCCESS An fixed loading address is assigned to this image by build tools .
- @retval EFI_NOT_FOUND The image has no assigned fixed loading address.
-**/
-EFI_STATUS
-GetPeCoffImageFixLoadingAssignedAddress (
- IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext
- )
-{
- UINTN SectionHeaderOffset;
- EFI_STATUS Status;
- EFI_IMAGE_SECTION_HEADER SectionHeader;
- EFI_IMAGE_OPTIONAL_HEADER_UNION *ImgHdr;
- EFI_PHYSICAL_ADDRESS FixLoadingAddress;
- UINT16 Index;
- UINTN Size;
- UINT16 NumberOfSections;
- EFI_PHYSICAL_ADDRESS SmramBase;
- UINT64 SmmCodeSize;
- UINT64 ValueInSectionHeader;
-
- //
- // Build tool will calculate the smm code size and then patch the PcdLoadFixAddressSmmCodePageNumber
- //
- SmmCodeSize = EFI_PAGES_TO_SIZE (PcdGet32 (PcdLoadFixAddressSmmCodePageNumber));
-
- FixLoadingAddress = 0;
- Status = EFI_NOT_FOUND;
- SmramBase = mLMFAConfigurationTable->SmramBase;
- //
- // 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 saves the offset to SMRAM base as image base in PointerToRelocations & PointerToLineNumbers fields in the
- // first section header that doesn't point to code section in image header. And there is an assumption that when the
- // feature is enabled, if a module is assigned a loading address by tools, PointerToRelocations & PointerToLineNumbers
- // fields should NOT be Zero, or else, these 2 fields should be set to Zero
- //
- ValueInSectionHeader = ReadUnaligned64 ((UINT64 *)&SectionHeader.PointerToRelocations);
- if (ValueInSectionHeader != 0) {
- //
- // 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)(SmramBase + (INT64)ValueInSectionHeader);
-
- if ((SmramBase + SmmCodeSize > FixLoadingAddress) && (SmramBase <= FixLoadingAddress)) {
- //
- // The assigned address is valid. Return the specified loading address
- //
- ImageContext->ImageAddress = FixLoadingAddress;
- Status = EFI_SUCCESS;
- }
- }
-
- 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;
-}
-
-/**
- Load the SMM Core image into SMRAM and executes the SMM Core from SMRAM.
-
- @param[in, out] SmramRange Descriptor for the range of SMRAM to reload the
- currently executing image, the rang of SMRAM to
- hold SMM Core will be excluded.
- @param[in, out] SmramRangeSmmCore Descriptor for the range of SMRAM to hold SMM Core.
-
- @param[in] Context Context to pass into SMM Core
-
- @return EFI_STATUS
-
-**/
-EFI_STATUS
-ExecuteSmmCoreFromSmram (
- IN OUT EFI_SMRAM_DESCRIPTOR *SmramRange,
- IN OUT EFI_SMRAM_DESCRIPTOR *SmramRangeSmmCore,
- IN VOID *Context
- )
-{
- EFI_STATUS Status;
- VOID *SourceBuffer;
- UINTN SourceSize;
- PE_COFF_LOADER_IMAGE_CONTEXT ImageContext;
- UINTN PageCount;
- EFI_IMAGE_ENTRY_POINT EntryPoint;
-
- //
- // Search all Firmware Volumes for a PE/COFF image in a file of type SMM_CORE
- //
- Status = GetSectionFromAnyFvByFileType (
- EFI_FV_FILETYPE_SMM_CORE,
- 0,
- EFI_SECTION_PE32,
- 0,
- &SourceBuffer,
- &SourceSize
- );
- if (EFI_ERROR (Status)) {
- return Status;
- }
-
- //
- // Initialize ImageContext
- //
- ImageContext.Handle = SourceBuffer;
- ImageContext.ImageRead = PeCoffLoaderImageReadFromMemory;
-
- //
- // Get information about the image being loaded
- //
- Status = PeCoffLoaderGetImageInfo (&ImageContext);
- if (EFI_ERROR (Status)) {
- return Status;
- }
-
- //
- // if Loading module at Fixed Address feature is enabled, the SMM core driver will be loaded to
- // the address assigned by build tool.
- //
- if (PcdGet64 (PcdLoadModuleAtFixAddressEnable) != 0) {
- //
- // Get the fixed loading address assigned by Build tool
- //
- Status = GetPeCoffImageFixLoadingAssignedAddress (&ImageContext);
- if (!EFI_ERROR (Status)) {
- //
- // Since the memory range to load SMM CORE will be cut out in SMM core, so no need to allocate and free this range
- //
- PageCount = 0;
- //
- // Reserved Smram Region for SmmCore is not used, and remove it from SmramRangeCount.
- //
- gSmmCorePrivate->SmramRangeCount--;
- } else {
- DEBUG ((DEBUG_INFO, "LOADING MODULE FIXED ERROR: Loading module at fixed address at address failed\n"));
- //
- // Allocate memory for the image being loaded from the EFI_SRAM_DESCRIPTOR
- // specified by SmramRange
- //
- PageCount = (UINTN)EFI_SIZE_TO_PAGES ((UINTN)ImageContext.ImageSize + ImageContext.SectionAlignment);
-
- ASSERT ((SmramRange->PhysicalSize & EFI_PAGE_MASK) == 0);
- ASSERT (SmramRange->PhysicalSize > EFI_PAGES_TO_SIZE (PageCount));
-
- SmramRange->PhysicalSize -= EFI_PAGES_TO_SIZE (PageCount);
- SmramRangeSmmCore->CpuStart = SmramRange->CpuStart + SmramRange->PhysicalSize;
- SmramRangeSmmCore->PhysicalStart = SmramRange->PhysicalStart + SmramRange->PhysicalSize;
- SmramRangeSmmCore->RegionState = SmramRange->RegionState | EFI_ALLOCATED;
- SmramRangeSmmCore->PhysicalSize = EFI_PAGES_TO_SIZE (PageCount);
-
- //
- // Align buffer on section boundary
- //
- ImageContext.ImageAddress = SmramRangeSmmCore->CpuStart;
- }
- } else {
- //
- // Allocate memory for the image being loaded from the EFI_SRAM_DESCRIPTOR
- // specified by SmramRange
- //
- PageCount = (UINTN)EFI_SIZE_TO_PAGES ((UINTN)ImageContext.ImageSize + ImageContext.SectionAlignment);
-
- ASSERT ((SmramRange->PhysicalSize & EFI_PAGE_MASK) == 0);
- ASSERT (SmramRange->PhysicalSize > EFI_PAGES_TO_SIZE (PageCount));
-
- SmramRange->PhysicalSize -= EFI_PAGES_TO_SIZE (PageCount);
- SmramRangeSmmCore->CpuStart = SmramRange->CpuStart + SmramRange->PhysicalSize;
- SmramRangeSmmCore->PhysicalStart = SmramRange->PhysicalStart + SmramRange->PhysicalSize;
- SmramRangeSmmCore->RegionState = SmramRange->RegionState | EFI_ALLOCATED;
- SmramRangeSmmCore->PhysicalSize = EFI_PAGES_TO_SIZE (PageCount);
-
- //
- // Align buffer on section boundary
- //
- ImageContext.ImageAddress = SmramRangeSmmCore->CpuStart;
- }
-
- ImageContext.ImageAddress += ImageContext.SectionAlignment - 1;
- ImageContext.ImageAddress &= ~((EFI_PHYSICAL_ADDRESS)ImageContext.SectionAlignment - 1);
-
- //
- // Print debug message showing SMM Core load address.
- //
- DEBUG ((DEBUG_INFO, "SMM IPL loading SMM Core at SMRAM address %p\n", (VOID *)(UINTN)ImageContext.ImageAddress));
-
- //
- // Load the image to our new buffer
- //
- Status = PeCoffLoaderLoadImage (&ImageContext);
- if (!EFI_ERROR (Status)) {
- //
- // Relocate the image in our new buffer
- //
- Status = PeCoffLoaderRelocateImage (&ImageContext);
- if (!EFI_ERROR (Status)) {
- //
- // Flush the instruction cache so the image data are written before we execute it
- //
- InvalidateInstructionCacheRange ((VOID *)(UINTN)ImageContext.ImageAddress, (UINTN)ImageContext.ImageSize);
-
- //
- // Print debug message showing SMM Core entry point address.
- //
- DEBUG ((DEBUG_INFO, "SMM IPL calling SMM Core at SMRAM address %p\n", (VOID *)(UINTN)ImageContext.EntryPoint));
-
- gSmmCorePrivate->PiSmmCoreImageBase = ImageContext.ImageAddress;
- gSmmCorePrivate->PiSmmCoreImageSize = ImageContext.ImageSize;
- DEBUG ((DEBUG_INFO, "PiSmmCoreImageBase - 0x%016lx\n", gSmmCorePrivate->PiSmmCoreImageBase));
- DEBUG ((DEBUG_INFO, "PiSmmCoreImageSize - 0x%016lx\n", gSmmCorePrivate->PiSmmCoreImageSize));
-
- gSmmCorePrivate->PiSmmCoreEntryPoint = ImageContext.EntryPoint;
-
- //
- // Execute image
- //
- EntryPoint = (EFI_IMAGE_ENTRY_POINT)(UINTN)ImageContext.EntryPoint;
- Status = EntryPoint ((EFI_HANDLE)Context, gST);
- }
- }
-
- //
- // Always free memory allocated by GetFileBufferByFilePath ()
- //
- FreePool (SourceBuffer);
-
- return Status;
-}
-
-/**
- SMM split SMRAM entry.
-
- @param[in, out] RangeToCompare Pointer to EFI_SMRAM_DESCRIPTOR to compare.
- @param[in, out] ReservedRangeToCompare Pointer to EFI_SMM_RESERVED_SMRAM_REGION to compare.
- @param[out] Ranges Output pointer to hold split EFI_SMRAM_DESCRIPTOR entry.
- @param[in, out] RangeCount Pointer to range count.
- @param[out] ReservedRanges Output pointer to hold split EFI_SMM_RESERVED_SMRAM_REGION entry.
- @param[in, out] ReservedRangeCount Pointer to reserved range count.
- @param[out] FinalRanges Output pointer to hold split final EFI_SMRAM_DESCRIPTOR entry
- that no need to be split anymore.
- @param[in, out] FinalRangeCount Pointer to final range count.
-
-**/
-VOID
-SmmSplitSmramEntry (
- IN OUT EFI_SMRAM_DESCRIPTOR *RangeToCompare,
- IN OUT EFI_SMM_RESERVED_SMRAM_REGION *ReservedRangeToCompare,
- OUT EFI_SMRAM_DESCRIPTOR *Ranges,
- IN OUT UINTN *RangeCount,
- OUT EFI_SMM_RESERVED_SMRAM_REGION *ReservedRanges,
- IN OUT UINTN *ReservedRangeCount,
- OUT EFI_SMRAM_DESCRIPTOR *FinalRanges,
- IN OUT UINTN *FinalRangeCount
- )
-{
- UINT64 RangeToCompareEnd;
- UINT64 ReservedRangeToCompareEnd;
-
- RangeToCompareEnd = RangeToCompare->CpuStart + RangeToCompare->PhysicalSize;
- ReservedRangeToCompareEnd = ReservedRangeToCompare->SmramReservedStart + ReservedRangeToCompare->SmramReservedSize;
-
- if ((RangeToCompare->CpuStart >= ReservedRangeToCompare->SmramReservedStart) &&
- (RangeToCompare->CpuStart < ReservedRangeToCompareEnd))
- {
- if (RangeToCompareEnd < ReservedRangeToCompareEnd) {
- //
- // RangeToCompare ReservedRangeToCompare
- // ---- ---- --------------------------------------
- // | | | | -> 1. ReservedRangeToCompare
- // ---- | | |--| --------------------------------------
- // | | | | | |
- // | | | | | | -> 2. FinalRanges[*FinalRangeCount] and increment *FinalRangeCount
- // | | | | | | RangeToCompare->PhysicalSize = 0
- // ---- | | |--| --------------------------------------
- // | | | | -> 3. ReservedRanges[*ReservedRangeCount] and increment *ReservedRangeCount
- // ---- ---- --------------------------------------
- //
-
- //
- // 1. Update ReservedRangeToCompare.
- //
- ReservedRangeToCompare->SmramReservedSize = RangeToCompare->CpuStart - ReservedRangeToCompare->SmramReservedStart;
- //
- // 2. Update FinalRanges[FinalRangeCount] and increment *FinalRangeCount.
- // Zero RangeToCompare->PhysicalSize.
- //
- FinalRanges[*FinalRangeCount].CpuStart = RangeToCompare->CpuStart;
- FinalRanges[*FinalRangeCount].PhysicalStart = RangeToCompare->PhysicalStart;
- FinalRanges[*FinalRangeCount].RegionState = RangeToCompare->RegionState | EFI_ALLOCATED;
- FinalRanges[*FinalRangeCount].PhysicalSize = RangeToCompare->PhysicalSize;
- *FinalRangeCount += 1;
- RangeToCompare->PhysicalSize = 0;
- //
- // 3. Update ReservedRanges[*ReservedRangeCount] and increment *ReservedRangeCount.
- //
- ReservedRanges[*ReservedRangeCount].SmramReservedStart = FinalRanges[*FinalRangeCount - 1].CpuStart + FinalRanges[*FinalRangeCount - 1].PhysicalSize;
- ReservedRanges[*ReservedRangeCount].SmramReservedSize = ReservedRangeToCompareEnd - RangeToCompareEnd;
- *ReservedRangeCount += 1;
- } else {
- //
- // RangeToCompare ReservedRangeToCompare
- // ---- ---- --------------------------------------
- // | | | | -> 1. ReservedRangeToCompare
- // ---- | | |--| --------------------------------------
- // | | | | | |
- // | | | | | | -> 2. FinalRanges[*FinalRangeCount] and increment *FinalRangeCount
- // | | | | | |
- // | | ---- |--| --------------------------------------
- // | | | | -> 3. RangeToCompare
- // ---- ---- --------------------------------------
- //
-
- //
- // 1. Update ReservedRangeToCompare.
- //
- ReservedRangeToCompare->SmramReservedSize = RangeToCompare->CpuStart - ReservedRangeToCompare->SmramReservedStart;
- //
- // 2. Update FinalRanges[FinalRangeCount] and increment *FinalRangeCount.
- //
- FinalRanges[*FinalRangeCount].CpuStart = RangeToCompare->CpuStart;
- FinalRanges[*FinalRangeCount].PhysicalStart = RangeToCompare->PhysicalStart;
- FinalRanges[*FinalRangeCount].RegionState = RangeToCompare->RegionState | EFI_ALLOCATED;
- FinalRanges[*FinalRangeCount].PhysicalSize = ReservedRangeToCompareEnd - RangeToCompare->CpuStart;
- *FinalRangeCount += 1;
- //
- // 3. Update RangeToCompare.
- //
- RangeToCompare->CpuStart += FinalRanges[*FinalRangeCount - 1].PhysicalSize;
- RangeToCompare->PhysicalStart += FinalRanges[*FinalRangeCount - 1].PhysicalSize;
- RangeToCompare->PhysicalSize -= FinalRanges[*FinalRangeCount - 1].PhysicalSize;
- }
- } else if ((ReservedRangeToCompare->SmramReservedStart >= RangeToCompare->CpuStart) &&
- (ReservedRangeToCompare->SmramReservedStart < RangeToCompareEnd))
- {
- if (ReservedRangeToCompareEnd < RangeToCompareEnd) {
- //
- // RangeToCompare ReservedRangeToCompare
- // ---- ---- --------------------------------------
- // | | | | -> 1. RangeToCompare
- // | | ---- |--| --------------------------------------
- // | | | | | |
- // | | | | | | -> 2. FinalRanges[*FinalRangeCount] and increment *FinalRangeCount
- // | | | | | | ReservedRangeToCompare->SmramReservedSize = 0
- // | | ---- |--| --------------------------------------
- // | | | | -> 3. Ranges[*RangeCount] and increment *RangeCount
- // ---- ---- --------------------------------------
- //
-
- //
- // 1. Update RangeToCompare.
- //
- RangeToCompare->PhysicalSize = ReservedRangeToCompare->SmramReservedStart - RangeToCompare->CpuStart;
- //
- // 2. Update FinalRanges[FinalRangeCount] and increment *FinalRangeCount.
- // ReservedRangeToCompare->SmramReservedSize = 0
- //
- FinalRanges[*FinalRangeCount].CpuStart = ReservedRangeToCompare->SmramReservedStart;
- FinalRanges[*FinalRangeCount].PhysicalStart = RangeToCompare->PhysicalStart + RangeToCompare->PhysicalSize;
- FinalRanges[*FinalRangeCount].RegionState = RangeToCompare->RegionState | EFI_ALLOCATED;
- FinalRanges[*FinalRangeCount].PhysicalSize = ReservedRangeToCompare->SmramReservedSize;
- *FinalRangeCount += 1;
- ReservedRangeToCompare->SmramReservedSize = 0;
- //
- // 3. Update Ranges[*RangeCount] and increment *RangeCount.
- //
- Ranges[*RangeCount].CpuStart = FinalRanges[*FinalRangeCount - 1].CpuStart + FinalRanges[*FinalRangeCount - 1].PhysicalSize;
- Ranges[*RangeCount].PhysicalStart = FinalRanges[*FinalRangeCount - 1].PhysicalStart + FinalRanges[*FinalRangeCount - 1].PhysicalSize;
- Ranges[*RangeCount].RegionState = RangeToCompare->RegionState;
- Ranges[*RangeCount].PhysicalSize = RangeToCompareEnd - ReservedRangeToCompareEnd;
- *RangeCount += 1;
- } else {
- //
- // RangeToCompare ReservedRangeToCompare
- // ---- ---- --------------------------------------
- // | | | | -> 1. RangeToCompare
- // | | ---- |--| --------------------------------------
- // | | | | | |
- // | | | | | | -> 2. FinalRanges[*FinalRangeCount] and increment *FinalRangeCount
- // | | | | | |
- // ---- | | |--| --------------------------------------
- // | | | | -> 3. ReservedRangeToCompare
- // ---- ---- --------------------------------------
- //
-
- //
- // 1. Update RangeToCompare.
- //
- RangeToCompare->PhysicalSize = ReservedRangeToCompare->SmramReservedStart - RangeToCompare->CpuStart;
- //
- // 2. Update FinalRanges[FinalRangeCount] and increment *FinalRangeCount.
- // ReservedRangeToCompare->SmramReservedSize = 0
- //
- FinalRanges[*FinalRangeCount].CpuStart = ReservedRangeToCompare->SmramReservedStart;
- FinalRanges[*FinalRangeCount].PhysicalStart = RangeToCompare->PhysicalStart + RangeToCompare->PhysicalSize;
- FinalRanges[*FinalRangeCount].RegionState = RangeToCompare->RegionState | EFI_ALLOCATED;
- FinalRanges[*FinalRangeCount].PhysicalSize = RangeToCompareEnd - ReservedRangeToCompare->SmramReservedStart;
- *FinalRangeCount += 1;
- //
- // 3. Update ReservedRangeToCompare.
- //
- ReservedRangeToCompare->SmramReservedStart += FinalRanges[*FinalRangeCount - 1].PhysicalSize;
- ReservedRangeToCompare->SmramReservedSize -= FinalRanges[*FinalRangeCount - 1].PhysicalSize;
- }
- }
-}
-
-/**
- Returns if SMRAM range and SMRAM reserved range are overlapped.
-
- @param[in] RangeToCompare Pointer to EFI_SMRAM_DESCRIPTOR to compare.
- @param[in] ReservedRangeToCompare Pointer to EFI_SMM_RESERVED_SMRAM_REGION to compare.
-
- @retval TRUE There is overlap.
- @retval TRUE Math error.
- @retval FALSE There is no overlap.
-
-**/
-BOOLEAN
-SmmIsSmramOverlap (
- IN EFI_SMRAM_DESCRIPTOR *RangeToCompare,
- IN EFI_SMM_RESERVED_SMRAM_REGION *ReservedRangeToCompare
- )
-{
- UINT64 RangeToCompareEnd;
- UINT64 ReservedRangeToCompareEnd;
- BOOLEAN IsOverUnderflow1;
- BOOLEAN IsOverUnderflow2;
-
- // Check for over or underflow.
- IsOverUnderflow1 = EFI_ERROR (
- SafeUint64Add (
- (UINT64)RangeToCompare->CpuStart,
- RangeToCompare->PhysicalSize,
- &RangeToCompareEnd
- )
- );
- IsOverUnderflow2 = EFI_ERROR (
- SafeUint64Add (
- (UINT64)ReservedRangeToCompare->SmramReservedStart,
- ReservedRangeToCompare->SmramReservedSize,
- &ReservedRangeToCompareEnd
- )
- );
- if (IsOverUnderflow1 || IsOverUnderflow2) {
- return TRUE;
- }
-
- if ((RangeToCompare->CpuStart >= ReservedRangeToCompare->SmramReservedStart) &&
- (RangeToCompare->CpuStart < ReservedRangeToCompareEnd))
- {
- return TRUE;
- } else if ((ReservedRangeToCompare->SmramReservedStart >= RangeToCompare->CpuStart) &&
- (ReservedRangeToCompare->SmramReservedStart < RangeToCompareEnd))
- {
- return TRUE;
- }
-
- return FALSE;
-}
-
-/**
- Get full SMRAM ranges.
-
- It will get SMRAM ranges from SmmAccess protocol and SMRAM reserved ranges from
- SmmConfiguration protocol, split the entries if there is overlap between them.
- It will also reserve one entry for SMM core.
-
- @param[out] FullSmramRangeCount Output pointer to full SMRAM range count.
-
- @return Pointer to full SMRAM ranges.
-
-**/
-EFI_SMRAM_DESCRIPTOR *
-GetFullSmramRanges (
- OUT UINTN *FullSmramRangeCount
- )
-{
- EFI_STATUS Status;
- EFI_SMM_CONFIGURATION_PROTOCOL *SmmConfiguration;
- UINTN Size;
- UINTN Index;
- UINTN Index2;
- EFI_SMRAM_DESCRIPTOR *FullSmramRanges;
- UINTN TempSmramRangeCount;
- UINTN AdditionSmramRangeCount;
- EFI_SMRAM_DESCRIPTOR *TempSmramRanges;
- UINTN SmramRangeCount;
- EFI_SMRAM_DESCRIPTOR *SmramRanges;
- UINTN SmramReservedCount;
- EFI_SMM_RESERVED_SMRAM_REGION *SmramReservedRanges;
- UINTN MaxCount;
- BOOLEAN Rescan;
-
- //
- // Get SMM Configuration Protocol if it is present.
- //
- SmmConfiguration = NULL;
- Status = gBS->LocateProtocol (&gEfiSmmConfigurationProtocolGuid, NULL, (VOID **)&SmmConfiguration);
-
- //
- // Get SMRAM information.
- //
- Size = 0;
- Status = mSmmAccess->GetCapabilities (mSmmAccess, &Size, NULL);
- ASSERT (Status == EFI_BUFFER_TOO_SMALL);
-
- SmramRangeCount = Size / sizeof (EFI_SMRAM_DESCRIPTOR);
-
- //
- // Get SMRAM reserved region count.
- //
- SmramReservedCount = 0;
- if (SmmConfiguration != NULL) {
- while (SmmConfiguration->SmramReservedRegions[SmramReservedCount].SmramReservedSize != 0) {
- SmramReservedCount++;
- }
- }
-
- //
- // Reserve one entry for SMM Core in the full SMRAM ranges.
- //
- AdditionSmramRangeCount = 1;
- if (PcdGet64 (PcdLoadModuleAtFixAddressEnable) != 0) {
- //
- // Reserve two entries for all SMM drivers and SMM Core in the full SMRAM ranges.
- //
- AdditionSmramRangeCount = 2;
- }
-
- if (SmramReservedCount == 0) {
- //
- // No reserved SMRAM entry from SMM Configuration Protocol.
- //
- *FullSmramRangeCount = SmramRangeCount + AdditionSmramRangeCount;
- Size = (*FullSmramRangeCount) * sizeof (EFI_SMRAM_DESCRIPTOR);
- FullSmramRanges = (EFI_SMRAM_DESCRIPTOR *)AllocateZeroPool (Size);
- ASSERT (FullSmramRanges != NULL);
-
- Status = mSmmAccess->GetCapabilities (mSmmAccess, &Size, FullSmramRanges);
- ASSERT_EFI_ERROR (Status);
-
- return FullSmramRanges;
- }
-
- //
- // Why MaxCount = X + 2 * Y?
- // Take Y = 1 as example below, Y > 1 case is just the iteration of Y = 1.
- //
- // X = 1 Y = 1 MaxCount = 3 = 1 + 2 * 1
- // ---- ----
- // | | ---- |--|
- // | | | | -> | |
- // | | ---- |--|
- // ---- ----
- //
- // X = 2 Y = 1 MaxCount = 4 = 2 + 2 * 1
- // ---- ----
- // | | | |
- // | | ---- |--|
- // | | | | | |
- // |--| | | -> |--|
- // | | | | | |
- // | | ---- |--|
- // | | | |
- // ---- ----
- //
- // X = 3 Y = 1 MaxCount = 5 = 3 + 2 * 1
- // ---- ----
- // | | | |
- // | | ---- |--|
- // |--| | | |--|
- // | | | | -> | |
- // |--| | | |--|
- // | | ---- |--|
- // | | | |
- // ---- ----
- //
- // ......
- //
- MaxCount = SmramRangeCount + 2 * SmramReservedCount;
-
- Size = MaxCount * sizeof (EFI_SMM_RESERVED_SMRAM_REGION);
- SmramReservedRanges = (EFI_SMM_RESERVED_SMRAM_REGION *)AllocatePool (Size);
- ASSERT (SmramReservedRanges != NULL);
- for (Index = 0; Index < SmramReservedCount; Index++) {
- CopyMem (&SmramReservedRanges[Index], &SmmConfiguration->SmramReservedRegions[Index], sizeof (EFI_SMM_RESERVED_SMRAM_REGION));
- }
-
- Size = MaxCount * sizeof (EFI_SMRAM_DESCRIPTOR);
- TempSmramRanges = (EFI_SMRAM_DESCRIPTOR *)AllocatePool (Size);
- ASSERT (TempSmramRanges != NULL);
- TempSmramRangeCount = 0;
-
- SmramRanges = (EFI_SMRAM_DESCRIPTOR *)AllocatePool (Size);
- ASSERT (SmramRanges != NULL);
- Status = mSmmAccess->GetCapabilities (mSmmAccess, &Size, SmramRanges);
- ASSERT_EFI_ERROR (Status);
-
- do {
- Rescan = FALSE;
- for (Index = 0; (Index < SmramRangeCount) && !Rescan; Index++) {
- //
- // Skip zero size entry.
- //
- if (SmramRanges[Index].PhysicalSize != 0) {
- for (Index2 = 0; (Index2 < SmramReservedCount) && !Rescan; Index2++) {
- //
- // Skip zero size entry.
- //
- if (SmramReservedRanges[Index2].SmramReservedSize != 0) {
- if (SmmIsSmramOverlap (
- &SmramRanges[Index],
- &SmramReservedRanges[Index2]
- ))
- {
- //
- // There is overlap, need to split entry and then rescan.
- //
- SmmSplitSmramEntry (
- &SmramRanges[Index],
- &SmramReservedRanges[Index2],
- SmramRanges,
- &SmramRangeCount,
- SmramReservedRanges,
- &SmramReservedCount,
- TempSmramRanges,
- &TempSmramRangeCount
- );
- Rescan = TRUE;
- }
- }
- }
-
- if (!Rescan) {
- //
- // No any overlap, copy the entry to the temp SMRAM ranges.
- // Zero SmramRanges[Index].PhysicalSize = 0;
- //
- CopyMem (&TempSmramRanges[TempSmramRangeCount++], &SmramRanges[Index], sizeof (EFI_SMRAM_DESCRIPTOR));
- SmramRanges[Index].PhysicalSize = 0;
- }
- }
- }
- } while (Rescan);
-
- ASSERT (TempSmramRangeCount <= MaxCount);
-
- //
- // Sort the entries
- //
- FullSmramRanges = AllocateZeroPool ((TempSmramRangeCount + AdditionSmramRangeCount) * sizeof (EFI_SMRAM_DESCRIPTOR));
- ASSERT (FullSmramRanges != NULL);
- *FullSmramRangeCount = 0;
- do {
- for (Index = 0; Index < TempSmramRangeCount; Index++) {
- if (TempSmramRanges[Index].PhysicalSize != 0) {
- break;
- }
- }
-
- ASSERT (Index < TempSmramRangeCount);
- for (Index2 = 0; Index2 < TempSmramRangeCount; Index2++) {
- if ((Index2 != Index) && (TempSmramRanges[Index2].PhysicalSize != 0) && (TempSmramRanges[Index2].CpuStart < TempSmramRanges[Index].CpuStart)) {
- Index = Index2;
- }
- }
-
- CopyMem (&FullSmramRanges[*FullSmramRangeCount], &TempSmramRanges[Index], sizeof (EFI_SMRAM_DESCRIPTOR));
- *FullSmramRangeCount += 1;
- TempSmramRanges[Index].PhysicalSize = 0;
- } while (*FullSmramRangeCount < TempSmramRangeCount);
-
- ASSERT (*FullSmramRangeCount == TempSmramRangeCount);
- *FullSmramRangeCount += AdditionSmramRangeCount;
-
- FreePool (SmramRanges);
- FreePool (SmramReservedRanges);
- FreePool (TempSmramRanges);
-
- return FullSmramRanges;
-}
-
-/**
- The Entry Point for SMM IPL
-
- Load SMM Core into SMRAM, register SMM Core entry point for SMIs, install
- SMM Base 2 Protocol and SMM Communication Protocol, and register for the
- critical events required to coordinate between DXE and SMM environments.
-
- @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
-SmmIplEntry (
- IN EFI_HANDLE ImageHandle,
- IN EFI_SYSTEM_TABLE *SystemTable
- )
-{
- EFI_STATUS Status;
- UINTN Index;
- UINT64 MaxSize;
- VOID *Registration;
- UINT64 SmmCodeSize;
- EFI_CPU_ARCH_PROTOCOL *CpuArch;
- EFI_STATUS SetAttrStatus;
- EFI_SMRAM_DESCRIPTOR *SmramRangeSmmDriver;
- EFI_GCD_MEMORY_SPACE_DESCRIPTOR MemDesc;
-
- //
- // Fill in the image handle of the SMM IPL so the SMM Core can use this as the
- // ParentImageHandle field of the Load Image Protocol for all SMM Drivers loaded
- // by the SMM Core
- //
- mSmmCorePrivateData.SmmIplImageHandle = ImageHandle;
-
- //
- // Get SMM Access Protocol
- //
- Status = gBS->LocateProtocol (&gEfiSmmAccess2ProtocolGuid, NULL, (VOID **)&mSmmAccess);
- ASSERT_EFI_ERROR (Status);
-
- //
- // Get SMM Control2 Protocol
- //
- Status = gBS->LocateProtocol (&gEfiSmmControl2ProtocolGuid, NULL, (VOID **)&mSmmControl2);
- ASSERT_EFI_ERROR (Status);
-
- gSmmCorePrivate->SmramRanges = GetFullSmramRanges (&gSmmCorePrivate->SmramRangeCount);
-
- //
- // Open all SMRAM ranges
- //
- Status = mSmmAccess->Open (mSmmAccess);
- ASSERT_EFI_ERROR (Status);
-
- //
- // Print debug message that the SMRAM window is now open.
- //
- DEBUG ((DEBUG_INFO, "SMM IPL opened SMRAM window\n"));
-
- //
- // Find the largest SMRAM range between 1MB and 4GB that is at least 256KB - 4K in size
- //
- mCurrentSmramRange = NULL;
- for (Index = 0, MaxSize = SIZE_256KB - EFI_PAGE_SIZE; Index < gSmmCorePrivate->SmramRangeCount; Index++) {
- //
- // Skip any SMRAM region that is already allocated, needs testing, or needs ECC initialization
- //
- if ((gSmmCorePrivate->SmramRanges[Index].RegionState & (EFI_ALLOCATED | EFI_NEEDS_TESTING | EFI_NEEDS_ECC_INITIALIZATION)) != 0) {
- continue;
- }
-
- if (gSmmCorePrivate->SmramRanges[Index].CpuStart >= BASE_1MB) {
- if ((gSmmCorePrivate->SmramRanges[Index].CpuStart + gSmmCorePrivate->SmramRanges[Index].PhysicalSize - 1) <= MAX_ADDRESS) {
- if (gSmmCorePrivate->SmramRanges[Index].PhysicalSize >= MaxSize) {
- MaxSize = gSmmCorePrivate->SmramRanges[Index].PhysicalSize;
- mCurrentSmramRange = &gSmmCorePrivate->SmramRanges[Index];
- }
- }
- }
- }
-
- if (mCurrentSmramRange != NULL) {
- //
- // Print debug message showing SMRAM window that will be used by SMM IPL and SMM Core
- //
- DEBUG ((
- DEBUG_INFO,
- "SMM IPL found SMRAM window %p - %p\n",
- (VOID *)(UINTN)mCurrentSmramRange->CpuStart,
- (VOID *)(UINTN)(mCurrentSmramRange->CpuStart + mCurrentSmramRange->PhysicalSize - 1)
- ));
-
- GetSmramCacheRange (mCurrentSmramRange, &mSmramCacheBase, &mSmramCacheSize);
- //
- // Make sure we can change the desired memory attributes.
- //
- Status = gDS->GetMemorySpaceDescriptor (
- mSmramCacheBase,
- &MemDesc
- );
- ASSERT_EFI_ERROR (Status);
- if ((MemDesc.Capabilities & SMRAM_CAPABILITIES) != SMRAM_CAPABILITIES) {
- gDS->SetMemorySpaceCapabilities (
- mSmramCacheBase,
- mSmramCacheSize,
- MemDesc.Capabilities | SMRAM_CAPABILITIES
- );
- }
-
- //
- // If CPU AP is present, attempt to set SMRAM cacheability to WB and clear
- // all paging attributes.
- // Note that it is expected that cacheability of SMRAM has been set to WB if CPU AP
- // is not available here.
- //
- CpuArch = NULL;
- Status = gBS->LocateProtocol (&gEfiCpuArchProtocolGuid, NULL, (VOID **)&CpuArch);
- if (!EFI_ERROR (Status)) {
- MemDesc.Attributes &= ~(EFI_CACHE_ATTRIBUTE_MASK | EFI_MEMORY_ATTRIBUTE_MASK);
- MemDesc.Attributes |= EFI_MEMORY_WB;
- Status = gDS->SetMemorySpaceAttributes (
- mSmramCacheBase,
- mSmramCacheSize,
- MemDesc.Attributes
- );
- if (EFI_ERROR (Status)) {
- DEBUG ((DEBUG_WARN, "SMM IPL failed to set SMRAM window to EFI_MEMORY_WB\n"));
- }
-
- DEBUG_CODE (
- gDS->GetMemorySpaceDescriptor (
- mSmramCacheBase,
- &MemDesc
- );
- DEBUG ((DEBUG_INFO, "SMRAM attributes: %016lx\n", MemDesc.Attributes));
- ASSERT ((MemDesc.Attributes & EFI_MEMORY_ATTRIBUTE_MASK) == 0);
- );
- }
-
- //
- // if Loading module at Fixed Address feature is enabled, save the SMRAM base to Load
- // Modules At Fixed Address Configuration Table.
- //
- if (PcdGet64 (PcdLoadModuleAtFixAddressEnable) != 0) {
- //
- // Build tool will calculate the smm code size and then patch the PcdLoadFixAddressSmmCodePageNumber
- //
- SmmCodeSize = LShiftU64 (PcdGet32 (PcdLoadFixAddressSmmCodePageNumber), EFI_PAGE_SHIFT);
- //
- // The SMRAM available memory is assumed to be larger than SmmCodeSize
- //
- ASSERT (mCurrentSmramRange->PhysicalSize > SmmCodeSize);
- //
- // Retrieve Load modules At fixed address configuration table and save the SMRAM base.
- //
- Status = EfiGetSystemConfigurationTable (
- &gLoadFixedAddressConfigurationTableGuid,
- (VOID **)&mLMFAConfigurationTable
- );
- if (!EFI_ERROR (Status) && (mLMFAConfigurationTable != NULL)) {
- mLMFAConfigurationTable->SmramBase = mCurrentSmramRange->CpuStart;
- //
- // Print the SMRAM base
- //
- DEBUG ((DEBUG_INFO, "LOADING MODULE FIXED INFO: TSEG BASE is %x. \n", mLMFAConfigurationTable->SmramBase));
- }
-
- //
- // Fill the Smram range for all SMM code
- //
- SmramRangeSmmDriver = &gSmmCorePrivate->SmramRanges[gSmmCorePrivate->SmramRangeCount - 2];
- SmramRangeSmmDriver->CpuStart = mCurrentSmramRange->CpuStart;
- SmramRangeSmmDriver->PhysicalStart = mCurrentSmramRange->PhysicalStart;
- SmramRangeSmmDriver->RegionState = mCurrentSmramRange->RegionState | EFI_ALLOCATED;
- SmramRangeSmmDriver->PhysicalSize = SmmCodeSize;
-
- mCurrentSmramRange->PhysicalSize -= SmmCodeSize;
- mCurrentSmramRange->CpuStart = mCurrentSmramRange->CpuStart + SmmCodeSize;
- mCurrentSmramRange->PhysicalStart = mCurrentSmramRange->PhysicalStart + SmmCodeSize;
- }
-
- //
- // Load SMM Core into SMRAM and execute it from SMRAM
- //
- Status = ExecuteSmmCoreFromSmram (
- mCurrentSmramRange,
- &gSmmCorePrivate->SmramRanges[gSmmCorePrivate->SmramRangeCount - 1],
- gSmmCorePrivate
- );
- if (EFI_ERROR (Status)) {
- //
- // Print error message that the SMM Core failed to be loaded and executed.
- //
- DEBUG ((DEBUG_ERROR, "SMM IPL could not load and execute SMM Core from SMRAM\n"));
-
- //
- // Attempt to reset SMRAM cacheability to UC
- //
- if (CpuArch != NULL) {
- SetAttrStatus = gDS->SetMemorySpaceAttributes (
- mSmramCacheBase,
- mSmramCacheSize,
- EFI_MEMORY_UC
- );
- if (EFI_ERROR (SetAttrStatus)) {
- DEBUG ((DEBUG_WARN, "SMM IPL failed to reset SMRAM window to EFI_MEMORY_UC\n"));
- }
- }
- }
- } else {
- //
- // Print error message that there are not enough SMRAM resources to load the SMM Core.
- //
- DEBUG ((DEBUG_ERROR, "SMM IPL could not find a large enough SMRAM region to load SMM Core\n"));
- }
-
- //
- // If the SMM Core could not be loaded then close SMRAM window, free allocated
- // resources, and return an error so SMM IPL will be unloaded.
- //
- if ((mCurrentSmramRange == NULL) || EFI_ERROR (Status)) {
- //
- // Close all SMRAM ranges
- //
- Status = mSmmAccess->Close (mSmmAccess);
- ASSERT_EFI_ERROR (Status);
-
- //
- // Print debug message that the SMRAM window is now closed.
- //
- DEBUG ((DEBUG_INFO, "SMM IPL closed SMRAM window\n"));
-
- //
- // Free all allocated resources
- //
- FreePool (gSmmCorePrivate->SmramRanges);
-
- return EFI_UNSUPPORTED;
- }
-
- //
- // Install SMM Base2 Protocol and SMM Communication Protocol
- //
- Status = gBS->InstallMultipleProtocolInterfaces (
- &mSmmIplHandle,
- &gEfiSmmBase2ProtocolGuid,
- &mSmmBase2,
- &gEfiSmmCommunicationProtocolGuid,
- &mSmmCommunication,
- &gEfiMmCommunication2ProtocolGuid,
- &mMmCommunication2,
- NULL
- );
- ASSERT_EFI_ERROR (Status);
-
- //
- // Create the set of protocol and event notifications that the SMM IPL requires
- //
- for (Index = 0; mSmmIplEvents[Index].NotifyFunction != NULL; Index++) {
- if (mSmmIplEvents[Index].Protocol) {
- mSmmIplEvents[Index].Event = EfiCreateProtocolNotifyEvent (
- mSmmIplEvents[Index].Guid,
- mSmmIplEvents[Index].NotifyTpl,
- mSmmIplEvents[Index].NotifyFunction,
- mSmmIplEvents[Index].NotifyContext,
- &Registration
- );
- } else {
- Status = gBS->CreateEventEx (
- EVT_NOTIFY_SIGNAL,
- mSmmIplEvents[Index].NotifyTpl,
- mSmmIplEvents[Index].NotifyFunction,
- mSmmIplEvents[Index].NotifyContext,
- mSmmIplEvents[Index].Guid,
- &mSmmIplEvents[Index].Event
- );
- ASSERT_EFI_ERROR (Status);
- }
- }
-
- return EFI_SUCCESS;
-}
+/** @file + SMM IPL that produces SMM related runtime protocols and load the SMM Core into SMRAM + + Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.<BR> + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include <PiDxe.h> + +#include <Protocol/SmmBase2.h> +#include <Protocol/SmmCommunication.h> +#include <Protocol/MmCommunication2.h> +#include <Protocol/SmmAccess2.h> +#include <Protocol/SmmConfiguration.h> +#include <Protocol/SmmControl2.h> +#include <Protocol/DxeSmmReadyToLock.h> +#include <Protocol/Cpu.h> + +#include <Guid/EventGroup.h> +#include <Guid/EventLegacyBios.h> +#include <Guid/LoadModuleAtFixedAddress.h> + +#include <Library/BaseLib.h> +#include <Library/BaseMemoryLib.h> +#include <Library/PeCoffLib.h> +#include <Library/CacheMaintenanceLib.h> +#include <Library/MemoryAllocationLib.h> +#include <Library/DebugLib.h> +#include <Library/UefiBootServicesTableLib.h> +#include <Library/DxeServicesTableLib.h> +#include <Library/DxeServicesLib.h> +#include <Library/UefiLib.h> +#include <Library/UefiRuntimeLib.h> +#include <Library/PcdLib.h> +#include <Library/ReportStatusCodeLib.h> +#include "PiSmmCorePrivateData.h" +#include <Library/SafeIntLib.h> + +#define SMRAM_CAPABILITIES (EFI_MEMORY_WB | EFI_MEMORY_UC) + +// +// Function prototypes from produced protocols +// + +/** + Indicate whether the driver is currently executing in the SMM Initialization phase. + + @param This The EFI_SMM_BASE2_PROTOCOL instance. + @param InSmram Pointer to a Boolean which, on return, indicates that the driver is currently executing + inside of SMRAM (TRUE) or outside of SMRAM (FALSE). + + @retval EFI_INVALID_PARAMETER InSmram was NULL. + @retval EFI_SUCCESS The call returned successfully. + +**/ +EFI_STATUS +EFIAPI +SmmBase2InSmram ( + IN CONST EFI_SMM_BASE2_PROTOCOL *This, + OUT BOOLEAN *InSmram + ); + +/** + Retrieves the location of the System Management System Table (SMST). + + @param This The EFI_SMM_BASE2_PROTOCOL instance. + @param Smst On return, points to a pointer to the System Management Service Table (SMST). + + @retval EFI_INVALID_PARAMETER Smst or This was invalid. + @retval EFI_SUCCESS The memory was returned to the system. + @retval EFI_UNSUPPORTED Not in SMM. + +**/ +EFI_STATUS +EFIAPI +SmmBase2GetSmstLocation ( + IN CONST EFI_SMM_BASE2_PROTOCOL *This, + OUT EFI_SMM_SYSTEM_TABLE2 **Smst + ); + +/** + Communicates with a registered handler. + + This function provides a service to send and receive messages from a registered + UEFI service. This function is part of the SMM Communication Protocol that may + be called in physical mode prior to SetVirtualAddressMap() and in virtual mode + after SetVirtualAddressMap(). + + @param[in] This The EFI_SMM_COMMUNICATION_PROTOCOL instance. + @param[in, out] CommBuffer A pointer to the buffer to convey into SMRAM. + @param[in, out] CommSize The size of the data buffer being passed in. On exit, the size of data + being returned. Zero if the handler does not wish to reply with any data. + This parameter is optional and may be NULL. + + @retval EFI_SUCCESS The message was successfully posted. + @retval EFI_INVALID_PARAMETER The CommBuffer was NULL. + @retval EFI_BAD_BUFFER_SIZE The buffer is too large for the MM implementation. + If this error is returned, the MessageLength field + in the CommBuffer header or the integer pointed by + CommSize, are updated to reflect the maximum payload + size the implementation can accommodate. + @retval EFI_ACCESS_DENIED The CommunicateBuffer parameter or CommSize parameter, + if not omitted, are in address range that cannot be + accessed by the MM environment. + +**/ +EFI_STATUS +EFIAPI +SmmCommunicationCommunicate ( + IN CONST EFI_SMM_COMMUNICATION_PROTOCOL *This, + IN OUT VOID *CommBuffer, + IN OUT UINTN *CommSize OPTIONAL + ); + +/** + Communicates with a registered handler. + + This function provides a service to send and receive messages from a registered UEFI service. + + @param[in] This The EFI_MM_COMMUNICATION_PROTOCOL instance. + @param[in] CommBufferPhysical Physical address of the MM communication buffer + @param[in] CommBufferVirtual Virtual address of the MM communication buffer + @param[in] CommSize The size of the data buffer being passed in. On exit, the size of data + being returned. Zero if the handler does not wish to reply with any data. + This parameter is optional and may be NULL. + + @retval EFI_SUCCESS The message was successfully posted. + @retval EFI_INVALID_PARAMETER The CommBuffer was NULL. + @retval EFI_BAD_BUFFER_SIZE The buffer is too large for the MM implementation. + If this error is returned, the MessageLength field + in the CommBuffer header or the integer pointed by + CommSize, are updated to reflect the maximum payload + size the implementation can accommodate. + @retval EFI_ACCESS_DENIED The CommunicateBuffer parameter or CommSize parameter, + if not omitted, are in address range that cannot be + accessed by the MM environment. + +**/ +EFI_STATUS +EFIAPI +SmmCommunicationMmCommunicate2 ( + IN CONST EFI_MM_COMMUNICATION2_PROTOCOL *This, + IN OUT VOID *CommBufferPhysical, + IN OUT VOID *CommBufferVirtual, + IN OUT UINTN *CommSize OPTIONAL + ); + +/** + Event notification that is fired every time a gEfiSmmConfigurationProtocol installs. + + @param Event The Event that is being processed, not used. + @param Context Event Context, not used. + +**/ +VOID +EFIAPI +SmmIplSmmConfigurationEventNotify ( + IN EFI_EVENT Event, + IN VOID *Context + ); + +/** + Event notification that is fired every time a DxeSmmReadyToLock protocol is added + or if gEfiEventReadyToBootGuid is signalled. + + @param Event The Event that is being processed, not used. + @param Context Event Context, not used. + +**/ +VOID +EFIAPI +SmmIplReadyToLockEventNotify ( + IN EFI_EVENT Event, + IN VOID *Context + ); + +/** + Event notification that is fired when DxeDispatch Event Group is signaled. + + @param Event The Event that is being processed, not used. + @param Context Event Context, not used. + +**/ +VOID +EFIAPI +SmmIplDxeDispatchEventNotify ( + IN EFI_EVENT Event, + IN VOID *Context + ); + +/** + Event notification that is fired when a GUIDed Event Group is signaled. + + @param Event The Event that is being processed, not used. + @param Context Event Context, not used. + +**/ +VOID +EFIAPI +SmmIplGuidedEventNotify ( + IN EFI_EVENT Event, + IN VOID *Context + ); + +/** + Event notification that is fired when EndOfDxe Event Group is signaled. + + @param Event The Event that is being processed, not used. + @param Context Event Context, not used. + +**/ +VOID +EFIAPI +SmmIplEndOfDxeEventNotify ( + IN EFI_EVENT Event, + IN VOID *Context + ); + +/** + Notification function of EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE. + + This is a notification function registered on EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE event. + It convers pointer to new virtual address. + + @param Event Event whose notification function is being invoked. + @param Context Pointer to the notification function's context. + +**/ +VOID +EFIAPI +SmmIplSetVirtualAddressNotify ( + IN EFI_EVENT Event, + IN VOID *Context + ); + +// +// Data structure used to declare a table of protocol notifications and event +// notifications required by the SMM IPL +// +typedef struct { + BOOLEAN Protocol; + BOOLEAN CloseOnLock; + EFI_GUID *Guid; + EFI_EVENT_NOTIFY NotifyFunction; + VOID *NotifyContext; + EFI_TPL NotifyTpl; + EFI_EVENT Event; +} SMM_IPL_EVENT_NOTIFICATION; + +// +// Handle to install the SMM Base2 Protocol and the SMM Communication Protocol +// +EFI_HANDLE mSmmIplHandle = NULL; + +// +// SMM Base 2 Protocol instance +// +EFI_SMM_BASE2_PROTOCOL mSmmBase2 = { + SmmBase2InSmram, + SmmBase2GetSmstLocation +}; + +// +// SMM Communication Protocol instance +// +EFI_SMM_COMMUNICATION_PROTOCOL mSmmCommunication = { + SmmCommunicationCommunicate +}; + +// +// PI 1.7 MM Communication Protocol 2 instance +// +EFI_MM_COMMUNICATION2_PROTOCOL mMmCommunication2 = { + SmmCommunicationMmCommunicate2 +}; + +// +// SMM Core Private Data structure that contains the data shared between +// the SMM IPL and the SMM Core. +// +SMM_CORE_PRIVATE_DATA mSmmCorePrivateData = { + SMM_CORE_PRIVATE_DATA_SIGNATURE, // Signature + NULL, // SmmIplImageHandle + 0, // SmramRangeCount + NULL, // SmramRanges + NULL, // SmmEntryPoint + FALSE, // SmmEntryPointRegistered + FALSE, // InSmm + NULL, // Smst + NULL, // CommunicationBuffer + 0, // BufferSize + EFI_SUCCESS // ReturnStatus +}; + +// +// Global pointer used to access mSmmCorePrivateData from outside and inside SMM +// +SMM_CORE_PRIVATE_DATA *gSmmCorePrivate = &mSmmCorePrivateData; + +// +// SMM IPL global variables +// +EFI_SMM_CONTROL2_PROTOCOL *mSmmControl2; +EFI_SMM_ACCESS2_PROTOCOL *mSmmAccess; +EFI_SMRAM_DESCRIPTOR *mCurrentSmramRange; +BOOLEAN mSmmLocked = FALSE; +BOOLEAN mEndOfDxe = FALSE; +EFI_PHYSICAL_ADDRESS mSmramCacheBase; +UINT64 mSmramCacheSize; + +EFI_SMM_COMMUNICATE_HEADER mCommunicateHeader; +EFI_LOAD_FIXED_ADDRESS_CONFIGURATION_TABLE *mLMFAConfigurationTable = NULL; + +// +// Table of Protocol notification and GUIDed Event notifications that the SMM IPL requires +// +SMM_IPL_EVENT_NOTIFICATION mSmmIplEvents[] = { + // + // Declare protocol notification on the SMM Configuration protocol. When this notification is established, + // the associated event is immediately signalled, so the notification function will be executed and the + // SMM Configuration Protocol will be found if it is already in the handle database. + // + { TRUE, FALSE, &gEfiSmmConfigurationProtocolGuid, SmmIplSmmConfigurationEventNotify, &gEfiSmmConfigurationProtocolGuid, TPL_NOTIFY, NULL }, + // + // Declare protocol notification on DxeSmmReadyToLock protocols. When this notification is established, + // the associated event is immediately signalled, so the notification function will be executed and the + // DXE SMM Ready To Lock Protocol will be found if it is already in the handle database. + // + { TRUE, TRUE, &gEfiDxeSmmReadyToLockProtocolGuid, SmmIplReadyToLockEventNotify, &gEfiDxeSmmReadyToLockProtocolGuid, TPL_CALLBACK, NULL }, + // + // Declare event notification on EndOfDxe event. When this notification is established, + // the associated event is immediately signalled, so the notification function will be executed and the + // SMM End Of Dxe Protocol will be found if it is already in the handle database. + // + { FALSE, TRUE, &gEfiEndOfDxeEventGroupGuid, SmmIplGuidedEventNotify, &gEfiEndOfDxeEventGroupGuid, TPL_CALLBACK, NULL }, + // + // Declare event notification on EndOfDxe event. This is used to set EndOfDxe event signaled flag. + // + { FALSE, TRUE, &gEfiEndOfDxeEventGroupGuid, SmmIplEndOfDxeEventNotify, &gEfiEndOfDxeEventGroupGuid, TPL_CALLBACK, NULL }, + // + // Declare event notification on the DXE Dispatch Event Group. This event is signaled by the DXE Core + // each time the DXE Core dispatcher has completed its work. When this event is signalled, the SMM Core + // if notified, so the SMM Core can dispatch SMM drivers. + // + { FALSE, TRUE, &gEfiEventDxeDispatchGuid, SmmIplDxeDispatchEventNotify, &gEfiEventDxeDispatchGuid, TPL_CALLBACK, NULL }, + // + // Declare event notification on Ready To Boot Event Group. This is an extra event notification that is + // used to make sure SMRAM is locked before any boot options are processed. + // + { FALSE, TRUE, &gEfiEventReadyToBootGuid, SmmIplReadyToLockEventNotify, &gEfiEventReadyToBootGuid, TPL_CALLBACK, NULL }, + // + // Declare event notification on Legacy Boot Event Group. This is used to inform the SMM Core that the platform + // is performing a legacy boot operation, and that the UEFI environment is no longer available and the SMM Core + // must guarantee that it does not access any UEFI related structures outside of SMRAM. + // It is also to inform the SMM Core to notify SMM driver that system enter legacy boot. + // + { FALSE, FALSE, &gEfiEventLegacyBootGuid, SmmIplGuidedEventNotify, &gEfiEventLegacyBootGuid, TPL_CALLBACK, NULL }, + // + // Declare event notification on Exit Boot Services Event Group. This is used to inform the SMM Core + // to notify SMM driver that system enter exit boot services. + // + { FALSE, FALSE, &gEfiEventExitBootServicesGuid, SmmIplGuidedEventNotify, &gEfiEventExitBootServicesGuid, TPL_CALLBACK, NULL }, + // + // Declare event notification on Ready To Boot Event Group. This is used to inform the SMM Core + // to notify SMM driver that system enter ready to boot. + // + { FALSE, FALSE, &gEfiEventReadyToBootGuid, SmmIplGuidedEventNotify, &gEfiEventReadyToBootGuid, TPL_CALLBACK, NULL }, + // + // Declare event notification on SetVirtualAddressMap() Event Group. This is used to convert gSmmCorePrivate + // and mSmmControl2 from physical addresses to virtual addresses. + // + { FALSE, FALSE, &gEfiEventVirtualAddressChangeGuid, SmmIplSetVirtualAddressNotify, NULL, TPL_CALLBACK, NULL }, + // + // Terminate the table of event notifications + // + { FALSE, FALSE, NULL, NULL, NULL, TPL_CALLBACK, NULL } +}; + +/** + Find the maximum SMRAM cache range that covers the range specified by SmramRange. + + This function searches and joins all adjacent ranges of SmramRange into a range to be cached. + + @param SmramRange The SMRAM range to search from. + @param SmramCacheBase The returned cache range base. + @param SmramCacheSize The returned cache range size. + +**/ +VOID +GetSmramCacheRange ( + IN EFI_SMRAM_DESCRIPTOR *SmramRange, + OUT EFI_PHYSICAL_ADDRESS *SmramCacheBase, + OUT UINT64 *SmramCacheSize + ) +{ + UINTN Index; + EFI_PHYSICAL_ADDRESS RangeCpuStart; + UINT64 RangePhysicalSize; + BOOLEAN FoundAjacentRange; + + *SmramCacheBase = SmramRange->CpuStart; + *SmramCacheSize = SmramRange->PhysicalSize; + + do { + FoundAjacentRange = FALSE; + for (Index = 0; Index < gSmmCorePrivate->SmramRangeCount; Index++) { + RangeCpuStart = gSmmCorePrivate->SmramRanges[Index].CpuStart; + RangePhysicalSize = gSmmCorePrivate->SmramRanges[Index].PhysicalSize; + if ((RangeCpuStart < *SmramCacheBase) && (*SmramCacheBase == (RangeCpuStart + RangePhysicalSize))) { + *SmramCacheBase = RangeCpuStart; + *SmramCacheSize += RangePhysicalSize; + FoundAjacentRange = TRUE; + } else if (((*SmramCacheBase + *SmramCacheSize) == RangeCpuStart) && (RangePhysicalSize > 0)) { + *SmramCacheSize += RangePhysicalSize; + FoundAjacentRange = TRUE; + } + } + } while (FoundAjacentRange); +} + +/** + Indicate whether the driver is currently executing in the SMM Initialization phase. + + @param This The EFI_SMM_BASE2_PROTOCOL instance. + @param InSmram Pointer to a Boolean which, on return, indicates that the driver is currently executing + inside of SMRAM (TRUE) or outside of SMRAM (FALSE). + + @retval EFI_INVALID_PARAMETER InSmram was NULL. + @retval EFI_SUCCESS The call returned successfully. + +**/ +EFI_STATUS +EFIAPI +SmmBase2InSmram ( + IN CONST EFI_SMM_BASE2_PROTOCOL *This, + OUT BOOLEAN *InSmram + ) +{ + if (InSmram == NULL) { + return EFI_INVALID_PARAMETER; + } + + *InSmram = gSmmCorePrivate->InSmm; + + return EFI_SUCCESS; +} + +/** + Retrieves the location of the System Management System Table (SMST). + + @param This The EFI_SMM_BASE2_PROTOCOL instance. + @param Smst On return, points to a pointer to the System Management Service Table (SMST). + + @retval EFI_INVALID_PARAMETER Smst or This was invalid. + @retval EFI_SUCCESS The memory was returned to the system. + @retval EFI_UNSUPPORTED Not in SMM. + +**/ +EFI_STATUS +EFIAPI +SmmBase2GetSmstLocation ( + IN CONST EFI_SMM_BASE2_PROTOCOL *This, + OUT EFI_SMM_SYSTEM_TABLE2 **Smst + ) +{ + if ((This == NULL) || (Smst == NULL)) { + return EFI_INVALID_PARAMETER; + } + + if (!gSmmCorePrivate->InSmm) { + return EFI_UNSUPPORTED; + } + + *Smst = gSmmCorePrivate->Smst; + + return EFI_SUCCESS; +} + +/** + Communicates with a registered handler. + + This function provides a service to send and receive messages from a registered + UEFI service. This function is part of the SMM Communication Protocol that may + be called in physical mode prior to SetVirtualAddressMap() and in virtual mode + after SetVirtualAddressMap(). + + @param[in] This The EFI_SMM_COMMUNICATION_PROTOCOL instance. + @param[in, out] CommBuffer A pointer to the buffer to convey into SMRAM. + @param[in, out] CommSize The size of the data buffer being passed in. On exit, the size of data + being returned. Zero if the handler does not wish to reply with any data. + This parameter is optional and may be NULL. + + @retval EFI_SUCCESS The message was successfully posted. + @retval EFI_INVALID_PARAMETER The CommBuffer was NULL. + @retval EFI_BAD_BUFFER_SIZE The buffer is too large for the MM implementation. + If this error is returned, the MessageLength field + in the CommBuffer header or the integer pointed by + CommSize, are updated to reflect the maximum payload + size the implementation can accommodate. + @retval EFI_ACCESS_DENIED The CommunicateBuffer parameter or CommSize parameter, + if not omitted, are in address range that cannot be + accessed by the MM environment. + +**/ +EFI_STATUS +EFIAPI +SmmCommunicationCommunicate ( + IN CONST EFI_SMM_COMMUNICATION_PROTOCOL *This, + IN OUT VOID *CommBuffer, + IN OUT UINTN *CommSize OPTIONAL + ) +{ + EFI_STATUS Status; + EFI_SMM_COMMUNICATE_HEADER *CommunicateHeader; + BOOLEAN OldInSmm; + UINTN TempCommSize; + + // + // Check parameters + // + if (CommBuffer == NULL) { + return EFI_INVALID_PARAMETER; + } + + CommunicateHeader = (EFI_SMM_COMMUNICATE_HEADER *)CommBuffer; + + if (CommSize == NULL) { + TempCommSize = OFFSET_OF (EFI_SMM_COMMUNICATE_HEADER, Data) + CommunicateHeader->MessageLength; + } else { + TempCommSize = *CommSize; + // + // CommSize must hold HeaderGuid and MessageLength + // + if (TempCommSize < OFFSET_OF (EFI_SMM_COMMUNICATE_HEADER, Data)) { + return EFI_INVALID_PARAMETER; + } + } + + // + // If not already in SMM, then generate a Software SMI + // + if (!gSmmCorePrivate->InSmm && gSmmCorePrivate->SmmEntryPointRegistered) { + // + // Put arguments for Software SMI in gSmmCorePrivate + // + gSmmCorePrivate->CommunicationBuffer = CommBuffer; + gSmmCorePrivate->BufferSize = TempCommSize; + + // + // Generate Software SMI + // + Status = mSmmControl2->Trigger (mSmmControl2, NULL, NULL, FALSE, 0); + if (EFI_ERROR (Status)) { + return EFI_UNSUPPORTED; + } + + // + // Return status from software SMI + // + if (CommSize != NULL) { + *CommSize = gSmmCorePrivate->BufferSize; + } + + return gSmmCorePrivate->ReturnStatus; + } + + // + // If we are in SMM, then the execution mode must be physical, which means that + // OS established virtual addresses can not be used. If SetVirtualAddressMap() + // has been called, then a direct invocation of the Software SMI is not allowed, + // so return EFI_INVALID_PARAMETER. + // + if (EfiGoneVirtual ()) { + return EFI_INVALID_PARAMETER; + } + + // + // If we are not in SMM, don't allow call SmiManage() directly when SMRAM is closed or locked. + // + if ((!gSmmCorePrivate->InSmm) && (!mSmmAccess->OpenState || mSmmAccess->LockState)) { + return EFI_INVALID_PARAMETER; + } + + // + // Save current InSmm state and set InSmm state to TRUE + // + OldInSmm = gSmmCorePrivate->InSmm; + gSmmCorePrivate->InSmm = TRUE; + + // + // Before SetVirtualAddressMap(), we are in SMM or SMRAM is open and unlocked, call SmiManage() directly. + // + TempCommSize -= OFFSET_OF (EFI_SMM_COMMUNICATE_HEADER, Data); + Status = gSmmCorePrivate->Smst->SmiManage ( + &CommunicateHeader->HeaderGuid, + NULL, + CommunicateHeader->Data, + &TempCommSize + ); + TempCommSize += OFFSET_OF (EFI_SMM_COMMUNICATE_HEADER, Data); + if (CommSize != NULL) { + *CommSize = TempCommSize; + } + + // + // Restore original InSmm state + // + gSmmCorePrivate->InSmm = OldInSmm; + + return (Status == EFI_SUCCESS) ? EFI_SUCCESS : EFI_NOT_FOUND; +} + +/** + Communicates with a registered handler. + + This function provides a service to send and receive messages from a registered UEFI service. + + @param[in] This The EFI_MM_COMMUNICATION_PROTOCOL instance. + @param[in] CommBufferPhysical Physical address of the MM communication buffer + @param[in] CommBufferVirtual Virtual address of the MM communication buffer + @param[in] CommSize The size of the data buffer being passed in. On exit, the size of data + being returned. Zero if the handler does not wish to reply with any data. + This parameter is optional and may be NULL. + + @retval EFI_SUCCESS The message was successfully posted. + @retval EFI_INVALID_PARAMETER The CommBuffer was NULL. + @retval EFI_BAD_BUFFER_SIZE The buffer is too large for the MM implementation. + If this error is returned, the MessageLength field + in the CommBuffer header or the integer pointed by + CommSize, are updated to reflect the maximum payload + size the implementation can accommodate. + @retval EFI_ACCESS_DENIED The CommunicateBuffer parameter or CommSize parameter, + if not omitted, are in address range that cannot be + accessed by the MM environment. + +**/ +EFI_STATUS +EFIAPI +SmmCommunicationMmCommunicate2 ( + IN CONST EFI_MM_COMMUNICATION2_PROTOCOL *This, + IN OUT VOID *CommBufferPhysical, + IN OUT VOID *CommBufferVirtual, + IN OUT UINTN *CommSize OPTIONAL + ) +{ + return SmmCommunicationCommunicate ( + &mSmmCommunication, + CommBufferPhysical, + CommSize + ); +} + +/** + Event notification that is fired when GUIDed Event Group is signaled. + + @param Event The Event that is being processed, not used. + @param Context Event Context, not used. + +**/ +VOID +EFIAPI +SmmIplGuidedEventNotify ( + IN EFI_EVENT Event, + IN VOID *Context + ) +{ + UINTN Size; + + // + // Use Guid to initialize EFI_SMM_COMMUNICATE_HEADER structure + // + CopyGuid (&mCommunicateHeader.HeaderGuid, (EFI_GUID *)Context); + mCommunicateHeader.MessageLength = 1; + mCommunicateHeader.Data[0] = 0; + + // + // Generate the Software SMI and return the result + // + Size = sizeof (mCommunicateHeader); + SmmCommunicationCommunicate (&mSmmCommunication, &mCommunicateHeader, &Size); +} + +/** + Event notification that is fired when EndOfDxe Event Group is signaled. + + @param Event The Event that is being processed, not used. + @param Context Event Context, not used. + +**/ +VOID +EFIAPI +SmmIplEndOfDxeEventNotify ( + IN EFI_EVENT Event, + IN VOID *Context + ) +{ + mEndOfDxe = TRUE; +} + +/** + Event notification that is fired when DxeDispatch Event Group is signaled. + + @param Event The Event that is being processed, not used. + @param Context Event Context, not used. + +**/ +VOID +EFIAPI +SmmIplDxeDispatchEventNotify ( + IN EFI_EVENT Event, + IN VOID *Context + ) +{ + UINTN Size; + EFI_STATUS Status; + + // + // Keep calling the SMM Core Dispatcher until there is no request to restart it. + // + while (TRUE) { + // + // Use Guid to initialize EFI_SMM_COMMUNICATE_HEADER structure + // Clear the buffer passed into the Software SMI. This buffer will return + // the status of the SMM Core Dispatcher. + // + CopyGuid (&mCommunicateHeader.HeaderGuid, (EFI_GUID *)Context); + mCommunicateHeader.MessageLength = 1; + mCommunicateHeader.Data[0] = 0; + + // + // Generate the Software SMI and return the result + // + Size = sizeof (mCommunicateHeader); + SmmCommunicationCommunicate (&mSmmCommunication, &mCommunicateHeader, &Size); + + // + // Return if there is no request to restart the SMM Core Dispatcher + // + if (mCommunicateHeader.Data[0] != COMM_BUFFER_SMM_DISPATCH_RESTART) { + return; + } + + // + // Close all SMRAM ranges to protect SMRAM + // NOTE: SMRR is enabled by CPU SMM driver by calling SmmCpuFeaturesInitializeProcessor() from SmmCpuFeaturesLib + // so no need to reset the SMRAM to UC in MTRR. + // + Status = mSmmAccess->Close (mSmmAccess); + ASSERT_EFI_ERROR (Status); + + // + // Print debug message that the SMRAM window is now closed. + // + DEBUG ((DEBUG_INFO, "SMM IPL closed SMRAM window\n")); + } +} + +/** + Event notification that is fired every time a gEfiSmmConfigurationProtocol installs. + + @param Event The Event that is being processed, not used. + @param Context Event Context, not used. + +**/ +VOID +EFIAPI +SmmIplSmmConfigurationEventNotify ( + IN EFI_EVENT Event, + IN VOID *Context + ) +{ + EFI_STATUS Status; + EFI_SMM_CONFIGURATION_PROTOCOL *SmmConfiguration; + + // + // Make sure this notification is for this handler + // + Status = gBS->LocateProtocol (Context, NULL, (VOID **)&SmmConfiguration); + if (EFI_ERROR (Status)) { + return; + } + + // + // Register the SMM Entry Point provided by the SMM Core with the SMM Configuration protocol + // + Status = SmmConfiguration->RegisterSmmEntry (SmmConfiguration, gSmmCorePrivate->SmmEntryPoint); + ASSERT_EFI_ERROR (Status); + + // + // Set flag to indicate that the SMM Entry Point has been registered which + // means that SMIs are now fully operational. + // + gSmmCorePrivate->SmmEntryPointRegistered = TRUE; + + // + // Print debug message showing SMM Core entry point address. + // + DEBUG ((DEBUG_INFO, "SMM IPL registered SMM Entry Point address %p\n", (VOID *)(UINTN)gSmmCorePrivate->SmmEntryPoint)); +} + +/** + Event notification that is fired every time a DxeSmmReadyToLock protocol is added + or if gEfiEventReadyToBootGuid is signaled. + + @param Event The Event that is being processed, not used. + @param Context Event Context, not used. + +**/ +VOID +EFIAPI +SmmIplReadyToLockEventNotify ( + IN EFI_EVENT Event, + IN VOID *Context + ) +{ + EFI_STATUS Status; + VOID *Interface; + UINTN Index; + + // + // See if we are already locked + // + if (mSmmLocked) { + return; + } + + // + // Make sure this notification is for this handler + // + if (CompareGuid ((EFI_GUID *)Context, &gEfiDxeSmmReadyToLockProtocolGuid)) { + Status = gBS->LocateProtocol (&gEfiDxeSmmReadyToLockProtocolGuid, NULL, &Interface); + if (EFI_ERROR (Status)) { + return; + } + } else { + // + // If SMM is not locked yet and we got here from gEfiEventReadyToBootGuid being + // signaled, then gEfiDxeSmmReadyToLockProtocolGuid was not installed as expected. + // Print a warning on debug builds. + // + DEBUG ((DEBUG_WARN, "SMM IPL! DXE SMM Ready To Lock Protocol not installed before Ready To Boot signal\n")); + } + + if (!mEndOfDxe) { + DEBUG ((DEBUG_ERROR, "EndOfDxe Event must be signaled before DxeSmmReadyToLock Protocol installation!\n")); + REPORT_STATUS_CODE ( + EFI_ERROR_CODE | EFI_ERROR_UNRECOVERED, + (EFI_SOFTWARE_SMM_DRIVER | EFI_SW_EC_ILLEGAL_SOFTWARE_STATE) + ); + ASSERT (FALSE); + } + + // + // Lock the SMRAM (Note: Locking SMRAM may not be supported on all platforms) + // + mSmmAccess->Lock (mSmmAccess); + + // + // Close protocol and event notification events that do not apply after the + // DXE SMM Ready To Lock Protocol has been installed or the Ready To Boot + // event has been signalled. + // + for (Index = 0; mSmmIplEvents[Index].NotifyFunction != NULL; Index++) { + if (mSmmIplEvents[Index].CloseOnLock) { + gBS->CloseEvent (mSmmIplEvents[Index].Event); + } + } + + // + // Inform SMM Core that the DxeSmmReadyToLock protocol was installed + // + SmmIplGuidedEventNotify (Event, (VOID *)&gEfiDxeSmmReadyToLockProtocolGuid); + + // + // Print debug message that the SMRAM window is now locked. + // + DEBUG ((DEBUG_INFO, "SMM IPL locked SMRAM window\n")); + + // + // Set flag so this operation will not be performed again + // + mSmmLocked = TRUE; +} + +/** + Notification function of EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE. + + This is a notification function registered on EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE event. + It convers pointer to new virtual address. + + @param Event Event whose notification function is being invoked. + @param Context Pointer to the notification function's context. + +**/ +VOID +EFIAPI +SmmIplSetVirtualAddressNotify ( + IN EFI_EVENT Event, + IN VOID *Context + ) +{ + EfiConvertPointer (0x0, (VOID **)&mSmmControl2); +} + +/** + Get the fixed loading address from image header assigned by build tool. This function only be called + when Loading module at Fixed address feature enabled. + + @param ImageContext Pointer to the image context structure that describes the PE/COFF + image that needs to be examined by this function. + @retval EFI_SUCCESS An fixed loading address is assigned to this image by build tools . + @retval EFI_NOT_FOUND The image has no assigned fixed loading address. +**/ +EFI_STATUS +GetPeCoffImageFixLoadingAssignedAddress ( + IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext + ) +{ + UINTN SectionHeaderOffset; + EFI_STATUS Status; + EFI_IMAGE_SECTION_HEADER SectionHeader; + EFI_IMAGE_OPTIONAL_HEADER_UNION *ImgHdr; + EFI_PHYSICAL_ADDRESS FixLoadingAddress; + UINT16 Index; + UINTN Size; + UINT16 NumberOfSections; + EFI_PHYSICAL_ADDRESS SmramBase; + UINT64 SmmCodeSize; + UINT64 ValueInSectionHeader; + + // + // Build tool will calculate the smm code size and then patch the PcdLoadFixAddressSmmCodePageNumber + // + SmmCodeSize = EFI_PAGES_TO_SIZE (PcdGet32 (PcdLoadFixAddressSmmCodePageNumber)); + + FixLoadingAddress = 0; + Status = EFI_NOT_FOUND; + SmramBase = mLMFAConfigurationTable->SmramBase; + // + // 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 saves the offset to SMRAM base as image base in PointerToRelocations & PointerToLineNumbers fields in the + // first section header that doesn't point to code section in image header. And there is an assumption that when the + // feature is enabled, if a module is assigned a loading address by tools, PointerToRelocations & PointerToLineNumbers + // fields should NOT be Zero, or else, these 2 fields should be set to Zero + // + ValueInSectionHeader = ReadUnaligned64 ((UINT64 *)&SectionHeader.PointerToRelocations); + if (ValueInSectionHeader != 0) { + // + // 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)(SmramBase + (INT64)ValueInSectionHeader); + + if ((SmramBase + SmmCodeSize > FixLoadingAddress) && (SmramBase <= FixLoadingAddress)) { + // + // The assigned address is valid. Return the specified loading address + // + ImageContext->ImageAddress = FixLoadingAddress; + Status = EFI_SUCCESS; + } + } + + 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; +} + +/** + Load the SMM Core image into SMRAM and executes the SMM Core from SMRAM. + + @param[in, out] SmramRange Descriptor for the range of SMRAM to reload the + currently executing image, the rang of SMRAM to + hold SMM Core will be excluded. + @param[in, out] SmramRangeSmmCore Descriptor for the range of SMRAM to hold SMM Core. + + @param[in] Context Context to pass into SMM Core + + @return EFI_STATUS + +**/ +EFI_STATUS +ExecuteSmmCoreFromSmram ( + IN OUT EFI_SMRAM_DESCRIPTOR *SmramRange, + IN OUT EFI_SMRAM_DESCRIPTOR *SmramRangeSmmCore, + IN VOID *Context + ) +{ + EFI_STATUS Status; + VOID *SourceBuffer; + UINTN SourceSize; + PE_COFF_LOADER_IMAGE_CONTEXT ImageContext; + UINTN PageCount; + EFI_IMAGE_ENTRY_POINT EntryPoint; + + // + // Search all Firmware Volumes for a PE/COFF image in a file of type SMM_CORE + // + Status = GetSectionFromAnyFvByFileType ( + EFI_FV_FILETYPE_SMM_CORE, + 0, + EFI_SECTION_PE32, + 0, + &SourceBuffer, + &SourceSize + ); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Initialize ImageContext + // + ImageContext.Handle = SourceBuffer; + ImageContext.ImageRead = PeCoffLoaderImageReadFromMemory; + + // + // Get information about the image being loaded + // + Status = PeCoffLoaderGetImageInfo (&ImageContext); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // if Loading module at Fixed Address feature is enabled, the SMM core driver will be loaded to + // the address assigned by build tool. + // + if (PcdGet64 (PcdLoadModuleAtFixAddressEnable) != 0) { + // + // Get the fixed loading address assigned by Build tool + // + Status = GetPeCoffImageFixLoadingAssignedAddress (&ImageContext); + if (!EFI_ERROR (Status)) { + // + // Since the memory range to load SMM CORE will be cut out in SMM core, so no need to allocate and free this range + // + PageCount = 0; + // + // Reserved Smram Region for SmmCore is not used, and remove it from SmramRangeCount. + // + gSmmCorePrivate->SmramRangeCount--; + } else { + DEBUG ((DEBUG_INFO, "LOADING MODULE FIXED ERROR: Loading module at fixed address at address failed\n")); + // + // Allocate memory for the image being loaded from the EFI_SRAM_DESCRIPTOR + // specified by SmramRange + // + PageCount = (UINTN)EFI_SIZE_TO_PAGES ((UINTN)ImageContext.ImageSize + ImageContext.SectionAlignment); + + ASSERT ((SmramRange->PhysicalSize & EFI_PAGE_MASK) == 0); + ASSERT (SmramRange->PhysicalSize > EFI_PAGES_TO_SIZE (PageCount)); + + SmramRange->PhysicalSize -= EFI_PAGES_TO_SIZE (PageCount); + SmramRangeSmmCore->CpuStart = SmramRange->CpuStart + SmramRange->PhysicalSize; + SmramRangeSmmCore->PhysicalStart = SmramRange->PhysicalStart + SmramRange->PhysicalSize; + SmramRangeSmmCore->RegionState = SmramRange->RegionState | EFI_ALLOCATED; + SmramRangeSmmCore->PhysicalSize = EFI_PAGES_TO_SIZE (PageCount); + + // + // Align buffer on section boundary + // + ImageContext.ImageAddress = SmramRangeSmmCore->CpuStart; + } + } else { + // + // Allocate memory for the image being loaded from the EFI_SRAM_DESCRIPTOR + // specified by SmramRange + // + PageCount = (UINTN)EFI_SIZE_TO_PAGES ((UINTN)ImageContext.ImageSize + ImageContext.SectionAlignment); + + ASSERT ((SmramRange->PhysicalSize & EFI_PAGE_MASK) == 0); + ASSERT (SmramRange->PhysicalSize > EFI_PAGES_TO_SIZE (PageCount)); + + SmramRange->PhysicalSize -= EFI_PAGES_TO_SIZE (PageCount); + SmramRangeSmmCore->CpuStart = SmramRange->CpuStart + SmramRange->PhysicalSize; + SmramRangeSmmCore->PhysicalStart = SmramRange->PhysicalStart + SmramRange->PhysicalSize; + SmramRangeSmmCore->RegionState = SmramRange->RegionState | EFI_ALLOCATED; + SmramRangeSmmCore->PhysicalSize = EFI_PAGES_TO_SIZE (PageCount); + + // + // Align buffer on section boundary + // + ImageContext.ImageAddress = SmramRangeSmmCore->CpuStart; + } + + ImageContext.ImageAddress += ImageContext.SectionAlignment - 1; + ImageContext.ImageAddress &= ~((EFI_PHYSICAL_ADDRESS)ImageContext.SectionAlignment - 1); + + // + // Print debug message showing SMM Core load address. + // + DEBUG ((DEBUG_INFO, "SMM IPL loading SMM Core at SMRAM address %p\n", (VOID *)(UINTN)ImageContext.ImageAddress)); + + // + // Load the image to our new buffer + // + Status = PeCoffLoaderLoadImage (&ImageContext); + if (!EFI_ERROR (Status)) { + // + // Relocate the image in our new buffer + // + Status = PeCoffLoaderRelocateImage (&ImageContext); + if (!EFI_ERROR (Status)) { + // + // Flush the instruction cache so the image data are written before we execute it + // + InvalidateInstructionCacheRange ((VOID *)(UINTN)ImageContext.ImageAddress, (UINTN)ImageContext.ImageSize); + + // + // Print debug message showing SMM Core entry point address. + // + DEBUG ((DEBUG_INFO, "SMM IPL calling SMM Core at SMRAM address %p\n", (VOID *)(UINTN)ImageContext.EntryPoint)); + + gSmmCorePrivate->PiSmmCoreImageBase = ImageContext.ImageAddress; + gSmmCorePrivate->PiSmmCoreImageSize = ImageContext.ImageSize; + DEBUG ((DEBUG_INFO, "PiSmmCoreImageBase - 0x%016lx\n", gSmmCorePrivate->PiSmmCoreImageBase)); + DEBUG ((DEBUG_INFO, "PiSmmCoreImageSize - 0x%016lx\n", gSmmCorePrivate->PiSmmCoreImageSize)); + + gSmmCorePrivate->PiSmmCoreEntryPoint = ImageContext.EntryPoint; + + // + // Execute image + // + EntryPoint = (EFI_IMAGE_ENTRY_POINT)(UINTN)ImageContext.EntryPoint; + Status = EntryPoint ((EFI_HANDLE)Context, gST); + } + } + + // + // Always free memory allocated by GetFileBufferByFilePath () + // + FreePool (SourceBuffer); + + return Status; +} + +/** + SMM split SMRAM entry. + + @param[in, out] RangeToCompare Pointer to EFI_SMRAM_DESCRIPTOR to compare. + @param[in, out] ReservedRangeToCompare Pointer to EFI_SMM_RESERVED_SMRAM_REGION to compare. + @param[out] Ranges Output pointer to hold split EFI_SMRAM_DESCRIPTOR entry. + @param[in, out] RangeCount Pointer to range count. + @param[out] ReservedRanges Output pointer to hold split EFI_SMM_RESERVED_SMRAM_REGION entry. + @param[in, out] ReservedRangeCount Pointer to reserved range count. + @param[out] FinalRanges Output pointer to hold split final EFI_SMRAM_DESCRIPTOR entry + that no need to be split anymore. + @param[in, out] FinalRangeCount Pointer to final range count. + +**/ +VOID +SmmSplitSmramEntry ( + IN OUT EFI_SMRAM_DESCRIPTOR *RangeToCompare, + IN OUT EFI_SMM_RESERVED_SMRAM_REGION *ReservedRangeToCompare, + OUT EFI_SMRAM_DESCRIPTOR *Ranges, + IN OUT UINTN *RangeCount, + OUT EFI_SMM_RESERVED_SMRAM_REGION *ReservedRanges, + IN OUT UINTN *ReservedRangeCount, + OUT EFI_SMRAM_DESCRIPTOR *FinalRanges, + IN OUT UINTN *FinalRangeCount + ) +{ + UINT64 RangeToCompareEnd; + UINT64 ReservedRangeToCompareEnd; + + RangeToCompareEnd = RangeToCompare->CpuStart + RangeToCompare->PhysicalSize; + ReservedRangeToCompareEnd = ReservedRangeToCompare->SmramReservedStart + ReservedRangeToCompare->SmramReservedSize; + + if ((RangeToCompare->CpuStart >= ReservedRangeToCompare->SmramReservedStart) && + (RangeToCompare->CpuStart < ReservedRangeToCompareEnd)) + { + if (RangeToCompareEnd < ReservedRangeToCompareEnd) { + // + // RangeToCompare ReservedRangeToCompare + // ---- ---- -------------------------------------- + // | | | | -> 1. ReservedRangeToCompare + // ---- | | |--| -------------------------------------- + // | | | | | | + // | | | | | | -> 2. FinalRanges[*FinalRangeCount] and increment *FinalRangeCount + // | | | | | | RangeToCompare->PhysicalSize = 0 + // ---- | | |--| -------------------------------------- + // | | | | -> 3. ReservedRanges[*ReservedRangeCount] and increment *ReservedRangeCount + // ---- ---- -------------------------------------- + // + + // + // 1. Update ReservedRangeToCompare. + // + ReservedRangeToCompare->SmramReservedSize = RangeToCompare->CpuStart - ReservedRangeToCompare->SmramReservedStart; + // + // 2. Update FinalRanges[FinalRangeCount] and increment *FinalRangeCount. + // Zero RangeToCompare->PhysicalSize. + // + FinalRanges[*FinalRangeCount].CpuStart = RangeToCompare->CpuStart; + FinalRanges[*FinalRangeCount].PhysicalStart = RangeToCompare->PhysicalStart; + FinalRanges[*FinalRangeCount].RegionState = RangeToCompare->RegionState | EFI_ALLOCATED; + FinalRanges[*FinalRangeCount].PhysicalSize = RangeToCompare->PhysicalSize; + *FinalRangeCount += 1; + RangeToCompare->PhysicalSize = 0; + // + // 3. Update ReservedRanges[*ReservedRangeCount] and increment *ReservedRangeCount. + // + ReservedRanges[*ReservedRangeCount].SmramReservedStart = FinalRanges[*FinalRangeCount - 1].CpuStart + FinalRanges[*FinalRangeCount - 1].PhysicalSize; + ReservedRanges[*ReservedRangeCount].SmramReservedSize = ReservedRangeToCompareEnd - RangeToCompareEnd; + *ReservedRangeCount += 1; + } else { + // + // RangeToCompare ReservedRangeToCompare + // ---- ---- -------------------------------------- + // | | | | -> 1. ReservedRangeToCompare + // ---- | | |--| -------------------------------------- + // | | | | | | + // | | | | | | -> 2. FinalRanges[*FinalRangeCount] and increment *FinalRangeCount + // | | | | | | + // | | ---- |--| -------------------------------------- + // | | | | -> 3. RangeToCompare + // ---- ---- -------------------------------------- + // + + // + // 1. Update ReservedRangeToCompare. + // + ReservedRangeToCompare->SmramReservedSize = RangeToCompare->CpuStart - ReservedRangeToCompare->SmramReservedStart; + // + // 2. Update FinalRanges[FinalRangeCount] and increment *FinalRangeCount. + // + FinalRanges[*FinalRangeCount].CpuStart = RangeToCompare->CpuStart; + FinalRanges[*FinalRangeCount].PhysicalStart = RangeToCompare->PhysicalStart; + FinalRanges[*FinalRangeCount].RegionState = RangeToCompare->RegionState | EFI_ALLOCATED; + FinalRanges[*FinalRangeCount].PhysicalSize = ReservedRangeToCompareEnd - RangeToCompare->CpuStart; + *FinalRangeCount += 1; + // + // 3. Update RangeToCompare. + // + RangeToCompare->CpuStart += FinalRanges[*FinalRangeCount - 1].PhysicalSize; + RangeToCompare->PhysicalStart += FinalRanges[*FinalRangeCount - 1].PhysicalSize; + RangeToCompare->PhysicalSize -= FinalRanges[*FinalRangeCount - 1].PhysicalSize; + } + } else if ((ReservedRangeToCompare->SmramReservedStart >= RangeToCompare->CpuStart) && + (ReservedRangeToCompare->SmramReservedStart < RangeToCompareEnd)) + { + if (ReservedRangeToCompareEnd < RangeToCompareEnd) { + // + // RangeToCompare ReservedRangeToCompare + // ---- ---- -------------------------------------- + // | | | | -> 1. RangeToCompare + // | | ---- |--| -------------------------------------- + // | | | | | | + // | | | | | | -> 2. FinalRanges[*FinalRangeCount] and increment *FinalRangeCount + // | | | | | | ReservedRangeToCompare->SmramReservedSize = 0 + // | | ---- |--| -------------------------------------- + // | | | | -> 3. Ranges[*RangeCount] and increment *RangeCount + // ---- ---- -------------------------------------- + // + + // + // 1. Update RangeToCompare. + // + RangeToCompare->PhysicalSize = ReservedRangeToCompare->SmramReservedStart - RangeToCompare->CpuStart; + // + // 2. Update FinalRanges[FinalRangeCount] and increment *FinalRangeCount. + // ReservedRangeToCompare->SmramReservedSize = 0 + // + FinalRanges[*FinalRangeCount].CpuStart = ReservedRangeToCompare->SmramReservedStart; + FinalRanges[*FinalRangeCount].PhysicalStart = RangeToCompare->PhysicalStart + RangeToCompare->PhysicalSize; + FinalRanges[*FinalRangeCount].RegionState = RangeToCompare->RegionState | EFI_ALLOCATED; + FinalRanges[*FinalRangeCount].PhysicalSize = ReservedRangeToCompare->SmramReservedSize; + *FinalRangeCount += 1; + ReservedRangeToCompare->SmramReservedSize = 0; + // + // 3. Update Ranges[*RangeCount] and increment *RangeCount. + // + Ranges[*RangeCount].CpuStart = FinalRanges[*FinalRangeCount - 1].CpuStart + FinalRanges[*FinalRangeCount - 1].PhysicalSize; + Ranges[*RangeCount].PhysicalStart = FinalRanges[*FinalRangeCount - 1].PhysicalStart + FinalRanges[*FinalRangeCount - 1].PhysicalSize; + Ranges[*RangeCount].RegionState = RangeToCompare->RegionState; + Ranges[*RangeCount].PhysicalSize = RangeToCompareEnd - ReservedRangeToCompareEnd; + *RangeCount += 1; + } else { + // + // RangeToCompare ReservedRangeToCompare + // ---- ---- -------------------------------------- + // | | | | -> 1. RangeToCompare + // | | ---- |--| -------------------------------------- + // | | | | | | + // | | | | | | -> 2. FinalRanges[*FinalRangeCount] and increment *FinalRangeCount + // | | | | | | + // ---- | | |--| -------------------------------------- + // | | | | -> 3. ReservedRangeToCompare + // ---- ---- -------------------------------------- + // + + // + // 1. Update RangeToCompare. + // + RangeToCompare->PhysicalSize = ReservedRangeToCompare->SmramReservedStart - RangeToCompare->CpuStart; + // + // 2. Update FinalRanges[FinalRangeCount] and increment *FinalRangeCount. + // ReservedRangeToCompare->SmramReservedSize = 0 + // + FinalRanges[*FinalRangeCount].CpuStart = ReservedRangeToCompare->SmramReservedStart; + FinalRanges[*FinalRangeCount].PhysicalStart = RangeToCompare->PhysicalStart + RangeToCompare->PhysicalSize; + FinalRanges[*FinalRangeCount].RegionState = RangeToCompare->RegionState | EFI_ALLOCATED; + FinalRanges[*FinalRangeCount].PhysicalSize = RangeToCompareEnd - ReservedRangeToCompare->SmramReservedStart; + *FinalRangeCount += 1; + // + // 3. Update ReservedRangeToCompare. + // + ReservedRangeToCompare->SmramReservedStart += FinalRanges[*FinalRangeCount - 1].PhysicalSize; + ReservedRangeToCompare->SmramReservedSize -= FinalRanges[*FinalRangeCount - 1].PhysicalSize; + } + } +} + +/** + Returns if SMRAM range and SMRAM reserved range are overlapped. + + @param[in] RangeToCompare Pointer to EFI_SMRAM_DESCRIPTOR to compare. + @param[in] ReservedRangeToCompare Pointer to EFI_SMM_RESERVED_SMRAM_REGION to compare. + + @retval TRUE There is overlap. + @retval TRUE Math error. + @retval FALSE There is no overlap. + +**/ +BOOLEAN +SmmIsSmramOverlap ( + IN EFI_SMRAM_DESCRIPTOR *RangeToCompare, + IN EFI_SMM_RESERVED_SMRAM_REGION *ReservedRangeToCompare + ) +{ + UINT64 RangeToCompareEnd; + UINT64 ReservedRangeToCompareEnd; + BOOLEAN IsOverUnderflow1; + BOOLEAN IsOverUnderflow2; + + // Check for over or underflow. + IsOverUnderflow1 = EFI_ERROR ( + SafeUint64Add ( + (UINT64)RangeToCompare->CpuStart, + RangeToCompare->PhysicalSize, + &RangeToCompareEnd + ) + ); + IsOverUnderflow2 = EFI_ERROR ( + SafeUint64Add ( + (UINT64)ReservedRangeToCompare->SmramReservedStart, + ReservedRangeToCompare->SmramReservedSize, + &ReservedRangeToCompareEnd + ) + ); + if (IsOverUnderflow1 || IsOverUnderflow2) { + return TRUE; + } + + if ((RangeToCompare->CpuStart >= ReservedRangeToCompare->SmramReservedStart) && + (RangeToCompare->CpuStart < ReservedRangeToCompareEnd)) + { + return TRUE; + } else if ((ReservedRangeToCompare->SmramReservedStart >= RangeToCompare->CpuStart) && + (ReservedRangeToCompare->SmramReservedStart < RangeToCompareEnd)) + { + return TRUE; + } + + return FALSE; +} + +/** + Get full SMRAM ranges. + + It will get SMRAM ranges from SmmAccess protocol and SMRAM reserved ranges from + SmmConfiguration protocol, split the entries if there is overlap between them. + It will also reserve one entry for SMM core. + + @param[out] FullSmramRangeCount Output pointer to full SMRAM range count. + + @return Pointer to full SMRAM ranges. + +**/ +EFI_SMRAM_DESCRIPTOR * +GetFullSmramRanges ( + OUT UINTN *FullSmramRangeCount + ) +{ + EFI_STATUS Status; + EFI_SMM_CONFIGURATION_PROTOCOL *SmmConfiguration; + UINTN Size; + UINTN Index; + UINTN Index2; + EFI_SMRAM_DESCRIPTOR *FullSmramRanges; + UINTN TempSmramRangeCount; + UINTN AdditionSmramRangeCount; + EFI_SMRAM_DESCRIPTOR *TempSmramRanges; + UINTN SmramRangeCount; + EFI_SMRAM_DESCRIPTOR *SmramRanges; + UINTN SmramReservedCount; + EFI_SMM_RESERVED_SMRAM_REGION *SmramReservedRanges; + UINTN MaxCount; + BOOLEAN Rescan; + + // + // Get SMM Configuration Protocol if it is present. + // + SmmConfiguration = NULL; + Status = gBS->LocateProtocol (&gEfiSmmConfigurationProtocolGuid, NULL, (VOID **)&SmmConfiguration); + + // + // Get SMRAM information. + // + Size = 0; + Status = mSmmAccess->GetCapabilities (mSmmAccess, &Size, NULL); + ASSERT (Status == EFI_BUFFER_TOO_SMALL); + + SmramRangeCount = Size / sizeof (EFI_SMRAM_DESCRIPTOR); + + // + // Get SMRAM reserved region count. + // + SmramReservedCount = 0; + if (SmmConfiguration != NULL) { + while (SmmConfiguration->SmramReservedRegions[SmramReservedCount].SmramReservedSize != 0) { + SmramReservedCount++; + } + } + + // + // Reserve one entry for SMM Core in the full SMRAM ranges. + // + AdditionSmramRangeCount = 1; + if (PcdGet64 (PcdLoadModuleAtFixAddressEnable) != 0) { + // + // Reserve two entries for all SMM drivers and SMM Core in the full SMRAM ranges. + // + AdditionSmramRangeCount = 2; + } + + if (SmramReservedCount == 0) { + // + // No reserved SMRAM entry from SMM Configuration Protocol. + // + *FullSmramRangeCount = SmramRangeCount + AdditionSmramRangeCount; + Size = (*FullSmramRangeCount) * sizeof (EFI_SMRAM_DESCRIPTOR); + FullSmramRanges = (EFI_SMRAM_DESCRIPTOR *)AllocateZeroPool (Size); + ASSERT (FullSmramRanges != NULL); + + Status = mSmmAccess->GetCapabilities (mSmmAccess, &Size, FullSmramRanges); + ASSERT_EFI_ERROR (Status); + + return FullSmramRanges; + } + + // + // Why MaxCount = X + 2 * Y? + // Take Y = 1 as example below, Y > 1 case is just the iteration of Y = 1. + // + // X = 1 Y = 1 MaxCount = 3 = 1 + 2 * 1 + // ---- ---- + // | | ---- |--| + // | | | | -> | | + // | | ---- |--| + // ---- ---- + // + // X = 2 Y = 1 MaxCount = 4 = 2 + 2 * 1 + // ---- ---- + // | | | | + // | | ---- |--| + // | | | | | | + // |--| | | -> |--| + // | | | | | | + // | | ---- |--| + // | | | | + // ---- ---- + // + // X = 3 Y = 1 MaxCount = 5 = 3 + 2 * 1 + // ---- ---- + // | | | | + // | | ---- |--| + // |--| | | |--| + // | | | | -> | | + // |--| | | |--| + // | | ---- |--| + // | | | | + // ---- ---- + // + // ...... + // + MaxCount = SmramRangeCount + 2 * SmramReservedCount; + + Size = MaxCount * sizeof (EFI_SMM_RESERVED_SMRAM_REGION); + SmramReservedRanges = (EFI_SMM_RESERVED_SMRAM_REGION *)AllocatePool (Size); + ASSERT (SmramReservedRanges != NULL); + for (Index = 0; Index < SmramReservedCount; Index++) { + CopyMem (&SmramReservedRanges[Index], &SmmConfiguration->SmramReservedRegions[Index], sizeof (EFI_SMM_RESERVED_SMRAM_REGION)); + } + + Size = MaxCount * sizeof (EFI_SMRAM_DESCRIPTOR); + TempSmramRanges = (EFI_SMRAM_DESCRIPTOR *)AllocatePool (Size); + ASSERT (TempSmramRanges != NULL); + TempSmramRangeCount = 0; + + SmramRanges = (EFI_SMRAM_DESCRIPTOR *)AllocatePool (Size); + ASSERT (SmramRanges != NULL); + Status = mSmmAccess->GetCapabilities (mSmmAccess, &Size, SmramRanges); + ASSERT_EFI_ERROR (Status); + + do { + Rescan = FALSE; + for (Index = 0; (Index < SmramRangeCount) && !Rescan; Index++) { + // + // Skip zero size entry. + // + if (SmramRanges[Index].PhysicalSize != 0) { + for (Index2 = 0; (Index2 < SmramReservedCount) && !Rescan; Index2++) { + // + // Skip zero size entry. + // + if (SmramReservedRanges[Index2].SmramReservedSize != 0) { + if (SmmIsSmramOverlap ( + &SmramRanges[Index], + &SmramReservedRanges[Index2] + )) + { + // + // There is overlap, need to split entry and then rescan. + // + SmmSplitSmramEntry ( + &SmramRanges[Index], + &SmramReservedRanges[Index2], + SmramRanges, + &SmramRangeCount, + SmramReservedRanges, + &SmramReservedCount, + TempSmramRanges, + &TempSmramRangeCount + ); + Rescan = TRUE; + } + } + } + + if (!Rescan) { + // + // No any overlap, copy the entry to the temp SMRAM ranges. + // Zero SmramRanges[Index].PhysicalSize = 0; + // + CopyMem (&TempSmramRanges[TempSmramRangeCount++], &SmramRanges[Index], sizeof (EFI_SMRAM_DESCRIPTOR)); + SmramRanges[Index].PhysicalSize = 0; + } + } + } + } while (Rescan); + + ASSERT (TempSmramRangeCount <= MaxCount); + + // + // Sort the entries + // + FullSmramRanges = AllocateZeroPool ((TempSmramRangeCount + AdditionSmramRangeCount) * sizeof (EFI_SMRAM_DESCRIPTOR)); + ASSERT (FullSmramRanges != NULL); + *FullSmramRangeCount = 0; + do { + for (Index = 0; Index < TempSmramRangeCount; Index++) { + if (TempSmramRanges[Index].PhysicalSize != 0) { + break; + } + } + + ASSERT (Index < TempSmramRangeCount); + for (Index2 = 0; Index2 < TempSmramRangeCount; Index2++) { + if ((Index2 != Index) && (TempSmramRanges[Index2].PhysicalSize != 0) && (TempSmramRanges[Index2].CpuStart < TempSmramRanges[Index].CpuStart)) { + Index = Index2; + } + } + + CopyMem (&FullSmramRanges[*FullSmramRangeCount], &TempSmramRanges[Index], sizeof (EFI_SMRAM_DESCRIPTOR)); + *FullSmramRangeCount += 1; + TempSmramRanges[Index].PhysicalSize = 0; + } while (*FullSmramRangeCount < TempSmramRangeCount); + + ASSERT (*FullSmramRangeCount == TempSmramRangeCount); + *FullSmramRangeCount += AdditionSmramRangeCount; + + FreePool (SmramRanges); + FreePool (SmramReservedRanges); + FreePool (TempSmramRanges); + + return FullSmramRanges; +} + +/** + The Entry Point for SMM IPL + + Load SMM Core into SMRAM, register SMM Core entry point for SMIs, install + SMM Base 2 Protocol and SMM Communication Protocol, and register for the + critical events required to coordinate between DXE and SMM environments. + + @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 +SmmIplEntry ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + UINTN Index; + UINT64 MaxSize; + VOID *Registration; + UINT64 SmmCodeSize; + EFI_CPU_ARCH_PROTOCOL *CpuArch; + EFI_STATUS SetAttrStatus; + EFI_SMRAM_DESCRIPTOR *SmramRangeSmmDriver; + EFI_GCD_MEMORY_SPACE_DESCRIPTOR MemDesc; + + // + // Fill in the image handle of the SMM IPL so the SMM Core can use this as the + // ParentImageHandle field of the Load Image Protocol for all SMM Drivers loaded + // by the SMM Core + // + mSmmCorePrivateData.SmmIplImageHandle = ImageHandle; + + // + // Get SMM Access Protocol + // + Status = gBS->LocateProtocol (&gEfiSmmAccess2ProtocolGuid, NULL, (VOID **)&mSmmAccess); + ASSERT_EFI_ERROR (Status); + + // + // Get SMM Control2 Protocol + // + Status = gBS->LocateProtocol (&gEfiSmmControl2ProtocolGuid, NULL, (VOID **)&mSmmControl2); + ASSERT_EFI_ERROR (Status); + + gSmmCorePrivate->SmramRanges = GetFullSmramRanges (&gSmmCorePrivate->SmramRangeCount); + + // + // Open all SMRAM ranges + // + Status = mSmmAccess->Open (mSmmAccess); + ASSERT_EFI_ERROR (Status); + + // + // Print debug message that the SMRAM window is now open. + // + DEBUG ((DEBUG_INFO, "SMM IPL opened SMRAM window\n")); + + // + // Find the largest SMRAM range between 1MB and 4GB that is at least 256KB - 4K in size + // + mCurrentSmramRange = NULL; + for (Index = 0, MaxSize = SIZE_256KB - EFI_PAGE_SIZE; Index < gSmmCorePrivate->SmramRangeCount; Index++) { + // + // Skip any SMRAM region that is already allocated, needs testing, or needs ECC initialization + // + if ((gSmmCorePrivate->SmramRanges[Index].RegionState & (EFI_ALLOCATED | EFI_NEEDS_TESTING | EFI_NEEDS_ECC_INITIALIZATION)) != 0) { + continue; + } + + if (gSmmCorePrivate->SmramRanges[Index].CpuStart >= BASE_1MB) { + if ((gSmmCorePrivate->SmramRanges[Index].CpuStart + gSmmCorePrivate->SmramRanges[Index].PhysicalSize - 1) <= MAX_ADDRESS) { + if (gSmmCorePrivate->SmramRanges[Index].PhysicalSize >= MaxSize) { + MaxSize = gSmmCorePrivate->SmramRanges[Index].PhysicalSize; + mCurrentSmramRange = &gSmmCorePrivate->SmramRanges[Index]; + } + } + } + } + + if (mCurrentSmramRange != NULL) { + // + // Print debug message showing SMRAM window that will be used by SMM IPL and SMM Core + // + DEBUG (( + DEBUG_INFO, + "SMM IPL found SMRAM window %p - %p\n", + (VOID *)(UINTN)mCurrentSmramRange->CpuStart, + (VOID *)(UINTN)(mCurrentSmramRange->CpuStart + mCurrentSmramRange->PhysicalSize - 1) + )); + + GetSmramCacheRange (mCurrentSmramRange, &mSmramCacheBase, &mSmramCacheSize); + // + // Make sure we can change the desired memory attributes. + // + Status = gDS->GetMemorySpaceDescriptor ( + mSmramCacheBase, + &MemDesc + ); + ASSERT_EFI_ERROR (Status); + if ((MemDesc.Capabilities & SMRAM_CAPABILITIES) != SMRAM_CAPABILITIES) { + gDS->SetMemorySpaceCapabilities ( + mSmramCacheBase, + mSmramCacheSize, + MemDesc.Capabilities | SMRAM_CAPABILITIES + ); + } + + // + // If CPU AP is present, attempt to set SMRAM cacheability to WB and clear + // all paging attributes. + // Note that it is expected that cacheability of SMRAM has been set to WB if CPU AP + // is not available here. + // + CpuArch = NULL; + Status = gBS->LocateProtocol (&gEfiCpuArchProtocolGuid, NULL, (VOID **)&CpuArch); + if (!EFI_ERROR (Status)) { + MemDesc.Attributes &= ~(EFI_CACHE_ATTRIBUTE_MASK | EFI_MEMORY_ATTRIBUTE_MASK); + MemDesc.Attributes |= EFI_MEMORY_WB; + Status = gDS->SetMemorySpaceAttributes ( + mSmramCacheBase, + mSmramCacheSize, + MemDesc.Attributes + ); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_WARN, "SMM IPL failed to set SMRAM window to EFI_MEMORY_WB\n")); + } + + DEBUG_CODE ( + gDS->GetMemorySpaceDescriptor ( + mSmramCacheBase, + &MemDesc + ); + DEBUG ((DEBUG_INFO, "SMRAM attributes: %016lx\n", MemDesc.Attributes)); + ASSERT ((MemDesc.Attributes & EFI_MEMORY_ATTRIBUTE_MASK) == 0); + ); + } + + // + // if Loading module at Fixed Address feature is enabled, save the SMRAM base to Load + // Modules At Fixed Address Configuration Table. + // + if (PcdGet64 (PcdLoadModuleAtFixAddressEnable) != 0) { + // + // Build tool will calculate the smm code size and then patch the PcdLoadFixAddressSmmCodePageNumber + // + SmmCodeSize = LShiftU64 (PcdGet32 (PcdLoadFixAddressSmmCodePageNumber), EFI_PAGE_SHIFT); + // + // The SMRAM available memory is assumed to be larger than SmmCodeSize + // + ASSERT (mCurrentSmramRange->PhysicalSize > SmmCodeSize); + // + // Retrieve Load modules At fixed address configuration table and save the SMRAM base. + // + Status = EfiGetSystemConfigurationTable ( + &gLoadFixedAddressConfigurationTableGuid, + (VOID **)&mLMFAConfigurationTable + ); + if (!EFI_ERROR (Status) && (mLMFAConfigurationTable != NULL)) { + mLMFAConfigurationTable->SmramBase = mCurrentSmramRange->CpuStart; + // + // Print the SMRAM base + // + DEBUG ((DEBUG_INFO, "LOADING MODULE FIXED INFO: TSEG BASE is %x. \n", mLMFAConfigurationTable->SmramBase)); + } + + // + // Fill the Smram range for all SMM code + // + SmramRangeSmmDriver = &gSmmCorePrivate->SmramRanges[gSmmCorePrivate->SmramRangeCount - 2]; + SmramRangeSmmDriver->CpuStart = mCurrentSmramRange->CpuStart; + SmramRangeSmmDriver->PhysicalStart = mCurrentSmramRange->PhysicalStart; + SmramRangeSmmDriver->RegionState = mCurrentSmramRange->RegionState | EFI_ALLOCATED; + SmramRangeSmmDriver->PhysicalSize = SmmCodeSize; + + mCurrentSmramRange->PhysicalSize -= SmmCodeSize; + mCurrentSmramRange->CpuStart = mCurrentSmramRange->CpuStart + SmmCodeSize; + mCurrentSmramRange->PhysicalStart = mCurrentSmramRange->PhysicalStart + SmmCodeSize; + } + + // + // Load SMM Core into SMRAM and execute it from SMRAM + // + Status = ExecuteSmmCoreFromSmram ( + mCurrentSmramRange, + &gSmmCorePrivate->SmramRanges[gSmmCorePrivate->SmramRangeCount - 1], + gSmmCorePrivate + ); + if (EFI_ERROR (Status)) { + // + // Print error message that the SMM Core failed to be loaded and executed. + // + DEBUG ((DEBUG_ERROR, "SMM IPL could not load and execute SMM Core from SMRAM\n")); + + // + // Attempt to reset SMRAM cacheability to UC + // + if (CpuArch != NULL) { + SetAttrStatus = gDS->SetMemorySpaceAttributes ( + mSmramCacheBase, + mSmramCacheSize, + EFI_MEMORY_UC + ); + if (EFI_ERROR (SetAttrStatus)) { + DEBUG ((DEBUG_WARN, "SMM IPL failed to reset SMRAM window to EFI_MEMORY_UC\n")); + } + } + } + } else { + // + // Print error message that there are not enough SMRAM resources to load the SMM Core. + // + DEBUG ((DEBUG_ERROR, "SMM IPL could not find a large enough SMRAM region to load SMM Core\n")); + } + + // + // If the SMM Core could not be loaded then close SMRAM window, free allocated + // resources, and return an error so SMM IPL will be unloaded. + // + if ((mCurrentSmramRange == NULL) || EFI_ERROR (Status)) { + // + // Close all SMRAM ranges + // + Status = mSmmAccess->Close (mSmmAccess); + ASSERT_EFI_ERROR (Status); + + // + // Print debug message that the SMRAM window is now closed. + // + DEBUG ((DEBUG_INFO, "SMM IPL closed SMRAM window\n")); + + // + // Free all allocated resources + // + FreePool (gSmmCorePrivate->SmramRanges); + + return EFI_UNSUPPORTED; + } + + // + // Install SMM Base2 Protocol and SMM Communication Protocol + // + Status = gBS->InstallMultipleProtocolInterfaces ( + &mSmmIplHandle, + &gEfiSmmBase2ProtocolGuid, + &mSmmBase2, + &gEfiSmmCommunicationProtocolGuid, + &mSmmCommunication, + &gEfiMmCommunication2ProtocolGuid, + &mMmCommunication2, + NULL + ); + ASSERT_EFI_ERROR (Status); + + // + // Create the set of protocol and event notifications that the SMM IPL requires + // + for (Index = 0; mSmmIplEvents[Index].NotifyFunction != NULL; Index++) { + if (mSmmIplEvents[Index].Protocol) { + mSmmIplEvents[Index].Event = EfiCreateProtocolNotifyEvent ( + mSmmIplEvents[Index].Guid, + mSmmIplEvents[Index].NotifyTpl, + mSmmIplEvents[Index].NotifyFunction, + mSmmIplEvents[Index].NotifyContext, + &Registration + ); + } else { + Status = gBS->CreateEventEx ( + EVT_NOTIFY_SIGNAL, + mSmmIplEvents[Index].NotifyTpl, + mSmmIplEvents[Index].NotifyFunction, + mSmmIplEvents[Index].NotifyContext, + mSmmIplEvents[Index].Guid, + &mSmmIplEvents[Index].Event + ); + ASSERT_EFI_ERROR (Status); + } + } + + return EFI_SUCCESS; +} diff --git a/MdeModulePkg/Core/PiSmmCore/PiSmmIpl.inf b/MdeModulePkg/Core/PiSmmCore/PiSmmIpl.inf index ddeb39cee2..865e447dcd 100644 --- a/MdeModulePkg/Core/PiSmmCore/PiSmmIpl.inf +++ b/MdeModulePkg/Core/PiSmmCore/PiSmmIpl.inf @@ -1,92 +1,92 @@ -## @file
-# This module provide an SMM CIS compliant implementation of SMM IPL.
-#
-# Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.<BR>
-#
-# SPDX-License-Identifier: BSD-2-Clause-Patent
-#
-##
-
-[Defines]
- INF_VERSION = 0x00010005
- BASE_NAME = PiSmmIpl
- MODULE_UNI_FILE = PiSmmIpl.uni
- FILE_GUID = 2FA2A6DA-11D5-4dc3-999A-749648B03C56
- MODULE_TYPE = DXE_RUNTIME_DRIVER
- VERSION_STRING = 1.0
- PI_SPECIFICATION_VERSION = 0x0001000A
- ENTRY_POINT = SmmIplEntry
-
-#
-# The following information is for reference only and not required by the build tools.
-#
-# VALID_ARCHITECTURES = IA32 X64
-#
-
-[Sources]
- PiSmmIpl.c
- PiSmmCorePrivateData.h
-
-[Packages]
- MdePkg/MdePkg.dec
- MdeModulePkg/MdeModulePkg.dec
-
-[LibraryClasses]
- UefiDriverEntryPoint
- BaseLib
- BaseMemoryLib
- PeCoffLib
- CacheMaintenanceLib
- MemoryAllocationLib
- DebugLib
- UefiBootServicesTableLib
- DxeServicesTableLib
- UefiLib
- UefiRuntimeLib
- DxeServicesLib
- PcdLib
- ReportStatusCodeLib
- SafeIntLib
-
-[Protocols]
- gEfiSmmBase2ProtocolGuid ## PRODUCES
- gEfiSmmCommunicationProtocolGuid ## PRODUCES
- gEfiMmCommunication2ProtocolGuid ## PRODUCES
- gEfiSmmAccess2ProtocolGuid ## CONSUMES
- ## NOTIFY
- ## CONSUMES
- gEfiSmmConfigurationProtocolGuid
- gEfiSmmControl2ProtocolGuid ## CONSUMES
- ## NOTIFY
- ## SOMETIMES_CONSUMES
- ## UNDEFINED # Used to do smm communication
- gEfiDxeSmmReadyToLockProtocolGuid
- gEfiCpuArchProtocolGuid ## SOMETIMES_CONSUMES
-
-[Guids]
- ## CONSUMES ## Event
- ## PRODUCES ## UNDEFINED # Used to do smm communication
- gEfiEventDxeDispatchGuid
- gEfiEventReadyToBootGuid ## CONSUMES ## Event
- ## SOMETIMES_CONSUMES ## Event
- ## SOMETIMES_PRODUCES ## UNDEFINED # Used to do smm communication
- gEfiEventLegacyBootGuid
- ## SOMETIMES_CONSUMES ## Event
- ## SOMETIMES_PRODUCES ## UNDEFINED # Used to do smm communication
- gEfiEventExitBootServicesGuid
- ## SOMETIMES_CONSUMES ## Event
- ## SOMETIMES_PRODUCES ## UNDEFINED # Used to do smm communication
- gEfiEventReadyToBootGuid
- gEfiEventVirtualAddressChangeGuid ## CONSUMES ## Event
- gEfiEndOfDxeEventGroupGuid ## CONSUMES ## Event
- gLoadFixedAddressConfigurationTableGuid ## SOMETIMES_CONSUMES ## SystemTable
-
-[Pcd]
- gEfiMdeModulePkgTokenSpaceGuid.PcdLoadFixAddressSmmCodePageNumber ## SOMETIMES_CONSUMES
- gEfiMdeModulePkgTokenSpaceGuid.PcdLoadModuleAtFixAddressEnable ## CONSUMES
-
-[Depex]
- gEfiSmmAccess2ProtocolGuid AND gEfiSmmControl2ProtocolGuid
-
-[UserExtensions.TianoCore."ExtraFiles"]
- PiSmmIplExtra.uni
+## @file +# This module provide an SMM CIS compliant implementation of SMM IPL. +# +# Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.<BR> +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = PiSmmIpl + MODULE_UNI_FILE = PiSmmIpl.uni + FILE_GUID = 2FA2A6DA-11D5-4dc3-999A-749648B03C56 + MODULE_TYPE = DXE_RUNTIME_DRIVER + VERSION_STRING = 1.0 + PI_SPECIFICATION_VERSION = 0x0001000A + ENTRY_POINT = SmmIplEntry + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 +# + +[Sources] + PiSmmIpl.c + PiSmmCorePrivateData.h + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + +[LibraryClasses] + UefiDriverEntryPoint + BaseLib + BaseMemoryLib + PeCoffLib + CacheMaintenanceLib + MemoryAllocationLib + DebugLib + UefiBootServicesTableLib + DxeServicesTableLib + UefiLib + UefiRuntimeLib + DxeServicesLib + PcdLib + ReportStatusCodeLib + SafeIntLib + +[Protocols] + gEfiSmmBase2ProtocolGuid ## PRODUCES + gEfiSmmCommunicationProtocolGuid ## PRODUCES + gEfiMmCommunication2ProtocolGuid ## PRODUCES + gEfiSmmAccess2ProtocolGuid ## CONSUMES + ## NOTIFY + ## CONSUMES + gEfiSmmConfigurationProtocolGuid + gEfiSmmControl2ProtocolGuid ## CONSUMES + ## NOTIFY + ## SOMETIMES_CONSUMES + ## UNDEFINED # Used to do smm communication + gEfiDxeSmmReadyToLockProtocolGuid + gEfiCpuArchProtocolGuid ## SOMETIMES_CONSUMES + +[Guids] + ## CONSUMES ## Event + ## PRODUCES ## UNDEFINED # Used to do smm communication + gEfiEventDxeDispatchGuid + gEfiEventReadyToBootGuid ## CONSUMES ## Event + ## SOMETIMES_CONSUMES ## Event + ## SOMETIMES_PRODUCES ## UNDEFINED # Used to do smm communication + gEfiEventLegacyBootGuid + ## SOMETIMES_CONSUMES ## Event + ## SOMETIMES_PRODUCES ## UNDEFINED # Used to do smm communication + gEfiEventExitBootServicesGuid + ## SOMETIMES_CONSUMES ## Event + ## SOMETIMES_PRODUCES ## UNDEFINED # Used to do smm communication + gEfiEventReadyToBootGuid + gEfiEventVirtualAddressChangeGuid ## CONSUMES ## Event + gEfiEndOfDxeEventGroupGuid ## CONSUMES ## Event + gLoadFixedAddressConfigurationTableGuid ## SOMETIMES_CONSUMES ## SystemTable + +[Pcd] + gEfiMdeModulePkgTokenSpaceGuid.PcdLoadFixAddressSmmCodePageNumber ## SOMETIMES_CONSUMES + gEfiMdeModulePkgTokenSpaceGuid.PcdLoadModuleAtFixAddressEnable ## CONSUMES + +[Depex] + gEfiSmmAccess2ProtocolGuid AND gEfiSmmControl2ProtocolGuid + +[UserExtensions.TianoCore."ExtraFiles"] + PiSmmIplExtra.uni diff --git a/MdeModulePkg/Core/PiSmmCore/PiSmmIpl.uni b/MdeModulePkg/Core/PiSmmCore/PiSmmIpl.uni index a2796854ec..3038b71254 100644 --- a/MdeModulePkg/Core/PiSmmCore/PiSmmIpl.uni +++ b/MdeModulePkg/Core/PiSmmCore/PiSmmIpl.uni @@ -1,16 +1,16 @@ -// /** @file
-// This module provide an SMM CIS compliant implementation of SMM IPL.
-//
-// This module provide an SMM CIS compliant implementation of SMM IPL.
-//
-// Copyright (c) 2009 - 2014, Intel Corporation. All rights reserved.<BR>
-//
-// SPDX-License-Identifier: BSD-2-Clause-Patent
-//
-// **/
-
-
-#string STR_MODULE_ABSTRACT #language en-US "Provides an SMM CIS compliant implementation of SMM IPL"
-
-#string STR_MODULE_DESCRIPTION #language en-US "This module provide an SMM CIS compliant implementation of SMM IPL."
-
+// /** @file +// This module provide an SMM CIS compliant implementation of SMM IPL. +// +// This module provide an SMM CIS compliant implementation of SMM IPL. +// +// Copyright (c) 2009 - 2014, Intel Corporation. All rights reserved.<BR> +// +// SPDX-License-Identifier: BSD-2-Clause-Patent +// +// **/ + + +#string STR_MODULE_ABSTRACT #language en-US "Provides an SMM CIS compliant implementation of SMM IPL" + +#string STR_MODULE_DESCRIPTION #language en-US "This module provide an SMM CIS compliant implementation of SMM IPL." + diff --git a/MdeModulePkg/Core/PiSmmCore/PiSmmIplExtra.uni b/MdeModulePkg/Core/PiSmmCore/PiSmmIplExtra.uni index d7674de9a0..edadacaf7e 100644 --- a/MdeModulePkg/Core/PiSmmCore/PiSmmIplExtra.uni +++ b/MdeModulePkg/Core/PiSmmCore/PiSmmIplExtra.uni @@ -1,14 +1,14 @@ -// /** @file
-// PiSmmIpl Localized Strings and Content
-//
-// Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.<BR>
-//
-// SPDX-License-Identifier: BSD-2-Clause-Patent
-//
-// **/
-
-#string STR_PROPERTIES_MODULE_NAME
-#language en-US
-"Core SMM Services Initial Program Loader"
-
-
+// /** @file +// PiSmmIpl Localized Strings and Content +// +// Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.<BR> +// +// SPDX-License-Identifier: BSD-2-Clause-Patent +// +// **/ + +#string STR_PROPERTIES_MODULE_NAME +#language en-US +"Core SMM Services Initial Program Loader" + + diff --git a/MdeModulePkg/Core/PiSmmCore/Pool.c b/MdeModulePkg/Core/PiSmmCore/Pool.c index e1ff40a8ea..6d1565d430 100644 --- a/MdeModulePkg/Core/PiSmmCore/Pool.c +++ b/MdeModulePkg/Core/PiSmmCore/Pool.c @@ -1,464 +1,464 @@ -/** @file
- SMM Memory pool management functions.
-
- Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.<BR>
- SPDX-License-Identifier: BSD-2-Clause-Patent
-
-**/
-
-#include "PiSmmCore.h"
-
-LIST_ENTRY mSmmPoolLists[SmmPoolTypeMax][MAX_POOL_INDEX];
-//
-// To cache the SMRAM base since when Loading modules At fixed address feature is enabled,
-// all module is assigned an offset relative the SMRAM base in build time.
-//
-GLOBAL_REMOVE_IF_UNREFERENCED EFI_PHYSICAL_ADDRESS gLoadModuleAtFixAddressSmramBase = 0;
-
-/**
- Convert a UEFI memory type to SMM pool type.
-
- @param[in] MemoryType Type of pool to allocate.
-
- @return SMM pool type
-**/
-SMM_POOL_TYPE
-UefiMemoryTypeToSmmPoolType (
- IN EFI_MEMORY_TYPE MemoryType
- )
-{
- ASSERT ((MemoryType == EfiRuntimeServicesCode) || (MemoryType == EfiRuntimeServicesData));
- switch (MemoryType) {
- case EfiRuntimeServicesCode:
- return SmmPoolTypeCode;
- case EfiRuntimeServicesData:
- return SmmPoolTypeData;
- default:
- return SmmPoolTypeMax;
- }
-}
-
-/**
- Called to initialize the memory service.
-
- @param SmramRangeCount Number of SMRAM Regions
- @param SmramRanges Pointer to SMRAM Descriptors
-
-**/
-VOID
-SmmInitializeMemoryServices (
- IN UINTN SmramRangeCount,
- IN EFI_SMRAM_DESCRIPTOR *SmramRanges
- )
-{
- UINTN Index;
- EFI_STATUS Status;
- UINTN SmmPoolTypeIndex;
- EFI_LOAD_FIXED_ADDRESS_CONFIGURATION_TABLE *LMFAConfigurationTable;
-
- //
- // Initialize Pool list
- //
- for (SmmPoolTypeIndex = 0; SmmPoolTypeIndex < SmmPoolTypeMax; SmmPoolTypeIndex++) {
- for (Index = 0; Index < ARRAY_SIZE (mSmmPoolLists[SmmPoolTypeIndex]); Index++) {
- InitializeListHead (&mSmmPoolLists[SmmPoolTypeIndex][Index]);
- }
- }
-
- Status = EfiGetSystemConfigurationTable (
- &gLoadFixedAddressConfigurationTableGuid,
- (VOID **)&LMFAConfigurationTable
- );
- if (!EFI_ERROR (Status) && (LMFAConfigurationTable != NULL)) {
- gLoadModuleAtFixAddressSmramBase = LMFAConfigurationTable->SmramBase;
- }
-
- //
- // Add Free SMRAM regions
- // Need add Free memory at first, to let gSmmMemoryMap record data
- //
- for (Index = 0; Index < SmramRangeCount; Index++) {
- if ((SmramRanges[Index].RegionState & (EFI_ALLOCATED | EFI_NEEDS_TESTING | EFI_NEEDS_ECC_INITIALIZATION)) != 0) {
- continue;
- }
-
- SmmAddMemoryRegion (
- SmramRanges[Index].CpuStart,
- SmramRanges[Index].PhysicalSize,
- EfiConventionalMemory,
- SmramRanges[Index].RegionState
- );
- }
-
- //
- // Add the allocated SMRAM regions
- //
- for (Index = 0; Index < SmramRangeCount; Index++) {
- if ((SmramRanges[Index].RegionState & (EFI_ALLOCATED | EFI_NEEDS_TESTING | EFI_NEEDS_ECC_INITIALIZATION)) == 0) {
- continue;
- }
-
- SmmAddMemoryRegion (
- SmramRanges[Index].CpuStart,
- SmramRanges[Index].PhysicalSize,
- EfiConventionalMemory,
- SmramRanges[Index].RegionState
- );
- }
-}
-
-/**
- Internal Function. Allocate a pool by specified PoolIndex.
-
- @param PoolType Type of pool to allocate.
- @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 EFI_MEMORY_TYPE PoolType,
- IN UINTN PoolIndex,
- OUT FREE_POOL_HEADER **FreePoolHdr
- )
-{
- EFI_STATUS Status;
- FREE_POOL_HEADER *Hdr;
- POOL_TAIL *Tail;
- EFI_PHYSICAL_ADDRESS Address;
- SMM_POOL_TYPE SmmPoolType;
-
- Address = 0;
- SmmPoolType = UefiMemoryTypeToSmmPoolType (PoolType);
-
- ASSERT (PoolIndex <= MAX_POOL_INDEX);
- Status = EFI_SUCCESS;
- Hdr = NULL;
- if (PoolIndex == MAX_POOL_INDEX) {
- Status = SmmInternalAllocatePages (
- AllocateAnyPages,
- PoolType,
- EFI_SIZE_TO_PAGES (MAX_POOL_SIZE << 1),
- &Address,
- FALSE
- );
- if (EFI_ERROR (Status)) {
- return EFI_OUT_OF_RESOURCES;
- }
-
- Hdr = (FREE_POOL_HEADER *)(UINTN)Address;
- } else if (!IsListEmpty (&mSmmPoolLists[SmmPoolType][PoolIndex])) {
- Hdr = BASE_CR (GetFirstNode (&mSmmPoolLists[SmmPoolType][PoolIndex]), FREE_POOL_HEADER, Link);
- RemoveEntryList (&Hdr->Link);
- } else {
- Status = InternalAllocPoolByIndex (PoolType, PoolIndex + 1, &Hdr);
- if (!EFI_ERROR (Status)) {
- Hdr->Header.Signature = 0;
- Hdr->Header.Size >>= 1;
- Hdr->Header.Available = TRUE;
- Hdr->Header.Type = 0;
- Tail = HEAD_TO_TAIL (&Hdr->Header);
- Tail->Signature = 0;
- Tail->Size = 0;
- InsertHeadList (&mSmmPoolLists[SmmPoolType][PoolIndex], &Hdr->Link);
- Hdr = (FREE_POOL_HEADER *)((UINT8 *)Hdr + Hdr->Header.Size);
- }
- }
-
- if (!EFI_ERROR (Status)) {
- Hdr->Header.Signature = POOL_HEAD_SIGNATURE;
- Hdr->Header.Size = MIN_POOL_SIZE << PoolIndex;
- Hdr->Header.Available = FALSE;
- Hdr->Header.Type = PoolType;
- Tail = HEAD_TO_TAIL (&Hdr->Header);
- Tail->Signature = POOL_TAIL_SIGNATURE;
- Tail->Size = Hdr->Header.Size;
- }
-
- *FreePoolHdr = Hdr;
- return Status;
-}
-
-/**
- Internal Function. Free a pool by specified PoolIndex.
-
- @param FreePoolHdr The pool to free.
- @param PoolTail The pointer to the pool tail.
-
- @retval EFI_SUCCESS Pool successfully freed.
-
-**/
-EFI_STATUS
-InternalFreePoolByIndex (
- IN FREE_POOL_HEADER *FreePoolHdr,
- IN POOL_TAIL *PoolTail
- )
-{
- UINTN PoolIndex;
- SMM_POOL_TYPE SmmPoolType;
-
- ASSERT ((FreePoolHdr->Header.Size & (FreePoolHdr->Header.Size - 1)) == 0);
- ASSERT (((UINTN)FreePoolHdr & (FreePoolHdr->Header.Size - 1)) == 0);
- ASSERT (FreePoolHdr->Header.Size >= MIN_POOL_SIZE);
-
- SmmPoolType = UefiMemoryTypeToSmmPoolType (FreePoolHdr->Header.Type);
-
- PoolIndex = (UINTN)(HighBitSet32 ((UINT32)FreePoolHdr->Header.Size) - MIN_POOL_SHIFT);
- FreePoolHdr->Header.Signature = 0;
- FreePoolHdr->Header.Available = TRUE;
- FreePoolHdr->Header.Type = 0;
- PoolTail->Signature = 0;
- PoolTail->Size = 0;
- ASSERT (PoolIndex < MAX_POOL_INDEX);
- InsertHeadList (&mSmmPoolLists[SmmPoolType][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
-SmmInternalAllocatePool (
- IN EFI_MEMORY_TYPE PoolType,
- IN UINTN Size,
- OUT VOID **Buffer
- )
-{
- POOL_HEADER *PoolHdr;
- POOL_TAIL *PoolTail;
- FREE_POOL_HEADER *FreePoolHdr;
- EFI_STATUS Status;
- EFI_PHYSICAL_ADDRESS Address;
- UINTN PoolIndex;
- BOOLEAN HasPoolTail;
- BOOLEAN NeedGuard;
- UINTN NoPages;
-
- Address = 0;
-
- if ((PoolType != EfiRuntimeServicesCode) &&
- (PoolType != EfiRuntimeServicesData))
- {
- return EFI_INVALID_PARAMETER;
- }
-
- NeedGuard = IsPoolTypeToGuard (PoolType);
- HasPoolTail = !(NeedGuard &&
- ((PcdGet8 (PcdHeapGuardPropertyMask) & BIT7) == 0));
-
- //
- // Adjust the size by the pool header & tail overhead
- //
- Size += POOL_OVERHEAD;
- if ((Size > MAX_POOL_SIZE) || NeedGuard) {
- if (!HasPoolTail) {
- Size -= sizeof (POOL_TAIL);
- }
-
- NoPages = EFI_SIZE_TO_PAGES (Size);
- Status = SmmInternalAllocatePages (
- AllocateAnyPages,
- PoolType,
- NoPages,
- &Address,
- NeedGuard
- );
- if (EFI_ERROR (Status)) {
- return Status;
- }
-
- if (NeedGuard) {
- ASSERT (VerifyMemoryGuard (Address, NoPages) == TRUE);
- Address = (EFI_PHYSICAL_ADDRESS)(UINTN)AdjustPoolHeadA (
- Address,
- NoPages,
- Size
- );
- }
-
- PoolHdr = (POOL_HEADER *)(UINTN)Address;
- PoolHdr->Signature = POOL_HEAD_SIGNATURE;
- PoolHdr->Size = EFI_PAGES_TO_SIZE (NoPages);
- PoolHdr->Available = FALSE;
- PoolHdr->Type = PoolType;
-
- if (HasPoolTail) {
- PoolTail = HEAD_TO_TAIL (PoolHdr);
- PoolTail->Signature = POOL_TAIL_SIGNATURE;
- PoolTail->Size = PoolHdr->Size;
- }
-
- *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 (PoolType, 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
-SmmAllocatePool (
- IN EFI_MEMORY_TYPE PoolType,
- IN UINTN Size,
- OUT VOID **Buffer
- )
-{
- EFI_STATUS Status;
-
- Status = SmmInternalAllocatePool (PoolType, Size, Buffer);
- if (!EFI_ERROR (Status)) {
- SmmCoreUpdateProfile (
- (EFI_PHYSICAL_ADDRESS)(UINTN)RETURN_ADDRESS (0),
- MemoryProfileActionAllocatePool,
- PoolType,
- Size,
- *Buffer,
- NULL
- );
- }
-
- 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
-SmmInternalFreePool (
- IN VOID *Buffer
- )
-{
- FREE_POOL_HEADER *FreePoolHdr;
- POOL_TAIL *PoolTail;
- BOOLEAN HasPoolTail;
- BOOLEAN MemoryGuarded;
-
- if (Buffer == NULL) {
- return EFI_INVALID_PARAMETER;
- }
-
- FreePoolHdr = (FREE_POOL_HEADER *)((POOL_HEADER *)Buffer - 1);
- ASSERT (FreePoolHdr->Header.Signature == POOL_HEAD_SIGNATURE);
- ASSERT (!FreePoolHdr->Header.Available);
- if (FreePoolHdr->Header.Signature != POOL_HEAD_SIGNATURE) {
- return EFI_INVALID_PARAMETER;
- }
-
- MemoryGuarded = IsHeapGuardEnabled () &&
- IsMemoryGuarded ((EFI_PHYSICAL_ADDRESS)(UINTN)FreePoolHdr);
- HasPoolTail = !(MemoryGuarded &&
- ((PcdGet8 (PcdHeapGuardPropertyMask) & BIT7) == 0));
-
- if (HasPoolTail) {
- PoolTail = HEAD_TO_TAIL (&FreePoolHdr->Header);
- ASSERT (PoolTail->Signature == POOL_TAIL_SIGNATURE);
- ASSERT (FreePoolHdr->Header.Size == PoolTail->Size);
- if (PoolTail->Signature != POOL_TAIL_SIGNATURE) {
- return EFI_INVALID_PARAMETER;
- }
-
- if (FreePoolHdr->Header.Size != PoolTail->Size) {
- return EFI_INVALID_PARAMETER;
- }
- } else {
- PoolTail = NULL;
- }
-
- if (MemoryGuarded) {
- Buffer = AdjustPoolHeadF ((EFI_PHYSICAL_ADDRESS)(UINTN)FreePoolHdr);
- return SmmInternalFreePages (
- (EFI_PHYSICAL_ADDRESS)(UINTN)Buffer,
- EFI_SIZE_TO_PAGES (FreePoolHdr->Header.Size),
- TRUE
- );
- }
-
- if (FreePoolHdr->Header.Size > MAX_POOL_SIZE) {
- ASSERT (((UINTN)FreePoolHdr & EFI_PAGE_MASK) == 0);
- ASSERT ((FreePoolHdr->Header.Size & EFI_PAGE_MASK) == 0);
- return SmmInternalFreePages (
- (EFI_PHYSICAL_ADDRESS)(UINTN)FreePoolHdr,
- EFI_SIZE_TO_PAGES (FreePoolHdr->Header.Size),
- FALSE
- );
- }
-
- return InternalFreePoolByIndex (FreePoolHdr, PoolTail);
-}
-
-/**
- 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
-SmmFreePool (
- IN VOID *Buffer
- )
-{
- EFI_STATUS Status;
-
- Status = SmmInternalFreePool (Buffer);
- if (!EFI_ERROR (Status)) {
- SmmCoreUpdateProfile (
- (EFI_PHYSICAL_ADDRESS)(UINTN)RETURN_ADDRESS (0),
- MemoryProfileActionFreePool,
- EfiMaxMemoryType,
- 0,
- Buffer,
- NULL
- );
- }
-
- return Status;
-}
+/** @file + SMM Memory pool management functions. + + Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.<BR> + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "PiSmmCore.h" + +LIST_ENTRY mSmmPoolLists[SmmPoolTypeMax][MAX_POOL_INDEX]; +// +// To cache the SMRAM base since when Loading modules At fixed address feature is enabled, +// all module is assigned an offset relative the SMRAM base in build time. +// +GLOBAL_REMOVE_IF_UNREFERENCED EFI_PHYSICAL_ADDRESS gLoadModuleAtFixAddressSmramBase = 0; + +/** + Convert a UEFI memory type to SMM pool type. + + @param[in] MemoryType Type of pool to allocate. + + @return SMM pool type +**/ +SMM_POOL_TYPE +UefiMemoryTypeToSmmPoolType ( + IN EFI_MEMORY_TYPE MemoryType + ) +{ + ASSERT ((MemoryType == EfiRuntimeServicesCode) || (MemoryType == EfiRuntimeServicesData)); + switch (MemoryType) { + case EfiRuntimeServicesCode: + return SmmPoolTypeCode; + case EfiRuntimeServicesData: + return SmmPoolTypeData; + default: + return SmmPoolTypeMax; + } +} + +/** + Called to initialize the memory service. + + @param SmramRangeCount Number of SMRAM Regions + @param SmramRanges Pointer to SMRAM Descriptors + +**/ +VOID +SmmInitializeMemoryServices ( + IN UINTN SmramRangeCount, + IN EFI_SMRAM_DESCRIPTOR *SmramRanges + ) +{ + UINTN Index; + EFI_STATUS Status; + UINTN SmmPoolTypeIndex; + EFI_LOAD_FIXED_ADDRESS_CONFIGURATION_TABLE *LMFAConfigurationTable; + + // + // Initialize Pool list + // + for (SmmPoolTypeIndex = 0; SmmPoolTypeIndex < SmmPoolTypeMax; SmmPoolTypeIndex++) { + for (Index = 0; Index < ARRAY_SIZE (mSmmPoolLists[SmmPoolTypeIndex]); Index++) { + InitializeListHead (&mSmmPoolLists[SmmPoolTypeIndex][Index]); + } + } + + Status = EfiGetSystemConfigurationTable ( + &gLoadFixedAddressConfigurationTableGuid, + (VOID **)&LMFAConfigurationTable + ); + if (!EFI_ERROR (Status) && (LMFAConfigurationTable != NULL)) { + gLoadModuleAtFixAddressSmramBase = LMFAConfigurationTable->SmramBase; + } + + // + // Add Free SMRAM regions + // Need add Free memory at first, to let gSmmMemoryMap record data + // + for (Index = 0; Index < SmramRangeCount; Index++) { + if ((SmramRanges[Index].RegionState & (EFI_ALLOCATED | EFI_NEEDS_TESTING | EFI_NEEDS_ECC_INITIALIZATION)) != 0) { + continue; + } + + SmmAddMemoryRegion ( + SmramRanges[Index].CpuStart, + SmramRanges[Index].PhysicalSize, + EfiConventionalMemory, + SmramRanges[Index].RegionState + ); + } + + // + // Add the allocated SMRAM regions + // + for (Index = 0; Index < SmramRangeCount; Index++) { + if ((SmramRanges[Index].RegionState & (EFI_ALLOCATED | EFI_NEEDS_TESTING | EFI_NEEDS_ECC_INITIALIZATION)) == 0) { + continue; + } + + SmmAddMemoryRegion ( + SmramRanges[Index].CpuStart, + SmramRanges[Index].PhysicalSize, + EfiConventionalMemory, + SmramRanges[Index].RegionState + ); + } +} + +/** + Internal Function. Allocate a pool by specified PoolIndex. + + @param PoolType Type of pool to allocate. + @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 EFI_MEMORY_TYPE PoolType, + IN UINTN PoolIndex, + OUT FREE_POOL_HEADER **FreePoolHdr + ) +{ + EFI_STATUS Status; + FREE_POOL_HEADER *Hdr; + POOL_TAIL *Tail; + EFI_PHYSICAL_ADDRESS Address; + SMM_POOL_TYPE SmmPoolType; + + Address = 0; + SmmPoolType = UefiMemoryTypeToSmmPoolType (PoolType); + + ASSERT (PoolIndex <= MAX_POOL_INDEX); + Status = EFI_SUCCESS; + Hdr = NULL; + if (PoolIndex == MAX_POOL_INDEX) { + Status = SmmInternalAllocatePages ( + AllocateAnyPages, + PoolType, + EFI_SIZE_TO_PAGES (MAX_POOL_SIZE << 1), + &Address, + FALSE + ); + if (EFI_ERROR (Status)) { + return EFI_OUT_OF_RESOURCES; + } + + Hdr = (FREE_POOL_HEADER *)(UINTN)Address; + } else if (!IsListEmpty (&mSmmPoolLists[SmmPoolType][PoolIndex])) { + Hdr = BASE_CR (GetFirstNode (&mSmmPoolLists[SmmPoolType][PoolIndex]), FREE_POOL_HEADER, Link); + RemoveEntryList (&Hdr->Link); + } else { + Status = InternalAllocPoolByIndex (PoolType, PoolIndex + 1, &Hdr); + if (!EFI_ERROR (Status)) { + Hdr->Header.Signature = 0; + Hdr->Header.Size >>= 1; + Hdr->Header.Available = TRUE; + Hdr->Header.Type = 0; + Tail = HEAD_TO_TAIL (&Hdr->Header); + Tail->Signature = 0; + Tail->Size = 0; + InsertHeadList (&mSmmPoolLists[SmmPoolType][PoolIndex], &Hdr->Link); + Hdr = (FREE_POOL_HEADER *)((UINT8 *)Hdr + Hdr->Header.Size); + } + } + + if (!EFI_ERROR (Status)) { + Hdr->Header.Signature = POOL_HEAD_SIGNATURE; + Hdr->Header.Size = MIN_POOL_SIZE << PoolIndex; + Hdr->Header.Available = FALSE; + Hdr->Header.Type = PoolType; + Tail = HEAD_TO_TAIL (&Hdr->Header); + Tail->Signature = POOL_TAIL_SIGNATURE; + Tail->Size = Hdr->Header.Size; + } + + *FreePoolHdr = Hdr; + return Status; +} + +/** + Internal Function. Free a pool by specified PoolIndex. + + @param FreePoolHdr The pool to free. + @param PoolTail The pointer to the pool tail. + + @retval EFI_SUCCESS Pool successfully freed. + +**/ +EFI_STATUS +InternalFreePoolByIndex ( + IN FREE_POOL_HEADER *FreePoolHdr, + IN POOL_TAIL *PoolTail + ) +{ + UINTN PoolIndex; + SMM_POOL_TYPE SmmPoolType; + + ASSERT ((FreePoolHdr->Header.Size & (FreePoolHdr->Header.Size - 1)) == 0); + ASSERT (((UINTN)FreePoolHdr & (FreePoolHdr->Header.Size - 1)) == 0); + ASSERT (FreePoolHdr->Header.Size >= MIN_POOL_SIZE); + + SmmPoolType = UefiMemoryTypeToSmmPoolType (FreePoolHdr->Header.Type); + + PoolIndex = (UINTN)(HighBitSet32 ((UINT32)FreePoolHdr->Header.Size) - MIN_POOL_SHIFT); + FreePoolHdr->Header.Signature = 0; + FreePoolHdr->Header.Available = TRUE; + FreePoolHdr->Header.Type = 0; + PoolTail->Signature = 0; + PoolTail->Size = 0; + ASSERT (PoolIndex < MAX_POOL_INDEX); + InsertHeadList (&mSmmPoolLists[SmmPoolType][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 +SmmInternalAllocatePool ( + IN EFI_MEMORY_TYPE PoolType, + IN UINTN Size, + OUT VOID **Buffer + ) +{ + POOL_HEADER *PoolHdr; + POOL_TAIL *PoolTail; + FREE_POOL_HEADER *FreePoolHdr; + EFI_STATUS Status; + EFI_PHYSICAL_ADDRESS Address; + UINTN PoolIndex; + BOOLEAN HasPoolTail; + BOOLEAN NeedGuard; + UINTN NoPages; + + Address = 0; + + if ((PoolType != EfiRuntimeServicesCode) && + (PoolType != EfiRuntimeServicesData)) + { + return EFI_INVALID_PARAMETER; + } + + NeedGuard = IsPoolTypeToGuard (PoolType); + HasPoolTail = !(NeedGuard && + ((PcdGet8 (PcdHeapGuardPropertyMask) & BIT7) == 0)); + + // + // Adjust the size by the pool header & tail overhead + // + Size += POOL_OVERHEAD; + if ((Size > MAX_POOL_SIZE) || NeedGuard) { + if (!HasPoolTail) { + Size -= sizeof (POOL_TAIL); + } + + NoPages = EFI_SIZE_TO_PAGES (Size); + Status = SmmInternalAllocatePages ( + AllocateAnyPages, + PoolType, + NoPages, + &Address, + NeedGuard + ); + if (EFI_ERROR (Status)) { + return Status; + } + + if (NeedGuard) { + ASSERT (VerifyMemoryGuard (Address, NoPages) == TRUE); + Address = (EFI_PHYSICAL_ADDRESS)(UINTN)AdjustPoolHeadA ( + Address, + NoPages, + Size + ); + } + + PoolHdr = (POOL_HEADER *)(UINTN)Address; + PoolHdr->Signature = POOL_HEAD_SIGNATURE; + PoolHdr->Size = EFI_PAGES_TO_SIZE (NoPages); + PoolHdr->Available = FALSE; + PoolHdr->Type = PoolType; + + if (HasPoolTail) { + PoolTail = HEAD_TO_TAIL (PoolHdr); + PoolTail->Signature = POOL_TAIL_SIGNATURE; + PoolTail->Size = PoolHdr->Size; + } + + *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 (PoolType, 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 +SmmAllocatePool ( + IN EFI_MEMORY_TYPE PoolType, + IN UINTN Size, + OUT VOID **Buffer + ) +{ + EFI_STATUS Status; + + Status = SmmInternalAllocatePool (PoolType, Size, Buffer); + if (!EFI_ERROR (Status)) { + SmmCoreUpdateProfile ( + (EFI_PHYSICAL_ADDRESS)(UINTN)RETURN_ADDRESS (0), + MemoryProfileActionAllocatePool, + PoolType, + Size, + *Buffer, + NULL + ); + } + + 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 +SmmInternalFreePool ( + IN VOID *Buffer + ) +{ + FREE_POOL_HEADER *FreePoolHdr; + POOL_TAIL *PoolTail; + BOOLEAN HasPoolTail; + BOOLEAN MemoryGuarded; + + if (Buffer == NULL) { + return EFI_INVALID_PARAMETER; + } + + FreePoolHdr = (FREE_POOL_HEADER *)((POOL_HEADER *)Buffer - 1); + ASSERT (FreePoolHdr->Header.Signature == POOL_HEAD_SIGNATURE); + ASSERT (!FreePoolHdr->Header.Available); + if (FreePoolHdr->Header.Signature != POOL_HEAD_SIGNATURE) { + return EFI_INVALID_PARAMETER; + } + + MemoryGuarded = IsHeapGuardEnabled () && + IsMemoryGuarded ((EFI_PHYSICAL_ADDRESS)(UINTN)FreePoolHdr); + HasPoolTail = !(MemoryGuarded && + ((PcdGet8 (PcdHeapGuardPropertyMask) & BIT7) == 0)); + + if (HasPoolTail) { + PoolTail = HEAD_TO_TAIL (&FreePoolHdr->Header); + ASSERT (PoolTail->Signature == POOL_TAIL_SIGNATURE); + ASSERT (FreePoolHdr->Header.Size == PoolTail->Size); + if (PoolTail->Signature != POOL_TAIL_SIGNATURE) { + return EFI_INVALID_PARAMETER; + } + + if (FreePoolHdr->Header.Size != PoolTail->Size) { + return EFI_INVALID_PARAMETER; + } + } else { + PoolTail = NULL; + } + + if (MemoryGuarded) { + Buffer = AdjustPoolHeadF ((EFI_PHYSICAL_ADDRESS)(UINTN)FreePoolHdr); + return SmmInternalFreePages ( + (EFI_PHYSICAL_ADDRESS)(UINTN)Buffer, + EFI_SIZE_TO_PAGES (FreePoolHdr->Header.Size), + TRUE + ); + } + + if (FreePoolHdr->Header.Size > MAX_POOL_SIZE) { + ASSERT (((UINTN)FreePoolHdr & EFI_PAGE_MASK) == 0); + ASSERT ((FreePoolHdr->Header.Size & EFI_PAGE_MASK) == 0); + return SmmInternalFreePages ( + (EFI_PHYSICAL_ADDRESS)(UINTN)FreePoolHdr, + EFI_SIZE_TO_PAGES (FreePoolHdr->Header.Size), + FALSE + ); + } + + return InternalFreePoolByIndex (FreePoolHdr, PoolTail); +} + +/** + 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 +SmmFreePool ( + IN VOID *Buffer + ) +{ + EFI_STATUS Status; + + Status = SmmInternalFreePool (Buffer); + if (!EFI_ERROR (Status)) { + SmmCoreUpdateProfile ( + (EFI_PHYSICAL_ADDRESS)(UINTN)RETURN_ADDRESS (0), + MemoryProfileActionFreePool, + EfiMaxMemoryType, + 0, + Buffer, + NULL + ); + } + + return Status; +} diff --git a/MdeModulePkg/Core/PiSmmCore/Smi.c b/MdeModulePkg/Core/PiSmmCore/Smi.c index 6b56fa5f69..f3ab4bbd92 100644 --- a/MdeModulePkg/Core/PiSmmCore/Smi.c +++ b/MdeModulePkg/Core/PiSmmCore/Smi.c @@ -1,460 +1,460 @@ -/** @file
- SMI management.
-
- Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.<BR>
- SPDX-License-Identifier: BSD-2-Clause-Patent
-
-**/
-
-#include "PiSmmCore.h"
-
-//
-// mSmiManageCallingDepth is used to track the depth of recursive calls of SmiManage.
-//
-UINTN mSmiManageCallingDepth = 0;
-
-LIST_ENTRY mSmiEntryList = INITIALIZE_LIST_HEAD_VARIABLE (mSmiEntryList);
-
-SMI_ENTRY mRootSmiEntry = {
- SMI_ENTRY_SIGNATURE,
- INITIALIZE_LIST_HEAD_VARIABLE (mRootSmiEntry.AllEntries),
- { 0 },
- INITIALIZE_LIST_HEAD_VARIABLE (mRootSmiEntry.SmiHandlers),
-};
-
-/**
- Finds the SMI entry for the requested handler type.
-
- @param HandlerType The type of the interrupt
- @param Create Create a new entry if not found
-
- @return SMI entry
-
-**/
-SMI_ENTRY *
-EFIAPI
-SmmCoreFindSmiEntry (
- IN EFI_GUID *HandlerType,
- IN BOOLEAN Create
- )
-{
- LIST_ENTRY *Link;
- SMI_ENTRY *Item;
- SMI_ENTRY *SmiEntry;
-
- //
- // Search the SMI entry list for the matching GUID
- //
- SmiEntry = NULL;
- for (Link = mSmiEntryList.ForwardLink;
- Link != &mSmiEntryList;
- Link = Link->ForwardLink)
- {
- Item = CR (Link, SMI_ENTRY, AllEntries, SMI_ENTRY_SIGNATURE);
- if (CompareGuid (&Item->HandlerType, HandlerType)) {
- //
- // This is the SMI entry
- //
- SmiEntry = Item;
- break;
- }
- }
-
- //
- // If the protocol entry was not found and Create is TRUE, then
- // allocate a new entry
- //
- if ((SmiEntry == NULL) && Create) {
- SmiEntry = AllocatePool (sizeof (SMI_ENTRY));
- if (SmiEntry != NULL) {
- //
- // Initialize new SMI entry structure
- //
- SmiEntry->Signature = SMI_ENTRY_SIGNATURE;
- CopyGuid ((VOID *)&SmiEntry->HandlerType, HandlerType);
- InitializeListHead (&SmiEntry->SmiHandlers);
-
- //
- // Add it to SMI entry list
- //
- InsertTailList (&mSmiEntryList, &SmiEntry->AllEntries);
- }
- }
-
- return SmiEntry;
-}
-
-/**
- Remove SmiHandler and free the memory it used.
- If SmiEntry is empty, remove SmiEntry and free the memory it used.
-
- @param SmiHandler Points to SMI handler.
- @param SmiEntry Points to SMI Entry or NULL for root SMI handlers.
-
- @retval TRUE SmiEntry is removed.
- @retval FALSE SmiEntry is not removed.
-**/
-BOOLEAN
-RemoveSmiHandler (
- IN SMI_HANDLER *SmiHandler,
- IN SMI_ENTRY *SmiEntry
- )
-{
- ASSERT (SmiHandler->ToRemove);
- RemoveEntryList (&SmiHandler->Link);
- FreePool (SmiHandler);
-
- //
- // Remove the SMI_ENTRY if all handlers have been removed.
- //
- if (SmiEntry != NULL) {
- if (IsListEmpty (&SmiEntry->SmiHandlers)) {
- RemoveEntryList (&SmiEntry->AllEntries);
- FreePool (SmiEntry);
- return TRUE;
- }
- }
-
- return FALSE;
-}
-
-/**
- Manage SMI of a particular type.
-
- @param HandlerType Points to the handler type or NULL for root SMI 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 SMI 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
-SmiManage (
- 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;
- LIST_ENTRY *EntryLink;
- SMI_ENTRY *SmiEntry;
- SMI_HANDLER *SmiHandler;
- EFI_STATUS ReturnStatus;
- BOOLEAN WillReturn;
- EFI_STATUS Status;
-
- PERF_FUNCTION_BEGIN ();
- mSmiManageCallingDepth++;
- WillReturn = FALSE;
- Status = EFI_NOT_FOUND;
- ReturnStatus = Status;
- if (HandlerType == NULL) {
- //
- // Root SMI handler
- //
- SmiEntry = &mRootSmiEntry;
- } else {
- //
- // Non-root SMI handler
- //
- SmiEntry = SmmCoreFindSmiEntry ((EFI_GUID *)HandlerType, FALSE);
- if (SmiEntry == NULL) {
- //
- // There is no handler registered for this interrupt source
- //
- PERF_FUNCTION_END ();
- return Status;
- }
- }
-
- Head = &SmiEntry->SmiHandlers;
-
- for (Link = Head->ForwardLink; Link != Head; Link = Link->ForwardLink) {
- SmiHandler = CR (Link, SMI_HANDLER, Link, SMI_HANDLER_SIGNATURE);
-
- Status = SmiHandler->Handler (
- (EFI_HANDLE)SmiHandler,
- 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) {
- PERF_FUNCTION_END ();
- ReturnStatus = EFI_INTERRUPT_PENDING;
- WillReturn = TRUE;
- } else {
- //
- // If any other handler's result sets ReturnStatus as EFI_SUCCESS, the return status
- // will be EFI_SUCCESS.
- //
- if (ReturnStatus != EFI_SUCCESS) {
- ReturnStatus = Status;
- }
- }
-
- 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) {
- PERF_FUNCTION_END ();
- WillReturn = TRUE;
- }
-
- ReturnStatus = EFI_SUCCESS;
- 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.
- //
- ReturnStatus = EFI_SUCCESS;
- 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.
- //
- if (ReturnStatus != EFI_SUCCESS) {
- ReturnStatus = Status;
- }
-
- break;
-
- default:
- //
- // Unexpected status code returned.
- //
- ASSERT (FALSE);
- break;
- }
-
- if (WillReturn) {
- break;
- }
- }
-
- ASSERT (mSmiManageCallingDepth > 0);
- mSmiManageCallingDepth--;
-
- //
- // SmiHandlerUnRegister() calls from SMI handlers are deferred till this point.
- // Before returned from SmiManage, delete the SmiHandler which is
- // marked as ToRemove.
- // Note that SmiManage can be called recursively.
- //
- if (mSmiManageCallingDepth == 0) {
- //
- // Go through all SmiHandler in root SMI handlers
- //
- for ( Link = GetFirstNode (&mRootSmiEntry.SmiHandlers)
- ; !IsNull (&mRootSmiEntry.SmiHandlers, Link);
- )
- {
- //
- // SmiHandler might be removed in below, so cache the next link in Link
- //
- SmiHandler = CR (Link, SMI_HANDLER, Link, SMI_HANDLER_SIGNATURE);
- Link = GetNextNode (&mRootSmiEntry.SmiHandlers, Link);
- if (SmiHandler->ToRemove) {
- //
- // Remove SmiHandler if the ToRemove is set.
- //
- RemoveSmiHandler (SmiHandler, NULL);
- }
- }
-
- //
- // Go through all SmiHandler in non-root SMI handlers
- //
- for ( EntryLink = GetFirstNode (&mSmiEntryList)
- ; !IsNull (&mSmiEntryList, EntryLink);
- )
- {
- //
- // SmiEntry might be removed in below, so cache the next link in EntryLink
- //
- SmiEntry = CR (EntryLink, SMI_ENTRY, AllEntries, SMI_ENTRY_SIGNATURE);
- EntryLink = GetNextNode (&mSmiEntryList, EntryLink);
- for ( Link = GetFirstNode (&SmiEntry->SmiHandlers)
- ; !IsNull (&SmiEntry->SmiHandlers, Link);
- )
- {
- //
- // SmiHandler might be removed in below, so cache the next link in Link
- //
- SmiHandler = CR (Link, SMI_HANDLER, Link, SMI_HANDLER_SIGNATURE);
- Link = GetNextNode (&SmiEntry->SmiHandlers, Link);
- if (SmiHandler->ToRemove) {
- if (RemoveSmiHandler (SmiHandler, SmiEntry)) {
- break;
- }
- }
- }
- }
- }
-
- PERF_FUNCTION_END ();
- return ReturnStatus;
-}
-
-/**
- Registers a handler to execute within SMM.
-
- @param Handler Handler service function pointer.
- @param HandlerType Points to the handler type or NULL for root SMI 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
-SmiHandlerRegister (
- IN EFI_SMM_HANDLER_ENTRY_POINT2 Handler,
- IN CONST EFI_GUID *HandlerType OPTIONAL,
- OUT EFI_HANDLE *DispatchHandle
- )
-{
- SMI_HANDLER *SmiHandler;
- SMI_ENTRY *SmiEntry;
- LIST_ENTRY *List;
-
- if ((Handler == NULL) || (DispatchHandle == NULL)) {
- return EFI_INVALID_PARAMETER;
- }
-
- SmiHandler = AllocateZeroPool (sizeof (SMI_HANDLER));
- if (SmiHandler == NULL) {
- return EFI_OUT_OF_RESOURCES;
- }
-
- SmiHandler->Signature = SMI_HANDLER_SIGNATURE;
- SmiHandler->Handler = Handler;
- SmiHandler->CallerAddr = (UINTN)RETURN_ADDRESS (0);
- SmiHandler->ToRemove = FALSE;
-
- if (HandlerType == NULL) {
- //
- // This is root SMI handler
- //
- SmiEntry = &mRootSmiEntry;
- } else {
- //
- // None root SMI handler
- //
- SmiEntry = SmmCoreFindSmiEntry ((EFI_GUID *)HandlerType, TRUE);
- if (SmiEntry == NULL) {
- return EFI_OUT_OF_RESOURCES;
- }
- }
-
- List = &SmiEntry->SmiHandlers;
-
- SmiHandler->SmiEntry = SmiEntry;
- InsertTailList (List, &SmiHandler->Link);
-
- *DispatchHandle = (EFI_HANDLE)SmiHandler;
-
- return EFI_SUCCESS;
-}
-
-/**
- Unregister a handler in SMM.
-
- @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
-SmiHandlerUnRegister (
- IN EFI_HANDLE DispatchHandle
- )
-{
- SMI_HANDLER *SmiHandler;
- SMI_ENTRY *SmiEntry;
- LIST_ENTRY *EntryLink;
- LIST_ENTRY *HandlerLink;
-
- if (DispatchHandle == NULL) {
- return EFI_INVALID_PARAMETER;
- }
-
- //
- // Look for it in root SMI handlers
- //
- SmiHandler = NULL;
- for ( HandlerLink = GetFirstNode (&mRootSmiEntry.SmiHandlers)
- ; !IsNull (&mRootSmiEntry.SmiHandlers, HandlerLink) && ((EFI_HANDLE)SmiHandler != DispatchHandle)
- ; HandlerLink = GetNextNode (&mRootSmiEntry.SmiHandlers, HandlerLink)
- )
- {
- SmiHandler = CR (HandlerLink, SMI_HANDLER, Link, SMI_HANDLER_SIGNATURE);
- }
-
- //
- // Look for it in non-root SMI handlers
- //
- for ( EntryLink = GetFirstNode (&mSmiEntryList)
- ; !IsNull (&mSmiEntryList, EntryLink) && ((EFI_HANDLE)SmiHandler != DispatchHandle)
- ; EntryLink = GetNextNode (&mSmiEntryList, EntryLink)
- )
- {
- SmiEntry = CR (EntryLink, SMI_ENTRY, AllEntries, SMI_ENTRY_SIGNATURE);
- for ( HandlerLink = GetFirstNode (&SmiEntry->SmiHandlers)
- ; !IsNull (&SmiEntry->SmiHandlers, HandlerLink) && ((EFI_HANDLE)SmiHandler != DispatchHandle)
- ; HandlerLink = GetNextNode (&SmiEntry->SmiHandlers, HandlerLink)
- )
- {
- SmiHandler = CR (HandlerLink, SMI_HANDLER, Link, SMI_HANDLER_SIGNATURE);
- }
- }
-
- if (SmiHandler == NULL) {
- return EFI_INVALID_PARAMETER;
- }
-
- ASSERT ((EFI_HANDLE)SmiHandler == DispatchHandle);
- SmiHandler->ToRemove = TRUE;
-
- if (mSmiManageCallingDepth > 0) {
- //
- // This function is called from SmiManage()
- // Do not delete or remove SmiHandler or SmiEntry now.
- // SmiManage will handle it later
- //
- return EFI_SUCCESS;
- }
-
- SmiEntry = SmiHandler->SmiEntry;
-
- //
- // For root SMI handler, use NULL for SmiEntry
- //
- RemoveSmiHandler (SmiHandler, (SmiEntry == &mRootSmiEntry) ? NULL : SmiEntry);
- return EFI_SUCCESS;
-}
+/** @file + SMI management. + + Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.<BR> + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "PiSmmCore.h" + +// +// mSmiManageCallingDepth is used to track the depth of recursive calls of SmiManage. +// +UINTN mSmiManageCallingDepth = 0; + +LIST_ENTRY mSmiEntryList = INITIALIZE_LIST_HEAD_VARIABLE (mSmiEntryList); + +SMI_ENTRY mRootSmiEntry = { + SMI_ENTRY_SIGNATURE, + INITIALIZE_LIST_HEAD_VARIABLE (mRootSmiEntry.AllEntries), + { 0 }, + INITIALIZE_LIST_HEAD_VARIABLE (mRootSmiEntry.SmiHandlers), +}; + +/** + Finds the SMI entry for the requested handler type. + + @param HandlerType The type of the interrupt + @param Create Create a new entry if not found + + @return SMI entry + +**/ +SMI_ENTRY * +EFIAPI +SmmCoreFindSmiEntry ( + IN EFI_GUID *HandlerType, + IN BOOLEAN Create + ) +{ + LIST_ENTRY *Link; + SMI_ENTRY *Item; + SMI_ENTRY *SmiEntry; + + // + // Search the SMI entry list for the matching GUID + // + SmiEntry = NULL; + for (Link = mSmiEntryList.ForwardLink; + Link != &mSmiEntryList; + Link = Link->ForwardLink) + { + Item = CR (Link, SMI_ENTRY, AllEntries, SMI_ENTRY_SIGNATURE); + if (CompareGuid (&Item->HandlerType, HandlerType)) { + // + // This is the SMI entry + // + SmiEntry = Item; + break; + } + } + + // + // If the protocol entry was not found and Create is TRUE, then + // allocate a new entry + // + if ((SmiEntry == NULL) && Create) { + SmiEntry = AllocatePool (sizeof (SMI_ENTRY)); + if (SmiEntry != NULL) { + // + // Initialize new SMI entry structure + // + SmiEntry->Signature = SMI_ENTRY_SIGNATURE; + CopyGuid ((VOID *)&SmiEntry->HandlerType, HandlerType); + InitializeListHead (&SmiEntry->SmiHandlers); + + // + // Add it to SMI entry list + // + InsertTailList (&mSmiEntryList, &SmiEntry->AllEntries); + } + } + + return SmiEntry; +} + +/** + Remove SmiHandler and free the memory it used. + If SmiEntry is empty, remove SmiEntry and free the memory it used. + + @param SmiHandler Points to SMI handler. + @param SmiEntry Points to SMI Entry or NULL for root SMI handlers. + + @retval TRUE SmiEntry is removed. + @retval FALSE SmiEntry is not removed. +**/ +BOOLEAN +RemoveSmiHandler ( + IN SMI_HANDLER *SmiHandler, + IN SMI_ENTRY *SmiEntry + ) +{ + ASSERT (SmiHandler->ToRemove); + RemoveEntryList (&SmiHandler->Link); + FreePool (SmiHandler); + + // + // Remove the SMI_ENTRY if all handlers have been removed. + // + if (SmiEntry != NULL) { + if (IsListEmpty (&SmiEntry->SmiHandlers)) { + RemoveEntryList (&SmiEntry->AllEntries); + FreePool (SmiEntry); + return TRUE; + } + } + + return FALSE; +} + +/** + Manage SMI of a particular type. + + @param HandlerType Points to the handler type or NULL for root SMI 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 SMI 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 +SmiManage ( + 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; + LIST_ENTRY *EntryLink; + SMI_ENTRY *SmiEntry; + SMI_HANDLER *SmiHandler; + EFI_STATUS ReturnStatus; + BOOLEAN WillReturn; + EFI_STATUS Status; + + PERF_FUNCTION_BEGIN (); + mSmiManageCallingDepth++; + WillReturn = FALSE; + Status = EFI_NOT_FOUND; + ReturnStatus = Status; + if (HandlerType == NULL) { + // + // Root SMI handler + // + SmiEntry = &mRootSmiEntry; + } else { + // + // Non-root SMI handler + // + SmiEntry = SmmCoreFindSmiEntry ((EFI_GUID *)HandlerType, FALSE); + if (SmiEntry == NULL) { + // + // There is no handler registered for this interrupt source + // + PERF_FUNCTION_END (); + return Status; + } + } + + Head = &SmiEntry->SmiHandlers; + + for (Link = Head->ForwardLink; Link != Head; Link = Link->ForwardLink) { + SmiHandler = CR (Link, SMI_HANDLER, Link, SMI_HANDLER_SIGNATURE); + + Status = SmiHandler->Handler ( + (EFI_HANDLE)SmiHandler, + 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) { + PERF_FUNCTION_END (); + ReturnStatus = EFI_INTERRUPT_PENDING; + WillReturn = TRUE; + } else { + // + // If any other handler's result sets ReturnStatus as EFI_SUCCESS, the return status + // will be EFI_SUCCESS. + // + if (ReturnStatus != EFI_SUCCESS) { + ReturnStatus = Status; + } + } + + 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) { + PERF_FUNCTION_END (); + WillReturn = TRUE; + } + + ReturnStatus = EFI_SUCCESS; + 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. + // + ReturnStatus = EFI_SUCCESS; + 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. + // + if (ReturnStatus != EFI_SUCCESS) { + ReturnStatus = Status; + } + + break; + + default: + // + // Unexpected status code returned. + // + ASSERT (FALSE); + break; + } + + if (WillReturn) { + break; + } + } + + ASSERT (mSmiManageCallingDepth > 0); + mSmiManageCallingDepth--; + + // + // SmiHandlerUnRegister() calls from SMI handlers are deferred till this point. + // Before returned from SmiManage, delete the SmiHandler which is + // marked as ToRemove. + // Note that SmiManage can be called recursively. + // + if (mSmiManageCallingDepth == 0) { + // + // Go through all SmiHandler in root SMI handlers + // + for ( Link = GetFirstNode (&mRootSmiEntry.SmiHandlers) + ; !IsNull (&mRootSmiEntry.SmiHandlers, Link); + ) + { + // + // SmiHandler might be removed in below, so cache the next link in Link + // + SmiHandler = CR (Link, SMI_HANDLER, Link, SMI_HANDLER_SIGNATURE); + Link = GetNextNode (&mRootSmiEntry.SmiHandlers, Link); + if (SmiHandler->ToRemove) { + // + // Remove SmiHandler if the ToRemove is set. + // + RemoveSmiHandler (SmiHandler, NULL); + } + } + + // + // Go through all SmiHandler in non-root SMI handlers + // + for ( EntryLink = GetFirstNode (&mSmiEntryList) + ; !IsNull (&mSmiEntryList, EntryLink); + ) + { + // + // SmiEntry might be removed in below, so cache the next link in EntryLink + // + SmiEntry = CR (EntryLink, SMI_ENTRY, AllEntries, SMI_ENTRY_SIGNATURE); + EntryLink = GetNextNode (&mSmiEntryList, EntryLink); + for ( Link = GetFirstNode (&SmiEntry->SmiHandlers) + ; !IsNull (&SmiEntry->SmiHandlers, Link); + ) + { + // + // SmiHandler might be removed in below, so cache the next link in Link + // + SmiHandler = CR (Link, SMI_HANDLER, Link, SMI_HANDLER_SIGNATURE); + Link = GetNextNode (&SmiEntry->SmiHandlers, Link); + if (SmiHandler->ToRemove) { + if (RemoveSmiHandler (SmiHandler, SmiEntry)) { + break; + } + } + } + } + } + + PERF_FUNCTION_END (); + return ReturnStatus; +} + +/** + Registers a handler to execute within SMM. + + @param Handler Handler service function pointer. + @param HandlerType Points to the handler type or NULL for root SMI 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 +SmiHandlerRegister ( + IN EFI_SMM_HANDLER_ENTRY_POINT2 Handler, + IN CONST EFI_GUID *HandlerType OPTIONAL, + OUT EFI_HANDLE *DispatchHandle + ) +{ + SMI_HANDLER *SmiHandler; + SMI_ENTRY *SmiEntry; + LIST_ENTRY *List; + + if ((Handler == NULL) || (DispatchHandle == NULL)) { + return EFI_INVALID_PARAMETER; + } + + SmiHandler = AllocateZeroPool (sizeof (SMI_HANDLER)); + if (SmiHandler == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + SmiHandler->Signature = SMI_HANDLER_SIGNATURE; + SmiHandler->Handler = Handler; + SmiHandler->CallerAddr = (UINTN)RETURN_ADDRESS (0); + SmiHandler->ToRemove = FALSE; + + if (HandlerType == NULL) { + // + // This is root SMI handler + // + SmiEntry = &mRootSmiEntry; + } else { + // + // None root SMI handler + // + SmiEntry = SmmCoreFindSmiEntry ((EFI_GUID *)HandlerType, TRUE); + if (SmiEntry == NULL) { + return EFI_OUT_OF_RESOURCES; + } + } + + List = &SmiEntry->SmiHandlers; + + SmiHandler->SmiEntry = SmiEntry; + InsertTailList (List, &SmiHandler->Link); + + *DispatchHandle = (EFI_HANDLE)SmiHandler; + + return EFI_SUCCESS; +} + +/** + Unregister a handler in SMM. + + @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 +SmiHandlerUnRegister ( + IN EFI_HANDLE DispatchHandle + ) +{ + SMI_HANDLER *SmiHandler; + SMI_ENTRY *SmiEntry; + LIST_ENTRY *EntryLink; + LIST_ENTRY *HandlerLink; + + if (DispatchHandle == NULL) { + return EFI_INVALID_PARAMETER; + } + + // + // Look for it in root SMI handlers + // + SmiHandler = NULL; + for ( HandlerLink = GetFirstNode (&mRootSmiEntry.SmiHandlers) + ; !IsNull (&mRootSmiEntry.SmiHandlers, HandlerLink) && ((EFI_HANDLE)SmiHandler != DispatchHandle) + ; HandlerLink = GetNextNode (&mRootSmiEntry.SmiHandlers, HandlerLink) + ) + { + SmiHandler = CR (HandlerLink, SMI_HANDLER, Link, SMI_HANDLER_SIGNATURE); + } + + // + // Look for it in non-root SMI handlers + // + for ( EntryLink = GetFirstNode (&mSmiEntryList) + ; !IsNull (&mSmiEntryList, EntryLink) && ((EFI_HANDLE)SmiHandler != DispatchHandle) + ; EntryLink = GetNextNode (&mSmiEntryList, EntryLink) + ) + { + SmiEntry = CR (EntryLink, SMI_ENTRY, AllEntries, SMI_ENTRY_SIGNATURE); + for ( HandlerLink = GetFirstNode (&SmiEntry->SmiHandlers) + ; !IsNull (&SmiEntry->SmiHandlers, HandlerLink) && ((EFI_HANDLE)SmiHandler != DispatchHandle) + ; HandlerLink = GetNextNode (&SmiEntry->SmiHandlers, HandlerLink) + ) + { + SmiHandler = CR (HandlerLink, SMI_HANDLER, Link, SMI_HANDLER_SIGNATURE); + } + } + + if (SmiHandler == NULL) { + return EFI_INVALID_PARAMETER; + } + + ASSERT ((EFI_HANDLE)SmiHandler == DispatchHandle); + SmiHandler->ToRemove = TRUE; + + if (mSmiManageCallingDepth > 0) { + // + // This function is called from SmiManage() + // Do not delete or remove SmiHandler or SmiEntry now. + // SmiManage will handle it later + // + return EFI_SUCCESS; + } + + SmiEntry = SmiHandler->SmiEntry; + + // + // For root SMI handler, use NULL for SmiEntry + // + RemoveSmiHandler (SmiHandler, (SmiEntry == &mRootSmiEntry) ? NULL : SmiEntry); + return EFI_SUCCESS; +} diff --git a/MdeModulePkg/Core/PiSmmCore/SmiHandlerProfile.c b/MdeModulePkg/Core/PiSmmCore/SmiHandlerProfile.c index 27da2898dd..4a22de6fb7 100644 --- a/MdeModulePkg/Core/PiSmmCore/SmiHandlerProfile.c +++ b/MdeModulePkg/Core/PiSmmCore/SmiHandlerProfile.c @@ -1,1419 +1,1419 @@ -/** @file
- SMI handler profile support.
-
-Copyright (c) 2017, Intel Corporation. All rights reserved.<BR>
-SPDX-License-Identifier: BSD-2-Clause-Patent
-
-**/
-
-#include <PiSmm.h>
-#include <Library/BaseLib.h>
-#include <Library/BaseMemoryLib.h>
-#include <Library/MemoryAllocationLib.h>
-#include <Library/UefiBootServicesTableLib.h>
-#include <Library/SmmServicesTableLib.h>
-#include <Library/DebugLib.h>
-#include <Library/PrintLib.h>
-#include <Library/UefiLib.h>
-#include <Library/DevicePathLib.h>
-#include <Library/PeCoffGetEntryPointLib.h>
-#include <Protocol/LoadedImage.h>
-#include <Protocol/SmmAccess2.h>
-#include <Protocol/SmmReadyToLock.h>
-#include <Protocol/SmmEndOfDxe.h>
-
-#include <Guid/SmiHandlerProfile.h>
-
-#include "PiSmmCore.h"
-
-#define GET_OCCUPIED_SIZE(ActualSize, Alignment) \
- ((ActualSize) + (((Alignment) - ((ActualSize) & ((Alignment) - 1))) & ((Alignment) - 1)))
-
-typedef struct {
- EFI_GUID FileGuid;
- PHYSICAL_ADDRESS EntryPoint;
- PHYSICAL_ADDRESS ImageBase;
- UINT64 ImageSize;
- UINT32 ImageRef;
- UINT16 PdbStringSize;
- CHAR8 *PdbString;
-} IMAGE_STRUCT;
-
-/**
- Register SMI handler profile handler.
-**/
-VOID
-RegisterSmiHandlerProfileHandler (
- VOID
- );
-
-/**
- Retrieves and returns a pointer to the entry point to a PE/COFF image that has been loaded
- into system memory with the PE/COFF Loader Library functions.
-
- Retrieves the entry point to the PE/COFF image specified by Pe32Data and returns this entry
- point in EntryPoint. If the entry point could not be retrieved from the PE/COFF image, then
- return RETURN_INVALID_PARAMETER. Otherwise return RETURN_SUCCESS.
- If Pe32Data is NULL, then ASSERT().
- If EntryPoint is NULL, then ASSERT().
-
- @param Pe32Data The pointer to the PE/COFF image that is loaded in system memory.
- @param EntryPoint The pointer to entry point to the PE/COFF image to return.
-
- @retval RETURN_SUCCESS EntryPoint was returned.
- @retval RETURN_INVALID_PARAMETER The entry point could not be found in the PE/COFF image.
-
-**/
-RETURN_STATUS
-InternalPeCoffGetEntryPoint (
- IN VOID *Pe32Data,
- OUT VOID **EntryPoint
- );
-
-extern LIST_ENTRY mSmiEntryList;
-extern LIST_ENTRY mHardwareSmiEntryList;
-extern SMI_ENTRY mRootSmiEntry;
-
-extern SMI_HANDLER_PROFILE_PROTOCOL mSmiHandlerProfile;
-
-GLOBAL_REMOVE_IF_UNREFERENCED LIST_ENTRY mHardwareSmiEntryList = INITIALIZE_LIST_HEAD_VARIABLE (mHardwareSmiEntryList);
-
-GLOBAL_REMOVE_IF_UNREFERENCED LIST_ENTRY mRootSmiEntryList = INITIALIZE_LIST_HEAD_VARIABLE (mRootSmiEntryList);
-
-GLOBAL_REMOVE_IF_UNREFERENCED LIST_ENTRY *mSmmCoreRootSmiEntryList = &mRootSmiEntryList;
-GLOBAL_REMOVE_IF_UNREFERENCED LIST_ENTRY *mSmmCoreSmiEntryList = &mSmiEntryList;
-GLOBAL_REMOVE_IF_UNREFERENCED LIST_ENTRY *mSmmCoreHardwareSmiEntryList = &mHardwareSmiEntryList;
-
-GLOBAL_REMOVE_IF_UNREFERENCED IMAGE_STRUCT *mImageStruct;
-GLOBAL_REMOVE_IF_UNREFERENCED UINT32 mImageStructCountMax;
-GLOBAL_REMOVE_IF_UNREFERENCED UINT32 mImageStructCount;
-
-GLOBAL_REMOVE_IF_UNREFERENCED VOID *mSmiHandlerProfileDatabase;
-GLOBAL_REMOVE_IF_UNREFERENCED UINTN mSmiHandlerProfileDatabaseSize;
-
-GLOBAL_REMOVE_IF_UNREFERENCED UINTN mSmmImageDatabaseSize;
-GLOBAL_REMOVE_IF_UNREFERENCED UINTN mSmmRootSmiDatabaseSize;
-GLOBAL_REMOVE_IF_UNREFERENCED UINTN mSmmSmiDatabaseSize;
-GLOBAL_REMOVE_IF_UNREFERENCED UINTN mSmmHardwareSmiDatabaseSize;
-
-GLOBAL_REMOVE_IF_UNREFERENCED BOOLEAN mSmiHandlerProfileRecordingStatus;
-
-GLOBAL_REMOVE_IF_UNREFERENCED SMI_HANDLER_PROFILE_PROTOCOL mSmiHandlerProfile = {
- SmiHandlerProfileRegisterHandler,
- SmiHandlerProfileUnregisterHandler,
-};
-
-/**
- This function dump raw data.
-
- @param Data raw data
- @param Size raw data size
-**/
-VOID
-InternalDumpData (
- IN UINT8 *Data,
- IN UINTN Size
- )
-{
- UINTN Index;
-
- for (Index = 0; Index < Size; Index++) {
- DEBUG ((DEBUG_INFO, "%02x ", (UINTN)Data[Index]));
- }
-}
-
-/**
- Get GUID name for an image.
-
- @param[in] LoadedImage LoadedImage protocol.
- @param[out] Guid Guid of the FFS
-**/
-VOID
-GetDriverGuid (
- IN EFI_LOADED_IMAGE_PROTOCOL *LoadedImage,
- OUT EFI_GUID *Guid
- )
-{
- EFI_GUID *FileName;
-
- FileName = NULL;
- if ((DevicePathType (LoadedImage->FilePath) == MEDIA_DEVICE_PATH) &&
- (DevicePathSubType (LoadedImage->FilePath) == MEDIA_PIWG_FW_FILE_DP))
- {
- FileName = &((MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *)LoadedImage->FilePath)->FvFileName;
- }
-
- if (FileName != NULL) {
- CopyGuid (Guid, FileName);
- } else {
- ZeroMem (Guid, sizeof (EFI_GUID));
- }
-}
-
-/**
- Add image structure.
-
- @param ImageBase image base
- @param ImageSize image size
- @param EntryPoint image entry point
- @param Guid FFS GUID of the image
- @param PdbString image PDB string
-**/
-VOID
-AddImageStruct (
- IN PHYSICAL_ADDRESS ImageBase,
- IN UINT64 ImageSize,
- IN PHYSICAL_ADDRESS EntryPoint,
- IN EFI_GUID *Guid,
- IN CHAR8 *PdbString
- )
-{
- UINTN PdbStringSize;
-
- if (mImageStructCount >= mImageStructCountMax) {
- ASSERT (FALSE);
- return;
- }
-
- CopyGuid (&mImageStruct[mImageStructCount].FileGuid, Guid);
- mImageStruct[mImageStructCount].ImageRef = mImageStructCount;
- mImageStruct[mImageStructCount].ImageBase = ImageBase;
- mImageStruct[mImageStructCount].ImageSize = ImageSize;
- mImageStruct[mImageStructCount].EntryPoint = EntryPoint;
- if (PdbString != NULL) {
- PdbStringSize = AsciiStrSize (PdbString);
- mImageStruct[mImageStructCount].PdbString = AllocateCopyPool (PdbStringSize, PdbString);
- if (mImageStruct[mImageStructCount].PdbString != NULL) {
- mImageStruct[mImageStructCount].PdbStringSize = (UINT16)PdbStringSize;
- }
- }
-
- mImageStructCount++;
-}
-
-/**
- return an image structure based upon image address.
-
- @param Address image address
-
- @return image structure
-**/
-IMAGE_STRUCT *
-AddressToImageStruct (
- IN UINTN Address
- )
-{
- UINTN Index;
-
- for (Index = 0; Index < mImageStructCount; Index++) {
- if ((Address >= mImageStruct[Index].ImageBase) &&
- (Address < mImageStruct[Index].ImageBase + mImageStruct[Index].ImageSize))
- {
- return &mImageStruct[Index];
- }
- }
-
- return NULL;
-}
-
-/**
- return an image reference index based upon image address.
-
- @param Address image address
-
- @return image reference index
-**/
-UINT32
-AddressToImageRef (
- IN UINTN Address
- )
-{
- IMAGE_STRUCT *ImageStruct;
-
- ImageStruct = AddressToImageStruct (Address);
- if (ImageStruct != NULL) {
- return ImageStruct->ImageRef;
- }
-
- return (UINT32)-1;
-}
-
-/**
- Collect SMM image information based upon loaded image protocol.
-**/
-VOID
-GetSmmLoadedImage (
- VOID
- )
-{
- EFI_STATUS Status;
- UINTN NoHandles;
- UINTN HandleBufferSize;
- EFI_HANDLE *HandleBuffer;
- UINTN Index;
- EFI_LOADED_IMAGE_PROTOCOL *LoadedImage;
- CHAR16 *PathStr;
- EFI_SMM_DRIVER_ENTRY *LoadedImagePrivate;
- PHYSICAL_ADDRESS EntryPoint;
- VOID *EntryPointInImage;
- EFI_GUID Guid;
- CHAR8 *PdbString;
- PHYSICAL_ADDRESS RealImageBase;
-
- HandleBufferSize = 0;
- HandleBuffer = NULL;
- Status = gSmst->SmmLocateHandle (
- ByProtocol,
- &gEfiLoadedImageProtocolGuid,
- NULL,
- &HandleBufferSize,
- HandleBuffer
- );
- if (Status != EFI_BUFFER_TOO_SMALL) {
- return;
- }
-
- HandleBuffer = AllocateZeroPool (HandleBufferSize);
- if (HandleBuffer == NULL) {
- return;
- }
-
- Status = gSmst->SmmLocateHandle (
- ByProtocol,
- &gEfiLoadedImageProtocolGuid,
- NULL,
- &HandleBufferSize,
- HandleBuffer
- );
- if (EFI_ERROR (Status)) {
- return;
- }
-
- NoHandles = HandleBufferSize/sizeof (EFI_HANDLE);
- mImageStructCountMax = (UINT32)NoHandles;
- mImageStruct = AllocateZeroPool (mImageStructCountMax * sizeof (IMAGE_STRUCT));
- if (mImageStruct == NULL) {
- goto Done;
- }
-
- for (Index = 0; Index < NoHandles; Index++) {
- Status = gSmst->SmmHandleProtocol (
- HandleBuffer[Index],
- &gEfiLoadedImageProtocolGuid,
- (VOID **)&LoadedImage
- );
- if (EFI_ERROR (Status)) {
- continue;
- }
-
- PathStr = ConvertDevicePathToText (LoadedImage->FilePath, TRUE, TRUE);
- GetDriverGuid (LoadedImage, &Guid);
- DEBUG ((DEBUG_INFO, "Image: %g ", &Guid));
-
- EntryPoint = 0;
- LoadedImagePrivate = BASE_CR (LoadedImage, EFI_SMM_DRIVER_ENTRY, SmmLoadedImage);
- RealImageBase = (UINTN)LoadedImage->ImageBase;
- if (LoadedImagePrivate->Signature == EFI_SMM_DRIVER_ENTRY_SIGNATURE) {
- EntryPoint = LoadedImagePrivate->ImageEntryPoint;
- if ((EntryPoint != 0) && ((EntryPoint < (UINTN)LoadedImage->ImageBase) || (EntryPoint >= ((UINTN)LoadedImage->ImageBase + LoadedImage->ImageSize)))) {
- //
- // If the EntryPoint is not in the range of image buffer, it should come from emulation environment.
- // So patch ImageBuffer here to align the EntryPoint.
- //
- Status = InternalPeCoffGetEntryPoint (LoadedImage->ImageBase, &EntryPointInImage);
- ASSERT_EFI_ERROR (Status);
- RealImageBase = (UINTN)LoadedImage->ImageBase + EntryPoint - (UINTN)EntryPointInImage;
- }
- }
-
- DEBUG ((DEBUG_INFO, "(0x%lx - 0x%lx", RealImageBase, LoadedImage->ImageSize));
- if (EntryPoint != 0) {
- DEBUG ((DEBUG_INFO, ", EntryPoint:0x%lx", EntryPoint));
- }
-
- DEBUG ((DEBUG_INFO, ")\n"));
-
- if (RealImageBase != 0) {
- PdbString = PeCoffLoaderGetPdbPointer ((VOID *)(UINTN)RealImageBase);
- DEBUG ((DEBUG_INFO, " pdb - %a\n", PdbString));
- } else {
- PdbString = NULL;
- }
-
- DEBUG ((DEBUG_INFO, " (%s)\n", PathStr));
-
- AddImageStruct (RealImageBase, LoadedImage->ImageSize, EntryPoint, &Guid, PdbString);
- }
-
-Done:
- FreePool (HandleBuffer);
- return;
-}
-
-/**
- Dump SMI child context.
-
- @param HandlerType the handler type
- @param Context the handler context
- @param ContextSize the handler context size
-**/
-VOID
-DumpSmiChildContext (
- IN EFI_GUID *HandlerType,
- IN VOID *Context,
- IN UINTN ContextSize
- )
-{
- CHAR16 *Str;
-
- if (CompareGuid (HandlerType, &gEfiSmmSwDispatch2ProtocolGuid)) {
- DEBUG ((DEBUG_INFO, " SwSmi - 0x%lx\n", ((SMI_HANDLER_PROFILE_SW_REGISTER_CONTEXT *)Context)->SwSmiInputValue));
- } else if (CompareGuid (HandlerType, &gEfiSmmSxDispatch2ProtocolGuid)) {
- DEBUG ((DEBUG_INFO, " SxType - 0x%x\n", ((EFI_SMM_SX_REGISTER_CONTEXT *)Context)->Type));
- DEBUG ((DEBUG_INFO, " SxPhase - 0x%x\n", ((EFI_SMM_SX_REGISTER_CONTEXT *)Context)->Phase));
- } else if (CompareGuid (HandlerType, &gEfiSmmPowerButtonDispatch2ProtocolGuid)) {
- DEBUG ((DEBUG_INFO, " PowerButtonPhase - 0x%x\n", ((EFI_SMM_POWER_BUTTON_REGISTER_CONTEXT *)Context)->Phase));
- } else if (CompareGuid (HandlerType, &gEfiSmmStandbyButtonDispatch2ProtocolGuid)) {
- DEBUG ((DEBUG_INFO, " StandbyButtonPhase - 0x%x\n", ((EFI_SMM_STANDBY_BUTTON_REGISTER_CONTEXT *)Context)->Phase));
- } else if (CompareGuid (HandlerType, &gEfiSmmPeriodicTimerDispatch2ProtocolGuid)) {
- DEBUG ((DEBUG_INFO, " PeriodicTimerPeriod - %ld\n", ((EFI_SMM_PERIODIC_TIMER_REGISTER_CONTEXT *)Context)->Period));
- DEBUG ((DEBUG_INFO, " PeriodicTimerSmiTickInterval - %ld\n", ((EFI_SMM_PERIODIC_TIMER_REGISTER_CONTEXT *)Context)->SmiTickInterval));
- } else if (CompareGuid (HandlerType, &gEfiSmmGpiDispatch2ProtocolGuid)) {
- DEBUG ((DEBUG_INFO, " GpiNum - 0x%lx\n", ((EFI_SMM_GPI_REGISTER_CONTEXT *)Context)->GpiNum));
- } else if (CompareGuid (HandlerType, &gEfiSmmIoTrapDispatch2ProtocolGuid)) {
- DEBUG ((DEBUG_INFO, " IoTrapAddress - 0x%x\n", ((EFI_SMM_IO_TRAP_REGISTER_CONTEXT *)Context)->Address));
- DEBUG ((DEBUG_INFO, " IoTrapLength - 0x%x\n", ((EFI_SMM_IO_TRAP_REGISTER_CONTEXT *)Context)->Length));
- DEBUG ((DEBUG_INFO, " IoTrapType - 0x%x\n", ((EFI_SMM_IO_TRAP_REGISTER_CONTEXT *)Context)->Type));
- } else if (CompareGuid (HandlerType, &gEfiSmmUsbDispatch2ProtocolGuid)) {
- DEBUG ((DEBUG_INFO, " UsbType - 0x%x\n", ((SMI_HANDLER_PROFILE_USB_REGISTER_CONTEXT *)Context)->Type));
- Str = ConvertDevicePathToText ((EFI_DEVICE_PATH_PROTOCOL *)(((SMI_HANDLER_PROFILE_USB_REGISTER_CONTEXT *)Context) + 1), TRUE, TRUE);
- DEBUG ((DEBUG_INFO, " UsbDevicePath - %s\n", Str));
- if (Str != NULL) {
- FreePool (Str);
- }
- } else {
- DEBUG ((DEBUG_INFO, " Context - "));
- InternalDumpData (Context, ContextSize);
- DEBUG ((DEBUG_INFO, "\n"));
- }
-}
-
-/**
- Dump all SMI handlers associated with SmiEntry.
-
- @param SmiEntry SMI entry.
-**/
-VOID
-DumpSmiHandlerOnSmiEntry (
- IN SMI_ENTRY *SmiEntry
- )
-{
- LIST_ENTRY *ListEntry;
- SMI_HANDLER *SmiHandler;
- IMAGE_STRUCT *ImageStruct;
-
- ListEntry = &SmiEntry->SmiHandlers;
- for (ListEntry = ListEntry->ForwardLink;
- ListEntry != &SmiEntry->SmiHandlers;
- ListEntry = ListEntry->ForwardLink)
- {
- SmiHandler = CR (ListEntry, SMI_HANDLER, Link, SMI_HANDLER_SIGNATURE);
- ImageStruct = AddressToImageStruct ((UINTN)SmiHandler->Handler);
- if (ImageStruct != NULL) {
- DEBUG ((DEBUG_INFO, " Module - %g", &ImageStruct->FileGuid));
- }
-
- if ((ImageStruct != NULL) && (ImageStruct->PdbString[0] != 0)) {
- DEBUG ((DEBUG_INFO, " (Pdb - %a)", ImageStruct->PdbString));
- }
-
- DEBUG ((DEBUG_INFO, "\n"));
- if (SmiHandler->ContextSize != 0) {
- DumpSmiChildContext (&SmiEntry->HandlerType, SmiHandler->Context, SmiHandler->ContextSize);
- }
-
- DEBUG ((DEBUG_INFO, " Handler - 0x%x", SmiHandler->Handler));
- if (ImageStruct != NULL) {
- DEBUG ((DEBUG_INFO, " <== RVA - 0x%x", (UINTN)SmiHandler->Handler - (UINTN)ImageStruct->ImageBase));
- }
-
- DEBUG ((DEBUG_INFO, "\n"));
- DEBUG ((DEBUG_INFO, " CallerAddr - 0x%x", SmiHandler->CallerAddr));
- if (ImageStruct != NULL) {
- DEBUG ((DEBUG_INFO, " <== RVA - 0x%x", SmiHandler->CallerAddr - (UINTN)ImageStruct->ImageBase));
- }
-
- DEBUG ((DEBUG_INFO, "\n"));
- }
-
- return;
-}
-
-/**
- Dump all SMI entry on the list.
-
- @param SmiEntryList a list of SMI entry.
-**/
-VOID
-DumpSmiEntryList (
- IN LIST_ENTRY *SmiEntryList
- )
-{
- LIST_ENTRY *ListEntry;
- SMI_ENTRY *SmiEntry;
-
- ListEntry = SmiEntryList;
- for (ListEntry = ListEntry->ForwardLink;
- ListEntry != SmiEntryList;
- ListEntry = ListEntry->ForwardLink)
- {
- SmiEntry = CR (ListEntry, SMI_ENTRY, AllEntries, SMI_ENTRY_SIGNATURE);
- DEBUG ((DEBUG_INFO, "SmiEntry - %g\n", &SmiEntry->HandlerType));
- DumpSmiHandlerOnSmiEntry (SmiEntry);
- }
-
- return;
-}
-
-/**
- SMM Ready To Lock event notification handler.
-
- This function collects all SMM image information and build SmiHandleProfile database,
- and register SmiHandlerProfile SMI handler.
-
- @param[in] Protocol Points to the protocol's unique identifier.
- @param[in] Interface Points to the interface instance.
- @param[in] Handle The handle on which the interface was installed.
-
- @retval EFI_SUCCESS Notification handler runs successfully.
-**/
-EFI_STATUS
-EFIAPI
-SmmReadyToLockInSmiHandlerProfile (
- IN CONST EFI_GUID *Protocol,
- IN VOID *Interface,
- IN EFI_HANDLE Handle
- )
-{
- //
- // Dump all image
- //
- DEBUG ((DEBUG_INFO, "##################\n"));
- DEBUG ((DEBUG_INFO, "# IMAGE DATABASE #\n"));
- DEBUG ((DEBUG_INFO, "##################\n"));
- GetSmmLoadedImage ();
- DEBUG ((DEBUG_INFO, "\n"));
-
- //
- // Dump SMI Handler
- //
- DEBUG ((DEBUG_INFO, "########################\n"));
- DEBUG ((DEBUG_INFO, "# SMI Handler DATABASE #\n"));
- DEBUG ((DEBUG_INFO, "########################\n"));
-
- DEBUG ((DEBUG_INFO, "# 1. ROOT SMI Handler #\n"));
- DEBUG_CODE (
- DumpSmiEntryList (mSmmCoreRootSmiEntryList);
- );
-
- DEBUG ((DEBUG_INFO, "# 2. GUID SMI Handler #\n"));
- DEBUG_CODE (
- DumpSmiEntryList (mSmmCoreSmiEntryList);
- );
-
- DEBUG ((DEBUG_INFO, "# 3. Hardware SMI Handler #\n"));
- DEBUG_CODE (
- DumpSmiEntryList (mSmmCoreHardwareSmiEntryList);
- );
-
- DEBUG ((DEBUG_INFO, "\n"));
-
- RegisterSmiHandlerProfileHandler ();
-
- if (mImageStruct != NULL) {
- FreePool (mImageStruct);
- }
-
- return EFI_SUCCESS;
-}
-
-/**
- returns SMM image data base size.
-
- @return SMM image data base size.
-**/
-UINTN
-GetSmmImageDatabaseSize (
- VOID
- )
-{
- UINTN Size;
- UINT32 Index;
-
- Size = 0;
- for (Index = 0; Index < mImageStructCount; Index++) {
- Size += sizeof (SMM_CORE_IMAGE_DATABASE_STRUCTURE) + GET_OCCUPIED_SIZE (mImageStruct[Index].PdbStringSize, sizeof (UINT64));
- }
-
- return Size;
-}
-
-/**
- returns all SMI handlers' size associated with SmiEntry.
-
- @param SmiEntry SMI entry.
-
- @return all SMI handlers' size associated with SmiEntry.
-**/
-UINTN
-GetSmmSmiHandlerSizeOnSmiEntry (
- IN SMI_ENTRY *SmiEntry
- )
-{
- LIST_ENTRY *ListEntry;
- SMI_HANDLER *SmiHandler;
- UINTN Size;
-
- Size = 0;
- ListEntry = &SmiEntry->SmiHandlers;
- for (ListEntry = ListEntry->ForwardLink;
- ListEntry != &SmiEntry->SmiHandlers;
- ListEntry = ListEntry->ForwardLink)
- {
- SmiHandler = CR (ListEntry, SMI_HANDLER, Link, SMI_HANDLER_SIGNATURE);
- Size += sizeof (SMM_CORE_SMI_HANDLER_STRUCTURE) + GET_OCCUPIED_SIZE (SmiHandler->ContextSize, sizeof (UINT64));
- }
-
- return Size;
-}
-
-/**
- return all SMI handler database size on the SMI entry list.
-
- @param SmiEntryList a list of SMI entry.
-
- @return all SMI handler database size on the SMI entry list.
-**/
-UINTN
-GetSmmSmiDatabaseSize (
- IN LIST_ENTRY *SmiEntryList
- )
-{
- LIST_ENTRY *ListEntry;
- SMI_ENTRY *SmiEntry;
- UINTN Size;
-
- Size = 0;
- ListEntry = SmiEntryList;
- for (ListEntry = ListEntry->ForwardLink;
- ListEntry != SmiEntryList;
- ListEntry = ListEntry->ForwardLink)
- {
- SmiEntry = CR (ListEntry, SMI_ENTRY, AllEntries, SMI_ENTRY_SIGNATURE);
- Size += sizeof (SMM_CORE_SMI_DATABASE_STRUCTURE);
- Size += GetSmmSmiHandlerSizeOnSmiEntry (SmiEntry);
- }
-
- return Size;
-}
-
-/**
- return SMI handler profile database size.
-
- @return SMI handler profile database size.
-**/
-UINTN
-GetSmiHandlerProfileDatabaseSize (
- VOID
- )
-{
- mSmmImageDatabaseSize = GetSmmImageDatabaseSize ();
- mSmmRootSmiDatabaseSize = GetSmmSmiDatabaseSize (mSmmCoreRootSmiEntryList);
- mSmmSmiDatabaseSize = GetSmmSmiDatabaseSize (mSmmCoreSmiEntryList);
- mSmmHardwareSmiDatabaseSize = GetSmmSmiDatabaseSize (mSmmCoreHardwareSmiEntryList);
-
- return mSmmImageDatabaseSize + mSmmSmiDatabaseSize + mSmmRootSmiDatabaseSize + mSmmHardwareSmiDatabaseSize;
-}
-
-/**
- get SMM image database.
-
- @param Data The buffer to hold SMM image database
- @param ExpectedSize The expected size of the SMM image database
-
- @return SMM image data base size.
-**/
-UINTN
-GetSmmImageDatabaseData (
- IN OUT VOID *Data,
- IN UINTN ExpectedSize
- )
-{
- SMM_CORE_IMAGE_DATABASE_STRUCTURE *ImageStruct;
- UINTN Size;
- UINTN Index;
-
- ImageStruct = Data;
- Size = 0;
- for (Index = 0; Index < mImageStructCount; Index++) {
- if (Size >= ExpectedSize) {
- return 0;
- }
-
- if (sizeof (SMM_CORE_IMAGE_DATABASE_STRUCTURE) + GET_OCCUPIED_SIZE (mImageStruct[Index].PdbStringSize, sizeof (UINT64)) > ExpectedSize - Size) {
- return 0;
- }
-
- ImageStruct->Header.Signature = SMM_CORE_IMAGE_DATABASE_SIGNATURE;
- ImageStruct->Header.Length = (UINT32)(sizeof (SMM_CORE_IMAGE_DATABASE_STRUCTURE) + GET_OCCUPIED_SIZE (mImageStruct[Index].PdbStringSize, sizeof (UINT64)));
- ImageStruct->Header.Revision = SMM_CORE_IMAGE_DATABASE_REVISION;
- CopyGuid (&ImageStruct->FileGuid, &mImageStruct[Index].FileGuid);
- ImageStruct->ImageRef = mImageStruct[Index].ImageRef;
- ImageStruct->EntryPoint = mImageStruct[Index].EntryPoint;
- ImageStruct->ImageBase = mImageStruct[Index].ImageBase;
- ImageStruct->ImageSize = mImageStruct[Index].ImageSize;
- if (mImageStruct[Index].PdbStringSize != 0) {
- ImageStruct->PdbStringOffset = sizeof (SMM_CORE_IMAGE_DATABASE_STRUCTURE);
- CopyMem ((VOID *)((UINTN)ImageStruct + ImageStruct->PdbStringOffset), mImageStruct[Index].PdbString, mImageStruct[Index].PdbStringSize);
- } else {
- ImageStruct->PdbStringOffset = 0;
- }
-
- ImageStruct = (SMM_CORE_IMAGE_DATABASE_STRUCTURE *)((UINTN)ImageStruct + ImageStruct->Header.Length);
- Size += sizeof (SMM_CORE_IMAGE_DATABASE_STRUCTURE) + GET_OCCUPIED_SIZE (mImageStruct[Index].PdbStringSize, sizeof (UINT64));
- }
-
- if (ExpectedSize != Size) {
- return 0;
- }
-
- return Size;
-}
-
-/**
- get all SMI handler data associated with SmiEntry.
-
- @param SmiEntry SMI entry.
- @param Data The buffer to hold all SMI handler data
- @param MaxSize The max size of the SMM image database
- @param Count The count of the SMI handler.
-
- @return SMM image data base size.
-**/
-UINTN
-GetSmmSmiHandlerDataOnSmiEntry (
- IN SMI_ENTRY *SmiEntry,
- IN OUT VOID *Data,
- IN UINTN MaxSize,
- OUT UINT32 *Count
- )
-{
- SMM_CORE_SMI_HANDLER_STRUCTURE *SmiHandlerStruct;
- LIST_ENTRY *ListEntry;
- SMI_HANDLER *SmiHandler;
- UINTN Size;
-
- SmiHandlerStruct = Data;
- Size = 0;
- *Count = 0;
- ListEntry = &SmiEntry->SmiHandlers;
- for (ListEntry = ListEntry->ForwardLink;
- ListEntry != &SmiEntry->SmiHandlers;
- ListEntry = ListEntry->ForwardLink)
- {
- SmiHandler = CR (ListEntry, SMI_HANDLER, Link, SMI_HANDLER_SIGNATURE);
- if (Size >= MaxSize) {
- *Count = 0;
- return 0;
- }
-
- if (sizeof (SMM_CORE_SMI_HANDLER_STRUCTURE) + GET_OCCUPIED_SIZE (SmiHandler->ContextSize, sizeof (UINT64)) > MaxSize - Size) {
- *Count = 0;
- return 0;
- }
-
- SmiHandlerStruct->Length = (UINT32)(sizeof (SMM_CORE_SMI_HANDLER_STRUCTURE) + GET_OCCUPIED_SIZE (SmiHandler->ContextSize, sizeof (UINT64)));
- SmiHandlerStruct->CallerAddr = (UINTN)SmiHandler->CallerAddr;
- SmiHandlerStruct->Handler = (UINTN)SmiHandler->Handler;
- SmiHandlerStruct->ImageRef = AddressToImageRef ((UINTN)SmiHandler->Handler);
- SmiHandlerStruct->ContextBufferSize = (UINT32)SmiHandler->ContextSize;
- if (SmiHandler->ContextSize != 0) {
- SmiHandlerStruct->ContextBufferOffset = sizeof (SMM_CORE_SMI_HANDLER_STRUCTURE);
- CopyMem ((UINT8 *)SmiHandlerStruct + SmiHandlerStruct->ContextBufferOffset, SmiHandler->Context, SmiHandler->ContextSize);
- } else {
- SmiHandlerStruct->ContextBufferOffset = 0;
- }
-
- Size += sizeof (SMM_CORE_SMI_HANDLER_STRUCTURE) + GET_OCCUPIED_SIZE (SmiHandler->ContextSize, sizeof (UINT64));
- SmiHandlerStruct = (SMM_CORE_SMI_HANDLER_STRUCTURE *)((UINTN)SmiHandlerStruct + SmiHandlerStruct->Length);
- *Count = *Count + 1;
- }
-
- return Size;
-}
-
-/**
- get all SMI handler database on the SMI entry list.
-
- @param SmiEntryList a list of SMI entry.
- @param HandlerCategory The handler category
- @param Data The buffer to hold all SMI handler database
- @param ExpectedSize The expected size of the SMM image database
-
- @return all SMI database size on the SMI entry list.
-**/
-UINTN
-GetSmmSmiDatabaseData (
- IN LIST_ENTRY *SmiEntryList,
- IN UINT32 HandlerCategory,
- IN OUT VOID *Data,
- IN UINTN ExpectedSize
- )
-{
- SMM_CORE_SMI_DATABASE_STRUCTURE *SmiStruct;
- LIST_ENTRY *ListEntry;
- SMI_ENTRY *SmiEntry;
- UINTN Size;
- UINTN SmiHandlerSize;
- UINT32 SmiHandlerCount;
-
- SmiStruct = Data;
- Size = 0;
- ListEntry = SmiEntryList;
- for (ListEntry = ListEntry->ForwardLink;
- ListEntry != SmiEntryList;
- ListEntry = ListEntry->ForwardLink)
- {
- SmiEntry = CR (ListEntry, SMI_ENTRY, AllEntries, SMI_ENTRY_SIGNATURE);
- if (Size >= ExpectedSize) {
- return 0;
- }
-
- if (sizeof (SMM_CORE_SMI_DATABASE_STRUCTURE) > ExpectedSize - Size) {
- return 0;
- }
-
- SmiStruct->Header.Signature = SMM_CORE_SMI_DATABASE_SIGNATURE;
- SmiStruct->Header.Length = sizeof (SMM_CORE_SMI_DATABASE_STRUCTURE);
- SmiStruct->Header.Revision = SMM_CORE_SMI_DATABASE_REVISION;
- SmiStruct->HandlerCategory = HandlerCategory;
- CopyGuid (&SmiStruct->HandlerType, &SmiEntry->HandlerType);
- Size += sizeof (SMM_CORE_SMI_DATABASE_STRUCTURE);
- SmiHandlerSize = GetSmmSmiHandlerDataOnSmiEntry (SmiEntry, (UINT8 *)SmiStruct + SmiStruct->Header.Length, ExpectedSize - Size, &SmiHandlerCount);
- SmiStruct->HandlerCount = SmiHandlerCount;
- Size += SmiHandlerSize;
- SmiStruct->Header.Length += (UINT32)SmiHandlerSize;
- SmiStruct = (VOID *)((UINTN)SmiStruct + SmiStruct->Header.Length);
- }
-
- if (ExpectedSize != Size) {
- return 0;
- }
-
- return Size;
-}
-
-/**
- Get SMI handler profile database.
-
- @param Data the buffer to hold SMI handler profile database
-
- @retval EFI_SUCCESS the database is got.
- @retval EFI_INVALID_PARAMETER the database size mismatch.
-**/
-EFI_STATUS
-GetSmiHandlerProfileDatabaseData (
- IN OUT VOID *Data
- )
-{
- UINTN SmmImageDatabaseSize;
- UINTN SmmSmiDatabaseSize;
- UINTN SmmRootSmiDatabaseSize;
- UINTN SmmHardwareSmiDatabaseSize;
-
- DEBUG ((DEBUG_VERBOSE, "GetSmiHandlerProfileDatabaseData\n"));
- SmmImageDatabaseSize = GetSmmImageDatabaseData (Data, mSmmImageDatabaseSize);
- if (SmmImageDatabaseSize != mSmmImageDatabaseSize) {
- DEBUG ((DEBUG_ERROR, "GetSmiHandlerProfileDatabaseData - SmmImageDatabaseSize mismatch!\n"));
- return EFI_INVALID_PARAMETER;
- }
-
- SmmRootSmiDatabaseSize = GetSmmSmiDatabaseData (mSmmCoreRootSmiEntryList, SmmCoreSmiHandlerCategoryRootHandler, (UINT8 *)Data + SmmImageDatabaseSize, mSmmRootSmiDatabaseSize);
- if (SmmRootSmiDatabaseSize != mSmmRootSmiDatabaseSize) {
- DEBUG ((DEBUG_ERROR, "GetSmiHandlerProfileDatabaseData - SmmRootSmiDatabaseSize mismatch!\n"));
- return EFI_INVALID_PARAMETER;
- }
-
- SmmSmiDatabaseSize = GetSmmSmiDatabaseData (mSmmCoreSmiEntryList, SmmCoreSmiHandlerCategoryGuidHandler, (UINT8 *)Data + SmmImageDatabaseSize + mSmmRootSmiDatabaseSize, mSmmSmiDatabaseSize);
- if (SmmSmiDatabaseSize != mSmmSmiDatabaseSize) {
- DEBUG ((DEBUG_ERROR, "GetSmiHandlerProfileDatabaseData - SmmSmiDatabaseSize mismatch!\n"));
- return EFI_INVALID_PARAMETER;
- }
-
- SmmHardwareSmiDatabaseSize = GetSmmSmiDatabaseData (mSmmCoreHardwareSmiEntryList, SmmCoreSmiHandlerCategoryHardwareHandler, (UINT8 *)Data + SmmImageDatabaseSize + SmmRootSmiDatabaseSize + SmmSmiDatabaseSize, mSmmHardwareSmiDatabaseSize);
- if (SmmHardwareSmiDatabaseSize != mSmmHardwareSmiDatabaseSize) {
- DEBUG ((DEBUG_ERROR, "GetSmiHandlerProfileDatabaseData - SmmHardwareSmiDatabaseSize mismatch!\n"));
- return EFI_INVALID_PARAMETER;
- }
-
- return EFI_SUCCESS;
-}
-
-/**
- build SMI handler profile database.
-**/
-VOID
-BuildSmiHandlerProfileDatabase (
- VOID
- )
-{
- EFI_STATUS Status;
-
- mSmiHandlerProfileDatabaseSize = GetSmiHandlerProfileDatabaseSize ();
- mSmiHandlerProfileDatabase = AllocatePool (mSmiHandlerProfileDatabaseSize);
- if (mSmiHandlerProfileDatabase == NULL) {
- return;
- }
-
- Status = GetSmiHandlerProfileDatabaseData (mSmiHandlerProfileDatabase);
- if (EFI_ERROR (Status)) {
- FreePool (mSmiHandlerProfileDatabase);
- mSmiHandlerProfileDatabase = NULL;
- }
-}
-
-/**
- Copy SMI handler profile data.
-
- @param DataBuffer The buffer to hold SMI handler profile data.
- @param DataSize On input, data buffer size.
- On output, actual data buffer size copied.
- @param DataOffset On input, data buffer offset to copy.
- On output, next time data buffer offset to copy.
-
-**/
-VOID
-SmiHandlerProfileCopyData (
- OUT VOID *DataBuffer,
- IN OUT UINT64 *DataSize,
- IN OUT UINT64 *DataOffset
- )
-{
- if (*DataOffset >= mSmiHandlerProfileDatabaseSize) {
- *DataOffset = mSmiHandlerProfileDatabaseSize;
- return;
- }
-
- if (mSmiHandlerProfileDatabaseSize - *DataOffset < *DataSize) {
- *DataSize = mSmiHandlerProfileDatabaseSize - *DataOffset;
- }
-
- CopyMem (
- DataBuffer,
- (UINT8 *)mSmiHandlerProfileDatabase + *DataOffset,
- (UINTN)*DataSize
- );
- *DataOffset = *DataOffset + *DataSize;
-}
-
-/**
- SMI handler profile handler to get info.
-
- @param SmiHandlerProfileParameterGetInfo The parameter of SMI handler profile get info.
-
-**/
-VOID
-SmiHandlerProfileHandlerGetInfo (
- IN SMI_HANDLER_PROFILE_PARAMETER_GET_INFO *SmiHandlerProfileParameterGetInfo
- )
-{
- BOOLEAN SmiHandlerProfileRecordingStatus;
-
- SmiHandlerProfileRecordingStatus = mSmiHandlerProfileRecordingStatus;
- mSmiHandlerProfileRecordingStatus = FALSE;
-
- SmiHandlerProfileParameterGetInfo->DataSize = mSmiHandlerProfileDatabaseSize;
- SmiHandlerProfileParameterGetInfo->Header.ReturnStatus = 0;
-
- mSmiHandlerProfileRecordingStatus = SmiHandlerProfileRecordingStatus;
-}
-
-/**
- SMI handler profile handler to get data by offset.
-
- @param SmiHandlerProfileParameterGetDataByOffset The parameter of SMI handler profile get data by offset.
-
-**/
-VOID
-SmiHandlerProfileHandlerGetDataByOffset (
- IN SMI_HANDLER_PROFILE_PARAMETER_GET_DATA_BY_OFFSET *SmiHandlerProfileParameterGetDataByOffset
- )
-{
- SMI_HANDLER_PROFILE_PARAMETER_GET_DATA_BY_OFFSET SmiHandlerProfileGetDataByOffset;
- BOOLEAN SmiHandlerProfileRecordingStatus;
-
- SmiHandlerProfileRecordingStatus = mSmiHandlerProfileRecordingStatus;
- mSmiHandlerProfileRecordingStatus = FALSE;
-
- CopyMem (&SmiHandlerProfileGetDataByOffset, SmiHandlerProfileParameterGetDataByOffset, sizeof (SmiHandlerProfileGetDataByOffset));
-
- //
- // Sanity check
- //
- if (!SmmIsBufferOutsideSmmValid ((UINTN)SmiHandlerProfileGetDataByOffset.DataBuffer, (UINTN)SmiHandlerProfileGetDataByOffset.DataSize)) {
- DEBUG ((DEBUG_ERROR, "SmiHandlerProfileHandlerGetDataByOffset: SMI handler profile get data in SMRAM or overflow!\n"));
- SmiHandlerProfileParameterGetDataByOffset->Header.ReturnStatus = (UINT64)(INT64)(INTN)EFI_ACCESS_DENIED;
- goto Done;
- }
-
- SmiHandlerProfileCopyData ((VOID *)(UINTN)SmiHandlerProfileGetDataByOffset.DataBuffer, &SmiHandlerProfileGetDataByOffset.DataSize, &SmiHandlerProfileGetDataByOffset.DataOffset);
- CopyMem (SmiHandlerProfileParameterGetDataByOffset, &SmiHandlerProfileGetDataByOffset, sizeof (SmiHandlerProfileGetDataByOffset));
- SmiHandlerProfileParameterGetDataByOffset->Header.ReturnStatus = 0;
-
-Done:
- mSmiHandlerProfileRecordingStatus = SmiHandlerProfileRecordingStatus;
-}
-
-/**
- Dispatch function for a Software SMI handler.
-
- Caution: This function may receive untrusted input.
- Communicate buffer and buffer size are external input, so this function will do basic validation.
-
- @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-SMM environment into an SMM environment.
- @param CommBufferSize The size of the CommBuffer.
-
- @retval EFI_SUCCESS Command is handled successfully.
-**/
-EFI_STATUS
-EFIAPI
-SmiHandlerProfileHandler (
- IN EFI_HANDLE DispatchHandle,
- IN CONST VOID *Context OPTIONAL,
- IN OUT VOID *CommBuffer OPTIONAL,
- IN OUT UINTN *CommBufferSize OPTIONAL
- )
-{
- SMI_HANDLER_PROFILE_PARAMETER_HEADER *SmiHandlerProfileParameterHeader;
- UINTN TempCommBufferSize;
-
- DEBUG ((DEBUG_ERROR, "SmiHandlerProfileHandler Enter\n"));
-
- if (mSmiHandlerProfileDatabase == NULL) {
- return EFI_SUCCESS;
- }
-
- //
- // If input is invalid, stop processing this SMI
- //
- if ((CommBuffer == NULL) || (CommBufferSize == NULL)) {
- return EFI_SUCCESS;
- }
-
- TempCommBufferSize = *CommBufferSize;
-
- if (TempCommBufferSize < sizeof (SMI_HANDLER_PROFILE_PARAMETER_HEADER)) {
- DEBUG ((DEBUG_ERROR, "SmiHandlerProfileHandler: SMM communication buffer size invalid!\n"));
- return EFI_SUCCESS;
- }
-
- if (!SmmIsBufferOutsideSmmValid ((UINTN)CommBuffer, TempCommBufferSize)) {
- DEBUG ((DEBUG_ERROR, "SmiHandlerProfileHandler: SMM communication buffer in SMRAM or overflow!\n"));
- return EFI_SUCCESS;
- }
-
- SmiHandlerProfileParameterHeader = (SMI_HANDLER_PROFILE_PARAMETER_HEADER *)((UINTN)CommBuffer);
- SmiHandlerProfileParameterHeader->ReturnStatus = (UINT64)-1;
-
- switch (SmiHandlerProfileParameterHeader->Command) {
- case SMI_HANDLER_PROFILE_COMMAND_GET_INFO:
- DEBUG ((DEBUG_ERROR, "SmiHandlerProfileHandlerGetInfo\n"));
- if (TempCommBufferSize != sizeof (SMI_HANDLER_PROFILE_PARAMETER_GET_INFO)) {
- DEBUG ((DEBUG_ERROR, "SmiHandlerProfileHandler: SMM communication buffer size invalid!\n"));
- return EFI_SUCCESS;
- }
-
- SmiHandlerProfileHandlerGetInfo ((SMI_HANDLER_PROFILE_PARAMETER_GET_INFO *)(UINTN)CommBuffer);
- break;
- case SMI_HANDLER_PROFILE_COMMAND_GET_DATA_BY_OFFSET:
- DEBUG ((DEBUG_ERROR, "SmiHandlerProfileHandlerGetDataByOffset\n"));
- if (TempCommBufferSize != sizeof (SMI_HANDLER_PROFILE_PARAMETER_GET_DATA_BY_OFFSET)) {
- DEBUG ((DEBUG_ERROR, "SmiHandlerProfileHandler: SMM communication buffer size invalid!\n"));
- return EFI_SUCCESS;
- }
-
- SmiHandlerProfileHandlerGetDataByOffset ((SMI_HANDLER_PROFILE_PARAMETER_GET_DATA_BY_OFFSET *)(UINTN)CommBuffer);
- break;
- default:
- break;
- }
-
- DEBUG ((DEBUG_ERROR, "SmiHandlerProfileHandler Exit\n"));
-
- return EFI_SUCCESS;
-}
-
-/**
- Register SMI handler profile handler.
-**/
-VOID
-RegisterSmiHandlerProfileHandler (
- VOID
- )
-{
- EFI_STATUS Status;
- EFI_HANDLE DispatchHandle;
-
- Status = gSmst->SmiHandlerRegister (
- SmiHandlerProfileHandler,
- &gSmiHandlerProfileGuid,
- &DispatchHandle
- );
- ASSERT_EFI_ERROR (Status);
-
- BuildSmiHandlerProfileDatabase ();
-}
-
-/**
- Finds the SMI entry for the requested handler type.
-
- @param HandlerType The type of the interrupt
- @param Create Create a new entry if not found
-
- @return SMI entry
-**/
-SMI_ENTRY *
-SmmCoreFindHardwareSmiEntry (
- IN EFI_GUID *HandlerType,
- IN BOOLEAN Create
- )
-{
- LIST_ENTRY *Link;
- SMI_ENTRY *Item;
- SMI_ENTRY *SmiEntry;
-
- //
- // Search the SMI entry list for the matching GUID
- //
- SmiEntry = NULL;
- for (Link = mHardwareSmiEntryList.ForwardLink;
- Link != &mHardwareSmiEntryList;
- Link = Link->ForwardLink)
- {
- Item = CR (Link, SMI_ENTRY, AllEntries, SMI_ENTRY_SIGNATURE);
- if (CompareGuid (&Item->HandlerType, HandlerType)) {
- //
- // This is the SMI entry
- //
- SmiEntry = Item;
- break;
- }
- }
-
- //
- // If the protocol entry was not found and Create is TRUE, then
- // allocate a new entry
- //
- if ((SmiEntry == NULL) && Create) {
- SmiEntry = AllocatePool (sizeof (SMI_ENTRY));
- if (SmiEntry != NULL) {
- //
- // Initialize new SMI entry structure
- //
- SmiEntry->Signature = SMI_ENTRY_SIGNATURE;
- CopyGuid ((VOID *)&SmiEntry->HandlerType, HandlerType);
- InitializeListHead (&SmiEntry->SmiHandlers);
-
- //
- // Add it to SMI entry list
- //
- InsertTailList (&mHardwareSmiEntryList, &SmiEntry->AllEntries);
- }
- }
-
- return SmiEntry;
-}
-
-/**
- Convert EFI_SMM_USB_REGISTER_CONTEXT to SMI_HANDLER_PROFILE_USB_REGISTER_CONTEXT.
-
- @param UsbContext A pointer to EFI_SMM_USB_REGISTER_CONTEXT
- @param UsbContextSize The size of EFI_SMM_USB_REGISTER_CONTEXT in bytes
- @param SmiHandlerUsbContextSize The size of SMI_HANDLER_PROFILE_USB_REGISTER_CONTEXT in bytes
-
- @return SmiHandlerUsbContext A pointer to SMI_HANDLER_PROFILE_USB_REGISTER_CONTEXT
-**/
-SMI_HANDLER_PROFILE_USB_REGISTER_CONTEXT *
-ConvertSmiHandlerUsbContext (
- IN EFI_SMM_USB_REGISTER_CONTEXT *UsbContext,
- IN UINTN UsbContextSize,
- OUT UINTN *SmiHandlerUsbContextSize
- )
-{
- UINTN DevicePathSize;
- SMI_HANDLER_PROFILE_USB_REGISTER_CONTEXT *SmiHandlerUsbContext;
-
- ASSERT (UsbContextSize == sizeof (EFI_SMM_USB_REGISTER_CONTEXT));
-
- DevicePathSize = GetDevicePathSize (UsbContext->Device);
- SmiHandlerUsbContext = AllocatePool (sizeof (SMI_HANDLER_PROFILE_USB_REGISTER_CONTEXT) + DevicePathSize);
- if (SmiHandlerUsbContext == NULL) {
- *SmiHandlerUsbContextSize = 0;
- return NULL;
- }
-
- SmiHandlerUsbContext->Type = UsbContext->Type;
- SmiHandlerUsbContext->DevicePathSize = (UINT32)DevicePathSize;
- CopyMem (SmiHandlerUsbContext + 1, UsbContext->Device, DevicePathSize);
- *SmiHandlerUsbContextSize = sizeof (SMI_HANDLER_PROFILE_USB_REGISTER_CONTEXT) + DevicePathSize;
- return SmiHandlerUsbContext;
-}
-
-/**
- Convert EFI_SMM_SW_REGISTER_CONTEXT to SMI_HANDLER_PROFILE_SW_REGISTER_CONTEXT.
-
- @param SwContext A pointer to EFI_SMM_SW_REGISTER_CONTEXT
- @param SwContextSize The size of EFI_SMM_SW_REGISTER_CONTEXT in bytes
- @param SmiHandlerSwContextSize The size of SMI_HANDLER_PROFILE_SW_REGISTER_CONTEXT in bytes
-
- @return SmiHandlerSwContext A pointer to SMI_HANDLER_PROFILE_SW_REGISTER_CONTEXT
-**/
-SMI_HANDLER_PROFILE_SW_REGISTER_CONTEXT *
-ConvertSmiHandlerSwContext (
- IN EFI_SMM_SW_REGISTER_CONTEXT *SwContext,
- IN UINTN SwContextSize,
- OUT UINTN *SmiHandlerSwContextSize
- )
-{
- SMI_HANDLER_PROFILE_SW_REGISTER_CONTEXT *SmiHandlerSwContext;
-
- ASSERT (SwContextSize == sizeof (EFI_SMM_SW_REGISTER_CONTEXT));
-
- SmiHandlerSwContext = AllocatePool (sizeof (SMI_HANDLER_PROFILE_SW_REGISTER_CONTEXT));
- if (SmiHandlerSwContext == NULL) {
- *SmiHandlerSwContextSize = 0;
- return NULL;
- }
-
- SmiHandlerSwContext->SwSmiInputValue = SwContext->SwSmiInputValue;
- *SmiHandlerSwContextSize = sizeof (SMI_HANDLER_PROFILE_SW_REGISTER_CONTEXT);
- return SmiHandlerSwContext;
-}
-
-/**
- This function is called by SmmChildDispatcher module to report
- a new SMI handler is registered, to SmmCore.
-
- @param This The protocol instance
- @param HandlerGuid The GUID to identify the type of the handler.
- For the SmmChildDispatch protocol, the HandlerGuid
- must be the GUID of SmmChildDispatch protocol.
- @param Handler The SMI handler.
- @param CallerAddress The address of the module who registers the SMI handler.
- @param Context The context of the SMI handler.
- For the SmmChildDispatch protocol, the Context
- must match the one defined for SmmChildDispatch protocol.
- @param ContextSize The size of the context in bytes.
- For the SmmChildDispatch protocol, the Context
- must match the one defined for SmmChildDispatch protocol.
-
- @retval EFI_SUCCESS The information is recorded.
- @retval EFI_OUT_OF_RESOURCES There is no enough resource to record the information.
-**/
-EFI_STATUS
-EFIAPI
-SmiHandlerProfileRegisterHandler (
- IN SMI_HANDLER_PROFILE_PROTOCOL *This,
- IN EFI_GUID *HandlerGuid,
- IN EFI_SMM_HANDLER_ENTRY_POINT2 Handler,
- IN PHYSICAL_ADDRESS CallerAddress,
- IN VOID *Context OPTIONAL,
- IN UINTN ContextSize OPTIONAL
- )
-{
- SMI_HANDLER *SmiHandler;
- SMI_ENTRY *SmiEntry;
- LIST_ENTRY *List;
-
- if (((ContextSize == 0) && (Context != NULL)) ||
- ((ContextSize != 0) && (Context == NULL)))
- {
- return EFI_INVALID_PARAMETER;
- }
-
- SmiHandler = AllocateZeroPool (sizeof (SMI_HANDLER));
- if (SmiHandler == NULL) {
- return EFI_OUT_OF_RESOURCES;
- }
-
- SmiHandler->Signature = SMI_HANDLER_SIGNATURE;
- SmiHandler->Handler = Handler;
- SmiHandler->CallerAddr = (UINTN)CallerAddress;
- SmiHandler->Context = Context;
- SmiHandler->ContextSize = ContextSize;
-
- if (Context != NULL) {
- if (CompareGuid (HandlerGuid, &gEfiSmmUsbDispatch2ProtocolGuid)) {
- SmiHandler->Context = ConvertSmiHandlerUsbContext (Context, ContextSize, &SmiHandler->ContextSize);
- } else if (CompareGuid (HandlerGuid, &gEfiSmmSwDispatch2ProtocolGuid)) {
- SmiHandler->Context = ConvertSmiHandlerSwContext (Context, ContextSize, &SmiHandler->ContextSize);
- } else {
- SmiHandler->Context = AllocateCopyPool (ContextSize, Context);
- }
- }
-
- if (SmiHandler->Context == NULL) {
- SmiHandler->ContextSize = 0;
- }
-
- SmiEntry = SmmCoreFindHardwareSmiEntry (HandlerGuid, TRUE);
- if (SmiEntry == NULL) {
- if (SmiHandler->Context != NULL) {
- FreePool (SmiHandler->Context);
- }
-
- FreePool (SmiHandler);
- return EFI_OUT_OF_RESOURCES;
- }
-
- List = &SmiEntry->SmiHandlers;
-
- SmiHandler->SmiEntry = SmiEntry;
- InsertTailList (List, &SmiHandler->Link);
-
- return EFI_SUCCESS;
-}
-
-/**
- This function is called by SmmChildDispatcher module to report
- an existing SMI handler is unregistered, to SmmCore.
-
- @param This The protocol instance
- @param HandlerGuid The GUID to identify the type of the handler.
- For the SmmChildDispatch protocol, the HandlerGuid
- must be the GUID of SmmChildDispatch protocol.
- @param Handler The SMI handler.
- @param Context The context of the SMI handler.
- If it is NOT NULL, it will be used to check what is registered.
- @param ContextSize The size of the context in bytes.
- If Context is NOT NULL, it will be used to check what is registered.
-
- @retval EFI_SUCCESS The original record is removed.
- @retval EFI_NOT_FOUND There is no record for the HandlerGuid and handler.
-**/
-EFI_STATUS
-EFIAPI
-SmiHandlerProfileUnregisterHandler (
- IN SMI_HANDLER_PROFILE_PROTOCOL *This,
- IN EFI_GUID *HandlerGuid,
- IN EFI_SMM_HANDLER_ENTRY_POINT2 Handler,
- IN VOID *Context OPTIONAL,
- IN UINTN ContextSize OPTIONAL
- )
-{
- LIST_ENTRY *Link;
- LIST_ENTRY *Head;
- SMI_HANDLER *SmiHandler;
- SMI_ENTRY *SmiEntry;
- SMI_HANDLER *TargetSmiHandler;
- VOID *SearchContext;
- UINTN SearchContextSize;
-
- if (((ContextSize == 0) && (Context != NULL)) ||
- ((ContextSize != 0) && (Context == NULL)))
- {
- return EFI_INVALID_PARAMETER;
- }
-
- SmiEntry = SmmCoreFindHardwareSmiEntry (HandlerGuid, FALSE);
- if (SmiEntry == NULL) {
- return EFI_NOT_FOUND;
- }
-
- SearchContext = Context;
- SearchContextSize = ContextSize;
- if (Context != NULL) {
- if (CompareGuid (HandlerGuid, &gEfiSmmUsbDispatch2ProtocolGuid)) {
- SearchContext = ConvertSmiHandlerUsbContext (Context, ContextSize, &SearchContextSize);
- } else if (CompareGuid (HandlerGuid, &gEfiSmmSwDispatch2ProtocolGuid)) {
- SearchContext = ConvertSmiHandlerSwContext (Context, ContextSize, &SearchContextSize);
- }
- }
-
- TargetSmiHandler = NULL;
- Head = &SmiEntry->SmiHandlers;
- for (Link = Head->ForwardLink; Link != Head; Link = Link->ForwardLink) {
- SmiHandler = CR (Link, SMI_HANDLER, Link, SMI_HANDLER_SIGNATURE);
- if (SmiHandler->Handler == Handler) {
- if ((SearchContext == NULL) ||
- ((SearchContextSize == SmiHandler->ContextSize) && (CompareMem (SearchContext, SmiHandler->Context, SearchContextSize) == 0)))
- {
- TargetSmiHandler = SmiHandler;
- break;
- }
- }
- }
-
- if (SearchContext != NULL) {
- if (CompareGuid (HandlerGuid, &gEfiSmmUsbDispatch2ProtocolGuid)) {
- FreePool (SearchContext);
- }
- }
-
- if (TargetSmiHandler == NULL) {
- return EFI_NOT_FOUND;
- }
-
- SmiHandler = TargetSmiHandler;
-
- RemoveEntryList (&SmiHandler->Link);
- if (SmiHandler->Context != NULL) {
- FreePool (SmiHandler->Context);
- }
-
- FreePool (SmiHandler);
-
- if (IsListEmpty (&SmiEntry->SmiHandlers)) {
- RemoveEntryList (&SmiEntry->AllEntries);
- FreePool (SmiEntry);
- }
-
- return EFI_SUCCESS;
-}
-
-/**
- Initialize SmiHandler profile feature.
-**/
-VOID
-SmmCoreInitializeSmiHandlerProfile (
- VOID
- )
-{
- EFI_STATUS Status;
- VOID *Registration;
- EFI_HANDLE Handle;
-
- if ((PcdGet8 (PcdSmiHandlerProfilePropertyMask) & 0x1) != 0) {
- InsertTailList (&mRootSmiEntryList, &mRootSmiEntry.AllEntries);
-
- Status = gSmst->SmmRegisterProtocolNotify (
- &gEfiSmmReadyToLockProtocolGuid,
- SmmReadyToLockInSmiHandlerProfile,
- &Registration
- );
- ASSERT_EFI_ERROR (Status);
-
- Handle = NULL;
- Status = gSmst->SmmInstallProtocolInterface (
- &Handle,
- &gSmiHandlerProfileGuid,
- EFI_NATIVE_INTERFACE,
- &mSmiHandlerProfile
- );
- ASSERT_EFI_ERROR (Status);
- }
-}
+/** @file + SMI handler profile support. + +Copyright (c) 2017, Intel Corporation. All rights reserved.<BR> +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include <PiSmm.h> +#include <Library/BaseLib.h> +#include <Library/BaseMemoryLib.h> +#include <Library/MemoryAllocationLib.h> +#include <Library/UefiBootServicesTableLib.h> +#include <Library/SmmServicesTableLib.h> +#include <Library/DebugLib.h> +#include <Library/PrintLib.h> +#include <Library/UefiLib.h> +#include <Library/DevicePathLib.h> +#include <Library/PeCoffGetEntryPointLib.h> +#include <Protocol/LoadedImage.h> +#include <Protocol/SmmAccess2.h> +#include <Protocol/SmmReadyToLock.h> +#include <Protocol/SmmEndOfDxe.h> + +#include <Guid/SmiHandlerProfile.h> + +#include "PiSmmCore.h" + +#define GET_OCCUPIED_SIZE(ActualSize, Alignment) \ + ((ActualSize) + (((Alignment) - ((ActualSize) & ((Alignment) - 1))) & ((Alignment) - 1))) + +typedef struct { + EFI_GUID FileGuid; + PHYSICAL_ADDRESS EntryPoint; + PHYSICAL_ADDRESS ImageBase; + UINT64 ImageSize; + UINT32 ImageRef; + UINT16 PdbStringSize; + CHAR8 *PdbString; +} IMAGE_STRUCT; + +/** + Register SMI handler profile handler. +**/ +VOID +RegisterSmiHandlerProfileHandler ( + VOID + ); + +/** + Retrieves and returns a pointer to the entry point to a PE/COFF image that has been loaded + into system memory with the PE/COFF Loader Library functions. + + Retrieves the entry point to the PE/COFF image specified by Pe32Data and returns this entry + point in EntryPoint. If the entry point could not be retrieved from the PE/COFF image, then + return RETURN_INVALID_PARAMETER. Otherwise return RETURN_SUCCESS. + If Pe32Data is NULL, then ASSERT(). + If EntryPoint is NULL, then ASSERT(). + + @param Pe32Data The pointer to the PE/COFF image that is loaded in system memory. + @param EntryPoint The pointer to entry point to the PE/COFF image to return. + + @retval RETURN_SUCCESS EntryPoint was returned. + @retval RETURN_INVALID_PARAMETER The entry point could not be found in the PE/COFF image. + +**/ +RETURN_STATUS +InternalPeCoffGetEntryPoint ( + IN VOID *Pe32Data, + OUT VOID **EntryPoint + ); + +extern LIST_ENTRY mSmiEntryList; +extern LIST_ENTRY mHardwareSmiEntryList; +extern SMI_ENTRY mRootSmiEntry; + +extern SMI_HANDLER_PROFILE_PROTOCOL mSmiHandlerProfile; + +GLOBAL_REMOVE_IF_UNREFERENCED LIST_ENTRY mHardwareSmiEntryList = INITIALIZE_LIST_HEAD_VARIABLE (mHardwareSmiEntryList); + +GLOBAL_REMOVE_IF_UNREFERENCED LIST_ENTRY mRootSmiEntryList = INITIALIZE_LIST_HEAD_VARIABLE (mRootSmiEntryList); + +GLOBAL_REMOVE_IF_UNREFERENCED LIST_ENTRY *mSmmCoreRootSmiEntryList = &mRootSmiEntryList; +GLOBAL_REMOVE_IF_UNREFERENCED LIST_ENTRY *mSmmCoreSmiEntryList = &mSmiEntryList; +GLOBAL_REMOVE_IF_UNREFERENCED LIST_ENTRY *mSmmCoreHardwareSmiEntryList = &mHardwareSmiEntryList; + +GLOBAL_REMOVE_IF_UNREFERENCED IMAGE_STRUCT *mImageStruct; +GLOBAL_REMOVE_IF_UNREFERENCED UINT32 mImageStructCountMax; +GLOBAL_REMOVE_IF_UNREFERENCED UINT32 mImageStructCount; + +GLOBAL_REMOVE_IF_UNREFERENCED VOID *mSmiHandlerProfileDatabase; +GLOBAL_REMOVE_IF_UNREFERENCED UINTN mSmiHandlerProfileDatabaseSize; + +GLOBAL_REMOVE_IF_UNREFERENCED UINTN mSmmImageDatabaseSize; +GLOBAL_REMOVE_IF_UNREFERENCED UINTN mSmmRootSmiDatabaseSize; +GLOBAL_REMOVE_IF_UNREFERENCED UINTN mSmmSmiDatabaseSize; +GLOBAL_REMOVE_IF_UNREFERENCED UINTN mSmmHardwareSmiDatabaseSize; + +GLOBAL_REMOVE_IF_UNREFERENCED BOOLEAN mSmiHandlerProfileRecordingStatus; + +GLOBAL_REMOVE_IF_UNREFERENCED SMI_HANDLER_PROFILE_PROTOCOL mSmiHandlerProfile = { + SmiHandlerProfileRegisterHandler, + SmiHandlerProfileUnregisterHandler, +}; + +/** + This function dump raw data. + + @param Data raw data + @param Size raw data size +**/ +VOID +InternalDumpData ( + IN UINT8 *Data, + IN UINTN Size + ) +{ + UINTN Index; + + for (Index = 0; Index < Size; Index++) { + DEBUG ((DEBUG_INFO, "%02x ", (UINTN)Data[Index])); + } +} + +/** + Get GUID name for an image. + + @param[in] LoadedImage LoadedImage protocol. + @param[out] Guid Guid of the FFS +**/ +VOID +GetDriverGuid ( + IN EFI_LOADED_IMAGE_PROTOCOL *LoadedImage, + OUT EFI_GUID *Guid + ) +{ + EFI_GUID *FileName; + + FileName = NULL; + if ((DevicePathType (LoadedImage->FilePath) == MEDIA_DEVICE_PATH) && + (DevicePathSubType (LoadedImage->FilePath) == MEDIA_PIWG_FW_FILE_DP)) + { + FileName = &((MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *)LoadedImage->FilePath)->FvFileName; + } + + if (FileName != NULL) { + CopyGuid (Guid, FileName); + } else { + ZeroMem (Guid, sizeof (EFI_GUID)); + } +} + +/** + Add image structure. + + @param ImageBase image base + @param ImageSize image size + @param EntryPoint image entry point + @param Guid FFS GUID of the image + @param PdbString image PDB string +**/ +VOID +AddImageStruct ( + IN PHYSICAL_ADDRESS ImageBase, + IN UINT64 ImageSize, + IN PHYSICAL_ADDRESS EntryPoint, + IN EFI_GUID *Guid, + IN CHAR8 *PdbString + ) +{ + UINTN PdbStringSize; + + if (mImageStructCount >= mImageStructCountMax) { + ASSERT (FALSE); + return; + } + + CopyGuid (&mImageStruct[mImageStructCount].FileGuid, Guid); + mImageStruct[mImageStructCount].ImageRef = mImageStructCount; + mImageStruct[mImageStructCount].ImageBase = ImageBase; + mImageStruct[mImageStructCount].ImageSize = ImageSize; + mImageStruct[mImageStructCount].EntryPoint = EntryPoint; + if (PdbString != NULL) { + PdbStringSize = AsciiStrSize (PdbString); + mImageStruct[mImageStructCount].PdbString = AllocateCopyPool (PdbStringSize, PdbString); + if (mImageStruct[mImageStructCount].PdbString != NULL) { + mImageStruct[mImageStructCount].PdbStringSize = (UINT16)PdbStringSize; + } + } + + mImageStructCount++; +} + +/** + return an image structure based upon image address. + + @param Address image address + + @return image structure +**/ +IMAGE_STRUCT * +AddressToImageStruct ( + IN UINTN Address + ) +{ + UINTN Index; + + for (Index = 0; Index < mImageStructCount; Index++) { + if ((Address >= mImageStruct[Index].ImageBase) && + (Address < mImageStruct[Index].ImageBase + mImageStruct[Index].ImageSize)) + { + return &mImageStruct[Index]; + } + } + + return NULL; +} + +/** + return an image reference index based upon image address. + + @param Address image address + + @return image reference index +**/ +UINT32 +AddressToImageRef ( + IN UINTN Address + ) +{ + IMAGE_STRUCT *ImageStruct; + + ImageStruct = AddressToImageStruct (Address); + if (ImageStruct != NULL) { + return ImageStruct->ImageRef; + } + + return (UINT32)-1; +} + +/** + Collect SMM image information based upon loaded image protocol. +**/ +VOID +GetSmmLoadedImage ( + VOID + ) +{ + EFI_STATUS Status; + UINTN NoHandles; + UINTN HandleBufferSize; + EFI_HANDLE *HandleBuffer; + UINTN Index; + EFI_LOADED_IMAGE_PROTOCOL *LoadedImage; + CHAR16 *PathStr; + EFI_SMM_DRIVER_ENTRY *LoadedImagePrivate; + PHYSICAL_ADDRESS EntryPoint; + VOID *EntryPointInImage; + EFI_GUID Guid; + CHAR8 *PdbString; + PHYSICAL_ADDRESS RealImageBase; + + HandleBufferSize = 0; + HandleBuffer = NULL; + Status = gSmst->SmmLocateHandle ( + ByProtocol, + &gEfiLoadedImageProtocolGuid, + NULL, + &HandleBufferSize, + HandleBuffer + ); + if (Status != EFI_BUFFER_TOO_SMALL) { + return; + } + + HandleBuffer = AllocateZeroPool (HandleBufferSize); + if (HandleBuffer == NULL) { + return; + } + + Status = gSmst->SmmLocateHandle ( + ByProtocol, + &gEfiLoadedImageProtocolGuid, + NULL, + &HandleBufferSize, + HandleBuffer + ); + if (EFI_ERROR (Status)) { + return; + } + + NoHandles = HandleBufferSize/sizeof (EFI_HANDLE); + mImageStructCountMax = (UINT32)NoHandles; + mImageStruct = AllocateZeroPool (mImageStructCountMax * sizeof (IMAGE_STRUCT)); + if (mImageStruct == NULL) { + goto Done; + } + + for (Index = 0; Index < NoHandles; Index++) { + Status = gSmst->SmmHandleProtocol ( + HandleBuffer[Index], + &gEfiLoadedImageProtocolGuid, + (VOID **)&LoadedImage + ); + if (EFI_ERROR (Status)) { + continue; + } + + PathStr = ConvertDevicePathToText (LoadedImage->FilePath, TRUE, TRUE); + GetDriverGuid (LoadedImage, &Guid); + DEBUG ((DEBUG_INFO, "Image: %g ", &Guid)); + + EntryPoint = 0; + LoadedImagePrivate = BASE_CR (LoadedImage, EFI_SMM_DRIVER_ENTRY, SmmLoadedImage); + RealImageBase = (UINTN)LoadedImage->ImageBase; + if (LoadedImagePrivate->Signature == EFI_SMM_DRIVER_ENTRY_SIGNATURE) { + EntryPoint = LoadedImagePrivate->ImageEntryPoint; + if ((EntryPoint != 0) && ((EntryPoint < (UINTN)LoadedImage->ImageBase) || (EntryPoint >= ((UINTN)LoadedImage->ImageBase + LoadedImage->ImageSize)))) { + // + // If the EntryPoint is not in the range of image buffer, it should come from emulation environment. + // So patch ImageBuffer here to align the EntryPoint. + // + Status = InternalPeCoffGetEntryPoint (LoadedImage->ImageBase, &EntryPointInImage); + ASSERT_EFI_ERROR (Status); + RealImageBase = (UINTN)LoadedImage->ImageBase + EntryPoint - (UINTN)EntryPointInImage; + } + } + + DEBUG ((DEBUG_INFO, "(0x%lx - 0x%lx", RealImageBase, LoadedImage->ImageSize)); + if (EntryPoint != 0) { + DEBUG ((DEBUG_INFO, ", EntryPoint:0x%lx", EntryPoint)); + } + + DEBUG ((DEBUG_INFO, ")\n")); + + if (RealImageBase != 0) { + PdbString = PeCoffLoaderGetPdbPointer ((VOID *)(UINTN)RealImageBase); + DEBUG ((DEBUG_INFO, " pdb - %a\n", PdbString)); + } else { + PdbString = NULL; + } + + DEBUG ((DEBUG_INFO, " (%s)\n", PathStr)); + + AddImageStruct (RealImageBase, LoadedImage->ImageSize, EntryPoint, &Guid, PdbString); + } + +Done: + FreePool (HandleBuffer); + return; +} + +/** + Dump SMI child context. + + @param HandlerType the handler type + @param Context the handler context + @param ContextSize the handler context size +**/ +VOID +DumpSmiChildContext ( + IN EFI_GUID *HandlerType, + IN VOID *Context, + IN UINTN ContextSize + ) +{ + CHAR16 *Str; + + if (CompareGuid (HandlerType, &gEfiSmmSwDispatch2ProtocolGuid)) { + DEBUG ((DEBUG_INFO, " SwSmi - 0x%lx\n", ((SMI_HANDLER_PROFILE_SW_REGISTER_CONTEXT *)Context)->SwSmiInputValue)); + } else if (CompareGuid (HandlerType, &gEfiSmmSxDispatch2ProtocolGuid)) { + DEBUG ((DEBUG_INFO, " SxType - 0x%x\n", ((EFI_SMM_SX_REGISTER_CONTEXT *)Context)->Type)); + DEBUG ((DEBUG_INFO, " SxPhase - 0x%x\n", ((EFI_SMM_SX_REGISTER_CONTEXT *)Context)->Phase)); + } else if (CompareGuid (HandlerType, &gEfiSmmPowerButtonDispatch2ProtocolGuid)) { + DEBUG ((DEBUG_INFO, " PowerButtonPhase - 0x%x\n", ((EFI_SMM_POWER_BUTTON_REGISTER_CONTEXT *)Context)->Phase)); + } else if (CompareGuid (HandlerType, &gEfiSmmStandbyButtonDispatch2ProtocolGuid)) { + DEBUG ((DEBUG_INFO, " StandbyButtonPhase - 0x%x\n", ((EFI_SMM_STANDBY_BUTTON_REGISTER_CONTEXT *)Context)->Phase)); + } else if (CompareGuid (HandlerType, &gEfiSmmPeriodicTimerDispatch2ProtocolGuid)) { + DEBUG ((DEBUG_INFO, " PeriodicTimerPeriod - %ld\n", ((EFI_SMM_PERIODIC_TIMER_REGISTER_CONTEXT *)Context)->Period)); + DEBUG ((DEBUG_INFO, " PeriodicTimerSmiTickInterval - %ld\n", ((EFI_SMM_PERIODIC_TIMER_REGISTER_CONTEXT *)Context)->SmiTickInterval)); + } else if (CompareGuid (HandlerType, &gEfiSmmGpiDispatch2ProtocolGuid)) { + DEBUG ((DEBUG_INFO, " GpiNum - 0x%lx\n", ((EFI_SMM_GPI_REGISTER_CONTEXT *)Context)->GpiNum)); + } else if (CompareGuid (HandlerType, &gEfiSmmIoTrapDispatch2ProtocolGuid)) { + DEBUG ((DEBUG_INFO, " IoTrapAddress - 0x%x\n", ((EFI_SMM_IO_TRAP_REGISTER_CONTEXT *)Context)->Address)); + DEBUG ((DEBUG_INFO, " IoTrapLength - 0x%x\n", ((EFI_SMM_IO_TRAP_REGISTER_CONTEXT *)Context)->Length)); + DEBUG ((DEBUG_INFO, " IoTrapType - 0x%x\n", ((EFI_SMM_IO_TRAP_REGISTER_CONTEXT *)Context)->Type)); + } else if (CompareGuid (HandlerType, &gEfiSmmUsbDispatch2ProtocolGuid)) { + DEBUG ((DEBUG_INFO, " UsbType - 0x%x\n", ((SMI_HANDLER_PROFILE_USB_REGISTER_CONTEXT *)Context)->Type)); + Str = ConvertDevicePathToText ((EFI_DEVICE_PATH_PROTOCOL *)(((SMI_HANDLER_PROFILE_USB_REGISTER_CONTEXT *)Context) + 1), TRUE, TRUE); + DEBUG ((DEBUG_INFO, " UsbDevicePath - %s\n", Str)); + if (Str != NULL) { + FreePool (Str); + } + } else { + DEBUG ((DEBUG_INFO, " Context - ")); + InternalDumpData (Context, ContextSize); + DEBUG ((DEBUG_INFO, "\n")); + } +} + +/** + Dump all SMI handlers associated with SmiEntry. + + @param SmiEntry SMI entry. +**/ +VOID +DumpSmiHandlerOnSmiEntry ( + IN SMI_ENTRY *SmiEntry + ) +{ + LIST_ENTRY *ListEntry; + SMI_HANDLER *SmiHandler; + IMAGE_STRUCT *ImageStruct; + + ListEntry = &SmiEntry->SmiHandlers; + for (ListEntry = ListEntry->ForwardLink; + ListEntry != &SmiEntry->SmiHandlers; + ListEntry = ListEntry->ForwardLink) + { + SmiHandler = CR (ListEntry, SMI_HANDLER, Link, SMI_HANDLER_SIGNATURE); + ImageStruct = AddressToImageStruct ((UINTN)SmiHandler->Handler); + if (ImageStruct != NULL) { + DEBUG ((DEBUG_INFO, " Module - %g", &ImageStruct->FileGuid)); + } + + if ((ImageStruct != NULL) && (ImageStruct->PdbString[0] != 0)) { + DEBUG ((DEBUG_INFO, " (Pdb - %a)", ImageStruct->PdbString)); + } + + DEBUG ((DEBUG_INFO, "\n")); + if (SmiHandler->ContextSize != 0) { + DumpSmiChildContext (&SmiEntry->HandlerType, SmiHandler->Context, SmiHandler->ContextSize); + } + + DEBUG ((DEBUG_INFO, " Handler - 0x%x", SmiHandler->Handler)); + if (ImageStruct != NULL) { + DEBUG ((DEBUG_INFO, " <== RVA - 0x%x", (UINTN)SmiHandler->Handler - (UINTN)ImageStruct->ImageBase)); + } + + DEBUG ((DEBUG_INFO, "\n")); + DEBUG ((DEBUG_INFO, " CallerAddr - 0x%x", SmiHandler->CallerAddr)); + if (ImageStruct != NULL) { + DEBUG ((DEBUG_INFO, " <== RVA - 0x%x", SmiHandler->CallerAddr - (UINTN)ImageStruct->ImageBase)); + } + + DEBUG ((DEBUG_INFO, "\n")); + } + + return; +} + +/** + Dump all SMI entry on the list. + + @param SmiEntryList a list of SMI entry. +**/ +VOID +DumpSmiEntryList ( + IN LIST_ENTRY *SmiEntryList + ) +{ + LIST_ENTRY *ListEntry; + SMI_ENTRY *SmiEntry; + + ListEntry = SmiEntryList; + for (ListEntry = ListEntry->ForwardLink; + ListEntry != SmiEntryList; + ListEntry = ListEntry->ForwardLink) + { + SmiEntry = CR (ListEntry, SMI_ENTRY, AllEntries, SMI_ENTRY_SIGNATURE); + DEBUG ((DEBUG_INFO, "SmiEntry - %g\n", &SmiEntry->HandlerType)); + DumpSmiHandlerOnSmiEntry (SmiEntry); + } + + return; +} + +/** + SMM Ready To Lock event notification handler. + + This function collects all SMM image information and build SmiHandleProfile database, + and register SmiHandlerProfile SMI handler. + + @param[in] Protocol Points to the protocol's unique identifier. + @param[in] Interface Points to the interface instance. + @param[in] Handle The handle on which the interface was installed. + + @retval EFI_SUCCESS Notification handler runs successfully. +**/ +EFI_STATUS +EFIAPI +SmmReadyToLockInSmiHandlerProfile ( + IN CONST EFI_GUID *Protocol, + IN VOID *Interface, + IN EFI_HANDLE Handle + ) +{ + // + // Dump all image + // + DEBUG ((DEBUG_INFO, "##################\n")); + DEBUG ((DEBUG_INFO, "# IMAGE DATABASE #\n")); + DEBUG ((DEBUG_INFO, "##################\n")); + GetSmmLoadedImage (); + DEBUG ((DEBUG_INFO, "\n")); + + // + // Dump SMI Handler + // + DEBUG ((DEBUG_INFO, "########################\n")); + DEBUG ((DEBUG_INFO, "# SMI Handler DATABASE #\n")); + DEBUG ((DEBUG_INFO, "########################\n")); + + DEBUG ((DEBUG_INFO, "# 1. ROOT SMI Handler #\n")); + DEBUG_CODE ( + DumpSmiEntryList (mSmmCoreRootSmiEntryList); + ); + + DEBUG ((DEBUG_INFO, "# 2. GUID SMI Handler #\n")); + DEBUG_CODE ( + DumpSmiEntryList (mSmmCoreSmiEntryList); + ); + + DEBUG ((DEBUG_INFO, "# 3. Hardware SMI Handler #\n")); + DEBUG_CODE ( + DumpSmiEntryList (mSmmCoreHardwareSmiEntryList); + ); + + DEBUG ((DEBUG_INFO, "\n")); + + RegisterSmiHandlerProfileHandler (); + + if (mImageStruct != NULL) { + FreePool (mImageStruct); + } + + return EFI_SUCCESS; +} + +/** + returns SMM image data base size. + + @return SMM image data base size. +**/ +UINTN +GetSmmImageDatabaseSize ( + VOID + ) +{ + UINTN Size; + UINT32 Index; + + Size = 0; + for (Index = 0; Index < mImageStructCount; Index++) { + Size += sizeof (SMM_CORE_IMAGE_DATABASE_STRUCTURE) + GET_OCCUPIED_SIZE (mImageStruct[Index].PdbStringSize, sizeof (UINT64)); + } + + return Size; +} + +/** + returns all SMI handlers' size associated with SmiEntry. + + @param SmiEntry SMI entry. + + @return all SMI handlers' size associated with SmiEntry. +**/ +UINTN +GetSmmSmiHandlerSizeOnSmiEntry ( + IN SMI_ENTRY *SmiEntry + ) +{ + LIST_ENTRY *ListEntry; + SMI_HANDLER *SmiHandler; + UINTN Size; + + Size = 0; + ListEntry = &SmiEntry->SmiHandlers; + for (ListEntry = ListEntry->ForwardLink; + ListEntry != &SmiEntry->SmiHandlers; + ListEntry = ListEntry->ForwardLink) + { + SmiHandler = CR (ListEntry, SMI_HANDLER, Link, SMI_HANDLER_SIGNATURE); + Size += sizeof (SMM_CORE_SMI_HANDLER_STRUCTURE) + GET_OCCUPIED_SIZE (SmiHandler->ContextSize, sizeof (UINT64)); + } + + return Size; +} + +/** + return all SMI handler database size on the SMI entry list. + + @param SmiEntryList a list of SMI entry. + + @return all SMI handler database size on the SMI entry list. +**/ +UINTN +GetSmmSmiDatabaseSize ( + IN LIST_ENTRY *SmiEntryList + ) +{ + LIST_ENTRY *ListEntry; + SMI_ENTRY *SmiEntry; + UINTN Size; + + Size = 0; + ListEntry = SmiEntryList; + for (ListEntry = ListEntry->ForwardLink; + ListEntry != SmiEntryList; + ListEntry = ListEntry->ForwardLink) + { + SmiEntry = CR (ListEntry, SMI_ENTRY, AllEntries, SMI_ENTRY_SIGNATURE); + Size += sizeof (SMM_CORE_SMI_DATABASE_STRUCTURE); + Size += GetSmmSmiHandlerSizeOnSmiEntry (SmiEntry); + } + + return Size; +} + +/** + return SMI handler profile database size. + + @return SMI handler profile database size. +**/ +UINTN +GetSmiHandlerProfileDatabaseSize ( + VOID + ) +{ + mSmmImageDatabaseSize = GetSmmImageDatabaseSize (); + mSmmRootSmiDatabaseSize = GetSmmSmiDatabaseSize (mSmmCoreRootSmiEntryList); + mSmmSmiDatabaseSize = GetSmmSmiDatabaseSize (mSmmCoreSmiEntryList); + mSmmHardwareSmiDatabaseSize = GetSmmSmiDatabaseSize (mSmmCoreHardwareSmiEntryList); + + return mSmmImageDatabaseSize + mSmmSmiDatabaseSize + mSmmRootSmiDatabaseSize + mSmmHardwareSmiDatabaseSize; +} + +/** + get SMM image database. + + @param Data The buffer to hold SMM image database + @param ExpectedSize The expected size of the SMM image database + + @return SMM image data base size. +**/ +UINTN +GetSmmImageDatabaseData ( + IN OUT VOID *Data, + IN UINTN ExpectedSize + ) +{ + SMM_CORE_IMAGE_DATABASE_STRUCTURE *ImageStruct; + UINTN Size; + UINTN Index; + + ImageStruct = Data; + Size = 0; + for (Index = 0; Index < mImageStructCount; Index++) { + if (Size >= ExpectedSize) { + return 0; + } + + if (sizeof (SMM_CORE_IMAGE_DATABASE_STRUCTURE) + GET_OCCUPIED_SIZE (mImageStruct[Index].PdbStringSize, sizeof (UINT64)) > ExpectedSize - Size) { + return 0; + } + + ImageStruct->Header.Signature = SMM_CORE_IMAGE_DATABASE_SIGNATURE; + ImageStruct->Header.Length = (UINT32)(sizeof (SMM_CORE_IMAGE_DATABASE_STRUCTURE) + GET_OCCUPIED_SIZE (mImageStruct[Index].PdbStringSize, sizeof (UINT64))); + ImageStruct->Header.Revision = SMM_CORE_IMAGE_DATABASE_REVISION; + CopyGuid (&ImageStruct->FileGuid, &mImageStruct[Index].FileGuid); + ImageStruct->ImageRef = mImageStruct[Index].ImageRef; + ImageStruct->EntryPoint = mImageStruct[Index].EntryPoint; + ImageStruct->ImageBase = mImageStruct[Index].ImageBase; + ImageStruct->ImageSize = mImageStruct[Index].ImageSize; + if (mImageStruct[Index].PdbStringSize != 0) { + ImageStruct->PdbStringOffset = sizeof (SMM_CORE_IMAGE_DATABASE_STRUCTURE); + CopyMem ((VOID *)((UINTN)ImageStruct + ImageStruct->PdbStringOffset), mImageStruct[Index].PdbString, mImageStruct[Index].PdbStringSize); + } else { + ImageStruct->PdbStringOffset = 0; + } + + ImageStruct = (SMM_CORE_IMAGE_DATABASE_STRUCTURE *)((UINTN)ImageStruct + ImageStruct->Header.Length); + Size += sizeof (SMM_CORE_IMAGE_DATABASE_STRUCTURE) + GET_OCCUPIED_SIZE (mImageStruct[Index].PdbStringSize, sizeof (UINT64)); + } + + if (ExpectedSize != Size) { + return 0; + } + + return Size; +} + +/** + get all SMI handler data associated with SmiEntry. + + @param SmiEntry SMI entry. + @param Data The buffer to hold all SMI handler data + @param MaxSize The max size of the SMM image database + @param Count The count of the SMI handler. + + @return SMM image data base size. +**/ +UINTN +GetSmmSmiHandlerDataOnSmiEntry ( + IN SMI_ENTRY *SmiEntry, + IN OUT VOID *Data, + IN UINTN MaxSize, + OUT UINT32 *Count + ) +{ + SMM_CORE_SMI_HANDLER_STRUCTURE *SmiHandlerStruct; + LIST_ENTRY *ListEntry; + SMI_HANDLER *SmiHandler; + UINTN Size; + + SmiHandlerStruct = Data; + Size = 0; + *Count = 0; + ListEntry = &SmiEntry->SmiHandlers; + for (ListEntry = ListEntry->ForwardLink; + ListEntry != &SmiEntry->SmiHandlers; + ListEntry = ListEntry->ForwardLink) + { + SmiHandler = CR (ListEntry, SMI_HANDLER, Link, SMI_HANDLER_SIGNATURE); + if (Size >= MaxSize) { + *Count = 0; + return 0; + } + + if (sizeof (SMM_CORE_SMI_HANDLER_STRUCTURE) + GET_OCCUPIED_SIZE (SmiHandler->ContextSize, sizeof (UINT64)) > MaxSize - Size) { + *Count = 0; + return 0; + } + + SmiHandlerStruct->Length = (UINT32)(sizeof (SMM_CORE_SMI_HANDLER_STRUCTURE) + GET_OCCUPIED_SIZE (SmiHandler->ContextSize, sizeof (UINT64))); + SmiHandlerStruct->CallerAddr = (UINTN)SmiHandler->CallerAddr; + SmiHandlerStruct->Handler = (UINTN)SmiHandler->Handler; + SmiHandlerStruct->ImageRef = AddressToImageRef ((UINTN)SmiHandler->Handler); + SmiHandlerStruct->ContextBufferSize = (UINT32)SmiHandler->ContextSize; + if (SmiHandler->ContextSize != 0) { + SmiHandlerStruct->ContextBufferOffset = sizeof (SMM_CORE_SMI_HANDLER_STRUCTURE); + CopyMem ((UINT8 *)SmiHandlerStruct + SmiHandlerStruct->ContextBufferOffset, SmiHandler->Context, SmiHandler->ContextSize); + } else { + SmiHandlerStruct->ContextBufferOffset = 0; + } + + Size += sizeof (SMM_CORE_SMI_HANDLER_STRUCTURE) + GET_OCCUPIED_SIZE (SmiHandler->ContextSize, sizeof (UINT64)); + SmiHandlerStruct = (SMM_CORE_SMI_HANDLER_STRUCTURE *)((UINTN)SmiHandlerStruct + SmiHandlerStruct->Length); + *Count = *Count + 1; + } + + return Size; +} + +/** + get all SMI handler database on the SMI entry list. + + @param SmiEntryList a list of SMI entry. + @param HandlerCategory The handler category + @param Data The buffer to hold all SMI handler database + @param ExpectedSize The expected size of the SMM image database + + @return all SMI database size on the SMI entry list. +**/ +UINTN +GetSmmSmiDatabaseData ( + IN LIST_ENTRY *SmiEntryList, + IN UINT32 HandlerCategory, + IN OUT VOID *Data, + IN UINTN ExpectedSize + ) +{ + SMM_CORE_SMI_DATABASE_STRUCTURE *SmiStruct; + LIST_ENTRY *ListEntry; + SMI_ENTRY *SmiEntry; + UINTN Size; + UINTN SmiHandlerSize; + UINT32 SmiHandlerCount; + + SmiStruct = Data; + Size = 0; + ListEntry = SmiEntryList; + for (ListEntry = ListEntry->ForwardLink; + ListEntry != SmiEntryList; + ListEntry = ListEntry->ForwardLink) + { + SmiEntry = CR (ListEntry, SMI_ENTRY, AllEntries, SMI_ENTRY_SIGNATURE); + if (Size >= ExpectedSize) { + return 0; + } + + if (sizeof (SMM_CORE_SMI_DATABASE_STRUCTURE) > ExpectedSize - Size) { + return 0; + } + + SmiStruct->Header.Signature = SMM_CORE_SMI_DATABASE_SIGNATURE; + SmiStruct->Header.Length = sizeof (SMM_CORE_SMI_DATABASE_STRUCTURE); + SmiStruct->Header.Revision = SMM_CORE_SMI_DATABASE_REVISION; + SmiStruct->HandlerCategory = HandlerCategory; + CopyGuid (&SmiStruct->HandlerType, &SmiEntry->HandlerType); + Size += sizeof (SMM_CORE_SMI_DATABASE_STRUCTURE); + SmiHandlerSize = GetSmmSmiHandlerDataOnSmiEntry (SmiEntry, (UINT8 *)SmiStruct + SmiStruct->Header.Length, ExpectedSize - Size, &SmiHandlerCount); + SmiStruct->HandlerCount = SmiHandlerCount; + Size += SmiHandlerSize; + SmiStruct->Header.Length += (UINT32)SmiHandlerSize; + SmiStruct = (VOID *)((UINTN)SmiStruct + SmiStruct->Header.Length); + } + + if (ExpectedSize != Size) { + return 0; + } + + return Size; +} + +/** + Get SMI handler profile database. + + @param Data the buffer to hold SMI handler profile database + + @retval EFI_SUCCESS the database is got. + @retval EFI_INVALID_PARAMETER the database size mismatch. +**/ +EFI_STATUS +GetSmiHandlerProfileDatabaseData ( + IN OUT VOID *Data + ) +{ + UINTN SmmImageDatabaseSize; + UINTN SmmSmiDatabaseSize; + UINTN SmmRootSmiDatabaseSize; + UINTN SmmHardwareSmiDatabaseSize; + + DEBUG ((DEBUG_VERBOSE, "GetSmiHandlerProfileDatabaseData\n")); + SmmImageDatabaseSize = GetSmmImageDatabaseData (Data, mSmmImageDatabaseSize); + if (SmmImageDatabaseSize != mSmmImageDatabaseSize) { + DEBUG ((DEBUG_ERROR, "GetSmiHandlerProfileDatabaseData - SmmImageDatabaseSize mismatch!\n")); + return EFI_INVALID_PARAMETER; + } + + SmmRootSmiDatabaseSize = GetSmmSmiDatabaseData (mSmmCoreRootSmiEntryList, SmmCoreSmiHandlerCategoryRootHandler, (UINT8 *)Data + SmmImageDatabaseSize, mSmmRootSmiDatabaseSize); + if (SmmRootSmiDatabaseSize != mSmmRootSmiDatabaseSize) { + DEBUG ((DEBUG_ERROR, "GetSmiHandlerProfileDatabaseData - SmmRootSmiDatabaseSize mismatch!\n")); + return EFI_INVALID_PARAMETER; + } + + SmmSmiDatabaseSize = GetSmmSmiDatabaseData (mSmmCoreSmiEntryList, SmmCoreSmiHandlerCategoryGuidHandler, (UINT8 *)Data + SmmImageDatabaseSize + mSmmRootSmiDatabaseSize, mSmmSmiDatabaseSize); + if (SmmSmiDatabaseSize != mSmmSmiDatabaseSize) { + DEBUG ((DEBUG_ERROR, "GetSmiHandlerProfileDatabaseData - SmmSmiDatabaseSize mismatch!\n")); + return EFI_INVALID_PARAMETER; + } + + SmmHardwareSmiDatabaseSize = GetSmmSmiDatabaseData (mSmmCoreHardwareSmiEntryList, SmmCoreSmiHandlerCategoryHardwareHandler, (UINT8 *)Data + SmmImageDatabaseSize + SmmRootSmiDatabaseSize + SmmSmiDatabaseSize, mSmmHardwareSmiDatabaseSize); + if (SmmHardwareSmiDatabaseSize != mSmmHardwareSmiDatabaseSize) { + DEBUG ((DEBUG_ERROR, "GetSmiHandlerProfileDatabaseData - SmmHardwareSmiDatabaseSize mismatch!\n")); + return EFI_INVALID_PARAMETER; + } + + return EFI_SUCCESS; +} + +/** + build SMI handler profile database. +**/ +VOID +BuildSmiHandlerProfileDatabase ( + VOID + ) +{ + EFI_STATUS Status; + + mSmiHandlerProfileDatabaseSize = GetSmiHandlerProfileDatabaseSize (); + mSmiHandlerProfileDatabase = AllocatePool (mSmiHandlerProfileDatabaseSize); + if (mSmiHandlerProfileDatabase == NULL) { + return; + } + + Status = GetSmiHandlerProfileDatabaseData (mSmiHandlerProfileDatabase); + if (EFI_ERROR (Status)) { + FreePool (mSmiHandlerProfileDatabase); + mSmiHandlerProfileDatabase = NULL; + } +} + +/** + Copy SMI handler profile data. + + @param DataBuffer The buffer to hold SMI handler profile data. + @param DataSize On input, data buffer size. + On output, actual data buffer size copied. + @param DataOffset On input, data buffer offset to copy. + On output, next time data buffer offset to copy. + +**/ +VOID +SmiHandlerProfileCopyData ( + OUT VOID *DataBuffer, + IN OUT UINT64 *DataSize, + IN OUT UINT64 *DataOffset + ) +{ + if (*DataOffset >= mSmiHandlerProfileDatabaseSize) { + *DataOffset = mSmiHandlerProfileDatabaseSize; + return; + } + + if (mSmiHandlerProfileDatabaseSize - *DataOffset < *DataSize) { + *DataSize = mSmiHandlerProfileDatabaseSize - *DataOffset; + } + + CopyMem ( + DataBuffer, + (UINT8 *)mSmiHandlerProfileDatabase + *DataOffset, + (UINTN)*DataSize + ); + *DataOffset = *DataOffset + *DataSize; +} + +/** + SMI handler profile handler to get info. + + @param SmiHandlerProfileParameterGetInfo The parameter of SMI handler profile get info. + +**/ +VOID +SmiHandlerProfileHandlerGetInfo ( + IN SMI_HANDLER_PROFILE_PARAMETER_GET_INFO *SmiHandlerProfileParameterGetInfo + ) +{ + BOOLEAN SmiHandlerProfileRecordingStatus; + + SmiHandlerProfileRecordingStatus = mSmiHandlerProfileRecordingStatus; + mSmiHandlerProfileRecordingStatus = FALSE; + + SmiHandlerProfileParameterGetInfo->DataSize = mSmiHandlerProfileDatabaseSize; + SmiHandlerProfileParameterGetInfo->Header.ReturnStatus = 0; + + mSmiHandlerProfileRecordingStatus = SmiHandlerProfileRecordingStatus; +} + +/** + SMI handler profile handler to get data by offset. + + @param SmiHandlerProfileParameterGetDataByOffset The parameter of SMI handler profile get data by offset. + +**/ +VOID +SmiHandlerProfileHandlerGetDataByOffset ( + IN SMI_HANDLER_PROFILE_PARAMETER_GET_DATA_BY_OFFSET *SmiHandlerProfileParameterGetDataByOffset + ) +{ + SMI_HANDLER_PROFILE_PARAMETER_GET_DATA_BY_OFFSET SmiHandlerProfileGetDataByOffset; + BOOLEAN SmiHandlerProfileRecordingStatus; + + SmiHandlerProfileRecordingStatus = mSmiHandlerProfileRecordingStatus; + mSmiHandlerProfileRecordingStatus = FALSE; + + CopyMem (&SmiHandlerProfileGetDataByOffset, SmiHandlerProfileParameterGetDataByOffset, sizeof (SmiHandlerProfileGetDataByOffset)); + + // + // Sanity check + // + if (!SmmIsBufferOutsideSmmValid ((UINTN)SmiHandlerProfileGetDataByOffset.DataBuffer, (UINTN)SmiHandlerProfileGetDataByOffset.DataSize)) { + DEBUG ((DEBUG_ERROR, "SmiHandlerProfileHandlerGetDataByOffset: SMI handler profile get data in SMRAM or overflow!\n")); + SmiHandlerProfileParameterGetDataByOffset->Header.ReturnStatus = (UINT64)(INT64)(INTN)EFI_ACCESS_DENIED; + goto Done; + } + + SmiHandlerProfileCopyData ((VOID *)(UINTN)SmiHandlerProfileGetDataByOffset.DataBuffer, &SmiHandlerProfileGetDataByOffset.DataSize, &SmiHandlerProfileGetDataByOffset.DataOffset); + CopyMem (SmiHandlerProfileParameterGetDataByOffset, &SmiHandlerProfileGetDataByOffset, sizeof (SmiHandlerProfileGetDataByOffset)); + SmiHandlerProfileParameterGetDataByOffset->Header.ReturnStatus = 0; + +Done: + mSmiHandlerProfileRecordingStatus = SmiHandlerProfileRecordingStatus; +} + +/** + Dispatch function for a Software SMI handler. + + Caution: This function may receive untrusted input. + Communicate buffer and buffer size are external input, so this function will do basic validation. + + @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-SMM environment into an SMM environment. + @param CommBufferSize The size of the CommBuffer. + + @retval EFI_SUCCESS Command is handled successfully. +**/ +EFI_STATUS +EFIAPI +SmiHandlerProfileHandler ( + IN EFI_HANDLE DispatchHandle, + IN CONST VOID *Context OPTIONAL, + IN OUT VOID *CommBuffer OPTIONAL, + IN OUT UINTN *CommBufferSize OPTIONAL + ) +{ + SMI_HANDLER_PROFILE_PARAMETER_HEADER *SmiHandlerProfileParameterHeader; + UINTN TempCommBufferSize; + + DEBUG ((DEBUG_ERROR, "SmiHandlerProfileHandler Enter\n")); + + if (mSmiHandlerProfileDatabase == NULL) { + return EFI_SUCCESS; + } + + // + // If input is invalid, stop processing this SMI + // + if ((CommBuffer == NULL) || (CommBufferSize == NULL)) { + return EFI_SUCCESS; + } + + TempCommBufferSize = *CommBufferSize; + + if (TempCommBufferSize < sizeof (SMI_HANDLER_PROFILE_PARAMETER_HEADER)) { + DEBUG ((DEBUG_ERROR, "SmiHandlerProfileHandler: SMM communication buffer size invalid!\n")); + return EFI_SUCCESS; + } + + if (!SmmIsBufferOutsideSmmValid ((UINTN)CommBuffer, TempCommBufferSize)) { + DEBUG ((DEBUG_ERROR, "SmiHandlerProfileHandler: SMM communication buffer in SMRAM or overflow!\n")); + return EFI_SUCCESS; + } + + SmiHandlerProfileParameterHeader = (SMI_HANDLER_PROFILE_PARAMETER_HEADER *)((UINTN)CommBuffer); + SmiHandlerProfileParameterHeader->ReturnStatus = (UINT64)-1; + + switch (SmiHandlerProfileParameterHeader->Command) { + case SMI_HANDLER_PROFILE_COMMAND_GET_INFO: + DEBUG ((DEBUG_ERROR, "SmiHandlerProfileHandlerGetInfo\n")); + if (TempCommBufferSize != sizeof (SMI_HANDLER_PROFILE_PARAMETER_GET_INFO)) { + DEBUG ((DEBUG_ERROR, "SmiHandlerProfileHandler: SMM communication buffer size invalid!\n")); + return EFI_SUCCESS; + } + + SmiHandlerProfileHandlerGetInfo ((SMI_HANDLER_PROFILE_PARAMETER_GET_INFO *)(UINTN)CommBuffer); + break; + case SMI_HANDLER_PROFILE_COMMAND_GET_DATA_BY_OFFSET: + DEBUG ((DEBUG_ERROR, "SmiHandlerProfileHandlerGetDataByOffset\n")); + if (TempCommBufferSize != sizeof (SMI_HANDLER_PROFILE_PARAMETER_GET_DATA_BY_OFFSET)) { + DEBUG ((DEBUG_ERROR, "SmiHandlerProfileHandler: SMM communication buffer size invalid!\n")); + return EFI_SUCCESS; + } + + SmiHandlerProfileHandlerGetDataByOffset ((SMI_HANDLER_PROFILE_PARAMETER_GET_DATA_BY_OFFSET *)(UINTN)CommBuffer); + break; + default: + break; + } + + DEBUG ((DEBUG_ERROR, "SmiHandlerProfileHandler Exit\n")); + + return EFI_SUCCESS; +} + +/** + Register SMI handler profile handler. +**/ +VOID +RegisterSmiHandlerProfileHandler ( + VOID + ) +{ + EFI_STATUS Status; + EFI_HANDLE DispatchHandle; + + Status = gSmst->SmiHandlerRegister ( + SmiHandlerProfileHandler, + &gSmiHandlerProfileGuid, + &DispatchHandle + ); + ASSERT_EFI_ERROR (Status); + + BuildSmiHandlerProfileDatabase (); +} + +/** + Finds the SMI entry for the requested handler type. + + @param HandlerType The type of the interrupt + @param Create Create a new entry if not found + + @return SMI entry +**/ +SMI_ENTRY * +SmmCoreFindHardwareSmiEntry ( + IN EFI_GUID *HandlerType, + IN BOOLEAN Create + ) +{ + LIST_ENTRY *Link; + SMI_ENTRY *Item; + SMI_ENTRY *SmiEntry; + + // + // Search the SMI entry list for the matching GUID + // + SmiEntry = NULL; + for (Link = mHardwareSmiEntryList.ForwardLink; + Link != &mHardwareSmiEntryList; + Link = Link->ForwardLink) + { + Item = CR (Link, SMI_ENTRY, AllEntries, SMI_ENTRY_SIGNATURE); + if (CompareGuid (&Item->HandlerType, HandlerType)) { + // + // This is the SMI entry + // + SmiEntry = Item; + break; + } + } + + // + // If the protocol entry was not found and Create is TRUE, then + // allocate a new entry + // + if ((SmiEntry == NULL) && Create) { + SmiEntry = AllocatePool (sizeof (SMI_ENTRY)); + if (SmiEntry != NULL) { + // + // Initialize new SMI entry structure + // + SmiEntry->Signature = SMI_ENTRY_SIGNATURE; + CopyGuid ((VOID *)&SmiEntry->HandlerType, HandlerType); + InitializeListHead (&SmiEntry->SmiHandlers); + + // + // Add it to SMI entry list + // + InsertTailList (&mHardwareSmiEntryList, &SmiEntry->AllEntries); + } + } + + return SmiEntry; +} + +/** + Convert EFI_SMM_USB_REGISTER_CONTEXT to SMI_HANDLER_PROFILE_USB_REGISTER_CONTEXT. + + @param UsbContext A pointer to EFI_SMM_USB_REGISTER_CONTEXT + @param UsbContextSize The size of EFI_SMM_USB_REGISTER_CONTEXT in bytes + @param SmiHandlerUsbContextSize The size of SMI_HANDLER_PROFILE_USB_REGISTER_CONTEXT in bytes + + @return SmiHandlerUsbContext A pointer to SMI_HANDLER_PROFILE_USB_REGISTER_CONTEXT +**/ +SMI_HANDLER_PROFILE_USB_REGISTER_CONTEXT * +ConvertSmiHandlerUsbContext ( + IN EFI_SMM_USB_REGISTER_CONTEXT *UsbContext, + IN UINTN UsbContextSize, + OUT UINTN *SmiHandlerUsbContextSize + ) +{ + UINTN DevicePathSize; + SMI_HANDLER_PROFILE_USB_REGISTER_CONTEXT *SmiHandlerUsbContext; + + ASSERT (UsbContextSize == sizeof (EFI_SMM_USB_REGISTER_CONTEXT)); + + DevicePathSize = GetDevicePathSize (UsbContext->Device); + SmiHandlerUsbContext = AllocatePool (sizeof (SMI_HANDLER_PROFILE_USB_REGISTER_CONTEXT) + DevicePathSize); + if (SmiHandlerUsbContext == NULL) { + *SmiHandlerUsbContextSize = 0; + return NULL; + } + + SmiHandlerUsbContext->Type = UsbContext->Type; + SmiHandlerUsbContext->DevicePathSize = (UINT32)DevicePathSize; + CopyMem (SmiHandlerUsbContext + 1, UsbContext->Device, DevicePathSize); + *SmiHandlerUsbContextSize = sizeof (SMI_HANDLER_PROFILE_USB_REGISTER_CONTEXT) + DevicePathSize; + return SmiHandlerUsbContext; +} + +/** + Convert EFI_SMM_SW_REGISTER_CONTEXT to SMI_HANDLER_PROFILE_SW_REGISTER_CONTEXT. + + @param SwContext A pointer to EFI_SMM_SW_REGISTER_CONTEXT + @param SwContextSize The size of EFI_SMM_SW_REGISTER_CONTEXT in bytes + @param SmiHandlerSwContextSize The size of SMI_HANDLER_PROFILE_SW_REGISTER_CONTEXT in bytes + + @return SmiHandlerSwContext A pointer to SMI_HANDLER_PROFILE_SW_REGISTER_CONTEXT +**/ +SMI_HANDLER_PROFILE_SW_REGISTER_CONTEXT * +ConvertSmiHandlerSwContext ( + IN EFI_SMM_SW_REGISTER_CONTEXT *SwContext, + IN UINTN SwContextSize, + OUT UINTN *SmiHandlerSwContextSize + ) +{ + SMI_HANDLER_PROFILE_SW_REGISTER_CONTEXT *SmiHandlerSwContext; + + ASSERT (SwContextSize == sizeof (EFI_SMM_SW_REGISTER_CONTEXT)); + + SmiHandlerSwContext = AllocatePool (sizeof (SMI_HANDLER_PROFILE_SW_REGISTER_CONTEXT)); + if (SmiHandlerSwContext == NULL) { + *SmiHandlerSwContextSize = 0; + return NULL; + } + + SmiHandlerSwContext->SwSmiInputValue = SwContext->SwSmiInputValue; + *SmiHandlerSwContextSize = sizeof (SMI_HANDLER_PROFILE_SW_REGISTER_CONTEXT); + return SmiHandlerSwContext; +} + +/** + This function is called by SmmChildDispatcher module to report + a new SMI handler is registered, to SmmCore. + + @param This The protocol instance + @param HandlerGuid The GUID to identify the type of the handler. + For the SmmChildDispatch protocol, the HandlerGuid + must be the GUID of SmmChildDispatch protocol. + @param Handler The SMI handler. + @param CallerAddress The address of the module who registers the SMI handler. + @param Context The context of the SMI handler. + For the SmmChildDispatch protocol, the Context + must match the one defined for SmmChildDispatch protocol. + @param ContextSize The size of the context in bytes. + For the SmmChildDispatch protocol, the Context + must match the one defined for SmmChildDispatch protocol. + + @retval EFI_SUCCESS The information is recorded. + @retval EFI_OUT_OF_RESOURCES There is no enough resource to record the information. +**/ +EFI_STATUS +EFIAPI +SmiHandlerProfileRegisterHandler ( + IN SMI_HANDLER_PROFILE_PROTOCOL *This, + IN EFI_GUID *HandlerGuid, + IN EFI_SMM_HANDLER_ENTRY_POINT2 Handler, + IN PHYSICAL_ADDRESS CallerAddress, + IN VOID *Context OPTIONAL, + IN UINTN ContextSize OPTIONAL + ) +{ + SMI_HANDLER *SmiHandler; + SMI_ENTRY *SmiEntry; + LIST_ENTRY *List; + + if (((ContextSize == 0) && (Context != NULL)) || + ((ContextSize != 0) && (Context == NULL))) + { + return EFI_INVALID_PARAMETER; + } + + SmiHandler = AllocateZeroPool (sizeof (SMI_HANDLER)); + if (SmiHandler == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + SmiHandler->Signature = SMI_HANDLER_SIGNATURE; + SmiHandler->Handler = Handler; + SmiHandler->CallerAddr = (UINTN)CallerAddress; + SmiHandler->Context = Context; + SmiHandler->ContextSize = ContextSize; + + if (Context != NULL) { + if (CompareGuid (HandlerGuid, &gEfiSmmUsbDispatch2ProtocolGuid)) { + SmiHandler->Context = ConvertSmiHandlerUsbContext (Context, ContextSize, &SmiHandler->ContextSize); + } else if (CompareGuid (HandlerGuid, &gEfiSmmSwDispatch2ProtocolGuid)) { + SmiHandler->Context = ConvertSmiHandlerSwContext (Context, ContextSize, &SmiHandler->ContextSize); + } else { + SmiHandler->Context = AllocateCopyPool (ContextSize, Context); + } + } + + if (SmiHandler->Context == NULL) { + SmiHandler->ContextSize = 0; + } + + SmiEntry = SmmCoreFindHardwareSmiEntry (HandlerGuid, TRUE); + if (SmiEntry == NULL) { + if (SmiHandler->Context != NULL) { + FreePool (SmiHandler->Context); + } + + FreePool (SmiHandler); + return EFI_OUT_OF_RESOURCES; + } + + List = &SmiEntry->SmiHandlers; + + SmiHandler->SmiEntry = SmiEntry; + InsertTailList (List, &SmiHandler->Link); + + return EFI_SUCCESS; +} + +/** + This function is called by SmmChildDispatcher module to report + an existing SMI handler is unregistered, to SmmCore. + + @param This The protocol instance + @param HandlerGuid The GUID to identify the type of the handler. + For the SmmChildDispatch protocol, the HandlerGuid + must be the GUID of SmmChildDispatch protocol. + @param Handler The SMI handler. + @param Context The context of the SMI handler. + If it is NOT NULL, it will be used to check what is registered. + @param ContextSize The size of the context in bytes. + If Context is NOT NULL, it will be used to check what is registered. + + @retval EFI_SUCCESS The original record is removed. + @retval EFI_NOT_FOUND There is no record for the HandlerGuid and handler. +**/ +EFI_STATUS +EFIAPI +SmiHandlerProfileUnregisterHandler ( + IN SMI_HANDLER_PROFILE_PROTOCOL *This, + IN EFI_GUID *HandlerGuid, + IN EFI_SMM_HANDLER_ENTRY_POINT2 Handler, + IN VOID *Context OPTIONAL, + IN UINTN ContextSize OPTIONAL + ) +{ + LIST_ENTRY *Link; + LIST_ENTRY *Head; + SMI_HANDLER *SmiHandler; + SMI_ENTRY *SmiEntry; + SMI_HANDLER *TargetSmiHandler; + VOID *SearchContext; + UINTN SearchContextSize; + + if (((ContextSize == 0) && (Context != NULL)) || + ((ContextSize != 0) && (Context == NULL))) + { + return EFI_INVALID_PARAMETER; + } + + SmiEntry = SmmCoreFindHardwareSmiEntry (HandlerGuid, FALSE); + if (SmiEntry == NULL) { + return EFI_NOT_FOUND; + } + + SearchContext = Context; + SearchContextSize = ContextSize; + if (Context != NULL) { + if (CompareGuid (HandlerGuid, &gEfiSmmUsbDispatch2ProtocolGuid)) { + SearchContext = ConvertSmiHandlerUsbContext (Context, ContextSize, &SearchContextSize); + } else if (CompareGuid (HandlerGuid, &gEfiSmmSwDispatch2ProtocolGuid)) { + SearchContext = ConvertSmiHandlerSwContext (Context, ContextSize, &SearchContextSize); + } + } + + TargetSmiHandler = NULL; + Head = &SmiEntry->SmiHandlers; + for (Link = Head->ForwardLink; Link != Head; Link = Link->ForwardLink) { + SmiHandler = CR (Link, SMI_HANDLER, Link, SMI_HANDLER_SIGNATURE); + if (SmiHandler->Handler == Handler) { + if ((SearchContext == NULL) || + ((SearchContextSize == SmiHandler->ContextSize) && (CompareMem (SearchContext, SmiHandler->Context, SearchContextSize) == 0))) + { + TargetSmiHandler = SmiHandler; + break; + } + } + } + + if (SearchContext != NULL) { + if (CompareGuid (HandlerGuid, &gEfiSmmUsbDispatch2ProtocolGuid)) { + FreePool (SearchContext); + } + } + + if (TargetSmiHandler == NULL) { + return EFI_NOT_FOUND; + } + + SmiHandler = TargetSmiHandler; + + RemoveEntryList (&SmiHandler->Link); + if (SmiHandler->Context != NULL) { + FreePool (SmiHandler->Context); + } + + FreePool (SmiHandler); + + if (IsListEmpty (&SmiEntry->SmiHandlers)) { + RemoveEntryList (&SmiEntry->AllEntries); + FreePool (SmiEntry); + } + + return EFI_SUCCESS; +} + +/** + Initialize SmiHandler profile feature. +**/ +VOID +SmmCoreInitializeSmiHandlerProfile ( + VOID + ) +{ + EFI_STATUS Status; + VOID *Registration; + EFI_HANDLE Handle; + + if ((PcdGet8 (PcdSmiHandlerProfilePropertyMask) & 0x1) != 0) { + InsertTailList (&mRootSmiEntryList, &mRootSmiEntry.AllEntries); + + Status = gSmst->SmmRegisterProtocolNotify ( + &gEfiSmmReadyToLockProtocolGuid, + SmmReadyToLockInSmiHandlerProfile, + &Registration + ); + ASSERT_EFI_ERROR (Status); + + Handle = NULL; + Status = gSmst->SmmInstallProtocolInterface ( + &Handle, + &gSmiHandlerProfileGuid, + EFI_NATIVE_INTERFACE, + &mSmiHandlerProfile + ); + ASSERT_EFI_ERROR (Status); + } +} diff --git a/MdeModulePkg/Core/PiSmmCore/SmramProfileRecord.c b/MdeModulePkg/Core/PiSmmCore/SmramProfileRecord.c index b437e4c433..649f971a42 100644 --- a/MdeModulePkg/Core/PiSmmCore/SmramProfileRecord.c +++ b/MdeModulePkg/Core/PiSmmCore/SmramProfileRecord.c @@ -1,2810 +1,2810 @@ -/** @file
- Support routines for SMRAM profile.
-
- Copyright (c) 2014 - 2018, Intel Corporation. All rights reserved.<BR>
- SPDX-License-Identifier: BSD-2-Clause-Patent
-
-**/
-
-#include "PiSmmCore.h"
-
-#define IS_SMRAM_PROFILE_ENABLED ((PcdGet8 (PcdMemoryProfilePropertyMask) & BIT1) != 0)
-#define IS_UEFI_MEMORY_PROFILE_ENABLED ((PcdGet8 (PcdMemoryProfilePropertyMask) & BIT0) != 0)
-
-#define GET_OCCUPIED_SIZE(ActualSize, Alignment) \
- ((ActualSize) + (((Alignment) - ((ActualSize) & ((Alignment) - 1))) & ((Alignment) - 1)))
-
-typedef struct {
- UINT32 Signature;
- MEMORY_PROFILE_CONTEXT Context;
- LIST_ENTRY *DriverInfoList;
-} MEMORY_PROFILE_CONTEXT_DATA;
-
-typedef struct {
- UINT32 Signature;
- MEMORY_PROFILE_DRIVER_INFO DriverInfo;
- LIST_ENTRY *AllocInfoList;
- CHAR8 *PdbString;
- LIST_ENTRY Link;
-} MEMORY_PROFILE_DRIVER_INFO_DATA;
-
-typedef struct {
- UINT32 Signature;
- MEMORY_PROFILE_ALLOC_INFO AllocInfo;
- CHAR8 *ActionString;
- LIST_ENTRY Link;
-} MEMORY_PROFILE_ALLOC_INFO_DATA;
-
-//
-// When free memory less than 4 pages, dump it.
-//
-#define SMRAM_INFO_DUMP_PAGE_THRESHOLD 4
-
-GLOBAL_REMOVE_IF_UNREFERENCED MEMORY_PROFILE_FREE_MEMORY mSmramFreeMemory = {
- {
- MEMORY_PROFILE_FREE_MEMORY_SIGNATURE,
- sizeof (MEMORY_PROFILE_FREE_MEMORY),
- MEMORY_PROFILE_FREE_MEMORY_REVISION
- },
- 0,
- 0
-};
-
-GLOBAL_REMOVE_IF_UNREFERENCED LIST_ENTRY mImageQueue = INITIALIZE_LIST_HEAD_VARIABLE (mImageQueue);
-GLOBAL_REMOVE_IF_UNREFERENCED MEMORY_PROFILE_CONTEXT_DATA mSmramProfileContext = {
- MEMORY_PROFILE_CONTEXT_SIGNATURE,
- {
- {
- MEMORY_PROFILE_CONTEXT_SIGNATURE,
- sizeof (MEMORY_PROFILE_CONTEXT),
- MEMORY_PROFILE_CONTEXT_REVISION
- },
- 0,
- 0,
- { 0 },
- { 0 },
- 0,
- 0,
- 0
- },
- &mImageQueue,
-};
-GLOBAL_REMOVE_IF_UNREFERENCED MEMORY_PROFILE_CONTEXT_DATA *mSmramProfileContextPtr = NULL;
-
-GLOBAL_REMOVE_IF_UNREFERENCED BOOLEAN mSmramReadyToLock;
-GLOBAL_REMOVE_IF_UNREFERENCED BOOLEAN mSmramProfileGettingStatus = FALSE;
-GLOBAL_REMOVE_IF_UNREFERENCED BOOLEAN mSmramProfileRecordingEnable = MEMORY_PROFILE_RECORDING_DISABLE;
-GLOBAL_REMOVE_IF_UNREFERENCED EFI_DEVICE_PATH_PROTOCOL *mSmramProfileDriverPath;
-GLOBAL_REMOVE_IF_UNREFERENCED UINTN mSmramProfileDriverPathSize;
-
-/**
- Dump SMRAM information.
-
-**/
-VOID
-DumpSmramInfo (
- VOID
- );
-
-/**
- Get memory profile data.
-
- @param[in] This The EDKII_SMM_MEMORY_PROFILE_PROTOCOL instance.
- @param[in, out] ProfileSize On entry, points to the size in bytes of the ProfileBuffer.
- On return, points to the size of the data returned in ProfileBuffer.
- @param[out] ProfileBuffer Profile buffer.
-
- @return EFI_SUCCESS Get the memory profile data successfully.
- @return EFI_UNSUPPORTED Memory profile is unsupported.
- @return EFI_BUFFER_TO_SMALL The ProfileSize is too small for the resulting data.
- ProfileSize is updated with the size required.
-
-**/
-EFI_STATUS
-EFIAPI
-SmramProfileProtocolGetData (
- IN EDKII_SMM_MEMORY_PROFILE_PROTOCOL *This,
- IN OUT UINT64 *ProfileSize,
- OUT VOID *ProfileBuffer
- );
-
-/**
- Register image to memory profile.
-
- @param[in] This The EDKII_SMM_MEMORY_PROFILE_PROTOCOL instance.
- @param[in] FilePath File path of the image.
- @param[in] ImageBase Image base address.
- @param[in] ImageSize Image size.
- @param[in] FileType File type of the image.
-
- @return EFI_SUCCESS Register successfully.
- @return EFI_UNSUPPORTED Memory profile is unsupported,
- or memory profile for the image is not required.
- @return EFI_OUT_OF_RESOURCE No enough resource for this register.
-
-**/
-EFI_STATUS
-EFIAPI
-SmramProfileProtocolRegisterImage (
- IN EDKII_SMM_MEMORY_PROFILE_PROTOCOL *This,
- IN EFI_DEVICE_PATH_PROTOCOL *FilePath,
- IN PHYSICAL_ADDRESS ImageBase,
- IN UINT64 ImageSize,
- IN EFI_FV_FILETYPE FileType
- );
-
-/**
- Unregister image from memory profile.
-
- @param[in] This The EDKII_SMM_MEMORY_PROFILE_PROTOCOL instance.
- @param[in] FilePath File path of the image.
- @param[in] ImageBase Image base address.
- @param[in] ImageSize Image size.
-
- @return EFI_SUCCESS Unregister successfully.
- @return EFI_UNSUPPORTED Memory profile is unsupported,
- or memory profile for the image is not required.
- @return EFI_NOT_FOUND The image is not found.
-
-**/
-EFI_STATUS
-EFIAPI
-SmramProfileProtocolUnregisterImage (
- IN EDKII_SMM_MEMORY_PROFILE_PROTOCOL *This,
- IN EFI_DEVICE_PATH_PROTOCOL *FilePath,
- IN PHYSICAL_ADDRESS ImageBase,
- IN UINT64 ImageSize
- );
-
-/**
- Get memory profile recording state.
-
- @param[in] This The EDKII_SMM_MEMORY_PROFILE_PROTOCOL instance.
- @param[out] RecordingState Recording state.
-
- @return EFI_SUCCESS Memory profile recording state is returned.
- @return EFI_UNSUPPORTED Memory profile is unsupported.
- @return EFI_INVALID_PARAMETER RecordingState is NULL.
-
-**/
-EFI_STATUS
-EFIAPI
-SmramProfileProtocolGetRecordingState (
- IN EDKII_SMM_MEMORY_PROFILE_PROTOCOL *This,
- OUT BOOLEAN *RecordingState
- );
-
-/**
- Set memory profile recording state.
-
- @param[in] This The EDKII_SMM_MEMORY_PROFILE_PROTOCOL instance.
- @param[in] RecordingState Recording state.
-
- @return EFI_SUCCESS Set memory profile recording state successfully.
- @return EFI_UNSUPPORTED Memory profile is unsupported.
-
-**/
-EFI_STATUS
-EFIAPI
-SmramProfileProtocolSetRecordingState (
- IN EDKII_SMM_MEMORY_PROFILE_PROTOCOL *This,
- IN BOOLEAN RecordingState
- );
-
-/**
- Record memory profile of multilevel caller.
-
- @param[in] This The EDKII_SMM_MEMORY_PROFILE_PROTOCOL instance.
- @param[in] CallerAddress Address of caller.
- @param[in] Action Memory profile action.
- @param[in] MemoryType Memory type.
- EfiMaxMemoryType means the MemoryType is unknown.
- @param[in] Buffer Buffer address.
- @param[in] Size Buffer size.
- @param[in] ActionString String for memory profile action.
- Only needed for user defined allocate action.
-
- @return EFI_SUCCESS Memory profile is updated.
- @return EFI_UNSUPPORTED Memory profile is unsupported,
- or memory profile for the image is not required,
- or memory profile for the memory type is not required.
- @return EFI_ACCESS_DENIED It is during memory profile data getting.
- @return EFI_ABORTED Memory profile recording is not enabled.
- @return EFI_OUT_OF_RESOURCES No enough resource to update memory profile for allocate action.
- @return EFI_NOT_FOUND No matched allocate info found for free action.
-
-**/
-EFI_STATUS
-EFIAPI
-SmramProfileProtocolRecord (
- IN EDKII_SMM_MEMORY_PROFILE_PROTOCOL *This,
- IN PHYSICAL_ADDRESS CallerAddress,
- IN MEMORY_PROFILE_ACTION Action,
- IN EFI_MEMORY_TYPE MemoryType,
- IN VOID *Buffer,
- IN UINTN Size,
- IN CHAR8 *ActionString OPTIONAL
- );
-
-GLOBAL_REMOVE_IF_UNREFERENCED EDKII_SMM_MEMORY_PROFILE_PROTOCOL mSmmProfileProtocol = {
- SmramProfileProtocolGetData,
- SmramProfileProtocolRegisterImage,
- SmramProfileProtocolUnregisterImage,
- SmramProfileProtocolGetRecordingState,
- SmramProfileProtocolSetRecordingState,
- SmramProfileProtocolRecord,
-};
-
-/**
- Return SMRAM profile context.
-
- @return SMRAM profile context.
-
-**/
-MEMORY_PROFILE_CONTEXT_DATA *
-GetSmramProfileContext (
- VOID
- )
-{
- return mSmramProfileContextPtr;
-}
-
-/**
- Retrieves and returns the Subsystem of a PE/COFF image that has been loaded into system memory.
- If Pe32Data is NULL, then ASSERT().
-
- @param Pe32Data The pointer to the PE/COFF image that is loaded in system memory.
-
- @return The Subsystem of the PE/COFF image.
-
-**/
-UINT16
-InternalPeCoffGetSubsystem (
- IN VOID *Pe32Data
- )
-{
- EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr;
- EFI_IMAGE_DOS_HEADER *DosHdr;
- UINT16 Magic;
-
- ASSERT (Pe32Data != NULL);
-
- DosHdr = (EFI_IMAGE_DOS_HEADER *)Pe32Data;
- if (DosHdr->e_magic == EFI_IMAGE_DOS_SIGNATURE) {
- //
- // DOS image header is present, so read the PE header after the DOS image header.
- //
- Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *)((UINTN)Pe32Data + (UINTN)((DosHdr->e_lfanew) & 0x0ffff));
- } else {
- //
- // DOS image header is not present, so PE header is at the image base.
- //
- Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *)Pe32Data;
- }
-
- if (Hdr.Te->Signature == EFI_TE_IMAGE_HEADER_SIGNATURE) {
- return Hdr.Te->Subsystem;
- } else if (Hdr.Pe32->Signature == EFI_IMAGE_NT_SIGNATURE) {
- Magic = Hdr.Pe32->OptionalHeader.Magic;
- if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
- return Hdr.Pe32->OptionalHeader.Subsystem;
- } else if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC) {
- return Hdr.Pe32Plus->OptionalHeader.Subsystem;
- }
- }
-
- return 0x0000;
-}
-
-/**
- Retrieves and returns a pointer to the entry point to a PE/COFF image that has been loaded
- into system memory with the PE/COFF Loader Library functions.
-
- Retrieves the entry point to the PE/COFF image specified by Pe32Data and returns this entry
- point in EntryPoint. If the entry point could not be retrieved from the PE/COFF image, then
- return RETURN_INVALID_PARAMETER. Otherwise return RETURN_SUCCESS.
- If Pe32Data is NULL, then ASSERT().
- If EntryPoint is NULL, then ASSERT().
-
- @param Pe32Data The pointer to the PE/COFF image that is loaded in system memory.
- @param EntryPoint The pointer to entry point to the PE/COFF image to return.
-
- @retval RETURN_SUCCESS EntryPoint was returned.
- @retval RETURN_INVALID_PARAMETER The entry point could not be found in the PE/COFF image.
-
-**/
-RETURN_STATUS
-InternalPeCoffGetEntryPoint (
- IN VOID *Pe32Data,
- OUT VOID **EntryPoint
- )
-{
- EFI_IMAGE_DOS_HEADER *DosHdr;
- EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr;
-
- ASSERT (Pe32Data != NULL);
- ASSERT (EntryPoint != NULL);
-
- DosHdr = (EFI_IMAGE_DOS_HEADER *)Pe32Data;
- if (DosHdr->e_magic == EFI_IMAGE_DOS_SIGNATURE) {
- //
- // DOS image header is present, so read the PE header after the DOS image header.
- //
- Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *)((UINTN)Pe32Data + (UINTN)((DosHdr->e_lfanew) & 0x0ffff));
- } else {
- //
- // DOS image header is not present, so PE header is at the image base.
- //
- Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *)Pe32Data;
- }
-
- //
- // Calculate the entry point relative to the start of the image.
- // AddressOfEntryPoint is common for PE32 & PE32+
- //
- if (Hdr.Te->Signature == EFI_TE_IMAGE_HEADER_SIGNATURE) {
- *EntryPoint = (VOID *)((UINTN)Pe32Data + (UINTN)(Hdr.Te->AddressOfEntryPoint & 0x0ffffffff) + sizeof (EFI_TE_IMAGE_HEADER) - Hdr.Te->StrippedSize);
- return RETURN_SUCCESS;
- } else if (Hdr.Pe32->Signature == EFI_IMAGE_NT_SIGNATURE) {
- *EntryPoint = (VOID *)((UINTN)Pe32Data + (UINTN)(Hdr.Pe32->OptionalHeader.AddressOfEntryPoint & 0x0ffffffff));
- return RETURN_SUCCESS;
- }
-
- return RETURN_UNSUPPORTED;
-}
-
-/**
- Build driver info.
-
- @param ContextData Memory profile context.
- @param FileName File name of the image.
- @param ImageBase Image base address.
- @param ImageSize Image size.
- @param EntryPoint Entry point of the image.
- @param ImageSubsystem Image subsystem of the image.
- @param FileType File type of the image.
-
- @return Pointer to memory profile driver info.
-
-**/
-MEMORY_PROFILE_DRIVER_INFO_DATA *
-BuildDriverInfo (
- IN MEMORY_PROFILE_CONTEXT_DATA *ContextData,
- IN EFI_GUID *FileName,
- IN PHYSICAL_ADDRESS ImageBase,
- IN UINT64 ImageSize,
- IN PHYSICAL_ADDRESS EntryPoint,
- IN UINT16 ImageSubsystem,
- IN EFI_FV_FILETYPE FileType
- )
-{
- EFI_STATUS Status;
- MEMORY_PROFILE_DRIVER_INFO *DriverInfo;
- MEMORY_PROFILE_DRIVER_INFO_DATA *DriverInfoData;
- VOID *EntryPointInImage;
- CHAR8 *PdbString;
- UINTN PdbSize;
- UINTN PdbOccupiedSize;
-
- PdbSize = 0;
- PdbOccupiedSize = 0;
- PdbString = NULL;
- if (ImageBase != 0) {
- PdbString = PeCoffLoaderGetPdbPointer ((VOID *)(UINTN)ImageBase);
- if (PdbString != NULL) {
- PdbSize = AsciiStrSize (PdbString);
- PdbOccupiedSize = GET_OCCUPIED_SIZE (PdbSize, sizeof (UINT64));
- }
- }
-
- //
- // Use SmmInternalAllocatePool() that will not update profile for this AllocatePool action.
- //
- Status = SmmInternalAllocatePool (
- EfiRuntimeServicesData,
- sizeof (*DriverInfoData) + sizeof (LIST_ENTRY) + PdbSize,
- (VOID **)&DriverInfoData
- );
- if (EFI_ERROR (Status)) {
- return NULL;
- }
-
- ASSERT (DriverInfoData != NULL);
-
- ZeroMem (DriverInfoData, sizeof (*DriverInfoData));
-
- DriverInfo = &DriverInfoData->DriverInfo;
- DriverInfoData->Signature = MEMORY_PROFILE_DRIVER_INFO_SIGNATURE;
- DriverInfo->Header.Signature = MEMORY_PROFILE_DRIVER_INFO_SIGNATURE;
- DriverInfo->Header.Length = (UINT16)(sizeof (MEMORY_PROFILE_DRIVER_INFO) + PdbOccupiedSize);
- DriverInfo->Header.Revision = MEMORY_PROFILE_DRIVER_INFO_REVISION;
- if (FileName != NULL) {
- CopyMem (&DriverInfo->FileName, FileName, sizeof (EFI_GUID));
- }
-
- DriverInfo->ImageBase = ImageBase;
- DriverInfo->ImageSize = ImageSize;
- DriverInfo->EntryPoint = EntryPoint;
- DriverInfo->ImageSubsystem = ImageSubsystem;
- if ((EntryPoint != 0) && ((EntryPoint < ImageBase) || (EntryPoint >= (ImageBase + ImageSize)))) {
- //
- // If the EntryPoint is not in the range of image buffer, it should come from emulation environment.
- // So patch ImageBuffer here to align the EntryPoint.
- //
- Status = InternalPeCoffGetEntryPoint ((VOID *)(UINTN)ImageBase, &EntryPointInImage);
- ASSERT_EFI_ERROR (Status);
- DriverInfo->ImageBase = ImageBase + EntryPoint - (PHYSICAL_ADDRESS)(UINTN)EntryPointInImage;
- }
-
- DriverInfo->FileType = FileType;
- DriverInfoData->AllocInfoList = (LIST_ENTRY *)(DriverInfoData + 1);
- InitializeListHead (DriverInfoData->AllocInfoList);
- DriverInfo->CurrentUsage = 0;
- DriverInfo->PeakUsage = 0;
- DriverInfo->AllocRecordCount = 0;
- if (PdbSize != 0) {
- DriverInfo->PdbStringOffset = (UINT16)sizeof (MEMORY_PROFILE_DRIVER_INFO);
- DriverInfoData->PdbString = (CHAR8 *)(DriverInfoData->AllocInfoList + 1);
- CopyMem (DriverInfoData->PdbString, PdbString, PdbSize);
- } else {
- DriverInfo->PdbStringOffset = 0;
- DriverInfoData->PdbString = NULL;
- }
-
- InsertTailList (ContextData->DriverInfoList, &DriverInfoData->Link);
- ContextData->Context.ImageCount++;
- ContextData->Context.TotalImageSize += DriverInfo->ImageSize;
-
- return DriverInfoData;
-}
-
-/**
- Register image to DXE.
-
- @param FileName File name of the image.
- @param ImageBase Image base address.
- @param ImageSize Image size.
- @param FileType File type of the image.
-
-**/
-VOID
-RegisterImageToDxe (
- IN EFI_GUID *FileName,
- IN PHYSICAL_ADDRESS ImageBase,
- IN UINT64 ImageSize,
- IN EFI_FV_FILETYPE FileType
- )
-{
- EFI_STATUS Status;
- EDKII_MEMORY_PROFILE_PROTOCOL *ProfileProtocol;
- MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *FilePath;
- UINT8 TempBuffer[sizeof (MEDIA_FW_VOL_FILEPATH_DEVICE_PATH) + sizeof (EFI_DEVICE_PATH_PROTOCOL)];
-
- if (IS_UEFI_MEMORY_PROFILE_ENABLED) {
- FilePath = (MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *)TempBuffer;
- Status = gBS->LocateProtocol (&gEdkiiMemoryProfileGuid, NULL, (VOID **)&ProfileProtocol);
- if (!EFI_ERROR (Status)) {
- EfiInitializeFwVolDevicepathNode (FilePath, FileName);
- SetDevicePathEndNode (FilePath + 1);
-
- Status = ProfileProtocol->RegisterImage (
- ProfileProtocol,
- (EFI_DEVICE_PATH_PROTOCOL *)FilePath,
- ImageBase,
- ImageSize,
- FileType
- );
- }
- }
-}
-
-/**
- Unregister image from DXE.
-
- @param FileName File name of the image.
- @param ImageBase Image base address.
- @param ImageSize Image size.
-
-**/
-VOID
-UnregisterImageFromDxe (
- IN EFI_GUID *FileName,
- IN PHYSICAL_ADDRESS ImageBase,
- IN UINT64 ImageSize
- )
-{
- EFI_STATUS Status;
- EDKII_MEMORY_PROFILE_PROTOCOL *ProfileProtocol;
- MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *FilePath;
- UINT8 TempBuffer[sizeof (MEDIA_FW_VOL_FILEPATH_DEVICE_PATH) + sizeof (EFI_DEVICE_PATH_PROTOCOL)];
-
- if (IS_UEFI_MEMORY_PROFILE_ENABLED) {
- FilePath = (MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *)TempBuffer;
- Status = gBS->LocateProtocol (&gEdkiiMemoryProfileGuid, NULL, (VOID *)&ProfileProtocol);
- if (!EFI_ERROR (Status)) {
- EfiInitializeFwVolDevicepathNode (FilePath, FileName);
- SetDevicePathEndNode (FilePath + 1);
-
- Status = ProfileProtocol->UnregisterImage (
- ProfileProtocol,
- (EFI_DEVICE_PATH_PROTOCOL *)FilePath,
- ImageBase,
- ImageSize
- );
- }
- }
-}
-
-/**
- Return if record for this driver is needed..
-
- @param DriverFilePath Driver file path.
-
- @retval TRUE Record for this driver is needed.
- @retval FALSE Record for this driver is not needed.
-
-**/
-BOOLEAN
-NeedRecordThisDriver (
- IN EFI_DEVICE_PATH_PROTOCOL *DriverFilePath
- )
-{
- EFI_DEVICE_PATH_PROTOCOL *TmpDevicePath;
- EFI_DEVICE_PATH_PROTOCOL *DevicePathInstance;
- UINTN DevicePathSize;
- UINTN FilePathSize;
-
- if (!IsDevicePathValid (mSmramProfileDriverPath, mSmramProfileDriverPathSize)) {
- //
- // Invalid Device Path means record all.
- //
- return TRUE;
- }
-
- //
- // Record FilePath without end node.
- //
- FilePathSize = GetDevicePathSize (DriverFilePath) - sizeof (EFI_DEVICE_PATH_PROTOCOL);
-
- DevicePathInstance = mSmramProfileDriverPath;
- do {
- //
- // Find End node (it might be END_ENTIRE or END_INSTANCE)
- //
- TmpDevicePath = DevicePathInstance;
- while (!IsDevicePathEndType (TmpDevicePath)) {
- TmpDevicePath = NextDevicePathNode (TmpDevicePath);
- }
-
- //
- // Do not compare END node
- //
- DevicePathSize = (UINTN)TmpDevicePath - (UINTN)DevicePathInstance;
- if ((FilePathSize == DevicePathSize) &&
- (CompareMem (DriverFilePath, DevicePathInstance, DevicePathSize) == 0))
- {
- return TRUE;
- }
-
- //
- // Get next instance
- //
- DevicePathInstance = (EFI_DEVICE_PATH_PROTOCOL *)((UINTN)DevicePathInstance + DevicePathSize + DevicePathNodeLength (TmpDevicePath));
- } while (DevicePathSubType (TmpDevicePath) != END_ENTIRE_DEVICE_PATH_SUBTYPE);
-
- return FALSE;
-}
-
-/**
- Register SMM Core to SMRAM profile.
-
- @param ContextData SMRAM profile context.
-
- @retval TRUE Register success.
- @retval FALSE Register fail.
-
-**/
-BOOLEAN
-RegisterSmmCore (
- IN MEMORY_PROFILE_CONTEXT_DATA *ContextData
- )
-{
- MEMORY_PROFILE_DRIVER_INFO_DATA *DriverInfoData;
- PHYSICAL_ADDRESS ImageBase;
- UINT8 TempBuffer[sizeof (MEDIA_FW_VOL_FILEPATH_DEVICE_PATH) + sizeof (EFI_DEVICE_PATH_PROTOCOL)];
- MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *FilePath;
-
- FilePath = (MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *)TempBuffer;
- EfiInitializeFwVolDevicepathNode (FilePath, &gEfiCallerIdGuid);
- SetDevicePathEndNode (FilePath + 1);
-
- if (!NeedRecordThisDriver ((EFI_DEVICE_PATH_PROTOCOL *)FilePath)) {
- return FALSE;
- }
-
- ImageBase = gSmmCorePrivate->PiSmmCoreImageBase;
- DriverInfoData = BuildDriverInfo (
- ContextData,
- &gEfiCallerIdGuid,
- ImageBase,
- gSmmCorePrivate->PiSmmCoreImageSize,
- gSmmCorePrivate->PiSmmCoreEntryPoint,
- InternalPeCoffGetSubsystem ((VOID *)(UINTN)ImageBase),
- EFI_FV_FILETYPE_SMM_CORE
- );
- if (DriverInfoData == NULL) {
- return FALSE;
- }
-
- return TRUE;
-}
-
-/**
- Initialize SMRAM profile.
-
-**/
-VOID
-SmramProfileInit (
- VOID
- )
-{
- MEMORY_PROFILE_CONTEXT_DATA *SmramProfileContext;
-
- RegisterImageToDxe (
- &gEfiCallerIdGuid,
- gSmmCorePrivate->PiSmmCoreImageBase,
- gSmmCorePrivate->PiSmmCoreImageSize,
- EFI_FV_FILETYPE_SMM_CORE
- );
-
- if (!IS_SMRAM_PROFILE_ENABLED) {
- return;
- }
-
- SmramProfileContext = GetSmramProfileContext ();
- if (SmramProfileContext != NULL) {
- return;
- }
-
- mSmramProfileGettingStatus = FALSE;
- if ((PcdGet8 (PcdMemoryProfilePropertyMask) & BIT7) != 0) {
- mSmramProfileRecordingEnable = MEMORY_PROFILE_RECORDING_DISABLE;
- } else {
- mSmramProfileRecordingEnable = MEMORY_PROFILE_RECORDING_ENABLE;
- }
-
- mSmramProfileDriverPathSize = PcdGetSize (PcdMemoryProfileDriverPath);
- mSmramProfileDriverPath = AllocateCopyPool (mSmramProfileDriverPathSize, PcdGetPtr (PcdMemoryProfileDriverPath));
- mSmramProfileContextPtr = &mSmramProfileContext;
-
- RegisterSmmCore (&mSmramProfileContext);
-
- DEBUG ((DEBUG_INFO, "SmramProfileInit SmramProfileContext - 0x%x\n", &mSmramProfileContext));
-}
-
-/**
- Install SMRAM profile protocol.
-
-**/
-VOID
-SmramProfileInstallProtocol (
- VOID
- )
-{
- EFI_HANDLE Handle;
- EFI_STATUS Status;
-
- if (!IS_SMRAM_PROFILE_ENABLED) {
- return;
- }
-
- Handle = NULL;
- Status = SmmInstallProtocolInterface (
- &Handle,
- &gEdkiiSmmMemoryProfileGuid,
- EFI_NATIVE_INTERFACE,
- &mSmmProfileProtocol
- );
- ASSERT_EFI_ERROR (Status);
-}
-
-/**
- Get the GUID file name from the file path.
-
- @param FilePath File path.
-
- @return The GUID file name from the file path.
-
-**/
-EFI_GUID *
-GetFileNameFromFilePath (
- IN EFI_DEVICE_PATH_PROTOCOL *FilePath
- )
-{
- MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *ThisFilePath;
- EFI_GUID *FileName;
-
- FileName = NULL;
- if (FilePath != NULL) {
- ThisFilePath = (MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *)FilePath;
- while (!IsDevicePathEnd (ThisFilePath)) {
- FileName = EfiGetNameGuidFromFwVolDevicePathNode (ThisFilePath);
- if (FileName != NULL) {
- break;
- }
-
- ThisFilePath = (MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *)NextDevicePathNode (ThisFilePath);
- }
- }
-
- return FileName;
-}
-
-/**
- Register SMM image to SMRAM profile.
-
- @param DriverEntry SMM image info.
- @param RegisterToDxe Register image to DXE.
-
- @return EFI_SUCCESS Register successfully.
- @return EFI_UNSUPPORTED Memory profile is unsupported,
- or memory profile for the image is not required.
- @return EFI_OUT_OF_RESOURCES No enough resource for this register.
-
-**/
-EFI_STATUS
-RegisterSmramProfileImage (
- IN EFI_SMM_DRIVER_ENTRY *DriverEntry,
- IN BOOLEAN RegisterToDxe
- )
-{
- MEMORY_PROFILE_CONTEXT_DATA *ContextData;
- MEMORY_PROFILE_DRIVER_INFO_DATA *DriverInfoData;
- UINT8 TempBuffer[sizeof (MEDIA_FW_VOL_FILEPATH_DEVICE_PATH) + sizeof (EFI_DEVICE_PATH_PROTOCOL)];
- MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *FilePath;
-
- if (RegisterToDxe) {
- RegisterImageToDxe (
- &DriverEntry->FileName,
- DriverEntry->ImageBuffer,
- EFI_PAGES_TO_SIZE (DriverEntry->NumberOfPage),
- EFI_FV_FILETYPE_SMM
- );
- }
-
- if (!IS_SMRAM_PROFILE_ENABLED) {
- return EFI_UNSUPPORTED;
- }
-
- FilePath = (MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *)TempBuffer;
- EfiInitializeFwVolDevicepathNode (FilePath, &DriverEntry->FileName);
- SetDevicePathEndNode (FilePath + 1);
-
- if (!NeedRecordThisDriver ((EFI_DEVICE_PATH_PROTOCOL *)FilePath)) {
- return EFI_UNSUPPORTED;
- }
-
- ContextData = GetSmramProfileContext ();
- if (ContextData == NULL) {
- return EFI_UNSUPPORTED;
- }
-
- DriverInfoData = BuildDriverInfo (
- ContextData,
- &DriverEntry->FileName,
- DriverEntry->ImageBuffer,
- EFI_PAGES_TO_SIZE (DriverEntry->NumberOfPage),
- DriverEntry->ImageEntryPoint,
- InternalPeCoffGetSubsystem ((VOID *)(UINTN)DriverEntry->ImageBuffer),
- EFI_FV_FILETYPE_SMM
- );
- if (DriverInfoData == NULL) {
- return EFI_OUT_OF_RESOURCES;
- }
-
- return EFI_SUCCESS;
-}
-
-/**
- Search image from memory profile.
-
- @param ContextData Memory profile context.
- @param FileName Image file name.
- @param Address Image Address.
-
- @return Pointer to memory profile driver info.
-
-**/
-MEMORY_PROFILE_DRIVER_INFO_DATA *
-GetMemoryProfileDriverInfoByFileNameAndAddress (
- IN MEMORY_PROFILE_CONTEXT_DATA *ContextData,
- IN EFI_GUID *FileName,
- IN PHYSICAL_ADDRESS Address
- )
-{
- MEMORY_PROFILE_DRIVER_INFO *DriverInfo;
- MEMORY_PROFILE_DRIVER_INFO_DATA *DriverInfoData;
- LIST_ENTRY *DriverLink;
- LIST_ENTRY *DriverInfoList;
-
- DriverInfoList = ContextData->DriverInfoList;
-
- for (DriverLink = DriverInfoList->ForwardLink;
- DriverLink != DriverInfoList;
- DriverLink = DriverLink->ForwardLink)
- {
- DriverInfoData = CR (
- DriverLink,
- MEMORY_PROFILE_DRIVER_INFO_DATA,
- Link,
- MEMORY_PROFILE_DRIVER_INFO_SIGNATURE
- );
- DriverInfo = &DriverInfoData->DriverInfo;
- if ((CompareGuid (&DriverInfo->FileName, FileName)) &&
- (Address >= DriverInfo->ImageBase) &&
- (Address < (DriverInfo->ImageBase + DriverInfo->ImageSize)))
- {
- return DriverInfoData;
- }
- }
-
- return NULL;
-}
-
-/**
- Search image from memory profile.
- It will return image, if (Address >= ImageBuffer) AND (Address < ImageBuffer + ImageSize)
-
- @param ContextData Memory profile context.
- @param Address Image or Function address.
-
- @return Pointer to memory profile driver info.
-
-**/
-MEMORY_PROFILE_DRIVER_INFO_DATA *
-GetMemoryProfileDriverInfoFromAddress (
- IN MEMORY_PROFILE_CONTEXT_DATA *ContextData,
- IN PHYSICAL_ADDRESS Address
- )
-{
- MEMORY_PROFILE_DRIVER_INFO *DriverInfo;
- MEMORY_PROFILE_DRIVER_INFO_DATA *DriverInfoData;
- LIST_ENTRY *DriverLink;
- LIST_ENTRY *DriverInfoList;
-
- DriverInfoList = ContextData->DriverInfoList;
-
- for (DriverLink = DriverInfoList->ForwardLink;
- DriverLink != DriverInfoList;
- DriverLink = DriverLink->ForwardLink)
- {
- DriverInfoData = CR (
- DriverLink,
- MEMORY_PROFILE_DRIVER_INFO_DATA,
- Link,
- MEMORY_PROFILE_DRIVER_INFO_SIGNATURE
- );
- DriverInfo = &DriverInfoData->DriverInfo;
- if ((Address >= DriverInfo->ImageBase) &&
- (Address < (DriverInfo->ImageBase + DriverInfo->ImageSize)))
- {
- return DriverInfoData;
- }
- }
-
- return NULL;
-}
-
-/**
- Unregister image from SMRAM profile.
-
- @param DriverEntry SMM image info.
- @param UnregisterFromDxe Unregister image from DXE.
-
- @return EFI_SUCCESS Unregister successfully.
- @return EFI_UNSUPPORTED Memory profile is unsupported,
- or memory profile for the image is not required.
- @return EFI_NOT_FOUND The image is not found.
-
-**/
-EFI_STATUS
-UnregisterSmramProfileImage (
- IN EFI_SMM_DRIVER_ENTRY *DriverEntry,
- IN BOOLEAN UnregisterFromDxe
- )
-{
- EFI_STATUS Status;
- MEMORY_PROFILE_CONTEXT_DATA *ContextData;
- MEMORY_PROFILE_DRIVER_INFO_DATA *DriverInfoData;
- EFI_GUID *FileName;
- PHYSICAL_ADDRESS ImageAddress;
- VOID *EntryPointInImage;
- UINT8 TempBuffer[sizeof (MEDIA_FW_VOL_FILEPATH_DEVICE_PATH) + sizeof (EFI_DEVICE_PATH_PROTOCOL)];
- MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *FilePath;
-
- if (UnregisterFromDxe) {
- UnregisterImageFromDxe (
- &DriverEntry->FileName,
- DriverEntry->ImageBuffer,
- EFI_PAGES_TO_SIZE (DriverEntry->NumberOfPage)
- );
- }
-
- if (!IS_SMRAM_PROFILE_ENABLED) {
- return EFI_UNSUPPORTED;
- }
-
- FilePath = (MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *)TempBuffer;
- EfiInitializeFwVolDevicepathNode (FilePath, &DriverEntry->FileName);
- SetDevicePathEndNode (FilePath + 1);
-
- if (!NeedRecordThisDriver ((EFI_DEVICE_PATH_PROTOCOL *)FilePath)) {
- return EFI_UNSUPPORTED;
- }
-
- ContextData = GetSmramProfileContext ();
- if (ContextData == NULL) {
- return EFI_UNSUPPORTED;
- }
-
- DriverInfoData = NULL;
- FileName = &DriverEntry->FileName;
- ImageAddress = DriverEntry->ImageBuffer;
- if ((DriverEntry->ImageEntryPoint < ImageAddress) || (DriverEntry->ImageEntryPoint >= (ImageAddress + EFI_PAGES_TO_SIZE (DriverEntry->NumberOfPage)))) {
- //
- // If the EntryPoint is not in the range of image buffer, it should come from emulation environment.
- // So patch ImageAddress here to align the EntryPoint.
- //
- Status = InternalPeCoffGetEntryPoint ((VOID *)(UINTN)ImageAddress, &EntryPointInImage);
- ASSERT_EFI_ERROR (Status);
- ImageAddress = ImageAddress + (UINTN)DriverEntry->ImageEntryPoint - (UINTN)EntryPointInImage;
- }
-
- if (FileName != NULL) {
- DriverInfoData = GetMemoryProfileDriverInfoByFileNameAndAddress (ContextData, FileName, ImageAddress);
- }
-
- if (DriverInfoData == NULL) {
- DriverInfoData = GetMemoryProfileDriverInfoFromAddress (ContextData, ImageAddress);
- }
-
- if (DriverInfoData == NULL) {
- return EFI_NOT_FOUND;
- }
-
- ContextData->Context.TotalImageSize -= DriverInfoData->DriverInfo.ImageSize;
-
- // Keep the ImageBase for RVA calculation in Application.
- // DriverInfoData->DriverInfo.ImageBase = 0;
- DriverInfoData->DriverInfo.ImageSize = 0;
-
- if (DriverInfoData->DriverInfo.PeakUsage == 0) {
- ContextData->Context.ImageCount--;
- RemoveEntryList (&DriverInfoData->Link);
- //
- // Use SmmInternalFreePool() that will not update profile for this FreePool action.
- //
- SmmInternalFreePool (DriverInfoData);
- }
-
- return EFI_SUCCESS;
-}
-
-/**
- Return if this memory type needs to be recorded into memory profile.
- Only need to record EfiRuntimeServicesCode and EfiRuntimeServicesData for SMRAM profile.
-
- @param MemoryType Memory type.
-
- @retval TRUE This memory type need to be recorded.
- @retval FALSE This memory type need not to be recorded.
-
-**/
-BOOLEAN
-SmmCoreNeedRecordProfile (
- IN EFI_MEMORY_TYPE MemoryType
- )
-{
- UINT64 TestBit;
-
- if ((MemoryType != EfiRuntimeServicesCode) &&
- (MemoryType != EfiRuntimeServicesData))
- {
- return FALSE;
- }
-
- TestBit = LShiftU64 (1, MemoryType);
-
- if ((PcdGet64 (PcdMemoryProfileMemoryType) & TestBit) != 0) {
- return TRUE;
- } else {
- return FALSE;
- }
-}
-
-/**
- Convert EFI memory type to profile memory index. The rule is:
- If BIOS memory type (0 ~ EfiMaxMemoryType - 1), ProfileMemoryIndex = MemoryType.
- As SMRAM profile is only to record EfiRuntimeServicesCode and EfiRuntimeServicesData,
- so return input memory type directly.
-
- @param MemoryType Memory type.
-
- @return EFI memory type as profile memory index.
-
-**/
-EFI_MEMORY_TYPE
-GetProfileMemoryIndex (
- IN EFI_MEMORY_TYPE MemoryType
- )
-{
- return MemoryType;
-}
-
-/**
- Update SMRAM profile FreeMemoryPages information
-
- @param ContextData Memory profile context.
-
-**/
-VOID
-SmramProfileUpdateFreePages (
- IN MEMORY_PROFILE_CONTEXT_DATA *ContextData
- )
-{
- LIST_ENTRY *Node;
- FREE_PAGE_LIST *Pages;
- LIST_ENTRY *FreePageList;
- UINTN NumberOfPages;
-
- NumberOfPages = 0;
- FreePageList = &mSmmMemoryMap;
- for (Node = FreePageList->BackLink;
- Node != FreePageList;
- Node = Node->BackLink)
- {
- Pages = BASE_CR (Node, FREE_PAGE_LIST, Link);
- NumberOfPages += Pages->NumberOfPages;
- }
-
- mSmramFreeMemory.TotalFreeMemoryPages = NumberOfPages;
-
- if (NumberOfPages <= SMRAM_INFO_DUMP_PAGE_THRESHOLD) {
- DumpSmramInfo ();
- }
-}
-
-/**
- Update SMRAM profile Allocate information.
-
- @param CallerAddress Address of caller who call Allocate.
- @param Action This Allocate action.
- @param MemoryType Memory type.
- @param Size Buffer size.
- @param Buffer Buffer address.
- @param ActionString String for memory profile action.
-
- @return EFI_SUCCESS Memory profile is updated.
- @return EFI_UNSUPPORTED Memory profile is unsupported,
- or memory profile for the image is not required.
- @return EFI_OUT_OF_RESOURCES No enough resource to update memory profile for allocate action.
-
-**/
-EFI_STATUS
-SmmCoreUpdateProfileAllocate (
- IN PHYSICAL_ADDRESS CallerAddress,
- IN MEMORY_PROFILE_ACTION Action,
- IN EFI_MEMORY_TYPE MemoryType,
- IN UINTN Size,
- IN VOID *Buffer,
- IN CHAR8 *ActionString OPTIONAL
- )
-{
- EFI_STATUS Status;
- MEMORY_PROFILE_CONTEXT *Context;
- MEMORY_PROFILE_DRIVER_INFO *DriverInfo;
- MEMORY_PROFILE_ALLOC_INFO *AllocInfo;
- MEMORY_PROFILE_CONTEXT_DATA *ContextData;
- MEMORY_PROFILE_DRIVER_INFO_DATA *DriverInfoData;
- MEMORY_PROFILE_ALLOC_INFO_DATA *AllocInfoData;
- EFI_MEMORY_TYPE ProfileMemoryIndex;
- MEMORY_PROFILE_ACTION BasicAction;
- UINTN ActionStringSize;
- UINTN ActionStringOccupiedSize;
-
- BasicAction = Action & MEMORY_PROFILE_ACTION_BASIC_MASK;
-
- ContextData = GetSmramProfileContext ();
- if (ContextData == NULL) {
- return EFI_UNSUPPORTED;
- }
-
- DriverInfoData = GetMemoryProfileDriverInfoFromAddress (ContextData, CallerAddress);
- if (DriverInfoData == NULL) {
- return EFI_UNSUPPORTED;
- }
-
- ActionStringSize = 0;
- ActionStringOccupiedSize = 0;
- if (ActionString != NULL) {
- ActionStringSize = AsciiStrSize (ActionString);
- ActionStringOccupiedSize = GET_OCCUPIED_SIZE (ActionStringSize, sizeof (UINT64));
- }
-
- //
- // Use SmmInternalAllocatePool() that will not update profile for this AllocatePool action.
- //
- AllocInfoData = NULL;
- Status = SmmInternalAllocatePool (
- EfiRuntimeServicesData,
- sizeof (*AllocInfoData) + ActionStringSize,
- (VOID **)&AllocInfoData
- );
- if (EFI_ERROR (Status)) {
- return EFI_OUT_OF_RESOURCES;
- }
-
- ASSERT (AllocInfoData != NULL);
-
- //
- // Only update SequenceCount if and only if it is basic action.
- //
- if (Action == BasicAction) {
- ContextData->Context.SequenceCount++;
- }
-
- AllocInfo = &AllocInfoData->AllocInfo;
- AllocInfoData->Signature = MEMORY_PROFILE_ALLOC_INFO_SIGNATURE;
- AllocInfo->Header.Signature = MEMORY_PROFILE_ALLOC_INFO_SIGNATURE;
- AllocInfo->Header.Length = (UINT16)(sizeof (MEMORY_PROFILE_ALLOC_INFO) + ActionStringOccupiedSize);
- AllocInfo->Header.Revision = MEMORY_PROFILE_ALLOC_INFO_REVISION;
- AllocInfo->CallerAddress = CallerAddress;
- AllocInfo->SequenceId = ContextData->Context.SequenceCount;
- AllocInfo->Action = Action;
- AllocInfo->MemoryType = MemoryType;
- AllocInfo->Buffer = (PHYSICAL_ADDRESS)(UINTN)Buffer;
- AllocInfo->Size = Size;
- if (ActionString != NULL) {
- AllocInfo->ActionStringOffset = (UINT16)sizeof (MEMORY_PROFILE_ALLOC_INFO);
- AllocInfoData->ActionString = (CHAR8 *)(AllocInfoData + 1);
- CopyMem (AllocInfoData->ActionString, ActionString, ActionStringSize);
- } else {
- AllocInfo->ActionStringOffset = 0;
- AllocInfoData->ActionString = NULL;
- }
-
- InsertTailList (DriverInfoData->AllocInfoList, &AllocInfoData->Link);
-
- Context = &ContextData->Context;
- DriverInfo = &DriverInfoData->DriverInfo;
- DriverInfo->AllocRecordCount++;
-
- //
- // Update summary if and only if it is basic action.
- //
- if (Action == BasicAction) {
- ProfileMemoryIndex = GetProfileMemoryIndex (MemoryType);
-
- DriverInfo->CurrentUsage += Size;
- if (DriverInfo->PeakUsage < DriverInfo->CurrentUsage) {
- DriverInfo->PeakUsage = DriverInfo->CurrentUsage;
- }
-
- DriverInfo->CurrentUsageByType[ProfileMemoryIndex] += Size;
- if (DriverInfo->PeakUsageByType[ProfileMemoryIndex] < DriverInfo->CurrentUsageByType[ProfileMemoryIndex]) {
- DriverInfo->PeakUsageByType[ProfileMemoryIndex] = DriverInfo->CurrentUsageByType[ProfileMemoryIndex];
- }
-
- Context->CurrentTotalUsage += Size;
- if (Context->PeakTotalUsage < Context->CurrentTotalUsage) {
- Context->PeakTotalUsage = Context->CurrentTotalUsage;
- }
-
- Context->CurrentTotalUsageByType[ProfileMemoryIndex] += Size;
- if (Context->PeakTotalUsageByType[ProfileMemoryIndex] < Context->CurrentTotalUsageByType[ProfileMemoryIndex]) {
- Context->PeakTotalUsageByType[ProfileMemoryIndex] = Context->CurrentTotalUsageByType[ProfileMemoryIndex];
- }
-
- SmramProfileUpdateFreePages (ContextData);
- }
-
- return EFI_SUCCESS;
-}
-
-/**
- Get memory profile alloc info from memory profile
-
- @param DriverInfoData Driver info
- @param BasicAction This Free basic action
- @param Size Buffer size
- @param Buffer Buffer address
-
- @return Pointer to memory profile alloc info.
-**/
-MEMORY_PROFILE_ALLOC_INFO_DATA *
-GetMemoryProfileAllocInfoFromAddress (
- IN MEMORY_PROFILE_DRIVER_INFO_DATA *DriverInfoData,
- IN MEMORY_PROFILE_ACTION BasicAction,
- IN UINTN Size,
- IN VOID *Buffer
- )
-{
- LIST_ENTRY *AllocInfoList;
- LIST_ENTRY *AllocLink;
- MEMORY_PROFILE_ALLOC_INFO *AllocInfo;
- MEMORY_PROFILE_ALLOC_INFO_DATA *AllocInfoData;
-
- AllocInfoList = DriverInfoData->AllocInfoList;
-
- for (AllocLink = AllocInfoList->ForwardLink;
- AllocLink != AllocInfoList;
- AllocLink = AllocLink->ForwardLink)
- {
- AllocInfoData = CR (
- AllocLink,
- MEMORY_PROFILE_ALLOC_INFO_DATA,
- Link,
- MEMORY_PROFILE_ALLOC_INFO_SIGNATURE
- );
- AllocInfo = &AllocInfoData->AllocInfo;
- if ((AllocInfo->Action & MEMORY_PROFILE_ACTION_BASIC_MASK) != BasicAction) {
- continue;
- }
-
- switch (BasicAction) {
- case MemoryProfileActionAllocatePages:
- if ((AllocInfo->Buffer <= (PHYSICAL_ADDRESS)(UINTN)Buffer) &&
- ((AllocInfo->Buffer + AllocInfo->Size) >= ((PHYSICAL_ADDRESS)(UINTN)Buffer + Size)))
- {
- return AllocInfoData;
- }
-
- break;
- case MemoryProfileActionAllocatePool:
- if (AllocInfo->Buffer == (PHYSICAL_ADDRESS)(UINTN)Buffer) {
- return AllocInfoData;
- }
-
- break;
- default:
- ASSERT (FALSE);
- break;
- }
- }
-
- return NULL;
-}
-
-/**
- Update SMRAM profile Free information.
-
- @param CallerAddress Address of caller who call Free.
- @param Action This Free action.
- @param Size Buffer size.
- @param Buffer Buffer address.
-
- @return EFI_SUCCESS Memory profile is updated.
- @return EFI_UNSUPPORTED Memory profile is unsupported.
- @return EFI_NOT_FOUND No matched allocate info found for free action.
-
-**/
-EFI_STATUS
-SmmCoreUpdateProfileFree (
- IN PHYSICAL_ADDRESS CallerAddress,
- IN MEMORY_PROFILE_ACTION Action,
- IN UINTN Size,
- IN VOID *Buffer
- )
-{
- MEMORY_PROFILE_CONTEXT *Context;
- MEMORY_PROFILE_DRIVER_INFO *DriverInfo;
- MEMORY_PROFILE_ALLOC_INFO *AllocInfo;
- MEMORY_PROFILE_CONTEXT_DATA *ContextData;
- MEMORY_PROFILE_DRIVER_INFO_DATA *DriverInfoData;
- LIST_ENTRY *DriverLink;
- LIST_ENTRY *DriverInfoList;
- MEMORY_PROFILE_DRIVER_INFO_DATA *ThisDriverInfoData;
- MEMORY_PROFILE_ALLOC_INFO_DATA *AllocInfoData;
- EFI_MEMORY_TYPE ProfileMemoryIndex;
- MEMORY_PROFILE_ACTION BasicAction;
- BOOLEAN Found;
-
- BasicAction = Action & MEMORY_PROFILE_ACTION_BASIC_MASK;
-
- ContextData = GetSmramProfileContext ();
- if (ContextData == NULL) {
- return EFI_UNSUPPORTED;
- }
-
- DriverInfoData = GetMemoryProfileDriverInfoFromAddress (ContextData, CallerAddress);
-
- //
- // Do not return if DriverInfoData == NULL here,
- // because driver A might free memory allocated by driver B.
- //
-
- //
- // Need use do-while loop to find all possible record,
- // because one address might be recorded multiple times.
- //
- Found = FALSE;
- AllocInfoData = NULL;
- do {
- if (DriverInfoData != NULL) {
- switch (BasicAction) {
- case MemoryProfileActionFreePages:
- AllocInfoData = GetMemoryProfileAllocInfoFromAddress (DriverInfoData, MemoryProfileActionAllocatePages, Size, Buffer);
- break;
- case MemoryProfileActionFreePool:
- AllocInfoData = GetMemoryProfileAllocInfoFromAddress (DriverInfoData, MemoryProfileActionAllocatePool, 0, Buffer);
- break;
- default:
- ASSERT (FALSE);
- AllocInfoData = NULL;
- break;
- }
- }
-
- if (AllocInfoData == NULL) {
- //
- // Legal case, because driver A might free memory allocated by driver B, by some protocol.
- //
- DriverInfoList = ContextData->DriverInfoList;
-
- for (DriverLink = DriverInfoList->ForwardLink;
- DriverLink != DriverInfoList;
- DriverLink = DriverLink->ForwardLink)
- {
- ThisDriverInfoData = CR (
- DriverLink,
- MEMORY_PROFILE_DRIVER_INFO_DATA,
- Link,
- MEMORY_PROFILE_DRIVER_INFO_SIGNATURE
- );
- switch (BasicAction) {
- case MemoryProfileActionFreePages:
- AllocInfoData = GetMemoryProfileAllocInfoFromAddress (ThisDriverInfoData, MemoryProfileActionAllocatePages, Size, Buffer);
- break;
- case MemoryProfileActionFreePool:
- AllocInfoData = GetMemoryProfileAllocInfoFromAddress (ThisDriverInfoData, MemoryProfileActionAllocatePool, 0, Buffer);
- break;
- default:
- ASSERT (FALSE);
- AllocInfoData = NULL;
- break;
- }
-
- if (AllocInfoData != NULL) {
- DriverInfoData = ThisDriverInfoData;
- break;
- }
- }
-
- if (AllocInfoData == NULL) {
- //
- // If (!Found), no matched allocate info is found for this free action.
- // It is because the specified memory type allocate actions have been filtered by
- // CoreNeedRecordProfile(), but free actions have no memory type information,
- // they can not be filtered by CoreNeedRecordProfile(). Then, they will be
- // filtered here.
- //
- // If (Found), it is normal exit path.
- return (Found ? EFI_SUCCESS : EFI_NOT_FOUND);
- }
- }
-
- ASSERT (DriverInfoData != NULL);
- ASSERT (AllocInfoData != NULL);
-
- Found = TRUE;
-
- Context = &ContextData->Context;
- DriverInfo = &DriverInfoData->DriverInfo;
- AllocInfo = &AllocInfoData->AllocInfo;
-
- DriverInfo->AllocRecordCount--;
- //
- // Update summary if and only if it is basic action.
- //
- if (AllocInfo->Action == (AllocInfo->Action & MEMORY_PROFILE_ACTION_BASIC_MASK)) {
- ProfileMemoryIndex = GetProfileMemoryIndex (AllocInfo->MemoryType);
-
- Context->CurrentTotalUsage -= AllocInfo->Size;
- Context->CurrentTotalUsageByType[ProfileMemoryIndex] -= AllocInfo->Size;
-
- DriverInfo->CurrentUsage -= AllocInfo->Size;
- DriverInfo->CurrentUsageByType[ProfileMemoryIndex] -= AllocInfo->Size;
- }
-
- RemoveEntryList (&AllocInfoData->Link);
-
- if (BasicAction == MemoryProfileActionFreePages) {
- if (AllocInfo->Buffer != (PHYSICAL_ADDRESS)(UINTN)Buffer) {
- SmmCoreUpdateProfileAllocate (
- AllocInfo->CallerAddress,
- AllocInfo->Action,
- AllocInfo->MemoryType,
- (UINTN)((PHYSICAL_ADDRESS)(UINTN)Buffer - AllocInfo->Buffer),
- (VOID *)(UINTN)AllocInfo->Buffer,
- AllocInfoData->ActionString
- );
- }
-
- if (AllocInfo->Buffer + AllocInfo->Size != ((PHYSICAL_ADDRESS)(UINTN)Buffer + Size)) {
- SmmCoreUpdateProfileAllocate (
- AllocInfo->CallerAddress,
- AllocInfo->Action,
- AllocInfo->MemoryType,
- (UINTN)((AllocInfo->Buffer + AllocInfo->Size) - ((PHYSICAL_ADDRESS)(UINTN)Buffer + Size)),
- (VOID *)((UINTN)Buffer + Size),
- AllocInfoData->ActionString
- );
- }
- }
-
- //
- // Use SmmInternalFreePool() that will not update profile for this FreePool action.
- //
- SmmInternalFreePool (AllocInfoData);
- } while (TRUE);
-}
-
-/**
- Update SMRAM profile information.
-
- @param CallerAddress Address of caller who call Allocate or Free.
- @param Action This Allocate or Free action.
- @param MemoryType Memory type.
- EfiMaxMemoryType means the MemoryType is unknown.
- @param Size Buffer size.
- @param Buffer Buffer address.
- @param ActionString String for memory profile action.
- Only needed for user defined allocate action.
-
- @return EFI_SUCCESS Memory profile is updated.
- @return EFI_UNSUPPORTED Memory profile is unsupported,
- or memory profile for the image is not required,
- or memory profile for the memory type is not required.
- @return EFI_ACCESS_DENIED It is during memory profile data getting.
- @return EFI_ABORTED Memory profile recording is not enabled.
- @return EFI_OUT_OF_RESOURCES No enough resource to update memory profile for allocate action.
- @return EFI_NOT_FOUND No matched allocate info found for free action.
-
-**/
-EFI_STATUS
-EFIAPI
-SmmCoreUpdateProfile (
- IN PHYSICAL_ADDRESS CallerAddress,
- IN MEMORY_PROFILE_ACTION Action,
- IN EFI_MEMORY_TYPE MemoryType, // Valid for AllocatePages/AllocatePool
- IN UINTN Size, // Valid for AllocatePages/FreePages/AllocatePool
- IN VOID *Buffer,
- IN CHAR8 *ActionString OPTIONAL
- )
-{
- EFI_STATUS Status;
- MEMORY_PROFILE_CONTEXT_DATA *ContextData;
- MEMORY_PROFILE_ACTION BasicAction;
-
- if (!IS_SMRAM_PROFILE_ENABLED) {
- return EFI_UNSUPPORTED;
- }
-
- if (mSmramProfileGettingStatus) {
- return EFI_ACCESS_DENIED;
- }
-
- if (!mSmramProfileRecordingEnable) {
- return EFI_ABORTED;
- }
-
- //
- // Get the basic action to know how to process the record
- //
- BasicAction = Action & MEMORY_PROFILE_ACTION_BASIC_MASK;
-
- //
- // Free operations have no memory type information, so skip the check.
- //
- if ((BasicAction == MemoryProfileActionAllocatePages) || (BasicAction == MemoryProfileActionAllocatePool)) {
- //
- // Only record limited MemoryType.
- //
- if (!SmmCoreNeedRecordProfile (MemoryType)) {
- return EFI_UNSUPPORTED;
- }
- }
-
- ContextData = GetSmramProfileContext ();
- if (ContextData == NULL) {
- return EFI_UNSUPPORTED;
- }
-
- switch (BasicAction) {
- case MemoryProfileActionAllocatePages:
- Status = SmmCoreUpdateProfileAllocate (CallerAddress, Action, MemoryType, Size, Buffer, ActionString);
- break;
- case MemoryProfileActionFreePages:
- Status = SmmCoreUpdateProfileFree (CallerAddress, Action, Size, Buffer);
- break;
- case MemoryProfileActionAllocatePool:
- Status = SmmCoreUpdateProfileAllocate (CallerAddress, Action, MemoryType, Size, Buffer, ActionString);
- break;
- case MemoryProfileActionFreePool:
- Status = SmmCoreUpdateProfileFree (CallerAddress, Action, 0, Buffer);
- break;
- default:
- ASSERT (FALSE);
- Status = EFI_UNSUPPORTED;
- break;
- }
-
- return Status;
-}
-
-/**
- SMRAM profile ready to lock callback function.
-
-**/
-VOID
-SmramProfileReadyToLock (
- VOID
- )
-{
- if (!IS_SMRAM_PROFILE_ENABLED) {
- return;
- }
-
- DEBUG ((DEBUG_INFO, "SmramProfileReadyToLock\n"));
- mSmramReadyToLock = TRUE;
-}
-
-////////////////////
-
-/**
- Get SMRAM profile data size.
-
- @return SMRAM profile data size.
-
-**/
-UINTN
-SmramProfileGetDataSize (
- VOID
- )
-{
- MEMORY_PROFILE_CONTEXT_DATA *ContextData;
- MEMORY_PROFILE_DRIVER_INFO_DATA *DriverInfoData;
- MEMORY_PROFILE_ALLOC_INFO_DATA *AllocInfoData;
- LIST_ENTRY *DriverInfoList;
- LIST_ENTRY *DriverLink;
- LIST_ENTRY *AllocInfoList;
- LIST_ENTRY *AllocLink;
- UINTN TotalSize;
- LIST_ENTRY *Node;
- LIST_ENTRY *FreePageList;
- LIST_ENTRY *FreePoolList;
- FREE_POOL_HEADER *Pool;
- UINTN PoolListIndex;
- UINTN Index;
- UINTN SmmPoolTypeIndex;
-
- ContextData = GetSmramProfileContext ();
- if (ContextData == NULL) {
- return 0;
- }
-
- TotalSize = sizeof (MEMORY_PROFILE_CONTEXT);
-
- DriverInfoList = ContextData->DriverInfoList;
- for (DriverLink = DriverInfoList->ForwardLink;
- DriverLink != DriverInfoList;
- DriverLink = DriverLink->ForwardLink)
- {
- DriverInfoData = CR (
- DriverLink,
- MEMORY_PROFILE_DRIVER_INFO_DATA,
- Link,
- MEMORY_PROFILE_DRIVER_INFO_SIGNATURE
- );
- TotalSize += DriverInfoData->DriverInfo.Header.Length;
-
- AllocInfoList = DriverInfoData->AllocInfoList;
- for (AllocLink = AllocInfoList->ForwardLink;
- AllocLink != AllocInfoList;
- AllocLink = AllocLink->ForwardLink)
- {
- AllocInfoData = CR (
- AllocLink,
- MEMORY_PROFILE_ALLOC_INFO_DATA,
- Link,
- MEMORY_PROFILE_ALLOC_INFO_SIGNATURE
- );
- TotalSize += AllocInfoData->AllocInfo.Header.Length;
- }
- }
-
- Index = 0;
- FreePageList = &mSmmMemoryMap;
- for (Node = FreePageList->BackLink;
- Node != FreePageList;
- Node = Node->BackLink)
- {
- Index++;
- }
-
- for (SmmPoolTypeIndex = 0; SmmPoolTypeIndex < SmmPoolTypeMax; SmmPoolTypeIndex++) {
- for (PoolListIndex = 0; PoolListIndex < MAX_POOL_INDEX; PoolListIndex++) {
- FreePoolList = &mSmmPoolLists[SmmPoolTypeIndex][PoolListIndex];
- for (Node = FreePoolList->BackLink;
- Node != FreePoolList;
- Node = Node->BackLink)
- {
- Pool = BASE_CR (Node, FREE_POOL_HEADER, Link);
- if (Pool->Header.Available) {
- Index++;
- }
- }
- }
- }
-
- TotalSize += (sizeof (MEMORY_PROFILE_FREE_MEMORY) + Index * sizeof (MEMORY_PROFILE_DESCRIPTOR));
- TotalSize += (sizeof (MEMORY_PROFILE_MEMORY_RANGE) + mFullSmramRangeCount * sizeof (MEMORY_PROFILE_DESCRIPTOR));
-
- return TotalSize;
-}
-
-/**
- Copy SMRAM profile data.
-
- @param ProfileBuffer The buffer to hold SMRAM profile data.
- @param ProfileSize On input, profile buffer size.
- On output, actual profile data size copied.
- @param ProfileOffset On input, profile buffer offset to copy.
- On output, next time profile buffer offset to copy.
-
-**/
-VOID
-SmramProfileCopyData (
- OUT VOID *ProfileBuffer,
- IN OUT UINT64 *ProfileSize,
- IN OUT UINT64 *ProfileOffset
- )
-{
- MEMORY_PROFILE_CONTEXT *Context;
- MEMORY_PROFILE_DRIVER_INFO *DriverInfo;
- MEMORY_PROFILE_ALLOC_INFO *AllocInfo;
- MEMORY_PROFILE_CONTEXT_DATA *ContextData;
- MEMORY_PROFILE_DRIVER_INFO_DATA *DriverInfoData;
- MEMORY_PROFILE_ALLOC_INFO_DATA *AllocInfoData;
- LIST_ENTRY *DriverInfoList;
- LIST_ENTRY *DriverLink;
- LIST_ENTRY *AllocInfoList;
- LIST_ENTRY *AllocLink;
- LIST_ENTRY *Node;
- FREE_PAGE_LIST *Pages;
- LIST_ENTRY *FreePageList;
- LIST_ENTRY *FreePoolList;
- FREE_POOL_HEADER *Pool;
- UINTN PoolListIndex;
- UINT32 Index;
- MEMORY_PROFILE_FREE_MEMORY *FreeMemory;
- MEMORY_PROFILE_MEMORY_RANGE *MemoryRange;
- MEMORY_PROFILE_DESCRIPTOR *MemoryProfileDescriptor;
- UINT64 Offset;
- UINT64 RemainingSize;
- UINTN PdbSize;
- UINTN ActionStringSize;
- UINTN SmmPoolTypeIndex;
-
- ContextData = GetSmramProfileContext ();
- if (ContextData == NULL) {
- return;
- }
-
- RemainingSize = *ProfileSize;
- Offset = 0;
-
- if (*ProfileOffset < sizeof (MEMORY_PROFILE_CONTEXT)) {
- if (RemainingSize >= sizeof (MEMORY_PROFILE_CONTEXT)) {
- Context = ProfileBuffer;
- CopyMem (Context, &ContextData->Context, sizeof (MEMORY_PROFILE_CONTEXT));
- RemainingSize -= sizeof (MEMORY_PROFILE_CONTEXT);
- ProfileBuffer = (UINT8 *)ProfileBuffer + sizeof (MEMORY_PROFILE_CONTEXT);
- } else {
- goto Done;
- }
- }
-
- Offset += sizeof (MEMORY_PROFILE_CONTEXT);
-
- DriverInfoList = ContextData->DriverInfoList;
- for (DriverLink = DriverInfoList->ForwardLink;
- DriverLink != DriverInfoList;
- DriverLink = DriverLink->ForwardLink)
- {
- DriverInfoData = CR (
- DriverLink,
- MEMORY_PROFILE_DRIVER_INFO_DATA,
- Link,
- MEMORY_PROFILE_DRIVER_INFO_SIGNATURE
- );
- if (*ProfileOffset < (Offset + DriverInfoData->DriverInfo.Header.Length)) {
- if (RemainingSize >= DriverInfoData->DriverInfo.Header.Length) {
- DriverInfo = ProfileBuffer;
- CopyMem (DriverInfo, &DriverInfoData->DriverInfo, sizeof (MEMORY_PROFILE_DRIVER_INFO));
- if (DriverInfo->PdbStringOffset != 0) {
- PdbSize = AsciiStrSize (DriverInfoData->PdbString);
- CopyMem ((VOID *)((UINTN)DriverInfo + DriverInfo->PdbStringOffset), DriverInfoData->PdbString, PdbSize);
- }
-
- RemainingSize -= DriverInfo->Header.Length;
- ProfileBuffer = (UINT8 *)ProfileBuffer + DriverInfo->Header.Length;
- } else {
- goto Done;
- }
- }
-
- Offset += DriverInfoData->DriverInfo.Header.Length;
-
- AllocInfoList = DriverInfoData->AllocInfoList;
- for (AllocLink = AllocInfoList->ForwardLink;
- AllocLink != AllocInfoList;
- AllocLink = AllocLink->ForwardLink)
- {
- AllocInfoData = CR (
- AllocLink,
- MEMORY_PROFILE_ALLOC_INFO_DATA,
- Link,
- MEMORY_PROFILE_ALLOC_INFO_SIGNATURE
- );
- if (*ProfileOffset < (Offset + AllocInfoData->AllocInfo.Header.Length)) {
- if (RemainingSize >= AllocInfoData->AllocInfo.Header.Length) {
- AllocInfo = ProfileBuffer;
- CopyMem (AllocInfo, &AllocInfoData->AllocInfo, sizeof (MEMORY_PROFILE_ALLOC_INFO));
- if (AllocInfo->ActionStringOffset) {
- ActionStringSize = AsciiStrSize (AllocInfoData->ActionString);
- CopyMem ((VOID *)((UINTN)AllocInfo + AllocInfo->ActionStringOffset), AllocInfoData->ActionString, ActionStringSize);
- }
-
- RemainingSize -= AllocInfo->Header.Length;
- ProfileBuffer = (UINT8 *)ProfileBuffer + AllocInfo->Header.Length;
- } else {
- goto Done;
- }
- }
-
- Offset += AllocInfoData->AllocInfo.Header.Length;
- }
- }
-
- if (*ProfileOffset < (Offset + sizeof (MEMORY_PROFILE_FREE_MEMORY))) {
- if (RemainingSize >= sizeof (MEMORY_PROFILE_FREE_MEMORY)) {
- FreeMemory = ProfileBuffer;
- CopyMem (FreeMemory, &mSmramFreeMemory, sizeof (MEMORY_PROFILE_FREE_MEMORY));
- Index = 0;
- FreePageList = &mSmmMemoryMap;
- for (Node = FreePageList->BackLink;
- Node != FreePageList;
- Node = Node->BackLink)
- {
- Index++;
- }
-
- for (SmmPoolTypeIndex = 0; SmmPoolTypeIndex < SmmPoolTypeMax; SmmPoolTypeIndex++) {
- for (PoolListIndex = 0; PoolListIndex < MAX_POOL_INDEX; PoolListIndex++) {
- FreePoolList = &mSmmPoolLists[SmmPoolTypeIndex][MAX_POOL_INDEX - PoolListIndex - 1];
- for (Node = FreePoolList->BackLink;
- Node != FreePoolList;
- Node = Node->BackLink)
- {
- Pool = BASE_CR (Node, FREE_POOL_HEADER, Link);
- if (Pool->Header.Available) {
- Index++;
- }
- }
- }
- }
-
- FreeMemory->FreeMemoryEntryCount = Index;
-
- RemainingSize -= sizeof (MEMORY_PROFILE_FREE_MEMORY);
- ProfileBuffer = (UINT8 *)ProfileBuffer + sizeof (MEMORY_PROFILE_FREE_MEMORY);
- } else {
- goto Done;
- }
- }
-
- Offset += sizeof (MEMORY_PROFILE_FREE_MEMORY);
- FreePageList = &mSmmMemoryMap;
- for (Node = FreePageList->BackLink;
- Node != FreePageList;
- Node = Node->BackLink)
- {
- if (*ProfileOffset < (Offset + sizeof (MEMORY_PROFILE_DESCRIPTOR))) {
- if (RemainingSize >= sizeof (MEMORY_PROFILE_DESCRIPTOR)) {
- Pages = BASE_CR (Node, FREE_PAGE_LIST, Link);
- MemoryProfileDescriptor = ProfileBuffer;
- MemoryProfileDescriptor->Header.Signature = MEMORY_PROFILE_DESCRIPTOR_SIGNATURE;
- MemoryProfileDescriptor->Header.Length = sizeof (MEMORY_PROFILE_DESCRIPTOR);
- MemoryProfileDescriptor->Header.Revision = MEMORY_PROFILE_DESCRIPTOR_REVISION;
- MemoryProfileDescriptor->Address = (PHYSICAL_ADDRESS)(UINTN)Pages;
- MemoryProfileDescriptor->Size = EFI_PAGES_TO_SIZE (Pages->NumberOfPages);
-
- RemainingSize -= sizeof (MEMORY_PROFILE_DESCRIPTOR);
- ProfileBuffer = (UINT8 *)ProfileBuffer + sizeof (MEMORY_PROFILE_DESCRIPTOR);
- } else {
- goto Done;
- }
- }
-
- Offset += sizeof (MEMORY_PROFILE_DESCRIPTOR);
- }
-
- for (SmmPoolTypeIndex = 0; SmmPoolTypeIndex < SmmPoolTypeMax; SmmPoolTypeIndex++) {
- for (PoolListIndex = 0; PoolListIndex < MAX_POOL_INDEX; PoolListIndex++) {
- FreePoolList = &mSmmPoolLists[SmmPoolTypeIndex][MAX_POOL_INDEX - PoolListIndex - 1];
- for (Node = FreePoolList->BackLink;
- Node != FreePoolList;
- Node = Node->BackLink)
- {
- Pool = BASE_CR (Node, FREE_POOL_HEADER, Link);
- if (Pool->Header.Available) {
- if (*ProfileOffset < (Offset + sizeof (MEMORY_PROFILE_DESCRIPTOR))) {
- if (RemainingSize >= sizeof (MEMORY_PROFILE_DESCRIPTOR)) {
- MemoryProfileDescriptor = ProfileBuffer;
- MemoryProfileDescriptor->Header.Signature = MEMORY_PROFILE_DESCRIPTOR_SIGNATURE;
- MemoryProfileDescriptor->Header.Length = sizeof (MEMORY_PROFILE_DESCRIPTOR);
- MemoryProfileDescriptor->Header.Revision = MEMORY_PROFILE_DESCRIPTOR_REVISION;
- MemoryProfileDescriptor->Address = (PHYSICAL_ADDRESS)(UINTN)Pool;
- MemoryProfileDescriptor->Size = Pool->Header.Size;
-
- RemainingSize -= sizeof (MEMORY_PROFILE_DESCRIPTOR);
- ProfileBuffer = (UINT8 *)ProfileBuffer + sizeof (MEMORY_PROFILE_DESCRIPTOR);
- } else {
- goto Done;
- }
- }
-
- Offset += sizeof (MEMORY_PROFILE_DESCRIPTOR);
- }
- }
- }
- }
-
- if (*ProfileOffset < (Offset + sizeof (MEMORY_PROFILE_MEMORY_RANGE))) {
- if (RemainingSize >= sizeof (MEMORY_PROFILE_MEMORY_RANGE)) {
- MemoryRange = ProfileBuffer;
- MemoryRange->Header.Signature = MEMORY_PROFILE_MEMORY_RANGE_SIGNATURE;
- MemoryRange->Header.Length = sizeof (MEMORY_PROFILE_MEMORY_RANGE);
- MemoryRange->Header.Revision = MEMORY_PROFILE_MEMORY_RANGE_REVISION;
- MemoryRange->MemoryRangeCount = (UINT32)mFullSmramRangeCount;
-
- RemainingSize -= sizeof (MEMORY_PROFILE_MEMORY_RANGE);
- ProfileBuffer = (UINT8 *)ProfileBuffer + sizeof (MEMORY_PROFILE_MEMORY_RANGE);
- } else {
- goto Done;
- }
- }
-
- Offset += sizeof (MEMORY_PROFILE_MEMORY_RANGE);
- for (Index = 0; Index < mFullSmramRangeCount; Index++) {
- if (*ProfileOffset < (Offset + sizeof (MEMORY_PROFILE_DESCRIPTOR))) {
- if (RemainingSize >= sizeof (MEMORY_PROFILE_DESCRIPTOR)) {
- MemoryProfileDescriptor = ProfileBuffer;
- MemoryProfileDescriptor->Header.Signature = MEMORY_PROFILE_DESCRIPTOR_SIGNATURE;
- MemoryProfileDescriptor->Header.Length = sizeof (MEMORY_PROFILE_DESCRIPTOR);
- MemoryProfileDescriptor->Header.Revision = MEMORY_PROFILE_DESCRIPTOR_REVISION;
- MemoryProfileDescriptor->Address = mFullSmramRanges[Index].PhysicalStart;
- MemoryProfileDescriptor->Size = mFullSmramRanges[Index].PhysicalSize;
-
- RemainingSize -= sizeof (MEMORY_PROFILE_DESCRIPTOR);
- ProfileBuffer = (UINT8 *)ProfileBuffer + sizeof (MEMORY_PROFILE_DESCRIPTOR);
- } else {
- goto Done;
- }
- }
-
- Offset += sizeof (MEMORY_PROFILE_DESCRIPTOR);
- }
-
-Done:
- //
- // On output, actual profile data size copied.
- //
- *ProfileSize -= RemainingSize;
- //
- // On output, next time profile buffer offset to copy.
- //
- *ProfileOffset = Offset;
-}
-
-/**
- Get memory profile data.
-
- @param[in] This The EDKII_SMM_MEMORY_PROFILE_PROTOCOL instance.
- @param[in, out] ProfileSize On entry, points to the size in bytes of the ProfileBuffer.
- On return, points to the size of the data returned in ProfileBuffer.
- @param[out] ProfileBuffer Profile buffer.
-
- @return EFI_SUCCESS Get the memory profile data successfully.
- @return EFI_UNSUPPORTED Memory profile is unsupported.
- @return EFI_BUFFER_TO_SMALL The ProfileSize is too small for the resulting data.
- ProfileSize is updated with the size required.
-
-**/
-EFI_STATUS
-EFIAPI
-SmramProfileProtocolGetData (
- IN EDKII_SMM_MEMORY_PROFILE_PROTOCOL *This,
- IN OUT UINT64 *ProfileSize,
- OUT VOID *ProfileBuffer
- )
-{
- UINT64 Size;
- UINT64 Offset;
- MEMORY_PROFILE_CONTEXT_DATA *ContextData;
- BOOLEAN SmramProfileGettingStatus;
-
- ContextData = GetSmramProfileContext ();
- if (ContextData == NULL) {
- return EFI_UNSUPPORTED;
- }
-
- SmramProfileGettingStatus = mSmramProfileGettingStatus;
- mSmramProfileGettingStatus = TRUE;
-
- Size = SmramProfileGetDataSize ();
-
- if (*ProfileSize < Size) {
- *ProfileSize = Size;
- mSmramProfileGettingStatus = SmramProfileGettingStatus;
- return EFI_BUFFER_TOO_SMALL;
- }
-
- Offset = 0;
- SmramProfileCopyData (ProfileBuffer, &Size, &Offset);
- *ProfileSize = Size;
-
- mSmramProfileGettingStatus = SmramProfileGettingStatus;
- return EFI_SUCCESS;
-}
-
-/**
- Register image to memory profile.
-
- @param[in] This The EDKII_SMM_MEMORY_PROFILE_PROTOCOL instance.
- @param[in] FilePath File path of the image.
- @param[in] ImageBase Image base address.
- @param[in] ImageSize Image size.
- @param[in] FileType File type of the image.
-
- @return EFI_SUCCESS Register successfully.
- @return EFI_UNSUPPORTED Memory profile is unsupported,
- or memory profile for the image is not required.
- @return EFI_OUT_OF_RESOURCES No enough resource for this register.
-
-**/
-EFI_STATUS
-EFIAPI
-SmramProfileProtocolRegisterImage (
- IN EDKII_SMM_MEMORY_PROFILE_PROTOCOL *This,
- IN EFI_DEVICE_PATH_PROTOCOL *FilePath,
- IN PHYSICAL_ADDRESS ImageBase,
- IN UINT64 ImageSize,
- IN EFI_FV_FILETYPE FileType
- )
-{
- EFI_STATUS Status;
- EFI_SMM_DRIVER_ENTRY DriverEntry;
- VOID *EntryPointInImage;
- EFI_GUID *Name;
-
- ZeroMem (&DriverEntry, sizeof (DriverEntry));
- Name = GetFileNameFromFilePath (FilePath);
- if (Name != NULL) {
- CopyMem (&DriverEntry.FileName, Name, sizeof (EFI_GUID));
- }
-
- DriverEntry.ImageBuffer = ImageBase;
- DriverEntry.NumberOfPage = EFI_SIZE_TO_PAGES ((UINTN)ImageSize);
- Status = InternalPeCoffGetEntryPoint ((VOID *)(UINTN)DriverEntry.ImageBuffer, &EntryPointInImage);
- ASSERT_EFI_ERROR (Status);
- DriverEntry.ImageEntryPoint = (PHYSICAL_ADDRESS)(UINTN)EntryPointInImage;
-
- return RegisterSmramProfileImage (&DriverEntry, FALSE);
-}
-
-/**
- Unregister image from memory profile.
-
- @param[in] This The EDKII_SMM_MEMORY_PROFILE_PROTOCOL instance.
- @param[in] FilePath File path of the image.
- @param[in] ImageBase Image base address.
- @param[in] ImageSize Image size.
-
- @return EFI_SUCCESS Unregister successfully.
- @return EFI_UNSUPPORTED Memory profile is unsupported,
- or memory profile for the image is not required.
- @return EFI_NOT_FOUND The image is not found.
-
-**/
-EFI_STATUS
-EFIAPI
-SmramProfileProtocolUnregisterImage (
- IN EDKII_SMM_MEMORY_PROFILE_PROTOCOL *This,
- IN EFI_DEVICE_PATH_PROTOCOL *FilePath,
- IN PHYSICAL_ADDRESS ImageBase,
- IN UINT64 ImageSize
- )
-{
- EFI_STATUS Status;
- EFI_SMM_DRIVER_ENTRY DriverEntry;
- VOID *EntryPointInImage;
- EFI_GUID *Name;
-
- ZeroMem (&DriverEntry, sizeof (DriverEntry));
- Name = GetFileNameFromFilePath (FilePath);
- if (Name != NULL) {
- CopyMem (&DriverEntry.FileName, Name, sizeof (EFI_GUID));
- }
-
- DriverEntry.ImageBuffer = ImageBase;
- DriverEntry.NumberOfPage = EFI_SIZE_TO_PAGES ((UINTN)ImageSize);
- Status = InternalPeCoffGetEntryPoint ((VOID *)(UINTN)DriverEntry.ImageBuffer, &EntryPointInImage);
- ASSERT_EFI_ERROR (Status);
- DriverEntry.ImageEntryPoint = (PHYSICAL_ADDRESS)(UINTN)EntryPointInImage;
-
- return UnregisterSmramProfileImage (&DriverEntry, FALSE);
-}
-
-/**
- Get memory profile recording state.
-
- @param[in] This The EDKII_SMM_MEMORY_PROFILE_PROTOCOL instance.
- @param[out] RecordingState Recording state.
-
- @return EFI_SUCCESS Memory profile recording state is returned.
- @return EFI_UNSUPPORTED Memory profile is unsupported.
- @return EFI_INVALID_PARAMETER RecordingState is NULL.
-
-**/
-EFI_STATUS
-EFIAPI
-SmramProfileProtocolGetRecordingState (
- IN EDKII_SMM_MEMORY_PROFILE_PROTOCOL *This,
- OUT BOOLEAN *RecordingState
- )
-{
- MEMORY_PROFILE_CONTEXT_DATA *ContextData;
-
- ContextData = GetSmramProfileContext ();
- if (ContextData == NULL) {
- return EFI_UNSUPPORTED;
- }
-
- if (RecordingState == NULL) {
- return EFI_INVALID_PARAMETER;
- }
-
- *RecordingState = mSmramProfileRecordingEnable;
- return EFI_SUCCESS;
-}
-
-/**
- Set memory profile recording state.
-
- @param[in] This The EDKII_SMM_MEMORY_PROFILE_PROTOCOL instance.
- @param[in] RecordingState Recording state.
-
- @return EFI_SUCCESS Set memory profile recording state successfully.
- @return EFI_UNSUPPORTED Memory profile is unsupported.
-
-**/
-EFI_STATUS
-EFIAPI
-SmramProfileProtocolSetRecordingState (
- IN EDKII_SMM_MEMORY_PROFILE_PROTOCOL *This,
- IN BOOLEAN RecordingState
- )
-{
- MEMORY_PROFILE_CONTEXT_DATA *ContextData;
-
- ContextData = GetSmramProfileContext ();
- if (ContextData == NULL) {
- return EFI_UNSUPPORTED;
- }
-
- mSmramProfileRecordingEnable = RecordingState;
- return EFI_SUCCESS;
-}
-
-/**
- Record memory profile of multilevel caller.
-
- @param[in] This The EDKII_SMM_MEMORY_PROFILE_PROTOCOL instance.
- @param[in] CallerAddress Address of caller.
- @param[in] Action Memory profile action.
- @param[in] MemoryType Memory type.
- EfiMaxMemoryType means the MemoryType is unknown.
- @param[in] Buffer Buffer address.
- @param[in] Size Buffer size.
- @param[in] ActionString String for memory profile action.
- Only needed for user defined allocate action.
-
- @return EFI_SUCCESS Memory profile is updated.
- @return EFI_UNSUPPORTED Memory profile is unsupported,
- or memory profile for the image is not required,
- or memory profile for the memory type is not required.
- @return EFI_ACCESS_DENIED It is during memory profile data getting.
- @return EFI_ABORTED Memory profile recording is not enabled.
- @return EFI_OUT_OF_RESOURCES No enough resource to update memory profile for allocate action.
- @return EFI_NOT_FOUND No matched allocate info found for free action.
-
-**/
-EFI_STATUS
-EFIAPI
-SmramProfileProtocolRecord (
- IN EDKII_SMM_MEMORY_PROFILE_PROTOCOL *This,
- IN PHYSICAL_ADDRESS CallerAddress,
- IN MEMORY_PROFILE_ACTION Action,
- IN EFI_MEMORY_TYPE MemoryType,
- IN VOID *Buffer,
- IN UINTN Size,
- IN CHAR8 *ActionString OPTIONAL
- )
-{
- return SmmCoreUpdateProfile (CallerAddress, Action, MemoryType, Size, Buffer, ActionString);
-}
-
-/**
- SMRAM profile handler to get profile info.
-
- @param SmramProfileParameterGetInfo The parameter of SMM profile get size.
-
-**/
-VOID
-SmramProfileHandlerGetInfo (
- IN SMRAM_PROFILE_PARAMETER_GET_PROFILE_INFO *SmramProfileParameterGetInfo
- )
-{
- MEMORY_PROFILE_CONTEXT_DATA *ContextData;
- BOOLEAN SmramProfileGettingStatus;
-
- ContextData = GetSmramProfileContext ();
- if (ContextData == NULL) {
- return;
- }
-
- SmramProfileGettingStatus = mSmramProfileGettingStatus;
- mSmramProfileGettingStatus = TRUE;
-
- SmramProfileParameterGetInfo->ProfileSize = SmramProfileGetDataSize ();
- SmramProfileParameterGetInfo->Header.ReturnStatus = 0;
-
- mSmramProfileGettingStatus = SmramProfileGettingStatus;
-}
-
-/**
- SMRAM profile handler to get profile data.
-
- @param SmramProfileParameterGetData The parameter of SMM profile get data.
-
-**/
-VOID
-SmramProfileHandlerGetData (
- IN SMRAM_PROFILE_PARAMETER_GET_PROFILE_DATA *SmramProfileParameterGetData
- )
-{
- UINT64 ProfileSize;
- UINT64 ProfileOffset;
- SMRAM_PROFILE_PARAMETER_GET_PROFILE_DATA SmramProfileGetData;
- MEMORY_PROFILE_CONTEXT_DATA *ContextData;
- BOOLEAN SmramProfileGettingStatus;
-
- ContextData = GetSmramProfileContext ();
- if (ContextData == NULL) {
- return;
- }
-
- SmramProfileGettingStatus = mSmramProfileGettingStatus;
- mSmramProfileGettingStatus = TRUE;
-
- CopyMem (&SmramProfileGetData, SmramProfileParameterGetData, sizeof (SmramProfileGetData));
-
- ProfileSize = SmramProfileGetDataSize ();
-
- //
- // Sanity check
- //
- if (!SmmIsBufferOutsideSmmValid ((UINTN)SmramProfileGetData.ProfileBuffer, (UINTN)ProfileSize)) {
- DEBUG ((DEBUG_ERROR, "SmramProfileHandlerGetData: SMM ProfileBuffer in SMRAM or overflow!\n"));
- SmramProfileParameterGetData->ProfileSize = ProfileSize;
- SmramProfileParameterGetData->Header.ReturnStatus = (UINT64)(INT64)(INTN)EFI_ACCESS_DENIED;
- goto Done;
- }
-
- if (SmramProfileGetData.ProfileSize < ProfileSize) {
- SmramProfileParameterGetData->ProfileSize = ProfileSize;
- SmramProfileParameterGetData->Header.ReturnStatus = (UINT64)(INT64)(INTN)EFI_BUFFER_TOO_SMALL;
- goto Done;
- }
-
- ProfileOffset = 0;
- SmramProfileCopyData ((VOID *)(UINTN)SmramProfileGetData.ProfileBuffer, &ProfileSize, &ProfileOffset);
- SmramProfileParameterGetData->ProfileSize = ProfileSize;
- SmramProfileParameterGetData->Header.ReturnStatus = 0;
-
-Done:
- mSmramProfileGettingStatus = SmramProfileGettingStatus;
-}
-
-/**
- SMRAM profile handler to get profile data by offset.
-
- @param SmramProfileParameterGetDataByOffset The parameter of SMM profile get data by offset.
-
-**/
-VOID
-SmramProfileHandlerGetDataByOffset (
- IN SMRAM_PROFILE_PARAMETER_GET_PROFILE_DATA_BY_OFFSET *SmramProfileParameterGetDataByOffset
- )
-{
- SMRAM_PROFILE_PARAMETER_GET_PROFILE_DATA_BY_OFFSET SmramProfileGetDataByOffset;
- MEMORY_PROFILE_CONTEXT_DATA *ContextData;
- BOOLEAN SmramProfileGettingStatus;
-
- ContextData = GetSmramProfileContext ();
- if (ContextData == NULL) {
- return;
- }
-
- SmramProfileGettingStatus = mSmramProfileGettingStatus;
- mSmramProfileGettingStatus = TRUE;
-
- CopyMem (&SmramProfileGetDataByOffset, SmramProfileParameterGetDataByOffset, sizeof (SmramProfileGetDataByOffset));
-
- //
- // Sanity check
- //
- if (!SmmIsBufferOutsideSmmValid ((UINTN)SmramProfileGetDataByOffset.ProfileBuffer, (UINTN)SmramProfileGetDataByOffset.ProfileSize)) {
- DEBUG ((DEBUG_ERROR, "SmramProfileHandlerGetDataByOffset: SMM ProfileBuffer in SMRAM or overflow!\n"));
- SmramProfileParameterGetDataByOffset->Header.ReturnStatus = (UINT64)(INT64)(INTN)EFI_ACCESS_DENIED;
- goto Done;
- }
-
- SmramProfileCopyData ((VOID *)(UINTN)SmramProfileGetDataByOffset.ProfileBuffer, &SmramProfileGetDataByOffset.ProfileSize, &SmramProfileGetDataByOffset.ProfileOffset);
- CopyMem (SmramProfileParameterGetDataByOffset, &SmramProfileGetDataByOffset, sizeof (SmramProfileGetDataByOffset));
- SmramProfileParameterGetDataByOffset->Header.ReturnStatus = 0;
-
-Done:
- mSmramProfileGettingStatus = SmramProfileGettingStatus;
-}
-
-/**
- Dispatch function for a Software SMI handler.
-
- Caution: This function may receive untrusted input.
- Communicate buffer and buffer size are external input, so this function will do basic validation.
-
- @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-SMM environment into an SMM environment.
- @param CommBufferSize The size of the CommBuffer.
-
- @retval EFI_SUCCESS Command is handled successfully.
-
-**/
-EFI_STATUS
-EFIAPI
-SmramProfileHandler (
- IN EFI_HANDLE DispatchHandle,
- IN CONST VOID *Context OPTIONAL,
- IN OUT VOID *CommBuffer OPTIONAL,
- IN OUT UINTN *CommBufferSize OPTIONAL
- )
-{
- SMRAM_PROFILE_PARAMETER_HEADER *SmramProfileParameterHeader;
- UINTN TempCommBufferSize;
- SMRAM_PROFILE_PARAMETER_RECORDING_STATE *ParameterRecordingState;
-
- DEBUG ((DEBUG_ERROR, "SmramProfileHandler Enter\n"));
-
- //
- // If input is invalid, stop processing this SMI
- //
- if ((CommBuffer == NULL) || (CommBufferSize == NULL)) {
- return EFI_SUCCESS;
- }
-
- TempCommBufferSize = *CommBufferSize;
-
- if (TempCommBufferSize < sizeof (SMRAM_PROFILE_PARAMETER_HEADER)) {
- DEBUG ((DEBUG_ERROR, "SmramProfileHandler: SMM communication buffer size invalid!\n"));
- return EFI_SUCCESS;
- }
-
- if (mSmramReadyToLock && !SmmIsBufferOutsideSmmValid ((UINTN)CommBuffer, TempCommBufferSize)) {
- DEBUG ((DEBUG_ERROR, "SmramProfileHandler: SMM communication buffer in SMRAM or overflow!\n"));
- return EFI_SUCCESS;
- }
-
- SmramProfileParameterHeader = (SMRAM_PROFILE_PARAMETER_HEADER *)((UINTN)CommBuffer);
-
- SmramProfileParameterHeader->ReturnStatus = (UINT64)-1;
-
- if (GetSmramProfileContext () == NULL) {
- SmramProfileParameterHeader->ReturnStatus = (UINT64)(INT64)(INTN)EFI_UNSUPPORTED;
- return EFI_SUCCESS;
- }
-
- switch (SmramProfileParameterHeader->Command) {
- case SMRAM_PROFILE_COMMAND_GET_PROFILE_INFO:
- DEBUG ((DEBUG_ERROR, "SmramProfileHandlerGetInfo\n"));
- if (TempCommBufferSize != sizeof (SMRAM_PROFILE_PARAMETER_GET_PROFILE_INFO)) {
- DEBUG ((DEBUG_ERROR, "SmramProfileHandler: SMM communication buffer size invalid!\n"));
- return EFI_SUCCESS;
- }
-
- SmramProfileHandlerGetInfo ((SMRAM_PROFILE_PARAMETER_GET_PROFILE_INFO *)(UINTN)CommBuffer);
- break;
- case SMRAM_PROFILE_COMMAND_GET_PROFILE_DATA:
- DEBUG ((DEBUG_ERROR, "SmramProfileHandlerGetData\n"));
- if (TempCommBufferSize != sizeof (SMRAM_PROFILE_PARAMETER_GET_PROFILE_DATA)) {
- DEBUG ((DEBUG_ERROR, "SmramProfileHandler: SMM communication buffer size invalid!\n"));
- return EFI_SUCCESS;
- }
-
- SmramProfileHandlerGetData ((SMRAM_PROFILE_PARAMETER_GET_PROFILE_DATA *)(UINTN)CommBuffer);
- break;
- case SMRAM_PROFILE_COMMAND_GET_PROFILE_DATA_BY_OFFSET:
- DEBUG ((DEBUG_ERROR, "SmramProfileHandlerGetDataByOffset\n"));
- if (TempCommBufferSize != sizeof (SMRAM_PROFILE_PARAMETER_GET_PROFILE_DATA_BY_OFFSET)) {
- DEBUG ((DEBUG_ERROR, "SmramProfileHandler: SMM communication buffer size invalid!\n"));
- return EFI_SUCCESS;
- }
-
- SmramProfileHandlerGetDataByOffset ((SMRAM_PROFILE_PARAMETER_GET_PROFILE_DATA_BY_OFFSET *)(UINTN)CommBuffer);
- break;
- case SMRAM_PROFILE_COMMAND_GET_RECORDING_STATE:
- DEBUG ((DEBUG_ERROR, "SmramProfileHandlerGetRecordingState\n"));
- if (TempCommBufferSize != sizeof (SMRAM_PROFILE_PARAMETER_RECORDING_STATE)) {
- DEBUG ((DEBUG_ERROR, "SmramProfileHandler: SMM communication buffer size invalid!\n"));
- return EFI_SUCCESS;
- }
-
- ParameterRecordingState = (SMRAM_PROFILE_PARAMETER_RECORDING_STATE *)(UINTN)CommBuffer;
- ParameterRecordingState->RecordingState = mSmramProfileRecordingEnable;
- ParameterRecordingState->Header.ReturnStatus = 0;
- break;
- case SMRAM_PROFILE_COMMAND_SET_RECORDING_STATE:
- DEBUG ((DEBUG_ERROR, "SmramProfileHandlerSetRecordingState\n"));
- if (TempCommBufferSize != sizeof (SMRAM_PROFILE_PARAMETER_RECORDING_STATE)) {
- DEBUG ((DEBUG_ERROR, "SmramProfileHandler: SMM communication buffer size invalid!\n"));
- return EFI_SUCCESS;
- }
-
- ParameterRecordingState = (SMRAM_PROFILE_PARAMETER_RECORDING_STATE *)(UINTN)CommBuffer;
- mSmramProfileRecordingEnable = ParameterRecordingState->RecordingState;
- ParameterRecordingState->Header.ReturnStatus = 0;
- break;
-
- //
- // Below 2 commands have been deprecated. They may not be (re-)used.
- //
- case SMRAM_PROFILE_COMMAND_DEPRECATED1:
- case SMRAM_PROFILE_COMMAND_DEPRECATED2:
- ASSERT (FALSE);
- //
- // Fall-through to the default (unrecognized command) case.
- //
- default:
- break;
- }
-
- DEBUG ((DEBUG_ERROR, "SmramProfileHandler Exit\n"));
-
- return EFI_SUCCESS;
-}
-
-/**
- Register SMRAM profile handler.
-
-**/
-VOID
-RegisterSmramProfileHandler (
- VOID
- )
-{
- EFI_STATUS Status;
- EFI_HANDLE DispatchHandle;
-
- if (!IS_SMRAM_PROFILE_ENABLED) {
- return;
- }
-
- Status = SmiHandlerRegister (
- SmramProfileHandler,
- &gEdkiiMemoryProfileGuid,
- &DispatchHandle
- );
- ASSERT_EFI_ERROR (Status);
-}
-
-////////////////////
-
-/**
- Dump SMRAM range.
-
-**/
-VOID
-DumpSmramRange (
- VOID
- )
-{
- UINTN Index;
- MEMORY_PROFILE_CONTEXT_DATA *ContextData;
- BOOLEAN SmramProfileGettingStatus;
-
- ContextData = GetSmramProfileContext ();
- if (ContextData == NULL) {
- return;
- }
-
- SmramProfileGettingStatus = mSmramProfileGettingStatus;
- mSmramProfileGettingStatus = TRUE;
-
- DEBUG ((DEBUG_INFO, "FullSmramRange address - 0x%08x\n", mFullSmramRanges));
-
- DEBUG ((DEBUG_INFO, "======= SmramProfile begin =======\n"));
-
- DEBUG ((DEBUG_INFO, "FullSmramRange:\n"));
- for (Index = 0; Index < mFullSmramRangeCount; Index++) {
- DEBUG ((DEBUG_INFO, " FullSmramRange (0x%x)\n", Index));
- DEBUG ((DEBUG_INFO, " PhysicalStart - 0x%016lx\n", mFullSmramRanges[Index].PhysicalStart));
- DEBUG ((DEBUG_INFO, " CpuStart - 0x%016lx\n", mFullSmramRanges[Index].CpuStart));
- DEBUG ((DEBUG_INFO, " PhysicalSize - 0x%016lx\n", mFullSmramRanges[Index].PhysicalSize));
- DEBUG ((DEBUG_INFO, " RegionState - 0x%016lx\n", mFullSmramRanges[Index].RegionState));
- }
-
- DEBUG ((DEBUG_INFO, "======= SmramProfile end =======\n"));
-
- mSmramProfileGettingStatus = SmramProfileGettingStatus;
-}
-
-/**
- Dump SMRAM free page list.
-
-**/
-VOID
-DumpFreePagesList (
- VOID
- )
-{
- LIST_ENTRY *FreePageList;
- LIST_ENTRY *Node;
- FREE_PAGE_LIST *Pages;
- UINTN Index;
- MEMORY_PROFILE_CONTEXT_DATA *ContextData;
- BOOLEAN SmramProfileGettingStatus;
-
- ContextData = GetSmramProfileContext ();
- if (ContextData == NULL) {
- return;
- }
-
- SmramProfileGettingStatus = mSmramProfileGettingStatus;
- mSmramProfileGettingStatus = TRUE;
-
- DEBUG ((DEBUG_INFO, "======= SmramProfile begin =======\n"));
-
- DEBUG ((DEBUG_INFO, "FreePagesList:\n"));
- FreePageList = &mSmmMemoryMap;
- for (Node = FreePageList->BackLink, Index = 0;
- Node != FreePageList;
- Node = Node->BackLink, Index++)
- {
- Pages = BASE_CR (Node, FREE_PAGE_LIST, Link);
- DEBUG ((DEBUG_INFO, " Index - 0x%x\n", Index));
- DEBUG ((DEBUG_INFO, " PhysicalStart - 0x%016lx\n", (PHYSICAL_ADDRESS)(UINTN)Pages));
- DEBUG ((DEBUG_INFO, " NumberOfPages - 0x%08x\n", Pages->NumberOfPages));
- }
-
- DEBUG ((DEBUG_INFO, "======= SmramProfile end =======\n"));
-
- mSmramProfileGettingStatus = SmramProfileGettingStatus;
-}
-
-/**
- Dump SMRAM free pool list.
-
-**/
-VOID
-DumpFreePoolList (
- VOID
- )
-{
- LIST_ENTRY *FreePoolList;
- LIST_ENTRY *Node;
- FREE_POOL_HEADER *Pool;
- UINTN Index;
- UINTN PoolListIndex;
- MEMORY_PROFILE_CONTEXT_DATA *ContextData;
- BOOLEAN SmramProfileGettingStatus;
- UINTN SmmPoolTypeIndex;
-
- ContextData = GetSmramProfileContext ();
- if (ContextData == NULL) {
- return;
- }
-
- SmramProfileGettingStatus = mSmramProfileGettingStatus;
- mSmramProfileGettingStatus = TRUE;
-
- DEBUG ((DEBUG_INFO, "======= SmramProfile begin =======\n"));
-
- for (SmmPoolTypeIndex = 0; SmmPoolTypeIndex < SmmPoolTypeMax; SmmPoolTypeIndex++) {
- for (PoolListIndex = 0; PoolListIndex < MAX_POOL_INDEX; PoolListIndex++) {
- DEBUG ((DEBUG_INFO, "FreePoolList(%d)(%d):\n", SmmPoolTypeIndex, PoolListIndex));
- FreePoolList = &mSmmPoolLists[SmmPoolTypeIndex][PoolListIndex];
- for (Node = FreePoolList->BackLink, Index = 0;
- Node != FreePoolList;
- Node = Node->BackLink, Index++)
- {
- Pool = BASE_CR (Node, FREE_POOL_HEADER, Link);
- DEBUG ((DEBUG_INFO, " Index - 0x%x\n", Index));
- DEBUG ((DEBUG_INFO, " PhysicalStart - 0x%016lx\n", (PHYSICAL_ADDRESS)(UINTN)Pool));
- DEBUG ((DEBUG_INFO, " Size - 0x%08x\n", Pool->Header.Size));
- DEBUG ((DEBUG_INFO, " Available - 0x%02x\n", Pool->Header.Available));
- }
- }
- }
-
- DEBUG ((DEBUG_INFO, "======= SmramProfile end =======\n"));
-
- mSmramProfileGettingStatus = SmramProfileGettingStatus;
-}
-
-GLOBAL_REMOVE_IF_UNREFERENCED CHAR8 *mSmmActionString[] = {
- "SmmUnknown",
- "gSmst->SmmAllocatePages",
- "gSmst->SmmFreePages",
- "gSmst->SmmAllocatePool",
- "gSmst->SmmFreePool",
-};
-
-typedef struct {
- MEMORY_PROFILE_ACTION Action;
- CHAR8 *String;
-} ACTION_STRING;
-
-GLOBAL_REMOVE_IF_UNREFERENCED ACTION_STRING mExtActionString[] = {
- { MEMORY_PROFILE_ACTION_LIB_ALLOCATE_PAGES, "Lib:AllocatePages" },
- { MEMORY_PROFILE_ACTION_LIB_ALLOCATE_RUNTIME_PAGES, "Lib:AllocateRuntimePages" },
- { MEMORY_PROFILE_ACTION_LIB_ALLOCATE_RESERVED_PAGES, "Lib:AllocateReservedPages" },
- { MEMORY_PROFILE_ACTION_LIB_FREE_PAGES, "Lib:FreePages" },
- { MEMORY_PROFILE_ACTION_LIB_ALLOCATE_ALIGNED_PAGES, "Lib:AllocateAlignedPages" },
- { MEMORY_PROFILE_ACTION_LIB_ALLOCATE_ALIGNED_RUNTIME_PAGES, "Lib:AllocateAlignedRuntimePages" },
- { MEMORY_PROFILE_ACTION_LIB_ALLOCATE_ALIGNED_RESERVED_PAGES, "Lib:AllocateAlignedReservedPages" },
- { MEMORY_PROFILE_ACTION_LIB_FREE_ALIGNED_PAGES, "Lib:FreeAlignedPages" },
- { MEMORY_PROFILE_ACTION_LIB_ALLOCATE_POOL, "Lib:AllocatePool" },
- { MEMORY_PROFILE_ACTION_LIB_ALLOCATE_RUNTIME_POOL, "Lib:AllocateRuntimePool" },
- { MEMORY_PROFILE_ACTION_LIB_ALLOCATE_RESERVED_POOL, "Lib:AllocateReservedPool" },
- { MEMORY_PROFILE_ACTION_LIB_FREE_POOL, "Lib:FreePool" },
- { MEMORY_PROFILE_ACTION_LIB_ALLOCATE_ZERO_POOL, "Lib:AllocateZeroPool" },
- { MEMORY_PROFILE_ACTION_LIB_ALLOCATE_RUNTIME_ZERO_POOL, "Lib:AllocateRuntimeZeroPool" },
- { MEMORY_PROFILE_ACTION_LIB_ALLOCATE_RESERVED_ZERO_POOL, "Lib:AllocateReservedZeroPool" },
- { MEMORY_PROFILE_ACTION_LIB_ALLOCATE_COPY_POOL, "Lib:AllocateCopyPool" },
- { MEMORY_PROFILE_ACTION_LIB_ALLOCATE_RUNTIME_COPY_POOL, "Lib:AllocateRuntimeCopyPool" },
- { MEMORY_PROFILE_ACTION_LIB_ALLOCATE_RESERVED_COPY_POOL, "Lib:AllocateReservedCopyPool" },
- { MEMORY_PROFILE_ACTION_LIB_REALLOCATE_POOL, "Lib:ReallocatePool" },
- { MEMORY_PROFILE_ACTION_LIB_REALLOCATE_RUNTIME_POOL, "Lib:ReallocateRuntimePool" },
- { MEMORY_PROFILE_ACTION_LIB_REALLOCATE_RESERVED_POOL, "Lib:ReallocateReservedPool" },
-};
-
-typedef struct {
- EFI_MEMORY_TYPE MemoryType;
- CHAR8 *MemoryTypeStr;
-} PROFILE_MEMORY_TYPE_STRING;
-
-GLOBAL_REMOVE_IF_UNREFERENCED PROFILE_MEMORY_TYPE_STRING mMemoryTypeString[] = {
- { EfiRuntimeServicesCode, "EfiRuntimeServicesCode" },
- { EfiRuntimeServicesData, "EfiRuntimeServicesData" }
-};
-
-/**
- Memory type to string.
-
- @param[in] MemoryType Memory type.
-
- @return Pointer to string.
-
-**/
-CHAR8 *
-ProfileMemoryTypeToStr (
- IN EFI_MEMORY_TYPE MemoryType
- )
-{
- UINTN Index;
-
- for (Index = 0; Index < ARRAY_SIZE (mMemoryTypeString); Index++) {
- if (mMemoryTypeString[Index].MemoryType == MemoryType) {
- return mMemoryTypeString[Index].MemoryTypeStr;
- }
- }
-
- return "UnexpectedMemoryType";
-}
-
-/**
- Action to string.
-
- @param[in] Action Profile action.
-
- @return Pointer to string.
-
-**/
-CHAR8 *
-ProfileActionToStr (
- IN MEMORY_PROFILE_ACTION Action
- )
-{
- UINTN Index;
- UINTN ActionStringCount;
- CHAR8 **ActionString;
-
- ActionString = mSmmActionString;
- ActionStringCount = ARRAY_SIZE (mSmmActionString);
-
- if ((UINTN)(UINT32)Action < ActionStringCount) {
- return ActionString[Action];
- }
-
- for (Index = 0; Index < ARRAY_SIZE (mExtActionString); Index++) {
- if (mExtActionString[Index].Action == Action) {
- return mExtActionString[Index].String;
- }
- }
-
- return ActionString[0];
-}
-
-/**
- Dump SMRAM profile.
-
-**/
-VOID
-DumpSmramProfile (
- VOID
- )
-{
- MEMORY_PROFILE_CONTEXT *Context;
- MEMORY_PROFILE_DRIVER_INFO *DriverInfo;
- MEMORY_PROFILE_ALLOC_INFO *AllocInfo;
- MEMORY_PROFILE_CONTEXT_DATA *ContextData;
- MEMORY_PROFILE_DRIVER_INFO_DATA *DriverInfoData;
- MEMORY_PROFILE_ALLOC_INFO_DATA *AllocInfoData;
- LIST_ENTRY *SmramDriverInfoList;
- UINTN DriverIndex;
- LIST_ENTRY *DriverLink;
- LIST_ENTRY *AllocInfoList;
- UINTN AllocIndex;
- LIST_ENTRY *AllocLink;
- BOOLEAN SmramProfileGettingStatus;
- UINTN TypeIndex;
-
- ContextData = GetSmramProfileContext ();
- if (ContextData == NULL) {
- return;
- }
-
- SmramProfileGettingStatus = mSmramProfileGettingStatus;
- mSmramProfileGettingStatus = TRUE;
-
- Context = &ContextData->Context;
- DEBUG ((DEBUG_INFO, "======= SmramProfile begin =======\n"));
- DEBUG ((DEBUG_INFO, "MEMORY_PROFILE_CONTEXT\n"));
-
- DEBUG ((DEBUG_INFO, " CurrentTotalUsage - 0x%016lx\n", Context->CurrentTotalUsage));
- DEBUG ((DEBUG_INFO, " PeakTotalUsage - 0x%016lx\n", Context->PeakTotalUsage));
- for (TypeIndex = 0; TypeIndex < sizeof (Context->CurrentTotalUsageByType) / sizeof (Context->CurrentTotalUsageByType[0]); TypeIndex++) {
- if ((Context->CurrentTotalUsageByType[TypeIndex] != 0) ||
- (Context->PeakTotalUsageByType[TypeIndex] != 0))
- {
- DEBUG ((DEBUG_INFO, " CurrentTotalUsage[0x%02x] - 0x%016lx (%a)\n", TypeIndex, Context->CurrentTotalUsageByType[TypeIndex], ProfileMemoryTypeToStr (TypeIndex)));
- DEBUG ((DEBUG_INFO, " PeakTotalUsage[0x%02x] - 0x%016lx (%a)\n", TypeIndex, Context->PeakTotalUsageByType[TypeIndex], ProfileMemoryTypeToStr (TypeIndex)));
- }
- }
-
- DEBUG ((DEBUG_INFO, " TotalImageSize - 0x%016lx\n", Context->TotalImageSize));
- DEBUG ((DEBUG_INFO, " ImageCount - 0x%08x\n", Context->ImageCount));
- DEBUG ((DEBUG_INFO, " SequenceCount - 0x%08x\n", Context->SequenceCount));
-
- SmramDriverInfoList = ContextData->DriverInfoList;
- for (DriverLink = SmramDriverInfoList->ForwardLink, DriverIndex = 0;
- DriverLink != SmramDriverInfoList;
- DriverLink = DriverLink->ForwardLink, DriverIndex++)
- {
- DriverInfoData = CR (
- DriverLink,
- MEMORY_PROFILE_DRIVER_INFO_DATA,
- Link,
- MEMORY_PROFILE_DRIVER_INFO_SIGNATURE
- );
- DriverInfo = &DriverInfoData->DriverInfo;
- DEBUG ((DEBUG_INFO, " MEMORY_PROFILE_DRIVER_INFO (0x%x)\n", DriverIndex));
- DEBUG ((DEBUG_INFO, " FileName - %g\n", &DriverInfo->FileName));
- DEBUG ((DEBUG_INFO, " ImageBase - 0x%016lx\n", DriverInfo->ImageBase));
- DEBUG ((DEBUG_INFO, " ImageSize - 0x%016lx\n", DriverInfo->ImageSize));
- DEBUG ((DEBUG_INFO, " EntryPoint - 0x%016lx\n", DriverInfo->EntryPoint));
- DEBUG ((DEBUG_INFO, " ImageSubsystem - 0x%04x\n", DriverInfo->ImageSubsystem));
- DEBUG ((DEBUG_INFO, " FileType - 0x%02x\n", DriverInfo->FileType));
- DEBUG ((DEBUG_INFO, " CurrentUsage - 0x%016lx\n", DriverInfo->CurrentUsage));
- DEBUG ((DEBUG_INFO, " PeakUsage - 0x%016lx\n", DriverInfo->PeakUsage));
- for (TypeIndex = 0; TypeIndex < sizeof (DriverInfo->CurrentUsageByType) / sizeof (DriverInfo->CurrentUsageByType[0]); TypeIndex++) {
- if ((DriverInfo->CurrentUsageByType[TypeIndex] != 0) ||
- (DriverInfo->PeakUsageByType[TypeIndex] != 0))
- {
- DEBUG ((DEBUG_INFO, " CurrentUsage[0x%02x] - 0x%016lx (%a)\n", TypeIndex, DriverInfo->CurrentUsageByType[TypeIndex], ProfileMemoryTypeToStr (TypeIndex)));
- DEBUG ((DEBUG_INFO, " PeakUsage[0x%02x] - 0x%016lx (%a)\n", TypeIndex, DriverInfo->PeakUsageByType[TypeIndex], ProfileMemoryTypeToStr (TypeIndex)));
- }
- }
-
- DEBUG ((DEBUG_INFO, " AllocRecordCount - 0x%08x\n", DriverInfo->AllocRecordCount));
-
- AllocInfoList = DriverInfoData->AllocInfoList;
- for (AllocLink = AllocInfoList->ForwardLink, AllocIndex = 0;
- AllocLink != AllocInfoList;
- AllocLink = AllocLink->ForwardLink, AllocIndex++)
- {
- AllocInfoData = CR (
- AllocLink,
- MEMORY_PROFILE_ALLOC_INFO_DATA,
- Link,
- MEMORY_PROFILE_ALLOC_INFO_SIGNATURE
- );
- AllocInfo = &AllocInfoData->AllocInfo;
- DEBUG ((DEBUG_INFO, " MEMORY_PROFILE_ALLOC_INFO (0x%x)\n", AllocIndex));
- DEBUG ((DEBUG_INFO, " CallerAddress - 0x%016lx (Offset: 0x%08x)\n", AllocInfo->CallerAddress, AllocInfo->CallerAddress - DriverInfo->ImageBase));
- DEBUG ((DEBUG_INFO, " SequenceId - 0x%08x\n", AllocInfo->SequenceId));
- if ((AllocInfo->Action & MEMORY_PROFILE_ACTION_USER_DEFINED_MASK) != 0) {
- if (AllocInfoData->ActionString != NULL) {
- DEBUG ((DEBUG_INFO, " Action - 0x%08x (%a)\n", AllocInfo->Action, AllocInfoData->ActionString));
- } else {
- DEBUG ((DEBUG_INFO, " Action - 0x%08x (UserDefined-0x%08x)\n", AllocInfo->Action, AllocInfo->Action));
- }
- } else {
- DEBUG ((DEBUG_INFO, " Action - 0x%08x (%a)\n", AllocInfo->Action, ProfileActionToStr (AllocInfo->Action)));
- }
-
- DEBUG ((DEBUG_INFO, " MemoryType - 0x%08x (%a)\n", AllocInfo->MemoryType, ProfileMemoryTypeToStr (AllocInfo->MemoryType)));
- DEBUG ((DEBUG_INFO, " Buffer - 0x%016lx\n", AllocInfo->Buffer));
- DEBUG ((DEBUG_INFO, " Size - 0x%016lx\n", AllocInfo->Size));
- }
- }
-
- DEBUG ((DEBUG_INFO, "======= SmramProfile end =======\n"));
-
- mSmramProfileGettingStatus = SmramProfileGettingStatus;
-}
-
-/**
- Dump SMRAM information.
-
-**/
-VOID
-DumpSmramInfo (
- VOID
- )
-{
- DEBUG_CODE_BEGIN ();
- if (IS_SMRAM_PROFILE_ENABLED) {
- DumpSmramProfile ();
- DumpFreePagesList ();
- DumpFreePoolList ();
- DumpSmramRange ();
- }
-
- DEBUG_CODE_END ();
-}
+/** @file + Support routines for SMRAM profile. + + Copyright (c) 2014 - 2018, Intel Corporation. All rights reserved.<BR> + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "PiSmmCore.h" + +#define IS_SMRAM_PROFILE_ENABLED ((PcdGet8 (PcdMemoryProfilePropertyMask) & BIT1) != 0) +#define IS_UEFI_MEMORY_PROFILE_ENABLED ((PcdGet8 (PcdMemoryProfilePropertyMask) & BIT0) != 0) + +#define GET_OCCUPIED_SIZE(ActualSize, Alignment) \ + ((ActualSize) + (((Alignment) - ((ActualSize) & ((Alignment) - 1))) & ((Alignment) - 1))) + +typedef struct { + UINT32 Signature; + MEMORY_PROFILE_CONTEXT Context; + LIST_ENTRY *DriverInfoList; +} MEMORY_PROFILE_CONTEXT_DATA; + +typedef struct { + UINT32 Signature; + MEMORY_PROFILE_DRIVER_INFO DriverInfo; + LIST_ENTRY *AllocInfoList; + CHAR8 *PdbString; + LIST_ENTRY Link; +} MEMORY_PROFILE_DRIVER_INFO_DATA; + +typedef struct { + UINT32 Signature; + MEMORY_PROFILE_ALLOC_INFO AllocInfo; + CHAR8 *ActionString; + LIST_ENTRY Link; +} MEMORY_PROFILE_ALLOC_INFO_DATA; + +// +// When free memory less than 4 pages, dump it. +// +#define SMRAM_INFO_DUMP_PAGE_THRESHOLD 4 + +GLOBAL_REMOVE_IF_UNREFERENCED MEMORY_PROFILE_FREE_MEMORY mSmramFreeMemory = { + { + MEMORY_PROFILE_FREE_MEMORY_SIGNATURE, + sizeof (MEMORY_PROFILE_FREE_MEMORY), + MEMORY_PROFILE_FREE_MEMORY_REVISION + }, + 0, + 0 +}; + +GLOBAL_REMOVE_IF_UNREFERENCED LIST_ENTRY mImageQueue = INITIALIZE_LIST_HEAD_VARIABLE (mImageQueue); +GLOBAL_REMOVE_IF_UNREFERENCED MEMORY_PROFILE_CONTEXT_DATA mSmramProfileContext = { + MEMORY_PROFILE_CONTEXT_SIGNATURE, + { + { + MEMORY_PROFILE_CONTEXT_SIGNATURE, + sizeof (MEMORY_PROFILE_CONTEXT), + MEMORY_PROFILE_CONTEXT_REVISION + }, + 0, + 0, + { 0 }, + { 0 }, + 0, + 0, + 0 + }, + &mImageQueue, +}; +GLOBAL_REMOVE_IF_UNREFERENCED MEMORY_PROFILE_CONTEXT_DATA *mSmramProfileContextPtr = NULL; + +GLOBAL_REMOVE_IF_UNREFERENCED BOOLEAN mSmramReadyToLock; +GLOBAL_REMOVE_IF_UNREFERENCED BOOLEAN mSmramProfileGettingStatus = FALSE; +GLOBAL_REMOVE_IF_UNREFERENCED BOOLEAN mSmramProfileRecordingEnable = MEMORY_PROFILE_RECORDING_DISABLE; +GLOBAL_REMOVE_IF_UNREFERENCED EFI_DEVICE_PATH_PROTOCOL *mSmramProfileDriverPath; +GLOBAL_REMOVE_IF_UNREFERENCED UINTN mSmramProfileDriverPathSize; + +/** + Dump SMRAM information. + +**/ +VOID +DumpSmramInfo ( + VOID + ); + +/** + Get memory profile data. + + @param[in] This The EDKII_SMM_MEMORY_PROFILE_PROTOCOL instance. + @param[in, out] ProfileSize On entry, points to the size in bytes of the ProfileBuffer. + On return, points to the size of the data returned in ProfileBuffer. + @param[out] ProfileBuffer Profile buffer. + + @return EFI_SUCCESS Get the memory profile data successfully. + @return EFI_UNSUPPORTED Memory profile is unsupported. + @return EFI_BUFFER_TO_SMALL The ProfileSize is too small for the resulting data. + ProfileSize is updated with the size required. + +**/ +EFI_STATUS +EFIAPI +SmramProfileProtocolGetData ( + IN EDKII_SMM_MEMORY_PROFILE_PROTOCOL *This, + IN OUT UINT64 *ProfileSize, + OUT VOID *ProfileBuffer + ); + +/** + Register image to memory profile. + + @param[in] This The EDKII_SMM_MEMORY_PROFILE_PROTOCOL instance. + @param[in] FilePath File path of the image. + @param[in] ImageBase Image base address. + @param[in] ImageSize Image size. + @param[in] FileType File type of the image. + + @return EFI_SUCCESS Register successfully. + @return EFI_UNSUPPORTED Memory profile is unsupported, + or memory profile for the image is not required. + @return EFI_OUT_OF_RESOURCE No enough resource for this register. + +**/ +EFI_STATUS +EFIAPI +SmramProfileProtocolRegisterImage ( + IN EDKII_SMM_MEMORY_PROFILE_PROTOCOL *This, + IN EFI_DEVICE_PATH_PROTOCOL *FilePath, + IN PHYSICAL_ADDRESS ImageBase, + IN UINT64 ImageSize, + IN EFI_FV_FILETYPE FileType + ); + +/** + Unregister image from memory profile. + + @param[in] This The EDKII_SMM_MEMORY_PROFILE_PROTOCOL instance. + @param[in] FilePath File path of the image. + @param[in] ImageBase Image base address. + @param[in] ImageSize Image size. + + @return EFI_SUCCESS Unregister successfully. + @return EFI_UNSUPPORTED Memory profile is unsupported, + or memory profile for the image is not required. + @return EFI_NOT_FOUND The image is not found. + +**/ +EFI_STATUS +EFIAPI +SmramProfileProtocolUnregisterImage ( + IN EDKII_SMM_MEMORY_PROFILE_PROTOCOL *This, + IN EFI_DEVICE_PATH_PROTOCOL *FilePath, + IN PHYSICAL_ADDRESS ImageBase, + IN UINT64 ImageSize + ); + +/** + Get memory profile recording state. + + @param[in] This The EDKII_SMM_MEMORY_PROFILE_PROTOCOL instance. + @param[out] RecordingState Recording state. + + @return EFI_SUCCESS Memory profile recording state is returned. + @return EFI_UNSUPPORTED Memory profile is unsupported. + @return EFI_INVALID_PARAMETER RecordingState is NULL. + +**/ +EFI_STATUS +EFIAPI +SmramProfileProtocolGetRecordingState ( + IN EDKII_SMM_MEMORY_PROFILE_PROTOCOL *This, + OUT BOOLEAN *RecordingState + ); + +/** + Set memory profile recording state. + + @param[in] This The EDKII_SMM_MEMORY_PROFILE_PROTOCOL instance. + @param[in] RecordingState Recording state. + + @return EFI_SUCCESS Set memory profile recording state successfully. + @return EFI_UNSUPPORTED Memory profile is unsupported. + +**/ +EFI_STATUS +EFIAPI +SmramProfileProtocolSetRecordingState ( + IN EDKII_SMM_MEMORY_PROFILE_PROTOCOL *This, + IN BOOLEAN RecordingState + ); + +/** + Record memory profile of multilevel caller. + + @param[in] This The EDKII_SMM_MEMORY_PROFILE_PROTOCOL instance. + @param[in] CallerAddress Address of caller. + @param[in] Action Memory profile action. + @param[in] MemoryType Memory type. + EfiMaxMemoryType means the MemoryType is unknown. + @param[in] Buffer Buffer address. + @param[in] Size Buffer size. + @param[in] ActionString String for memory profile action. + Only needed for user defined allocate action. + + @return EFI_SUCCESS Memory profile is updated. + @return EFI_UNSUPPORTED Memory profile is unsupported, + or memory profile for the image is not required, + or memory profile for the memory type is not required. + @return EFI_ACCESS_DENIED It is during memory profile data getting. + @return EFI_ABORTED Memory profile recording is not enabled. + @return EFI_OUT_OF_RESOURCES No enough resource to update memory profile for allocate action. + @return EFI_NOT_FOUND No matched allocate info found for free action. + +**/ +EFI_STATUS +EFIAPI +SmramProfileProtocolRecord ( + IN EDKII_SMM_MEMORY_PROFILE_PROTOCOL *This, + IN PHYSICAL_ADDRESS CallerAddress, + IN MEMORY_PROFILE_ACTION Action, + IN EFI_MEMORY_TYPE MemoryType, + IN VOID *Buffer, + IN UINTN Size, + IN CHAR8 *ActionString OPTIONAL + ); + +GLOBAL_REMOVE_IF_UNREFERENCED EDKII_SMM_MEMORY_PROFILE_PROTOCOL mSmmProfileProtocol = { + SmramProfileProtocolGetData, + SmramProfileProtocolRegisterImage, + SmramProfileProtocolUnregisterImage, + SmramProfileProtocolGetRecordingState, + SmramProfileProtocolSetRecordingState, + SmramProfileProtocolRecord, +}; + +/** + Return SMRAM profile context. + + @return SMRAM profile context. + +**/ +MEMORY_PROFILE_CONTEXT_DATA * +GetSmramProfileContext ( + VOID + ) +{ + return mSmramProfileContextPtr; +} + +/** + Retrieves and returns the Subsystem of a PE/COFF image that has been loaded into system memory. + If Pe32Data is NULL, then ASSERT(). + + @param Pe32Data The pointer to the PE/COFF image that is loaded in system memory. + + @return The Subsystem of the PE/COFF image. + +**/ +UINT16 +InternalPeCoffGetSubsystem ( + IN VOID *Pe32Data + ) +{ + EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr; + EFI_IMAGE_DOS_HEADER *DosHdr; + UINT16 Magic; + + ASSERT (Pe32Data != NULL); + + DosHdr = (EFI_IMAGE_DOS_HEADER *)Pe32Data; + if (DosHdr->e_magic == EFI_IMAGE_DOS_SIGNATURE) { + // + // DOS image header is present, so read the PE header after the DOS image header. + // + Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *)((UINTN)Pe32Data + (UINTN)((DosHdr->e_lfanew) & 0x0ffff)); + } else { + // + // DOS image header is not present, so PE header is at the image base. + // + Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *)Pe32Data; + } + + if (Hdr.Te->Signature == EFI_TE_IMAGE_HEADER_SIGNATURE) { + return Hdr.Te->Subsystem; + } else if (Hdr.Pe32->Signature == EFI_IMAGE_NT_SIGNATURE) { + Magic = Hdr.Pe32->OptionalHeader.Magic; + if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) { + return Hdr.Pe32->OptionalHeader.Subsystem; + } else if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC) { + return Hdr.Pe32Plus->OptionalHeader.Subsystem; + } + } + + return 0x0000; +} + +/** + Retrieves and returns a pointer to the entry point to a PE/COFF image that has been loaded + into system memory with the PE/COFF Loader Library functions. + + Retrieves the entry point to the PE/COFF image specified by Pe32Data and returns this entry + point in EntryPoint. If the entry point could not be retrieved from the PE/COFF image, then + return RETURN_INVALID_PARAMETER. Otherwise return RETURN_SUCCESS. + If Pe32Data is NULL, then ASSERT(). + If EntryPoint is NULL, then ASSERT(). + + @param Pe32Data The pointer to the PE/COFF image that is loaded in system memory. + @param EntryPoint The pointer to entry point to the PE/COFF image to return. + + @retval RETURN_SUCCESS EntryPoint was returned. + @retval RETURN_INVALID_PARAMETER The entry point could not be found in the PE/COFF image. + +**/ +RETURN_STATUS +InternalPeCoffGetEntryPoint ( + IN VOID *Pe32Data, + OUT VOID **EntryPoint + ) +{ + EFI_IMAGE_DOS_HEADER *DosHdr; + EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr; + + ASSERT (Pe32Data != NULL); + ASSERT (EntryPoint != NULL); + + DosHdr = (EFI_IMAGE_DOS_HEADER *)Pe32Data; + if (DosHdr->e_magic == EFI_IMAGE_DOS_SIGNATURE) { + // + // DOS image header is present, so read the PE header after the DOS image header. + // + Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *)((UINTN)Pe32Data + (UINTN)((DosHdr->e_lfanew) & 0x0ffff)); + } else { + // + // DOS image header is not present, so PE header is at the image base. + // + Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *)Pe32Data; + } + + // + // Calculate the entry point relative to the start of the image. + // AddressOfEntryPoint is common for PE32 & PE32+ + // + if (Hdr.Te->Signature == EFI_TE_IMAGE_HEADER_SIGNATURE) { + *EntryPoint = (VOID *)((UINTN)Pe32Data + (UINTN)(Hdr.Te->AddressOfEntryPoint & 0x0ffffffff) + sizeof (EFI_TE_IMAGE_HEADER) - Hdr.Te->StrippedSize); + return RETURN_SUCCESS; + } else if (Hdr.Pe32->Signature == EFI_IMAGE_NT_SIGNATURE) { + *EntryPoint = (VOID *)((UINTN)Pe32Data + (UINTN)(Hdr.Pe32->OptionalHeader.AddressOfEntryPoint & 0x0ffffffff)); + return RETURN_SUCCESS; + } + + return RETURN_UNSUPPORTED; +} + +/** + Build driver info. + + @param ContextData Memory profile context. + @param FileName File name of the image. + @param ImageBase Image base address. + @param ImageSize Image size. + @param EntryPoint Entry point of the image. + @param ImageSubsystem Image subsystem of the image. + @param FileType File type of the image. + + @return Pointer to memory profile driver info. + +**/ +MEMORY_PROFILE_DRIVER_INFO_DATA * +BuildDriverInfo ( + IN MEMORY_PROFILE_CONTEXT_DATA *ContextData, + IN EFI_GUID *FileName, + IN PHYSICAL_ADDRESS ImageBase, + IN UINT64 ImageSize, + IN PHYSICAL_ADDRESS EntryPoint, + IN UINT16 ImageSubsystem, + IN EFI_FV_FILETYPE FileType + ) +{ + EFI_STATUS Status; + MEMORY_PROFILE_DRIVER_INFO *DriverInfo; + MEMORY_PROFILE_DRIVER_INFO_DATA *DriverInfoData; + VOID *EntryPointInImage; + CHAR8 *PdbString; + UINTN PdbSize; + UINTN PdbOccupiedSize; + + PdbSize = 0; + PdbOccupiedSize = 0; + PdbString = NULL; + if (ImageBase != 0) { + PdbString = PeCoffLoaderGetPdbPointer ((VOID *)(UINTN)ImageBase); + if (PdbString != NULL) { + PdbSize = AsciiStrSize (PdbString); + PdbOccupiedSize = GET_OCCUPIED_SIZE (PdbSize, sizeof (UINT64)); + } + } + + // + // Use SmmInternalAllocatePool() that will not update profile for this AllocatePool action. + // + Status = SmmInternalAllocatePool ( + EfiRuntimeServicesData, + sizeof (*DriverInfoData) + sizeof (LIST_ENTRY) + PdbSize, + (VOID **)&DriverInfoData + ); + if (EFI_ERROR (Status)) { + return NULL; + } + + ASSERT (DriverInfoData != NULL); + + ZeroMem (DriverInfoData, sizeof (*DriverInfoData)); + + DriverInfo = &DriverInfoData->DriverInfo; + DriverInfoData->Signature = MEMORY_PROFILE_DRIVER_INFO_SIGNATURE; + DriverInfo->Header.Signature = MEMORY_PROFILE_DRIVER_INFO_SIGNATURE; + DriverInfo->Header.Length = (UINT16)(sizeof (MEMORY_PROFILE_DRIVER_INFO) + PdbOccupiedSize); + DriverInfo->Header.Revision = MEMORY_PROFILE_DRIVER_INFO_REVISION; + if (FileName != NULL) { + CopyMem (&DriverInfo->FileName, FileName, sizeof (EFI_GUID)); + } + + DriverInfo->ImageBase = ImageBase; + DriverInfo->ImageSize = ImageSize; + DriverInfo->EntryPoint = EntryPoint; + DriverInfo->ImageSubsystem = ImageSubsystem; + if ((EntryPoint != 0) && ((EntryPoint < ImageBase) || (EntryPoint >= (ImageBase + ImageSize)))) { + // + // If the EntryPoint is not in the range of image buffer, it should come from emulation environment. + // So patch ImageBuffer here to align the EntryPoint. + // + Status = InternalPeCoffGetEntryPoint ((VOID *)(UINTN)ImageBase, &EntryPointInImage); + ASSERT_EFI_ERROR (Status); + DriverInfo->ImageBase = ImageBase + EntryPoint - (PHYSICAL_ADDRESS)(UINTN)EntryPointInImage; + } + + DriverInfo->FileType = FileType; + DriverInfoData->AllocInfoList = (LIST_ENTRY *)(DriverInfoData + 1); + InitializeListHead (DriverInfoData->AllocInfoList); + DriverInfo->CurrentUsage = 0; + DriverInfo->PeakUsage = 0; + DriverInfo->AllocRecordCount = 0; + if (PdbSize != 0) { + DriverInfo->PdbStringOffset = (UINT16)sizeof (MEMORY_PROFILE_DRIVER_INFO); + DriverInfoData->PdbString = (CHAR8 *)(DriverInfoData->AllocInfoList + 1); + CopyMem (DriverInfoData->PdbString, PdbString, PdbSize); + } else { + DriverInfo->PdbStringOffset = 0; + DriverInfoData->PdbString = NULL; + } + + InsertTailList (ContextData->DriverInfoList, &DriverInfoData->Link); + ContextData->Context.ImageCount++; + ContextData->Context.TotalImageSize += DriverInfo->ImageSize; + + return DriverInfoData; +} + +/** + Register image to DXE. + + @param FileName File name of the image. + @param ImageBase Image base address. + @param ImageSize Image size. + @param FileType File type of the image. + +**/ +VOID +RegisterImageToDxe ( + IN EFI_GUID *FileName, + IN PHYSICAL_ADDRESS ImageBase, + IN UINT64 ImageSize, + IN EFI_FV_FILETYPE FileType + ) +{ + EFI_STATUS Status; + EDKII_MEMORY_PROFILE_PROTOCOL *ProfileProtocol; + MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *FilePath; + UINT8 TempBuffer[sizeof (MEDIA_FW_VOL_FILEPATH_DEVICE_PATH) + sizeof (EFI_DEVICE_PATH_PROTOCOL)]; + + if (IS_UEFI_MEMORY_PROFILE_ENABLED) { + FilePath = (MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *)TempBuffer; + Status = gBS->LocateProtocol (&gEdkiiMemoryProfileGuid, NULL, (VOID **)&ProfileProtocol); + if (!EFI_ERROR (Status)) { + EfiInitializeFwVolDevicepathNode (FilePath, FileName); + SetDevicePathEndNode (FilePath + 1); + + Status = ProfileProtocol->RegisterImage ( + ProfileProtocol, + (EFI_DEVICE_PATH_PROTOCOL *)FilePath, + ImageBase, + ImageSize, + FileType + ); + } + } +} + +/** + Unregister image from DXE. + + @param FileName File name of the image. + @param ImageBase Image base address. + @param ImageSize Image size. + +**/ +VOID +UnregisterImageFromDxe ( + IN EFI_GUID *FileName, + IN PHYSICAL_ADDRESS ImageBase, + IN UINT64 ImageSize + ) +{ + EFI_STATUS Status; + EDKII_MEMORY_PROFILE_PROTOCOL *ProfileProtocol; + MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *FilePath; + UINT8 TempBuffer[sizeof (MEDIA_FW_VOL_FILEPATH_DEVICE_PATH) + sizeof (EFI_DEVICE_PATH_PROTOCOL)]; + + if (IS_UEFI_MEMORY_PROFILE_ENABLED) { + FilePath = (MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *)TempBuffer; + Status = gBS->LocateProtocol (&gEdkiiMemoryProfileGuid, NULL, (VOID *)&ProfileProtocol); + if (!EFI_ERROR (Status)) { + EfiInitializeFwVolDevicepathNode (FilePath, FileName); + SetDevicePathEndNode (FilePath + 1); + + Status = ProfileProtocol->UnregisterImage ( + ProfileProtocol, + (EFI_DEVICE_PATH_PROTOCOL *)FilePath, + ImageBase, + ImageSize + ); + } + } +} + +/** + Return if record for this driver is needed.. + + @param DriverFilePath Driver file path. + + @retval TRUE Record for this driver is needed. + @retval FALSE Record for this driver is not needed. + +**/ +BOOLEAN +NeedRecordThisDriver ( + IN EFI_DEVICE_PATH_PROTOCOL *DriverFilePath + ) +{ + EFI_DEVICE_PATH_PROTOCOL *TmpDevicePath; + EFI_DEVICE_PATH_PROTOCOL *DevicePathInstance; + UINTN DevicePathSize; + UINTN FilePathSize; + + if (!IsDevicePathValid (mSmramProfileDriverPath, mSmramProfileDriverPathSize)) { + // + // Invalid Device Path means record all. + // + return TRUE; + } + + // + // Record FilePath without end node. + // + FilePathSize = GetDevicePathSize (DriverFilePath) - sizeof (EFI_DEVICE_PATH_PROTOCOL); + + DevicePathInstance = mSmramProfileDriverPath; + do { + // + // Find End node (it might be END_ENTIRE or END_INSTANCE) + // + TmpDevicePath = DevicePathInstance; + while (!IsDevicePathEndType (TmpDevicePath)) { + TmpDevicePath = NextDevicePathNode (TmpDevicePath); + } + + // + // Do not compare END node + // + DevicePathSize = (UINTN)TmpDevicePath - (UINTN)DevicePathInstance; + if ((FilePathSize == DevicePathSize) && + (CompareMem (DriverFilePath, DevicePathInstance, DevicePathSize) == 0)) + { + return TRUE; + } + + // + // Get next instance + // + DevicePathInstance = (EFI_DEVICE_PATH_PROTOCOL *)((UINTN)DevicePathInstance + DevicePathSize + DevicePathNodeLength (TmpDevicePath)); + } while (DevicePathSubType (TmpDevicePath) != END_ENTIRE_DEVICE_PATH_SUBTYPE); + + return FALSE; +} + +/** + Register SMM Core to SMRAM profile. + + @param ContextData SMRAM profile context. + + @retval TRUE Register success. + @retval FALSE Register fail. + +**/ +BOOLEAN +RegisterSmmCore ( + IN MEMORY_PROFILE_CONTEXT_DATA *ContextData + ) +{ + MEMORY_PROFILE_DRIVER_INFO_DATA *DriverInfoData; + PHYSICAL_ADDRESS ImageBase; + UINT8 TempBuffer[sizeof (MEDIA_FW_VOL_FILEPATH_DEVICE_PATH) + sizeof (EFI_DEVICE_PATH_PROTOCOL)]; + MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *FilePath; + + FilePath = (MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *)TempBuffer; + EfiInitializeFwVolDevicepathNode (FilePath, &gEfiCallerIdGuid); + SetDevicePathEndNode (FilePath + 1); + + if (!NeedRecordThisDriver ((EFI_DEVICE_PATH_PROTOCOL *)FilePath)) { + return FALSE; + } + + ImageBase = gSmmCorePrivate->PiSmmCoreImageBase; + DriverInfoData = BuildDriverInfo ( + ContextData, + &gEfiCallerIdGuid, + ImageBase, + gSmmCorePrivate->PiSmmCoreImageSize, + gSmmCorePrivate->PiSmmCoreEntryPoint, + InternalPeCoffGetSubsystem ((VOID *)(UINTN)ImageBase), + EFI_FV_FILETYPE_SMM_CORE + ); + if (DriverInfoData == NULL) { + return FALSE; + } + + return TRUE; +} + +/** + Initialize SMRAM profile. + +**/ +VOID +SmramProfileInit ( + VOID + ) +{ + MEMORY_PROFILE_CONTEXT_DATA *SmramProfileContext; + + RegisterImageToDxe ( + &gEfiCallerIdGuid, + gSmmCorePrivate->PiSmmCoreImageBase, + gSmmCorePrivate->PiSmmCoreImageSize, + EFI_FV_FILETYPE_SMM_CORE + ); + + if (!IS_SMRAM_PROFILE_ENABLED) { + return; + } + + SmramProfileContext = GetSmramProfileContext (); + if (SmramProfileContext != NULL) { + return; + } + + mSmramProfileGettingStatus = FALSE; + if ((PcdGet8 (PcdMemoryProfilePropertyMask) & BIT7) != 0) { + mSmramProfileRecordingEnable = MEMORY_PROFILE_RECORDING_DISABLE; + } else { + mSmramProfileRecordingEnable = MEMORY_PROFILE_RECORDING_ENABLE; + } + + mSmramProfileDriverPathSize = PcdGetSize (PcdMemoryProfileDriverPath); + mSmramProfileDriverPath = AllocateCopyPool (mSmramProfileDriverPathSize, PcdGetPtr (PcdMemoryProfileDriverPath)); + mSmramProfileContextPtr = &mSmramProfileContext; + + RegisterSmmCore (&mSmramProfileContext); + + DEBUG ((DEBUG_INFO, "SmramProfileInit SmramProfileContext - 0x%x\n", &mSmramProfileContext)); +} + +/** + Install SMRAM profile protocol. + +**/ +VOID +SmramProfileInstallProtocol ( + VOID + ) +{ + EFI_HANDLE Handle; + EFI_STATUS Status; + + if (!IS_SMRAM_PROFILE_ENABLED) { + return; + } + + Handle = NULL; + Status = SmmInstallProtocolInterface ( + &Handle, + &gEdkiiSmmMemoryProfileGuid, + EFI_NATIVE_INTERFACE, + &mSmmProfileProtocol + ); + ASSERT_EFI_ERROR (Status); +} + +/** + Get the GUID file name from the file path. + + @param FilePath File path. + + @return The GUID file name from the file path. + +**/ +EFI_GUID * +GetFileNameFromFilePath ( + IN EFI_DEVICE_PATH_PROTOCOL *FilePath + ) +{ + MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *ThisFilePath; + EFI_GUID *FileName; + + FileName = NULL; + if (FilePath != NULL) { + ThisFilePath = (MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *)FilePath; + while (!IsDevicePathEnd (ThisFilePath)) { + FileName = EfiGetNameGuidFromFwVolDevicePathNode (ThisFilePath); + if (FileName != NULL) { + break; + } + + ThisFilePath = (MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *)NextDevicePathNode (ThisFilePath); + } + } + + return FileName; +} + +/** + Register SMM image to SMRAM profile. + + @param DriverEntry SMM image info. + @param RegisterToDxe Register image to DXE. + + @return EFI_SUCCESS Register successfully. + @return EFI_UNSUPPORTED Memory profile is unsupported, + or memory profile for the image is not required. + @return EFI_OUT_OF_RESOURCES No enough resource for this register. + +**/ +EFI_STATUS +RegisterSmramProfileImage ( + IN EFI_SMM_DRIVER_ENTRY *DriverEntry, + IN BOOLEAN RegisterToDxe + ) +{ + MEMORY_PROFILE_CONTEXT_DATA *ContextData; + MEMORY_PROFILE_DRIVER_INFO_DATA *DriverInfoData; + UINT8 TempBuffer[sizeof (MEDIA_FW_VOL_FILEPATH_DEVICE_PATH) + sizeof (EFI_DEVICE_PATH_PROTOCOL)]; + MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *FilePath; + + if (RegisterToDxe) { + RegisterImageToDxe ( + &DriverEntry->FileName, + DriverEntry->ImageBuffer, + EFI_PAGES_TO_SIZE (DriverEntry->NumberOfPage), + EFI_FV_FILETYPE_SMM + ); + } + + if (!IS_SMRAM_PROFILE_ENABLED) { + return EFI_UNSUPPORTED; + } + + FilePath = (MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *)TempBuffer; + EfiInitializeFwVolDevicepathNode (FilePath, &DriverEntry->FileName); + SetDevicePathEndNode (FilePath + 1); + + if (!NeedRecordThisDriver ((EFI_DEVICE_PATH_PROTOCOL *)FilePath)) { + return EFI_UNSUPPORTED; + } + + ContextData = GetSmramProfileContext (); + if (ContextData == NULL) { + return EFI_UNSUPPORTED; + } + + DriverInfoData = BuildDriverInfo ( + ContextData, + &DriverEntry->FileName, + DriverEntry->ImageBuffer, + EFI_PAGES_TO_SIZE (DriverEntry->NumberOfPage), + DriverEntry->ImageEntryPoint, + InternalPeCoffGetSubsystem ((VOID *)(UINTN)DriverEntry->ImageBuffer), + EFI_FV_FILETYPE_SMM + ); + if (DriverInfoData == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + return EFI_SUCCESS; +} + +/** + Search image from memory profile. + + @param ContextData Memory profile context. + @param FileName Image file name. + @param Address Image Address. + + @return Pointer to memory profile driver info. + +**/ +MEMORY_PROFILE_DRIVER_INFO_DATA * +GetMemoryProfileDriverInfoByFileNameAndAddress ( + IN MEMORY_PROFILE_CONTEXT_DATA *ContextData, + IN EFI_GUID *FileName, + IN PHYSICAL_ADDRESS Address + ) +{ + MEMORY_PROFILE_DRIVER_INFO *DriverInfo; + MEMORY_PROFILE_DRIVER_INFO_DATA *DriverInfoData; + LIST_ENTRY *DriverLink; + LIST_ENTRY *DriverInfoList; + + DriverInfoList = ContextData->DriverInfoList; + + for (DriverLink = DriverInfoList->ForwardLink; + DriverLink != DriverInfoList; + DriverLink = DriverLink->ForwardLink) + { + DriverInfoData = CR ( + DriverLink, + MEMORY_PROFILE_DRIVER_INFO_DATA, + Link, + MEMORY_PROFILE_DRIVER_INFO_SIGNATURE + ); + DriverInfo = &DriverInfoData->DriverInfo; + if ((CompareGuid (&DriverInfo->FileName, FileName)) && + (Address >= DriverInfo->ImageBase) && + (Address < (DriverInfo->ImageBase + DriverInfo->ImageSize))) + { + return DriverInfoData; + } + } + + return NULL; +} + +/** + Search image from memory profile. + It will return image, if (Address >= ImageBuffer) AND (Address < ImageBuffer + ImageSize) + + @param ContextData Memory profile context. + @param Address Image or Function address. + + @return Pointer to memory profile driver info. + +**/ +MEMORY_PROFILE_DRIVER_INFO_DATA * +GetMemoryProfileDriverInfoFromAddress ( + IN MEMORY_PROFILE_CONTEXT_DATA *ContextData, + IN PHYSICAL_ADDRESS Address + ) +{ + MEMORY_PROFILE_DRIVER_INFO *DriverInfo; + MEMORY_PROFILE_DRIVER_INFO_DATA *DriverInfoData; + LIST_ENTRY *DriverLink; + LIST_ENTRY *DriverInfoList; + + DriverInfoList = ContextData->DriverInfoList; + + for (DriverLink = DriverInfoList->ForwardLink; + DriverLink != DriverInfoList; + DriverLink = DriverLink->ForwardLink) + { + DriverInfoData = CR ( + DriverLink, + MEMORY_PROFILE_DRIVER_INFO_DATA, + Link, + MEMORY_PROFILE_DRIVER_INFO_SIGNATURE + ); + DriverInfo = &DriverInfoData->DriverInfo; + if ((Address >= DriverInfo->ImageBase) && + (Address < (DriverInfo->ImageBase + DriverInfo->ImageSize))) + { + return DriverInfoData; + } + } + + return NULL; +} + +/** + Unregister image from SMRAM profile. + + @param DriverEntry SMM image info. + @param UnregisterFromDxe Unregister image from DXE. + + @return EFI_SUCCESS Unregister successfully. + @return EFI_UNSUPPORTED Memory profile is unsupported, + or memory profile for the image is not required. + @return EFI_NOT_FOUND The image is not found. + +**/ +EFI_STATUS +UnregisterSmramProfileImage ( + IN EFI_SMM_DRIVER_ENTRY *DriverEntry, + IN BOOLEAN UnregisterFromDxe + ) +{ + EFI_STATUS Status; + MEMORY_PROFILE_CONTEXT_DATA *ContextData; + MEMORY_PROFILE_DRIVER_INFO_DATA *DriverInfoData; + EFI_GUID *FileName; + PHYSICAL_ADDRESS ImageAddress; + VOID *EntryPointInImage; + UINT8 TempBuffer[sizeof (MEDIA_FW_VOL_FILEPATH_DEVICE_PATH) + sizeof (EFI_DEVICE_PATH_PROTOCOL)]; + MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *FilePath; + + if (UnregisterFromDxe) { + UnregisterImageFromDxe ( + &DriverEntry->FileName, + DriverEntry->ImageBuffer, + EFI_PAGES_TO_SIZE (DriverEntry->NumberOfPage) + ); + } + + if (!IS_SMRAM_PROFILE_ENABLED) { + return EFI_UNSUPPORTED; + } + + FilePath = (MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *)TempBuffer; + EfiInitializeFwVolDevicepathNode (FilePath, &DriverEntry->FileName); + SetDevicePathEndNode (FilePath + 1); + + if (!NeedRecordThisDriver ((EFI_DEVICE_PATH_PROTOCOL *)FilePath)) { + return EFI_UNSUPPORTED; + } + + ContextData = GetSmramProfileContext (); + if (ContextData == NULL) { + return EFI_UNSUPPORTED; + } + + DriverInfoData = NULL; + FileName = &DriverEntry->FileName; + ImageAddress = DriverEntry->ImageBuffer; + if ((DriverEntry->ImageEntryPoint < ImageAddress) || (DriverEntry->ImageEntryPoint >= (ImageAddress + EFI_PAGES_TO_SIZE (DriverEntry->NumberOfPage)))) { + // + // If the EntryPoint is not in the range of image buffer, it should come from emulation environment. + // So patch ImageAddress here to align the EntryPoint. + // + Status = InternalPeCoffGetEntryPoint ((VOID *)(UINTN)ImageAddress, &EntryPointInImage); + ASSERT_EFI_ERROR (Status); + ImageAddress = ImageAddress + (UINTN)DriverEntry->ImageEntryPoint - (UINTN)EntryPointInImage; + } + + if (FileName != NULL) { + DriverInfoData = GetMemoryProfileDriverInfoByFileNameAndAddress (ContextData, FileName, ImageAddress); + } + + if (DriverInfoData == NULL) { + DriverInfoData = GetMemoryProfileDriverInfoFromAddress (ContextData, ImageAddress); + } + + if (DriverInfoData == NULL) { + return EFI_NOT_FOUND; + } + + ContextData->Context.TotalImageSize -= DriverInfoData->DriverInfo.ImageSize; + + // Keep the ImageBase for RVA calculation in Application. + // DriverInfoData->DriverInfo.ImageBase = 0; + DriverInfoData->DriverInfo.ImageSize = 0; + + if (DriverInfoData->DriverInfo.PeakUsage == 0) { + ContextData->Context.ImageCount--; + RemoveEntryList (&DriverInfoData->Link); + // + // Use SmmInternalFreePool() that will not update profile for this FreePool action. + // + SmmInternalFreePool (DriverInfoData); + } + + return EFI_SUCCESS; +} + +/** + Return if this memory type needs to be recorded into memory profile. + Only need to record EfiRuntimeServicesCode and EfiRuntimeServicesData for SMRAM profile. + + @param MemoryType Memory type. + + @retval TRUE This memory type need to be recorded. + @retval FALSE This memory type need not to be recorded. + +**/ +BOOLEAN +SmmCoreNeedRecordProfile ( + IN EFI_MEMORY_TYPE MemoryType + ) +{ + UINT64 TestBit; + + if ((MemoryType != EfiRuntimeServicesCode) && + (MemoryType != EfiRuntimeServicesData)) + { + return FALSE; + } + + TestBit = LShiftU64 (1, MemoryType); + + if ((PcdGet64 (PcdMemoryProfileMemoryType) & TestBit) != 0) { + return TRUE; + } else { + return FALSE; + } +} + +/** + Convert EFI memory type to profile memory index. The rule is: + If BIOS memory type (0 ~ EfiMaxMemoryType - 1), ProfileMemoryIndex = MemoryType. + As SMRAM profile is only to record EfiRuntimeServicesCode and EfiRuntimeServicesData, + so return input memory type directly. + + @param MemoryType Memory type. + + @return EFI memory type as profile memory index. + +**/ +EFI_MEMORY_TYPE +GetProfileMemoryIndex ( + IN EFI_MEMORY_TYPE MemoryType + ) +{ + return MemoryType; +} + +/** + Update SMRAM profile FreeMemoryPages information + + @param ContextData Memory profile context. + +**/ +VOID +SmramProfileUpdateFreePages ( + IN MEMORY_PROFILE_CONTEXT_DATA *ContextData + ) +{ + LIST_ENTRY *Node; + FREE_PAGE_LIST *Pages; + LIST_ENTRY *FreePageList; + UINTN NumberOfPages; + + NumberOfPages = 0; + FreePageList = &mSmmMemoryMap; + for (Node = FreePageList->BackLink; + Node != FreePageList; + Node = Node->BackLink) + { + Pages = BASE_CR (Node, FREE_PAGE_LIST, Link); + NumberOfPages += Pages->NumberOfPages; + } + + mSmramFreeMemory.TotalFreeMemoryPages = NumberOfPages; + + if (NumberOfPages <= SMRAM_INFO_DUMP_PAGE_THRESHOLD) { + DumpSmramInfo (); + } +} + +/** + Update SMRAM profile Allocate information. + + @param CallerAddress Address of caller who call Allocate. + @param Action This Allocate action. + @param MemoryType Memory type. + @param Size Buffer size. + @param Buffer Buffer address. + @param ActionString String for memory profile action. + + @return EFI_SUCCESS Memory profile is updated. + @return EFI_UNSUPPORTED Memory profile is unsupported, + or memory profile for the image is not required. + @return EFI_OUT_OF_RESOURCES No enough resource to update memory profile for allocate action. + +**/ +EFI_STATUS +SmmCoreUpdateProfileAllocate ( + IN PHYSICAL_ADDRESS CallerAddress, + IN MEMORY_PROFILE_ACTION Action, + IN EFI_MEMORY_TYPE MemoryType, + IN UINTN Size, + IN VOID *Buffer, + IN CHAR8 *ActionString OPTIONAL + ) +{ + EFI_STATUS Status; + MEMORY_PROFILE_CONTEXT *Context; + MEMORY_PROFILE_DRIVER_INFO *DriverInfo; + MEMORY_PROFILE_ALLOC_INFO *AllocInfo; + MEMORY_PROFILE_CONTEXT_DATA *ContextData; + MEMORY_PROFILE_DRIVER_INFO_DATA *DriverInfoData; + MEMORY_PROFILE_ALLOC_INFO_DATA *AllocInfoData; + EFI_MEMORY_TYPE ProfileMemoryIndex; + MEMORY_PROFILE_ACTION BasicAction; + UINTN ActionStringSize; + UINTN ActionStringOccupiedSize; + + BasicAction = Action & MEMORY_PROFILE_ACTION_BASIC_MASK; + + ContextData = GetSmramProfileContext (); + if (ContextData == NULL) { + return EFI_UNSUPPORTED; + } + + DriverInfoData = GetMemoryProfileDriverInfoFromAddress (ContextData, CallerAddress); + if (DriverInfoData == NULL) { + return EFI_UNSUPPORTED; + } + + ActionStringSize = 0; + ActionStringOccupiedSize = 0; + if (ActionString != NULL) { + ActionStringSize = AsciiStrSize (ActionString); + ActionStringOccupiedSize = GET_OCCUPIED_SIZE (ActionStringSize, sizeof (UINT64)); + } + + // + // Use SmmInternalAllocatePool() that will not update profile for this AllocatePool action. + // + AllocInfoData = NULL; + Status = SmmInternalAllocatePool ( + EfiRuntimeServicesData, + sizeof (*AllocInfoData) + ActionStringSize, + (VOID **)&AllocInfoData + ); + if (EFI_ERROR (Status)) { + return EFI_OUT_OF_RESOURCES; + } + + ASSERT (AllocInfoData != NULL); + + // + // Only update SequenceCount if and only if it is basic action. + // + if (Action == BasicAction) { + ContextData->Context.SequenceCount++; + } + + AllocInfo = &AllocInfoData->AllocInfo; + AllocInfoData->Signature = MEMORY_PROFILE_ALLOC_INFO_SIGNATURE; + AllocInfo->Header.Signature = MEMORY_PROFILE_ALLOC_INFO_SIGNATURE; + AllocInfo->Header.Length = (UINT16)(sizeof (MEMORY_PROFILE_ALLOC_INFO) + ActionStringOccupiedSize); + AllocInfo->Header.Revision = MEMORY_PROFILE_ALLOC_INFO_REVISION; + AllocInfo->CallerAddress = CallerAddress; + AllocInfo->SequenceId = ContextData->Context.SequenceCount; + AllocInfo->Action = Action; + AllocInfo->MemoryType = MemoryType; + AllocInfo->Buffer = (PHYSICAL_ADDRESS)(UINTN)Buffer; + AllocInfo->Size = Size; + if (ActionString != NULL) { + AllocInfo->ActionStringOffset = (UINT16)sizeof (MEMORY_PROFILE_ALLOC_INFO); + AllocInfoData->ActionString = (CHAR8 *)(AllocInfoData + 1); + CopyMem (AllocInfoData->ActionString, ActionString, ActionStringSize); + } else { + AllocInfo->ActionStringOffset = 0; + AllocInfoData->ActionString = NULL; + } + + InsertTailList (DriverInfoData->AllocInfoList, &AllocInfoData->Link); + + Context = &ContextData->Context; + DriverInfo = &DriverInfoData->DriverInfo; + DriverInfo->AllocRecordCount++; + + // + // Update summary if and only if it is basic action. + // + if (Action == BasicAction) { + ProfileMemoryIndex = GetProfileMemoryIndex (MemoryType); + + DriverInfo->CurrentUsage += Size; + if (DriverInfo->PeakUsage < DriverInfo->CurrentUsage) { + DriverInfo->PeakUsage = DriverInfo->CurrentUsage; + } + + DriverInfo->CurrentUsageByType[ProfileMemoryIndex] += Size; + if (DriverInfo->PeakUsageByType[ProfileMemoryIndex] < DriverInfo->CurrentUsageByType[ProfileMemoryIndex]) { + DriverInfo->PeakUsageByType[ProfileMemoryIndex] = DriverInfo->CurrentUsageByType[ProfileMemoryIndex]; + } + + Context->CurrentTotalUsage += Size; + if (Context->PeakTotalUsage < Context->CurrentTotalUsage) { + Context->PeakTotalUsage = Context->CurrentTotalUsage; + } + + Context->CurrentTotalUsageByType[ProfileMemoryIndex] += Size; + if (Context->PeakTotalUsageByType[ProfileMemoryIndex] < Context->CurrentTotalUsageByType[ProfileMemoryIndex]) { + Context->PeakTotalUsageByType[ProfileMemoryIndex] = Context->CurrentTotalUsageByType[ProfileMemoryIndex]; + } + + SmramProfileUpdateFreePages (ContextData); + } + + return EFI_SUCCESS; +} + +/** + Get memory profile alloc info from memory profile + + @param DriverInfoData Driver info + @param BasicAction This Free basic action + @param Size Buffer size + @param Buffer Buffer address + + @return Pointer to memory profile alloc info. +**/ +MEMORY_PROFILE_ALLOC_INFO_DATA * +GetMemoryProfileAllocInfoFromAddress ( + IN MEMORY_PROFILE_DRIVER_INFO_DATA *DriverInfoData, + IN MEMORY_PROFILE_ACTION BasicAction, + IN UINTN Size, + IN VOID *Buffer + ) +{ + LIST_ENTRY *AllocInfoList; + LIST_ENTRY *AllocLink; + MEMORY_PROFILE_ALLOC_INFO *AllocInfo; + MEMORY_PROFILE_ALLOC_INFO_DATA *AllocInfoData; + + AllocInfoList = DriverInfoData->AllocInfoList; + + for (AllocLink = AllocInfoList->ForwardLink; + AllocLink != AllocInfoList; + AllocLink = AllocLink->ForwardLink) + { + AllocInfoData = CR ( + AllocLink, + MEMORY_PROFILE_ALLOC_INFO_DATA, + Link, + MEMORY_PROFILE_ALLOC_INFO_SIGNATURE + ); + AllocInfo = &AllocInfoData->AllocInfo; + if ((AllocInfo->Action & MEMORY_PROFILE_ACTION_BASIC_MASK) != BasicAction) { + continue; + } + + switch (BasicAction) { + case MemoryProfileActionAllocatePages: + if ((AllocInfo->Buffer <= (PHYSICAL_ADDRESS)(UINTN)Buffer) && + ((AllocInfo->Buffer + AllocInfo->Size) >= ((PHYSICAL_ADDRESS)(UINTN)Buffer + Size))) + { + return AllocInfoData; + } + + break; + case MemoryProfileActionAllocatePool: + if (AllocInfo->Buffer == (PHYSICAL_ADDRESS)(UINTN)Buffer) { + return AllocInfoData; + } + + break; + default: + ASSERT (FALSE); + break; + } + } + + return NULL; +} + +/** + Update SMRAM profile Free information. + + @param CallerAddress Address of caller who call Free. + @param Action This Free action. + @param Size Buffer size. + @param Buffer Buffer address. + + @return EFI_SUCCESS Memory profile is updated. + @return EFI_UNSUPPORTED Memory profile is unsupported. + @return EFI_NOT_FOUND No matched allocate info found for free action. + +**/ +EFI_STATUS +SmmCoreUpdateProfileFree ( + IN PHYSICAL_ADDRESS CallerAddress, + IN MEMORY_PROFILE_ACTION Action, + IN UINTN Size, + IN VOID *Buffer + ) +{ + MEMORY_PROFILE_CONTEXT *Context; + MEMORY_PROFILE_DRIVER_INFO *DriverInfo; + MEMORY_PROFILE_ALLOC_INFO *AllocInfo; + MEMORY_PROFILE_CONTEXT_DATA *ContextData; + MEMORY_PROFILE_DRIVER_INFO_DATA *DriverInfoData; + LIST_ENTRY *DriverLink; + LIST_ENTRY *DriverInfoList; + MEMORY_PROFILE_DRIVER_INFO_DATA *ThisDriverInfoData; + MEMORY_PROFILE_ALLOC_INFO_DATA *AllocInfoData; + EFI_MEMORY_TYPE ProfileMemoryIndex; + MEMORY_PROFILE_ACTION BasicAction; + BOOLEAN Found; + + BasicAction = Action & MEMORY_PROFILE_ACTION_BASIC_MASK; + + ContextData = GetSmramProfileContext (); + if (ContextData == NULL) { + return EFI_UNSUPPORTED; + } + + DriverInfoData = GetMemoryProfileDriverInfoFromAddress (ContextData, CallerAddress); + + // + // Do not return if DriverInfoData == NULL here, + // because driver A might free memory allocated by driver B. + // + + // + // Need use do-while loop to find all possible record, + // because one address might be recorded multiple times. + // + Found = FALSE; + AllocInfoData = NULL; + do { + if (DriverInfoData != NULL) { + switch (BasicAction) { + case MemoryProfileActionFreePages: + AllocInfoData = GetMemoryProfileAllocInfoFromAddress (DriverInfoData, MemoryProfileActionAllocatePages, Size, Buffer); + break; + case MemoryProfileActionFreePool: + AllocInfoData = GetMemoryProfileAllocInfoFromAddress (DriverInfoData, MemoryProfileActionAllocatePool, 0, Buffer); + break; + default: + ASSERT (FALSE); + AllocInfoData = NULL; + break; + } + } + + if (AllocInfoData == NULL) { + // + // Legal case, because driver A might free memory allocated by driver B, by some protocol. + // + DriverInfoList = ContextData->DriverInfoList; + + for (DriverLink = DriverInfoList->ForwardLink; + DriverLink != DriverInfoList; + DriverLink = DriverLink->ForwardLink) + { + ThisDriverInfoData = CR ( + DriverLink, + MEMORY_PROFILE_DRIVER_INFO_DATA, + Link, + MEMORY_PROFILE_DRIVER_INFO_SIGNATURE + ); + switch (BasicAction) { + case MemoryProfileActionFreePages: + AllocInfoData = GetMemoryProfileAllocInfoFromAddress (ThisDriverInfoData, MemoryProfileActionAllocatePages, Size, Buffer); + break; + case MemoryProfileActionFreePool: + AllocInfoData = GetMemoryProfileAllocInfoFromAddress (ThisDriverInfoData, MemoryProfileActionAllocatePool, 0, Buffer); + break; + default: + ASSERT (FALSE); + AllocInfoData = NULL; + break; + } + + if (AllocInfoData != NULL) { + DriverInfoData = ThisDriverInfoData; + break; + } + } + + if (AllocInfoData == NULL) { + // + // If (!Found), no matched allocate info is found for this free action. + // It is because the specified memory type allocate actions have been filtered by + // CoreNeedRecordProfile(), but free actions have no memory type information, + // they can not be filtered by CoreNeedRecordProfile(). Then, they will be + // filtered here. + // + // If (Found), it is normal exit path. + return (Found ? EFI_SUCCESS : EFI_NOT_FOUND); + } + } + + ASSERT (DriverInfoData != NULL); + ASSERT (AllocInfoData != NULL); + + Found = TRUE; + + Context = &ContextData->Context; + DriverInfo = &DriverInfoData->DriverInfo; + AllocInfo = &AllocInfoData->AllocInfo; + + DriverInfo->AllocRecordCount--; + // + // Update summary if and only if it is basic action. + // + if (AllocInfo->Action == (AllocInfo->Action & MEMORY_PROFILE_ACTION_BASIC_MASK)) { + ProfileMemoryIndex = GetProfileMemoryIndex (AllocInfo->MemoryType); + + Context->CurrentTotalUsage -= AllocInfo->Size; + Context->CurrentTotalUsageByType[ProfileMemoryIndex] -= AllocInfo->Size; + + DriverInfo->CurrentUsage -= AllocInfo->Size; + DriverInfo->CurrentUsageByType[ProfileMemoryIndex] -= AllocInfo->Size; + } + + RemoveEntryList (&AllocInfoData->Link); + + if (BasicAction == MemoryProfileActionFreePages) { + if (AllocInfo->Buffer != (PHYSICAL_ADDRESS)(UINTN)Buffer) { + SmmCoreUpdateProfileAllocate ( + AllocInfo->CallerAddress, + AllocInfo->Action, + AllocInfo->MemoryType, + (UINTN)((PHYSICAL_ADDRESS)(UINTN)Buffer - AllocInfo->Buffer), + (VOID *)(UINTN)AllocInfo->Buffer, + AllocInfoData->ActionString + ); + } + + if (AllocInfo->Buffer + AllocInfo->Size != ((PHYSICAL_ADDRESS)(UINTN)Buffer + Size)) { + SmmCoreUpdateProfileAllocate ( + AllocInfo->CallerAddress, + AllocInfo->Action, + AllocInfo->MemoryType, + (UINTN)((AllocInfo->Buffer + AllocInfo->Size) - ((PHYSICAL_ADDRESS)(UINTN)Buffer + Size)), + (VOID *)((UINTN)Buffer + Size), + AllocInfoData->ActionString + ); + } + } + + // + // Use SmmInternalFreePool() that will not update profile for this FreePool action. + // + SmmInternalFreePool (AllocInfoData); + } while (TRUE); +} + +/** + Update SMRAM profile information. + + @param CallerAddress Address of caller who call Allocate or Free. + @param Action This Allocate or Free action. + @param MemoryType Memory type. + EfiMaxMemoryType means the MemoryType is unknown. + @param Size Buffer size. + @param Buffer Buffer address. + @param ActionString String for memory profile action. + Only needed for user defined allocate action. + + @return EFI_SUCCESS Memory profile is updated. + @return EFI_UNSUPPORTED Memory profile is unsupported, + or memory profile for the image is not required, + or memory profile for the memory type is not required. + @return EFI_ACCESS_DENIED It is during memory profile data getting. + @return EFI_ABORTED Memory profile recording is not enabled. + @return EFI_OUT_OF_RESOURCES No enough resource to update memory profile for allocate action. + @return EFI_NOT_FOUND No matched allocate info found for free action. + +**/ +EFI_STATUS +EFIAPI +SmmCoreUpdateProfile ( + IN PHYSICAL_ADDRESS CallerAddress, + IN MEMORY_PROFILE_ACTION Action, + IN EFI_MEMORY_TYPE MemoryType, // Valid for AllocatePages/AllocatePool + IN UINTN Size, // Valid for AllocatePages/FreePages/AllocatePool + IN VOID *Buffer, + IN CHAR8 *ActionString OPTIONAL + ) +{ + EFI_STATUS Status; + MEMORY_PROFILE_CONTEXT_DATA *ContextData; + MEMORY_PROFILE_ACTION BasicAction; + + if (!IS_SMRAM_PROFILE_ENABLED) { + return EFI_UNSUPPORTED; + } + + if (mSmramProfileGettingStatus) { + return EFI_ACCESS_DENIED; + } + + if (!mSmramProfileRecordingEnable) { + return EFI_ABORTED; + } + + // + // Get the basic action to know how to process the record + // + BasicAction = Action & MEMORY_PROFILE_ACTION_BASIC_MASK; + + // + // Free operations have no memory type information, so skip the check. + // + if ((BasicAction == MemoryProfileActionAllocatePages) || (BasicAction == MemoryProfileActionAllocatePool)) { + // + // Only record limited MemoryType. + // + if (!SmmCoreNeedRecordProfile (MemoryType)) { + return EFI_UNSUPPORTED; + } + } + + ContextData = GetSmramProfileContext (); + if (ContextData == NULL) { + return EFI_UNSUPPORTED; + } + + switch (BasicAction) { + case MemoryProfileActionAllocatePages: + Status = SmmCoreUpdateProfileAllocate (CallerAddress, Action, MemoryType, Size, Buffer, ActionString); + break; + case MemoryProfileActionFreePages: + Status = SmmCoreUpdateProfileFree (CallerAddress, Action, Size, Buffer); + break; + case MemoryProfileActionAllocatePool: + Status = SmmCoreUpdateProfileAllocate (CallerAddress, Action, MemoryType, Size, Buffer, ActionString); + break; + case MemoryProfileActionFreePool: + Status = SmmCoreUpdateProfileFree (CallerAddress, Action, 0, Buffer); + break; + default: + ASSERT (FALSE); + Status = EFI_UNSUPPORTED; + break; + } + + return Status; +} + +/** + SMRAM profile ready to lock callback function. + +**/ +VOID +SmramProfileReadyToLock ( + VOID + ) +{ + if (!IS_SMRAM_PROFILE_ENABLED) { + return; + } + + DEBUG ((DEBUG_INFO, "SmramProfileReadyToLock\n")); + mSmramReadyToLock = TRUE; +} + +//////////////////// + +/** + Get SMRAM profile data size. + + @return SMRAM profile data size. + +**/ +UINTN +SmramProfileGetDataSize ( + VOID + ) +{ + MEMORY_PROFILE_CONTEXT_DATA *ContextData; + MEMORY_PROFILE_DRIVER_INFO_DATA *DriverInfoData; + MEMORY_PROFILE_ALLOC_INFO_DATA *AllocInfoData; + LIST_ENTRY *DriverInfoList; + LIST_ENTRY *DriverLink; + LIST_ENTRY *AllocInfoList; + LIST_ENTRY *AllocLink; + UINTN TotalSize; + LIST_ENTRY *Node; + LIST_ENTRY *FreePageList; + LIST_ENTRY *FreePoolList; + FREE_POOL_HEADER *Pool; + UINTN PoolListIndex; + UINTN Index; + UINTN SmmPoolTypeIndex; + + ContextData = GetSmramProfileContext (); + if (ContextData == NULL) { + return 0; + } + + TotalSize = sizeof (MEMORY_PROFILE_CONTEXT); + + DriverInfoList = ContextData->DriverInfoList; + for (DriverLink = DriverInfoList->ForwardLink; + DriverLink != DriverInfoList; + DriverLink = DriverLink->ForwardLink) + { + DriverInfoData = CR ( + DriverLink, + MEMORY_PROFILE_DRIVER_INFO_DATA, + Link, + MEMORY_PROFILE_DRIVER_INFO_SIGNATURE + ); + TotalSize += DriverInfoData->DriverInfo.Header.Length; + + AllocInfoList = DriverInfoData->AllocInfoList; + for (AllocLink = AllocInfoList->ForwardLink; + AllocLink != AllocInfoList; + AllocLink = AllocLink->ForwardLink) + { + AllocInfoData = CR ( + AllocLink, + MEMORY_PROFILE_ALLOC_INFO_DATA, + Link, + MEMORY_PROFILE_ALLOC_INFO_SIGNATURE + ); + TotalSize += AllocInfoData->AllocInfo.Header.Length; + } + } + + Index = 0; + FreePageList = &mSmmMemoryMap; + for (Node = FreePageList->BackLink; + Node != FreePageList; + Node = Node->BackLink) + { + Index++; + } + + for (SmmPoolTypeIndex = 0; SmmPoolTypeIndex < SmmPoolTypeMax; SmmPoolTypeIndex++) { + for (PoolListIndex = 0; PoolListIndex < MAX_POOL_INDEX; PoolListIndex++) { + FreePoolList = &mSmmPoolLists[SmmPoolTypeIndex][PoolListIndex]; + for (Node = FreePoolList->BackLink; + Node != FreePoolList; + Node = Node->BackLink) + { + Pool = BASE_CR (Node, FREE_POOL_HEADER, Link); + if (Pool->Header.Available) { + Index++; + } + } + } + } + + TotalSize += (sizeof (MEMORY_PROFILE_FREE_MEMORY) + Index * sizeof (MEMORY_PROFILE_DESCRIPTOR)); + TotalSize += (sizeof (MEMORY_PROFILE_MEMORY_RANGE) + mFullSmramRangeCount * sizeof (MEMORY_PROFILE_DESCRIPTOR)); + + return TotalSize; +} + +/** + Copy SMRAM profile data. + + @param ProfileBuffer The buffer to hold SMRAM profile data. + @param ProfileSize On input, profile buffer size. + On output, actual profile data size copied. + @param ProfileOffset On input, profile buffer offset to copy. + On output, next time profile buffer offset to copy. + +**/ +VOID +SmramProfileCopyData ( + OUT VOID *ProfileBuffer, + IN OUT UINT64 *ProfileSize, + IN OUT UINT64 *ProfileOffset + ) +{ + MEMORY_PROFILE_CONTEXT *Context; + MEMORY_PROFILE_DRIVER_INFO *DriverInfo; + MEMORY_PROFILE_ALLOC_INFO *AllocInfo; + MEMORY_PROFILE_CONTEXT_DATA *ContextData; + MEMORY_PROFILE_DRIVER_INFO_DATA *DriverInfoData; + MEMORY_PROFILE_ALLOC_INFO_DATA *AllocInfoData; + LIST_ENTRY *DriverInfoList; + LIST_ENTRY *DriverLink; + LIST_ENTRY *AllocInfoList; + LIST_ENTRY *AllocLink; + LIST_ENTRY *Node; + FREE_PAGE_LIST *Pages; + LIST_ENTRY *FreePageList; + LIST_ENTRY *FreePoolList; + FREE_POOL_HEADER *Pool; + UINTN PoolListIndex; + UINT32 Index; + MEMORY_PROFILE_FREE_MEMORY *FreeMemory; + MEMORY_PROFILE_MEMORY_RANGE *MemoryRange; + MEMORY_PROFILE_DESCRIPTOR *MemoryProfileDescriptor; + UINT64 Offset; + UINT64 RemainingSize; + UINTN PdbSize; + UINTN ActionStringSize; + UINTN SmmPoolTypeIndex; + + ContextData = GetSmramProfileContext (); + if (ContextData == NULL) { + return; + } + + RemainingSize = *ProfileSize; + Offset = 0; + + if (*ProfileOffset < sizeof (MEMORY_PROFILE_CONTEXT)) { + if (RemainingSize >= sizeof (MEMORY_PROFILE_CONTEXT)) { + Context = ProfileBuffer; + CopyMem (Context, &ContextData->Context, sizeof (MEMORY_PROFILE_CONTEXT)); + RemainingSize -= sizeof (MEMORY_PROFILE_CONTEXT); + ProfileBuffer = (UINT8 *)ProfileBuffer + sizeof (MEMORY_PROFILE_CONTEXT); + } else { + goto Done; + } + } + + Offset += sizeof (MEMORY_PROFILE_CONTEXT); + + DriverInfoList = ContextData->DriverInfoList; + for (DriverLink = DriverInfoList->ForwardLink; + DriverLink != DriverInfoList; + DriverLink = DriverLink->ForwardLink) + { + DriverInfoData = CR ( + DriverLink, + MEMORY_PROFILE_DRIVER_INFO_DATA, + Link, + MEMORY_PROFILE_DRIVER_INFO_SIGNATURE + ); + if (*ProfileOffset < (Offset + DriverInfoData->DriverInfo.Header.Length)) { + if (RemainingSize >= DriverInfoData->DriverInfo.Header.Length) { + DriverInfo = ProfileBuffer; + CopyMem (DriverInfo, &DriverInfoData->DriverInfo, sizeof (MEMORY_PROFILE_DRIVER_INFO)); + if (DriverInfo->PdbStringOffset != 0) { + PdbSize = AsciiStrSize (DriverInfoData->PdbString); + CopyMem ((VOID *)((UINTN)DriverInfo + DriverInfo->PdbStringOffset), DriverInfoData->PdbString, PdbSize); + } + + RemainingSize -= DriverInfo->Header.Length; + ProfileBuffer = (UINT8 *)ProfileBuffer + DriverInfo->Header.Length; + } else { + goto Done; + } + } + + Offset += DriverInfoData->DriverInfo.Header.Length; + + AllocInfoList = DriverInfoData->AllocInfoList; + for (AllocLink = AllocInfoList->ForwardLink; + AllocLink != AllocInfoList; + AllocLink = AllocLink->ForwardLink) + { + AllocInfoData = CR ( + AllocLink, + MEMORY_PROFILE_ALLOC_INFO_DATA, + Link, + MEMORY_PROFILE_ALLOC_INFO_SIGNATURE + ); + if (*ProfileOffset < (Offset + AllocInfoData->AllocInfo.Header.Length)) { + if (RemainingSize >= AllocInfoData->AllocInfo.Header.Length) { + AllocInfo = ProfileBuffer; + CopyMem (AllocInfo, &AllocInfoData->AllocInfo, sizeof (MEMORY_PROFILE_ALLOC_INFO)); + if (AllocInfo->ActionStringOffset) { + ActionStringSize = AsciiStrSize (AllocInfoData->ActionString); + CopyMem ((VOID *)((UINTN)AllocInfo + AllocInfo->ActionStringOffset), AllocInfoData->ActionString, ActionStringSize); + } + + RemainingSize -= AllocInfo->Header.Length; + ProfileBuffer = (UINT8 *)ProfileBuffer + AllocInfo->Header.Length; + } else { + goto Done; + } + } + + Offset += AllocInfoData->AllocInfo.Header.Length; + } + } + + if (*ProfileOffset < (Offset + sizeof (MEMORY_PROFILE_FREE_MEMORY))) { + if (RemainingSize >= sizeof (MEMORY_PROFILE_FREE_MEMORY)) { + FreeMemory = ProfileBuffer; + CopyMem (FreeMemory, &mSmramFreeMemory, sizeof (MEMORY_PROFILE_FREE_MEMORY)); + Index = 0; + FreePageList = &mSmmMemoryMap; + for (Node = FreePageList->BackLink; + Node != FreePageList; + Node = Node->BackLink) + { + Index++; + } + + for (SmmPoolTypeIndex = 0; SmmPoolTypeIndex < SmmPoolTypeMax; SmmPoolTypeIndex++) { + for (PoolListIndex = 0; PoolListIndex < MAX_POOL_INDEX; PoolListIndex++) { + FreePoolList = &mSmmPoolLists[SmmPoolTypeIndex][MAX_POOL_INDEX - PoolListIndex - 1]; + for (Node = FreePoolList->BackLink; + Node != FreePoolList; + Node = Node->BackLink) + { + Pool = BASE_CR (Node, FREE_POOL_HEADER, Link); + if (Pool->Header.Available) { + Index++; + } + } + } + } + + FreeMemory->FreeMemoryEntryCount = Index; + + RemainingSize -= sizeof (MEMORY_PROFILE_FREE_MEMORY); + ProfileBuffer = (UINT8 *)ProfileBuffer + sizeof (MEMORY_PROFILE_FREE_MEMORY); + } else { + goto Done; + } + } + + Offset += sizeof (MEMORY_PROFILE_FREE_MEMORY); + FreePageList = &mSmmMemoryMap; + for (Node = FreePageList->BackLink; + Node != FreePageList; + Node = Node->BackLink) + { + if (*ProfileOffset < (Offset + sizeof (MEMORY_PROFILE_DESCRIPTOR))) { + if (RemainingSize >= sizeof (MEMORY_PROFILE_DESCRIPTOR)) { + Pages = BASE_CR (Node, FREE_PAGE_LIST, Link); + MemoryProfileDescriptor = ProfileBuffer; + MemoryProfileDescriptor->Header.Signature = MEMORY_PROFILE_DESCRIPTOR_SIGNATURE; + MemoryProfileDescriptor->Header.Length = sizeof (MEMORY_PROFILE_DESCRIPTOR); + MemoryProfileDescriptor->Header.Revision = MEMORY_PROFILE_DESCRIPTOR_REVISION; + MemoryProfileDescriptor->Address = (PHYSICAL_ADDRESS)(UINTN)Pages; + MemoryProfileDescriptor->Size = EFI_PAGES_TO_SIZE (Pages->NumberOfPages); + + RemainingSize -= sizeof (MEMORY_PROFILE_DESCRIPTOR); + ProfileBuffer = (UINT8 *)ProfileBuffer + sizeof (MEMORY_PROFILE_DESCRIPTOR); + } else { + goto Done; + } + } + + Offset += sizeof (MEMORY_PROFILE_DESCRIPTOR); + } + + for (SmmPoolTypeIndex = 0; SmmPoolTypeIndex < SmmPoolTypeMax; SmmPoolTypeIndex++) { + for (PoolListIndex = 0; PoolListIndex < MAX_POOL_INDEX; PoolListIndex++) { + FreePoolList = &mSmmPoolLists[SmmPoolTypeIndex][MAX_POOL_INDEX - PoolListIndex - 1]; + for (Node = FreePoolList->BackLink; + Node != FreePoolList; + Node = Node->BackLink) + { + Pool = BASE_CR (Node, FREE_POOL_HEADER, Link); + if (Pool->Header.Available) { + if (*ProfileOffset < (Offset + sizeof (MEMORY_PROFILE_DESCRIPTOR))) { + if (RemainingSize >= sizeof (MEMORY_PROFILE_DESCRIPTOR)) { + MemoryProfileDescriptor = ProfileBuffer; + MemoryProfileDescriptor->Header.Signature = MEMORY_PROFILE_DESCRIPTOR_SIGNATURE; + MemoryProfileDescriptor->Header.Length = sizeof (MEMORY_PROFILE_DESCRIPTOR); + MemoryProfileDescriptor->Header.Revision = MEMORY_PROFILE_DESCRIPTOR_REVISION; + MemoryProfileDescriptor->Address = (PHYSICAL_ADDRESS)(UINTN)Pool; + MemoryProfileDescriptor->Size = Pool->Header.Size; + + RemainingSize -= sizeof (MEMORY_PROFILE_DESCRIPTOR); + ProfileBuffer = (UINT8 *)ProfileBuffer + sizeof (MEMORY_PROFILE_DESCRIPTOR); + } else { + goto Done; + } + } + + Offset += sizeof (MEMORY_PROFILE_DESCRIPTOR); + } + } + } + } + + if (*ProfileOffset < (Offset + sizeof (MEMORY_PROFILE_MEMORY_RANGE))) { + if (RemainingSize >= sizeof (MEMORY_PROFILE_MEMORY_RANGE)) { + MemoryRange = ProfileBuffer; + MemoryRange->Header.Signature = MEMORY_PROFILE_MEMORY_RANGE_SIGNATURE; + MemoryRange->Header.Length = sizeof (MEMORY_PROFILE_MEMORY_RANGE); + MemoryRange->Header.Revision = MEMORY_PROFILE_MEMORY_RANGE_REVISION; + MemoryRange->MemoryRangeCount = (UINT32)mFullSmramRangeCount; + + RemainingSize -= sizeof (MEMORY_PROFILE_MEMORY_RANGE); + ProfileBuffer = (UINT8 *)ProfileBuffer + sizeof (MEMORY_PROFILE_MEMORY_RANGE); + } else { + goto Done; + } + } + + Offset += sizeof (MEMORY_PROFILE_MEMORY_RANGE); + for (Index = 0; Index < mFullSmramRangeCount; Index++) { + if (*ProfileOffset < (Offset + sizeof (MEMORY_PROFILE_DESCRIPTOR))) { + if (RemainingSize >= sizeof (MEMORY_PROFILE_DESCRIPTOR)) { + MemoryProfileDescriptor = ProfileBuffer; + MemoryProfileDescriptor->Header.Signature = MEMORY_PROFILE_DESCRIPTOR_SIGNATURE; + MemoryProfileDescriptor->Header.Length = sizeof (MEMORY_PROFILE_DESCRIPTOR); + MemoryProfileDescriptor->Header.Revision = MEMORY_PROFILE_DESCRIPTOR_REVISION; + MemoryProfileDescriptor->Address = mFullSmramRanges[Index].PhysicalStart; + MemoryProfileDescriptor->Size = mFullSmramRanges[Index].PhysicalSize; + + RemainingSize -= sizeof (MEMORY_PROFILE_DESCRIPTOR); + ProfileBuffer = (UINT8 *)ProfileBuffer + sizeof (MEMORY_PROFILE_DESCRIPTOR); + } else { + goto Done; + } + } + + Offset += sizeof (MEMORY_PROFILE_DESCRIPTOR); + } + +Done: + // + // On output, actual profile data size copied. + // + *ProfileSize -= RemainingSize; + // + // On output, next time profile buffer offset to copy. + // + *ProfileOffset = Offset; +} + +/** + Get memory profile data. + + @param[in] This The EDKII_SMM_MEMORY_PROFILE_PROTOCOL instance. + @param[in, out] ProfileSize On entry, points to the size in bytes of the ProfileBuffer. + On return, points to the size of the data returned in ProfileBuffer. + @param[out] ProfileBuffer Profile buffer. + + @return EFI_SUCCESS Get the memory profile data successfully. + @return EFI_UNSUPPORTED Memory profile is unsupported. + @return EFI_BUFFER_TO_SMALL The ProfileSize is too small for the resulting data. + ProfileSize is updated with the size required. + +**/ +EFI_STATUS +EFIAPI +SmramProfileProtocolGetData ( + IN EDKII_SMM_MEMORY_PROFILE_PROTOCOL *This, + IN OUT UINT64 *ProfileSize, + OUT VOID *ProfileBuffer + ) +{ + UINT64 Size; + UINT64 Offset; + MEMORY_PROFILE_CONTEXT_DATA *ContextData; + BOOLEAN SmramProfileGettingStatus; + + ContextData = GetSmramProfileContext (); + if (ContextData == NULL) { + return EFI_UNSUPPORTED; + } + + SmramProfileGettingStatus = mSmramProfileGettingStatus; + mSmramProfileGettingStatus = TRUE; + + Size = SmramProfileGetDataSize (); + + if (*ProfileSize < Size) { + *ProfileSize = Size; + mSmramProfileGettingStatus = SmramProfileGettingStatus; + return EFI_BUFFER_TOO_SMALL; + } + + Offset = 0; + SmramProfileCopyData (ProfileBuffer, &Size, &Offset); + *ProfileSize = Size; + + mSmramProfileGettingStatus = SmramProfileGettingStatus; + return EFI_SUCCESS; +} + +/** + Register image to memory profile. + + @param[in] This The EDKII_SMM_MEMORY_PROFILE_PROTOCOL instance. + @param[in] FilePath File path of the image. + @param[in] ImageBase Image base address. + @param[in] ImageSize Image size. + @param[in] FileType File type of the image. + + @return EFI_SUCCESS Register successfully. + @return EFI_UNSUPPORTED Memory profile is unsupported, + or memory profile for the image is not required. + @return EFI_OUT_OF_RESOURCES No enough resource for this register. + +**/ +EFI_STATUS +EFIAPI +SmramProfileProtocolRegisterImage ( + IN EDKII_SMM_MEMORY_PROFILE_PROTOCOL *This, + IN EFI_DEVICE_PATH_PROTOCOL *FilePath, + IN PHYSICAL_ADDRESS ImageBase, + IN UINT64 ImageSize, + IN EFI_FV_FILETYPE FileType + ) +{ + EFI_STATUS Status; + EFI_SMM_DRIVER_ENTRY DriverEntry; + VOID *EntryPointInImage; + EFI_GUID *Name; + + ZeroMem (&DriverEntry, sizeof (DriverEntry)); + Name = GetFileNameFromFilePath (FilePath); + if (Name != NULL) { + CopyMem (&DriverEntry.FileName, Name, sizeof (EFI_GUID)); + } + + DriverEntry.ImageBuffer = ImageBase; + DriverEntry.NumberOfPage = EFI_SIZE_TO_PAGES ((UINTN)ImageSize); + Status = InternalPeCoffGetEntryPoint ((VOID *)(UINTN)DriverEntry.ImageBuffer, &EntryPointInImage); + ASSERT_EFI_ERROR (Status); + DriverEntry.ImageEntryPoint = (PHYSICAL_ADDRESS)(UINTN)EntryPointInImage; + + return RegisterSmramProfileImage (&DriverEntry, FALSE); +} + +/** + Unregister image from memory profile. + + @param[in] This The EDKII_SMM_MEMORY_PROFILE_PROTOCOL instance. + @param[in] FilePath File path of the image. + @param[in] ImageBase Image base address. + @param[in] ImageSize Image size. + + @return EFI_SUCCESS Unregister successfully. + @return EFI_UNSUPPORTED Memory profile is unsupported, + or memory profile for the image is not required. + @return EFI_NOT_FOUND The image is not found. + +**/ +EFI_STATUS +EFIAPI +SmramProfileProtocolUnregisterImage ( + IN EDKII_SMM_MEMORY_PROFILE_PROTOCOL *This, + IN EFI_DEVICE_PATH_PROTOCOL *FilePath, + IN PHYSICAL_ADDRESS ImageBase, + IN UINT64 ImageSize + ) +{ + EFI_STATUS Status; + EFI_SMM_DRIVER_ENTRY DriverEntry; + VOID *EntryPointInImage; + EFI_GUID *Name; + + ZeroMem (&DriverEntry, sizeof (DriverEntry)); + Name = GetFileNameFromFilePath (FilePath); + if (Name != NULL) { + CopyMem (&DriverEntry.FileName, Name, sizeof (EFI_GUID)); + } + + DriverEntry.ImageBuffer = ImageBase; + DriverEntry.NumberOfPage = EFI_SIZE_TO_PAGES ((UINTN)ImageSize); + Status = InternalPeCoffGetEntryPoint ((VOID *)(UINTN)DriverEntry.ImageBuffer, &EntryPointInImage); + ASSERT_EFI_ERROR (Status); + DriverEntry.ImageEntryPoint = (PHYSICAL_ADDRESS)(UINTN)EntryPointInImage; + + return UnregisterSmramProfileImage (&DriverEntry, FALSE); +} + +/** + Get memory profile recording state. + + @param[in] This The EDKII_SMM_MEMORY_PROFILE_PROTOCOL instance. + @param[out] RecordingState Recording state. + + @return EFI_SUCCESS Memory profile recording state is returned. + @return EFI_UNSUPPORTED Memory profile is unsupported. + @return EFI_INVALID_PARAMETER RecordingState is NULL. + +**/ +EFI_STATUS +EFIAPI +SmramProfileProtocolGetRecordingState ( + IN EDKII_SMM_MEMORY_PROFILE_PROTOCOL *This, + OUT BOOLEAN *RecordingState + ) +{ + MEMORY_PROFILE_CONTEXT_DATA *ContextData; + + ContextData = GetSmramProfileContext (); + if (ContextData == NULL) { + return EFI_UNSUPPORTED; + } + + if (RecordingState == NULL) { + return EFI_INVALID_PARAMETER; + } + + *RecordingState = mSmramProfileRecordingEnable; + return EFI_SUCCESS; +} + +/** + Set memory profile recording state. + + @param[in] This The EDKII_SMM_MEMORY_PROFILE_PROTOCOL instance. + @param[in] RecordingState Recording state. + + @return EFI_SUCCESS Set memory profile recording state successfully. + @return EFI_UNSUPPORTED Memory profile is unsupported. + +**/ +EFI_STATUS +EFIAPI +SmramProfileProtocolSetRecordingState ( + IN EDKII_SMM_MEMORY_PROFILE_PROTOCOL *This, + IN BOOLEAN RecordingState + ) +{ + MEMORY_PROFILE_CONTEXT_DATA *ContextData; + + ContextData = GetSmramProfileContext (); + if (ContextData == NULL) { + return EFI_UNSUPPORTED; + } + + mSmramProfileRecordingEnable = RecordingState; + return EFI_SUCCESS; +} + +/** + Record memory profile of multilevel caller. + + @param[in] This The EDKII_SMM_MEMORY_PROFILE_PROTOCOL instance. + @param[in] CallerAddress Address of caller. + @param[in] Action Memory profile action. + @param[in] MemoryType Memory type. + EfiMaxMemoryType means the MemoryType is unknown. + @param[in] Buffer Buffer address. + @param[in] Size Buffer size. + @param[in] ActionString String for memory profile action. + Only needed for user defined allocate action. + + @return EFI_SUCCESS Memory profile is updated. + @return EFI_UNSUPPORTED Memory profile is unsupported, + or memory profile for the image is not required, + or memory profile for the memory type is not required. + @return EFI_ACCESS_DENIED It is during memory profile data getting. + @return EFI_ABORTED Memory profile recording is not enabled. + @return EFI_OUT_OF_RESOURCES No enough resource to update memory profile for allocate action. + @return EFI_NOT_FOUND No matched allocate info found for free action. + +**/ +EFI_STATUS +EFIAPI +SmramProfileProtocolRecord ( + IN EDKII_SMM_MEMORY_PROFILE_PROTOCOL *This, + IN PHYSICAL_ADDRESS CallerAddress, + IN MEMORY_PROFILE_ACTION Action, + IN EFI_MEMORY_TYPE MemoryType, + IN VOID *Buffer, + IN UINTN Size, + IN CHAR8 *ActionString OPTIONAL + ) +{ + return SmmCoreUpdateProfile (CallerAddress, Action, MemoryType, Size, Buffer, ActionString); +} + +/** + SMRAM profile handler to get profile info. + + @param SmramProfileParameterGetInfo The parameter of SMM profile get size. + +**/ +VOID +SmramProfileHandlerGetInfo ( + IN SMRAM_PROFILE_PARAMETER_GET_PROFILE_INFO *SmramProfileParameterGetInfo + ) +{ + MEMORY_PROFILE_CONTEXT_DATA *ContextData; + BOOLEAN SmramProfileGettingStatus; + + ContextData = GetSmramProfileContext (); + if (ContextData == NULL) { + return; + } + + SmramProfileGettingStatus = mSmramProfileGettingStatus; + mSmramProfileGettingStatus = TRUE; + + SmramProfileParameterGetInfo->ProfileSize = SmramProfileGetDataSize (); + SmramProfileParameterGetInfo->Header.ReturnStatus = 0; + + mSmramProfileGettingStatus = SmramProfileGettingStatus; +} + +/** + SMRAM profile handler to get profile data. + + @param SmramProfileParameterGetData The parameter of SMM profile get data. + +**/ +VOID +SmramProfileHandlerGetData ( + IN SMRAM_PROFILE_PARAMETER_GET_PROFILE_DATA *SmramProfileParameterGetData + ) +{ + UINT64 ProfileSize; + UINT64 ProfileOffset; + SMRAM_PROFILE_PARAMETER_GET_PROFILE_DATA SmramProfileGetData; + MEMORY_PROFILE_CONTEXT_DATA *ContextData; + BOOLEAN SmramProfileGettingStatus; + + ContextData = GetSmramProfileContext (); + if (ContextData == NULL) { + return; + } + + SmramProfileGettingStatus = mSmramProfileGettingStatus; + mSmramProfileGettingStatus = TRUE; + + CopyMem (&SmramProfileGetData, SmramProfileParameterGetData, sizeof (SmramProfileGetData)); + + ProfileSize = SmramProfileGetDataSize (); + + // + // Sanity check + // + if (!SmmIsBufferOutsideSmmValid ((UINTN)SmramProfileGetData.ProfileBuffer, (UINTN)ProfileSize)) { + DEBUG ((DEBUG_ERROR, "SmramProfileHandlerGetData: SMM ProfileBuffer in SMRAM or overflow!\n")); + SmramProfileParameterGetData->ProfileSize = ProfileSize; + SmramProfileParameterGetData->Header.ReturnStatus = (UINT64)(INT64)(INTN)EFI_ACCESS_DENIED; + goto Done; + } + + if (SmramProfileGetData.ProfileSize < ProfileSize) { + SmramProfileParameterGetData->ProfileSize = ProfileSize; + SmramProfileParameterGetData->Header.ReturnStatus = (UINT64)(INT64)(INTN)EFI_BUFFER_TOO_SMALL; + goto Done; + } + + ProfileOffset = 0; + SmramProfileCopyData ((VOID *)(UINTN)SmramProfileGetData.ProfileBuffer, &ProfileSize, &ProfileOffset); + SmramProfileParameterGetData->ProfileSize = ProfileSize; + SmramProfileParameterGetData->Header.ReturnStatus = 0; + +Done: + mSmramProfileGettingStatus = SmramProfileGettingStatus; +} + +/** + SMRAM profile handler to get profile data by offset. + + @param SmramProfileParameterGetDataByOffset The parameter of SMM profile get data by offset. + +**/ +VOID +SmramProfileHandlerGetDataByOffset ( + IN SMRAM_PROFILE_PARAMETER_GET_PROFILE_DATA_BY_OFFSET *SmramProfileParameterGetDataByOffset + ) +{ + SMRAM_PROFILE_PARAMETER_GET_PROFILE_DATA_BY_OFFSET SmramProfileGetDataByOffset; + MEMORY_PROFILE_CONTEXT_DATA *ContextData; + BOOLEAN SmramProfileGettingStatus; + + ContextData = GetSmramProfileContext (); + if (ContextData == NULL) { + return; + } + + SmramProfileGettingStatus = mSmramProfileGettingStatus; + mSmramProfileGettingStatus = TRUE; + + CopyMem (&SmramProfileGetDataByOffset, SmramProfileParameterGetDataByOffset, sizeof (SmramProfileGetDataByOffset)); + + // + // Sanity check + // + if (!SmmIsBufferOutsideSmmValid ((UINTN)SmramProfileGetDataByOffset.ProfileBuffer, (UINTN)SmramProfileGetDataByOffset.ProfileSize)) { + DEBUG ((DEBUG_ERROR, "SmramProfileHandlerGetDataByOffset: SMM ProfileBuffer in SMRAM or overflow!\n")); + SmramProfileParameterGetDataByOffset->Header.ReturnStatus = (UINT64)(INT64)(INTN)EFI_ACCESS_DENIED; + goto Done; + } + + SmramProfileCopyData ((VOID *)(UINTN)SmramProfileGetDataByOffset.ProfileBuffer, &SmramProfileGetDataByOffset.ProfileSize, &SmramProfileGetDataByOffset.ProfileOffset); + CopyMem (SmramProfileParameterGetDataByOffset, &SmramProfileGetDataByOffset, sizeof (SmramProfileGetDataByOffset)); + SmramProfileParameterGetDataByOffset->Header.ReturnStatus = 0; + +Done: + mSmramProfileGettingStatus = SmramProfileGettingStatus; +} + +/** + Dispatch function for a Software SMI handler. + + Caution: This function may receive untrusted input. + Communicate buffer and buffer size are external input, so this function will do basic validation. + + @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-SMM environment into an SMM environment. + @param CommBufferSize The size of the CommBuffer. + + @retval EFI_SUCCESS Command is handled successfully. + +**/ +EFI_STATUS +EFIAPI +SmramProfileHandler ( + IN EFI_HANDLE DispatchHandle, + IN CONST VOID *Context OPTIONAL, + IN OUT VOID *CommBuffer OPTIONAL, + IN OUT UINTN *CommBufferSize OPTIONAL + ) +{ + SMRAM_PROFILE_PARAMETER_HEADER *SmramProfileParameterHeader; + UINTN TempCommBufferSize; + SMRAM_PROFILE_PARAMETER_RECORDING_STATE *ParameterRecordingState; + + DEBUG ((DEBUG_ERROR, "SmramProfileHandler Enter\n")); + + // + // If input is invalid, stop processing this SMI + // + if ((CommBuffer == NULL) || (CommBufferSize == NULL)) { + return EFI_SUCCESS; + } + + TempCommBufferSize = *CommBufferSize; + + if (TempCommBufferSize < sizeof (SMRAM_PROFILE_PARAMETER_HEADER)) { + DEBUG ((DEBUG_ERROR, "SmramProfileHandler: SMM communication buffer size invalid!\n")); + return EFI_SUCCESS; + } + + if (mSmramReadyToLock && !SmmIsBufferOutsideSmmValid ((UINTN)CommBuffer, TempCommBufferSize)) { + DEBUG ((DEBUG_ERROR, "SmramProfileHandler: SMM communication buffer in SMRAM or overflow!\n")); + return EFI_SUCCESS; + } + + SmramProfileParameterHeader = (SMRAM_PROFILE_PARAMETER_HEADER *)((UINTN)CommBuffer); + + SmramProfileParameterHeader->ReturnStatus = (UINT64)-1; + + if (GetSmramProfileContext () == NULL) { + SmramProfileParameterHeader->ReturnStatus = (UINT64)(INT64)(INTN)EFI_UNSUPPORTED; + return EFI_SUCCESS; + } + + switch (SmramProfileParameterHeader->Command) { + case SMRAM_PROFILE_COMMAND_GET_PROFILE_INFO: + DEBUG ((DEBUG_ERROR, "SmramProfileHandlerGetInfo\n")); + if (TempCommBufferSize != sizeof (SMRAM_PROFILE_PARAMETER_GET_PROFILE_INFO)) { + DEBUG ((DEBUG_ERROR, "SmramProfileHandler: SMM communication buffer size invalid!\n")); + return EFI_SUCCESS; + } + + SmramProfileHandlerGetInfo ((SMRAM_PROFILE_PARAMETER_GET_PROFILE_INFO *)(UINTN)CommBuffer); + break; + case SMRAM_PROFILE_COMMAND_GET_PROFILE_DATA: + DEBUG ((DEBUG_ERROR, "SmramProfileHandlerGetData\n")); + if (TempCommBufferSize != sizeof (SMRAM_PROFILE_PARAMETER_GET_PROFILE_DATA)) { + DEBUG ((DEBUG_ERROR, "SmramProfileHandler: SMM communication buffer size invalid!\n")); + return EFI_SUCCESS; + } + + SmramProfileHandlerGetData ((SMRAM_PROFILE_PARAMETER_GET_PROFILE_DATA *)(UINTN)CommBuffer); + break; + case SMRAM_PROFILE_COMMAND_GET_PROFILE_DATA_BY_OFFSET: + DEBUG ((DEBUG_ERROR, "SmramProfileHandlerGetDataByOffset\n")); + if (TempCommBufferSize != sizeof (SMRAM_PROFILE_PARAMETER_GET_PROFILE_DATA_BY_OFFSET)) { + DEBUG ((DEBUG_ERROR, "SmramProfileHandler: SMM communication buffer size invalid!\n")); + return EFI_SUCCESS; + } + + SmramProfileHandlerGetDataByOffset ((SMRAM_PROFILE_PARAMETER_GET_PROFILE_DATA_BY_OFFSET *)(UINTN)CommBuffer); + break; + case SMRAM_PROFILE_COMMAND_GET_RECORDING_STATE: + DEBUG ((DEBUG_ERROR, "SmramProfileHandlerGetRecordingState\n")); + if (TempCommBufferSize != sizeof (SMRAM_PROFILE_PARAMETER_RECORDING_STATE)) { + DEBUG ((DEBUG_ERROR, "SmramProfileHandler: SMM communication buffer size invalid!\n")); + return EFI_SUCCESS; + } + + ParameterRecordingState = (SMRAM_PROFILE_PARAMETER_RECORDING_STATE *)(UINTN)CommBuffer; + ParameterRecordingState->RecordingState = mSmramProfileRecordingEnable; + ParameterRecordingState->Header.ReturnStatus = 0; + break; + case SMRAM_PROFILE_COMMAND_SET_RECORDING_STATE: + DEBUG ((DEBUG_ERROR, "SmramProfileHandlerSetRecordingState\n")); + if (TempCommBufferSize != sizeof (SMRAM_PROFILE_PARAMETER_RECORDING_STATE)) { + DEBUG ((DEBUG_ERROR, "SmramProfileHandler: SMM communication buffer size invalid!\n")); + return EFI_SUCCESS; + } + + ParameterRecordingState = (SMRAM_PROFILE_PARAMETER_RECORDING_STATE *)(UINTN)CommBuffer; + mSmramProfileRecordingEnable = ParameterRecordingState->RecordingState; + ParameterRecordingState->Header.ReturnStatus = 0; + break; + + // + // Below 2 commands have been deprecated. They may not be (re-)used. + // + case SMRAM_PROFILE_COMMAND_DEPRECATED1: + case SMRAM_PROFILE_COMMAND_DEPRECATED2: + ASSERT (FALSE); + // + // Fall-through to the default (unrecognized command) case. + // + default: + break; + } + + DEBUG ((DEBUG_ERROR, "SmramProfileHandler Exit\n")); + + return EFI_SUCCESS; +} + +/** + Register SMRAM profile handler. + +**/ +VOID +RegisterSmramProfileHandler ( + VOID + ) +{ + EFI_STATUS Status; + EFI_HANDLE DispatchHandle; + + if (!IS_SMRAM_PROFILE_ENABLED) { + return; + } + + Status = SmiHandlerRegister ( + SmramProfileHandler, + &gEdkiiMemoryProfileGuid, + &DispatchHandle + ); + ASSERT_EFI_ERROR (Status); +} + +//////////////////// + +/** + Dump SMRAM range. + +**/ +VOID +DumpSmramRange ( + VOID + ) +{ + UINTN Index; + MEMORY_PROFILE_CONTEXT_DATA *ContextData; + BOOLEAN SmramProfileGettingStatus; + + ContextData = GetSmramProfileContext (); + if (ContextData == NULL) { + return; + } + + SmramProfileGettingStatus = mSmramProfileGettingStatus; + mSmramProfileGettingStatus = TRUE; + + DEBUG ((DEBUG_INFO, "FullSmramRange address - 0x%08x\n", mFullSmramRanges)); + + DEBUG ((DEBUG_INFO, "======= SmramProfile begin =======\n")); + + DEBUG ((DEBUG_INFO, "FullSmramRange:\n")); + for (Index = 0; Index < mFullSmramRangeCount; Index++) { + DEBUG ((DEBUG_INFO, " FullSmramRange (0x%x)\n", Index)); + DEBUG ((DEBUG_INFO, " PhysicalStart - 0x%016lx\n", mFullSmramRanges[Index].PhysicalStart)); + DEBUG ((DEBUG_INFO, " CpuStart - 0x%016lx\n", mFullSmramRanges[Index].CpuStart)); + DEBUG ((DEBUG_INFO, " PhysicalSize - 0x%016lx\n", mFullSmramRanges[Index].PhysicalSize)); + DEBUG ((DEBUG_INFO, " RegionState - 0x%016lx\n", mFullSmramRanges[Index].RegionState)); + } + + DEBUG ((DEBUG_INFO, "======= SmramProfile end =======\n")); + + mSmramProfileGettingStatus = SmramProfileGettingStatus; +} + +/** + Dump SMRAM free page list. + +**/ +VOID +DumpFreePagesList ( + VOID + ) +{ + LIST_ENTRY *FreePageList; + LIST_ENTRY *Node; + FREE_PAGE_LIST *Pages; + UINTN Index; + MEMORY_PROFILE_CONTEXT_DATA *ContextData; + BOOLEAN SmramProfileGettingStatus; + + ContextData = GetSmramProfileContext (); + if (ContextData == NULL) { + return; + } + + SmramProfileGettingStatus = mSmramProfileGettingStatus; + mSmramProfileGettingStatus = TRUE; + + DEBUG ((DEBUG_INFO, "======= SmramProfile begin =======\n")); + + DEBUG ((DEBUG_INFO, "FreePagesList:\n")); + FreePageList = &mSmmMemoryMap; + for (Node = FreePageList->BackLink, Index = 0; + Node != FreePageList; + Node = Node->BackLink, Index++) + { + Pages = BASE_CR (Node, FREE_PAGE_LIST, Link); + DEBUG ((DEBUG_INFO, " Index - 0x%x\n", Index)); + DEBUG ((DEBUG_INFO, " PhysicalStart - 0x%016lx\n", (PHYSICAL_ADDRESS)(UINTN)Pages)); + DEBUG ((DEBUG_INFO, " NumberOfPages - 0x%08x\n", Pages->NumberOfPages)); + } + + DEBUG ((DEBUG_INFO, "======= SmramProfile end =======\n")); + + mSmramProfileGettingStatus = SmramProfileGettingStatus; +} + +/** + Dump SMRAM free pool list. + +**/ +VOID +DumpFreePoolList ( + VOID + ) +{ + LIST_ENTRY *FreePoolList; + LIST_ENTRY *Node; + FREE_POOL_HEADER *Pool; + UINTN Index; + UINTN PoolListIndex; + MEMORY_PROFILE_CONTEXT_DATA *ContextData; + BOOLEAN SmramProfileGettingStatus; + UINTN SmmPoolTypeIndex; + + ContextData = GetSmramProfileContext (); + if (ContextData == NULL) { + return; + } + + SmramProfileGettingStatus = mSmramProfileGettingStatus; + mSmramProfileGettingStatus = TRUE; + + DEBUG ((DEBUG_INFO, "======= SmramProfile begin =======\n")); + + for (SmmPoolTypeIndex = 0; SmmPoolTypeIndex < SmmPoolTypeMax; SmmPoolTypeIndex++) { + for (PoolListIndex = 0; PoolListIndex < MAX_POOL_INDEX; PoolListIndex++) { + DEBUG ((DEBUG_INFO, "FreePoolList(%d)(%d):\n", SmmPoolTypeIndex, PoolListIndex)); + FreePoolList = &mSmmPoolLists[SmmPoolTypeIndex][PoolListIndex]; + for (Node = FreePoolList->BackLink, Index = 0; + Node != FreePoolList; + Node = Node->BackLink, Index++) + { + Pool = BASE_CR (Node, FREE_POOL_HEADER, Link); + DEBUG ((DEBUG_INFO, " Index - 0x%x\n", Index)); + DEBUG ((DEBUG_INFO, " PhysicalStart - 0x%016lx\n", (PHYSICAL_ADDRESS)(UINTN)Pool)); + DEBUG ((DEBUG_INFO, " Size - 0x%08x\n", Pool->Header.Size)); + DEBUG ((DEBUG_INFO, " Available - 0x%02x\n", Pool->Header.Available)); + } + } + } + + DEBUG ((DEBUG_INFO, "======= SmramProfile end =======\n")); + + mSmramProfileGettingStatus = SmramProfileGettingStatus; +} + +GLOBAL_REMOVE_IF_UNREFERENCED CHAR8 *mSmmActionString[] = { + "SmmUnknown", + "gSmst->SmmAllocatePages", + "gSmst->SmmFreePages", + "gSmst->SmmAllocatePool", + "gSmst->SmmFreePool", +}; + +typedef struct { + MEMORY_PROFILE_ACTION Action; + CHAR8 *String; +} ACTION_STRING; + +GLOBAL_REMOVE_IF_UNREFERENCED ACTION_STRING mExtActionString[] = { + { MEMORY_PROFILE_ACTION_LIB_ALLOCATE_PAGES, "Lib:AllocatePages" }, + { MEMORY_PROFILE_ACTION_LIB_ALLOCATE_RUNTIME_PAGES, "Lib:AllocateRuntimePages" }, + { MEMORY_PROFILE_ACTION_LIB_ALLOCATE_RESERVED_PAGES, "Lib:AllocateReservedPages" }, + { MEMORY_PROFILE_ACTION_LIB_FREE_PAGES, "Lib:FreePages" }, + { MEMORY_PROFILE_ACTION_LIB_ALLOCATE_ALIGNED_PAGES, "Lib:AllocateAlignedPages" }, + { MEMORY_PROFILE_ACTION_LIB_ALLOCATE_ALIGNED_RUNTIME_PAGES, "Lib:AllocateAlignedRuntimePages" }, + { MEMORY_PROFILE_ACTION_LIB_ALLOCATE_ALIGNED_RESERVED_PAGES, "Lib:AllocateAlignedReservedPages" }, + { MEMORY_PROFILE_ACTION_LIB_FREE_ALIGNED_PAGES, "Lib:FreeAlignedPages" }, + { MEMORY_PROFILE_ACTION_LIB_ALLOCATE_POOL, "Lib:AllocatePool" }, + { MEMORY_PROFILE_ACTION_LIB_ALLOCATE_RUNTIME_POOL, "Lib:AllocateRuntimePool" }, + { MEMORY_PROFILE_ACTION_LIB_ALLOCATE_RESERVED_POOL, "Lib:AllocateReservedPool" }, + { MEMORY_PROFILE_ACTION_LIB_FREE_POOL, "Lib:FreePool" }, + { MEMORY_PROFILE_ACTION_LIB_ALLOCATE_ZERO_POOL, "Lib:AllocateZeroPool" }, + { MEMORY_PROFILE_ACTION_LIB_ALLOCATE_RUNTIME_ZERO_POOL, "Lib:AllocateRuntimeZeroPool" }, + { MEMORY_PROFILE_ACTION_LIB_ALLOCATE_RESERVED_ZERO_POOL, "Lib:AllocateReservedZeroPool" }, + { MEMORY_PROFILE_ACTION_LIB_ALLOCATE_COPY_POOL, "Lib:AllocateCopyPool" }, + { MEMORY_PROFILE_ACTION_LIB_ALLOCATE_RUNTIME_COPY_POOL, "Lib:AllocateRuntimeCopyPool" }, + { MEMORY_PROFILE_ACTION_LIB_ALLOCATE_RESERVED_COPY_POOL, "Lib:AllocateReservedCopyPool" }, + { MEMORY_PROFILE_ACTION_LIB_REALLOCATE_POOL, "Lib:ReallocatePool" }, + { MEMORY_PROFILE_ACTION_LIB_REALLOCATE_RUNTIME_POOL, "Lib:ReallocateRuntimePool" }, + { MEMORY_PROFILE_ACTION_LIB_REALLOCATE_RESERVED_POOL, "Lib:ReallocateReservedPool" }, +}; + +typedef struct { + EFI_MEMORY_TYPE MemoryType; + CHAR8 *MemoryTypeStr; +} PROFILE_MEMORY_TYPE_STRING; + +GLOBAL_REMOVE_IF_UNREFERENCED PROFILE_MEMORY_TYPE_STRING mMemoryTypeString[] = { + { EfiRuntimeServicesCode, "EfiRuntimeServicesCode" }, + { EfiRuntimeServicesData, "EfiRuntimeServicesData" } +}; + +/** + Memory type to string. + + @param[in] MemoryType Memory type. + + @return Pointer to string. + +**/ +CHAR8 * +ProfileMemoryTypeToStr ( + IN EFI_MEMORY_TYPE MemoryType + ) +{ + UINTN Index; + + for (Index = 0; Index < ARRAY_SIZE (mMemoryTypeString); Index++) { + if (mMemoryTypeString[Index].MemoryType == MemoryType) { + return mMemoryTypeString[Index].MemoryTypeStr; + } + } + + return "UnexpectedMemoryType"; +} + +/** + Action to string. + + @param[in] Action Profile action. + + @return Pointer to string. + +**/ +CHAR8 * +ProfileActionToStr ( + IN MEMORY_PROFILE_ACTION Action + ) +{ + UINTN Index; + UINTN ActionStringCount; + CHAR8 **ActionString; + + ActionString = mSmmActionString; + ActionStringCount = ARRAY_SIZE (mSmmActionString); + + if ((UINTN)(UINT32)Action < ActionStringCount) { + return ActionString[Action]; + } + + for (Index = 0; Index < ARRAY_SIZE (mExtActionString); Index++) { + if (mExtActionString[Index].Action == Action) { + return mExtActionString[Index].String; + } + } + + return ActionString[0]; +} + +/** + Dump SMRAM profile. + +**/ +VOID +DumpSmramProfile ( + VOID + ) +{ + MEMORY_PROFILE_CONTEXT *Context; + MEMORY_PROFILE_DRIVER_INFO *DriverInfo; + MEMORY_PROFILE_ALLOC_INFO *AllocInfo; + MEMORY_PROFILE_CONTEXT_DATA *ContextData; + MEMORY_PROFILE_DRIVER_INFO_DATA *DriverInfoData; + MEMORY_PROFILE_ALLOC_INFO_DATA *AllocInfoData; + LIST_ENTRY *SmramDriverInfoList; + UINTN DriverIndex; + LIST_ENTRY *DriverLink; + LIST_ENTRY *AllocInfoList; + UINTN AllocIndex; + LIST_ENTRY *AllocLink; + BOOLEAN SmramProfileGettingStatus; + UINTN TypeIndex; + + ContextData = GetSmramProfileContext (); + if (ContextData == NULL) { + return; + } + + SmramProfileGettingStatus = mSmramProfileGettingStatus; + mSmramProfileGettingStatus = TRUE; + + Context = &ContextData->Context; + DEBUG ((DEBUG_INFO, "======= SmramProfile begin =======\n")); + DEBUG ((DEBUG_INFO, "MEMORY_PROFILE_CONTEXT\n")); + + DEBUG ((DEBUG_INFO, " CurrentTotalUsage - 0x%016lx\n", Context->CurrentTotalUsage)); + DEBUG ((DEBUG_INFO, " PeakTotalUsage - 0x%016lx\n", Context->PeakTotalUsage)); + for (TypeIndex = 0; TypeIndex < sizeof (Context->CurrentTotalUsageByType) / sizeof (Context->CurrentTotalUsageByType[0]); TypeIndex++) { + if ((Context->CurrentTotalUsageByType[TypeIndex] != 0) || + (Context->PeakTotalUsageByType[TypeIndex] != 0)) + { + DEBUG ((DEBUG_INFO, " CurrentTotalUsage[0x%02x] - 0x%016lx (%a)\n", TypeIndex, Context->CurrentTotalUsageByType[TypeIndex], ProfileMemoryTypeToStr (TypeIndex))); + DEBUG ((DEBUG_INFO, " PeakTotalUsage[0x%02x] - 0x%016lx (%a)\n", TypeIndex, Context->PeakTotalUsageByType[TypeIndex], ProfileMemoryTypeToStr (TypeIndex))); + } + } + + DEBUG ((DEBUG_INFO, " TotalImageSize - 0x%016lx\n", Context->TotalImageSize)); + DEBUG ((DEBUG_INFO, " ImageCount - 0x%08x\n", Context->ImageCount)); + DEBUG ((DEBUG_INFO, " SequenceCount - 0x%08x\n", Context->SequenceCount)); + + SmramDriverInfoList = ContextData->DriverInfoList; + for (DriverLink = SmramDriverInfoList->ForwardLink, DriverIndex = 0; + DriverLink != SmramDriverInfoList; + DriverLink = DriverLink->ForwardLink, DriverIndex++) + { + DriverInfoData = CR ( + DriverLink, + MEMORY_PROFILE_DRIVER_INFO_DATA, + Link, + MEMORY_PROFILE_DRIVER_INFO_SIGNATURE + ); + DriverInfo = &DriverInfoData->DriverInfo; + DEBUG ((DEBUG_INFO, " MEMORY_PROFILE_DRIVER_INFO (0x%x)\n", DriverIndex)); + DEBUG ((DEBUG_INFO, " FileName - %g\n", &DriverInfo->FileName)); + DEBUG ((DEBUG_INFO, " ImageBase - 0x%016lx\n", DriverInfo->ImageBase)); + DEBUG ((DEBUG_INFO, " ImageSize - 0x%016lx\n", DriverInfo->ImageSize)); + DEBUG ((DEBUG_INFO, " EntryPoint - 0x%016lx\n", DriverInfo->EntryPoint)); + DEBUG ((DEBUG_INFO, " ImageSubsystem - 0x%04x\n", DriverInfo->ImageSubsystem)); + DEBUG ((DEBUG_INFO, " FileType - 0x%02x\n", DriverInfo->FileType)); + DEBUG ((DEBUG_INFO, " CurrentUsage - 0x%016lx\n", DriverInfo->CurrentUsage)); + DEBUG ((DEBUG_INFO, " PeakUsage - 0x%016lx\n", DriverInfo->PeakUsage)); + for (TypeIndex = 0; TypeIndex < sizeof (DriverInfo->CurrentUsageByType) / sizeof (DriverInfo->CurrentUsageByType[0]); TypeIndex++) { + if ((DriverInfo->CurrentUsageByType[TypeIndex] != 0) || + (DriverInfo->PeakUsageByType[TypeIndex] != 0)) + { + DEBUG ((DEBUG_INFO, " CurrentUsage[0x%02x] - 0x%016lx (%a)\n", TypeIndex, DriverInfo->CurrentUsageByType[TypeIndex], ProfileMemoryTypeToStr (TypeIndex))); + DEBUG ((DEBUG_INFO, " PeakUsage[0x%02x] - 0x%016lx (%a)\n", TypeIndex, DriverInfo->PeakUsageByType[TypeIndex], ProfileMemoryTypeToStr (TypeIndex))); + } + } + + DEBUG ((DEBUG_INFO, " AllocRecordCount - 0x%08x\n", DriverInfo->AllocRecordCount)); + + AllocInfoList = DriverInfoData->AllocInfoList; + for (AllocLink = AllocInfoList->ForwardLink, AllocIndex = 0; + AllocLink != AllocInfoList; + AllocLink = AllocLink->ForwardLink, AllocIndex++) + { + AllocInfoData = CR ( + AllocLink, + MEMORY_PROFILE_ALLOC_INFO_DATA, + Link, + MEMORY_PROFILE_ALLOC_INFO_SIGNATURE + ); + AllocInfo = &AllocInfoData->AllocInfo; + DEBUG ((DEBUG_INFO, " MEMORY_PROFILE_ALLOC_INFO (0x%x)\n", AllocIndex)); + DEBUG ((DEBUG_INFO, " CallerAddress - 0x%016lx (Offset: 0x%08x)\n", AllocInfo->CallerAddress, AllocInfo->CallerAddress - DriverInfo->ImageBase)); + DEBUG ((DEBUG_INFO, " SequenceId - 0x%08x\n", AllocInfo->SequenceId)); + if ((AllocInfo->Action & MEMORY_PROFILE_ACTION_USER_DEFINED_MASK) != 0) { + if (AllocInfoData->ActionString != NULL) { + DEBUG ((DEBUG_INFO, " Action - 0x%08x (%a)\n", AllocInfo->Action, AllocInfoData->ActionString)); + } else { + DEBUG ((DEBUG_INFO, " Action - 0x%08x (UserDefined-0x%08x)\n", AllocInfo->Action, AllocInfo->Action)); + } + } else { + DEBUG ((DEBUG_INFO, " Action - 0x%08x (%a)\n", AllocInfo->Action, ProfileActionToStr (AllocInfo->Action))); + } + + DEBUG ((DEBUG_INFO, " MemoryType - 0x%08x (%a)\n", AllocInfo->MemoryType, ProfileMemoryTypeToStr (AllocInfo->MemoryType))); + DEBUG ((DEBUG_INFO, " Buffer - 0x%016lx\n", AllocInfo->Buffer)); + DEBUG ((DEBUG_INFO, " Size - 0x%016lx\n", AllocInfo->Size)); + } + } + + DEBUG ((DEBUG_INFO, "======= SmramProfile end =======\n")); + + mSmramProfileGettingStatus = SmramProfileGettingStatus; +} + +/** + Dump SMRAM information. + +**/ +VOID +DumpSmramInfo ( + VOID + ) +{ + DEBUG_CODE_BEGIN (); + if (IS_SMRAM_PROFILE_ENABLED) { + DumpSmramProfile (); + DumpFreePagesList (); + DumpFreePoolList (); + DumpSmramRange (); + } + + DEBUG_CODE_END (); +} |
