summaryrefslogtreecommitdiff
path: root/MdeModulePkg/Core/Dxe
diff options
context:
space:
mode:
Diffstat (limited to 'MdeModulePkg/Core/Dxe')
-rw-r--r--MdeModulePkg/Core/Dxe/Dispatcher/Dependency.c866
-rw-r--r--MdeModulePkg/Core/Dxe/Dispatcher/Dispatcher.c2968
-rw-r--r--MdeModulePkg/Core/Dxe/DxeCore.uni32
-rw-r--r--MdeModulePkg/Core/Dxe/DxeCoreExtra.uni28
-rw-r--r--MdeModulePkg/Core/Dxe/DxeMain.h5586
-rw-r--r--MdeModulePkg/Core/Dxe/DxeMain.inf410
-rw-r--r--MdeModulePkg/Core/Dxe/DxeMain/DxeMain.c1942
-rw-r--r--MdeModulePkg/Core/Dxe/DxeMain/DxeProtocolNotify.c558
-rw-r--r--MdeModulePkg/Core/Dxe/Event/Event.c1520
-rw-r--r--MdeModulePkg/Core/Dxe/Event/Event.h176
-rw-r--r--MdeModulePkg/Core/Dxe/Event/Timer.c582
-rw-r--r--MdeModulePkg/Core/Dxe/Event/Tpl.c298
-rw-r--r--MdeModulePkg/Core/Dxe/FwVol/Ffs.c432
-rw-r--r--MdeModulePkg/Core/Dxe/FwVol/FwVol.c1450
-rw-r--r--MdeModulePkg/Core/Dxe/FwVol/FwVolAttrib.c240
-rw-r--r--MdeModulePkg/Core/Dxe/FwVol/FwVolDriver.h774
-rw-r--r--MdeModulePkg/Core/Dxe/FwVol/FwVolRead.c1064
-rw-r--r--MdeModulePkg/Core/Dxe/FwVol/FwVolWrite.c86
-rw-r--r--MdeModulePkg/Core/Dxe/FwVolBlock/FwVolBlock.c1426
-rw-r--r--MdeModulePkg/Core/Dxe/FwVolBlock/FwVolBlock.h442
-rw-r--r--MdeModulePkg/Core/Dxe/Gcd/Gcd.c5752
-rw-r--r--MdeModulePkg/Core/Dxe/Gcd/Gcd.h80
-rw-r--r--MdeModulePkg/Core/Dxe/Hand/DriverSupport.c1988
-rw-r--r--MdeModulePkg/Core/Dxe/Hand/Handle.c3248
-rw-r--r--MdeModulePkg/Core/Dxe/Hand/Handle.h504
-rw-r--r--MdeModulePkg/Core/Dxe/Hand/Locate.c1482
-rw-r--r--MdeModulePkg/Core/Dxe/Hand/Notify.c556
-rw-r--r--MdeModulePkg/Core/Dxe/Image/Image.c3914
-rw-r--r--MdeModulePkg/Core/Dxe/Image/Image.h46
-rw-r--r--MdeModulePkg/Core/Dxe/Library/Library.c188
-rw-r--r--MdeModulePkg/Core/Dxe/Mem/HeapGuard.c3510
-rw-r--r--MdeModulePkg/Core/Dxe/Mem/HeapGuard.h972
-rw-r--r--MdeModulePkg/Core/Dxe/Mem/Imem.h344
-rw-r--r--MdeModulePkg/Core/Dxe/Mem/MemData.c38
-rw-r--r--MdeModulePkg/Core/Dxe/Mem/MemoryProfileRecord.c3584
-rw-r--r--MdeModulePkg/Core/Dxe/Mem/Page.c4616
-rw-r--r--MdeModulePkg/Core/Dxe/Mem/Pool.c1764
-rw-r--r--MdeModulePkg/Core/Dxe/Misc/DebugImageInfo.c564
-rwxr-xr-xMdeModulePkg/Core/Dxe/Misc/InstallConfigurationTable.c358
-rw-r--r--MdeModulePkg/Core/Dxe/Misc/MemoryAttributesTable.c1374
-rw-r--r--MdeModulePkg/Core/Dxe/Misc/MemoryProtection.c2220
-rw-r--r--MdeModulePkg/Core/Dxe/Misc/SetWatchdogTimer.c132
-rw-r--r--MdeModulePkg/Core/Dxe/Misc/Stall.c218
-rw-r--r--MdeModulePkg/Core/Dxe/SectionExtraction/CoreSectionExtraction.c3306
44 files changed, 30819 insertions, 30819 deletions
diff --git a/MdeModulePkg/Core/Dxe/Dispatcher/Dependency.c b/MdeModulePkg/Core/Dxe/Dispatcher/Dependency.c
index acbf68b700..da19ad04b9 100644
--- a/MdeModulePkg/Core/Dxe/Dispatcher/Dependency.c
+++ b/MdeModulePkg/Core/Dxe/Dispatcher/Dependency.c
@@ -1,433 +1,433 @@
-/** @file
- DXE Dispatcher Dependency Evaluator.
-
- This routine evaluates a dependency expression (DEPENDENCY_EXPRESSION) to determine
- if a driver can be scheduled for execution. The criteria for
- schedulability is that the dependency expression is satisfied.
-
-Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
-SPDX-License-Identifier: BSD-2-Clause-Patent
-
-**/
-
-#include "DxeMain.h"
-
-//
-// Global stack used to evaluate dependency expressions
-//
-BOOLEAN *mDepexEvaluationStack = NULL;
-BOOLEAN *mDepexEvaluationStackEnd = NULL;
-BOOLEAN *mDepexEvaluationStackPointer = NULL;
-
-//
-// Worker functions
-//
-
-/**
- Grow size of the Depex stack
-
- @retval EFI_SUCCESS Stack successfully growed.
- @retval EFI_OUT_OF_RESOURCES There is not enough system memory to grow the stack.
-
-**/
-EFI_STATUS
-GrowDepexStack (
- VOID
- )
-{
- BOOLEAN *NewStack;
- UINTN Size;
-
- Size = DEPEX_STACK_SIZE_INCREMENT;
- if (mDepexEvaluationStack != NULL) {
- Size = Size + (mDepexEvaluationStackEnd - mDepexEvaluationStack);
- }
-
- NewStack = AllocatePool (Size * sizeof (BOOLEAN));
- if (NewStack == NULL) {
- return EFI_OUT_OF_RESOURCES;
- }
-
- if (mDepexEvaluationStack != NULL) {
- //
- // Copy to Old Stack to the New Stack
- //
- CopyMem (
- NewStack,
- mDepexEvaluationStack,
- (mDepexEvaluationStackEnd - mDepexEvaluationStack) * sizeof (BOOLEAN)
- );
-
- //
- // Free The Old Stack
- //
- FreePool (mDepexEvaluationStack);
- }
-
- //
- // Make the Stack pointer point to the old data in the new stack
- //
- mDepexEvaluationStackPointer = NewStack + (mDepexEvaluationStackPointer - mDepexEvaluationStack);
- mDepexEvaluationStack = NewStack;
- mDepexEvaluationStackEnd = NewStack + Size;
-
- return EFI_SUCCESS;
-}
-
-/**
- Push an element onto the Boolean Stack.
-
- @param Value BOOLEAN to push.
-
- @retval EFI_SUCCESS The value was pushed onto the stack.
- @retval EFI_OUT_OF_RESOURCES There is not enough system memory to grow the stack.
-
-**/
-EFI_STATUS
-PushBool (
- IN BOOLEAN Value
- )
-{
- EFI_STATUS Status;
-
- //
- // Check for a stack overflow condition
- //
- if (mDepexEvaluationStackPointer == mDepexEvaluationStackEnd) {
- //
- // Grow the stack
- //
- Status = GrowDepexStack ();
- if (EFI_ERROR (Status)) {
- return Status;
- }
- }
-
- //
- // Push the item onto the stack
- //
- *mDepexEvaluationStackPointer = Value;
- mDepexEvaluationStackPointer++;
-
- return EFI_SUCCESS;
-}
-
-/**
- Pop an element from the Boolean stack.
-
- @param Value BOOLEAN to pop.
-
- @retval EFI_SUCCESS The value was popped onto the stack.
- @retval EFI_ACCESS_DENIED The pop operation underflowed the stack.
-
-**/
-EFI_STATUS
-PopBool (
- OUT BOOLEAN *Value
- )
-{
- //
- // Check for a stack underflow condition
- //
- if (mDepexEvaluationStackPointer == mDepexEvaluationStack) {
- return EFI_ACCESS_DENIED;
- }
-
- //
- // Pop the item off the stack
- //
- mDepexEvaluationStackPointer--;
- *Value = *mDepexEvaluationStackPointer;
- return EFI_SUCCESS;
-}
-
-/**
- Preprocess dependency expression and update DriverEntry to reflect the
- state of Before, After, and SOR dependencies. If DriverEntry->Before
- or DriverEntry->After is set it will never be cleared. If SOR is set
- it will be cleared by CoreSchedule(), and then the driver can be
- dispatched.
-
- @param DriverEntry DriverEntry element to update .
-
- @retval EFI_SUCCESS It always works.
-
-**/
-EFI_STATUS
-CorePreProcessDepex (
- IN EFI_CORE_DRIVER_ENTRY *DriverEntry
- )
-{
- UINT8 *Iterator;
-
- Iterator = DriverEntry->Depex;
- if (*Iterator == EFI_DEP_SOR) {
- DriverEntry->Unrequested = TRUE;
- } else {
- DriverEntry->Dependent = TRUE;
- }
-
- if (*Iterator == EFI_DEP_BEFORE) {
- DriverEntry->Before = TRUE;
- } else if (*Iterator == EFI_DEP_AFTER) {
- DriverEntry->After = TRUE;
- }
-
- if (DriverEntry->Before || DriverEntry->After) {
- CopyMem (&DriverEntry->BeforeAfterGuid, Iterator + 1, sizeof (EFI_GUID));
- }
-
- return EFI_SUCCESS;
-}
-
-/**
- This is the POSTFIX version of the dependency evaluator. This code does
- not need to handle Before or After, as it is not valid to call this
- routine in this case. The SOR is just ignored and is a nop in the grammer.
- POSTFIX means all the math is done on top of the stack.
-
- @param DriverEntry DriverEntry element to update.
-
- @retval TRUE If driver is ready to run.
- @retval FALSE If driver is not ready to run or some fatal error
- was found.
-
-**/
-BOOLEAN
-CoreIsSchedulable (
- IN EFI_CORE_DRIVER_ENTRY *DriverEntry
- )
-{
- EFI_STATUS Status;
- UINT8 *Iterator;
- BOOLEAN Operator;
- BOOLEAN Operator2;
- EFI_GUID DriverGuid;
- VOID *Interface;
-
- Operator = FALSE;
- Operator2 = FALSE;
-
- if (DriverEntry->After || DriverEntry->Before) {
- //
- // If Before or After Depex skip as CoreInsertOnScheduledQueueWhileProcessingBeforeAndAfter ()
- // processes them.
- //
- return FALSE;
- }
-
- DEBUG ((DEBUG_DISPATCH, "Evaluate DXE DEPEX for FFS(%g)\n", &DriverEntry->FileName));
-
- if (DriverEntry->Depex == NULL) {
- //
- // A NULL Depex means treat the driver like an UEFI 2.0 thing.
- //
- Status = CoreAllEfiServicesAvailable ();
- DEBUG ((DEBUG_DISPATCH, " All UEFI Services Available = "));
- if (EFI_ERROR (Status)) {
- DEBUG ((DEBUG_DISPATCH, "FALSE\n RESULT = FALSE\n"));
- return FALSE;
- }
-
- DEBUG ((DEBUG_DISPATCH, "TRUE\n RESULT = TRUE\n"));
- return TRUE;
- }
-
- //
- // Clean out memory leaks in Depex Boolean stack. Leaks are only caused by
- // incorrectly formed DEPEX expressions
- //
- mDepexEvaluationStackPointer = mDepexEvaluationStack;
-
- Iterator = DriverEntry->Depex;
-
- while (TRUE) {
- //
- // Check to see if we are attempting to fetch dependency expression instructions
- // past the end of the dependency expression.
- //
- if (((UINTN)Iterator - (UINTN)DriverEntry->Depex) >= DriverEntry->DepexSize) {
- DEBUG ((DEBUG_DISPATCH, " RESULT = FALSE (Attempt to fetch past end of depex)\n"));
- return FALSE;
- }
-
- //
- // Look at the opcode of the dependency expression instruction.
- //
- switch (*Iterator) {
- case EFI_DEP_BEFORE:
- case EFI_DEP_AFTER:
- //
- // For a well-formed Dependency Expression, the code should never get here.
- // The BEFORE and AFTER are processed prior to this routine's invocation.
- // If the code flow arrives at this point, there was a BEFORE or AFTER
- // that were not the first opcodes.
- //
- DEBUG ((DEBUG_DISPATCH, " RESULT = FALSE (Unexpected BEFORE or AFTER opcode)\n"));
- ASSERT (FALSE);
- case EFI_DEP_SOR:
- //
- // These opcodes can only appear once as the first opcode. If it is found
- // at any other location, then the dependency expression evaluates to FALSE
- //
- if (Iterator != DriverEntry->Depex) {
- DEBUG ((DEBUG_DISPATCH, " SOR\n"));
- DEBUG ((DEBUG_DISPATCH, " RESULT = FALSE (Unexpected SOR opcode)\n"));
- return FALSE;
- }
-
- DEBUG ((DEBUG_DISPATCH, " SOR = Requested\n"));
- //
- // Otherwise, it is the first opcode and should be treated as a NOP.
- //
- break;
-
- case EFI_DEP_PUSH:
- //
- // Push operator is followed by a GUID. Test to see if the GUID protocol
- // is installed and push the boolean result on the stack.
- //
- CopyMem (&DriverGuid, Iterator + 1, sizeof (EFI_GUID));
-
- Status = CoreLocateProtocol (&DriverGuid, NULL, &Interface);
-
- if (EFI_ERROR (Status)) {
- DEBUG ((DEBUG_DISPATCH, " PUSH GUID(%g) = FALSE\n", &DriverGuid));
- Status = PushBool (FALSE);
- } else {
- DEBUG ((DEBUG_DISPATCH, " PUSH GUID(%g) = TRUE\n", &DriverGuid));
- *Iterator = EFI_DEP_REPLACE_TRUE;
- Status = PushBool (TRUE);
- }
-
- if (EFI_ERROR (Status)) {
- DEBUG ((DEBUG_DISPATCH, " RESULT = FALSE (Unexpected error)\n"));
- return FALSE;
- }
-
- Iterator += sizeof (EFI_GUID);
- break;
-
- case EFI_DEP_AND:
- DEBUG ((DEBUG_DISPATCH, " AND\n"));
- Status = PopBool (&Operator);
- if (EFI_ERROR (Status)) {
- DEBUG ((DEBUG_DISPATCH, " RESULT = FALSE (Unexpected error)\n"));
- return FALSE;
- }
-
- Status = PopBool (&Operator2);
- if (EFI_ERROR (Status)) {
- DEBUG ((DEBUG_DISPATCH, " RESULT = FALSE (Unexpected error)\n"));
- return FALSE;
- }
-
- Status = PushBool ((BOOLEAN)(Operator && Operator2));
- if (EFI_ERROR (Status)) {
- DEBUG ((DEBUG_DISPATCH, " RESULT = FALSE (Unexpected error)\n"));
- return FALSE;
- }
-
- break;
-
- case EFI_DEP_OR:
- DEBUG ((DEBUG_DISPATCH, " OR\n"));
- Status = PopBool (&Operator);
- if (EFI_ERROR (Status)) {
- DEBUG ((DEBUG_DISPATCH, " RESULT = FALSE (Unexpected error)\n"));
- return FALSE;
- }
-
- Status = PopBool (&Operator2);
- if (EFI_ERROR (Status)) {
- DEBUG ((DEBUG_DISPATCH, " RESULT = FALSE (Unexpected error)\n"));
- return FALSE;
- }
-
- Status = PushBool ((BOOLEAN)(Operator || Operator2));
- if (EFI_ERROR (Status)) {
- DEBUG ((DEBUG_DISPATCH, " RESULT = FALSE (Unexpected error)\n"));
- return FALSE;
- }
-
- break;
-
- case EFI_DEP_NOT:
- DEBUG ((DEBUG_DISPATCH, " NOT\n"));
- Status = PopBool (&Operator);
- if (EFI_ERROR (Status)) {
- DEBUG ((DEBUG_DISPATCH, " RESULT = FALSE (Unexpected error)\n"));
- return FALSE;
- }
-
- Status = PushBool ((BOOLEAN)(!Operator));
- if (EFI_ERROR (Status)) {
- DEBUG ((DEBUG_DISPATCH, " RESULT = FALSE (Unexpected error)\n"));
- return FALSE;
- }
-
- break;
-
- case EFI_DEP_TRUE:
- DEBUG ((DEBUG_DISPATCH, " TRUE\n"));
- Status = PushBool (TRUE);
- if (EFI_ERROR (Status)) {
- DEBUG ((DEBUG_DISPATCH, " RESULT = FALSE (Unexpected error)\n"));
- return FALSE;
- }
-
- break;
-
- case EFI_DEP_FALSE:
- DEBUG ((DEBUG_DISPATCH, " FALSE\n"));
- Status = PushBool (FALSE);
- if (EFI_ERROR (Status)) {
- DEBUG ((DEBUG_DISPATCH, " RESULT = FALSE (Unexpected error)\n"));
- return FALSE;
- }
-
- break;
-
- case EFI_DEP_END:
- DEBUG ((DEBUG_DISPATCH, " END\n"));
- Status = PopBool (&Operator);
- if (EFI_ERROR (Status)) {
- DEBUG ((DEBUG_DISPATCH, " RESULT = FALSE (Unexpected error)\n"));
- return FALSE;
- }
-
- DEBUG ((DEBUG_DISPATCH, " RESULT = %a\n", Operator ? "TRUE" : "FALSE"));
- return Operator;
-
- case EFI_DEP_REPLACE_TRUE:
- CopyMem (&DriverGuid, Iterator + 1, sizeof (EFI_GUID));
- DEBUG ((DEBUG_DISPATCH, " PUSH GUID(%g) = TRUE\n", &DriverGuid));
-
- Status = PushBool (TRUE);
- if (EFI_ERROR (Status)) {
- DEBUG ((DEBUG_DISPATCH, " RESULT = FALSE (Unexpected error)\n"));
- return FALSE;
- }
-
- Iterator += sizeof (EFI_GUID);
- break;
-
- default:
- DEBUG ((DEBUG_DISPATCH, " RESULT = FALSE (Unknown opcode)\n"));
- goto Done;
- }
-
- //
- // Skip over the Dependency Op Code we just processed in the switch.
- // The math is done out of order, but it should not matter. That is
- // we may add in the sizeof (EFI_GUID) before we account for the OP Code.
- // This is not an issue, since we just need the correct end result. You
- // need to be careful using Iterator in the loop as it's intermediate value
- // may be strange.
- //
- Iterator++;
- }
-
-Done:
- return FALSE;
-}
+/** @file
+ DXE Dispatcher Dependency Evaluator.
+
+ This routine evaluates a dependency expression (DEPENDENCY_EXPRESSION) to determine
+ if a driver can be scheduled for execution. The criteria for
+ schedulability is that the dependency expression is satisfied.
+
+Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "DxeMain.h"
+
+//
+// Global stack used to evaluate dependency expressions
+//
+BOOLEAN *mDepexEvaluationStack = NULL;
+BOOLEAN *mDepexEvaluationStackEnd = NULL;
+BOOLEAN *mDepexEvaluationStackPointer = NULL;
+
+//
+// Worker functions
+//
+
+/**
+ Grow size of the Depex stack
+
+ @retval EFI_SUCCESS Stack successfully growed.
+ @retval EFI_OUT_OF_RESOURCES There is not enough system memory to grow the stack.
+
+**/
+EFI_STATUS
+GrowDepexStack (
+ VOID
+ )
+{
+ BOOLEAN *NewStack;
+ UINTN Size;
+
+ Size = DEPEX_STACK_SIZE_INCREMENT;
+ if (mDepexEvaluationStack != NULL) {
+ Size = Size + (mDepexEvaluationStackEnd - mDepexEvaluationStack);
+ }
+
+ NewStack = AllocatePool (Size * sizeof (BOOLEAN));
+ if (NewStack == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ if (mDepexEvaluationStack != NULL) {
+ //
+ // Copy to Old Stack to the New Stack
+ //
+ CopyMem (
+ NewStack,
+ mDepexEvaluationStack,
+ (mDepexEvaluationStackEnd - mDepexEvaluationStack) * sizeof (BOOLEAN)
+ );
+
+ //
+ // Free The Old Stack
+ //
+ FreePool (mDepexEvaluationStack);
+ }
+
+ //
+ // Make the Stack pointer point to the old data in the new stack
+ //
+ mDepexEvaluationStackPointer = NewStack + (mDepexEvaluationStackPointer - mDepexEvaluationStack);
+ mDepexEvaluationStack = NewStack;
+ mDepexEvaluationStackEnd = NewStack + Size;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Push an element onto the Boolean Stack.
+
+ @param Value BOOLEAN to push.
+
+ @retval EFI_SUCCESS The value was pushed onto the stack.
+ @retval EFI_OUT_OF_RESOURCES There is not enough system memory to grow the stack.
+
+**/
+EFI_STATUS
+PushBool (
+ IN BOOLEAN Value
+ )
+{
+ EFI_STATUS Status;
+
+ //
+ // Check for a stack overflow condition
+ //
+ if (mDepexEvaluationStackPointer == mDepexEvaluationStackEnd) {
+ //
+ // Grow the stack
+ //
+ Status = GrowDepexStack ();
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+
+ //
+ // Push the item onto the stack
+ //
+ *mDepexEvaluationStackPointer = Value;
+ mDepexEvaluationStackPointer++;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Pop an element from the Boolean stack.
+
+ @param Value BOOLEAN to pop.
+
+ @retval EFI_SUCCESS The value was popped onto the stack.
+ @retval EFI_ACCESS_DENIED The pop operation underflowed the stack.
+
+**/
+EFI_STATUS
+PopBool (
+ OUT BOOLEAN *Value
+ )
+{
+ //
+ // Check for a stack underflow condition
+ //
+ if (mDepexEvaluationStackPointer == mDepexEvaluationStack) {
+ return EFI_ACCESS_DENIED;
+ }
+
+ //
+ // Pop the item off the stack
+ //
+ mDepexEvaluationStackPointer--;
+ *Value = *mDepexEvaluationStackPointer;
+ return EFI_SUCCESS;
+}
+
+/**
+ Preprocess dependency expression and update DriverEntry to reflect the
+ state of Before, After, and SOR dependencies. If DriverEntry->Before
+ or DriverEntry->After is set it will never be cleared. If SOR is set
+ it will be cleared by CoreSchedule(), and then the driver can be
+ dispatched.
+
+ @param DriverEntry DriverEntry element to update .
+
+ @retval EFI_SUCCESS It always works.
+
+**/
+EFI_STATUS
+CorePreProcessDepex (
+ IN EFI_CORE_DRIVER_ENTRY *DriverEntry
+ )
+{
+ UINT8 *Iterator;
+
+ Iterator = DriverEntry->Depex;
+ if (*Iterator == EFI_DEP_SOR) {
+ DriverEntry->Unrequested = TRUE;
+ } else {
+ DriverEntry->Dependent = TRUE;
+ }
+
+ if (*Iterator == EFI_DEP_BEFORE) {
+ DriverEntry->Before = TRUE;
+ } else if (*Iterator == EFI_DEP_AFTER) {
+ DriverEntry->After = TRUE;
+ }
+
+ if (DriverEntry->Before || DriverEntry->After) {
+ CopyMem (&DriverEntry->BeforeAfterGuid, Iterator + 1, sizeof (EFI_GUID));
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ This is the POSTFIX version of the dependency evaluator. This code does
+ not need to handle Before or After, as it is not valid to call this
+ routine in this case. The SOR is just ignored and is a nop in the grammer.
+ POSTFIX means all the math is done on top of the stack.
+
+ @param DriverEntry DriverEntry element to update.
+
+ @retval TRUE If driver is ready to run.
+ @retval FALSE If driver is not ready to run or some fatal error
+ was found.
+
+**/
+BOOLEAN
+CoreIsSchedulable (
+ IN EFI_CORE_DRIVER_ENTRY *DriverEntry
+ )
+{
+ EFI_STATUS Status;
+ UINT8 *Iterator;
+ BOOLEAN Operator;
+ BOOLEAN Operator2;
+ EFI_GUID DriverGuid;
+ VOID *Interface;
+
+ Operator = FALSE;
+ Operator2 = FALSE;
+
+ if (DriverEntry->After || DriverEntry->Before) {
+ //
+ // If Before or After Depex skip as CoreInsertOnScheduledQueueWhileProcessingBeforeAndAfter ()
+ // processes them.
+ //
+ return FALSE;
+ }
+
+ DEBUG ((DEBUG_DISPATCH, "Evaluate DXE DEPEX for FFS(%g)\n", &DriverEntry->FileName));
+
+ if (DriverEntry->Depex == NULL) {
+ //
+ // A NULL Depex means treat the driver like an UEFI 2.0 thing.
+ //
+ Status = CoreAllEfiServicesAvailable ();
+ DEBUG ((DEBUG_DISPATCH, " All UEFI Services Available = "));
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_DISPATCH, "FALSE\n RESULT = FALSE\n"));
+ return FALSE;
+ }
+
+ DEBUG ((DEBUG_DISPATCH, "TRUE\n RESULT = TRUE\n"));
+ return TRUE;
+ }
+
+ //
+ // Clean out memory leaks in Depex Boolean stack. Leaks are only caused by
+ // incorrectly formed DEPEX expressions
+ //
+ mDepexEvaluationStackPointer = mDepexEvaluationStack;
+
+ Iterator = DriverEntry->Depex;
+
+ while (TRUE) {
+ //
+ // Check to see if we are attempting to fetch dependency expression instructions
+ // past the end of the dependency expression.
+ //
+ if (((UINTN)Iterator - (UINTN)DriverEntry->Depex) >= DriverEntry->DepexSize) {
+ DEBUG ((DEBUG_DISPATCH, " RESULT = FALSE (Attempt to fetch past end of depex)\n"));
+ return FALSE;
+ }
+
+ //
+ // Look at the opcode of the dependency expression instruction.
+ //
+ switch (*Iterator) {
+ case EFI_DEP_BEFORE:
+ case EFI_DEP_AFTER:
+ //
+ // For a well-formed Dependency Expression, the code should never get here.
+ // The BEFORE and AFTER are processed prior to this routine's invocation.
+ // If the code flow arrives at this point, there was a BEFORE or AFTER
+ // that were not the first opcodes.
+ //
+ DEBUG ((DEBUG_DISPATCH, " RESULT = FALSE (Unexpected BEFORE or AFTER opcode)\n"));
+ ASSERT (FALSE);
+ case EFI_DEP_SOR:
+ //
+ // These opcodes can only appear once as the first opcode. If it is found
+ // at any other location, then the dependency expression evaluates to FALSE
+ //
+ if (Iterator != DriverEntry->Depex) {
+ DEBUG ((DEBUG_DISPATCH, " SOR\n"));
+ DEBUG ((DEBUG_DISPATCH, " RESULT = FALSE (Unexpected SOR opcode)\n"));
+ return FALSE;
+ }
+
+ DEBUG ((DEBUG_DISPATCH, " SOR = Requested\n"));
+ //
+ // Otherwise, it is the first opcode and should be treated as a NOP.
+ //
+ break;
+
+ case EFI_DEP_PUSH:
+ //
+ // Push operator is followed by a GUID. Test to see if the GUID protocol
+ // is installed and push the boolean result on the stack.
+ //
+ CopyMem (&DriverGuid, Iterator + 1, sizeof (EFI_GUID));
+
+ Status = CoreLocateProtocol (&DriverGuid, NULL, &Interface);
+
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_DISPATCH, " PUSH GUID(%g) = FALSE\n", &DriverGuid));
+ Status = PushBool (FALSE);
+ } else {
+ DEBUG ((DEBUG_DISPATCH, " PUSH GUID(%g) = TRUE\n", &DriverGuid));
+ *Iterator = EFI_DEP_REPLACE_TRUE;
+ Status = PushBool (TRUE);
+ }
+
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_DISPATCH, " RESULT = FALSE (Unexpected error)\n"));
+ return FALSE;
+ }
+
+ Iterator += sizeof (EFI_GUID);
+ break;
+
+ case EFI_DEP_AND:
+ DEBUG ((DEBUG_DISPATCH, " AND\n"));
+ Status = PopBool (&Operator);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_DISPATCH, " RESULT = FALSE (Unexpected error)\n"));
+ return FALSE;
+ }
+
+ Status = PopBool (&Operator2);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_DISPATCH, " RESULT = FALSE (Unexpected error)\n"));
+ return FALSE;
+ }
+
+ Status = PushBool ((BOOLEAN)(Operator && Operator2));
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_DISPATCH, " RESULT = FALSE (Unexpected error)\n"));
+ return FALSE;
+ }
+
+ break;
+
+ case EFI_DEP_OR:
+ DEBUG ((DEBUG_DISPATCH, " OR\n"));
+ Status = PopBool (&Operator);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_DISPATCH, " RESULT = FALSE (Unexpected error)\n"));
+ return FALSE;
+ }
+
+ Status = PopBool (&Operator2);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_DISPATCH, " RESULT = FALSE (Unexpected error)\n"));
+ return FALSE;
+ }
+
+ Status = PushBool ((BOOLEAN)(Operator || Operator2));
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_DISPATCH, " RESULT = FALSE (Unexpected error)\n"));
+ return FALSE;
+ }
+
+ break;
+
+ case EFI_DEP_NOT:
+ DEBUG ((DEBUG_DISPATCH, " NOT\n"));
+ Status = PopBool (&Operator);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_DISPATCH, " RESULT = FALSE (Unexpected error)\n"));
+ return FALSE;
+ }
+
+ Status = PushBool ((BOOLEAN)(!Operator));
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_DISPATCH, " RESULT = FALSE (Unexpected error)\n"));
+ return FALSE;
+ }
+
+ break;
+
+ case EFI_DEP_TRUE:
+ DEBUG ((DEBUG_DISPATCH, " TRUE\n"));
+ Status = PushBool (TRUE);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_DISPATCH, " RESULT = FALSE (Unexpected error)\n"));
+ return FALSE;
+ }
+
+ break;
+
+ case EFI_DEP_FALSE:
+ DEBUG ((DEBUG_DISPATCH, " FALSE\n"));
+ Status = PushBool (FALSE);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_DISPATCH, " RESULT = FALSE (Unexpected error)\n"));
+ return FALSE;
+ }
+
+ break;
+
+ case EFI_DEP_END:
+ DEBUG ((DEBUG_DISPATCH, " END\n"));
+ Status = PopBool (&Operator);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_DISPATCH, " RESULT = FALSE (Unexpected error)\n"));
+ return FALSE;
+ }
+
+ DEBUG ((DEBUG_DISPATCH, " RESULT = %a\n", Operator ? "TRUE" : "FALSE"));
+ return Operator;
+
+ case EFI_DEP_REPLACE_TRUE:
+ CopyMem (&DriverGuid, Iterator + 1, sizeof (EFI_GUID));
+ DEBUG ((DEBUG_DISPATCH, " PUSH GUID(%g) = TRUE\n", &DriverGuid));
+
+ Status = PushBool (TRUE);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_DISPATCH, " RESULT = FALSE (Unexpected error)\n"));
+ return FALSE;
+ }
+
+ Iterator += sizeof (EFI_GUID);
+ break;
+
+ default:
+ DEBUG ((DEBUG_DISPATCH, " RESULT = FALSE (Unknown opcode)\n"));
+ goto Done;
+ }
+
+ //
+ // Skip over the Dependency Op Code we just processed in the switch.
+ // The math is done out of order, but it should not matter. That is
+ // we may add in the sizeof (EFI_GUID) before we account for the OP Code.
+ // This is not an issue, since we just need the correct end result. You
+ // need to be careful using Iterator in the loop as it's intermediate value
+ // may be strange.
+ //
+ Iterator++;
+ }
+
+Done:
+ return FALSE;
+}
diff --git a/MdeModulePkg/Core/Dxe/Dispatcher/Dispatcher.c b/MdeModulePkg/Core/Dxe/Dispatcher/Dispatcher.c
index cf9d556877..86313eba16 100644
--- a/MdeModulePkg/Core/Dxe/Dispatcher/Dispatcher.c
+++ b/MdeModulePkg/Core/Dxe/Dispatcher/Dispatcher.c
@@ -1,1484 +1,1484 @@
-/** @file
- DXE Dispatcher.
-
- Step #1 - When a FV protocol is added to the system every driver in the FV
- is added to the mDiscoveredList. The SOR, Before, and After Depex are
- pre-processed as drivers are added to the mDiscoveredList. If an Apriori
- file exists in the FV those drivers are addeded to the
- mScheduledQueue. The mFvHandleList is used to make sure a
- FV is only processed once.
-
- Step #2 - Dispatch. Remove driver from the mScheduledQueue and load and
- start it. After mScheduledQueue is drained check the
- mDiscoveredList to see if any item has a Depex that is ready to
- be placed on the mScheduledQueue.
-
- Step #3 - Adding to the mScheduledQueue requires that you process Before
- and After dependencies. This is done recursively as the call to add
- to the mScheduledQueue checks for Before and recursively adds
- all Befores. It then addes the item that was passed in and then
- processess the After dependecies by recursively calling the routine.
-
- Dispatcher Rules:
- The rules for the dispatcher are in chapter 10 of the DXE CIS. Figure 10-3
- is the state diagram for the DXE dispatcher
-
- Depex - Dependency Expresion.
- SOR - Schedule On Request - Don't schedule if this bit is set.
-
-Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
-SPDX-License-Identifier: BSD-2-Clause-Patent
-
-**/
-
-#include "DxeMain.h"
-
-//
-// The Driver List contains one copy of every driver that has been discovered.
-// Items are never removed from the driver list. List of EFI_CORE_DRIVER_ENTRY
-//
-LIST_ENTRY mDiscoveredList = INITIALIZE_LIST_HEAD_VARIABLE (mDiscoveredList);
-
-//
-// Queue of drivers that are ready to dispatch. This queue is a subset of the
-// mDiscoveredList.list of EFI_CORE_DRIVER_ENTRY.
-//
-LIST_ENTRY mScheduledQueue = INITIALIZE_LIST_HEAD_VARIABLE (mScheduledQueue);
-
-//
-// List of handles who's Fv's have been parsed and added to the mFwDriverList.
-//
-LIST_ENTRY mFvHandleList = INITIALIZE_LIST_HEAD_VARIABLE (mFvHandleList); // list of KNOWN_HANDLE
-
-//
-// Lock for mDiscoveredList, mScheduledQueue, gDispatcherRunning.
-//
-EFI_LOCK mDispatcherLock = EFI_INITIALIZE_LOCK_VARIABLE (TPL_HIGH_LEVEL);
-
-//
-// Flag for the DXE Dispacher. TRUE if dispatcher is execuing.
-//
-BOOLEAN gDispatcherRunning = FALSE;
-
-//
-// Module globals to manage the FwVol registration notification event
-//
-EFI_EVENT mFwVolEvent;
-VOID *mFwVolEventRegistration;
-
-//
-// List of file types supported by dispatcher
-//
-EFI_FV_FILETYPE mDxeFileTypes[] = {
- EFI_FV_FILETYPE_DRIVER,
- EFI_FV_FILETYPE_COMBINED_SMM_DXE,
- EFI_FV_FILETYPE_COMBINED_PEIM_DRIVER,
- EFI_FV_FILETYPE_DXE_CORE,
- EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE
-};
-
-typedef struct {
- MEDIA_FW_VOL_FILEPATH_DEVICE_PATH File;
- EFI_DEVICE_PATH_PROTOCOL End;
-} FV_FILEPATH_DEVICE_PATH;
-
-FV_FILEPATH_DEVICE_PATH mFvDevicePath;
-
-//
-// Function Prototypes
-//
-
-/**
- Insert InsertedDriverEntry onto the mScheduledQueue. To do this you
- must add any driver with a before dependency on InsertedDriverEntry first.
- You do this by recursively calling this routine. After all the Befores are
- processed you can add InsertedDriverEntry to the mScheduledQueue.
- Then you can add any driver with an After dependency on InsertedDriverEntry
- by recursively calling this routine.
-
- @param InsertedDriverEntry The driver to insert on the ScheduledLink Queue
-
-**/
-VOID
-CoreInsertOnScheduledQueueWhileProcessingBeforeAndAfter (
- IN EFI_CORE_DRIVER_ENTRY *InsertedDriverEntry
- );
-
-/**
- Event notification that is fired every time a FV dispatch protocol is added.
- More than one protocol may have been added when this event is fired, so you
- must loop on CoreLocateHandle () to see how many protocols were added and
- do the following to each FV:
- If the Fv has already been processed, skip it. If the Fv has not been
- processed then mark it as being processed, as we are about to process it.
- Read the Fv and add any driver in the Fv to the mDiscoveredList.The
- mDiscoveredList is never free'ed and contains variables that define
- the other states the DXE driver transitions to..
- While you are at it read the A Priori file into memory.
- Place drivers in the A Priori list onto the mScheduledQueue.
-
- @param Event The Event that is being processed, not used.
- @param Context Event Context, not used.
-
-**/
-VOID
-EFIAPI
-CoreFwVolEventProtocolNotify (
- IN EFI_EVENT Event,
- IN VOID *Context
- );
-
-/**
- Convert FvHandle and DriverName into an EFI device path
-
- @param Fv Fv protocol, needed to read Depex info out of
- FLASH.
- @param FvHandle Handle for Fv, needed in the
- EFI_CORE_DRIVER_ENTRY so that the PE image can be
- read out of the FV at a later time.
- @param DriverName Name of driver to add to mDiscoveredList.
-
- @return Pointer to device path constructed from FvHandle and DriverName
-
-**/
-EFI_DEVICE_PATH_PROTOCOL *
-CoreFvToDevicePath (
- IN EFI_FIRMWARE_VOLUME2_PROTOCOL *Fv,
- IN EFI_HANDLE FvHandle,
- IN EFI_GUID *DriverName
- );
-
-/**
- Add an entry to the mDiscoveredList. Allocate memory to store the DriverEntry,
- and initilize any state variables. Read the Depex from the FV and store it
- in DriverEntry. Pre-process the Depex to set the SOR, Before and After state.
- The Discovered list is never free'ed and contains booleans that represent the
- other possible DXE driver states.
-
- @param Fv Fv protocol, needed to read Depex info out of
- FLASH.
- @param FvHandle Handle for Fv, needed in the
- EFI_CORE_DRIVER_ENTRY so that the PE image can be
- read out of the FV at a later time.
- @param DriverName Name of driver to add to mDiscoveredList.
- @param Type Fv File Type of file to add to mDiscoveredList.
-
- @retval EFI_SUCCESS If driver was added to the mDiscoveredList.
- @retval EFI_ALREADY_STARTED The driver has already been started. Only one
- DriverName may be active in the system at any one
- time.
-
-**/
-EFI_STATUS
-CoreAddToDriverList (
- IN EFI_FIRMWARE_VOLUME2_PROTOCOL *Fv,
- IN EFI_HANDLE FvHandle,
- IN EFI_GUID *DriverName,
- IN EFI_FV_FILETYPE Type
- );
-
-/**
- Get Fv image(s) from the FV through file name, and produce FVB protocol for every Fv image(s).
-
- @param Fv The FIRMWARE_VOLUME protocol installed on the FV.
- @param FvHandle The handle which FVB protocol installed on.
- @param FileName The file name guid specified.
-
- @retval EFI_OUT_OF_RESOURCES No enough memory or other resource.
- @retval EFI_SUCCESS Function successfully returned.
-
-**/
-EFI_STATUS
-CoreProcessFvImageFile (
- IN EFI_FIRMWARE_VOLUME2_PROTOCOL *Fv,
- IN EFI_HANDLE FvHandle,
- IN EFI_GUID *FileName
- );
-
-/**
- Enter critical section by gaining lock on mDispatcherLock.
-
-**/
-VOID
-CoreAcquireDispatcherLock (
- VOID
- )
-{
- CoreAcquireLock (&mDispatcherLock);
-}
-
-/**
- Exit critical section by releasing lock on mDispatcherLock.
-
-**/
-VOID
-CoreReleaseDispatcherLock (
- VOID
- )
-{
- CoreReleaseLock (&mDispatcherLock);
-}
-
-/**
- Read Depex and pre-process the Depex for Before and After. If Section Extraction
- protocol returns an error via ReadSection defer the reading of the Depex.
-
- @param DriverEntry Driver to work on.
-
- @retval EFI_SUCCESS Depex read and preprossesed
- @retval EFI_PROTOCOL_ERROR The section extraction protocol returned an error
- and Depex reading needs to be retried.
- @retval Error DEPEX not found.
-
-**/
-EFI_STATUS
-CoreGetDepexSectionAndPreProccess (
- IN EFI_CORE_DRIVER_ENTRY *DriverEntry
- )
-{
- EFI_STATUS Status;
- EFI_SECTION_TYPE SectionType;
- UINT32 AuthenticationStatus;
- EFI_FIRMWARE_VOLUME2_PROTOCOL *Fv;
-
- Fv = DriverEntry->Fv;
-
- //
- // Grab Depex info, it will never be free'ed.
- //
- SectionType = EFI_SECTION_DXE_DEPEX;
- Status = Fv->ReadSection (
- DriverEntry->Fv,
- &DriverEntry->FileName,
- SectionType,
- 0,
- &DriverEntry->Depex,
- (UINTN *)&DriverEntry->DepexSize,
- &AuthenticationStatus
- );
- if (EFI_ERROR (Status)) {
- if (Status == EFI_PROTOCOL_ERROR) {
- //
- // The section extraction protocol failed so set protocol error flag
- //
- DriverEntry->DepexProtocolError = TRUE;
- } else {
- //
- // If no Depex assume UEFI 2.0 driver model
- //
- DriverEntry->Depex = NULL;
- DriverEntry->Dependent = TRUE;
- DriverEntry->DepexProtocolError = FALSE;
- }
- } else {
- //
- // Set Before, After, and Unrequested state information based on Depex
- // Driver will be put in Dependent or Unrequested state
- //
- CorePreProcessDepex (DriverEntry);
- DriverEntry->DepexProtocolError = FALSE;
- }
-
- return Status;
-}
-
-/**
- Check every driver and locate a matching one. If the driver is found, the Unrequested
- state flag is cleared.
-
- @param FirmwareVolumeHandle The handle of the Firmware Volume that contains
- the firmware file specified by DriverName.
- @param DriverName The Driver name to put in the Dependent state.
-
- @retval EFI_SUCCESS The DriverName was found and it's SOR bit was
- cleared
- @retval EFI_NOT_FOUND The DriverName does not exist or it's SOR bit was
- not set.
-
-**/
-EFI_STATUS
-EFIAPI
-CoreSchedule (
- IN EFI_HANDLE FirmwareVolumeHandle,
- IN EFI_GUID *DriverName
- )
-{
- LIST_ENTRY *Link;
- EFI_CORE_DRIVER_ENTRY *DriverEntry;
-
- //
- // Check every driver
- //
- for (Link = mDiscoveredList.ForwardLink; Link != &mDiscoveredList; Link = Link->ForwardLink) {
- DriverEntry = CR (Link, EFI_CORE_DRIVER_ENTRY, Link, EFI_CORE_DRIVER_ENTRY_SIGNATURE);
- if ((DriverEntry->FvHandle == FirmwareVolumeHandle) &&
- DriverEntry->Unrequested &&
- CompareGuid (DriverName, &DriverEntry->FileName))
- {
- //
- // Move the driver from the Unrequested to the Dependent state
- //
- CoreAcquireDispatcherLock ();
- DriverEntry->Unrequested = FALSE;
- DriverEntry->Dependent = TRUE;
- CoreReleaseDispatcherLock ();
-
- DEBUG ((DEBUG_DISPATCH, "Schedule FFS(%g) - EFI_SUCCESS\n", DriverName));
-
- return EFI_SUCCESS;
- }
- }
-
- DEBUG ((DEBUG_DISPATCH, "Schedule FFS(%g) - EFI_NOT_FOUND\n", DriverName));
-
- return EFI_NOT_FOUND;
-}
-
-/**
- Convert a driver from the Untrused back to the Scheduled state.
-
- @param FirmwareVolumeHandle The handle of the Firmware Volume that contains
- the firmware file specified by DriverName.
- @param DriverName The Driver name to put in the Scheduled state
-
- @retval EFI_SUCCESS The file was found in the untrusted state, and it
- was promoted to the trusted state.
- @retval EFI_NOT_FOUND The file was not found in the untrusted state.
-
-**/
-EFI_STATUS
-EFIAPI
-CoreTrust (
- IN EFI_HANDLE FirmwareVolumeHandle,
- IN EFI_GUID *DriverName
- )
-{
- LIST_ENTRY *Link;
- EFI_CORE_DRIVER_ENTRY *DriverEntry;
-
- //
- // Check every driver
- //
- for (Link = mDiscoveredList.ForwardLink; Link != &mDiscoveredList; Link = Link->ForwardLink) {
- DriverEntry = CR (Link, EFI_CORE_DRIVER_ENTRY, Link, EFI_CORE_DRIVER_ENTRY_SIGNATURE);
- if ((DriverEntry->FvHandle == FirmwareVolumeHandle) &&
- DriverEntry->Untrusted &&
- CompareGuid (DriverName, &DriverEntry->FileName))
- {
- //
- // Transition driver from Untrusted to Scheduled state.
- //
- CoreAcquireDispatcherLock ();
- DriverEntry->Untrusted = FALSE;
- DriverEntry->Scheduled = TRUE;
- InsertTailList (&mScheduledQueue, &DriverEntry->ScheduledLink);
- CoreReleaseDispatcherLock ();
-
- return EFI_SUCCESS;
- }
- }
-
- return EFI_NOT_FOUND;
-}
-
-/**
- This is the main Dispatcher for DXE and it exits when there are no more
- drivers to run. Drain the mScheduledQueue and load and start a PE
- image for each driver. Search the mDiscoveredList to see if any driver can
- be placed on the mScheduledQueue. If no drivers are placed on the
- mScheduledQueue exit the function. On exit it is assumed the Bds()
- will be called, and when the Bds() exits the Dispatcher will be called
- again.
-
- @retval EFI_ALREADY_STARTED The DXE Dispatcher is already running
- @retval EFI_NOT_FOUND No DXE Drivers were dispatched
- @retval EFI_SUCCESS One or more DXE Drivers were dispatched
-
-**/
-EFI_STATUS
-EFIAPI
-CoreDispatcher (
- VOID
- )
-{
- EFI_STATUS Status;
- EFI_STATUS ReturnStatus;
- LIST_ENTRY *Link;
- EFI_CORE_DRIVER_ENTRY *DriverEntry;
- BOOLEAN ReadyToRun;
- EFI_EVENT DxeDispatchEvent;
-
- PERF_FUNCTION_BEGIN ();
-
- if (gDispatcherRunning) {
- //
- // If the dispatcher is running don't let it be restarted.
- //
- return EFI_ALREADY_STARTED;
- }
-
- gDispatcherRunning = TRUE;
-
- Status = CoreCreateEventEx (
- EVT_NOTIFY_SIGNAL,
- TPL_NOTIFY,
- EfiEventEmptyFunction,
- NULL,
- &gEfiEventDxeDispatchGuid,
- &DxeDispatchEvent
- );
- if (EFI_ERROR (Status)) {
- return Status;
- }
-
- ReturnStatus = EFI_NOT_FOUND;
- do {
- //
- // Drain the Scheduled Queue
- //
- while (!IsListEmpty (&mScheduledQueue)) {
- DriverEntry = CR (
- mScheduledQueue.ForwardLink,
- EFI_CORE_DRIVER_ENTRY,
- ScheduledLink,
- EFI_CORE_DRIVER_ENTRY_SIGNATURE
- );
-
- //
- // Load the DXE Driver image into memory. If the Driver was transitioned from
- // Untrused to Scheduled it would have already been loaded so we may need to
- // skip the LoadImage
- //
- if ((DriverEntry->ImageHandle == NULL) && !DriverEntry->IsFvImage) {
- DEBUG ((DEBUG_INFO, "Loading driver %g\n", &DriverEntry->FileName));
- Status = CoreLoadImage (
- FALSE,
- gDxeCoreImageHandle,
- DriverEntry->FvFileDevicePath,
- NULL,
- 0,
- &DriverEntry->ImageHandle
- );
-
- //
- // Update the driver state to reflect that it's been loaded
- //
- if (EFI_ERROR (Status)) {
- CoreAcquireDispatcherLock ();
-
- if (Status == EFI_SECURITY_VIOLATION) {
- //
- // Take driver from Scheduled to Untrused state
- //
- DriverEntry->Untrusted = TRUE;
- } else {
- //
- // The DXE Driver could not be loaded, and do not attempt to load or start it again.
- // Take driver from Scheduled to Initialized.
- //
- // This case include the Never Trusted state if EFI_ACCESS_DENIED is returned
- //
- DriverEntry->Initialized = TRUE;
- }
-
- DriverEntry->Scheduled = FALSE;
- RemoveEntryList (&DriverEntry->ScheduledLink);
-
- CoreReleaseDispatcherLock ();
-
- //
- // If it's an error don't try the StartImage
- //
- continue;
- }
- }
-
- CoreAcquireDispatcherLock ();
-
- DriverEntry->Scheduled = FALSE;
- DriverEntry->Initialized = TRUE;
- RemoveEntryList (&DriverEntry->ScheduledLink);
-
- CoreReleaseDispatcherLock ();
-
- if (DriverEntry->IsFvImage) {
- //
- // Produce a firmware volume block protocol for FvImage so it gets dispatched from.
- //
- Status = CoreProcessFvImageFile (DriverEntry->Fv, DriverEntry->FvHandle, &DriverEntry->FileName);
- } else {
- REPORT_STATUS_CODE_WITH_EXTENDED_DATA (
- EFI_PROGRESS_CODE,
- (EFI_SOFTWARE_DXE_CORE | EFI_SW_PC_INIT_BEGIN),
- &DriverEntry->ImageHandle,
- sizeof (DriverEntry->ImageHandle)
- );
- ASSERT (DriverEntry->ImageHandle != NULL);
-
- Status = CoreStartImage (DriverEntry->ImageHandle, NULL, NULL);
-
- REPORT_STATUS_CODE_WITH_EXTENDED_DATA (
- EFI_PROGRESS_CODE,
- (EFI_SOFTWARE_DXE_CORE | EFI_SW_PC_INIT_END),
- &DriverEntry->ImageHandle,
- sizeof (DriverEntry->ImageHandle)
- );
- }
-
- ReturnStatus = EFI_SUCCESS;
- }
-
- //
- // Now DXE Dispatcher finished one round of dispatch, signal an event group
- // so that SMM Dispatcher get chance to dispatch SMM Drivers which depend
- // on UEFI protocols
- //
- if (!EFI_ERROR (ReturnStatus)) {
- CoreSignalEvent (DxeDispatchEvent);
- }
-
- //
- // Search DriverList for items to place on Scheduled Queue
- //
- ReadyToRun = FALSE;
- for (Link = mDiscoveredList.ForwardLink; Link != &mDiscoveredList; Link = Link->ForwardLink) {
- DriverEntry = CR (Link, EFI_CORE_DRIVER_ENTRY, Link, EFI_CORE_DRIVER_ENTRY_SIGNATURE);
-
- if (DriverEntry->DepexProtocolError) {
- //
- // If Section Extraction Protocol did not let the Depex be read before retry the read
- //
- Status = CoreGetDepexSectionAndPreProccess (DriverEntry);
- }
-
- if (DriverEntry->Dependent) {
- if (CoreIsSchedulable (DriverEntry)) {
- CoreInsertOnScheduledQueueWhileProcessingBeforeAndAfter (DriverEntry);
- ReadyToRun = TRUE;
- }
- } else {
- if (DriverEntry->Unrequested) {
- DEBUG ((DEBUG_DISPATCH, "Evaluate DXE DEPEX for FFS(%g)\n", &DriverEntry->FileName));
- DEBUG ((DEBUG_DISPATCH, " SOR = Not Requested\n"));
- DEBUG ((DEBUG_DISPATCH, " RESULT = FALSE\n"));
- }
- }
- }
- } while (ReadyToRun);
-
- //
- // Close DXE dispatch Event
- //
- CoreCloseEvent (DxeDispatchEvent);
-
- gDispatcherRunning = FALSE;
-
- PERF_FUNCTION_END ();
-
- return ReturnStatus;
-}
-
-/**
- Insert InsertedDriverEntry onto the mScheduledQueue. To do this you
- must add any driver with a before dependency on InsertedDriverEntry first.
- You do this by recursively calling this routine. After all the Befores are
- processed you can add InsertedDriverEntry to the mScheduledQueue.
- Then you can add any driver with an After dependency on InsertedDriverEntry
- by recursively calling this routine.
-
- @param InsertedDriverEntry The driver to insert on the ScheduledLink Queue
-
-**/
-VOID
-CoreInsertOnScheduledQueueWhileProcessingBeforeAndAfter (
- IN EFI_CORE_DRIVER_ENTRY *InsertedDriverEntry
- )
-{
- LIST_ENTRY *Link;
- EFI_CORE_DRIVER_ENTRY *DriverEntry;
-
- //
- // Process Before Dependency
- //
- for (Link = mDiscoveredList.ForwardLink; Link != &mDiscoveredList; Link = Link->ForwardLink) {
- DriverEntry = CR (Link, EFI_CORE_DRIVER_ENTRY, Link, EFI_CORE_DRIVER_ENTRY_SIGNATURE);
- if (DriverEntry->Before && DriverEntry->Dependent && (DriverEntry != InsertedDriverEntry)) {
- DEBUG ((DEBUG_DISPATCH, "Evaluate DXE DEPEX for FFS(%g)\n", &DriverEntry->FileName));
- DEBUG ((DEBUG_DISPATCH, " BEFORE FFS(%g) = ", &DriverEntry->BeforeAfterGuid));
- if (CompareGuid (&InsertedDriverEntry->FileName, &DriverEntry->BeforeAfterGuid)) {
- //
- // Recursively process BEFORE
- //
- DEBUG ((DEBUG_DISPATCH, "TRUE\n END\n RESULT = TRUE\n"));
- CoreInsertOnScheduledQueueWhileProcessingBeforeAndAfter (DriverEntry);
- } else {
- DEBUG ((DEBUG_DISPATCH, "FALSE\n END\n RESULT = FALSE\n"));
- }
- }
- }
-
- //
- // Convert driver from Dependent to Scheduled state
- //
- CoreAcquireDispatcherLock ();
-
- InsertedDriverEntry->Dependent = FALSE;
- InsertedDriverEntry->Scheduled = TRUE;
- InsertTailList (&mScheduledQueue, &InsertedDriverEntry->ScheduledLink);
-
- CoreReleaseDispatcherLock ();
-
- //
- // Process After Dependency
- //
- for (Link = mDiscoveredList.ForwardLink; Link != &mDiscoveredList; Link = Link->ForwardLink) {
- DriverEntry = CR (Link, EFI_CORE_DRIVER_ENTRY, Link, EFI_CORE_DRIVER_ENTRY_SIGNATURE);
- if (DriverEntry->After && DriverEntry->Dependent && (DriverEntry != InsertedDriverEntry)) {
- DEBUG ((DEBUG_DISPATCH, "Evaluate DXE DEPEX for FFS(%g)\n", &DriverEntry->FileName));
- DEBUG ((DEBUG_DISPATCH, " AFTER FFS(%g) = ", &DriverEntry->BeforeAfterGuid));
- if (CompareGuid (&InsertedDriverEntry->FileName, &DriverEntry->BeforeAfterGuid)) {
- //
- // Recursively process AFTER
- //
- DEBUG ((DEBUG_DISPATCH, "TRUE\n END\n RESULT = TRUE\n"));
- CoreInsertOnScheduledQueueWhileProcessingBeforeAndAfter (DriverEntry);
- } else {
- DEBUG ((DEBUG_DISPATCH, "FALSE\n END\n RESULT = FALSE\n"));
- }
- }
- }
-}
-
-/**
- Return TRUE if the Fv has been processed, FALSE if not.
-
- @param FvHandle The handle of a FV that's being tested
-
- @retval TRUE Fv protocol on FvHandle has been processed
- @retval FALSE Fv protocol on FvHandle has not yet been processed
-
-**/
-BOOLEAN
-FvHasBeenProcessed (
- IN EFI_HANDLE FvHandle
- )
-{
- LIST_ENTRY *Link;
- KNOWN_HANDLE *KnownHandle;
-
- for (Link = mFvHandleList.ForwardLink; Link != &mFvHandleList; Link = Link->ForwardLink) {
- KnownHandle = CR (Link, KNOWN_HANDLE, Link, KNOWN_HANDLE_SIGNATURE);
- if (KnownHandle->Handle == FvHandle) {
- return TRUE;
- }
- }
-
- return FALSE;
-}
-
-/**
- Remember that Fv protocol on FvHandle has had it's drivers placed on the
- mDiscoveredList. This fucntion adds entries on the mFvHandleList if new
- entry is different from one in mFvHandleList by checking FvImage Guid.
- Items are never removed/freed from the mFvHandleList.
-
- @param FvHandle The handle of a FV that has been processed
-
- @return A point to new added FvHandle entry. If FvHandle with the same FvImage guid
- has been added, NULL will return.
-
-**/
-KNOWN_HANDLE *
-FvIsBeingProcessed (
- IN EFI_HANDLE FvHandle
- )
-{
- EFI_STATUS Status;
- EFI_GUID FvNameGuid;
- BOOLEAN FvNameGuidIsFound;
- UINT32 ExtHeaderOffset;
- EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb;
- EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader;
- EFI_FV_BLOCK_MAP_ENTRY *BlockMap;
- UINTN LbaOffset;
- UINTN Index;
- EFI_LBA LbaIndex;
- LIST_ENTRY *Link;
- KNOWN_HANDLE *KnownHandle;
-
- FwVolHeader = NULL;
-
- //
- // Get the FirmwareVolumeBlock protocol on that handle
- //
- FvNameGuidIsFound = FALSE;
- Status = CoreHandleProtocol (FvHandle, &gEfiFirmwareVolumeBlockProtocolGuid, (VOID **)&Fvb);
- if (!EFI_ERROR (Status)) {
- //
- // Get the full FV header based on FVB protocol.
- //
- ASSERT (Fvb != NULL);
- Status = GetFwVolHeader (Fvb, &FwVolHeader);
- if (!EFI_ERROR (Status)) {
- ASSERT (FwVolHeader != NULL);
- if (VerifyFvHeaderChecksum (FwVolHeader) && (FwVolHeader->ExtHeaderOffset != 0)) {
- ExtHeaderOffset = (UINT32)FwVolHeader->ExtHeaderOffset;
- BlockMap = FwVolHeader->BlockMap;
- LbaIndex = 0;
- LbaOffset = 0;
- //
- // Find LbaIndex and LbaOffset for FV extension header based on BlockMap.
- //
- while ((BlockMap->NumBlocks != 0) || (BlockMap->Length != 0)) {
- for (Index = 0; Index < BlockMap->NumBlocks && ExtHeaderOffset >= BlockMap->Length; Index++) {
- ExtHeaderOffset -= BlockMap->Length;
- LbaIndex++;
- }
-
- //
- // Check whether FvExtHeader is crossing the multi block range.
- //
- if (Index < BlockMap->NumBlocks) {
- LbaOffset = ExtHeaderOffset;
- break;
- }
-
- BlockMap++;
- }
-
- //
- // Read FvNameGuid from FV extension header.
- //
- Status = ReadFvbData (Fvb, &LbaIndex, &LbaOffset, sizeof (FvNameGuid), (UINT8 *)&FvNameGuid);
- if (!EFI_ERROR (Status)) {
- FvNameGuidIsFound = TRUE;
- }
- }
-
- CoreFreePool (FwVolHeader);
- }
- }
-
- if (FvNameGuidIsFound) {
- //
- // Check whether the FV image with the found FvNameGuid has been processed.
- //
- for (Link = mFvHandleList.ForwardLink; Link != &mFvHandleList; Link = Link->ForwardLink) {
- KnownHandle = CR (Link, KNOWN_HANDLE, Link, KNOWN_HANDLE_SIGNATURE);
- if (CompareGuid (&FvNameGuid, &KnownHandle->FvNameGuid)) {
- DEBUG ((DEBUG_ERROR, "FvImage on FvHandle %p and %p has the same FvNameGuid %g.\n", FvHandle, KnownHandle->Handle, &FvNameGuid));
- return NULL;
- }
- }
- }
-
- KnownHandle = AllocateZeroPool (sizeof (KNOWN_HANDLE));
- ASSERT (KnownHandle != NULL);
-
- KnownHandle->Signature = KNOWN_HANDLE_SIGNATURE;
- KnownHandle->Handle = FvHandle;
- if (FvNameGuidIsFound) {
- CopyGuid (&KnownHandle->FvNameGuid, &FvNameGuid);
- }
-
- InsertTailList (&mFvHandleList, &KnownHandle->Link);
- return KnownHandle;
-}
-
-/**
- Convert FvHandle and DriverName into an EFI device path
-
- @param Fv Fv protocol, needed to read Depex info out of
- FLASH.
- @param FvHandle Handle for Fv, needed in the
- EFI_CORE_DRIVER_ENTRY so that the PE image can be
- read out of the FV at a later time.
- @param DriverName Name of driver to add to mDiscoveredList.
-
- @return Pointer to device path constructed from FvHandle and DriverName
-
-**/
-EFI_DEVICE_PATH_PROTOCOL *
-CoreFvToDevicePath (
- IN EFI_FIRMWARE_VOLUME2_PROTOCOL *Fv,
- IN EFI_HANDLE FvHandle,
- IN EFI_GUID *DriverName
- )
-{
- EFI_STATUS Status;
- EFI_DEVICE_PATH_PROTOCOL *FvDevicePath;
- EFI_DEVICE_PATH_PROTOCOL *FileNameDevicePath;
-
- //
- // Remember the device path of the FV
- //
- Status = CoreHandleProtocol (FvHandle, &gEfiDevicePathProtocolGuid, (VOID **)&FvDevicePath);
- if (EFI_ERROR (Status)) {
- FileNameDevicePath = NULL;
- } else {
- //
- // Build a device path to the file in the FV to pass into gBS->LoadImage
- //
- EfiInitializeFwVolDevicepathNode (&mFvDevicePath.File, DriverName);
- SetDevicePathEndNode (&mFvDevicePath.End);
-
- FileNameDevicePath = AppendDevicePath (
- FvDevicePath,
- (EFI_DEVICE_PATH_PROTOCOL *)&mFvDevicePath
- );
- }
-
- return FileNameDevicePath;
-}
-
-/**
- Add an entry to the mDiscoveredList. Allocate memory to store the DriverEntry,
- and initilize any state variables. Read the Depex from the FV and store it
- in DriverEntry. Pre-process the Depex to set the SOR, Before and After state.
- The Discovered list is never free'ed and contains booleans that represent the
- other possible DXE driver states.
-
- @param Fv Fv protocol, needed to read Depex info out of
- FLASH.
- @param FvHandle Handle for Fv, needed in the
- EFI_CORE_DRIVER_ENTRY so that the PE image can be
- read out of the FV at a later time.
- @param DriverName Name of driver to add to mDiscoveredList.
- @param Type Fv File Type of file to add to mDiscoveredList.
-
- @retval EFI_SUCCESS If driver was added to the mDiscoveredList.
- @retval EFI_ALREADY_STARTED The driver has already been started. Only one
- DriverName may be active in the system at any one
- time.
-
-**/
-EFI_STATUS
-CoreAddToDriverList (
- IN EFI_FIRMWARE_VOLUME2_PROTOCOL *Fv,
- IN EFI_HANDLE FvHandle,
- IN EFI_GUID *DriverName,
- IN EFI_FV_FILETYPE Type
- )
-{
- EFI_CORE_DRIVER_ENTRY *DriverEntry;
-
- //
- // Create the Driver Entry for the list. ZeroPool initializes lots of variables to
- // NULL or FALSE.
- //
- DriverEntry = AllocateZeroPool (sizeof (EFI_CORE_DRIVER_ENTRY));
- ASSERT (DriverEntry != NULL);
- if (Type == EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE) {
- DriverEntry->IsFvImage = TRUE;
- }
-
- DriverEntry->Signature = EFI_CORE_DRIVER_ENTRY_SIGNATURE;
- CopyGuid (&DriverEntry->FileName, DriverName);
- DriverEntry->FvHandle = FvHandle;
- DriverEntry->Fv = Fv;
- DriverEntry->FvFileDevicePath = CoreFvToDevicePath (Fv, FvHandle, DriverName);
-
- CoreGetDepexSectionAndPreProccess (DriverEntry);
-
- CoreAcquireDispatcherLock ();
-
- InsertTailList (&mDiscoveredList, &DriverEntry->Link);
-
- CoreReleaseDispatcherLock ();
-
- return EFI_SUCCESS;
-}
-
-/**
- Check if a FV Image type file (EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE) is
- described by a EFI_HOB_FIRMWARE_VOLUME2 Hob.
-
- @param FvNameGuid The FV image guid specified.
- @param DriverName The driver guid specified.
-
- @retval TRUE This file is found in a EFI_HOB_FIRMWARE_VOLUME2
- Hob.
- @retval FALSE Not found.
-
-**/
-BOOLEAN
-FvFoundInHobFv2 (
- IN CONST EFI_GUID *FvNameGuid,
- IN CONST EFI_GUID *DriverName
- )
-{
- EFI_PEI_HOB_POINTERS HobFv2;
-
- HobFv2.Raw = GetHobList ();
-
- while ((HobFv2.Raw = GetNextHob (EFI_HOB_TYPE_FV2, HobFv2.Raw)) != NULL) {
- //
- // Compare parent FvNameGuid and FileGuid both.
- //
- if (CompareGuid (DriverName, &HobFv2.FirmwareVolume2->FileName) &&
- CompareGuid (FvNameGuid, &HobFv2.FirmwareVolume2->FvName))
- {
- return TRUE;
- }
-
- HobFv2.Raw = GET_NEXT_HOB (HobFv2);
- }
-
- return FALSE;
-}
-
-/**
- Find USED_SIZE FV_EXT_TYPE entry in FV extension header and get the FV used size.
-
- @param[in] FvHeader Pointer to FV header.
- @param[out] FvUsedSize Pointer to FV used size returned,
- only valid if USED_SIZE FV_EXT_TYPE entry is found.
- @param[out] EraseByte Pointer to erase byte returned,
- only valid if USED_SIZE FV_EXT_TYPE entry is found.
-
- @retval TRUE USED_SIZE FV_EXT_TYPE entry is found,
- FV used size and erase byte are returned.
- @retval FALSE No USED_SIZE FV_EXT_TYPE entry found.
-
-**/
-BOOLEAN
-GetFvUsedSize (
- IN EFI_FIRMWARE_VOLUME_HEADER *FvHeader,
- OUT UINT32 *FvUsedSize,
- OUT UINT8 *EraseByte
- )
-{
- UINT16 ExtHeaderOffset;
- EFI_FIRMWARE_VOLUME_EXT_HEADER *ExtHeader;
- EFI_FIRMWARE_VOLUME_EXT_ENTRY *ExtEntryList;
- EFI_FIRMWARE_VOLUME_EXT_ENTRY_USED_SIZE_TYPE *ExtEntryUsedSize;
-
- ExtHeaderOffset = ReadUnaligned16 (&FvHeader->ExtHeaderOffset);
- if (ExtHeaderOffset != 0) {
- ExtHeader = (EFI_FIRMWARE_VOLUME_EXT_HEADER *)((UINT8 *)FvHeader + ExtHeaderOffset);
- ExtEntryList = (EFI_FIRMWARE_VOLUME_EXT_ENTRY *)(ExtHeader + 1);
- while ((UINTN)ExtEntryList < ((UINTN)ExtHeader + ReadUnaligned32 (&ExtHeader->ExtHeaderSize))) {
- if (ReadUnaligned16 (&ExtEntryList->ExtEntryType) == EFI_FV_EXT_TYPE_USED_SIZE_TYPE) {
- //
- // USED_SIZE FV_EXT_TYPE entry is found.
- //
- ExtEntryUsedSize = (EFI_FIRMWARE_VOLUME_EXT_ENTRY_USED_SIZE_TYPE *)ExtEntryList;
- *FvUsedSize = ReadUnaligned32 (&ExtEntryUsedSize->UsedSize);
- if ((ReadUnaligned32 (&FvHeader->Attributes) & EFI_FVB2_ERASE_POLARITY) != 0) {
- *EraseByte = 0xFF;
- } else {
- *EraseByte = 0;
- }
-
- DEBUG ((
- DEBUG_INFO,
- "FV at 0x%x has 0x%x used size, and erase byte is 0x%02x\n",
- FvHeader,
- *FvUsedSize,
- *EraseByte
- ));
- return TRUE;
- }
-
- ExtEntryList = (EFI_FIRMWARE_VOLUME_EXT_ENTRY *)
- ((UINT8 *)ExtEntryList + ReadUnaligned16 (&ExtEntryList->ExtEntrySize));
- }
- }
-
- //
- // No USED_SIZE FV_EXT_TYPE entry found.
- //
- return FALSE;
-}
-
-/**
- Get Fv image(s) from the FV through file name, and produce FVB protocol for every Fv image(s).
-
- @param Fv The FIRMWARE_VOLUME protocol installed on the FV.
- @param FvHandle The handle which FVB protocol installed on.
- @param FileName The file name guid specified.
-
- @retval EFI_OUT_OF_RESOURCES No enough memory or other resource.
- @retval EFI_SUCCESS Function successfully returned.
-
-**/
-EFI_STATUS
-CoreProcessFvImageFile (
- IN EFI_FIRMWARE_VOLUME2_PROTOCOL *Fv,
- IN EFI_HANDLE FvHandle,
- IN EFI_GUID *FileName
- )
-{
- EFI_STATUS Status;
- EFI_SECTION_TYPE SectionType;
- UINT32 AuthenticationStatus;
- VOID *Buffer;
- VOID *AlignedBuffer;
- UINTN BufferSize;
- EFI_FIRMWARE_VOLUME_HEADER *FvHeader;
- UINT32 FvAlignment;
- EFI_DEVICE_PATH_PROTOCOL *FvFileDevicePath;
- UINT32 FvUsedSize;
- UINT8 EraseByte;
- UINTN Index;
-
- //
- // Read firmware volume section(s)
- //
- SectionType = EFI_SECTION_FIRMWARE_VOLUME_IMAGE;
-
- Index = 0;
- do {
- FvHeader = NULL;
- FvAlignment = 0;
- Buffer = NULL;
- BufferSize = 0;
- AlignedBuffer = NULL;
- Status = Fv->ReadSection (
- Fv,
- FileName,
- SectionType,
- Index,
- &Buffer,
- &BufferSize,
- &AuthenticationStatus
- );
- if (!EFI_ERROR (Status)) {
- //
- // Evaluate the authentication status of the Firmware Volume through
- // Security Architectural Protocol
- //
- if (gSecurity != NULL) {
- FvFileDevicePath = CoreFvToDevicePath (Fv, FvHandle, FileName);
- Status = gSecurity->FileAuthenticationState (
- gSecurity,
- AuthenticationStatus,
- FvFileDevicePath
- );
- if (FvFileDevicePath != NULL) {
- FreePool (FvFileDevicePath);
- }
-
- if (Status != EFI_SUCCESS) {
- //
- // Security check failed. The firmware volume should not be used for any purpose.
- //
- if (Buffer != NULL) {
- FreePool (Buffer);
- }
-
- break;
- }
- }
-
- //
- // FvImage should be at its required alignment.
- //
- FvHeader = (EFI_FIRMWARE_VOLUME_HEADER *)Buffer;
- //
- // If EFI_FVB2_WEAK_ALIGNMENT is set in the volume header then the first byte of the volume
- // can be aligned on any power-of-two boundary. A weakly aligned volume can not be moved from
- // its initial linked location and maintain its alignment.
- //
- if ((ReadUnaligned32 (&FvHeader->Attributes) & EFI_FVB2_WEAK_ALIGNMENT) != EFI_FVB2_WEAK_ALIGNMENT) {
- //
- // Get FvHeader alignment
- //
- FvAlignment = 1 << ((ReadUnaligned32 (&FvHeader->Attributes) & EFI_FVB2_ALIGNMENT) >> 16);
- //
- // FvAlignment must be greater than or equal to 8 bytes of the minimum FFS alignment value.
- //
- if (FvAlignment < 8) {
- FvAlignment = 8;
- }
-
- DEBUG ((
- DEBUG_INFO,
- "%a() FV at 0x%x, FvAlignment required is 0x%x\n",
- __func__,
- FvHeader,
- FvAlignment
- ));
-
- //
- // Check FvImage alignment.
- //
- if ((UINTN)FvHeader % FvAlignment != 0) {
- //
- // Allocate the aligned buffer for the FvImage.
- //
- AlignedBuffer = AllocateAlignedPages (EFI_SIZE_TO_PAGES (BufferSize), (UINTN)FvAlignment);
- if (AlignedBuffer == NULL) {
- FreePool (Buffer);
- Status = EFI_OUT_OF_RESOURCES;
- break;
- } else {
- //
- // Move FvImage into the aligned buffer and release the original buffer.
- //
- if (GetFvUsedSize (FvHeader, &FvUsedSize, &EraseByte)) {
- //
- // Copy the used bytes and fill the rest with the erase value.
- //
- CopyMem (AlignedBuffer, FvHeader, (UINTN)FvUsedSize);
- SetMem (
- (UINT8 *)AlignedBuffer + FvUsedSize,
- (UINTN)(BufferSize - FvUsedSize),
- EraseByte
- );
- } else {
- CopyMem (AlignedBuffer, Buffer, BufferSize);
- }
-
- FvHeader = (EFI_FIRMWARE_VOLUME_HEADER *)AlignedBuffer;
- FreePool (Buffer);
- Buffer = NULL;
- }
- }
- }
-
- //
- // Produce a FVB protocol for the file
- //
- Status = ProduceFVBProtocolOnBuffer (
- (EFI_PHYSICAL_ADDRESS)(UINTN)FvHeader,
- (UINT64)BufferSize,
- FvHandle,
- AuthenticationStatus,
- NULL
- );
- }
-
- if (EFI_ERROR (Status)) {
- //
- // ReadSection or Produce FVB failed, Free data buffer
- //
- if (Buffer != NULL) {
- FreePool (Buffer);
- }
-
- if (AlignedBuffer != NULL) {
- FreeAlignedPages (AlignedBuffer, EFI_SIZE_TO_PAGES (BufferSize));
- }
-
- break;
- } else {
- Index++;
- }
- } while (TRUE);
-
- if (Index > 0) {
- //
- // At least one FvImage has been processed successfully.
- //
- return EFI_SUCCESS;
- } else {
- return Status;
- }
-}
-
-/**
- Event notification that is fired every time a FV dispatch protocol is added.
- More than one protocol may have been added when this event is fired, so you
- must loop on CoreLocateHandle () to see how many protocols were added and
- do the following to each FV:
- If the Fv has already been processed, skip it. If the Fv has not been
- processed then mark it as being processed, as we are about to process it.
- Read the Fv and add any driver in the Fv to the mDiscoveredList.The
- mDiscoveredList is never free'ed and contains variables that define
- the other states the DXE driver transitions to..
- While you are at it read the A Priori file into memory.
- Place drivers in the A Priori list onto the mScheduledQueue.
-
- @param Event The Event that is being processed, not used.
- @param Context Event Context, not used.
-
-**/
-VOID
-EFIAPI
-CoreFwVolEventProtocolNotify (
- IN EFI_EVENT Event,
- IN VOID *Context
- )
-{
- EFI_STATUS Status;
- EFI_STATUS GetNextFileStatus;
- EFI_FIRMWARE_VOLUME2_PROTOCOL *Fv;
- EFI_DEVICE_PATH_PROTOCOL *FvDevicePath;
- EFI_HANDLE FvHandle;
- UINTN BufferSize;
- EFI_GUID NameGuid;
- UINTN Key;
- EFI_FV_FILETYPE Type;
- EFI_FV_FILE_ATTRIBUTES Attributes;
- UINTN Size;
- EFI_CORE_DRIVER_ENTRY *DriverEntry;
- EFI_GUID *AprioriFile;
- UINTN AprioriEntryCount;
- UINTN Index;
- LIST_ENTRY *Link;
- UINT32 AuthenticationStatus;
- UINTN SizeOfBuffer;
- VOID *DepexBuffer;
- KNOWN_HANDLE *KnownHandle;
-
- FvHandle = NULL;
-
- while (TRUE) {
- BufferSize = sizeof (EFI_HANDLE);
- Status = CoreLocateHandle (
- ByRegisterNotify,
- NULL,
- mFwVolEventRegistration,
- &BufferSize,
- &FvHandle
- );
- if (EFI_ERROR (Status)) {
- //
- // If no more notification events exit
- //
- return;
- }
-
- if (FvHasBeenProcessed (FvHandle)) {
- //
- // This Fv has already been processed so lets skip it!
- //
- continue;
- }
-
- //
- // Since we are about to process this Fv mark it as processed.
- //
- KnownHandle = FvIsBeingProcessed (FvHandle);
- if (KnownHandle == NULL) {
- //
- // The FV with the same FV name guid has already been processed.
- // So lets skip it!
- //
- continue;
- }
-
- Status = CoreHandleProtocol (FvHandle, &gEfiFirmwareVolume2ProtocolGuid, (VOID **)&Fv);
- if (EFI_ERROR (Status) || (Fv == NULL)) {
- //
- // FvHandle must have Firmware Volume2 protocol thus we should never get here.
- //
- ASSERT (FALSE);
- continue;
- }
-
- Status = CoreHandleProtocol (FvHandle, &gEfiDevicePathProtocolGuid, (VOID **)&FvDevicePath);
- if (EFI_ERROR (Status)) {
- //
- // The Firmware volume doesn't have device path, can't be dispatched.
- //
- continue;
- }
-
- //
- // Discover Drivers in FV and add them to the Discovered Driver List.
- // Process EFI_FV_FILETYPE_DRIVER type and then EFI_FV_FILETYPE_COMBINED_PEIM_DRIVER
- // EFI_FV_FILETYPE_DXE_CORE is processed to produce a Loaded Image protocol for the core
- // EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE is processed to create a Fvb
- //
- for (Index = 0; Index < sizeof (mDxeFileTypes) / sizeof (EFI_FV_FILETYPE); Index++) {
- //
- // Initialize the search key
- //
- Key = 0;
- do {
- Type = mDxeFileTypes[Index];
- GetNextFileStatus = Fv->GetNextFile (
- Fv,
- &Key,
- &Type,
- &NameGuid,
- &Attributes,
- &Size
- );
- if (!EFI_ERROR (GetNextFileStatus)) {
- if (Type == EFI_FV_FILETYPE_DXE_CORE) {
- //
- // If this is the DXE core fill in it's DevicePath & DeviceHandle
- //
- if (gDxeCoreLoadedImage->FilePath == NULL) {
- if (CompareGuid (&NameGuid, gDxeCoreFileName)) {
- //
- // Maybe One specail Fv cantains only one DXE_CORE module, so its device path must
- // be initialized completely.
- //
- EfiInitializeFwVolDevicepathNode (&mFvDevicePath.File, &NameGuid);
- SetDevicePathEndNode (&mFvDevicePath.End);
-
- gDxeCoreLoadedImage->FilePath = DuplicateDevicePath (
- (EFI_DEVICE_PATH_PROTOCOL *)&mFvDevicePath
- );
- gDxeCoreLoadedImage->DeviceHandle = FvHandle;
- }
- }
- } else if (Type == EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE) {
- //
- // Check if this EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE file has already
- // been extracted.
- //
- if (FvFoundInHobFv2 (&KnownHandle->FvNameGuid, &NameGuid)) {
- continue;
- }
-
- //
- // Check if this EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE file has SMM depex section.
- //
- DepexBuffer = NULL;
- SizeOfBuffer = 0;
- Status = Fv->ReadSection (
- Fv,
- &NameGuid,
- EFI_SECTION_SMM_DEPEX,
- 0,
- &DepexBuffer,
- &SizeOfBuffer,
- &AuthenticationStatus
- );
- if (!EFI_ERROR (Status)) {
- //
- // If SMM depex section is found, this FV image is invalid to be supported.
- // ASSERT FALSE to report this FV image.
- //
- FreePool (DepexBuffer);
- ASSERT (FALSE);
- }
-
- //
- // Check if this EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE file has DXE depex section.
- //
- DepexBuffer = NULL;
- SizeOfBuffer = 0;
- Status = Fv->ReadSection (
- Fv,
- &NameGuid,
- EFI_SECTION_DXE_DEPEX,
- 0,
- &DepexBuffer,
- &SizeOfBuffer,
- &AuthenticationStatus
- );
- if (EFI_ERROR (Status)) {
- //
- // If no depex section, produce a firmware volume block protocol for it so it gets dispatched from.
- //
- CoreProcessFvImageFile (Fv, FvHandle, &NameGuid);
- } else {
- //
- // If depex section is found, this FV image will be dispatched until its depex is evaluated to TRUE.
- //
- FreePool (DepexBuffer);
- CoreAddToDriverList (Fv, FvHandle, &NameGuid, Type);
- }
- } else {
- //
- // Transition driver from Undiscovered to Discovered state
- //
- CoreAddToDriverList (Fv, FvHandle, &NameGuid, Type);
- }
- }
- } while (!EFI_ERROR (GetNextFileStatus));
- }
-
- //
- // Read the array of GUIDs from the Apriori file if it is present in the firmware volume
- //
- AprioriFile = NULL;
- Status = Fv->ReadSection (
- Fv,
- &gAprioriGuid,
- EFI_SECTION_RAW,
- 0,
- (VOID **)&AprioriFile,
- &SizeOfBuffer,
- &AuthenticationStatus
- );
- if (!EFI_ERROR (Status)) {
- AprioriEntryCount = SizeOfBuffer / sizeof (EFI_GUID);
- } else {
- AprioriEntryCount = 0;
- }
-
- //
- // Put drivers on Apriori List on the Scheduled queue. The Discovered List includes
- // drivers not in the current FV and these must be skipped since the a priori list
- // is only valid for the FV that it resided in.
- //
-
- for (Index = 0; Index < AprioriEntryCount; Index++) {
- for (Link = mDiscoveredList.ForwardLink; Link != &mDiscoveredList; Link = Link->ForwardLink) {
- DriverEntry = CR (Link, EFI_CORE_DRIVER_ENTRY, Link, EFI_CORE_DRIVER_ENTRY_SIGNATURE);
- if (CompareGuid (&DriverEntry->FileName, &AprioriFile[Index]) &&
- (FvHandle == DriverEntry->FvHandle))
- {
- CoreAcquireDispatcherLock ();
- DriverEntry->Dependent = FALSE;
- DriverEntry->Scheduled = TRUE;
- InsertTailList (&mScheduledQueue, &DriverEntry->ScheduledLink);
- CoreReleaseDispatcherLock ();
- DEBUG ((DEBUG_DISPATCH, "Evaluate DXE DEPEX for FFS(%g)\n", &DriverEntry->FileName));
- DEBUG ((DEBUG_DISPATCH, " RESULT = TRUE (Apriori)\n"));
- break;
- }
- }
- }
-
- //
- // Free data allocated by Fv->ReadSection ()
- //
- CoreFreePool (AprioriFile);
- }
-}
-
-/**
- Initialize the dispatcher. Initialize the notification function that runs when
- an FV2 protocol is added to the system.
-
-**/
-VOID
-CoreInitializeDispatcher (
- VOID
- )
-{
- PERF_FUNCTION_BEGIN ();
-
- mFwVolEvent = EfiCreateProtocolNotifyEvent (
- &gEfiFirmwareVolume2ProtocolGuid,
- TPL_CALLBACK,
- CoreFwVolEventProtocolNotify,
- NULL,
- &mFwVolEventRegistration
- );
-
- PERF_FUNCTION_END ();
-}
-
-//
-// Function only used in debug builds
-//
-
-/**
- Traverse the discovered list for any drivers that were discovered but not loaded
- because the dependency experessions evaluated to false.
-
-**/
-VOID
-CoreDisplayDiscoveredNotDispatched (
- VOID
- )
-{
- LIST_ENTRY *Link;
- EFI_CORE_DRIVER_ENTRY *DriverEntry;
-
- for (Link = mDiscoveredList.ForwardLink; Link != &mDiscoveredList; Link = Link->ForwardLink) {
- DriverEntry = CR (Link, EFI_CORE_DRIVER_ENTRY, Link, EFI_CORE_DRIVER_ENTRY_SIGNATURE);
- if (DriverEntry->Dependent) {
- DEBUG ((DEBUG_LOAD, "Driver %g was discovered but not loaded!!\n", &DriverEntry->FileName));
- }
- }
-}
+/** @file
+ DXE Dispatcher.
+
+ Step #1 - When a FV protocol is added to the system every driver in the FV
+ is added to the mDiscoveredList. The SOR, Before, and After Depex are
+ pre-processed as drivers are added to the mDiscoveredList. If an Apriori
+ file exists in the FV those drivers are addeded to the
+ mScheduledQueue. The mFvHandleList is used to make sure a
+ FV is only processed once.
+
+ Step #2 - Dispatch. Remove driver from the mScheduledQueue and load and
+ start it. After mScheduledQueue is drained check the
+ mDiscoveredList to see if any item has a Depex that is ready to
+ be placed on the mScheduledQueue.
+
+ Step #3 - Adding to the mScheduledQueue requires that you process Before
+ and After dependencies. This is done recursively as the call to add
+ to the mScheduledQueue checks for Before and recursively adds
+ all Befores. It then addes the item that was passed in and then
+ processess the After dependecies by recursively calling the routine.
+
+ Dispatcher Rules:
+ The rules for the dispatcher are in chapter 10 of the DXE CIS. Figure 10-3
+ is the state diagram for the DXE dispatcher
+
+ Depex - Dependency Expresion.
+ SOR - Schedule On Request - Don't schedule if this bit is set.
+
+Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "DxeMain.h"
+
+//
+// The Driver List contains one copy of every driver that has been discovered.
+// Items are never removed from the driver list. List of EFI_CORE_DRIVER_ENTRY
+//
+LIST_ENTRY mDiscoveredList = INITIALIZE_LIST_HEAD_VARIABLE (mDiscoveredList);
+
+//
+// Queue of drivers that are ready to dispatch. This queue is a subset of the
+// mDiscoveredList.list of EFI_CORE_DRIVER_ENTRY.
+//
+LIST_ENTRY mScheduledQueue = INITIALIZE_LIST_HEAD_VARIABLE (mScheduledQueue);
+
+//
+// List of handles who's Fv's have been parsed and added to the mFwDriverList.
+//
+LIST_ENTRY mFvHandleList = INITIALIZE_LIST_HEAD_VARIABLE (mFvHandleList); // list of KNOWN_HANDLE
+
+//
+// Lock for mDiscoveredList, mScheduledQueue, gDispatcherRunning.
+//
+EFI_LOCK mDispatcherLock = EFI_INITIALIZE_LOCK_VARIABLE (TPL_HIGH_LEVEL);
+
+//
+// Flag for the DXE Dispacher. TRUE if dispatcher is execuing.
+//
+BOOLEAN gDispatcherRunning = FALSE;
+
+//
+// Module globals to manage the FwVol registration notification event
+//
+EFI_EVENT mFwVolEvent;
+VOID *mFwVolEventRegistration;
+
+//
+// List of file types supported by dispatcher
+//
+EFI_FV_FILETYPE mDxeFileTypes[] = {
+ EFI_FV_FILETYPE_DRIVER,
+ EFI_FV_FILETYPE_COMBINED_SMM_DXE,
+ EFI_FV_FILETYPE_COMBINED_PEIM_DRIVER,
+ EFI_FV_FILETYPE_DXE_CORE,
+ EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE
+};
+
+typedef struct {
+ MEDIA_FW_VOL_FILEPATH_DEVICE_PATH File;
+ EFI_DEVICE_PATH_PROTOCOL End;
+} FV_FILEPATH_DEVICE_PATH;
+
+FV_FILEPATH_DEVICE_PATH mFvDevicePath;
+
+//
+// Function Prototypes
+//
+
+/**
+ Insert InsertedDriverEntry onto the mScheduledQueue. To do this you
+ must add any driver with a before dependency on InsertedDriverEntry first.
+ You do this by recursively calling this routine. After all the Befores are
+ processed you can add InsertedDriverEntry to the mScheduledQueue.
+ Then you can add any driver with an After dependency on InsertedDriverEntry
+ by recursively calling this routine.
+
+ @param InsertedDriverEntry The driver to insert on the ScheduledLink Queue
+
+**/
+VOID
+CoreInsertOnScheduledQueueWhileProcessingBeforeAndAfter (
+ IN EFI_CORE_DRIVER_ENTRY *InsertedDriverEntry
+ );
+
+/**
+ Event notification that is fired every time a FV dispatch protocol is added.
+ More than one protocol may have been added when this event is fired, so you
+ must loop on CoreLocateHandle () to see how many protocols were added and
+ do the following to each FV:
+ If the Fv has already been processed, skip it. If the Fv has not been
+ processed then mark it as being processed, as we are about to process it.
+ Read the Fv and add any driver in the Fv to the mDiscoveredList.The
+ mDiscoveredList is never free'ed and contains variables that define
+ the other states the DXE driver transitions to..
+ While you are at it read the A Priori file into memory.
+ Place drivers in the A Priori list onto the mScheduledQueue.
+
+ @param Event The Event that is being processed, not used.
+ @param Context Event Context, not used.
+
+**/
+VOID
+EFIAPI
+CoreFwVolEventProtocolNotify (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ );
+
+/**
+ Convert FvHandle and DriverName into an EFI device path
+
+ @param Fv Fv protocol, needed to read Depex info out of
+ FLASH.
+ @param FvHandle Handle for Fv, needed in the
+ EFI_CORE_DRIVER_ENTRY so that the PE image can be
+ read out of the FV at a later time.
+ @param DriverName Name of driver to add to mDiscoveredList.
+
+ @return Pointer to device path constructed from FvHandle and DriverName
+
+**/
+EFI_DEVICE_PATH_PROTOCOL *
+CoreFvToDevicePath (
+ IN EFI_FIRMWARE_VOLUME2_PROTOCOL *Fv,
+ IN EFI_HANDLE FvHandle,
+ IN EFI_GUID *DriverName
+ );
+
+/**
+ Add an entry to the mDiscoveredList. Allocate memory to store the DriverEntry,
+ and initilize any state variables. Read the Depex from the FV and store it
+ in DriverEntry. Pre-process the Depex to set the SOR, Before and After state.
+ The Discovered list is never free'ed and contains booleans that represent the
+ other possible DXE driver states.
+
+ @param Fv Fv protocol, needed to read Depex info out of
+ FLASH.
+ @param FvHandle Handle for Fv, needed in the
+ EFI_CORE_DRIVER_ENTRY so that the PE image can be
+ read out of the FV at a later time.
+ @param DriverName Name of driver to add to mDiscoveredList.
+ @param Type Fv File Type of file to add to mDiscoveredList.
+
+ @retval EFI_SUCCESS If driver was added to the mDiscoveredList.
+ @retval EFI_ALREADY_STARTED The driver has already been started. Only one
+ DriverName may be active in the system at any one
+ time.
+
+**/
+EFI_STATUS
+CoreAddToDriverList (
+ IN EFI_FIRMWARE_VOLUME2_PROTOCOL *Fv,
+ IN EFI_HANDLE FvHandle,
+ IN EFI_GUID *DriverName,
+ IN EFI_FV_FILETYPE Type
+ );
+
+/**
+ Get Fv image(s) from the FV through file name, and produce FVB protocol for every Fv image(s).
+
+ @param Fv The FIRMWARE_VOLUME protocol installed on the FV.
+ @param FvHandle The handle which FVB protocol installed on.
+ @param FileName The file name guid specified.
+
+ @retval EFI_OUT_OF_RESOURCES No enough memory or other resource.
+ @retval EFI_SUCCESS Function successfully returned.
+
+**/
+EFI_STATUS
+CoreProcessFvImageFile (
+ IN EFI_FIRMWARE_VOLUME2_PROTOCOL *Fv,
+ IN EFI_HANDLE FvHandle,
+ IN EFI_GUID *FileName
+ );
+
+/**
+ Enter critical section by gaining lock on mDispatcherLock.
+
+**/
+VOID
+CoreAcquireDispatcherLock (
+ VOID
+ )
+{
+ CoreAcquireLock (&mDispatcherLock);
+}
+
+/**
+ Exit critical section by releasing lock on mDispatcherLock.
+
+**/
+VOID
+CoreReleaseDispatcherLock (
+ VOID
+ )
+{
+ CoreReleaseLock (&mDispatcherLock);
+}
+
+/**
+ Read Depex and pre-process the Depex for Before and After. If Section Extraction
+ protocol returns an error via ReadSection defer the reading of the Depex.
+
+ @param DriverEntry Driver to work on.
+
+ @retval EFI_SUCCESS Depex read and preprossesed
+ @retval EFI_PROTOCOL_ERROR The section extraction protocol returned an error
+ and Depex reading needs to be retried.
+ @retval Error DEPEX not found.
+
+**/
+EFI_STATUS
+CoreGetDepexSectionAndPreProccess (
+ IN EFI_CORE_DRIVER_ENTRY *DriverEntry
+ )
+{
+ EFI_STATUS Status;
+ EFI_SECTION_TYPE SectionType;
+ UINT32 AuthenticationStatus;
+ EFI_FIRMWARE_VOLUME2_PROTOCOL *Fv;
+
+ Fv = DriverEntry->Fv;
+
+ //
+ // Grab Depex info, it will never be free'ed.
+ //
+ SectionType = EFI_SECTION_DXE_DEPEX;
+ Status = Fv->ReadSection (
+ DriverEntry->Fv,
+ &DriverEntry->FileName,
+ SectionType,
+ 0,
+ &DriverEntry->Depex,
+ (UINTN *)&DriverEntry->DepexSize,
+ &AuthenticationStatus
+ );
+ if (EFI_ERROR (Status)) {
+ if (Status == EFI_PROTOCOL_ERROR) {
+ //
+ // The section extraction protocol failed so set protocol error flag
+ //
+ DriverEntry->DepexProtocolError = TRUE;
+ } else {
+ //
+ // If no Depex assume UEFI 2.0 driver model
+ //
+ DriverEntry->Depex = NULL;
+ DriverEntry->Dependent = TRUE;
+ DriverEntry->DepexProtocolError = FALSE;
+ }
+ } else {
+ //
+ // Set Before, After, and Unrequested state information based on Depex
+ // Driver will be put in Dependent or Unrequested state
+ //
+ CorePreProcessDepex (DriverEntry);
+ DriverEntry->DepexProtocolError = FALSE;
+ }
+
+ return Status;
+}
+
+/**
+ Check every driver and locate a matching one. If the driver is found, the Unrequested
+ state flag is cleared.
+
+ @param FirmwareVolumeHandle The handle of the Firmware Volume that contains
+ the firmware file specified by DriverName.
+ @param DriverName The Driver name to put in the Dependent state.
+
+ @retval EFI_SUCCESS The DriverName was found and it's SOR bit was
+ cleared
+ @retval EFI_NOT_FOUND The DriverName does not exist or it's SOR bit was
+ not set.
+
+**/
+EFI_STATUS
+EFIAPI
+CoreSchedule (
+ IN EFI_HANDLE FirmwareVolumeHandle,
+ IN EFI_GUID *DriverName
+ )
+{
+ LIST_ENTRY *Link;
+ EFI_CORE_DRIVER_ENTRY *DriverEntry;
+
+ //
+ // Check every driver
+ //
+ for (Link = mDiscoveredList.ForwardLink; Link != &mDiscoveredList; Link = Link->ForwardLink) {
+ DriverEntry = CR (Link, EFI_CORE_DRIVER_ENTRY, Link, EFI_CORE_DRIVER_ENTRY_SIGNATURE);
+ if ((DriverEntry->FvHandle == FirmwareVolumeHandle) &&
+ DriverEntry->Unrequested &&
+ CompareGuid (DriverName, &DriverEntry->FileName))
+ {
+ //
+ // Move the driver from the Unrequested to the Dependent state
+ //
+ CoreAcquireDispatcherLock ();
+ DriverEntry->Unrequested = FALSE;
+ DriverEntry->Dependent = TRUE;
+ CoreReleaseDispatcherLock ();
+
+ DEBUG ((DEBUG_DISPATCH, "Schedule FFS(%g) - EFI_SUCCESS\n", DriverName));
+
+ return EFI_SUCCESS;
+ }
+ }
+
+ DEBUG ((DEBUG_DISPATCH, "Schedule FFS(%g) - EFI_NOT_FOUND\n", DriverName));
+
+ return EFI_NOT_FOUND;
+}
+
+/**
+ Convert a driver from the Untrused back to the Scheduled state.
+
+ @param FirmwareVolumeHandle The handle of the Firmware Volume that contains
+ the firmware file specified by DriverName.
+ @param DriverName The Driver name to put in the Scheduled state
+
+ @retval EFI_SUCCESS The file was found in the untrusted state, and it
+ was promoted to the trusted state.
+ @retval EFI_NOT_FOUND The file was not found in the untrusted state.
+
+**/
+EFI_STATUS
+EFIAPI
+CoreTrust (
+ IN EFI_HANDLE FirmwareVolumeHandle,
+ IN EFI_GUID *DriverName
+ )
+{
+ LIST_ENTRY *Link;
+ EFI_CORE_DRIVER_ENTRY *DriverEntry;
+
+ //
+ // Check every driver
+ //
+ for (Link = mDiscoveredList.ForwardLink; Link != &mDiscoveredList; Link = Link->ForwardLink) {
+ DriverEntry = CR (Link, EFI_CORE_DRIVER_ENTRY, Link, EFI_CORE_DRIVER_ENTRY_SIGNATURE);
+ if ((DriverEntry->FvHandle == FirmwareVolumeHandle) &&
+ DriverEntry->Untrusted &&
+ CompareGuid (DriverName, &DriverEntry->FileName))
+ {
+ //
+ // Transition driver from Untrusted to Scheduled state.
+ //
+ CoreAcquireDispatcherLock ();
+ DriverEntry->Untrusted = FALSE;
+ DriverEntry->Scheduled = TRUE;
+ InsertTailList (&mScheduledQueue, &DriverEntry->ScheduledLink);
+ CoreReleaseDispatcherLock ();
+
+ return EFI_SUCCESS;
+ }
+ }
+
+ return EFI_NOT_FOUND;
+}
+
+/**
+ This is the main Dispatcher for DXE and it exits when there are no more
+ drivers to run. Drain the mScheduledQueue and load and start a PE
+ image for each driver. Search the mDiscoveredList to see if any driver can
+ be placed on the mScheduledQueue. If no drivers are placed on the
+ mScheduledQueue exit the function. On exit it is assumed the Bds()
+ will be called, and when the Bds() exits the Dispatcher will be called
+ again.
+
+ @retval EFI_ALREADY_STARTED The DXE Dispatcher is already running
+ @retval EFI_NOT_FOUND No DXE Drivers were dispatched
+ @retval EFI_SUCCESS One or more DXE Drivers were dispatched
+
+**/
+EFI_STATUS
+EFIAPI
+CoreDispatcher (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ EFI_STATUS ReturnStatus;
+ LIST_ENTRY *Link;
+ EFI_CORE_DRIVER_ENTRY *DriverEntry;
+ BOOLEAN ReadyToRun;
+ EFI_EVENT DxeDispatchEvent;
+
+ PERF_FUNCTION_BEGIN ();
+
+ if (gDispatcherRunning) {
+ //
+ // If the dispatcher is running don't let it be restarted.
+ //
+ return EFI_ALREADY_STARTED;
+ }
+
+ gDispatcherRunning = TRUE;
+
+ Status = CoreCreateEventEx (
+ EVT_NOTIFY_SIGNAL,
+ TPL_NOTIFY,
+ EfiEventEmptyFunction,
+ NULL,
+ &gEfiEventDxeDispatchGuid,
+ &DxeDispatchEvent
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ ReturnStatus = EFI_NOT_FOUND;
+ do {
+ //
+ // Drain the Scheduled Queue
+ //
+ while (!IsListEmpty (&mScheduledQueue)) {
+ DriverEntry = CR (
+ mScheduledQueue.ForwardLink,
+ EFI_CORE_DRIVER_ENTRY,
+ ScheduledLink,
+ EFI_CORE_DRIVER_ENTRY_SIGNATURE
+ );
+
+ //
+ // Load the DXE Driver image into memory. If the Driver was transitioned from
+ // Untrused to Scheduled it would have already been loaded so we may need to
+ // skip the LoadImage
+ //
+ if ((DriverEntry->ImageHandle == NULL) && !DriverEntry->IsFvImage) {
+ DEBUG ((DEBUG_INFO, "Loading driver %g\n", &DriverEntry->FileName));
+ Status = CoreLoadImage (
+ FALSE,
+ gDxeCoreImageHandle,
+ DriverEntry->FvFileDevicePath,
+ NULL,
+ 0,
+ &DriverEntry->ImageHandle
+ );
+
+ //
+ // Update the driver state to reflect that it's been loaded
+ //
+ if (EFI_ERROR (Status)) {
+ CoreAcquireDispatcherLock ();
+
+ if (Status == EFI_SECURITY_VIOLATION) {
+ //
+ // Take driver from Scheduled to Untrused state
+ //
+ DriverEntry->Untrusted = TRUE;
+ } else {
+ //
+ // The DXE Driver could not be loaded, and do not attempt to load or start it again.
+ // Take driver from Scheduled to Initialized.
+ //
+ // This case include the Never Trusted state if EFI_ACCESS_DENIED is returned
+ //
+ DriverEntry->Initialized = TRUE;
+ }
+
+ DriverEntry->Scheduled = FALSE;
+ RemoveEntryList (&DriverEntry->ScheduledLink);
+
+ CoreReleaseDispatcherLock ();
+
+ //
+ // If it's an error don't try the StartImage
+ //
+ continue;
+ }
+ }
+
+ CoreAcquireDispatcherLock ();
+
+ DriverEntry->Scheduled = FALSE;
+ DriverEntry->Initialized = TRUE;
+ RemoveEntryList (&DriverEntry->ScheduledLink);
+
+ CoreReleaseDispatcherLock ();
+
+ if (DriverEntry->IsFvImage) {
+ //
+ // Produce a firmware volume block protocol for FvImage so it gets dispatched from.
+ //
+ Status = CoreProcessFvImageFile (DriverEntry->Fv, DriverEntry->FvHandle, &DriverEntry->FileName);
+ } else {
+ REPORT_STATUS_CODE_WITH_EXTENDED_DATA (
+ EFI_PROGRESS_CODE,
+ (EFI_SOFTWARE_DXE_CORE | EFI_SW_PC_INIT_BEGIN),
+ &DriverEntry->ImageHandle,
+ sizeof (DriverEntry->ImageHandle)
+ );
+ ASSERT (DriverEntry->ImageHandle != NULL);
+
+ Status = CoreStartImage (DriverEntry->ImageHandle, NULL, NULL);
+
+ REPORT_STATUS_CODE_WITH_EXTENDED_DATA (
+ EFI_PROGRESS_CODE,
+ (EFI_SOFTWARE_DXE_CORE | EFI_SW_PC_INIT_END),
+ &DriverEntry->ImageHandle,
+ sizeof (DriverEntry->ImageHandle)
+ );
+ }
+
+ ReturnStatus = EFI_SUCCESS;
+ }
+
+ //
+ // Now DXE Dispatcher finished one round of dispatch, signal an event group
+ // so that SMM Dispatcher get chance to dispatch SMM Drivers which depend
+ // on UEFI protocols
+ //
+ if (!EFI_ERROR (ReturnStatus)) {
+ CoreSignalEvent (DxeDispatchEvent);
+ }
+
+ //
+ // Search DriverList for items to place on Scheduled Queue
+ //
+ ReadyToRun = FALSE;
+ for (Link = mDiscoveredList.ForwardLink; Link != &mDiscoveredList; Link = Link->ForwardLink) {
+ DriverEntry = CR (Link, EFI_CORE_DRIVER_ENTRY, Link, EFI_CORE_DRIVER_ENTRY_SIGNATURE);
+
+ if (DriverEntry->DepexProtocolError) {
+ //
+ // If Section Extraction Protocol did not let the Depex be read before retry the read
+ //
+ Status = CoreGetDepexSectionAndPreProccess (DriverEntry);
+ }
+
+ if (DriverEntry->Dependent) {
+ if (CoreIsSchedulable (DriverEntry)) {
+ CoreInsertOnScheduledQueueWhileProcessingBeforeAndAfter (DriverEntry);
+ ReadyToRun = TRUE;
+ }
+ } else {
+ if (DriverEntry->Unrequested) {
+ DEBUG ((DEBUG_DISPATCH, "Evaluate DXE DEPEX for FFS(%g)\n", &DriverEntry->FileName));
+ DEBUG ((DEBUG_DISPATCH, " SOR = Not Requested\n"));
+ DEBUG ((DEBUG_DISPATCH, " RESULT = FALSE\n"));
+ }
+ }
+ }
+ } while (ReadyToRun);
+
+ //
+ // Close DXE dispatch Event
+ //
+ CoreCloseEvent (DxeDispatchEvent);
+
+ gDispatcherRunning = FALSE;
+
+ PERF_FUNCTION_END ();
+
+ return ReturnStatus;
+}
+
+/**
+ Insert InsertedDriverEntry onto the mScheduledQueue. To do this you
+ must add any driver with a before dependency on InsertedDriverEntry first.
+ You do this by recursively calling this routine. After all the Befores are
+ processed you can add InsertedDriverEntry to the mScheduledQueue.
+ Then you can add any driver with an After dependency on InsertedDriverEntry
+ by recursively calling this routine.
+
+ @param InsertedDriverEntry The driver to insert on the ScheduledLink Queue
+
+**/
+VOID
+CoreInsertOnScheduledQueueWhileProcessingBeforeAndAfter (
+ IN EFI_CORE_DRIVER_ENTRY *InsertedDriverEntry
+ )
+{
+ LIST_ENTRY *Link;
+ EFI_CORE_DRIVER_ENTRY *DriverEntry;
+
+ //
+ // Process Before Dependency
+ //
+ for (Link = mDiscoveredList.ForwardLink; Link != &mDiscoveredList; Link = Link->ForwardLink) {
+ DriverEntry = CR (Link, EFI_CORE_DRIVER_ENTRY, Link, EFI_CORE_DRIVER_ENTRY_SIGNATURE);
+ if (DriverEntry->Before && DriverEntry->Dependent && (DriverEntry != InsertedDriverEntry)) {
+ DEBUG ((DEBUG_DISPATCH, "Evaluate DXE DEPEX for FFS(%g)\n", &DriverEntry->FileName));
+ DEBUG ((DEBUG_DISPATCH, " BEFORE FFS(%g) = ", &DriverEntry->BeforeAfterGuid));
+ if (CompareGuid (&InsertedDriverEntry->FileName, &DriverEntry->BeforeAfterGuid)) {
+ //
+ // Recursively process BEFORE
+ //
+ DEBUG ((DEBUG_DISPATCH, "TRUE\n END\n RESULT = TRUE\n"));
+ CoreInsertOnScheduledQueueWhileProcessingBeforeAndAfter (DriverEntry);
+ } else {
+ DEBUG ((DEBUG_DISPATCH, "FALSE\n END\n RESULT = FALSE\n"));
+ }
+ }
+ }
+
+ //
+ // Convert driver from Dependent to Scheduled state
+ //
+ CoreAcquireDispatcherLock ();
+
+ InsertedDriverEntry->Dependent = FALSE;
+ InsertedDriverEntry->Scheduled = TRUE;
+ InsertTailList (&mScheduledQueue, &InsertedDriverEntry->ScheduledLink);
+
+ CoreReleaseDispatcherLock ();
+
+ //
+ // Process After Dependency
+ //
+ for (Link = mDiscoveredList.ForwardLink; Link != &mDiscoveredList; Link = Link->ForwardLink) {
+ DriverEntry = CR (Link, EFI_CORE_DRIVER_ENTRY, Link, EFI_CORE_DRIVER_ENTRY_SIGNATURE);
+ if (DriverEntry->After && DriverEntry->Dependent && (DriverEntry != InsertedDriverEntry)) {
+ DEBUG ((DEBUG_DISPATCH, "Evaluate DXE DEPEX for FFS(%g)\n", &DriverEntry->FileName));
+ DEBUG ((DEBUG_DISPATCH, " AFTER FFS(%g) = ", &DriverEntry->BeforeAfterGuid));
+ if (CompareGuid (&InsertedDriverEntry->FileName, &DriverEntry->BeforeAfterGuid)) {
+ //
+ // Recursively process AFTER
+ //
+ DEBUG ((DEBUG_DISPATCH, "TRUE\n END\n RESULT = TRUE\n"));
+ CoreInsertOnScheduledQueueWhileProcessingBeforeAndAfter (DriverEntry);
+ } else {
+ DEBUG ((DEBUG_DISPATCH, "FALSE\n END\n RESULT = FALSE\n"));
+ }
+ }
+ }
+}
+
+/**
+ Return TRUE if the Fv has been processed, FALSE if not.
+
+ @param FvHandle The handle of a FV that's being tested
+
+ @retval TRUE Fv protocol on FvHandle has been processed
+ @retval FALSE Fv protocol on FvHandle has not yet been processed
+
+**/
+BOOLEAN
+FvHasBeenProcessed (
+ IN EFI_HANDLE FvHandle
+ )
+{
+ LIST_ENTRY *Link;
+ KNOWN_HANDLE *KnownHandle;
+
+ for (Link = mFvHandleList.ForwardLink; Link != &mFvHandleList; Link = Link->ForwardLink) {
+ KnownHandle = CR (Link, KNOWN_HANDLE, Link, KNOWN_HANDLE_SIGNATURE);
+ if (KnownHandle->Handle == FvHandle) {
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
+/**
+ Remember that Fv protocol on FvHandle has had it's drivers placed on the
+ mDiscoveredList. This fucntion adds entries on the mFvHandleList if new
+ entry is different from one in mFvHandleList by checking FvImage Guid.
+ Items are never removed/freed from the mFvHandleList.
+
+ @param FvHandle The handle of a FV that has been processed
+
+ @return A point to new added FvHandle entry. If FvHandle with the same FvImage guid
+ has been added, NULL will return.
+
+**/
+KNOWN_HANDLE *
+FvIsBeingProcessed (
+ IN EFI_HANDLE FvHandle
+ )
+{
+ EFI_STATUS Status;
+ EFI_GUID FvNameGuid;
+ BOOLEAN FvNameGuidIsFound;
+ UINT32 ExtHeaderOffset;
+ EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb;
+ EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader;
+ EFI_FV_BLOCK_MAP_ENTRY *BlockMap;
+ UINTN LbaOffset;
+ UINTN Index;
+ EFI_LBA LbaIndex;
+ LIST_ENTRY *Link;
+ KNOWN_HANDLE *KnownHandle;
+
+ FwVolHeader = NULL;
+
+ //
+ // Get the FirmwareVolumeBlock protocol on that handle
+ //
+ FvNameGuidIsFound = FALSE;
+ Status = CoreHandleProtocol (FvHandle, &gEfiFirmwareVolumeBlockProtocolGuid, (VOID **)&Fvb);
+ if (!EFI_ERROR (Status)) {
+ //
+ // Get the full FV header based on FVB protocol.
+ //
+ ASSERT (Fvb != NULL);
+ Status = GetFwVolHeader (Fvb, &FwVolHeader);
+ if (!EFI_ERROR (Status)) {
+ ASSERT (FwVolHeader != NULL);
+ if (VerifyFvHeaderChecksum (FwVolHeader) && (FwVolHeader->ExtHeaderOffset != 0)) {
+ ExtHeaderOffset = (UINT32)FwVolHeader->ExtHeaderOffset;
+ BlockMap = FwVolHeader->BlockMap;
+ LbaIndex = 0;
+ LbaOffset = 0;
+ //
+ // Find LbaIndex and LbaOffset for FV extension header based on BlockMap.
+ //
+ while ((BlockMap->NumBlocks != 0) || (BlockMap->Length != 0)) {
+ for (Index = 0; Index < BlockMap->NumBlocks && ExtHeaderOffset >= BlockMap->Length; Index++) {
+ ExtHeaderOffset -= BlockMap->Length;
+ LbaIndex++;
+ }
+
+ //
+ // Check whether FvExtHeader is crossing the multi block range.
+ //
+ if (Index < BlockMap->NumBlocks) {
+ LbaOffset = ExtHeaderOffset;
+ break;
+ }
+
+ BlockMap++;
+ }
+
+ //
+ // Read FvNameGuid from FV extension header.
+ //
+ Status = ReadFvbData (Fvb, &LbaIndex, &LbaOffset, sizeof (FvNameGuid), (UINT8 *)&FvNameGuid);
+ if (!EFI_ERROR (Status)) {
+ FvNameGuidIsFound = TRUE;
+ }
+ }
+
+ CoreFreePool (FwVolHeader);
+ }
+ }
+
+ if (FvNameGuidIsFound) {
+ //
+ // Check whether the FV image with the found FvNameGuid has been processed.
+ //
+ for (Link = mFvHandleList.ForwardLink; Link != &mFvHandleList; Link = Link->ForwardLink) {
+ KnownHandle = CR (Link, KNOWN_HANDLE, Link, KNOWN_HANDLE_SIGNATURE);
+ if (CompareGuid (&FvNameGuid, &KnownHandle->FvNameGuid)) {
+ DEBUG ((DEBUG_ERROR, "FvImage on FvHandle %p and %p has the same FvNameGuid %g.\n", FvHandle, KnownHandle->Handle, &FvNameGuid));
+ return NULL;
+ }
+ }
+ }
+
+ KnownHandle = AllocateZeroPool (sizeof (KNOWN_HANDLE));
+ ASSERT (KnownHandle != NULL);
+
+ KnownHandle->Signature = KNOWN_HANDLE_SIGNATURE;
+ KnownHandle->Handle = FvHandle;
+ if (FvNameGuidIsFound) {
+ CopyGuid (&KnownHandle->FvNameGuid, &FvNameGuid);
+ }
+
+ InsertTailList (&mFvHandleList, &KnownHandle->Link);
+ return KnownHandle;
+}
+
+/**
+ Convert FvHandle and DriverName into an EFI device path
+
+ @param Fv Fv protocol, needed to read Depex info out of
+ FLASH.
+ @param FvHandle Handle for Fv, needed in the
+ EFI_CORE_DRIVER_ENTRY so that the PE image can be
+ read out of the FV at a later time.
+ @param DriverName Name of driver to add to mDiscoveredList.
+
+ @return Pointer to device path constructed from FvHandle and DriverName
+
+**/
+EFI_DEVICE_PATH_PROTOCOL *
+CoreFvToDevicePath (
+ IN EFI_FIRMWARE_VOLUME2_PROTOCOL *Fv,
+ IN EFI_HANDLE FvHandle,
+ IN EFI_GUID *DriverName
+ )
+{
+ EFI_STATUS Status;
+ EFI_DEVICE_PATH_PROTOCOL *FvDevicePath;
+ EFI_DEVICE_PATH_PROTOCOL *FileNameDevicePath;
+
+ //
+ // Remember the device path of the FV
+ //
+ Status = CoreHandleProtocol (FvHandle, &gEfiDevicePathProtocolGuid, (VOID **)&FvDevicePath);
+ if (EFI_ERROR (Status)) {
+ FileNameDevicePath = NULL;
+ } else {
+ //
+ // Build a device path to the file in the FV to pass into gBS->LoadImage
+ //
+ EfiInitializeFwVolDevicepathNode (&mFvDevicePath.File, DriverName);
+ SetDevicePathEndNode (&mFvDevicePath.End);
+
+ FileNameDevicePath = AppendDevicePath (
+ FvDevicePath,
+ (EFI_DEVICE_PATH_PROTOCOL *)&mFvDevicePath
+ );
+ }
+
+ return FileNameDevicePath;
+}
+
+/**
+ Add an entry to the mDiscoveredList. Allocate memory to store the DriverEntry,
+ and initilize any state variables. Read the Depex from the FV and store it
+ in DriverEntry. Pre-process the Depex to set the SOR, Before and After state.
+ The Discovered list is never free'ed and contains booleans that represent the
+ other possible DXE driver states.
+
+ @param Fv Fv protocol, needed to read Depex info out of
+ FLASH.
+ @param FvHandle Handle for Fv, needed in the
+ EFI_CORE_DRIVER_ENTRY so that the PE image can be
+ read out of the FV at a later time.
+ @param DriverName Name of driver to add to mDiscoveredList.
+ @param Type Fv File Type of file to add to mDiscoveredList.
+
+ @retval EFI_SUCCESS If driver was added to the mDiscoveredList.
+ @retval EFI_ALREADY_STARTED The driver has already been started. Only one
+ DriverName may be active in the system at any one
+ time.
+
+**/
+EFI_STATUS
+CoreAddToDriverList (
+ IN EFI_FIRMWARE_VOLUME2_PROTOCOL *Fv,
+ IN EFI_HANDLE FvHandle,
+ IN EFI_GUID *DriverName,
+ IN EFI_FV_FILETYPE Type
+ )
+{
+ EFI_CORE_DRIVER_ENTRY *DriverEntry;
+
+ //
+ // Create the Driver Entry for the list. ZeroPool initializes lots of variables to
+ // NULL or FALSE.
+ //
+ DriverEntry = AllocateZeroPool (sizeof (EFI_CORE_DRIVER_ENTRY));
+ ASSERT (DriverEntry != NULL);
+ if (Type == EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE) {
+ DriverEntry->IsFvImage = TRUE;
+ }
+
+ DriverEntry->Signature = EFI_CORE_DRIVER_ENTRY_SIGNATURE;
+ CopyGuid (&DriverEntry->FileName, DriverName);
+ DriverEntry->FvHandle = FvHandle;
+ DriverEntry->Fv = Fv;
+ DriverEntry->FvFileDevicePath = CoreFvToDevicePath (Fv, FvHandle, DriverName);
+
+ CoreGetDepexSectionAndPreProccess (DriverEntry);
+
+ CoreAcquireDispatcherLock ();
+
+ InsertTailList (&mDiscoveredList, &DriverEntry->Link);
+
+ CoreReleaseDispatcherLock ();
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Check if a FV Image type file (EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE) is
+ described by a EFI_HOB_FIRMWARE_VOLUME2 Hob.
+
+ @param FvNameGuid The FV image guid specified.
+ @param DriverName The driver guid specified.
+
+ @retval TRUE This file is found in a EFI_HOB_FIRMWARE_VOLUME2
+ Hob.
+ @retval FALSE Not found.
+
+**/
+BOOLEAN
+FvFoundInHobFv2 (
+ IN CONST EFI_GUID *FvNameGuid,
+ IN CONST EFI_GUID *DriverName
+ )
+{
+ EFI_PEI_HOB_POINTERS HobFv2;
+
+ HobFv2.Raw = GetHobList ();
+
+ while ((HobFv2.Raw = GetNextHob (EFI_HOB_TYPE_FV2, HobFv2.Raw)) != NULL) {
+ //
+ // Compare parent FvNameGuid and FileGuid both.
+ //
+ if (CompareGuid (DriverName, &HobFv2.FirmwareVolume2->FileName) &&
+ CompareGuid (FvNameGuid, &HobFv2.FirmwareVolume2->FvName))
+ {
+ return TRUE;
+ }
+
+ HobFv2.Raw = GET_NEXT_HOB (HobFv2);
+ }
+
+ return FALSE;
+}
+
+/**
+ Find USED_SIZE FV_EXT_TYPE entry in FV extension header and get the FV used size.
+
+ @param[in] FvHeader Pointer to FV header.
+ @param[out] FvUsedSize Pointer to FV used size returned,
+ only valid if USED_SIZE FV_EXT_TYPE entry is found.
+ @param[out] EraseByte Pointer to erase byte returned,
+ only valid if USED_SIZE FV_EXT_TYPE entry is found.
+
+ @retval TRUE USED_SIZE FV_EXT_TYPE entry is found,
+ FV used size and erase byte are returned.
+ @retval FALSE No USED_SIZE FV_EXT_TYPE entry found.
+
+**/
+BOOLEAN
+GetFvUsedSize (
+ IN EFI_FIRMWARE_VOLUME_HEADER *FvHeader,
+ OUT UINT32 *FvUsedSize,
+ OUT UINT8 *EraseByte
+ )
+{
+ UINT16 ExtHeaderOffset;
+ EFI_FIRMWARE_VOLUME_EXT_HEADER *ExtHeader;
+ EFI_FIRMWARE_VOLUME_EXT_ENTRY *ExtEntryList;
+ EFI_FIRMWARE_VOLUME_EXT_ENTRY_USED_SIZE_TYPE *ExtEntryUsedSize;
+
+ ExtHeaderOffset = ReadUnaligned16 (&FvHeader->ExtHeaderOffset);
+ if (ExtHeaderOffset != 0) {
+ ExtHeader = (EFI_FIRMWARE_VOLUME_EXT_HEADER *)((UINT8 *)FvHeader + ExtHeaderOffset);
+ ExtEntryList = (EFI_FIRMWARE_VOLUME_EXT_ENTRY *)(ExtHeader + 1);
+ while ((UINTN)ExtEntryList < ((UINTN)ExtHeader + ReadUnaligned32 (&ExtHeader->ExtHeaderSize))) {
+ if (ReadUnaligned16 (&ExtEntryList->ExtEntryType) == EFI_FV_EXT_TYPE_USED_SIZE_TYPE) {
+ //
+ // USED_SIZE FV_EXT_TYPE entry is found.
+ //
+ ExtEntryUsedSize = (EFI_FIRMWARE_VOLUME_EXT_ENTRY_USED_SIZE_TYPE *)ExtEntryList;
+ *FvUsedSize = ReadUnaligned32 (&ExtEntryUsedSize->UsedSize);
+ if ((ReadUnaligned32 (&FvHeader->Attributes) & EFI_FVB2_ERASE_POLARITY) != 0) {
+ *EraseByte = 0xFF;
+ } else {
+ *EraseByte = 0;
+ }
+
+ DEBUG ((
+ DEBUG_INFO,
+ "FV at 0x%x has 0x%x used size, and erase byte is 0x%02x\n",
+ FvHeader,
+ *FvUsedSize,
+ *EraseByte
+ ));
+ return TRUE;
+ }
+
+ ExtEntryList = (EFI_FIRMWARE_VOLUME_EXT_ENTRY *)
+ ((UINT8 *)ExtEntryList + ReadUnaligned16 (&ExtEntryList->ExtEntrySize));
+ }
+ }
+
+ //
+ // No USED_SIZE FV_EXT_TYPE entry found.
+ //
+ return FALSE;
+}
+
+/**
+ Get Fv image(s) from the FV through file name, and produce FVB protocol for every Fv image(s).
+
+ @param Fv The FIRMWARE_VOLUME protocol installed on the FV.
+ @param FvHandle The handle which FVB protocol installed on.
+ @param FileName The file name guid specified.
+
+ @retval EFI_OUT_OF_RESOURCES No enough memory or other resource.
+ @retval EFI_SUCCESS Function successfully returned.
+
+**/
+EFI_STATUS
+CoreProcessFvImageFile (
+ IN EFI_FIRMWARE_VOLUME2_PROTOCOL *Fv,
+ IN EFI_HANDLE FvHandle,
+ IN EFI_GUID *FileName
+ )
+{
+ EFI_STATUS Status;
+ EFI_SECTION_TYPE SectionType;
+ UINT32 AuthenticationStatus;
+ VOID *Buffer;
+ VOID *AlignedBuffer;
+ UINTN BufferSize;
+ EFI_FIRMWARE_VOLUME_HEADER *FvHeader;
+ UINT32 FvAlignment;
+ EFI_DEVICE_PATH_PROTOCOL *FvFileDevicePath;
+ UINT32 FvUsedSize;
+ UINT8 EraseByte;
+ UINTN Index;
+
+ //
+ // Read firmware volume section(s)
+ //
+ SectionType = EFI_SECTION_FIRMWARE_VOLUME_IMAGE;
+
+ Index = 0;
+ do {
+ FvHeader = NULL;
+ FvAlignment = 0;
+ Buffer = NULL;
+ BufferSize = 0;
+ AlignedBuffer = NULL;
+ Status = Fv->ReadSection (
+ Fv,
+ FileName,
+ SectionType,
+ Index,
+ &Buffer,
+ &BufferSize,
+ &AuthenticationStatus
+ );
+ if (!EFI_ERROR (Status)) {
+ //
+ // Evaluate the authentication status of the Firmware Volume through
+ // Security Architectural Protocol
+ //
+ if (gSecurity != NULL) {
+ FvFileDevicePath = CoreFvToDevicePath (Fv, FvHandle, FileName);
+ Status = gSecurity->FileAuthenticationState (
+ gSecurity,
+ AuthenticationStatus,
+ FvFileDevicePath
+ );
+ if (FvFileDevicePath != NULL) {
+ FreePool (FvFileDevicePath);
+ }
+
+ if (Status != EFI_SUCCESS) {
+ //
+ // Security check failed. The firmware volume should not be used for any purpose.
+ //
+ if (Buffer != NULL) {
+ FreePool (Buffer);
+ }
+
+ break;
+ }
+ }
+
+ //
+ // FvImage should be at its required alignment.
+ //
+ FvHeader = (EFI_FIRMWARE_VOLUME_HEADER *)Buffer;
+ //
+ // If EFI_FVB2_WEAK_ALIGNMENT is set in the volume header then the first byte of the volume
+ // can be aligned on any power-of-two boundary. A weakly aligned volume can not be moved from
+ // its initial linked location and maintain its alignment.
+ //
+ if ((ReadUnaligned32 (&FvHeader->Attributes) & EFI_FVB2_WEAK_ALIGNMENT) != EFI_FVB2_WEAK_ALIGNMENT) {
+ //
+ // Get FvHeader alignment
+ //
+ FvAlignment = 1 << ((ReadUnaligned32 (&FvHeader->Attributes) & EFI_FVB2_ALIGNMENT) >> 16);
+ //
+ // FvAlignment must be greater than or equal to 8 bytes of the minimum FFS alignment value.
+ //
+ if (FvAlignment < 8) {
+ FvAlignment = 8;
+ }
+
+ DEBUG ((
+ DEBUG_INFO,
+ "%a() FV at 0x%x, FvAlignment required is 0x%x\n",
+ __func__,
+ FvHeader,
+ FvAlignment
+ ));
+
+ //
+ // Check FvImage alignment.
+ //
+ if ((UINTN)FvHeader % FvAlignment != 0) {
+ //
+ // Allocate the aligned buffer for the FvImage.
+ //
+ AlignedBuffer = AllocateAlignedPages (EFI_SIZE_TO_PAGES (BufferSize), (UINTN)FvAlignment);
+ if (AlignedBuffer == NULL) {
+ FreePool (Buffer);
+ Status = EFI_OUT_OF_RESOURCES;
+ break;
+ } else {
+ //
+ // Move FvImage into the aligned buffer and release the original buffer.
+ //
+ if (GetFvUsedSize (FvHeader, &FvUsedSize, &EraseByte)) {
+ //
+ // Copy the used bytes and fill the rest with the erase value.
+ //
+ CopyMem (AlignedBuffer, FvHeader, (UINTN)FvUsedSize);
+ SetMem (
+ (UINT8 *)AlignedBuffer + FvUsedSize,
+ (UINTN)(BufferSize - FvUsedSize),
+ EraseByte
+ );
+ } else {
+ CopyMem (AlignedBuffer, Buffer, BufferSize);
+ }
+
+ FvHeader = (EFI_FIRMWARE_VOLUME_HEADER *)AlignedBuffer;
+ FreePool (Buffer);
+ Buffer = NULL;
+ }
+ }
+ }
+
+ //
+ // Produce a FVB protocol for the file
+ //
+ Status = ProduceFVBProtocolOnBuffer (
+ (EFI_PHYSICAL_ADDRESS)(UINTN)FvHeader,
+ (UINT64)BufferSize,
+ FvHandle,
+ AuthenticationStatus,
+ NULL
+ );
+ }
+
+ if (EFI_ERROR (Status)) {
+ //
+ // ReadSection or Produce FVB failed, Free data buffer
+ //
+ if (Buffer != NULL) {
+ FreePool (Buffer);
+ }
+
+ if (AlignedBuffer != NULL) {
+ FreeAlignedPages (AlignedBuffer, EFI_SIZE_TO_PAGES (BufferSize));
+ }
+
+ break;
+ } else {
+ Index++;
+ }
+ } while (TRUE);
+
+ if (Index > 0) {
+ //
+ // At least one FvImage has been processed successfully.
+ //
+ return EFI_SUCCESS;
+ } else {
+ return Status;
+ }
+}
+
+/**
+ Event notification that is fired every time a FV dispatch protocol is added.
+ More than one protocol may have been added when this event is fired, so you
+ must loop on CoreLocateHandle () to see how many protocols were added and
+ do the following to each FV:
+ If the Fv has already been processed, skip it. If the Fv has not been
+ processed then mark it as being processed, as we are about to process it.
+ Read the Fv and add any driver in the Fv to the mDiscoveredList.The
+ mDiscoveredList is never free'ed and contains variables that define
+ the other states the DXE driver transitions to..
+ While you are at it read the A Priori file into memory.
+ Place drivers in the A Priori list onto the mScheduledQueue.
+
+ @param Event The Event that is being processed, not used.
+ @param Context Event Context, not used.
+
+**/
+VOID
+EFIAPI
+CoreFwVolEventProtocolNotify (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ EFI_STATUS Status;
+ EFI_STATUS GetNextFileStatus;
+ EFI_FIRMWARE_VOLUME2_PROTOCOL *Fv;
+ EFI_DEVICE_PATH_PROTOCOL *FvDevicePath;
+ EFI_HANDLE FvHandle;
+ UINTN BufferSize;
+ EFI_GUID NameGuid;
+ UINTN Key;
+ EFI_FV_FILETYPE Type;
+ EFI_FV_FILE_ATTRIBUTES Attributes;
+ UINTN Size;
+ EFI_CORE_DRIVER_ENTRY *DriverEntry;
+ EFI_GUID *AprioriFile;
+ UINTN AprioriEntryCount;
+ UINTN Index;
+ LIST_ENTRY *Link;
+ UINT32 AuthenticationStatus;
+ UINTN SizeOfBuffer;
+ VOID *DepexBuffer;
+ KNOWN_HANDLE *KnownHandle;
+
+ FvHandle = NULL;
+
+ while (TRUE) {
+ BufferSize = sizeof (EFI_HANDLE);
+ Status = CoreLocateHandle (
+ ByRegisterNotify,
+ NULL,
+ mFwVolEventRegistration,
+ &BufferSize,
+ &FvHandle
+ );
+ if (EFI_ERROR (Status)) {
+ //
+ // If no more notification events exit
+ //
+ return;
+ }
+
+ if (FvHasBeenProcessed (FvHandle)) {
+ //
+ // This Fv has already been processed so lets skip it!
+ //
+ continue;
+ }
+
+ //
+ // Since we are about to process this Fv mark it as processed.
+ //
+ KnownHandle = FvIsBeingProcessed (FvHandle);
+ if (KnownHandle == NULL) {
+ //
+ // The FV with the same FV name guid has already been processed.
+ // So lets skip it!
+ //
+ continue;
+ }
+
+ Status = CoreHandleProtocol (FvHandle, &gEfiFirmwareVolume2ProtocolGuid, (VOID **)&Fv);
+ if (EFI_ERROR (Status) || (Fv == NULL)) {
+ //
+ // FvHandle must have Firmware Volume2 protocol thus we should never get here.
+ //
+ ASSERT (FALSE);
+ continue;
+ }
+
+ Status = CoreHandleProtocol (FvHandle, &gEfiDevicePathProtocolGuid, (VOID **)&FvDevicePath);
+ if (EFI_ERROR (Status)) {
+ //
+ // The Firmware volume doesn't have device path, can't be dispatched.
+ //
+ continue;
+ }
+
+ //
+ // Discover Drivers in FV and add them to the Discovered Driver List.
+ // Process EFI_FV_FILETYPE_DRIVER type and then EFI_FV_FILETYPE_COMBINED_PEIM_DRIVER
+ // EFI_FV_FILETYPE_DXE_CORE is processed to produce a Loaded Image protocol for the core
+ // EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE is processed to create a Fvb
+ //
+ for (Index = 0; Index < sizeof (mDxeFileTypes) / sizeof (EFI_FV_FILETYPE); Index++) {
+ //
+ // Initialize the search key
+ //
+ Key = 0;
+ do {
+ Type = mDxeFileTypes[Index];
+ GetNextFileStatus = Fv->GetNextFile (
+ Fv,
+ &Key,
+ &Type,
+ &NameGuid,
+ &Attributes,
+ &Size
+ );
+ if (!EFI_ERROR (GetNextFileStatus)) {
+ if (Type == EFI_FV_FILETYPE_DXE_CORE) {
+ //
+ // If this is the DXE core fill in it's DevicePath & DeviceHandle
+ //
+ if (gDxeCoreLoadedImage->FilePath == NULL) {
+ if (CompareGuid (&NameGuid, gDxeCoreFileName)) {
+ //
+ // Maybe One specail Fv cantains only one DXE_CORE module, so its device path must
+ // be initialized completely.
+ //
+ EfiInitializeFwVolDevicepathNode (&mFvDevicePath.File, &NameGuid);
+ SetDevicePathEndNode (&mFvDevicePath.End);
+
+ gDxeCoreLoadedImage->FilePath = DuplicateDevicePath (
+ (EFI_DEVICE_PATH_PROTOCOL *)&mFvDevicePath
+ );
+ gDxeCoreLoadedImage->DeviceHandle = FvHandle;
+ }
+ }
+ } else if (Type == EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE) {
+ //
+ // Check if this EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE file has already
+ // been extracted.
+ //
+ if (FvFoundInHobFv2 (&KnownHandle->FvNameGuid, &NameGuid)) {
+ continue;
+ }
+
+ //
+ // Check if this EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE file has SMM depex section.
+ //
+ DepexBuffer = NULL;
+ SizeOfBuffer = 0;
+ Status = Fv->ReadSection (
+ Fv,
+ &NameGuid,
+ EFI_SECTION_SMM_DEPEX,
+ 0,
+ &DepexBuffer,
+ &SizeOfBuffer,
+ &AuthenticationStatus
+ );
+ if (!EFI_ERROR (Status)) {
+ //
+ // If SMM depex section is found, this FV image is invalid to be supported.
+ // ASSERT FALSE to report this FV image.
+ //
+ FreePool (DepexBuffer);
+ ASSERT (FALSE);
+ }
+
+ //
+ // Check if this EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE file has DXE depex section.
+ //
+ DepexBuffer = NULL;
+ SizeOfBuffer = 0;
+ Status = Fv->ReadSection (
+ Fv,
+ &NameGuid,
+ EFI_SECTION_DXE_DEPEX,
+ 0,
+ &DepexBuffer,
+ &SizeOfBuffer,
+ &AuthenticationStatus
+ );
+ if (EFI_ERROR (Status)) {
+ //
+ // If no depex section, produce a firmware volume block protocol for it so it gets dispatched from.
+ //
+ CoreProcessFvImageFile (Fv, FvHandle, &NameGuid);
+ } else {
+ //
+ // If depex section is found, this FV image will be dispatched until its depex is evaluated to TRUE.
+ //
+ FreePool (DepexBuffer);
+ CoreAddToDriverList (Fv, FvHandle, &NameGuid, Type);
+ }
+ } else {
+ //
+ // Transition driver from Undiscovered to Discovered state
+ //
+ CoreAddToDriverList (Fv, FvHandle, &NameGuid, Type);
+ }
+ }
+ } while (!EFI_ERROR (GetNextFileStatus));
+ }
+
+ //
+ // Read the array of GUIDs from the Apriori file if it is present in the firmware volume
+ //
+ AprioriFile = NULL;
+ Status = Fv->ReadSection (
+ Fv,
+ &gAprioriGuid,
+ EFI_SECTION_RAW,
+ 0,
+ (VOID **)&AprioriFile,
+ &SizeOfBuffer,
+ &AuthenticationStatus
+ );
+ if (!EFI_ERROR (Status)) {
+ AprioriEntryCount = SizeOfBuffer / sizeof (EFI_GUID);
+ } else {
+ AprioriEntryCount = 0;
+ }
+
+ //
+ // Put drivers on Apriori List on the Scheduled queue. The Discovered List includes
+ // drivers not in the current FV and these must be skipped since the a priori list
+ // is only valid for the FV that it resided in.
+ //
+
+ for (Index = 0; Index < AprioriEntryCount; Index++) {
+ for (Link = mDiscoveredList.ForwardLink; Link != &mDiscoveredList; Link = Link->ForwardLink) {
+ DriverEntry = CR (Link, EFI_CORE_DRIVER_ENTRY, Link, EFI_CORE_DRIVER_ENTRY_SIGNATURE);
+ if (CompareGuid (&DriverEntry->FileName, &AprioriFile[Index]) &&
+ (FvHandle == DriverEntry->FvHandle))
+ {
+ CoreAcquireDispatcherLock ();
+ DriverEntry->Dependent = FALSE;
+ DriverEntry->Scheduled = TRUE;
+ InsertTailList (&mScheduledQueue, &DriverEntry->ScheduledLink);
+ CoreReleaseDispatcherLock ();
+ DEBUG ((DEBUG_DISPATCH, "Evaluate DXE DEPEX for FFS(%g)\n", &DriverEntry->FileName));
+ DEBUG ((DEBUG_DISPATCH, " RESULT = TRUE (Apriori)\n"));
+ break;
+ }
+ }
+ }
+
+ //
+ // Free data allocated by Fv->ReadSection ()
+ //
+ CoreFreePool (AprioriFile);
+ }
+}
+
+/**
+ Initialize the dispatcher. Initialize the notification function that runs when
+ an FV2 protocol is added to the system.
+
+**/
+VOID
+CoreInitializeDispatcher (
+ VOID
+ )
+{
+ PERF_FUNCTION_BEGIN ();
+
+ mFwVolEvent = EfiCreateProtocolNotifyEvent (
+ &gEfiFirmwareVolume2ProtocolGuid,
+ TPL_CALLBACK,
+ CoreFwVolEventProtocolNotify,
+ NULL,
+ &mFwVolEventRegistration
+ );
+
+ PERF_FUNCTION_END ();
+}
+
+//
+// Function only used in debug builds
+//
+
+/**
+ Traverse the discovered list for any drivers that were discovered but not loaded
+ because the dependency experessions evaluated to false.
+
+**/
+VOID
+CoreDisplayDiscoveredNotDispatched (
+ VOID
+ )
+{
+ LIST_ENTRY *Link;
+ EFI_CORE_DRIVER_ENTRY *DriverEntry;
+
+ for (Link = mDiscoveredList.ForwardLink; Link != &mDiscoveredList; Link = Link->ForwardLink) {
+ DriverEntry = CR (Link, EFI_CORE_DRIVER_ENTRY, Link, EFI_CORE_DRIVER_ENTRY_SIGNATURE);
+ if (DriverEntry->Dependent) {
+ DEBUG ((DEBUG_LOAD, "Driver %g was discovered but not loaded!!\n", &DriverEntry->FileName));
+ }
+ }
+}
diff --git a/MdeModulePkg/Core/Dxe/DxeCore.uni b/MdeModulePkg/Core/Dxe/DxeCore.uni
index 54b8552812..a65ea31237 100644
--- a/MdeModulePkg/Core/Dxe/DxeCore.uni
+++ b/MdeModulePkg/Core/Dxe/DxeCore.uni
@@ -1,16 +1,16 @@
-// /** @file
-// This is core module in DXE phase.
-//
-// It provides an implementation of DXE Core that is compliant with DXE CIS.
-//
-// Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
-//
-// SPDX-License-Identifier: BSD-2-Clause-Patent
-//
-// **/
-
-
-#string STR_MODULE_ABSTRACT #language en-US "The core module in DXE phase"
-
-#string STR_MODULE_DESCRIPTION #language en-US "It provides an implementation of DXE Core that is compliant with DXE CIS."
-
+// /** @file
+// This is core module in DXE phase.
+//
+// It provides an implementation of DXE Core that is compliant with DXE CIS.
+//
+// Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "The core module in DXE phase"
+
+#string STR_MODULE_DESCRIPTION #language en-US "It provides an implementation of DXE Core that is compliant with DXE CIS."
+
diff --git a/MdeModulePkg/Core/Dxe/DxeCoreExtra.uni b/MdeModulePkg/Core/Dxe/DxeCoreExtra.uni
index c9abba4f6b..bcb88407fa 100644
--- a/MdeModulePkg/Core/Dxe/DxeCoreExtra.uni
+++ b/MdeModulePkg/Core/Dxe/DxeCoreExtra.uni
@@ -1,14 +1,14 @@
-// /** @file
-// DxeCore Localized Strings and Content
-//
-// Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.<BR>
-//
-// SPDX-License-Identifier: BSD-2-Clause-Patent
-//
-// **/
-
-#string STR_PROPERTIES_MODULE_NAME
-#language en-US
-"Core DXE Services Driver"
-
-
+// /** @file
+// DxeCore Localized Strings and Content
+//
+// Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+#string STR_PROPERTIES_MODULE_NAME
+#language en-US
+"Core DXE Services Driver"
+
+
diff --git a/MdeModulePkg/Core/Dxe/DxeMain.h b/MdeModulePkg/Core/Dxe/DxeMain.h
index 53e26703f8..230671368c 100644
--- a/MdeModulePkg/Core/Dxe/DxeMain.h
+++ b/MdeModulePkg/Core/Dxe/DxeMain.h
@@ -1,2793 +1,2793 @@
-/** @file
- The internal header file includes the common header files, defines
- internal structure and functions used by DxeCore module.
-
-Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
-SPDX-License-Identifier: BSD-2-Clause-Patent
-
-**/
-
-#ifndef _DXE_MAIN_H_
-#define _DXE_MAIN_H_
-
-#include <PiDxe.h>
-
-#include <Protocol/LoadedImage.h>
-#include <Protocol/GuidedSectionExtraction.h>
-#include <Protocol/DevicePath.h>
-#include <Protocol/Runtime.h>
-#include <Protocol/LoadFile.h>
-#include <Protocol/LoadFile2.h>
-#include <Protocol/DriverBinding.h>
-#include <Protocol/VariableWrite.h>
-#include <Protocol/PlatformDriverOverride.h>
-#include <Protocol/Variable.h>
-#include <Protocol/Timer.h>
-#include <Protocol/SimpleFileSystem.h>
-#include <Protocol/Bds.h>
-#include <Protocol/RealTimeClock.h>
-#include <Protocol/WatchdogTimer.h>
-#include <Protocol/FirmwareVolume2.h>
-#include <Protocol/MonotonicCounter.h>
-#include <Protocol/StatusCode.h>
-#include <Protocol/Decompress.h>
-#include <Protocol/LoadPe32Image.h>
-#include <Protocol/Security.h>
-#include <Protocol/Security2.h>
-#include <Protocol/Reset.h>
-#include <Protocol/Cpu.h>
-#include <Protocol/Metronome.h>
-#include <Protocol/FirmwareVolumeBlock.h>
-#include <Protocol/Capsule.h>
-#include <Protocol/BusSpecificDriverOverride.h>
-#include <Protocol/DriverFamilyOverride.h>
-#include <Protocol/TcgService.h>
-#include <Protocol/HiiPackageList.h>
-#include <Protocol/SmmBase2.h>
-#include <Protocol/PeCoffImageEmulator.h>
-#include <Guid/MemoryTypeInformation.h>
-#include <Guid/FirmwareFileSystem2.h>
-#include <Guid/FirmwareFileSystem3.h>
-#include <Guid/HobList.h>
-#include <Guid/DebugImageInfoTable.h>
-#include <Guid/FileInfo.h>
-#include <Guid/Apriori.h>
-#include <Guid/DxeServices.h>
-#include <Guid/MemoryAllocationHob.h>
-#include <Guid/EventLegacyBios.h>
-#include <Guid/EventGroup.h>
-#include <Guid/EventExitBootServiceFailed.h>
-#include <Guid/LoadModuleAtFixedAddress.h>
-#include <Guid/IdleLoopEvent.h>
-#include <Guid/VectorHandoffTable.h>
-#include <Ppi/VectorHandoffInfo.h>
-#include <Guid/MemoryProfile.h>
-
-#include <Library/DxeCoreEntryPoint.h>
-#include <Library/DebugLib.h>
-#include <Library/UefiLib.h>
-#include <Library/BaseLib.h>
-#include <Library/HobLib.h>
-#include <Library/PerformanceLib.h>
-#include <Library/UefiDecompressLib.h>
-#include <Library/ExtractGuidedSectionLib.h>
-#include <Library/CacheMaintenanceLib.h>
-#include <Library/BaseMemoryLib.h>
-#include <Library/PeCoffLib.h>
-#include <Library/PeCoffGetEntryPointLib.h>
-#include <Library/PeCoffExtraActionLib.h>
-#include <Library/PcdLib.h>
-#include <Library/MemoryAllocationLib.h>
-#include <Library/DevicePathLib.h>
-#include <Library/UefiBootServicesTableLib.h>
-#include <Library/ReportStatusCodeLib.h>
-#include <Library/DxeServicesLib.h>
-#include <Library/DebugAgentLib.h>
-#include <Library/CpuExceptionHandlerLib.h>
-
-//
-// attributes for reserved memory before it is promoted to system memory
-//
-#define EFI_MEMORY_PRESENT 0x0100000000000000ULL
-#define EFI_MEMORY_INITIALIZED 0x0200000000000000ULL
-#define EFI_MEMORY_TESTED 0x0400000000000000ULL
-
-//
-// range for memory mapped port I/O on IPF
-//
-#define EFI_MEMORY_PORT_IO 0x4000000000000000ULL
-
-///
-/// EFI_DEP_REPLACE_TRUE - Used to dynamically patch the dependency expression
-/// to save time. A EFI_DEP_PUSH is evaluated one an
-/// replaced with EFI_DEP_REPLACE_TRUE. If PI spec's Vol 2
-/// Driver Execution Environment Core Interface use 0xff
-/// as new DEPEX opcode. EFI_DEP_REPLACE_TRUE should be
-/// defined to a new value that is not conflicting with PI spec.
-///
-#define EFI_DEP_REPLACE_TRUE 0xff
-
-///
-/// Define the initial size of the dependency expression evaluation stack
-///
-#define DEPEX_STACK_SIZE_INCREMENT 0x1000
-
-typedef struct {
- EFI_GUID *ProtocolGuid;
- VOID **Protocol;
- EFI_EVENT Event;
- VOID *Registration;
- BOOLEAN Present;
-} EFI_CORE_PROTOCOL_NOTIFY_ENTRY;
-
-//
-// DXE Dispatcher Data structures
-//
-
-#define KNOWN_HANDLE_SIGNATURE SIGNATURE_32('k','n','o','w')
-typedef struct {
- UINTN Signature;
- LIST_ENTRY Link; // mFvHandleList
- EFI_HANDLE Handle;
- EFI_GUID FvNameGuid;
-} KNOWN_HANDLE;
-
-#define EFI_CORE_DRIVER_ENTRY_SIGNATURE SIGNATURE_32('d','r','v','r')
-typedef struct {
- UINTN Signature;
- LIST_ENTRY Link; // mDriverList
-
- LIST_ENTRY ScheduledLink; // mScheduledQueue
-
- EFI_HANDLE FvHandle;
- EFI_GUID FileName;
- EFI_DEVICE_PATH_PROTOCOL *FvFileDevicePath;
- EFI_FIRMWARE_VOLUME2_PROTOCOL *Fv;
-
- VOID *Depex;
- UINTN DepexSize;
-
- BOOLEAN Before;
- BOOLEAN After;
- EFI_GUID BeforeAfterGuid;
-
- BOOLEAN Dependent;
- BOOLEAN Unrequested;
- BOOLEAN Scheduled;
- BOOLEAN Untrusted;
- BOOLEAN Initialized;
- BOOLEAN DepexProtocolError;
-
- EFI_HANDLE ImageHandle;
- BOOLEAN IsFvImage;
-} EFI_CORE_DRIVER_ENTRY;
-
-//
-// The data structure of GCD memory map entry
-//
-#define EFI_GCD_MAP_SIGNATURE SIGNATURE_32('g','c','d','m')
-typedef struct {
- UINTN Signature;
- LIST_ENTRY Link;
- EFI_PHYSICAL_ADDRESS BaseAddress;
- UINT64 EndAddress;
- UINT64 Capabilities;
- UINT64 Attributes;
- EFI_GCD_MEMORY_TYPE GcdMemoryType;
- EFI_GCD_IO_TYPE GcdIoType;
- EFI_HANDLE ImageHandle;
- EFI_HANDLE DeviceHandle;
-} EFI_GCD_MAP_ENTRY;
-
-#define LOADED_IMAGE_PRIVATE_DATA_SIGNATURE SIGNATURE_32('l','d','r','i')
-
-typedef struct {
- UINTN Signature;
- /// Image handle
- EFI_HANDLE Handle;
- /// Image type
- UINTN Type;
- /// If entrypoint has been called
- BOOLEAN Started;
- /// The image's entry point
- EFI_IMAGE_ENTRY_POINT EntryPoint;
- /// loaded image protocol
- EFI_LOADED_IMAGE_PROTOCOL Info;
- /// Location in memory
- EFI_PHYSICAL_ADDRESS ImageBasePage;
- /// Number of pages
- UINTN NumberOfPages;
- /// Original fixup data
- CHAR8 *FixupData;
- /// Tpl of started image
- EFI_TPL Tpl;
- /// Status returned by started image
- EFI_STATUS Status;
- /// Size of ExitData from started image
- UINTN ExitDataSize;
- /// Pointer to exit data from started image
- VOID *ExitData;
- /// Pointer to pool allocation for context save/restore
- VOID *JumpBuffer;
- /// Pointer to buffer for context save/restore
- BASE_LIBRARY_JUMP_BUFFER *JumpContext;
- /// Machine type from PE image
- UINT16 Machine;
- /// PE/COFF Image Emulator Protocol pointer
- EDKII_PECOFF_IMAGE_EMULATOR_PROTOCOL *PeCoffEmu;
- /// Runtime image list
- EFI_RUNTIME_IMAGE_ENTRY *RuntimeData;
- /// Pointer to Loaded Image Device Path Protocol
- EFI_DEVICE_PATH_PROTOCOL *LoadedImageDevicePath;
- /// PeCoffLoader ImageContext
- PE_COFF_LOADER_IMAGE_CONTEXT ImageContext;
- /// Status returned by LoadImage() service.
- EFI_STATUS LoadImageStatus;
-} LOADED_IMAGE_PRIVATE_DATA;
-
-#define LOADED_IMAGE_PRIVATE_DATA_FROM_THIS(a) \
- CR(a, LOADED_IMAGE_PRIVATE_DATA, Info, LOADED_IMAGE_PRIVATE_DATA_SIGNATURE)
-
-//
-// DXE Core Global Variables
-//
-extern EFI_SYSTEM_TABLE *gDxeCoreST;
-extern EFI_RUNTIME_SERVICES *gDxeCoreRT;
-extern EFI_DXE_SERVICES *gDxeCoreDS;
-extern EFI_HANDLE gDxeCoreImageHandle;
-
-extern BOOLEAN gMemoryMapTerminated;
-
-extern EFI_DECOMPRESS_PROTOCOL gEfiDecompress;
-
-extern EFI_RUNTIME_ARCH_PROTOCOL *gRuntime;
-extern EFI_CPU_ARCH_PROTOCOL *gCpu;
-extern EFI_WATCHDOG_TIMER_ARCH_PROTOCOL *gWatchdogTimer;
-extern EFI_METRONOME_ARCH_PROTOCOL *gMetronome;
-extern EFI_TIMER_ARCH_PROTOCOL *gTimer;
-extern EFI_SECURITY_ARCH_PROTOCOL *gSecurity;
-extern EFI_SECURITY2_ARCH_PROTOCOL *gSecurity2;
-extern EFI_BDS_ARCH_PROTOCOL *gBds;
-extern EFI_SMM_BASE2_PROTOCOL *gSmmBase2;
-
-extern EFI_TPL gEfiCurrentTpl;
-
-extern EFI_GUID *gDxeCoreFileName;
-extern EFI_LOADED_IMAGE_PROTOCOL *gDxeCoreLoadedImage;
-
-extern EFI_MEMORY_TYPE_INFORMATION gMemoryTypeInformation[EfiMaxMemoryType + 1];
-
-extern BOOLEAN gDispatcherRunning;
-extern EFI_RUNTIME_ARCH_PROTOCOL gRuntimeTemplate;
-
-extern BOOLEAN gMemoryAttributesTableForwardCfi;
-
-extern EFI_LOAD_FIXED_ADDRESS_CONFIGURATION_TABLE gLoadModuleAtFixAddressConfigurationTable;
-extern BOOLEAN gLoadFixedAddressCodeMemoryReady;
-//
-// Service Initialization Functions
-//
-
-/**
- Called to initialize the pool.
-
-**/
-VOID
-CoreInitializePool (
- VOID
- );
-
-VOID
-CoreSetMemoryTypeInformationRange (
- IN EFI_PHYSICAL_ADDRESS Start,
- IN UINT64 Length
- );
-
-/**
- Called to initialize the memory map and add descriptors to
- the current descriptor list.
- The first descriptor that is added must be general usable
- memory as the addition allocates heap.
-
- @param Type The type of memory to add
- @param Start The starting address in the memory range Must be
- page aligned
- @param NumberOfPages The number of pages in the range
- @param Attribute Attributes of the memory to add
-
- @return None. The range is added to the memory map
-
-**/
-VOID
-CoreAddMemoryDescriptor (
- IN EFI_MEMORY_TYPE Type,
- IN EFI_PHYSICAL_ADDRESS Start,
- IN UINT64 NumberOfPages,
- IN UINT64 Attribute
- );
-
-/**
- Release memory lock on mGcdMemorySpaceLock.
-
-**/
-VOID
-CoreReleaseGcdMemoryLock (
- VOID
- );
-
-/**
- Acquire memory lock on mGcdMemorySpaceLock.
-
-**/
-VOID
-CoreAcquireGcdMemoryLock (
- VOID
- );
-
-/**
- External function. Initializes memory services based on the memory
- descriptor HOBs. This function is responsible for priming the memory
- map, so memory allocations and resource allocations can be made.
- The first part of this function can not depend on any memory services
- until at least one memory descriptor is provided to the memory services.
-
- @param HobStart The start address of the HOB.
- @param MemoryBaseAddress Start address of memory region found to init DXE
- core.
- @param MemoryLength Length of memory region found to init DXE core.
-
- @retval EFI_SUCCESS Memory services successfully initialized.
-
-**/
-EFI_STATUS
-CoreInitializeMemoryServices (
- IN VOID **HobStart,
- OUT EFI_PHYSICAL_ADDRESS *MemoryBaseAddress,
- OUT UINT64 *MemoryLength
- );
-
-/**
- External function. Initializes the GCD and memory services based on the memory
- descriptor HOBs. This function is responsible for priming the GCD map and the
- memory map, so memory allocations and resource allocations can be made. The
- HobStart will be relocated to a pool buffer.
-
- @param HobStart The start address of the HOB
- @param MemoryBaseAddress Start address of memory region found to init DXE
- core.
- @param MemoryLength Length of memory region found to init DXE core.
-
- @retval EFI_SUCCESS GCD services successfully initialized.
-
-**/
-EFI_STATUS
-CoreInitializeGcdServices (
- IN OUT VOID **HobStart,
- IN EFI_PHYSICAL_ADDRESS MemoryBaseAddress,
- IN UINT64 MemoryLength
- );
-
-/**
- Initializes "event" support.
-
- @retval EFI_SUCCESS Always return success
-
-**/
-EFI_STATUS
-CoreInitializeEventServices (
- VOID
- );
-
-/**
- Add the Image Services to EFI Boot Services Table and install the protocol
- interfaces for this image.
-
- @param HobStart The HOB to initialize
-
- @return Status code.
-
-**/
-EFI_STATUS
-CoreInitializeImageServices (
- IN VOID *HobStart
- );
-
-/**
- Creates an event that is fired everytime a Protocol of a specific type is installed.
-
-**/
-VOID
-CoreNotifyOnProtocolInstallation (
- VOID
- );
-
-/**
- Return TRUE if all AP services are available.
-
- @retval EFI_SUCCESS All AP services are available
- @retval EFI_NOT_FOUND At least one AP service is not available
-
-**/
-EFI_STATUS
-CoreAllEfiServicesAvailable (
- VOID
- );
-
-/**
- Calcualte the 32-bit CRC in a EFI table using the service provided by the
- gRuntime service.
-
- @param Hdr Pointer to an EFI standard header
-
-**/
-VOID
-CalculateEfiHdrCrc (
- IN OUT EFI_TABLE_HEADER *Hdr
- );
-
-/**
- Called by the platform code to process a tick.
-
- @param Duration The number of 100ns elapsed since the last call
- to TimerTick
-
-**/
-VOID
-EFIAPI
-CoreTimerTick (
- IN UINT64 Duration
- );
-
-/**
- Initialize the dispatcher. Initialize the notification function that runs when
- an FV2 protocol is added to the system.
-
-**/
-VOID
-CoreInitializeDispatcher (
- VOID
- );
-
-/**
- This is the POSTFIX version of the dependency evaluator. This code does
- not need to handle Before or After, as it is not valid to call this
- routine in this case. The SOR is just ignored and is a nop in the grammer.
- POSTFIX means all the math is done on top of the stack.
-
- @param DriverEntry DriverEntry element to update.
-
- @retval TRUE If driver is ready to run.
- @retval FALSE If driver is not ready to run or some fatal error
- was found.
-
-**/
-BOOLEAN
-CoreIsSchedulable (
- IN EFI_CORE_DRIVER_ENTRY *DriverEntry
- );
-
-/**
- Preprocess dependency expression and update DriverEntry to reflect the
- state of Before, After, and SOR dependencies. If DriverEntry->Before
- or DriverEntry->After is set it will never be cleared. If SOR is set
- it will be cleared by CoreSchedule(), and then the driver can be
- dispatched.
-
- @param DriverEntry DriverEntry element to update .
-
- @retval EFI_SUCCESS It always works.
-
-**/
-EFI_STATUS
-CorePreProcessDepex (
- IN EFI_CORE_DRIVER_ENTRY *DriverEntry
- );
-
-/**
- Terminates all boot services.
-
- @param ImageHandle Handle that identifies the exiting image.
- @param MapKey Key to the latest memory map.
-
- @retval EFI_SUCCESS Boot Services terminated
- @retval EFI_INVALID_PARAMETER MapKey is incorrect.
-
-**/
-EFI_STATUS
-EFIAPI
-CoreExitBootServices (
- IN EFI_HANDLE ImageHandle,
- IN UINTN MapKey
- );
-
-/**
- Make sure the memory map is following all the construction rules,
- it is the last time to check memory map error before exit boot services.
-
- @param MapKey Memory map key
-
- @retval EFI_INVALID_PARAMETER Memory map not consistent with construction
- rules.
- @retval EFI_SUCCESS Valid memory map.
-
-**/
-EFI_STATUS
-CoreTerminateMemoryMap (
- IN UINTN MapKey
- );
-
-/**
- Signals all events in the EventGroup.
-
- @param EventGroup The list to signal
-
-**/
-VOID
-CoreNotifySignalList (
- IN EFI_GUID *EventGroup
- );
-
-/**
- Boot Service called to add, modify, or remove a system configuration table from
- the EFI System Table.
-
- @param Guid Pointer to the GUID for the entry to add, update, or
- remove
- @param Table Pointer to the configuration table for the entry to add,
- update, or remove, may be NULL.
-
- @return EFI_SUCCESS Guid, Table pair added, updated, or removed.
- @return EFI_INVALID_PARAMETER Input GUID not valid.
- @return EFI_NOT_FOUND Attempted to delete non-existant entry
- @return EFI_OUT_OF_RESOURCES Not enough memory available
-
-**/
-EFI_STATUS
-EFIAPI
-CoreInstallConfigurationTable (
- IN EFI_GUID *Guid,
- IN VOID *Table
- );
-
-/**
- Raise the task priority level to the new level.
- High level is implemented by disabling processor interrupts.
-
- @param NewTpl New task priority level
-
- @return The previous task priority level
-
-**/
-EFI_TPL
-EFIAPI
-CoreRaiseTpl (
- IN EFI_TPL NewTpl
- );
-
-/**
- Lowers the task priority to the previous value. If the new
- priority unmasks events at a higher priority, they are dispatched.
-
- @param NewTpl New, lower, task priority
-
-**/
-VOID
-EFIAPI
-CoreRestoreTpl (
- IN EFI_TPL NewTpl
- );
-
-/**
- Introduces a fine-grained stall.
-
- @param Microseconds The number of microseconds to stall execution.
-
- @retval EFI_SUCCESS Execution was stalled for at least the requested
- amount of microseconds.
- @retval EFI_NOT_AVAILABLE_YET gMetronome is not available yet
-
-**/
-EFI_STATUS
-EFIAPI
-CoreStall (
- IN UINTN Microseconds
- );
-
-/**
- Sets the system's watchdog timer.
-
- @param Timeout The number of seconds to set the watchdog timer to.
- A value of zero disables the timer.
- @param WatchdogCode The numeric code to log on a watchdog timer timeout
- event. The firmware reserves codes 0x0000 to 0xFFFF.
- Loaders and operating systems may use other timeout
- codes.
- @param DataSize The size, in bytes, of WatchdogData.
- @param WatchdogData A data buffer that includes a Null-terminated Unicode
- string, optionally followed by additional binary data.
- The string is a description that the call may use to
- further indicate the reason to be logged with a
- watchdog event.
-
- @return EFI_SUCCESS Timeout has been set
- @return EFI_NOT_AVAILABLE_YET WatchdogTimer is not available yet
- @return EFI_UNSUPPORTED System does not have a timer (currently not used)
- @return EFI_DEVICE_ERROR Could not complete due to hardware error
-
-**/
-EFI_STATUS
-EFIAPI
-CoreSetWatchdogTimer (
- IN UINTN Timeout,
- IN UINT64 WatchdogCode,
- IN UINTN DataSize,
- IN CHAR16 *WatchdogData OPTIONAL
- );
-
-/**
- Wrapper function to CoreInstallProtocolInterfaceNotify. This is the public API which
- Calls the private one which contains a BOOLEAN parameter for notifications
-
- @param UserHandle The handle to install the protocol handler on,
- or NULL if a new handle is to be allocated
- @param Protocol The protocol to add to the handle
- @param InterfaceType Indicates whether Interface is supplied in
- native form.
- @param Interface The interface for the protocol being added
-
- @return Status code
-
-**/
-EFI_STATUS
-EFIAPI
-CoreInstallProtocolInterface (
- IN OUT EFI_HANDLE *UserHandle,
- IN EFI_GUID *Protocol,
- IN EFI_INTERFACE_TYPE InterfaceType,
- IN VOID *Interface
- );
-
-/**
- Installs a protocol interface into the boot services environment.
-
- @param UserHandle The handle to install the protocol handler on,
- or NULL if a new handle is to be allocated
- @param Protocol The protocol to add to the handle
- @param InterfaceType Indicates whether Interface is supplied in
- native form.
- @param Interface The interface for the protocol being added
- @param Notify indicates whether notify the notification list
- for this protocol
-
- @retval EFI_INVALID_PARAMETER Invalid parameter
- @retval EFI_OUT_OF_RESOURCES No enough buffer to allocate
- @retval EFI_SUCCESS Protocol interface successfully installed
-
-**/
-EFI_STATUS
-CoreInstallProtocolInterfaceNotify (
- IN OUT EFI_HANDLE *UserHandle,
- IN EFI_GUID *Protocol,
- IN EFI_INTERFACE_TYPE InterfaceType,
- IN VOID *Interface,
- IN BOOLEAN Notify
- );
-
-/**
- Installs a list of protocol interface into the boot services environment.
- This function calls InstallProtocolInterface() in a loop. If any error
- occures all the protocols added by this function are removed. This is
- basically a lib function to save space.
-
- @param Handle The handle to install the protocol handlers on,
- or NULL if a new handle is to be allocated
- @param ... EFI_GUID followed by protocol instance. A NULL
- terminates the list. The pairs are the
- arguments to InstallProtocolInterface(). All the
- protocols are added to Handle.
-
- @retval EFI_SUCCESS All the protocol interface was installed.
- @retval EFI_OUT_OF_RESOURCES There was not enough memory in pool to install all the protocols.
- @retval EFI_ALREADY_STARTED A Device Path Protocol instance was passed in that is already present in
- the handle database.
- @retval EFI_INVALID_PARAMETER Handle is NULL.
- @retval EFI_INVALID_PARAMETER Protocol is already installed on the handle specified by Handle.
-
-**/
-EFI_STATUS
-EFIAPI
-CoreInstallMultipleProtocolInterfaces (
- IN OUT EFI_HANDLE *Handle,
- ...
- );
-
-/**
- Uninstalls a list of protocol interface in the boot services environment.
- This function calls UnisatllProtocolInterface() in a loop. This is
- basically a lib function to save space.
-
- @param Handle The handle to uninstall the protocol
- @param ... EFI_GUID followed by protocol instance. A NULL
- terminates the list. The pairs are the
- arguments to UninstallProtocolInterface(). All
- the protocols are added to Handle.
-
- @return Status code
-
-**/
-EFI_STATUS
-EFIAPI
-CoreUninstallMultipleProtocolInterfaces (
- IN EFI_HANDLE Handle,
- ...
- );
-
-/**
- Reinstall a protocol interface on a device handle. The OldInterface for Protocol is replaced by the NewInterface.
-
- @param UserHandle Handle on which the interface is to be
- reinstalled
- @param Protocol The numeric ID of the interface
- @param OldInterface A pointer to the old interface
- @param NewInterface A pointer to the new interface
-
- @retval EFI_SUCCESS The protocol interface was installed
- @retval EFI_NOT_FOUND The OldInterface on the handle was not found
- @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value
-
-**/
-EFI_STATUS
-EFIAPI
-CoreReinstallProtocolInterface (
- IN EFI_HANDLE UserHandle,
- IN EFI_GUID *Protocol,
- IN VOID *OldInterface,
- IN VOID *NewInterface
- );
-
-/**
- Uninstalls all instances of a protocol:interfacer from a handle.
- If the last protocol interface is remove from the handle, the
- handle is freed.
-
- @param UserHandle The handle to remove the protocol handler from
- @param Protocol The protocol, of protocol:interface, to remove
- @param Interface The interface, of protocol:interface, to remove
-
- @retval EFI_INVALID_PARAMETER Protocol is NULL.
- @retval EFI_SUCCESS Protocol interface successfully uninstalled.
-
-**/
-EFI_STATUS
-EFIAPI
-CoreUninstallProtocolInterface (
- IN EFI_HANDLE UserHandle,
- IN EFI_GUID *Protocol,
- IN VOID *Interface
- );
-
-/**
- Queries a handle to determine if it supports a specified protocol.
-
- @param UserHandle The handle being queried.
- @param Protocol The published unique identifier of the protocol.
- @param Interface Supplies the address where a pointer to the
- corresponding Protocol Interface is returned.
-
- @return The requested protocol interface for the handle
-
-**/
-EFI_STATUS
-EFIAPI
-CoreHandleProtocol (
- IN EFI_HANDLE UserHandle,
- IN EFI_GUID *Protocol,
- OUT VOID **Interface
- );
-
-/**
- Locates the installed protocol handler for the handle, and
- invokes it to obtain the protocol interface. Usage information
- is registered in the protocol data base.
-
- @param UserHandle The handle to obtain the protocol interface on
- @param Protocol The ID of the protocol
- @param Interface The location to return the protocol interface
- @param ImageHandle The handle of the Image that is opening the
- protocol interface specified by Protocol and
- Interface.
- @param ControllerHandle The controller handle that is requiring this
- interface.
- @param Attributes The open mode of the protocol interface
- specified by Handle and Protocol.
-
- @retval EFI_INVALID_PARAMETER Protocol is NULL.
- @retval EFI_SUCCESS Get the protocol interface.
-
-**/
-EFI_STATUS
-EFIAPI
-CoreOpenProtocol (
- IN EFI_HANDLE UserHandle,
- IN EFI_GUID *Protocol,
- OUT VOID **Interface OPTIONAL,
- IN EFI_HANDLE ImageHandle,
- IN EFI_HANDLE ControllerHandle,
- IN UINT32 Attributes
- );
-
-/**
- Return information about Opened protocols in the system
-
- @param UserHandle The handle to close the protocol interface on
- @param Protocol The ID of the protocol
- @param EntryBuffer A pointer to a buffer of open protocol
- information in the form of
- EFI_OPEN_PROTOCOL_INFORMATION_ENTRY structures.
- @param EntryCount Number of EntryBuffer entries
-
-**/
-EFI_STATUS
-EFIAPI
-CoreOpenProtocolInformation (
- IN EFI_HANDLE UserHandle,
- IN EFI_GUID *Protocol,
- OUT EFI_OPEN_PROTOCOL_INFORMATION_ENTRY **EntryBuffer,
- OUT UINTN *EntryCount
- );
-
-/**
- Closes a protocol on a handle that was opened using OpenProtocol().
-
- @param UserHandle The handle for the protocol interface that was
- previously opened with OpenProtocol(), and is
- now being closed.
- @param Protocol The published unique identifier of the protocol.
- It is the caller's responsibility to pass in a
- valid GUID.
- @param AgentHandle The handle of the agent that is closing the
- protocol interface.
- @param ControllerHandle If the agent that opened a protocol is a driver
- that follows the EFI Driver Model, then this
- parameter is the controller handle that required
- the protocol interface. If the agent does not
- follow the EFI Driver Model, then this parameter
- is optional and may be NULL.
-
- @retval EFI_SUCCESS The protocol instance was closed.
- @retval EFI_INVALID_PARAMETER Handle, AgentHandle or ControllerHandle is not a
- valid EFI_HANDLE.
- @retval EFI_NOT_FOUND Can not find the specified protocol or
- AgentHandle.
-
-**/
-EFI_STATUS
-EFIAPI
-CoreCloseProtocol (
- IN EFI_HANDLE UserHandle,
- IN EFI_GUID *Protocol,
- IN EFI_HANDLE AgentHandle,
- IN EFI_HANDLE ControllerHandle
- );
-
-/**
- Retrieves the list of protocol interface GUIDs that are installed on a handle in a buffer allocated
- from pool.
-
- @param UserHandle The handle from which to retrieve the list of
- protocol interface GUIDs.
- @param ProtocolBuffer A pointer to the list of protocol interface GUID
- pointers that are installed on Handle.
- @param ProtocolBufferCount A pointer to the number of GUID pointers present
- in ProtocolBuffer.
-
- @retval EFI_SUCCESS The list of protocol interface GUIDs installed
- on Handle was returned in ProtocolBuffer. The
- number of protocol interface GUIDs was returned
- in ProtocolBufferCount.
- @retval EFI_INVALID_PARAMETER Handle is NULL.
- @retval EFI_INVALID_PARAMETER Handle is not a valid EFI_HANDLE.
- @retval EFI_INVALID_PARAMETER ProtocolBuffer is NULL.
- @retval EFI_INVALID_PARAMETER ProtocolBufferCount is NULL.
- @retval EFI_OUT_OF_RESOURCES There is not enough pool memory to store the
- results.
-
-**/
-EFI_STATUS
-EFIAPI
-CoreProtocolsPerHandle (
- IN EFI_HANDLE UserHandle,
- OUT EFI_GUID ***ProtocolBuffer,
- OUT UINTN *ProtocolBufferCount
- );
-
-/**
- Add a new protocol notification record for the request protocol.
-
- @param Protocol The requested protocol to add the notify
- registration
- @param Event The event to signal
- @param Registration Returns the registration record
-
- @retval EFI_INVALID_PARAMETER Invalid parameter
- @retval EFI_SUCCESS Successfully returned the registration record
- that has been added
-
-**/
-EFI_STATUS
-EFIAPI
-CoreRegisterProtocolNotify (
- IN EFI_GUID *Protocol,
- IN EFI_EVENT Event,
- OUT VOID **Registration
- );
-
-/**
- Removes all the events in the protocol database that match Event.
-
- @param Event The event to search for in the protocol
- database.
-
- @return EFI_SUCCESS when done searching the entire database.
-
-**/
-EFI_STATUS
-CoreUnregisterProtocolNotify (
- IN EFI_EVENT Event
- );
-
-/**
- Locates the requested handle(s) and returns them in Buffer.
-
- @param SearchType The type of search to perform to locate the
- handles
- @param Protocol The protocol to search for
- @param SearchKey Dependant on SearchType
- @param BufferSize On input the size of Buffer. On output the
- size of data returned.
- @param Buffer The buffer to return the results in
-
- @retval EFI_BUFFER_TOO_SMALL Buffer too small, required buffer size is
- returned in BufferSize.
- @retval EFI_INVALID_PARAMETER Invalid parameter
- @retval EFI_SUCCESS Successfully found the requested handle(s) and
- returns them in Buffer.
-
-**/
-EFI_STATUS
-EFIAPI
-CoreLocateHandle (
- IN EFI_LOCATE_SEARCH_TYPE SearchType,
- IN EFI_GUID *Protocol OPTIONAL,
- IN VOID *SearchKey OPTIONAL,
- IN OUT UINTN *BufferSize,
- OUT EFI_HANDLE *Buffer
- );
-
-/**
- Locates the handle to a device on the device path that best matches the specified protocol.
-
- @param Protocol The protocol to search for.
- @param DevicePath On input, a pointer to a pointer to the device
- path. On output, the device path pointer is
- modified to point to the remaining part of the
- devicepath.
- @param Device A pointer to the returned device handle.
-
- @retval EFI_SUCCESS The resulting handle was returned.
- @retval EFI_NOT_FOUND No handles matched the search.
- @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
-
-**/
-EFI_STATUS
-EFIAPI
-CoreLocateDevicePath (
- IN EFI_GUID *Protocol,
- IN OUT EFI_DEVICE_PATH_PROTOCOL **DevicePath,
- OUT EFI_HANDLE *Device
- );
-
-/**
- Function returns an array of handles that support the requested protocol
- in a buffer allocated from pool. This is a version of CoreLocateHandle()
- that allocates a buffer for the caller.
-
- @param SearchType Specifies which handle(s) are to be returned.
- @param Protocol Provides the protocol to search by. This
- parameter is only valid for SearchType
- ByProtocol.
- @param SearchKey Supplies the search key depending on the
- SearchType.
- @param NumberHandles The number of handles returned in Buffer.
- @param Buffer A pointer to the buffer to return the requested
- array of handles that support Protocol.
-
- @retval EFI_SUCCESS The result array of handles was returned.
- @retval EFI_NOT_FOUND No handles match the search.
- @retval EFI_OUT_OF_RESOURCES There is not enough pool memory to store the
- matching results.
- @retval EFI_INVALID_PARAMETER One or more parameters are not valid.
-
-**/
-EFI_STATUS
-EFIAPI
-CoreLocateHandleBuffer (
- IN EFI_LOCATE_SEARCH_TYPE SearchType,
- IN EFI_GUID *Protocol OPTIONAL,
- IN VOID *SearchKey OPTIONAL,
- IN OUT UINTN *NumberHandles,
- OUT EFI_HANDLE **Buffer
- );
-
-/**
- Return the first Protocol Interface that matches the Protocol GUID. If
- Registration is passed in, return a Protocol Instance that was just add
- to the system. If Registration is NULL return the first Protocol Interface
- you find.
-
- @param Protocol The protocol to search for
- @param Registration Optional Registration Key returned from
- RegisterProtocolNotify()
- @param Interface Return the Protocol interface (instance).
-
- @retval EFI_SUCCESS If a valid Interface is returned
- @retval EFI_INVALID_PARAMETER Invalid parameter
- @retval EFI_NOT_FOUND Protocol interface not found
-
-**/
-EFI_STATUS
-EFIAPI
-CoreLocateProtocol (
- IN EFI_GUID *Protocol,
- IN VOID *Registration OPTIONAL,
- OUT VOID **Interface
- );
-
-/**
- return handle database key.
-
-
- @return Handle database key.
-
-**/
-UINT64
-CoreGetHandleDatabaseKey (
- VOID
- );
-
-/**
- Go connect any handles that were created or modified while a image executed.
-
- @param Key The Key to show that the handle has been
- created/modified
-
-**/
-VOID
-CoreConnectHandlesByKey (
- UINT64 Key
- );
-
-/**
- Connects one or more drivers to a controller.
-
- @param ControllerHandle The handle of the controller to which driver(s) are to be connected.
- @param DriverImageHandle A pointer to an ordered list handles that support the
- EFI_DRIVER_BINDING_PROTOCOL.
- @param RemainingDevicePath A pointer to the device path that specifies a child of the
- controller specified by ControllerHandle.
- @param Recursive If TRUE, then ConnectController() is called recursively
- until the entire tree of controllers below the controller specified
- by ControllerHandle have been created. If FALSE, then
- the tree of controllers is only expanded one level.
-
- @retval EFI_SUCCESS 1) One or more drivers were connected to ControllerHandle.
- 2) No drivers were connected to ControllerHandle, but
- RemainingDevicePath is not NULL, and it is an End Device
- Path Node.
- @retval EFI_INVALID_PARAMETER ControllerHandle is NULL.
- @retval EFI_NOT_FOUND 1) There are no EFI_DRIVER_BINDING_PROTOCOL instances
- present in the system.
- 2) No drivers were connected to ControllerHandle.
- @retval EFI_SECURITY_VIOLATION
- The user has no permission to start UEFI device drivers on the device path
- associated with the ControllerHandle or specified by the RemainingDevicePath.
-
-**/
-EFI_STATUS
-EFIAPI
-CoreConnectController (
- IN EFI_HANDLE ControllerHandle,
- IN EFI_HANDLE *DriverImageHandle OPTIONAL,
- IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL,
- IN BOOLEAN Recursive
- );
-
-/**
- Disonnects a controller from a driver
-
- @param ControllerHandle ControllerHandle The handle of
- the controller from which
- driver(s) are to be
- disconnected.
- @param DriverImageHandle DriverImageHandle The driver to
- disconnect from ControllerHandle.
- @param ChildHandle ChildHandle The handle of the
- child to destroy.
-
- @retval EFI_SUCCESS One or more drivers were
- disconnected from the controller.
- @retval EFI_SUCCESS On entry, no drivers are managing
- ControllerHandle.
- @retval EFI_SUCCESS DriverImageHandle is not NULL,
- and on entry DriverImageHandle is
- not managing ControllerHandle.
- @retval EFI_INVALID_PARAMETER ControllerHandle is NULL.
- @retval EFI_INVALID_PARAMETER DriverImageHandle is not NULL,
- and it is not a valid EFI_HANDLE.
- @retval EFI_INVALID_PARAMETER ChildHandle is not NULL, and it
- is not a valid EFI_HANDLE.
- @retval EFI_OUT_OF_RESOURCES There are not enough resources
- available to disconnect any
- drivers from ControllerHandle.
- @retval EFI_DEVICE_ERROR The controller could not be
- disconnected because of a device
- error.
-
-**/
-EFI_STATUS
-EFIAPI
-CoreDisconnectController (
- IN EFI_HANDLE ControllerHandle,
- IN EFI_HANDLE DriverImageHandle OPTIONAL,
- IN EFI_HANDLE ChildHandle OPTIONAL
- );
-
-/**
- Allocates pages from the memory map.
-
- @param Type The type of allocation to perform
- @param MemoryType The type of memory to turn the allocated pages
- into
- @param NumberOfPages The number of pages to allocate
- @param Memory A pointer to receive the base allocated memory
- address
-
- @return Status. On success, Memory is filled in with the base address allocated
- @retval EFI_INVALID_PARAMETER Parameters violate checking rules defined in
- spec.
- @retval EFI_NOT_FOUND Could not allocate pages match the requirement.
- @retval EFI_OUT_OF_RESOURCES No enough pages to allocate.
- @retval EFI_SUCCESS Pages successfully allocated.
-
-**/
-EFI_STATUS
-EFIAPI
-CoreAllocatePages (
- IN EFI_ALLOCATE_TYPE Type,
- IN EFI_MEMORY_TYPE MemoryType,
- IN UINTN NumberOfPages,
- IN OUT EFI_PHYSICAL_ADDRESS *Memory
- );
-
-/**
- Frees previous allocated pages.
-
- @param Memory Base address of memory being freed
- @param NumberOfPages The number of pages to free
-
- @retval EFI_NOT_FOUND Could not find the entry that covers the range
- @retval EFI_INVALID_PARAMETER Address not aligned
- @return EFI_SUCCESS -Pages successfully freed.
-
-**/
-EFI_STATUS
-EFIAPI
-CoreFreePages (
- IN EFI_PHYSICAL_ADDRESS Memory,
- IN UINTN NumberOfPages
- );
-
-/**
- This function returns a copy of the current memory map. The map is an array of
- memory descriptors, each of which describes a contiguous block of memory.
-
- @param MemoryMapSize A pointer to the size, in bytes, of the
- MemoryMap buffer. On input, this is the size of
- the buffer allocated by the caller. On output,
- it is the size of the buffer returned by the
- firmware if the buffer was large enough, or the
- size of the buffer needed to contain the map if
- the buffer was too small.
- @param MemoryMap A pointer to the buffer in which firmware places
- the current memory map.
- @param MapKey A pointer to the location in which firmware
- returns the key for the current memory map.
- @param DescriptorSize A pointer to the location in which firmware
- returns the size, in bytes, of an individual
- EFI_MEMORY_DESCRIPTOR.
- @param DescriptorVersion A pointer to the location in which firmware
- returns the version number associated with the
- EFI_MEMORY_DESCRIPTOR.
-
- @retval EFI_SUCCESS The memory map was returned in the MemoryMap
- buffer.
- @retval EFI_BUFFER_TOO_SMALL The MemoryMap buffer was too small. The current
- buffer size needed to hold the memory map is
- returned in MemoryMapSize.
- @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
-
-**/
-EFI_STATUS
-EFIAPI
-CoreGetMemoryMap (
- IN OUT UINTN *MemoryMapSize,
- IN OUT EFI_MEMORY_DESCRIPTOR *MemoryMap,
- OUT UINTN *MapKey,
- OUT UINTN *DescriptorSize,
- OUT UINT32 *DescriptorVersion
- );
-
-/**
- Allocate pool of a particular type.
-
- @param PoolType Type of pool to allocate
- @param Size The amount of pool to allocate
- @param Buffer The address to return a pointer to the allocated
- pool
-
- @retval EFI_INVALID_PARAMETER PoolType not valid or Buffer is NULL
- @retval EFI_OUT_OF_RESOURCES Size exceeds max pool size or allocation failed.
- @retval EFI_SUCCESS Pool successfully allocated.
-
-**/
-EFI_STATUS
-EFIAPI
-CoreAllocatePool (
- IN EFI_MEMORY_TYPE PoolType,
- IN UINTN Size,
- OUT VOID **Buffer
- );
-
-/**
- Allocate pool of a particular type.
-
- @param PoolType Type of pool to allocate
- @param Size The amount of pool to allocate
- @param Buffer The address to return a pointer to the allocated
- pool
-
- @retval EFI_INVALID_PARAMETER PoolType not valid or Buffer is NULL
- @retval EFI_OUT_OF_RESOURCES Size exceeds max pool size or allocation failed.
- @retval EFI_SUCCESS Pool successfully allocated.
-
-**/
-EFI_STATUS
-EFIAPI
-CoreInternalAllocatePool (
- IN EFI_MEMORY_TYPE PoolType,
- IN UINTN Size,
- OUT VOID **Buffer
- );
-
-/**
- Frees pool.
-
- @param Buffer The allocated pool entry to free
-
- @retval EFI_INVALID_PARAMETER Buffer is not a valid value.
- @retval EFI_SUCCESS Pool successfully freed.
-
-**/
-EFI_STATUS
-EFIAPI
-CoreFreePool (
- IN VOID *Buffer
- );
-
-/**
- Frees pool.
-
- @param Buffer The allocated pool entry to free
- @param PoolType Pointer to pool type
-
- @retval EFI_INVALID_PARAMETER Buffer is not a valid value.
- @retval EFI_SUCCESS Pool successfully freed.
-
-**/
-EFI_STATUS
-EFIAPI
-CoreInternalFreePool (
- IN VOID *Buffer,
- OUT EFI_MEMORY_TYPE *PoolType OPTIONAL
- );
-
-/**
- Loads an EFI image into memory and returns a handle to the image.
-
- @param BootPolicy If TRUE, indicates that the request originates
- from the boot manager, and that the boot
- manager is attempting to load FilePath as a
- boot selection.
- @param ParentImageHandle The caller's image handle.
- @param FilePath The specific file path from which the image is
- loaded.
- @param SourceBuffer If not NULL, a pointer to the memory location
- containing a copy of the image to be loaded.
- @param SourceSize The size in bytes of SourceBuffer.
- @param ImageHandle Pointer to the returned image handle that is
- created when the image is successfully loaded.
-
- @retval EFI_SUCCESS The image was loaded into memory.
- @retval EFI_NOT_FOUND The FilePath was not found.
- @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
- @retval EFI_UNSUPPORTED The image type is not supported, or the device
- path cannot be parsed to locate the proper
- protocol for loading the file.
- @retval EFI_OUT_OF_RESOURCES Image was not loaded due to insufficient
- resources.
- @retval EFI_LOAD_ERROR Image was not loaded because the image format was corrupt or not
- understood.
- @retval EFI_DEVICE_ERROR Image was not loaded because the device returned a read error.
- @retval EFI_ACCESS_DENIED Image was not loaded because the platform policy prohibits the
- image from being loaded. NULL is returned in *ImageHandle.
- @retval EFI_SECURITY_VIOLATION Image was loaded and an ImageHandle was created with a
- valid EFI_LOADED_IMAGE_PROTOCOL. However, the current
- platform policy specifies that the image should not be started.
-
-**/
-EFI_STATUS
-EFIAPI
-CoreLoadImage (
- IN BOOLEAN BootPolicy,
- IN EFI_HANDLE ParentImageHandle,
- IN EFI_DEVICE_PATH_PROTOCOL *FilePath,
- IN VOID *SourceBuffer OPTIONAL,
- IN UINTN SourceSize,
- OUT EFI_HANDLE *ImageHandle
- );
-
-/**
- Unloads an image.
-
- @param ImageHandle Handle that identifies the image to be
- unloaded.
-
- @retval EFI_SUCCESS The image has been unloaded.
- @retval EFI_UNSUPPORTED The image has been started, and does not support
- unload.
- @retval EFI_INVALID_PARAMPETER ImageHandle is not a valid image handle.
-
-**/
-EFI_STATUS
-EFIAPI
-CoreUnloadImage (
- IN EFI_HANDLE ImageHandle
- );
-
-/**
- Transfer control to a loaded image's entry point.
-
- @param ImageHandle Handle of image to be started.
- @param ExitDataSize Pointer of the size to ExitData
- @param ExitData Pointer to a pointer to a data buffer that
- includes a Null-terminated string,
- optionally followed by additional binary data.
- The string is a description that the caller may
- use to further indicate the reason for the
- image's exit.
-
- @retval EFI_INVALID_PARAMETER Invalid parameter
- @retval EFI_OUT_OF_RESOURCES No enough buffer to allocate
- @retval EFI_SECURITY_VIOLATION The current platform policy specifies that the image should not be started.
- @retval EFI_SUCCESS Successfully transfer control to the image's
- entry point.
-
-**/
-EFI_STATUS
-EFIAPI
-CoreStartImage (
- IN EFI_HANDLE ImageHandle,
- OUT UINTN *ExitDataSize,
- OUT CHAR16 **ExitData OPTIONAL
- );
-
-/**
- Terminates the currently loaded EFI image and returns control to boot services.
-
- @param ImageHandle Handle that identifies the image. This
- parameter is passed to the image on entry.
- @param Status The image's exit code.
- @param ExitDataSize The size, in bytes, of ExitData. Ignored if
- ExitStatus is EFI_SUCCESS.
- @param ExitData Pointer to a data buffer that includes a
- Null-terminated Unicode string, optionally
- followed by additional binary data. The string
- is a description that the caller may use to
- further indicate the reason for the image's
- exit.
-
- @retval EFI_INVALID_PARAMETER Image handle is NULL or it is not current
- image.
- @retval EFI_SUCCESS Successfully terminates the currently loaded
- EFI image.
- @retval EFI_ACCESS_DENIED Should never reach there.
- @retval EFI_OUT_OF_RESOURCES Could not allocate pool
-
-**/
-EFI_STATUS
-EFIAPI
-CoreExit (
- IN EFI_HANDLE ImageHandle,
- IN EFI_STATUS Status,
- IN UINTN ExitDataSize,
- IN CHAR16 *ExitData OPTIONAL
- );
-
-/**
- Creates an event.
-
- @param Type The type of event to create and its mode and
- attributes
- @param NotifyTpl The task priority level of event notifications
- @param NotifyFunction Pointer to the events notification function
- @param NotifyContext Pointer to the notification functions context;
- corresponds to parameter "Context" in the
- notification function
- @param Event Pointer to the newly created event if the call
- succeeds; undefined otherwise
-
- @retval EFI_SUCCESS The event structure was created
- @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value
- @retval EFI_OUT_OF_RESOURCES The event could not be allocated
-
-**/
-EFI_STATUS
-EFIAPI
-CoreCreateEvent (
- IN UINT32 Type,
- IN EFI_TPL NotifyTpl,
- IN EFI_EVENT_NOTIFY NotifyFunction OPTIONAL,
- IN VOID *NotifyContext OPTIONAL,
- OUT EFI_EVENT *Event
- );
-
-/**
- Creates an event in a group.
-
- @param Type The type of event to create and its mode and
- attributes
- @param NotifyTpl The task priority level of event notifications
- @param NotifyFunction Pointer to the events notification function
- @param NotifyContext Pointer to the notification functions context;
- corresponds to parameter "Context" in the
- notification function
- @param EventGroup GUID for EventGroup if NULL act the same as
- gBS->CreateEvent().
- @param Event Pointer to the newly created event if the call
- succeeds; undefined otherwise
-
- @retval EFI_SUCCESS The event structure was created
- @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value
- @retval EFI_OUT_OF_RESOURCES The event could not be allocated
-
-**/
-EFI_STATUS
-EFIAPI
-CoreCreateEventEx (
- IN UINT32 Type,
- IN EFI_TPL NotifyTpl,
- IN EFI_EVENT_NOTIFY NotifyFunction OPTIONAL,
- IN CONST VOID *NotifyContext OPTIONAL,
- IN CONST EFI_GUID *EventGroup OPTIONAL,
- OUT EFI_EVENT *Event
- );
-
-/**
- Creates a general-purpose event structure
-
- @param Type The type of event to create and its mode and
- attributes
- @param NotifyTpl The task priority level of event notifications
- @param NotifyFunction Pointer to the events notification function
- @param NotifyContext Pointer to the notification functions context;
- corresponds to parameter "Context" in the
- notification function
- @param EventGroup GUID for EventGroup if NULL act the same as
- gBS->CreateEvent().
- @param Event Pointer to the newly created event if the call
- succeeds; undefined otherwise
-
- @retval EFI_SUCCESS The event structure was created
- @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value
- @retval EFI_OUT_OF_RESOURCES The event could not be allocated
-
-**/
-EFI_STATUS
-EFIAPI
-CoreCreateEventInternal (
- IN UINT32 Type,
- IN EFI_TPL NotifyTpl,
- IN EFI_EVENT_NOTIFY NotifyFunction OPTIONAL,
- IN CONST VOID *NotifyContext OPTIONAL,
- IN CONST EFI_GUID *EventGroup OPTIONAL,
- OUT EFI_EVENT *Event
- );
-
-/**
- Sets the type of timer and the trigger time for a timer event.
-
- @param UserEvent The timer event that is to be signaled at the
- specified time
- @param Type The type of time that is specified in
- TriggerTime
- @param TriggerTime The number of 100ns units until the timer
- expires
-
- @retval EFI_SUCCESS The event has been set to be signaled at the
- requested time
- @retval EFI_INVALID_PARAMETER Event or Type is not valid
-
-**/
-EFI_STATUS
-EFIAPI
-CoreSetTimer (
- IN EFI_EVENT UserEvent,
- IN EFI_TIMER_DELAY Type,
- IN UINT64 TriggerTime
- );
-
-/**
- Signals the event. Queues the event to be notified if needed.
-
- @param UserEvent The event to signal .
-
- @retval EFI_INVALID_PARAMETER Parameters are not valid.
- @retval EFI_SUCCESS The event was signaled.
-
-**/
-EFI_STATUS
-EFIAPI
-CoreSignalEvent (
- IN EFI_EVENT UserEvent
- );
-
-/**
- Stops execution until an event is signaled.
-
- @param NumberOfEvents The number of events in the UserEvents array
- @param UserEvents An array of EFI_EVENT
- @param UserIndex Pointer to the index of the event which
- satisfied the wait condition
-
- @retval EFI_SUCCESS The event indicated by Index was signaled.
- @retval EFI_INVALID_PARAMETER The event indicated by Index has a notification
- function or Event was not a valid type
- @retval EFI_UNSUPPORTED The current TPL is not TPL_APPLICATION
-
-**/
-EFI_STATUS
-EFIAPI
-CoreWaitForEvent (
- IN UINTN NumberOfEvents,
- IN EFI_EVENT *UserEvents,
- OUT UINTN *UserIndex
- );
-
-/**
- Closes an event and frees the event structure.
-
- @param UserEvent Event to close
-
- @retval EFI_INVALID_PARAMETER Parameters are not valid.
- @retval EFI_SUCCESS The event has been closed
-
-**/
-EFI_STATUS
-EFIAPI
-CoreCloseEvent (
- IN EFI_EVENT UserEvent
- );
-
-/**
- Check the status of an event.
-
- @param UserEvent The event to check
-
- @retval EFI_SUCCESS The event is in the signaled state
- @retval EFI_NOT_READY The event is not in the signaled state
- @retval EFI_INVALID_PARAMETER Event is of type EVT_NOTIFY_SIGNAL
-
-**/
-EFI_STATUS
-EFIAPI
-CoreCheckEvent (
- IN EFI_EVENT UserEvent
- );
-
-/**
- Adds reserved memory, system memory, or memory-mapped I/O resources to the
- global coherency domain of the processor.
-
- @param GcdMemoryType Memory type of the memory space.
- @param BaseAddress Base address of the memory space.
- @param Length Length of the memory space.
- @param Capabilities alterable attributes of the memory space.
-
- @retval EFI_SUCCESS Merged this memory space into GCD map.
-
-**/
-EFI_STATUS
-EFIAPI
-CoreAddMemorySpace (
- IN EFI_GCD_MEMORY_TYPE GcdMemoryType,
- IN EFI_PHYSICAL_ADDRESS BaseAddress,
- IN UINT64 Length,
- IN UINT64 Capabilities
- );
-
-/**
- Allocates nonexistent memory, reserved memory, system memory, or memorymapped
- I/O resources from the global coherency domain of the processor.
-
- @param GcdAllocateType The type of allocate operation
- @param GcdMemoryType The desired memory type
- @param Alignment Align with 2^Alignment
- @param Length Length to allocate
- @param BaseAddress Base address to allocate
- @param ImageHandle The image handle consume the allocated space.
- @param DeviceHandle The device handle consume the allocated space.
-
- @retval EFI_INVALID_PARAMETER Invalid parameter.
- @retval EFI_NOT_FOUND No descriptor contains the desired space.
- @retval EFI_SUCCESS Memory space successfully allocated.
-
-**/
-EFI_STATUS
-EFIAPI
-CoreAllocateMemorySpace (
- IN EFI_GCD_ALLOCATE_TYPE GcdAllocateType,
- IN EFI_GCD_MEMORY_TYPE GcdMemoryType,
- IN UINTN Alignment,
- IN UINT64 Length,
- IN OUT EFI_PHYSICAL_ADDRESS *BaseAddress,
- IN EFI_HANDLE ImageHandle,
- IN EFI_HANDLE DeviceHandle OPTIONAL
- );
-
-/**
- Frees nonexistent memory, reserved memory, system memory, or memory-mapped
- I/O resources from the global coherency domain of the processor.
-
- @param BaseAddress Base address of the memory space.
- @param Length Length of the memory space.
-
- @retval EFI_SUCCESS Space successfully freed.
-
-**/
-EFI_STATUS
-EFIAPI
-CoreFreeMemorySpace (
- IN EFI_PHYSICAL_ADDRESS BaseAddress,
- IN UINT64 Length
- );
-
-/**
- Removes reserved memory, system memory, or memory-mapped I/O resources from
- the global coherency domain of the processor.
-
- @param BaseAddress Base address of the memory space.
- @param Length Length of the memory space.
-
- @retval EFI_SUCCESS Successfully remove a segment of memory space.
-
-**/
-EFI_STATUS
-EFIAPI
-CoreRemoveMemorySpace (
- IN EFI_PHYSICAL_ADDRESS BaseAddress,
- IN UINT64 Length
- );
-
-/**
- Retrieves the descriptor for a memory region containing a specified address.
-
- @param BaseAddress Specified start address
- @param Descriptor Specified length
-
- @retval EFI_INVALID_PARAMETER Invalid parameter
- @retval EFI_SUCCESS Successfully get memory space descriptor.
-
-**/
-EFI_STATUS
-EFIAPI
-CoreGetMemorySpaceDescriptor (
- IN EFI_PHYSICAL_ADDRESS BaseAddress,
- OUT EFI_GCD_MEMORY_SPACE_DESCRIPTOR *Descriptor
- );
-
-/**
- Modifies the attributes for a memory region in the global coherency domain of the
- processor.
-
- @param BaseAddress Specified start address
- @param Length Specified length
- @param Attributes Specified attributes
-
- @retval EFI_SUCCESS The attributes were set for the memory region.
- @retval EFI_INVALID_PARAMETER Length is zero.
- @retval EFI_UNSUPPORTED The processor does not support one or more bytes of the memory
- resource range specified by BaseAddress and Length.
- @retval EFI_UNSUPPORTED The bit mask of attributes is not support for the memory resource
- range specified by BaseAddress and Length.
- @retval EFI_ACCESS_DENIED The attributes for the memory resource range specified by
- BaseAddress and Length cannot be modified.
- @retval EFI_OUT_OF_RESOURCES There are not enough system resources to modify the attributes of
- the memory resource range.
- @retval EFI_NOT_AVAILABLE_YET The attributes cannot be set because CPU architectural protocol is
- not available yet.
-
-**/
-EFI_STATUS
-EFIAPI
-CoreSetMemorySpaceAttributes (
- IN EFI_PHYSICAL_ADDRESS BaseAddress,
- IN UINT64 Length,
- IN UINT64 Attributes
- );
-
-/**
- Modifies the capabilities for a memory region in the global coherency domain of the
- processor.
-
- @param BaseAddress The physical address that is the start address of a memory region.
- @param Length The size in bytes of the memory region.
- @param Capabilities The bit mask of capabilities that the memory region supports.
-
- @retval EFI_SUCCESS The capabilities were set for the memory region.
- @retval EFI_INVALID_PARAMETER Length is zero.
- @retval EFI_UNSUPPORTED The capabilities specified by Capabilities do not include the
- memory region attributes currently in use.
- @retval EFI_ACCESS_DENIED The capabilities for the memory resource range specified by
- BaseAddress and Length cannot be modified.
- @retval EFI_OUT_OF_RESOURCES There are not enough system resources to modify the capabilities
- of the memory resource range.
-**/
-EFI_STATUS
-EFIAPI
-CoreSetMemorySpaceCapabilities (
- IN EFI_PHYSICAL_ADDRESS BaseAddress,
- IN UINT64 Length,
- IN UINT64 Capabilities
- );
-
-/**
- Returns a map of the memory resources in the global coherency domain of the
- processor.
-
- @param NumberOfDescriptors Number of descriptors.
- @param MemorySpaceMap Descriptor array
-
- @retval EFI_INVALID_PARAMETER Invalid parameter
- @retval EFI_OUT_OF_RESOURCES No enough buffer to allocate
- @retval EFI_SUCCESS Successfully get memory space map.
-
-**/
-EFI_STATUS
-EFIAPI
-CoreGetMemorySpaceMap (
- OUT UINTN *NumberOfDescriptors,
- OUT EFI_GCD_MEMORY_SPACE_DESCRIPTOR **MemorySpaceMap
- );
-
-/**
- Adds reserved I/O or I/O resources to the global coherency domain of the processor.
-
- @param GcdIoType IO type of the segment.
- @param BaseAddress Base address of the segment.
- @param Length Length of the segment.
-
- @retval EFI_SUCCESS Merged this segment into GCD map.
- @retval EFI_INVALID_PARAMETER Parameter not valid
-
-**/
-EFI_STATUS
-EFIAPI
-CoreAddIoSpace (
- IN EFI_GCD_IO_TYPE GcdIoType,
- IN EFI_PHYSICAL_ADDRESS BaseAddress,
- IN UINT64 Length
- );
-
-/**
- Allocates nonexistent I/O, reserved I/O, or I/O resources from the global coherency
- domain of the processor.
-
- @param GcdAllocateType The type of allocate operation
- @param GcdIoType The desired IO type
- @param Alignment Align with 2^Alignment
- @param Length Length to allocate
- @param BaseAddress Base address to allocate
- @param ImageHandle The image handle consume the allocated space.
- @param DeviceHandle The device handle consume the allocated space.
-
- @retval EFI_INVALID_PARAMETER Invalid parameter.
- @retval EFI_NOT_FOUND No descriptor contains the desired space.
- @retval EFI_SUCCESS IO space successfully allocated.
-
-**/
-EFI_STATUS
-EFIAPI
-CoreAllocateIoSpace (
- IN EFI_GCD_ALLOCATE_TYPE GcdAllocateType,
- IN EFI_GCD_IO_TYPE GcdIoType,
- IN UINTN Alignment,
- IN UINT64 Length,
- IN OUT EFI_PHYSICAL_ADDRESS *BaseAddress,
- IN EFI_HANDLE ImageHandle,
- IN EFI_HANDLE DeviceHandle OPTIONAL
- );
-
-/**
- Frees nonexistent I/O, reserved I/O, or I/O resources from the global coherency
- domain of the processor.
-
- @param BaseAddress Base address of the segment.
- @param Length Length of the segment.
-
- @retval EFI_SUCCESS Space successfully freed.
-
-**/
-EFI_STATUS
-EFIAPI
-CoreFreeIoSpace (
- IN EFI_PHYSICAL_ADDRESS BaseAddress,
- IN UINT64 Length
- );
-
-/**
- Removes reserved I/O or I/O resources from the global coherency domain of the
- processor.
-
- @param BaseAddress Base address of the segment.
- @param Length Length of the segment.
-
- @retval EFI_SUCCESS Successfully removed a segment of IO space.
-
-**/
-EFI_STATUS
-EFIAPI
-CoreRemoveIoSpace (
- IN EFI_PHYSICAL_ADDRESS BaseAddress,
- IN UINT64 Length
- );
-
-/**
- Retrieves the descriptor for an I/O region containing a specified address.
-
- @param BaseAddress Specified start address
- @param Descriptor Specified length
-
- @retval EFI_INVALID_PARAMETER Descriptor is NULL.
- @retval EFI_SUCCESS Successfully get the IO space descriptor.
-
-**/
-EFI_STATUS
-EFIAPI
-CoreGetIoSpaceDescriptor (
- IN EFI_PHYSICAL_ADDRESS BaseAddress,
- OUT EFI_GCD_IO_SPACE_DESCRIPTOR *Descriptor
- );
-
-/**
- Returns a map of the I/O resources in the global coherency domain of the processor.
-
- @param NumberOfDescriptors Number of descriptors.
- @param IoSpaceMap Descriptor array
-
- @retval EFI_INVALID_PARAMETER Invalid parameter
- @retval EFI_OUT_OF_RESOURCES No enough buffer to allocate
- @retval EFI_SUCCESS Successfully get IO space map.
-
-**/
-EFI_STATUS
-EFIAPI
-CoreGetIoSpaceMap (
- OUT UINTN *NumberOfDescriptors,
- OUT EFI_GCD_IO_SPACE_DESCRIPTOR **IoSpaceMap
- );
-
-/**
- This is the main Dispatcher for DXE and it exits when there are no more
- drivers to run. Drain the mScheduledQueue and load and start a PE
- image for each driver. Search the mDiscoveredList to see if any driver can
- be placed on the mScheduledQueue. If no drivers are placed on the
- mScheduledQueue exit the function. On exit it is assumed the Bds()
- will be called, and when the Bds() exits the Dispatcher will be called
- again.
-
- @retval EFI_ALREADY_STARTED The DXE Dispatcher is already running
- @retval EFI_NOT_FOUND No DXE Drivers were dispatched
- @retval EFI_SUCCESS One or more DXE Drivers were dispatched
-
-**/
-EFI_STATUS
-EFIAPI
-CoreDispatcher (
- VOID
- );
-
-/**
- Check every driver and locate a matching one. If the driver is found, the Unrequested
- state flag is cleared.
-
- @param FirmwareVolumeHandle The handle of the Firmware Volume that contains
- the firmware file specified by DriverName.
- @param DriverName The Driver name to put in the Dependent state.
-
- @retval EFI_SUCCESS The DriverName was found and it's SOR bit was
- cleared
- @retval EFI_NOT_FOUND The DriverName does not exist or it's SOR bit was
- not set.
-
-**/
-EFI_STATUS
-EFIAPI
-CoreSchedule (
- IN EFI_HANDLE FirmwareVolumeHandle,
- IN EFI_GUID *DriverName
- );
-
-/**
- Convert a driver from the Untrused back to the Scheduled state.
-
- @param FirmwareVolumeHandle The handle of the Firmware Volume that contains
- the firmware file specified by DriverName.
- @param DriverName The Driver name to put in the Scheduled state
-
- @retval EFI_SUCCESS The file was found in the untrusted state, and it
- was promoted to the trusted state.
- @retval EFI_NOT_FOUND The file was not found in the untrusted state.
-
-**/
-EFI_STATUS
-EFIAPI
-CoreTrust (
- IN EFI_HANDLE FirmwareVolumeHandle,
- IN EFI_GUID *DriverName
- );
-
-/**
- This routine is the driver initialization entry point. It initializes the
- libraries, and registers two notification functions. These notification
- functions are responsible for building the FV stack dynamically.
-
- @param ImageHandle The image handle.
- @param SystemTable The system table.
-
- @retval EFI_SUCCESS Function successfully returned.
-
-**/
-EFI_STATUS
-EFIAPI
-FwVolDriverInit (
- IN EFI_HANDLE ImageHandle,
- IN EFI_SYSTEM_TABLE *SystemTable
- );
-
-/**
- Entry point of the section extraction code. Initializes an instance of the
- section extraction interface and installs it on a new handle.
-
- @param ImageHandle A handle for the image that is initializing this driver
- @param SystemTable A pointer to the EFI system table
-
- @retval EFI_SUCCESS Driver initialized successfully
- @retval EFI_OUT_OF_RESOURCES Could not allocate needed resources
-
-**/
-EFI_STATUS
-EFIAPI
-InitializeSectionExtraction (
- IN EFI_HANDLE ImageHandle,
- IN EFI_SYSTEM_TABLE *SystemTable
- );
-
-/**
- This DXE service routine is used to process a firmware volume. In
- particular, it can be called by BDS to process a single firmware
- volume found in a capsule.
-
- @param FvHeader pointer to a firmware volume header
- @param Size the size of the buffer pointed to by FvHeader
- @param FVProtocolHandle the handle on which a firmware volume protocol
- was produced for the firmware volume passed in.
-
- @retval EFI_OUT_OF_RESOURCES if an FVB could not be produced due to lack of
- system resources
- @retval EFI_VOLUME_CORRUPTED if the volume was corrupted
- @retval EFI_SUCCESS a firmware volume protocol was produced for the
- firmware volume
-
-**/
-EFI_STATUS
-EFIAPI
-CoreProcessFirmwareVolume (
- IN VOID *FvHeader,
- IN UINTN Size,
- OUT EFI_HANDLE *FVProtocolHandle
- );
-
-//
-// Functions used during debug buils
-//
-
-/**
- Displays Architectural protocols that were not loaded and are required for DXE
- core to function. Only used in Debug Builds.
-
-**/
-VOID
-CoreDisplayMissingArchProtocols (
- VOID
- );
-
-/**
- Traverse the discovered list for any drivers that were discovered but not loaded
- because the dependency experessions evaluated to false.
-
-**/
-VOID
-CoreDisplayDiscoveredNotDispatched (
- VOID
- );
-
-/**
- Place holder function until all the Boot Services and Runtime Services are
- available.
-
- @param Arg1 Undefined
-
- @return EFI_NOT_AVAILABLE_YET
-
-**/
-EFI_STATUS
-EFIAPI
-CoreEfiNotAvailableYetArg1 (
- UINTN Arg1
- );
-
-/**
- Place holder function until all the Boot Services and Runtime Services are available.
-
- @param Arg1 Undefined
- @param Arg2 Undefined
-
- @return EFI_NOT_AVAILABLE_YET
-
-**/
-EFI_STATUS
-EFIAPI
-CoreEfiNotAvailableYetArg2 (
- UINTN Arg1,
- UINTN Arg2
- );
-
-/**
- Place holder function until all the Boot Services and Runtime Services are available.
-
- @param Arg1 Undefined
- @param Arg2 Undefined
- @param Arg3 Undefined
-
- @return EFI_NOT_AVAILABLE_YET
-
-**/
-EFI_STATUS
-EFIAPI
-CoreEfiNotAvailableYetArg3 (
- UINTN Arg1,
- UINTN Arg2,
- UINTN Arg3
- );
-
-/**
- Place holder function until all the Boot Services and Runtime Services are available.
-
- @param Arg1 Undefined
- @param Arg2 Undefined
- @param Arg3 Undefined
- @param Arg4 Undefined
-
- @return EFI_NOT_AVAILABLE_YET
-
-**/
-EFI_STATUS
-EFIAPI
-CoreEfiNotAvailableYetArg4 (
- UINTN Arg1,
- UINTN Arg2,
- UINTN Arg3,
- UINTN Arg4
- );
-
-/**
- Place holder function until all the Boot Services and Runtime Services are available.
-
- @param Arg1 Undefined
- @param Arg2 Undefined
- @param Arg3 Undefined
- @param Arg4 Undefined
- @param Arg5 Undefined
-
- @return EFI_NOT_AVAILABLE_YET
-
-**/
-EFI_STATUS
-EFIAPI
-CoreEfiNotAvailableYetArg5 (
- UINTN Arg1,
- UINTN Arg2,
- UINTN Arg3,
- UINTN Arg4,
- UINTN Arg5
- );
-
-/**
- Given a compressed source buffer, this function retrieves the size of the
- uncompressed buffer and the size of the scratch buffer required to decompress
- the compressed source buffer.
-
- The GetInfo() function retrieves the size of the uncompressed buffer and the
- temporary scratch buffer required to decompress the buffer specified by Source
- and SourceSize. If the size of the uncompressed buffer or the size of the
- scratch buffer cannot be determined from the compressed data specified by
- Source and SourceData, then EFI_INVALID_PARAMETER is returned. Otherwise, the
- size of the uncompressed buffer is returned in DestinationSize, the size of
- the scratch buffer is returned in ScratchSize, and EFI_SUCCESS is returned.
- The GetInfo() function does not have scratch buffer available to perform a
- thorough checking of the validity of the source data. It just retrieves the
- "Original Size" field from the beginning bytes of the source data and output
- it as DestinationSize. And ScratchSize is specific to the decompression
- implementation.
-
- @param This A pointer to the EFI_DECOMPRESS_PROTOCOL instance.
- @param Source The source buffer containing the compressed data.
- @param SourceSize The size, in bytes, of the source buffer.
- @param DestinationSize A pointer to the size, in bytes, of the
- uncompressed buffer that will be generated when the
- compressed buffer specified by Source and
- SourceSize is decompressed.
- @param ScratchSize A pointer to the size, in bytes, of the scratch
- buffer that is required to decompress the
- compressed buffer specified by Source and
- SourceSize.
-
- @retval EFI_SUCCESS The size of the uncompressed data was returned in
- DestinationSize and the size of the scratch buffer
- was returned in ScratchSize.
- @retval EFI_INVALID_PARAMETER The size of the uncompressed data or the size of
- the scratch buffer cannot be determined from the
- compressed data specified by Source and
- SourceSize.
-
-**/
-EFI_STATUS
-EFIAPI
-DxeMainUefiDecompressGetInfo (
- IN EFI_DECOMPRESS_PROTOCOL *This,
- IN VOID *Source,
- IN UINT32 SourceSize,
- OUT UINT32 *DestinationSize,
- OUT UINT32 *ScratchSize
- );
-
-/**
- Decompresses a compressed source buffer.
-
- The Decompress() function extracts decompressed data to its original form.
- This protocol is designed so that the decompression algorithm can be
- implemented without using any memory services. As a result, the Decompress()
- Function is not allowed to call AllocatePool() or AllocatePages() in its
- implementation. It is the caller's responsibility to allocate and free the
- Destination and Scratch buffers.
- If the compressed source data specified by Source and SourceSize is
- sucessfully decompressed into Destination, then EFI_SUCCESS is returned. If
- the compressed source data specified by Source and SourceSize is not in a
- valid compressed data format, then EFI_INVALID_PARAMETER is returned.
-
- @param This A pointer to the EFI_DECOMPRESS_PROTOCOL instance.
- @param Source The source buffer containing the compressed data.
- @param SourceSize SourceSizeThe size of source data.
- @param Destination On output, the destination buffer that contains
- the uncompressed data.
- @param DestinationSize The size of the destination buffer. The size of
- the destination buffer needed is obtained from
- EFI_DECOMPRESS_PROTOCOL.GetInfo().
- @param Scratch A temporary scratch buffer that is used to perform
- the decompression.
- @param ScratchSize The size of scratch buffer. The size of the
- scratch buffer needed is obtained from GetInfo().
-
- @retval EFI_SUCCESS Decompression completed successfully, and the
- uncompressed buffer is returned in Destination.
- @retval EFI_INVALID_PARAMETER The source buffer specified by Source and
- SourceSize is corrupted (not in a valid
- compressed format).
-
-**/
-EFI_STATUS
-EFIAPI
-DxeMainUefiDecompress (
- IN EFI_DECOMPRESS_PROTOCOL *This,
- IN VOID *Source,
- IN UINT32 SourceSize,
- IN OUT VOID *Destination,
- IN UINT32 DestinationSize,
- IN OUT VOID *Scratch,
- IN UINT32 ScratchSize
- );
-
-/**
- SEP member function. This function creates and returns a new section stream
- handle to represent the new section stream.
-
- @param SectionStreamLength Size in bytes of the section stream.
- @param SectionStream Buffer containing the new section stream.
- @param SectionStreamHandle A pointer to a caller allocated UINTN that on
- output contains the new section stream handle.
-
- @retval EFI_SUCCESS The section stream is created successfully.
- @retval EFI_OUT_OF_RESOURCES memory allocation failed.
- @retval EFI_INVALID_PARAMETER Section stream does not end concident with end
- of last section.
-
-**/
-EFI_STATUS
-EFIAPI
-OpenSectionStream (
- IN UINTN SectionStreamLength,
- IN VOID *SectionStream,
- OUT UINTN *SectionStreamHandle
- );
-
-/**
- SEP member function. Retrieves requested section from section stream.
-
- @param SectionStreamHandle The section stream from which to extract the
- requested section.
- @param SectionType A pointer to the type of section to search for.
- @param SectionDefinitionGuid If the section type is EFI_SECTION_GUID_DEFINED,
- then SectionDefinitionGuid indicates which of
- these types of sections to search for.
- @param SectionInstance Indicates which instance of the requested
- section to return.
- @param Buffer Double indirection to buffer. If *Buffer is
- non-null on input, then the buffer is caller
- allocated. If Buffer is NULL, then the buffer
- is callee allocated. In either case, the
- required buffer size is returned in *BufferSize.
- @param BufferSize On input, indicates the size of *Buffer if
- *Buffer is non-null on input. On output,
- indicates the required size (allocated size if
- callee allocated) of *Buffer.
- @param AuthenticationStatus A pointer to a caller-allocated UINT32 that
- indicates the authentication status of the
- output buffer. If the input section's
- GuidedSectionHeader.Attributes field
- has the EFI_GUIDED_SECTION_AUTH_STATUS_VALID
- bit as clear, AuthenticationStatus must return
- zero. Both local bits (19:16) and aggregate
- bits (3:0) in AuthenticationStatus are returned
- by ExtractSection(). These bits reflect the
- status of the extraction operation. The bit
- pattern in both regions must be the same, as
- the local and aggregate authentication statuses
- have equivalent meaning at this level. If the
- function returns anything other than
- EFI_SUCCESS, the value of *AuthenticationStatus
- is undefined.
- @param IsFfs3Fv Indicates the FV format.
-
- @retval EFI_SUCCESS Section was retrieved successfully
- @retval EFI_PROTOCOL_ERROR A GUID defined section was encountered in the
- section stream with its
- EFI_GUIDED_SECTION_PROCESSING_REQUIRED bit set,
- but there was no corresponding GUIDed Section
- Extraction Protocol in the handle database.
- *Buffer is unmodified.
- @retval EFI_NOT_FOUND An error was encountered when parsing the
- SectionStream. This indicates the SectionStream
- is not correctly formatted.
- @retval EFI_NOT_FOUND The requested section does not exist.
- @retval EFI_OUT_OF_RESOURCES The system has insufficient resources to process
- the request.
- @retval EFI_INVALID_PARAMETER The SectionStreamHandle does not exist.
- @retval EFI_WARN_TOO_SMALL The size of the caller allocated input buffer is
- insufficient to contain the requested section.
- The input buffer is filled and section contents
- are truncated.
-
-**/
-EFI_STATUS
-EFIAPI
-GetSection (
- IN UINTN SectionStreamHandle,
- IN EFI_SECTION_TYPE *SectionType,
- IN EFI_GUID *SectionDefinitionGuid,
- IN UINTN SectionInstance,
- IN VOID **Buffer,
- IN OUT UINTN *BufferSize,
- OUT UINT32 *AuthenticationStatus,
- IN BOOLEAN IsFfs3Fv
- );
-
-/**
- SEP member function. Deletes an existing section stream
-
- @param StreamHandleToClose Indicates the stream to close
- @param FreeStreamBuffer TRUE - Need to free stream buffer;
- FALSE - No need to free stream buffer.
-
- @retval EFI_SUCCESS The section stream is closed sucessfully.
- @retval EFI_OUT_OF_RESOURCES Memory allocation failed.
- @retval EFI_INVALID_PARAMETER Section stream does not end concident with end
- of last section.
-
-**/
-EFI_STATUS
-EFIAPI
-CloseSectionStream (
- IN UINTN StreamHandleToClose,
- IN BOOLEAN FreeStreamBuffer
- );
-
-/**
- Creates and initializes the DebugImageInfo Table. Also creates the configuration
- table and registers it into the system table.
-
- Note:
- This function allocates memory, frees it, and then allocates memory at an
- address within the initial allocation. Since this function is called early
- in DXE core initialization (before drivers are dispatched), this should not
- be a problem.
-
-**/
-VOID
-CoreInitializeDebugImageInfoTable (
- VOID
- );
-
-/**
- Update the CRC32 in the Debug Table.
- Since the CRC32 service is made available by the Runtime driver, we have to
- wait for the Runtime Driver to be installed before the CRC32 can be computed.
- This function is called elsewhere by the core when the runtime architectural
- protocol is produced.
-
-**/
-VOID
-CoreUpdateDebugTableCrc32 (
- VOID
- );
-
-/**
- Adds a new DebugImageInfo structure to the DebugImageInfo Table. Re-Allocates
- the table if it's not large enough to accomidate another entry.
-
- @param ImageInfoType type of debug image information
- @param LoadedImage pointer to the loaded image protocol for the image being
- loaded
- @param ImageHandle image handle for the image being loaded
-
-**/
-VOID
-CoreNewDebugImageInfoEntry (
- IN UINT32 ImageInfoType,
- IN EFI_LOADED_IMAGE_PROTOCOL *LoadedImage,
- IN EFI_HANDLE ImageHandle
- );
-
-/**
- Removes and frees an entry from the DebugImageInfo Table.
-
- @param ImageHandle image handle for the image being unloaded
-
-**/
-VOID
-CoreRemoveDebugImageInfoEntry (
- EFI_HANDLE ImageHandle
- );
-
-/**
- This routine consumes FV hobs and produces instances of FW_VOL_BLOCK_PROTOCOL as appropriate.
-
- @param ImageHandle The image handle.
- @param SystemTable The system table.
-
- @retval EFI_SUCCESS Successfully initialized firmware volume block
- driver.
-
-**/
-EFI_STATUS
-EFIAPI
-FwVolBlockDriverInit (
- IN EFI_HANDLE ImageHandle,
- IN EFI_SYSTEM_TABLE *SystemTable
- );
-
-/**
-
- Get FVB authentication status
-
- @param FvbProtocol FVB protocol.
-
- @return Authentication status.
-
-**/
-UINT32
-GetFvbAuthenticationStatus (
- IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *FvbProtocol
- );
-
-/**
- This routine produces a firmware volume block protocol on a given
- buffer.
-
- @param BaseAddress base address of the firmware volume image
- @param Length length of the firmware volume image
- @param ParentHandle handle of parent firmware volume, if this image
- came from an FV image file and section in another firmware
- volume (ala capsules)
- @param AuthenticationStatus Authentication status inherited, if this image
- came from an FV image file and section in another firmware volume.
- @param FvProtocol Firmware volume block protocol produced.
-
- @retval EFI_VOLUME_CORRUPTED Volume corrupted.
- @retval EFI_OUT_OF_RESOURCES No enough buffer to be allocated.
- @retval EFI_SUCCESS Successfully produced a FVB protocol on given
- buffer.
-
-**/
-EFI_STATUS
-ProduceFVBProtocolOnBuffer (
- IN EFI_PHYSICAL_ADDRESS BaseAddress,
- IN UINT64 Length,
- IN EFI_HANDLE ParentHandle,
- IN UINT32 AuthenticationStatus,
- OUT EFI_HANDLE *FvProtocol OPTIONAL
- );
-
-/**
- Raising to the task priority level of the mutual exclusion
- lock, and then acquires ownership of the lock.
-
- @param Lock The lock to acquire
-
- @return Lock owned
-
-**/
-VOID
-CoreAcquireLock (
- IN EFI_LOCK *Lock
- );
-
-/**
- Initialize a basic mutual exclusion lock. Each lock
- provides mutual exclusion access at it's task priority
- level. Since there is no-premption (at any TPL) or
- multiprocessor support, acquiring the lock only consists
- of raising to the locks TPL.
-
- @param Lock The EFI_LOCK structure to initialize
-
- @retval EFI_SUCCESS Lock Owned.
- @retval EFI_ACCESS_DENIED Reentrant Lock Acquisition, Lock not Owned.
-
-**/
-EFI_STATUS
-CoreAcquireLockOrFail (
- IN EFI_LOCK *Lock
- );
-
-/**
- Releases ownership of the mutual exclusion lock, and
- restores the previous task priority level.
-
- @param Lock The lock to release
-
- @return Lock unowned
-
-**/
-VOID
-CoreReleaseLock (
- IN EFI_LOCK *Lock
- );
-
-/**
- Read data from Firmware Block by FVB protocol Read.
- The data may cross the multi block ranges.
-
- @param Fvb The FW_VOL_BLOCK_PROTOCOL instance from which to read data.
- @param StartLba Pointer to StartLba.
- On input, the start logical block index from which to read.
- On output,the end logical block index after reading.
- @param Offset Pointer to Offset
- On input, offset into the block at which to begin reading.
- On output, offset into the end block after reading.
- @param DataSize Size of data to be read.
- @param Data Pointer to Buffer that the data will be read into.
-
- @retval EFI_SUCCESS Successfully read data from firmware block.
- @retval others
-**/
-EFI_STATUS
-ReadFvbData (
- IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb,
- IN OUT EFI_LBA *StartLba,
- IN OUT UINTN *Offset,
- IN UINTN DataSize,
- OUT UINT8 *Data
- );
-
-/**
- Given the supplied FW_VOL_BLOCK_PROTOCOL, allocate a buffer for output and
- copy the real length volume header into it.
-
- @param Fvb The FW_VOL_BLOCK_PROTOCOL instance from which to
- read the volume header
- @param FwVolHeader Pointer to pointer to allocated buffer in which
- the volume header is returned.
-
- @retval EFI_OUT_OF_RESOURCES No enough buffer could be allocated.
- @retval EFI_SUCCESS Successfully read volume header to the allocated
- buffer.
- @retval EFI_INVALID_PARAMETER The FV Header signature is not as expected or
- the file system could not be understood.
-
-**/
-EFI_STATUS
-GetFwVolHeader (
- IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb,
- OUT EFI_FIRMWARE_VOLUME_HEADER **FwVolHeader
- );
-
-/**
- Verify checksum of the firmware volume header.
-
- @param FvHeader Points to the firmware volume header to be checked
-
- @retval TRUE Checksum verification passed
- @retval FALSE Checksum verification failed
-
-**/
-BOOLEAN
-VerifyFvHeaderChecksum (
- IN EFI_FIRMWARE_VOLUME_HEADER *FvHeader
- );
-
-/**
- Initialize memory profile.
-
- @param HobStart The start address of the HOB.
-
-**/
-VOID
-MemoryProfileInit (
- IN VOID *HobStart
- );
-
-/**
- Install memory profile protocol.
-
-**/
-VOID
-MemoryProfileInstallProtocol (
- VOID
- );
-
-/**
- Register image to memory profile.
-
- @param DriverEntry Image info.
- @param FileType Image file type.
-
- @return EFI_SUCCESS Register successfully.
- @return EFI_UNSUPPORTED Memory profile unsupported,
- or memory profile for the image is not required.
- @return EFI_OUT_OF_RESOURCES No enough resource for this register.
-
-**/
-EFI_STATUS
-RegisterMemoryProfileImage (
- IN LOADED_IMAGE_PRIVATE_DATA *DriverEntry,
- IN EFI_FV_FILETYPE FileType
- );
-
-/**
- Unregister image from memory profile.
-
- @param DriverEntry Image info.
-
- @return EFI_SUCCESS Unregister successfully.
- @return EFI_UNSUPPORTED Memory profile unsupported,
- or memory profile for the image is not required.
- @return EFI_NOT_FOUND The image is not found.
-
-**/
-EFI_STATUS
-UnregisterMemoryProfileImage (
- IN LOADED_IMAGE_PRIVATE_DATA *DriverEntry
- );
-
-/**
- Update memory profile information.
-
- @param CallerAddress Address of caller who call Allocate or Free.
- @param Action This Allocate or Free action.
- @param MemoryType Memory type.
- EfiMaxMemoryType means the MemoryType is unknown.
- @param Size Buffer size.
- @param Buffer Buffer address.
- @param ActionString String for memory profile action.
- Only needed for user defined allocate action.
-
- @return EFI_SUCCESS Memory profile is updated.
- @return EFI_UNSUPPORTED Memory profile is unsupported,
- or memory profile for the image is not required,
- or memory profile for the memory type is not required.
- @return EFI_ACCESS_DENIED It is during memory profile data getting.
- @return EFI_ABORTED Memory profile recording is not enabled.
- @return EFI_OUT_OF_RESOURCES No enough resource to update memory profile for allocate action.
- @return EFI_NOT_FOUND No matched allocate info found for free action.
-
-**/
-EFI_STATUS
-EFIAPI
-CoreUpdateProfile (
- IN EFI_PHYSICAL_ADDRESS CallerAddress,
- IN MEMORY_PROFILE_ACTION Action,
- IN EFI_MEMORY_TYPE MemoryType,
- IN UINTN Size, // Valid for AllocatePages/FreePages/AllocatePool
- IN VOID *Buffer,
- IN CHAR8 *ActionString OPTIONAL
- );
-
-/**
- Internal function. Converts a memory range to use new attributes.
-
- @param Start The first address of the range Must be page
- aligned
- @param NumberOfPages The number of pages to convert
- @param NewAttributes The new attributes value for the range.
-
-**/
-VOID
-CoreUpdateMemoryAttributes (
- IN EFI_PHYSICAL_ADDRESS Start,
- IN UINT64 NumberOfPages,
- IN UINT64 NewAttributes
- );
-
-/**
- Initialize MemoryAttrubutesTable support.
-**/
-VOID
-EFIAPI
-CoreInitializeMemoryAttributesTable (
- VOID
- );
-
-/**
- Initialize Memory Protection support.
-**/
-VOID
-EFIAPI
-CoreInitializeMemoryProtection (
- VOID
- );
-
-/**
- Install MemoryAttributesTable on memory allocation.
-
- @param[in] MemoryType EFI memory type.
-**/
-VOID
-InstallMemoryAttributesTableOnMemoryAllocation (
- IN EFI_MEMORY_TYPE MemoryType
- );
-
-/**
- Insert image record.
-
- @param RuntimeImage Runtime image information
-**/
-VOID
-InsertImageRecord (
- IN EFI_RUNTIME_IMAGE_ENTRY *RuntimeImage
- );
-
-/**
- Remove Image record.
-
- @param RuntimeImage Runtime image information
-**/
-VOID
-RemoveImageRecord (
- IN EFI_RUNTIME_IMAGE_ENTRY *RuntimeImage
- );
-
-/**
- Protect UEFI image.
-
- @param[in] LoadedImage The loaded image protocol
- @param[in] LoadedImageDevicePath The loaded image device path protocol
-**/
-VOID
-ProtectUefiImage (
- IN EFI_LOADED_IMAGE_PROTOCOL *LoadedImage,
- IN EFI_DEVICE_PATH_PROTOCOL *LoadedImageDevicePath
- );
-
-/**
- Unprotect UEFI image.
-
- @param[in] LoadedImage The loaded image protocol
- @param[in] LoadedImageDevicePath The loaded image device path protocol
-**/
-VOID
-UnprotectUefiImage (
- IN EFI_LOADED_IMAGE_PROTOCOL *LoadedImage,
- IN EFI_DEVICE_PATH_PROTOCOL *LoadedImageDevicePath
- );
-
-/**
- ExitBootServices Callback function for memory protection.
-**/
-VOID
-MemoryProtectionExitBootServicesCallback (
- VOID
- );
-
-/**
- Manage memory permission attributes on a memory range, according to the
- configured DXE memory protection policy.
-
- @param OldType The old memory type of the range
- @param NewType The new memory type of the range
- @param Memory The base address of the range
- @param Length The size of the range (in bytes)
-
- @return EFI_SUCCESS If the the CPU arch protocol is not installed yet
- @return EFI_SUCCESS If no DXE memory protection policy has been configured
- @return EFI_SUCCESS If OldType and NewType use the same permission attributes
- @return other Return value of gCpu->SetMemoryAttributes()
-
-**/
-EFI_STATUS
-EFIAPI
-ApplyMemoryProtectionPolicy (
- IN EFI_MEMORY_TYPE OldType,
- IN EFI_MEMORY_TYPE NewType,
- IN EFI_PHYSICAL_ADDRESS Memory,
- IN UINT64 Length
- );
-
-/**
- Merge continous memory map entries whose have same attributes.
-
- @param MemoryMap A pointer to the buffer in which firmware places
- the current memory map.
- @param MemoryMapSize A pointer to the size, in bytes, of the
- MemoryMap buffer. On input, this is the size of
- the current memory map. On output,
- it is the size of new memory map after merge.
- @param DescriptorSize Size, in bytes, of an individual EFI_MEMORY_DESCRIPTOR.
-**/
-VOID
-MergeMemoryMap (
- IN OUT EFI_MEMORY_DESCRIPTOR *MemoryMap,
- IN OUT UINTN *MemoryMapSize,
- IN UINTN DescriptorSize
- );
-
-#endif
+/** @file
+ The internal header file includes the common header files, defines
+ internal structure and functions used by DxeCore module.
+
+Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _DXE_MAIN_H_
+#define _DXE_MAIN_H_
+
+#include <PiDxe.h>
+
+#include <Protocol/LoadedImage.h>
+#include <Protocol/GuidedSectionExtraction.h>
+#include <Protocol/DevicePath.h>
+#include <Protocol/Runtime.h>
+#include <Protocol/LoadFile.h>
+#include <Protocol/LoadFile2.h>
+#include <Protocol/DriverBinding.h>
+#include <Protocol/VariableWrite.h>
+#include <Protocol/PlatformDriverOverride.h>
+#include <Protocol/Variable.h>
+#include <Protocol/Timer.h>
+#include <Protocol/SimpleFileSystem.h>
+#include <Protocol/Bds.h>
+#include <Protocol/RealTimeClock.h>
+#include <Protocol/WatchdogTimer.h>
+#include <Protocol/FirmwareVolume2.h>
+#include <Protocol/MonotonicCounter.h>
+#include <Protocol/StatusCode.h>
+#include <Protocol/Decompress.h>
+#include <Protocol/LoadPe32Image.h>
+#include <Protocol/Security.h>
+#include <Protocol/Security2.h>
+#include <Protocol/Reset.h>
+#include <Protocol/Cpu.h>
+#include <Protocol/Metronome.h>
+#include <Protocol/FirmwareVolumeBlock.h>
+#include <Protocol/Capsule.h>
+#include <Protocol/BusSpecificDriverOverride.h>
+#include <Protocol/DriverFamilyOverride.h>
+#include <Protocol/TcgService.h>
+#include <Protocol/HiiPackageList.h>
+#include <Protocol/SmmBase2.h>
+#include <Protocol/PeCoffImageEmulator.h>
+#include <Guid/MemoryTypeInformation.h>
+#include <Guid/FirmwareFileSystem2.h>
+#include <Guid/FirmwareFileSystem3.h>
+#include <Guid/HobList.h>
+#include <Guid/DebugImageInfoTable.h>
+#include <Guid/FileInfo.h>
+#include <Guid/Apriori.h>
+#include <Guid/DxeServices.h>
+#include <Guid/MemoryAllocationHob.h>
+#include <Guid/EventLegacyBios.h>
+#include <Guid/EventGroup.h>
+#include <Guid/EventExitBootServiceFailed.h>
+#include <Guid/LoadModuleAtFixedAddress.h>
+#include <Guid/IdleLoopEvent.h>
+#include <Guid/VectorHandoffTable.h>
+#include <Ppi/VectorHandoffInfo.h>
+#include <Guid/MemoryProfile.h>
+
+#include <Library/DxeCoreEntryPoint.h>
+#include <Library/DebugLib.h>
+#include <Library/UefiLib.h>
+#include <Library/BaseLib.h>
+#include <Library/HobLib.h>
+#include <Library/PerformanceLib.h>
+#include <Library/UefiDecompressLib.h>
+#include <Library/ExtractGuidedSectionLib.h>
+#include <Library/CacheMaintenanceLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/PeCoffLib.h>
+#include <Library/PeCoffGetEntryPointLib.h>
+#include <Library/PeCoffExtraActionLib.h>
+#include <Library/PcdLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/DevicePathLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/ReportStatusCodeLib.h>
+#include <Library/DxeServicesLib.h>
+#include <Library/DebugAgentLib.h>
+#include <Library/CpuExceptionHandlerLib.h>
+
+//
+// attributes for reserved memory before it is promoted to system memory
+//
+#define EFI_MEMORY_PRESENT 0x0100000000000000ULL
+#define EFI_MEMORY_INITIALIZED 0x0200000000000000ULL
+#define EFI_MEMORY_TESTED 0x0400000000000000ULL
+
+//
+// range for memory mapped port I/O on IPF
+//
+#define EFI_MEMORY_PORT_IO 0x4000000000000000ULL
+
+///
+/// EFI_DEP_REPLACE_TRUE - Used to dynamically patch the dependency expression
+/// to save time. A EFI_DEP_PUSH is evaluated one an
+/// replaced with EFI_DEP_REPLACE_TRUE. If PI spec's Vol 2
+/// Driver Execution Environment Core Interface use 0xff
+/// as new DEPEX opcode. EFI_DEP_REPLACE_TRUE should be
+/// defined to a new value that is not conflicting with PI spec.
+///
+#define EFI_DEP_REPLACE_TRUE 0xff
+
+///
+/// Define the initial size of the dependency expression evaluation stack
+///
+#define DEPEX_STACK_SIZE_INCREMENT 0x1000
+
+typedef struct {
+ EFI_GUID *ProtocolGuid;
+ VOID **Protocol;
+ EFI_EVENT Event;
+ VOID *Registration;
+ BOOLEAN Present;
+} EFI_CORE_PROTOCOL_NOTIFY_ENTRY;
+
+//
+// DXE Dispatcher Data structures
+//
+
+#define KNOWN_HANDLE_SIGNATURE SIGNATURE_32('k','n','o','w')
+typedef struct {
+ UINTN Signature;
+ LIST_ENTRY Link; // mFvHandleList
+ EFI_HANDLE Handle;
+ EFI_GUID FvNameGuid;
+} KNOWN_HANDLE;
+
+#define EFI_CORE_DRIVER_ENTRY_SIGNATURE SIGNATURE_32('d','r','v','r')
+typedef struct {
+ UINTN Signature;
+ LIST_ENTRY Link; // mDriverList
+
+ LIST_ENTRY ScheduledLink; // mScheduledQueue
+
+ EFI_HANDLE FvHandle;
+ EFI_GUID FileName;
+ EFI_DEVICE_PATH_PROTOCOL *FvFileDevicePath;
+ EFI_FIRMWARE_VOLUME2_PROTOCOL *Fv;
+
+ VOID *Depex;
+ UINTN DepexSize;
+
+ BOOLEAN Before;
+ BOOLEAN After;
+ EFI_GUID BeforeAfterGuid;
+
+ BOOLEAN Dependent;
+ BOOLEAN Unrequested;
+ BOOLEAN Scheduled;
+ BOOLEAN Untrusted;
+ BOOLEAN Initialized;
+ BOOLEAN DepexProtocolError;
+
+ EFI_HANDLE ImageHandle;
+ BOOLEAN IsFvImage;
+} EFI_CORE_DRIVER_ENTRY;
+
+//
+// The data structure of GCD memory map entry
+//
+#define EFI_GCD_MAP_SIGNATURE SIGNATURE_32('g','c','d','m')
+typedef struct {
+ UINTN Signature;
+ LIST_ENTRY Link;
+ EFI_PHYSICAL_ADDRESS BaseAddress;
+ UINT64 EndAddress;
+ UINT64 Capabilities;
+ UINT64 Attributes;
+ EFI_GCD_MEMORY_TYPE GcdMemoryType;
+ EFI_GCD_IO_TYPE GcdIoType;
+ EFI_HANDLE ImageHandle;
+ EFI_HANDLE DeviceHandle;
+} EFI_GCD_MAP_ENTRY;
+
+#define LOADED_IMAGE_PRIVATE_DATA_SIGNATURE SIGNATURE_32('l','d','r','i')
+
+typedef struct {
+ UINTN Signature;
+ /// Image handle
+ EFI_HANDLE Handle;
+ /// Image type
+ UINTN Type;
+ /// If entrypoint has been called
+ BOOLEAN Started;
+ /// The image's entry point
+ EFI_IMAGE_ENTRY_POINT EntryPoint;
+ /// loaded image protocol
+ EFI_LOADED_IMAGE_PROTOCOL Info;
+ /// Location in memory
+ EFI_PHYSICAL_ADDRESS ImageBasePage;
+ /// Number of pages
+ UINTN NumberOfPages;
+ /// Original fixup data
+ CHAR8 *FixupData;
+ /// Tpl of started image
+ EFI_TPL Tpl;
+ /// Status returned by started image
+ EFI_STATUS Status;
+ /// Size of ExitData from started image
+ UINTN ExitDataSize;
+ /// Pointer to exit data from started image
+ VOID *ExitData;
+ /// Pointer to pool allocation for context save/restore
+ VOID *JumpBuffer;
+ /// Pointer to buffer for context save/restore
+ BASE_LIBRARY_JUMP_BUFFER *JumpContext;
+ /// Machine type from PE image
+ UINT16 Machine;
+ /// PE/COFF Image Emulator Protocol pointer
+ EDKII_PECOFF_IMAGE_EMULATOR_PROTOCOL *PeCoffEmu;
+ /// Runtime image list
+ EFI_RUNTIME_IMAGE_ENTRY *RuntimeData;
+ /// Pointer to Loaded Image Device Path Protocol
+ EFI_DEVICE_PATH_PROTOCOL *LoadedImageDevicePath;
+ /// PeCoffLoader ImageContext
+ PE_COFF_LOADER_IMAGE_CONTEXT ImageContext;
+ /// Status returned by LoadImage() service.
+ EFI_STATUS LoadImageStatus;
+} LOADED_IMAGE_PRIVATE_DATA;
+
+#define LOADED_IMAGE_PRIVATE_DATA_FROM_THIS(a) \
+ CR(a, LOADED_IMAGE_PRIVATE_DATA, Info, LOADED_IMAGE_PRIVATE_DATA_SIGNATURE)
+
+//
+// DXE Core Global Variables
+//
+extern EFI_SYSTEM_TABLE *gDxeCoreST;
+extern EFI_RUNTIME_SERVICES *gDxeCoreRT;
+extern EFI_DXE_SERVICES *gDxeCoreDS;
+extern EFI_HANDLE gDxeCoreImageHandle;
+
+extern BOOLEAN gMemoryMapTerminated;
+
+extern EFI_DECOMPRESS_PROTOCOL gEfiDecompress;
+
+extern EFI_RUNTIME_ARCH_PROTOCOL *gRuntime;
+extern EFI_CPU_ARCH_PROTOCOL *gCpu;
+extern EFI_WATCHDOG_TIMER_ARCH_PROTOCOL *gWatchdogTimer;
+extern EFI_METRONOME_ARCH_PROTOCOL *gMetronome;
+extern EFI_TIMER_ARCH_PROTOCOL *gTimer;
+extern EFI_SECURITY_ARCH_PROTOCOL *gSecurity;
+extern EFI_SECURITY2_ARCH_PROTOCOL *gSecurity2;
+extern EFI_BDS_ARCH_PROTOCOL *gBds;
+extern EFI_SMM_BASE2_PROTOCOL *gSmmBase2;
+
+extern EFI_TPL gEfiCurrentTpl;
+
+extern EFI_GUID *gDxeCoreFileName;
+extern EFI_LOADED_IMAGE_PROTOCOL *gDxeCoreLoadedImage;
+
+extern EFI_MEMORY_TYPE_INFORMATION gMemoryTypeInformation[EfiMaxMemoryType + 1];
+
+extern BOOLEAN gDispatcherRunning;
+extern EFI_RUNTIME_ARCH_PROTOCOL gRuntimeTemplate;
+
+extern BOOLEAN gMemoryAttributesTableForwardCfi;
+
+extern EFI_LOAD_FIXED_ADDRESS_CONFIGURATION_TABLE gLoadModuleAtFixAddressConfigurationTable;
+extern BOOLEAN gLoadFixedAddressCodeMemoryReady;
+//
+// Service Initialization Functions
+//
+
+/**
+ Called to initialize the pool.
+
+**/
+VOID
+CoreInitializePool (
+ VOID
+ );
+
+VOID
+CoreSetMemoryTypeInformationRange (
+ IN EFI_PHYSICAL_ADDRESS Start,
+ IN UINT64 Length
+ );
+
+/**
+ Called to initialize the memory map and add descriptors to
+ the current descriptor list.
+ The first descriptor that is added must be general usable
+ memory as the addition allocates heap.
+
+ @param Type The type of memory to add
+ @param Start The starting address in the memory range Must be
+ page aligned
+ @param NumberOfPages The number of pages in the range
+ @param Attribute Attributes of the memory to add
+
+ @return None. The range is added to the memory map
+
+**/
+VOID
+CoreAddMemoryDescriptor (
+ IN EFI_MEMORY_TYPE Type,
+ IN EFI_PHYSICAL_ADDRESS Start,
+ IN UINT64 NumberOfPages,
+ IN UINT64 Attribute
+ );
+
+/**
+ Release memory lock on mGcdMemorySpaceLock.
+
+**/
+VOID
+CoreReleaseGcdMemoryLock (
+ VOID
+ );
+
+/**
+ Acquire memory lock on mGcdMemorySpaceLock.
+
+**/
+VOID
+CoreAcquireGcdMemoryLock (
+ VOID
+ );
+
+/**
+ External function. Initializes memory services based on the memory
+ descriptor HOBs. This function is responsible for priming the memory
+ map, so memory allocations and resource allocations can be made.
+ The first part of this function can not depend on any memory services
+ until at least one memory descriptor is provided to the memory services.
+
+ @param HobStart The start address of the HOB.
+ @param MemoryBaseAddress Start address of memory region found to init DXE
+ core.
+ @param MemoryLength Length of memory region found to init DXE core.
+
+ @retval EFI_SUCCESS Memory services successfully initialized.
+
+**/
+EFI_STATUS
+CoreInitializeMemoryServices (
+ IN VOID **HobStart,
+ OUT EFI_PHYSICAL_ADDRESS *MemoryBaseAddress,
+ OUT UINT64 *MemoryLength
+ );
+
+/**
+ External function. Initializes the GCD and memory services based on the memory
+ descriptor HOBs. This function is responsible for priming the GCD map and the
+ memory map, so memory allocations and resource allocations can be made. The
+ HobStart will be relocated to a pool buffer.
+
+ @param HobStart The start address of the HOB
+ @param MemoryBaseAddress Start address of memory region found to init DXE
+ core.
+ @param MemoryLength Length of memory region found to init DXE core.
+
+ @retval EFI_SUCCESS GCD services successfully initialized.
+
+**/
+EFI_STATUS
+CoreInitializeGcdServices (
+ IN OUT VOID **HobStart,
+ IN EFI_PHYSICAL_ADDRESS MemoryBaseAddress,
+ IN UINT64 MemoryLength
+ );
+
+/**
+ Initializes "event" support.
+
+ @retval EFI_SUCCESS Always return success
+
+**/
+EFI_STATUS
+CoreInitializeEventServices (
+ VOID
+ );
+
+/**
+ Add the Image Services to EFI Boot Services Table and install the protocol
+ interfaces for this image.
+
+ @param HobStart The HOB to initialize
+
+ @return Status code.
+
+**/
+EFI_STATUS
+CoreInitializeImageServices (
+ IN VOID *HobStart
+ );
+
+/**
+ Creates an event that is fired everytime a Protocol of a specific type is installed.
+
+**/
+VOID
+CoreNotifyOnProtocolInstallation (
+ VOID
+ );
+
+/**
+ Return TRUE if all AP services are available.
+
+ @retval EFI_SUCCESS All AP services are available
+ @retval EFI_NOT_FOUND At least one AP service is not available
+
+**/
+EFI_STATUS
+CoreAllEfiServicesAvailable (
+ VOID
+ );
+
+/**
+ Calcualte the 32-bit CRC in a EFI table using the service provided by the
+ gRuntime service.
+
+ @param Hdr Pointer to an EFI standard header
+
+**/
+VOID
+CalculateEfiHdrCrc (
+ IN OUT EFI_TABLE_HEADER *Hdr
+ );
+
+/**
+ Called by the platform code to process a tick.
+
+ @param Duration The number of 100ns elapsed since the last call
+ to TimerTick
+
+**/
+VOID
+EFIAPI
+CoreTimerTick (
+ IN UINT64 Duration
+ );
+
+/**
+ Initialize the dispatcher. Initialize the notification function that runs when
+ an FV2 protocol is added to the system.
+
+**/
+VOID
+CoreInitializeDispatcher (
+ VOID
+ );
+
+/**
+ This is the POSTFIX version of the dependency evaluator. This code does
+ not need to handle Before or After, as it is not valid to call this
+ routine in this case. The SOR is just ignored and is a nop in the grammer.
+ POSTFIX means all the math is done on top of the stack.
+
+ @param DriverEntry DriverEntry element to update.
+
+ @retval TRUE If driver is ready to run.
+ @retval FALSE If driver is not ready to run or some fatal error
+ was found.
+
+**/
+BOOLEAN
+CoreIsSchedulable (
+ IN EFI_CORE_DRIVER_ENTRY *DriverEntry
+ );
+
+/**
+ Preprocess dependency expression and update DriverEntry to reflect the
+ state of Before, After, and SOR dependencies. If DriverEntry->Before
+ or DriverEntry->After is set it will never be cleared. If SOR is set
+ it will be cleared by CoreSchedule(), and then the driver can be
+ dispatched.
+
+ @param DriverEntry DriverEntry element to update .
+
+ @retval EFI_SUCCESS It always works.
+
+**/
+EFI_STATUS
+CorePreProcessDepex (
+ IN EFI_CORE_DRIVER_ENTRY *DriverEntry
+ );
+
+/**
+ Terminates all boot services.
+
+ @param ImageHandle Handle that identifies the exiting image.
+ @param MapKey Key to the latest memory map.
+
+ @retval EFI_SUCCESS Boot Services terminated
+ @retval EFI_INVALID_PARAMETER MapKey is incorrect.
+
+**/
+EFI_STATUS
+EFIAPI
+CoreExitBootServices (
+ IN EFI_HANDLE ImageHandle,
+ IN UINTN MapKey
+ );
+
+/**
+ Make sure the memory map is following all the construction rules,
+ it is the last time to check memory map error before exit boot services.
+
+ @param MapKey Memory map key
+
+ @retval EFI_INVALID_PARAMETER Memory map not consistent with construction
+ rules.
+ @retval EFI_SUCCESS Valid memory map.
+
+**/
+EFI_STATUS
+CoreTerminateMemoryMap (
+ IN UINTN MapKey
+ );
+
+/**
+ Signals all events in the EventGroup.
+
+ @param EventGroup The list to signal
+
+**/
+VOID
+CoreNotifySignalList (
+ IN EFI_GUID *EventGroup
+ );
+
+/**
+ Boot Service called to add, modify, or remove a system configuration table from
+ the EFI System Table.
+
+ @param Guid Pointer to the GUID for the entry to add, update, or
+ remove
+ @param Table Pointer to the configuration table for the entry to add,
+ update, or remove, may be NULL.
+
+ @return EFI_SUCCESS Guid, Table pair added, updated, or removed.
+ @return EFI_INVALID_PARAMETER Input GUID not valid.
+ @return EFI_NOT_FOUND Attempted to delete non-existant entry
+ @return EFI_OUT_OF_RESOURCES Not enough memory available
+
+**/
+EFI_STATUS
+EFIAPI
+CoreInstallConfigurationTable (
+ IN EFI_GUID *Guid,
+ IN VOID *Table
+ );
+
+/**
+ Raise the task priority level to the new level.
+ High level is implemented by disabling processor interrupts.
+
+ @param NewTpl New task priority level
+
+ @return The previous task priority level
+
+**/
+EFI_TPL
+EFIAPI
+CoreRaiseTpl (
+ IN EFI_TPL NewTpl
+ );
+
+/**
+ Lowers the task priority to the previous value. If the new
+ priority unmasks events at a higher priority, they are dispatched.
+
+ @param NewTpl New, lower, task priority
+
+**/
+VOID
+EFIAPI
+CoreRestoreTpl (
+ IN EFI_TPL NewTpl
+ );
+
+/**
+ Introduces a fine-grained stall.
+
+ @param Microseconds The number of microseconds to stall execution.
+
+ @retval EFI_SUCCESS Execution was stalled for at least the requested
+ amount of microseconds.
+ @retval EFI_NOT_AVAILABLE_YET gMetronome is not available yet
+
+**/
+EFI_STATUS
+EFIAPI
+CoreStall (
+ IN UINTN Microseconds
+ );
+
+/**
+ Sets the system's watchdog timer.
+
+ @param Timeout The number of seconds to set the watchdog timer to.
+ A value of zero disables the timer.
+ @param WatchdogCode The numeric code to log on a watchdog timer timeout
+ event. The firmware reserves codes 0x0000 to 0xFFFF.
+ Loaders and operating systems may use other timeout
+ codes.
+ @param DataSize The size, in bytes, of WatchdogData.
+ @param WatchdogData A data buffer that includes a Null-terminated Unicode
+ string, optionally followed by additional binary data.
+ The string is a description that the call may use to
+ further indicate the reason to be logged with a
+ watchdog event.
+
+ @return EFI_SUCCESS Timeout has been set
+ @return EFI_NOT_AVAILABLE_YET WatchdogTimer is not available yet
+ @return EFI_UNSUPPORTED System does not have a timer (currently not used)
+ @return EFI_DEVICE_ERROR Could not complete due to hardware error
+
+**/
+EFI_STATUS
+EFIAPI
+CoreSetWatchdogTimer (
+ IN UINTN Timeout,
+ IN UINT64 WatchdogCode,
+ IN UINTN DataSize,
+ IN CHAR16 *WatchdogData OPTIONAL
+ );
+
+/**
+ Wrapper function to CoreInstallProtocolInterfaceNotify. This is the public API which
+ Calls the private one which contains a BOOLEAN parameter for notifications
+
+ @param UserHandle The handle to install the protocol handler on,
+ or NULL if a new handle is to be allocated
+ @param Protocol The protocol to add to the handle
+ @param InterfaceType Indicates whether Interface is supplied in
+ native form.
+ @param Interface The interface for the protocol being added
+
+ @return Status code
+
+**/
+EFI_STATUS
+EFIAPI
+CoreInstallProtocolInterface (
+ IN OUT EFI_HANDLE *UserHandle,
+ IN EFI_GUID *Protocol,
+ IN EFI_INTERFACE_TYPE InterfaceType,
+ IN VOID *Interface
+ );
+
+/**
+ Installs a protocol interface into the boot services environment.
+
+ @param UserHandle The handle to install the protocol handler on,
+ or NULL if a new handle is to be allocated
+ @param Protocol The protocol to add to the handle
+ @param InterfaceType Indicates whether Interface is supplied in
+ native form.
+ @param Interface The interface for the protocol being added
+ @param Notify indicates whether notify the notification list
+ for this protocol
+
+ @retval EFI_INVALID_PARAMETER Invalid parameter
+ @retval EFI_OUT_OF_RESOURCES No enough buffer to allocate
+ @retval EFI_SUCCESS Protocol interface successfully installed
+
+**/
+EFI_STATUS
+CoreInstallProtocolInterfaceNotify (
+ IN OUT EFI_HANDLE *UserHandle,
+ IN EFI_GUID *Protocol,
+ IN EFI_INTERFACE_TYPE InterfaceType,
+ IN VOID *Interface,
+ IN BOOLEAN Notify
+ );
+
+/**
+ Installs a list of protocol interface into the boot services environment.
+ This function calls InstallProtocolInterface() in a loop. If any error
+ occures all the protocols added by this function are removed. This is
+ basically a lib function to save space.
+
+ @param Handle The handle to install the protocol handlers on,
+ or NULL if a new handle is to be allocated
+ @param ... EFI_GUID followed by protocol instance. A NULL
+ terminates the list. The pairs are the
+ arguments to InstallProtocolInterface(). All the
+ protocols are added to Handle.
+
+ @retval EFI_SUCCESS All the protocol interface was installed.
+ @retval EFI_OUT_OF_RESOURCES There was not enough memory in pool to install all the protocols.
+ @retval EFI_ALREADY_STARTED A Device Path Protocol instance was passed in that is already present in
+ the handle database.
+ @retval EFI_INVALID_PARAMETER Handle is NULL.
+ @retval EFI_INVALID_PARAMETER Protocol is already installed on the handle specified by Handle.
+
+**/
+EFI_STATUS
+EFIAPI
+CoreInstallMultipleProtocolInterfaces (
+ IN OUT EFI_HANDLE *Handle,
+ ...
+ );
+
+/**
+ Uninstalls a list of protocol interface in the boot services environment.
+ This function calls UnisatllProtocolInterface() in a loop. This is
+ basically a lib function to save space.
+
+ @param Handle The handle to uninstall the protocol
+ @param ... EFI_GUID followed by protocol instance. A NULL
+ terminates the list. The pairs are the
+ arguments to UninstallProtocolInterface(). All
+ the protocols are added to Handle.
+
+ @return Status code
+
+**/
+EFI_STATUS
+EFIAPI
+CoreUninstallMultipleProtocolInterfaces (
+ IN EFI_HANDLE Handle,
+ ...
+ );
+
+/**
+ Reinstall a protocol interface on a device handle. The OldInterface for Protocol is replaced by the NewInterface.
+
+ @param UserHandle Handle on which the interface is to be
+ reinstalled
+ @param Protocol The numeric ID of the interface
+ @param OldInterface A pointer to the old interface
+ @param NewInterface A pointer to the new interface
+
+ @retval EFI_SUCCESS The protocol interface was installed
+ @retval EFI_NOT_FOUND The OldInterface on the handle was not found
+ @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value
+
+**/
+EFI_STATUS
+EFIAPI
+CoreReinstallProtocolInterface (
+ IN EFI_HANDLE UserHandle,
+ IN EFI_GUID *Protocol,
+ IN VOID *OldInterface,
+ IN VOID *NewInterface
+ );
+
+/**
+ Uninstalls all instances of a protocol:interfacer from a handle.
+ If the last protocol interface is remove from the handle, the
+ handle is freed.
+
+ @param UserHandle The handle to remove the protocol handler from
+ @param Protocol The protocol, of protocol:interface, to remove
+ @param Interface The interface, of protocol:interface, to remove
+
+ @retval EFI_INVALID_PARAMETER Protocol is NULL.
+ @retval EFI_SUCCESS Protocol interface successfully uninstalled.
+
+**/
+EFI_STATUS
+EFIAPI
+CoreUninstallProtocolInterface (
+ IN EFI_HANDLE UserHandle,
+ IN EFI_GUID *Protocol,
+ IN VOID *Interface
+ );
+
+/**
+ Queries a handle to determine if it supports a specified protocol.
+
+ @param UserHandle The handle being queried.
+ @param Protocol The published unique identifier of the protocol.
+ @param Interface Supplies the address where a pointer to the
+ corresponding Protocol Interface is returned.
+
+ @return The requested protocol interface for the handle
+
+**/
+EFI_STATUS
+EFIAPI
+CoreHandleProtocol (
+ IN EFI_HANDLE UserHandle,
+ IN EFI_GUID *Protocol,
+ OUT VOID **Interface
+ );
+
+/**
+ Locates the installed protocol handler for the handle, and
+ invokes it to obtain the protocol interface. Usage information
+ is registered in the protocol data base.
+
+ @param UserHandle The handle to obtain the protocol interface on
+ @param Protocol The ID of the protocol
+ @param Interface The location to return the protocol interface
+ @param ImageHandle The handle of the Image that is opening the
+ protocol interface specified by Protocol and
+ Interface.
+ @param ControllerHandle The controller handle that is requiring this
+ interface.
+ @param Attributes The open mode of the protocol interface
+ specified by Handle and Protocol.
+
+ @retval EFI_INVALID_PARAMETER Protocol is NULL.
+ @retval EFI_SUCCESS Get the protocol interface.
+
+**/
+EFI_STATUS
+EFIAPI
+CoreOpenProtocol (
+ IN EFI_HANDLE UserHandle,
+ IN EFI_GUID *Protocol,
+ OUT VOID **Interface OPTIONAL,
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_HANDLE ControllerHandle,
+ IN UINT32 Attributes
+ );
+
+/**
+ Return information about Opened protocols in the system
+
+ @param UserHandle The handle to close the protocol interface on
+ @param Protocol The ID of the protocol
+ @param EntryBuffer A pointer to a buffer of open protocol
+ information in the form of
+ EFI_OPEN_PROTOCOL_INFORMATION_ENTRY structures.
+ @param EntryCount Number of EntryBuffer entries
+
+**/
+EFI_STATUS
+EFIAPI
+CoreOpenProtocolInformation (
+ IN EFI_HANDLE UserHandle,
+ IN EFI_GUID *Protocol,
+ OUT EFI_OPEN_PROTOCOL_INFORMATION_ENTRY **EntryBuffer,
+ OUT UINTN *EntryCount
+ );
+
+/**
+ Closes a protocol on a handle that was opened using OpenProtocol().
+
+ @param UserHandle The handle for the protocol interface that was
+ previously opened with OpenProtocol(), and is
+ now being closed.
+ @param Protocol The published unique identifier of the protocol.
+ It is the caller's responsibility to pass in a
+ valid GUID.
+ @param AgentHandle The handle of the agent that is closing the
+ protocol interface.
+ @param ControllerHandle If the agent that opened a protocol is a driver
+ that follows the EFI Driver Model, then this
+ parameter is the controller handle that required
+ the protocol interface. If the agent does not
+ follow the EFI Driver Model, then this parameter
+ is optional and may be NULL.
+
+ @retval EFI_SUCCESS The protocol instance was closed.
+ @retval EFI_INVALID_PARAMETER Handle, AgentHandle or ControllerHandle is not a
+ valid EFI_HANDLE.
+ @retval EFI_NOT_FOUND Can not find the specified protocol or
+ AgentHandle.
+
+**/
+EFI_STATUS
+EFIAPI
+CoreCloseProtocol (
+ IN EFI_HANDLE UserHandle,
+ IN EFI_GUID *Protocol,
+ IN EFI_HANDLE AgentHandle,
+ IN EFI_HANDLE ControllerHandle
+ );
+
+/**
+ Retrieves the list of protocol interface GUIDs that are installed on a handle in a buffer allocated
+ from pool.
+
+ @param UserHandle The handle from which to retrieve the list of
+ protocol interface GUIDs.
+ @param ProtocolBuffer A pointer to the list of protocol interface GUID
+ pointers that are installed on Handle.
+ @param ProtocolBufferCount A pointer to the number of GUID pointers present
+ in ProtocolBuffer.
+
+ @retval EFI_SUCCESS The list of protocol interface GUIDs installed
+ on Handle was returned in ProtocolBuffer. The
+ number of protocol interface GUIDs was returned
+ in ProtocolBufferCount.
+ @retval EFI_INVALID_PARAMETER Handle is NULL.
+ @retval EFI_INVALID_PARAMETER Handle is not a valid EFI_HANDLE.
+ @retval EFI_INVALID_PARAMETER ProtocolBuffer is NULL.
+ @retval EFI_INVALID_PARAMETER ProtocolBufferCount is NULL.
+ @retval EFI_OUT_OF_RESOURCES There is not enough pool memory to store the
+ results.
+
+**/
+EFI_STATUS
+EFIAPI
+CoreProtocolsPerHandle (
+ IN EFI_HANDLE UserHandle,
+ OUT EFI_GUID ***ProtocolBuffer,
+ OUT UINTN *ProtocolBufferCount
+ );
+
+/**
+ Add a new protocol notification record for the request protocol.
+
+ @param Protocol The requested protocol to add the notify
+ registration
+ @param Event The event to signal
+ @param Registration Returns the registration record
+
+ @retval EFI_INVALID_PARAMETER Invalid parameter
+ @retval EFI_SUCCESS Successfully returned the registration record
+ that has been added
+
+**/
+EFI_STATUS
+EFIAPI
+CoreRegisterProtocolNotify (
+ IN EFI_GUID *Protocol,
+ IN EFI_EVENT Event,
+ OUT VOID **Registration
+ );
+
+/**
+ Removes all the events in the protocol database that match Event.
+
+ @param Event The event to search for in the protocol
+ database.
+
+ @return EFI_SUCCESS when done searching the entire database.
+
+**/
+EFI_STATUS
+CoreUnregisterProtocolNotify (
+ IN EFI_EVENT Event
+ );
+
+/**
+ Locates the requested handle(s) and returns them in Buffer.
+
+ @param SearchType The type of search to perform to locate the
+ handles
+ @param Protocol The protocol to search for
+ @param SearchKey Dependant on SearchType
+ @param BufferSize On input the size of Buffer. On output the
+ size of data returned.
+ @param Buffer The buffer to return the results in
+
+ @retval EFI_BUFFER_TOO_SMALL Buffer too small, required buffer size is
+ returned in BufferSize.
+ @retval EFI_INVALID_PARAMETER Invalid parameter
+ @retval EFI_SUCCESS Successfully found the requested handle(s) and
+ returns them in Buffer.
+
+**/
+EFI_STATUS
+EFIAPI
+CoreLocateHandle (
+ IN EFI_LOCATE_SEARCH_TYPE SearchType,
+ IN EFI_GUID *Protocol OPTIONAL,
+ IN VOID *SearchKey OPTIONAL,
+ IN OUT UINTN *BufferSize,
+ OUT EFI_HANDLE *Buffer
+ );
+
+/**
+ Locates the handle to a device on the device path that best matches the specified protocol.
+
+ @param Protocol The protocol to search for.
+ @param DevicePath On input, a pointer to a pointer to the device
+ path. On output, the device path pointer is
+ modified to point to the remaining part of the
+ devicepath.
+ @param Device A pointer to the returned device handle.
+
+ @retval EFI_SUCCESS The resulting handle was returned.
+ @retval EFI_NOT_FOUND No handles matched the search.
+ @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
+
+**/
+EFI_STATUS
+EFIAPI
+CoreLocateDevicePath (
+ IN EFI_GUID *Protocol,
+ IN OUT EFI_DEVICE_PATH_PROTOCOL **DevicePath,
+ OUT EFI_HANDLE *Device
+ );
+
+/**
+ Function returns an array of handles that support the requested protocol
+ in a buffer allocated from pool. This is a version of CoreLocateHandle()
+ that allocates a buffer for the caller.
+
+ @param SearchType Specifies which handle(s) are to be returned.
+ @param Protocol Provides the protocol to search by. This
+ parameter is only valid for SearchType
+ ByProtocol.
+ @param SearchKey Supplies the search key depending on the
+ SearchType.
+ @param NumberHandles The number of handles returned in Buffer.
+ @param Buffer A pointer to the buffer to return the requested
+ array of handles that support Protocol.
+
+ @retval EFI_SUCCESS The result array of handles was returned.
+ @retval EFI_NOT_FOUND No handles match the search.
+ @retval EFI_OUT_OF_RESOURCES There is not enough pool memory to store the
+ matching results.
+ @retval EFI_INVALID_PARAMETER One or more parameters are not valid.
+
+**/
+EFI_STATUS
+EFIAPI
+CoreLocateHandleBuffer (
+ IN EFI_LOCATE_SEARCH_TYPE SearchType,
+ IN EFI_GUID *Protocol OPTIONAL,
+ IN VOID *SearchKey OPTIONAL,
+ IN OUT UINTN *NumberHandles,
+ OUT EFI_HANDLE **Buffer
+ );
+
+/**
+ Return the first Protocol Interface that matches the Protocol GUID. If
+ Registration is passed in, return a Protocol Instance that was just add
+ to the system. If Registration is NULL return the first Protocol Interface
+ you find.
+
+ @param Protocol The protocol to search for
+ @param Registration Optional Registration Key returned from
+ RegisterProtocolNotify()
+ @param Interface Return the Protocol interface (instance).
+
+ @retval EFI_SUCCESS If a valid Interface is returned
+ @retval EFI_INVALID_PARAMETER Invalid parameter
+ @retval EFI_NOT_FOUND Protocol interface not found
+
+**/
+EFI_STATUS
+EFIAPI
+CoreLocateProtocol (
+ IN EFI_GUID *Protocol,
+ IN VOID *Registration OPTIONAL,
+ OUT VOID **Interface
+ );
+
+/**
+ return handle database key.
+
+
+ @return Handle database key.
+
+**/
+UINT64
+CoreGetHandleDatabaseKey (
+ VOID
+ );
+
+/**
+ Go connect any handles that were created or modified while a image executed.
+
+ @param Key The Key to show that the handle has been
+ created/modified
+
+**/
+VOID
+CoreConnectHandlesByKey (
+ UINT64 Key
+ );
+
+/**
+ Connects one or more drivers to a controller.
+
+ @param ControllerHandle The handle of the controller to which driver(s) are to be connected.
+ @param DriverImageHandle A pointer to an ordered list handles that support the
+ EFI_DRIVER_BINDING_PROTOCOL.
+ @param RemainingDevicePath A pointer to the device path that specifies a child of the
+ controller specified by ControllerHandle.
+ @param Recursive If TRUE, then ConnectController() is called recursively
+ until the entire tree of controllers below the controller specified
+ by ControllerHandle have been created. If FALSE, then
+ the tree of controllers is only expanded one level.
+
+ @retval EFI_SUCCESS 1) One or more drivers were connected to ControllerHandle.
+ 2) No drivers were connected to ControllerHandle, but
+ RemainingDevicePath is not NULL, and it is an End Device
+ Path Node.
+ @retval EFI_INVALID_PARAMETER ControllerHandle is NULL.
+ @retval EFI_NOT_FOUND 1) There are no EFI_DRIVER_BINDING_PROTOCOL instances
+ present in the system.
+ 2) No drivers were connected to ControllerHandle.
+ @retval EFI_SECURITY_VIOLATION
+ The user has no permission to start UEFI device drivers on the device path
+ associated with the ControllerHandle or specified by the RemainingDevicePath.
+
+**/
+EFI_STATUS
+EFIAPI
+CoreConnectController (
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_HANDLE *DriverImageHandle OPTIONAL,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL,
+ IN BOOLEAN Recursive
+ );
+
+/**
+ Disonnects a controller from a driver
+
+ @param ControllerHandle ControllerHandle The handle of
+ the controller from which
+ driver(s) are to be
+ disconnected.
+ @param DriverImageHandle DriverImageHandle The driver to
+ disconnect from ControllerHandle.
+ @param ChildHandle ChildHandle The handle of the
+ child to destroy.
+
+ @retval EFI_SUCCESS One or more drivers were
+ disconnected from the controller.
+ @retval EFI_SUCCESS On entry, no drivers are managing
+ ControllerHandle.
+ @retval EFI_SUCCESS DriverImageHandle is not NULL,
+ and on entry DriverImageHandle is
+ not managing ControllerHandle.
+ @retval EFI_INVALID_PARAMETER ControllerHandle is NULL.
+ @retval EFI_INVALID_PARAMETER DriverImageHandle is not NULL,
+ and it is not a valid EFI_HANDLE.
+ @retval EFI_INVALID_PARAMETER ChildHandle is not NULL, and it
+ is not a valid EFI_HANDLE.
+ @retval EFI_OUT_OF_RESOURCES There are not enough resources
+ available to disconnect any
+ drivers from ControllerHandle.
+ @retval EFI_DEVICE_ERROR The controller could not be
+ disconnected because of a device
+ error.
+
+**/
+EFI_STATUS
+EFIAPI
+CoreDisconnectController (
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_HANDLE DriverImageHandle OPTIONAL,
+ IN EFI_HANDLE ChildHandle OPTIONAL
+ );
+
+/**
+ Allocates pages from the memory map.
+
+ @param Type The type of allocation to perform
+ @param MemoryType The type of memory to turn the allocated pages
+ into
+ @param NumberOfPages The number of pages to allocate
+ @param Memory A pointer to receive the base allocated memory
+ address
+
+ @return Status. On success, Memory is filled in with the base address allocated
+ @retval EFI_INVALID_PARAMETER Parameters violate checking rules defined in
+ spec.
+ @retval EFI_NOT_FOUND Could not allocate pages match the requirement.
+ @retval EFI_OUT_OF_RESOURCES No enough pages to allocate.
+ @retval EFI_SUCCESS Pages successfully allocated.
+
+**/
+EFI_STATUS
+EFIAPI
+CoreAllocatePages (
+ IN EFI_ALLOCATE_TYPE Type,
+ IN EFI_MEMORY_TYPE MemoryType,
+ IN UINTN NumberOfPages,
+ IN OUT EFI_PHYSICAL_ADDRESS *Memory
+ );
+
+/**
+ Frees previous allocated pages.
+
+ @param Memory Base address of memory being freed
+ @param NumberOfPages The number of pages to free
+
+ @retval EFI_NOT_FOUND Could not find the entry that covers the range
+ @retval EFI_INVALID_PARAMETER Address not aligned
+ @return EFI_SUCCESS -Pages successfully freed.
+
+**/
+EFI_STATUS
+EFIAPI
+CoreFreePages (
+ IN EFI_PHYSICAL_ADDRESS Memory,
+ IN UINTN NumberOfPages
+ );
+
+/**
+ This function returns a copy of the current memory map. The map is an array of
+ memory descriptors, each of which describes a contiguous block of memory.
+
+ @param MemoryMapSize A pointer to the size, in bytes, of the
+ MemoryMap buffer. On input, this is the size of
+ the buffer allocated by the caller. On output,
+ it is the size of the buffer returned by the
+ firmware if the buffer was large enough, or the
+ size of the buffer needed to contain the map if
+ the buffer was too small.
+ @param MemoryMap A pointer to the buffer in which firmware places
+ the current memory map.
+ @param MapKey A pointer to the location in which firmware
+ returns the key for the current memory map.
+ @param DescriptorSize A pointer to the location in which firmware
+ returns the size, in bytes, of an individual
+ EFI_MEMORY_DESCRIPTOR.
+ @param DescriptorVersion A pointer to the location in which firmware
+ returns the version number associated with the
+ EFI_MEMORY_DESCRIPTOR.
+
+ @retval EFI_SUCCESS The memory map was returned in the MemoryMap
+ buffer.
+ @retval EFI_BUFFER_TOO_SMALL The MemoryMap buffer was too small. The current
+ buffer size needed to hold the memory map is
+ returned in MemoryMapSize.
+ @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
+
+**/
+EFI_STATUS
+EFIAPI
+CoreGetMemoryMap (
+ IN OUT UINTN *MemoryMapSize,
+ IN OUT EFI_MEMORY_DESCRIPTOR *MemoryMap,
+ OUT UINTN *MapKey,
+ OUT UINTN *DescriptorSize,
+ OUT UINT32 *DescriptorVersion
+ );
+
+/**
+ Allocate pool of a particular type.
+
+ @param PoolType Type of pool to allocate
+ @param Size The amount of pool to allocate
+ @param Buffer The address to return a pointer to the allocated
+ pool
+
+ @retval EFI_INVALID_PARAMETER PoolType not valid or Buffer is NULL
+ @retval EFI_OUT_OF_RESOURCES Size exceeds max pool size or allocation failed.
+ @retval EFI_SUCCESS Pool successfully allocated.
+
+**/
+EFI_STATUS
+EFIAPI
+CoreAllocatePool (
+ IN EFI_MEMORY_TYPE PoolType,
+ IN UINTN Size,
+ OUT VOID **Buffer
+ );
+
+/**
+ Allocate pool of a particular type.
+
+ @param PoolType Type of pool to allocate
+ @param Size The amount of pool to allocate
+ @param Buffer The address to return a pointer to the allocated
+ pool
+
+ @retval EFI_INVALID_PARAMETER PoolType not valid or Buffer is NULL
+ @retval EFI_OUT_OF_RESOURCES Size exceeds max pool size or allocation failed.
+ @retval EFI_SUCCESS Pool successfully allocated.
+
+**/
+EFI_STATUS
+EFIAPI
+CoreInternalAllocatePool (
+ IN EFI_MEMORY_TYPE PoolType,
+ IN UINTN Size,
+ OUT VOID **Buffer
+ );
+
+/**
+ Frees pool.
+
+ @param Buffer The allocated pool entry to free
+
+ @retval EFI_INVALID_PARAMETER Buffer is not a valid value.
+ @retval EFI_SUCCESS Pool successfully freed.
+
+**/
+EFI_STATUS
+EFIAPI
+CoreFreePool (
+ IN VOID *Buffer
+ );
+
+/**
+ Frees pool.
+
+ @param Buffer The allocated pool entry to free
+ @param PoolType Pointer to pool type
+
+ @retval EFI_INVALID_PARAMETER Buffer is not a valid value.
+ @retval EFI_SUCCESS Pool successfully freed.
+
+**/
+EFI_STATUS
+EFIAPI
+CoreInternalFreePool (
+ IN VOID *Buffer,
+ OUT EFI_MEMORY_TYPE *PoolType OPTIONAL
+ );
+
+/**
+ Loads an EFI image into memory and returns a handle to the image.
+
+ @param BootPolicy If TRUE, indicates that the request originates
+ from the boot manager, and that the boot
+ manager is attempting to load FilePath as a
+ boot selection.
+ @param ParentImageHandle The caller's image handle.
+ @param FilePath The specific file path from which the image is
+ loaded.
+ @param SourceBuffer If not NULL, a pointer to the memory location
+ containing a copy of the image to be loaded.
+ @param SourceSize The size in bytes of SourceBuffer.
+ @param ImageHandle Pointer to the returned image handle that is
+ created when the image is successfully loaded.
+
+ @retval EFI_SUCCESS The image was loaded into memory.
+ @retval EFI_NOT_FOUND The FilePath was not found.
+ @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
+ @retval EFI_UNSUPPORTED The image type is not supported, or the device
+ path cannot be parsed to locate the proper
+ protocol for loading the file.
+ @retval EFI_OUT_OF_RESOURCES Image was not loaded due to insufficient
+ resources.
+ @retval EFI_LOAD_ERROR Image was not loaded because the image format was corrupt or not
+ understood.
+ @retval EFI_DEVICE_ERROR Image was not loaded because the device returned a read error.
+ @retval EFI_ACCESS_DENIED Image was not loaded because the platform policy prohibits the
+ image from being loaded. NULL is returned in *ImageHandle.
+ @retval EFI_SECURITY_VIOLATION Image was loaded and an ImageHandle was created with a
+ valid EFI_LOADED_IMAGE_PROTOCOL. However, the current
+ platform policy specifies that the image should not be started.
+
+**/
+EFI_STATUS
+EFIAPI
+CoreLoadImage (
+ IN BOOLEAN BootPolicy,
+ IN EFI_HANDLE ParentImageHandle,
+ IN EFI_DEVICE_PATH_PROTOCOL *FilePath,
+ IN VOID *SourceBuffer OPTIONAL,
+ IN UINTN SourceSize,
+ OUT EFI_HANDLE *ImageHandle
+ );
+
+/**
+ Unloads an image.
+
+ @param ImageHandle Handle that identifies the image to be
+ unloaded.
+
+ @retval EFI_SUCCESS The image has been unloaded.
+ @retval EFI_UNSUPPORTED The image has been started, and does not support
+ unload.
+ @retval EFI_INVALID_PARAMPETER ImageHandle is not a valid image handle.
+
+**/
+EFI_STATUS
+EFIAPI
+CoreUnloadImage (
+ IN EFI_HANDLE ImageHandle
+ );
+
+/**
+ Transfer control to a loaded image's entry point.
+
+ @param ImageHandle Handle of image to be started.
+ @param ExitDataSize Pointer of the size to ExitData
+ @param ExitData Pointer to a pointer to a data buffer that
+ includes a Null-terminated string,
+ optionally followed by additional binary data.
+ The string is a description that the caller may
+ use to further indicate the reason for the
+ image's exit.
+
+ @retval EFI_INVALID_PARAMETER Invalid parameter
+ @retval EFI_OUT_OF_RESOURCES No enough buffer to allocate
+ @retval EFI_SECURITY_VIOLATION The current platform policy specifies that the image should not be started.
+ @retval EFI_SUCCESS Successfully transfer control to the image's
+ entry point.
+
+**/
+EFI_STATUS
+EFIAPI
+CoreStartImage (
+ IN EFI_HANDLE ImageHandle,
+ OUT UINTN *ExitDataSize,
+ OUT CHAR16 **ExitData OPTIONAL
+ );
+
+/**
+ Terminates the currently loaded EFI image and returns control to boot services.
+
+ @param ImageHandle Handle that identifies the image. This
+ parameter is passed to the image on entry.
+ @param Status The image's exit code.
+ @param ExitDataSize The size, in bytes, of ExitData. Ignored if
+ ExitStatus is EFI_SUCCESS.
+ @param ExitData Pointer to a data buffer that includes a
+ Null-terminated Unicode string, optionally
+ followed by additional binary data. The string
+ is a description that the caller may use to
+ further indicate the reason for the image's
+ exit.
+
+ @retval EFI_INVALID_PARAMETER Image handle is NULL or it is not current
+ image.
+ @retval EFI_SUCCESS Successfully terminates the currently loaded
+ EFI image.
+ @retval EFI_ACCESS_DENIED Should never reach there.
+ @retval EFI_OUT_OF_RESOURCES Could not allocate pool
+
+**/
+EFI_STATUS
+EFIAPI
+CoreExit (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_STATUS Status,
+ IN UINTN ExitDataSize,
+ IN CHAR16 *ExitData OPTIONAL
+ );
+
+/**
+ Creates an event.
+
+ @param Type The type of event to create and its mode and
+ attributes
+ @param NotifyTpl The task priority level of event notifications
+ @param NotifyFunction Pointer to the events notification function
+ @param NotifyContext Pointer to the notification functions context;
+ corresponds to parameter "Context" in the
+ notification function
+ @param Event Pointer to the newly created event if the call
+ succeeds; undefined otherwise
+
+ @retval EFI_SUCCESS The event structure was created
+ @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value
+ @retval EFI_OUT_OF_RESOURCES The event could not be allocated
+
+**/
+EFI_STATUS
+EFIAPI
+CoreCreateEvent (
+ IN UINT32 Type,
+ IN EFI_TPL NotifyTpl,
+ IN EFI_EVENT_NOTIFY NotifyFunction OPTIONAL,
+ IN VOID *NotifyContext OPTIONAL,
+ OUT EFI_EVENT *Event
+ );
+
+/**
+ Creates an event in a group.
+
+ @param Type The type of event to create and its mode and
+ attributes
+ @param NotifyTpl The task priority level of event notifications
+ @param NotifyFunction Pointer to the events notification function
+ @param NotifyContext Pointer to the notification functions context;
+ corresponds to parameter "Context" in the
+ notification function
+ @param EventGroup GUID for EventGroup if NULL act the same as
+ gBS->CreateEvent().
+ @param Event Pointer to the newly created event if the call
+ succeeds; undefined otherwise
+
+ @retval EFI_SUCCESS The event structure was created
+ @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value
+ @retval EFI_OUT_OF_RESOURCES The event could not be allocated
+
+**/
+EFI_STATUS
+EFIAPI
+CoreCreateEventEx (
+ IN UINT32 Type,
+ IN EFI_TPL NotifyTpl,
+ IN EFI_EVENT_NOTIFY NotifyFunction OPTIONAL,
+ IN CONST VOID *NotifyContext OPTIONAL,
+ IN CONST EFI_GUID *EventGroup OPTIONAL,
+ OUT EFI_EVENT *Event
+ );
+
+/**
+ Creates a general-purpose event structure
+
+ @param Type The type of event to create and its mode and
+ attributes
+ @param NotifyTpl The task priority level of event notifications
+ @param NotifyFunction Pointer to the events notification function
+ @param NotifyContext Pointer to the notification functions context;
+ corresponds to parameter "Context" in the
+ notification function
+ @param EventGroup GUID for EventGroup if NULL act the same as
+ gBS->CreateEvent().
+ @param Event Pointer to the newly created event if the call
+ succeeds; undefined otherwise
+
+ @retval EFI_SUCCESS The event structure was created
+ @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value
+ @retval EFI_OUT_OF_RESOURCES The event could not be allocated
+
+**/
+EFI_STATUS
+EFIAPI
+CoreCreateEventInternal (
+ IN UINT32 Type,
+ IN EFI_TPL NotifyTpl,
+ IN EFI_EVENT_NOTIFY NotifyFunction OPTIONAL,
+ IN CONST VOID *NotifyContext OPTIONAL,
+ IN CONST EFI_GUID *EventGroup OPTIONAL,
+ OUT EFI_EVENT *Event
+ );
+
+/**
+ Sets the type of timer and the trigger time for a timer event.
+
+ @param UserEvent The timer event that is to be signaled at the
+ specified time
+ @param Type The type of time that is specified in
+ TriggerTime
+ @param TriggerTime The number of 100ns units until the timer
+ expires
+
+ @retval EFI_SUCCESS The event has been set to be signaled at the
+ requested time
+ @retval EFI_INVALID_PARAMETER Event or Type is not valid
+
+**/
+EFI_STATUS
+EFIAPI
+CoreSetTimer (
+ IN EFI_EVENT UserEvent,
+ IN EFI_TIMER_DELAY Type,
+ IN UINT64 TriggerTime
+ );
+
+/**
+ Signals the event. Queues the event to be notified if needed.
+
+ @param UserEvent The event to signal .
+
+ @retval EFI_INVALID_PARAMETER Parameters are not valid.
+ @retval EFI_SUCCESS The event was signaled.
+
+**/
+EFI_STATUS
+EFIAPI
+CoreSignalEvent (
+ IN EFI_EVENT UserEvent
+ );
+
+/**
+ Stops execution until an event is signaled.
+
+ @param NumberOfEvents The number of events in the UserEvents array
+ @param UserEvents An array of EFI_EVENT
+ @param UserIndex Pointer to the index of the event which
+ satisfied the wait condition
+
+ @retval EFI_SUCCESS The event indicated by Index was signaled.
+ @retval EFI_INVALID_PARAMETER The event indicated by Index has a notification
+ function or Event was not a valid type
+ @retval EFI_UNSUPPORTED The current TPL is not TPL_APPLICATION
+
+**/
+EFI_STATUS
+EFIAPI
+CoreWaitForEvent (
+ IN UINTN NumberOfEvents,
+ IN EFI_EVENT *UserEvents,
+ OUT UINTN *UserIndex
+ );
+
+/**
+ Closes an event and frees the event structure.
+
+ @param UserEvent Event to close
+
+ @retval EFI_INVALID_PARAMETER Parameters are not valid.
+ @retval EFI_SUCCESS The event has been closed
+
+**/
+EFI_STATUS
+EFIAPI
+CoreCloseEvent (
+ IN EFI_EVENT UserEvent
+ );
+
+/**
+ Check the status of an event.
+
+ @param UserEvent The event to check
+
+ @retval EFI_SUCCESS The event is in the signaled state
+ @retval EFI_NOT_READY The event is not in the signaled state
+ @retval EFI_INVALID_PARAMETER Event is of type EVT_NOTIFY_SIGNAL
+
+**/
+EFI_STATUS
+EFIAPI
+CoreCheckEvent (
+ IN EFI_EVENT UserEvent
+ );
+
+/**
+ Adds reserved memory, system memory, or memory-mapped I/O resources to the
+ global coherency domain of the processor.
+
+ @param GcdMemoryType Memory type of the memory space.
+ @param BaseAddress Base address of the memory space.
+ @param Length Length of the memory space.
+ @param Capabilities alterable attributes of the memory space.
+
+ @retval EFI_SUCCESS Merged this memory space into GCD map.
+
+**/
+EFI_STATUS
+EFIAPI
+CoreAddMemorySpace (
+ IN EFI_GCD_MEMORY_TYPE GcdMemoryType,
+ IN EFI_PHYSICAL_ADDRESS BaseAddress,
+ IN UINT64 Length,
+ IN UINT64 Capabilities
+ );
+
+/**
+ Allocates nonexistent memory, reserved memory, system memory, or memorymapped
+ I/O resources from the global coherency domain of the processor.
+
+ @param GcdAllocateType The type of allocate operation
+ @param GcdMemoryType The desired memory type
+ @param Alignment Align with 2^Alignment
+ @param Length Length to allocate
+ @param BaseAddress Base address to allocate
+ @param ImageHandle The image handle consume the allocated space.
+ @param DeviceHandle The device handle consume the allocated space.
+
+ @retval EFI_INVALID_PARAMETER Invalid parameter.
+ @retval EFI_NOT_FOUND No descriptor contains the desired space.
+ @retval EFI_SUCCESS Memory space successfully allocated.
+
+**/
+EFI_STATUS
+EFIAPI
+CoreAllocateMemorySpace (
+ IN EFI_GCD_ALLOCATE_TYPE GcdAllocateType,
+ IN EFI_GCD_MEMORY_TYPE GcdMemoryType,
+ IN UINTN Alignment,
+ IN UINT64 Length,
+ IN OUT EFI_PHYSICAL_ADDRESS *BaseAddress,
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_HANDLE DeviceHandle OPTIONAL
+ );
+
+/**
+ Frees nonexistent memory, reserved memory, system memory, or memory-mapped
+ I/O resources from the global coherency domain of the processor.
+
+ @param BaseAddress Base address of the memory space.
+ @param Length Length of the memory space.
+
+ @retval EFI_SUCCESS Space successfully freed.
+
+**/
+EFI_STATUS
+EFIAPI
+CoreFreeMemorySpace (
+ IN EFI_PHYSICAL_ADDRESS BaseAddress,
+ IN UINT64 Length
+ );
+
+/**
+ Removes reserved memory, system memory, or memory-mapped I/O resources from
+ the global coherency domain of the processor.
+
+ @param BaseAddress Base address of the memory space.
+ @param Length Length of the memory space.
+
+ @retval EFI_SUCCESS Successfully remove a segment of memory space.
+
+**/
+EFI_STATUS
+EFIAPI
+CoreRemoveMemorySpace (
+ IN EFI_PHYSICAL_ADDRESS BaseAddress,
+ IN UINT64 Length
+ );
+
+/**
+ Retrieves the descriptor for a memory region containing a specified address.
+
+ @param BaseAddress Specified start address
+ @param Descriptor Specified length
+
+ @retval EFI_INVALID_PARAMETER Invalid parameter
+ @retval EFI_SUCCESS Successfully get memory space descriptor.
+
+**/
+EFI_STATUS
+EFIAPI
+CoreGetMemorySpaceDescriptor (
+ IN EFI_PHYSICAL_ADDRESS BaseAddress,
+ OUT EFI_GCD_MEMORY_SPACE_DESCRIPTOR *Descriptor
+ );
+
+/**
+ Modifies the attributes for a memory region in the global coherency domain of the
+ processor.
+
+ @param BaseAddress Specified start address
+ @param Length Specified length
+ @param Attributes Specified attributes
+
+ @retval EFI_SUCCESS The attributes were set for the memory region.
+ @retval EFI_INVALID_PARAMETER Length is zero.
+ @retval EFI_UNSUPPORTED The processor does not support one or more bytes of the memory
+ resource range specified by BaseAddress and Length.
+ @retval EFI_UNSUPPORTED The bit mask of attributes is not support for the memory resource
+ range specified by BaseAddress and Length.
+ @retval EFI_ACCESS_DENIED The attributes for the memory resource range specified by
+ BaseAddress and Length cannot be modified.
+ @retval EFI_OUT_OF_RESOURCES There are not enough system resources to modify the attributes of
+ the memory resource range.
+ @retval EFI_NOT_AVAILABLE_YET The attributes cannot be set because CPU architectural protocol is
+ not available yet.
+
+**/
+EFI_STATUS
+EFIAPI
+CoreSetMemorySpaceAttributes (
+ IN EFI_PHYSICAL_ADDRESS BaseAddress,
+ IN UINT64 Length,
+ IN UINT64 Attributes
+ );
+
+/**
+ Modifies the capabilities for a memory region in the global coherency domain of the
+ processor.
+
+ @param BaseAddress The physical address that is the start address of a memory region.
+ @param Length The size in bytes of the memory region.
+ @param Capabilities The bit mask of capabilities that the memory region supports.
+
+ @retval EFI_SUCCESS The capabilities were set for the memory region.
+ @retval EFI_INVALID_PARAMETER Length is zero.
+ @retval EFI_UNSUPPORTED The capabilities specified by Capabilities do not include the
+ memory region attributes currently in use.
+ @retval EFI_ACCESS_DENIED The capabilities for the memory resource range specified by
+ BaseAddress and Length cannot be modified.
+ @retval EFI_OUT_OF_RESOURCES There are not enough system resources to modify the capabilities
+ of the memory resource range.
+**/
+EFI_STATUS
+EFIAPI
+CoreSetMemorySpaceCapabilities (
+ IN EFI_PHYSICAL_ADDRESS BaseAddress,
+ IN UINT64 Length,
+ IN UINT64 Capabilities
+ );
+
+/**
+ Returns a map of the memory resources in the global coherency domain of the
+ processor.
+
+ @param NumberOfDescriptors Number of descriptors.
+ @param MemorySpaceMap Descriptor array
+
+ @retval EFI_INVALID_PARAMETER Invalid parameter
+ @retval EFI_OUT_OF_RESOURCES No enough buffer to allocate
+ @retval EFI_SUCCESS Successfully get memory space map.
+
+**/
+EFI_STATUS
+EFIAPI
+CoreGetMemorySpaceMap (
+ OUT UINTN *NumberOfDescriptors,
+ OUT EFI_GCD_MEMORY_SPACE_DESCRIPTOR **MemorySpaceMap
+ );
+
+/**
+ Adds reserved I/O or I/O resources to the global coherency domain of the processor.
+
+ @param GcdIoType IO type of the segment.
+ @param BaseAddress Base address of the segment.
+ @param Length Length of the segment.
+
+ @retval EFI_SUCCESS Merged this segment into GCD map.
+ @retval EFI_INVALID_PARAMETER Parameter not valid
+
+**/
+EFI_STATUS
+EFIAPI
+CoreAddIoSpace (
+ IN EFI_GCD_IO_TYPE GcdIoType,
+ IN EFI_PHYSICAL_ADDRESS BaseAddress,
+ IN UINT64 Length
+ );
+
+/**
+ Allocates nonexistent I/O, reserved I/O, or I/O resources from the global coherency
+ domain of the processor.
+
+ @param GcdAllocateType The type of allocate operation
+ @param GcdIoType The desired IO type
+ @param Alignment Align with 2^Alignment
+ @param Length Length to allocate
+ @param BaseAddress Base address to allocate
+ @param ImageHandle The image handle consume the allocated space.
+ @param DeviceHandle The device handle consume the allocated space.
+
+ @retval EFI_INVALID_PARAMETER Invalid parameter.
+ @retval EFI_NOT_FOUND No descriptor contains the desired space.
+ @retval EFI_SUCCESS IO space successfully allocated.
+
+**/
+EFI_STATUS
+EFIAPI
+CoreAllocateIoSpace (
+ IN EFI_GCD_ALLOCATE_TYPE GcdAllocateType,
+ IN EFI_GCD_IO_TYPE GcdIoType,
+ IN UINTN Alignment,
+ IN UINT64 Length,
+ IN OUT EFI_PHYSICAL_ADDRESS *BaseAddress,
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_HANDLE DeviceHandle OPTIONAL
+ );
+
+/**
+ Frees nonexistent I/O, reserved I/O, or I/O resources from the global coherency
+ domain of the processor.
+
+ @param BaseAddress Base address of the segment.
+ @param Length Length of the segment.
+
+ @retval EFI_SUCCESS Space successfully freed.
+
+**/
+EFI_STATUS
+EFIAPI
+CoreFreeIoSpace (
+ IN EFI_PHYSICAL_ADDRESS BaseAddress,
+ IN UINT64 Length
+ );
+
+/**
+ Removes reserved I/O or I/O resources from the global coherency domain of the
+ processor.
+
+ @param BaseAddress Base address of the segment.
+ @param Length Length of the segment.
+
+ @retval EFI_SUCCESS Successfully removed a segment of IO space.
+
+**/
+EFI_STATUS
+EFIAPI
+CoreRemoveIoSpace (
+ IN EFI_PHYSICAL_ADDRESS BaseAddress,
+ IN UINT64 Length
+ );
+
+/**
+ Retrieves the descriptor for an I/O region containing a specified address.
+
+ @param BaseAddress Specified start address
+ @param Descriptor Specified length
+
+ @retval EFI_INVALID_PARAMETER Descriptor is NULL.
+ @retval EFI_SUCCESS Successfully get the IO space descriptor.
+
+**/
+EFI_STATUS
+EFIAPI
+CoreGetIoSpaceDescriptor (
+ IN EFI_PHYSICAL_ADDRESS BaseAddress,
+ OUT EFI_GCD_IO_SPACE_DESCRIPTOR *Descriptor
+ );
+
+/**
+ Returns a map of the I/O resources in the global coherency domain of the processor.
+
+ @param NumberOfDescriptors Number of descriptors.
+ @param IoSpaceMap Descriptor array
+
+ @retval EFI_INVALID_PARAMETER Invalid parameter
+ @retval EFI_OUT_OF_RESOURCES No enough buffer to allocate
+ @retval EFI_SUCCESS Successfully get IO space map.
+
+**/
+EFI_STATUS
+EFIAPI
+CoreGetIoSpaceMap (
+ OUT UINTN *NumberOfDescriptors,
+ OUT EFI_GCD_IO_SPACE_DESCRIPTOR **IoSpaceMap
+ );
+
+/**
+ This is the main Dispatcher for DXE and it exits when there are no more
+ drivers to run. Drain the mScheduledQueue and load and start a PE
+ image for each driver. Search the mDiscoveredList to see if any driver can
+ be placed on the mScheduledQueue. If no drivers are placed on the
+ mScheduledQueue exit the function. On exit it is assumed the Bds()
+ will be called, and when the Bds() exits the Dispatcher will be called
+ again.
+
+ @retval EFI_ALREADY_STARTED The DXE Dispatcher is already running
+ @retval EFI_NOT_FOUND No DXE Drivers were dispatched
+ @retval EFI_SUCCESS One or more DXE Drivers were dispatched
+
+**/
+EFI_STATUS
+EFIAPI
+CoreDispatcher (
+ VOID
+ );
+
+/**
+ Check every driver and locate a matching one. If the driver is found, the Unrequested
+ state flag is cleared.
+
+ @param FirmwareVolumeHandle The handle of the Firmware Volume that contains
+ the firmware file specified by DriverName.
+ @param DriverName The Driver name to put in the Dependent state.
+
+ @retval EFI_SUCCESS The DriverName was found and it's SOR bit was
+ cleared
+ @retval EFI_NOT_FOUND The DriverName does not exist or it's SOR bit was
+ not set.
+
+**/
+EFI_STATUS
+EFIAPI
+CoreSchedule (
+ IN EFI_HANDLE FirmwareVolumeHandle,
+ IN EFI_GUID *DriverName
+ );
+
+/**
+ Convert a driver from the Untrused back to the Scheduled state.
+
+ @param FirmwareVolumeHandle The handle of the Firmware Volume that contains
+ the firmware file specified by DriverName.
+ @param DriverName The Driver name to put in the Scheduled state
+
+ @retval EFI_SUCCESS The file was found in the untrusted state, and it
+ was promoted to the trusted state.
+ @retval EFI_NOT_FOUND The file was not found in the untrusted state.
+
+**/
+EFI_STATUS
+EFIAPI
+CoreTrust (
+ IN EFI_HANDLE FirmwareVolumeHandle,
+ IN EFI_GUID *DriverName
+ );
+
+/**
+ This routine is the driver initialization entry point. It initializes the
+ libraries, and registers two notification functions. These notification
+ functions are responsible for building the FV stack dynamically.
+
+ @param ImageHandle The image handle.
+ @param SystemTable The system table.
+
+ @retval EFI_SUCCESS Function successfully returned.
+
+**/
+EFI_STATUS
+EFIAPI
+FwVolDriverInit (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ );
+
+/**
+ Entry point of the section extraction code. Initializes an instance of the
+ section extraction interface and installs it on a new handle.
+
+ @param ImageHandle A handle for the image that is initializing this driver
+ @param SystemTable A pointer to the EFI system table
+
+ @retval EFI_SUCCESS Driver initialized successfully
+ @retval EFI_OUT_OF_RESOURCES Could not allocate needed resources
+
+**/
+EFI_STATUS
+EFIAPI
+InitializeSectionExtraction (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ );
+
+/**
+ This DXE service routine is used to process a firmware volume. In
+ particular, it can be called by BDS to process a single firmware
+ volume found in a capsule.
+
+ @param FvHeader pointer to a firmware volume header
+ @param Size the size of the buffer pointed to by FvHeader
+ @param FVProtocolHandle the handle on which a firmware volume protocol
+ was produced for the firmware volume passed in.
+
+ @retval EFI_OUT_OF_RESOURCES if an FVB could not be produced due to lack of
+ system resources
+ @retval EFI_VOLUME_CORRUPTED if the volume was corrupted
+ @retval EFI_SUCCESS a firmware volume protocol was produced for the
+ firmware volume
+
+**/
+EFI_STATUS
+EFIAPI
+CoreProcessFirmwareVolume (
+ IN VOID *FvHeader,
+ IN UINTN Size,
+ OUT EFI_HANDLE *FVProtocolHandle
+ );
+
+//
+// Functions used during debug buils
+//
+
+/**
+ Displays Architectural protocols that were not loaded and are required for DXE
+ core to function. Only used in Debug Builds.
+
+**/
+VOID
+CoreDisplayMissingArchProtocols (
+ VOID
+ );
+
+/**
+ Traverse the discovered list for any drivers that were discovered but not loaded
+ because the dependency experessions evaluated to false.
+
+**/
+VOID
+CoreDisplayDiscoveredNotDispatched (
+ VOID
+ );
+
+/**
+ Place holder function until all the Boot Services and Runtime Services are
+ available.
+
+ @param Arg1 Undefined
+
+ @return EFI_NOT_AVAILABLE_YET
+
+**/
+EFI_STATUS
+EFIAPI
+CoreEfiNotAvailableYetArg1 (
+ UINTN Arg1
+ );
+
+/**
+ Place holder function until all the Boot Services and Runtime Services are available.
+
+ @param Arg1 Undefined
+ @param Arg2 Undefined
+
+ @return EFI_NOT_AVAILABLE_YET
+
+**/
+EFI_STATUS
+EFIAPI
+CoreEfiNotAvailableYetArg2 (
+ UINTN Arg1,
+ UINTN Arg2
+ );
+
+/**
+ Place holder function until all the Boot Services and Runtime Services are available.
+
+ @param Arg1 Undefined
+ @param Arg2 Undefined
+ @param Arg3 Undefined
+
+ @return EFI_NOT_AVAILABLE_YET
+
+**/
+EFI_STATUS
+EFIAPI
+CoreEfiNotAvailableYetArg3 (
+ UINTN Arg1,
+ UINTN Arg2,
+ UINTN Arg3
+ );
+
+/**
+ Place holder function until all the Boot Services and Runtime Services are available.
+
+ @param Arg1 Undefined
+ @param Arg2 Undefined
+ @param Arg3 Undefined
+ @param Arg4 Undefined
+
+ @return EFI_NOT_AVAILABLE_YET
+
+**/
+EFI_STATUS
+EFIAPI
+CoreEfiNotAvailableYetArg4 (
+ UINTN Arg1,
+ UINTN Arg2,
+ UINTN Arg3,
+ UINTN Arg4
+ );
+
+/**
+ Place holder function until all the Boot Services and Runtime Services are available.
+
+ @param Arg1 Undefined
+ @param Arg2 Undefined
+ @param Arg3 Undefined
+ @param Arg4 Undefined
+ @param Arg5 Undefined
+
+ @return EFI_NOT_AVAILABLE_YET
+
+**/
+EFI_STATUS
+EFIAPI
+CoreEfiNotAvailableYetArg5 (
+ UINTN Arg1,
+ UINTN Arg2,
+ UINTN Arg3,
+ UINTN Arg4,
+ UINTN Arg5
+ );
+
+/**
+ Given a compressed source buffer, this function retrieves the size of the
+ uncompressed buffer and the size of the scratch buffer required to decompress
+ the compressed source buffer.
+
+ The GetInfo() function retrieves the size of the uncompressed buffer and the
+ temporary scratch buffer required to decompress the buffer specified by Source
+ and SourceSize. If the size of the uncompressed buffer or the size of the
+ scratch buffer cannot be determined from the compressed data specified by
+ Source and SourceData, then EFI_INVALID_PARAMETER is returned. Otherwise, the
+ size of the uncompressed buffer is returned in DestinationSize, the size of
+ the scratch buffer is returned in ScratchSize, and EFI_SUCCESS is returned.
+ The GetInfo() function does not have scratch buffer available to perform a
+ thorough checking of the validity of the source data. It just retrieves the
+ "Original Size" field from the beginning bytes of the source data and output
+ it as DestinationSize. And ScratchSize is specific to the decompression
+ implementation.
+
+ @param This A pointer to the EFI_DECOMPRESS_PROTOCOL instance.
+ @param Source The source buffer containing the compressed data.
+ @param SourceSize The size, in bytes, of the source buffer.
+ @param DestinationSize A pointer to the size, in bytes, of the
+ uncompressed buffer that will be generated when the
+ compressed buffer specified by Source and
+ SourceSize is decompressed.
+ @param ScratchSize A pointer to the size, in bytes, of the scratch
+ buffer that is required to decompress the
+ compressed buffer specified by Source and
+ SourceSize.
+
+ @retval EFI_SUCCESS The size of the uncompressed data was returned in
+ DestinationSize and the size of the scratch buffer
+ was returned in ScratchSize.
+ @retval EFI_INVALID_PARAMETER The size of the uncompressed data or the size of
+ the scratch buffer cannot be determined from the
+ compressed data specified by Source and
+ SourceSize.
+
+**/
+EFI_STATUS
+EFIAPI
+DxeMainUefiDecompressGetInfo (
+ IN EFI_DECOMPRESS_PROTOCOL *This,
+ IN VOID *Source,
+ IN UINT32 SourceSize,
+ OUT UINT32 *DestinationSize,
+ OUT UINT32 *ScratchSize
+ );
+
+/**
+ Decompresses a compressed source buffer.
+
+ The Decompress() function extracts decompressed data to its original form.
+ This protocol is designed so that the decompression algorithm can be
+ implemented without using any memory services. As a result, the Decompress()
+ Function is not allowed to call AllocatePool() or AllocatePages() in its
+ implementation. It is the caller's responsibility to allocate and free the
+ Destination and Scratch buffers.
+ If the compressed source data specified by Source and SourceSize is
+ sucessfully decompressed into Destination, then EFI_SUCCESS is returned. If
+ the compressed source data specified by Source and SourceSize is not in a
+ valid compressed data format, then EFI_INVALID_PARAMETER is returned.
+
+ @param This A pointer to the EFI_DECOMPRESS_PROTOCOL instance.
+ @param Source The source buffer containing the compressed data.
+ @param SourceSize SourceSizeThe size of source data.
+ @param Destination On output, the destination buffer that contains
+ the uncompressed data.
+ @param DestinationSize The size of the destination buffer. The size of
+ the destination buffer needed is obtained from
+ EFI_DECOMPRESS_PROTOCOL.GetInfo().
+ @param Scratch A temporary scratch buffer that is used to perform
+ the decompression.
+ @param ScratchSize The size of scratch buffer. The size of the
+ scratch buffer needed is obtained from GetInfo().
+
+ @retval EFI_SUCCESS Decompression completed successfully, and the
+ uncompressed buffer is returned in Destination.
+ @retval EFI_INVALID_PARAMETER The source buffer specified by Source and
+ SourceSize is corrupted (not in a valid
+ compressed format).
+
+**/
+EFI_STATUS
+EFIAPI
+DxeMainUefiDecompress (
+ IN EFI_DECOMPRESS_PROTOCOL *This,
+ IN VOID *Source,
+ IN UINT32 SourceSize,
+ IN OUT VOID *Destination,
+ IN UINT32 DestinationSize,
+ IN OUT VOID *Scratch,
+ IN UINT32 ScratchSize
+ );
+
+/**
+ SEP member function. This function creates and returns a new section stream
+ handle to represent the new section stream.
+
+ @param SectionStreamLength Size in bytes of the section stream.
+ @param SectionStream Buffer containing the new section stream.
+ @param SectionStreamHandle A pointer to a caller allocated UINTN that on
+ output contains the new section stream handle.
+
+ @retval EFI_SUCCESS The section stream is created successfully.
+ @retval EFI_OUT_OF_RESOURCES memory allocation failed.
+ @retval EFI_INVALID_PARAMETER Section stream does not end concident with end
+ of last section.
+
+**/
+EFI_STATUS
+EFIAPI
+OpenSectionStream (
+ IN UINTN SectionStreamLength,
+ IN VOID *SectionStream,
+ OUT UINTN *SectionStreamHandle
+ );
+
+/**
+ SEP member function. Retrieves requested section from section stream.
+
+ @param SectionStreamHandle The section stream from which to extract the
+ requested section.
+ @param SectionType A pointer to the type of section to search for.
+ @param SectionDefinitionGuid If the section type is EFI_SECTION_GUID_DEFINED,
+ then SectionDefinitionGuid indicates which of
+ these types of sections to search for.
+ @param SectionInstance Indicates which instance of the requested
+ section to return.
+ @param Buffer Double indirection to buffer. If *Buffer is
+ non-null on input, then the buffer is caller
+ allocated. If Buffer is NULL, then the buffer
+ is callee allocated. In either case, the
+ required buffer size is returned in *BufferSize.
+ @param BufferSize On input, indicates the size of *Buffer if
+ *Buffer is non-null on input. On output,
+ indicates the required size (allocated size if
+ callee allocated) of *Buffer.
+ @param AuthenticationStatus A pointer to a caller-allocated UINT32 that
+ indicates the authentication status of the
+ output buffer. If the input section's
+ GuidedSectionHeader.Attributes field
+ has the EFI_GUIDED_SECTION_AUTH_STATUS_VALID
+ bit as clear, AuthenticationStatus must return
+ zero. Both local bits (19:16) and aggregate
+ bits (3:0) in AuthenticationStatus are returned
+ by ExtractSection(). These bits reflect the
+ status of the extraction operation. The bit
+ pattern in both regions must be the same, as
+ the local and aggregate authentication statuses
+ have equivalent meaning at this level. If the
+ function returns anything other than
+ EFI_SUCCESS, the value of *AuthenticationStatus
+ is undefined.
+ @param IsFfs3Fv Indicates the FV format.
+
+ @retval EFI_SUCCESS Section was retrieved successfully
+ @retval EFI_PROTOCOL_ERROR A GUID defined section was encountered in the
+ section stream with its
+ EFI_GUIDED_SECTION_PROCESSING_REQUIRED bit set,
+ but there was no corresponding GUIDed Section
+ Extraction Protocol in the handle database.
+ *Buffer is unmodified.
+ @retval EFI_NOT_FOUND An error was encountered when parsing the
+ SectionStream. This indicates the SectionStream
+ is not correctly formatted.
+ @retval EFI_NOT_FOUND The requested section does not exist.
+ @retval EFI_OUT_OF_RESOURCES The system has insufficient resources to process
+ the request.
+ @retval EFI_INVALID_PARAMETER The SectionStreamHandle does not exist.
+ @retval EFI_WARN_TOO_SMALL The size of the caller allocated input buffer is
+ insufficient to contain the requested section.
+ The input buffer is filled and section contents
+ are truncated.
+
+**/
+EFI_STATUS
+EFIAPI
+GetSection (
+ IN UINTN SectionStreamHandle,
+ IN EFI_SECTION_TYPE *SectionType,
+ IN EFI_GUID *SectionDefinitionGuid,
+ IN UINTN SectionInstance,
+ IN VOID **Buffer,
+ IN OUT UINTN *BufferSize,
+ OUT UINT32 *AuthenticationStatus,
+ IN BOOLEAN IsFfs3Fv
+ );
+
+/**
+ SEP member function. Deletes an existing section stream
+
+ @param StreamHandleToClose Indicates the stream to close
+ @param FreeStreamBuffer TRUE - Need to free stream buffer;
+ FALSE - No need to free stream buffer.
+
+ @retval EFI_SUCCESS The section stream is closed sucessfully.
+ @retval EFI_OUT_OF_RESOURCES Memory allocation failed.
+ @retval EFI_INVALID_PARAMETER Section stream does not end concident with end
+ of last section.
+
+**/
+EFI_STATUS
+EFIAPI
+CloseSectionStream (
+ IN UINTN StreamHandleToClose,
+ IN BOOLEAN FreeStreamBuffer
+ );
+
+/**
+ Creates and initializes the DebugImageInfo Table. Also creates the configuration
+ table and registers it into the system table.
+
+ Note:
+ This function allocates memory, frees it, and then allocates memory at an
+ address within the initial allocation. Since this function is called early
+ in DXE core initialization (before drivers are dispatched), this should not
+ be a problem.
+
+**/
+VOID
+CoreInitializeDebugImageInfoTable (
+ VOID
+ );
+
+/**
+ Update the CRC32 in the Debug Table.
+ Since the CRC32 service is made available by the Runtime driver, we have to
+ wait for the Runtime Driver to be installed before the CRC32 can be computed.
+ This function is called elsewhere by the core when the runtime architectural
+ protocol is produced.
+
+**/
+VOID
+CoreUpdateDebugTableCrc32 (
+ VOID
+ );
+
+/**
+ Adds a new DebugImageInfo structure to the DebugImageInfo Table. Re-Allocates
+ the table if it's not large enough to accomidate another entry.
+
+ @param ImageInfoType type of debug image information
+ @param LoadedImage pointer to the loaded image protocol for the image being
+ loaded
+ @param ImageHandle image handle for the image being loaded
+
+**/
+VOID
+CoreNewDebugImageInfoEntry (
+ IN UINT32 ImageInfoType,
+ IN EFI_LOADED_IMAGE_PROTOCOL *LoadedImage,
+ IN EFI_HANDLE ImageHandle
+ );
+
+/**
+ Removes and frees an entry from the DebugImageInfo Table.
+
+ @param ImageHandle image handle for the image being unloaded
+
+**/
+VOID
+CoreRemoveDebugImageInfoEntry (
+ EFI_HANDLE ImageHandle
+ );
+
+/**
+ This routine consumes FV hobs and produces instances of FW_VOL_BLOCK_PROTOCOL as appropriate.
+
+ @param ImageHandle The image handle.
+ @param SystemTable The system table.
+
+ @retval EFI_SUCCESS Successfully initialized firmware volume block
+ driver.
+
+**/
+EFI_STATUS
+EFIAPI
+FwVolBlockDriverInit (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ );
+
+/**
+
+ Get FVB authentication status
+
+ @param FvbProtocol FVB protocol.
+
+ @return Authentication status.
+
+**/
+UINT32
+GetFvbAuthenticationStatus (
+ IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *FvbProtocol
+ );
+
+/**
+ This routine produces a firmware volume block protocol on a given
+ buffer.
+
+ @param BaseAddress base address of the firmware volume image
+ @param Length length of the firmware volume image
+ @param ParentHandle handle of parent firmware volume, if this image
+ came from an FV image file and section in another firmware
+ volume (ala capsules)
+ @param AuthenticationStatus Authentication status inherited, if this image
+ came from an FV image file and section in another firmware volume.
+ @param FvProtocol Firmware volume block protocol produced.
+
+ @retval EFI_VOLUME_CORRUPTED Volume corrupted.
+ @retval EFI_OUT_OF_RESOURCES No enough buffer to be allocated.
+ @retval EFI_SUCCESS Successfully produced a FVB protocol on given
+ buffer.
+
+**/
+EFI_STATUS
+ProduceFVBProtocolOnBuffer (
+ IN EFI_PHYSICAL_ADDRESS BaseAddress,
+ IN UINT64 Length,
+ IN EFI_HANDLE ParentHandle,
+ IN UINT32 AuthenticationStatus,
+ OUT EFI_HANDLE *FvProtocol OPTIONAL
+ );
+
+/**
+ Raising to the task priority level of the mutual exclusion
+ lock, and then acquires ownership of the lock.
+
+ @param Lock The lock to acquire
+
+ @return Lock owned
+
+**/
+VOID
+CoreAcquireLock (
+ IN EFI_LOCK *Lock
+ );
+
+/**
+ Initialize a basic mutual exclusion lock. Each lock
+ provides mutual exclusion access at it's task priority
+ level. Since there is no-premption (at any TPL) or
+ multiprocessor support, acquiring the lock only consists
+ of raising to the locks TPL.
+
+ @param Lock The EFI_LOCK structure to initialize
+
+ @retval EFI_SUCCESS Lock Owned.
+ @retval EFI_ACCESS_DENIED Reentrant Lock Acquisition, Lock not Owned.
+
+**/
+EFI_STATUS
+CoreAcquireLockOrFail (
+ IN EFI_LOCK *Lock
+ );
+
+/**
+ Releases ownership of the mutual exclusion lock, and
+ restores the previous task priority level.
+
+ @param Lock The lock to release
+
+ @return Lock unowned
+
+**/
+VOID
+CoreReleaseLock (
+ IN EFI_LOCK *Lock
+ );
+
+/**
+ Read data from Firmware Block by FVB protocol Read.
+ The data may cross the multi block ranges.
+
+ @param Fvb The FW_VOL_BLOCK_PROTOCOL instance from which to read data.
+ @param StartLba Pointer to StartLba.
+ On input, the start logical block index from which to read.
+ On output,the end logical block index after reading.
+ @param Offset Pointer to Offset
+ On input, offset into the block at which to begin reading.
+ On output, offset into the end block after reading.
+ @param DataSize Size of data to be read.
+ @param Data Pointer to Buffer that the data will be read into.
+
+ @retval EFI_SUCCESS Successfully read data from firmware block.
+ @retval others
+**/
+EFI_STATUS
+ReadFvbData (
+ IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb,
+ IN OUT EFI_LBA *StartLba,
+ IN OUT UINTN *Offset,
+ IN UINTN DataSize,
+ OUT UINT8 *Data
+ );
+
+/**
+ Given the supplied FW_VOL_BLOCK_PROTOCOL, allocate a buffer for output and
+ copy the real length volume header into it.
+
+ @param Fvb The FW_VOL_BLOCK_PROTOCOL instance from which to
+ read the volume header
+ @param FwVolHeader Pointer to pointer to allocated buffer in which
+ the volume header is returned.
+
+ @retval EFI_OUT_OF_RESOURCES No enough buffer could be allocated.
+ @retval EFI_SUCCESS Successfully read volume header to the allocated
+ buffer.
+ @retval EFI_INVALID_PARAMETER The FV Header signature is not as expected or
+ the file system could not be understood.
+
+**/
+EFI_STATUS
+GetFwVolHeader (
+ IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb,
+ OUT EFI_FIRMWARE_VOLUME_HEADER **FwVolHeader
+ );
+
+/**
+ Verify checksum of the firmware volume header.
+
+ @param FvHeader Points to the firmware volume header to be checked
+
+ @retval TRUE Checksum verification passed
+ @retval FALSE Checksum verification failed
+
+**/
+BOOLEAN
+VerifyFvHeaderChecksum (
+ IN EFI_FIRMWARE_VOLUME_HEADER *FvHeader
+ );
+
+/**
+ Initialize memory profile.
+
+ @param HobStart The start address of the HOB.
+
+**/
+VOID
+MemoryProfileInit (
+ IN VOID *HobStart
+ );
+
+/**
+ Install memory profile protocol.
+
+**/
+VOID
+MemoryProfileInstallProtocol (
+ VOID
+ );
+
+/**
+ Register image to memory profile.
+
+ @param DriverEntry Image info.
+ @param FileType Image file type.
+
+ @return EFI_SUCCESS Register successfully.
+ @return EFI_UNSUPPORTED Memory profile unsupported,
+ or memory profile for the image is not required.
+ @return EFI_OUT_OF_RESOURCES No enough resource for this register.
+
+**/
+EFI_STATUS
+RegisterMemoryProfileImage (
+ IN LOADED_IMAGE_PRIVATE_DATA *DriverEntry,
+ IN EFI_FV_FILETYPE FileType
+ );
+
+/**
+ Unregister image from memory profile.
+
+ @param DriverEntry Image info.
+
+ @return EFI_SUCCESS Unregister successfully.
+ @return EFI_UNSUPPORTED Memory profile unsupported,
+ or memory profile for the image is not required.
+ @return EFI_NOT_FOUND The image is not found.
+
+**/
+EFI_STATUS
+UnregisterMemoryProfileImage (
+ IN LOADED_IMAGE_PRIVATE_DATA *DriverEntry
+ );
+
+/**
+ Update memory profile information.
+
+ @param CallerAddress Address of caller who call Allocate or Free.
+ @param Action This Allocate or Free action.
+ @param MemoryType Memory type.
+ EfiMaxMemoryType means the MemoryType is unknown.
+ @param Size Buffer size.
+ @param Buffer Buffer address.
+ @param ActionString String for memory profile action.
+ Only needed for user defined allocate action.
+
+ @return EFI_SUCCESS Memory profile is updated.
+ @return EFI_UNSUPPORTED Memory profile is unsupported,
+ or memory profile for the image is not required,
+ or memory profile for the memory type is not required.
+ @return EFI_ACCESS_DENIED It is during memory profile data getting.
+ @return EFI_ABORTED Memory profile recording is not enabled.
+ @return EFI_OUT_OF_RESOURCES No enough resource to update memory profile for allocate action.
+ @return EFI_NOT_FOUND No matched allocate info found for free action.
+
+**/
+EFI_STATUS
+EFIAPI
+CoreUpdateProfile (
+ IN EFI_PHYSICAL_ADDRESS CallerAddress,
+ IN MEMORY_PROFILE_ACTION Action,
+ IN EFI_MEMORY_TYPE MemoryType,
+ IN UINTN Size, // Valid for AllocatePages/FreePages/AllocatePool
+ IN VOID *Buffer,
+ IN CHAR8 *ActionString OPTIONAL
+ );
+
+/**
+ Internal function. Converts a memory range to use new attributes.
+
+ @param Start The first address of the range Must be page
+ aligned
+ @param NumberOfPages The number of pages to convert
+ @param NewAttributes The new attributes value for the range.
+
+**/
+VOID
+CoreUpdateMemoryAttributes (
+ IN EFI_PHYSICAL_ADDRESS Start,
+ IN UINT64 NumberOfPages,
+ IN UINT64 NewAttributes
+ );
+
+/**
+ Initialize MemoryAttrubutesTable support.
+**/
+VOID
+EFIAPI
+CoreInitializeMemoryAttributesTable (
+ VOID
+ );
+
+/**
+ Initialize Memory Protection support.
+**/
+VOID
+EFIAPI
+CoreInitializeMemoryProtection (
+ VOID
+ );
+
+/**
+ Install MemoryAttributesTable on memory allocation.
+
+ @param[in] MemoryType EFI memory type.
+**/
+VOID
+InstallMemoryAttributesTableOnMemoryAllocation (
+ IN EFI_MEMORY_TYPE MemoryType
+ );
+
+/**
+ Insert image record.
+
+ @param RuntimeImage Runtime image information
+**/
+VOID
+InsertImageRecord (
+ IN EFI_RUNTIME_IMAGE_ENTRY *RuntimeImage
+ );
+
+/**
+ Remove Image record.
+
+ @param RuntimeImage Runtime image information
+**/
+VOID
+RemoveImageRecord (
+ IN EFI_RUNTIME_IMAGE_ENTRY *RuntimeImage
+ );
+
+/**
+ Protect UEFI image.
+
+ @param[in] LoadedImage The loaded image protocol
+ @param[in] LoadedImageDevicePath The loaded image device path protocol
+**/
+VOID
+ProtectUefiImage (
+ IN EFI_LOADED_IMAGE_PROTOCOL *LoadedImage,
+ IN EFI_DEVICE_PATH_PROTOCOL *LoadedImageDevicePath
+ );
+
+/**
+ Unprotect UEFI image.
+
+ @param[in] LoadedImage The loaded image protocol
+ @param[in] LoadedImageDevicePath The loaded image device path protocol
+**/
+VOID
+UnprotectUefiImage (
+ IN EFI_LOADED_IMAGE_PROTOCOL *LoadedImage,
+ IN EFI_DEVICE_PATH_PROTOCOL *LoadedImageDevicePath
+ );
+
+/**
+ ExitBootServices Callback function for memory protection.
+**/
+VOID
+MemoryProtectionExitBootServicesCallback (
+ VOID
+ );
+
+/**
+ Manage memory permission attributes on a memory range, according to the
+ configured DXE memory protection policy.
+
+ @param OldType The old memory type of the range
+ @param NewType The new memory type of the range
+ @param Memory The base address of the range
+ @param Length The size of the range (in bytes)
+
+ @return EFI_SUCCESS If the the CPU arch protocol is not installed yet
+ @return EFI_SUCCESS If no DXE memory protection policy has been configured
+ @return EFI_SUCCESS If OldType and NewType use the same permission attributes
+ @return other Return value of gCpu->SetMemoryAttributes()
+
+**/
+EFI_STATUS
+EFIAPI
+ApplyMemoryProtectionPolicy (
+ IN EFI_MEMORY_TYPE OldType,
+ IN EFI_MEMORY_TYPE NewType,
+ IN EFI_PHYSICAL_ADDRESS Memory,
+ IN UINT64 Length
+ );
+
+/**
+ Merge continous memory map entries whose have same attributes.
+
+ @param MemoryMap A pointer to the buffer in which firmware places
+ the current memory map.
+ @param MemoryMapSize A pointer to the size, in bytes, of the
+ MemoryMap buffer. On input, this is the size of
+ the current memory map. On output,
+ it is the size of new memory map after merge.
+ @param DescriptorSize Size, in bytes, of an individual EFI_MEMORY_DESCRIPTOR.
+**/
+VOID
+MergeMemoryMap (
+ IN OUT EFI_MEMORY_DESCRIPTOR *MemoryMap,
+ IN OUT UINTN *MemoryMapSize,
+ IN UINTN DescriptorSize
+ );
+
+#endif
diff --git a/MdeModulePkg/Core/Dxe/DxeMain.inf b/MdeModulePkg/Core/Dxe/DxeMain.inf
index 090970aec6..0563377ff8 100644
--- a/MdeModulePkg/Core/Dxe/DxeMain.inf
+++ b/MdeModulePkg/Core/Dxe/DxeMain.inf
@@ -1,205 +1,205 @@
-## @file
-# This is core module in DXE phase.
-#
-# It provides an implementation of DXE Core that is compliant with DXE CIS.
-#
-# Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR>
-# SPDX-License-Identifier: BSD-2-Clause-Patent
-#
-##
-
-[Defines]
- INF_VERSION = 0x00010005
- BASE_NAME = DxeCore
- MODULE_UNI_FILE = DxeCore.uni
- FILE_GUID = D6A2CB7F-6A18-4e2f-B43B-9920A733700A
- MODULE_TYPE = DXE_CORE
- VERSION_STRING = 1.0
-
-
- ENTRY_POINT = DxeMain
-
-#
-# The following information is for reference only and not required by the build tools.
-#
-# VALID_ARCHITECTURES = IA32 X64 EBC (EBC is for build only)
-#
-
-[Sources]
- DxeMain.h
- SectionExtraction/CoreSectionExtraction.c
- Image/Image.c
- Image/Image.h
- Misc/DebugImageInfo.c
- Misc/Stall.c
- Misc/SetWatchdogTimer.c
- Misc/InstallConfigurationTable.c
- Misc/MemoryAttributesTable.c
- Misc/MemoryProtection.c
- Library/Library.c
- Hand/DriverSupport.c
- Hand/Notify.c
- Hand/Locate.c
- Hand/Handle.c
- Hand/Handle.h
- Gcd/Gcd.c
- Gcd/Gcd.h
- Mem/Pool.c
- Mem/Page.c
- Mem/MemData.c
- Mem/Imem.h
- Mem/MemoryProfileRecord.c
- Mem/HeapGuard.c
- Mem/HeapGuard.h
- FwVolBlock/FwVolBlock.c
- FwVolBlock/FwVolBlock.h
- FwVol/FwVolWrite.c
- FwVol/FwVolRead.c
- FwVol/FwVolAttrib.c
- FwVol/Ffs.c
- FwVol/FwVol.c
- FwVol/FwVolDriver.h
- Event/Tpl.c
- Event/Timer.c
- Event/Event.c
- Event/Event.h
- Dispatcher/Dependency.c
- Dispatcher/Dispatcher.c
- DxeMain/DxeProtocolNotify.c
- DxeMain/DxeMain.c
-
-[Packages]
- MdePkg/MdePkg.dec
- MdeModulePkg/MdeModulePkg.dec
-
-[LibraryClasses]
- BaseMemoryLib
- CacheMaintenanceLib
- UefiDecompressLib
- PerformanceLib
- HobLib
- BaseLib
- UefiLib
- DebugLib
- DxeCoreEntryPoint
- PeCoffLib
- PeCoffGetEntryPointLib
- PeCoffExtraActionLib
- ExtractGuidedSectionLib
- MemoryAllocationLib
- UefiBootServicesTableLib
- DevicePathLib
- ReportStatusCodeLib
- DxeServicesLib
- DebugAgentLib
- CpuExceptionHandlerLib
- PcdLib
- ImagePropertiesRecordLib
-
-[Guids]
- gEfiEventMemoryMapChangeGuid ## PRODUCES ## Event
- gEfiEventVirtualAddressChangeGuid ## CONSUMES ## Event
- ## CONSUMES ## Event
- ## PRODUCES ## Event
- gEfiEventBeforeExitBootServicesGuid
- gEfiEventExitBootServicesGuid
- gEfiHobMemoryAllocModuleGuid ## SOMETIMES_CONSUMES ## HOB
- gEfiFirmwareFileSystem2Guid ## CONSUMES ## GUID # Used to compare with FV's file system guid and get the FV's file system format
- gEfiFirmwareFileSystem3Guid ## CONSUMES ## GUID # Used to compare with FV's file system guid and get the FV's file system format
- gAprioriGuid ## SOMETIMES_CONSUMES ## File
- gEfiDebugImageInfoTableGuid ## PRODUCES ## SystemTable
- gEfiHobListGuid ## PRODUCES ## SystemTable
- gEfiDxeServicesTableGuid ## PRODUCES ## SystemTable
- ## PRODUCES ## SystemTable
- ## SOMETIMES_CONSUMES ## HOB
- gEfiMemoryTypeInformationGuid
- gEfiEventDxeDispatchGuid ## PRODUCES ## Event
- gLoadFixedAddressConfigurationTableGuid ## SOMETIMES_PRODUCES ## SystemTable
- ## PRODUCES ## Event
- ## CONSUMES ## Event
- gIdleLoopEventGuid
- gEventExitBootServicesFailedGuid ## SOMETIMES_PRODUCES ## Event
- gEfiVectorHandoffTableGuid ## SOMETIMES_PRODUCES ## SystemTable
- gEdkiiMemoryProfileGuid ## SOMETIMES_PRODUCES ## GUID # Install protocol
- gEfiMemoryAttributesTableGuid ## SOMETIMES_PRODUCES ## SystemTable
- gEfiEndOfDxeEventGroupGuid ## SOMETIMES_CONSUMES ## Event
- gEfiHobMemoryAllocStackGuid ## SOMETIMES_CONSUMES ## SystemTable
-
-[Ppis]
- gEfiVectorHandoffInfoPpiGuid ## UNDEFINED # HOB
-
-[Protocols]
- ## PRODUCES
- ## SOMETIMES_CONSUMES
- gEfiDecompressProtocolGuid
- gEfiSimpleFileSystemProtocolGuid ## SOMETIMES_CONSUMES
- gEfiLoadFileProtocolGuid ## SOMETIMES_CONSUMES
- gEfiLoadFile2ProtocolGuid ## SOMETIMES_CONSUMES
- gEfiBusSpecificDriverOverrideProtocolGuid ## SOMETIMES_CONSUMES
- gEfiDriverFamilyOverrideProtocolGuid ## SOMETIMES_CONSUMES
- gEfiPlatformDriverOverrideProtocolGuid ## SOMETIMES_CONSUMES
- gEfiDriverBindingProtocolGuid ## SOMETIMES_CONSUMES
- ## PRODUCES
- ## CONSUMES
- ## NOTIFY
- gEfiFirmwareVolumeBlockProtocolGuid
- ## PRODUCES
- ## CONSUMES
- ## NOTIFY
- gEfiFirmwareVolume2ProtocolGuid
- ## PRODUCES
- ## CONSUMES
- gEfiDevicePathProtocolGuid
- gEfiLoadedImageProtocolGuid ## PRODUCES
- gEfiLoadedImageDevicePathProtocolGuid ## PRODUCES
- gEfiHiiPackageListProtocolGuid ## SOMETIMES_PRODUCES
- gEfiSmmBase2ProtocolGuid ## SOMETIMES_CONSUMES
- gEdkiiPeCoffImageEmulatorProtocolGuid ## SOMETIMES_CONSUMES
-
- # Arch Protocols
- gEfiBdsArchProtocolGuid ## CONSUMES
- gEfiCpuArchProtocolGuid ## CONSUMES
- gEfiMetronomeArchProtocolGuid ## CONSUMES
- gEfiMonotonicCounterArchProtocolGuid ## CONSUMES
- gEfiRealTimeClockArchProtocolGuid ## CONSUMES
- gEfiResetArchProtocolGuid ## CONSUMES
- gEfiRuntimeArchProtocolGuid ## CONSUMES
- gEfiSecurityArchProtocolGuid ## CONSUMES
- gEfiSecurity2ArchProtocolGuid ## SOMETIMES_CONSUMES
- gEfiTimerArchProtocolGuid ## CONSUMES
- gEfiVariableWriteArchProtocolGuid ## CONSUMES
- gEfiVariableArchProtocolGuid ## CONSUMES
- gEfiCapsuleArchProtocolGuid ## CONSUMES
- gEfiWatchdogTimerArchProtocolGuid ## CONSUMES
-
-[Pcd]
- gEfiMdeModulePkgTokenSpaceGuid.PcdLoadFixAddressBootTimeCodePageNumber ## SOMETIMES_CONSUMES
- gEfiMdeModulePkgTokenSpaceGuid.PcdLoadFixAddressRuntimeCodePageNumber ## SOMETIMES_CONSUMES
- gEfiMdeModulePkgTokenSpaceGuid.PcdLoadModuleAtFixAddressEnable ## CONSUMES
- gEfiMdeModulePkgTokenSpaceGuid.PcdMaxEfiSystemTablePointerAddress ## CONSUMES
- gEfiMdeModulePkgTokenSpaceGuid.PcdMemoryProfileMemoryType ## CONSUMES
- gEfiMdeModulePkgTokenSpaceGuid.PcdMemoryProfilePropertyMask ## CONSUMES
- gEfiMdeModulePkgTokenSpaceGuid.PcdMemoryProfileDriverPath ## CONSUMES
- gEfiMdeModulePkgTokenSpaceGuid.PcdImageProtectionPolicy ## CONSUMES
- gEfiMdeModulePkgTokenSpaceGuid.PcdDxeNxMemoryProtectionPolicy ## CONSUMES
- gEfiMdeModulePkgTokenSpaceGuid.PcdNullPointerDetectionPropertyMask ## CONSUMES
- gEfiMdeModulePkgTokenSpaceGuid.PcdHeapGuardPageType ## CONSUMES
- gEfiMdeModulePkgTokenSpaceGuid.PcdHeapGuardPoolType ## CONSUMES
- gEfiMdeModulePkgTokenSpaceGuid.PcdHeapGuardPropertyMask ## CONSUMES
- gEfiMdeModulePkgTokenSpaceGuid.PcdCpuStackGuard ## CONSUMES
- gEfiMdeModulePkgTokenSpaceGuid.PcdFwVolDxeMaxEncapsulationDepth ## CONSUMES
- gEfiMdeModulePkgTokenSpaceGuid.PcdImageLargeAddressLoad ## CONSUMES
-
-# [Hob]
-# RESOURCE_DESCRIPTOR ## CONSUMES
-# MEMORY_ALLOCATION ## CONSUMES
-# FIRMWARE_VOLUME ## CONSUMES
-# UNDEFINED ## CONSUMES # CPU
-#
-# [Event]
-# EVENT_TYPE_RELATIVE_TIMER ## PRODUCES # DxeCore signals timer event.
-# EVENT_TYPE_PERIODIC_TIMER ## PRODUCES # DxeCore signals timer event.
-#
-
-[UserExtensions.TianoCore."ExtraFiles"]
- DxeCoreExtra.uni
+## @file
+# This is core module in DXE phase.
+#
+# It provides an implementation of DXE Core that is compliant with DXE CIS.
+#
+# Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR>
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = DxeCore
+ MODULE_UNI_FILE = DxeCore.uni
+ FILE_GUID = D6A2CB7F-6A18-4e2f-B43B-9920A733700A
+ MODULE_TYPE = DXE_CORE
+ VERSION_STRING = 1.0
+
+
+ ENTRY_POINT = DxeMain
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 EBC (EBC is for build only)
+#
+
+[Sources]
+ DxeMain.h
+ SectionExtraction/CoreSectionExtraction.c
+ Image/Image.c
+ Image/Image.h
+ Misc/DebugImageInfo.c
+ Misc/Stall.c
+ Misc/SetWatchdogTimer.c
+ Misc/InstallConfigurationTable.c
+ Misc/MemoryAttributesTable.c
+ Misc/MemoryProtection.c
+ Library/Library.c
+ Hand/DriverSupport.c
+ Hand/Notify.c
+ Hand/Locate.c
+ Hand/Handle.c
+ Hand/Handle.h
+ Gcd/Gcd.c
+ Gcd/Gcd.h
+ Mem/Pool.c
+ Mem/Page.c
+ Mem/MemData.c
+ Mem/Imem.h
+ Mem/MemoryProfileRecord.c
+ Mem/HeapGuard.c
+ Mem/HeapGuard.h
+ FwVolBlock/FwVolBlock.c
+ FwVolBlock/FwVolBlock.h
+ FwVol/FwVolWrite.c
+ FwVol/FwVolRead.c
+ FwVol/FwVolAttrib.c
+ FwVol/Ffs.c
+ FwVol/FwVol.c
+ FwVol/FwVolDriver.h
+ Event/Tpl.c
+ Event/Timer.c
+ Event/Event.c
+ Event/Event.h
+ Dispatcher/Dependency.c
+ Dispatcher/Dispatcher.c
+ DxeMain/DxeProtocolNotify.c
+ DxeMain/DxeMain.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+ BaseMemoryLib
+ CacheMaintenanceLib
+ UefiDecompressLib
+ PerformanceLib
+ HobLib
+ BaseLib
+ UefiLib
+ DebugLib
+ DxeCoreEntryPoint
+ PeCoffLib
+ PeCoffGetEntryPointLib
+ PeCoffExtraActionLib
+ ExtractGuidedSectionLib
+ MemoryAllocationLib
+ UefiBootServicesTableLib
+ DevicePathLib
+ ReportStatusCodeLib
+ DxeServicesLib
+ DebugAgentLib
+ CpuExceptionHandlerLib
+ PcdLib
+ ImagePropertiesRecordLib
+
+[Guids]
+ gEfiEventMemoryMapChangeGuid ## PRODUCES ## Event
+ gEfiEventVirtualAddressChangeGuid ## CONSUMES ## Event
+ ## CONSUMES ## Event
+ ## PRODUCES ## Event
+ gEfiEventBeforeExitBootServicesGuid
+ gEfiEventExitBootServicesGuid
+ gEfiHobMemoryAllocModuleGuid ## SOMETIMES_CONSUMES ## HOB
+ gEfiFirmwareFileSystem2Guid ## CONSUMES ## GUID # Used to compare with FV's file system guid and get the FV's file system format
+ gEfiFirmwareFileSystem3Guid ## CONSUMES ## GUID # Used to compare with FV's file system guid and get the FV's file system format
+ gAprioriGuid ## SOMETIMES_CONSUMES ## File
+ gEfiDebugImageInfoTableGuid ## PRODUCES ## SystemTable
+ gEfiHobListGuid ## PRODUCES ## SystemTable
+ gEfiDxeServicesTableGuid ## PRODUCES ## SystemTable
+ ## PRODUCES ## SystemTable
+ ## SOMETIMES_CONSUMES ## HOB
+ gEfiMemoryTypeInformationGuid
+ gEfiEventDxeDispatchGuid ## PRODUCES ## Event
+ gLoadFixedAddressConfigurationTableGuid ## SOMETIMES_PRODUCES ## SystemTable
+ ## PRODUCES ## Event
+ ## CONSUMES ## Event
+ gIdleLoopEventGuid
+ gEventExitBootServicesFailedGuid ## SOMETIMES_PRODUCES ## Event
+ gEfiVectorHandoffTableGuid ## SOMETIMES_PRODUCES ## SystemTable
+ gEdkiiMemoryProfileGuid ## SOMETIMES_PRODUCES ## GUID # Install protocol
+ gEfiMemoryAttributesTableGuid ## SOMETIMES_PRODUCES ## SystemTable
+ gEfiEndOfDxeEventGroupGuid ## SOMETIMES_CONSUMES ## Event
+ gEfiHobMemoryAllocStackGuid ## SOMETIMES_CONSUMES ## SystemTable
+
+[Ppis]
+ gEfiVectorHandoffInfoPpiGuid ## UNDEFINED # HOB
+
+[Protocols]
+ ## PRODUCES
+ ## SOMETIMES_CONSUMES
+ gEfiDecompressProtocolGuid
+ gEfiSimpleFileSystemProtocolGuid ## SOMETIMES_CONSUMES
+ gEfiLoadFileProtocolGuid ## SOMETIMES_CONSUMES
+ gEfiLoadFile2ProtocolGuid ## SOMETIMES_CONSUMES
+ gEfiBusSpecificDriverOverrideProtocolGuid ## SOMETIMES_CONSUMES
+ gEfiDriverFamilyOverrideProtocolGuid ## SOMETIMES_CONSUMES
+ gEfiPlatformDriverOverrideProtocolGuid ## SOMETIMES_CONSUMES
+ gEfiDriverBindingProtocolGuid ## SOMETIMES_CONSUMES
+ ## PRODUCES
+ ## CONSUMES
+ ## NOTIFY
+ gEfiFirmwareVolumeBlockProtocolGuid
+ ## PRODUCES
+ ## CONSUMES
+ ## NOTIFY
+ gEfiFirmwareVolume2ProtocolGuid
+ ## PRODUCES
+ ## CONSUMES
+ gEfiDevicePathProtocolGuid
+ gEfiLoadedImageProtocolGuid ## PRODUCES
+ gEfiLoadedImageDevicePathProtocolGuid ## PRODUCES
+ gEfiHiiPackageListProtocolGuid ## SOMETIMES_PRODUCES
+ gEfiSmmBase2ProtocolGuid ## SOMETIMES_CONSUMES
+ gEdkiiPeCoffImageEmulatorProtocolGuid ## SOMETIMES_CONSUMES
+
+ # Arch Protocols
+ gEfiBdsArchProtocolGuid ## CONSUMES
+ gEfiCpuArchProtocolGuid ## CONSUMES
+ gEfiMetronomeArchProtocolGuid ## CONSUMES
+ gEfiMonotonicCounterArchProtocolGuid ## CONSUMES
+ gEfiRealTimeClockArchProtocolGuid ## CONSUMES
+ gEfiResetArchProtocolGuid ## CONSUMES
+ gEfiRuntimeArchProtocolGuid ## CONSUMES
+ gEfiSecurityArchProtocolGuid ## CONSUMES
+ gEfiSecurity2ArchProtocolGuid ## SOMETIMES_CONSUMES
+ gEfiTimerArchProtocolGuid ## CONSUMES
+ gEfiVariableWriteArchProtocolGuid ## CONSUMES
+ gEfiVariableArchProtocolGuid ## CONSUMES
+ gEfiCapsuleArchProtocolGuid ## CONSUMES
+ gEfiWatchdogTimerArchProtocolGuid ## CONSUMES
+
+[Pcd]
+ gEfiMdeModulePkgTokenSpaceGuid.PcdLoadFixAddressBootTimeCodePageNumber ## SOMETIMES_CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdLoadFixAddressRuntimeCodePageNumber ## SOMETIMES_CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdLoadModuleAtFixAddressEnable ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdMaxEfiSystemTablePointerAddress ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdMemoryProfileMemoryType ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdMemoryProfilePropertyMask ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdMemoryProfileDriverPath ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdImageProtectionPolicy ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdDxeNxMemoryProtectionPolicy ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdNullPointerDetectionPropertyMask ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdHeapGuardPageType ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdHeapGuardPoolType ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdHeapGuardPropertyMask ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdCpuStackGuard ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdFwVolDxeMaxEncapsulationDepth ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdImageLargeAddressLoad ## CONSUMES
+
+# [Hob]
+# RESOURCE_DESCRIPTOR ## CONSUMES
+# MEMORY_ALLOCATION ## CONSUMES
+# FIRMWARE_VOLUME ## CONSUMES
+# UNDEFINED ## CONSUMES # CPU
+#
+# [Event]
+# EVENT_TYPE_RELATIVE_TIMER ## PRODUCES # DxeCore signals timer event.
+# EVENT_TYPE_PERIODIC_TIMER ## PRODUCES # DxeCore signals timer event.
+#
+
+[UserExtensions.TianoCore."ExtraFiles"]
+ DxeCoreExtra.uni
diff --git a/MdeModulePkg/Core/Dxe/DxeMain/DxeMain.c b/MdeModulePkg/Core/Dxe/DxeMain/DxeMain.c
index 17d510a287..7528872203 100644
--- a/MdeModulePkg/Core/Dxe/DxeMain/DxeMain.c
+++ b/MdeModulePkg/Core/Dxe/DxeMain/DxeMain.c
@@ -1,971 +1,971 @@
-/** @file
- DXE Core Main Entry Point
-
-Copyright (c) 2006 - 2022, Intel Corporation. All rights reserved.<BR>
-SPDX-License-Identifier: BSD-2-Clause-Patent
-
-**/
-
-#include "DxeMain.h"
-
-//
-// DXE Core Global Variables for Protocols from PEI
-//
-EFI_HANDLE mDecompressHandle = NULL;
-
-//
-// DXE Core globals for Architecture Protocols
-//
-EFI_SECURITY_ARCH_PROTOCOL *gSecurity = NULL;
-EFI_SECURITY2_ARCH_PROTOCOL *gSecurity2 = NULL;
-EFI_CPU_ARCH_PROTOCOL *gCpu = NULL;
-EFI_METRONOME_ARCH_PROTOCOL *gMetronome = NULL;
-EFI_TIMER_ARCH_PROTOCOL *gTimer = NULL;
-EFI_BDS_ARCH_PROTOCOL *gBds = NULL;
-EFI_WATCHDOG_TIMER_ARCH_PROTOCOL *gWatchdogTimer = NULL;
-
-//
-// DXE Core globals for optional protocol dependencies
-//
-EFI_SMM_BASE2_PROTOCOL *gSmmBase2 = NULL;
-
-//
-// DXE Core Global used to update core loaded image protocol handle
-//
-EFI_GUID *gDxeCoreFileName;
-EFI_LOADED_IMAGE_PROTOCOL *gDxeCoreLoadedImage;
-
-//
-// DXE Core Module Variables
-//
-EFI_BOOT_SERVICES mBootServices = {
- {
- EFI_BOOT_SERVICES_SIGNATURE, // Signature
- EFI_BOOT_SERVICES_REVISION, // Revision
- sizeof (EFI_BOOT_SERVICES), // HeaderSize
- 0, // CRC32
- 0 // Reserved
- },
- (EFI_RAISE_TPL)CoreRaiseTpl, // RaiseTPL
- (EFI_RESTORE_TPL)CoreRestoreTpl, // RestoreTPL
- (EFI_ALLOCATE_PAGES)CoreAllocatePages, // AllocatePages
- (EFI_FREE_PAGES)CoreFreePages, // FreePages
- (EFI_GET_MEMORY_MAP)CoreGetMemoryMap, // GetMemoryMap
- (EFI_ALLOCATE_POOL)CoreAllocatePool, // AllocatePool
- (EFI_FREE_POOL)CoreFreePool, // FreePool
- (EFI_CREATE_EVENT)CoreCreateEvent, // CreateEvent
- (EFI_SET_TIMER)CoreSetTimer, // SetTimer
- (EFI_WAIT_FOR_EVENT)CoreWaitForEvent, // WaitForEvent
- (EFI_SIGNAL_EVENT)CoreSignalEvent, // SignalEvent
- (EFI_CLOSE_EVENT)CoreCloseEvent, // CloseEvent
- (EFI_CHECK_EVENT)CoreCheckEvent, // CheckEvent
- (EFI_INSTALL_PROTOCOL_INTERFACE)CoreInstallProtocolInterface, // InstallProtocolInterface
- (EFI_REINSTALL_PROTOCOL_INTERFACE)CoreReinstallProtocolInterface, // ReinstallProtocolInterface
- (EFI_UNINSTALL_PROTOCOL_INTERFACE)CoreUninstallProtocolInterface, // UninstallProtocolInterface
- (EFI_HANDLE_PROTOCOL)CoreHandleProtocol, // HandleProtocol
- (VOID *)NULL, // Reserved
- (EFI_REGISTER_PROTOCOL_NOTIFY)CoreRegisterProtocolNotify, // RegisterProtocolNotify
- (EFI_LOCATE_HANDLE)CoreLocateHandle, // LocateHandle
- (EFI_LOCATE_DEVICE_PATH)CoreLocateDevicePath, // LocateDevicePath
- (EFI_INSTALL_CONFIGURATION_TABLE)CoreInstallConfigurationTable, // InstallConfigurationTable
- (EFI_IMAGE_LOAD)CoreLoadImage, // LoadImage
- (EFI_IMAGE_START)CoreStartImage, // StartImage
- (EFI_EXIT)CoreExit, // Exit
- (EFI_IMAGE_UNLOAD)CoreUnloadImage, // UnloadImage
- (EFI_EXIT_BOOT_SERVICES)CoreExitBootServices, // ExitBootServices
- (EFI_GET_NEXT_MONOTONIC_COUNT)CoreEfiNotAvailableYetArg1, // GetNextMonotonicCount
- (EFI_STALL)CoreStall, // Stall
- (EFI_SET_WATCHDOG_TIMER)CoreSetWatchdogTimer, // SetWatchdogTimer
- (EFI_CONNECT_CONTROLLER)CoreConnectController, // ConnectController
- (EFI_DISCONNECT_CONTROLLER)CoreDisconnectController, // DisconnectController
- (EFI_OPEN_PROTOCOL)CoreOpenProtocol, // OpenProtocol
- (EFI_CLOSE_PROTOCOL)CoreCloseProtocol, // CloseProtocol
- (EFI_OPEN_PROTOCOL_INFORMATION)CoreOpenProtocolInformation, // OpenProtocolInformation
- (EFI_PROTOCOLS_PER_HANDLE)CoreProtocolsPerHandle, // ProtocolsPerHandle
- (EFI_LOCATE_HANDLE_BUFFER)CoreLocateHandleBuffer, // LocateHandleBuffer
- (EFI_LOCATE_PROTOCOL)CoreLocateProtocol, // LocateProtocol
- (EFI_INSTALL_MULTIPLE_PROTOCOL_INTERFACES)CoreInstallMultipleProtocolInterfaces, // InstallMultipleProtocolInterfaces
- (EFI_UNINSTALL_MULTIPLE_PROTOCOL_INTERFACES)CoreUninstallMultipleProtocolInterfaces, // UninstallMultipleProtocolInterfaces
- (EFI_CALCULATE_CRC32)CoreEfiNotAvailableYetArg3, // CalculateCrc32
- (EFI_COPY_MEM)CopyMem, // CopyMem
- (EFI_SET_MEM)SetMem, // SetMem
- (EFI_CREATE_EVENT_EX)CoreCreateEventEx // CreateEventEx
-};
-
-EFI_DXE_SERVICES mDxeServices = {
- {
- DXE_SERVICES_SIGNATURE, // Signature
- DXE_SERVICES_REVISION, // Revision
- sizeof (DXE_SERVICES), // HeaderSize
- 0, // CRC32
- 0 // Reserved
- },
- (EFI_ADD_MEMORY_SPACE)CoreAddMemorySpace, // AddMemorySpace
- (EFI_ALLOCATE_MEMORY_SPACE)CoreAllocateMemorySpace, // AllocateMemorySpace
- (EFI_FREE_MEMORY_SPACE)CoreFreeMemorySpace, // FreeMemorySpace
- (EFI_REMOVE_MEMORY_SPACE)CoreRemoveMemorySpace, // RemoveMemorySpace
- (EFI_GET_MEMORY_SPACE_DESCRIPTOR)CoreGetMemorySpaceDescriptor, // GetMemorySpaceDescriptor
- (EFI_SET_MEMORY_SPACE_ATTRIBUTES)CoreSetMemorySpaceAttributes, // SetMemorySpaceAttributes
- (EFI_GET_MEMORY_SPACE_MAP)CoreGetMemorySpaceMap, // GetMemorySpaceMap
- (EFI_ADD_IO_SPACE)CoreAddIoSpace, // AddIoSpace
- (EFI_ALLOCATE_IO_SPACE)CoreAllocateIoSpace, // AllocateIoSpace
- (EFI_FREE_IO_SPACE)CoreFreeIoSpace, // FreeIoSpace
- (EFI_REMOVE_IO_SPACE)CoreRemoveIoSpace, // RemoveIoSpace
- (EFI_GET_IO_SPACE_DESCRIPTOR)CoreGetIoSpaceDescriptor, // GetIoSpaceDescriptor
- (EFI_GET_IO_SPACE_MAP)CoreGetIoSpaceMap, // GetIoSpaceMap
- (EFI_DISPATCH)CoreDispatcher, // Dispatch
- (EFI_SCHEDULE)CoreSchedule, // Schedule
- (EFI_TRUST)CoreTrust, // Trust
- (EFI_PROCESS_FIRMWARE_VOLUME)CoreProcessFirmwareVolume, // ProcessFirmwareVolume
- (EFI_SET_MEMORY_SPACE_CAPABILITIES)CoreSetMemorySpaceCapabilities, // SetMemorySpaceCapabilities
-};
-
-EFI_SYSTEM_TABLE mEfiSystemTableTemplate = {
- {
- EFI_SYSTEM_TABLE_SIGNATURE, // Signature
- EFI_SYSTEM_TABLE_REVISION, // Revision
- sizeof (EFI_SYSTEM_TABLE), // HeaderSize
- 0, // CRC32
- 0 // Reserved
- },
- NULL, // FirmwareVendor
- 0, // FirmwareRevision
- NULL, // ConsoleInHandle
- NULL, // ConIn
- NULL, // ConsoleOutHandle
- NULL, // ConOut
- NULL, // StandardErrorHandle
- NULL, // StdErr
- NULL, // RuntimeServices
- &mBootServices, // BootServices
- 0, // NumberOfConfigurationTableEntries
- NULL // ConfigurationTable
-};
-
-EFI_RUNTIME_SERVICES mEfiRuntimeServicesTableTemplate = {
- {
- EFI_RUNTIME_SERVICES_SIGNATURE, // Signature
- EFI_RUNTIME_SERVICES_REVISION, // Revision
- sizeof (EFI_RUNTIME_SERVICES), // HeaderSize
- 0, // CRC32
- 0 // Reserved
- },
- (EFI_GET_TIME)CoreEfiNotAvailableYetArg2, // GetTime
- (EFI_SET_TIME)CoreEfiNotAvailableYetArg1, // SetTime
- (EFI_GET_WAKEUP_TIME)CoreEfiNotAvailableYetArg3, // GetWakeupTime
- (EFI_SET_WAKEUP_TIME)CoreEfiNotAvailableYetArg2, // SetWakeupTime
- (EFI_SET_VIRTUAL_ADDRESS_MAP)CoreEfiNotAvailableYetArg4, // SetVirtualAddressMap
- (EFI_CONVERT_POINTER)CoreEfiNotAvailableYetArg2, // ConvertPointer
- (EFI_GET_VARIABLE)CoreEfiNotAvailableYetArg5, // GetVariable
- (EFI_GET_NEXT_VARIABLE_NAME)CoreEfiNotAvailableYetArg3, // GetNextVariableName
- (EFI_SET_VARIABLE)CoreEfiNotAvailableYetArg5, // SetVariable
- (EFI_GET_NEXT_HIGH_MONO_COUNT)CoreEfiNotAvailableYetArg1, // GetNextHighMonotonicCount
- (EFI_RESET_SYSTEM)CoreEfiNotAvailableYetArg4, // ResetSystem
- (EFI_UPDATE_CAPSULE)CoreEfiNotAvailableYetArg3, // UpdateCapsule
- (EFI_QUERY_CAPSULE_CAPABILITIES)CoreEfiNotAvailableYetArg4, // QueryCapsuleCapabilities
- (EFI_QUERY_VARIABLE_INFO)CoreEfiNotAvailableYetArg4 // QueryVariableInfo
-};
-
-EFI_RUNTIME_ARCH_PROTOCOL gRuntimeTemplate = {
- INITIALIZE_LIST_HEAD_VARIABLE (gRuntimeTemplate.ImageHead),
- INITIALIZE_LIST_HEAD_VARIABLE (gRuntimeTemplate.EventHead),
-
- //
- // Make sure Size != sizeof (EFI_MEMORY_DESCRIPTOR). This will
- // prevent people from having pointer math bugs in their code.
- // now you have to use *DescriptorSize to make things work.
- //
- sizeof (EFI_MEMORY_DESCRIPTOR) + sizeof (UINT64) - (sizeof (EFI_MEMORY_DESCRIPTOR) % sizeof (UINT64)),
- EFI_MEMORY_DESCRIPTOR_VERSION,
- 0,
- NULL,
- NULL,
- FALSE,
- FALSE
-};
-
-EFI_RUNTIME_ARCH_PROTOCOL *gRuntime = &gRuntimeTemplate;
-
-//
-// DXE Core Global Variables for the EFI System Table, Boot Services Table,
-// DXE Services Table, and Runtime Services Table
-//
-EFI_DXE_SERVICES *gDxeCoreDS = &mDxeServices;
-EFI_SYSTEM_TABLE *gDxeCoreST = NULL;
-
-//
-// For debug initialize gDxeCoreRT to template. gDxeCoreRT must be allocated from RT memory
-// but gDxeCoreRT is used for ASSERT () and DEBUG () type macros so lets give it
-// a value that will not cause debug infrastructure to crash early on.
-//
-EFI_RUNTIME_SERVICES *gDxeCoreRT = &mEfiRuntimeServicesTableTemplate;
-EFI_HANDLE gDxeCoreImageHandle = NULL;
-
-BOOLEAN gMemoryMapTerminated = FALSE;
-
-//
-// EFI Decompress Protocol
-//
-EFI_DECOMPRESS_PROTOCOL gEfiDecompress = {
- DxeMainUefiDecompressGetInfo,
- DxeMainUefiDecompress
-};
-
-//
-// For Loading modules at fixed address feature, the configuration table is to cache the top address below which to load
-// Runtime code&boot time code
-//
-GLOBAL_REMOVE_IF_UNREFERENCED EFI_LOAD_FIXED_ADDRESS_CONFIGURATION_TABLE gLoadModuleAtFixAddressConfigurationTable = { 0, 0 };
-
-// Main entry point to the DXE Core
-//
-
-/**
- Main entry point to DXE Core.
-
- @param HobStart Pointer to the beginning of the HOB List from PEI.
-
- @return This function should never return.
-
-**/
-VOID
-EFIAPI
-DxeMain (
- IN VOID *HobStart
- )
-{
- EFI_STATUS Status;
- EFI_PHYSICAL_ADDRESS MemoryBaseAddress;
- UINT64 MemoryLength;
- PE_COFF_LOADER_IMAGE_CONTEXT ImageContext;
- UINTN Index;
- EFI_HOB_GUID_TYPE *GuidHob;
- EFI_VECTOR_HANDOFF_INFO *VectorInfoList;
- EFI_VECTOR_HANDOFF_INFO *VectorInfo;
- VOID *EntryPoint;
-
- //
- // Setup the default exception handlers
- //
- VectorInfoList = NULL;
- GuidHob = GetNextGuidHob (&gEfiVectorHandoffInfoPpiGuid, HobStart);
- if (GuidHob != NULL) {
- VectorInfoList = (EFI_VECTOR_HANDOFF_INFO *)(GET_GUID_HOB_DATA (GuidHob));
- }
-
- Status = InitializeCpuExceptionHandlers (VectorInfoList);
- ASSERT_EFI_ERROR (Status);
-
- //
- // Setup Stack Guard
- //
- if (PcdGetBool (PcdCpuStackGuard)) {
- Status = InitializeSeparateExceptionStacks (NULL, NULL);
- ASSERT_EFI_ERROR (Status);
- }
-
- //
- // Initialize Debug Agent to support source level debug in DXE phase
- //
- InitializeDebugAgent (DEBUG_AGENT_INIT_DXE_CORE, HobStart, NULL);
-
- //
- // Initialize Memory Services
- //
- CoreInitializeMemoryServices (&HobStart, &MemoryBaseAddress, &MemoryLength);
-
- MemoryProfileInit (HobStart);
-
- //
- // Start the Image Services.
- //
- Status = CoreInitializeImageServices (HobStart);
- ASSERT_EFI_ERROR (Status);
-
- //
- // Initialize the Global Coherency Domain Services
- //
- Status = CoreInitializeGcdServices (&HobStart, MemoryBaseAddress, MemoryLength);
- ASSERT_EFI_ERROR (Status);
-
- //
- // Allocate the EFI System Table and EFI Runtime Service Table from EfiRuntimeServicesData
- // Use the templates to initialize the contents of the EFI System Table and EFI Runtime Services Table
- //
- gDxeCoreST = AllocateRuntimeCopyPool (sizeof (EFI_SYSTEM_TABLE), &mEfiSystemTableTemplate);
- ASSERT (gDxeCoreST != NULL);
-
- gDxeCoreRT = AllocateRuntimeCopyPool (sizeof (EFI_RUNTIME_SERVICES), &mEfiRuntimeServicesTableTemplate);
- ASSERT (gDxeCoreRT != NULL);
-
- gDxeCoreST->RuntimeServices = gDxeCoreRT;
-
- //
- // Update DXE Core Loaded Image Protocol with allocated UEFI System Table
- //
- gDxeCoreLoadedImage->SystemTable = gDxeCoreST;
-
- //
- // Call constructor for all libraries
- //
- ProcessLibraryConstructorList (gDxeCoreImageHandle, gDxeCoreST);
- PERF_CROSSMODULE_END ("PEI");
- PERF_CROSSMODULE_BEGIN ("DXE");
-
- //
- // Log MemoryBaseAddress and MemoryLength again (from
- // CoreInitializeMemoryServices()), now that library constructors have
- // executed.
- //
- DEBUG ((
- DEBUG_INFO,
- "%a: MemoryBaseAddress=0x%Lx MemoryLength=0x%Lx\n",
- __func__,
- MemoryBaseAddress,
- MemoryLength
- ));
-
- //
- // Report DXE Core image information to the PE/COFF Extra Action Library
- //
- ZeroMem (&ImageContext, sizeof (ImageContext));
- ImageContext.ImageAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)gDxeCoreLoadedImage->ImageBase;
- ImageContext.PdbPointer = PeCoffLoaderGetPdbPointer ((VOID *)(UINTN)ImageContext.ImageAddress);
- ImageContext.SizeOfHeaders = PeCoffGetSizeOfHeaders ((VOID *)(UINTN)ImageContext.ImageAddress);
- Status = PeCoffLoaderGetEntryPoint ((VOID *)(UINTN)ImageContext.ImageAddress, &EntryPoint);
- if (Status == EFI_SUCCESS) {
- ImageContext.EntryPoint = (EFI_PHYSICAL_ADDRESS)(UINTN)EntryPoint;
- }
-
- ImageContext.Handle = (VOID *)(UINTN)gDxeCoreLoadedImage->ImageBase;
- ImageContext.ImageRead = PeCoffLoaderImageReadFromMemory;
- PeCoffLoaderRelocateImageExtraAction (&ImageContext);
-
- //
- // Install the DXE Services Table into the EFI System Tables's Configuration Table
- //
- Status = CoreInstallConfigurationTable (&gEfiDxeServicesTableGuid, gDxeCoreDS);
- ASSERT_EFI_ERROR (Status);
-
- //
- // Install the HOB List into the EFI System Tables's Configuration Table
- //
- Status = CoreInstallConfigurationTable (&gEfiHobListGuid, HobStart);
- ASSERT_EFI_ERROR (Status);
-
- //
- // Install Memory Type Information Table into the EFI System Tables's Configuration Table
- //
- Status = CoreInstallConfigurationTable (&gEfiMemoryTypeInformationGuid, &gMemoryTypeInformation);
- ASSERT_EFI_ERROR (Status);
-
- //
- // If Loading modules At fixed address feature is enabled, install Load moduels at fixed address
- // Configuration Table so that user could easily to retrieve the top address to load Dxe and PEI
- // Code and Tseg base to load SMM driver.
- //
- if (PcdGet64 (PcdLoadModuleAtFixAddressEnable) != 0) {
- Status = CoreInstallConfigurationTable (&gLoadFixedAddressConfigurationTableGuid, &gLoadModuleAtFixAddressConfigurationTable);
- ASSERT_EFI_ERROR (Status);
- }
-
- //
- // Report Status Code here for DXE_ENTRY_POINT once it is available
- //
- REPORT_STATUS_CODE (
- EFI_PROGRESS_CODE,
- (EFI_SOFTWARE_DXE_CORE | EFI_SW_DXE_CORE_PC_ENTRY_POINT)
- );
-
- //
- // Create the aligned system table pointer structure that is used by external
- // debuggers to locate the system table... Also, install debug image info
- // configuration table.
- //
- CoreInitializeDebugImageInfoTable ();
- CoreNewDebugImageInfoEntry (
- EFI_DEBUG_IMAGE_INFO_TYPE_NORMAL,
- gDxeCoreLoadedImage,
- gDxeCoreImageHandle
- );
-
- DEBUG ((DEBUG_INFO | DEBUG_LOAD, "HOBLIST address in DXE = 0x%p\n", HobStart));
-
- DEBUG_CODE_BEGIN ();
- EFI_PEI_HOB_POINTERS Hob;
-
- for (Hob.Raw = HobStart; !END_OF_HOB_LIST (Hob); Hob.Raw = GET_NEXT_HOB (Hob)) {
- if (GET_HOB_TYPE (Hob) == EFI_HOB_TYPE_MEMORY_ALLOCATION) {
- DEBUG ((
- DEBUG_INFO | DEBUG_LOAD,
- "Memory Allocation 0x%08x 0x%0lx - 0x%0lx\n", \
- Hob.MemoryAllocation->AllocDescriptor.MemoryType, \
- Hob.MemoryAllocation->AllocDescriptor.MemoryBaseAddress, \
- Hob.MemoryAllocation->AllocDescriptor.MemoryBaseAddress + Hob.MemoryAllocation->AllocDescriptor.MemoryLength - 1
- ));
- }
- }
-
- for (Hob.Raw = HobStart; !END_OF_HOB_LIST (Hob); Hob.Raw = GET_NEXT_HOB (Hob)) {
- if (GET_HOB_TYPE (Hob) == EFI_HOB_TYPE_FV) {
- DEBUG ((
- DEBUG_INFO | DEBUG_LOAD,
- "FV Hob 0x%0lx - 0x%0lx\n",
- Hob.FirmwareVolume->BaseAddress,
- Hob.FirmwareVolume->BaseAddress + Hob.FirmwareVolume->Length - 1
- ));
- } else if (GET_HOB_TYPE (Hob) == EFI_HOB_TYPE_FV2) {
- DEBUG ((
- DEBUG_INFO | DEBUG_LOAD,
- "FV2 Hob 0x%0lx - 0x%0lx\n",
- Hob.FirmwareVolume2->BaseAddress,
- Hob.FirmwareVolume2->BaseAddress + Hob.FirmwareVolume2->Length - 1
- ));
- DEBUG ((
- DEBUG_INFO | DEBUG_LOAD,
- " %g - %g\n",
- &Hob.FirmwareVolume2->FvName,
- &Hob.FirmwareVolume2->FileName
- ));
- } else if (GET_HOB_TYPE (Hob) == EFI_HOB_TYPE_FV3) {
- DEBUG ((
- DEBUG_INFO | DEBUG_LOAD,
- "FV3 Hob 0x%0lx - 0x%0lx - 0x%x - 0x%x\n",
- Hob.FirmwareVolume3->BaseAddress,
- Hob.FirmwareVolume3->BaseAddress + Hob.FirmwareVolume3->Length - 1,
- Hob.FirmwareVolume3->AuthenticationStatus,
- Hob.FirmwareVolume3->ExtractedFv
- ));
- if (Hob.FirmwareVolume3->ExtractedFv) {
- DEBUG ((
- DEBUG_INFO | DEBUG_LOAD,
- " %g - %g\n",
- &Hob.FirmwareVolume3->FvName,
- &Hob.FirmwareVolume3->FileName
- ));
- }
- }
- }
-
- DEBUG_CODE_END ();
-
- //
- // Initialize the Event Services
- //
- Status = CoreInitializeEventServices ();
- ASSERT_EFI_ERROR (Status);
-
- MemoryProfileInstallProtocol ();
-
- CoreInitializeMemoryAttributesTable ();
- CoreInitializeMemoryProtection ();
-
- //
- // Get persisted vector hand-off info from GUIDeed HOB again due to HobStart may be updated,
- // and install configuration table
- //
- GuidHob = GetNextGuidHob (&gEfiVectorHandoffInfoPpiGuid, HobStart);
- if (GuidHob != NULL) {
- VectorInfoList = (EFI_VECTOR_HANDOFF_INFO *)(GET_GUID_HOB_DATA (GuidHob));
- VectorInfo = VectorInfoList;
- Index = 1;
- while (VectorInfo->Attribute != EFI_VECTOR_HANDOFF_LAST_ENTRY) {
- VectorInfo++;
- Index++;
- }
-
- VectorInfo = AllocateCopyPool (sizeof (EFI_VECTOR_HANDOFF_INFO) * Index, (VOID *)VectorInfoList);
- ASSERT (VectorInfo != NULL);
- Status = CoreInstallConfigurationTable (&gEfiVectorHandoffTableGuid, (VOID *)VectorInfo);
- ASSERT_EFI_ERROR (Status);
- }
-
- //
- // Get the Protocols that were passed in from PEI to DXE through GUIDed HOBs
- //
- // These Protocols are not architectural. This implementation is sharing code between
- // PEI and DXE in order to save FLASH space. These Protocols could also be implemented
- // as part of the DXE Core. However, that would also require the DXE Core to be ported
- // each time a different CPU is used, a different Decompression algorithm is used, or a
- // different Image type is used. By placing these Protocols in PEI, the DXE Core remains
- // generic, and only PEI and the Arch Protocols need to be ported from Platform to Platform,
- // and from CPU to CPU.
- //
-
- //
- // Publish the EFI, Tiano, and Custom Decompress protocols for use by other DXE components
- //
- Status = CoreInstallMultipleProtocolInterfaces (
- &mDecompressHandle,
- &gEfiDecompressProtocolGuid,
- &gEfiDecompress,
- NULL
- );
- ASSERT_EFI_ERROR (Status);
-
- //
- // Register for the GUIDs of the Architectural Protocols, so the rest of the
- // EFI Boot Services and EFI Runtime Services tables can be filled in.
- // Also register for the GUIDs of optional protocols.
- //
- CoreNotifyOnProtocolInstallation ();
-
- //
- // Produce Firmware Volume Protocols, one for each FV in the HOB list.
- //
- Status = FwVolBlockDriverInit (gDxeCoreImageHandle, gDxeCoreST);
- ASSERT_EFI_ERROR (Status);
-
- Status = FwVolDriverInit (gDxeCoreImageHandle, gDxeCoreST);
- ASSERT_EFI_ERROR (Status);
-
- //
- // Produce the Section Extraction Protocol
- //
- Status = InitializeSectionExtraction (gDxeCoreImageHandle, gDxeCoreST);
- ASSERT_EFI_ERROR (Status);
-
- //
- // Initialize the DXE Dispatcher
- //
- CoreInitializeDispatcher ();
-
- //
- // Invoke the DXE Dispatcher
- //
- CoreDispatcher ();
-
- //
- // Display Architectural protocols that were not loaded if this is DEBUG build
- //
- DEBUG_CODE_BEGIN ();
- CoreDisplayMissingArchProtocols ();
- DEBUG_CODE_END ();
-
- //
- // Display any drivers that were not dispatched because dependency expression
- // evaluated to false if this is a debug build
- //
- DEBUG_CODE_BEGIN ();
- CoreDisplayDiscoveredNotDispatched ();
- DEBUG_CODE_END ();
-
- //
- // Assert if the Architectural Protocols are not present.
- //
- Status = CoreAllEfiServicesAvailable ();
- if (EFI_ERROR (Status)) {
- //
- // Report Status code that some Architectural Protocols are not present.
- //
- REPORT_STATUS_CODE (
- EFI_ERROR_CODE | EFI_ERROR_MAJOR,
- (EFI_SOFTWARE_DXE_CORE | EFI_SW_DXE_CORE_EC_NO_ARCH)
- );
- }
-
- ASSERT_EFI_ERROR (Status);
-
- //
- // Report Status code before transfer control to BDS
- //
- REPORT_STATUS_CODE (
- EFI_PROGRESS_CODE,
- (EFI_SOFTWARE_DXE_CORE | EFI_SW_DXE_CORE_PC_HANDOFF_TO_NEXT)
- );
-
- //
- // Transfer control to the BDS Architectural Protocol
- //
- gBds->Entry (gBds);
-
- //
- // BDS should never return
- //
- ASSERT (FALSE);
- CpuDeadLoop ();
-
- UNREACHABLE ();
-}
-
-/**
- Place holder function until all the Boot Services and Runtime Services are
- available.
-
- @param Arg1 Undefined
-
- @return EFI_NOT_AVAILABLE_YET
-
-**/
-EFI_STATUS
-EFIAPI
-CoreEfiNotAvailableYetArg1 (
- UINTN Arg1
- )
-{
- //
- // This function should never be executed. If it does, then the architectural protocols
- // have not been designed correctly. The CpuBreakpoint () is commented out for now until the
- // DXE Core and all the Architectural Protocols are complete.
- //
-
- return EFI_NOT_AVAILABLE_YET;
-}
-
-/**
- Place holder function until all the Boot Services and Runtime Services are available.
-
- @param Arg1 Undefined
- @param Arg2 Undefined
-
- @return EFI_NOT_AVAILABLE_YET
-
-**/
-EFI_STATUS
-EFIAPI
-CoreEfiNotAvailableYetArg2 (
- UINTN Arg1,
- UINTN Arg2
- )
-{
- //
- // This function should never be executed. If it does, then the architectural protocols
- // have not been designed correctly. The CpuBreakpoint () is commented out for now until the
- // DXE Core and all the Architectural Protocols are complete.
- //
-
- return EFI_NOT_AVAILABLE_YET;
-}
-
-/**
- Place holder function until all the Boot Services and Runtime Services are available.
-
- @param Arg1 Undefined
- @param Arg2 Undefined
- @param Arg3 Undefined
-
- @return EFI_NOT_AVAILABLE_YET
-
-**/
-EFI_STATUS
-EFIAPI
-CoreEfiNotAvailableYetArg3 (
- UINTN Arg1,
- UINTN Arg2,
- UINTN Arg3
- )
-{
- //
- // This function should never be executed. If it does, then the architectural protocols
- // have not been designed correctly. The CpuBreakpoint () is commented out for now until the
- // DXE Core and all the Architectural Protocols are complete.
- //
-
- return EFI_NOT_AVAILABLE_YET;
-}
-
-/**
- Place holder function until all the Boot Services and Runtime Services are available.
-
- @param Arg1 Undefined
- @param Arg2 Undefined
- @param Arg3 Undefined
- @param Arg4 Undefined
-
- @return EFI_NOT_AVAILABLE_YET
-
-**/
-EFI_STATUS
-EFIAPI
-CoreEfiNotAvailableYetArg4 (
- UINTN Arg1,
- UINTN Arg2,
- UINTN Arg3,
- UINTN Arg4
- )
-{
- //
- // This function should never be executed. If it does, then the architectural protocols
- // have not been designed correctly. The CpuBreakpoint () is commented out for now until the
- // DXE Core and all the Architectural Protocols are complete.
- //
-
- return EFI_NOT_AVAILABLE_YET;
-}
-
-/**
- Place holder function until all the Boot Services and Runtime Services are available.
-
- @param Arg1 Undefined
- @param Arg2 Undefined
- @param Arg3 Undefined
- @param Arg4 Undefined
- @param Arg5 Undefined
-
- @return EFI_NOT_AVAILABLE_YET
-
-**/
-EFI_STATUS
-EFIAPI
-CoreEfiNotAvailableYetArg5 (
- UINTN Arg1,
- UINTN Arg2,
- UINTN Arg3,
- UINTN Arg4,
- UINTN Arg5
- )
-{
- //
- // This function should never be executed. If it does, then the architectural protocols
- // have not been designed correctly. The CpuBreakpoint () is commented out for now until the
- // DXE Core and all the Architectural Protocols are complete.
- //
-
- return EFI_NOT_AVAILABLE_YET;
-}
-
-/**
- Calcualte the 32-bit CRC in a EFI table using the service provided by the
- gRuntime service.
-
- @param Hdr Pointer to an EFI standard header
-
-**/
-VOID
-CalculateEfiHdrCrc (
- IN OUT EFI_TABLE_HEADER *Hdr
- )
-{
- UINT32 Crc;
-
- Hdr->CRC32 = 0;
-
- //
- // If gBS->CalculateCrce32 () == CoreEfiNotAvailableYet () then
- // Crc will come back as zero if we set it to zero here
- //
- Crc = 0;
- gBS->CalculateCrc32 ((UINT8 *)Hdr, Hdr->HeaderSize, &Crc);
- Hdr->CRC32 = Crc;
-}
-
-/**
- Terminates all boot services.
-
- @param ImageHandle Handle that identifies the exiting image.
- @param MapKey Key to the latest memory map.
-
- @retval EFI_SUCCESS Boot Services terminated
- @retval EFI_INVALID_PARAMETER MapKey is incorrect.
-
-**/
-EFI_STATUS
-EFIAPI
-CoreExitBootServices (
- IN EFI_HANDLE ImageHandle,
- IN UINTN MapKey
- )
-{
- EFI_STATUS Status;
-
- //
- // Notify other drivers of their last chance to use boot services
- // before the memory map is terminated.
- //
- CoreNotifySignalList (&gEfiEventBeforeExitBootServicesGuid);
-
- //
- // Disable Timer
- //
- gTimer->SetTimerPeriod (gTimer, 0);
-
- //
- // Terminate memory services if the MapKey matches
- //
- Status = CoreTerminateMemoryMap (MapKey);
- if (EFI_ERROR (Status)) {
- //
- // Notify other drivers that ExitBootServices fail
- //
- CoreNotifySignalList (&gEventExitBootServicesFailedGuid);
- return Status;
- }
-
- gMemoryMapTerminated = TRUE;
-
- //
- // Notify other drivers that we are exiting boot services.
- //
- CoreNotifySignalList (&gEfiEventExitBootServicesGuid);
-
- //
- // Report that ExitBootServices() has been called
- //
- REPORT_STATUS_CODE (
- EFI_PROGRESS_CODE,
- (EFI_SOFTWARE_EFI_BOOT_SERVICE | EFI_SW_BS_PC_EXIT_BOOT_SERVICES)
- );
-
- MemoryProtectionExitBootServicesCallback ();
-
- //
- // Disable interrupt of Debug timer.
- //
- SaveAndSetDebugTimerInterrupt (FALSE);
-
- //
- // Disable CPU Interrupts
- //
- gCpu->DisableInterrupt (gCpu);
-
- //
- // Clear the non-runtime values of the EFI System Table
- //
- gDxeCoreST->BootServices = NULL;
- gDxeCoreST->ConIn = NULL;
- gDxeCoreST->ConsoleInHandle = NULL;
- gDxeCoreST->ConOut = NULL;
- gDxeCoreST->ConsoleOutHandle = NULL;
- gDxeCoreST->StdErr = NULL;
- gDxeCoreST->StandardErrorHandle = NULL;
-
- //
- // Recompute the 32-bit CRC of the EFI System Table
- //
- CalculateEfiHdrCrc (&gDxeCoreST->Hdr);
-
- //
- // Zero out the Boot Service Table
- //
- ZeroMem (gBS, sizeof (EFI_BOOT_SERVICES));
- gBS = NULL;
-
- //
- // Update the AtRuntime field in Runtiem AP.
- //
- gRuntime->AtRuntime = TRUE;
-
- return Status;
-}
-
-/**
- Given a compressed source buffer, this function retrieves the size of the
- uncompressed buffer and the size of the scratch buffer required to decompress
- the compressed source buffer.
-
- The GetInfo() function retrieves the size of the uncompressed buffer and the
- temporary scratch buffer required to decompress the buffer specified by Source
- and SourceSize. If the size of the uncompressed buffer or the size of the
- scratch buffer cannot be determined from the compressed data specified by
- Source and SourceData, then EFI_INVALID_PARAMETER is returned. Otherwise, the
- size of the uncompressed buffer is returned in DestinationSize, the size of
- the scratch buffer is returned in ScratchSize, and EFI_SUCCESS is returned.
- The GetInfo() function does not have scratch buffer available to perform a
- thorough checking of the validity of the source data. It just retrieves the
- "Original Size" field from the beginning bytes of the source data and output
- it as DestinationSize. And ScratchSize is specific to the decompression
- implementation.
-
- @param This A pointer to the EFI_DECOMPRESS_PROTOCOL instance.
- @param Source The source buffer containing the compressed data.
- @param SourceSize The size, in bytes, of the source buffer.
- @param DestinationSize A pointer to the size, in bytes, of the
- uncompressed buffer that will be generated when the
- compressed buffer specified by Source and
- SourceSize is decompressed.
- @param ScratchSize A pointer to the size, in bytes, of the scratch
- buffer that is required to decompress the
- compressed buffer specified by Source and
- SourceSize.
-
- @retval EFI_SUCCESS The size of the uncompressed data was returned in
- DestinationSize and the size of the scratch buffer
- was returned in ScratchSize.
- @retval EFI_INVALID_PARAMETER The size of the uncompressed data or the size of
- the scratch buffer cannot be determined from the
- compressed data specified by Source and
- SourceSize.
-
-**/
-EFI_STATUS
-EFIAPI
-DxeMainUefiDecompressGetInfo (
- IN EFI_DECOMPRESS_PROTOCOL *This,
- IN VOID *Source,
- IN UINT32 SourceSize,
- OUT UINT32 *DestinationSize,
- OUT UINT32 *ScratchSize
- )
-{
- if ((Source == NULL) || (DestinationSize == NULL) || (ScratchSize == NULL)) {
- return EFI_INVALID_PARAMETER;
- }
-
- return UefiDecompressGetInfo (Source, SourceSize, DestinationSize, ScratchSize);
-}
-
-/**
- Decompresses a compressed source buffer.
-
- The Decompress() function extracts decompressed data to its original form.
- This protocol is designed so that the decompression algorithm can be
- implemented without using any memory services. As a result, the Decompress()
- Function is not allowed to call AllocatePool() or AllocatePages() in its
- implementation. It is the caller's responsibility to allocate and free the
- Destination and Scratch buffers.
- If the compressed source data specified by Source and SourceSize is
- successfully decompressed into Destination, then EFI_SUCCESS is returned. If
- the compressed source data specified by Source and SourceSize is not in a
- valid compressed data format, then EFI_INVALID_PARAMETER is returned.
-
- @param This A pointer to the EFI_DECOMPRESS_PROTOCOL instance.
- @param Source The source buffer containing the compressed data.
- @param SourceSize SourceSizeThe size of source data.
- @param Destination On output, the destination buffer that contains
- the uncompressed data.
- @param DestinationSize The size of the destination buffer. The size of
- the destination buffer needed is obtained from
- EFI_DECOMPRESS_PROTOCOL.GetInfo().
- @param Scratch A temporary scratch buffer that is used to perform
- the decompression.
- @param ScratchSize The size of scratch buffer. The size of the
- scratch buffer needed is obtained from GetInfo().
-
- @retval EFI_SUCCESS Decompression completed successfully, and the
- uncompressed buffer is returned in Destination.
- @retval EFI_INVALID_PARAMETER The source buffer specified by Source and
- SourceSize is corrupted (not in a valid
- compressed format).
-
-**/
-EFI_STATUS
-EFIAPI
-DxeMainUefiDecompress (
- IN EFI_DECOMPRESS_PROTOCOL *This,
- IN VOID *Source,
- IN UINT32 SourceSize,
- IN OUT VOID *Destination,
- IN UINT32 DestinationSize,
- IN OUT VOID *Scratch,
- IN UINT32 ScratchSize
- )
-{
- EFI_STATUS Status;
- UINT32 TestDestinationSize;
- UINT32 TestScratchSize;
-
- if ((Source == NULL) || (Destination == NULL) || (Scratch == NULL)) {
- return EFI_INVALID_PARAMETER;
- }
-
- Status = UefiDecompressGetInfo (Source, SourceSize, &TestDestinationSize, &TestScratchSize);
- if (EFI_ERROR (Status)) {
- return Status;
- }
-
- if ((ScratchSize < TestScratchSize) || (DestinationSize < TestDestinationSize)) {
- return RETURN_INVALID_PARAMETER;
- }
-
- return UefiDecompress (Source, Destination, Scratch);
-}
+/** @file
+ DXE Core Main Entry Point
+
+Copyright (c) 2006 - 2022, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "DxeMain.h"
+
+//
+// DXE Core Global Variables for Protocols from PEI
+//
+EFI_HANDLE mDecompressHandle = NULL;
+
+//
+// DXE Core globals for Architecture Protocols
+//
+EFI_SECURITY_ARCH_PROTOCOL *gSecurity = NULL;
+EFI_SECURITY2_ARCH_PROTOCOL *gSecurity2 = NULL;
+EFI_CPU_ARCH_PROTOCOL *gCpu = NULL;
+EFI_METRONOME_ARCH_PROTOCOL *gMetronome = NULL;
+EFI_TIMER_ARCH_PROTOCOL *gTimer = NULL;
+EFI_BDS_ARCH_PROTOCOL *gBds = NULL;
+EFI_WATCHDOG_TIMER_ARCH_PROTOCOL *gWatchdogTimer = NULL;
+
+//
+// DXE Core globals for optional protocol dependencies
+//
+EFI_SMM_BASE2_PROTOCOL *gSmmBase2 = NULL;
+
+//
+// DXE Core Global used to update core loaded image protocol handle
+//
+EFI_GUID *gDxeCoreFileName;
+EFI_LOADED_IMAGE_PROTOCOL *gDxeCoreLoadedImage;
+
+//
+// DXE Core Module Variables
+//
+EFI_BOOT_SERVICES mBootServices = {
+ {
+ EFI_BOOT_SERVICES_SIGNATURE, // Signature
+ EFI_BOOT_SERVICES_REVISION, // Revision
+ sizeof (EFI_BOOT_SERVICES), // HeaderSize
+ 0, // CRC32
+ 0 // Reserved
+ },
+ (EFI_RAISE_TPL)CoreRaiseTpl, // RaiseTPL
+ (EFI_RESTORE_TPL)CoreRestoreTpl, // RestoreTPL
+ (EFI_ALLOCATE_PAGES)CoreAllocatePages, // AllocatePages
+ (EFI_FREE_PAGES)CoreFreePages, // FreePages
+ (EFI_GET_MEMORY_MAP)CoreGetMemoryMap, // GetMemoryMap
+ (EFI_ALLOCATE_POOL)CoreAllocatePool, // AllocatePool
+ (EFI_FREE_POOL)CoreFreePool, // FreePool
+ (EFI_CREATE_EVENT)CoreCreateEvent, // CreateEvent
+ (EFI_SET_TIMER)CoreSetTimer, // SetTimer
+ (EFI_WAIT_FOR_EVENT)CoreWaitForEvent, // WaitForEvent
+ (EFI_SIGNAL_EVENT)CoreSignalEvent, // SignalEvent
+ (EFI_CLOSE_EVENT)CoreCloseEvent, // CloseEvent
+ (EFI_CHECK_EVENT)CoreCheckEvent, // CheckEvent
+ (EFI_INSTALL_PROTOCOL_INTERFACE)CoreInstallProtocolInterface, // InstallProtocolInterface
+ (EFI_REINSTALL_PROTOCOL_INTERFACE)CoreReinstallProtocolInterface, // ReinstallProtocolInterface
+ (EFI_UNINSTALL_PROTOCOL_INTERFACE)CoreUninstallProtocolInterface, // UninstallProtocolInterface
+ (EFI_HANDLE_PROTOCOL)CoreHandleProtocol, // HandleProtocol
+ (VOID *)NULL, // Reserved
+ (EFI_REGISTER_PROTOCOL_NOTIFY)CoreRegisterProtocolNotify, // RegisterProtocolNotify
+ (EFI_LOCATE_HANDLE)CoreLocateHandle, // LocateHandle
+ (EFI_LOCATE_DEVICE_PATH)CoreLocateDevicePath, // LocateDevicePath
+ (EFI_INSTALL_CONFIGURATION_TABLE)CoreInstallConfigurationTable, // InstallConfigurationTable
+ (EFI_IMAGE_LOAD)CoreLoadImage, // LoadImage
+ (EFI_IMAGE_START)CoreStartImage, // StartImage
+ (EFI_EXIT)CoreExit, // Exit
+ (EFI_IMAGE_UNLOAD)CoreUnloadImage, // UnloadImage
+ (EFI_EXIT_BOOT_SERVICES)CoreExitBootServices, // ExitBootServices
+ (EFI_GET_NEXT_MONOTONIC_COUNT)CoreEfiNotAvailableYetArg1, // GetNextMonotonicCount
+ (EFI_STALL)CoreStall, // Stall
+ (EFI_SET_WATCHDOG_TIMER)CoreSetWatchdogTimer, // SetWatchdogTimer
+ (EFI_CONNECT_CONTROLLER)CoreConnectController, // ConnectController
+ (EFI_DISCONNECT_CONTROLLER)CoreDisconnectController, // DisconnectController
+ (EFI_OPEN_PROTOCOL)CoreOpenProtocol, // OpenProtocol
+ (EFI_CLOSE_PROTOCOL)CoreCloseProtocol, // CloseProtocol
+ (EFI_OPEN_PROTOCOL_INFORMATION)CoreOpenProtocolInformation, // OpenProtocolInformation
+ (EFI_PROTOCOLS_PER_HANDLE)CoreProtocolsPerHandle, // ProtocolsPerHandle
+ (EFI_LOCATE_HANDLE_BUFFER)CoreLocateHandleBuffer, // LocateHandleBuffer
+ (EFI_LOCATE_PROTOCOL)CoreLocateProtocol, // LocateProtocol
+ (EFI_INSTALL_MULTIPLE_PROTOCOL_INTERFACES)CoreInstallMultipleProtocolInterfaces, // InstallMultipleProtocolInterfaces
+ (EFI_UNINSTALL_MULTIPLE_PROTOCOL_INTERFACES)CoreUninstallMultipleProtocolInterfaces, // UninstallMultipleProtocolInterfaces
+ (EFI_CALCULATE_CRC32)CoreEfiNotAvailableYetArg3, // CalculateCrc32
+ (EFI_COPY_MEM)CopyMem, // CopyMem
+ (EFI_SET_MEM)SetMem, // SetMem
+ (EFI_CREATE_EVENT_EX)CoreCreateEventEx // CreateEventEx
+};
+
+EFI_DXE_SERVICES mDxeServices = {
+ {
+ DXE_SERVICES_SIGNATURE, // Signature
+ DXE_SERVICES_REVISION, // Revision
+ sizeof (DXE_SERVICES), // HeaderSize
+ 0, // CRC32
+ 0 // Reserved
+ },
+ (EFI_ADD_MEMORY_SPACE)CoreAddMemorySpace, // AddMemorySpace
+ (EFI_ALLOCATE_MEMORY_SPACE)CoreAllocateMemorySpace, // AllocateMemorySpace
+ (EFI_FREE_MEMORY_SPACE)CoreFreeMemorySpace, // FreeMemorySpace
+ (EFI_REMOVE_MEMORY_SPACE)CoreRemoveMemorySpace, // RemoveMemorySpace
+ (EFI_GET_MEMORY_SPACE_DESCRIPTOR)CoreGetMemorySpaceDescriptor, // GetMemorySpaceDescriptor
+ (EFI_SET_MEMORY_SPACE_ATTRIBUTES)CoreSetMemorySpaceAttributes, // SetMemorySpaceAttributes
+ (EFI_GET_MEMORY_SPACE_MAP)CoreGetMemorySpaceMap, // GetMemorySpaceMap
+ (EFI_ADD_IO_SPACE)CoreAddIoSpace, // AddIoSpace
+ (EFI_ALLOCATE_IO_SPACE)CoreAllocateIoSpace, // AllocateIoSpace
+ (EFI_FREE_IO_SPACE)CoreFreeIoSpace, // FreeIoSpace
+ (EFI_REMOVE_IO_SPACE)CoreRemoveIoSpace, // RemoveIoSpace
+ (EFI_GET_IO_SPACE_DESCRIPTOR)CoreGetIoSpaceDescriptor, // GetIoSpaceDescriptor
+ (EFI_GET_IO_SPACE_MAP)CoreGetIoSpaceMap, // GetIoSpaceMap
+ (EFI_DISPATCH)CoreDispatcher, // Dispatch
+ (EFI_SCHEDULE)CoreSchedule, // Schedule
+ (EFI_TRUST)CoreTrust, // Trust
+ (EFI_PROCESS_FIRMWARE_VOLUME)CoreProcessFirmwareVolume, // ProcessFirmwareVolume
+ (EFI_SET_MEMORY_SPACE_CAPABILITIES)CoreSetMemorySpaceCapabilities, // SetMemorySpaceCapabilities
+};
+
+EFI_SYSTEM_TABLE mEfiSystemTableTemplate = {
+ {
+ EFI_SYSTEM_TABLE_SIGNATURE, // Signature
+ EFI_SYSTEM_TABLE_REVISION, // Revision
+ sizeof (EFI_SYSTEM_TABLE), // HeaderSize
+ 0, // CRC32
+ 0 // Reserved
+ },
+ NULL, // FirmwareVendor
+ 0, // FirmwareRevision
+ NULL, // ConsoleInHandle
+ NULL, // ConIn
+ NULL, // ConsoleOutHandle
+ NULL, // ConOut
+ NULL, // StandardErrorHandle
+ NULL, // StdErr
+ NULL, // RuntimeServices
+ &mBootServices, // BootServices
+ 0, // NumberOfConfigurationTableEntries
+ NULL // ConfigurationTable
+};
+
+EFI_RUNTIME_SERVICES mEfiRuntimeServicesTableTemplate = {
+ {
+ EFI_RUNTIME_SERVICES_SIGNATURE, // Signature
+ EFI_RUNTIME_SERVICES_REVISION, // Revision
+ sizeof (EFI_RUNTIME_SERVICES), // HeaderSize
+ 0, // CRC32
+ 0 // Reserved
+ },
+ (EFI_GET_TIME)CoreEfiNotAvailableYetArg2, // GetTime
+ (EFI_SET_TIME)CoreEfiNotAvailableYetArg1, // SetTime
+ (EFI_GET_WAKEUP_TIME)CoreEfiNotAvailableYetArg3, // GetWakeupTime
+ (EFI_SET_WAKEUP_TIME)CoreEfiNotAvailableYetArg2, // SetWakeupTime
+ (EFI_SET_VIRTUAL_ADDRESS_MAP)CoreEfiNotAvailableYetArg4, // SetVirtualAddressMap
+ (EFI_CONVERT_POINTER)CoreEfiNotAvailableYetArg2, // ConvertPointer
+ (EFI_GET_VARIABLE)CoreEfiNotAvailableYetArg5, // GetVariable
+ (EFI_GET_NEXT_VARIABLE_NAME)CoreEfiNotAvailableYetArg3, // GetNextVariableName
+ (EFI_SET_VARIABLE)CoreEfiNotAvailableYetArg5, // SetVariable
+ (EFI_GET_NEXT_HIGH_MONO_COUNT)CoreEfiNotAvailableYetArg1, // GetNextHighMonotonicCount
+ (EFI_RESET_SYSTEM)CoreEfiNotAvailableYetArg4, // ResetSystem
+ (EFI_UPDATE_CAPSULE)CoreEfiNotAvailableYetArg3, // UpdateCapsule
+ (EFI_QUERY_CAPSULE_CAPABILITIES)CoreEfiNotAvailableYetArg4, // QueryCapsuleCapabilities
+ (EFI_QUERY_VARIABLE_INFO)CoreEfiNotAvailableYetArg4 // QueryVariableInfo
+};
+
+EFI_RUNTIME_ARCH_PROTOCOL gRuntimeTemplate = {
+ INITIALIZE_LIST_HEAD_VARIABLE (gRuntimeTemplate.ImageHead),
+ INITIALIZE_LIST_HEAD_VARIABLE (gRuntimeTemplate.EventHead),
+
+ //
+ // Make sure Size != sizeof (EFI_MEMORY_DESCRIPTOR). This will
+ // prevent people from having pointer math bugs in their code.
+ // now you have to use *DescriptorSize to make things work.
+ //
+ sizeof (EFI_MEMORY_DESCRIPTOR) + sizeof (UINT64) - (sizeof (EFI_MEMORY_DESCRIPTOR) % sizeof (UINT64)),
+ EFI_MEMORY_DESCRIPTOR_VERSION,
+ 0,
+ NULL,
+ NULL,
+ FALSE,
+ FALSE
+};
+
+EFI_RUNTIME_ARCH_PROTOCOL *gRuntime = &gRuntimeTemplate;
+
+//
+// DXE Core Global Variables for the EFI System Table, Boot Services Table,
+// DXE Services Table, and Runtime Services Table
+//
+EFI_DXE_SERVICES *gDxeCoreDS = &mDxeServices;
+EFI_SYSTEM_TABLE *gDxeCoreST = NULL;
+
+//
+// For debug initialize gDxeCoreRT to template. gDxeCoreRT must be allocated from RT memory
+// but gDxeCoreRT is used for ASSERT () and DEBUG () type macros so lets give it
+// a value that will not cause debug infrastructure to crash early on.
+//
+EFI_RUNTIME_SERVICES *gDxeCoreRT = &mEfiRuntimeServicesTableTemplate;
+EFI_HANDLE gDxeCoreImageHandle = NULL;
+
+BOOLEAN gMemoryMapTerminated = FALSE;
+
+//
+// EFI Decompress Protocol
+//
+EFI_DECOMPRESS_PROTOCOL gEfiDecompress = {
+ DxeMainUefiDecompressGetInfo,
+ DxeMainUefiDecompress
+};
+
+//
+// For Loading modules at fixed address feature, the configuration table is to cache the top address below which to load
+// Runtime code&boot time code
+//
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_LOAD_FIXED_ADDRESS_CONFIGURATION_TABLE gLoadModuleAtFixAddressConfigurationTable = { 0, 0 };
+
+// Main entry point to the DXE Core
+//
+
+/**
+ Main entry point to DXE Core.
+
+ @param HobStart Pointer to the beginning of the HOB List from PEI.
+
+ @return This function should never return.
+
+**/
+VOID
+EFIAPI
+DxeMain (
+ IN VOID *HobStart
+ )
+{
+ EFI_STATUS Status;
+ EFI_PHYSICAL_ADDRESS MemoryBaseAddress;
+ UINT64 MemoryLength;
+ PE_COFF_LOADER_IMAGE_CONTEXT ImageContext;
+ UINTN Index;
+ EFI_HOB_GUID_TYPE *GuidHob;
+ EFI_VECTOR_HANDOFF_INFO *VectorInfoList;
+ EFI_VECTOR_HANDOFF_INFO *VectorInfo;
+ VOID *EntryPoint;
+
+ //
+ // Setup the default exception handlers
+ //
+ VectorInfoList = NULL;
+ GuidHob = GetNextGuidHob (&gEfiVectorHandoffInfoPpiGuid, HobStart);
+ if (GuidHob != NULL) {
+ VectorInfoList = (EFI_VECTOR_HANDOFF_INFO *)(GET_GUID_HOB_DATA (GuidHob));
+ }
+
+ Status = InitializeCpuExceptionHandlers (VectorInfoList);
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Setup Stack Guard
+ //
+ if (PcdGetBool (PcdCpuStackGuard)) {
+ Status = InitializeSeparateExceptionStacks (NULL, NULL);
+ ASSERT_EFI_ERROR (Status);
+ }
+
+ //
+ // Initialize Debug Agent to support source level debug in DXE phase
+ //
+ InitializeDebugAgent (DEBUG_AGENT_INIT_DXE_CORE, HobStart, NULL);
+
+ //
+ // Initialize Memory Services
+ //
+ CoreInitializeMemoryServices (&HobStart, &MemoryBaseAddress, &MemoryLength);
+
+ MemoryProfileInit (HobStart);
+
+ //
+ // Start the Image Services.
+ //
+ Status = CoreInitializeImageServices (HobStart);
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Initialize the Global Coherency Domain Services
+ //
+ Status = CoreInitializeGcdServices (&HobStart, MemoryBaseAddress, MemoryLength);
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Allocate the EFI System Table and EFI Runtime Service Table from EfiRuntimeServicesData
+ // Use the templates to initialize the contents of the EFI System Table and EFI Runtime Services Table
+ //
+ gDxeCoreST = AllocateRuntimeCopyPool (sizeof (EFI_SYSTEM_TABLE), &mEfiSystemTableTemplate);
+ ASSERT (gDxeCoreST != NULL);
+
+ gDxeCoreRT = AllocateRuntimeCopyPool (sizeof (EFI_RUNTIME_SERVICES), &mEfiRuntimeServicesTableTemplate);
+ ASSERT (gDxeCoreRT != NULL);
+
+ gDxeCoreST->RuntimeServices = gDxeCoreRT;
+
+ //
+ // Update DXE Core Loaded Image Protocol with allocated UEFI System Table
+ //
+ gDxeCoreLoadedImage->SystemTable = gDxeCoreST;
+
+ //
+ // Call constructor for all libraries
+ //
+ ProcessLibraryConstructorList (gDxeCoreImageHandle, gDxeCoreST);
+ PERF_CROSSMODULE_END ("PEI");
+ PERF_CROSSMODULE_BEGIN ("DXE");
+
+ //
+ // Log MemoryBaseAddress and MemoryLength again (from
+ // CoreInitializeMemoryServices()), now that library constructors have
+ // executed.
+ //
+ DEBUG ((
+ DEBUG_INFO,
+ "%a: MemoryBaseAddress=0x%Lx MemoryLength=0x%Lx\n",
+ __func__,
+ MemoryBaseAddress,
+ MemoryLength
+ ));
+
+ //
+ // Report DXE Core image information to the PE/COFF Extra Action Library
+ //
+ ZeroMem (&ImageContext, sizeof (ImageContext));
+ ImageContext.ImageAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)gDxeCoreLoadedImage->ImageBase;
+ ImageContext.PdbPointer = PeCoffLoaderGetPdbPointer ((VOID *)(UINTN)ImageContext.ImageAddress);
+ ImageContext.SizeOfHeaders = PeCoffGetSizeOfHeaders ((VOID *)(UINTN)ImageContext.ImageAddress);
+ Status = PeCoffLoaderGetEntryPoint ((VOID *)(UINTN)ImageContext.ImageAddress, &EntryPoint);
+ if (Status == EFI_SUCCESS) {
+ ImageContext.EntryPoint = (EFI_PHYSICAL_ADDRESS)(UINTN)EntryPoint;
+ }
+
+ ImageContext.Handle = (VOID *)(UINTN)gDxeCoreLoadedImage->ImageBase;
+ ImageContext.ImageRead = PeCoffLoaderImageReadFromMemory;
+ PeCoffLoaderRelocateImageExtraAction (&ImageContext);
+
+ //
+ // Install the DXE Services Table into the EFI System Tables's Configuration Table
+ //
+ Status = CoreInstallConfigurationTable (&gEfiDxeServicesTableGuid, gDxeCoreDS);
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Install the HOB List into the EFI System Tables's Configuration Table
+ //
+ Status = CoreInstallConfigurationTable (&gEfiHobListGuid, HobStart);
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Install Memory Type Information Table into the EFI System Tables's Configuration Table
+ //
+ Status = CoreInstallConfigurationTable (&gEfiMemoryTypeInformationGuid, &gMemoryTypeInformation);
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // If Loading modules At fixed address feature is enabled, install Load moduels at fixed address
+ // Configuration Table so that user could easily to retrieve the top address to load Dxe and PEI
+ // Code and Tseg base to load SMM driver.
+ //
+ if (PcdGet64 (PcdLoadModuleAtFixAddressEnable) != 0) {
+ Status = CoreInstallConfigurationTable (&gLoadFixedAddressConfigurationTableGuid, &gLoadModuleAtFixAddressConfigurationTable);
+ ASSERT_EFI_ERROR (Status);
+ }
+
+ //
+ // Report Status Code here for DXE_ENTRY_POINT once it is available
+ //
+ REPORT_STATUS_CODE (
+ EFI_PROGRESS_CODE,
+ (EFI_SOFTWARE_DXE_CORE | EFI_SW_DXE_CORE_PC_ENTRY_POINT)
+ );
+
+ //
+ // Create the aligned system table pointer structure that is used by external
+ // debuggers to locate the system table... Also, install debug image info
+ // configuration table.
+ //
+ CoreInitializeDebugImageInfoTable ();
+ CoreNewDebugImageInfoEntry (
+ EFI_DEBUG_IMAGE_INFO_TYPE_NORMAL,
+ gDxeCoreLoadedImage,
+ gDxeCoreImageHandle
+ );
+
+ DEBUG ((DEBUG_INFO | DEBUG_LOAD, "HOBLIST address in DXE = 0x%p\n", HobStart));
+
+ DEBUG_CODE_BEGIN ();
+ EFI_PEI_HOB_POINTERS Hob;
+
+ for (Hob.Raw = HobStart; !END_OF_HOB_LIST (Hob); Hob.Raw = GET_NEXT_HOB (Hob)) {
+ if (GET_HOB_TYPE (Hob) == EFI_HOB_TYPE_MEMORY_ALLOCATION) {
+ DEBUG ((
+ DEBUG_INFO | DEBUG_LOAD,
+ "Memory Allocation 0x%08x 0x%0lx - 0x%0lx\n", \
+ Hob.MemoryAllocation->AllocDescriptor.MemoryType, \
+ Hob.MemoryAllocation->AllocDescriptor.MemoryBaseAddress, \
+ Hob.MemoryAllocation->AllocDescriptor.MemoryBaseAddress + Hob.MemoryAllocation->AllocDescriptor.MemoryLength - 1
+ ));
+ }
+ }
+
+ for (Hob.Raw = HobStart; !END_OF_HOB_LIST (Hob); Hob.Raw = GET_NEXT_HOB (Hob)) {
+ if (GET_HOB_TYPE (Hob) == EFI_HOB_TYPE_FV) {
+ DEBUG ((
+ DEBUG_INFO | DEBUG_LOAD,
+ "FV Hob 0x%0lx - 0x%0lx\n",
+ Hob.FirmwareVolume->BaseAddress,
+ Hob.FirmwareVolume->BaseAddress + Hob.FirmwareVolume->Length - 1
+ ));
+ } else if (GET_HOB_TYPE (Hob) == EFI_HOB_TYPE_FV2) {
+ DEBUG ((
+ DEBUG_INFO | DEBUG_LOAD,
+ "FV2 Hob 0x%0lx - 0x%0lx\n",
+ Hob.FirmwareVolume2->BaseAddress,
+ Hob.FirmwareVolume2->BaseAddress + Hob.FirmwareVolume2->Length - 1
+ ));
+ DEBUG ((
+ DEBUG_INFO | DEBUG_LOAD,
+ " %g - %g\n",
+ &Hob.FirmwareVolume2->FvName,
+ &Hob.FirmwareVolume2->FileName
+ ));
+ } else if (GET_HOB_TYPE (Hob) == EFI_HOB_TYPE_FV3) {
+ DEBUG ((
+ DEBUG_INFO | DEBUG_LOAD,
+ "FV3 Hob 0x%0lx - 0x%0lx - 0x%x - 0x%x\n",
+ Hob.FirmwareVolume3->BaseAddress,
+ Hob.FirmwareVolume3->BaseAddress + Hob.FirmwareVolume3->Length - 1,
+ Hob.FirmwareVolume3->AuthenticationStatus,
+ Hob.FirmwareVolume3->ExtractedFv
+ ));
+ if (Hob.FirmwareVolume3->ExtractedFv) {
+ DEBUG ((
+ DEBUG_INFO | DEBUG_LOAD,
+ " %g - %g\n",
+ &Hob.FirmwareVolume3->FvName,
+ &Hob.FirmwareVolume3->FileName
+ ));
+ }
+ }
+ }
+
+ DEBUG_CODE_END ();
+
+ //
+ // Initialize the Event Services
+ //
+ Status = CoreInitializeEventServices ();
+ ASSERT_EFI_ERROR (Status);
+
+ MemoryProfileInstallProtocol ();
+
+ CoreInitializeMemoryAttributesTable ();
+ CoreInitializeMemoryProtection ();
+
+ //
+ // Get persisted vector hand-off info from GUIDeed HOB again due to HobStart may be updated,
+ // and install configuration table
+ //
+ GuidHob = GetNextGuidHob (&gEfiVectorHandoffInfoPpiGuid, HobStart);
+ if (GuidHob != NULL) {
+ VectorInfoList = (EFI_VECTOR_HANDOFF_INFO *)(GET_GUID_HOB_DATA (GuidHob));
+ VectorInfo = VectorInfoList;
+ Index = 1;
+ while (VectorInfo->Attribute != EFI_VECTOR_HANDOFF_LAST_ENTRY) {
+ VectorInfo++;
+ Index++;
+ }
+
+ VectorInfo = AllocateCopyPool (sizeof (EFI_VECTOR_HANDOFF_INFO) * Index, (VOID *)VectorInfoList);
+ ASSERT (VectorInfo != NULL);
+ Status = CoreInstallConfigurationTable (&gEfiVectorHandoffTableGuid, (VOID *)VectorInfo);
+ ASSERT_EFI_ERROR (Status);
+ }
+
+ //
+ // Get the Protocols that were passed in from PEI to DXE through GUIDed HOBs
+ //
+ // These Protocols are not architectural. This implementation is sharing code between
+ // PEI and DXE in order to save FLASH space. These Protocols could also be implemented
+ // as part of the DXE Core. However, that would also require the DXE Core to be ported
+ // each time a different CPU is used, a different Decompression algorithm is used, or a
+ // different Image type is used. By placing these Protocols in PEI, the DXE Core remains
+ // generic, and only PEI and the Arch Protocols need to be ported from Platform to Platform,
+ // and from CPU to CPU.
+ //
+
+ //
+ // Publish the EFI, Tiano, and Custom Decompress protocols for use by other DXE components
+ //
+ Status = CoreInstallMultipleProtocolInterfaces (
+ &mDecompressHandle,
+ &gEfiDecompressProtocolGuid,
+ &gEfiDecompress,
+ NULL
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Register for the GUIDs of the Architectural Protocols, so the rest of the
+ // EFI Boot Services and EFI Runtime Services tables can be filled in.
+ // Also register for the GUIDs of optional protocols.
+ //
+ CoreNotifyOnProtocolInstallation ();
+
+ //
+ // Produce Firmware Volume Protocols, one for each FV in the HOB list.
+ //
+ Status = FwVolBlockDriverInit (gDxeCoreImageHandle, gDxeCoreST);
+ ASSERT_EFI_ERROR (Status);
+
+ Status = FwVolDriverInit (gDxeCoreImageHandle, gDxeCoreST);
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Produce the Section Extraction Protocol
+ //
+ Status = InitializeSectionExtraction (gDxeCoreImageHandle, gDxeCoreST);
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Initialize the DXE Dispatcher
+ //
+ CoreInitializeDispatcher ();
+
+ //
+ // Invoke the DXE Dispatcher
+ //
+ CoreDispatcher ();
+
+ //
+ // Display Architectural protocols that were not loaded if this is DEBUG build
+ //
+ DEBUG_CODE_BEGIN ();
+ CoreDisplayMissingArchProtocols ();
+ DEBUG_CODE_END ();
+
+ //
+ // Display any drivers that were not dispatched because dependency expression
+ // evaluated to false if this is a debug build
+ //
+ DEBUG_CODE_BEGIN ();
+ CoreDisplayDiscoveredNotDispatched ();
+ DEBUG_CODE_END ();
+
+ //
+ // Assert if the Architectural Protocols are not present.
+ //
+ Status = CoreAllEfiServicesAvailable ();
+ if (EFI_ERROR (Status)) {
+ //
+ // Report Status code that some Architectural Protocols are not present.
+ //
+ REPORT_STATUS_CODE (
+ EFI_ERROR_CODE | EFI_ERROR_MAJOR,
+ (EFI_SOFTWARE_DXE_CORE | EFI_SW_DXE_CORE_EC_NO_ARCH)
+ );
+ }
+
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Report Status code before transfer control to BDS
+ //
+ REPORT_STATUS_CODE (
+ EFI_PROGRESS_CODE,
+ (EFI_SOFTWARE_DXE_CORE | EFI_SW_DXE_CORE_PC_HANDOFF_TO_NEXT)
+ );
+
+ //
+ // Transfer control to the BDS Architectural Protocol
+ //
+ gBds->Entry (gBds);
+
+ //
+ // BDS should never return
+ //
+ ASSERT (FALSE);
+ CpuDeadLoop ();
+
+ UNREACHABLE ();
+}
+
+/**
+ Place holder function until all the Boot Services and Runtime Services are
+ available.
+
+ @param Arg1 Undefined
+
+ @return EFI_NOT_AVAILABLE_YET
+
+**/
+EFI_STATUS
+EFIAPI
+CoreEfiNotAvailableYetArg1 (
+ UINTN Arg1
+ )
+{
+ //
+ // This function should never be executed. If it does, then the architectural protocols
+ // have not been designed correctly. The CpuBreakpoint () is commented out for now until the
+ // DXE Core and all the Architectural Protocols are complete.
+ //
+
+ return EFI_NOT_AVAILABLE_YET;
+}
+
+/**
+ Place holder function until all the Boot Services and Runtime Services are available.
+
+ @param Arg1 Undefined
+ @param Arg2 Undefined
+
+ @return EFI_NOT_AVAILABLE_YET
+
+**/
+EFI_STATUS
+EFIAPI
+CoreEfiNotAvailableYetArg2 (
+ UINTN Arg1,
+ UINTN Arg2
+ )
+{
+ //
+ // This function should never be executed. If it does, then the architectural protocols
+ // have not been designed correctly. The CpuBreakpoint () is commented out for now until the
+ // DXE Core and all the Architectural Protocols are complete.
+ //
+
+ return EFI_NOT_AVAILABLE_YET;
+}
+
+/**
+ Place holder function until all the Boot Services and Runtime Services are available.
+
+ @param Arg1 Undefined
+ @param Arg2 Undefined
+ @param Arg3 Undefined
+
+ @return EFI_NOT_AVAILABLE_YET
+
+**/
+EFI_STATUS
+EFIAPI
+CoreEfiNotAvailableYetArg3 (
+ UINTN Arg1,
+ UINTN Arg2,
+ UINTN Arg3
+ )
+{
+ //
+ // This function should never be executed. If it does, then the architectural protocols
+ // have not been designed correctly. The CpuBreakpoint () is commented out for now until the
+ // DXE Core and all the Architectural Protocols are complete.
+ //
+
+ return EFI_NOT_AVAILABLE_YET;
+}
+
+/**
+ Place holder function until all the Boot Services and Runtime Services are available.
+
+ @param Arg1 Undefined
+ @param Arg2 Undefined
+ @param Arg3 Undefined
+ @param Arg4 Undefined
+
+ @return EFI_NOT_AVAILABLE_YET
+
+**/
+EFI_STATUS
+EFIAPI
+CoreEfiNotAvailableYetArg4 (
+ UINTN Arg1,
+ UINTN Arg2,
+ UINTN Arg3,
+ UINTN Arg4
+ )
+{
+ //
+ // This function should never be executed. If it does, then the architectural protocols
+ // have not been designed correctly. The CpuBreakpoint () is commented out for now until the
+ // DXE Core and all the Architectural Protocols are complete.
+ //
+
+ return EFI_NOT_AVAILABLE_YET;
+}
+
+/**
+ Place holder function until all the Boot Services and Runtime Services are available.
+
+ @param Arg1 Undefined
+ @param Arg2 Undefined
+ @param Arg3 Undefined
+ @param Arg4 Undefined
+ @param Arg5 Undefined
+
+ @return EFI_NOT_AVAILABLE_YET
+
+**/
+EFI_STATUS
+EFIAPI
+CoreEfiNotAvailableYetArg5 (
+ UINTN Arg1,
+ UINTN Arg2,
+ UINTN Arg3,
+ UINTN Arg4,
+ UINTN Arg5
+ )
+{
+ //
+ // This function should never be executed. If it does, then the architectural protocols
+ // have not been designed correctly. The CpuBreakpoint () is commented out for now until the
+ // DXE Core and all the Architectural Protocols are complete.
+ //
+
+ return EFI_NOT_AVAILABLE_YET;
+}
+
+/**
+ Calcualte the 32-bit CRC in a EFI table using the service provided by the
+ gRuntime service.
+
+ @param Hdr Pointer to an EFI standard header
+
+**/
+VOID
+CalculateEfiHdrCrc (
+ IN OUT EFI_TABLE_HEADER *Hdr
+ )
+{
+ UINT32 Crc;
+
+ Hdr->CRC32 = 0;
+
+ //
+ // If gBS->CalculateCrce32 () == CoreEfiNotAvailableYet () then
+ // Crc will come back as zero if we set it to zero here
+ //
+ Crc = 0;
+ gBS->CalculateCrc32 ((UINT8 *)Hdr, Hdr->HeaderSize, &Crc);
+ Hdr->CRC32 = Crc;
+}
+
+/**
+ Terminates all boot services.
+
+ @param ImageHandle Handle that identifies the exiting image.
+ @param MapKey Key to the latest memory map.
+
+ @retval EFI_SUCCESS Boot Services terminated
+ @retval EFI_INVALID_PARAMETER MapKey is incorrect.
+
+**/
+EFI_STATUS
+EFIAPI
+CoreExitBootServices (
+ IN EFI_HANDLE ImageHandle,
+ IN UINTN MapKey
+ )
+{
+ EFI_STATUS Status;
+
+ //
+ // Notify other drivers of their last chance to use boot services
+ // before the memory map is terminated.
+ //
+ CoreNotifySignalList (&gEfiEventBeforeExitBootServicesGuid);
+
+ //
+ // Disable Timer
+ //
+ gTimer->SetTimerPeriod (gTimer, 0);
+
+ //
+ // Terminate memory services if the MapKey matches
+ //
+ Status = CoreTerminateMemoryMap (MapKey);
+ if (EFI_ERROR (Status)) {
+ //
+ // Notify other drivers that ExitBootServices fail
+ //
+ CoreNotifySignalList (&gEventExitBootServicesFailedGuid);
+ return Status;
+ }
+
+ gMemoryMapTerminated = TRUE;
+
+ //
+ // Notify other drivers that we are exiting boot services.
+ //
+ CoreNotifySignalList (&gEfiEventExitBootServicesGuid);
+
+ //
+ // Report that ExitBootServices() has been called
+ //
+ REPORT_STATUS_CODE (
+ EFI_PROGRESS_CODE,
+ (EFI_SOFTWARE_EFI_BOOT_SERVICE | EFI_SW_BS_PC_EXIT_BOOT_SERVICES)
+ );
+
+ MemoryProtectionExitBootServicesCallback ();
+
+ //
+ // Disable interrupt of Debug timer.
+ //
+ SaveAndSetDebugTimerInterrupt (FALSE);
+
+ //
+ // Disable CPU Interrupts
+ //
+ gCpu->DisableInterrupt (gCpu);
+
+ //
+ // Clear the non-runtime values of the EFI System Table
+ //
+ gDxeCoreST->BootServices = NULL;
+ gDxeCoreST->ConIn = NULL;
+ gDxeCoreST->ConsoleInHandle = NULL;
+ gDxeCoreST->ConOut = NULL;
+ gDxeCoreST->ConsoleOutHandle = NULL;
+ gDxeCoreST->StdErr = NULL;
+ gDxeCoreST->StandardErrorHandle = NULL;
+
+ //
+ // Recompute the 32-bit CRC of the EFI System Table
+ //
+ CalculateEfiHdrCrc (&gDxeCoreST->Hdr);
+
+ //
+ // Zero out the Boot Service Table
+ //
+ ZeroMem (gBS, sizeof (EFI_BOOT_SERVICES));
+ gBS = NULL;
+
+ //
+ // Update the AtRuntime field in Runtiem AP.
+ //
+ gRuntime->AtRuntime = TRUE;
+
+ return Status;
+}
+
+/**
+ Given a compressed source buffer, this function retrieves the size of the
+ uncompressed buffer and the size of the scratch buffer required to decompress
+ the compressed source buffer.
+
+ The GetInfo() function retrieves the size of the uncompressed buffer and the
+ temporary scratch buffer required to decompress the buffer specified by Source
+ and SourceSize. If the size of the uncompressed buffer or the size of the
+ scratch buffer cannot be determined from the compressed data specified by
+ Source and SourceData, then EFI_INVALID_PARAMETER is returned. Otherwise, the
+ size of the uncompressed buffer is returned in DestinationSize, the size of
+ the scratch buffer is returned in ScratchSize, and EFI_SUCCESS is returned.
+ The GetInfo() function does not have scratch buffer available to perform a
+ thorough checking of the validity of the source data. It just retrieves the
+ "Original Size" field from the beginning bytes of the source data and output
+ it as DestinationSize. And ScratchSize is specific to the decompression
+ implementation.
+
+ @param This A pointer to the EFI_DECOMPRESS_PROTOCOL instance.
+ @param Source The source buffer containing the compressed data.
+ @param SourceSize The size, in bytes, of the source buffer.
+ @param DestinationSize A pointer to the size, in bytes, of the
+ uncompressed buffer that will be generated when the
+ compressed buffer specified by Source and
+ SourceSize is decompressed.
+ @param ScratchSize A pointer to the size, in bytes, of the scratch
+ buffer that is required to decompress the
+ compressed buffer specified by Source and
+ SourceSize.
+
+ @retval EFI_SUCCESS The size of the uncompressed data was returned in
+ DestinationSize and the size of the scratch buffer
+ was returned in ScratchSize.
+ @retval EFI_INVALID_PARAMETER The size of the uncompressed data or the size of
+ the scratch buffer cannot be determined from the
+ compressed data specified by Source and
+ SourceSize.
+
+**/
+EFI_STATUS
+EFIAPI
+DxeMainUefiDecompressGetInfo (
+ IN EFI_DECOMPRESS_PROTOCOL *This,
+ IN VOID *Source,
+ IN UINT32 SourceSize,
+ OUT UINT32 *DestinationSize,
+ OUT UINT32 *ScratchSize
+ )
+{
+ if ((Source == NULL) || (DestinationSize == NULL) || (ScratchSize == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ return UefiDecompressGetInfo (Source, SourceSize, DestinationSize, ScratchSize);
+}
+
+/**
+ Decompresses a compressed source buffer.
+
+ The Decompress() function extracts decompressed data to its original form.
+ This protocol is designed so that the decompression algorithm can be
+ implemented without using any memory services. As a result, the Decompress()
+ Function is not allowed to call AllocatePool() or AllocatePages() in its
+ implementation. It is the caller's responsibility to allocate and free the
+ Destination and Scratch buffers.
+ If the compressed source data specified by Source and SourceSize is
+ successfully decompressed into Destination, then EFI_SUCCESS is returned. If
+ the compressed source data specified by Source and SourceSize is not in a
+ valid compressed data format, then EFI_INVALID_PARAMETER is returned.
+
+ @param This A pointer to the EFI_DECOMPRESS_PROTOCOL instance.
+ @param Source The source buffer containing the compressed data.
+ @param SourceSize SourceSizeThe size of source data.
+ @param Destination On output, the destination buffer that contains
+ the uncompressed data.
+ @param DestinationSize The size of the destination buffer. The size of
+ the destination buffer needed is obtained from
+ EFI_DECOMPRESS_PROTOCOL.GetInfo().
+ @param Scratch A temporary scratch buffer that is used to perform
+ the decompression.
+ @param ScratchSize The size of scratch buffer. The size of the
+ scratch buffer needed is obtained from GetInfo().
+
+ @retval EFI_SUCCESS Decompression completed successfully, and the
+ uncompressed buffer is returned in Destination.
+ @retval EFI_INVALID_PARAMETER The source buffer specified by Source and
+ SourceSize is corrupted (not in a valid
+ compressed format).
+
+**/
+EFI_STATUS
+EFIAPI
+DxeMainUefiDecompress (
+ IN EFI_DECOMPRESS_PROTOCOL *This,
+ IN VOID *Source,
+ IN UINT32 SourceSize,
+ IN OUT VOID *Destination,
+ IN UINT32 DestinationSize,
+ IN OUT VOID *Scratch,
+ IN UINT32 ScratchSize
+ )
+{
+ EFI_STATUS Status;
+ UINT32 TestDestinationSize;
+ UINT32 TestScratchSize;
+
+ if ((Source == NULL) || (Destination == NULL) || (Scratch == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Status = UefiDecompressGetInfo (Source, SourceSize, &TestDestinationSize, &TestScratchSize);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if ((ScratchSize < TestScratchSize) || (DestinationSize < TestDestinationSize)) {
+ return RETURN_INVALID_PARAMETER;
+ }
+
+ return UefiDecompress (Source, Destination, Scratch);
+}
diff --git a/MdeModulePkg/Core/Dxe/DxeMain/DxeProtocolNotify.c b/MdeModulePkg/Core/Dxe/DxeMain/DxeProtocolNotify.c
index 3fe02940ed..62c7bda96d 100644
--- a/MdeModulePkg/Core/Dxe/DxeMain/DxeProtocolNotify.c
+++ b/MdeModulePkg/Core/Dxe/DxeMain/DxeProtocolNotify.c
@@ -1,279 +1,279 @@
-/** @file
- This file deals with Architecture Protocol (AP) registration in
- the Dxe Core. The mArchProtocols[] array represents a list of
- events that represent the Architectural Protocols.
-
-Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
-SPDX-License-Identifier: BSD-2-Clause-Patent
-
-**/
-
-#include "DxeMain.h"
-
-//
-// DXE Core Global Variables for all of the Architectural Protocols.
-// If a protocol is installed mArchProtocols[].Present will be TRUE.
-//
-// CoreNotifyOnArchProtocolInstallation () fills in mArchProtocols[].Event
-// and mArchProtocols[].Registration as it creates events for every array
-// entry.
-//
-EFI_CORE_PROTOCOL_NOTIFY_ENTRY mArchProtocols[] = {
- { &gEfiSecurityArchProtocolGuid, (VOID **)&gSecurity, NULL, NULL, FALSE },
- { &gEfiCpuArchProtocolGuid, (VOID **)&gCpu, NULL, NULL, FALSE },
- { &gEfiMetronomeArchProtocolGuid, (VOID **)&gMetronome, NULL, NULL, FALSE },
- { &gEfiTimerArchProtocolGuid, (VOID **)&gTimer, NULL, NULL, FALSE },
- { &gEfiBdsArchProtocolGuid, (VOID **)&gBds, NULL, NULL, FALSE },
- { &gEfiWatchdogTimerArchProtocolGuid, (VOID **)&gWatchdogTimer, NULL, NULL, FALSE },
- { &gEfiRuntimeArchProtocolGuid, (VOID **)&gRuntime, NULL, NULL, FALSE },
- { &gEfiVariableArchProtocolGuid, (VOID **)NULL, NULL, NULL, FALSE },
- { &gEfiVariableWriteArchProtocolGuid, (VOID **)NULL, NULL, NULL, FALSE },
- { &gEfiCapsuleArchProtocolGuid, (VOID **)NULL, NULL, NULL, FALSE },
- { &gEfiMonotonicCounterArchProtocolGuid, (VOID **)NULL, NULL, NULL, FALSE },
- { &gEfiResetArchProtocolGuid, (VOID **)NULL, NULL, NULL, FALSE },
- { &gEfiRealTimeClockArchProtocolGuid, (VOID **)NULL, NULL, NULL, FALSE },
- { NULL, (VOID **)NULL, NULL, NULL, FALSE }
-};
-
-//
-// Optional protocols that the DXE Core will use if they are present
-//
-EFI_CORE_PROTOCOL_NOTIFY_ENTRY mOptionalProtocols[] = {
- { &gEfiSecurity2ArchProtocolGuid, (VOID **)&gSecurity2, NULL, NULL, FALSE },
- { &gEfiSmmBase2ProtocolGuid, (VOID **)&gSmmBase2, NULL, NULL, FALSE },
- { NULL, (VOID **)NULL, NULL, NULL, FALSE }
-};
-
-//
-// Following is needed to display missing architectural protocols in debug builds
-//
-typedef struct {
- EFI_GUID *ProtocolGuid;
- CHAR8 *GuidString;
-} GUID_TO_STRING_PROTOCOL_ENTRY;
-
-GLOBAL_REMOVE_IF_UNREFERENCED CONST GUID_TO_STRING_PROTOCOL_ENTRY mMissingProtocols[] = {
- { &gEfiSecurityArchProtocolGuid, "Security" },
- { &gEfiCpuArchProtocolGuid, "CPU" },
- { &gEfiMetronomeArchProtocolGuid, "Metronome" },
- { &gEfiTimerArchProtocolGuid, "Timer" },
- { &gEfiBdsArchProtocolGuid, "Bds" },
- { &gEfiWatchdogTimerArchProtocolGuid, "Watchdog Timer" },
- { &gEfiRuntimeArchProtocolGuid, "Runtime" },
- { &gEfiVariableArchProtocolGuid, "Variable" },
- { &gEfiVariableWriteArchProtocolGuid, "Variable Write" },
- { &gEfiCapsuleArchProtocolGuid, "Capsule" },
- { &gEfiMonotonicCounterArchProtocolGuid, "Monotonic Counter" },
- { &gEfiResetArchProtocolGuid, "Reset" },
- { &gEfiRealTimeClockArchProtocolGuid, "Real Time Clock" },
- { NULL, "" }
-};
-
-/**
- Return TRUE if all AP services are available.
-
- @retval EFI_SUCCESS All AP services are available
- @retval EFI_NOT_FOUND At least one AP service is not available
-
-**/
-EFI_STATUS
-CoreAllEfiServicesAvailable (
- VOID
- )
-{
- EFI_CORE_PROTOCOL_NOTIFY_ENTRY *Entry;
-
- for (Entry = mArchProtocols; Entry->ProtocolGuid != NULL; Entry++) {
- if (!Entry->Present) {
- return EFI_NOT_FOUND;
- }
- }
-
- return EFI_SUCCESS;
-}
-
-/**
- Notification event handler registered by CoreNotifyOnArchProtocolInstallation ().
- This notify function is registered for every architectural protocol. This handler
- updates mArchProtocol[] array entry with protocol instance data and sets it's
- present flag to TRUE. If any constructor is required it is executed. The EFI
- System Table headers are updated.
-
- @param Event The Event that is being processed, not used.
- @param Context Event Context, not used.
-
-**/
-VOID
-EFIAPI
-GenericProtocolNotify (
- IN EFI_EVENT Event,
- IN VOID *Context
- )
-{
- EFI_STATUS Status;
- EFI_CORE_PROTOCOL_NOTIFY_ENTRY *Entry;
- VOID *Protocol;
- LIST_ENTRY *Link;
- LIST_ENTRY TempLinkNode;
-
- Protocol = NULL;
-
- //
- // Get Entry from Context
- //
- Entry = (EFI_CORE_PROTOCOL_NOTIFY_ENTRY *)Context;
-
- //
- // See if the expected protocol is present in the handle database
- //
- Status = CoreLocateProtocol (Entry->ProtocolGuid, Entry->Registration, &Protocol);
- if (EFI_ERROR (Status)) {
- return;
- }
-
- //
- // Mark the protocol as present
- //
- Entry->Present = TRUE;
-
- //
- // Update protocol global variable if one exists. Entry->Protocol points to a global variable
- // if one exists in the DXE core for this Architectural Protocol
- //
- if (Entry->Protocol != NULL) {
- *(Entry->Protocol) = Protocol;
- }
-
- //
- // Do special operations for Architectural Protocols
- //
-
- if (CompareGuid (Entry->ProtocolGuid, &gEfiTimerArchProtocolGuid)) {
- //
- // Register the Core timer tick handler with the Timer AP
- //
- gTimer->RegisterHandler (gTimer, CoreTimerTick);
- }
-
- if (CompareGuid (Entry->ProtocolGuid, &gEfiRuntimeArchProtocolGuid)) {
- //
- // When runtime architectural protocol is available, updates CRC32 in the Debug Table
- //
- CoreUpdateDebugTableCrc32 ();
-
- //
- // Update the Runtime Architectural protocol with the template that the core was
- // using so there would not need to be a dependency on the Runtime AP
- //
-
- //
- // Copy all the registered Image to new gRuntime protocol
- //
- for (Link = gRuntimeTemplate.ImageHead.ForwardLink; Link != &gRuntimeTemplate.ImageHead; Link = TempLinkNode.ForwardLink) {
- CopyMem (&TempLinkNode, Link, sizeof (LIST_ENTRY));
- InsertTailList (&gRuntime->ImageHead, Link);
- }
-
- //
- // Copy all the registered Event to new gRuntime protocol
- //
- for (Link = gRuntimeTemplate.EventHead.ForwardLink; Link != &gRuntimeTemplate.EventHead; Link = TempLinkNode.ForwardLink) {
- CopyMem (&TempLinkNode, Link, sizeof (LIST_ENTRY));
- InsertTailList (&gRuntime->EventHead, Link);
- }
-
- //
- // Clean up gRuntimeTemplate
- //
- gRuntimeTemplate.ImageHead.ForwardLink = &gRuntimeTemplate.ImageHead;
- gRuntimeTemplate.ImageHead.BackLink = &gRuntimeTemplate.ImageHead;
- gRuntimeTemplate.EventHead.ForwardLink = &gRuntimeTemplate.EventHead;
- gRuntimeTemplate.EventHead.BackLink = &gRuntimeTemplate.EventHead;
- }
-
- //
- // It's over kill to do them all every time, but it saves a lot of code.
- //
- CalculateEfiHdrCrc (&gDxeCoreRT->Hdr);
- CalculateEfiHdrCrc (&gBS->Hdr);
- CalculateEfiHdrCrc (&gDxeCoreST->Hdr);
- CalculateEfiHdrCrc (&gDxeCoreDS->Hdr);
-}
-
-/**
- Creates an event for each entry in a table that is fired everytime a Protocol
- of a specific type is installed.
-
- @param Entry Pointer to EFI_CORE_PROTOCOL_NOTIFY_ENTRY.
-
-**/
-VOID
-CoreNotifyOnProtocolEntryTable (
- EFI_CORE_PROTOCOL_NOTIFY_ENTRY *Entry
- )
-{
- EFI_STATUS Status;
-
- for ( ; Entry->ProtocolGuid != NULL; Entry++) {
- //
- // Create the event
- //
- Status = CoreCreateEvent (
- EVT_NOTIFY_SIGNAL,
- TPL_CALLBACK,
- GenericProtocolNotify,
- Entry,
- &Entry->Event
- );
- ASSERT_EFI_ERROR (Status);
-
- //
- // Register for protocol notifactions on this event
- //
- Status = CoreRegisterProtocolNotify (
- Entry->ProtocolGuid,
- Entry->Event,
- &Entry->Registration
- );
- ASSERT_EFI_ERROR (Status);
- }
-}
-
-/**
- Creates an events for the Architectural Protocols and the optional protocols
- that are fired everytime a Protocol of a specific type is installed.
-
-**/
-VOID
-CoreNotifyOnProtocolInstallation (
- VOID
- )
-{
- CoreNotifyOnProtocolEntryTable (mArchProtocols);
- CoreNotifyOnProtocolEntryTable (mOptionalProtocols);
-}
-
-/**
- Displays Architectural protocols that were not loaded and are required for DXE
- core to function. Only used in Debug Builds.
-
-**/
-VOID
-CoreDisplayMissingArchProtocols (
- VOID
- )
-{
- EFI_CORE_PROTOCOL_NOTIFY_ENTRY *Entry;
- CONST GUID_TO_STRING_PROTOCOL_ENTRY *MissingEntry;
-
- for (Entry = mArchProtocols; Entry->ProtocolGuid != NULL; Entry++) {
- if (!Entry->Present) {
- for (MissingEntry = mMissingProtocols; MissingEntry->ProtocolGuid != NULL; MissingEntry++) {
- if (CompareGuid (Entry->ProtocolGuid, MissingEntry->ProtocolGuid)) {
- DEBUG ((DEBUG_ERROR, "\n%a Arch Protocol not present!!\n", MissingEntry->GuidString));
- break;
- }
- }
- }
- }
-}
+/** @file
+ This file deals with Architecture Protocol (AP) registration in
+ the Dxe Core. The mArchProtocols[] array represents a list of
+ events that represent the Architectural Protocols.
+
+Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "DxeMain.h"
+
+//
+// DXE Core Global Variables for all of the Architectural Protocols.
+// If a protocol is installed mArchProtocols[].Present will be TRUE.
+//
+// CoreNotifyOnArchProtocolInstallation () fills in mArchProtocols[].Event
+// and mArchProtocols[].Registration as it creates events for every array
+// entry.
+//
+EFI_CORE_PROTOCOL_NOTIFY_ENTRY mArchProtocols[] = {
+ { &gEfiSecurityArchProtocolGuid, (VOID **)&gSecurity, NULL, NULL, FALSE },
+ { &gEfiCpuArchProtocolGuid, (VOID **)&gCpu, NULL, NULL, FALSE },
+ { &gEfiMetronomeArchProtocolGuid, (VOID **)&gMetronome, NULL, NULL, FALSE },
+ { &gEfiTimerArchProtocolGuid, (VOID **)&gTimer, NULL, NULL, FALSE },
+ { &gEfiBdsArchProtocolGuid, (VOID **)&gBds, NULL, NULL, FALSE },
+ { &gEfiWatchdogTimerArchProtocolGuid, (VOID **)&gWatchdogTimer, NULL, NULL, FALSE },
+ { &gEfiRuntimeArchProtocolGuid, (VOID **)&gRuntime, NULL, NULL, FALSE },
+ { &gEfiVariableArchProtocolGuid, (VOID **)NULL, NULL, NULL, FALSE },
+ { &gEfiVariableWriteArchProtocolGuid, (VOID **)NULL, NULL, NULL, FALSE },
+ { &gEfiCapsuleArchProtocolGuid, (VOID **)NULL, NULL, NULL, FALSE },
+ { &gEfiMonotonicCounterArchProtocolGuid, (VOID **)NULL, NULL, NULL, FALSE },
+ { &gEfiResetArchProtocolGuid, (VOID **)NULL, NULL, NULL, FALSE },
+ { &gEfiRealTimeClockArchProtocolGuid, (VOID **)NULL, NULL, NULL, FALSE },
+ { NULL, (VOID **)NULL, NULL, NULL, FALSE }
+};
+
+//
+// Optional protocols that the DXE Core will use if they are present
+//
+EFI_CORE_PROTOCOL_NOTIFY_ENTRY mOptionalProtocols[] = {
+ { &gEfiSecurity2ArchProtocolGuid, (VOID **)&gSecurity2, NULL, NULL, FALSE },
+ { &gEfiSmmBase2ProtocolGuid, (VOID **)&gSmmBase2, NULL, NULL, FALSE },
+ { NULL, (VOID **)NULL, NULL, NULL, FALSE }
+};
+
+//
+// Following is needed to display missing architectural protocols in debug builds
+//
+typedef struct {
+ EFI_GUID *ProtocolGuid;
+ CHAR8 *GuidString;
+} GUID_TO_STRING_PROTOCOL_ENTRY;
+
+GLOBAL_REMOVE_IF_UNREFERENCED CONST GUID_TO_STRING_PROTOCOL_ENTRY mMissingProtocols[] = {
+ { &gEfiSecurityArchProtocolGuid, "Security" },
+ { &gEfiCpuArchProtocolGuid, "CPU" },
+ { &gEfiMetronomeArchProtocolGuid, "Metronome" },
+ { &gEfiTimerArchProtocolGuid, "Timer" },
+ { &gEfiBdsArchProtocolGuid, "Bds" },
+ { &gEfiWatchdogTimerArchProtocolGuid, "Watchdog Timer" },
+ { &gEfiRuntimeArchProtocolGuid, "Runtime" },
+ { &gEfiVariableArchProtocolGuid, "Variable" },
+ { &gEfiVariableWriteArchProtocolGuid, "Variable Write" },
+ { &gEfiCapsuleArchProtocolGuid, "Capsule" },
+ { &gEfiMonotonicCounterArchProtocolGuid, "Monotonic Counter" },
+ { &gEfiResetArchProtocolGuid, "Reset" },
+ { &gEfiRealTimeClockArchProtocolGuid, "Real Time Clock" },
+ { NULL, "" }
+};
+
+/**
+ Return TRUE if all AP services are available.
+
+ @retval EFI_SUCCESS All AP services are available
+ @retval EFI_NOT_FOUND At least one AP service is not available
+
+**/
+EFI_STATUS
+CoreAllEfiServicesAvailable (
+ VOID
+ )
+{
+ EFI_CORE_PROTOCOL_NOTIFY_ENTRY *Entry;
+
+ for (Entry = mArchProtocols; Entry->ProtocolGuid != NULL; Entry++) {
+ if (!Entry->Present) {
+ return EFI_NOT_FOUND;
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Notification event handler registered by CoreNotifyOnArchProtocolInstallation ().
+ This notify function is registered for every architectural protocol. This handler
+ updates mArchProtocol[] array entry with protocol instance data and sets it's
+ present flag to TRUE. If any constructor is required it is executed. The EFI
+ System Table headers are updated.
+
+ @param Event The Event that is being processed, not used.
+ @param Context Event Context, not used.
+
+**/
+VOID
+EFIAPI
+GenericProtocolNotify (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ EFI_STATUS Status;
+ EFI_CORE_PROTOCOL_NOTIFY_ENTRY *Entry;
+ VOID *Protocol;
+ LIST_ENTRY *Link;
+ LIST_ENTRY TempLinkNode;
+
+ Protocol = NULL;
+
+ //
+ // Get Entry from Context
+ //
+ Entry = (EFI_CORE_PROTOCOL_NOTIFY_ENTRY *)Context;
+
+ //
+ // See if the expected protocol is present in the handle database
+ //
+ Status = CoreLocateProtocol (Entry->ProtocolGuid, Entry->Registration, &Protocol);
+ if (EFI_ERROR (Status)) {
+ return;
+ }
+
+ //
+ // Mark the protocol as present
+ //
+ Entry->Present = TRUE;
+
+ //
+ // Update protocol global variable if one exists. Entry->Protocol points to a global variable
+ // if one exists in the DXE core for this Architectural Protocol
+ //
+ if (Entry->Protocol != NULL) {
+ *(Entry->Protocol) = Protocol;
+ }
+
+ //
+ // Do special operations for Architectural Protocols
+ //
+
+ if (CompareGuid (Entry->ProtocolGuid, &gEfiTimerArchProtocolGuid)) {
+ //
+ // Register the Core timer tick handler with the Timer AP
+ //
+ gTimer->RegisterHandler (gTimer, CoreTimerTick);
+ }
+
+ if (CompareGuid (Entry->ProtocolGuid, &gEfiRuntimeArchProtocolGuid)) {
+ //
+ // When runtime architectural protocol is available, updates CRC32 in the Debug Table
+ //
+ CoreUpdateDebugTableCrc32 ();
+
+ //
+ // Update the Runtime Architectural protocol with the template that the core was
+ // using so there would not need to be a dependency on the Runtime AP
+ //
+
+ //
+ // Copy all the registered Image to new gRuntime protocol
+ //
+ for (Link = gRuntimeTemplate.ImageHead.ForwardLink; Link != &gRuntimeTemplate.ImageHead; Link = TempLinkNode.ForwardLink) {
+ CopyMem (&TempLinkNode, Link, sizeof (LIST_ENTRY));
+ InsertTailList (&gRuntime->ImageHead, Link);
+ }
+
+ //
+ // Copy all the registered Event to new gRuntime protocol
+ //
+ for (Link = gRuntimeTemplate.EventHead.ForwardLink; Link != &gRuntimeTemplate.EventHead; Link = TempLinkNode.ForwardLink) {
+ CopyMem (&TempLinkNode, Link, sizeof (LIST_ENTRY));
+ InsertTailList (&gRuntime->EventHead, Link);
+ }
+
+ //
+ // Clean up gRuntimeTemplate
+ //
+ gRuntimeTemplate.ImageHead.ForwardLink = &gRuntimeTemplate.ImageHead;
+ gRuntimeTemplate.ImageHead.BackLink = &gRuntimeTemplate.ImageHead;
+ gRuntimeTemplate.EventHead.ForwardLink = &gRuntimeTemplate.EventHead;
+ gRuntimeTemplate.EventHead.BackLink = &gRuntimeTemplate.EventHead;
+ }
+
+ //
+ // It's over kill to do them all every time, but it saves a lot of code.
+ //
+ CalculateEfiHdrCrc (&gDxeCoreRT->Hdr);
+ CalculateEfiHdrCrc (&gBS->Hdr);
+ CalculateEfiHdrCrc (&gDxeCoreST->Hdr);
+ CalculateEfiHdrCrc (&gDxeCoreDS->Hdr);
+}
+
+/**
+ Creates an event for each entry in a table that is fired everytime a Protocol
+ of a specific type is installed.
+
+ @param Entry Pointer to EFI_CORE_PROTOCOL_NOTIFY_ENTRY.
+
+**/
+VOID
+CoreNotifyOnProtocolEntryTable (
+ EFI_CORE_PROTOCOL_NOTIFY_ENTRY *Entry
+ )
+{
+ EFI_STATUS Status;
+
+ for ( ; Entry->ProtocolGuid != NULL; Entry++) {
+ //
+ // Create the event
+ //
+ Status = CoreCreateEvent (
+ EVT_NOTIFY_SIGNAL,
+ TPL_CALLBACK,
+ GenericProtocolNotify,
+ Entry,
+ &Entry->Event
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Register for protocol notifactions on this event
+ //
+ Status = CoreRegisterProtocolNotify (
+ Entry->ProtocolGuid,
+ Entry->Event,
+ &Entry->Registration
+ );
+ ASSERT_EFI_ERROR (Status);
+ }
+}
+
+/**
+ Creates an events for the Architectural Protocols and the optional protocols
+ that are fired everytime a Protocol of a specific type is installed.
+
+**/
+VOID
+CoreNotifyOnProtocolInstallation (
+ VOID
+ )
+{
+ CoreNotifyOnProtocolEntryTable (mArchProtocols);
+ CoreNotifyOnProtocolEntryTable (mOptionalProtocols);
+}
+
+/**
+ Displays Architectural protocols that were not loaded and are required for DXE
+ core to function. Only used in Debug Builds.
+
+**/
+VOID
+CoreDisplayMissingArchProtocols (
+ VOID
+ )
+{
+ EFI_CORE_PROTOCOL_NOTIFY_ENTRY *Entry;
+ CONST GUID_TO_STRING_PROTOCOL_ENTRY *MissingEntry;
+
+ for (Entry = mArchProtocols; Entry->ProtocolGuid != NULL; Entry++) {
+ if (!Entry->Present) {
+ for (MissingEntry = mMissingProtocols; MissingEntry->ProtocolGuid != NULL; MissingEntry++) {
+ if (CompareGuid (Entry->ProtocolGuid, MissingEntry->ProtocolGuid)) {
+ DEBUG ((DEBUG_ERROR, "\n%a Arch Protocol not present!!\n", MissingEntry->GuidString));
+ break;
+ }
+ }
+ }
+ }
+}
diff --git a/MdeModulePkg/Core/Dxe/Event/Event.c b/MdeModulePkg/Core/Dxe/Event/Event.c
index dc82abb021..21f562ea95 100644
--- a/MdeModulePkg/Core/Dxe/Event/Event.c
+++ b/MdeModulePkg/Core/Dxe/Event/Event.c
@@ -1,760 +1,760 @@
-/** @file
- UEFI Event support functions implemented in this file.
-
-Copyright (c) 2006 - 2017, Intel Corporation. All rights reserved.<BR>
-(C) Copyright 2015 Hewlett Packard Enterprise Development LP<BR>
-SPDX-License-Identifier: BSD-2-Clause-Patent
-
-**/
-
-#include "DxeMain.h"
-#include "Event.h"
-
-///
-/// gEfiCurrentTpl - Current Task priority level
-///
-EFI_TPL gEfiCurrentTpl = TPL_APPLICATION;
-
-///
-/// gEventQueueLock - Protects the event queues
-///
-EFI_LOCK gEventQueueLock = EFI_INITIALIZE_LOCK_VARIABLE (TPL_HIGH_LEVEL);
-
-///
-/// gEventQueue - A list of event's to notify for each priority level
-///
-LIST_ENTRY gEventQueue[TPL_HIGH_LEVEL + 1];
-
-///
-/// gEventPending - A bitmask of the EventQueues that are pending
-///
-UINTN gEventPending = 0;
-
-///
-/// gEventSignalQueue - A list of events to signal based on EventGroup type
-///
-LIST_ENTRY gEventSignalQueue = INITIALIZE_LIST_HEAD_VARIABLE (gEventSignalQueue);
-
-///
-/// Enumerate the valid types
-///
-UINT32 mEventTable[] = {
- ///
- /// 0x80000200 Timer event with a notification function that is
- /// queue when the event is signaled with SignalEvent()
- ///
- EVT_TIMER | EVT_NOTIFY_SIGNAL,
- ///
- /// 0x80000000 Timer event without a notification function. It can be
- /// signaled with SignalEvent() and checked with CheckEvent() or WaitForEvent().
- ///
- EVT_TIMER,
- ///
- /// 0x00000100 Generic event with a notification function that
- /// can be waited on with CheckEvent() or WaitForEvent()
- ///
- EVT_NOTIFY_WAIT,
- ///
- /// 0x00000200 Generic event with a notification function that
- /// is queue when the event is signaled with SignalEvent()
- ///
- EVT_NOTIFY_SIGNAL,
- ///
- /// 0x00000201 ExitBootServicesEvent.
- ///
- EVT_SIGNAL_EXIT_BOOT_SERVICES,
- ///
- /// 0x60000202 SetVirtualAddressMapEvent.
- ///
- EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE,
-
- ///
- /// 0x00000000 Generic event without a notification function.
- /// It can be signaled with SignalEvent() and checked with CheckEvent()
- /// or WaitForEvent().
- ///
- 0x00000000,
- ///
- /// 0x80000100 Timer event with a notification function that can be
- /// waited on with CheckEvent() or WaitForEvent()
- ///
- EVT_TIMER | EVT_NOTIFY_WAIT,
-};
-
-///
-/// gIdleLoopEvent - Event which is signalled when the core is idle
-///
-EFI_EVENT gIdleLoopEvent = NULL;
-
-/**
- Enter critical section by acquiring the lock on gEventQueueLock.
-
-**/
-VOID
-CoreAcquireEventLock (
- VOID
- )
-{
- CoreAcquireLock (&gEventQueueLock);
-}
-
-/**
- Exit critical section by releasing the lock on gEventQueueLock.
-
-**/
-VOID
-CoreReleaseEventLock (
- VOID
- )
-{
- CoreReleaseLock (&gEventQueueLock);
-}
-
-/**
- Initializes "event" support.
-
- @retval EFI_SUCCESS Always return success
-
-**/
-EFI_STATUS
-CoreInitializeEventServices (
- VOID
- )
-{
- UINTN Index;
-
- for (Index = 0; Index <= TPL_HIGH_LEVEL; Index++) {
- InitializeListHead (&gEventQueue[Index]);
- }
-
- CoreInitializeTimer ();
-
- CoreCreateEventEx (
- EVT_NOTIFY_SIGNAL,
- TPL_NOTIFY,
- EfiEventEmptyFunction,
- NULL,
- &gIdleLoopEventGuid,
- &gIdleLoopEvent
- );
-
- return EFI_SUCCESS;
-}
-
-/**
- Dispatches all pending events.
-
- @param Priority The task priority level of event notifications
- to dispatch
-
-**/
-VOID
-CoreDispatchEventNotifies (
- IN EFI_TPL Priority
- )
-{
- IEVENT *Event;
- LIST_ENTRY *Head;
-
- CoreAcquireEventLock ();
- ASSERT (gEventQueueLock.OwnerTpl == Priority);
- Head = &gEventQueue[Priority];
-
- //
- // Dispatch all the pending notifications
- //
- while (!IsListEmpty (Head)) {
- Event = CR (Head->ForwardLink, IEVENT, NotifyLink, EVENT_SIGNATURE);
- RemoveEntryList (&Event->NotifyLink);
-
- Event->NotifyLink.ForwardLink = NULL;
-
- //
- // Only clear the SIGNAL status if it is a SIGNAL type event.
- // WAIT type events are only cleared in CheckEvent()
- //
- if ((Event->Type & EVT_NOTIFY_SIGNAL) != 0) {
- Event->SignalCount = 0;
- }
-
- CoreReleaseEventLock ();
-
- //
- // Notify this event
- //
- ASSERT (Event->NotifyFunction != NULL);
- Event->NotifyFunction (Event, Event->NotifyContext);
-
- //
- // Check for next pending event
- //
- CoreAcquireEventLock ();
- }
-
- gEventPending &= ~(UINTN)(1 << Priority);
- CoreReleaseEventLock ();
-}
-
-/**
- Queues the event's notification function to fire.
-
- @param Event The Event to notify
-
-**/
-VOID
-CoreNotifyEvent (
- IN IEVENT *Event
- )
-{
- //
- // Event database must be locked
- //
- ASSERT_LOCKED (&gEventQueueLock);
-
- //
- // If the event is queued somewhere, remove it
- //
-
- if (Event->NotifyLink.ForwardLink != NULL) {
- RemoveEntryList (&Event->NotifyLink);
- Event->NotifyLink.ForwardLink = NULL;
- }
-
- //
- // Queue the event to the pending notification list
- //
-
- InsertTailList (&gEventQueue[Event->NotifyTpl], &Event->NotifyLink);
- gEventPending |= (UINTN)(1 << Event->NotifyTpl);
-}
-
-/**
- Signals all events in the EventGroup.
-
- @param EventGroup The list to signal
-
-**/
-VOID
-CoreNotifySignalList (
- IN EFI_GUID *EventGroup
- )
-{
- LIST_ENTRY *Link;
- LIST_ENTRY *Head;
- IEVENT *Event;
-
- CoreAcquireEventLock ();
-
- Head = &gEventSignalQueue;
- for (Link = Head->ForwardLink; Link != Head; Link = Link->ForwardLink) {
- Event = CR (Link, IEVENT, SignalLink, EVENT_SIGNATURE);
- if (CompareGuid (&Event->EventGroup, EventGroup)) {
- CoreNotifyEvent (Event);
- }
- }
-
- CoreReleaseEventLock ();
-}
-
-/**
- Creates an event.
-
- @param Type The type of event to create and its mode and
- attributes
- @param NotifyTpl The task priority level of event notifications
- @param NotifyFunction Pointer to the events notification function
- @param NotifyContext Pointer to the notification functions context;
- corresponds to parameter "Context" in the
- notification function
- @param Event Pointer to the newly created event if the call
- succeeds; undefined otherwise
-
- @retval EFI_SUCCESS The event structure was created
- @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value
- @retval EFI_OUT_OF_RESOURCES The event could not be allocated
-
-**/
-EFI_STATUS
-EFIAPI
-CoreCreateEvent (
- IN UINT32 Type,
- IN EFI_TPL NotifyTpl,
- IN EFI_EVENT_NOTIFY NotifyFunction OPTIONAL,
- IN VOID *NotifyContext OPTIONAL,
- OUT EFI_EVENT *Event
- )
-{
- return CoreCreateEventEx (Type, NotifyTpl, NotifyFunction, NotifyContext, NULL, Event);
-}
-
-/**
- Creates an event in a group.
-
- @param Type The type of event to create and its mode and
- attributes
- @param NotifyTpl The task priority level of event notifications
- @param NotifyFunction Pointer to the events notification function
- @param NotifyContext Pointer to the notification functions context;
- corresponds to parameter "Context" in the
- notification function
- @param EventGroup GUID for EventGroup if NULL act the same as
- gBS->CreateEvent().
- @param Event Pointer to the newly created event if the call
- succeeds; undefined otherwise
-
- @retval EFI_SUCCESS The event structure was created
- @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value
- @retval EFI_OUT_OF_RESOURCES The event could not be allocated
-
-**/
-EFI_STATUS
-EFIAPI
-CoreCreateEventEx (
- IN UINT32 Type,
- IN EFI_TPL NotifyTpl,
- IN EFI_EVENT_NOTIFY NotifyFunction OPTIONAL,
- IN CONST VOID *NotifyContext OPTIONAL,
- IN CONST EFI_GUID *EventGroup OPTIONAL,
- OUT EFI_EVENT *Event
- )
-{
- //
- // If it's a notify type of event, check for invalid NotifyTpl
- //
- if ((Type & (EVT_NOTIFY_WAIT | EVT_NOTIFY_SIGNAL)) != 0) {
- if ((NotifyTpl != TPL_APPLICATION) &&
- (NotifyTpl != TPL_CALLBACK) &&
- (NotifyTpl != TPL_NOTIFY))
- {
- return EFI_INVALID_PARAMETER;
- }
- }
-
- return CoreCreateEventInternal (Type, NotifyTpl, NotifyFunction, NotifyContext, EventGroup, Event);
-}
-
-/**
- Creates a general-purpose event structure
-
- @param Type The type of event to create and its mode and
- attributes
- @param NotifyTpl The task priority level of event notifications
- @param NotifyFunction Pointer to the events notification function
- @param NotifyContext Pointer to the notification functions context;
- corresponds to parameter "Context" in the
- notification function
- @param EventGroup GUID for EventGroup if NULL act the same as
- gBS->CreateEvent().
- @param Event Pointer to the newly created event if the call
- succeeds; undefined otherwise
-
- @retval EFI_SUCCESS The event structure was created
- @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value
- @retval EFI_OUT_OF_RESOURCES The event could not be allocated
-
-**/
-EFI_STATUS
-EFIAPI
-CoreCreateEventInternal (
- IN UINT32 Type,
- IN EFI_TPL NotifyTpl,
- IN EFI_EVENT_NOTIFY NotifyFunction OPTIONAL,
- IN CONST VOID *NotifyContext OPTIONAL,
- IN CONST EFI_GUID *EventGroup OPTIONAL,
- OUT EFI_EVENT *Event
- )
-{
- EFI_STATUS Status;
- IEVENT *IEvent;
- INTN Index;
-
- if (Event == NULL) {
- return EFI_INVALID_PARAMETER;
- }
-
- //
- // Check to make sure no reserved flags are set
- //
- Status = EFI_INVALID_PARAMETER;
- for (Index = 0; Index < (sizeof (mEventTable) / sizeof (UINT32)); Index++) {
- if (Type == mEventTable[Index]) {
- Status = EFI_SUCCESS;
- break;
- }
- }
-
- if (EFI_ERROR (Status)) {
- return EFI_INVALID_PARAMETER;
- }
-
- //
- // Convert Event type for pre-defined Event groups
- //
- if (EventGroup != NULL) {
- //
- // For event group, type EVT_SIGNAL_EXIT_BOOT_SERVICES and EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE
- // are not valid
- //
- if ((Type == EVT_SIGNAL_EXIT_BOOT_SERVICES) || (Type == EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE)) {
- return EFI_INVALID_PARAMETER;
- }
-
- if (CompareGuid (EventGroup, &gEfiEventExitBootServicesGuid)) {
- Type = EVT_SIGNAL_EXIT_BOOT_SERVICES;
- } else if (CompareGuid (EventGroup, &gEfiEventVirtualAddressChangeGuid)) {
- Type = EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE;
- }
- } else {
- //
- // Convert EFI 1.10 Events to their UEFI 2.0 CreateEventEx mapping
- //
- if (Type == EVT_SIGNAL_EXIT_BOOT_SERVICES) {
- EventGroup = &gEfiEventExitBootServicesGuid;
- } else if (Type == EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE) {
- EventGroup = &gEfiEventVirtualAddressChangeGuid;
- }
- }
-
- //
- // If it's a notify type of event, check its parameters
- //
- if ((Type & (EVT_NOTIFY_WAIT | EVT_NOTIFY_SIGNAL)) != 0) {
- //
- // Check for an invalid NotifyFunction or NotifyTpl
- //
- if ((NotifyFunction == NULL) ||
- (NotifyTpl <= TPL_APPLICATION) ||
- (NotifyTpl >= TPL_HIGH_LEVEL))
- {
- return EFI_INVALID_PARAMETER;
- }
- } else {
- //
- // No notification needed, zero ignored values
- //
- NotifyTpl = 0;
- NotifyFunction = NULL;
- NotifyContext = NULL;
- }
-
- //
- // Allocate and initialize a new event structure.
- //
- if ((Type & EVT_RUNTIME) != 0) {
- IEvent = AllocateRuntimeZeroPool (sizeof (IEVENT));
- } else {
- IEvent = AllocateZeroPool (sizeof (IEVENT));
- }
-
- if (IEvent == NULL) {
- return EFI_OUT_OF_RESOURCES;
- }
-
- IEvent->Signature = EVENT_SIGNATURE;
- IEvent->Type = Type;
-
- IEvent->NotifyTpl = NotifyTpl;
- IEvent->NotifyFunction = NotifyFunction;
- IEvent->NotifyContext = (VOID *)NotifyContext;
- if (EventGroup != NULL) {
- CopyGuid (&IEvent->EventGroup, EventGroup);
- IEvent->ExFlag |= EVT_EXFLAG_EVENT_GROUP;
- }
-
- *Event = IEvent;
-
- if ((Type & EVT_RUNTIME) != 0) {
- //
- // Keep a list of all RT events so we can tell the RT AP.
- //
- IEvent->RuntimeData.Type = Type;
- IEvent->RuntimeData.NotifyTpl = NotifyTpl;
- IEvent->RuntimeData.NotifyFunction = NotifyFunction;
- IEvent->RuntimeData.NotifyContext = (VOID *)NotifyContext;
- //
- // Work around the bug in the Platform Init specification (v1.7), reported
- // as Mantis#2017: "EFI_RUNTIME_EVENT_ENTRY.Event" should have type
- // EFI_EVENT, not (EFI_EVENT*). The PI spec documents the field correctly
- // as "The EFI_EVENT returned by CreateEvent()", but the type of the field
- // doesn't match the natural language description. Therefore we need an
- // explicit cast here.
- //
- IEvent->RuntimeData.Event = (EFI_EVENT *)IEvent;
- InsertTailList (&gRuntime->EventHead, &IEvent->RuntimeData.Link);
- }
-
- CoreAcquireEventLock ();
-
- if ((Type & EVT_NOTIFY_SIGNAL) != 0x00000000) {
- //
- // The Event's NotifyFunction must be queued whenever the event is signaled
- //
- InsertHeadList (&gEventSignalQueue, &IEvent->SignalLink);
- }
-
- CoreReleaseEventLock ();
-
- //
- // Done
- //
- return EFI_SUCCESS;
-}
-
-/**
- Signals the event. Queues the event to be notified if needed.
-
- @param UserEvent The event to signal .
-
- @retval EFI_INVALID_PARAMETER Parameters are not valid.
- @retval EFI_SUCCESS The event was signaled.
-
-**/
-EFI_STATUS
-EFIAPI
-CoreSignalEvent (
- IN EFI_EVENT UserEvent
- )
-{
- IEVENT *Event;
-
- Event = UserEvent;
-
- if (Event == NULL) {
- return EFI_INVALID_PARAMETER;
- }
-
- if (Event->Signature != EVENT_SIGNATURE) {
- return EFI_INVALID_PARAMETER;
- }
-
- CoreAcquireEventLock ();
-
- //
- // If the event is not already signalled, do so
- //
-
- if (Event->SignalCount == 0x00000000) {
- Event->SignalCount++;
-
- //
- // If signalling type is a notify function, queue it
- //
- if ((Event->Type & EVT_NOTIFY_SIGNAL) != 0) {
- if ((Event->ExFlag & EVT_EXFLAG_EVENT_GROUP) != 0) {
- //
- // The CreateEventEx() style requires all members of the Event Group
- // to be signaled.
- //
- CoreReleaseEventLock ();
- CoreNotifySignalList (&Event->EventGroup);
- CoreAcquireEventLock ();
- } else {
- CoreNotifyEvent (Event);
- }
- }
- }
-
- CoreReleaseEventLock ();
- return EFI_SUCCESS;
-}
-
-/**
- Check the status of an event.
-
- @param UserEvent The event to check
-
- @retval EFI_SUCCESS The event is in the signaled state
- @retval EFI_NOT_READY The event is not in the signaled state
- @retval EFI_INVALID_PARAMETER Event is of type EVT_NOTIFY_SIGNAL
-
-**/
-EFI_STATUS
-EFIAPI
-CoreCheckEvent (
- IN EFI_EVENT UserEvent
- )
-{
- IEVENT *Event;
- EFI_STATUS Status;
-
- Event = UserEvent;
-
- if (Event == NULL) {
- return EFI_INVALID_PARAMETER;
- }
-
- if (Event->Signature != EVENT_SIGNATURE) {
- return EFI_INVALID_PARAMETER;
- }
-
- if ((Event->Type & EVT_NOTIFY_SIGNAL) != 0) {
- return EFI_INVALID_PARAMETER;
- }
-
- Status = EFI_NOT_READY;
-
- if ((Event->SignalCount == 0) && ((Event->Type & EVT_NOTIFY_WAIT) != 0)) {
- //
- // Queue the wait notify function
- //
- CoreAcquireEventLock ();
- if (Event->SignalCount == 0) {
- CoreNotifyEvent (Event);
- }
-
- CoreReleaseEventLock ();
- }
-
- //
- // If the even looks signalled, get the lock and clear it
- //
-
- if (Event->SignalCount != 0) {
- CoreAcquireEventLock ();
-
- if (Event->SignalCount != 0) {
- Event->SignalCount = 0;
- Status = EFI_SUCCESS;
- }
-
- CoreReleaseEventLock ();
- }
-
- return Status;
-}
-
-/**
- Stops execution until an event is signaled.
-
- @param NumberOfEvents The number of events in the UserEvents array
- @param UserEvents An array of EFI_EVENT
- @param UserIndex Pointer to the index of the event which
- satisfied the wait condition
-
- @retval EFI_SUCCESS The event indicated by Index was signaled.
- @retval EFI_INVALID_PARAMETER The event indicated by Index has a notification
- function or Event was not a valid type
- @retval EFI_UNSUPPORTED The current TPL is not TPL_APPLICATION
-
-**/
-EFI_STATUS
-EFIAPI
-CoreWaitForEvent (
- IN UINTN NumberOfEvents,
- IN EFI_EVENT *UserEvents,
- OUT UINTN *UserIndex
- )
-{
- EFI_STATUS Status;
- UINTN Index;
-
- //
- // Can only WaitForEvent at TPL_APPLICATION
- //
- if (gEfiCurrentTpl != TPL_APPLICATION) {
- return EFI_UNSUPPORTED;
- }
-
- if (NumberOfEvents == 0) {
- return EFI_INVALID_PARAMETER;
- }
-
- if (UserEvents == NULL) {
- return EFI_INVALID_PARAMETER;
- }
-
- for ( ; ;) {
- for (Index = 0; Index < NumberOfEvents; Index++) {
- Status = CoreCheckEvent (UserEvents[Index]);
-
- //
- // provide index of event that caused problem
- //
- if (Status != EFI_NOT_READY) {
- if (UserIndex != NULL) {
- *UserIndex = Index;
- }
-
- return Status;
- }
- }
-
- //
- // Signal the Idle event
- //
- CoreSignalEvent (gIdleLoopEvent);
- }
-}
-
-/**
- Closes an event and frees the event structure.
-
- @param UserEvent Event to close
-
- @retval EFI_INVALID_PARAMETER Parameters are not valid.
- @retval EFI_SUCCESS The event has been closed
-
-**/
-EFI_STATUS
-EFIAPI
-CoreCloseEvent (
- IN EFI_EVENT UserEvent
- )
-{
- EFI_STATUS Status;
- IEVENT *Event;
-
- Event = UserEvent;
-
- if (Event == NULL) {
- return EFI_INVALID_PARAMETER;
- }
-
- if (Event->Signature != EVENT_SIGNATURE) {
- return EFI_INVALID_PARAMETER;
- }
-
- //
- // If it's a timer event, make sure it's not pending
- //
- if ((Event->Type & EVT_TIMER) != 0) {
- CoreSetTimer (Event, TimerCancel, 0);
- }
-
- CoreAcquireEventLock ();
-
- //
- // If the event is queued somewhere, remove it
- //
-
- if (Event->RuntimeData.Link.ForwardLink != NULL) {
- RemoveEntryList (&Event->RuntimeData.Link);
- }
-
- if (Event->NotifyLink.ForwardLink != NULL) {
- RemoveEntryList (&Event->NotifyLink);
- }
-
- if (Event->SignalLink.ForwardLink != NULL) {
- RemoveEntryList (&Event->SignalLink);
- }
-
- CoreReleaseEventLock ();
-
- //
- // If the event is registered on a protocol notify, then remove it from the protocol database
- //
- if ((Event->ExFlag & EVT_EXFLAG_EVENT_PROTOCOL_NOTIFICATION) != 0) {
- CoreUnregisterProtocolNotify (Event);
- }
-
- //
- // To avoid the Event to be signalled wrongly after closed,
- // clear the Signature of Event before free pool.
- //
- Event->Signature = 0;
- Status = CoreFreePool (Event);
- ASSERT_EFI_ERROR (Status);
-
- return Status;
-}
+/** @file
+ UEFI Event support functions implemented in this file.
+
+Copyright (c) 2006 - 2017, Intel Corporation. All rights reserved.<BR>
+(C) Copyright 2015 Hewlett Packard Enterprise Development LP<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "DxeMain.h"
+#include "Event.h"
+
+///
+/// gEfiCurrentTpl - Current Task priority level
+///
+EFI_TPL gEfiCurrentTpl = TPL_APPLICATION;
+
+///
+/// gEventQueueLock - Protects the event queues
+///
+EFI_LOCK gEventQueueLock = EFI_INITIALIZE_LOCK_VARIABLE (TPL_HIGH_LEVEL);
+
+///
+/// gEventQueue - A list of event's to notify for each priority level
+///
+LIST_ENTRY gEventQueue[TPL_HIGH_LEVEL + 1];
+
+///
+/// gEventPending - A bitmask of the EventQueues that are pending
+///
+UINTN gEventPending = 0;
+
+///
+/// gEventSignalQueue - A list of events to signal based on EventGroup type
+///
+LIST_ENTRY gEventSignalQueue = INITIALIZE_LIST_HEAD_VARIABLE (gEventSignalQueue);
+
+///
+/// Enumerate the valid types
+///
+UINT32 mEventTable[] = {
+ ///
+ /// 0x80000200 Timer event with a notification function that is
+ /// queue when the event is signaled with SignalEvent()
+ ///
+ EVT_TIMER | EVT_NOTIFY_SIGNAL,
+ ///
+ /// 0x80000000 Timer event without a notification function. It can be
+ /// signaled with SignalEvent() and checked with CheckEvent() or WaitForEvent().
+ ///
+ EVT_TIMER,
+ ///
+ /// 0x00000100 Generic event with a notification function that
+ /// can be waited on with CheckEvent() or WaitForEvent()
+ ///
+ EVT_NOTIFY_WAIT,
+ ///
+ /// 0x00000200 Generic event with a notification function that
+ /// is queue when the event is signaled with SignalEvent()
+ ///
+ EVT_NOTIFY_SIGNAL,
+ ///
+ /// 0x00000201 ExitBootServicesEvent.
+ ///
+ EVT_SIGNAL_EXIT_BOOT_SERVICES,
+ ///
+ /// 0x60000202 SetVirtualAddressMapEvent.
+ ///
+ EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE,
+
+ ///
+ /// 0x00000000 Generic event without a notification function.
+ /// It can be signaled with SignalEvent() and checked with CheckEvent()
+ /// or WaitForEvent().
+ ///
+ 0x00000000,
+ ///
+ /// 0x80000100 Timer event with a notification function that can be
+ /// waited on with CheckEvent() or WaitForEvent()
+ ///
+ EVT_TIMER | EVT_NOTIFY_WAIT,
+};
+
+///
+/// gIdleLoopEvent - Event which is signalled when the core is idle
+///
+EFI_EVENT gIdleLoopEvent = NULL;
+
+/**
+ Enter critical section by acquiring the lock on gEventQueueLock.
+
+**/
+VOID
+CoreAcquireEventLock (
+ VOID
+ )
+{
+ CoreAcquireLock (&gEventQueueLock);
+}
+
+/**
+ Exit critical section by releasing the lock on gEventQueueLock.
+
+**/
+VOID
+CoreReleaseEventLock (
+ VOID
+ )
+{
+ CoreReleaseLock (&gEventQueueLock);
+}
+
+/**
+ Initializes "event" support.
+
+ @retval EFI_SUCCESS Always return success
+
+**/
+EFI_STATUS
+CoreInitializeEventServices (
+ VOID
+ )
+{
+ UINTN Index;
+
+ for (Index = 0; Index <= TPL_HIGH_LEVEL; Index++) {
+ InitializeListHead (&gEventQueue[Index]);
+ }
+
+ CoreInitializeTimer ();
+
+ CoreCreateEventEx (
+ EVT_NOTIFY_SIGNAL,
+ TPL_NOTIFY,
+ EfiEventEmptyFunction,
+ NULL,
+ &gIdleLoopEventGuid,
+ &gIdleLoopEvent
+ );
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Dispatches all pending events.
+
+ @param Priority The task priority level of event notifications
+ to dispatch
+
+**/
+VOID
+CoreDispatchEventNotifies (
+ IN EFI_TPL Priority
+ )
+{
+ IEVENT *Event;
+ LIST_ENTRY *Head;
+
+ CoreAcquireEventLock ();
+ ASSERT (gEventQueueLock.OwnerTpl == Priority);
+ Head = &gEventQueue[Priority];
+
+ //
+ // Dispatch all the pending notifications
+ //
+ while (!IsListEmpty (Head)) {
+ Event = CR (Head->ForwardLink, IEVENT, NotifyLink, EVENT_SIGNATURE);
+ RemoveEntryList (&Event->NotifyLink);
+
+ Event->NotifyLink.ForwardLink = NULL;
+
+ //
+ // Only clear the SIGNAL status if it is a SIGNAL type event.
+ // WAIT type events are only cleared in CheckEvent()
+ //
+ if ((Event->Type & EVT_NOTIFY_SIGNAL) != 0) {
+ Event->SignalCount = 0;
+ }
+
+ CoreReleaseEventLock ();
+
+ //
+ // Notify this event
+ //
+ ASSERT (Event->NotifyFunction != NULL);
+ Event->NotifyFunction (Event, Event->NotifyContext);
+
+ //
+ // Check for next pending event
+ //
+ CoreAcquireEventLock ();
+ }
+
+ gEventPending &= ~(UINTN)(1 << Priority);
+ CoreReleaseEventLock ();
+}
+
+/**
+ Queues the event's notification function to fire.
+
+ @param Event The Event to notify
+
+**/
+VOID
+CoreNotifyEvent (
+ IN IEVENT *Event
+ )
+{
+ //
+ // Event database must be locked
+ //
+ ASSERT_LOCKED (&gEventQueueLock);
+
+ //
+ // If the event is queued somewhere, remove it
+ //
+
+ if (Event->NotifyLink.ForwardLink != NULL) {
+ RemoveEntryList (&Event->NotifyLink);
+ Event->NotifyLink.ForwardLink = NULL;
+ }
+
+ //
+ // Queue the event to the pending notification list
+ //
+
+ InsertTailList (&gEventQueue[Event->NotifyTpl], &Event->NotifyLink);
+ gEventPending |= (UINTN)(1 << Event->NotifyTpl);
+}
+
+/**
+ Signals all events in the EventGroup.
+
+ @param EventGroup The list to signal
+
+**/
+VOID
+CoreNotifySignalList (
+ IN EFI_GUID *EventGroup
+ )
+{
+ LIST_ENTRY *Link;
+ LIST_ENTRY *Head;
+ IEVENT *Event;
+
+ CoreAcquireEventLock ();
+
+ Head = &gEventSignalQueue;
+ for (Link = Head->ForwardLink; Link != Head; Link = Link->ForwardLink) {
+ Event = CR (Link, IEVENT, SignalLink, EVENT_SIGNATURE);
+ if (CompareGuid (&Event->EventGroup, EventGroup)) {
+ CoreNotifyEvent (Event);
+ }
+ }
+
+ CoreReleaseEventLock ();
+}
+
+/**
+ Creates an event.
+
+ @param Type The type of event to create and its mode and
+ attributes
+ @param NotifyTpl The task priority level of event notifications
+ @param NotifyFunction Pointer to the events notification function
+ @param NotifyContext Pointer to the notification functions context;
+ corresponds to parameter "Context" in the
+ notification function
+ @param Event Pointer to the newly created event if the call
+ succeeds; undefined otherwise
+
+ @retval EFI_SUCCESS The event structure was created
+ @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value
+ @retval EFI_OUT_OF_RESOURCES The event could not be allocated
+
+**/
+EFI_STATUS
+EFIAPI
+CoreCreateEvent (
+ IN UINT32 Type,
+ IN EFI_TPL NotifyTpl,
+ IN EFI_EVENT_NOTIFY NotifyFunction OPTIONAL,
+ IN VOID *NotifyContext OPTIONAL,
+ OUT EFI_EVENT *Event
+ )
+{
+ return CoreCreateEventEx (Type, NotifyTpl, NotifyFunction, NotifyContext, NULL, Event);
+}
+
+/**
+ Creates an event in a group.
+
+ @param Type The type of event to create and its mode and
+ attributes
+ @param NotifyTpl The task priority level of event notifications
+ @param NotifyFunction Pointer to the events notification function
+ @param NotifyContext Pointer to the notification functions context;
+ corresponds to parameter "Context" in the
+ notification function
+ @param EventGroup GUID for EventGroup if NULL act the same as
+ gBS->CreateEvent().
+ @param Event Pointer to the newly created event if the call
+ succeeds; undefined otherwise
+
+ @retval EFI_SUCCESS The event structure was created
+ @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value
+ @retval EFI_OUT_OF_RESOURCES The event could not be allocated
+
+**/
+EFI_STATUS
+EFIAPI
+CoreCreateEventEx (
+ IN UINT32 Type,
+ IN EFI_TPL NotifyTpl,
+ IN EFI_EVENT_NOTIFY NotifyFunction OPTIONAL,
+ IN CONST VOID *NotifyContext OPTIONAL,
+ IN CONST EFI_GUID *EventGroup OPTIONAL,
+ OUT EFI_EVENT *Event
+ )
+{
+ //
+ // If it's a notify type of event, check for invalid NotifyTpl
+ //
+ if ((Type & (EVT_NOTIFY_WAIT | EVT_NOTIFY_SIGNAL)) != 0) {
+ if ((NotifyTpl != TPL_APPLICATION) &&
+ (NotifyTpl != TPL_CALLBACK) &&
+ (NotifyTpl != TPL_NOTIFY))
+ {
+ return EFI_INVALID_PARAMETER;
+ }
+ }
+
+ return CoreCreateEventInternal (Type, NotifyTpl, NotifyFunction, NotifyContext, EventGroup, Event);
+}
+
+/**
+ Creates a general-purpose event structure
+
+ @param Type The type of event to create and its mode and
+ attributes
+ @param NotifyTpl The task priority level of event notifications
+ @param NotifyFunction Pointer to the events notification function
+ @param NotifyContext Pointer to the notification functions context;
+ corresponds to parameter "Context" in the
+ notification function
+ @param EventGroup GUID for EventGroup if NULL act the same as
+ gBS->CreateEvent().
+ @param Event Pointer to the newly created event if the call
+ succeeds; undefined otherwise
+
+ @retval EFI_SUCCESS The event structure was created
+ @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value
+ @retval EFI_OUT_OF_RESOURCES The event could not be allocated
+
+**/
+EFI_STATUS
+EFIAPI
+CoreCreateEventInternal (
+ IN UINT32 Type,
+ IN EFI_TPL NotifyTpl,
+ IN EFI_EVENT_NOTIFY NotifyFunction OPTIONAL,
+ IN CONST VOID *NotifyContext OPTIONAL,
+ IN CONST EFI_GUID *EventGroup OPTIONAL,
+ OUT EFI_EVENT *Event
+ )
+{
+ EFI_STATUS Status;
+ IEVENT *IEvent;
+ INTN Index;
+
+ if (Event == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Check to make sure no reserved flags are set
+ //
+ Status = EFI_INVALID_PARAMETER;
+ for (Index = 0; Index < (sizeof (mEventTable) / sizeof (UINT32)); Index++) {
+ if (Type == mEventTable[Index]) {
+ Status = EFI_SUCCESS;
+ break;
+ }
+ }
+
+ if (EFI_ERROR (Status)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Convert Event type for pre-defined Event groups
+ //
+ if (EventGroup != NULL) {
+ //
+ // For event group, type EVT_SIGNAL_EXIT_BOOT_SERVICES and EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE
+ // are not valid
+ //
+ if ((Type == EVT_SIGNAL_EXIT_BOOT_SERVICES) || (Type == EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (CompareGuid (EventGroup, &gEfiEventExitBootServicesGuid)) {
+ Type = EVT_SIGNAL_EXIT_BOOT_SERVICES;
+ } else if (CompareGuid (EventGroup, &gEfiEventVirtualAddressChangeGuid)) {
+ Type = EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE;
+ }
+ } else {
+ //
+ // Convert EFI 1.10 Events to their UEFI 2.0 CreateEventEx mapping
+ //
+ if (Type == EVT_SIGNAL_EXIT_BOOT_SERVICES) {
+ EventGroup = &gEfiEventExitBootServicesGuid;
+ } else if (Type == EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE) {
+ EventGroup = &gEfiEventVirtualAddressChangeGuid;
+ }
+ }
+
+ //
+ // If it's a notify type of event, check its parameters
+ //
+ if ((Type & (EVT_NOTIFY_WAIT | EVT_NOTIFY_SIGNAL)) != 0) {
+ //
+ // Check for an invalid NotifyFunction or NotifyTpl
+ //
+ if ((NotifyFunction == NULL) ||
+ (NotifyTpl <= TPL_APPLICATION) ||
+ (NotifyTpl >= TPL_HIGH_LEVEL))
+ {
+ return EFI_INVALID_PARAMETER;
+ }
+ } else {
+ //
+ // No notification needed, zero ignored values
+ //
+ NotifyTpl = 0;
+ NotifyFunction = NULL;
+ NotifyContext = NULL;
+ }
+
+ //
+ // Allocate and initialize a new event structure.
+ //
+ if ((Type & EVT_RUNTIME) != 0) {
+ IEvent = AllocateRuntimeZeroPool (sizeof (IEVENT));
+ } else {
+ IEvent = AllocateZeroPool (sizeof (IEVENT));
+ }
+
+ if (IEvent == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ IEvent->Signature = EVENT_SIGNATURE;
+ IEvent->Type = Type;
+
+ IEvent->NotifyTpl = NotifyTpl;
+ IEvent->NotifyFunction = NotifyFunction;
+ IEvent->NotifyContext = (VOID *)NotifyContext;
+ if (EventGroup != NULL) {
+ CopyGuid (&IEvent->EventGroup, EventGroup);
+ IEvent->ExFlag |= EVT_EXFLAG_EVENT_GROUP;
+ }
+
+ *Event = IEvent;
+
+ if ((Type & EVT_RUNTIME) != 0) {
+ //
+ // Keep a list of all RT events so we can tell the RT AP.
+ //
+ IEvent->RuntimeData.Type = Type;
+ IEvent->RuntimeData.NotifyTpl = NotifyTpl;
+ IEvent->RuntimeData.NotifyFunction = NotifyFunction;
+ IEvent->RuntimeData.NotifyContext = (VOID *)NotifyContext;
+ //
+ // Work around the bug in the Platform Init specification (v1.7), reported
+ // as Mantis#2017: "EFI_RUNTIME_EVENT_ENTRY.Event" should have type
+ // EFI_EVENT, not (EFI_EVENT*). The PI spec documents the field correctly
+ // as "The EFI_EVENT returned by CreateEvent()", but the type of the field
+ // doesn't match the natural language description. Therefore we need an
+ // explicit cast here.
+ //
+ IEvent->RuntimeData.Event = (EFI_EVENT *)IEvent;
+ InsertTailList (&gRuntime->EventHead, &IEvent->RuntimeData.Link);
+ }
+
+ CoreAcquireEventLock ();
+
+ if ((Type & EVT_NOTIFY_SIGNAL) != 0x00000000) {
+ //
+ // The Event's NotifyFunction must be queued whenever the event is signaled
+ //
+ InsertHeadList (&gEventSignalQueue, &IEvent->SignalLink);
+ }
+
+ CoreReleaseEventLock ();
+
+ //
+ // Done
+ //
+ return EFI_SUCCESS;
+}
+
+/**
+ Signals the event. Queues the event to be notified if needed.
+
+ @param UserEvent The event to signal .
+
+ @retval EFI_INVALID_PARAMETER Parameters are not valid.
+ @retval EFI_SUCCESS The event was signaled.
+
+**/
+EFI_STATUS
+EFIAPI
+CoreSignalEvent (
+ IN EFI_EVENT UserEvent
+ )
+{
+ IEVENT *Event;
+
+ Event = UserEvent;
+
+ if (Event == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (Event->Signature != EVENT_SIGNATURE) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ CoreAcquireEventLock ();
+
+ //
+ // If the event is not already signalled, do so
+ //
+
+ if (Event->SignalCount == 0x00000000) {
+ Event->SignalCount++;
+
+ //
+ // If signalling type is a notify function, queue it
+ //
+ if ((Event->Type & EVT_NOTIFY_SIGNAL) != 0) {
+ if ((Event->ExFlag & EVT_EXFLAG_EVENT_GROUP) != 0) {
+ //
+ // The CreateEventEx() style requires all members of the Event Group
+ // to be signaled.
+ //
+ CoreReleaseEventLock ();
+ CoreNotifySignalList (&Event->EventGroup);
+ CoreAcquireEventLock ();
+ } else {
+ CoreNotifyEvent (Event);
+ }
+ }
+ }
+
+ CoreReleaseEventLock ();
+ return EFI_SUCCESS;
+}
+
+/**
+ Check the status of an event.
+
+ @param UserEvent The event to check
+
+ @retval EFI_SUCCESS The event is in the signaled state
+ @retval EFI_NOT_READY The event is not in the signaled state
+ @retval EFI_INVALID_PARAMETER Event is of type EVT_NOTIFY_SIGNAL
+
+**/
+EFI_STATUS
+EFIAPI
+CoreCheckEvent (
+ IN EFI_EVENT UserEvent
+ )
+{
+ IEVENT *Event;
+ EFI_STATUS Status;
+
+ Event = UserEvent;
+
+ if (Event == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (Event->Signature != EVENT_SIGNATURE) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if ((Event->Type & EVT_NOTIFY_SIGNAL) != 0) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Status = EFI_NOT_READY;
+
+ if ((Event->SignalCount == 0) && ((Event->Type & EVT_NOTIFY_WAIT) != 0)) {
+ //
+ // Queue the wait notify function
+ //
+ CoreAcquireEventLock ();
+ if (Event->SignalCount == 0) {
+ CoreNotifyEvent (Event);
+ }
+
+ CoreReleaseEventLock ();
+ }
+
+ //
+ // If the even looks signalled, get the lock and clear it
+ //
+
+ if (Event->SignalCount != 0) {
+ CoreAcquireEventLock ();
+
+ if (Event->SignalCount != 0) {
+ Event->SignalCount = 0;
+ Status = EFI_SUCCESS;
+ }
+
+ CoreReleaseEventLock ();
+ }
+
+ return Status;
+}
+
+/**
+ Stops execution until an event is signaled.
+
+ @param NumberOfEvents The number of events in the UserEvents array
+ @param UserEvents An array of EFI_EVENT
+ @param UserIndex Pointer to the index of the event which
+ satisfied the wait condition
+
+ @retval EFI_SUCCESS The event indicated by Index was signaled.
+ @retval EFI_INVALID_PARAMETER The event indicated by Index has a notification
+ function or Event was not a valid type
+ @retval EFI_UNSUPPORTED The current TPL is not TPL_APPLICATION
+
+**/
+EFI_STATUS
+EFIAPI
+CoreWaitForEvent (
+ IN UINTN NumberOfEvents,
+ IN EFI_EVENT *UserEvents,
+ OUT UINTN *UserIndex
+ )
+{
+ EFI_STATUS Status;
+ UINTN Index;
+
+ //
+ // Can only WaitForEvent at TPL_APPLICATION
+ //
+ if (gEfiCurrentTpl != TPL_APPLICATION) {
+ return EFI_UNSUPPORTED;
+ }
+
+ if (NumberOfEvents == 0) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (UserEvents == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ for ( ; ;) {
+ for (Index = 0; Index < NumberOfEvents; Index++) {
+ Status = CoreCheckEvent (UserEvents[Index]);
+
+ //
+ // provide index of event that caused problem
+ //
+ if (Status != EFI_NOT_READY) {
+ if (UserIndex != NULL) {
+ *UserIndex = Index;
+ }
+
+ return Status;
+ }
+ }
+
+ //
+ // Signal the Idle event
+ //
+ CoreSignalEvent (gIdleLoopEvent);
+ }
+}
+
+/**
+ Closes an event and frees the event structure.
+
+ @param UserEvent Event to close
+
+ @retval EFI_INVALID_PARAMETER Parameters are not valid.
+ @retval EFI_SUCCESS The event has been closed
+
+**/
+EFI_STATUS
+EFIAPI
+CoreCloseEvent (
+ IN EFI_EVENT UserEvent
+ )
+{
+ EFI_STATUS Status;
+ IEVENT *Event;
+
+ Event = UserEvent;
+
+ if (Event == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (Event->Signature != EVENT_SIGNATURE) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // If it's a timer event, make sure it's not pending
+ //
+ if ((Event->Type & EVT_TIMER) != 0) {
+ CoreSetTimer (Event, TimerCancel, 0);
+ }
+
+ CoreAcquireEventLock ();
+
+ //
+ // If the event is queued somewhere, remove it
+ //
+
+ if (Event->RuntimeData.Link.ForwardLink != NULL) {
+ RemoveEntryList (&Event->RuntimeData.Link);
+ }
+
+ if (Event->NotifyLink.ForwardLink != NULL) {
+ RemoveEntryList (&Event->NotifyLink);
+ }
+
+ if (Event->SignalLink.ForwardLink != NULL) {
+ RemoveEntryList (&Event->SignalLink);
+ }
+
+ CoreReleaseEventLock ();
+
+ //
+ // If the event is registered on a protocol notify, then remove it from the protocol database
+ //
+ if ((Event->ExFlag & EVT_EXFLAG_EVENT_PROTOCOL_NOTIFICATION) != 0) {
+ CoreUnregisterProtocolNotify (Event);
+ }
+
+ //
+ // To avoid the Event to be signalled wrongly after closed,
+ // clear the Signature of Event before free pool.
+ //
+ Event->Signature = 0;
+ Status = CoreFreePool (Event);
+ ASSERT_EFI_ERROR (Status);
+
+ return Status;
+}
diff --git a/MdeModulePkg/Core/Dxe/Event/Event.h b/MdeModulePkg/Core/Dxe/Event/Event.h
index 201b90b301..3c80149f68 100644
--- a/MdeModulePkg/Core/Dxe/Event/Event.h
+++ b/MdeModulePkg/Core/Dxe/Event/Event.h
@@ -1,88 +1,88 @@
-/** @file
- UEFI Event support functions and structure.
-
-Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.<BR>
-(C) Copyright 2015 Hewlett Packard Enterprise Development LP<BR>
-SPDX-License-Identifier: BSD-2-Clause-Patent
-
-**/
-
-#ifndef __EVENT_H__
-#define __EVENT_H__
-
-#define VALID_TPL(a) ((a) <= TPL_HIGH_LEVEL)
-extern UINTN gEventPending;
-
-///
-/// Set if Event is part of an event group
-///
-#define EVT_EXFLAG_EVENT_GROUP 0x01
-///
-/// Set if Event is registered on a protocol notify
-///
-#define EVT_EXFLAG_EVENT_PROTOCOL_NOTIFICATION 0x02
-
-//
-// EFI_EVENT
-//
-
-///
-/// Timer event information
-///
-typedef struct {
- LIST_ENTRY Link;
- UINT64 TriggerTime;
- UINT64 Period;
-} TIMER_EVENT_INFO;
-
-#define EVENT_SIGNATURE SIGNATURE_32('e','v','n','t')
-typedef struct {
- UINTN Signature;
- UINT32 Type;
- UINT32 SignalCount;
- ///
- /// Entry if the event is registered to be signalled
- ///
- LIST_ENTRY SignalLink;
- ///
- /// Notification information for this event
- ///
- EFI_TPL NotifyTpl;
- EFI_EVENT_NOTIFY NotifyFunction;
- VOID *NotifyContext;
- EFI_GUID EventGroup;
- LIST_ENTRY NotifyLink;
- UINT8 ExFlag;
- ///
- /// A list of all runtime events
- ///
- EFI_RUNTIME_EVENT_ENTRY RuntimeData;
- TIMER_EVENT_INFO Timer;
-} IEVENT;
-
-//
-// Internal prototypes
-//
-
-/**
- Dispatches all pending events.
-
- @param Priority The task priority level of event notifications
- to dispatch
-
-**/
-VOID
-CoreDispatchEventNotifies (
- IN EFI_TPL Priority
- );
-
-/**
- Initializes timer support.
-
-**/
-VOID
-CoreInitializeTimer (
- VOID
- );
-
-#endif
+/** @file
+ UEFI Event support functions and structure.
+
+Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.<BR>
+(C) Copyright 2015 Hewlett Packard Enterprise Development LP<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef __EVENT_H__
+#define __EVENT_H__
+
+#define VALID_TPL(a) ((a) <= TPL_HIGH_LEVEL)
+extern UINTN gEventPending;
+
+///
+/// Set if Event is part of an event group
+///
+#define EVT_EXFLAG_EVENT_GROUP 0x01
+///
+/// Set if Event is registered on a protocol notify
+///
+#define EVT_EXFLAG_EVENT_PROTOCOL_NOTIFICATION 0x02
+
+//
+// EFI_EVENT
+//
+
+///
+/// Timer event information
+///
+typedef struct {
+ LIST_ENTRY Link;
+ UINT64 TriggerTime;
+ UINT64 Period;
+} TIMER_EVENT_INFO;
+
+#define EVENT_SIGNATURE SIGNATURE_32('e','v','n','t')
+typedef struct {
+ UINTN Signature;
+ UINT32 Type;
+ UINT32 SignalCount;
+ ///
+ /// Entry if the event is registered to be signalled
+ ///
+ LIST_ENTRY SignalLink;
+ ///
+ /// Notification information for this event
+ ///
+ EFI_TPL NotifyTpl;
+ EFI_EVENT_NOTIFY NotifyFunction;
+ VOID *NotifyContext;
+ EFI_GUID EventGroup;
+ LIST_ENTRY NotifyLink;
+ UINT8 ExFlag;
+ ///
+ /// A list of all runtime events
+ ///
+ EFI_RUNTIME_EVENT_ENTRY RuntimeData;
+ TIMER_EVENT_INFO Timer;
+} IEVENT;
+
+//
+// Internal prototypes
+//
+
+/**
+ Dispatches all pending events.
+
+ @param Priority The task priority level of event notifications
+ to dispatch
+
+**/
+VOID
+CoreDispatchEventNotifies (
+ IN EFI_TPL Priority
+ );
+
+/**
+ Initializes timer support.
+
+**/
+VOID
+CoreInitializeTimer (
+ VOID
+ );
+
+#endif
diff --git a/MdeModulePkg/Core/Dxe/Event/Timer.c b/MdeModulePkg/Core/Dxe/Event/Timer.c
index 29e507c67c..59c839a4f1 100644
--- a/MdeModulePkg/Core/Dxe/Event/Timer.c
+++ b/MdeModulePkg/Core/Dxe/Event/Timer.c
@@ -1,291 +1,291 @@
-/** @file
- Core Timer Services
-
-Copyright (c) 2006 - 2013, Intel Corporation. All rights reserved.<BR>
-SPDX-License-Identifier: BSD-2-Clause-Patent
-
-**/
-
-#include "DxeMain.h"
-#include "Event.h"
-
-//
-// Internal data
-//
-
-LIST_ENTRY mEfiTimerList = INITIALIZE_LIST_HEAD_VARIABLE (mEfiTimerList);
-EFI_LOCK mEfiTimerLock = EFI_INITIALIZE_LOCK_VARIABLE (TPL_HIGH_LEVEL - 1);
-EFI_EVENT mEfiCheckTimerEvent = NULL;
-
-EFI_LOCK mEfiSystemTimeLock = EFI_INITIALIZE_LOCK_VARIABLE (TPL_HIGH_LEVEL);
-UINT64 mEfiSystemTime = 0;
-
-//
-// Timer functions
-//
-
-/**
- Inserts the timer event.
-
- @param Event Points to the internal structure of timer event
- to be installed
-
-**/
-VOID
-CoreInsertEventTimer (
- IN IEVENT *Event
- )
-{
- UINT64 TriggerTime;
- LIST_ENTRY *Link;
- IEVENT *Event2;
-
- ASSERT_LOCKED (&mEfiTimerLock);
-
- //
- // Get the timer's trigger time
- //
- TriggerTime = Event->Timer.TriggerTime;
-
- //
- // Insert the timer into the timer database in assending sorted order
- //
- for (Link = mEfiTimerList.ForwardLink; Link != &mEfiTimerList; Link = Link->ForwardLink) {
- Event2 = CR (Link, IEVENT, Timer.Link, EVENT_SIGNATURE);
-
- if (Event2->Timer.TriggerTime > TriggerTime) {
- break;
- }
- }
-
- InsertTailList (Link, &Event->Timer.Link);
-}
-
-/**
- Returns the current system time.
-
- @return The current system time
-
-**/
-UINT64
-CoreCurrentSystemTime (
- VOID
- )
-{
- UINT64 SystemTime;
-
- CoreAcquireLock (&mEfiSystemTimeLock);
- SystemTime = mEfiSystemTime;
- CoreReleaseLock (&mEfiSystemTimeLock);
-
- return SystemTime;
-}
-
-/**
- Checks the sorted timer list against the current system time.
- Signals any expired event timer.
-
- @param CheckEvent Not used
- @param Context Not used
-
-**/
-VOID
-EFIAPI
-CoreCheckTimers (
- IN EFI_EVENT CheckEvent,
- IN VOID *Context
- )
-{
- UINT64 SystemTime;
- IEVENT *Event;
-
- //
- // Check the timer database for expired timers
- //
- CoreAcquireLock (&mEfiTimerLock);
- SystemTime = CoreCurrentSystemTime ();
-
- while (!IsListEmpty (&mEfiTimerList)) {
- Event = CR (mEfiTimerList.ForwardLink, IEVENT, Timer.Link, EVENT_SIGNATURE);
-
- //
- // If this timer is not expired, then we're done
- //
- if (Event->Timer.TriggerTime > SystemTime) {
- break;
- }
-
- //
- // Remove this timer from the timer queue
- //
-
- RemoveEntryList (&Event->Timer.Link);
- Event->Timer.Link.ForwardLink = NULL;
-
- //
- // Signal it
- //
- CoreSignalEvent (Event);
-
- //
- // If this is a periodic timer, set it
- //
- if (Event->Timer.Period != 0) {
- //
- // Compute the timers new trigger time
- //
- Event->Timer.TriggerTime = Event->Timer.TriggerTime + Event->Timer.Period;
-
- //
- // If that's before now, then reset the timer to start from now
- //
- if (Event->Timer.TriggerTime <= SystemTime) {
- Event->Timer.TriggerTime = SystemTime;
- CoreSignalEvent (mEfiCheckTimerEvent);
- }
-
- //
- // Add the timer
- //
- CoreInsertEventTimer (Event);
- }
- }
-
- CoreReleaseLock (&mEfiTimerLock);
-}
-
-/**
- Initializes timer support.
-
-**/
-VOID
-CoreInitializeTimer (
- VOID
- )
-{
- EFI_STATUS Status;
-
- Status = CoreCreateEventInternal (
- EVT_NOTIFY_SIGNAL,
- TPL_HIGH_LEVEL - 1,
- CoreCheckTimers,
- NULL,
- NULL,
- &mEfiCheckTimerEvent
- );
- ASSERT_EFI_ERROR (Status);
-}
-
-/**
- Called by the platform code to process a tick.
-
- @param Duration The number of 100ns elapsed since the last call
- to TimerTick
-
-**/
-VOID
-EFIAPI
-CoreTimerTick (
- IN UINT64 Duration
- )
-{
- IEVENT *Event;
-
- //
- // Check runtiem flag in case there are ticks while exiting boot services
- //
- CoreAcquireLock (&mEfiSystemTimeLock);
-
- //
- // Update the system time
- //
- mEfiSystemTime += Duration;
-
- //
- // If the head of the list is expired, fire the timer event
- // to process it
- //
- if (!IsListEmpty (&mEfiTimerList)) {
- Event = CR (mEfiTimerList.ForwardLink, IEVENT, Timer.Link, EVENT_SIGNATURE);
-
- if (Event->Timer.TriggerTime <= mEfiSystemTime) {
- CoreSignalEvent (mEfiCheckTimerEvent);
- }
- }
-
- CoreReleaseLock (&mEfiSystemTimeLock);
-}
-
-/**
- Sets the type of timer and the trigger time for a timer event.
-
- @param UserEvent The timer event that is to be signaled at the
- specified time
- @param Type The type of time that is specified in
- TriggerTime
- @param TriggerTime The number of 100ns units until the timer
- expires
-
- @retval EFI_SUCCESS The event has been set to be signaled at the
- requested time
- @retval EFI_INVALID_PARAMETER Event or Type is not valid
-
-**/
-EFI_STATUS
-EFIAPI
-CoreSetTimer (
- IN EFI_EVENT UserEvent,
- IN EFI_TIMER_DELAY Type,
- IN UINT64 TriggerTime
- )
-{
- IEVENT *Event;
-
- Event = UserEvent;
-
- if (Event == NULL) {
- return EFI_INVALID_PARAMETER;
- }
-
- if (Event->Signature != EVENT_SIGNATURE) {
- return EFI_INVALID_PARAMETER;
- }
-
- if (((UINT32)Type > TimerRelative) || ((Event->Type & EVT_TIMER) == 0)) {
- return EFI_INVALID_PARAMETER;
- }
-
- CoreAcquireLock (&mEfiTimerLock);
-
- //
- // If the timer is queued to the timer database, remove it
- //
- if (Event->Timer.Link.ForwardLink != NULL) {
- RemoveEntryList (&Event->Timer.Link);
- Event->Timer.Link.ForwardLink = NULL;
- }
-
- Event->Timer.TriggerTime = 0;
- Event->Timer.Period = 0;
-
- if (Type != TimerCancel) {
- if (Type == TimerPeriodic) {
- if (TriggerTime == 0) {
- gTimer->GetTimerPeriod (gTimer, &TriggerTime);
- }
-
- Event->Timer.Period = TriggerTime;
- }
-
- Event->Timer.TriggerTime = CoreCurrentSystemTime () + TriggerTime;
- CoreInsertEventTimer (Event);
-
- if (TriggerTime == 0) {
- CoreSignalEvent (mEfiCheckTimerEvent);
- }
- }
-
- CoreReleaseLock (&mEfiTimerLock);
-
- return EFI_SUCCESS;
-}
+/** @file
+ Core Timer Services
+
+Copyright (c) 2006 - 2013, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "DxeMain.h"
+#include "Event.h"
+
+//
+// Internal data
+//
+
+LIST_ENTRY mEfiTimerList = INITIALIZE_LIST_HEAD_VARIABLE (mEfiTimerList);
+EFI_LOCK mEfiTimerLock = EFI_INITIALIZE_LOCK_VARIABLE (TPL_HIGH_LEVEL - 1);
+EFI_EVENT mEfiCheckTimerEvent = NULL;
+
+EFI_LOCK mEfiSystemTimeLock = EFI_INITIALIZE_LOCK_VARIABLE (TPL_HIGH_LEVEL);
+UINT64 mEfiSystemTime = 0;
+
+//
+// Timer functions
+//
+
+/**
+ Inserts the timer event.
+
+ @param Event Points to the internal structure of timer event
+ to be installed
+
+**/
+VOID
+CoreInsertEventTimer (
+ IN IEVENT *Event
+ )
+{
+ UINT64 TriggerTime;
+ LIST_ENTRY *Link;
+ IEVENT *Event2;
+
+ ASSERT_LOCKED (&mEfiTimerLock);
+
+ //
+ // Get the timer's trigger time
+ //
+ TriggerTime = Event->Timer.TriggerTime;
+
+ //
+ // Insert the timer into the timer database in assending sorted order
+ //
+ for (Link = mEfiTimerList.ForwardLink; Link != &mEfiTimerList; Link = Link->ForwardLink) {
+ Event2 = CR (Link, IEVENT, Timer.Link, EVENT_SIGNATURE);
+
+ if (Event2->Timer.TriggerTime > TriggerTime) {
+ break;
+ }
+ }
+
+ InsertTailList (Link, &Event->Timer.Link);
+}
+
+/**
+ Returns the current system time.
+
+ @return The current system time
+
+**/
+UINT64
+CoreCurrentSystemTime (
+ VOID
+ )
+{
+ UINT64 SystemTime;
+
+ CoreAcquireLock (&mEfiSystemTimeLock);
+ SystemTime = mEfiSystemTime;
+ CoreReleaseLock (&mEfiSystemTimeLock);
+
+ return SystemTime;
+}
+
+/**
+ Checks the sorted timer list against the current system time.
+ Signals any expired event timer.
+
+ @param CheckEvent Not used
+ @param Context Not used
+
+**/
+VOID
+EFIAPI
+CoreCheckTimers (
+ IN EFI_EVENT CheckEvent,
+ IN VOID *Context
+ )
+{
+ UINT64 SystemTime;
+ IEVENT *Event;
+
+ //
+ // Check the timer database for expired timers
+ //
+ CoreAcquireLock (&mEfiTimerLock);
+ SystemTime = CoreCurrentSystemTime ();
+
+ while (!IsListEmpty (&mEfiTimerList)) {
+ Event = CR (mEfiTimerList.ForwardLink, IEVENT, Timer.Link, EVENT_SIGNATURE);
+
+ //
+ // If this timer is not expired, then we're done
+ //
+ if (Event->Timer.TriggerTime > SystemTime) {
+ break;
+ }
+
+ //
+ // Remove this timer from the timer queue
+ //
+
+ RemoveEntryList (&Event->Timer.Link);
+ Event->Timer.Link.ForwardLink = NULL;
+
+ //
+ // Signal it
+ //
+ CoreSignalEvent (Event);
+
+ //
+ // If this is a periodic timer, set it
+ //
+ if (Event->Timer.Period != 0) {
+ //
+ // Compute the timers new trigger time
+ //
+ Event->Timer.TriggerTime = Event->Timer.TriggerTime + Event->Timer.Period;
+
+ //
+ // If that's before now, then reset the timer to start from now
+ //
+ if (Event->Timer.TriggerTime <= SystemTime) {
+ Event->Timer.TriggerTime = SystemTime;
+ CoreSignalEvent (mEfiCheckTimerEvent);
+ }
+
+ //
+ // Add the timer
+ //
+ CoreInsertEventTimer (Event);
+ }
+ }
+
+ CoreReleaseLock (&mEfiTimerLock);
+}
+
+/**
+ Initializes timer support.
+
+**/
+VOID
+CoreInitializeTimer (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+
+ Status = CoreCreateEventInternal (
+ EVT_NOTIFY_SIGNAL,
+ TPL_HIGH_LEVEL - 1,
+ CoreCheckTimers,
+ NULL,
+ NULL,
+ &mEfiCheckTimerEvent
+ );
+ ASSERT_EFI_ERROR (Status);
+}
+
+/**
+ Called by the platform code to process a tick.
+
+ @param Duration The number of 100ns elapsed since the last call
+ to TimerTick
+
+**/
+VOID
+EFIAPI
+CoreTimerTick (
+ IN UINT64 Duration
+ )
+{
+ IEVENT *Event;
+
+ //
+ // Check runtiem flag in case there are ticks while exiting boot services
+ //
+ CoreAcquireLock (&mEfiSystemTimeLock);
+
+ //
+ // Update the system time
+ //
+ mEfiSystemTime += Duration;
+
+ //
+ // If the head of the list is expired, fire the timer event
+ // to process it
+ //
+ if (!IsListEmpty (&mEfiTimerList)) {
+ Event = CR (mEfiTimerList.ForwardLink, IEVENT, Timer.Link, EVENT_SIGNATURE);
+
+ if (Event->Timer.TriggerTime <= mEfiSystemTime) {
+ CoreSignalEvent (mEfiCheckTimerEvent);
+ }
+ }
+
+ CoreReleaseLock (&mEfiSystemTimeLock);
+}
+
+/**
+ Sets the type of timer and the trigger time for a timer event.
+
+ @param UserEvent The timer event that is to be signaled at the
+ specified time
+ @param Type The type of time that is specified in
+ TriggerTime
+ @param TriggerTime The number of 100ns units until the timer
+ expires
+
+ @retval EFI_SUCCESS The event has been set to be signaled at the
+ requested time
+ @retval EFI_INVALID_PARAMETER Event or Type is not valid
+
+**/
+EFI_STATUS
+EFIAPI
+CoreSetTimer (
+ IN EFI_EVENT UserEvent,
+ IN EFI_TIMER_DELAY Type,
+ IN UINT64 TriggerTime
+ )
+{
+ IEVENT *Event;
+
+ Event = UserEvent;
+
+ if (Event == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (Event->Signature != EVENT_SIGNATURE) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (((UINT32)Type > TimerRelative) || ((Event->Type & EVT_TIMER) == 0)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ CoreAcquireLock (&mEfiTimerLock);
+
+ //
+ // If the timer is queued to the timer database, remove it
+ //
+ if (Event->Timer.Link.ForwardLink != NULL) {
+ RemoveEntryList (&Event->Timer.Link);
+ Event->Timer.Link.ForwardLink = NULL;
+ }
+
+ Event->Timer.TriggerTime = 0;
+ Event->Timer.Period = 0;
+
+ if (Type != TimerCancel) {
+ if (Type == TimerPeriodic) {
+ if (TriggerTime == 0) {
+ gTimer->GetTimerPeriod (gTimer, &TriggerTime);
+ }
+
+ Event->Timer.Period = TriggerTime;
+ }
+
+ Event->Timer.TriggerTime = CoreCurrentSystemTime () + TriggerTime;
+ CoreInsertEventTimer (Event);
+
+ if (TriggerTime == 0) {
+ CoreSignalEvent (mEfiCheckTimerEvent);
+ }
+ }
+
+ CoreReleaseLock (&mEfiTimerLock);
+
+ return EFI_SUCCESS;
+}
diff --git a/MdeModulePkg/Core/Dxe/Event/Tpl.c b/MdeModulePkg/Core/Dxe/Event/Tpl.c
index b33f80573c..d7ef8eb970 100644
--- a/MdeModulePkg/Core/Dxe/Event/Tpl.c
+++ b/MdeModulePkg/Core/Dxe/Event/Tpl.c
@@ -1,149 +1,149 @@
-/** @file
- Task priority (TPL) functions.
-
-Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
-SPDX-License-Identifier: BSD-2-Clause-Patent
-
-**/
-
-#include "DxeMain.h"
-#include "Event.h"
-
-/**
- Set Interrupt State.
-
- @param Enable The state of enable or disable interrupt
-
-**/
-VOID
-CoreSetInterruptState (
- IN BOOLEAN Enable
- )
-{
- EFI_STATUS Status;
- BOOLEAN InSmm;
-
- if (gCpu == NULL) {
- return;
- }
-
- if (!Enable) {
- gCpu->DisableInterrupt (gCpu);
- return;
- }
-
- if (gSmmBase2 == NULL) {
- gCpu->EnableInterrupt (gCpu);
- return;
- }
-
- Status = gSmmBase2->InSmm (gSmmBase2, &InSmm);
- if (!EFI_ERROR (Status) && !InSmm) {
- gCpu->EnableInterrupt (gCpu);
- }
-}
-
-/**
- Raise the task priority level to the new level.
- High level is implemented by disabling processor interrupts.
-
- @param NewTpl New task priority level
-
- @return The previous task priority level
-
-**/
-EFI_TPL
-EFIAPI
-CoreRaiseTpl (
- IN EFI_TPL NewTpl
- )
-{
- EFI_TPL OldTpl;
-
- OldTpl = gEfiCurrentTpl;
- if (OldTpl > NewTpl) {
- DEBUG ((DEBUG_ERROR, "FATAL ERROR - RaiseTpl with OldTpl(0x%x) > NewTpl(0x%x)\n", OldTpl, NewTpl));
- ASSERT (FALSE);
- }
-
- ASSERT (VALID_TPL (NewTpl));
-
- //
- // If raising to high level, disable interrupts
- //
- if ((NewTpl >= TPL_HIGH_LEVEL) && (OldTpl < TPL_HIGH_LEVEL)) {
- CoreSetInterruptState (FALSE);
- }
-
- //
- // Set the new value
- //
- gEfiCurrentTpl = NewTpl;
-
- return OldTpl;
-}
-
-/**
- Lowers the task priority to the previous value. If the new
- priority unmasks events at a higher priority, they are dispatched.
-
- @param NewTpl New, lower, task priority
-
-**/
-VOID
-EFIAPI
-CoreRestoreTpl (
- IN EFI_TPL NewTpl
- )
-{
- EFI_TPL OldTpl;
- EFI_TPL PendingTpl;
-
- OldTpl = gEfiCurrentTpl;
- if (NewTpl > OldTpl) {
- DEBUG ((DEBUG_ERROR, "FATAL ERROR - RestoreTpl with NewTpl(0x%x) > OldTpl(0x%x)\n", NewTpl, OldTpl));
- ASSERT (FALSE);
- }
-
- ASSERT (VALID_TPL (NewTpl));
-
- //
- // If lowering below HIGH_LEVEL, make sure
- // interrupts are enabled
- //
-
- if ((OldTpl >= TPL_HIGH_LEVEL) && (NewTpl < TPL_HIGH_LEVEL)) {
- gEfiCurrentTpl = TPL_HIGH_LEVEL;
- }
-
- //
- // Dispatch any pending events
- //
- while (gEventPending != 0) {
- PendingTpl = (UINTN)HighBitSet64 (gEventPending);
- if (PendingTpl <= NewTpl) {
- break;
- }
-
- gEfiCurrentTpl = PendingTpl;
- if (gEfiCurrentTpl < TPL_HIGH_LEVEL) {
- CoreSetInterruptState (TRUE);
- }
-
- CoreDispatchEventNotifies (gEfiCurrentTpl);
- }
-
- //
- // Set the new value
- //
-
- gEfiCurrentTpl = NewTpl;
-
- //
- // If lowering below HIGH_LEVEL, make sure
- // interrupts are enabled
- //
- if (gEfiCurrentTpl < TPL_HIGH_LEVEL) {
- CoreSetInterruptState (TRUE);
- }
-}
+/** @file
+ Task priority (TPL) functions.
+
+Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "DxeMain.h"
+#include "Event.h"
+
+/**
+ Set Interrupt State.
+
+ @param Enable The state of enable or disable interrupt
+
+**/
+VOID
+CoreSetInterruptState (
+ IN BOOLEAN Enable
+ )
+{
+ EFI_STATUS Status;
+ BOOLEAN InSmm;
+
+ if (gCpu == NULL) {
+ return;
+ }
+
+ if (!Enable) {
+ gCpu->DisableInterrupt (gCpu);
+ return;
+ }
+
+ if (gSmmBase2 == NULL) {
+ gCpu->EnableInterrupt (gCpu);
+ return;
+ }
+
+ Status = gSmmBase2->InSmm (gSmmBase2, &InSmm);
+ if (!EFI_ERROR (Status) && !InSmm) {
+ gCpu->EnableInterrupt (gCpu);
+ }
+}
+
+/**
+ Raise the task priority level to the new level.
+ High level is implemented by disabling processor interrupts.
+
+ @param NewTpl New task priority level
+
+ @return The previous task priority level
+
+**/
+EFI_TPL
+EFIAPI
+CoreRaiseTpl (
+ IN EFI_TPL NewTpl
+ )
+{
+ EFI_TPL OldTpl;
+
+ OldTpl = gEfiCurrentTpl;
+ if (OldTpl > NewTpl) {
+ DEBUG ((DEBUG_ERROR, "FATAL ERROR - RaiseTpl with OldTpl(0x%x) > NewTpl(0x%x)\n", OldTpl, NewTpl));
+ ASSERT (FALSE);
+ }
+
+ ASSERT (VALID_TPL (NewTpl));
+
+ //
+ // If raising to high level, disable interrupts
+ //
+ if ((NewTpl >= TPL_HIGH_LEVEL) && (OldTpl < TPL_HIGH_LEVEL)) {
+ CoreSetInterruptState (FALSE);
+ }
+
+ //
+ // Set the new value
+ //
+ gEfiCurrentTpl = NewTpl;
+
+ return OldTpl;
+}
+
+/**
+ Lowers the task priority to the previous value. If the new
+ priority unmasks events at a higher priority, they are dispatched.
+
+ @param NewTpl New, lower, task priority
+
+**/
+VOID
+EFIAPI
+CoreRestoreTpl (
+ IN EFI_TPL NewTpl
+ )
+{
+ EFI_TPL OldTpl;
+ EFI_TPL PendingTpl;
+
+ OldTpl = gEfiCurrentTpl;
+ if (NewTpl > OldTpl) {
+ DEBUG ((DEBUG_ERROR, "FATAL ERROR - RestoreTpl with NewTpl(0x%x) > OldTpl(0x%x)\n", NewTpl, OldTpl));
+ ASSERT (FALSE);
+ }
+
+ ASSERT (VALID_TPL (NewTpl));
+
+ //
+ // If lowering below HIGH_LEVEL, make sure
+ // interrupts are enabled
+ //
+
+ if ((OldTpl >= TPL_HIGH_LEVEL) && (NewTpl < TPL_HIGH_LEVEL)) {
+ gEfiCurrentTpl = TPL_HIGH_LEVEL;
+ }
+
+ //
+ // Dispatch any pending events
+ //
+ while (gEventPending != 0) {
+ PendingTpl = (UINTN)HighBitSet64 (gEventPending);
+ if (PendingTpl <= NewTpl) {
+ break;
+ }
+
+ gEfiCurrentTpl = PendingTpl;
+ if (gEfiCurrentTpl < TPL_HIGH_LEVEL) {
+ CoreSetInterruptState (TRUE);
+ }
+
+ CoreDispatchEventNotifies (gEfiCurrentTpl);
+ }
+
+ //
+ // Set the new value
+ //
+
+ gEfiCurrentTpl = NewTpl;
+
+ //
+ // If lowering below HIGH_LEVEL, make sure
+ // interrupts are enabled
+ //
+ if (gEfiCurrentTpl < TPL_HIGH_LEVEL) {
+ CoreSetInterruptState (TRUE);
+ }
+}
diff --git a/MdeModulePkg/Core/Dxe/FwVol/Ffs.c b/MdeModulePkg/Core/Dxe/FwVol/Ffs.c
index 17e599cc15..7d669d4c49 100644
--- a/MdeModulePkg/Core/Dxe/FwVol/Ffs.c
+++ b/MdeModulePkg/Core/Dxe/FwVol/Ffs.c
@@ -1,216 +1,216 @@
-/** @file
- FFS file access utilities.
-
-Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.<BR>
-SPDX-License-Identifier: BSD-2-Clause-Patent
-
-**/
-
-#include "DxeMain.h"
-#include "FwVolDriver.h"
-
-/**
- Get the FFS file state by checking the highest bit set in the header's state field.
-
- @param ErasePolarity Erase polarity attribute of the firmware volume
- @param FfsHeader Points to the FFS file header
-
- @return FFS File state
-
-**/
-EFI_FFS_FILE_STATE
-GetFileState (
- IN UINT8 ErasePolarity,
- IN EFI_FFS_FILE_HEADER *FfsHeader
- )
-{
- EFI_FFS_FILE_STATE FileState;
- UINT8 HighestBit;
-
- FileState = FfsHeader->State;
-
- if (ErasePolarity != 0) {
- FileState = (EFI_FFS_FILE_STATE) ~FileState;
- }
-
- HighestBit = 0x80;
- while (HighestBit != 0 && ((HighestBit & FileState) == 0)) {
- HighestBit >>= 1;
- }
-
- return (EFI_FFS_FILE_STATE)HighestBit;
-}
-
-/**
- Check if a block of buffer is erased.
-
- @param ErasePolarity Erase polarity attribute of the firmware volume
- @param InBuffer The buffer to be checked
- @param BufferSize Size of the buffer in bytes
-
- @retval TRUE The block of buffer is erased
- @retval FALSE The block of buffer is not erased
-
-**/
-BOOLEAN
-IsBufferErased (
- IN UINT8 ErasePolarity,
- IN VOID *InBuffer,
- IN UINTN BufferSize
- )
-{
- UINTN Count;
- UINT8 EraseByte;
- UINT8 *Buffer;
-
- if (ErasePolarity == 1) {
- EraseByte = 0xFF;
- } else {
- EraseByte = 0;
- }
-
- Buffer = InBuffer;
- for (Count = 0; Count < BufferSize; Count++) {
- if (Buffer[Count] != EraseByte) {
- return FALSE;
- }
- }
-
- return TRUE;
-}
-
-/**
- Verify checksum of the firmware volume header.
-
- @param FvHeader Points to the firmware volume header to be checked
-
- @retval TRUE Checksum verification passed
- @retval FALSE Checksum verification failed
-
-**/
-BOOLEAN
-VerifyFvHeaderChecksum (
- IN EFI_FIRMWARE_VOLUME_HEADER *FvHeader
- )
-{
- UINT16 Checksum;
-
- Checksum = CalculateSum16 ((UINT16 *)FvHeader, FvHeader->HeaderLength);
-
- if (Checksum == 0) {
- return TRUE;
- } else {
- return FALSE;
- }
-}
-
-/**
- Verify checksum of the FFS file header.
-
- @param FfsHeader Points to the FFS file header to be checked
-
- @retval TRUE Checksum verification passed
- @retval FALSE Checksum verification failed
-
-**/
-BOOLEAN
-VerifyHeaderChecksum (
- IN EFI_FFS_FILE_HEADER *FfsHeader
- )
-{
- UINT8 HeaderChecksum;
-
- if (IS_FFS_FILE2 (FfsHeader)) {
- HeaderChecksum = CalculateSum8 ((UINT8 *)FfsHeader, sizeof (EFI_FFS_FILE_HEADER2));
- } else {
- HeaderChecksum = CalculateSum8 ((UINT8 *)FfsHeader, sizeof (EFI_FFS_FILE_HEADER));
- }
-
- HeaderChecksum = (UINT8)(HeaderChecksum - FfsHeader->State - FfsHeader->IntegrityCheck.Checksum.File);
-
- if (HeaderChecksum == 0) {
- return TRUE;
- } else {
- return FALSE;
- }
-}
-
-/**
- Check if it's a valid FFS file header.
-
- @param ErasePolarity Erase polarity attribute of the firmware volume
- @param FfsHeader Points to the FFS file header to be checked
- @param FileState FFS file state to be returned
-
- @retval TRUE Valid FFS file header
- @retval FALSE Invalid FFS file header
-
-**/
-BOOLEAN
-IsValidFfsHeader (
- IN UINT8 ErasePolarity,
- IN EFI_FFS_FILE_HEADER *FfsHeader,
- OUT EFI_FFS_FILE_STATE *FileState
- )
-{
- *FileState = GetFileState (ErasePolarity, FfsHeader);
-
- switch (*FileState) {
- case EFI_FILE_HEADER_VALID:
- case EFI_FILE_DATA_VALID:
- case EFI_FILE_MARKED_FOR_UPDATE:
- case EFI_FILE_DELETED:
- //
- // Here we need to verify header checksum
- //
- return VerifyHeaderChecksum (FfsHeader);
-
- case EFI_FILE_HEADER_CONSTRUCTION:
- case EFI_FILE_HEADER_INVALID:
- default:
- return FALSE;
- }
-}
-
-/**
- Check if it's a valid FFS file.
- Here we are sure that it has a valid FFS file header since we must call IsValidFfsHeader() first.
-
- @param ErasePolarity Erase polarity attribute of the firmware volume
- @param FfsHeader Points to the FFS file to be checked
-
- @retval TRUE Valid FFS file
- @retval FALSE Invalid FFS file
-
-**/
-BOOLEAN
-IsValidFfsFile (
- IN UINT8 ErasePolarity,
- IN EFI_FFS_FILE_HEADER *FfsHeader
- )
-{
- EFI_FFS_FILE_STATE FileState;
- UINT8 DataCheckSum;
-
- FileState = GetFileState (ErasePolarity, FfsHeader);
- switch (FileState) {
- case EFI_FILE_DELETED:
- case EFI_FILE_DATA_VALID:
- case EFI_FILE_MARKED_FOR_UPDATE:
- DataCheckSum = FFS_FIXED_CHECKSUM;
- if ((FfsHeader->Attributes & FFS_ATTRIB_CHECKSUM) == FFS_ATTRIB_CHECKSUM) {
- if (IS_FFS_FILE2 (FfsHeader)) {
- DataCheckSum = CalculateCheckSum8 ((CONST UINT8 *)FfsHeader + sizeof (EFI_FFS_FILE_HEADER2), FFS_FILE2_SIZE (FfsHeader) - sizeof (EFI_FFS_FILE_HEADER2));
- } else {
- DataCheckSum = CalculateCheckSum8 ((CONST UINT8 *)FfsHeader + sizeof (EFI_FFS_FILE_HEADER), FFS_FILE_SIZE (FfsHeader) - sizeof (EFI_FFS_FILE_HEADER));
- }
- }
-
- if (FfsHeader->IntegrityCheck.Checksum.File == DataCheckSum) {
- return TRUE;
- }
-
- default:
- return FALSE;
- }
-}
+/** @file
+ FFS file access utilities.
+
+Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "DxeMain.h"
+#include "FwVolDriver.h"
+
+/**
+ Get the FFS file state by checking the highest bit set in the header's state field.
+
+ @param ErasePolarity Erase polarity attribute of the firmware volume
+ @param FfsHeader Points to the FFS file header
+
+ @return FFS File state
+
+**/
+EFI_FFS_FILE_STATE
+GetFileState (
+ IN UINT8 ErasePolarity,
+ IN EFI_FFS_FILE_HEADER *FfsHeader
+ )
+{
+ EFI_FFS_FILE_STATE FileState;
+ UINT8 HighestBit;
+
+ FileState = FfsHeader->State;
+
+ if (ErasePolarity != 0) {
+ FileState = (EFI_FFS_FILE_STATE) ~FileState;
+ }
+
+ HighestBit = 0x80;
+ while (HighestBit != 0 && ((HighestBit & FileState) == 0)) {
+ HighestBit >>= 1;
+ }
+
+ return (EFI_FFS_FILE_STATE)HighestBit;
+}
+
+/**
+ Check if a block of buffer is erased.
+
+ @param ErasePolarity Erase polarity attribute of the firmware volume
+ @param InBuffer The buffer to be checked
+ @param BufferSize Size of the buffer in bytes
+
+ @retval TRUE The block of buffer is erased
+ @retval FALSE The block of buffer is not erased
+
+**/
+BOOLEAN
+IsBufferErased (
+ IN UINT8 ErasePolarity,
+ IN VOID *InBuffer,
+ IN UINTN BufferSize
+ )
+{
+ UINTN Count;
+ UINT8 EraseByte;
+ UINT8 *Buffer;
+
+ if (ErasePolarity == 1) {
+ EraseByte = 0xFF;
+ } else {
+ EraseByte = 0;
+ }
+
+ Buffer = InBuffer;
+ for (Count = 0; Count < BufferSize; Count++) {
+ if (Buffer[Count] != EraseByte) {
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+}
+
+/**
+ Verify checksum of the firmware volume header.
+
+ @param FvHeader Points to the firmware volume header to be checked
+
+ @retval TRUE Checksum verification passed
+ @retval FALSE Checksum verification failed
+
+**/
+BOOLEAN
+VerifyFvHeaderChecksum (
+ IN EFI_FIRMWARE_VOLUME_HEADER *FvHeader
+ )
+{
+ UINT16 Checksum;
+
+ Checksum = CalculateSum16 ((UINT16 *)FvHeader, FvHeader->HeaderLength);
+
+ if (Checksum == 0) {
+ return TRUE;
+ } else {
+ return FALSE;
+ }
+}
+
+/**
+ Verify checksum of the FFS file header.
+
+ @param FfsHeader Points to the FFS file header to be checked
+
+ @retval TRUE Checksum verification passed
+ @retval FALSE Checksum verification failed
+
+**/
+BOOLEAN
+VerifyHeaderChecksum (
+ IN EFI_FFS_FILE_HEADER *FfsHeader
+ )
+{
+ UINT8 HeaderChecksum;
+
+ if (IS_FFS_FILE2 (FfsHeader)) {
+ HeaderChecksum = CalculateSum8 ((UINT8 *)FfsHeader, sizeof (EFI_FFS_FILE_HEADER2));
+ } else {
+ HeaderChecksum = CalculateSum8 ((UINT8 *)FfsHeader, sizeof (EFI_FFS_FILE_HEADER));
+ }
+
+ HeaderChecksum = (UINT8)(HeaderChecksum - FfsHeader->State - FfsHeader->IntegrityCheck.Checksum.File);
+
+ if (HeaderChecksum == 0) {
+ return TRUE;
+ } else {
+ return FALSE;
+ }
+}
+
+/**
+ Check if it's a valid FFS file header.
+
+ @param ErasePolarity Erase polarity attribute of the firmware volume
+ @param FfsHeader Points to the FFS file header to be checked
+ @param FileState FFS file state to be returned
+
+ @retval TRUE Valid FFS file header
+ @retval FALSE Invalid FFS file header
+
+**/
+BOOLEAN
+IsValidFfsHeader (
+ IN UINT8 ErasePolarity,
+ IN EFI_FFS_FILE_HEADER *FfsHeader,
+ OUT EFI_FFS_FILE_STATE *FileState
+ )
+{
+ *FileState = GetFileState (ErasePolarity, FfsHeader);
+
+ switch (*FileState) {
+ case EFI_FILE_HEADER_VALID:
+ case EFI_FILE_DATA_VALID:
+ case EFI_FILE_MARKED_FOR_UPDATE:
+ case EFI_FILE_DELETED:
+ //
+ // Here we need to verify header checksum
+ //
+ return VerifyHeaderChecksum (FfsHeader);
+
+ case EFI_FILE_HEADER_CONSTRUCTION:
+ case EFI_FILE_HEADER_INVALID:
+ default:
+ return FALSE;
+ }
+}
+
+/**
+ Check if it's a valid FFS file.
+ Here we are sure that it has a valid FFS file header since we must call IsValidFfsHeader() first.
+
+ @param ErasePolarity Erase polarity attribute of the firmware volume
+ @param FfsHeader Points to the FFS file to be checked
+
+ @retval TRUE Valid FFS file
+ @retval FALSE Invalid FFS file
+
+**/
+BOOLEAN
+IsValidFfsFile (
+ IN UINT8 ErasePolarity,
+ IN EFI_FFS_FILE_HEADER *FfsHeader
+ )
+{
+ EFI_FFS_FILE_STATE FileState;
+ UINT8 DataCheckSum;
+
+ FileState = GetFileState (ErasePolarity, FfsHeader);
+ switch (FileState) {
+ case EFI_FILE_DELETED:
+ case EFI_FILE_DATA_VALID:
+ case EFI_FILE_MARKED_FOR_UPDATE:
+ DataCheckSum = FFS_FIXED_CHECKSUM;
+ if ((FfsHeader->Attributes & FFS_ATTRIB_CHECKSUM) == FFS_ATTRIB_CHECKSUM) {
+ if (IS_FFS_FILE2 (FfsHeader)) {
+ DataCheckSum = CalculateCheckSum8 ((CONST UINT8 *)FfsHeader + sizeof (EFI_FFS_FILE_HEADER2), FFS_FILE2_SIZE (FfsHeader) - sizeof (EFI_FFS_FILE_HEADER2));
+ } else {
+ DataCheckSum = CalculateCheckSum8 ((CONST UINT8 *)FfsHeader + sizeof (EFI_FFS_FILE_HEADER), FFS_FILE_SIZE (FfsHeader) - sizeof (EFI_FFS_FILE_HEADER));
+ }
+ }
+
+ if (FfsHeader->IntegrityCheck.Checksum.File == DataCheckSum) {
+ return TRUE;
+ }
+
+ default:
+ return FALSE;
+ }
+}
diff --git a/MdeModulePkg/Core/Dxe/FwVol/FwVol.c b/MdeModulePkg/Core/Dxe/FwVol/FwVol.c
index 0c1554ba4d..7743182bcf 100644
--- a/MdeModulePkg/Core/Dxe/FwVol/FwVol.c
+++ b/MdeModulePkg/Core/Dxe/FwVol/FwVol.c
@@ -1,725 +1,725 @@
-/** @file
- Firmware File System driver that produce Firmware Volume protocol.
- Layers on top of Firmware Block protocol to produce a file abstraction
- of FV based files.
-
-Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR>
-SPDX-License-Identifier: BSD-2-Clause-Patent
-
-**/
-
-#include "DxeMain.h"
-#include "FwVolDriver.h"
-
-//
-// Protocol notify related globals
-//
-VOID *gEfiFwVolBlockNotifyReg;
-EFI_EVENT gEfiFwVolBlockEvent;
-
-FV_DEVICE mFvDevice = {
- FV2_DEVICE_SIGNATURE,
- NULL,
- NULL,
- {
- FvGetVolumeAttributes,
- FvSetVolumeAttributes,
- FvReadFile,
- FvReadFileSection,
- FvWriteFile,
- FvGetNextFile,
- sizeof (UINTN),
- NULL,
- FvGetVolumeInfo,
- FvSetVolumeInfo
- },
- NULL,
- NULL,
- NULL,
- NULL,
- { NULL, NULL},
- 0,
- 0,
- FALSE,
- FALSE
-};
-
-//
-// FFS helper functions
-//
-
-/**
- Read data from Firmware Block by FVB protocol Read.
- The data may cross the multi block ranges.
-
- @param Fvb The FW_VOL_BLOCK_PROTOCOL instance from which to read data.
- @param StartLba Pointer to StartLba.
- On input, the start logical block index from which to read.
- On output,the end logical block index after reading.
- @param Offset Pointer to Offset
- On input, offset into the block at which to begin reading.
- On output, offset into the end block after reading.
- @param DataSize Size of data to be read.
- @param Data Pointer to Buffer that the data will be read into.
-
- @retval EFI_SUCCESS Successfully read data from firmware block.
- @retval others
-**/
-EFI_STATUS
-ReadFvbData (
- IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb,
- IN OUT EFI_LBA *StartLba,
- IN OUT UINTN *Offset,
- IN UINTN DataSize,
- OUT UINT8 *Data
- )
-{
- UINTN BlockSize;
- UINTN NumberOfBlocks;
- UINTN BlockIndex;
- UINTN ReadDataSize;
- EFI_STATUS Status;
-
- //
- // Try read data in current block
- //
- BlockIndex = 0;
- ReadDataSize = DataSize;
- Status = Fvb->Read (Fvb, *StartLba, *Offset, &ReadDataSize, Data);
- if (Status == EFI_SUCCESS) {
- *Offset += DataSize;
- return EFI_SUCCESS;
- } else if (Status != EFI_BAD_BUFFER_SIZE) {
- //
- // other error will direct return
- //
- return Status;
- }
-
- //
- // Data crosses the blocks, read data from next block
- //
- DataSize -= ReadDataSize;
- Data += ReadDataSize;
- *StartLba = *StartLba + 1;
- while (DataSize > 0) {
- Status = Fvb->GetBlockSize (Fvb, *StartLba, &BlockSize, &NumberOfBlocks);
- if (EFI_ERROR (Status)) {
- return Status;
- }
-
- //
- // Read data from the crossing blocks
- //
- BlockIndex = 0;
- while (BlockIndex < NumberOfBlocks && DataSize >= BlockSize) {
- Status = Fvb->Read (Fvb, *StartLba + BlockIndex, 0, &BlockSize, Data);
- if (EFI_ERROR (Status)) {
- return Status;
- }
-
- Data += BlockSize;
- DataSize -= BlockSize;
- BlockIndex++;
- }
-
- //
- // Data doesn't exceed the current block range.
- //
- if (DataSize < BlockSize) {
- break;
- }
-
- //
- // Data must be got from the next block range.
- //
- *StartLba += NumberOfBlocks;
- }
-
- //
- // read the remaining data
- //
- if (DataSize > 0) {
- Status = Fvb->Read (Fvb, *StartLba + BlockIndex, 0, &DataSize, Data);
- if (EFI_ERROR (Status)) {
- return Status;
- }
- }
-
- //
- // Update Lba and Offset used by the following read.
- //
- *StartLba += BlockIndex;
- *Offset = DataSize;
-
- return EFI_SUCCESS;
-}
-
-/**
- Given the supplied FW_VOL_BLOCK_PROTOCOL, allocate a buffer for output and
- copy the real length volume header into it.
-
- @param Fvb The FW_VOL_BLOCK_PROTOCOL instance from which to
- read the volume header
- @param FwVolHeader Pointer to pointer to allocated buffer in which
- the volume header is returned.
-
- @retval EFI_OUT_OF_RESOURCES No enough buffer could be allocated.
- @retval EFI_SUCCESS Successfully read volume header to the allocated
- buffer.
- @retval EFI_INVALID_PARAMETER The FV Header signature is not as expected or
- the file system could not be understood.
-
-**/
-EFI_STATUS
-GetFwVolHeader (
- IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb,
- OUT EFI_FIRMWARE_VOLUME_HEADER **FwVolHeader
- )
-{
- EFI_STATUS Status;
- EFI_FIRMWARE_VOLUME_HEADER TempFvh;
- UINTN FvhLength;
- EFI_LBA StartLba;
- UINTN Offset;
- UINT8 *Buffer;
-
- //
- // Read the standard FV header
- //
- StartLba = 0;
- Offset = 0;
- FvhLength = sizeof (EFI_FIRMWARE_VOLUME_HEADER);
- Status = ReadFvbData (Fvb, &StartLba, &Offset, FvhLength, (UINT8 *)&TempFvh);
- if (EFI_ERROR (Status)) {
- return Status;
- }
-
- //
- // Validate FV Header signature, if not as expected, continue.
- //
- if (TempFvh.Signature != EFI_FVH_SIGNATURE) {
- return EFI_INVALID_PARAMETER;
- }
-
- //
- // Check to see that the file system is indeed formatted in a way we can
- // understand it...
- //
- if ((!CompareGuid (&TempFvh.FileSystemGuid, &gEfiFirmwareFileSystem2Guid)) &&
- (!CompareGuid (&TempFvh.FileSystemGuid, &gEfiFirmwareFileSystem3Guid)))
- {
- return EFI_INVALID_PARAMETER;
- }
-
- //
- // Allocate a buffer for the caller
- //
- *FwVolHeader = AllocatePool (TempFvh.HeaderLength);
- if (*FwVolHeader == NULL) {
- return EFI_OUT_OF_RESOURCES;
- }
-
- //
- // Copy the standard header into the buffer
- //
- CopyMem (*FwVolHeader, &TempFvh, sizeof (EFI_FIRMWARE_VOLUME_HEADER));
-
- //
- // Read the rest of the header
- //
- FvhLength = TempFvh.HeaderLength - sizeof (EFI_FIRMWARE_VOLUME_HEADER);
- Buffer = (UINT8 *)*FwVolHeader + sizeof (EFI_FIRMWARE_VOLUME_HEADER);
- Status = ReadFvbData (Fvb, &StartLba, &Offset, FvhLength, Buffer);
- if (EFI_ERROR (Status)) {
- //
- // Read failed so free buffer
- //
- CoreFreePool (*FwVolHeader);
- }
-
- return Status;
-}
-
-/**
- Free FvDevice resource when error happens
-
- @param FvDevice pointer to the FvDevice to be freed.
-
-**/
-VOID
-FreeFvDeviceResource (
- IN FV_DEVICE *FvDevice
- )
-{
- FFS_FILE_LIST_ENTRY *FfsFileEntry;
- LIST_ENTRY *NextEntry;
-
- //
- // Free File List Entry
- //
- FfsFileEntry = (FFS_FILE_LIST_ENTRY *)FvDevice->FfsFileListHeader.ForwardLink;
- while (&FfsFileEntry->Link != &FvDevice->FfsFileListHeader) {
- NextEntry = (&FfsFileEntry->Link)->ForwardLink;
-
- if (FfsFileEntry->StreamHandle != 0) {
- //
- // Close stream and free resources from SEP
- //
- CloseSectionStream (FfsFileEntry->StreamHandle, FALSE);
- }
-
- if (FfsFileEntry->FileCached) {
- //
- // Free the cached file buffer.
- //
- CoreFreePool (FfsFileEntry->FfsHeader);
- }
-
- CoreFreePool (FfsFileEntry);
-
- FfsFileEntry = (FFS_FILE_LIST_ENTRY *)NextEntry;
- }
-
- if (!FvDevice->IsMemoryMapped) {
- //
- // Free the cached FV buffer.
- //
- CoreFreePool (FvDevice->CachedFv);
- }
-
- //
- // Free Volume Header
- //
- CoreFreePool (FvDevice->FwVolHeader);
-
- return;
-}
-
-/**
- Check if an FV is consistent and allocate cache for it.
-
- @param FvDevice A pointer to the FvDevice to be checked.
-
- @retval EFI_OUT_OF_RESOURCES No enough buffer could be allocated.
- @retval EFI_SUCCESS FV is consistent and cache is allocated.
- @retval EFI_VOLUME_CORRUPTED File system is corrupted.
-
-**/
-EFI_STATUS
-FvCheck (
- IN OUT FV_DEVICE *FvDevice
- )
-{
- EFI_STATUS Status;
- EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb;
- EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader;
- EFI_FIRMWARE_VOLUME_EXT_HEADER *FwVolExtHeader;
- EFI_FVB_ATTRIBUTES_2 FvbAttributes;
- EFI_FV_BLOCK_MAP_ENTRY *BlockMap;
- FFS_FILE_LIST_ENTRY *FfsFileEntry;
- EFI_FFS_FILE_HEADER *FfsHeader;
- UINT8 *CacheLocation;
- UINTN Index;
- EFI_LBA LbaIndex;
- UINTN Size;
- EFI_FFS_FILE_STATE FileState;
- UINT8 *TopFvAddress;
- UINTN TestLength;
- EFI_PHYSICAL_ADDRESS PhysicalAddress;
- BOOLEAN FileCached;
- UINTN WholeFileSize;
- EFI_FFS_FILE_HEADER *CacheFfsHeader;
-
- FileCached = FALSE;
- CacheFfsHeader = NULL;
-
- Fvb = FvDevice->Fvb;
- FwVolHeader = FvDevice->FwVolHeader;
-
- Status = Fvb->GetAttributes (Fvb, &FvbAttributes);
- if (EFI_ERROR (Status)) {
- return Status;
- }
-
- Size = (UINTN)FwVolHeader->FvLength;
- if ((FvbAttributes & EFI_FVB2_MEMORY_MAPPED) != 0) {
- FvDevice->IsMemoryMapped = TRUE;
-
- Status = Fvb->GetPhysicalAddress (Fvb, &PhysicalAddress);
- if (EFI_ERROR (Status)) {
- return Status;
- }
-
- //
- // Don't cache memory mapped FV really.
- //
- FvDevice->CachedFv = (UINT8 *)(UINTN)PhysicalAddress;
- } else {
- FvDevice->IsMemoryMapped = FALSE;
- FvDevice->CachedFv = AllocatePool (Size);
-
- if (FvDevice->CachedFv == NULL) {
- return EFI_OUT_OF_RESOURCES;
- }
- }
-
- //
- // Remember a pointer to the end of the CachedFv
- //
- FvDevice->EndOfCachedFv = FvDevice->CachedFv + Size;
-
- if (!FvDevice->IsMemoryMapped) {
- //
- // Copy FV into memory using the block map.
- //
- BlockMap = FwVolHeader->BlockMap;
- CacheLocation = FvDevice->CachedFv;
- LbaIndex = 0;
- while ((BlockMap->NumBlocks != 0) || (BlockMap->Length != 0)) {
- //
- // read the FV data
- //
- Size = BlockMap->Length;
- for (Index = 0; Index < BlockMap->NumBlocks; Index++) {
- Status = Fvb->Read (
- Fvb,
- LbaIndex,
- 0,
- &Size,
- CacheLocation
- );
-
- //
- // Not check EFI_BAD_BUFFER_SIZE, for Size = BlockMap->Length
- //
- if (EFI_ERROR (Status)) {
- goto Done;
- }
-
- LbaIndex++;
- CacheLocation += BlockMap->Length;
- }
-
- BlockMap++;
- }
- }
-
- //
- // Scan to check the free space & File list
- //
- if ((FvbAttributes & EFI_FVB2_ERASE_POLARITY) != 0) {
- FvDevice->ErasePolarity = 1;
- } else {
- FvDevice->ErasePolarity = 0;
- }
-
- //
- // go through the whole FV cache, check the consistence of the FV.
- // Make a linked list of all the Ffs file headers
- //
- Status = EFI_SUCCESS;
- InitializeListHead (&FvDevice->FfsFileListHeader);
-
- //
- // Build FFS list
- //
- if (FwVolHeader->ExtHeaderOffset != 0) {
- //
- // Searching for files starts on an 8 byte aligned boundary after the end of the Extended Header if it exists.
- //
- FwVolExtHeader = (EFI_FIRMWARE_VOLUME_EXT_HEADER *)(FvDevice->CachedFv + FwVolHeader->ExtHeaderOffset);
- FfsHeader = (EFI_FFS_FILE_HEADER *)((UINT8 *)FwVolExtHeader + FwVolExtHeader->ExtHeaderSize);
- } else {
- FfsHeader = (EFI_FFS_FILE_HEADER *)(FvDevice->CachedFv + FwVolHeader->HeaderLength);
- }
-
- FfsHeader = (EFI_FFS_FILE_HEADER *)ALIGN_POINTER (FfsHeader, 8);
- TopFvAddress = FvDevice->EndOfCachedFv;
- while (((UINTN)FfsHeader >= (UINTN)FvDevice->CachedFv) && ((UINTN)FfsHeader <= (UINTN)((UINTN)TopFvAddress - sizeof (EFI_FFS_FILE_HEADER)))) {
- if (FileCached) {
- CoreFreePool (CacheFfsHeader);
- FileCached = FALSE;
- }
-
- TestLength = TopFvAddress - ((UINT8 *)FfsHeader);
- if (TestLength > sizeof (EFI_FFS_FILE_HEADER)) {
- TestLength = sizeof (EFI_FFS_FILE_HEADER);
- }
-
- if (IsBufferErased (FvDevice->ErasePolarity, FfsHeader, TestLength)) {
- //
- // We have found the free space so we are done!
- //
- goto Done;
- }
-
- if (!IsValidFfsHeader (FvDevice->ErasePolarity, FfsHeader, &FileState)) {
- if ((FileState == EFI_FILE_HEADER_INVALID) ||
- (FileState == EFI_FILE_HEADER_CONSTRUCTION))
- {
- if (IS_FFS_FILE2 (FfsHeader)) {
- if (!FvDevice->IsFfs3Fv) {
- DEBUG ((DEBUG_ERROR, "Found a FFS3 formatted file: %g in a non-FFS3 formatted FV.\n", &FfsHeader->Name));
- }
-
- FfsHeader = (EFI_FFS_FILE_HEADER *)((UINT8 *)FfsHeader + sizeof (EFI_FFS_FILE_HEADER2));
- } else {
- FfsHeader = (EFI_FFS_FILE_HEADER *)((UINT8 *)FfsHeader + sizeof (EFI_FFS_FILE_HEADER));
- }
-
- continue;
- } else {
- //
- // File system is corrputed
- //
- Status = EFI_VOLUME_CORRUPTED;
- goto Done;
- }
- }
-
- CacheFfsHeader = FfsHeader;
- if ((CacheFfsHeader->Attributes & FFS_ATTRIB_CHECKSUM) == FFS_ATTRIB_CHECKSUM) {
- if (FvDevice->IsMemoryMapped) {
- //
- // Memory mapped FV has not been cached.
- // Here is to cache FFS file to memory buffer for following checksum calculating.
- // And then, the cached file buffer can be also used for FvReadFile.
- //
- WholeFileSize = IS_FFS_FILE2 (CacheFfsHeader) ? FFS_FILE2_SIZE (CacheFfsHeader) : FFS_FILE_SIZE (CacheFfsHeader);
- CacheFfsHeader = AllocateCopyPool (WholeFileSize, CacheFfsHeader);
- if (CacheFfsHeader == NULL) {
- Status = EFI_OUT_OF_RESOURCES;
- goto Done;
- }
-
- FileCached = TRUE;
- }
- }
-
- if (!IsValidFfsFile (FvDevice->ErasePolarity, CacheFfsHeader)) {
- //
- // File system is corrupted
- //
- Status = EFI_VOLUME_CORRUPTED;
- goto Done;
- }
-
- if (IS_FFS_FILE2 (CacheFfsHeader)) {
- ASSERT (FFS_FILE2_SIZE (CacheFfsHeader) > 0x00FFFFFF);
- if (!FvDevice->IsFfs3Fv) {
- DEBUG ((DEBUG_ERROR, "Found a FFS3 formatted file: %g in a non-FFS3 formatted FV.\n", &CacheFfsHeader->Name));
- FfsHeader = (EFI_FFS_FILE_HEADER *)((UINT8 *)FfsHeader + FFS_FILE2_SIZE (CacheFfsHeader));
- //
- // Adjust pointer to the next 8-byte aligned boundary.
- //
- FfsHeader = (EFI_FFS_FILE_HEADER *)(((UINTN)FfsHeader + 7) & ~0x07);
- continue;
- }
- }
-
- FileState = GetFileState (FvDevice->ErasePolarity, CacheFfsHeader);
-
- //
- // check for non-deleted file
- //
- if (FileState != EFI_FILE_DELETED) {
- //
- // Create a FFS list entry for each non-deleted file
- //
- FfsFileEntry = AllocateZeroPool (sizeof (FFS_FILE_LIST_ENTRY));
- if (FfsFileEntry == NULL) {
- Status = EFI_OUT_OF_RESOURCES;
- goto Done;
- }
-
- FfsFileEntry->FfsHeader = CacheFfsHeader;
- FfsFileEntry->FileCached = FileCached;
- FileCached = FALSE;
- InsertTailList (&FvDevice->FfsFileListHeader, &FfsFileEntry->Link);
- }
-
- if (IS_FFS_FILE2 (CacheFfsHeader)) {
- FfsHeader = (EFI_FFS_FILE_HEADER *)((UINT8 *)FfsHeader + FFS_FILE2_SIZE (CacheFfsHeader));
- } else {
- FfsHeader = (EFI_FFS_FILE_HEADER *)((UINT8 *)FfsHeader + FFS_FILE_SIZE (CacheFfsHeader));
- }
-
- //
- // Adjust pointer to the next 8-byte aligned boundary.
- //
- FfsHeader = (EFI_FFS_FILE_HEADER *)(((UINTN)FfsHeader + 7) & ~0x07);
- }
-
-Done:
- if (EFI_ERROR (Status)) {
- if (FileCached) {
- CoreFreePool (CacheFfsHeader);
- FileCached = FALSE;
- }
-
- FreeFvDeviceResource (FvDevice);
- }
-
- return Status;
-}
-
-/**
- This notification function is invoked when an instance of the
- EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL is produced. It layers an instance of the
- EFI_FIRMWARE_VOLUME2_PROTOCOL on the same handle. This is the function where
- the actual initialization of the EFI_FIRMWARE_VOLUME2_PROTOCOL is done.
-
- @param Event The event that occurred
- @param Context For EFI compatiblity. Not used.
-
-**/
-VOID
-EFIAPI
-NotifyFwVolBlock (
- IN EFI_EVENT Event,
- IN VOID *Context
- )
-{
- EFI_HANDLE Handle;
- EFI_STATUS Status;
- UINTN BufferSize;
- EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb;
- EFI_FIRMWARE_VOLUME2_PROTOCOL *Fv;
- FV_DEVICE *FvDevice;
- EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader;
-
- //
- // Examine all new handles
- //
- for ( ; ;) {
- //
- // Get the next handle
- //
- BufferSize = sizeof (Handle);
- Status = CoreLocateHandle (
- ByRegisterNotify,
- NULL,
- gEfiFwVolBlockNotifyReg,
- &BufferSize,
- &Handle
- );
-
- //
- // If not found, we're done
- //
- if (EFI_NOT_FOUND == Status) {
- break;
- }
-
- if (EFI_ERROR (Status)) {
- continue;
- }
-
- //
- // Get the FirmwareVolumeBlock protocol on that handle
- //
- Status = CoreHandleProtocol (Handle, &gEfiFirmwareVolumeBlockProtocolGuid, (VOID **)&Fvb);
- ASSERT_EFI_ERROR (Status);
- ASSERT (Fvb != NULL);
-
- //
- // Make sure the Fv Header is O.K.
- //
- Status = GetFwVolHeader (Fvb, &FwVolHeader);
- if (EFI_ERROR (Status)) {
- continue;
- }
-
- ASSERT (FwVolHeader != NULL);
-
- if (!VerifyFvHeaderChecksum (FwVolHeader)) {
- CoreFreePool (FwVolHeader);
- continue;
- }
-
- //
- // Check if there is an FV protocol already installed in that handle
- //
- Status = CoreHandleProtocol (Handle, &gEfiFirmwareVolume2ProtocolGuid, (VOID **)&Fv);
- if (!EFI_ERROR (Status)) {
- //
- // Update Fv to use a new Fvb
- //
- FvDevice = BASE_CR (Fv, FV_DEVICE, Fv);
- if (FvDevice->Signature == FV2_DEVICE_SIGNATURE) {
- //
- // Only write into our device structure if it's our device structure
- //
- FvDevice->Fvb = Fvb;
- }
- } else {
- //
- // No FwVol protocol on the handle so create a new one
- //
- FvDevice = AllocateCopyPool (sizeof (FV_DEVICE), &mFvDevice);
- if (FvDevice == NULL) {
- CoreFreePool (FwVolHeader);
- return;
- }
-
- FvDevice->Fvb = Fvb;
- FvDevice->Handle = Handle;
- FvDevice->FwVolHeader = FwVolHeader;
- FvDevice->IsFfs3Fv = CompareGuid (&FwVolHeader->FileSystemGuid, &gEfiFirmwareFileSystem3Guid);
- FvDevice->Fv.ParentHandle = Fvb->ParentHandle;
- //
- // Inherit the authentication status from FVB.
- //
- FvDevice->AuthenticationStatus = GetFvbAuthenticationStatus (Fvb);
-
- if (!EFI_ERROR (FvCheck (FvDevice))) {
- //
- // Install an New FV protocol on the existing handle
- //
- Status = CoreInstallProtocolInterface (
- &Handle,
- &gEfiFirmwareVolume2ProtocolGuid,
- EFI_NATIVE_INTERFACE,
- &FvDevice->Fv
- );
- ASSERT_EFI_ERROR (Status);
- } else {
- //
- // Free FvDevice Buffer for the corrupt FV image.
- //
- CoreFreePool (FvDevice);
- }
- }
- }
-
- return;
-}
-
-/**
- This routine is the driver initialization entry point. It registers
- a notification function. This notification function are responsible
- for building the FV stack dynamically.
-
- @param ImageHandle The image handle.
- @param SystemTable The system table.
-
- @retval EFI_SUCCESS Function successfully returned.
-
-**/
-EFI_STATUS
-EFIAPI
-FwVolDriverInit (
- IN EFI_HANDLE ImageHandle,
- IN EFI_SYSTEM_TABLE *SystemTable
- )
-{
- gEfiFwVolBlockEvent = EfiCreateProtocolNotifyEvent (
- &gEfiFirmwareVolumeBlockProtocolGuid,
- TPL_CALLBACK,
- NotifyFwVolBlock,
- NULL,
- &gEfiFwVolBlockNotifyReg
- );
- return EFI_SUCCESS;
-}
+/** @file
+ Firmware File System driver that produce Firmware Volume protocol.
+ Layers on top of Firmware Block protocol to produce a file abstraction
+ of FV based files.
+
+Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "DxeMain.h"
+#include "FwVolDriver.h"
+
+//
+// Protocol notify related globals
+//
+VOID *gEfiFwVolBlockNotifyReg;
+EFI_EVENT gEfiFwVolBlockEvent;
+
+FV_DEVICE mFvDevice = {
+ FV2_DEVICE_SIGNATURE,
+ NULL,
+ NULL,
+ {
+ FvGetVolumeAttributes,
+ FvSetVolumeAttributes,
+ FvReadFile,
+ FvReadFileSection,
+ FvWriteFile,
+ FvGetNextFile,
+ sizeof (UINTN),
+ NULL,
+ FvGetVolumeInfo,
+ FvSetVolumeInfo
+ },
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ { NULL, NULL},
+ 0,
+ 0,
+ FALSE,
+ FALSE
+};
+
+//
+// FFS helper functions
+//
+
+/**
+ Read data from Firmware Block by FVB protocol Read.
+ The data may cross the multi block ranges.
+
+ @param Fvb The FW_VOL_BLOCK_PROTOCOL instance from which to read data.
+ @param StartLba Pointer to StartLba.
+ On input, the start logical block index from which to read.
+ On output,the end logical block index after reading.
+ @param Offset Pointer to Offset
+ On input, offset into the block at which to begin reading.
+ On output, offset into the end block after reading.
+ @param DataSize Size of data to be read.
+ @param Data Pointer to Buffer that the data will be read into.
+
+ @retval EFI_SUCCESS Successfully read data from firmware block.
+ @retval others
+**/
+EFI_STATUS
+ReadFvbData (
+ IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb,
+ IN OUT EFI_LBA *StartLba,
+ IN OUT UINTN *Offset,
+ IN UINTN DataSize,
+ OUT UINT8 *Data
+ )
+{
+ UINTN BlockSize;
+ UINTN NumberOfBlocks;
+ UINTN BlockIndex;
+ UINTN ReadDataSize;
+ EFI_STATUS Status;
+
+ //
+ // Try read data in current block
+ //
+ BlockIndex = 0;
+ ReadDataSize = DataSize;
+ Status = Fvb->Read (Fvb, *StartLba, *Offset, &ReadDataSize, Data);
+ if (Status == EFI_SUCCESS) {
+ *Offset += DataSize;
+ return EFI_SUCCESS;
+ } else if (Status != EFI_BAD_BUFFER_SIZE) {
+ //
+ // other error will direct return
+ //
+ return Status;
+ }
+
+ //
+ // Data crosses the blocks, read data from next block
+ //
+ DataSize -= ReadDataSize;
+ Data += ReadDataSize;
+ *StartLba = *StartLba + 1;
+ while (DataSize > 0) {
+ Status = Fvb->GetBlockSize (Fvb, *StartLba, &BlockSize, &NumberOfBlocks);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Read data from the crossing blocks
+ //
+ BlockIndex = 0;
+ while (BlockIndex < NumberOfBlocks && DataSize >= BlockSize) {
+ Status = Fvb->Read (Fvb, *StartLba + BlockIndex, 0, &BlockSize, Data);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Data += BlockSize;
+ DataSize -= BlockSize;
+ BlockIndex++;
+ }
+
+ //
+ // Data doesn't exceed the current block range.
+ //
+ if (DataSize < BlockSize) {
+ break;
+ }
+
+ //
+ // Data must be got from the next block range.
+ //
+ *StartLba += NumberOfBlocks;
+ }
+
+ //
+ // read the remaining data
+ //
+ if (DataSize > 0) {
+ Status = Fvb->Read (Fvb, *StartLba + BlockIndex, 0, &DataSize, Data);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+
+ //
+ // Update Lba and Offset used by the following read.
+ //
+ *StartLba += BlockIndex;
+ *Offset = DataSize;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Given the supplied FW_VOL_BLOCK_PROTOCOL, allocate a buffer for output and
+ copy the real length volume header into it.
+
+ @param Fvb The FW_VOL_BLOCK_PROTOCOL instance from which to
+ read the volume header
+ @param FwVolHeader Pointer to pointer to allocated buffer in which
+ the volume header is returned.
+
+ @retval EFI_OUT_OF_RESOURCES No enough buffer could be allocated.
+ @retval EFI_SUCCESS Successfully read volume header to the allocated
+ buffer.
+ @retval EFI_INVALID_PARAMETER The FV Header signature is not as expected or
+ the file system could not be understood.
+
+**/
+EFI_STATUS
+GetFwVolHeader (
+ IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb,
+ OUT EFI_FIRMWARE_VOLUME_HEADER **FwVolHeader
+ )
+{
+ EFI_STATUS Status;
+ EFI_FIRMWARE_VOLUME_HEADER TempFvh;
+ UINTN FvhLength;
+ EFI_LBA StartLba;
+ UINTN Offset;
+ UINT8 *Buffer;
+
+ //
+ // Read the standard FV header
+ //
+ StartLba = 0;
+ Offset = 0;
+ FvhLength = sizeof (EFI_FIRMWARE_VOLUME_HEADER);
+ Status = ReadFvbData (Fvb, &StartLba, &Offset, FvhLength, (UINT8 *)&TempFvh);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Validate FV Header signature, if not as expected, continue.
+ //
+ if (TempFvh.Signature != EFI_FVH_SIGNATURE) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Check to see that the file system is indeed formatted in a way we can
+ // understand it...
+ //
+ if ((!CompareGuid (&TempFvh.FileSystemGuid, &gEfiFirmwareFileSystem2Guid)) &&
+ (!CompareGuid (&TempFvh.FileSystemGuid, &gEfiFirmwareFileSystem3Guid)))
+ {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Allocate a buffer for the caller
+ //
+ *FwVolHeader = AllocatePool (TempFvh.HeaderLength);
+ if (*FwVolHeader == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ //
+ // Copy the standard header into the buffer
+ //
+ CopyMem (*FwVolHeader, &TempFvh, sizeof (EFI_FIRMWARE_VOLUME_HEADER));
+
+ //
+ // Read the rest of the header
+ //
+ FvhLength = TempFvh.HeaderLength - sizeof (EFI_FIRMWARE_VOLUME_HEADER);
+ Buffer = (UINT8 *)*FwVolHeader + sizeof (EFI_FIRMWARE_VOLUME_HEADER);
+ Status = ReadFvbData (Fvb, &StartLba, &Offset, FvhLength, Buffer);
+ if (EFI_ERROR (Status)) {
+ //
+ // Read failed so free buffer
+ //
+ CoreFreePool (*FwVolHeader);
+ }
+
+ return Status;
+}
+
+/**
+ Free FvDevice resource when error happens
+
+ @param FvDevice pointer to the FvDevice to be freed.
+
+**/
+VOID
+FreeFvDeviceResource (
+ IN FV_DEVICE *FvDevice
+ )
+{
+ FFS_FILE_LIST_ENTRY *FfsFileEntry;
+ LIST_ENTRY *NextEntry;
+
+ //
+ // Free File List Entry
+ //
+ FfsFileEntry = (FFS_FILE_LIST_ENTRY *)FvDevice->FfsFileListHeader.ForwardLink;
+ while (&FfsFileEntry->Link != &FvDevice->FfsFileListHeader) {
+ NextEntry = (&FfsFileEntry->Link)->ForwardLink;
+
+ if (FfsFileEntry->StreamHandle != 0) {
+ //
+ // Close stream and free resources from SEP
+ //
+ CloseSectionStream (FfsFileEntry->StreamHandle, FALSE);
+ }
+
+ if (FfsFileEntry->FileCached) {
+ //
+ // Free the cached file buffer.
+ //
+ CoreFreePool (FfsFileEntry->FfsHeader);
+ }
+
+ CoreFreePool (FfsFileEntry);
+
+ FfsFileEntry = (FFS_FILE_LIST_ENTRY *)NextEntry;
+ }
+
+ if (!FvDevice->IsMemoryMapped) {
+ //
+ // Free the cached FV buffer.
+ //
+ CoreFreePool (FvDevice->CachedFv);
+ }
+
+ //
+ // Free Volume Header
+ //
+ CoreFreePool (FvDevice->FwVolHeader);
+
+ return;
+}
+
+/**
+ Check if an FV is consistent and allocate cache for it.
+
+ @param FvDevice A pointer to the FvDevice to be checked.
+
+ @retval EFI_OUT_OF_RESOURCES No enough buffer could be allocated.
+ @retval EFI_SUCCESS FV is consistent and cache is allocated.
+ @retval EFI_VOLUME_CORRUPTED File system is corrupted.
+
+**/
+EFI_STATUS
+FvCheck (
+ IN OUT FV_DEVICE *FvDevice
+ )
+{
+ EFI_STATUS Status;
+ EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb;
+ EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader;
+ EFI_FIRMWARE_VOLUME_EXT_HEADER *FwVolExtHeader;
+ EFI_FVB_ATTRIBUTES_2 FvbAttributes;
+ EFI_FV_BLOCK_MAP_ENTRY *BlockMap;
+ FFS_FILE_LIST_ENTRY *FfsFileEntry;
+ EFI_FFS_FILE_HEADER *FfsHeader;
+ UINT8 *CacheLocation;
+ UINTN Index;
+ EFI_LBA LbaIndex;
+ UINTN Size;
+ EFI_FFS_FILE_STATE FileState;
+ UINT8 *TopFvAddress;
+ UINTN TestLength;
+ EFI_PHYSICAL_ADDRESS PhysicalAddress;
+ BOOLEAN FileCached;
+ UINTN WholeFileSize;
+ EFI_FFS_FILE_HEADER *CacheFfsHeader;
+
+ FileCached = FALSE;
+ CacheFfsHeader = NULL;
+
+ Fvb = FvDevice->Fvb;
+ FwVolHeader = FvDevice->FwVolHeader;
+
+ Status = Fvb->GetAttributes (Fvb, &FvbAttributes);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Size = (UINTN)FwVolHeader->FvLength;
+ if ((FvbAttributes & EFI_FVB2_MEMORY_MAPPED) != 0) {
+ FvDevice->IsMemoryMapped = TRUE;
+
+ Status = Fvb->GetPhysicalAddress (Fvb, &PhysicalAddress);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Don't cache memory mapped FV really.
+ //
+ FvDevice->CachedFv = (UINT8 *)(UINTN)PhysicalAddress;
+ } else {
+ FvDevice->IsMemoryMapped = FALSE;
+ FvDevice->CachedFv = AllocatePool (Size);
+
+ if (FvDevice->CachedFv == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ }
+
+ //
+ // Remember a pointer to the end of the CachedFv
+ //
+ FvDevice->EndOfCachedFv = FvDevice->CachedFv + Size;
+
+ if (!FvDevice->IsMemoryMapped) {
+ //
+ // Copy FV into memory using the block map.
+ //
+ BlockMap = FwVolHeader->BlockMap;
+ CacheLocation = FvDevice->CachedFv;
+ LbaIndex = 0;
+ while ((BlockMap->NumBlocks != 0) || (BlockMap->Length != 0)) {
+ //
+ // read the FV data
+ //
+ Size = BlockMap->Length;
+ for (Index = 0; Index < BlockMap->NumBlocks; Index++) {
+ Status = Fvb->Read (
+ Fvb,
+ LbaIndex,
+ 0,
+ &Size,
+ CacheLocation
+ );
+
+ //
+ // Not check EFI_BAD_BUFFER_SIZE, for Size = BlockMap->Length
+ //
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ LbaIndex++;
+ CacheLocation += BlockMap->Length;
+ }
+
+ BlockMap++;
+ }
+ }
+
+ //
+ // Scan to check the free space & File list
+ //
+ if ((FvbAttributes & EFI_FVB2_ERASE_POLARITY) != 0) {
+ FvDevice->ErasePolarity = 1;
+ } else {
+ FvDevice->ErasePolarity = 0;
+ }
+
+ //
+ // go through the whole FV cache, check the consistence of the FV.
+ // Make a linked list of all the Ffs file headers
+ //
+ Status = EFI_SUCCESS;
+ InitializeListHead (&FvDevice->FfsFileListHeader);
+
+ //
+ // Build FFS list
+ //
+ if (FwVolHeader->ExtHeaderOffset != 0) {
+ //
+ // Searching for files starts on an 8 byte aligned boundary after the end of the Extended Header if it exists.
+ //
+ FwVolExtHeader = (EFI_FIRMWARE_VOLUME_EXT_HEADER *)(FvDevice->CachedFv + FwVolHeader->ExtHeaderOffset);
+ FfsHeader = (EFI_FFS_FILE_HEADER *)((UINT8 *)FwVolExtHeader + FwVolExtHeader->ExtHeaderSize);
+ } else {
+ FfsHeader = (EFI_FFS_FILE_HEADER *)(FvDevice->CachedFv + FwVolHeader->HeaderLength);
+ }
+
+ FfsHeader = (EFI_FFS_FILE_HEADER *)ALIGN_POINTER (FfsHeader, 8);
+ TopFvAddress = FvDevice->EndOfCachedFv;
+ while (((UINTN)FfsHeader >= (UINTN)FvDevice->CachedFv) && ((UINTN)FfsHeader <= (UINTN)((UINTN)TopFvAddress - sizeof (EFI_FFS_FILE_HEADER)))) {
+ if (FileCached) {
+ CoreFreePool (CacheFfsHeader);
+ FileCached = FALSE;
+ }
+
+ TestLength = TopFvAddress - ((UINT8 *)FfsHeader);
+ if (TestLength > sizeof (EFI_FFS_FILE_HEADER)) {
+ TestLength = sizeof (EFI_FFS_FILE_HEADER);
+ }
+
+ if (IsBufferErased (FvDevice->ErasePolarity, FfsHeader, TestLength)) {
+ //
+ // We have found the free space so we are done!
+ //
+ goto Done;
+ }
+
+ if (!IsValidFfsHeader (FvDevice->ErasePolarity, FfsHeader, &FileState)) {
+ if ((FileState == EFI_FILE_HEADER_INVALID) ||
+ (FileState == EFI_FILE_HEADER_CONSTRUCTION))
+ {
+ if (IS_FFS_FILE2 (FfsHeader)) {
+ if (!FvDevice->IsFfs3Fv) {
+ DEBUG ((DEBUG_ERROR, "Found a FFS3 formatted file: %g in a non-FFS3 formatted FV.\n", &FfsHeader->Name));
+ }
+
+ FfsHeader = (EFI_FFS_FILE_HEADER *)((UINT8 *)FfsHeader + sizeof (EFI_FFS_FILE_HEADER2));
+ } else {
+ FfsHeader = (EFI_FFS_FILE_HEADER *)((UINT8 *)FfsHeader + sizeof (EFI_FFS_FILE_HEADER));
+ }
+
+ continue;
+ } else {
+ //
+ // File system is corrputed
+ //
+ Status = EFI_VOLUME_CORRUPTED;
+ goto Done;
+ }
+ }
+
+ CacheFfsHeader = FfsHeader;
+ if ((CacheFfsHeader->Attributes & FFS_ATTRIB_CHECKSUM) == FFS_ATTRIB_CHECKSUM) {
+ if (FvDevice->IsMemoryMapped) {
+ //
+ // Memory mapped FV has not been cached.
+ // Here is to cache FFS file to memory buffer for following checksum calculating.
+ // And then, the cached file buffer can be also used for FvReadFile.
+ //
+ WholeFileSize = IS_FFS_FILE2 (CacheFfsHeader) ? FFS_FILE2_SIZE (CacheFfsHeader) : FFS_FILE_SIZE (CacheFfsHeader);
+ CacheFfsHeader = AllocateCopyPool (WholeFileSize, CacheFfsHeader);
+ if (CacheFfsHeader == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Done;
+ }
+
+ FileCached = TRUE;
+ }
+ }
+
+ if (!IsValidFfsFile (FvDevice->ErasePolarity, CacheFfsHeader)) {
+ //
+ // File system is corrupted
+ //
+ Status = EFI_VOLUME_CORRUPTED;
+ goto Done;
+ }
+
+ if (IS_FFS_FILE2 (CacheFfsHeader)) {
+ ASSERT (FFS_FILE2_SIZE (CacheFfsHeader) > 0x00FFFFFF);
+ if (!FvDevice->IsFfs3Fv) {
+ DEBUG ((DEBUG_ERROR, "Found a FFS3 formatted file: %g in a non-FFS3 formatted FV.\n", &CacheFfsHeader->Name));
+ FfsHeader = (EFI_FFS_FILE_HEADER *)((UINT8 *)FfsHeader + FFS_FILE2_SIZE (CacheFfsHeader));
+ //
+ // Adjust pointer to the next 8-byte aligned boundary.
+ //
+ FfsHeader = (EFI_FFS_FILE_HEADER *)(((UINTN)FfsHeader + 7) & ~0x07);
+ continue;
+ }
+ }
+
+ FileState = GetFileState (FvDevice->ErasePolarity, CacheFfsHeader);
+
+ //
+ // check for non-deleted file
+ //
+ if (FileState != EFI_FILE_DELETED) {
+ //
+ // Create a FFS list entry for each non-deleted file
+ //
+ FfsFileEntry = AllocateZeroPool (sizeof (FFS_FILE_LIST_ENTRY));
+ if (FfsFileEntry == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Done;
+ }
+
+ FfsFileEntry->FfsHeader = CacheFfsHeader;
+ FfsFileEntry->FileCached = FileCached;
+ FileCached = FALSE;
+ InsertTailList (&FvDevice->FfsFileListHeader, &FfsFileEntry->Link);
+ }
+
+ if (IS_FFS_FILE2 (CacheFfsHeader)) {
+ FfsHeader = (EFI_FFS_FILE_HEADER *)((UINT8 *)FfsHeader + FFS_FILE2_SIZE (CacheFfsHeader));
+ } else {
+ FfsHeader = (EFI_FFS_FILE_HEADER *)((UINT8 *)FfsHeader + FFS_FILE_SIZE (CacheFfsHeader));
+ }
+
+ //
+ // Adjust pointer to the next 8-byte aligned boundary.
+ //
+ FfsHeader = (EFI_FFS_FILE_HEADER *)(((UINTN)FfsHeader + 7) & ~0x07);
+ }
+
+Done:
+ if (EFI_ERROR (Status)) {
+ if (FileCached) {
+ CoreFreePool (CacheFfsHeader);
+ FileCached = FALSE;
+ }
+
+ FreeFvDeviceResource (FvDevice);
+ }
+
+ return Status;
+}
+
+/**
+ This notification function is invoked when an instance of the
+ EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL is produced. It layers an instance of the
+ EFI_FIRMWARE_VOLUME2_PROTOCOL on the same handle. This is the function where
+ the actual initialization of the EFI_FIRMWARE_VOLUME2_PROTOCOL is done.
+
+ @param Event The event that occurred
+ @param Context For EFI compatiblity. Not used.
+
+**/
+VOID
+EFIAPI
+NotifyFwVolBlock (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ EFI_HANDLE Handle;
+ EFI_STATUS Status;
+ UINTN BufferSize;
+ EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb;
+ EFI_FIRMWARE_VOLUME2_PROTOCOL *Fv;
+ FV_DEVICE *FvDevice;
+ EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader;
+
+ //
+ // Examine all new handles
+ //
+ for ( ; ;) {
+ //
+ // Get the next handle
+ //
+ BufferSize = sizeof (Handle);
+ Status = CoreLocateHandle (
+ ByRegisterNotify,
+ NULL,
+ gEfiFwVolBlockNotifyReg,
+ &BufferSize,
+ &Handle
+ );
+
+ //
+ // If not found, we're done
+ //
+ if (EFI_NOT_FOUND == Status) {
+ break;
+ }
+
+ if (EFI_ERROR (Status)) {
+ continue;
+ }
+
+ //
+ // Get the FirmwareVolumeBlock protocol on that handle
+ //
+ Status = CoreHandleProtocol (Handle, &gEfiFirmwareVolumeBlockProtocolGuid, (VOID **)&Fvb);
+ ASSERT_EFI_ERROR (Status);
+ ASSERT (Fvb != NULL);
+
+ //
+ // Make sure the Fv Header is O.K.
+ //
+ Status = GetFwVolHeader (Fvb, &FwVolHeader);
+ if (EFI_ERROR (Status)) {
+ continue;
+ }
+
+ ASSERT (FwVolHeader != NULL);
+
+ if (!VerifyFvHeaderChecksum (FwVolHeader)) {
+ CoreFreePool (FwVolHeader);
+ continue;
+ }
+
+ //
+ // Check if there is an FV protocol already installed in that handle
+ //
+ Status = CoreHandleProtocol (Handle, &gEfiFirmwareVolume2ProtocolGuid, (VOID **)&Fv);
+ if (!EFI_ERROR (Status)) {
+ //
+ // Update Fv to use a new Fvb
+ //
+ FvDevice = BASE_CR (Fv, FV_DEVICE, Fv);
+ if (FvDevice->Signature == FV2_DEVICE_SIGNATURE) {
+ //
+ // Only write into our device structure if it's our device structure
+ //
+ FvDevice->Fvb = Fvb;
+ }
+ } else {
+ //
+ // No FwVol protocol on the handle so create a new one
+ //
+ FvDevice = AllocateCopyPool (sizeof (FV_DEVICE), &mFvDevice);
+ if (FvDevice == NULL) {
+ CoreFreePool (FwVolHeader);
+ return;
+ }
+
+ FvDevice->Fvb = Fvb;
+ FvDevice->Handle = Handle;
+ FvDevice->FwVolHeader = FwVolHeader;
+ FvDevice->IsFfs3Fv = CompareGuid (&FwVolHeader->FileSystemGuid, &gEfiFirmwareFileSystem3Guid);
+ FvDevice->Fv.ParentHandle = Fvb->ParentHandle;
+ //
+ // Inherit the authentication status from FVB.
+ //
+ FvDevice->AuthenticationStatus = GetFvbAuthenticationStatus (Fvb);
+
+ if (!EFI_ERROR (FvCheck (FvDevice))) {
+ //
+ // Install an New FV protocol on the existing handle
+ //
+ Status = CoreInstallProtocolInterface (
+ &Handle,
+ &gEfiFirmwareVolume2ProtocolGuid,
+ EFI_NATIVE_INTERFACE,
+ &FvDevice->Fv
+ );
+ ASSERT_EFI_ERROR (Status);
+ } else {
+ //
+ // Free FvDevice Buffer for the corrupt FV image.
+ //
+ CoreFreePool (FvDevice);
+ }
+ }
+ }
+
+ return;
+}
+
+/**
+ This routine is the driver initialization entry point. It registers
+ a notification function. This notification function are responsible
+ for building the FV stack dynamically.
+
+ @param ImageHandle The image handle.
+ @param SystemTable The system table.
+
+ @retval EFI_SUCCESS Function successfully returned.
+
+**/
+EFI_STATUS
+EFIAPI
+FwVolDriverInit (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ gEfiFwVolBlockEvent = EfiCreateProtocolNotifyEvent (
+ &gEfiFirmwareVolumeBlockProtocolGuid,
+ TPL_CALLBACK,
+ NotifyFwVolBlock,
+ NULL,
+ &gEfiFwVolBlockNotifyReg
+ );
+ return EFI_SUCCESS;
+}
diff --git a/MdeModulePkg/Core/Dxe/FwVol/FwVolAttrib.c b/MdeModulePkg/Core/Dxe/FwVol/FwVolAttrib.c
index eed9f86305..60b82c45c8 100644
--- a/MdeModulePkg/Core/Dxe/FwVol/FwVolAttrib.c
+++ b/MdeModulePkg/Core/Dxe/FwVol/FwVolAttrib.c
@@ -1,120 +1,120 @@
-/** @file
- Implements get/set firmware volume attributes
-
-Copyright (c) 2006 - 2012, Intel Corporation. All rights reserved.<BR>
-SPDX-License-Identifier: BSD-2-Clause-Patent
-
-**/
-
-#include "DxeMain.h"
-#include "FwVolDriver.h"
-
-/**
- Retrieves attributes, insures positive polarity of attribute bits, returns
- resulting attributes in output parameter.
-
- @param This Calling context
- @param Attributes output buffer which contains attributes
-
- @retval EFI_SUCCESS Successfully got volume attributes
-
-**/
-EFI_STATUS
-EFIAPI
-FvGetVolumeAttributes (
- IN CONST EFI_FIRMWARE_VOLUME2_PROTOCOL *This,
- OUT EFI_FV_ATTRIBUTES *Attributes
- )
-{
- EFI_STATUS Status;
- FV_DEVICE *FvDevice;
- EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb;
- EFI_FVB_ATTRIBUTES_2 FvbAttributes;
-
- FvDevice = FV_DEVICE_FROM_THIS (This);
- Fvb = FvDevice->Fvb;
-
- //
- // First get the Firmware Volume Block Attributes
- //
- Status = Fvb->GetAttributes (Fvb, &FvbAttributes);
-
- //
- // Mask out Fvb bits that are not defined in FV
- //
- FvbAttributes &= 0xfffff0ff;
-
- *Attributes = (EFI_FV_ATTRIBUTES)FvbAttributes;
-
- return Status;
-}
-
-/**
- Sets current attributes for volume
-
- @param This Calling context
- @param Attributes At input, contains attributes to be set. At output
- contains new value of FV
-
- @retval EFI_UNSUPPORTED Could not be set.
-
-**/
-EFI_STATUS
-EFIAPI
-FvSetVolumeAttributes (
- IN CONST EFI_FIRMWARE_VOLUME2_PROTOCOL *This,
- IN OUT EFI_FV_ATTRIBUTES *Attributes
- )
-{
- return EFI_UNSUPPORTED;
-}
-
-/**
- Return information of type InformationType for the requested firmware
- volume.
-
- @param This Pointer to EFI_FIRMWARE_VOLUME2_PROTOCOL.
- @param InformationType InformationType for requested.
- @param BufferSize On input, size of Buffer.On output, the amount of data
- returned in Buffer.
- @param Buffer A poniter to the data buffer to return.
-
- @retval EFI_SUCCESS Successfully got volume Information.
-
-**/
-EFI_STATUS
-EFIAPI
-FvGetVolumeInfo (
- IN CONST EFI_FIRMWARE_VOLUME2_PROTOCOL *This,
- IN CONST EFI_GUID *InformationType,
- IN OUT UINTN *BufferSize,
- OUT VOID *Buffer
- )
-{
- return EFI_UNSUPPORTED;
-}
-
-/**
- Set information of type InformationType for the requested firmware
- volume.
-
- @param This Pointer to EFI_FIRMWARE_VOLUME2_PROTOCOL.
- @param InformationType InformationType for requested.
- @param BufferSize On input, size of Buffer.On output, the amount of data
- returned in Buffer.
- @param Buffer A poniter to the data buffer to return.
-
- @retval EFI_SUCCESS Successfully set volume Information.
-
-**/
-EFI_STATUS
-EFIAPI
-FvSetVolumeInfo (
- IN CONST EFI_FIRMWARE_VOLUME2_PROTOCOL *This,
- IN CONST EFI_GUID *InformationType,
- IN UINTN BufferSize,
- IN CONST VOID *Buffer
- )
-{
- return EFI_UNSUPPORTED;
-}
+/** @file
+ Implements get/set firmware volume attributes
+
+Copyright (c) 2006 - 2012, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "DxeMain.h"
+#include "FwVolDriver.h"
+
+/**
+ Retrieves attributes, insures positive polarity of attribute bits, returns
+ resulting attributes in output parameter.
+
+ @param This Calling context
+ @param Attributes output buffer which contains attributes
+
+ @retval EFI_SUCCESS Successfully got volume attributes
+
+**/
+EFI_STATUS
+EFIAPI
+FvGetVolumeAttributes (
+ IN CONST EFI_FIRMWARE_VOLUME2_PROTOCOL *This,
+ OUT EFI_FV_ATTRIBUTES *Attributes
+ )
+{
+ EFI_STATUS Status;
+ FV_DEVICE *FvDevice;
+ EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb;
+ EFI_FVB_ATTRIBUTES_2 FvbAttributes;
+
+ FvDevice = FV_DEVICE_FROM_THIS (This);
+ Fvb = FvDevice->Fvb;
+
+ //
+ // First get the Firmware Volume Block Attributes
+ //
+ Status = Fvb->GetAttributes (Fvb, &FvbAttributes);
+
+ //
+ // Mask out Fvb bits that are not defined in FV
+ //
+ FvbAttributes &= 0xfffff0ff;
+
+ *Attributes = (EFI_FV_ATTRIBUTES)FvbAttributes;
+
+ return Status;
+}
+
+/**
+ Sets current attributes for volume
+
+ @param This Calling context
+ @param Attributes At input, contains attributes to be set. At output
+ contains new value of FV
+
+ @retval EFI_UNSUPPORTED Could not be set.
+
+**/
+EFI_STATUS
+EFIAPI
+FvSetVolumeAttributes (
+ IN CONST EFI_FIRMWARE_VOLUME2_PROTOCOL *This,
+ IN OUT EFI_FV_ATTRIBUTES *Attributes
+ )
+{
+ return EFI_UNSUPPORTED;
+}
+
+/**
+ Return information of type InformationType for the requested firmware
+ volume.
+
+ @param This Pointer to EFI_FIRMWARE_VOLUME2_PROTOCOL.
+ @param InformationType InformationType for requested.
+ @param BufferSize On input, size of Buffer.On output, the amount of data
+ returned in Buffer.
+ @param Buffer A poniter to the data buffer to return.
+
+ @retval EFI_SUCCESS Successfully got volume Information.
+
+**/
+EFI_STATUS
+EFIAPI
+FvGetVolumeInfo (
+ IN CONST EFI_FIRMWARE_VOLUME2_PROTOCOL *This,
+ IN CONST EFI_GUID *InformationType,
+ IN OUT UINTN *BufferSize,
+ OUT VOID *Buffer
+ )
+{
+ return EFI_UNSUPPORTED;
+}
+
+/**
+ Set information of type InformationType for the requested firmware
+ volume.
+
+ @param This Pointer to EFI_FIRMWARE_VOLUME2_PROTOCOL.
+ @param InformationType InformationType for requested.
+ @param BufferSize On input, size of Buffer.On output, the amount of data
+ returned in Buffer.
+ @param Buffer A poniter to the data buffer to return.
+
+ @retval EFI_SUCCESS Successfully set volume Information.
+
+**/
+EFI_STATUS
+EFIAPI
+FvSetVolumeInfo (
+ IN CONST EFI_FIRMWARE_VOLUME2_PROTOCOL *This,
+ IN CONST EFI_GUID *InformationType,
+ IN UINTN BufferSize,
+ IN CONST VOID *Buffer
+ )
+{
+ return EFI_UNSUPPORTED;
+}
diff --git a/MdeModulePkg/Core/Dxe/FwVol/FwVolDriver.h b/MdeModulePkg/Core/Dxe/FwVol/FwVolDriver.h
index 3403c812b2..19855c915b 100644
--- a/MdeModulePkg/Core/Dxe/FwVol/FwVolDriver.h
+++ b/MdeModulePkg/Core/Dxe/FwVol/FwVolDriver.h
@@ -1,387 +1,387 @@
-/** @file
- Firmware File System protocol. Layers on top of Firmware
- Block protocol to produce a file abstraction of FV based files.
-
-Copyright (c) 2006 - 2014, Intel Corporation. All rights reserved.<BR>
-SPDX-License-Identifier: BSD-2-Clause-Patent
-
-**/
-
-#ifndef __FW_VOL_DRIVER_H_
-#define __FW_VOL_DRIVER_H_
-
-#define FV2_DEVICE_SIGNATURE SIGNATURE_32 ('_', 'F', 'V', '2')
-
-//
-// Used to track all non-deleted files
-//
-typedef struct {
- LIST_ENTRY Link;
- EFI_FFS_FILE_HEADER *FfsHeader;
- UINTN StreamHandle;
- BOOLEAN FileCached;
-} FFS_FILE_LIST_ENTRY;
-
-typedef struct {
- UINTN Signature;
- EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb;
- EFI_HANDLE Handle;
- EFI_FIRMWARE_VOLUME2_PROTOCOL Fv;
-
- EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader;
- UINT8 *CachedFv;
- UINT8 *EndOfCachedFv;
-
- FFS_FILE_LIST_ENTRY *LastKey;
-
- LIST_ENTRY FfsFileListHeader;
-
- UINT32 AuthenticationStatus;
- UINT8 ErasePolarity;
- BOOLEAN IsFfs3Fv;
- BOOLEAN IsMemoryMapped;
-} FV_DEVICE;
-
-#define FV_DEVICE_FROM_THIS(a) CR(a, FV_DEVICE, Fv, FV2_DEVICE_SIGNATURE)
-
-/**
- Retrieves attributes, insures positive polarity of attribute bits, returns
- resulting attributes in output parameter.
-
- @param This Pointer to EFI_FIRMWARE_VOLUME2_PROTOCOL.
- @param Attributes output buffer which contains attributes.
-
- @retval EFI_SUCCESS Successfully got volume attributes.
-
-**/
-EFI_STATUS
-EFIAPI
-FvGetVolumeAttributes (
- IN CONST EFI_FIRMWARE_VOLUME2_PROTOCOL *This,
- OUT EFI_FV_ATTRIBUTES *Attributes
- );
-
-/**
- Sets current attributes for volume
-
- @param This Pointer to EFI_FIRMWARE_VOLUME2_PROTOCOL.
- @param Attributes At input, contains attributes to be set. At output
- contains new value of FV.
-
- @retval EFI_UNSUPPORTED Could not be set.
-
-**/
-EFI_STATUS
-EFIAPI
-FvSetVolumeAttributes (
- IN CONST EFI_FIRMWARE_VOLUME2_PROTOCOL *This,
- IN OUT EFI_FV_ATTRIBUTES *Attributes
- );
-
-/**
- Given the input key, search for the next matching file in the volume.
-
- @param This Pointer to EFI_FIRMWARE_VOLUME2_PROTOCOL.
- @param Key Key is a pointer to a caller allocated
- buffer that contains implementation specific
- data that is used to track where to begin
- the search for the next file. The size of
- the buffer must be at least This->KeySize
- bytes long. To reinitialize the search and
- begin from the beginning of the firmware
- volume, the entire buffer must be cleared to
- zero. Other than clearing the buffer to
- initiate a new search, the caller must not
- modify the data in the buffer between calls
- to GetNextFile().
- @param FileType FileType is a pointer to a caller allocated
- EFI_FV_FILETYPE. The GetNextFile() API can
- filter it's search for files based on the
- value of *FileType input. A *FileType input
- of 0 causes GetNextFile() to search for
- files of all types. If a file is found, the
- file's type is returned in *FileType.
- *FileType is not modified if no file is
- found.
- @param NameGuid NameGuid is a pointer to a caller allocated
- EFI_GUID. If a file is found, the file's
- name is returned in *NameGuid. *NameGuid is
- not modified if no file is found.
- @param Attributes Attributes is a pointer to a caller
- allocated EFI_FV_FILE_ATTRIBUTES. If a file
- is found, the file's attributes are returned
- in *Attributes. *Attributes is not modified
- if no file is found.
- @param Size Size is a pointer to a caller allocated
- UINTN. If a file is found, the file's size
- is returned in *Size. *Size is not modified
- if no file is found.
-
- @retval EFI_SUCCESS Successfully find the file.
- @retval EFI_DEVICE_ERROR Device error.
- @retval EFI_ACCESS_DENIED Fv could not read.
- @retval EFI_NOT_FOUND No matching file found.
- @retval EFI_INVALID_PARAMETER Invalid parameter
-
-**/
-EFI_STATUS
-EFIAPI
-FvGetNextFile (
- IN CONST EFI_FIRMWARE_VOLUME2_PROTOCOL *This,
- IN OUT VOID *Key,
- IN OUT EFI_FV_FILETYPE *FileType,
- OUT EFI_GUID *NameGuid,
- OUT EFI_FV_FILE_ATTRIBUTES *Attributes,
- OUT UINTN *Size
- );
-
-/**
- Locates a file in the firmware volume and
- copies it to the supplied buffer.
-
- @param This Pointer to EFI_FIRMWARE_VOLUME2_PROTOCOL.
- @param NameGuid Pointer to an EFI_GUID, which is the
- filename.
- @param Buffer Buffer is a pointer to pointer to a buffer
- in which the file or section contents or are
- returned.
- @param BufferSize BufferSize is a pointer to caller allocated
- UINTN. On input *BufferSize indicates the
- size in bytes of the memory region pointed
- to by Buffer. On output, *BufferSize
- contains the number of bytes required to
- read the file.
- @param FoundType FoundType is a pointer to a caller allocated
- EFI_FV_FILETYPE that on successful return
- from Read() contains the type of file read.
- This output reflects the file type
- irrespective of the value of the SectionType
- input.
- @param FileAttributes FileAttributes is a pointer to a caller
- allocated EFI_FV_FILE_ATTRIBUTES. On
- successful return from Read(),
- *FileAttributes contains the attributes of
- the file read.
- @param AuthenticationStatus AuthenticationStatus is a pointer to a
- caller allocated UINTN in which the
- authentication status is returned.
-
- @retval EFI_SUCCESS Successfully read to memory buffer.
- @retval EFI_WARN_BUFFER_TOO_SMALL Buffer too small.
- @retval EFI_NOT_FOUND Not found.
- @retval EFI_DEVICE_ERROR Device error.
- @retval EFI_ACCESS_DENIED Could not read.
- @retval EFI_INVALID_PARAMETER Invalid parameter.
- @retval EFI_OUT_OF_RESOURCES Not enough buffer to be allocated.
-
-**/
-EFI_STATUS
-EFIAPI
-FvReadFile (
- IN CONST EFI_FIRMWARE_VOLUME2_PROTOCOL *This,
- IN CONST EFI_GUID *NameGuid,
- IN OUT VOID **Buffer,
- IN OUT UINTN *BufferSize,
- OUT EFI_FV_FILETYPE *FoundType,
- OUT EFI_FV_FILE_ATTRIBUTES *FileAttributes,
- OUT UINT32 *AuthenticationStatus
- );
-
-/**
- Locates a section in a given FFS File and
- copies it to the supplied buffer (not including section header).
-
- @param This Pointer to EFI_FIRMWARE_VOLUME2_PROTOCOL.
- @param NameGuid Pointer to an EFI_GUID, which is the
- filename.
- @param SectionType Indicates the section type to return.
- @param SectionInstance Indicates which instance of sections with a
- type of SectionType to return.
- @param Buffer Buffer is a pointer to pointer to a buffer
- in which the file or section contents or are
- returned.
- @param BufferSize BufferSize is a pointer to caller allocated
- UINTN.
- @param AuthenticationStatus AuthenticationStatus is a pointer to a
- caller allocated UINT32 in which the
- authentication status is returned.
-
- @retval EFI_SUCCESS Successfully read the file section into
- buffer.
- @retval EFI_WARN_BUFFER_TOO_SMALL Buffer too small.
- @retval EFI_NOT_FOUND Section not found.
- @retval EFI_DEVICE_ERROR Device error.
- @retval EFI_ACCESS_DENIED Could not read.
- @retval EFI_INVALID_PARAMETER Invalid parameter.
-
-**/
-EFI_STATUS
-EFIAPI
-FvReadFileSection (
- IN CONST EFI_FIRMWARE_VOLUME2_PROTOCOL *This,
- IN CONST EFI_GUID *NameGuid,
- IN EFI_SECTION_TYPE SectionType,
- IN UINTN SectionInstance,
- IN OUT VOID **Buffer,
- IN OUT UINTN *BufferSize,
- OUT UINT32 *AuthenticationStatus
- );
-
-/**
- Writes one or more files to the firmware volume.
-
- @param This Pointer to EFI_FIRMWARE_VOLUME2_PROTOCOL.
- @param NumberOfFiles Number of files.
- @param WritePolicy WritePolicy indicates the level of reliability
- for the write in the event of a power failure or
- other system failure during the write operation.
- @param FileData FileData is an pointer to an array of
- EFI_FV_WRITE_DATA. Each element of array
- FileData represents a file to be written.
-
- @retval EFI_SUCCESS Files successfully written to firmware volume
- @retval EFI_OUT_OF_RESOURCES Not enough buffer to be allocated.
- @retval EFI_DEVICE_ERROR Device error.
- @retval EFI_WRITE_PROTECTED Write protected.
- @retval EFI_NOT_FOUND Not found.
- @retval EFI_INVALID_PARAMETER Invalid parameter.
- @retval EFI_UNSUPPORTED This function not supported.
-
-**/
-EFI_STATUS
-EFIAPI
-FvWriteFile (
- IN CONST EFI_FIRMWARE_VOLUME2_PROTOCOL *This,
- IN UINT32 NumberOfFiles,
- IN EFI_FV_WRITE_POLICY WritePolicy,
- IN EFI_FV_WRITE_FILE_DATA *FileData
- );
-
-/**
- Return information of type InformationType for the requested firmware
- volume.
-
- @param This Pointer to EFI_FIRMWARE_VOLUME2_PROTOCOL.
- @param InformationType InformationType for requested.
- @param BufferSize On input, size of Buffer.On output, the amount of data
- returned in Buffer.
- @param Buffer A poniter to the data buffer to return.
-
- @retval EFI_SUCCESS Successfully got volume Information.
-
-**/
-EFI_STATUS
-EFIAPI
-FvGetVolumeInfo (
- IN CONST EFI_FIRMWARE_VOLUME2_PROTOCOL *This,
- IN CONST EFI_GUID *InformationType,
- IN OUT UINTN *BufferSize,
- OUT VOID *Buffer
- );
-
-/**
- Set information of type InformationType for the requested firmware
- volume.
-
- @param This Pointer to EFI_FIRMWARE_VOLUME2_PROTOCOL.
- @param InformationType InformationType for requested.
- @param BufferSize On input, size of Buffer.On output, the amount of data
- returned in Buffer.
- @param Buffer A poniter to the data buffer to return.
-
- @retval EFI_SUCCESS Successfully set volume Information.
-
-**/
-EFI_STATUS
-EFIAPI
-FvSetVolumeInfo (
- IN CONST EFI_FIRMWARE_VOLUME2_PROTOCOL *This,
- IN CONST EFI_GUID *InformationType,
- IN UINTN BufferSize,
- IN CONST VOID *Buffer
- );
-
-/**
- Check if a block of buffer is erased.
-
- @param ErasePolarity Erase polarity attribute of the firmware volume
- @param InBuffer The buffer to be checked
- @param BufferSize Size of the buffer in bytes
-
- @retval TRUE The block of buffer is erased
- @retval FALSE The block of buffer is not erased
-
-**/
-BOOLEAN
-IsBufferErased (
- IN UINT8 ErasePolarity,
- IN VOID *InBuffer,
- IN UINTN BufferSize
- );
-
-/**
- Get the FFS file state by checking the highest bit set in the header's state field.
-
- @param ErasePolarity Erase polarity attribute of the firmware volume
- @param FfsHeader Points to the FFS file header
-
- @return FFS File state
-
-**/
-EFI_FFS_FILE_STATE
-GetFileState (
- IN UINT8 ErasePolarity,
- IN EFI_FFS_FILE_HEADER *FfsHeader
- );
-
-/**
- Set the FFS file state.
-
- @param State The state to be set.
- @param FfsHeader Points to the FFS file header
-
- @return None.
-
-**/
-VOID
-SetFileState (
- IN UINT8 State,
- IN EFI_FFS_FILE_HEADER *FfsHeader
- );
-
-/**
- Check if it's a valid FFS file header.
-
- @param ErasePolarity Erase polarity attribute of the firmware volume
- @param FfsHeader Points to the FFS file header to be checked
- @param FileState FFS file state to be returned
-
- @retval TRUE Valid FFS file header
- @retval FALSE Invalid FFS file header
-
-**/
-BOOLEAN
-IsValidFfsHeader (
- IN UINT8 ErasePolarity,
- IN EFI_FFS_FILE_HEADER *FfsHeader,
- OUT EFI_FFS_FILE_STATE *FileState
- );
-
-/**
- Check if it's a valid FFS file.
- Here we are sure that it has a valid FFS file header since we must call IsValidFfsHeader() first.
-
- @param ErasePolarity Erase polarity attribute of the firmware volume
- @param FfsHeader Points to the FFS file to be checked
-
- @retval TRUE Valid FFS file
- @retval FALSE Invalid FFS file
-
-**/
-BOOLEAN
-IsValidFfsFile (
- IN UINT8 ErasePolarity,
- IN EFI_FFS_FILE_HEADER *FfsHeader
- );
-
-#endif
+/** @file
+ Firmware File System protocol. Layers on top of Firmware
+ Block protocol to produce a file abstraction of FV based files.
+
+Copyright (c) 2006 - 2014, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef __FW_VOL_DRIVER_H_
+#define __FW_VOL_DRIVER_H_
+
+#define FV2_DEVICE_SIGNATURE SIGNATURE_32 ('_', 'F', 'V', '2')
+
+//
+// Used to track all non-deleted files
+//
+typedef struct {
+ LIST_ENTRY Link;
+ EFI_FFS_FILE_HEADER *FfsHeader;
+ UINTN StreamHandle;
+ BOOLEAN FileCached;
+} FFS_FILE_LIST_ENTRY;
+
+typedef struct {
+ UINTN Signature;
+ EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb;
+ EFI_HANDLE Handle;
+ EFI_FIRMWARE_VOLUME2_PROTOCOL Fv;
+
+ EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader;
+ UINT8 *CachedFv;
+ UINT8 *EndOfCachedFv;
+
+ FFS_FILE_LIST_ENTRY *LastKey;
+
+ LIST_ENTRY FfsFileListHeader;
+
+ UINT32 AuthenticationStatus;
+ UINT8 ErasePolarity;
+ BOOLEAN IsFfs3Fv;
+ BOOLEAN IsMemoryMapped;
+} FV_DEVICE;
+
+#define FV_DEVICE_FROM_THIS(a) CR(a, FV_DEVICE, Fv, FV2_DEVICE_SIGNATURE)
+
+/**
+ Retrieves attributes, insures positive polarity of attribute bits, returns
+ resulting attributes in output parameter.
+
+ @param This Pointer to EFI_FIRMWARE_VOLUME2_PROTOCOL.
+ @param Attributes output buffer which contains attributes.
+
+ @retval EFI_SUCCESS Successfully got volume attributes.
+
+**/
+EFI_STATUS
+EFIAPI
+FvGetVolumeAttributes (
+ IN CONST EFI_FIRMWARE_VOLUME2_PROTOCOL *This,
+ OUT EFI_FV_ATTRIBUTES *Attributes
+ );
+
+/**
+ Sets current attributes for volume
+
+ @param This Pointer to EFI_FIRMWARE_VOLUME2_PROTOCOL.
+ @param Attributes At input, contains attributes to be set. At output
+ contains new value of FV.
+
+ @retval EFI_UNSUPPORTED Could not be set.
+
+**/
+EFI_STATUS
+EFIAPI
+FvSetVolumeAttributes (
+ IN CONST EFI_FIRMWARE_VOLUME2_PROTOCOL *This,
+ IN OUT EFI_FV_ATTRIBUTES *Attributes
+ );
+
+/**
+ Given the input key, search for the next matching file in the volume.
+
+ @param This Pointer to EFI_FIRMWARE_VOLUME2_PROTOCOL.
+ @param Key Key is a pointer to a caller allocated
+ buffer that contains implementation specific
+ data that is used to track where to begin
+ the search for the next file. The size of
+ the buffer must be at least This->KeySize
+ bytes long. To reinitialize the search and
+ begin from the beginning of the firmware
+ volume, the entire buffer must be cleared to
+ zero. Other than clearing the buffer to
+ initiate a new search, the caller must not
+ modify the data in the buffer between calls
+ to GetNextFile().
+ @param FileType FileType is a pointer to a caller allocated
+ EFI_FV_FILETYPE. The GetNextFile() API can
+ filter it's search for files based on the
+ value of *FileType input. A *FileType input
+ of 0 causes GetNextFile() to search for
+ files of all types. If a file is found, the
+ file's type is returned in *FileType.
+ *FileType is not modified if no file is
+ found.
+ @param NameGuid NameGuid is a pointer to a caller allocated
+ EFI_GUID. If a file is found, the file's
+ name is returned in *NameGuid. *NameGuid is
+ not modified if no file is found.
+ @param Attributes Attributes is a pointer to a caller
+ allocated EFI_FV_FILE_ATTRIBUTES. If a file
+ is found, the file's attributes are returned
+ in *Attributes. *Attributes is not modified
+ if no file is found.
+ @param Size Size is a pointer to a caller allocated
+ UINTN. If a file is found, the file's size
+ is returned in *Size. *Size is not modified
+ if no file is found.
+
+ @retval EFI_SUCCESS Successfully find the file.
+ @retval EFI_DEVICE_ERROR Device error.
+ @retval EFI_ACCESS_DENIED Fv could not read.
+ @retval EFI_NOT_FOUND No matching file found.
+ @retval EFI_INVALID_PARAMETER Invalid parameter
+
+**/
+EFI_STATUS
+EFIAPI
+FvGetNextFile (
+ IN CONST EFI_FIRMWARE_VOLUME2_PROTOCOL *This,
+ IN OUT VOID *Key,
+ IN OUT EFI_FV_FILETYPE *FileType,
+ OUT EFI_GUID *NameGuid,
+ OUT EFI_FV_FILE_ATTRIBUTES *Attributes,
+ OUT UINTN *Size
+ );
+
+/**
+ Locates a file in the firmware volume and
+ copies it to the supplied buffer.
+
+ @param This Pointer to EFI_FIRMWARE_VOLUME2_PROTOCOL.
+ @param NameGuid Pointer to an EFI_GUID, which is the
+ filename.
+ @param Buffer Buffer is a pointer to pointer to a buffer
+ in which the file or section contents or are
+ returned.
+ @param BufferSize BufferSize is a pointer to caller allocated
+ UINTN. On input *BufferSize indicates the
+ size in bytes of the memory region pointed
+ to by Buffer. On output, *BufferSize
+ contains the number of bytes required to
+ read the file.
+ @param FoundType FoundType is a pointer to a caller allocated
+ EFI_FV_FILETYPE that on successful return
+ from Read() contains the type of file read.
+ This output reflects the file type
+ irrespective of the value of the SectionType
+ input.
+ @param FileAttributes FileAttributes is a pointer to a caller
+ allocated EFI_FV_FILE_ATTRIBUTES. On
+ successful return from Read(),
+ *FileAttributes contains the attributes of
+ the file read.
+ @param AuthenticationStatus AuthenticationStatus is a pointer to a
+ caller allocated UINTN in which the
+ authentication status is returned.
+
+ @retval EFI_SUCCESS Successfully read to memory buffer.
+ @retval EFI_WARN_BUFFER_TOO_SMALL Buffer too small.
+ @retval EFI_NOT_FOUND Not found.
+ @retval EFI_DEVICE_ERROR Device error.
+ @retval EFI_ACCESS_DENIED Could not read.
+ @retval EFI_INVALID_PARAMETER Invalid parameter.
+ @retval EFI_OUT_OF_RESOURCES Not enough buffer to be allocated.
+
+**/
+EFI_STATUS
+EFIAPI
+FvReadFile (
+ IN CONST EFI_FIRMWARE_VOLUME2_PROTOCOL *This,
+ IN CONST EFI_GUID *NameGuid,
+ IN OUT VOID **Buffer,
+ IN OUT UINTN *BufferSize,
+ OUT EFI_FV_FILETYPE *FoundType,
+ OUT EFI_FV_FILE_ATTRIBUTES *FileAttributes,
+ OUT UINT32 *AuthenticationStatus
+ );
+
+/**
+ Locates a section in a given FFS File and
+ copies it to the supplied buffer (not including section header).
+
+ @param This Pointer to EFI_FIRMWARE_VOLUME2_PROTOCOL.
+ @param NameGuid Pointer to an EFI_GUID, which is the
+ filename.
+ @param SectionType Indicates the section type to return.
+ @param SectionInstance Indicates which instance of sections with a
+ type of SectionType to return.
+ @param Buffer Buffer is a pointer to pointer to a buffer
+ in which the file or section contents or are
+ returned.
+ @param BufferSize BufferSize is a pointer to caller allocated
+ UINTN.
+ @param AuthenticationStatus AuthenticationStatus is a pointer to a
+ caller allocated UINT32 in which the
+ authentication status is returned.
+
+ @retval EFI_SUCCESS Successfully read the file section into
+ buffer.
+ @retval EFI_WARN_BUFFER_TOO_SMALL Buffer too small.
+ @retval EFI_NOT_FOUND Section not found.
+ @retval EFI_DEVICE_ERROR Device error.
+ @retval EFI_ACCESS_DENIED Could not read.
+ @retval EFI_INVALID_PARAMETER Invalid parameter.
+
+**/
+EFI_STATUS
+EFIAPI
+FvReadFileSection (
+ IN CONST EFI_FIRMWARE_VOLUME2_PROTOCOL *This,
+ IN CONST EFI_GUID *NameGuid,
+ IN EFI_SECTION_TYPE SectionType,
+ IN UINTN SectionInstance,
+ IN OUT VOID **Buffer,
+ IN OUT UINTN *BufferSize,
+ OUT UINT32 *AuthenticationStatus
+ );
+
+/**
+ Writes one or more files to the firmware volume.
+
+ @param This Pointer to EFI_FIRMWARE_VOLUME2_PROTOCOL.
+ @param NumberOfFiles Number of files.
+ @param WritePolicy WritePolicy indicates the level of reliability
+ for the write in the event of a power failure or
+ other system failure during the write operation.
+ @param FileData FileData is an pointer to an array of
+ EFI_FV_WRITE_DATA. Each element of array
+ FileData represents a file to be written.
+
+ @retval EFI_SUCCESS Files successfully written to firmware volume
+ @retval EFI_OUT_OF_RESOURCES Not enough buffer to be allocated.
+ @retval EFI_DEVICE_ERROR Device error.
+ @retval EFI_WRITE_PROTECTED Write protected.
+ @retval EFI_NOT_FOUND Not found.
+ @retval EFI_INVALID_PARAMETER Invalid parameter.
+ @retval EFI_UNSUPPORTED This function not supported.
+
+**/
+EFI_STATUS
+EFIAPI
+FvWriteFile (
+ IN CONST EFI_FIRMWARE_VOLUME2_PROTOCOL *This,
+ IN UINT32 NumberOfFiles,
+ IN EFI_FV_WRITE_POLICY WritePolicy,
+ IN EFI_FV_WRITE_FILE_DATA *FileData
+ );
+
+/**
+ Return information of type InformationType for the requested firmware
+ volume.
+
+ @param This Pointer to EFI_FIRMWARE_VOLUME2_PROTOCOL.
+ @param InformationType InformationType for requested.
+ @param BufferSize On input, size of Buffer.On output, the amount of data
+ returned in Buffer.
+ @param Buffer A poniter to the data buffer to return.
+
+ @retval EFI_SUCCESS Successfully got volume Information.
+
+**/
+EFI_STATUS
+EFIAPI
+FvGetVolumeInfo (
+ IN CONST EFI_FIRMWARE_VOLUME2_PROTOCOL *This,
+ IN CONST EFI_GUID *InformationType,
+ IN OUT UINTN *BufferSize,
+ OUT VOID *Buffer
+ );
+
+/**
+ Set information of type InformationType for the requested firmware
+ volume.
+
+ @param This Pointer to EFI_FIRMWARE_VOLUME2_PROTOCOL.
+ @param InformationType InformationType for requested.
+ @param BufferSize On input, size of Buffer.On output, the amount of data
+ returned in Buffer.
+ @param Buffer A poniter to the data buffer to return.
+
+ @retval EFI_SUCCESS Successfully set volume Information.
+
+**/
+EFI_STATUS
+EFIAPI
+FvSetVolumeInfo (
+ IN CONST EFI_FIRMWARE_VOLUME2_PROTOCOL *This,
+ IN CONST EFI_GUID *InformationType,
+ IN UINTN BufferSize,
+ IN CONST VOID *Buffer
+ );
+
+/**
+ Check if a block of buffer is erased.
+
+ @param ErasePolarity Erase polarity attribute of the firmware volume
+ @param InBuffer The buffer to be checked
+ @param BufferSize Size of the buffer in bytes
+
+ @retval TRUE The block of buffer is erased
+ @retval FALSE The block of buffer is not erased
+
+**/
+BOOLEAN
+IsBufferErased (
+ IN UINT8 ErasePolarity,
+ IN VOID *InBuffer,
+ IN UINTN BufferSize
+ );
+
+/**
+ Get the FFS file state by checking the highest bit set in the header's state field.
+
+ @param ErasePolarity Erase polarity attribute of the firmware volume
+ @param FfsHeader Points to the FFS file header
+
+ @return FFS File state
+
+**/
+EFI_FFS_FILE_STATE
+GetFileState (
+ IN UINT8 ErasePolarity,
+ IN EFI_FFS_FILE_HEADER *FfsHeader
+ );
+
+/**
+ Set the FFS file state.
+
+ @param State The state to be set.
+ @param FfsHeader Points to the FFS file header
+
+ @return None.
+
+**/
+VOID
+SetFileState (
+ IN UINT8 State,
+ IN EFI_FFS_FILE_HEADER *FfsHeader
+ );
+
+/**
+ Check if it's a valid FFS file header.
+
+ @param ErasePolarity Erase polarity attribute of the firmware volume
+ @param FfsHeader Points to the FFS file header to be checked
+ @param FileState FFS file state to be returned
+
+ @retval TRUE Valid FFS file header
+ @retval FALSE Invalid FFS file header
+
+**/
+BOOLEAN
+IsValidFfsHeader (
+ IN UINT8 ErasePolarity,
+ IN EFI_FFS_FILE_HEADER *FfsHeader,
+ OUT EFI_FFS_FILE_STATE *FileState
+ );
+
+/**
+ Check if it's a valid FFS file.
+ Here we are sure that it has a valid FFS file header since we must call IsValidFfsHeader() first.
+
+ @param ErasePolarity Erase polarity attribute of the firmware volume
+ @param FfsHeader Points to the FFS file to be checked
+
+ @retval TRUE Valid FFS file
+ @retval FALSE Invalid FFS file
+
+**/
+BOOLEAN
+IsValidFfsFile (
+ IN UINT8 ErasePolarity,
+ IN EFI_FFS_FILE_HEADER *FfsHeader
+ );
+
+#endif
diff --git a/MdeModulePkg/Core/Dxe/FwVol/FwVolRead.c b/MdeModulePkg/Core/Dxe/FwVol/FwVolRead.c
index 2ff22c93aa..6d5caa206f 100644
--- a/MdeModulePkg/Core/Dxe/FwVol/FwVolRead.c
+++ b/MdeModulePkg/Core/Dxe/FwVol/FwVolRead.c
@@ -1,532 +1,532 @@
-/** @file
- Implements functions to read firmware file
-
-Copyright (c) 2006 - 2020, Intel Corporation. All rights reserved.<BR>
-SPDX-License-Identifier: BSD-2-Clause-Patent
-
-**/
-
-#include "DxeMain.h"
-#include "FwVolDriver.h"
-
-/**
-Required Alignment Alignment Value in FFS FFS_ATTRIB_DATA_ALIGNMENT2 Alignment Value in
-(bytes) Attributes Field in FFS Attributes Field Firmware Volume Interfaces
-1 0 0 0
-16 1 0 4
-128 2 0 7
-512 3 0 9
-1 KB 4 0 10
-4 KB 5 0 12
-32 KB 6 0 15
-64 KB 7 0 16
-128 KB 0 1 17
-256 KB 1 1 18
-512 KB 2 1 19
-1 MB 3 1 20
-2 MB 4 1 21
-4 MB 5 1 22
-8 MB 6 1 23
-16 MB 7 1 24
-**/
-UINT8 mFvAttributes[] = { 0, 4, 7, 9, 10, 12, 15, 16 };
-UINT8 mFvAttributes2[] = { 17, 18, 19, 20, 21, 22, 23, 24 };
-
-/**
- Convert the FFS File Attributes to FV File Attributes
-
- @param FfsAttributes The attributes of UINT8 type.
-
- @return The attributes of EFI_FV_FILE_ATTRIBUTES
-
-**/
-EFI_FV_FILE_ATTRIBUTES
-FfsAttributes2FvFileAttributes (
- IN EFI_FFS_FILE_ATTRIBUTES FfsAttributes
- )
-{
- UINT8 DataAlignment;
- EFI_FV_FILE_ATTRIBUTES FileAttribute;
-
- DataAlignment = (UINT8)((FfsAttributes & FFS_ATTRIB_DATA_ALIGNMENT) >> 3);
- ASSERT (DataAlignment < 8);
-
- if ((FfsAttributes & FFS_ATTRIB_DATA_ALIGNMENT_2) != 0) {
- FileAttribute = (EFI_FV_FILE_ATTRIBUTES)mFvAttributes2[DataAlignment];
- } else {
- FileAttribute = (EFI_FV_FILE_ATTRIBUTES)mFvAttributes[DataAlignment];
- }
-
- if ((FfsAttributes & FFS_ATTRIB_FIXED) == FFS_ATTRIB_FIXED) {
- FileAttribute |= EFI_FV_FILE_ATTRIB_FIXED;
- }
-
- return FileAttribute;
-}
-
-/**
- Given the input key, search for the next matching file in the volume.
-
- @param This Indicates the calling context.
- @param Key Key is a pointer to a caller allocated
- buffer that contains implementation specific
- data that is used to track where to begin
- the search for the next file. The size of
- the buffer must be at least This->KeySize
- bytes long. To reinitialize the search and
- begin from the beginning of the firmware
- volume, the entire buffer must be cleared to
- zero. Other than clearing the buffer to
- initiate a new search, the caller must not
- modify the data in the buffer between calls
- to GetNextFile().
- @param FileType FileType is a pointer to a caller allocated
- EFI_FV_FILETYPE. The GetNextFile() API can
- filter it's search for files based on the
- value of *FileType input. A *FileType input
- of 0 causes GetNextFile() to search for
- files of all types. If a file is found, the
- file's type is returned in *FileType.
- *FileType is not modified if no file is
- found.
- @param NameGuid NameGuid is a pointer to a caller allocated
- EFI_GUID. If a file is found, the file's
- name is returned in *NameGuid. *NameGuid is
- not modified if no file is found.
- @param Attributes Attributes is a pointer to a caller
- allocated EFI_FV_FILE_ATTRIBUTES. If a file
- is found, the file's attributes are returned
- in *Attributes. *Attributes is not modified
- if no file is found.
- @param Size Size is a pointer to a caller allocated
- UINTN. If a file is found, the file's size
- is returned in *Size. *Size is not modified
- if no file is found.
-
- @retval EFI_SUCCESS Successfully find the file.
- @retval EFI_DEVICE_ERROR Device error.
- @retval EFI_ACCESS_DENIED Fv could not read.
- @retval EFI_NOT_FOUND No matching file found.
- @retval EFI_INVALID_PARAMETER Invalid parameter
-
-**/
-EFI_STATUS
-EFIAPI
-FvGetNextFile (
- IN CONST EFI_FIRMWARE_VOLUME2_PROTOCOL *This,
- IN OUT VOID *Key,
- IN OUT EFI_FV_FILETYPE *FileType,
- OUT EFI_GUID *NameGuid,
- OUT EFI_FV_FILE_ATTRIBUTES *Attributes,
- OUT UINTN *Size
- )
-{
- EFI_STATUS Status;
- FV_DEVICE *FvDevice;
- EFI_FV_ATTRIBUTES FvAttributes;
- EFI_FFS_FILE_HEADER *FfsFileHeader;
- UINTN *KeyValue;
- LIST_ENTRY *Link;
- FFS_FILE_LIST_ENTRY *FfsFileEntry;
-
- FvDevice = FV_DEVICE_FROM_THIS (This);
-
- Status = FvGetVolumeAttributes (This, &FvAttributes);
- if (EFI_ERROR (Status)) {
- return Status;
- }
-
- //
- // Check if read operation is enabled
- //
- if ((FvAttributes & EFI_FV2_READ_STATUS) == 0) {
- return EFI_ACCESS_DENIED;
- }
-
- if (*FileType > EFI_FV_FILETYPE_MM_CORE_STANDALONE) {
- //
- // File type needs to be in 0 - 0x0F
- //
- return EFI_NOT_FOUND;
- }
-
- KeyValue = (UINTN *)Key;
- for ( ; ;) {
- if (*KeyValue == 0) {
- //
- // Search for 1st matching file
- //
- Link = &FvDevice->FfsFileListHeader;
- } else {
- //
- // Key is pointer to FFsFileEntry, so get next one
- //
- Link = (LIST_ENTRY *)(*KeyValue);
- }
-
- if (Link->ForwardLink == &FvDevice->FfsFileListHeader) {
- //
- // Next is end of list so we did not find data
- //
- return EFI_NOT_FOUND;
- }
-
- FfsFileEntry = (FFS_FILE_LIST_ENTRY *)Link->ForwardLink;
- FfsFileHeader = (EFI_FFS_FILE_HEADER *)FfsFileEntry->FfsHeader;
-
- //
- // remember the key
- //
- *KeyValue = (UINTN)FfsFileEntry;
-
- if (FfsFileHeader->Type == EFI_FV_FILETYPE_FFS_PAD) {
- //
- // we ignore pad files
- //
- continue;
- }
-
- if (*FileType == EFI_FV_FILETYPE_ALL) {
- //
- // Process all file types so we have a match
- //
- break;
- }
-
- if (*FileType == FfsFileHeader->Type) {
- //
- // Found a matching file type
- //
- break;
- }
- }
-
- //
- // Return FileType, NameGuid, and Attributes
- //
- *FileType = FfsFileHeader->Type;
- CopyGuid (NameGuid, &FfsFileHeader->Name);
- *Attributes = FfsAttributes2FvFileAttributes (FfsFileHeader->Attributes);
- if ((FvDevice->FwVolHeader->Attributes & EFI_FVB2_MEMORY_MAPPED) == EFI_FVB2_MEMORY_MAPPED) {
- *Attributes |= EFI_FV_FILE_ATTRIB_MEMORY_MAPPED;
- }
-
- //
- // we need to substract the header size
- //
- if (IS_FFS_FILE2 (FfsFileHeader)) {
- *Size = FFS_FILE2_SIZE (FfsFileHeader) - sizeof (EFI_FFS_FILE_HEADER2);
- } else {
- *Size = FFS_FILE_SIZE (FfsFileHeader) - sizeof (EFI_FFS_FILE_HEADER);
- }
-
- return EFI_SUCCESS;
-}
-
-/**
- Locates a file in the firmware volume and
- copies it to the supplied buffer.
-
- @param This Indicates the calling context.
- @param NameGuid Pointer to an EFI_GUID, which is the
- filename.
- @param Buffer Buffer is a pointer to pointer to a buffer
- in which the file or section contents or are
- returned.
- @param BufferSize BufferSize is a pointer to caller allocated
- UINTN. On input *BufferSize indicates the
- size in bytes of the memory region pointed
- to by Buffer. On output, *BufferSize
- contains the number of bytes required to
- read the file.
- @param FoundType FoundType is a pointer to a caller allocated
- EFI_FV_FILETYPE that on successful return
- from Read() contains the type of file read.
- This output reflects the file type
- irrespective of the value of the SectionType
- input.
- @param FileAttributes FileAttributes is a pointer to a caller
- allocated EFI_FV_FILE_ATTRIBUTES. On
- successful return from Read(),
- *FileAttributes contains the attributes of
- the file read.
- @param AuthenticationStatus AuthenticationStatus is a pointer to a
- caller allocated UINTN in which the
- authentication status is returned.
-
- @retval EFI_SUCCESS Successfully read to memory buffer.
- @retval EFI_WARN_BUFFER_TOO_SMALL Buffer too small.
- @retval EFI_NOT_FOUND Not found.
- @retval EFI_DEVICE_ERROR Device error.
- @retval EFI_ACCESS_DENIED Could not read.
- @retval EFI_INVALID_PARAMETER Invalid parameter.
- @retval EFI_OUT_OF_RESOURCES Not enough buffer to be allocated.
-
-**/
-EFI_STATUS
-EFIAPI
-FvReadFile (
- IN CONST EFI_FIRMWARE_VOLUME2_PROTOCOL *This,
- IN CONST EFI_GUID *NameGuid,
- IN OUT VOID **Buffer,
- IN OUT UINTN *BufferSize,
- OUT EFI_FV_FILETYPE *FoundType,
- OUT EFI_FV_FILE_ATTRIBUTES *FileAttributes,
- OUT UINT32 *AuthenticationStatus
- )
-{
- EFI_STATUS Status;
- FV_DEVICE *FvDevice;
- EFI_GUID SearchNameGuid;
- EFI_FV_FILETYPE LocalFoundType;
- EFI_FV_FILE_ATTRIBUTES LocalAttributes;
- UINTN FileSize;
- UINT8 *SrcPtr;
- EFI_FFS_FILE_HEADER *FfsHeader;
- UINTN InputBufferSize;
- UINTN WholeFileSize;
-
- if (NameGuid == NULL) {
- return EFI_INVALID_PARAMETER;
- }
-
- FvDevice = FV_DEVICE_FROM_THIS (This);
-
- //
- // Keep looking until we find the matching NameGuid.
- // The Key is really a FfsFileEntry
- //
- FvDevice->LastKey = 0;
- do {
- LocalFoundType = 0;
- Status = FvGetNextFile (
- This,
- &FvDevice->LastKey,
- &LocalFoundType,
- &SearchNameGuid,
- &LocalAttributes,
- &FileSize
- );
- if (EFI_ERROR (Status)) {
- return EFI_NOT_FOUND;
- }
- } while (!CompareGuid (&SearchNameGuid, NameGuid));
-
- //
- // Get a pointer to the header
- //
- FfsHeader = FvDevice->LastKey->FfsHeader;
- if (FvDevice->IsMemoryMapped) {
- //
- // Memory mapped FV has not been cached, so here is to cache by file.
- //
- if (!FvDevice->LastKey->FileCached) {
- //
- // Cache FFS file to memory buffer.
- //
- WholeFileSize = IS_FFS_FILE2 (FfsHeader) ? FFS_FILE2_SIZE (FfsHeader) : FFS_FILE_SIZE (FfsHeader);
- FfsHeader = AllocateCopyPool (WholeFileSize, FfsHeader);
- if (FfsHeader == NULL) {
- return EFI_OUT_OF_RESOURCES;
- }
-
- //
- // Let FfsHeader in FfsFileEntry point to the cached file buffer.
- //
- FvDevice->LastKey->FfsHeader = FfsHeader;
- FvDevice->LastKey->FileCached = TRUE;
- }
- }
-
- //
- // Remember callers buffer size
- //
- InputBufferSize = *BufferSize;
-
- //
- // Calculate return values
- //
- *FoundType = FfsHeader->Type;
- *FileAttributes = FfsAttributes2FvFileAttributes (FfsHeader->Attributes);
- if ((FvDevice->FwVolHeader->Attributes & EFI_FVB2_MEMORY_MAPPED) == EFI_FVB2_MEMORY_MAPPED) {
- *FileAttributes |= EFI_FV_FILE_ATTRIB_MEMORY_MAPPED;
- }
-
- //
- // Inherit the authentication status.
- //
- *AuthenticationStatus = FvDevice->AuthenticationStatus;
- *BufferSize = FileSize;
-
- if (Buffer == NULL) {
- //
- // If Buffer is NULL, we only want to get the information collected so far
- //
- return EFI_SUCCESS;
- }
-
- //
- // Skip over file header
- //
- if (IS_FFS_FILE2 (FfsHeader)) {
- SrcPtr = ((UINT8 *)FfsHeader) + sizeof (EFI_FFS_FILE_HEADER2);
- } else {
- SrcPtr = ((UINT8 *)FfsHeader) + sizeof (EFI_FFS_FILE_HEADER);
- }
-
- Status = EFI_SUCCESS;
- if (*Buffer == NULL) {
- //
- // Caller passed in a pointer so allocate buffer for them
- //
- *Buffer = AllocatePool (FileSize);
- if (*Buffer == NULL) {
- return EFI_OUT_OF_RESOURCES;
- }
- } else if (FileSize > InputBufferSize) {
- //
- // Callers buffer was not big enough
- //
- Status = EFI_WARN_BUFFER_TOO_SMALL;
- FileSize = InputBufferSize;
- }
-
- //
- // Copy data into callers buffer
- //
- CopyMem (*Buffer, SrcPtr, FileSize);
-
- return Status;
-}
-
-/**
- Locates a section in a given FFS File and
- copies it to the supplied buffer (not including section header).
-
- @param This Indicates the calling context.
- @param NameGuid Pointer to an EFI_GUID, which is the
- filename.
- @param SectionType Indicates the section type to return.
- @param SectionInstance Indicates which instance of sections with a
- type of SectionType to return.
- @param Buffer Buffer is a pointer to pointer to a buffer
- in which the file or section contents or are
- returned.
- @param BufferSize BufferSize is a pointer to caller allocated
- UINTN.
- @param AuthenticationStatus AuthenticationStatus is a pointer to a
- caller allocated UINT32 in which the
- authentication status is returned.
-
- @retval EFI_SUCCESS Successfully read the file section into
- buffer.
- @retval EFI_WARN_BUFFER_TOO_SMALL Buffer too small.
- @retval EFI_NOT_FOUND Section not found.
- @retval EFI_DEVICE_ERROR Device error.
- @retval EFI_ACCESS_DENIED Could not read.
- @retval EFI_INVALID_PARAMETER Invalid parameter.
-
-**/
-EFI_STATUS
-EFIAPI
-FvReadFileSection (
- IN CONST EFI_FIRMWARE_VOLUME2_PROTOCOL *This,
- IN CONST EFI_GUID *NameGuid,
- IN EFI_SECTION_TYPE SectionType,
- IN UINTN SectionInstance,
- IN OUT VOID **Buffer,
- IN OUT UINTN *BufferSize,
- OUT UINT32 *AuthenticationStatus
- )
-{
- EFI_STATUS Status;
- FV_DEVICE *FvDevice;
- EFI_FV_FILETYPE FileType;
- EFI_FV_FILE_ATTRIBUTES FileAttributes;
- UINTN FileSize;
- UINT8 *FileBuffer;
- FFS_FILE_LIST_ENTRY *FfsEntry;
-
- if ((NameGuid == NULL) || (Buffer == NULL)) {
- return EFI_INVALID_PARAMETER;
- }
-
- FvDevice = FV_DEVICE_FROM_THIS (This);
-
- //
- // Read the file
- //
- Status = FvReadFile (
- This,
- NameGuid,
- NULL,
- &FileSize,
- &FileType,
- &FileAttributes,
- AuthenticationStatus
- );
- //
- // Get the last key used by our call to FvReadFile as it is the FfsEntry for this file.
- //
- FfsEntry = (FFS_FILE_LIST_ENTRY *)FvDevice->LastKey;
-
- if (EFI_ERROR (Status)) {
- return Status;
- }
-
- if (IS_FFS_FILE2 (FfsEntry->FfsHeader)) {
- FileBuffer = ((UINT8 *)FfsEntry->FfsHeader) + sizeof (EFI_FFS_FILE_HEADER2);
- } else {
- FileBuffer = ((UINT8 *)FfsEntry->FfsHeader) + sizeof (EFI_FFS_FILE_HEADER);
- }
-
- //
- // Check to see that the file actually HAS sections before we go any further.
- //
- if (FileType == EFI_FV_FILETYPE_RAW) {
- Status = EFI_NOT_FOUND;
- goto Done;
- }
-
- //
- // Use FfsEntry to cache Section Extraction Protocol Information
- //
- if (FfsEntry->StreamHandle == 0) {
- Status = OpenSectionStream (
- FileSize,
- FileBuffer,
- &FfsEntry->StreamHandle
- );
- if (EFI_ERROR (Status)) {
- goto Done;
- }
- }
-
- //
- // If SectionType == 0 We need the whole section stream
- //
- Status = GetSection (
- FfsEntry->StreamHandle,
- (SectionType == 0) ? NULL : &SectionType,
- NULL,
- (SectionType == 0) ? 0 : SectionInstance,
- Buffer,
- BufferSize,
- AuthenticationStatus,
- FvDevice->IsFfs3Fv
- );
-
- if (!EFI_ERROR (Status)) {
- //
- // Inherit the authentication status.
- //
- *AuthenticationStatus |= FvDevice->AuthenticationStatus;
- }
-
- //
- // Close of stream defered to close of FfsHeader list to allow SEP to cache data
- //
-
-Done:
- return Status;
-}
+/** @file
+ Implements functions to read firmware file
+
+Copyright (c) 2006 - 2020, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "DxeMain.h"
+#include "FwVolDriver.h"
+
+/**
+Required Alignment Alignment Value in FFS FFS_ATTRIB_DATA_ALIGNMENT2 Alignment Value in
+(bytes) Attributes Field in FFS Attributes Field Firmware Volume Interfaces
+1 0 0 0
+16 1 0 4
+128 2 0 7
+512 3 0 9
+1 KB 4 0 10
+4 KB 5 0 12
+32 KB 6 0 15
+64 KB 7 0 16
+128 KB 0 1 17
+256 KB 1 1 18
+512 KB 2 1 19
+1 MB 3 1 20
+2 MB 4 1 21
+4 MB 5 1 22
+8 MB 6 1 23
+16 MB 7 1 24
+**/
+UINT8 mFvAttributes[] = { 0, 4, 7, 9, 10, 12, 15, 16 };
+UINT8 mFvAttributes2[] = { 17, 18, 19, 20, 21, 22, 23, 24 };
+
+/**
+ Convert the FFS File Attributes to FV File Attributes
+
+ @param FfsAttributes The attributes of UINT8 type.
+
+ @return The attributes of EFI_FV_FILE_ATTRIBUTES
+
+**/
+EFI_FV_FILE_ATTRIBUTES
+FfsAttributes2FvFileAttributes (
+ IN EFI_FFS_FILE_ATTRIBUTES FfsAttributes
+ )
+{
+ UINT8 DataAlignment;
+ EFI_FV_FILE_ATTRIBUTES FileAttribute;
+
+ DataAlignment = (UINT8)((FfsAttributes & FFS_ATTRIB_DATA_ALIGNMENT) >> 3);
+ ASSERT (DataAlignment < 8);
+
+ if ((FfsAttributes & FFS_ATTRIB_DATA_ALIGNMENT_2) != 0) {
+ FileAttribute = (EFI_FV_FILE_ATTRIBUTES)mFvAttributes2[DataAlignment];
+ } else {
+ FileAttribute = (EFI_FV_FILE_ATTRIBUTES)mFvAttributes[DataAlignment];
+ }
+
+ if ((FfsAttributes & FFS_ATTRIB_FIXED) == FFS_ATTRIB_FIXED) {
+ FileAttribute |= EFI_FV_FILE_ATTRIB_FIXED;
+ }
+
+ return FileAttribute;
+}
+
+/**
+ Given the input key, search for the next matching file in the volume.
+
+ @param This Indicates the calling context.
+ @param Key Key is a pointer to a caller allocated
+ buffer that contains implementation specific
+ data that is used to track where to begin
+ the search for the next file. The size of
+ the buffer must be at least This->KeySize
+ bytes long. To reinitialize the search and
+ begin from the beginning of the firmware
+ volume, the entire buffer must be cleared to
+ zero. Other than clearing the buffer to
+ initiate a new search, the caller must not
+ modify the data in the buffer between calls
+ to GetNextFile().
+ @param FileType FileType is a pointer to a caller allocated
+ EFI_FV_FILETYPE. The GetNextFile() API can
+ filter it's search for files based on the
+ value of *FileType input. A *FileType input
+ of 0 causes GetNextFile() to search for
+ files of all types. If a file is found, the
+ file's type is returned in *FileType.
+ *FileType is not modified if no file is
+ found.
+ @param NameGuid NameGuid is a pointer to a caller allocated
+ EFI_GUID. If a file is found, the file's
+ name is returned in *NameGuid. *NameGuid is
+ not modified if no file is found.
+ @param Attributes Attributes is a pointer to a caller
+ allocated EFI_FV_FILE_ATTRIBUTES. If a file
+ is found, the file's attributes are returned
+ in *Attributes. *Attributes is not modified
+ if no file is found.
+ @param Size Size is a pointer to a caller allocated
+ UINTN. If a file is found, the file's size
+ is returned in *Size. *Size is not modified
+ if no file is found.
+
+ @retval EFI_SUCCESS Successfully find the file.
+ @retval EFI_DEVICE_ERROR Device error.
+ @retval EFI_ACCESS_DENIED Fv could not read.
+ @retval EFI_NOT_FOUND No matching file found.
+ @retval EFI_INVALID_PARAMETER Invalid parameter
+
+**/
+EFI_STATUS
+EFIAPI
+FvGetNextFile (
+ IN CONST EFI_FIRMWARE_VOLUME2_PROTOCOL *This,
+ IN OUT VOID *Key,
+ IN OUT EFI_FV_FILETYPE *FileType,
+ OUT EFI_GUID *NameGuid,
+ OUT EFI_FV_FILE_ATTRIBUTES *Attributes,
+ OUT UINTN *Size
+ )
+{
+ EFI_STATUS Status;
+ FV_DEVICE *FvDevice;
+ EFI_FV_ATTRIBUTES FvAttributes;
+ EFI_FFS_FILE_HEADER *FfsFileHeader;
+ UINTN *KeyValue;
+ LIST_ENTRY *Link;
+ FFS_FILE_LIST_ENTRY *FfsFileEntry;
+
+ FvDevice = FV_DEVICE_FROM_THIS (This);
+
+ Status = FvGetVolumeAttributes (This, &FvAttributes);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Check if read operation is enabled
+ //
+ if ((FvAttributes & EFI_FV2_READ_STATUS) == 0) {
+ return EFI_ACCESS_DENIED;
+ }
+
+ if (*FileType > EFI_FV_FILETYPE_MM_CORE_STANDALONE) {
+ //
+ // File type needs to be in 0 - 0x0F
+ //
+ return EFI_NOT_FOUND;
+ }
+
+ KeyValue = (UINTN *)Key;
+ for ( ; ;) {
+ if (*KeyValue == 0) {
+ //
+ // Search for 1st matching file
+ //
+ Link = &FvDevice->FfsFileListHeader;
+ } else {
+ //
+ // Key is pointer to FFsFileEntry, so get next one
+ //
+ Link = (LIST_ENTRY *)(*KeyValue);
+ }
+
+ if (Link->ForwardLink == &FvDevice->FfsFileListHeader) {
+ //
+ // Next is end of list so we did not find data
+ //
+ return EFI_NOT_FOUND;
+ }
+
+ FfsFileEntry = (FFS_FILE_LIST_ENTRY *)Link->ForwardLink;
+ FfsFileHeader = (EFI_FFS_FILE_HEADER *)FfsFileEntry->FfsHeader;
+
+ //
+ // remember the key
+ //
+ *KeyValue = (UINTN)FfsFileEntry;
+
+ if (FfsFileHeader->Type == EFI_FV_FILETYPE_FFS_PAD) {
+ //
+ // we ignore pad files
+ //
+ continue;
+ }
+
+ if (*FileType == EFI_FV_FILETYPE_ALL) {
+ //
+ // Process all file types so we have a match
+ //
+ break;
+ }
+
+ if (*FileType == FfsFileHeader->Type) {
+ //
+ // Found a matching file type
+ //
+ break;
+ }
+ }
+
+ //
+ // Return FileType, NameGuid, and Attributes
+ //
+ *FileType = FfsFileHeader->Type;
+ CopyGuid (NameGuid, &FfsFileHeader->Name);
+ *Attributes = FfsAttributes2FvFileAttributes (FfsFileHeader->Attributes);
+ if ((FvDevice->FwVolHeader->Attributes & EFI_FVB2_MEMORY_MAPPED) == EFI_FVB2_MEMORY_MAPPED) {
+ *Attributes |= EFI_FV_FILE_ATTRIB_MEMORY_MAPPED;
+ }
+
+ //
+ // we need to substract the header size
+ //
+ if (IS_FFS_FILE2 (FfsFileHeader)) {
+ *Size = FFS_FILE2_SIZE (FfsFileHeader) - sizeof (EFI_FFS_FILE_HEADER2);
+ } else {
+ *Size = FFS_FILE_SIZE (FfsFileHeader) - sizeof (EFI_FFS_FILE_HEADER);
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Locates a file in the firmware volume and
+ copies it to the supplied buffer.
+
+ @param This Indicates the calling context.
+ @param NameGuid Pointer to an EFI_GUID, which is the
+ filename.
+ @param Buffer Buffer is a pointer to pointer to a buffer
+ in which the file or section contents or are
+ returned.
+ @param BufferSize BufferSize is a pointer to caller allocated
+ UINTN. On input *BufferSize indicates the
+ size in bytes of the memory region pointed
+ to by Buffer. On output, *BufferSize
+ contains the number of bytes required to
+ read the file.
+ @param FoundType FoundType is a pointer to a caller allocated
+ EFI_FV_FILETYPE that on successful return
+ from Read() contains the type of file read.
+ This output reflects the file type
+ irrespective of the value of the SectionType
+ input.
+ @param FileAttributes FileAttributes is a pointer to a caller
+ allocated EFI_FV_FILE_ATTRIBUTES. On
+ successful return from Read(),
+ *FileAttributes contains the attributes of
+ the file read.
+ @param AuthenticationStatus AuthenticationStatus is a pointer to a
+ caller allocated UINTN in which the
+ authentication status is returned.
+
+ @retval EFI_SUCCESS Successfully read to memory buffer.
+ @retval EFI_WARN_BUFFER_TOO_SMALL Buffer too small.
+ @retval EFI_NOT_FOUND Not found.
+ @retval EFI_DEVICE_ERROR Device error.
+ @retval EFI_ACCESS_DENIED Could not read.
+ @retval EFI_INVALID_PARAMETER Invalid parameter.
+ @retval EFI_OUT_OF_RESOURCES Not enough buffer to be allocated.
+
+**/
+EFI_STATUS
+EFIAPI
+FvReadFile (
+ IN CONST EFI_FIRMWARE_VOLUME2_PROTOCOL *This,
+ IN CONST EFI_GUID *NameGuid,
+ IN OUT VOID **Buffer,
+ IN OUT UINTN *BufferSize,
+ OUT EFI_FV_FILETYPE *FoundType,
+ OUT EFI_FV_FILE_ATTRIBUTES *FileAttributes,
+ OUT UINT32 *AuthenticationStatus
+ )
+{
+ EFI_STATUS Status;
+ FV_DEVICE *FvDevice;
+ EFI_GUID SearchNameGuid;
+ EFI_FV_FILETYPE LocalFoundType;
+ EFI_FV_FILE_ATTRIBUTES LocalAttributes;
+ UINTN FileSize;
+ UINT8 *SrcPtr;
+ EFI_FFS_FILE_HEADER *FfsHeader;
+ UINTN InputBufferSize;
+ UINTN WholeFileSize;
+
+ if (NameGuid == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ FvDevice = FV_DEVICE_FROM_THIS (This);
+
+ //
+ // Keep looking until we find the matching NameGuid.
+ // The Key is really a FfsFileEntry
+ //
+ FvDevice->LastKey = 0;
+ do {
+ LocalFoundType = 0;
+ Status = FvGetNextFile (
+ This,
+ &FvDevice->LastKey,
+ &LocalFoundType,
+ &SearchNameGuid,
+ &LocalAttributes,
+ &FileSize
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_NOT_FOUND;
+ }
+ } while (!CompareGuid (&SearchNameGuid, NameGuid));
+
+ //
+ // Get a pointer to the header
+ //
+ FfsHeader = FvDevice->LastKey->FfsHeader;
+ if (FvDevice->IsMemoryMapped) {
+ //
+ // Memory mapped FV has not been cached, so here is to cache by file.
+ //
+ if (!FvDevice->LastKey->FileCached) {
+ //
+ // Cache FFS file to memory buffer.
+ //
+ WholeFileSize = IS_FFS_FILE2 (FfsHeader) ? FFS_FILE2_SIZE (FfsHeader) : FFS_FILE_SIZE (FfsHeader);
+ FfsHeader = AllocateCopyPool (WholeFileSize, FfsHeader);
+ if (FfsHeader == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ //
+ // Let FfsHeader in FfsFileEntry point to the cached file buffer.
+ //
+ FvDevice->LastKey->FfsHeader = FfsHeader;
+ FvDevice->LastKey->FileCached = TRUE;
+ }
+ }
+
+ //
+ // Remember callers buffer size
+ //
+ InputBufferSize = *BufferSize;
+
+ //
+ // Calculate return values
+ //
+ *FoundType = FfsHeader->Type;
+ *FileAttributes = FfsAttributes2FvFileAttributes (FfsHeader->Attributes);
+ if ((FvDevice->FwVolHeader->Attributes & EFI_FVB2_MEMORY_MAPPED) == EFI_FVB2_MEMORY_MAPPED) {
+ *FileAttributes |= EFI_FV_FILE_ATTRIB_MEMORY_MAPPED;
+ }
+
+ //
+ // Inherit the authentication status.
+ //
+ *AuthenticationStatus = FvDevice->AuthenticationStatus;
+ *BufferSize = FileSize;
+
+ if (Buffer == NULL) {
+ //
+ // If Buffer is NULL, we only want to get the information collected so far
+ //
+ return EFI_SUCCESS;
+ }
+
+ //
+ // Skip over file header
+ //
+ if (IS_FFS_FILE2 (FfsHeader)) {
+ SrcPtr = ((UINT8 *)FfsHeader) + sizeof (EFI_FFS_FILE_HEADER2);
+ } else {
+ SrcPtr = ((UINT8 *)FfsHeader) + sizeof (EFI_FFS_FILE_HEADER);
+ }
+
+ Status = EFI_SUCCESS;
+ if (*Buffer == NULL) {
+ //
+ // Caller passed in a pointer so allocate buffer for them
+ //
+ *Buffer = AllocatePool (FileSize);
+ if (*Buffer == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ } else if (FileSize > InputBufferSize) {
+ //
+ // Callers buffer was not big enough
+ //
+ Status = EFI_WARN_BUFFER_TOO_SMALL;
+ FileSize = InputBufferSize;
+ }
+
+ //
+ // Copy data into callers buffer
+ //
+ CopyMem (*Buffer, SrcPtr, FileSize);
+
+ return Status;
+}
+
+/**
+ Locates a section in a given FFS File and
+ copies it to the supplied buffer (not including section header).
+
+ @param This Indicates the calling context.
+ @param NameGuid Pointer to an EFI_GUID, which is the
+ filename.
+ @param SectionType Indicates the section type to return.
+ @param SectionInstance Indicates which instance of sections with a
+ type of SectionType to return.
+ @param Buffer Buffer is a pointer to pointer to a buffer
+ in which the file or section contents or are
+ returned.
+ @param BufferSize BufferSize is a pointer to caller allocated
+ UINTN.
+ @param AuthenticationStatus AuthenticationStatus is a pointer to a
+ caller allocated UINT32 in which the
+ authentication status is returned.
+
+ @retval EFI_SUCCESS Successfully read the file section into
+ buffer.
+ @retval EFI_WARN_BUFFER_TOO_SMALL Buffer too small.
+ @retval EFI_NOT_FOUND Section not found.
+ @retval EFI_DEVICE_ERROR Device error.
+ @retval EFI_ACCESS_DENIED Could not read.
+ @retval EFI_INVALID_PARAMETER Invalid parameter.
+
+**/
+EFI_STATUS
+EFIAPI
+FvReadFileSection (
+ IN CONST EFI_FIRMWARE_VOLUME2_PROTOCOL *This,
+ IN CONST EFI_GUID *NameGuid,
+ IN EFI_SECTION_TYPE SectionType,
+ IN UINTN SectionInstance,
+ IN OUT VOID **Buffer,
+ IN OUT UINTN *BufferSize,
+ OUT UINT32 *AuthenticationStatus
+ )
+{
+ EFI_STATUS Status;
+ FV_DEVICE *FvDevice;
+ EFI_FV_FILETYPE FileType;
+ EFI_FV_FILE_ATTRIBUTES FileAttributes;
+ UINTN FileSize;
+ UINT8 *FileBuffer;
+ FFS_FILE_LIST_ENTRY *FfsEntry;
+
+ if ((NameGuid == NULL) || (Buffer == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ FvDevice = FV_DEVICE_FROM_THIS (This);
+
+ //
+ // Read the file
+ //
+ Status = FvReadFile (
+ This,
+ NameGuid,
+ NULL,
+ &FileSize,
+ &FileType,
+ &FileAttributes,
+ AuthenticationStatus
+ );
+ //
+ // Get the last key used by our call to FvReadFile as it is the FfsEntry for this file.
+ //
+ FfsEntry = (FFS_FILE_LIST_ENTRY *)FvDevice->LastKey;
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if (IS_FFS_FILE2 (FfsEntry->FfsHeader)) {
+ FileBuffer = ((UINT8 *)FfsEntry->FfsHeader) + sizeof (EFI_FFS_FILE_HEADER2);
+ } else {
+ FileBuffer = ((UINT8 *)FfsEntry->FfsHeader) + sizeof (EFI_FFS_FILE_HEADER);
+ }
+
+ //
+ // Check to see that the file actually HAS sections before we go any further.
+ //
+ if (FileType == EFI_FV_FILETYPE_RAW) {
+ Status = EFI_NOT_FOUND;
+ goto Done;
+ }
+
+ //
+ // Use FfsEntry to cache Section Extraction Protocol Information
+ //
+ if (FfsEntry->StreamHandle == 0) {
+ Status = OpenSectionStream (
+ FileSize,
+ FileBuffer,
+ &FfsEntry->StreamHandle
+ );
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+ }
+
+ //
+ // If SectionType == 0 We need the whole section stream
+ //
+ Status = GetSection (
+ FfsEntry->StreamHandle,
+ (SectionType == 0) ? NULL : &SectionType,
+ NULL,
+ (SectionType == 0) ? 0 : SectionInstance,
+ Buffer,
+ BufferSize,
+ AuthenticationStatus,
+ FvDevice->IsFfs3Fv
+ );
+
+ if (!EFI_ERROR (Status)) {
+ //
+ // Inherit the authentication status.
+ //
+ *AuthenticationStatus |= FvDevice->AuthenticationStatus;
+ }
+
+ //
+ // Close of stream defered to close of FfsHeader list to allow SEP to cache data
+ //
+
+Done:
+ return Status;
+}
diff --git a/MdeModulePkg/Core/Dxe/FwVol/FwVolWrite.c b/MdeModulePkg/Core/Dxe/FwVol/FwVolWrite.c
index 6e3a59bc4c..c3eace21ee 100644
--- a/MdeModulePkg/Core/Dxe/FwVol/FwVolWrite.c
+++ b/MdeModulePkg/Core/Dxe/FwVol/FwVolWrite.c
@@ -1,43 +1,43 @@
-/** @file
- Implements functions to write firmware file
-
-Copyright (c) 2006 - 2008, Intel Corporation. All rights reserved.<BR>
-SPDX-License-Identifier: BSD-2-Clause-Patent
-
-**/
-
-#include "DxeMain.h"
-#include "FwVolDriver.h"
-
-/**
- Writes one or more files to the firmware volume.
-
- @param This Indicates the calling context.
- @param NumberOfFiles Number of files.
- @param WritePolicy WritePolicy indicates the level of reliability
- for the write in the event of a power failure or
- other system failure during the write operation.
- @param FileData FileData is an pointer to an array of
- EFI_FV_WRITE_DATA. Each element of array
- FileData represents a file to be written.
-
- @retval EFI_SUCCESS Files successfully written to firmware volume
- @retval EFI_OUT_OF_RESOURCES Not enough buffer to be allocated.
- @retval EFI_DEVICE_ERROR Device error.
- @retval EFI_WRITE_PROTECTED Write protected.
- @retval EFI_NOT_FOUND Not found.
- @retval EFI_INVALID_PARAMETER Invalid parameter.
- @retval EFI_UNSUPPORTED This function not supported.
-
-**/
-EFI_STATUS
-EFIAPI
-FvWriteFile (
- IN CONST EFI_FIRMWARE_VOLUME2_PROTOCOL *This,
- IN UINT32 NumberOfFiles,
- IN EFI_FV_WRITE_POLICY WritePolicy,
- IN EFI_FV_WRITE_FILE_DATA *FileData
- )
-{
- return EFI_UNSUPPORTED;
-}
+/** @file
+ Implements functions to write firmware file
+
+Copyright (c) 2006 - 2008, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "DxeMain.h"
+#include "FwVolDriver.h"
+
+/**
+ Writes one or more files to the firmware volume.
+
+ @param This Indicates the calling context.
+ @param NumberOfFiles Number of files.
+ @param WritePolicy WritePolicy indicates the level of reliability
+ for the write in the event of a power failure or
+ other system failure during the write operation.
+ @param FileData FileData is an pointer to an array of
+ EFI_FV_WRITE_DATA. Each element of array
+ FileData represents a file to be written.
+
+ @retval EFI_SUCCESS Files successfully written to firmware volume
+ @retval EFI_OUT_OF_RESOURCES Not enough buffer to be allocated.
+ @retval EFI_DEVICE_ERROR Device error.
+ @retval EFI_WRITE_PROTECTED Write protected.
+ @retval EFI_NOT_FOUND Not found.
+ @retval EFI_INVALID_PARAMETER Invalid parameter.
+ @retval EFI_UNSUPPORTED This function not supported.
+
+**/
+EFI_STATUS
+EFIAPI
+FvWriteFile (
+ IN CONST EFI_FIRMWARE_VOLUME2_PROTOCOL *This,
+ IN UINT32 NumberOfFiles,
+ IN EFI_FV_WRITE_POLICY WritePolicy,
+ IN EFI_FV_WRITE_FILE_DATA *FileData
+ )
+{
+ return EFI_UNSUPPORTED;
+}
diff --git a/MdeModulePkg/Core/Dxe/FwVolBlock/FwVolBlock.c b/MdeModulePkg/Core/Dxe/FwVolBlock/FwVolBlock.c
index 9f5f40e5cd..575ab601d8 100644
--- a/MdeModulePkg/Core/Dxe/FwVolBlock/FwVolBlock.c
+++ b/MdeModulePkg/Core/Dxe/FwVolBlock/FwVolBlock.c
@@ -1,713 +1,713 @@
-/** @file
- Implementations for Firmware Volume Block protocol.
-
- It consumes FV HOBs and creates read-only Firmare Volume Block protocol
- instances for each of them.
-
-Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
-SPDX-License-Identifier: BSD-2-Clause-Patent
-
-**/
-
-#include "DxeMain.h"
-#include "FwVolBlock.h"
-
-FV_MEMMAP_DEVICE_PATH mFvMemmapDevicePathTemplate = {
- {
- {
- HARDWARE_DEVICE_PATH,
- HW_MEMMAP_DP,
- {
- (UINT8)(sizeof (MEMMAP_DEVICE_PATH)),
- (UINT8)(sizeof (MEMMAP_DEVICE_PATH) >> 8)
- }
- },
- EfiMemoryMappedIO,
- (EFI_PHYSICAL_ADDRESS)0,
- (EFI_PHYSICAL_ADDRESS)0,
- },
- {
- END_DEVICE_PATH_TYPE,
- END_ENTIRE_DEVICE_PATH_SUBTYPE,
- {
- END_DEVICE_PATH_LENGTH,
- 0
- }
- }
-};
-
-FV_PIWG_DEVICE_PATH mFvPIWGDevicePathTemplate = {
- {
- {
- MEDIA_DEVICE_PATH,
- MEDIA_PIWG_FW_VOL_DP,
- {
- (UINT8)(sizeof (MEDIA_FW_VOL_DEVICE_PATH)),
- (UINT8)(sizeof (MEDIA_FW_VOL_DEVICE_PATH) >> 8)
- }
- },
- { 0 }
- },
- {
- END_DEVICE_PATH_TYPE,
- END_ENTIRE_DEVICE_PATH_SUBTYPE,
- {
- END_DEVICE_PATH_LENGTH,
- 0
- }
- }
-};
-
-EFI_FW_VOL_BLOCK_DEVICE mFwVolBlock = {
- FVB_DEVICE_SIGNATURE,
- NULL,
- NULL,
- {
- FwVolBlockGetAttributes,
- (EFI_FVB_SET_ATTRIBUTES)FwVolBlockSetAttributes,
- FwVolBlockGetPhysicalAddress,
- FwVolBlockGetBlockSize,
- FwVolBlockReadBlock,
- (EFI_FVB_WRITE)FwVolBlockWriteBlock,
- (EFI_FVB_ERASE_BLOCKS)FwVolBlockEraseBlock,
- NULL
- },
- 0,
- NULL,
- 0,
- 0,
- 0
-};
-
-/**
- Retrieves Volume attributes. No polarity translations are done.
-
- @param This Calling context
- @param Attributes output buffer which contains attributes
-
- @retval EFI_SUCCESS The firmware volume attributes were returned.
-
-**/
-EFI_STATUS
-EFIAPI
-FwVolBlockGetAttributes (
- IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,
- OUT EFI_FVB_ATTRIBUTES_2 *Attributes
- )
-{
- EFI_FW_VOL_BLOCK_DEVICE *FvbDevice;
-
- FvbDevice = FVB_DEVICE_FROM_THIS (This);
-
- //
- // Since we are read only, it's safe to get attributes data from our in-memory copy.
- //
- *Attributes = FvbDevice->FvbAttributes & ~EFI_FVB2_WRITE_STATUS;
-
- return EFI_SUCCESS;
-}
-
-/**
- Modifies the current settings of the firmware volume according to the input parameter.
-
- @param This Calling context
- @param Attributes input buffer which contains attributes
-
- @retval EFI_SUCCESS The firmware volume attributes were returned.
- @retval EFI_INVALID_PARAMETER The attributes requested are in conflict with
- the capabilities as declared in the firmware
- volume header.
- @retval EFI_UNSUPPORTED Not supported.
-
-**/
-EFI_STATUS
-EFIAPI
-FwVolBlockSetAttributes (
- IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,
- IN CONST EFI_FVB_ATTRIBUTES_2 *Attributes
- )
-{
- return EFI_UNSUPPORTED;
-}
-
-/**
- The EraseBlock() function erases one or more blocks as denoted by the
- variable argument list. The entire parameter list of blocks must be verified
- prior to erasing any blocks. If a block is requested that does not exist
- within the associated firmware volume (it has a larger index than the last
- block of the firmware volume), the EraseBlock() function must return
- EFI_INVALID_PARAMETER without modifying the contents of the firmware volume.
-
- @param This Calling context
- @param ... Starting LBA followed by Number of Lba to erase.
- a -1 to terminate the list.
-
- @retval EFI_SUCCESS The erase request was successfully completed.
- @retval EFI_ACCESS_DENIED The firmware volume is in the WriteDisabled
- state.
- @retval EFI_DEVICE_ERROR The block device is not functioning correctly
- and could not be written. The firmware device
- may have been partially erased.
- @retval EFI_INVALID_PARAMETER One or more of the LBAs listed in the variable
- argument list do
- @retval EFI_UNSUPPORTED Not supported.
-
-**/
-EFI_STATUS
-EFIAPI
-FwVolBlockEraseBlock (
- IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,
- ...
- )
-{
- return EFI_UNSUPPORTED;
-}
-
-/**
- Read the specified number of bytes from the block to the input buffer.
-
- @param This Indicates the calling context.
- @param Lba The starting logical block index to read.
- @param Offset Offset into the block at which to begin reading.
- @param NumBytes Pointer to a UINT32. At entry, *NumBytes
- contains the total size of the buffer. At exit,
- *NumBytes contains the total number of bytes
- actually read.
- @param Buffer Pinter to a caller-allocated buffer that
- contains the destine for the read.
-
- @retval EFI_SUCCESS The firmware volume was read successfully.
- @retval EFI_BAD_BUFFER_SIZE The read was attempted across an LBA boundary.
- @retval EFI_ACCESS_DENIED Access denied.
- @retval EFI_DEVICE_ERROR The block device is malfunctioning and could not
- be read.
-
-**/
-EFI_STATUS
-EFIAPI
-FwVolBlockReadBlock (
- IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,
- IN CONST EFI_LBA Lba,
- IN CONST UINTN Offset,
- IN OUT UINTN *NumBytes,
- IN OUT UINT8 *Buffer
- )
-{
- EFI_FW_VOL_BLOCK_DEVICE *FvbDevice;
- EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader;
- UINT8 *LbaOffset;
- UINTN LbaStart;
- UINTN NumOfBytesRead;
- UINTN LbaIndex;
-
- FvbDevice = FVB_DEVICE_FROM_THIS (This);
-
- //
- // Check if This FW can be read
- //
- if ((FvbDevice->FvbAttributes & EFI_FVB2_READ_STATUS) == 0) {
- return EFI_ACCESS_DENIED;
- }
-
- LbaIndex = (UINTN)Lba;
- if (LbaIndex >= FvbDevice->NumBlocks) {
- //
- // Invalid Lba, read nothing.
- //
- *NumBytes = 0;
- return EFI_BAD_BUFFER_SIZE;
- }
-
- if (Offset > FvbDevice->LbaCache[LbaIndex].Length) {
- //
- // all exceed boundary, read nothing.
- //
- *NumBytes = 0;
- return EFI_BAD_BUFFER_SIZE;
- }
-
- NumOfBytesRead = *NumBytes;
- if (Offset + NumOfBytesRead > FvbDevice->LbaCache[LbaIndex].Length) {
- //
- // partial exceed boundary, read data from current postion to end.
- //
- NumOfBytesRead = FvbDevice->LbaCache[LbaIndex].Length - Offset;
- }
-
- LbaStart = FvbDevice->LbaCache[LbaIndex].Base;
- FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *)((UINTN)FvbDevice->BaseAddress);
- LbaOffset = (UINT8 *)FwVolHeader + LbaStart + Offset;
-
- //
- // Perform read operation
- //
- CopyMem (Buffer, LbaOffset, NumOfBytesRead);
-
- if (NumOfBytesRead == *NumBytes) {
- return EFI_SUCCESS;
- }
-
- *NumBytes = NumOfBytesRead;
- return EFI_BAD_BUFFER_SIZE;
-}
-
-/**
- Writes the specified number of bytes from the input buffer to the block.
-
- @param This Indicates the calling context.
- @param Lba The starting logical block index to write to.
- @param Offset Offset into the block at which to begin writing.
- @param NumBytes Pointer to a UINT32. At entry, *NumBytes
- contains the total size of the buffer. At exit,
- *NumBytes contains the total number of bytes
- actually written.
- @param Buffer Pinter to a caller-allocated buffer that
- contains the source for the write.
-
- @retval EFI_SUCCESS The firmware volume was written successfully.
- @retval EFI_BAD_BUFFER_SIZE The write was attempted across an LBA boundary.
- On output, NumBytes contains the total number of
- bytes actually written.
- @retval EFI_ACCESS_DENIED The firmware volume is in the WriteDisabled
- state.
- @retval EFI_DEVICE_ERROR The block device is malfunctioning and could not
- be written.
- @retval EFI_UNSUPPORTED Not supported.
-
-**/
-EFI_STATUS
-EFIAPI
-FwVolBlockWriteBlock (
- IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,
- IN EFI_LBA Lba,
- IN UINTN Offset,
- IN OUT UINTN *NumBytes,
- IN UINT8 *Buffer
- )
-{
- return EFI_UNSUPPORTED;
-}
-
-/**
- Get Fvb's base address.
-
- @param This Indicates the calling context.
- @param Address Fvb device base address.
-
- @retval EFI_SUCCESS Successfully got Fvb's base address.
- @retval EFI_UNSUPPORTED Not supported.
-
-**/
-EFI_STATUS
-EFIAPI
-FwVolBlockGetPhysicalAddress (
- IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,
- OUT EFI_PHYSICAL_ADDRESS *Address
- )
-{
- EFI_FW_VOL_BLOCK_DEVICE *FvbDevice;
-
- FvbDevice = FVB_DEVICE_FROM_THIS (This);
-
- if ((FvbDevice->FvbAttributes & EFI_FVB2_MEMORY_MAPPED) != 0) {
- *Address = FvbDevice->BaseAddress;
- return EFI_SUCCESS;
- }
-
- return EFI_UNSUPPORTED;
-}
-
-/**
- Retrieves the size in bytes of a specific block within a firmware volume.
-
- @param This Indicates the calling context.
- @param Lba Indicates the block for which to return the
- size.
- @param BlockSize Pointer to a caller-allocated UINTN in which the
- size of the block is returned.
- @param NumberOfBlocks Pointer to a caller-allocated UINTN in which the
- number of consecutive blocks starting with Lba
- is returned. All blocks in this range have a
- size of BlockSize.
-
- @retval EFI_SUCCESS The firmware volume base address is returned.
- @retval EFI_INVALID_PARAMETER The requested LBA is out of range.
-
-**/
-EFI_STATUS
-EFIAPI
-FwVolBlockGetBlockSize (
- IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,
- IN CONST EFI_LBA Lba,
- IN OUT UINTN *BlockSize,
- IN OUT UINTN *NumberOfBlocks
- )
-{
- UINTN TotalBlocks;
- EFI_FW_VOL_BLOCK_DEVICE *FvbDevice;
- EFI_FV_BLOCK_MAP_ENTRY *PtrBlockMapEntry;
- EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader;
-
- FvbDevice = FVB_DEVICE_FROM_THIS (This);
-
- //
- // Do parameter checking
- //
- if (Lba >= FvbDevice->NumBlocks) {
- return EFI_INVALID_PARAMETER;
- }
-
- FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *)((UINTN)FvbDevice->BaseAddress);
-
- PtrBlockMapEntry = FwVolHeader->BlockMap;
-
- //
- // Search the block map for the given block
- //
- TotalBlocks = 0;
- while ((PtrBlockMapEntry->NumBlocks != 0) || (PtrBlockMapEntry->Length != 0)) {
- TotalBlocks += PtrBlockMapEntry->NumBlocks;
- if (Lba < TotalBlocks) {
- //
- // We find the range
- //
- break;
- }
-
- PtrBlockMapEntry++;
- }
-
- *BlockSize = PtrBlockMapEntry->Length;
- *NumberOfBlocks = TotalBlocks - (UINTN)Lba;
-
- return EFI_SUCCESS;
-}
-
-/**
-
- Get FVB authentication status
-
- @param FvbProtocol FVB protocol.
-
- @return Authentication status.
-
-**/
-UINT32
-GetFvbAuthenticationStatus (
- IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *FvbProtocol
- )
-{
- EFI_FW_VOL_BLOCK_DEVICE *FvbDevice;
- UINT32 AuthenticationStatus;
-
- AuthenticationStatus = 0;
- FvbDevice = BASE_CR (FvbProtocol, EFI_FW_VOL_BLOCK_DEVICE, FwVolBlockInstance);
- if (FvbDevice->Signature == FVB_DEVICE_SIGNATURE) {
- AuthenticationStatus = FvbDevice->AuthenticationStatus;
- }
-
- return AuthenticationStatus;
-}
-
-/**
- This routine produces a firmware volume block protocol on a given
- buffer.
-
- @param BaseAddress base address of the firmware volume image
- @param Length length of the firmware volume image
- @param ParentHandle handle of parent firmware volume, if this image
- came from an FV image file and section in another firmware
- volume (ala capsules)
- @param AuthenticationStatus Authentication status inherited, if this image
- came from an FV image file and section in another firmware volume.
- @param FvProtocol Firmware volume block protocol produced.
-
- @retval EFI_VOLUME_CORRUPTED Volume corrupted.
- @retval EFI_OUT_OF_RESOURCES No enough buffer to be allocated.
- @retval EFI_SUCCESS Successfully produced a FVB protocol on given
- buffer.
-
-**/
-EFI_STATUS
-ProduceFVBProtocolOnBuffer (
- IN EFI_PHYSICAL_ADDRESS BaseAddress,
- IN UINT64 Length,
- IN EFI_HANDLE ParentHandle,
- IN UINT32 AuthenticationStatus,
- OUT EFI_HANDLE *FvProtocol OPTIONAL
- )
-{
- EFI_STATUS Status;
- EFI_FW_VOL_BLOCK_DEVICE *FvbDev;
- EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader;
- UINTN BlockIndex;
- UINTN BlockIndex2;
- UINTN LinearOffset;
- UINT32 FvAlignment;
- EFI_FV_BLOCK_MAP_ENTRY *PtrBlockMapEntry;
-
- FvAlignment = 0;
- FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *)(UINTN)BaseAddress;
- //
- // Validate FV Header, if not as expected, return
- //
- if (FwVolHeader->Signature != EFI_FVH_SIGNATURE) {
- return EFI_VOLUME_CORRUPTED;
- }
-
- //
- // If EFI_FVB2_WEAK_ALIGNMENT is set in the volume header then the first byte of the volume
- // can be aligned on any power-of-two boundary. A weakly aligned volume can not be moved from
- // its initial linked location and maintain its alignment.
- //
- if ((FwVolHeader->Attributes & EFI_FVB2_WEAK_ALIGNMENT) != EFI_FVB2_WEAK_ALIGNMENT) {
- //
- // Get FvHeader alignment
- //
- FvAlignment = 1 << ((FwVolHeader->Attributes & EFI_FVB2_ALIGNMENT) >> 16);
- //
- // FvAlignment must be greater than or equal to 8 bytes of the minimum FFS alignment value.
- //
- if (FvAlignment < 8) {
- FvAlignment = 8;
- }
-
- if ((UINTN)BaseAddress % FvAlignment != 0) {
- //
- // FvImage buffer is not at its required alignment.
- //
- DEBUG ((
- DEBUG_ERROR,
- "Unaligned FvImage found at 0x%lx:0x%lx, the required alignment is 0x%x\n",
- BaseAddress,
- Length,
- FvAlignment
- ));
- return EFI_VOLUME_CORRUPTED;
- }
- }
-
- //
- // Allocate EFI_FW_VOL_BLOCK_DEVICE
- //
- FvbDev = AllocateCopyPool (sizeof (EFI_FW_VOL_BLOCK_DEVICE), &mFwVolBlock);
- if (FvbDev == NULL) {
- return EFI_OUT_OF_RESOURCES;
- }
-
- FvbDev->BaseAddress = BaseAddress;
- FvbDev->FvbAttributes = FwVolHeader->Attributes;
- FvbDev->FwVolBlockInstance.ParentHandle = ParentHandle;
- FvbDev->AuthenticationStatus = AuthenticationStatus;
-
- //
- // Init the block caching fields of the device
- // First, count the number of blocks
- //
- FvbDev->NumBlocks = 0;
- for (PtrBlockMapEntry = FwVolHeader->BlockMap;
- PtrBlockMapEntry->NumBlocks != 0;
- PtrBlockMapEntry++)
- {
- FvbDev->NumBlocks += PtrBlockMapEntry->NumBlocks;
- }
-
- //
- // Second, allocate the cache
- //
- if (FvbDev->NumBlocks >= (MAX_ADDRESS / sizeof (LBA_CACHE))) {
- CoreFreePool (FvbDev);
- return EFI_OUT_OF_RESOURCES;
- }
-
- FvbDev->LbaCache = AllocatePool (FvbDev->NumBlocks * sizeof (LBA_CACHE));
- if (FvbDev->LbaCache == NULL) {
- CoreFreePool (FvbDev);
- return EFI_OUT_OF_RESOURCES;
- }
-
- //
- // Last, fill in the cache with the linear address of the blocks
- //
- BlockIndex = 0;
- LinearOffset = 0;
- for (PtrBlockMapEntry = FwVolHeader->BlockMap;
- PtrBlockMapEntry->NumBlocks != 0; PtrBlockMapEntry++)
- {
- for (BlockIndex2 = 0; BlockIndex2 < PtrBlockMapEntry->NumBlocks; BlockIndex2++) {
- FvbDev->LbaCache[BlockIndex].Base = LinearOffset;
- FvbDev->LbaCache[BlockIndex].Length = PtrBlockMapEntry->Length;
- LinearOffset += PtrBlockMapEntry->Length;
- BlockIndex++;
- }
- }
-
- //
- // Judget whether FV name guid is produced in Fv extension header
- //
- if (FwVolHeader->ExtHeaderOffset == 0) {
- //
- // FV does not contains extension header, then produce MEMMAP_DEVICE_PATH
- //
- FvbDev->DevicePath = (EFI_DEVICE_PATH_PROTOCOL *)AllocateCopyPool (sizeof (FV_MEMMAP_DEVICE_PATH), &mFvMemmapDevicePathTemplate);
- if (FvbDev->DevicePath == NULL) {
- FreePool (FvbDev->LbaCache);
- FreePool (FvbDev);
- return EFI_OUT_OF_RESOURCES;
- }
-
- ((FV_MEMMAP_DEVICE_PATH *)FvbDev->DevicePath)->MemMapDevPath.StartingAddress = BaseAddress;
- ((FV_MEMMAP_DEVICE_PATH *)FvbDev->DevicePath)->MemMapDevPath.EndingAddress = BaseAddress + FwVolHeader->FvLength - 1;
- } else {
- //
- // FV contains extension header, then produce MEDIA_FW_VOL_DEVICE_PATH
- //
- FvbDev->DevicePath = (EFI_DEVICE_PATH_PROTOCOL *)AllocateCopyPool (sizeof (FV_PIWG_DEVICE_PATH), &mFvPIWGDevicePathTemplate);
- if (FvbDev->DevicePath == NULL) {
- FreePool (FvbDev->LbaCache);
- FreePool (FvbDev);
- return EFI_OUT_OF_RESOURCES;
- }
-
- CopyGuid (
- &((FV_PIWG_DEVICE_PATH *)FvbDev->DevicePath)->FvDevPath.FvName,
- (GUID *)(UINTN)(BaseAddress + FwVolHeader->ExtHeaderOffset)
- );
- }
-
- //
- //
- // Attach FvVolBlock Protocol to new handle
- //
- Status = CoreInstallMultipleProtocolInterfaces (
- &FvbDev->Handle,
- &gEfiFirmwareVolumeBlockProtocolGuid,
- &FvbDev->FwVolBlockInstance,
- &gEfiDevicePathProtocolGuid,
- FvbDev->DevicePath,
- NULL
- );
-
- //
- // If they want the handle back, set it.
- //
- if (FvProtocol != NULL) {
- *FvProtocol = FvbDev->Handle;
- }
-
- return Status;
-}
-
-/**
- This routine consumes FV hobs and produces instances of FW_VOL_BLOCK_PROTOCOL as appropriate.
-
- @param ImageHandle The image handle.
- @param SystemTable The system table.
-
- @retval EFI_SUCCESS Successfully initialized firmware volume block
- driver.
-
-**/
-EFI_STATUS
-EFIAPI
-FwVolBlockDriverInit (
- IN EFI_HANDLE ImageHandle,
- IN EFI_SYSTEM_TABLE *SystemTable
- )
-{
- EFI_PEI_HOB_POINTERS FvHob;
- EFI_PEI_HOB_POINTERS Fv3Hob;
- UINT32 AuthenticationStatus;
-
- //
- // Core Needs Firmware Volumes to function
- //
- FvHob.Raw = GetHobList ();
- while ((FvHob.Raw = GetNextHob (EFI_HOB_TYPE_FV, FvHob.Raw)) != NULL) {
- AuthenticationStatus = 0;
- //
- // Get the authentication status propagated from PEI-phase to DXE.
- //
- Fv3Hob.Raw = GetHobList ();
- while ((Fv3Hob.Raw = GetNextHob (EFI_HOB_TYPE_FV3, Fv3Hob.Raw)) != NULL) {
- if ((Fv3Hob.FirmwareVolume3->BaseAddress == FvHob.FirmwareVolume->BaseAddress) &&
- (Fv3Hob.FirmwareVolume3->Length == FvHob.FirmwareVolume->Length))
- {
- AuthenticationStatus = Fv3Hob.FirmwareVolume3->AuthenticationStatus;
- break;
- }
-
- Fv3Hob.Raw = GET_NEXT_HOB (Fv3Hob);
- }
-
- //
- // Produce an FVB protocol for it
- //
- ProduceFVBProtocolOnBuffer (FvHob.FirmwareVolume->BaseAddress, FvHob.FirmwareVolume->Length, NULL, AuthenticationStatus, NULL);
- FvHob.Raw = GET_NEXT_HOB (FvHob);
- }
-
- return EFI_SUCCESS;
-}
-
-/**
- This DXE service routine is used to process a firmware volume. In
- particular, it can be called by BDS to process a single firmware
- volume found in a capsule.
-
- Caution: The caller need validate the input firmware volume to follow
- PI specification.
- DxeCore will trust the input data and process firmware volume directly.
-
- @param FvHeader pointer to a firmware volume header
- @param Size the size of the buffer pointed to by FvHeader
- @param FVProtocolHandle the handle on which a firmware volume protocol
- was produced for the firmware volume passed in.
-
- @retval EFI_OUT_OF_RESOURCES if an FVB could not be produced due to lack of
- system resources
- @retval EFI_VOLUME_CORRUPTED if the volume was corrupted
- @retval EFI_SUCCESS a firmware volume protocol was produced for the
- firmware volume
-
-**/
-EFI_STATUS
-EFIAPI
-CoreProcessFirmwareVolume (
- IN VOID *FvHeader,
- IN UINTN Size,
- OUT EFI_HANDLE *FVProtocolHandle
- )
-{
- VOID *Ptr;
- EFI_STATUS Status;
-
- *FVProtocolHandle = NULL;
- Status = ProduceFVBProtocolOnBuffer (
- (EFI_PHYSICAL_ADDRESS)(UINTN)FvHeader,
- (UINT64)Size,
- NULL,
- 0,
- FVProtocolHandle
- );
- //
- // Since in our implementation we use register-protocol-notify to put a
- // FV protocol on the FVB protocol handle, we can't directly verify that
- // the FV protocol was produced. Therefore here we will check the handle
- // and make sure an FV protocol is on it. This indicates that all went
- // well. Otherwise we have to assume that the volume was corrupted
- // somehow.
- //
- if (!EFI_ERROR (Status)) {
- ASSERT (*FVProtocolHandle != NULL);
- Ptr = NULL;
- Status = CoreHandleProtocol (*FVProtocolHandle, &gEfiFirmwareVolume2ProtocolGuid, (VOID **)&Ptr);
- if (EFI_ERROR (Status) || (Ptr == NULL)) {
- return EFI_VOLUME_CORRUPTED;
- }
-
- return EFI_SUCCESS;
- }
-
- return Status;
-}
+/** @file
+ Implementations for Firmware Volume Block protocol.
+
+ It consumes FV HOBs and creates read-only Firmare Volume Block protocol
+ instances for each of them.
+
+Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "DxeMain.h"
+#include "FwVolBlock.h"
+
+FV_MEMMAP_DEVICE_PATH mFvMemmapDevicePathTemplate = {
+ {
+ {
+ HARDWARE_DEVICE_PATH,
+ HW_MEMMAP_DP,
+ {
+ (UINT8)(sizeof (MEMMAP_DEVICE_PATH)),
+ (UINT8)(sizeof (MEMMAP_DEVICE_PATH) >> 8)
+ }
+ },
+ EfiMemoryMappedIO,
+ (EFI_PHYSICAL_ADDRESS)0,
+ (EFI_PHYSICAL_ADDRESS)0,
+ },
+ {
+ END_DEVICE_PATH_TYPE,
+ END_ENTIRE_DEVICE_PATH_SUBTYPE,
+ {
+ END_DEVICE_PATH_LENGTH,
+ 0
+ }
+ }
+};
+
+FV_PIWG_DEVICE_PATH mFvPIWGDevicePathTemplate = {
+ {
+ {
+ MEDIA_DEVICE_PATH,
+ MEDIA_PIWG_FW_VOL_DP,
+ {
+ (UINT8)(sizeof (MEDIA_FW_VOL_DEVICE_PATH)),
+ (UINT8)(sizeof (MEDIA_FW_VOL_DEVICE_PATH) >> 8)
+ }
+ },
+ { 0 }
+ },
+ {
+ END_DEVICE_PATH_TYPE,
+ END_ENTIRE_DEVICE_PATH_SUBTYPE,
+ {
+ END_DEVICE_PATH_LENGTH,
+ 0
+ }
+ }
+};
+
+EFI_FW_VOL_BLOCK_DEVICE mFwVolBlock = {
+ FVB_DEVICE_SIGNATURE,
+ NULL,
+ NULL,
+ {
+ FwVolBlockGetAttributes,
+ (EFI_FVB_SET_ATTRIBUTES)FwVolBlockSetAttributes,
+ FwVolBlockGetPhysicalAddress,
+ FwVolBlockGetBlockSize,
+ FwVolBlockReadBlock,
+ (EFI_FVB_WRITE)FwVolBlockWriteBlock,
+ (EFI_FVB_ERASE_BLOCKS)FwVolBlockEraseBlock,
+ NULL
+ },
+ 0,
+ NULL,
+ 0,
+ 0,
+ 0
+};
+
+/**
+ Retrieves Volume attributes. No polarity translations are done.
+
+ @param This Calling context
+ @param Attributes output buffer which contains attributes
+
+ @retval EFI_SUCCESS The firmware volume attributes were returned.
+
+**/
+EFI_STATUS
+EFIAPI
+FwVolBlockGetAttributes (
+ IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,
+ OUT EFI_FVB_ATTRIBUTES_2 *Attributes
+ )
+{
+ EFI_FW_VOL_BLOCK_DEVICE *FvbDevice;
+
+ FvbDevice = FVB_DEVICE_FROM_THIS (This);
+
+ //
+ // Since we are read only, it's safe to get attributes data from our in-memory copy.
+ //
+ *Attributes = FvbDevice->FvbAttributes & ~EFI_FVB2_WRITE_STATUS;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Modifies the current settings of the firmware volume according to the input parameter.
+
+ @param This Calling context
+ @param Attributes input buffer which contains attributes
+
+ @retval EFI_SUCCESS The firmware volume attributes were returned.
+ @retval EFI_INVALID_PARAMETER The attributes requested are in conflict with
+ the capabilities as declared in the firmware
+ volume header.
+ @retval EFI_UNSUPPORTED Not supported.
+
+**/
+EFI_STATUS
+EFIAPI
+FwVolBlockSetAttributes (
+ IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,
+ IN CONST EFI_FVB_ATTRIBUTES_2 *Attributes
+ )
+{
+ return EFI_UNSUPPORTED;
+}
+
+/**
+ The EraseBlock() function erases one or more blocks as denoted by the
+ variable argument list. The entire parameter list of blocks must be verified
+ prior to erasing any blocks. If a block is requested that does not exist
+ within the associated firmware volume (it has a larger index than the last
+ block of the firmware volume), the EraseBlock() function must return
+ EFI_INVALID_PARAMETER without modifying the contents of the firmware volume.
+
+ @param This Calling context
+ @param ... Starting LBA followed by Number of Lba to erase.
+ a -1 to terminate the list.
+
+ @retval EFI_SUCCESS The erase request was successfully completed.
+ @retval EFI_ACCESS_DENIED The firmware volume is in the WriteDisabled
+ state.
+ @retval EFI_DEVICE_ERROR The block device is not functioning correctly
+ and could not be written. The firmware device
+ may have been partially erased.
+ @retval EFI_INVALID_PARAMETER One or more of the LBAs listed in the variable
+ argument list do
+ @retval EFI_UNSUPPORTED Not supported.
+
+**/
+EFI_STATUS
+EFIAPI
+FwVolBlockEraseBlock (
+ IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,
+ ...
+ )
+{
+ return EFI_UNSUPPORTED;
+}
+
+/**
+ Read the specified number of bytes from the block to the input buffer.
+
+ @param This Indicates the calling context.
+ @param Lba The starting logical block index to read.
+ @param Offset Offset into the block at which to begin reading.
+ @param NumBytes Pointer to a UINT32. At entry, *NumBytes
+ contains the total size of the buffer. At exit,
+ *NumBytes contains the total number of bytes
+ actually read.
+ @param Buffer Pinter to a caller-allocated buffer that
+ contains the destine for the read.
+
+ @retval EFI_SUCCESS The firmware volume was read successfully.
+ @retval EFI_BAD_BUFFER_SIZE The read was attempted across an LBA boundary.
+ @retval EFI_ACCESS_DENIED Access denied.
+ @retval EFI_DEVICE_ERROR The block device is malfunctioning and could not
+ be read.
+
+**/
+EFI_STATUS
+EFIAPI
+FwVolBlockReadBlock (
+ IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,
+ IN CONST EFI_LBA Lba,
+ IN CONST UINTN Offset,
+ IN OUT UINTN *NumBytes,
+ IN OUT UINT8 *Buffer
+ )
+{
+ EFI_FW_VOL_BLOCK_DEVICE *FvbDevice;
+ EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader;
+ UINT8 *LbaOffset;
+ UINTN LbaStart;
+ UINTN NumOfBytesRead;
+ UINTN LbaIndex;
+
+ FvbDevice = FVB_DEVICE_FROM_THIS (This);
+
+ //
+ // Check if This FW can be read
+ //
+ if ((FvbDevice->FvbAttributes & EFI_FVB2_READ_STATUS) == 0) {
+ return EFI_ACCESS_DENIED;
+ }
+
+ LbaIndex = (UINTN)Lba;
+ if (LbaIndex >= FvbDevice->NumBlocks) {
+ //
+ // Invalid Lba, read nothing.
+ //
+ *NumBytes = 0;
+ return EFI_BAD_BUFFER_SIZE;
+ }
+
+ if (Offset > FvbDevice->LbaCache[LbaIndex].Length) {
+ //
+ // all exceed boundary, read nothing.
+ //
+ *NumBytes = 0;
+ return EFI_BAD_BUFFER_SIZE;
+ }
+
+ NumOfBytesRead = *NumBytes;
+ if (Offset + NumOfBytesRead > FvbDevice->LbaCache[LbaIndex].Length) {
+ //
+ // partial exceed boundary, read data from current postion to end.
+ //
+ NumOfBytesRead = FvbDevice->LbaCache[LbaIndex].Length - Offset;
+ }
+
+ LbaStart = FvbDevice->LbaCache[LbaIndex].Base;
+ FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *)((UINTN)FvbDevice->BaseAddress);
+ LbaOffset = (UINT8 *)FwVolHeader + LbaStart + Offset;
+
+ //
+ // Perform read operation
+ //
+ CopyMem (Buffer, LbaOffset, NumOfBytesRead);
+
+ if (NumOfBytesRead == *NumBytes) {
+ return EFI_SUCCESS;
+ }
+
+ *NumBytes = NumOfBytesRead;
+ return EFI_BAD_BUFFER_SIZE;
+}
+
+/**
+ Writes the specified number of bytes from the input buffer to the block.
+
+ @param This Indicates the calling context.
+ @param Lba The starting logical block index to write to.
+ @param Offset Offset into the block at which to begin writing.
+ @param NumBytes Pointer to a UINT32. At entry, *NumBytes
+ contains the total size of the buffer. At exit,
+ *NumBytes contains the total number of bytes
+ actually written.
+ @param Buffer Pinter to a caller-allocated buffer that
+ contains the source for the write.
+
+ @retval EFI_SUCCESS The firmware volume was written successfully.
+ @retval EFI_BAD_BUFFER_SIZE The write was attempted across an LBA boundary.
+ On output, NumBytes contains the total number of
+ bytes actually written.
+ @retval EFI_ACCESS_DENIED The firmware volume is in the WriteDisabled
+ state.
+ @retval EFI_DEVICE_ERROR The block device is malfunctioning and could not
+ be written.
+ @retval EFI_UNSUPPORTED Not supported.
+
+**/
+EFI_STATUS
+EFIAPI
+FwVolBlockWriteBlock (
+ IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,
+ IN EFI_LBA Lba,
+ IN UINTN Offset,
+ IN OUT UINTN *NumBytes,
+ IN UINT8 *Buffer
+ )
+{
+ return EFI_UNSUPPORTED;
+}
+
+/**
+ Get Fvb's base address.
+
+ @param This Indicates the calling context.
+ @param Address Fvb device base address.
+
+ @retval EFI_SUCCESS Successfully got Fvb's base address.
+ @retval EFI_UNSUPPORTED Not supported.
+
+**/
+EFI_STATUS
+EFIAPI
+FwVolBlockGetPhysicalAddress (
+ IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,
+ OUT EFI_PHYSICAL_ADDRESS *Address
+ )
+{
+ EFI_FW_VOL_BLOCK_DEVICE *FvbDevice;
+
+ FvbDevice = FVB_DEVICE_FROM_THIS (This);
+
+ if ((FvbDevice->FvbAttributes & EFI_FVB2_MEMORY_MAPPED) != 0) {
+ *Address = FvbDevice->BaseAddress;
+ return EFI_SUCCESS;
+ }
+
+ return EFI_UNSUPPORTED;
+}
+
+/**
+ Retrieves the size in bytes of a specific block within a firmware volume.
+
+ @param This Indicates the calling context.
+ @param Lba Indicates the block for which to return the
+ size.
+ @param BlockSize Pointer to a caller-allocated UINTN in which the
+ size of the block is returned.
+ @param NumberOfBlocks Pointer to a caller-allocated UINTN in which the
+ number of consecutive blocks starting with Lba
+ is returned. All blocks in this range have a
+ size of BlockSize.
+
+ @retval EFI_SUCCESS The firmware volume base address is returned.
+ @retval EFI_INVALID_PARAMETER The requested LBA is out of range.
+
+**/
+EFI_STATUS
+EFIAPI
+FwVolBlockGetBlockSize (
+ IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,
+ IN CONST EFI_LBA Lba,
+ IN OUT UINTN *BlockSize,
+ IN OUT UINTN *NumberOfBlocks
+ )
+{
+ UINTN TotalBlocks;
+ EFI_FW_VOL_BLOCK_DEVICE *FvbDevice;
+ EFI_FV_BLOCK_MAP_ENTRY *PtrBlockMapEntry;
+ EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader;
+
+ FvbDevice = FVB_DEVICE_FROM_THIS (This);
+
+ //
+ // Do parameter checking
+ //
+ if (Lba >= FvbDevice->NumBlocks) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *)((UINTN)FvbDevice->BaseAddress);
+
+ PtrBlockMapEntry = FwVolHeader->BlockMap;
+
+ //
+ // Search the block map for the given block
+ //
+ TotalBlocks = 0;
+ while ((PtrBlockMapEntry->NumBlocks != 0) || (PtrBlockMapEntry->Length != 0)) {
+ TotalBlocks += PtrBlockMapEntry->NumBlocks;
+ if (Lba < TotalBlocks) {
+ //
+ // We find the range
+ //
+ break;
+ }
+
+ PtrBlockMapEntry++;
+ }
+
+ *BlockSize = PtrBlockMapEntry->Length;
+ *NumberOfBlocks = TotalBlocks - (UINTN)Lba;
+
+ return EFI_SUCCESS;
+}
+
+/**
+
+ Get FVB authentication status
+
+ @param FvbProtocol FVB protocol.
+
+ @return Authentication status.
+
+**/
+UINT32
+GetFvbAuthenticationStatus (
+ IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *FvbProtocol
+ )
+{
+ EFI_FW_VOL_BLOCK_DEVICE *FvbDevice;
+ UINT32 AuthenticationStatus;
+
+ AuthenticationStatus = 0;
+ FvbDevice = BASE_CR (FvbProtocol, EFI_FW_VOL_BLOCK_DEVICE, FwVolBlockInstance);
+ if (FvbDevice->Signature == FVB_DEVICE_SIGNATURE) {
+ AuthenticationStatus = FvbDevice->AuthenticationStatus;
+ }
+
+ return AuthenticationStatus;
+}
+
+/**
+ This routine produces a firmware volume block protocol on a given
+ buffer.
+
+ @param BaseAddress base address of the firmware volume image
+ @param Length length of the firmware volume image
+ @param ParentHandle handle of parent firmware volume, if this image
+ came from an FV image file and section in another firmware
+ volume (ala capsules)
+ @param AuthenticationStatus Authentication status inherited, if this image
+ came from an FV image file and section in another firmware volume.
+ @param FvProtocol Firmware volume block protocol produced.
+
+ @retval EFI_VOLUME_CORRUPTED Volume corrupted.
+ @retval EFI_OUT_OF_RESOURCES No enough buffer to be allocated.
+ @retval EFI_SUCCESS Successfully produced a FVB protocol on given
+ buffer.
+
+**/
+EFI_STATUS
+ProduceFVBProtocolOnBuffer (
+ IN EFI_PHYSICAL_ADDRESS BaseAddress,
+ IN UINT64 Length,
+ IN EFI_HANDLE ParentHandle,
+ IN UINT32 AuthenticationStatus,
+ OUT EFI_HANDLE *FvProtocol OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+ EFI_FW_VOL_BLOCK_DEVICE *FvbDev;
+ EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader;
+ UINTN BlockIndex;
+ UINTN BlockIndex2;
+ UINTN LinearOffset;
+ UINT32 FvAlignment;
+ EFI_FV_BLOCK_MAP_ENTRY *PtrBlockMapEntry;
+
+ FvAlignment = 0;
+ FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *)(UINTN)BaseAddress;
+ //
+ // Validate FV Header, if not as expected, return
+ //
+ if (FwVolHeader->Signature != EFI_FVH_SIGNATURE) {
+ return EFI_VOLUME_CORRUPTED;
+ }
+
+ //
+ // If EFI_FVB2_WEAK_ALIGNMENT is set in the volume header then the first byte of the volume
+ // can be aligned on any power-of-two boundary. A weakly aligned volume can not be moved from
+ // its initial linked location and maintain its alignment.
+ //
+ if ((FwVolHeader->Attributes & EFI_FVB2_WEAK_ALIGNMENT) != EFI_FVB2_WEAK_ALIGNMENT) {
+ //
+ // Get FvHeader alignment
+ //
+ FvAlignment = 1 << ((FwVolHeader->Attributes & EFI_FVB2_ALIGNMENT) >> 16);
+ //
+ // FvAlignment must be greater than or equal to 8 bytes of the minimum FFS alignment value.
+ //
+ if (FvAlignment < 8) {
+ FvAlignment = 8;
+ }
+
+ if ((UINTN)BaseAddress % FvAlignment != 0) {
+ //
+ // FvImage buffer is not at its required alignment.
+ //
+ DEBUG ((
+ DEBUG_ERROR,
+ "Unaligned FvImage found at 0x%lx:0x%lx, the required alignment is 0x%x\n",
+ BaseAddress,
+ Length,
+ FvAlignment
+ ));
+ return EFI_VOLUME_CORRUPTED;
+ }
+ }
+
+ //
+ // Allocate EFI_FW_VOL_BLOCK_DEVICE
+ //
+ FvbDev = AllocateCopyPool (sizeof (EFI_FW_VOL_BLOCK_DEVICE), &mFwVolBlock);
+ if (FvbDev == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ FvbDev->BaseAddress = BaseAddress;
+ FvbDev->FvbAttributes = FwVolHeader->Attributes;
+ FvbDev->FwVolBlockInstance.ParentHandle = ParentHandle;
+ FvbDev->AuthenticationStatus = AuthenticationStatus;
+
+ //
+ // Init the block caching fields of the device
+ // First, count the number of blocks
+ //
+ FvbDev->NumBlocks = 0;
+ for (PtrBlockMapEntry = FwVolHeader->BlockMap;
+ PtrBlockMapEntry->NumBlocks != 0;
+ PtrBlockMapEntry++)
+ {
+ FvbDev->NumBlocks += PtrBlockMapEntry->NumBlocks;
+ }
+
+ //
+ // Second, allocate the cache
+ //
+ if (FvbDev->NumBlocks >= (MAX_ADDRESS / sizeof (LBA_CACHE))) {
+ CoreFreePool (FvbDev);
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ FvbDev->LbaCache = AllocatePool (FvbDev->NumBlocks * sizeof (LBA_CACHE));
+ if (FvbDev->LbaCache == NULL) {
+ CoreFreePool (FvbDev);
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ //
+ // Last, fill in the cache with the linear address of the blocks
+ //
+ BlockIndex = 0;
+ LinearOffset = 0;
+ for (PtrBlockMapEntry = FwVolHeader->BlockMap;
+ PtrBlockMapEntry->NumBlocks != 0; PtrBlockMapEntry++)
+ {
+ for (BlockIndex2 = 0; BlockIndex2 < PtrBlockMapEntry->NumBlocks; BlockIndex2++) {
+ FvbDev->LbaCache[BlockIndex].Base = LinearOffset;
+ FvbDev->LbaCache[BlockIndex].Length = PtrBlockMapEntry->Length;
+ LinearOffset += PtrBlockMapEntry->Length;
+ BlockIndex++;
+ }
+ }
+
+ //
+ // Judget whether FV name guid is produced in Fv extension header
+ //
+ if (FwVolHeader->ExtHeaderOffset == 0) {
+ //
+ // FV does not contains extension header, then produce MEMMAP_DEVICE_PATH
+ //
+ FvbDev->DevicePath = (EFI_DEVICE_PATH_PROTOCOL *)AllocateCopyPool (sizeof (FV_MEMMAP_DEVICE_PATH), &mFvMemmapDevicePathTemplate);
+ if (FvbDev->DevicePath == NULL) {
+ FreePool (FvbDev->LbaCache);
+ FreePool (FvbDev);
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ ((FV_MEMMAP_DEVICE_PATH *)FvbDev->DevicePath)->MemMapDevPath.StartingAddress = BaseAddress;
+ ((FV_MEMMAP_DEVICE_PATH *)FvbDev->DevicePath)->MemMapDevPath.EndingAddress = BaseAddress + FwVolHeader->FvLength - 1;
+ } else {
+ //
+ // FV contains extension header, then produce MEDIA_FW_VOL_DEVICE_PATH
+ //
+ FvbDev->DevicePath = (EFI_DEVICE_PATH_PROTOCOL *)AllocateCopyPool (sizeof (FV_PIWG_DEVICE_PATH), &mFvPIWGDevicePathTemplate);
+ if (FvbDev->DevicePath == NULL) {
+ FreePool (FvbDev->LbaCache);
+ FreePool (FvbDev);
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ CopyGuid (
+ &((FV_PIWG_DEVICE_PATH *)FvbDev->DevicePath)->FvDevPath.FvName,
+ (GUID *)(UINTN)(BaseAddress + FwVolHeader->ExtHeaderOffset)
+ );
+ }
+
+ //
+ //
+ // Attach FvVolBlock Protocol to new handle
+ //
+ Status = CoreInstallMultipleProtocolInterfaces (
+ &FvbDev->Handle,
+ &gEfiFirmwareVolumeBlockProtocolGuid,
+ &FvbDev->FwVolBlockInstance,
+ &gEfiDevicePathProtocolGuid,
+ FvbDev->DevicePath,
+ NULL
+ );
+
+ //
+ // If they want the handle back, set it.
+ //
+ if (FvProtocol != NULL) {
+ *FvProtocol = FvbDev->Handle;
+ }
+
+ return Status;
+}
+
+/**
+ This routine consumes FV hobs and produces instances of FW_VOL_BLOCK_PROTOCOL as appropriate.
+
+ @param ImageHandle The image handle.
+ @param SystemTable The system table.
+
+ @retval EFI_SUCCESS Successfully initialized firmware volume block
+ driver.
+
+**/
+EFI_STATUS
+EFIAPI
+FwVolBlockDriverInit (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_PEI_HOB_POINTERS FvHob;
+ EFI_PEI_HOB_POINTERS Fv3Hob;
+ UINT32 AuthenticationStatus;
+
+ //
+ // Core Needs Firmware Volumes to function
+ //
+ FvHob.Raw = GetHobList ();
+ while ((FvHob.Raw = GetNextHob (EFI_HOB_TYPE_FV, FvHob.Raw)) != NULL) {
+ AuthenticationStatus = 0;
+ //
+ // Get the authentication status propagated from PEI-phase to DXE.
+ //
+ Fv3Hob.Raw = GetHobList ();
+ while ((Fv3Hob.Raw = GetNextHob (EFI_HOB_TYPE_FV3, Fv3Hob.Raw)) != NULL) {
+ if ((Fv3Hob.FirmwareVolume3->BaseAddress == FvHob.FirmwareVolume->BaseAddress) &&
+ (Fv3Hob.FirmwareVolume3->Length == FvHob.FirmwareVolume->Length))
+ {
+ AuthenticationStatus = Fv3Hob.FirmwareVolume3->AuthenticationStatus;
+ break;
+ }
+
+ Fv3Hob.Raw = GET_NEXT_HOB (Fv3Hob);
+ }
+
+ //
+ // Produce an FVB protocol for it
+ //
+ ProduceFVBProtocolOnBuffer (FvHob.FirmwareVolume->BaseAddress, FvHob.FirmwareVolume->Length, NULL, AuthenticationStatus, NULL);
+ FvHob.Raw = GET_NEXT_HOB (FvHob);
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ This DXE service routine is used to process a firmware volume. In
+ particular, it can be called by BDS to process a single firmware
+ volume found in a capsule.
+
+ Caution: The caller need validate the input firmware volume to follow
+ PI specification.
+ DxeCore will trust the input data and process firmware volume directly.
+
+ @param FvHeader pointer to a firmware volume header
+ @param Size the size of the buffer pointed to by FvHeader
+ @param FVProtocolHandle the handle on which a firmware volume protocol
+ was produced for the firmware volume passed in.
+
+ @retval EFI_OUT_OF_RESOURCES if an FVB could not be produced due to lack of
+ system resources
+ @retval EFI_VOLUME_CORRUPTED if the volume was corrupted
+ @retval EFI_SUCCESS a firmware volume protocol was produced for the
+ firmware volume
+
+**/
+EFI_STATUS
+EFIAPI
+CoreProcessFirmwareVolume (
+ IN VOID *FvHeader,
+ IN UINTN Size,
+ OUT EFI_HANDLE *FVProtocolHandle
+ )
+{
+ VOID *Ptr;
+ EFI_STATUS Status;
+
+ *FVProtocolHandle = NULL;
+ Status = ProduceFVBProtocolOnBuffer (
+ (EFI_PHYSICAL_ADDRESS)(UINTN)FvHeader,
+ (UINT64)Size,
+ NULL,
+ 0,
+ FVProtocolHandle
+ );
+ //
+ // Since in our implementation we use register-protocol-notify to put a
+ // FV protocol on the FVB protocol handle, we can't directly verify that
+ // the FV protocol was produced. Therefore here we will check the handle
+ // and make sure an FV protocol is on it. This indicates that all went
+ // well. Otherwise we have to assume that the volume was corrupted
+ // somehow.
+ //
+ if (!EFI_ERROR (Status)) {
+ ASSERT (*FVProtocolHandle != NULL);
+ Ptr = NULL;
+ Status = CoreHandleProtocol (*FVProtocolHandle, &gEfiFirmwareVolume2ProtocolGuid, (VOID **)&Ptr);
+ if (EFI_ERROR (Status) || (Ptr == NULL)) {
+ return EFI_VOLUME_CORRUPTED;
+ }
+
+ return EFI_SUCCESS;
+ }
+
+ return Status;
+}
diff --git a/MdeModulePkg/Core/Dxe/FwVolBlock/FwVolBlock.h b/MdeModulePkg/Core/Dxe/FwVolBlock/FwVolBlock.h
index aa2ab7f7c2..06a9535ea6 100644
--- a/MdeModulePkg/Core/Dxe/FwVolBlock/FwVolBlock.h
+++ b/MdeModulePkg/Core/Dxe/FwVolBlock/FwVolBlock.h
@@ -1,221 +1,221 @@
-/** @file
- Firmware Volume Block protocol functions.
- Consumes FV hobs and creates appropriate block protocols.
-
-Copyright (c) 2006 - 2012, Intel Corporation. All rights reserved.<BR>
-SPDX-License-Identifier: BSD-2-Clause-Patent
-
-**/
-
-#ifndef _FWVOL_BLOCK_H_
-#define _FWVOL_BLOCK_H_
-
-#define FVB_DEVICE_SIGNATURE SIGNATURE_32('_','F','V','B')
-
-typedef struct {
- UINTN Base;
- UINTN Length;
-} LBA_CACHE;
-
-typedef struct {
- MEMMAP_DEVICE_PATH MemMapDevPath;
- EFI_DEVICE_PATH_PROTOCOL EndDevPath;
-} FV_MEMMAP_DEVICE_PATH;
-
-//
-// UEFI Specification define FV device path format if FV provide name guid in extension header
-//
-typedef struct {
- MEDIA_FW_VOL_DEVICE_PATH FvDevPath;
- EFI_DEVICE_PATH_PROTOCOL EndDevPath;
-} FV_PIWG_DEVICE_PATH;
-
-typedef struct {
- UINTN Signature;
- EFI_HANDLE Handle;
- EFI_DEVICE_PATH_PROTOCOL *DevicePath;
- EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL FwVolBlockInstance;
- UINTN NumBlocks;
- LBA_CACHE *LbaCache;
- UINT32 FvbAttributes;
- EFI_PHYSICAL_ADDRESS BaseAddress;
- UINT32 AuthenticationStatus;
-} EFI_FW_VOL_BLOCK_DEVICE;
-
-#define FVB_DEVICE_FROM_THIS(a) \
- CR(a, EFI_FW_VOL_BLOCK_DEVICE, FwVolBlockInstance, FVB_DEVICE_SIGNATURE)
-
-/**
- Retrieves Volume attributes. No polarity translations are done.
-
- @param This Calling context
- @param Attributes output buffer which contains attributes
-
- @retval EFI_SUCCESS The firmware volume attributes were returned.
-
-**/
-EFI_STATUS
-EFIAPI
-FwVolBlockGetAttributes (
- IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,
- OUT EFI_FVB_ATTRIBUTES_2 *Attributes
- );
-
-/**
- Modifies the current settings of the firmware volume according to the input parameter.
-
- @param This Calling context
- @param Attributes input buffer which contains attributes
-
- @retval EFI_SUCCESS The firmware volume attributes were returned.
- @retval EFI_INVALID_PARAMETER The attributes requested are in conflict with
- the capabilities as declared in the firmware
- volume header.
- @retval EFI_UNSUPPORTED Not supported.
-
-**/
-EFI_STATUS
-EFIAPI
-FwVolBlockSetAttributes (
- IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,
- IN CONST EFI_FVB_ATTRIBUTES_2 *Attributes
- );
-
-/**
- The EraseBlock() function erases one or more blocks as denoted by the
- variable argument list. The entire parameter list of blocks must be verified
- prior to erasing any blocks. If a block is requested that does not exist
- within the associated firmware volume (it has a larger index than the last
- block of the firmware volume), the EraseBlock() function must return
- EFI_INVALID_PARAMETER without modifying the contents of the firmware volume.
-
- @param This Calling context
- @param ... Starting LBA followed by Number of Lba to erase.
- a -1 to terminate the list.
-
- @retval EFI_SUCCESS The erase request was successfully completed.
- @retval EFI_ACCESS_DENIED The firmware volume is in the WriteDisabled
- state.
- @retval EFI_DEVICE_ERROR The block device is not functioning correctly
- and could not be written. The firmware device
- may have been partially erased.
- @retval EFI_INVALID_PARAMETER One or more of the LBAs listed in the variable
- argument list do
- @retval EFI_UNSUPPORTED Not supported.
-
-**/
-EFI_STATUS
-EFIAPI
-FwVolBlockEraseBlock (
- IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,
- ...
- );
-
-/**
- Read the specified number of bytes from the block to the input buffer.
-
- @param This Indicates the calling context.
- @param Lba The starting logical block index to read.
- @param Offset Offset into the block at which to begin reading.
- @param NumBytes Pointer to a UINT32. At entry, *NumBytes
- contains the total size of the buffer. At exit,
- *NumBytes contains the total number of bytes
- actually read.
- @param Buffer Pinter to a caller-allocated buffer that
- contains the destine for the read.
-
- @retval EFI_SUCCESS The firmware volume was read successfully.
- @retval EFI_BAD_BUFFER_SIZE The read was attempted across an LBA boundary.
- @retval EFI_ACCESS_DENIED Access denied.
- @retval EFI_DEVICE_ERROR The block device is malfunctioning and could not
- be read.
-
-**/
-EFI_STATUS
-EFIAPI
-FwVolBlockReadBlock (
- IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,
- IN CONST EFI_LBA Lba,
- IN CONST UINTN Offset,
- IN OUT UINTN *NumBytes,
- IN OUT UINT8 *Buffer
- );
-
-/**
- Writes the specified number of bytes from the input buffer to the block.
-
- @param This Indicates the calling context.
- @param Lba The starting logical block index to write to.
- @param Offset Offset into the block at which to begin writing.
- @param NumBytes Pointer to a UINT32. At entry, *NumBytes
- contains the total size of the buffer. At exit,
- *NumBytes contains the total number of bytes
- actually written.
- @param Buffer Pinter to a caller-allocated buffer that
- contains the source for the write.
-
- @retval EFI_SUCCESS The firmware volume was written successfully.
- @retval EFI_BAD_BUFFER_SIZE The write was attempted across an LBA boundary.
- On output, NumBytes contains the total number of
- bytes actually written.
- @retval EFI_ACCESS_DENIED The firmware volume is in the WriteDisabled
- state.
- @retval EFI_DEVICE_ERROR The block device is malfunctioning and could not
- be written.
- @retval EFI_UNSUPPORTED Not supported.
-
-**/
-EFI_STATUS
-EFIAPI
-FwVolBlockWriteBlock (
- IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,
- IN EFI_LBA Lba,
- IN UINTN Offset,
- IN OUT UINTN *NumBytes,
- IN UINT8 *Buffer
- );
-
-/**
- Get Fvb's base address.
-
- @param This Indicates the calling context.
- @param Address Fvb device base address.
-
- @retval EFI_SUCCESS Successfully got Fvb's base address.
- @retval EFI_UNSUPPORTED Not supported.
-
-**/
-EFI_STATUS
-EFIAPI
-FwVolBlockGetPhysicalAddress (
- IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,
- OUT EFI_PHYSICAL_ADDRESS *Address
- );
-
-/**
- Retrieves the size in bytes of a specific block within a firmware volume.
-
- @param This Indicates the calling context.
- @param Lba Indicates the block for which to return the
- size.
- @param BlockSize Pointer to a caller-allocated UINTN in which the
- size of the block is returned.
- @param NumberOfBlocks Pointer to a caller-allocated UINTN in which the
- number of consecutive blocks starting with Lba
- is returned. All blocks in this range have a
- size of BlockSize.
-
- @retval EFI_SUCCESS The firmware volume base address is returned.
- @retval EFI_INVALID_PARAMETER The requested LBA is out of range.
-
-**/
-EFI_STATUS
-EFIAPI
-FwVolBlockGetBlockSize (
- IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,
- IN CONST EFI_LBA Lba,
- IN OUT UINTN *BlockSize,
- IN OUT UINTN *NumberOfBlocks
- );
-
-#endif
+/** @file
+ Firmware Volume Block protocol functions.
+ Consumes FV hobs and creates appropriate block protocols.
+
+Copyright (c) 2006 - 2012, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _FWVOL_BLOCK_H_
+#define _FWVOL_BLOCK_H_
+
+#define FVB_DEVICE_SIGNATURE SIGNATURE_32('_','F','V','B')
+
+typedef struct {
+ UINTN Base;
+ UINTN Length;
+} LBA_CACHE;
+
+typedef struct {
+ MEMMAP_DEVICE_PATH MemMapDevPath;
+ EFI_DEVICE_PATH_PROTOCOL EndDevPath;
+} FV_MEMMAP_DEVICE_PATH;
+
+//
+// UEFI Specification define FV device path format if FV provide name guid in extension header
+//
+typedef struct {
+ MEDIA_FW_VOL_DEVICE_PATH FvDevPath;
+ EFI_DEVICE_PATH_PROTOCOL EndDevPath;
+} FV_PIWG_DEVICE_PATH;
+
+typedef struct {
+ UINTN Signature;
+ EFI_HANDLE Handle;
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;
+ EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL FwVolBlockInstance;
+ UINTN NumBlocks;
+ LBA_CACHE *LbaCache;
+ UINT32 FvbAttributes;
+ EFI_PHYSICAL_ADDRESS BaseAddress;
+ UINT32 AuthenticationStatus;
+} EFI_FW_VOL_BLOCK_DEVICE;
+
+#define FVB_DEVICE_FROM_THIS(a) \
+ CR(a, EFI_FW_VOL_BLOCK_DEVICE, FwVolBlockInstance, FVB_DEVICE_SIGNATURE)
+
+/**
+ Retrieves Volume attributes. No polarity translations are done.
+
+ @param This Calling context
+ @param Attributes output buffer which contains attributes
+
+ @retval EFI_SUCCESS The firmware volume attributes were returned.
+
+**/
+EFI_STATUS
+EFIAPI
+FwVolBlockGetAttributes (
+ IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,
+ OUT EFI_FVB_ATTRIBUTES_2 *Attributes
+ );
+
+/**
+ Modifies the current settings of the firmware volume according to the input parameter.
+
+ @param This Calling context
+ @param Attributes input buffer which contains attributes
+
+ @retval EFI_SUCCESS The firmware volume attributes were returned.
+ @retval EFI_INVALID_PARAMETER The attributes requested are in conflict with
+ the capabilities as declared in the firmware
+ volume header.
+ @retval EFI_UNSUPPORTED Not supported.
+
+**/
+EFI_STATUS
+EFIAPI
+FwVolBlockSetAttributes (
+ IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,
+ IN CONST EFI_FVB_ATTRIBUTES_2 *Attributes
+ );
+
+/**
+ The EraseBlock() function erases one or more blocks as denoted by the
+ variable argument list. The entire parameter list of blocks must be verified
+ prior to erasing any blocks. If a block is requested that does not exist
+ within the associated firmware volume (it has a larger index than the last
+ block of the firmware volume), the EraseBlock() function must return
+ EFI_INVALID_PARAMETER without modifying the contents of the firmware volume.
+
+ @param This Calling context
+ @param ... Starting LBA followed by Number of Lba to erase.
+ a -1 to terminate the list.
+
+ @retval EFI_SUCCESS The erase request was successfully completed.
+ @retval EFI_ACCESS_DENIED The firmware volume is in the WriteDisabled
+ state.
+ @retval EFI_DEVICE_ERROR The block device is not functioning correctly
+ and could not be written. The firmware device
+ may have been partially erased.
+ @retval EFI_INVALID_PARAMETER One or more of the LBAs listed in the variable
+ argument list do
+ @retval EFI_UNSUPPORTED Not supported.
+
+**/
+EFI_STATUS
+EFIAPI
+FwVolBlockEraseBlock (
+ IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,
+ ...
+ );
+
+/**
+ Read the specified number of bytes from the block to the input buffer.
+
+ @param This Indicates the calling context.
+ @param Lba The starting logical block index to read.
+ @param Offset Offset into the block at which to begin reading.
+ @param NumBytes Pointer to a UINT32. At entry, *NumBytes
+ contains the total size of the buffer. At exit,
+ *NumBytes contains the total number of bytes
+ actually read.
+ @param Buffer Pinter to a caller-allocated buffer that
+ contains the destine for the read.
+
+ @retval EFI_SUCCESS The firmware volume was read successfully.
+ @retval EFI_BAD_BUFFER_SIZE The read was attempted across an LBA boundary.
+ @retval EFI_ACCESS_DENIED Access denied.
+ @retval EFI_DEVICE_ERROR The block device is malfunctioning and could not
+ be read.
+
+**/
+EFI_STATUS
+EFIAPI
+FwVolBlockReadBlock (
+ IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,
+ IN CONST EFI_LBA Lba,
+ IN CONST UINTN Offset,
+ IN OUT UINTN *NumBytes,
+ IN OUT UINT8 *Buffer
+ );
+
+/**
+ Writes the specified number of bytes from the input buffer to the block.
+
+ @param This Indicates the calling context.
+ @param Lba The starting logical block index to write to.
+ @param Offset Offset into the block at which to begin writing.
+ @param NumBytes Pointer to a UINT32. At entry, *NumBytes
+ contains the total size of the buffer. At exit,
+ *NumBytes contains the total number of bytes
+ actually written.
+ @param Buffer Pinter to a caller-allocated buffer that
+ contains the source for the write.
+
+ @retval EFI_SUCCESS The firmware volume was written successfully.
+ @retval EFI_BAD_BUFFER_SIZE The write was attempted across an LBA boundary.
+ On output, NumBytes contains the total number of
+ bytes actually written.
+ @retval EFI_ACCESS_DENIED The firmware volume is in the WriteDisabled
+ state.
+ @retval EFI_DEVICE_ERROR The block device is malfunctioning and could not
+ be written.
+ @retval EFI_UNSUPPORTED Not supported.
+
+**/
+EFI_STATUS
+EFIAPI
+FwVolBlockWriteBlock (
+ IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,
+ IN EFI_LBA Lba,
+ IN UINTN Offset,
+ IN OUT UINTN *NumBytes,
+ IN UINT8 *Buffer
+ );
+
+/**
+ Get Fvb's base address.
+
+ @param This Indicates the calling context.
+ @param Address Fvb device base address.
+
+ @retval EFI_SUCCESS Successfully got Fvb's base address.
+ @retval EFI_UNSUPPORTED Not supported.
+
+**/
+EFI_STATUS
+EFIAPI
+FwVolBlockGetPhysicalAddress (
+ IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,
+ OUT EFI_PHYSICAL_ADDRESS *Address
+ );
+
+/**
+ Retrieves the size in bytes of a specific block within a firmware volume.
+
+ @param This Indicates the calling context.
+ @param Lba Indicates the block for which to return the
+ size.
+ @param BlockSize Pointer to a caller-allocated UINTN in which the
+ size of the block is returned.
+ @param NumberOfBlocks Pointer to a caller-allocated UINTN in which the
+ number of consecutive blocks starting with Lba
+ is returned. All blocks in this range have a
+ size of BlockSize.
+
+ @retval EFI_SUCCESS The firmware volume base address is returned.
+ @retval EFI_INVALID_PARAMETER The requested LBA is out of range.
+
+**/
+EFI_STATUS
+EFIAPI
+FwVolBlockGetBlockSize (
+ IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,
+ IN CONST EFI_LBA Lba,
+ IN OUT UINTN *BlockSize,
+ IN OUT UINTN *NumberOfBlocks
+ );
+
+#endif
diff --git a/MdeModulePkg/Core/Dxe/Gcd/Gcd.c b/MdeModulePkg/Core/Dxe/Gcd/Gcd.c
index 99364508cd..b9057b158b 100644
--- a/MdeModulePkg/Core/Dxe/Gcd/Gcd.c
+++ b/MdeModulePkg/Core/Dxe/Gcd/Gcd.c
@@ -1,2876 +1,2876 @@
-/** @file
- The file contains the GCD related services in the EFI Boot Services Table.
- The GCD services are used to manage the memory and I/O regions that
- are accessible to the CPU that is executing the DXE core.
-
-Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
-SPDX-License-Identifier: BSD-2-Clause-Patent
-
-**/
-
-#include <Pi/PiDxeCis.h>
-#include <Pi/PiHob.h>
-#include "DxeMain.h"
-#include "Gcd.h"
-#include "Mem/HeapGuard.h"
-
-#define MINIMUM_INITIAL_MEMORY_SIZE 0x10000
-
-#define MEMORY_ATTRIBUTE_MASK (EFI_RESOURCE_ATTRIBUTE_PRESENT | \
- EFI_RESOURCE_ATTRIBUTE_INITIALIZED | \
- EFI_RESOURCE_ATTRIBUTE_TESTED | \
- EFI_RESOURCE_ATTRIBUTE_READ_PROTECTED | \
- EFI_RESOURCE_ATTRIBUTE_WRITE_PROTECTED | \
- EFI_RESOURCE_ATTRIBUTE_EXECUTION_PROTECTED | \
- EFI_RESOURCE_ATTRIBUTE_READ_ONLY_PROTECTED | \
- EFI_RESOURCE_ATTRIBUTE_16_BIT_IO | \
- EFI_RESOURCE_ATTRIBUTE_32_BIT_IO | \
- EFI_RESOURCE_ATTRIBUTE_64_BIT_IO | \
- EFI_RESOURCE_ATTRIBUTE_PERSISTENT )
-
-#define TESTED_MEMORY_ATTRIBUTES (EFI_RESOURCE_ATTRIBUTE_PRESENT | \
- EFI_RESOURCE_ATTRIBUTE_INITIALIZED | \
- EFI_RESOURCE_ATTRIBUTE_TESTED )
-
-#define INITIALIZED_MEMORY_ATTRIBUTES (EFI_RESOURCE_ATTRIBUTE_PRESENT |\
- EFI_RESOURCE_ATTRIBUTE_INITIALIZED )
-
-#define PRESENT_MEMORY_ATTRIBUTES (EFI_RESOURCE_ATTRIBUTE_PRESENT)
-
-//
-// Module Variables
-//
-EFI_LOCK mGcdMemorySpaceLock = EFI_INITIALIZE_LOCK_VARIABLE (TPL_NOTIFY);
-EFI_LOCK mGcdIoSpaceLock = EFI_INITIALIZE_LOCK_VARIABLE (TPL_NOTIFY);
-LIST_ENTRY mGcdMemorySpaceMap = INITIALIZE_LIST_HEAD_VARIABLE (mGcdMemorySpaceMap);
-LIST_ENTRY mGcdIoSpaceMap = INITIALIZE_LIST_HEAD_VARIABLE (mGcdIoSpaceMap);
-
-EFI_GCD_MAP_ENTRY mGcdMemorySpaceMapEntryTemplate = {
- EFI_GCD_MAP_SIGNATURE,
- {
- NULL,
- NULL
- },
- 0,
- 0,
- 0,
- 0,
- EfiGcdMemoryTypeNonExistent,
- (EFI_GCD_IO_TYPE)0,
- NULL,
- NULL
-};
-
-EFI_GCD_MAP_ENTRY mGcdIoSpaceMapEntryTemplate = {
- EFI_GCD_MAP_SIGNATURE,
- {
- NULL,
- NULL
- },
- 0,
- 0,
- 0,
- 0,
- (EFI_GCD_MEMORY_TYPE)0,
- EfiGcdIoTypeNonExistent,
- NULL,
- NULL
-};
-
-GCD_ATTRIBUTE_CONVERSION_ENTRY mAttributeConversionTable[] = {
- { EFI_RESOURCE_ATTRIBUTE_UNCACHEABLE, EFI_MEMORY_UC, TRUE },
- { EFI_RESOURCE_ATTRIBUTE_UNCACHED_EXPORTED, EFI_MEMORY_UCE, TRUE },
- { EFI_RESOURCE_ATTRIBUTE_WRITE_COMBINEABLE, EFI_MEMORY_WC, TRUE },
- { EFI_RESOURCE_ATTRIBUTE_WRITE_THROUGH_CACHEABLE, EFI_MEMORY_WT, TRUE },
- { EFI_RESOURCE_ATTRIBUTE_WRITE_BACK_CACHEABLE, EFI_MEMORY_WB, TRUE },
- { EFI_RESOURCE_ATTRIBUTE_READ_PROTECTABLE, EFI_MEMORY_RP, TRUE },
- { EFI_RESOURCE_ATTRIBUTE_WRITE_PROTECTABLE, EFI_MEMORY_WP, TRUE },
- { EFI_RESOURCE_ATTRIBUTE_EXECUTION_PROTECTABLE, EFI_MEMORY_XP, TRUE },
- { EFI_RESOURCE_ATTRIBUTE_READ_ONLY_PROTECTABLE, EFI_MEMORY_RO, TRUE },
- { EFI_RESOURCE_ATTRIBUTE_PRESENT, EFI_MEMORY_PRESENT, FALSE },
- { EFI_RESOURCE_ATTRIBUTE_INITIALIZED, EFI_MEMORY_INITIALIZED, FALSE },
- { EFI_RESOURCE_ATTRIBUTE_TESTED, EFI_MEMORY_TESTED, FALSE },
- { EFI_RESOURCE_ATTRIBUTE_PERSISTABLE, EFI_MEMORY_NV, TRUE },
- { EFI_RESOURCE_ATTRIBUTE_MORE_RELIABLE, EFI_MEMORY_MORE_RELIABLE, TRUE },
- { EFI_RESOURCE_ATTRIBUTE_SPECIAL_PURPOSE, EFI_MEMORY_SP, TRUE },
- { 0, 0, FALSE }
-};
-
-///
-/// Lookup table used to print GCD Memory Space Map
-///
-GLOBAL_REMOVE_IF_UNREFERENCED CONST CHAR8 *mGcdMemoryTypeNames[] = {
- "NonExist ", // EfiGcdMemoryTypeNonExistent
- "Reserved ", // EfiGcdMemoryTypeReserved
- "SystemMem", // EfiGcdMemoryTypeSystemMemory
- "MMIO ", // EfiGcdMemoryTypeMemoryMappedIo
- "PersisMem", // EfiGcdMemoryTypePersistent
- "MoreRelia", // EfiGcdMemoryTypeMoreReliable
- "Unaccepte", // EfiGcdMemoryTypeUnaccepted
- "Unknown " // EfiGcdMemoryTypeMaximum
-};
-
-///
-/// Lookup table used to print GCD I/O Space Map
-///
-GLOBAL_REMOVE_IF_UNREFERENCED CONST CHAR8 *mGcdIoTypeNames[] = {
- "NonExist", // EfiGcdIoTypeNonExistent
- "Reserved", // EfiGcdIoTypeReserved
- "I/O ", // EfiGcdIoTypeIo
- "Unknown " // EfiGcdIoTypeMaximum
-};
-
-///
-/// Lookup table used to print GCD Allocation Types
-///
-GLOBAL_REMOVE_IF_UNREFERENCED CONST CHAR8 *mGcdAllocationTypeNames[] = {
- "AnySearchBottomUp ", // EfiGcdAllocateAnySearchBottomUp
- "MaxAddressSearchBottomUp ", // EfiGcdAllocateMaxAddressSearchBottomUp
- "AtAddress ", // EfiGcdAllocateAddress
- "AnySearchTopDown ", // EfiGcdAllocateAnySearchTopDown
- "MaxAddressSearchTopDown ", // EfiGcdAllocateMaxAddressSearchTopDown
- "Unknown " // EfiGcdMaxAllocateType
-};
-
-/**
- Dump the entire contents if the GCD Memory Space Map using DEBUG() macros when
- PcdDebugPrintErrorLevel has the DEBUG_GCD bit set.
-
- @param InitialMap TRUE if the initial GCD Memory Map is being dumped. Otherwise, FALSE.
-
-**/
-VOID
-EFIAPI
-CoreDumpGcdMemorySpaceMap (
- BOOLEAN InitialMap
- )
-{
- DEBUG_CODE_BEGIN ();
- EFI_STATUS Status;
- UINTN NumberOfDescriptors;
- EFI_GCD_MEMORY_SPACE_DESCRIPTOR *MemorySpaceMap;
- UINTN Index;
-
- Status = CoreGetMemorySpaceMap (&NumberOfDescriptors, &MemorySpaceMap);
- ASSERT (Status == EFI_SUCCESS && MemorySpaceMap != NULL);
-
- if (InitialMap) {
- DEBUG ((DEBUG_GCD, "GCD:Initial GCD Memory Space Map\n"));
- }
-
- DEBUG ((DEBUG_GCD, "GCDMemType Range Capabilities Attributes \n"));
- DEBUG ((DEBUG_GCD, "========== ================================= ================ ================\n"));
- for (Index = 0; Index < NumberOfDescriptors; Index++) {
- DEBUG ((
- DEBUG_GCD,
- "%a %016lx-%016lx %016lx %016lx%c\n",
- mGcdMemoryTypeNames[MIN (MemorySpaceMap[Index].GcdMemoryType, EfiGcdMemoryTypeMaximum)],
- MemorySpaceMap[Index].BaseAddress,
- MemorySpaceMap[Index].BaseAddress + MemorySpaceMap[Index].Length - 1,
- MemorySpaceMap[Index].Capabilities,
- MemorySpaceMap[Index].Attributes,
- MemorySpaceMap[Index].ImageHandle == NULL ? ' ' : '*'
- ));
- }
-
- DEBUG ((DEBUG_GCD, "\n"));
- FreePool (MemorySpaceMap);
- DEBUG_CODE_END ();
-}
-
-/**
- Dump the entire contents if the GCD I/O Space Map using DEBUG() macros when
- PcdDebugPrintErrorLevel has the DEBUG_GCD bit set.
-
- @param InitialMap TRUE if the initial GCD I/O Map is being dumped. Otherwise, FALSE.
-
-**/
-VOID
-EFIAPI
-CoreDumpGcdIoSpaceMap (
- BOOLEAN InitialMap
- )
-{
- DEBUG_CODE_BEGIN ();
- EFI_STATUS Status;
- UINTN NumberOfDescriptors;
- EFI_GCD_IO_SPACE_DESCRIPTOR *IoSpaceMap;
- UINTN Index;
-
- Status = CoreGetIoSpaceMap (&NumberOfDescriptors, &IoSpaceMap);
- ASSERT (Status == EFI_SUCCESS && IoSpaceMap != NULL);
-
- if (InitialMap) {
- DEBUG ((DEBUG_GCD, "GCD:Initial GCD I/O Space Map\n"));
- }
-
- DEBUG ((DEBUG_GCD, "GCDIoType Range \n"));
- DEBUG ((DEBUG_GCD, "========== =================================\n"));
- for (Index = 0; Index < NumberOfDescriptors; Index++) {
- DEBUG ((
- DEBUG_GCD,
- "%a %016lx-%016lx%c\n",
- mGcdIoTypeNames[MIN (IoSpaceMap[Index].GcdIoType, EfiGcdIoTypeMaximum)],
- IoSpaceMap[Index].BaseAddress,
- IoSpaceMap[Index].BaseAddress + IoSpaceMap[Index].Length - 1,
- IoSpaceMap[Index].ImageHandle == NULL ? ' ' : '*'
- ));
- }
-
- DEBUG ((DEBUG_GCD, "\n"));
- FreePool (IoSpaceMap);
- DEBUG_CODE_END ();
-}
-
-/**
- Validate resource descriptor HOB's attributes.
-
- If Attributes includes some memory resource's settings, it should include
- the corresponding capabilites also.
-
- @param Attributes Resource descriptor HOB attributes.
-
-**/
-VOID
-CoreValidateResourceDescriptorHobAttributes (
- IN UINT64 Attributes
- )
-{
- ASSERT (
- ((Attributes & EFI_RESOURCE_ATTRIBUTE_READ_PROTECTED) == 0) ||
- ((Attributes & EFI_RESOURCE_ATTRIBUTE_READ_PROTECTABLE) != 0)
- );
- ASSERT (
- ((Attributes & EFI_RESOURCE_ATTRIBUTE_WRITE_PROTECTED) == 0) ||
- ((Attributes & EFI_RESOURCE_ATTRIBUTE_WRITE_PROTECTABLE) != 0)
- );
- ASSERT (
- ((Attributes & EFI_RESOURCE_ATTRIBUTE_EXECUTION_PROTECTED) == 0) ||
- ((Attributes & EFI_RESOURCE_ATTRIBUTE_EXECUTION_PROTECTABLE) != 0)
- );
- ASSERT (
- ((Attributes & EFI_RESOURCE_ATTRIBUTE_READ_ONLY_PROTECTED) == 0) ||
- ((Attributes & EFI_RESOURCE_ATTRIBUTE_READ_ONLY_PROTECTABLE) != 0)
- );
- ASSERT (
- ((Attributes & EFI_RESOURCE_ATTRIBUTE_PERSISTENT) == 0) ||
- ((Attributes & EFI_RESOURCE_ATTRIBUTE_PERSISTABLE) != 0)
- );
-}
-
-/**
- Acquire memory lock on mGcdMemorySpaceLock.
-
-**/
-VOID
-CoreAcquireGcdMemoryLock (
- VOID
- )
-{
- CoreAcquireLock (&mGcdMemorySpaceLock);
-}
-
-/**
- Release memory lock on mGcdMemorySpaceLock.
-
-**/
-VOID
-CoreReleaseGcdMemoryLock (
- VOID
- )
-{
- CoreReleaseLock (&mGcdMemorySpaceLock);
-}
-
-/**
- Acquire memory lock on mGcdIoSpaceLock.
-
-**/
-VOID
-CoreAcquireGcdIoLock (
- VOID
- )
-{
- CoreAcquireLock (&mGcdIoSpaceLock);
-}
-
-/**
- Release memory lock on mGcdIoSpaceLock.
-
-**/
-VOID
-CoreReleaseGcdIoLock (
- VOID
- )
-{
- CoreReleaseLock (&mGcdIoSpaceLock);
-}
-
-//
-// GCD Initialization Worker Functions
-//
-
-/**
- Aligns a value to the specified boundary.
-
- @param Value 64 bit value to align
- @param Alignment Log base 2 of the boundary to align Value to
- @param RoundUp TRUE if Value is to be rounded up to the nearest
- aligned boundary. FALSE is Value is to be
- rounded down to the nearest aligned boundary.
-
- @return A 64 bit value is the aligned to the value nearest Value with an alignment by Alignment.
-
-**/
-UINT64
-AlignValue (
- IN UINT64 Value,
- IN UINTN Alignment,
- IN BOOLEAN RoundUp
- )
-{
- UINT64 AlignmentMask;
-
- AlignmentMask = LShiftU64 (1, Alignment) - 1;
- if (RoundUp) {
- Value += AlignmentMask;
- }
-
- return Value & (~AlignmentMask);
-}
-
-/**
- Aligns address to the page boundary.
-
- @param Value 64 bit address to align
-
- @return A 64 bit value is the aligned to the value nearest Value with an alignment by Alignment.
-
-**/
-UINT64
-PageAlignAddress (
- IN UINT64 Value
- )
-{
- return AlignValue (Value, EFI_PAGE_SHIFT, TRUE);
-}
-
-/**
- Aligns length to the page boundary.
-
- @param Value 64 bit length to align
-
- @return A 64 bit value is the aligned to the value nearest Value with an alignment by Alignment.
-
-**/
-UINT64
-PageAlignLength (
- IN UINT64 Value
- )
-{
- return AlignValue (Value, EFI_PAGE_SHIFT, FALSE);
-}
-
-//
-// GCD Memory Space Worker Functions
-//
-
-/**
- Allocate pool for two entries.
-
- @param TopEntry An entry of GCD map
- @param BottomEntry An entry of GCD map
-
- @retval EFI_OUT_OF_RESOURCES No enough buffer to be allocated.
- @retval EFI_SUCCESS Both entries successfully allocated.
-
-**/
-EFI_STATUS
-CoreAllocateGcdMapEntry (
- IN OUT EFI_GCD_MAP_ENTRY **TopEntry,
- IN OUT EFI_GCD_MAP_ENTRY **BottomEntry
- )
-{
- //
- // Set to mOnGuarding to TRUE before memory allocation. This will make sure
- // that the entry memory is not "guarded" by HeapGuard. Otherwise it might
- // cause problem when it's freed (if HeapGuard is enabled).
- //
- mOnGuarding = TRUE;
- *TopEntry = AllocateZeroPool (sizeof (EFI_GCD_MAP_ENTRY));
- mOnGuarding = FALSE;
- if (*TopEntry == NULL) {
- return EFI_OUT_OF_RESOURCES;
- }
-
- mOnGuarding = TRUE;
- *BottomEntry = AllocateZeroPool (sizeof (EFI_GCD_MAP_ENTRY));
- mOnGuarding = FALSE;
- if (*BottomEntry == NULL) {
- CoreFreePool (*TopEntry);
- return EFI_OUT_OF_RESOURCES;
- }
-
- return EFI_SUCCESS;
-}
-
-/**
- Internal function. Inserts a new descriptor into a sorted list
-
- @param Link The linked list to insert the range BaseAddress
- and Length into
- @param Entry A pointer to the entry that is inserted
- @param BaseAddress The base address of the new range
- @param Length The length of the new range in bytes
- @param TopEntry Top pad entry to insert if needed.
- @param BottomEntry Bottom pad entry to insert if needed.
-
- @retval EFI_SUCCESS The new range was inserted into the linked list
-
-**/
-EFI_STATUS
-CoreInsertGcdMapEntry (
- IN LIST_ENTRY *Link,
- IN EFI_GCD_MAP_ENTRY *Entry,
- IN EFI_PHYSICAL_ADDRESS BaseAddress,
- IN UINT64 Length,
- IN EFI_GCD_MAP_ENTRY *TopEntry,
- IN EFI_GCD_MAP_ENTRY *BottomEntry
- )
-{
- ASSERT (Length != 0);
-
- if (BaseAddress > Entry->BaseAddress) {
- ASSERT (BottomEntry->Signature == 0);
-
- CopyMem (BottomEntry, Entry, sizeof (EFI_GCD_MAP_ENTRY));
- Entry->BaseAddress = BaseAddress;
- BottomEntry->EndAddress = BaseAddress - 1;
- InsertTailList (Link, &BottomEntry->Link);
- }
-
- if ((BaseAddress + Length - 1) < Entry->EndAddress) {
- ASSERT (TopEntry->Signature == 0);
-
- CopyMem (TopEntry, Entry, sizeof (EFI_GCD_MAP_ENTRY));
- TopEntry->BaseAddress = BaseAddress + Length;
- Entry->EndAddress = BaseAddress + Length - 1;
- InsertHeadList (Link, &TopEntry->Link);
- }
-
- return EFI_SUCCESS;
-}
-
-/**
- Merge the Gcd region specified by Link and its adjacent entry.
-
- @param Link Specify the entry to be merged (with its
- adjacent entry).
- @param Forward Direction (forward or backward).
- @param Map Boundary.
-
- @retval EFI_SUCCESS Successfully returned.
- @retval EFI_UNSUPPORTED These adjacent regions could not merge.
-
-**/
-EFI_STATUS
-CoreMergeGcdMapEntry (
- IN LIST_ENTRY *Link,
- IN BOOLEAN Forward,
- IN LIST_ENTRY *Map
- )
-{
- LIST_ENTRY *AdjacentLink;
- EFI_GCD_MAP_ENTRY *Entry;
- EFI_GCD_MAP_ENTRY *AdjacentEntry;
-
- //
- // Get adjacent entry
- //
- if (Forward) {
- AdjacentLink = Link->ForwardLink;
- } else {
- AdjacentLink = Link->BackLink;
- }
-
- //
- // If AdjacentLink is the head of the list, then no merge can be performed
- //
- if (AdjacentLink == Map) {
- return EFI_SUCCESS;
- }
-
- Entry = CR (Link, EFI_GCD_MAP_ENTRY, Link, EFI_GCD_MAP_SIGNATURE);
- AdjacentEntry = CR (AdjacentLink, EFI_GCD_MAP_ENTRY, Link, EFI_GCD_MAP_SIGNATURE);
-
- if (Entry->Capabilities != AdjacentEntry->Capabilities) {
- return EFI_UNSUPPORTED;
- }
-
- if (Entry->Attributes != AdjacentEntry->Attributes) {
- return EFI_UNSUPPORTED;
- }
-
- if (Entry->GcdMemoryType != AdjacentEntry->GcdMemoryType) {
- return EFI_UNSUPPORTED;
- }
-
- if (Entry->GcdIoType != AdjacentEntry->GcdIoType) {
- return EFI_UNSUPPORTED;
- }
-
- if (Entry->ImageHandle != AdjacentEntry->ImageHandle) {
- return EFI_UNSUPPORTED;
- }
-
- if (Entry->DeviceHandle != AdjacentEntry->DeviceHandle) {
- return EFI_UNSUPPORTED;
- }
-
- if (Forward) {
- Entry->EndAddress = AdjacentEntry->EndAddress;
- } else {
- Entry->BaseAddress = AdjacentEntry->BaseAddress;
- }
-
- RemoveEntryList (AdjacentLink);
- CoreFreePool (AdjacentEntry);
-
- return EFI_SUCCESS;
-}
-
-/**
- Merge adjacent entries on total chain.
-
- @param TopEntry Top entry of GCD map.
- @param BottomEntry Bottom entry of GCD map.
- @param StartLink Start link of the list for this loop.
- @param EndLink End link of the list for this loop.
- @param Map Boundary.
-
- @retval EFI_SUCCESS GCD map successfully cleaned up.
-
-**/
-EFI_STATUS
-CoreCleanupGcdMapEntry (
- IN EFI_GCD_MAP_ENTRY *TopEntry,
- IN EFI_GCD_MAP_ENTRY *BottomEntry,
- IN LIST_ENTRY *StartLink,
- IN LIST_ENTRY *EndLink,
- IN LIST_ENTRY *Map
- )
-{
- LIST_ENTRY *Link;
-
- if (TopEntry->Signature == 0) {
- CoreFreePool (TopEntry);
- }
-
- if (BottomEntry->Signature == 0) {
- CoreFreePool (BottomEntry);
- }
-
- Link = StartLink;
- while (Link != EndLink->ForwardLink) {
- CoreMergeGcdMapEntry (Link, FALSE, Map);
- Link = Link->ForwardLink;
- }
-
- CoreMergeGcdMapEntry (EndLink, TRUE, Map);
-
- return EFI_SUCCESS;
-}
-
-/**
- Search a segment of memory space in GCD map. The result is a range of GCD entry list.
-
- @param BaseAddress The start address of the segment.
- @param Length The length of the segment.
- @param StartLink The first GCD entry involves this segment of
- memory space.
- @param EndLink The first GCD entry involves this segment of
- memory space.
- @param Map Points to the start entry to search.
-
- @retval EFI_SUCCESS Successfully found the entry.
- @retval EFI_NOT_FOUND Not found.
-
-**/
-EFI_STATUS
-CoreSearchGcdMapEntry (
- IN EFI_PHYSICAL_ADDRESS BaseAddress,
- IN UINT64 Length,
- OUT LIST_ENTRY **StartLink,
- OUT LIST_ENTRY **EndLink,
- IN LIST_ENTRY *Map
- )
-{
- LIST_ENTRY *Link;
- EFI_GCD_MAP_ENTRY *Entry;
-
- ASSERT (Length != 0);
-
- *StartLink = NULL;
- *EndLink = NULL;
-
- Link = Map->ForwardLink;
- while (Link != Map) {
- Entry = CR (Link, EFI_GCD_MAP_ENTRY, Link, EFI_GCD_MAP_SIGNATURE);
- if ((BaseAddress >= Entry->BaseAddress) && (BaseAddress <= Entry->EndAddress)) {
- *StartLink = Link;
- }
-
- if (*StartLink != NULL) {
- if (((BaseAddress + Length - 1) >= Entry->BaseAddress) &&
- ((BaseAddress + Length - 1) <= Entry->EndAddress))
- {
- *EndLink = Link;
- return EFI_SUCCESS;
- }
- }
-
- Link = Link->ForwardLink;
- }
-
- return EFI_NOT_FOUND;
-}
-
-/**
- Count the amount of GCD map entries.
-
- @param Map Points to the start entry to do the count loop.
-
- @return The count.
-
-**/
-UINTN
-CoreCountGcdMapEntry (
- IN LIST_ENTRY *Map
- )
-{
- UINTN Count;
- LIST_ENTRY *Link;
-
- Count = 0;
- Link = Map->ForwardLink;
- while (Link != Map) {
- Count++;
- Link = Link->ForwardLink;
- }
-
- return Count;
-}
-
-/**
- Return the memory attribute specified by Attributes
-
- @param Attributes A num with some attribute bits on.
-
- @return The enum value of memory attribute.
-
-**/
-UINT64
-ConverToCpuArchAttributes (
- UINT64 Attributes
- )
-{
- UINT64 CpuArchAttributes;
-
- CpuArchAttributes = Attributes & EFI_MEMORY_ATTRIBUTE_MASK;
-
- if ((Attributes & EFI_MEMORY_UC) == EFI_MEMORY_UC) {
- CpuArchAttributes |= EFI_MEMORY_UC;
- } else if ((Attributes & EFI_MEMORY_WC) == EFI_MEMORY_WC) {
- CpuArchAttributes |= EFI_MEMORY_WC;
- } else if ((Attributes & EFI_MEMORY_WT) == EFI_MEMORY_WT) {
- CpuArchAttributes |= EFI_MEMORY_WT;
- } else if ((Attributes & EFI_MEMORY_WB) == EFI_MEMORY_WB) {
- CpuArchAttributes |= EFI_MEMORY_WB;
- } else if ((Attributes & EFI_MEMORY_UCE) == EFI_MEMORY_UCE) {
- CpuArchAttributes |= EFI_MEMORY_UCE;
- } else if ((Attributes & EFI_MEMORY_WP) == EFI_MEMORY_WP) {
- CpuArchAttributes |= EFI_MEMORY_WP;
- }
-
- return CpuArchAttributes;
-}
-
-/**
- Do operation on a segment of memory space specified (add, free, remove, change attribute ...).
-
- @param Operation The type of the operation
- @param GcdMemoryType Additional information for the operation
- @param GcdIoType Additional information for the operation
- @param BaseAddress Start address of the segment
- @param Length length of the segment
- @param Capabilities The alterable attributes of a newly added entry
- @param Attributes The attributes needs to be set
-
- @retval EFI_INVALID_PARAMETER Length is 0 or address (length) not aligned when
- setting attribute.
- @retval EFI_SUCCESS Action successfully done.
- @retval EFI_UNSUPPORTED Could not find the proper descriptor on this
- segment or set an upsupported attribute.
- @retval EFI_ACCESS_DENIED Operate on an space non-exist or is used for an
- image.
- @retval EFI_NOT_FOUND Free a non-using space or remove a non-exist
- space, and so on.
- @retval EFI_OUT_OF_RESOURCES No buffer could be allocated.
- @retval EFI_NOT_AVAILABLE_YET The attributes cannot be set because CPU architectural protocol
- is not available yet.
-**/
-EFI_STATUS
-CoreConvertSpace (
- IN UINTN Operation,
- IN EFI_GCD_MEMORY_TYPE GcdMemoryType,
- IN EFI_GCD_IO_TYPE GcdIoType,
- IN EFI_PHYSICAL_ADDRESS BaseAddress,
- IN UINT64 Length,
- IN UINT64 Capabilities,
- IN UINT64 Attributes
- )
-{
- EFI_STATUS Status;
- LIST_ENTRY *Map;
- LIST_ENTRY *Link;
- EFI_GCD_MAP_ENTRY *Entry;
- EFI_GCD_MAP_ENTRY *TopEntry;
- EFI_GCD_MAP_ENTRY *BottomEntry;
- LIST_ENTRY *StartLink;
- LIST_ENTRY *EndLink;
- UINT64 CpuArchAttributes;
-
- if (Length == 0) {
- DEBUG ((DEBUG_GCD, " Status = %r\n", EFI_INVALID_PARAMETER));
- return EFI_INVALID_PARAMETER;
- }
-
- Map = NULL;
- if ((Operation & GCD_MEMORY_SPACE_OPERATION) != 0) {
- CoreAcquireGcdMemoryLock ();
- Map = &mGcdMemorySpaceMap;
- } else if ((Operation & GCD_IO_SPACE_OPERATION) != 0) {
- CoreAcquireGcdIoLock ();
- Map = &mGcdIoSpaceMap;
- } else {
- ASSERT (FALSE);
- }
-
- //
- // Search for the list of descriptors that cover the range BaseAddress to BaseAddress+Length
- //
- Status = CoreSearchGcdMapEntry (BaseAddress, Length, &StartLink, &EndLink, Map);
- if (EFI_ERROR (Status)) {
- Status = EFI_UNSUPPORTED;
-
- goto Done;
- }
-
- ASSERT (StartLink != NULL && EndLink != NULL);
-
- //
- // Verify that the list of descriptors are unallocated non-existent memory.
- //
- Link = StartLink;
- while (Link != EndLink->ForwardLink) {
- Entry = CR (Link, EFI_GCD_MAP_ENTRY, Link, EFI_GCD_MAP_SIGNATURE);
- switch (Operation) {
- //
- // Add operations
- //
- case GCD_ADD_MEMORY_OPERATION:
- if ((Entry->GcdMemoryType != EfiGcdMemoryTypeNonExistent) ||
- (Entry->ImageHandle != NULL))
- {
- Status = EFI_ACCESS_DENIED;
- goto Done;
- }
-
- break;
- case GCD_ADD_IO_OPERATION:
- if ((Entry->GcdIoType != EfiGcdIoTypeNonExistent) ||
- (Entry->ImageHandle != NULL))
- {
- Status = EFI_ACCESS_DENIED;
- goto Done;
- }
-
- break;
- //
- // Free operations
- //
- case GCD_FREE_MEMORY_OPERATION:
- case GCD_FREE_IO_OPERATION:
- if (Entry->ImageHandle == NULL) {
- Status = EFI_NOT_FOUND;
- goto Done;
- }
-
- break;
- //
- // Remove operations
- //
- case GCD_REMOVE_MEMORY_OPERATION:
- if (Entry->GcdMemoryType == EfiGcdMemoryTypeNonExistent) {
- Status = EFI_NOT_FOUND;
- goto Done;
- }
-
- if (Entry->ImageHandle != NULL) {
- Status = EFI_ACCESS_DENIED;
- goto Done;
- }
-
- break;
- case GCD_REMOVE_IO_OPERATION:
- if (Entry->GcdIoType == EfiGcdIoTypeNonExistent) {
- Status = EFI_NOT_FOUND;
- goto Done;
- }
-
- if (Entry->ImageHandle != NULL) {
- Status = EFI_ACCESS_DENIED;
- goto Done;
- }
-
- break;
- //
- // Set attributes operation
- //
- case GCD_SET_ATTRIBUTES_MEMORY_OPERATION:
- if ((Attributes & EFI_MEMORY_RUNTIME) != 0) {
- if (((BaseAddress & EFI_PAGE_MASK) != 0) || ((Length & EFI_PAGE_MASK) != 0)) {
- Status = EFI_INVALID_PARAMETER;
- goto Done;
- }
- }
-
- if ((Entry->Capabilities & Attributes) != Attributes) {
- Status = EFI_UNSUPPORTED;
- goto Done;
- }
-
- break;
- //
- // Set capabilities operation
- //
- case GCD_SET_CAPABILITIES_MEMORY_OPERATION:
- if (((BaseAddress & EFI_PAGE_MASK) != 0) || ((Length & EFI_PAGE_MASK) != 0)) {
- Status = EFI_INVALID_PARAMETER;
-
- goto Done;
- }
-
- //
- // Current attributes must still be supported with new capabilities
- //
- if ((Capabilities & Entry->Attributes) != Entry->Attributes) {
- Status = EFI_UNSUPPORTED;
- goto Done;
- }
-
- break;
- }
-
- Link = Link->ForwardLink;
- }
-
- //
- // Allocate work space to perform this operation
- //
- Status = CoreAllocateGcdMapEntry (&TopEntry, &BottomEntry);
- if (EFI_ERROR (Status)) {
- Status = EFI_OUT_OF_RESOURCES;
- goto Done;
- }
-
- ASSERT (TopEntry != NULL && BottomEntry != NULL);
-
- //
- // Initialize CpuArchAttributes to suppress incorrect compiler/analyzer warnings.
- //
- CpuArchAttributes = 0;
- if (Operation == GCD_SET_ATTRIBUTES_MEMORY_OPERATION) {
- //
- // Call CPU Arch Protocol to attempt to set attributes on the range
- //
- CpuArchAttributes = ConverToCpuArchAttributes (Attributes);
- //
- // CPU arch attributes include page attributes and cache attributes.
- // Only page attributes supports to be cleared, but not cache attributes.
- // Caller is expected to use GetMemorySpaceDescriptor() to get the current
- // attributes, AND/OR attributes, and then calls SetMemorySpaceAttributes()
- // to set the new attributes.
- // So 0 CPU arch attributes should not happen as memory should always have
- // a cache attribute (no matter UC or WB, etc).
- //
- // Here, 0 CPU arch attributes will be filtered to be compatible with the
- // case that caller just calls SetMemorySpaceAttributes() with none CPU
- // arch attributes (for example, RUNTIME) as the purpose of the case is not
- // to clear CPU arch attributes.
- //
- if (CpuArchAttributes != 0) {
- if (gCpu == NULL) {
- Status = EFI_NOT_AVAILABLE_YET;
- } else {
- Status = gCpu->SetMemoryAttributes (
- gCpu,
- BaseAddress,
- Length,
- CpuArchAttributes
- );
- }
-
- if (EFI_ERROR (Status)) {
- CoreFreePool (TopEntry);
- CoreFreePool (BottomEntry);
- goto Done;
- }
- }
- }
-
- //
- // Convert/Insert the list of descriptors from StartLink to EndLink
- //
- Link = StartLink;
- while (Link != EndLink->ForwardLink) {
- Entry = CR (Link, EFI_GCD_MAP_ENTRY, Link, EFI_GCD_MAP_SIGNATURE);
- CoreInsertGcdMapEntry (Link, Entry, BaseAddress, Length, TopEntry, BottomEntry);
- switch (Operation) {
- //
- // Add operations
- //
- case GCD_ADD_MEMORY_OPERATION:
- Entry->GcdMemoryType = GcdMemoryType;
- if (GcdMemoryType == EfiGcdMemoryTypeMemoryMappedIo) {
- Entry->Capabilities = Capabilities | EFI_MEMORY_RUNTIME | EFI_MEMORY_PORT_IO;
- } else {
- Entry->Capabilities = Capabilities | EFI_MEMORY_RUNTIME;
- }
-
- break;
- case GCD_ADD_IO_OPERATION:
- Entry->GcdIoType = GcdIoType;
- break;
- //
- // Free operations
- //
- case GCD_FREE_MEMORY_OPERATION:
- case GCD_FREE_IO_OPERATION:
- Entry->ImageHandle = NULL;
- Entry->DeviceHandle = NULL;
- break;
- //
- // Remove operations
- //
- case GCD_REMOVE_MEMORY_OPERATION:
- Entry->GcdMemoryType = EfiGcdMemoryTypeNonExistent;
- Entry->Capabilities = 0;
- break;
- case GCD_REMOVE_IO_OPERATION:
- Entry->GcdIoType = EfiGcdIoTypeNonExistent;
- break;
- //
- // Set attributes operation
- //
- case GCD_SET_ATTRIBUTES_MEMORY_OPERATION:
- if (CpuArchAttributes == 0) {
- //
- // Keep original CPU arch attributes when caller just calls
- // SetMemorySpaceAttributes() with none CPU arch attributes (for example, RUNTIME).
- //
- Attributes |= (Entry->Attributes & (EFI_CACHE_ATTRIBUTE_MASK | EFI_MEMORY_ATTRIBUTE_MASK));
- }
-
- Entry->Attributes = Attributes;
- break;
- //
- // Set capabilities operation
- //
- case GCD_SET_CAPABILITIES_MEMORY_OPERATION:
- Entry->Capabilities = Capabilities;
- break;
- }
-
- Link = Link->ForwardLink;
- }
-
- //
- // Cleanup
- //
- Status = CoreCleanupGcdMapEntry (TopEntry, BottomEntry, StartLink, EndLink, Map);
-
-Done:
- DEBUG ((DEBUG_GCD, " Status = %r\n", Status));
-
- if ((Operation & GCD_MEMORY_SPACE_OPERATION) != 0) {
- CoreReleaseGcdMemoryLock ();
- CoreDumpGcdMemorySpaceMap (FALSE);
- }
-
- if ((Operation & GCD_IO_SPACE_OPERATION) != 0) {
- CoreReleaseGcdIoLock ();
- CoreDumpGcdIoSpaceMap (FALSE);
- }
-
- return Status;
-}
-
-/**
- Check whether an entry could be used to allocate space.
-
- @param Operation Allocate memory or IO
- @param Entry The entry to be tested
- @param GcdMemoryType The desired memory type
- @param GcdIoType The desired IO type
-
- @retval EFI_NOT_FOUND The memory type does not match or there's an
- image handle on the entry.
- @retval EFI_UNSUPPORTED The operation unsupported.
- @retval EFI_SUCCESS It's ok for this entry to be used to allocate
- space.
-
-**/
-EFI_STATUS
-CoreAllocateSpaceCheckEntry (
- IN UINTN Operation,
- IN EFI_GCD_MAP_ENTRY *Entry,
- IN EFI_GCD_MEMORY_TYPE GcdMemoryType,
- IN EFI_GCD_IO_TYPE GcdIoType
- )
-{
- if (Entry->ImageHandle != NULL) {
- return EFI_NOT_FOUND;
- }
-
- switch (Operation) {
- case GCD_ALLOCATE_MEMORY_OPERATION:
- if (Entry->GcdMemoryType != GcdMemoryType) {
- return EFI_NOT_FOUND;
- }
-
- break;
- case GCD_ALLOCATE_IO_OPERATION:
- if (Entry->GcdIoType != GcdIoType) {
- return EFI_NOT_FOUND;
- }
-
- break;
- default:
- return EFI_UNSUPPORTED;
- }
-
- return EFI_SUCCESS;
-}
-
-/**
- Allocate space on specified address and length.
-
- @param Operation The type of operation (memory or IO)
- @param GcdAllocateType The type of allocate operation
- @param GcdMemoryType The desired memory type
- @param GcdIoType The desired IO type
- @param Alignment Align with 2^Alignment
- @param Length Length to allocate
- @param BaseAddress Base address to allocate
- @param ImageHandle The image handle consume the allocated space.
- @param DeviceHandle The device handle consume the allocated space.
-
- @retval EFI_INVALID_PARAMETER Invalid parameter.
- @retval EFI_NOT_FOUND No descriptor for the desired space exists.
- @retval EFI_SUCCESS Space successfully allocated.
-
-**/
-EFI_STATUS
-CoreAllocateSpace (
- IN UINTN Operation,
- IN EFI_GCD_ALLOCATE_TYPE GcdAllocateType,
- IN EFI_GCD_MEMORY_TYPE GcdMemoryType,
- IN EFI_GCD_IO_TYPE GcdIoType,
- IN UINTN Alignment,
- IN UINT64 Length,
- IN OUT EFI_PHYSICAL_ADDRESS *BaseAddress,
- IN EFI_HANDLE ImageHandle,
- IN EFI_HANDLE DeviceHandle OPTIONAL
- )
-{
- EFI_STATUS Status;
- EFI_PHYSICAL_ADDRESS AlignmentMask;
- EFI_PHYSICAL_ADDRESS MaxAddress;
- LIST_ENTRY *Map;
- LIST_ENTRY *Link;
- LIST_ENTRY *SubLink;
- EFI_GCD_MAP_ENTRY *Entry;
- EFI_GCD_MAP_ENTRY *TopEntry;
- EFI_GCD_MAP_ENTRY *BottomEntry;
- LIST_ENTRY *StartLink;
- LIST_ENTRY *EndLink;
- BOOLEAN Found;
-
- //
- // Make sure parameters are valid
- //
- if ((UINT32)GcdAllocateType >= EfiGcdMaxAllocateType) {
- DEBUG ((DEBUG_GCD, " Status = %r\n", EFI_INVALID_PARAMETER));
- return EFI_INVALID_PARAMETER;
- }
-
- if ((UINT32)GcdMemoryType >= EfiGcdMemoryTypeMaximum) {
- DEBUG ((DEBUG_GCD, " Status = %r\n", EFI_INVALID_PARAMETER));
- return EFI_INVALID_PARAMETER;
- }
-
- if ((UINT32)GcdIoType >= EfiGcdIoTypeMaximum) {
- DEBUG ((DEBUG_GCD, " Status = %r\n", EFI_INVALID_PARAMETER));
- return EFI_INVALID_PARAMETER;
- }
-
- if (BaseAddress == NULL) {
- DEBUG ((DEBUG_GCD, " Status = %r\n", EFI_INVALID_PARAMETER));
- return EFI_INVALID_PARAMETER;
- }
-
- if (ImageHandle == NULL) {
- DEBUG ((DEBUG_GCD, " Status = %r\n", EFI_INVALID_PARAMETER));
- return EFI_INVALID_PARAMETER;
- }
-
- if (Alignment >= 64) {
- DEBUG ((DEBUG_GCD, " Status = %r\n", EFI_NOT_FOUND));
- return EFI_NOT_FOUND;
- }
-
- if (Length == 0) {
- DEBUG ((DEBUG_GCD, " Status = %r\n", EFI_INVALID_PARAMETER));
- return EFI_INVALID_PARAMETER;
- }
-
- Map = NULL;
- if ((Operation & GCD_MEMORY_SPACE_OPERATION) != 0) {
- CoreAcquireGcdMemoryLock ();
- Map = &mGcdMemorySpaceMap;
- } else if ((Operation & GCD_IO_SPACE_OPERATION) != 0) {
- CoreAcquireGcdIoLock ();
- Map = &mGcdIoSpaceMap;
- } else {
- ASSERT (FALSE);
- }
-
- Found = FALSE;
- StartLink = NULL;
- EndLink = NULL;
- //
- // Compute alignment bit mask
- //
- AlignmentMask = LShiftU64 (1, Alignment) - 1;
-
- if (GcdAllocateType == EfiGcdAllocateAddress) {
- //
- // Verify that the BaseAddress passed in is aligned correctly
- //
- if ((*BaseAddress & AlignmentMask) != 0) {
- Status = EFI_NOT_FOUND;
- goto Done;
- }
-
- //
- // Search for the list of descriptors that cover the range BaseAddress to BaseAddress+Length
- //
- Status = CoreSearchGcdMapEntry (*BaseAddress, Length, &StartLink, &EndLink, Map);
- if (EFI_ERROR (Status)) {
- Status = EFI_NOT_FOUND;
- goto Done;
- }
-
- ASSERT (StartLink != NULL && EndLink != NULL);
-
- //
- // Verify that the list of descriptors are unallocated memory matching GcdMemoryType.
- //
- Link = StartLink;
- while (Link != EndLink->ForwardLink) {
- Entry = CR (Link, EFI_GCD_MAP_ENTRY, Link, EFI_GCD_MAP_SIGNATURE);
- Link = Link->ForwardLink;
- Status = CoreAllocateSpaceCheckEntry (Operation, Entry, GcdMemoryType, GcdIoType);
- if (EFI_ERROR (Status)) {
- goto Done;
- }
- }
-
- Found = TRUE;
- } else {
- Entry = CR (Map->BackLink, EFI_GCD_MAP_ENTRY, Link, EFI_GCD_MAP_SIGNATURE);
-
- //
- // Compute the maximum address to use in the search algorithm
- //
- if ((GcdAllocateType == EfiGcdAllocateMaxAddressSearchBottomUp) ||
- (GcdAllocateType == EfiGcdAllocateMaxAddressSearchTopDown))
- {
- MaxAddress = *BaseAddress;
- } else {
- MaxAddress = Entry->EndAddress;
- }
-
- //
- // Verify that the list of descriptors are unallocated memory matching GcdMemoryType.
- //
- if ((GcdAllocateType == EfiGcdAllocateMaxAddressSearchTopDown) ||
- (GcdAllocateType == EfiGcdAllocateAnySearchTopDown))
- {
- Link = Map->BackLink;
- } else {
- Link = Map->ForwardLink;
- }
-
- while (Link != Map) {
- Entry = CR (Link, EFI_GCD_MAP_ENTRY, Link, EFI_GCD_MAP_SIGNATURE);
-
- if ((GcdAllocateType == EfiGcdAllocateMaxAddressSearchTopDown) ||
- (GcdAllocateType == EfiGcdAllocateAnySearchTopDown))
- {
- Link = Link->BackLink;
- } else {
- Link = Link->ForwardLink;
- }
-
- Status = CoreAllocateSpaceCheckEntry (Operation, Entry, GcdMemoryType, GcdIoType);
- if (EFI_ERROR (Status)) {
- continue;
- }
-
- if ((GcdAllocateType == EfiGcdAllocateMaxAddressSearchTopDown) ||
- (GcdAllocateType == EfiGcdAllocateAnySearchTopDown))
- {
- if ((Entry->BaseAddress + Length) > MaxAddress) {
- continue;
- }
-
- if (Length > (Entry->EndAddress + 1)) {
- Status = EFI_NOT_FOUND;
- goto Done;
- }
-
- if (Entry->EndAddress > MaxAddress) {
- *BaseAddress = MaxAddress;
- } else {
- *BaseAddress = Entry->EndAddress;
- }
-
- *BaseAddress = (*BaseAddress + 1 - Length) & (~AlignmentMask);
- } else {
- *BaseAddress = (Entry->BaseAddress + AlignmentMask) & (~AlignmentMask);
- if ((*BaseAddress + Length - 1) > MaxAddress) {
- Status = EFI_NOT_FOUND;
- goto Done;
- }
- }
-
- //
- // Search for the list of descriptors that cover the range BaseAddress to BaseAddress+Length
- //
- Status = CoreSearchGcdMapEntry (*BaseAddress, Length, &StartLink, &EndLink, Map);
- if (EFI_ERROR (Status)) {
- Status = EFI_NOT_FOUND;
- goto Done;
- }
-
- ASSERT (StartLink != NULL && EndLink != NULL);
-
- Link = StartLink;
- //
- // Verify that the list of descriptors are unallocated memory matching GcdMemoryType.
- //
- Found = TRUE;
- SubLink = StartLink;
- while (SubLink != EndLink->ForwardLink) {
- Entry = CR (SubLink, EFI_GCD_MAP_ENTRY, Link, EFI_GCD_MAP_SIGNATURE);
- Status = CoreAllocateSpaceCheckEntry (Operation, Entry, GcdMemoryType, GcdIoType);
- if (EFI_ERROR (Status)) {
- Link = SubLink;
- Found = FALSE;
- break;
- }
-
- SubLink = SubLink->ForwardLink;
- }
-
- if (Found) {
- break;
- }
- }
- }
-
- if (!Found) {
- Status = EFI_NOT_FOUND;
- goto Done;
- }
-
- //
- // Allocate work space to perform this operation
- //
- Status = CoreAllocateGcdMapEntry (&TopEntry, &BottomEntry);
- if (EFI_ERROR (Status)) {
- Status = EFI_OUT_OF_RESOURCES;
- goto Done;
- }
-
- ASSERT (TopEntry != NULL && BottomEntry != NULL);
-
- //
- // Convert/Insert the list of descriptors from StartLink to EndLink
- //
- Link = StartLink;
- while (Link != EndLink->ForwardLink) {
- Entry = CR (Link, EFI_GCD_MAP_ENTRY, Link, EFI_GCD_MAP_SIGNATURE);
- CoreInsertGcdMapEntry (Link, Entry, *BaseAddress, Length, TopEntry, BottomEntry);
- Entry->ImageHandle = ImageHandle;
- Entry->DeviceHandle = DeviceHandle;
- Link = Link->ForwardLink;
- }
-
- //
- // Cleanup
- //
- Status = CoreCleanupGcdMapEntry (TopEntry, BottomEntry, StartLink, EndLink, Map);
-
-Done:
- DEBUG ((DEBUG_GCD, " Status = %r", Status));
- if (!EFI_ERROR (Status)) {
- DEBUG ((DEBUG_GCD, " (BaseAddress = %016lx)", *BaseAddress));
- }
-
- DEBUG ((DEBUG_GCD, "\n"));
-
- if ((Operation & GCD_MEMORY_SPACE_OPERATION) != 0) {
- CoreReleaseGcdMemoryLock ();
- CoreDumpGcdMemorySpaceMap (FALSE);
- }
-
- if ((Operation & GCD_IO_SPACE_OPERATION) != 0) {
- CoreReleaseGcdIoLock ();
- CoreDumpGcdIoSpaceMap (FALSE);
- }
-
- return Status;
-}
-
-/**
- Add a segment of memory to GCD map.
-
- @param GcdMemoryType Memory type of the segment.
- @param BaseAddress Base address of the segment.
- @param Length Length of the segment.
- @param Capabilities alterable attributes of the segment.
-
- @retval EFI_INVALID_PARAMETER Invalid parameters.
- @retval EFI_SUCCESS Successfully add a segment of memory space.
-
-**/
-EFI_STATUS
-CoreInternalAddMemorySpace (
- IN EFI_GCD_MEMORY_TYPE GcdMemoryType,
- IN EFI_PHYSICAL_ADDRESS BaseAddress,
- IN UINT64 Length,
- IN UINT64 Capabilities
- )
-{
- DEBUG ((DEBUG_GCD, "GCD:AddMemorySpace(Base=%016lx,Length=%016lx)\n", BaseAddress, Length));
- DEBUG ((DEBUG_GCD, " GcdMemoryType = %a\n", mGcdMemoryTypeNames[MIN (GcdMemoryType, EfiGcdMemoryTypeMaximum)]));
- DEBUG ((DEBUG_GCD, " Capabilities = %016lx\n", Capabilities));
-
- //
- // Make sure parameters are valid
- //
- if ((GcdMemoryType <= EfiGcdMemoryTypeNonExistent) || (GcdMemoryType >= EfiGcdMemoryTypeMaximum)) {
- return EFI_INVALID_PARAMETER;
- }
-
- return CoreConvertSpace (GCD_ADD_MEMORY_OPERATION, GcdMemoryType, (EFI_GCD_IO_TYPE)0, BaseAddress, Length, Capabilities, 0);
-}
-
-//
-// GCD Core Services
-//
-
-/**
- Allocates nonexistent memory, reserved memory, system memory, or memorymapped
- I/O resources from the global coherency domain of the processor.
-
- @param GcdAllocateType The type of allocate operation
- @param GcdMemoryType The desired memory type
- @param Alignment Align with 2^Alignment
- @param Length Length to allocate
- @param BaseAddress Base address to allocate
- @param ImageHandle The image handle consume the allocated space.
- @param DeviceHandle The device handle consume the allocated space.
-
- @retval EFI_INVALID_PARAMETER Invalid parameter.
- @retval EFI_NOT_FOUND No descriptor contains the desired space.
- @retval EFI_SUCCESS Memory space successfully allocated.
-
-**/
-EFI_STATUS
-EFIAPI
-CoreAllocateMemorySpace (
- IN EFI_GCD_ALLOCATE_TYPE GcdAllocateType,
- IN EFI_GCD_MEMORY_TYPE GcdMemoryType,
- IN UINTN Alignment,
- IN UINT64 Length,
- IN OUT EFI_PHYSICAL_ADDRESS *BaseAddress,
- IN EFI_HANDLE ImageHandle,
- IN EFI_HANDLE DeviceHandle OPTIONAL
- )
-{
- if (BaseAddress != NULL) {
- DEBUG ((DEBUG_GCD, "GCD:AllocateMemorySpace(Base=%016lx,Length=%016lx)\n", *BaseAddress, Length));
- } else {
- DEBUG ((DEBUG_GCD, "GCD:AllocateMemorySpace(Base=<NULL>,Length=%016lx)\n", Length));
- }
-
- DEBUG ((DEBUG_GCD, " GcdAllocateType = %a\n", mGcdAllocationTypeNames[MIN (GcdAllocateType, EfiGcdMaxAllocateType)]));
- DEBUG ((DEBUG_GCD, " GcdMemoryType = %a\n", mGcdMemoryTypeNames[MIN (GcdMemoryType, EfiGcdMemoryTypeMaximum)]));
- DEBUG ((DEBUG_GCD, " Alignment = %016lx\n", LShiftU64 (1, Alignment)));
- DEBUG ((DEBUG_GCD, " ImageHandle = %p\n", ImageHandle));
- DEBUG ((DEBUG_GCD, " DeviceHandle = %p\n", DeviceHandle));
-
- return CoreAllocateSpace (
- GCD_ALLOCATE_MEMORY_OPERATION,
- GcdAllocateType,
- GcdMemoryType,
- (EFI_GCD_IO_TYPE)0,
- Alignment,
- Length,
- BaseAddress,
- ImageHandle,
- DeviceHandle
- );
-}
-
-/**
- Adds reserved memory, system memory, or memory-mapped I/O resources to the
- global coherency domain of the processor.
-
- @param GcdMemoryType Memory type of the memory space.
- @param BaseAddress Base address of the memory space.
- @param Length Length of the memory space.
- @param Capabilities alterable attributes of the memory space.
-
- @retval EFI_SUCCESS Merged this memory space into GCD map.
-
-**/
-EFI_STATUS
-EFIAPI
-CoreAddMemorySpace (
- IN EFI_GCD_MEMORY_TYPE GcdMemoryType,
- IN EFI_PHYSICAL_ADDRESS BaseAddress,
- IN UINT64 Length,
- IN UINT64 Capabilities
- )
-{
- EFI_STATUS Status;
- EFI_PHYSICAL_ADDRESS PageBaseAddress;
- UINT64 PageLength;
-
- Status = CoreInternalAddMemorySpace (GcdMemoryType, BaseAddress, Length, Capabilities);
-
- if (!EFI_ERROR (Status) && ((GcdMemoryType == EfiGcdMemoryTypeSystemMemory) || (GcdMemoryType == EfiGcdMemoryTypeMoreReliable))) {
- PageBaseAddress = PageAlignAddress (BaseAddress);
- PageLength = PageAlignLength (BaseAddress + Length - PageBaseAddress);
-
- Status = CoreAllocateMemorySpace (
- EfiGcdAllocateAddress,
- GcdMemoryType,
- EFI_PAGE_SHIFT,
- PageLength,
- &PageBaseAddress,
- gDxeCoreImageHandle,
- NULL
- );
-
- if (!EFI_ERROR (Status)) {
- CoreAddMemoryDescriptor (
- EfiConventionalMemory,
- PageBaseAddress,
- RShiftU64 (PageLength, EFI_PAGE_SHIFT),
- Capabilities
- );
- } else {
- for ( ; PageLength != 0; PageLength -= EFI_PAGE_SIZE, PageBaseAddress += EFI_PAGE_SIZE) {
- Status = CoreAllocateMemorySpace (
- EfiGcdAllocateAddress,
- GcdMemoryType,
- EFI_PAGE_SHIFT,
- EFI_PAGE_SIZE,
- &PageBaseAddress,
- gDxeCoreImageHandle,
- NULL
- );
-
- if (!EFI_ERROR (Status)) {
- CoreAddMemoryDescriptor (
- EfiConventionalMemory,
- PageBaseAddress,
- 1,
- Capabilities
- );
- }
- }
- }
- }
-
- return Status;
-}
-
-/**
- Frees nonexistent memory, reserved memory, system memory, or memory-mapped
- I/O resources from the global coherency domain of the processor.
-
- @param BaseAddress Base address of the memory space.
- @param Length Length of the memory space.
-
- @retval EFI_SUCCESS Space successfully freed.
-
-**/
-EFI_STATUS
-EFIAPI
-CoreFreeMemorySpace (
- IN EFI_PHYSICAL_ADDRESS BaseAddress,
- IN UINT64 Length
- )
-{
- DEBUG ((DEBUG_GCD, "GCD:FreeMemorySpace(Base=%016lx,Length=%016lx)\n", BaseAddress, Length));
-
- return CoreConvertSpace (GCD_FREE_MEMORY_OPERATION, (EFI_GCD_MEMORY_TYPE)0, (EFI_GCD_IO_TYPE)0, BaseAddress, Length, 0, 0);
-}
-
-/**
- Removes reserved memory, system memory, or memory-mapped I/O resources from
- the global coherency domain of the processor.
-
- @param BaseAddress Base address of the memory space.
- @param Length Length of the memory space.
-
- @retval EFI_SUCCESS Successfully remove a segment of memory space.
-
-**/
-EFI_STATUS
-EFIAPI
-CoreRemoveMemorySpace (
- IN EFI_PHYSICAL_ADDRESS BaseAddress,
- IN UINT64 Length
- )
-{
- DEBUG ((DEBUG_GCD, "GCD:RemoveMemorySpace(Base=%016lx,Length=%016lx)\n", BaseAddress, Length));
-
- return CoreConvertSpace (GCD_REMOVE_MEMORY_OPERATION, (EFI_GCD_MEMORY_TYPE)0, (EFI_GCD_IO_TYPE)0, BaseAddress, Length, 0, 0);
-}
-
-/**
- Build a memory descriptor according to an entry.
-
- @param Descriptor The descriptor to be built
- @param Entry According to this entry
-
-**/
-VOID
-BuildMemoryDescriptor (
- IN OUT EFI_GCD_MEMORY_SPACE_DESCRIPTOR *Descriptor,
- IN EFI_GCD_MAP_ENTRY *Entry
- )
-{
- Descriptor->BaseAddress = Entry->BaseAddress;
- Descriptor->Length = Entry->EndAddress - Entry->BaseAddress + 1;
- Descriptor->Capabilities = Entry->Capabilities;
- Descriptor->Attributes = Entry->Attributes;
- Descriptor->GcdMemoryType = Entry->GcdMemoryType;
- Descriptor->ImageHandle = Entry->ImageHandle;
- Descriptor->DeviceHandle = Entry->DeviceHandle;
-}
-
-/**
- Retrieves the descriptor for a memory region containing a specified address.
-
- @param BaseAddress Specified start address
- @param Descriptor Specified length
-
- @retval EFI_INVALID_PARAMETER Invalid parameter
- @retval EFI_SUCCESS Successfully get memory space descriptor.
-
-**/
-EFI_STATUS
-EFIAPI
-CoreGetMemorySpaceDescriptor (
- IN EFI_PHYSICAL_ADDRESS BaseAddress,
- OUT EFI_GCD_MEMORY_SPACE_DESCRIPTOR *Descriptor
- )
-{
- EFI_STATUS Status;
- LIST_ENTRY *StartLink;
- LIST_ENTRY *EndLink;
- EFI_GCD_MAP_ENTRY *Entry;
-
- //
- // Make sure parameters are valid
- //
- if (Descriptor == NULL) {
- return EFI_INVALID_PARAMETER;
- }
-
- CoreAcquireGcdMemoryLock ();
-
- //
- // Search for the list of descriptors that contain BaseAddress
- //
- Status = CoreSearchGcdMapEntry (BaseAddress, 1, &StartLink, &EndLink, &mGcdMemorySpaceMap);
- if (EFI_ERROR (Status)) {
- Status = EFI_NOT_FOUND;
- } else {
- ASSERT (StartLink != NULL && EndLink != NULL);
- //
- // Copy the contents of the found descriptor into Descriptor
- //
- Entry = CR (StartLink, EFI_GCD_MAP_ENTRY, Link, EFI_GCD_MAP_SIGNATURE);
- BuildMemoryDescriptor (Descriptor, Entry);
- }
-
- CoreReleaseGcdMemoryLock ();
-
- return Status;
-}
-
-/**
- Modifies the attributes for a memory region in the global coherency domain of the
- processor.
-
- @param BaseAddress Specified start address
- @param Length Specified length
- @param Attributes Specified attributes
-
- @retval EFI_SUCCESS The attributes were set for the memory region.
- @retval EFI_INVALID_PARAMETER Length is zero.
- @retval EFI_UNSUPPORTED The processor does not support one or more bytes of the memory
- resource range specified by BaseAddress and Length.
- @retval EFI_UNSUPPORTED The bit mask of attributes is not support for the memory resource
- range specified by BaseAddress and Length.
- @retval EFI_ACCESS_DEFINED The attributes for the memory resource range specified by
- BaseAddress and Length cannot be modified.
- @retval EFI_OUT_OF_RESOURCES There are not enough system resources to modify the attributes of
- the memory resource range.
- @retval EFI_NOT_AVAILABLE_YET The attributes cannot be set because CPU architectural protocol is
- not available yet.
-
-**/
-EFI_STATUS
-EFIAPI
-CoreSetMemorySpaceAttributes (
- IN EFI_PHYSICAL_ADDRESS BaseAddress,
- IN UINT64 Length,
- IN UINT64 Attributes
- )
-{
- DEBUG ((DEBUG_GCD, "GCD:SetMemorySpaceAttributes(Base=%016lx,Length=%016lx)\n", BaseAddress, Length));
- DEBUG ((DEBUG_GCD, " Attributes = %016lx\n", Attributes));
-
- return CoreConvertSpace (GCD_SET_ATTRIBUTES_MEMORY_OPERATION, (EFI_GCD_MEMORY_TYPE)0, (EFI_GCD_IO_TYPE)0, BaseAddress, Length, 0, Attributes);
-}
-
-/**
- Modifies the capabilities for a memory region in the global coherency domain of the
- processor.
-
- @param BaseAddress The physical address that is the start address of a memory region.
- @param Length The size in bytes of the memory region.
- @param Capabilities The bit mask of capabilities that the memory region supports.
-
- @retval EFI_SUCCESS The capabilities were set for the memory region.
- @retval EFI_INVALID_PARAMETER Length is zero.
- @retval EFI_UNSUPPORTED The capabilities specified by Capabilities do not include the
- memory region attributes currently in use.
- @retval EFI_ACCESS_DENIED The capabilities for the memory resource range specified by
- BaseAddress and Length cannot be modified.
- @retval EFI_OUT_OF_RESOURCES There are not enough system resources to modify the capabilities
- of the memory resource range.
-**/
-EFI_STATUS
-EFIAPI
-CoreSetMemorySpaceCapabilities (
- IN EFI_PHYSICAL_ADDRESS BaseAddress,
- IN UINT64 Length,
- IN UINT64 Capabilities
- )
-{
- EFI_STATUS Status;
-
- DEBUG ((DEBUG_GCD, "GCD:CoreSetMemorySpaceCapabilities(Base=%016lx,Length=%016lx)\n", BaseAddress, Length));
- DEBUG ((DEBUG_GCD, " Capabilities = %016lx\n", Capabilities));
-
- Status = CoreConvertSpace (GCD_SET_CAPABILITIES_MEMORY_OPERATION, (EFI_GCD_MEMORY_TYPE)0, (EFI_GCD_IO_TYPE)0, BaseAddress, Length, Capabilities, 0);
- if (!EFI_ERROR (Status)) {
- CoreUpdateMemoryAttributes (BaseAddress, RShiftU64 (Length, EFI_PAGE_SHIFT), Capabilities & (~EFI_MEMORY_RUNTIME));
- }
-
- return Status;
-}
-
-/**
- Returns a map of the memory resources in the global coherency domain of the
- processor.
-
- @param NumberOfDescriptors Number of descriptors.
- @param MemorySpaceMap Descriptor array
-
- @retval EFI_INVALID_PARAMETER Invalid parameter
- @retval EFI_OUT_OF_RESOURCES No enough buffer to allocate
- @retval EFI_SUCCESS Successfully get memory space map.
-
-**/
-EFI_STATUS
-EFIAPI
-CoreGetMemorySpaceMap (
- OUT UINTN *NumberOfDescriptors,
- OUT EFI_GCD_MEMORY_SPACE_DESCRIPTOR **MemorySpaceMap
- )
-{
- LIST_ENTRY *Link;
- EFI_GCD_MAP_ENTRY *Entry;
- EFI_GCD_MEMORY_SPACE_DESCRIPTOR *Descriptor;
- UINTN DescriptorCount;
-
- //
- // Make sure parameters are valid
- //
- if (NumberOfDescriptors == NULL) {
- return EFI_INVALID_PARAMETER;
- }
-
- if (MemorySpaceMap == NULL) {
- return EFI_INVALID_PARAMETER;
- }
-
- *NumberOfDescriptors = 0;
- *MemorySpaceMap = NULL;
-
- //
- // Take the lock, for entering the loop with the lock held.
- //
- CoreAcquireGcdMemoryLock ();
- while (TRUE) {
- //
- // Count descriptors. It might be done more than once because the
- // AllocatePool() called below has to be running outside the GCD lock.
- //
- DescriptorCount = CoreCountGcdMapEntry (&mGcdMemorySpaceMap);
- if ((DescriptorCount == *NumberOfDescriptors) && (*MemorySpaceMap != NULL)) {
- //
- // Fill in the MemorySpaceMap if no memory space map change.
- //
- Descriptor = *MemorySpaceMap;
- Link = mGcdMemorySpaceMap.ForwardLink;
- while (Link != &mGcdMemorySpaceMap) {
- Entry = CR (Link, EFI_GCD_MAP_ENTRY, Link, EFI_GCD_MAP_SIGNATURE);
- BuildMemoryDescriptor (Descriptor, Entry);
- Descriptor++;
- Link = Link->ForwardLink;
- }
-
- //
- // We're done; exit the loop with the lock held.
- //
- break;
- }
-
- //
- // Release the lock before memory allocation, because it might cause
- // GCD lock conflict in one of calling path in AllocatPool().
- //
- CoreReleaseGcdMemoryLock ();
-
- //
- // Allocate memory to store the MemorySpaceMap. Note it might be already
- // allocated if there's map descriptor change during memory allocation at
- // last time.
- //
- if (*MemorySpaceMap != NULL) {
- FreePool (*MemorySpaceMap);
- }
-
- *MemorySpaceMap = AllocatePool (
- DescriptorCount *
- sizeof (EFI_GCD_MEMORY_SPACE_DESCRIPTOR)
- );
- if (*MemorySpaceMap == NULL) {
- *NumberOfDescriptors = 0;
- return EFI_OUT_OF_RESOURCES;
- }
-
- //
- // Save the descriptor count got before for another round of check to make
- // sure we won't miss any, since we have code running outside the GCD lock.
- //
- *NumberOfDescriptors = DescriptorCount;
- //
- // Re-acquire the lock, for the next iteration.
- //
- CoreAcquireGcdMemoryLock ();
- }
-
- //
- // We exited the loop with the lock held, release it.
- //
- CoreReleaseGcdMemoryLock ();
-
- return EFI_SUCCESS;
-}
-
-/**
- Adds reserved I/O or I/O resources to the global coherency domain of the processor.
-
- @param GcdIoType IO type of the segment.
- @param BaseAddress Base address of the segment.
- @param Length Length of the segment.
-
- @retval EFI_SUCCESS Merged this segment into GCD map.
- @retval EFI_INVALID_PARAMETER Parameter not valid
-
-**/
-EFI_STATUS
-EFIAPI
-CoreAddIoSpace (
- IN EFI_GCD_IO_TYPE GcdIoType,
- IN EFI_PHYSICAL_ADDRESS BaseAddress,
- IN UINT64 Length
- )
-{
- DEBUG ((DEBUG_GCD, "GCD:AddIoSpace(Base=%016lx,Length=%016lx)\n", BaseAddress, Length));
- DEBUG ((DEBUG_GCD, " GcdIoType = %a\n", mGcdIoTypeNames[MIN (GcdIoType, EfiGcdIoTypeMaximum)]));
-
- //
- // Make sure parameters are valid
- //
- if ((GcdIoType <= EfiGcdIoTypeNonExistent) || (GcdIoType >= EfiGcdIoTypeMaximum)) {
- return EFI_INVALID_PARAMETER;
- }
-
- return CoreConvertSpace (GCD_ADD_IO_OPERATION, (EFI_GCD_MEMORY_TYPE)0, GcdIoType, BaseAddress, Length, 0, 0);
-}
-
-/**
- Allocates nonexistent I/O, reserved I/O, or I/O resources from the global coherency
- domain of the processor.
-
- @param GcdAllocateType The type of allocate operation
- @param GcdIoType The desired IO type
- @param Alignment Align with 2^Alignment
- @param Length Length to allocate
- @param BaseAddress Base address to allocate
- @param ImageHandle The image handle consume the allocated space.
- @param DeviceHandle The device handle consume the allocated space.
-
- @retval EFI_INVALID_PARAMETER Invalid parameter.
- @retval EFI_NOT_FOUND No descriptor contains the desired space.
- @retval EFI_SUCCESS IO space successfully allocated.
-
-**/
-EFI_STATUS
-EFIAPI
-CoreAllocateIoSpace (
- IN EFI_GCD_ALLOCATE_TYPE GcdAllocateType,
- IN EFI_GCD_IO_TYPE GcdIoType,
- IN UINTN Alignment,
- IN UINT64 Length,
- IN OUT EFI_PHYSICAL_ADDRESS *BaseAddress,
- IN EFI_HANDLE ImageHandle,
- IN EFI_HANDLE DeviceHandle OPTIONAL
- )
-{
- if (BaseAddress != NULL) {
- DEBUG ((DEBUG_GCD, "GCD:AllocateIoSpace(Base=%016lx,Length=%016lx)\n", *BaseAddress, Length));
- } else {
- DEBUG ((DEBUG_GCD, "GCD:AllocateIoSpace(Base=<NULL>,Length=%016lx)\n", Length));
- }
-
- DEBUG ((DEBUG_GCD, " GcdAllocateType = %a\n", mGcdAllocationTypeNames[MIN (GcdAllocateType, EfiGcdMaxAllocateType)]));
- DEBUG ((DEBUG_GCD, " GcdIoType = %a\n", mGcdIoTypeNames[MIN (GcdIoType, EfiGcdIoTypeMaximum)]));
- DEBUG ((DEBUG_GCD, " Alignment = %016lx\n", LShiftU64 (1, Alignment)));
- DEBUG ((DEBUG_GCD, " ImageHandle = %p\n", ImageHandle));
- DEBUG ((DEBUG_GCD, " DeviceHandle = %p\n", DeviceHandle));
-
- return CoreAllocateSpace (
- GCD_ALLOCATE_IO_OPERATION,
- GcdAllocateType,
- (EFI_GCD_MEMORY_TYPE)0,
- GcdIoType,
- Alignment,
- Length,
- BaseAddress,
- ImageHandle,
- DeviceHandle
- );
-}
-
-/**
- Frees nonexistent I/O, reserved I/O, or I/O resources from the global coherency
- domain of the processor.
-
- @param BaseAddress Base address of the segment.
- @param Length Length of the segment.
-
- @retval EFI_SUCCESS Space successfully freed.
-
-**/
-EFI_STATUS
-EFIAPI
-CoreFreeIoSpace (
- IN EFI_PHYSICAL_ADDRESS BaseAddress,
- IN UINT64 Length
- )
-{
- DEBUG ((DEBUG_GCD, "GCD:FreeIoSpace(Base=%016lx,Length=%016lx)\n", BaseAddress, Length));
-
- return CoreConvertSpace (GCD_FREE_IO_OPERATION, (EFI_GCD_MEMORY_TYPE)0, (EFI_GCD_IO_TYPE)0, BaseAddress, Length, 0, 0);
-}
-
-/**
- Removes reserved I/O or I/O resources from the global coherency domain of the
- processor.
-
- @param BaseAddress Base address of the segment.
- @param Length Length of the segment.
-
- @retval EFI_SUCCESS Successfully removed a segment of IO space.
-
-**/
-EFI_STATUS
-EFIAPI
-CoreRemoveIoSpace (
- IN EFI_PHYSICAL_ADDRESS BaseAddress,
- IN UINT64 Length
- )
-{
- DEBUG ((DEBUG_GCD, "GCD:RemoveIoSpace(Base=%016lx,Length=%016lx)\n", BaseAddress, Length));
-
- return CoreConvertSpace (GCD_REMOVE_IO_OPERATION, (EFI_GCD_MEMORY_TYPE)0, (EFI_GCD_IO_TYPE)0, BaseAddress, Length, 0, 0);
-}
-
-/**
- Build a IO descriptor according to an entry.
-
- @param Descriptor The descriptor to be built
- @param Entry According to this entry
-
-**/
-VOID
-BuildIoDescriptor (
- IN EFI_GCD_IO_SPACE_DESCRIPTOR *Descriptor,
- IN EFI_GCD_MAP_ENTRY *Entry
- )
-{
- Descriptor->BaseAddress = Entry->BaseAddress;
- Descriptor->Length = Entry->EndAddress - Entry->BaseAddress + 1;
- Descriptor->GcdIoType = Entry->GcdIoType;
- Descriptor->ImageHandle = Entry->ImageHandle;
- Descriptor->DeviceHandle = Entry->DeviceHandle;
-}
-
-/**
- Retrieves the descriptor for an I/O region containing a specified address.
-
- @param BaseAddress Specified start address
- @param Descriptor Specified length
-
- @retval EFI_INVALID_PARAMETER Descriptor is NULL.
- @retval EFI_SUCCESS Successfully get the IO space descriptor.
-
-**/
-EFI_STATUS
-EFIAPI
-CoreGetIoSpaceDescriptor (
- IN EFI_PHYSICAL_ADDRESS BaseAddress,
- OUT EFI_GCD_IO_SPACE_DESCRIPTOR *Descriptor
- )
-{
- EFI_STATUS Status;
- LIST_ENTRY *StartLink;
- LIST_ENTRY *EndLink;
- EFI_GCD_MAP_ENTRY *Entry;
-
- //
- // Make sure parameters are valid
- //
- if (Descriptor == NULL) {
- return EFI_INVALID_PARAMETER;
- }
-
- CoreAcquireGcdIoLock ();
-
- //
- // Search for the list of descriptors that contain BaseAddress
- //
- Status = CoreSearchGcdMapEntry (BaseAddress, 1, &StartLink, &EndLink, &mGcdIoSpaceMap);
- if (EFI_ERROR (Status)) {
- Status = EFI_NOT_FOUND;
- } else {
- ASSERT (StartLink != NULL && EndLink != NULL);
- //
- // Copy the contents of the found descriptor into Descriptor
- //
- Entry = CR (StartLink, EFI_GCD_MAP_ENTRY, Link, EFI_GCD_MAP_SIGNATURE);
- BuildIoDescriptor (Descriptor, Entry);
- }
-
- CoreReleaseGcdIoLock ();
-
- return Status;
-}
-
-/**
- Returns a map of the I/O resources in the global coherency domain of the processor.
-
- @param NumberOfDescriptors Number of descriptors.
- @param IoSpaceMap Descriptor array
-
- @retval EFI_INVALID_PARAMETER Invalid parameter
- @retval EFI_OUT_OF_RESOURCES No enough buffer to allocate
- @retval EFI_SUCCESS Successfully get IO space map.
-
-**/
-EFI_STATUS
-EFIAPI
-CoreGetIoSpaceMap (
- OUT UINTN *NumberOfDescriptors,
- OUT EFI_GCD_IO_SPACE_DESCRIPTOR **IoSpaceMap
- )
-{
- EFI_STATUS Status;
- LIST_ENTRY *Link;
- EFI_GCD_MAP_ENTRY *Entry;
- EFI_GCD_IO_SPACE_DESCRIPTOR *Descriptor;
-
- //
- // Make sure parameters are valid
- //
- if (NumberOfDescriptors == NULL) {
- return EFI_INVALID_PARAMETER;
- }
-
- if (IoSpaceMap == NULL) {
- return EFI_INVALID_PARAMETER;
- }
-
- CoreAcquireGcdIoLock ();
-
- //
- // Count the number of descriptors
- //
- *NumberOfDescriptors = CoreCountGcdMapEntry (&mGcdIoSpaceMap);
-
- //
- // Allocate the IoSpaceMap
- //
- *IoSpaceMap = AllocatePool (*NumberOfDescriptors * sizeof (EFI_GCD_IO_SPACE_DESCRIPTOR));
- if (*IoSpaceMap == NULL) {
- Status = EFI_OUT_OF_RESOURCES;
- goto Done;
- }
-
- //
- // Fill in the IoSpaceMap
- //
- Descriptor = *IoSpaceMap;
- Link = mGcdIoSpaceMap.ForwardLink;
- while (Link != &mGcdIoSpaceMap) {
- Entry = CR (Link, EFI_GCD_MAP_ENTRY, Link, EFI_GCD_MAP_SIGNATURE);
- BuildIoDescriptor (Descriptor, Entry);
- Descriptor++;
- Link = Link->ForwardLink;
- }
-
- Status = EFI_SUCCESS;
-
-Done:
- CoreReleaseGcdIoLock ();
- return Status;
-}
-
-/**
- Converts a Resource Descriptor HOB attributes mask to an EFI Memory Descriptor
- capabilities mask
-
- @param GcdMemoryType Type of resource in the GCD memory map.
- @param Attributes The attribute mask in the Resource Descriptor
- HOB.
-
- @return The capabilities mask for an EFI Memory Descriptor.
-
-**/
-UINT64
-CoreConvertResourceDescriptorHobAttributesToCapabilities (
- EFI_GCD_MEMORY_TYPE GcdMemoryType,
- UINT64 Attributes
- )
-{
- UINT64 Capabilities;
- GCD_ATTRIBUTE_CONVERSION_ENTRY *Conversion;
-
- //
- // Convert the Resource HOB Attributes to an EFI Memory Capabilities mask
- //
- for (Capabilities = 0, Conversion = mAttributeConversionTable; Conversion->Attribute != 0; Conversion++) {
- if (Conversion->Memory || ((GcdMemoryType != EfiGcdMemoryTypeSystemMemory) && (GcdMemoryType != EfiGcdMemoryTypeMoreReliable))) {
- if (Attributes & Conversion->Attribute) {
- Capabilities |= Conversion->Capability;
- }
- }
- }
-
- return Capabilities;
-}
-
-/**
- Calculate total memory bin size neeeded.
-
- @return The total memory bin size neeeded.
-
-**/
-UINT64
-CalculateTotalMemoryBinSizeNeeded (
- VOID
- )
-{
- UINTN Index;
- UINT64 TotalSize;
-
- //
- // Loop through each memory type in the order specified by the gMemoryTypeInformation[] array
- //
- TotalSize = 0;
- for (Index = 0; gMemoryTypeInformation[Index].Type != EfiMaxMemoryType; Index++) {
- TotalSize += LShiftU64 (gMemoryTypeInformation[Index].NumberOfPages, EFI_PAGE_SHIFT);
- }
-
- return TotalSize;
-}
-
-/**
- Find the largest region in the specified region that is not covered by an existing memory allocation
-
- @param BaseAddress On input start of the region to check.
- On output start of the largest free region.
- @param Length On input size of region to check.
- On output size of the largest free region.
- @param MemoryHob Hob pointer for the first memory allocation pointer to check
-**/
-VOID
-FindLargestFreeRegion (
- IN OUT EFI_PHYSICAL_ADDRESS *BaseAddress,
- IN OUT UINT64 *Length,
- IN EFI_HOB_MEMORY_ALLOCATION *MemoryHob
- )
-{
- EFI_PHYSICAL_ADDRESS TopAddress;
- EFI_PHYSICAL_ADDRESS AllocatedTop;
- EFI_PHYSICAL_ADDRESS LowerBase;
- UINT64 LowerSize;
- EFI_PHYSICAL_ADDRESS UpperBase;
- UINT64 UpperSize;
-
- TopAddress = *BaseAddress + *Length;
- while (MemoryHob != NULL) {
- AllocatedTop = MemoryHob->AllocDescriptor.MemoryBaseAddress + MemoryHob->AllocDescriptor.MemoryLength;
-
- if ((MemoryHob->AllocDescriptor.MemoryBaseAddress >= *BaseAddress) &&
- (AllocatedTop <= TopAddress))
- {
- LowerBase = *BaseAddress;
- LowerSize = MemoryHob->AllocDescriptor.MemoryBaseAddress - *BaseAddress;
- UpperBase = AllocatedTop;
- UpperSize = TopAddress - AllocatedTop;
-
- if (LowerSize != 0) {
- FindLargestFreeRegion (&LowerBase, &LowerSize, (EFI_HOB_MEMORY_ALLOCATION *)GetNextHob (EFI_HOB_TYPE_MEMORY_ALLOCATION, GET_NEXT_HOB (MemoryHob)));
- }
-
- if (UpperSize != 0) {
- FindLargestFreeRegion (&UpperBase, &UpperSize, (EFI_HOB_MEMORY_ALLOCATION *)GetNextHob (EFI_HOB_TYPE_MEMORY_ALLOCATION, GET_NEXT_HOB (MemoryHob)));
- }
-
- if (UpperSize >= LowerSize) {
- *Length = UpperSize;
- *BaseAddress = UpperBase;
- } else {
- *Length = LowerSize;
- *BaseAddress = LowerBase;
- }
-
- return;
- }
-
- MemoryHob = GetNextHob (EFI_HOB_TYPE_MEMORY_ALLOCATION, GET_NEXT_HOB (MemoryHob));
- }
-}
-
-/**
- External function. Initializes memory services based on the memory
- descriptor HOBs. This function is responsible for priming the memory
- map, so memory allocations and resource allocations can be made.
- The first part of this function can not depend on any memory services
- until at least one memory descriptor is provided to the memory services.
-
- @param HobStart The start address of the HOB.
- @param MemoryBaseAddress Start address of memory region found to init DXE
- core.
- @param MemoryLength Length of memory region found to init DXE core.
-
- @retval EFI_SUCCESS Memory services successfully initialized.
-
-**/
-EFI_STATUS
-CoreInitializeMemoryServices (
- IN VOID **HobStart,
- OUT EFI_PHYSICAL_ADDRESS *MemoryBaseAddress,
- OUT UINT64 *MemoryLength
- )
-{
- EFI_PEI_HOB_POINTERS Hob;
- EFI_MEMORY_TYPE_INFORMATION *EfiMemoryTypeInformation;
- UINTN DataSize;
- BOOLEAN Found;
- EFI_HOB_HANDOFF_INFO_TABLE *PhitHob;
- EFI_HOB_RESOURCE_DESCRIPTOR *ResourceHob;
- EFI_HOB_RESOURCE_DESCRIPTOR *PhitResourceHob;
- EFI_HOB_RESOURCE_DESCRIPTOR *MemoryTypeInformationResourceHob;
- UINTN Count;
- EFI_PHYSICAL_ADDRESS BaseAddress;
- UINT64 Length;
- UINT64 Attributes;
- UINT64 Capabilities;
- EFI_PHYSICAL_ADDRESS TestedMemoryBaseAddress;
- UINT64 TestedMemoryLength;
- EFI_PHYSICAL_ADDRESS HighAddress;
- EFI_HOB_GUID_TYPE *GuidHob;
- UINT32 ReservedCodePageNumber;
- UINT64 MinimalMemorySizeNeeded;
-
- //
- // Point at the first HOB. This must be the PHIT HOB.
- //
- Hob.Raw = *HobStart;
- ASSERT (GET_HOB_TYPE (Hob) == EFI_HOB_TYPE_HANDOFF);
-
- //
- // Initialize the spin locks and maps in the memory services.
- // Also fill in the memory services into the EFI Boot Services Table
- //
- CoreInitializePool ();
-
- //
- // Initialize Local Variables
- //
- PhitResourceHob = NULL;
- ResourceHob = NULL;
- BaseAddress = 0;
- Length = 0;
- Attributes = 0;
-
- //
- // Cache the PHIT HOB for later use
- //
- PhitHob = Hob.HandoffInformationTable;
-
- if (PcdGet64 (PcdLoadModuleAtFixAddressEnable) != 0) {
- ReservedCodePageNumber = PcdGet32 (PcdLoadFixAddressRuntimeCodePageNumber);
- ReservedCodePageNumber += PcdGet32 (PcdLoadFixAddressBootTimeCodePageNumber);
-
- //
- // cache the Top address for loading modules at Fixed Address
- //
- gLoadModuleAtFixAddressConfigurationTable.DxeCodeTopAddress = PhitHob->EfiMemoryTop
- + EFI_PAGES_TO_SIZE (ReservedCodePageNumber);
- }
-
- //
- // See if a Memory Type Information HOB is available
- //
- MemoryTypeInformationResourceHob = NULL;
- GuidHob = GetFirstGuidHob (&gEfiMemoryTypeInformationGuid);
- if (GuidHob != NULL) {
- EfiMemoryTypeInformation = GET_GUID_HOB_DATA (GuidHob);
- DataSize = GET_GUID_HOB_DATA_SIZE (GuidHob);
- if ((EfiMemoryTypeInformation != NULL) && (DataSize > 0) && (DataSize <= (EfiMaxMemoryType + 1) * sizeof (EFI_MEMORY_TYPE_INFORMATION))) {
- CopyMem (&gMemoryTypeInformation, EfiMemoryTypeInformation, DataSize);
-
- //
- // Look for Resource Descriptor HOB with a ResourceType of System Memory
- // and an Owner GUID of gEfiMemoryTypeInformationGuid. If more than 1 is
- // found, then set MemoryTypeInformationResourceHob to NULL.
- //
- Count = 0;
- for (Hob.Raw = *HobStart; !END_OF_HOB_LIST (Hob); Hob.Raw = GET_NEXT_HOB (Hob)) {
- if (GET_HOB_TYPE (Hob) != EFI_HOB_TYPE_RESOURCE_DESCRIPTOR) {
- continue;
- }
-
- ResourceHob = Hob.ResourceDescriptor;
- if (!CompareGuid (&ResourceHob->Owner, &gEfiMemoryTypeInformationGuid)) {
- continue;
- }
-
- Count++;
- if (ResourceHob->ResourceType != EFI_RESOURCE_SYSTEM_MEMORY) {
- continue;
- }
-
- if ((ResourceHob->ResourceAttribute & MEMORY_ATTRIBUTE_MASK) != TESTED_MEMORY_ATTRIBUTES) {
- continue;
- }
-
- if (ResourceHob->ResourceLength >= CalculateTotalMemoryBinSizeNeeded ()) {
- MemoryTypeInformationResourceHob = ResourceHob;
- }
- }
-
- if (Count > 1) {
- MemoryTypeInformationResourceHob = NULL;
- }
- }
- }
-
- //
- // Include the total memory bin size needed to make sure memory bin could be allocated successfully.
- //
- MinimalMemorySizeNeeded = MINIMUM_INITIAL_MEMORY_SIZE + CalculateTotalMemoryBinSizeNeeded ();
-
- //
- // Find the Resource Descriptor HOB that contains PHIT range EfiFreeMemoryBottom..EfiFreeMemoryTop
- //
- Found = FALSE;
- for (Hob.Raw = *HobStart; !END_OF_HOB_LIST (Hob); Hob.Raw = GET_NEXT_HOB (Hob)) {
- //
- // Skip all HOBs except Resource Descriptor HOBs
- //
- if (GET_HOB_TYPE (Hob) != EFI_HOB_TYPE_RESOURCE_DESCRIPTOR) {
- continue;
- }
-
- //
- // Skip Resource Descriptor HOBs that do not describe tested system memory
- //
- ResourceHob = Hob.ResourceDescriptor;
- if (ResourceHob->ResourceType != EFI_RESOURCE_SYSTEM_MEMORY) {
- continue;
- }
-
- if ((ResourceHob->ResourceAttribute & MEMORY_ATTRIBUTE_MASK) != TESTED_MEMORY_ATTRIBUTES) {
- continue;
- }
-
- //
- // Skip Resource Descriptor HOBs that do not contain the PHIT range EfiFreeMemoryBottom..EfiFreeMemoryTop
- //
- if (PhitHob->EfiFreeMemoryBottom < ResourceHob->PhysicalStart) {
- continue;
- }
-
- if (PhitHob->EfiFreeMemoryTop > (ResourceHob->PhysicalStart + ResourceHob->ResourceLength)) {
- continue;
- }
-
- //
- // Cache the resource descriptor HOB for the memory region described by the PHIT HOB
- //
- PhitResourceHob = ResourceHob;
- Found = TRUE;
-
- //
- // If a Memory Type Information Resource HOB was found and is the same
- // Resource HOB that describes the PHIT HOB, then ignore the Memory Type
- // Information Resource HOB.
- //
- if (MemoryTypeInformationResourceHob == PhitResourceHob) {
- MemoryTypeInformationResourceHob = NULL;
- }
-
- //
- // Compute range between PHIT EfiMemoryTop and the end of the Resource Descriptor HOB
- //
- Attributes = PhitResourceHob->ResourceAttribute;
- BaseAddress = PageAlignAddress (PhitHob->EfiMemoryTop);
- Length = PageAlignLength (ResourceHob->PhysicalStart + ResourceHob->ResourceLength - BaseAddress);
- FindLargestFreeRegion (&BaseAddress, &Length, (EFI_HOB_MEMORY_ALLOCATION *)GetFirstHob (EFI_HOB_TYPE_MEMORY_ALLOCATION));
- if (Length < MinimalMemorySizeNeeded) {
- //
- // If that range is not large enough to intialize the DXE Core, then
- // Compute range between PHIT EfiFreeMemoryBottom and PHIT EfiFreeMemoryTop
- //
- BaseAddress = PageAlignAddress (PhitHob->EfiFreeMemoryBottom);
- Length = PageAlignLength (PhitHob->EfiFreeMemoryTop - BaseAddress);
- // This region is required to have no memory allocation inside it, skip check for entries in HOB List
- if (Length < MinimalMemorySizeNeeded) {
- //
- // If that range is not large enough to intialize the DXE Core, then
- // Compute range between the start of the Resource Descriptor HOB and the start of the HOB List
- //
- BaseAddress = PageAlignAddress (ResourceHob->PhysicalStart);
- Length = PageAlignLength ((UINT64)((UINTN)*HobStart - BaseAddress));
- FindLargestFreeRegion (&BaseAddress, &Length, (EFI_HOB_MEMORY_ALLOCATION *)GetFirstHob (EFI_HOB_TYPE_MEMORY_ALLOCATION));
- }
- }
-
- break;
- }
-
- //
- // Assert if a resource descriptor HOB for the memory region described by the PHIT was not found
- //
- ASSERT (Found);
-
- //
- // Take the range in the resource descriptor HOB for the memory region described
- // by the PHIT as higher priority if it is big enough. It can make the memory bin
- // allocated to be at the same memory region with PHIT that has more better compatibility
- // to avoid memory fragmentation for some code practices assume and allocate <4G ACPI memory.
- //
- if (Length < MinimalMemorySizeNeeded) {
- //
- // Search all the resource descriptor HOBs from the highest possible addresses down for a memory
- // region that is big enough to initialize the DXE core. Always skip the PHIT Resource HOB
- // and the Memory Type Information Resource HOB. The max address must be within the physically
- // addressable range for the processor.
- //
- HighAddress = MAX_ALLOC_ADDRESS;
- for (Hob.Raw = *HobStart; !END_OF_HOB_LIST (Hob); Hob.Raw = GET_NEXT_HOB (Hob)) {
- //
- // Skip the Resource Descriptor HOB that contains the PHIT
- //
- if (Hob.ResourceDescriptor == PhitResourceHob) {
- continue;
- }
-
- //
- // Skip the Resource Descriptor HOB that contains Memory Type Information bins
- //
- if (Hob.ResourceDescriptor == MemoryTypeInformationResourceHob) {
- continue;
- }
-
- //
- // Skip all HOBs except Resource Descriptor HOBs
- //
- if (GET_HOB_TYPE (Hob) != EFI_HOB_TYPE_RESOURCE_DESCRIPTOR) {
- continue;
- }
-
- //
- // Skip Resource Descriptor HOBs that do not describe tested system memory below MAX_ALLOC_ADDRESS
- //
- ResourceHob = Hob.ResourceDescriptor;
- if (ResourceHob->ResourceType != EFI_RESOURCE_SYSTEM_MEMORY) {
- continue;
- }
-
- if ((ResourceHob->ResourceAttribute & MEMORY_ATTRIBUTE_MASK) != TESTED_MEMORY_ATTRIBUTES) {
- continue;
- }
-
- if ((ResourceHob->PhysicalStart + ResourceHob->ResourceLength) > (EFI_PHYSICAL_ADDRESS)MAX_ALLOC_ADDRESS) {
- continue;
- }
-
- //
- // Skip Resource Descriptor HOBs that are below a previously found Resource Descriptor HOB
- //
- if ((HighAddress != (EFI_PHYSICAL_ADDRESS)MAX_ALLOC_ADDRESS) && (ResourceHob->PhysicalStart <= HighAddress)) {
- continue;
- }
-
- //
- // Skip Resource Descriptor HOBs that are not large enough to initilize the DXE Core
- //
- TestedMemoryBaseAddress = PageAlignAddress (ResourceHob->PhysicalStart);
- TestedMemoryLength = PageAlignLength (ResourceHob->PhysicalStart + ResourceHob->ResourceLength - TestedMemoryBaseAddress);
- FindLargestFreeRegion (&TestedMemoryBaseAddress, &TestedMemoryLength, (EFI_HOB_MEMORY_ALLOCATION *)GetFirstHob (EFI_HOB_TYPE_MEMORY_ALLOCATION));
- if (TestedMemoryLength < MinimalMemorySizeNeeded) {
- continue;
- }
-
- //
- // Save the range described by the Resource Descriptor that is large enough to initilize the DXE Core
- //
- BaseAddress = TestedMemoryBaseAddress;
- Length = TestedMemoryLength;
- Attributes = ResourceHob->ResourceAttribute;
- HighAddress = ResourceHob->PhysicalStart;
- }
- }
-
- DEBUG ((DEBUG_INFO, "CoreInitializeMemoryServices:\n"));
- DEBUG ((DEBUG_INFO, " BaseAddress - 0x%lx Length - 0x%lx MinimalMemorySizeNeeded - 0x%lx\n", BaseAddress, Length, MinimalMemorySizeNeeded));
-
- //
- // If no memory regions are found that are big enough to initialize the DXE core, then ASSERT().
- //
- ASSERT (Length >= MinimalMemorySizeNeeded);
-
- //
- // Convert the Resource HOB Attributes to an EFI Memory Capabilities mask
- //
- if ((Attributes & EFI_RESOURCE_ATTRIBUTE_MORE_RELIABLE) == EFI_RESOURCE_ATTRIBUTE_MORE_RELIABLE) {
- Capabilities = CoreConvertResourceDescriptorHobAttributesToCapabilities (EfiGcdMemoryTypeMoreReliable, Attributes);
- } else {
- Capabilities = CoreConvertResourceDescriptorHobAttributesToCapabilities (EfiGcdMemoryTypeSystemMemory, Attributes);
- }
-
- if (MemoryTypeInformationResourceHob != NULL) {
- //
- // If a Memory Type Information Resource HOB was found, then use the address
- // range of the Memory Type Information Resource HOB as the preferred
- // address range for the Memory Type Information bins.
- //
- CoreSetMemoryTypeInformationRange (
- MemoryTypeInformationResourceHob->PhysicalStart,
- MemoryTypeInformationResourceHob->ResourceLength
- );
- }
-
- //
- // Declare the very first memory region, so the EFI Memory Services are available.
- //
- CoreAddMemoryDescriptor (
- EfiConventionalMemory,
- BaseAddress,
- RShiftU64 (Length, EFI_PAGE_SHIFT),
- Capabilities
- );
-
- *MemoryBaseAddress = BaseAddress;
- *MemoryLength = Length;
-
- return EFI_SUCCESS;
-}
-
-/**
- External function. Initializes the GCD and memory services based on the memory
- descriptor HOBs. This function is responsible for priming the GCD map and the
- memory map, so memory allocations and resource allocations can be made. The
- HobStart will be relocated to a pool buffer.
-
- @param HobStart The start address of the HOB
- @param MemoryBaseAddress Start address of memory region found to init DXE
- core.
- @param MemoryLength Length of memory region found to init DXE core.
-
- @retval EFI_SUCCESS GCD services successfully initialized.
-
-**/
-EFI_STATUS
-CoreInitializeGcdServices (
- IN OUT VOID **HobStart,
- IN EFI_PHYSICAL_ADDRESS MemoryBaseAddress,
- IN UINT64 MemoryLength
- )
-{
- EFI_PEI_HOB_POINTERS Hob;
- VOID *NewHobList;
- EFI_HOB_HANDOFF_INFO_TABLE *PhitHob;
- UINT8 SizeOfMemorySpace;
- UINT8 SizeOfIoSpace;
- EFI_HOB_RESOURCE_DESCRIPTOR *ResourceHob;
- EFI_PHYSICAL_ADDRESS BaseAddress;
- UINT64 Length;
- EFI_STATUS Status;
- EFI_GCD_MAP_ENTRY *Entry;
- EFI_GCD_MEMORY_TYPE GcdMemoryType;
- EFI_GCD_IO_TYPE GcdIoType;
- EFI_GCD_MEMORY_SPACE_DESCRIPTOR Descriptor;
- EFI_HOB_MEMORY_ALLOCATION *MemoryHob;
- EFI_HOB_FIRMWARE_VOLUME *FirmwareVolumeHob;
- UINTN NumberOfDescriptors;
- EFI_GCD_MEMORY_SPACE_DESCRIPTOR *MemorySpaceMap;
- UINTN Index;
- UINT64 Capabilities;
- EFI_HOB_CPU *CpuHob;
- EFI_GCD_MEMORY_SPACE_DESCRIPTOR *MemorySpaceMapHobList;
-
- //
- // Cache the PHIT HOB for later use
- //
- PhitHob = (EFI_HOB_HANDOFF_INFO_TABLE *)(*HobStart);
-
- //
- // Get the number of address lines in the I/O and Memory space for the CPU
- //
- CpuHob = GetFirstHob (EFI_HOB_TYPE_CPU);
- ASSERT (CpuHob != NULL);
- SizeOfMemorySpace = CpuHob->SizeOfMemorySpace;
- SizeOfIoSpace = CpuHob->SizeOfIoSpace;
-
- //
- // Initialize the GCD Memory Space Map
- //
- Entry = AllocateCopyPool (sizeof (EFI_GCD_MAP_ENTRY), &mGcdMemorySpaceMapEntryTemplate);
- ASSERT (Entry != NULL);
-
- Entry->EndAddress = LShiftU64 (1, SizeOfMemorySpace) - 1;
-
- InsertHeadList (&mGcdMemorySpaceMap, &Entry->Link);
-
- CoreDumpGcdMemorySpaceMap (TRUE);
-
- //
- // Initialize the GCD I/O Space Map
- //
- Entry = AllocateCopyPool (sizeof (EFI_GCD_MAP_ENTRY), &mGcdIoSpaceMapEntryTemplate);
- ASSERT (Entry != NULL);
-
- Entry->EndAddress = LShiftU64 (1, SizeOfIoSpace) - 1;
-
- InsertHeadList (&mGcdIoSpaceMap, &Entry->Link);
-
- CoreDumpGcdIoSpaceMap (TRUE);
-
- //
- // Walk the HOB list and add all resource descriptors to the GCD
- //
- for (Hob.Raw = *HobStart; !END_OF_HOB_LIST (Hob); Hob.Raw = GET_NEXT_HOB (Hob)) {
- GcdMemoryType = EfiGcdMemoryTypeNonExistent;
- GcdIoType = EfiGcdIoTypeNonExistent;
-
- if (GET_HOB_TYPE (Hob) == EFI_HOB_TYPE_RESOURCE_DESCRIPTOR) {
- ResourceHob = Hob.ResourceDescriptor;
-
- switch (ResourceHob->ResourceType) {
- case EFI_RESOURCE_SYSTEM_MEMORY:
- if ((ResourceHob->ResourceAttribute & MEMORY_ATTRIBUTE_MASK) == TESTED_MEMORY_ATTRIBUTES) {
- if ((ResourceHob->ResourceAttribute & EFI_RESOURCE_ATTRIBUTE_MORE_RELIABLE) == EFI_RESOURCE_ATTRIBUTE_MORE_RELIABLE) {
- GcdMemoryType = EfiGcdMemoryTypeMoreReliable;
- } else {
- GcdMemoryType = EfiGcdMemoryTypeSystemMemory;
- }
- }
-
- if ((ResourceHob->ResourceAttribute & MEMORY_ATTRIBUTE_MASK) == INITIALIZED_MEMORY_ATTRIBUTES) {
- GcdMemoryType = EfiGcdMemoryTypeReserved;
- }
-
- if ((ResourceHob->ResourceAttribute & MEMORY_ATTRIBUTE_MASK) == PRESENT_MEMORY_ATTRIBUTES) {
- GcdMemoryType = EfiGcdMemoryTypeReserved;
- }
-
- if ((ResourceHob->ResourceAttribute & EFI_RESOURCE_ATTRIBUTE_PERSISTENT) == EFI_RESOURCE_ATTRIBUTE_PERSISTENT) {
- GcdMemoryType = EfiGcdMemoryTypePersistent;
- }
-
- break;
- case EFI_RESOURCE_MEMORY_MAPPED_IO:
- case EFI_RESOURCE_FIRMWARE_DEVICE:
- GcdMemoryType = EfiGcdMemoryTypeMemoryMappedIo;
- break;
- case EFI_RESOURCE_MEMORY_MAPPED_IO_PORT:
- case EFI_RESOURCE_MEMORY_RESERVED:
- GcdMemoryType = EfiGcdMemoryTypeReserved;
- break;
- case EFI_RESOURCE_MEMORY_UNACCEPTED:
- GcdMemoryType = EfiGcdMemoryTypeUnaccepted;
- break;
- case EFI_RESOURCE_IO:
- GcdIoType = EfiGcdIoTypeIo;
- break;
- case EFI_RESOURCE_IO_RESERVED:
- GcdIoType = EfiGcdIoTypeReserved;
- break;
- }
-
- if (GcdMemoryType != EfiGcdMemoryTypeNonExistent) {
- //
- // Validate the Resource HOB Attributes
- //
- CoreValidateResourceDescriptorHobAttributes (ResourceHob->ResourceAttribute);
-
- //
- // Convert the Resource HOB Attributes to an EFI Memory Capabilities mask
- //
- Capabilities = CoreConvertResourceDescriptorHobAttributesToCapabilities (
- GcdMemoryType,
- ResourceHob->ResourceAttribute
- );
-
- Status = CoreInternalAddMemorySpace (
- GcdMemoryType,
- ResourceHob->PhysicalStart,
- ResourceHob->ResourceLength,
- Capabilities
- );
- }
-
- if (GcdIoType != EfiGcdIoTypeNonExistent) {
- Status = CoreAddIoSpace (
- GcdIoType,
- ResourceHob->PhysicalStart,
- ResourceHob->ResourceLength
- );
- }
- }
- }
-
- //
- // Allocate first memory region from the GCD by the DXE core
- //
- Status = CoreGetMemorySpaceDescriptor (MemoryBaseAddress, &Descriptor);
- if (!EFI_ERROR (Status)) {
- ASSERT (
- (Descriptor.GcdMemoryType == EfiGcdMemoryTypeSystemMemory) ||
- (Descriptor.GcdMemoryType == EfiGcdMemoryTypeMoreReliable)
- );
- Status = CoreAllocateMemorySpace (
- EfiGcdAllocateAddress,
- Descriptor.GcdMemoryType,
- 0,
- MemoryLength,
- &MemoryBaseAddress,
- gDxeCoreImageHandle,
- NULL
- );
- }
-
- //
- // Walk the HOB list and allocate all memory space that is consumed by memory allocation HOBs,
- // and Firmware Volume HOBs. Also update the EFI Memory Map with the memory allocation HOBs.
- //
- for (Hob.Raw = *HobStart; !END_OF_HOB_LIST (Hob); Hob.Raw = GET_NEXT_HOB (Hob)) {
- if (GET_HOB_TYPE (Hob) == EFI_HOB_TYPE_MEMORY_ALLOCATION) {
- MemoryHob = Hob.MemoryAllocation;
- BaseAddress = MemoryHob->AllocDescriptor.MemoryBaseAddress;
- Status = CoreGetMemorySpaceDescriptor (BaseAddress, &Descriptor);
- if (!EFI_ERROR (Status)) {
- Status = CoreAllocateMemorySpace (
- EfiGcdAllocateAddress,
- Descriptor.GcdMemoryType,
- 0,
- MemoryHob->AllocDescriptor.MemoryLength,
- &BaseAddress,
- gDxeCoreImageHandle,
- NULL
- );
- if (!EFI_ERROR (Status) &&
- ((Descriptor.GcdMemoryType == EfiGcdMemoryTypeSystemMemory) ||
- (Descriptor.GcdMemoryType == EfiGcdMemoryTypeMoreReliable)))
- {
- CoreAddMemoryDescriptor (
- MemoryHob->AllocDescriptor.MemoryType,
- MemoryHob->AllocDescriptor.MemoryBaseAddress,
- RShiftU64 (MemoryHob->AllocDescriptor.MemoryLength, EFI_PAGE_SHIFT),
- Descriptor.Capabilities & (~EFI_MEMORY_RUNTIME)
- );
- }
- }
- }
-
- if (GET_HOB_TYPE (Hob) == EFI_HOB_TYPE_FV) {
- FirmwareVolumeHob = Hob.FirmwareVolume;
- BaseAddress = FirmwareVolumeHob->BaseAddress;
- Status = CoreAllocateMemorySpace (
- EfiGcdAllocateAddress,
- EfiGcdMemoryTypeMemoryMappedIo,
- 0,
- FirmwareVolumeHob->Length,
- &BaseAddress,
- gDxeCoreImageHandle,
- NULL
- );
- }
- }
-
- //
- // Add and allocate the remaining unallocated system memory to the memory services.
- //
- Status = CoreGetMemorySpaceMap (&NumberOfDescriptors, &MemorySpaceMap);
- ASSERT (Status == EFI_SUCCESS);
-
- MemorySpaceMapHobList = NULL;
- for (Index = 0; Index < NumberOfDescriptors; Index++) {
- if ((MemorySpaceMap[Index].GcdMemoryType == EfiGcdMemoryTypeSystemMemory) ||
- (MemorySpaceMap[Index].GcdMemoryType == EfiGcdMemoryTypeMoreReliable))
- {
- if (MemorySpaceMap[Index].ImageHandle == NULL) {
- BaseAddress = PageAlignAddress (MemorySpaceMap[Index].BaseAddress);
- Length = PageAlignLength (MemorySpaceMap[Index].BaseAddress + MemorySpaceMap[Index].Length - BaseAddress);
- if ((Length == 0) || (MemorySpaceMap[Index].BaseAddress + MemorySpaceMap[Index].Length < BaseAddress)) {
- continue;
- }
-
- if (((UINTN)MemorySpaceMap[Index].BaseAddress <= (UINTN)(*HobStart)) &&
- ((UINTN)(MemorySpaceMap[Index].BaseAddress + MemorySpaceMap[Index].Length) >= (UINTN)PhitHob->EfiFreeMemoryBottom))
- {
- //
- // Skip the memory space that covers HOB List, it should be processed
- // after HOB List relocation to avoid the resources allocated by others
- // to corrupt HOB List before its relocation.
- //
- MemorySpaceMapHobList = &MemorySpaceMap[Index];
- continue;
- }
-
- CoreAddMemoryDescriptor (
- EfiConventionalMemory,
- BaseAddress,
- RShiftU64 (Length, EFI_PAGE_SHIFT),
- MemorySpaceMap[Index].Capabilities & (~EFI_MEMORY_RUNTIME)
- );
- Status = CoreAllocateMemorySpace (
- EfiGcdAllocateAddress,
- MemorySpaceMap[Index].GcdMemoryType,
- 0,
- Length,
- &BaseAddress,
- gDxeCoreImageHandle,
- NULL
- );
- }
- }
- }
-
- //
- // Relocate HOB List to an allocated pool buffer.
- // The relocation should be at after all the tested memory resources added
- // (except the memory space that covers HOB List) to the memory services,
- // because the memory resource found in CoreInitializeMemoryServices()
- // may have not enough remaining resource for HOB List.
- //
- NewHobList = AllocateCopyPool (
- (UINTN)PhitHob->EfiFreeMemoryBottom - (UINTN)(*HobStart),
- *HobStart
- );
- ASSERT (NewHobList != NULL);
-
- *HobStart = NewHobList;
- gHobList = NewHobList;
-
- if (MemorySpaceMapHobList != NULL) {
- //
- // Add and allocate the memory space that covers HOB List to the memory services
- // after HOB List relocation.
- //
- BaseAddress = PageAlignAddress (MemorySpaceMapHobList->BaseAddress);
- Length = PageAlignLength (MemorySpaceMapHobList->BaseAddress + MemorySpaceMapHobList->Length - BaseAddress);
- CoreAddMemoryDescriptor (
- EfiConventionalMemory,
- BaseAddress,
- RShiftU64 (Length, EFI_PAGE_SHIFT),
- MemorySpaceMapHobList->Capabilities & (~EFI_MEMORY_RUNTIME)
- );
- Status = CoreAllocateMemorySpace (
- EfiGcdAllocateAddress,
- MemorySpaceMapHobList->GcdMemoryType,
- 0,
- Length,
- &BaseAddress,
- gDxeCoreImageHandle,
- NULL
- );
- }
-
- CoreFreePool (MemorySpaceMap);
-
- return EFI_SUCCESS;
-}
+/** @file
+ The file contains the GCD related services in the EFI Boot Services Table.
+ The GCD services are used to manage the memory and I/O regions that
+ are accessible to the CPU that is executing the DXE core.
+
+Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Pi/PiDxeCis.h>
+#include <Pi/PiHob.h>
+#include "DxeMain.h"
+#include "Gcd.h"
+#include "Mem/HeapGuard.h"
+
+#define MINIMUM_INITIAL_MEMORY_SIZE 0x10000
+
+#define MEMORY_ATTRIBUTE_MASK (EFI_RESOURCE_ATTRIBUTE_PRESENT | \
+ EFI_RESOURCE_ATTRIBUTE_INITIALIZED | \
+ EFI_RESOURCE_ATTRIBUTE_TESTED | \
+ EFI_RESOURCE_ATTRIBUTE_READ_PROTECTED | \
+ EFI_RESOURCE_ATTRIBUTE_WRITE_PROTECTED | \
+ EFI_RESOURCE_ATTRIBUTE_EXECUTION_PROTECTED | \
+ EFI_RESOURCE_ATTRIBUTE_READ_ONLY_PROTECTED | \
+ EFI_RESOURCE_ATTRIBUTE_16_BIT_IO | \
+ EFI_RESOURCE_ATTRIBUTE_32_BIT_IO | \
+ EFI_RESOURCE_ATTRIBUTE_64_BIT_IO | \
+ EFI_RESOURCE_ATTRIBUTE_PERSISTENT )
+
+#define TESTED_MEMORY_ATTRIBUTES (EFI_RESOURCE_ATTRIBUTE_PRESENT | \
+ EFI_RESOURCE_ATTRIBUTE_INITIALIZED | \
+ EFI_RESOURCE_ATTRIBUTE_TESTED )
+
+#define INITIALIZED_MEMORY_ATTRIBUTES (EFI_RESOURCE_ATTRIBUTE_PRESENT |\
+ EFI_RESOURCE_ATTRIBUTE_INITIALIZED )
+
+#define PRESENT_MEMORY_ATTRIBUTES (EFI_RESOURCE_ATTRIBUTE_PRESENT)
+
+//
+// Module Variables
+//
+EFI_LOCK mGcdMemorySpaceLock = EFI_INITIALIZE_LOCK_VARIABLE (TPL_NOTIFY);
+EFI_LOCK mGcdIoSpaceLock = EFI_INITIALIZE_LOCK_VARIABLE (TPL_NOTIFY);
+LIST_ENTRY mGcdMemorySpaceMap = INITIALIZE_LIST_HEAD_VARIABLE (mGcdMemorySpaceMap);
+LIST_ENTRY mGcdIoSpaceMap = INITIALIZE_LIST_HEAD_VARIABLE (mGcdIoSpaceMap);
+
+EFI_GCD_MAP_ENTRY mGcdMemorySpaceMapEntryTemplate = {
+ EFI_GCD_MAP_SIGNATURE,
+ {
+ NULL,
+ NULL
+ },
+ 0,
+ 0,
+ 0,
+ 0,
+ EfiGcdMemoryTypeNonExistent,
+ (EFI_GCD_IO_TYPE)0,
+ NULL,
+ NULL
+};
+
+EFI_GCD_MAP_ENTRY mGcdIoSpaceMapEntryTemplate = {
+ EFI_GCD_MAP_SIGNATURE,
+ {
+ NULL,
+ NULL
+ },
+ 0,
+ 0,
+ 0,
+ 0,
+ (EFI_GCD_MEMORY_TYPE)0,
+ EfiGcdIoTypeNonExistent,
+ NULL,
+ NULL
+};
+
+GCD_ATTRIBUTE_CONVERSION_ENTRY mAttributeConversionTable[] = {
+ { EFI_RESOURCE_ATTRIBUTE_UNCACHEABLE, EFI_MEMORY_UC, TRUE },
+ { EFI_RESOURCE_ATTRIBUTE_UNCACHED_EXPORTED, EFI_MEMORY_UCE, TRUE },
+ { EFI_RESOURCE_ATTRIBUTE_WRITE_COMBINEABLE, EFI_MEMORY_WC, TRUE },
+ { EFI_RESOURCE_ATTRIBUTE_WRITE_THROUGH_CACHEABLE, EFI_MEMORY_WT, TRUE },
+ { EFI_RESOURCE_ATTRIBUTE_WRITE_BACK_CACHEABLE, EFI_MEMORY_WB, TRUE },
+ { EFI_RESOURCE_ATTRIBUTE_READ_PROTECTABLE, EFI_MEMORY_RP, TRUE },
+ { EFI_RESOURCE_ATTRIBUTE_WRITE_PROTECTABLE, EFI_MEMORY_WP, TRUE },
+ { EFI_RESOURCE_ATTRIBUTE_EXECUTION_PROTECTABLE, EFI_MEMORY_XP, TRUE },
+ { EFI_RESOURCE_ATTRIBUTE_READ_ONLY_PROTECTABLE, EFI_MEMORY_RO, TRUE },
+ { EFI_RESOURCE_ATTRIBUTE_PRESENT, EFI_MEMORY_PRESENT, FALSE },
+ { EFI_RESOURCE_ATTRIBUTE_INITIALIZED, EFI_MEMORY_INITIALIZED, FALSE },
+ { EFI_RESOURCE_ATTRIBUTE_TESTED, EFI_MEMORY_TESTED, FALSE },
+ { EFI_RESOURCE_ATTRIBUTE_PERSISTABLE, EFI_MEMORY_NV, TRUE },
+ { EFI_RESOURCE_ATTRIBUTE_MORE_RELIABLE, EFI_MEMORY_MORE_RELIABLE, TRUE },
+ { EFI_RESOURCE_ATTRIBUTE_SPECIAL_PURPOSE, EFI_MEMORY_SP, TRUE },
+ { 0, 0, FALSE }
+};
+
+///
+/// Lookup table used to print GCD Memory Space Map
+///
+GLOBAL_REMOVE_IF_UNREFERENCED CONST CHAR8 *mGcdMemoryTypeNames[] = {
+ "NonExist ", // EfiGcdMemoryTypeNonExistent
+ "Reserved ", // EfiGcdMemoryTypeReserved
+ "SystemMem", // EfiGcdMemoryTypeSystemMemory
+ "MMIO ", // EfiGcdMemoryTypeMemoryMappedIo
+ "PersisMem", // EfiGcdMemoryTypePersistent
+ "MoreRelia", // EfiGcdMemoryTypeMoreReliable
+ "Unaccepte", // EfiGcdMemoryTypeUnaccepted
+ "Unknown " // EfiGcdMemoryTypeMaximum
+};
+
+///
+/// Lookup table used to print GCD I/O Space Map
+///
+GLOBAL_REMOVE_IF_UNREFERENCED CONST CHAR8 *mGcdIoTypeNames[] = {
+ "NonExist", // EfiGcdIoTypeNonExistent
+ "Reserved", // EfiGcdIoTypeReserved
+ "I/O ", // EfiGcdIoTypeIo
+ "Unknown " // EfiGcdIoTypeMaximum
+};
+
+///
+/// Lookup table used to print GCD Allocation Types
+///
+GLOBAL_REMOVE_IF_UNREFERENCED CONST CHAR8 *mGcdAllocationTypeNames[] = {
+ "AnySearchBottomUp ", // EfiGcdAllocateAnySearchBottomUp
+ "MaxAddressSearchBottomUp ", // EfiGcdAllocateMaxAddressSearchBottomUp
+ "AtAddress ", // EfiGcdAllocateAddress
+ "AnySearchTopDown ", // EfiGcdAllocateAnySearchTopDown
+ "MaxAddressSearchTopDown ", // EfiGcdAllocateMaxAddressSearchTopDown
+ "Unknown " // EfiGcdMaxAllocateType
+};
+
+/**
+ Dump the entire contents if the GCD Memory Space Map using DEBUG() macros when
+ PcdDebugPrintErrorLevel has the DEBUG_GCD bit set.
+
+ @param InitialMap TRUE if the initial GCD Memory Map is being dumped. Otherwise, FALSE.
+
+**/
+VOID
+EFIAPI
+CoreDumpGcdMemorySpaceMap (
+ BOOLEAN InitialMap
+ )
+{
+ DEBUG_CODE_BEGIN ();
+ EFI_STATUS Status;
+ UINTN NumberOfDescriptors;
+ EFI_GCD_MEMORY_SPACE_DESCRIPTOR *MemorySpaceMap;
+ UINTN Index;
+
+ Status = CoreGetMemorySpaceMap (&NumberOfDescriptors, &MemorySpaceMap);
+ ASSERT (Status == EFI_SUCCESS && MemorySpaceMap != NULL);
+
+ if (InitialMap) {
+ DEBUG ((DEBUG_GCD, "GCD:Initial GCD Memory Space Map\n"));
+ }
+
+ DEBUG ((DEBUG_GCD, "GCDMemType Range Capabilities Attributes \n"));
+ DEBUG ((DEBUG_GCD, "========== ================================= ================ ================\n"));
+ for (Index = 0; Index < NumberOfDescriptors; Index++) {
+ DEBUG ((
+ DEBUG_GCD,
+ "%a %016lx-%016lx %016lx %016lx%c\n",
+ mGcdMemoryTypeNames[MIN (MemorySpaceMap[Index].GcdMemoryType, EfiGcdMemoryTypeMaximum)],
+ MemorySpaceMap[Index].BaseAddress,
+ MemorySpaceMap[Index].BaseAddress + MemorySpaceMap[Index].Length - 1,
+ MemorySpaceMap[Index].Capabilities,
+ MemorySpaceMap[Index].Attributes,
+ MemorySpaceMap[Index].ImageHandle == NULL ? ' ' : '*'
+ ));
+ }
+
+ DEBUG ((DEBUG_GCD, "\n"));
+ FreePool (MemorySpaceMap);
+ DEBUG_CODE_END ();
+}
+
+/**
+ Dump the entire contents if the GCD I/O Space Map using DEBUG() macros when
+ PcdDebugPrintErrorLevel has the DEBUG_GCD bit set.
+
+ @param InitialMap TRUE if the initial GCD I/O Map is being dumped. Otherwise, FALSE.
+
+**/
+VOID
+EFIAPI
+CoreDumpGcdIoSpaceMap (
+ BOOLEAN InitialMap
+ )
+{
+ DEBUG_CODE_BEGIN ();
+ EFI_STATUS Status;
+ UINTN NumberOfDescriptors;
+ EFI_GCD_IO_SPACE_DESCRIPTOR *IoSpaceMap;
+ UINTN Index;
+
+ Status = CoreGetIoSpaceMap (&NumberOfDescriptors, &IoSpaceMap);
+ ASSERT (Status == EFI_SUCCESS && IoSpaceMap != NULL);
+
+ if (InitialMap) {
+ DEBUG ((DEBUG_GCD, "GCD:Initial GCD I/O Space Map\n"));
+ }
+
+ DEBUG ((DEBUG_GCD, "GCDIoType Range \n"));
+ DEBUG ((DEBUG_GCD, "========== =================================\n"));
+ for (Index = 0; Index < NumberOfDescriptors; Index++) {
+ DEBUG ((
+ DEBUG_GCD,
+ "%a %016lx-%016lx%c\n",
+ mGcdIoTypeNames[MIN (IoSpaceMap[Index].GcdIoType, EfiGcdIoTypeMaximum)],
+ IoSpaceMap[Index].BaseAddress,
+ IoSpaceMap[Index].BaseAddress + IoSpaceMap[Index].Length - 1,
+ IoSpaceMap[Index].ImageHandle == NULL ? ' ' : '*'
+ ));
+ }
+
+ DEBUG ((DEBUG_GCD, "\n"));
+ FreePool (IoSpaceMap);
+ DEBUG_CODE_END ();
+}
+
+/**
+ Validate resource descriptor HOB's attributes.
+
+ If Attributes includes some memory resource's settings, it should include
+ the corresponding capabilites also.
+
+ @param Attributes Resource descriptor HOB attributes.
+
+**/
+VOID
+CoreValidateResourceDescriptorHobAttributes (
+ IN UINT64 Attributes
+ )
+{
+ ASSERT (
+ ((Attributes & EFI_RESOURCE_ATTRIBUTE_READ_PROTECTED) == 0) ||
+ ((Attributes & EFI_RESOURCE_ATTRIBUTE_READ_PROTECTABLE) != 0)
+ );
+ ASSERT (
+ ((Attributes & EFI_RESOURCE_ATTRIBUTE_WRITE_PROTECTED) == 0) ||
+ ((Attributes & EFI_RESOURCE_ATTRIBUTE_WRITE_PROTECTABLE) != 0)
+ );
+ ASSERT (
+ ((Attributes & EFI_RESOURCE_ATTRIBUTE_EXECUTION_PROTECTED) == 0) ||
+ ((Attributes & EFI_RESOURCE_ATTRIBUTE_EXECUTION_PROTECTABLE) != 0)
+ );
+ ASSERT (
+ ((Attributes & EFI_RESOURCE_ATTRIBUTE_READ_ONLY_PROTECTED) == 0) ||
+ ((Attributes & EFI_RESOURCE_ATTRIBUTE_READ_ONLY_PROTECTABLE) != 0)
+ );
+ ASSERT (
+ ((Attributes & EFI_RESOURCE_ATTRIBUTE_PERSISTENT) == 0) ||
+ ((Attributes & EFI_RESOURCE_ATTRIBUTE_PERSISTABLE) != 0)
+ );
+}
+
+/**
+ Acquire memory lock on mGcdMemorySpaceLock.
+
+**/
+VOID
+CoreAcquireGcdMemoryLock (
+ VOID
+ )
+{
+ CoreAcquireLock (&mGcdMemorySpaceLock);
+}
+
+/**
+ Release memory lock on mGcdMemorySpaceLock.
+
+**/
+VOID
+CoreReleaseGcdMemoryLock (
+ VOID
+ )
+{
+ CoreReleaseLock (&mGcdMemorySpaceLock);
+}
+
+/**
+ Acquire memory lock on mGcdIoSpaceLock.
+
+**/
+VOID
+CoreAcquireGcdIoLock (
+ VOID
+ )
+{
+ CoreAcquireLock (&mGcdIoSpaceLock);
+}
+
+/**
+ Release memory lock on mGcdIoSpaceLock.
+
+**/
+VOID
+CoreReleaseGcdIoLock (
+ VOID
+ )
+{
+ CoreReleaseLock (&mGcdIoSpaceLock);
+}
+
+//
+// GCD Initialization Worker Functions
+//
+
+/**
+ Aligns a value to the specified boundary.
+
+ @param Value 64 bit value to align
+ @param Alignment Log base 2 of the boundary to align Value to
+ @param RoundUp TRUE if Value is to be rounded up to the nearest
+ aligned boundary. FALSE is Value is to be
+ rounded down to the nearest aligned boundary.
+
+ @return A 64 bit value is the aligned to the value nearest Value with an alignment by Alignment.
+
+**/
+UINT64
+AlignValue (
+ IN UINT64 Value,
+ IN UINTN Alignment,
+ IN BOOLEAN RoundUp
+ )
+{
+ UINT64 AlignmentMask;
+
+ AlignmentMask = LShiftU64 (1, Alignment) - 1;
+ if (RoundUp) {
+ Value += AlignmentMask;
+ }
+
+ return Value & (~AlignmentMask);
+}
+
+/**
+ Aligns address to the page boundary.
+
+ @param Value 64 bit address to align
+
+ @return A 64 bit value is the aligned to the value nearest Value with an alignment by Alignment.
+
+**/
+UINT64
+PageAlignAddress (
+ IN UINT64 Value
+ )
+{
+ return AlignValue (Value, EFI_PAGE_SHIFT, TRUE);
+}
+
+/**
+ Aligns length to the page boundary.
+
+ @param Value 64 bit length to align
+
+ @return A 64 bit value is the aligned to the value nearest Value with an alignment by Alignment.
+
+**/
+UINT64
+PageAlignLength (
+ IN UINT64 Value
+ )
+{
+ return AlignValue (Value, EFI_PAGE_SHIFT, FALSE);
+}
+
+//
+// GCD Memory Space Worker Functions
+//
+
+/**
+ Allocate pool for two entries.
+
+ @param TopEntry An entry of GCD map
+ @param BottomEntry An entry of GCD map
+
+ @retval EFI_OUT_OF_RESOURCES No enough buffer to be allocated.
+ @retval EFI_SUCCESS Both entries successfully allocated.
+
+**/
+EFI_STATUS
+CoreAllocateGcdMapEntry (
+ IN OUT EFI_GCD_MAP_ENTRY **TopEntry,
+ IN OUT EFI_GCD_MAP_ENTRY **BottomEntry
+ )
+{
+ //
+ // Set to mOnGuarding to TRUE before memory allocation. This will make sure
+ // that the entry memory is not "guarded" by HeapGuard. Otherwise it might
+ // cause problem when it's freed (if HeapGuard is enabled).
+ //
+ mOnGuarding = TRUE;
+ *TopEntry = AllocateZeroPool (sizeof (EFI_GCD_MAP_ENTRY));
+ mOnGuarding = FALSE;
+ if (*TopEntry == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ mOnGuarding = TRUE;
+ *BottomEntry = AllocateZeroPool (sizeof (EFI_GCD_MAP_ENTRY));
+ mOnGuarding = FALSE;
+ if (*BottomEntry == NULL) {
+ CoreFreePool (*TopEntry);
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Internal function. Inserts a new descriptor into a sorted list
+
+ @param Link The linked list to insert the range BaseAddress
+ and Length into
+ @param Entry A pointer to the entry that is inserted
+ @param BaseAddress The base address of the new range
+ @param Length The length of the new range in bytes
+ @param TopEntry Top pad entry to insert if needed.
+ @param BottomEntry Bottom pad entry to insert if needed.
+
+ @retval EFI_SUCCESS The new range was inserted into the linked list
+
+**/
+EFI_STATUS
+CoreInsertGcdMapEntry (
+ IN LIST_ENTRY *Link,
+ IN EFI_GCD_MAP_ENTRY *Entry,
+ IN EFI_PHYSICAL_ADDRESS BaseAddress,
+ IN UINT64 Length,
+ IN EFI_GCD_MAP_ENTRY *TopEntry,
+ IN EFI_GCD_MAP_ENTRY *BottomEntry
+ )
+{
+ ASSERT (Length != 0);
+
+ if (BaseAddress > Entry->BaseAddress) {
+ ASSERT (BottomEntry->Signature == 0);
+
+ CopyMem (BottomEntry, Entry, sizeof (EFI_GCD_MAP_ENTRY));
+ Entry->BaseAddress = BaseAddress;
+ BottomEntry->EndAddress = BaseAddress - 1;
+ InsertTailList (Link, &BottomEntry->Link);
+ }
+
+ if ((BaseAddress + Length - 1) < Entry->EndAddress) {
+ ASSERT (TopEntry->Signature == 0);
+
+ CopyMem (TopEntry, Entry, sizeof (EFI_GCD_MAP_ENTRY));
+ TopEntry->BaseAddress = BaseAddress + Length;
+ Entry->EndAddress = BaseAddress + Length - 1;
+ InsertHeadList (Link, &TopEntry->Link);
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Merge the Gcd region specified by Link and its adjacent entry.
+
+ @param Link Specify the entry to be merged (with its
+ adjacent entry).
+ @param Forward Direction (forward or backward).
+ @param Map Boundary.
+
+ @retval EFI_SUCCESS Successfully returned.
+ @retval EFI_UNSUPPORTED These adjacent regions could not merge.
+
+**/
+EFI_STATUS
+CoreMergeGcdMapEntry (
+ IN LIST_ENTRY *Link,
+ IN BOOLEAN Forward,
+ IN LIST_ENTRY *Map
+ )
+{
+ LIST_ENTRY *AdjacentLink;
+ EFI_GCD_MAP_ENTRY *Entry;
+ EFI_GCD_MAP_ENTRY *AdjacentEntry;
+
+ //
+ // Get adjacent entry
+ //
+ if (Forward) {
+ AdjacentLink = Link->ForwardLink;
+ } else {
+ AdjacentLink = Link->BackLink;
+ }
+
+ //
+ // If AdjacentLink is the head of the list, then no merge can be performed
+ //
+ if (AdjacentLink == Map) {
+ return EFI_SUCCESS;
+ }
+
+ Entry = CR (Link, EFI_GCD_MAP_ENTRY, Link, EFI_GCD_MAP_SIGNATURE);
+ AdjacentEntry = CR (AdjacentLink, EFI_GCD_MAP_ENTRY, Link, EFI_GCD_MAP_SIGNATURE);
+
+ if (Entry->Capabilities != AdjacentEntry->Capabilities) {
+ return EFI_UNSUPPORTED;
+ }
+
+ if (Entry->Attributes != AdjacentEntry->Attributes) {
+ return EFI_UNSUPPORTED;
+ }
+
+ if (Entry->GcdMemoryType != AdjacentEntry->GcdMemoryType) {
+ return EFI_UNSUPPORTED;
+ }
+
+ if (Entry->GcdIoType != AdjacentEntry->GcdIoType) {
+ return EFI_UNSUPPORTED;
+ }
+
+ if (Entry->ImageHandle != AdjacentEntry->ImageHandle) {
+ return EFI_UNSUPPORTED;
+ }
+
+ if (Entry->DeviceHandle != AdjacentEntry->DeviceHandle) {
+ return EFI_UNSUPPORTED;
+ }
+
+ if (Forward) {
+ Entry->EndAddress = AdjacentEntry->EndAddress;
+ } else {
+ Entry->BaseAddress = AdjacentEntry->BaseAddress;
+ }
+
+ RemoveEntryList (AdjacentLink);
+ CoreFreePool (AdjacentEntry);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Merge adjacent entries on total chain.
+
+ @param TopEntry Top entry of GCD map.
+ @param BottomEntry Bottom entry of GCD map.
+ @param StartLink Start link of the list for this loop.
+ @param EndLink End link of the list for this loop.
+ @param Map Boundary.
+
+ @retval EFI_SUCCESS GCD map successfully cleaned up.
+
+**/
+EFI_STATUS
+CoreCleanupGcdMapEntry (
+ IN EFI_GCD_MAP_ENTRY *TopEntry,
+ IN EFI_GCD_MAP_ENTRY *BottomEntry,
+ IN LIST_ENTRY *StartLink,
+ IN LIST_ENTRY *EndLink,
+ IN LIST_ENTRY *Map
+ )
+{
+ LIST_ENTRY *Link;
+
+ if (TopEntry->Signature == 0) {
+ CoreFreePool (TopEntry);
+ }
+
+ if (BottomEntry->Signature == 0) {
+ CoreFreePool (BottomEntry);
+ }
+
+ Link = StartLink;
+ while (Link != EndLink->ForwardLink) {
+ CoreMergeGcdMapEntry (Link, FALSE, Map);
+ Link = Link->ForwardLink;
+ }
+
+ CoreMergeGcdMapEntry (EndLink, TRUE, Map);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Search a segment of memory space in GCD map. The result is a range of GCD entry list.
+
+ @param BaseAddress The start address of the segment.
+ @param Length The length of the segment.
+ @param StartLink The first GCD entry involves this segment of
+ memory space.
+ @param EndLink The first GCD entry involves this segment of
+ memory space.
+ @param Map Points to the start entry to search.
+
+ @retval EFI_SUCCESS Successfully found the entry.
+ @retval EFI_NOT_FOUND Not found.
+
+**/
+EFI_STATUS
+CoreSearchGcdMapEntry (
+ IN EFI_PHYSICAL_ADDRESS BaseAddress,
+ IN UINT64 Length,
+ OUT LIST_ENTRY **StartLink,
+ OUT LIST_ENTRY **EndLink,
+ IN LIST_ENTRY *Map
+ )
+{
+ LIST_ENTRY *Link;
+ EFI_GCD_MAP_ENTRY *Entry;
+
+ ASSERT (Length != 0);
+
+ *StartLink = NULL;
+ *EndLink = NULL;
+
+ Link = Map->ForwardLink;
+ while (Link != Map) {
+ Entry = CR (Link, EFI_GCD_MAP_ENTRY, Link, EFI_GCD_MAP_SIGNATURE);
+ if ((BaseAddress >= Entry->BaseAddress) && (BaseAddress <= Entry->EndAddress)) {
+ *StartLink = Link;
+ }
+
+ if (*StartLink != NULL) {
+ if (((BaseAddress + Length - 1) >= Entry->BaseAddress) &&
+ ((BaseAddress + Length - 1) <= Entry->EndAddress))
+ {
+ *EndLink = Link;
+ return EFI_SUCCESS;
+ }
+ }
+
+ Link = Link->ForwardLink;
+ }
+
+ return EFI_NOT_FOUND;
+}
+
+/**
+ Count the amount of GCD map entries.
+
+ @param Map Points to the start entry to do the count loop.
+
+ @return The count.
+
+**/
+UINTN
+CoreCountGcdMapEntry (
+ IN LIST_ENTRY *Map
+ )
+{
+ UINTN Count;
+ LIST_ENTRY *Link;
+
+ Count = 0;
+ Link = Map->ForwardLink;
+ while (Link != Map) {
+ Count++;
+ Link = Link->ForwardLink;
+ }
+
+ return Count;
+}
+
+/**
+ Return the memory attribute specified by Attributes
+
+ @param Attributes A num with some attribute bits on.
+
+ @return The enum value of memory attribute.
+
+**/
+UINT64
+ConverToCpuArchAttributes (
+ UINT64 Attributes
+ )
+{
+ UINT64 CpuArchAttributes;
+
+ CpuArchAttributes = Attributes & EFI_MEMORY_ATTRIBUTE_MASK;
+
+ if ((Attributes & EFI_MEMORY_UC) == EFI_MEMORY_UC) {
+ CpuArchAttributes |= EFI_MEMORY_UC;
+ } else if ((Attributes & EFI_MEMORY_WC) == EFI_MEMORY_WC) {
+ CpuArchAttributes |= EFI_MEMORY_WC;
+ } else if ((Attributes & EFI_MEMORY_WT) == EFI_MEMORY_WT) {
+ CpuArchAttributes |= EFI_MEMORY_WT;
+ } else if ((Attributes & EFI_MEMORY_WB) == EFI_MEMORY_WB) {
+ CpuArchAttributes |= EFI_MEMORY_WB;
+ } else if ((Attributes & EFI_MEMORY_UCE) == EFI_MEMORY_UCE) {
+ CpuArchAttributes |= EFI_MEMORY_UCE;
+ } else if ((Attributes & EFI_MEMORY_WP) == EFI_MEMORY_WP) {
+ CpuArchAttributes |= EFI_MEMORY_WP;
+ }
+
+ return CpuArchAttributes;
+}
+
+/**
+ Do operation on a segment of memory space specified (add, free, remove, change attribute ...).
+
+ @param Operation The type of the operation
+ @param GcdMemoryType Additional information for the operation
+ @param GcdIoType Additional information for the operation
+ @param BaseAddress Start address of the segment
+ @param Length length of the segment
+ @param Capabilities The alterable attributes of a newly added entry
+ @param Attributes The attributes needs to be set
+
+ @retval EFI_INVALID_PARAMETER Length is 0 or address (length) not aligned when
+ setting attribute.
+ @retval EFI_SUCCESS Action successfully done.
+ @retval EFI_UNSUPPORTED Could not find the proper descriptor on this
+ segment or set an upsupported attribute.
+ @retval EFI_ACCESS_DENIED Operate on an space non-exist or is used for an
+ image.
+ @retval EFI_NOT_FOUND Free a non-using space or remove a non-exist
+ space, and so on.
+ @retval EFI_OUT_OF_RESOURCES No buffer could be allocated.
+ @retval EFI_NOT_AVAILABLE_YET The attributes cannot be set because CPU architectural protocol
+ is not available yet.
+**/
+EFI_STATUS
+CoreConvertSpace (
+ IN UINTN Operation,
+ IN EFI_GCD_MEMORY_TYPE GcdMemoryType,
+ IN EFI_GCD_IO_TYPE GcdIoType,
+ IN EFI_PHYSICAL_ADDRESS BaseAddress,
+ IN UINT64 Length,
+ IN UINT64 Capabilities,
+ IN UINT64 Attributes
+ )
+{
+ EFI_STATUS Status;
+ LIST_ENTRY *Map;
+ LIST_ENTRY *Link;
+ EFI_GCD_MAP_ENTRY *Entry;
+ EFI_GCD_MAP_ENTRY *TopEntry;
+ EFI_GCD_MAP_ENTRY *BottomEntry;
+ LIST_ENTRY *StartLink;
+ LIST_ENTRY *EndLink;
+ UINT64 CpuArchAttributes;
+
+ if (Length == 0) {
+ DEBUG ((DEBUG_GCD, " Status = %r\n", EFI_INVALID_PARAMETER));
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Map = NULL;
+ if ((Operation & GCD_MEMORY_SPACE_OPERATION) != 0) {
+ CoreAcquireGcdMemoryLock ();
+ Map = &mGcdMemorySpaceMap;
+ } else if ((Operation & GCD_IO_SPACE_OPERATION) != 0) {
+ CoreAcquireGcdIoLock ();
+ Map = &mGcdIoSpaceMap;
+ } else {
+ ASSERT (FALSE);
+ }
+
+ //
+ // Search for the list of descriptors that cover the range BaseAddress to BaseAddress+Length
+ //
+ Status = CoreSearchGcdMapEntry (BaseAddress, Length, &StartLink, &EndLink, Map);
+ if (EFI_ERROR (Status)) {
+ Status = EFI_UNSUPPORTED;
+
+ goto Done;
+ }
+
+ ASSERT (StartLink != NULL && EndLink != NULL);
+
+ //
+ // Verify that the list of descriptors are unallocated non-existent memory.
+ //
+ Link = StartLink;
+ while (Link != EndLink->ForwardLink) {
+ Entry = CR (Link, EFI_GCD_MAP_ENTRY, Link, EFI_GCD_MAP_SIGNATURE);
+ switch (Operation) {
+ //
+ // Add operations
+ //
+ case GCD_ADD_MEMORY_OPERATION:
+ if ((Entry->GcdMemoryType != EfiGcdMemoryTypeNonExistent) ||
+ (Entry->ImageHandle != NULL))
+ {
+ Status = EFI_ACCESS_DENIED;
+ goto Done;
+ }
+
+ break;
+ case GCD_ADD_IO_OPERATION:
+ if ((Entry->GcdIoType != EfiGcdIoTypeNonExistent) ||
+ (Entry->ImageHandle != NULL))
+ {
+ Status = EFI_ACCESS_DENIED;
+ goto Done;
+ }
+
+ break;
+ //
+ // Free operations
+ //
+ case GCD_FREE_MEMORY_OPERATION:
+ case GCD_FREE_IO_OPERATION:
+ if (Entry->ImageHandle == NULL) {
+ Status = EFI_NOT_FOUND;
+ goto Done;
+ }
+
+ break;
+ //
+ // Remove operations
+ //
+ case GCD_REMOVE_MEMORY_OPERATION:
+ if (Entry->GcdMemoryType == EfiGcdMemoryTypeNonExistent) {
+ Status = EFI_NOT_FOUND;
+ goto Done;
+ }
+
+ if (Entry->ImageHandle != NULL) {
+ Status = EFI_ACCESS_DENIED;
+ goto Done;
+ }
+
+ break;
+ case GCD_REMOVE_IO_OPERATION:
+ if (Entry->GcdIoType == EfiGcdIoTypeNonExistent) {
+ Status = EFI_NOT_FOUND;
+ goto Done;
+ }
+
+ if (Entry->ImageHandle != NULL) {
+ Status = EFI_ACCESS_DENIED;
+ goto Done;
+ }
+
+ break;
+ //
+ // Set attributes operation
+ //
+ case GCD_SET_ATTRIBUTES_MEMORY_OPERATION:
+ if ((Attributes & EFI_MEMORY_RUNTIME) != 0) {
+ if (((BaseAddress & EFI_PAGE_MASK) != 0) || ((Length & EFI_PAGE_MASK) != 0)) {
+ Status = EFI_INVALID_PARAMETER;
+ goto Done;
+ }
+ }
+
+ if ((Entry->Capabilities & Attributes) != Attributes) {
+ Status = EFI_UNSUPPORTED;
+ goto Done;
+ }
+
+ break;
+ //
+ // Set capabilities operation
+ //
+ case GCD_SET_CAPABILITIES_MEMORY_OPERATION:
+ if (((BaseAddress & EFI_PAGE_MASK) != 0) || ((Length & EFI_PAGE_MASK) != 0)) {
+ Status = EFI_INVALID_PARAMETER;
+
+ goto Done;
+ }
+
+ //
+ // Current attributes must still be supported with new capabilities
+ //
+ if ((Capabilities & Entry->Attributes) != Entry->Attributes) {
+ Status = EFI_UNSUPPORTED;
+ goto Done;
+ }
+
+ break;
+ }
+
+ Link = Link->ForwardLink;
+ }
+
+ //
+ // Allocate work space to perform this operation
+ //
+ Status = CoreAllocateGcdMapEntry (&TopEntry, &BottomEntry);
+ if (EFI_ERROR (Status)) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Done;
+ }
+
+ ASSERT (TopEntry != NULL && BottomEntry != NULL);
+
+ //
+ // Initialize CpuArchAttributes to suppress incorrect compiler/analyzer warnings.
+ //
+ CpuArchAttributes = 0;
+ if (Operation == GCD_SET_ATTRIBUTES_MEMORY_OPERATION) {
+ //
+ // Call CPU Arch Protocol to attempt to set attributes on the range
+ //
+ CpuArchAttributes = ConverToCpuArchAttributes (Attributes);
+ //
+ // CPU arch attributes include page attributes and cache attributes.
+ // Only page attributes supports to be cleared, but not cache attributes.
+ // Caller is expected to use GetMemorySpaceDescriptor() to get the current
+ // attributes, AND/OR attributes, and then calls SetMemorySpaceAttributes()
+ // to set the new attributes.
+ // So 0 CPU arch attributes should not happen as memory should always have
+ // a cache attribute (no matter UC or WB, etc).
+ //
+ // Here, 0 CPU arch attributes will be filtered to be compatible with the
+ // case that caller just calls SetMemorySpaceAttributes() with none CPU
+ // arch attributes (for example, RUNTIME) as the purpose of the case is not
+ // to clear CPU arch attributes.
+ //
+ if (CpuArchAttributes != 0) {
+ if (gCpu == NULL) {
+ Status = EFI_NOT_AVAILABLE_YET;
+ } else {
+ Status = gCpu->SetMemoryAttributes (
+ gCpu,
+ BaseAddress,
+ Length,
+ CpuArchAttributes
+ );
+ }
+
+ if (EFI_ERROR (Status)) {
+ CoreFreePool (TopEntry);
+ CoreFreePool (BottomEntry);
+ goto Done;
+ }
+ }
+ }
+
+ //
+ // Convert/Insert the list of descriptors from StartLink to EndLink
+ //
+ Link = StartLink;
+ while (Link != EndLink->ForwardLink) {
+ Entry = CR (Link, EFI_GCD_MAP_ENTRY, Link, EFI_GCD_MAP_SIGNATURE);
+ CoreInsertGcdMapEntry (Link, Entry, BaseAddress, Length, TopEntry, BottomEntry);
+ switch (Operation) {
+ //
+ // Add operations
+ //
+ case GCD_ADD_MEMORY_OPERATION:
+ Entry->GcdMemoryType = GcdMemoryType;
+ if (GcdMemoryType == EfiGcdMemoryTypeMemoryMappedIo) {
+ Entry->Capabilities = Capabilities | EFI_MEMORY_RUNTIME | EFI_MEMORY_PORT_IO;
+ } else {
+ Entry->Capabilities = Capabilities | EFI_MEMORY_RUNTIME;
+ }
+
+ break;
+ case GCD_ADD_IO_OPERATION:
+ Entry->GcdIoType = GcdIoType;
+ break;
+ //
+ // Free operations
+ //
+ case GCD_FREE_MEMORY_OPERATION:
+ case GCD_FREE_IO_OPERATION:
+ Entry->ImageHandle = NULL;
+ Entry->DeviceHandle = NULL;
+ break;
+ //
+ // Remove operations
+ //
+ case GCD_REMOVE_MEMORY_OPERATION:
+ Entry->GcdMemoryType = EfiGcdMemoryTypeNonExistent;
+ Entry->Capabilities = 0;
+ break;
+ case GCD_REMOVE_IO_OPERATION:
+ Entry->GcdIoType = EfiGcdIoTypeNonExistent;
+ break;
+ //
+ // Set attributes operation
+ //
+ case GCD_SET_ATTRIBUTES_MEMORY_OPERATION:
+ if (CpuArchAttributes == 0) {
+ //
+ // Keep original CPU arch attributes when caller just calls
+ // SetMemorySpaceAttributes() with none CPU arch attributes (for example, RUNTIME).
+ //
+ Attributes |= (Entry->Attributes & (EFI_CACHE_ATTRIBUTE_MASK | EFI_MEMORY_ATTRIBUTE_MASK));
+ }
+
+ Entry->Attributes = Attributes;
+ break;
+ //
+ // Set capabilities operation
+ //
+ case GCD_SET_CAPABILITIES_MEMORY_OPERATION:
+ Entry->Capabilities = Capabilities;
+ break;
+ }
+
+ Link = Link->ForwardLink;
+ }
+
+ //
+ // Cleanup
+ //
+ Status = CoreCleanupGcdMapEntry (TopEntry, BottomEntry, StartLink, EndLink, Map);
+
+Done:
+ DEBUG ((DEBUG_GCD, " Status = %r\n", Status));
+
+ if ((Operation & GCD_MEMORY_SPACE_OPERATION) != 0) {
+ CoreReleaseGcdMemoryLock ();
+ CoreDumpGcdMemorySpaceMap (FALSE);
+ }
+
+ if ((Operation & GCD_IO_SPACE_OPERATION) != 0) {
+ CoreReleaseGcdIoLock ();
+ CoreDumpGcdIoSpaceMap (FALSE);
+ }
+
+ return Status;
+}
+
+/**
+ Check whether an entry could be used to allocate space.
+
+ @param Operation Allocate memory or IO
+ @param Entry The entry to be tested
+ @param GcdMemoryType The desired memory type
+ @param GcdIoType The desired IO type
+
+ @retval EFI_NOT_FOUND The memory type does not match or there's an
+ image handle on the entry.
+ @retval EFI_UNSUPPORTED The operation unsupported.
+ @retval EFI_SUCCESS It's ok for this entry to be used to allocate
+ space.
+
+**/
+EFI_STATUS
+CoreAllocateSpaceCheckEntry (
+ IN UINTN Operation,
+ IN EFI_GCD_MAP_ENTRY *Entry,
+ IN EFI_GCD_MEMORY_TYPE GcdMemoryType,
+ IN EFI_GCD_IO_TYPE GcdIoType
+ )
+{
+ if (Entry->ImageHandle != NULL) {
+ return EFI_NOT_FOUND;
+ }
+
+ switch (Operation) {
+ case GCD_ALLOCATE_MEMORY_OPERATION:
+ if (Entry->GcdMemoryType != GcdMemoryType) {
+ return EFI_NOT_FOUND;
+ }
+
+ break;
+ case GCD_ALLOCATE_IO_OPERATION:
+ if (Entry->GcdIoType != GcdIoType) {
+ return EFI_NOT_FOUND;
+ }
+
+ break;
+ default:
+ return EFI_UNSUPPORTED;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Allocate space on specified address and length.
+
+ @param Operation The type of operation (memory or IO)
+ @param GcdAllocateType The type of allocate operation
+ @param GcdMemoryType The desired memory type
+ @param GcdIoType The desired IO type
+ @param Alignment Align with 2^Alignment
+ @param Length Length to allocate
+ @param BaseAddress Base address to allocate
+ @param ImageHandle The image handle consume the allocated space.
+ @param DeviceHandle The device handle consume the allocated space.
+
+ @retval EFI_INVALID_PARAMETER Invalid parameter.
+ @retval EFI_NOT_FOUND No descriptor for the desired space exists.
+ @retval EFI_SUCCESS Space successfully allocated.
+
+**/
+EFI_STATUS
+CoreAllocateSpace (
+ IN UINTN Operation,
+ IN EFI_GCD_ALLOCATE_TYPE GcdAllocateType,
+ IN EFI_GCD_MEMORY_TYPE GcdMemoryType,
+ IN EFI_GCD_IO_TYPE GcdIoType,
+ IN UINTN Alignment,
+ IN UINT64 Length,
+ IN OUT EFI_PHYSICAL_ADDRESS *BaseAddress,
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_HANDLE DeviceHandle OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+ EFI_PHYSICAL_ADDRESS AlignmentMask;
+ EFI_PHYSICAL_ADDRESS MaxAddress;
+ LIST_ENTRY *Map;
+ LIST_ENTRY *Link;
+ LIST_ENTRY *SubLink;
+ EFI_GCD_MAP_ENTRY *Entry;
+ EFI_GCD_MAP_ENTRY *TopEntry;
+ EFI_GCD_MAP_ENTRY *BottomEntry;
+ LIST_ENTRY *StartLink;
+ LIST_ENTRY *EndLink;
+ BOOLEAN Found;
+
+ //
+ // Make sure parameters are valid
+ //
+ if ((UINT32)GcdAllocateType >= EfiGcdMaxAllocateType) {
+ DEBUG ((DEBUG_GCD, " Status = %r\n", EFI_INVALID_PARAMETER));
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if ((UINT32)GcdMemoryType >= EfiGcdMemoryTypeMaximum) {
+ DEBUG ((DEBUG_GCD, " Status = %r\n", EFI_INVALID_PARAMETER));
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if ((UINT32)GcdIoType >= EfiGcdIoTypeMaximum) {
+ DEBUG ((DEBUG_GCD, " Status = %r\n", EFI_INVALID_PARAMETER));
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (BaseAddress == NULL) {
+ DEBUG ((DEBUG_GCD, " Status = %r\n", EFI_INVALID_PARAMETER));
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (ImageHandle == NULL) {
+ DEBUG ((DEBUG_GCD, " Status = %r\n", EFI_INVALID_PARAMETER));
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (Alignment >= 64) {
+ DEBUG ((DEBUG_GCD, " Status = %r\n", EFI_NOT_FOUND));
+ return EFI_NOT_FOUND;
+ }
+
+ if (Length == 0) {
+ DEBUG ((DEBUG_GCD, " Status = %r\n", EFI_INVALID_PARAMETER));
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Map = NULL;
+ if ((Operation & GCD_MEMORY_SPACE_OPERATION) != 0) {
+ CoreAcquireGcdMemoryLock ();
+ Map = &mGcdMemorySpaceMap;
+ } else if ((Operation & GCD_IO_SPACE_OPERATION) != 0) {
+ CoreAcquireGcdIoLock ();
+ Map = &mGcdIoSpaceMap;
+ } else {
+ ASSERT (FALSE);
+ }
+
+ Found = FALSE;
+ StartLink = NULL;
+ EndLink = NULL;
+ //
+ // Compute alignment bit mask
+ //
+ AlignmentMask = LShiftU64 (1, Alignment) - 1;
+
+ if (GcdAllocateType == EfiGcdAllocateAddress) {
+ //
+ // Verify that the BaseAddress passed in is aligned correctly
+ //
+ if ((*BaseAddress & AlignmentMask) != 0) {
+ Status = EFI_NOT_FOUND;
+ goto Done;
+ }
+
+ //
+ // Search for the list of descriptors that cover the range BaseAddress to BaseAddress+Length
+ //
+ Status = CoreSearchGcdMapEntry (*BaseAddress, Length, &StartLink, &EndLink, Map);
+ if (EFI_ERROR (Status)) {
+ Status = EFI_NOT_FOUND;
+ goto Done;
+ }
+
+ ASSERT (StartLink != NULL && EndLink != NULL);
+
+ //
+ // Verify that the list of descriptors are unallocated memory matching GcdMemoryType.
+ //
+ Link = StartLink;
+ while (Link != EndLink->ForwardLink) {
+ Entry = CR (Link, EFI_GCD_MAP_ENTRY, Link, EFI_GCD_MAP_SIGNATURE);
+ Link = Link->ForwardLink;
+ Status = CoreAllocateSpaceCheckEntry (Operation, Entry, GcdMemoryType, GcdIoType);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+ }
+
+ Found = TRUE;
+ } else {
+ Entry = CR (Map->BackLink, EFI_GCD_MAP_ENTRY, Link, EFI_GCD_MAP_SIGNATURE);
+
+ //
+ // Compute the maximum address to use in the search algorithm
+ //
+ if ((GcdAllocateType == EfiGcdAllocateMaxAddressSearchBottomUp) ||
+ (GcdAllocateType == EfiGcdAllocateMaxAddressSearchTopDown))
+ {
+ MaxAddress = *BaseAddress;
+ } else {
+ MaxAddress = Entry->EndAddress;
+ }
+
+ //
+ // Verify that the list of descriptors are unallocated memory matching GcdMemoryType.
+ //
+ if ((GcdAllocateType == EfiGcdAllocateMaxAddressSearchTopDown) ||
+ (GcdAllocateType == EfiGcdAllocateAnySearchTopDown))
+ {
+ Link = Map->BackLink;
+ } else {
+ Link = Map->ForwardLink;
+ }
+
+ while (Link != Map) {
+ Entry = CR (Link, EFI_GCD_MAP_ENTRY, Link, EFI_GCD_MAP_SIGNATURE);
+
+ if ((GcdAllocateType == EfiGcdAllocateMaxAddressSearchTopDown) ||
+ (GcdAllocateType == EfiGcdAllocateAnySearchTopDown))
+ {
+ Link = Link->BackLink;
+ } else {
+ Link = Link->ForwardLink;
+ }
+
+ Status = CoreAllocateSpaceCheckEntry (Operation, Entry, GcdMemoryType, GcdIoType);
+ if (EFI_ERROR (Status)) {
+ continue;
+ }
+
+ if ((GcdAllocateType == EfiGcdAllocateMaxAddressSearchTopDown) ||
+ (GcdAllocateType == EfiGcdAllocateAnySearchTopDown))
+ {
+ if ((Entry->BaseAddress + Length) > MaxAddress) {
+ continue;
+ }
+
+ if (Length > (Entry->EndAddress + 1)) {
+ Status = EFI_NOT_FOUND;
+ goto Done;
+ }
+
+ if (Entry->EndAddress > MaxAddress) {
+ *BaseAddress = MaxAddress;
+ } else {
+ *BaseAddress = Entry->EndAddress;
+ }
+
+ *BaseAddress = (*BaseAddress + 1 - Length) & (~AlignmentMask);
+ } else {
+ *BaseAddress = (Entry->BaseAddress + AlignmentMask) & (~AlignmentMask);
+ if ((*BaseAddress + Length - 1) > MaxAddress) {
+ Status = EFI_NOT_FOUND;
+ goto Done;
+ }
+ }
+
+ //
+ // Search for the list of descriptors that cover the range BaseAddress to BaseAddress+Length
+ //
+ Status = CoreSearchGcdMapEntry (*BaseAddress, Length, &StartLink, &EndLink, Map);
+ if (EFI_ERROR (Status)) {
+ Status = EFI_NOT_FOUND;
+ goto Done;
+ }
+
+ ASSERT (StartLink != NULL && EndLink != NULL);
+
+ Link = StartLink;
+ //
+ // Verify that the list of descriptors are unallocated memory matching GcdMemoryType.
+ //
+ Found = TRUE;
+ SubLink = StartLink;
+ while (SubLink != EndLink->ForwardLink) {
+ Entry = CR (SubLink, EFI_GCD_MAP_ENTRY, Link, EFI_GCD_MAP_SIGNATURE);
+ Status = CoreAllocateSpaceCheckEntry (Operation, Entry, GcdMemoryType, GcdIoType);
+ if (EFI_ERROR (Status)) {
+ Link = SubLink;
+ Found = FALSE;
+ break;
+ }
+
+ SubLink = SubLink->ForwardLink;
+ }
+
+ if (Found) {
+ break;
+ }
+ }
+ }
+
+ if (!Found) {
+ Status = EFI_NOT_FOUND;
+ goto Done;
+ }
+
+ //
+ // Allocate work space to perform this operation
+ //
+ Status = CoreAllocateGcdMapEntry (&TopEntry, &BottomEntry);
+ if (EFI_ERROR (Status)) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Done;
+ }
+
+ ASSERT (TopEntry != NULL && BottomEntry != NULL);
+
+ //
+ // Convert/Insert the list of descriptors from StartLink to EndLink
+ //
+ Link = StartLink;
+ while (Link != EndLink->ForwardLink) {
+ Entry = CR (Link, EFI_GCD_MAP_ENTRY, Link, EFI_GCD_MAP_SIGNATURE);
+ CoreInsertGcdMapEntry (Link, Entry, *BaseAddress, Length, TopEntry, BottomEntry);
+ Entry->ImageHandle = ImageHandle;
+ Entry->DeviceHandle = DeviceHandle;
+ Link = Link->ForwardLink;
+ }
+
+ //
+ // Cleanup
+ //
+ Status = CoreCleanupGcdMapEntry (TopEntry, BottomEntry, StartLink, EndLink, Map);
+
+Done:
+ DEBUG ((DEBUG_GCD, " Status = %r", Status));
+ if (!EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_GCD, " (BaseAddress = %016lx)", *BaseAddress));
+ }
+
+ DEBUG ((DEBUG_GCD, "\n"));
+
+ if ((Operation & GCD_MEMORY_SPACE_OPERATION) != 0) {
+ CoreReleaseGcdMemoryLock ();
+ CoreDumpGcdMemorySpaceMap (FALSE);
+ }
+
+ if ((Operation & GCD_IO_SPACE_OPERATION) != 0) {
+ CoreReleaseGcdIoLock ();
+ CoreDumpGcdIoSpaceMap (FALSE);
+ }
+
+ return Status;
+}
+
+/**
+ Add a segment of memory to GCD map.
+
+ @param GcdMemoryType Memory type of the segment.
+ @param BaseAddress Base address of the segment.
+ @param Length Length of the segment.
+ @param Capabilities alterable attributes of the segment.
+
+ @retval EFI_INVALID_PARAMETER Invalid parameters.
+ @retval EFI_SUCCESS Successfully add a segment of memory space.
+
+**/
+EFI_STATUS
+CoreInternalAddMemorySpace (
+ IN EFI_GCD_MEMORY_TYPE GcdMemoryType,
+ IN EFI_PHYSICAL_ADDRESS BaseAddress,
+ IN UINT64 Length,
+ IN UINT64 Capabilities
+ )
+{
+ DEBUG ((DEBUG_GCD, "GCD:AddMemorySpace(Base=%016lx,Length=%016lx)\n", BaseAddress, Length));
+ DEBUG ((DEBUG_GCD, " GcdMemoryType = %a\n", mGcdMemoryTypeNames[MIN (GcdMemoryType, EfiGcdMemoryTypeMaximum)]));
+ DEBUG ((DEBUG_GCD, " Capabilities = %016lx\n", Capabilities));
+
+ //
+ // Make sure parameters are valid
+ //
+ if ((GcdMemoryType <= EfiGcdMemoryTypeNonExistent) || (GcdMemoryType >= EfiGcdMemoryTypeMaximum)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ return CoreConvertSpace (GCD_ADD_MEMORY_OPERATION, GcdMemoryType, (EFI_GCD_IO_TYPE)0, BaseAddress, Length, Capabilities, 0);
+}
+
+//
+// GCD Core Services
+//
+
+/**
+ Allocates nonexistent memory, reserved memory, system memory, or memorymapped
+ I/O resources from the global coherency domain of the processor.
+
+ @param GcdAllocateType The type of allocate operation
+ @param GcdMemoryType The desired memory type
+ @param Alignment Align with 2^Alignment
+ @param Length Length to allocate
+ @param BaseAddress Base address to allocate
+ @param ImageHandle The image handle consume the allocated space.
+ @param DeviceHandle The device handle consume the allocated space.
+
+ @retval EFI_INVALID_PARAMETER Invalid parameter.
+ @retval EFI_NOT_FOUND No descriptor contains the desired space.
+ @retval EFI_SUCCESS Memory space successfully allocated.
+
+**/
+EFI_STATUS
+EFIAPI
+CoreAllocateMemorySpace (
+ IN EFI_GCD_ALLOCATE_TYPE GcdAllocateType,
+ IN EFI_GCD_MEMORY_TYPE GcdMemoryType,
+ IN UINTN Alignment,
+ IN UINT64 Length,
+ IN OUT EFI_PHYSICAL_ADDRESS *BaseAddress,
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_HANDLE DeviceHandle OPTIONAL
+ )
+{
+ if (BaseAddress != NULL) {
+ DEBUG ((DEBUG_GCD, "GCD:AllocateMemorySpace(Base=%016lx,Length=%016lx)\n", *BaseAddress, Length));
+ } else {
+ DEBUG ((DEBUG_GCD, "GCD:AllocateMemorySpace(Base=<NULL>,Length=%016lx)\n", Length));
+ }
+
+ DEBUG ((DEBUG_GCD, " GcdAllocateType = %a\n", mGcdAllocationTypeNames[MIN (GcdAllocateType, EfiGcdMaxAllocateType)]));
+ DEBUG ((DEBUG_GCD, " GcdMemoryType = %a\n", mGcdMemoryTypeNames[MIN (GcdMemoryType, EfiGcdMemoryTypeMaximum)]));
+ DEBUG ((DEBUG_GCD, " Alignment = %016lx\n", LShiftU64 (1, Alignment)));
+ DEBUG ((DEBUG_GCD, " ImageHandle = %p\n", ImageHandle));
+ DEBUG ((DEBUG_GCD, " DeviceHandle = %p\n", DeviceHandle));
+
+ return CoreAllocateSpace (
+ GCD_ALLOCATE_MEMORY_OPERATION,
+ GcdAllocateType,
+ GcdMemoryType,
+ (EFI_GCD_IO_TYPE)0,
+ Alignment,
+ Length,
+ BaseAddress,
+ ImageHandle,
+ DeviceHandle
+ );
+}
+
+/**
+ Adds reserved memory, system memory, or memory-mapped I/O resources to the
+ global coherency domain of the processor.
+
+ @param GcdMemoryType Memory type of the memory space.
+ @param BaseAddress Base address of the memory space.
+ @param Length Length of the memory space.
+ @param Capabilities alterable attributes of the memory space.
+
+ @retval EFI_SUCCESS Merged this memory space into GCD map.
+
+**/
+EFI_STATUS
+EFIAPI
+CoreAddMemorySpace (
+ IN EFI_GCD_MEMORY_TYPE GcdMemoryType,
+ IN EFI_PHYSICAL_ADDRESS BaseAddress,
+ IN UINT64 Length,
+ IN UINT64 Capabilities
+ )
+{
+ EFI_STATUS Status;
+ EFI_PHYSICAL_ADDRESS PageBaseAddress;
+ UINT64 PageLength;
+
+ Status = CoreInternalAddMemorySpace (GcdMemoryType, BaseAddress, Length, Capabilities);
+
+ if (!EFI_ERROR (Status) && ((GcdMemoryType == EfiGcdMemoryTypeSystemMemory) || (GcdMemoryType == EfiGcdMemoryTypeMoreReliable))) {
+ PageBaseAddress = PageAlignAddress (BaseAddress);
+ PageLength = PageAlignLength (BaseAddress + Length - PageBaseAddress);
+
+ Status = CoreAllocateMemorySpace (
+ EfiGcdAllocateAddress,
+ GcdMemoryType,
+ EFI_PAGE_SHIFT,
+ PageLength,
+ &PageBaseAddress,
+ gDxeCoreImageHandle,
+ NULL
+ );
+
+ if (!EFI_ERROR (Status)) {
+ CoreAddMemoryDescriptor (
+ EfiConventionalMemory,
+ PageBaseAddress,
+ RShiftU64 (PageLength, EFI_PAGE_SHIFT),
+ Capabilities
+ );
+ } else {
+ for ( ; PageLength != 0; PageLength -= EFI_PAGE_SIZE, PageBaseAddress += EFI_PAGE_SIZE) {
+ Status = CoreAllocateMemorySpace (
+ EfiGcdAllocateAddress,
+ GcdMemoryType,
+ EFI_PAGE_SHIFT,
+ EFI_PAGE_SIZE,
+ &PageBaseAddress,
+ gDxeCoreImageHandle,
+ NULL
+ );
+
+ if (!EFI_ERROR (Status)) {
+ CoreAddMemoryDescriptor (
+ EfiConventionalMemory,
+ PageBaseAddress,
+ 1,
+ Capabilities
+ );
+ }
+ }
+ }
+ }
+
+ return Status;
+}
+
+/**
+ Frees nonexistent memory, reserved memory, system memory, or memory-mapped
+ I/O resources from the global coherency domain of the processor.
+
+ @param BaseAddress Base address of the memory space.
+ @param Length Length of the memory space.
+
+ @retval EFI_SUCCESS Space successfully freed.
+
+**/
+EFI_STATUS
+EFIAPI
+CoreFreeMemorySpace (
+ IN EFI_PHYSICAL_ADDRESS BaseAddress,
+ IN UINT64 Length
+ )
+{
+ DEBUG ((DEBUG_GCD, "GCD:FreeMemorySpace(Base=%016lx,Length=%016lx)\n", BaseAddress, Length));
+
+ return CoreConvertSpace (GCD_FREE_MEMORY_OPERATION, (EFI_GCD_MEMORY_TYPE)0, (EFI_GCD_IO_TYPE)0, BaseAddress, Length, 0, 0);
+}
+
+/**
+ Removes reserved memory, system memory, or memory-mapped I/O resources from
+ the global coherency domain of the processor.
+
+ @param BaseAddress Base address of the memory space.
+ @param Length Length of the memory space.
+
+ @retval EFI_SUCCESS Successfully remove a segment of memory space.
+
+**/
+EFI_STATUS
+EFIAPI
+CoreRemoveMemorySpace (
+ IN EFI_PHYSICAL_ADDRESS BaseAddress,
+ IN UINT64 Length
+ )
+{
+ DEBUG ((DEBUG_GCD, "GCD:RemoveMemorySpace(Base=%016lx,Length=%016lx)\n", BaseAddress, Length));
+
+ return CoreConvertSpace (GCD_REMOVE_MEMORY_OPERATION, (EFI_GCD_MEMORY_TYPE)0, (EFI_GCD_IO_TYPE)0, BaseAddress, Length, 0, 0);
+}
+
+/**
+ Build a memory descriptor according to an entry.
+
+ @param Descriptor The descriptor to be built
+ @param Entry According to this entry
+
+**/
+VOID
+BuildMemoryDescriptor (
+ IN OUT EFI_GCD_MEMORY_SPACE_DESCRIPTOR *Descriptor,
+ IN EFI_GCD_MAP_ENTRY *Entry
+ )
+{
+ Descriptor->BaseAddress = Entry->BaseAddress;
+ Descriptor->Length = Entry->EndAddress - Entry->BaseAddress + 1;
+ Descriptor->Capabilities = Entry->Capabilities;
+ Descriptor->Attributes = Entry->Attributes;
+ Descriptor->GcdMemoryType = Entry->GcdMemoryType;
+ Descriptor->ImageHandle = Entry->ImageHandle;
+ Descriptor->DeviceHandle = Entry->DeviceHandle;
+}
+
+/**
+ Retrieves the descriptor for a memory region containing a specified address.
+
+ @param BaseAddress Specified start address
+ @param Descriptor Specified length
+
+ @retval EFI_INVALID_PARAMETER Invalid parameter
+ @retval EFI_SUCCESS Successfully get memory space descriptor.
+
+**/
+EFI_STATUS
+EFIAPI
+CoreGetMemorySpaceDescriptor (
+ IN EFI_PHYSICAL_ADDRESS BaseAddress,
+ OUT EFI_GCD_MEMORY_SPACE_DESCRIPTOR *Descriptor
+ )
+{
+ EFI_STATUS Status;
+ LIST_ENTRY *StartLink;
+ LIST_ENTRY *EndLink;
+ EFI_GCD_MAP_ENTRY *Entry;
+
+ //
+ // Make sure parameters are valid
+ //
+ if (Descriptor == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ CoreAcquireGcdMemoryLock ();
+
+ //
+ // Search for the list of descriptors that contain BaseAddress
+ //
+ Status = CoreSearchGcdMapEntry (BaseAddress, 1, &StartLink, &EndLink, &mGcdMemorySpaceMap);
+ if (EFI_ERROR (Status)) {
+ Status = EFI_NOT_FOUND;
+ } else {
+ ASSERT (StartLink != NULL && EndLink != NULL);
+ //
+ // Copy the contents of the found descriptor into Descriptor
+ //
+ Entry = CR (StartLink, EFI_GCD_MAP_ENTRY, Link, EFI_GCD_MAP_SIGNATURE);
+ BuildMemoryDescriptor (Descriptor, Entry);
+ }
+
+ CoreReleaseGcdMemoryLock ();
+
+ return Status;
+}
+
+/**
+ Modifies the attributes for a memory region in the global coherency domain of the
+ processor.
+
+ @param BaseAddress Specified start address
+ @param Length Specified length
+ @param Attributes Specified attributes
+
+ @retval EFI_SUCCESS The attributes were set for the memory region.
+ @retval EFI_INVALID_PARAMETER Length is zero.
+ @retval EFI_UNSUPPORTED The processor does not support one or more bytes of the memory
+ resource range specified by BaseAddress and Length.
+ @retval EFI_UNSUPPORTED The bit mask of attributes is not support for the memory resource
+ range specified by BaseAddress and Length.
+ @retval EFI_ACCESS_DEFINED The attributes for the memory resource range specified by
+ BaseAddress and Length cannot be modified.
+ @retval EFI_OUT_OF_RESOURCES There are not enough system resources to modify the attributes of
+ the memory resource range.
+ @retval EFI_NOT_AVAILABLE_YET The attributes cannot be set because CPU architectural protocol is
+ not available yet.
+
+**/
+EFI_STATUS
+EFIAPI
+CoreSetMemorySpaceAttributes (
+ IN EFI_PHYSICAL_ADDRESS BaseAddress,
+ IN UINT64 Length,
+ IN UINT64 Attributes
+ )
+{
+ DEBUG ((DEBUG_GCD, "GCD:SetMemorySpaceAttributes(Base=%016lx,Length=%016lx)\n", BaseAddress, Length));
+ DEBUG ((DEBUG_GCD, " Attributes = %016lx\n", Attributes));
+
+ return CoreConvertSpace (GCD_SET_ATTRIBUTES_MEMORY_OPERATION, (EFI_GCD_MEMORY_TYPE)0, (EFI_GCD_IO_TYPE)0, BaseAddress, Length, 0, Attributes);
+}
+
+/**
+ Modifies the capabilities for a memory region in the global coherency domain of the
+ processor.
+
+ @param BaseAddress The physical address that is the start address of a memory region.
+ @param Length The size in bytes of the memory region.
+ @param Capabilities The bit mask of capabilities that the memory region supports.
+
+ @retval EFI_SUCCESS The capabilities were set for the memory region.
+ @retval EFI_INVALID_PARAMETER Length is zero.
+ @retval EFI_UNSUPPORTED The capabilities specified by Capabilities do not include the
+ memory region attributes currently in use.
+ @retval EFI_ACCESS_DENIED The capabilities for the memory resource range specified by
+ BaseAddress and Length cannot be modified.
+ @retval EFI_OUT_OF_RESOURCES There are not enough system resources to modify the capabilities
+ of the memory resource range.
+**/
+EFI_STATUS
+EFIAPI
+CoreSetMemorySpaceCapabilities (
+ IN EFI_PHYSICAL_ADDRESS BaseAddress,
+ IN UINT64 Length,
+ IN UINT64 Capabilities
+ )
+{
+ EFI_STATUS Status;
+
+ DEBUG ((DEBUG_GCD, "GCD:CoreSetMemorySpaceCapabilities(Base=%016lx,Length=%016lx)\n", BaseAddress, Length));
+ DEBUG ((DEBUG_GCD, " Capabilities = %016lx\n", Capabilities));
+
+ Status = CoreConvertSpace (GCD_SET_CAPABILITIES_MEMORY_OPERATION, (EFI_GCD_MEMORY_TYPE)0, (EFI_GCD_IO_TYPE)0, BaseAddress, Length, Capabilities, 0);
+ if (!EFI_ERROR (Status)) {
+ CoreUpdateMemoryAttributes (BaseAddress, RShiftU64 (Length, EFI_PAGE_SHIFT), Capabilities & (~EFI_MEMORY_RUNTIME));
+ }
+
+ return Status;
+}
+
+/**
+ Returns a map of the memory resources in the global coherency domain of the
+ processor.
+
+ @param NumberOfDescriptors Number of descriptors.
+ @param MemorySpaceMap Descriptor array
+
+ @retval EFI_INVALID_PARAMETER Invalid parameter
+ @retval EFI_OUT_OF_RESOURCES No enough buffer to allocate
+ @retval EFI_SUCCESS Successfully get memory space map.
+
+**/
+EFI_STATUS
+EFIAPI
+CoreGetMemorySpaceMap (
+ OUT UINTN *NumberOfDescriptors,
+ OUT EFI_GCD_MEMORY_SPACE_DESCRIPTOR **MemorySpaceMap
+ )
+{
+ LIST_ENTRY *Link;
+ EFI_GCD_MAP_ENTRY *Entry;
+ EFI_GCD_MEMORY_SPACE_DESCRIPTOR *Descriptor;
+ UINTN DescriptorCount;
+
+ //
+ // Make sure parameters are valid
+ //
+ if (NumberOfDescriptors == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (MemorySpaceMap == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ *NumberOfDescriptors = 0;
+ *MemorySpaceMap = NULL;
+
+ //
+ // Take the lock, for entering the loop with the lock held.
+ //
+ CoreAcquireGcdMemoryLock ();
+ while (TRUE) {
+ //
+ // Count descriptors. It might be done more than once because the
+ // AllocatePool() called below has to be running outside the GCD lock.
+ //
+ DescriptorCount = CoreCountGcdMapEntry (&mGcdMemorySpaceMap);
+ if ((DescriptorCount == *NumberOfDescriptors) && (*MemorySpaceMap != NULL)) {
+ //
+ // Fill in the MemorySpaceMap if no memory space map change.
+ //
+ Descriptor = *MemorySpaceMap;
+ Link = mGcdMemorySpaceMap.ForwardLink;
+ while (Link != &mGcdMemorySpaceMap) {
+ Entry = CR (Link, EFI_GCD_MAP_ENTRY, Link, EFI_GCD_MAP_SIGNATURE);
+ BuildMemoryDescriptor (Descriptor, Entry);
+ Descriptor++;
+ Link = Link->ForwardLink;
+ }
+
+ //
+ // We're done; exit the loop with the lock held.
+ //
+ break;
+ }
+
+ //
+ // Release the lock before memory allocation, because it might cause
+ // GCD lock conflict in one of calling path in AllocatPool().
+ //
+ CoreReleaseGcdMemoryLock ();
+
+ //
+ // Allocate memory to store the MemorySpaceMap. Note it might be already
+ // allocated if there's map descriptor change during memory allocation at
+ // last time.
+ //
+ if (*MemorySpaceMap != NULL) {
+ FreePool (*MemorySpaceMap);
+ }
+
+ *MemorySpaceMap = AllocatePool (
+ DescriptorCount *
+ sizeof (EFI_GCD_MEMORY_SPACE_DESCRIPTOR)
+ );
+ if (*MemorySpaceMap == NULL) {
+ *NumberOfDescriptors = 0;
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ //
+ // Save the descriptor count got before for another round of check to make
+ // sure we won't miss any, since we have code running outside the GCD lock.
+ //
+ *NumberOfDescriptors = DescriptorCount;
+ //
+ // Re-acquire the lock, for the next iteration.
+ //
+ CoreAcquireGcdMemoryLock ();
+ }
+
+ //
+ // We exited the loop with the lock held, release it.
+ //
+ CoreReleaseGcdMemoryLock ();
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Adds reserved I/O or I/O resources to the global coherency domain of the processor.
+
+ @param GcdIoType IO type of the segment.
+ @param BaseAddress Base address of the segment.
+ @param Length Length of the segment.
+
+ @retval EFI_SUCCESS Merged this segment into GCD map.
+ @retval EFI_INVALID_PARAMETER Parameter not valid
+
+**/
+EFI_STATUS
+EFIAPI
+CoreAddIoSpace (
+ IN EFI_GCD_IO_TYPE GcdIoType,
+ IN EFI_PHYSICAL_ADDRESS BaseAddress,
+ IN UINT64 Length
+ )
+{
+ DEBUG ((DEBUG_GCD, "GCD:AddIoSpace(Base=%016lx,Length=%016lx)\n", BaseAddress, Length));
+ DEBUG ((DEBUG_GCD, " GcdIoType = %a\n", mGcdIoTypeNames[MIN (GcdIoType, EfiGcdIoTypeMaximum)]));
+
+ //
+ // Make sure parameters are valid
+ //
+ if ((GcdIoType <= EfiGcdIoTypeNonExistent) || (GcdIoType >= EfiGcdIoTypeMaximum)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ return CoreConvertSpace (GCD_ADD_IO_OPERATION, (EFI_GCD_MEMORY_TYPE)0, GcdIoType, BaseAddress, Length, 0, 0);
+}
+
+/**
+ Allocates nonexistent I/O, reserved I/O, or I/O resources from the global coherency
+ domain of the processor.
+
+ @param GcdAllocateType The type of allocate operation
+ @param GcdIoType The desired IO type
+ @param Alignment Align with 2^Alignment
+ @param Length Length to allocate
+ @param BaseAddress Base address to allocate
+ @param ImageHandle The image handle consume the allocated space.
+ @param DeviceHandle The device handle consume the allocated space.
+
+ @retval EFI_INVALID_PARAMETER Invalid parameter.
+ @retval EFI_NOT_FOUND No descriptor contains the desired space.
+ @retval EFI_SUCCESS IO space successfully allocated.
+
+**/
+EFI_STATUS
+EFIAPI
+CoreAllocateIoSpace (
+ IN EFI_GCD_ALLOCATE_TYPE GcdAllocateType,
+ IN EFI_GCD_IO_TYPE GcdIoType,
+ IN UINTN Alignment,
+ IN UINT64 Length,
+ IN OUT EFI_PHYSICAL_ADDRESS *BaseAddress,
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_HANDLE DeviceHandle OPTIONAL
+ )
+{
+ if (BaseAddress != NULL) {
+ DEBUG ((DEBUG_GCD, "GCD:AllocateIoSpace(Base=%016lx,Length=%016lx)\n", *BaseAddress, Length));
+ } else {
+ DEBUG ((DEBUG_GCD, "GCD:AllocateIoSpace(Base=<NULL>,Length=%016lx)\n", Length));
+ }
+
+ DEBUG ((DEBUG_GCD, " GcdAllocateType = %a\n", mGcdAllocationTypeNames[MIN (GcdAllocateType, EfiGcdMaxAllocateType)]));
+ DEBUG ((DEBUG_GCD, " GcdIoType = %a\n", mGcdIoTypeNames[MIN (GcdIoType, EfiGcdIoTypeMaximum)]));
+ DEBUG ((DEBUG_GCD, " Alignment = %016lx\n", LShiftU64 (1, Alignment)));
+ DEBUG ((DEBUG_GCD, " ImageHandle = %p\n", ImageHandle));
+ DEBUG ((DEBUG_GCD, " DeviceHandle = %p\n", DeviceHandle));
+
+ return CoreAllocateSpace (
+ GCD_ALLOCATE_IO_OPERATION,
+ GcdAllocateType,
+ (EFI_GCD_MEMORY_TYPE)0,
+ GcdIoType,
+ Alignment,
+ Length,
+ BaseAddress,
+ ImageHandle,
+ DeviceHandle
+ );
+}
+
+/**
+ Frees nonexistent I/O, reserved I/O, or I/O resources from the global coherency
+ domain of the processor.
+
+ @param BaseAddress Base address of the segment.
+ @param Length Length of the segment.
+
+ @retval EFI_SUCCESS Space successfully freed.
+
+**/
+EFI_STATUS
+EFIAPI
+CoreFreeIoSpace (
+ IN EFI_PHYSICAL_ADDRESS BaseAddress,
+ IN UINT64 Length
+ )
+{
+ DEBUG ((DEBUG_GCD, "GCD:FreeIoSpace(Base=%016lx,Length=%016lx)\n", BaseAddress, Length));
+
+ return CoreConvertSpace (GCD_FREE_IO_OPERATION, (EFI_GCD_MEMORY_TYPE)0, (EFI_GCD_IO_TYPE)0, BaseAddress, Length, 0, 0);
+}
+
+/**
+ Removes reserved I/O or I/O resources from the global coherency domain of the
+ processor.
+
+ @param BaseAddress Base address of the segment.
+ @param Length Length of the segment.
+
+ @retval EFI_SUCCESS Successfully removed a segment of IO space.
+
+**/
+EFI_STATUS
+EFIAPI
+CoreRemoveIoSpace (
+ IN EFI_PHYSICAL_ADDRESS BaseAddress,
+ IN UINT64 Length
+ )
+{
+ DEBUG ((DEBUG_GCD, "GCD:RemoveIoSpace(Base=%016lx,Length=%016lx)\n", BaseAddress, Length));
+
+ return CoreConvertSpace (GCD_REMOVE_IO_OPERATION, (EFI_GCD_MEMORY_TYPE)0, (EFI_GCD_IO_TYPE)0, BaseAddress, Length, 0, 0);
+}
+
+/**
+ Build a IO descriptor according to an entry.
+
+ @param Descriptor The descriptor to be built
+ @param Entry According to this entry
+
+**/
+VOID
+BuildIoDescriptor (
+ IN EFI_GCD_IO_SPACE_DESCRIPTOR *Descriptor,
+ IN EFI_GCD_MAP_ENTRY *Entry
+ )
+{
+ Descriptor->BaseAddress = Entry->BaseAddress;
+ Descriptor->Length = Entry->EndAddress - Entry->BaseAddress + 1;
+ Descriptor->GcdIoType = Entry->GcdIoType;
+ Descriptor->ImageHandle = Entry->ImageHandle;
+ Descriptor->DeviceHandle = Entry->DeviceHandle;
+}
+
+/**
+ Retrieves the descriptor for an I/O region containing a specified address.
+
+ @param BaseAddress Specified start address
+ @param Descriptor Specified length
+
+ @retval EFI_INVALID_PARAMETER Descriptor is NULL.
+ @retval EFI_SUCCESS Successfully get the IO space descriptor.
+
+**/
+EFI_STATUS
+EFIAPI
+CoreGetIoSpaceDescriptor (
+ IN EFI_PHYSICAL_ADDRESS BaseAddress,
+ OUT EFI_GCD_IO_SPACE_DESCRIPTOR *Descriptor
+ )
+{
+ EFI_STATUS Status;
+ LIST_ENTRY *StartLink;
+ LIST_ENTRY *EndLink;
+ EFI_GCD_MAP_ENTRY *Entry;
+
+ //
+ // Make sure parameters are valid
+ //
+ if (Descriptor == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ CoreAcquireGcdIoLock ();
+
+ //
+ // Search for the list of descriptors that contain BaseAddress
+ //
+ Status = CoreSearchGcdMapEntry (BaseAddress, 1, &StartLink, &EndLink, &mGcdIoSpaceMap);
+ if (EFI_ERROR (Status)) {
+ Status = EFI_NOT_FOUND;
+ } else {
+ ASSERT (StartLink != NULL && EndLink != NULL);
+ //
+ // Copy the contents of the found descriptor into Descriptor
+ //
+ Entry = CR (StartLink, EFI_GCD_MAP_ENTRY, Link, EFI_GCD_MAP_SIGNATURE);
+ BuildIoDescriptor (Descriptor, Entry);
+ }
+
+ CoreReleaseGcdIoLock ();
+
+ return Status;
+}
+
+/**
+ Returns a map of the I/O resources in the global coherency domain of the processor.
+
+ @param NumberOfDescriptors Number of descriptors.
+ @param IoSpaceMap Descriptor array
+
+ @retval EFI_INVALID_PARAMETER Invalid parameter
+ @retval EFI_OUT_OF_RESOURCES No enough buffer to allocate
+ @retval EFI_SUCCESS Successfully get IO space map.
+
+**/
+EFI_STATUS
+EFIAPI
+CoreGetIoSpaceMap (
+ OUT UINTN *NumberOfDescriptors,
+ OUT EFI_GCD_IO_SPACE_DESCRIPTOR **IoSpaceMap
+ )
+{
+ EFI_STATUS Status;
+ LIST_ENTRY *Link;
+ EFI_GCD_MAP_ENTRY *Entry;
+ EFI_GCD_IO_SPACE_DESCRIPTOR *Descriptor;
+
+ //
+ // Make sure parameters are valid
+ //
+ if (NumberOfDescriptors == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (IoSpaceMap == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ CoreAcquireGcdIoLock ();
+
+ //
+ // Count the number of descriptors
+ //
+ *NumberOfDescriptors = CoreCountGcdMapEntry (&mGcdIoSpaceMap);
+
+ //
+ // Allocate the IoSpaceMap
+ //
+ *IoSpaceMap = AllocatePool (*NumberOfDescriptors * sizeof (EFI_GCD_IO_SPACE_DESCRIPTOR));
+ if (*IoSpaceMap == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Done;
+ }
+
+ //
+ // Fill in the IoSpaceMap
+ //
+ Descriptor = *IoSpaceMap;
+ Link = mGcdIoSpaceMap.ForwardLink;
+ while (Link != &mGcdIoSpaceMap) {
+ Entry = CR (Link, EFI_GCD_MAP_ENTRY, Link, EFI_GCD_MAP_SIGNATURE);
+ BuildIoDescriptor (Descriptor, Entry);
+ Descriptor++;
+ Link = Link->ForwardLink;
+ }
+
+ Status = EFI_SUCCESS;
+
+Done:
+ CoreReleaseGcdIoLock ();
+ return Status;
+}
+
+/**
+ Converts a Resource Descriptor HOB attributes mask to an EFI Memory Descriptor
+ capabilities mask
+
+ @param GcdMemoryType Type of resource in the GCD memory map.
+ @param Attributes The attribute mask in the Resource Descriptor
+ HOB.
+
+ @return The capabilities mask for an EFI Memory Descriptor.
+
+**/
+UINT64
+CoreConvertResourceDescriptorHobAttributesToCapabilities (
+ EFI_GCD_MEMORY_TYPE GcdMemoryType,
+ UINT64 Attributes
+ )
+{
+ UINT64 Capabilities;
+ GCD_ATTRIBUTE_CONVERSION_ENTRY *Conversion;
+
+ //
+ // Convert the Resource HOB Attributes to an EFI Memory Capabilities mask
+ //
+ for (Capabilities = 0, Conversion = mAttributeConversionTable; Conversion->Attribute != 0; Conversion++) {
+ if (Conversion->Memory || ((GcdMemoryType != EfiGcdMemoryTypeSystemMemory) && (GcdMemoryType != EfiGcdMemoryTypeMoreReliable))) {
+ if (Attributes & Conversion->Attribute) {
+ Capabilities |= Conversion->Capability;
+ }
+ }
+ }
+
+ return Capabilities;
+}
+
+/**
+ Calculate total memory bin size neeeded.
+
+ @return The total memory bin size neeeded.
+
+**/
+UINT64
+CalculateTotalMemoryBinSizeNeeded (
+ VOID
+ )
+{
+ UINTN Index;
+ UINT64 TotalSize;
+
+ //
+ // Loop through each memory type in the order specified by the gMemoryTypeInformation[] array
+ //
+ TotalSize = 0;
+ for (Index = 0; gMemoryTypeInformation[Index].Type != EfiMaxMemoryType; Index++) {
+ TotalSize += LShiftU64 (gMemoryTypeInformation[Index].NumberOfPages, EFI_PAGE_SHIFT);
+ }
+
+ return TotalSize;
+}
+
+/**
+ Find the largest region in the specified region that is not covered by an existing memory allocation
+
+ @param BaseAddress On input start of the region to check.
+ On output start of the largest free region.
+ @param Length On input size of region to check.
+ On output size of the largest free region.
+ @param MemoryHob Hob pointer for the first memory allocation pointer to check
+**/
+VOID
+FindLargestFreeRegion (
+ IN OUT EFI_PHYSICAL_ADDRESS *BaseAddress,
+ IN OUT UINT64 *Length,
+ IN EFI_HOB_MEMORY_ALLOCATION *MemoryHob
+ )
+{
+ EFI_PHYSICAL_ADDRESS TopAddress;
+ EFI_PHYSICAL_ADDRESS AllocatedTop;
+ EFI_PHYSICAL_ADDRESS LowerBase;
+ UINT64 LowerSize;
+ EFI_PHYSICAL_ADDRESS UpperBase;
+ UINT64 UpperSize;
+
+ TopAddress = *BaseAddress + *Length;
+ while (MemoryHob != NULL) {
+ AllocatedTop = MemoryHob->AllocDescriptor.MemoryBaseAddress + MemoryHob->AllocDescriptor.MemoryLength;
+
+ if ((MemoryHob->AllocDescriptor.MemoryBaseAddress >= *BaseAddress) &&
+ (AllocatedTop <= TopAddress))
+ {
+ LowerBase = *BaseAddress;
+ LowerSize = MemoryHob->AllocDescriptor.MemoryBaseAddress - *BaseAddress;
+ UpperBase = AllocatedTop;
+ UpperSize = TopAddress - AllocatedTop;
+
+ if (LowerSize != 0) {
+ FindLargestFreeRegion (&LowerBase, &LowerSize, (EFI_HOB_MEMORY_ALLOCATION *)GetNextHob (EFI_HOB_TYPE_MEMORY_ALLOCATION, GET_NEXT_HOB (MemoryHob)));
+ }
+
+ if (UpperSize != 0) {
+ FindLargestFreeRegion (&UpperBase, &UpperSize, (EFI_HOB_MEMORY_ALLOCATION *)GetNextHob (EFI_HOB_TYPE_MEMORY_ALLOCATION, GET_NEXT_HOB (MemoryHob)));
+ }
+
+ if (UpperSize >= LowerSize) {
+ *Length = UpperSize;
+ *BaseAddress = UpperBase;
+ } else {
+ *Length = LowerSize;
+ *BaseAddress = LowerBase;
+ }
+
+ return;
+ }
+
+ MemoryHob = GetNextHob (EFI_HOB_TYPE_MEMORY_ALLOCATION, GET_NEXT_HOB (MemoryHob));
+ }
+}
+
+/**
+ External function. Initializes memory services based on the memory
+ descriptor HOBs. This function is responsible for priming the memory
+ map, so memory allocations and resource allocations can be made.
+ The first part of this function can not depend on any memory services
+ until at least one memory descriptor is provided to the memory services.
+
+ @param HobStart The start address of the HOB.
+ @param MemoryBaseAddress Start address of memory region found to init DXE
+ core.
+ @param MemoryLength Length of memory region found to init DXE core.
+
+ @retval EFI_SUCCESS Memory services successfully initialized.
+
+**/
+EFI_STATUS
+CoreInitializeMemoryServices (
+ IN VOID **HobStart,
+ OUT EFI_PHYSICAL_ADDRESS *MemoryBaseAddress,
+ OUT UINT64 *MemoryLength
+ )
+{
+ EFI_PEI_HOB_POINTERS Hob;
+ EFI_MEMORY_TYPE_INFORMATION *EfiMemoryTypeInformation;
+ UINTN DataSize;
+ BOOLEAN Found;
+ EFI_HOB_HANDOFF_INFO_TABLE *PhitHob;
+ EFI_HOB_RESOURCE_DESCRIPTOR *ResourceHob;
+ EFI_HOB_RESOURCE_DESCRIPTOR *PhitResourceHob;
+ EFI_HOB_RESOURCE_DESCRIPTOR *MemoryTypeInformationResourceHob;
+ UINTN Count;
+ EFI_PHYSICAL_ADDRESS BaseAddress;
+ UINT64 Length;
+ UINT64 Attributes;
+ UINT64 Capabilities;
+ EFI_PHYSICAL_ADDRESS TestedMemoryBaseAddress;
+ UINT64 TestedMemoryLength;
+ EFI_PHYSICAL_ADDRESS HighAddress;
+ EFI_HOB_GUID_TYPE *GuidHob;
+ UINT32 ReservedCodePageNumber;
+ UINT64 MinimalMemorySizeNeeded;
+
+ //
+ // Point at the first HOB. This must be the PHIT HOB.
+ //
+ Hob.Raw = *HobStart;
+ ASSERT (GET_HOB_TYPE (Hob) == EFI_HOB_TYPE_HANDOFF);
+
+ //
+ // Initialize the spin locks and maps in the memory services.
+ // Also fill in the memory services into the EFI Boot Services Table
+ //
+ CoreInitializePool ();
+
+ //
+ // Initialize Local Variables
+ //
+ PhitResourceHob = NULL;
+ ResourceHob = NULL;
+ BaseAddress = 0;
+ Length = 0;
+ Attributes = 0;
+
+ //
+ // Cache the PHIT HOB for later use
+ //
+ PhitHob = Hob.HandoffInformationTable;
+
+ if (PcdGet64 (PcdLoadModuleAtFixAddressEnable) != 0) {
+ ReservedCodePageNumber = PcdGet32 (PcdLoadFixAddressRuntimeCodePageNumber);
+ ReservedCodePageNumber += PcdGet32 (PcdLoadFixAddressBootTimeCodePageNumber);
+
+ //
+ // cache the Top address for loading modules at Fixed Address
+ //
+ gLoadModuleAtFixAddressConfigurationTable.DxeCodeTopAddress = PhitHob->EfiMemoryTop
+ + EFI_PAGES_TO_SIZE (ReservedCodePageNumber);
+ }
+
+ //
+ // See if a Memory Type Information HOB is available
+ //
+ MemoryTypeInformationResourceHob = NULL;
+ GuidHob = GetFirstGuidHob (&gEfiMemoryTypeInformationGuid);
+ if (GuidHob != NULL) {
+ EfiMemoryTypeInformation = GET_GUID_HOB_DATA (GuidHob);
+ DataSize = GET_GUID_HOB_DATA_SIZE (GuidHob);
+ if ((EfiMemoryTypeInformation != NULL) && (DataSize > 0) && (DataSize <= (EfiMaxMemoryType + 1) * sizeof (EFI_MEMORY_TYPE_INFORMATION))) {
+ CopyMem (&gMemoryTypeInformation, EfiMemoryTypeInformation, DataSize);
+
+ //
+ // Look for Resource Descriptor HOB with a ResourceType of System Memory
+ // and an Owner GUID of gEfiMemoryTypeInformationGuid. If more than 1 is
+ // found, then set MemoryTypeInformationResourceHob to NULL.
+ //
+ Count = 0;
+ for (Hob.Raw = *HobStart; !END_OF_HOB_LIST (Hob); Hob.Raw = GET_NEXT_HOB (Hob)) {
+ if (GET_HOB_TYPE (Hob) != EFI_HOB_TYPE_RESOURCE_DESCRIPTOR) {
+ continue;
+ }
+
+ ResourceHob = Hob.ResourceDescriptor;
+ if (!CompareGuid (&ResourceHob->Owner, &gEfiMemoryTypeInformationGuid)) {
+ continue;
+ }
+
+ Count++;
+ if (ResourceHob->ResourceType != EFI_RESOURCE_SYSTEM_MEMORY) {
+ continue;
+ }
+
+ if ((ResourceHob->ResourceAttribute & MEMORY_ATTRIBUTE_MASK) != TESTED_MEMORY_ATTRIBUTES) {
+ continue;
+ }
+
+ if (ResourceHob->ResourceLength >= CalculateTotalMemoryBinSizeNeeded ()) {
+ MemoryTypeInformationResourceHob = ResourceHob;
+ }
+ }
+
+ if (Count > 1) {
+ MemoryTypeInformationResourceHob = NULL;
+ }
+ }
+ }
+
+ //
+ // Include the total memory bin size needed to make sure memory bin could be allocated successfully.
+ //
+ MinimalMemorySizeNeeded = MINIMUM_INITIAL_MEMORY_SIZE + CalculateTotalMemoryBinSizeNeeded ();
+
+ //
+ // Find the Resource Descriptor HOB that contains PHIT range EfiFreeMemoryBottom..EfiFreeMemoryTop
+ //
+ Found = FALSE;
+ for (Hob.Raw = *HobStart; !END_OF_HOB_LIST (Hob); Hob.Raw = GET_NEXT_HOB (Hob)) {
+ //
+ // Skip all HOBs except Resource Descriptor HOBs
+ //
+ if (GET_HOB_TYPE (Hob) != EFI_HOB_TYPE_RESOURCE_DESCRIPTOR) {
+ continue;
+ }
+
+ //
+ // Skip Resource Descriptor HOBs that do not describe tested system memory
+ //
+ ResourceHob = Hob.ResourceDescriptor;
+ if (ResourceHob->ResourceType != EFI_RESOURCE_SYSTEM_MEMORY) {
+ continue;
+ }
+
+ if ((ResourceHob->ResourceAttribute & MEMORY_ATTRIBUTE_MASK) != TESTED_MEMORY_ATTRIBUTES) {
+ continue;
+ }
+
+ //
+ // Skip Resource Descriptor HOBs that do not contain the PHIT range EfiFreeMemoryBottom..EfiFreeMemoryTop
+ //
+ if (PhitHob->EfiFreeMemoryBottom < ResourceHob->PhysicalStart) {
+ continue;
+ }
+
+ if (PhitHob->EfiFreeMemoryTop > (ResourceHob->PhysicalStart + ResourceHob->ResourceLength)) {
+ continue;
+ }
+
+ //
+ // Cache the resource descriptor HOB for the memory region described by the PHIT HOB
+ //
+ PhitResourceHob = ResourceHob;
+ Found = TRUE;
+
+ //
+ // If a Memory Type Information Resource HOB was found and is the same
+ // Resource HOB that describes the PHIT HOB, then ignore the Memory Type
+ // Information Resource HOB.
+ //
+ if (MemoryTypeInformationResourceHob == PhitResourceHob) {
+ MemoryTypeInformationResourceHob = NULL;
+ }
+
+ //
+ // Compute range between PHIT EfiMemoryTop and the end of the Resource Descriptor HOB
+ //
+ Attributes = PhitResourceHob->ResourceAttribute;
+ BaseAddress = PageAlignAddress (PhitHob->EfiMemoryTop);
+ Length = PageAlignLength (ResourceHob->PhysicalStart + ResourceHob->ResourceLength - BaseAddress);
+ FindLargestFreeRegion (&BaseAddress, &Length, (EFI_HOB_MEMORY_ALLOCATION *)GetFirstHob (EFI_HOB_TYPE_MEMORY_ALLOCATION));
+ if (Length < MinimalMemorySizeNeeded) {
+ //
+ // If that range is not large enough to intialize the DXE Core, then
+ // Compute range between PHIT EfiFreeMemoryBottom and PHIT EfiFreeMemoryTop
+ //
+ BaseAddress = PageAlignAddress (PhitHob->EfiFreeMemoryBottom);
+ Length = PageAlignLength (PhitHob->EfiFreeMemoryTop - BaseAddress);
+ // This region is required to have no memory allocation inside it, skip check for entries in HOB List
+ if (Length < MinimalMemorySizeNeeded) {
+ //
+ // If that range is not large enough to intialize the DXE Core, then
+ // Compute range between the start of the Resource Descriptor HOB and the start of the HOB List
+ //
+ BaseAddress = PageAlignAddress (ResourceHob->PhysicalStart);
+ Length = PageAlignLength ((UINT64)((UINTN)*HobStart - BaseAddress));
+ FindLargestFreeRegion (&BaseAddress, &Length, (EFI_HOB_MEMORY_ALLOCATION *)GetFirstHob (EFI_HOB_TYPE_MEMORY_ALLOCATION));
+ }
+ }
+
+ break;
+ }
+
+ //
+ // Assert if a resource descriptor HOB for the memory region described by the PHIT was not found
+ //
+ ASSERT (Found);
+
+ //
+ // Take the range in the resource descriptor HOB for the memory region described
+ // by the PHIT as higher priority if it is big enough. It can make the memory bin
+ // allocated to be at the same memory region with PHIT that has more better compatibility
+ // to avoid memory fragmentation for some code practices assume and allocate <4G ACPI memory.
+ //
+ if (Length < MinimalMemorySizeNeeded) {
+ //
+ // Search all the resource descriptor HOBs from the highest possible addresses down for a memory
+ // region that is big enough to initialize the DXE core. Always skip the PHIT Resource HOB
+ // and the Memory Type Information Resource HOB. The max address must be within the physically
+ // addressable range for the processor.
+ //
+ HighAddress = MAX_ALLOC_ADDRESS;
+ for (Hob.Raw = *HobStart; !END_OF_HOB_LIST (Hob); Hob.Raw = GET_NEXT_HOB (Hob)) {
+ //
+ // Skip the Resource Descriptor HOB that contains the PHIT
+ //
+ if (Hob.ResourceDescriptor == PhitResourceHob) {
+ continue;
+ }
+
+ //
+ // Skip the Resource Descriptor HOB that contains Memory Type Information bins
+ //
+ if (Hob.ResourceDescriptor == MemoryTypeInformationResourceHob) {
+ continue;
+ }
+
+ //
+ // Skip all HOBs except Resource Descriptor HOBs
+ //
+ if (GET_HOB_TYPE (Hob) != EFI_HOB_TYPE_RESOURCE_DESCRIPTOR) {
+ continue;
+ }
+
+ //
+ // Skip Resource Descriptor HOBs that do not describe tested system memory below MAX_ALLOC_ADDRESS
+ //
+ ResourceHob = Hob.ResourceDescriptor;
+ if (ResourceHob->ResourceType != EFI_RESOURCE_SYSTEM_MEMORY) {
+ continue;
+ }
+
+ if ((ResourceHob->ResourceAttribute & MEMORY_ATTRIBUTE_MASK) != TESTED_MEMORY_ATTRIBUTES) {
+ continue;
+ }
+
+ if ((ResourceHob->PhysicalStart + ResourceHob->ResourceLength) > (EFI_PHYSICAL_ADDRESS)MAX_ALLOC_ADDRESS) {
+ continue;
+ }
+
+ //
+ // Skip Resource Descriptor HOBs that are below a previously found Resource Descriptor HOB
+ //
+ if ((HighAddress != (EFI_PHYSICAL_ADDRESS)MAX_ALLOC_ADDRESS) && (ResourceHob->PhysicalStart <= HighAddress)) {
+ continue;
+ }
+
+ //
+ // Skip Resource Descriptor HOBs that are not large enough to initilize the DXE Core
+ //
+ TestedMemoryBaseAddress = PageAlignAddress (ResourceHob->PhysicalStart);
+ TestedMemoryLength = PageAlignLength (ResourceHob->PhysicalStart + ResourceHob->ResourceLength - TestedMemoryBaseAddress);
+ FindLargestFreeRegion (&TestedMemoryBaseAddress, &TestedMemoryLength, (EFI_HOB_MEMORY_ALLOCATION *)GetFirstHob (EFI_HOB_TYPE_MEMORY_ALLOCATION));
+ if (TestedMemoryLength < MinimalMemorySizeNeeded) {
+ continue;
+ }
+
+ //
+ // Save the range described by the Resource Descriptor that is large enough to initilize the DXE Core
+ //
+ BaseAddress = TestedMemoryBaseAddress;
+ Length = TestedMemoryLength;
+ Attributes = ResourceHob->ResourceAttribute;
+ HighAddress = ResourceHob->PhysicalStart;
+ }
+ }
+
+ DEBUG ((DEBUG_INFO, "CoreInitializeMemoryServices:\n"));
+ DEBUG ((DEBUG_INFO, " BaseAddress - 0x%lx Length - 0x%lx MinimalMemorySizeNeeded - 0x%lx\n", BaseAddress, Length, MinimalMemorySizeNeeded));
+
+ //
+ // If no memory regions are found that are big enough to initialize the DXE core, then ASSERT().
+ //
+ ASSERT (Length >= MinimalMemorySizeNeeded);
+
+ //
+ // Convert the Resource HOB Attributes to an EFI Memory Capabilities mask
+ //
+ if ((Attributes & EFI_RESOURCE_ATTRIBUTE_MORE_RELIABLE) == EFI_RESOURCE_ATTRIBUTE_MORE_RELIABLE) {
+ Capabilities = CoreConvertResourceDescriptorHobAttributesToCapabilities (EfiGcdMemoryTypeMoreReliable, Attributes);
+ } else {
+ Capabilities = CoreConvertResourceDescriptorHobAttributesToCapabilities (EfiGcdMemoryTypeSystemMemory, Attributes);
+ }
+
+ if (MemoryTypeInformationResourceHob != NULL) {
+ //
+ // If a Memory Type Information Resource HOB was found, then use the address
+ // range of the Memory Type Information Resource HOB as the preferred
+ // address range for the Memory Type Information bins.
+ //
+ CoreSetMemoryTypeInformationRange (
+ MemoryTypeInformationResourceHob->PhysicalStart,
+ MemoryTypeInformationResourceHob->ResourceLength
+ );
+ }
+
+ //
+ // Declare the very first memory region, so the EFI Memory Services are available.
+ //
+ CoreAddMemoryDescriptor (
+ EfiConventionalMemory,
+ BaseAddress,
+ RShiftU64 (Length, EFI_PAGE_SHIFT),
+ Capabilities
+ );
+
+ *MemoryBaseAddress = BaseAddress;
+ *MemoryLength = Length;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ External function. Initializes the GCD and memory services based on the memory
+ descriptor HOBs. This function is responsible for priming the GCD map and the
+ memory map, so memory allocations and resource allocations can be made. The
+ HobStart will be relocated to a pool buffer.
+
+ @param HobStart The start address of the HOB
+ @param MemoryBaseAddress Start address of memory region found to init DXE
+ core.
+ @param MemoryLength Length of memory region found to init DXE core.
+
+ @retval EFI_SUCCESS GCD services successfully initialized.
+
+**/
+EFI_STATUS
+CoreInitializeGcdServices (
+ IN OUT VOID **HobStart,
+ IN EFI_PHYSICAL_ADDRESS MemoryBaseAddress,
+ IN UINT64 MemoryLength
+ )
+{
+ EFI_PEI_HOB_POINTERS Hob;
+ VOID *NewHobList;
+ EFI_HOB_HANDOFF_INFO_TABLE *PhitHob;
+ UINT8 SizeOfMemorySpace;
+ UINT8 SizeOfIoSpace;
+ EFI_HOB_RESOURCE_DESCRIPTOR *ResourceHob;
+ EFI_PHYSICAL_ADDRESS BaseAddress;
+ UINT64 Length;
+ EFI_STATUS Status;
+ EFI_GCD_MAP_ENTRY *Entry;
+ EFI_GCD_MEMORY_TYPE GcdMemoryType;
+ EFI_GCD_IO_TYPE GcdIoType;
+ EFI_GCD_MEMORY_SPACE_DESCRIPTOR Descriptor;
+ EFI_HOB_MEMORY_ALLOCATION *MemoryHob;
+ EFI_HOB_FIRMWARE_VOLUME *FirmwareVolumeHob;
+ UINTN NumberOfDescriptors;
+ EFI_GCD_MEMORY_SPACE_DESCRIPTOR *MemorySpaceMap;
+ UINTN Index;
+ UINT64 Capabilities;
+ EFI_HOB_CPU *CpuHob;
+ EFI_GCD_MEMORY_SPACE_DESCRIPTOR *MemorySpaceMapHobList;
+
+ //
+ // Cache the PHIT HOB for later use
+ //
+ PhitHob = (EFI_HOB_HANDOFF_INFO_TABLE *)(*HobStart);
+
+ //
+ // Get the number of address lines in the I/O and Memory space for the CPU
+ //
+ CpuHob = GetFirstHob (EFI_HOB_TYPE_CPU);
+ ASSERT (CpuHob != NULL);
+ SizeOfMemorySpace = CpuHob->SizeOfMemorySpace;
+ SizeOfIoSpace = CpuHob->SizeOfIoSpace;
+
+ //
+ // Initialize the GCD Memory Space Map
+ //
+ Entry = AllocateCopyPool (sizeof (EFI_GCD_MAP_ENTRY), &mGcdMemorySpaceMapEntryTemplate);
+ ASSERT (Entry != NULL);
+
+ Entry->EndAddress = LShiftU64 (1, SizeOfMemorySpace) - 1;
+
+ InsertHeadList (&mGcdMemorySpaceMap, &Entry->Link);
+
+ CoreDumpGcdMemorySpaceMap (TRUE);
+
+ //
+ // Initialize the GCD I/O Space Map
+ //
+ Entry = AllocateCopyPool (sizeof (EFI_GCD_MAP_ENTRY), &mGcdIoSpaceMapEntryTemplate);
+ ASSERT (Entry != NULL);
+
+ Entry->EndAddress = LShiftU64 (1, SizeOfIoSpace) - 1;
+
+ InsertHeadList (&mGcdIoSpaceMap, &Entry->Link);
+
+ CoreDumpGcdIoSpaceMap (TRUE);
+
+ //
+ // Walk the HOB list and add all resource descriptors to the GCD
+ //
+ for (Hob.Raw = *HobStart; !END_OF_HOB_LIST (Hob); Hob.Raw = GET_NEXT_HOB (Hob)) {
+ GcdMemoryType = EfiGcdMemoryTypeNonExistent;
+ GcdIoType = EfiGcdIoTypeNonExistent;
+
+ if (GET_HOB_TYPE (Hob) == EFI_HOB_TYPE_RESOURCE_DESCRIPTOR) {
+ ResourceHob = Hob.ResourceDescriptor;
+
+ switch (ResourceHob->ResourceType) {
+ case EFI_RESOURCE_SYSTEM_MEMORY:
+ if ((ResourceHob->ResourceAttribute & MEMORY_ATTRIBUTE_MASK) == TESTED_MEMORY_ATTRIBUTES) {
+ if ((ResourceHob->ResourceAttribute & EFI_RESOURCE_ATTRIBUTE_MORE_RELIABLE) == EFI_RESOURCE_ATTRIBUTE_MORE_RELIABLE) {
+ GcdMemoryType = EfiGcdMemoryTypeMoreReliable;
+ } else {
+ GcdMemoryType = EfiGcdMemoryTypeSystemMemory;
+ }
+ }
+
+ if ((ResourceHob->ResourceAttribute & MEMORY_ATTRIBUTE_MASK) == INITIALIZED_MEMORY_ATTRIBUTES) {
+ GcdMemoryType = EfiGcdMemoryTypeReserved;
+ }
+
+ if ((ResourceHob->ResourceAttribute & MEMORY_ATTRIBUTE_MASK) == PRESENT_MEMORY_ATTRIBUTES) {
+ GcdMemoryType = EfiGcdMemoryTypeReserved;
+ }
+
+ if ((ResourceHob->ResourceAttribute & EFI_RESOURCE_ATTRIBUTE_PERSISTENT) == EFI_RESOURCE_ATTRIBUTE_PERSISTENT) {
+ GcdMemoryType = EfiGcdMemoryTypePersistent;
+ }
+
+ break;
+ case EFI_RESOURCE_MEMORY_MAPPED_IO:
+ case EFI_RESOURCE_FIRMWARE_DEVICE:
+ GcdMemoryType = EfiGcdMemoryTypeMemoryMappedIo;
+ break;
+ case EFI_RESOURCE_MEMORY_MAPPED_IO_PORT:
+ case EFI_RESOURCE_MEMORY_RESERVED:
+ GcdMemoryType = EfiGcdMemoryTypeReserved;
+ break;
+ case EFI_RESOURCE_MEMORY_UNACCEPTED:
+ GcdMemoryType = EfiGcdMemoryTypeUnaccepted;
+ break;
+ case EFI_RESOURCE_IO:
+ GcdIoType = EfiGcdIoTypeIo;
+ break;
+ case EFI_RESOURCE_IO_RESERVED:
+ GcdIoType = EfiGcdIoTypeReserved;
+ break;
+ }
+
+ if (GcdMemoryType != EfiGcdMemoryTypeNonExistent) {
+ //
+ // Validate the Resource HOB Attributes
+ //
+ CoreValidateResourceDescriptorHobAttributes (ResourceHob->ResourceAttribute);
+
+ //
+ // Convert the Resource HOB Attributes to an EFI Memory Capabilities mask
+ //
+ Capabilities = CoreConvertResourceDescriptorHobAttributesToCapabilities (
+ GcdMemoryType,
+ ResourceHob->ResourceAttribute
+ );
+
+ Status = CoreInternalAddMemorySpace (
+ GcdMemoryType,
+ ResourceHob->PhysicalStart,
+ ResourceHob->ResourceLength,
+ Capabilities
+ );
+ }
+
+ if (GcdIoType != EfiGcdIoTypeNonExistent) {
+ Status = CoreAddIoSpace (
+ GcdIoType,
+ ResourceHob->PhysicalStart,
+ ResourceHob->ResourceLength
+ );
+ }
+ }
+ }
+
+ //
+ // Allocate first memory region from the GCD by the DXE core
+ //
+ Status = CoreGetMemorySpaceDescriptor (MemoryBaseAddress, &Descriptor);
+ if (!EFI_ERROR (Status)) {
+ ASSERT (
+ (Descriptor.GcdMemoryType == EfiGcdMemoryTypeSystemMemory) ||
+ (Descriptor.GcdMemoryType == EfiGcdMemoryTypeMoreReliable)
+ );
+ Status = CoreAllocateMemorySpace (
+ EfiGcdAllocateAddress,
+ Descriptor.GcdMemoryType,
+ 0,
+ MemoryLength,
+ &MemoryBaseAddress,
+ gDxeCoreImageHandle,
+ NULL
+ );
+ }
+
+ //
+ // Walk the HOB list and allocate all memory space that is consumed by memory allocation HOBs,
+ // and Firmware Volume HOBs. Also update the EFI Memory Map with the memory allocation HOBs.
+ //
+ for (Hob.Raw = *HobStart; !END_OF_HOB_LIST (Hob); Hob.Raw = GET_NEXT_HOB (Hob)) {
+ if (GET_HOB_TYPE (Hob) == EFI_HOB_TYPE_MEMORY_ALLOCATION) {
+ MemoryHob = Hob.MemoryAllocation;
+ BaseAddress = MemoryHob->AllocDescriptor.MemoryBaseAddress;
+ Status = CoreGetMemorySpaceDescriptor (BaseAddress, &Descriptor);
+ if (!EFI_ERROR (Status)) {
+ Status = CoreAllocateMemorySpace (
+ EfiGcdAllocateAddress,
+ Descriptor.GcdMemoryType,
+ 0,
+ MemoryHob->AllocDescriptor.MemoryLength,
+ &BaseAddress,
+ gDxeCoreImageHandle,
+ NULL
+ );
+ if (!EFI_ERROR (Status) &&
+ ((Descriptor.GcdMemoryType == EfiGcdMemoryTypeSystemMemory) ||
+ (Descriptor.GcdMemoryType == EfiGcdMemoryTypeMoreReliable)))
+ {
+ CoreAddMemoryDescriptor (
+ MemoryHob->AllocDescriptor.MemoryType,
+ MemoryHob->AllocDescriptor.MemoryBaseAddress,
+ RShiftU64 (MemoryHob->AllocDescriptor.MemoryLength, EFI_PAGE_SHIFT),
+ Descriptor.Capabilities & (~EFI_MEMORY_RUNTIME)
+ );
+ }
+ }
+ }
+
+ if (GET_HOB_TYPE (Hob) == EFI_HOB_TYPE_FV) {
+ FirmwareVolumeHob = Hob.FirmwareVolume;
+ BaseAddress = FirmwareVolumeHob->BaseAddress;
+ Status = CoreAllocateMemorySpace (
+ EfiGcdAllocateAddress,
+ EfiGcdMemoryTypeMemoryMappedIo,
+ 0,
+ FirmwareVolumeHob->Length,
+ &BaseAddress,
+ gDxeCoreImageHandle,
+ NULL
+ );
+ }
+ }
+
+ //
+ // Add and allocate the remaining unallocated system memory to the memory services.
+ //
+ Status = CoreGetMemorySpaceMap (&NumberOfDescriptors, &MemorySpaceMap);
+ ASSERT (Status == EFI_SUCCESS);
+
+ MemorySpaceMapHobList = NULL;
+ for (Index = 0; Index < NumberOfDescriptors; Index++) {
+ if ((MemorySpaceMap[Index].GcdMemoryType == EfiGcdMemoryTypeSystemMemory) ||
+ (MemorySpaceMap[Index].GcdMemoryType == EfiGcdMemoryTypeMoreReliable))
+ {
+ if (MemorySpaceMap[Index].ImageHandle == NULL) {
+ BaseAddress = PageAlignAddress (MemorySpaceMap[Index].BaseAddress);
+ Length = PageAlignLength (MemorySpaceMap[Index].BaseAddress + MemorySpaceMap[Index].Length - BaseAddress);
+ if ((Length == 0) || (MemorySpaceMap[Index].BaseAddress + MemorySpaceMap[Index].Length < BaseAddress)) {
+ continue;
+ }
+
+ if (((UINTN)MemorySpaceMap[Index].BaseAddress <= (UINTN)(*HobStart)) &&
+ ((UINTN)(MemorySpaceMap[Index].BaseAddress + MemorySpaceMap[Index].Length) >= (UINTN)PhitHob->EfiFreeMemoryBottom))
+ {
+ //
+ // Skip the memory space that covers HOB List, it should be processed
+ // after HOB List relocation to avoid the resources allocated by others
+ // to corrupt HOB List before its relocation.
+ //
+ MemorySpaceMapHobList = &MemorySpaceMap[Index];
+ continue;
+ }
+
+ CoreAddMemoryDescriptor (
+ EfiConventionalMemory,
+ BaseAddress,
+ RShiftU64 (Length, EFI_PAGE_SHIFT),
+ MemorySpaceMap[Index].Capabilities & (~EFI_MEMORY_RUNTIME)
+ );
+ Status = CoreAllocateMemorySpace (
+ EfiGcdAllocateAddress,
+ MemorySpaceMap[Index].GcdMemoryType,
+ 0,
+ Length,
+ &BaseAddress,
+ gDxeCoreImageHandle,
+ NULL
+ );
+ }
+ }
+ }
+
+ //
+ // Relocate HOB List to an allocated pool buffer.
+ // The relocation should be at after all the tested memory resources added
+ // (except the memory space that covers HOB List) to the memory services,
+ // because the memory resource found in CoreInitializeMemoryServices()
+ // may have not enough remaining resource for HOB List.
+ //
+ NewHobList = AllocateCopyPool (
+ (UINTN)PhitHob->EfiFreeMemoryBottom - (UINTN)(*HobStart),
+ *HobStart
+ );
+ ASSERT (NewHobList != NULL);
+
+ *HobStart = NewHobList;
+ gHobList = NewHobList;
+
+ if (MemorySpaceMapHobList != NULL) {
+ //
+ // Add and allocate the memory space that covers HOB List to the memory services
+ // after HOB List relocation.
+ //
+ BaseAddress = PageAlignAddress (MemorySpaceMapHobList->BaseAddress);
+ Length = PageAlignLength (MemorySpaceMapHobList->BaseAddress + MemorySpaceMapHobList->Length - BaseAddress);
+ CoreAddMemoryDescriptor (
+ EfiConventionalMemory,
+ BaseAddress,
+ RShiftU64 (Length, EFI_PAGE_SHIFT),
+ MemorySpaceMapHobList->Capabilities & (~EFI_MEMORY_RUNTIME)
+ );
+ Status = CoreAllocateMemorySpace (
+ EfiGcdAllocateAddress,
+ MemorySpaceMapHobList->GcdMemoryType,
+ 0,
+ Length,
+ &BaseAddress,
+ gDxeCoreImageHandle,
+ NULL
+ );
+ }
+
+ CoreFreePool (MemorySpaceMap);
+
+ return EFI_SUCCESS;
+}
diff --git a/MdeModulePkg/Core/Dxe/Gcd/Gcd.h b/MdeModulePkg/Core/Dxe/Gcd/Gcd.h
index d4a4dd7c1b..5ea1cc86e0 100644
--- a/MdeModulePkg/Core/Dxe/Gcd/Gcd.h
+++ b/MdeModulePkg/Core/Dxe/Gcd/Gcd.h
@@ -1,40 +1,40 @@
-/** @file
- GCD Operations and data structure used to
- convert from GCD attributes to EFI Memory Map attributes.
-
-Copyright (c) 2006 - 2014, Intel Corporation. All rights reserved.<BR>
-SPDX-License-Identifier: BSD-2-Clause-Patent
-
-**/
-
-#ifndef _GCD_H_
-#define _GCD_H_
-
-//
-// GCD Operations
-//
-#define GCD_MEMORY_SPACE_OPERATION 0x20
-#define GCD_IO_SPACE_OPERATION 0x40
-
-#define GCD_ADD_MEMORY_OPERATION (GCD_MEMORY_SPACE_OPERATION | 0)
-#define GCD_ALLOCATE_MEMORY_OPERATION (GCD_MEMORY_SPACE_OPERATION | 1)
-#define GCD_FREE_MEMORY_OPERATION (GCD_MEMORY_SPACE_OPERATION | 2)
-#define GCD_REMOVE_MEMORY_OPERATION (GCD_MEMORY_SPACE_OPERATION | 3)
-#define GCD_SET_ATTRIBUTES_MEMORY_OPERATION (GCD_MEMORY_SPACE_OPERATION | 4)
-#define GCD_SET_CAPABILITIES_MEMORY_OPERATION (GCD_MEMORY_SPACE_OPERATION | 5)
-
-#define GCD_ADD_IO_OPERATION (GCD_IO_SPACE_OPERATION | 0)
-#define GCD_ALLOCATE_IO_OPERATION (GCD_IO_SPACE_OPERATION | 1)
-#define GCD_FREE_IO_OPERATION (GCD_IO_SPACE_OPERATION | 2)
-#define GCD_REMOVE_IO_OPERATION (GCD_IO_SPACE_OPERATION | 3)
-
-//
-// The data structure used to convert from GCD attributes to EFI Memory Map attributes
-//
-typedef struct {
- UINT64 Attribute;
- UINT64 Capability;
- BOOLEAN Memory;
-} GCD_ATTRIBUTE_CONVERSION_ENTRY;
-
-#endif
+/** @file
+ GCD Operations and data structure used to
+ convert from GCD attributes to EFI Memory Map attributes.
+
+Copyright (c) 2006 - 2014, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _GCD_H_
+#define _GCD_H_
+
+//
+// GCD Operations
+//
+#define GCD_MEMORY_SPACE_OPERATION 0x20
+#define GCD_IO_SPACE_OPERATION 0x40
+
+#define GCD_ADD_MEMORY_OPERATION (GCD_MEMORY_SPACE_OPERATION | 0)
+#define GCD_ALLOCATE_MEMORY_OPERATION (GCD_MEMORY_SPACE_OPERATION | 1)
+#define GCD_FREE_MEMORY_OPERATION (GCD_MEMORY_SPACE_OPERATION | 2)
+#define GCD_REMOVE_MEMORY_OPERATION (GCD_MEMORY_SPACE_OPERATION | 3)
+#define GCD_SET_ATTRIBUTES_MEMORY_OPERATION (GCD_MEMORY_SPACE_OPERATION | 4)
+#define GCD_SET_CAPABILITIES_MEMORY_OPERATION (GCD_MEMORY_SPACE_OPERATION | 5)
+
+#define GCD_ADD_IO_OPERATION (GCD_IO_SPACE_OPERATION | 0)
+#define GCD_ALLOCATE_IO_OPERATION (GCD_IO_SPACE_OPERATION | 1)
+#define GCD_FREE_IO_OPERATION (GCD_IO_SPACE_OPERATION | 2)
+#define GCD_REMOVE_IO_OPERATION (GCD_IO_SPACE_OPERATION | 3)
+
+//
+// The data structure used to convert from GCD attributes to EFI Memory Map attributes
+//
+typedef struct {
+ UINT64 Attribute;
+ UINT64 Capability;
+ BOOLEAN Memory;
+} GCD_ATTRIBUTE_CONVERSION_ENTRY;
+
+#endif
diff --git a/MdeModulePkg/Core/Dxe/Hand/DriverSupport.c b/MdeModulePkg/Core/Dxe/Hand/DriverSupport.c
index 64d7474f15..5ae6ce9448 100644
--- a/MdeModulePkg/Core/Dxe/Hand/DriverSupport.c
+++ b/MdeModulePkg/Core/Dxe/Hand/DriverSupport.c
@@ -1,994 +1,994 @@
-/** @file
- Support functions to connect/disconnect UEFI Driver model Protocol
-
-Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
-SPDX-License-Identifier: BSD-2-Clause-Patent
-
-**/
-
-#include "DxeMain.h"
-#include "Handle.h"
-
-//
-// Driver Support Functions
-//
-
-/**
- Connects one or more drivers to a controller.
-
- @param ControllerHandle The handle of the controller to which driver(s) are to be connected.
- @param DriverImageHandle A pointer to an ordered list handles that support the
- EFI_DRIVER_BINDING_PROTOCOL.
- @param RemainingDevicePath A pointer to the device path that specifies a child of the
- controller specified by ControllerHandle.
- @param Recursive If TRUE, then ConnectController() is called recursively
- until the entire tree of controllers below the controller specified
- by ControllerHandle have been created. If FALSE, then
- the tree of controllers is only expanded one level.
-
- @retval EFI_SUCCESS 1) One or more drivers were connected to ControllerHandle.
- 2) No drivers were connected to ControllerHandle, but
- RemainingDevicePath is not NULL, and it is an End Device
- Path Node.
- @retval EFI_INVALID_PARAMETER ControllerHandle is NULL.
- @retval EFI_NOT_FOUND 1) There are no EFI_DRIVER_BINDING_PROTOCOL instances
- present in the system.
- 2) No drivers were connected to ControllerHandle.
- @retval EFI_SECURITY_VIOLATION
- The user has no permission to start UEFI device drivers on the device path
- associated with the ControllerHandle or specified by the RemainingDevicePath.
-
-**/
-EFI_STATUS
-EFIAPI
-CoreConnectController (
- IN EFI_HANDLE ControllerHandle,
- IN EFI_HANDLE *DriverImageHandle OPTIONAL,
- IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL,
- IN BOOLEAN Recursive
- )
-{
- EFI_STATUS Status;
- EFI_STATUS ReturnStatus;
- IHANDLE *Handle;
- PROTOCOL_INTERFACE *Prot;
- LIST_ENTRY *Link;
- LIST_ENTRY *ProtLink;
- OPEN_PROTOCOL_DATA *OpenData;
- EFI_DEVICE_PATH_PROTOCOL *AlignedRemainingDevicePath;
- EFI_HANDLE *ChildHandleBuffer;
- UINTN ChildHandleCount;
- UINTN Index;
- UINTN HandleFilePathSize;
- UINTN RemainingDevicePathSize;
- EFI_DEVICE_PATH_PROTOCOL *HandleFilePath;
- EFI_DEVICE_PATH_PROTOCOL *FilePath;
- EFI_DEVICE_PATH_PROTOCOL *TempFilePath;
-
- //
- // Make sure ControllerHandle is valid
- //
- CoreAcquireProtocolLock ();
-
- Status = CoreValidateHandle (ControllerHandle);
-
- CoreReleaseProtocolLock ();
-
- if (EFI_ERROR (Status)) {
- return Status;
- }
-
- if (gSecurity2 != NULL) {
- //
- // Check whether the user has permission to start UEFI device drivers.
- //
- Status = CoreHandleProtocol (ControllerHandle, &gEfiDevicePathProtocolGuid, (VOID **)&HandleFilePath);
- if (!EFI_ERROR (Status)) {
- ASSERT (HandleFilePath != NULL);
- FilePath = HandleFilePath;
- TempFilePath = NULL;
- if ((RemainingDevicePath != NULL) && !Recursive) {
- HandleFilePathSize = GetDevicePathSize (HandleFilePath) - sizeof (EFI_DEVICE_PATH_PROTOCOL);
- RemainingDevicePathSize = GetDevicePathSize (RemainingDevicePath);
- TempFilePath = AllocateZeroPool (HandleFilePathSize + RemainingDevicePathSize);
- ASSERT (TempFilePath != NULL);
- CopyMem (TempFilePath, HandleFilePath, HandleFilePathSize);
- CopyMem ((UINT8 *)TempFilePath + HandleFilePathSize, RemainingDevicePath, RemainingDevicePathSize);
- FilePath = TempFilePath;
- }
-
- Status = gSecurity2->FileAuthentication (
- gSecurity2,
- FilePath,
- NULL,
- 0,
- FALSE
- );
- if (TempFilePath != NULL) {
- FreePool (TempFilePath);
- }
-
- if (EFI_ERROR (Status)) {
- return Status;
- }
- }
- }
-
- Handle = ControllerHandle;
-
- //
- // Make a copy of RemainingDevicePath to guanatee it is aligned
- //
- AlignedRemainingDevicePath = NULL;
- if (RemainingDevicePath != NULL) {
- AlignedRemainingDevicePath = DuplicateDevicePath (RemainingDevicePath);
-
- if (AlignedRemainingDevicePath == NULL) {
- return EFI_OUT_OF_RESOURCES;
- }
- }
-
- //
- // Connect all drivers to ControllerHandle
- // If CoreConnectSingleController returns EFI_NOT_READY, then the number of
- // Driver Binding Protocols in the handle database has increased during the call
- // so the connect operation must be restarted
- //
- do {
- ReturnStatus = CoreConnectSingleController (
- ControllerHandle,
- DriverImageHandle,
- AlignedRemainingDevicePath
- );
- } while (ReturnStatus == EFI_NOT_READY);
-
- //
- // Free the aligned copy of RemainingDevicePath
- //
- if (AlignedRemainingDevicePath != NULL) {
- CoreFreePool (AlignedRemainingDevicePath);
- }
-
- //
- // If recursive, then connect all drivers to all of ControllerHandle's children
- //
- if (Recursive) {
- //
- // Acquire the protocol lock on the handle database so the child handles can be collected
- //
- CoreAcquireProtocolLock ();
-
- //
- // Make sure the DriverBindingHandle is valid
- //
- Status = CoreValidateHandle (ControllerHandle);
- if (EFI_ERROR (Status)) {
- //
- // Release the protocol lock on the handle database
- //
- CoreReleaseProtocolLock ();
-
- return ReturnStatus;
- }
-
- //
- // Count ControllerHandle's children
- //
- for (Link = Handle->Protocols.ForwardLink, ChildHandleCount = 0; Link != &Handle->Protocols; Link = Link->ForwardLink) {
- Prot = CR (Link, PROTOCOL_INTERFACE, Link, PROTOCOL_INTERFACE_SIGNATURE);
- for (ProtLink = Prot->OpenList.ForwardLink;
- ProtLink != &Prot->OpenList;
- ProtLink = ProtLink->ForwardLink)
- {
- OpenData = CR (ProtLink, OPEN_PROTOCOL_DATA, Link, OPEN_PROTOCOL_DATA_SIGNATURE);
- if ((OpenData->Attributes & EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER) != 0) {
- ChildHandleCount++;
- }
- }
- }
-
- //
- // Allocate a handle buffer for ControllerHandle's children
- //
- ChildHandleBuffer = AllocatePool (ChildHandleCount * sizeof (EFI_HANDLE));
- if (ChildHandleBuffer == NULL) {
- CoreReleaseProtocolLock ();
- return EFI_OUT_OF_RESOURCES;
- }
-
- //
- // Fill in a handle buffer with ControllerHandle's children
- //
- for (Link = Handle->Protocols.ForwardLink, ChildHandleCount = 0; Link != &Handle->Protocols; Link = Link->ForwardLink) {
- Prot = CR (Link, PROTOCOL_INTERFACE, Link, PROTOCOL_INTERFACE_SIGNATURE);
- for (ProtLink = Prot->OpenList.ForwardLink;
- ProtLink != &Prot->OpenList;
- ProtLink = ProtLink->ForwardLink)
- {
- OpenData = CR (ProtLink, OPEN_PROTOCOL_DATA, Link, OPEN_PROTOCOL_DATA_SIGNATURE);
- if ((OpenData->Attributes & EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER) != 0) {
- ChildHandleBuffer[ChildHandleCount] = OpenData->ControllerHandle;
- ChildHandleCount++;
- }
- }
- }
-
- //
- // Release the protocol lock on the handle database
- //
- CoreReleaseProtocolLock ();
-
- //
- // Recursively connect each child handle
- //
- for (Index = 0; Index < ChildHandleCount; Index++) {
- CoreConnectController (
- ChildHandleBuffer[Index],
- NULL,
- NULL,
- TRUE
- );
- }
-
- //
- // Free the handle buffer of ControllerHandle's children
- //
- CoreFreePool (ChildHandleBuffer);
- }
-
- return ReturnStatus;
-}
-
-/**
- Add Driver Binding Protocols from Context Driver Image Handles to sorted
- Driver Binding Protocol list.
-
- @param DriverBindingHandle Handle of the driver binding
- protocol.
- @param NumberOfSortedDriverBindingProtocols Number Of sorted driver binding
- protocols
- @param SortedDriverBindingProtocols The sorted protocol list.
- @param DriverBindingHandleCount Driver Binding Handle Count.
- @param DriverBindingHandleBuffer The buffer of driver binding
- protocol to be modified.
- @param IsImageHandle Indicate whether
- DriverBindingHandle is an image
- handle
-
- @return None.
-
-**/
-VOID
-AddSortedDriverBindingProtocol (
- IN EFI_HANDLE DriverBindingHandle,
- IN OUT UINTN *NumberOfSortedDriverBindingProtocols,
- IN OUT EFI_DRIVER_BINDING_PROTOCOL **SortedDriverBindingProtocols,
- IN UINTN DriverBindingHandleCount,
- IN OUT EFI_HANDLE *DriverBindingHandleBuffer,
- IN BOOLEAN IsImageHandle
- )
-{
- EFI_STATUS Status;
- EFI_DRIVER_BINDING_PROTOCOL *DriverBinding;
- UINTN Index;
-
- //
- // Make sure the DriverBindingHandle is valid
- //
- CoreAcquireProtocolLock ();
-
- Status = CoreValidateHandle (DriverBindingHandle);
-
- CoreReleaseProtocolLock ();
-
- if (EFI_ERROR (Status)) {
- return;
- }
-
- //
- // If IsImageHandle is TRUE, then DriverBindingHandle is an image handle
- // Find all the DriverBindingHandles associated with that image handle and add them to the sorted list
- //
- if (IsImageHandle) {
- //
- // Loop through all the Driver Binding Handles
- //
- for (Index = 0; Index < DriverBindingHandleCount; Index++) {
- //
- // Retrieve the Driver Binding Protocol associated with each Driver Binding Handle
- //
- Status = CoreHandleProtocol (
- DriverBindingHandleBuffer[Index],
- &gEfiDriverBindingProtocolGuid,
- (VOID **)&DriverBinding
- );
- if (EFI_ERROR (Status) || (DriverBinding == NULL)) {
- continue;
- }
-
- //
- // If the ImageHandle associated with DriverBinding matches DriverBindingHandle,
- // then add the DriverBindingProtocol[Index] to the sorted list
- //
- if (DriverBinding->ImageHandle == DriverBindingHandle) {
- AddSortedDriverBindingProtocol (
- DriverBindingHandleBuffer[Index],
- NumberOfSortedDriverBindingProtocols,
- SortedDriverBindingProtocols,
- DriverBindingHandleCount,
- DriverBindingHandleBuffer,
- FALSE
- );
- }
- }
-
- return;
- }
-
- //
- // Retrieve the Driver Binding Protocol from DriverBindingHandle
- //
- Status = CoreHandleProtocol (
- DriverBindingHandle,
- &gEfiDriverBindingProtocolGuid,
- (VOID **)&DriverBinding
- );
- //
- // If DriverBindingHandle does not support the Driver Binding Protocol then return
- //
- if (EFI_ERROR (Status) || (DriverBinding == NULL)) {
- return;
- }
-
- //
- // See if DriverBinding is already in the sorted list
- //
- for (Index = 0; Index < *NumberOfSortedDriverBindingProtocols && Index < DriverBindingHandleCount; Index++) {
- if (DriverBinding == SortedDriverBindingProtocols[Index]) {
- return;
- }
- }
-
- //
- // Add DriverBinding to the end of the list
- //
- if (*NumberOfSortedDriverBindingProtocols < DriverBindingHandleCount) {
- SortedDriverBindingProtocols[*NumberOfSortedDriverBindingProtocols] = DriverBinding;
- }
-
- *NumberOfSortedDriverBindingProtocols = *NumberOfSortedDriverBindingProtocols + 1;
-
- //
- // Mark the cooresponding handle in DriverBindingHandleBuffer as used
- //
- for (Index = 0; Index < DriverBindingHandleCount; Index++) {
- if (DriverBindingHandleBuffer[Index] == DriverBindingHandle) {
- DriverBindingHandleBuffer[Index] = NULL;
- }
- }
-}
-
-/**
- Connects a controller to a driver.
-
- @param ControllerHandle Handle of the controller to be
- connected.
- @param ContextDriverImageHandles DriverImageHandle A pointer to an
- ordered list of driver image
- handles.
- @param RemainingDevicePath RemainingDevicePath A pointer to
- the device path that specifies a
- child of the controller
- specified by ControllerHandle.
-
- @retval EFI_SUCCESS One or more drivers were
- connected to ControllerHandle.
- @retval EFI_OUT_OF_RESOURCES No enough system resources to
- complete the request.
- @retval EFI_NOT_FOUND No drivers were connected to
- ControllerHandle.
-
-**/
-EFI_STATUS
-CoreConnectSingleController (
- IN EFI_HANDLE ControllerHandle,
- IN EFI_HANDLE *ContextDriverImageHandles OPTIONAL,
- IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL
- )
-{
- EFI_STATUS Status;
- UINTN Index;
- EFI_HANDLE DriverImageHandle;
- EFI_PLATFORM_DRIVER_OVERRIDE_PROTOCOL *PlatformDriverOverride;
- EFI_BUS_SPECIFIC_DRIVER_OVERRIDE_PROTOCOL *BusSpecificDriverOverride;
- UINTN DriverBindingHandleCount;
- EFI_HANDLE *DriverBindingHandleBuffer;
- UINTN NewDriverBindingHandleCount;
- EFI_HANDLE *NewDriverBindingHandleBuffer;
- EFI_DRIVER_BINDING_PROTOCOL *DriverBinding;
- EFI_DRIVER_FAMILY_OVERRIDE_PROTOCOL *DriverFamilyOverride;
- UINTN NumberOfSortedDriverBindingProtocols;
- EFI_DRIVER_BINDING_PROTOCOL **SortedDriverBindingProtocols;
- UINT32 DriverFamilyOverrideVersion;
- UINT32 HighestVersion;
- UINTN HighestIndex;
- UINTN SortIndex;
- BOOLEAN OneStarted;
- BOOLEAN DriverFound;
-
- //
- // Initialize local variables
- //
- DriverBindingHandleCount = 0;
- DriverBindingHandleBuffer = NULL;
- NumberOfSortedDriverBindingProtocols = 0;
- SortedDriverBindingProtocols = NULL;
- PlatformDriverOverride = NULL;
- NewDriverBindingHandleBuffer = NULL;
-
- //
- // Get list of all Driver Binding Protocol Instances
- //
- Status = CoreLocateHandleBuffer (
- ByProtocol,
- &gEfiDriverBindingProtocolGuid,
- NULL,
- &DriverBindingHandleCount,
- &DriverBindingHandleBuffer
- );
- if (EFI_ERROR (Status) || (DriverBindingHandleCount == 0)) {
- return EFI_NOT_FOUND;
- }
-
- //
- // Allocate a duplicate array for the sorted Driver Binding Protocol Instances
- //
- SortedDriverBindingProtocols = AllocatePool (sizeof (VOID *) * DriverBindingHandleCount);
- if (SortedDriverBindingProtocols == NULL) {
- CoreFreePool (DriverBindingHandleBuffer);
- return EFI_OUT_OF_RESOURCES;
- }
-
- //
- // Add Driver Binding Protocols from Context Driver Image Handles first
- //
- if (ContextDriverImageHandles != NULL) {
- for (Index = 0; ContextDriverImageHandles[Index] != NULL; Index++) {
- AddSortedDriverBindingProtocol (
- ContextDriverImageHandles[Index],
- &NumberOfSortedDriverBindingProtocols,
- SortedDriverBindingProtocols,
- DriverBindingHandleCount,
- DriverBindingHandleBuffer,
- FALSE
- );
- }
- }
-
- //
- // Add the Platform Driver Override Protocol drivers for ControllerHandle next
- //
- Status = CoreLocateProtocol (
- &gEfiPlatformDriverOverrideProtocolGuid,
- NULL,
- (VOID **)&PlatformDriverOverride
- );
- if (!EFI_ERROR (Status) && (PlatformDriverOverride != NULL)) {
- DriverImageHandle = NULL;
- do {
- Status = PlatformDriverOverride->GetDriver (
- PlatformDriverOverride,
- ControllerHandle,
- &DriverImageHandle
- );
- if (!EFI_ERROR (Status)) {
- AddSortedDriverBindingProtocol (
- DriverImageHandle,
- &NumberOfSortedDriverBindingProtocols,
- SortedDriverBindingProtocols,
- DriverBindingHandleCount,
- DriverBindingHandleBuffer,
- TRUE
- );
- }
- } while (!EFI_ERROR (Status));
- }
-
- //
- // Add the Driver Family Override Protocol drivers for ControllerHandle
- //
- Status = CoreLocateProtocol (
- &gEfiDriverFamilyOverrideProtocolGuid,
- NULL,
- (VOID **)&DriverFamilyOverride
- );
- while (!EFI_ERROR (Status) && (DriverFamilyOverride != NULL)) {
- HighestIndex = DriverBindingHandleCount;
- HighestVersion = 0;
- for (Index = 0; Index < DriverBindingHandleCount; Index++) {
- Status = CoreHandleProtocol (
- DriverBindingHandleBuffer[Index],
- &gEfiDriverFamilyOverrideProtocolGuid,
- (VOID **)&DriverFamilyOverride
- );
- if (!EFI_ERROR (Status) && (DriverFamilyOverride != NULL)) {
- DriverFamilyOverrideVersion = DriverFamilyOverride->GetVersion (DriverFamilyOverride);
- if ((HighestIndex == DriverBindingHandleCount) || (DriverFamilyOverrideVersion > HighestVersion)) {
- HighestVersion = DriverFamilyOverrideVersion;
- HighestIndex = Index;
- }
- }
- }
-
- if (HighestIndex == DriverBindingHandleCount) {
- break;
- }
-
- AddSortedDriverBindingProtocol (
- DriverBindingHandleBuffer[HighestIndex],
- &NumberOfSortedDriverBindingProtocols,
- SortedDriverBindingProtocols,
- DriverBindingHandleCount,
- DriverBindingHandleBuffer,
- FALSE
- );
- }
-
- //
- // Get the Bus Specific Driver Override Protocol instance on the Controller Handle
- //
- Status = CoreHandleProtocol (
- ControllerHandle,
- &gEfiBusSpecificDriverOverrideProtocolGuid,
- (VOID **)&BusSpecificDriverOverride
- );
- if (!EFI_ERROR (Status) && (BusSpecificDriverOverride != NULL)) {
- DriverImageHandle = NULL;
- do {
- Status = BusSpecificDriverOverride->GetDriver (
- BusSpecificDriverOverride,
- &DriverImageHandle
- );
- if (!EFI_ERROR (Status)) {
- AddSortedDriverBindingProtocol (
- DriverImageHandle,
- &NumberOfSortedDriverBindingProtocols,
- SortedDriverBindingProtocols,
- DriverBindingHandleCount,
- DriverBindingHandleBuffer,
- TRUE
- );
- }
- } while (!EFI_ERROR (Status));
- }
-
- //
- // Then add all the remaining Driver Binding Protocols
- //
- SortIndex = NumberOfSortedDriverBindingProtocols;
- for (Index = 0; Index < DriverBindingHandleCount; Index++) {
- AddSortedDriverBindingProtocol (
- DriverBindingHandleBuffer[Index],
- &NumberOfSortedDriverBindingProtocols,
- SortedDriverBindingProtocols,
- DriverBindingHandleCount,
- DriverBindingHandleBuffer,
- FALSE
- );
- }
-
- //
- // Free the Driver Binding Handle Buffer
- //
- CoreFreePool (DriverBindingHandleBuffer);
-
- //
- // If the number of Driver Binding Protocols has increased since this function started, then return
- // EFI_NOT_READY, so it will be restarted
- //
- Status = CoreLocateHandleBuffer (
- ByProtocol,
- &gEfiDriverBindingProtocolGuid,
- NULL,
- &NewDriverBindingHandleCount,
- &NewDriverBindingHandleBuffer
- );
- CoreFreePool (NewDriverBindingHandleBuffer);
- if (NewDriverBindingHandleCount > DriverBindingHandleCount) {
- //
- // Free any buffers that were allocated with AllocatePool()
- //
- CoreFreePool (SortedDriverBindingProtocols);
-
- return EFI_NOT_READY;
- }
-
- //
- // Sort the remaining DriverBinding Protocol based on their Version field from
- // highest to lowest.
- //
- for ( ; SortIndex < NumberOfSortedDriverBindingProtocols; SortIndex++) {
- HighestVersion = SortedDriverBindingProtocols[SortIndex]->Version;
- HighestIndex = SortIndex;
- for (Index = SortIndex + 1; Index < NumberOfSortedDriverBindingProtocols; Index++) {
- if (SortedDriverBindingProtocols[Index]->Version > HighestVersion) {
- HighestVersion = SortedDriverBindingProtocols[Index]->Version;
- HighestIndex = Index;
- }
- }
-
- if (SortIndex != HighestIndex) {
- DriverBinding = SortedDriverBindingProtocols[SortIndex];
- SortedDriverBindingProtocols[SortIndex] = SortedDriverBindingProtocols[HighestIndex];
- SortedDriverBindingProtocols[HighestIndex] = DriverBinding;
- }
- }
-
- //
- // Loop until no more drivers can be started on ControllerHandle
- //
- OneStarted = FALSE;
- do {
- //
- // Loop through the sorted Driver Binding Protocol Instances in order, and see if
- // any of the Driver Binding Protocols support the controller specified by
- // ControllerHandle.
- //
- DriverBinding = NULL;
- DriverFound = FALSE;
- for (Index = 0; (Index < NumberOfSortedDriverBindingProtocols) && !DriverFound; Index++) {
- if (SortedDriverBindingProtocols[Index] != NULL) {
- DriverBinding = SortedDriverBindingProtocols[Index];
- PERF_DRIVER_BINDING_SUPPORT_BEGIN (DriverBinding->DriverBindingHandle, ControllerHandle);
- Status = DriverBinding->Supported (
- DriverBinding,
- ControllerHandle,
- RemainingDevicePath
- );
- PERF_DRIVER_BINDING_SUPPORT_END (DriverBinding->DriverBindingHandle, ControllerHandle);
- if (!EFI_ERROR (Status)) {
- SortedDriverBindingProtocols[Index] = NULL;
- DriverFound = TRUE;
-
- //
- // A driver was found that supports ControllerHandle, so attempt to start the driver
- // on ControllerHandle.
- //
- PERF_DRIVER_BINDING_START_BEGIN (DriverBinding->DriverBindingHandle, ControllerHandle);
- Status = DriverBinding->Start (
- DriverBinding,
- ControllerHandle,
- RemainingDevicePath
- );
- PERF_DRIVER_BINDING_START_END (DriverBinding->DriverBindingHandle, ControllerHandle);
-
- if (!EFI_ERROR (Status)) {
- //
- // The driver was successfully started on ControllerHandle, so set a flag
- //
- OneStarted = TRUE;
- }
- }
- }
- }
- } while (DriverFound);
-
- //
- // Free any buffers that were allocated with AllocatePool()
- //
- CoreFreePool (SortedDriverBindingProtocols);
-
- //
- // If at least one driver was started on ControllerHandle, then return EFI_SUCCESS.
- //
- if (OneStarted) {
- return EFI_SUCCESS;
- }
-
- //
- // If no drivers started and RemainingDevicePath is an End Device Path Node, then return EFI_SUCCESS
- //
- if (RemainingDevicePath != NULL) {
- if (IsDevicePathEnd (RemainingDevicePath)) {
- return EFI_SUCCESS;
- }
- }
-
- //
- // Otherwise, no drivers were started on ControllerHandle, so return EFI_NOT_FOUND
- //
- return EFI_NOT_FOUND;
-}
-
-/**
- Disonnects a controller from a driver
-
- @param ControllerHandle ControllerHandle The handle of
- the controller from which
- driver(s) are to be
- disconnected.
- @param DriverImageHandle DriverImageHandle The driver to
- disconnect from ControllerHandle.
- @param ChildHandle ChildHandle The handle of the
- child to destroy.
-
- @retval EFI_SUCCESS One or more drivers were
- disconnected from the controller.
- @retval EFI_SUCCESS On entry, no drivers are managing
- ControllerHandle.
- @retval EFI_SUCCESS DriverImageHandle is not NULL,
- and on entry DriverImageHandle is
- not managing ControllerHandle.
- @retval EFI_INVALID_PARAMETER ControllerHandle is NULL.
- @retval EFI_INVALID_PARAMETER DriverImageHandle is not NULL,
- and it is not a valid EFI_HANDLE.
- @retval EFI_INVALID_PARAMETER ChildHandle is not NULL, and it
- is not a valid EFI_HANDLE.
- @retval EFI_OUT_OF_RESOURCES There are not enough resources
- available to disconnect any
- drivers from ControllerHandle.
- @retval EFI_DEVICE_ERROR The controller could not be
- disconnected because of a device
- error.
-
-**/
-EFI_STATUS
-EFIAPI
-CoreDisconnectController (
- IN EFI_HANDLE ControllerHandle,
- IN EFI_HANDLE DriverImageHandle OPTIONAL,
- IN EFI_HANDLE ChildHandle OPTIONAL
- )
-{
- EFI_STATUS Status;
- IHANDLE *Handle;
- EFI_HANDLE *DriverImageHandleBuffer;
- EFI_HANDLE *ChildBuffer;
- UINTN Index;
- UINTN HandleIndex;
- UINTN DriverImageHandleCount;
- UINTN ChildrenToStop;
- UINTN ChildBufferCount;
- UINTN StopCount;
- BOOLEAN Duplicate;
- BOOLEAN ChildHandleValid;
- BOOLEAN DriverImageHandleValid;
- LIST_ENTRY *Link;
- LIST_ENTRY *ProtLink;
- OPEN_PROTOCOL_DATA *OpenData;
- PROTOCOL_INTERFACE *Prot;
- EFI_DRIVER_BINDING_PROTOCOL *DriverBinding;
-
- //
- // Make sure ControllerHandle is valid
- //
- CoreAcquireProtocolLock ();
-
- Status = CoreValidateHandle (ControllerHandle);
- if (EFI_ERROR (Status)) {
- CoreReleaseProtocolLock ();
- return Status;
- }
-
- //
- // Make sure ChildHandle is valid if it is not NULL
- //
- if (ChildHandle != NULL) {
- Status = CoreValidateHandle (ChildHandle);
- if (EFI_ERROR (Status)) {
- CoreReleaseProtocolLock ();
- return Status;
- }
- }
-
- CoreReleaseProtocolLock ();
-
- Handle = ControllerHandle;
-
- //
- // Get list of drivers that are currently managing ControllerHandle
- //
- DriverImageHandleBuffer = NULL;
- DriverImageHandleCount = 1;
-
- if (DriverImageHandle == NULL) {
- //
- // Look at each protocol interface for a match
- //
- DriverImageHandleCount = 0;
-
- CoreAcquireProtocolLock ();
- for (Link = Handle->Protocols.ForwardLink; Link != &Handle->Protocols; Link = Link->ForwardLink) {
- Prot = CR (Link, PROTOCOL_INTERFACE, Link, PROTOCOL_INTERFACE_SIGNATURE);
- for (ProtLink = Prot->OpenList.ForwardLink;
- ProtLink != &Prot->OpenList;
- ProtLink = ProtLink->ForwardLink)
- {
- OpenData = CR (ProtLink, OPEN_PROTOCOL_DATA, Link, OPEN_PROTOCOL_DATA_SIGNATURE);
- if ((OpenData->Attributes & EFI_OPEN_PROTOCOL_BY_DRIVER) != 0) {
- DriverImageHandleCount++;
- }
- }
- }
-
- CoreReleaseProtocolLock ();
-
- //
- // If there are no drivers managing this controller, then return EFI_SUCCESS
- //
- if (DriverImageHandleCount == 0) {
- Status = EFI_SUCCESS;
- goto Done;
- }
-
- DriverImageHandleBuffer = AllocatePool (sizeof (EFI_HANDLE) * DriverImageHandleCount);
- if (DriverImageHandleBuffer == NULL) {
- Status = EFI_OUT_OF_RESOURCES;
- goto Done;
- }
-
- DriverImageHandleCount = 0;
-
- CoreAcquireProtocolLock ();
- for (Link = Handle->Protocols.ForwardLink; Link != &Handle->Protocols; Link = Link->ForwardLink) {
- Prot = CR (Link, PROTOCOL_INTERFACE, Link, PROTOCOL_INTERFACE_SIGNATURE);
- for (ProtLink = Prot->OpenList.ForwardLink;
- ProtLink != &Prot->OpenList;
- ProtLink = ProtLink->ForwardLink)
- {
- OpenData = CR (ProtLink, OPEN_PROTOCOL_DATA, Link, OPEN_PROTOCOL_DATA_SIGNATURE);
- if ((OpenData->Attributes & EFI_OPEN_PROTOCOL_BY_DRIVER) != 0) {
- Duplicate = FALSE;
- for (Index = 0; Index < DriverImageHandleCount; Index++) {
- if (DriverImageHandleBuffer[Index] == OpenData->AgentHandle) {
- Duplicate = TRUE;
- break;
- }
- }
-
- if (!Duplicate) {
- DriverImageHandleBuffer[DriverImageHandleCount] = OpenData->AgentHandle;
- DriverImageHandleCount++;
- }
- }
- }
- }
-
- CoreReleaseProtocolLock ();
- }
-
- StopCount = 0;
- for (HandleIndex = 0; HandleIndex < DriverImageHandleCount; HandleIndex++) {
- if (DriverImageHandleBuffer != NULL) {
- DriverImageHandle = DriverImageHandleBuffer[HandleIndex];
- }
-
- //
- // Get the Driver Binding Protocol of the driver that is managing this controller
- //
- Status = CoreHandleProtocol (
- DriverImageHandle,
- &gEfiDriverBindingProtocolGuid,
- (VOID **)&DriverBinding
- );
- if (EFI_ERROR (Status) || (DriverBinding == NULL)) {
- Status = EFI_INVALID_PARAMETER;
- goto Done;
- }
-
- //
- // Look at each protocol interface for a match
- //
- DriverImageHandleValid = FALSE;
- ChildBufferCount = 0;
-
- CoreAcquireProtocolLock ();
- for (Link = Handle->Protocols.ForwardLink; Link != &Handle->Protocols; Link = Link->ForwardLink) {
- Prot = CR (Link, PROTOCOL_INTERFACE, Link, PROTOCOL_INTERFACE_SIGNATURE);
- for (ProtLink = Prot->OpenList.ForwardLink;
- ProtLink != &Prot->OpenList;
- ProtLink = ProtLink->ForwardLink)
- {
- OpenData = CR (ProtLink, OPEN_PROTOCOL_DATA, Link, OPEN_PROTOCOL_DATA_SIGNATURE);
- if (OpenData->AgentHandle == DriverImageHandle) {
- if ((OpenData->Attributes & EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER) != 0) {
- ChildBufferCount++;
- }
-
- if ((OpenData->Attributes & EFI_OPEN_PROTOCOL_BY_DRIVER) != 0) {
- DriverImageHandleValid = TRUE;
- }
- }
- }
- }
-
- CoreReleaseProtocolLock ();
-
- if (DriverImageHandleValid) {
- ChildHandleValid = FALSE;
- ChildBuffer = NULL;
- if (ChildBufferCount != 0) {
- ChildBuffer = AllocatePool (sizeof (EFI_HANDLE) * ChildBufferCount);
- if (ChildBuffer == NULL) {
- Status = EFI_OUT_OF_RESOURCES;
- goto Done;
- }
-
- ChildBufferCount = 0;
-
- CoreAcquireProtocolLock ();
- for (Link = Handle->Protocols.ForwardLink; Link != &Handle->Protocols; Link = Link->ForwardLink) {
- Prot = CR (Link, PROTOCOL_INTERFACE, Link, PROTOCOL_INTERFACE_SIGNATURE);
- for (ProtLink = Prot->OpenList.ForwardLink;
- ProtLink != &Prot->OpenList;
- ProtLink = ProtLink->ForwardLink)
- {
- OpenData = CR (ProtLink, OPEN_PROTOCOL_DATA, Link, OPEN_PROTOCOL_DATA_SIGNATURE);
- if ((OpenData->AgentHandle == DriverImageHandle) &&
- ((OpenData->Attributes & EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER) != 0))
- {
- Duplicate = FALSE;
- for (Index = 0; Index < ChildBufferCount; Index++) {
- if (ChildBuffer[Index] == OpenData->ControllerHandle) {
- Duplicate = TRUE;
- break;
- }
- }
-
- if (!Duplicate) {
- ChildBuffer[ChildBufferCount] = OpenData->ControllerHandle;
- if (ChildHandle == ChildBuffer[ChildBufferCount]) {
- ChildHandleValid = TRUE;
- }
-
- ChildBufferCount++;
- }
- }
- }
- }
-
- CoreReleaseProtocolLock ();
- }
-
- if ((ChildHandle == NULL) || ChildHandleValid) {
- ChildrenToStop = 0;
- Status = EFI_SUCCESS;
- if (ChildBufferCount > 0) {
- if (ChildHandle != NULL) {
- ChildrenToStop = 1;
- Status = DriverBinding->Stop (DriverBinding, ControllerHandle, ChildrenToStop, &ChildHandle);
- } else {
- ChildrenToStop = ChildBufferCount;
- Status = DriverBinding->Stop (DriverBinding, ControllerHandle, ChildrenToStop, ChildBuffer);
- }
- }
-
- if (!EFI_ERROR (Status) && ((ChildHandle == NULL) || (ChildBufferCount == ChildrenToStop))) {
- Status = DriverBinding->Stop (DriverBinding, ControllerHandle, 0, NULL);
- }
-
- if (!EFI_ERROR (Status)) {
- StopCount++;
- }
- }
-
- if (ChildBuffer != NULL) {
- CoreFreePool (ChildBuffer);
- }
- }
- }
-
- if (StopCount > 0) {
- Status = EFI_SUCCESS;
- } else {
- Status = EFI_NOT_FOUND;
- }
-
-Done:
-
- if (DriverImageHandleBuffer != NULL) {
- CoreFreePool (DriverImageHandleBuffer);
- }
-
- return Status;
-}
+/** @file
+ Support functions to connect/disconnect UEFI Driver model Protocol
+
+Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "DxeMain.h"
+#include "Handle.h"
+
+//
+// Driver Support Functions
+//
+
+/**
+ Connects one or more drivers to a controller.
+
+ @param ControllerHandle The handle of the controller to which driver(s) are to be connected.
+ @param DriverImageHandle A pointer to an ordered list handles that support the
+ EFI_DRIVER_BINDING_PROTOCOL.
+ @param RemainingDevicePath A pointer to the device path that specifies a child of the
+ controller specified by ControllerHandle.
+ @param Recursive If TRUE, then ConnectController() is called recursively
+ until the entire tree of controllers below the controller specified
+ by ControllerHandle have been created. If FALSE, then
+ the tree of controllers is only expanded one level.
+
+ @retval EFI_SUCCESS 1) One or more drivers were connected to ControllerHandle.
+ 2) No drivers were connected to ControllerHandle, but
+ RemainingDevicePath is not NULL, and it is an End Device
+ Path Node.
+ @retval EFI_INVALID_PARAMETER ControllerHandle is NULL.
+ @retval EFI_NOT_FOUND 1) There are no EFI_DRIVER_BINDING_PROTOCOL instances
+ present in the system.
+ 2) No drivers were connected to ControllerHandle.
+ @retval EFI_SECURITY_VIOLATION
+ The user has no permission to start UEFI device drivers on the device path
+ associated with the ControllerHandle or specified by the RemainingDevicePath.
+
+**/
+EFI_STATUS
+EFIAPI
+CoreConnectController (
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_HANDLE *DriverImageHandle OPTIONAL,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL,
+ IN BOOLEAN Recursive
+ )
+{
+ EFI_STATUS Status;
+ EFI_STATUS ReturnStatus;
+ IHANDLE *Handle;
+ PROTOCOL_INTERFACE *Prot;
+ LIST_ENTRY *Link;
+ LIST_ENTRY *ProtLink;
+ OPEN_PROTOCOL_DATA *OpenData;
+ EFI_DEVICE_PATH_PROTOCOL *AlignedRemainingDevicePath;
+ EFI_HANDLE *ChildHandleBuffer;
+ UINTN ChildHandleCount;
+ UINTN Index;
+ UINTN HandleFilePathSize;
+ UINTN RemainingDevicePathSize;
+ EFI_DEVICE_PATH_PROTOCOL *HandleFilePath;
+ EFI_DEVICE_PATH_PROTOCOL *FilePath;
+ EFI_DEVICE_PATH_PROTOCOL *TempFilePath;
+
+ //
+ // Make sure ControllerHandle is valid
+ //
+ CoreAcquireProtocolLock ();
+
+ Status = CoreValidateHandle (ControllerHandle);
+
+ CoreReleaseProtocolLock ();
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if (gSecurity2 != NULL) {
+ //
+ // Check whether the user has permission to start UEFI device drivers.
+ //
+ Status = CoreHandleProtocol (ControllerHandle, &gEfiDevicePathProtocolGuid, (VOID **)&HandleFilePath);
+ if (!EFI_ERROR (Status)) {
+ ASSERT (HandleFilePath != NULL);
+ FilePath = HandleFilePath;
+ TempFilePath = NULL;
+ if ((RemainingDevicePath != NULL) && !Recursive) {
+ HandleFilePathSize = GetDevicePathSize (HandleFilePath) - sizeof (EFI_DEVICE_PATH_PROTOCOL);
+ RemainingDevicePathSize = GetDevicePathSize (RemainingDevicePath);
+ TempFilePath = AllocateZeroPool (HandleFilePathSize + RemainingDevicePathSize);
+ ASSERT (TempFilePath != NULL);
+ CopyMem (TempFilePath, HandleFilePath, HandleFilePathSize);
+ CopyMem ((UINT8 *)TempFilePath + HandleFilePathSize, RemainingDevicePath, RemainingDevicePathSize);
+ FilePath = TempFilePath;
+ }
+
+ Status = gSecurity2->FileAuthentication (
+ gSecurity2,
+ FilePath,
+ NULL,
+ 0,
+ FALSE
+ );
+ if (TempFilePath != NULL) {
+ FreePool (TempFilePath);
+ }
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+ }
+
+ Handle = ControllerHandle;
+
+ //
+ // Make a copy of RemainingDevicePath to guanatee it is aligned
+ //
+ AlignedRemainingDevicePath = NULL;
+ if (RemainingDevicePath != NULL) {
+ AlignedRemainingDevicePath = DuplicateDevicePath (RemainingDevicePath);
+
+ if (AlignedRemainingDevicePath == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ }
+
+ //
+ // Connect all drivers to ControllerHandle
+ // If CoreConnectSingleController returns EFI_NOT_READY, then the number of
+ // Driver Binding Protocols in the handle database has increased during the call
+ // so the connect operation must be restarted
+ //
+ do {
+ ReturnStatus = CoreConnectSingleController (
+ ControllerHandle,
+ DriverImageHandle,
+ AlignedRemainingDevicePath
+ );
+ } while (ReturnStatus == EFI_NOT_READY);
+
+ //
+ // Free the aligned copy of RemainingDevicePath
+ //
+ if (AlignedRemainingDevicePath != NULL) {
+ CoreFreePool (AlignedRemainingDevicePath);
+ }
+
+ //
+ // If recursive, then connect all drivers to all of ControllerHandle's children
+ //
+ if (Recursive) {
+ //
+ // Acquire the protocol lock on the handle database so the child handles can be collected
+ //
+ CoreAcquireProtocolLock ();
+
+ //
+ // Make sure the DriverBindingHandle is valid
+ //
+ Status = CoreValidateHandle (ControllerHandle);
+ if (EFI_ERROR (Status)) {
+ //
+ // Release the protocol lock on the handle database
+ //
+ CoreReleaseProtocolLock ();
+
+ return ReturnStatus;
+ }
+
+ //
+ // Count ControllerHandle's children
+ //
+ for (Link = Handle->Protocols.ForwardLink, ChildHandleCount = 0; Link != &Handle->Protocols; Link = Link->ForwardLink) {
+ Prot = CR (Link, PROTOCOL_INTERFACE, Link, PROTOCOL_INTERFACE_SIGNATURE);
+ for (ProtLink = Prot->OpenList.ForwardLink;
+ ProtLink != &Prot->OpenList;
+ ProtLink = ProtLink->ForwardLink)
+ {
+ OpenData = CR (ProtLink, OPEN_PROTOCOL_DATA, Link, OPEN_PROTOCOL_DATA_SIGNATURE);
+ if ((OpenData->Attributes & EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER) != 0) {
+ ChildHandleCount++;
+ }
+ }
+ }
+
+ //
+ // Allocate a handle buffer for ControllerHandle's children
+ //
+ ChildHandleBuffer = AllocatePool (ChildHandleCount * sizeof (EFI_HANDLE));
+ if (ChildHandleBuffer == NULL) {
+ CoreReleaseProtocolLock ();
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ //
+ // Fill in a handle buffer with ControllerHandle's children
+ //
+ for (Link = Handle->Protocols.ForwardLink, ChildHandleCount = 0; Link != &Handle->Protocols; Link = Link->ForwardLink) {
+ Prot = CR (Link, PROTOCOL_INTERFACE, Link, PROTOCOL_INTERFACE_SIGNATURE);
+ for (ProtLink = Prot->OpenList.ForwardLink;
+ ProtLink != &Prot->OpenList;
+ ProtLink = ProtLink->ForwardLink)
+ {
+ OpenData = CR (ProtLink, OPEN_PROTOCOL_DATA, Link, OPEN_PROTOCOL_DATA_SIGNATURE);
+ if ((OpenData->Attributes & EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER) != 0) {
+ ChildHandleBuffer[ChildHandleCount] = OpenData->ControllerHandle;
+ ChildHandleCount++;
+ }
+ }
+ }
+
+ //
+ // Release the protocol lock on the handle database
+ //
+ CoreReleaseProtocolLock ();
+
+ //
+ // Recursively connect each child handle
+ //
+ for (Index = 0; Index < ChildHandleCount; Index++) {
+ CoreConnectController (
+ ChildHandleBuffer[Index],
+ NULL,
+ NULL,
+ TRUE
+ );
+ }
+
+ //
+ // Free the handle buffer of ControllerHandle's children
+ //
+ CoreFreePool (ChildHandleBuffer);
+ }
+
+ return ReturnStatus;
+}
+
+/**
+ Add Driver Binding Protocols from Context Driver Image Handles to sorted
+ Driver Binding Protocol list.
+
+ @param DriverBindingHandle Handle of the driver binding
+ protocol.
+ @param NumberOfSortedDriverBindingProtocols Number Of sorted driver binding
+ protocols
+ @param SortedDriverBindingProtocols The sorted protocol list.
+ @param DriverBindingHandleCount Driver Binding Handle Count.
+ @param DriverBindingHandleBuffer The buffer of driver binding
+ protocol to be modified.
+ @param IsImageHandle Indicate whether
+ DriverBindingHandle is an image
+ handle
+
+ @return None.
+
+**/
+VOID
+AddSortedDriverBindingProtocol (
+ IN EFI_HANDLE DriverBindingHandle,
+ IN OUT UINTN *NumberOfSortedDriverBindingProtocols,
+ IN OUT EFI_DRIVER_BINDING_PROTOCOL **SortedDriverBindingProtocols,
+ IN UINTN DriverBindingHandleCount,
+ IN OUT EFI_HANDLE *DriverBindingHandleBuffer,
+ IN BOOLEAN IsImageHandle
+ )
+{
+ EFI_STATUS Status;
+ EFI_DRIVER_BINDING_PROTOCOL *DriverBinding;
+ UINTN Index;
+
+ //
+ // Make sure the DriverBindingHandle is valid
+ //
+ CoreAcquireProtocolLock ();
+
+ Status = CoreValidateHandle (DriverBindingHandle);
+
+ CoreReleaseProtocolLock ();
+
+ if (EFI_ERROR (Status)) {
+ return;
+ }
+
+ //
+ // If IsImageHandle is TRUE, then DriverBindingHandle is an image handle
+ // Find all the DriverBindingHandles associated with that image handle and add them to the sorted list
+ //
+ if (IsImageHandle) {
+ //
+ // Loop through all the Driver Binding Handles
+ //
+ for (Index = 0; Index < DriverBindingHandleCount; Index++) {
+ //
+ // Retrieve the Driver Binding Protocol associated with each Driver Binding Handle
+ //
+ Status = CoreHandleProtocol (
+ DriverBindingHandleBuffer[Index],
+ &gEfiDriverBindingProtocolGuid,
+ (VOID **)&DriverBinding
+ );
+ if (EFI_ERROR (Status) || (DriverBinding == NULL)) {
+ continue;
+ }
+
+ //
+ // If the ImageHandle associated with DriverBinding matches DriverBindingHandle,
+ // then add the DriverBindingProtocol[Index] to the sorted list
+ //
+ if (DriverBinding->ImageHandle == DriverBindingHandle) {
+ AddSortedDriverBindingProtocol (
+ DriverBindingHandleBuffer[Index],
+ NumberOfSortedDriverBindingProtocols,
+ SortedDriverBindingProtocols,
+ DriverBindingHandleCount,
+ DriverBindingHandleBuffer,
+ FALSE
+ );
+ }
+ }
+
+ return;
+ }
+
+ //
+ // Retrieve the Driver Binding Protocol from DriverBindingHandle
+ //
+ Status = CoreHandleProtocol (
+ DriverBindingHandle,
+ &gEfiDriverBindingProtocolGuid,
+ (VOID **)&DriverBinding
+ );
+ //
+ // If DriverBindingHandle does not support the Driver Binding Protocol then return
+ //
+ if (EFI_ERROR (Status) || (DriverBinding == NULL)) {
+ return;
+ }
+
+ //
+ // See if DriverBinding is already in the sorted list
+ //
+ for (Index = 0; Index < *NumberOfSortedDriverBindingProtocols && Index < DriverBindingHandleCount; Index++) {
+ if (DriverBinding == SortedDriverBindingProtocols[Index]) {
+ return;
+ }
+ }
+
+ //
+ // Add DriverBinding to the end of the list
+ //
+ if (*NumberOfSortedDriverBindingProtocols < DriverBindingHandleCount) {
+ SortedDriverBindingProtocols[*NumberOfSortedDriverBindingProtocols] = DriverBinding;
+ }
+
+ *NumberOfSortedDriverBindingProtocols = *NumberOfSortedDriverBindingProtocols + 1;
+
+ //
+ // Mark the cooresponding handle in DriverBindingHandleBuffer as used
+ //
+ for (Index = 0; Index < DriverBindingHandleCount; Index++) {
+ if (DriverBindingHandleBuffer[Index] == DriverBindingHandle) {
+ DriverBindingHandleBuffer[Index] = NULL;
+ }
+ }
+}
+
+/**
+ Connects a controller to a driver.
+
+ @param ControllerHandle Handle of the controller to be
+ connected.
+ @param ContextDriverImageHandles DriverImageHandle A pointer to an
+ ordered list of driver image
+ handles.
+ @param RemainingDevicePath RemainingDevicePath A pointer to
+ the device path that specifies a
+ child of the controller
+ specified by ControllerHandle.
+
+ @retval EFI_SUCCESS One or more drivers were
+ connected to ControllerHandle.
+ @retval EFI_OUT_OF_RESOURCES No enough system resources to
+ complete the request.
+ @retval EFI_NOT_FOUND No drivers were connected to
+ ControllerHandle.
+
+**/
+EFI_STATUS
+CoreConnectSingleController (
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_HANDLE *ContextDriverImageHandles OPTIONAL,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+ UINTN Index;
+ EFI_HANDLE DriverImageHandle;
+ EFI_PLATFORM_DRIVER_OVERRIDE_PROTOCOL *PlatformDriverOverride;
+ EFI_BUS_SPECIFIC_DRIVER_OVERRIDE_PROTOCOL *BusSpecificDriverOverride;
+ UINTN DriverBindingHandleCount;
+ EFI_HANDLE *DriverBindingHandleBuffer;
+ UINTN NewDriverBindingHandleCount;
+ EFI_HANDLE *NewDriverBindingHandleBuffer;
+ EFI_DRIVER_BINDING_PROTOCOL *DriverBinding;
+ EFI_DRIVER_FAMILY_OVERRIDE_PROTOCOL *DriverFamilyOverride;
+ UINTN NumberOfSortedDriverBindingProtocols;
+ EFI_DRIVER_BINDING_PROTOCOL **SortedDriverBindingProtocols;
+ UINT32 DriverFamilyOverrideVersion;
+ UINT32 HighestVersion;
+ UINTN HighestIndex;
+ UINTN SortIndex;
+ BOOLEAN OneStarted;
+ BOOLEAN DriverFound;
+
+ //
+ // Initialize local variables
+ //
+ DriverBindingHandleCount = 0;
+ DriverBindingHandleBuffer = NULL;
+ NumberOfSortedDriverBindingProtocols = 0;
+ SortedDriverBindingProtocols = NULL;
+ PlatformDriverOverride = NULL;
+ NewDriverBindingHandleBuffer = NULL;
+
+ //
+ // Get list of all Driver Binding Protocol Instances
+ //
+ Status = CoreLocateHandleBuffer (
+ ByProtocol,
+ &gEfiDriverBindingProtocolGuid,
+ NULL,
+ &DriverBindingHandleCount,
+ &DriverBindingHandleBuffer
+ );
+ if (EFI_ERROR (Status) || (DriverBindingHandleCount == 0)) {
+ return EFI_NOT_FOUND;
+ }
+
+ //
+ // Allocate a duplicate array for the sorted Driver Binding Protocol Instances
+ //
+ SortedDriverBindingProtocols = AllocatePool (sizeof (VOID *) * DriverBindingHandleCount);
+ if (SortedDriverBindingProtocols == NULL) {
+ CoreFreePool (DriverBindingHandleBuffer);
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ //
+ // Add Driver Binding Protocols from Context Driver Image Handles first
+ //
+ if (ContextDriverImageHandles != NULL) {
+ for (Index = 0; ContextDriverImageHandles[Index] != NULL; Index++) {
+ AddSortedDriverBindingProtocol (
+ ContextDriverImageHandles[Index],
+ &NumberOfSortedDriverBindingProtocols,
+ SortedDriverBindingProtocols,
+ DriverBindingHandleCount,
+ DriverBindingHandleBuffer,
+ FALSE
+ );
+ }
+ }
+
+ //
+ // Add the Platform Driver Override Protocol drivers for ControllerHandle next
+ //
+ Status = CoreLocateProtocol (
+ &gEfiPlatformDriverOverrideProtocolGuid,
+ NULL,
+ (VOID **)&PlatformDriverOverride
+ );
+ if (!EFI_ERROR (Status) && (PlatformDriverOverride != NULL)) {
+ DriverImageHandle = NULL;
+ do {
+ Status = PlatformDriverOverride->GetDriver (
+ PlatformDriverOverride,
+ ControllerHandle,
+ &DriverImageHandle
+ );
+ if (!EFI_ERROR (Status)) {
+ AddSortedDriverBindingProtocol (
+ DriverImageHandle,
+ &NumberOfSortedDriverBindingProtocols,
+ SortedDriverBindingProtocols,
+ DriverBindingHandleCount,
+ DriverBindingHandleBuffer,
+ TRUE
+ );
+ }
+ } while (!EFI_ERROR (Status));
+ }
+
+ //
+ // Add the Driver Family Override Protocol drivers for ControllerHandle
+ //
+ Status = CoreLocateProtocol (
+ &gEfiDriverFamilyOverrideProtocolGuid,
+ NULL,
+ (VOID **)&DriverFamilyOverride
+ );
+ while (!EFI_ERROR (Status) && (DriverFamilyOverride != NULL)) {
+ HighestIndex = DriverBindingHandleCount;
+ HighestVersion = 0;
+ for (Index = 0; Index < DriverBindingHandleCount; Index++) {
+ Status = CoreHandleProtocol (
+ DriverBindingHandleBuffer[Index],
+ &gEfiDriverFamilyOverrideProtocolGuid,
+ (VOID **)&DriverFamilyOverride
+ );
+ if (!EFI_ERROR (Status) && (DriverFamilyOverride != NULL)) {
+ DriverFamilyOverrideVersion = DriverFamilyOverride->GetVersion (DriverFamilyOverride);
+ if ((HighestIndex == DriverBindingHandleCount) || (DriverFamilyOverrideVersion > HighestVersion)) {
+ HighestVersion = DriverFamilyOverrideVersion;
+ HighestIndex = Index;
+ }
+ }
+ }
+
+ if (HighestIndex == DriverBindingHandleCount) {
+ break;
+ }
+
+ AddSortedDriverBindingProtocol (
+ DriverBindingHandleBuffer[HighestIndex],
+ &NumberOfSortedDriverBindingProtocols,
+ SortedDriverBindingProtocols,
+ DriverBindingHandleCount,
+ DriverBindingHandleBuffer,
+ FALSE
+ );
+ }
+
+ //
+ // Get the Bus Specific Driver Override Protocol instance on the Controller Handle
+ //
+ Status = CoreHandleProtocol (
+ ControllerHandle,
+ &gEfiBusSpecificDriverOverrideProtocolGuid,
+ (VOID **)&BusSpecificDriverOverride
+ );
+ if (!EFI_ERROR (Status) && (BusSpecificDriverOverride != NULL)) {
+ DriverImageHandle = NULL;
+ do {
+ Status = BusSpecificDriverOverride->GetDriver (
+ BusSpecificDriverOverride,
+ &DriverImageHandle
+ );
+ if (!EFI_ERROR (Status)) {
+ AddSortedDriverBindingProtocol (
+ DriverImageHandle,
+ &NumberOfSortedDriverBindingProtocols,
+ SortedDriverBindingProtocols,
+ DriverBindingHandleCount,
+ DriverBindingHandleBuffer,
+ TRUE
+ );
+ }
+ } while (!EFI_ERROR (Status));
+ }
+
+ //
+ // Then add all the remaining Driver Binding Protocols
+ //
+ SortIndex = NumberOfSortedDriverBindingProtocols;
+ for (Index = 0; Index < DriverBindingHandleCount; Index++) {
+ AddSortedDriverBindingProtocol (
+ DriverBindingHandleBuffer[Index],
+ &NumberOfSortedDriverBindingProtocols,
+ SortedDriverBindingProtocols,
+ DriverBindingHandleCount,
+ DriverBindingHandleBuffer,
+ FALSE
+ );
+ }
+
+ //
+ // Free the Driver Binding Handle Buffer
+ //
+ CoreFreePool (DriverBindingHandleBuffer);
+
+ //
+ // If the number of Driver Binding Protocols has increased since this function started, then return
+ // EFI_NOT_READY, so it will be restarted
+ //
+ Status = CoreLocateHandleBuffer (
+ ByProtocol,
+ &gEfiDriverBindingProtocolGuid,
+ NULL,
+ &NewDriverBindingHandleCount,
+ &NewDriverBindingHandleBuffer
+ );
+ CoreFreePool (NewDriverBindingHandleBuffer);
+ if (NewDriverBindingHandleCount > DriverBindingHandleCount) {
+ //
+ // Free any buffers that were allocated with AllocatePool()
+ //
+ CoreFreePool (SortedDriverBindingProtocols);
+
+ return EFI_NOT_READY;
+ }
+
+ //
+ // Sort the remaining DriverBinding Protocol based on their Version field from
+ // highest to lowest.
+ //
+ for ( ; SortIndex < NumberOfSortedDriverBindingProtocols; SortIndex++) {
+ HighestVersion = SortedDriverBindingProtocols[SortIndex]->Version;
+ HighestIndex = SortIndex;
+ for (Index = SortIndex + 1; Index < NumberOfSortedDriverBindingProtocols; Index++) {
+ if (SortedDriverBindingProtocols[Index]->Version > HighestVersion) {
+ HighestVersion = SortedDriverBindingProtocols[Index]->Version;
+ HighestIndex = Index;
+ }
+ }
+
+ if (SortIndex != HighestIndex) {
+ DriverBinding = SortedDriverBindingProtocols[SortIndex];
+ SortedDriverBindingProtocols[SortIndex] = SortedDriverBindingProtocols[HighestIndex];
+ SortedDriverBindingProtocols[HighestIndex] = DriverBinding;
+ }
+ }
+
+ //
+ // Loop until no more drivers can be started on ControllerHandle
+ //
+ OneStarted = FALSE;
+ do {
+ //
+ // Loop through the sorted Driver Binding Protocol Instances in order, and see if
+ // any of the Driver Binding Protocols support the controller specified by
+ // ControllerHandle.
+ //
+ DriverBinding = NULL;
+ DriverFound = FALSE;
+ for (Index = 0; (Index < NumberOfSortedDriverBindingProtocols) && !DriverFound; Index++) {
+ if (SortedDriverBindingProtocols[Index] != NULL) {
+ DriverBinding = SortedDriverBindingProtocols[Index];
+ PERF_DRIVER_BINDING_SUPPORT_BEGIN (DriverBinding->DriverBindingHandle, ControllerHandle);
+ Status = DriverBinding->Supported (
+ DriverBinding,
+ ControllerHandle,
+ RemainingDevicePath
+ );
+ PERF_DRIVER_BINDING_SUPPORT_END (DriverBinding->DriverBindingHandle, ControllerHandle);
+ if (!EFI_ERROR (Status)) {
+ SortedDriverBindingProtocols[Index] = NULL;
+ DriverFound = TRUE;
+
+ //
+ // A driver was found that supports ControllerHandle, so attempt to start the driver
+ // on ControllerHandle.
+ //
+ PERF_DRIVER_BINDING_START_BEGIN (DriverBinding->DriverBindingHandle, ControllerHandle);
+ Status = DriverBinding->Start (
+ DriverBinding,
+ ControllerHandle,
+ RemainingDevicePath
+ );
+ PERF_DRIVER_BINDING_START_END (DriverBinding->DriverBindingHandle, ControllerHandle);
+
+ if (!EFI_ERROR (Status)) {
+ //
+ // The driver was successfully started on ControllerHandle, so set a flag
+ //
+ OneStarted = TRUE;
+ }
+ }
+ }
+ }
+ } while (DriverFound);
+
+ //
+ // Free any buffers that were allocated with AllocatePool()
+ //
+ CoreFreePool (SortedDriverBindingProtocols);
+
+ //
+ // If at least one driver was started on ControllerHandle, then return EFI_SUCCESS.
+ //
+ if (OneStarted) {
+ return EFI_SUCCESS;
+ }
+
+ //
+ // If no drivers started and RemainingDevicePath is an End Device Path Node, then return EFI_SUCCESS
+ //
+ if (RemainingDevicePath != NULL) {
+ if (IsDevicePathEnd (RemainingDevicePath)) {
+ return EFI_SUCCESS;
+ }
+ }
+
+ //
+ // Otherwise, no drivers were started on ControllerHandle, so return EFI_NOT_FOUND
+ //
+ return EFI_NOT_FOUND;
+}
+
+/**
+ Disonnects a controller from a driver
+
+ @param ControllerHandle ControllerHandle The handle of
+ the controller from which
+ driver(s) are to be
+ disconnected.
+ @param DriverImageHandle DriverImageHandle The driver to
+ disconnect from ControllerHandle.
+ @param ChildHandle ChildHandle The handle of the
+ child to destroy.
+
+ @retval EFI_SUCCESS One or more drivers were
+ disconnected from the controller.
+ @retval EFI_SUCCESS On entry, no drivers are managing
+ ControllerHandle.
+ @retval EFI_SUCCESS DriverImageHandle is not NULL,
+ and on entry DriverImageHandle is
+ not managing ControllerHandle.
+ @retval EFI_INVALID_PARAMETER ControllerHandle is NULL.
+ @retval EFI_INVALID_PARAMETER DriverImageHandle is not NULL,
+ and it is not a valid EFI_HANDLE.
+ @retval EFI_INVALID_PARAMETER ChildHandle is not NULL, and it
+ is not a valid EFI_HANDLE.
+ @retval EFI_OUT_OF_RESOURCES There are not enough resources
+ available to disconnect any
+ drivers from ControllerHandle.
+ @retval EFI_DEVICE_ERROR The controller could not be
+ disconnected because of a device
+ error.
+
+**/
+EFI_STATUS
+EFIAPI
+CoreDisconnectController (
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_HANDLE DriverImageHandle OPTIONAL,
+ IN EFI_HANDLE ChildHandle OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+ IHANDLE *Handle;
+ EFI_HANDLE *DriverImageHandleBuffer;
+ EFI_HANDLE *ChildBuffer;
+ UINTN Index;
+ UINTN HandleIndex;
+ UINTN DriverImageHandleCount;
+ UINTN ChildrenToStop;
+ UINTN ChildBufferCount;
+ UINTN StopCount;
+ BOOLEAN Duplicate;
+ BOOLEAN ChildHandleValid;
+ BOOLEAN DriverImageHandleValid;
+ LIST_ENTRY *Link;
+ LIST_ENTRY *ProtLink;
+ OPEN_PROTOCOL_DATA *OpenData;
+ PROTOCOL_INTERFACE *Prot;
+ EFI_DRIVER_BINDING_PROTOCOL *DriverBinding;
+
+ //
+ // Make sure ControllerHandle is valid
+ //
+ CoreAcquireProtocolLock ();
+
+ Status = CoreValidateHandle (ControllerHandle);
+ if (EFI_ERROR (Status)) {
+ CoreReleaseProtocolLock ();
+ return Status;
+ }
+
+ //
+ // Make sure ChildHandle is valid if it is not NULL
+ //
+ if (ChildHandle != NULL) {
+ Status = CoreValidateHandle (ChildHandle);
+ if (EFI_ERROR (Status)) {
+ CoreReleaseProtocolLock ();
+ return Status;
+ }
+ }
+
+ CoreReleaseProtocolLock ();
+
+ Handle = ControllerHandle;
+
+ //
+ // Get list of drivers that are currently managing ControllerHandle
+ //
+ DriverImageHandleBuffer = NULL;
+ DriverImageHandleCount = 1;
+
+ if (DriverImageHandle == NULL) {
+ //
+ // Look at each protocol interface for a match
+ //
+ DriverImageHandleCount = 0;
+
+ CoreAcquireProtocolLock ();
+ for (Link = Handle->Protocols.ForwardLink; Link != &Handle->Protocols; Link = Link->ForwardLink) {
+ Prot = CR (Link, PROTOCOL_INTERFACE, Link, PROTOCOL_INTERFACE_SIGNATURE);
+ for (ProtLink = Prot->OpenList.ForwardLink;
+ ProtLink != &Prot->OpenList;
+ ProtLink = ProtLink->ForwardLink)
+ {
+ OpenData = CR (ProtLink, OPEN_PROTOCOL_DATA, Link, OPEN_PROTOCOL_DATA_SIGNATURE);
+ if ((OpenData->Attributes & EFI_OPEN_PROTOCOL_BY_DRIVER) != 0) {
+ DriverImageHandleCount++;
+ }
+ }
+ }
+
+ CoreReleaseProtocolLock ();
+
+ //
+ // If there are no drivers managing this controller, then return EFI_SUCCESS
+ //
+ if (DriverImageHandleCount == 0) {
+ Status = EFI_SUCCESS;
+ goto Done;
+ }
+
+ DriverImageHandleBuffer = AllocatePool (sizeof (EFI_HANDLE) * DriverImageHandleCount);
+ if (DriverImageHandleBuffer == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Done;
+ }
+
+ DriverImageHandleCount = 0;
+
+ CoreAcquireProtocolLock ();
+ for (Link = Handle->Protocols.ForwardLink; Link != &Handle->Protocols; Link = Link->ForwardLink) {
+ Prot = CR (Link, PROTOCOL_INTERFACE, Link, PROTOCOL_INTERFACE_SIGNATURE);
+ for (ProtLink = Prot->OpenList.ForwardLink;
+ ProtLink != &Prot->OpenList;
+ ProtLink = ProtLink->ForwardLink)
+ {
+ OpenData = CR (ProtLink, OPEN_PROTOCOL_DATA, Link, OPEN_PROTOCOL_DATA_SIGNATURE);
+ if ((OpenData->Attributes & EFI_OPEN_PROTOCOL_BY_DRIVER) != 0) {
+ Duplicate = FALSE;
+ for (Index = 0; Index < DriverImageHandleCount; Index++) {
+ if (DriverImageHandleBuffer[Index] == OpenData->AgentHandle) {
+ Duplicate = TRUE;
+ break;
+ }
+ }
+
+ if (!Duplicate) {
+ DriverImageHandleBuffer[DriverImageHandleCount] = OpenData->AgentHandle;
+ DriverImageHandleCount++;
+ }
+ }
+ }
+ }
+
+ CoreReleaseProtocolLock ();
+ }
+
+ StopCount = 0;
+ for (HandleIndex = 0; HandleIndex < DriverImageHandleCount; HandleIndex++) {
+ if (DriverImageHandleBuffer != NULL) {
+ DriverImageHandle = DriverImageHandleBuffer[HandleIndex];
+ }
+
+ //
+ // Get the Driver Binding Protocol of the driver that is managing this controller
+ //
+ Status = CoreHandleProtocol (
+ DriverImageHandle,
+ &gEfiDriverBindingProtocolGuid,
+ (VOID **)&DriverBinding
+ );
+ if (EFI_ERROR (Status) || (DriverBinding == NULL)) {
+ Status = EFI_INVALID_PARAMETER;
+ goto Done;
+ }
+
+ //
+ // Look at each protocol interface for a match
+ //
+ DriverImageHandleValid = FALSE;
+ ChildBufferCount = 0;
+
+ CoreAcquireProtocolLock ();
+ for (Link = Handle->Protocols.ForwardLink; Link != &Handle->Protocols; Link = Link->ForwardLink) {
+ Prot = CR (Link, PROTOCOL_INTERFACE, Link, PROTOCOL_INTERFACE_SIGNATURE);
+ for (ProtLink = Prot->OpenList.ForwardLink;
+ ProtLink != &Prot->OpenList;
+ ProtLink = ProtLink->ForwardLink)
+ {
+ OpenData = CR (ProtLink, OPEN_PROTOCOL_DATA, Link, OPEN_PROTOCOL_DATA_SIGNATURE);
+ if (OpenData->AgentHandle == DriverImageHandle) {
+ if ((OpenData->Attributes & EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER) != 0) {
+ ChildBufferCount++;
+ }
+
+ if ((OpenData->Attributes & EFI_OPEN_PROTOCOL_BY_DRIVER) != 0) {
+ DriverImageHandleValid = TRUE;
+ }
+ }
+ }
+ }
+
+ CoreReleaseProtocolLock ();
+
+ if (DriverImageHandleValid) {
+ ChildHandleValid = FALSE;
+ ChildBuffer = NULL;
+ if (ChildBufferCount != 0) {
+ ChildBuffer = AllocatePool (sizeof (EFI_HANDLE) * ChildBufferCount);
+ if (ChildBuffer == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Done;
+ }
+
+ ChildBufferCount = 0;
+
+ CoreAcquireProtocolLock ();
+ for (Link = Handle->Protocols.ForwardLink; Link != &Handle->Protocols; Link = Link->ForwardLink) {
+ Prot = CR (Link, PROTOCOL_INTERFACE, Link, PROTOCOL_INTERFACE_SIGNATURE);
+ for (ProtLink = Prot->OpenList.ForwardLink;
+ ProtLink != &Prot->OpenList;
+ ProtLink = ProtLink->ForwardLink)
+ {
+ OpenData = CR (ProtLink, OPEN_PROTOCOL_DATA, Link, OPEN_PROTOCOL_DATA_SIGNATURE);
+ if ((OpenData->AgentHandle == DriverImageHandle) &&
+ ((OpenData->Attributes & EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER) != 0))
+ {
+ Duplicate = FALSE;
+ for (Index = 0; Index < ChildBufferCount; Index++) {
+ if (ChildBuffer[Index] == OpenData->ControllerHandle) {
+ Duplicate = TRUE;
+ break;
+ }
+ }
+
+ if (!Duplicate) {
+ ChildBuffer[ChildBufferCount] = OpenData->ControllerHandle;
+ if (ChildHandle == ChildBuffer[ChildBufferCount]) {
+ ChildHandleValid = TRUE;
+ }
+
+ ChildBufferCount++;
+ }
+ }
+ }
+ }
+
+ CoreReleaseProtocolLock ();
+ }
+
+ if ((ChildHandle == NULL) || ChildHandleValid) {
+ ChildrenToStop = 0;
+ Status = EFI_SUCCESS;
+ if (ChildBufferCount > 0) {
+ if (ChildHandle != NULL) {
+ ChildrenToStop = 1;
+ Status = DriverBinding->Stop (DriverBinding, ControllerHandle, ChildrenToStop, &ChildHandle);
+ } else {
+ ChildrenToStop = ChildBufferCount;
+ Status = DriverBinding->Stop (DriverBinding, ControllerHandle, ChildrenToStop, ChildBuffer);
+ }
+ }
+
+ if (!EFI_ERROR (Status) && ((ChildHandle == NULL) || (ChildBufferCount == ChildrenToStop))) {
+ Status = DriverBinding->Stop (DriverBinding, ControllerHandle, 0, NULL);
+ }
+
+ if (!EFI_ERROR (Status)) {
+ StopCount++;
+ }
+ }
+
+ if (ChildBuffer != NULL) {
+ CoreFreePool (ChildBuffer);
+ }
+ }
+ }
+
+ if (StopCount > 0) {
+ Status = EFI_SUCCESS;
+ } else {
+ Status = EFI_NOT_FOUND;
+ }
+
+Done:
+
+ if (DriverImageHandleBuffer != NULL) {
+ CoreFreePool (DriverImageHandleBuffer);
+ }
+
+ return Status;
+}
diff --git a/MdeModulePkg/Core/Dxe/Hand/Handle.c b/MdeModulePkg/Core/Dxe/Hand/Handle.c
index 24e4fbf5f3..02762f2100 100644
--- a/MdeModulePkg/Core/Dxe/Hand/Handle.c
+++ b/MdeModulePkg/Core/Dxe/Hand/Handle.c
@@ -1,1624 +1,1624 @@
-/** @file
- UEFI handle & protocol handling.
-
-Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
-SPDX-License-Identifier: BSD-2-Clause-Patent
-
-**/
-
-#include "DxeMain.h"
-#include "Handle.h"
-
-//
-// mProtocolDatabase - A list of all protocols in the system. (simple list for now)
-// gHandleList - A list of all the handles in the system
-// gProtocolDatabaseLock - Lock to protect the mProtocolDatabase
-// gHandleDatabaseKey - The Key to show that the handle has been created/modified
-//
-LIST_ENTRY mProtocolDatabase = INITIALIZE_LIST_HEAD_VARIABLE (mProtocolDatabase);
-LIST_ENTRY gHandleList = INITIALIZE_LIST_HEAD_VARIABLE (gHandleList);
-EFI_LOCK gProtocolDatabaseLock = EFI_INITIALIZE_LOCK_VARIABLE (TPL_NOTIFY);
-UINT64 gHandleDatabaseKey = 0;
-
-/**
- Acquire lock on gProtocolDatabaseLock.
-
-**/
-VOID
-CoreAcquireProtocolLock (
- VOID
- )
-{
- CoreAcquireLock (&gProtocolDatabaseLock);
-}
-
-/**
- Release lock on gProtocolDatabaseLock.
-
-**/
-VOID
-CoreReleaseProtocolLock (
- VOID
- )
-{
- CoreReleaseLock (&gProtocolDatabaseLock);
-}
-
-/**
- Check whether a handle is a valid EFI_HANDLE
- The gProtocolDatabaseLock must be owned
-
- @param UserHandle The handle to check
-
- @retval EFI_INVALID_PARAMETER The handle is NULL or not a valid EFI_HANDLE.
- @retval EFI_SUCCESS The handle is valid EFI_HANDLE.
-
-**/
-EFI_STATUS
-CoreValidateHandle (
- IN EFI_HANDLE UserHandle
- )
-{
- IHANDLE *Handle;
- LIST_ENTRY *Link;
-
- if (UserHandle == NULL) {
- return EFI_INVALID_PARAMETER;
- }
-
- ASSERT_LOCKED (&gProtocolDatabaseLock);
-
- for (Link = gHandleList.BackLink; Link != &gHandleList; Link = Link->BackLink) {
- Handle = CR (Link, IHANDLE, AllHandles, EFI_HANDLE_SIGNATURE);
- if (Handle == (IHANDLE *)UserHandle) {
- return EFI_SUCCESS;
- }
- }
-
- return EFI_INVALID_PARAMETER;
-}
-
-/**
- Finds the protocol entry for the requested protocol.
- The gProtocolDatabaseLock must be owned
-
- @param Protocol The ID of the protocol
- @param Create Create a new entry if not found
-
- @return Protocol entry
-
-**/
-PROTOCOL_ENTRY *
-CoreFindProtocolEntry (
- IN EFI_GUID *Protocol,
- IN BOOLEAN Create
- )
-{
- LIST_ENTRY *Link;
- PROTOCOL_ENTRY *Item;
- PROTOCOL_ENTRY *ProtEntry;
-
- ASSERT_LOCKED (&gProtocolDatabaseLock);
-
- //
- // Search the database for the matching GUID
- //
-
- ProtEntry = NULL;
- for (Link = mProtocolDatabase.ForwardLink;
- Link != &mProtocolDatabase;
- Link = Link->ForwardLink)
- {
- Item = CR (Link, PROTOCOL_ENTRY, AllEntries, PROTOCOL_ENTRY_SIGNATURE);
- if (CompareGuid (&Item->ProtocolID, Protocol)) {
- //
- // This is the protocol entry
- //
-
- ProtEntry = Item;
- break;
- }
- }
-
- //
- // If the protocol entry was not found and Create is TRUE, then
- // allocate a new entry
- //
- if ((ProtEntry == NULL) && Create) {
- ProtEntry = AllocatePool (sizeof (PROTOCOL_ENTRY));
-
- if (ProtEntry != NULL) {
- //
- // Initialize new protocol entry structure
- //
- ProtEntry->Signature = PROTOCOL_ENTRY_SIGNATURE;
- CopyGuid ((VOID *)&ProtEntry->ProtocolID, Protocol);
- InitializeListHead (&ProtEntry->Protocols);
- InitializeListHead (&ProtEntry->Notify);
-
- //
- // Add it to protocol database
- //
- InsertTailList (&mProtocolDatabase, &ProtEntry->AllEntries);
- }
- }
-
- return ProtEntry;
-}
-
-/**
- Finds the protocol instance for the requested handle and protocol.
- Note: This function doesn't do parameters checking, it's caller's responsibility
- to pass in valid parameters.
-
- @param Handle The handle to search the protocol on
- @param Protocol GUID of the protocol
- @param Interface The interface for the protocol being searched
-
- @return Protocol instance (NULL: Not found)
-
-**/
-PROTOCOL_INTERFACE *
-CoreFindProtocolInterface (
- IN IHANDLE *Handle,
- IN EFI_GUID *Protocol,
- IN VOID *Interface
- )
-{
- PROTOCOL_INTERFACE *Prot;
- PROTOCOL_ENTRY *ProtEntry;
- LIST_ENTRY *Link;
-
- ASSERT_LOCKED (&gProtocolDatabaseLock);
- Prot = NULL;
-
- //
- // Lookup the protocol entry for this protocol ID
- //
-
- ProtEntry = CoreFindProtocolEntry (Protocol, FALSE);
- if (ProtEntry != NULL) {
- //
- // Look at each protocol interface for any matches
- //
- for (Link = Handle->Protocols.ForwardLink; Link != &Handle->Protocols; Link = Link->ForwardLink) {
- //
- // If this protocol interface matches, remove it
- //
- Prot = CR (Link, PROTOCOL_INTERFACE, Link, PROTOCOL_INTERFACE_SIGNATURE);
- if ((Prot->Interface == Interface) && (Prot->Protocol == ProtEntry)) {
- break;
- }
-
- Prot = NULL;
- }
- }
-
- return Prot;
-}
-
-/**
- Check if the given device path is already installed.
-
- @param DevicePath The given device path
-
- @retval TRUE The device path is already installed
- @retval FALSE The device path is not installed
-
-**/
-BOOLEAN
-IsDevicePathInstalled (
- IN EFI_DEVICE_PATH_PROTOCOL *DevicePath
- )
-{
- UINTN SourceSize;
- UINTN Size;
- BOOLEAN Found;
- LIST_ENTRY *Link;
- PROTOCOL_ENTRY *ProtEntry;
- PROTOCOL_INTERFACE *Prot;
-
- if (DevicePath == NULL) {
- return FALSE;
- }
-
- Found = FALSE;
- SourceSize = GetDevicePathSize (DevicePath);
- ASSERT (SourceSize >= END_DEVICE_PATH_LENGTH);
-
- CoreAcquireProtocolLock ();
- //
- // Look up the protocol entry
- //
- ProtEntry = CoreFindProtocolEntry (&gEfiDevicePathProtocolGuid, FALSE);
- if (ProtEntry == NULL) {
- goto Done;
- }
-
- for (Link = ProtEntry->Protocols.ForwardLink; Link != &ProtEntry->Protocols; Link = Link->ForwardLink) {
- //
- // Loop on the DevicePathProtocol interfaces
- //
- Prot = CR (Link, PROTOCOL_INTERFACE, ByProtocol, PROTOCOL_INTERFACE_SIGNATURE);
-
- //
- // Check if DevicePath is same as this interface
- //
- Size = GetDevicePathSize (Prot->Interface);
- ASSERT (Size >= END_DEVICE_PATH_LENGTH);
- if ((Size == SourceSize) && (CompareMem (DevicePath, Prot->Interface, Size - END_DEVICE_PATH_LENGTH) == 0)) {
- Found = TRUE;
- break;
- }
- }
-
-Done:
- CoreReleaseProtocolLock ();
- return Found;
-}
-
-/**
- Removes an event from a register protocol notify list on a protocol.
-
- @param Event The event to search for in the protocol
- database.
-
- @return EFI_SUCCESS if the event was found and removed.
- @return EFI_NOT_FOUND if the event was not found in the protocl database.
-
-**/
-EFI_STATUS
-CoreUnregisterProtocolNotifyEvent (
- IN EFI_EVENT Event
- )
-{
- LIST_ENTRY *Link;
- PROTOCOL_ENTRY *ProtEntry;
- LIST_ENTRY *NotifyLink;
- PROTOCOL_NOTIFY *ProtNotify;
-
- CoreAcquireProtocolLock ();
-
- for ( Link = mProtocolDatabase.ForwardLink;
- Link != &mProtocolDatabase;
- Link = Link->ForwardLink)
- {
- ProtEntry = CR (Link, PROTOCOL_ENTRY, AllEntries, PROTOCOL_ENTRY_SIGNATURE);
-
- for ( NotifyLink = ProtEntry->Notify.ForwardLink;
- NotifyLink != &ProtEntry->Notify;
- NotifyLink = NotifyLink->ForwardLink)
- {
- ProtNotify = CR (NotifyLink, PROTOCOL_NOTIFY, Link, PROTOCOL_NOTIFY_SIGNATURE);
-
- if (ProtNotify->Event == Event) {
- RemoveEntryList (&ProtNotify->Link);
- CoreFreePool (ProtNotify);
- CoreReleaseProtocolLock ();
- return EFI_SUCCESS;
- }
- }
- }
-
- CoreReleaseProtocolLock ();
- return EFI_NOT_FOUND;
-}
-
-/**
- Removes all the events in the protocol database that match Event.
-
- @param Event The event to search for in the protocol
- database.
-
- @return EFI_SUCCESS when done searching the entire database.
-
-**/
-EFI_STATUS
-CoreUnregisterProtocolNotify (
- IN EFI_EVENT Event
- )
-{
- EFI_STATUS Status;
-
- do {
- Status = CoreUnregisterProtocolNotifyEvent (Event);
- } while (!EFI_ERROR (Status));
-
- return EFI_SUCCESS;
-}
-
-/**
- Wrapper function to CoreInstallProtocolInterfaceNotify. This is the public API which
- Calls the private one which contains a BOOLEAN parameter for notifications
-
- @param UserHandle The handle to install the protocol handler on,
- or NULL if a new handle is to be allocated
- @param Protocol The protocol to add to the handle
- @param InterfaceType Indicates whether Interface is supplied in
- native form.
- @param Interface The interface for the protocol being added
-
- @return Status code
-
-**/
-EFI_STATUS
-EFIAPI
-CoreInstallProtocolInterface (
- IN OUT EFI_HANDLE *UserHandle,
- IN EFI_GUID *Protocol,
- IN EFI_INTERFACE_TYPE InterfaceType,
- IN VOID *Interface
- )
-{
- return CoreInstallProtocolInterfaceNotify (
- UserHandle,
- Protocol,
- InterfaceType,
- Interface,
- TRUE
- );
-}
-
-/**
- Installs a protocol interface into the boot services environment.
-
- @param UserHandle The handle to install the protocol handler on,
- or NULL if a new handle is to be allocated
- @param Protocol The protocol to add to the handle
- @param InterfaceType Indicates whether Interface is supplied in
- native form.
- @param Interface The interface for the protocol being added
- @param Notify indicates whether notify the notification list
- for this protocol
-
- @retval EFI_INVALID_PARAMETER Invalid parameter
- @retval EFI_OUT_OF_RESOURCES No enough buffer to allocate
- @retval EFI_SUCCESS Protocol interface successfully installed
-
-**/
-EFI_STATUS
-CoreInstallProtocolInterfaceNotify (
- IN OUT EFI_HANDLE *UserHandle,
- IN EFI_GUID *Protocol,
- IN EFI_INTERFACE_TYPE InterfaceType,
- IN VOID *Interface,
- IN BOOLEAN Notify
- )
-{
- PROTOCOL_INTERFACE *Prot;
- PROTOCOL_ENTRY *ProtEntry;
- IHANDLE *Handle;
- EFI_STATUS Status;
- VOID *ExistingInterface;
-
- //
- // returns EFI_INVALID_PARAMETER if InterfaceType is invalid.
- // Also added check for invalid UserHandle and Protocol pointers.
- //
- if ((UserHandle == NULL) || (Protocol == NULL)) {
- return EFI_INVALID_PARAMETER;
- }
-
- if (InterfaceType != EFI_NATIVE_INTERFACE) {
- return EFI_INVALID_PARAMETER;
- }
-
- //
- // Print debug message
- //
- DEBUG ((DEBUG_INFO, "InstallProtocolInterface: %g %p\n", Protocol, Interface));
-
- Status = EFI_OUT_OF_RESOURCES;
- Prot = NULL;
- Handle = NULL;
-
- if (*UserHandle != NULL) {
- Status = CoreHandleProtocol (*UserHandle, Protocol, (VOID **)&ExistingInterface);
- if (!EFI_ERROR (Status)) {
- return EFI_INVALID_PARAMETER;
- }
- }
-
- //
- // Lock the protocol database
- //
- CoreAcquireProtocolLock ();
-
- //
- // Lookup the Protocol Entry for the requested protocol
- //
- ProtEntry = CoreFindProtocolEntry (Protocol, TRUE);
- if (ProtEntry == NULL) {
- goto Done;
- }
-
- //
- // Allocate a new protocol interface structure
- //
- Prot = AllocateZeroPool (sizeof (PROTOCOL_INTERFACE));
- if (Prot == NULL) {
- Status = EFI_OUT_OF_RESOURCES;
- goto Done;
- }
-
- //
- // If caller didn't supply a handle, allocate a new one
- //
- Handle = (IHANDLE *)*UserHandle;
- if (Handle == NULL) {
- Handle = AllocateZeroPool (sizeof (IHANDLE));
- if (Handle == NULL) {
- Status = EFI_OUT_OF_RESOURCES;
- goto Done;
- }
-
- //
- // Initialize new handler structure
- //
- Handle->Signature = EFI_HANDLE_SIGNATURE;
- InitializeListHead (&Handle->Protocols);
-
- //
- // Initialize the Key to show that the handle has been created/modified
- //
- gHandleDatabaseKey++;
- Handle->Key = gHandleDatabaseKey;
-
- //
- // Add this handle to the list global list of all handles
- // in the system
- //
- InsertTailList (&gHandleList, &Handle->AllHandles);
- } else {
- Status = CoreValidateHandle (Handle);
- if (EFI_ERROR (Status)) {
- DEBUG ((DEBUG_ERROR, "InstallProtocolInterface: input handle at 0x%x is invalid\n", Handle));
- goto Done;
- }
- }
-
- //
- // Each interface that is added must be unique
- //
- ASSERT (CoreFindProtocolInterface (Handle, Protocol, Interface) == NULL);
-
- //
- // Initialize the protocol interface structure
- //
- Prot->Signature = PROTOCOL_INTERFACE_SIGNATURE;
- Prot->Handle = Handle;
- Prot->Protocol = ProtEntry;
- Prot->Interface = Interface;
-
- //
- // Initalize OpenProtocol Data base
- //
- InitializeListHead (&Prot->OpenList);
- Prot->OpenListCount = 0;
-
- //
- // Add this protocol interface to the head of the supported
- // protocol list for this handle
- //
- InsertHeadList (&Handle->Protocols, &Prot->Link);
-
- //
- // Add this protocol interface to the tail of the
- // protocol entry
- //
- InsertTailList (&ProtEntry->Protocols, &Prot->ByProtocol);
-
- //
- // Notify the notification list for this protocol
- //
- if (Notify) {
- CoreNotifyProtocolEntry (ProtEntry);
- }
-
- Status = EFI_SUCCESS;
-
-Done:
- //
- // Done, unlock the database and return
- //
- CoreReleaseProtocolLock ();
- if (!EFI_ERROR (Status)) {
- //
- // Return the new handle back to the caller
- //
- *UserHandle = Handle;
- } else {
- //
- // There was an error, clean up
- //
- if (Prot != NULL) {
- CoreFreePool (Prot);
- }
-
- DEBUG ((DEBUG_ERROR, "InstallProtocolInterface: %g %p failed with %r\n", Protocol, Interface, Status));
- }
-
- return Status;
-}
-
-/**
- Installs a list of protocol interface into the boot services environment.
- This function calls InstallProtocolInterface() in a loop. If any error
- occures all the protocols added by this function are removed. This is
- basically a lib function to save space.
-
- @param Handle The pointer to a handle to install the new
- protocol interfaces on, or a pointer to NULL
- if a new handle is to be allocated.
- @param ... EFI_GUID followed by protocol instance. A NULL
- terminates the list. The pairs are the
- arguments to InstallProtocolInterface(). All the
- protocols are added to Handle.
-
- @retval EFI_SUCCESS All the protocol interface was installed.
- @retval EFI_OUT_OF_RESOURCES There was not enough memory in pool to install all the protocols.
- @retval EFI_ALREADY_STARTED A Device Path Protocol instance was passed in that is already present in
- the handle database.
- @retval EFI_INVALID_PARAMETER Handle is NULL.
- @retval EFI_INVALID_PARAMETER Protocol is already installed on the handle specified by Handle.
-
-**/
-EFI_STATUS
-EFIAPI
-CoreInstallMultipleProtocolInterfaces (
- IN OUT EFI_HANDLE *Handle,
- ...
- )
-{
- VA_LIST Args;
- EFI_STATUS Status;
- EFI_GUID *Protocol;
- VOID *Interface;
- EFI_TPL OldTpl;
- UINTN Index;
- EFI_HANDLE OldHandle;
-
- if (Handle == NULL) {
- return EFI_INVALID_PARAMETER;
- }
-
- //
- // Syncronize with notifcations.
- //
- OldTpl = CoreRaiseTpl (TPL_NOTIFY);
- OldHandle = *Handle;
-
- //
- // Check for duplicate device path and install the protocol interfaces
- //
- VA_START (Args, Handle);
- for (Index = 0, Status = EFI_SUCCESS; !EFI_ERROR (Status); Index++) {
- //
- // If protocol is NULL, then it's the end of the list
- //
- Protocol = VA_ARG (Args, EFI_GUID *);
- if (Protocol == NULL) {
- break;
- }
-
- Interface = VA_ARG (Args, VOID *);
-
- //
- // Make sure you are installing on top a device path that has already been added.
- //
- if (CompareGuid (Protocol, &gEfiDevicePathProtocolGuid) &&
- IsDevicePathInstalled (Interface))
- {
- Status = EFI_ALREADY_STARTED;
- continue;
- }
-
- //
- // Install it
- //
- Status = CoreInstallProtocolInterface (Handle, Protocol, EFI_NATIVE_INTERFACE, Interface);
- }
-
- VA_END (Args);
-
- //
- // If there was an error, remove all the interfaces that were installed without any errors
- //
- if (EFI_ERROR (Status)) {
- //
- // Reset the va_arg back to the first argument.
- //
- VA_START (Args, Handle);
- for ( ; Index > 1; Index--) {
- Protocol = VA_ARG (Args, EFI_GUID *);
- Interface = VA_ARG (Args, VOID *);
- CoreUninstallProtocolInterface (*Handle, Protocol, Interface);
- }
-
- VA_END (Args);
-
- *Handle = OldHandle;
- }
-
- //
- // Done
- //
- CoreRestoreTpl (OldTpl);
- return Status;
-}
-
-/**
- Attempts to disconnect all drivers that are using the protocol interface being queried.
- If failed, reconnect all drivers disconnected.
- Note: This function doesn't do parameters checking, it's caller's responsibility
- to pass in valid parameters.
-
- @param UserHandle The handle on which the protocol is installed
- @param Prot The protocol to disconnect drivers from
-
- @retval EFI_SUCCESS Drivers using the protocol interface are all
- disconnected
- @retval EFI_ACCESS_DENIED Failed to disconnect one or all of the drivers
-
-**/
-EFI_STATUS
-CoreDisconnectControllersUsingProtocolInterface (
- IN EFI_HANDLE UserHandle,
- IN PROTOCOL_INTERFACE *Prot
- )
-{
- EFI_STATUS Status;
- BOOLEAN ItemFound;
- LIST_ENTRY *Link;
- OPEN_PROTOCOL_DATA *OpenData;
-
- Status = EFI_SUCCESS;
-
- //
- // Attempt to disconnect all drivers from this protocol interface
- //
- do {
- ItemFound = FALSE;
- for (Link = Prot->OpenList.ForwardLink; Link != &Prot->OpenList; Link = Link->ForwardLink) {
- OpenData = CR (Link, OPEN_PROTOCOL_DATA, Link, OPEN_PROTOCOL_DATA_SIGNATURE);
- if ((OpenData->Attributes & EFI_OPEN_PROTOCOL_BY_DRIVER) != 0) {
- CoreReleaseProtocolLock ();
- Status = CoreDisconnectController (UserHandle, OpenData->AgentHandle, NULL);
- CoreAcquireProtocolLock ();
- if (!EFI_ERROR (Status)) {
- ItemFound = TRUE;
- }
-
- break;
- }
- }
- } while (ItemFound);
-
- if (!EFI_ERROR (Status)) {
- //
- // Attempt to remove BY_HANDLE_PROTOOCL and GET_PROTOCOL and TEST_PROTOCOL Open List items
- //
- for (Link = Prot->OpenList.ForwardLink; Link != &Prot->OpenList;) {
- OpenData = CR (Link, OPEN_PROTOCOL_DATA, Link, OPEN_PROTOCOL_DATA_SIGNATURE);
- if ((OpenData->Attributes &
- (EFI_OPEN_PROTOCOL_BY_HANDLE_PROTOCOL | EFI_OPEN_PROTOCOL_GET_PROTOCOL | EFI_OPEN_PROTOCOL_TEST_PROTOCOL)) != 0)
- {
- Link = RemoveEntryList (&OpenData->Link);
- Prot->OpenListCount--;
- CoreFreePool (OpenData);
- } else {
- Link = Link->ForwardLink;
- }
- }
- }
-
- //
- // If there are errors or still has open items in the list, then reconnect all the drivers and return an error
- //
- if (EFI_ERROR (Status) || (Prot->OpenListCount > 0)) {
- CoreReleaseProtocolLock ();
- CoreConnectController (UserHandle, NULL, NULL, TRUE);
- CoreAcquireProtocolLock ();
- Status = EFI_ACCESS_DENIED;
- }
-
- return Status;
-}
-
-/**
- Uninstalls all instances of a protocol:interfacer from a handle.
- If the last protocol interface is remove from the handle, the
- handle is freed.
-
- @param UserHandle The handle to remove the protocol handler from
- @param Protocol The protocol, of protocol:interface, to remove
- @param Interface The interface, of protocol:interface, to remove
-
- @retval EFI_INVALID_PARAMETER Protocol is NULL.
- @retval EFI_SUCCESS Protocol interface successfully uninstalled.
-
-**/
-EFI_STATUS
-EFIAPI
-CoreUninstallProtocolInterface (
- IN EFI_HANDLE UserHandle,
- IN EFI_GUID *Protocol,
- IN VOID *Interface
- )
-{
- EFI_STATUS Status;
- IHANDLE *Handle;
- PROTOCOL_INTERFACE *Prot;
-
- //
- // Check that Protocol is valid
- //
- if (Protocol == NULL) {
- return EFI_INVALID_PARAMETER;
- }
-
- //
- // Lock the protocol database
- //
- CoreAcquireProtocolLock ();
-
- //
- // Check that UserHandle is a valid handle
- //
- Status = CoreValidateHandle (UserHandle);
- if (EFI_ERROR (Status)) {
- goto Done;
- }
-
- //
- // Check that Protocol exists on UserHandle, and Interface matches the interface in the database
- //
- Prot = CoreFindProtocolInterface (UserHandle, Protocol, Interface);
- if (Prot == NULL) {
- Status = EFI_NOT_FOUND;
- goto Done;
- }
-
- //
- // Attempt to disconnect all drivers that are using the protocol interface that is about to be removed
- //
- Status = CoreDisconnectControllersUsingProtocolInterface (
- UserHandle,
- Prot
- );
- if (EFI_ERROR (Status)) {
- //
- // One or more drivers refused to release, so return the error
- //
- goto Done;
- }
-
- //
- // Remove the protocol interface from the protocol
- //
- Status = EFI_NOT_FOUND;
- Handle = (IHANDLE *)UserHandle;
- Prot = CoreRemoveInterfaceFromProtocol (Handle, Protocol, Interface);
-
- if (Prot != NULL) {
- //
- // Update the Key to show that the handle has been created/modified
- //
- gHandleDatabaseKey++;
- Handle->Key = gHandleDatabaseKey;
-
- //
- // Remove the protocol interface from the handle
- //
- RemoveEntryList (&Prot->Link);
-
- //
- // Free the memory
- //
- Prot->Signature = 0;
- CoreFreePool (Prot);
- Status = EFI_SUCCESS;
- }
-
- //
- // If there are no more handlers for the handle, free the handle
- //
- if (IsListEmpty (&Handle->Protocols)) {
- Handle->Signature = 0;
- RemoveEntryList (&Handle->AllHandles);
- CoreFreePool (Handle);
- }
-
-Done:
- //
- // Done, unlock the database and return
- //
- CoreReleaseProtocolLock ();
- return Status;
-}
-
-/**
- Uninstalls a list of protocol interface in the boot services environment.
- This function calls UninstallProtocolInterface() in a loop. This is
- basically a lib function to save space.
-
- If any errors are generated while the protocol interfaces are being
- uninstalled, then the protocol interfaces uninstalled prior to the error will
- be reinstalled and EFI_INVALID_PARAMETER will be returned.
-
- @param Handle The handle to uninstall the protocol interfaces
- from.
- @param ... EFI_GUID followed by protocol instance. A NULL
- terminates the list. The pairs are the
- arguments to UninstallProtocolInterface(). All
- the protocols are added to Handle.
-
- @retval EFI_SUCCESS if all protocol interfaces where uninstalled.
- @retval EFI_INVALID_PARAMETER if any protocol interface could not be
- uninstalled and an attempt was made to
- reinstall previously uninstalled protocol
- interfaces.
-**/
-EFI_STATUS
-EFIAPI
-CoreUninstallMultipleProtocolInterfaces (
- IN EFI_HANDLE Handle,
- ...
- )
-{
- EFI_STATUS Status;
- VA_LIST Args;
- EFI_GUID *Protocol;
- VOID *Interface;
- UINTN Index;
-
- VA_START (Args, Handle);
- for (Index = 0, Status = EFI_SUCCESS; !EFI_ERROR (Status); Index++) {
- //
- // If protocol is NULL, then it's the end of the list
- //
- Protocol = VA_ARG (Args, EFI_GUID *);
- if (Protocol == NULL) {
- break;
- }
-
- Interface = VA_ARG (Args, VOID *);
-
- //
- // Uninstall it
- //
- Status = CoreUninstallProtocolInterface (Handle, Protocol, Interface);
- }
-
- VA_END (Args);
-
- //
- // If there was an error, add all the interfaces that were
- // uninstalled without any errors
- //
- if (EFI_ERROR (Status)) {
- //
- // Reset the va_arg back to the first argument.
- //
- VA_START (Args, Handle);
- for ( ; Index > 1; Index--) {
- Protocol = VA_ARG (Args, EFI_GUID *);
- Interface = VA_ARG (Args, VOID *);
- CoreInstallProtocolInterface (&Handle, Protocol, EFI_NATIVE_INTERFACE, Interface);
- }
-
- VA_END (Args);
- Status = EFI_INVALID_PARAMETER;
- }
-
- return Status;
-}
-
-/**
- Locate a certain GUID protocol interface in a Handle's protocols.
-
- @param UserHandle The handle to obtain the protocol interface on
- The caller must pass in a valid UserHandle that
- is checked with CoreValidateHandle().
- @param Protocol The GUID of the protocol
-
- @return The requested protocol interface for the handle
-
-**/
-STATIC
-PROTOCOL_INTERFACE *
-CoreGetProtocolInterface (
- IN EFI_HANDLE UserHandle,
- IN EFI_GUID *Protocol
- )
-{
- PROTOCOL_ENTRY *ProtEntry;
- PROTOCOL_INTERFACE *Prot;
- IHANDLE *Handle;
- LIST_ENTRY *Link;
-
- Handle = (IHANDLE *)UserHandle;
-
- //
- // Look at each protocol interface for a match
- //
- for (Link = Handle->Protocols.ForwardLink; Link != &Handle->Protocols; Link = Link->ForwardLink) {
- Prot = CR (Link, PROTOCOL_INTERFACE, Link, PROTOCOL_INTERFACE_SIGNATURE);
- ProtEntry = Prot->Protocol;
- if (CompareGuid (&ProtEntry->ProtocolID, Protocol)) {
- return Prot;
- }
- }
-
- return NULL;
-}
-
-/**
- Queries a handle to determine if it supports a specified protocol.
-
- @param UserHandle The handle being queried.
- @param Protocol The published unique identifier of the protocol.
- @param Interface Supplies the address where a pointer to the
- corresponding Protocol Interface is returned.
-
- @retval EFI_SUCCESS The interface information for the specified protocol was returned.
- @retval EFI_UNSUPPORTED The device does not support the specified protocol.
- @retval EFI_INVALID_PARAMETER Handle is NULL..
- @retval EFI_INVALID_PARAMETER Protocol is NULL.
- @retval EFI_INVALID_PARAMETER Interface is NULL.
-
-**/
-EFI_STATUS
-EFIAPI
-CoreHandleProtocol (
- IN EFI_HANDLE UserHandle,
- IN EFI_GUID *Protocol,
- OUT VOID **Interface
- )
-{
- return CoreOpenProtocol (
- UserHandle,
- Protocol,
- Interface,
- gDxeCoreImageHandle,
- NULL,
- EFI_OPEN_PROTOCOL_BY_HANDLE_PROTOCOL
- );
-}
-
-/**
- Locates the installed protocol handler for the handle, and
- invokes it to obtain the protocol interface. Usage information
- is registered in the protocol data base.
-
- @param UserHandle The handle to obtain the protocol interface on
- @param Protocol The ID of the protocol
- @param Interface The location to return the protocol interface
- @param ImageHandle The handle of the Image that is opening the
- protocol interface specified by Protocol and
- Interface.
- @param ControllerHandle The controller handle that is requiring this
- interface.
- @param Attributes The open mode of the protocol interface
- specified by Handle and Protocol.
-
- @retval EFI_INVALID_PARAMETER Protocol is NULL.
- @retval EFI_SUCCESS Get the protocol interface.
-
-**/
-EFI_STATUS
-EFIAPI
-CoreOpenProtocol (
- IN EFI_HANDLE UserHandle,
- IN EFI_GUID *Protocol,
- OUT VOID **Interface OPTIONAL,
- IN EFI_HANDLE ImageHandle,
- IN EFI_HANDLE ControllerHandle,
- IN UINT32 Attributes
- )
-{
- EFI_STATUS Status;
- PROTOCOL_INTERFACE *Prot;
- LIST_ENTRY *Link;
- OPEN_PROTOCOL_DATA *OpenData;
- BOOLEAN ByDriver;
- BOOLEAN Exclusive;
- BOOLEAN Disconnect;
- BOOLEAN ExactMatch;
-
- //
- // Check for invalid Protocol
- //
- if (Protocol == NULL) {
- return EFI_INVALID_PARAMETER;
- }
-
- //
- // Check for invalid Interface
- //
- if ((Attributes != EFI_OPEN_PROTOCOL_TEST_PROTOCOL) && (Interface == NULL)) {
- return EFI_INVALID_PARAMETER;
- }
-
- //
- // Lock the protocol database
- //
- CoreAcquireProtocolLock ();
-
- //
- // Check for invalid UserHandle
- //
- Status = CoreValidateHandle (UserHandle);
- if (EFI_ERROR (Status)) {
- goto Done;
- }
-
- //
- // Check for invalid Attributes
- //
- switch (Attributes) {
- case EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER:
- Status = CoreValidateHandle (ImageHandle);
- if (EFI_ERROR (Status)) {
- goto Done;
- }
-
- Status = CoreValidateHandle (ControllerHandle);
- if (EFI_ERROR (Status)) {
- goto Done;
- }
-
- if (UserHandle == ControllerHandle) {
- Status = EFI_INVALID_PARAMETER;
- goto Done;
- }
-
- break;
- case EFI_OPEN_PROTOCOL_BY_DRIVER:
- case EFI_OPEN_PROTOCOL_BY_DRIVER | EFI_OPEN_PROTOCOL_EXCLUSIVE:
- Status = CoreValidateHandle (ImageHandle);
- if (EFI_ERROR (Status)) {
- goto Done;
- }
-
- Status = CoreValidateHandle (ControllerHandle);
- if (EFI_ERROR (Status)) {
- goto Done;
- }
-
- break;
- case EFI_OPEN_PROTOCOL_EXCLUSIVE:
- Status = CoreValidateHandle (ImageHandle);
- if (EFI_ERROR (Status)) {
- goto Done;
- }
-
- break;
- case EFI_OPEN_PROTOCOL_BY_HANDLE_PROTOCOL:
- case EFI_OPEN_PROTOCOL_GET_PROTOCOL:
- case EFI_OPEN_PROTOCOL_TEST_PROTOCOL:
- break;
- default:
- Status = EFI_INVALID_PARAMETER;
- goto Done;
- }
-
- //
- // Look at each protocol interface for a match
- //
- Prot = CoreGetProtocolInterface (UserHandle, Protocol);
- if (Prot == NULL) {
- Status = EFI_UNSUPPORTED;
- goto Done;
- }
-
- Status = EFI_SUCCESS;
-
- ByDriver = FALSE;
- Exclusive = FALSE;
- for ( Link = Prot->OpenList.ForwardLink; Link != &Prot->OpenList; Link = Link->ForwardLink) {
- OpenData = CR (Link, OPEN_PROTOCOL_DATA, Link, OPEN_PROTOCOL_DATA_SIGNATURE);
- ExactMatch = (BOOLEAN)((OpenData->AgentHandle == ImageHandle) &&
- (OpenData->Attributes == Attributes) &&
- (OpenData->ControllerHandle == ControllerHandle));
- if ((OpenData->Attributes & EFI_OPEN_PROTOCOL_BY_DRIVER) != 0) {
- ByDriver = TRUE;
- if (ExactMatch) {
- Status = EFI_ALREADY_STARTED;
- goto Done;
- }
- }
-
- if ((OpenData->Attributes & EFI_OPEN_PROTOCOL_EXCLUSIVE) != 0) {
- Exclusive = TRUE;
- } else if (ExactMatch) {
- OpenData->OpenCount++;
- Status = EFI_SUCCESS;
- goto Done;
- }
- }
-
- //
- // ByDriver TRUE -> A driver is managing (UserHandle, Protocol)
- // ByDriver FALSE -> There are no drivers managing (UserHandle, Protocol)
- // Exclusive TRUE -> Something has exclusive access to (UserHandle, Protocol)
- // Exclusive FALSE -> Nothing has exclusive access to (UserHandle, Protocol)
- //
-
- switch (Attributes) {
- case EFI_OPEN_PROTOCOL_BY_DRIVER:
- if (Exclusive || ByDriver) {
- Status = EFI_ACCESS_DENIED;
- goto Done;
- }
-
- break;
- case EFI_OPEN_PROTOCOL_BY_DRIVER | EFI_OPEN_PROTOCOL_EXCLUSIVE:
- case EFI_OPEN_PROTOCOL_EXCLUSIVE:
- if (Exclusive) {
- Status = EFI_ACCESS_DENIED;
- goto Done;
- }
-
- if (ByDriver) {
- do {
- Disconnect = FALSE;
- for (Link = Prot->OpenList.ForwardLink; Link != &Prot->OpenList; Link = Link->ForwardLink) {
- OpenData = CR (Link, OPEN_PROTOCOL_DATA, Link, OPEN_PROTOCOL_DATA_SIGNATURE);
- if ((OpenData->Attributes & EFI_OPEN_PROTOCOL_BY_DRIVER) != 0) {
- Disconnect = TRUE;
- CoreReleaseProtocolLock ();
- Status = CoreDisconnectController (UserHandle, OpenData->AgentHandle, NULL);
- CoreAcquireProtocolLock ();
- if (EFI_ERROR (Status)) {
- Status = EFI_ACCESS_DENIED;
- goto Done;
- } else {
- break;
- }
- }
- }
- } while (Disconnect);
- }
-
- break;
- case EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER:
- case EFI_OPEN_PROTOCOL_BY_HANDLE_PROTOCOL:
- case EFI_OPEN_PROTOCOL_GET_PROTOCOL:
- case EFI_OPEN_PROTOCOL_TEST_PROTOCOL:
- break;
- }
-
- if (ImageHandle == NULL) {
- Status = EFI_SUCCESS;
- goto Done;
- }
-
- //
- // Create new entry
- //
- OpenData = AllocatePool (sizeof (OPEN_PROTOCOL_DATA));
- if (OpenData == NULL) {
- Status = EFI_OUT_OF_RESOURCES;
- } else {
- OpenData->Signature = OPEN_PROTOCOL_DATA_SIGNATURE;
- OpenData->AgentHandle = ImageHandle;
- OpenData->ControllerHandle = ControllerHandle;
- OpenData->Attributes = Attributes;
- OpenData->OpenCount = 1;
- InsertTailList (&Prot->OpenList, &OpenData->Link);
- Prot->OpenListCount++;
- Status = EFI_SUCCESS;
- }
-
-Done:
-
- if (Attributes != EFI_OPEN_PROTOCOL_TEST_PROTOCOL) {
- //
- // Keep Interface unmodified in case of any Error
- // except EFI_ALREADY_STARTED and EFI_UNSUPPORTED.
- //
- if (!EFI_ERROR (Status) || (Status == EFI_ALREADY_STARTED)) {
- //
- // According to above logic, if 'Prot' is NULL, then the 'Status' must be
- // EFI_UNSUPPORTED. Here the 'Status' is not EFI_UNSUPPORTED, so 'Prot'
- // must be not NULL.
- //
- // The ASSERT here is for addressing a false positive NULL pointer
- // dereference issue raised from static analysis.
- //
- ASSERT (Prot != NULL);
- //
- // EFI_ALREADY_STARTED is not an error for bus driver.
- // Return the corresponding protocol interface.
- //
- *Interface = Prot->Interface;
- } else if (Status == EFI_UNSUPPORTED) {
- //
- // Return NULL Interface if Unsupported Protocol.
- //
- *Interface = NULL;
- }
- }
-
- //
- // Done. Release the database lock and return
- //
- CoreReleaseProtocolLock ();
- return Status;
-}
-
-/**
- Closes a protocol on a handle that was opened using OpenProtocol().
-
- @param UserHandle The handle for the protocol interface that was
- previously opened with OpenProtocol(), and is
- now being closed.
- @param Protocol The published unique identifier of the protocol.
- It is the caller's responsibility to pass in a
- valid GUID.
- @param AgentHandle The handle of the agent that is closing the
- protocol interface.
- @param ControllerHandle If the agent that opened a protocol is a driver
- that follows the EFI Driver Model, then this
- parameter is the controller handle that required
- the protocol interface. If the agent does not
- follow the EFI Driver Model, then this parameter
- is optional and may be NULL.
-
- @retval EFI_SUCCESS The protocol instance was closed.
- @retval EFI_INVALID_PARAMETER Handle, AgentHandle or ControllerHandle is not a
- valid EFI_HANDLE.
- @retval EFI_NOT_FOUND Can not find the specified protocol or
- AgentHandle.
-
-**/
-EFI_STATUS
-EFIAPI
-CoreCloseProtocol (
- IN EFI_HANDLE UserHandle,
- IN EFI_GUID *Protocol,
- IN EFI_HANDLE AgentHandle,
- IN EFI_HANDLE ControllerHandle
- )
-{
- EFI_STATUS Status;
- PROTOCOL_INTERFACE *ProtocolInterface;
- LIST_ENTRY *Link;
- OPEN_PROTOCOL_DATA *OpenData;
-
- //
- // Lock the protocol database
- //
- CoreAcquireProtocolLock ();
-
- //
- // Check for invalid parameters
- //
- Status = CoreValidateHandle (UserHandle);
- if (EFI_ERROR (Status)) {
- goto Done;
- }
-
- Status = CoreValidateHandle (AgentHandle);
- if (EFI_ERROR (Status)) {
- goto Done;
- }
-
- if (ControllerHandle != NULL) {
- Status = CoreValidateHandle (ControllerHandle);
- if (EFI_ERROR (Status)) {
- goto Done;
- }
- }
-
- if (Protocol == NULL) {
- Status = EFI_INVALID_PARAMETER;
- goto Done;
- }
-
- //
- // Look at each protocol interface for a match
- //
- Status = EFI_NOT_FOUND;
- ProtocolInterface = CoreGetProtocolInterface (UserHandle, Protocol);
- if (ProtocolInterface == NULL) {
- goto Done;
- }
-
- //
- // Walk the Open data base looking for AgentHandle
- //
- Link = ProtocolInterface->OpenList.ForwardLink;
- while (Link != &ProtocolInterface->OpenList) {
- OpenData = CR (Link, OPEN_PROTOCOL_DATA, Link, OPEN_PROTOCOL_DATA_SIGNATURE);
- Link = Link->ForwardLink;
- if ((OpenData->AgentHandle == AgentHandle) && (OpenData->ControllerHandle == ControllerHandle)) {
- RemoveEntryList (&OpenData->Link);
- ProtocolInterface->OpenListCount--;
- CoreFreePool (OpenData);
- Status = EFI_SUCCESS;
- }
- }
-
-Done:
- //
- // Done. Release the database lock and return.
- //
- CoreReleaseProtocolLock ();
- return Status;
-}
-
-/**
- Return information about Opened protocols in the system
-
- @param UserHandle The handle to close the protocol interface on
- @param Protocol The ID of the protocol
- @param EntryBuffer A pointer to a buffer of open protocol information in the
- form of EFI_OPEN_PROTOCOL_INFORMATION_ENTRY structures.
- @param EntryCount Number of EntryBuffer entries
-
- @retval EFI_SUCCESS The open protocol information was returned in EntryBuffer,
- and the number of entries was returned EntryCount.
- @retval EFI_NOT_FOUND Handle does not support the protocol specified by Protocol.
- @retval EFI_OUT_OF_RESOURCES There are not enough resources available to allocate EntryBuffer.
-
-**/
-EFI_STATUS
-EFIAPI
-CoreOpenProtocolInformation (
- IN EFI_HANDLE UserHandle,
- IN EFI_GUID *Protocol,
- OUT EFI_OPEN_PROTOCOL_INFORMATION_ENTRY **EntryBuffer,
- OUT UINTN *EntryCount
- )
-{
- EFI_STATUS Status;
- PROTOCOL_INTERFACE *ProtocolInterface;
- LIST_ENTRY *Link;
- OPEN_PROTOCOL_DATA *OpenData;
- EFI_OPEN_PROTOCOL_INFORMATION_ENTRY *Buffer;
- UINTN Count;
- UINTN Size;
-
- *EntryBuffer = NULL;
- *EntryCount = 0;
-
- //
- // Lock the protocol database
- //
- CoreAcquireProtocolLock ();
-
- //
- // Check for invalid UserHandle
- //
- Status = CoreValidateHandle (UserHandle);
- if (EFI_ERROR (Status)) {
- Status = EFI_NOT_FOUND;
- goto Done;
- }
-
- //
- // Look at each protocol interface for a match
- //
- Status = EFI_NOT_FOUND;
- ProtocolInterface = CoreGetProtocolInterface (UserHandle, Protocol);
- if (ProtocolInterface == NULL) {
- goto Done;
- }
-
- //
- // Count the number of Open Entries
- //
- for ( Link = ProtocolInterface->OpenList.ForwardLink, Count = 0;
- (Link != &ProtocolInterface->OpenList);
- Link = Link->ForwardLink )
- {
- Count++;
- }
-
- ASSERT (Count == ProtocolInterface->OpenListCount);
-
- if (Count == 0) {
- Size = sizeof (EFI_OPEN_PROTOCOL_INFORMATION_ENTRY);
- } else {
- Size = Count * sizeof (EFI_OPEN_PROTOCOL_INFORMATION_ENTRY);
- }
-
- Buffer = AllocatePool (Size);
- if (Buffer == NULL) {
- Status = EFI_OUT_OF_RESOURCES;
- goto Done;
- }
-
- Status = EFI_SUCCESS;
- for ( Link = ProtocolInterface->OpenList.ForwardLink, Count = 0;
- (Link != &ProtocolInterface->OpenList);
- Link = Link->ForwardLink, Count++ )
- {
- OpenData = CR (Link, OPEN_PROTOCOL_DATA, Link, OPEN_PROTOCOL_DATA_SIGNATURE);
-
- Buffer[Count].AgentHandle = OpenData->AgentHandle;
- Buffer[Count].ControllerHandle = OpenData->ControllerHandle;
- Buffer[Count].Attributes = OpenData->Attributes;
- Buffer[Count].OpenCount = OpenData->OpenCount;
- }
-
- *EntryBuffer = Buffer;
- *EntryCount = Count;
-
-Done:
- //
- // Done. Release the database lock.
- //
- CoreReleaseProtocolLock ();
- return Status;
-}
-
-/**
- Retrieves the list of protocol interface GUIDs that are installed on a handle in a buffer allocated
- from pool.
-
- @param UserHandle The handle from which to retrieve the list of
- protocol interface GUIDs.
- @param ProtocolBuffer A pointer to the list of protocol interface GUID
- pointers that are installed on Handle.
- @param ProtocolBufferCount A pointer to the number of GUID pointers present
- in ProtocolBuffer.
-
- @retval EFI_SUCCESS The list of protocol interface GUIDs installed
- on Handle was returned in ProtocolBuffer. The
- number of protocol interface GUIDs was returned
- in ProtocolBufferCount.
- @retval EFI_INVALID_PARAMETER Handle is NULL.
- @retval EFI_INVALID_PARAMETER Handle is not a valid EFI_HANDLE.
- @retval EFI_INVALID_PARAMETER ProtocolBuffer is NULL.
- @retval EFI_INVALID_PARAMETER ProtocolBufferCount is NULL.
- @retval EFI_OUT_OF_RESOURCES There is not enough pool memory to store the
- results.
-
-**/
-EFI_STATUS
-EFIAPI
-CoreProtocolsPerHandle (
- IN EFI_HANDLE UserHandle,
- OUT EFI_GUID ***ProtocolBuffer,
- OUT UINTN *ProtocolBufferCount
- )
-{
- EFI_STATUS Status;
- IHANDLE *Handle;
- PROTOCOL_INTERFACE *Prot;
- LIST_ENTRY *Link;
- UINTN ProtocolCount;
- EFI_GUID **Buffer;
-
- if (ProtocolBuffer == NULL) {
- return EFI_INVALID_PARAMETER;
- }
-
- if (ProtocolBufferCount == NULL) {
- return EFI_INVALID_PARAMETER;
- }
-
- *ProtocolBufferCount = 0;
-
- ProtocolCount = 0;
-
- CoreAcquireProtocolLock ();
-
- Status = CoreValidateHandle (UserHandle);
- if (EFI_ERROR (Status)) {
- goto Done;
- }
-
- Handle = (IHANDLE *)UserHandle;
-
- for (Link = Handle->Protocols.ForwardLink; Link != &Handle->Protocols; Link = Link->ForwardLink) {
- ProtocolCount++;
- }
-
- //
- // If there are no protocol interfaces installed on Handle, then Handle is not a valid EFI_HANDLE
- //
- if (ProtocolCount == 0) {
- Status = EFI_INVALID_PARAMETER;
- goto Done;
- }
-
- Buffer = AllocatePool (sizeof (EFI_GUID *) * ProtocolCount);
- if (Buffer == NULL) {
- Status = EFI_OUT_OF_RESOURCES;
- goto Done;
- }
-
- *ProtocolBuffer = Buffer;
- *ProtocolBufferCount = ProtocolCount;
-
- for ( Link = Handle->Protocols.ForwardLink, ProtocolCount = 0;
- Link != &Handle->Protocols;
- Link = Link->ForwardLink, ProtocolCount++)
- {
- Prot = CR (Link, PROTOCOL_INTERFACE, Link, PROTOCOL_INTERFACE_SIGNATURE);
- Buffer[ProtocolCount] = &(Prot->Protocol->ProtocolID);
- }
-
- Status = EFI_SUCCESS;
-
-Done:
- CoreReleaseProtocolLock ();
- return Status;
-}
-
-/**
- return handle database key.
-
-
- @return Handle database key.
-
-**/
-UINT64
-CoreGetHandleDatabaseKey (
- VOID
- )
-{
- return gHandleDatabaseKey;
-}
-
-/**
- Go connect any handles that were created or modified while a image executed.
-
- @param Key The Key to show that the handle has been
- created/modified
-
-**/
-VOID
-CoreConnectHandlesByKey (
- UINT64 Key
- )
-{
- UINTN Count;
- LIST_ENTRY *Link;
- EFI_HANDLE *HandleBuffer;
- IHANDLE *Handle;
- UINTN Index;
-
- //
- // Lock the protocol database
- //
- CoreAcquireProtocolLock ();
-
- for (Link = gHandleList.ForwardLink, Count = 0; Link != &gHandleList; Link = Link->ForwardLink) {
- Handle = CR (Link, IHANDLE, AllHandles, EFI_HANDLE_SIGNATURE);
- if (Handle->Key > Key) {
- Count++;
- }
- }
-
- HandleBuffer = AllocatePool (Count * sizeof (EFI_HANDLE));
- if (HandleBuffer == NULL) {
- CoreReleaseProtocolLock ();
- return;
- }
-
- for (Link = gHandleList.ForwardLink, Count = 0; Link != &gHandleList; Link = Link->ForwardLink) {
- Handle = CR (Link, IHANDLE, AllHandles, EFI_HANDLE_SIGNATURE);
- if (Handle->Key > Key) {
- HandleBuffer[Count++] = Handle;
- }
- }
-
- //
- // Unlock the protocol database
- //
- CoreReleaseProtocolLock ();
-
- //
- // Connect all handles whose Key value is greater than Key
- //
- for (Index = 0; Index < Count; Index++) {
- CoreConnectController (HandleBuffer[Index], NULL, NULL, TRUE);
- }
-
- CoreFreePool (HandleBuffer);
-}
+/** @file
+ UEFI handle & protocol handling.
+
+Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "DxeMain.h"
+#include "Handle.h"
+
+//
+// mProtocolDatabase - A list of all protocols in the system. (simple list for now)
+// gHandleList - A list of all the handles in the system
+// gProtocolDatabaseLock - Lock to protect the mProtocolDatabase
+// gHandleDatabaseKey - The Key to show that the handle has been created/modified
+//
+LIST_ENTRY mProtocolDatabase = INITIALIZE_LIST_HEAD_VARIABLE (mProtocolDatabase);
+LIST_ENTRY gHandleList = INITIALIZE_LIST_HEAD_VARIABLE (gHandleList);
+EFI_LOCK gProtocolDatabaseLock = EFI_INITIALIZE_LOCK_VARIABLE (TPL_NOTIFY);
+UINT64 gHandleDatabaseKey = 0;
+
+/**
+ Acquire lock on gProtocolDatabaseLock.
+
+**/
+VOID
+CoreAcquireProtocolLock (
+ VOID
+ )
+{
+ CoreAcquireLock (&gProtocolDatabaseLock);
+}
+
+/**
+ Release lock on gProtocolDatabaseLock.
+
+**/
+VOID
+CoreReleaseProtocolLock (
+ VOID
+ )
+{
+ CoreReleaseLock (&gProtocolDatabaseLock);
+}
+
+/**
+ Check whether a handle is a valid EFI_HANDLE
+ The gProtocolDatabaseLock must be owned
+
+ @param UserHandle The handle to check
+
+ @retval EFI_INVALID_PARAMETER The handle is NULL or not a valid EFI_HANDLE.
+ @retval EFI_SUCCESS The handle is valid EFI_HANDLE.
+
+**/
+EFI_STATUS
+CoreValidateHandle (
+ IN EFI_HANDLE UserHandle
+ )
+{
+ IHANDLE *Handle;
+ LIST_ENTRY *Link;
+
+ if (UserHandle == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ ASSERT_LOCKED (&gProtocolDatabaseLock);
+
+ for (Link = gHandleList.BackLink; Link != &gHandleList; Link = Link->BackLink) {
+ Handle = CR (Link, IHANDLE, AllHandles, EFI_HANDLE_SIGNATURE);
+ if (Handle == (IHANDLE *)UserHandle) {
+ return EFI_SUCCESS;
+ }
+ }
+
+ return EFI_INVALID_PARAMETER;
+}
+
+/**
+ Finds the protocol entry for the requested protocol.
+ The gProtocolDatabaseLock must be owned
+
+ @param Protocol The ID of the protocol
+ @param Create Create a new entry if not found
+
+ @return Protocol entry
+
+**/
+PROTOCOL_ENTRY *
+CoreFindProtocolEntry (
+ IN EFI_GUID *Protocol,
+ IN BOOLEAN Create
+ )
+{
+ LIST_ENTRY *Link;
+ PROTOCOL_ENTRY *Item;
+ PROTOCOL_ENTRY *ProtEntry;
+
+ ASSERT_LOCKED (&gProtocolDatabaseLock);
+
+ //
+ // Search the database for the matching GUID
+ //
+
+ ProtEntry = NULL;
+ for (Link = mProtocolDatabase.ForwardLink;
+ Link != &mProtocolDatabase;
+ Link = Link->ForwardLink)
+ {
+ Item = CR (Link, PROTOCOL_ENTRY, AllEntries, PROTOCOL_ENTRY_SIGNATURE);
+ if (CompareGuid (&Item->ProtocolID, Protocol)) {
+ //
+ // This is the protocol entry
+ //
+
+ ProtEntry = Item;
+ break;
+ }
+ }
+
+ //
+ // If the protocol entry was not found and Create is TRUE, then
+ // allocate a new entry
+ //
+ if ((ProtEntry == NULL) && Create) {
+ ProtEntry = AllocatePool (sizeof (PROTOCOL_ENTRY));
+
+ if (ProtEntry != NULL) {
+ //
+ // Initialize new protocol entry structure
+ //
+ ProtEntry->Signature = PROTOCOL_ENTRY_SIGNATURE;
+ CopyGuid ((VOID *)&ProtEntry->ProtocolID, Protocol);
+ InitializeListHead (&ProtEntry->Protocols);
+ InitializeListHead (&ProtEntry->Notify);
+
+ //
+ // Add it to protocol database
+ //
+ InsertTailList (&mProtocolDatabase, &ProtEntry->AllEntries);
+ }
+ }
+
+ return ProtEntry;
+}
+
+/**
+ Finds the protocol instance for the requested handle and protocol.
+ Note: This function doesn't do parameters checking, it's caller's responsibility
+ to pass in valid parameters.
+
+ @param Handle The handle to search the protocol on
+ @param Protocol GUID of the protocol
+ @param Interface The interface for the protocol being searched
+
+ @return Protocol instance (NULL: Not found)
+
+**/
+PROTOCOL_INTERFACE *
+CoreFindProtocolInterface (
+ IN IHANDLE *Handle,
+ IN EFI_GUID *Protocol,
+ IN VOID *Interface
+ )
+{
+ PROTOCOL_INTERFACE *Prot;
+ PROTOCOL_ENTRY *ProtEntry;
+ LIST_ENTRY *Link;
+
+ ASSERT_LOCKED (&gProtocolDatabaseLock);
+ Prot = NULL;
+
+ //
+ // Lookup the protocol entry for this protocol ID
+ //
+
+ ProtEntry = CoreFindProtocolEntry (Protocol, FALSE);
+ if (ProtEntry != NULL) {
+ //
+ // Look at each protocol interface for any matches
+ //
+ for (Link = Handle->Protocols.ForwardLink; Link != &Handle->Protocols; Link = Link->ForwardLink) {
+ //
+ // If this protocol interface matches, remove it
+ //
+ Prot = CR (Link, PROTOCOL_INTERFACE, Link, PROTOCOL_INTERFACE_SIGNATURE);
+ if ((Prot->Interface == Interface) && (Prot->Protocol == ProtEntry)) {
+ break;
+ }
+
+ Prot = NULL;
+ }
+ }
+
+ return Prot;
+}
+
+/**
+ Check if the given device path is already installed.
+
+ @param DevicePath The given device path
+
+ @retval TRUE The device path is already installed
+ @retval FALSE The device path is not installed
+
+**/
+BOOLEAN
+IsDevicePathInstalled (
+ IN EFI_DEVICE_PATH_PROTOCOL *DevicePath
+ )
+{
+ UINTN SourceSize;
+ UINTN Size;
+ BOOLEAN Found;
+ LIST_ENTRY *Link;
+ PROTOCOL_ENTRY *ProtEntry;
+ PROTOCOL_INTERFACE *Prot;
+
+ if (DevicePath == NULL) {
+ return FALSE;
+ }
+
+ Found = FALSE;
+ SourceSize = GetDevicePathSize (DevicePath);
+ ASSERT (SourceSize >= END_DEVICE_PATH_LENGTH);
+
+ CoreAcquireProtocolLock ();
+ //
+ // Look up the protocol entry
+ //
+ ProtEntry = CoreFindProtocolEntry (&gEfiDevicePathProtocolGuid, FALSE);
+ if (ProtEntry == NULL) {
+ goto Done;
+ }
+
+ for (Link = ProtEntry->Protocols.ForwardLink; Link != &ProtEntry->Protocols; Link = Link->ForwardLink) {
+ //
+ // Loop on the DevicePathProtocol interfaces
+ //
+ Prot = CR (Link, PROTOCOL_INTERFACE, ByProtocol, PROTOCOL_INTERFACE_SIGNATURE);
+
+ //
+ // Check if DevicePath is same as this interface
+ //
+ Size = GetDevicePathSize (Prot->Interface);
+ ASSERT (Size >= END_DEVICE_PATH_LENGTH);
+ if ((Size == SourceSize) && (CompareMem (DevicePath, Prot->Interface, Size - END_DEVICE_PATH_LENGTH) == 0)) {
+ Found = TRUE;
+ break;
+ }
+ }
+
+Done:
+ CoreReleaseProtocolLock ();
+ return Found;
+}
+
+/**
+ Removes an event from a register protocol notify list on a protocol.
+
+ @param Event The event to search for in the protocol
+ database.
+
+ @return EFI_SUCCESS if the event was found and removed.
+ @return EFI_NOT_FOUND if the event was not found in the protocl database.
+
+**/
+EFI_STATUS
+CoreUnregisterProtocolNotifyEvent (
+ IN EFI_EVENT Event
+ )
+{
+ LIST_ENTRY *Link;
+ PROTOCOL_ENTRY *ProtEntry;
+ LIST_ENTRY *NotifyLink;
+ PROTOCOL_NOTIFY *ProtNotify;
+
+ CoreAcquireProtocolLock ();
+
+ for ( Link = mProtocolDatabase.ForwardLink;
+ Link != &mProtocolDatabase;
+ Link = Link->ForwardLink)
+ {
+ ProtEntry = CR (Link, PROTOCOL_ENTRY, AllEntries, PROTOCOL_ENTRY_SIGNATURE);
+
+ for ( NotifyLink = ProtEntry->Notify.ForwardLink;
+ NotifyLink != &ProtEntry->Notify;
+ NotifyLink = NotifyLink->ForwardLink)
+ {
+ ProtNotify = CR (NotifyLink, PROTOCOL_NOTIFY, Link, PROTOCOL_NOTIFY_SIGNATURE);
+
+ if (ProtNotify->Event == Event) {
+ RemoveEntryList (&ProtNotify->Link);
+ CoreFreePool (ProtNotify);
+ CoreReleaseProtocolLock ();
+ return EFI_SUCCESS;
+ }
+ }
+ }
+
+ CoreReleaseProtocolLock ();
+ return EFI_NOT_FOUND;
+}
+
+/**
+ Removes all the events in the protocol database that match Event.
+
+ @param Event The event to search for in the protocol
+ database.
+
+ @return EFI_SUCCESS when done searching the entire database.
+
+**/
+EFI_STATUS
+CoreUnregisterProtocolNotify (
+ IN EFI_EVENT Event
+ )
+{
+ EFI_STATUS Status;
+
+ do {
+ Status = CoreUnregisterProtocolNotifyEvent (Event);
+ } while (!EFI_ERROR (Status));
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Wrapper function to CoreInstallProtocolInterfaceNotify. This is the public API which
+ Calls the private one which contains a BOOLEAN parameter for notifications
+
+ @param UserHandle The handle to install the protocol handler on,
+ or NULL if a new handle is to be allocated
+ @param Protocol The protocol to add to the handle
+ @param InterfaceType Indicates whether Interface is supplied in
+ native form.
+ @param Interface The interface for the protocol being added
+
+ @return Status code
+
+**/
+EFI_STATUS
+EFIAPI
+CoreInstallProtocolInterface (
+ IN OUT EFI_HANDLE *UserHandle,
+ IN EFI_GUID *Protocol,
+ IN EFI_INTERFACE_TYPE InterfaceType,
+ IN VOID *Interface
+ )
+{
+ return CoreInstallProtocolInterfaceNotify (
+ UserHandle,
+ Protocol,
+ InterfaceType,
+ Interface,
+ TRUE
+ );
+}
+
+/**
+ Installs a protocol interface into the boot services environment.
+
+ @param UserHandle The handle to install the protocol handler on,
+ or NULL if a new handle is to be allocated
+ @param Protocol The protocol to add to the handle
+ @param InterfaceType Indicates whether Interface is supplied in
+ native form.
+ @param Interface The interface for the protocol being added
+ @param Notify indicates whether notify the notification list
+ for this protocol
+
+ @retval EFI_INVALID_PARAMETER Invalid parameter
+ @retval EFI_OUT_OF_RESOURCES No enough buffer to allocate
+ @retval EFI_SUCCESS Protocol interface successfully installed
+
+**/
+EFI_STATUS
+CoreInstallProtocolInterfaceNotify (
+ IN OUT EFI_HANDLE *UserHandle,
+ IN EFI_GUID *Protocol,
+ IN EFI_INTERFACE_TYPE InterfaceType,
+ IN VOID *Interface,
+ IN BOOLEAN Notify
+ )
+{
+ PROTOCOL_INTERFACE *Prot;
+ PROTOCOL_ENTRY *ProtEntry;
+ IHANDLE *Handle;
+ EFI_STATUS Status;
+ VOID *ExistingInterface;
+
+ //
+ // returns EFI_INVALID_PARAMETER if InterfaceType is invalid.
+ // Also added check for invalid UserHandle and Protocol pointers.
+ //
+ if ((UserHandle == NULL) || (Protocol == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (InterfaceType != EFI_NATIVE_INTERFACE) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Print debug message
+ //
+ DEBUG ((DEBUG_INFO, "InstallProtocolInterface: %g %p\n", Protocol, Interface));
+
+ Status = EFI_OUT_OF_RESOURCES;
+ Prot = NULL;
+ Handle = NULL;
+
+ if (*UserHandle != NULL) {
+ Status = CoreHandleProtocol (*UserHandle, Protocol, (VOID **)&ExistingInterface);
+ if (!EFI_ERROR (Status)) {
+ return EFI_INVALID_PARAMETER;
+ }
+ }
+
+ //
+ // Lock the protocol database
+ //
+ CoreAcquireProtocolLock ();
+
+ //
+ // Lookup the Protocol Entry for the requested protocol
+ //
+ ProtEntry = CoreFindProtocolEntry (Protocol, TRUE);
+ if (ProtEntry == NULL) {
+ goto Done;
+ }
+
+ //
+ // Allocate a new protocol interface structure
+ //
+ Prot = AllocateZeroPool (sizeof (PROTOCOL_INTERFACE));
+ if (Prot == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Done;
+ }
+
+ //
+ // If caller didn't supply a handle, allocate a new one
+ //
+ Handle = (IHANDLE *)*UserHandle;
+ if (Handle == NULL) {
+ Handle = AllocateZeroPool (sizeof (IHANDLE));
+ if (Handle == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Done;
+ }
+
+ //
+ // Initialize new handler structure
+ //
+ Handle->Signature = EFI_HANDLE_SIGNATURE;
+ InitializeListHead (&Handle->Protocols);
+
+ //
+ // Initialize the Key to show that the handle has been created/modified
+ //
+ gHandleDatabaseKey++;
+ Handle->Key = gHandleDatabaseKey;
+
+ //
+ // Add this handle to the list global list of all handles
+ // in the system
+ //
+ InsertTailList (&gHandleList, &Handle->AllHandles);
+ } else {
+ Status = CoreValidateHandle (Handle);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "InstallProtocolInterface: input handle at 0x%x is invalid\n", Handle));
+ goto Done;
+ }
+ }
+
+ //
+ // Each interface that is added must be unique
+ //
+ ASSERT (CoreFindProtocolInterface (Handle, Protocol, Interface) == NULL);
+
+ //
+ // Initialize the protocol interface structure
+ //
+ Prot->Signature = PROTOCOL_INTERFACE_SIGNATURE;
+ Prot->Handle = Handle;
+ Prot->Protocol = ProtEntry;
+ Prot->Interface = Interface;
+
+ //
+ // Initalize OpenProtocol Data base
+ //
+ InitializeListHead (&Prot->OpenList);
+ Prot->OpenListCount = 0;
+
+ //
+ // Add this protocol interface to the head of the supported
+ // protocol list for this handle
+ //
+ InsertHeadList (&Handle->Protocols, &Prot->Link);
+
+ //
+ // Add this protocol interface to the tail of the
+ // protocol entry
+ //
+ InsertTailList (&ProtEntry->Protocols, &Prot->ByProtocol);
+
+ //
+ // Notify the notification list for this protocol
+ //
+ if (Notify) {
+ CoreNotifyProtocolEntry (ProtEntry);
+ }
+
+ Status = EFI_SUCCESS;
+
+Done:
+ //
+ // Done, unlock the database and return
+ //
+ CoreReleaseProtocolLock ();
+ if (!EFI_ERROR (Status)) {
+ //
+ // Return the new handle back to the caller
+ //
+ *UserHandle = Handle;
+ } else {
+ //
+ // There was an error, clean up
+ //
+ if (Prot != NULL) {
+ CoreFreePool (Prot);
+ }
+
+ DEBUG ((DEBUG_ERROR, "InstallProtocolInterface: %g %p failed with %r\n", Protocol, Interface, Status));
+ }
+
+ return Status;
+}
+
+/**
+ Installs a list of protocol interface into the boot services environment.
+ This function calls InstallProtocolInterface() in a loop. If any error
+ occures all the protocols added by this function are removed. This is
+ basically a lib function to save space.
+
+ @param Handle The pointer to a handle to install the new
+ protocol interfaces on, or a pointer to NULL
+ if a new handle is to be allocated.
+ @param ... EFI_GUID followed by protocol instance. A NULL
+ terminates the list. The pairs are the
+ arguments to InstallProtocolInterface(). All the
+ protocols are added to Handle.
+
+ @retval EFI_SUCCESS All the protocol interface was installed.
+ @retval EFI_OUT_OF_RESOURCES There was not enough memory in pool to install all the protocols.
+ @retval EFI_ALREADY_STARTED A Device Path Protocol instance was passed in that is already present in
+ the handle database.
+ @retval EFI_INVALID_PARAMETER Handle is NULL.
+ @retval EFI_INVALID_PARAMETER Protocol is already installed on the handle specified by Handle.
+
+**/
+EFI_STATUS
+EFIAPI
+CoreInstallMultipleProtocolInterfaces (
+ IN OUT EFI_HANDLE *Handle,
+ ...
+ )
+{
+ VA_LIST Args;
+ EFI_STATUS Status;
+ EFI_GUID *Protocol;
+ VOID *Interface;
+ EFI_TPL OldTpl;
+ UINTN Index;
+ EFI_HANDLE OldHandle;
+
+ if (Handle == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Syncronize with notifcations.
+ //
+ OldTpl = CoreRaiseTpl (TPL_NOTIFY);
+ OldHandle = *Handle;
+
+ //
+ // Check for duplicate device path and install the protocol interfaces
+ //
+ VA_START (Args, Handle);
+ for (Index = 0, Status = EFI_SUCCESS; !EFI_ERROR (Status); Index++) {
+ //
+ // If protocol is NULL, then it's the end of the list
+ //
+ Protocol = VA_ARG (Args, EFI_GUID *);
+ if (Protocol == NULL) {
+ break;
+ }
+
+ Interface = VA_ARG (Args, VOID *);
+
+ //
+ // Make sure you are installing on top a device path that has already been added.
+ //
+ if (CompareGuid (Protocol, &gEfiDevicePathProtocolGuid) &&
+ IsDevicePathInstalled (Interface))
+ {
+ Status = EFI_ALREADY_STARTED;
+ continue;
+ }
+
+ //
+ // Install it
+ //
+ Status = CoreInstallProtocolInterface (Handle, Protocol, EFI_NATIVE_INTERFACE, Interface);
+ }
+
+ VA_END (Args);
+
+ //
+ // If there was an error, remove all the interfaces that were installed without any errors
+ //
+ if (EFI_ERROR (Status)) {
+ //
+ // Reset the va_arg back to the first argument.
+ //
+ VA_START (Args, Handle);
+ for ( ; Index > 1; Index--) {
+ Protocol = VA_ARG (Args, EFI_GUID *);
+ Interface = VA_ARG (Args, VOID *);
+ CoreUninstallProtocolInterface (*Handle, Protocol, Interface);
+ }
+
+ VA_END (Args);
+
+ *Handle = OldHandle;
+ }
+
+ //
+ // Done
+ //
+ CoreRestoreTpl (OldTpl);
+ return Status;
+}
+
+/**
+ Attempts to disconnect all drivers that are using the protocol interface being queried.
+ If failed, reconnect all drivers disconnected.
+ Note: This function doesn't do parameters checking, it's caller's responsibility
+ to pass in valid parameters.
+
+ @param UserHandle The handle on which the protocol is installed
+ @param Prot The protocol to disconnect drivers from
+
+ @retval EFI_SUCCESS Drivers using the protocol interface are all
+ disconnected
+ @retval EFI_ACCESS_DENIED Failed to disconnect one or all of the drivers
+
+**/
+EFI_STATUS
+CoreDisconnectControllersUsingProtocolInterface (
+ IN EFI_HANDLE UserHandle,
+ IN PROTOCOL_INTERFACE *Prot
+ )
+{
+ EFI_STATUS Status;
+ BOOLEAN ItemFound;
+ LIST_ENTRY *Link;
+ OPEN_PROTOCOL_DATA *OpenData;
+
+ Status = EFI_SUCCESS;
+
+ //
+ // Attempt to disconnect all drivers from this protocol interface
+ //
+ do {
+ ItemFound = FALSE;
+ for (Link = Prot->OpenList.ForwardLink; Link != &Prot->OpenList; Link = Link->ForwardLink) {
+ OpenData = CR (Link, OPEN_PROTOCOL_DATA, Link, OPEN_PROTOCOL_DATA_SIGNATURE);
+ if ((OpenData->Attributes & EFI_OPEN_PROTOCOL_BY_DRIVER) != 0) {
+ CoreReleaseProtocolLock ();
+ Status = CoreDisconnectController (UserHandle, OpenData->AgentHandle, NULL);
+ CoreAcquireProtocolLock ();
+ if (!EFI_ERROR (Status)) {
+ ItemFound = TRUE;
+ }
+
+ break;
+ }
+ }
+ } while (ItemFound);
+
+ if (!EFI_ERROR (Status)) {
+ //
+ // Attempt to remove BY_HANDLE_PROTOOCL and GET_PROTOCOL and TEST_PROTOCOL Open List items
+ //
+ for (Link = Prot->OpenList.ForwardLink; Link != &Prot->OpenList;) {
+ OpenData = CR (Link, OPEN_PROTOCOL_DATA, Link, OPEN_PROTOCOL_DATA_SIGNATURE);
+ if ((OpenData->Attributes &
+ (EFI_OPEN_PROTOCOL_BY_HANDLE_PROTOCOL | EFI_OPEN_PROTOCOL_GET_PROTOCOL | EFI_OPEN_PROTOCOL_TEST_PROTOCOL)) != 0)
+ {
+ Link = RemoveEntryList (&OpenData->Link);
+ Prot->OpenListCount--;
+ CoreFreePool (OpenData);
+ } else {
+ Link = Link->ForwardLink;
+ }
+ }
+ }
+
+ //
+ // If there are errors or still has open items in the list, then reconnect all the drivers and return an error
+ //
+ if (EFI_ERROR (Status) || (Prot->OpenListCount > 0)) {
+ CoreReleaseProtocolLock ();
+ CoreConnectController (UserHandle, NULL, NULL, TRUE);
+ CoreAcquireProtocolLock ();
+ Status = EFI_ACCESS_DENIED;
+ }
+
+ return Status;
+}
+
+/**
+ Uninstalls all instances of a protocol:interfacer from a handle.
+ If the last protocol interface is remove from the handle, the
+ handle is freed.
+
+ @param UserHandle The handle to remove the protocol handler from
+ @param Protocol The protocol, of protocol:interface, to remove
+ @param Interface The interface, of protocol:interface, to remove
+
+ @retval EFI_INVALID_PARAMETER Protocol is NULL.
+ @retval EFI_SUCCESS Protocol interface successfully uninstalled.
+
+**/
+EFI_STATUS
+EFIAPI
+CoreUninstallProtocolInterface (
+ IN EFI_HANDLE UserHandle,
+ IN EFI_GUID *Protocol,
+ IN VOID *Interface
+ )
+{
+ EFI_STATUS Status;
+ IHANDLE *Handle;
+ PROTOCOL_INTERFACE *Prot;
+
+ //
+ // Check that Protocol is valid
+ //
+ if (Protocol == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Lock the protocol database
+ //
+ CoreAcquireProtocolLock ();
+
+ //
+ // Check that UserHandle is a valid handle
+ //
+ Status = CoreValidateHandle (UserHandle);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ //
+ // Check that Protocol exists on UserHandle, and Interface matches the interface in the database
+ //
+ Prot = CoreFindProtocolInterface (UserHandle, Protocol, Interface);
+ if (Prot == NULL) {
+ Status = EFI_NOT_FOUND;
+ goto Done;
+ }
+
+ //
+ // Attempt to disconnect all drivers that are using the protocol interface that is about to be removed
+ //
+ Status = CoreDisconnectControllersUsingProtocolInterface (
+ UserHandle,
+ Prot
+ );
+ if (EFI_ERROR (Status)) {
+ //
+ // One or more drivers refused to release, so return the error
+ //
+ goto Done;
+ }
+
+ //
+ // Remove the protocol interface from the protocol
+ //
+ Status = EFI_NOT_FOUND;
+ Handle = (IHANDLE *)UserHandle;
+ Prot = CoreRemoveInterfaceFromProtocol (Handle, Protocol, Interface);
+
+ if (Prot != NULL) {
+ //
+ // Update the Key to show that the handle has been created/modified
+ //
+ gHandleDatabaseKey++;
+ Handle->Key = gHandleDatabaseKey;
+
+ //
+ // Remove the protocol interface from the handle
+ //
+ RemoveEntryList (&Prot->Link);
+
+ //
+ // Free the memory
+ //
+ Prot->Signature = 0;
+ CoreFreePool (Prot);
+ Status = EFI_SUCCESS;
+ }
+
+ //
+ // If there are no more handlers for the handle, free the handle
+ //
+ if (IsListEmpty (&Handle->Protocols)) {
+ Handle->Signature = 0;
+ RemoveEntryList (&Handle->AllHandles);
+ CoreFreePool (Handle);
+ }
+
+Done:
+ //
+ // Done, unlock the database and return
+ //
+ CoreReleaseProtocolLock ();
+ return Status;
+}
+
+/**
+ Uninstalls a list of protocol interface in the boot services environment.
+ This function calls UninstallProtocolInterface() in a loop. This is
+ basically a lib function to save space.
+
+ If any errors are generated while the protocol interfaces are being
+ uninstalled, then the protocol interfaces uninstalled prior to the error will
+ be reinstalled and EFI_INVALID_PARAMETER will be returned.
+
+ @param Handle The handle to uninstall the protocol interfaces
+ from.
+ @param ... EFI_GUID followed by protocol instance. A NULL
+ terminates the list. The pairs are the
+ arguments to UninstallProtocolInterface(). All
+ the protocols are added to Handle.
+
+ @retval EFI_SUCCESS if all protocol interfaces where uninstalled.
+ @retval EFI_INVALID_PARAMETER if any protocol interface could not be
+ uninstalled and an attempt was made to
+ reinstall previously uninstalled protocol
+ interfaces.
+**/
+EFI_STATUS
+EFIAPI
+CoreUninstallMultipleProtocolInterfaces (
+ IN EFI_HANDLE Handle,
+ ...
+ )
+{
+ EFI_STATUS Status;
+ VA_LIST Args;
+ EFI_GUID *Protocol;
+ VOID *Interface;
+ UINTN Index;
+
+ VA_START (Args, Handle);
+ for (Index = 0, Status = EFI_SUCCESS; !EFI_ERROR (Status); Index++) {
+ //
+ // If protocol is NULL, then it's the end of the list
+ //
+ Protocol = VA_ARG (Args, EFI_GUID *);
+ if (Protocol == NULL) {
+ break;
+ }
+
+ Interface = VA_ARG (Args, VOID *);
+
+ //
+ // Uninstall it
+ //
+ Status = CoreUninstallProtocolInterface (Handle, Protocol, Interface);
+ }
+
+ VA_END (Args);
+
+ //
+ // If there was an error, add all the interfaces that were
+ // uninstalled without any errors
+ //
+ if (EFI_ERROR (Status)) {
+ //
+ // Reset the va_arg back to the first argument.
+ //
+ VA_START (Args, Handle);
+ for ( ; Index > 1; Index--) {
+ Protocol = VA_ARG (Args, EFI_GUID *);
+ Interface = VA_ARG (Args, VOID *);
+ CoreInstallProtocolInterface (&Handle, Protocol, EFI_NATIVE_INTERFACE, Interface);
+ }
+
+ VA_END (Args);
+ Status = EFI_INVALID_PARAMETER;
+ }
+
+ return Status;
+}
+
+/**
+ Locate a certain GUID protocol interface in a Handle's protocols.
+
+ @param UserHandle The handle to obtain the protocol interface on
+ The caller must pass in a valid UserHandle that
+ is checked with CoreValidateHandle().
+ @param Protocol The GUID of the protocol
+
+ @return The requested protocol interface for the handle
+
+**/
+STATIC
+PROTOCOL_INTERFACE *
+CoreGetProtocolInterface (
+ IN EFI_HANDLE UserHandle,
+ IN EFI_GUID *Protocol
+ )
+{
+ PROTOCOL_ENTRY *ProtEntry;
+ PROTOCOL_INTERFACE *Prot;
+ IHANDLE *Handle;
+ LIST_ENTRY *Link;
+
+ Handle = (IHANDLE *)UserHandle;
+
+ //
+ // Look at each protocol interface for a match
+ //
+ for (Link = Handle->Protocols.ForwardLink; Link != &Handle->Protocols; Link = Link->ForwardLink) {
+ Prot = CR (Link, PROTOCOL_INTERFACE, Link, PROTOCOL_INTERFACE_SIGNATURE);
+ ProtEntry = Prot->Protocol;
+ if (CompareGuid (&ProtEntry->ProtocolID, Protocol)) {
+ return Prot;
+ }
+ }
+
+ return NULL;
+}
+
+/**
+ Queries a handle to determine if it supports a specified protocol.
+
+ @param UserHandle The handle being queried.
+ @param Protocol The published unique identifier of the protocol.
+ @param Interface Supplies the address where a pointer to the
+ corresponding Protocol Interface is returned.
+
+ @retval EFI_SUCCESS The interface information for the specified protocol was returned.
+ @retval EFI_UNSUPPORTED The device does not support the specified protocol.
+ @retval EFI_INVALID_PARAMETER Handle is NULL..
+ @retval EFI_INVALID_PARAMETER Protocol is NULL.
+ @retval EFI_INVALID_PARAMETER Interface is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+CoreHandleProtocol (
+ IN EFI_HANDLE UserHandle,
+ IN EFI_GUID *Protocol,
+ OUT VOID **Interface
+ )
+{
+ return CoreOpenProtocol (
+ UserHandle,
+ Protocol,
+ Interface,
+ gDxeCoreImageHandle,
+ NULL,
+ EFI_OPEN_PROTOCOL_BY_HANDLE_PROTOCOL
+ );
+}
+
+/**
+ Locates the installed protocol handler for the handle, and
+ invokes it to obtain the protocol interface. Usage information
+ is registered in the protocol data base.
+
+ @param UserHandle The handle to obtain the protocol interface on
+ @param Protocol The ID of the protocol
+ @param Interface The location to return the protocol interface
+ @param ImageHandle The handle of the Image that is opening the
+ protocol interface specified by Protocol and
+ Interface.
+ @param ControllerHandle The controller handle that is requiring this
+ interface.
+ @param Attributes The open mode of the protocol interface
+ specified by Handle and Protocol.
+
+ @retval EFI_INVALID_PARAMETER Protocol is NULL.
+ @retval EFI_SUCCESS Get the protocol interface.
+
+**/
+EFI_STATUS
+EFIAPI
+CoreOpenProtocol (
+ IN EFI_HANDLE UserHandle,
+ IN EFI_GUID *Protocol,
+ OUT VOID **Interface OPTIONAL,
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_HANDLE ControllerHandle,
+ IN UINT32 Attributes
+ )
+{
+ EFI_STATUS Status;
+ PROTOCOL_INTERFACE *Prot;
+ LIST_ENTRY *Link;
+ OPEN_PROTOCOL_DATA *OpenData;
+ BOOLEAN ByDriver;
+ BOOLEAN Exclusive;
+ BOOLEAN Disconnect;
+ BOOLEAN ExactMatch;
+
+ //
+ // Check for invalid Protocol
+ //
+ if (Protocol == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Check for invalid Interface
+ //
+ if ((Attributes != EFI_OPEN_PROTOCOL_TEST_PROTOCOL) && (Interface == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Lock the protocol database
+ //
+ CoreAcquireProtocolLock ();
+
+ //
+ // Check for invalid UserHandle
+ //
+ Status = CoreValidateHandle (UserHandle);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ //
+ // Check for invalid Attributes
+ //
+ switch (Attributes) {
+ case EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER:
+ Status = CoreValidateHandle (ImageHandle);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ Status = CoreValidateHandle (ControllerHandle);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ if (UserHandle == ControllerHandle) {
+ Status = EFI_INVALID_PARAMETER;
+ goto Done;
+ }
+
+ break;
+ case EFI_OPEN_PROTOCOL_BY_DRIVER:
+ case EFI_OPEN_PROTOCOL_BY_DRIVER | EFI_OPEN_PROTOCOL_EXCLUSIVE:
+ Status = CoreValidateHandle (ImageHandle);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ Status = CoreValidateHandle (ControllerHandle);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ break;
+ case EFI_OPEN_PROTOCOL_EXCLUSIVE:
+ Status = CoreValidateHandle (ImageHandle);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ break;
+ case EFI_OPEN_PROTOCOL_BY_HANDLE_PROTOCOL:
+ case EFI_OPEN_PROTOCOL_GET_PROTOCOL:
+ case EFI_OPEN_PROTOCOL_TEST_PROTOCOL:
+ break;
+ default:
+ Status = EFI_INVALID_PARAMETER;
+ goto Done;
+ }
+
+ //
+ // Look at each protocol interface for a match
+ //
+ Prot = CoreGetProtocolInterface (UserHandle, Protocol);
+ if (Prot == NULL) {
+ Status = EFI_UNSUPPORTED;
+ goto Done;
+ }
+
+ Status = EFI_SUCCESS;
+
+ ByDriver = FALSE;
+ Exclusive = FALSE;
+ for ( Link = Prot->OpenList.ForwardLink; Link != &Prot->OpenList; Link = Link->ForwardLink) {
+ OpenData = CR (Link, OPEN_PROTOCOL_DATA, Link, OPEN_PROTOCOL_DATA_SIGNATURE);
+ ExactMatch = (BOOLEAN)((OpenData->AgentHandle == ImageHandle) &&
+ (OpenData->Attributes == Attributes) &&
+ (OpenData->ControllerHandle == ControllerHandle));
+ if ((OpenData->Attributes & EFI_OPEN_PROTOCOL_BY_DRIVER) != 0) {
+ ByDriver = TRUE;
+ if (ExactMatch) {
+ Status = EFI_ALREADY_STARTED;
+ goto Done;
+ }
+ }
+
+ if ((OpenData->Attributes & EFI_OPEN_PROTOCOL_EXCLUSIVE) != 0) {
+ Exclusive = TRUE;
+ } else if (ExactMatch) {
+ OpenData->OpenCount++;
+ Status = EFI_SUCCESS;
+ goto Done;
+ }
+ }
+
+ //
+ // ByDriver TRUE -> A driver is managing (UserHandle, Protocol)
+ // ByDriver FALSE -> There are no drivers managing (UserHandle, Protocol)
+ // Exclusive TRUE -> Something has exclusive access to (UserHandle, Protocol)
+ // Exclusive FALSE -> Nothing has exclusive access to (UserHandle, Protocol)
+ //
+
+ switch (Attributes) {
+ case EFI_OPEN_PROTOCOL_BY_DRIVER:
+ if (Exclusive || ByDriver) {
+ Status = EFI_ACCESS_DENIED;
+ goto Done;
+ }
+
+ break;
+ case EFI_OPEN_PROTOCOL_BY_DRIVER | EFI_OPEN_PROTOCOL_EXCLUSIVE:
+ case EFI_OPEN_PROTOCOL_EXCLUSIVE:
+ if (Exclusive) {
+ Status = EFI_ACCESS_DENIED;
+ goto Done;
+ }
+
+ if (ByDriver) {
+ do {
+ Disconnect = FALSE;
+ for (Link = Prot->OpenList.ForwardLink; Link != &Prot->OpenList; Link = Link->ForwardLink) {
+ OpenData = CR (Link, OPEN_PROTOCOL_DATA, Link, OPEN_PROTOCOL_DATA_SIGNATURE);
+ if ((OpenData->Attributes & EFI_OPEN_PROTOCOL_BY_DRIVER) != 0) {
+ Disconnect = TRUE;
+ CoreReleaseProtocolLock ();
+ Status = CoreDisconnectController (UserHandle, OpenData->AgentHandle, NULL);
+ CoreAcquireProtocolLock ();
+ if (EFI_ERROR (Status)) {
+ Status = EFI_ACCESS_DENIED;
+ goto Done;
+ } else {
+ break;
+ }
+ }
+ }
+ } while (Disconnect);
+ }
+
+ break;
+ case EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER:
+ case EFI_OPEN_PROTOCOL_BY_HANDLE_PROTOCOL:
+ case EFI_OPEN_PROTOCOL_GET_PROTOCOL:
+ case EFI_OPEN_PROTOCOL_TEST_PROTOCOL:
+ break;
+ }
+
+ if (ImageHandle == NULL) {
+ Status = EFI_SUCCESS;
+ goto Done;
+ }
+
+ //
+ // Create new entry
+ //
+ OpenData = AllocatePool (sizeof (OPEN_PROTOCOL_DATA));
+ if (OpenData == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ } else {
+ OpenData->Signature = OPEN_PROTOCOL_DATA_SIGNATURE;
+ OpenData->AgentHandle = ImageHandle;
+ OpenData->ControllerHandle = ControllerHandle;
+ OpenData->Attributes = Attributes;
+ OpenData->OpenCount = 1;
+ InsertTailList (&Prot->OpenList, &OpenData->Link);
+ Prot->OpenListCount++;
+ Status = EFI_SUCCESS;
+ }
+
+Done:
+
+ if (Attributes != EFI_OPEN_PROTOCOL_TEST_PROTOCOL) {
+ //
+ // Keep Interface unmodified in case of any Error
+ // except EFI_ALREADY_STARTED and EFI_UNSUPPORTED.
+ //
+ if (!EFI_ERROR (Status) || (Status == EFI_ALREADY_STARTED)) {
+ //
+ // According to above logic, if 'Prot' is NULL, then the 'Status' must be
+ // EFI_UNSUPPORTED. Here the 'Status' is not EFI_UNSUPPORTED, so 'Prot'
+ // must be not NULL.
+ //
+ // The ASSERT here is for addressing a false positive NULL pointer
+ // dereference issue raised from static analysis.
+ //
+ ASSERT (Prot != NULL);
+ //
+ // EFI_ALREADY_STARTED is not an error for bus driver.
+ // Return the corresponding protocol interface.
+ //
+ *Interface = Prot->Interface;
+ } else if (Status == EFI_UNSUPPORTED) {
+ //
+ // Return NULL Interface if Unsupported Protocol.
+ //
+ *Interface = NULL;
+ }
+ }
+
+ //
+ // Done. Release the database lock and return
+ //
+ CoreReleaseProtocolLock ();
+ return Status;
+}
+
+/**
+ Closes a protocol on a handle that was opened using OpenProtocol().
+
+ @param UserHandle The handle for the protocol interface that was
+ previously opened with OpenProtocol(), and is
+ now being closed.
+ @param Protocol The published unique identifier of the protocol.
+ It is the caller's responsibility to pass in a
+ valid GUID.
+ @param AgentHandle The handle of the agent that is closing the
+ protocol interface.
+ @param ControllerHandle If the agent that opened a protocol is a driver
+ that follows the EFI Driver Model, then this
+ parameter is the controller handle that required
+ the protocol interface. If the agent does not
+ follow the EFI Driver Model, then this parameter
+ is optional and may be NULL.
+
+ @retval EFI_SUCCESS The protocol instance was closed.
+ @retval EFI_INVALID_PARAMETER Handle, AgentHandle or ControllerHandle is not a
+ valid EFI_HANDLE.
+ @retval EFI_NOT_FOUND Can not find the specified protocol or
+ AgentHandle.
+
+**/
+EFI_STATUS
+EFIAPI
+CoreCloseProtocol (
+ IN EFI_HANDLE UserHandle,
+ IN EFI_GUID *Protocol,
+ IN EFI_HANDLE AgentHandle,
+ IN EFI_HANDLE ControllerHandle
+ )
+{
+ EFI_STATUS Status;
+ PROTOCOL_INTERFACE *ProtocolInterface;
+ LIST_ENTRY *Link;
+ OPEN_PROTOCOL_DATA *OpenData;
+
+ //
+ // Lock the protocol database
+ //
+ CoreAcquireProtocolLock ();
+
+ //
+ // Check for invalid parameters
+ //
+ Status = CoreValidateHandle (UserHandle);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ Status = CoreValidateHandle (AgentHandle);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ if (ControllerHandle != NULL) {
+ Status = CoreValidateHandle (ControllerHandle);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+ }
+
+ if (Protocol == NULL) {
+ Status = EFI_INVALID_PARAMETER;
+ goto Done;
+ }
+
+ //
+ // Look at each protocol interface for a match
+ //
+ Status = EFI_NOT_FOUND;
+ ProtocolInterface = CoreGetProtocolInterface (UserHandle, Protocol);
+ if (ProtocolInterface == NULL) {
+ goto Done;
+ }
+
+ //
+ // Walk the Open data base looking for AgentHandle
+ //
+ Link = ProtocolInterface->OpenList.ForwardLink;
+ while (Link != &ProtocolInterface->OpenList) {
+ OpenData = CR (Link, OPEN_PROTOCOL_DATA, Link, OPEN_PROTOCOL_DATA_SIGNATURE);
+ Link = Link->ForwardLink;
+ if ((OpenData->AgentHandle == AgentHandle) && (OpenData->ControllerHandle == ControllerHandle)) {
+ RemoveEntryList (&OpenData->Link);
+ ProtocolInterface->OpenListCount--;
+ CoreFreePool (OpenData);
+ Status = EFI_SUCCESS;
+ }
+ }
+
+Done:
+ //
+ // Done. Release the database lock and return.
+ //
+ CoreReleaseProtocolLock ();
+ return Status;
+}
+
+/**
+ Return information about Opened protocols in the system
+
+ @param UserHandle The handle to close the protocol interface on
+ @param Protocol The ID of the protocol
+ @param EntryBuffer A pointer to a buffer of open protocol information in the
+ form of EFI_OPEN_PROTOCOL_INFORMATION_ENTRY structures.
+ @param EntryCount Number of EntryBuffer entries
+
+ @retval EFI_SUCCESS The open protocol information was returned in EntryBuffer,
+ and the number of entries was returned EntryCount.
+ @retval EFI_NOT_FOUND Handle does not support the protocol specified by Protocol.
+ @retval EFI_OUT_OF_RESOURCES There are not enough resources available to allocate EntryBuffer.
+
+**/
+EFI_STATUS
+EFIAPI
+CoreOpenProtocolInformation (
+ IN EFI_HANDLE UserHandle,
+ IN EFI_GUID *Protocol,
+ OUT EFI_OPEN_PROTOCOL_INFORMATION_ENTRY **EntryBuffer,
+ OUT UINTN *EntryCount
+ )
+{
+ EFI_STATUS Status;
+ PROTOCOL_INTERFACE *ProtocolInterface;
+ LIST_ENTRY *Link;
+ OPEN_PROTOCOL_DATA *OpenData;
+ EFI_OPEN_PROTOCOL_INFORMATION_ENTRY *Buffer;
+ UINTN Count;
+ UINTN Size;
+
+ *EntryBuffer = NULL;
+ *EntryCount = 0;
+
+ //
+ // Lock the protocol database
+ //
+ CoreAcquireProtocolLock ();
+
+ //
+ // Check for invalid UserHandle
+ //
+ Status = CoreValidateHandle (UserHandle);
+ if (EFI_ERROR (Status)) {
+ Status = EFI_NOT_FOUND;
+ goto Done;
+ }
+
+ //
+ // Look at each protocol interface for a match
+ //
+ Status = EFI_NOT_FOUND;
+ ProtocolInterface = CoreGetProtocolInterface (UserHandle, Protocol);
+ if (ProtocolInterface == NULL) {
+ goto Done;
+ }
+
+ //
+ // Count the number of Open Entries
+ //
+ for ( Link = ProtocolInterface->OpenList.ForwardLink, Count = 0;
+ (Link != &ProtocolInterface->OpenList);
+ Link = Link->ForwardLink )
+ {
+ Count++;
+ }
+
+ ASSERT (Count == ProtocolInterface->OpenListCount);
+
+ if (Count == 0) {
+ Size = sizeof (EFI_OPEN_PROTOCOL_INFORMATION_ENTRY);
+ } else {
+ Size = Count * sizeof (EFI_OPEN_PROTOCOL_INFORMATION_ENTRY);
+ }
+
+ Buffer = AllocatePool (Size);
+ if (Buffer == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Done;
+ }
+
+ Status = EFI_SUCCESS;
+ for ( Link = ProtocolInterface->OpenList.ForwardLink, Count = 0;
+ (Link != &ProtocolInterface->OpenList);
+ Link = Link->ForwardLink, Count++ )
+ {
+ OpenData = CR (Link, OPEN_PROTOCOL_DATA, Link, OPEN_PROTOCOL_DATA_SIGNATURE);
+
+ Buffer[Count].AgentHandle = OpenData->AgentHandle;
+ Buffer[Count].ControllerHandle = OpenData->ControllerHandle;
+ Buffer[Count].Attributes = OpenData->Attributes;
+ Buffer[Count].OpenCount = OpenData->OpenCount;
+ }
+
+ *EntryBuffer = Buffer;
+ *EntryCount = Count;
+
+Done:
+ //
+ // Done. Release the database lock.
+ //
+ CoreReleaseProtocolLock ();
+ return Status;
+}
+
+/**
+ Retrieves the list of protocol interface GUIDs that are installed on a handle in a buffer allocated
+ from pool.
+
+ @param UserHandle The handle from which to retrieve the list of
+ protocol interface GUIDs.
+ @param ProtocolBuffer A pointer to the list of protocol interface GUID
+ pointers that are installed on Handle.
+ @param ProtocolBufferCount A pointer to the number of GUID pointers present
+ in ProtocolBuffer.
+
+ @retval EFI_SUCCESS The list of protocol interface GUIDs installed
+ on Handle was returned in ProtocolBuffer. The
+ number of protocol interface GUIDs was returned
+ in ProtocolBufferCount.
+ @retval EFI_INVALID_PARAMETER Handle is NULL.
+ @retval EFI_INVALID_PARAMETER Handle is not a valid EFI_HANDLE.
+ @retval EFI_INVALID_PARAMETER ProtocolBuffer is NULL.
+ @retval EFI_INVALID_PARAMETER ProtocolBufferCount is NULL.
+ @retval EFI_OUT_OF_RESOURCES There is not enough pool memory to store the
+ results.
+
+**/
+EFI_STATUS
+EFIAPI
+CoreProtocolsPerHandle (
+ IN EFI_HANDLE UserHandle,
+ OUT EFI_GUID ***ProtocolBuffer,
+ OUT UINTN *ProtocolBufferCount
+ )
+{
+ EFI_STATUS Status;
+ IHANDLE *Handle;
+ PROTOCOL_INTERFACE *Prot;
+ LIST_ENTRY *Link;
+ UINTN ProtocolCount;
+ EFI_GUID **Buffer;
+
+ if (ProtocolBuffer == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (ProtocolBufferCount == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ *ProtocolBufferCount = 0;
+
+ ProtocolCount = 0;
+
+ CoreAcquireProtocolLock ();
+
+ Status = CoreValidateHandle (UserHandle);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ Handle = (IHANDLE *)UserHandle;
+
+ for (Link = Handle->Protocols.ForwardLink; Link != &Handle->Protocols; Link = Link->ForwardLink) {
+ ProtocolCount++;
+ }
+
+ //
+ // If there are no protocol interfaces installed on Handle, then Handle is not a valid EFI_HANDLE
+ //
+ if (ProtocolCount == 0) {
+ Status = EFI_INVALID_PARAMETER;
+ goto Done;
+ }
+
+ Buffer = AllocatePool (sizeof (EFI_GUID *) * ProtocolCount);
+ if (Buffer == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Done;
+ }
+
+ *ProtocolBuffer = Buffer;
+ *ProtocolBufferCount = ProtocolCount;
+
+ for ( Link = Handle->Protocols.ForwardLink, ProtocolCount = 0;
+ Link != &Handle->Protocols;
+ Link = Link->ForwardLink, ProtocolCount++)
+ {
+ Prot = CR (Link, PROTOCOL_INTERFACE, Link, PROTOCOL_INTERFACE_SIGNATURE);
+ Buffer[ProtocolCount] = &(Prot->Protocol->ProtocolID);
+ }
+
+ Status = EFI_SUCCESS;
+
+Done:
+ CoreReleaseProtocolLock ();
+ return Status;
+}
+
+/**
+ return handle database key.
+
+
+ @return Handle database key.
+
+**/
+UINT64
+CoreGetHandleDatabaseKey (
+ VOID
+ )
+{
+ return gHandleDatabaseKey;
+}
+
+/**
+ Go connect any handles that were created or modified while a image executed.
+
+ @param Key The Key to show that the handle has been
+ created/modified
+
+**/
+VOID
+CoreConnectHandlesByKey (
+ UINT64 Key
+ )
+{
+ UINTN Count;
+ LIST_ENTRY *Link;
+ EFI_HANDLE *HandleBuffer;
+ IHANDLE *Handle;
+ UINTN Index;
+
+ //
+ // Lock the protocol database
+ //
+ CoreAcquireProtocolLock ();
+
+ for (Link = gHandleList.ForwardLink, Count = 0; Link != &gHandleList; Link = Link->ForwardLink) {
+ Handle = CR (Link, IHANDLE, AllHandles, EFI_HANDLE_SIGNATURE);
+ if (Handle->Key > Key) {
+ Count++;
+ }
+ }
+
+ HandleBuffer = AllocatePool (Count * sizeof (EFI_HANDLE));
+ if (HandleBuffer == NULL) {
+ CoreReleaseProtocolLock ();
+ return;
+ }
+
+ for (Link = gHandleList.ForwardLink, Count = 0; Link != &gHandleList; Link = Link->ForwardLink) {
+ Handle = CR (Link, IHANDLE, AllHandles, EFI_HANDLE_SIGNATURE);
+ if (Handle->Key > Key) {
+ HandleBuffer[Count++] = Handle;
+ }
+ }
+
+ //
+ // Unlock the protocol database
+ //
+ CoreReleaseProtocolLock ();
+
+ //
+ // Connect all handles whose Key value is greater than Key
+ //
+ for (Index = 0; Index < Count; Index++) {
+ CoreConnectController (HandleBuffer[Index], NULL, NULL, TRUE);
+ }
+
+ CoreFreePool (HandleBuffer);
+}
diff --git a/MdeModulePkg/Core/Dxe/Hand/Handle.h b/MdeModulePkg/Core/Dxe/Hand/Handle.h
index 5c66e4da66..df4b934123 100644
--- a/MdeModulePkg/Core/Dxe/Hand/Handle.h
+++ b/MdeModulePkg/Core/Dxe/Hand/Handle.h
@@ -1,252 +1,252 @@
-/** @file
- Support functions for managing protocol.
-
-Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
-SPDX-License-Identifier: BSD-2-Clause-Patent
-
-**/
-
-#ifndef _HAND_H_
-#define _HAND_H_
-
-#define EFI_HANDLE_SIGNATURE SIGNATURE_32('h','n','d','l')
-
-///
-/// IHANDLE - contains a list of protocol handles
-///
-typedef struct {
- UINTN Signature;
- /// All handles list of IHANDLE
- LIST_ENTRY AllHandles;
- /// List of PROTOCOL_INTERFACE's for this handle
- LIST_ENTRY Protocols;
- UINTN LocateRequest;
- /// The Handle Database Key value when this handle was last created or modified
- UINT64 Key;
-} IHANDLE;
-
-#define ASSERT_IS_HANDLE(a) ASSERT((a)->Signature == EFI_HANDLE_SIGNATURE)
-
-#define PROTOCOL_ENTRY_SIGNATURE SIGNATURE_32('p','r','t','e')
-
-///
-/// PROTOCOL_ENTRY - each different protocol has 1 entry in the protocol
-/// database. Each handler that supports this protocol is listed, along
-/// with a list of registered notifies.
-///
-typedef struct {
- UINTN Signature;
- /// Link Entry inserted to mProtocolDatabase
- LIST_ENTRY AllEntries;
- /// ID of the protocol
- EFI_GUID ProtocolID;
- /// All protocol interfaces
- LIST_ENTRY Protocols;
- /// Registerd notification handlers
- LIST_ENTRY Notify;
-} PROTOCOL_ENTRY;
-
-#define PROTOCOL_INTERFACE_SIGNATURE SIGNATURE_32('p','i','f','c')
-
-///
-/// PROTOCOL_INTERFACE - each protocol installed on a handle is tracked
-/// with a protocol interface structure
-///
-typedef struct {
- UINTN Signature;
- /// Link on IHANDLE.Protocols
- LIST_ENTRY Link;
- /// Back pointer
- IHANDLE *Handle;
- /// Link on PROTOCOL_ENTRY.Protocols
- LIST_ENTRY ByProtocol;
- /// The protocol ID
- PROTOCOL_ENTRY *Protocol;
- /// The interface value
- VOID *Interface;
- /// OPEN_PROTOCOL_DATA list
- LIST_ENTRY OpenList;
- UINTN OpenListCount;
-} PROTOCOL_INTERFACE;
-
-#define OPEN_PROTOCOL_DATA_SIGNATURE SIGNATURE_32('p','o','d','l')
-
-typedef struct {
- UINTN Signature;
- /// Link on PROTOCOL_INTERFACE.OpenList
- LIST_ENTRY Link;
-
- EFI_HANDLE AgentHandle;
- EFI_HANDLE ControllerHandle;
- UINT32 Attributes;
- UINT32 OpenCount;
-} OPEN_PROTOCOL_DATA;
-
-#define PROTOCOL_NOTIFY_SIGNATURE SIGNATURE_32('p','r','t','n')
-
-///
-/// PROTOCOL_NOTIFY - used for each register notification for a protocol
-///
-typedef struct {
- UINTN Signature;
- PROTOCOL_ENTRY *Protocol;
- /// All notifications for this protocol
- LIST_ENTRY Link;
- /// Event to notify
- EFI_EVENT Event;
- /// Last position notified
- LIST_ENTRY *Position;
-} PROTOCOL_NOTIFY;
-
-/**
- Finds the protocol entry for the requested protocol.
- The gProtocolDatabaseLock must be owned
-
- @param Protocol The ID of the protocol
- @param Create Create a new entry if not found
-
- @return Protocol entry
-
-**/
-PROTOCOL_ENTRY *
-CoreFindProtocolEntry (
- IN EFI_GUID *Protocol,
- IN BOOLEAN Create
- );
-
-/**
- Signal event for every protocol in protocol entry.
-
- @param ProtEntry Protocol entry
-
-**/
-VOID
-CoreNotifyProtocolEntry (
- IN PROTOCOL_ENTRY *ProtEntry
- );
-
-/**
- Finds the protocol instance for the requested handle and protocol.
- Note: This function doesn't do parameters checking, it's caller's responsibility
- to pass in valid parameters.
-
- @param Handle The handle to search the protocol on
- @param Protocol GUID of the protocol
- @param Interface The interface for the protocol being searched
-
- @return Protocol instance (NULL: Not found)
-
-**/
-PROTOCOL_INTERFACE *
-CoreFindProtocolInterface (
- IN IHANDLE *Handle,
- IN EFI_GUID *Protocol,
- IN VOID *Interface
- );
-
-/**
- Removes Protocol from the protocol list (but not the handle list).
-
- @param Handle The handle to remove protocol on.
- @param Protocol GUID of the protocol to be moved
- @param Interface The interface of the protocol
-
- @return Protocol Entry
-
-**/
-PROTOCOL_INTERFACE *
-CoreRemoveInterfaceFromProtocol (
- IN IHANDLE *Handle,
- IN EFI_GUID *Protocol,
- IN VOID *Interface
- );
-
-/**
- Connects a controller to a driver.
-
- @param ControllerHandle Handle of the controller to be
- connected.
- @param ContextDriverImageHandles DriverImageHandle A pointer to an
- ordered list of driver image
- handles.
- @param RemainingDevicePath RemainingDevicePath A pointer to
- the device path that specifies a
- child of the controller
- specified by ControllerHandle.
-
- @retval EFI_SUCCESS One or more drivers were
- connected to ControllerHandle.
- @retval EFI_OUT_OF_RESOURCES No enough system resources to
- complete the request.
- @retval EFI_NOT_FOUND No drivers were connected to
- ControllerHandle.
-
-**/
-EFI_STATUS
-CoreConnectSingleController (
- IN EFI_HANDLE ControllerHandle,
- IN EFI_HANDLE *ContextDriverImageHandles OPTIONAL,
- IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL
- );
-
-/**
- Attempts to disconnect all drivers that are using the protocol interface being queried.
- If failed, reconnect all drivers disconnected.
- Note: This function doesn't do parameters checking, it's caller's responsibility
- to pass in valid parameters.
-
- @param UserHandle The handle on which the protocol is installed
- @param Prot The protocol to disconnect drivers from
-
- @retval EFI_SUCCESS Drivers using the protocol interface are all
- disconnected
- @retval EFI_ACCESS_DENIED Failed to disconnect one or all of the drivers
-
-**/
-EFI_STATUS
-CoreDisconnectControllersUsingProtocolInterface (
- IN EFI_HANDLE UserHandle,
- IN PROTOCOL_INTERFACE *Prot
- );
-
-/**
- Acquire lock on gProtocolDatabaseLock.
-
-**/
-VOID
-CoreAcquireProtocolLock (
- VOID
- );
-
-/**
- Release lock on gProtocolDatabaseLock.
-
-**/
-VOID
-CoreReleaseProtocolLock (
- VOID
- );
-
-/**
- Check whether a handle is a valid EFI_HANDLE
- The gProtocolDatabaseLock must be owned
-
- @param UserHandle The handle to check
-
- @retval EFI_INVALID_PARAMETER The handle is NULL or not a valid EFI_HANDLE.
- @retval EFI_SUCCESS The handle is valid EFI_HANDLE.
-
-**/
-EFI_STATUS
-CoreValidateHandle (
- IN EFI_HANDLE UserHandle
- );
-
-//
-// Externs
-//
-extern EFI_LOCK gProtocolDatabaseLock;
-extern LIST_ENTRY gHandleList;
-extern UINT64 gHandleDatabaseKey;
-
-#endif
+/** @file
+ Support functions for managing protocol.
+
+Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _HAND_H_
+#define _HAND_H_
+
+#define EFI_HANDLE_SIGNATURE SIGNATURE_32('h','n','d','l')
+
+///
+/// IHANDLE - contains a list of protocol handles
+///
+typedef struct {
+ UINTN Signature;
+ /// All handles list of IHANDLE
+ LIST_ENTRY AllHandles;
+ /// List of PROTOCOL_INTERFACE's for this handle
+ LIST_ENTRY Protocols;
+ UINTN LocateRequest;
+ /// The Handle Database Key value when this handle was last created or modified
+ UINT64 Key;
+} IHANDLE;
+
+#define ASSERT_IS_HANDLE(a) ASSERT((a)->Signature == EFI_HANDLE_SIGNATURE)
+
+#define PROTOCOL_ENTRY_SIGNATURE SIGNATURE_32('p','r','t','e')
+
+///
+/// PROTOCOL_ENTRY - each different protocol has 1 entry in the protocol
+/// database. Each handler that supports this protocol is listed, along
+/// with a list of registered notifies.
+///
+typedef struct {
+ UINTN Signature;
+ /// Link Entry inserted to mProtocolDatabase
+ LIST_ENTRY AllEntries;
+ /// ID of the protocol
+ EFI_GUID ProtocolID;
+ /// All protocol interfaces
+ LIST_ENTRY Protocols;
+ /// Registerd notification handlers
+ LIST_ENTRY Notify;
+} PROTOCOL_ENTRY;
+
+#define PROTOCOL_INTERFACE_SIGNATURE SIGNATURE_32('p','i','f','c')
+
+///
+/// PROTOCOL_INTERFACE - each protocol installed on a handle is tracked
+/// with a protocol interface structure
+///
+typedef struct {
+ UINTN Signature;
+ /// Link on IHANDLE.Protocols
+ LIST_ENTRY Link;
+ /// Back pointer
+ IHANDLE *Handle;
+ /// Link on PROTOCOL_ENTRY.Protocols
+ LIST_ENTRY ByProtocol;
+ /// The protocol ID
+ PROTOCOL_ENTRY *Protocol;
+ /// The interface value
+ VOID *Interface;
+ /// OPEN_PROTOCOL_DATA list
+ LIST_ENTRY OpenList;
+ UINTN OpenListCount;
+} PROTOCOL_INTERFACE;
+
+#define OPEN_PROTOCOL_DATA_SIGNATURE SIGNATURE_32('p','o','d','l')
+
+typedef struct {
+ UINTN Signature;
+ /// Link on PROTOCOL_INTERFACE.OpenList
+ LIST_ENTRY Link;
+
+ EFI_HANDLE AgentHandle;
+ EFI_HANDLE ControllerHandle;
+ UINT32 Attributes;
+ UINT32 OpenCount;
+} OPEN_PROTOCOL_DATA;
+
+#define PROTOCOL_NOTIFY_SIGNATURE SIGNATURE_32('p','r','t','n')
+
+///
+/// PROTOCOL_NOTIFY - used for each register notification for a protocol
+///
+typedef struct {
+ UINTN Signature;
+ PROTOCOL_ENTRY *Protocol;
+ /// All notifications for this protocol
+ LIST_ENTRY Link;
+ /// Event to notify
+ EFI_EVENT Event;
+ /// Last position notified
+ LIST_ENTRY *Position;
+} PROTOCOL_NOTIFY;
+
+/**
+ Finds the protocol entry for the requested protocol.
+ The gProtocolDatabaseLock must be owned
+
+ @param Protocol The ID of the protocol
+ @param Create Create a new entry if not found
+
+ @return Protocol entry
+
+**/
+PROTOCOL_ENTRY *
+CoreFindProtocolEntry (
+ IN EFI_GUID *Protocol,
+ IN BOOLEAN Create
+ );
+
+/**
+ Signal event for every protocol in protocol entry.
+
+ @param ProtEntry Protocol entry
+
+**/
+VOID
+CoreNotifyProtocolEntry (
+ IN PROTOCOL_ENTRY *ProtEntry
+ );
+
+/**
+ Finds the protocol instance for the requested handle and protocol.
+ Note: This function doesn't do parameters checking, it's caller's responsibility
+ to pass in valid parameters.
+
+ @param Handle The handle to search the protocol on
+ @param Protocol GUID of the protocol
+ @param Interface The interface for the protocol being searched
+
+ @return Protocol instance (NULL: Not found)
+
+**/
+PROTOCOL_INTERFACE *
+CoreFindProtocolInterface (
+ IN IHANDLE *Handle,
+ IN EFI_GUID *Protocol,
+ IN VOID *Interface
+ );
+
+/**
+ Removes Protocol from the protocol list (but not the handle list).
+
+ @param Handle The handle to remove protocol on.
+ @param Protocol GUID of the protocol to be moved
+ @param Interface The interface of the protocol
+
+ @return Protocol Entry
+
+**/
+PROTOCOL_INTERFACE *
+CoreRemoveInterfaceFromProtocol (
+ IN IHANDLE *Handle,
+ IN EFI_GUID *Protocol,
+ IN VOID *Interface
+ );
+
+/**
+ Connects a controller to a driver.
+
+ @param ControllerHandle Handle of the controller to be
+ connected.
+ @param ContextDriverImageHandles DriverImageHandle A pointer to an
+ ordered list of driver image
+ handles.
+ @param RemainingDevicePath RemainingDevicePath A pointer to
+ the device path that specifies a
+ child of the controller
+ specified by ControllerHandle.
+
+ @retval EFI_SUCCESS One or more drivers were
+ connected to ControllerHandle.
+ @retval EFI_OUT_OF_RESOURCES No enough system resources to
+ complete the request.
+ @retval EFI_NOT_FOUND No drivers were connected to
+ ControllerHandle.
+
+**/
+EFI_STATUS
+CoreConnectSingleController (
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_HANDLE *ContextDriverImageHandles OPTIONAL,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL
+ );
+
+/**
+ Attempts to disconnect all drivers that are using the protocol interface being queried.
+ If failed, reconnect all drivers disconnected.
+ Note: This function doesn't do parameters checking, it's caller's responsibility
+ to pass in valid parameters.
+
+ @param UserHandle The handle on which the protocol is installed
+ @param Prot The protocol to disconnect drivers from
+
+ @retval EFI_SUCCESS Drivers using the protocol interface are all
+ disconnected
+ @retval EFI_ACCESS_DENIED Failed to disconnect one or all of the drivers
+
+**/
+EFI_STATUS
+CoreDisconnectControllersUsingProtocolInterface (
+ IN EFI_HANDLE UserHandle,
+ IN PROTOCOL_INTERFACE *Prot
+ );
+
+/**
+ Acquire lock on gProtocolDatabaseLock.
+
+**/
+VOID
+CoreAcquireProtocolLock (
+ VOID
+ );
+
+/**
+ Release lock on gProtocolDatabaseLock.
+
+**/
+VOID
+CoreReleaseProtocolLock (
+ VOID
+ );
+
+/**
+ Check whether a handle is a valid EFI_HANDLE
+ The gProtocolDatabaseLock must be owned
+
+ @param UserHandle The handle to check
+
+ @retval EFI_INVALID_PARAMETER The handle is NULL or not a valid EFI_HANDLE.
+ @retval EFI_SUCCESS The handle is valid EFI_HANDLE.
+
+**/
+EFI_STATUS
+CoreValidateHandle (
+ IN EFI_HANDLE UserHandle
+ );
+
+//
+// Externs
+//
+extern EFI_LOCK gProtocolDatabaseLock;
+extern LIST_ENTRY gHandleList;
+extern UINT64 gHandleDatabaseKey;
+
+#endif
diff --git a/MdeModulePkg/Core/Dxe/Hand/Locate.c b/MdeModulePkg/Core/Dxe/Hand/Locate.c
index 8f20c6332d..4de2d1ea4d 100644
--- a/MdeModulePkg/Core/Dxe/Hand/Locate.c
+++ b/MdeModulePkg/Core/Dxe/Hand/Locate.c
@@ -1,741 +1,741 @@
-/** @file
- Locate handle functions
-
-Copyright (c) 2006 - 2023, Intel Corporation. All rights reserved.<BR>
-SPDX-License-Identifier: BSD-2-Clause-Patent
-
-**/
-
-#include "DxeMain.h"
-#include "Handle.h"
-
-//
-// ProtocolRequest - Last LocateHandle request ID
-//
-UINTN mEfiLocateHandleRequest = 0;
-
-//
-// Internal prototypes
-//
-
-typedef struct {
- EFI_GUID *Protocol;
- VOID *SearchKey;
- LIST_ENTRY *Position;
- PROTOCOL_ENTRY *ProtEntry;
-} LOCATE_POSITION;
-
-typedef
-IHANDLE *
-(*CORE_GET_NEXT) (
- IN OUT LOCATE_POSITION *Position,
- OUT VOID **Interface
- );
-
-/**
- Routine to get the next Handle, when you are searching for all handles.
-
- @param Position Information about which Handle to seach for.
- @param Interface Return the interface structure for the matching
- protocol.
-
- @return An pointer to IHANDLE if the next Position is not the end of the list.
- Otherwise,NULL is returned.
-
-**/
-IHANDLE *
-CoreGetNextLocateAllHandles (
- IN OUT LOCATE_POSITION *Position,
- OUT VOID **Interface
- );
-
-/**
- Routine to get the next Handle, when you are searching for register protocol
- notifies.
-
- @param Position Information about which Handle to seach for.
- @param Interface Return the interface structure for the matching
- protocol.
-
- @return An pointer to IHANDLE if the next Position is not the end of the list.
- Otherwise,NULL is returned.
-
-**/
-IHANDLE *
-CoreGetNextLocateByRegisterNotify (
- IN OUT LOCATE_POSITION *Position,
- OUT VOID **Interface
- );
-
-/**
- Routine to get the next Handle, when you are searching for a given protocol.
-
- @param Position Information about which Handle to seach for.
- @param Interface Return the interface structure for the matching
- protocol.
-
- @return An pointer to IHANDLE if the next Position is not the end of the list.
- Otherwise,NULL is returned.
-
-**/
-IHANDLE *
-CoreGetNextLocateByProtocol (
- IN OUT LOCATE_POSITION *Position,
- OUT VOID **Interface
- );
-
-/**
- Internal function for locating the requested handle(s) and returns them in Buffer.
- The caller should already have acquired the ProtocolLock.
-
- @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
-InternalCoreLocateHandle (
- 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 = CoreGetNextLocateAllHandles;
- break;
-
- case ByRegisterNotify:
- //
- // Must have SearchKey for locate ByRegisterNotify
- //
- if (SearchKey == NULL) {
- Status = EFI_INVALID_PARAMETER;
- break;
- }
-
- GetNext = CoreGetNextLocateByRegisterNotify;
- break;
-
- case ByProtocol:
- GetNext = CoreGetNextLocateByProtocol;
- if (Protocol == NULL) {
- Status = EFI_INVALID_PARAMETER;
- break;
- }
-
- //
- // Look up the protocol entry and set the head pointer
- //
- Position.ProtEntry = CoreFindProtocolEntry (Protocol, FALSE);
- if (Position.ProtEntry == NULL) {
- Status = EFI_NOT_FOUND;
- break;
- }
-
- Position.Position = &Position.ProtEntry->Protocols;
- break;
-
- default:
- Status = EFI_INVALID_PARAMETER;
- break;
- }
-
- if (EFI_ERROR (Status)) {
- return Status;
- }
-
- ASSERT (GetNext != NULL);
- //
- // Enumerate out the matching handles
- //
- mEfiLocateHandleRequest += 1;
- for ( ; ;) {
- //
- // Get the next handle. If no more handles, stop
- //
- Handle = GetNext (&Position, &Interface);
- if (NULL == Handle) {
- break;
- }
-
- //
- // Increase the resulting buffer size, and if this handle
- // fits return it
- //
- ResultSize += sizeof (Handle);
- if (ResultSize <= *BufferSize) {
- *ResultBuffer = Handle;
- ResultBuffer += 1;
- }
- }
-
- //
- // If the result is a zero length buffer, then there were no
- // matching handles
- //
- if (ResultSize == 0) {
- Status = EFI_NOT_FOUND;
- } else {
- //
- // Return the resulting buffer size. If it's larger than what
- // was passed, then set the error code
- //
- if (ResultSize > *BufferSize) {
- Status = EFI_BUFFER_TOO_SMALL;
- }
-
- *BufferSize = ResultSize;
-
- if ((SearchType == ByRegisterNotify) && !EFI_ERROR (Status)) {
- //
- // If this is a search by register notify and a handle was
- // returned, update the register notification position
- //
- ASSERT (SearchKey != NULL);
- ProtNotify = SearchKey;
- ProtNotify->Position = ProtNotify->Position->ForwardLink;
- }
- }
-
- 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
-CoreLocateHandle (
- IN EFI_LOCATE_SEARCH_TYPE SearchType,
- IN EFI_GUID *Protocol OPTIONAL,
- IN VOID *SearchKey OPTIONAL,
- IN OUT UINTN *BufferSize,
- OUT EFI_HANDLE *Buffer
- )
-{
- EFI_STATUS Status;
-
- //
- // Lock the protocol database
- //
- CoreAcquireProtocolLock ();
- Status = InternalCoreLocateHandle (SearchType, Protocol, SearchKey, BufferSize, Buffer);
- CoreReleaseProtocolLock ();
- return Status;
-}
-
-/**
- Routine to get the next Handle, when you are searching for all handles.
-
- @param Position Information about which Handle to seach for.
- @param Interface Return the interface structure for the matching
- protocol.
-
- @return An pointer to IHANDLE if the next Position is not the end of the list.
- Otherwise,NULL is returned.
-
-**/
-IHANDLE *
-CoreGetNextLocateAllHandles (
- IN OUT LOCATE_POSITION *Position,
- OUT VOID **Interface
- )
-{
- IHANDLE *Handle;
-
- //
- // Next handle
- //
- Position->Position = Position->Position->ForwardLink;
-
- //
- // If not at the end of the list, get the handle
- //
- Handle = NULL;
- *Interface = NULL;
- if (Position->Position != &gHandleList) {
- Handle = CR (Position->Position, IHANDLE, AllHandles, EFI_HANDLE_SIGNATURE);
- }
-
- return Handle;
-}
-
-/**
- Routine to get the next Handle, when you are searching for register protocol
- notifies.
-
- @param Position Information about which Handle to seach for.
- @param Interface Return the interface structure for the matching
- protocol.
-
- @return An pointer to IHANDLE if the next Position is not the end of the list.
- Otherwise,NULL is returned.
-
-**/
-IHANDLE *
-CoreGetNextLocateByRegisterNotify (
- IN OUT LOCATE_POSITION *Position,
- OUT VOID **Interface
- )
-{
- IHANDLE *Handle;
- PROTOCOL_NOTIFY *ProtNotify;
- PROTOCOL_INTERFACE *Prot;
- LIST_ENTRY *Link;
-
- Handle = NULL;
- *Interface = NULL;
- ProtNotify = Position->SearchKey;
-
- //
- // If this is the first request, get the next handle
- //
- if (ProtNotify != NULL) {
- ASSERT (ProtNotify->Signature == PROTOCOL_NOTIFY_SIGNATURE);
- Position->SearchKey = NULL;
-
- //
- // If not at the end of the list, get the next handle
- //
- Link = ProtNotify->Position->ForwardLink;
- if (Link != &ProtNotify->Protocol->Protocols) {
- Prot = CR (Link, PROTOCOL_INTERFACE, ByProtocol, PROTOCOL_INTERFACE_SIGNATURE);
- Handle = Prot->Handle;
- *Interface = Prot->Interface;
- }
- }
-
- return Handle;
-}
-
-/**
- Routine to get the next Handle, when you are searching for a given protocol.
-
- @param Position Information about which Handle to seach for.
- @param Interface Return the interface structure for the matching
- protocol.
-
- @return An pointer to IHANDLE if the next Position is not the end of the list.
- Otherwise,NULL is returned.
-
-**/
-IHANDLE *
-CoreGetNextLocateByProtocol (
- IN OUT LOCATE_POSITION *Position,
- OUT VOID **Interface
- )
-{
- IHANDLE *Handle;
- LIST_ENTRY *Link;
- PROTOCOL_INTERFACE *Prot;
-
- Handle = NULL;
- *Interface = NULL;
- for ( ; ;) {
- //
- // Next entry
- //
- Link = Position->Position->ForwardLink;
- Position->Position = Link;
-
- //
- // If not at the end, return the handle
- //
- if (Link == &Position->ProtEntry->Protocols) {
- Handle = NULL;
- break;
- }
-
- //
- // Get the handle
- //
- Prot = CR (Link, PROTOCOL_INTERFACE, ByProtocol, PROTOCOL_INTERFACE_SIGNATURE);
- Handle = Prot->Handle;
- *Interface = Prot->Interface;
-
- //
- // If this handle has not been returned this request, then
- // return it now
- //
- if (Handle->LocateRequest != mEfiLocateHandleRequest) {
- Handle->LocateRequest = mEfiLocateHandleRequest;
- break;
- }
- }
-
- return Handle;
-}
-
-/**
- Locates the handle to a device on the device path that supports the specified protocol.
-
- @param Protocol Specifies the protocol to search for.
- @param DevicePath On input, a pointer to a pointer to the device path. On output, the device
- path pointer is modified to point to the remaining part of the device
- path.
- @param Device A pointer to the returned device handle.
-
- @retval EFI_SUCCESS The resulting handle was returned.
- @retval EFI_NOT_FOUND No handles match the search.
- @retval EFI_INVALID_PARAMETER Protocol is NULL.
- @retval EFI_INVALID_PARAMETER DevicePath is NULL.
- @retval EFI_INVALID_PARAMETER A handle matched the search and Device is NULL.
-
-**/
-EFI_STATUS
-EFIAPI
-CoreLocateDevicePath (
- IN EFI_GUID *Protocol,
- IN OUT EFI_DEVICE_PATH_PROTOCOL **DevicePath,
- OUT EFI_HANDLE *Device
- )
-{
- INTN SourceSize;
- INTN Size;
- INTN BestMatch;
- UINTN HandleCount;
- UINTN Index;
- EFI_STATUS Status;
- EFI_HANDLE *Handles;
- EFI_HANDLE Handle;
- EFI_HANDLE BestDevice;
- EFI_DEVICE_PATH_PROTOCOL *SourcePath;
- EFI_DEVICE_PATH_PROTOCOL *TmpDevicePath;
-
- if (Protocol == NULL) {
- return EFI_INVALID_PARAMETER;
- }
-
- if ((DevicePath == NULL) || (*DevicePath == NULL)) {
- return EFI_INVALID_PARAMETER;
- }
-
- Handles = NULL;
- BestDevice = NULL;
- SourcePath = *DevicePath;
- TmpDevicePath = SourcePath;
- while (!IsDevicePathEnd (TmpDevicePath)) {
- if (IsDevicePathEndInstance (TmpDevicePath)) {
- //
- // If DevicePath is a multi-instance device path,
- // the function will operate on the first instance
- //
- break;
- }
-
- TmpDevicePath = NextDevicePathNode (TmpDevicePath);
- }
-
- SourceSize = (UINTN)TmpDevicePath - (UINTN)SourcePath;
-
- //
- // Get a list of all handles that support the requested protocol
- //
- Status = CoreLocateHandleBuffer (ByProtocol, Protocol, NULL, &HandleCount, &Handles);
- if (EFI_ERROR (Status) || (HandleCount == 0)) {
- return EFI_NOT_FOUND;
- }
-
- BestMatch = -1;
- for (Index = 0; Index < HandleCount; Index += 1) {
- Handle = Handles[Index];
- Status = CoreHandleProtocol (Handle, &gEfiDevicePathProtocolGuid, (VOID **)&TmpDevicePath);
- if (EFI_ERROR (Status)) {
- //
- // If this handle doesn't support device path, then skip it
- //
- continue;
- }
-
- //
- // Check if DevicePath is first part of SourcePath
- //
- Size = GetDevicePathSize (TmpDevicePath) - sizeof (EFI_DEVICE_PATH_PROTOCOL);
- ASSERT (Size >= 0);
- if ((Size <= SourceSize) && (CompareMem (SourcePath, TmpDevicePath, (UINTN)Size) == 0)) {
- //
- // If the size is equal to the best match, then we
- // have a duplicate device path for 2 different device
- // handles
- //
- ASSERT (Size != BestMatch);
-
- //
- // We've got a match, see if it's the best match so far
- //
- if (Size > BestMatch) {
- BestMatch = Size;
- BestDevice = Handle;
- }
- }
- }
-
- CoreFreePool (Handles);
-
- //
- // If there wasn't any match, then no parts of the device path was found.
- // Which is strange since there is likely a "root level" device path in the system.
- //
- if (BestMatch == -1) {
- return EFI_NOT_FOUND;
- }
-
- if (Device == NULL) {
- return EFI_INVALID_PARAMETER;
- }
-
- *Device = BestDevice;
-
- //
- // Return the remaining part of the device path
- //
- *DevicePath = (EFI_DEVICE_PATH_PROTOCOL *)(((UINT8 *)SourcePath) + BestMatch);
- return EFI_SUCCESS;
-}
-
-/**
- Return the first Protocol Interface that matches the Protocol GUID. If
- Registration is passed in, return a Protocol Instance that was just add
- to the system. If Registration is NULL return the first Protocol Interface
- you find.
-
- @param Protocol The protocol to search for
- @param Registration Optional Registration Key returned from
- RegisterProtocolNotify()
- @param Interface Return the Protocol interface (instance).
-
- @retval EFI_SUCCESS If a valid Interface is returned
- @retval EFI_INVALID_PARAMETER Invalid parameter
- @retval EFI_NOT_FOUND Protocol interface not found
-
-**/
-EFI_STATUS
-EFIAPI
-CoreLocateProtocol (
- IN EFI_GUID *Protocol,
- IN VOID *Registration OPTIONAL,
- OUT VOID **Interface
- )
-{
- EFI_STATUS Status;
- LOCATE_POSITION Position;
- PROTOCOL_NOTIFY *ProtNotify;
- IHANDLE *Handle;
-
- if ((Interface == NULL) || (Protocol == NULL)) {
- return EFI_INVALID_PARAMETER;
- }
-
- *Interface = NULL;
- Status = EFI_SUCCESS;
-
- //
- // Set initial position
- //
- Position.Protocol = Protocol;
- Position.SearchKey = Registration;
- Position.Position = &gHandleList;
-
- //
- // Lock the protocol database
- //
- Status = CoreAcquireLockOrFail (&gProtocolDatabaseLock);
- if (EFI_ERROR (Status)) {
- return EFI_NOT_FOUND;
- }
-
- mEfiLocateHandleRequest += 1;
-
- if (Registration == NULL) {
- //
- // Look up the protocol entry and set the head pointer
- //
- Position.ProtEntry = CoreFindProtocolEntry (Protocol, FALSE);
- if (Position.ProtEntry == NULL) {
- Status = EFI_NOT_FOUND;
- goto Done;
- }
-
- Position.Position = &Position.ProtEntry->Protocols;
-
- Handle = CoreGetNextLocateByProtocol (&Position, Interface);
- } else {
- Handle = CoreGetNextLocateByRegisterNotify (&Position, Interface);
- }
-
- if (Handle == NULL) {
- Status = EFI_NOT_FOUND;
- } else if (Registration != NULL) {
- //
- // If this is a search by register notify and a handle was
- // returned, update the register notification position
- //
- ProtNotify = Registration;
- ProtNotify->Position = ProtNotify->Position->ForwardLink;
- }
-
-Done:
- CoreReleaseProtocolLock ();
- return Status;
-}
-
-/**
- Function returns an array of handles that support the requested protocol
- in a buffer allocated from pool. This is a version of CoreLocateHandle()
- that allocates a buffer for the caller.
-
- @param SearchType Specifies which handle(s) are to be returned.
- @param Protocol Provides the protocol to search by. This
- parameter is only valid for SearchType
- ByProtocol.
- @param SearchKey Supplies the search key depending on the
- SearchType.
- @param NumberHandles The number of handles returned in Buffer.
- @param Buffer A pointer to the buffer to return the requested
- array of handles that support Protocol.
-
- @retval EFI_SUCCESS The result array of handles was returned.
- @retval EFI_NOT_FOUND No handles match the search.
- @retval EFI_OUT_OF_RESOURCES There is not enough pool memory to store the
- matching results.
- @retval EFI_INVALID_PARAMETER One or more parameters are not valid.
-
-**/
-EFI_STATUS
-EFIAPI
-CoreLocateHandleBuffer (
- IN EFI_LOCATE_SEARCH_TYPE SearchType,
- IN EFI_GUID *Protocol OPTIONAL,
- IN VOID *SearchKey OPTIONAL,
- IN OUT UINTN *NumberHandles,
- OUT EFI_HANDLE **Buffer
- )
-{
- EFI_STATUS Status;
- UINTN BufferSize;
-
- if (NumberHandles == NULL) {
- return EFI_INVALID_PARAMETER;
- }
-
- if (Buffer == NULL) {
- return EFI_INVALID_PARAMETER;
- }
-
- BufferSize = 0;
- *NumberHandles = 0;
- *Buffer = NULL;
-
- //
- // Lock the protocol database
- //
- CoreAcquireProtocolLock ();
- Status = InternalCoreLocateHandle (
- SearchType,
- Protocol,
- SearchKey,
- &BufferSize,
- *Buffer
- );
- //
- // LocateHandleBuffer() returns incorrect status code if SearchType is
- // invalid.
- //
- // Add code to correctly handle expected errors from CoreLocateHandle().
- //
- if (EFI_ERROR (Status) && (Status != EFI_BUFFER_TOO_SMALL)) {
- if (Status != EFI_INVALID_PARAMETER) {
- Status = EFI_NOT_FOUND;
- }
-
- CoreReleaseProtocolLock ();
- return Status;
- }
-
- *Buffer = AllocatePool (BufferSize);
- if (*Buffer == NULL) {
- CoreReleaseProtocolLock ();
- return EFI_OUT_OF_RESOURCES;
- }
-
- Status = InternalCoreLocateHandle (
- SearchType,
- Protocol,
- SearchKey,
- &BufferSize,
- *Buffer
- );
-
- *NumberHandles = BufferSize / sizeof (EFI_HANDLE);
- if (EFI_ERROR (Status)) {
- *NumberHandles = 0;
- if (*Buffer != NULL) {
- CoreFreePool (*Buffer);
- *Buffer = NULL;
- }
- }
-
- CoreReleaseProtocolLock ();
- return Status;
-}
+/** @file
+ Locate handle functions
+
+Copyright (c) 2006 - 2023, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "DxeMain.h"
+#include "Handle.h"
+
+//
+// ProtocolRequest - Last LocateHandle request ID
+//
+UINTN mEfiLocateHandleRequest = 0;
+
+//
+// Internal prototypes
+//
+
+typedef struct {
+ EFI_GUID *Protocol;
+ VOID *SearchKey;
+ LIST_ENTRY *Position;
+ PROTOCOL_ENTRY *ProtEntry;
+} LOCATE_POSITION;
+
+typedef
+IHANDLE *
+(*CORE_GET_NEXT) (
+ IN OUT LOCATE_POSITION *Position,
+ OUT VOID **Interface
+ );
+
+/**
+ Routine to get the next Handle, when you are searching for all handles.
+
+ @param Position Information about which Handle to seach for.
+ @param Interface Return the interface structure for the matching
+ protocol.
+
+ @return An pointer to IHANDLE if the next Position is not the end of the list.
+ Otherwise,NULL is returned.
+
+**/
+IHANDLE *
+CoreGetNextLocateAllHandles (
+ IN OUT LOCATE_POSITION *Position,
+ OUT VOID **Interface
+ );
+
+/**
+ Routine to get the next Handle, when you are searching for register protocol
+ notifies.
+
+ @param Position Information about which Handle to seach for.
+ @param Interface Return the interface structure for the matching
+ protocol.
+
+ @return An pointer to IHANDLE if the next Position is not the end of the list.
+ Otherwise,NULL is returned.
+
+**/
+IHANDLE *
+CoreGetNextLocateByRegisterNotify (
+ IN OUT LOCATE_POSITION *Position,
+ OUT VOID **Interface
+ );
+
+/**
+ Routine to get the next Handle, when you are searching for a given protocol.
+
+ @param Position Information about which Handle to seach for.
+ @param Interface Return the interface structure for the matching
+ protocol.
+
+ @return An pointer to IHANDLE if the next Position is not the end of the list.
+ Otherwise,NULL is returned.
+
+**/
+IHANDLE *
+CoreGetNextLocateByProtocol (
+ IN OUT LOCATE_POSITION *Position,
+ OUT VOID **Interface
+ );
+
+/**
+ Internal function for locating the requested handle(s) and returns them in Buffer.
+ The caller should already have acquired the ProtocolLock.
+
+ @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
+InternalCoreLocateHandle (
+ 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 = CoreGetNextLocateAllHandles;
+ break;
+
+ case ByRegisterNotify:
+ //
+ // Must have SearchKey for locate ByRegisterNotify
+ //
+ if (SearchKey == NULL) {
+ Status = EFI_INVALID_PARAMETER;
+ break;
+ }
+
+ GetNext = CoreGetNextLocateByRegisterNotify;
+ break;
+
+ case ByProtocol:
+ GetNext = CoreGetNextLocateByProtocol;
+ if (Protocol == NULL) {
+ Status = EFI_INVALID_PARAMETER;
+ break;
+ }
+
+ //
+ // Look up the protocol entry and set the head pointer
+ //
+ Position.ProtEntry = CoreFindProtocolEntry (Protocol, FALSE);
+ if (Position.ProtEntry == NULL) {
+ Status = EFI_NOT_FOUND;
+ break;
+ }
+
+ Position.Position = &Position.ProtEntry->Protocols;
+ break;
+
+ default:
+ Status = EFI_INVALID_PARAMETER;
+ break;
+ }
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ ASSERT (GetNext != NULL);
+ //
+ // Enumerate out the matching handles
+ //
+ mEfiLocateHandleRequest += 1;
+ for ( ; ;) {
+ //
+ // Get the next handle. If no more handles, stop
+ //
+ Handle = GetNext (&Position, &Interface);
+ if (NULL == Handle) {
+ break;
+ }
+
+ //
+ // Increase the resulting buffer size, and if this handle
+ // fits return it
+ //
+ ResultSize += sizeof (Handle);
+ if (ResultSize <= *BufferSize) {
+ *ResultBuffer = Handle;
+ ResultBuffer += 1;
+ }
+ }
+
+ //
+ // If the result is a zero length buffer, then there were no
+ // matching handles
+ //
+ if (ResultSize == 0) {
+ Status = EFI_NOT_FOUND;
+ } else {
+ //
+ // Return the resulting buffer size. If it's larger than what
+ // was passed, then set the error code
+ //
+ if (ResultSize > *BufferSize) {
+ Status = EFI_BUFFER_TOO_SMALL;
+ }
+
+ *BufferSize = ResultSize;
+
+ if ((SearchType == ByRegisterNotify) && !EFI_ERROR (Status)) {
+ //
+ // If this is a search by register notify and a handle was
+ // returned, update the register notification position
+ //
+ ASSERT (SearchKey != NULL);
+ ProtNotify = SearchKey;
+ ProtNotify->Position = ProtNotify->Position->ForwardLink;
+ }
+ }
+
+ 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
+CoreLocateHandle (
+ IN EFI_LOCATE_SEARCH_TYPE SearchType,
+ IN EFI_GUID *Protocol OPTIONAL,
+ IN VOID *SearchKey OPTIONAL,
+ IN OUT UINTN *BufferSize,
+ OUT EFI_HANDLE *Buffer
+ )
+{
+ EFI_STATUS Status;
+
+ //
+ // Lock the protocol database
+ //
+ CoreAcquireProtocolLock ();
+ Status = InternalCoreLocateHandle (SearchType, Protocol, SearchKey, BufferSize, Buffer);
+ CoreReleaseProtocolLock ();
+ return Status;
+}
+
+/**
+ Routine to get the next Handle, when you are searching for all handles.
+
+ @param Position Information about which Handle to seach for.
+ @param Interface Return the interface structure for the matching
+ protocol.
+
+ @return An pointer to IHANDLE if the next Position is not the end of the list.
+ Otherwise,NULL is returned.
+
+**/
+IHANDLE *
+CoreGetNextLocateAllHandles (
+ IN OUT LOCATE_POSITION *Position,
+ OUT VOID **Interface
+ )
+{
+ IHANDLE *Handle;
+
+ //
+ // Next handle
+ //
+ Position->Position = Position->Position->ForwardLink;
+
+ //
+ // If not at the end of the list, get the handle
+ //
+ Handle = NULL;
+ *Interface = NULL;
+ if (Position->Position != &gHandleList) {
+ Handle = CR (Position->Position, IHANDLE, AllHandles, EFI_HANDLE_SIGNATURE);
+ }
+
+ return Handle;
+}
+
+/**
+ Routine to get the next Handle, when you are searching for register protocol
+ notifies.
+
+ @param Position Information about which Handle to seach for.
+ @param Interface Return the interface structure for the matching
+ protocol.
+
+ @return An pointer to IHANDLE if the next Position is not the end of the list.
+ Otherwise,NULL is returned.
+
+**/
+IHANDLE *
+CoreGetNextLocateByRegisterNotify (
+ IN OUT LOCATE_POSITION *Position,
+ OUT VOID **Interface
+ )
+{
+ IHANDLE *Handle;
+ PROTOCOL_NOTIFY *ProtNotify;
+ PROTOCOL_INTERFACE *Prot;
+ LIST_ENTRY *Link;
+
+ Handle = NULL;
+ *Interface = NULL;
+ ProtNotify = Position->SearchKey;
+
+ //
+ // If this is the first request, get the next handle
+ //
+ if (ProtNotify != NULL) {
+ ASSERT (ProtNotify->Signature == PROTOCOL_NOTIFY_SIGNATURE);
+ Position->SearchKey = NULL;
+
+ //
+ // If not at the end of the list, get the next handle
+ //
+ Link = ProtNotify->Position->ForwardLink;
+ if (Link != &ProtNotify->Protocol->Protocols) {
+ Prot = CR (Link, PROTOCOL_INTERFACE, ByProtocol, PROTOCOL_INTERFACE_SIGNATURE);
+ Handle = Prot->Handle;
+ *Interface = Prot->Interface;
+ }
+ }
+
+ return Handle;
+}
+
+/**
+ Routine to get the next Handle, when you are searching for a given protocol.
+
+ @param Position Information about which Handle to seach for.
+ @param Interface Return the interface structure for the matching
+ protocol.
+
+ @return An pointer to IHANDLE if the next Position is not the end of the list.
+ Otherwise,NULL is returned.
+
+**/
+IHANDLE *
+CoreGetNextLocateByProtocol (
+ IN OUT LOCATE_POSITION *Position,
+ OUT VOID **Interface
+ )
+{
+ IHANDLE *Handle;
+ LIST_ENTRY *Link;
+ PROTOCOL_INTERFACE *Prot;
+
+ Handle = NULL;
+ *Interface = NULL;
+ for ( ; ;) {
+ //
+ // Next entry
+ //
+ Link = Position->Position->ForwardLink;
+ Position->Position = Link;
+
+ //
+ // If not at the end, return the handle
+ //
+ if (Link == &Position->ProtEntry->Protocols) {
+ Handle = NULL;
+ break;
+ }
+
+ //
+ // Get the handle
+ //
+ Prot = CR (Link, PROTOCOL_INTERFACE, ByProtocol, PROTOCOL_INTERFACE_SIGNATURE);
+ Handle = Prot->Handle;
+ *Interface = Prot->Interface;
+
+ //
+ // If this handle has not been returned this request, then
+ // return it now
+ //
+ if (Handle->LocateRequest != mEfiLocateHandleRequest) {
+ Handle->LocateRequest = mEfiLocateHandleRequest;
+ break;
+ }
+ }
+
+ return Handle;
+}
+
+/**
+ Locates the handle to a device on the device path that supports the specified protocol.
+
+ @param Protocol Specifies the protocol to search for.
+ @param DevicePath On input, a pointer to a pointer to the device path. On output, the device
+ path pointer is modified to point to the remaining part of the device
+ path.
+ @param Device A pointer to the returned device handle.
+
+ @retval EFI_SUCCESS The resulting handle was returned.
+ @retval EFI_NOT_FOUND No handles match the search.
+ @retval EFI_INVALID_PARAMETER Protocol is NULL.
+ @retval EFI_INVALID_PARAMETER DevicePath is NULL.
+ @retval EFI_INVALID_PARAMETER A handle matched the search and Device is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+CoreLocateDevicePath (
+ IN EFI_GUID *Protocol,
+ IN OUT EFI_DEVICE_PATH_PROTOCOL **DevicePath,
+ OUT EFI_HANDLE *Device
+ )
+{
+ INTN SourceSize;
+ INTN Size;
+ INTN BestMatch;
+ UINTN HandleCount;
+ UINTN Index;
+ EFI_STATUS Status;
+ EFI_HANDLE *Handles;
+ EFI_HANDLE Handle;
+ EFI_HANDLE BestDevice;
+ EFI_DEVICE_PATH_PROTOCOL *SourcePath;
+ EFI_DEVICE_PATH_PROTOCOL *TmpDevicePath;
+
+ if (Protocol == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if ((DevicePath == NULL) || (*DevicePath == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Handles = NULL;
+ BestDevice = NULL;
+ SourcePath = *DevicePath;
+ TmpDevicePath = SourcePath;
+ while (!IsDevicePathEnd (TmpDevicePath)) {
+ if (IsDevicePathEndInstance (TmpDevicePath)) {
+ //
+ // If DevicePath is a multi-instance device path,
+ // the function will operate on the first instance
+ //
+ break;
+ }
+
+ TmpDevicePath = NextDevicePathNode (TmpDevicePath);
+ }
+
+ SourceSize = (UINTN)TmpDevicePath - (UINTN)SourcePath;
+
+ //
+ // Get a list of all handles that support the requested protocol
+ //
+ Status = CoreLocateHandleBuffer (ByProtocol, Protocol, NULL, &HandleCount, &Handles);
+ if (EFI_ERROR (Status) || (HandleCount == 0)) {
+ return EFI_NOT_FOUND;
+ }
+
+ BestMatch = -1;
+ for (Index = 0; Index < HandleCount; Index += 1) {
+ Handle = Handles[Index];
+ Status = CoreHandleProtocol (Handle, &gEfiDevicePathProtocolGuid, (VOID **)&TmpDevicePath);
+ if (EFI_ERROR (Status)) {
+ //
+ // If this handle doesn't support device path, then skip it
+ //
+ continue;
+ }
+
+ //
+ // Check if DevicePath is first part of SourcePath
+ //
+ Size = GetDevicePathSize (TmpDevicePath) - sizeof (EFI_DEVICE_PATH_PROTOCOL);
+ ASSERT (Size >= 0);
+ if ((Size <= SourceSize) && (CompareMem (SourcePath, TmpDevicePath, (UINTN)Size) == 0)) {
+ //
+ // If the size is equal to the best match, then we
+ // have a duplicate device path for 2 different device
+ // handles
+ //
+ ASSERT (Size != BestMatch);
+
+ //
+ // We've got a match, see if it's the best match so far
+ //
+ if (Size > BestMatch) {
+ BestMatch = Size;
+ BestDevice = Handle;
+ }
+ }
+ }
+
+ CoreFreePool (Handles);
+
+ //
+ // If there wasn't any match, then no parts of the device path was found.
+ // Which is strange since there is likely a "root level" device path in the system.
+ //
+ if (BestMatch == -1) {
+ return EFI_NOT_FOUND;
+ }
+
+ if (Device == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ *Device = BestDevice;
+
+ //
+ // Return the remaining part of the device path
+ //
+ *DevicePath = (EFI_DEVICE_PATH_PROTOCOL *)(((UINT8 *)SourcePath) + BestMatch);
+ return EFI_SUCCESS;
+}
+
+/**
+ Return the first Protocol Interface that matches the Protocol GUID. If
+ Registration is passed in, return a Protocol Instance that was just add
+ to the system. If Registration is NULL return the first Protocol Interface
+ you find.
+
+ @param Protocol The protocol to search for
+ @param Registration Optional Registration Key returned from
+ RegisterProtocolNotify()
+ @param Interface Return the Protocol interface (instance).
+
+ @retval EFI_SUCCESS If a valid Interface is returned
+ @retval EFI_INVALID_PARAMETER Invalid parameter
+ @retval EFI_NOT_FOUND Protocol interface not found
+
+**/
+EFI_STATUS
+EFIAPI
+CoreLocateProtocol (
+ IN EFI_GUID *Protocol,
+ IN VOID *Registration OPTIONAL,
+ OUT VOID **Interface
+ )
+{
+ EFI_STATUS Status;
+ LOCATE_POSITION Position;
+ PROTOCOL_NOTIFY *ProtNotify;
+ IHANDLE *Handle;
+
+ if ((Interface == NULL) || (Protocol == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ *Interface = NULL;
+ Status = EFI_SUCCESS;
+
+ //
+ // Set initial position
+ //
+ Position.Protocol = Protocol;
+ Position.SearchKey = Registration;
+ Position.Position = &gHandleList;
+
+ //
+ // Lock the protocol database
+ //
+ Status = CoreAcquireLockOrFail (&gProtocolDatabaseLock);
+ if (EFI_ERROR (Status)) {
+ return EFI_NOT_FOUND;
+ }
+
+ mEfiLocateHandleRequest += 1;
+
+ if (Registration == NULL) {
+ //
+ // Look up the protocol entry and set the head pointer
+ //
+ Position.ProtEntry = CoreFindProtocolEntry (Protocol, FALSE);
+ if (Position.ProtEntry == NULL) {
+ Status = EFI_NOT_FOUND;
+ goto Done;
+ }
+
+ Position.Position = &Position.ProtEntry->Protocols;
+
+ Handle = CoreGetNextLocateByProtocol (&Position, Interface);
+ } else {
+ Handle = CoreGetNextLocateByRegisterNotify (&Position, Interface);
+ }
+
+ if (Handle == NULL) {
+ Status = EFI_NOT_FOUND;
+ } else if (Registration != NULL) {
+ //
+ // If this is a search by register notify and a handle was
+ // returned, update the register notification position
+ //
+ ProtNotify = Registration;
+ ProtNotify->Position = ProtNotify->Position->ForwardLink;
+ }
+
+Done:
+ CoreReleaseProtocolLock ();
+ return Status;
+}
+
+/**
+ Function returns an array of handles that support the requested protocol
+ in a buffer allocated from pool. This is a version of CoreLocateHandle()
+ that allocates a buffer for the caller.
+
+ @param SearchType Specifies which handle(s) are to be returned.
+ @param Protocol Provides the protocol to search by. This
+ parameter is only valid for SearchType
+ ByProtocol.
+ @param SearchKey Supplies the search key depending on the
+ SearchType.
+ @param NumberHandles The number of handles returned in Buffer.
+ @param Buffer A pointer to the buffer to return the requested
+ array of handles that support Protocol.
+
+ @retval EFI_SUCCESS The result array of handles was returned.
+ @retval EFI_NOT_FOUND No handles match the search.
+ @retval EFI_OUT_OF_RESOURCES There is not enough pool memory to store the
+ matching results.
+ @retval EFI_INVALID_PARAMETER One or more parameters are not valid.
+
+**/
+EFI_STATUS
+EFIAPI
+CoreLocateHandleBuffer (
+ IN EFI_LOCATE_SEARCH_TYPE SearchType,
+ IN EFI_GUID *Protocol OPTIONAL,
+ IN VOID *SearchKey OPTIONAL,
+ IN OUT UINTN *NumberHandles,
+ OUT EFI_HANDLE **Buffer
+ )
+{
+ EFI_STATUS Status;
+ UINTN BufferSize;
+
+ if (NumberHandles == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (Buffer == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ BufferSize = 0;
+ *NumberHandles = 0;
+ *Buffer = NULL;
+
+ //
+ // Lock the protocol database
+ //
+ CoreAcquireProtocolLock ();
+ Status = InternalCoreLocateHandle (
+ SearchType,
+ Protocol,
+ SearchKey,
+ &BufferSize,
+ *Buffer
+ );
+ //
+ // LocateHandleBuffer() returns incorrect status code if SearchType is
+ // invalid.
+ //
+ // Add code to correctly handle expected errors from CoreLocateHandle().
+ //
+ if (EFI_ERROR (Status) && (Status != EFI_BUFFER_TOO_SMALL)) {
+ if (Status != EFI_INVALID_PARAMETER) {
+ Status = EFI_NOT_FOUND;
+ }
+
+ CoreReleaseProtocolLock ();
+ return Status;
+ }
+
+ *Buffer = AllocatePool (BufferSize);
+ if (*Buffer == NULL) {
+ CoreReleaseProtocolLock ();
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ Status = InternalCoreLocateHandle (
+ SearchType,
+ Protocol,
+ SearchKey,
+ &BufferSize,
+ *Buffer
+ );
+
+ *NumberHandles = BufferSize / sizeof (EFI_HANDLE);
+ if (EFI_ERROR (Status)) {
+ *NumberHandles = 0;
+ if (*Buffer != NULL) {
+ CoreFreePool (*Buffer);
+ *Buffer = NULL;
+ }
+ }
+
+ CoreReleaseProtocolLock ();
+ return Status;
+}
diff --git a/MdeModulePkg/Core/Dxe/Hand/Notify.c b/MdeModulePkg/Core/Dxe/Hand/Notify.c
index a6e20cad23..8d65a72457 100644
--- a/MdeModulePkg/Core/Dxe/Hand/Notify.c
+++ b/MdeModulePkg/Core/Dxe/Hand/Notify.c
@@ -1,278 +1,278 @@
-/** @file
- Support functions for UEFI protocol notification infrastructure.
-
-Copyright (c) 2006 - 2008, Intel Corporation. All rights reserved.<BR>
-(C) Copyright 2015 Hewlett Packard Enterprise Development LP<BR>
-SPDX-License-Identifier: BSD-2-Clause-Patent
-
-**/
-
-#include "DxeMain.h"
-#include "Handle.h"
-#include "Event.h"
-
-/**
- Signal event for every protocol in protocol entry.
-
- @param ProtEntry Protocol entry
-
-**/
-VOID
-CoreNotifyProtocolEntry (
- IN PROTOCOL_ENTRY *ProtEntry
- )
-{
- PROTOCOL_NOTIFY *ProtNotify;
- LIST_ENTRY *Link;
-
- ASSERT_LOCKED (&gProtocolDatabaseLock);
-
- for (Link = ProtEntry->Notify.ForwardLink; Link != &ProtEntry->Notify; Link = Link->ForwardLink) {
- ProtNotify = CR (Link, PROTOCOL_NOTIFY, Link, PROTOCOL_NOTIFY_SIGNATURE);
- CoreSignalEvent (ProtNotify->Event);
- }
-}
-
-/**
- Removes Protocol from the protocol list (but not the handle list).
-
- @param Handle The handle to remove protocol on.
- @param Protocol GUID of the protocol to be moved
- @param Interface The interface of the protocol
-
- @return Protocol Entry
-
-**/
-PROTOCOL_INTERFACE *
-CoreRemoveInterfaceFromProtocol (
- IN IHANDLE *Handle,
- IN EFI_GUID *Protocol,
- IN VOID *Interface
- )
-{
- PROTOCOL_INTERFACE *Prot;
- PROTOCOL_NOTIFY *ProtNotify;
- PROTOCOL_ENTRY *ProtEntry;
- LIST_ENTRY *Link;
-
- ASSERT_LOCKED (&gProtocolDatabaseLock);
-
- Prot = CoreFindProtocolInterface (Handle, Protocol, Interface);
- if (Prot != NULL) {
- ProtEntry = Prot->Protocol;
-
- //
- // If there's a protocol notify location pointing to this entry, back it up one
- //
- for (Link = ProtEntry->Notify.ForwardLink; Link != &ProtEntry->Notify; Link = Link->ForwardLink) {
- ProtNotify = CR (Link, PROTOCOL_NOTIFY, Link, PROTOCOL_NOTIFY_SIGNATURE);
-
- if (ProtNotify->Position == &Prot->ByProtocol) {
- ProtNotify->Position = Prot->ByProtocol.BackLink;
- }
- }
-
- //
- // Remove the protocol interface entry
- //
- RemoveEntryList (&Prot->ByProtocol);
- }
-
- return Prot;
-}
-
-/**
- Add a new protocol notification record for the request protocol.
-
- @param Protocol The requested protocol to add the notify
- registration
- @param Event The event to signal
- @param Registration Returns the registration record
-
- @retval EFI_INVALID_PARAMETER Invalid parameter
- @retval EFI_SUCCESS Successfully returned the registration record
- that has been added
-
-**/
-EFI_STATUS
-EFIAPI
-CoreRegisterProtocolNotify (
- IN EFI_GUID *Protocol,
- IN EFI_EVENT Event,
- OUT VOID **Registration
- )
-{
- PROTOCOL_ENTRY *ProtEntry;
- PROTOCOL_NOTIFY *ProtNotify;
- EFI_STATUS Status;
-
- if ((Protocol == NULL) || (Event == NULL) || (Registration == NULL)) {
- return EFI_INVALID_PARAMETER;
- }
-
- CoreAcquireProtocolLock ();
-
- ProtNotify = NULL;
-
- //
- // Get the protocol entry to add the notification too
- //
-
- ProtEntry = CoreFindProtocolEntry (Protocol, TRUE);
- if (ProtEntry != NULL) {
- //
- // Allocate a new notification record
- //
- ProtNotify = AllocatePool (sizeof (PROTOCOL_NOTIFY));
- if (ProtNotify != NULL) {
- ((IEVENT *)Event)->ExFlag |= EVT_EXFLAG_EVENT_PROTOCOL_NOTIFICATION;
- ProtNotify->Signature = PROTOCOL_NOTIFY_SIGNATURE;
- ProtNotify->Protocol = ProtEntry;
- ProtNotify->Event = Event;
- //
- // start at the begining
- //
- ProtNotify->Position = &ProtEntry->Protocols;
-
- InsertTailList (&ProtEntry->Notify, &ProtNotify->Link);
- }
- }
-
- CoreReleaseProtocolLock ();
-
- //
- // Done. If we have a protocol notify entry, then return it.
- // Otherwise, we must have run out of resources trying to add one
- //
-
- Status = EFI_OUT_OF_RESOURCES;
- if (ProtNotify != NULL) {
- *Registration = ProtNotify;
- Status = EFI_SUCCESS;
- }
-
- return Status;
-}
-
-/**
- Reinstall a protocol interface on a device handle. The OldInterface for Protocol is replaced by the NewInterface.
-
- @param UserHandle Handle on which the interface is to be
- reinstalled
- @param Protocol The numeric ID of the interface
- @param OldInterface A pointer to the old interface
- @param NewInterface A pointer to the new interface
-
- @retval EFI_SUCCESS The protocol interface was installed
- @retval EFI_NOT_FOUND The OldInterface on the handle was not found
- @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value
-
-**/
-EFI_STATUS
-EFIAPI
-CoreReinstallProtocolInterface (
- IN EFI_HANDLE UserHandle,
- IN EFI_GUID *Protocol,
- IN VOID *OldInterface,
- IN VOID *NewInterface
- )
-{
- EFI_STATUS Status;
- IHANDLE *Handle;
- PROTOCOL_INTERFACE *Prot;
- PROTOCOL_ENTRY *ProtEntry;
-
- if (Protocol == NULL) {
- return EFI_INVALID_PARAMETER;
- }
-
- //
- // Lock the protocol database
- //
- CoreAcquireProtocolLock ();
-
- Status = CoreValidateHandle (UserHandle);
- if (EFI_ERROR (Status)) {
- goto Done;
- }
-
- Handle = (IHANDLE *)UserHandle;
- //
- // Check that Protocol exists on UserHandle, and Interface matches the interface in the database
- //
- Prot = CoreFindProtocolInterface (UserHandle, Protocol, OldInterface);
- if (Prot == NULL) {
- Status = EFI_NOT_FOUND;
- goto Done;
- }
-
- //
- // Attempt to disconnect all drivers that are using the protocol interface that is about to be reinstalled
- //
- Status = CoreDisconnectControllersUsingProtocolInterface (
- UserHandle,
- Prot
- );
- if (EFI_ERROR (Status)) {
- //
- // One or more drivers refused to release, so return the error
- //
- goto Done;
- }
-
- //
- // Remove the protocol interface from the protocol
- //
- Prot = CoreRemoveInterfaceFromProtocol (Handle, Protocol, OldInterface);
-
- if (Prot == NULL) {
- Status = EFI_NOT_FOUND;
- goto Done;
- }
-
- ProtEntry = Prot->Protocol;
-
- //
- // Update the interface on the protocol
- //
- Prot->Interface = NewInterface;
-
- //
- // Add this protocol interface to the tail of the
- // protocol entry
- //
- InsertTailList (&ProtEntry->Protocols, &Prot->ByProtocol);
-
- //
- // Update the Key to show that the handle has been created/modified
- //
- gHandleDatabaseKey++;
- Handle->Key = gHandleDatabaseKey;
-
- //
- // Release the lock and connect all drivers to UserHandle
- //
- CoreReleaseProtocolLock ();
- //
- // Return code is ignored on purpose.
- //
- CoreConnectController (
- UserHandle,
- NULL,
- NULL,
- TRUE
- );
- CoreAcquireProtocolLock ();
-
- //
- // Notify the notification list for this protocol
- //
- CoreNotifyProtocolEntry (ProtEntry);
-
- Status = EFI_SUCCESS;
-
-Done:
- CoreReleaseProtocolLock ();
-
- return Status;
-}
+/** @file
+ Support functions for UEFI protocol notification infrastructure.
+
+Copyright (c) 2006 - 2008, Intel Corporation. All rights reserved.<BR>
+(C) Copyright 2015 Hewlett Packard Enterprise Development LP<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "DxeMain.h"
+#include "Handle.h"
+#include "Event.h"
+
+/**
+ Signal event for every protocol in protocol entry.
+
+ @param ProtEntry Protocol entry
+
+**/
+VOID
+CoreNotifyProtocolEntry (
+ IN PROTOCOL_ENTRY *ProtEntry
+ )
+{
+ PROTOCOL_NOTIFY *ProtNotify;
+ LIST_ENTRY *Link;
+
+ ASSERT_LOCKED (&gProtocolDatabaseLock);
+
+ for (Link = ProtEntry->Notify.ForwardLink; Link != &ProtEntry->Notify; Link = Link->ForwardLink) {
+ ProtNotify = CR (Link, PROTOCOL_NOTIFY, Link, PROTOCOL_NOTIFY_SIGNATURE);
+ CoreSignalEvent (ProtNotify->Event);
+ }
+}
+
+/**
+ Removes Protocol from the protocol list (but not the handle list).
+
+ @param Handle The handle to remove protocol on.
+ @param Protocol GUID of the protocol to be moved
+ @param Interface The interface of the protocol
+
+ @return Protocol Entry
+
+**/
+PROTOCOL_INTERFACE *
+CoreRemoveInterfaceFromProtocol (
+ IN IHANDLE *Handle,
+ IN EFI_GUID *Protocol,
+ IN VOID *Interface
+ )
+{
+ PROTOCOL_INTERFACE *Prot;
+ PROTOCOL_NOTIFY *ProtNotify;
+ PROTOCOL_ENTRY *ProtEntry;
+ LIST_ENTRY *Link;
+
+ ASSERT_LOCKED (&gProtocolDatabaseLock);
+
+ Prot = CoreFindProtocolInterface (Handle, Protocol, Interface);
+ if (Prot != NULL) {
+ ProtEntry = Prot->Protocol;
+
+ //
+ // If there's a protocol notify location pointing to this entry, back it up one
+ //
+ for (Link = ProtEntry->Notify.ForwardLink; Link != &ProtEntry->Notify; Link = Link->ForwardLink) {
+ ProtNotify = CR (Link, PROTOCOL_NOTIFY, Link, PROTOCOL_NOTIFY_SIGNATURE);
+
+ if (ProtNotify->Position == &Prot->ByProtocol) {
+ ProtNotify->Position = Prot->ByProtocol.BackLink;
+ }
+ }
+
+ //
+ // Remove the protocol interface entry
+ //
+ RemoveEntryList (&Prot->ByProtocol);
+ }
+
+ return Prot;
+}
+
+/**
+ Add a new protocol notification record for the request protocol.
+
+ @param Protocol The requested protocol to add the notify
+ registration
+ @param Event The event to signal
+ @param Registration Returns the registration record
+
+ @retval EFI_INVALID_PARAMETER Invalid parameter
+ @retval EFI_SUCCESS Successfully returned the registration record
+ that has been added
+
+**/
+EFI_STATUS
+EFIAPI
+CoreRegisterProtocolNotify (
+ IN EFI_GUID *Protocol,
+ IN EFI_EVENT Event,
+ OUT VOID **Registration
+ )
+{
+ PROTOCOL_ENTRY *ProtEntry;
+ PROTOCOL_NOTIFY *ProtNotify;
+ EFI_STATUS Status;
+
+ if ((Protocol == NULL) || (Event == NULL) || (Registration == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ CoreAcquireProtocolLock ();
+
+ ProtNotify = NULL;
+
+ //
+ // Get the protocol entry to add the notification too
+ //
+
+ ProtEntry = CoreFindProtocolEntry (Protocol, TRUE);
+ if (ProtEntry != NULL) {
+ //
+ // Allocate a new notification record
+ //
+ ProtNotify = AllocatePool (sizeof (PROTOCOL_NOTIFY));
+ if (ProtNotify != NULL) {
+ ((IEVENT *)Event)->ExFlag |= EVT_EXFLAG_EVENT_PROTOCOL_NOTIFICATION;
+ ProtNotify->Signature = PROTOCOL_NOTIFY_SIGNATURE;
+ ProtNotify->Protocol = ProtEntry;
+ ProtNotify->Event = Event;
+ //
+ // start at the begining
+ //
+ ProtNotify->Position = &ProtEntry->Protocols;
+
+ InsertTailList (&ProtEntry->Notify, &ProtNotify->Link);
+ }
+ }
+
+ CoreReleaseProtocolLock ();
+
+ //
+ // Done. If we have a protocol notify entry, then return it.
+ // Otherwise, we must have run out of resources trying to add one
+ //
+
+ Status = EFI_OUT_OF_RESOURCES;
+ if (ProtNotify != NULL) {
+ *Registration = ProtNotify;
+ Status = EFI_SUCCESS;
+ }
+
+ return Status;
+}
+
+/**
+ Reinstall a protocol interface on a device handle. The OldInterface for Protocol is replaced by the NewInterface.
+
+ @param UserHandle Handle on which the interface is to be
+ reinstalled
+ @param Protocol The numeric ID of the interface
+ @param OldInterface A pointer to the old interface
+ @param NewInterface A pointer to the new interface
+
+ @retval EFI_SUCCESS The protocol interface was installed
+ @retval EFI_NOT_FOUND The OldInterface on the handle was not found
+ @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value
+
+**/
+EFI_STATUS
+EFIAPI
+CoreReinstallProtocolInterface (
+ IN EFI_HANDLE UserHandle,
+ IN EFI_GUID *Protocol,
+ IN VOID *OldInterface,
+ IN VOID *NewInterface
+ )
+{
+ EFI_STATUS Status;
+ IHANDLE *Handle;
+ PROTOCOL_INTERFACE *Prot;
+ PROTOCOL_ENTRY *ProtEntry;
+
+ if (Protocol == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Lock the protocol database
+ //
+ CoreAcquireProtocolLock ();
+
+ Status = CoreValidateHandle (UserHandle);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ Handle = (IHANDLE *)UserHandle;
+ //
+ // Check that Protocol exists on UserHandle, and Interface matches the interface in the database
+ //
+ Prot = CoreFindProtocolInterface (UserHandle, Protocol, OldInterface);
+ if (Prot == NULL) {
+ Status = EFI_NOT_FOUND;
+ goto Done;
+ }
+
+ //
+ // Attempt to disconnect all drivers that are using the protocol interface that is about to be reinstalled
+ //
+ Status = CoreDisconnectControllersUsingProtocolInterface (
+ UserHandle,
+ Prot
+ );
+ if (EFI_ERROR (Status)) {
+ //
+ // One or more drivers refused to release, so return the error
+ //
+ goto Done;
+ }
+
+ //
+ // Remove the protocol interface from the protocol
+ //
+ Prot = CoreRemoveInterfaceFromProtocol (Handle, Protocol, OldInterface);
+
+ if (Prot == NULL) {
+ Status = EFI_NOT_FOUND;
+ goto Done;
+ }
+
+ ProtEntry = Prot->Protocol;
+
+ //
+ // Update the interface on the protocol
+ //
+ Prot->Interface = NewInterface;
+
+ //
+ // Add this protocol interface to the tail of the
+ // protocol entry
+ //
+ InsertTailList (&ProtEntry->Protocols, &Prot->ByProtocol);
+
+ //
+ // Update the Key to show that the handle has been created/modified
+ //
+ gHandleDatabaseKey++;
+ Handle->Key = gHandleDatabaseKey;
+
+ //
+ // Release the lock and connect all drivers to UserHandle
+ //
+ CoreReleaseProtocolLock ();
+ //
+ // Return code is ignored on purpose.
+ //
+ CoreConnectController (
+ UserHandle,
+ NULL,
+ NULL,
+ TRUE
+ );
+ CoreAcquireProtocolLock ();
+
+ //
+ // Notify the notification list for this protocol
+ //
+ CoreNotifyProtocolEntry (ProtEntry);
+
+ Status = EFI_SUCCESS;
+
+Done:
+ CoreReleaseProtocolLock ();
+
+ return Status;
+}
diff --git a/MdeModulePkg/Core/Dxe/Image/Image.c b/MdeModulePkg/Core/Dxe/Image/Image.c
index 37fc74d5d1..ad18fe8c21 100644
--- a/MdeModulePkg/Core/Dxe/Image/Image.c
+++ b/MdeModulePkg/Core/Dxe/Image/Image.c
@@ -1,1957 +1,1957 @@
-/** @file
- Core image handling services to load and unload PeImage.
-
-Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR>
-SPDX-License-Identifier: BSD-2-Clause-Patent
-
-**/
-
-#include "DxeMain.h"
-#include "Image.h"
-
-//
-// Module Globals
-//
-LOADED_IMAGE_PRIVATE_DATA *mCurrentImage = NULL;
-
-typedef struct {
- LIST_ENTRY Link;
- EDKII_PECOFF_IMAGE_EMULATOR_PROTOCOL *Emulator;
- UINT16 MachineType;
-} EMULATOR_ENTRY;
-
-STATIC LIST_ENTRY mAvailableEmulators;
-STATIC EFI_EVENT mPeCoffEmuProtocolRegistrationEvent;
-STATIC VOID *mPeCoffEmuProtocolNotifyRegistration;
-
-//
-// This code is needed to build the Image handle for the DXE Core
-//
-LOADED_IMAGE_PRIVATE_DATA mCorePrivateImage = {
- LOADED_IMAGE_PRIVATE_DATA_SIGNATURE, // Signature
- NULL, // Image handle
- EFI_IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER, // Image type
- TRUE, // If entrypoint has been called
- NULL, // EntryPoint
- {
- EFI_LOADED_IMAGE_INFORMATION_REVISION, // Revision
- NULL, // Parent handle
- NULL, // System handle
-
- NULL, // Device handle
- NULL, // File path
- NULL, // Reserved
-
- 0, // LoadOptionsSize
- NULL, // LoadOptions
-
- NULL, // ImageBase
- 0, // ImageSize
- EfiBootServicesCode, // ImageCodeType
- EfiBootServicesData // ImageDataType
- },
- (EFI_PHYSICAL_ADDRESS)0, // ImageBasePage
- 0, // NumberOfPages
- NULL, // FixupData
- 0, // Tpl
- EFI_SUCCESS, // Status
- 0, // ExitDataSize
- NULL, // ExitData
- NULL, // JumpBuffer
- NULL, // JumpContext
- 0, // Machine
- NULL, // PeCoffEmu
- NULL, // RuntimeData
- NULL // LoadedImageDevicePath
-};
-//
-// The field is define for Loading modules at fixed address feature to tracker the PEI code
-// memory range usage. It is a bit mapped array in which every bit indicates the correspoding memory page
-// available or not.
-//
-GLOBAL_REMOVE_IF_UNREFERENCED UINT64 *mDxeCodeMemoryRangeUsageBitMap = NULL;
-
-typedef struct {
- UINT16 MachineType;
- CHAR16 *MachineTypeName;
-} MACHINE_TYPE_INFO;
-
-GLOBAL_REMOVE_IF_UNREFERENCED MACHINE_TYPE_INFO mMachineTypeInfo[] = {
- { EFI_IMAGE_MACHINE_IA32, L"IA32" },
- { EFI_IMAGE_MACHINE_IA64, L"IA64" },
- { EFI_IMAGE_MACHINE_X64, L"X64" },
- { EFI_IMAGE_MACHINE_ARMTHUMB_MIXED, L"ARM" },
- { EFI_IMAGE_MACHINE_AARCH64, L"AARCH64" },
- { EFI_IMAGE_MACHINE_RISCV64, L"RISCV64" },
- { EFI_IMAGE_MACHINE_LOONGARCH64, L"LOONGARCH64" },
-};
-
-UINT16 mDxeCoreImageMachineType = 0;
-
-/**
- Return machine type name.
-
- @param MachineType The machine type
-
- @return machine type name
-**/
-CHAR16 *
-GetMachineTypeName (
- UINT16 MachineType
- )
-{
- UINTN Index;
-
- for (Index = 0; Index < sizeof (mMachineTypeInfo)/sizeof (mMachineTypeInfo[0]); Index++) {
- if (mMachineTypeInfo[Index].MachineType == MachineType) {
- return mMachineTypeInfo[Index].MachineTypeName;
- }
- }
-
- return L"<Unknown>";
-}
-
-/**
- Notification event handler registered by CoreInitializeImageServices () to
- keep track of which PE/COFF image emulators are available.
-
- @param Event The Event that is being processed, not used.
- @param Context Event Context, not used.
-
-**/
-STATIC
-VOID
-EFIAPI
-PeCoffEmuProtocolNotify (
- IN EFI_EVENT Event,
- IN VOID *Context
- )
-{
- EFI_STATUS Status;
- UINTN BufferSize;
- EFI_HANDLE EmuHandle;
- EDKII_PECOFF_IMAGE_EMULATOR_PROTOCOL *Emulator;
- EMULATOR_ENTRY *Entry;
-
- EmuHandle = NULL;
- Emulator = NULL;
-
- while (TRUE) {
- BufferSize = sizeof (EmuHandle);
- Status = CoreLocateHandle (
- ByRegisterNotify,
- NULL,
- mPeCoffEmuProtocolNotifyRegistration,
- &BufferSize,
- &EmuHandle
- );
- if (EFI_ERROR (Status)) {
- //
- // If no more notification events exit
- //
- return;
- }
-
- Status = CoreHandleProtocol (
- EmuHandle,
- &gEdkiiPeCoffImageEmulatorProtocolGuid,
- (VOID **)&Emulator
- );
- if (EFI_ERROR (Status) || (Emulator == NULL)) {
- continue;
- }
-
- Entry = AllocateZeroPool (sizeof (*Entry));
- ASSERT (Entry != NULL);
-
- Entry->Emulator = Emulator;
- Entry->MachineType = Entry->Emulator->MachineType;
-
- InsertTailList (&mAvailableEmulators, &Entry->Link);
- }
-}
-
-/**
- Add the Image Services to EFI Boot Services Table and install the protocol
- interfaces for this image.
-
- @param HobStart The HOB to initialize
-
- @return Status code.
-
-**/
-EFI_STATUS
-CoreInitializeImageServices (
- IN VOID *HobStart
- )
-{
- EFI_STATUS Status;
- LOADED_IMAGE_PRIVATE_DATA *Image;
- EFI_PHYSICAL_ADDRESS DxeCoreImageBaseAddress;
- UINT64 DxeCoreImageLength;
- VOID *DxeCoreEntryPoint;
- EFI_PEI_HOB_POINTERS DxeCoreHob;
-
- //
- // Searching for image hob
- //
- DxeCoreHob.Raw = HobStart;
- while ((DxeCoreHob.Raw = GetNextHob (EFI_HOB_TYPE_MEMORY_ALLOCATION, DxeCoreHob.Raw)) != NULL) {
- if (CompareGuid (&DxeCoreHob.MemoryAllocationModule->MemoryAllocationHeader.Name, &gEfiHobMemoryAllocModuleGuid)) {
- //
- // Find Dxe Core HOB
- //
- break;
- }
-
- DxeCoreHob.Raw = GET_NEXT_HOB (DxeCoreHob);
- }
-
- ASSERT (DxeCoreHob.Raw != NULL);
-
- DxeCoreImageBaseAddress = DxeCoreHob.MemoryAllocationModule->MemoryAllocationHeader.MemoryBaseAddress;
- DxeCoreImageLength = DxeCoreHob.MemoryAllocationModule->MemoryAllocationHeader.MemoryLength;
- DxeCoreEntryPoint = (VOID *)(UINTN)DxeCoreHob.MemoryAllocationModule->EntryPoint;
- gDxeCoreFileName = &DxeCoreHob.MemoryAllocationModule->ModuleName;
-
- //
- // Initialize the fields for an internal driver
- //
- Image = &mCorePrivateImage;
-
- Image->EntryPoint = (EFI_IMAGE_ENTRY_POINT)(UINTN)DxeCoreEntryPoint;
- Image->ImageBasePage = DxeCoreImageBaseAddress;
- Image->NumberOfPages = (UINTN)(EFI_SIZE_TO_PAGES ((UINTN)(DxeCoreImageLength)));
- Image->Tpl = gEfiCurrentTpl;
- Image->Info.ImageBase = (VOID *)(UINTN)DxeCoreImageBaseAddress;
- Image->Info.ImageSize = DxeCoreImageLength;
-
- //
- // Install the protocol interfaces for this image
- //
- Status = CoreInstallProtocolInterface (
- &Image->Handle,
- &gEfiLoadedImageProtocolGuid,
- EFI_NATIVE_INTERFACE,
- &Image->Info
- );
- ASSERT_EFI_ERROR (Status);
-
- mCurrentImage = Image;
-
- //
- // Fill in DXE globals
- //
- mDxeCoreImageMachineType = PeCoffLoaderGetMachineType (Image->Info.ImageBase);
- gDxeCoreImageHandle = Image->Handle;
- gDxeCoreLoadedImage = &Image->Info;
-
- //
- // Create the PE/COFF emulator protocol registration event
- //
- Status = CoreCreateEvent (
- EVT_NOTIFY_SIGNAL,
- TPL_CALLBACK,
- PeCoffEmuProtocolNotify,
- NULL,
- &mPeCoffEmuProtocolRegistrationEvent
- );
- ASSERT_EFI_ERROR (Status);
-
- //
- // Register for protocol notifications on this event
- //
- Status = CoreRegisterProtocolNotify (
- &gEdkiiPeCoffImageEmulatorProtocolGuid,
- mPeCoffEmuProtocolRegistrationEvent,
- &mPeCoffEmuProtocolNotifyRegistration
- );
- ASSERT_EFI_ERROR (Status);
-
- InitializeListHead (&mAvailableEmulators);
-
- ProtectUefiImage (&Image->Info, Image->LoadedImageDevicePath);
-
- return Status;
-}
-
-/**
- Read image file (specified by UserHandle) into user specified buffer with specified offset
- and length.
-
- @param UserHandle Image file handle
- @param Offset Offset to the source file
- @param ReadSize For input, pointer of size to read; For output,
- pointer of size actually read.
- @param Buffer Buffer to write into
-
- @retval EFI_SUCCESS Successfully read the specified part of file
- into buffer.
-
-**/
-EFI_STATUS
-EFIAPI
-CoreReadImageFile (
- IN VOID *UserHandle,
- IN UINTN Offset,
- IN OUT UINTN *ReadSize,
- OUT VOID *Buffer
- )
-{
- UINTN EndPosition;
- IMAGE_FILE_HANDLE *FHand;
-
- if ((UserHandle == NULL) || (ReadSize == NULL) || (Buffer == NULL)) {
- return EFI_INVALID_PARAMETER;
- }
-
- if (MAX_ADDRESS - Offset < *ReadSize) {
- return EFI_INVALID_PARAMETER;
- }
-
- FHand = (IMAGE_FILE_HANDLE *)UserHandle;
- ASSERT (FHand->Signature == IMAGE_FILE_HANDLE_SIGNATURE);
-
- //
- // Move data from our local copy of the file
- //
- EndPosition = Offset + *ReadSize;
- if (EndPosition > FHand->SourceSize) {
- *ReadSize = (UINT32)(FHand->SourceSize - Offset);
- }
-
- if (Offset >= FHand->SourceSize) {
- *ReadSize = 0;
- }
-
- CopyMem (Buffer, (CHAR8 *)FHand->Source + Offset, *ReadSize);
- return EFI_SUCCESS;
-}
-
-/**
- To check memory usage bit map array to figure out if the memory range the image will be loaded in is available or not. If
- memory range is available, the function will mark the corresponding bits to 1 which indicates the memory range is used.
- The function is only invoked when load modules at fixed address feature is enabled.
-
- @param ImageBase The base address the image will be loaded at.
- @param ImageSize The size of the image
-
- @retval EFI_SUCCESS The memory range the image will be loaded in is available
- @retval EFI_NOT_FOUND The memory range the image will be loaded in is not available
-**/
-EFI_STATUS
-CheckAndMarkFixLoadingMemoryUsageBitMap (
- IN EFI_PHYSICAL_ADDRESS ImageBase,
- IN UINTN ImageSize
- )
-{
- UINT32 DxeCodePageNumber;
- UINT64 DxeCodeSize;
- EFI_PHYSICAL_ADDRESS DxeCodeBase;
- UINTN BaseOffsetPageNumber;
- UINTN TopOffsetPageNumber;
- UINTN Index;
-
- //
- // The DXE code range includes RuntimeCodePage range and Boot time code range.
- //
- DxeCodePageNumber = PcdGet32 (PcdLoadFixAddressRuntimeCodePageNumber);
- DxeCodePageNumber += PcdGet32 (PcdLoadFixAddressBootTimeCodePageNumber);
- DxeCodeSize = EFI_PAGES_TO_SIZE (DxeCodePageNumber);
- DxeCodeBase = gLoadModuleAtFixAddressConfigurationTable.DxeCodeTopAddress - DxeCodeSize;
-
- //
- // If the memory usage bit map is not initialized, do it. Every bit in the array
- // indicate the status of the corresponding memory page, available or not
- //
- if (mDxeCodeMemoryRangeUsageBitMap == NULL) {
- mDxeCodeMemoryRangeUsageBitMap = AllocateZeroPool (((DxeCodePageNumber/64) + 1)*sizeof (UINT64));
- }
-
- //
- // If the Dxe code memory range is not allocated or the bit map array allocation failed, return EFI_NOT_FOUND
- //
- if (!gLoadFixedAddressCodeMemoryReady || (mDxeCodeMemoryRangeUsageBitMap == NULL)) {
- return EFI_NOT_FOUND;
- }
-
- //
- // Test the memory range for loading the image in the DXE code range.
- //
- if ((gLoadModuleAtFixAddressConfigurationTable.DxeCodeTopAddress < ImageBase + ImageSize) ||
- (DxeCodeBase > ImageBase))
- {
- return EFI_NOT_FOUND;
- }
-
- //
- // Test if the memory is avalaible or not.
- //
- BaseOffsetPageNumber = EFI_SIZE_TO_PAGES ((UINT32)(ImageBase - DxeCodeBase));
- TopOffsetPageNumber = EFI_SIZE_TO_PAGES ((UINT32)(ImageBase + ImageSize - DxeCodeBase));
- for (Index = BaseOffsetPageNumber; Index < TopOffsetPageNumber; Index++) {
- if ((mDxeCodeMemoryRangeUsageBitMap[Index / 64] & LShiftU64 (1, (Index % 64))) != 0) {
- //
- // This page is already used.
- //
- return EFI_NOT_FOUND;
- }
- }
-
- //
- // Being here means the memory range is available. So mark the bits for the memory range
- //
- for (Index = BaseOffsetPageNumber; Index < TopOffsetPageNumber; Index++) {
- mDxeCodeMemoryRangeUsageBitMap[Index / 64] |= LShiftU64 (1, (Index % 64));
- }
-
- return EFI_SUCCESS;
-}
-
-/**
-
- Get the fixed loading address from image header assigned by build tool. This function only be called
- when Loading module at Fixed address feature enabled.
-
- @param ImageContext Pointer to the image context structure that describes the PE/COFF
- image that needs to be examined by this function.
- @retval EFI_SUCCESS An fixed loading address is assigned to this image by build tools .
- @retval EFI_NOT_FOUND The image has no assigned fixed loading address.
-
-**/
-EFI_STATUS
-GetPeCoffImageFixLoadingAssignedAddress (
- IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext
- )
-{
- UINTN SectionHeaderOffset;
- EFI_STATUS Status;
- EFI_IMAGE_SECTION_HEADER SectionHeader;
- EFI_IMAGE_OPTIONAL_HEADER_UNION *ImgHdr;
- UINT16 Index;
- UINTN Size;
- UINT16 NumberOfSections;
- IMAGE_FILE_HANDLE *Handle;
- UINT64 ValueInSectionHeader;
-
- Status = EFI_NOT_FOUND;
-
- //
- // Get PeHeader pointer
- //
- Handle = (IMAGE_FILE_HANDLE *)ImageContext->Handle;
- ImgHdr = (EFI_IMAGE_OPTIONAL_HEADER_UNION *)((CHAR8 *)Handle->Source + ImageContext->PeCoffHeaderOffset);
- SectionHeaderOffset = ImageContext->PeCoffHeaderOffset +
- sizeof (UINT32) +
- sizeof (EFI_IMAGE_FILE_HEADER) +
- ImgHdr->Pe32.FileHeader.SizeOfOptionalHeader;
- NumberOfSections = ImgHdr->Pe32.FileHeader.NumberOfSections;
-
- //
- // Get base address from the first section header that doesn't point to code section.
- //
- for (Index = 0; Index < NumberOfSections; Index++) {
- //
- // Read section header from file
- //
- Size = sizeof (EFI_IMAGE_SECTION_HEADER);
- Status = ImageContext->ImageRead (
- ImageContext->Handle,
- SectionHeaderOffset,
- &Size,
- &SectionHeader
- );
- if (EFI_ERROR (Status)) {
- return Status;
- }
-
- if (Size != sizeof (EFI_IMAGE_SECTION_HEADER)) {
- return EFI_NOT_FOUND;
- }
-
- Status = EFI_NOT_FOUND;
-
- if ((SectionHeader.Characteristics & EFI_IMAGE_SCN_CNT_CODE) == 0) {
- //
- // Build tool will save the address in PointerToRelocations & PointerToLineNumbers fields in the first section header
- // that doesn't point to code section in image header, as well as ImageBase field of image header. And there is an
- // assumption that when the feature is enabled, if a module is assigned a loading address by tools, PointerToRelocations
- // & PointerToLineNumbers fields should NOT be Zero, or else, these 2 fields should be set to Zero
- //
- ValueInSectionHeader = ReadUnaligned64 ((UINT64 *)&SectionHeader.PointerToRelocations);
- if (ValueInSectionHeader != 0) {
- //
- // When the feature is configured as load module at fixed absolute address, the ImageAddress field of ImageContext
- // hold the specified address. If the feature is configured as load module at fixed offset, ImageAddress hold an offset
- // relative to top address
- //
- if ((INT64)PcdGet64 (PcdLoadModuleAtFixAddressEnable) < 0) {
- ImageContext->ImageAddress = gLoadModuleAtFixAddressConfigurationTable.DxeCodeTopAddress + (INT64)(INTN)ImageContext->ImageAddress;
- }
-
- //
- // Check if the memory range is available.
- //
- Status = CheckAndMarkFixLoadingMemoryUsageBitMap (ImageContext->ImageAddress, (UINTN)(ImageContext->ImageSize + ImageContext->SectionAlignment));
- }
-
- break;
- }
-
- SectionHeaderOffset += sizeof (EFI_IMAGE_SECTION_HEADER);
- }
-
- DEBUG ((DEBUG_INFO|DEBUG_LOAD, "LOADING MODULE FIXED INFO: Loading module at fixed address 0x%11p. Status = %r \n", (VOID *)(UINTN)(ImageContext->ImageAddress), Status));
- return Status;
-}
-
-/**
- Decides whether a PE/COFF image can execute on this system, either natively
- or via emulation/interpretation. In the latter case, the PeCoffEmu member
- of the LOADED_IMAGE_PRIVATE_DATA struct pointer is populated with a pointer
- to the emulator protocol that supports this image.
-
- @param[in, out] Image LOADED_IMAGE_PRIVATE_DATA struct pointer
-
- @retval TRUE The image is supported
- @retval FALSE The image is not supported
-
-**/
-STATIC
-BOOLEAN
-CoreIsImageTypeSupported (
- IN OUT LOADED_IMAGE_PRIVATE_DATA *Image
- )
-{
- LIST_ENTRY *Link;
- EMULATOR_ENTRY *Entry;
-
- for (Link = GetFirstNode (&mAvailableEmulators);
- !IsNull (&mAvailableEmulators, Link);
- Link = GetNextNode (&mAvailableEmulators, Link))
- {
- Entry = BASE_CR (Link, EMULATOR_ENTRY, Link);
- if (Entry->MachineType != Image->ImageContext.Machine) {
- continue;
- }
-
- if (Entry->Emulator->IsImageSupported (
- Entry->Emulator,
- Image->ImageContext.ImageType,
- Image->Info.FilePath
- ))
- {
- Image->PeCoffEmu = Entry->Emulator;
- return TRUE;
- }
- }
-
- return EFI_IMAGE_MACHINE_TYPE_SUPPORTED (Image->ImageContext.Machine) ||
- EFI_IMAGE_MACHINE_CROSS_TYPE_SUPPORTED (Image->ImageContext.Machine);
-}
-
-/**
- Loads, relocates, and invokes a PE/COFF image
-
- @param BootPolicy If TRUE, indicates that the request originates
- from the boot manager, and that the boot
- manager is attempting to load FilePath as a
- boot selection.
- @param Pe32Handle The handle of PE32 image
- @param Image PE image to be loaded
- @param DstBuffer The buffer to store the image
- @param EntryPoint A pointer to the entry point
- @param Attribute The bit mask of attributes to set for the load
- PE image
-
- @retval EFI_SUCCESS The file was loaded, relocated, and invoked
- @retval EFI_OUT_OF_RESOURCES There was not enough memory to load and
- relocate the PE/COFF file
- @retval EFI_INVALID_PARAMETER Invalid parameter
- @retval EFI_BUFFER_TOO_SMALL Buffer for image is too small
-
-**/
-EFI_STATUS
-CoreLoadPeImage (
- IN BOOLEAN BootPolicy,
- IN VOID *Pe32Handle,
- IN LOADED_IMAGE_PRIVATE_DATA *Image,
- IN EFI_PHYSICAL_ADDRESS DstBuffer OPTIONAL,
- OUT EFI_PHYSICAL_ADDRESS *EntryPoint OPTIONAL,
- IN UINT32 Attribute
- )
-{
- EFI_STATUS Status;
- BOOLEAN DstBufAlocated;
- UINTN Size;
-
- ZeroMem (&Image->ImageContext, sizeof (Image->ImageContext));
-
- Image->ImageContext.Handle = Pe32Handle;
- Image->ImageContext.ImageRead = (PE_COFF_LOADER_READ_FILE)CoreReadImageFile;
-
- //
- // Get information about the image being loaded
- //
- Status = PeCoffLoaderGetImageInfo (&Image->ImageContext);
- if (EFI_ERROR (Status)) {
- return Status;
- }
-
- if (!CoreIsImageTypeSupported (Image)) {
- //
- // The PE/COFF loader can support loading image types that can be executed.
- // If we loaded an image type that we can not execute return EFI_UNSUPPORTED.
- //
- DEBUG ((
- DEBUG_ERROR,
- "Image type %s can't be loaded on %s UEFI system.\n",
- GetMachineTypeName (Image->ImageContext.Machine),
- GetMachineTypeName (mDxeCoreImageMachineType)
- ));
- return EFI_UNSUPPORTED;
- }
-
- //
- // Set EFI memory type based on ImageType
- //
- switch (Image->ImageContext.ImageType) {
- case EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION:
- Image->ImageContext.ImageCodeMemoryType = EfiLoaderCode;
- Image->ImageContext.ImageDataMemoryType = EfiLoaderData;
- break;
- case EFI_IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER:
- Image->ImageContext.ImageCodeMemoryType = EfiBootServicesCode;
- Image->ImageContext.ImageDataMemoryType = EfiBootServicesData;
- break;
- case EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER:
- case EFI_IMAGE_SUBSYSTEM_SAL_RUNTIME_DRIVER:
- Image->ImageContext.ImageCodeMemoryType = EfiRuntimeServicesCode;
- Image->ImageContext.ImageDataMemoryType = EfiRuntimeServicesData;
- break;
- default:
- Image->ImageContext.ImageError = IMAGE_ERROR_INVALID_SUBSYSTEM;
- return EFI_UNSUPPORTED;
- }
-
- //
- // Allocate memory of the correct memory type aligned on the required image boundary
- //
- DstBufAlocated = FALSE;
- if (DstBuffer == 0) {
- //
- // Allocate Destination Buffer as caller did not pass it in
- //
-
- if (Image->ImageContext.SectionAlignment > EFI_PAGE_SIZE) {
- Size = (UINTN)Image->ImageContext.ImageSize + Image->ImageContext.SectionAlignment;
- } else {
- Size = (UINTN)Image->ImageContext.ImageSize;
- }
-
- Image->NumberOfPages = EFI_SIZE_TO_PAGES (Size);
-
- //
- // If the image relocations have not been stripped, then load at any address.
- // Otherwise load at the address at which it was linked.
- //
- // Memory below 1MB should be treated reserved for CSM and there should be
- // no modules whose preferred load addresses are below 1MB.
- //
- Status = EFI_OUT_OF_RESOURCES;
- //
- // If Loading Module At Fixed Address feature is enabled, the module should be loaded to
- // a specified address.
- //
- if (PcdGet64 (PcdLoadModuleAtFixAddressEnable) != 0 ) {
- Status = GetPeCoffImageFixLoadingAssignedAddress (&(Image->ImageContext));
-
- if (EFI_ERROR (Status)) {
- //
- // If the code memory is not ready, invoke CoreAllocatePage with AllocateAnyPages to load the driver.
- //
- DEBUG ((DEBUG_INFO|DEBUG_LOAD, "LOADING MODULE FIXED ERROR: Loading module at fixed address failed since specified memory is not available.\n"));
-
- Status = CoreAllocatePages (
- AllocateAnyPages,
- (EFI_MEMORY_TYPE)(Image->ImageContext.ImageCodeMemoryType),
- Image->NumberOfPages,
- &Image->ImageContext.ImageAddress
- );
- }
- } else {
- if ((PcdGetBool (PcdImageLargeAddressLoad) && ((Image->ImageContext.ImageAddress) >= 0x100000)) ||
- Image->ImageContext.RelocationsStripped)
- {
- Status = CoreAllocatePages (
- AllocateAddress,
- (EFI_MEMORY_TYPE)(Image->ImageContext.ImageCodeMemoryType),
- Image->NumberOfPages,
- &Image->ImageContext.ImageAddress
- );
- }
-
- if (EFI_ERROR (Status) && !Image->ImageContext.RelocationsStripped) {
- Status = CoreAllocatePages (
- AllocateAnyPages,
- (EFI_MEMORY_TYPE)(Image->ImageContext.ImageCodeMemoryType),
- Image->NumberOfPages,
- &Image->ImageContext.ImageAddress
- );
- }
- }
-
- if (EFI_ERROR (Status)) {
- return Status;
- }
-
- DstBufAlocated = TRUE;
- } else {
- //
- // Caller provided the destination buffer
- //
-
- if (Image->ImageContext.RelocationsStripped && (Image->ImageContext.ImageAddress != DstBuffer)) {
- //
- // If the image relocations were stripped, and the caller provided a
- // destination buffer address that does not match the address that the
- // image is linked at, then the image cannot be loaded.
- //
- return EFI_INVALID_PARAMETER;
- }
-
- if ((Image->NumberOfPages != 0) &&
- (Image->NumberOfPages <
- (EFI_SIZE_TO_PAGES ((UINTN)Image->ImageContext.ImageSize + Image->ImageContext.SectionAlignment))))
- {
- Image->NumberOfPages = EFI_SIZE_TO_PAGES ((UINTN)Image->ImageContext.ImageSize + Image->ImageContext.SectionAlignment);
- return EFI_BUFFER_TOO_SMALL;
- }
-
- Image->NumberOfPages = EFI_SIZE_TO_PAGES ((UINTN)Image->ImageContext.ImageSize + Image->ImageContext.SectionAlignment);
- Image->ImageContext.ImageAddress = DstBuffer;
- }
-
- Image->ImageBasePage = Image->ImageContext.ImageAddress;
- if (!Image->ImageContext.IsTeImage) {
- Image->ImageContext.ImageAddress =
- (Image->ImageContext.ImageAddress + Image->ImageContext.SectionAlignment - 1) &
- ~((UINTN)Image->ImageContext.SectionAlignment - 1);
- }
-
- //
- // Load the image from the file into the allocated memory
- //
- Status = PeCoffLoaderLoadImage (&Image->ImageContext);
- if (EFI_ERROR (Status)) {
- goto Done;
- }
-
- //
- // If this is a Runtime Driver, then allocate memory for the FixupData that
- // is used to relocate the image when SetVirtualAddressMap() is called. The
- // relocation is done by the Runtime AP.
- //
- if ((Attribute & EFI_LOAD_PE_IMAGE_ATTRIBUTE_RUNTIME_REGISTRATION) != 0) {
- if (Image->ImageContext.ImageType == EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER) {
- Image->ImageContext.FixupData = AllocateRuntimePool ((UINTN)(Image->ImageContext.FixupDataSize));
- if (Image->ImageContext.FixupData == NULL) {
- Status = EFI_OUT_OF_RESOURCES;
- goto Done;
- }
- }
- }
-
- //
- // Relocate the image in memory
- //
- Status = PeCoffLoaderRelocateImage (&Image->ImageContext);
- if (EFI_ERROR (Status)) {
- goto Done;
- }
-
- //
- // Flush the Instruction Cache
- //
- InvalidateInstructionCacheRange ((VOID *)(UINTN)Image->ImageContext.ImageAddress, (UINTN)Image->ImageContext.ImageSize);
-
- //
- // Copy the machine type from the context to the image private data.
- //
- Image->Machine = Image->ImageContext.Machine;
-
- //
- // Get the image entry point.
- //
- Image->EntryPoint = (EFI_IMAGE_ENTRY_POINT)(UINTN)Image->ImageContext.EntryPoint;
-
- //
- // Fill in the image information for the Loaded Image Protocol
- //
- Image->Type = Image->ImageContext.ImageType;
- Image->Info.ImageBase = (VOID *)(UINTN)Image->ImageContext.ImageAddress;
- Image->Info.ImageSize = Image->ImageContext.ImageSize;
- Image->Info.ImageCodeType = (EFI_MEMORY_TYPE)(Image->ImageContext.ImageCodeMemoryType);
- Image->Info.ImageDataType = (EFI_MEMORY_TYPE)(Image->ImageContext.ImageDataMemoryType);
- if ((Attribute & EFI_LOAD_PE_IMAGE_ATTRIBUTE_RUNTIME_REGISTRATION) != 0) {
- if (Image->ImageContext.ImageType == EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER) {
- //
- // Make a list off all the RT images so we can let the RT AP know about them.
- //
- Image->RuntimeData = AllocateRuntimePool (sizeof (EFI_RUNTIME_IMAGE_ENTRY));
- if (Image->RuntimeData == NULL) {
- goto Done;
- }
-
- Image->RuntimeData->ImageBase = Image->Info.ImageBase;
- Image->RuntimeData->ImageSize = (UINT64)(Image->Info.ImageSize);
- Image->RuntimeData->RelocationData = Image->ImageContext.FixupData;
- Image->RuntimeData->Handle = Image->Handle;
- InsertTailList (&gRuntime->ImageHead, &Image->RuntimeData->Link);
- InsertImageRecord (Image->RuntimeData);
- }
- }
-
- //
- // Fill in the entry point of the image if it is available
- //
- if (EntryPoint != NULL) {
- *EntryPoint = Image->ImageContext.EntryPoint;
- }
-
- //
- // Print the load address and the PDB file name if it is available
- //
-
- DEBUG_CODE_BEGIN ();
-
- UINTN Index;
- UINTN StartIndex;
- CHAR8 EfiFileName[256];
-
- DEBUG ((
- DEBUG_INFO | DEBUG_LOAD,
- "Loading driver at 0x%11p EntryPoint=0x%11p ",
- (VOID *)(UINTN)Image->ImageContext.ImageAddress,
- FUNCTION_ENTRY_POINT (Image->ImageContext.EntryPoint)
- ));
-
- //
- // Print Module Name by Pdb file path.
- // Windows and Unix style file path are all trimmed correctly.
- //
- if (Image->ImageContext.PdbPointer != NULL) {
- StartIndex = 0;
- for (Index = 0; Image->ImageContext.PdbPointer[Index] != 0; Index++) {
- if ((Image->ImageContext.PdbPointer[Index] == '\\') || (Image->ImageContext.PdbPointer[Index] == '/')) {
- StartIndex = Index + 1;
- }
- }
-
- //
- // Copy the PDB file name to our temporary string, and replace .pdb with .efi
- // The PDB file name is limited in the range of 0~255.
- // If the length is bigger than 255, trim the redudant characters to avoid overflow in array boundary.
- //
- for (Index = 0; Index < sizeof (EfiFileName) - 4; Index++) {
- EfiFileName[Index] = Image->ImageContext.PdbPointer[Index + StartIndex];
- if (EfiFileName[Index] == 0) {
- EfiFileName[Index] = '.';
- }
-
- if (EfiFileName[Index] == '.') {
- EfiFileName[Index + 1] = 'e';
- EfiFileName[Index + 2] = 'f';
- EfiFileName[Index + 3] = 'i';
- EfiFileName[Index + 4] = 0;
- break;
- }
- }
-
- if (Index == sizeof (EfiFileName) - 4) {
- EfiFileName[Index] = 0;
- }
-
- DEBUG ((DEBUG_INFO | DEBUG_LOAD, "%a", EfiFileName)); // &Image->ImageContext.PdbPointer[StartIndex]));
- }
-
- DEBUG ((DEBUG_INFO | DEBUG_LOAD, "\n"));
-
- DEBUG_CODE_END ();
-
- return EFI_SUCCESS;
-
-Done:
-
- //
- // Free memory.
- //
-
- if (DstBufAlocated) {
- CoreFreePages (Image->ImageContext.ImageAddress, Image->NumberOfPages);
- Image->ImageContext.ImageAddress = 0;
- Image->ImageBasePage = 0;
- }
-
- if (Image->ImageContext.FixupData != NULL) {
- CoreFreePool (Image->ImageContext.FixupData);
- }
-
- return Status;
-}
-
-/**
- Get the image's private data from its handle.
-
- @param ImageHandle The image handle
-
- @return Return the image private data associated with ImageHandle.
-
-**/
-LOADED_IMAGE_PRIVATE_DATA *
-CoreLoadedImageInfo (
- IN EFI_HANDLE ImageHandle
- )
-{
- EFI_STATUS Status;
- EFI_LOADED_IMAGE_PROTOCOL *LoadedImage;
- LOADED_IMAGE_PRIVATE_DATA *Image;
-
- Status = CoreHandleProtocol (
- ImageHandle,
- &gEfiLoadedImageProtocolGuid,
- (VOID **)&LoadedImage
- );
- if (!EFI_ERROR (Status)) {
- Image = LOADED_IMAGE_PRIVATE_DATA_FROM_THIS (LoadedImage);
- } else {
- DEBUG ((DEBUG_LOAD, "CoreLoadedImageInfo: Not an ImageHandle %p\n", ImageHandle));
- Image = NULL;
- }
-
- return Image;
-}
-
-/**
- Unloads EFI image from memory.
-
- @param Image EFI image
- @param FreePage Free allocated pages
-
-**/
-VOID
-CoreUnloadAndCloseImage (
- IN LOADED_IMAGE_PRIVATE_DATA *Image,
- IN BOOLEAN FreePage
- )
-{
- EFI_STATUS Status;
- UINTN HandleCount;
- EFI_HANDLE *HandleBuffer;
- UINTN HandleIndex;
- EFI_GUID **ProtocolGuidArray;
- UINTN ArrayCount;
- UINTN ProtocolIndex;
- EFI_OPEN_PROTOCOL_INFORMATION_ENTRY *OpenInfo;
- UINTN OpenInfoCount;
- UINTN OpenInfoIndex;
-
- HandleBuffer = NULL;
- ProtocolGuidArray = NULL;
-
- if (Image->Started) {
- UnregisterMemoryProfileImage (Image);
- }
-
- UnprotectUefiImage (&Image->Info, Image->LoadedImageDevicePath);
-
- if (Image->PeCoffEmu != NULL) {
- //
- // If the PE/COFF Emulator protocol exists we must unregister the image.
- //
- Image->PeCoffEmu->UnregisterImage (Image->PeCoffEmu, Image->ImageBasePage);
- }
-
- //
- // Unload image, free Image->ImageContext->ModHandle
- //
- PeCoffLoaderUnloadImage (&Image->ImageContext);
-
- //
- // Free our references to the image handle
- //
- if (Image->Handle != NULL) {
- Status = CoreLocateHandleBuffer (
- AllHandles,
- NULL,
- NULL,
- &HandleCount,
- &HandleBuffer
- );
- if (!EFI_ERROR (Status)) {
- for (HandleIndex = 0; HandleIndex < HandleCount; HandleIndex++) {
- Status = CoreProtocolsPerHandle (
- HandleBuffer[HandleIndex],
- &ProtocolGuidArray,
- &ArrayCount
- );
- if (!EFI_ERROR (Status)) {
- for (ProtocolIndex = 0; ProtocolIndex < ArrayCount; ProtocolIndex++) {
- Status = CoreOpenProtocolInformation (
- HandleBuffer[HandleIndex],
- ProtocolGuidArray[ProtocolIndex],
- &OpenInfo,
- &OpenInfoCount
- );
- if (!EFI_ERROR (Status)) {
- for (OpenInfoIndex = 0; OpenInfoIndex < OpenInfoCount; OpenInfoIndex++) {
- if (OpenInfo[OpenInfoIndex].AgentHandle == Image->Handle) {
- Status = CoreCloseProtocol (
- HandleBuffer[HandleIndex],
- ProtocolGuidArray[ProtocolIndex],
- Image->Handle,
- OpenInfo[OpenInfoIndex].ControllerHandle
- );
- }
- }
-
- if (OpenInfo != NULL) {
- CoreFreePool (OpenInfo);
- }
- }
- }
-
- if (ProtocolGuidArray != NULL) {
- CoreFreePool (ProtocolGuidArray);
- }
- }
- }
-
- if (HandleBuffer != NULL) {
- CoreFreePool (HandleBuffer);
- }
- }
-
- CoreRemoveDebugImageInfoEntry (Image->Handle);
-
- Status = CoreUninstallProtocolInterface (
- Image->Handle,
- &gEfiLoadedImageDevicePathProtocolGuid,
- Image->LoadedImageDevicePath
- );
-
- Status = CoreUninstallProtocolInterface (
- Image->Handle,
- &gEfiLoadedImageProtocolGuid,
- &Image->Info
- );
-
- if (Image->ImageContext.HiiResourceData != 0) {
- Status = CoreUninstallProtocolInterface (
- Image->Handle,
- &gEfiHiiPackageListProtocolGuid,
- (VOID *)(UINTN)Image->ImageContext.HiiResourceData
- );
- }
- }
-
- if (Image->RuntimeData != NULL) {
- if (Image->RuntimeData->Link.ForwardLink != NULL) {
- //
- // Remove the Image from the Runtime Image list as we are about to Free it!
- //
- RemoveEntryList (&Image->RuntimeData->Link);
- RemoveImageRecord (Image->RuntimeData);
- }
-
- CoreFreePool (Image->RuntimeData);
- }
-
- //
- // Free the Image from memory
- //
- if ((Image->ImageBasePage != 0) && FreePage) {
- CoreFreePages (Image->ImageBasePage, Image->NumberOfPages);
- }
-
- //
- // Done with the Image structure
- //
- if (Image->Info.FilePath != NULL) {
- CoreFreePool (Image->Info.FilePath);
- }
-
- if (Image->LoadedImageDevicePath != NULL) {
- CoreFreePool (Image->LoadedImageDevicePath);
- }
-
- if (Image->FixupData != NULL) {
- CoreFreePool (Image->FixupData);
- }
-
- CoreFreePool (Image);
-}
-
-/**
- Loads an EFI image into memory and returns a handle to the image.
-
- @param BootPolicy If TRUE, indicates that the request originates
- from the boot manager, and that the boot
- manager is attempting to load FilePath as a
- boot selection.
- @param ParentImageHandle The caller's image handle.
- @param FilePath The specific file path from which the image is
- loaded.
- @param SourceBuffer If not NULL, a pointer to the memory location
- containing a copy of the image to be loaded.
- @param SourceSize The size in bytes of SourceBuffer.
- @param DstBuffer The buffer to store the image
- @param NumberOfPages If not NULL, it inputs a pointer to the page
- number of DstBuffer and outputs a pointer to
- the page number of the image. If this number is
- not enough, return EFI_BUFFER_TOO_SMALL and
- this parameter contains the required number.
- @param ImageHandle Pointer to the returned image handle that is
- created when the image is successfully loaded.
- @param EntryPoint A pointer to the entry point
- @param Attribute The bit mask of attributes to set for the load
- PE image
-
- @retval EFI_SUCCESS The image was loaded into memory.
- @retval EFI_NOT_FOUND The FilePath was not found.
- @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
- @retval EFI_BUFFER_TOO_SMALL The buffer is too small
- @retval EFI_UNSUPPORTED The image type is not supported, or the device
- path cannot be parsed to locate the proper
- protocol for loading the file.
- @retval EFI_OUT_OF_RESOURCES Image was not loaded due to insufficient
- resources.
- @retval EFI_LOAD_ERROR Image was not loaded because the image format was corrupt or not
- understood.
- @retval EFI_DEVICE_ERROR Image was not loaded because the device returned a read error.
- @retval EFI_ACCESS_DENIED Image was not loaded because the platform policy prohibits the
- image from being loaded. NULL is returned in *ImageHandle.
- @retval EFI_SECURITY_VIOLATION Image was loaded and an ImageHandle was created with a
- valid EFI_LOADED_IMAGE_PROTOCOL. However, the current
- platform policy specifies that the image should not be started.
-
-**/
-EFI_STATUS
-CoreLoadImageCommon (
- IN BOOLEAN BootPolicy,
- IN EFI_HANDLE ParentImageHandle,
- IN EFI_DEVICE_PATH_PROTOCOL *FilePath,
- IN VOID *SourceBuffer OPTIONAL,
- IN UINTN SourceSize,
- IN EFI_PHYSICAL_ADDRESS DstBuffer OPTIONAL,
- IN OUT UINTN *NumberOfPages OPTIONAL,
- OUT EFI_HANDLE *ImageHandle,
- OUT EFI_PHYSICAL_ADDRESS *EntryPoint OPTIONAL,
- IN UINT32 Attribute
- )
-{
- LOADED_IMAGE_PRIVATE_DATA *Image;
- LOADED_IMAGE_PRIVATE_DATA *ParentImage;
- IMAGE_FILE_HANDLE FHand;
- EFI_STATUS Status;
- EFI_STATUS SecurityStatus;
- EFI_HANDLE DeviceHandle;
- UINT32 AuthenticationStatus;
- EFI_DEVICE_PATH_PROTOCOL *OriginalFilePath;
- EFI_DEVICE_PATH_PROTOCOL *HandleFilePath;
- EFI_DEVICE_PATH_PROTOCOL *InputFilePath;
- EFI_DEVICE_PATH_PROTOCOL *Node;
- UINTN FilePathSize;
- BOOLEAN ImageIsFromFv;
- BOOLEAN ImageIsFromLoadFile;
-
- SecurityStatus = EFI_SUCCESS;
-
- ASSERT (gEfiCurrentTpl < TPL_NOTIFY);
- ParentImage = NULL;
-
- //
- // The caller must pass in a valid ParentImageHandle
- //
- if ((ImageHandle == NULL) || (ParentImageHandle == NULL)) {
- return EFI_INVALID_PARAMETER;
- }
-
- ParentImage = CoreLoadedImageInfo (ParentImageHandle);
- if (ParentImage == NULL) {
- DEBUG ((DEBUG_LOAD|DEBUG_ERROR, "LoadImageEx: Parent handle not an image handle\n"));
- return EFI_INVALID_PARAMETER;
- }
-
- ZeroMem (&FHand, sizeof (IMAGE_FILE_HANDLE));
- FHand.Signature = IMAGE_FILE_HANDLE_SIGNATURE;
- OriginalFilePath = FilePath;
- InputFilePath = FilePath;
- HandleFilePath = FilePath;
- DeviceHandle = NULL;
- Status = EFI_SUCCESS;
- AuthenticationStatus = 0;
- ImageIsFromFv = FALSE;
- ImageIsFromLoadFile = FALSE;
-
- //
- // If the caller passed a copy of the file, then just use it
- //
- if (SourceBuffer != NULL) {
- FHand.Source = SourceBuffer;
- FHand.SourceSize = SourceSize;
- Status = CoreLocateDevicePath (&gEfiDevicePathProtocolGuid, &HandleFilePath, &DeviceHandle);
- if (EFI_ERROR (Status)) {
- DeviceHandle = NULL;
- }
-
- if (SourceSize > 0) {
- Status = EFI_SUCCESS;
- } else {
- Status = EFI_LOAD_ERROR;
- }
- } else {
- if (FilePath == NULL) {
- return EFI_INVALID_PARAMETER;
- }
-
- //
- // Try to get the image device handle by checking the match protocol.
- //
- Node = NULL;
- Status = CoreLocateDevicePath (&gEfiFirmwareVolume2ProtocolGuid, &HandleFilePath, &DeviceHandle);
- if (!EFI_ERROR (Status)) {
- ImageIsFromFv = TRUE;
- } else {
- HandleFilePath = FilePath;
- Status = CoreLocateDevicePath (&gEfiSimpleFileSystemProtocolGuid, &HandleFilePath, &DeviceHandle);
- if (EFI_ERROR (Status)) {
- if (!BootPolicy) {
- HandleFilePath = FilePath;
- Status = CoreLocateDevicePath (&gEfiLoadFile2ProtocolGuid, &HandleFilePath, &DeviceHandle);
- }
-
- if (EFI_ERROR (Status)) {
- HandleFilePath = FilePath;
- Status = CoreLocateDevicePath (&gEfiLoadFileProtocolGuid, &HandleFilePath, &DeviceHandle);
- if (!EFI_ERROR (Status)) {
- ImageIsFromLoadFile = TRUE;
- Node = HandleFilePath;
- }
- }
- }
- }
-
- //
- // Get the source file buffer by its device path.
- //
- FHand.Source = GetFileBufferByFilePath (
- BootPolicy,
- FilePath,
- &FHand.SourceSize,
- &AuthenticationStatus
- );
- if (FHand.Source == NULL) {
- Status = EFI_NOT_FOUND;
- } else {
- FHand.FreeBuffer = TRUE;
- if (ImageIsFromLoadFile) {
- //
- // LoadFile () may cause the device path of the Handle be updated.
- //
- OriginalFilePath = AppendDevicePath (DevicePathFromHandle (DeviceHandle), Node);
- }
- }
- }
-
- if (EFI_ERROR (Status)) {
- Image = NULL;
- goto Done;
- }
-
- if (gSecurity2 != NULL) {
- //
- // Verify File Authentication through the Security2 Architectural Protocol
- //
- SecurityStatus = gSecurity2->FileAuthentication (
- gSecurity2,
- OriginalFilePath,
- FHand.Source,
- FHand.SourceSize,
- BootPolicy
- );
- if (!EFI_ERROR (SecurityStatus) && ImageIsFromFv) {
- //
- // When Security2 is installed, Security Architectural Protocol must be published.
- //
- ASSERT (gSecurity != NULL);
-
- //
- // Verify the Authentication Status through the Security Architectural Protocol
- // Only on images that have been read using Firmware Volume protocol.
- //
- SecurityStatus = gSecurity->FileAuthenticationState (
- gSecurity,
- AuthenticationStatus,
- OriginalFilePath
- );
- }
- } else if ((gSecurity != NULL) && (OriginalFilePath != NULL)) {
- //
- // Verify the Authentication Status through the Security Architectural Protocol
- //
- SecurityStatus = gSecurity->FileAuthenticationState (
- gSecurity,
- AuthenticationStatus,
- OriginalFilePath
- );
- }
-
- //
- // Check Security Status.
- //
- if (EFI_ERROR (SecurityStatus) && (SecurityStatus != EFI_SECURITY_VIOLATION)) {
- if (SecurityStatus == EFI_ACCESS_DENIED) {
- //
- // Image was not loaded because the platform policy prohibits the image from being loaded.
- // It's the only place we could meet EFI_ACCESS_DENIED.
- //
- *ImageHandle = NULL;
- }
-
- Status = SecurityStatus;
- Image = NULL;
- goto Done;
- }
-
- //
- // Allocate a new image structure
- //
- Image = AllocateZeroPool (sizeof (LOADED_IMAGE_PRIVATE_DATA));
- if (Image == NULL) {
- Status = EFI_OUT_OF_RESOURCES;
- goto Done;
- }
-
- //
- // Pull out just the file portion of the DevicePath for the LoadedImage FilePath
- //
- FilePath = OriginalFilePath;
- if (DeviceHandle != NULL) {
- Status = CoreHandleProtocol (DeviceHandle, &gEfiDevicePathProtocolGuid, (VOID **)&HandleFilePath);
- if (!EFI_ERROR (Status)) {
- FilePathSize = GetDevicePathSize (HandleFilePath) - sizeof (EFI_DEVICE_PATH_PROTOCOL);
- FilePath = (EFI_DEVICE_PATH_PROTOCOL *)(((UINT8 *)FilePath) + FilePathSize);
- }
- }
-
- //
- // Initialize the fields for an internal driver
- //
- Image->Signature = LOADED_IMAGE_PRIVATE_DATA_SIGNATURE;
- Image->Info.SystemTable = gDxeCoreST;
- Image->Info.DeviceHandle = DeviceHandle;
- Image->Info.Revision = EFI_LOADED_IMAGE_PROTOCOL_REVISION;
- Image->Info.FilePath = DuplicateDevicePath (FilePath);
- Image->Info.ParentHandle = ParentImageHandle;
-
- if (NumberOfPages != NULL) {
- Image->NumberOfPages = *NumberOfPages;
- } else {
- Image->NumberOfPages = 0;
- }
-
- //
- // Install the protocol interfaces for this image
- // don't fire notifications yet
- //
- Status = CoreInstallProtocolInterfaceNotify (
- &Image->Handle,
- &gEfiLoadedImageProtocolGuid,
- EFI_NATIVE_INTERFACE,
- &Image->Info,
- FALSE
- );
- if (EFI_ERROR (Status)) {
- goto Done;
- }
-
- //
- // Load the image. If EntryPoint is Null, it will not be set.
- //
- Status = CoreLoadPeImage (BootPolicy, &FHand, Image, DstBuffer, EntryPoint, Attribute);
- if (EFI_ERROR (Status)) {
- if ((Status == EFI_BUFFER_TOO_SMALL) || (Status == EFI_OUT_OF_RESOURCES)) {
- if (NumberOfPages != NULL) {
- *NumberOfPages = Image->NumberOfPages;
- }
- }
-
- goto Done;
- }
-
- if (NumberOfPages != NULL) {
- *NumberOfPages = Image->NumberOfPages;
- }
-
- //
- // Register the image in the Debug Image Info Table if the attribute is set
- //
- if ((Attribute & EFI_LOAD_PE_IMAGE_ATTRIBUTE_DEBUG_IMAGE_INFO_TABLE_REGISTRATION) != 0) {
- CoreNewDebugImageInfoEntry (EFI_DEBUG_IMAGE_INFO_TYPE_NORMAL, &Image->Info, Image->Handle);
- }
-
- //
- // Check whether we are loading a runtime image that lacks support for
- // IBT/BTI landing pads.
- //
- if ((Image->ImageContext.ImageCodeMemoryType == EfiRuntimeServicesCode) &&
- ((Image->ImageContext.DllCharacteristicsEx & EFI_IMAGE_DLLCHARACTERISTICS_EX_FORWARD_CFI_COMPAT) == 0))
- {
- gMemoryAttributesTableForwardCfi = FALSE;
- }
-
- //
- // Reinstall loaded image protocol to fire any notifications
- //
- Status = CoreReinstallProtocolInterface (
- Image->Handle,
- &gEfiLoadedImageProtocolGuid,
- &Image->Info,
- &Image->Info
- );
- if (EFI_ERROR (Status)) {
- goto Done;
- }
-
- //
- // If DevicePath parameter to the LoadImage() is not NULL, then make a copy of DevicePath,
- // otherwise Loaded Image Device Path Protocol is installed with a NULL interface pointer.
- //
- if (OriginalFilePath != NULL) {
- Image->LoadedImageDevicePath = DuplicateDevicePath (OriginalFilePath);
- }
-
- //
- // Install Loaded Image Device Path Protocol onto the image handle of a PE/COFE image
- //
- Status = CoreInstallProtocolInterface (
- &Image->Handle,
- &gEfiLoadedImageDevicePathProtocolGuid,
- EFI_NATIVE_INTERFACE,
- Image->LoadedImageDevicePath
- );
- if (EFI_ERROR (Status)) {
- goto Done;
- }
-
- //
- // Install HII Package List Protocol onto the image handle
- //
- if (Image->ImageContext.HiiResourceData != 0) {
- Status = CoreInstallProtocolInterface (
- &Image->Handle,
- &gEfiHiiPackageListProtocolGuid,
- EFI_NATIVE_INTERFACE,
- (VOID *)(UINTN)Image->ImageContext.HiiResourceData
- );
- if (EFI_ERROR (Status)) {
- goto Done;
- }
- }
-
- ProtectUefiImage (&Image->Info, Image->LoadedImageDevicePath);
-
- //
- // Success. Return the image handle
- //
- *ImageHandle = Image->Handle;
-
-Done:
- //
- // All done accessing the source file
- // If we allocated the Source buffer, free it
- //
- if (FHand.FreeBuffer) {
- CoreFreePool (FHand.Source);
- }
-
- if (OriginalFilePath != InputFilePath) {
- CoreFreePool (OriginalFilePath);
- }
-
- //
- // There was an error. If there's an Image structure, free it
- //
- if (EFI_ERROR (Status)) {
- if (Image != NULL) {
- CoreUnloadAndCloseImage (Image, (BOOLEAN)(DstBuffer == 0));
- Image = NULL;
- }
- } else if (EFI_ERROR (SecurityStatus)) {
- Status = SecurityStatus;
- }
-
- //
- // Track the return status from LoadImage.
- //
- if (Image != NULL) {
- Image->LoadImageStatus = Status;
- }
-
- return Status;
-}
-
-/**
- Loads an EFI image into memory and returns a handle to the image.
-
- @param BootPolicy If TRUE, indicates that the request originates
- from the boot manager, and that the boot
- manager is attempting to load FilePath as a
- boot selection.
- @param ParentImageHandle The caller's image handle.
- @param FilePath The specific file path from which the image is
- loaded.
- @param SourceBuffer If not NULL, a pointer to the memory location
- containing a copy of the image to be loaded.
- @param SourceSize The size in bytes of SourceBuffer.
- @param ImageHandle Pointer to the returned image handle that is
- created when the image is successfully loaded.
-
- @retval EFI_SUCCESS The image was loaded into memory.
- @retval EFI_NOT_FOUND The FilePath was not found.
- @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
- @retval EFI_UNSUPPORTED The image type is not supported, or the device
- path cannot be parsed to locate the proper
- protocol for loading the file.
- @retval EFI_OUT_OF_RESOURCES Image was not loaded due to insufficient
- resources.
- @retval EFI_LOAD_ERROR Image was not loaded because the image format was corrupt or not
- understood.
- @retval EFI_DEVICE_ERROR Image was not loaded because the device returned a read error.
- @retval EFI_ACCESS_DENIED Image was not loaded because the platform policy prohibits the
- image from being loaded. NULL is returned in *ImageHandle.
- @retval EFI_SECURITY_VIOLATION Image was loaded and an ImageHandle was created with a
- valid EFI_LOADED_IMAGE_PROTOCOL. However, the current
- platform policy specifies that the image should not be started.
-
-**/
-EFI_STATUS
-EFIAPI
-CoreLoadImage (
- IN BOOLEAN BootPolicy,
- IN EFI_HANDLE ParentImageHandle,
- IN EFI_DEVICE_PATH_PROTOCOL *FilePath,
- IN VOID *SourceBuffer OPTIONAL,
- IN UINTN SourceSize,
- OUT EFI_HANDLE *ImageHandle
- )
-{
- EFI_STATUS Status;
- EFI_HANDLE Handle;
-
- PERF_LOAD_IMAGE_BEGIN (NULL);
-
- Status = CoreLoadImageCommon (
- BootPolicy,
- ParentImageHandle,
- FilePath,
- SourceBuffer,
- SourceSize,
- (EFI_PHYSICAL_ADDRESS)(UINTN)NULL,
- NULL,
- ImageHandle,
- NULL,
- EFI_LOAD_PE_IMAGE_ATTRIBUTE_RUNTIME_REGISTRATION | EFI_LOAD_PE_IMAGE_ATTRIBUTE_DEBUG_IMAGE_INFO_TABLE_REGISTRATION
- );
-
- Handle = NULL;
- if (!EFI_ERROR (Status)) {
- //
- // ImageHandle will be valid only Status is success.
- //
- Handle = *ImageHandle;
- }
-
- PERF_LOAD_IMAGE_END (Handle);
-
- return Status;
-}
-
-/**
- Transfer control to a loaded image's entry point.
-
- @param ImageHandle Handle of image to be started.
- @param ExitDataSize Pointer of the size to ExitData
- @param ExitData Pointer to a pointer to a data buffer that
- includes a Null-terminated string,
- optionally followed by additional binary data.
- The string is a description that the caller may
- use to further indicate the reason for the
- image's exit.
-
- @retval EFI_INVALID_PARAMETER Invalid parameter
- @retval EFI_OUT_OF_RESOURCES No enough buffer to allocate
- @retval EFI_SECURITY_VIOLATION The current platform policy specifies that the image should not be started.
- @retval EFI_SUCCESS Successfully transfer control to the image's
- entry point.
-
-**/
-EFI_STATUS
-EFIAPI
-CoreStartImage (
- IN EFI_HANDLE ImageHandle,
- OUT UINTN *ExitDataSize,
- OUT CHAR16 **ExitData OPTIONAL
- )
-{
- EFI_STATUS Status;
- LOADED_IMAGE_PRIVATE_DATA *Image;
- LOADED_IMAGE_PRIVATE_DATA *LastImage;
- UINT64 HandleDatabaseKey;
- UINTN SetJumpFlag;
- EFI_HANDLE Handle;
-
- Handle = ImageHandle;
-
- Image = CoreLoadedImageInfo (ImageHandle);
- if ((Image == NULL) || Image->Started) {
- return EFI_INVALID_PARAMETER;
- }
-
- if (EFI_ERROR (Image->LoadImageStatus)) {
- return Image->LoadImageStatus;
- }
-
- //
- // The image to be started must have the machine type supported by DxeCore.
- //
- if (!EFI_IMAGE_MACHINE_TYPE_SUPPORTED (Image->Machine) &&
- (Image->PeCoffEmu == NULL))
- {
- //
- // Do not ASSERT here, because image might be loaded via EFI_IMAGE_MACHINE_CROSS_TYPE_SUPPORTED
- // But it can not be started.
- //
- DEBUG ((DEBUG_ERROR, "Image type %s can't be started ", GetMachineTypeName (Image->Machine)));
- DEBUG ((DEBUG_ERROR, "on %s UEFI system.\n", GetMachineTypeName (mDxeCoreImageMachineType)));
- return EFI_UNSUPPORTED;
- }
-
- if (Image->PeCoffEmu != NULL) {
- Status = Image->PeCoffEmu->RegisterImage (
- Image->PeCoffEmu,
- Image->ImageBasePage,
- EFI_PAGES_TO_SIZE (Image->NumberOfPages),
- &Image->EntryPoint
- );
- if (EFI_ERROR (Status)) {
- DEBUG ((
- DEBUG_LOAD | DEBUG_ERROR,
- "CoreLoadPeImage: Failed to register foreign image with emulator - %r\n",
- Status
- ));
- return Status;
- }
- }
-
- PERF_START_IMAGE_BEGIN (Handle);
-
- //
- // Push the current start image context, and
- // link the current image to the head. This is the
- // only image that can call Exit()
- //
- HandleDatabaseKey = CoreGetHandleDatabaseKey ();
- LastImage = mCurrentImage;
- mCurrentImage = Image;
- Image->Tpl = gEfiCurrentTpl;
-
- //
- // Set long jump for Exit() support
- // JumpContext must be aligned on a CPU specific boundary.
- // Overallocate the buffer and force the required alignment
- //
- Image->JumpBuffer = AllocatePool (sizeof (BASE_LIBRARY_JUMP_BUFFER) + BASE_LIBRARY_JUMP_BUFFER_ALIGNMENT);
- if (Image->JumpBuffer == NULL) {
- //
- // Image may be unloaded after return with failure,
- // then ImageHandle may be invalid, so use NULL handle to record perf log.
- //
- PERF_START_IMAGE_END (NULL);
-
- //
- // Pop the current start image context
- //
- mCurrentImage = LastImage;
-
- return EFI_OUT_OF_RESOURCES;
- }
-
- Image->JumpContext = ALIGN_POINTER (Image->JumpBuffer, BASE_LIBRARY_JUMP_BUFFER_ALIGNMENT);
-
- SetJumpFlag = SetJump (Image->JumpContext);
- //
- // The initial call to SetJump() must always return 0.
- // Subsequent calls to LongJump() cause a non-zero value to be returned by SetJump().
- //
- if (SetJumpFlag == 0) {
- RegisterMemoryProfileImage (Image, (Image->ImageContext.ImageType == EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION ? EFI_FV_FILETYPE_APPLICATION : EFI_FV_FILETYPE_DRIVER));
- //
- // Call the image's entry point
- //
- Image->Started = TRUE;
- Image->Status = Image->EntryPoint (ImageHandle, Image->Info.SystemTable);
-
- //
- // Add some debug information if the image returned with error.
- // This make the user aware and check if the driver image have already released
- // all the resource in this situation.
- //
- DEBUG_CODE_BEGIN ();
- if (EFI_ERROR (Image->Status)) {
- DEBUG ((DEBUG_ERROR, "Error: Image at %11p start failed: %r\n", Image->Info.ImageBase, Image->Status));
- }
-
- DEBUG_CODE_END ();
-
- //
- // If the image returns, exit it through Exit()
- //
- CoreExit (ImageHandle, Image->Status, 0, NULL);
- }
-
- //
- // Image has completed. Verify the tpl is the same
- //
- ASSERT (Image->Tpl == gEfiCurrentTpl);
- CoreRestoreTpl (Image->Tpl);
-
- CoreFreePool (Image->JumpBuffer);
-
- //
- // Pop the current start image context
- //
- mCurrentImage = LastImage;
-
- //
- // UEFI Specification - StartImage() - EFI 1.10 Extension
- // To maintain compatibility with UEFI drivers that are written to the EFI
- // 1.02 Specification, StartImage() must monitor the handle database before
- // and after each image is started. If any handles are created or modified
- // when an image is started, then EFI_BOOT_SERVICES.ConnectController() must
- // be called with the Recursive parameter set to TRUE for each of the newly
- // created or modified handles before StartImage() returns.
- //
- if (Image->Type != EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION) {
- CoreConnectHandlesByKey (HandleDatabaseKey);
- }
-
- //
- // Handle the image's returned ExitData
- //
- DEBUG_CODE_BEGIN ();
- if ((Image->ExitDataSize != 0) || (Image->ExitData != NULL)) {
- DEBUG ((DEBUG_LOAD, "StartImage: ExitDataSize %d, ExitData %p", (UINT32)Image->ExitDataSize, Image->ExitData));
- if (Image->ExitData != NULL) {
- DEBUG ((DEBUG_LOAD, " (%s)", Image->ExitData));
- }
-
- DEBUG ((DEBUG_LOAD, "\n"));
- }
-
- DEBUG_CODE_END ();
-
- //
- // Return the exit data to the caller
- //
- if ((ExitData != NULL) && (ExitDataSize != NULL)) {
- *ExitDataSize = Image->ExitDataSize;
- *ExitData = Image->ExitData;
- } else {
- //
- // Caller doesn't want the exit data, free it
- //
- CoreFreePool (Image->ExitData);
- Image->ExitData = NULL;
- }
-
- //
- // Save the Status because Image will get destroyed if it is unloaded.
- //
- Status = Image->Status;
-
- //
- // If the image returned an error, or if the image is an application
- // unload it
- //
- if (EFI_ERROR (Image->Status) || (Image->Type == EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION)) {
- CoreUnloadAndCloseImage (Image, TRUE);
- //
- // ImageHandle may be invalid after the image is unloaded, so use NULL handle to record perf log.
- //
- Handle = NULL;
- }
-
- //
- // Done
- //
- PERF_START_IMAGE_END (Handle);
- return Status;
-}
-
-/**
- Terminates the currently loaded EFI image and returns control to boot services.
-
- @param ImageHandle Handle that identifies the image. This
- parameter is passed to the image on entry.
- @param Status The image's exit code.
- @param ExitDataSize The size, in bytes, of ExitData. Ignored if
- ExitStatus is EFI_SUCCESS.
- @param ExitData Pointer to a data buffer that includes a
- Null-terminated Unicode string, optionally
- followed by additional binary data. The string
- is a description that the caller may use to
- further indicate the reason for the image's
- exit.
-
- @retval EFI_INVALID_PARAMETER Image handle is NULL or it is not current
- image.
- @retval EFI_SUCCESS Successfully terminates the currently loaded
- EFI image.
- @retval EFI_ACCESS_DENIED Should never reach there.
- @retval EFI_OUT_OF_RESOURCES Could not allocate pool
-
-**/
-EFI_STATUS
-EFIAPI
-CoreExit (
- IN EFI_HANDLE ImageHandle,
- IN EFI_STATUS Status,
- IN UINTN ExitDataSize,
- IN CHAR16 *ExitData OPTIONAL
- )
-{
- LOADED_IMAGE_PRIVATE_DATA *Image;
- EFI_TPL OldTpl;
-
- //
- // Prevent possible reentrance to this function
- // for the same ImageHandle
- //
- OldTpl = CoreRaiseTpl (TPL_NOTIFY);
-
- Image = CoreLoadedImageInfo (ImageHandle);
- if (Image == NULL) {
- Status = EFI_INVALID_PARAMETER;
- goto Done;
- }
-
- if (!Image->Started) {
- //
- // The image has not been started so just free its resources
- //
- CoreUnloadAndCloseImage (Image, TRUE);
- Status = EFI_SUCCESS;
- goto Done;
- }
-
- //
- // Image has been started, verify this image can exit
- //
- if (Image != mCurrentImage) {
- DEBUG ((DEBUG_LOAD|DEBUG_ERROR, "Exit: Image is not exitable image\n"));
- Status = EFI_INVALID_PARAMETER;
- goto Done;
- }
-
- //
- // Set status
- //
- Image->Status = Status;
-
- //
- // If there's ExitData info, move it
- //
- if (ExitData != NULL) {
- Image->ExitDataSize = ExitDataSize;
- Image->ExitData = AllocatePool (Image->ExitDataSize);
- if (Image->ExitData == NULL) {
- Status = EFI_OUT_OF_RESOURCES;
- goto Done;
- }
-
- CopyMem (Image->ExitData, ExitData, Image->ExitDataSize);
- }
-
- CoreRestoreTpl (OldTpl);
- //
- // return to StartImage
- //
- LongJump (Image->JumpContext, (UINTN)-1);
-
- //
- // If we return from LongJump, then it is an error
- //
- ASSERT (FALSE);
- Status = EFI_ACCESS_DENIED;
-Done:
- CoreRestoreTpl (OldTpl);
- return Status;
-}
-
-/**
- Unloads an image.
-
- @param ImageHandle Handle that identifies the image to be
- unloaded.
-
- @retval EFI_SUCCESS The image has been unloaded.
- @retval EFI_UNSUPPORTED The image has been started, and does not support
- unload.
- @retval EFI_INVALID_PARAMPETER ImageHandle is not a valid image handle.
-
-**/
-EFI_STATUS
-EFIAPI
-CoreUnloadImage (
- IN EFI_HANDLE ImageHandle
- )
-{
- EFI_STATUS Status;
- LOADED_IMAGE_PRIVATE_DATA *Image;
-
- Image = CoreLoadedImageInfo (ImageHandle);
- if (Image == NULL ) {
- //
- // The image handle is not valid
- //
- Status = EFI_INVALID_PARAMETER;
- goto Done;
- }
-
- if (Image->Started) {
- //
- // The image has been started, request it to unload.
- //
- Status = EFI_UNSUPPORTED;
- if (Image->Info.Unload != NULL) {
- Status = Image->Info.Unload (ImageHandle);
- }
- } else {
- //
- // This Image hasn't been started, thus it can be unloaded
- //
- Status = EFI_SUCCESS;
- }
-
- if (!EFI_ERROR (Status)) {
- //
- // if the Image was not started or Unloaded O.K. then clean up
- //
- CoreUnloadAndCloseImage (Image, TRUE);
- }
-
-Done:
- return Status;
-}
+/** @file
+ Core image handling services to load and unload PeImage.
+
+Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "DxeMain.h"
+#include "Image.h"
+
+//
+// Module Globals
+//
+LOADED_IMAGE_PRIVATE_DATA *mCurrentImage = NULL;
+
+typedef struct {
+ LIST_ENTRY Link;
+ EDKII_PECOFF_IMAGE_EMULATOR_PROTOCOL *Emulator;
+ UINT16 MachineType;
+} EMULATOR_ENTRY;
+
+STATIC LIST_ENTRY mAvailableEmulators;
+STATIC EFI_EVENT mPeCoffEmuProtocolRegistrationEvent;
+STATIC VOID *mPeCoffEmuProtocolNotifyRegistration;
+
+//
+// This code is needed to build the Image handle for the DXE Core
+//
+LOADED_IMAGE_PRIVATE_DATA mCorePrivateImage = {
+ LOADED_IMAGE_PRIVATE_DATA_SIGNATURE, // Signature
+ NULL, // Image handle
+ EFI_IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER, // Image type
+ TRUE, // If entrypoint has been called
+ NULL, // EntryPoint
+ {
+ EFI_LOADED_IMAGE_INFORMATION_REVISION, // Revision
+ NULL, // Parent handle
+ NULL, // System handle
+
+ NULL, // Device handle
+ NULL, // File path
+ NULL, // Reserved
+
+ 0, // LoadOptionsSize
+ NULL, // LoadOptions
+
+ NULL, // ImageBase
+ 0, // ImageSize
+ EfiBootServicesCode, // ImageCodeType
+ EfiBootServicesData // ImageDataType
+ },
+ (EFI_PHYSICAL_ADDRESS)0, // ImageBasePage
+ 0, // NumberOfPages
+ NULL, // FixupData
+ 0, // Tpl
+ EFI_SUCCESS, // Status
+ 0, // ExitDataSize
+ NULL, // ExitData
+ NULL, // JumpBuffer
+ NULL, // JumpContext
+ 0, // Machine
+ NULL, // PeCoffEmu
+ NULL, // RuntimeData
+ NULL // LoadedImageDevicePath
+};
+//
+// The field is define for Loading modules at fixed address feature to tracker the PEI code
+// memory range usage. It is a bit mapped array in which every bit indicates the correspoding memory page
+// available or not.
+//
+GLOBAL_REMOVE_IF_UNREFERENCED UINT64 *mDxeCodeMemoryRangeUsageBitMap = NULL;
+
+typedef struct {
+ UINT16 MachineType;
+ CHAR16 *MachineTypeName;
+} MACHINE_TYPE_INFO;
+
+GLOBAL_REMOVE_IF_UNREFERENCED MACHINE_TYPE_INFO mMachineTypeInfo[] = {
+ { EFI_IMAGE_MACHINE_IA32, L"IA32" },
+ { EFI_IMAGE_MACHINE_IA64, L"IA64" },
+ { EFI_IMAGE_MACHINE_X64, L"X64" },
+ { EFI_IMAGE_MACHINE_ARMTHUMB_MIXED, L"ARM" },
+ { EFI_IMAGE_MACHINE_AARCH64, L"AARCH64" },
+ { EFI_IMAGE_MACHINE_RISCV64, L"RISCV64" },
+ { EFI_IMAGE_MACHINE_LOONGARCH64, L"LOONGARCH64" },
+};
+
+UINT16 mDxeCoreImageMachineType = 0;
+
+/**
+ Return machine type name.
+
+ @param MachineType The machine type
+
+ @return machine type name
+**/
+CHAR16 *
+GetMachineTypeName (
+ UINT16 MachineType
+ )
+{
+ UINTN Index;
+
+ for (Index = 0; Index < sizeof (mMachineTypeInfo)/sizeof (mMachineTypeInfo[0]); Index++) {
+ if (mMachineTypeInfo[Index].MachineType == MachineType) {
+ return mMachineTypeInfo[Index].MachineTypeName;
+ }
+ }
+
+ return L"<Unknown>";
+}
+
+/**
+ Notification event handler registered by CoreInitializeImageServices () to
+ keep track of which PE/COFF image emulators are available.
+
+ @param Event The Event that is being processed, not used.
+ @param Context Event Context, not used.
+
+**/
+STATIC
+VOID
+EFIAPI
+PeCoffEmuProtocolNotify (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ EFI_STATUS Status;
+ UINTN BufferSize;
+ EFI_HANDLE EmuHandle;
+ EDKII_PECOFF_IMAGE_EMULATOR_PROTOCOL *Emulator;
+ EMULATOR_ENTRY *Entry;
+
+ EmuHandle = NULL;
+ Emulator = NULL;
+
+ while (TRUE) {
+ BufferSize = sizeof (EmuHandle);
+ Status = CoreLocateHandle (
+ ByRegisterNotify,
+ NULL,
+ mPeCoffEmuProtocolNotifyRegistration,
+ &BufferSize,
+ &EmuHandle
+ );
+ if (EFI_ERROR (Status)) {
+ //
+ // If no more notification events exit
+ //
+ return;
+ }
+
+ Status = CoreHandleProtocol (
+ EmuHandle,
+ &gEdkiiPeCoffImageEmulatorProtocolGuid,
+ (VOID **)&Emulator
+ );
+ if (EFI_ERROR (Status) || (Emulator == NULL)) {
+ continue;
+ }
+
+ Entry = AllocateZeroPool (sizeof (*Entry));
+ ASSERT (Entry != NULL);
+
+ Entry->Emulator = Emulator;
+ Entry->MachineType = Entry->Emulator->MachineType;
+
+ InsertTailList (&mAvailableEmulators, &Entry->Link);
+ }
+}
+
+/**
+ Add the Image Services to EFI Boot Services Table and install the protocol
+ interfaces for this image.
+
+ @param HobStart The HOB to initialize
+
+ @return Status code.
+
+**/
+EFI_STATUS
+CoreInitializeImageServices (
+ IN VOID *HobStart
+ )
+{
+ EFI_STATUS Status;
+ LOADED_IMAGE_PRIVATE_DATA *Image;
+ EFI_PHYSICAL_ADDRESS DxeCoreImageBaseAddress;
+ UINT64 DxeCoreImageLength;
+ VOID *DxeCoreEntryPoint;
+ EFI_PEI_HOB_POINTERS DxeCoreHob;
+
+ //
+ // Searching for image hob
+ //
+ DxeCoreHob.Raw = HobStart;
+ while ((DxeCoreHob.Raw = GetNextHob (EFI_HOB_TYPE_MEMORY_ALLOCATION, DxeCoreHob.Raw)) != NULL) {
+ if (CompareGuid (&DxeCoreHob.MemoryAllocationModule->MemoryAllocationHeader.Name, &gEfiHobMemoryAllocModuleGuid)) {
+ //
+ // Find Dxe Core HOB
+ //
+ break;
+ }
+
+ DxeCoreHob.Raw = GET_NEXT_HOB (DxeCoreHob);
+ }
+
+ ASSERT (DxeCoreHob.Raw != NULL);
+
+ DxeCoreImageBaseAddress = DxeCoreHob.MemoryAllocationModule->MemoryAllocationHeader.MemoryBaseAddress;
+ DxeCoreImageLength = DxeCoreHob.MemoryAllocationModule->MemoryAllocationHeader.MemoryLength;
+ DxeCoreEntryPoint = (VOID *)(UINTN)DxeCoreHob.MemoryAllocationModule->EntryPoint;
+ gDxeCoreFileName = &DxeCoreHob.MemoryAllocationModule->ModuleName;
+
+ //
+ // Initialize the fields for an internal driver
+ //
+ Image = &mCorePrivateImage;
+
+ Image->EntryPoint = (EFI_IMAGE_ENTRY_POINT)(UINTN)DxeCoreEntryPoint;
+ Image->ImageBasePage = DxeCoreImageBaseAddress;
+ Image->NumberOfPages = (UINTN)(EFI_SIZE_TO_PAGES ((UINTN)(DxeCoreImageLength)));
+ Image->Tpl = gEfiCurrentTpl;
+ Image->Info.ImageBase = (VOID *)(UINTN)DxeCoreImageBaseAddress;
+ Image->Info.ImageSize = DxeCoreImageLength;
+
+ //
+ // Install the protocol interfaces for this image
+ //
+ Status = CoreInstallProtocolInterface (
+ &Image->Handle,
+ &gEfiLoadedImageProtocolGuid,
+ EFI_NATIVE_INTERFACE,
+ &Image->Info
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ mCurrentImage = Image;
+
+ //
+ // Fill in DXE globals
+ //
+ mDxeCoreImageMachineType = PeCoffLoaderGetMachineType (Image->Info.ImageBase);
+ gDxeCoreImageHandle = Image->Handle;
+ gDxeCoreLoadedImage = &Image->Info;
+
+ //
+ // Create the PE/COFF emulator protocol registration event
+ //
+ Status = CoreCreateEvent (
+ EVT_NOTIFY_SIGNAL,
+ TPL_CALLBACK,
+ PeCoffEmuProtocolNotify,
+ NULL,
+ &mPeCoffEmuProtocolRegistrationEvent
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Register for protocol notifications on this event
+ //
+ Status = CoreRegisterProtocolNotify (
+ &gEdkiiPeCoffImageEmulatorProtocolGuid,
+ mPeCoffEmuProtocolRegistrationEvent,
+ &mPeCoffEmuProtocolNotifyRegistration
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ InitializeListHead (&mAvailableEmulators);
+
+ ProtectUefiImage (&Image->Info, Image->LoadedImageDevicePath);
+
+ return Status;
+}
+
+/**
+ Read image file (specified by UserHandle) into user specified buffer with specified offset
+ and length.
+
+ @param UserHandle Image file handle
+ @param Offset Offset to the source file
+ @param ReadSize For input, pointer of size to read; For output,
+ pointer of size actually read.
+ @param Buffer Buffer to write into
+
+ @retval EFI_SUCCESS Successfully read the specified part of file
+ into buffer.
+
+**/
+EFI_STATUS
+EFIAPI
+CoreReadImageFile (
+ IN VOID *UserHandle,
+ IN UINTN Offset,
+ IN OUT UINTN *ReadSize,
+ OUT VOID *Buffer
+ )
+{
+ UINTN EndPosition;
+ IMAGE_FILE_HANDLE *FHand;
+
+ if ((UserHandle == NULL) || (ReadSize == NULL) || (Buffer == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (MAX_ADDRESS - Offset < *ReadSize) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ FHand = (IMAGE_FILE_HANDLE *)UserHandle;
+ ASSERT (FHand->Signature == IMAGE_FILE_HANDLE_SIGNATURE);
+
+ //
+ // Move data from our local copy of the file
+ //
+ EndPosition = Offset + *ReadSize;
+ if (EndPosition > FHand->SourceSize) {
+ *ReadSize = (UINT32)(FHand->SourceSize - Offset);
+ }
+
+ if (Offset >= FHand->SourceSize) {
+ *ReadSize = 0;
+ }
+
+ CopyMem (Buffer, (CHAR8 *)FHand->Source + Offset, *ReadSize);
+ return EFI_SUCCESS;
+}
+
+/**
+ To check memory usage bit map array to figure out if the memory range the image will be loaded in is available or not. If
+ memory range is available, the function will mark the corresponding bits to 1 which indicates the memory range is used.
+ The function is only invoked when load modules at fixed address feature is enabled.
+
+ @param ImageBase The base address the image will be loaded at.
+ @param ImageSize The size of the image
+
+ @retval EFI_SUCCESS The memory range the image will be loaded in is available
+ @retval EFI_NOT_FOUND The memory range the image will be loaded in is not available
+**/
+EFI_STATUS
+CheckAndMarkFixLoadingMemoryUsageBitMap (
+ IN EFI_PHYSICAL_ADDRESS ImageBase,
+ IN UINTN ImageSize
+ )
+{
+ UINT32 DxeCodePageNumber;
+ UINT64 DxeCodeSize;
+ EFI_PHYSICAL_ADDRESS DxeCodeBase;
+ UINTN BaseOffsetPageNumber;
+ UINTN TopOffsetPageNumber;
+ UINTN Index;
+
+ //
+ // The DXE code range includes RuntimeCodePage range and Boot time code range.
+ //
+ DxeCodePageNumber = PcdGet32 (PcdLoadFixAddressRuntimeCodePageNumber);
+ DxeCodePageNumber += PcdGet32 (PcdLoadFixAddressBootTimeCodePageNumber);
+ DxeCodeSize = EFI_PAGES_TO_SIZE (DxeCodePageNumber);
+ DxeCodeBase = gLoadModuleAtFixAddressConfigurationTable.DxeCodeTopAddress - DxeCodeSize;
+
+ //
+ // If the memory usage bit map is not initialized, do it. Every bit in the array
+ // indicate the status of the corresponding memory page, available or not
+ //
+ if (mDxeCodeMemoryRangeUsageBitMap == NULL) {
+ mDxeCodeMemoryRangeUsageBitMap = AllocateZeroPool (((DxeCodePageNumber/64) + 1)*sizeof (UINT64));
+ }
+
+ //
+ // If the Dxe code memory range is not allocated or the bit map array allocation failed, return EFI_NOT_FOUND
+ //
+ if (!gLoadFixedAddressCodeMemoryReady || (mDxeCodeMemoryRangeUsageBitMap == NULL)) {
+ return EFI_NOT_FOUND;
+ }
+
+ //
+ // Test the memory range for loading the image in the DXE code range.
+ //
+ if ((gLoadModuleAtFixAddressConfigurationTable.DxeCodeTopAddress < ImageBase + ImageSize) ||
+ (DxeCodeBase > ImageBase))
+ {
+ return EFI_NOT_FOUND;
+ }
+
+ //
+ // Test if the memory is avalaible or not.
+ //
+ BaseOffsetPageNumber = EFI_SIZE_TO_PAGES ((UINT32)(ImageBase - DxeCodeBase));
+ TopOffsetPageNumber = EFI_SIZE_TO_PAGES ((UINT32)(ImageBase + ImageSize - DxeCodeBase));
+ for (Index = BaseOffsetPageNumber; Index < TopOffsetPageNumber; Index++) {
+ if ((mDxeCodeMemoryRangeUsageBitMap[Index / 64] & LShiftU64 (1, (Index % 64))) != 0) {
+ //
+ // This page is already used.
+ //
+ return EFI_NOT_FOUND;
+ }
+ }
+
+ //
+ // Being here means the memory range is available. So mark the bits for the memory range
+ //
+ for (Index = BaseOffsetPageNumber; Index < TopOffsetPageNumber; Index++) {
+ mDxeCodeMemoryRangeUsageBitMap[Index / 64] |= LShiftU64 (1, (Index % 64));
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+
+ Get the fixed loading address from image header assigned by build tool. This function only be called
+ when Loading module at Fixed address feature enabled.
+
+ @param ImageContext Pointer to the image context structure that describes the PE/COFF
+ image that needs to be examined by this function.
+ @retval EFI_SUCCESS An fixed loading address is assigned to this image by build tools .
+ @retval EFI_NOT_FOUND The image has no assigned fixed loading address.
+
+**/
+EFI_STATUS
+GetPeCoffImageFixLoadingAssignedAddress (
+ IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext
+ )
+{
+ UINTN SectionHeaderOffset;
+ EFI_STATUS Status;
+ EFI_IMAGE_SECTION_HEADER SectionHeader;
+ EFI_IMAGE_OPTIONAL_HEADER_UNION *ImgHdr;
+ UINT16 Index;
+ UINTN Size;
+ UINT16 NumberOfSections;
+ IMAGE_FILE_HANDLE *Handle;
+ UINT64 ValueInSectionHeader;
+
+ Status = EFI_NOT_FOUND;
+
+ //
+ // Get PeHeader pointer
+ //
+ Handle = (IMAGE_FILE_HANDLE *)ImageContext->Handle;
+ ImgHdr = (EFI_IMAGE_OPTIONAL_HEADER_UNION *)((CHAR8 *)Handle->Source + ImageContext->PeCoffHeaderOffset);
+ SectionHeaderOffset = ImageContext->PeCoffHeaderOffset +
+ sizeof (UINT32) +
+ sizeof (EFI_IMAGE_FILE_HEADER) +
+ ImgHdr->Pe32.FileHeader.SizeOfOptionalHeader;
+ NumberOfSections = ImgHdr->Pe32.FileHeader.NumberOfSections;
+
+ //
+ // Get base address from the first section header that doesn't point to code section.
+ //
+ for (Index = 0; Index < NumberOfSections; Index++) {
+ //
+ // Read section header from file
+ //
+ Size = sizeof (EFI_IMAGE_SECTION_HEADER);
+ Status = ImageContext->ImageRead (
+ ImageContext->Handle,
+ SectionHeaderOffset,
+ &Size,
+ &SectionHeader
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if (Size != sizeof (EFI_IMAGE_SECTION_HEADER)) {
+ return EFI_NOT_FOUND;
+ }
+
+ Status = EFI_NOT_FOUND;
+
+ if ((SectionHeader.Characteristics & EFI_IMAGE_SCN_CNT_CODE) == 0) {
+ //
+ // Build tool will save the address in PointerToRelocations & PointerToLineNumbers fields in the first section header
+ // that doesn't point to code section in image header, as well as ImageBase field of image header. And there is an
+ // assumption that when the feature is enabled, if a module is assigned a loading address by tools, PointerToRelocations
+ // & PointerToLineNumbers fields should NOT be Zero, or else, these 2 fields should be set to Zero
+ //
+ ValueInSectionHeader = ReadUnaligned64 ((UINT64 *)&SectionHeader.PointerToRelocations);
+ if (ValueInSectionHeader != 0) {
+ //
+ // When the feature is configured as load module at fixed absolute address, the ImageAddress field of ImageContext
+ // hold the specified address. If the feature is configured as load module at fixed offset, ImageAddress hold an offset
+ // relative to top address
+ //
+ if ((INT64)PcdGet64 (PcdLoadModuleAtFixAddressEnable) < 0) {
+ ImageContext->ImageAddress = gLoadModuleAtFixAddressConfigurationTable.DxeCodeTopAddress + (INT64)(INTN)ImageContext->ImageAddress;
+ }
+
+ //
+ // Check if the memory range is available.
+ //
+ Status = CheckAndMarkFixLoadingMemoryUsageBitMap (ImageContext->ImageAddress, (UINTN)(ImageContext->ImageSize + ImageContext->SectionAlignment));
+ }
+
+ break;
+ }
+
+ SectionHeaderOffset += sizeof (EFI_IMAGE_SECTION_HEADER);
+ }
+
+ DEBUG ((DEBUG_INFO|DEBUG_LOAD, "LOADING MODULE FIXED INFO: Loading module at fixed address 0x%11p. Status = %r \n", (VOID *)(UINTN)(ImageContext->ImageAddress), Status));
+ return Status;
+}
+
+/**
+ Decides whether a PE/COFF image can execute on this system, either natively
+ or via emulation/interpretation. In the latter case, the PeCoffEmu member
+ of the LOADED_IMAGE_PRIVATE_DATA struct pointer is populated with a pointer
+ to the emulator protocol that supports this image.
+
+ @param[in, out] Image LOADED_IMAGE_PRIVATE_DATA struct pointer
+
+ @retval TRUE The image is supported
+ @retval FALSE The image is not supported
+
+**/
+STATIC
+BOOLEAN
+CoreIsImageTypeSupported (
+ IN OUT LOADED_IMAGE_PRIVATE_DATA *Image
+ )
+{
+ LIST_ENTRY *Link;
+ EMULATOR_ENTRY *Entry;
+
+ for (Link = GetFirstNode (&mAvailableEmulators);
+ !IsNull (&mAvailableEmulators, Link);
+ Link = GetNextNode (&mAvailableEmulators, Link))
+ {
+ Entry = BASE_CR (Link, EMULATOR_ENTRY, Link);
+ if (Entry->MachineType != Image->ImageContext.Machine) {
+ continue;
+ }
+
+ if (Entry->Emulator->IsImageSupported (
+ Entry->Emulator,
+ Image->ImageContext.ImageType,
+ Image->Info.FilePath
+ ))
+ {
+ Image->PeCoffEmu = Entry->Emulator;
+ return TRUE;
+ }
+ }
+
+ return EFI_IMAGE_MACHINE_TYPE_SUPPORTED (Image->ImageContext.Machine) ||
+ EFI_IMAGE_MACHINE_CROSS_TYPE_SUPPORTED (Image->ImageContext.Machine);
+}
+
+/**
+ Loads, relocates, and invokes a PE/COFF image
+
+ @param BootPolicy If TRUE, indicates that the request originates
+ from the boot manager, and that the boot
+ manager is attempting to load FilePath as a
+ boot selection.
+ @param Pe32Handle The handle of PE32 image
+ @param Image PE image to be loaded
+ @param DstBuffer The buffer to store the image
+ @param EntryPoint A pointer to the entry point
+ @param Attribute The bit mask of attributes to set for the load
+ PE image
+
+ @retval EFI_SUCCESS The file was loaded, relocated, and invoked
+ @retval EFI_OUT_OF_RESOURCES There was not enough memory to load and
+ relocate the PE/COFF file
+ @retval EFI_INVALID_PARAMETER Invalid parameter
+ @retval EFI_BUFFER_TOO_SMALL Buffer for image is too small
+
+**/
+EFI_STATUS
+CoreLoadPeImage (
+ IN BOOLEAN BootPolicy,
+ IN VOID *Pe32Handle,
+ IN LOADED_IMAGE_PRIVATE_DATA *Image,
+ IN EFI_PHYSICAL_ADDRESS DstBuffer OPTIONAL,
+ OUT EFI_PHYSICAL_ADDRESS *EntryPoint OPTIONAL,
+ IN UINT32 Attribute
+ )
+{
+ EFI_STATUS Status;
+ BOOLEAN DstBufAlocated;
+ UINTN Size;
+
+ ZeroMem (&Image->ImageContext, sizeof (Image->ImageContext));
+
+ Image->ImageContext.Handle = Pe32Handle;
+ Image->ImageContext.ImageRead = (PE_COFF_LOADER_READ_FILE)CoreReadImageFile;
+
+ //
+ // Get information about the image being loaded
+ //
+ Status = PeCoffLoaderGetImageInfo (&Image->ImageContext);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if (!CoreIsImageTypeSupported (Image)) {
+ //
+ // The PE/COFF loader can support loading image types that can be executed.
+ // If we loaded an image type that we can not execute return EFI_UNSUPPORTED.
+ //
+ DEBUG ((
+ DEBUG_ERROR,
+ "Image type %s can't be loaded on %s UEFI system.\n",
+ GetMachineTypeName (Image->ImageContext.Machine),
+ GetMachineTypeName (mDxeCoreImageMachineType)
+ ));
+ return EFI_UNSUPPORTED;
+ }
+
+ //
+ // Set EFI memory type based on ImageType
+ //
+ switch (Image->ImageContext.ImageType) {
+ case EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION:
+ Image->ImageContext.ImageCodeMemoryType = EfiLoaderCode;
+ Image->ImageContext.ImageDataMemoryType = EfiLoaderData;
+ break;
+ case EFI_IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER:
+ Image->ImageContext.ImageCodeMemoryType = EfiBootServicesCode;
+ Image->ImageContext.ImageDataMemoryType = EfiBootServicesData;
+ break;
+ case EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER:
+ case EFI_IMAGE_SUBSYSTEM_SAL_RUNTIME_DRIVER:
+ Image->ImageContext.ImageCodeMemoryType = EfiRuntimeServicesCode;
+ Image->ImageContext.ImageDataMemoryType = EfiRuntimeServicesData;
+ break;
+ default:
+ Image->ImageContext.ImageError = IMAGE_ERROR_INVALID_SUBSYSTEM;
+ return EFI_UNSUPPORTED;
+ }
+
+ //
+ // Allocate memory of the correct memory type aligned on the required image boundary
+ //
+ DstBufAlocated = FALSE;
+ if (DstBuffer == 0) {
+ //
+ // Allocate Destination Buffer as caller did not pass it in
+ //
+
+ if (Image->ImageContext.SectionAlignment > EFI_PAGE_SIZE) {
+ Size = (UINTN)Image->ImageContext.ImageSize + Image->ImageContext.SectionAlignment;
+ } else {
+ Size = (UINTN)Image->ImageContext.ImageSize;
+ }
+
+ Image->NumberOfPages = EFI_SIZE_TO_PAGES (Size);
+
+ //
+ // If the image relocations have not been stripped, then load at any address.
+ // Otherwise load at the address at which it was linked.
+ //
+ // Memory below 1MB should be treated reserved for CSM and there should be
+ // no modules whose preferred load addresses are below 1MB.
+ //
+ Status = EFI_OUT_OF_RESOURCES;
+ //
+ // If Loading Module At Fixed Address feature is enabled, the module should be loaded to
+ // a specified address.
+ //
+ if (PcdGet64 (PcdLoadModuleAtFixAddressEnable) != 0 ) {
+ Status = GetPeCoffImageFixLoadingAssignedAddress (&(Image->ImageContext));
+
+ if (EFI_ERROR (Status)) {
+ //
+ // If the code memory is not ready, invoke CoreAllocatePage with AllocateAnyPages to load the driver.
+ //
+ DEBUG ((DEBUG_INFO|DEBUG_LOAD, "LOADING MODULE FIXED ERROR: Loading module at fixed address failed since specified memory is not available.\n"));
+
+ Status = CoreAllocatePages (
+ AllocateAnyPages,
+ (EFI_MEMORY_TYPE)(Image->ImageContext.ImageCodeMemoryType),
+ Image->NumberOfPages,
+ &Image->ImageContext.ImageAddress
+ );
+ }
+ } else {
+ if ((PcdGetBool (PcdImageLargeAddressLoad) && ((Image->ImageContext.ImageAddress) >= 0x100000)) ||
+ Image->ImageContext.RelocationsStripped)
+ {
+ Status = CoreAllocatePages (
+ AllocateAddress,
+ (EFI_MEMORY_TYPE)(Image->ImageContext.ImageCodeMemoryType),
+ Image->NumberOfPages,
+ &Image->ImageContext.ImageAddress
+ );
+ }
+
+ if (EFI_ERROR (Status) && !Image->ImageContext.RelocationsStripped) {
+ Status = CoreAllocatePages (
+ AllocateAnyPages,
+ (EFI_MEMORY_TYPE)(Image->ImageContext.ImageCodeMemoryType),
+ Image->NumberOfPages,
+ &Image->ImageContext.ImageAddress
+ );
+ }
+ }
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ DstBufAlocated = TRUE;
+ } else {
+ //
+ // Caller provided the destination buffer
+ //
+
+ if (Image->ImageContext.RelocationsStripped && (Image->ImageContext.ImageAddress != DstBuffer)) {
+ //
+ // If the image relocations were stripped, and the caller provided a
+ // destination buffer address that does not match the address that the
+ // image is linked at, then the image cannot be loaded.
+ //
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if ((Image->NumberOfPages != 0) &&
+ (Image->NumberOfPages <
+ (EFI_SIZE_TO_PAGES ((UINTN)Image->ImageContext.ImageSize + Image->ImageContext.SectionAlignment))))
+ {
+ Image->NumberOfPages = EFI_SIZE_TO_PAGES ((UINTN)Image->ImageContext.ImageSize + Image->ImageContext.SectionAlignment);
+ return EFI_BUFFER_TOO_SMALL;
+ }
+
+ Image->NumberOfPages = EFI_SIZE_TO_PAGES ((UINTN)Image->ImageContext.ImageSize + Image->ImageContext.SectionAlignment);
+ Image->ImageContext.ImageAddress = DstBuffer;
+ }
+
+ Image->ImageBasePage = Image->ImageContext.ImageAddress;
+ if (!Image->ImageContext.IsTeImage) {
+ Image->ImageContext.ImageAddress =
+ (Image->ImageContext.ImageAddress + Image->ImageContext.SectionAlignment - 1) &
+ ~((UINTN)Image->ImageContext.SectionAlignment - 1);
+ }
+
+ //
+ // Load the image from the file into the allocated memory
+ //
+ Status = PeCoffLoaderLoadImage (&Image->ImageContext);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ //
+ // If this is a Runtime Driver, then allocate memory for the FixupData that
+ // is used to relocate the image when SetVirtualAddressMap() is called. The
+ // relocation is done by the Runtime AP.
+ //
+ if ((Attribute & EFI_LOAD_PE_IMAGE_ATTRIBUTE_RUNTIME_REGISTRATION) != 0) {
+ if (Image->ImageContext.ImageType == EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER) {
+ Image->ImageContext.FixupData = AllocateRuntimePool ((UINTN)(Image->ImageContext.FixupDataSize));
+ if (Image->ImageContext.FixupData == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Done;
+ }
+ }
+ }
+
+ //
+ // Relocate the image in memory
+ //
+ Status = PeCoffLoaderRelocateImage (&Image->ImageContext);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ //
+ // Flush the Instruction Cache
+ //
+ InvalidateInstructionCacheRange ((VOID *)(UINTN)Image->ImageContext.ImageAddress, (UINTN)Image->ImageContext.ImageSize);
+
+ //
+ // Copy the machine type from the context to the image private data.
+ //
+ Image->Machine = Image->ImageContext.Machine;
+
+ //
+ // Get the image entry point.
+ //
+ Image->EntryPoint = (EFI_IMAGE_ENTRY_POINT)(UINTN)Image->ImageContext.EntryPoint;
+
+ //
+ // Fill in the image information for the Loaded Image Protocol
+ //
+ Image->Type = Image->ImageContext.ImageType;
+ Image->Info.ImageBase = (VOID *)(UINTN)Image->ImageContext.ImageAddress;
+ Image->Info.ImageSize = Image->ImageContext.ImageSize;
+ Image->Info.ImageCodeType = (EFI_MEMORY_TYPE)(Image->ImageContext.ImageCodeMemoryType);
+ Image->Info.ImageDataType = (EFI_MEMORY_TYPE)(Image->ImageContext.ImageDataMemoryType);
+ if ((Attribute & EFI_LOAD_PE_IMAGE_ATTRIBUTE_RUNTIME_REGISTRATION) != 0) {
+ if (Image->ImageContext.ImageType == EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER) {
+ //
+ // Make a list off all the RT images so we can let the RT AP know about them.
+ //
+ Image->RuntimeData = AllocateRuntimePool (sizeof (EFI_RUNTIME_IMAGE_ENTRY));
+ if (Image->RuntimeData == NULL) {
+ goto Done;
+ }
+
+ Image->RuntimeData->ImageBase = Image->Info.ImageBase;
+ Image->RuntimeData->ImageSize = (UINT64)(Image->Info.ImageSize);
+ Image->RuntimeData->RelocationData = Image->ImageContext.FixupData;
+ Image->RuntimeData->Handle = Image->Handle;
+ InsertTailList (&gRuntime->ImageHead, &Image->RuntimeData->Link);
+ InsertImageRecord (Image->RuntimeData);
+ }
+ }
+
+ //
+ // Fill in the entry point of the image if it is available
+ //
+ if (EntryPoint != NULL) {
+ *EntryPoint = Image->ImageContext.EntryPoint;
+ }
+
+ //
+ // Print the load address and the PDB file name if it is available
+ //
+
+ DEBUG_CODE_BEGIN ();
+
+ UINTN Index;
+ UINTN StartIndex;
+ CHAR8 EfiFileName[256];
+
+ DEBUG ((
+ DEBUG_INFO | DEBUG_LOAD,
+ "Loading driver at 0x%11p EntryPoint=0x%11p ",
+ (VOID *)(UINTN)Image->ImageContext.ImageAddress,
+ FUNCTION_ENTRY_POINT (Image->ImageContext.EntryPoint)
+ ));
+
+ //
+ // Print Module Name by Pdb file path.
+ // Windows and Unix style file path are all trimmed correctly.
+ //
+ if (Image->ImageContext.PdbPointer != NULL) {
+ StartIndex = 0;
+ for (Index = 0; Image->ImageContext.PdbPointer[Index] != 0; Index++) {
+ if ((Image->ImageContext.PdbPointer[Index] == '\\') || (Image->ImageContext.PdbPointer[Index] == '/')) {
+ StartIndex = Index + 1;
+ }
+ }
+
+ //
+ // Copy the PDB file name to our temporary string, and replace .pdb with .efi
+ // The PDB file name is limited in the range of 0~255.
+ // If the length is bigger than 255, trim the redudant characters to avoid overflow in array boundary.
+ //
+ for (Index = 0; Index < sizeof (EfiFileName) - 4; Index++) {
+ EfiFileName[Index] = Image->ImageContext.PdbPointer[Index + StartIndex];
+ if (EfiFileName[Index] == 0) {
+ EfiFileName[Index] = '.';
+ }
+
+ if (EfiFileName[Index] == '.') {
+ EfiFileName[Index + 1] = 'e';
+ EfiFileName[Index + 2] = 'f';
+ EfiFileName[Index + 3] = 'i';
+ EfiFileName[Index + 4] = 0;
+ break;
+ }
+ }
+
+ if (Index == sizeof (EfiFileName) - 4) {
+ EfiFileName[Index] = 0;
+ }
+
+ DEBUG ((DEBUG_INFO | DEBUG_LOAD, "%a", EfiFileName)); // &Image->ImageContext.PdbPointer[StartIndex]));
+ }
+
+ DEBUG ((DEBUG_INFO | DEBUG_LOAD, "\n"));
+
+ DEBUG_CODE_END ();
+
+ return EFI_SUCCESS;
+
+Done:
+
+ //
+ // Free memory.
+ //
+
+ if (DstBufAlocated) {
+ CoreFreePages (Image->ImageContext.ImageAddress, Image->NumberOfPages);
+ Image->ImageContext.ImageAddress = 0;
+ Image->ImageBasePage = 0;
+ }
+
+ if (Image->ImageContext.FixupData != NULL) {
+ CoreFreePool (Image->ImageContext.FixupData);
+ }
+
+ return Status;
+}
+
+/**
+ Get the image's private data from its handle.
+
+ @param ImageHandle The image handle
+
+ @return Return the image private data associated with ImageHandle.
+
+**/
+LOADED_IMAGE_PRIVATE_DATA *
+CoreLoadedImageInfo (
+ IN EFI_HANDLE ImageHandle
+ )
+{
+ EFI_STATUS Status;
+ EFI_LOADED_IMAGE_PROTOCOL *LoadedImage;
+ LOADED_IMAGE_PRIVATE_DATA *Image;
+
+ Status = CoreHandleProtocol (
+ ImageHandle,
+ &gEfiLoadedImageProtocolGuid,
+ (VOID **)&LoadedImage
+ );
+ if (!EFI_ERROR (Status)) {
+ Image = LOADED_IMAGE_PRIVATE_DATA_FROM_THIS (LoadedImage);
+ } else {
+ DEBUG ((DEBUG_LOAD, "CoreLoadedImageInfo: Not an ImageHandle %p\n", ImageHandle));
+ Image = NULL;
+ }
+
+ return Image;
+}
+
+/**
+ Unloads EFI image from memory.
+
+ @param Image EFI image
+ @param FreePage Free allocated pages
+
+**/
+VOID
+CoreUnloadAndCloseImage (
+ IN LOADED_IMAGE_PRIVATE_DATA *Image,
+ IN BOOLEAN FreePage
+ )
+{
+ EFI_STATUS Status;
+ UINTN HandleCount;
+ EFI_HANDLE *HandleBuffer;
+ UINTN HandleIndex;
+ EFI_GUID **ProtocolGuidArray;
+ UINTN ArrayCount;
+ UINTN ProtocolIndex;
+ EFI_OPEN_PROTOCOL_INFORMATION_ENTRY *OpenInfo;
+ UINTN OpenInfoCount;
+ UINTN OpenInfoIndex;
+
+ HandleBuffer = NULL;
+ ProtocolGuidArray = NULL;
+
+ if (Image->Started) {
+ UnregisterMemoryProfileImage (Image);
+ }
+
+ UnprotectUefiImage (&Image->Info, Image->LoadedImageDevicePath);
+
+ if (Image->PeCoffEmu != NULL) {
+ //
+ // If the PE/COFF Emulator protocol exists we must unregister the image.
+ //
+ Image->PeCoffEmu->UnregisterImage (Image->PeCoffEmu, Image->ImageBasePage);
+ }
+
+ //
+ // Unload image, free Image->ImageContext->ModHandle
+ //
+ PeCoffLoaderUnloadImage (&Image->ImageContext);
+
+ //
+ // Free our references to the image handle
+ //
+ if (Image->Handle != NULL) {
+ Status = CoreLocateHandleBuffer (
+ AllHandles,
+ NULL,
+ NULL,
+ &HandleCount,
+ &HandleBuffer
+ );
+ if (!EFI_ERROR (Status)) {
+ for (HandleIndex = 0; HandleIndex < HandleCount; HandleIndex++) {
+ Status = CoreProtocolsPerHandle (
+ HandleBuffer[HandleIndex],
+ &ProtocolGuidArray,
+ &ArrayCount
+ );
+ if (!EFI_ERROR (Status)) {
+ for (ProtocolIndex = 0; ProtocolIndex < ArrayCount; ProtocolIndex++) {
+ Status = CoreOpenProtocolInformation (
+ HandleBuffer[HandleIndex],
+ ProtocolGuidArray[ProtocolIndex],
+ &OpenInfo,
+ &OpenInfoCount
+ );
+ if (!EFI_ERROR (Status)) {
+ for (OpenInfoIndex = 0; OpenInfoIndex < OpenInfoCount; OpenInfoIndex++) {
+ if (OpenInfo[OpenInfoIndex].AgentHandle == Image->Handle) {
+ Status = CoreCloseProtocol (
+ HandleBuffer[HandleIndex],
+ ProtocolGuidArray[ProtocolIndex],
+ Image->Handle,
+ OpenInfo[OpenInfoIndex].ControllerHandle
+ );
+ }
+ }
+
+ if (OpenInfo != NULL) {
+ CoreFreePool (OpenInfo);
+ }
+ }
+ }
+
+ if (ProtocolGuidArray != NULL) {
+ CoreFreePool (ProtocolGuidArray);
+ }
+ }
+ }
+
+ if (HandleBuffer != NULL) {
+ CoreFreePool (HandleBuffer);
+ }
+ }
+
+ CoreRemoveDebugImageInfoEntry (Image->Handle);
+
+ Status = CoreUninstallProtocolInterface (
+ Image->Handle,
+ &gEfiLoadedImageDevicePathProtocolGuid,
+ Image->LoadedImageDevicePath
+ );
+
+ Status = CoreUninstallProtocolInterface (
+ Image->Handle,
+ &gEfiLoadedImageProtocolGuid,
+ &Image->Info
+ );
+
+ if (Image->ImageContext.HiiResourceData != 0) {
+ Status = CoreUninstallProtocolInterface (
+ Image->Handle,
+ &gEfiHiiPackageListProtocolGuid,
+ (VOID *)(UINTN)Image->ImageContext.HiiResourceData
+ );
+ }
+ }
+
+ if (Image->RuntimeData != NULL) {
+ if (Image->RuntimeData->Link.ForwardLink != NULL) {
+ //
+ // Remove the Image from the Runtime Image list as we are about to Free it!
+ //
+ RemoveEntryList (&Image->RuntimeData->Link);
+ RemoveImageRecord (Image->RuntimeData);
+ }
+
+ CoreFreePool (Image->RuntimeData);
+ }
+
+ //
+ // Free the Image from memory
+ //
+ if ((Image->ImageBasePage != 0) && FreePage) {
+ CoreFreePages (Image->ImageBasePage, Image->NumberOfPages);
+ }
+
+ //
+ // Done with the Image structure
+ //
+ if (Image->Info.FilePath != NULL) {
+ CoreFreePool (Image->Info.FilePath);
+ }
+
+ if (Image->LoadedImageDevicePath != NULL) {
+ CoreFreePool (Image->LoadedImageDevicePath);
+ }
+
+ if (Image->FixupData != NULL) {
+ CoreFreePool (Image->FixupData);
+ }
+
+ CoreFreePool (Image);
+}
+
+/**
+ Loads an EFI image into memory and returns a handle to the image.
+
+ @param BootPolicy If TRUE, indicates that the request originates
+ from the boot manager, and that the boot
+ manager is attempting to load FilePath as a
+ boot selection.
+ @param ParentImageHandle The caller's image handle.
+ @param FilePath The specific file path from which the image is
+ loaded.
+ @param SourceBuffer If not NULL, a pointer to the memory location
+ containing a copy of the image to be loaded.
+ @param SourceSize The size in bytes of SourceBuffer.
+ @param DstBuffer The buffer to store the image
+ @param NumberOfPages If not NULL, it inputs a pointer to the page
+ number of DstBuffer and outputs a pointer to
+ the page number of the image. If this number is
+ not enough, return EFI_BUFFER_TOO_SMALL and
+ this parameter contains the required number.
+ @param ImageHandle Pointer to the returned image handle that is
+ created when the image is successfully loaded.
+ @param EntryPoint A pointer to the entry point
+ @param Attribute The bit mask of attributes to set for the load
+ PE image
+
+ @retval EFI_SUCCESS The image was loaded into memory.
+ @retval EFI_NOT_FOUND The FilePath was not found.
+ @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
+ @retval EFI_BUFFER_TOO_SMALL The buffer is too small
+ @retval EFI_UNSUPPORTED The image type is not supported, or the device
+ path cannot be parsed to locate the proper
+ protocol for loading the file.
+ @retval EFI_OUT_OF_RESOURCES Image was not loaded due to insufficient
+ resources.
+ @retval EFI_LOAD_ERROR Image was not loaded because the image format was corrupt or not
+ understood.
+ @retval EFI_DEVICE_ERROR Image was not loaded because the device returned a read error.
+ @retval EFI_ACCESS_DENIED Image was not loaded because the platform policy prohibits the
+ image from being loaded. NULL is returned in *ImageHandle.
+ @retval EFI_SECURITY_VIOLATION Image was loaded and an ImageHandle was created with a
+ valid EFI_LOADED_IMAGE_PROTOCOL. However, the current
+ platform policy specifies that the image should not be started.
+
+**/
+EFI_STATUS
+CoreLoadImageCommon (
+ IN BOOLEAN BootPolicy,
+ IN EFI_HANDLE ParentImageHandle,
+ IN EFI_DEVICE_PATH_PROTOCOL *FilePath,
+ IN VOID *SourceBuffer OPTIONAL,
+ IN UINTN SourceSize,
+ IN EFI_PHYSICAL_ADDRESS DstBuffer OPTIONAL,
+ IN OUT UINTN *NumberOfPages OPTIONAL,
+ OUT EFI_HANDLE *ImageHandle,
+ OUT EFI_PHYSICAL_ADDRESS *EntryPoint OPTIONAL,
+ IN UINT32 Attribute
+ )
+{
+ LOADED_IMAGE_PRIVATE_DATA *Image;
+ LOADED_IMAGE_PRIVATE_DATA *ParentImage;
+ IMAGE_FILE_HANDLE FHand;
+ EFI_STATUS Status;
+ EFI_STATUS SecurityStatus;
+ EFI_HANDLE DeviceHandle;
+ UINT32 AuthenticationStatus;
+ EFI_DEVICE_PATH_PROTOCOL *OriginalFilePath;
+ EFI_DEVICE_PATH_PROTOCOL *HandleFilePath;
+ EFI_DEVICE_PATH_PROTOCOL *InputFilePath;
+ EFI_DEVICE_PATH_PROTOCOL *Node;
+ UINTN FilePathSize;
+ BOOLEAN ImageIsFromFv;
+ BOOLEAN ImageIsFromLoadFile;
+
+ SecurityStatus = EFI_SUCCESS;
+
+ ASSERT (gEfiCurrentTpl < TPL_NOTIFY);
+ ParentImage = NULL;
+
+ //
+ // The caller must pass in a valid ParentImageHandle
+ //
+ if ((ImageHandle == NULL) || (ParentImageHandle == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ ParentImage = CoreLoadedImageInfo (ParentImageHandle);
+ if (ParentImage == NULL) {
+ DEBUG ((DEBUG_LOAD|DEBUG_ERROR, "LoadImageEx: Parent handle not an image handle\n"));
+ return EFI_INVALID_PARAMETER;
+ }
+
+ ZeroMem (&FHand, sizeof (IMAGE_FILE_HANDLE));
+ FHand.Signature = IMAGE_FILE_HANDLE_SIGNATURE;
+ OriginalFilePath = FilePath;
+ InputFilePath = FilePath;
+ HandleFilePath = FilePath;
+ DeviceHandle = NULL;
+ Status = EFI_SUCCESS;
+ AuthenticationStatus = 0;
+ ImageIsFromFv = FALSE;
+ ImageIsFromLoadFile = FALSE;
+
+ //
+ // If the caller passed a copy of the file, then just use it
+ //
+ if (SourceBuffer != NULL) {
+ FHand.Source = SourceBuffer;
+ FHand.SourceSize = SourceSize;
+ Status = CoreLocateDevicePath (&gEfiDevicePathProtocolGuid, &HandleFilePath, &DeviceHandle);
+ if (EFI_ERROR (Status)) {
+ DeviceHandle = NULL;
+ }
+
+ if (SourceSize > 0) {
+ Status = EFI_SUCCESS;
+ } else {
+ Status = EFI_LOAD_ERROR;
+ }
+ } else {
+ if (FilePath == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Try to get the image device handle by checking the match protocol.
+ //
+ Node = NULL;
+ Status = CoreLocateDevicePath (&gEfiFirmwareVolume2ProtocolGuid, &HandleFilePath, &DeviceHandle);
+ if (!EFI_ERROR (Status)) {
+ ImageIsFromFv = TRUE;
+ } else {
+ HandleFilePath = FilePath;
+ Status = CoreLocateDevicePath (&gEfiSimpleFileSystemProtocolGuid, &HandleFilePath, &DeviceHandle);
+ if (EFI_ERROR (Status)) {
+ if (!BootPolicy) {
+ HandleFilePath = FilePath;
+ Status = CoreLocateDevicePath (&gEfiLoadFile2ProtocolGuid, &HandleFilePath, &DeviceHandle);
+ }
+
+ if (EFI_ERROR (Status)) {
+ HandleFilePath = FilePath;
+ Status = CoreLocateDevicePath (&gEfiLoadFileProtocolGuid, &HandleFilePath, &DeviceHandle);
+ if (!EFI_ERROR (Status)) {
+ ImageIsFromLoadFile = TRUE;
+ Node = HandleFilePath;
+ }
+ }
+ }
+ }
+
+ //
+ // Get the source file buffer by its device path.
+ //
+ FHand.Source = GetFileBufferByFilePath (
+ BootPolicy,
+ FilePath,
+ &FHand.SourceSize,
+ &AuthenticationStatus
+ );
+ if (FHand.Source == NULL) {
+ Status = EFI_NOT_FOUND;
+ } else {
+ FHand.FreeBuffer = TRUE;
+ if (ImageIsFromLoadFile) {
+ //
+ // LoadFile () may cause the device path of the Handle be updated.
+ //
+ OriginalFilePath = AppendDevicePath (DevicePathFromHandle (DeviceHandle), Node);
+ }
+ }
+ }
+
+ if (EFI_ERROR (Status)) {
+ Image = NULL;
+ goto Done;
+ }
+
+ if (gSecurity2 != NULL) {
+ //
+ // Verify File Authentication through the Security2 Architectural Protocol
+ //
+ SecurityStatus = gSecurity2->FileAuthentication (
+ gSecurity2,
+ OriginalFilePath,
+ FHand.Source,
+ FHand.SourceSize,
+ BootPolicy
+ );
+ if (!EFI_ERROR (SecurityStatus) && ImageIsFromFv) {
+ //
+ // When Security2 is installed, Security Architectural Protocol must be published.
+ //
+ ASSERT (gSecurity != NULL);
+
+ //
+ // Verify the Authentication Status through the Security Architectural Protocol
+ // Only on images that have been read using Firmware Volume protocol.
+ //
+ SecurityStatus = gSecurity->FileAuthenticationState (
+ gSecurity,
+ AuthenticationStatus,
+ OriginalFilePath
+ );
+ }
+ } else if ((gSecurity != NULL) && (OriginalFilePath != NULL)) {
+ //
+ // Verify the Authentication Status through the Security Architectural Protocol
+ //
+ SecurityStatus = gSecurity->FileAuthenticationState (
+ gSecurity,
+ AuthenticationStatus,
+ OriginalFilePath
+ );
+ }
+
+ //
+ // Check Security Status.
+ //
+ if (EFI_ERROR (SecurityStatus) && (SecurityStatus != EFI_SECURITY_VIOLATION)) {
+ if (SecurityStatus == EFI_ACCESS_DENIED) {
+ //
+ // Image was not loaded because the platform policy prohibits the image from being loaded.
+ // It's the only place we could meet EFI_ACCESS_DENIED.
+ //
+ *ImageHandle = NULL;
+ }
+
+ Status = SecurityStatus;
+ Image = NULL;
+ goto Done;
+ }
+
+ //
+ // Allocate a new image structure
+ //
+ Image = AllocateZeroPool (sizeof (LOADED_IMAGE_PRIVATE_DATA));
+ if (Image == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Done;
+ }
+
+ //
+ // Pull out just the file portion of the DevicePath for the LoadedImage FilePath
+ //
+ FilePath = OriginalFilePath;
+ if (DeviceHandle != NULL) {
+ Status = CoreHandleProtocol (DeviceHandle, &gEfiDevicePathProtocolGuid, (VOID **)&HandleFilePath);
+ if (!EFI_ERROR (Status)) {
+ FilePathSize = GetDevicePathSize (HandleFilePath) - sizeof (EFI_DEVICE_PATH_PROTOCOL);
+ FilePath = (EFI_DEVICE_PATH_PROTOCOL *)(((UINT8 *)FilePath) + FilePathSize);
+ }
+ }
+
+ //
+ // Initialize the fields for an internal driver
+ //
+ Image->Signature = LOADED_IMAGE_PRIVATE_DATA_SIGNATURE;
+ Image->Info.SystemTable = gDxeCoreST;
+ Image->Info.DeviceHandle = DeviceHandle;
+ Image->Info.Revision = EFI_LOADED_IMAGE_PROTOCOL_REVISION;
+ Image->Info.FilePath = DuplicateDevicePath (FilePath);
+ Image->Info.ParentHandle = ParentImageHandle;
+
+ if (NumberOfPages != NULL) {
+ Image->NumberOfPages = *NumberOfPages;
+ } else {
+ Image->NumberOfPages = 0;
+ }
+
+ //
+ // Install the protocol interfaces for this image
+ // don't fire notifications yet
+ //
+ Status = CoreInstallProtocolInterfaceNotify (
+ &Image->Handle,
+ &gEfiLoadedImageProtocolGuid,
+ EFI_NATIVE_INTERFACE,
+ &Image->Info,
+ FALSE
+ );
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ //
+ // Load the image. If EntryPoint is Null, it will not be set.
+ //
+ Status = CoreLoadPeImage (BootPolicy, &FHand, Image, DstBuffer, EntryPoint, Attribute);
+ if (EFI_ERROR (Status)) {
+ if ((Status == EFI_BUFFER_TOO_SMALL) || (Status == EFI_OUT_OF_RESOURCES)) {
+ if (NumberOfPages != NULL) {
+ *NumberOfPages = Image->NumberOfPages;
+ }
+ }
+
+ goto Done;
+ }
+
+ if (NumberOfPages != NULL) {
+ *NumberOfPages = Image->NumberOfPages;
+ }
+
+ //
+ // Register the image in the Debug Image Info Table if the attribute is set
+ //
+ if ((Attribute & EFI_LOAD_PE_IMAGE_ATTRIBUTE_DEBUG_IMAGE_INFO_TABLE_REGISTRATION) != 0) {
+ CoreNewDebugImageInfoEntry (EFI_DEBUG_IMAGE_INFO_TYPE_NORMAL, &Image->Info, Image->Handle);
+ }
+
+ //
+ // Check whether we are loading a runtime image that lacks support for
+ // IBT/BTI landing pads.
+ //
+ if ((Image->ImageContext.ImageCodeMemoryType == EfiRuntimeServicesCode) &&
+ ((Image->ImageContext.DllCharacteristicsEx & EFI_IMAGE_DLLCHARACTERISTICS_EX_FORWARD_CFI_COMPAT) == 0))
+ {
+ gMemoryAttributesTableForwardCfi = FALSE;
+ }
+
+ //
+ // Reinstall loaded image protocol to fire any notifications
+ //
+ Status = CoreReinstallProtocolInterface (
+ Image->Handle,
+ &gEfiLoadedImageProtocolGuid,
+ &Image->Info,
+ &Image->Info
+ );
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ //
+ // If DevicePath parameter to the LoadImage() is not NULL, then make a copy of DevicePath,
+ // otherwise Loaded Image Device Path Protocol is installed with a NULL interface pointer.
+ //
+ if (OriginalFilePath != NULL) {
+ Image->LoadedImageDevicePath = DuplicateDevicePath (OriginalFilePath);
+ }
+
+ //
+ // Install Loaded Image Device Path Protocol onto the image handle of a PE/COFE image
+ //
+ Status = CoreInstallProtocolInterface (
+ &Image->Handle,
+ &gEfiLoadedImageDevicePathProtocolGuid,
+ EFI_NATIVE_INTERFACE,
+ Image->LoadedImageDevicePath
+ );
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ //
+ // Install HII Package List Protocol onto the image handle
+ //
+ if (Image->ImageContext.HiiResourceData != 0) {
+ Status = CoreInstallProtocolInterface (
+ &Image->Handle,
+ &gEfiHiiPackageListProtocolGuid,
+ EFI_NATIVE_INTERFACE,
+ (VOID *)(UINTN)Image->ImageContext.HiiResourceData
+ );
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+ }
+
+ ProtectUefiImage (&Image->Info, Image->LoadedImageDevicePath);
+
+ //
+ // Success. Return the image handle
+ //
+ *ImageHandle = Image->Handle;
+
+Done:
+ //
+ // All done accessing the source file
+ // If we allocated the Source buffer, free it
+ //
+ if (FHand.FreeBuffer) {
+ CoreFreePool (FHand.Source);
+ }
+
+ if (OriginalFilePath != InputFilePath) {
+ CoreFreePool (OriginalFilePath);
+ }
+
+ //
+ // There was an error. If there's an Image structure, free it
+ //
+ if (EFI_ERROR (Status)) {
+ if (Image != NULL) {
+ CoreUnloadAndCloseImage (Image, (BOOLEAN)(DstBuffer == 0));
+ Image = NULL;
+ }
+ } else if (EFI_ERROR (SecurityStatus)) {
+ Status = SecurityStatus;
+ }
+
+ //
+ // Track the return status from LoadImage.
+ //
+ if (Image != NULL) {
+ Image->LoadImageStatus = Status;
+ }
+
+ return Status;
+}
+
+/**
+ Loads an EFI image into memory and returns a handle to the image.
+
+ @param BootPolicy If TRUE, indicates that the request originates
+ from the boot manager, and that the boot
+ manager is attempting to load FilePath as a
+ boot selection.
+ @param ParentImageHandle The caller's image handle.
+ @param FilePath The specific file path from which the image is
+ loaded.
+ @param SourceBuffer If not NULL, a pointer to the memory location
+ containing a copy of the image to be loaded.
+ @param SourceSize The size in bytes of SourceBuffer.
+ @param ImageHandle Pointer to the returned image handle that is
+ created when the image is successfully loaded.
+
+ @retval EFI_SUCCESS The image was loaded into memory.
+ @retval EFI_NOT_FOUND The FilePath was not found.
+ @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
+ @retval EFI_UNSUPPORTED The image type is not supported, or the device
+ path cannot be parsed to locate the proper
+ protocol for loading the file.
+ @retval EFI_OUT_OF_RESOURCES Image was not loaded due to insufficient
+ resources.
+ @retval EFI_LOAD_ERROR Image was not loaded because the image format was corrupt or not
+ understood.
+ @retval EFI_DEVICE_ERROR Image was not loaded because the device returned a read error.
+ @retval EFI_ACCESS_DENIED Image was not loaded because the platform policy prohibits the
+ image from being loaded. NULL is returned in *ImageHandle.
+ @retval EFI_SECURITY_VIOLATION Image was loaded and an ImageHandle was created with a
+ valid EFI_LOADED_IMAGE_PROTOCOL. However, the current
+ platform policy specifies that the image should not be started.
+
+**/
+EFI_STATUS
+EFIAPI
+CoreLoadImage (
+ IN BOOLEAN BootPolicy,
+ IN EFI_HANDLE ParentImageHandle,
+ IN EFI_DEVICE_PATH_PROTOCOL *FilePath,
+ IN VOID *SourceBuffer OPTIONAL,
+ IN UINTN SourceSize,
+ OUT EFI_HANDLE *ImageHandle
+ )
+{
+ EFI_STATUS Status;
+ EFI_HANDLE Handle;
+
+ PERF_LOAD_IMAGE_BEGIN (NULL);
+
+ Status = CoreLoadImageCommon (
+ BootPolicy,
+ ParentImageHandle,
+ FilePath,
+ SourceBuffer,
+ SourceSize,
+ (EFI_PHYSICAL_ADDRESS)(UINTN)NULL,
+ NULL,
+ ImageHandle,
+ NULL,
+ EFI_LOAD_PE_IMAGE_ATTRIBUTE_RUNTIME_REGISTRATION | EFI_LOAD_PE_IMAGE_ATTRIBUTE_DEBUG_IMAGE_INFO_TABLE_REGISTRATION
+ );
+
+ Handle = NULL;
+ if (!EFI_ERROR (Status)) {
+ //
+ // ImageHandle will be valid only Status is success.
+ //
+ Handle = *ImageHandle;
+ }
+
+ PERF_LOAD_IMAGE_END (Handle);
+
+ return Status;
+}
+
+/**
+ Transfer control to a loaded image's entry point.
+
+ @param ImageHandle Handle of image to be started.
+ @param ExitDataSize Pointer of the size to ExitData
+ @param ExitData Pointer to a pointer to a data buffer that
+ includes a Null-terminated string,
+ optionally followed by additional binary data.
+ The string is a description that the caller may
+ use to further indicate the reason for the
+ image's exit.
+
+ @retval EFI_INVALID_PARAMETER Invalid parameter
+ @retval EFI_OUT_OF_RESOURCES No enough buffer to allocate
+ @retval EFI_SECURITY_VIOLATION The current platform policy specifies that the image should not be started.
+ @retval EFI_SUCCESS Successfully transfer control to the image's
+ entry point.
+
+**/
+EFI_STATUS
+EFIAPI
+CoreStartImage (
+ IN EFI_HANDLE ImageHandle,
+ OUT UINTN *ExitDataSize,
+ OUT CHAR16 **ExitData OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+ LOADED_IMAGE_PRIVATE_DATA *Image;
+ LOADED_IMAGE_PRIVATE_DATA *LastImage;
+ UINT64 HandleDatabaseKey;
+ UINTN SetJumpFlag;
+ EFI_HANDLE Handle;
+
+ Handle = ImageHandle;
+
+ Image = CoreLoadedImageInfo (ImageHandle);
+ if ((Image == NULL) || Image->Started) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (EFI_ERROR (Image->LoadImageStatus)) {
+ return Image->LoadImageStatus;
+ }
+
+ //
+ // The image to be started must have the machine type supported by DxeCore.
+ //
+ if (!EFI_IMAGE_MACHINE_TYPE_SUPPORTED (Image->Machine) &&
+ (Image->PeCoffEmu == NULL))
+ {
+ //
+ // Do not ASSERT here, because image might be loaded via EFI_IMAGE_MACHINE_CROSS_TYPE_SUPPORTED
+ // But it can not be started.
+ //
+ DEBUG ((DEBUG_ERROR, "Image type %s can't be started ", GetMachineTypeName (Image->Machine)));
+ DEBUG ((DEBUG_ERROR, "on %s UEFI system.\n", GetMachineTypeName (mDxeCoreImageMachineType)));
+ return EFI_UNSUPPORTED;
+ }
+
+ if (Image->PeCoffEmu != NULL) {
+ Status = Image->PeCoffEmu->RegisterImage (
+ Image->PeCoffEmu,
+ Image->ImageBasePage,
+ EFI_PAGES_TO_SIZE (Image->NumberOfPages),
+ &Image->EntryPoint
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((
+ DEBUG_LOAD | DEBUG_ERROR,
+ "CoreLoadPeImage: Failed to register foreign image with emulator - %r\n",
+ Status
+ ));
+ return Status;
+ }
+ }
+
+ PERF_START_IMAGE_BEGIN (Handle);
+
+ //
+ // Push the current start image context, and
+ // link the current image to the head. This is the
+ // only image that can call Exit()
+ //
+ HandleDatabaseKey = CoreGetHandleDatabaseKey ();
+ LastImage = mCurrentImage;
+ mCurrentImage = Image;
+ Image->Tpl = gEfiCurrentTpl;
+
+ //
+ // Set long jump for Exit() support
+ // JumpContext must be aligned on a CPU specific boundary.
+ // Overallocate the buffer and force the required alignment
+ //
+ Image->JumpBuffer = AllocatePool (sizeof (BASE_LIBRARY_JUMP_BUFFER) + BASE_LIBRARY_JUMP_BUFFER_ALIGNMENT);
+ if (Image->JumpBuffer == NULL) {
+ //
+ // Image may be unloaded after return with failure,
+ // then ImageHandle may be invalid, so use NULL handle to record perf log.
+ //
+ PERF_START_IMAGE_END (NULL);
+
+ //
+ // Pop the current start image context
+ //
+ mCurrentImage = LastImage;
+
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ Image->JumpContext = ALIGN_POINTER (Image->JumpBuffer, BASE_LIBRARY_JUMP_BUFFER_ALIGNMENT);
+
+ SetJumpFlag = SetJump (Image->JumpContext);
+ //
+ // The initial call to SetJump() must always return 0.
+ // Subsequent calls to LongJump() cause a non-zero value to be returned by SetJump().
+ //
+ if (SetJumpFlag == 0) {
+ RegisterMemoryProfileImage (Image, (Image->ImageContext.ImageType == EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION ? EFI_FV_FILETYPE_APPLICATION : EFI_FV_FILETYPE_DRIVER));
+ //
+ // Call the image's entry point
+ //
+ Image->Started = TRUE;
+ Image->Status = Image->EntryPoint (ImageHandle, Image->Info.SystemTable);
+
+ //
+ // Add some debug information if the image returned with error.
+ // This make the user aware and check if the driver image have already released
+ // all the resource in this situation.
+ //
+ DEBUG_CODE_BEGIN ();
+ if (EFI_ERROR (Image->Status)) {
+ DEBUG ((DEBUG_ERROR, "Error: Image at %11p start failed: %r\n", Image->Info.ImageBase, Image->Status));
+ }
+
+ DEBUG_CODE_END ();
+
+ //
+ // If the image returns, exit it through Exit()
+ //
+ CoreExit (ImageHandle, Image->Status, 0, NULL);
+ }
+
+ //
+ // Image has completed. Verify the tpl is the same
+ //
+ ASSERT (Image->Tpl == gEfiCurrentTpl);
+ CoreRestoreTpl (Image->Tpl);
+
+ CoreFreePool (Image->JumpBuffer);
+
+ //
+ // Pop the current start image context
+ //
+ mCurrentImage = LastImage;
+
+ //
+ // UEFI Specification - StartImage() - EFI 1.10 Extension
+ // To maintain compatibility with UEFI drivers that are written to the EFI
+ // 1.02 Specification, StartImage() must monitor the handle database before
+ // and after each image is started. If any handles are created or modified
+ // when an image is started, then EFI_BOOT_SERVICES.ConnectController() must
+ // be called with the Recursive parameter set to TRUE for each of the newly
+ // created or modified handles before StartImage() returns.
+ //
+ if (Image->Type != EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION) {
+ CoreConnectHandlesByKey (HandleDatabaseKey);
+ }
+
+ //
+ // Handle the image's returned ExitData
+ //
+ DEBUG_CODE_BEGIN ();
+ if ((Image->ExitDataSize != 0) || (Image->ExitData != NULL)) {
+ DEBUG ((DEBUG_LOAD, "StartImage: ExitDataSize %d, ExitData %p", (UINT32)Image->ExitDataSize, Image->ExitData));
+ if (Image->ExitData != NULL) {
+ DEBUG ((DEBUG_LOAD, " (%s)", Image->ExitData));
+ }
+
+ DEBUG ((DEBUG_LOAD, "\n"));
+ }
+
+ DEBUG_CODE_END ();
+
+ //
+ // Return the exit data to the caller
+ //
+ if ((ExitData != NULL) && (ExitDataSize != NULL)) {
+ *ExitDataSize = Image->ExitDataSize;
+ *ExitData = Image->ExitData;
+ } else {
+ //
+ // Caller doesn't want the exit data, free it
+ //
+ CoreFreePool (Image->ExitData);
+ Image->ExitData = NULL;
+ }
+
+ //
+ // Save the Status because Image will get destroyed if it is unloaded.
+ //
+ Status = Image->Status;
+
+ //
+ // If the image returned an error, or if the image is an application
+ // unload it
+ //
+ if (EFI_ERROR (Image->Status) || (Image->Type == EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION)) {
+ CoreUnloadAndCloseImage (Image, TRUE);
+ //
+ // ImageHandle may be invalid after the image is unloaded, so use NULL handle to record perf log.
+ //
+ Handle = NULL;
+ }
+
+ //
+ // Done
+ //
+ PERF_START_IMAGE_END (Handle);
+ return Status;
+}
+
+/**
+ Terminates the currently loaded EFI image and returns control to boot services.
+
+ @param ImageHandle Handle that identifies the image. This
+ parameter is passed to the image on entry.
+ @param Status The image's exit code.
+ @param ExitDataSize The size, in bytes, of ExitData. Ignored if
+ ExitStatus is EFI_SUCCESS.
+ @param ExitData Pointer to a data buffer that includes a
+ Null-terminated Unicode string, optionally
+ followed by additional binary data. The string
+ is a description that the caller may use to
+ further indicate the reason for the image's
+ exit.
+
+ @retval EFI_INVALID_PARAMETER Image handle is NULL or it is not current
+ image.
+ @retval EFI_SUCCESS Successfully terminates the currently loaded
+ EFI image.
+ @retval EFI_ACCESS_DENIED Should never reach there.
+ @retval EFI_OUT_OF_RESOURCES Could not allocate pool
+
+**/
+EFI_STATUS
+EFIAPI
+CoreExit (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_STATUS Status,
+ IN UINTN ExitDataSize,
+ IN CHAR16 *ExitData OPTIONAL
+ )
+{
+ LOADED_IMAGE_PRIVATE_DATA *Image;
+ EFI_TPL OldTpl;
+
+ //
+ // Prevent possible reentrance to this function
+ // for the same ImageHandle
+ //
+ OldTpl = CoreRaiseTpl (TPL_NOTIFY);
+
+ Image = CoreLoadedImageInfo (ImageHandle);
+ if (Image == NULL) {
+ Status = EFI_INVALID_PARAMETER;
+ goto Done;
+ }
+
+ if (!Image->Started) {
+ //
+ // The image has not been started so just free its resources
+ //
+ CoreUnloadAndCloseImage (Image, TRUE);
+ Status = EFI_SUCCESS;
+ goto Done;
+ }
+
+ //
+ // Image has been started, verify this image can exit
+ //
+ if (Image != mCurrentImage) {
+ DEBUG ((DEBUG_LOAD|DEBUG_ERROR, "Exit: Image is not exitable image\n"));
+ Status = EFI_INVALID_PARAMETER;
+ goto Done;
+ }
+
+ //
+ // Set status
+ //
+ Image->Status = Status;
+
+ //
+ // If there's ExitData info, move it
+ //
+ if (ExitData != NULL) {
+ Image->ExitDataSize = ExitDataSize;
+ Image->ExitData = AllocatePool (Image->ExitDataSize);
+ if (Image->ExitData == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Done;
+ }
+
+ CopyMem (Image->ExitData, ExitData, Image->ExitDataSize);
+ }
+
+ CoreRestoreTpl (OldTpl);
+ //
+ // return to StartImage
+ //
+ LongJump (Image->JumpContext, (UINTN)-1);
+
+ //
+ // If we return from LongJump, then it is an error
+ //
+ ASSERT (FALSE);
+ Status = EFI_ACCESS_DENIED;
+Done:
+ CoreRestoreTpl (OldTpl);
+ return Status;
+}
+
+/**
+ Unloads an image.
+
+ @param ImageHandle Handle that identifies the image to be
+ unloaded.
+
+ @retval EFI_SUCCESS The image has been unloaded.
+ @retval EFI_UNSUPPORTED The image has been started, and does not support
+ unload.
+ @retval EFI_INVALID_PARAMPETER ImageHandle is not a valid image handle.
+
+**/
+EFI_STATUS
+EFIAPI
+CoreUnloadImage (
+ IN EFI_HANDLE ImageHandle
+ )
+{
+ EFI_STATUS Status;
+ LOADED_IMAGE_PRIVATE_DATA *Image;
+
+ Image = CoreLoadedImageInfo (ImageHandle);
+ if (Image == NULL ) {
+ //
+ // The image handle is not valid
+ //
+ Status = EFI_INVALID_PARAMETER;
+ goto Done;
+ }
+
+ if (Image->Started) {
+ //
+ // The image has been started, request it to unload.
+ //
+ Status = EFI_UNSUPPORTED;
+ if (Image->Info.Unload != NULL) {
+ Status = Image->Info.Unload (ImageHandle);
+ }
+ } else {
+ //
+ // This Image hasn't been started, thus it can be unloaded
+ //
+ Status = EFI_SUCCESS;
+ }
+
+ if (!EFI_ERROR (Status)) {
+ //
+ // if the Image was not started or Unloaded O.K. then clean up
+ //
+ CoreUnloadAndCloseImage (Image, TRUE);
+ }
+
+Done:
+ return Status;
+}
diff --git a/MdeModulePkg/Core/Dxe/Image/Image.h b/MdeModulePkg/Core/Dxe/Image/Image.h
index 7e4175e562..60cabe2ea9 100644
--- a/MdeModulePkg/Core/Dxe/Image/Image.h
+++ b/MdeModulePkg/Core/Dxe/Image/Image.h
@@ -1,23 +1,23 @@
-/** @file
- Data structure and functions to load and unload PeImage.
-
-Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR>
-SPDX-License-Identifier: BSD-2-Clause-Patent
-
-**/
-
-#ifndef _IMAGE_H_
-#define _IMAGE_H_
-
-//
-// Private Data Types
-//
-#define IMAGE_FILE_HANDLE_SIGNATURE SIGNATURE_32('i','m','g','f')
-typedef struct {
- UINTN Signature;
- BOOLEAN FreeBuffer;
- VOID *Source;
- UINTN SourceSize;
-} IMAGE_FILE_HANDLE;
-
-#endif
+/** @file
+ Data structure and functions to load and unload PeImage.
+
+Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _IMAGE_H_
+#define _IMAGE_H_
+
+//
+// Private Data Types
+//
+#define IMAGE_FILE_HANDLE_SIGNATURE SIGNATURE_32('i','m','g','f')
+typedef struct {
+ UINTN Signature;
+ BOOLEAN FreeBuffer;
+ VOID *Source;
+ UINTN SourceSize;
+} IMAGE_FILE_HANDLE;
+
+#endif
diff --git a/MdeModulePkg/Core/Dxe/Library/Library.c b/MdeModulePkg/Core/Dxe/Library/Library.c
index 63cef1daca..6162744281 100644
--- a/MdeModulePkg/Core/Dxe/Library/Library.c
+++ b/MdeModulePkg/Core/Dxe/Library/Library.c
@@ -1,94 +1,94 @@
-/** @file
- DXE Core library services.
-
-Copyright (c) 2006 - 2008, Intel Corporation. All rights reserved.<BR>
-SPDX-License-Identifier: BSD-2-Clause-Patent
-
-**/
-
-#include "DxeMain.h"
-
-//
-// Lock Stuff
-//
-
-/**
- Initialize a basic mutual exclusion lock. Each lock
- provides mutual exclusion access at it's task priority
- level. Since there is no-premption (at any TPL) or
- multiprocessor support, acquiring the lock only consists
- of raising to the locks TPL.
-
- @param Lock The EFI_LOCK structure to initialize
-
- @retval EFI_SUCCESS Lock Owned.
- @retval EFI_ACCESS_DENIED Reentrant Lock Acquisition, Lock not Owned.
-
-**/
-EFI_STATUS
-CoreAcquireLockOrFail (
- IN EFI_LOCK *Lock
- )
-{
- ASSERT (Lock != NULL);
- ASSERT (Lock->Lock != EfiLockUninitialized);
-
- if (Lock->Lock == EfiLockAcquired) {
- //
- // Lock is already owned, so bail out
- //
- return EFI_ACCESS_DENIED;
- }
-
- Lock->OwnerTpl = CoreRaiseTpl (Lock->Tpl);
-
- Lock->Lock = EfiLockAcquired;
- return EFI_SUCCESS;
-}
-
-/**
- Raising to the task priority level of the mutual exclusion
- lock, and then acquires ownership of the lock.
-
- @param Lock The lock to acquire
-
- @return Lock owned
-
-**/
-VOID
-CoreAcquireLock (
- IN EFI_LOCK *Lock
- )
-{
- ASSERT (Lock != NULL);
- ASSERT (Lock->Lock == EfiLockReleased);
-
- Lock->OwnerTpl = CoreRaiseTpl (Lock->Tpl);
- Lock->Lock = EfiLockAcquired;
-}
-
-/**
- Releases ownership of the mutual exclusion lock, and
- restores the previous task priority level.
-
- @param Lock The lock to release
-
- @return Lock unowned
-
-**/
-VOID
-CoreReleaseLock (
- IN EFI_LOCK *Lock
- )
-{
- EFI_TPL Tpl;
-
- ASSERT (Lock != NULL);
- ASSERT (Lock->Lock == EfiLockAcquired);
-
- Tpl = Lock->OwnerTpl;
-
- Lock->Lock = EfiLockReleased;
-
- CoreRestoreTpl (Tpl);
-}
+/** @file
+ DXE Core library services.
+
+Copyright (c) 2006 - 2008, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "DxeMain.h"
+
+//
+// Lock Stuff
+//
+
+/**
+ Initialize a basic mutual exclusion lock. Each lock
+ provides mutual exclusion access at it's task priority
+ level. Since there is no-premption (at any TPL) or
+ multiprocessor support, acquiring the lock only consists
+ of raising to the locks TPL.
+
+ @param Lock The EFI_LOCK structure to initialize
+
+ @retval EFI_SUCCESS Lock Owned.
+ @retval EFI_ACCESS_DENIED Reentrant Lock Acquisition, Lock not Owned.
+
+**/
+EFI_STATUS
+CoreAcquireLockOrFail (
+ IN EFI_LOCK *Lock
+ )
+{
+ ASSERT (Lock != NULL);
+ ASSERT (Lock->Lock != EfiLockUninitialized);
+
+ if (Lock->Lock == EfiLockAcquired) {
+ //
+ // Lock is already owned, so bail out
+ //
+ return EFI_ACCESS_DENIED;
+ }
+
+ Lock->OwnerTpl = CoreRaiseTpl (Lock->Tpl);
+
+ Lock->Lock = EfiLockAcquired;
+ return EFI_SUCCESS;
+}
+
+/**
+ Raising to the task priority level of the mutual exclusion
+ lock, and then acquires ownership of the lock.
+
+ @param Lock The lock to acquire
+
+ @return Lock owned
+
+**/
+VOID
+CoreAcquireLock (
+ IN EFI_LOCK *Lock
+ )
+{
+ ASSERT (Lock != NULL);
+ ASSERT (Lock->Lock == EfiLockReleased);
+
+ Lock->OwnerTpl = CoreRaiseTpl (Lock->Tpl);
+ Lock->Lock = EfiLockAcquired;
+}
+
+/**
+ Releases ownership of the mutual exclusion lock, and
+ restores the previous task priority level.
+
+ @param Lock The lock to release
+
+ @return Lock unowned
+
+**/
+VOID
+CoreReleaseLock (
+ IN EFI_LOCK *Lock
+ )
+{
+ EFI_TPL Tpl;
+
+ ASSERT (Lock != NULL);
+ ASSERT (Lock->Lock == EfiLockAcquired);
+
+ Tpl = Lock->OwnerTpl;
+
+ Lock->Lock = EfiLockReleased;
+
+ CoreRestoreTpl (Tpl);
+}
diff --git a/MdeModulePkg/Core/Dxe/Mem/HeapGuard.c b/MdeModulePkg/Core/Dxe/Mem/HeapGuard.c
index 0c0ca61872..0f5cfaeff1 100644
--- a/MdeModulePkg/Core/Dxe/Mem/HeapGuard.c
+++ b/MdeModulePkg/Core/Dxe/Mem/HeapGuard.c
@@ -1,1755 +1,1755 @@
-/** @file
- UEFI Heap Guard functions.
-
-Copyright (c) 2017-2018, Intel Corporation. All rights reserved.<BR>
-SPDX-License-Identifier: BSD-2-Clause-Patent
-
-**/
-
-#include "DxeMain.h"
-#include "Imem.h"
-#include "HeapGuard.h"
-
-//
-// Global to avoid infinite reentrance of memory allocation when updating
-// page table attributes, which may need allocate pages for new PDE/PTE.
-//
-GLOBAL_REMOVE_IF_UNREFERENCED BOOLEAN mOnGuarding = FALSE;
-
-//
-// Pointer to table tracking the Guarded memory with bitmap, in which '1'
-// is used to indicate memory guarded. '0' might be free memory or Guard
-// page itself, depending on status of memory adjacent to it.
-//
-GLOBAL_REMOVE_IF_UNREFERENCED UINT64 mGuardedMemoryMap = 0;
-
-//
-// Current depth level of map table pointed by mGuardedMemoryMap.
-// mMapLevel must be initialized at least by 1. It will be automatically
-// updated according to the address of memory just tracked.
-//
-GLOBAL_REMOVE_IF_UNREFERENCED UINTN mMapLevel = 1;
-
-//
-// Shift and mask for each level of map table
-//
-GLOBAL_REMOVE_IF_UNREFERENCED UINTN mLevelShift[GUARDED_HEAP_MAP_TABLE_DEPTH]
- = GUARDED_HEAP_MAP_TABLE_DEPTH_SHIFTS;
-GLOBAL_REMOVE_IF_UNREFERENCED UINTN mLevelMask[GUARDED_HEAP_MAP_TABLE_DEPTH]
- = GUARDED_HEAP_MAP_TABLE_DEPTH_MASKS;
-
-//
-// Used for promoting freed but not used pages.
-//
-GLOBAL_REMOVE_IF_UNREFERENCED EFI_PHYSICAL_ADDRESS mLastPromotedPage = BASE_4GB;
-
-/**
- Set corresponding bits in bitmap table to 1 according to the address.
-
- @param[in] Address Start address to set for.
- @param[in] BitNumber Number of bits to set.
- @param[in] BitMap Pointer to bitmap which covers the Address.
-
- @return VOID.
-**/
-STATIC
-VOID
-SetBits (
- IN EFI_PHYSICAL_ADDRESS Address,
- IN UINTN BitNumber,
- IN UINT64 *BitMap
- )
-{
- UINTN Lsbs;
- UINTN Qwords;
- UINTN Msbs;
- UINTN StartBit;
- UINTN EndBit;
-
- StartBit = (UINTN)GUARDED_HEAP_MAP_ENTRY_BIT_INDEX (Address);
- EndBit = (StartBit + BitNumber - 1) % GUARDED_HEAP_MAP_ENTRY_BITS;
-
- if ((StartBit + BitNumber) >= GUARDED_HEAP_MAP_ENTRY_BITS) {
- Msbs = (GUARDED_HEAP_MAP_ENTRY_BITS - StartBit) %
- GUARDED_HEAP_MAP_ENTRY_BITS;
- Lsbs = (EndBit + 1) % GUARDED_HEAP_MAP_ENTRY_BITS;
- Qwords = (BitNumber - Msbs) / GUARDED_HEAP_MAP_ENTRY_BITS;
- } else {
- Msbs = BitNumber;
- Lsbs = 0;
- Qwords = 0;
- }
-
- if (Msbs > 0) {
- *BitMap |= LShiftU64 (LShiftU64 (1, Msbs) - 1, StartBit);
- BitMap += 1;
- }
-
- if (Qwords > 0) {
- SetMem64 (
- (VOID *)BitMap,
- Qwords * GUARDED_HEAP_MAP_ENTRY_BYTES,
- (UINT64)-1
- );
- BitMap += Qwords;
- }
-
- if (Lsbs > 0) {
- *BitMap |= (LShiftU64 (1, Lsbs) - 1);
- }
-}
-
-/**
- Set corresponding bits in bitmap table to 0 according to the address.
-
- @param[in] Address Start address to set for.
- @param[in] BitNumber Number of bits to set.
- @param[in] BitMap Pointer to bitmap which covers the Address.
-
- @return VOID.
-**/
-STATIC
-VOID
-ClearBits (
- IN EFI_PHYSICAL_ADDRESS Address,
- IN UINTN BitNumber,
- IN UINT64 *BitMap
- )
-{
- UINTN Lsbs;
- UINTN Qwords;
- UINTN Msbs;
- UINTN StartBit;
- UINTN EndBit;
-
- StartBit = (UINTN)GUARDED_HEAP_MAP_ENTRY_BIT_INDEX (Address);
- EndBit = (StartBit + BitNumber - 1) % GUARDED_HEAP_MAP_ENTRY_BITS;
-
- if ((StartBit + BitNumber) >= GUARDED_HEAP_MAP_ENTRY_BITS) {
- Msbs = (GUARDED_HEAP_MAP_ENTRY_BITS - StartBit) %
- GUARDED_HEAP_MAP_ENTRY_BITS;
- Lsbs = (EndBit + 1) % GUARDED_HEAP_MAP_ENTRY_BITS;
- Qwords = (BitNumber - Msbs) / GUARDED_HEAP_MAP_ENTRY_BITS;
- } else {
- Msbs = BitNumber;
- Lsbs = 0;
- Qwords = 0;
- }
-
- if (Msbs > 0) {
- *BitMap &= ~LShiftU64 (LShiftU64 (1, Msbs) - 1, StartBit);
- BitMap += 1;
- }
-
- if (Qwords > 0) {
- SetMem64 ((VOID *)BitMap, Qwords * GUARDED_HEAP_MAP_ENTRY_BYTES, 0);
- BitMap += Qwords;
- }
-
- if (Lsbs > 0) {
- *BitMap &= ~(LShiftU64 (1, Lsbs) - 1);
- }
-}
-
-/**
- Get corresponding bits in bitmap table according to the address.
-
- The value of bit 0 corresponds to the status of memory at given Address.
- No more than 64 bits can be retrieved in one call.
-
- @param[in] Address Start address to retrieve bits for.
- @param[in] BitNumber Number of bits to get.
- @param[in] BitMap Pointer to bitmap which covers the Address.
-
- @return An integer containing the bits information.
-**/
-STATIC
-UINT64
-GetBits (
- IN EFI_PHYSICAL_ADDRESS Address,
- IN UINTN BitNumber,
- IN UINT64 *BitMap
- )
-{
- UINTN StartBit;
- UINTN EndBit;
- UINTN Lsbs;
- UINTN Msbs;
- UINT64 Result;
-
- ASSERT (BitNumber <= GUARDED_HEAP_MAP_ENTRY_BITS);
-
- StartBit = (UINTN)GUARDED_HEAP_MAP_ENTRY_BIT_INDEX (Address);
- EndBit = (StartBit + BitNumber - 1) % GUARDED_HEAP_MAP_ENTRY_BITS;
-
- if ((StartBit + BitNumber) > GUARDED_HEAP_MAP_ENTRY_BITS) {
- Msbs = GUARDED_HEAP_MAP_ENTRY_BITS - StartBit;
- Lsbs = (EndBit + 1) % GUARDED_HEAP_MAP_ENTRY_BITS;
- } else {
- Msbs = BitNumber;
- Lsbs = 0;
- }
-
- if ((StartBit == 0) && (BitNumber == GUARDED_HEAP_MAP_ENTRY_BITS)) {
- Result = *BitMap;
- } else {
- Result = RShiftU64 ((*BitMap), StartBit) & (LShiftU64 (1, Msbs) - 1);
- if (Lsbs > 0) {
- BitMap += 1;
- Result |= LShiftU64 ((*BitMap) & (LShiftU64 (1, Lsbs) - 1), Msbs);
- }
- }
-
- return Result;
-}
-
-/**
- Locate the pointer of bitmap from the guarded memory bitmap tables, which
- covers the given Address.
-
- @param[in] Address Start address to search the bitmap for.
- @param[in] AllocMapUnit Flag to indicate memory allocation for the table.
- @param[out] BitMap Pointer to bitmap which covers the Address.
-
- @return The bit number from given Address to the end of current map table.
-**/
-UINTN
-FindGuardedMemoryMap (
- IN EFI_PHYSICAL_ADDRESS Address,
- IN BOOLEAN AllocMapUnit,
- OUT UINT64 **BitMap
- )
-{
- UINTN Level;
- UINT64 *GuardMap;
- UINT64 MapMemory;
- UINTN Index;
- UINTN Size;
- UINTN BitsToUnitEnd;
- EFI_STATUS Status;
-
- MapMemory = 0;
-
- //
- // Adjust current map table depth according to the address to access
- //
- while (AllocMapUnit &&
- mMapLevel < GUARDED_HEAP_MAP_TABLE_DEPTH &&
- RShiftU64 (
- Address,
- mLevelShift[GUARDED_HEAP_MAP_TABLE_DEPTH - mMapLevel - 1]
- ) != 0)
- {
- if (mGuardedMemoryMap != 0) {
- Size = (mLevelMask[GUARDED_HEAP_MAP_TABLE_DEPTH - mMapLevel - 1] + 1)
- * GUARDED_HEAP_MAP_ENTRY_BYTES;
- Status = CoreInternalAllocatePages (
- AllocateAnyPages,
- EfiBootServicesData,
- EFI_SIZE_TO_PAGES (Size),
- &MapMemory,
- FALSE
- );
- ASSERT_EFI_ERROR (Status);
- ASSERT (MapMemory != 0);
-
- SetMem ((VOID *)(UINTN)MapMemory, Size, 0);
-
- *(UINT64 *)(UINTN)MapMemory = mGuardedMemoryMap;
- mGuardedMemoryMap = MapMemory;
- }
-
- mMapLevel++;
- }
-
- GuardMap = &mGuardedMemoryMap;
- for (Level = GUARDED_HEAP_MAP_TABLE_DEPTH - mMapLevel;
- Level < GUARDED_HEAP_MAP_TABLE_DEPTH;
- ++Level)
- {
- if (*GuardMap == 0) {
- if (!AllocMapUnit) {
- GuardMap = NULL;
- break;
- }
-
- Size = (mLevelMask[Level] + 1) * GUARDED_HEAP_MAP_ENTRY_BYTES;
- Status = CoreInternalAllocatePages (
- AllocateAnyPages,
- EfiBootServicesData,
- EFI_SIZE_TO_PAGES (Size),
- &MapMemory,
- FALSE
- );
- ASSERT_EFI_ERROR (Status);
- ASSERT (MapMemory != 0);
-
- SetMem ((VOID *)(UINTN)MapMemory, Size, 0);
- *GuardMap = MapMemory;
- }
-
- Index = (UINTN)RShiftU64 (Address, mLevelShift[Level]);
- Index &= mLevelMask[Level];
- GuardMap = (UINT64 *)(UINTN)((*GuardMap) + Index * sizeof (UINT64));
- }
-
- BitsToUnitEnd = GUARDED_HEAP_MAP_BITS - GUARDED_HEAP_MAP_BIT_INDEX (Address);
- *BitMap = GuardMap;
-
- return BitsToUnitEnd;
-}
-
-/**
- Set corresponding bits in bitmap table to 1 according to given memory range.
-
- @param[in] Address Memory address to guard from.
- @param[in] NumberOfPages Number of pages to guard.
-
- @return VOID.
-**/
-VOID
-EFIAPI
-SetGuardedMemoryBits (
- IN EFI_PHYSICAL_ADDRESS Address,
- IN UINTN NumberOfPages
- )
-{
- UINT64 *BitMap;
- UINTN Bits;
- UINTN BitsToUnitEnd;
-
- while (NumberOfPages > 0) {
- BitsToUnitEnd = FindGuardedMemoryMap (Address, TRUE, &BitMap);
- ASSERT (BitMap != NULL);
-
- if (NumberOfPages > BitsToUnitEnd) {
- // Cross map unit
- Bits = BitsToUnitEnd;
- } else {
- Bits = NumberOfPages;
- }
-
- SetBits (Address, Bits, BitMap);
-
- NumberOfPages -= Bits;
- Address += EFI_PAGES_TO_SIZE (Bits);
- }
-}
-
-/**
- Clear corresponding bits in bitmap table according to given memory range.
-
- @param[in] Address Memory address to unset from.
- @param[in] NumberOfPages Number of pages to unset guard.
-
- @return VOID.
-**/
-VOID
-EFIAPI
-ClearGuardedMemoryBits (
- IN EFI_PHYSICAL_ADDRESS Address,
- IN UINTN NumberOfPages
- )
-{
- UINT64 *BitMap;
- UINTN Bits;
- UINTN BitsToUnitEnd;
-
- while (NumberOfPages > 0) {
- BitsToUnitEnd = FindGuardedMemoryMap (Address, TRUE, &BitMap);
- ASSERT (BitMap != NULL);
-
- if (NumberOfPages > BitsToUnitEnd) {
- // Cross map unit
- Bits = BitsToUnitEnd;
- } else {
- Bits = NumberOfPages;
- }
-
- ClearBits (Address, Bits, BitMap);
-
- NumberOfPages -= Bits;
- Address += EFI_PAGES_TO_SIZE (Bits);
- }
-}
-
-/**
- Retrieve corresponding bits in bitmap table according to given memory range.
-
- @param[in] Address Memory address to retrieve from.
- @param[in] NumberOfPages Number of pages to retrieve.
-
- @return An integer containing the guarded memory bitmap.
-**/
-UINT64
-GetGuardedMemoryBits (
- IN EFI_PHYSICAL_ADDRESS Address,
- IN UINTN NumberOfPages
- )
-{
- UINT64 *BitMap;
- UINTN Bits;
- UINT64 Result;
- UINTN Shift;
- UINTN BitsToUnitEnd;
-
- ASSERT (NumberOfPages <= GUARDED_HEAP_MAP_ENTRY_BITS);
-
- Result = 0;
- Shift = 0;
- while (NumberOfPages > 0) {
- BitsToUnitEnd = FindGuardedMemoryMap (Address, FALSE, &BitMap);
-
- if (NumberOfPages > BitsToUnitEnd) {
- // Cross map unit
- Bits = BitsToUnitEnd;
- } else {
- Bits = NumberOfPages;
- }
-
- if (BitMap != NULL) {
- Result |= LShiftU64 (GetBits (Address, Bits, BitMap), Shift);
- }
-
- Shift += Bits;
- NumberOfPages -= Bits;
- Address += EFI_PAGES_TO_SIZE (Bits);
- }
-
- return Result;
-}
-
-/**
- Get bit value in bitmap table for the given address.
-
- @param[in] Address The address to retrieve for.
-
- @return 1 or 0.
-**/
-UINTN
-EFIAPI
-GetGuardMapBit (
- IN EFI_PHYSICAL_ADDRESS Address
- )
-{
- UINT64 *GuardMap;
-
- FindGuardedMemoryMap (Address, FALSE, &GuardMap);
- if (GuardMap != NULL) {
- if (RShiftU64 (
- *GuardMap,
- GUARDED_HEAP_MAP_ENTRY_BIT_INDEX (Address)
- ) & 1)
- {
- return 1;
- }
- }
-
- return 0;
-}
-
-/**
- Check to see if the page at the given address is a Guard page or not.
-
- @param[in] Address The address to check for.
-
- @return TRUE The page at Address is a Guard page.
- @return FALSE The page at Address is not a Guard page.
-**/
-BOOLEAN
-EFIAPI
-IsGuardPage (
- IN EFI_PHYSICAL_ADDRESS Address
- )
-{
- UINT64 BitMap;
-
- //
- // There must be at least one guarded page before and/or after given
- // address if it's a Guard page. The bitmap pattern should be one of
- // 001, 100 and 101
- //
- BitMap = GetGuardedMemoryBits (Address - EFI_PAGE_SIZE, 3);
- return ((BitMap == BIT0) || (BitMap == BIT2) || (BitMap == (BIT2 | BIT0)));
-}
-
-/**
- Check to see if the page at the given address is guarded or not.
-
- @param[in] Address The address to check for.
-
- @return TRUE The page at Address is guarded.
- @return FALSE The page at Address is not guarded.
-**/
-BOOLEAN
-EFIAPI
-IsMemoryGuarded (
- IN EFI_PHYSICAL_ADDRESS Address
- )
-{
- return (GetGuardMapBit (Address) == 1);
-}
-
-/**
- Set the page at the given address to be a Guard page.
-
- This is done by changing the page table attribute to be NOT PRSENT.
-
- @param[in] BaseAddress Page address to Guard at
-
- @return VOID
-**/
-VOID
-EFIAPI
-SetGuardPage (
- IN EFI_PHYSICAL_ADDRESS BaseAddress
- )
-{
- EFI_STATUS Status;
-
- if (gCpu == NULL) {
- return;
- }
-
- //
- // Set flag to make sure allocating memory without GUARD for page table
- // operation; otherwise infinite loops could be caused.
- //
- mOnGuarding = TRUE;
- //
- // Note: This might overwrite other attributes needed by other features,
- // such as NX memory protection.
- //
- Status = gCpu->SetMemoryAttributes (gCpu, BaseAddress, EFI_PAGE_SIZE, EFI_MEMORY_RP);
- ASSERT_EFI_ERROR (Status);
- mOnGuarding = FALSE;
-}
-
-/**
- Unset the Guard page at the given address to the normal memory.
-
- This is done by changing the page table attribute to be PRSENT.
-
- @param[in] BaseAddress Page address to Guard at.
-
- @return VOID.
-**/
-VOID
-EFIAPI
-UnsetGuardPage (
- IN EFI_PHYSICAL_ADDRESS BaseAddress
- )
-{
- UINT64 Attributes;
- EFI_STATUS Status;
-
- if (gCpu == NULL) {
- return;
- }
-
- //
- // Once the Guard page is unset, it will be freed back to memory pool. NX
- // memory protection must be restored for this page if NX is enabled for free
- // memory.
- //
- Attributes = 0;
- if ((PcdGet64 (PcdDxeNxMemoryProtectionPolicy) & (1 << EfiConventionalMemory)) != 0) {
- Attributes |= EFI_MEMORY_XP;
- }
-
- //
- // Set flag to make sure allocating memory without GUARD for page table
- // operation; otherwise infinite loops could be caused.
- //
- mOnGuarding = TRUE;
- //
- // Note: This might overwrite other attributes needed by other features,
- // such as memory protection (NX). Please make sure they are not enabled
- // at the same time.
- //
- Status = gCpu->SetMemoryAttributes (gCpu, BaseAddress, EFI_PAGE_SIZE, Attributes);
- ASSERT_EFI_ERROR (Status);
- mOnGuarding = FALSE;
-}
-
-/**
- Check to see if the memory at the given address should be guarded or not.
-
- @param[in] MemoryType Memory type to check.
- @param[in] AllocateType Allocation type to check.
- @param[in] PageOrPool Indicate a page allocation or pool allocation.
-
-
- @return TRUE The given type of memory should be guarded.
- @return FALSE The given type of memory should not be guarded.
-**/
-BOOLEAN
-IsMemoryTypeToGuard (
- IN EFI_MEMORY_TYPE MemoryType,
- IN EFI_ALLOCATE_TYPE AllocateType,
- IN UINT8 PageOrPool
- )
-{
- UINT64 TestBit;
- UINT64 ConfigBit;
-
- if (AllocateType == AllocateAddress) {
- return FALSE;
- }
-
- if ((PcdGet8 (PcdHeapGuardPropertyMask) & PageOrPool) == 0) {
- return FALSE;
- }
-
- if (PageOrPool == GUARD_HEAP_TYPE_POOL) {
- ConfigBit = PcdGet64 (PcdHeapGuardPoolType);
- } else if (PageOrPool == GUARD_HEAP_TYPE_PAGE) {
- ConfigBit = PcdGet64 (PcdHeapGuardPageType);
- } else {
- ConfigBit = (UINT64)-1;
- }
-
- if ((UINT32)MemoryType >= MEMORY_TYPE_OS_RESERVED_MIN) {
- TestBit = BIT63;
- } else if ((UINT32)MemoryType >= MEMORY_TYPE_OEM_RESERVED_MIN) {
- TestBit = BIT62;
- } else if (MemoryType < EfiMaxMemoryType) {
- TestBit = LShiftU64 (1, MemoryType);
- } else if (MemoryType == EfiMaxMemoryType) {
- TestBit = (UINT64)-1;
- } else {
- TestBit = 0;
- }
-
- return ((ConfigBit & TestBit) != 0);
-}
-
-/**
- Check to see if the pool at the given address should be guarded or not.
-
- @param[in] MemoryType Pool type to check.
-
-
- @return TRUE The given type of pool should be guarded.
- @return FALSE The given type of pool should not be guarded.
-**/
-BOOLEAN
-IsPoolTypeToGuard (
- IN EFI_MEMORY_TYPE MemoryType
- )
-{
- return IsMemoryTypeToGuard (
- MemoryType,
- AllocateAnyPages,
- GUARD_HEAP_TYPE_POOL
- );
-}
-
-/**
- Check to see if the page at the given address should be guarded or not.
-
- @param[in] MemoryType Page type to check.
- @param[in] AllocateType Allocation type to check.
-
- @return TRUE The given type of page should be guarded.
- @return FALSE The given type of page should not be guarded.
-**/
-BOOLEAN
-IsPageTypeToGuard (
- IN EFI_MEMORY_TYPE MemoryType,
- IN EFI_ALLOCATE_TYPE AllocateType
- )
-{
- return IsMemoryTypeToGuard (MemoryType, AllocateType, GUARD_HEAP_TYPE_PAGE);
-}
-
-/**
- Check to see if the heap guard is enabled for page and/or pool allocation.
-
- @param[in] GuardType Specify the sub-type(s) of Heap Guard.
-
- @return TRUE/FALSE.
-**/
-BOOLEAN
-IsHeapGuardEnabled (
- UINT8 GuardType
- )
-{
- return IsMemoryTypeToGuard (EfiMaxMemoryType, AllocateAnyPages, GuardType);
-}
-
-/**
- Set head Guard and tail Guard for the given memory range.
-
- @param[in] Memory Base address of memory to set guard for.
- @param[in] NumberOfPages Memory size in pages.
-
- @return VOID
-**/
-VOID
-SetGuardForMemory (
- IN EFI_PHYSICAL_ADDRESS Memory,
- IN UINTN NumberOfPages
- )
-{
- EFI_PHYSICAL_ADDRESS GuardPage;
-
- //
- // Set tail Guard
- //
- GuardPage = Memory + EFI_PAGES_TO_SIZE (NumberOfPages);
- if (!IsGuardPage (GuardPage)) {
- SetGuardPage (GuardPage);
- }
-
- // Set head Guard
- GuardPage = Memory - EFI_PAGES_TO_SIZE (1);
- if (!IsGuardPage (GuardPage)) {
- SetGuardPage (GuardPage);
- }
-
- //
- // Mark the memory range as Guarded
- //
- SetGuardedMemoryBits (Memory, NumberOfPages);
-}
-
-/**
- Unset head Guard and tail Guard for the given memory range.
-
- @param[in] Memory Base address of memory to unset guard for.
- @param[in] NumberOfPages Memory size in pages.
-
- @return VOID
-**/
-VOID
-UnsetGuardForMemory (
- IN EFI_PHYSICAL_ADDRESS Memory,
- IN UINTN NumberOfPages
- )
-{
- EFI_PHYSICAL_ADDRESS GuardPage;
- UINT64 GuardBitmap;
-
- if (NumberOfPages == 0) {
- return;
- }
-
- //
- // Head Guard must be one page before, if any.
- //
- // MSB-> 1 0 <-LSB
- // -------------------
- // Head Guard -> 0 1 -> Don't free Head Guard (shared Guard)
- // Head Guard -> 0 0 -> Free Head Guard either (not shared Guard)
- // 1 X -> Don't free first page (need a new Guard)
- // (it'll be turned into a Guard page later)
- // -------------------
- // Start -> -1 -2
- //
- GuardPage = Memory - EFI_PAGES_TO_SIZE (1);
- GuardBitmap = GetGuardedMemoryBits (Memory - EFI_PAGES_TO_SIZE (2), 2);
- if ((GuardBitmap & BIT1) == 0) {
- //
- // Head Guard exists.
- //
- if ((GuardBitmap & BIT0) == 0) {
- //
- // If the head Guard is not a tail Guard of adjacent memory block,
- // unset it.
- //
- UnsetGuardPage (GuardPage);
- }
- } else {
- //
- // Pages before memory to free are still in Guard. It's a partial free
- // case. Turn first page of memory block to free into a new Guard.
- //
- SetGuardPage (Memory);
- }
-
- //
- // Tail Guard must be the page after this memory block to free, if any.
- //
- // MSB-> 1 0 <-LSB
- // --------------------
- // 1 0 <- Tail Guard -> Don't free Tail Guard (shared Guard)
- // 0 0 <- Tail Guard -> Free Tail Guard either (not shared Guard)
- // X 1 -> Don't free last page (need a new Guard)
- // (it'll be turned into a Guard page later)
- // --------------------
- // +1 +0 <- End
- //
- GuardPage = Memory + EFI_PAGES_TO_SIZE (NumberOfPages);
- GuardBitmap = GetGuardedMemoryBits (GuardPage, 2);
- if ((GuardBitmap & BIT0) == 0) {
- //
- // Tail Guard exists.
- //
- if ((GuardBitmap & BIT1) == 0) {
- //
- // If the tail Guard is not a head Guard of adjacent memory block,
- // free it; otherwise, keep it.
- //
- UnsetGuardPage (GuardPage);
- }
- } else {
- //
- // Pages after memory to free are still in Guard. It's a partial free
- // case. We need to keep one page to be a head Guard.
- //
- SetGuardPage (GuardPage - EFI_PAGES_TO_SIZE (1));
- }
-
- //
- // No matter what, we just clear the mark of the Guarded memory.
- //
- ClearGuardedMemoryBits (Memory, NumberOfPages);
-}
-
-/**
- Adjust address of free memory according to existing and/or required Guard.
-
- This function will check if there're existing Guard pages of adjacent
- memory blocks, and try to use it as the Guard page of the memory to be
- allocated.
-
- @param[in] Start Start address of free memory block.
- @param[in] Size Size of free memory block.
- @param[in] SizeRequested Size of memory to allocate.
-
- @return The end address of memory block found.
- @return 0 if no enough space for the required size of memory and its Guard.
-**/
-UINT64
-AdjustMemoryS (
- IN UINT64 Start,
- IN UINT64 Size,
- IN UINT64 SizeRequested
- )
-{
- UINT64 Target;
-
- //
- // UEFI spec requires that allocated pool must be 8-byte aligned. If it's
- // indicated to put the pool near the Tail Guard, we need extra bytes to
- // make sure alignment of the returned pool address.
- //
- if ((PcdGet8 (PcdHeapGuardPropertyMask) & BIT7) == 0) {
- SizeRequested = ALIGN_VALUE (SizeRequested, 8);
- }
-
- Target = Start + Size - SizeRequested;
- ASSERT (Target >= Start);
- if (Target == 0) {
- return 0;
- }
-
- if (!IsGuardPage (Start + Size)) {
- // No Guard at tail to share. One more page is needed.
- Target -= EFI_PAGES_TO_SIZE (1);
- }
-
- // Out of range?
- if (Target < Start) {
- return 0;
- }
-
- // At the edge?
- if (Target == Start) {
- if (!IsGuardPage (Target - EFI_PAGES_TO_SIZE (1))) {
- // No enough space for a new head Guard if no Guard at head to share.
- return 0;
- }
- }
-
- // OK, we have enough pages for memory and its Guards. Return the End of the
- // free space.
- return Target + SizeRequested - 1;
-}
-
-/**
- Adjust the start address and number of pages to free according to Guard.
-
- The purpose of this function is to keep the shared Guard page with adjacent
- memory block if it's still in guard, or free it if no more sharing. Another
- is to reserve pages as Guard pages in partial page free situation.
-
- @param[in,out] Memory Base address of memory to free.
- @param[in,out] NumberOfPages Size of memory to free.
-
- @return VOID.
-**/
-VOID
-AdjustMemoryF (
- IN OUT EFI_PHYSICAL_ADDRESS *Memory,
- IN OUT UINTN *NumberOfPages
- )
-{
- EFI_PHYSICAL_ADDRESS Start;
- EFI_PHYSICAL_ADDRESS MemoryToTest;
- UINTN PagesToFree;
- UINT64 GuardBitmap;
-
- if ((Memory == NULL) || (NumberOfPages == NULL) || (*NumberOfPages == 0)) {
- return;
- }
-
- Start = *Memory;
- PagesToFree = *NumberOfPages;
-
- //
- // Head Guard must be one page before, if any.
- //
- // MSB-> 1 0 <-LSB
- // -------------------
- // Head Guard -> 0 1 -> Don't free Head Guard (shared Guard)
- // Head Guard -> 0 0 -> Free Head Guard either (not shared Guard)
- // 1 X -> Don't free first page (need a new Guard)
- // (it'll be turned into a Guard page later)
- // -------------------
- // Start -> -1 -2
- //
- MemoryToTest = Start - EFI_PAGES_TO_SIZE (2);
- GuardBitmap = GetGuardedMemoryBits (MemoryToTest, 2);
- if ((GuardBitmap & BIT1) == 0) {
- //
- // Head Guard exists.
- //
- if ((GuardBitmap & BIT0) == 0) {
- //
- // If the head Guard is not a tail Guard of adjacent memory block,
- // free it; otherwise, keep it.
- //
- Start -= EFI_PAGES_TO_SIZE (1);
- PagesToFree += 1;
- }
- } else {
- //
- // No Head Guard, and pages before memory to free are still in Guard. It's a
- // partial free case. We need to keep one page to be a tail Guard.
- //
- Start += EFI_PAGES_TO_SIZE (1);
- PagesToFree -= 1;
- }
-
- //
- // Tail Guard must be the page after this memory block to free, if any.
- //
- // MSB-> 1 0 <-LSB
- // --------------------
- // 1 0 <- Tail Guard -> Don't free Tail Guard (shared Guard)
- // 0 0 <- Tail Guard -> Free Tail Guard either (not shared Guard)
- // X 1 -> Don't free last page (need a new Guard)
- // (it'll be turned into a Guard page later)
- // --------------------
- // +1 +0 <- End
- //
- MemoryToTest = Start + EFI_PAGES_TO_SIZE (PagesToFree);
- GuardBitmap = GetGuardedMemoryBits (MemoryToTest, 2);
- if ((GuardBitmap & BIT0) == 0) {
- //
- // Tail Guard exists.
- //
- if ((GuardBitmap & BIT1) == 0) {
- //
- // If the tail Guard is not a head Guard of adjacent memory block,
- // free it; otherwise, keep it.
- //
- PagesToFree += 1;
- }
- } else if (PagesToFree > 0) {
- //
- // No Tail Guard, and pages after memory to free are still in Guard. It's a
- // partial free case. We need to keep one page to be a head Guard.
- //
- PagesToFree -= 1;
- }
-
- *Memory = Start;
- *NumberOfPages = PagesToFree;
-}
-
-/**
- Adjust the base and number of pages to really allocate according to Guard.
-
- @param[in,out] Memory Base address of free memory.
- @param[in,out] NumberOfPages Size of memory to allocate.
-
- @return VOID.
-**/
-VOID
-AdjustMemoryA (
- IN OUT EFI_PHYSICAL_ADDRESS *Memory,
- IN OUT UINTN *NumberOfPages
- )
-{
- //
- // FindFreePages() has already taken the Guard into account. It's safe to
- // adjust the start address and/or number of pages here, to make sure that
- // the Guards are also "allocated".
- //
- if (!IsGuardPage (*Memory + EFI_PAGES_TO_SIZE (*NumberOfPages))) {
- // No tail Guard, add one.
- *NumberOfPages += 1;
- }
-
- if (!IsGuardPage (*Memory - EFI_PAGE_SIZE)) {
- // No head Guard, add one.
- *Memory -= EFI_PAGE_SIZE;
- *NumberOfPages += 1;
- }
-}
-
-/**
- Adjust the pool head position to make sure the Guard page is adjavent to
- pool tail or pool head.
-
- @param[in] Memory Base address of memory allocated.
- @param[in] NoPages Number of pages actually allocated.
- @param[in] Size Size of memory requested.
- (plus pool head/tail overhead)
-
- @return Address of pool head.
-**/
-VOID *
-AdjustPoolHeadA (
- IN EFI_PHYSICAL_ADDRESS Memory,
- IN UINTN NoPages,
- IN UINTN Size
- )
-{
- if ((Memory == 0) || ((PcdGet8 (PcdHeapGuardPropertyMask) & BIT7) != 0)) {
- //
- // Pool head is put near the head Guard
- //
- return (VOID *)(UINTN)Memory;
- }
-
- //
- // Pool head is put near the tail Guard
- //
- Size = ALIGN_VALUE (Size, 8);
- return (VOID *)(UINTN)(Memory + EFI_PAGES_TO_SIZE (NoPages) - Size);
-}
-
-/**
- Get the page base address according to pool head address.
-
- @param[in] Memory Head address of pool to free.
- @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 *
-AdjustPoolHeadF (
- 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. We need to exactly undo the addition done in AdjustPoolHeadA
- // because we may not have allocated the pool head on the first allocated page, since we are aligned to
- // the tail and on some architectures, the runtime page allocation granularity is > one page. So we allocate
- // more pages than we need and put the pool head somewhere past the first page.
- //
- return (VOID *)(UINTN)(Memory + Size - EFI_PAGES_TO_SIZE (NoPages));
-}
-
-/**
- Allocate or free guarded memory.
-
- @param[in] Start Start address of memory to allocate or free.
- @param[in] NumberOfPages Memory size in pages.
- @param[in] NewType Memory type to convert to.
-
- @return VOID.
-**/
-EFI_STATUS
-CoreConvertPagesWithGuard (
- IN UINT64 Start,
- IN UINTN NumberOfPages,
- IN EFI_MEMORY_TYPE NewType
- )
-{
- UINT64 OldStart;
- UINTN OldPages;
-
- if (NewType == EfiConventionalMemory) {
- OldStart = Start;
- OldPages = NumberOfPages;
-
- AdjustMemoryF (&Start, &NumberOfPages);
- //
- // It's safe to unset Guard page inside memory lock because there should
- // be no memory allocation occurred in updating memory page attribute at
- // this point. And unsetting Guard page before free will prevent Guard
- // page just freed back to pool from being allocated right away before
- // marking it usable (from non-present to present).
- //
- UnsetGuardForMemory (OldStart, OldPages);
- if (NumberOfPages == 0) {
- return EFI_SUCCESS;
- }
- } else {
- AdjustMemoryA (&Start, &NumberOfPages);
- }
-
- return CoreConvertPages (Start, NumberOfPages, NewType);
-}
-
-/**
- Set all Guard pages which cannot be set before CPU Arch Protocol installed.
-**/
-VOID
-SetAllGuardPages (
- VOID
- )
-{
- UINTN Entries[GUARDED_HEAP_MAP_TABLE_DEPTH];
- UINTN Shifts[GUARDED_HEAP_MAP_TABLE_DEPTH];
- UINTN Indices[GUARDED_HEAP_MAP_TABLE_DEPTH];
- UINT64 Tables[GUARDED_HEAP_MAP_TABLE_DEPTH];
- UINT64 Addresses[GUARDED_HEAP_MAP_TABLE_DEPTH];
- UINT64 TableEntry;
- UINT64 Address;
- UINT64 GuardPage;
- INTN Level;
- UINTN Index;
- BOOLEAN OnGuarding;
-
- if ((mGuardedMemoryMap == 0) ||
- (mMapLevel == 0) ||
- (mMapLevel > GUARDED_HEAP_MAP_TABLE_DEPTH))
- {
- return;
- }
-
- CopyMem (Entries, mLevelMask, sizeof (Entries));
- CopyMem (Shifts, mLevelShift, sizeof (Shifts));
-
- SetMem (Tables, sizeof (Tables), 0);
- SetMem (Addresses, sizeof (Addresses), 0);
- SetMem (Indices, sizeof (Indices), 0);
-
- Level = GUARDED_HEAP_MAP_TABLE_DEPTH - mMapLevel;
- Tables[Level] = mGuardedMemoryMap;
- Address = 0;
- OnGuarding = FALSE;
-
- DEBUG_CODE (
- DumpGuardedMemoryBitmap ();
- );
-
- while (TRUE) {
- if (Indices[Level] > Entries[Level]) {
- Tables[Level] = 0;
- Level -= 1;
- } else {
- TableEntry = ((UINT64 *)(UINTN)(Tables[Level]))[Indices[Level]];
- Address = Addresses[Level];
-
- if (TableEntry == 0) {
- OnGuarding = FALSE;
- } else if (Level < GUARDED_HEAP_MAP_TABLE_DEPTH - 1) {
- Level += 1;
- Tables[Level] = TableEntry;
- Addresses[Level] = Address;
- Indices[Level] = 0;
-
- continue;
- } else {
- Index = 0;
- while (Index < GUARDED_HEAP_MAP_ENTRY_BITS) {
- if ((TableEntry & 1) == 1) {
- if (OnGuarding) {
- GuardPage = 0;
- } else {
- GuardPage = Address - EFI_PAGE_SIZE;
- }
-
- OnGuarding = TRUE;
- } else {
- if (OnGuarding) {
- GuardPage = Address;
- } else {
- GuardPage = 0;
- }
-
- OnGuarding = FALSE;
- }
-
- if (GuardPage != 0) {
- SetGuardPage (GuardPage);
- }
-
- if (TableEntry == 0) {
- break;
- }
-
- TableEntry = RShiftU64 (TableEntry, 1);
- Address += EFI_PAGE_SIZE;
- Index += 1;
- }
- }
- }
-
- if (Level < (GUARDED_HEAP_MAP_TABLE_DEPTH - (INTN)mMapLevel)) {
- break;
- }
-
- Indices[Level] += 1;
- Address = (Level == 0) ? 0 : Addresses[Level - 1];
- Addresses[Level] = Address | LShiftU64 (Indices[Level], Shifts[Level]);
- }
-}
-
-/**
- Find the address of top-most guarded free page.
-
- @param[out] Address Start address of top-most guarded free page.
-
- @return VOID.
-**/
-VOID
-GetLastGuardedFreePageAddress (
- OUT EFI_PHYSICAL_ADDRESS *Address
- )
-{
- EFI_PHYSICAL_ADDRESS AddressGranularity;
- EFI_PHYSICAL_ADDRESS BaseAddress;
- UINTN Level;
- UINT64 Map;
- INTN Index;
-
- ASSERT (mMapLevel >= 1);
-
- BaseAddress = 0;
- Map = mGuardedMemoryMap;
- for (Level = GUARDED_HEAP_MAP_TABLE_DEPTH - mMapLevel;
- Level < GUARDED_HEAP_MAP_TABLE_DEPTH;
- ++Level)
- {
- AddressGranularity = LShiftU64 (1, mLevelShift[Level]);
-
- //
- // Find the non-NULL entry at largest index.
- //
- for (Index = (INTN)mLevelMask[Level]; Index >= 0; --Index) {
- if (((UINT64 *)(UINTN)Map)[Index] != 0) {
- BaseAddress += MultU64x32 (AddressGranularity, (UINT32)Index);
- Map = ((UINT64 *)(UINTN)Map)[Index];
- break;
- }
- }
- }
-
- //
- // Find the non-zero MSB then get the page address.
- //
- while (Map != 0) {
- Map = RShiftU64 (Map, 1);
- BaseAddress += EFI_PAGES_TO_SIZE (1);
- }
-
- *Address = BaseAddress;
-}
-
-/**
- Record freed pages.
-
- @param[in] BaseAddress Base address of just freed pages.
- @param[in] Pages Number of freed pages.
-
- @return VOID.
-**/
-VOID
-MarkFreedPages (
- IN EFI_PHYSICAL_ADDRESS BaseAddress,
- IN UINTN Pages
- )
-{
- SetGuardedMemoryBits (BaseAddress, Pages);
-}
-
-/**
- Record freed pages as well as mark them as not-present.
-
- @param[in] BaseAddress Base address of just freed pages.
- @param[in] Pages Number of freed pages.
-
- @return VOID.
-**/
-VOID
-EFIAPI
-GuardFreedPages (
- IN EFI_PHYSICAL_ADDRESS BaseAddress,
- IN UINTN Pages
- )
-{
- EFI_STATUS Status;
-
- //
- // Legacy memory lower than 1MB might be accessed with no allocation. Leave
- // them alone.
- //
- if (BaseAddress < BASE_1MB) {
- return;
- }
-
- MarkFreedPages (BaseAddress, Pages);
- if (gCpu != NULL) {
- //
- // Set flag to make sure allocating memory without GUARD for page table
- // operation; otherwise infinite loops could be caused.
- //
- mOnGuarding = TRUE;
- //
- // Note: This might overwrite other attributes needed by other features,
- // such as NX memory protection.
- //
- Status = gCpu->SetMemoryAttributes (
- gCpu,
- BaseAddress,
- EFI_PAGES_TO_SIZE (Pages),
- EFI_MEMORY_RP
- );
- //
- // Normally we should ASSERT the returned Status. But there might be memory
- // alloc/free involved in SetMemoryAttributes(), which might fail this
- // calling. It's rare case so it's OK to let a few tiny holes be not-guarded.
- //
- if (EFI_ERROR (Status)) {
- DEBUG ((DEBUG_WARN, "Failed to guard freed pages: %p (%lu)\n", BaseAddress, (UINT64)Pages));
- }
-
- mOnGuarding = FALSE;
- }
-}
-
-/**
- Record freed pages as well as mark them as not-present, if enabled.
-
- @param[in] BaseAddress Base address of just freed pages.
- @param[in] Pages Number of freed pages.
-
- @return VOID.
-**/
-VOID
-EFIAPI
-GuardFreedPagesChecked (
- IN EFI_PHYSICAL_ADDRESS BaseAddress,
- IN UINTN Pages
- )
-{
- if (IsHeapGuardEnabled (GUARD_HEAP_TYPE_FREED)) {
- GuardFreedPages (BaseAddress, Pages);
- }
-}
-
-/**
- Mark all pages freed before CPU Arch Protocol as not-present.
-
-**/
-VOID
-GuardAllFreedPages (
- VOID
- )
-{
- UINTN Entries[GUARDED_HEAP_MAP_TABLE_DEPTH];
- UINTN Shifts[GUARDED_HEAP_MAP_TABLE_DEPTH];
- UINTN Indices[GUARDED_HEAP_MAP_TABLE_DEPTH];
- UINT64 Tables[GUARDED_HEAP_MAP_TABLE_DEPTH];
- UINT64 Addresses[GUARDED_HEAP_MAP_TABLE_DEPTH];
- UINT64 TableEntry;
- UINT64 Address;
- UINT64 GuardPage;
- INTN Level;
- UINT64 BitIndex;
- UINTN GuardPageNumber;
-
- if ((mGuardedMemoryMap == 0) ||
- (mMapLevel == 0) ||
- (mMapLevel > GUARDED_HEAP_MAP_TABLE_DEPTH))
- {
- return;
- }
-
- CopyMem (Entries, mLevelMask, sizeof (Entries));
- CopyMem (Shifts, mLevelShift, sizeof (Shifts));
-
- SetMem (Tables, sizeof (Tables), 0);
- SetMem (Addresses, sizeof (Addresses), 0);
- SetMem (Indices, sizeof (Indices), 0);
-
- Level = GUARDED_HEAP_MAP_TABLE_DEPTH - mMapLevel;
- Tables[Level] = mGuardedMemoryMap;
- Address = 0;
- GuardPage = (UINT64)-1;
- GuardPageNumber = 0;
-
- while (TRUE) {
- if (Indices[Level] > Entries[Level]) {
- Tables[Level] = 0;
- Level -= 1;
- } else {
- TableEntry = ((UINT64 *)(UINTN)(Tables[Level]))[Indices[Level]];
- Address = Addresses[Level];
-
- if (Level < GUARDED_HEAP_MAP_TABLE_DEPTH - 1) {
- Level += 1;
- Tables[Level] = TableEntry;
- Addresses[Level] = Address;
- Indices[Level] = 0;
-
- continue;
- } else {
- BitIndex = 1;
- while (BitIndex != 0) {
- if ((TableEntry & BitIndex) != 0) {
- if (GuardPage == (UINT64)-1) {
- GuardPage = Address;
- }
-
- ++GuardPageNumber;
- } else if (GuardPageNumber > 0) {
- GuardFreedPages (GuardPage, GuardPageNumber);
- GuardPageNumber = 0;
- GuardPage = (UINT64)-1;
- }
-
- if (TableEntry == 0) {
- break;
- }
-
- Address += EFI_PAGES_TO_SIZE (1);
- BitIndex = LShiftU64 (BitIndex, 1);
- }
- }
- }
-
- if (Level < (GUARDED_HEAP_MAP_TABLE_DEPTH - (INTN)mMapLevel)) {
- break;
- }
-
- Indices[Level] += 1;
- Address = (Level == 0) ? 0 : Addresses[Level - 1];
- Addresses[Level] = Address | LShiftU64 (Indices[Level], Shifts[Level]);
- }
-
- //
- // Update the maximum address of freed page which can be used for memory
- // promotion upon out-of-memory-space.
- //
- GetLastGuardedFreePageAddress (&Address);
- if (Address != 0) {
- mLastPromotedPage = Address;
- }
-}
-
-/**
- This function checks to see if the given memory map descriptor in a memory map
- can be merged with any guarded free pages.
-
- @param MemoryMapEntry A pointer to a descriptor in MemoryMap.
- @param MaxAddress Maximum address to stop the merge.
-
- @return VOID
-
-**/
-VOID
-MergeGuardPages (
- IN EFI_MEMORY_DESCRIPTOR *MemoryMapEntry,
- IN EFI_PHYSICAL_ADDRESS MaxAddress
- )
-{
- EFI_PHYSICAL_ADDRESS EndAddress;
- UINT64 Bitmap;
- INTN Pages;
-
- if (!IsHeapGuardEnabled (GUARD_HEAP_TYPE_FREED) ||
- (MemoryMapEntry->Type >= EfiMemoryMappedIO))
- {
- return;
- }
-
- Bitmap = 0;
- Pages = EFI_SIZE_TO_PAGES ((UINTN)(MaxAddress - MemoryMapEntry->PhysicalStart));
- Pages -= (INTN)MemoryMapEntry->NumberOfPages;
- while (Pages > 0) {
- if (Bitmap == 0) {
- EndAddress = MemoryMapEntry->PhysicalStart +
- EFI_PAGES_TO_SIZE ((UINTN)MemoryMapEntry->NumberOfPages);
- Bitmap = GetGuardedMemoryBits (EndAddress, GUARDED_HEAP_MAP_ENTRY_BITS);
- }
-
- if ((Bitmap & 1) == 0) {
- break;
- }
-
- Pages--;
- MemoryMapEntry->NumberOfPages++;
- Bitmap = RShiftU64 (Bitmap, 1);
- }
-}
-
-/**
- Put part (at most 64 pages a time) guarded free pages back to free page pool.
-
- Freed memory guard is used to detect Use-After-Free (UAF) memory issue, which
- makes use of 'Used then throw away' way to detect any illegal access to freed
- memory. The thrown-away memory will be marked as not-present so that any access
- to those memory (after free) will be caught by page-fault exception.
-
- The problem is that this will consume lots of memory space. Once no memory
- left in pool to allocate, we have to restore part of the freed pages to their
- normal function. Otherwise the whole system will stop functioning.
-
- @param StartAddress Start address of promoted memory.
- @param EndAddress End address of promoted memory.
-
- @return TRUE Succeeded to promote memory.
- @return FALSE No free memory found.
-
-**/
-BOOLEAN
-PromoteGuardedFreePages (
- OUT EFI_PHYSICAL_ADDRESS *StartAddress,
- OUT EFI_PHYSICAL_ADDRESS *EndAddress
- )
-{
- EFI_STATUS Status;
- UINTN AvailablePages;
- UINT64 Bitmap;
- EFI_PHYSICAL_ADDRESS Start;
-
- if (!IsHeapGuardEnabled (GUARD_HEAP_TYPE_FREED)) {
- return FALSE;
- }
-
- //
- // Similar to memory allocation service, always search the freed pages in
- // descending direction.
- //
- Start = mLastPromotedPage;
- AvailablePages = 0;
- while (AvailablePages == 0) {
- Start -= EFI_PAGES_TO_SIZE (GUARDED_HEAP_MAP_ENTRY_BITS);
- //
- // If the address wraps around, try the really freed pages at top.
- //
- if (Start > mLastPromotedPage) {
- GetLastGuardedFreePageAddress (&Start);
- ASSERT (Start != 0);
- Start -= EFI_PAGES_TO_SIZE (GUARDED_HEAP_MAP_ENTRY_BITS);
- }
-
- Bitmap = GetGuardedMemoryBits (Start, GUARDED_HEAP_MAP_ENTRY_BITS);
- while (Bitmap > 0) {
- if ((Bitmap & 1) != 0) {
- ++AvailablePages;
- } else if (AvailablePages == 0) {
- Start += EFI_PAGES_TO_SIZE (1);
- } else {
- break;
- }
-
- Bitmap = RShiftU64 (Bitmap, 1);
- }
- }
-
- if (AvailablePages != 0) {
- DEBUG ((DEBUG_INFO, "Promoted pages: %lX (%lx)\r\n", Start, (UINT64)AvailablePages));
- ClearGuardedMemoryBits (Start, AvailablePages);
-
- if (gCpu != NULL) {
- //
- // Set flag to make sure allocating memory without GUARD for page table
- // operation; otherwise infinite loops could be caused.
- //
- mOnGuarding = TRUE;
- Status = gCpu->SetMemoryAttributes (gCpu, Start, EFI_PAGES_TO_SIZE (AvailablePages), 0);
- ASSERT_EFI_ERROR (Status);
- mOnGuarding = FALSE;
- }
-
- mLastPromotedPage = Start;
- *StartAddress = Start;
- *EndAddress = Start + EFI_PAGES_TO_SIZE (AvailablePages) - 1;
- return TRUE;
- }
-
- return FALSE;
-}
-
-/**
- Notify function used to set all Guard pages before CPU Arch Protocol installed.
-**/
-VOID
-HeapGuardCpuArchProtocolNotify (
- VOID
- )
-{
- ASSERT (gCpu != NULL);
-
- if (IsHeapGuardEnabled (GUARD_HEAP_TYPE_PAGE|GUARD_HEAP_TYPE_POOL) &&
- IsHeapGuardEnabled (GUARD_HEAP_TYPE_FREED))
- {
- DEBUG ((DEBUG_ERROR, "Heap guard and freed memory guard cannot be enabled at the same time.\n"));
- CpuDeadLoop ();
- }
-
- if (IsHeapGuardEnabled (GUARD_HEAP_TYPE_PAGE|GUARD_HEAP_TYPE_POOL)) {
- SetAllGuardPages ();
- }
-
- if (IsHeapGuardEnabled (GUARD_HEAP_TYPE_FREED)) {
- GuardAllFreedPages ();
- }
-}
-
-/**
- Helper function to convert a UINT64 value in binary to a string.
-
- @param[in] Value Value of a UINT64 integer.
- @param[out] BinString String buffer to contain the conversion result.
-
- @return VOID.
-**/
-VOID
-Uint64ToBinString (
- IN UINT64 Value,
- OUT CHAR8 *BinString
- )
-{
- UINTN Index;
-
- if (BinString == NULL) {
- return;
- }
-
- for (Index = 64; Index > 0; --Index) {
- BinString[Index - 1] = '0' + (Value & 1);
- Value = RShiftU64 (Value, 1);
- }
-
- BinString[64] = '\0';
-}
-
-/**
- Dump the guarded memory bit map.
-**/
-VOID
-EFIAPI
-DumpGuardedMemoryBitmap (
- VOID
- )
-{
- UINTN Entries[GUARDED_HEAP_MAP_TABLE_DEPTH];
- UINTN Shifts[GUARDED_HEAP_MAP_TABLE_DEPTH];
- UINTN Indices[GUARDED_HEAP_MAP_TABLE_DEPTH];
- UINT64 Tables[GUARDED_HEAP_MAP_TABLE_DEPTH];
- UINT64 Addresses[GUARDED_HEAP_MAP_TABLE_DEPTH];
- UINT64 TableEntry;
- UINT64 Address;
- INTN Level;
- UINTN RepeatZero;
- CHAR8 String[GUARDED_HEAP_MAP_ENTRY_BITS + 1];
- CHAR8 *Ruler1;
- CHAR8 *Ruler2;
-
- if (!IsHeapGuardEnabled (GUARD_HEAP_TYPE_ALL)) {
- return;
- }
-
- if ((mGuardedMemoryMap == 0) ||
- (mMapLevel == 0) ||
- (mMapLevel > GUARDED_HEAP_MAP_TABLE_DEPTH))
- {
- return;
- }
-
- Ruler1 = " 3 2 1 0";
- Ruler2 = "FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210";
-
- DEBUG ((
- HEAP_GUARD_DEBUG_LEVEL,
- "============================="
- " Guarded Memory Bitmap "
- "==============================\r\n"
- ));
- DEBUG ((HEAP_GUARD_DEBUG_LEVEL, " %a\r\n", Ruler1));
- DEBUG ((HEAP_GUARD_DEBUG_LEVEL, " %a\r\n", Ruler2));
-
- CopyMem (Entries, mLevelMask, sizeof (Entries));
- CopyMem (Shifts, mLevelShift, sizeof (Shifts));
-
- SetMem (Indices, sizeof (Indices), 0);
- SetMem (Tables, sizeof (Tables), 0);
- SetMem (Addresses, sizeof (Addresses), 0);
-
- Level = GUARDED_HEAP_MAP_TABLE_DEPTH - mMapLevel;
- Tables[Level] = mGuardedMemoryMap;
- Address = 0;
- RepeatZero = 0;
-
- while (TRUE) {
- if (Indices[Level] > Entries[Level]) {
- Tables[Level] = 0;
- Level -= 1;
- RepeatZero = 0;
-
- DEBUG ((
- HEAP_GUARD_DEBUG_LEVEL,
- "========================================="
- "=========================================\r\n"
- ));
- } else {
- TableEntry = ((UINT64 *)(UINTN)Tables[Level])[Indices[Level]];
- Address = Addresses[Level];
-
- if (TableEntry == 0) {
- if (Level == GUARDED_HEAP_MAP_TABLE_DEPTH - 1) {
- if (RepeatZero == 0) {
- Uint64ToBinString (TableEntry, String);
- DEBUG ((HEAP_GUARD_DEBUG_LEVEL, "%016lx: %a\r\n", Address, String));
- } else if (RepeatZero == 1) {
- DEBUG ((HEAP_GUARD_DEBUG_LEVEL, "... : ...\r\n"));
- }
-
- RepeatZero += 1;
- }
- } else if (Level < GUARDED_HEAP_MAP_TABLE_DEPTH - 1) {
- Level += 1;
- Tables[Level] = TableEntry;
- Addresses[Level] = Address;
- Indices[Level] = 0;
- RepeatZero = 0;
-
- continue;
- } else {
- RepeatZero = 0;
- Uint64ToBinString (TableEntry, String);
- DEBUG ((HEAP_GUARD_DEBUG_LEVEL, "%016lx: %a\r\n", Address, String));
- }
- }
-
- if (Level < (GUARDED_HEAP_MAP_TABLE_DEPTH - (INTN)mMapLevel)) {
- break;
- }
-
- Indices[Level] += 1;
- Address = (Level == 0) ? 0 : Addresses[Level - 1];
- Addresses[Level] = Address | LShiftU64 (Indices[Level], Shifts[Level]);
- }
-}
+/** @file
+ UEFI Heap Guard functions.
+
+Copyright (c) 2017-2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "DxeMain.h"
+#include "Imem.h"
+#include "HeapGuard.h"
+
+//
+// Global to avoid infinite reentrance of memory allocation when updating
+// page table attributes, which may need allocate pages for new PDE/PTE.
+//
+GLOBAL_REMOVE_IF_UNREFERENCED BOOLEAN mOnGuarding = FALSE;
+
+//
+// Pointer to table tracking the Guarded memory with bitmap, in which '1'
+// is used to indicate memory guarded. '0' might be free memory or Guard
+// page itself, depending on status of memory adjacent to it.
+//
+GLOBAL_REMOVE_IF_UNREFERENCED UINT64 mGuardedMemoryMap = 0;
+
+//
+// Current depth level of map table pointed by mGuardedMemoryMap.
+// mMapLevel must be initialized at least by 1. It will be automatically
+// updated according to the address of memory just tracked.
+//
+GLOBAL_REMOVE_IF_UNREFERENCED UINTN mMapLevel = 1;
+
+//
+// Shift and mask for each level of map table
+//
+GLOBAL_REMOVE_IF_UNREFERENCED UINTN mLevelShift[GUARDED_HEAP_MAP_TABLE_DEPTH]
+ = GUARDED_HEAP_MAP_TABLE_DEPTH_SHIFTS;
+GLOBAL_REMOVE_IF_UNREFERENCED UINTN mLevelMask[GUARDED_HEAP_MAP_TABLE_DEPTH]
+ = GUARDED_HEAP_MAP_TABLE_DEPTH_MASKS;
+
+//
+// Used for promoting freed but not used pages.
+//
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_PHYSICAL_ADDRESS mLastPromotedPage = BASE_4GB;
+
+/**
+ Set corresponding bits in bitmap table to 1 according to the address.
+
+ @param[in] Address Start address to set for.
+ @param[in] BitNumber Number of bits to set.
+ @param[in] BitMap Pointer to bitmap which covers the Address.
+
+ @return VOID.
+**/
+STATIC
+VOID
+SetBits (
+ IN EFI_PHYSICAL_ADDRESS Address,
+ IN UINTN BitNumber,
+ IN UINT64 *BitMap
+ )
+{
+ UINTN Lsbs;
+ UINTN Qwords;
+ UINTN Msbs;
+ UINTN StartBit;
+ UINTN EndBit;
+
+ StartBit = (UINTN)GUARDED_HEAP_MAP_ENTRY_BIT_INDEX (Address);
+ EndBit = (StartBit + BitNumber - 1) % GUARDED_HEAP_MAP_ENTRY_BITS;
+
+ if ((StartBit + BitNumber) >= GUARDED_HEAP_MAP_ENTRY_BITS) {
+ Msbs = (GUARDED_HEAP_MAP_ENTRY_BITS - StartBit) %
+ GUARDED_HEAP_MAP_ENTRY_BITS;
+ Lsbs = (EndBit + 1) % GUARDED_HEAP_MAP_ENTRY_BITS;
+ Qwords = (BitNumber - Msbs) / GUARDED_HEAP_MAP_ENTRY_BITS;
+ } else {
+ Msbs = BitNumber;
+ Lsbs = 0;
+ Qwords = 0;
+ }
+
+ if (Msbs > 0) {
+ *BitMap |= LShiftU64 (LShiftU64 (1, Msbs) - 1, StartBit);
+ BitMap += 1;
+ }
+
+ if (Qwords > 0) {
+ SetMem64 (
+ (VOID *)BitMap,
+ Qwords * GUARDED_HEAP_MAP_ENTRY_BYTES,
+ (UINT64)-1
+ );
+ BitMap += Qwords;
+ }
+
+ if (Lsbs > 0) {
+ *BitMap |= (LShiftU64 (1, Lsbs) - 1);
+ }
+}
+
+/**
+ Set corresponding bits in bitmap table to 0 according to the address.
+
+ @param[in] Address Start address to set for.
+ @param[in] BitNumber Number of bits to set.
+ @param[in] BitMap Pointer to bitmap which covers the Address.
+
+ @return VOID.
+**/
+STATIC
+VOID
+ClearBits (
+ IN EFI_PHYSICAL_ADDRESS Address,
+ IN UINTN BitNumber,
+ IN UINT64 *BitMap
+ )
+{
+ UINTN Lsbs;
+ UINTN Qwords;
+ UINTN Msbs;
+ UINTN StartBit;
+ UINTN EndBit;
+
+ StartBit = (UINTN)GUARDED_HEAP_MAP_ENTRY_BIT_INDEX (Address);
+ EndBit = (StartBit + BitNumber - 1) % GUARDED_HEAP_MAP_ENTRY_BITS;
+
+ if ((StartBit + BitNumber) >= GUARDED_HEAP_MAP_ENTRY_BITS) {
+ Msbs = (GUARDED_HEAP_MAP_ENTRY_BITS - StartBit) %
+ GUARDED_HEAP_MAP_ENTRY_BITS;
+ Lsbs = (EndBit + 1) % GUARDED_HEAP_MAP_ENTRY_BITS;
+ Qwords = (BitNumber - Msbs) / GUARDED_HEAP_MAP_ENTRY_BITS;
+ } else {
+ Msbs = BitNumber;
+ Lsbs = 0;
+ Qwords = 0;
+ }
+
+ if (Msbs > 0) {
+ *BitMap &= ~LShiftU64 (LShiftU64 (1, Msbs) - 1, StartBit);
+ BitMap += 1;
+ }
+
+ if (Qwords > 0) {
+ SetMem64 ((VOID *)BitMap, Qwords * GUARDED_HEAP_MAP_ENTRY_BYTES, 0);
+ BitMap += Qwords;
+ }
+
+ if (Lsbs > 0) {
+ *BitMap &= ~(LShiftU64 (1, Lsbs) - 1);
+ }
+}
+
+/**
+ Get corresponding bits in bitmap table according to the address.
+
+ The value of bit 0 corresponds to the status of memory at given Address.
+ No more than 64 bits can be retrieved in one call.
+
+ @param[in] Address Start address to retrieve bits for.
+ @param[in] BitNumber Number of bits to get.
+ @param[in] BitMap Pointer to bitmap which covers the Address.
+
+ @return An integer containing the bits information.
+**/
+STATIC
+UINT64
+GetBits (
+ IN EFI_PHYSICAL_ADDRESS Address,
+ IN UINTN BitNumber,
+ IN UINT64 *BitMap
+ )
+{
+ UINTN StartBit;
+ UINTN EndBit;
+ UINTN Lsbs;
+ UINTN Msbs;
+ UINT64 Result;
+
+ ASSERT (BitNumber <= GUARDED_HEAP_MAP_ENTRY_BITS);
+
+ StartBit = (UINTN)GUARDED_HEAP_MAP_ENTRY_BIT_INDEX (Address);
+ EndBit = (StartBit + BitNumber - 1) % GUARDED_HEAP_MAP_ENTRY_BITS;
+
+ if ((StartBit + BitNumber) > GUARDED_HEAP_MAP_ENTRY_BITS) {
+ Msbs = GUARDED_HEAP_MAP_ENTRY_BITS - StartBit;
+ Lsbs = (EndBit + 1) % GUARDED_HEAP_MAP_ENTRY_BITS;
+ } else {
+ Msbs = BitNumber;
+ Lsbs = 0;
+ }
+
+ if ((StartBit == 0) && (BitNumber == GUARDED_HEAP_MAP_ENTRY_BITS)) {
+ Result = *BitMap;
+ } else {
+ Result = RShiftU64 ((*BitMap), StartBit) & (LShiftU64 (1, Msbs) - 1);
+ if (Lsbs > 0) {
+ BitMap += 1;
+ Result |= LShiftU64 ((*BitMap) & (LShiftU64 (1, Lsbs) - 1), Msbs);
+ }
+ }
+
+ return Result;
+}
+
+/**
+ Locate the pointer of bitmap from the guarded memory bitmap tables, which
+ covers the given Address.
+
+ @param[in] Address Start address to search the bitmap for.
+ @param[in] AllocMapUnit Flag to indicate memory allocation for the table.
+ @param[out] BitMap Pointer to bitmap which covers the Address.
+
+ @return The bit number from given Address to the end of current map table.
+**/
+UINTN
+FindGuardedMemoryMap (
+ IN EFI_PHYSICAL_ADDRESS Address,
+ IN BOOLEAN AllocMapUnit,
+ OUT UINT64 **BitMap
+ )
+{
+ UINTN Level;
+ UINT64 *GuardMap;
+ UINT64 MapMemory;
+ UINTN Index;
+ UINTN Size;
+ UINTN BitsToUnitEnd;
+ EFI_STATUS Status;
+
+ MapMemory = 0;
+
+ //
+ // Adjust current map table depth according to the address to access
+ //
+ while (AllocMapUnit &&
+ mMapLevel < GUARDED_HEAP_MAP_TABLE_DEPTH &&
+ RShiftU64 (
+ Address,
+ mLevelShift[GUARDED_HEAP_MAP_TABLE_DEPTH - mMapLevel - 1]
+ ) != 0)
+ {
+ if (mGuardedMemoryMap != 0) {
+ Size = (mLevelMask[GUARDED_HEAP_MAP_TABLE_DEPTH - mMapLevel - 1] + 1)
+ * GUARDED_HEAP_MAP_ENTRY_BYTES;
+ Status = CoreInternalAllocatePages (
+ AllocateAnyPages,
+ EfiBootServicesData,
+ EFI_SIZE_TO_PAGES (Size),
+ &MapMemory,
+ FALSE
+ );
+ ASSERT_EFI_ERROR (Status);
+ ASSERT (MapMemory != 0);
+
+ SetMem ((VOID *)(UINTN)MapMemory, Size, 0);
+
+ *(UINT64 *)(UINTN)MapMemory = mGuardedMemoryMap;
+ mGuardedMemoryMap = MapMemory;
+ }
+
+ mMapLevel++;
+ }
+
+ GuardMap = &mGuardedMemoryMap;
+ for (Level = GUARDED_HEAP_MAP_TABLE_DEPTH - mMapLevel;
+ Level < GUARDED_HEAP_MAP_TABLE_DEPTH;
+ ++Level)
+ {
+ if (*GuardMap == 0) {
+ if (!AllocMapUnit) {
+ GuardMap = NULL;
+ break;
+ }
+
+ Size = (mLevelMask[Level] + 1) * GUARDED_HEAP_MAP_ENTRY_BYTES;
+ Status = CoreInternalAllocatePages (
+ AllocateAnyPages,
+ EfiBootServicesData,
+ EFI_SIZE_TO_PAGES (Size),
+ &MapMemory,
+ FALSE
+ );
+ ASSERT_EFI_ERROR (Status);
+ ASSERT (MapMemory != 0);
+
+ SetMem ((VOID *)(UINTN)MapMemory, Size, 0);
+ *GuardMap = MapMemory;
+ }
+
+ Index = (UINTN)RShiftU64 (Address, mLevelShift[Level]);
+ Index &= mLevelMask[Level];
+ GuardMap = (UINT64 *)(UINTN)((*GuardMap) + Index * sizeof (UINT64));
+ }
+
+ BitsToUnitEnd = GUARDED_HEAP_MAP_BITS - GUARDED_HEAP_MAP_BIT_INDEX (Address);
+ *BitMap = GuardMap;
+
+ return BitsToUnitEnd;
+}
+
+/**
+ Set corresponding bits in bitmap table to 1 according to given memory range.
+
+ @param[in] Address Memory address to guard from.
+ @param[in] NumberOfPages Number of pages to guard.
+
+ @return VOID.
+**/
+VOID
+EFIAPI
+SetGuardedMemoryBits (
+ IN EFI_PHYSICAL_ADDRESS Address,
+ IN UINTN NumberOfPages
+ )
+{
+ UINT64 *BitMap;
+ UINTN Bits;
+ UINTN BitsToUnitEnd;
+
+ while (NumberOfPages > 0) {
+ BitsToUnitEnd = FindGuardedMemoryMap (Address, TRUE, &BitMap);
+ ASSERT (BitMap != NULL);
+
+ if (NumberOfPages > BitsToUnitEnd) {
+ // Cross map unit
+ Bits = BitsToUnitEnd;
+ } else {
+ Bits = NumberOfPages;
+ }
+
+ SetBits (Address, Bits, BitMap);
+
+ NumberOfPages -= Bits;
+ Address += EFI_PAGES_TO_SIZE (Bits);
+ }
+}
+
+/**
+ Clear corresponding bits in bitmap table according to given memory range.
+
+ @param[in] Address Memory address to unset from.
+ @param[in] NumberOfPages Number of pages to unset guard.
+
+ @return VOID.
+**/
+VOID
+EFIAPI
+ClearGuardedMemoryBits (
+ IN EFI_PHYSICAL_ADDRESS Address,
+ IN UINTN NumberOfPages
+ )
+{
+ UINT64 *BitMap;
+ UINTN Bits;
+ UINTN BitsToUnitEnd;
+
+ while (NumberOfPages > 0) {
+ BitsToUnitEnd = FindGuardedMemoryMap (Address, TRUE, &BitMap);
+ ASSERT (BitMap != NULL);
+
+ if (NumberOfPages > BitsToUnitEnd) {
+ // Cross map unit
+ Bits = BitsToUnitEnd;
+ } else {
+ Bits = NumberOfPages;
+ }
+
+ ClearBits (Address, Bits, BitMap);
+
+ NumberOfPages -= Bits;
+ Address += EFI_PAGES_TO_SIZE (Bits);
+ }
+}
+
+/**
+ Retrieve corresponding bits in bitmap table according to given memory range.
+
+ @param[in] Address Memory address to retrieve from.
+ @param[in] NumberOfPages Number of pages to retrieve.
+
+ @return An integer containing the guarded memory bitmap.
+**/
+UINT64
+GetGuardedMemoryBits (
+ IN EFI_PHYSICAL_ADDRESS Address,
+ IN UINTN NumberOfPages
+ )
+{
+ UINT64 *BitMap;
+ UINTN Bits;
+ UINT64 Result;
+ UINTN Shift;
+ UINTN BitsToUnitEnd;
+
+ ASSERT (NumberOfPages <= GUARDED_HEAP_MAP_ENTRY_BITS);
+
+ Result = 0;
+ Shift = 0;
+ while (NumberOfPages > 0) {
+ BitsToUnitEnd = FindGuardedMemoryMap (Address, FALSE, &BitMap);
+
+ if (NumberOfPages > BitsToUnitEnd) {
+ // Cross map unit
+ Bits = BitsToUnitEnd;
+ } else {
+ Bits = NumberOfPages;
+ }
+
+ if (BitMap != NULL) {
+ Result |= LShiftU64 (GetBits (Address, Bits, BitMap), Shift);
+ }
+
+ Shift += Bits;
+ NumberOfPages -= Bits;
+ Address += EFI_PAGES_TO_SIZE (Bits);
+ }
+
+ return Result;
+}
+
+/**
+ Get bit value in bitmap table for the given address.
+
+ @param[in] Address The address to retrieve for.
+
+ @return 1 or 0.
+**/
+UINTN
+EFIAPI
+GetGuardMapBit (
+ IN EFI_PHYSICAL_ADDRESS Address
+ )
+{
+ UINT64 *GuardMap;
+
+ FindGuardedMemoryMap (Address, FALSE, &GuardMap);
+ if (GuardMap != NULL) {
+ if (RShiftU64 (
+ *GuardMap,
+ GUARDED_HEAP_MAP_ENTRY_BIT_INDEX (Address)
+ ) & 1)
+ {
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+/**
+ Check to see if the page at the given address is a Guard page or not.
+
+ @param[in] Address The address to check for.
+
+ @return TRUE The page at Address is a Guard page.
+ @return FALSE The page at Address is not a Guard page.
+**/
+BOOLEAN
+EFIAPI
+IsGuardPage (
+ IN EFI_PHYSICAL_ADDRESS Address
+ )
+{
+ UINT64 BitMap;
+
+ //
+ // There must be at least one guarded page before and/or after given
+ // address if it's a Guard page. The bitmap pattern should be one of
+ // 001, 100 and 101
+ //
+ BitMap = GetGuardedMemoryBits (Address - EFI_PAGE_SIZE, 3);
+ return ((BitMap == BIT0) || (BitMap == BIT2) || (BitMap == (BIT2 | BIT0)));
+}
+
+/**
+ Check to see if the page at the given address is guarded or not.
+
+ @param[in] Address The address to check for.
+
+ @return TRUE The page at Address is guarded.
+ @return FALSE The page at Address is not guarded.
+**/
+BOOLEAN
+EFIAPI
+IsMemoryGuarded (
+ IN EFI_PHYSICAL_ADDRESS Address
+ )
+{
+ return (GetGuardMapBit (Address) == 1);
+}
+
+/**
+ Set the page at the given address to be a Guard page.
+
+ This is done by changing the page table attribute to be NOT PRSENT.
+
+ @param[in] BaseAddress Page address to Guard at
+
+ @return VOID
+**/
+VOID
+EFIAPI
+SetGuardPage (
+ IN EFI_PHYSICAL_ADDRESS BaseAddress
+ )
+{
+ EFI_STATUS Status;
+
+ if (gCpu == NULL) {
+ return;
+ }
+
+ //
+ // Set flag to make sure allocating memory without GUARD for page table
+ // operation; otherwise infinite loops could be caused.
+ //
+ mOnGuarding = TRUE;
+ //
+ // Note: This might overwrite other attributes needed by other features,
+ // such as NX memory protection.
+ //
+ Status = gCpu->SetMemoryAttributes (gCpu, BaseAddress, EFI_PAGE_SIZE, EFI_MEMORY_RP);
+ ASSERT_EFI_ERROR (Status);
+ mOnGuarding = FALSE;
+}
+
+/**
+ Unset the Guard page at the given address to the normal memory.
+
+ This is done by changing the page table attribute to be PRSENT.
+
+ @param[in] BaseAddress Page address to Guard at.
+
+ @return VOID.
+**/
+VOID
+EFIAPI
+UnsetGuardPage (
+ IN EFI_PHYSICAL_ADDRESS BaseAddress
+ )
+{
+ UINT64 Attributes;
+ EFI_STATUS Status;
+
+ if (gCpu == NULL) {
+ return;
+ }
+
+ //
+ // Once the Guard page is unset, it will be freed back to memory pool. NX
+ // memory protection must be restored for this page if NX is enabled for free
+ // memory.
+ //
+ Attributes = 0;
+ if ((PcdGet64 (PcdDxeNxMemoryProtectionPolicy) & (1 << EfiConventionalMemory)) != 0) {
+ Attributes |= EFI_MEMORY_XP;
+ }
+
+ //
+ // Set flag to make sure allocating memory without GUARD for page table
+ // operation; otherwise infinite loops could be caused.
+ //
+ mOnGuarding = TRUE;
+ //
+ // Note: This might overwrite other attributes needed by other features,
+ // such as memory protection (NX). Please make sure they are not enabled
+ // at the same time.
+ //
+ Status = gCpu->SetMemoryAttributes (gCpu, BaseAddress, EFI_PAGE_SIZE, Attributes);
+ ASSERT_EFI_ERROR (Status);
+ mOnGuarding = FALSE;
+}
+
+/**
+ Check to see if the memory at the given address should be guarded or not.
+
+ @param[in] MemoryType Memory type to check.
+ @param[in] AllocateType Allocation type to check.
+ @param[in] PageOrPool Indicate a page allocation or pool allocation.
+
+
+ @return TRUE The given type of memory should be guarded.
+ @return FALSE The given type of memory should not be guarded.
+**/
+BOOLEAN
+IsMemoryTypeToGuard (
+ IN EFI_MEMORY_TYPE MemoryType,
+ IN EFI_ALLOCATE_TYPE AllocateType,
+ IN UINT8 PageOrPool
+ )
+{
+ UINT64 TestBit;
+ UINT64 ConfigBit;
+
+ if (AllocateType == AllocateAddress) {
+ return FALSE;
+ }
+
+ if ((PcdGet8 (PcdHeapGuardPropertyMask) & PageOrPool) == 0) {
+ return FALSE;
+ }
+
+ if (PageOrPool == GUARD_HEAP_TYPE_POOL) {
+ ConfigBit = PcdGet64 (PcdHeapGuardPoolType);
+ } else if (PageOrPool == GUARD_HEAP_TYPE_PAGE) {
+ ConfigBit = PcdGet64 (PcdHeapGuardPageType);
+ } else {
+ ConfigBit = (UINT64)-1;
+ }
+
+ if ((UINT32)MemoryType >= MEMORY_TYPE_OS_RESERVED_MIN) {
+ TestBit = BIT63;
+ } else if ((UINT32)MemoryType >= MEMORY_TYPE_OEM_RESERVED_MIN) {
+ TestBit = BIT62;
+ } else if (MemoryType < EfiMaxMemoryType) {
+ TestBit = LShiftU64 (1, MemoryType);
+ } else if (MemoryType == EfiMaxMemoryType) {
+ TestBit = (UINT64)-1;
+ } else {
+ TestBit = 0;
+ }
+
+ return ((ConfigBit & TestBit) != 0);
+}
+
+/**
+ Check to see if the pool at the given address should be guarded or not.
+
+ @param[in] MemoryType Pool type to check.
+
+
+ @return TRUE The given type of pool should be guarded.
+ @return FALSE The given type of pool should not be guarded.
+**/
+BOOLEAN
+IsPoolTypeToGuard (
+ IN EFI_MEMORY_TYPE MemoryType
+ )
+{
+ return IsMemoryTypeToGuard (
+ MemoryType,
+ AllocateAnyPages,
+ GUARD_HEAP_TYPE_POOL
+ );
+}
+
+/**
+ Check to see if the page at the given address should be guarded or not.
+
+ @param[in] MemoryType Page type to check.
+ @param[in] AllocateType Allocation type to check.
+
+ @return TRUE The given type of page should be guarded.
+ @return FALSE The given type of page should not be guarded.
+**/
+BOOLEAN
+IsPageTypeToGuard (
+ IN EFI_MEMORY_TYPE MemoryType,
+ IN EFI_ALLOCATE_TYPE AllocateType
+ )
+{
+ return IsMemoryTypeToGuard (MemoryType, AllocateType, GUARD_HEAP_TYPE_PAGE);
+}
+
+/**
+ Check to see if the heap guard is enabled for page and/or pool allocation.
+
+ @param[in] GuardType Specify the sub-type(s) of Heap Guard.
+
+ @return TRUE/FALSE.
+**/
+BOOLEAN
+IsHeapGuardEnabled (
+ UINT8 GuardType
+ )
+{
+ return IsMemoryTypeToGuard (EfiMaxMemoryType, AllocateAnyPages, GuardType);
+}
+
+/**
+ Set head Guard and tail Guard for the given memory range.
+
+ @param[in] Memory Base address of memory to set guard for.
+ @param[in] NumberOfPages Memory size in pages.
+
+ @return VOID
+**/
+VOID
+SetGuardForMemory (
+ IN EFI_PHYSICAL_ADDRESS Memory,
+ IN UINTN NumberOfPages
+ )
+{
+ EFI_PHYSICAL_ADDRESS GuardPage;
+
+ //
+ // Set tail Guard
+ //
+ GuardPage = Memory + EFI_PAGES_TO_SIZE (NumberOfPages);
+ if (!IsGuardPage (GuardPage)) {
+ SetGuardPage (GuardPage);
+ }
+
+ // Set head Guard
+ GuardPage = Memory - EFI_PAGES_TO_SIZE (1);
+ if (!IsGuardPage (GuardPage)) {
+ SetGuardPage (GuardPage);
+ }
+
+ //
+ // Mark the memory range as Guarded
+ //
+ SetGuardedMemoryBits (Memory, NumberOfPages);
+}
+
+/**
+ Unset head Guard and tail Guard for the given memory range.
+
+ @param[in] Memory Base address of memory to unset guard for.
+ @param[in] NumberOfPages Memory size in pages.
+
+ @return VOID
+**/
+VOID
+UnsetGuardForMemory (
+ IN EFI_PHYSICAL_ADDRESS Memory,
+ IN UINTN NumberOfPages
+ )
+{
+ EFI_PHYSICAL_ADDRESS GuardPage;
+ UINT64 GuardBitmap;
+
+ if (NumberOfPages == 0) {
+ return;
+ }
+
+ //
+ // Head Guard must be one page before, if any.
+ //
+ // MSB-> 1 0 <-LSB
+ // -------------------
+ // Head Guard -> 0 1 -> Don't free Head Guard (shared Guard)
+ // Head Guard -> 0 0 -> Free Head Guard either (not shared Guard)
+ // 1 X -> Don't free first page (need a new Guard)
+ // (it'll be turned into a Guard page later)
+ // -------------------
+ // Start -> -1 -2
+ //
+ GuardPage = Memory - EFI_PAGES_TO_SIZE (1);
+ GuardBitmap = GetGuardedMemoryBits (Memory - EFI_PAGES_TO_SIZE (2), 2);
+ if ((GuardBitmap & BIT1) == 0) {
+ //
+ // Head Guard exists.
+ //
+ if ((GuardBitmap & BIT0) == 0) {
+ //
+ // If the head Guard is not a tail Guard of adjacent memory block,
+ // unset it.
+ //
+ UnsetGuardPage (GuardPage);
+ }
+ } else {
+ //
+ // Pages before memory to free are still in Guard. It's a partial free
+ // case. Turn first page of memory block to free into a new Guard.
+ //
+ SetGuardPage (Memory);
+ }
+
+ //
+ // Tail Guard must be the page after this memory block to free, if any.
+ //
+ // MSB-> 1 0 <-LSB
+ // --------------------
+ // 1 0 <- Tail Guard -> Don't free Tail Guard (shared Guard)
+ // 0 0 <- Tail Guard -> Free Tail Guard either (not shared Guard)
+ // X 1 -> Don't free last page (need a new Guard)
+ // (it'll be turned into a Guard page later)
+ // --------------------
+ // +1 +0 <- End
+ //
+ GuardPage = Memory + EFI_PAGES_TO_SIZE (NumberOfPages);
+ GuardBitmap = GetGuardedMemoryBits (GuardPage, 2);
+ if ((GuardBitmap & BIT0) == 0) {
+ //
+ // Tail Guard exists.
+ //
+ if ((GuardBitmap & BIT1) == 0) {
+ //
+ // If the tail Guard is not a head Guard of adjacent memory block,
+ // free it; otherwise, keep it.
+ //
+ UnsetGuardPage (GuardPage);
+ }
+ } else {
+ //
+ // Pages after memory to free are still in Guard. It's a partial free
+ // case. We need to keep one page to be a head Guard.
+ //
+ SetGuardPage (GuardPage - EFI_PAGES_TO_SIZE (1));
+ }
+
+ //
+ // No matter what, we just clear the mark of the Guarded memory.
+ //
+ ClearGuardedMemoryBits (Memory, NumberOfPages);
+}
+
+/**
+ Adjust address of free memory according to existing and/or required Guard.
+
+ This function will check if there're existing Guard pages of adjacent
+ memory blocks, and try to use it as the Guard page of the memory to be
+ allocated.
+
+ @param[in] Start Start address of free memory block.
+ @param[in] Size Size of free memory block.
+ @param[in] SizeRequested Size of memory to allocate.
+
+ @return The end address of memory block found.
+ @return 0 if no enough space for the required size of memory and its Guard.
+**/
+UINT64
+AdjustMemoryS (
+ IN UINT64 Start,
+ IN UINT64 Size,
+ IN UINT64 SizeRequested
+ )
+{
+ UINT64 Target;
+
+ //
+ // UEFI spec requires that allocated pool must be 8-byte aligned. If it's
+ // indicated to put the pool near the Tail Guard, we need extra bytes to
+ // make sure alignment of the returned pool address.
+ //
+ if ((PcdGet8 (PcdHeapGuardPropertyMask) & BIT7) == 0) {
+ SizeRequested = ALIGN_VALUE (SizeRequested, 8);
+ }
+
+ Target = Start + Size - SizeRequested;
+ ASSERT (Target >= Start);
+ if (Target == 0) {
+ return 0;
+ }
+
+ if (!IsGuardPage (Start + Size)) {
+ // No Guard at tail to share. One more page is needed.
+ Target -= EFI_PAGES_TO_SIZE (1);
+ }
+
+ // Out of range?
+ if (Target < Start) {
+ return 0;
+ }
+
+ // At the edge?
+ if (Target == Start) {
+ if (!IsGuardPage (Target - EFI_PAGES_TO_SIZE (1))) {
+ // No enough space for a new head Guard if no Guard at head to share.
+ return 0;
+ }
+ }
+
+ // OK, we have enough pages for memory and its Guards. Return the End of the
+ // free space.
+ return Target + SizeRequested - 1;
+}
+
+/**
+ Adjust the start address and number of pages to free according to Guard.
+
+ The purpose of this function is to keep the shared Guard page with adjacent
+ memory block if it's still in guard, or free it if no more sharing. Another
+ is to reserve pages as Guard pages in partial page free situation.
+
+ @param[in,out] Memory Base address of memory to free.
+ @param[in,out] NumberOfPages Size of memory to free.
+
+ @return VOID.
+**/
+VOID
+AdjustMemoryF (
+ IN OUT EFI_PHYSICAL_ADDRESS *Memory,
+ IN OUT UINTN *NumberOfPages
+ )
+{
+ EFI_PHYSICAL_ADDRESS Start;
+ EFI_PHYSICAL_ADDRESS MemoryToTest;
+ UINTN PagesToFree;
+ UINT64 GuardBitmap;
+
+ if ((Memory == NULL) || (NumberOfPages == NULL) || (*NumberOfPages == 0)) {
+ return;
+ }
+
+ Start = *Memory;
+ PagesToFree = *NumberOfPages;
+
+ //
+ // Head Guard must be one page before, if any.
+ //
+ // MSB-> 1 0 <-LSB
+ // -------------------
+ // Head Guard -> 0 1 -> Don't free Head Guard (shared Guard)
+ // Head Guard -> 0 0 -> Free Head Guard either (not shared Guard)
+ // 1 X -> Don't free first page (need a new Guard)
+ // (it'll be turned into a Guard page later)
+ // -------------------
+ // Start -> -1 -2
+ //
+ MemoryToTest = Start - EFI_PAGES_TO_SIZE (2);
+ GuardBitmap = GetGuardedMemoryBits (MemoryToTest, 2);
+ if ((GuardBitmap & BIT1) == 0) {
+ //
+ // Head Guard exists.
+ //
+ if ((GuardBitmap & BIT0) == 0) {
+ //
+ // If the head Guard is not a tail Guard of adjacent memory block,
+ // free it; otherwise, keep it.
+ //
+ Start -= EFI_PAGES_TO_SIZE (1);
+ PagesToFree += 1;
+ }
+ } else {
+ //
+ // No Head Guard, and pages before memory to free are still in Guard. It's a
+ // partial free case. We need to keep one page to be a tail Guard.
+ //
+ Start += EFI_PAGES_TO_SIZE (1);
+ PagesToFree -= 1;
+ }
+
+ //
+ // Tail Guard must be the page after this memory block to free, if any.
+ //
+ // MSB-> 1 0 <-LSB
+ // --------------------
+ // 1 0 <- Tail Guard -> Don't free Tail Guard (shared Guard)
+ // 0 0 <- Tail Guard -> Free Tail Guard either (not shared Guard)
+ // X 1 -> Don't free last page (need a new Guard)
+ // (it'll be turned into a Guard page later)
+ // --------------------
+ // +1 +0 <- End
+ //
+ MemoryToTest = Start + EFI_PAGES_TO_SIZE (PagesToFree);
+ GuardBitmap = GetGuardedMemoryBits (MemoryToTest, 2);
+ if ((GuardBitmap & BIT0) == 0) {
+ //
+ // Tail Guard exists.
+ //
+ if ((GuardBitmap & BIT1) == 0) {
+ //
+ // If the tail Guard is not a head Guard of adjacent memory block,
+ // free it; otherwise, keep it.
+ //
+ PagesToFree += 1;
+ }
+ } else if (PagesToFree > 0) {
+ //
+ // No Tail Guard, and pages after memory to free are still in Guard. It's a
+ // partial free case. We need to keep one page to be a head Guard.
+ //
+ PagesToFree -= 1;
+ }
+
+ *Memory = Start;
+ *NumberOfPages = PagesToFree;
+}
+
+/**
+ Adjust the base and number of pages to really allocate according to Guard.
+
+ @param[in,out] Memory Base address of free memory.
+ @param[in,out] NumberOfPages Size of memory to allocate.
+
+ @return VOID.
+**/
+VOID
+AdjustMemoryA (
+ IN OUT EFI_PHYSICAL_ADDRESS *Memory,
+ IN OUT UINTN *NumberOfPages
+ )
+{
+ //
+ // FindFreePages() has already taken the Guard into account. It's safe to
+ // adjust the start address and/or number of pages here, to make sure that
+ // the Guards are also "allocated".
+ //
+ if (!IsGuardPage (*Memory + EFI_PAGES_TO_SIZE (*NumberOfPages))) {
+ // No tail Guard, add one.
+ *NumberOfPages += 1;
+ }
+
+ if (!IsGuardPage (*Memory - EFI_PAGE_SIZE)) {
+ // No head Guard, add one.
+ *Memory -= EFI_PAGE_SIZE;
+ *NumberOfPages += 1;
+ }
+}
+
+/**
+ Adjust the pool head position to make sure the Guard page is adjavent to
+ pool tail or pool head.
+
+ @param[in] Memory Base address of memory allocated.
+ @param[in] NoPages Number of pages actually allocated.
+ @param[in] Size Size of memory requested.
+ (plus pool head/tail overhead)
+
+ @return Address of pool head.
+**/
+VOID *
+AdjustPoolHeadA (
+ IN EFI_PHYSICAL_ADDRESS Memory,
+ IN UINTN NoPages,
+ IN UINTN Size
+ )
+{
+ if ((Memory == 0) || ((PcdGet8 (PcdHeapGuardPropertyMask) & BIT7) != 0)) {
+ //
+ // Pool head is put near the head Guard
+ //
+ return (VOID *)(UINTN)Memory;
+ }
+
+ //
+ // Pool head is put near the tail Guard
+ //
+ Size = ALIGN_VALUE (Size, 8);
+ return (VOID *)(UINTN)(Memory + EFI_PAGES_TO_SIZE (NoPages) - Size);
+}
+
+/**
+ Get the page base address according to pool head address.
+
+ @param[in] Memory Head address of pool to free.
+ @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 *
+AdjustPoolHeadF (
+ 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. We need to exactly undo the addition done in AdjustPoolHeadA
+ // because we may not have allocated the pool head on the first allocated page, since we are aligned to
+ // the tail and on some architectures, the runtime page allocation granularity is > one page. So we allocate
+ // more pages than we need and put the pool head somewhere past the first page.
+ //
+ return (VOID *)(UINTN)(Memory + Size - EFI_PAGES_TO_SIZE (NoPages));
+}
+
+/**
+ Allocate or free guarded memory.
+
+ @param[in] Start Start address of memory to allocate or free.
+ @param[in] NumberOfPages Memory size in pages.
+ @param[in] NewType Memory type to convert to.
+
+ @return VOID.
+**/
+EFI_STATUS
+CoreConvertPagesWithGuard (
+ IN UINT64 Start,
+ IN UINTN NumberOfPages,
+ IN EFI_MEMORY_TYPE NewType
+ )
+{
+ UINT64 OldStart;
+ UINTN OldPages;
+
+ if (NewType == EfiConventionalMemory) {
+ OldStart = Start;
+ OldPages = NumberOfPages;
+
+ AdjustMemoryF (&Start, &NumberOfPages);
+ //
+ // It's safe to unset Guard page inside memory lock because there should
+ // be no memory allocation occurred in updating memory page attribute at
+ // this point. And unsetting Guard page before free will prevent Guard
+ // page just freed back to pool from being allocated right away before
+ // marking it usable (from non-present to present).
+ //
+ UnsetGuardForMemory (OldStart, OldPages);
+ if (NumberOfPages == 0) {
+ return EFI_SUCCESS;
+ }
+ } else {
+ AdjustMemoryA (&Start, &NumberOfPages);
+ }
+
+ return CoreConvertPages (Start, NumberOfPages, NewType);
+}
+
+/**
+ Set all Guard pages which cannot be set before CPU Arch Protocol installed.
+**/
+VOID
+SetAllGuardPages (
+ VOID
+ )
+{
+ UINTN Entries[GUARDED_HEAP_MAP_TABLE_DEPTH];
+ UINTN Shifts[GUARDED_HEAP_MAP_TABLE_DEPTH];
+ UINTN Indices[GUARDED_HEAP_MAP_TABLE_DEPTH];
+ UINT64 Tables[GUARDED_HEAP_MAP_TABLE_DEPTH];
+ UINT64 Addresses[GUARDED_HEAP_MAP_TABLE_DEPTH];
+ UINT64 TableEntry;
+ UINT64 Address;
+ UINT64 GuardPage;
+ INTN Level;
+ UINTN Index;
+ BOOLEAN OnGuarding;
+
+ if ((mGuardedMemoryMap == 0) ||
+ (mMapLevel == 0) ||
+ (mMapLevel > GUARDED_HEAP_MAP_TABLE_DEPTH))
+ {
+ return;
+ }
+
+ CopyMem (Entries, mLevelMask, sizeof (Entries));
+ CopyMem (Shifts, mLevelShift, sizeof (Shifts));
+
+ SetMem (Tables, sizeof (Tables), 0);
+ SetMem (Addresses, sizeof (Addresses), 0);
+ SetMem (Indices, sizeof (Indices), 0);
+
+ Level = GUARDED_HEAP_MAP_TABLE_DEPTH - mMapLevel;
+ Tables[Level] = mGuardedMemoryMap;
+ Address = 0;
+ OnGuarding = FALSE;
+
+ DEBUG_CODE (
+ DumpGuardedMemoryBitmap ();
+ );
+
+ while (TRUE) {
+ if (Indices[Level] > Entries[Level]) {
+ Tables[Level] = 0;
+ Level -= 1;
+ } else {
+ TableEntry = ((UINT64 *)(UINTN)(Tables[Level]))[Indices[Level]];
+ Address = Addresses[Level];
+
+ if (TableEntry == 0) {
+ OnGuarding = FALSE;
+ } else if (Level < GUARDED_HEAP_MAP_TABLE_DEPTH - 1) {
+ Level += 1;
+ Tables[Level] = TableEntry;
+ Addresses[Level] = Address;
+ Indices[Level] = 0;
+
+ continue;
+ } else {
+ Index = 0;
+ while (Index < GUARDED_HEAP_MAP_ENTRY_BITS) {
+ if ((TableEntry & 1) == 1) {
+ if (OnGuarding) {
+ GuardPage = 0;
+ } else {
+ GuardPage = Address - EFI_PAGE_SIZE;
+ }
+
+ OnGuarding = TRUE;
+ } else {
+ if (OnGuarding) {
+ GuardPage = Address;
+ } else {
+ GuardPage = 0;
+ }
+
+ OnGuarding = FALSE;
+ }
+
+ if (GuardPage != 0) {
+ SetGuardPage (GuardPage);
+ }
+
+ if (TableEntry == 0) {
+ break;
+ }
+
+ TableEntry = RShiftU64 (TableEntry, 1);
+ Address += EFI_PAGE_SIZE;
+ Index += 1;
+ }
+ }
+ }
+
+ if (Level < (GUARDED_HEAP_MAP_TABLE_DEPTH - (INTN)mMapLevel)) {
+ break;
+ }
+
+ Indices[Level] += 1;
+ Address = (Level == 0) ? 0 : Addresses[Level - 1];
+ Addresses[Level] = Address | LShiftU64 (Indices[Level], Shifts[Level]);
+ }
+}
+
+/**
+ Find the address of top-most guarded free page.
+
+ @param[out] Address Start address of top-most guarded free page.
+
+ @return VOID.
+**/
+VOID
+GetLastGuardedFreePageAddress (
+ OUT EFI_PHYSICAL_ADDRESS *Address
+ )
+{
+ EFI_PHYSICAL_ADDRESS AddressGranularity;
+ EFI_PHYSICAL_ADDRESS BaseAddress;
+ UINTN Level;
+ UINT64 Map;
+ INTN Index;
+
+ ASSERT (mMapLevel >= 1);
+
+ BaseAddress = 0;
+ Map = mGuardedMemoryMap;
+ for (Level = GUARDED_HEAP_MAP_TABLE_DEPTH - mMapLevel;
+ Level < GUARDED_HEAP_MAP_TABLE_DEPTH;
+ ++Level)
+ {
+ AddressGranularity = LShiftU64 (1, mLevelShift[Level]);
+
+ //
+ // Find the non-NULL entry at largest index.
+ //
+ for (Index = (INTN)mLevelMask[Level]; Index >= 0; --Index) {
+ if (((UINT64 *)(UINTN)Map)[Index] != 0) {
+ BaseAddress += MultU64x32 (AddressGranularity, (UINT32)Index);
+ Map = ((UINT64 *)(UINTN)Map)[Index];
+ break;
+ }
+ }
+ }
+
+ //
+ // Find the non-zero MSB then get the page address.
+ //
+ while (Map != 0) {
+ Map = RShiftU64 (Map, 1);
+ BaseAddress += EFI_PAGES_TO_SIZE (1);
+ }
+
+ *Address = BaseAddress;
+}
+
+/**
+ Record freed pages.
+
+ @param[in] BaseAddress Base address of just freed pages.
+ @param[in] Pages Number of freed pages.
+
+ @return VOID.
+**/
+VOID
+MarkFreedPages (
+ IN EFI_PHYSICAL_ADDRESS BaseAddress,
+ IN UINTN Pages
+ )
+{
+ SetGuardedMemoryBits (BaseAddress, Pages);
+}
+
+/**
+ Record freed pages as well as mark them as not-present.
+
+ @param[in] BaseAddress Base address of just freed pages.
+ @param[in] Pages Number of freed pages.
+
+ @return VOID.
+**/
+VOID
+EFIAPI
+GuardFreedPages (
+ IN EFI_PHYSICAL_ADDRESS BaseAddress,
+ IN UINTN Pages
+ )
+{
+ EFI_STATUS Status;
+
+ //
+ // Legacy memory lower than 1MB might be accessed with no allocation. Leave
+ // them alone.
+ //
+ if (BaseAddress < BASE_1MB) {
+ return;
+ }
+
+ MarkFreedPages (BaseAddress, Pages);
+ if (gCpu != NULL) {
+ //
+ // Set flag to make sure allocating memory without GUARD for page table
+ // operation; otherwise infinite loops could be caused.
+ //
+ mOnGuarding = TRUE;
+ //
+ // Note: This might overwrite other attributes needed by other features,
+ // such as NX memory protection.
+ //
+ Status = gCpu->SetMemoryAttributes (
+ gCpu,
+ BaseAddress,
+ EFI_PAGES_TO_SIZE (Pages),
+ EFI_MEMORY_RP
+ );
+ //
+ // Normally we should ASSERT the returned Status. But there might be memory
+ // alloc/free involved in SetMemoryAttributes(), which might fail this
+ // calling. It's rare case so it's OK to let a few tiny holes be not-guarded.
+ //
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_WARN, "Failed to guard freed pages: %p (%lu)\n", BaseAddress, (UINT64)Pages));
+ }
+
+ mOnGuarding = FALSE;
+ }
+}
+
+/**
+ Record freed pages as well as mark them as not-present, if enabled.
+
+ @param[in] BaseAddress Base address of just freed pages.
+ @param[in] Pages Number of freed pages.
+
+ @return VOID.
+**/
+VOID
+EFIAPI
+GuardFreedPagesChecked (
+ IN EFI_PHYSICAL_ADDRESS BaseAddress,
+ IN UINTN Pages
+ )
+{
+ if (IsHeapGuardEnabled (GUARD_HEAP_TYPE_FREED)) {
+ GuardFreedPages (BaseAddress, Pages);
+ }
+}
+
+/**
+ Mark all pages freed before CPU Arch Protocol as not-present.
+
+**/
+VOID
+GuardAllFreedPages (
+ VOID
+ )
+{
+ UINTN Entries[GUARDED_HEAP_MAP_TABLE_DEPTH];
+ UINTN Shifts[GUARDED_HEAP_MAP_TABLE_DEPTH];
+ UINTN Indices[GUARDED_HEAP_MAP_TABLE_DEPTH];
+ UINT64 Tables[GUARDED_HEAP_MAP_TABLE_DEPTH];
+ UINT64 Addresses[GUARDED_HEAP_MAP_TABLE_DEPTH];
+ UINT64 TableEntry;
+ UINT64 Address;
+ UINT64 GuardPage;
+ INTN Level;
+ UINT64 BitIndex;
+ UINTN GuardPageNumber;
+
+ if ((mGuardedMemoryMap == 0) ||
+ (mMapLevel == 0) ||
+ (mMapLevel > GUARDED_HEAP_MAP_TABLE_DEPTH))
+ {
+ return;
+ }
+
+ CopyMem (Entries, mLevelMask, sizeof (Entries));
+ CopyMem (Shifts, mLevelShift, sizeof (Shifts));
+
+ SetMem (Tables, sizeof (Tables), 0);
+ SetMem (Addresses, sizeof (Addresses), 0);
+ SetMem (Indices, sizeof (Indices), 0);
+
+ Level = GUARDED_HEAP_MAP_TABLE_DEPTH - mMapLevel;
+ Tables[Level] = mGuardedMemoryMap;
+ Address = 0;
+ GuardPage = (UINT64)-1;
+ GuardPageNumber = 0;
+
+ while (TRUE) {
+ if (Indices[Level] > Entries[Level]) {
+ Tables[Level] = 0;
+ Level -= 1;
+ } else {
+ TableEntry = ((UINT64 *)(UINTN)(Tables[Level]))[Indices[Level]];
+ Address = Addresses[Level];
+
+ if (Level < GUARDED_HEAP_MAP_TABLE_DEPTH - 1) {
+ Level += 1;
+ Tables[Level] = TableEntry;
+ Addresses[Level] = Address;
+ Indices[Level] = 0;
+
+ continue;
+ } else {
+ BitIndex = 1;
+ while (BitIndex != 0) {
+ if ((TableEntry & BitIndex) != 0) {
+ if (GuardPage == (UINT64)-1) {
+ GuardPage = Address;
+ }
+
+ ++GuardPageNumber;
+ } else if (GuardPageNumber > 0) {
+ GuardFreedPages (GuardPage, GuardPageNumber);
+ GuardPageNumber = 0;
+ GuardPage = (UINT64)-1;
+ }
+
+ if (TableEntry == 0) {
+ break;
+ }
+
+ Address += EFI_PAGES_TO_SIZE (1);
+ BitIndex = LShiftU64 (BitIndex, 1);
+ }
+ }
+ }
+
+ if (Level < (GUARDED_HEAP_MAP_TABLE_DEPTH - (INTN)mMapLevel)) {
+ break;
+ }
+
+ Indices[Level] += 1;
+ Address = (Level == 0) ? 0 : Addresses[Level - 1];
+ Addresses[Level] = Address | LShiftU64 (Indices[Level], Shifts[Level]);
+ }
+
+ //
+ // Update the maximum address of freed page which can be used for memory
+ // promotion upon out-of-memory-space.
+ //
+ GetLastGuardedFreePageAddress (&Address);
+ if (Address != 0) {
+ mLastPromotedPage = Address;
+ }
+}
+
+/**
+ This function checks to see if the given memory map descriptor in a memory map
+ can be merged with any guarded free pages.
+
+ @param MemoryMapEntry A pointer to a descriptor in MemoryMap.
+ @param MaxAddress Maximum address to stop the merge.
+
+ @return VOID
+
+**/
+VOID
+MergeGuardPages (
+ IN EFI_MEMORY_DESCRIPTOR *MemoryMapEntry,
+ IN EFI_PHYSICAL_ADDRESS MaxAddress
+ )
+{
+ EFI_PHYSICAL_ADDRESS EndAddress;
+ UINT64 Bitmap;
+ INTN Pages;
+
+ if (!IsHeapGuardEnabled (GUARD_HEAP_TYPE_FREED) ||
+ (MemoryMapEntry->Type >= EfiMemoryMappedIO))
+ {
+ return;
+ }
+
+ Bitmap = 0;
+ Pages = EFI_SIZE_TO_PAGES ((UINTN)(MaxAddress - MemoryMapEntry->PhysicalStart));
+ Pages -= (INTN)MemoryMapEntry->NumberOfPages;
+ while (Pages > 0) {
+ if (Bitmap == 0) {
+ EndAddress = MemoryMapEntry->PhysicalStart +
+ EFI_PAGES_TO_SIZE ((UINTN)MemoryMapEntry->NumberOfPages);
+ Bitmap = GetGuardedMemoryBits (EndAddress, GUARDED_HEAP_MAP_ENTRY_BITS);
+ }
+
+ if ((Bitmap & 1) == 0) {
+ break;
+ }
+
+ Pages--;
+ MemoryMapEntry->NumberOfPages++;
+ Bitmap = RShiftU64 (Bitmap, 1);
+ }
+}
+
+/**
+ Put part (at most 64 pages a time) guarded free pages back to free page pool.
+
+ Freed memory guard is used to detect Use-After-Free (UAF) memory issue, which
+ makes use of 'Used then throw away' way to detect any illegal access to freed
+ memory. The thrown-away memory will be marked as not-present so that any access
+ to those memory (after free) will be caught by page-fault exception.
+
+ The problem is that this will consume lots of memory space. Once no memory
+ left in pool to allocate, we have to restore part of the freed pages to their
+ normal function. Otherwise the whole system will stop functioning.
+
+ @param StartAddress Start address of promoted memory.
+ @param EndAddress End address of promoted memory.
+
+ @return TRUE Succeeded to promote memory.
+ @return FALSE No free memory found.
+
+**/
+BOOLEAN
+PromoteGuardedFreePages (
+ OUT EFI_PHYSICAL_ADDRESS *StartAddress,
+ OUT EFI_PHYSICAL_ADDRESS *EndAddress
+ )
+{
+ EFI_STATUS Status;
+ UINTN AvailablePages;
+ UINT64 Bitmap;
+ EFI_PHYSICAL_ADDRESS Start;
+
+ if (!IsHeapGuardEnabled (GUARD_HEAP_TYPE_FREED)) {
+ return FALSE;
+ }
+
+ //
+ // Similar to memory allocation service, always search the freed pages in
+ // descending direction.
+ //
+ Start = mLastPromotedPage;
+ AvailablePages = 0;
+ while (AvailablePages == 0) {
+ Start -= EFI_PAGES_TO_SIZE (GUARDED_HEAP_MAP_ENTRY_BITS);
+ //
+ // If the address wraps around, try the really freed pages at top.
+ //
+ if (Start > mLastPromotedPage) {
+ GetLastGuardedFreePageAddress (&Start);
+ ASSERT (Start != 0);
+ Start -= EFI_PAGES_TO_SIZE (GUARDED_HEAP_MAP_ENTRY_BITS);
+ }
+
+ Bitmap = GetGuardedMemoryBits (Start, GUARDED_HEAP_MAP_ENTRY_BITS);
+ while (Bitmap > 0) {
+ if ((Bitmap & 1) != 0) {
+ ++AvailablePages;
+ } else if (AvailablePages == 0) {
+ Start += EFI_PAGES_TO_SIZE (1);
+ } else {
+ break;
+ }
+
+ Bitmap = RShiftU64 (Bitmap, 1);
+ }
+ }
+
+ if (AvailablePages != 0) {
+ DEBUG ((DEBUG_INFO, "Promoted pages: %lX (%lx)\r\n", Start, (UINT64)AvailablePages));
+ ClearGuardedMemoryBits (Start, AvailablePages);
+
+ if (gCpu != NULL) {
+ //
+ // Set flag to make sure allocating memory without GUARD for page table
+ // operation; otherwise infinite loops could be caused.
+ //
+ mOnGuarding = TRUE;
+ Status = gCpu->SetMemoryAttributes (gCpu, Start, EFI_PAGES_TO_SIZE (AvailablePages), 0);
+ ASSERT_EFI_ERROR (Status);
+ mOnGuarding = FALSE;
+ }
+
+ mLastPromotedPage = Start;
+ *StartAddress = Start;
+ *EndAddress = Start + EFI_PAGES_TO_SIZE (AvailablePages) - 1;
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+/**
+ Notify function used to set all Guard pages before CPU Arch Protocol installed.
+**/
+VOID
+HeapGuardCpuArchProtocolNotify (
+ VOID
+ )
+{
+ ASSERT (gCpu != NULL);
+
+ if (IsHeapGuardEnabled (GUARD_HEAP_TYPE_PAGE|GUARD_HEAP_TYPE_POOL) &&
+ IsHeapGuardEnabled (GUARD_HEAP_TYPE_FREED))
+ {
+ DEBUG ((DEBUG_ERROR, "Heap guard and freed memory guard cannot be enabled at the same time.\n"));
+ CpuDeadLoop ();
+ }
+
+ if (IsHeapGuardEnabled (GUARD_HEAP_TYPE_PAGE|GUARD_HEAP_TYPE_POOL)) {
+ SetAllGuardPages ();
+ }
+
+ if (IsHeapGuardEnabled (GUARD_HEAP_TYPE_FREED)) {
+ GuardAllFreedPages ();
+ }
+}
+
+/**
+ Helper function to convert a UINT64 value in binary to a string.
+
+ @param[in] Value Value of a UINT64 integer.
+ @param[out] BinString String buffer to contain the conversion result.
+
+ @return VOID.
+**/
+VOID
+Uint64ToBinString (
+ IN UINT64 Value,
+ OUT CHAR8 *BinString
+ )
+{
+ UINTN Index;
+
+ if (BinString == NULL) {
+ return;
+ }
+
+ for (Index = 64; Index > 0; --Index) {
+ BinString[Index - 1] = '0' + (Value & 1);
+ Value = RShiftU64 (Value, 1);
+ }
+
+ BinString[64] = '\0';
+}
+
+/**
+ Dump the guarded memory bit map.
+**/
+VOID
+EFIAPI
+DumpGuardedMemoryBitmap (
+ VOID
+ )
+{
+ UINTN Entries[GUARDED_HEAP_MAP_TABLE_DEPTH];
+ UINTN Shifts[GUARDED_HEAP_MAP_TABLE_DEPTH];
+ UINTN Indices[GUARDED_HEAP_MAP_TABLE_DEPTH];
+ UINT64 Tables[GUARDED_HEAP_MAP_TABLE_DEPTH];
+ UINT64 Addresses[GUARDED_HEAP_MAP_TABLE_DEPTH];
+ UINT64 TableEntry;
+ UINT64 Address;
+ INTN Level;
+ UINTN RepeatZero;
+ CHAR8 String[GUARDED_HEAP_MAP_ENTRY_BITS + 1];
+ CHAR8 *Ruler1;
+ CHAR8 *Ruler2;
+
+ if (!IsHeapGuardEnabled (GUARD_HEAP_TYPE_ALL)) {
+ return;
+ }
+
+ if ((mGuardedMemoryMap == 0) ||
+ (mMapLevel == 0) ||
+ (mMapLevel > GUARDED_HEAP_MAP_TABLE_DEPTH))
+ {
+ return;
+ }
+
+ Ruler1 = " 3 2 1 0";
+ Ruler2 = "FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210";
+
+ DEBUG ((
+ HEAP_GUARD_DEBUG_LEVEL,
+ "============================="
+ " Guarded Memory Bitmap "
+ "==============================\r\n"
+ ));
+ DEBUG ((HEAP_GUARD_DEBUG_LEVEL, " %a\r\n", Ruler1));
+ DEBUG ((HEAP_GUARD_DEBUG_LEVEL, " %a\r\n", Ruler2));
+
+ CopyMem (Entries, mLevelMask, sizeof (Entries));
+ CopyMem (Shifts, mLevelShift, sizeof (Shifts));
+
+ SetMem (Indices, sizeof (Indices), 0);
+ SetMem (Tables, sizeof (Tables), 0);
+ SetMem (Addresses, sizeof (Addresses), 0);
+
+ Level = GUARDED_HEAP_MAP_TABLE_DEPTH - mMapLevel;
+ Tables[Level] = mGuardedMemoryMap;
+ Address = 0;
+ RepeatZero = 0;
+
+ while (TRUE) {
+ if (Indices[Level] > Entries[Level]) {
+ Tables[Level] = 0;
+ Level -= 1;
+ RepeatZero = 0;
+
+ DEBUG ((
+ HEAP_GUARD_DEBUG_LEVEL,
+ "========================================="
+ "=========================================\r\n"
+ ));
+ } else {
+ TableEntry = ((UINT64 *)(UINTN)Tables[Level])[Indices[Level]];
+ Address = Addresses[Level];
+
+ if (TableEntry == 0) {
+ if (Level == GUARDED_HEAP_MAP_TABLE_DEPTH - 1) {
+ if (RepeatZero == 0) {
+ Uint64ToBinString (TableEntry, String);
+ DEBUG ((HEAP_GUARD_DEBUG_LEVEL, "%016lx: %a\r\n", Address, String));
+ } else if (RepeatZero == 1) {
+ DEBUG ((HEAP_GUARD_DEBUG_LEVEL, "... : ...\r\n"));
+ }
+
+ RepeatZero += 1;
+ }
+ } else if (Level < GUARDED_HEAP_MAP_TABLE_DEPTH - 1) {
+ Level += 1;
+ Tables[Level] = TableEntry;
+ Addresses[Level] = Address;
+ Indices[Level] = 0;
+ RepeatZero = 0;
+
+ continue;
+ } else {
+ RepeatZero = 0;
+ Uint64ToBinString (TableEntry, String);
+ DEBUG ((HEAP_GUARD_DEBUG_LEVEL, "%016lx: %a\r\n", Address, String));
+ }
+ }
+
+ if (Level < (GUARDED_HEAP_MAP_TABLE_DEPTH - (INTN)mMapLevel)) {
+ break;
+ }
+
+ Indices[Level] += 1;
+ Address = (Level == 0) ? 0 : Addresses[Level - 1];
+ Addresses[Level] = Address | LShiftU64 (Indices[Level], Shifts[Level]);
+ }
+}
diff --git a/MdeModulePkg/Core/Dxe/Mem/HeapGuard.h b/MdeModulePkg/Core/Dxe/Mem/HeapGuard.h
index 578e857465..fa108527c3 100644
--- a/MdeModulePkg/Core/Dxe/Mem/HeapGuard.h
+++ b/MdeModulePkg/Core/Dxe/Mem/HeapGuard.h
@@ -1,486 +1,486 @@
-/** @file
- Data type, macros and function prototypes of heap guard feature.
-
-Copyright (c) 2017-2018, Intel Corporation. All rights reserved.<BR>
-SPDX-License-Identifier: BSD-2-Clause-Patent
-
-**/
-
-#ifndef _HEAPGUARD_H_
-#define _HEAPGUARD_H_
-
-//
-// Following macros are used to define and access the guarded memory bitmap
-// table.
-//
-// To simplify the access and reduce the memory used for this table, the
-// table is constructed in the similar way as page table structure but in
-// reverse direction, i.e. from bottom growing up to top.
-//
-// - 1-bit tracks 1 page (4KB)
-// - 1-UINT64 map entry tracks 256KB memory
-// - 1K-UINT64 map table tracks 256MB memory
-// - Five levels of tables can track any address of memory of 64-bit
-// system, like below.
-//
-// 512 * 512 * 512 * 512 * 1K * 64b * 4K
-// 111111111 111111111 111111111 111111111 1111111111 111111 111111111111
-// 63 54 45 36 27 17 11 0
-// 9b 9b 9b 9b 10b 6b 12b
-// L0 -> L1 -> L2 -> L3 -> L4 -> bits -> page
-// 1FF 1FF 1FF 1FF 3FF 3F FFF
-//
-// L4 table has 1K * sizeof(UINT64) = 8K (2-page), which can track 256MB
-// memory. Each table of L0-L3 will be allocated when its memory address
-// range is to be tracked. Only 1-page will be allocated each time. This
-// can save memories used to establish this map table.
-//
-// For a normal configuration of system with 4G memory, two levels of tables
-// can track the whole memory, because two levels (L3+L4) of map tables have
-// already coverred 37-bit of memory address. And for a normal UEFI BIOS,
-// less than 128M memory would be consumed during boot. That means we just
-// need
-//
-// 1-page (L3) + 2-page (L4)
-//
-// memory (3 pages) to track the memory allocation works. In this case,
-// there's no need to setup L0-L2 tables.
-//
-
-//
-// Each entry occupies 8B/64b. 1-page can hold 512 entries, which spans 9
-// bits in address. (512 = 1 << 9)
-//
-#define BYTE_LENGTH_SHIFT 3 // (8 = 1 << 3)
-
-#define GUARDED_HEAP_MAP_TABLE_ENTRY_SHIFT \
- (EFI_PAGE_SHIFT - BYTE_LENGTH_SHIFT)
-
-#define GUARDED_HEAP_MAP_TABLE_DEPTH 5
-
-// Use UINT64_index + bit_index_of_UINT64 to locate the bit in may
-#define GUARDED_HEAP_MAP_ENTRY_BIT_SHIFT 6 // (64 = 1 << 6)
-
-#define GUARDED_HEAP_MAP_ENTRY_BITS \
- (1 << GUARDED_HEAP_MAP_ENTRY_BIT_SHIFT)
-
-#define GUARDED_HEAP_MAP_ENTRY_BYTES \
- (GUARDED_HEAP_MAP_ENTRY_BITS / 8)
-
-// L4 table address width: 64 - 9 * 4 - 6 - 12 = 10b
-#define GUARDED_HEAP_MAP_ENTRY_SHIFT \
- (GUARDED_HEAP_MAP_ENTRY_BITS \
- - GUARDED_HEAP_MAP_TABLE_ENTRY_SHIFT * 4 \
- - GUARDED_HEAP_MAP_ENTRY_BIT_SHIFT \
- - EFI_PAGE_SHIFT)
-
-// L4 table address mask: (1 << 10 - 1) = 0x3FF
-#define GUARDED_HEAP_MAP_ENTRY_MASK \
- ((1 << GUARDED_HEAP_MAP_ENTRY_SHIFT) - 1)
-
-// Size of each L4 table: (1 << 10) * 8 = 8KB = 2-page
-#define GUARDED_HEAP_MAP_SIZE \
- ((1 << GUARDED_HEAP_MAP_ENTRY_SHIFT) * GUARDED_HEAP_MAP_ENTRY_BYTES)
-
-// Memory size tracked by one L4 table: 8KB * 8 * 4KB = 256MB
-#define GUARDED_HEAP_MAP_UNIT_SIZE \
- (GUARDED_HEAP_MAP_SIZE * 8 * EFI_PAGE_SIZE)
-
-// L4 table entry number: 8KB / 8 = 1024
-#define GUARDED_HEAP_MAP_ENTRIES_PER_UNIT \
- (GUARDED_HEAP_MAP_SIZE / GUARDED_HEAP_MAP_ENTRY_BYTES)
-
-// L4 table entry indexing
-#define GUARDED_HEAP_MAP_ENTRY_INDEX(Address) \
- (RShiftU64 (Address, EFI_PAGE_SHIFT \
- + GUARDED_HEAP_MAP_ENTRY_BIT_SHIFT) \
- & GUARDED_HEAP_MAP_ENTRY_MASK)
-
-// L4 table entry bit indexing
-#define GUARDED_HEAP_MAP_ENTRY_BIT_INDEX(Address) \
- (RShiftU64 (Address, EFI_PAGE_SHIFT) \
- & ((1 << GUARDED_HEAP_MAP_ENTRY_BIT_SHIFT) - 1))
-
-//
-// Total bits (pages) tracked by one L4 table (65536-bit)
-//
-#define GUARDED_HEAP_MAP_BITS \
- (1 << (GUARDED_HEAP_MAP_ENTRY_SHIFT \
- + GUARDED_HEAP_MAP_ENTRY_BIT_SHIFT))
-
-//
-// Bit indexing inside the whole L4 table (0 - 65535)
-//
-#define GUARDED_HEAP_MAP_BIT_INDEX(Address) \
- (RShiftU64 (Address, EFI_PAGE_SHIFT) \
- & ((1 << (GUARDED_HEAP_MAP_ENTRY_SHIFT \
- + GUARDED_HEAP_MAP_ENTRY_BIT_SHIFT)) - 1))
-
-//
-// Memory address bit width tracked by L4 table: 10 + 6 + 12 = 28
-//
-#define GUARDED_HEAP_MAP_TABLE_SHIFT \
- (GUARDED_HEAP_MAP_ENTRY_SHIFT + GUARDED_HEAP_MAP_ENTRY_BIT_SHIFT \
- + EFI_PAGE_SHIFT)
-
-//
-// Macro used to initialize the local array variable for map table traversing
-// {55, 46, 37, 28, 18}
-//
-#define GUARDED_HEAP_MAP_TABLE_DEPTH_SHIFTS \
- { \
- GUARDED_HEAP_MAP_TABLE_SHIFT + GUARDED_HEAP_MAP_TABLE_ENTRY_SHIFT * 3, \
- GUARDED_HEAP_MAP_TABLE_SHIFT + GUARDED_HEAP_MAP_TABLE_ENTRY_SHIFT * 2, \
- GUARDED_HEAP_MAP_TABLE_SHIFT + GUARDED_HEAP_MAP_TABLE_ENTRY_SHIFT, \
- GUARDED_HEAP_MAP_TABLE_SHIFT, \
- EFI_PAGE_SHIFT + GUARDED_HEAP_MAP_ENTRY_BIT_SHIFT \
- }
-
-//
-// Masks used to extract address range of each level of table
-// {0x1FF, 0x1FF, 0x1FF, 0x1FF, 0x3FF}
-//
-#define GUARDED_HEAP_MAP_TABLE_DEPTH_MASKS \
- { \
- (1 << GUARDED_HEAP_MAP_TABLE_ENTRY_SHIFT) - 1, \
- (1 << GUARDED_HEAP_MAP_TABLE_ENTRY_SHIFT) - 1, \
- (1 << GUARDED_HEAP_MAP_TABLE_ENTRY_SHIFT) - 1, \
- (1 << GUARDED_HEAP_MAP_TABLE_ENTRY_SHIFT) - 1, \
- (1 << GUARDED_HEAP_MAP_ENTRY_SHIFT) - 1 \
- }
-
-//
-// Memory type to guard (matching the related PCD definition)
-//
-#define GUARD_HEAP_TYPE_PAGE BIT0
-#define GUARD_HEAP_TYPE_POOL BIT1
-#define GUARD_HEAP_TYPE_FREED BIT4
-#define GUARD_HEAP_TYPE_ALL \
- (GUARD_HEAP_TYPE_PAGE|GUARD_HEAP_TYPE_POOL|GUARD_HEAP_TYPE_FREED)
-
-//
-// Debug message level
-//
-#define HEAP_GUARD_DEBUG_LEVEL (DEBUG_POOL|DEBUG_PAGE)
-
-typedef struct {
- UINT32 TailMark;
- UINT32 HeadMark;
- EFI_PHYSICAL_ADDRESS Address;
- LIST_ENTRY Link;
-} HEAP_GUARD_NODE;
-
-/**
- Internal function. Converts a memory range to the specified type.
- The range must exist in the memory map.
-
- @param Start The first address of the range Must be page
- aligned.
- @param NumberOfPages The number of pages to convert.
- @param NewType The new type for the memory range.
-
- @retval EFI_INVALID_PARAMETER Invalid parameter.
- @retval EFI_NOT_FOUND Could not find a descriptor cover the specified
- range or convertion not allowed.
- @retval EFI_SUCCESS Successfully converts the memory range to the
- specified type.
-
-**/
-EFI_STATUS
-CoreConvertPages (
- IN UINT64 Start,
- IN UINT64 NumberOfPages,
- IN EFI_MEMORY_TYPE NewType
- );
-
-/**
- Allocate or free guarded memory.
-
- @param[in] Start Start address of memory to allocate or free.
- @param[in] NumberOfPages Memory size in pages.
- @param[in] NewType Memory type to convert to.
-
- @return VOID.
-**/
-EFI_STATUS
-CoreConvertPagesWithGuard (
- IN UINT64 Start,
- IN UINTN NumberOfPages,
- IN EFI_MEMORY_TYPE NewType
- );
-
-/**
- Set head Guard and tail Guard for the given memory range.
-
- @param[in] Memory Base address of memory to set guard for.
- @param[in] NumberOfPages Memory size in pages.
-
- @return VOID.
-**/
-VOID
-SetGuardForMemory (
- IN EFI_PHYSICAL_ADDRESS Memory,
- IN UINTN NumberOfPages
- );
-
-/**
- Unset head Guard and tail Guard for the given memory range.
-
- @param[in] Memory Base address of memory to unset guard for.
- @param[in] NumberOfPages Memory size in pages.
-
- @return VOID.
-**/
-VOID
-UnsetGuardForMemory (
- IN EFI_PHYSICAL_ADDRESS Memory,
- IN UINTN NumberOfPages
- );
-
-/**
- Adjust the base and number of pages to really allocate according to Guard.
-
- @param[in,out] Memory Base address of free memory.
- @param[in,out] NumberOfPages Size of memory to allocate.
-
- @return VOID.
-**/
-VOID
-AdjustMemoryA (
- IN OUT EFI_PHYSICAL_ADDRESS *Memory,
- IN OUT UINTN *NumberOfPages
- );
-
-/**
- Adjust the start address and number of pages to free according to Guard.
-
- The purpose of this function is to keep the shared Guard page with adjacent
- memory block if it's still in guard, or free it if no more sharing. Another
- is to reserve pages as Guard pages in partial page free situation.
-
- @param[in,out] Memory Base address of memory to free.
- @param[in,out] NumberOfPages Size of memory to free.
-
- @return VOID.
-**/
-VOID
-AdjustMemoryF (
- IN OUT EFI_PHYSICAL_ADDRESS *Memory,
- IN OUT UINTN *NumberOfPages
- );
-
-/**
- Adjust address of free memory according to existing and/or required Guard.
-
- This function will check if there're existing Guard pages of adjacent
- memory blocks, and try to use it as the Guard page of the memory to be
- allocated.
-
- @param[in] Start Start address of free memory block.
- @param[in] Size Size of free memory block.
- @param[in] SizeRequested Size of memory to allocate.
-
- @return The end address of memory block found.
- @return 0 if no enough space for the required size of memory and its Guard.
-**/
-UINT64
-AdjustMemoryS (
- IN UINT64 Start,
- IN UINT64 Size,
- IN UINT64 SizeRequested
- );
-
-/**
- Check to see if the pool at the given address should be guarded or not.
-
- @param[in] MemoryType Pool type to check.
-
-
- @return TRUE The given type of pool should be guarded.
- @return FALSE The given type of pool should not be guarded.
-**/
-BOOLEAN
-IsPoolTypeToGuard (
- IN EFI_MEMORY_TYPE MemoryType
- );
-
-/**
- Check to see if the page at the given address should be guarded or not.
-
- @param[in] MemoryType Page type to check.
- @param[in] AllocateType Allocation type to check.
-
- @return TRUE The given type of page should be guarded.
- @return FALSE The given type of page should not be guarded.
-**/
-BOOLEAN
-IsPageTypeToGuard (
- IN EFI_MEMORY_TYPE MemoryType,
- IN EFI_ALLOCATE_TYPE AllocateType
- );
-
-/**
- Check to see if the page at the given address is guarded or not.
-
- @param[in] Address The address to check for.
-
- @return TRUE The page at Address is guarded.
- @return FALSE The page at Address is not guarded.
-**/
-BOOLEAN
-EFIAPI
-IsMemoryGuarded (
- IN EFI_PHYSICAL_ADDRESS Address
- );
-
-/**
- Check to see if the page at the given address is a Guard page or not.
-
- @param[in] Address The address to check for.
-
- @return TRUE The page at Address is a Guard page.
- @return FALSE The page at Address is not a Guard page.
-**/
-BOOLEAN
-EFIAPI
-IsGuardPage (
- IN EFI_PHYSICAL_ADDRESS Address
- );
-
-/**
- Dump the guarded memory bit map.
-**/
-VOID
-EFIAPI
-DumpGuardedMemoryBitmap (
- VOID
- );
-
-/**
- Adjust the pool head position to make sure the Guard page is adjavent to
- pool tail or pool head.
-
- @param[in] Memory Base address of memory allocated.
- @param[in] NoPages Number of pages actually allocated.
- @param[in] Size Size of memory requested.
- (plus pool head/tail overhead)
-
- @return Address of pool head.
-**/
-VOID *
-AdjustPoolHeadA (
- IN EFI_PHYSICAL_ADDRESS Memory,
- IN UINTN NoPages,
- IN UINTN Size
- );
-
-/**
- Get the page base address according to pool head address.
-
- @param[in] Memory Head address of pool to free.
- @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 *
-AdjustPoolHeadF (
- IN EFI_PHYSICAL_ADDRESS Memory,
- IN UINTN NoPages,
- IN UINTN Size
- );
-
-/**
- Check to see if the heap guard is enabled for page and/or pool allocation.
-
- @param[in] GuardType Specify the sub-type(s) of Heap Guard.
-
- @return TRUE/FALSE.
-**/
-BOOLEAN
-IsHeapGuardEnabled (
- UINT8 GuardType
- );
-
-/**
- Notify function used to set all Guard pages after CPU Arch Protocol installed.
-**/
-VOID
-HeapGuardCpuArchProtocolNotify (
- VOID
- );
-
-/**
- This function checks to see if the given memory map descriptor in a memory map
- can be merged with any guarded free pages.
-
- @param MemoryMapEntry A pointer to a descriptor in MemoryMap.
- @param MaxAddress Maximum address to stop the merge.
-
- @return VOID
-
-**/
-VOID
-MergeGuardPages (
- IN EFI_MEMORY_DESCRIPTOR *MemoryMapEntry,
- IN EFI_PHYSICAL_ADDRESS MaxAddress
- );
-
-/**
- Record freed pages as well as mark them as not-present, if enabled.
-
- @param[in] BaseAddress Base address of just freed pages.
- @param[in] Pages Number of freed pages.
-
- @return VOID.
-**/
-VOID
-EFIAPI
-GuardFreedPagesChecked (
- IN EFI_PHYSICAL_ADDRESS BaseAddress,
- IN UINTN Pages
- );
-
-/**
- Put part (at most 64 pages a time) guarded free pages back to free page pool.
-
- Freed memory guard is used to detect Use-After-Free (UAF) memory issue, which
- makes use of 'Used then throw away' way to detect any illegal access to freed
- memory. The thrown-away memory will be marked as not-present so that any access
- to those memory (after free) will be caught by page-fault exception.
-
- The problem is that this will consume lots of memory space. Once no memory
- left in pool to allocate, we have to restore part of the freed pages to their
- normal function. Otherwise the whole system will stop functioning.
-
- @param StartAddress Start address of promoted memory.
- @param EndAddress End address of promoted memory.
-
- @return TRUE Succeeded to promote memory.
- @return FALSE No free memory found.
-
-**/
-BOOLEAN
-PromoteGuardedFreePages (
- OUT EFI_PHYSICAL_ADDRESS *StartAddress,
- OUT EFI_PHYSICAL_ADDRESS *EndAddress
- );
-
-extern BOOLEAN mOnGuarding;
-
-//
-// The heap guard system does not support non-EFI_PAGE_SIZE alignments.
-// Architectures that require larger RUNTIME_PAGE_ALLOCATION_GRANULARITY
-// cannot have EfiRuntimeServicesCode, EfiRuntimeServicesData, EfiReservedMemoryType,
-// and EfiACPIMemoryNVS guarded. OSes do not map guard pages anyway, so this is a
-// minimal loss. Not guarding prevents alignment mismatches
-//
-STATIC_ASSERT (
- RUNTIME_PAGE_ALLOCATION_GRANULARITY == EFI_PAGE_SIZE ||
- (((FixedPcdGet64 (PcdHeapGuardPageType) & 0x461) == 0) &&
- ((FixedPcdGet64 (PcdHeapGuardPoolType) & 0x461) == 0)),
- "Unsupported Heap Guard configuration on system with greater than EFI_PAGE_SIZE RUNTIME_PAGE_ALLOCATION_GRANULARITY"
- );
-
-#endif
+/** @file
+ Data type, macros and function prototypes of heap guard feature.
+
+Copyright (c) 2017-2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _HEAPGUARD_H_
+#define _HEAPGUARD_H_
+
+//
+// Following macros are used to define and access the guarded memory bitmap
+// table.
+//
+// To simplify the access and reduce the memory used for this table, the
+// table is constructed in the similar way as page table structure but in
+// reverse direction, i.e. from bottom growing up to top.
+//
+// - 1-bit tracks 1 page (4KB)
+// - 1-UINT64 map entry tracks 256KB memory
+// - 1K-UINT64 map table tracks 256MB memory
+// - Five levels of tables can track any address of memory of 64-bit
+// system, like below.
+//
+// 512 * 512 * 512 * 512 * 1K * 64b * 4K
+// 111111111 111111111 111111111 111111111 1111111111 111111 111111111111
+// 63 54 45 36 27 17 11 0
+// 9b 9b 9b 9b 10b 6b 12b
+// L0 -> L1 -> L2 -> L3 -> L4 -> bits -> page
+// 1FF 1FF 1FF 1FF 3FF 3F FFF
+//
+// L4 table has 1K * sizeof(UINT64) = 8K (2-page), which can track 256MB
+// memory. Each table of L0-L3 will be allocated when its memory address
+// range is to be tracked. Only 1-page will be allocated each time. This
+// can save memories used to establish this map table.
+//
+// For a normal configuration of system with 4G memory, two levels of tables
+// can track the whole memory, because two levels (L3+L4) of map tables have
+// already coverred 37-bit of memory address. And for a normal UEFI BIOS,
+// less than 128M memory would be consumed during boot. That means we just
+// need
+//
+// 1-page (L3) + 2-page (L4)
+//
+// memory (3 pages) to track the memory allocation works. In this case,
+// there's no need to setup L0-L2 tables.
+//
+
+//
+// Each entry occupies 8B/64b. 1-page can hold 512 entries, which spans 9
+// bits in address. (512 = 1 << 9)
+//
+#define BYTE_LENGTH_SHIFT 3 // (8 = 1 << 3)
+
+#define GUARDED_HEAP_MAP_TABLE_ENTRY_SHIFT \
+ (EFI_PAGE_SHIFT - BYTE_LENGTH_SHIFT)
+
+#define GUARDED_HEAP_MAP_TABLE_DEPTH 5
+
+// Use UINT64_index + bit_index_of_UINT64 to locate the bit in may
+#define GUARDED_HEAP_MAP_ENTRY_BIT_SHIFT 6 // (64 = 1 << 6)
+
+#define GUARDED_HEAP_MAP_ENTRY_BITS \
+ (1 << GUARDED_HEAP_MAP_ENTRY_BIT_SHIFT)
+
+#define GUARDED_HEAP_MAP_ENTRY_BYTES \
+ (GUARDED_HEAP_MAP_ENTRY_BITS / 8)
+
+// L4 table address width: 64 - 9 * 4 - 6 - 12 = 10b
+#define GUARDED_HEAP_MAP_ENTRY_SHIFT \
+ (GUARDED_HEAP_MAP_ENTRY_BITS \
+ - GUARDED_HEAP_MAP_TABLE_ENTRY_SHIFT * 4 \
+ - GUARDED_HEAP_MAP_ENTRY_BIT_SHIFT \
+ - EFI_PAGE_SHIFT)
+
+// L4 table address mask: (1 << 10 - 1) = 0x3FF
+#define GUARDED_HEAP_MAP_ENTRY_MASK \
+ ((1 << GUARDED_HEAP_MAP_ENTRY_SHIFT) - 1)
+
+// Size of each L4 table: (1 << 10) * 8 = 8KB = 2-page
+#define GUARDED_HEAP_MAP_SIZE \
+ ((1 << GUARDED_HEAP_MAP_ENTRY_SHIFT) * GUARDED_HEAP_MAP_ENTRY_BYTES)
+
+// Memory size tracked by one L4 table: 8KB * 8 * 4KB = 256MB
+#define GUARDED_HEAP_MAP_UNIT_SIZE \
+ (GUARDED_HEAP_MAP_SIZE * 8 * EFI_PAGE_SIZE)
+
+// L4 table entry number: 8KB / 8 = 1024
+#define GUARDED_HEAP_MAP_ENTRIES_PER_UNIT \
+ (GUARDED_HEAP_MAP_SIZE / GUARDED_HEAP_MAP_ENTRY_BYTES)
+
+// L4 table entry indexing
+#define GUARDED_HEAP_MAP_ENTRY_INDEX(Address) \
+ (RShiftU64 (Address, EFI_PAGE_SHIFT \
+ + GUARDED_HEAP_MAP_ENTRY_BIT_SHIFT) \
+ & GUARDED_HEAP_MAP_ENTRY_MASK)
+
+// L4 table entry bit indexing
+#define GUARDED_HEAP_MAP_ENTRY_BIT_INDEX(Address) \
+ (RShiftU64 (Address, EFI_PAGE_SHIFT) \
+ & ((1 << GUARDED_HEAP_MAP_ENTRY_BIT_SHIFT) - 1))
+
+//
+// Total bits (pages) tracked by one L4 table (65536-bit)
+//
+#define GUARDED_HEAP_MAP_BITS \
+ (1 << (GUARDED_HEAP_MAP_ENTRY_SHIFT \
+ + GUARDED_HEAP_MAP_ENTRY_BIT_SHIFT))
+
+//
+// Bit indexing inside the whole L4 table (0 - 65535)
+//
+#define GUARDED_HEAP_MAP_BIT_INDEX(Address) \
+ (RShiftU64 (Address, EFI_PAGE_SHIFT) \
+ & ((1 << (GUARDED_HEAP_MAP_ENTRY_SHIFT \
+ + GUARDED_HEAP_MAP_ENTRY_BIT_SHIFT)) - 1))
+
+//
+// Memory address bit width tracked by L4 table: 10 + 6 + 12 = 28
+//
+#define GUARDED_HEAP_MAP_TABLE_SHIFT \
+ (GUARDED_HEAP_MAP_ENTRY_SHIFT + GUARDED_HEAP_MAP_ENTRY_BIT_SHIFT \
+ + EFI_PAGE_SHIFT)
+
+//
+// Macro used to initialize the local array variable for map table traversing
+// {55, 46, 37, 28, 18}
+//
+#define GUARDED_HEAP_MAP_TABLE_DEPTH_SHIFTS \
+ { \
+ GUARDED_HEAP_MAP_TABLE_SHIFT + GUARDED_HEAP_MAP_TABLE_ENTRY_SHIFT * 3, \
+ GUARDED_HEAP_MAP_TABLE_SHIFT + GUARDED_HEAP_MAP_TABLE_ENTRY_SHIFT * 2, \
+ GUARDED_HEAP_MAP_TABLE_SHIFT + GUARDED_HEAP_MAP_TABLE_ENTRY_SHIFT, \
+ GUARDED_HEAP_MAP_TABLE_SHIFT, \
+ EFI_PAGE_SHIFT + GUARDED_HEAP_MAP_ENTRY_BIT_SHIFT \
+ }
+
+//
+// Masks used to extract address range of each level of table
+// {0x1FF, 0x1FF, 0x1FF, 0x1FF, 0x3FF}
+//
+#define GUARDED_HEAP_MAP_TABLE_DEPTH_MASKS \
+ { \
+ (1 << GUARDED_HEAP_MAP_TABLE_ENTRY_SHIFT) - 1, \
+ (1 << GUARDED_HEAP_MAP_TABLE_ENTRY_SHIFT) - 1, \
+ (1 << GUARDED_HEAP_MAP_TABLE_ENTRY_SHIFT) - 1, \
+ (1 << GUARDED_HEAP_MAP_TABLE_ENTRY_SHIFT) - 1, \
+ (1 << GUARDED_HEAP_MAP_ENTRY_SHIFT) - 1 \
+ }
+
+//
+// Memory type to guard (matching the related PCD definition)
+//
+#define GUARD_HEAP_TYPE_PAGE BIT0
+#define GUARD_HEAP_TYPE_POOL BIT1
+#define GUARD_HEAP_TYPE_FREED BIT4
+#define GUARD_HEAP_TYPE_ALL \
+ (GUARD_HEAP_TYPE_PAGE|GUARD_HEAP_TYPE_POOL|GUARD_HEAP_TYPE_FREED)
+
+//
+// Debug message level
+//
+#define HEAP_GUARD_DEBUG_LEVEL (DEBUG_POOL|DEBUG_PAGE)
+
+typedef struct {
+ UINT32 TailMark;
+ UINT32 HeadMark;
+ EFI_PHYSICAL_ADDRESS Address;
+ LIST_ENTRY Link;
+} HEAP_GUARD_NODE;
+
+/**
+ Internal function. Converts a memory range to the specified type.
+ The range must exist in the memory map.
+
+ @param Start The first address of the range Must be page
+ aligned.
+ @param NumberOfPages The number of pages to convert.
+ @param NewType The new type for the memory range.
+
+ @retval EFI_INVALID_PARAMETER Invalid parameter.
+ @retval EFI_NOT_FOUND Could not find a descriptor cover the specified
+ range or convertion not allowed.
+ @retval EFI_SUCCESS Successfully converts the memory range to the
+ specified type.
+
+**/
+EFI_STATUS
+CoreConvertPages (
+ IN UINT64 Start,
+ IN UINT64 NumberOfPages,
+ IN EFI_MEMORY_TYPE NewType
+ );
+
+/**
+ Allocate or free guarded memory.
+
+ @param[in] Start Start address of memory to allocate or free.
+ @param[in] NumberOfPages Memory size in pages.
+ @param[in] NewType Memory type to convert to.
+
+ @return VOID.
+**/
+EFI_STATUS
+CoreConvertPagesWithGuard (
+ IN UINT64 Start,
+ IN UINTN NumberOfPages,
+ IN EFI_MEMORY_TYPE NewType
+ );
+
+/**
+ Set head Guard and tail Guard for the given memory range.
+
+ @param[in] Memory Base address of memory to set guard for.
+ @param[in] NumberOfPages Memory size in pages.
+
+ @return VOID.
+**/
+VOID
+SetGuardForMemory (
+ IN EFI_PHYSICAL_ADDRESS Memory,
+ IN UINTN NumberOfPages
+ );
+
+/**
+ Unset head Guard and tail Guard for the given memory range.
+
+ @param[in] Memory Base address of memory to unset guard for.
+ @param[in] NumberOfPages Memory size in pages.
+
+ @return VOID.
+**/
+VOID
+UnsetGuardForMemory (
+ IN EFI_PHYSICAL_ADDRESS Memory,
+ IN UINTN NumberOfPages
+ );
+
+/**
+ Adjust the base and number of pages to really allocate according to Guard.
+
+ @param[in,out] Memory Base address of free memory.
+ @param[in,out] NumberOfPages Size of memory to allocate.
+
+ @return VOID.
+**/
+VOID
+AdjustMemoryA (
+ IN OUT EFI_PHYSICAL_ADDRESS *Memory,
+ IN OUT UINTN *NumberOfPages
+ );
+
+/**
+ Adjust the start address and number of pages to free according to Guard.
+
+ The purpose of this function is to keep the shared Guard page with adjacent
+ memory block if it's still in guard, or free it if no more sharing. Another
+ is to reserve pages as Guard pages in partial page free situation.
+
+ @param[in,out] Memory Base address of memory to free.
+ @param[in,out] NumberOfPages Size of memory to free.
+
+ @return VOID.
+**/
+VOID
+AdjustMemoryF (
+ IN OUT EFI_PHYSICAL_ADDRESS *Memory,
+ IN OUT UINTN *NumberOfPages
+ );
+
+/**
+ Adjust address of free memory according to existing and/or required Guard.
+
+ This function will check if there're existing Guard pages of adjacent
+ memory blocks, and try to use it as the Guard page of the memory to be
+ allocated.
+
+ @param[in] Start Start address of free memory block.
+ @param[in] Size Size of free memory block.
+ @param[in] SizeRequested Size of memory to allocate.
+
+ @return The end address of memory block found.
+ @return 0 if no enough space for the required size of memory and its Guard.
+**/
+UINT64
+AdjustMemoryS (
+ IN UINT64 Start,
+ IN UINT64 Size,
+ IN UINT64 SizeRequested
+ );
+
+/**
+ Check to see if the pool at the given address should be guarded or not.
+
+ @param[in] MemoryType Pool type to check.
+
+
+ @return TRUE The given type of pool should be guarded.
+ @return FALSE The given type of pool should not be guarded.
+**/
+BOOLEAN
+IsPoolTypeToGuard (
+ IN EFI_MEMORY_TYPE MemoryType
+ );
+
+/**
+ Check to see if the page at the given address should be guarded or not.
+
+ @param[in] MemoryType Page type to check.
+ @param[in] AllocateType Allocation type to check.
+
+ @return TRUE The given type of page should be guarded.
+ @return FALSE The given type of page should not be guarded.
+**/
+BOOLEAN
+IsPageTypeToGuard (
+ IN EFI_MEMORY_TYPE MemoryType,
+ IN EFI_ALLOCATE_TYPE AllocateType
+ );
+
+/**
+ Check to see if the page at the given address is guarded or not.
+
+ @param[in] Address The address to check for.
+
+ @return TRUE The page at Address is guarded.
+ @return FALSE The page at Address is not guarded.
+**/
+BOOLEAN
+EFIAPI
+IsMemoryGuarded (
+ IN EFI_PHYSICAL_ADDRESS Address
+ );
+
+/**
+ Check to see if the page at the given address is a Guard page or not.
+
+ @param[in] Address The address to check for.
+
+ @return TRUE The page at Address is a Guard page.
+ @return FALSE The page at Address is not a Guard page.
+**/
+BOOLEAN
+EFIAPI
+IsGuardPage (
+ IN EFI_PHYSICAL_ADDRESS Address
+ );
+
+/**
+ Dump the guarded memory bit map.
+**/
+VOID
+EFIAPI
+DumpGuardedMemoryBitmap (
+ VOID
+ );
+
+/**
+ Adjust the pool head position to make sure the Guard page is adjavent to
+ pool tail or pool head.
+
+ @param[in] Memory Base address of memory allocated.
+ @param[in] NoPages Number of pages actually allocated.
+ @param[in] Size Size of memory requested.
+ (plus pool head/tail overhead)
+
+ @return Address of pool head.
+**/
+VOID *
+AdjustPoolHeadA (
+ IN EFI_PHYSICAL_ADDRESS Memory,
+ IN UINTN NoPages,
+ IN UINTN Size
+ );
+
+/**
+ Get the page base address according to pool head address.
+
+ @param[in] Memory Head address of pool to free.
+ @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 *
+AdjustPoolHeadF (
+ IN EFI_PHYSICAL_ADDRESS Memory,
+ IN UINTN NoPages,
+ IN UINTN Size
+ );
+
+/**
+ Check to see if the heap guard is enabled for page and/or pool allocation.
+
+ @param[in] GuardType Specify the sub-type(s) of Heap Guard.
+
+ @return TRUE/FALSE.
+**/
+BOOLEAN
+IsHeapGuardEnabled (
+ UINT8 GuardType
+ );
+
+/**
+ Notify function used to set all Guard pages after CPU Arch Protocol installed.
+**/
+VOID
+HeapGuardCpuArchProtocolNotify (
+ VOID
+ );
+
+/**
+ This function checks to see if the given memory map descriptor in a memory map
+ can be merged with any guarded free pages.
+
+ @param MemoryMapEntry A pointer to a descriptor in MemoryMap.
+ @param MaxAddress Maximum address to stop the merge.
+
+ @return VOID
+
+**/
+VOID
+MergeGuardPages (
+ IN EFI_MEMORY_DESCRIPTOR *MemoryMapEntry,
+ IN EFI_PHYSICAL_ADDRESS MaxAddress
+ );
+
+/**
+ Record freed pages as well as mark them as not-present, if enabled.
+
+ @param[in] BaseAddress Base address of just freed pages.
+ @param[in] Pages Number of freed pages.
+
+ @return VOID.
+**/
+VOID
+EFIAPI
+GuardFreedPagesChecked (
+ IN EFI_PHYSICAL_ADDRESS BaseAddress,
+ IN UINTN Pages
+ );
+
+/**
+ Put part (at most 64 pages a time) guarded free pages back to free page pool.
+
+ Freed memory guard is used to detect Use-After-Free (UAF) memory issue, which
+ makes use of 'Used then throw away' way to detect any illegal access to freed
+ memory. The thrown-away memory will be marked as not-present so that any access
+ to those memory (after free) will be caught by page-fault exception.
+
+ The problem is that this will consume lots of memory space. Once no memory
+ left in pool to allocate, we have to restore part of the freed pages to their
+ normal function. Otherwise the whole system will stop functioning.
+
+ @param StartAddress Start address of promoted memory.
+ @param EndAddress End address of promoted memory.
+
+ @return TRUE Succeeded to promote memory.
+ @return FALSE No free memory found.
+
+**/
+BOOLEAN
+PromoteGuardedFreePages (
+ OUT EFI_PHYSICAL_ADDRESS *StartAddress,
+ OUT EFI_PHYSICAL_ADDRESS *EndAddress
+ );
+
+extern BOOLEAN mOnGuarding;
+
+//
+// The heap guard system does not support non-EFI_PAGE_SIZE alignments.
+// Architectures that require larger RUNTIME_PAGE_ALLOCATION_GRANULARITY
+// cannot have EfiRuntimeServicesCode, EfiRuntimeServicesData, EfiReservedMemoryType,
+// and EfiACPIMemoryNVS guarded. OSes do not map guard pages anyway, so this is a
+// minimal loss. Not guarding prevents alignment mismatches
+//
+STATIC_ASSERT (
+ RUNTIME_PAGE_ALLOCATION_GRANULARITY == EFI_PAGE_SIZE ||
+ (((FixedPcdGet64 (PcdHeapGuardPageType) & 0x461) == 0) &&
+ ((FixedPcdGet64 (PcdHeapGuardPoolType) & 0x461) == 0)),
+ "Unsupported Heap Guard configuration on system with greater than EFI_PAGE_SIZE RUNTIME_PAGE_ALLOCATION_GRANULARITY"
+ );
+
+#endif
diff --git a/MdeModulePkg/Core/Dxe/Mem/Imem.h b/MdeModulePkg/Core/Dxe/Mem/Imem.h
index 2f0bf2bf63..684876ea9b 100644
--- a/MdeModulePkg/Core/Dxe/Mem/Imem.h
+++ b/MdeModulePkg/Core/Dxe/Mem/Imem.h
@@ -1,172 +1,172 @@
-/** @file
- Data structure and functions to allocate and free memory space.
-
-Copyright (c) 2006 - 2017, Intel Corporation. All rights reserved.<BR>
-SPDX-License-Identifier: BSD-2-Clause-Patent
-
-**/
-
-#ifndef _IMEM_H_
-#define _IMEM_H_
-
-//
-// +---------------------------------------------------+
-// | 0..(EfiMaxMemoryType - 1) - Normal memory type |
-// +---------------------------------------------------+
-// | EfiMaxMemoryType..0x6FFFFFFF - Invalid |
-// +---------------------------------------------------+
-// | 0x70000000..0x7FFFFFFF - OEM reserved |
-// +---------------------------------------------------+
-// | 0x80000000..0xFFFFFFFF - OS reserved |
-// +---------------------------------------------------+
-//
-#define MEMORY_TYPE_OS_RESERVED_MIN 0x80000000
-#define MEMORY_TYPE_OS_RESERVED_MAX 0xFFFFFFFF
-#define MEMORY_TYPE_OEM_RESERVED_MIN 0x70000000
-#define MEMORY_TYPE_OEM_RESERVED_MAX 0x7FFFFFFF
-
-//
-// MEMORY_MAP_ENTRY
-//
-
-#define MEMORY_MAP_SIGNATURE SIGNATURE_32('m','m','a','p')
-typedef struct {
- UINTN Signature;
- LIST_ENTRY Link;
- BOOLEAN FromPages;
-
- EFI_MEMORY_TYPE Type;
- UINT64 Start;
- UINT64 End;
-
- UINT64 VirtualStart;
- UINT64 Attribute;
-} MEMORY_MAP;
-
-//
-// Internal prototypes
-//
-
-/**
- Internal function. Used by the pool functions to allocate pages
- to back pool allocation requests.
-
- @param PoolType The type of memory for the new pool pages
- @param NumberOfPages No of pages to allocate
- @param Alignment Bits to align.
- @param NeedGuard Flag to indicate Guard page is needed or not
-
- @return The allocated memory, or NULL
-
-**/
-VOID *
-CoreAllocatePoolPages (
- IN EFI_MEMORY_TYPE PoolType,
- IN UINTN NumberOfPages,
- IN UINTN Alignment,
- IN BOOLEAN NeedGuard
- );
-
-/**
- Internal function. Frees pool pages allocated via AllocatePoolPages ()
-
- @param Memory The base address to free
- @param NumberOfPages The number of pages to free
-
-**/
-VOID
-CoreFreePoolPages (
- IN EFI_PHYSICAL_ADDRESS Memory,
- IN UINTN NumberOfPages
- );
-
-/**
- Internal function to allocate pool of a particular type.
- Caller must have the memory lock held
-
- @param PoolType Type of pool to allocate
- @param Size The amount of pool to allocate
- @param NeedGuard Flag to indicate Guard page is needed or not
-
- @return The allocate pool, or NULL
-
-**/
-VOID *
-CoreAllocatePoolI (
- IN EFI_MEMORY_TYPE PoolType,
- IN UINTN Size,
- IN BOOLEAN NeedGuard
- );
-
-/**
- Internal function to free a pool entry.
- Caller must have the memory lock held
-
- @param Buffer The allocated pool entry to free
- @param PoolType Pointer to pool type
-
- @retval EFI_INVALID_PARAMETER Buffer not valid
- @retval EFI_SUCCESS Buffer successfully freed.
-
-**/
-EFI_STATUS
-CoreFreePoolI (
- IN VOID *Buffer,
- OUT EFI_MEMORY_TYPE *PoolType OPTIONAL
- );
-
-/**
- Enter critical section by gaining lock on gMemoryLock.
-
-**/
-VOID
-CoreAcquireMemoryLock (
- VOID
- );
-
-/**
- Exit critical section by releasing lock on gMemoryLock.
-
-**/
-VOID
-CoreReleaseMemoryLock (
- VOID
- );
-
-/**
- Allocates pages from the memory map.
-
- @param Type The type of allocation to perform
- @param MemoryType The type of memory to turn the allocated pages
- into
- @param NumberOfPages The number of pages to allocate
- @param Memory A pointer to receive the base allocated memory
- address
- @param NeedGuard Flag to indicate Guard page is needed or not
-
- @return Status. On success, Memory is filled in with the base address allocated
- @retval EFI_INVALID_PARAMETER Parameters violate checking rules defined in
- spec.
- @retval EFI_NOT_FOUND Could not allocate pages match the requirement.
- @retval EFI_OUT_OF_RESOURCES No enough pages to allocate.
- @retval EFI_SUCCESS Pages successfully allocated.
-
-**/
-EFI_STATUS
-EFIAPI
-CoreInternalAllocatePages (
- IN EFI_ALLOCATE_TYPE Type,
- IN EFI_MEMORY_TYPE MemoryType,
- IN UINTN NumberOfPages,
- IN OUT EFI_PHYSICAL_ADDRESS *Memory,
- IN BOOLEAN NeedGuard
- );
-
-//
-// Internal Global data
-//
-
-extern EFI_LOCK gMemoryLock;
-extern LIST_ENTRY gMemoryMap;
-extern LIST_ENTRY mGcdMemorySpaceMap;
-#endif
+/** @file
+ Data structure and functions to allocate and free memory space.
+
+Copyright (c) 2006 - 2017, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _IMEM_H_
+#define _IMEM_H_
+
+//
+// +---------------------------------------------------+
+// | 0..(EfiMaxMemoryType - 1) - Normal memory type |
+// +---------------------------------------------------+
+// | EfiMaxMemoryType..0x6FFFFFFF - Invalid |
+// +---------------------------------------------------+
+// | 0x70000000..0x7FFFFFFF - OEM reserved |
+// +---------------------------------------------------+
+// | 0x80000000..0xFFFFFFFF - OS reserved |
+// +---------------------------------------------------+
+//
+#define MEMORY_TYPE_OS_RESERVED_MIN 0x80000000
+#define MEMORY_TYPE_OS_RESERVED_MAX 0xFFFFFFFF
+#define MEMORY_TYPE_OEM_RESERVED_MIN 0x70000000
+#define MEMORY_TYPE_OEM_RESERVED_MAX 0x7FFFFFFF
+
+//
+// MEMORY_MAP_ENTRY
+//
+
+#define MEMORY_MAP_SIGNATURE SIGNATURE_32('m','m','a','p')
+typedef struct {
+ UINTN Signature;
+ LIST_ENTRY Link;
+ BOOLEAN FromPages;
+
+ EFI_MEMORY_TYPE Type;
+ UINT64 Start;
+ UINT64 End;
+
+ UINT64 VirtualStart;
+ UINT64 Attribute;
+} MEMORY_MAP;
+
+//
+// Internal prototypes
+//
+
+/**
+ Internal function. Used by the pool functions to allocate pages
+ to back pool allocation requests.
+
+ @param PoolType The type of memory for the new pool pages
+ @param NumberOfPages No of pages to allocate
+ @param Alignment Bits to align.
+ @param NeedGuard Flag to indicate Guard page is needed or not
+
+ @return The allocated memory, or NULL
+
+**/
+VOID *
+CoreAllocatePoolPages (
+ IN EFI_MEMORY_TYPE PoolType,
+ IN UINTN NumberOfPages,
+ IN UINTN Alignment,
+ IN BOOLEAN NeedGuard
+ );
+
+/**
+ Internal function. Frees pool pages allocated via AllocatePoolPages ()
+
+ @param Memory The base address to free
+ @param NumberOfPages The number of pages to free
+
+**/
+VOID
+CoreFreePoolPages (
+ IN EFI_PHYSICAL_ADDRESS Memory,
+ IN UINTN NumberOfPages
+ );
+
+/**
+ Internal function to allocate pool of a particular type.
+ Caller must have the memory lock held
+
+ @param PoolType Type of pool to allocate
+ @param Size The amount of pool to allocate
+ @param NeedGuard Flag to indicate Guard page is needed or not
+
+ @return The allocate pool, or NULL
+
+**/
+VOID *
+CoreAllocatePoolI (
+ IN EFI_MEMORY_TYPE PoolType,
+ IN UINTN Size,
+ IN BOOLEAN NeedGuard
+ );
+
+/**
+ Internal function to free a pool entry.
+ Caller must have the memory lock held
+
+ @param Buffer The allocated pool entry to free
+ @param PoolType Pointer to pool type
+
+ @retval EFI_INVALID_PARAMETER Buffer not valid
+ @retval EFI_SUCCESS Buffer successfully freed.
+
+**/
+EFI_STATUS
+CoreFreePoolI (
+ IN VOID *Buffer,
+ OUT EFI_MEMORY_TYPE *PoolType OPTIONAL
+ );
+
+/**
+ Enter critical section by gaining lock on gMemoryLock.
+
+**/
+VOID
+CoreAcquireMemoryLock (
+ VOID
+ );
+
+/**
+ Exit critical section by releasing lock on gMemoryLock.
+
+**/
+VOID
+CoreReleaseMemoryLock (
+ VOID
+ );
+
+/**
+ Allocates pages from the memory map.
+
+ @param Type The type of allocation to perform
+ @param MemoryType The type of memory to turn the allocated pages
+ into
+ @param NumberOfPages The number of pages to allocate
+ @param Memory A pointer to receive the base allocated memory
+ address
+ @param NeedGuard Flag to indicate Guard page is needed or not
+
+ @return Status. On success, Memory is filled in with the base address allocated
+ @retval EFI_INVALID_PARAMETER Parameters violate checking rules defined in
+ spec.
+ @retval EFI_NOT_FOUND Could not allocate pages match the requirement.
+ @retval EFI_OUT_OF_RESOURCES No enough pages to allocate.
+ @retval EFI_SUCCESS Pages successfully allocated.
+
+**/
+EFI_STATUS
+EFIAPI
+CoreInternalAllocatePages (
+ IN EFI_ALLOCATE_TYPE Type,
+ IN EFI_MEMORY_TYPE MemoryType,
+ IN UINTN NumberOfPages,
+ IN OUT EFI_PHYSICAL_ADDRESS *Memory,
+ IN BOOLEAN NeedGuard
+ );
+
+//
+// Internal Global data
+//
+
+extern EFI_LOCK gMemoryLock;
+extern LIST_ENTRY gMemoryMap;
+extern LIST_ENTRY mGcdMemorySpaceMap;
+#endif
diff --git a/MdeModulePkg/Core/Dxe/Mem/MemData.c b/MdeModulePkg/Core/Dxe/Mem/MemData.c
index 8f138b703e..83b74f8c12 100644
--- a/MdeModulePkg/Core/Dxe/Mem/MemData.c
+++ b/MdeModulePkg/Core/Dxe/Mem/MemData.c
@@ -1,19 +1,19 @@
-/** @file
- Global data used in memory service
-
-Copyright (c) 2006 - 2008, Intel Corporation. All rights reserved.<BR>
-SPDX-License-Identifier: BSD-2-Clause-Patent
-
-**/
-
-#include "DxeMain.h"
-
-//
-// MemoryLock - synchronizes access to the memory map and pool lists
-//
-EFI_LOCK gMemoryLock = EFI_INITIALIZE_LOCK_VARIABLE (TPL_NOTIFY);
-
-//
-// MemoryMap - the current memory map
-//
-LIST_ENTRY gMemoryMap = INITIALIZE_LIST_HEAD_VARIABLE (gMemoryMap);
+/** @file
+ Global data used in memory service
+
+Copyright (c) 2006 - 2008, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "DxeMain.h"
+
+//
+// MemoryLock - synchronizes access to the memory map and pool lists
+//
+EFI_LOCK gMemoryLock = EFI_INITIALIZE_LOCK_VARIABLE (TPL_NOTIFY);
+
+//
+// MemoryMap - the current memory map
+//
+LIST_ENTRY gMemoryMap = INITIALIZE_LIST_HEAD_VARIABLE (gMemoryMap);
diff --git a/MdeModulePkg/Core/Dxe/Mem/MemoryProfileRecord.c b/MdeModulePkg/Core/Dxe/Mem/MemoryProfileRecord.c
index 00e33b707d..0401e19a5c 100644
--- a/MdeModulePkg/Core/Dxe/Mem/MemoryProfileRecord.c
+++ b/MdeModulePkg/Core/Dxe/Mem/MemoryProfileRecord.c
@@ -1,1792 +1,1792 @@
-/** @file
- Support routines for UEFI memory profile.
-
- Copyright (c) 2014 - 2018, Intel Corporation. All rights reserved.<BR>
- SPDX-License-Identifier: BSD-2-Clause-Patent
-
-**/
-
-#include "DxeMain.h"
-#include "Imem.h"
-
-#define IS_UEFI_MEMORY_PROFILE_ENABLED ((PcdGet8 (PcdMemoryProfilePropertyMask) & BIT0) != 0)
-
-#define GET_OCCUPIED_SIZE(ActualSize, Alignment) \
- ((ActualSize) + (((Alignment) - ((ActualSize) & ((Alignment) - 1))) & ((Alignment) - 1)))
-
-typedef struct {
- UINT32 Signature;
- MEMORY_PROFILE_CONTEXT Context;
- LIST_ENTRY *DriverInfoList;
-} MEMORY_PROFILE_CONTEXT_DATA;
-
-typedef struct {
- UINT32 Signature;
- MEMORY_PROFILE_DRIVER_INFO DriverInfo;
- LIST_ENTRY *AllocInfoList;
- CHAR8 *PdbString;
- LIST_ENTRY Link;
-} MEMORY_PROFILE_DRIVER_INFO_DATA;
-
-typedef struct {
- UINT32 Signature;
- MEMORY_PROFILE_ALLOC_INFO AllocInfo;
- CHAR8 *ActionString;
- LIST_ENTRY Link;
-} MEMORY_PROFILE_ALLOC_INFO_DATA;
-
-GLOBAL_REMOVE_IF_UNREFERENCED LIST_ENTRY mImageQueue = INITIALIZE_LIST_HEAD_VARIABLE (mImageQueue);
-GLOBAL_REMOVE_IF_UNREFERENCED MEMORY_PROFILE_CONTEXT_DATA mMemoryProfileContext = {
- MEMORY_PROFILE_CONTEXT_SIGNATURE,
- {
- {
- MEMORY_PROFILE_CONTEXT_SIGNATURE,
- sizeof (MEMORY_PROFILE_CONTEXT),
- MEMORY_PROFILE_CONTEXT_REVISION
- },
- 0,
- 0,
- { 0 },
- { 0 },
- 0,
- 0,
- 0
- },
- &mImageQueue,
-};
-GLOBAL_REMOVE_IF_UNREFERENCED MEMORY_PROFILE_CONTEXT_DATA *mMemoryProfileContextPtr = NULL;
-
-GLOBAL_REMOVE_IF_UNREFERENCED EFI_LOCK mMemoryProfileLock = EFI_INITIALIZE_LOCK_VARIABLE (TPL_NOTIFY);
-GLOBAL_REMOVE_IF_UNREFERENCED BOOLEAN mMemoryProfileGettingStatus = FALSE;
-GLOBAL_REMOVE_IF_UNREFERENCED BOOLEAN mMemoryProfileRecordingEnable = MEMORY_PROFILE_RECORDING_DISABLE;
-GLOBAL_REMOVE_IF_UNREFERENCED EFI_DEVICE_PATH_PROTOCOL *mMemoryProfileDriverPath;
-GLOBAL_REMOVE_IF_UNREFERENCED UINTN mMemoryProfileDriverPathSize;
-
-/**
- Get memory profile data.
-
- @param[in] This The EDKII_MEMORY_PROFILE_PROTOCOL instance.
- @param[in, out] ProfileSize On entry, points to the size in bytes of the ProfileBuffer.
- On return, points to the size of the data returned in ProfileBuffer.
- @param[out] ProfileBuffer Profile buffer.
-
- @return EFI_SUCCESS Get the memory profile data successfully.
- @return EFI_UNSUPPORTED Memory profile is unsupported.
- @return EFI_BUFFER_TO_SMALL The ProfileSize is too small for the resulting data.
- ProfileSize is updated with the size required.
-
-**/
-EFI_STATUS
-EFIAPI
-ProfileProtocolGetData (
- IN EDKII_MEMORY_PROFILE_PROTOCOL *This,
- IN OUT UINT64 *ProfileSize,
- OUT VOID *ProfileBuffer
- );
-
-/**
- Register image to memory profile.
-
- @param[in] This The EDKII_MEMORY_PROFILE_PROTOCOL instance.
- @param[in] FilePath File path of the image.
- @param[in] ImageBase Image base address.
- @param[in] ImageSize Image size.
- @param[in] FileType File type of the image.
-
- @return EFI_SUCCESS Register successfully.
- @return EFI_UNSUPPORTED Memory profile is unsupported,
- or memory profile for the image is not required.
- @return EFI_OUT_OF_RESOURCE No enough resource for this register.
-
-**/
-EFI_STATUS
-EFIAPI
-ProfileProtocolRegisterImage (
- IN EDKII_MEMORY_PROFILE_PROTOCOL *This,
- IN EFI_DEVICE_PATH_PROTOCOL *FilePath,
- IN PHYSICAL_ADDRESS ImageBase,
- IN UINT64 ImageSize,
- IN EFI_FV_FILETYPE FileType
- );
-
-/**
- Unregister image from memory profile.
-
- @param[in] This The EDKII_MEMORY_PROFILE_PROTOCOL instance.
- @param[in] FilePath File path of the image.
- @param[in] ImageBase Image base address.
- @param[in] ImageSize Image size.
-
- @return EFI_SUCCESS Unregister successfully.
- @return EFI_UNSUPPORTED Memory profile is unsupported,
- or memory profile for the image is not required.
- @return EFI_NOT_FOUND The image is not found.
-
-**/
-EFI_STATUS
-EFIAPI
-ProfileProtocolUnregisterImage (
- IN EDKII_MEMORY_PROFILE_PROTOCOL *This,
- IN EFI_DEVICE_PATH_PROTOCOL *FilePath,
- IN PHYSICAL_ADDRESS ImageBase,
- IN UINT64 ImageSize
- );
-
-/**
- Get memory profile recording state.
-
- @param[in] This The EDKII_MEMORY_PROFILE_PROTOCOL instance.
- @param[out] RecordingState Recording state.
-
- @return EFI_SUCCESS Memory profile recording state is returned.
- @return EFI_UNSUPPORTED Memory profile is unsupported.
- @return EFI_INVALID_PARAMETER RecordingState is NULL.
-
-**/
-EFI_STATUS
-EFIAPI
-ProfileProtocolGetRecordingState (
- IN EDKII_MEMORY_PROFILE_PROTOCOL *This,
- OUT BOOLEAN *RecordingState
- );
-
-/**
- Set memory profile recording state.
-
- @param[in] This The EDKII_MEMORY_PROFILE_PROTOCOL instance.
- @param[in] RecordingState Recording state.
-
- @return EFI_SUCCESS Set memory profile recording state successfully.
- @return EFI_UNSUPPORTED Memory profile is unsupported.
-
-**/
-EFI_STATUS
-EFIAPI
-ProfileProtocolSetRecordingState (
- IN EDKII_MEMORY_PROFILE_PROTOCOL *This,
- IN BOOLEAN RecordingState
- );
-
-/**
- Record memory profile of multilevel caller.
-
- @param[in] This The EDKII_MEMORY_PROFILE_PROTOCOL instance.
- @param[in] CallerAddress Address of caller.
- @param[in] Action Memory profile action.
- @param[in] MemoryType Memory type.
- EfiMaxMemoryType means the MemoryType is unknown.
- @param[in] Buffer Buffer address.
- @param[in] Size Buffer size.
- @param[in] ActionString String for memory profile action.
- Only needed for user defined allocate action.
-
- @return EFI_SUCCESS Memory profile is updated.
- @return EFI_UNSUPPORTED Memory profile is unsupported,
- or memory profile for the image is not required,
- or memory profile for the memory type is not required.
- @return EFI_ACCESS_DENIED It is during memory profile data getting.
- @return EFI_ABORTED Memory profile recording is not enabled.
- @return EFI_OUT_OF_RESOURCES No enough resource to update memory profile for allocate action.
- @return EFI_NOT_FOUND No matched allocate info found for free action.
-
-**/
-EFI_STATUS
-EFIAPI
-ProfileProtocolRecord (
- IN EDKII_MEMORY_PROFILE_PROTOCOL *This,
- IN PHYSICAL_ADDRESS CallerAddress,
- IN MEMORY_PROFILE_ACTION Action,
- IN EFI_MEMORY_TYPE MemoryType,
- IN VOID *Buffer,
- IN UINTN Size,
- IN CHAR8 *ActionString OPTIONAL
- );
-
-GLOBAL_REMOVE_IF_UNREFERENCED EDKII_MEMORY_PROFILE_PROTOCOL mProfileProtocol = {
- ProfileProtocolGetData,
- ProfileProtocolRegisterImage,
- ProfileProtocolUnregisterImage,
- ProfileProtocolGetRecordingState,
- ProfileProtocolSetRecordingState,
- ProfileProtocolRecord,
-};
-
-/**
- Acquire lock on mMemoryProfileLock.
-**/
-VOID
-CoreAcquireMemoryProfileLock (
- VOID
- )
-{
- CoreAcquireLock (&mMemoryProfileLock);
-}
-
-/**
- Release lock on mMemoryProfileLock.
-**/
-VOID
-CoreReleaseMemoryProfileLock (
- VOID
- )
-{
- CoreReleaseLock (&mMemoryProfileLock);
-}
-
-/**
- Return memory profile context.
-
- @return Memory profile context.
-
-**/
-MEMORY_PROFILE_CONTEXT_DATA *
-GetMemoryProfileContext (
- VOID
- )
-{
- return mMemoryProfileContextPtr;
-}
-
-/**
- Retrieves and returns the Subsystem of a PE/COFF image that has been loaded into system memory.
- If Pe32Data is NULL, then ASSERT().
-
- @param Pe32Data The pointer to the PE/COFF image that is loaded in system memory.
-
- @return The Subsystem of the PE/COFF image.
-
-**/
-UINT16
-InternalPeCoffGetSubsystem (
- IN VOID *Pe32Data
- )
-{
- EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr;
- EFI_IMAGE_DOS_HEADER *DosHdr;
- UINT16 Magic;
-
- ASSERT (Pe32Data != NULL);
-
- DosHdr = (EFI_IMAGE_DOS_HEADER *)Pe32Data;
- if (DosHdr->e_magic == EFI_IMAGE_DOS_SIGNATURE) {
- //
- // DOS image header is present, so read the PE header after the DOS image header.
- //
- Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *)((UINTN)Pe32Data + (UINTN)((DosHdr->e_lfanew) & 0x0ffff));
- } else {
- //
- // DOS image header is not present, so PE header is at the image base.
- //
- Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *)Pe32Data;
- }
-
- if (Hdr.Te->Signature == EFI_TE_IMAGE_HEADER_SIGNATURE) {
- return Hdr.Te->Subsystem;
- } else if (Hdr.Pe32->Signature == EFI_IMAGE_NT_SIGNATURE) {
- Magic = Hdr.Pe32->OptionalHeader.Magic;
- if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
- return Hdr.Pe32->OptionalHeader.Subsystem;
- } else if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC) {
- return Hdr.Pe32Plus->OptionalHeader.Subsystem;
- }
- }
-
- return 0x0000;
-}
-
-/**
- Retrieves and returns a pointer to the entry point to a PE/COFF image that has been loaded
- into system memory with the PE/COFF Loader Library functions.
-
- Retrieves the entry point to the PE/COFF image specified by Pe32Data and returns this entry
- point in EntryPoint. If the entry point could not be retrieved from the PE/COFF image, then
- return RETURN_INVALID_PARAMETER. Otherwise return RETURN_SUCCESS.
- If Pe32Data is NULL, then ASSERT().
- If EntryPoint is NULL, then ASSERT().
-
- @param Pe32Data The pointer to the PE/COFF image that is loaded in system memory.
- @param EntryPoint The pointer to entry point to the PE/COFF image to return.
-
- @retval RETURN_SUCCESS EntryPoint was returned.
- @retval RETURN_INVALID_PARAMETER The entry point could not be found in the PE/COFF image.
-
-**/
-RETURN_STATUS
-InternalPeCoffGetEntryPoint (
- IN VOID *Pe32Data,
- OUT VOID **EntryPoint
- )
-{
- EFI_IMAGE_DOS_HEADER *DosHdr;
- EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr;
-
- ASSERT (Pe32Data != NULL);
- ASSERT (EntryPoint != NULL);
-
- DosHdr = (EFI_IMAGE_DOS_HEADER *)Pe32Data;
- if (DosHdr->e_magic == EFI_IMAGE_DOS_SIGNATURE) {
- //
- // DOS image header is present, so read the PE header after the DOS image header.
- //
- Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *)((UINTN)Pe32Data + (UINTN)((DosHdr->e_lfanew) & 0x0ffff));
- } else {
- //
- // DOS image header is not present, so PE header is at the image base.
- //
- Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *)Pe32Data;
- }
-
- //
- // Calculate the entry point relative to the start of the image.
- // AddressOfEntryPoint is common for PE32 & PE32+
- //
- if (Hdr.Te->Signature == EFI_TE_IMAGE_HEADER_SIGNATURE) {
- *EntryPoint = (VOID *)((UINTN)Pe32Data + (UINTN)(Hdr.Te->AddressOfEntryPoint & 0x0ffffffff) + sizeof (EFI_TE_IMAGE_HEADER) - Hdr.Te->StrippedSize);
- return RETURN_SUCCESS;
- } else if (Hdr.Pe32->Signature == EFI_IMAGE_NT_SIGNATURE) {
- *EntryPoint = (VOID *)((UINTN)Pe32Data + (UINTN)(Hdr.Pe32->OptionalHeader.AddressOfEntryPoint & 0x0ffffffff));
- return RETURN_SUCCESS;
- }
-
- return RETURN_UNSUPPORTED;
-}
-
-/**
- Build driver info.
-
- @param ContextData Memory profile context.
- @param FileName File name of the image.
- @param ImageBase Image base address.
- @param ImageSize Image size.
- @param EntryPoint Entry point of the image.
- @param ImageSubsystem Image subsystem of the image.
- @param FileType File type of the image.
-
- @return Pointer to memory profile driver info.
-
-**/
-MEMORY_PROFILE_DRIVER_INFO_DATA *
-BuildDriverInfo (
- IN MEMORY_PROFILE_CONTEXT_DATA *ContextData,
- IN EFI_GUID *FileName,
- IN PHYSICAL_ADDRESS ImageBase,
- IN UINT64 ImageSize,
- IN PHYSICAL_ADDRESS EntryPoint,
- IN UINT16 ImageSubsystem,
- IN EFI_FV_FILETYPE FileType
- )
-{
- EFI_STATUS Status;
- MEMORY_PROFILE_DRIVER_INFO *DriverInfo;
- MEMORY_PROFILE_DRIVER_INFO_DATA *DriverInfoData;
- VOID *EntryPointInImage;
- CHAR8 *PdbString;
- UINTN PdbSize;
- UINTN PdbOccupiedSize;
-
- PdbSize = 0;
- PdbOccupiedSize = 0;
- PdbString = NULL;
- if (ImageBase != 0) {
- PdbString = PeCoffLoaderGetPdbPointer ((VOID *)(UINTN)ImageBase);
- if (PdbString != NULL) {
- PdbSize = AsciiStrSize (PdbString);
- PdbOccupiedSize = GET_OCCUPIED_SIZE (PdbSize, sizeof (UINT64));
- }
- }
-
- //
- // Use CoreInternalAllocatePool() that will not update profile for this AllocatePool action.
- //
- Status = CoreInternalAllocatePool (
- EfiBootServicesData,
- sizeof (*DriverInfoData) + sizeof (LIST_ENTRY) + PdbSize,
- (VOID **)&DriverInfoData
- );
- if (EFI_ERROR (Status)) {
- return NULL;
- }
-
- ASSERT (DriverInfoData != NULL);
-
- ZeroMem (DriverInfoData, sizeof (*DriverInfoData));
-
- DriverInfo = &DriverInfoData->DriverInfo;
- DriverInfoData->Signature = MEMORY_PROFILE_DRIVER_INFO_SIGNATURE;
- DriverInfo->Header.Signature = MEMORY_PROFILE_DRIVER_INFO_SIGNATURE;
- DriverInfo->Header.Length = (UINT16)(sizeof (MEMORY_PROFILE_DRIVER_INFO) + PdbOccupiedSize);
- DriverInfo->Header.Revision = MEMORY_PROFILE_DRIVER_INFO_REVISION;
- if (FileName != NULL) {
- CopyMem (&DriverInfo->FileName, FileName, sizeof (EFI_GUID));
- }
-
- DriverInfo->ImageBase = ImageBase;
- DriverInfo->ImageSize = ImageSize;
- DriverInfo->EntryPoint = EntryPoint;
- DriverInfo->ImageSubsystem = ImageSubsystem;
- if ((EntryPoint != 0) && ((EntryPoint < ImageBase) || (EntryPoint >= (ImageBase + ImageSize)))) {
- //
- // If the EntryPoint is not in the range of image buffer, it should come from emulation environment.
- // So patch ImageBuffer here to align the EntryPoint.
- //
- Status = InternalPeCoffGetEntryPoint ((VOID *)(UINTN)ImageBase, &EntryPointInImage);
- ASSERT_EFI_ERROR (Status);
- DriverInfo->ImageBase = ImageBase + EntryPoint - (PHYSICAL_ADDRESS)(UINTN)EntryPointInImage;
- }
-
- DriverInfo->FileType = FileType;
- DriverInfoData->AllocInfoList = (LIST_ENTRY *)(DriverInfoData + 1);
- InitializeListHead (DriverInfoData->AllocInfoList);
- DriverInfo->CurrentUsage = 0;
- DriverInfo->PeakUsage = 0;
- DriverInfo->AllocRecordCount = 0;
- if (PdbSize != 0) {
- DriverInfo->PdbStringOffset = (UINT16)sizeof (MEMORY_PROFILE_DRIVER_INFO);
- DriverInfoData->PdbString = (CHAR8 *)(DriverInfoData->AllocInfoList + 1);
- CopyMem (DriverInfoData->PdbString, PdbString, PdbSize);
- } else {
- DriverInfo->PdbStringOffset = 0;
- DriverInfoData->PdbString = NULL;
- }
-
- InsertTailList (ContextData->DriverInfoList, &DriverInfoData->Link);
- ContextData->Context.ImageCount++;
- ContextData->Context.TotalImageSize += DriverInfo->ImageSize;
-
- return DriverInfoData;
-}
-
-/**
- Return if record for this driver is needed..
-
- @param DriverFilePath Driver file path.
-
- @retval TRUE Record for this driver is needed.
- @retval FALSE Record for this driver is not needed.
-
-**/
-BOOLEAN
-NeedRecordThisDriver (
- IN EFI_DEVICE_PATH_PROTOCOL *DriverFilePath
- )
-{
- EFI_DEVICE_PATH_PROTOCOL *TmpDevicePath;
- EFI_DEVICE_PATH_PROTOCOL *DevicePathInstance;
- UINTN DevicePathSize;
- UINTN FilePathSize;
-
- if (!IsDevicePathValid (mMemoryProfileDriverPath, mMemoryProfileDriverPathSize)) {
- //
- // Invalid Device Path means record all.
- //
- return TRUE;
- }
-
- //
- // Record FilePath without END node.
- //
- FilePathSize = GetDevicePathSize (DriverFilePath) - sizeof (EFI_DEVICE_PATH_PROTOCOL);
-
- DevicePathInstance = mMemoryProfileDriverPath;
- do {
- //
- // Find END node (it might be END_ENTIRE or END_INSTANCE).
- //
- TmpDevicePath = DevicePathInstance;
- while (!IsDevicePathEndType (TmpDevicePath)) {
- TmpDevicePath = NextDevicePathNode (TmpDevicePath);
- }
-
- //
- // Do not compare END node.
- //
- DevicePathSize = (UINTN)TmpDevicePath - (UINTN)DevicePathInstance;
- if ((FilePathSize == DevicePathSize) &&
- (CompareMem (DriverFilePath, DevicePathInstance, DevicePathSize) == 0))
- {
- return TRUE;
- }
-
- //
- // Get next instance.
- //
- DevicePathInstance = (EFI_DEVICE_PATH_PROTOCOL *)((UINTN)DevicePathInstance + DevicePathSize + DevicePathNodeLength (TmpDevicePath));
- } while (DevicePathSubType (TmpDevicePath) != END_ENTIRE_DEVICE_PATH_SUBTYPE);
-
- return FALSE;
-}
-
-/**
- Register DXE Core to memory profile.
-
- @param HobStart The start address of the HOB.
- @param ContextData Memory profile context.
-
- @retval TRUE Register success.
- @retval FALSE Register fail.
-
-**/
-BOOLEAN
-RegisterDxeCore (
- IN VOID *HobStart,
- IN MEMORY_PROFILE_CONTEXT_DATA *ContextData
- )
-{
- EFI_PEI_HOB_POINTERS DxeCoreHob;
- MEMORY_PROFILE_DRIVER_INFO_DATA *DriverInfoData;
- PHYSICAL_ADDRESS ImageBase;
- UINT8 TempBuffer[sizeof (MEDIA_FW_VOL_FILEPATH_DEVICE_PATH) + sizeof (EFI_DEVICE_PATH_PROTOCOL)];
- MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *FilePath;
-
- ASSERT (ContextData != NULL);
-
- //
- // Searching for image hob
- //
- DxeCoreHob.Raw = HobStart;
- while ((DxeCoreHob.Raw = GetNextHob (EFI_HOB_TYPE_MEMORY_ALLOCATION, DxeCoreHob.Raw)) != NULL) {
- if (CompareGuid (&DxeCoreHob.MemoryAllocationModule->MemoryAllocationHeader.Name, &gEfiHobMemoryAllocModuleGuid)) {
- //
- // Find Dxe Core HOB
- //
- break;
- }
-
- DxeCoreHob.Raw = GET_NEXT_HOB (DxeCoreHob);
- }
-
- ASSERT (DxeCoreHob.Raw != NULL);
-
- FilePath = (MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *)TempBuffer;
- EfiInitializeFwVolDevicepathNode (FilePath, &DxeCoreHob.MemoryAllocationModule->ModuleName);
- SetDevicePathEndNode (FilePath + 1);
-
- if (!NeedRecordThisDriver ((EFI_DEVICE_PATH_PROTOCOL *)FilePath)) {
- return FALSE;
- }
-
- ImageBase = DxeCoreHob.MemoryAllocationModule->MemoryAllocationHeader.MemoryBaseAddress;
- DriverInfoData = BuildDriverInfo (
- ContextData,
- &DxeCoreHob.MemoryAllocationModule->ModuleName,
- ImageBase,
- DxeCoreHob.MemoryAllocationModule->MemoryAllocationHeader.MemoryLength,
- DxeCoreHob.MemoryAllocationModule->EntryPoint,
- InternalPeCoffGetSubsystem ((VOID *)(UINTN)ImageBase),
- EFI_FV_FILETYPE_DXE_CORE
- );
- if (DriverInfoData == NULL) {
- return FALSE;
- }
-
- return TRUE;
-}
-
-/**
- Initialize memory profile.
-
- @param HobStart The start address of the HOB.
-
-**/
-VOID
-MemoryProfileInit (
- IN VOID *HobStart
- )
-{
- MEMORY_PROFILE_CONTEXT_DATA *ContextData;
-
- if (!IS_UEFI_MEMORY_PROFILE_ENABLED) {
- return;
- }
-
- ContextData = GetMemoryProfileContext ();
- if (ContextData != NULL) {
- return;
- }
-
- mMemoryProfileGettingStatus = FALSE;
- if ((PcdGet8 (PcdMemoryProfilePropertyMask) & BIT7) != 0) {
- mMemoryProfileRecordingEnable = MEMORY_PROFILE_RECORDING_DISABLE;
- } else {
- mMemoryProfileRecordingEnable = MEMORY_PROFILE_RECORDING_ENABLE;
- }
-
- mMemoryProfileDriverPathSize = PcdGetSize (PcdMemoryProfileDriverPath);
- mMemoryProfileDriverPath = AllocateCopyPool (mMemoryProfileDriverPathSize, PcdGetPtr (PcdMemoryProfileDriverPath));
- mMemoryProfileContextPtr = &mMemoryProfileContext;
-
- RegisterDxeCore (HobStart, &mMemoryProfileContext);
-
- DEBUG ((DEBUG_INFO, "MemoryProfileInit MemoryProfileContext - 0x%x\n", &mMemoryProfileContext));
-}
-
-/**
- Install memory profile protocol.
-
-**/
-VOID
-MemoryProfileInstallProtocol (
- VOID
- )
-{
- EFI_HANDLE Handle;
- EFI_STATUS Status;
-
- if (!IS_UEFI_MEMORY_PROFILE_ENABLED) {
- return;
- }
-
- Handle = NULL;
- Status = CoreInstallMultipleProtocolInterfaces (
- &Handle,
- &gEdkiiMemoryProfileGuid,
- &mProfileProtocol,
- NULL
- );
- ASSERT_EFI_ERROR (Status);
-}
-
-/**
- Get the GUID file name from the file path.
-
- @param FilePath File path.
-
- @return The GUID file name from the file path.
-
-**/
-EFI_GUID *
-GetFileNameFromFilePath (
- IN EFI_DEVICE_PATH_PROTOCOL *FilePath
- )
-{
- MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *ThisFilePath;
- EFI_GUID *FileName;
-
- FileName = NULL;
- if (FilePath != NULL) {
- ThisFilePath = (MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *)FilePath;
- while (!IsDevicePathEnd (ThisFilePath)) {
- FileName = EfiGetNameGuidFromFwVolDevicePathNode (ThisFilePath);
- if (FileName != NULL) {
- break;
- }
-
- ThisFilePath = (MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *)NextDevicePathNode (ThisFilePath);
- }
- }
-
- return FileName;
-}
-
-/**
- Register image to memory profile.
-
- @param DriverEntry Image info.
- @param FileType Image file type.
-
- @return EFI_SUCCESS Register successfully.
- @return EFI_UNSUPPORTED Memory profile is unsupported,
- or memory profile for the image is not required.
- @return EFI_OUT_OF_RESOURCES No enough resource for this register.
-
-**/
-EFI_STATUS
-RegisterMemoryProfileImage (
- IN LOADED_IMAGE_PRIVATE_DATA *DriverEntry,
- IN EFI_FV_FILETYPE FileType
- )
-{
- MEMORY_PROFILE_CONTEXT_DATA *ContextData;
- MEMORY_PROFILE_DRIVER_INFO_DATA *DriverInfoData;
-
- if (!IS_UEFI_MEMORY_PROFILE_ENABLED) {
- return EFI_UNSUPPORTED;
- }
-
- if (!NeedRecordThisDriver (DriverEntry->Info.FilePath)) {
- return EFI_UNSUPPORTED;
- }
-
- ContextData = GetMemoryProfileContext ();
- if (ContextData == NULL) {
- return EFI_UNSUPPORTED;
- }
-
- DriverInfoData = BuildDriverInfo (
- ContextData,
- GetFileNameFromFilePath (DriverEntry->Info.FilePath),
- DriverEntry->ImageContext.ImageAddress,
- DriverEntry->ImageContext.ImageSize,
- DriverEntry->ImageContext.EntryPoint,
- DriverEntry->ImageContext.ImageType,
- FileType
- );
- if (DriverInfoData == NULL) {
- return EFI_OUT_OF_RESOURCES;
- }
-
- return EFI_SUCCESS;
-}
-
-/**
- Search image from memory profile.
-
- @param ContextData Memory profile context.
- @param FileName Image file name.
- @param Address Image Address.
-
- @return Pointer to memory profile driver info.
-
-**/
-MEMORY_PROFILE_DRIVER_INFO_DATA *
-GetMemoryProfileDriverInfoByFileNameAndAddress (
- IN MEMORY_PROFILE_CONTEXT_DATA *ContextData,
- IN EFI_GUID *FileName,
- IN PHYSICAL_ADDRESS Address
- )
-{
- MEMORY_PROFILE_DRIVER_INFO *DriverInfo;
- MEMORY_PROFILE_DRIVER_INFO_DATA *DriverInfoData;
- LIST_ENTRY *DriverLink;
- LIST_ENTRY *DriverInfoList;
-
- DriverInfoList = ContextData->DriverInfoList;
-
- for (DriverLink = DriverInfoList->ForwardLink;
- DriverLink != DriverInfoList;
- DriverLink = DriverLink->ForwardLink)
- {
- DriverInfoData = CR (
- DriverLink,
- MEMORY_PROFILE_DRIVER_INFO_DATA,
- Link,
- MEMORY_PROFILE_DRIVER_INFO_SIGNATURE
- );
- DriverInfo = &DriverInfoData->DriverInfo;
- if ((CompareGuid (&DriverInfo->FileName, FileName)) &&
- (Address >= DriverInfo->ImageBase) &&
- (Address < (DriverInfo->ImageBase + DriverInfo->ImageSize)))
- {
- return DriverInfoData;
- }
- }
-
- return NULL;
-}
-
-/**
- Search image from memory profile.
- It will return image, if (Address >= ImageBuffer) AND (Address < ImageBuffer + ImageSize).
-
- @param ContextData Memory profile context.
- @param Address Image or Function address.
-
- @return Pointer to memory profile driver info.
-
-**/
-MEMORY_PROFILE_DRIVER_INFO_DATA *
-GetMemoryProfileDriverInfoFromAddress (
- IN MEMORY_PROFILE_CONTEXT_DATA *ContextData,
- IN PHYSICAL_ADDRESS Address
- )
-{
- MEMORY_PROFILE_DRIVER_INFO *DriverInfo;
- MEMORY_PROFILE_DRIVER_INFO_DATA *DriverInfoData;
- LIST_ENTRY *DriverLink;
- LIST_ENTRY *DriverInfoList;
-
- DriverInfoList = ContextData->DriverInfoList;
-
- for (DriverLink = DriverInfoList->ForwardLink;
- DriverLink != DriverInfoList;
- DriverLink = DriverLink->ForwardLink)
- {
- DriverInfoData = CR (
- DriverLink,
- MEMORY_PROFILE_DRIVER_INFO_DATA,
- Link,
- MEMORY_PROFILE_DRIVER_INFO_SIGNATURE
- );
- DriverInfo = &DriverInfoData->DriverInfo;
- if ((Address >= DriverInfo->ImageBase) &&
- (Address < (DriverInfo->ImageBase + DriverInfo->ImageSize)))
- {
- return DriverInfoData;
- }
- }
-
- return NULL;
-}
-
-/**
- Unregister image from memory profile.
-
- @param DriverEntry Image info.
-
- @return EFI_SUCCESS Unregister successfully.
- @return EFI_UNSUPPORTED Memory profile is unsupported,
- or memory profile for the image is not required.
- @return EFI_NOT_FOUND The image is not found.
-
-**/
-EFI_STATUS
-UnregisterMemoryProfileImage (
- IN LOADED_IMAGE_PRIVATE_DATA *DriverEntry
- )
-{
- EFI_STATUS Status;
- MEMORY_PROFILE_CONTEXT_DATA *ContextData;
- MEMORY_PROFILE_DRIVER_INFO_DATA *DriverInfoData;
- EFI_GUID *FileName;
- PHYSICAL_ADDRESS ImageAddress;
- VOID *EntryPointInImage;
-
- if (!IS_UEFI_MEMORY_PROFILE_ENABLED) {
- return EFI_UNSUPPORTED;
- }
-
- if (!NeedRecordThisDriver (DriverEntry->Info.FilePath)) {
- return EFI_UNSUPPORTED;
- }
-
- ContextData = GetMemoryProfileContext ();
- if (ContextData == NULL) {
- return EFI_UNSUPPORTED;
- }
-
- DriverInfoData = NULL;
- FileName = GetFileNameFromFilePath (DriverEntry->Info.FilePath);
- ImageAddress = DriverEntry->ImageContext.ImageAddress;
- if ((DriverEntry->ImageContext.EntryPoint < ImageAddress) || (DriverEntry->ImageContext.EntryPoint >= (ImageAddress + DriverEntry->ImageContext.ImageSize))) {
- //
- // If the EntryPoint is not in the range of image buffer, it should come from emulation environment.
- // So patch ImageAddress here to align the EntryPoint.
- //
- Status = InternalPeCoffGetEntryPoint ((VOID *)(UINTN)ImageAddress, &EntryPointInImage);
- ASSERT_EFI_ERROR (Status);
- ImageAddress = ImageAddress + (UINTN)DriverEntry->ImageContext.EntryPoint - (UINTN)EntryPointInImage;
- }
-
- if (FileName != NULL) {
- DriverInfoData = GetMemoryProfileDriverInfoByFileNameAndAddress (ContextData, FileName, ImageAddress);
- }
-
- if (DriverInfoData == NULL) {
- DriverInfoData = GetMemoryProfileDriverInfoFromAddress (ContextData, ImageAddress);
- }
-
- if (DriverInfoData == NULL) {
- return EFI_NOT_FOUND;
- }
-
- ContextData->Context.TotalImageSize -= DriverInfoData->DriverInfo.ImageSize;
-
- // Keep the ImageBase for RVA calculation in Application.
- // DriverInfoData->DriverInfo.ImageBase = 0;
- DriverInfoData->DriverInfo.ImageSize = 0;
-
- if (DriverInfoData->DriverInfo.PeakUsage == 0) {
- ContextData->Context.ImageCount--;
- RemoveEntryList (&DriverInfoData->Link);
- //
- // Use CoreInternalFreePool() that will not update profile for this FreePool action.
- //
- CoreInternalFreePool (DriverInfoData, NULL);
- }
-
- return EFI_SUCCESS;
-}
-
-/**
- Return if this memory type needs to be recorded into memory profile.
- If BIOS memory type (0 ~ EfiMaxMemoryType - 1), it checks bit (1 << MemoryType).
- If OS memory type (0x80000000 ~ 0xFFFFFFFF), it checks bit63 - 0x8000000000000000.
- If OEM memory type (0x70000000 ~ 0x7FFFFFFF), it checks bit62 - 0x4000000000000000.
-
- @param MemoryType Memory type.
-
- @retval TRUE This memory type need to be recorded.
- @retval FALSE This memory type need not to be recorded.
-
-**/
-BOOLEAN
-CoreNeedRecordProfile (
- IN EFI_MEMORY_TYPE MemoryType
- )
-{
- UINT64 TestBit;
-
- if ((UINT32)MemoryType >= MEMORY_TYPE_OS_RESERVED_MIN) {
- TestBit = BIT63;
- } else if ((UINT32)MemoryType >= MEMORY_TYPE_OEM_RESERVED_MIN) {
- TestBit = BIT62;
- } else {
- TestBit = LShiftU64 (1, MemoryType);
- }
-
- if ((PcdGet64 (PcdMemoryProfileMemoryType) & TestBit) != 0) {
- return TRUE;
- } else {
- return FALSE;
- }
-}
-
-/**
- Convert EFI memory type to profile memory index. The rule is:
- If BIOS memory type (0 ~ EfiMaxMemoryType - 1), ProfileMemoryIndex = MemoryType.
- If OS memory type (0x80000000 ~ 0xFFFFFFFF), ProfileMemoryIndex = EfiMaxMemoryType.
- If OEM memory type (0x70000000 ~ 0x7FFFFFFF), ProfileMemoryIndex = EfiMaxMemoryType + 1.
-
- @param MemoryType Memory type.
-
- @return Profile memory index.
-
-**/
-UINTN
-GetProfileMemoryIndex (
- IN EFI_MEMORY_TYPE MemoryType
- )
-{
- if ((UINT32)MemoryType >= MEMORY_TYPE_OS_RESERVED_MIN) {
- return EfiMaxMemoryType;
- } else if ((UINT32)MemoryType >= MEMORY_TYPE_OEM_RESERVED_MIN) {
- return EfiMaxMemoryType + 1;
- } else {
- return MemoryType;
- }
-}
-
-/**
- Update memory profile Allocate information.
-
- @param CallerAddress Address of caller who call Allocate.
- @param Action This Allocate action.
- @param MemoryType Memory type.
- @param Size Buffer size.
- @param Buffer Buffer address.
- @param ActionString String for memory profile action.
-
- @return EFI_SUCCESS Memory profile is updated.
- @return EFI_UNSUPPORTED Memory profile is unsupported,
- or memory profile for the image is not required.
- @return EFI_OUT_OF_RESOURCES No enough resource to update memory profile for allocate action.
-
-**/
-EFI_STATUS
-CoreUpdateProfileAllocate (
- IN PHYSICAL_ADDRESS CallerAddress,
- IN MEMORY_PROFILE_ACTION Action,
- IN EFI_MEMORY_TYPE MemoryType,
- IN UINTN Size,
- IN VOID *Buffer,
- IN CHAR8 *ActionString OPTIONAL
- )
-{
- EFI_STATUS Status;
- MEMORY_PROFILE_CONTEXT *Context;
- MEMORY_PROFILE_DRIVER_INFO *DriverInfo;
- MEMORY_PROFILE_ALLOC_INFO *AllocInfo;
- MEMORY_PROFILE_CONTEXT_DATA *ContextData;
- MEMORY_PROFILE_DRIVER_INFO_DATA *DriverInfoData;
- MEMORY_PROFILE_ALLOC_INFO_DATA *AllocInfoData;
- UINTN ProfileMemoryIndex;
- MEMORY_PROFILE_ACTION BasicAction;
- UINTN ActionStringSize;
- UINTN ActionStringOccupiedSize;
-
- BasicAction = Action & MEMORY_PROFILE_ACTION_BASIC_MASK;
-
- ContextData = GetMemoryProfileContext ();
- if (ContextData == NULL) {
- return EFI_UNSUPPORTED;
- }
-
- DriverInfoData = GetMemoryProfileDriverInfoFromAddress (ContextData, CallerAddress);
- if (DriverInfoData == NULL) {
- return EFI_UNSUPPORTED;
- }
-
- ActionStringSize = 0;
- ActionStringOccupiedSize = 0;
- if (ActionString != NULL) {
- ActionStringSize = AsciiStrSize (ActionString);
- ActionStringOccupiedSize = GET_OCCUPIED_SIZE (ActionStringSize, sizeof (UINT64));
- }
-
- //
- // Use CoreInternalAllocatePool() that will not update profile for this AllocatePool action.
- //
- AllocInfoData = NULL;
- Status = CoreInternalAllocatePool (
- EfiBootServicesData,
- sizeof (*AllocInfoData) + ActionStringSize,
- (VOID **)&AllocInfoData
- );
- if (EFI_ERROR (Status)) {
- return EFI_OUT_OF_RESOURCES;
- }
-
- ASSERT (AllocInfoData != NULL);
-
- //
- // Only update SequenceCount if and only if it is basic action.
- //
- if (Action == BasicAction) {
- ContextData->Context.SequenceCount++;
- }
-
- AllocInfo = &AllocInfoData->AllocInfo;
- AllocInfoData->Signature = MEMORY_PROFILE_ALLOC_INFO_SIGNATURE;
- AllocInfo->Header.Signature = MEMORY_PROFILE_ALLOC_INFO_SIGNATURE;
- AllocInfo->Header.Length = (UINT16)(sizeof (MEMORY_PROFILE_ALLOC_INFO) + ActionStringOccupiedSize);
- AllocInfo->Header.Revision = MEMORY_PROFILE_ALLOC_INFO_REVISION;
- AllocInfo->CallerAddress = CallerAddress;
- AllocInfo->SequenceId = ContextData->Context.SequenceCount;
- AllocInfo->Action = Action;
- AllocInfo->MemoryType = MemoryType;
- AllocInfo->Buffer = (PHYSICAL_ADDRESS)(UINTN)Buffer;
- AllocInfo->Size = Size;
- if (ActionString != NULL) {
- AllocInfo->ActionStringOffset = (UINT16)sizeof (MEMORY_PROFILE_ALLOC_INFO);
- AllocInfoData->ActionString = (CHAR8 *)(AllocInfoData + 1);
- CopyMem (AllocInfoData->ActionString, ActionString, ActionStringSize);
- } else {
- AllocInfo->ActionStringOffset = 0;
- AllocInfoData->ActionString = NULL;
- }
-
- InsertTailList (DriverInfoData->AllocInfoList, &AllocInfoData->Link);
-
- Context = &ContextData->Context;
- DriverInfo = &DriverInfoData->DriverInfo;
- DriverInfo->AllocRecordCount++;
-
- //
- // Update summary if and only if it is basic action.
- //
- if (Action == BasicAction) {
- ProfileMemoryIndex = GetProfileMemoryIndex (MemoryType);
-
- DriverInfo->CurrentUsage += Size;
- if (DriverInfo->PeakUsage < DriverInfo->CurrentUsage) {
- DriverInfo->PeakUsage = DriverInfo->CurrentUsage;
- }
-
- DriverInfo->CurrentUsageByType[ProfileMemoryIndex] += Size;
- if (DriverInfo->PeakUsageByType[ProfileMemoryIndex] < DriverInfo->CurrentUsageByType[ProfileMemoryIndex]) {
- DriverInfo->PeakUsageByType[ProfileMemoryIndex] = DriverInfo->CurrentUsageByType[ProfileMemoryIndex];
- }
-
- Context->CurrentTotalUsage += Size;
- if (Context->PeakTotalUsage < Context->CurrentTotalUsage) {
- Context->PeakTotalUsage = Context->CurrentTotalUsage;
- }
-
- Context->CurrentTotalUsageByType[ProfileMemoryIndex] += Size;
- if (Context->PeakTotalUsageByType[ProfileMemoryIndex] < Context->CurrentTotalUsageByType[ProfileMemoryIndex]) {
- Context->PeakTotalUsageByType[ProfileMemoryIndex] = Context->CurrentTotalUsageByType[ProfileMemoryIndex];
- }
- }
-
- return EFI_SUCCESS;
-}
-
-/**
- Get memory profile alloc info from memory profile.
-
- @param DriverInfoData Driver info.
- @param BasicAction This Free basic action.
- @param Size Buffer size.
- @param Buffer Buffer address.
-
- @return Pointer to memory profile alloc info.
-
-**/
-MEMORY_PROFILE_ALLOC_INFO_DATA *
-GetMemoryProfileAllocInfoFromAddress (
- IN MEMORY_PROFILE_DRIVER_INFO_DATA *DriverInfoData,
- IN MEMORY_PROFILE_ACTION BasicAction,
- IN UINTN Size,
- IN VOID *Buffer
- )
-{
- LIST_ENTRY *AllocInfoList;
- LIST_ENTRY *AllocLink;
- MEMORY_PROFILE_ALLOC_INFO *AllocInfo;
- MEMORY_PROFILE_ALLOC_INFO_DATA *AllocInfoData;
-
- AllocInfoList = DriverInfoData->AllocInfoList;
-
- for (AllocLink = AllocInfoList->ForwardLink;
- AllocLink != AllocInfoList;
- AllocLink = AllocLink->ForwardLink)
- {
- AllocInfoData = CR (
- AllocLink,
- MEMORY_PROFILE_ALLOC_INFO_DATA,
- Link,
- MEMORY_PROFILE_ALLOC_INFO_SIGNATURE
- );
- AllocInfo = &AllocInfoData->AllocInfo;
- if ((AllocInfo->Action & MEMORY_PROFILE_ACTION_BASIC_MASK) != BasicAction) {
- continue;
- }
-
- switch (BasicAction) {
- case MemoryProfileActionAllocatePages:
- if ((AllocInfo->Buffer <= (PHYSICAL_ADDRESS)(UINTN)Buffer) &&
- ((AllocInfo->Buffer + AllocInfo->Size) >= ((PHYSICAL_ADDRESS)(UINTN)Buffer + Size)))
- {
- return AllocInfoData;
- }
-
- break;
- case MemoryProfileActionAllocatePool:
- if (AllocInfo->Buffer == (PHYSICAL_ADDRESS)(UINTN)Buffer) {
- return AllocInfoData;
- }
-
- break;
- default:
- ASSERT (FALSE);
- break;
- }
- }
-
- return NULL;
-}
-
-/**
- Update memory profile Free information.
-
- @param CallerAddress Address of caller who call Free.
- @param Action This Free action.
- @param Size Buffer size.
- @param Buffer Buffer address.
-
- @return EFI_SUCCESS Memory profile is updated.
- @return EFI_UNSUPPORTED Memory profile is unsupported.
- @return EFI_NOT_FOUND No matched allocate info found for free action.
-
-**/
-EFI_STATUS
-CoreUpdateProfileFree (
- IN PHYSICAL_ADDRESS CallerAddress,
- IN MEMORY_PROFILE_ACTION Action,
- IN UINTN Size,
- IN VOID *Buffer
- )
-{
- MEMORY_PROFILE_CONTEXT *Context;
- MEMORY_PROFILE_DRIVER_INFO *DriverInfo;
- MEMORY_PROFILE_ALLOC_INFO *AllocInfo;
- MEMORY_PROFILE_CONTEXT_DATA *ContextData;
- MEMORY_PROFILE_DRIVER_INFO_DATA *DriverInfoData;
- LIST_ENTRY *DriverLink;
- LIST_ENTRY *DriverInfoList;
- MEMORY_PROFILE_DRIVER_INFO_DATA *ThisDriverInfoData;
- MEMORY_PROFILE_ALLOC_INFO_DATA *AllocInfoData;
- UINTN ProfileMemoryIndex;
- MEMORY_PROFILE_ACTION BasicAction;
- BOOLEAN Found;
-
- BasicAction = Action & MEMORY_PROFILE_ACTION_BASIC_MASK;
-
- ContextData = GetMemoryProfileContext ();
- if (ContextData == NULL) {
- return EFI_UNSUPPORTED;
- }
-
- DriverInfoData = GetMemoryProfileDriverInfoFromAddress (ContextData, CallerAddress);
-
- //
- // Do not return if DriverInfoData == NULL here,
- // because driver A might free memory allocated by driver B.
- //
-
- //
- // Need use do-while loop to find all possible records,
- // because one address might be recorded multiple times.
- //
- Found = FALSE;
- AllocInfoData = NULL;
- do {
- if (DriverInfoData != NULL) {
- switch (BasicAction) {
- case MemoryProfileActionFreePages:
- AllocInfoData = GetMemoryProfileAllocInfoFromAddress (DriverInfoData, MemoryProfileActionAllocatePages, Size, Buffer);
- break;
- case MemoryProfileActionFreePool:
- AllocInfoData = GetMemoryProfileAllocInfoFromAddress (DriverInfoData, MemoryProfileActionAllocatePool, 0, Buffer);
- break;
- default:
- ASSERT (FALSE);
- AllocInfoData = NULL;
- break;
- }
- }
-
- if (AllocInfoData == NULL) {
- //
- // Legal case, because driver A might free memory allocated by driver B, by some protocol.
- //
- DriverInfoList = ContextData->DriverInfoList;
-
- for (DriverLink = DriverInfoList->ForwardLink;
- DriverLink != DriverInfoList;
- DriverLink = DriverLink->ForwardLink)
- {
- ThisDriverInfoData = CR (
- DriverLink,
- MEMORY_PROFILE_DRIVER_INFO_DATA,
- Link,
- MEMORY_PROFILE_DRIVER_INFO_SIGNATURE
- );
- switch (BasicAction) {
- case MemoryProfileActionFreePages:
- AllocInfoData = GetMemoryProfileAllocInfoFromAddress (ThisDriverInfoData, MemoryProfileActionAllocatePages, Size, Buffer);
- break;
- case MemoryProfileActionFreePool:
- AllocInfoData = GetMemoryProfileAllocInfoFromAddress (ThisDriverInfoData, MemoryProfileActionAllocatePool, 0, Buffer);
- break;
- default:
- ASSERT (FALSE);
- AllocInfoData = NULL;
- break;
- }
-
- if (AllocInfoData != NULL) {
- DriverInfoData = ThisDriverInfoData;
- break;
- }
- }
-
- if (AllocInfoData == NULL) {
- //
- // If (!Found), no matched allocate info is found for this free action.
- // It is because the specified memory type allocate actions have been filtered by
- // CoreNeedRecordProfile(), but free actions may have no memory type information,
- // they can not be filtered by CoreNeedRecordProfile(). Then, they will be
- // filtered here.
- //
- // If (Found), it is normal exit path.
- return (Found ? EFI_SUCCESS : EFI_NOT_FOUND);
- }
- }
-
- ASSERT (DriverInfoData != NULL);
- ASSERT (AllocInfoData != NULL);
-
- Found = TRUE;
-
- Context = &ContextData->Context;
- DriverInfo = &DriverInfoData->DriverInfo;
- AllocInfo = &AllocInfoData->AllocInfo;
-
- DriverInfo->AllocRecordCount--;
- //
- // Update summary if and only if it is basic action.
- //
- if (AllocInfo->Action == (AllocInfo->Action & MEMORY_PROFILE_ACTION_BASIC_MASK)) {
- ProfileMemoryIndex = GetProfileMemoryIndex (AllocInfo->MemoryType);
-
- Context->CurrentTotalUsage -= AllocInfo->Size;
- Context->CurrentTotalUsageByType[ProfileMemoryIndex] -= AllocInfo->Size;
-
- DriverInfo->CurrentUsage -= AllocInfo->Size;
- DriverInfo->CurrentUsageByType[ProfileMemoryIndex] -= AllocInfo->Size;
- }
-
- RemoveEntryList (&AllocInfoData->Link);
-
- if (BasicAction == MemoryProfileActionFreePages) {
- if (AllocInfo->Buffer != (PHYSICAL_ADDRESS)(UINTN)Buffer) {
- CoreUpdateProfileAllocate (
- AllocInfo->CallerAddress,
- AllocInfo->Action,
- AllocInfo->MemoryType,
- (UINTN)((PHYSICAL_ADDRESS)(UINTN)Buffer - AllocInfo->Buffer),
- (VOID *)(UINTN)AllocInfo->Buffer,
- AllocInfoData->ActionString
- );
- }
-
- if (AllocInfo->Buffer + AllocInfo->Size != ((PHYSICAL_ADDRESS)(UINTN)Buffer + Size)) {
- CoreUpdateProfileAllocate (
- AllocInfo->CallerAddress,
- AllocInfo->Action,
- AllocInfo->MemoryType,
- (UINTN)((AllocInfo->Buffer + AllocInfo->Size) - ((PHYSICAL_ADDRESS)(UINTN)Buffer + Size)),
- (VOID *)((UINTN)Buffer + Size),
- AllocInfoData->ActionString
- );
- }
- }
-
- //
- // Use CoreInternalFreePool() that will not update profile for this FreePool action.
- //
- CoreInternalFreePool (AllocInfoData, NULL);
- } while (TRUE);
-}
-
-/**
- Update memory profile information.
-
- @param CallerAddress Address of caller who call Allocate or Free.
- @param Action This Allocate or Free action.
- @param MemoryType Memory type.
- EfiMaxMemoryType means the MemoryType is unknown.
- @param Size Buffer size.
- @param Buffer Buffer address.
- @param ActionString String for memory profile action.
- Only needed for user defined allocate action.
-
- @return EFI_SUCCESS Memory profile is updated.
- @return EFI_UNSUPPORTED Memory profile is unsupported,
- or memory profile for the image is not required,
- or memory profile for the memory type is not required.
- @return EFI_ACCESS_DENIED It is during memory profile data getting.
- @return EFI_ABORTED Memory profile recording is not enabled.
- @return EFI_OUT_OF_RESOURCES No enough resource to update memory profile for allocate action.
- @return EFI_NOT_FOUND No matched allocate info found for free action.
-
-**/
-EFI_STATUS
-EFIAPI
-CoreUpdateProfile (
- IN PHYSICAL_ADDRESS CallerAddress,
- IN MEMORY_PROFILE_ACTION Action,
- IN EFI_MEMORY_TYPE MemoryType,
- IN UINTN Size, // Valid for AllocatePages/FreePages/AllocatePool
- IN VOID *Buffer,
- IN CHAR8 *ActionString OPTIONAL
- )
-{
- EFI_STATUS Status;
- MEMORY_PROFILE_CONTEXT_DATA *ContextData;
- MEMORY_PROFILE_ACTION BasicAction;
-
- if (!IS_UEFI_MEMORY_PROFILE_ENABLED) {
- return EFI_UNSUPPORTED;
- }
-
- if (mMemoryProfileGettingStatus) {
- return EFI_ACCESS_DENIED;
- }
-
- if (!mMemoryProfileRecordingEnable) {
- return EFI_ABORTED;
- }
-
- //
- // Get the basic action to know how to process the record
- //
- BasicAction = Action & MEMORY_PROFILE_ACTION_BASIC_MASK;
-
- //
- // EfiMaxMemoryType means the MemoryType is unknown.
- //
- if (MemoryType != EfiMaxMemoryType) {
- //
- // Only record limited MemoryType.
- //
- if (!CoreNeedRecordProfile (MemoryType)) {
- return EFI_UNSUPPORTED;
- }
- }
-
- ContextData = GetMemoryProfileContext ();
- if (ContextData == NULL) {
- return EFI_UNSUPPORTED;
- }
-
- CoreAcquireMemoryProfileLock ();
- switch (BasicAction) {
- case MemoryProfileActionAllocatePages:
- Status = CoreUpdateProfileAllocate (CallerAddress, Action, MemoryType, Size, Buffer, ActionString);
- break;
- case MemoryProfileActionFreePages:
- Status = CoreUpdateProfileFree (CallerAddress, Action, Size, Buffer);
- break;
- case MemoryProfileActionAllocatePool:
- Status = CoreUpdateProfileAllocate (CallerAddress, Action, MemoryType, Size, Buffer, ActionString);
- break;
- case MemoryProfileActionFreePool:
- Status = CoreUpdateProfileFree (CallerAddress, Action, 0, Buffer);
- break;
- default:
- ASSERT (FALSE);
- Status = EFI_UNSUPPORTED;
- break;
- }
-
- CoreReleaseMemoryProfileLock ();
-
- return Status;
-}
-
-////////////////////
-
-/**
- Get memory profile data size.
-
- @return Memory profile data size.
-
-**/
-UINTN
-MemoryProfileGetDataSize (
- VOID
- )
-{
- MEMORY_PROFILE_CONTEXT_DATA *ContextData;
- MEMORY_PROFILE_DRIVER_INFO_DATA *DriverInfoData;
- MEMORY_PROFILE_ALLOC_INFO_DATA *AllocInfoData;
- LIST_ENTRY *DriverInfoList;
- LIST_ENTRY *DriverLink;
- LIST_ENTRY *AllocInfoList;
- LIST_ENTRY *AllocLink;
- UINTN TotalSize;
-
- ContextData = GetMemoryProfileContext ();
- if (ContextData == NULL) {
- return 0;
- }
-
- TotalSize = sizeof (MEMORY_PROFILE_CONTEXT);
-
- DriverInfoList = ContextData->DriverInfoList;
- for (DriverLink = DriverInfoList->ForwardLink;
- DriverLink != DriverInfoList;
- DriverLink = DriverLink->ForwardLink)
- {
- DriverInfoData = CR (
- DriverLink,
- MEMORY_PROFILE_DRIVER_INFO_DATA,
- Link,
- MEMORY_PROFILE_DRIVER_INFO_SIGNATURE
- );
- TotalSize += DriverInfoData->DriverInfo.Header.Length;
-
- AllocInfoList = DriverInfoData->AllocInfoList;
- for (AllocLink = AllocInfoList->ForwardLink;
- AllocLink != AllocInfoList;
- AllocLink = AllocLink->ForwardLink)
- {
- AllocInfoData = CR (
- AllocLink,
- MEMORY_PROFILE_ALLOC_INFO_DATA,
- Link,
- MEMORY_PROFILE_ALLOC_INFO_SIGNATURE
- );
- TotalSize += AllocInfoData->AllocInfo.Header.Length;
- }
- }
-
- return TotalSize;
-}
-
-/**
- Copy memory profile data.
-
- @param ProfileBuffer The buffer to hold memory profile data.
-
-**/
-VOID
-MemoryProfileCopyData (
- IN VOID *ProfileBuffer
- )
-{
- MEMORY_PROFILE_CONTEXT *Context;
- MEMORY_PROFILE_DRIVER_INFO *DriverInfo;
- MEMORY_PROFILE_ALLOC_INFO *AllocInfo;
- MEMORY_PROFILE_CONTEXT_DATA *ContextData;
- MEMORY_PROFILE_DRIVER_INFO_DATA *DriverInfoData;
- MEMORY_PROFILE_ALLOC_INFO_DATA *AllocInfoData;
- LIST_ENTRY *DriverInfoList;
- LIST_ENTRY *DriverLink;
- LIST_ENTRY *AllocInfoList;
- LIST_ENTRY *AllocLink;
- UINTN PdbSize;
- UINTN ActionStringSize;
-
- ContextData = GetMemoryProfileContext ();
- if (ContextData == NULL) {
- return;
- }
-
- Context = ProfileBuffer;
- CopyMem (Context, &ContextData->Context, sizeof (MEMORY_PROFILE_CONTEXT));
- DriverInfo = (MEMORY_PROFILE_DRIVER_INFO *)(Context + 1);
-
- DriverInfoList = ContextData->DriverInfoList;
- for (DriverLink = DriverInfoList->ForwardLink;
- DriverLink != DriverInfoList;
- DriverLink = DriverLink->ForwardLink)
- {
- DriverInfoData = CR (
- DriverLink,
- MEMORY_PROFILE_DRIVER_INFO_DATA,
- Link,
- MEMORY_PROFILE_DRIVER_INFO_SIGNATURE
- );
- CopyMem (DriverInfo, &DriverInfoData->DriverInfo, sizeof (MEMORY_PROFILE_DRIVER_INFO));
- if (DriverInfo->PdbStringOffset != 0) {
- PdbSize = AsciiStrSize (DriverInfoData->PdbString);
- CopyMem ((VOID *)((UINTN)DriverInfo + DriverInfo->PdbStringOffset), DriverInfoData->PdbString, PdbSize);
- }
-
- AllocInfo = (MEMORY_PROFILE_ALLOC_INFO *)((UINTN)DriverInfo + DriverInfo->Header.Length);
-
- AllocInfoList = DriverInfoData->AllocInfoList;
- for (AllocLink = AllocInfoList->ForwardLink;
- AllocLink != AllocInfoList;
- AllocLink = AllocLink->ForwardLink)
- {
- AllocInfoData = CR (
- AllocLink,
- MEMORY_PROFILE_ALLOC_INFO_DATA,
- Link,
- MEMORY_PROFILE_ALLOC_INFO_SIGNATURE
- );
- CopyMem (AllocInfo, &AllocInfoData->AllocInfo, sizeof (MEMORY_PROFILE_ALLOC_INFO));
- if (AllocInfo->ActionStringOffset != 0) {
- ActionStringSize = AsciiStrSize (AllocInfoData->ActionString);
- CopyMem ((VOID *)((UINTN)AllocInfo + AllocInfo->ActionStringOffset), AllocInfoData->ActionString, ActionStringSize);
- }
-
- AllocInfo = (MEMORY_PROFILE_ALLOC_INFO *)((UINTN)AllocInfo + AllocInfo->Header.Length);
- }
-
- DriverInfo = (MEMORY_PROFILE_DRIVER_INFO *)AllocInfo;
- }
-}
-
-/**
- Get memory profile data.
-
- @param[in] This The EDKII_MEMORY_PROFILE_PROTOCOL instance.
- @param[in, out] ProfileSize On entry, points to the size in bytes of the ProfileBuffer.
- On return, points to the size of the data returned in ProfileBuffer.
- @param[out] ProfileBuffer Profile buffer.
-
- @return EFI_SUCCESS Get the memory profile data successfully.
- @return EFI_UNSUPPORTED Memory profile is unsupported.
- @return EFI_BUFFER_TO_SMALL The ProfileSize is too small for the resulting data.
- ProfileSize is updated with the size required.
-
-**/
-EFI_STATUS
-EFIAPI
-ProfileProtocolGetData (
- IN EDKII_MEMORY_PROFILE_PROTOCOL *This,
- IN OUT UINT64 *ProfileSize,
- OUT VOID *ProfileBuffer
- )
-{
- UINTN Size;
- MEMORY_PROFILE_CONTEXT_DATA *ContextData;
- BOOLEAN MemoryProfileGettingStatus;
-
- ContextData = GetMemoryProfileContext ();
- if (ContextData == NULL) {
- return EFI_UNSUPPORTED;
- }
-
- MemoryProfileGettingStatus = mMemoryProfileGettingStatus;
- mMemoryProfileGettingStatus = TRUE;
-
- Size = MemoryProfileGetDataSize ();
-
- if (*ProfileSize < Size) {
- *ProfileSize = Size;
- mMemoryProfileGettingStatus = MemoryProfileGettingStatus;
- return EFI_BUFFER_TOO_SMALL;
- }
-
- *ProfileSize = Size;
- MemoryProfileCopyData (ProfileBuffer);
-
- mMemoryProfileGettingStatus = MemoryProfileGettingStatus;
- return EFI_SUCCESS;
-}
-
-/**
- Register image to memory profile.
-
- @param[in] This The EDKII_MEMORY_PROFILE_PROTOCOL instance.
- @param[in] FilePath File path of the image.
- @param[in] ImageBase Image base address.
- @param[in] ImageSize Image size.
- @param[in] FileType File type of the image.
-
- @return EFI_SUCCESS Register successfully.
- @return EFI_UNSUPPORTED Memory profile is unsupported,
- or memory profile for the image is not required.
- @return EFI_OUT_OF_RESOURCES No enough resource for this register.
-
-**/
-EFI_STATUS
-EFIAPI
-ProfileProtocolRegisterImage (
- IN EDKII_MEMORY_PROFILE_PROTOCOL *This,
- IN EFI_DEVICE_PATH_PROTOCOL *FilePath,
- IN PHYSICAL_ADDRESS ImageBase,
- IN UINT64 ImageSize,
- IN EFI_FV_FILETYPE FileType
- )
-{
- EFI_STATUS Status;
- LOADED_IMAGE_PRIVATE_DATA DriverEntry;
- VOID *EntryPointInImage;
-
- ZeroMem (&DriverEntry, sizeof (DriverEntry));
- DriverEntry.Info.FilePath = FilePath;
- DriverEntry.ImageContext.ImageAddress = ImageBase;
- DriverEntry.ImageContext.ImageSize = ImageSize;
- Status = InternalPeCoffGetEntryPoint ((VOID *)(UINTN)ImageBase, &EntryPointInImage);
- ASSERT_EFI_ERROR (Status);
- DriverEntry.ImageContext.EntryPoint = (PHYSICAL_ADDRESS)(UINTN)EntryPointInImage;
- DriverEntry.ImageContext.ImageType = InternalPeCoffGetSubsystem ((VOID *)(UINTN)ImageBase);
-
- return RegisterMemoryProfileImage (&DriverEntry, FileType);
-}
-
-/**
- Unregister image from memory profile.
-
- @param[in] This The EDKII_MEMORY_PROFILE_PROTOCOL instance.
- @param[in] FilePath File path of the image.
- @param[in] ImageBase Image base address.
- @param[in] ImageSize Image size.
-
- @return EFI_SUCCESS Unregister successfully.
- @return EFI_UNSUPPORTED Memory profile is unsupported,
- or memory profile for the image is not required.
- @return EFI_NOT_FOUND The image is not found.
-
-**/
-EFI_STATUS
-EFIAPI
-ProfileProtocolUnregisterImage (
- IN EDKII_MEMORY_PROFILE_PROTOCOL *This,
- IN EFI_DEVICE_PATH_PROTOCOL *FilePath,
- IN PHYSICAL_ADDRESS ImageBase,
- IN UINT64 ImageSize
- )
-{
- EFI_STATUS Status;
- LOADED_IMAGE_PRIVATE_DATA DriverEntry;
- VOID *EntryPointInImage;
-
- ZeroMem (&DriverEntry, sizeof (DriverEntry));
- DriverEntry.Info.FilePath = FilePath;
- DriverEntry.ImageContext.ImageAddress = ImageBase;
- DriverEntry.ImageContext.ImageSize = ImageSize;
- Status = InternalPeCoffGetEntryPoint ((VOID *)(UINTN)ImageBase, &EntryPointInImage);
- ASSERT_EFI_ERROR (Status);
- DriverEntry.ImageContext.EntryPoint = (PHYSICAL_ADDRESS)(UINTN)EntryPointInImage;
-
- return UnregisterMemoryProfileImage (&DriverEntry);
-}
-
-/**
- Get memory profile recording state.
-
- @param[in] This The EDKII_MEMORY_PROFILE_PROTOCOL instance.
- @param[out] RecordingState Recording state.
-
- @return EFI_SUCCESS Memory profile recording state is returned.
- @return EFI_UNSUPPORTED Memory profile is unsupported.
- @return EFI_INVALID_PARAMETER RecordingState is NULL.
-
-**/
-EFI_STATUS
-EFIAPI
-ProfileProtocolGetRecordingState (
- IN EDKII_MEMORY_PROFILE_PROTOCOL *This,
- OUT BOOLEAN *RecordingState
- )
-{
- MEMORY_PROFILE_CONTEXT_DATA *ContextData;
-
- ContextData = GetMemoryProfileContext ();
- if (ContextData == NULL) {
- return EFI_UNSUPPORTED;
- }
-
- if (RecordingState == NULL) {
- return EFI_INVALID_PARAMETER;
- }
-
- *RecordingState = mMemoryProfileRecordingEnable;
- return EFI_SUCCESS;
-}
-
-/**
- Set memory profile recording state.
-
- @param[in] This The EDKII_MEMORY_PROFILE_PROTOCOL instance.
- @param[in] RecordingState Recording state.
-
- @return EFI_SUCCESS Set memory profile recording state successfully.
- @return EFI_UNSUPPORTED Memory profile is unsupported.
-
-**/
-EFI_STATUS
-EFIAPI
-ProfileProtocolSetRecordingState (
- IN EDKII_MEMORY_PROFILE_PROTOCOL *This,
- IN BOOLEAN RecordingState
- )
-{
- MEMORY_PROFILE_CONTEXT_DATA *ContextData;
-
- ContextData = GetMemoryProfileContext ();
- if (ContextData == NULL) {
- return EFI_UNSUPPORTED;
- }
-
- mMemoryProfileRecordingEnable = RecordingState;
- return EFI_SUCCESS;
-}
-
-/**
- Record memory profile of multilevel caller.
-
- @param[in] This The EDKII_MEMORY_PROFILE_PROTOCOL instance.
- @param[in] CallerAddress Address of caller.
- @param[in] Action Memory profile action.
- @param[in] MemoryType Memory type.
- EfiMaxMemoryType means the MemoryType is unknown.
- @param[in] Buffer Buffer address.
- @param[in] Size Buffer size.
- @param[in] ActionString String for memory profile action.
- Only needed for user defined allocate action.
-
- @return EFI_SUCCESS Memory profile is updated.
- @return EFI_UNSUPPORTED Memory profile is unsupported,
- or memory profile for the image is not required,
- or memory profile for the memory type is not required.
- @return EFI_ACCESS_DENIED It is during memory profile data getting.
- @return EFI_ABORTED Memory profile recording is not enabled.
- @return EFI_OUT_OF_RESOURCES No enough resource to update memory profile for allocate action.
- @return EFI_NOT_FOUND No matched allocate info found for free action.
-
-**/
-EFI_STATUS
-EFIAPI
-ProfileProtocolRecord (
- IN EDKII_MEMORY_PROFILE_PROTOCOL *This,
- IN PHYSICAL_ADDRESS CallerAddress,
- IN MEMORY_PROFILE_ACTION Action,
- IN EFI_MEMORY_TYPE MemoryType,
- IN VOID *Buffer,
- IN UINTN Size,
- IN CHAR8 *ActionString OPTIONAL
- )
-{
- return CoreUpdateProfile (CallerAddress, Action, MemoryType, Size, Buffer, ActionString);
-}
-
-////////////////////
+/** @file
+ Support routines for UEFI memory profile.
+
+ Copyright (c) 2014 - 2018, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "DxeMain.h"
+#include "Imem.h"
+
+#define IS_UEFI_MEMORY_PROFILE_ENABLED ((PcdGet8 (PcdMemoryProfilePropertyMask) & BIT0) != 0)
+
+#define GET_OCCUPIED_SIZE(ActualSize, Alignment) \
+ ((ActualSize) + (((Alignment) - ((ActualSize) & ((Alignment) - 1))) & ((Alignment) - 1)))
+
+typedef struct {
+ UINT32 Signature;
+ MEMORY_PROFILE_CONTEXT Context;
+ LIST_ENTRY *DriverInfoList;
+} MEMORY_PROFILE_CONTEXT_DATA;
+
+typedef struct {
+ UINT32 Signature;
+ MEMORY_PROFILE_DRIVER_INFO DriverInfo;
+ LIST_ENTRY *AllocInfoList;
+ CHAR8 *PdbString;
+ LIST_ENTRY Link;
+} MEMORY_PROFILE_DRIVER_INFO_DATA;
+
+typedef struct {
+ UINT32 Signature;
+ MEMORY_PROFILE_ALLOC_INFO AllocInfo;
+ CHAR8 *ActionString;
+ LIST_ENTRY Link;
+} MEMORY_PROFILE_ALLOC_INFO_DATA;
+
+GLOBAL_REMOVE_IF_UNREFERENCED LIST_ENTRY mImageQueue = INITIALIZE_LIST_HEAD_VARIABLE (mImageQueue);
+GLOBAL_REMOVE_IF_UNREFERENCED MEMORY_PROFILE_CONTEXT_DATA mMemoryProfileContext = {
+ MEMORY_PROFILE_CONTEXT_SIGNATURE,
+ {
+ {
+ MEMORY_PROFILE_CONTEXT_SIGNATURE,
+ sizeof (MEMORY_PROFILE_CONTEXT),
+ MEMORY_PROFILE_CONTEXT_REVISION
+ },
+ 0,
+ 0,
+ { 0 },
+ { 0 },
+ 0,
+ 0,
+ 0
+ },
+ &mImageQueue,
+};
+GLOBAL_REMOVE_IF_UNREFERENCED MEMORY_PROFILE_CONTEXT_DATA *mMemoryProfileContextPtr = NULL;
+
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_LOCK mMemoryProfileLock = EFI_INITIALIZE_LOCK_VARIABLE (TPL_NOTIFY);
+GLOBAL_REMOVE_IF_UNREFERENCED BOOLEAN mMemoryProfileGettingStatus = FALSE;
+GLOBAL_REMOVE_IF_UNREFERENCED BOOLEAN mMemoryProfileRecordingEnable = MEMORY_PROFILE_RECORDING_DISABLE;
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_DEVICE_PATH_PROTOCOL *mMemoryProfileDriverPath;
+GLOBAL_REMOVE_IF_UNREFERENCED UINTN mMemoryProfileDriverPathSize;
+
+/**
+ Get memory profile data.
+
+ @param[in] This The EDKII_MEMORY_PROFILE_PROTOCOL instance.
+ @param[in, out] ProfileSize On entry, points to the size in bytes of the ProfileBuffer.
+ On return, points to the size of the data returned in ProfileBuffer.
+ @param[out] ProfileBuffer Profile buffer.
+
+ @return EFI_SUCCESS Get the memory profile data successfully.
+ @return EFI_UNSUPPORTED Memory profile is unsupported.
+ @return EFI_BUFFER_TO_SMALL The ProfileSize is too small for the resulting data.
+ ProfileSize is updated with the size required.
+
+**/
+EFI_STATUS
+EFIAPI
+ProfileProtocolGetData (
+ IN EDKII_MEMORY_PROFILE_PROTOCOL *This,
+ IN OUT UINT64 *ProfileSize,
+ OUT VOID *ProfileBuffer
+ );
+
+/**
+ Register image to memory profile.
+
+ @param[in] This The EDKII_MEMORY_PROFILE_PROTOCOL instance.
+ @param[in] FilePath File path of the image.
+ @param[in] ImageBase Image base address.
+ @param[in] ImageSize Image size.
+ @param[in] FileType File type of the image.
+
+ @return EFI_SUCCESS Register successfully.
+ @return EFI_UNSUPPORTED Memory profile is unsupported,
+ or memory profile for the image is not required.
+ @return EFI_OUT_OF_RESOURCE No enough resource for this register.
+
+**/
+EFI_STATUS
+EFIAPI
+ProfileProtocolRegisterImage (
+ IN EDKII_MEMORY_PROFILE_PROTOCOL *This,
+ IN EFI_DEVICE_PATH_PROTOCOL *FilePath,
+ IN PHYSICAL_ADDRESS ImageBase,
+ IN UINT64 ImageSize,
+ IN EFI_FV_FILETYPE FileType
+ );
+
+/**
+ Unregister image from memory profile.
+
+ @param[in] This The EDKII_MEMORY_PROFILE_PROTOCOL instance.
+ @param[in] FilePath File path of the image.
+ @param[in] ImageBase Image base address.
+ @param[in] ImageSize Image size.
+
+ @return EFI_SUCCESS Unregister successfully.
+ @return EFI_UNSUPPORTED Memory profile is unsupported,
+ or memory profile for the image is not required.
+ @return EFI_NOT_FOUND The image is not found.
+
+**/
+EFI_STATUS
+EFIAPI
+ProfileProtocolUnregisterImage (
+ IN EDKII_MEMORY_PROFILE_PROTOCOL *This,
+ IN EFI_DEVICE_PATH_PROTOCOL *FilePath,
+ IN PHYSICAL_ADDRESS ImageBase,
+ IN UINT64 ImageSize
+ );
+
+/**
+ Get memory profile recording state.
+
+ @param[in] This The EDKII_MEMORY_PROFILE_PROTOCOL instance.
+ @param[out] RecordingState Recording state.
+
+ @return EFI_SUCCESS Memory profile recording state is returned.
+ @return EFI_UNSUPPORTED Memory profile is unsupported.
+ @return EFI_INVALID_PARAMETER RecordingState is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+ProfileProtocolGetRecordingState (
+ IN EDKII_MEMORY_PROFILE_PROTOCOL *This,
+ OUT BOOLEAN *RecordingState
+ );
+
+/**
+ Set memory profile recording state.
+
+ @param[in] This The EDKII_MEMORY_PROFILE_PROTOCOL instance.
+ @param[in] RecordingState Recording state.
+
+ @return EFI_SUCCESS Set memory profile recording state successfully.
+ @return EFI_UNSUPPORTED Memory profile is unsupported.
+
+**/
+EFI_STATUS
+EFIAPI
+ProfileProtocolSetRecordingState (
+ IN EDKII_MEMORY_PROFILE_PROTOCOL *This,
+ IN BOOLEAN RecordingState
+ );
+
+/**
+ Record memory profile of multilevel caller.
+
+ @param[in] This The EDKII_MEMORY_PROFILE_PROTOCOL instance.
+ @param[in] CallerAddress Address of caller.
+ @param[in] Action Memory profile action.
+ @param[in] MemoryType Memory type.
+ EfiMaxMemoryType means the MemoryType is unknown.
+ @param[in] Buffer Buffer address.
+ @param[in] Size Buffer size.
+ @param[in] ActionString String for memory profile action.
+ Only needed for user defined allocate action.
+
+ @return EFI_SUCCESS Memory profile is updated.
+ @return EFI_UNSUPPORTED Memory profile is unsupported,
+ or memory profile for the image is not required,
+ or memory profile for the memory type is not required.
+ @return EFI_ACCESS_DENIED It is during memory profile data getting.
+ @return EFI_ABORTED Memory profile recording is not enabled.
+ @return EFI_OUT_OF_RESOURCES No enough resource to update memory profile for allocate action.
+ @return EFI_NOT_FOUND No matched allocate info found for free action.
+
+**/
+EFI_STATUS
+EFIAPI
+ProfileProtocolRecord (
+ IN EDKII_MEMORY_PROFILE_PROTOCOL *This,
+ IN PHYSICAL_ADDRESS CallerAddress,
+ IN MEMORY_PROFILE_ACTION Action,
+ IN EFI_MEMORY_TYPE MemoryType,
+ IN VOID *Buffer,
+ IN UINTN Size,
+ IN CHAR8 *ActionString OPTIONAL
+ );
+
+GLOBAL_REMOVE_IF_UNREFERENCED EDKII_MEMORY_PROFILE_PROTOCOL mProfileProtocol = {
+ ProfileProtocolGetData,
+ ProfileProtocolRegisterImage,
+ ProfileProtocolUnregisterImage,
+ ProfileProtocolGetRecordingState,
+ ProfileProtocolSetRecordingState,
+ ProfileProtocolRecord,
+};
+
+/**
+ Acquire lock on mMemoryProfileLock.
+**/
+VOID
+CoreAcquireMemoryProfileLock (
+ VOID
+ )
+{
+ CoreAcquireLock (&mMemoryProfileLock);
+}
+
+/**
+ Release lock on mMemoryProfileLock.
+**/
+VOID
+CoreReleaseMemoryProfileLock (
+ VOID
+ )
+{
+ CoreReleaseLock (&mMemoryProfileLock);
+}
+
+/**
+ Return memory profile context.
+
+ @return Memory profile context.
+
+**/
+MEMORY_PROFILE_CONTEXT_DATA *
+GetMemoryProfileContext (
+ VOID
+ )
+{
+ return mMemoryProfileContextPtr;
+}
+
+/**
+ Retrieves and returns the Subsystem of a PE/COFF image that has been loaded into system memory.
+ If Pe32Data is NULL, then ASSERT().
+
+ @param Pe32Data The pointer to the PE/COFF image that is loaded in system memory.
+
+ @return The Subsystem of the PE/COFF image.
+
+**/
+UINT16
+InternalPeCoffGetSubsystem (
+ IN VOID *Pe32Data
+ )
+{
+ EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr;
+ EFI_IMAGE_DOS_HEADER *DosHdr;
+ UINT16 Magic;
+
+ ASSERT (Pe32Data != NULL);
+
+ DosHdr = (EFI_IMAGE_DOS_HEADER *)Pe32Data;
+ if (DosHdr->e_magic == EFI_IMAGE_DOS_SIGNATURE) {
+ //
+ // DOS image header is present, so read the PE header after the DOS image header.
+ //
+ Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *)((UINTN)Pe32Data + (UINTN)((DosHdr->e_lfanew) & 0x0ffff));
+ } else {
+ //
+ // DOS image header is not present, so PE header is at the image base.
+ //
+ Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *)Pe32Data;
+ }
+
+ if (Hdr.Te->Signature == EFI_TE_IMAGE_HEADER_SIGNATURE) {
+ return Hdr.Te->Subsystem;
+ } else if (Hdr.Pe32->Signature == EFI_IMAGE_NT_SIGNATURE) {
+ Magic = Hdr.Pe32->OptionalHeader.Magic;
+ if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
+ return Hdr.Pe32->OptionalHeader.Subsystem;
+ } else if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC) {
+ return Hdr.Pe32Plus->OptionalHeader.Subsystem;
+ }
+ }
+
+ return 0x0000;
+}
+
+/**
+ Retrieves and returns a pointer to the entry point to a PE/COFF image that has been loaded
+ into system memory with the PE/COFF Loader Library functions.
+
+ Retrieves the entry point to the PE/COFF image specified by Pe32Data and returns this entry
+ point in EntryPoint. If the entry point could not be retrieved from the PE/COFF image, then
+ return RETURN_INVALID_PARAMETER. Otherwise return RETURN_SUCCESS.
+ If Pe32Data is NULL, then ASSERT().
+ If EntryPoint is NULL, then ASSERT().
+
+ @param Pe32Data The pointer to the PE/COFF image that is loaded in system memory.
+ @param EntryPoint The pointer to entry point to the PE/COFF image to return.
+
+ @retval RETURN_SUCCESS EntryPoint was returned.
+ @retval RETURN_INVALID_PARAMETER The entry point could not be found in the PE/COFF image.
+
+**/
+RETURN_STATUS
+InternalPeCoffGetEntryPoint (
+ IN VOID *Pe32Data,
+ OUT VOID **EntryPoint
+ )
+{
+ EFI_IMAGE_DOS_HEADER *DosHdr;
+ EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr;
+
+ ASSERT (Pe32Data != NULL);
+ ASSERT (EntryPoint != NULL);
+
+ DosHdr = (EFI_IMAGE_DOS_HEADER *)Pe32Data;
+ if (DosHdr->e_magic == EFI_IMAGE_DOS_SIGNATURE) {
+ //
+ // DOS image header is present, so read the PE header after the DOS image header.
+ //
+ Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *)((UINTN)Pe32Data + (UINTN)((DosHdr->e_lfanew) & 0x0ffff));
+ } else {
+ //
+ // DOS image header is not present, so PE header is at the image base.
+ //
+ Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *)Pe32Data;
+ }
+
+ //
+ // Calculate the entry point relative to the start of the image.
+ // AddressOfEntryPoint is common for PE32 & PE32+
+ //
+ if (Hdr.Te->Signature == EFI_TE_IMAGE_HEADER_SIGNATURE) {
+ *EntryPoint = (VOID *)((UINTN)Pe32Data + (UINTN)(Hdr.Te->AddressOfEntryPoint & 0x0ffffffff) + sizeof (EFI_TE_IMAGE_HEADER) - Hdr.Te->StrippedSize);
+ return RETURN_SUCCESS;
+ } else if (Hdr.Pe32->Signature == EFI_IMAGE_NT_SIGNATURE) {
+ *EntryPoint = (VOID *)((UINTN)Pe32Data + (UINTN)(Hdr.Pe32->OptionalHeader.AddressOfEntryPoint & 0x0ffffffff));
+ return RETURN_SUCCESS;
+ }
+
+ return RETURN_UNSUPPORTED;
+}
+
+/**
+ Build driver info.
+
+ @param ContextData Memory profile context.
+ @param FileName File name of the image.
+ @param ImageBase Image base address.
+ @param ImageSize Image size.
+ @param EntryPoint Entry point of the image.
+ @param ImageSubsystem Image subsystem of the image.
+ @param FileType File type of the image.
+
+ @return Pointer to memory profile driver info.
+
+**/
+MEMORY_PROFILE_DRIVER_INFO_DATA *
+BuildDriverInfo (
+ IN MEMORY_PROFILE_CONTEXT_DATA *ContextData,
+ IN EFI_GUID *FileName,
+ IN PHYSICAL_ADDRESS ImageBase,
+ IN UINT64 ImageSize,
+ IN PHYSICAL_ADDRESS EntryPoint,
+ IN UINT16 ImageSubsystem,
+ IN EFI_FV_FILETYPE FileType
+ )
+{
+ EFI_STATUS Status;
+ MEMORY_PROFILE_DRIVER_INFO *DriverInfo;
+ MEMORY_PROFILE_DRIVER_INFO_DATA *DriverInfoData;
+ VOID *EntryPointInImage;
+ CHAR8 *PdbString;
+ UINTN PdbSize;
+ UINTN PdbOccupiedSize;
+
+ PdbSize = 0;
+ PdbOccupiedSize = 0;
+ PdbString = NULL;
+ if (ImageBase != 0) {
+ PdbString = PeCoffLoaderGetPdbPointer ((VOID *)(UINTN)ImageBase);
+ if (PdbString != NULL) {
+ PdbSize = AsciiStrSize (PdbString);
+ PdbOccupiedSize = GET_OCCUPIED_SIZE (PdbSize, sizeof (UINT64));
+ }
+ }
+
+ //
+ // Use CoreInternalAllocatePool() that will not update profile for this AllocatePool action.
+ //
+ Status = CoreInternalAllocatePool (
+ EfiBootServicesData,
+ sizeof (*DriverInfoData) + sizeof (LIST_ENTRY) + PdbSize,
+ (VOID **)&DriverInfoData
+ );
+ if (EFI_ERROR (Status)) {
+ return NULL;
+ }
+
+ ASSERT (DriverInfoData != NULL);
+
+ ZeroMem (DriverInfoData, sizeof (*DriverInfoData));
+
+ DriverInfo = &DriverInfoData->DriverInfo;
+ DriverInfoData->Signature = MEMORY_PROFILE_DRIVER_INFO_SIGNATURE;
+ DriverInfo->Header.Signature = MEMORY_PROFILE_DRIVER_INFO_SIGNATURE;
+ DriverInfo->Header.Length = (UINT16)(sizeof (MEMORY_PROFILE_DRIVER_INFO) + PdbOccupiedSize);
+ DriverInfo->Header.Revision = MEMORY_PROFILE_DRIVER_INFO_REVISION;
+ if (FileName != NULL) {
+ CopyMem (&DriverInfo->FileName, FileName, sizeof (EFI_GUID));
+ }
+
+ DriverInfo->ImageBase = ImageBase;
+ DriverInfo->ImageSize = ImageSize;
+ DriverInfo->EntryPoint = EntryPoint;
+ DriverInfo->ImageSubsystem = ImageSubsystem;
+ if ((EntryPoint != 0) && ((EntryPoint < ImageBase) || (EntryPoint >= (ImageBase + ImageSize)))) {
+ //
+ // If the EntryPoint is not in the range of image buffer, it should come from emulation environment.
+ // So patch ImageBuffer here to align the EntryPoint.
+ //
+ Status = InternalPeCoffGetEntryPoint ((VOID *)(UINTN)ImageBase, &EntryPointInImage);
+ ASSERT_EFI_ERROR (Status);
+ DriverInfo->ImageBase = ImageBase + EntryPoint - (PHYSICAL_ADDRESS)(UINTN)EntryPointInImage;
+ }
+
+ DriverInfo->FileType = FileType;
+ DriverInfoData->AllocInfoList = (LIST_ENTRY *)(DriverInfoData + 1);
+ InitializeListHead (DriverInfoData->AllocInfoList);
+ DriverInfo->CurrentUsage = 0;
+ DriverInfo->PeakUsage = 0;
+ DriverInfo->AllocRecordCount = 0;
+ if (PdbSize != 0) {
+ DriverInfo->PdbStringOffset = (UINT16)sizeof (MEMORY_PROFILE_DRIVER_INFO);
+ DriverInfoData->PdbString = (CHAR8 *)(DriverInfoData->AllocInfoList + 1);
+ CopyMem (DriverInfoData->PdbString, PdbString, PdbSize);
+ } else {
+ DriverInfo->PdbStringOffset = 0;
+ DriverInfoData->PdbString = NULL;
+ }
+
+ InsertTailList (ContextData->DriverInfoList, &DriverInfoData->Link);
+ ContextData->Context.ImageCount++;
+ ContextData->Context.TotalImageSize += DriverInfo->ImageSize;
+
+ return DriverInfoData;
+}
+
+/**
+ Return if record for this driver is needed..
+
+ @param DriverFilePath Driver file path.
+
+ @retval TRUE Record for this driver is needed.
+ @retval FALSE Record for this driver is not needed.
+
+**/
+BOOLEAN
+NeedRecordThisDriver (
+ IN EFI_DEVICE_PATH_PROTOCOL *DriverFilePath
+ )
+{
+ EFI_DEVICE_PATH_PROTOCOL *TmpDevicePath;
+ EFI_DEVICE_PATH_PROTOCOL *DevicePathInstance;
+ UINTN DevicePathSize;
+ UINTN FilePathSize;
+
+ if (!IsDevicePathValid (mMemoryProfileDriverPath, mMemoryProfileDriverPathSize)) {
+ //
+ // Invalid Device Path means record all.
+ //
+ return TRUE;
+ }
+
+ //
+ // Record FilePath without END node.
+ //
+ FilePathSize = GetDevicePathSize (DriverFilePath) - sizeof (EFI_DEVICE_PATH_PROTOCOL);
+
+ DevicePathInstance = mMemoryProfileDriverPath;
+ do {
+ //
+ // Find END node (it might be END_ENTIRE or END_INSTANCE).
+ //
+ TmpDevicePath = DevicePathInstance;
+ while (!IsDevicePathEndType (TmpDevicePath)) {
+ TmpDevicePath = NextDevicePathNode (TmpDevicePath);
+ }
+
+ //
+ // Do not compare END node.
+ //
+ DevicePathSize = (UINTN)TmpDevicePath - (UINTN)DevicePathInstance;
+ if ((FilePathSize == DevicePathSize) &&
+ (CompareMem (DriverFilePath, DevicePathInstance, DevicePathSize) == 0))
+ {
+ return TRUE;
+ }
+
+ //
+ // Get next instance.
+ //
+ DevicePathInstance = (EFI_DEVICE_PATH_PROTOCOL *)((UINTN)DevicePathInstance + DevicePathSize + DevicePathNodeLength (TmpDevicePath));
+ } while (DevicePathSubType (TmpDevicePath) != END_ENTIRE_DEVICE_PATH_SUBTYPE);
+
+ return FALSE;
+}
+
+/**
+ Register DXE Core to memory profile.
+
+ @param HobStart The start address of the HOB.
+ @param ContextData Memory profile context.
+
+ @retval TRUE Register success.
+ @retval FALSE Register fail.
+
+**/
+BOOLEAN
+RegisterDxeCore (
+ IN VOID *HobStart,
+ IN MEMORY_PROFILE_CONTEXT_DATA *ContextData
+ )
+{
+ EFI_PEI_HOB_POINTERS DxeCoreHob;
+ MEMORY_PROFILE_DRIVER_INFO_DATA *DriverInfoData;
+ PHYSICAL_ADDRESS ImageBase;
+ UINT8 TempBuffer[sizeof (MEDIA_FW_VOL_FILEPATH_DEVICE_PATH) + sizeof (EFI_DEVICE_PATH_PROTOCOL)];
+ MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *FilePath;
+
+ ASSERT (ContextData != NULL);
+
+ //
+ // Searching for image hob
+ //
+ DxeCoreHob.Raw = HobStart;
+ while ((DxeCoreHob.Raw = GetNextHob (EFI_HOB_TYPE_MEMORY_ALLOCATION, DxeCoreHob.Raw)) != NULL) {
+ if (CompareGuid (&DxeCoreHob.MemoryAllocationModule->MemoryAllocationHeader.Name, &gEfiHobMemoryAllocModuleGuid)) {
+ //
+ // Find Dxe Core HOB
+ //
+ break;
+ }
+
+ DxeCoreHob.Raw = GET_NEXT_HOB (DxeCoreHob);
+ }
+
+ ASSERT (DxeCoreHob.Raw != NULL);
+
+ FilePath = (MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *)TempBuffer;
+ EfiInitializeFwVolDevicepathNode (FilePath, &DxeCoreHob.MemoryAllocationModule->ModuleName);
+ SetDevicePathEndNode (FilePath + 1);
+
+ if (!NeedRecordThisDriver ((EFI_DEVICE_PATH_PROTOCOL *)FilePath)) {
+ return FALSE;
+ }
+
+ ImageBase = DxeCoreHob.MemoryAllocationModule->MemoryAllocationHeader.MemoryBaseAddress;
+ DriverInfoData = BuildDriverInfo (
+ ContextData,
+ &DxeCoreHob.MemoryAllocationModule->ModuleName,
+ ImageBase,
+ DxeCoreHob.MemoryAllocationModule->MemoryAllocationHeader.MemoryLength,
+ DxeCoreHob.MemoryAllocationModule->EntryPoint,
+ InternalPeCoffGetSubsystem ((VOID *)(UINTN)ImageBase),
+ EFI_FV_FILETYPE_DXE_CORE
+ );
+ if (DriverInfoData == NULL) {
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+/**
+ Initialize memory profile.
+
+ @param HobStart The start address of the HOB.
+
+**/
+VOID
+MemoryProfileInit (
+ IN VOID *HobStart
+ )
+{
+ MEMORY_PROFILE_CONTEXT_DATA *ContextData;
+
+ if (!IS_UEFI_MEMORY_PROFILE_ENABLED) {
+ return;
+ }
+
+ ContextData = GetMemoryProfileContext ();
+ if (ContextData != NULL) {
+ return;
+ }
+
+ mMemoryProfileGettingStatus = FALSE;
+ if ((PcdGet8 (PcdMemoryProfilePropertyMask) & BIT7) != 0) {
+ mMemoryProfileRecordingEnable = MEMORY_PROFILE_RECORDING_DISABLE;
+ } else {
+ mMemoryProfileRecordingEnable = MEMORY_PROFILE_RECORDING_ENABLE;
+ }
+
+ mMemoryProfileDriverPathSize = PcdGetSize (PcdMemoryProfileDriverPath);
+ mMemoryProfileDriverPath = AllocateCopyPool (mMemoryProfileDriverPathSize, PcdGetPtr (PcdMemoryProfileDriverPath));
+ mMemoryProfileContextPtr = &mMemoryProfileContext;
+
+ RegisterDxeCore (HobStart, &mMemoryProfileContext);
+
+ DEBUG ((DEBUG_INFO, "MemoryProfileInit MemoryProfileContext - 0x%x\n", &mMemoryProfileContext));
+}
+
+/**
+ Install memory profile protocol.
+
+**/
+VOID
+MemoryProfileInstallProtocol (
+ VOID
+ )
+{
+ EFI_HANDLE Handle;
+ EFI_STATUS Status;
+
+ if (!IS_UEFI_MEMORY_PROFILE_ENABLED) {
+ return;
+ }
+
+ Handle = NULL;
+ Status = CoreInstallMultipleProtocolInterfaces (
+ &Handle,
+ &gEdkiiMemoryProfileGuid,
+ &mProfileProtocol,
+ NULL
+ );
+ ASSERT_EFI_ERROR (Status);
+}
+
+/**
+ Get the GUID file name from the file path.
+
+ @param FilePath File path.
+
+ @return The GUID file name from the file path.
+
+**/
+EFI_GUID *
+GetFileNameFromFilePath (
+ IN EFI_DEVICE_PATH_PROTOCOL *FilePath
+ )
+{
+ MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *ThisFilePath;
+ EFI_GUID *FileName;
+
+ FileName = NULL;
+ if (FilePath != NULL) {
+ ThisFilePath = (MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *)FilePath;
+ while (!IsDevicePathEnd (ThisFilePath)) {
+ FileName = EfiGetNameGuidFromFwVolDevicePathNode (ThisFilePath);
+ if (FileName != NULL) {
+ break;
+ }
+
+ ThisFilePath = (MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *)NextDevicePathNode (ThisFilePath);
+ }
+ }
+
+ return FileName;
+}
+
+/**
+ Register image to memory profile.
+
+ @param DriverEntry Image info.
+ @param FileType Image file type.
+
+ @return EFI_SUCCESS Register successfully.
+ @return EFI_UNSUPPORTED Memory profile is unsupported,
+ or memory profile for the image is not required.
+ @return EFI_OUT_OF_RESOURCES No enough resource for this register.
+
+**/
+EFI_STATUS
+RegisterMemoryProfileImage (
+ IN LOADED_IMAGE_PRIVATE_DATA *DriverEntry,
+ IN EFI_FV_FILETYPE FileType
+ )
+{
+ MEMORY_PROFILE_CONTEXT_DATA *ContextData;
+ MEMORY_PROFILE_DRIVER_INFO_DATA *DriverInfoData;
+
+ if (!IS_UEFI_MEMORY_PROFILE_ENABLED) {
+ return EFI_UNSUPPORTED;
+ }
+
+ if (!NeedRecordThisDriver (DriverEntry->Info.FilePath)) {
+ return EFI_UNSUPPORTED;
+ }
+
+ ContextData = GetMemoryProfileContext ();
+ if (ContextData == NULL) {
+ return EFI_UNSUPPORTED;
+ }
+
+ DriverInfoData = BuildDriverInfo (
+ ContextData,
+ GetFileNameFromFilePath (DriverEntry->Info.FilePath),
+ DriverEntry->ImageContext.ImageAddress,
+ DriverEntry->ImageContext.ImageSize,
+ DriverEntry->ImageContext.EntryPoint,
+ DriverEntry->ImageContext.ImageType,
+ FileType
+ );
+ if (DriverInfoData == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Search image from memory profile.
+
+ @param ContextData Memory profile context.
+ @param FileName Image file name.
+ @param Address Image Address.
+
+ @return Pointer to memory profile driver info.
+
+**/
+MEMORY_PROFILE_DRIVER_INFO_DATA *
+GetMemoryProfileDriverInfoByFileNameAndAddress (
+ IN MEMORY_PROFILE_CONTEXT_DATA *ContextData,
+ IN EFI_GUID *FileName,
+ IN PHYSICAL_ADDRESS Address
+ )
+{
+ MEMORY_PROFILE_DRIVER_INFO *DriverInfo;
+ MEMORY_PROFILE_DRIVER_INFO_DATA *DriverInfoData;
+ LIST_ENTRY *DriverLink;
+ LIST_ENTRY *DriverInfoList;
+
+ DriverInfoList = ContextData->DriverInfoList;
+
+ for (DriverLink = DriverInfoList->ForwardLink;
+ DriverLink != DriverInfoList;
+ DriverLink = DriverLink->ForwardLink)
+ {
+ DriverInfoData = CR (
+ DriverLink,
+ MEMORY_PROFILE_DRIVER_INFO_DATA,
+ Link,
+ MEMORY_PROFILE_DRIVER_INFO_SIGNATURE
+ );
+ DriverInfo = &DriverInfoData->DriverInfo;
+ if ((CompareGuid (&DriverInfo->FileName, FileName)) &&
+ (Address >= DriverInfo->ImageBase) &&
+ (Address < (DriverInfo->ImageBase + DriverInfo->ImageSize)))
+ {
+ return DriverInfoData;
+ }
+ }
+
+ return NULL;
+}
+
+/**
+ Search image from memory profile.
+ It will return image, if (Address >= ImageBuffer) AND (Address < ImageBuffer + ImageSize).
+
+ @param ContextData Memory profile context.
+ @param Address Image or Function address.
+
+ @return Pointer to memory profile driver info.
+
+**/
+MEMORY_PROFILE_DRIVER_INFO_DATA *
+GetMemoryProfileDriverInfoFromAddress (
+ IN MEMORY_PROFILE_CONTEXT_DATA *ContextData,
+ IN PHYSICAL_ADDRESS Address
+ )
+{
+ MEMORY_PROFILE_DRIVER_INFO *DriverInfo;
+ MEMORY_PROFILE_DRIVER_INFO_DATA *DriverInfoData;
+ LIST_ENTRY *DriverLink;
+ LIST_ENTRY *DriverInfoList;
+
+ DriverInfoList = ContextData->DriverInfoList;
+
+ for (DriverLink = DriverInfoList->ForwardLink;
+ DriverLink != DriverInfoList;
+ DriverLink = DriverLink->ForwardLink)
+ {
+ DriverInfoData = CR (
+ DriverLink,
+ MEMORY_PROFILE_DRIVER_INFO_DATA,
+ Link,
+ MEMORY_PROFILE_DRIVER_INFO_SIGNATURE
+ );
+ DriverInfo = &DriverInfoData->DriverInfo;
+ if ((Address >= DriverInfo->ImageBase) &&
+ (Address < (DriverInfo->ImageBase + DriverInfo->ImageSize)))
+ {
+ return DriverInfoData;
+ }
+ }
+
+ return NULL;
+}
+
+/**
+ Unregister image from memory profile.
+
+ @param DriverEntry Image info.
+
+ @return EFI_SUCCESS Unregister successfully.
+ @return EFI_UNSUPPORTED Memory profile is unsupported,
+ or memory profile for the image is not required.
+ @return EFI_NOT_FOUND The image is not found.
+
+**/
+EFI_STATUS
+UnregisterMemoryProfileImage (
+ IN LOADED_IMAGE_PRIVATE_DATA *DriverEntry
+ )
+{
+ EFI_STATUS Status;
+ MEMORY_PROFILE_CONTEXT_DATA *ContextData;
+ MEMORY_PROFILE_DRIVER_INFO_DATA *DriverInfoData;
+ EFI_GUID *FileName;
+ PHYSICAL_ADDRESS ImageAddress;
+ VOID *EntryPointInImage;
+
+ if (!IS_UEFI_MEMORY_PROFILE_ENABLED) {
+ return EFI_UNSUPPORTED;
+ }
+
+ if (!NeedRecordThisDriver (DriverEntry->Info.FilePath)) {
+ return EFI_UNSUPPORTED;
+ }
+
+ ContextData = GetMemoryProfileContext ();
+ if (ContextData == NULL) {
+ return EFI_UNSUPPORTED;
+ }
+
+ DriverInfoData = NULL;
+ FileName = GetFileNameFromFilePath (DriverEntry->Info.FilePath);
+ ImageAddress = DriverEntry->ImageContext.ImageAddress;
+ if ((DriverEntry->ImageContext.EntryPoint < ImageAddress) || (DriverEntry->ImageContext.EntryPoint >= (ImageAddress + DriverEntry->ImageContext.ImageSize))) {
+ //
+ // If the EntryPoint is not in the range of image buffer, it should come from emulation environment.
+ // So patch ImageAddress here to align the EntryPoint.
+ //
+ Status = InternalPeCoffGetEntryPoint ((VOID *)(UINTN)ImageAddress, &EntryPointInImage);
+ ASSERT_EFI_ERROR (Status);
+ ImageAddress = ImageAddress + (UINTN)DriverEntry->ImageContext.EntryPoint - (UINTN)EntryPointInImage;
+ }
+
+ if (FileName != NULL) {
+ DriverInfoData = GetMemoryProfileDriverInfoByFileNameAndAddress (ContextData, FileName, ImageAddress);
+ }
+
+ if (DriverInfoData == NULL) {
+ DriverInfoData = GetMemoryProfileDriverInfoFromAddress (ContextData, ImageAddress);
+ }
+
+ if (DriverInfoData == NULL) {
+ return EFI_NOT_FOUND;
+ }
+
+ ContextData->Context.TotalImageSize -= DriverInfoData->DriverInfo.ImageSize;
+
+ // Keep the ImageBase for RVA calculation in Application.
+ // DriverInfoData->DriverInfo.ImageBase = 0;
+ DriverInfoData->DriverInfo.ImageSize = 0;
+
+ if (DriverInfoData->DriverInfo.PeakUsage == 0) {
+ ContextData->Context.ImageCount--;
+ RemoveEntryList (&DriverInfoData->Link);
+ //
+ // Use CoreInternalFreePool() that will not update profile for this FreePool action.
+ //
+ CoreInternalFreePool (DriverInfoData, NULL);
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Return if this memory type needs to be recorded into memory profile.
+ If BIOS memory type (0 ~ EfiMaxMemoryType - 1), it checks bit (1 << MemoryType).
+ If OS memory type (0x80000000 ~ 0xFFFFFFFF), it checks bit63 - 0x8000000000000000.
+ If OEM memory type (0x70000000 ~ 0x7FFFFFFF), it checks bit62 - 0x4000000000000000.
+
+ @param MemoryType Memory type.
+
+ @retval TRUE This memory type need to be recorded.
+ @retval FALSE This memory type need not to be recorded.
+
+**/
+BOOLEAN
+CoreNeedRecordProfile (
+ IN EFI_MEMORY_TYPE MemoryType
+ )
+{
+ UINT64 TestBit;
+
+ if ((UINT32)MemoryType >= MEMORY_TYPE_OS_RESERVED_MIN) {
+ TestBit = BIT63;
+ } else if ((UINT32)MemoryType >= MEMORY_TYPE_OEM_RESERVED_MIN) {
+ TestBit = BIT62;
+ } else {
+ TestBit = LShiftU64 (1, MemoryType);
+ }
+
+ if ((PcdGet64 (PcdMemoryProfileMemoryType) & TestBit) != 0) {
+ return TRUE;
+ } else {
+ return FALSE;
+ }
+}
+
+/**
+ Convert EFI memory type to profile memory index. The rule is:
+ If BIOS memory type (0 ~ EfiMaxMemoryType - 1), ProfileMemoryIndex = MemoryType.
+ If OS memory type (0x80000000 ~ 0xFFFFFFFF), ProfileMemoryIndex = EfiMaxMemoryType.
+ If OEM memory type (0x70000000 ~ 0x7FFFFFFF), ProfileMemoryIndex = EfiMaxMemoryType + 1.
+
+ @param MemoryType Memory type.
+
+ @return Profile memory index.
+
+**/
+UINTN
+GetProfileMemoryIndex (
+ IN EFI_MEMORY_TYPE MemoryType
+ )
+{
+ if ((UINT32)MemoryType >= MEMORY_TYPE_OS_RESERVED_MIN) {
+ return EfiMaxMemoryType;
+ } else if ((UINT32)MemoryType >= MEMORY_TYPE_OEM_RESERVED_MIN) {
+ return EfiMaxMemoryType + 1;
+ } else {
+ return MemoryType;
+ }
+}
+
+/**
+ Update memory profile Allocate information.
+
+ @param CallerAddress Address of caller who call Allocate.
+ @param Action This Allocate action.
+ @param MemoryType Memory type.
+ @param Size Buffer size.
+ @param Buffer Buffer address.
+ @param ActionString String for memory profile action.
+
+ @return EFI_SUCCESS Memory profile is updated.
+ @return EFI_UNSUPPORTED Memory profile is unsupported,
+ or memory profile for the image is not required.
+ @return EFI_OUT_OF_RESOURCES No enough resource to update memory profile for allocate action.
+
+**/
+EFI_STATUS
+CoreUpdateProfileAllocate (
+ IN PHYSICAL_ADDRESS CallerAddress,
+ IN MEMORY_PROFILE_ACTION Action,
+ IN EFI_MEMORY_TYPE MemoryType,
+ IN UINTN Size,
+ IN VOID *Buffer,
+ IN CHAR8 *ActionString OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+ MEMORY_PROFILE_CONTEXT *Context;
+ MEMORY_PROFILE_DRIVER_INFO *DriverInfo;
+ MEMORY_PROFILE_ALLOC_INFO *AllocInfo;
+ MEMORY_PROFILE_CONTEXT_DATA *ContextData;
+ MEMORY_PROFILE_DRIVER_INFO_DATA *DriverInfoData;
+ MEMORY_PROFILE_ALLOC_INFO_DATA *AllocInfoData;
+ UINTN ProfileMemoryIndex;
+ MEMORY_PROFILE_ACTION BasicAction;
+ UINTN ActionStringSize;
+ UINTN ActionStringOccupiedSize;
+
+ BasicAction = Action & MEMORY_PROFILE_ACTION_BASIC_MASK;
+
+ ContextData = GetMemoryProfileContext ();
+ if (ContextData == NULL) {
+ return EFI_UNSUPPORTED;
+ }
+
+ DriverInfoData = GetMemoryProfileDriverInfoFromAddress (ContextData, CallerAddress);
+ if (DriverInfoData == NULL) {
+ return EFI_UNSUPPORTED;
+ }
+
+ ActionStringSize = 0;
+ ActionStringOccupiedSize = 0;
+ if (ActionString != NULL) {
+ ActionStringSize = AsciiStrSize (ActionString);
+ ActionStringOccupiedSize = GET_OCCUPIED_SIZE (ActionStringSize, sizeof (UINT64));
+ }
+
+ //
+ // Use CoreInternalAllocatePool() that will not update profile for this AllocatePool action.
+ //
+ AllocInfoData = NULL;
+ Status = CoreInternalAllocatePool (
+ EfiBootServicesData,
+ sizeof (*AllocInfoData) + ActionStringSize,
+ (VOID **)&AllocInfoData
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ ASSERT (AllocInfoData != NULL);
+
+ //
+ // Only update SequenceCount if and only if it is basic action.
+ //
+ if (Action == BasicAction) {
+ ContextData->Context.SequenceCount++;
+ }
+
+ AllocInfo = &AllocInfoData->AllocInfo;
+ AllocInfoData->Signature = MEMORY_PROFILE_ALLOC_INFO_SIGNATURE;
+ AllocInfo->Header.Signature = MEMORY_PROFILE_ALLOC_INFO_SIGNATURE;
+ AllocInfo->Header.Length = (UINT16)(sizeof (MEMORY_PROFILE_ALLOC_INFO) + ActionStringOccupiedSize);
+ AllocInfo->Header.Revision = MEMORY_PROFILE_ALLOC_INFO_REVISION;
+ AllocInfo->CallerAddress = CallerAddress;
+ AllocInfo->SequenceId = ContextData->Context.SequenceCount;
+ AllocInfo->Action = Action;
+ AllocInfo->MemoryType = MemoryType;
+ AllocInfo->Buffer = (PHYSICAL_ADDRESS)(UINTN)Buffer;
+ AllocInfo->Size = Size;
+ if (ActionString != NULL) {
+ AllocInfo->ActionStringOffset = (UINT16)sizeof (MEMORY_PROFILE_ALLOC_INFO);
+ AllocInfoData->ActionString = (CHAR8 *)(AllocInfoData + 1);
+ CopyMem (AllocInfoData->ActionString, ActionString, ActionStringSize);
+ } else {
+ AllocInfo->ActionStringOffset = 0;
+ AllocInfoData->ActionString = NULL;
+ }
+
+ InsertTailList (DriverInfoData->AllocInfoList, &AllocInfoData->Link);
+
+ Context = &ContextData->Context;
+ DriverInfo = &DriverInfoData->DriverInfo;
+ DriverInfo->AllocRecordCount++;
+
+ //
+ // Update summary if and only if it is basic action.
+ //
+ if (Action == BasicAction) {
+ ProfileMemoryIndex = GetProfileMemoryIndex (MemoryType);
+
+ DriverInfo->CurrentUsage += Size;
+ if (DriverInfo->PeakUsage < DriverInfo->CurrentUsage) {
+ DriverInfo->PeakUsage = DriverInfo->CurrentUsage;
+ }
+
+ DriverInfo->CurrentUsageByType[ProfileMemoryIndex] += Size;
+ if (DriverInfo->PeakUsageByType[ProfileMemoryIndex] < DriverInfo->CurrentUsageByType[ProfileMemoryIndex]) {
+ DriverInfo->PeakUsageByType[ProfileMemoryIndex] = DriverInfo->CurrentUsageByType[ProfileMemoryIndex];
+ }
+
+ Context->CurrentTotalUsage += Size;
+ if (Context->PeakTotalUsage < Context->CurrentTotalUsage) {
+ Context->PeakTotalUsage = Context->CurrentTotalUsage;
+ }
+
+ Context->CurrentTotalUsageByType[ProfileMemoryIndex] += Size;
+ if (Context->PeakTotalUsageByType[ProfileMemoryIndex] < Context->CurrentTotalUsageByType[ProfileMemoryIndex]) {
+ Context->PeakTotalUsageByType[ProfileMemoryIndex] = Context->CurrentTotalUsageByType[ProfileMemoryIndex];
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Get memory profile alloc info from memory profile.
+
+ @param DriverInfoData Driver info.
+ @param BasicAction This Free basic action.
+ @param Size Buffer size.
+ @param Buffer Buffer address.
+
+ @return Pointer to memory profile alloc info.
+
+**/
+MEMORY_PROFILE_ALLOC_INFO_DATA *
+GetMemoryProfileAllocInfoFromAddress (
+ IN MEMORY_PROFILE_DRIVER_INFO_DATA *DriverInfoData,
+ IN MEMORY_PROFILE_ACTION BasicAction,
+ IN UINTN Size,
+ IN VOID *Buffer
+ )
+{
+ LIST_ENTRY *AllocInfoList;
+ LIST_ENTRY *AllocLink;
+ MEMORY_PROFILE_ALLOC_INFO *AllocInfo;
+ MEMORY_PROFILE_ALLOC_INFO_DATA *AllocInfoData;
+
+ AllocInfoList = DriverInfoData->AllocInfoList;
+
+ for (AllocLink = AllocInfoList->ForwardLink;
+ AllocLink != AllocInfoList;
+ AllocLink = AllocLink->ForwardLink)
+ {
+ AllocInfoData = CR (
+ AllocLink,
+ MEMORY_PROFILE_ALLOC_INFO_DATA,
+ Link,
+ MEMORY_PROFILE_ALLOC_INFO_SIGNATURE
+ );
+ AllocInfo = &AllocInfoData->AllocInfo;
+ if ((AllocInfo->Action & MEMORY_PROFILE_ACTION_BASIC_MASK) != BasicAction) {
+ continue;
+ }
+
+ switch (BasicAction) {
+ case MemoryProfileActionAllocatePages:
+ if ((AllocInfo->Buffer <= (PHYSICAL_ADDRESS)(UINTN)Buffer) &&
+ ((AllocInfo->Buffer + AllocInfo->Size) >= ((PHYSICAL_ADDRESS)(UINTN)Buffer + Size)))
+ {
+ return AllocInfoData;
+ }
+
+ break;
+ case MemoryProfileActionAllocatePool:
+ if (AllocInfo->Buffer == (PHYSICAL_ADDRESS)(UINTN)Buffer) {
+ return AllocInfoData;
+ }
+
+ break;
+ default:
+ ASSERT (FALSE);
+ break;
+ }
+ }
+
+ return NULL;
+}
+
+/**
+ Update memory profile Free information.
+
+ @param CallerAddress Address of caller who call Free.
+ @param Action This Free action.
+ @param Size Buffer size.
+ @param Buffer Buffer address.
+
+ @return EFI_SUCCESS Memory profile is updated.
+ @return EFI_UNSUPPORTED Memory profile is unsupported.
+ @return EFI_NOT_FOUND No matched allocate info found for free action.
+
+**/
+EFI_STATUS
+CoreUpdateProfileFree (
+ IN PHYSICAL_ADDRESS CallerAddress,
+ IN MEMORY_PROFILE_ACTION Action,
+ IN UINTN Size,
+ IN VOID *Buffer
+ )
+{
+ MEMORY_PROFILE_CONTEXT *Context;
+ MEMORY_PROFILE_DRIVER_INFO *DriverInfo;
+ MEMORY_PROFILE_ALLOC_INFO *AllocInfo;
+ MEMORY_PROFILE_CONTEXT_DATA *ContextData;
+ MEMORY_PROFILE_DRIVER_INFO_DATA *DriverInfoData;
+ LIST_ENTRY *DriverLink;
+ LIST_ENTRY *DriverInfoList;
+ MEMORY_PROFILE_DRIVER_INFO_DATA *ThisDriverInfoData;
+ MEMORY_PROFILE_ALLOC_INFO_DATA *AllocInfoData;
+ UINTN ProfileMemoryIndex;
+ MEMORY_PROFILE_ACTION BasicAction;
+ BOOLEAN Found;
+
+ BasicAction = Action & MEMORY_PROFILE_ACTION_BASIC_MASK;
+
+ ContextData = GetMemoryProfileContext ();
+ if (ContextData == NULL) {
+ return EFI_UNSUPPORTED;
+ }
+
+ DriverInfoData = GetMemoryProfileDriverInfoFromAddress (ContextData, CallerAddress);
+
+ //
+ // Do not return if DriverInfoData == NULL here,
+ // because driver A might free memory allocated by driver B.
+ //
+
+ //
+ // Need use do-while loop to find all possible records,
+ // because one address might be recorded multiple times.
+ //
+ Found = FALSE;
+ AllocInfoData = NULL;
+ do {
+ if (DriverInfoData != NULL) {
+ switch (BasicAction) {
+ case MemoryProfileActionFreePages:
+ AllocInfoData = GetMemoryProfileAllocInfoFromAddress (DriverInfoData, MemoryProfileActionAllocatePages, Size, Buffer);
+ break;
+ case MemoryProfileActionFreePool:
+ AllocInfoData = GetMemoryProfileAllocInfoFromAddress (DriverInfoData, MemoryProfileActionAllocatePool, 0, Buffer);
+ break;
+ default:
+ ASSERT (FALSE);
+ AllocInfoData = NULL;
+ break;
+ }
+ }
+
+ if (AllocInfoData == NULL) {
+ //
+ // Legal case, because driver A might free memory allocated by driver B, by some protocol.
+ //
+ DriverInfoList = ContextData->DriverInfoList;
+
+ for (DriverLink = DriverInfoList->ForwardLink;
+ DriverLink != DriverInfoList;
+ DriverLink = DriverLink->ForwardLink)
+ {
+ ThisDriverInfoData = CR (
+ DriverLink,
+ MEMORY_PROFILE_DRIVER_INFO_DATA,
+ Link,
+ MEMORY_PROFILE_DRIVER_INFO_SIGNATURE
+ );
+ switch (BasicAction) {
+ case MemoryProfileActionFreePages:
+ AllocInfoData = GetMemoryProfileAllocInfoFromAddress (ThisDriverInfoData, MemoryProfileActionAllocatePages, Size, Buffer);
+ break;
+ case MemoryProfileActionFreePool:
+ AllocInfoData = GetMemoryProfileAllocInfoFromAddress (ThisDriverInfoData, MemoryProfileActionAllocatePool, 0, Buffer);
+ break;
+ default:
+ ASSERT (FALSE);
+ AllocInfoData = NULL;
+ break;
+ }
+
+ if (AllocInfoData != NULL) {
+ DriverInfoData = ThisDriverInfoData;
+ break;
+ }
+ }
+
+ if (AllocInfoData == NULL) {
+ //
+ // If (!Found), no matched allocate info is found for this free action.
+ // It is because the specified memory type allocate actions have been filtered by
+ // CoreNeedRecordProfile(), but free actions may have no memory type information,
+ // they can not be filtered by CoreNeedRecordProfile(). Then, they will be
+ // filtered here.
+ //
+ // If (Found), it is normal exit path.
+ return (Found ? EFI_SUCCESS : EFI_NOT_FOUND);
+ }
+ }
+
+ ASSERT (DriverInfoData != NULL);
+ ASSERT (AllocInfoData != NULL);
+
+ Found = TRUE;
+
+ Context = &ContextData->Context;
+ DriverInfo = &DriverInfoData->DriverInfo;
+ AllocInfo = &AllocInfoData->AllocInfo;
+
+ DriverInfo->AllocRecordCount--;
+ //
+ // Update summary if and only if it is basic action.
+ //
+ if (AllocInfo->Action == (AllocInfo->Action & MEMORY_PROFILE_ACTION_BASIC_MASK)) {
+ ProfileMemoryIndex = GetProfileMemoryIndex (AllocInfo->MemoryType);
+
+ Context->CurrentTotalUsage -= AllocInfo->Size;
+ Context->CurrentTotalUsageByType[ProfileMemoryIndex] -= AllocInfo->Size;
+
+ DriverInfo->CurrentUsage -= AllocInfo->Size;
+ DriverInfo->CurrentUsageByType[ProfileMemoryIndex] -= AllocInfo->Size;
+ }
+
+ RemoveEntryList (&AllocInfoData->Link);
+
+ if (BasicAction == MemoryProfileActionFreePages) {
+ if (AllocInfo->Buffer != (PHYSICAL_ADDRESS)(UINTN)Buffer) {
+ CoreUpdateProfileAllocate (
+ AllocInfo->CallerAddress,
+ AllocInfo->Action,
+ AllocInfo->MemoryType,
+ (UINTN)((PHYSICAL_ADDRESS)(UINTN)Buffer - AllocInfo->Buffer),
+ (VOID *)(UINTN)AllocInfo->Buffer,
+ AllocInfoData->ActionString
+ );
+ }
+
+ if (AllocInfo->Buffer + AllocInfo->Size != ((PHYSICAL_ADDRESS)(UINTN)Buffer + Size)) {
+ CoreUpdateProfileAllocate (
+ AllocInfo->CallerAddress,
+ AllocInfo->Action,
+ AllocInfo->MemoryType,
+ (UINTN)((AllocInfo->Buffer + AllocInfo->Size) - ((PHYSICAL_ADDRESS)(UINTN)Buffer + Size)),
+ (VOID *)((UINTN)Buffer + Size),
+ AllocInfoData->ActionString
+ );
+ }
+ }
+
+ //
+ // Use CoreInternalFreePool() that will not update profile for this FreePool action.
+ //
+ CoreInternalFreePool (AllocInfoData, NULL);
+ } while (TRUE);
+}
+
+/**
+ Update memory profile information.
+
+ @param CallerAddress Address of caller who call Allocate or Free.
+ @param Action This Allocate or Free action.
+ @param MemoryType Memory type.
+ EfiMaxMemoryType means the MemoryType is unknown.
+ @param Size Buffer size.
+ @param Buffer Buffer address.
+ @param ActionString String for memory profile action.
+ Only needed for user defined allocate action.
+
+ @return EFI_SUCCESS Memory profile is updated.
+ @return EFI_UNSUPPORTED Memory profile is unsupported,
+ or memory profile for the image is not required,
+ or memory profile for the memory type is not required.
+ @return EFI_ACCESS_DENIED It is during memory profile data getting.
+ @return EFI_ABORTED Memory profile recording is not enabled.
+ @return EFI_OUT_OF_RESOURCES No enough resource to update memory profile for allocate action.
+ @return EFI_NOT_FOUND No matched allocate info found for free action.
+
+**/
+EFI_STATUS
+EFIAPI
+CoreUpdateProfile (
+ IN PHYSICAL_ADDRESS CallerAddress,
+ IN MEMORY_PROFILE_ACTION Action,
+ IN EFI_MEMORY_TYPE MemoryType,
+ IN UINTN Size, // Valid for AllocatePages/FreePages/AllocatePool
+ IN VOID *Buffer,
+ IN CHAR8 *ActionString OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+ MEMORY_PROFILE_CONTEXT_DATA *ContextData;
+ MEMORY_PROFILE_ACTION BasicAction;
+
+ if (!IS_UEFI_MEMORY_PROFILE_ENABLED) {
+ return EFI_UNSUPPORTED;
+ }
+
+ if (mMemoryProfileGettingStatus) {
+ return EFI_ACCESS_DENIED;
+ }
+
+ if (!mMemoryProfileRecordingEnable) {
+ return EFI_ABORTED;
+ }
+
+ //
+ // Get the basic action to know how to process the record
+ //
+ BasicAction = Action & MEMORY_PROFILE_ACTION_BASIC_MASK;
+
+ //
+ // EfiMaxMemoryType means the MemoryType is unknown.
+ //
+ if (MemoryType != EfiMaxMemoryType) {
+ //
+ // Only record limited MemoryType.
+ //
+ if (!CoreNeedRecordProfile (MemoryType)) {
+ return EFI_UNSUPPORTED;
+ }
+ }
+
+ ContextData = GetMemoryProfileContext ();
+ if (ContextData == NULL) {
+ return EFI_UNSUPPORTED;
+ }
+
+ CoreAcquireMemoryProfileLock ();
+ switch (BasicAction) {
+ case MemoryProfileActionAllocatePages:
+ Status = CoreUpdateProfileAllocate (CallerAddress, Action, MemoryType, Size, Buffer, ActionString);
+ break;
+ case MemoryProfileActionFreePages:
+ Status = CoreUpdateProfileFree (CallerAddress, Action, Size, Buffer);
+ break;
+ case MemoryProfileActionAllocatePool:
+ Status = CoreUpdateProfileAllocate (CallerAddress, Action, MemoryType, Size, Buffer, ActionString);
+ break;
+ case MemoryProfileActionFreePool:
+ Status = CoreUpdateProfileFree (CallerAddress, Action, 0, Buffer);
+ break;
+ default:
+ ASSERT (FALSE);
+ Status = EFI_UNSUPPORTED;
+ break;
+ }
+
+ CoreReleaseMemoryProfileLock ();
+
+ return Status;
+}
+
+////////////////////
+
+/**
+ Get memory profile data size.
+
+ @return Memory profile data size.
+
+**/
+UINTN
+MemoryProfileGetDataSize (
+ VOID
+ )
+{
+ MEMORY_PROFILE_CONTEXT_DATA *ContextData;
+ MEMORY_PROFILE_DRIVER_INFO_DATA *DriverInfoData;
+ MEMORY_PROFILE_ALLOC_INFO_DATA *AllocInfoData;
+ LIST_ENTRY *DriverInfoList;
+ LIST_ENTRY *DriverLink;
+ LIST_ENTRY *AllocInfoList;
+ LIST_ENTRY *AllocLink;
+ UINTN TotalSize;
+
+ ContextData = GetMemoryProfileContext ();
+ if (ContextData == NULL) {
+ return 0;
+ }
+
+ TotalSize = sizeof (MEMORY_PROFILE_CONTEXT);
+
+ DriverInfoList = ContextData->DriverInfoList;
+ for (DriverLink = DriverInfoList->ForwardLink;
+ DriverLink != DriverInfoList;
+ DriverLink = DriverLink->ForwardLink)
+ {
+ DriverInfoData = CR (
+ DriverLink,
+ MEMORY_PROFILE_DRIVER_INFO_DATA,
+ Link,
+ MEMORY_PROFILE_DRIVER_INFO_SIGNATURE
+ );
+ TotalSize += DriverInfoData->DriverInfo.Header.Length;
+
+ AllocInfoList = DriverInfoData->AllocInfoList;
+ for (AllocLink = AllocInfoList->ForwardLink;
+ AllocLink != AllocInfoList;
+ AllocLink = AllocLink->ForwardLink)
+ {
+ AllocInfoData = CR (
+ AllocLink,
+ MEMORY_PROFILE_ALLOC_INFO_DATA,
+ Link,
+ MEMORY_PROFILE_ALLOC_INFO_SIGNATURE
+ );
+ TotalSize += AllocInfoData->AllocInfo.Header.Length;
+ }
+ }
+
+ return TotalSize;
+}
+
+/**
+ Copy memory profile data.
+
+ @param ProfileBuffer The buffer to hold memory profile data.
+
+**/
+VOID
+MemoryProfileCopyData (
+ IN VOID *ProfileBuffer
+ )
+{
+ MEMORY_PROFILE_CONTEXT *Context;
+ MEMORY_PROFILE_DRIVER_INFO *DriverInfo;
+ MEMORY_PROFILE_ALLOC_INFO *AllocInfo;
+ MEMORY_PROFILE_CONTEXT_DATA *ContextData;
+ MEMORY_PROFILE_DRIVER_INFO_DATA *DriverInfoData;
+ MEMORY_PROFILE_ALLOC_INFO_DATA *AllocInfoData;
+ LIST_ENTRY *DriverInfoList;
+ LIST_ENTRY *DriverLink;
+ LIST_ENTRY *AllocInfoList;
+ LIST_ENTRY *AllocLink;
+ UINTN PdbSize;
+ UINTN ActionStringSize;
+
+ ContextData = GetMemoryProfileContext ();
+ if (ContextData == NULL) {
+ return;
+ }
+
+ Context = ProfileBuffer;
+ CopyMem (Context, &ContextData->Context, sizeof (MEMORY_PROFILE_CONTEXT));
+ DriverInfo = (MEMORY_PROFILE_DRIVER_INFO *)(Context + 1);
+
+ DriverInfoList = ContextData->DriverInfoList;
+ for (DriverLink = DriverInfoList->ForwardLink;
+ DriverLink != DriverInfoList;
+ DriverLink = DriverLink->ForwardLink)
+ {
+ DriverInfoData = CR (
+ DriverLink,
+ MEMORY_PROFILE_DRIVER_INFO_DATA,
+ Link,
+ MEMORY_PROFILE_DRIVER_INFO_SIGNATURE
+ );
+ CopyMem (DriverInfo, &DriverInfoData->DriverInfo, sizeof (MEMORY_PROFILE_DRIVER_INFO));
+ if (DriverInfo->PdbStringOffset != 0) {
+ PdbSize = AsciiStrSize (DriverInfoData->PdbString);
+ CopyMem ((VOID *)((UINTN)DriverInfo + DriverInfo->PdbStringOffset), DriverInfoData->PdbString, PdbSize);
+ }
+
+ AllocInfo = (MEMORY_PROFILE_ALLOC_INFO *)((UINTN)DriverInfo + DriverInfo->Header.Length);
+
+ AllocInfoList = DriverInfoData->AllocInfoList;
+ for (AllocLink = AllocInfoList->ForwardLink;
+ AllocLink != AllocInfoList;
+ AllocLink = AllocLink->ForwardLink)
+ {
+ AllocInfoData = CR (
+ AllocLink,
+ MEMORY_PROFILE_ALLOC_INFO_DATA,
+ Link,
+ MEMORY_PROFILE_ALLOC_INFO_SIGNATURE
+ );
+ CopyMem (AllocInfo, &AllocInfoData->AllocInfo, sizeof (MEMORY_PROFILE_ALLOC_INFO));
+ if (AllocInfo->ActionStringOffset != 0) {
+ ActionStringSize = AsciiStrSize (AllocInfoData->ActionString);
+ CopyMem ((VOID *)((UINTN)AllocInfo + AllocInfo->ActionStringOffset), AllocInfoData->ActionString, ActionStringSize);
+ }
+
+ AllocInfo = (MEMORY_PROFILE_ALLOC_INFO *)((UINTN)AllocInfo + AllocInfo->Header.Length);
+ }
+
+ DriverInfo = (MEMORY_PROFILE_DRIVER_INFO *)AllocInfo;
+ }
+}
+
+/**
+ Get memory profile data.
+
+ @param[in] This The EDKII_MEMORY_PROFILE_PROTOCOL instance.
+ @param[in, out] ProfileSize On entry, points to the size in bytes of the ProfileBuffer.
+ On return, points to the size of the data returned in ProfileBuffer.
+ @param[out] ProfileBuffer Profile buffer.
+
+ @return EFI_SUCCESS Get the memory profile data successfully.
+ @return EFI_UNSUPPORTED Memory profile is unsupported.
+ @return EFI_BUFFER_TO_SMALL The ProfileSize is too small for the resulting data.
+ ProfileSize is updated with the size required.
+
+**/
+EFI_STATUS
+EFIAPI
+ProfileProtocolGetData (
+ IN EDKII_MEMORY_PROFILE_PROTOCOL *This,
+ IN OUT UINT64 *ProfileSize,
+ OUT VOID *ProfileBuffer
+ )
+{
+ UINTN Size;
+ MEMORY_PROFILE_CONTEXT_DATA *ContextData;
+ BOOLEAN MemoryProfileGettingStatus;
+
+ ContextData = GetMemoryProfileContext ();
+ if (ContextData == NULL) {
+ return EFI_UNSUPPORTED;
+ }
+
+ MemoryProfileGettingStatus = mMemoryProfileGettingStatus;
+ mMemoryProfileGettingStatus = TRUE;
+
+ Size = MemoryProfileGetDataSize ();
+
+ if (*ProfileSize < Size) {
+ *ProfileSize = Size;
+ mMemoryProfileGettingStatus = MemoryProfileGettingStatus;
+ return EFI_BUFFER_TOO_SMALL;
+ }
+
+ *ProfileSize = Size;
+ MemoryProfileCopyData (ProfileBuffer);
+
+ mMemoryProfileGettingStatus = MemoryProfileGettingStatus;
+ return EFI_SUCCESS;
+}
+
+/**
+ Register image to memory profile.
+
+ @param[in] This The EDKII_MEMORY_PROFILE_PROTOCOL instance.
+ @param[in] FilePath File path of the image.
+ @param[in] ImageBase Image base address.
+ @param[in] ImageSize Image size.
+ @param[in] FileType File type of the image.
+
+ @return EFI_SUCCESS Register successfully.
+ @return EFI_UNSUPPORTED Memory profile is unsupported,
+ or memory profile for the image is not required.
+ @return EFI_OUT_OF_RESOURCES No enough resource for this register.
+
+**/
+EFI_STATUS
+EFIAPI
+ProfileProtocolRegisterImage (
+ IN EDKII_MEMORY_PROFILE_PROTOCOL *This,
+ IN EFI_DEVICE_PATH_PROTOCOL *FilePath,
+ IN PHYSICAL_ADDRESS ImageBase,
+ IN UINT64 ImageSize,
+ IN EFI_FV_FILETYPE FileType
+ )
+{
+ EFI_STATUS Status;
+ LOADED_IMAGE_PRIVATE_DATA DriverEntry;
+ VOID *EntryPointInImage;
+
+ ZeroMem (&DriverEntry, sizeof (DriverEntry));
+ DriverEntry.Info.FilePath = FilePath;
+ DriverEntry.ImageContext.ImageAddress = ImageBase;
+ DriverEntry.ImageContext.ImageSize = ImageSize;
+ Status = InternalPeCoffGetEntryPoint ((VOID *)(UINTN)ImageBase, &EntryPointInImage);
+ ASSERT_EFI_ERROR (Status);
+ DriverEntry.ImageContext.EntryPoint = (PHYSICAL_ADDRESS)(UINTN)EntryPointInImage;
+ DriverEntry.ImageContext.ImageType = InternalPeCoffGetSubsystem ((VOID *)(UINTN)ImageBase);
+
+ return RegisterMemoryProfileImage (&DriverEntry, FileType);
+}
+
+/**
+ Unregister image from memory profile.
+
+ @param[in] This The EDKII_MEMORY_PROFILE_PROTOCOL instance.
+ @param[in] FilePath File path of the image.
+ @param[in] ImageBase Image base address.
+ @param[in] ImageSize Image size.
+
+ @return EFI_SUCCESS Unregister successfully.
+ @return EFI_UNSUPPORTED Memory profile is unsupported,
+ or memory profile for the image is not required.
+ @return EFI_NOT_FOUND The image is not found.
+
+**/
+EFI_STATUS
+EFIAPI
+ProfileProtocolUnregisterImage (
+ IN EDKII_MEMORY_PROFILE_PROTOCOL *This,
+ IN EFI_DEVICE_PATH_PROTOCOL *FilePath,
+ IN PHYSICAL_ADDRESS ImageBase,
+ IN UINT64 ImageSize
+ )
+{
+ EFI_STATUS Status;
+ LOADED_IMAGE_PRIVATE_DATA DriverEntry;
+ VOID *EntryPointInImage;
+
+ ZeroMem (&DriverEntry, sizeof (DriverEntry));
+ DriverEntry.Info.FilePath = FilePath;
+ DriverEntry.ImageContext.ImageAddress = ImageBase;
+ DriverEntry.ImageContext.ImageSize = ImageSize;
+ Status = InternalPeCoffGetEntryPoint ((VOID *)(UINTN)ImageBase, &EntryPointInImage);
+ ASSERT_EFI_ERROR (Status);
+ DriverEntry.ImageContext.EntryPoint = (PHYSICAL_ADDRESS)(UINTN)EntryPointInImage;
+
+ return UnregisterMemoryProfileImage (&DriverEntry);
+}
+
+/**
+ Get memory profile recording state.
+
+ @param[in] This The EDKII_MEMORY_PROFILE_PROTOCOL instance.
+ @param[out] RecordingState Recording state.
+
+ @return EFI_SUCCESS Memory profile recording state is returned.
+ @return EFI_UNSUPPORTED Memory profile is unsupported.
+ @return EFI_INVALID_PARAMETER RecordingState is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+ProfileProtocolGetRecordingState (
+ IN EDKII_MEMORY_PROFILE_PROTOCOL *This,
+ OUT BOOLEAN *RecordingState
+ )
+{
+ MEMORY_PROFILE_CONTEXT_DATA *ContextData;
+
+ ContextData = GetMemoryProfileContext ();
+ if (ContextData == NULL) {
+ return EFI_UNSUPPORTED;
+ }
+
+ if (RecordingState == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ *RecordingState = mMemoryProfileRecordingEnable;
+ return EFI_SUCCESS;
+}
+
+/**
+ Set memory profile recording state.
+
+ @param[in] This The EDKII_MEMORY_PROFILE_PROTOCOL instance.
+ @param[in] RecordingState Recording state.
+
+ @return EFI_SUCCESS Set memory profile recording state successfully.
+ @return EFI_UNSUPPORTED Memory profile is unsupported.
+
+**/
+EFI_STATUS
+EFIAPI
+ProfileProtocolSetRecordingState (
+ IN EDKII_MEMORY_PROFILE_PROTOCOL *This,
+ IN BOOLEAN RecordingState
+ )
+{
+ MEMORY_PROFILE_CONTEXT_DATA *ContextData;
+
+ ContextData = GetMemoryProfileContext ();
+ if (ContextData == NULL) {
+ return EFI_UNSUPPORTED;
+ }
+
+ mMemoryProfileRecordingEnable = RecordingState;
+ return EFI_SUCCESS;
+}
+
+/**
+ Record memory profile of multilevel caller.
+
+ @param[in] This The EDKII_MEMORY_PROFILE_PROTOCOL instance.
+ @param[in] CallerAddress Address of caller.
+ @param[in] Action Memory profile action.
+ @param[in] MemoryType Memory type.
+ EfiMaxMemoryType means the MemoryType is unknown.
+ @param[in] Buffer Buffer address.
+ @param[in] Size Buffer size.
+ @param[in] ActionString String for memory profile action.
+ Only needed for user defined allocate action.
+
+ @return EFI_SUCCESS Memory profile is updated.
+ @return EFI_UNSUPPORTED Memory profile is unsupported,
+ or memory profile for the image is not required,
+ or memory profile for the memory type is not required.
+ @return EFI_ACCESS_DENIED It is during memory profile data getting.
+ @return EFI_ABORTED Memory profile recording is not enabled.
+ @return EFI_OUT_OF_RESOURCES No enough resource to update memory profile for allocate action.
+ @return EFI_NOT_FOUND No matched allocate info found for free action.
+
+**/
+EFI_STATUS
+EFIAPI
+ProfileProtocolRecord (
+ IN EDKII_MEMORY_PROFILE_PROTOCOL *This,
+ IN PHYSICAL_ADDRESS CallerAddress,
+ IN MEMORY_PROFILE_ACTION Action,
+ IN EFI_MEMORY_TYPE MemoryType,
+ IN VOID *Buffer,
+ IN UINTN Size,
+ IN CHAR8 *ActionString OPTIONAL
+ )
+{
+ return CoreUpdateProfile (CallerAddress, Action, MemoryType, Size, Buffer, ActionString);
+}
+
+////////////////////
diff --git a/MdeModulePkg/Core/Dxe/Mem/Page.c b/MdeModulePkg/Core/Dxe/Mem/Page.c
index 5a51d9df1a..609bddf0d2 100644
--- a/MdeModulePkg/Core/Dxe/Mem/Page.c
+++ b/MdeModulePkg/Core/Dxe/Mem/Page.c
@@ -1,2308 +1,2308 @@
-/** @file
- UEFI Memory page management functions.
-
-Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.<BR>
-SPDX-License-Identifier: BSD-2-Clause-Patent
-
-**/
-
-#include "DxeMain.h"
-#include "Imem.h"
-#include "HeapGuard.h"
-#include <Pi/PiDxeCis.h>
-
-//
-// Entry for tracking the memory regions for each memory type to coalesce similar memory types
-//
-typedef struct {
- EFI_PHYSICAL_ADDRESS BaseAddress;
- EFI_PHYSICAL_ADDRESS MaximumAddress;
- UINT64 CurrentNumberOfPages;
- UINT64 NumberOfPages;
- UINTN InformationIndex;
- BOOLEAN Special;
- BOOLEAN Runtime;
-} EFI_MEMORY_TYPE_STATISTICS;
-
-//
-// MemoryMap - The current memory map
-//
-UINTN mMemoryMapKey = 0;
-
-#define MAX_MAP_DEPTH 6
-
-///
-/// mMapDepth - depth of new descriptor stack
-///
-UINTN mMapDepth = 0;
-///
-/// mMapStack - space to use as temp storage to build new map descriptors
-///
-MEMORY_MAP mMapStack[MAX_MAP_DEPTH];
-UINTN mFreeMapStack = 0;
-///
-/// This list maintain the free memory map list
-///
-LIST_ENTRY mFreeMemoryMapEntryList = INITIALIZE_LIST_HEAD_VARIABLE (mFreeMemoryMapEntryList);
-BOOLEAN mMemoryTypeInformationInitialized = FALSE;
-
-EFI_MEMORY_TYPE_STATISTICS mMemoryTypeStatistics[EfiMaxMemoryType + 1] = {
- { 0, MAX_ALLOC_ADDRESS, 0, 0, EfiMaxMemoryType, TRUE, FALSE }, // EfiReservedMemoryType
- { 0, MAX_ALLOC_ADDRESS, 0, 0, EfiMaxMemoryType, FALSE, FALSE }, // EfiLoaderCode
- { 0, MAX_ALLOC_ADDRESS, 0, 0, EfiMaxMemoryType, FALSE, FALSE }, // EfiLoaderData
- { 0, MAX_ALLOC_ADDRESS, 0, 0, EfiMaxMemoryType, FALSE, FALSE }, // EfiBootServicesCode
- { 0, MAX_ALLOC_ADDRESS, 0, 0, EfiMaxMemoryType, FALSE, FALSE }, // EfiBootServicesData
- { 0, MAX_ALLOC_ADDRESS, 0, 0, EfiMaxMemoryType, TRUE, TRUE }, // EfiRuntimeServicesCode
- { 0, MAX_ALLOC_ADDRESS, 0, 0, EfiMaxMemoryType, TRUE, TRUE }, // EfiRuntimeServicesData
- { 0, MAX_ALLOC_ADDRESS, 0, 0, EfiMaxMemoryType, FALSE, FALSE }, // EfiConventionalMemory
- { 0, MAX_ALLOC_ADDRESS, 0, 0, EfiMaxMemoryType, FALSE, FALSE }, // EfiUnusableMemory
- { 0, MAX_ALLOC_ADDRESS, 0, 0, EfiMaxMemoryType, TRUE, FALSE }, // EfiACPIReclaimMemory
- { 0, MAX_ALLOC_ADDRESS, 0, 0, EfiMaxMemoryType, TRUE, FALSE }, // EfiACPIMemoryNVS
- { 0, MAX_ALLOC_ADDRESS, 0, 0, EfiMaxMemoryType, FALSE, FALSE }, // EfiMemoryMappedIO
- { 0, MAX_ALLOC_ADDRESS, 0, 0, EfiMaxMemoryType, FALSE, FALSE }, // EfiMemoryMappedIOPortSpace
- { 0, MAX_ALLOC_ADDRESS, 0, 0, EfiMaxMemoryType, TRUE, TRUE }, // EfiPalCode
- { 0, MAX_ALLOC_ADDRESS, 0, 0, EfiMaxMemoryType, FALSE, FALSE }, // EfiPersistentMemory
- { 0, MAX_ALLOC_ADDRESS, 0, 0, EfiMaxMemoryType, TRUE, FALSE }, // EfiUnacceptedMemoryType
- { 0, MAX_ALLOC_ADDRESS, 0, 0, EfiMaxMemoryType, FALSE, FALSE } // EfiMaxMemoryType
-};
-
-EFI_PHYSICAL_ADDRESS mDefaultMaximumAddress = MAX_ALLOC_ADDRESS;
-EFI_PHYSICAL_ADDRESS mDefaultBaseAddress = MAX_ALLOC_ADDRESS;
-
-EFI_MEMORY_TYPE_INFORMATION gMemoryTypeInformation[EfiMaxMemoryType + 1] = {
- { EfiReservedMemoryType, 0 },
- { EfiLoaderCode, 0 },
- { EfiLoaderData, 0 },
- { EfiBootServicesCode, 0 },
- { EfiBootServicesData, 0 },
- { EfiRuntimeServicesCode, 0 },
- { EfiRuntimeServicesData, 0 },
- { EfiConventionalMemory, 0 },
- { EfiUnusableMemory, 0 },
- { EfiACPIReclaimMemory, 0 },
- { EfiACPIMemoryNVS, 0 },
- { EfiMemoryMappedIO, 0 },
- { EfiMemoryMappedIOPortSpace, 0 },
- { EfiPalCode, 0 },
- { EfiPersistentMemory, 0 },
- { EfiGcdMemoryTypeUnaccepted, 0 },
- { EfiMaxMemoryType, 0 }
-};
-//
-// Only used when load module at fixed address feature is enabled. True means the memory is alreay successfully allocated
-// and ready to load the module in to specified address.or else, the memory is not ready and module will be loaded at a
-// address assigned by DXE core.
-//
-GLOBAL_REMOVE_IF_UNREFERENCED BOOLEAN gLoadFixedAddressCodeMemoryReady = FALSE;
-
-/**
- Enter critical section by gaining lock on gMemoryLock.
-
-**/
-VOID
-CoreAcquireMemoryLock (
- VOID
- )
-{
- CoreAcquireLock (&gMemoryLock);
-}
-
-/**
- Exit critical section by releasing lock on gMemoryLock.
-
-**/
-VOID
-CoreReleaseMemoryLock (
- VOID
- )
-{
- CoreReleaseLock (&gMemoryLock);
-}
-
-/**
- Internal function. Removes a descriptor entry.
-
- @param Entry The entry to remove
-
-**/
-VOID
-RemoveMemoryMapEntry (
- IN OUT MEMORY_MAP *Entry
- )
-{
- RemoveEntryList (&Entry->Link);
- Entry->Link.ForwardLink = NULL;
-
- if (Entry->FromPages) {
- //
- // Insert the free memory map descriptor to the end of mFreeMemoryMapEntryList
- //
- InsertTailList (&mFreeMemoryMapEntryList, &Entry->Link);
- }
-}
-
-/**
- Internal function. Adds a ranges to the memory map.
- The range must not already exist in the map.
-
- @param Type The type of memory range to add
- @param Start The starting address in the memory range Must be
- paged aligned
- @param End The last address in the range Must be the last
- byte of a page
- @param Attribute The attributes of the memory range to add
-
-**/
-VOID
-CoreAddRange (
- IN EFI_MEMORY_TYPE Type,
- IN EFI_PHYSICAL_ADDRESS Start,
- IN EFI_PHYSICAL_ADDRESS End,
- IN UINT64 Attribute
- )
-{
- LIST_ENTRY *Link;
- MEMORY_MAP *Entry;
-
- ASSERT ((Start & EFI_PAGE_MASK) == 0);
- ASSERT (End > Start);
-
- ASSERT_LOCKED (&gMemoryLock);
-
- DEBUG ((DEBUG_PAGE, "AddRange: %lx-%lx to %d\n", Start, End, Type));
-
- //
- // If memory of type EfiConventionalMemory is being added that includes the page
- // starting at address 0, then zero the page starting at address 0. This has
- // two benifits. It helps find NULL pointer bugs and it also maximizes
- // compatibility with operating systems that may evaluate memory in this page
- // for legacy data structures. If memory of any other type is added starting
- // at address 0, then do not zero the page at address 0 because the page is being
- // used for other purposes.
- //
- if ((Type == EfiConventionalMemory) && (Start == 0) && (End >= EFI_PAGE_SIZE - 1)) {
- if ((PcdGet8 (PcdNullPointerDetectionPropertyMask) & BIT0) == 0) {
- SetMem ((VOID *)(UINTN)Start, EFI_PAGE_SIZE, 0);
- }
- }
-
- //
- // Memory map being altered so updated key
- //
- mMemoryMapKey += 1;
-
- //
- // UEFI 2.0 added an event group for notificaiton on memory map changes.
- // So we need to signal this Event Group every time the memory map changes.
- // If we are in EFI 1.10 compatability mode no event groups will be
- // found and nothing will happen we we call this function. These events
- // will get signaled but since a lock is held around the call to this
- // function the notificaiton events will only be called after this function
- // returns and the lock is released.
- //
- CoreNotifySignalList (&gEfiEventMemoryMapChangeGuid);
-
- //
- // Look for adjoining memory descriptor
- //
-
- // Two memory descriptors can only be merged if they have the same Type
- // and the same Attribute
- //
-
- Link = gMemoryMap.ForwardLink;
- while (Link != &gMemoryMap) {
- Entry = CR (Link, MEMORY_MAP, Link, MEMORY_MAP_SIGNATURE);
- Link = Link->ForwardLink;
-
- if (Entry->Type != Type) {
- continue;
- }
-
- if (Entry->Attribute != Attribute) {
- continue;
- }
-
- if (Entry->End + 1 == Start) {
- Start = Entry->Start;
- RemoveMemoryMapEntry (Entry);
- } else if (Entry->Start == End + 1) {
- End = Entry->End;
- RemoveMemoryMapEntry (Entry);
- }
- }
-
- //
- // Add descriptor
- //
-
- mMapStack[mMapDepth].Signature = MEMORY_MAP_SIGNATURE;
- mMapStack[mMapDepth].FromPages = FALSE;
- mMapStack[mMapDepth].Type = Type;
- mMapStack[mMapDepth].Start = Start;
- mMapStack[mMapDepth].End = End;
- mMapStack[mMapDepth].VirtualStart = 0;
- mMapStack[mMapDepth].Attribute = Attribute;
- InsertTailList (&gMemoryMap, &mMapStack[mMapDepth].Link);
-
- mMapDepth += 1;
- ASSERT (mMapDepth < MAX_MAP_DEPTH);
-
- return;
-}
-
-/**
- Internal function. Deque a descriptor entry from the mFreeMemoryMapEntryList.
- If the list is emtry, then allocate a new page to refuel the list.
- Please Note this algorithm to allocate the memory map descriptor has a property
- that the memory allocated for memory entries always grows, and will never really be freed
- For example, if the current boot uses 2000 memory map entries at the maximum point, but
- ends up with only 50 at the time the OS is booted, then the memory associated with the 1950
- memory map entries is still allocated from EfiBootServicesMemory.
-
-
- @return The Memory map descriptor dequed from the mFreeMemoryMapEntryList
-
-**/
-MEMORY_MAP *
-AllocateMemoryMapEntry (
- VOID
- )
-{
- MEMORY_MAP *FreeDescriptorEntries;
- MEMORY_MAP *Entry;
- UINTN Index;
-
- if (IsListEmpty (&mFreeMemoryMapEntryList)) {
- //
- // The list is empty, to allocate one page to refuel the list
- //
- FreeDescriptorEntries = CoreAllocatePoolPages (
- EfiBootServicesData,
- EFI_SIZE_TO_PAGES (DEFAULT_PAGE_ALLOCATION_GRANULARITY),
- DEFAULT_PAGE_ALLOCATION_GRANULARITY,
- FALSE
- );
- if (FreeDescriptorEntries != NULL) {
- //
- // Enque the free memmory map entries into the list
- //
- for (Index = 0; Index < DEFAULT_PAGE_ALLOCATION_GRANULARITY / sizeof (MEMORY_MAP); Index++) {
- FreeDescriptorEntries[Index].Signature = MEMORY_MAP_SIGNATURE;
- InsertTailList (&mFreeMemoryMapEntryList, &FreeDescriptorEntries[Index].Link);
- }
- } else {
- return NULL;
- }
- }
-
- //
- // dequeue the first descriptor from the list
- //
- Entry = CR (mFreeMemoryMapEntryList.ForwardLink, MEMORY_MAP, Link, MEMORY_MAP_SIGNATURE);
- RemoveEntryList (&Entry->Link);
-
- return Entry;
-}
-
-/**
- Internal function. Moves any memory descriptors that are on the
- temporary descriptor stack to heap.
-
-**/
-VOID
-CoreFreeMemoryMapStack (
- VOID
- )
-{
- MEMORY_MAP *Entry;
- MEMORY_MAP *Entry2;
- LIST_ENTRY *Link2;
-
- ASSERT_LOCKED (&gMemoryLock);
-
- //
- // If already freeing the map stack, then return
- //
- if (mFreeMapStack != 0) {
- return;
- }
-
- //
- // Move the temporary memory descriptor stack into pool
- //
- mFreeMapStack += 1;
-
- while (mMapDepth != 0) {
- //
- // Deque an memory map entry from mFreeMemoryMapEntryList
- //
- Entry = AllocateMemoryMapEntry ();
-
- ASSERT (Entry);
-
- //
- // Update to proper entry
- //
- mMapDepth -= 1;
-
- if (mMapStack[mMapDepth].Link.ForwardLink != NULL) {
- //
- // Move this entry to general memory
- //
- RemoveEntryList (&mMapStack[mMapDepth].Link);
- mMapStack[mMapDepth].Link.ForwardLink = NULL;
-
- CopyMem (Entry, &mMapStack[mMapDepth], sizeof (MEMORY_MAP));
- Entry->FromPages = TRUE;
-
- //
- // Find insertion location
- //
- for (Link2 = gMemoryMap.ForwardLink; Link2 != &gMemoryMap; Link2 = Link2->ForwardLink) {
- Entry2 = CR (Link2, MEMORY_MAP, Link, MEMORY_MAP_SIGNATURE);
- if (Entry2->FromPages && (Entry2->Start > Entry->Start)) {
- break;
- }
- }
-
- InsertTailList (Link2, &Entry->Link);
- } else {
- //
- // This item of mMapStack[mMapDepth] has already been dequeued from gMemoryMap list,
- // so here no need to move it to memory.
- //
- InsertTailList (&mFreeMemoryMapEntryList, &Entry->Link);
- }
- }
-
- mFreeMapStack -= 1;
-}
-
-/**
- Find untested but initialized memory regions in GCD map and convert them to be DXE allocatable.
-
-**/
-BOOLEAN
-PromoteMemoryResource (
- VOID
- )
-{
- LIST_ENTRY *Link;
- EFI_GCD_MAP_ENTRY *Entry;
- BOOLEAN Promoted;
- EFI_PHYSICAL_ADDRESS StartAddress;
- EFI_PHYSICAL_ADDRESS EndAddress;
- EFI_GCD_MEMORY_SPACE_DESCRIPTOR Descriptor;
-
- DEBUG ((DEBUG_PAGE, "Promote the memory resource\n"));
-
- CoreAcquireGcdMemoryLock ();
-
- Promoted = FALSE;
- Link = mGcdMemorySpaceMap.ForwardLink;
- while (Link != &mGcdMemorySpaceMap) {
- Entry = CR (Link, EFI_GCD_MAP_ENTRY, Link, EFI_GCD_MAP_SIGNATURE);
-
- if ((Entry->GcdMemoryType == EfiGcdMemoryTypeReserved) &&
- (Entry->EndAddress < MAX_ALLOC_ADDRESS) &&
- ((Entry->Capabilities & (EFI_MEMORY_PRESENT | EFI_MEMORY_INITIALIZED | EFI_MEMORY_TESTED)) ==
- (EFI_MEMORY_PRESENT | EFI_MEMORY_INITIALIZED)))
- {
- //
- // Update the GCD map
- //
- if ((Entry->Capabilities & EFI_MEMORY_MORE_RELIABLE) == EFI_MEMORY_MORE_RELIABLE) {
- Entry->GcdMemoryType = EfiGcdMemoryTypeMoreReliable;
- } else {
- Entry->GcdMemoryType = EfiGcdMemoryTypeSystemMemory;
- }
-
- Entry->Capabilities |= EFI_MEMORY_TESTED;
- Entry->ImageHandle = gDxeCoreImageHandle;
- Entry->DeviceHandle = NULL;
-
- //
- // Add to allocable system memory resource
- //
-
- CoreAddRange (
- EfiConventionalMemory,
- Entry->BaseAddress,
- Entry->EndAddress,
- Entry->Capabilities & ~(EFI_MEMORY_PRESENT | EFI_MEMORY_INITIALIZED | EFI_MEMORY_TESTED | EFI_MEMORY_RUNTIME)
- );
- CoreFreeMemoryMapStack ();
-
- Promoted = TRUE;
- }
-
- Link = Link->ForwardLink;
- }
-
- CoreReleaseGcdMemoryLock ();
-
- if (!Promoted) {
- //
- // If freed-memory guard is enabled, we could promote pages from
- // guarded free pages.
- //
- Promoted = PromoteGuardedFreePages (&StartAddress, &EndAddress);
- if (Promoted) {
- if (!EFI_ERROR (CoreGetMemorySpaceDescriptor (StartAddress, &Descriptor))) {
- CoreAddRange (
- EfiConventionalMemory,
- StartAddress,
- EndAddress,
- Descriptor.Capabilities & ~(EFI_MEMORY_PRESENT | EFI_MEMORY_INITIALIZED |
- EFI_MEMORY_TESTED | EFI_MEMORY_RUNTIME)
- );
- }
- }
- }
-
- return Promoted;
-}
-
-/**
- This function try to allocate Runtime code & Boot time code memory range. If LMFA enabled, 2 patchable PCD
- PcdLoadFixAddressRuntimeCodePageNumber & PcdLoadFixAddressBootTimeCodePageNumber which are set by tools will record the
- size of boot time and runtime code.
-
-**/
-VOID
-CoreLoadingFixedAddressHook (
- VOID
- )
-{
- UINT32 RuntimeCodePageNumber;
- UINT32 BootTimeCodePageNumber;
- EFI_PHYSICAL_ADDRESS RuntimeCodeBase;
- EFI_PHYSICAL_ADDRESS BootTimeCodeBase;
- EFI_STATUS Status;
-
- //
- // Make sure these 2 areas are not initialzied.
- //
- if (!gLoadFixedAddressCodeMemoryReady) {
- RuntimeCodePageNumber = PcdGet32 (PcdLoadFixAddressRuntimeCodePageNumber);
- BootTimeCodePageNumber = PcdGet32 (PcdLoadFixAddressBootTimeCodePageNumber);
- RuntimeCodeBase = (EFI_PHYSICAL_ADDRESS)(gLoadModuleAtFixAddressConfigurationTable.DxeCodeTopAddress - EFI_PAGES_TO_SIZE (RuntimeCodePageNumber));
- BootTimeCodeBase = (EFI_PHYSICAL_ADDRESS)(RuntimeCodeBase - EFI_PAGES_TO_SIZE (BootTimeCodePageNumber));
- //
- // Try to allocate runtime memory.
- //
- Status = CoreAllocatePages (
- AllocateAddress,
- EfiRuntimeServicesCode,
- RuntimeCodePageNumber,
- &RuntimeCodeBase
- );
- if (EFI_ERROR (Status)) {
- //
- // Runtime memory allocation failed
- //
- return;
- }
-
- //
- // Try to allocate boot memory.
- //
- Status = CoreAllocatePages (
- AllocateAddress,
- EfiBootServicesCode,
- BootTimeCodePageNumber,
- &BootTimeCodeBase
- );
- if (EFI_ERROR (Status)) {
- //
- // boot memory allocation failed. Free Runtime code range and will try the allocation again when
- // new memory range is installed.
- //
- CoreFreePages (
- RuntimeCodeBase,
- RuntimeCodePageNumber
- );
- return;
- }
-
- gLoadFixedAddressCodeMemoryReady = TRUE;
- }
-
- return;
-}
-
-/**
- Sets the preferred memory range to use for the Memory Type Information bins.
- This service must be called before fist call to CoreAddMemoryDescriptor().
-
- If the location of the Memory Type Information bins has already been
- established or the size of the range provides is smaller than all the
- Memory Type Information bins, then the range provides is not used.
-
- @param Start The start address of the Memory Type Information range.
- @param Length The size, in bytes, of the Memory Type Information range.
-**/
-VOID
-CoreSetMemoryTypeInformationRange (
- IN EFI_PHYSICAL_ADDRESS Start,
- IN UINT64 Length
- )
-{
- EFI_PHYSICAL_ADDRESS Top;
- EFI_MEMORY_TYPE Type;
- UINTN Index;
- UINTN Size;
-
- //
- // Return if Memory Type Information bin locations have already been set
- //
- if (mMemoryTypeInformationInitialized) {
- DEBUG ((DEBUG_ERROR, "%a: Ignored. Bins already set.\n", __func__));
- return;
- }
-
- //
- // Return if size of the Memory Type Information bins is greater than Length
- //
- Size = 0;
- for (Index = 0; gMemoryTypeInformation[Index].Type != EfiMaxMemoryType; Index++) {
- //
- // Make sure the memory type in the gMemoryTypeInformation[] array is valid
- //
- Type = (EFI_MEMORY_TYPE)(gMemoryTypeInformation[Index].Type);
- if ((UINT32)Type > EfiMaxMemoryType) {
- continue;
- }
-
- Size += EFI_PAGES_TO_SIZE (gMemoryTypeInformation[Index].NumberOfPages);
- }
-
- if (Size > Length) {
- return;
- }
-
- //
- // Loop through each memory type in the order specified by the
- // gMemoryTypeInformation[] array
- //
- Top = Start + Length;
- for (Index = 0; gMemoryTypeInformation[Index].Type != EfiMaxMemoryType; Index++) {
- //
- // Make sure the memory type in the gMemoryTypeInformation[] array is valid
- //
- Type = (EFI_MEMORY_TYPE)(gMemoryTypeInformation[Index].Type);
- if ((UINT32)Type > EfiMaxMemoryType) {
- continue;
- }
-
- if (gMemoryTypeInformation[Index].NumberOfPages != 0) {
- mMemoryTypeStatistics[Type].MaximumAddress = Top - 1;
- Top -= EFI_PAGES_TO_SIZE (gMemoryTypeInformation[Index].NumberOfPages);
- mMemoryTypeStatistics[Type].BaseAddress = Top;
-
- //
- // If the current base address is the lowest address so far, then update
- // the default maximum address
- //
- if (mMemoryTypeStatistics[Type].BaseAddress < mDefaultMaximumAddress) {
- mDefaultMaximumAddress = mMemoryTypeStatistics[Type].BaseAddress - 1;
- }
-
- mMemoryTypeStatistics[Type].NumberOfPages = gMemoryTypeInformation[Index].NumberOfPages;
- gMemoryTypeInformation[Index].NumberOfPages = 0;
- }
- }
-
- //
- // If the number of pages reserved for a memory type is 0, then all
- // allocations for that type should be in the default range.
- //
- for (Type = (EFI_MEMORY_TYPE)0; Type < EfiMaxMemoryType; Type++) {
- for (Index = 0; gMemoryTypeInformation[Index].Type != EfiMaxMemoryType; Index++) {
- if (Type == (EFI_MEMORY_TYPE)gMemoryTypeInformation[Index].Type) {
- mMemoryTypeStatistics[Type].InformationIndex = Index;
- }
- }
-
- mMemoryTypeStatistics[Type].CurrentNumberOfPages = 0;
- if (mMemoryTypeStatistics[Type].MaximumAddress == MAX_ALLOC_ADDRESS) {
- mMemoryTypeStatistics[Type].MaximumAddress = mDefaultMaximumAddress;
- }
- }
-
- mMemoryTypeInformationInitialized = TRUE;
-}
-
-/**
- Called to initialize the memory map and add descriptors to
- the current descriptor list.
- The first descriptor that is added must be general usable
- memory as the addition allocates heap.
-
- @param Type The type of memory to add
- @param Start The starting address in the memory range Must be
- page aligned
- @param NumberOfPages The number of pages in the range
- @param Attribute Attributes of the memory to add
-
- @return None. The range is added to the memory map
-
-**/
-VOID
-CoreAddMemoryDescriptor (
- IN EFI_MEMORY_TYPE Type,
- IN EFI_PHYSICAL_ADDRESS Start,
- IN UINT64 NumberOfPages,
- IN UINT64 Attribute
- )
-{
- EFI_PHYSICAL_ADDRESS End;
- EFI_STATUS Status;
- UINTN Index;
- UINTN FreeIndex;
-
- if ((Start & EFI_PAGE_MASK) != 0) {
- return;
- }
-
- if ((Type >= EfiMaxMemoryType) && (Type < MEMORY_TYPE_OEM_RESERVED_MIN)) {
- return;
- }
-
- CoreAcquireMemoryLock ();
- End = Start + LShiftU64 (NumberOfPages, EFI_PAGE_SHIFT) - 1;
- CoreAddRange (Type, Start, End, Attribute);
- CoreFreeMemoryMapStack ();
- CoreReleaseMemoryLock ();
-
- ApplyMemoryProtectionPolicy (
- EfiMaxMemoryType,
- Type,
- Start,
- LShiftU64 (NumberOfPages, EFI_PAGE_SHIFT)
- );
-
- //
- // If Loading Module At Fixed Address feature is enabled. try to allocate memory with Runtime code & Boot time code type
- //
- if (PcdGet64 (PcdLoadModuleAtFixAddressEnable) != 0) {
- CoreLoadingFixedAddressHook ();
- }
-
- //
- // Check to see if the statistics for the different memory types have already been established
- //
- if (mMemoryTypeInformationInitialized) {
- return;
- }
-
- //
- // Loop through each memory type in the order specified by the gMemoryTypeInformation[] array
- //
- for (Index = 0; gMemoryTypeInformation[Index].Type != EfiMaxMemoryType; Index++) {
- //
- // Make sure the memory type in the gMemoryTypeInformation[] array is valid
- //
- Type = (EFI_MEMORY_TYPE)(gMemoryTypeInformation[Index].Type);
- if ((UINT32)Type > EfiMaxMemoryType) {
- continue;
- }
-
- if (gMemoryTypeInformation[Index].NumberOfPages != 0) {
- //
- // Allocate pages for the current memory type from the top of available memory
- //
- Status = CoreAllocatePages (
- AllocateAnyPages,
- Type,
- gMemoryTypeInformation[Index].NumberOfPages,
- &mMemoryTypeStatistics[Type].BaseAddress
- );
- if (EFI_ERROR (Status)) {
- //
- // If an error occurs allocating the pages for the current memory type, then
- // free all the pages allocates for the previous memory types and return. This
- // operation with be retied when/if more memory is added to the system
- //
- for (FreeIndex = 0; FreeIndex < Index; FreeIndex++) {
- //
- // Make sure the memory type in the gMemoryTypeInformation[] array is valid
- //
- Type = (EFI_MEMORY_TYPE)(gMemoryTypeInformation[FreeIndex].Type);
- if ((UINT32)Type > EfiMaxMemoryType) {
- continue;
- }
-
- if (gMemoryTypeInformation[FreeIndex].NumberOfPages != 0) {
- CoreFreePages (
- mMemoryTypeStatistics[Type].BaseAddress,
- gMemoryTypeInformation[FreeIndex].NumberOfPages
- );
- mMemoryTypeStatistics[Type].BaseAddress = 0;
- mMemoryTypeStatistics[Type].MaximumAddress = MAX_ALLOC_ADDRESS;
- }
- }
-
- return;
- }
-
- //
- // Compute the address at the top of the current statistics
- //
- mMemoryTypeStatistics[Type].MaximumAddress =
- mMemoryTypeStatistics[Type].BaseAddress +
- LShiftU64 (gMemoryTypeInformation[Index].NumberOfPages, EFI_PAGE_SHIFT) - 1;
-
- //
- // If the current base address is the lowest address so far, then update the default
- // maximum address
- //
- if (mMemoryTypeStatistics[Type].BaseAddress < mDefaultMaximumAddress) {
- mDefaultMaximumAddress = mMemoryTypeStatistics[Type].BaseAddress - 1;
- }
- }
- }
-
- //
- // There was enough system memory for all the the memory types were allocated. So,
- // those memory areas can be freed for future allocations, and all future memory
- // allocations can occur within their respective bins
- //
- for (Index = 0; gMemoryTypeInformation[Index].Type != EfiMaxMemoryType; Index++) {
- //
- // Make sure the memory type in the gMemoryTypeInformation[] array is valid
- //
- Type = (EFI_MEMORY_TYPE)(gMemoryTypeInformation[Index].Type);
- if ((UINT32)Type > EfiMaxMemoryType) {
- continue;
- }
-
- if (gMemoryTypeInformation[Index].NumberOfPages != 0) {
- CoreFreePages (
- mMemoryTypeStatistics[Type].BaseAddress,
- gMemoryTypeInformation[Index].NumberOfPages
- );
- mMemoryTypeStatistics[Type].NumberOfPages = gMemoryTypeInformation[Index].NumberOfPages;
- gMemoryTypeInformation[Index].NumberOfPages = 0;
- }
- }
-
- //
- // If the number of pages reserved for a memory type is 0, then all allocations for that type
- // should be in the default range.
- //
- for (Type = (EFI_MEMORY_TYPE)0; Type < EfiMaxMemoryType; Type++) {
- for (Index = 0; gMemoryTypeInformation[Index].Type != EfiMaxMemoryType; Index++) {
- if (Type == (EFI_MEMORY_TYPE)gMemoryTypeInformation[Index].Type) {
- mMemoryTypeStatistics[Type].InformationIndex = Index;
- }
- }
-
- mMemoryTypeStatistics[Type].CurrentNumberOfPages = 0;
- if (mMemoryTypeStatistics[Type].MaximumAddress == MAX_ALLOC_ADDRESS) {
- mMemoryTypeStatistics[Type].MaximumAddress = mDefaultMaximumAddress;
- }
- }
-
- mMemoryTypeInformationInitialized = TRUE;
-}
-
-/**
- Internal function. Converts a memory range to the specified type or attributes.
- The range must exist in the memory map. Either ChangingType or
- ChangingAttributes must be set, but not both.
-
- @param Start The first address of the range Must be page
- aligned
- @param NumberOfPages The number of pages to convert
- @param ChangingType Boolean indicating that type value should be changed
- @param NewType The new type for the memory range
- @param ChangingAttributes Boolean indicating that attributes value should be changed
- @param NewAttributes The new attributes for the memory range
-
- @retval EFI_INVALID_PARAMETER Invalid parameter
- @retval EFI_NOT_FOUND Could not find a descriptor cover the specified
- range or convertion not allowed.
- @retval EFI_SUCCESS Successfully converts the memory range to the
- specified type.
-
-**/
-EFI_STATUS
-CoreConvertPagesEx (
- IN UINT64 Start,
- IN UINT64 NumberOfPages,
- IN BOOLEAN ChangingType,
- IN EFI_MEMORY_TYPE NewType,
- IN BOOLEAN ChangingAttributes,
- IN UINT64 NewAttributes
- )
-{
- UINT64 NumberOfBytes;
- UINT64 End;
- UINT64 RangeEnd;
- UINT64 Attribute;
- EFI_MEMORY_TYPE MemType;
- LIST_ENTRY *Link;
- MEMORY_MAP *Entry;
-
- Entry = NULL;
- NumberOfBytes = LShiftU64 (NumberOfPages, EFI_PAGE_SHIFT);
- End = Start + NumberOfBytes - 1;
-
- ASSERT (NumberOfPages);
- ASSERT ((Start & EFI_PAGE_MASK) == 0);
- ASSERT (End > Start);
- ASSERT_LOCKED (&gMemoryLock);
- ASSERT ((ChangingType == FALSE) || (ChangingAttributes == FALSE));
-
- if ((NumberOfPages == 0) || ((Start & EFI_PAGE_MASK) != 0) || (Start >= End)) {
- return EFI_INVALID_PARAMETER;
- }
-
- //
- // Convert the entire range
- //
-
- while (Start < End) {
- //
- // Find the entry that the covers the range
- //
- for (Link = gMemoryMap.ForwardLink; Link != &gMemoryMap; Link = Link->ForwardLink) {
- Entry = CR (Link, MEMORY_MAP, Link, MEMORY_MAP_SIGNATURE);
-
- if ((Entry->Start <= Start) && (Entry->End > Start)) {
- break;
- }
- }
-
- if (Link == &gMemoryMap) {
- DEBUG ((DEBUG_ERROR | DEBUG_PAGE, "ConvertPages: failed to find range %lx - %lx\n", Start, End));
- return EFI_NOT_FOUND;
- }
-
- //
- // If we are converting the type of the range from EfiConventionalMemory to
- // another type, we have to ensure that the entire range is covered by a
- // single entry.
- //
- if (ChangingType && (NewType != EfiConventionalMemory)) {
- if (Entry->End < End) {
- DEBUG ((DEBUG_ERROR | DEBUG_PAGE, "ConvertPages: range %lx - %lx covers multiple entries\n", Start, End));
- return EFI_NOT_FOUND;
- }
- }
-
- //
- // Convert range to the end, or to the end of the descriptor
- // if that's all we've got
- //
- RangeEnd = End;
-
- ASSERT (Entry != NULL);
- if (Entry->End < End) {
- RangeEnd = Entry->End;
- }
-
- if (ChangingType) {
- DEBUG ((DEBUG_PAGE, "ConvertRange: %lx-%lx to type %d\n", Start, RangeEnd, NewType));
- }
-
- if (ChangingAttributes) {
- DEBUG ((DEBUG_PAGE, "ConvertRange: %lx-%lx to attr %lx\n", Start, RangeEnd, NewAttributes));
- }
-
- if (ChangingType) {
- //
- // Debug code - verify conversion is allowed
- //
- if (!((NewType == EfiConventionalMemory) ? 1 : 0) ^ ((Entry->Type == EfiConventionalMemory) ? 1 : 0)) {
- DEBUG ((DEBUG_ERROR | DEBUG_PAGE, "ConvertPages: Incompatible memory types, "));
- if (Entry->Type == EfiConventionalMemory) {
- DEBUG ((DEBUG_ERROR | DEBUG_PAGE, "the pages to free have been freed\n"));
- } else {
- DEBUG ((DEBUG_ERROR | DEBUG_PAGE, "the pages to allocate have been allocated\n"));
- }
-
- return EFI_NOT_FOUND;
- }
-
- //
- // Update counters for the number of pages allocated to each memory type
- //
- if ((UINT32)Entry->Type < EfiMaxMemoryType) {
- if (((Start >= mMemoryTypeStatistics[Entry->Type].BaseAddress) && (Start <= mMemoryTypeStatistics[Entry->Type].MaximumAddress)) ||
- ((Start >= mDefaultBaseAddress) && (Start <= mDefaultMaximumAddress)))
- {
- if (NumberOfPages > mMemoryTypeStatistics[Entry->Type].CurrentNumberOfPages) {
- mMemoryTypeStatistics[Entry->Type].CurrentNumberOfPages = 0;
- } else {
- mMemoryTypeStatistics[Entry->Type].CurrentNumberOfPages -= NumberOfPages;
- }
- }
- }
-
- if ((UINT32)NewType < EfiMaxMemoryType) {
- if (((Start >= mMemoryTypeStatistics[NewType].BaseAddress) && (Start <= mMemoryTypeStatistics[NewType].MaximumAddress)) ||
- ((Start >= mDefaultBaseAddress) && (Start <= mDefaultMaximumAddress)))
- {
- mMemoryTypeStatistics[NewType].CurrentNumberOfPages += NumberOfPages;
- if (mMemoryTypeStatistics[NewType].CurrentNumberOfPages > gMemoryTypeInformation[mMemoryTypeStatistics[NewType].InformationIndex].NumberOfPages) {
- gMemoryTypeInformation[mMemoryTypeStatistics[NewType].InformationIndex].NumberOfPages = (UINT32)mMemoryTypeStatistics[NewType].CurrentNumberOfPages;
- }
- }
- }
- }
-
- //
- // Pull range out of descriptor
- //
- if (Entry->Start == Start) {
- //
- // Clip start
- //
- Entry->Start = RangeEnd + 1;
- } else if (Entry->End == RangeEnd) {
- //
- // Clip end
- //
- Entry->End = Start - 1;
- } else {
- //
- // Pull it out of the center, clip current
- //
-
- //
- // Add a new one
- //
- mMapStack[mMapDepth].Signature = MEMORY_MAP_SIGNATURE;
- mMapStack[mMapDepth].FromPages = FALSE;
- mMapStack[mMapDepth].Type = Entry->Type;
- mMapStack[mMapDepth].Start = RangeEnd+1;
- mMapStack[mMapDepth].End = Entry->End;
-
- //
- // Inherit Attribute from the Memory Descriptor that is being clipped
- //
- mMapStack[mMapDepth].Attribute = Entry->Attribute;
-
- Entry->End = Start - 1;
- ASSERT (Entry->Start < Entry->End);
-
- Entry = &mMapStack[mMapDepth];
- InsertTailList (&gMemoryMap, &Entry->Link);
-
- mMapDepth += 1;
- ASSERT (mMapDepth < MAX_MAP_DEPTH);
- }
-
- //
- // The new range inherits the same Attribute as the Entry
- // it is being cut out of unless attributes are being changed
- //
- if (ChangingType) {
- Attribute = Entry->Attribute;
- MemType = NewType;
- } else {
- Attribute = NewAttributes;
- MemType = Entry->Type;
- }
-
- //
- // If the descriptor is empty, then remove it from the map
- //
- if (Entry->Start == Entry->End + 1) {
- RemoveMemoryMapEntry (Entry);
- Entry = NULL;
- }
-
- //
- // Add our new range in. Don't do this for freed pages if freed-memory
- // guard is enabled.
- //
- if (!IsHeapGuardEnabled (GUARD_HEAP_TYPE_FREED) ||
- !ChangingType ||
- (MemType != EfiConventionalMemory))
- {
- CoreAddRange (MemType, Start, RangeEnd, Attribute);
- }
-
- if (ChangingType && (MemType == EfiConventionalMemory)) {
- //
- // Avoid calling DEBUG_CLEAR_MEMORY() for an address of 0 because this
- // macro will ASSERT() if address is 0. Instead, CoreAddRange() guarantees
- // that the page starting at address 0 is always filled with zeros.
- //
- if (Start == 0) {
- if (RangeEnd > EFI_PAGE_SIZE) {
- DEBUG_CLEAR_MEMORY ((VOID *)(UINTN)EFI_PAGE_SIZE, (UINTN)(RangeEnd - EFI_PAGE_SIZE + 1));
- }
- } else {
- DEBUG_CLEAR_MEMORY ((VOID *)(UINTN)Start, (UINTN)(RangeEnd - Start + 1));
- }
- }
-
- //
- // Move any map descriptor stack to general pool
- //
- CoreFreeMemoryMapStack ();
-
- //
- // Bump the starting address, and convert the next range
- //
- Start = RangeEnd + 1;
- }
-
- //
- // Converted the whole range, done
- //
-
- return EFI_SUCCESS;
-}
-
-/**
- Internal function. Converts a memory range to the specified type.
- The range must exist in the memory map.
-
- @param Start The first address of the range Must be page
- aligned
- @param NumberOfPages The number of pages to convert
- @param NewType The new type for the memory range
-
- @retval EFI_INVALID_PARAMETER Invalid parameter
- @retval EFI_NOT_FOUND Could not find a descriptor cover the specified
- range or convertion not allowed.
- @retval EFI_SUCCESS Successfully converts the memory range to the
- specified type.
-
-**/
-EFI_STATUS
-CoreConvertPages (
- IN UINT64 Start,
- IN UINT64 NumberOfPages,
- IN EFI_MEMORY_TYPE NewType
- )
-{
- return CoreConvertPagesEx (Start, NumberOfPages, TRUE, NewType, FALSE, 0);
-}
-
-/**
- Internal function. Converts a memory range to use new attributes.
-
- @param Start The first address of the range Must be page
- aligned
- @param NumberOfPages The number of pages to convert
- @param NewAttributes The new attributes value for the range.
-
-**/
-VOID
-CoreUpdateMemoryAttributes (
- IN EFI_PHYSICAL_ADDRESS Start,
- IN UINT64 NumberOfPages,
- IN UINT64 NewAttributes
- )
-{
- CoreAcquireMemoryLock ();
-
- //
- // Update the attributes to the new value
- //
- CoreConvertPagesEx (Start, NumberOfPages, FALSE, (EFI_MEMORY_TYPE)0, TRUE, NewAttributes);
-
- CoreReleaseMemoryLock ();
-}
-
-/**
- Internal function. Finds a consecutive free page range below
- the requested address.
-
- @param MaxAddress The address that the range must be below
- @param MinAddress The address that the range must be above
- @param NumberOfPages Number of pages needed
- @param NewType The type of memory the range is going to be
- turned into
- @param Alignment Bits to align with
- @param NeedGuard Flag to indicate Guard page is needed or not
-
- @return The base address of the range, or 0 if the range was not found
-
-**/
-UINT64
-CoreFindFreePagesI (
- IN UINT64 MaxAddress,
- IN UINT64 MinAddress,
- IN UINT64 NumberOfPages,
- IN EFI_MEMORY_TYPE NewType,
- IN UINTN Alignment,
- IN BOOLEAN NeedGuard
- )
-{
- UINT64 NumberOfBytes;
- UINT64 Target;
- UINT64 DescStart;
- UINT64 DescEnd;
- UINT64 DescNumberOfBytes;
- LIST_ENTRY *Link;
- MEMORY_MAP *Entry;
-
- if ((MaxAddress < EFI_PAGE_MASK) || (NumberOfPages == 0)) {
- return 0;
- }
-
- if ((MaxAddress & EFI_PAGE_MASK) != EFI_PAGE_MASK) {
- //
- // If MaxAddress is not aligned to the end of a page
- //
-
- //
- // Change MaxAddress to be 1 page lower
- //
- MaxAddress -= (EFI_PAGE_MASK + 1);
-
- //
- // Set MaxAddress to a page boundary
- //
- MaxAddress &= ~(UINT64)EFI_PAGE_MASK;
-
- //
- // Set MaxAddress to end of the page
- //
- MaxAddress |= EFI_PAGE_MASK;
- }
-
- NumberOfBytes = LShiftU64 (NumberOfPages, EFI_PAGE_SHIFT);
- Target = 0;
-
- for (Link = gMemoryMap.ForwardLink; Link != &gMemoryMap; Link = Link->ForwardLink) {
- Entry = CR (Link, MEMORY_MAP, Link, MEMORY_MAP_SIGNATURE);
-
- //
- // If it's not a free entry, don't bother with it
- //
- if (Entry->Type != EfiConventionalMemory) {
- continue;
- }
-
- DescStart = Entry->Start;
- DescEnd = Entry->End;
-
- //
- // If desc is past max allowed address or below min allowed address, skip it
- //
- if ((DescStart >= MaxAddress) || (DescEnd < MinAddress)) {
- continue;
- }
-
- //
- // If desc ends past max allowed address, clip the end
- //
- if (DescEnd >= MaxAddress) {
- DescEnd = MaxAddress;
- }
-
- DescEnd = ((DescEnd + 1) & (~((UINT64)Alignment - 1))) - 1;
-
- // Skip if DescEnd is less than DescStart after alignment clipping
- if (DescEnd < DescStart) {
- continue;
- }
-
- //
- // Compute the number of bytes we can used from this
- // descriptor, and see it's enough to satisfy the request
- //
- DescNumberOfBytes = DescEnd - DescStart + 1;
-
- if (DescNumberOfBytes >= NumberOfBytes) {
- //
- // If the start of the allocated range is below the min address allowed, skip it
- //
- if ((DescEnd - NumberOfBytes + 1) < MinAddress) {
- continue;
- }
-
- //
- // If this is the best match so far remember it
- //
- if (DescEnd > Target) {
- if (NeedGuard) {
- DescEnd = AdjustMemoryS (
- DescEnd + 1 - DescNumberOfBytes,
- DescNumberOfBytes,
- NumberOfBytes
- );
- if (DescEnd == 0) {
- continue;
- }
- }
-
- Target = DescEnd;
- }
- }
- }
-
- //
- // If this is a grow down, adjust target to be the allocation base
- //
- Target -= NumberOfBytes - 1;
-
- //
- // If we didn't find a match, return 0
- //
- if ((Target & EFI_PAGE_MASK) != 0) {
- return 0;
- }
-
- return Target;
-}
-
-/**
- Internal function. Finds a consecutive free page range below
- the requested address
-
- @param MaxAddress The address that the range must be below
- @param NoPages Number of pages needed
- @param NewType The type of memory the range is going to be
- turned into
- @param Alignment Bits to align with
- @param NeedGuard Flag to indicate Guard page is needed or not
-
- @return The base address of the range, or 0 if the range was not found.
-
-**/
-UINT64
-FindFreePages (
- IN UINT64 MaxAddress,
- IN UINT64 NoPages,
- IN EFI_MEMORY_TYPE NewType,
- IN UINTN Alignment,
- IN BOOLEAN NeedGuard
- )
-{
- UINT64 Start;
-
- //
- // Attempt to find free pages in the preferred bin based on the requested memory type
- //
- if (((UINT32)NewType < EfiMaxMemoryType) && (MaxAddress >= mMemoryTypeStatistics[NewType].MaximumAddress)) {
- Start = CoreFindFreePagesI (
- mMemoryTypeStatistics[NewType].MaximumAddress,
- mMemoryTypeStatistics[NewType].BaseAddress,
- NoPages,
- NewType,
- Alignment,
- NeedGuard
- );
- if (Start != 0) {
- return Start;
- }
- }
-
- //
- // Attempt to find free pages in the default allocation bin
- //
- if (MaxAddress >= mDefaultMaximumAddress) {
- Start = CoreFindFreePagesI (
- mDefaultMaximumAddress,
- 0,
- NoPages,
- NewType,
- Alignment,
- NeedGuard
- );
- if (Start != 0) {
- if (Start < mDefaultBaseAddress) {
- mDefaultBaseAddress = NeedGuard ? Start - EFI_PAGE_SIZE : Start;
- }
-
- return Start;
- }
- }
-
- //
- // The allocation did not succeed in any of the prefered bins even after
- // promoting resources. Attempt to find free pages anywhere is the requested
- // address range. If this allocation fails, then there are not enough
- // resources anywhere to satisfy the request.
- //
- Start = CoreFindFreePagesI (
- MaxAddress,
- 0,
- NoPages,
- NewType,
- Alignment,
- NeedGuard
- );
- if (Start != 0) {
- return Start;
- }
-
- //
- // If allocations from the preferred bins fail, then attempt to promote memory resources.
- //
- if (!PromoteMemoryResource ()) {
- return 0;
- }
-
- //
- // If any memory resources were promoted, then re-attempt the allocation
- //
- return FindFreePages (MaxAddress, NoPages, NewType, Alignment, NeedGuard);
-}
-
-/**
- Allocates pages from the memory map.
-
- @param Type The type of allocation to perform
- @param MemoryType The type of memory to turn the allocated pages
- into
- @param NumberOfPages The number of pages to allocate
- @param Memory A pointer to receive the base allocated memory
- address
- @param NeedGuard Flag to indicate Guard page is needed or not
-
- @return Status. On success, Memory is filled in with the base address allocated
- @retval EFI_INVALID_PARAMETER Parameters violate checking rules defined in
- spec.
- @retval EFI_NOT_FOUND Could not allocate pages match the requirement.
- @retval EFI_OUT_OF_RESOURCES No enough pages to allocate.
- @retval EFI_SUCCESS Pages successfully allocated.
-
-**/
-EFI_STATUS
-EFIAPI
-CoreInternalAllocatePages (
- IN EFI_ALLOCATE_TYPE Type,
- IN EFI_MEMORY_TYPE MemoryType,
- IN UINTN NumberOfPages,
- IN OUT EFI_PHYSICAL_ADDRESS *Memory,
- IN BOOLEAN NeedGuard
- )
-{
- EFI_STATUS Status;
- UINT64 Start;
- UINT64 NumberOfBytes;
- UINT64 End;
- UINT64 MaxAddress;
- UINTN Alignment;
- EFI_MEMORY_TYPE CheckType;
-
- if ((UINT32)Type >= MaxAllocateType) {
- return EFI_INVALID_PARAMETER;
- }
-
- if (((MemoryType >= EfiMaxMemoryType) && (MemoryType < MEMORY_TYPE_OEM_RESERVED_MIN)) ||
- (MemoryType == EfiConventionalMemory) || (MemoryType == EfiPersistentMemory) || (MemoryType == EfiUnacceptedMemoryType))
- {
- return EFI_INVALID_PARAMETER;
- }
-
- if (Memory == NULL) {
- return EFI_INVALID_PARAMETER;
- }
-
- Alignment = DEFAULT_PAGE_ALLOCATION_GRANULARITY;
-
- if ((MemoryType == EfiReservedMemoryType) ||
- (MemoryType == EfiACPIMemoryNVS) ||
- (MemoryType == EfiRuntimeServicesCode) ||
- (MemoryType == EfiRuntimeServicesData))
- {
- Alignment = RUNTIME_PAGE_ALLOCATION_GRANULARITY;
- }
-
- //
- // The heap guard system does not support non-EFI_PAGE_SIZE alignments.
- // Architectures that require larger RUNTIME_PAGE_ALLOCATION_GRANULARITY
- // will have the runtime memory regions unguarded. OSes do not
- // map guard pages anyway, so this is a minimal loss. Not guarding prevents
- // alignment mismatches
- //
- if (Alignment != EFI_PAGE_SIZE) {
- NeedGuard = FALSE;
- }
-
- if (Type == AllocateAddress) {
- if ((*Memory & (Alignment - 1)) != 0) {
- return EFI_NOT_FOUND;
- }
- }
-
- NumberOfPages += EFI_SIZE_TO_PAGES (Alignment) - 1;
- NumberOfPages &= ~(EFI_SIZE_TO_PAGES (Alignment) - 1);
-
- //
- // If this is for below a particular address, then
- //
- Start = *Memory;
-
- //
- // The max address is the max natively addressable address for the processor
- //
- MaxAddress = MAX_ALLOC_ADDRESS;
-
- //
- // Check for Type AllocateAddress,
- // if NumberOfPages is 0 or
- // if (NumberOfPages << EFI_PAGE_SHIFT) is above MAX_ALLOC_ADDRESS or
- // if (Start + NumberOfBytes) rolls over 0 or
- // if Start is above MAX_ALLOC_ADDRESS or
- // if End is above MAX_ALLOC_ADDRESS,
- // if Start..End overlaps any tracked MemoryTypeStatistics range
- // return EFI_NOT_FOUND.
- //
- if (Type == AllocateAddress) {
- if ((NumberOfPages == 0) ||
- (NumberOfPages > RShiftU64 (MaxAddress, EFI_PAGE_SHIFT)))
- {
- return EFI_NOT_FOUND;
- }
-
- NumberOfBytes = LShiftU64 (NumberOfPages, EFI_PAGE_SHIFT);
- End = Start + NumberOfBytes - 1;
-
- if ((Start >= End) ||
- (Start > MaxAddress) ||
- (End > MaxAddress))
- {
- return EFI_NOT_FOUND;
- }
-
- //
- // A driver is allowed to call AllocatePages using an AllocateAddress type. This type of
- // AllocatePage request the exact physical address if it is not used. The existing code
- // will allow this request even in 'special' pages. The problem with this is that the
- // reason to have 'special' pages for OS hibernate/resume is defeated as memory is
- // fragmented.
- //
-
- for (CheckType = (EFI_MEMORY_TYPE)0; CheckType < EfiMaxMemoryType; CheckType++) {
- if ((MemoryType != CheckType) &&
- mMemoryTypeStatistics[CheckType].Special &&
- (mMemoryTypeStatistics[CheckType].NumberOfPages > 0))
- {
- if ((Start >= mMemoryTypeStatistics[CheckType].BaseAddress) &&
- (Start <= mMemoryTypeStatistics[CheckType].MaximumAddress))
- {
- return EFI_NOT_FOUND;
- }
-
- if ((End >= mMemoryTypeStatistics[CheckType].BaseAddress) &&
- (End <= mMemoryTypeStatistics[CheckType].MaximumAddress))
- {
- return EFI_NOT_FOUND;
- }
-
- if ((Start < mMemoryTypeStatistics[CheckType].BaseAddress) &&
- (End > mMemoryTypeStatistics[CheckType].MaximumAddress))
- {
- return EFI_NOT_FOUND;
- }
- }
- }
- }
-
- if (Type == AllocateMaxAddress) {
- MaxAddress = Start;
- }
-
- CoreAcquireMemoryLock ();
-
- //
- // If not a specific address, then find an address to allocate
- //
- if (Type != AllocateAddress) {
- Start = FindFreePages (
- MaxAddress,
- NumberOfPages,
- MemoryType,
- Alignment,
- NeedGuard
- );
- if (Start == 0) {
- Status = EFI_OUT_OF_RESOURCES;
- goto Done;
- }
- }
-
- //
- // Convert pages from FreeMemory to the requested type
- //
- if (NeedGuard) {
- Status = CoreConvertPagesWithGuard (Start, NumberOfPages, MemoryType);
- } else {
- Status = CoreConvertPages (Start, NumberOfPages, MemoryType);
- }
-
- if (EFI_ERROR (Status)) {
- //
- // If requested memory region is unavailable it may be untested memory
- // Attempt to promote memory resources, then re-attempt the allocation
- //
- if (PromoteMemoryResource ()) {
- if (NeedGuard) {
- Status = CoreConvertPagesWithGuard (Start, NumberOfPages, MemoryType);
- } else {
- Status = CoreConvertPages (Start, NumberOfPages, MemoryType);
- }
- }
- }
-
-Done:
- CoreReleaseMemoryLock ();
-
- if (!EFI_ERROR (Status)) {
- if (NeedGuard) {
- SetGuardForMemory (Start, NumberOfPages);
- }
-
- *Memory = Start;
- }
-
- return Status;
-}
-
-/**
- Allocates pages from the memory map.
-
- @param Type The type of allocation to perform
- @param MemoryType The type of memory to turn the allocated pages
- into
- @param NumberOfPages The number of pages to allocate
- @param Memory A pointer to receive the base allocated memory
- address
-
- @return Status. On success, Memory is filled in with the base address allocated
- @retval EFI_INVALID_PARAMETER Parameters violate checking rules defined in
- spec.
- @retval EFI_NOT_FOUND Could not allocate pages match the requirement.
- @retval EFI_OUT_OF_RESOURCES No enough pages to allocate.
- @retval EFI_SUCCESS Pages successfully allocated.
-
-**/
-EFI_STATUS
-EFIAPI
-CoreAllocatePages (
- IN EFI_ALLOCATE_TYPE Type,
- IN EFI_MEMORY_TYPE MemoryType,
- IN UINTN NumberOfPages,
- OUT EFI_PHYSICAL_ADDRESS *Memory
- )
-{
- EFI_STATUS Status;
- BOOLEAN NeedGuard;
-
- NeedGuard = IsPageTypeToGuard (MemoryType, Type) && !mOnGuarding;
- Status = CoreInternalAllocatePages (
- Type,
- MemoryType,
- NumberOfPages,
- Memory,
- NeedGuard
- );
- if (!EFI_ERROR (Status)) {
- CoreUpdateProfile (
- (EFI_PHYSICAL_ADDRESS)(UINTN)RETURN_ADDRESS (0),
- MemoryProfileActionAllocatePages,
- MemoryType,
- EFI_PAGES_TO_SIZE (NumberOfPages),
- (VOID *)(UINTN)*Memory,
- NULL
- );
- InstallMemoryAttributesTableOnMemoryAllocation (MemoryType);
- ApplyMemoryProtectionPolicy (
- EfiConventionalMemory,
- MemoryType,
- *Memory,
- EFI_PAGES_TO_SIZE (NumberOfPages)
- );
- }
-
- return Status;
-}
-
-/**
- Frees previous allocated pages.
-
- @param Memory Base address of memory being freed
- @param NumberOfPages The number of pages to free
- @param MemoryType Pointer to memory type
-
- @retval EFI_NOT_FOUND Could not find the entry that covers the range
- @retval EFI_INVALID_PARAMETER Address not aligned
- @return EFI_SUCCESS -Pages successfully freed.
-
-**/
-EFI_STATUS
-EFIAPI
-CoreInternalFreePages (
- IN EFI_PHYSICAL_ADDRESS Memory,
- IN UINTN NumberOfPages,
- OUT EFI_MEMORY_TYPE *MemoryType OPTIONAL
- )
-{
- EFI_STATUS Status;
- LIST_ENTRY *Link;
- MEMORY_MAP *Entry;
- UINTN Alignment;
- BOOLEAN IsGuarded;
-
- //
- // Free the range
- //
- CoreAcquireMemoryLock ();
-
- //
- // Find the entry that the covers the range
- //
- IsGuarded = FALSE;
- Entry = NULL;
- for (Link = gMemoryMap.ForwardLink; Link != &gMemoryMap; Link = Link->ForwardLink) {
- Entry = CR (Link, MEMORY_MAP, Link, MEMORY_MAP_SIGNATURE);
- if ((Entry->Start <= Memory) && (Entry->End > Memory)) {
- break;
- }
- }
-
- if (Link == &gMemoryMap) {
- Status = EFI_NOT_FOUND;
- goto Done;
- }
-
- if (Entry == NULL) {
- ASSERT (Entry != NULL);
- Status = EFI_NOT_FOUND;
- goto Done;
- }
-
- Alignment = DEFAULT_PAGE_ALLOCATION_GRANULARITY;
-
- if ((Entry->Type == EfiReservedMemoryType) ||
- (Entry->Type == EfiACPIMemoryNVS) ||
- (Entry->Type == EfiRuntimeServicesCode) ||
- (Entry->Type == EfiRuntimeServicesData))
- {
- Alignment = RUNTIME_PAGE_ALLOCATION_GRANULARITY;
- }
-
- if ((Memory & (Alignment - 1)) != 0) {
- Status = EFI_INVALID_PARAMETER;
- goto Done;
- }
-
- NumberOfPages += EFI_SIZE_TO_PAGES (Alignment) - 1;
- NumberOfPages &= ~(EFI_SIZE_TO_PAGES (Alignment) - 1);
-
- if (MemoryType != NULL) {
- *MemoryType = Entry->Type;
- }
-
- IsGuarded = IsPageTypeToGuard (Entry->Type, AllocateAnyPages) &&
- IsMemoryGuarded (Memory);
- if (IsGuarded) {
- Status = CoreConvertPagesWithGuard (
- Memory,
- NumberOfPages,
- EfiConventionalMemory
- );
- } else {
- Status = CoreConvertPages (Memory, NumberOfPages, EfiConventionalMemory);
- }
-
-Done:
- CoreReleaseMemoryLock ();
- return Status;
-}
-
-/**
- Frees previous allocated pages.
-
- @param Memory Base address of memory being freed
- @param NumberOfPages The number of pages to free
-
- @retval EFI_NOT_FOUND Could not find the entry that covers the range
- @retval EFI_INVALID_PARAMETER Address not aligned
- @return EFI_SUCCESS -Pages successfully freed.
-
-**/
-EFI_STATUS
-EFIAPI
-CoreFreePages (
- IN EFI_PHYSICAL_ADDRESS Memory,
- IN UINTN NumberOfPages
- )
-{
- EFI_STATUS Status;
- EFI_MEMORY_TYPE MemoryType;
-
- Status = CoreInternalFreePages (Memory, NumberOfPages, &MemoryType);
- if (!EFI_ERROR (Status)) {
- GuardFreedPagesChecked (Memory, NumberOfPages);
- CoreUpdateProfile (
- (EFI_PHYSICAL_ADDRESS)(UINTN)RETURN_ADDRESS (0),
- MemoryProfileActionFreePages,
- MemoryType,
- EFI_PAGES_TO_SIZE (NumberOfPages),
- (VOID *)(UINTN)Memory,
- NULL
- );
- InstallMemoryAttributesTableOnMemoryAllocation (MemoryType);
- ApplyMemoryProtectionPolicy (
- MemoryType,
- EfiConventionalMemory,
- Memory,
- EFI_PAGES_TO_SIZE (NumberOfPages)
- );
- }
-
- return Status;
-}
-
-/**
- This function checks to see if the last memory map descriptor in a memory map
- can be merged with any of the other memory map descriptors in a memorymap.
- Memory descriptors may be merged if they are adjacent and have the same type
- and attributes.
-
- @param MemoryMap A pointer to the start of the memory map.
- @param MemoryMapDescriptor A pointer to the last descriptor in MemoryMap.
- @param DescriptorSize The size, in bytes, of an individual
- EFI_MEMORY_DESCRIPTOR.
-
- @return A pointer to the next available descriptor in MemoryMap
-
-**/
-EFI_MEMORY_DESCRIPTOR *
-MergeMemoryMapDescriptor (
- IN EFI_MEMORY_DESCRIPTOR *MemoryMap,
- IN EFI_MEMORY_DESCRIPTOR *MemoryMapDescriptor,
- IN UINTN DescriptorSize
- )
-{
- //
- // Traverse the array of descriptors in MemoryMap
- //
- for ( ; MemoryMap != MemoryMapDescriptor; MemoryMap = NEXT_MEMORY_DESCRIPTOR (MemoryMap, DescriptorSize)) {
- //
- // Check to see if the Type fields are identical.
- //
- if (MemoryMap->Type != MemoryMapDescriptor->Type) {
- continue;
- }
-
- //
- // Check to see if the Attribute fields are identical.
- //
- if (MemoryMap->Attribute != MemoryMapDescriptor->Attribute) {
- continue;
- }
-
- //
- // Check to see if MemoryMapDescriptor is immediately above MemoryMap
- //
- if (MemoryMap->PhysicalStart + EFI_PAGES_TO_SIZE ((UINTN)MemoryMap->NumberOfPages) == MemoryMapDescriptor->PhysicalStart) {
- //
- // Merge MemoryMapDescriptor into MemoryMap
- //
- MemoryMap->NumberOfPages += MemoryMapDescriptor->NumberOfPages;
-
- //
- // Return MemoryMapDescriptor as the next available slot int he MemoryMap array
- //
- return MemoryMapDescriptor;
- }
-
- //
- // Check to see if MemoryMapDescriptor is immediately below MemoryMap
- //
- if (MemoryMap->PhysicalStart - EFI_PAGES_TO_SIZE ((UINTN)MemoryMapDescriptor->NumberOfPages) == MemoryMapDescriptor->PhysicalStart) {
- //
- // Merge MemoryMapDescriptor into MemoryMap
- //
- MemoryMap->PhysicalStart = MemoryMapDescriptor->PhysicalStart;
- MemoryMap->VirtualStart = MemoryMapDescriptor->VirtualStart;
- MemoryMap->NumberOfPages += MemoryMapDescriptor->NumberOfPages;
-
- //
- // Return MemoryMapDescriptor as the next available slot int he MemoryMap array
- //
- return MemoryMapDescriptor;
- }
- }
-
- //
- // MemoryMapDescrtiptor could not be merged with any descriptors in MemoryMap.
- //
- // Return the slot immediately after MemoryMapDescriptor as the next available
- // slot in the MemoryMap array
- //
- return NEXT_MEMORY_DESCRIPTOR (MemoryMapDescriptor, DescriptorSize);
-}
-
-/**
- This function returns a copy of the current memory map. The map is an array of
- memory descriptors, each of which describes a contiguous block of memory.
-
- @param MemoryMapSize A pointer to the size, in bytes, of the
- MemoryMap buffer. On input, this is the size of
- the buffer allocated by the caller. On output,
- it is the size of the buffer returned by the
- firmware if the buffer was large enough, or the
- size of the buffer needed to contain the map if
- the buffer was too small.
- @param MemoryMap A pointer to the buffer in which firmware places
- the current memory map.
- @param MapKey A pointer to the location in which firmware
- returns the key for the current memory map.
- @param DescriptorSize A pointer to the location in which firmware
- returns the size, in bytes, of an individual
- EFI_MEMORY_DESCRIPTOR.
- @param DescriptorVersion A pointer to the location in which firmware
- returns the version number associated with the
- EFI_MEMORY_DESCRIPTOR.
-
- @retval EFI_SUCCESS The memory map was returned in the MemoryMap
- buffer.
- @retval EFI_BUFFER_TOO_SMALL The MemoryMap buffer was too small. The current
- buffer size needed to hold the memory map is
- returned in MemoryMapSize.
- @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
-
-**/
-EFI_STATUS
-EFIAPI
-CoreGetMemoryMap (
- IN OUT UINTN *MemoryMapSize,
- IN OUT EFI_MEMORY_DESCRIPTOR *MemoryMap,
- OUT UINTN *MapKey,
- OUT UINTN *DescriptorSize,
- OUT UINT32 *DescriptorVersion
- )
-{
- EFI_STATUS Status;
- UINTN Size;
- UINTN BufferSize;
- UINTN NumberOfEntries;
- LIST_ENTRY *Link;
- MEMORY_MAP *Entry;
- EFI_GCD_MAP_ENTRY *GcdMapEntry;
- EFI_GCD_MAP_ENTRY MergeGcdMapEntry;
- EFI_MEMORY_TYPE Type;
- EFI_MEMORY_DESCRIPTOR *MemoryMapStart;
- EFI_MEMORY_DESCRIPTOR *MemoryMapEnd;
-
- //
- // Make sure the parameters are valid
- //
- if (MemoryMapSize == NULL) {
- return EFI_INVALID_PARAMETER;
- }
-
- CoreAcquireGcdMemoryLock ();
-
- //
- // Count the number of Reserved and runtime MMIO entries
- // And, count the number of Persistent entries.
- //
- NumberOfEntries = 0;
- for (Link = mGcdMemorySpaceMap.ForwardLink; Link != &mGcdMemorySpaceMap; Link = Link->ForwardLink) {
- GcdMapEntry = CR (Link, EFI_GCD_MAP_ENTRY, Link, EFI_GCD_MAP_SIGNATURE);
- if ((GcdMapEntry->GcdMemoryType == EfiGcdMemoryTypePersistent) ||
- (GcdMapEntry->GcdMemoryType == EfiGcdMemoryTypeReserved) ||
- ((GcdMapEntry->GcdMemoryType == EfiGcdMemoryTypeMemoryMappedIo) &&
- ((GcdMapEntry->Attributes & EFI_MEMORY_RUNTIME) == EFI_MEMORY_RUNTIME)))
- {
- NumberOfEntries++;
- }
- }
-
- Size = sizeof (EFI_MEMORY_DESCRIPTOR);
-
- //
- // Make sure Size != sizeof(EFI_MEMORY_DESCRIPTOR). This will
- // prevent people from having pointer math bugs in their code.
- // now you have to use *DescriptorSize to make things work.
- //
- Size += sizeof (UINT64) - (Size % sizeof (UINT64));
-
- if (DescriptorSize != NULL) {
- *DescriptorSize = Size;
- }
-
- if (DescriptorVersion != NULL) {
- *DescriptorVersion = EFI_MEMORY_DESCRIPTOR_VERSION;
- }
-
- CoreAcquireMemoryLock ();
-
- //
- // Compute the buffer size needed to fit the entire map
- //
- BufferSize = Size * NumberOfEntries;
- for (Link = gMemoryMap.ForwardLink; Link != &gMemoryMap; Link = Link->ForwardLink) {
- BufferSize += Size;
- }
-
- if (*MemoryMapSize < BufferSize) {
- Status = EFI_BUFFER_TOO_SMALL;
- goto Done;
- }
-
- if (MemoryMap == NULL) {
- Status = EFI_INVALID_PARAMETER;
- goto Done;
- }
-
- //
- // Build the map
- //
- ZeroMem (MemoryMap, BufferSize);
- MemoryMapStart = MemoryMap;
- for (Link = gMemoryMap.ForwardLink; Link != &gMemoryMap; Link = Link->ForwardLink) {
- Entry = CR (Link, MEMORY_MAP, Link, MEMORY_MAP_SIGNATURE);
- ASSERT (Entry->VirtualStart == 0);
-
- //
- // Convert internal map into an EFI_MEMORY_DESCRIPTOR
- //
- MemoryMap->Type = Entry->Type;
- MemoryMap->PhysicalStart = Entry->Start;
- MemoryMap->VirtualStart = Entry->VirtualStart;
- MemoryMap->NumberOfPages = RShiftU64 (Entry->End - Entry->Start + 1, EFI_PAGE_SHIFT);
- //
- // If the memory type is EfiConventionalMemory, then determine if the range is part of a
- // memory type bin and needs to be converted to the same memory type as the rest of the
- // memory type bin in order to minimize EFI Memory Map changes across reboots. This
- // improves the chances for a successful S4 resume in the presence of minor page allocation
- // differences across reboots.
- //
- if (MemoryMap->Type == EfiConventionalMemory) {
- for (Type = (EFI_MEMORY_TYPE)0; Type < EfiMaxMemoryType; Type++) {
- if (mMemoryTypeStatistics[Type].Special &&
- (mMemoryTypeStatistics[Type].NumberOfPages > 0) &&
- (Entry->Start >= mMemoryTypeStatistics[Type].BaseAddress) &&
- (Entry->End <= mMemoryTypeStatistics[Type].MaximumAddress))
- {
- MemoryMap->Type = Type;
- }
- }
- }
-
- MemoryMap->Attribute = Entry->Attribute;
- if (MemoryMap->Type < EfiMaxMemoryType) {
- if (mMemoryTypeStatistics[MemoryMap->Type].Runtime) {
- MemoryMap->Attribute |= EFI_MEMORY_RUNTIME;
- }
- }
-
- //
- // Check to see if the new Memory Map Descriptor can be merged with an
- // existing descriptor if they are adjacent and have the same attributes
- //
- MemoryMap = MergeMemoryMapDescriptor (MemoryMapStart, MemoryMap, Size);
- }
-
- ZeroMem (&MergeGcdMapEntry, sizeof (MergeGcdMapEntry));
- GcdMapEntry = NULL;
- for (Link = mGcdMemorySpaceMap.ForwardLink; ; Link = Link->ForwardLink) {
- if (Link != &mGcdMemorySpaceMap) {
- //
- // Merge adjacent same type and attribute GCD memory range
- //
- GcdMapEntry = CR (Link, EFI_GCD_MAP_ENTRY, Link, EFI_GCD_MAP_SIGNATURE);
-
- if ((MergeGcdMapEntry.Capabilities == GcdMapEntry->Capabilities) &&
- (MergeGcdMapEntry.Attributes == GcdMapEntry->Attributes) &&
- (MergeGcdMapEntry.GcdMemoryType == GcdMapEntry->GcdMemoryType) &&
- (MergeGcdMapEntry.GcdIoType == GcdMapEntry->GcdIoType))
- {
- MergeGcdMapEntry.EndAddress = GcdMapEntry->EndAddress;
- continue;
- }
- }
-
- if ((MergeGcdMapEntry.GcdMemoryType == EfiGcdMemoryTypeReserved) ||
- ((MergeGcdMapEntry.GcdMemoryType == EfiGcdMemoryTypeMemoryMappedIo) &&
- ((MergeGcdMapEntry.Attributes & EFI_MEMORY_RUNTIME) == EFI_MEMORY_RUNTIME)))
- {
- //
- // Page Align GCD range is required. When it is converted to EFI_MEMORY_DESCRIPTOR,
- // it will be recorded as page PhysicalStart and NumberOfPages.
- //
- ASSERT ((MergeGcdMapEntry.BaseAddress & EFI_PAGE_MASK) == 0);
- ASSERT (((MergeGcdMapEntry.EndAddress - MergeGcdMapEntry.BaseAddress + 1) & EFI_PAGE_MASK) == 0);
-
- //
- // Create EFI_MEMORY_DESCRIPTOR for every Reserved and runtime MMIO GCD entries
- //
- MemoryMap->PhysicalStart = MergeGcdMapEntry.BaseAddress;
- MemoryMap->VirtualStart = 0;
- MemoryMap->NumberOfPages = RShiftU64 ((MergeGcdMapEntry.EndAddress - MergeGcdMapEntry.BaseAddress + 1), EFI_PAGE_SHIFT);
- MemoryMap->Attribute = (MergeGcdMapEntry.Attributes & ~EFI_MEMORY_PORT_IO) |
- (MergeGcdMapEntry.Capabilities & (EFI_CACHE_ATTRIBUTE_MASK | EFI_MEMORY_ATTRIBUTE_MASK));
-
- if (MergeGcdMapEntry.GcdMemoryType == EfiGcdMemoryTypeReserved) {
- MemoryMap->Type = EfiReservedMemoryType;
- } else if (MergeGcdMapEntry.GcdMemoryType == EfiGcdMemoryTypeMemoryMappedIo) {
- if ((MergeGcdMapEntry.Attributes & EFI_MEMORY_PORT_IO) == EFI_MEMORY_PORT_IO) {
- MemoryMap->Type = EfiMemoryMappedIOPortSpace;
- } else {
- MemoryMap->Type = EfiMemoryMappedIO;
- }
- }
-
- //
- // Check to see if the new Memory Map Descriptor can be merged with an
- // existing descriptor if they are adjacent and have the same attributes
- //
- MemoryMap = MergeMemoryMapDescriptor (MemoryMapStart, MemoryMap, Size);
- }
-
- if (MergeGcdMapEntry.GcdMemoryType == EfiGcdMemoryTypePersistent) {
- //
- // Page Align GCD range is required. When it is converted to EFI_MEMORY_DESCRIPTOR,
- // it will be recorded as page PhysicalStart and NumberOfPages.
- //
- ASSERT ((MergeGcdMapEntry.BaseAddress & EFI_PAGE_MASK) == 0);
- ASSERT (((MergeGcdMapEntry.EndAddress - MergeGcdMapEntry.BaseAddress + 1) & EFI_PAGE_MASK) == 0);
-
- //
- // Create EFI_MEMORY_DESCRIPTOR for every Persistent GCD entries
- //
- MemoryMap->PhysicalStart = MergeGcdMapEntry.BaseAddress;
- MemoryMap->VirtualStart = 0;
- MemoryMap->NumberOfPages = RShiftU64 ((MergeGcdMapEntry.EndAddress - MergeGcdMapEntry.BaseAddress + 1), EFI_PAGE_SHIFT);
- MemoryMap->Attribute = MergeGcdMapEntry.Attributes | EFI_MEMORY_NV |
- (MergeGcdMapEntry.Capabilities & (EFI_CACHE_ATTRIBUTE_MASK | EFI_MEMORY_ATTRIBUTE_MASK));
- MemoryMap->Type = EfiPersistentMemory;
-
- //
- // Check to see if the new Memory Map Descriptor can be merged with an
- // existing descriptor if they are adjacent and have the same attributes
- //
- MemoryMap = MergeMemoryMapDescriptor (MemoryMapStart, MemoryMap, Size);
- }
-
- if (MergeGcdMapEntry.GcdMemoryType == EfiGcdMemoryTypeUnaccepted) {
- //
- // Page Align GCD range is required. When it is converted to EFI_MEMORY_DESCRIPTOR,
- // it will be recorded as page PhysicalStart and NumberOfPages.
- //
- ASSERT ((MergeGcdMapEntry.BaseAddress & EFI_PAGE_MASK) == 0);
- ASSERT (((MergeGcdMapEntry.EndAddress - MergeGcdMapEntry.BaseAddress + 1) & EFI_PAGE_MASK) == 0);
-
- //
- // Create EFI_MEMORY_DESCRIPTOR for every Unaccepted GCD entries
- //
- MemoryMap->PhysicalStart = MergeGcdMapEntry.BaseAddress;
- MemoryMap->VirtualStart = 0;
- MemoryMap->NumberOfPages = RShiftU64 ((MergeGcdMapEntry.EndAddress - MergeGcdMapEntry.BaseAddress + 1), EFI_PAGE_SHIFT);
- MemoryMap->Attribute = MergeGcdMapEntry.Attributes |
- (MergeGcdMapEntry.Capabilities & (EFI_MEMORY_RP | EFI_MEMORY_WP | EFI_MEMORY_XP | EFI_MEMORY_RO |
- EFI_MEMORY_UC | EFI_MEMORY_UCE | EFI_MEMORY_WC | EFI_MEMORY_WT | EFI_MEMORY_WB));
- MemoryMap->Type = EfiUnacceptedMemoryType;
-
- //
- // Check to see if the new Memory Map Descriptor can be merged with an
- // existing descriptor if they are adjacent and have the same attributes
- //
- MemoryMap = MergeMemoryMapDescriptor (MemoryMapStart, MemoryMap, Size);
- }
-
- if (Link == &mGcdMemorySpaceMap) {
- //
- // break loop when arrive at head.
- //
- break;
- }
-
- if (GcdMapEntry != NULL) {
- //
- // Copy new GCD map entry for the following GCD range merge
- //
- CopyMem (&MergeGcdMapEntry, GcdMapEntry, sizeof (MergeGcdMapEntry));
- }
- }
-
- //
- // Compute the size of the buffer actually used after all memory map descriptor merge operations
- //
- BufferSize = ((UINT8 *)MemoryMap - (UINT8 *)MemoryMapStart);
-
- //
- // Note: Some OSs will treat EFI_MEMORY_DESCRIPTOR.Attribute as really
- // set attributes and change memory paging attribute accordingly.
- // But current EFI_MEMORY_DESCRIPTOR.Attribute is assigned by
- // value from Capabilities in GCD memory map. This might cause
- // boot problems. Clearing all page-access permission related
- // capabilities can workaround it. Following code is supposed to
- // be removed once the usage of EFI_MEMORY_DESCRIPTOR.Attribute
- // is clarified in UEFI spec and adopted by both EDK-II Core and
- // all supported OSs.
- //
- MemoryMapEnd = MemoryMap;
- MemoryMap = MemoryMapStart;
- while (MemoryMap < MemoryMapEnd) {
- MemoryMap->Attribute &= ~(UINT64)EFI_MEMORY_ACCESS_MASK;
- MemoryMap = NEXT_MEMORY_DESCRIPTOR (MemoryMap, Size);
- }
-
- MergeMemoryMap (MemoryMapStart, &BufferSize, Size);
- MemoryMapEnd = (EFI_MEMORY_DESCRIPTOR *)((UINT8 *)MemoryMapStart + BufferSize);
-
- Status = EFI_SUCCESS;
-
-Done:
- //
- // Update the map key finally
- //
- if (MapKey != NULL) {
- *MapKey = mMemoryMapKey;
- }
-
- CoreReleaseMemoryLock ();
-
- CoreReleaseGcdMemoryLock ();
-
- *MemoryMapSize = BufferSize;
-
- DEBUG_CODE (
- DumpGuardedMemoryBitmap ();
- );
-
- return Status;
-}
-
-/**
- Internal function. Used by the pool functions to allocate pages
- to back pool allocation requests.
-
- @param PoolType The type of memory for the new pool pages
- @param NumberOfPages No of pages to allocate
- @param Alignment Bits to align.
- @param NeedGuard Flag to indicate Guard page is needed or not
-
- @return The allocated memory, or NULL
-
-**/
-VOID *
-CoreAllocatePoolPages (
- IN EFI_MEMORY_TYPE PoolType,
- IN UINTN NumberOfPages,
- IN UINTN Alignment,
- IN BOOLEAN NeedGuard
- )
-{
- UINT64 Start;
-
- //
- // Find the pages to convert
- //
- Start = FindFreePages (
- MAX_ALLOC_ADDRESS,
- NumberOfPages,
- PoolType,
- Alignment,
- NeedGuard
- );
-
- //
- // Convert it to boot services data
- //
- if (Start == 0) {
- DEBUG ((DEBUG_ERROR | DEBUG_PAGE, "AllocatePoolPages: failed to allocate %d pages\n", (UINT32)NumberOfPages));
- } else {
- if (NeedGuard) {
- CoreConvertPagesWithGuard (Start, NumberOfPages, PoolType);
- } else {
- CoreConvertPages (Start, NumberOfPages, PoolType);
- }
- }
-
- return (VOID *)(UINTN)Start;
-}
-
-/**
- Internal function. Frees pool pages allocated via AllocatePoolPages ()
-
- @param Memory The base address to free
- @param NumberOfPages The number of pages to free
-
-**/
-VOID
-CoreFreePoolPages (
- IN EFI_PHYSICAL_ADDRESS Memory,
- IN UINTN NumberOfPages
- )
-{
- CoreConvertPages (Memory, NumberOfPages, EfiConventionalMemory);
-}
-
-/**
- Make sure the memory map is following all the construction rules,
- it is the last time to check memory map error before exit boot services.
-
- @param MapKey Memory map key
-
- @retval EFI_INVALID_PARAMETER Memory map not consistent with construction
- rules.
- @retval EFI_SUCCESS Valid memory map.
-
-**/
-EFI_STATUS
-CoreTerminateMemoryMap (
- IN UINTN MapKey
- )
-{
- EFI_STATUS Status;
- LIST_ENTRY *Link;
- MEMORY_MAP *Entry;
-
- Status = EFI_SUCCESS;
-
- CoreAcquireMemoryLock ();
-
- if (MapKey == mMemoryMapKey) {
- //
- // Make sure the memory map is following all the construction rules
- // This is the last chance we will be able to display any messages on
- // the console devices.
- //
-
- for (Link = gMemoryMap.ForwardLink; Link != &gMemoryMap; Link = Link->ForwardLink) {
- Entry = CR (Link, MEMORY_MAP, Link, MEMORY_MAP_SIGNATURE);
- if (Entry->Type < EfiMaxMemoryType) {
- if (mMemoryTypeStatistics[Entry->Type].Runtime) {
- ASSERT (Entry->Type != EfiACPIReclaimMemory);
- ASSERT (Entry->Type != EfiACPIMemoryNVS);
- if ((Entry->Start & (RUNTIME_PAGE_ALLOCATION_GRANULARITY - 1)) != 0) {
- DEBUG ((DEBUG_ERROR | DEBUG_PAGE, "ExitBootServices: A RUNTIME memory entry is not on a proper alignment.\n"));
- Status = EFI_INVALID_PARAMETER;
- goto Done;
- }
-
- if (((Entry->End + 1) & (RUNTIME_PAGE_ALLOCATION_GRANULARITY - 1)) != 0) {
- DEBUG ((DEBUG_ERROR | DEBUG_PAGE, "ExitBootServices: A RUNTIME memory entry is not on a proper alignment.\n"));
- Status = EFI_INVALID_PARAMETER;
- goto Done;
- }
- }
- }
- }
-
- //
- // The map key they gave us matches what we expect. Fall through and
- // return success. In an ideal world we would clear out all of
- // EfiBootServicesCode and EfiBootServicesData. However this function
- // is not the last one called by ExitBootServices(), so we have to
- // preserve the memory contents.
- //
- } else {
- Status = EFI_INVALID_PARAMETER;
- }
-
-Done:
- CoreReleaseMemoryLock ();
-
- return Status;
-}
+/** @file
+ UEFI Memory page management functions.
+
+Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "DxeMain.h"
+#include "Imem.h"
+#include "HeapGuard.h"
+#include <Pi/PiDxeCis.h>
+
+//
+// Entry for tracking the memory regions for each memory type to coalesce similar memory types
+//
+typedef struct {
+ EFI_PHYSICAL_ADDRESS BaseAddress;
+ EFI_PHYSICAL_ADDRESS MaximumAddress;
+ UINT64 CurrentNumberOfPages;
+ UINT64 NumberOfPages;
+ UINTN InformationIndex;
+ BOOLEAN Special;
+ BOOLEAN Runtime;
+} EFI_MEMORY_TYPE_STATISTICS;
+
+//
+// MemoryMap - The current memory map
+//
+UINTN mMemoryMapKey = 0;
+
+#define MAX_MAP_DEPTH 6
+
+///
+/// mMapDepth - depth of new descriptor stack
+///
+UINTN mMapDepth = 0;
+///
+/// mMapStack - space to use as temp storage to build new map descriptors
+///
+MEMORY_MAP mMapStack[MAX_MAP_DEPTH];
+UINTN mFreeMapStack = 0;
+///
+/// This list maintain the free memory map list
+///
+LIST_ENTRY mFreeMemoryMapEntryList = INITIALIZE_LIST_HEAD_VARIABLE (mFreeMemoryMapEntryList);
+BOOLEAN mMemoryTypeInformationInitialized = FALSE;
+
+EFI_MEMORY_TYPE_STATISTICS mMemoryTypeStatistics[EfiMaxMemoryType + 1] = {
+ { 0, MAX_ALLOC_ADDRESS, 0, 0, EfiMaxMemoryType, TRUE, FALSE }, // EfiReservedMemoryType
+ { 0, MAX_ALLOC_ADDRESS, 0, 0, EfiMaxMemoryType, FALSE, FALSE }, // EfiLoaderCode
+ { 0, MAX_ALLOC_ADDRESS, 0, 0, EfiMaxMemoryType, FALSE, FALSE }, // EfiLoaderData
+ { 0, MAX_ALLOC_ADDRESS, 0, 0, EfiMaxMemoryType, FALSE, FALSE }, // EfiBootServicesCode
+ { 0, MAX_ALLOC_ADDRESS, 0, 0, EfiMaxMemoryType, FALSE, FALSE }, // EfiBootServicesData
+ { 0, MAX_ALLOC_ADDRESS, 0, 0, EfiMaxMemoryType, TRUE, TRUE }, // EfiRuntimeServicesCode
+ { 0, MAX_ALLOC_ADDRESS, 0, 0, EfiMaxMemoryType, TRUE, TRUE }, // EfiRuntimeServicesData
+ { 0, MAX_ALLOC_ADDRESS, 0, 0, EfiMaxMemoryType, FALSE, FALSE }, // EfiConventionalMemory
+ { 0, MAX_ALLOC_ADDRESS, 0, 0, EfiMaxMemoryType, FALSE, FALSE }, // EfiUnusableMemory
+ { 0, MAX_ALLOC_ADDRESS, 0, 0, EfiMaxMemoryType, TRUE, FALSE }, // EfiACPIReclaimMemory
+ { 0, MAX_ALLOC_ADDRESS, 0, 0, EfiMaxMemoryType, TRUE, FALSE }, // EfiACPIMemoryNVS
+ { 0, MAX_ALLOC_ADDRESS, 0, 0, EfiMaxMemoryType, FALSE, FALSE }, // EfiMemoryMappedIO
+ { 0, MAX_ALLOC_ADDRESS, 0, 0, EfiMaxMemoryType, FALSE, FALSE }, // EfiMemoryMappedIOPortSpace
+ { 0, MAX_ALLOC_ADDRESS, 0, 0, EfiMaxMemoryType, TRUE, TRUE }, // EfiPalCode
+ { 0, MAX_ALLOC_ADDRESS, 0, 0, EfiMaxMemoryType, FALSE, FALSE }, // EfiPersistentMemory
+ { 0, MAX_ALLOC_ADDRESS, 0, 0, EfiMaxMemoryType, TRUE, FALSE }, // EfiUnacceptedMemoryType
+ { 0, MAX_ALLOC_ADDRESS, 0, 0, EfiMaxMemoryType, FALSE, FALSE } // EfiMaxMemoryType
+};
+
+EFI_PHYSICAL_ADDRESS mDefaultMaximumAddress = MAX_ALLOC_ADDRESS;
+EFI_PHYSICAL_ADDRESS mDefaultBaseAddress = MAX_ALLOC_ADDRESS;
+
+EFI_MEMORY_TYPE_INFORMATION gMemoryTypeInformation[EfiMaxMemoryType + 1] = {
+ { EfiReservedMemoryType, 0 },
+ { EfiLoaderCode, 0 },
+ { EfiLoaderData, 0 },
+ { EfiBootServicesCode, 0 },
+ { EfiBootServicesData, 0 },
+ { EfiRuntimeServicesCode, 0 },
+ { EfiRuntimeServicesData, 0 },
+ { EfiConventionalMemory, 0 },
+ { EfiUnusableMemory, 0 },
+ { EfiACPIReclaimMemory, 0 },
+ { EfiACPIMemoryNVS, 0 },
+ { EfiMemoryMappedIO, 0 },
+ { EfiMemoryMappedIOPortSpace, 0 },
+ { EfiPalCode, 0 },
+ { EfiPersistentMemory, 0 },
+ { EfiGcdMemoryTypeUnaccepted, 0 },
+ { EfiMaxMemoryType, 0 }
+};
+//
+// Only used when load module at fixed address feature is enabled. True means the memory is alreay successfully allocated
+// and ready to load the module in to specified address.or else, the memory is not ready and module will be loaded at a
+// address assigned by DXE core.
+//
+GLOBAL_REMOVE_IF_UNREFERENCED BOOLEAN gLoadFixedAddressCodeMemoryReady = FALSE;
+
+/**
+ Enter critical section by gaining lock on gMemoryLock.
+
+**/
+VOID
+CoreAcquireMemoryLock (
+ VOID
+ )
+{
+ CoreAcquireLock (&gMemoryLock);
+}
+
+/**
+ Exit critical section by releasing lock on gMemoryLock.
+
+**/
+VOID
+CoreReleaseMemoryLock (
+ VOID
+ )
+{
+ CoreReleaseLock (&gMemoryLock);
+}
+
+/**
+ Internal function. Removes a descriptor entry.
+
+ @param Entry The entry to remove
+
+**/
+VOID
+RemoveMemoryMapEntry (
+ IN OUT MEMORY_MAP *Entry
+ )
+{
+ RemoveEntryList (&Entry->Link);
+ Entry->Link.ForwardLink = NULL;
+
+ if (Entry->FromPages) {
+ //
+ // Insert the free memory map descriptor to the end of mFreeMemoryMapEntryList
+ //
+ InsertTailList (&mFreeMemoryMapEntryList, &Entry->Link);
+ }
+}
+
+/**
+ Internal function. Adds a ranges to the memory map.
+ The range must not already exist in the map.
+
+ @param Type The type of memory range to add
+ @param Start The starting address in the memory range Must be
+ paged aligned
+ @param End The last address in the range Must be the last
+ byte of a page
+ @param Attribute The attributes of the memory range to add
+
+**/
+VOID
+CoreAddRange (
+ IN EFI_MEMORY_TYPE Type,
+ IN EFI_PHYSICAL_ADDRESS Start,
+ IN EFI_PHYSICAL_ADDRESS End,
+ IN UINT64 Attribute
+ )
+{
+ LIST_ENTRY *Link;
+ MEMORY_MAP *Entry;
+
+ ASSERT ((Start & EFI_PAGE_MASK) == 0);
+ ASSERT (End > Start);
+
+ ASSERT_LOCKED (&gMemoryLock);
+
+ DEBUG ((DEBUG_PAGE, "AddRange: %lx-%lx to %d\n", Start, End, Type));
+
+ //
+ // If memory of type EfiConventionalMemory is being added that includes the page
+ // starting at address 0, then zero the page starting at address 0. This has
+ // two benifits. It helps find NULL pointer bugs and it also maximizes
+ // compatibility with operating systems that may evaluate memory in this page
+ // for legacy data structures. If memory of any other type is added starting
+ // at address 0, then do not zero the page at address 0 because the page is being
+ // used for other purposes.
+ //
+ if ((Type == EfiConventionalMemory) && (Start == 0) && (End >= EFI_PAGE_SIZE - 1)) {
+ if ((PcdGet8 (PcdNullPointerDetectionPropertyMask) & BIT0) == 0) {
+ SetMem ((VOID *)(UINTN)Start, EFI_PAGE_SIZE, 0);
+ }
+ }
+
+ //
+ // Memory map being altered so updated key
+ //
+ mMemoryMapKey += 1;
+
+ //
+ // UEFI 2.0 added an event group for notificaiton on memory map changes.
+ // So we need to signal this Event Group every time the memory map changes.
+ // If we are in EFI 1.10 compatability mode no event groups will be
+ // found and nothing will happen we we call this function. These events
+ // will get signaled but since a lock is held around the call to this
+ // function the notificaiton events will only be called after this function
+ // returns and the lock is released.
+ //
+ CoreNotifySignalList (&gEfiEventMemoryMapChangeGuid);
+
+ //
+ // Look for adjoining memory descriptor
+ //
+
+ // Two memory descriptors can only be merged if they have the same Type
+ // and the same Attribute
+ //
+
+ Link = gMemoryMap.ForwardLink;
+ while (Link != &gMemoryMap) {
+ Entry = CR (Link, MEMORY_MAP, Link, MEMORY_MAP_SIGNATURE);
+ Link = Link->ForwardLink;
+
+ if (Entry->Type != Type) {
+ continue;
+ }
+
+ if (Entry->Attribute != Attribute) {
+ continue;
+ }
+
+ if (Entry->End + 1 == Start) {
+ Start = Entry->Start;
+ RemoveMemoryMapEntry (Entry);
+ } else if (Entry->Start == End + 1) {
+ End = Entry->End;
+ RemoveMemoryMapEntry (Entry);
+ }
+ }
+
+ //
+ // Add descriptor
+ //
+
+ mMapStack[mMapDepth].Signature = MEMORY_MAP_SIGNATURE;
+ mMapStack[mMapDepth].FromPages = FALSE;
+ mMapStack[mMapDepth].Type = Type;
+ mMapStack[mMapDepth].Start = Start;
+ mMapStack[mMapDepth].End = End;
+ mMapStack[mMapDepth].VirtualStart = 0;
+ mMapStack[mMapDepth].Attribute = Attribute;
+ InsertTailList (&gMemoryMap, &mMapStack[mMapDepth].Link);
+
+ mMapDepth += 1;
+ ASSERT (mMapDepth < MAX_MAP_DEPTH);
+
+ return;
+}
+
+/**
+ Internal function. Deque a descriptor entry from the mFreeMemoryMapEntryList.
+ If the list is emtry, then allocate a new page to refuel the list.
+ Please Note this algorithm to allocate the memory map descriptor has a property
+ that the memory allocated for memory entries always grows, and will never really be freed
+ For example, if the current boot uses 2000 memory map entries at the maximum point, but
+ ends up with only 50 at the time the OS is booted, then the memory associated with the 1950
+ memory map entries is still allocated from EfiBootServicesMemory.
+
+
+ @return The Memory map descriptor dequed from the mFreeMemoryMapEntryList
+
+**/
+MEMORY_MAP *
+AllocateMemoryMapEntry (
+ VOID
+ )
+{
+ MEMORY_MAP *FreeDescriptorEntries;
+ MEMORY_MAP *Entry;
+ UINTN Index;
+
+ if (IsListEmpty (&mFreeMemoryMapEntryList)) {
+ //
+ // The list is empty, to allocate one page to refuel the list
+ //
+ FreeDescriptorEntries = CoreAllocatePoolPages (
+ EfiBootServicesData,
+ EFI_SIZE_TO_PAGES (DEFAULT_PAGE_ALLOCATION_GRANULARITY),
+ DEFAULT_PAGE_ALLOCATION_GRANULARITY,
+ FALSE
+ );
+ if (FreeDescriptorEntries != NULL) {
+ //
+ // Enque the free memmory map entries into the list
+ //
+ for (Index = 0; Index < DEFAULT_PAGE_ALLOCATION_GRANULARITY / sizeof (MEMORY_MAP); Index++) {
+ FreeDescriptorEntries[Index].Signature = MEMORY_MAP_SIGNATURE;
+ InsertTailList (&mFreeMemoryMapEntryList, &FreeDescriptorEntries[Index].Link);
+ }
+ } else {
+ return NULL;
+ }
+ }
+
+ //
+ // dequeue the first descriptor from the list
+ //
+ Entry = CR (mFreeMemoryMapEntryList.ForwardLink, MEMORY_MAP, Link, MEMORY_MAP_SIGNATURE);
+ RemoveEntryList (&Entry->Link);
+
+ return Entry;
+}
+
+/**
+ Internal function. Moves any memory descriptors that are on the
+ temporary descriptor stack to heap.
+
+**/
+VOID
+CoreFreeMemoryMapStack (
+ VOID
+ )
+{
+ MEMORY_MAP *Entry;
+ MEMORY_MAP *Entry2;
+ LIST_ENTRY *Link2;
+
+ ASSERT_LOCKED (&gMemoryLock);
+
+ //
+ // If already freeing the map stack, then return
+ //
+ if (mFreeMapStack != 0) {
+ return;
+ }
+
+ //
+ // Move the temporary memory descriptor stack into pool
+ //
+ mFreeMapStack += 1;
+
+ while (mMapDepth != 0) {
+ //
+ // Deque an memory map entry from mFreeMemoryMapEntryList
+ //
+ Entry = AllocateMemoryMapEntry ();
+
+ ASSERT (Entry);
+
+ //
+ // Update to proper entry
+ //
+ mMapDepth -= 1;
+
+ if (mMapStack[mMapDepth].Link.ForwardLink != NULL) {
+ //
+ // Move this entry to general memory
+ //
+ RemoveEntryList (&mMapStack[mMapDepth].Link);
+ mMapStack[mMapDepth].Link.ForwardLink = NULL;
+
+ CopyMem (Entry, &mMapStack[mMapDepth], sizeof (MEMORY_MAP));
+ Entry->FromPages = TRUE;
+
+ //
+ // Find insertion location
+ //
+ for (Link2 = gMemoryMap.ForwardLink; Link2 != &gMemoryMap; Link2 = Link2->ForwardLink) {
+ Entry2 = CR (Link2, MEMORY_MAP, Link, MEMORY_MAP_SIGNATURE);
+ if (Entry2->FromPages && (Entry2->Start > Entry->Start)) {
+ break;
+ }
+ }
+
+ InsertTailList (Link2, &Entry->Link);
+ } else {
+ //
+ // This item of mMapStack[mMapDepth] has already been dequeued from gMemoryMap list,
+ // so here no need to move it to memory.
+ //
+ InsertTailList (&mFreeMemoryMapEntryList, &Entry->Link);
+ }
+ }
+
+ mFreeMapStack -= 1;
+}
+
+/**
+ Find untested but initialized memory regions in GCD map and convert them to be DXE allocatable.
+
+**/
+BOOLEAN
+PromoteMemoryResource (
+ VOID
+ )
+{
+ LIST_ENTRY *Link;
+ EFI_GCD_MAP_ENTRY *Entry;
+ BOOLEAN Promoted;
+ EFI_PHYSICAL_ADDRESS StartAddress;
+ EFI_PHYSICAL_ADDRESS EndAddress;
+ EFI_GCD_MEMORY_SPACE_DESCRIPTOR Descriptor;
+
+ DEBUG ((DEBUG_PAGE, "Promote the memory resource\n"));
+
+ CoreAcquireGcdMemoryLock ();
+
+ Promoted = FALSE;
+ Link = mGcdMemorySpaceMap.ForwardLink;
+ while (Link != &mGcdMemorySpaceMap) {
+ Entry = CR (Link, EFI_GCD_MAP_ENTRY, Link, EFI_GCD_MAP_SIGNATURE);
+
+ if ((Entry->GcdMemoryType == EfiGcdMemoryTypeReserved) &&
+ (Entry->EndAddress < MAX_ALLOC_ADDRESS) &&
+ ((Entry->Capabilities & (EFI_MEMORY_PRESENT | EFI_MEMORY_INITIALIZED | EFI_MEMORY_TESTED)) ==
+ (EFI_MEMORY_PRESENT | EFI_MEMORY_INITIALIZED)))
+ {
+ //
+ // Update the GCD map
+ //
+ if ((Entry->Capabilities & EFI_MEMORY_MORE_RELIABLE) == EFI_MEMORY_MORE_RELIABLE) {
+ Entry->GcdMemoryType = EfiGcdMemoryTypeMoreReliable;
+ } else {
+ Entry->GcdMemoryType = EfiGcdMemoryTypeSystemMemory;
+ }
+
+ Entry->Capabilities |= EFI_MEMORY_TESTED;
+ Entry->ImageHandle = gDxeCoreImageHandle;
+ Entry->DeviceHandle = NULL;
+
+ //
+ // Add to allocable system memory resource
+ //
+
+ CoreAddRange (
+ EfiConventionalMemory,
+ Entry->BaseAddress,
+ Entry->EndAddress,
+ Entry->Capabilities & ~(EFI_MEMORY_PRESENT | EFI_MEMORY_INITIALIZED | EFI_MEMORY_TESTED | EFI_MEMORY_RUNTIME)
+ );
+ CoreFreeMemoryMapStack ();
+
+ Promoted = TRUE;
+ }
+
+ Link = Link->ForwardLink;
+ }
+
+ CoreReleaseGcdMemoryLock ();
+
+ if (!Promoted) {
+ //
+ // If freed-memory guard is enabled, we could promote pages from
+ // guarded free pages.
+ //
+ Promoted = PromoteGuardedFreePages (&StartAddress, &EndAddress);
+ if (Promoted) {
+ if (!EFI_ERROR (CoreGetMemorySpaceDescriptor (StartAddress, &Descriptor))) {
+ CoreAddRange (
+ EfiConventionalMemory,
+ StartAddress,
+ EndAddress,
+ Descriptor.Capabilities & ~(EFI_MEMORY_PRESENT | EFI_MEMORY_INITIALIZED |
+ EFI_MEMORY_TESTED | EFI_MEMORY_RUNTIME)
+ );
+ }
+ }
+ }
+
+ return Promoted;
+}
+
+/**
+ This function try to allocate Runtime code & Boot time code memory range. If LMFA enabled, 2 patchable PCD
+ PcdLoadFixAddressRuntimeCodePageNumber & PcdLoadFixAddressBootTimeCodePageNumber which are set by tools will record the
+ size of boot time and runtime code.
+
+**/
+VOID
+CoreLoadingFixedAddressHook (
+ VOID
+ )
+{
+ UINT32 RuntimeCodePageNumber;
+ UINT32 BootTimeCodePageNumber;
+ EFI_PHYSICAL_ADDRESS RuntimeCodeBase;
+ EFI_PHYSICAL_ADDRESS BootTimeCodeBase;
+ EFI_STATUS Status;
+
+ //
+ // Make sure these 2 areas are not initialzied.
+ //
+ if (!gLoadFixedAddressCodeMemoryReady) {
+ RuntimeCodePageNumber = PcdGet32 (PcdLoadFixAddressRuntimeCodePageNumber);
+ BootTimeCodePageNumber = PcdGet32 (PcdLoadFixAddressBootTimeCodePageNumber);
+ RuntimeCodeBase = (EFI_PHYSICAL_ADDRESS)(gLoadModuleAtFixAddressConfigurationTable.DxeCodeTopAddress - EFI_PAGES_TO_SIZE (RuntimeCodePageNumber));
+ BootTimeCodeBase = (EFI_PHYSICAL_ADDRESS)(RuntimeCodeBase - EFI_PAGES_TO_SIZE (BootTimeCodePageNumber));
+ //
+ // Try to allocate runtime memory.
+ //
+ Status = CoreAllocatePages (
+ AllocateAddress,
+ EfiRuntimeServicesCode,
+ RuntimeCodePageNumber,
+ &RuntimeCodeBase
+ );
+ if (EFI_ERROR (Status)) {
+ //
+ // Runtime memory allocation failed
+ //
+ return;
+ }
+
+ //
+ // Try to allocate boot memory.
+ //
+ Status = CoreAllocatePages (
+ AllocateAddress,
+ EfiBootServicesCode,
+ BootTimeCodePageNumber,
+ &BootTimeCodeBase
+ );
+ if (EFI_ERROR (Status)) {
+ //
+ // boot memory allocation failed. Free Runtime code range and will try the allocation again when
+ // new memory range is installed.
+ //
+ CoreFreePages (
+ RuntimeCodeBase,
+ RuntimeCodePageNumber
+ );
+ return;
+ }
+
+ gLoadFixedAddressCodeMemoryReady = TRUE;
+ }
+
+ return;
+}
+
+/**
+ Sets the preferred memory range to use for the Memory Type Information bins.
+ This service must be called before fist call to CoreAddMemoryDescriptor().
+
+ If the location of the Memory Type Information bins has already been
+ established or the size of the range provides is smaller than all the
+ Memory Type Information bins, then the range provides is not used.
+
+ @param Start The start address of the Memory Type Information range.
+ @param Length The size, in bytes, of the Memory Type Information range.
+**/
+VOID
+CoreSetMemoryTypeInformationRange (
+ IN EFI_PHYSICAL_ADDRESS Start,
+ IN UINT64 Length
+ )
+{
+ EFI_PHYSICAL_ADDRESS Top;
+ EFI_MEMORY_TYPE Type;
+ UINTN Index;
+ UINTN Size;
+
+ //
+ // Return if Memory Type Information bin locations have already been set
+ //
+ if (mMemoryTypeInformationInitialized) {
+ DEBUG ((DEBUG_ERROR, "%a: Ignored. Bins already set.\n", __func__));
+ return;
+ }
+
+ //
+ // Return if size of the Memory Type Information bins is greater than Length
+ //
+ Size = 0;
+ for (Index = 0; gMemoryTypeInformation[Index].Type != EfiMaxMemoryType; Index++) {
+ //
+ // Make sure the memory type in the gMemoryTypeInformation[] array is valid
+ //
+ Type = (EFI_MEMORY_TYPE)(gMemoryTypeInformation[Index].Type);
+ if ((UINT32)Type > EfiMaxMemoryType) {
+ continue;
+ }
+
+ Size += EFI_PAGES_TO_SIZE (gMemoryTypeInformation[Index].NumberOfPages);
+ }
+
+ if (Size > Length) {
+ return;
+ }
+
+ //
+ // Loop through each memory type in the order specified by the
+ // gMemoryTypeInformation[] array
+ //
+ Top = Start + Length;
+ for (Index = 0; gMemoryTypeInformation[Index].Type != EfiMaxMemoryType; Index++) {
+ //
+ // Make sure the memory type in the gMemoryTypeInformation[] array is valid
+ //
+ Type = (EFI_MEMORY_TYPE)(gMemoryTypeInformation[Index].Type);
+ if ((UINT32)Type > EfiMaxMemoryType) {
+ continue;
+ }
+
+ if (gMemoryTypeInformation[Index].NumberOfPages != 0) {
+ mMemoryTypeStatistics[Type].MaximumAddress = Top - 1;
+ Top -= EFI_PAGES_TO_SIZE (gMemoryTypeInformation[Index].NumberOfPages);
+ mMemoryTypeStatistics[Type].BaseAddress = Top;
+
+ //
+ // If the current base address is the lowest address so far, then update
+ // the default maximum address
+ //
+ if (mMemoryTypeStatistics[Type].BaseAddress < mDefaultMaximumAddress) {
+ mDefaultMaximumAddress = mMemoryTypeStatistics[Type].BaseAddress - 1;
+ }
+
+ mMemoryTypeStatistics[Type].NumberOfPages = gMemoryTypeInformation[Index].NumberOfPages;
+ gMemoryTypeInformation[Index].NumberOfPages = 0;
+ }
+ }
+
+ //
+ // If the number of pages reserved for a memory type is 0, then all
+ // allocations for that type should be in the default range.
+ //
+ for (Type = (EFI_MEMORY_TYPE)0; Type < EfiMaxMemoryType; Type++) {
+ for (Index = 0; gMemoryTypeInformation[Index].Type != EfiMaxMemoryType; Index++) {
+ if (Type == (EFI_MEMORY_TYPE)gMemoryTypeInformation[Index].Type) {
+ mMemoryTypeStatistics[Type].InformationIndex = Index;
+ }
+ }
+
+ mMemoryTypeStatistics[Type].CurrentNumberOfPages = 0;
+ if (mMemoryTypeStatistics[Type].MaximumAddress == MAX_ALLOC_ADDRESS) {
+ mMemoryTypeStatistics[Type].MaximumAddress = mDefaultMaximumAddress;
+ }
+ }
+
+ mMemoryTypeInformationInitialized = TRUE;
+}
+
+/**
+ Called to initialize the memory map and add descriptors to
+ the current descriptor list.
+ The first descriptor that is added must be general usable
+ memory as the addition allocates heap.
+
+ @param Type The type of memory to add
+ @param Start The starting address in the memory range Must be
+ page aligned
+ @param NumberOfPages The number of pages in the range
+ @param Attribute Attributes of the memory to add
+
+ @return None. The range is added to the memory map
+
+**/
+VOID
+CoreAddMemoryDescriptor (
+ IN EFI_MEMORY_TYPE Type,
+ IN EFI_PHYSICAL_ADDRESS Start,
+ IN UINT64 NumberOfPages,
+ IN UINT64 Attribute
+ )
+{
+ EFI_PHYSICAL_ADDRESS End;
+ EFI_STATUS Status;
+ UINTN Index;
+ UINTN FreeIndex;
+
+ if ((Start & EFI_PAGE_MASK) != 0) {
+ return;
+ }
+
+ if ((Type >= EfiMaxMemoryType) && (Type < MEMORY_TYPE_OEM_RESERVED_MIN)) {
+ return;
+ }
+
+ CoreAcquireMemoryLock ();
+ End = Start + LShiftU64 (NumberOfPages, EFI_PAGE_SHIFT) - 1;
+ CoreAddRange (Type, Start, End, Attribute);
+ CoreFreeMemoryMapStack ();
+ CoreReleaseMemoryLock ();
+
+ ApplyMemoryProtectionPolicy (
+ EfiMaxMemoryType,
+ Type,
+ Start,
+ LShiftU64 (NumberOfPages, EFI_PAGE_SHIFT)
+ );
+
+ //
+ // If Loading Module At Fixed Address feature is enabled. try to allocate memory with Runtime code & Boot time code type
+ //
+ if (PcdGet64 (PcdLoadModuleAtFixAddressEnable) != 0) {
+ CoreLoadingFixedAddressHook ();
+ }
+
+ //
+ // Check to see if the statistics for the different memory types have already been established
+ //
+ if (mMemoryTypeInformationInitialized) {
+ return;
+ }
+
+ //
+ // Loop through each memory type in the order specified by the gMemoryTypeInformation[] array
+ //
+ for (Index = 0; gMemoryTypeInformation[Index].Type != EfiMaxMemoryType; Index++) {
+ //
+ // Make sure the memory type in the gMemoryTypeInformation[] array is valid
+ //
+ Type = (EFI_MEMORY_TYPE)(gMemoryTypeInformation[Index].Type);
+ if ((UINT32)Type > EfiMaxMemoryType) {
+ continue;
+ }
+
+ if (gMemoryTypeInformation[Index].NumberOfPages != 0) {
+ //
+ // Allocate pages for the current memory type from the top of available memory
+ //
+ Status = CoreAllocatePages (
+ AllocateAnyPages,
+ Type,
+ gMemoryTypeInformation[Index].NumberOfPages,
+ &mMemoryTypeStatistics[Type].BaseAddress
+ );
+ if (EFI_ERROR (Status)) {
+ //
+ // If an error occurs allocating the pages for the current memory type, then
+ // free all the pages allocates for the previous memory types and return. This
+ // operation with be retied when/if more memory is added to the system
+ //
+ for (FreeIndex = 0; FreeIndex < Index; FreeIndex++) {
+ //
+ // Make sure the memory type in the gMemoryTypeInformation[] array is valid
+ //
+ Type = (EFI_MEMORY_TYPE)(gMemoryTypeInformation[FreeIndex].Type);
+ if ((UINT32)Type > EfiMaxMemoryType) {
+ continue;
+ }
+
+ if (gMemoryTypeInformation[FreeIndex].NumberOfPages != 0) {
+ CoreFreePages (
+ mMemoryTypeStatistics[Type].BaseAddress,
+ gMemoryTypeInformation[FreeIndex].NumberOfPages
+ );
+ mMemoryTypeStatistics[Type].BaseAddress = 0;
+ mMemoryTypeStatistics[Type].MaximumAddress = MAX_ALLOC_ADDRESS;
+ }
+ }
+
+ return;
+ }
+
+ //
+ // Compute the address at the top of the current statistics
+ //
+ mMemoryTypeStatistics[Type].MaximumAddress =
+ mMemoryTypeStatistics[Type].BaseAddress +
+ LShiftU64 (gMemoryTypeInformation[Index].NumberOfPages, EFI_PAGE_SHIFT) - 1;
+
+ //
+ // If the current base address is the lowest address so far, then update the default
+ // maximum address
+ //
+ if (mMemoryTypeStatistics[Type].BaseAddress < mDefaultMaximumAddress) {
+ mDefaultMaximumAddress = mMemoryTypeStatistics[Type].BaseAddress - 1;
+ }
+ }
+ }
+
+ //
+ // There was enough system memory for all the the memory types were allocated. So,
+ // those memory areas can be freed for future allocations, and all future memory
+ // allocations can occur within their respective bins
+ //
+ for (Index = 0; gMemoryTypeInformation[Index].Type != EfiMaxMemoryType; Index++) {
+ //
+ // Make sure the memory type in the gMemoryTypeInformation[] array is valid
+ //
+ Type = (EFI_MEMORY_TYPE)(gMemoryTypeInformation[Index].Type);
+ if ((UINT32)Type > EfiMaxMemoryType) {
+ continue;
+ }
+
+ if (gMemoryTypeInformation[Index].NumberOfPages != 0) {
+ CoreFreePages (
+ mMemoryTypeStatistics[Type].BaseAddress,
+ gMemoryTypeInformation[Index].NumberOfPages
+ );
+ mMemoryTypeStatistics[Type].NumberOfPages = gMemoryTypeInformation[Index].NumberOfPages;
+ gMemoryTypeInformation[Index].NumberOfPages = 0;
+ }
+ }
+
+ //
+ // If the number of pages reserved for a memory type is 0, then all allocations for that type
+ // should be in the default range.
+ //
+ for (Type = (EFI_MEMORY_TYPE)0; Type < EfiMaxMemoryType; Type++) {
+ for (Index = 0; gMemoryTypeInformation[Index].Type != EfiMaxMemoryType; Index++) {
+ if (Type == (EFI_MEMORY_TYPE)gMemoryTypeInformation[Index].Type) {
+ mMemoryTypeStatistics[Type].InformationIndex = Index;
+ }
+ }
+
+ mMemoryTypeStatistics[Type].CurrentNumberOfPages = 0;
+ if (mMemoryTypeStatistics[Type].MaximumAddress == MAX_ALLOC_ADDRESS) {
+ mMemoryTypeStatistics[Type].MaximumAddress = mDefaultMaximumAddress;
+ }
+ }
+
+ mMemoryTypeInformationInitialized = TRUE;
+}
+
+/**
+ Internal function. Converts a memory range to the specified type or attributes.
+ The range must exist in the memory map. Either ChangingType or
+ ChangingAttributes must be set, but not both.
+
+ @param Start The first address of the range Must be page
+ aligned
+ @param NumberOfPages The number of pages to convert
+ @param ChangingType Boolean indicating that type value should be changed
+ @param NewType The new type for the memory range
+ @param ChangingAttributes Boolean indicating that attributes value should be changed
+ @param NewAttributes The new attributes for the memory range
+
+ @retval EFI_INVALID_PARAMETER Invalid parameter
+ @retval EFI_NOT_FOUND Could not find a descriptor cover the specified
+ range or convertion not allowed.
+ @retval EFI_SUCCESS Successfully converts the memory range to the
+ specified type.
+
+**/
+EFI_STATUS
+CoreConvertPagesEx (
+ IN UINT64 Start,
+ IN UINT64 NumberOfPages,
+ IN BOOLEAN ChangingType,
+ IN EFI_MEMORY_TYPE NewType,
+ IN BOOLEAN ChangingAttributes,
+ IN UINT64 NewAttributes
+ )
+{
+ UINT64 NumberOfBytes;
+ UINT64 End;
+ UINT64 RangeEnd;
+ UINT64 Attribute;
+ EFI_MEMORY_TYPE MemType;
+ LIST_ENTRY *Link;
+ MEMORY_MAP *Entry;
+
+ Entry = NULL;
+ NumberOfBytes = LShiftU64 (NumberOfPages, EFI_PAGE_SHIFT);
+ End = Start + NumberOfBytes - 1;
+
+ ASSERT (NumberOfPages);
+ ASSERT ((Start & EFI_PAGE_MASK) == 0);
+ ASSERT (End > Start);
+ ASSERT_LOCKED (&gMemoryLock);
+ ASSERT ((ChangingType == FALSE) || (ChangingAttributes == FALSE));
+
+ if ((NumberOfPages == 0) || ((Start & EFI_PAGE_MASK) != 0) || (Start >= End)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Convert the entire range
+ //
+
+ while (Start < End) {
+ //
+ // Find the entry that the covers the range
+ //
+ for (Link = gMemoryMap.ForwardLink; Link != &gMemoryMap; Link = Link->ForwardLink) {
+ Entry = CR (Link, MEMORY_MAP, Link, MEMORY_MAP_SIGNATURE);
+
+ if ((Entry->Start <= Start) && (Entry->End > Start)) {
+ break;
+ }
+ }
+
+ if (Link == &gMemoryMap) {
+ DEBUG ((DEBUG_ERROR | DEBUG_PAGE, "ConvertPages: failed to find range %lx - %lx\n", Start, End));
+ return EFI_NOT_FOUND;
+ }
+
+ //
+ // If we are converting the type of the range from EfiConventionalMemory to
+ // another type, we have to ensure that the entire range is covered by a
+ // single entry.
+ //
+ if (ChangingType && (NewType != EfiConventionalMemory)) {
+ if (Entry->End < End) {
+ DEBUG ((DEBUG_ERROR | DEBUG_PAGE, "ConvertPages: range %lx - %lx covers multiple entries\n", Start, End));
+ return EFI_NOT_FOUND;
+ }
+ }
+
+ //
+ // Convert range to the end, or to the end of the descriptor
+ // if that's all we've got
+ //
+ RangeEnd = End;
+
+ ASSERT (Entry != NULL);
+ if (Entry->End < End) {
+ RangeEnd = Entry->End;
+ }
+
+ if (ChangingType) {
+ DEBUG ((DEBUG_PAGE, "ConvertRange: %lx-%lx to type %d\n", Start, RangeEnd, NewType));
+ }
+
+ if (ChangingAttributes) {
+ DEBUG ((DEBUG_PAGE, "ConvertRange: %lx-%lx to attr %lx\n", Start, RangeEnd, NewAttributes));
+ }
+
+ if (ChangingType) {
+ //
+ // Debug code - verify conversion is allowed
+ //
+ if (!((NewType == EfiConventionalMemory) ? 1 : 0) ^ ((Entry->Type == EfiConventionalMemory) ? 1 : 0)) {
+ DEBUG ((DEBUG_ERROR | DEBUG_PAGE, "ConvertPages: Incompatible memory types, "));
+ if (Entry->Type == EfiConventionalMemory) {
+ DEBUG ((DEBUG_ERROR | DEBUG_PAGE, "the pages to free have been freed\n"));
+ } else {
+ DEBUG ((DEBUG_ERROR | DEBUG_PAGE, "the pages to allocate have been allocated\n"));
+ }
+
+ return EFI_NOT_FOUND;
+ }
+
+ //
+ // Update counters for the number of pages allocated to each memory type
+ //
+ if ((UINT32)Entry->Type < EfiMaxMemoryType) {
+ if (((Start >= mMemoryTypeStatistics[Entry->Type].BaseAddress) && (Start <= mMemoryTypeStatistics[Entry->Type].MaximumAddress)) ||
+ ((Start >= mDefaultBaseAddress) && (Start <= mDefaultMaximumAddress)))
+ {
+ if (NumberOfPages > mMemoryTypeStatistics[Entry->Type].CurrentNumberOfPages) {
+ mMemoryTypeStatistics[Entry->Type].CurrentNumberOfPages = 0;
+ } else {
+ mMemoryTypeStatistics[Entry->Type].CurrentNumberOfPages -= NumberOfPages;
+ }
+ }
+ }
+
+ if ((UINT32)NewType < EfiMaxMemoryType) {
+ if (((Start >= mMemoryTypeStatistics[NewType].BaseAddress) && (Start <= mMemoryTypeStatistics[NewType].MaximumAddress)) ||
+ ((Start >= mDefaultBaseAddress) && (Start <= mDefaultMaximumAddress)))
+ {
+ mMemoryTypeStatistics[NewType].CurrentNumberOfPages += NumberOfPages;
+ if (mMemoryTypeStatistics[NewType].CurrentNumberOfPages > gMemoryTypeInformation[mMemoryTypeStatistics[NewType].InformationIndex].NumberOfPages) {
+ gMemoryTypeInformation[mMemoryTypeStatistics[NewType].InformationIndex].NumberOfPages = (UINT32)mMemoryTypeStatistics[NewType].CurrentNumberOfPages;
+ }
+ }
+ }
+ }
+
+ //
+ // Pull range out of descriptor
+ //
+ if (Entry->Start == Start) {
+ //
+ // Clip start
+ //
+ Entry->Start = RangeEnd + 1;
+ } else if (Entry->End == RangeEnd) {
+ //
+ // Clip end
+ //
+ Entry->End = Start - 1;
+ } else {
+ //
+ // Pull it out of the center, clip current
+ //
+
+ //
+ // Add a new one
+ //
+ mMapStack[mMapDepth].Signature = MEMORY_MAP_SIGNATURE;
+ mMapStack[mMapDepth].FromPages = FALSE;
+ mMapStack[mMapDepth].Type = Entry->Type;
+ mMapStack[mMapDepth].Start = RangeEnd+1;
+ mMapStack[mMapDepth].End = Entry->End;
+
+ //
+ // Inherit Attribute from the Memory Descriptor that is being clipped
+ //
+ mMapStack[mMapDepth].Attribute = Entry->Attribute;
+
+ Entry->End = Start - 1;
+ ASSERT (Entry->Start < Entry->End);
+
+ Entry = &mMapStack[mMapDepth];
+ InsertTailList (&gMemoryMap, &Entry->Link);
+
+ mMapDepth += 1;
+ ASSERT (mMapDepth < MAX_MAP_DEPTH);
+ }
+
+ //
+ // The new range inherits the same Attribute as the Entry
+ // it is being cut out of unless attributes are being changed
+ //
+ if (ChangingType) {
+ Attribute = Entry->Attribute;
+ MemType = NewType;
+ } else {
+ Attribute = NewAttributes;
+ MemType = Entry->Type;
+ }
+
+ //
+ // If the descriptor is empty, then remove it from the map
+ //
+ if (Entry->Start == Entry->End + 1) {
+ RemoveMemoryMapEntry (Entry);
+ Entry = NULL;
+ }
+
+ //
+ // Add our new range in. Don't do this for freed pages if freed-memory
+ // guard is enabled.
+ //
+ if (!IsHeapGuardEnabled (GUARD_HEAP_TYPE_FREED) ||
+ !ChangingType ||
+ (MemType != EfiConventionalMemory))
+ {
+ CoreAddRange (MemType, Start, RangeEnd, Attribute);
+ }
+
+ if (ChangingType && (MemType == EfiConventionalMemory)) {
+ //
+ // Avoid calling DEBUG_CLEAR_MEMORY() for an address of 0 because this
+ // macro will ASSERT() if address is 0. Instead, CoreAddRange() guarantees
+ // that the page starting at address 0 is always filled with zeros.
+ //
+ if (Start == 0) {
+ if (RangeEnd > EFI_PAGE_SIZE) {
+ DEBUG_CLEAR_MEMORY ((VOID *)(UINTN)EFI_PAGE_SIZE, (UINTN)(RangeEnd - EFI_PAGE_SIZE + 1));
+ }
+ } else {
+ DEBUG_CLEAR_MEMORY ((VOID *)(UINTN)Start, (UINTN)(RangeEnd - Start + 1));
+ }
+ }
+
+ //
+ // Move any map descriptor stack to general pool
+ //
+ CoreFreeMemoryMapStack ();
+
+ //
+ // Bump the starting address, and convert the next range
+ //
+ Start = RangeEnd + 1;
+ }
+
+ //
+ // Converted the whole range, done
+ //
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Internal function. Converts a memory range to the specified type.
+ The range must exist in the memory map.
+
+ @param Start The first address of the range Must be page
+ aligned
+ @param NumberOfPages The number of pages to convert
+ @param NewType The new type for the memory range
+
+ @retval EFI_INVALID_PARAMETER Invalid parameter
+ @retval EFI_NOT_FOUND Could not find a descriptor cover the specified
+ range or convertion not allowed.
+ @retval EFI_SUCCESS Successfully converts the memory range to the
+ specified type.
+
+**/
+EFI_STATUS
+CoreConvertPages (
+ IN UINT64 Start,
+ IN UINT64 NumberOfPages,
+ IN EFI_MEMORY_TYPE NewType
+ )
+{
+ return CoreConvertPagesEx (Start, NumberOfPages, TRUE, NewType, FALSE, 0);
+}
+
+/**
+ Internal function. Converts a memory range to use new attributes.
+
+ @param Start The first address of the range Must be page
+ aligned
+ @param NumberOfPages The number of pages to convert
+ @param NewAttributes The new attributes value for the range.
+
+**/
+VOID
+CoreUpdateMemoryAttributes (
+ IN EFI_PHYSICAL_ADDRESS Start,
+ IN UINT64 NumberOfPages,
+ IN UINT64 NewAttributes
+ )
+{
+ CoreAcquireMemoryLock ();
+
+ //
+ // Update the attributes to the new value
+ //
+ CoreConvertPagesEx (Start, NumberOfPages, FALSE, (EFI_MEMORY_TYPE)0, TRUE, NewAttributes);
+
+ CoreReleaseMemoryLock ();
+}
+
+/**
+ Internal function. Finds a consecutive free page range below
+ the requested address.
+
+ @param MaxAddress The address that the range must be below
+ @param MinAddress The address that the range must be above
+ @param NumberOfPages Number of pages needed
+ @param NewType The type of memory the range is going to be
+ turned into
+ @param Alignment Bits to align with
+ @param NeedGuard Flag to indicate Guard page is needed or not
+
+ @return The base address of the range, or 0 if the range was not found
+
+**/
+UINT64
+CoreFindFreePagesI (
+ IN UINT64 MaxAddress,
+ IN UINT64 MinAddress,
+ IN UINT64 NumberOfPages,
+ IN EFI_MEMORY_TYPE NewType,
+ IN UINTN Alignment,
+ IN BOOLEAN NeedGuard
+ )
+{
+ UINT64 NumberOfBytes;
+ UINT64 Target;
+ UINT64 DescStart;
+ UINT64 DescEnd;
+ UINT64 DescNumberOfBytes;
+ LIST_ENTRY *Link;
+ MEMORY_MAP *Entry;
+
+ if ((MaxAddress < EFI_PAGE_MASK) || (NumberOfPages == 0)) {
+ return 0;
+ }
+
+ if ((MaxAddress & EFI_PAGE_MASK) != EFI_PAGE_MASK) {
+ //
+ // If MaxAddress is not aligned to the end of a page
+ //
+
+ //
+ // Change MaxAddress to be 1 page lower
+ //
+ MaxAddress -= (EFI_PAGE_MASK + 1);
+
+ //
+ // Set MaxAddress to a page boundary
+ //
+ MaxAddress &= ~(UINT64)EFI_PAGE_MASK;
+
+ //
+ // Set MaxAddress to end of the page
+ //
+ MaxAddress |= EFI_PAGE_MASK;
+ }
+
+ NumberOfBytes = LShiftU64 (NumberOfPages, EFI_PAGE_SHIFT);
+ Target = 0;
+
+ for (Link = gMemoryMap.ForwardLink; Link != &gMemoryMap; Link = Link->ForwardLink) {
+ Entry = CR (Link, MEMORY_MAP, Link, MEMORY_MAP_SIGNATURE);
+
+ //
+ // If it's not a free entry, don't bother with it
+ //
+ if (Entry->Type != EfiConventionalMemory) {
+ continue;
+ }
+
+ DescStart = Entry->Start;
+ DescEnd = Entry->End;
+
+ //
+ // If desc is past max allowed address or below min allowed address, skip it
+ //
+ if ((DescStart >= MaxAddress) || (DescEnd < MinAddress)) {
+ continue;
+ }
+
+ //
+ // If desc ends past max allowed address, clip the end
+ //
+ if (DescEnd >= MaxAddress) {
+ DescEnd = MaxAddress;
+ }
+
+ DescEnd = ((DescEnd + 1) & (~((UINT64)Alignment - 1))) - 1;
+
+ // Skip if DescEnd is less than DescStart after alignment clipping
+ if (DescEnd < DescStart) {
+ continue;
+ }
+
+ //
+ // Compute the number of bytes we can used from this
+ // descriptor, and see it's enough to satisfy the request
+ //
+ DescNumberOfBytes = DescEnd - DescStart + 1;
+
+ if (DescNumberOfBytes >= NumberOfBytes) {
+ //
+ // If the start of the allocated range is below the min address allowed, skip it
+ //
+ if ((DescEnd - NumberOfBytes + 1) < MinAddress) {
+ continue;
+ }
+
+ //
+ // If this is the best match so far remember it
+ //
+ if (DescEnd > Target) {
+ if (NeedGuard) {
+ DescEnd = AdjustMemoryS (
+ DescEnd + 1 - DescNumberOfBytes,
+ DescNumberOfBytes,
+ NumberOfBytes
+ );
+ if (DescEnd == 0) {
+ continue;
+ }
+ }
+
+ Target = DescEnd;
+ }
+ }
+ }
+
+ //
+ // If this is a grow down, adjust target to be the allocation base
+ //
+ Target -= NumberOfBytes - 1;
+
+ //
+ // If we didn't find a match, return 0
+ //
+ if ((Target & EFI_PAGE_MASK) != 0) {
+ return 0;
+ }
+
+ return Target;
+}
+
+/**
+ Internal function. Finds a consecutive free page range below
+ the requested address
+
+ @param MaxAddress The address that the range must be below
+ @param NoPages Number of pages needed
+ @param NewType The type of memory the range is going to be
+ turned into
+ @param Alignment Bits to align with
+ @param NeedGuard Flag to indicate Guard page is needed or not
+
+ @return The base address of the range, or 0 if the range was not found.
+
+**/
+UINT64
+FindFreePages (
+ IN UINT64 MaxAddress,
+ IN UINT64 NoPages,
+ IN EFI_MEMORY_TYPE NewType,
+ IN UINTN Alignment,
+ IN BOOLEAN NeedGuard
+ )
+{
+ UINT64 Start;
+
+ //
+ // Attempt to find free pages in the preferred bin based on the requested memory type
+ //
+ if (((UINT32)NewType < EfiMaxMemoryType) && (MaxAddress >= mMemoryTypeStatistics[NewType].MaximumAddress)) {
+ Start = CoreFindFreePagesI (
+ mMemoryTypeStatistics[NewType].MaximumAddress,
+ mMemoryTypeStatistics[NewType].BaseAddress,
+ NoPages,
+ NewType,
+ Alignment,
+ NeedGuard
+ );
+ if (Start != 0) {
+ return Start;
+ }
+ }
+
+ //
+ // Attempt to find free pages in the default allocation bin
+ //
+ if (MaxAddress >= mDefaultMaximumAddress) {
+ Start = CoreFindFreePagesI (
+ mDefaultMaximumAddress,
+ 0,
+ NoPages,
+ NewType,
+ Alignment,
+ NeedGuard
+ );
+ if (Start != 0) {
+ if (Start < mDefaultBaseAddress) {
+ mDefaultBaseAddress = NeedGuard ? Start - EFI_PAGE_SIZE : Start;
+ }
+
+ return Start;
+ }
+ }
+
+ //
+ // The allocation did not succeed in any of the prefered bins even after
+ // promoting resources. Attempt to find free pages anywhere is the requested
+ // address range. If this allocation fails, then there are not enough
+ // resources anywhere to satisfy the request.
+ //
+ Start = CoreFindFreePagesI (
+ MaxAddress,
+ 0,
+ NoPages,
+ NewType,
+ Alignment,
+ NeedGuard
+ );
+ if (Start != 0) {
+ return Start;
+ }
+
+ //
+ // If allocations from the preferred bins fail, then attempt to promote memory resources.
+ //
+ if (!PromoteMemoryResource ()) {
+ return 0;
+ }
+
+ //
+ // If any memory resources were promoted, then re-attempt the allocation
+ //
+ return FindFreePages (MaxAddress, NoPages, NewType, Alignment, NeedGuard);
+}
+
+/**
+ Allocates pages from the memory map.
+
+ @param Type The type of allocation to perform
+ @param MemoryType The type of memory to turn the allocated pages
+ into
+ @param NumberOfPages The number of pages to allocate
+ @param Memory A pointer to receive the base allocated memory
+ address
+ @param NeedGuard Flag to indicate Guard page is needed or not
+
+ @return Status. On success, Memory is filled in with the base address allocated
+ @retval EFI_INVALID_PARAMETER Parameters violate checking rules defined in
+ spec.
+ @retval EFI_NOT_FOUND Could not allocate pages match the requirement.
+ @retval EFI_OUT_OF_RESOURCES No enough pages to allocate.
+ @retval EFI_SUCCESS Pages successfully allocated.
+
+**/
+EFI_STATUS
+EFIAPI
+CoreInternalAllocatePages (
+ IN EFI_ALLOCATE_TYPE Type,
+ IN EFI_MEMORY_TYPE MemoryType,
+ IN UINTN NumberOfPages,
+ IN OUT EFI_PHYSICAL_ADDRESS *Memory,
+ IN BOOLEAN NeedGuard
+ )
+{
+ EFI_STATUS Status;
+ UINT64 Start;
+ UINT64 NumberOfBytes;
+ UINT64 End;
+ UINT64 MaxAddress;
+ UINTN Alignment;
+ EFI_MEMORY_TYPE CheckType;
+
+ if ((UINT32)Type >= MaxAllocateType) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (((MemoryType >= EfiMaxMemoryType) && (MemoryType < MEMORY_TYPE_OEM_RESERVED_MIN)) ||
+ (MemoryType == EfiConventionalMemory) || (MemoryType == EfiPersistentMemory) || (MemoryType == EfiUnacceptedMemoryType))
+ {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (Memory == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Alignment = DEFAULT_PAGE_ALLOCATION_GRANULARITY;
+
+ if ((MemoryType == EfiReservedMemoryType) ||
+ (MemoryType == EfiACPIMemoryNVS) ||
+ (MemoryType == EfiRuntimeServicesCode) ||
+ (MemoryType == EfiRuntimeServicesData))
+ {
+ Alignment = RUNTIME_PAGE_ALLOCATION_GRANULARITY;
+ }
+
+ //
+ // The heap guard system does not support non-EFI_PAGE_SIZE alignments.
+ // Architectures that require larger RUNTIME_PAGE_ALLOCATION_GRANULARITY
+ // will have the runtime memory regions unguarded. OSes do not
+ // map guard pages anyway, so this is a minimal loss. Not guarding prevents
+ // alignment mismatches
+ //
+ if (Alignment != EFI_PAGE_SIZE) {
+ NeedGuard = FALSE;
+ }
+
+ if (Type == AllocateAddress) {
+ if ((*Memory & (Alignment - 1)) != 0) {
+ return EFI_NOT_FOUND;
+ }
+ }
+
+ NumberOfPages += EFI_SIZE_TO_PAGES (Alignment) - 1;
+ NumberOfPages &= ~(EFI_SIZE_TO_PAGES (Alignment) - 1);
+
+ //
+ // If this is for below a particular address, then
+ //
+ Start = *Memory;
+
+ //
+ // The max address is the max natively addressable address for the processor
+ //
+ MaxAddress = MAX_ALLOC_ADDRESS;
+
+ //
+ // Check for Type AllocateAddress,
+ // if NumberOfPages is 0 or
+ // if (NumberOfPages << EFI_PAGE_SHIFT) is above MAX_ALLOC_ADDRESS or
+ // if (Start + NumberOfBytes) rolls over 0 or
+ // if Start is above MAX_ALLOC_ADDRESS or
+ // if End is above MAX_ALLOC_ADDRESS,
+ // if Start..End overlaps any tracked MemoryTypeStatistics range
+ // return EFI_NOT_FOUND.
+ //
+ if (Type == AllocateAddress) {
+ if ((NumberOfPages == 0) ||
+ (NumberOfPages > RShiftU64 (MaxAddress, EFI_PAGE_SHIFT)))
+ {
+ return EFI_NOT_FOUND;
+ }
+
+ NumberOfBytes = LShiftU64 (NumberOfPages, EFI_PAGE_SHIFT);
+ End = Start + NumberOfBytes - 1;
+
+ if ((Start >= End) ||
+ (Start > MaxAddress) ||
+ (End > MaxAddress))
+ {
+ return EFI_NOT_FOUND;
+ }
+
+ //
+ // A driver is allowed to call AllocatePages using an AllocateAddress type. This type of
+ // AllocatePage request the exact physical address if it is not used. The existing code
+ // will allow this request even in 'special' pages. The problem with this is that the
+ // reason to have 'special' pages for OS hibernate/resume is defeated as memory is
+ // fragmented.
+ //
+
+ for (CheckType = (EFI_MEMORY_TYPE)0; CheckType < EfiMaxMemoryType; CheckType++) {
+ if ((MemoryType != CheckType) &&
+ mMemoryTypeStatistics[CheckType].Special &&
+ (mMemoryTypeStatistics[CheckType].NumberOfPages > 0))
+ {
+ if ((Start >= mMemoryTypeStatistics[CheckType].BaseAddress) &&
+ (Start <= mMemoryTypeStatistics[CheckType].MaximumAddress))
+ {
+ return EFI_NOT_FOUND;
+ }
+
+ if ((End >= mMemoryTypeStatistics[CheckType].BaseAddress) &&
+ (End <= mMemoryTypeStatistics[CheckType].MaximumAddress))
+ {
+ return EFI_NOT_FOUND;
+ }
+
+ if ((Start < mMemoryTypeStatistics[CheckType].BaseAddress) &&
+ (End > mMemoryTypeStatistics[CheckType].MaximumAddress))
+ {
+ return EFI_NOT_FOUND;
+ }
+ }
+ }
+ }
+
+ if (Type == AllocateMaxAddress) {
+ MaxAddress = Start;
+ }
+
+ CoreAcquireMemoryLock ();
+
+ //
+ // If not a specific address, then find an address to allocate
+ //
+ if (Type != AllocateAddress) {
+ Start = FindFreePages (
+ MaxAddress,
+ NumberOfPages,
+ MemoryType,
+ Alignment,
+ NeedGuard
+ );
+ if (Start == 0) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Done;
+ }
+ }
+
+ //
+ // Convert pages from FreeMemory to the requested type
+ //
+ if (NeedGuard) {
+ Status = CoreConvertPagesWithGuard (Start, NumberOfPages, MemoryType);
+ } else {
+ Status = CoreConvertPages (Start, NumberOfPages, MemoryType);
+ }
+
+ if (EFI_ERROR (Status)) {
+ //
+ // If requested memory region is unavailable it may be untested memory
+ // Attempt to promote memory resources, then re-attempt the allocation
+ //
+ if (PromoteMemoryResource ()) {
+ if (NeedGuard) {
+ Status = CoreConvertPagesWithGuard (Start, NumberOfPages, MemoryType);
+ } else {
+ Status = CoreConvertPages (Start, NumberOfPages, MemoryType);
+ }
+ }
+ }
+
+Done:
+ CoreReleaseMemoryLock ();
+
+ if (!EFI_ERROR (Status)) {
+ if (NeedGuard) {
+ SetGuardForMemory (Start, NumberOfPages);
+ }
+
+ *Memory = Start;
+ }
+
+ return Status;
+}
+
+/**
+ Allocates pages from the memory map.
+
+ @param Type The type of allocation to perform
+ @param MemoryType The type of memory to turn the allocated pages
+ into
+ @param NumberOfPages The number of pages to allocate
+ @param Memory A pointer to receive the base allocated memory
+ address
+
+ @return Status. On success, Memory is filled in with the base address allocated
+ @retval EFI_INVALID_PARAMETER Parameters violate checking rules defined in
+ spec.
+ @retval EFI_NOT_FOUND Could not allocate pages match the requirement.
+ @retval EFI_OUT_OF_RESOURCES No enough pages to allocate.
+ @retval EFI_SUCCESS Pages successfully allocated.
+
+**/
+EFI_STATUS
+EFIAPI
+CoreAllocatePages (
+ IN EFI_ALLOCATE_TYPE Type,
+ IN EFI_MEMORY_TYPE MemoryType,
+ IN UINTN NumberOfPages,
+ OUT EFI_PHYSICAL_ADDRESS *Memory
+ )
+{
+ EFI_STATUS Status;
+ BOOLEAN NeedGuard;
+
+ NeedGuard = IsPageTypeToGuard (MemoryType, Type) && !mOnGuarding;
+ Status = CoreInternalAllocatePages (
+ Type,
+ MemoryType,
+ NumberOfPages,
+ Memory,
+ NeedGuard
+ );
+ if (!EFI_ERROR (Status)) {
+ CoreUpdateProfile (
+ (EFI_PHYSICAL_ADDRESS)(UINTN)RETURN_ADDRESS (0),
+ MemoryProfileActionAllocatePages,
+ MemoryType,
+ EFI_PAGES_TO_SIZE (NumberOfPages),
+ (VOID *)(UINTN)*Memory,
+ NULL
+ );
+ InstallMemoryAttributesTableOnMemoryAllocation (MemoryType);
+ ApplyMemoryProtectionPolicy (
+ EfiConventionalMemory,
+ MemoryType,
+ *Memory,
+ EFI_PAGES_TO_SIZE (NumberOfPages)
+ );
+ }
+
+ return Status;
+}
+
+/**
+ Frees previous allocated pages.
+
+ @param Memory Base address of memory being freed
+ @param NumberOfPages The number of pages to free
+ @param MemoryType Pointer to memory type
+
+ @retval EFI_NOT_FOUND Could not find the entry that covers the range
+ @retval EFI_INVALID_PARAMETER Address not aligned
+ @return EFI_SUCCESS -Pages successfully freed.
+
+**/
+EFI_STATUS
+EFIAPI
+CoreInternalFreePages (
+ IN EFI_PHYSICAL_ADDRESS Memory,
+ IN UINTN NumberOfPages,
+ OUT EFI_MEMORY_TYPE *MemoryType OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+ LIST_ENTRY *Link;
+ MEMORY_MAP *Entry;
+ UINTN Alignment;
+ BOOLEAN IsGuarded;
+
+ //
+ // Free the range
+ //
+ CoreAcquireMemoryLock ();
+
+ //
+ // Find the entry that the covers the range
+ //
+ IsGuarded = FALSE;
+ Entry = NULL;
+ for (Link = gMemoryMap.ForwardLink; Link != &gMemoryMap; Link = Link->ForwardLink) {
+ Entry = CR (Link, MEMORY_MAP, Link, MEMORY_MAP_SIGNATURE);
+ if ((Entry->Start <= Memory) && (Entry->End > Memory)) {
+ break;
+ }
+ }
+
+ if (Link == &gMemoryMap) {
+ Status = EFI_NOT_FOUND;
+ goto Done;
+ }
+
+ if (Entry == NULL) {
+ ASSERT (Entry != NULL);
+ Status = EFI_NOT_FOUND;
+ goto Done;
+ }
+
+ Alignment = DEFAULT_PAGE_ALLOCATION_GRANULARITY;
+
+ if ((Entry->Type == EfiReservedMemoryType) ||
+ (Entry->Type == EfiACPIMemoryNVS) ||
+ (Entry->Type == EfiRuntimeServicesCode) ||
+ (Entry->Type == EfiRuntimeServicesData))
+ {
+ Alignment = RUNTIME_PAGE_ALLOCATION_GRANULARITY;
+ }
+
+ if ((Memory & (Alignment - 1)) != 0) {
+ Status = EFI_INVALID_PARAMETER;
+ goto Done;
+ }
+
+ NumberOfPages += EFI_SIZE_TO_PAGES (Alignment) - 1;
+ NumberOfPages &= ~(EFI_SIZE_TO_PAGES (Alignment) - 1);
+
+ if (MemoryType != NULL) {
+ *MemoryType = Entry->Type;
+ }
+
+ IsGuarded = IsPageTypeToGuard (Entry->Type, AllocateAnyPages) &&
+ IsMemoryGuarded (Memory);
+ if (IsGuarded) {
+ Status = CoreConvertPagesWithGuard (
+ Memory,
+ NumberOfPages,
+ EfiConventionalMemory
+ );
+ } else {
+ Status = CoreConvertPages (Memory, NumberOfPages, EfiConventionalMemory);
+ }
+
+Done:
+ CoreReleaseMemoryLock ();
+ return Status;
+}
+
+/**
+ Frees previous allocated pages.
+
+ @param Memory Base address of memory being freed
+ @param NumberOfPages The number of pages to free
+
+ @retval EFI_NOT_FOUND Could not find the entry that covers the range
+ @retval EFI_INVALID_PARAMETER Address not aligned
+ @return EFI_SUCCESS -Pages successfully freed.
+
+**/
+EFI_STATUS
+EFIAPI
+CoreFreePages (
+ IN EFI_PHYSICAL_ADDRESS Memory,
+ IN UINTN NumberOfPages
+ )
+{
+ EFI_STATUS Status;
+ EFI_MEMORY_TYPE MemoryType;
+
+ Status = CoreInternalFreePages (Memory, NumberOfPages, &MemoryType);
+ if (!EFI_ERROR (Status)) {
+ GuardFreedPagesChecked (Memory, NumberOfPages);
+ CoreUpdateProfile (
+ (EFI_PHYSICAL_ADDRESS)(UINTN)RETURN_ADDRESS (0),
+ MemoryProfileActionFreePages,
+ MemoryType,
+ EFI_PAGES_TO_SIZE (NumberOfPages),
+ (VOID *)(UINTN)Memory,
+ NULL
+ );
+ InstallMemoryAttributesTableOnMemoryAllocation (MemoryType);
+ ApplyMemoryProtectionPolicy (
+ MemoryType,
+ EfiConventionalMemory,
+ Memory,
+ EFI_PAGES_TO_SIZE (NumberOfPages)
+ );
+ }
+
+ return Status;
+}
+
+/**
+ This function checks to see if the last memory map descriptor in a memory map
+ can be merged with any of the other memory map descriptors in a memorymap.
+ Memory descriptors may be merged if they are adjacent and have the same type
+ and attributes.
+
+ @param MemoryMap A pointer to the start of the memory map.
+ @param MemoryMapDescriptor A pointer to the last descriptor in MemoryMap.
+ @param DescriptorSize The size, in bytes, of an individual
+ EFI_MEMORY_DESCRIPTOR.
+
+ @return A pointer to the next available descriptor in MemoryMap
+
+**/
+EFI_MEMORY_DESCRIPTOR *
+MergeMemoryMapDescriptor (
+ IN EFI_MEMORY_DESCRIPTOR *MemoryMap,
+ IN EFI_MEMORY_DESCRIPTOR *MemoryMapDescriptor,
+ IN UINTN DescriptorSize
+ )
+{
+ //
+ // Traverse the array of descriptors in MemoryMap
+ //
+ for ( ; MemoryMap != MemoryMapDescriptor; MemoryMap = NEXT_MEMORY_DESCRIPTOR (MemoryMap, DescriptorSize)) {
+ //
+ // Check to see if the Type fields are identical.
+ //
+ if (MemoryMap->Type != MemoryMapDescriptor->Type) {
+ continue;
+ }
+
+ //
+ // Check to see if the Attribute fields are identical.
+ //
+ if (MemoryMap->Attribute != MemoryMapDescriptor->Attribute) {
+ continue;
+ }
+
+ //
+ // Check to see if MemoryMapDescriptor is immediately above MemoryMap
+ //
+ if (MemoryMap->PhysicalStart + EFI_PAGES_TO_SIZE ((UINTN)MemoryMap->NumberOfPages) == MemoryMapDescriptor->PhysicalStart) {
+ //
+ // Merge MemoryMapDescriptor into MemoryMap
+ //
+ MemoryMap->NumberOfPages += MemoryMapDescriptor->NumberOfPages;
+
+ //
+ // Return MemoryMapDescriptor as the next available slot int he MemoryMap array
+ //
+ return MemoryMapDescriptor;
+ }
+
+ //
+ // Check to see if MemoryMapDescriptor is immediately below MemoryMap
+ //
+ if (MemoryMap->PhysicalStart - EFI_PAGES_TO_SIZE ((UINTN)MemoryMapDescriptor->NumberOfPages) == MemoryMapDescriptor->PhysicalStart) {
+ //
+ // Merge MemoryMapDescriptor into MemoryMap
+ //
+ MemoryMap->PhysicalStart = MemoryMapDescriptor->PhysicalStart;
+ MemoryMap->VirtualStart = MemoryMapDescriptor->VirtualStart;
+ MemoryMap->NumberOfPages += MemoryMapDescriptor->NumberOfPages;
+
+ //
+ // Return MemoryMapDescriptor as the next available slot int he MemoryMap array
+ //
+ return MemoryMapDescriptor;
+ }
+ }
+
+ //
+ // MemoryMapDescrtiptor could not be merged with any descriptors in MemoryMap.
+ //
+ // Return the slot immediately after MemoryMapDescriptor as the next available
+ // slot in the MemoryMap array
+ //
+ return NEXT_MEMORY_DESCRIPTOR (MemoryMapDescriptor, DescriptorSize);
+}
+
+/**
+ This function returns a copy of the current memory map. The map is an array of
+ memory descriptors, each of which describes a contiguous block of memory.
+
+ @param MemoryMapSize A pointer to the size, in bytes, of the
+ MemoryMap buffer. On input, this is the size of
+ the buffer allocated by the caller. On output,
+ it is the size of the buffer returned by the
+ firmware if the buffer was large enough, or the
+ size of the buffer needed to contain the map if
+ the buffer was too small.
+ @param MemoryMap A pointer to the buffer in which firmware places
+ the current memory map.
+ @param MapKey A pointer to the location in which firmware
+ returns the key for the current memory map.
+ @param DescriptorSize A pointer to the location in which firmware
+ returns the size, in bytes, of an individual
+ EFI_MEMORY_DESCRIPTOR.
+ @param DescriptorVersion A pointer to the location in which firmware
+ returns the version number associated with the
+ EFI_MEMORY_DESCRIPTOR.
+
+ @retval EFI_SUCCESS The memory map was returned in the MemoryMap
+ buffer.
+ @retval EFI_BUFFER_TOO_SMALL The MemoryMap buffer was too small. The current
+ buffer size needed to hold the memory map is
+ returned in MemoryMapSize.
+ @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
+
+**/
+EFI_STATUS
+EFIAPI
+CoreGetMemoryMap (
+ IN OUT UINTN *MemoryMapSize,
+ IN OUT EFI_MEMORY_DESCRIPTOR *MemoryMap,
+ OUT UINTN *MapKey,
+ OUT UINTN *DescriptorSize,
+ OUT UINT32 *DescriptorVersion
+ )
+{
+ EFI_STATUS Status;
+ UINTN Size;
+ UINTN BufferSize;
+ UINTN NumberOfEntries;
+ LIST_ENTRY *Link;
+ MEMORY_MAP *Entry;
+ EFI_GCD_MAP_ENTRY *GcdMapEntry;
+ EFI_GCD_MAP_ENTRY MergeGcdMapEntry;
+ EFI_MEMORY_TYPE Type;
+ EFI_MEMORY_DESCRIPTOR *MemoryMapStart;
+ EFI_MEMORY_DESCRIPTOR *MemoryMapEnd;
+
+ //
+ // Make sure the parameters are valid
+ //
+ if (MemoryMapSize == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ CoreAcquireGcdMemoryLock ();
+
+ //
+ // Count the number of Reserved and runtime MMIO entries
+ // And, count the number of Persistent entries.
+ //
+ NumberOfEntries = 0;
+ for (Link = mGcdMemorySpaceMap.ForwardLink; Link != &mGcdMemorySpaceMap; Link = Link->ForwardLink) {
+ GcdMapEntry = CR (Link, EFI_GCD_MAP_ENTRY, Link, EFI_GCD_MAP_SIGNATURE);
+ if ((GcdMapEntry->GcdMemoryType == EfiGcdMemoryTypePersistent) ||
+ (GcdMapEntry->GcdMemoryType == EfiGcdMemoryTypeReserved) ||
+ ((GcdMapEntry->GcdMemoryType == EfiGcdMemoryTypeMemoryMappedIo) &&
+ ((GcdMapEntry->Attributes & EFI_MEMORY_RUNTIME) == EFI_MEMORY_RUNTIME)))
+ {
+ NumberOfEntries++;
+ }
+ }
+
+ Size = sizeof (EFI_MEMORY_DESCRIPTOR);
+
+ //
+ // Make sure Size != sizeof(EFI_MEMORY_DESCRIPTOR). This will
+ // prevent people from having pointer math bugs in their code.
+ // now you have to use *DescriptorSize to make things work.
+ //
+ Size += sizeof (UINT64) - (Size % sizeof (UINT64));
+
+ if (DescriptorSize != NULL) {
+ *DescriptorSize = Size;
+ }
+
+ if (DescriptorVersion != NULL) {
+ *DescriptorVersion = EFI_MEMORY_DESCRIPTOR_VERSION;
+ }
+
+ CoreAcquireMemoryLock ();
+
+ //
+ // Compute the buffer size needed to fit the entire map
+ //
+ BufferSize = Size * NumberOfEntries;
+ for (Link = gMemoryMap.ForwardLink; Link != &gMemoryMap; Link = Link->ForwardLink) {
+ BufferSize += Size;
+ }
+
+ if (*MemoryMapSize < BufferSize) {
+ Status = EFI_BUFFER_TOO_SMALL;
+ goto Done;
+ }
+
+ if (MemoryMap == NULL) {
+ Status = EFI_INVALID_PARAMETER;
+ goto Done;
+ }
+
+ //
+ // Build the map
+ //
+ ZeroMem (MemoryMap, BufferSize);
+ MemoryMapStart = MemoryMap;
+ for (Link = gMemoryMap.ForwardLink; Link != &gMemoryMap; Link = Link->ForwardLink) {
+ Entry = CR (Link, MEMORY_MAP, Link, MEMORY_MAP_SIGNATURE);
+ ASSERT (Entry->VirtualStart == 0);
+
+ //
+ // Convert internal map into an EFI_MEMORY_DESCRIPTOR
+ //
+ MemoryMap->Type = Entry->Type;
+ MemoryMap->PhysicalStart = Entry->Start;
+ MemoryMap->VirtualStart = Entry->VirtualStart;
+ MemoryMap->NumberOfPages = RShiftU64 (Entry->End - Entry->Start + 1, EFI_PAGE_SHIFT);
+ //
+ // If the memory type is EfiConventionalMemory, then determine if the range is part of a
+ // memory type bin and needs to be converted to the same memory type as the rest of the
+ // memory type bin in order to minimize EFI Memory Map changes across reboots. This
+ // improves the chances for a successful S4 resume in the presence of minor page allocation
+ // differences across reboots.
+ //
+ if (MemoryMap->Type == EfiConventionalMemory) {
+ for (Type = (EFI_MEMORY_TYPE)0; Type < EfiMaxMemoryType; Type++) {
+ if (mMemoryTypeStatistics[Type].Special &&
+ (mMemoryTypeStatistics[Type].NumberOfPages > 0) &&
+ (Entry->Start >= mMemoryTypeStatistics[Type].BaseAddress) &&
+ (Entry->End <= mMemoryTypeStatistics[Type].MaximumAddress))
+ {
+ MemoryMap->Type = Type;
+ }
+ }
+ }
+
+ MemoryMap->Attribute = Entry->Attribute;
+ if (MemoryMap->Type < EfiMaxMemoryType) {
+ if (mMemoryTypeStatistics[MemoryMap->Type].Runtime) {
+ MemoryMap->Attribute |= EFI_MEMORY_RUNTIME;
+ }
+ }
+
+ //
+ // Check to see if the new Memory Map Descriptor can be merged with an
+ // existing descriptor if they are adjacent and have the same attributes
+ //
+ MemoryMap = MergeMemoryMapDescriptor (MemoryMapStart, MemoryMap, Size);
+ }
+
+ ZeroMem (&MergeGcdMapEntry, sizeof (MergeGcdMapEntry));
+ GcdMapEntry = NULL;
+ for (Link = mGcdMemorySpaceMap.ForwardLink; ; Link = Link->ForwardLink) {
+ if (Link != &mGcdMemorySpaceMap) {
+ //
+ // Merge adjacent same type and attribute GCD memory range
+ //
+ GcdMapEntry = CR (Link, EFI_GCD_MAP_ENTRY, Link, EFI_GCD_MAP_SIGNATURE);
+
+ if ((MergeGcdMapEntry.Capabilities == GcdMapEntry->Capabilities) &&
+ (MergeGcdMapEntry.Attributes == GcdMapEntry->Attributes) &&
+ (MergeGcdMapEntry.GcdMemoryType == GcdMapEntry->GcdMemoryType) &&
+ (MergeGcdMapEntry.GcdIoType == GcdMapEntry->GcdIoType))
+ {
+ MergeGcdMapEntry.EndAddress = GcdMapEntry->EndAddress;
+ continue;
+ }
+ }
+
+ if ((MergeGcdMapEntry.GcdMemoryType == EfiGcdMemoryTypeReserved) ||
+ ((MergeGcdMapEntry.GcdMemoryType == EfiGcdMemoryTypeMemoryMappedIo) &&
+ ((MergeGcdMapEntry.Attributes & EFI_MEMORY_RUNTIME) == EFI_MEMORY_RUNTIME)))
+ {
+ //
+ // Page Align GCD range is required. When it is converted to EFI_MEMORY_DESCRIPTOR,
+ // it will be recorded as page PhysicalStart and NumberOfPages.
+ //
+ ASSERT ((MergeGcdMapEntry.BaseAddress & EFI_PAGE_MASK) == 0);
+ ASSERT (((MergeGcdMapEntry.EndAddress - MergeGcdMapEntry.BaseAddress + 1) & EFI_PAGE_MASK) == 0);
+
+ //
+ // Create EFI_MEMORY_DESCRIPTOR for every Reserved and runtime MMIO GCD entries
+ //
+ MemoryMap->PhysicalStart = MergeGcdMapEntry.BaseAddress;
+ MemoryMap->VirtualStart = 0;
+ MemoryMap->NumberOfPages = RShiftU64 ((MergeGcdMapEntry.EndAddress - MergeGcdMapEntry.BaseAddress + 1), EFI_PAGE_SHIFT);
+ MemoryMap->Attribute = (MergeGcdMapEntry.Attributes & ~EFI_MEMORY_PORT_IO) |
+ (MergeGcdMapEntry.Capabilities & (EFI_CACHE_ATTRIBUTE_MASK | EFI_MEMORY_ATTRIBUTE_MASK));
+
+ if (MergeGcdMapEntry.GcdMemoryType == EfiGcdMemoryTypeReserved) {
+ MemoryMap->Type = EfiReservedMemoryType;
+ } else if (MergeGcdMapEntry.GcdMemoryType == EfiGcdMemoryTypeMemoryMappedIo) {
+ if ((MergeGcdMapEntry.Attributes & EFI_MEMORY_PORT_IO) == EFI_MEMORY_PORT_IO) {
+ MemoryMap->Type = EfiMemoryMappedIOPortSpace;
+ } else {
+ MemoryMap->Type = EfiMemoryMappedIO;
+ }
+ }
+
+ //
+ // Check to see if the new Memory Map Descriptor can be merged with an
+ // existing descriptor if they are adjacent and have the same attributes
+ //
+ MemoryMap = MergeMemoryMapDescriptor (MemoryMapStart, MemoryMap, Size);
+ }
+
+ if (MergeGcdMapEntry.GcdMemoryType == EfiGcdMemoryTypePersistent) {
+ //
+ // Page Align GCD range is required. When it is converted to EFI_MEMORY_DESCRIPTOR,
+ // it will be recorded as page PhysicalStart and NumberOfPages.
+ //
+ ASSERT ((MergeGcdMapEntry.BaseAddress & EFI_PAGE_MASK) == 0);
+ ASSERT (((MergeGcdMapEntry.EndAddress - MergeGcdMapEntry.BaseAddress + 1) & EFI_PAGE_MASK) == 0);
+
+ //
+ // Create EFI_MEMORY_DESCRIPTOR for every Persistent GCD entries
+ //
+ MemoryMap->PhysicalStart = MergeGcdMapEntry.BaseAddress;
+ MemoryMap->VirtualStart = 0;
+ MemoryMap->NumberOfPages = RShiftU64 ((MergeGcdMapEntry.EndAddress - MergeGcdMapEntry.BaseAddress + 1), EFI_PAGE_SHIFT);
+ MemoryMap->Attribute = MergeGcdMapEntry.Attributes | EFI_MEMORY_NV |
+ (MergeGcdMapEntry.Capabilities & (EFI_CACHE_ATTRIBUTE_MASK | EFI_MEMORY_ATTRIBUTE_MASK));
+ MemoryMap->Type = EfiPersistentMemory;
+
+ //
+ // Check to see if the new Memory Map Descriptor can be merged with an
+ // existing descriptor if they are adjacent and have the same attributes
+ //
+ MemoryMap = MergeMemoryMapDescriptor (MemoryMapStart, MemoryMap, Size);
+ }
+
+ if (MergeGcdMapEntry.GcdMemoryType == EfiGcdMemoryTypeUnaccepted) {
+ //
+ // Page Align GCD range is required. When it is converted to EFI_MEMORY_DESCRIPTOR,
+ // it will be recorded as page PhysicalStart and NumberOfPages.
+ //
+ ASSERT ((MergeGcdMapEntry.BaseAddress & EFI_PAGE_MASK) == 0);
+ ASSERT (((MergeGcdMapEntry.EndAddress - MergeGcdMapEntry.BaseAddress + 1) & EFI_PAGE_MASK) == 0);
+
+ //
+ // Create EFI_MEMORY_DESCRIPTOR for every Unaccepted GCD entries
+ //
+ MemoryMap->PhysicalStart = MergeGcdMapEntry.BaseAddress;
+ MemoryMap->VirtualStart = 0;
+ MemoryMap->NumberOfPages = RShiftU64 ((MergeGcdMapEntry.EndAddress - MergeGcdMapEntry.BaseAddress + 1), EFI_PAGE_SHIFT);
+ MemoryMap->Attribute = MergeGcdMapEntry.Attributes |
+ (MergeGcdMapEntry.Capabilities & (EFI_MEMORY_RP | EFI_MEMORY_WP | EFI_MEMORY_XP | EFI_MEMORY_RO |
+ EFI_MEMORY_UC | EFI_MEMORY_UCE | EFI_MEMORY_WC | EFI_MEMORY_WT | EFI_MEMORY_WB));
+ MemoryMap->Type = EfiUnacceptedMemoryType;
+
+ //
+ // Check to see if the new Memory Map Descriptor can be merged with an
+ // existing descriptor if they are adjacent and have the same attributes
+ //
+ MemoryMap = MergeMemoryMapDescriptor (MemoryMapStart, MemoryMap, Size);
+ }
+
+ if (Link == &mGcdMemorySpaceMap) {
+ //
+ // break loop when arrive at head.
+ //
+ break;
+ }
+
+ if (GcdMapEntry != NULL) {
+ //
+ // Copy new GCD map entry for the following GCD range merge
+ //
+ CopyMem (&MergeGcdMapEntry, GcdMapEntry, sizeof (MergeGcdMapEntry));
+ }
+ }
+
+ //
+ // Compute the size of the buffer actually used after all memory map descriptor merge operations
+ //
+ BufferSize = ((UINT8 *)MemoryMap - (UINT8 *)MemoryMapStart);
+
+ //
+ // Note: Some OSs will treat EFI_MEMORY_DESCRIPTOR.Attribute as really
+ // set attributes and change memory paging attribute accordingly.
+ // But current EFI_MEMORY_DESCRIPTOR.Attribute is assigned by
+ // value from Capabilities in GCD memory map. This might cause
+ // boot problems. Clearing all page-access permission related
+ // capabilities can workaround it. Following code is supposed to
+ // be removed once the usage of EFI_MEMORY_DESCRIPTOR.Attribute
+ // is clarified in UEFI spec and adopted by both EDK-II Core and
+ // all supported OSs.
+ //
+ MemoryMapEnd = MemoryMap;
+ MemoryMap = MemoryMapStart;
+ while (MemoryMap < MemoryMapEnd) {
+ MemoryMap->Attribute &= ~(UINT64)EFI_MEMORY_ACCESS_MASK;
+ MemoryMap = NEXT_MEMORY_DESCRIPTOR (MemoryMap, Size);
+ }
+
+ MergeMemoryMap (MemoryMapStart, &BufferSize, Size);
+ MemoryMapEnd = (EFI_MEMORY_DESCRIPTOR *)((UINT8 *)MemoryMapStart + BufferSize);
+
+ Status = EFI_SUCCESS;
+
+Done:
+ //
+ // Update the map key finally
+ //
+ if (MapKey != NULL) {
+ *MapKey = mMemoryMapKey;
+ }
+
+ CoreReleaseMemoryLock ();
+
+ CoreReleaseGcdMemoryLock ();
+
+ *MemoryMapSize = BufferSize;
+
+ DEBUG_CODE (
+ DumpGuardedMemoryBitmap ();
+ );
+
+ return Status;
+}
+
+/**
+ Internal function. Used by the pool functions to allocate pages
+ to back pool allocation requests.
+
+ @param PoolType The type of memory for the new pool pages
+ @param NumberOfPages No of pages to allocate
+ @param Alignment Bits to align.
+ @param NeedGuard Flag to indicate Guard page is needed or not
+
+ @return The allocated memory, or NULL
+
+**/
+VOID *
+CoreAllocatePoolPages (
+ IN EFI_MEMORY_TYPE PoolType,
+ IN UINTN NumberOfPages,
+ IN UINTN Alignment,
+ IN BOOLEAN NeedGuard
+ )
+{
+ UINT64 Start;
+
+ //
+ // Find the pages to convert
+ //
+ Start = FindFreePages (
+ MAX_ALLOC_ADDRESS,
+ NumberOfPages,
+ PoolType,
+ Alignment,
+ NeedGuard
+ );
+
+ //
+ // Convert it to boot services data
+ //
+ if (Start == 0) {
+ DEBUG ((DEBUG_ERROR | DEBUG_PAGE, "AllocatePoolPages: failed to allocate %d pages\n", (UINT32)NumberOfPages));
+ } else {
+ if (NeedGuard) {
+ CoreConvertPagesWithGuard (Start, NumberOfPages, PoolType);
+ } else {
+ CoreConvertPages (Start, NumberOfPages, PoolType);
+ }
+ }
+
+ return (VOID *)(UINTN)Start;
+}
+
+/**
+ Internal function. Frees pool pages allocated via AllocatePoolPages ()
+
+ @param Memory The base address to free
+ @param NumberOfPages The number of pages to free
+
+**/
+VOID
+CoreFreePoolPages (
+ IN EFI_PHYSICAL_ADDRESS Memory,
+ IN UINTN NumberOfPages
+ )
+{
+ CoreConvertPages (Memory, NumberOfPages, EfiConventionalMemory);
+}
+
+/**
+ Make sure the memory map is following all the construction rules,
+ it is the last time to check memory map error before exit boot services.
+
+ @param MapKey Memory map key
+
+ @retval EFI_INVALID_PARAMETER Memory map not consistent with construction
+ rules.
+ @retval EFI_SUCCESS Valid memory map.
+
+**/
+EFI_STATUS
+CoreTerminateMemoryMap (
+ IN UINTN MapKey
+ )
+{
+ EFI_STATUS Status;
+ LIST_ENTRY *Link;
+ MEMORY_MAP *Entry;
+
+ Status = EFI_SUCCESS;
+
+ CoreAcquireMemoryLock ();
+
+ if (MapKey == mMemoryMapKey) {
+ //
+ // Make sure the memory map is following all the construction rules
+ // This is the last chance we will be able to display any messages on
+ // the console devices.
+ //
+
+ for (Link = gMemoryMap.ForwardLink; Link != &gMemoryMap; Link = Link->ForwardLink) {
+ Entry = CR (Link, MEMORY_MAP, Link, MEMORY_MAP_SIGNATURE);
+ if (Entry->Type < EfiMaxMemoryType) {
+ if (mMemoryTypeStatistics[Entry->Type].Runtime) {
+ ASSERT (Entry->Type != EfiACPIReclaimMemory);
+ ASSERT (Entry->Type != EfiACPIMemoryNVS);
+ if ((Entry->Start & (RUNTIME_PAGE_ALLOCATION_GRANULARITY - 1)) != 0) {
+ DEBUG ((DEBUG_ERROR | DEBUG_PAGE, "ExitBootServices: A RUNTIME memory entry is not on a proper alignment.\n"));
+ Status = EFI_INVALID_PARAMETER;
+ goto Done;
+ }
+
+ if (((Entry->End + 1) & (RUNTIME_PAGE_ALLOCATION_GRANULARITY - 1)) != 0) {
+ DEBUG ((DEBUG_ERROR | DEBUG_PAGE, "ExitBootServices: A RUNTIME memory entry is not on a proper alignment.\n"));
+ Status = EFI_INVALID_PARAMETER;
+ goto Done;
+ }
+ }
+ }
+ }
+
+ //
+ // The map key they gave us matches what we expect. Fall through and
+ // return success. In an ideal world we would clear out all of
+ // EfiBootServicesCode and EfiBootServicesData. However this function
+ // is not the last one called by ExitBootServices(), so we have to
+ // preserve the memory contents.
+ //
+ } else {
+ Status = EFI_INVALID_PARAMETER;
+ }
+
+Done:
+ CoreReleaseMemoryLock ();
+
+ return Status;
+}
diff --git a/MdeModulePkg/Core/Dxe/Mem/Pool.c b/MdeModulePkg/Core/Dxe/Mem/Pool.c
index 72293e6dfe..4a7e97708b 100644
--- a/MdeModulePkg/Core/Dxe/Mem/Pool.c
+++ b/MdeModulePkg/Core/Dxe/Mem/Pool.c
@@ -1,882 +1,882 @@
-/** @file
- UEFI Memory pool management functions.
-
-Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
-SPDX-License-Identifier: BSD-2-Clause-Patent
-
-**/
-
-#include "DxeMain.h"
-#include "Imem.h"
-#include "HeapGuard.h"
-
-STATIC EFI_LOCK mPoolMemoryLock = EFI_INITIALIZE_LOCK_VARIABLE (TPL_NOTIFY);
-
-#define POOL_FREE_SIGNATURE SIGNATURE_32('p','f','r','0')
-typedef struct {
- UINT32 Signature;
- UINT32 Index;
- LIST_ENTRY Link;
-} POOL_FREE;
-
-#define POOL_HEAD_SIGNATURE SIGNATURE_32('p','h','d','0')
-#define POOLPAGE_HEAD_SIGNATURE SIGNATURE_32('p','h','d','1')
-typedef struct {
- UINT32 Signature;
- UINT32 Reserved;
- EFI_MEMORY_TYPE Type;
- UINTN Size;
- CHAR8 Data[1];
-} POOL_HEAD;
-
-#define SIZE_OF_POOL_HEAD OFFSET_OF(POOL_HEAD,Data)
-
-#define POOL_TAIL_SIGNATURE SIGNATURE_32('p','t','a','l')
-typedef struct {
- UINT32 Signature;
- UINT32 Reserved;
- UINTN Size;
-} POOL_TAIL;
-
-#define POOL_OVERHEAD (SIZE_OF_POOL_HEAD + sizeof(POOL_TAIL))
-
-#define HEAD_TO_TAIL(a) \
- ((POOL_TAIL *) (((CHAR8 *) (a)) + (a)->Size - sizeof(POOL_TAIL)));
-
-//
-// Each element is the sum of the 2 previous ones: this allows us to migrate
-// blocks between bins by splitting them up, while not wasting too much memory
-// as we would in a strict power-of-2 sequence
-//
-STATIC CONST UINT16 mPoolSizeTable[] = {
- 128, 256, 384, 640, 1024, 1664, 2688, 4352, 7040, 11392, 18432, 29824
-};
-
-#define SIZE_TO_LIST(a) (GetPoolIndexFromSize (a))
-#define LIST_TO_SIZE(a) (mPoolSizeTable [a])
-
-#define MAX_POOL_LIST (ARRAY_SIZE (mPoolSizeTable))
-
-#define MAX_POOL_SIZE (MAX_ADDRESS - POOL_OVERHEAD)
-
-//
-// Globals
-//
-
-#define POOL_SIGNATURE SIGNATURE_32('p','l','s','t')
-typedef struct {
- INTN Signature;
- UINTN Used;
- EFI_MEMORY_TYPE MemoryType;
- LIST_ENTRY FreeList[MAX_POOL_LIST];
- LIST_ENTRY Link;
-} POOL;
-
-//
-// Pool header for each memory type.
-//
-POOL mPoolHead[EfiMaxMemoryType];
-
-//
-// List of pool header to search for the appropriate memory type.
-//
-LIST_ENTRY mPoolHeadList = INITIALIZE_LIST_HEAD_VARIABLE (mPoolHeadList);
-
-/**
- Get pool size table index from the specified size.
-
- @param Size The specified size to get index from pool table.
-
- @return The index of pool size table.
-
-**/
-STATIC
-UINTN
-GetPoolIndexFromSize (
- UINTN Size
- )
-{
- UINTN Index;
-
- for (Index = 0; Index < MAX_POOL_LIST; Index++) {
- if (mPoolSizeTable[Index] >= Size) {
- return Index;
- }
- }
-
- return MAX_POOL_LIST;
-}
-
-/**
- Called to initialize the pool.
-
-**/
-VOID
-CoreInitializePool (
- VOID
- )
-{
- UINTN Type;
- UINTN Index;
-
- for (Type = 0; Type < EfiMaxMemoryType; Type++) {
- mPoolHead[Type].Signature = 0;
- mPoolHead[Type].Used = 0;
- mPoolHead[Type].MemoryType = (EFI_MEMORY_TYPE)Type;
- for (Index = 0; Index < MAX_POOL_LIST; Index++) {
- InitializeListHead (&mPoolHead[Type].FreeList[Index]);
- }
- }
-}
-
-/**
- Look up pool head for specified memory type.
-
- @param MemoryType Memory type of which pool head is looked for
-
- @return Pointer of Corresponding pool head.
-
-**/
-POOL *
-LookupPoolHead (
- IN EFI_MEMORY_TYPE MemoryType
- )
-{
- LIST_ENTRY *Link;
- POOL *Pool;
- UINTN Index;
-
- if ((UINT32)MemoryType < EfiMaxMemoryType) {
- return &mPoolHead[MemoryType];
- }
-
- //
- // MemoryType values in the range 0x80000000..0xFFFFFFFF are reserved for use by UEFI
- // OS loaders that are provided by operating system vendors.
- // MemoryType values in the range 0x70000000..0x7FFFFFFF are reserved for OEM use.
- //
- if ((UINT32)MemoryType >= MEMORY_TYPE_OEM_RESERVED_MIN) {
- for (Link = mPoolHeadList.ForwardLink; Link != &mPoolHeadList; Link = Link->ForwardLink) {
- Pool = CR (Link, POOL, Link, POOL_SIGNATURE);
- if (Pool->MemoryType == MemoryType) {
- return Pool;
- }
- }
-
- Pool = CoreAllocatePoolI (EfiBootServicesData, sizeof (POOL), FALSE);
- if (Pool == NULL) {
- return NULL;
- }
-
- Pool->Signature = POOL_SIGNATURE;
- Pool->Used = 0;
- Pool->MemoryType = MemoryType;
- for (Index = 0; Index < MAX_POOL_LIST; Index++) {
- InitializeListHead (&Pool->FreeList[Index]);
- }
-
- InsertHeadList (&mPoolHeadList, &Pool->Link);
-
- return Pool;
- }
-
- return NULL;
-}
-
-/**
- Allocate pool of a particular type.
-
- @param PoolType Type of pool to allocate
- @param Size The amount of pool to allocate
- @param Buffer The address to return a pointer to the allocated
- pool
-
- @retval EFI_INVALID_PARAMETER Buffer is NULL.
- PoolType is in the range EfiMaxMemoryType..0x6FFFFFFF.
- PoolType is EfiPersistentMemory.
- @retval EFI_OUT_OF_RESOURCES Size exceeds max pool size or allocation failed.
- @retval EFI_SUCCESS Pool successfully allocated.
-
-**/
-EFI_STATUS
-EFIAPI
-CoreInternalAllocatePool (
- IN EFI_MEMORY_TYPE PoolType,
- IN UINTN Size,
- OUT VOID **Buffer
- )
-{
- EFI_STATUS Status;
- BOOLEAN NeedGuard;
-
- //
- // If it's not a valid type, fail it
- //
- if (((PoolType >= EfiMaxMemoryType) && (PoolType < MEMORY_TYPE_OEM_RESERVED_MIN)) ||
- (PoolType == EfiConventionalMemory) || (PoolType == EfiPersistentMemory) || (PoolType == EfiUnacceptedMemoryType))
- {
- return EFI_INVALID_PARAMETER;
- }
-
- if (Buffer == NULL) {
- return EFI_INVALID_PARAMETER;
- }
-
- *Buffer = NULL;
-
- //
- // If size is too large, fail it
- // Base on the EFI spec, return status of EFI_OUT_OF_RESOURCES
- //
- if (Size > MAX_POOL_SIZE) {
- return EFI_OUT_OF_RESOURCES;
- }
-
- NeedGuard = IsPoolTypeToGuard (PoolType) && !mOnGuarding;
-
- //
- // Acquire the memory lock and make the allocation
- //
- Status = CoreAcquireLockOrFail (&mPoolMemoryLock);
- if (EFI_ERROR (Status)) {
- return EFI_OUT_OF_RESOURCES;
- }
-
- *Buffer = CoreAllocatePoolI (PoolType, Size, NeedGuard);
- CoreReleaseLock (&mPoolMemoryLock);
- return (*Buffer != NULL) ? EFI_SUCCESS : EFI_OUT_OF_RESOURCES;
-}
-
-/**
- Allocate pool of a particular type.
-
- @param PoolType Type of pool to allocate
- @param Size The amount of pool to allocate
- @param Buffer The address to return a pointer to the allocated
- pool
-
- @retval EFI_INVALID_PARAMETER Buffer is NULL.
- PoolType is in the range EfiMaxMemoryType..0x6FFFFFFF.
- PoolType is EfiPersistentMemory.
- @retval EFI_OUT_OF_RESOURCES Size exceeds max pool size or allocation failed.
- @retval EFI_SUCCESS Pool successfully allocated.
-
-**/
-EFI_STATUS
-EFIAPI
-CoreAllocatePool (
- IN EFI_MEMORY_TYPE PoolType,
- IN UINTN Size,
- OUT VOID **Buffer
- )
-{
- EFI_STATUS Status;
-
- Status = CoreInternalAllocatePool (PoolType, Size, Buffer);
- if (!EFI_ERROR (Status)) {
- CoreUpdateProfile (
- (EFI_PHYSICAL_ADDRESS)(UINTN)RETURN_ADDRESS (0),
- MemoryProfileActionAllocatePool,
- PoolType,
- Size,
- *Buffer,
- NULL
- );
- InstallMemoryAttributesTableOnMemoryAllocation (PoolType);
- }
-
- return Status;
-}
-
-/**
- Internal function. Used by the pool functions to allocate pages
- to back pool allocation requests.
-
- @param PoolType The type of memory for the new pool pages
- @param NoPages No of pages to allocate
- @param Granularity Bits to align.
- @param NeedGuard Flag to indicate Guard page is needed or not
-
- @return The allocated memory, or NULL
-
-**/
-STATIC
-VOID *
-CoreAllocatePoolPagesI (
- IN EFI_MEMORY_TYPE PoolType,
- IN UINTN NoPages,
- IN UINTN Granularity,
- IN BOOLEAN NeedGuard
- )
-{
- VOID *Buffer;
- EFI_STATUS Status;
-
- Status = CoreAcquireLockOrFail (&gMemoryLock);
- if (EFI_ERROR (Status)) {
- return NULL;
- }
-
- Buffer = CoreAllocatePoolPages (PoolType, NoPages, Granularity, NeedGuard);
- CoreReleaseMemoryLock ();
-
- if (Buffer != NULL) {
- if (NeedGuard) {
- SetGuardForMemory ((EFI_PHYSICAL_ADDRESS)(UINTN)Buffer, NoPages);
- }
-
- ApplyMemoryProtectionPolicy (
- EfiConventionalMemory,
- PoolType,
- (EFI_PHYSICAL_ADDRESS)(UINTN)Buffer,
- EFI_PAGES_TO_SIZE (NoPages)
- );
- }
-
- return Buffer;
-}
-
-/**
- Internal function to allocate pool of a particular type.
- Caller must have the memory lock held
-
- @param PoolType Type of pool to allocate
- @param Size The amount of pool to allocate
- @param NeedGuard Flag to indicate Guard page is needed or not
-
- @return The allocate pool, or NULL
-
-**/
-VOID *
-CoreAllocatePoolI (
- IN EFI_MEMORY_TYPE PoolType,
- IN UINTN Size,
- IN BOOLEAN NeedGuard
- )
-{
- POOL *Pool;
- POOL_FREE *Free;
- POOL_HEAD *Head;
- POOL_TAIL *Tail;
- CHAR8 *NewPage;
- VOID *Buffer;
- UINTN Index;
- UINTN FSize;
- UINTN Offset, MaxOffset;
- UINTN NoPages;
- UINTN Granularity;
- BOOLEAN HasPoolTail;
- BOOLEAN PageAsPool;
-
- ASSERT_LOCKED (&mPoolMemoryLock);
-
- if ((PoolType == EfiReservedMemoryType) ||
- (PoolType == EfiACPIMemoryNVS) ||
- (PoolType == EfiRuntimeServicesCode) ||
- (PoolType == EfiRuntimeServicesData))
- {
- Granularity = RUNTIME_PAGE_ALLOCATION_GRANULARITY;
- } else {
- Granularity = DEFAULT_PAGE_ALLOCATION_GRANULARITY;
- }
-
- //
- // The heap guard system does not support non-EFI_PAGE_SIZE alignments.
- // Architectures that require larger RUNTIME_PAGE_ALLOCATION_GRANULARITY
- // will have the runtime memory regions unguarded. OSes do not
- // map guard pages anyway, so this is a minimal loss. Not guarding prevents
- // alignment mismatches
- //
- if (Granularity != EFI_PAGE_SIZE) {
- NeedGuard = FALSE;
- }
-
- //
- // Adjust the size by the pool header & tail overhead
- //
-
- HasPoolTail = !(NeedGuard &&
- ((PcdGet8 (PcdHeapGuardPropertyMask) & BIT7) == 0));
- PageAsPool = (IsHeapGuardEnabled (GUARD_HEAP_TYPE_FREED) && !mOnGuarding);
-
- //
- // Adjusting the Size to be of proper alignment so that
- // we don't get an unaligned access fault later when
- // pool_Tail is being initialized
- //
- Size = ALIGN_VARIABLE (Size);
-
- Size += POOL_OVERHEAD;
- Index = SIZE_TO_LIST (Size);
- Pool = LookupPoolHead (PoolType);
- if (Pool == NULL) {
- return NULL;
- }
-
- Head = NULL;
-
- //
- // If allocation is over max size, just allocate pages for the request
- // (slow)
- //
- if ((Index >= SIZE_TO_LIST (Granularity)) || NeedGuard || PageAsPool) {
- if (!HasPoolTail) {
- Size -= sizeof (POOL_TAIL);
- }
-
- NoPages = EFI_SIZE_TO_PAGES (Size) + EFI_SIZE_TO_PAGES (Granularity) - 1;
- NoPages &= ~(UINTN)(EFI_SIZE_TO_PAGES (Granularity) - 1);
- Head = CoreAllocatePoolPagesI (PoolType, NoPages, Granularity, NeedGuard);
- if (NeedGuard) {
- Head = AdjustPoolHeadA ((EFI_PHYSICAL_ADDRESS)(UINTN)Head, NoPages, Size);
- }
-
- goto Done;
- }
-
- //
- // If there's no free pool in the proper list size, go get some more pages
- //
- if (IsListEmpty (&Pool->FreeList[Index])) {
- Offset = LIST_TO_SIZE (Index);
- MaxOffset = Granularity;
-
- //
- // Check the bins holding larger blocks, and carve one up if needed
- //
- while (++Index < SIZE_TO_LIST (Granularity)) {
- if (!IsListEmpty (&Pool->FreeList[Index])) {
- Free = CR (Pool->FreeList[Index].ForwardLink, POOL_FREE, Link, POOL_FREE_SIGNATURE);
- RemoveEntryList (&Free->Link);
- NewPage = (VOID *)Free;
- MaxOffset = LIST_TO_SIZE (Index);
- goto Carve;
- }
- }
-
- //
- // Get another page
- //
- NewPage = CoreAllocatePoolPagesI (
- PoolType,
- EFI_SIZE_TO_PAGES (Granularity),
- Granularity,
- NeedGuard
- );
- if (NewPage == NULL) {
- goto Done;
- }
-
- //
- // Serve the allocation request from the head of the allocated block
- //
-Carve:
- Head = (POOL_HEAD *)NewPage;
-
- //
- // Carve up remaining space into free pool blocks
- //
- Index--;
- while (Offset < MaxOffset) {
- ASSERT (Index < MAX_POOL_LIST);
- FSize = LIST_TO_SIZE (Index);
-
- while (Offset + FSize <= MaxOffset) {
- Free = (POOL_FREE *)&NewPage[Offset];
- Free->Signature = POOL_FREE_SIGNATURE;
- Free->Index = (UINT32)Index;
- InsertHeadList (&Pool->FreeList[Index], &Free->Link);
- Offset += FSize;
- }
-
- Index -= 1;
- }
-
- ASSERT (Offset == MaxOffset);
- goto Done;
- }
-
- //
- // Remove entry from free pool list
- //
- Free = CR (Pool->FreeList[Index].ForwardLink, POOL_FREE, Link, POOL_FREE_SIGNATURE);
- RemoveEntryList (&Free->Link);
-
- Head = (POOL_HEAD *)Free;
-
-Done:
- Buffer = NULL;
-
- if (Head != NULL) {
- //
- // Account the allocation
- //
- Pool->Used += Size;
-
- //
- // If we have a pool buffer, fill in the header & tail info
- //
- Head->Signature = (PageAsPool) ? POOLPAGE_HEAD_SIGNATURE : POOL_HEAD_SIGNATURE;
- Head->Size = Size;
- Head->Type = (EFI_MEMORY_TYPE)PoolType;
- Buffer = Head->Data;
-
- if (HasPoolTail) {
- Tail = HEAD_TO_TAIL (Head);
- Tail->Signature = POOL_TAIL_SIGNATURE;
- Tail->Size = Size;
-
- Size -= POOL_OVERHEAD;
- } else {
- Size -= SIZE_OF_POOL_HEAD;
- }
-
- DEBUG_CLEAR_MEMORY (Buffer, Size);
-
- DEBUG ((
- DEBUG_POOL,
- "AllocatePoolI: Type %x, Addr %p (len %lx) %,ld\n",
- PoolType,
- Buffer,
- (UINT64)Size,
- (UINT64)Pool->Used
- ));
- } else {
- DEBUG ((DEBUG_ERROR | DEBUG_POOL, "AllocatePool: failed to allocate %ld bytes\n", (UINT64)Size));
- }
-
- return Buffer;
-}
-
-/**
- Frees pool.
-
- @param Buffer The allocated pool entry to free
- @param PoolType Pointer to pool type
-
- @retval EFI_INVALID_PARAMETER Buffer is not a valid value.
- @retval EFI_SUCCESS Pool successfully freed.
-
-**/
-EFI_STATUS
-EFIAPI
-CoreInternalFreePool (
- IN VOID *Buffer,
- OUT EFI_MEMORY_TYPE *PoolType OPTIONAL
- )
-{
- EFI_STATUS Status;
-
- if (Buffer == NULL) {
- return EFI_INVALID_PARAMETER;
- }
-
- CoreAcquireLock (&mPoolMemoryLock);
- Status = CoreFreePoolI (Buffer, PoolType);
- CoreReleaseLock (&mPoolMemoryLock);
- return Status;
-}
-
-/**
- Frees pool.
-
- @param Buffer The allocated pool entry to free
-
- @retval EFI_INVALID_PARAMETER Buffer is not a valid value.
- @retval EFI_SUCCESS Pool successfully freed.
-
-**/
-EFI_STATUS
-EFIAPI
-CoreFreePool (
- IN VOID *Buffer
- )
-{
- EFI_STATUS Status;
- EFI_MEMORY_TYPE PoolType;
-
- Status = CoreInternalFreePool (Buffer, &PoolType);
- if (!EFI_ERROR (Status)) {
- CoreUpdateProfile (
- (EFI_PHYSICAL_ADDRESS)(UINTN)RETURN_ADDRESS (0),
- MemoryProfileActionFreePool,
- PoolType,
- 0,
- Buffer,
- NULL
- );
- InstallMemoryAttributesTableOnMemoryAllocation (PoolType);
- }
-
- return Status;
-}
-
-/**
- Internal function. Frees pool pages allocated via CoreAllocatePoolPagesI().
-
- @param PoolType The type of memory for the pool pages
- @param Memory The base address to free
- @param NoPages The number of pages to free
-
-**/
-STATIC
-VOID
-CoreFreePoolPagesI (
- IN EFI_MEMORY_TYPE PoolType,
- IN EFI_PHYSICAL_ADDRESS Memory,
- IN UINTN NoPages
- )
-{
- CoreAcquireMemoryLock ();
- CoreFreePoolPages (Memory, NoPages);
- CoreReleaseMemoryLock ();
-
- GuardFreedPagesChecked (Memory, NoPages);
- ApplyMemoryProtectionPolicy (
- PoolType,
- EfiConventionalMemory,
- (EFI_PHYSICAL_ADDRESS)(UINTN)Memory,
- EFI_PAGES_TO_SIZE (NoPages)
- );
-}
-
-/**
- Internal function. Frees guarded pool pages.
-
- @param PoolType The type of memory for the pool pages
- @param Memory The base address to free
- @param NoPages The number of pages to free
-
-**/
-STATIC
-VOID
-CoreFreePoolPagesWithGuard (
- IN EFI_MEMORY_TYPE PoolType,
- IN EFI_PHYSICAL_ADDRESS Memory,
- IN UINTN NoPages
- )
-{
- EFI_PHYSICAL_ADDRESS MemoryGuarded;
- UINTN NoPagesGuarded;
-
- MemoryGuarded = Memory;
- NoPagesGuarded = NoPages;
-
- AdjustMemoryF (&Memory, &NoPages);
- //
- // It's safe to unset Guard page inside memory lock because there should
- // be no memory allocation occurred in updating memory page attribute at
- // this point. And unsetting Guard page before free will prevent Guard
- // page just freed back to pool from being allocated right away before
- // marking it usable (from non-present to present).
- //
- UnsetGuardForMemory (MemoryGuarded, NoPagesGuarded);
- if (NoPages > 0) {
- CoreFreePoolPagesI (PoolType, Memory, NoPages);
- }
-}
-
-/**
- Internal function to free a pool entry.
- Caller must have the memory lock held
-
- @param Buffer The allocated pool entry to free
- @param PoolType Pointer to pool type
-
- @retval EFI_INVALID_PARAMETER Buffer not valid
- @retval EFI_SUCCESS Buffer successfully freed.
-
-**/
-EFI_STATUS
-CoreFreePoolI (
- IN VOID *Buffer,
- OUT EFI_MEMORY_TYPE *PoolType OPTIONAL
- )
-{
- POOL *Pool;
- POOL_HEAD *Head;
- POOL_TAIL *Tail;
- POOL_FREE *Free;
- UINTN Index;
- UINTN NoPages;
- UINTN Size;
- CHAR8 *NewPage;
- UINTN Offset;
- BOOLEAN AllFree;
- UINTN Granularity;
- BOOLEAN IsGuarded;
- BOOLEAN HasPoolTail;
- BOOLEAN PageAsPool;
-
- ASSERT (Buffer != NULL);
- //
- // Get the head & tail of the pool entry
- //
- Head = BASE_CR (Buffer, POOL_HEAD, Data);
- ASSERT (Head != NULL);
-
- if ((Head->Signature != POOL_HEAD_SIGNATURE) &&
- (Head->Signature != POOLPAGE_HEAD_SIGNATURE))
- {
- ASSERT (
- Head->Signature == POOL_HEAD_SIGNATURE ||
- Head->Signature == POOLPAGE_HEAD_SIGNATURE
- );
- return EFI_INVALID_PARAMETER;
- }
-
- IsGuarded = IsPoolTypeToGuard (Head->Type) &&
- IsMemoryGuarded ((EFI_PHYSICAL_ADDRESS)(UINTN)Head);
- HasPoolTail = !(IsGuarded &&
- ((PcdGet8 (PcdHeapGuardPropertyMask) & BIT7) == 0));
- PageAsPool = (Head->Signature == POOLPAGE_HEAD_SIGNATURE);
-
- if (HasPoolTail) {
- Tail = HEAD_TO_TAIL (Head);
- ASSERT (Tail != NULL);
-
- //
- // Debug
- //
- ASSERT (Tail->Signature == POOL_TAIL_SIGNATURE);
- ASSERT (Head->Size == Tail->Size);
-
- if (Tail->Signature != POOL_TAIL_SIGNATURE) {
- return EFI_INVALID_PARAMETER;
- }
-
- if (Head->Size != Tail->Size) {
- return EFI_INVALID_PARAMETER;
- }
- }
-
- ASSERT_LOCKED (&mPoolMemoryLock);
-
- //
- // Determine the pool type and account for it
- //
- Size = Head->Size;
- Pool = LookupPoolHead (Head->Type);
- if (Pool == NULL) {
- return EFI_INVALID_PARAMETER;
- }
-
- Pool->Used -= Size;
- DEBUG ((DEBUG_POOL, "FreePool: %p (len %lx) %,ld\n", Head->Data, (UINT64)(Head->Size - POOL_OVERHEAD), (UINT64)Pool->Used));
-
- if ((Head->Type == EfiReservedMemoryType) ||
- (Head->Type == EfiACPIMemoryNVS) ||
- (Head->Type == EfiRuntimeServicesCode) ||
- (Head->Type == EfiRuntimeServicesData))
- {
- Granularity = RUNTIME_PAGE_ALLOCATION_GRANULARITY;
- } else {
- Granularity = DEFAULT_PAGE_ALLOCATION_GRANULARITY;
- }
-
- if (PoolType != NULL) {
- *PoolType = Head->Type;
- }
-
- //
- // Determine the pool list
- //
- Index = SIZE_TO_LIST (Size);
- DEBUG_CLEAR_MEMORY (Head, Size);
-
- //
- // If it's not on the list, it must be pool pages
- //
- if ((Index >= SIZE_TO_LIST (Granularity)) || IsGuarded || PageAsPool) {
- //
- // Return the memory pages back to free memory
- //
- NoPages = EFI_SIZE_TO_PAGES (Size) + EFI_SIZE_TO_PAGES (Granularity) - 1;
- NoPages &= ~(UINTN)(EFI_SIZE_TO_PAGES (Granularity) - 1);
- if (IsGuarded) {
- Head = AdjustPoolHeadF ((EFI_PHYSICAL_ADDRESS)(UINTN)Head, NoPages, Size);
- CoreFreePoolPagesWithGuard (
- Pool->MemoryType,
- (EFI_PHYSICAL_ADDRESS)(UINTN)Head,
- NoPages
- );
- } else {
- CoreFreePoolPagesI (
- Pool->MemoryType,
- (EFI_PHYSICAL_ADDRESS)(UINTN)Head,
- NoPages
- );
- }
- } else {
- //
- // Put the pool entry onto the free pool list
- //
- Free = (POOL_FREE *)Head;
- ASSERT (Free != NULL);
- Free->Signature = POOL_FREE_SIGNATURE;
- Free->Index = (UINT32)Index;
- InsertHeadList (&Pool->FreeList[Index], &Free->Link);
-
- //
- // See if all the pool entries in the same page as Free are freed pool
- // entries
- //
- NewPage = (CHAR8 *)((UINTN)Free & ~(Granularity - 1));
- Free = (POOL_FREE *)&NewPage[0];
- ASSERT (Free != NULL);
-
- if (Free->Signature == POOL_FREE_SIGNATURE) {
- AllFree = TRUE;
- Offset = 0;
-
- while ((Offset < Granularity) && (AllFree)) {
- Free = (POOL_FREE *)&NewPage[Offset];
- ASSERT (Free != NULL);
- if (Free->Signature != POOL_FREE_SIGNATURE) {
- AllFree = FALSE;
- }
-
- Offset += LIST_TO_SIZE (Free->Index);
- }
-
- if (AllFree) {
- //
- // All of the pool entries in the same page as Free are free pool
- // entries
- // Remove all of these pool entries from the free loop lists.
- //
- Free = (POOL_FREE *)&NewPage[0];
- ASSERT (Free != NULL);
- Offset = 0;
-
- while (Offset < Granularity) {
- Free = (POOL_FREE *)&NewPage[Offset];
- ASSERT (Free != NULL);
- RemoveEntryList (&Free->Link);
- Offset += LIST_TO_SIZE (Free->Index);
- }
-
- //
- // Free the page
- //
- CoreFreePoolPagesI (
- Pool->MemoryType,
- (EFI_PHYSICAL_ADDRESS)(UINTN)NewPage,
- EFI_SIZE_TO_PAGES (Granularity)
- );
- }
- }
- }
-
- //
- // If this is an OS/OEM specific memory type, then check to see if the last
- // portion of that memory type has been freed. If it has, then free the
- // list entry for that memory type
- //
- if (((UINT32)Pool->MemoryType >= MEMORY_TYPE_OEM_RESERVED_MIN) && (Pool->Used == 0)) {
- RemoveEntryList (&Pool->Link);
- CoreFreePoolI (Pool, NULL);
- }
-
- return EFI_SUCCESS;
-}
+/** @file
+ UEFI Memory pool management functions.
+
+Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "DxeMain.h"
+#include "Imem.h"
+#include "HeapGuard.h"
+
+STATIC EFI_LOCK mPoolMemoryLock = EFI_INITIALIZE_LOCK_VARIABLE (TPL_NOTIFY);
+
+#define POOL_FREE_SIGNATURE SIGNATURE_32('p','f','r','0')
+typedef struct {
+ UINT32 Signature;
+ UINT32 Index;
+ LIST_ENTRY Link;
+} POOL_FREE;
+
+#define POOL_HEAD_SIGNATURE SIGNATURE_32('p','h','d','0')
+#define POOLPAGE_HEAD_SIGNATURE SIGNATURE_32('p','h','d','1')
+typedef struct {
+ UINT32 Signature;
+ UINT32 Reserved;
+ EFI_MEMORY_TYPE Type;
+ UINTN Size;
+ CHAR8 Data[1];
+} POOL_HEAD;
+
+#define SIZE_OF_POOL_HEAD OFFSET_OF(POOL_HEAD,Data)
+
+#define POOL_TAIL_SIGNATURE SIGNATURE_32('p','t','a','l')
+typedef struct {
+ UINT32 Signature;
+ UINT32 Reserved;
+ UINTN Size;
+} POOL_TAIL;
+
+#define POOL_OVERHEAD (SIZE_OF_POOL_HEAD + sizeof(POOL_TAIL))
+
+#define HEAD_TO_TAIL(a) \
+ ((POOL_TAIL *) (((CHAR8 *) (a)) + (a)->Size - sizeof(POOL_TAIL)));
+
+//
+// Each element is the sum of the 2 previous ones: this allows us to migrate
+// blocks between bins by splitting them up, while not wasting too much memory
+// as we would in a strict power-of-2 sequence
+//
+STATIC CONST UINT16 mPoolSizeTable[] = {
+ 128, 256, 384, 640, 1024, 1664, 2688, 4352, 7040, 11392, 18432, 29824
+};
+
+#define SIZE_TO_LIST(a) (GetPoolIndexFromSize (a))
+#define LIST_TO_SIZE(a) (mPoolSizeTable [a])
+
+#define MAX_POOL_LIST (ARRAY_SIZE (mPoolSizeTable))
+
+#define MAX_POOL_SIZE (MAX_ADDRESS - POOL_OVERHEAD)
+
+//
+// Globals
+//
+
+#define POOL_SIGNATURE SIGNATURE_32('p','l','s','t')
+typedef struct {
+ INTN Signature;
+ UINTN Used;
+ EFI_MEMORY_TYPE MemoryType;
+ LIST_ENTRY FreeList[MAX_POOL_LIST];
+ LIST_ENTRY Link;
+} POOL;
+
+//
+// Pool header for each memory type.
+//
+POOL mPoolHead[EfiMaxMemoryType];
+
+//
+// List of pool header to search for the appropriate memory type.
+//
+LIST_ENTRY mPoolHeadList = INITIALIZE_LIST_HEAD_VARIABLE (mPoolHeadList);
+
+/**
+ Get pool size table index from the specified size.
+
+ @param Size The specified size to get index from pool table.
+
+ @return The index of pool size table.
+
+**/
+STATIC
+UINTN
+GetPoolIndexFromSize (
+ UINTN Size
+ )
+{
+ UINTN Index;
+
+ for (Index = 0; Index < MAX_POOL_LIST; Index++) {
+ if (mPoolSizeTable[Index] >= Size) {
+ return Index;
+ }
+ }
+
+ return MAX_POOL_LIST;
+}
+
+/**
+ Called to initialize the pool.
+
+**/
+VOID
+CoreInitializePool (
+ VOID
+ )
+{
+ UINTN Type;
+ UINTN Index;
+
+ for (Type = 0; Type < EfiMaxMemoryType; Type++) {
+ mPoolHead[Type].Signature = 0;
+ mPoolHead[Type].Used = 0;
+ mPoolHead[Type].MemoryType = (EFI_MEMORY_TYPE)Type;
+ for (Index = 0; Index < MAX_POOL_LIST; Index++) {
+ InitializeListHead (&mPoolHead[Type].FreeList[Index]);
+ }
+ }
+}
+
+/**
+ Look up pool head for specified memory type.
+
+ @param MemoryType Memory type of which pool head is looked for
+
+ @return Pointer of Corresponding pool head.
+
+**/
+POOL *
+LookupPoolHead (
+ IN EFI_MEMORY_TYPE MemoryType
+ )
+{
+ LIST_ENTRY *Link;
+ POOL *Pool;
+ UINTN Index;
+
+ if ((UINT32)MemoryType < EfiMaxMemoryType) {
+ return &mPoolHead[MemoryType];
+ }
+
+ //
+ // MemoryType values in the range 0x80000000..0xFFFFFFFF are reserved for use by UEFI
+ // OS loaders that are provided by operating system vendors.
+ // MemoryType values in the range 0x70000000..0x7FFFFFFF are reserved for OEM use.
+ //
+ if ((UINT32)MemoryType >= MEMORY_TYPE_OEM_RESERVED_MIN) {
+ for (Link = mPoolHeadList.ForwardLink; Link != &mPoolHeadList; Link = Link->ForwardLink) {
+ Pool = CR (Link, POOL, Link, POOL_SIGNATURE);
+ if (Pool->MemoryType == MemoryType) {
+ return Pool;
+ }
+ }
+
+ Pool = CoreAllocatePoolI (EfiBootServicesData, sizeof (POOL), FALSE);
+ if (Pool == NULL) {
+ return NULL;
+ }
+
+ Pool->Signature = POOL_SIGNATURE;
+ Pool->Used = 0;
+ Pool->MemoryType = MemoryType;
+ for (Index = 0; Index < MAX_POOL_LIST; Index++) {
+ InitializeListHead (&Pool->FreeList[Index]);
+ }
+
+ InsertHeadList (&mPoolHeadList, &Pool->Link);
+
+ return Pool;
+ }
+
+ return NULL;
+}
+
+/**
+ Allocate pool of a particular type.
+
+ @param PoolType Type of pool to allocate
+ @param Size The amount of pool to allocate
+ @param Buffer The address to return a pointer to the allocated
+ pool
+
+ @retval EFI_INVALID_PARAMETER Buffer is NULL.
+ PoolType is in the range EfiMaxMemoryType..0x6FFFFFFF.
+ PoolType is EfiPersistentMemory.
+ @retval EFI_OUT_OF_RESOURCES Size exceeds max pool size or allocation failed.
+ @retval EFI_SUCCESS Pool successfully allocated.
+
+**/
+EFI_STATUS
+EFIAPI
+CoreInternalAllocatePool (
+ IN EFI_MEMORY_TYPE PoolType,
+ IN UINTN Size,
+ OUT VOID **Buffer
+ )
+{
+ EFI_STATUS Status;
+ BOOLEAN NeedGuard;
+
+ //
+ // If it's not a valid type, fail it
+ //
+ if (((PoolType >= EfiMaxMemoryType) && (PoolType < MEMORY_TYPE_OEM_RESERVED_MIN)) ||
+ (PoolType == EfiConventionalMemory) || (PoolType == EfiPersistentMemory) || (PoolType == EfiUnacceptedMemoryType))
+ {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (Buffer == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ *Buffer = NULL;
+
+ //
+ // If size is too large, fail it
+ // Base on the EFI spec, return status of EFI_OUT_OF_RESOURCES
+ //
+ if (Size > MAX_POOL_SIZE) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ NeedGuard = IsPoolTypeToGuard (PoolType) && !mOnGuarding;
+
+ //
+ // Acquire the memory lock and make the allocation
+ //
+ Status = CoreAcquireLockOrFail (&mPoolMemoryLock);
+ if (EFI_ERROR (Status)) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ *Buffer = CoreAllocatePoolI (PoolType, Size, NeedGuard);
+ CoreReleaseLock (&mPoolMemoryLock);
+ return (*Buffer != NULL) ? EFI_SUCCESS : EFI_OUT_OF_RESOURCES;
+}
+
+/**
+ Allocate pool of a particular type.
+
+ @param PoolType Type of pool to allocate
+ @param Size The amount of pool to allocate
+ @param Buffer The address to return a pointer to the allocated
+ pool
+
+ @retval EFI_INVALID_PARAMETER Buffer is NULL.
+ PoolType is in the range EfiMaxMemoryType..0x6FFFFFFF.
+ PoolType is EfiPersistentMemory.
+ @retval EFI_OUT_OF_RESOURCES Size exceeds max pool size or allocation failed.
+ @retval EFI_SUCCESS Pool successfully allocated.
+
+**/
+EFI_STATUS
+EFIAPI
+CoreAllocatePool (
+ IN EFI_MEMORY_TYPE PoolType,
+ IN UINTN Size,
+ OUT VOID **Buffer
+ )
+{
+ EFI_STATUS Status;
+
+ Status = CoreInternalAllocatePool (PoolType, Size, Buffer);
+ if (!EFI_ERROR (Status)) {
+ CoreUpdateProfile (
+ (EFI_PHYSICAL_ADDRESS)(UINTN)RETURN_ADDRESS (0),
+ MemoryProfileActionAllocatePool,
+ PoolType,
+ Size,
+ *Buffer,
+ NULL
+ );
+ InstallMemoryAttributesTableOnMemoryAllocation (PoolType);
+ }
+
+ return Status;
+}
+
+/**
+ Internal function. Used by the pool functions to allocate pages
+ to back pool allocation requests.
+
+ @param PoolType The type of memory for the new pool pages
+ @param NoPages No of pages to allocate
+ @param Granularity Bits to align.
+ @param NeedGuard Flag to indicate Guard page is needed or not
+
+ @return The allocated memory, or NULL
+
+**/
+STATIC
+VOID *
+CoreAllocatePoolPagesI (
+ IN EFI_MEMORY_TYPE PoolType,
+ IN UINTN NoPages,
+ IN UINTN Granularity,
+ IN BOOLEAN NeedGuard
+ )
+{
+ VOID *Buffer;
+ EFI_STATUS Status;
+
+ Status = CoreAcquireLockOrFail (&gMemoryLock);
+ if (EFI_ERROR (Status)) {
+ return NULL;
+ }
+
+ Buffer = CoreAllocatePoolPages (PoolType, NoPages, Granularity, NeedGuard);
+ CoreReleaseMemoryLock ();
+
+ if (Buffer != NULL) {
+ if (NeedGuard) {
+ SetGuardForMemory ((EFI_PHYSICAL_ADDRESS)(UINTN)Buffer, NoPages);
+ }
+
+ ApplyMemoryProtectionPolicy (
+ EfiConventionalMemory,
+ PoolType,
+ (EFI_PHYSICAL_ADDRESS)(UINTN)Buffer,
+ EFI_PAGES_TO_SIZE (NoPages)
+ );
+ }
+
+ return Buffer;
+}
+
+/**
+ Internal function to allocate pool of a particular type.
+ Caller must have the memory lock held
+
+ @param PoolType Type of pool to allocate
+ @param Size The amount of pool to allocate
+ @param NeedGuard Flag to indicate Guard page is needed or not
+
+ @return The allocate pool, or NULL
+
+**/
+VOID *
+CoreAllocatePoolI (
+ IN EFI_MEMORY_TYPE PoolType,
+ IN UINTN Size,
+ IN BOOLEAN NeedGuard
+ )
+{
+ POOL *Pool;
+ POOL_FREE *Free;
+ POOL_HEAD *Head;
+ POOL_TAIL *Tail;
+ CHAR8 *NewPage;
+ VOID *Buffer;
+ UINTN Index;
+ UINTN FSize;
+ UINTN Offset, MaxOffset;
+ UINTN NoPages;
+ UINTN Granularity;
+ BOOLEAN HasPoolTail;
+ BOOLEAN PageAsPool;
+
+ ASSERT_LOCKED (&mPoolMemoryLock);
+
+ if ((PoolType == EfiReservedMemoryType) ||
+ (PoolType == EfiACPIMemoryNVS) ||
+ (PoolType == EfiRuntimeServicesCode) ||
+ (PoolType == EfiRuntimeServicesData))
+ {
+ Granularity = RUNTIME_PAGE_ALLOCATION_GRANULARITY;
+ } else {
+ Granularity = DEFAULT_PAGE_ALLOCATION_GRANULARITY;
+ }
+
+ //
+ // The heap guard system does not support non-EFI_PAGE_SIZE alignments.
+ // Architectures that require larger RUNTIME_PAGE_ALLOCATION_GRANULARITY
+ // will have the runtime memory regions unguarded. OSes do not
+ // map guard pages anyway, so this is a minimal loss. Not guarding prevents
+ // alignment mismatches
+ //
+ if (Granularity != EFI_PAGE_SIZE) {
+ NeedGuard = FALSE;
+ }
+
+ //
+ // Adjust the size by the pool header & tail overhead
+ //
+
+ HasPoolTail = !(NeedGuard &&
+ ((PcdGet8 (PcdHeapGuardPropertyMask) & BIT7) == 0));
+ PageAsPool = (IsHeapGuardEnabled (GUARD_HEAP_TYPE_FREED) && !mOnGuarding);
+
+ //
+ // Adjusting the Size to be of proper alignment so that
+ // we don't get an unaligned access fault later when
+ // pool_Tail is being initialized
+ //
+ Size = ALIGN_VARIABLE (Size);
+
+ Size += POOL_OVERHEAD;
+ Index = SIZE_TO_LIST (Size);
+ Pool = LookupPoolHead (PoolType);
+ if (Pool == NULL) {
+ return NULL;
+ }
+
+ Head = NULL;
+
+ //
+ // If allocation is over max size, just allocate pages for the request
+ // (slow)
+ //
+ if ((Index >= SIZE_TO_LIST (Granularity)) || NeedGuard || PageAsPool) {
+ if (!HasPoolTail) {
+ Size -= sizeof (POOL_TAIL);
+ }
+
+ NoPages = EFI_SIZE_TO_PAGES (Size) + EFI_SIZE_TO_PAGES (Granularity) - 1;
+ NoPages &= ~(UINTN)(EFI_SIZE_TO_PAGES (Granularity) - 1);
+ Head = CoreAllocatePoolPagesI (PoolType, NoPages, Granularity, NeedGuard);
+ if (NeedGuard) {
+ Head = AdjustPoolHeadA ((EFI_PHYSICAL_ADDRESS)(UINTN)Head, NoPages, Size);
+ }
+
+ goto Done;
+ }
+
+ //
+ // If there's no free pool in the proper list size, go get some more pages
+ //
+ if (IsListEmpty (&Pool->FreeList[Index])) {
+ Offset = LIST_TO_SIZE (Index);
+ MaxOffset = Granularity;
+
+ //
+ // Check the bins holding larger blocks, and carve one up if needed
+ //
+ while (++Index < SIZE_TO_LIST (Granularity)) {
+ if (!IsListEmpty (&Pool->FreeList[Index])) {
+ Free = CR (Pool->FreeList[Index].ForwardLink, POOL_FREE, Link, POOL_FREE_SIGNATURE);
+ RemoveEntryList (&Free->Link);
+ NewPage = (VOID *)Free;
+ MaxOffset = LIST_TO_SIZE (Index);
+ goto Carve;
+ }
+ }
+
+ //
+ // Get another page
+ //
+ NewPage = CoreAllocatePoolPagesI (
+ PoolType,
+ EFI_SIZE_TO_PAGES (Granularity),
+ Granularity,
+ NeedGuard
+ );
+ if (NewPage == NULL) {
+ goto Done;
+ }
+
+ //
+ // Serve the allocation request from the head of the allocated block
+ //
+Carve:
+ Head = (POOL_HEAD *)NewPage;
+
+ //
+ // Carve up remaining space into free pool blocks
+ //
+ Index--;
+ while (Offset < MaxOffset) {
+ ASSERT (Index < MAX_POOL_LIST);
+ FSize = LIST_TO_SIZE (Index);
+
+ while (Offset + FSize <= MaxOffset) {
+ Free = (POOL_FREE *)&NewPage[Offset];
+ Free->Signature = POOL_FREE_SIGNATURE;
+ Free->Index = (UINT32)Index;
+ InsertHeadList (&Pool->FreeList[Index], &Free->Link);
+ Offset += FSize;
+ }
+
+ Index -= 1;
+ }
+
+ ASSERT (Offset == MaxOffset);
+ goto Done;
+ }
+
+ //
+ // Remove entry from free pool list
+ //
+ Free = CR (Pool->FreeList[Index].ForwardLink, POOL_FREE, Link, POOL_FREE_SIGNATURE);
+ RemoveEntryList (&Free->Link);
+
+ Head = (POOL_HEAD *)Free;
+
+Done:
+ Buffer = NULL;
+
+ if (Head != NULL) {
+ //
+ // Account the allocation
+ //
+ Pool->Used += Size;
+
+ //
+ // If we have a pool buffer, fill in the header & tail info
+ //
+ Head->Signature = (PageAsPool) ? POOLPAGE_HEAD_SIGNATURE : POOL_HEAD_SIGNATURE;
+ Head->Size = Size;
+ Head->Type = (EFI_MEMORY_TYPE)PoolType;
+ Buffer = Head->Data;
+
+ if (HasPoolTail) {
+ Tail = HEAD_TO_TAIL (Head);
+ Tail->Signature = POOL_TAIL_SIGNATURE;
+ Tail->Size = Size;
+
+ Size -= POOL_OVERHEAD;
+ } else {
+ Size -= SIZE_OF_POOL_HEAD;
+ }
+
+ DEBUG_CLEAR_MEMORY (Buffer, Size);
+
+ DEBUG ((
+ DEBUG_POOL,
+ "AllocatePoolI: Type %x, Addr %p (len %lx) %,ld\n",
+ PoolType,
+ Buffer,
+ (UINT64)Size,
+ (UINT64)Pool->Used
+ ));
+ } else {
+ DEBUG ((DEBUG_ERROR | DEBUG_POOL, "AllocatePool: failed to allocate %ld bytes\n", (UINT64)Size));
+ }
+
+ return Buffer;
+}
+
+/**
+ Frees pool.
+
+ @param Buffer The allocated pool entry to free
+ @param PoolType Pointer to pool type
+
+ @retval EFI_INVALID_PARAMETER Buffer is not a valid value.
+ @retval EFI_SUCCESS Pool successfully freed.
+
+**/
+EFI_STATUS
+EFIAPI
+CoreInternalFreePool (
+ IN VOID *Buffer,
+ OUT EFI_MEMORY_TYPE *PoolType OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+
+ if (Buffer == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ CoreAcquireLock (&mPoolMemoryLock);
+ Status = CoreFreePoolI (Buffer, PoolType);
+ CoreReleaseLock (&mPoolMemoryLock);
+ return Status;
+}
+
+/**
+ Frees pool.
+
+ @param Buffer The allocated pool entry to free
+
+ @retval EFI_INVALID_PARAMETER Buffer is not a valid value.
+ @retval EFI_SUCCESS Pool successfully freed.
+
+**/
+EFI_STATUS
+EFIAPI
+CoreFreePool (
+ IN VOID *Buffer
+ )
+{
+ EFI_STATUS Status;
+ EFI_MEMORY_TYPE PoolType;
+
+ Status = CoreInternalFreePool (Buffer, &PoolType);
+ if (!EFI_ERROR (Status)) {
+ CoreUpdateProfile (
+ (EFI_PHYSICAL_ADDRESS)(UINTN)RETURN_ADDRESS (0),
+ MemoryProfileActionFreePool,
+ PoolType,
+ 0,
+ Buffer,
+ NULL
+ );
+ InstallMemoryAttributesTableOnMemoryAllocation (PoolType);
+ }
+
+ return Status;
+}
+
+/**
+ Internal function. Frees pool pages allocated via CoreAllocatePoolPagesI().
+
+ @param PoolType The type of memory for the pool pages
+ @param Memory The base address to free
+ @param NoPages The number of pages to free
+
+**/
+STATIC
+VOID
+CoreFreePoolPagesI (
+ IN EFI_MEMORY_TYPE PoolType,
+ IN EFI_PHYSICAL_ADDRESS Memory,
+ IN UINTN NoPages
+ )
+{
+ CoreAcquireMemoryLock ();
+ CoreFreePoolPages (Memory, NoPages);
+ CoreReleaseMemoryLock ();
+
+ GuardFreedPagesChecked (Memory, NoPages);
+ ApplyMemoryProtectionPolicy (
+ PoolType,
+ EfiConventionalMemory,
+ (EFI_PHYSICAL_ADDRESS)(UINTN)Memory,
+ EFI_PAGES_TO_SIZE (NoPages)
+ );
+}
+
+/**
+ Internal function. Frees guarded pool pages.
+
+ @param PoolType The type of memory for the pool pages
+ @param Memory The base address to free
+ @param NoPages The number of pages to free
+
+**/
+STATIC
+VOID
+CoreFreePoolPagesWithGuard (
+ IN EFI_MEMORY_TYPE PoolType,
+ IN EFI_PHYSICAL_ADDRESS Memory,
+ IN UINTN NoPages
+ )
+{
+ EFI_PHYSICAL_ADDRESS MemoryGuarded;
+ UINTN NoPagesGuarded;
+
+ MemoryGuarded = Memory;
+ NoPagesGuarded = NoPages;
+
+ AdjustMemoryF (&Memory, &NoPages);
+ //
+ // It's safe to unset Guard page inside memory lock because there should
+ // be no memory allocation occurred in updating memory page attribute at
+ // this point. And unsetting Guard page before free will prevent Guard
+ // page just freed back to pool from being allocated right away before
+ // marking it usable (from non-present to present).
+ //
+ UnsetGuardForMemory (MemoryGuarded, NoPagesGuarded);
+ if (NoPages > 0) {
+ CoreFreePoolPagesI (PoolType, Memory, NoPages);
+ }
+}
+
+/**
+ Internal function to free a pool entry.
+ Caller must have the memory lock held
+
+ @param Buffer The allocated pool entry to free
+ @param PoolType Pointer to pool type
+
+ @retval EFI_INVALID_PARAMETER Buffer not valid
+ @retval EFI_SUCCESS Buffer successfully freed.
+
+**/
+EFI_STATUS
+CoreFreePoolI (
+ IN VOID *Buffer,
+ OUT EFI_MEMORY_TYPE *PoolType OPTIONAL
+ )
+{
+ POOL *Pool;
+ POOL_HEAD *Head;
+ POOL_TAIL *Tail;
+ POOL_FREE *Free;
+ UINTN Index;
+ UINTN NoPages;
+ UINTN Size;
+ CHAR8 *NewPage;
+ UINTN Offset;
+ BOOLEAN AllFree;
+ UINTN Granularity;
+ BOOLEAN IsGuarded;
+ BOOLEAN HasPoolTail;
+ BOOLEAN PageAsPool;
+
+ ASSERT (Buffer != NULL);
+ //
+ // Get the head & tail of the pool entry
+ //
+ Head = BASE_CR (Buffer, POOL_HEAD, Data);
+ ASSERT (Head != NULL);
+
+ if ((Head->Signature != POOL_HEAD_SIGNATURE) &&
+ (Head->Signature != POOLPAGE_HEAD_SIGNATURE))
+ {
+ ASSERT (
+ Head->Signature == POOL_HEAD_SIGNATURE ||
+ Head->Signature == POOLPAGE_HEAD_SIGNATURE
+ );
+ return EFI_INVALID_PARAMETER;
+ }
+
+ IsGuarded = IsPoolTypeToGuard (Head->Type) &&
+ IsMemoryGuarded ((EFI_PHYSICAL_ADDRESS)(UINTN)Head);
+ HasPoolTail = !(IsGuarded &&
+ ((PcdGet8 (PcdHeapGuardPropertyMask) & BIT7) == 0));
+ PageAsPool = (Head->Signature == POOLPAGE_HEAD_SIGNATURE);
+
+ if (HasPoolTail) {
+ Tail = HEAD_TO_TAIL (Head);
+ ASSERT (Tail != NULL);
+
+ //
+ // Debug
+ //
+ ASSERT (Tail->Signature == POOL_TAIL_SIGNATURE);
+ ASSERT (Head->Size == Tail->Size);
+
+ if (Tail->Signature != POOL_TAIL_SIGNATURE) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (Head->Size != Tail->Size) {
+ return EFI_INVALID_PARAMETER;
+ }
+ }
+
+ ASSERT_LOCKED (&mPoolMemoryLock);
+
+ //
+ // Determine the pool type and account for it
+ //
+ Size = Head->Size;
+ Pool = LookupPoolHead (Head->Type);
+ if (Pool == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Pool->Used -= Size;
+ DEBUG ((DEBUG_POOL, "FreePool: %p (len %lx) %,ld\n", Head->Data, (UINT64)(Head->Size - POOL_OVERHEAD), (UINT64)Pool->Used));
+
+ if ((Head->Type == EfiReservedMemoryType) ||
+ (Head->Type == EfiACPIMemoryNVS) ||
+ (Head->Type == EfiRuntimeServicesCode) ||
+ (Head->Type == EfiRuntimeServicesData))
+ {
+ Granularity = RUNTIME_PAGE_ALLOCATION_GRANULARITY;
+ } else {
+ Granularity = DEFAULT_PAGE_ALLOCATION_GRANULARITY;
+ }
+
+ if (PoolType != NULL) {
+ *PoolType = Head->Type;
+ }
+
+ //
+ // Determine the pool list
+ //
+ Index = SIZE_TO_LIST (Size);
+ DEBUG_CLEAR_MEMORY (Head, Size);
+
+ //
+ // If it's not on the list, it must be pool pages
+ //
+ if ((Index >= SIZE_TO_LIST (Granularity)) || IsGuarded || PageAsPool) {
+ //
+ // Return the memory pages back to free memory
+ //
+ NoPages = EFI_SIZE_TO_PAGES (Size) + EFI_SIZE_TO_PAGES (Granularity) - 1;
+ NoPages &= ~(UINTN)(EFI_SIZE_TO_PAGES (Granularity) - 1);
+ if (IsGuarded) {
+ Head = AdjustPoolHeadF ((EFI_PHYSICAL_ADDRESS)(UINTN)Head, NoPages, Size);
+ CoreFreePoolPagesWithGuard (
+ Pool->MemoryType,
+ (EFI_PHYSICAL_ADDRESS)(UINTN)Head,
+ NoPages
+ );
+ } else {
+ CoreFreePoolPagesI (
+ Pool->MemoryType,
+ (EFI_PHYSICAL_ADDRESS)(UINTN)Head,
+ NoPages
+ );
+ }
+ } else {
+ //
+ // Put the pool entry onto the free pool list
+ //
+ Free = (POOL_FREE *)Head;
+ ASSERT (Free != NULL);
+ Free->Signature = POOL_FREE_SIGNATURE;
+ Free->Index = (UINT32)Index;
+ InsertHeadList (&Pool->FreeList[Index], &Free->Link);
+
+ //
+ // See if all the pool entries in the same page as Free are freed pool
+ // entries
+ //
+ NewPage = (CHAR8 *)((UINTN)Free & ~(Granularity - 1));
+ Free = (POOL_FREE *)&NewPage[0];
+ ASSERT (Free != NULL);
+
+ if (Free->Signature == POOL_FREE_SIGNATURE) {
+ AllFree = TRUE;
+ Offset = 0;
+
+ while ((Offset < Granularity) && (AllFree)) {
+ Free = (POOL_FREE *)&NewPage[Offset];
+ ASSERT (Free != NULL);
+ if (Free->Signature != POOL_FREE_SIGNATURE) {
+ AllFree = FALSE;
+ }
+
+ Offset += LIST_TO_SIZE (Free->Index);
+ }
+
+ if (AllFree) {
+ //
+ // All of the pool entries in the same page as Free are free pool
+ // entries
+ // Remove all of these pool entries from the free loop lists.
+ //
+ Free = (POOL_FREE *)&NewPage[0];
+ ASSERT (Free != NULL);
+ Offset = 0;
+
+ while (Offset < Granularity) {
+ Free = (POOL_FREE *)&NewPage[Offset];
+ ASSERT (Free != NULL);
+ RemoveEntryList (&Free->Link);
+ Offset += LIST_TO_SIZE (Free->Index);
+ }
+
+ //
+ // Free the page
+ //
+ CoreFreePoolPagesI (
+ Pool->MemoryType,
+ (EFI_PHYSICAL_ADDRESS)(UINTN)NewPage,
+ EFI_SIZE_TO_PAGES (Granularity)
+ );
+ }
+ }
+ }
+
+ //
+ // If this is an OS/OEM specific memory type, then check to see if the last
+ // portion of that memory type has been freed. If it has, then free the
+ // list entry for that memory type
+ //
+ if (((UINT32)Pool->MemoryType >= MEMORY_TYPE_OEM_RESERVED_MIN) && (Pool->Used == 0)) {
+ RemoveEntryList (&Pool->Link);
+ CoreFreePoolI (Pool, NULL);
+ }
+
+ return EFI_SUCCESS;
+}
diff --git a/MdeModulePkg/Core/Dxe/Misc/DebugImageInfo.c b/MdeModulePkg/Core/Dxe/Misc/DebugImageInfo.c
index eeb18f6e47..7b96806686 100644
--- a/MdeModulePkg/Core/Dxe/Misc/DebugImageInfo.c
+++ b/MdeModulePkg/Core/Dxe/Misc/DebugImageInfo.c
@@ -1,282 +1,282 @@
-/** @file
- Support functions for managing debug image info table when loading and unloading
- images.
-
-Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
-SPDX-License-Identifier: BSD-2-Clause-Patent
-
-**/
-
-#include "DxeMain.h"
-
-EFI_DEBUG_IMAGE_INFO_TABLE_HEADER mDebugInfoTableHeader = {
- 0, // volatile UINT32 UpdateStatus;
- 0, // UINT32 TableSize;
- NULL // EFI_DEBUG_IMAGE_INFO *EfiDebugImageInfoTable;
-};
-
-UINTN mMaxTableEntries = 0;
-
-EFI_SYSTEM_TABLE_POINTER *mDebugTable = NULL;
-
-#define EFI_DEBUG_TABLE_ENTRY_SIZE (sizeof (VOID *))
-
-/**
- Creates and initializes the DebugImageInfo Table. Also creates the configuration
- table and registers it into the system table.
-
-**/
-VOID
-CoreInitializeDebugImageInfoTable (
- VOID
- )
-{
- EFI_STATUS Status;
- UINTN Pages;
- EFI_PHYSICAL_ADDRESS Memory;
- UINTN AlignedMemory;
- UINTN AlignmentMask;
- UINTN UnalignedPages;
- UINTN RealPages;
-
- //
- // Allocate 4M aligned page for the structure and fill in the data.
- // Ideally we would update the CRC now as well, but the service may not yet be available.
- // See comments in the CoreUpdateDebugTableCrc32() function below for details.
- //
- Pages = EFI_SIZE_TO_PAGES (sizeof (EFI_SYSTEM_TABLE_POINTER));
- AlignmentMask = SIZE_4MB - 1;
- RealPages = Pages + EFI_SIZE_TO_PAGES (SIZE_4MB);
-
- //
- // Attempt to allocate memory below PcdMaxEfiSystemTablePointerAddress
- // If PcdMaxEfiSystemTablePointerAddress is 0, then allocate memory below
- // MAX_ADDRESS
- //
- Memory = PcdGet64 (PcdMaxEfiSystemTablePointerAddress);
- if (Memory == 0) {
- Memory = MAX_ADDRESS;
- }
-
- Status = CoreAllocatePages (
- AllocateMaxAddress,
- EfiBootServicesData,
- RealPages,
- &Memory
- );
- if (EFI_ERROR (Status)) {
- if (PcdGet64 (PcdMaxEfiSystemTablePointerAddress) != 0) {
- DEBUG ((DEBUG_INFO, "Allocate memory for EFI_SYSTEM_TABLE_POINTER below PcdMaxEfiSystemTablePointerAddress failed. \
- Retry to allocate memroy as close to the top of memory as feasible.\n"));
- }
-
- //
- // If the initial memory allocation fails, then reattempt allocation
- // as close to the top of memory as feasible.
- //
- Status = CoreAllocatePages (
- AllocateAnyPages,
- EfiBootServicesData,
- RealPages,
- &Memory
- );
- ASSERT_EFI_ERROR (Status);
- if (EFI_ERROR (Status)) {
- return;
- }
- }
-
- //
- // Free overallocated pages
- //
- AlignedMemory = ((UINTN)Memory + AlignmentMask) & ~AlignmentMask;
- UnalignedPages = EFI_SIZE_TO_PAGES (AlignedMemory - (UINTN)Memory);
- if (UnalignedPages > 0) {
- //
- // Free first unaligned page(s).
- //
- Status = CoreFreePages (Memory, UnalignedPages);
- ASSERT_EFI_ERROR (Status);
- }
-
- Memory = AlignedMemory + EFI_PAGES_TO_SIZE (Pages);
- UnalignedPages = RealPages - Pages - UnalignedPages;
- if (UnalignedPages > 0) {
- //
- // Free last unaligned page(s).
- //
- Status = CoreFreePages (Memory, UnalignedPages);
- ASSERT_EFI_ERROR (Status);
- }
-
- //
- // Set mDebugTable to the 4MB aligned allocated pages
- //
- mDebugTable = (EFI_SYSTEM_TABLE_POINTER *)(AlignedMemory);
- ASSERT (mDebugTable != NULL);
-
- //
- // Initialize EFI_SYSTEM_TABLE_POINTER structure
- //
- mDebugTable->Signature = EFI_SYSTEM_TABLE_SIGNATURE;
- mDebugTable->EfiSystemTableBase = (EFI_PHYSICAL_ADDRESS)(UINTN)gDxeCoreST;
- mDebugTable->Crc32 = 0;
-
- //
- // Install the EFI_SYSTEM_TABLE_POINTER structure in the EFI System
- // Configuration Table
- //
- Status = CoreInstallConfigurationTable (&gEfiDebugImageInfoTableGuid, &mDebugInfoTableHeader);
- ASSERT_EFI_ERROR (Status);
-}
-
-/**
- Update the CRC32 in the Debug Table.
- Since the CRC32 service is made available by the Runtime driver, we have to
- wait for the Runtime Driver to be installed before the CRC32 can be computed.
- This function is called elsewhere by the core when the runtime architectural
- protocol is produced.
-
-**/
-VOID
-CoreUpdateDebugTableCrc32 (
- VOID
- )
-{
- ASSERT (mDebugTable != NULL);
- mDebugTable->Crc32 = 0;
- gBS->CalculateCrc32 ((VOID *)mDebugTable, sizeof (EFI_SYSTEM_TABLE_POINTER), &mDebugTable->Crc32);
-}
-
-/**
- Adds a new DebugImageInfo structure to the DebugImageInfo Table. Re-Allocates
- the table if it's not large enough to accomidate another entry.
-
- @param ImageInfoType type of debug image information
- @param LoadedImage pointer to the loaded image protocol for the image being
- loaded
- @param ImageHandle image handle for the image being loaded
-
-**/
-VOID
-CoreNewDebugImageInfoEntry (
- IN UINT32 ImageInfoType,
- IN EFI_LOADED_IMAGE_PROTOCOL *LoadedImage,
- IN EFI_HANDLE ImageHandle
- )
-{
- EFI_DEBUG_IMAGE_INFO *Table;
- EFI_DEBUG_IMAGE_INFO *NewTable;
- UINTN Index;
- UINTN TableSize;
-
- //
- // Set the flag indicating that we're in the process of updating the table.
- //
- mDebugInfoTableHeader.UpdateStatus |= EFI_DEBUG_IMAGE_INFO_UPDATE_IN_PROGRESS;
-
- Table = mDebugInfoTableHeader.EfiDebugImageInfoTable;
-
- if (mDebugInfoTableHeader.TableSize < mMaxTableEntries) {
- //
- // We still have empty entires in the Table, find the first empty entry.
- //
- Index = 0;
- while (Table[Index].NormalImage != NULL) {
- Index++;
- }
-
- //
- // There must be an empty entry in the in the table.
- //
- ASSERT (Index < mMaxTableEntries);
- } else {
- //
- // Table is full, so re-allocate another page for a larger table...
- //
- TableSize = mMaxTableEntries * EFI_DEBUG_TABLE_ENTRY_SIZE;
- NewTable = AllocateZeroPool (TableSize + EFI_PAGE_SIZE);
- if (NewTable == NULL) {
- mDebugInfoTableHeader.UpdateStatus &= ~EFI_DEBUG_IMAGE_INFO_UPDATE_IN_PROGRESS;
- return;
- }
-
- //
- // Copy the old table into the new one
- //
- CopyMem (NewTable, Table, TableSize);
- //
- // Free the old table
- //
- CoreFreePool (Table);
- //
- // Update the table header
- //
- Table = NewTable;
- mDebugInfoTableHeader.EfiDebugImageInfoTable = NewTable;
- //
- // Enlarge the max table entries and set the first empty entry index to
- // be the original max table entries.
- //
- Index = mMaxTableEntries;
- mMaxTableEntries += EFI_PAGE_SIZE / EFI_DEBUG_TABLE_ENTRY_SIZE;
- }
-
- //
- // Allocate data for new entry
- //
- Table[Index].NormalImage = AllocateZeroPool (sizeof (EFI_DEBUG_IMAGE_INFO_NORMAL));
- if (Table[Index].NormalImage != NULL) {
- //
- // Update the entry
- //
- Table[Index].NormalImage->ImageInfoType = (UINT32)ImageInfoType;
- Table[Index].NormalImage->LoadedImageProtocolInstance = LoadedImage;
- Table[Index].NormalImage->ImageHandle = ImageHandle;
- //
- // Increase the number of EFI_DEBUG_IMAGE_INFO elements and set the mDebugInfoTable in modified status.
- //
- mDebugInfoTableHeader.TableSize++;
- mDebugInfoTableHeader.UpdateStatus |= EFI_DEBUG_IMAGE_INFO_TABLE_MODIFIED;
- }
-
- mDebugInfoTableHeader.UpdateStatus &= ~EFI_DEBUG_IMAGE_INFO_UPDATE_IN_PROGRESS;
-}
-
-/**
- Removes and frees an entry from the DebugImageInfo Table.
-
- @param ImageHandle image handle for the image being unloaded
-
-**/
-VOID
-CoreRemoveDebugImageInfoEntry (
- EFI_HANDLE ImageHandle
- )
-{
- EFI_DEBUG_IMAGE_INFO *Table;
- UINTN Index;
-
- mDebugInfoTableHeader.UpdateStatus |= EFI_DEBUG_IMAGE_INFO_UPDATE_IN_PROGRESS;
-
- Table = mDebugInfoTableHeader.EfiDebugImageInfoTable;
-
- for (Index = 0; Index < mMaxTableEntries; Index++) {
- if ((Table[Index].NormalImage != NULL) && (Table[Index].NormalImage->ImageHandle == ImageHandle)) {
- //
- // Found a match. Free up the record, then NULL the pointer to indicate the slot
- // is free.
- //
- CoreFreePool (Table[Index].NormalImage);
- Table[Index].NormalImage = NULL;
- //
- // Decrease the number of EFI_DEBUG_IMAGE_INFO elements and set the mDebugInfoTable in modified status.
- //
- mDebugInfoTableHeader.TableSize--;
- mDebugInfoTableHeader.UpdateStatus |= EFI_DEBUG_IMAGE_INFO_TABLE_MODIFIED;
- break;
- }
- }
-
- mDebugInfoTableHeader.UpdateStatus &= ~EFI_DEBUG_IMAGE_INFO_UPDATE_IN_PROGRESS;
-}
+/** @file
+ Support functions for managing debug image info table when loading and unloading
+ images.
+
+Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "DxeMain.h"
+
+EFI_DEBUG_IMAGE_INFO_TABLE_HEADER mDebugInfoTableHeader = {
+ 0, // volatile UINT32 UpdateStatus;
+ 0, // UINT32 TableSize;
+ NULL // EFI_DEBUG_IMAGE_INFO *EfiDebugImageInfoTable;
+};
+
+UINTN mMaxTableEntries = 0;
+
+EFI_SYSTEM_TABLE_POINTER *mDebugTable = NULL;
+
+#define EFI_DEBUG_TABLE_ENTRY_SIZE (sizeof (VOID *))
+
+/**
+ Creates and initializes the DebugImageInfo Table. Also creates the configuration
+ table and registers it into the system table.
+
+**/
+VOID
+CoreInitializeDebugImageInfoTable (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ UINTN Pages;
+ EFI_PHYSICAL_ADDRESS Memory;
+ UINTN AlignedMemory;
+ UINTN AlignmentMask;
+ UINTN UnalignedPages;
+ UINTN RealPages;
+
+ //
+ // Allocate 4M aligned page for the structure and fill in the data.
+ // Ideally we would update the CRC now as well, but the service may not yet be available.
+ // See comments in the CoreUpdateDebugTableCrc32() function below for details.
+ //
+ Pages = EFI_SIZE_TO_PAGES (sizeof (EFI_SYSTEM_TABLE_POINTER));
+ AlignmentMask = SIZE_4MB - 1;
+ RealPages = Pages + EFI_SIZE_TO_PAGES (SIZE_4MB);
+
+ //
+ // Attempt to allocate memory below PcdMaxEfiSystemTablePointerAddress
+ // If PcdMaxEfiSystemTablePointerAddress is 0, then allocate memory below
+ // MAX_ADDRESS
+ //
+ Memory = PcdGet64 (PcdMaxEfiSystemTablePointerAddress);
+ if (Memory == 0) {
+ Memory = MAX_ADDRESS;
+ }
+
+ Status = CoreAllocatePages (
+ AllocateMaxAddress,
+ EfiBootServicesData,
+ RealPages,
+ &Memory
+ );
+ if (EFI_ERROR (Status)) {
+ if (PcdGet64 (PcdMaxEfiSystemTablePointerAddress) != 0) {
+ DEBUG ((DEBUG_INFO, "Allocate memory for EFI_SYSTEM_TABLE_POINTER below PcdMaxEfiSystemTablePointerAddress failed. \
+ Retry to allocate memroy as close to the top of memory as feasible.\n"));
+ }
+
+ //
+ // If the initial memory allocation fails, then reattempt allocation
+ // as close to the top of memory as feasible.
+ //
+ Status = CoreAllocatePages (
+ AllocateAnyPages,
+ EfiBootServicesData,
+ RealPages,
+ &Memory
+ );
+ ASSERT_EFI_ERROR (Status);
+ if (EFI_ERROR (Status)) {
+ return;
+ }
+ }
+
+ //
+ // Free overallocated pages
+ //
+ AlignedMemory = ((UINTN)Memory + AlignmentMask) & ~AlignmentMask;
+ UnalignedPages = EFI_SIZE_TO_PAGES (AlignedMemory - (UINTN)Memory);
+ if (UnalignedPages > 0) {
+ //
+ // Free first unaligned page(s).
+ //
+ Status = CoreFreePages (Memory, UnalignedPages);
+ ASSERT_EFI_ERROR (Status);
+ }
+
+ Memory = AlignedMemory + EFI_PAGES_TO_SIZE (Pages);
+ UnalignedPages = RealPages - Pages - UnalignedPages;
+ if (UnalignedPages > 0) {
+ //
+ // Free last unaligned page(s).
+ //
+ Status = CoreFreePages (Memory, UnalignedPages);
+ ASSERT_EFI_ERROR (Status);
+ }
+
+ //
+ // Set mDebugTable to the 4MB aligned allocated pages
+ //
+ mDebugTable = (EFI_SYSTEM_TABLE_POINTER *)(AlignedMemory);
+ ASSERT (mDebugTable != NULL);
+
+ //
+ // Initialize EFI_SYSTEM_TABLE_POINTER structure
+ //
+ mDebugTable->Signature = EFI_SYSTEM_TABLE_SIGNATURE;
+ mDebugTable->EfiSystemTableBase = (EFI_PHYSICAL_ADDRESS)(UINTN)gDxeCoreST;
+ mDebugTable->Crc32 = 0;
+
+ //
+ // Install the EFI_SYSTEM_TABLE_POINTER structure in the EFI System
+ // Configuration Table
+ //
+ Status = CoreInstallConfigurationTable (&gEfiDebugImageInfoTableGuid, &mDebugInfoTableHeader);
+ ASSERT_EFI_ERROR (Status);
+}
+
+/**
+ Update the CRC32 in the Debug Table.
+ Since the CRC32 service is made available by the Runtime driver, we have to
+ wait for the Runtime Driver to be installed before the CRC32 can be computed.
+ This function is called elsewhere by the core when the runtime architectural
+ protocol is produced.
+
+**/
+VOID
+CoreUpdateDebugTableCrc32 (
+ VOID
+ )
+{
+ ASSERT (mDebugTable != NULL);
+ mDebugTable->Crc32 = 0;
+ gBS->CalculateCrc32 ((VOID *)mDebugTable, sizeof (EFI_SYSTEM_TABLE_POINTER), &mDebugTable->Crc32);
+}
+
+/**
+ Adds a new DebugImageInfo structure to the DebugImageInfo Table. Re-Allocates
+ the table if it's not large enough to accomidate another entry.
+
+ @param ImageInfoType type of debug image information
+ @param LoadedImage pointer to the loaded image protocol for the image being
+ loaded
+ @param ImageHandle image handle for the image being loaded
+
+**/
+VOID
+CoreNewDebugImageInfoEntry (
+ IN UINT32 ImageInfoType,
+ IN EFI_LOADED_IMAGE_PROTOCOL *LoadedImage,
+ IN EFI_HANDLE ImageHandle
+ )
+{
+ EFI_DEBUG_IMAGE_INFO *Table;
+ EFI_DEBUG_IMAGE_INFO *NewTable;
+ UINTN Index;
+ UINTN TableSize;
+
+ //
+ // Set the flag indicating that we're in the process of updating the table.
+ //
+ mDebugInfoTableHeader.UpdateStatus |= EFI_DEBUG_IMAGE_INFO_UPDATE_IN_PROGRESS;
+
+ Table = mDebugInfoTableHeader.EfiDebugImageInfoTable;
+
+ if (mDebugInfoTableHeader.TableSize < mMaxTableEntries) {
+ //
+ // We still have empty entires in the Table, find the first empty entry.
+ //
+ Index = 0;
+ while (Table[Index].NormalImage != NULL) {
+ Index++;
+ }
+
+ //
+ // There must be an empty entry in the in the table.
+ //
+ ASSERT (Index < mMaxTableEntries);
+ } else {
+ //
+ // Table is full, so re-allocate another page for a larger table...
+ //
+ TableSize = mMaxTableEntries * EFI_DEBUG_TABLE_ENTRY_SIZE;
+ NewTable = AllocateZeroPool (TableSize + EFI_PAGE_SIZE);
+ if (NewTable == NULL) {
+ mDebugInfoTableHeader.UpdateStatus &= ~EFI_DEBUG_IMAGE_INFO_UPDATE_IN_PROGRESS;
+ return;
+ }
+
+ //
+ // Copy the old table into the new one
+ //
+ CopyMem (NewTable, Table, TableSize);
+ //
+ // Free the old table
+ //
+ CoreFreePool (Table);
+ //
+ // Update the table header
+ //
+ Table = NewTable;
+ mDebugInfoTableHeader.EfiDebugImageInfoTable = NewTable;
+ //
+ // Enlarge the max table entries and set the first empty entry index to
+ // be the original max table entries.
+ //
+ Index = mMaxTableEntries;
+ mMaxTableEntries += EFI_PAGE_SIZE / EFI_DEBUG_TABLE_ENTRY_SIZE;
+ }
+
+ //
+ // Allocate data for new entry
+ //
+ Table[Index].NormalImage = AllocateZeroPool (sizeof (EFI_DEBUG_IMAGE_INFO_NORMAL));
+ if (Table[Index].NormalImage != NULL) {
+ //
+ // Update the entry
+ //
+ Table[Index].NormalImage->ImageInfoType = (UINT32)ImageInfoType;
+ Table[Index].NormalImage->LoadedImageProtocolInstance = LoadedImage;
+ Table[Index].NormalImage->ImageHandle = ImageHandle;
+ //
+ // Increase the number of EFI_DEBUG_IMAGE_INFO elements and set the mDebugInfoTable in modified status.
+ //
+ mDebugInfoTableHeader.TableSize++;
+ mDebugInfoTableHeader.UpdateStatus |= EFI_DEBUG_IMAGE_INFO_TABLE_MODIFIED;
+ }
+
+ mDebugInfoTableHeader.UpdateStatus &= ~EFI_DEBUG_IMAGE_INFO_UPDATE_IN_PROGRESS;
+}
+
+/**
+ Removes and frees an entry from the DebugImageInfo Table.
+
+ @param ImageHandle image handle for the image being unloaded
+
+**/
+VOID
+CoreRemoveDebugImageInfoEntry (
+ EFI_HANDLE ImageHandle
+ )
+{
+ EFI_DEBUG_IMAGE_INFO *Table;
+ UINTN Index;
+
+ mDebugInfoTableHeader.UpdateStatus |= EFI_DEBUG_IMAGE_INFO_UPDATE_IN_PROGRESS;
+
+ Table = mDebugInfoTableHeader.EfiDebugImageInfoTable;
+
+ for (Index = 0; Index < mMaxTableEntries; Index++) {
+ if ((Table[Index].NormalImage != NULL) && (Table[Index].NormalImage->ImageHandle == ImageHandle)) {
+ //
+ // Found a match. Free up the record, then NULL the pointer to indicate the slot
+ // is free.
+ //
+ CoreFreePool (Table[Index].NormalImage);
+ Table[Index].NormalImage = NULL;
+ //
+ // Decrease the number of EFI_DEBUG_IMAGE_INFO elements and set the mDebugInfoTable in modified status.
+ //
+ mDebugInfoTableHeader.TableSize--;
+ mDebugInfoTableHeader.UpdateStatus |= EFI_DEBUG_IMAGE_INFO_TABLE_MODIFIED;
+ break;
+ }
+ }
+
+ mDebugInfoTableHeader.UpdateStatus &= ~EFI_DEBUG_IMAGE_INFO_UPDATE_IN_PROGRESS;
+}
diff --git a/MdeModulePkg/Core/Dxe/Misc/InstallConfigurationTable.c b/MdeModulePkg/Core/Dxe/Misc/InstallConfigurationTable.c
index f47f3bd804..70fb4dd337 100755
--- a/MdeModulePkg/Core/Dxe/Misc/InstallConfigurationTable.c
+++ b/MdeModulePkg/Core/Dxe/Misc/InstallConfigurationTable.c
@@ -1,179 +1,179 @@
-/** @file
- UEFI Miscellaneous boot Services InstallConfigurationTable service
-
-Copyright (c) 2006 - 2017, Intel Corporation. All rights reserved.<BR>
-SPDX-License-Identifier: BSD-2-Clause-Patent
-
-**/
-
-#include "DxeMain.h"
-
-#define CONFIG_TABLE_SIZE_INCREASED 0x10
-
-UINTN mSystemTableAllocateSize = 0;
-
-/**
- Boot Service called to add, modify, or remove a system configuration table from
- the EFI System Table.
-
- @param Guid Pointer to the GUID for the entry to add, update, or
- remove
- @param Table Pointer to the configuration table for the entry to add,
- update, or remove, may be NULL.
-
- @return EFI_SUCCESS Guid, Table pair added, updated, or removed.
- @return EFI_INVALID_PARAMETER Input GUID is NULL.
- @return EFI_NOT_FOUND Attempted to delete non-existant entry
- @return EFI_OUT_OF_RESOURCES Not enough memory available
-
-**/
-EFI_STATUS
-EFIAPI
-CoreInstallConfigurationTable (
- IN EFI_GUID *Guid,
- IN VOID *Table
- )
-{
- UINTN Index;
- EFI_CONFIGURATION_TABLE *EfiConfigurationTable;
- EFI_CONFIGURATION_TABLE *OldTable;
-
- //
- // If Guid is NULL, then this operation cannot be performed
- //
- if (Guid == NULL) {
- return EFI_INVALID_PARAMETER;
- }
-
- EfiConfigurationTable = gDxeCoreST->ConfigurationTable;
-
- //
- // Search all the table for an entry that matches Guid
- //
- for (Index = 0; Index < gDxeCoreST->NumberOfTableEntries; Index++) {
- if (CompareGuid (Guid, &(gDxeCoreST->ConfigurationTable[Index].VendorGuid))) {
- break;
- }
- }
-
- if (Index < gDxeCoreST->NumberOfTableEntries) {
- //
- // A match was found, so this is either a modify or a delete operation
- //
- if (Table != NULL) {
- //
- // If Table is not NULL, then this is a modify operation.
- // Modify the table entry and return.
- //
- gDxeCoreST->ConfigurationTable[Index].VendorTable = Table;
-
- //
- // Signal Configuration Table change
- //
- CoreNotifySignalList (Guid);
-
- return EFI_SUCCESS;
- }
-
- //
- // A match was found and Table is NULL, so this is a delete operation.
- //
- gDxeCoreST->NumberOfTableEntries--;
-
- //
- // Copy over deleted entry
- //
- CopyMem (
- &(EfiConfigurationTable[Index]),
- &(gDxeCoreST->ConfigurationTable[Index + 1]),
- (gDxeCoreST->NumberOfTableEntries - Index) * sizeof (EFI_CONFIGURATION_TABLE)
- );
- } else {
- //
- // No matching GUIDs were found, so this is an add operation.
- //
-
- if (Table == NULL) {
- //
- // If Table is NULL on an add operation, then return an error.
- //
- return EFI_NOT_FOUND;
- }
-
- //
- // Assume that Index == gDxeCoreST->NumberOfTableEntries
- //
- if ((Index * sizeof (EFI_CONFIGURATION_TABLE)) >= mSystemTableAllocateSize) {
- //
- // Allocate a table with one additional entry.
- //
- mSystemTableAllocateSize += (CONFIG_TABLE_SIZE_INCREASED * sizeof (EFI_CONFIGURATION_TABLE));
- EfiConfigurationTable = AllocateRuntimePool (mSystemTableAllocateSize);
- if (EfiConfigurationTable == NULL) {
- //
- // If a new table could not be allocated, then return an error.
- //
- return EFI_OUT_OF_RESOURCES;
- }
-
- if (gDxeCoreST->ConfigurationTable != NULL) {
- //
- // Copy the old table to the new table.
- //
- CopyMem (
- EfiConfigurationTable,
- gDxeCoreST->ConfigurationTable,
- Index * sizeof (EFI_CONFIGURATION_TABLE)
- );
-
- //
- // Record the old table pointer.
- //
- OldTable = gDxeCoreST->ConfigurationTable;
-
- //
- // As the CoreInstallConfigurationTable() may be re-entered by CoreFreePool()
- // in its calling stack, updating System table to the new table pointer must
- // be done before calling CoreFreePool() to free the old table.
- // It can make sure the gDxeCoreST->ConfigurationTable point to the new table
- // and avoid the errors of use-after-free to the old table by the reenter of
- // CoreInstallConfigurationTable() in CoreFreePool()'s calling stack.
- //
- gDxeCoreST->ConfigurationTable = EfiConfigurationTable;
-
- //
- // Free the old table after updating System Table to the new table pointer.
- //
- CoreFreePool (OldTable);
- } else {
- //
- // Update System Table
- //
- gDxeCoreST->ConfigurationTable = EfiConfigurationTable;
- }
- }
-
- //
- // Fill in the new entry
- //
- CopyGuid ((VOID *)&EfiConfigurationTable[Index].VendorGuid, Guid);
- EfiConfigurationTable[Index].VendorTable = Table;
-
- //
- // This is an add operation, so increment the number of table entries
- //
- gDxeCoreST->NumberOfTableEntries++;
- }
-
- //
- // Fix up the CRC-32 in the EFI System Table
- //
- CalculateEfiHdrCrc (&gDxeCoreST->Hdr);
-
- //
- // Signal Configuration Table change
- //
- CoreNotifySignalList (Guid);
-
- return EFI_SUCCESS;
-}
+/** @file
+ UEFI Miscellaneous boot Services InstallConfigurationTable service
+
+Copyright (c) 2006 - 2017, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "DxeMain.h"
+
+#define CONFIG_TABLE_SIZE_INCREASED 0x10
+
+UINTN mSystemTableAllocateSize = 0;
+
+/**
+ Boot Service called to add, modify, or remove a system configuration table from
+ the EFI System Table.
+
+ @param Guid Pointer to the GUID for the entry to add, update, or
+ remove
+ @param Table Pointer to the configuration table for the entry to add,
+ update, or remove, may be NULL.
+
+ @return EFI_SUCCESS Guid, Table pair added, updated, or removed.
+ @return EFI_INVALID_PARAMETER Input GUID is NULL.
+ @return EFI_NOT_FOUND Attempted to delete non-existant entry
+ @return EFI_OUT_OF_RESOURCES Not enough memory available
+
+**/
+EFI_STATUS
+EFIAPI
+CoreInstallConfigurationTable (
+ IN EFI_GUID *Guid,
+ IN VOID *Table
+ )
+{
+ UINTN Index;
+ EFI_CONFIGURATION_TABLE *EfiConfigurationTable;
+ EFI_CONFIGURATION_TABLE *OldTable;
+
+ //
+ // If Guid is NULL, then this operation cannot be performed
+ //
+ if (Guid == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ EfiConfigurationTable = gDxeCoreST->ConfigurationTable;
+
+ //
+ // Search all the table for an entry that matches Guid
+ //
+ for (Index = 0; Index < gDxeCoreST->NumberOfTableEntries; Index++) {
+ if (CompareGuid (Guid, &(gDxeCoreST->ConfigurationTable[Index].VendorGuid))) {
+ break;
+ }
+ }
+
+ if (Index < gDxeCoreST->NumberOfTableEntries) {
+ //
+ // A match was found, so this is either a modify or a delete operation
+ //
+ if (Table != NULL) {
+ //
+ // If Table is not NULL, then this is a modify operation.
+ // Modify the table entry and return.
+ //
+ gDxeCoreST->ConfigurationTable[Index].VendorTable = Table;
+
+ //
+ // Signal Configuration Table change
+ //
+ CoreNotifySignalList (Guid);
+
+ return EFI_SUCCESS;
+ }
+
+ //
+ // A match was found and Table is NULL, so this is a delete operation.
+ //
+ gDxeCoreST->NumberOfTableEntries--;
+
+ //
+ // Copy over deleted entry
+ //
+ CopyMem (
+ &(EfiConfigurationTable[Index]),
+ &(gDxeCoreST->ConfigurationTable[Index + 1]),
+ (gDxeCoreST->NumberOfTableEntries - Index) * sizeof (EFI_CONFIGURATION_TABLE)
+ );
+ } else {
+ //
+ // No matching GUIDs were found, so this is an add operation.
+ //
+
+ if (Table == NULL) {
+ //
+ // If Table is NULL on an add operation, then return an error.
+ //
+ return EFI_NOT_FOUND;
+ }
+
+ //
+ // Assume that Index == gDxeCoreST->NumberOfTableEntries
+ //
+ if ((Index * sizeof (EFI_CONFIGURATION_TABLE)) >= mSystemTableAllocateSize) {
+ //
+ // Allocate a table with one additional entry.
+ //
+ mSystemTableAllocateSize += (CONFIG_TABLE_SIZE_INCREASED * sizeof (EFI_CONFIGURATION_TABLE));
+ EfiConfigurationTable = AllocateRuntimePool (mSystemTableAllocateSize);
+ if (EfiConfigurationTable == NULL) {
+ //
+ // If a new table could not be allocated, then return an error.
+ //
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ if (gDxeCoreST->ConfigurationTable != NULL) {
+ //
+ // Copy the old table to the new table.
+ //
+ CopyMem (
+ EfiConfigurationTable,
+ gDxeCoreST->ConfigurationTable,
+ Index * sizeof (EFI_CONFIGURATION_TABLE)
+ );
+
+ //
+ // Record the old table pointer.
+ //
+ OldTable = gDxeCoreST->ConfigurationTable;
+
+ //
+ // As the CoreInstallConfigurationTable() may be re-entered by CoreFreePool()
+ // in its calling stack, updating System table to the new table pointer must
+ // be done before calling CoreFreePool() to free the old table.
+ // It can make sure the gDxeCoreST->ConfigurationTable point to the new table
+ // and avoid the errors of use-after-free to the old table by the reenter of
+ // CoreInstallConfigurationTable() in CoreFreePool()'s calling stack.
+ //
+ gDxeCoreST->ConfigurationTable = EfiConfigurationTable;
+
+ //
+ // Free the old table after updating System Table to the new table pointer.
+ //
+ CoreFreePool (OldTable);
+ } else {
+ //
+ // Update System Table
+ //
+ gDxeCoreST->ConfigurationTable = EfiConfigurationTable;
+ }
+ }
+
+ //
+ // Fill in the new entry
+ //
+ CopyGuid ((VOID *)&EfiConfigurationTable[Index].VendorGuid, Guid);
+ EfiConfigurationTable[Index].VendorTable = Table;
+
+ //
+ // This is an add operation, so increment the number of table entries
+ //
+ gDxeCoreST->NumberOfTableEntries++;
+ }
+
+ //
+ // Fix up the CRC-32 in the EFI System Table
+ //
+ CalculateEfiHdrCrc (&gDxeCoreST->Hdr);
+
+ //
+ // Signal Configuration Table change
+ //
+ CoreNotifySignalList (Guid);
+
+ return EFI_SUCCESS;
+}
diff --git a/MdeModulePkg/Core/Dxe/Misc/MemoryAttributesTable.c b/MdeModulePkg/Core/Dxe/Misc/MemoryAttributesTable.c
index e9343a2c4e..9abd79b9e4 100644
--- a/MdeModulePkg/Core/Dxe/Misc/MemoryAttributesTable.c
+++ b/MdeModulePkg/Core/Dxe/Misc/MemoryAttributesTable.c
@@ -1,687 +1,687 @@
-/** @file
- UEFI MemoryAttributesTable support
-
-Copyright (c) 2016 - 2018, Intel Corporation. All rights reserved.<BR>
-SPDX-License-Identifier: BSD-2-Clause-Patent
-
-**/
-
-#include <PiDxe.h>
-#include <Library/BaseLib.h>
-#include <Library/BaseMemoryLib.h>
-#include <Library/MemoryAllocationLib.h>
-#include <Library/UefiBootServicesTableLib.h>
-#include <Library/DxeServicesTableLib.h>
-#include <Library/DebugLib.h>
-#include <Library/UefiLib.h>
-#include <Library/ImagePropertiesRecordLib.h>
-
-#include <Guid/EventGroup.h>
-
-#include <Guid/MemoryAttributesTable.h>
-
-#include "DxeMain.h"
-#include "HeapGuard.h"
-
-/**
- This function for GetMemoryMap() with properties table capability.
-
- It calls original GetMemoryMap() to get the original memory map information. Then
- plus the additional memory map entries for PE Code/Data seperation.
-
- @param MemoryMapSize A pointer to the size, in bytes, of the
- MemoryMap buffer. On input, this is the size of
- the buffer allocated by the caller. On output,
- it is the size of the buffer returned by the
- firmware if the buffer was large enough, or the
- size of the buffer needed to contain the map if
- the buffer was too small.
- @param MemoryMap A pointer to the buffer in which firmware places
- the current memory map.
- @param MapKey A pointer to the location in which firmware
- returns the key for the current memory map.
- @param DescriptorSize A pointer to the location in which firmware
- returns the size, in bytes, of an individual
- EFI_MEMORY_DESCRIPTOR.
- @param DescriptorVersion A pointer to the location in which firmware
- returns the version number associated with the
- EFI_MEMORY_DESCRIPTOR.
-
- @retval EFI_SUCCESS The memory map was returned in the MemoryMap
- buffer.
- @retval EFI_BUFFER_TOO_SMALL The MemoryMap buffer was too small. The current
- buffer size needed to hold the memory map is
- returned in MemoryMapSize.
- @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
-
-**/
-EFI_STATUS
-EFIAPI
-CoreGetMemoryMapWithSeparatedImageSection (
- IN OUT UINTN *MemoryMapSize,
- IN OUT EFI_MEMORY_DESCRIPTOR *MemoryMap,
- OUT UINTN *MapKey,
- OUT UINTN *DescriptorSize,
- OUT UINT32 *DescriptorVersion
- );
-
-#define PREVIOUS_MEMORY_DESCRIPTOR(MemoryDescriptor, Size) \
- ((EFI_MEMORY_DESCRIPTOR *)((UINT8 *)(MemoryDescriptor) - (Size)))
-
-#define IMAGE_PROPERTIES_PRIVATE_DATA_SIGNATURE SIGNATURE_32 ('I','P','P','D')
-
-typedef struct {
- UINT32 Signature;
- UINTN ImageRecordCount;
- UINTN CodeSegmentCountMax;
- LIST_ENTRY ImageRecordList;
-} IMAGE_PROPERTIES_PRIVATE_DATA;
-
-STATIC IMAGE_PROPERTIES_PRIVATE_DATA mImagePropertiesPrivateData = {
- IMAGE_PROPERTIES_PRIVATE_DATA_SIGNATURE,
- 0,
- 0,
- INITIALIZE_LIST_HEAD_VARIABLE (mImagePropertiesPrivateData.ImageRecordList)
-};
-
-STATIC EFI_LOCK mMemoryAttributesTableLock = EFI_INITIALIZE_LOCK_VARIABLE (TPL_NOTIFY);
-
-BOOLEAN mMemoryAttributesTableEnable = TRUE;
-BOOLEAN mMemoryAttributesTableEndOfDxe = FALSE;
-EFI_MEMORY_ATTRIBUTES_TABLE *mMemoryAttributesTable = NULL;
-BOOLEAN mMemoryAttributesTableReadyToBoot = FALSE;
-BOOLEAN gMemoryAttributesTableForwardCfi = TRUE;
-
-/**
- Install MemoryAttributesTable.
-
-**/
-VOID
-InstallMemoryAttributesTable (
- VOID
- )
-{
- UINTN MemoryMapSize;
- EFI_MEMORY_DESCRIPTOR *MemoryMap;
- EFI_MEMORY_DESCRIPTOR *MemoryMapStart;
- UINTN MapKey;
- UINTN DescriptorSize;
- UINT32 DescriptorVersion;
- UINTN Index;
- EFI_STATUS Status;
- UINT32 RuntimeEntryCount;
- EFI_MEMORY_ATTRIBUTES_TABLE *MemoryAttributesTable;
- EFI_MEMORY_DESCRIPTOR *MemoryAttributesEntry;
-
- if (gMemoryMapTerminated) {
- //
- // Directly return after MemoryMap terminated.
- //
- return;
- }
-
- if (!mMemoryAttributesTableEnable) {
- DEBUG ((DEBUG_VERBOSE, "Cannot install Memory Attributes Table "));
- DEBUG ((DEBUG_VERBOSE, "because Runtime Driver Section Alignment is not %dK.\n", RUNTIME_PAGE_ALLOCATION_GRANULARITY >> 10));
- return;
- }
-
- if (mMemoryAttributesTable == NULL) {
- //
- // InstallConfigurationTable here to occupy one entry for MemoryAttributesTable
- // before GetMemoryMap below, as InstallConfigurationTable may allocate runtime
- // memory for the new entry.
- //
- Status = gBS->InstallConfigurationTable (&gEfiMemoryAttributesTableGuid, (VOID *)(UINTN)MAX_ADDRESS);
- ASSERT_EFI_ERROR (Status);
- }
-
- MemoryMapSize = 0;
- MemoryMap = NULL;
- Status = CoreGetMemoryMapWithSeparatedImageSection (
- &MemoryMapSize,
- MemoryMap,
- &MapKey,
- &DescriptorSize,
- &DescriptorVersion
- );
- ASSERT (Status == EFI_BUFFER_TOO_SMALL);
-
- do {
- MemoryMap = AllocatePool (MemoryMapSize);
- ASSERT (MemoryMap != NULL);
-
- Status = CoreGetMemoryMapWithSeparatedImageSection (
- &MemoryMapSize,
- MemoryMap,
- &MapKey,
- &DescriptorSize,
- &DescriptorVersion
- );
- if (EFI_ERROR (Status)) {
- FreePool (MemoryMap);
- }
- } while (Status == EFI_BUFFER_TOO_SMALL);
-
- MemoryMapStart = MemoryMap;
- RuntimeEntryCount = 0;
- for (Index = 0; Index < MemoryMapSize/DescriptorSize; Index++) {
- switch (MemoryMap->Type) {
- case EfiRuntimeServicesCode:
- case EfiRuntimeServicesData:
- RuntimeEntryCount++;
- break;
- }
-
- MemoryMap = NEXT_MEMORY_DESCRIPTOR (MemoryMap, DescriptorSize);
- }
-
- //
- // Allocate MemoryAttributesTable
- //
- MemoryAttributesTable = AllocatePool (sizeof (EFI_MEMORY_ATTRIBUTES_TABLE) + DescriptorSize * RuntimeEntryCount);
- ASSERT (MemoryAttributesTable != NULL);
- MemoryAttributesTable->Version = EFI_MEMORY_ATTRIBUTES_TABLE_VERSION;
- MemoryAttributesTable->NumberOfEntries = RuntimeEntryCount;
- MemoryAttributesTable->DescriptorSize = (UINT32)DescriptorSize;
- if (gMemoryAttributesTableForwardCfi) {
- MemoryAttributesTable->Flags = EFI_MEMORY_ATTRIBUTES_FLAGS_RT_FORWARD_CONTROL_FLOW_GUARD;
- } else {
- MemoryAttributesTable->Flags = 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);
- MemoryMap = MemoryMapStart;
- for (Index = 0; Index < MemoryMapSize/DescriptorSize; Index++) {
- switch (MemoryMap->Type) {
- case EfiRuntimeServicesCode:
- case EfiRuntimeServicesData:
- CopyMem (MemoryAttributesEntry, MemoryMap, DescriptorSize);
- MemoryAttributesEntry->Attribute &= (EFI_MEMORY_RO|EFI_MEMORY_XP|EFI_MEMORY_RUNTIME);
- DEBUG ((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);
- break;
- }
-
- MemoryMap = NEXT_MEMORY_DESCRIPTOR (MemoryMap, DescriptorSize);
- }
-
- MemoryMap = MemoryMapStart;
- FreePool (MemoryMap);
-
- //
- // Update configuratoin table for MemoryAttributesTable.
- //
- Status = gBS->InstallConfigurationTable (&gEfiMemoryAttributesTableGuid, MemoryAttributesTable);
- ASSERT_EFI_ERROR (Status);
-
- if (mMemoryAttributesTable != NULL) {
- FreePool (mMemoryAttributesTable);
- }
-
- mMemoryAttributesTable = MemoryAttributesTable;
-}
-
-/**
- Install MemoryAttributesTable on memory allocation.
-
- @param[in] MemoryType EFI memory type.
-**/
-VOID
-InstallMemoryAttributesTableOnMemoryAllocation (
- IN EFI_MEMORY_TYPE MemoryType
- )
-{
- //
- // Install MemoryAttributesTable after ReadyToBoot on runtime memory allocation.
- //
- if (mMemoryAttributesTableReadyToBoot &&
- ((MemoryType == EfiRuntimeServicesCode) || (MemoryType == EfiRuntimeServicesData)))
- {
- InstallMemoryAttributesTable ();
- }
-}
-
-/**
- Install MemoryAttributesTable on ReadyToBoot.
-
- @param[in] Event The Event this notify function registered to.
- @param[in] Context Pointer to the context data registered to the Event.
-**/
-VOID
-EFIAPI
-InstallMemoryAttributesTableOnReadyToBoot (
- IN EFI_EVENT Event,
- IN VOID *Context
- )
-{
- InstallMemoryAttributesTable ();
- mMemoryAttributesTableReadyToBoot = TRUE;
-}
-
-/**
- Install initial MemoryAttributesTable on EndOfDxe.
- Then SMM can consume this information.
-
- @param[in] Event The Event this notify function registered to.
- @param[in] Context Pointer to the context data registered to the Event.
-**/
-VOID
-EFIAPI
-InstallMemoryAttributesTableOnEndOfDxe (
- IN EFI_EVENT Event,
- IN VOID *Context
- )
-{
- mMemoryAttributesTableEndOfDxe = TRUE;
- InstallMemoryAttributesTable ();
-
- DEBUG_CODE_BEGIN ();
- if ( mImagePropertiesPrivateData.ImageRecordCount > 0) {
- DEBUG ((DEBUG_INFO, "DXE - Total Runtime Image Count: 0x%x\n", mImagePropertiesPrivateData.ImageRecordCount));
- DEBUG ((DEBUG_INFO, "DXE - Dump Runtime Image Records:\n"));
- DumpImageRecords (&mImagePropertiesPrivateData.ImageRecordList);
- }
-
- DEBUG_CODE_END ();
-}
-
-/**
- Initialize MemoryAttrubutesTable support.
-**/
-VOID
-EFIAPI
-CoreInitializeMemoryAttributesTable (
- VOID
- )
-{
- EFI_STATUS Status;
- EFI_EVENT ReadyToBootEvent;
- EFI_EVENT EndOfDxeEvent;
-
- //
- // Construct the table at ReadyToBoot.
- //
- Status = CoreCreateEventInternal (
- EVT_NOTIFY_SIGNAL,
- TPL_CALLBACK,
- InstallMemoryAttributesTableOnReadyToBoot,
- NULL,
- &gEfiEventReadyToBootGuid,
- &ReadyToBootEvent
- );
- ASSERT_EFI_ERROR (Status);
-
- //
- // Construct the initial table at EndOfDxe,
- // then SMM can consume this information.
- // Use TPL_NOTIFY here, as such SMM code (TPL_CALLBACK)
- // can run after it.
- //
- Status = CoreCreateEventInternal (
- EVT_NOTIFY_SIGNAL,
- TPL_NOTIFY,
- InstallMemoryAttributesTableOnEndOfDxe,
- NULL,
- &gEfiEndOfDxeEventGroupGuid,
- &EndOfDxeEvent
- );
- ASSERT_EFI_ERROR (Status);
- return;
-}
-
-//
-// Below functions are for MemoryMap
-//
-
-/**
- Acquire memory lock on mMemoryAttributesTableLock.
-**/
-STATIC
-VOID
-CoreAcquiremMemoryAttributesTableLock (
- VOID
- )
-{
- CoreAcquireLock (&mMemoryAttributesTableLock);
-}
-
-/**
- Release memory lock on mMemoryAttributesTableLock.
-**/
-STATIC
-VOID
-CoreReleasemMemoryAttributesTableLock (
- VOID
- )
-{
- CoreReleaseLock (&mMemoryAttributesTableLock);
-}
-
-/**
- Merge continous memory map entries whose have same attributes.
-
- @param MemoryMap A pointer to the buffer in which firmware places
- the current memory map.
- @param MemoryMapSize A pointer to the size, in bytes, of the
- MemoryMap buffer. On input, this is the size of
- the current memory map. On output,
- it is the size of new memory map after merge.
- @param DescriptorSize Size, in bytes, of an individual EFI_MEMORY_DESCRIPTOR.
-**/
-VOID
-MergeMemoryMap (
- IN OUT EFI_MEMORY_DESCRIPTOR *MemoryMap,
- IN OUT UINTN *MemoryMapSize,
- IN UINTN DescriptorSize
- )
-{
- EFI_MEMORY_DESCRIPTOR *MemoryMapEntry;
- EFI_MEMORY_DESCRIPTOR *MemoryMapEnd;
- UINT64 MemoryBlockLength;
- EFI_MEMORY_DESCRIPTOR *NewMemoryMapEntry;
- EFI_MEMORY_DESCRIPTOR *NextMemoryMapEntry;
-
- MemoryMapEntry = MemoryMap;
- NewMemoryMapEntry = MemoryMap;
- MemoryMapEnd = (EFI_MEMORY_DESCRIPTOR *)((UINT8 *)MemoryMap + *MemoryMapSize);
- while ((UINTN)MemoryMapEntry < (UINTN)MemoryMapEnd) {
- CopyMem (NewMemoryMapEntry, MemoryMapEntry, sizeof (EFI_MEMORY_DESCRIPTOR));
- NextMemoryMapEntry = NEXT_MEMORY_DESCRIPTOR (MemoryMapEntry, DescriptorSize);
-
- do {
- MergeGuardPages (NewMemoryMapEntry, NextMemoryMapEntry->PhysicalStart);
- MemoryBlockLength = LShiftU64 (NewMemoryMapEntry->NumberOfPages, EFI_PAGE_SHIFT);
- if (((UINTN)NextMemoryMapEntry < (UINTN)MemoryMapEnd) &&
- (NewMemoryMapEntry->Type == NextMemoryMapEntry->Type) &&
- (NewMemoryMapEntry->Attribute == NextMemoryMapEntry->Attribute) &&
- ((NewMemoryMapEntry->PhysicalStart + MemoryBlockLength) == NextMemoryMapEntry->PhysicalStart))
- {
- NewMemoryMapEntry->NumberOfPages += NextMemoryMapEntry->NumberOfPages;
- NextMemoryMapEntry = NEXT_MEMORY_DESCRIPTOR (NextMemoryMapEntry, DescriptorSize);
- continue;
- } else {
- MemoryMapEntry = PREVIOUS_MEMORY_DESCRIPTOR (NextMemoryMapEntry, DescriptorSize);
- break;
- }
- } while (TRUE);
-
- MemoryMapEntry = NEXT_MEMORY_DESCRIPTOR (MemoryMapEntry, DescriptorSize);
- NewMemoryMapEntry = NEXT_MEMORY_DESCRIPTOR (NewMemoryMapEntry, DescriptorSize);
- }
-
- *MemoryMapSize = (UINTN)NewMemoryMapEntry - (UINTN)MemoryMap;
-
- return;
-}
-
-/**
- Enforce memory map attributes.
- This function will set EfiRuntimeServicesData/EfiMemoryMappedIO/EfiMemoryMappedIOPortSpace to be EFI_MEMORY_XP.
-
- @param MemoryMap A pointer to the buffer in which firmware places
- the current memory map.
- @param MemoryMapSize Size, in bytes, of the MemoryMap buffer.
- @param DescriptorSize Size, in bytes, of an individual EFI_MEMORY_DESCRIPTOR.
-**/
-STATIC
-VOID
-EnforceMemoryMapAttribute (
- IN OUT EFI_MEMORY_DESCRIPTOR *MemoryMap,
- IN UINTN MemoryMapSize,
- IN UINTN DescriptorSize
- )
-{
- EFI_MEMORY_DESCRIPTOR *MemoryMapEntry;
- EFI_MEMORY_DESCRIPTOR *MemoryMapEnd;
-
- MemoryMapEntry = MemoryMap;
- MemoryMapEnd = (EFI_MEMORY_DESCRIPTOR *)((UINT8 *)MemoryMap + MemoryMapSize);
- while ((UINTN)MemoryMapEntry < (UINTN)MemoryMapEnd) {
- switch (MemoryMapEntry->Type) {
- case EfiRuntimeServicesCode:
- // do nothing
- break;
- case EfiRuntimeServicesData:
- case EfiMemoryMappedIO:
- case EfiMemoryMappedIOPortSpace:
- MemoryMapEntry->Attribute |= EFI_MEMORY_XP;
- break;
- case EfiReservedMemoryType:
- case EfiACPIMemoryNVS:
- break;
- }
-
- MemoryMapEntry = NEXT_MEMORY_DESCRIPTOR (MemoryMapEntry, DescriptorSize);
- }
-
- return;
-}
-
-/**
- This function for GetMemoryMap() with properties table capability.
-
- It calls original GetMemoryMap() to get the original memory map information. Then
- plus the additional memory map entries for PE Code/Data seperation.
-
- @param MemoryMapSize A pointer to the size, in bytes, of the
- MemoryMap buffer. On input, this is the size of
- the buffer allocated by the caller. On output,
- it is the size of the buffer returned by the
- firmware if the buffer was large enough, or the
- size of the buffer needed to contain the map if
- the buffer was too small.
- @param MemoryMap A pointer to the buffer in which firmware places
- the current memory map.
- @param MapKey A pointer to the location in which firmware
- returns the key for the current memory map.
- @param DescriptorSize A pointer to the location in which firmware
- returns the size, in bytes, of an individual
- EFI_MEMORY_DESCRIPTOR.
- @param DescriptorVersion A pointer to the location in which firmware
- returns the version number associated with the
- EFI_MEMORY_DESCRIPTOR.
-
- @retval EFI_SUCCESS The memory map was returned in the MemoryMap
- buffer.
- @retval EFI_BUFFER_TOO_SMALL The MemoryMap buffer was too small. The current
- buffer size needed to hold the memory map is
- returned in MemoryMapSize.
- @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
-
-**/
-EFI_STATUS
-EFIAPI
-CoreGetMemoryMapWithSeparatedImageSection (
- IN OUT UINTN *MemoryMapSize,
- IN OUT EFI_MEMORY_DESCRIPTOR *MemoryMap,
- OUT UINTN *MapKey,
- OUT UINTN *DescriptorSize,
- OUT UINT32 *DescriptorVersion
- )
-{
- EFI_STATUS Status;
- UINTN OldMemoryMapSize;
- UINTN AdditionalRecordCount;
-
- //
- // If PE code/data is not aligned, just return.
- //
- if (!mMemoryAttributesTableEnable) {
- return CoreGetMemoryMap (MemoryMapSize, MemoryMap, MapKey, DescriptorSize, DescriptorVersion);
- }
-
- if (MemoryMapSize == NULL) {
- return EFI_INVALID_PARAMETER;
- }
-
- CoreAcquiremMemoryAttributesTableLock ();
-
- AdditionalRecordCount = (2 * mImagePropertiesPrivateData.CodeSegmentCountMax + 3) * mImagePropertiesPrivateData.ImageRecordCount;
-
- OldMemoryMapSize = *MemoryMapSize;
- Status = CoreGetMemoryMap (MemoryMapSize, MemoryMap, MapKey, DescriptorSize, DescriptorVersion);
- if (Status == EFI_BUFFER_TOO_SMALL) {
- *MemoryMapSize = *MemoryMapSize + (*DescriptorSize) * AdditionalRecordCount;
- } else if (Status == EFI_SUCCESS) {
- ASSERT (MemoryMap != NULL);
- if (OldMemoryMapSize - *MemoryMapSize < (*DescriptorSize) * AdditionalRecordCount) {
- *MemoryMapSize = *MemoryMapSize + (*DescriptorSize) * AdditionalRecordCount;
- //
- // Need update status to buffer too small
- //
- Status = EFI_BUFFER_TOO_SMALL;
- } else {
- //
- // Split PE code/data
- //
- SplitTable (MemoryMapSize, MemoryMap, *DescriptorSize, &mImagePropertiesPrivateData.ImageRecordList, AdditionalRecordCount);
-
- //
- // Set RuntimeData to XP
- //
- EnforceMemoryMapAttribute (MemoryMap, *MemoryMapSize, *DescriptorSize);
-
- //
- // Merge same type to save entry size
- //
- MergeMemoryMap (MemoryMap, MemoryMapSize, *DescriptorSize);
- }
- }
-
- CoreReleasemMemoryAttributesTableLock ();
- return Status;
-}
-
-//
-// Below functions are for ImageRecord
-//
-
-/**
- Insert image record.
-
- @param RuntimeImage Runtime image information
-**/
-VOID
-InsertImageRecord (
- IN EFI_RUNTIME_IMAGE_ENTRY *RuntimeImage
- )
-{
- EFI_STATUS Status;
- IMAGE_PROPERTIES_RECORD *ImageRecord;
- CHAR8 *PdbPointer;
- UINT32 RequiredAlignment;
-
- DEBUG ((DEBUG_VERBOSE, "InsertImageRecord - 0x%x\n", RuntimeImage));
-
- if (mMemoryAttributesTableEndOfDxe) {
- DEBUG ((DEBUG_INFO, "Do not insert runtime image record after EndOfDxe\n"));
- return;
- }
-
- ImageRecord = AllocatePool (sizeof (*ImageRecord));
- if (ImageRecord == NULL) {
- return;
- }
-
- InitializeListHead (&ImageRecord->Link);
- InitializeListHead (&ImageRecord->CodeSegmentList);
-
- PdbPointer = PeCoffLoaderGetPdbPointer ((VOID *)(UINTN)RuntimeImage->ImageBase);
- if (PdbPointer != NULL) {
- DEBUG ((DEBUG_VERBOSE, " Image - %a\n", PdbPointer));
- }
-
- RequiredAlignment = RUNTIME_PAGE_ALLOCATION_GRANULARITY;
- Status = CreateImagePropertiesRecord (
- RuntimeImage->ImageBase,
- RuntimeImage->ImageSize,
- &RequiredAlignment,
- ImageRecord
- );
-
- if (EFI_ERROR (Status)) {
- if (Status == EFI_ABORTED) {
- mMemoryAttributesTableEnable = FALSE;
- }
-
- Status = EFI_ABORTED;
- goto Finish;
- }
-
- if (ImageRecord->CodeSegmentCount == 0) {
- mMemoryAttributesTableEnable = FALSE;
- DEBUG ((DEBUG_ERROR, "!!!!!!!! InsertImageRecord - CodeSegmentCount is 0 !!!!!!!!\n"));
- if (PdbPointer != NULL) {
- DEBUG ((DEBUG_ERROR, "!!!!!!!! Image - %a !!!!!!!!\n", PdbPointer));
- }
-
- Status = EFI_ABORTED;
- goto Finish;
- }
-
- //
- // Check overlap all section in ImageBase/Size
- //
- if (!IsImageRecordCodeSectionValid (ImageRecord)) {
- DEBUG ((DEBUG_ERROR, "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;
-}
-
-/**
- Remove Image record.
-
- @param RuntimeImage Runtime image information
-**/
-VOID
-RemoveImageRecord (
- IN EFI_RUNTIME_IMAGE_ENTRY *RuntimeImage
- )
-{
- IMAGE_PROPERTIES_RECORD *ImageRecord;
-
- DEBUG ((DEBUG_VERBOSE, "RemoveImageRecord - 0x%x\n", RuntimeImage));
- DEBUG ((DEBUG_VERBOSE, "RemoveImageRecord - 0x%016lx - 0x%016lx\n", (EFI_PHYSICAL_ADDRESS)(UINTN)RuntimeImage->ImageBase, RuntimeImage->ImageSize));
-
- if (mMemoryAttributesTableEndOfDxe) {
- DEBUG ((DEBUG_INFO, "Do not remove runtime image record after EndOfDxe\n"));
- return;
- }
-
- ImageRecord = FindImageRecord ((EFI_PHYSICAL_ADDRESS)(UINTN)RuntimeImage->ImageBase, RuntimeImage->ImageSize, &mImagePropertiesPrivateData.ImageRecordList);
- if (ImageRecord == NULL) {
- DEBUG ((DEBUG_ERROR, "!!!!!!!! ImageRecord not found !!!!!!!!\n"));
- return;
- }
-
- DeleteImagePropertiesRecord (ImageRecord);
-
- mImagePropertiesPrivateData.ImageRecordCount--;
-}
+/** @file
+ UEFI MemoryAttributesTable support
+
+Copyright (c) 2016 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <PiDxe.h>
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/DxeServicesTableLib.h>
+#include <Library/DebugLib.h>
+#include <Library/UefiLib.h>
+#include <Library/ImagePropertiesRecordLib.h>
+
+#include <Guid/EventGroup.h>
+
+#include <Guid/MemoryAttributesTable.h>
+
+#include "DxeMain.h"
+#include "HeapGuard.h"
+
+/**
+ This function for GetMemoryMap() with properties table capability.
+
+ It calls original GetMemoryMap() to get the original memory map information. Then
+ plus the additional memory map entries for PE Code/Data seperation.
+
+ @param MemoryMapSize A pointer to the size, in bytes, of the
+ MemoryMap buffer. On input, this is the size of
+ the buffer allocated by the caller. On output,
+ it is the size of the buffer returned by the
+ firmware if the buffer was large enough, or the
+ size of the buffer needed to contain the map if
+ the buffer was too small.
+ @param MemoryMap A pointer to the buffer in which firmware places
+ the current memory map.
+ @param MapKey A pointer to the location in which firmware
+ returns the key for the current memory map.
+ @param DescriptorSize A pointer to the location in which firmware
+ returns the size, in bytes, of an individual
+ EFI_MEMORY_DESCRIPTOR.
+ @param DescriptorVersion A pointer to the location in which firmware
+ returns the version number associated with the
+ EFI_MEMORY_DESCRIPTOR.
+
+ @retval EFI_SUCCESS The memory map was returned in the MemoryMap
+ buffer.
+ @retval EFI_BUFFER_TOO_SMALL The MemoryMap buffer was too small. The current
+ buffer size needed to hold the memory map is
+ returned in MemoryMapSize.
+ @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
+
+**/
+EFI_STATUS
+EFIAPI
+CoreGetMemoryMapWithSeparatedImageSection (
+ IN OUT UINTN *MemoryMapSize,
+ IN OUT EFI_MEMORY_DESCRIPTOR *MemoryMap,
+ OUT UINTN *MapKey,
+ OUT UINTN *DescriptorSize,
+ OUT UINT32 *DescriptorVersion
+ );
+
+#define PREVIOUS_MEMORY_DESCRIPTOR(MemoryDescriptor, Size) \
+ ((EFI_MEMORY_DESCRIPTOR *)((UINT8 *)(MemoryDescriptor) - (Size)))
+
+#define IMAGE_PROPERTIES_PRIVATE_DATA_SIGNATURE SIGNATURE_32 ('I','P','P','D')
+
+typedef struct {
+ UINT32 Signature;
+ UINTN ImageRecordCount;
+ UINTN CodeSegmentCountMax;
+ LIST_ENTRY ImageRecordList;
+} IMAGE_PROPERTIES_PRIVATE_DATA;
+
+STATIC IMAGE_PROPERTIES_PRIVATE_DATA mImagePropertiesPrivateData = {
+ IMAGE_PROPERTIES_PRIVATE_DATA_SIGNATURE,
+ 0,
+ 0,
+ INITIALIZE_LIST_HEAD_VARIABLE (mImagePropertiesPrivateData.ImageRecordList)
+};
+
+STATIC EFI_LOCK mMemoryAttributesTableLock = EFI_INITIALIZE_LOCK_VARIABLE (TPL_NOTIFY);
+
+BOOLEAN mMemoryAttributesTableEnable = TRUE;
+BOOLEAN mMemoryAttributesTableEndOfDxe = FALSE;
+EFI_MEMORY_ATTRIBUTES_TABLE *mMemoryAttributesTable = NULL;
+BOOLEAN mMemoryAttributesTableReadyToBoot = FALSE;
+BOOLEAN gMemoryAttributesTableForwardCfi = TRUE;
+
+/**
+ Install MemoryAttributesTable.
+
+**/
+VOID
+InstallMemoryAttributesTable (
+ VOID
+ )
+{
+ UINTN MemoryMapSize;
+ EFI_MEMORY_DESCRIPTOR *MemoryMap;
+ EFI_MEMORY_DESCRIPTOR *MemoryMapStart;
+ UINTN MapKey;
+ UINTN DescriptorSize;
+ UINT32 DescriptorVersion;
+ UINTN Index;
+ EFI_STATUS Status;
+ UINT32 RuntimeEntryCount;
+ EFI_MEMORY_ATTRIBUTES_TABLE *MemoryAttributesTable;
+ EFI_MEMORY_DESCRIPTOR *MemoryAttributesEntry;
+
+ if (gMemoryMapTerminated) {
+ //
+ // Directly return after MemoryMap terminated.
+ //
+ return;
+ }
+
+ if (!mMemoryAttributesTableEnable) {
+ DEBUG ((DEBUG_VERBOSE, "Cannot install Memory Attributes Table "));
+ DEBUG ((DEBUG_VERBOSE, "because Runtime Driver Section Alignment is not %dK.\n", RUNTIME_PAGE_ALLOCATION_GRANULARITY >> 10));
+ return;
+ }
+
+ if (mMemoryAttributesTable == NULL) {
+ //
+ // InstallConfigurationTable here to occupy one entry for MemoryAttributesTable
+ // before GetMemoryMap below, as InstallConfigurationTable may allocate runtime
+ // memory for the new entry.
+ //
+ Status = gBS->InstallConfigurationTable (&gEfiMemoryAttributesTableGuid, (VOID *)(UINTN)MAX_ADDRESS);
+ ASSERT_EFI_ERROR (Status);
+ }
+
+ MemoryMapSize = 0;
+ MemoryMap = NULL;
+ Status = CoreGetMemoryMapWithSeparatedImageSection (
+ &MemoryMapSize,
+ MemoryMap,
+ &MapKey,
+ &DescriptorSize,
+ &DescriptorVersion
+ );
+ ASSERT (Status == EFI_BUFFER_TOO_SMALL);
+
+ do {
+ MemoryMap = AllocatePool (MemoryMapSize);
+ ASSERT (MemoryMap != NULL);
+
+ Status = CoreGetMemoryMapWithSeparatedImageSection (
+ &MemoryMapSize,
+ MemoryMap,
+ &MapKey,
+ &DescriptorSize,
+ &DescriptorVersion
+ );
+ if (EFI_ERROR (Status)) {
+ FreePool (MemoryMap);
+ }
+ } while (Status == EFI_BUFFER_TOO_SMALL);
+
+ MemoryMapStart = MemoryMap;
+ RuntimeEntryCount = 0;
+ for (Index = 0; Index < MemoryMapSize/DescriptorSize; Index++) {
+ switch (MemoryMap->Type) {
+ case EfiRuntimeServicesCode:
+ case EfiRuntimeServicesData:
+ RuntimeEntryCount++;
+ break;
+ }
+
+ MemoryMap = NEXT_MEMORY_DESCRIPTOR (MemoryMap, DescriptorSize);
+ }
+
+ //
+ // Allocate MemoryAttributesTable
+ //
+ MemoryAttributesTable = AllocatePool (sizeof (EFI_MEMORY_ATTRIBUTES_TABLE) + DescriptorSize * RuntimeEntryCount);
+ ASSERT (MemoryAttributesTable != NULL);
+ MemoryAttributesTable->Version = EFI_MEMORY_ATTRIBUTES_TABLE_VERSION;
+ MemoryAttributesTable->NumberOfEntries = RuntimeEntryCount;
+ MemoryAttributesTable->DescriptorSize = (UINT32)DescriptorSize;
+ if (gMemoryAttributesTableForwardCfi) {
+ MemoryAttributesTable->Flags = EFI_MEMORY_ATTRIBUTES_FLAGS_RT_FORWARD_CONTROL_FLOW_GUARD;
+ } else {
+ MemoryAttributesTable->Flags = 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);
+ MemoryMap = MemoryMapStart;
+ for (Index = 0; Index < MemoryMapSize/DescriptorSize; Index++) {
+ switch (MemoryMap->Type) {
+ case EfiRuntimeServicesCode:
+ case EfiRuntimeServicesData:
+ CopyMem (MemoryAttributesEntry, MemoryMap, DescriptorSize);
+ MemoryAttributesEntry->Attribute &= (EFI_MEMORY_RO|EFI_MEMORY_XP|EFI_MEMORY_RUNTIME);
+ DEBUG ((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);
+ break;
+ }
+
+ MemoryMap = NEXT_MEMORY_DESCRIPTOR (MemoryMap, DescriptorSize);
+ }
+
+ MemoryMap = MemoryMapStart;
+ FreePool (MemoryMap);
+
+ //
+ // Update configuratoin table for MemoryAttributesTable.
+ //
+ Status = gBS->InstallConfigurationTable (&gEfiMemoryAttributesTableGuid, MemoryAttributesTable);
+ ASSERT_EFI_ERROR (Status);
+
+ if (mMemoryAttributesTable != NULL) {
+ FreePool (mMemoryAttributesTable);
+ }
+
+ mMemoryAttributesTable = MemoryAttributesTable;
+}
+
+/**
+ Install MemoryAttributesTable on memory allocation.
+
+ @param[in] MemoryType EFI memory type.
+**/
+VOID
+InstallMemoryAttributesTableOnMemoryAllocation (
+ IN EFI_MEMORY_TYPE MemoryType
+ )
+{
+ //
+ // Install MemoryAttributesTable after ReadyToBoot on runtime memory allocation.
+ //
+ if (mMemoryAttributesTableReadyToBoot &&
+ ((MemoryType == EfiRuntimeServicesCode) || (MemoryType == EfiRuntimeServicesData)))
+ {
+ InstallMemoryAttributesTable ();
+ }
+}
+
+/**
+ Install MemoryAttributesTable on ReadyToBoot.
+
+ @param[in] Event The Event this notify function registered to.
+ @param[in] Context Pointer to the context data registered to the Event.
+**/
+VOID
+EFIAPI
+InstallMemoryAttributesTableOnReadyToBoot (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ InstallMemoryAttributesTable ();
+ mMemoryAttributesTableReadyToBoot = TRUE;
+}
+
+/**
+ Install initial MemoryAttributesTable on EndOfDxe.
+ Then SMM can consume this information.
+
+ @param[in] Event The Event this notify function registered to.
+ @param[in] Context Pointer to the context data registered to the Event.
+**/
+VOID
+EFIAPI
+InstallMemoryAttributesTableOnEndOfDxe (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ mMemoryAttributesTableEndOfDxe = TRUE;
+ InstallMemoryAttributesTable ();
+
+ DEBUG_CODE_BEGIN ();
+ if ( mImagePropertiesPrivateData.ImageRecordCount > 0) {
+ DEBUG ((DEBUG_INFO, "DXE - Total Runtime Image Count: 0x%x\n", mImagePropertiesPrivateData.ImageRecordCount));
+ DEBUG ((DEBUG_INFO, "DXE - Dump Runtime Image Records:\n"));
+ DumpImageRecords (&mImagePropertiesPrivateData.ImageRecordList);
+ }
+
+ DEBUG_CODE_END ();
+}
+
+/**
+ Initialize MemoryAttrubutesTable support.
+**/
+VOID
+EFIAPI
+CoreInitializeMemoryAttributesTable (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ EFI_EVENT ReadyToBootEvent;
+ EFI_EVENT EndOfDxeEvent;
+
+ //
+ // Construct the table at ReadyToBoot.
+ //
+ Status = CoreCreateEventInternal (
+ EVT_NOTIFY_SIGNAL,
+ TPL_CALLBACK,
+ InstallMemoryAttributesTableOnReadyToBoot,
+ NULL,
+ &gEfiEventReadyToBootGuid,
+ &ReadyToBootEvent
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Construct the initial table at EndOfDxe,
+ // then SMM can consume this information.
+ // Use TPL_NOTIFY here, as such SMM code (TPL_CALLBACK)
+ // can run after it.
+ //
+ Status = CoreCreateEventInternal (
+ EVT_NOTIFY_SIGNAL,
+ TPL_NOTIFY,
+ InstallMemoryAttributesTableOnEndOfDxe,
+ NULL,
+ &gEfiEndOfDxeEventGroupGuid,
+ &EndOfDxeEvent
+ );
+ ASSERT_EFI_ERROR (Status);
+ return;
+}
+
+//
+// Below functions are for MemoryMap
+//
+
+/**
+ Acquire memory lock on mMemoryAttributesTableLock.
+**/
+STATIC
+VOID
+CoreAcquiremMemoryAttributesTableLock (
+ VOID
+ )
+{
+ CoreAcquireLock (&mMemoryAttributesTableLock);
+}
+
+/**
+ Release memory lock on mMemoryAttributesTableLock.
+**/
+STATIC
+VOID
+CoreReleasemMemoryAttributesTableLock (
+ VOID
+ )
+{
+ CoreReleaseLock (&mMemoryAttributesTableLock);
+}
+
+/**
+ Merge continous memory map entries whose have same attributes.
+
+ @param MemoryMap A pointer to the buffer in which firmware places
+ the current memory map.
+ @param MemoryMapSize A pointer to the size, in bytes, of the
+ MemoryMap buffer. On input, this is the size of
+ the current memory map. On output,
+ it is the size of new memory map after merge.
+ @param DescriptorSize Size, in bytes, of an individual EFI_MEMORY_DESCRIPTOR.
+**/
+VOID
+MergeMemoryMap (
+ IN OUT EFI_MEMORY_DESCRIPTOR *MemoryMap,
+ IN OUT UINTN *MemoryMapSize,
+ IN UINTN DescriptorSize
+ )
+{
+ EFI_MEMORY_DESCRIPTOR *MemoryMapEntry;
+ EFI_MEMORY_DESCRIPTOR *MemoryMapEnd;
+ UINT64 MemoryBlockLength;
+ EFI_MEMORY_DESCRIPTOR *NewMemoryMapEntry;
+ EFI_MEMORY_DESCRIPTOR *NextMemoryMapEntry;
+
+ MemoryMapEntry = MemoryMap;
+ NewMemoryMapEntry = MemoryMap;
+ MemoryMapEnd = (EFI_MEMORY_DESCRIPTOR *)((UINT8 *)MemoryMap + *MemoryMapSize);
+ while ((UINTN)MemoryMapEntry < (UINTN)MemoryMapEnd) {
+ CopyMem (NewMemoryMapEntry, MemoryMapEntry, sizeof (EFI_MEMORY_DESCRIPTOR));
+ NextMemoryMapEntry = NEXT_MEMORY_DESCRIPTOR (MemoryMapEntry, DescriptorSize);
+
+ do {
+ MergeGuardPages (NewMemoryMapEntry, NextMemoryMapEntry->PhysicalStart);
+ MemoryBlockLength = LShiftU64 (NewMemoryMapEntry->NumberOfPages, EFI_PAGE_SHIFT);
+ if (((UINTN)NextMemoryMapEntry < (UINTN)MemoryMapEnd) &&
+ (NewMemoryMapEntry->Type == NextMemoryMapEntry->Type) &&
+ (NewMemoryMapEntry->Attribute == NextMemoryMapEntry->Attribute) &&
+ ((NewMemoryMapEntry->PhysicalStart + MemoryBlockLength) == NextMemoryMapEntry->PhysicalStart))
+ {
+ NewMemoryMapEntry->NumberOfPages += NextMemoryMapEntry->NumberOfPages;
+ NextMemoryMapEntry = NEXT_MEMORY_DESCRIPTOR (NextMemoryMapEntry, DescriptorSize);
+ continue;
+ } else {
+ MemoryMapEntry = PREVIOUS_MEMORY_DESCRIPTOR (NextMemoryMapEntry, DescriptorSize);
+ break;
+ }
+ } while (TRUE);
+
+ MemoryMapEntry = NEXT_MEMORY_DESCRIPTOR (MemoryMapEntry, DescriptorSize);
+ NewMemoryMapEntry = NEXT_MEMORY_DESCRIPTOR (NewMemoryMapEntry, DescriptorSize);
+ }
+
+ *MemoryMapSize = (UINTN)NewMemoryMapEntry - (UINTN)MemoryMap;
+
+ return;
+}
+
+/**
+ Enforce memory map attributes.
+ This function will set EfiRuntimeServicesData/EfiMemoryMappedIO/EfiMemoryMappedIOPortSpace to be EFI_MEMORY_XP.
+
+ @param MemoryMap A pointer to the buffer in which firmware places
+ the current memory map.
+ @param MemoryMapSize Size, in bytes, of the MemoryMap buffer.
+ @param DescriptorSize Size, in bytes, of an individual EFI_MEMORY_DESCRIPTOR.
+**/
+STATIC
+VOID
+EnforceMemoryMapAttribute (
+ IN OUT EFI_MEMORY_DESCRIPTOR *MemoryMap,
+ IN UINTN MemoryMapSize,
+ IN UINTN DescriptorSize
+ )
+{
+ EFI_MEMORY_DESCRIPTOR *MemoryMapEntry;
+ EFI_MEMORY_DESCRIPTOR *MemoryMapEnd;
+
+ MemoryMapEntry = MemoryMap;
+ MemoryMapEnd = (EFI_MEMORY_DESCRIPTOR *)((UINT8 *)MemoryMap + MemoryMapSize);
+ while ((UINTN)MemoryMapEntry < (UINTN)MemoryMapEnd) {
+ switch (MemoryMapEntry->Type) {
+ case EfiRuntimeServicesCode:
+ // do nothing
+ break;
+ case EfiRuntimeServicesData:
+ case EfiMemoryMappedIO:
+ case EfiMemoryMappedIOPortSpace:
+ MemoryMapEntry->Attribute |= EFI_MEMORY_XP;
+ break;
+ case EfiReservedMemoryType:
+ case EfiACPIMemoryNVS:
+ break;
+ }
+
+ MemoryMapEntry = NEXT_MEMORY_DESCRIPTOR (MemoryMapEntry, DescriptorSize);
+ }
+
+ return;
+}
+
+/**
+ This function for GetMemoryMap() with properties table capability.
+
+ It calls original GetMemoryMap() to get the original memory map information. Then
+ plus the additional memory map entries for PE Code/Data seperation.
+
+ @param MemoryMapSize A pointer to the size, in bytes, of the
+ MemoryMap buffer. On input, this is the size of
+ the buffer allocated by the caller. On output,
+ it is the size of the buffer returned by the
+ firmware if the buffer was large enough, or the
+ size of the buffer needed to contain the map if
+ the buffer was too small.
+ @param MemoryMap A pointer to the buffer in which firmware places
+ the current memory map.
+ @param MapKey A pointer to the location in which firmware
+ returns the key for the current memory map.
+ @param DescriptorSize A pointer to the location in which firmware
+ returns the size, in bytes, of an individual
+ EFI_MEMORY_DESCRIPTOR.
+ @param DescriptorVersion A pointer to the location in which firmware
+ returns the version number associated with the
+ EFI_MEMORY_DESCRIPTOR.
+
+ @retval EFI_SUCCESS The memory map was returned in the MemoryMap
+ buffer.
+ @retval EFI_BUFFER_TOO_SMALL The MemoryMap buffer was too small. The current
+ buffer size needed to hold the memory map is
+ returned in MemoryMapSize.
+ @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
+
+**/
+EFI_STATUS
+EFIAPI
+CoreGetMemoryMapWithSeparatedImageSection (
+ IN OUT UINTN *MemoryMapSize,
+ IN OUT EFI_MEMORY_DESCRIPTOR *MemoryMap,
+ OUT UINTN *MapKey,
+ OUT UINTN *DescriptorSize,
+ OUT UINT32 *DescriptorVersion
+ )
+{
+ EFI_STATUS Status;
+ UINTN OldMemoryMapSize;
+ UINTN AdditionalRecordCount;
+
+ //
+ // If PE code/data is not aligned, just return.
+ //
+ if (!mMemoryAttributesTableEnable) {
+ return CoreGetMemoryMap (MemoryMapSize, MemoryMap, MapKey, DescriptorSize, DescriptorVersion);
+ }
+
+ if (MemoryMapSize == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ CoreAcquiremMemoryAttributesTableLock ();
+
+ AdditionalRecordCount = (2 * mImagePropertiesPrivateData.CodeSegmentCountMax + 3) * mImagePropertiesPrivateData.ImageRecordCount;
+
+ OldMemoryMapSize = *MemoryMapSize;
+ Status = CoreGetMemoryMap (MemoryMapSize, MemoryMap, MapKey, DescriptorSize, DescriptorVersion);
+ if (Status == EFI_BUFFER_TOO_SMALL) {
+ *MemoryMapSize = *MemoryMapSize + (*DescriptorSize) * AdditionalRecordCount;
+ } else if (Status == EFI_SUCCESS) {
+ ASSERT (MemoryMap != NULL);
+ if (OldMemoryMapSize - *MemoryMapSize < (*DescriptorSize) * AdditionalRecordCount) {
+ *MemoryMapSize = *MemoryMapSize + (*DescriptorSize) * AdditionalRecordCount;
+ //
+ // Need update status to buffer too small
+ //
+ Status = EFI_BUFFER_TOO_SMALL;
+ } else {
+ //
+ // Split PE code/data
+ //
+ SplitTable (MemoryMapSize, MemoryMap, *DescriptorSize, &mImagePropertiesPrivateData.ImageRecordList, AdditionalRecordCount);
+
+ //
+ // Set RuntimeData to XP
+ //
+ EnforceMemoryMapAttribute (MemoryMap, *MemoryMapSize, *DescriptorSize);
+
+ //
+ // Merge same type to save entry size
+ //
+ MergeMemoryMap (MemoryMap, MemoryMapSize, *DescriptorSize);
+ }
+ }
+
+ CoreReleasemMemoryAttributesTableLock ();
+ return Status;
+}
+
+//
+// Below functions are for ImageRecord
+//
+
+/**
+ Insert image record.
+
+ @param RuntimeImage Runtime image information
+**/
+VOID
+InsertImageRecord (
+ IN EFI_RUNTIME_IMAGE_ENTRY *RuntimeImage
+ )
+{
+ EFI_STATUS Status;
+ IMAGE_PROPERTIES_RECORD *ImageRecord;
+ CHAR8 *PdbPointer;
+ UINT32 RequiredAlignment;
+
+ DEBUG ((DEBUG_VERBOSE, "InsertImageRecord - 0x%x\n", RuntimeImage));
+
+ if (mMemoryAttributesTableEndOfDxe) {
+ DEBUG ((DEBUG_INFO, "Do not insert runtime image record after EndOfDxe\n"));
+ return;
+ }
+
+ ImageRecord = AllocatePool (sizeof (*ImageRecord));
+ if (ImageRecord == NULL) {
+ return;
+ }
+
+ InitializeListHead (&ImageRecord->Link);
+ InitializeListHead (&ImageRecord->CodeSegmentList);
+
+ PdbPointer = PeCoffLoaderGetPdbPointer ((VOID *)(UINTN)RuntimeImage->ImageBase);
+ if (PdbPointer != NULL) {
+ DEBUG ((DEBUG_VERBOSE, " Image - %a\n", PdbPointer));
+ }
+
+ RequiredAlignment = RUNTIME_PAGE_ALLOCATION_GRANULARITY;
+ Status = CreateImagePropertiesRecord (
+ RuntimeImage->ImageBase,
+ RuntimeImage->ImageSize,
+ &RequiredAlignment,
+ ImageRecord
+ );
+
+ if (EFI_ERROR (Status)) {
+ if (Status == EFI_ABORTED) {
+ mMemoryAttributesTableEnable = FALSE;
+ }
+
+ Status = EFI_ABORTED;
+ goto Finish;
+ }
+
+ if (ImageRecord->CodeSegmentCount == 0) {
+ mMemoryAttributesTableEnable = FALSE;
+ DEBUG ((DEBUG_ERROR, "!!!!!!!! InsertImageRecord - CodeSegmentCount is 0 !!!!!!!!\n"));
+ if (PdbPointer != NULL) {
+ DEBUG ((DEBUG_ERROR, "!!!!!!!! Image - %a !!!!!!!!\n", PdbPointer));
+ }
+
+ Status = EFI_ABORTED;
+ goto Finish;
+ }
+
+ //
+ // Check overlap all section in ImageBase/Size
+ //
+ if (!IsImageRecordCodeSectionValid (ImageRecord)) {
+ DEBUG ((DEBUG_ERROR, "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;
+}
+
+/**
+ Remove Image record.
+
+ @param RuntimeImage Runtime image information
+**/
+VOID
+RemoveImageRecord (
+ IN EFI_RUNTIME_IMAGE_ENTRY *RuntimeImage
+ )
+{
+ IMAGE_PROPERTIES_RECORD *ImageRecord;
+
+ DEBUG ((DEBUG_VERBOSE, "RemoveImageRecord - 0x%x\n", RuntimeImage));
+ DEBUG ((DEBUG_VERBOSE, "RemoveImageRecord - 0x%016lx - 0x%016lx\n", (EFI_PHYSICAL_ADDRESS)(UINTN)RuntimeImage->ImageBase, RuntimeImage->ImageSize));
+
+ if (mMemoryAttributesTableEndOfDxe) {
+ DEBUG ((DEBUG_INFO, "Do not remove runtime image record after EndOfDxe\n"));
+ return;
+ }
+
+ ImageRecord = FindImageRecord ((EFI_PHYSICAL_ADDRESS)(UINTN)RuntimeImage->ImageBase, RuntimeImage->ImageSize, &mImagePropertiesPrivateData.ImageRecordList);
+ if (ImageRecord == NULL) {
+ DEBUG ((DEBUG_ERROR, "!!!!!!!! ImageRecord not found !!!!!!!!\n"));
+ return;
+ }
+
+ DeleteImagePropertiesRecord (ImageRecord);
+
+ mImagePropertiesPrivateData.ImageRecordCount--;
+}
diff --git a/MdeModulePkg/Core/Dxe/Misc/MemoryProtection.c b/MdeModulePkg/Core/Dxe/Misc/MemoryProtection.c
index 2c069cc12c..9cfd107730 100644
--- a/MdeModulePkg/Core/Dxe/Misc/MemoryProtection.c
+++ b/MdeModulePkg/Core/Dxe/Misc/MemoryProtection.c
@@ -1,1110 +1,1110 @@
-/** @file
- UEFI Memory Protection support.
-
- If the UEFI image is page aligned, the image code section is set to read only
- and the image data section is set to non-executable.
-
- 1) This policy is applied for all UEFI image including boot service driver,
- runtime driver or application.
- 2) This policy is applied only if the UEFI image meets the page alignment
- requirement.
- 3) This policy is applied only if the Source UEFI image matches the
- PcdImageProtectionPolicy definition.
- 4) This policy is not applied to the non-PE image region.
-
- The DxeCore calls CpuArchProtocol->SetMemoryAttributes() to protect
- the image. If the CpuArch protocol is not installed yet, the DxeCore
- enqueues the protection request. Once the CpuArch is installed, the
- DxeCore dequeues the protection request and applies policy.
-
- Once the image is unloaded, the protection is removed automatically.
-
-Copyright (c) 2017 - 2018, Intel Corporation. All rights reserved.<BR>
-SPDX-License-Identifier: BSD-2-Clause-Patent
-
-**/
-
-#include <PiDxe.h>
-#include <Library/BaseLib.h>
-#include <Library/BaseMemoryLib.h>
-#include <Library/MemoryAllocationLib.h>
-#include <Library/UefiBootServicesTableLib.h>
-#include <Library/DxeServicesTableLib.h>
-#include <Library/DebugLib.h>
-#include <Library/UefiLib.h>
-#include <Library/ImagePropertiesRecordLib.h>
-
-#include <Guid/EventGroup.h>
-#include <Guid/MemoryAttributesTable.h>
-
-#include <Protocol/FirmwareVolume2.h>
-#include <Protocol/SimpleFileSystem.h>
-
-#include "DxeMain.h"
-#include "Mem/HeapGuard.h"
-
-//
-// Image type definitions
-//
-#define IMAGE_UNKNOWN 0x00000001
-#define IMAGE_FROM_FV 0x00000002
-
-//
-// Protection policy bit definition
-//
-#define DO_NOT_PROTECT 0x00000000
-#define PROTECT_IF_ALIGNED_ELSE_ALLOW 0x00000001
-
-#define MEMORY_TYPE_OS_RESERVED_MIN 0x80000000
-#define MEMORY_TYPE_OEM_RESERVED_MIN 0x70000000
-
-#define PREVIOUS_MEMORY_DESCRIPTOR(MemoryDescriptor, Size) \
- ((EFI_MEMORY_DESCRIPTOR *)((UINT8 *)(MemoryDescriptor) - (Size)))
-
-UINT32 mImageProtectionPolicy;
-
-extern LIST_ENTRY mGcdMemorySpaceMap;
-
-STATIC LIST_ENTRY mProtectedImageRecordList;
-
-/**
- Get the image type.
-
- @param[in] File This is a pointer to the device path of the file that is
- being dispatched.
-
- @return UINT32 Image Type
-**/
-UINT32
-GetImageType (
- IN CONST EFI_DEVICE_PATH_PROTOCOL *File
- )
-{
- EFI_STATUS Status;
- EFI_HANDLE DeviceHandle;
- EFI_DEVICE_PATH_PROTOCOL *TempDevicePath;
-
- if (File == NULL) {
- return IMAGE_UNKNOWN;
- }
-
- //
- // First check to see if File is from a Firmware Volume
- //
- DeviceHandle = NULL;
- TempDevicePath = (EFI_DEVICE_PATH_PROTOCOL *)File;
- Status = gBS->LocateDevicePath (
- &gEfiFirmwareVolume2ProtocolGuid,
- &TempDevicePath,
- &DeviceHandle
- );
- if (!EFI_ERROR (Status)) {
- Status = gBS->OpenProtocol (
- DeviceHandle,
- &gEfiFirmwareVolume2ProtocolGuid,
- NULL,
- NULL,
- NULL,
- EFI_OPEN_PROTOCOL_TEST_PROTOCOL
- );
- if (!EFI_ERROR (Status)) {
- return IMAGE_FROM_FV;
- }
- }
-
- return IMAGE_UNKNOWN;
-}
-
-/**
- Get UEFI image protection policy based upon image type.
-
- @param[in] ImageType The UEFI image type
-
- @return UEFI image protection policy
-**/
-UINT32
-GetProtectionPolicyFromImageType (
- IN UINT32 ImageType
- )
-{
- if ((ImageType & mImageProtectionPolicy) == 0) {
- return DO_NOT_PROTECT;
- } else {
- return PROTECT_IF_ALIGNED_ELSE_ALLOW;
- }
-}
-
-/**
- Get UEFI image protection policy based upon loaded image device path.
-
- @param[in] LoadedImage The loaded image protocol
- @param[in] LoadedImageDevicePath The loaded image device path protocol
-
- @return UEFI image protection policy
-**/
-UINT32
-GetUefiImageProtectionPolicy (
- IN EFI_LOADED_IMAGE_PROTOCOL *LoadedImage,
- IN EFI_DEVICE_PATH_PROTOCOL *LoadedImageDevicePath
- )
-{
- BOOLEAN InSmm;
- UINT32 ImageType;
- UINT32 ProtectionPolicy;
-
- //
- // Check SMM
- //
- InSmm = FALSE;
- if (gSmmBase2 != NULL) {
- gSmmBase2->InSmm (gSmmBase2, &InSmm);
- }
-
- if (InSmm) {
- return FALSE;
- }
-
- //
- // Check DevicePath
- //
- if (LoadedImage == gDxeCoreLoadedImage) {
- ImageType = IMAGE_FROM_FV;
- } else {
- ImageType = GetImageType (LoadedImageDevicePath);
- }
-
- ProtectionPolicy = GetProtectionPolicyFromImageType (ImageType);
- return ProtectionPolicy;
-}
-
-/**
- Set UEFI image memory attributes.
-
- @param[in] BaseAddress Specified start address
- @param[in] Length Specified length
- @param[in] Attributes Specified attributes
-**/
-VOID
-SetUefiImageMemoryAttributes (
- IN UINT64 BaseAddress,
- IN UINT64 Length,
- IN UINT64 Attributes
- )
-{
- EFI_STATUS Status;
- EFI_GCD_MEMORY_SPACE_DESCRIPTOR Descriptor;
- UINT64 FinalAttributes;
-
- Status = CoreGetMemorySpaceDescriptor (BaseAddress, &Descriptor);
- ASSERT_EFI_ERROR (Status);
-
- FinalAttributes = (Descriptor.Attributes & EFI_CACHE_ATTRIBUTE_MASK) | (Attributes & EFI_MEMORY_ATTRIBUTE_MASK);
-
- DEBUG ((DEBUG_INFO, "SetUefiImageMemoryAttributes - 0x%016lx - 0x%016lx (0x%016lx)\n", BaseAddress, Length, FinalAttributes));
-
- ASSERT (gCpu != NULL);
- gCpu->SetMemoryAttributes (gCpu, BaseAddress, Length, FinalAttributes);
-}
-
-/**
- Set UEFI image protection attributes.
-
- @param[in] ImageRecord A UEFI image record
-**/
-VOID
-SetUefiImageProtectionAttributes (
- IN IMAGE_PROPERTIES_RECORD *ImageRecord
- )
-{
- IMAGE_PROPERTIES_RECORD_CODE_SECTION *ImageRecordCodeSection;
- LIST_ENTRY *ImageRecordCodeSectionLink;
- LIST_ENTRY *ImageRecordCodeSectionEndLink;
- LIST_ENTRY *ImageRecordCodeSectionList;
- UINT64 CurrentBase;
- UINT64 ImageEnd;
-
- ImageRecordCodeSectionList = &ImageRecord->CodeSegmentList;
-
- CurrentBase = ImageRecord->ImageBase;
- ImageEnd = ImageRecord->ImageBase + ImageRecord->ImageSize;
-
- ImageRecordCodeSectionLink = ImageRecordCodeSectionList->ForwardLink;
- ImageRecordCodeSectionEndLink = ImageRecordCodeSectionList;
- while (ImageRecordCodeSectionLink != ImageRecordCodeSectionEndLink) {
- ImageRecordCodeSection = CR (
- ImageRecordCodeSectionLink,
- IMAGE_PROPERTIES_RECORD_CODE_SECTION,
- Link,
- IMAGE_PROPERTIES_RECORD_CODE_SECTION_SIGNATURE
- );
- ImageRecordCodeSectionLink = ImageRecordCodeSectionLink->ForwardLink;
-
- ASSERT (CurrentBase <= ImageRecordCodeSection->CodeSegmentBase);
- if (CurrentBase < ImageRecordCodeSection->CodeSegmentBase) {
- //
- // DATA
- //
- SetUefiImageMemoryAttributes (
- CurrentBase,
- ImageRecordCodeSection->CodeSegmentBase - CurrentBase,
- EFI_MEMORY_XP
- );
- }
-
- //
- // CODE
- //
- SetUefiImageMemoryAttributes (
- ImageRecordCodeSection->CodeSegmentBase,
- ImageRecordCodeSection->CodeSegmentSize,
- EFI_MEMORY_RO
- );
- CurrentBase = ImageRecordCodeSection->CodeSegmentBase + ImageRecordCodeSection->CodeSegmentSize;
- }
-
- //
- // Last DATA
- //
- ASSERT (CurrentBase <= ImageEnd);
- if (CurrentBase < ImageEnd) {
- //
- // DATA
- //
- SetUefiImageMemoryAttributes (
- CurrentBase,
- ImageEnd - CurrentBase,
- EFI_MEMORY_XP
- );
- }
-
- return;
-}
-
-/**
- Return the section alignment requirement for the PE image section type.
-
- @param[in] MemoryType PE/COFF image memory type
-
- @retval The required section alignment for this memory type
-
-**/
-STATIC
-UINT32
-GetMemoryProtectionSectionAlignment (
- IN EFI_MEMORY_TYPE MemoryType
- )
-{
- UINT32 SectionAlignment;
-
- switch (MemoryType) {
- case EfiRuntimeServicesCode:
- case EfiACPIMemoryNVS:
- case EfiReservedMemoryType:
- SectionAlignment = RUNTIME_PAGE_ALLOCATION_GRANULARITY;
- break;
- case EfiRuntimeServicesData:
- ASSERT (FALSE);
- SectionAlignment = RUNTIME_PAGE_ALLOCATION_GRANULARITY;
- break;
- case EfiBootServicesCode:
- case EfiLoaderCode:
- SectionAlignment = EFI_PAGE_SIZE;
- break;
- case EfiACPIReclaimMemory:
- default:
- ASSERT (FALSE);
- SectionAlignment = EFI_PAGE_SIZE;
- break;
- }
-
- return SectionAlignment;
-}
-
-/**
- Protect UEFI PE/COFF image.
-
- @param[in] LoadedImage The loaded image protocol
- @param[in] LoadedImageDevicePath The loaded image device path protocol
-**/
-VOID
-ProtectUefiImage (
- IN EFI_LOADED_IMAGE_PROTOCOL *LoadedImage,
- IN EFI_DEVICE_PATH_PROTOCOL *LoadedImageDevicePath
- )
-{
- IMAGE_PROPERTIES_RECORD *ImageRecord;
- UINT32 ProtectionPolicy;
- EFI_STATUS Status;
- UINT32 RequiredAlignment;
-
- DEBUG ((DEBUG_INFO, "ProtectUefiImageCommon - 0x%x\n", LoadedImage));
- DEBUG ((DEBUG_INFO, " - 0x%016lx - 0x%016lx\n", (EFI_PHYSICAL_ADDRESS)(UINTN)LoadedImage->ImageBase, LoadedImage->ImageSize));
-
- if (gCpu == NULL) {
- return;
- }
-
- ProtectionPolicy = GetUefiImageProtectionPolicy (LoadedImage, LoadedImageDevicePath);
- switch (ProtectionPolicy) {
- case DO_NOT_PROTECT:
- return;
- case PROTECT_IF_ALIGNED_ELSE_ALLOW:
- break;
- default:
- ASSERT (FALSE);
- return;
- }
-
- ImageRecord = AllocateZeroPool (sizeof (*ImageRecord));
- if (ImageRecord == NULL) {
- return;
- }
-
- RequiredAlignment = GetMemoryProtectionSectionAlignment (LoadedImage->ImageCodeType);
-
- Status = CreateImagePropertiesRecord (
- LoadedImage->ImageBase,
- LoadedImage->ImageSize,
- &RequiredAlignment,
- ImageRecord
- );
-
- if (EFI_ERROR (Status)) {
- DEBUG ((DEBUG_ERROR, "%a failed to create image properties record\n", __func__));
- FreePool (ImageRecord);
- goto Finish;
- }
-
- //
- // CPU ARCH present. Update memory attribute directly.
- //
- SetUefiImageProtectionAttributes (ImageRecord);
-
- //
- // Record the image record in the list so we can undo the protections later
- //
- InsertTailList (&mProtectedImageRecordList, &ImageRecord->Link);
-
-Finish:
- return;
-}
-
-/**
- Unprotect UEFI image.
-
- @param[in] LoadedImage The loaded image protocol
- @param[in] LoadedImageDevicePath The loaded image device path protocol
-**/
-VOID
-UnprotectUefiImage (
- IN EFI_LOADED_IMAGE_PROTOCOL *LoadedImage,
- IN EFI_DEVICE_PATH_PROTOCOL *LoadedImageDevicePath
- )
-{
- IMAGE_PROPERTIES_RECORD *ImageRecord;
- LIST_ENTRY *ImageRecordLink;
-
- if (PcdGet32 (PcdImageProtectionPolicy) != 0) {
- for (ImageRecordLink = mProtectedImageRecordList.ForwardLink;
- ImageRecordLink != &mProtectedImageRecordList;
- ImageRecordLink = ImageRecordLink->ForwardLink)
- {
- ImageRecord = CR (
- ImageRecordLink,
- IMAGE_PROPERTIES_RECORD,
- Link,
- IMAGE_PROPERTIES_RECORD_SIGNATURE
- );
-
- if (ImageRecord->ImageBase == (EFI_PHYSICAL_ADDRESS)(UINTN)LoadedImage->ImageBase) {
- SetUefiImageMemoryAttributes (
- ImageRecord->ImageBase,
- ImageRecord->ImageSize,
- 0
- );
- DeleteImagePropertiesRecord (ImageRecord);
- return;
- }
- }
- }
-}
-
-/**
- Return the EFI memory permission attribute associated with memory
- type 'MemoryType' under the configured DXE memory protection policy.
-
- @param MemoryType Memory type.
-**/
-STATIC
-UINT64
-GetPermissionAttributeForMemoryType (
- IN EFI_MEMORY_TYPE MemoryType
- )
-{
- UINT64 TestBit;
-
- if ((UINT32)MemoryType >= MEMORY_TYPE_OS_RESERVED_MIN) {
- TestBit = BIT63;
- } else if ((UINT32)MemoryType >= MEMORY_TYPE_OEM_RESERVED_MIN) {
- TestBit = BIT62;
- } else {
- TestBit = LShiftU64 (1, MemoryType);
- }
-
- if ((PcdGet64 (PcdDxeNxMemoryProtectionPolicy) & TestBit) != 0) {
- return EFI_MEMORY_XP;
- } else {
- return 0;
- }
-}
-
-/**
- Sort memory map entries based upon PhysicalStart, from low to high.
-
- @param MemoryMap A pointer to the buffer in which firmware places
- the current memory map.
- @param MemoryMapSize Size, in bytes, of the MemoryMap buffer.
- @param DescriptorSize Size, in bytes, of an individual EFI_MEMORY_DESCRIPTOR.
-**/
-STATIC
-VOID
-SortMemoryMap (
- IN OUT EFI_MEMORY_DESCRIPTOR *MemoryMap,
- IN UINTN MemoryMapSize,
- IN UINTN DescriptorSize
- )
-{
- EFI_MEMORY_DESCRIPTOR *MemoryMapEntry;
- EFI_MEMORY_DESCRIPTOR *NextMemoryMapEntry;
- EFI_MEMORY_DESCRIPTOR *MemoryMapEnd;
- EFI_MEMORY_DESCRIPTOR TempMemoryMap;
-
- MemoryMapEntry = MemoryMap;
- NextMemoryMapEntry = NEXT_MEMORY_DESCRIPTOR (MemoryMapEntry, DescriptorSize);
- MemoryMapEnd = (EFI_MEMORY_DESCRIPTOR *)((UINT8 *)MemoryMap + MemoryMapSize);
- while (MemoryMapEntry < MemoryMapEnd) {
- while (NextMemoryMapEntry < MemoryMapEnd) {
- if (MemoryMapEntry->PhysicalStart > NextMemoryMapEntry->PhysicalStart) {
- CopyMem (&TempMemoryMap, MemoryMapEntry, sizeof (EFI_MEMORY_DESCRIPTOR));
- CopyMem (MemoryMapEntry, NextMemoryMapEntry, sizeof (EFI_MEMORY_DESCRIPTOR));
- CopyMem (NextMemoryMapEntry, &TempMemoryMap, sizeof (EFI_MEMORY_DESCRIPTOR));
- }
-
- NextMemoryMapEntry = NEXT_MEMORY_DESCRIPTOR (NextMemoryMapEntry, DescriptorSize);
- }
-
- MemoryMapEntry = NEXT_MEMORY_DESCRIPTOR (MemoryMapEntry, DescriptorSize);
- NextMemoryMapEntry = NEXT_MEMORY_DESCRIPTOR (MemoryMapEntry, DescriptorSize);
- }
-}
-
-/**
- Merge adjacent memory map entries if they use the same memory protection policy
-
- @param[in, out] MemoryMap A pointer to the buffer in which firmware places
- the current memory map.
- @param[in, out] MemoryMapSize A pointer to the size, in bytes, of the
- MemoryMap buffer. On input, this is the size of
- the current memory map. On output,
- it is the size of new memory map after merge.
- @param[in] DescriptorSize Size, in bytes, of an individual EFI_MEMORY_DESCRIPTOR.
-**/
-STATIC
-VOID
-MergeMemoryMapForProtectionPolicy (
- IN OUT EFI_MEMORY_DESCRIPTOR *MemoryMap,
- IN OUT UINTN *MemoryMapSize,
- IN UINTN DescriptorSize
- )
-{
- EFI_MEMORY_DESCRIPTOR *MemoryMapEntry;
- EFI_MEMORY_DESCRIPTOR *MemoryMapEnd;
- UINT64 MemoryBlockLength;
- EFI_MEMORY_DESCRIPTOR *NewMemoryMapEntry;
- EFI_MEMORY_DESCRIPTOR *NextMemoryMapEntry;
- UINT64 Attributes;
-
- SortMemoryMap (MemoryMap, *MemoryMapSize, DescriptorSize);
-
- MemoryMapEntry = MemoryMap;
- NewMemoryMapEntry = MemoryMap;
- MemoryMapEnd = (EFI_MEMORY_DESCRIPTOR *)((UINT8 *)MemoryMap + *MemoryMapSize);
- while ((UINTN)MemoryMapEntry < (UINTN)MemoryMapEnd) {
- CopyMem (NewMemoryMapEntry, MemoryMapEntry, sizeof (EFI_MEMORY_DESCRIPTOR));
- NextMemoryMapEntry = NEXT_MEMORY_DESCRIPTOR (MemoryMapEntry, DescriptorSize);
-
- do {
- MemoryBlockLength = (UINT64)(EFI_PAGES_TO_SIZE ((UINTN)MemoryMapEntry->NumberOfPages));
- Attributes = GetPermissionAttributeForMemoryType (MemoryMapEntry->Type);
-
- if (((UINTN)NextMemoryMapEntry < (UINTN)MemoryMapEnd) &&
- (Attributes == GetPermissionAttributeForMemoryType (NextMemoryMapEntry->Type)) &&
- ((MemoryMapEntry->PhysicalStart + MemoryBlockLength) == NextMemoryMapEntry->PhysicalStart))
- {
- MemoryMapEntry->NumberOfPages += NextMemoryMapEntry->NumberOfPages;
- if (NewMemoryMapEntry != MemoryMapEntry) {
- NewMemoryMapEntry->NumberOfPages += NextMemoryMapEntry->NumberOfPages;
- }
-
- NextMemoryMapEntry = NEXT_MEMORY_DESCRIPTOR (NextMemoryMapEntry, DescriptorSize);
- continue;
- } else {
- MemoryMapEntry = PREVIOUS_MEMORY_DESCRIPTOR (NextMemoryMapEntry, DescriptorSize);
- break;
- }
- } while (TRUE);
-
- MemoryMapEntry = NEXT_MEMORY_DESCRIPTOR (MemoryMapEntry, DescriptorSize);
- NewMemoryMapEntry = NEXT_MEMORY_DESCRIPTOR (NewMemoryMapEntry, DescriptorSize);
- }
-
- *MemoryMapSize = (UINTN)NewMemoryMapEntry - (UINTN)MemoryMap;
-
- return;
-}
-
-/**
- Remove exec permissions from all regions whose type is identified by
- PcdDxeNxMemoryProtectionPolicy.
-**/
-STATIC
-VOID
-InitializeDxeNxMemoryProtectionPolicy (
- VOID
- )
-{
- UINTN MemoryMapSize;
- UINTN MapKey;
- UINTN DescriptorSize;
- UINT32 DescriptorVersion;
- EFI_MEMORY_DESCRIPTOR *MemoryMap;
- EFI_MEMORY_DESCRIPTOR *MemoryMapEntry;
- EFI_MEMORY_DESCRIPTOR *MemoryMapEnd;
- EFI_STATUS Status;
- UINT64 Attributes;
- LIST_ENTRY *Link;
- EFI_GCD_MAP_ENTRY *Entry;
- EFI_PEI_HOB_POINTERS Hob;
- EFI_HOB_MEMORY_ALLOCATION *MemoryHob;
- EFI_PHYSICAL_ADDRESS StackBase;
-
- //
- // Get the EFI memory map.
- //
- MemoryMapSize = 0;
- MemoryMap = NULL;
-
- Status = gBS->GetMemoryMap (
- &MemoryMapSize,
- MemoryMap,
- &MapKey,
- &DescriptorSize,
- &DescriptorVersion
- );
- ASSERT (Status == EFI_BUFFER_TOO_SMALL);
- do {
- MemoryMap = (EFI_MEMORY_DESCRIPTOR *)AllocatePool (MemoryMapSize);
- ASSERT (MemoryMap != NULL);
- Status = gBS->GetMemoryMap (
- &MemoryMapSize,
- MemoryMap,
- &MapKey,
- &DescriptorSize,
- &DescriptorVersion
- );
- if (EFI_ERROR (Status)) {
- FreePool (MemoryMap);
- }
- } while (Status == EFI_BUFFER_TOO_SMALL);
-
- ASSERT_EFI_ERROR (Status);
-
- StackBase = 0;
- if (PcdGetBool (PcdCpuStackGuard)) {
- //
- // Get the base of stack from Hob.
- //
- Hob.Raw = GetHobList ();
- while ((Hob.Raw = GetNextHob (EFI_HOB_TYPE_MEMORY_ALLOCATION, Hob.Raw)) != NULL) {
- MemoryHob = Hob.MemoryAllocation;
- if (CompareGuid (&gEfiHobMemoryAllocStackGuid, &MemoryHob->AllocDescriptor.Name)) {
- DEBUG ((
- DEBUG_INFO,
- "%a: StackBase = 0x%016lx StackSize = 0x%016lx\n",
- __func__,
- MemoryHob->AllocDescriptor.MemoryBaseAddress,
- MemoryHob->AllocDescriptor.MemoryLength
- ));
-
- StackBase = MemoryHob->AllocDescriptor.MemoryBaseAddress;
- //
- // Ensure the base of the stack is page-size aligned.
- //
- ASSERT ((StackBase & EFI_PAGE_MASK) == 0);
- break;
- }
-
- Hob.Raw = GET_NEXT_HOB (Hob);
- }
-
- //
- // Ensure the base of stack can be found from Hob when stack guard is
- // enabled.
- //
- ASSERT (StackBase != 0);
- }
-
- DEBUG ((
- DEBUG_INFO,
- "%a: applying strict permissions to active memory regions\n",
- __func__
- ));
-
- MergeMemoryMapForProtectionPolicy (MemoryMap, &MemoryMapSize, DescriptorSize);
-
- MemoryMapEntry = MemoryMap;
- MemoryMapEnd = (EFI_MEMORY_DESCRIPTOR *)((UINT8 *)MemoryMap + MemoryMapSize);
- while ((UINTN)MemoryMapEntry < (UINTN)MemoryMapEnd) {
- Attributes = GetPermissionAttributeForMemoryType (MemoryMapEntry->Type);
- if (Attributes != 0) {
- SetUefiImageMemoryAttributes (
- MemoryMapEntry->PhysicalStart,
- LShiftU64 (MemoryMapEntry->NumberOfPages, EFI_PAGE_SHIFT),
- Attributes
- );
-
- //
- // Add EFI_MEMORY_RP attribute for page 0 if NULL pointer detection is
- // enabled.
- //
- if ((MemoryMapEntry->PhysicalStart == 0) &&
- (PcdGet8 (PcdNullPointerDetectionPropertyMask) != 0))
- {
- ASSERT (MemoryMapEntry->NumberOfPages > 0);
- SetUefiImageMemoryAttributes (
- 0,
- EFI_PAGES_TO_SIZE (1),
- EFI_MEMORY_RP | Attributes
- );
- }
-
- //
- // Add EFI_MEMORY_RP attribute for the first page of the stack if stack
- // guard is enabled.
- //
- if ((StackBase != 0) &&
- ((StackBase >= MemoryMapEntry->PhysicalStart) &&
- (StackBase < MemoryMapEntry->PhysicalStart +
- LShiftU64 (MemoryMapEntry->NumberOfPages, EFI_PAGE_SHIFT))) &&
- PcdGetBool (PcdCpuStackGuard))
- {
- SetUefiImageMemoryAttributes (
- StackBase,
- EFI_PAGES_TO_SIZE (1),
- EFI_MEMORY_RP | Attributes
- );
- }
- }
-
- MemoryMapEntry = NEXT_MEMORY_DESCRIPTOR (MemoryMapEntry, DescriptorSize);
- }
-
- FreePool (MemoryMap);
-
- //
- // Apply the policy for RAM regions that we know are present and
- // accessible, but have not been added to the UEFI memory map (yet).
- //
- if (GetPermissionAttributeForMemoryType (EfiConventionalMemory) != 0) {
- DEBUG ((
- DEBUG_INFO,
- "%a: applying strict permissions to inactive memory regions\n",
- __func__
- ));
-
- CoreAcquireGcdMemoryLock ();
-
- Link = mGcdMemorySpaceMap.ForwardLink;
- while (Link != &mGcdMemorySpaceMap) {
- Entry = CR (Link, EFI_GCD_MAP_ENTRY, Link, EFI_GCD_MAP_SIGNATURE);
-
- if ((Entry->GcdMemoryType == EfiGcdMemoryTypeReserved) &&
- (Entry->EndAddress < MAX_ADDRESS) &&
- ((Entry->Capabilities & (EFI_MEMORY_PRESENT | EFI_MEMORY_INITIALIZED | EFI_MEMORY_TESTED)) ==
- (EFI_MEMORY_PRESENT | EFI_MEMORY_INITIALIZED)))
- {
- Attributes = GetPermissionAttributeForMemoryType (EfiConventionalMemory) |
- (Entry->Attributes & EFI_CACHE_ATTRIBUTE_MASK);
-
- DEBUG ((
- DEBUG_INFO,
- "Untested GCD memory space region: - 0x%016lx - 0x%016lx (0x%016lx)\n",
- Entry->BaseAddress,
- Entry->EndAddress - Entry->BaseAddress + 1,
- Attributes
- ));
-
- ASSERT (gCpu != NULL);
- gCpu->SetMemoryAttributes (
- gCpu,
- Entry->BaseAddress,
- Entry->EndAddress - Entry->BaseAddress + 1,
- Attributes
- );
- }
-
- Link = Link->ForwardLink;
- }
-
- CoreReleaseGcdMemoryLock ();
- }
-}
-
-/**
- A notification for CPU_ARCH protocol.
-
- @param[in] Event Event whose notification function is being invoked.
- @param[in] Context Pointer to the notification function's context,
- which is implementation-dependent.
-
-**/
-VOID
-EFIAPI
-MemoryProtectionCpuArchProtocolNotify (
- IN EFI_EVENT Event,
- IN VOID *Context
- )
-{
- EFI_STATUS Status;
- EFI_LOADED_IMAGE_PROTOCOL *LoadedImage;
- EFI_DEVICE_PATH_PROTOCOL *LoadedImageDevicePath;
- UINTN NoHandles;
- EFI_HANDLE *HandleBuffer;
- UINTN Index;
-
- DEBUG ((DEBUG_INFO, "MemoryProtectionCpuArchProtocolNotify:\n"));
- Status = CoreLocateProtocol (&gEfiCpuArchProtocolGuid, NULL, (VOID **)&gCpu);
- if (EFI_ERROR (Status)) {
- goto Done;
- }
-
- //
- // Apply the memory protection policy on non-BScode/RTcode regions.
- //
- if (PcdGet64 (PcdDxeNxMemoryProtectionPolicy) != 0) {
- InitializeDxeNxMemoryProtectionPolicy ();
- }
-
- //
- // Call notify function meant for Heap Guard.
- //
- HeapGuardCpuArchProtocolNotify ();
-
- if (mImageProtectionPolicy == 0) {
- goto Done;
- }
-
- Status = gBS->LocateHandleBuffer (
- ByProtocol,
- &gEfiLoadedImageProtocolGuid,
- NULL,
- &NoHandles,
- &HandleBuffer
- );
- if (EFI_ERROR (Status) && (NoHandles == 0)) {
- goto Done;
- }
-
- for (Index = 0; Index < NoHandles; Index++) {
- Status = gBS->HandleProtocol (
- HandleBuffer[Index],
- &gEfiLoadedImageProtocolGuid,
- (VOID **)&LoadedImage
- );
- if (EFI_ERROR (Status)) {
- continue;
- }
-
- Status = gBS->HandleProtocol (
- HandleBuffer[Index],
- &gEfiLoadedImageDevicePathProtocolGuid,
- (VOID **)&LoadedImageDevicePath
- );
- if (EFI_ERROR (Status)) {
- LoadedImageDevicePath = NULL;
- }
-
- ProtectUefiImage (LoadedImage, LoadedImageDevicePath);
- }
-
- FreePool (HandleBuffer);
-
-Done:
- CoreCloseEvent (Event);
-}
-
-/**
- ExitBootServices Callback function for memory protection.
-**/
-VOID
-MemoryProtectionExitBootServicesCallback (
- VOID
- )
-{
- EFI_RUNTIME_IMAGE_ENTRY *RuntimeImage;
- LIST_ENTRY *Link;
-
- //
- // We need remove the RT protection, because RT relocation need write code segment
- // at SetVirtualAddressMap(). We cannot assume OS/Loader has taken over page table at that time.
- //
- // Firmware does not own page tables after ExitBootServices(), so the OS would
- // have to relax protection of RT code pages across SetVirtualAddressMap(), or
- // delay setting protections on RT code pages until after SetVirtualAddressMap().
- // OS may set protection on RT based upon EFI_MEMORY_ATTRIBUTES_TABLE later.
- //
- if (mImageProtectionPolicy != 0) {
- for (Link = gRuntime->ImageHead.ForwardLink; Link != &gRuntime->ImageHead; Link = Link->ForwardLink) {
- RuntimeImage = BASE_CR (Link, EFI_RUNTIME_IMAGE_ENTRY, Link);
- SetUefiImageMemoryAttributes ((UINT64)(UINTN)RuntimeImage->ImageBase, ALIGN_VALUE (RuntimeImage->ImageSize, EFI_PAGE_SIZE), 0);
- }
- }
-}
-
-/**
- Disable NULL pointer detection after EndOfDxe. This is a workaround resort in
- order to skip unfixable NULL pointer access issues detected in OptionROM or
- boot loaders.
-
- @param[in] Event The Event this notify function registered to.
- @param[in] Context Pointer to the context data registered to the Event.
-**/
-VOID
-EFIAPI
-DisableNullDetectionAtTheEndOfDxe (
- EFI_EVENT Event,
- VOID *Context
- )
-{
- EFI_STATUS Status;
- EFI_GCD_MEMORY_SPACE_DESCRIPTOR Desc;
-
- DEBUG ((DEBUG_INFO, "DisableNullDetectionAtTheEndOfDxe(): start\r\n"));
- //
- // Disable NULL pointer detection by enabling first 4K page
- //
- Status = CoreGetMemorySpaceDescriptor (0, &Desc);
- ASSERT_EFI_ERROR (Status);
-
- if ((Desc.Capabilities & EFI_MEMORY_RP) == 0) {
- Status = CoreSetMemorySpaceCapabilities (
- 0,
- EFI_PAGE_SIZE,
- Desc.Capabilities | EFI_MEMORY_RP
- );
- ASSERT_EFI_ERROR (Status);
- }
-
- Status = CoreSetMemorySpaceAttributes (
- 0,
- EFI_PAGE_SIZE,
- Desc.Attributes & ~EFI_MEMORY_RP
- );
- ASSERT_EFI_ERROR (Status);
-
- //
- // Page 0 might have be allocated to avoid misuses. Free it here anyway.
- //
- CoreFreePages (0, 1);
-
- CoreCloseEvent (Event);
- DEBUG ((DEBUG_INFO, "DisableNullDetectionAtTheEndOfDxe(): end\r\n"));
-
- return;
-}
-
-/**
- Initialize Memory Protection support.
-**/
-VOID
-EFIAPI
-CoreInitializeMemoryProtection (
- VOID
- )
-{
- EFI_STATUS Status;
- EFI_EVENT Event;
- EFI_EVENT EndOfDxeEvent;
- VOID *Registration;
-
- mImageProtectionPolicy = PcdGet32 (PcdImageProtectionPolicy);
-
- InitializeListHead (&mProtectedImageRecordList);
-
- //
- // Sanity check the PcdDxeNxMemoryProtectionPolicy setting:
- // - code regions should have no EFI_MEMORY_XP attribute
- // - EfiConventionalMemory and EfiBootServicesData should use the
- // same attribute
- //
- ASSERT ((GetPermissionAttributeForMemoryType (EfiBootServicesCode) & EFI_MEMORY_XP) == 0);
- ASSERT ((GetPermissionAttributeForMemoryType (EfiRuntimeServicesCode) & EFI_MEMORY_XP) == 0);
- ASSERT ((GetPermissionAttributeForMemoryType (EfiLoaderCode) & EFI_MEMORY_XP) == 0);
- ASSERT (
- GetPermissionAttributeForMemoryType (EfiBootServicesData) ==
- GetPermissionAttributeForMemoryType (EfiConventionalMemory)
- );
-
- Status = CoreCreateEvent (
- EVT_NOTIFY_SIGNAL,
- TPL_CALLBACK,
- MemoryProtectionCpuArchProtocolNotify,
- NULL,
- &Event
- );
- ASSERT_EFI_ERROR (Status);
-
- //
- // Register for protocol notifactions on this event
- //
- Status = CoreRegisterProtocolNotify (
- &gEfiCpuArchProtocolGuid,
- Event,
- &Registration
- );
- ASSERT_EFI_ERROR (Status);
-
- //
- // Register a callback to disable NULL pointer detection at EndOfDxe
- //
- if ((PcdGet8 (PcdNullPointerDetectionPropertyMask) & (BIT0|BIT7))
- == (BIT0|BIT7))
- {
- Status = CoreCreateEventEx (
- EVT_NOTIFY_SIGNAL,
- TPL_NOTIFY,
- DisableNullDetectionAtTheEndOfDxe,
- NULL,
- &gEfiEndOfDxeEventGroupGuid,
- &EndOfDxeEvent
- );
- ASSERT_EFI_ERROR (Status);
- }
-
- return;
-}
-
-/**
- Returns whether we are currently executing in SMM mode.
-**/
-STATIC
-BOOLEAN
-IsInSmm (
- VOID
- )
-{
- BOOLEAN InSmm;
-
- InSmm = FALSE;
- if (gSmmBase2 != NULL) {
- gSmmBase2->InSmm (gSmmBase2, &InSmm);
- }
-
- return InSmm;
-}
-
-/**
- Manage memory permission attributes on a memory range, according to the
- configured DXE memory protection policy.
-
- @param OldType The old memory type of the range
- @param NewType The new memory type of the range
- @param Memory The base address of the range
- @param Length The size of the range (in bytes)
-
- @return EFI_SUCCESS If we are executing in SMM mode. No permission attributes
- are updated in this case
- @return EFI_SUCCESS If the the CPU arch protocol is not installed yet
- @return EFI_SUCCESS If no DXE memory protection policy has been configured
- @return EFI_SUCCESS If OldType and NewType use the same permission attributes
- @return other Return value of gCpu->SetMemoryAttributes()
-
-**/
-EFI_STATUS
-EFIAPI
-ApplyMemoryProtectionPolicy (
- IN EFI_MEMORY_TYPE OldType,
- IN EFI_MEMORY_TYPE NewType,
- IN EFI_PHYSICAL_ADDRESS Memory,
- IN UINT64 Length
- )
-{
- UINT64 OldAttributes;
- UINT64 NewAttributes;
-
- //
- // The policy configured in PcdDxeNxMemoryProtectionPolicy
- // does not apply to allocations performed in SMM mode.
- //
- if (IsInSmm ()) {
- return EFI_SUCCESS;
- }
-
- //
- // If the CPU arch protocol is not installed yet, we cannot manage memory
- // permission attributes, and it is the job of the driver that installs this
- // protocol to set the permissions on existing allocations.
- //
- if (gCpu == NULL) {
- return EFI_SUCCESS;
- }
-
- //
- // Check if a DXE memory protection policy has been configured
- //
- if (PcdGet64 (PcdDxeNxMemoryProtectionPolicy) == 0) {
- return EFI_SUCCESS;
- }
-
- //
- // Don't overwrite Guard pages, which should be the first and/or last page,
- // if any.
- //
- if (IsHeapGuardEnabled (GUARD_HEAP_TYPE_PAGE|GUARD_HEAP_TYPE_POOL)) {
- if (IsGuardPage (Memory)) {
- Memory += EFI_PAGE_SIZE;
- Length -= EFI_PAGE_SIZE;
- if (Length == 0) {
- return EFI_SUCCESS;
- }
- }
-
- if (IsGuardPage (Memory + Length - EFI_PAGE_SIZE)) {
- Length -= EFI_PAGE_SIZE;
- if (Length == 0) {
- return EFI_SUCCESS;
- }
- }
- }
-
- //
- // Update the executable permissions according to the DXE memory
- // protection policy, but only if
- // - the policy is different between the old and the new type, or
- // - this is a newly added region (OldType == EfiMaxMemoryType)
- //
- NewAttributes = GetPermissionAttributeForMemoryType (NewType);
-
- if (OldType != EfiMaxMemoryType) {
- OldAttributes = GetPermissionAttributeForMemoryType (OldType);
- if (OldAttributes == NewAttributes) {
- // policy is the same between OldType and NewType
- return EFI_SUCCESS;
- }
- } else if (NewAttributes == 0) {
- // newly added region of a type that does not require protection
- return EFI_SUCCESS;
- }
-
- return gCpu->SetMemoryAttributes (gCpu, Memory, Length, NewAttributes);
-}
+/** @file
+ UEFI Memory Protection support.
+
+ If the UEFI image is page aligned, the image code section is set to read only
+ and the image data section is set to non-executable.
+
+ 1) This policy is applied for all UEFI image including boot service driver,
+ runtime driver or application.
+ 2) This policy is applied only if the UEFI image meets the page alignment
+ requirement.
+ 3) This policy is applied only if the Source UEFI image matches the
+ PcdImageProtectionPolicy definition.
+ 4) This policy is not applied to the non-PE image region.
+
+ The DxeCore calls CpuArchProtocol->SetMemoryAttributes() to protect
+ the image. If the CpuArch protocol is not installed yet, the DxeCore
+ enqueues the protection request. Once the CpuArch is installed, the
+ DxeCore dequeues the protection request and applies policy.
+
+ Once the image is unloaded, the protection is removed automatically.
+
+Copyright (c) 2017 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <PiDxe.h>
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/DxeServicesTableLib.h>
+#include <Library/DebugLib.h>
+#include <Library/UefiLib.h>
+#include <Library/ImagePropertiesRecordLib.h>
+
+#include <Guid/EventGroup.h>
+#include <Guid/MemoryAttributesTable.h>
+
+#include <Protocol/FirmwareVolume2.h>
+#include <Protocol/SimpleFileSystem.h>
+
+#include "DxeMain.h"
+#include "Mem/HeapGuard.h"
+
+//
+// Image type definitions
+//
+#define IMAGE_UNKNOWN 0x00000001
+#define IMAGE_FROM_FV 0x00000002
+
+//
+// Protection policy bit definition
+//
+#define DO_NOT_PROTECT 0x00000000
+#define PROTECT_IF_ALIGNED_ELSE_ALLOW 0x00000001
+
+#define MEMORY_TYPE_OS_RESERVED_MIN 0x80000000
+#define MEMORY_TYPE_OEM_RESERVED_MIN 0x70000000
+
+#define PREVIOUS_MEMORY_DESCRIPTOR(MemoryDescriptor, Size) \
+ ((EFI_MEMORY_DESCRIPTOR *)((UINT8 *)(MemoryDescriptor) - (Size)))
+
+UINT32 mImageProtectionPolicy;
+
+extern LIST_ENTRY mGcdMemorySpaceMap;
+
+STATIC LIST_ENTRY mProtectedImageRecordList;
+
+/**
+ Get the image type.
+
+ @param[in] File This is a pointer to the device path of the file that is
+ being dispatched.
+
+ @return UINT32 Image Type
+**/
+UINT32
+GetImageType (
+ IN CONST EFI_DEVICE_PATH_PROTOCOL *File
+ )
+{
+ EFI_STATUS Status;
+ EFI_HANDLE DeviceHandle;
+ EFI_DEVICE_PATH_PROTOCOL *TempDevicePath;
+
+ if (File == NULL) {
+ return IMAGE_UNKNOWN;
+ }
+
+ //
+ // First check to see if File is from a Firmware Volume
+ //
+ DeviceHandle = NULL;
+ TempDevicePath = (EFI_DEVICE_PATH_PROTOCOL *)File;
+ Status = gBS->LocateDevicePath (
+ &gEfiFirmwareVolume2ProtocolGuid,
+ &TempDevicePath,
+ &DeviceHandle
+ );
+ if (!EFI_ERROR (Status)) {
+ Status = gBS->OpenProtocol (
+ DeviceHandle,
+ &gEfiFirmwareVolume2ProtocolGuid,
+ NULL,
+ NULL,
+ NULL,
+ EFI_OPEN_PROTOCOL_TEST_PROTOCOL
+ );
+ if (!EFI_ERROR (Status)) {
+ return IMAGE_FROM_FV;
+ }
+ }
+
+ return IMAGE_UNKNOWN;
+}
+
+/**
+ Get UEFI image protection policy based upon image type.
+
+ @param[in] ImageType The UEFI image type
+
+ @return UEFI image protection policy
+**/
+UINT32
+GetProtectionPolicyFromImageType (
+ IN UINT32 ImageType
+ )
+{
+ if ((ImageType & mImageProtectionPolicy) == 0) {
+ return DO_NOT_PROTECT;
+ } else {
+ return PROTECT_IF_ALIGNED_ELSE_ALLOW;
+ }
+}
+
+/**
+ Get UEFI image protection policy based upon loaded image device path.
+
+ @param[in] LoadedImage The loaded image protocol
+ @param[in] LoadedImageDevicePath The loaded image device path protocol
+
+ @return UEFI image protection policy
+**/
+UINT32
+GetUefiImageProtectionPolicy (
+ IN EFI_LOADED_IMAGE_PROTOCOL *LoadedImage,
+ IN EFI_DEVICE_PATH_PROTOCOL *LoadedImageDevicePath
+ )
+{
+ BOOLEAN InSmm;
+ UINT32 ImageType;
+ UINT32 ProtectionPolicy;
+
+ //
+ // Check SMM
+ //
+ InSmm = FALSE;
+ if (gSmmBase2 != NULL) {
+ gSmmBase2->InSmm (gSmmBase2, &InSmm);
+ }
+
+ if (InSmm) {
+ return FALSE;
+ }
+
+ //
+ // Check DevicePath
+ //
+ if (LoadedImage == gDxeCoreLoadedImage) {
+ ImageType = IMAGE_FROM_FV;
+ } else {
+ ImageType = GetImageType (LoadedImageDevicePath);
+ }
+
+ ProtectionPolicy = GetProtectionPolicyFromImageType (ImageType);
+ return ProtectionPolicy;
+}
+
+/**
+ Set UEFI image memory attributes.
+
+ @param[in] BaseAddress Specified start address
+ @param[in] Length Specified length
+ @param[in] Attributes Specified attributes
+**/
+VOID
+SetUefiImageMemoryAttributes (
+ IN UINT64 BaseAddress,
+ IN UINT64 Length,
+ IN UINT64 Attributes
+ )
+{
+ EFI_STATUS Status;
+ EFI_GCD_MEMORY_SPACE_DESCRIPTOR Descriptor;
+ UINT64 FinalAttributes;
+
+ Status = CoreGetMemorySpaceDescriptor (BaseAddress, &Descriptor);
+ ASSERT_EFI_ERROR (Status);
+
+ FinalAttributes = (Descriptor.Attributes & EFI_CACHE_ATTRIBUTE_MASK) | (Attributes & EFI_MEMORY_ATTRIBUTE_MASK);
+
+ DEBUG ((DEBUG_INFO, "SetUefiImageMemoryAttributes - 0x%016lx - 0x%016lx (0x%016lx)\n", BaseAddress, Length, FinalAttributes));
+
+ ASSERT (gCpu != NULL);
+ gCpu->SetMemoryAttributes (gCpu, BaseAddress, Length, FinalAttributes);
+}
+
+/**
+ Set UEFI image protection attributes.
+
+ @param[in] ImageRecord A UEFI image record
+**/
+VOID
+SetUefiImageProtectionAttributes (
+ IN IMAGE_PROPERTIES_RECORD *ImageRecord
+ )
+{
+ IMAGE_PROPERTIES_RECORD_CODE_SECTION *ImageRecordCodeSection;
+ LIST_ENTRY *ImageRecordCodeSectionLink;
+ LIST_ENTRY *ImageRecordCodeSectionEndLink;
+ LIST_ENTRY *ImageRecordCodeSectionList;
+ UINT64 CurrentBase;
+ UINT64 ImageEnd;
+
+ ImageRecordCodeSectionList = &ImageRecord->CodeSegmentList;
+
+ CurrentBase = ImageRecord->ImageBase;
+ ImageEnd = ImageRecord->ImageBase + ImageRecord->ImageSize;
+
+ ImageRecordCodeSectionLink = ImageRecordCodeSectionList->ForwardLink;
+ ImageRecordCodeSectionEndLink = ImageRecordCodeSectionList;
+ while (ImageRecordCodeSectionLink != ImageRecordCodeSectionEndLink) {
+ ImageRecordCodeSection = CR (
+ ImageRecordCodeSectionLink,
+ IMAGE_PROPERTIES_RECORD_CODE_SECTION,
+ Link,
+ IMAGE_PROPERTIES_RECORD_CODE_SECTION_SIGNATURE
+ );
+ ImageRecordCodeSectionLink = ImageRecordCodeSectionLink->ForwardLink;
+
+ ASSERT (CurrentBase <= ImageRecordCodeSection->CodeSegmentBase);
+ if (CurrentBase < ImageRecordCodeSection->CodeSegmentBase) {
+ //
+ // DATA
+ //
+ SetUefiImageMemoryAttributes (
+ CurrentBase,
+ ImageRecordCodeSection->CodeSegmentBase - CurrentBase,
+ EFI_MEMORY_XP
+ );
+ }
+
+ //
+ // CODE
+ //
+ SetUefiImageMemoryAttributes (
+ ImageRecordCodeSection->CodeSegmentBase,
+ ImageRecordCodeSection->CodeSegmentSize,
+ EFI_MEMORY_RO
+ );
+ CurrentBase = ImageRecordCodeSection->CodeSegmentBase + ImageRecordCodeSection->CodeSegmentSize;
+ }
+
+ //
+ // Last DATA
+ //
+ ASSERT (CurrentBase <= ImageEnd);
+ if (CurrentBase < ImageEnd) {
+ //
+ // DATA
+ //
+ SetUefiImageMemoryAttributes (
+ CurrentBase,
+ ImageEnd - CurrentBase,
+ EFI_MEMORY_XP
+ );
+ }
+
+ return;
+}
+
+/**
+ Return the section alignment requirement for the PE image section type.
+
+ @param[in] MemoryType PE/COFF image memory type
+
+ @retval The required section alignment for this memory type
+
+**/
+STATIC
+UINT32
+GetMemoryProtectionSectionAlignment (
+ IN EFI_MEMORY_TYPE MemoryType
+ )
+{
+ UINT32 SectionAlignment;
+
+ switch (MemoryType) {
+ case EfiRuntimeServicesCode:
+ case EfiACPIMemoryNVS:
+ case EfiReservedMemoryType:
+ SectionAlignment = RUNTIME_PAGE_ALLOCATION_GRANULARITY;
+ break;
+ case EfiRuntimeServicesData:
+ ASSERT (FALSE);
+ SectionAlignment = RUNTIME_PAGE_ALLOCATION_GRANULARITY;
+ break;
+ case EfiBootServicesCode:
+ case EfiLoaderCode:
+ SectionAlignment = EFI_PAGE_SIZE;
+ break;
+ case EfiACPIReclaimMemory:
+ default:
+ ASSERT (FALSE);
+ SectionAlignment = EFI_PAGE_SIZE;
+ break;
+ }
+
+ return SectionAlignment;
+}
+
+/**
+ Protect UEFI PE/COFF image.
+
+ @param[in] LoadedImage The loaded image protocol
+ @param[in] LoadedImageDevicePath The loaded image device path protocol
+**/
+VOID
+ProtectUefiImage (
+ IN EFI_LOADED_IMAGE_PROTOCOL *LoadedImage,
+ IN EFI_DEVICE_PATH_PROTOCOL *LoadedImageDevicePath
+ )
+{
+ IMAGE_PROPERTIES_RECORD *ImageRecord;
+ UINT32 ProtectionPolicy;
+ EFI_STATUS Status;
+ UINT32 RequiredAlignment;
+
+ DEBUG ((DEBUG_INFO, "ProtectUefiImageCommon - 0x%x\n", LoadedImage));
+ DEBUG ((DEBUG_INFO, " - 0x%016lx - 0x%016lx\n", (EFI_PHYSICAL_ADDRESS)(UINTN)LoadedImage->ImageBase, LoadedImage->ImageSize));
+
+ if (gCpu == NULL) {
+ return;
+ }
+
+ ProtectionPolicy = GetUefiImageProtectionPolicy (LoadedImage, LoadedImageDevicePath);
+ switch (ProtectionPolicy) {
+ case DO_NOT_PROTECT:
+ return;
+ case PROTECT_IF_ALIGNED_ELSE_ALLOW:
+ break;
+ default:
+ ASSERT (FALSE);
+ return;
+ }
+
+ ImageRecord = AllocateZeroPool (sizeof (*ImageRecord));
+ if (ImageRecord == NULL) {
+ return;
+ }
+
+ RequiredAlignment = GetMemoryProtectionSectionAlignment (LoadedImage->ImageCodeType);
+
+ Status = CreateImagePropertiesRecord (
+ LoadedImage->ImageBase,
+ LoadedImage->ImageSize,
+ &RequiredAlignment,
+ ImageRecord
+ );
+
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "%a failed to create image properties record\n", __func__));
+ FreePool (ImageRecord);
+ goto Finish;
+ }
+
+ //
+ // CPU ARCH present. Update memory attribute directly.
+ //
+ SetUefiImageProtectionAttributes (ImageRecord);
+
+ //
+ // Record the image record in the list so we can undo the protections later
+ //
+ InsertTailList (&mProtectedImageRecordList, &ImageRecord->Link);
+
+Finish:
+ return;
+}
+
+/**
+ Unprotect UEFI image.
+
+ @param[in] LoadedImage The loaded image protocol
+ @param[in] LoadedImageDevicePath The loaded image device path protocol
+**/
+VOID
+UnprotectUefiImage (
+ IN EFI_LOADED_IMAGE_PROTOCOL *LoadedImage,
+ IN EFI_DEVICE_PATH_PROTOCOL *LoadedImageDevicePath
+ )
+{
+ IMAGE_PROPERTIES_RECORD *ImageRecord;
+ LIST_ENTRY *ImageRecordLink;
+
+ if (PcdGet32 (PcdImageProtectionPolicy) != 0) {
+ for (ImageRecordLink = mProtectedImageRecordList.ForwardLink;
+ ImageRecordLink != &mProtectedImageRecordList;
+ ImageRecordLink = ImageRecordLink->ForwardLink)
+ {
+ ImageRecord = CR (
+ ImageRecordLink,
+ IMAGE_PROPERTIES_RECORD,
+ Link,
+ IMAGE_PROPERTIES_RECORD_SIGNATURE
+ );
+
+ if (ImageRecord->ImageBase == (EFI_PHYSICAL_ADDRESS)(UINTN)LoadedImage->ImageBase) {
+ SetUefiImageMemoryAttributes (
+ ImageRecord->ImageBase,
+ ImageRecord->ImageSize,
+ 0
+ );
+ DeleteImagePropertiesRecord (ImageRecord);
+ return;
+ }
+ }
+ }
+}
+
+/**
+ Return the EFI memory permission attribute associated with memory
+ type 'MemoryType' under the configured DXE memory protection policy.
+
+ @param MemoryType Memory type.
+**/
+STATIC
+UINT64
+GetPermissionAttributeForMemoryType (
+ IN EFI_MEMORY_TYPE MemoryType
+ )
+{
+ UINT64 TestBit;
+
+ if ((UINT32)MemoryType >= MEMORY_TYPE_OS_RESERVED_MIN) {
+ TestBit = BIT63;
+ } else if ((UINT32)MemoryType >= MEMORY_TYPE_OEM_RESERVED_MIN) {
+ TestBit = BIT62;
+ } else {
+ TestBit = LShiftU64 (1, MemoryType);
+ }
+
+ if ((PcdGet64 (PcdDxeNxMemoryProtectionPolicy) & TestBit) != 0) {
+ return EFI_MEMORY_XP;
+ } else {
+ return 0;
+ }
+}
+
+/**
+ Sort memory map entries based upon PhysicalStart, from low to high.
+
+ @param MemoryMap A pointer to the buffer in which firmware places
+ the current memory map.
+ @param MemoryMapSize Size, in bytes, of the MemoryMap buffer.
+ @param DescriptorSize Size, in bytes, of an individual EFI_MEMORY_DESCRIPTOR.
+**/
+STATIC
+VOID
+SortMemoryMap (
+ IN OUT EFI_MEMORY_DESCRIPTOR *MemoryMap,
+ IN UINTN MemoryMapSize,
+ IN UINTN DescriptorSize
+ )
+{
+ EFI_MEMORY_DESCRIPTOR *MemoryMapEntry;
+ EFI_MEMORY_DESCRIPTOR *NextMemoryMapEntry;
+ EFI_MEMORY_DESCRIPTOR *MemoryMapEnd;
+ EFI_MEMORY_DESCRIPTOR TempMemoryMap;
+
+ MemoryMapEntry = MemoryMap;
+ NextMemoryMapEntry = NEXT_MEMORY_DESCRIPTOR (MemoryMapEntry, DescriptorSize);
+ MemoryMapEnd = (EFI_MEMORY_DESCRIPTOR *)((UINT8 *)MemoryMap + MemoryMapSize);
+ while (MemoryMapEntry < MemoryMapEnd) {
+ while (NextMemoryMapEntry < MemoryMapEnd) {
+ if (MemoryMapEntry->PhysicalStart > NextMemoryMapEntry->PhysicalStart) {
+ CopyMem (&TempMemoryMap, MemoryMapEntry, sizeof (EFI_MEMORY_DESCRIPTOR));
+ CopyMem (MemoryMapEntry, NextMemoryMapEntry, sizeof (EFI_MEMORY_DESCRIPTOR));
+ CopyMem (NextMemoryMapEntry, &TempMemoryMap, sizeof (EFI_MEMORY_DESCRIPTOR));
+ }
+
+ NextMemoryMapEntry = NEXT_MEMORY_DESCRIPTOR (NextMemoryMapEntry, DescriptorSize);
+ }
+
+ MemoryMapEntry = NEXT_MEMORY_DESCRIPTOR (MemoryMapEntry, DescriptorSize);
+ NextMemoryMapEntry = NEXT_MEMORY_DESCRIPTOR (MemoryMapEntry, DescriptorSize);
+ }
+}
+
+/**
+ Merge adjacent memory map entries if they use the same memory protection policy
+
+ @param[in, out] MemoryMap A pointer to the buffer in which firmware places
+ the current memory map.
+ @param[in, out] MemoryMapSize A pointer to the size, in bytes, of the
+ MemoryMap buffer. On input, this is the size of
+ the current memory map. On output,
+ it is the size of new memory map after merge.
+ @param[in] DescriptorSize Size, in bytes, of an individual EFI_MEMORY_DESCRIPTOR.
+**/
+STATIC
+VOID
+MergeMemoryMapForProtectionPolicy (
+ IN OUT EFI_MEMORY_DESCRIPTOR *MemoryMap,
+ IN OUT UINTN *MemoryMapSize,
+ IN UINTN DescriptorSize
+ )
+{
+ EFI_MEMORY_DESCRIPTOR *MemoryMapEntry;
+ EFI_MEMORY_DESCRIPTOR *MemoryMapEnd;
+ UINT64 MemoryBlockLength;
+ EFI_MEMORY_DESCRIPTOR *NewMemoryMapEntry;
+ EFI_MEMORY_DESCRIPTOR *NextMemoryMapEntry;
+ UINT64 Attributes;
+
+ SortMemoryMap (MemoryMap, *MemoryMapSize, DescriptorSize);
+
+ MemoryMapEntry = MemoryMap;
+ NewMemoryMapEntry = MemoryMap;
+ MemoryMapEnd = (EFI_MEMORY_DESCRIPTOR *)((UINT8 *)MemoryMap + *MemoryMapSize);
+ while ((UINTN)MemoryMapEntry < (UINTN)MemoryMapEnd) {
+ CopyMem (NewMemoryMapEntry, MemoryMapEntry, sizeof (EFI_MEMORY_DESCRIPTOR));
+ NextMemoryMapEntry = NEXT_MEMORY_DESCRIPTOR (MemoryMapEntry, DescriptorSize);
+
+ do {
+ MemoryBlockLength = (UINT64)(EFI_PAGES_TO_SIZE ((UINTN)MemoryMapEntry->NumberOfPages));
+ Attributes = GetPermissionAttributeForMemoryType (MemoryMapEntry->Type);
+
+ if (((UINTN)NextMemoryMapEntry < (UINTN)MemoryMapEnd) &&
+ (Attributes == GetPermissionAttributeForMemoryType (NextMemoryMapEntry->Type)) &&
+ ((MemoryMapEntry->PhysicalStart + MemoryBlockLength) == NextMemoryMapEntry->PhysicalStart))
+ {
+ MemoryMapEntry->NumberOfPages += NextMemoryMapEntry->NumberOfPages;
+ if (NewMemoryMapEntry != MemoryMapEntry) {
+ NewMemoryMapEntry->NumberOfPages += NextMemoryMapEntry->NumberOfPages;
+ }
+
+ NextMemoryMapEntry = NEXT_MEMORY_DESCRIPTOR (NextMemoryMapEntry, DescriptorSize);
+ continue;
+ } else {
+ MemoryMapEntry = PREVIOUS_MEMORY_DESCRIPTOR (NextMemoryMapEntry, DescriptorSize);
+ break;
+ }
+ } while (TRUE);
+
+ MemoryMapEntry = NEXT_MEMORY_DESCRIPTOR (MemoryMapEntry, DescriptorSize);
+ NewMemoryMapEntry = NEXT_MEMORY_DESCRIPTOR (NewMemoryMapEntry, DescriptorSize);
+ }
+
+ *MemoryMapSize = (UINTN)NewMemoryMapEntry - (UINTN)MemoryMap;
+
+ return;
+}
+
+/**
+ Remove exec permissions from all regions whose type is identified by
+ PcdDxeNxMemoryProtectionPolicy.
+**/
+STATIC
+VOID
+InitializeDxeNxMemoryProtectionPolicy (
+ VOID
+ )
+{
+ UINTN MemoryMapSize;
+ UINTN MapKey;
+ UINTN DescriptorSize;
+ UINT32 DescriptorVersion;
+ EFI_MEMORY_DESCRIPTOR *MemoryMap;
+ EFI_MEMORY_DESCRIPTOR *MemoryMapEntry;
+ EFI_MEMORY_DESCRIPTOR *MemoryMapEnd;
+ EFI_STATUS Status;
+ UINT64 Attributes;
+ LIST_ENTRY *Link;
+ EFI_GCD_MAP_ENTRY *Entry;
+ EFI_PEI_HOB_POINTERS Hob;
+ EFI_HOB_MEMORY_ALLOCATION *MemoryHob;
+ EFI_PHYSICAL_ADDRESS StackBase;
+
+ //
+ // Get the EFI memory map.
+ //
+ MemoryMapSize = 0;
+ MemoryMap = NULL;
+
+ Status = gBS->GetMemoryMap (
+ &MemoryMapSize,
+ MemoryMap,
+ &MapKey,
+ &DescriptorSize,
+ &DescriptorVersion
+ );
+ ASSERT (Status == EFI_BUFFER_TOO_SMALL);
+ do {
+ MemoryMap = (EFI_MEMORY_DESCRIPTOR *)AllocatePool (MemoryMapSize);
+ ASSERT (MemoryMap != NULL);
+ Status = gBS->GetMemoryMap (
+ &MemoryMapSize,
+ MemoryMap,
+ &MapKey,
+ &DescriptorSize,
+ &DescriptorVersion
+ );
+ if (EFI_ERROR (Status)) {
+ FreePool (MemoryMap);
+ }
+ } while (Status == EFI_BUFFER_TOO_SMALL);
+
+ ASSERT_EFI_ERROR (Status);
+
+ StackBase = 0;
+ if (PcdGetBool (PcdCpuStackGuard)) {
+ //
+ // Get the base of stack from Hob.
+ //
+ Hob.Raw = GetHobList ();
+ while ((Hob.Raw = GetNextHob (EFI_HOB_TYPE_MEMORY_ALLOCATION, Hob.Raw)) != NULL) {
+ MemoryHob = Hob.MemoryAllocation;
+ if (CompareGuid (&gEfiHobMemoryAllocStackGuid, &MemoryHob->AllocDescriptor.Name)) {
+ DEBUG ((
+ DEBUG_INFO,
+ "%a: StackBase = 0x%016lx StackSize = 0x%016lx\n",
+ __func__,
+ MemoryHob->AllocDescriptor.MemoryBaseAddress,
+ MemoryHob->AllocDescriptor.MemoryLength
+ ));
+
+ StackBase = MemoryHob->AllocDescriptor.MemoryBaseAddress;
+ //
+ // Ensure the base of the stack is page-size aligned.
+ //
+ ASSERT ((StackBase & EFI_PAGE_MASK) == 0);
+ break;
+ }
+
+ Hob.Raw = GET_NEXT_HOB (Hob);
+ }
+
+ //
+ // Ensure the base of stack can be found from Hob when stack guard is
+ // enabled.
+ //
+ ASSERT (StackBase != 0);
+ }
+
+ DEBUG ((
+ DEBUG_INFO,
+ "%a: applying strict permissions to active memory regions\n",
+ __func__
+ ));
+
+ MergeMemoryMapForProtectionPolicy (MemoryMap, &MemoryMapSize, DescriptorSize);
+
+ MemoryMapEntry = MemoryMap;
+ MemoryMapEnd = (EFI_MEMORY_DESCRIPTOR *)((UINT8 *)MemoryMap + MemoryMapSize);
+ while ((UINTN)MemoryMapEntry < (UINTN)MemoryMapEnd) {
+ Attributes = GetPermissionAttributeForMemoryType (MemoryMapEntry->Type);
+ if (Attributes != 0) {
+ SetUefiImageMemoryAttributes (
+ MemoryMapEntry->PhysicalStart,
+ LShiftU64 (MemoryMapEntry->NumberOfPages, EFI_PAGE_SHIFT),
+ Attributes
+ );
+
+ //
+ // Add EFI_MEMORY_RP attribute for page 0 if NULL pointer detection is
+ // enabled.
+ //
+ if ((MemoryMapEntry->PhysicalStart == 0) &&
+ (PcdGet8 (PcdNullPointerDetectionPropertyMask) != 0))
+ {
+ ASSERT (MemoryMapEntry->NumberOfPages > 0);
+ SetUefiImageMemoryAttributes (
+ 0,
+ EFI_PAGES_TO_SIZE (1),
+ EFI_MEMORY_RP | Attributes
+ );
+ }
+
+ //
+ // Add EFI_MEMORY_RP attribute for the first page of the stack if stack
+ // guard is enabled.
+ //
+ if ((StackBase != 0) &&
+ ((StackBase >= MemoryMapEntry->PhysicalStart) &&
+ (StackBase < MemoryMapEntry->PhysicalStart +
+ LShiftU64 (MemoryMapEntry->NumberOfPages, EFI_PAGE_SHIFT))) &&
+ PcdGetBool (PcdCpuStackGuard))
+ {
+ SetUefiImageMemoryAttributes (
+ StackBase,
+ EFI_PAGES_TO_SIZE (1),
+ EFI_MEMORY_RP | Attributes
+ );
+ }
+ }
+
+ MemoryMapEntry = NEXT_MEMORY_DESCRIPTOR (MemoryMapEntry, DescriptorSize);
+ }
+
+ FreePool (MemoryMap);
+
+ //
+ // Apply the policy for RAM regions that we know are present and
+ // accessible, but have not been added to the UEFI memory map (yet).
+ //
+ if (GetPermissionAttributeForMemoryType (EfiConventionalMemory) != 0) {
+ DEBUG ((
+ DEBUG_INFO,
+ "%a: applying strict permissions to inactive memory regions\n",
+ __func__
+ ));
+
+ CoreAcquireGcdMemoryLock ();
+
+ Link = mGcdMemorySpaceMap.ForwardLink;
+ while (Link != &mGcdMemorySpaceMap) {
+ Entry = CR (Link, EFI_GCD_MAP_ENTRY, Link, EFI_GCD_MAP_SIGNATURE);
+
+ if ((Entry->GcdMemoryType == EfiGcdMemoryTypeReserved) &&
+ (Entry->EndAddress < MAX_ADDRESS) &&
+ ((Entry->Capabilities & (EFI_MEMORY_PRESENT | EFI_MEMORY_INITIALIZED | EFI_MEMORY_TESTED)) ==
+ (EFI_MEMORY_PRESENT | EFI_MEMORY_INITIALIZED)))
+ {
+ Attributes = GetPermissionAttributeForMemoryType (EfiConventionalMemory) |
+ (Entry->Attributes & EFI_CACHE_ATTRIBUTE_MASK);
+
+ DEBUG ((
+ DEBUG_INFO,
+ "Untested GCD memory space region: - 0x%016lx - 0x%016lx (0x%016lx)\n",
+ Entry->BaseAddress,
+ Entry->EndAddress - Entry->BaseAddress + 1,
+ Attributes
+ ));
+
+ ASSERT (gCpu != NULL);
+ gCpu->SetMemoryAttributes (
+ gCpu,
+ Entry->BaseAddress,
+ Entry->EndAddress - Entry->BaseAddress + 1,
+ Attributes
+ );
+ }
+
+ Link = Link->ForwardLink;
+ }
+
+ CoreReleaseGcdMemoryLock ();
+ }
+}
+
+/**
+ A notification for CPU_ARCH protocol.
+
+ @param[in] Event Event whose notification function is being invoked.
+ @param[in] Context Pointer to the notification function's context,
+ which is implementation-dependent.
+
+**/
+VOID
+EFIAPI
+MemoryProtectionCpuArchProtocolNotify (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ EFI_STATUS Status;
+ EFI_LOADED_IMAGE_PROTOCOL *LoadedImage;
+ EFI_DEVICE_PATH_PROTOCOL *LoadedImageDevicePath;
+ UINTN NoHandles;
+ EFI_HANDLE *HandleBuffer;
+ UINTN Index;
+
+ DEBUG ((DEBUG_INFO, "MemoryProtectionCpuArchProtocolNotify:\n"));
+ Status = CoreLocateProtocol (&gEfiCpuArchProtocolGuid, NULL, (VOID **)&gCpu);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ //
+ // Apply the memory protection policy on non-BScode/RTcode regions.
+ //
+ if (PcdGet64 (PcdDxeNxMemoryProtectionPolicy) != 0) {
+ InitializeDxeNxMemoryProtectionPolicy ();
+ }
+
+ //
+ // Call notify function meant for Heap Guard.
+ //
+ HeapGuardCpuArchProtocolNotify ();
+
+ if (mImageProtectionPolicy == 0) {
+ goto Done;
+ }
+
+ Status = gBS->LocateHandleBuffer (
+ ByProtocol,
+ &gEfiLoadedImageProtocolGuid,
+ NULL,
+ &NoHandles,
+ &HandleBuffer
+ );
+ if (EFI_ERROR (Status) && (NoHandles == 0)) {
+ goto Done;
+ }
+
+ for (Index = 0; Index < NoHandles; Index++) {
+ Status = gBS->HandleProtocol (
+ HandleBuffer[Index],
+ &gEfiLoadedImageProtocolGuid,
+ (VOID **)&LoadedImage
+ );
+ if (EFI_ERROR (Status)) {
+ continue;
+ }
+
+ Status = gBS->HandleProtocol (
+ HandleBuffer[Index],
+ &gEfiLoadedImageDevicePathProtocolGuid,
+ (VOID **)&LoadedImageDevicePath
+ );
+ if (EFI_ERROR (Status)) {
+ LoadedImageDevicePath = NULL;
+ }
+
+ ProtectUefiImage (LoadedImage, LoadedImageDevicePath);
+ }
+
+ FreePool (HandleBuffer);
+
+Done:
+ CoreCloseEvent (Event);
+}
+
+/**
+ ExitBootServices Callback function for memory protection.
+**/
+VOID
+MemoryProtectionExitBootServicesCallback (
+ VOID
+ )
+{
+ EFI_RUNTIME_IMAGE_ENTRY *RuntimeImage;
+ LIST_ENTRY *Link;
+
+ //
+ // We need remove the RT protection, because RT relocation need write code segment
+ // at SetVirtualAddressMap(). We cannot assume OS/Loader has taken over page table at that time.
+ //
+ // Firmware does not own page tables after ExitBootServices(), so the OS would
+ // have to relax protection of RT code pages across SetVirtualAddressMap(), or
+ // delay setting protections on RT code pages until after SetVirtualAddressMap().
+ // OS may set protection on RT based upon EFI_MEMORY_ATTRIBUTES_TABLE later.
+ //
+ if (mImageProtectionPolicy != 0) {
+ for (Link = gRuntime->ImageHead.ForwardLink; Link != &gRuntime->ImageHead; Link = Link->ForwardLink) {
+ RuntimeImage = BASE_CR (Link, EFI_RUNTIME_IMAGE_ENTRY, Link);
+ SetUefiImageMemoryAttributes ((UINT64)(UINTN)RuntimeImage->ImageBase, ALIGN_VALUE (RuntimeImage->ImageSize, EFI_PAGE_SIZE), 0);
+ }
+ }
+}
+
+/**
+ Disable NULL pointer detection after EndOfDxe. This is a workaround resort in
+ order to skip unfixable NULL pointer access issues detected in OptionROM or
+ boot loaders.
+
+ @param[in] Event The Event this notify function registered to.
+ @param[in] Context Pointer to the context data registered to the Event.
+**/
+VOID
+EFIAPI
+DisableNullDetectionAtTheEndOfDxe (
+ EFI_EVENT Event,
+ VOID *Context
+ )
+{
+ EFI_STATUS Status;
+ EFI_GCD_MEMORY_SPACE_DESCRIPTOR Desc;
+
+ DEBUG ((DEBUG_INFO, "DisableNullDetectionAtTheEndOfDxe(): start\r\n"));
+ //
+ // Disable NULL pointer detection by enabling first 4K page
+ //
+ Status = CoreGetMemorySpaceDescriptor (0, &Desc);
+ ASSERT_EFI_ERROR (Status);
+
+ if ((Desc.Capabilities & EFI_MEMORY_RP) == 0) {
+ Status = CoreSetMemorySpaceCapabilities (
+ 0,
+ EFI_PAGE_SIZE,
+ Desc.Capabilities | EFI_MEMORY_RP
+ );
+ ASSERT_EFI_ERROR (Status);
+ }
+
+ Status = CoreSetMemorySpaceAttributes (
+ 0,
+ EFI_PAGE_SIZE,
+ Desc.Attributes & ~EFI_MEMORY_RP
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Page 0 might have be allocated to avoid misuses. Free it here anyway.
+ //
+ CoreFreePages (0, 1);
+
+ CoreCloseEvent (Event);
+ DEBUG ((DEBUG_INFO, "DisableNullDetectionAtTheEndOfDxe(): end\r\n"));
+
+ return;
+}
+
+/**
+ Initialize Memory Protection support.
+**/
+VOID
+EFIAPI
+CoreInitializeMemoryProtection (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ EFI_EVENT Event;
+ EFI_EVENT EndOfDxeEvent;
+ VOID *Registration;
+
+ mImageProtectionPolicy = PcdGet32 (PcdImageProtectionPolicy);
+
+ InitializeListHead (&mProtectedImageRecordList);
+
+ //
+ // Sanity check the PcdDxeNxMemoryProtectionPolicy setting:
+ // - code regions should have no EFI_MEMORY_XP attribute
+ // - EfiConventionalMemory and EfiBootServicesData should use the
+ // same attribute
+ //
+ ASSERT ((GetPermissionAttributeForMemoryType (EfiBootServicesCode) & EFI_MEMORY_XP) == 0);
+ ASSERT ((GetPermissionAttributeForMemoryType (EfiRuntimeServicesCode) & EFI_MEMORY_XP) == 0);
+ ASSERT ((GetPermissionAttributeForMemoryType (EfiLoaderCode) & EFI_MEMORY_XP) == 0);
+ ASSERT (
+ GetPermissionAttributeForMemoryType (EfiBootServicesData) ==
+ GetPermissionAttributeForMemoryType (EfiConventionalMemory)
+ );
+
+ Status = CoreCreateEvent (
+ EVT_NOTIFY_SIGNAL,
+ TPL_CALLBACK,
+ MemoryProtectionCpuArchProtocolNotify,
+ NULL,
+ &Event
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Register for protocol notifactions on this event
+ //
+ Status = CoreRegisterProtocolNotify (
+ &gEfiCpuArchProtocolGuid,
+ Event,
+ &Registration
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Register a callback to disable NULL pointer detection at EndOfDxe
+ //
+ if ((PcdGet8 (PcdNullPointerDetectionPropertyMask) & (BIT0|BIT7))
+ == (BIT0|BIT7))
+ {
+ Status = CoreCreateEventEx (
+ EVT_NOTIFY_SIGNAL,
+ TPL_NOTIFY,
+ DisableNullDetectionAtTheEndOfDxe,
+ NULL,
+ &gEfiEndOfDxeEventGroupGuid,
+ &EndOfDxeEvent
+ );
+ ASSERT_EFI_ERROR (Status);
+ }
+
+ return;
+}
+
+/**
+ Returns whether we are currently executing in SMM mode.
+**/
+STATIC
+BOOLEAN
+IsInSmm (
+ VOID
+ )
+{
+ BOOLEAN InSmm;
+
+ InSmm = FALSE;
+ if (gSmmBase2 != NULL) {
+ gSmmBase2->InSmm (gSmmBase2, &InSmm);
+ }
+
+ return InSmm;
+}
+
+/**
+ Manage memory permission attributes on a memory range, according to the
+ configured DXE memory protection policy.
+
+ @param OldType The old memory type of the range
+ @param NewType The new memory type of the range
+ @param Memory The base address of the range
+ @param Length The size of the range (in bytes)
+
+ @return EFI_SUCCESS If we are executing in SMM mode. No permission attributes
+ are updated in this case
+ @return EFI_SUCCESS If the the CPU arch protocol is not installed yet
+ @return EFI_SUCCESS If no DXE memory protection policy has been configured
+ @return EFI_SUCCESS If OldType and NewType use the same permission attributes
+ @return other Return value of gCpu->SetMemoryAttributes()
+
+**/
+EFI_STATUS
+EFIAPI
+ApplyMemoryProtectionPolicy (
+ IN EFI_MEMORY_TYPE OldType,
+ IN EFI_MEMORY_TYPE NewType,
+ IN EFI_PHYSICAL_ADDRESS Memory,
+ IN UINT64 Length
+ )
+{
+ UINT64 OldAttributes;
+ UINT64 NewAttributes;
+
+ //
+ // The policy configured in PcdDxeNxMemoryProtectionPolicy
+ // does not apply to allocations performed in SMM mode.
+ //
+ if (IsInSmm ()) {
+ return EFI_SUCCESS;
+ }
+
+ //
+ // If the CPU arch protocol is not installed yet, we cannot manage memory
+ // permission attributes, and it is the job of the driver that installs this
+ // protocol to set the permissions on existing allocations.
+ //
+ if (gCpu == NULL) {
+ return EFI_SUCCESS;
+ }
+
+ //
+ // Check if a DXE memory protection policy has been configured
+ //
+ if (PcdGet64 (PcdDxeNxMemoryProtectionPolicy) == 0) {
+ return EFI_SUCCESS;
+ }
+
+ //
+ // Don't overwrite Guard pages, which should be the first and/or last page,
+ // if any.
+ //
+ if (IsHeapGuardEnabled (GUARD_HEAP_TYPE_PAGE|GUARD_HEAP_TYPE_POOL)) {
+ if (IsGuardPage (Memory)) {
+ Memory += EFI_PAGE_SIZE;
+ Length -= EFI_PAGE_SIZE;
+ if (Length == 0) {
+ return EFI_SUCCESS;
+ }
+ }
+
+ if (IsGuardPage (Memory + Length - EFI_PAGE_SIZE)) {
+ Length -= EFI_PAGE_SIZE;
+ if (Length == 0) {
+ return EFI_SUCCESS;
+ }
+ }
+ }
+
+ //
+ // Update the executable permissions according to the DXE memory
+ // protection policy, but only if
+ // - the policy is different between the old and the new type, or
+ // - this is a newly added region (OldType == EfiMaxMemoryType)
+ //
+ NewAttributes = GetPermissionAttributeForMemoryType (NewType);
+
+ if (OldType != EfiMaxMemoryType) {
+ OldAttributes = GetPermissionAttributeForMemoryType (OldType);
+ if (OldAttributes == NewAttributes) {
+ // policy is the same between OldType and NewType
+ return EFI_SUCCESS;
+ }
+ } else if (NewAttributes == 0) {
+ // newly added region of a type that does not require protection
+ return EFI_SUCCESS;
+ }
+
+ return gCpu->SetMemoryAttributes (gCpu, Memory, Length, NewAttributes);
+}
diff --git a/MdeModulePkg/Core/Dxe/Misc/SetWatchdogTimer.c b/MdeModulePkg/Core/Dxe/Misc/SetWatchdogTimer.c
index c3cabc0d36..e1b092176b 100644
--- a/MdeModulePkg/Core/Dxe/Misc/SetWatchdogTimer.c
+++ b/MdeModulePkg/Core/Dxe/Misc/SetWatchdogTimer.c
@@ -1,66 +1,66 @@
-/** @file
- UEFI Miscellaneous boot Services SetWatchdogTimer service implementation
-
-Copyright (c) 2006 - 2008, Intel Corporation. All rights reserved.<BR>
-SPDX-License-Identifier: BSD-2-Clause-Patent
-
-**/
-
-#include "DxeMain.h"
-
-#define WATCHDOG_TIMER_CALIBRATE_PER_SECOND 10000000
-
-/**
- Sets the system's watchdog timer.
-
- @param Timeout The number of seconds to set the watchdog timer to.
- A value of zero disables the timer.
- @param WatchdogCode The numeric code to log on a watchdog timer timeout
- event. The firmware reserves codes 0x0000 to 0xFFFF.
- Loaders and operating systems may use other timeout
- codes.
- @param DataSize The size, in bytes, of WatchdogData.
- @param WatchdogData A data buffer that includes a Null-terminated Unicode
- string, optionally followed by additional binary data.
- The string is a description that the call may use to
- further indicate the reason to be logged with a
- watchdog event.
-
- @return EFI_SUCCESS Timeout has been set
- @return EFI_NOT_AVAILABLE_YET WatchdogTimer is not available yet
- @return EFI_UNSUPPORTED System does not have a timer (currently not used)
- @return EFI_DEVICE_ERROR Could not complete due to hardware error
-
-**/
-EFI_STATUS
-EFIAPI
-CoreSetWatchdogTimer (
- IN UINTN Timeout,
- IN UINT64 WatchdogCode,
- IN UINTN DataSize,
- IN CHAR16 *WatchdogData OPTIONAL
- )
-{
- EFI_STATUS Status;
-
- //
- // Check our architectural protocol
- //
- if (gWatchdogTimer == NULL) {
- return EFI_NOT_AVAILABLE_YET;
- }
-
- //
- // Attempt to set the timeout
- //
- Status = gWatchdogTimer->SetTimerPeriod (gWatchdogTimer, MultU64x32 (Timeout, WATCHDOG_TIMER_CALIBRATE_PER_SECOND));
-
- //
- // Check for errors
- //
- if (EFI_ERROR (Status)) {
- return EFI_DEVICE_ERROR;
- }
-
- return EFI_SUCCESS;
-}
+/** @file
+ UEFI Miscellaneous boot Services SetWatchdogTimer service implementation
+
+Copyright (c) 2006 - 2008, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "DxeMain.h"
+
+#define WATCHDOG_TIMER_CALIBRATE_PER_SECOND 10000000
+
+/**
+ Sets the system's watchdog timer.
+
+ @param Timeout The number of seconds to set the watchdog timer to.
+ A value of zero disables the timer.
+ @param WatchdogCode The numeric code to log on a watchdog timer timeout
+ event. The firmware reserves codes 0x0000 to 0xFFFF.
+ Loaders and operating systems may use other timeout
+ codes.
+ @param DataSize The size, in bytes, of WatchdogData.
+ @param WatchdogData A data buffer that includes a Null-terminated Unicode
+ string, optionally followed by additional binary data.
+ The string is a description that the call may use to
+ further indicate the reason to be logged with a
+ watchdog event.
+
+ @return EFI_SUCCESS Timeout has been set
+ @return EFI_NOT_AVAILABLE_YET WatchdogTimer is not available yet
+ @return EFI_UNSUPPORTED System does not have a timer (currently not used)
+ @return EFI_DEVICE_ERROR Could not complete due to hardware error
+
+**/
+EFI_STATUS
+EFIAPI
+CoreSetWatchdogTimer (
+ IN UINTN Timeout,
+ IN UINT64 WatchdogCode,
+ IN UINTN DataSize,
+ IN CHAR16 *WatchdogData OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+
+ //
+ // Check our architectural protocol
+ //
+ if (gWatchdogTimer == NULL) {
+ return EFI_NOT_AVAILABLE_YET;
+ }
+
+ //
+ // Attempt to set the timeout
+ //
+ Status = gWatchdogTimer->SetTimerPeriod (gWatchdogTimer, MultU64x32 (Timeout, WATCHDOG_TIMER_CALIBRATE_PER_SECOND));
+
+ //
+ // Check for errors
+ //
+ if (EFI_ERROR (Status)) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ return EFI_SUCCESS;
+}
diff --git a/MdeModulePkg/Core/Dxe/Misc/Stall.c b/MdeModulePkg/Core/Dxe/Misc/Stall.c
index 35e045d41a..43a272af6c 100644
--- a/MdeModulePkg/Core/Dxe/Misc/Stall.c
+++ b/MdeModulePkg/Core/Dxe/Misc/Stall.c
@@ -1,109 +1,109 @@
-/** @file
- UEFI Miscellaneous boot Services Stall service implementation
-
-Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
-SPDX-License-Identifier: BSD-2-Clause-Patent
-
-**/
-
-//
-// Include statements
-//
-
-#include "DxeMain.h"
-
-/**
- Internal worker function to call the Metronome Architectural Protocol for
- the number of ticks specified by the UINT64 Counter value. WaitForTick()
- service of the Metronome Architectural Protocol uses a UINT32 for the number
- of ticks to wait, so this function loops when Counter is larger than 0xffffffff.
-
- @param Counter Number of ticks to wait.
-
-**/
-VOID
-CoreInternalWaitForTick (
- IN UINT64 Counter
- )
-{
- while (RShiftU64 (Counter, 32) > 0) {
- gMetronome->WaitForTick (gMetronome, 0xffffffff);
- Counter -= 0xffffffff;
- }
-
- gMetronome->WaitForTick (gMetronome, (UINT32)Counter);
-}
-
-/**
- Introduces a fine-grained stall.
-
- @param Microseconds The number of microseconds to stall execution.
-
- @retval EFI_SUCCESS Execution was stalled for at least the requested
- amount of microseconds.
- @retval EFI_NOT_AVAILABLE_YET gMetronome is not available yet
-
-**/
-EFI_STATUS
-EFIAPI
-CoreStall (
- IN UINTN Microseconds
- )
-{
- UINT64 Counter;
- UINT32 Remainder;
- UINTN Index;
-
- if (gMetronome == NULL) {
- return EFI_NOT_AVAILABLE_YET;
- }
-
- //
- // Counter = Microseconds * 10 / gMetronome->TickPeriod
- // 0x1999999999999999 = (2^64 - 1) / 10
- //
- if ((UINT64)Microseconds > 0x1999999999999999ULL) {
- //
- // Microseconds is too large to multiple by 10 first. Perform the divide
- // operation first and loop 10 times to avoid 64-bit math overflow.
- //
- Counter = DivU64x32Remainder (
- Microseconds,
- gMetronome->TickPeriod,
- &Remainder
- );
- for (Index = 0; Index < 10; Index++) {
- CoreInternalWaitForTick (Counter);
- }
-
- if (Remainder != 0) {
- //
- // If Remainder was not zero, then normally, Counter would be rounded
- // up by 1 tick. In this case, since a loop for 10 counts was used
- // to emulate the multiply by 10 operation, Counter needs to be rounded
- // up by 10 counts.
- //
- CoreInternalWaitForTick (10);
- }
- } else {
- //
- // Calculate the number of ticks by dividing the number of microseconds by
- // the TickPeriod. Calculation is based on 100ns unit.
- //
- Counter = DivU64x32Remainder (
- MultU64x32 (Microseconds, 10),
- gMetronome->TickPeriod,
- &Remainder
- );
- if (Remainder != 0) {
- //
- // If Remainder is not zero, then round Counter up by one tick.
- //
- Counter++;
- }
-
- CoreInternalWaitForTick (Counter);
- }
-
- return EFI_SUCCESS;
-}
+/** @file
+ UEFI Miscellaneous boot Services Stall service implementation
+
+Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+//
+// Include statements
+//
+
+#include "DxeMain.h"
+
+/**
+ Internal worker function to call the Metronome Architectural Protocol for
+ the number of ticks specified by the UINT64 Counter value. WaitForTick()
+ service of the Metronome Architectural Protocol uses a UINT32 for the number
+ of ticks to wait, so this function loops when Counter is larger than 0xffffffff.
+
+ @param Counter Number of ticks to wait.
+
+**/
+VOID
+CoreInternalWaitForTick (
+ IN UINT64 Counter
+ )
+{
+ while (RShiftU64 (Counter, 32) > 0) {
+ gMetronome->WaitForTick (gMetronome, 0xffffffff);
+ Counter -= 0xffffffff;
+ }
+
+ gMetronome->WaitForTick (gMetronome, (UINT32)Counter);
+}
+
+/**
+ Introduces a fine-grained stall.
+
+ @param Microseconds The number of microseconds to stall execution.
+
+ @retval EFI_SUCCESS Execution was stalled for at least the requested
+ amount of microseconds.
+ @retval EFI_NOT_AVAILABLE_YET gMetronome is not available yet
+
+**/
+EFI_STATUS
+EFIAPI
+CoreStall (
+ IN UINTN Microseconds
+ )
+{
+ UINT64 Counter;
+ UINT32 Remainder;
+ UINTN Index;
+
+ if (gMetronome == NULL) {
+ return EFI_NOT_AVAILABLE_YET;
+ }
+
+ //
+ // Counter = Microseconds * 10 / gMetronome->TickPeriod
+ // 0x1999999999999999 = (2^64 - 1) / 10
+ //
+ if ((UINT64)Microseconds > 0x1999999999999999ULL) {
+ //
+ // Microseconds is too large to multiple by 10 first. Perform the divide
+ // operation first and loop 10 times to avoid 64-bit math overflow.
+ //
+ Counter = DivU64x32Remainder (
+ Microseconds,
+ gMetronome->TickPeriod,
+ &Remainder
+ );
+ for (Index = 0; Index < 10; Index++) {
+ CoreInternalWaitForTick (Counter);
+ }
+
+ if (Remainder != 0) {
+ //
+ // If Remainder was not zero, then normally, Counter would be rounded
+ // up by 1 tick. In this case, since a loop for 10 counts was used
+ // to emulate the multiply by 10 operation, Counter needs to be rounded
+ // up by 10 counts.
+ //
+ CoreInternalWaitForTick (10);
+ }
+ } else {
+ //
+ // Calculate the number of ticks by dividing the number of microseconds by
+ // the TickPeriod. Calculation is based on 100ns unit.
+ //
+ Counter = DivU64x32Remainder (
+ MultU64x32 (Microseconds, 10),
+ gMetronome->TickPeriod,
+ &Remainder
+ );
+ if (Remainder != 0) {
+ //
+ // If Remainder is not zero, then round Counter up by one tick.
+ //
+ Counter++;
+ }
+
+ CoreInternalWaitForTick (Counter);
+ }
+
+ return EFI_SUCCESS;
+}
diff --git a/MdeModulePkg/Core/Dxe/SectionExtraction/CoreSectionExtraction.c b/MdeModulePkg/Core/Dxe/SectionExtraction/CoreSectionExtraction.c
index 2152833ff6..ce1a3835ba 100644
--- a/MdeModulePkg/Core/Dxe/SectionExtraction/CoreSectionExtraction.c
+++ b/MdeModulePkg/Core/Dxe/SectionExtraction/CoreSectionExtraction.c
@@ -1,1653 +1,1653 @@
-/** @file
- Section Extraction Protocol implementation.
-
- Stream database is implemented as a linked list of section streams,
- where each stream contains a linked list of children, which may be leaves or
- encapsulations.
-
- Children that are encapsulations generate new stream entries
- when they are created. Streams can also be created by calls to
- SEP->OpenSectionStream().
-
- The database is only created far enough to return the requested data from
- any given stream, or to determine that the requested data is not found.
-
- If a GUIDed encapsulation is encountered, there are three possiblilites.
-
- 1) A support protocol is found, in which the stream is simply processed with
- the support protocol.
-
- 2) A support protocol is not found, but the data is available to be read
- without processing. In this case, the database is built up through the
- recursions to return the data, and a RPN event is set that will enable
- the stream in question to be refreshed if and when the required section
- extraction protocol is published.This insures the AuthenticationStatus
- does not become stale in the cache.
-
- 3) A support protocol is not found, and the data is not available to be read
- without it. This results in EFI_PROTOCOL_ERROR.
-
-Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
-SPDX-License-Identifier: BSD-2-Clause-Patent
-
-**/
-
-#include "DxeMain.h"
-
-//
-// Local defines and typedefs
-//
-#define CORE_SECTION_CHILD_SIGNATURE SIGNATURE_32('S','X','C','S')
-#define CHILD_SECTION_NODE_FROM_LINK(Node) \
- CR (Node, CORE_SECTION_CHILD_NODE, Link, CORE_SECTION_CHILD_SIGNATURE)
-
-typedef struct {
- UINT32 Signature;
- LIST_ENTRY Link;
- UINT32 Type;
- UINT32 Size;
- //
- // StreamBase + OffsetInStream == pointer to section header in stream. The
- // stream base is always known when walking the sections within.
- //
- UINT32 OffsetInStream;
- //
- // Then EncapsulatedStreamHandle below is always 0 if the section is NOT an
- // encapsulating section. Otherwise, it contains the stream handle
- // of the encapsulated stream. This handle is ALWAYS produced any time an
- // encapsulating child is encountered, irrespective of whether the
- // encapsulated stream is processed further.
- //
- UINTN EncapsulatedStreamHandle;
- EFI_GUID *EncapsulationGuid;
- //
- // If the section REQUIRES an extraction protocol, register for RPN
- // when the required GUIDed extraction protocol becomes available.
- //
- EFI_EVENT Event;
-} CORE_SECTION_CHILD_NODE;
-
-#define CORE_SECTION_STREAM_SIGNATURE SIGNATURE_32('S','X','S','S')
-#define STREAM_NODE_FROM_LINK(Node) \
- CR (Node, CORE_SECTION_STREAM_NODE, Link, CORE_SECTION_STREAM_SIGNATURE)
-
-typedef struct {
- UINT32 Signature;
- LIST_ENTRY Link;
- UINTN StreamHandle;
- UINT8 *StreamBuffer;
- UINTN StreamLength;
- LIST_ENTRY Children;
- //
- // Authentication status is from GUIDed encapsulations.
- //
- UINT32 AuthenticationStatus;
-} CORE_SECTION_STREAM_NODE;
-
-#define NULL_STREAM_HANDLE 0
-
-typedef struct {
- CORE_SECTION_CHILD_NODE *ChildNode;
- CORE_SECTION_STREAM_NODE *ParentStream;
- VOID *Registration;
-} RPN_EVENT_CONTEXT;
-
-/**
- The ExtractSection() function processes the input section and
- allocates a buffer from the pool in which it returns the section
- contents. If the section being extracted contains
- authentication information (the section's
- GuidedSectionHeader.Attributes field has the
- EFI_GUIDED_SECTION_AUTH_STATUS_VALID bit set), the values
- returned in AuthenticationStatus must reflect the results of
- the authentication operation. Depending on the algorithm and
- size of the encapsulated data, the time that is required to do
- a full authentication may be prohibitively long for some
- classes of systems. To indicate this, use
- EFI_SECURITY_POLICY_PROTOCOL_GUID, which may be published by
- the security policy driver (see the Platform Initialization
- Driver Execution Environment Core Interface Specification for
- more details and the GUID definition). If the
- EFI_SECURITY_POLICY_PROTOCOL_GUID exists in the handle
- database, then, if possible, full authentication should be
- skipped and the section contents simply returned in the
- OutputBuffer. In this case, the
- EFI_AUTH_STATUS_PLATFORM_OVERRIDE bit AuthenticationStatus
- must be set on return. ExtractSection() is callable only from
- TPL_NOTIFY and below. Behavior of ExtractSection() at any
- EFI_TPL above TPL_NOTIFY is undefined. Type EFI_TPL is
- defined in RaiseTPL() in the UEFI 2.0 specification.
-
-
- @param This Indicates the
- EFI_GUIDED_SECTION_EXTRACTION_PROTOCOL instance.
- @param InputSection Buffer containing the input GUIDed section
- to be processed. OutputBuffer OutputBuffer
- is allocated from boot services pool
- memory and contains the new section
- stream. The caller is responsible for
- freeing this buffer.
- @param OutputBuffer *OutputBuffer is allocated from boot services
- pool memory and contains the new section stream.
- The caller is responsible for freeing this buffer.
- @param OutputSize A pointer to a caller-allocated UINTN in
- which the size of OutputBuffer allocation
- is stored. If the function returns
- anything other than EFI_SUCCESS, the value
- of OutputSize is undefined.
-
- @param AuthenticationStatus A pointer to a caller-allocated
- UINT32 that indicates the
- authentication status of the
- output buffer. If the input
- section's
- GuidedSectionHeader.Attributes
- field has the
- EFI_GUIDED_SECTION_AUTH_STATUS_VAL
- bit as clear, AuthenticationStatus
- must return zero. Both local bits
- (19:16) and aggregate bits (3:0)
- in AuthenticationStatus are
- returned by ExtractSection().
- These bits reflect the status of
- the extraction operation. The bit
- pattern in both regions must be
- the same, as the local and
- aggregate authentication statuses
- have equivalent meaning at this
- level. If the function returns
- anything other than EFI_SUCCESS,
- the value of AuthenticationStatus
- is undefined.
-
-
- @retval EFI_SUCCESS The InputSection was successfully
- processed and the section contents were
- returned.
-
- @retval EFI_OUT_OF_RESOURCES The system has insufficient
- resources to process the
- request.
-
- @retval EFI_INVALID_PARAMETER The GUID in InputSection does
- not match this instance of the
- GUIDed Section Extraction
- Protocol.
-
-**/
-EFI_STATUS
-EFIAPI
-CustomGuidedSectionExtract (
- IN CONST EFI_GUIDED_SECTION_EXTRACTION_PROTOCOL *This,
- IN CONST VOID *InputSection,
- OUT VOID **OutputBuffer,
- OUT UINTN *OutputSize,
- OUT UINT32 *AuthenticationStatus
- );
-
-//
-// Module globals
-//
-LIST_ENTRY mStreamRoot = INITIALIZE_LIST_HEAD_VARIABLE (mStreamRoot);
-
-EFI_HANDLE mSectionExtractionHandle = NULL;
-
-EFI_GUIDED_SECTION_EXTRACTION_PROTOCOL mCustomGuidedSectionExtractionProtocol = {
- CustomGuidedSectionExtract
-};
-
-/**
- Entry point of the section extraction code. Initializes an instance of the
- section extraction interface and installs it on a new handle.
-
- @param ImageHandle A handle for the image that is initializing this driver
- @param SystemTable A pointer to the EFI system table
-
- @retval EFI_SUCCESS Driver initialized successfully
- @retval EFI_OUT_OF_RESOURCES Could not allocate needed resources
-
-**/
-EFI_STATUS
-EFIAPI
-InitializeSectionExtraction (
- IN EFI_HANDLE ImageHandle,
- IN EFI_SYSTEM_TABLE *SystemTable
- )
-{
- EFI_STATUS Status;
- EFI_GUID *ExtractHandlerGuidTable;
- UINTN ExtractHandlerNumber;
-
- //
- // Get custom extract guided section method guid list
- //
- ExtractHandlerNumber = ExtractGuidedSectionGetGuidList (&ExtractHandlerGuidTable);
-
- Status = EFI_SUCCESS;
- //
- // Install custom guided extraction protocol
- //
- while (ExtractHandlerNumber-- > 0) {
- Status = CoreInstallProtocolInterface (
- &mSectionExtractionHandle,
- &ExtractHandlerGuidTable[ExtractHandlerNumber],
- EFI_NATIVE_INTERFACE,
- &mCustomGuidedSectionExtractionProtocol
- );
- ASSERT_EFI_ERROR (Status);
- }
-
- return Status;
-}
-
-/**
- Check if a stream is valid.
-
- @param SectionStream The section stream to be checked
- @param SectionStreamLength The length of section stream
-
- @return A boolean value indicating the validness of the section stream.
-
-**/
-BOOLEAN
-IsValidSectionStream (
- IN VOID *SectionStream,
- IN UINTN SectionStreamLength
- )
-{
- UINTN TotalLength;
- UINTN SectionLength;
- EFI_COMMON_SECTION_HEADER *SectionHeader;
- EFI_COMMON_SECTION_HEADER *NextSectionHeader;
-
- TotalLength = 0;
- SectionHeader = (EFI_COMMON_SECTION_HEADER *)SectionStream;
-
- while (TotalLength < SectionStreamLength) {
- if (IS_SECTION2 (SectionHeader)) {
- SectionLength = SECTION2_SIZE (SectionHeader);
- } else {
- SectionLength = SECTION_SIZE (SectionHeader);
- }
-
- TotalLength += SectionLength;
-
- if (TotalLength == SectionStreamLength) {
- return TRUE;
- }
-
- //
- // Move to the next byte following the section...
- //
- SectionHeader = (EFI_COMMON_SECTION_HEADER *)((UINT8 *)SectionHeader + SectionLength);
-
- //
- // Figure out where the next section begins
- //
- NextSectionHeader = ALIGN_POINTER (SectionHeader, 4);
- TotalLength += (UINTN)NextSectionHeader - (UINTN)SectionHeader;
- SectionHeader = NextSectionHeader;
- }
-
- ASSERT (FALSE);
- return FALSE;
-}
-
-/**
- Worker function. Constructor for section streams.
-
- @param SectionStreamLength Size in bytes of the section stream.
- @param SectionStream Buffer containing the new section stream.
- @param AllocateBuffer Indicates whether the stream buffer is to be
- copied or the input buffer is to be used in
- place. AuthenticationStatus- Indicates the
- default authentication status for the new
- stream.
- @param AuthenticationStatus A pointer to a caller-allocated UINT32 that
- indicates the authentication status of the
- output buffer. If the input section's
- GuidedSectionHeader.Attributes field
- has the EFI_GUIDED_SECTION_AUTH_STATUS_VALID
- bit as clear, AuthenticationStatus must return
- zero. Both local bits (19:16) and aggregate
- bits (3:0) in AuthenticationStatus are returned
- by ExtractSection(). These bits reflect the
- status of the extraction operation. The bit
- pattern in both regions must be the same, as
- the local and aggregate authentication statuses
- have equivalent meaning at this level. If the
- function returns anything other than
- EFI_SUCCESS, the value of *AuthenticationStatus
- is undefined.
- @param SectionStreamHandle A pointer to a caller allocated section stream
- handle.
-
- @retval EFI_SUCCESS Stream was added to stream database.
- @retval EFI_OUT_OF_RESOURCES memory allocation failed.
-
-**/
-EFI_STATUS
-OpenSectionStreamEx (
- IN UINTN SectionStreamLength,
- IN VOID *SectionStream,
- IN BOOLEAN AllocateBuffer,
- IN UINT32 AuthenticationStatus,
- OUT UINTN *SectionStreamHandle
- )
-{
- CORE_SECTION_STREAM_NODE *NewStream;
- EFI_TPL OldTpl;
-
- //
- // Allocate a new stream
- //
- NewStream = AllocatePool (sizeof (CORE_SECTION_STREAM_NODE));
- if (NewStream == NULL) {
- return EFI_OUT_OF_RESOURCES;
- }
-
- if (AllocateBuffer) {
- //
- // if we're here, we're double buffering, allocate the buffer and copy the
- // data in
- //
- if (SectionStreamLength > 0) {
- NewStream->StreamBuffer = AllocatePool (SectionStreamLength);
- if (NewStream->StreamBuffer == NULL) {
- CoreFreePool (NewStream);
- return EFI_OUT_OF_RESOURCES;
- }
-
- //
- // Copy in stream data
- //
- CopyMem (NewStream->StreamBuffer, SectionStream, SectionStreamLength);
- } else {
- //
- // It's possible to have a zero length section stream.
- //
- NewStream->StreamBuffer = NULL;
- }
- } else {
- //
- // If were here, the caller has supplied the buffer (it's an internal call)
- // so just assign the buffer. This happens when we open section streams
- // as a result of expanding an encapsulating section.
- //
- NewStream->StreamBuffer = SectionStream;
- }
-
- //
- // Initialize the rest of the section stream
- //
- NewStream->Signature = CORE_SECTION_STREAM_SIGNATURE;
- NewStream->StreamHandle = (UINTN)NewStream;
- NewStream->StreamLength = SectionStreamLength;
- InitializeListHead (&NewStream->Children);
- NewStream->AuthenticationStatus = AuthenticationStatus;
-
- //
- // Add new stream to stream list
- //
- OldTpl = CoreRaiseTpl (TPL_NOTIFY);
- InsertTailList (&mStreamRoot, &NewStream->Link);
- CoreRestoreTpl (OldTpl);
-
- *SectionStreamHandle = NewStream->StreamHandle;
-
- return EFI_SUCCESS;
-}
-
-/**
- SEP member function. This function creates and returns a new section stream
- handle to represent the new section stream.
-
- @param SectionStreamLength Size in bytes of the section stream.
- @param SectionStream Buffer containing the new section stream.
- @param SectionStreamHandle A pointer to a caller allocated UINTN that on
- output contains the new section stream handle.
-
- @retval EFI_SUCCESS The section stream is created successfully.
- @retval EFI_OUT_OF_RESOURCES memory allocation failed.
- @retval EFI_INVALID_PARAMETER Section stream does not end concident with end
- of last section.
-
-**/
-EFI_STATUS
-EFIAPI
-OpenSectionStream (
- IN UINTN SectionStreamLength,
- IN VOID *SectionStream,
- OUT UINTN *SectionStreamHandle
- )
-{
- //
- // Check to see section stream looks good...
- //
- if (!IsValidSectionStream (SectionStream, SectionStreamLength)) {
- return EFI_INVALID_PARAMETER;
- }
-
- return OpenSectionStreamEx (
- SectionStreamLength,
- SectionStream,
- FALSE,
- 0,
- SectionStreamHandle
- );
-}
-
-/**
- Worker function. Determine if the input stream:child matches the input type.
-
- @param Stream Indicates the section stream associated with the
- child
- @param Child Indicates the child to check
- @param SearchType Indicates the type of section to check against
- for
- @param SectionDefinitionGuid Indicates the GUID to check against if the type
- is EFI_SECTION_GUID_DEFINED
-
- @retval TRUE The child matches
- @retval FALSE The child doesn't match
-
-**/
-BOOLEAN
-ChildIsType (
- IN CORE_SECTION_STREAM_NODE *Stream,
- IN CORE_SECTION_CHILD_NODE *Child,
- IN EFI_SECTION_TYPE SearchType,
- IN EFI_GUID *SectionDefinitionGuid
- )
-{
- EFI_GUID_DEFINED_SECTION *GuidedSection;
-
- if (SearchType == EFI_SECTION_ALL) {
- return TRUE;
- }
-
- if (Child->Type != SearchType) {
- return FALSE;
- }
-
- if ((SearchType != EFI_SECTION_GUID_DEFINED) || (SectionDefinitionGuid == NULL)) {
- return TRUE;
- }
-
- GuidedSection = (EFI_GUID_DEFINED_SECTION *)(Stream->StreamBuffer + Child->OffsetInStream);
- if (IS_SECTION2 (GuidedSection)) {
- return CompareGuid (&(((EFI_GUID_DEFINED_SECTION2 *)GuidedSection)->SectionDefinitionGuid), SectionDefinitionGuid);
- } else {
- return CompareGuid (&GuidedSection->SectionDefinitionGuid, SectionDefinitionGuid);
- }
-}
-
-/**
- Verify the Guided Section GUID by checking if there is the Guided Section GUID configuration table recorded the GUID itself.
-
- @param GuidedSectionGuid The Guided Section GUID.
- @param GuidedSectionExtraction A pointer to the pointer to the supported Guided Section Extraction Protocol
- for the Guided Section.
-
- @return TRUE The GuidedSectionGuid could be identified, and the pointer to
- the Guided Section Extraction Protocol will be returned to *GuidedSectionExtraction.
- @return FALSE The GuidedSectionGuid could not be identified, or
- the Guided Section Extraction Protocol has not been installed yet.
-
-**/
-BOOLEAN
-VerifyGuidedSectionGuid (
- IN EFI_GUID *GuidedSectionGuid,
- OUT EFI_GUIDED_SECTION_EXTRACTION_PROTOCOL **GuidedSectionExtraction
- )
-{
- EFI_GUID *GuidRecorded;
- VOID *Interface;
- EFI_STATUS Status;
-
- Interface = NULL;
-
- //
- // Check if there is the Guided Section GUID configuration table recorded the GUID itself.
- //
- Status = EfiGetSystemConfigurationTable (GuidedSectionGuid, (VOID **)&GuidRecorded);
- if (Status == EFI_SUCCESS) {
- if (CompareGuid (GuidRecorded, GuidedSectionGuid)) {
- //
- // Found the recorded GuidedSectionGuid.
- //
- Status = CoreLocateProtocol (GuidedSectionGuid, NULL, (VOID **)&Interface);
- if (!EFI_ERROR (Status) && (Interface != NULL)) {
- //
- // Found the supported Guided Section Extraction Porotocol for the Guided Section.
- //
- *GuidedSectionExtraction = (EFI_GUIDED_SECTION_EXTRACTION_PROTOCOL *)Interface;
- return TRUE;
- }
-
- return FALSE;
- }
- }
-
- return FALSE;
-}
-
-/**
- RPN callback function. Initializes the section stream
- when GUIDED_SECTION_EXTRACTION_PROTOCOL is installed.
-
- @param Event The event that fired
- @param RpnContext A pointer to the context that allows us to identify
- the relevent encapsulation.
-**/
-VOID
-EFIAPI
-NotifyGuidedExtraction (
- IN EFI_EVENT Event,
- IN VOID *RpnContext
- )
-{
- EFI_STATUS Status;
- EFI_GUID_DEFINED_SECTION *GuidedHeader;
- EFI_GUIDED_SECTION_EXTRACTION_PROTOCOL *GuidedExtraction;
- VOID *NewStreamBuffer;
- UINTN NewStreamBufferSize;
- UINT32 AuthenticationStatus;
- RPN_EVENT_CONTEXT *Context;
-
- Context = RpnContext;
-
- GuidedHeader = (EFI_GUID_DEFINED_SECTION *)(Context->ParentStream->StreamBuffer + Context->ChildNode->OffsetInStream);
- ASSERT (GuidedHeader->CommonHeader.Type == EFI_SECTION_GUID_DEFINED);
-
- if (!VerifyGuidedSectionGuid (Context->ChildNode->EncapsulationGuid, &GuidedExtraction)) {
- return;
- }
-
- Status = GuidedExtraction->ExtractSection (
- GuidedExtraction,
- GuidedHeader,
- &NewStreamBuffer,
- &NewStreamBufferSize,
- &AuthenticationStatus
- );
- ASSERT_EFI_ERROR (Status);
-
- //
- // Make sure we initialize the new stream with the correct
- // authentication status for both aggregate and local status fields.
- //
- if ((GuidedHeader->Attributes & EFI_GUIDED_SECTION_AUTH_STATUS_VALID) != 0) {
- //
- // OR in the parent stream's aggregate status.
- //
- AuthenticationStatus |= Context->ParentStream->AuthenticationStatus & EFI_AUTH_STATUS_ALL;
- } else {
- //
- // since there's no authentication data contributed by the section,
- // just inherit the full value from our immediate parent.
- //
- AuthenticationStatus = Context->ParentStream->AuthenticationStatus;
- }
-
- Status = OpenSectionStreamEx (
- NewStreamBufferSize,
- NewStreamBuffer,
- FALSE,
- AuthenticationStatus,
- &Context->ChildNode->EncapsulatedStreamHandle
- );
- ASSERT_EFI_ERROR (Status);
-
- //
- // Close the event when done.
- //
- gBS->CloseEvent (Event);
- Context->ChildNode->Event = NULL;
- FreePool (Context);
-}
-
-/**
- Constructor for RPN event when a missing GUIDED_SECTION_EXTRACTION_PROTOCOL appears...
-
- @param ParentStream Indicates the parent of the ecnapsulation section (child)
- @param ChildNode Indicates the child node that is the encapsulation section.
-
-**/
-VOID
-CreateGuidedExtractionRpnEvent (
- IN CORE_SECTION_STREAM_NODE *ParentStream,
- IN CORE_SECTION_CHILD_NODE *ChildNode
- )
-{
- RPN_EVENT_CONTEXT *Context;
-
- //
- // Allocate new event structure and context
- //
- Context = AllocatePool (sizeof (RPN_EVENT_CONTEXT));
- ASSERT (Context != NULL);
-
- Context->ChildNode = ChildNode;
- Context->ParentStream = ParentStream;
-
- Context->ChildNode->Event = EfiCreateProtocolNotifyEvent (
- Context->ChildNode->EncapsulationGuid,
- TPL_NOTIFY,
- NotifyGuidedExtraction,
- Context,
- &Context->Registration
- );
-}
-
-/**
- Worker function. Constructor for new child nodes.
-
- @param Stream Indicates the section stream in which to add the
- child.
- @param ChildOffset Indicates the offset in Stream that is the
- beginning of the child section.
- @param ChildNode Indicates the Callee allocated and initialized
- child.
-
- @retval EFI_SUCCESS Child node was found and returned.
- EFI_OUT_OF_RESOURCES- Memory allocation failed.
- @retval EFI_PROTOCOL_ERROR Encapsulation sections produce new stream
- handles when the child node is created. If the
- section type is GUID defined, and the extraction
- GUID does not exist, and producing the stream
- requires the GUID, then a protocol error is
- generated and no child is produced. Values
- returned by OpenSectionStreamEx.
-
-**/
-EFI_STATUS
-CreateChildNode (
- IN CORE_SECTION_STREAM_NODE *Stream,
- IN UINT32 ChildOffset,
- OUT CORE_SECTION_CHILD_NODE **ChildNode
- )
-{
- EFI_STATUS Status;
- EFI_COMMON_SECTION_HEADER *SectionHeader;
- EFI_COMPRESSION_SECTION *CompressionHeader;
- EFI_GUID_DEFINED_SECTION *GuidedHeader;
- EFI_DECOMPRESS_PROTOCOL *Decompress;
- EFI_GUIDED_SECTION_EXTRACTION_PROTOCOL *GuidedExtraction;
- VOID *NewStreamBuffer;
- VOID *ScratchBuffer;
- UINT32 ScratchSize;
- UINTN NewStreamBufferSize;
- UINT32 AuthenticationStatus;
- VOID *CompressionSource;
- UINT32 CompressionSourceSize;
- UINT32 UncompressedLength;
- UINT8 CompressionType;
- UINT16 GuidedSectionAttributes;
-
- CORE_SECTION_CHILD_NODE *Node;
-
- SectionHeader = (EFI_COMMON_SECTION_HEADER *)(Stream->StreamBuffer + ChildOffset);
-
- //
- // Allocate a new node
- //
- *ChildNode = AllocateZeroPool (sizeof (CORE_SECTION_CHILD_NODE));
- Node = *ChildNode;
- if (Node == NULL) {
- return EFI_OUT_OF_RESOURCES;
- }
-
- //
- // Now initialize it
- //
- Node->Signature = CORE_SECTION_CHILD_SIGNATURE;
- Node->Type = SectionHeader->Type;
- if (IS_SECTION2 (SectionHeader)) {
- Node->Size = SECTION2_SIZE (SectionHeader);
- } else {
- Node->Size = SECTION_SIZE (SectionHeader);
- }
-
- Node->OffsetInStream = ChildOffset;
- Node->EncapsulatedStreamHandle = NULL_STREAM_HANDLE;
- Node->EncapsulationGuid = NULL;
-
- //
- // If it's an encapsulating section, then create the new section stream also
- //
- switch (Node->Type) {
- case EFI_SECTION_COMPRESSION:
- //
- // Get the CompressionSectionHeader
- //
- if (Node->Size < sizeof (EFI_COMPRESSION_SECTION)) {
- CoreFreePool (Node);
- return EFI_NOT_FOUND;
- }
-
- CompressionHeader = (EFI_COMPRESSION_SECTION *)SectionHeader;
-
- if (IS_SECTION2 (CompressionHeader)) {
- CompressionSource = (VOID *)((UINT8 *)CompressionHeader + sizeof (EFI_COMPRESSION_SECTION2));
- CompressionSourceSize = (UINT32)(SECTION2_SIZE (CompressionHeader) - sizeof (EFI_COMPRESSION_SECTION2));
- UncompressedLength = ((EFI_COMPRESSION_SECTION2 *)CompressionHeader)->UncompressedLength;
- CompressionType = ((EFI_COMPRESSION_SECTION2 *)CompressionHeader)->CompressionType;
- } else {
- CompressionSource = (VOID *)((UINT8 *)CompressionHeader + sizeof (EFI_COMPRESSION_SECTION));
- CompressionSourceSize = (UINT32)(SECTION_SIZE (CompressionHeader) - sizeof (EFI_COMPRESSION_SECTION));
- UncompressedLength = CompressionHeader->UncompressedLength;
- CompressionType = CompressionHeader->CompressionType;
- }
-
- //
- // Allocate space for the new stream
- //
- if (UncompressedLength > 0) {
- NewStreamBufferSize = UncompressedLength;
- NewStreamBuffer = AllocatePool (NewStreamBufferSize);
- if (NewStreamBuffer == NULL) {
- CoreFreePool (Node);
- return EFI_OUT_OF_RESOURCES;
- }
-
- if (CompressionType == EFI_NOT_COMPRESSED) {
- //
- // stream is not actually compressed, just encapsulated. So just copy it.
- //
- CopyMem (NewStreamBuffer, CompressionSource, NewStreamBufferSize);
- } else if (CompressionType == EFI_STANDARD_COMPRESSION) {
- //
- // Only support the EFI_SATNDARD_COMPRESSION algorithm.
- //
-
- //
- // Decompress the stream
- //
- Status = CoreLocateProtocol (&gEfiDecompressProtocolGuid, NULL, (VOID **)&Decompress);
- ASSERT_EFI_ERROR (Status);
- ASSERT (Decompress != NULL);
-
- Status = Decompress->GetInfo (
- Decompress,
- CompressionSource,
- CompressionSourceSize,
- (UINT32 *)&NewStreamBufferSize,
- &ScratchSize
- );
- if (EFI_ERROR (Status) || (NewStreamBufferSize != UncompressedLength)) {
- CoreFreePool (Node);
- CoreFreePool (NewStreamBuffer);
- if (!EFI_ERROR (Status)) {
- Status = EFI_BAD_BUFFER_SIZE;
- }
-
- return Status;
- }
-
- ScratchBuffer = AllocatePool (ScratchSize);
- if (ScratchBuffer == NULL) {
- CoreFreePool (Node);
- CoreFreePool (NewStreamBuffer);
- return EFI_OUT_OF_RESOURCES;
- }
-
- Status = Decompress->Decompress (
- Decompress,
- CompressionSource,
- CompressionSourceSize,
- NewStreamBuffer,
- (UINT32)NewStreamBufferSize,
- ScratchBuffer,
- ScratchSize
- );
- CoreFreePool (ScratchBuffer);
- if (EFI_ERROR (Status)) {
- CoreFreePool (Node);
- CoreFreePool (NewStreamBuffer);
- return Status;
- }
- }
- } else {
- NewStreamBuffer = NULL;
- NewStreamBufferSize = 0;
- }
-
- Status = OpenSectionStreamEx (
- NewStreamBufferSize,
- NewStreamBuffer,
- FALSE,
- Stream->AuthenticationStatus,
- &Node->EncapsulatedStreamHandle
- );
- if (EFI_ERROR (Status)) {
- CoreFreePool (Node);
- CoreFreePool (NewStreamBuffer);
- return Status;
- }
-
- break;
-
- case EFI_SECTION_GUID_DEFINED:
- GuidedHeader = (EFI_GUID_DEFINED_SECTION *)SectionHeader;
- if (IS_SECTION2 (GuidedHeader)) {
- Node->EncapsulationGuid = &(((EFI_GUID_DEFINED_SECTION2 *)GuidedHeader)->SectionDefinitionGuid);
- GuidedSectionAttributes = ((EFI_GUID_DEFINED_SECTION2 *)GuidedHeader)->Attributes;
- } else {
- Node->EncapsulationGuid = &GuidedHeader->SectionDefinitionGuid;
- GuidedSectionAttributes = GuidedHeader->Attributes;
- }
-
- if (VerifyGuidedSectionGuid (Node->EncapsulationGuid, &GuidedExtraction)) {
- //
- // NewStreamBuffer is always allocated by ExtractSection... No caller
- // allocation here.
- //
- Status = GuidedExtraction->ExtractSection (
- GuidedExtraction,
- GuidedHeader,
- &NewStreamBuffer,
- &NewStreamBufferSize,
- &AuthenticationStatus
- );
- if (EFI_ERROR (Status)) {
- CoreFreePool (*ChildNode);
- return EFI_PROTOCOL_ERROR;
- }
-
- //
- // Make sure we initialize the new stream with the correct
- // authentication status for both aggregate and local status fields.
- //
- if ((GuidedSectionAttributes & EFI_GUIDED_SECTION_AUTH_STATUS_VALID) != 0) {
- //
- // OR in the parent stream's aggregate status.
- //
- AuthenticationStatus |= Stream->AuthenticationStatus & EFI_AUTH_STATUS_ALL;
- } else {
- //
- // since there's no authentication data contributed by the section,
- // just inherit the full value from our immediate parent.
- //
- AuthenticationStatus = Stream->AuthenticationStatus;
- }
-
- Status = OpenSectionStreamEx (
- NewStreamBufferSize,
- NewStreamBuffer,
- FALSE,
- AuthenticationStatus,
- &Node->EncapsulatedStreamHandle
- );
- if (EFI_ERROR (Status)) {
- CoreFreePool (*ChildNode);
- CoreFreePool (NewStreamBuffer);
- return Status;
- }
- } else {
- //
- // There's no GUIDed section extraction protocol available.
- //
- if ((GuidedSectionAttributes & EFI_GUIDED_SECTION_PROCESSING_REQUIRED) != 0) {
- //
- // If the section REQUIRES an extraction protocol, register for RPN
- // when the required GUIDed extraction protocol becomes available.
- //
- CreateGuidedExtractionRpnEvent (Stream, Node);
- } else {
- //
- // Figure out the proper authentication status
- //
- AuthenticationStatus = Stream->AuthenticationStatus;
-
- if ((GuidedSectionAttributes & EFI_GUIDED_SECTION_AUTH_STATUS_VALID) == EFI_GUIDED_SECTION_AUTH_STATUS_VALID) {
- AuthenticationStatus |= EFI_AUTH_STATUS_IMAGE_SIGNED | EFI_AUTH_STATUS_NOT_TESTED;
- }
-
- if (IS_SECTION2 (GuidedHeader)) {
- Status = OpenSectionStreamEx (
- SECTION2_SIZE (GuidedHeader) - ((EFI_GUID_DEFINED_SECTION2 *)GuidedHeader)->DataOffset,
- (UINT8 *)GuidedHeader + ((EFI_GUID_DEFINED_SECTION2 *)GuidedHeader)->DataOffset,
- TRUE,
- AuthenticationStatus,
- &Node->EncapsulatedStreamHandle
- );
- } else {
- Status = OpenSectionStreamEx (
- SECTION_SIZE (GuidedHeader) - ((EFI_GUID_DEFINED_SECTION *)GuidedHeader)->DataOffset,
- (UINT8 *)GuidedHeader + ((EFI_GUID_DEFINED_SECTION *)GuidedHeader)->DataOffset,
- TRUE,
- AuthenticationStatus,
- &Node->EncapsulatedStreamHandle
- );
- }
-
- if (EFI_ERROR (Status)) {
- CoreFreePool (Node);
- return Status;
- }
- }
- }
-
- break;
-
- default:
-
- //
- // Nothing to do if it's a leaf
- //
- break;
- }
-
- //
- // Last, add the new child node to the stream
- //
- InsertTailList (&Stream->Children, &Node->Link);
-
- return EFI_SUCCESS;
-}
-
-/**
- Worker function Recursively searches / builds section stream database
- looking for requested section.
-
- @param SourceStream Indicates the section stream in which to do the
- search.
- @param SearchType Indicates the type of section to search for.
- @param SectionInstance Indicates which instance of section to find.
- This is an in/out parameter and it is 1-based,
- to deal with recursions.
- @param SectionDefinitionGuid Guid of section definition
- @param Depth Nesting depth of encapsulation sections.
- Callers different from FindChildNode() are
- responsible for passing in a zero Depth.
- @param FoundChild Output indicating the child node that is found.
- @param FoundStream Output indicating which section stream the child
- was found in. If this stream was generated as a
- result of an encapsulation section, the
- streamhandle is visible within the SEP driver
- only.
- @param AuthenticationStatus Indicates the authentication status of the found section.
-
- @retval EFI_SUCCESS Child node was found and returned.
- EFI_OUT_OF_RESOURCES- Memory allocation failed.
- @retval EFI_NOT_FOUND Requested child node does not exist.
- @retval EFI_PROTOCOL_ERROR a required GUIDED section extraction protocol
- does not exist
- @retval EFI_ABORTED Recursion aborted because Depth has been
- greater than or equal to
- PcdFwVolDxeMaxEncapsulationDepth.
-
-**/
-EFI_STATUS
-FindChildNode (
- IN CORE_SECTION_STREAM_NODE *SourceStream,
- IN EFI_SECTION_TYPE SearchType,
- IN OUT UINTN *SectionInstance,
- IN EFI_GUID *SectionDefinitionGuid,
- IN UINT32 Depth,
- OUT CORE_SECTION_CHILD_NODE **FoundChild,
- OUT CORE_SECTION_STREAM_NODE **FoundStream,
- OUT UINT32 *AuthenticationStatus
- )
-{
- CORE_SECTION_CHILD_NODE *CurrentChildNode;
- CORE_SECTION_CHILD_NODE *RecursedChildNode;
- CORE_SECTION_STREAM_NODE *RecursedFoundStream;
- UINT32 NextChildOffset;
- EFI_STATUS ErrorStatus;
- EFI_STATUS Status;
-
- ASSERT (*SectionInstance > 0);
-
- if (Depth >= PcdGet32 (PcdFwVolDxeMaxEncapsulationDepth)) {
- return EFI_ABORTED;
- }
-
- CurrentChildNode = NULL;
- ErrorStatus = EFI_NOT_FOUND;
-
- if (SourceStream->StreamLength == 0) {
- return EFI_NOT_FOUND;
- }
-
- if (IsListEmpty (&SourceStream->Children) &&
- (SourceStream->StreamLength >= sizeof (EFI_COMMON_SECTION_HEADER)))
- {
- //
- // This occurs when a section stream exists, but no child sections
- // have been parsed out yet. Therefore, extract the first child and add it
- // to the list of children so we can get started.
- // Section stream may contain an array of zero or more bytes.
- // So, its size should be >= the size of commen section header.
- //
- Status = CreateChildNode (SourceStream, 0, &CurrentChildNode);
- if (EFI_ERROR (Status)) {
- return Status;
- }
- }
-
- //
- // At least one child has been parsed out of the section stream. So, walk
- // through the sections that have already been parsed out looking for the
- // requested section, if necessary, continue parsing section stream and
- // adding children until either the requested section is found, or we run
- // out of data
- //
- CurrentChildNode = CHILD_SECTION_NODE_FROM_LINK (GetFirstNode (&SourceStream->Children));
-
- for ( ; ;) {
- ASSERT (CurrentChildNode != NULL);
- if (ChildIsType (SourceStream, CurrentChildNode, SearchType, SectionDefinitionGuid)) {
- //
- // The type matches, so check the instance count to see if it's the one we want
- //
- (*SectionInstance)--;
- if (*SectionInstance == 0) {
- //
- // Got it!
- //
- *FoundChild = CurrentChildNode;
- *FoundStream = SourceStream;
- *AuthenticationStatus = SourceStream->AuthenticationStatus;
- return EFI_SUCCESS;
- }
- }
-
- //
- // Type mismatch, or we haven't found the desired instance yet.
- //
- ASSERT (*SectionInstance > 0);
-
- if (CurrentChildNode->EncapsulatedStreamHandle != NULL_STREAM_HANDLE) {
- //
- // If the current node is an encapsulating node, recurse into it...
- //
- Status = FindChildNode (
- (CORE_SECTION_STREAM_NODE *)CurrentChildNode->EncapsulatedStreamHandle,
- SearchType,
- SectionInstance,
- SectionDefinitionGuid,
- Depth + 1,
- &RecursedChildNode,
- &RecursedFoundStream,
- AuthenticationStatus
- );
- if (*SectionInstance == 0) {
- //
- // The recursive FindChildNode() call decreased (*SectionInstance) to
- // zero.
- //
- ASSERT_EFI_ERROR (Status);
- *FoundChild = RecursedChildNode;
- *FoundStream = RecursedFoundStream;
- return EFI_SUCCESS;
- } else {
- if (Status == EFI_ABORTED) {
- //
- // If the recursive call was aborted due to nesting depth, stop
- // looking for the requested child node. The skipped subtree could
- // throw off the instance counting.
- //
- return Status;
- }
-
- //
- // Save the error code and continue to find the requested child node in
- // the rest of the stream.
- //
- ErrorStatus = Status;
- }
- } else if ((CurrentChildNode->Type == EFI_SECTION_GUID_DEFINED) && (SearchType != EFI_SECTION_GUID_DEFINED)) {
- //
- // When Node Type is GUIDED section, but Node has no encapsulated data, Node data should not be parsed
- // because a required GUIDED section extraction protocol does not exist.
- // If SearchType is not GUIDED section, EFI_PROTOCOL_ERROR should return.
- //
- ErrorStatus = EFI_PROTOCOL_ERROR;
- }
-
- if (!IsNodeAtEnd (&SourceStream->Children, &CurrentChildNode->Link)) {
- //
- // We haven't found the child node we're interested in yet, but there's
- // still more nodes that have already been parsed so get the next one
- // and continue searching..
- //
- CurrentChildNode = CHILD_SECTION_NODE_FROM_LINK (GetNextNode (&SourceStream->Children, &CurrentChildNode->Link));
- } else {
- //
- // We've exhausted children that have already been parsed, so see if
- // there's any more data and continue parsing out more children if there
- // is.
- //
- NextChildOffset = CurrentChildNode->OffsetInStream + CurrentChildNode->Size;
- //
- // Round up to 4 byte boundary
- //
- NextChildOffset += 3;
- NextChildOffset &= ~(UINTN)3;
- if (NextChildOffset <= SourceStream->StreamLength - sizeof (EFI_COMMON_SECTION_HEADER)) {
- //
- // There's an unparsed child remaining in the stream, so create a new child node
- //
- Status = CreateChildNode (SourceStream, NextChildOffset, &CurrentChildNode);
- if (EFI_ERROR (Status)) {
- return Status;
- }
- } else {
- ASSERT (EFI_ERROR (ErrorStatus));
- return ErrorStatus;
- }
- }
- }
-}
-
-/**
- Worker function. Search stream database for requested stream handle.
-
- @param SearchHandle Indicates which stream to look for.
- @param FoundStream Output pointer to the found stream.
-
- @retval EFI_SUCCESS StreamHandle was found and *FoundStream contains
- the stream node.
- @retval EFI_NOT_FOUND SearchHandle was not found in the stream
- database.
-
-**/
-EFI_STATUS
-FindStreamNode (
- IN UINTN SearchHandle,
- OUT CORE_SECTION_STREAM_NODE **FoundStream
- )
-{
- CORE_SECTION_STREAM_NODE *StreamNode;
-
- if (!IsListEmpty (&mStreamRoot)) {
- StreamNode = STREAM_NODE_FROM_LINK (GetFirstNode (&mStreamRoot));
- for ( ; ;) {
- if (StreamNode->StreamHandle == SearchHandle) {
- *FoundStream = StreamNode;
- return EFI_SUCCESS;
- } else if (IsNodeAtEnd (&mStreamRoot, &StreamNode->Link)) {
- break;
- } else {
- StreamNode = STREAM_NODE_FROM_LINK (GetNextNode (&mStreamRoot, &StreamNode->Link));
- }
- }
- }
-
- return EFI_NOT_FOUND;
-}
-
-/**
- SEP member function. Retrieves requested section from section stream.
-
- @param SectionStreamHandle The section stream from which to extract the
- requested section.
- @param SectionType A pointer to the type of section to search for.
- @param SectionDefinitionGuid If the section type is EFI_SECTION_GUID_DEFINED,
- then SectionDefinitionGuid indicates which of
- these types of sections to search for.
- @param SectionInstance Indicates which instance of the requested
- section to return.
- @param Buffer Double indirection to buffer. If *Buffer is
- non-null on input, then the buffer is caller
- allocated. If Buffer is NULL, then the buffer
- is callee allocated. In either case, the
- required buffer size is returned in *BufferSize.
- @param BufferSize On input, indicates the size of *Buffer if
- *Buffer is non-null on input. On output,
- indicates the required size (allocated size if
- callee allocated) of *Buffer.
- @param AuthenticationStatus A pointer to a caller-allocated UINT32 that
- indicates the authentication status of the
- output buffer. If the input section's
- GuidedSectionHeader.Attributes field
- has the EFI_GUIDED_SECTION_AUTH_STATUS_VALID
- bit as clear, AuthenticationStatus must return
- zero. Both local bits (19:16) and aggregate
- bits (3:0) in AuthenticationStatus are returned
- by ExtractSection(). These bits reflect the
- status of the extraction operation. The bit
- pattern in both regions must be the same, as
- the local and aggregate authentication statuses
- have equivalent meaning at this level. If the
- function returns anything other than
- EFI_SUCCESS, the value of *AuthenticationStatus
- is undefined.
- @param IsFfs3Fv Indicates the FV format.
-
- @retval EFI_SUCCESS Section was retrieved successfully
- @retval EFI_PROTOCOL_ERROR A GUID defined section was encountered in the
- section stream with its
- EFI_GUIDED_SECTION_PROCESSING_REQUIRED bit set,
- but there was no corresponding GUIDed Section
- Extraction Protocol in the handle database.
- *Buffer is unmodified.
- @retval EFI_NOT_FOUND An error was encountered when parsing the
- SectionStream. This indicates the SectionStream
- is not correctly formatted.
- @retval EFI_NOT_FOUND The requested section does not exist.
- @retval EFI_OUT_OF_RESOURCES The system has insufficient resources to process
- the request.
- @retval EFI_INVALID_PARAMETER The SectionStreamHandle does not exist.
- @retval EFI_WARN_TOO_SMALL The size of the caller allocated input buffer is
- insufficient to contain the requested section.
- The input buffer is filled and section contents
- are truncated.
-
-**/
-EFI_STATUS
-EFIAPI
-GetSection (
- IN UINTN SectionStreamHandle,
- IN EFI_SECTION_TYPE *SectionType,
- IN EFI_GUID *SectionDefinitionGuid,
- IN UINTN SectionInstance,
- IN VOID **Buffer,
- IN OUT UINTN *BufferSize,
- OUT UINT32 *AuthenticationStatus,
- IN BOOLEAN IsFfs3Fv
- )
-{
- CORE_SECTION_STREAM_NODE *StreamNode;
- EFI_TPL OldTpl;
- EFI_STATUS Status;
- CORE_SECTION_CHILD_NODE *ChildNode;
- CORE_SECTION_STREAM_NODE *ChildStreamNode;
- UINTN CopySize;
- UINT32 ExtractedAuthenticationStatus;
- UINTN Instance;
- UINT8 *CopyBuffer;
- UINTN SectionSize;
- EFI_COMMON_SECTION_HEADER *Section;
-
- ChildStreamNode = NULL;
- OldTpl = CoreRaiseTpl (TPL_NOTIFY);
- Instance = SectionInstance + 1;
-
- //
- // Locate target stream
- //
- Status = FindStreamNode (SectionStreamHandle, &StreamNode);
- if (EFI_ERROR (Status)) {
- Status = EFI_INVALID_PARAMETER;
- goto GetSection_Done;
- }
-
- //
- // Found the stream, now locate and return the appropriate section
- //
- if (SectionType == NULL) {
- //
- // SectionType == NULL means return the WHOLE section stream...
- //
- CopySize = StreamNode->StreamLength;
- CopyBuffer = StreamNode->StreamBuffer;
- *AuthenticationStatus = StreamNode->AuthenticationStatus;
- } else {
- //
- // There's a requested section type, so go find it and return it...
- //
- Status = FindChildNode (
- StreamNode,
- *SectionType,
- &Instance,
- SectionDefinitionGuid,
- 0, // encapsulation depth
- &ChildNode,
- &ChildStreamNode,
- &ExtractedAuthenticationStatus
- );
- if (EFI_ERROR (Status)) {
- if (Status == EFI_ABORTED) {
- DEBUG ((
- DEBUG_ERROR,
- "%a: recursion aborted due to nesting depth\n",
- __func__
- ));
- //
- // Map "aborted" to "not found".
- //
- Status = EFI_NOT_FOUND;
- }
-
- goto GetSection_Done;
- }
-
- Section = (EFI_COMMON_SECTION_HEADER *)(ChildStreamNode->StreamBuffer + ChildNode->OffsetInStream);
-
- if (IS_SECTION2 (Section)) {
- ASSERT (SECTION2_SIZE (Section) > 0x00FFFFFF);
- if (!IsFfs3Fv) {
- DEBUG ((DEBUG_ERROR, "It is a FFS3 formatted section in a non-FFS3 formatted FV.\n"));
- Status = EFI_NOT_FOUND;
- goto GetSection_Done;
- }
-
- CopySize = SECTION2_SIZE (Section) - sizeof (EFI_COMMON_SECTION_HEADER2);
- CopyBuffer = (UINT8 *)Section + sizeof (EFI_COMMON_SECTION_HEADER2);
- } else {
- CopySize = SECTION_SIZE (Section) - sizeof (EFI_COMMON_SECTION_HEADER);
- CopyBuffer = (UINT8 *)Section + sizeof (EFI_COMMON_SECTION_HEADER);
- }
-
- *AuthenticationStatus = ExtractedAuthenticationStatus;
- }
-
- SectionSize = CopySize;
- if (*Buffer != NULL) {
- //
- // Caller allocated buffer. Fill to size and return required size...
- //
- if (*BufferSize < CopySize) {
- Status = EFI_WARN_BUFFER_TOO_SMALL;
- CopySize = *BufferSize;
- }
- } else {
- //
- // Callee allocated buffer. Allocate buffer and return size.
- //
- *Buffer = AllocatePool (CopySize);
- if (*Buffer == NULL) {
- Status = EFI_OUT_OF_RESOURCES;
- goto GetSection_Done;
- }
- }
-
- CopyMem (*Buffer, CopyBuffer, CopySize);
- *BufferSize = SectionSize;
-
-GetSection_Done:
- CoreRestoreTpl (OldTpl);
-
- return Status;
-}
-
-/**
- Worker function. Destructor for child nodes.
-
- @param ChildNode Indicates the node to destroy
-
-**/
-VOID
-FreeChildNode (
- IN CORE_SECTION_CHILD_NODE *ChildNode
- )
-{
- ASSERT (ChildNode->Signature == CORE_SECTION_CHILD_SIGNATURE);
- //
- // Remove the child from it's list
- //
- RemoveEntryList (&ChildNode->Link);
-
- if (ChildNode->EncapsulatedStreamHandle != NULL_STREAM_HANDLE) {
- //
- // If it's an encapsulating section, we close the resulting section stream.
- // CloseSectionStream will free all memory associated with the stream.
- //
- CloseSectionStream (ChildNode->EncapsulatedStreamHandle, TRUE);
- }
-
- if (ChildNode->Event != NULL) {
- gBS->CloseEvent (ChildNode->Event);
- }
-
- //
- // Last, free the child node itself
- //
- CoreFreePool (ChildNode);
-}
-
-/**
- SEP member function. Deletes an existing section stream
-
- @param StreamHandleToClose Indicates the stream to close
- @param FreeStreamBuffer TRUE - Need to free stream buffer;
- FALSE - No need to free stream buffer.
-
- @retval EFI_SUCCESS The section stream is closed sucessfully.
- @retval EFI_OUT_OF_RESOURCES Memory allocation failed.
- @retval EFI_INVALID_PARAMETER Section stream does not end concident with end
- of last section.
-
-**/
-EFI_STATUS
-EFIAPI
-CloseSectionStream (
- IN UINTN StreamHandleToClose,
- IN BOOLEAN FreeStreamBuffer
- )
-{
- CORE_SECTION_STREAM_NODE *StreamNode;
- EFI_TPL OldTpl;
- EFI_STATUS Status;
- LIST_ENTRY *Link;
- CORE_SECTION_CHILD_NODE *ChildNode;
-
- OldTpl = CoreRaiseTpl (TPL_NOTIFY);
-
- //
- // Locate target stream
- //
- Status = FindStreamNode (StreamHandleToClose, &StreamNode);
- if (!EFI_ERROR (Status)) {
- //
- // Found the stream, so close it
- //
- RemoveEntryList (&StreamNode->Link);
- while (!IsListEmpty (&StreamNode->Children)) {
- Link = GetFirstNode (&StreamNode->Children);
- ChildNode = CHILD_SECTION_NODE_FROM_LINK (Link);
- FreeChildNode (ChildNode);
- }
-
- if (FreeStreamBuffer) {
- CoreFreePool (StreamNode->StreamBuffer);
- }
-
- CoreFreePool (StreamNode);
- Status = EFI_SUCCESS;
- } else {
- Status = EFI_INVALID_PARAMETER;
- }
-
- CoreRestoreTpl (OldTpl);
- return Status;
-}
-
-/**
- The ExtractSection() function processes the input section and
- allocates a buffer from the pool in which it returns the section
- contents. If the section being extracted contains
- authentication information (the section's
- GuidedSectionHeader.Attributes field has the
- EFI_GUIDED_SECTION_AUTH_STATUS_VALID bit set), the values
- returned in AuthenticationStatus must reflect the results of
- the authentication operation. Depending on the algorithm and
- size of the encapsulated data, the time that is required to do
- a full authentication may be prohibitively long for some
- classes of systems. To indicate this, use
- EFI_SECURITY_POLICY_PROTOCOL_GUID, which may be published by
- the security policy driver (see the Platform Initialization
- Driver Execution Environment Core Interface Specification for
- more details and the GUID definition). If the
- EFI_SECURITY_POLICY_PROTOCOL_GUID exists in the handle
- database, then, if possible, full authentication should be
- skipped and the section contents simply returned in the
- OutputBuffer. In this case, the
- EFI_AUTH_STATUS_PLATFORM_OVERRIDE bit AuthenticationStatus
- must be set on return. ExtractSection() is callable only from
- TPL_NOTIFY and below. Behavior of ExtractSection() at any
- EFI_TPL above TPL_NOTIFY is undefined. Type EFI_TPL is
- defined in RaiseTPL() in the UEFI 2.0 specification.
-
-
- @param This Indicates the
- EFI_GUIDED_SECTION_EXTRACTION_PROTOCOL instance.
- @param InputSection Buffer containing the input GUIDed section
- to be processed. OutputBuffer OutputBuffer
- is allocated from boot services pool
- memory and contains the new section
- stream. The caller is responsible for
- freeing this buffer.
- @param OutputBuffer *OutputBuffer is allocated from boot services
- pool memory and contains the new section stream.
- The caller is responsible for freeing this buffer.
- @param OutputSize A pointer to a caller-allocated UINTN in
- which the size of OutputBuffer allocation
- is stored. If the function returns
- anything other than EFI_SUCCESS, the value
- of OutputSize is undefined.
-
- @param AuthenticationStatus A pointer to a caller-allocated
- UINT32 that indicates the
- authentication status of the
- output buffer. If the input
- section's
- GuidedSectionHeader.Attributes
- field has the
- EFI_GUIDED_SECTION_AUTH_STATUS_VAL
- bit as clear, AuthenticationStatus
- must return zero. Both local bits
- (19:16) and aggregate bits (3:0)
- in AuthenticationStatus are
- returned by ExtractSection().
- These bits reflect the status of
- the extraction operation. The bit
- pattern in both regions must be
- the same, as the local and
- aggregate authentication statuses
- have equivalent meaning at this
- level. If the function returns
- anything other than EFI_SUCCESS,
- the value of AuthenticationStatus
- is undefined.
-
-
- @retval EFI_SUCCESS The InputSection was successfully
- processed and the section contents were
- returned.
-
- @retval EFI_OUT_OF_RESOURCES The system has insufficient
- resources to process the
- request.
-
- @retval EFI_INVALID_PARAMETER The GUID in InputSection does
- not match this instance of the
- GUIDed Section Extraction
- Protocol.
-
-**/
-EFI_STATUS
-EFIAPI
-CustomGuidedSectionExtract (
- IN CONST EFI_GUIDED_SECTION_EXTRACTION_PROTOCOL *This,
- IN CONST VOID *InputSection,
- OUT VOID **OutputBuffer,
- OUT UINTN *OutputSize,
- OUT UINT32 *AuthenticationStatus
- )
-{
- EFI_STATUS Status;
- VOID *ScratchBuffer;
- VOID *AllocatedOutputBuffer;
- UINT32 OutputBufferSize;
- UINT32 ScratchBufferSize;
- UINT16 SectionAttribute;
-
- //
- // Init local variable
- //
- ScratchBuffer = NULL;
- AllocatedOutputBuffer = NULL;
-
- //
- // Call GetInfo to get the size and attribute of input guided section data.
- //
- Status = ExtractGuidedSectionGetInfo (
- InputSection,
- &OutputBufferSize,
- &ScratchBufferSize,
- &SectionAttribute
- );
-
- if (EFI_ERROR (Status)) {
- DEBUG ((DEBUG_ERROR, "GetInfo from guided section Failed - %r\n", Status));
- return Status;
- }
-
- if (ScratchBufferSize > 0) {
- //
- // Allocate scratch buffer
- //
- ScratchBuffer = AllocatePool (ScratchBufferSize);
- if (ScratchBuffer == NULL) {
- return EFI_OUT_OF_RESOURCES;
- }
- }
-
- if (OutputBufferSize > 0) {
- //
- // Allocate output buffer
- //
- AllocatedOutputBuffer = AllocatePool (OutputBufferSize);
- if (AllocatedOutputBuffer == NULL) {
- if (ScratchBuffer != NULL) {
- FreePool (ScratchBuffer);
- }
-
- return EFI_OUT_OF_RESOURCES;
- }
-
- *OutputBuffer = AllocatedOutputBuffer;
- }
-
- //
- // Call decode function to extract raw data from the guided section.
- //
- Status = ExtractGuidedSectionDecode (
- InputSection,
- OutputBuffer,
- ScratchBuffer,
- AuthenticationStatus
- );
- if (EFI_ERROR (Status)) {
- //
- // Decode failed
- //
- if (AllocatedOutputBuffer != NULL) {
- CoreFreePool (AllocatedOutputBuffer);
- }
-
- if (ScratchBuffer != NULL) {
- CoreFreePool (ScratchBuffer);
- }
-
- DEBUG ((DEBUG_ERROR, "Extract guided section Failed - %r\n", Status));
- return Status;
- }
-
- if (*OutputBuffer != AllocatedOutputBuffer) {
- //
- // OutputBuffer was returned as a different value,
- // so copy section contents to the allocated memory buffer.
- //
- CopyMem (AllocatedOutputBuffer, *OutputBuffer, OutputBufferSize);
- *OutputBuffer = AllocatedOutputBuffer;
- }
-
- //
- // Set real size of output buffer.
- //
- *OutputSize = (UINTN)OutputBufferSize;
-
- //
- // Free unused scratch buffer.
- //
- if (ScratchBuffer != NULL) {
- CoreFreePool (ScratchBuffer);
- }
-
- return EFI_SUCCESS;
-}
+/** @file
+ Section Extraction Protocol implementation.
+
+ Stream database is implemented as a linked list of section streams,
+ where each stream contains a linked list of children, which may be leaves or
+ encapsulations.
+
+ Children that are encapsulations generate new stream entries
+ when they are created. Streams can also be created by calls to
+ SEP->OpenSectionStream().
+
+ The database is only created far enough to return the requested data from
+ any given stream, or to determine that the requested data is not found.
+
+ If a GUIDed encapsulation is encountered, there are three possiblilites.
+
+ 1) A support protocol is found, in which the stream is simply processed with
+ the support protocol.
+
+ 2) A support protocol is not found, but the data is available to be read
+ without processing. In this case, the database is built up through the
+ recursions to return the data, and a RPN event is set that will enable
+ the stream in question to be refreshed if and when the required section
+ extraction protocol is published.This insures the AuthenticationStatus
+ does not become stale in the cache.
+
+ 3) A support protocol is not found, and the data is not available to be read
+ without it. This results in EFI_PROTOCOL_ERROR.
+
+Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "DxeMain.h"
+
+//
+// Local defines and typedefs
+//
+#define CORE_SECTION_CHILD_SIGNATURE SIGNATURE_32('S','X','C','S')
+#define CHILD_SECTION_NODE_FROM_LINK(Node) \
+ CR (Node, CORE_SECTION_CHILD_NODE, Link, CORE_SECTION_CHILD_SIGNATURE)
+
+typedef struct {
+ UINT32 Signature;
+ LIST_ENTRY Link;
+ UINT32 Type;
+ UINT32 Size;
+ //
+ // StreamBase + OffsetInStream == pointer to section header in stream. The
+ // stream base is always known when walking the sections within.
+ //
+ UINT32 OffsetInStream;
+ //
+ // Then EncapsulatedStreamHandle below is always 0 if the section is NOT an
+ // encapsulating section. Otherwise, it contains the stream handle
+ // of the encapsulated stream. This handle is ALWAYS produced any time an
+ // encapsulating child is encountered, irrespective of whether the
+ // encapsulated stream is processed further.
+ //
+ UINTN EncapsulatedStreamHandle;
+ EFI_GUID *EncapsulationGuid;
+ //
+ // If the section REQUIRES an extraction protocol, register for RPN
+ // when the required GUIDed extraction protocol becomes available.
+ //
+ EFI_EVENT Event;
+} CORE_SECTION_CHILD_NODE;
+
+#define CORE_SECTION_STREAM_SIGNATURE SIGNATURE_32('S','X','S','S')
+#define STREAM_NODE_FROM_LINK(Node) \
+ CR (Node, CORE_SECTION_STREAM_NODE, Link, CORE_SECTION_STREAM_SIGNATURE)
+
+typedef struct {
+ UINT32 Signature;
+ LIST_ENTRY Link;
+ UINTN StreamHandle;
+ UINT8 *StreamBuffer;
+ UINTN StreamLength;
+ LIST_ENTRY Children;
+ //
+ // Authentication status is from GUIDed encapsulations.
+ //
+ UINT32 AuthenticationStatus;
+} CORE_SECTION_STREAM_NODE;
+
+#define NULL_STREAM_HANDLE 0
+
+typedef struct {
+ CORE_SECTION_CHILD_NODE *ChildNode;
+ CORE_SECTION_STREAM_NODE *ParentStream;
+ VOID *Registration;
+} RPN_EVENT_CONTEXT;
+
+/**
+ The ExtractSection() function processes the input section and
+ allocates a buffer from the pool in which it returns the section
+ contents. If the section being extracted contains
+ authentication information (the section's
+ GuidedSectionHeader.Attributes field has the
+ EFI_GUIDED_SECTION_AUTH_STATUS_VALID bit set), the values
+ returned in AuthenticationStatus must reflect the results of
+ the authentication operation. Depending on the algorithm and
+ size of the encapsulated data, the time that is required to do
+ a full authentication may be prohibitively long for some
+ classes of systems. To indicate this, use
+ EFI_SECURITY_POLICY_PROTOCOL_GUID, which may be published by
+ the security policy driver (see the Platform Initialization
+ Driver Execution Environment Core Interface Specification for
+ more details and the GUID definition). If the
+ EFI_SECURITY_POLICY_PROTOCOL_GUID exists in the handle
+ database, then, if possible, full authentication should be
+ skipped and the section contents simply returned in the
+ OutputBuffer. In this case, the
+ EFI_AUTH_STATUS_PLATFORM_OVERRIDE bit AuthenticationStatus
+ must be set on return. ExtractSection() is callable only from
+ TPL_NOTIFY and below. Behavior of ExtractSection() at any
+ EFI_TPL above TPL_NOTIFY is undefined. Type EFI_TPL is
+ defined in RaiseTPL() in the UEFI 2.0 specification.
+
+
+ @param This Indicates the
+ EFI_GUIDED_SECTION_EXTRACTION_PROTOCOL instance.
+ @param InputSection Buffer containing the input GUIDed section
+ to be processed. OutputBuffer OutputBuffer
+ is allocated from boot services pool
+ memory and contains the new section
+ stream. The caller is responsible for
+ freeing this buffer.
+ @param OutputBuffer *OutputBuffer is allocated from boot services
+ pool memory and contains the new section stream.
+ The caller is responsible for freeing this buffer.
+ @param OutputSize A pointer to a caller-allocated UINTN in
+ which the size of OutputBuffer allocation
+ is stored. If the function returns
+ anything other than EFI_SUCCESS, the value
+ of OutputSize is undefined.
+
+ @param AuthenticationStatus A pointer to a caller-allocated
+ UINT32 that indicates the
+ authentication status of the
+ output buffer. If the input
+ section's
+ GuidedSectionHeader.Attributes
+ field has the
+ EFI_GUIDED_SECTION_AUTH_STATUS_VAL
+ bit as clear, AuthenticationStatus
+ must return zero. Both local bits
+ (19:16) and aggregate bits (3:0)
+ in AuthenticationStatus are
+ returned by ExtractSection().
+ These bits reflect the status of
+ the extraction operation. The bit
+ pattern in both regions must be
+ the same, as the local and
+ aggregate authentication statuses
+ have equivalent meaning at this
+ level. If the function returns
+ anything other than EFI_SUCCESS,
+ the value of AuthenticationStatus
+ is undefined.
+
+
+ @retval EFI_SUCCESS The InputSection was successfully
+ processed and the section contents were
+ returned.
+
+ @retval EFI_OUT_OF_RESOURCES The system has insufficient
+ resources to process the
+ request.
+
+ @retval EFI_INVALID_PARAMETER The GUID in InputSection does
+ not match this instance of the
+ GUIDed Section Extraction
+ Protocol.
+
+**/
+EFI_STATUS
+EFIAPI
+CustomGuidedSectionExtract (
+ IN CONST EFI_GUIDED_SECTION_EXTRACTION_PROTOCOL *This,
+ IN CONST VOID *InputSection,
+ OUT VOID **OutputBuffer,
+ OUT UINTN *OutputSize,
+ OUT UINT32 *AuthenticationStatus
+ );
+
+//
+// Module globals
+//
+LIST_ENTRY mStreamRoot = INITIALIZE_LIST_HEAD_VARIABLE (mStreamRoot);
+
+EFI_HANDLE mSectionExtractionHandle = NULL;
+
+EFI_GUIDED_SECTION_EXTRACTION_PROTOCOL mCustomGuidedSectionExtractionProtocol = {
+ CustomGuidedSectionExtract
+};
+
+/**
+ Entry point of the section extraction code. Initializes an instance of the
+ section extraction interface and installs it on a new handle.
+
+ @param ImageHandle A handle for the image that is initializing this driver
+ @param SystemTable A pointer to the EFI system table
+
+ @retval EFI_SUCCESS Driver initialized successfully
+ @retval EFI_OUT_OF_RESOURCES Could not allocate needed resources
+
+**/
+EFI_STATUS
+EFIAPI
+InitializeSectionExtraction (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+ EFI_GUID *ExtractHandlerGuidTable;
+ UINTN ExtractHandlerNumber;
+
+ //
+ // Get custom extract guided section method guid list
+ //
+ ExtractHandlerNumber = ExtractGuidedSectionGetGuidList (&ExtractHandlerGuidTable);
+
+ Status = EFI_SUCCESS;
+ //
+ // Install custom guided extraction protocol
+ //
+ while (ExtractHandlerNumber-- > 0) {
+ Status = CoreInstallProtocolInterface (
+ &mSectionExtractionHandle,
+ &ExtractHandlerGuidTable[ExtractHandlerNumber],
+ EFI_NATIVE_INTERFACE,
+ &mCustomGuidedSectionExtractionProtocol
+ );
+ ASSERT_EFI_ERROR (Status);
+ }
+
+ return Status;
+}
+
+/**
+ Check if a stream is valid.
+
+ @param SectionStream The section stream to be checked
+ @param SectionStreamLength The length of section stream
+
+ @return A boolean value indicating the validness of the section stream.
+
+**/
+BOOLEAN
+IsValidSectionStream (
+ IN VOID *SectionStream,
+ IN UINTN SectionStreamLength
+ )
+{
+ UINTN TotalLength;
+ UINTN SectionLength;
+ EFI_COMMON_SECTION_HEADER *SectionHeader;
+ EFI_COMMON_SECTION_HEADER *NextSectionHeader;
+
+ TotalLength = 0;
+ SectionHeader = (EFI_COMMON_SECTION_HEADER *)SectionStream;
+
+ while (TotalLength < SectionStreamLength) {
+ if (IS_SECTION2 (SectionHeader)) {
+ SectionLength = SECTION2_SIZE (SectionHeader);
+ } else {
+ SectionLength = SECTION_SIZE (SectionHeader);
+ }
+
+ TotalLength += SectionLength;
+
+ if (TotalLength == SectionStreamLength) {
+ return TRUE;
+ }
+
+ //
+ // Move to the next byte following the section...
+ //
+ SectionHeader = (EFI_COMMON_SECTION_HEADER *)((UINT8 *)SectionHeader + SectionLength);
+
+ //
+ // Figure out where the next section begins
+ //
+ NextSectionHeader = ALIGN_POINTER (SectionHeader, 4);
+ TotalLength += (UINTN)NextSectionHeader - (UINTN)SectionHeader;
+ SectionHeader = NextSectionHeader;
+ }
+
+ ASSERT (FALSE);
+ return FALSE;
+}
+
+/**
+ Worker function. Constructor for section streams.
+
+ @param SectionStreamLength Size in bytes of the section stream.
+ @param SectionStream Buffer containing the new section stream.
+ @param AllocateBuffer Indicates whether the stream buffer is to be
+ copied or the input buffer is to be used in
+ place. AuthenticationStatus- Indicates the
+ default authentication status for the new
+ stream.
+ @param AuthenticationStatus A pointer to a caller-allocated UINT32 that
+ indicates the authentication status of the
+ output buffer. If the input section's
+ GuidedSectionHeader.Attributes field
+ has the EFI_GUIDED_SECTION_AUTH_STATUS_VALID
+ bit as clear, AuthenticationStatus must return
+ zero. Both local bits (19:16) and aggregate
+ bits (3:0) in AuthenticationStatus are returned
+ by ExtractSection(). These bits reflect the
+ status of the extraction operation. The bit
+ pattern in both regions must be the same, as
+ the local and aggregate authentication statuses
+ have equivalent meaning at this level. If the
+ function returns anything other than
+ EFI_SUCCESS, the value of *AuthenticationStatus
+ is undefined.
+ @param SectionStreamHandle A pointer to a caller allocated section stream
+ handle.
+
+ @retval EFI_SUCCESS Stream was added to stream database.
+ @retval EFI_OUT_OF_RESOURCES memory allocation failed.
+
+**/
+EFI_STATUS
+OpenSectionStreamEx (
+ IN UINTN SectionStreamLength,
+ IN VOID *SectionStream,
+ IN BOOLEAN AllocateBuffer,
+ IN UINT32 AuthenticationStatus,
+ OUT UINTN *SectionStreamHandle
+ )
+{
+ CORE_SECTION_STREAM_NODE *NewStream;
+ EFI_TPL OldTpl;
+
+ //
+ // Allocate a new stream
+ //
+ NewStream = AllocatePool (sizeof (CORE_SECTION_STREAM_NODE));
+ if (NewStream == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ if (AllocateBuffer) {
+ //
+ // if we're here, we're double buffering, allocate the buffer and copy the
+ // data in
+ //
+ if (SectionStreamLength > 0) {
+ NewStream->StreamBuffer = AllocatePool (SectionStreamLength);
+ if (NewStream->StreamBuffer == NULL) {
+ CoreFreePool (NewStream);
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ //
+ // Copy in stream data
+ //
+ CopyMem (NewStream->StreamBuffer, SectionStream, SectionStreamLength);
+ } else {
+ //
+ // It's possible to have a zero length section stream.
+ //
+ NewStream->StreamBuffer = NULL;
+ }
+ } else {
+ //
+ // If were here, the caller has supplied the buffer (it's an internal call)
+ // so just assign the buffer. This happens when we open section streams
+ // as a result of expanding an encapsulating section.
+ //
+ NewStream->StreamBuffer = SectionStream;
+ }
+
+ //
+ // Initialize the rest of the section stream
+ //
+ NewStream->Signature = CORE_SECTION_STREAM_SIGNATURE;
+ NewStream->StreamHandle = (UINTN)NewStream;
+ NewStream->StreamLength = SectionStreamLength;
+ InitializeListHead (&NewStream->Children);
+ NewStream->AuthenticationStatus = AuthenticationStatus;
+
+ //
+ // Add new stream to stream list
+ //
+ OldTpl = CoreRaiseTpl (TPL_NOTIFY);
+ InsertTailList (&mStreamRoot, &NewStream->Link);
+ CoreRestoreTpl (OldTpl);
+
+ *SectionStreamHandle = NewStream->StreamHandle;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ SEP member function. This function creates and returns a new section stream
+ handle to represent the new section stream.
+
+ @param SectionStreamLength Size in bytes of the section stream.
+ @param SectionStream Buffer containing the new section stream.
+ @param SectionStreamHandle A pointer to a caller allocated UINTN that on
+ output contains the new section stream handle.
+
+ @retval EFI_SUCCESS The section stream is created successfully.
+ @retval EFI_OUT_OF_RESOURCES memory allocation failed.
+ @retval EFI_INVALID_PARAMETER Section stream does not end concident with end
+ of last section.
+
+**/
+EFI_STATUS
+EFIAPI
+OpenSectionStream (
+ IN UINTN SectionStreamLength,
+ IN VOID *SectionStream,
+ OUT UINTN *SectionStreamHandle
+ )
+{
+ //
+ // Check to see section stream looks good...
+ //
+ if (!IsValidSectionStream (SectionStream, SectionStreamLength)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ return OpenSectionStreamEx (
+ SectionStreamLength,
+ SectionStream,
+ FALSE,
+ 0,
+ SectionStreamHandle
+ );
+}
+
+/**
+ Worker function. Determine if the input stream:child matches the input type.
+
+ @param Stream Indicates the section stream associated with the
+ child
+ @param Child Indicates the child to check
+ @param SearchType Indicates the type of section to check against
+ for
+ @param SectionDefinitionGuid Indicates the GUID to check against if the type
+ is EFI_SECTION_GUID_DEFINED
+
+ @retval TRUE The child matches
+ @retval FALSE The child doesn't match
+
+**/
+BOOLEAN
+ChildIsType (
+ IN CORE_SECTION_STREAM_NODE *Stream,
+ IN CORE_SECTION_CHILD_NODE *Child,
+ IN EFI_SECTION_TYPE SearchType,
+ IN EFI_GUID *SectionDefinitionGuid
+ )
+{
+ EFI_GUID_DEFINED_SECTION *GuidedSection;
+
+ if (SearchType == EFI_SECTION_ALL) {
+ return TRUE;
+ }
+
+ if (Child->Type != SearchType) {
+ return FALSE;
+ }
+
+ if ((SearchType != EFI_SECTION_GUID_DEFINED) || (SectionDefinitionGuid == NULL)) {
+ return TRUE;
+ }
+
+ GuidedSection = (EFI_GUID_DEFINED_SECTION *)(Stream->StreamBuffer + Child->OffsetInStream);
+ if (IS_SECTION2 (GuidedSection)) {
+ return CompareGuid (&(((EFI_GUID_DEFINED_SECTION2 *)GuidedSection)->SectionDefinitionGuid), SectionDefinitionGuid);
+ } else {
+ return CompareGuid (&GuidedSection->SectionDefinitionGuid, SectionDefinitionGuid);
+ }
+}
+
+/**
+ Verify the Guided Section GUID by checking if there is the Guided Section GUID configuration table recorded the GUID itself.
+
+ @param GuidedSectionGuid The Guided Section GUID.
+ @param GuidedSectionExtraction A pointer to the pointer to the supported Guided Section Extraction Protocol
+ for the Guided Section.
+
+ @return TRUE The GuidedSectionGuid could be identified, and the pointer to
+ the Guided Section Extraction Protocol will be returned to *GuidedSectionExtraction.
+ @return FALSE The GuidedSectionGuid could not be identified, or
+ the Guided Section Extraction Protocol has not been installed yet.
+
+**/
+BOOLEAN
+VerifyGuidedSectionGuid (
+ IN EFI_GUID *GuidedSectionGuid,
+ OUT EFI_GUIDED_SECTION_EXTRACTION_PROTOCOL **GuidedSectionExtraction
+ )
+{
+ EFI_GUID *GuidRecorded;
+ VOID *Interface;
+ EFI_STATUS Status;
+
+ Interface = NULL;
+
+ //
+ // Check if there is the Guided Section GUID configuration table recorded the GUID itself.
+ //
+ Status = EfiGetSystemConfigurationTable (GuidedSectionGuid, (VOID **)&GuidRecorded);
+ if (Status == EFI_SUCCESS) {
+ if (CompareGuid (GuidRecorded, GuidedSectionGuid)) {
+ //
+ // Found the recorded GuidedSectionGuid.
+ //
+ Status = CoreLocateProtocol (GuidedSectionGuid, NULL, (VOID **)&Interface);
+ if (!EFI_ERROR (Status) && (Interface != NULL)) {
+ //
+ // Found the supported Guided Section Extraction Porotocol for the Guided Section.
+ //
+ *GuidedSectionExtraction = (EFI_GUIDED_SECTION_EXTRACTION_PROTOCOL *)Interface;
+ return TRUE;
+ }
+
+ return FALSE;
+ }
+ }
+
+ return FALSE;
+}
+
+/**
+ RPN callback function. Initializes the section stream
+ when GUIDED_SECTION_EXTRACTION_PROTOCOL is installed.
+
+ @param Event The event that fired
+ @param RpnContext A pointer to the context that allows us to identify
+ the relevent encapsulation.
+**/
+VOID
+EFIAPI
+NotifyGuidedExtraction (
+ IN EFI_EVENT Event,
+ IN VOID *RpnContext
+ )
+{
+ EFI_STATUS Status;
+ EFI_GUID_DEFINED_SECTION *GuidedHeader;
+ EFI_GUIDED_SECTION_EXTRACTION_PROTOCOL *GuidedExtraction;
+ VOID *NewStreamBuffer;
+ UINTN NewStreamBufferSize;
+ UINT32 AuthenticationStatus;
+ RPN_EVENT_CONTEXT *Context;
+
+ Context = RpnContext;
+
+ GuidedHeader = (EFI_GUID_DEFINED_SECTION *)(Context->ParentStream->StreamBuffer + Context->ChildNode->OffsetInStream);
+ ASSERT (GuidedHeader->CommonHeader.Type == EFI_SECTION_GUID_DEFINED);
+
+ if (!VerifyGuidedSectionGuid (Context->ChildNode->EncapsulationGuid, &GuidedExtraction)) {
+ return;
+ }
+
+ Status = GuidedExtraction->ExtractSection (
+ GuidedExtraction,
+ GuidedHeader,
+ &NewStreamBuffer,
+ &NewStreamBufferSize,
+ &AuthenticationStatus
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Make sure we initialize the new stream with the correct
+ // authentication status for both aggregate and local status fields.
+ //
+ if ((GuidedHeader->Attributes & EFI_GUIDED_SECTION_AUTH_STATUS_VALID) != 0) {
+ //
+ // OR in the parent stream's aggregate status.
+ //
+ AuthenticationStatus |= Context->ParentStream->AuthenticationStatus & EFI_AUTH_STATUS_ALL;
+ } else {
+ //
+ // since there's no authentication data contributed by the section,
+ // just inherit the full value from our immediate parent.
+ //
+ AuthenticationStatus = Context->ParentStream->AuthenticationStatus;
+ }
+
+ Status = OpenSectionStreamEx (
+ NewStreamBufferSize,
+ NewStreamBuffer,
+ FALSE,
+ AuthenticationStatus,
+ &Context->ChildNode->EncapsulatedStreamHandle
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Close the event when done.
+ //
+ gBS->CloseEvent (Event);
+ Context->ChildNode->Event = NULL;
+ FreePool (Context);
+}
+
+/**
+ Constructor for RPN event when a missing GUIDED_SECTION_EXTRACTION_PROTOCOL appears...
+
+ @param ParentStream Indicates the parent of the ecnapsulation section (child)
+ @param ChildNode Indicates the child node that is the encapsulation section.
+
+**/
+VOID
+CreateGuidedExtractionRpnEvent (
+ IN CORE_SECTION_STREAM_NODE *ParentStream,
+ IN CORE_SECTION_CHILD_NODE *ChildNode
+ )
+{
+ RPN_EVENT_CONTEXT *Context;
+
+ //
+ // Allocate new event structure and context
+ //
+ Context = AllocatePool (sizeof (RPN_EVENT_CONTEXT));
+ ASSERT (Context != NULL);
+
+ Context->ChildNode = ChildNode;
+ Context->ParentStream = ParentStream;
+
+ Context->ChildNode->Event = EfiCreateProtocolNotifyEvent (
+ Context->ChildNode->EncapsulationGuid,
+ TPL_NOTIFY,
+ NotifyGuidedExtraction,
+ Context,
+ &Context->Registration
+ );
+}
+
+/**
+ Worker function. Constructor for new child nodes.
+
+ @param Stream Indicates the section stream in which to add the
+ child.
+ @param ChildOffset Indicates the offset in Stream that is the
+ beginning of the child section.
+ @param ChildNode Indicates the Callee allocated and initialized
+ child.
+
+ @retval EFI_SUCCESS Child node was found and returned.
+ EFI_OUT_OF_RESOURCES- Memory allocation failed.
+ @retval EFI_PROTOCOL_ERROR Encapsulation sections produce new stream
+ handles when the child node is created. If the
+ section type is GUID defined, and the extraction
+ GUID does not exist, and producing the stream
+ requires the GUID, then a protocol error is
+ generated and no child is produced. Values
+ returned by OpenSectionStreamEx.
+
+**/
+EFI_STATUS
+CreateChildNode (
+ IN CORE_SECTION_STREAM_NODE *Stream,
+ IN UINT32 ChildOffset,
+ OUT CORE_SECTION_CHILD_NODE **ChildNode
+ )
+{
+ EFI_STATUS Status;
+ EFI_COMMON_SECTION_HEADER *SectionHeader;
+ EFI_COMPRESSION_SECTION *CompressionHeader;
+ EFI_GUID_DEFINED_SECTION *GuidedHeader;
+ EFI_DECOMPRESS_PROTOCOL *Decompress;
+ EFI_GUIDED_SECTION_EXTRACTION_PROTOCOL *GuidedExtraction;
+ VOID *NewStreamBuffer;
+ VOID *ScratchBuffer;
+ UINT32 ScratchSize;
+ UINTN NewStreamBufferSize;
+ UINT32 AuthenticationStatus;
+ VOID *CompressionSource;
+ UINT32 CompressionSourceSize;
+ UINT32 UncompressedLength;
+ UINT8 CompressionType;
+ UINT16 GuidedSectionAttributes;
+
+ CORE_SECTION_CHILD_NODE *Node;
+
+ SectionHeader = (EFI_COMMON_SECTION_HEADER *)(Stream->StreamBuffer + ChildOffset);
+
+ //
+ // Allocate a new node
+ //
+ *ChildNode = AllocateZeroPool (sizeof (CORE_SECTION_CHILD_NODE));
+ Node = *ChildNode;
+ if (Node == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ //
+ // Now initialize it
+ //
+ Node->Signature = CORE_SECTION_CHILD_SIGNATURE;
+ Node->Type = SectionHeader->Type;
+ if (IS_SECTION2 (SectionHeader)) {
+ Node->Size = SECTION2_SIZE (SectionHeader);
+ } else {
+ Node->Size = SECTION_SIZE (SectionHeader);
+ }
+
+ Node->OffsetInStream = ChildOffset;
+ Node->EncapsulatedStreamHandle = NULL_STREAM_HANDLE;
+ Node->EncapsulationGuid = NULL;
+
+ //
+ // If it's an encapsulating section, then create the new section stream also
+ //
+ switch (Node->Type) {
+ case EFI_SECTION_COMPRESSION:
+ //
+ // Get the CompressionSectionHeader
+ //
+ if (Node->Size < sizeof (EFI_COMPRESSION_SECTION)) {
+ CoreFreePool (Node);
+ return EFI_NOT_FOUND;
+ }
+
+ CompressionHeader = (EFI_COMPRESSION_SECTION *)SectionHeader;
+
+ if (IS_SECTION2 (CompressionHeader)) {
+ CompressionSource = (VOID *)((UINT8 *)CompressionHeader + sizeof (EFI_COMPRESSION_SECTION2));
+ CompressionSourceSize = (UINT32)(SECTION2_SIZE (CompressionHeader) - sizeof (EFI_COMPRESSION_SECTION2));
+ UncompressedLength = ((EFI_COMPRESSION_SECTION2 *)CompressionHeader)->UncompressedLength;
+ CompressionType = ((EFI_COMPRESSION_SECTION2 *)CompressionHeader)->CompressionType;
+ } else {
+ CompressionSource = (VOID *)((UINT8 *)CompressionHeader + sizeof (EFI_COMPRESSION_SECTION));
+ CompressionSourceSize = (UINT32)(SECTION_SIZE (CompressionHeader) - sizeof (EFI_COMPRESSION_SECTION));
+ UncompressedLength = CompressionHeader->UncompressedLength;
+ CompressionType = CompressionHeader->CompressionType;
+ }
+
+ //
+ // Allocate space for the new stream
+ //
+ if (UncompressedLength > 0) {
+ NewStreamBufferSize = UncompressedLength;
+ NewStreamBuffer = AllocatePool (NewStreamBufferSize);
+ if (NewStreamBuffer == NULL) {
+ CoreFreePool (Node);
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ if (CompressionType == EFI_NOT_COMPRESSED) {
+ //
+ // stream is not actually compressed, just encapsulated. So just copy it.
+ //
+ CopyMem (NewStreamBuffer, CompressionSource, NewStreamBufferSize);
+ } else if (CompressionType == EFI_STANDARD_COMPRESSION) {
+ //
+ // Only support the EFI_SATNDARD_COMPRESSION algorithm.
+ //
+
+ //
+ // Decompress the stream
+ //
+ Status = CoreLocateProtocol (&gEfiDecompressProtocolGuid, NULL, (VOID **)&Decompress);
+ ASSERT_EFI_ERROR (Status);
+ ASSERT (Decompress != NULL);
+
+ Status = Decompress->GetInfo (
+ Decompress,
+ CompressionSource,
+ CompressionSourceSize,
+ (UINT32 *)&NewStreamBufferSize,
+ &ScratchSize
+ );
+ if (EFI_ERROR (Status) || (NewStreamBufferSize != UncompressedLength)) {
+ CoreFreePool (Node);
+ CoreFreePool (NewStreamBuffer);
+ if (!EFI_ERROR (Status)) {
+ Status = EFI_BAD_BUFFER_SIZE;
+ }
+
+ return Status;
+ }
+
+ ScratchBuffer = AllocatePool (ScratchSize);
+ if (ScratchBuffer == NULL) {
+ CoreFreePool (Node);
+ CoreFreePool (NewStreamBuffer);
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ Status = Decompress->Decompress (
+ Decompress,
+ CompressionSource,
+ CompressionSourceSize,
+ NewStreamBuffer,
+ (UINT32)NewStreamBufferSize,
+ ScratchBuffer,
+ ScratchSize
+ );
+ CoreFreePool (ScratchBuffer);
+ if (EFI_ERROR (Status)) {
+ CoreFreePool (Node);
+ CoreFreePool (NewStreamBuffer);
+ return Status;
+ }
+ }
+ } else {
+ NewStreamBuffer = NULL;
+ NewStreamBufferSize = 0;
+ }
+
+ Status = OpenSectionStreamEx (
+ NewStreamBufferSize,
+ NewStreamBuffer,
+ FALSE,
+ Stream->AuthenticationStatus,
+ &Node->EncapsulatedStreamHandle
+ );
+ if (EFI_ERROR (Status)) {
+ CoreFreePool (Node);
+ CoreFreePool (NewStreamBuffer);
+ return Status;
+ }
+
+ break;
+
+ case EFI_SECTION_GUID_DEFINED:
+ GuidedHeader = (EFI_GUID_DEFINED_SECTION *)SectionHeader;
+ if (IS_SECTION2 (GuidedHeader)) {
+ Node->EncapsulationGuid = &(((EFI_GUID_DEFINED_SECTION2 *)GuidedHeader)->SectionDefinitionGuid);
+ GuidedSectionAttributes = ((EFI_GUID_DEFINED_SECTION2 *)GuidedHeader)->Attributes;
+ } else {
+ Node->EncapsulationGuid = &GuidedHeader->SectionDefinitionGuid;
+ GuidedSectionAttributes = GuidedHeader->Attributes;
+ }
+
+ if (VerifyGuidedSectionGuid (Node->EncapsulationGuid, &GuidedExtraction)) {
+ //
+ // NewStreamBuffer is always allocated by ExtractSection... No caller
+ // allocation here.
+ //
+ Status = GuidedExtraction->ExtractSection (
+ GuidedExtraction,
+ GuidedHeader,
+ &NewStreamBuffer,
+ &NewStreamBufferSize,
+ &AuthenticationStatus
+ );
+ if (EFI_ERROR (Status)) {
+ CoreFreePool (*ChildNode);
+ return EFI_PROTOCOL_ERROR;
+ }
+
+ //
+ // Make sure we initialize the new stream with the correct
+ // authentication status for both aggregate and local status fields.
+ //
+ if ((GuidedSectionAttributes & EFI_GUIDED_SECTION_AUTH_STATUS_VALID) != 0) {
+ //
+ // OR in the parent stream's aggregate status.
+ //
+ AuthenticationStatus |= Stream->AuthenticationStatus & EFI_AUTH_STATUS_ALL;
+ } else {
+ //
+ // since there's no authentication data contributed by the section,
+ // just inherit the full value from our immediate parent.
+ //
+ AuthenticationStatus = Stream->AuthenticationStatus;
+ }
+
+ Status = OpenSectionStreamEx (
+ NewStreamBufferSize,
+ NewStreamBuffer,
+ FALSE,
+ AuthenticationStatus,
+ &Node->EncapsulatedStreamHandle
+ );
+ if (EFI_ERROR (Status)) {
+ CoreFreePool (*ChildNode);
+ CoreFreePool (NewStreamBuffer);
+ return Status;
+ }
+ } else {
+ //
+ // There's no GUIDed section extraction protocol available.
+ //
+ if ((GuidedSectionAttributes & EFI_GUIDED_SECTION_PROCESSING_REQUIRED) != 0) {
+ //
+ // If the section REQUIRES an extraction protocol, register for RPN
+ // when the required GUIDed extraction protocol becomes available.
+ //
+ CreateGuidedExtractionRpnEvent (Stream, Node);
+ } else {
+ //
+ // Figure out the proper authentication status
+ //
+ AuthenticationStatus = Stream->AuthenticationStatus;
+
+ if ((GuidedSectionAttributes & EFI_GUIDED_SECTION_AUTH_STATUS_VALID) == EFI_GUIDED_SECTION_AUTH_STATUS_VALID) {
+ AuthenticationStatus |= EFI_AUTH_STATUS_IMAGE_SIGNED | EFI_AUTH_STATUS_NOT_TESTED;
+ }
+
+ if (IS_SECTION2 (GuidedHeader)) {
+ Status = OpenSectionStreamEx (
+ SECTION2_SIZE (GuidedHeader) - ((EFI_GUID_DEFINED_SECTION2 *)GuidedHeader)->DataOffset,
+ (UINT8 *)GuidedHeader + ((EFI_GUID_DEFINED_SECTION2 *)GuidedHeader)->DataOffset,
+ TRUE,
+ AuthenticationStatus,
+ &Node->EncapsulatedStreamHandle
+ );
+ } else {
+ Status = OpenSectionStreamEx (
+ SECTION_SIZE (GuidedHeader) - ((EFI_GUID_DEFINED_SECTION *)GuidedHeader)->DataOffset,
+ (UINT8 *)GuidedHeader + ((EFI_GUID_DEFINED_SECTION *)GuidedHeader)->DataOffset,
+ TRUE,
+ AuthenticationStatus,
+ &Node->EncapsulatedStreamHandle
+ );
+ }
+
+ if (EFI_ERROR (Status)) {
+ CoreFreePool (Node);
+ return Status;
+ }
+ }
+ }
+
+ break;
+
+ default:
+
+ //
+ // Nothing to do if it's a leaf
+ //
+ break;
+ }
+
+ //
+ // Last, add the new child node to the stream
+ //
+ InsertTailList (&Stream->Children, &Node->Link);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Worker function Recursively searches / builds section stream database
+ looking for requested section.
+
+ @param SourceStream Indicates the section stream in which to do the
+ search.
+ @param SearchType Indicates the type of section to search for.
+ @param SectionInstance Indicates which instance of section to find.
+ This is an in/out parameter and it is 1-based,
+ to deal with recursions.
+ @param SectionDefinitionGuid Guid of section definition
+ @param Depth Nesting depth of encapsulation sections.
+ Callers different from FindChildNode() are
+ responsible for passing in a zero Depth.
+ @param FoundChild Output indicating the child node that is found.
+ @param FoundStream Output indicating which section stream the child
+ was found in. If this stream was generated as a
+ result of an encapsulation section, the
+ streamhandle is visible within the SEP driver
+ only.
+ @param AuthenticationStatus Indicates the authentication status of the found section.
+
+ @retval EFI_SUCCESS Child node was found and returned.
+ EFI_OUT_OF_RESOURCES- Memory allocation failed.
+ @retval EFI_NOT_FOUND Requested child node does not exist.
+ @retval EFI_PROTOCOL_ERROR a required GUIDED section extraction protocol
+ does not exist
+ @retval EFI_ABORTED Recursion aborted because Depth has been
+ greater than or equal to
+ PcdFwVolDxeMaxEncapsulationDepth.
+
+**/
+EFI_STATUS
+FindChildNode (
+ IN CORE_SECTION_STREAM_NODE *SourceStream,
+ IN EFI_SECTION_TYPE SearchType,
+ IN OUT UINTN *SectionInstance,
+ IN EFI_GUID *SectionDefinitionGuid,
+ IN UINT32 Depth,
+ OUT CORE_SECTION_CHILD_NODE **FoundChild,
+ OUT CORE_SECTION_STREAM_NODE **FoundStream,
+ OUT UINT32 *AuthenticationStatus
+ )
+{
+ CORE_SECTION_CHILD_NODE *CurrentChildNode;
+ CORE_SECTION_CHILD_NODE *RecursedChildNode;
+ CORE_SECTION_STREAM_NODE *RecursedFoundStream;
+ UINT32 NextChildOffset;
+ EFI_STATUS ErrorStatus;
+ EFI_STATUS Status;
+
+ ASSERT (*SectionInstance > 0);
+
+ if (Depth >= PcdGet32 (PcdFwVolDxeMaxEncapsulationDepth)) {
+ return EFI_ABORTED;
+ }
+
+ CurrentChildNode = NULL;
+ ErrorStatus = EFI_NOT_FOUND;
+
+ if (SourceStream->StreamLength == 0) {
+ return EFI_NOT_FOUND;
+ }
+
+ if (IsListEmpty (&SourceStream->Children) &&
+ (SourceStream->StreamLength >= sizeof (EFI_COMMON_SECTION_HEADER)))
+ {
+ //
+ // This occurs when a section stream exists, but no child sections
+ // have been parsed out yet. Therefore, extract the first child and add it
+ // to the list of children so we can get started.
+ // Section stream may contain an array of zero or more bytes.
+ // So, its size should be >= the size of commen section header.
+ //
+ Status = CreateChildNode (SourceStream, 0, &CurrentChildNode);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+
+ //
+ // At least one child has been parsed out of the section stream. So, walk
+ // through the sections that have already been parsed out looking for the
+ // requested section, if necessary, continue parsing section stream and
+ // adding children until either the requested section is found, or we run
+ // out of data
+ //
+ CurrentChildNode = CHILD_SECTION_NODE_FROM_LINK (GetFirstNode (&SourceStream->Children));
+
+ for ( ; ;) {
+ ASSERT (CurrentChildNode != NULL);
+ if (ChildIsType (SourceStream, CurrentChildNode, SearchType, SectionDefinitionGuid)) {
+ //
+ // The type matches, so check the instance count to see if it's the one we want
+ //
+ (*SectionInstance)--;
+ if (*SectionInstance == 0) {
+ //
+ // Got it!
+ //
+ *FoundChild = CurrentChildNode;
+ *FoundStream = SourceStream;
+ *AuthenticationStatus = SourceStream->AuthenticationStatus;
+ return EFI_SUCCESS;
+ }
+ }
+
+ //
+ // Type mismatch, or we haven't found the desired instance yet.
+ //
+ ASSERT (*SectionInstance > 0);
+
+ if (CurrentChildNode->EncapsulatedStreamHandle != NULL_STREAM_HANDLE) {
+ //
+ // If the current node is an encapsulating node, recurse into it...
+ //
+ Status = FindChildNode (
+ (CORE_SECTION_STREAM_NODE *)CurrentChildNode->EncapsulatedStreamHandle,
+ SearchType,
+ SectionInstance,
+ SectionDefinitionGuid,
+ Depth + 1,
+ &RecursedChildNode,
+ &RecursedFoundStream,
+ AuthenticationStatus
+ );
+ if (*SectionInstance == 0) {
+ //
+ // The recursive FindChildNode() call decreased (*SectionInstance) to
+ // zero.
+ //
+ ASSERT_EFI_ERROR (Status);
+ *FoundChild = RecursedChildNode;
+ *FoundStream = RecursedFoundStream;
+ return EFI_SUCCESS;
+ } else {
+ if (Status == EFI_ABORTED) {
+ //
+ // If the recursive call was aborted due to nesting depth, stop
+ // looking for the requested child node. The skipped subtree could
+ // throw off the instance counting.
+ //
+ return Status;
+ }
+
+ //
+ // Save the error code and continue to find the requested child node in
+ // the rest of the stream.
+ //
+ ErrorStatus = Status;
+ }
+ } else if ((CurrentChildNode->Type == EFI_SECTION_GUID_DEFINED) && (SearchType != EFI_SECTION_GUID_DEFINED)) {
+ //
+ // When Node Type is GUIDED section, but Node has no encapsulated data, Node data should not be parsed
+ // because a required GUIDED section extraction protocol does not exist.
+ // If SearchType is not GUIDED section, EFI_PROTOCOL_ERROR should return.
+ //
+ ErrorStatus = EFI_PROTOCOL_ERROR;
+ }
+
+ if (!IsNodeAtEnd (&SourceStream->Children, &CurrentChildNode->Link)) {
+ //
+ // We haven't found the child node we're interested in yet, but there's
+ // still more nodes that have already been parsed so get the next one
+ // and continue searching..
+ //
+ CurrentChildNode = CHILD_SECTION_NODE_FROM_LINK (GetNextNode (&SourceStream->Children, &CurrentChildNode->Link));
+ } else {
+ //
+ // We've exhausted children that have already been parsed, so see if
+ // there's any more data and continue parsing out more children if there
+ // is.
+ //
+ NextChildOffset = CurrentChildNode->OffsetInStream + CurrentChildNode->Size;
+ //
+ // Round up to 4 byte boundary
+ //
+ NextChildOffset += 3;
+ NextChildOffset &= ~(UINTN)3;
+ if (NextChildOffset <= SourceStream->StreamLength - sizeof (EFI_COMMON_SECTION_HEADER)) {
+ //
+ // There's an unparsed child remaining in the stream, so create a new child node
+ //
+ Status = CreateChildNode (SourceStream, NextChildOffset, &CurrentChildNode);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ } else {
+ ASSERT (EFI_ERROR (ErrorStatus));
+ return ErrorStatus;
+ }
+ }
+ }
+}
+
+/**
+ Worker function. Search stream database for requested stream handle.
+
+ @param SearchHandle Indicates which stream to look for.
+ @param FoundStream Output pointer to the found stream.
+
+ @retval EFI_SUCCESS StreamHandle was found and *FoundStream contains
+ the stream node.
+ @retval EFI_NOT_FOUND SearchHandle was not found in the stream
+ database.
+
+**/
+EFI_STATUS
+FindStreamNode (
+ IN UINTN SearchHandle,
+ OUT CORE_SECTION_STREAM_NODE **FoundStream
+ )
+{
+ CORE_SECTION_STREAM_NODE *StreamNode;
+
+ if (!IsListEmpty (&mStreamRoot)) {
+ StreamNode = STREAM_NODE_FROM_LINK (GetFirstNode (&mStreamRoot));
+ for ( ; ;) {
+ if (StreamNode->StreamHandle == SearchHandle) {
+ *FoundStream = StreamNode;
+ return EFI_SUCCESS;
+ } else if (IsNodeAtEnd (&mStreamRoot, &StreamNode->Link)) {
+ break;
+ } else {
+ StreamNode = STREAM_NODE_FROM_LINK (GetNextNode (&mStreamRoot, &StreamNode->Link));
+ }
+ }
+ }
+
+ return EFI_NOT_FOUND;
+}
+
+/**
+ SEP member function. Retrieves requested section from section stream.
+
+ @param SectionStreamHandle The section stream from which to extract the
+ requested section.
+ @param SectionType A pointer to the type of section to search for.
+ @param SectionDefinitionGuid If the section type is EFI_SECTION_GUID_DEFINED,
+ then SectionDefinitionGuid indicates which of
+ these types of sections to search for.
+ @param SectionInstance Indicates which instance of the requested
+ section to return.
+ @param Buffer Double indirection to buffer. If *Buffer is
+ non-null on input, then the buffer is caller
+ allocated. If Buffer is NULL, then the buffer
+ is callee allocated. In either case, the
+ required buffer size is returned in *BufferSize.
+ @param BufferSize On input, indicates the size of *Buffer if
+ *Buffer is non-null on input. On output,
+ indicates the required size (allocated size if
+ callee allocated) of *Buffer.
+ @param AuthenticationStatus A pointer to a caller-allocated UINT32 that
+ indicates the authentication status of the
+ output buffer. If the input section's
+ GuidedSectionHeader.Attributes field
+ has the EFI_GUIDED_SECTION_AUTH_STATUS_VALID
+ bit as clear, AuthenticationStatus must return
+ zero. Both local bits (19:16) and aggregate
+ bits (3:0) in AuthenticationStatus are returned
+ by ExtractSection(). These bits reflect the
+ status of the extraction operation. The bit
+ pattern in both regions must be the same, as
+ the local and aggregate authentication statuses
+ have equivalent meaning at this level. If the
+ function returns anything other than
+ EFI_SUCCESS, the value of *AuthenticationStatus
+ is undefined.
+ @param IsFfs3Fv Indicates the FV format.
+
+ @retval EFI_SUCCESS Section was retrieved successfully
+ @retval EFI_PROTOCOL_ERROR A GUID defined section was encountered in the
+ section stream with its
+ EFI_GUIDED_SECTION_PROCESSING_REQUIRED bit set,
+ but there was no corresponding GUIDed Section
+ Extraction Protocol in the handle database.
+ *Buffer is unmodified.
+ @retval EFI_NOT_FOUND An error was encountered when parsing the
+ SectionStream. This indicates the SectionStream
+ is not correctly formatted.
+ @retval EFI_NOT_FOUND The requested section does not exist.
+ @retval EFI_OUT_OF_RESOURCES The system has insufficient resources to process
+ the request.
+ @retval EFI_INVALID_PARAMETER The SectionStreamHandle does not exist.
+ @retval EFI_WARN_TOO_SMALL The size of the caller allocated input buffer is
+ insufficient to contain the requested section.
+ The input buffer is filled and section contents
+ are truncated.
+
+**/
+EFI_STATUS
+EFIAPI
+GetSection (
+ IN UINTN SectionStreamHandle,
+ IN EFI_SECTION_TYPE *SectionType,
+ IN EFI_GUID *SectionDefinitionGuid,
+ IN UINTN SectionInstance,
+ IN VOID **Buffer,
+ IN OUT UINTN *BufferSize,
+ OUT UINT32 *AuthenticationStatus,
+ IN BOOLEAN IsFfs3Fv
+ )
+{
+ CORE_SECTION_STREAM_NODE *StreamNode;
+ EFI_TPL OldTpl;
+ EFI_STATUS Status;
+ CORE_SECTION_CHILD_NODE *ChildNode;
+ CORE_SECTION_STREAM_NODE *ChildStreamNode;
+ UINTN CopySize;
+ UINT32 ExtractedAuthenticationStatus;
+ UINTN Instance;
+ UINT8 *CopyBuffer;
+ UINTN SectionSize;
+ EFI_COMMON_SECTION_HEADER *Section;
+
+ ChildStreamNode = NULL;
+ OldTpl = CoreRaiseTpl (TPL_NOTIFY);
+ Instance = SectionInstance + 1;
+
+ //
+ // Locate target stream
+ //
+ Status = FindStreamNode (SectionStreamHandle, &StreamNode);
+ if (EFI_ERROR (Status)) {
+ Status = EFI_INVALID_PARAMETER;
+ goto GetSection_Done;
+ }
+
+ //
+ // Found the stream, now locate and return the appropriate section
+ //
+ if (SectionType == NULL) {
+ //
+ // SectionType == NULL means return the WHOLE section stream...
+ //
+ CopySize = StreamNode->StreamLength;
+ CopyBuffer = StreamNode->StreamBuffer;
+ *AuthenticationStatus = StreamNode->AuthenticationStatus;
+ } else {
+ //
+ // There's a requested section type, so go find it and return it...
+ //
+ Status = FindChildNode (
+ StreamNode,
+ *SectionType,
+ &Instance,
+ SectionDefinitionGuid,
+ 0, // encapsulation depth
+ &ChildNode,
+ &ChildStreamNode,
+ &ExtractedAuthenticationStatus
+ );
+ if (EFI_ERROR (Status)) {
+ if (Status == EFI_ABORTED) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "%a: recursion aborted due to nesting depth\n",
+ __func__
+ ));
+ //
+ // Map "aborted" to "not found".
+ //
+ Status = EFI_NOT_FOUND;
+ }
+
+ goto GetSection_Done;
+ }
+
+ Section = (EFI_COMMON_SECTION_HEADER *)(ChildStreamNode->StreamBuffer + ChildNode->OffsetInStream);
+
+ if (IS_SECTION2 (Section)) {
+ ASSERT (SECTION2_SIZE (Section) > 0x00FFFFFF);
+ if (!IsFfs3Fv) {
+ DEBUG ((DEBUG_ERROR, "It is a FFS3 formatted section in a non-FFS3 formatted FV.\n"));
+ Status = EFI_NOT_FOUND;
+ goto GetSection_Done;
+ }
+
+ CopySize = SECTION2_SIZE (Section) - sizeof (EFI_COMMON_SECTION_HEADER2);
+ CopyBuffer = (UINT8 *)Section + sizeof (EFI_COMMON_SECTION_HEADER2);
+ } else {
+ CopySize = SECTION_SIZE (Section) - sizeof (EFI_COMMON_SECTION_HEADER);
+ CopyBuffer = (UINT8 *)Section + sizeof (EFI_COMMON_SECTION_HEADER);
+ }
+
+ *AuthenticationStatus = ExtractedAuthenticationStatus;
+ }
+
+ SectionSize = CopySize;
+ if (*Buffer != NULL) {
+ //
+ // Caller allocated buffer. Fill to size and return required size...
+ //
+ if (*BufferSize < CopySize) {
+ Status = EFI_WARN_BUFFER_TOO_SMALL;
+ CopySize = *BufferSize;
+ }
+ } else {
+ //
+ // Callee allocated buffer. Allocate buffer and return size.
+ //
+ *Buffer = AllocatePool (CopySize);
+ if (*Buffer == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto GetSection_Done;
+ }
+ }
+
+ CopyMem (*Buffer, CopyBuffer, CopySize);
+ *BufferSize = SectionSize;
+
+GetSection_Done:
+ CoreRestoreTpl (OldTpl);
+
+ return Status;
+}
+
+/**
+ Worker function. Destructor for child nodes.
+
+ @param ChildNode Indicates the node to destroy
+
+**/
+VOID
+FreeChildNode (
+ IN CORE_SECTION_CHILD_NODE *ChildNode
+ )
+{
+ ASSERT (ChildNode->Signature == CORE_SECTION_CHILD_SIGNATURE);
+ //
+ // Remove the child from it's list
+ //
+ RemoveEntryList (&ChildNode->Link);
+
+ if (ChildNode->EncapsulatedStreamHandle != NULL_STREAM_HANDLE) {
+ //
+ // If it's an encapsulating section, we close the resulting section stream.
+ // CloseSectionStream will free all memory associated with the stream.
+ //
+ CloseSectionStream (ChildNode->EncapsulatedStreamHandle, TRUE);
+ }
+
+ if (ChildNode->Event != NULL) {
+ gBS->CloseEvent (ChildNode->Event);
+ }
+
+ //
+ // Last, free the child node itself
+ //
+ CoreFreePool (ChildNode);
+}
+
+/**
+ SEP member function. Deletes an existing section stream
+
+ @param StreamHandleToClose Indicates the stream to close
+ @param FreeStreamBuffer TRUE - Need to free stream buffer;
+ FALSE - No need to free stream buffer.
+
+ @retval EFI_SUCCESS The section stream is closed sucessfully.
+ @retval EFI_OUT_OF_RESOURCES Memory allocation failed.
+ @retval EFI_INVALID_PARAMETER Section stream does not end concident with end
+ of last section.
+
+**/
+EFI_STATUS
+EFIAPI
+CloseSectionStream (
+ IN UINTN StreamHandleToClose,
+ IN BOOLEAN FreeStreamBuffer
+ )
+{
+ CORE_SECTION_STREAM_NODE *StreamNode;
+ EFI_TPL OldTpl;
+ EFI_STATUS Status;
+ LIST_ENTRY *Link;
+ CORE_SECTION_CHILD_NODE *ChildNode;
+
+ OldTpl = CoreRaiseTpl (TPL_NOTIFY);
+
+ //
+ // Locate target stream
+ //
+ Status = FindStreamNode (StreamHandleToClose, &StreamNode);
+ if (!EFI_ERROR (Status)) {
+ //
+ // Found the stream, so close it
+ //
+ RemoveEntryList (&StreamNode->Link);
+ while (!IsListEmpty (&StreamNode->Children)) {
+ Link = GetFirstNode (&StreamNode->Children);
+ ChildNode = CHILD_SECTION_NODE_FROM_LINK (Link);
+ FreeChildNode (ChildNode);
+ }
+
+ if (FreeStreamBuffer) {
+ CoreFreePool (StreamNode->StreamBuffer);
+ }
+
+ CoreFreePool (StreamNode);
+ Status = EFI_SUCCESS;
+ } else {
+ Status = EFI_INVALID_PARAMETER;
+ }
+
+ CoreRestoreTpl (OldTpl);
+ return Status;
+}
+
+/**
+ The ExtractSection() function processes the input section and
+ allocates a buffer from the pool in which it returns the section
+ contents. If the section being extracted contains
+ authentication information (the section's
+ GuidedSectionHeader.Attributes field has the
+ EFI_GUIDED_SECTION_AUTH_STATUS_VALID bit set), the values
+ returned in AuthenticationStatus must reflect the results of
+ the authentication operation. Depending on the algorithm and
+ size of the encapsulated data, the time that is required to do
+ a full authentication may be prohibitively long for some
+ classes of systems. To indicate this, use
+ EFI_SECURITY_POLICY_PROTOCOL_GUID, which may be published by
+ the security policy driver (see the Platform Initialization
+ Driver Execution Environment Core Interface Specification for
+ more details and the GUID definition). If the
+ EFI_SECURITY_POLICY_PROTOCOL_GUID exists in the handle
+ database, then, if possible, full authentication should be
+ skipped and the section contents simply returned in the
+ OutputBuffer. In this case, the
+ EFI_AUTH_STATUS_PLATFORM_OVERRIDE bit AuthenticationStatus
+ must be set on return. ExtractSection() is callable only from
+ TPL_NOTIFY and below. Behavior of ExtractSection() at any
+ EFI_TPL above TPL_NOTIFY is undefined. Type EFI_TPL is
+ defined in RaiseTPL() in the UEFI 2.0 specification.
+
+
+ @param This Indicates the
+ EFI_GUIDED_SECTION_EXTRACTION_PROTOCOL instance.
+ @param InputSection Buffer containing the input GUIDed section
+ to be processed. OutputBuffer OutputBuffer
+ is allocated from boot services pool
+ memory and contains the new section
+ stream. The caller is responsible for
+ freeing this buffer.
+ @param OutputBuffer *OutputBuffer is allocated from boot services
+ pool memory and contains the new section stream.
+ The caller is responsible for freeing this buffer.
+ @param OutputSize A pointer to a caller-allocated UINTN in
+ which the size of OutputBuffer allocation
+ is stored. If the function returns
+ anything other than EFI_SUCCESS, the value
+ of OutputSize is undefined.
+
+ @param AuthenticationStatus A pointer to a caller-allocated
+ UINT32 that indicates the
+ authentication status of the
+ output buffer. If the input
+ section's
+ GuidedSectionHeader.Attributes
+ field has the
+ EFI_GUIDED_SECTION_AUTH_STATUS_VAL
+ bit as clear, AuthenticationStatus
+ must return zero. Both local bits
+ (19:16) and aggregate bits (3:0)
+ in AuthenticationStatus are
+ returned by ExtractSection().
+ These bits reflect the status of
+ the extraction operation. The bit
+ pattern in both regions must be
+ the same, as the local and
+ aggregate authentication statuses
+ have equivalent meaning at this
+ level. If the function returns
+ anything other than EFI_SUCCESS,
+ the value of AuthenticationStatus
+ is undefined.
+
+
+ @retval EFI_SUCCESS The InputSection was successfully
+ processed and the section contents were
+ returned.
+
+ @retval EFI_OUT_OF_RESOURCES The system has insufficient
+ resources to process the
+ request.
+
+ @retval EFI_INVALID_PARAMETER The GUID in InputSection does
+ not match this instance of the
+ GUIDed Section Extraction
+ Protocol.
+
+**/
+EFI_STATUS
+EFIAPI
+CustomGuidedSectionExtract (
+ IN CONST EFI_GUIDED_SECTION_EXTRACTION_PROTOCOL *This,
+ IN CONST VOID *InputSection,
+ OUT VOID **OutputBuffer,
+ OUT UINTN *OutputSize,
+ OUT UINT32 *AuthenticationStatus
+ )
+{
+ EFI_STATUS Status;
+ VOID *ScratchBuffer;
+ VOID *AllocatedOutputBuffer;
+ UINT32 OutputBufferSize;
+ UINT32 ScratchBufferSize;
+ UINT16 SectionAttribute;
+
+ //
+ // Init local variable
+ //
+ ScratchBuffer = NULL;
+ AllocatedOutputBuffer = NULL;
+
+ //
+ // Call GetInfo to get the size and attribute of input guided section data.
+ //
+ Status = ExtractGuidedSectionGetInfo (
+ InputSection,
+ &OutputBufferSize,
+ &ScratchBufferSize,
+ &SectionAttribute
+ );
+
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "GetInfo from guided section Failed - %r\n", Status));
+ return Status;
+ }
+
+ if (ScratchBufferSize > 0) {
+ //
+ // Allocate scratch buffer
+ //
+ ScratchBuffer = AllocatePool (ScratchBufferSize);
+ if (ScratchBuffer == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ }
+
+ if (OutputBufferSize > 0) {
+ //
+ // Allocate output buffer
+ //
+ AllocatedOutputBuffer = AllocatePool (OutputBufferSize);
+ if (AllocatedOutputBuffer == NULL) {
+ if (ScratchBuffer != NULL) {
+ FreePool (ScratchBuffer);
+ }
+
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ *OutputBuffer = AllocatedOutputBuffer;
+ }
+
+ //
+ // Call decode function to extract raw data from the guided section.
+ //
+ Status = ExtractGuidedSectionDecode (
+ InputSection,
+ OutputBuffer,
+ ScratchBuffer,
+ AuthenticationStatus
+ );
+ if (EFI_ERROR (Status)) {
+ //
+ // Decode failed
+ //
+ if (AllocatedOutputBuffer != NULL) {
+ CoreFreePool (AllocatedOutputBuffer);
+ }
+
+ if (ScratchBuffer != NULL) {
+ CoreFreePool (ScratchBuffer);
+ }
+
+ DEBUG ((DEBUG_ERROR, "Extract guided section Failed - %r\n", Status));
+ return Status;
+ }
+
+ if (*OutputBuffer != AllocatedOutputBuffer) {
+ //
+ // OutputBuffer was returned as a different value,
+ // so copy section contents to the allocated memory buffer.
+ //
+ CopyMem (AllocatedOutputBuffer, *OutputBuffer, OutputBufferSize);
+ *OutputBuffer = AllocatedOutputBuffer;
+ }
+
+ //
+ // Set real size of output buffer.
+ //
+ *OutputSize = (UINTN)OutputBufferSize;
+
+ //
+ // Free unused scratch buffer.
+ //
+ if (ScratchBuffer != NULL) {
+ CoreFreePool (ScratchBuffer);
+ }
+
+ return EFI_SUCCESS;
+}