diff options
Diffstat (limited to 'MdeModulePkg/Core/Dxe')
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; +} |
