/** The Entry Point for Debug Agent Dxe driver. It will invoke Debug Agent Library to enable source debugging feature in DXE phase. @param[in] ImageHandle The firmware allocated handle for the EFI image. @param[in] SystemTable A pointer to the EFI System Table. @retval EFI_SUCCESS The entry point is executed successfully. @retval other Some error occurs when initialzed Debug Agent. **/ EFI_STATUS EFIAPI DebugAgentDxeInitialize( IN EFI_HANDLE ImageHandle, IN EFI_SYSTEM_TABLE *SystemTable ) { EFI_STATUS Status; Status = EFI_UNSUPPORTED; InitializeDebugAgent (DEBUG_AGENT_INIT_DXE_LOAD, &Status, NULL); if (EFI_ERROR (Status)) { return Status; } // // Create event to disable Debug Timer interrupt when exit boot service. // Status = gBS->CreateEventEx ( EVT_NOTIFY_SIGNAL, TPL_NOTIFY, DisableDebugTimerExitBootService, NULL, &gEfiEventExitBootServicesGuid, &mExitBootServiceEvent ); return Status; }
/** Enable Debug Agent to support source debugging on AP function. **/ VOID EnableDebugAgent ( VOID ) { // // Initialize Debug Agent to support source level debug in DXE phase // InitializeDebugAgent (DEBUG_AGENT_INIT_DXE_AP, NULL, NULL); }
/** This is the unload handle for Debug Agent Dxe driver. It will invoke Debug Agent Library to disable source debugging feature. @param[in] ImageHandle The drivers' driver image. @retval EFI_SUCCESS The image is unloaded. @retval Others Failed to unload the image. **/ EFI_STATUS EFIAPI DebugAgentDxeUnload ( IN EFI_HANDLE ImageHandle ) { EFI_STATUS Status; Status = EFI_UNSUPPORTED; InitializeDebugAgent (DEBUG_AGENT_INIT_DXE_UNLOAD, &Status, NULL); return Status; }
VOID CEntryPoint ( IN UINTN MpId, IN EFI_PEI_CORE_ENTRY_POINT PeiCoreEntryPoint ) { // Data Cache enabled on Primary core when MMU is enabled. ArmDisableDataCache (); // Invalidate Data cache ArmInvalidateDataCache (); // Invalidate instruction cache ArmInvalidateInstructionCache (); // Enable Instruction Caches on all cores. ArmEnableInstructionCache (); // // Note: Doesn't have to Enable CPU interface in non-secure world, // as Non-secure interface is already enabled in Secure world. // // Write VBAR - The Exception Vector table must be aligned to its requirement // Note: The AArch64 Vector table must be 2k-byte aligned - if this assertion fails ensure // 'Align=4K' is defined into your FDF for this module. ASSERT (((UINTN)PeiVectorTable & ARM_VECTOR_TABLE_ALIGNMENT) == 0); ArmWriteVBar ((UINTN)PeiVectorTable); //Note: The MMU will be enabled by MemoryPeim. Only the primary core will have the MMU on. // If not primary Jump to Secondary Main if (ArmPlatformIsPrimaryCore (MpId)) { // Initialize the Debug Agent for Source Level Debugging InitializeDebugAgent (DEBUG_AGENT_INIT_POSTMEM_SEC, NULL, NULL); SaveAndSetDebugTimerInterrupt (TRUE); // Initialize the platform specific controllers ArmPlatformInitialize (MpId); // Goto primary Main. PrimaryMain (PeiCoreEntryPoint); } else { SecondaryMain (MpId); } // PEI Core should always load and never return ASSERT (FALSE); }
/** The module Entry Point of the CPU SMM driver. @param ImageHandle The firmware allocated handle for the EFI image. @param SystemTable A pointer to the EFI System Table. @retval EFI_SUCCESS The entry point is executed successfully. @retval Other Some error occurs when executing this entry point. **/ EFI_STATUS EFIAPI PiCpuSmmEntry ( IN EFI_HANDLE ImageHandle, IN EFI_SYSTEM_TABLE *SystemTable ) { EFI_STATUS Status; EFI_MP_SERVICES_PROTOCOL *MpServices; UINTN NumberOfEnabledProcessors; UINTN Index; VOID *Buffer; UINTN BufferPages; UINTN TileCodeSize; UINTN TileDataSize; UINTN TileSize; UINT8 *Stacks; VOID *Registration; UINT32 RegEax; UINT32 RegEdx; UINTN FamilyId; UINTN ModelId; UINT32 Cr3; // // Initialize Debug Agent to support source level debug in SMM code // InitializeDebugAgent (DEBUG_AGENT_INIT_SMM, NULL, NULL); // // Report the start of CPU SMM initialization. // REPORT_STATUS_CODE ( EFI_PROGRESS_CODE, EFI_COMPUTING_UNIT_HOST_PROCESSOR | EFI_CU_HP_PC_SMM_INIT ); // // Fix segment address of the long-mode-switch jump // if (sizeof (UINTN) == sizeof (UINT64)) { gSmmJmpAddr.Segment = LONG_MODE_CODE_SEGMENT; } // // Find out SMRR Base and SMRR Size // FindSmramInfo (&mCpuHotPlugData.SmrrBase, &mCpuHotPlugData.SmrrSize); // // Get MP Services Protocol // Status = SystemTable->BootServices->LocateProtocol (&gEfiMpServiceProtocolGuid, NULL, (VOID **)&MpServices); ASSERT_EFI_ERROR (Status); // // Use MP Services Protocol to retrieve the number of processors and number of enabled processors // Status = MpServices->GetNumberOfProcessors (MpServices, &mNumberOfCpus, &NumberOfEnabledProcessors); ASSERT_EFI_ERROR (Status); ASSERT (mNumberOfCpus <= PcdGet32 (PcdCpuMaxLogicalProcessorNumber)); // // If support CPU hot plug, PcdCpuSmmEnableBspElection should be set to TRUE. // A constant BSP index makes no sense because it may be hot removed. // DEBUG_CODE ( if (FeaturePcdGet (PcdCpuHotPlugSupport)) { ASSERT (FeaturePcdGet (PcdCpuSmmEnableBspElection)); } );
/** The X64 entrypoint is used to process capsule in long mode then return to 32-bit protected mode. @param EntrypointContext Pointer to the context of long mode. @param ReturnContext Pointer to the context of 32-bit protected mode. @retval This function should never return actually. **/ EFI_STATUS EFIAPI _ModuleEntryPoint ( SWITCH_32_TO_64_CONTEXT *EntrypointContext, SWITCH_64_TO_32_CONTEXT *ReturnContext ) { EFI_STATUS Status; IA32_DESCRIPTOR Ia32Idtr; IA32_DESCRIPTOR X64Idtr; IA32_IDT_GATE_DESCRIPTOR IdtEntryTable[EXCEPTION_VECTOR_NUMBER]; // // Save the IA32 IDT Descriptor // AsmReadIdtr ((IA32_DESCRIPTOR *) &Ia32Idtr); // // Setup X64 IDT table // ZeroMem (IdtEntryTable, sizeof (IA32_IDT_GATE_DESCRIPTOR) * EXCEPTION_VECTOR_NUMBER); X64Idtr.Base = (UINTN) IdtEntryTable; X64Idtr.Limit = (UINT16) (sizeof (IA32_IDT_GATE_DESCRIPTOR) * EXCEPTION_VECTOR_NUMBER - 1); AsmWriteIdtr ((IA32_DESCRIPTOR *) &X64Idtr); // // Setup the default CPU exception handlers // Status = InitializeCpuExceptionHandlers (NULL); ASSERT_EFI_ERROR (Status); // // Initialize Debug Agent to support source level debug // InitializeDebugAgent (DEBUG_AGENT_INIT_THUNK_PEI_IA32TOX64, (VOID *) &Ia32Idtr, NULL); // // Call CapsuleDataCoalesce to process capsule. // Status = CapsuleDataCoalesce ( NULL, (EFI_PHYSICAL_ADDRESS *) (UINTN) EntrypointContext->BlockListAddr, (VOID **) (UINTN) EntrypointContext->MemoryBase64Ptr, (UINTN *) (UINTN) EntrypointContext->MemorySize64Ptr ); ReturnContext->ReturnStatus = Status; // // Disable interrupt of Debug timer, since the new IDT table cannot work in long mode // SaveAndSetDebugTimerInterrupt (FALSE); // // Restore IA32 IDT table // AsmWriteIdtr ((IA32_DESCRIPTOR *) &Ia32Idtr); // // Finish to coalesce capsule, and return to 32-bit mode. // AsmDisablePaging64 ( ReturnContext->ReturnCs, (UINT32) ReturnContext->ReturnEntryPoint, (UINT32) (UINTN) EntrypointContext, (UINT32) (UINTN) ReturnContext, (UINT32) (EntrypointContext->StackBufferBase + EntrypointContext->StackBufferLength) ); // // Should never be here. // ASSERT (FALSE); return EFI_SUCCESS; }
/** Entry function of Boot script exector. This function will be executed in S3 boot path. This function should not return, because it is invoked by switch stack. @param AcpiS3Context a pointer to a structure of ACPI_S3_CONTEXT @param PeiS3ResumeState a pointer to a structure of PEI_S3_RESUME_STATE @retval EFI_INVALID_PARAMETER - OS waking vector not found @retval EFI_UNSUPPORTED - something wrong when we resume to OS **/ EFI_STATUS EFIAPI S3BootScriptExecutorEntryFunction ( IN ACPI_S3_CONTEXT *AcpiS3Context, IN PEI_S3_RESUME_STATE *PeiS3ResumeState ) { EFI_ACPI_4_0_FIRMWARE_ACPI_CONTROL_STRUCTURE *Facs; EFI_STATUS Status; UINTN TempStackTop; UINTN TempStack[0x10]; UINTN AsmTransferControl16Address; IA32_DESCRIPTOR IdtDescriptor; // // Disable interrupt of Debug timer, since new IDT table cannot handle it. // SaveAndSetDebugTimerInterrupt (FALSE); AsmReadIdtr (&IdtDescriptor); // // Restore IDT for debug // SetIdtEntry (AcpiS3Context); // // Initialize Debug Agent to support source level debug in S3 path, it will disable interrupt and Debug Timer. // InitializeDebugAgent (DEBUG_AGENT_INIT_S3, (VOID *)&IdtDescriptor, NULL); // // Because not install BootScriptExecute PPI(used just in this module), So just pass NULL // for that parameter. // Status = S3BootScriptExecute (); // // If invalid script table or opcode in S3 boot script table. // ASSERT_EFI_ERROR (Status); if (EFI_ERROR (Status)) { CpuDeadLoop (); return Status; } AsmWbinvd (); // // Get ACPI Table Address // Facs = (EFI_ACPI_4_0_FIRMWARE_ACPI_CONTROL_STRUCTURE *) ((UINTN) (AcpiS3Context->AcpiFacsTable)); // // We need turn back to S3Resume - install boot script done ppi and report status code on S3resume. // if (PeiS3ResumeState != 0) { // // Need report status back to S3ResumePeim. // If boot script execution is failed, S3ResumePeim wil report the error status code. // PeiS3ResumeState->ReturnStatus = (UINT64)(UINTN)Status; if (FeaturePcdGet (PcdDxeIplSwitchToLongMode)) { // // X64 S3 Resume // DEBUG ((EFI_D_ERROR, "Call AsmDisablePaging64() to return to S3 Resume in PEI Phase\n")); PeiS3ResumeState->AsmTransferControl = (EFI_PHYSICAL_ADDRESS)(UINTN)AsmTransferControl32; if ((Facs != NULL) && (Facs->Signature == EFI_ACPI_4_0_FIRMWARE_ACPI_CONTROL_STRUCTURE_SIGNATURE) && (Facs->FirmwareWakingVector != 0) ) { // // more step needed - because relative address is handled differently between X64 and IA32. // AsmTransferControl16Address = (UINTN)AsmTransferControl16; AsmFixAddress16 = (UINT32)AsmTransferControl16Address; AsmJmpAddr32 = (UINT32)((Facs->FirmwareWakingVector & 0xF) | ((Facs->FirmwareWakingVector & 0xFFFF0) << 12)); } AsmDisablePaging64 ( PeiS3ResumeState->ReturnCs, (UINT32)PeiS3ResumeState->ReturnEntryPoint, (UINT32)(UINTN)AcpiS3Context, (UINT32)(UINTN)PeiS3ResumeState, (UINT32)PeiS3ResumeState->ReturnStackPointer ); } else { // // IA32 S3 Resume // DEBUG ((EFI_D_ERROR, "Call SwitchStack() to return to S3 Resume in PEI Phase\n")); PeiS3ResumeState->AsmTransferControl = (EFI_PHYSICAL_ADDRESS)(UINTN)AsmTransferControl; SwitchStack ( (SWITCH_STACK_ENTRY_POINT)(UINTN)PeiS3ResumeState->ReturnEntryPoint, (VOID *)(UINTN)AcpiS3Context, (VOID *)(UINTN)PeiS3ResumeState, (VOID *)(UINTN)PeiS3ResumeState->ReturnStackPointer ); } // // Never run to here // CpuDeadLoop(); return EFI_UNSUPPORTED; } // // S3ResumePeim does not provide a way to jump back to itself, so resume to OS here directly // if (Facs->XFirmwareWakingVector != 0) { // // Switch to native waking vector // TempStackTop = (UINTN)&TempStack + sizeof(TempStack); if ((Facs->Version == EFI_ACPI_4_0_FIRMWARE_ACPI_CONTROL_STRUCTURE_VERSION) && ((Facs->Flags & EFI_ACPI_4_0_64BIT_WAKE_SUPPORTED_F) != 0) && ((Facs->Flags & EFI_ACPI_4_0_OSPM_64BIT_WAKE__F) != 0)) { // // X64 long mode waking vector // DEBUG (( EFI_D_ERROR, "Transfer to 64bit OS waking vector - %x\r\n", (UINTN)Facs->XFirmwareWakingVector)); if (FeaturePcdGet (PcdDxeIplSwitchToLongMode)) { SwitchStack ( (SWITCH_STACK_ENTRY_POINT)(UINTN)Facs->XFirmwareWakingVector, NULL, NULL, (VOID *)(UINTN)TempStackTop ); } else { // Unsupported for 32bit DXE, 64bit OS vector DEBUG (( EFI_D_ERROR, "Unsupported for 32bit DXE transfer to 64bit OS waking vector!\r\n")); ASSERT (FALSE); } } else { // // IA32 protected mode waking vector (Page disabled) // DEBUG (( EFI_D_ERROR, "Transfer to 32bit OS waking vector - %x\r\n", (UINTN)Facs->XFirmwareWakingVector)); if (FeaturePcdGet (PcdDxeIplSwitchToLongMode)) { AsmDisablePaging64 ( 0x10, (UINT32)Facs->XFirmwareWakingVector, 0, 0, (UINT32)TempStackTop ); } else { SwitchStack ( (SWITCH_STACK_ENTRY_POINT)(UINTN)Facs->XFirmwareWakingVector, NULL, NULL, (VOID *)(UINTN)TempStackTop ); } } } else { // // 16bit Realmode waking vector // DEBUG (( EFI_D_ERROR, "Transfer to 16bit OS waking vector - %x\r\n", (UINTN)Facs->FirmwareWakingVector)); AsmTransferControl (Facs->FirmwareWakingVector, 0x0); } // // Never run to here // CpuDeadLoop(); return EFI_UNSUPPORTED; }
VOID CEntryPoint ( IN VOID *MemoryBase, IN UINTN MemorySize, IN VOID *StackBase, IN UINTN StackSize ) { VOID *HobBase; // Build a basic HOB list HobBase = (VOID *)(UINTN)(FixedPcdGet32(PcdEmbeddedFdBaseAddress) + FixedPcdGet32(PcdEmbeddedFdSize)); CreateHobList (MemoryBase, MemorySize, HobBase, StackBase); //Set up Pin muxing. PadConfiguration (); // Set up system clocking ClockInit (); // Enable program flow prediction, if supported. ArmEnableBranchPrediction (); // Initialize CPU cache InitCache ((UINT32)MemoryBase, (UINT32)MemorySize); // Add memory allocation hob for relocated FD BuildMemoryAllocationHob (FixedPcdGet32(PcdEmbeddedFdBaseAddress), FixedPcdGet32(PcdEmbeddedFdSize), EfiBootServicesData); // Add the FVs to the hob list BuildFvHob (PcdGet32(PcdFlashFvMainBase), PcdGet32(PcdFlashFvMainSize)); // Start talking UartInit (); InitializeDebugAgent (DEBUG_AGENT_INIT_PREMEM_SEC, NULL, NULL); SaveAndSetDebugTimerInterrupt (TRUE); DEBUG ((EFI_D_ERROR, "UART Enabled\n")); // Start up a free running timer so that the timer lib will work TimerInit (); // SEC phase needs to run library constructors by hand. ExtractGuidedSectionLibConstructor (); LzmaDecompressLibConstructor (); // Build HOBs to pass up our version of stuff the DXE Core needs to save space BuildPeCoffLoaderHob (); BuildExtractSectionHob ( &gLzmaCustomDecompressGuid, LzmaGuidedSectionGetInfo, LzmaGuidedSectionExtraction ); // Assume the FV that contains the SEC (our code) also contains a compressed FV. DecompressFirstFv (); // Load the DXE Core and transfer control to it LoadDxeCoreFromFv (NULL, 0); // DXE Core should always load and never return ASSERT (FALSE); }
/** 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); // // 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); // // 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; // // 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); // // Call constructor for all libraries // ProcessLibraryConstructorList (gDxeCoreImageHandle, gDxeCoreST); PERF_END (NULL,"PEI", NULL, 0) ; PERF_START (NULL,"DXE", NULL, 0) ; // // 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_FV2) { DEBUG ((DEBUG_INFO | DEBUG_LOAD, "FV2 Hob 0x%0lx - 0x%0lx\n", Hob.FirmwareVolume2->BaseAddress, Hob.FirmwareVolume2->BaseAddress + Hob.FirmwareVolume2->Length - 1)); } else 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)); } } DEBUG_CODE_END (); // // Initialize the Event Services // Status = CoreInitializeEventServices (); ASSERT_EFI_ERROR (Status); MemoryProfileInstallProtocol (); CoreInitializePropertiesTable (); CoreInitializeMemoryAttributesTable (); // // 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 // PERF_START (NULL,"CoreInitializeDispatcher", "DxeMain", 0) ; CoreInitializeDispatcher (); PERF_END (NULL,"CoreInitializeDispatcher", "DxeMain", 0) ; // // Invoke the DXE Dispatcher // PERF_START (NULL, "CoreDispatcher", "DxeMain", 0); CoreDispatcher (); PERF_END (NULL, "CoreDispatcher", "DxeMain", 0); // // 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 (); }
VOID CEntryPoint ( IN UINTN MpId, IN UINTN SecBootMode ) { CHAR8 Buffer[100]; UINTN CharCount; UINTN JumpAddress; // Invalidate the data cache. Doesn't have to do the Data cache clean. ArmInvalidateDataCache (); // Invalidate Instruction Cache ArmInvalidateInstructionCache (); // Invalidate I & D TLBs ArmInvalidateInstructionAndDataTlb (); // CPU specific settings ArmCpuSetup (MpId); // Enable Floating Point Coprocessor if supported by the platform if (FixedPcdGet32 (PcdVFPEnabled)) { ArmEnableVFP (); } // Initialize peripherals that must be done at the early stage // Example: Some L2 controller, interconnect, clock, DMC, etc ArmPlatformSecInitialize (MpId); // Primary CPU clears out the SCU tag RAMs, secondaries wait if (ArmPlatformIsPrimaryCore (MpId) && (SecBootMode == ARM_SEC_COLD_BOOT)) { if (ArmIsMpCore()) { // Signal for the initial memory is configured (event: BOOT_MEM_INIT) ArmCallSEV (); } // SEC phase needs to run library constructors by hand. This assumes we are linked against the SerialLib // In non SEC modules the init call is in autogenerated code. SerialPortInitialize (); // Start talking if (FixedPcdGetBool (PcdTrustzoneSupport)) { CharCount = AsciiSPrint (Buffer,sizeof (Buffer),"Secure firmware (version %s built at %a on %a)\n\r", (CHAR16*)PcdGetPtr(PcdFirmwareVersionString), __TIME__, __DATE__); } else { CharCount = AsciiSPrint (Buffer,sizeof (Buffer),"Boot firmware (version %s built at %a on %a)\n\r", (CHAR16*)PcdGetPtr(PcdFirmwareVersionString), __TIME__, __DATE__); } SerialPortWrite ((UINT8 *) Buffer, CharCount); // Initialize the Debug Agent for Source Level Debugging InitializeDebugAgent (DEBUG_AGENT_INIT_PREMEM_SEC, NULL, NULL); SaveAndSetDebugTimerInterrupt (TRUE); // Enable the GIC distributor and CPU Interface // - no other Interrupts are enabled, doesn't have to worry about the priority. // - all the cores are in secure state, use secure SGI's ArmGicEnableDistributor (PcdGet32(PcdGicDistributorBase)); ArmGicEnableInterruptInterface (PcdGet32(PcdGicInterruptInterfaceBase)); } else { // Enable the GIC CPU Interface ArmGicEnableInterruptInterface (PcdGet32(PcdGicInterruptInterfaceBase)); } // Enable Full Access to CoProcessors ArmWriteCpacr (CPACR_CP_FULL_ACCESS); // Test if Trustzone is supported on this platform if (FixedPcdGetBool (PcdTrustzoneSupport)) { if (ArmIsMpCore ()) { // Setup SMP in Non Secure world ArmCpuSetupSmpNonSecure (GET_CORE_ID(MpId)); } // Either we use the Secure Stacks for Secure Monitor (in this case (Base == 0) && (Size == 0)) // Or we use separate Secure Monitor stacks (but (Base != 0) && (Size != 0)) ASSERT (((PcdGet32(PcdCPUCoresSecMonStackBase) == 0) && (PcdGet32(PcdCPUCoreSecMonStackSize) == 0)) || ((PcdGet32(PcdCPUCoresSecMonStackBase) != 0) && (PcdGet32(PcdCPUCoreSecMonStackSize) != 0))); // Enter Monitor Mode enter_monitor_mode ( (UINTN)TrustedWorldInitialization, MpId, SecBootMode, (VOID*) (PcdGet32 (PcdCPUCoresSecMonStackBase) + (PcdGet32 (PcdCPUCoreSecMonStackSize) * (ArmPlatformGetCorePosition (MpId) + 1))) ); } else { if (ArmPlatformIsPrimaryCore (MpId)) { SerialPrint ("Trust Zone Configuration is disabled\n\r"); } // With Trustzone support the transition from Sec to Normal world is done by return_from_exception(). // If we want to keep this function call we need to ensure the SVC's SPSR point to the same Program // Status Register as the the current one (CPSR). copy_cpsr_into_spsr (); // Call the Platform specific function to execute additional actions if required JumpAddress = PcdGet32 (PcdFvBaseAddress); ArmPlatformSecExtraAction (MpId, &JumpAddress); NonTrustedWorldTransition (MpId, JumpAddress); } ASSERT (0); // We must never return from the above function }
/** Perform SMM initialization for all processors in the S3 boot path. For a native platform, MP initialization in the S3 boot path is also performed in this function. **/ VOID EFIAPI SmmRestoreCpu ( VOID ) { SMM_S3_RESUME_STATE *SmmS3ResumeState; IA32_DESCRIPTOR Ia32Idtr; IA32_DESCRIPTOR X64Idtr; IA32_IDT_GATE_DESCRIPTOR IdtEntryTable[EXCEPTION_VECTOR_NUMBER]; EFI_STATUS Status; DEBUG ((EFI_D_INFO, "SmmRestoreCpu()\n")); mSmmS3Flag = TRUE; InitializeSpinLock (mMemoryMappedLock); // // See if there is enough context to resume PEI Phase // if (mSmmS3ResumeState == NULL) { DEBUG ((EFI_D_ERROR, "No context to return to PEI Phase\n")); CpuDeadLoop (); } SmmS3ResumeState = mSmmS3ResumeState; ASSERT (SmmS3ResumeState != NULL); if (SmmS3ResumeState->Signature == SMM_S3_RESUME_SMM_64) { // // Save the IA32 IDT Descriptor // AsmReadIdtr ((IA32_DESCRIPTOR *) &Ia32Idtr); // // Setup X64 IDT table // ZeroMem (IdtEntryTable, sizeof (IA32_IDT_GATE_DESCRIPTOR) * 32); X64Idtr.Base = (UINTN) IdtEntryTable; X64Idtr.Limit = (UINT16) (sizeof (IA32_IDT_GATE_DESCRIPTOR) * 32 - 1); AsmWriteIdtr ((IA32_DESCRIPTOR *) &X64Idtr); // // Setup the default exception handler // Status = InitializeCpuExceptionHandlers (NULL); ASSERT_EFI_ERROR (Status); // // Initialize Debug Agent to support source level debug // InitializeDebugAgent (DEBUG_AGENT_INIT_THUNK_PEI_IA32TOX64, (VOID *)&Ia32Idtr, NULL); } // // Skip initialization if mAcpiCpuData is not valid // if (mAcpiCpuData.NumberOfCpus > 0) { // // First time microcode load and restore MTRRs // InitializeCpuBeforeRebase (); } // // Restore SMBASE for BSP and all APs // SmmRelocateBases (); // // Skip initialization if mAcpiCpuData is not valid // if (mAcpiCpuData.NumberOfCpus > 0) { // // Restore MSRs for BSP and all APs // InitializeCpuAfterRebase (); } // // Set a flag to restore SMM configuration in S3 path. // mRestoreSmmConfigurationInS3 = TRUE; DEBUG (( EFI_D_INFO, "SMM S3 Return CS = %x\n", SmmS3ResumeState->ReturnCs)); DEBUG (( EFI_D_INFO, "SMM S3 Return Entry Point = %x\n", SmmS3ResumeState->ReturnEntryPoint)); DEBUG (( EFI_D_INFO, "SMM S3 Return Context1 = %x\n", SmmS3ResumeState->ReturnContext1)); DEBUG (( EFI_D_INFO, "SMM S3 Return Context2 = %x\n", SmmS3ResumeState->ReturnContext2)); DEBUG (( EFI_D_INFO, "SMM S3 Return Stack Pointer = %x\n", SmmS3ResumeState->ReturnStackPointer)); // // If SMM is in 32-bit mode, then use SwitchStack() to resume PEI Phase // if (SmmS3ResumeState->Signature == SMM_S3_RESUME_SMM_32) { DEBUG ((EFI_D_INFO, "Call SwitchStack() to return to S3 Resume in PEI Phase\n")); SwitchStack ( (SWITCH_STACK_ENTRY_POINT)(UINTN)SmmS3ResumeState->ReturnEntryPoint, (VOID *)(UINTN)SmmS3ResumeState->ReturnContext1, (VOID *)(UINTN)SmmS3ResumeState->ReturnContext2, (VOID *)(UINTN)SmmS3ResumeState->ReturnStackPointer ); } // // If SMM is in 64-bit mode, then use AsmDisablePaging64() to resume PEI Phase // if (SmmS3ResumeState->Signature == SMM_S3_RESUME_SMM_64) { DEBUG ((EFI_D_INFO, "Call AsmDisablePaging64() to return to S3 Resume in PEI Phase\n")); // // Disable interrupt of Debug timer, since new IDT table is for IA32 and will not work in long mode. // SaveAndSetDebugTimerInterrupt (FALSE); // // Restore IA32 IDT table // AsmWriteIdtr ((IA32_DESCRIPTOR *) &Ia32Idtr); AsmDisablePaging64 ( SmmS3ResumeState->ReturnCs, (UINT32)SmmS3ResumeState->ReturnEntryPoint, (UINT32)SmmS3ResumeState->ReturnContext1, (UINT32)SmmS3ResumeState->ReturnContext2, (UINT32)SmmS3ResumeState->ReturnStackPointer ); } // // Can not resume PEI Phase // DEBUG ((EFI_D_ERROR, "No context to return to PEI Phase\n")); CpuDeadLoop (); }
/** Entry function of Boot script exector. This function will be executed in S3 boot path. This function should not return, because it is invoked by switch stack. @param AcpiS3Context a pointer to a structure of ACPI_S3_CONTEXT @param PeiS3ResumeState a pointer to a structure of PEI_S3_RESUME_STATE @retval EFI_INVALID_PARAMETER - OS waking vector not found @retval EFI_UNSUPPORTED - something wrong when we resume to OS **/ EFI_STATUS EFIAPI S3BootScriptExecutorEntryFunction ( IN ACPI_S3_CONTEXT *AcpiS3Context, IN PEI_S3_RESUME_STATE *PeiS3ResumeState ) { EFI_STATUS Status; // // Disable interrupt of Debug timer, since new IDT table cannot handle it. // SaveAndSetDebugTimerInterrupt (FALSE); // // Restore IDT for debug // SetIdtEntry (AcpiS3Context); // // Initialize Debug Agent to support source level debug in S3 path. // InitializeDebugAgent (DEBUG_AGENT_INIT_S3, NULL, NULL); // // Because not install BootScriptExecute PPI(used just in this module), So just pass NULL // for that parameter. // Status = S3BootScriptExecute (); AsmWbinvd (); // // We need turn back to S3Resume - install boot script done ppi and report status code on S3resume. // if (PeiS3ResumeState != 0) { // // Need report status back to S3ResumePeim. // If boot script execution is failed, S3ResumePeim wil report the error status code. // PeiS3ResumeState->ReturnStatus = (UINT64)(UINTN)Status; // // IA32 S3 Resume // DEBUG ((EFI_D_INFO, "Call SwitchStack() to return to S3 Resume in PEI Phase\n")); PeiS3ResumeState->AsmTransferControl = (EFI_PHYSICAL_ADDRESS)(UINTN)PlatformTransferControl16; SwitchStack ( (SWITCH_STACK_ENTRY_POINT)(UINTN)PeiS3ResumeState->ReturnEntryPoint, (VOID *)(UINTN)AcpiS3Context, (VOID *)(UINTN)PeiS3ResumeState, (VOID *)(UINTN)PeiS3ResumeState->ReturnStackPointer ); // // Never run to here // CpuDeadLoop(); return EFI_UNSUPPORTED; } // // Never run to here // CpuDeadLoop(); return EFI_UNSUPPORTED; }
VOID PrePiMain ( IN UINTN UefiMemoryBase, IN UINTN StacksBase, IN UINT64 StartTimeStamp ) { EFI_HOB_HANDOFF_INFO_TABLE* HobList; ARM_MP_CORE_INFO_PPI* ArmMpCoreInfoPpi; UINTN ArmCoreCount; ARM_CORE_INFO* ArmCoreInfoTable; EFI_STATUS Status; CHAR8 Buffer[100]; UINTN CharCount; UINTN StacksSize; // If ensure the FD is either part of the System Memory or totally outside of the System Memory (XIP) ASSERT (IS_XIP() || ((FixedPcdGet64 (PcdFdBaseAddress) >= FixedPcdGet64 (PcdSystemMemoryBase)) && ((UINT64)(FixedPcdGet64 (PcdFdBaseAddress) + FixedPcdGet32 (PcdFdSize)) <= (UINT64)mSystemMemoryEnd))); // Initialize the architecture specific bits ArchInitialize (); // Initialize the Serial Port SerialPortInitialize (); CharCount = AsciiSPrint (Buffer,sizeof (Buffer),"UEFI firmware (version %s built at %a on %a)\n\r", (CHAR16*)PcdGetPtr(PcdFirmwareVersionString), __TIME__, __DATE__); SerialPortWrite ((UINT8 *) Buffer, CharCount); // Initialize the Debug Agent for Source Level Debugging InitializeDebugAgent (DEBUG_AGENT_INIT_POSTMEM_SEC, NULL, NULL); SaveAndSetDebugTimerInterrupt (TRUE); // Declare the PI/UEFI memory region HobList = HobConstructor ( (VOID*)UefiMemoryBase, FixedPcdGet32 (PcdSystemMemoryUefiRegionSize), (VOID*)UefiMemoryBase, (VOID*)StacksBase // The top of the UEFI Memory is reserved for the stacks ); PrePeiSetHobList (HobList); // Initialize MMU and Memory HOBs (Resource Descriptor HOBs) Status = MemoryPeim (UefiMemoryBase, FixedPcdGet32 (PcdSystemMemoryUefiRegionSize)); ASSERT_EFI_ERROR (Status); // Create the Stacks HOB (reserve the memory for all stacks) if (ArmIsMpCore ()) { StacksSize = PcdGet32 (PcdCPUCorePrimaryStackSize) + ((FixedPcdGet32 (PcdCoreCount) - 1) * FixedPcdGet32 (PcdCPUCoreSecondaryStackSize)); } else { StacksSize = PcdGet32 (PcdCPUCorePrimaryStackSize); } BuildStackHob (StacksBase, StacksSize); //TODO: Call CpuPei as a library BuildCpuHob (PcdGet8 (PcdPrePiCpuMemorySize), PcdGet8 (PcdPrePiCpuIoSize)); if (ArmIsMpCore ()) { // Only MP Core platform need to produce gArmMpCoreInfoPpiGuid Status = GetPlatformPpi (&gArmMpCoreInfoPpiGuid, (VOID**)&ArmMpCoreInfoPpi); // On MP Core Platform we must implement the ARM MP Core Info PPI (gArmMpCoreInfoPpiGuid) ASSERT_EFI_ERROR (Status); // Build the MP Core Info Table ArmCoreCount = 0; Status = ArmMpCoreInfoPpi->GetMpCoreInfo (&ArmCoreCount, &ArmCoreInfoTable); if (!EFI_ERROR(Status) && (ArmCoreCount > 0)) { // Build MPCore Info HOB BuildGuidDataHob (&gArmMpCoreInfoGuid, ArmCoreInfoTable, sizeof (ARM_CORE_INFO) * ArmCoreCount); } } // Set the Boot Mode SetBootMode (ArmPlatformGetBootMode ()); // Initialize Platform HOBs (CpuHob and FvHob) Status = PlatformPeim (); ASSERT_EFI_ERROR (Status); // Now, the HOB List has been initialized, we can register performance information PERF_START (NULL, "PEI", NULL, StartTimeStamp); // SEC phase needs to run library constructors by hand. ExtractGuidedSectionLibConstructor (); LzmaDecompressLibConstructor (); // Build HOBs to pass up our version of stuff the DXE Core needs to save space BuildPeCoffLoaderHob (); BuildExtractSectionHob ( &gLzmaCustomDecompressGuid, LzmaGuidedSectionGetInfo, LzmaGuidedSectionExtraction ); // Assume the FV that contains the SEC (our code) also contains a compressed FV. Status = DecompressFirstFv (); ASSERT_EFI_ERROR (Status); // Load the DXE Core and transfer control to it Status = LoadDxeCoreFromFv (NULL, 0); ASSERT_EFI_ERROR (Status); }
/** SMI handler for BSP. @param CpuIndex BSP processor Index @param SyncMode SMM MP sync mode **/ VOID BSPHandler ( IN UINTN CpuIndex, IN SMM_CPU_SYNC_MODE SyncMode ) { UINTN Index; MTRR_SETTINGS Mtrrs; UINTN ApCount; BOOLEAN ClearTopLevelSmiResult; UINTN PresentCount; ASSERT (CpuIndex == mSmmMpSyncData->BspIndex); ApCount = 0; // // Flag BSP's presence // mSmmMpSyncData->InsideSmm = TRUE; // // Initialize Debug Agent to start source level debug in BSP handler // InitializeDebugAgent (DEBUG_AGENT_INIT_ENTER_SMI, NULL, NULL); // // Mark this processor's presence // mSmmMpSyncData->CpuData[CpuIndex].Present = TRUE; // // Clear platform top level SMI status bit before calling SMI handlers. If // we cleared it after SMI handlers are run, we would miss the SMI that // occurs after SMI handlers are done and before SMI status bit is cleared. // ClearTopLevelSmiResult = ClearTopLevelSmiStatus(); ASSERT (ClearTopLevelSmiResult == TRUE); // // Set running processor index // gSmmCpuPrivate->SmmCoreEntryContext.CurrentlyExecutingCpu = CpuIndex; // // If Traditional Sync Mode or need to configure MTRRs: gather all available APs. // if (SyncMode == SmmCpuSyncModeTradition || SmmCpuFeaturesNeedConfigureMtrrs()) { // // Wait for APs to arrive // SmmWaitForApArrival(); // // Lock the counter down and retrieve the number of APs // mSmmMpSyncData->AllCpusInSync = TRUE; ApCount = LockdownSemaphore (&mSmmMpSyncData->Counter) - 1; // // Wait for all APs to get ready for programming MTRRs // WaitForAllAPs (ApCount); if (SmmCpuFeaturesNeedConfigureMtrrs()) { // // Signal all APs it's time for backup MTRRs // ReleaseAllAPs (); // // WaitForSemaphore() may wait for ever if an AP happens to enter SMM at // exactly this point. Please make sure PcdCpuSmmMaxSyncLoops has been set // to a large enough value to avoid this situation. // Note: For HT capable CPUs, threads within a core share the same set of MTRRs. // We do the backup first and then set MTRR to avoid race condition for threads // in the same core. // MtrrGetAllMtrrs(&Mtrrs); // // Wait for all APs to complete their MTRR saving // WaitForAllAPs (ApCount); // // Let all processors program SMM MTRRs together // ReleaseAllAPs (); // // WaitForSemaphore() may wait for ever if an AP happens to enter SMM at // exactly this point. Please make sure PcdCpuSmmMaxSyncLoops has been set // to a large enough value to avoid this situation. // ReplaceOSMtrrs (CpuIndex); // // Wait for all APs to complete their MTRR programming // WaitForAllAPs (ApCount); } } // // The BUSY lock is initialized to Acquired state // AcquireSpinLockOrFail (&mSmmMpSyncData->CpuData[CpuIndex].Busy); // // Restore SMM Configuration in S3 boot path. // if (mRestoreSmmConfigurationInS3) { // // Configure SMM Code Access Check feature if available. // ConfigSmmCodeAccessCheck (); mRestoreSmmConfigurationInS3 = FALSE; } // // Invoke SMM Foundation EntryPoint with the processor information context. // gSmmCpuPrivate->SmmCoreEntry (&gSmmCpuPrivate->SmmCoreEntryContext); // // Make sure all APs have completed their pending none-block tasks // for (Index = mMaxNumberOfCpus; Index-- > 0;) { if (Index != CpuIndex && mSmmMpSyncData->CpuData[Index].Present) { AcquireSpinLock (&mSmmMpSyncData->CpuData[Index].Busy); ReleaseSpinLock (&mSmmMpSyncData->CpuData[Index].Busy);; } } // // Perform the remaining tasks // PerformRemainingTasks (); // // If Relaxed-AP Sync Mode: gather all available APs after BSP SMM handlers are done, and // make those APs to exit SMI synchronously. APs which arrive later will be excluded and // will run through freely. // if (SyncMode != SmmCpuSyncModeTradition && !SmmCpuFeaturesNeedConfigureMtrrs()) { // // Lock the counter down and retrieve the number of APs // mSmmMpSyncData->AllCpusInSync = TRUE; ApCount = LockdownSemaphore (&mSmmMpSyncData->Counter) - 1; // // Make sure all APs have their Present flag set // while (TRUE) { PresentCount = 0; for (Index = mMaxNumberOfCpus; Index-- > 0;) { if (mSmmMpSyncData->CpuData[Index].Present) { PresentCount ++; } } if (PresentCount > ApCount) { break; } } } // // Notify all APs to exit // mSmmMpSyncData->InsideSmm = FALSE; ReleaseAllAPs (); // // Wait for all APs to complete their pending tasks // WaitForAllAPs (ApCount); if (SmmCpuFeaturesNeedConfigureMtrrs()) { // // Signal APs to restore MTRRs // ReleaseAllAPs (); // // Restore OS MTRRs // SmmCpuFeaturesReenableSmrr (); MtrrSetAllMtrrs(&Mtrrs); // // Wait for all APs to complete MTRR programming // WaitForAllAPs (ApCount); } // // Stop source level debug in BSP handler, the code below will not be // debugged. // InitializeDebugAgent (DEBUG_AGENT_INIT_EXIT_SMI, NULL, NULL); // // Signal APs to Reset states/semaphore for this processor // ReleaseAllAPs (); // // Perform pending operations for hot-plug // SmmCpuUpdate (); // // Clear the Present flag of BSP // mSmmMpSyncData->CpuData[CpuIndex].Present = FALSE; // // Gather APs to exit SMM synchronously. Note the Present flag is cleared by now but // WaitForAllAps does not depend on the Present flag. // WaitForAllAPs (ApCount); // // Reset BspIndex to -1, meaning BSP has not been elected. // if (FeaturePcdGet (PcdCpuSmmEnableBspElection)) { mSmmMpSyncData->BspIndex = (UINT32)-1; } // // Allow APs to check in from this point on // mSmmMpSyncData->Counter = 0; mSmmMpSyncData->AllCpusInSync = FALSE; }