summaryrefslogtreecommitdiff
path: root/MdeModulePkg/Core/PiSmmCore
diff options
context:
space:
mode:
authorkx <kx@radix.pro>2024-06-04 06:43:08 +0300
committerkx <kx@radix.pro>2024-06-04 06:43:08 +0300
commit7e2ccccace24636f29ddc210b94606abd4c7e42b (patch)
tree545d43ea12671048956cafeb12303e84d601e571 /MdeModulePkg/Core/PiSmmCore
parent27b044605cd5f6b33a3d231576003850b3fe305b (diff)
downloadedk2-trunk.tar.xz
Renormalized end-of-lines from master@27b044605cd5f6b33a3d231576003850b3fe305btrunk
Diffstat (limited to 'MdeModulePkg/Core/PiSmmCore')
-rw-r--r--MdeModulePkg/Core/PiSmmCore/Dependency.c776
-rw-r--r--MdeModulePkg/Core/PiSmmCore/Dispatcher.c3078
-rw-r--r--MdeModulePkg/Core/PiSmmCore/Handle.c1076
-rw-r--r--MdeModulePkg/Core/PiSmmCore/HeapGuard.c2860
-rw-r--r--MdeModulePkg/Core/PiSmmCore/HeapGuard.h784
-rw-r--r--MdeModulePkg/Core/PiSmmCore/InstallConfigurationTable.c340
-rw-r--r--MdeModulePkg/Core/PiSmmCore/Locate.c994
-rw-r--r--MdeModulePkg/Core/PiSmmCore/MemoryAttributesTable.c1066
-rw-r--r--MdeModulePkg/Core/PiSmmCore/Notify.c396
-rw-r--r--MdeModulePkg/Core/PiSmmCore/Page.c2198
-rw-r--r--MdeModulePkg/Core/PiSmmCore/PiSmmCore.c1924
-rw-r--r--MdeModulePkg/Core/PiSmmCore/PiSmmCore.h2710
-rw-r--r--MdeModulePkg/Core/PiSmmCore/PiSmmCore.inf250
-rw-r--r--MdeModulePkg/Core/PiSmmCore/PiSmmCore.uni32
-rw-r--r--MdeModulePkg/Core/PiSmmCore/PiSmmCoreExtra.uni28
-rw-r--r--MdeModulePkg/Core/PiSmmCore/PiSmmCorePrivateData.h238
-rw-r--r--MdeModulePkg/Core/PiSmmCore/PiSmmIpl.c3822
-rw-r--r--MdeModulePkg/Core/PiSmmCore/PiSmmIpl.inf184
-rw-r--r--MdeModulePkg/Core/PiSmmCore/PiSmmIpl.uni32
-rw-r--r--MdeModulePkg/Core/PiSmmCore/PiSmmIplExtra.uni28
-rw-r--r--MdeModulePkg/Core/PiSmmCore/Pool.c928
-rw-r--r--MdeModulePkg/Core/PiSmmCore/Smi.c920
-rw-r--r--MdeModulePkg/Core/PiSmmCore/SmiHandlerProfile.c2838
-rw-r--r--MdeModulePkg/Core/PiSmmCore/SmramProfileRecord.c5620
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 ();
+}