**/\r
\r
#include "MpLib.h"\r
+#include <Ppi/EndOfPeiPhase.h>\r
+#include <Library/PeiServicesLib.h>\r
+\r
+//\r
+// Global PEI notify function descriptor on EndofPei event\r
+//\r
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_PEI_NOTIFY_DESCRIPTOR mMpInitLibNotifyList = {\r
+ (EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),\r
+ &gEfiEndOfPeiSignalPpiGuid,\r
+ CpuMpEndOfPeiCallback\r
+};\r
+\r
+\r
+/**\r
+ Enable Debug Agent to support source debugging on AP function.\r
+\r
+**/\r
+VOID\r
+EnableDebugAgent (\r
+ VOID\r
+ )\r
+{\r
+}\r
+\r
+/**\r
+ Get pointer to CPU MP Data structure.\r
+\r
+ @return The pointer to CPU MP Data structure.\r
+**/\r
+CPU_MP_DATA *\r
+GetCpuMpData (\r
+ VOID\r
+ )\r
+{\r
+ CPU_MP_DATA *CpuMpData;\r
+\r
+ CpuMpData = GetCpuMpDataFromGuidedHob ();\r
+ ASSERT (CpuMpData != NULL);\r
+ return CpuMpData;\r
+}\r
+\r
+/**\r
+ Save the pointer to CPU MP Data structure.\r
+\r
+ @param[in] CpuMpData The pointer to CPU MP Data structure will be saved.\r
+**/\r
+VOID\r
+SaveCpuMpData (\r
+ IN CPU_MP_DATA *CpuMpData\r
+ )\r
+{\r
+ UINT64 Data64;\r
+ //\r
+ // Build location of CPU MP DATA buffer in HOB\r
+ //\r
+ Data64 = (UINT64) (UINTN) CpuMpData;\r
+ BuildGuidDataHob (\r
+ &mCpuInitMpLibHobGuid,\r
+ (VOID *) &Data64,\r
+ sizeof (UINT64)\r
+ );\r
+}\r
+\r
+/**\r
+ Notify function on End Of PEI PPI.\r
+\r
+ On S3 boot, this function will restore wakeup buffer data.\r
+ On normal boot, this function will flag wakeup buffer to be un-used type.\r
+\r
+ @param[in] PeiServices The pointer to the PEI Services Table.\r
+ @param[in] NotifyDescriptor Address of the notification descriptor data structure.\r
+ @param[in] Ppi Address of the PPI that was installed.\r
+\r
+ @retval EFI_SUCCESS When everything is OK.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+CpuMpEndOfPeiCallback (\r
+ IN EFI_PEI_SERVICES **PeiServices,\r
+ IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDescriptor,\r
+ IN VOID *Ppi\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_BOOT_MODE BootMode;\r
+ CPU_MP_DATA *CpuMpData;\r
+ EFI_PEI_HOB_POINTERS Hob;\r
+ EFI_HOB_MEMORY_ALLOCATION *MemoryHob;\r
+\r
+ DEBUG ((DEBUG_INFO, "PeiMpInitLib: CpuMpEndOfPeiCallback () invoked\n"));\r
+\r
+ Status = PeiServicesGetBootMode (&BootMode);\r
+ ASSERT_EFI_ERROR (Status);\r
+\r
+ CpuMpData = GetCpuMpData ();\r
+ if (BootMode != BOOT_ON_S3_RESUME) {\r
+ //\r
+ // Get the HOB list for processing\r
+ //\r
+ Hob.Raw = GetHobList ();\r
+ //\r
+ // Collect memory ranges\r
+ //\r
+ while (!END_OF_HOB_LIST (Hob)) {\r
+ if (Hob.Header->HobType == EFI_HOB_TYPE_MEMORY_ALLOCATION) {\r
+ MemoryHob = Hob.MemoryAllocation;\r
+ if (MemoryHob->AllocDescriptor.MemoryBaseAddress == CpuMpData->WakeupBuffer) {\r
+ //\r
+ // Flag this HOB type to un-used\r
+ //\r
+ GET_HOB_TYPE (Hob) = EFI_HOB_TYPE_UNUSED;\r
+ break;\r
+ }\r
+ }\r
+ Hob.Raw = GET_NEXT_HOB (Hob);\r
+ }\r
+ } else {\r
+ CpuMpData->SaveRestoreFlag = TRUE;\r
+ RestoreWakeupBuffer (CpuMpData);\r
+ }\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Check if AP wakeup buffer is overlapped with existing allocated buffer.\r
+\r
+ @param[in] WakeupBufferStart AP wakeup buffer start address.\r
+ @param[in] WakeupBufferEnd AP wakeup buffer end address.\r
+\r
+ @retval TRUE There is overlap.\r
+ @retval FALSE There is no overlap.\r
+**/\r
+BOOLEAN\r
+CheckOverlapWithAllocatedBuffer (\r
+ IN UINTN WakeupBufferStart,\r
+ IN UINTN WakeupBufferEnd\r
+ )\r
+{\r
+ EFI_PEI_HOB_POINTERS Hob;\r
+ EFI_HOB_MEMORY_ALLOCATION *MemoryHob;\r
+ BOOLEAN Overlapped;\r
+ UINTN MemoryStart;\r
+ UINTN MemoryEnd;\r
+\r
+ Overlapped = FALSE;\r
+ //\r
+ // Get the HOB list for processing\r
+ //\r
+ Hob.Raw = GetHobList ();\r
+ //\r
+ // Collect memory ranges\r
+ //\r
+ while (!END_OF_HOB_LIST (Hob)) {\r
+ if (Hob.Header->HobType == EFI_HOB_TYPE_MEMORY_ALLOCATION) {\r
+ MemoryHob = Hob.MemoryAllocation;\r
+ MemoryStart = (UINTN) MemoryHob->AllocDescriptor.MemoryBaseAddress;\r
+ MemoryEnd = (UINTN) (MemoryHob->AllocDescriptor.MemoryBaseAddress +\r
+ MemoryHob->AllocDescriptor.MemoryLength);\r
+ if (!((WakeupBufferStart >= MemoryEnd) || (WakeupBufferEnd <= MemoryStart))) {\r
+ Overlapped = TRUE;\r
+ break;\r
+ }\r
+ }\r
+ Hob.Raw = GET_NEXT_HOB (Hob);\r
+ }\r
+ return Overlapped;\r
+}\r
+\r
+/**\r
+ Get available system memory below 1MB by specified size.\r
+\r
+ @param[in] WakeupBufferSize Wakeup buffer size required\r
+\r
+ @retval other Return wakeup buffer address below 1MB.\r
+ @retval -1 Cannot find free memory below 1MB.\r
+**/\r
+UINTN\r
+GetWakeupBuffer (\r
+ IN UINTN WakeupBufferSize\r
+ )\r
+{\r
+ EFI_PEI_HOB_POINTERS Hob;\r
+ UINTN WakeupBufferStart;\r
+ UINTN WakeupBufferEnd;\r
+\r
+ WakeupBufferSize = (WakeupBufferSize + SIZE_4KB - 1) & ~(SIZE_4KB - 1);\r
+\r
+ //\r
+ // Get the HOB list for processing\r
+ //\r
+ Hob.Raw = GetHobList ();\r
+\r
+ //\r
+ // Collect memory ranges\r
+ //\r
+ while (!END_OF_HOB_LIST (Hob)) {\r
+ if (Hob.Header->HobType == EFI_HOB_TYPE_RESOURCE_DESCRIPTOR) {\r
+ if ((Hob.ResourceDescriptor->PhysicalStart < BASE_1MB) &&\r
+ (Hob.ResourceDescriptor->ResourceType == EFI_RESOURCE_SYSTEM_MEMORY) &&\r
+ ((Hob.ResourceDescriptor->ResourceAttribute &\r
+ (EFI_RESOURCE_ATTRIBUTE_READ_PROTECTED |\r
+ EFI_RESOURCE_ATTRIBUTE_WRITE_PROTECTED |\r
+ EFI_RESOURCE_ATTRIBUTE_EXECUTION_PROTECTED\r
+ )) == 0)\r
+ ) {\r
+ //\r
+ // Need memory under 1MB to be collected here\r
+ //\r
+ WakeupBufferEnd = (UINTN) (Hob.ResourceDescriptor->PhysicalStart + Hob.ResourceDescriptor->ResourceLength);\r
+ if (WakeupBufferEnd > BASE_1MB) {\r
+ //\r
+ // Wakeup buffer should be under 1MB\r
+ //\r
+ WakeupBufferEnd = BASE_1MB;\r
+ }\r
+ while (WakeupBufferEnd > WakeupBufferSize) {\r
+ //\r
+ // Wakeup buffer should be aligned on 4KB\r
+ //\r
+ WakeupBufferStart = (WakeupBufferEnd - WakeupBufferSize) & ~(SIZE_4KB - 1);\r
+ if (WakeupBufferStart < Hob.ResourceDescriptor->PhysicalStart) {\r
+ break;\r
+ }\r
+ if (CheckOverlapWithAllocatedBuffer (WakeupBufferStart, WakeupBufferEnd)) {\r
+ //\r
+ // If this range is overlapped with existing allocated buffer, skip it\r
+ // and find the next range\r
+ //\r
+ WakeupBufferEnd -= WakeupBufferSize;\r
+ continue;\r
+ }\r
+ DEBUG ((DEBUG_INFO, "WakeupBufferStart = %x, WakeupBufferSize = %x\n",\r
+ WakeupBufferStart, WakeupBufferSize));\r
+ //\r
+ // Create a memory allocation HOB.\r
+ //\r
+ BuildMemoryAllocationHob (\r
+ WakeupBufferStart,\r
+ WakeupBufferSize,\r
+ EfiBootServicesData\r
+ );\r
+ return WakeupBufferStart;\r
+ }\r
+ }\r
+ }\r
+ //\r
+ // Find the next HOB\r
+ //\r
+ Hob.Raw = GET_NEXT_HOB (Hob);\r
+ }\r
+\r
+ return (UINTN) -1;\r
+}\r
+\r
+/**\r
+ Allocate reset vector buffer.\r
+\r
+ @param[in, out] CpuMpData The pointer to CPU MP Data structure.\r
+**/\r
+VOID\r
+AllocateResetVector (\r
+ IN OUT CPU_MP_DATA *CpuMpData\r
+ )\r
+{\r
+ UINTN ApResetVectorSize;\r
+\r
+ if (CpuMpData->WakeupBuffer == (UINTN) -1) {\r
+ ApResetVectorSize = CpuMpData->AddressMap.RendezvousFunnelSize +\r
+ sizeof (MP_CPU_EXCHANGE_INFO);\r
+\r
+ CpuMpData->WakeupBuffer = GetWakeupBuffer (ApResetVectorSize);\r
+ CpuMpData->MpCpuExchangeInfo = (MP_CPU_EXCHANGE_INFO *) (UINTN)\r
+ (CpuMpData->WakeupBuffer + CpuMpData->AddressMap.RendezvousFunnelSize);\r
+ BackupAndPrepareWakeupBuffer (CpuMpData);\r
+ }\r
+\r
+ if (CpuMpData->SaveRestoreFlag) {\r
+ BackupAndPrepareWakeupBuffer (CpuMpData);\r
+ }\r
+}\r
+\r
+/**\r
+ Free AP reset vector buffer.\r
+\r
+ @param[in] CpuMpData The pointer to CPU MP Data structure.\r
+**/\r
+VOID\r
+FreeResetVector (\r
+ IN CPU_MP_DATA *CpuMpData\r
+ )\r
+{\r
+ if (CpuMpData->SaveRestoreFlag) {\r
+ RestoreWakeupBuffer (CpuMpData);\r
+ }\r
+}\r
+\r
+/**\r
+ Checks APs status and updates APs status if needed.\r
+\r
+**/\r
+VOID\r
+CheckAndUpdateApsStatus (\r
+ VOID\r
+ )\r
+{\r
+}\r
+\r
+/**\r
+ Initialize global data for MP support.\r
+\r
+ @param[in] CpuMpData The pointer to CPU MP Data structure.\r
+**/\r
+VOID\r
+InitMpGlobalData (\r
+ IN CPU_MP_DATA *CpuMpData\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+\r
+ SaveCpuMpData (CpuMpData);\r
+\r
+ if (CpuMpData->CpuCount == 1) {\r
+ //\r
+ // If only BSP exists, return\r
+ //\r
+ return;\r
+ }\r
+\r
+ //\r
+ // Register an event for EndOfPei\r
+ //\r
+ Status = PeiServicesNotifyPpi (&mMpInitLibNotifyList);\r
+ ASSERT_EFI_ERROR (Status);\r
+}\r
\r
/**\r
This service executes a caller provided function on all enabled APs.\r
EFI_EVENT is defined in CreateEvent() in\r
the Unified Extensible Firmware Interface\r
Specification.\r
- @param[in] TimeoutInMicrosecsond Indicates the time limit in microseconds for\r
+ @param[in] TimeoutInMicroseconds Indicates the time limit in microseconds for\r
APs to return from Procedure, either for\r
blocking or non-blocking mode. Zero means\r
infinity. If the timeout expires before\r
OUT UINTN **FailedCpuList OPTIONAL\r
)\r
{\r
- return EFI_UNSUPPORTED;\r
+ if (WaitEvent != NULL) {\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+\r
+ return StartupAllAPsWorker (\r
+ Procedure,\r
+ SingleThread,\r
+ NULL,\r
+ TimeoutInMicroseconds,\r
+ ProcedureArgument,\r
+ FailedCpuList\r
+ );\r
}\r
\r
/**\r
EFI_EVENT is defined in CreateEvent() in\r
the Unified Extensible Firmware Interface\r
Specification.\r
- @param[in] TimeoutInMicrosecsond Indicates the time limit in microseconds for\r
+ @param[in] TimeoutInMicroseconds Indicates the time limit in microseconds for\r
this AP to finish this Procedure, either for\r
blocking or non-blocking mode. Zero means\r
infinity. If the timeout expires before\r
OUT BOOLEAN *Finished OPTIONAL\r
)\r
{\r
- return EFI_UNSUPPORTED;\r
+ if (WaitEvent != NULL) {\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+\r
+ return StartupThisAPWorker (\r
+ Procedure,\r
+ ProcessorNumber,\r
+ NULL,\r
+ TimeoutInMicroseconds,\r
+ ProcedureArgument,\r
+ Finished\r
+ );\r
}\r
\r
/**\r
IN BOOLEAN EnableOldBSP\r
)\r
{\r
- return EFI_UNSUPPORTED;\r
+ return SwitchBSPWorker (ProcessorNumber, EnableOldBSP);\r
}\r
\r
/**\r
IN UINT32 *HealthFlag OPTIONAL\r
)\r
{\r
- return EFI_UNSUPPORTED;\r
+ return EnableDisableApWorker (ProcessorNumber, EnableAP, HealthFlag);\r
}\r
\r
\r