X-Git-Url: https://git.proxmox.com/?a=blobdiff_plain;f=UefiCpuPkg%2FLibrary%2FMpInitLib%2FPeiMpLib.c;h=5e714eaf19b5a464d2d2d4afbd13d180f4483414;hb=86efe97693a218349778727c7976cb5f584fb5f1;hp=a7e9fb8ed3f6184081aae09ca56437418e85361d;hpb=3e8ad6bd7684502c6a57796a57fb7c6dbe3ec1c5;p=mirror_edk2.git diff --git a/UefiCpuPkg/Library/MpInitLib/PeiMpLib.c b/UefiCpuPkg/Library/MpInitLib/PeiMpLib.c index a7e9fb8ed3..5e714eaf19 100644 --- a/UefiCpuPkg/Library/MpInitLib/PeiMpLib.c +++ b/UefiCpuPkg/Library/MpInitLib/PeiMpLib.c @@ -13,6 +13,359 @@ **/ #include "MpLib.h" +#include +#include + +// +// Global PEI notify function descriptor on EndofPei event +// +GLOBAL_REMOVE_IF_UNREFERENCED EFI_PEI_NOTIFY_DESCRIPTOR mMpInitLibNotifyList = { + (EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST), + &gEfiEndOfPeiSignalPpiGuid, + CpuMpEndOfPeiCallback +}; + +/** + Get pointer to CPU MP Data structure. + + @return The pointer to CPU MP Data structure. +**/ +CPU_MP_DATA * +GetCpuMpData ( + VOID + ) +{ + CPU_MP_DATA *CpuMpData; + + CpuMpData = GetCpuMpDataFromGuidedHob (); + ASSERT (CpuMpData != NULL); + return CpuMpData; +} + +/** + Save the pointer to CPU MP Data structure. + + @param[in] CpuMpData The pointer to CPU MP Data structure will be saved. +**/ +VOID +SaveCpuMpData ( + IN CPU_MP_DATA *CpuMpData + ) +{ + UINT64 Data64; + // + // Build location of CPU MP DATA buffer in HOB + // + Data64 = (UINT64) (UINTN) CpuMpData; + BuildGuidDataHob ( + &mCpuInitMpLibHobGuid, + (VOID *) &Data64, + sizeof (UINT64) + ); +} + +/** + Get available system memory below 1MB by specified size. + + @param[in] PeiCpuMpData Pointer to PEI CPU MP Data +**/ +VOID +BackupAndPrepareWakeupBuffer( + IN CPU_MP_DATA *CpuMpData + ) +{ + CopyMem ( + (VOID *) CpuMpData->BackupBuffer, + (VOID *) CpuMpData->WakeupBuffer, + CpuMpData->BackupBufferSize + ); + CopyMem ( + (VOID *) CpuMpData->WakeupBuffer, + (VOID *) CpuMpData->AddressMap.RendezvousFunnelAddress, + CpuMpData->AddressMap.RendezvousFunnelSize + ); +} + +/** + Restore wakeup buffer data. + + @param[in] PeiCpuMpData Pointer to PEI CPU MP Data +**/ +VOID +RestoreWakeupBuffer( + IN CPU_MP_DATA *CpuMpData + ) +{ + CopyMem ( + (VOID *) CpuMpData->WakeupBuffer, + (VOID *) CpuMpData->BackupBuffer, + CpuMpData->BackupBufferSize + ); +} + +/** + Notify function on End Of PEI PPI. + + On S3 boot, this function will restore wakeup buffer data. + On normal boot, this function will flag wakeup buffer to be un-used type. + + @param[in] PeiServices The pointer to the PEI Services Table. + @param[in] NotifyDescriptor Address of the notification descriptor data structure. + @param[in] Ppi Address of the PPI that was installed. + + @retval EFI_SUCCESS When everything is OK. +**/ +EFI_STATUS +EFIAPI +CpuMpEndOfPeiCallback ( + IN EFI_PEI_SERVICES **PeiServices, + IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDescriptor, + IN VOID *Ppi + ) +{ + EFI_STATUS Status; + EFI_BOOT_MODE BootMode; + CPU_MP_DATA *CpuMpData; + EFI_PEI_HOB_POINTERS Hob; + EFI_HOB_MEMORY_ALLOCATION *MemoryHob; + + DEBUG ((DEBUG_INFO, "PeiMpInitLib: CpuMpEndOfPeiCallback () invoked\n")); + + Status = PeiServicesGetBootMode (&BootMode); + ASSERT_EFI_ERROR (Status); + + CpuMpData = GetCpuMpData (); + if (BootMode != BOOT_ON_S3_RESUME) { + // + // Get the HOB list for processing + // + Hob.Raw = GetHobList (); + // + // Collect memory ranges + // + while (!END_OF_HOB_LIST (Hob)) { + if (Hob.Header->HobType == EFI_HOB_TYPE_MEMORY_ALLOCATION) { + MemoryHob = Hob.MemoryAllocation; + if (MemoryHob->AllocDescriptor.MemoryBaseAddress == CpuMpData->WakeupBuffer) { + // + // Flag this HOB type to un-used + // + GET_HOB_TYPE (Hob) = EFI_HOB_TYPE_UNUSED; + break; + } + } + Hob.Raw = GET_NEXT_HOB (Hob); + } + } else { + CpuMpData->EndOfPeiFlag = TRUE; + RestoreWakeupBuffer (CpuMpData); + } + return EFI_SUCCESS; +} + +/** + Check if AP wakeup buffer is overlapped with existing allocated buffer. + + @param[in] WakeupBufferStart AP wakeup buffer start address. + @param[in] WakeupBufferEnd AP wakeup buffer end address. + + @retval TRUE There is overlap. + @retval FALSE There is no overlap. +**/ +BOOLEAN +CheckOverlapWithAllocatedBuffer ( + IN UINTN WakeupBufferStart, + IN UINTN WakeupBufferEnd + ) +{ + EFI_PEI_HOB_POINTERS Hob; + EFI_HOB_MEMORY_ALLOCATION *MemoryHob; + BOOLEAN Overlapped; + UINTN MemoryStart; + UINTN MemoryEnd; + + Overlapped = FALSE; + // + // Get the HOB list for processing + // + Hob.Raw = GetHobList (); + // + // Collect memory ranges + // + while (!END_OF_HOB_LIST (Hob)) { + if (Hob.Header->HobType == EFI_HOB_TYPE_MEMORY_ALLOCATION) { + MemoryHob = Hob.MemoryAllocation; + MemoryStart = (UINTN) MemoryHob->AllocDescriptor.MemoryBaseAddress; + MemoryEnd = (UINTN) (MemoryHob->AllocDescriptor.MemoryBaseAddress + + MemoryHob->AllocDescriptor.MemoryLength); + if (!((WakeupBufferStart >= MemoryEnd) || (WakeupBufferEnd <= MemoryStart))) { + Overlapped = TRUE; + break; + } + } + Hob.Raw = GET_NEXT_HOB (Hob); + } + return Overlapped; +} + +/** + Get available system memory below 1MB by specified size. + + @param[in] WakeupBufferSize Wakeup buffer size required + + @retval other Return wakeup buffer address below 1MB. + @retval -1 Cannot find free memory below 1MB. +**/ +UINTN +GetWakeupBuffer ( + IN UINTN WakeupBufferSize + ) +{ + EFI_PEI_HOB_POINTERS Hob; + UINTN WakeupBufferStart; + UINTN WakeupBufferEnd; + + WakeupBufferSize = (WakeupBufferSize + SIZE_4KB - 1) & ~(SIZE_4KB - 1); + + // + // Get the HOB list for processing + // + Hob.Raw = GetHobList (); + + // + // Collect memory ranges + // + while (!END_OF_HOB_LIST (Hob)) { + if (Hob.Header->HobType == EFI_HOB_TYPE_RESOURCE_DESCRIPTOR) { + if ((Hob.ResourceDescriptor->PhysicalStart < BASE_1MB) && + (Hob.ResourceDescriptor->ResourceType == EFI_RESOURCE_SYSTEM_MEMORY) && + ((Hob.ResourceDescriptor->ResourceAttribute & + (EFI_RESOURCE_ATTRIBUTE_READ_PROTECTED | + EFI_RESOURCE_ATTRIBUTE_WRITE_PROTECTED | + EFI_RESOURCE_ATTRIBUTE_EXECUTION_PROTECTED + )) == 0) + ) { + // + // Need memory under 1MB to be collected here + // + WakeupBufferEnd = (UINTN) (Hob.ResourceDescriptor->PhysicalStart + Hob.ResourceDescriptor->ResourceLength); + if (WakeupBufferEnd > BASE_1MB) { + // + // Wakeup buffer should be under 1MB + // + WakeupBufferEnd = BASE_1MB; + } + while (WakeupBufferEnd > WakeupBufferSize) { + // + // Wakeup buffer should be aligned on 4KB + // + WakeupBufferStart = (WakeupBufferEnd - WakeupBufferSize) & ~(SIZE_4KB - 1); + if (WakeupBufferStart < Hob.ResourceDescriptor->PhysicalStart) { + break; + } + if (CheckOverlapWithAllocatedBuffer (WakeupBufferStart, WakeupBufferEnd)) { + // + // If this range is overlapped with existing allocated buffer, skip it + // and find the next range + // + WakeupBufferEnd -= WakeupBufferSize; + continue; + } + DEBUG ((DEBUG_INFO, "WakeupBufferStart = %x, WakeupBufferSize = %x\n", + WakeupBufferStart, WakeupBufferSize)); + // + // Create a memory allocation HOB. + // + BuildMemoryAllocationHob ( + WakeupBufferStart, + WakeupBufferSize, + EfiBootServicesData + ); + return WakeupBufferStart; + } + } + } + // + // Find the next HOB + // + Hob.Raw = GET_NEXT_HOB (Hob); + } + + return (UINTN) -1; +} + +/** + Allocate reset vector buffer. + + @param[in, out] CpuMpData The pointer to CPU MP Data structure. +**/ +VOID +AllocateResetVector ( + IN OUT CPU_MP_DATA *CpuMpData + ) +{ + UINTN ApResetVectorSize; + + if (CpuMpData->WakeupBuffer == (UINTN) -1) { + ApResetVectorSize = CpuMpData->AddressMap.RendezvousFunnelSize + + sizeof (MP_CPU_EXCHANGE_INFO); + + CpuMpData->WakeupBuffer = GetWakeupBuffer (ApResetVectorSize); + CpuMpData->MpCpuExchangeInfo = (MP_CPU_EXCHANGE_INFO *) (UINTN) + (CpuMpData->WakeupBuffer + CpuMpData->AddressMap.RendezvousFunnelSize); + BackupAndPrepareWakeupBuffer (CpuMpData); + } + + if (CpuMpData->EndOfPeiFlag) { + BackupAndPrepareWakeupBuffer (CpuMpData); + } +} + +/** + Free AP reset vector buffer. + + @param[in] CpuMpData The pointer to CPU MP Data structure. +**/ +VOID +FreeResetVector ( + IN CPU_MP_DATA *CpuMpData + ) +{ + if (CpuMpData->EndOfPeiFlag) { + RestoreWakeupBuffer (CpuMpData); + } +} + +/** + Checks APs status and updates APs status if needed. + +**/ +VOID +CheckAndUpdateApsStatus ( + VOID + ) +{ +} + +/** + Initialize global data for MP support. + + @param[in] CpuMpData The pointer to CPU MP Data structure. +**/ +VOID +InitMpGlobalData ( + IN CPU_MP_DATA *CpuMpData + ) +{ + EFI_STATUS Status; + + SaveCpuMpData (CpuMpData); + // + // Register an event for EndOfPei + // + Status = PeiServicesNotifyPpi (&mMpInitLibNotifyList); + ASSERT_EFI_ERROR (Status); +} /** This service executes a caller provided function on all enabled APs. @@ -100,7 +453,18 @@ MpInitLibStartupAllAPs ( OUT UINTN **FailedCpuList OPTIONAL ) { - return EFI_UNSUPPORTED; + if (WaitEvent != NULL) { + return EFI_UNSUPPORTED; + } + + return StartupAllAPsWorker ( + Procedure, + SingleThread, + NULL, + TimeoutInMicroseconds, + ProcedureArgument, + FailedCpuList + ); } /** @@ -185,7 +549,18 @@ MpInitLibStartupThisAP ( OUT BOOLEAN *Finished OPTIONAL ) { - return EFI_UNSUPPORTED; + if (WaitEvent != NULL) { + return EFI_UNSUPPORTED; + } + + return StartupThisAPWorker ( + Procedure, + ProcessorNumber, + NULL, + TimeoutInMicroseconds, + ProcedureArgument, + Finished + ); } /** @@ -221,7 +596,7 @@ MpInitLibSwitchBSP ( IN BOOLEAN EnableOldBSP ) { - return EFI_UNSUPPORTED; + return SwitchBSPWorker (ProcessorNumber, EnableOldBSP); } /** @@ -262,7 +637,7 @@ MpInitLibEnableDisableAP ( IN UINT32 *HealthFlag OPTIONAL ) { - return EFI_UNSUPPORTED; + return EnableDisableApWorker (ProcessorNumber, EnableAP, HealthFlag); }