\r
CPU_MP_DATA *mCpuMpData = NULL;\r
EFI_EVENT mCheckAllApsEvent = NULL;\r
+EFI_EVENT mMpInitExitBootServicesEvent = NULL;\r
volatile BOOLEAN mStopCheckAllApsStatus = TRUE;\r
-\r
+VOID *mReservedApLoopFunc = NULL;\r
\r
/**\r
Get the pointer to CPU MP Data structure.\r
UINTN ApResetVectorSize;\r
EFI_PHYSICAL_ADDRESS StartAddress;\r
\r
- ApResetVectorSize = CpuMpData->AddressMap.RendezvousFunnelSize +\r
- sizeof (MP_CPU_EXCHANGE_INFO);\r
-\r
- StartAddress = BASE_1MB;\r
- Status = gBS->AllocatePages (\r
- AllocateMaxAddress,\r
- EfiACPIMemoryNVS,\r
- EFI_SIZE_TO_PAGES (ApResetVectorSize),\r
- &StartAddress\r
- );\r
- ASSERT_EFI_ERROR (Status);\r
-\r
- CpuMpData->WakeupBuffer = (UINTN) StartAddress;\r
- CpuMpData->MpCpuExchangeInfo = (MP_CPU_EXCHANGE_INFO *) (UINTN)\r
+ if (CpuMpData->SaveRestoreFlag) {\r
+ BackupAndPrepareWakeupBuffer (CpuMpData);\r
+ } else {\r
+ ApResetVectorSize = CpuMpData->AddressMap.RendezvousFunnelSize +\r
+ sizeof (MP_CPU_EXCHANGE_INFO);\r
+\r
+ StartAddress = BASE_1MB;\r
+ Status = gBS->AllocatePages (\r
+ AllocateMaxAddress,\r
+ EfiACPIMemoryNVS,\r
+ EFI_SIZE_TO_PAGES (ApResetVectorSize),\r
+ &StartAddress\r
+ );\r
+ ASSERT_EFI_ERROR (Status);\r
+\r
+ CpuMpData->WakeupBuffer = (UINTN) StartAddress;\r
+ CpuMpData->MpCpuExchangeInfo = (MP_CPU_EXCHANGE_INFO *) (UINTN)\r
(CpuMpData->WakeupBuffer + CpuMpData->AddressMap.RendezvousFunnelSize);\r
- //\r
- // copy AP reset code in it\r
- //\r
- CopyMem (\r
- (VOID *) CpuMpData->WakeupBuffer,\r
- (VOID *) CpuMpData->AddressMap.RendezvousFunnelAddress,\r
- CpuMpData->AddressMap.RendezvousFunnelSize\r
- );\r
+ //\r
+ // copy AP reset code in it\r
+ //\r
+ CopyMem (\r
+ (VOID *) CpuMpData->WakeupBuffer,\r
+ (VOID *) CpuMpData->AddressMap.RendezvousFunnelAddress,\r
+ CpuMpData->AddressMap.RendezvousFunnelSize\r
+ );\r
+ }\r
}\r
\r
/**\r
{\r
EFI_STATUS Status;\r
UINTN ApResetVectorSize;\r
- ApResetVectorSize = CpuMpData->AddressMap.RendezvousFunnelSize +\r
- sizeof (MP_CPU_EXCHANGE_INFO);\r
- Status = gBS->FreePages(\r
- (EFI_PHYSICAL_ADDRESS)CpuMpData->WakeupBuffer,\r
- EFI_SIZE_TO_PAGES (ApResetVectorSize)\r
- );\r
- ASSERT_EFI_ERROR (Status);\r
+\r
+ if (CpuMpData->SaveRestoreFlag) {\r
+ RestoreWakeupBuffer (CpuMpData);\r
+ } else {\r
+ ApResetVectorSize = CpuMpData->AddressMap.RendezvousFunnelSize +\r
+ sizeof (MP_CPU_EXCHANGE_INFO);\r
+ Status = gBS->FreePages(\r
+ (EFI_PHYSICAL_ADDRESS)CpuMpData->WakeupBuffer,\r
+ EFI_SIZE_TO_PAGES (ApResetVectorSize)\r
+ );\r
+ ASSERT_EFI_ERROR (Status);\r
+ }\r
}\r
\r
/**\r
VOID\r
)\r
{\r
+ UINTN ProcessorNumber;\r
+ EFI_STATUS Status;\r
+ CPU_MP_DATA *CpuMpData;\r
+\r
+ CpuMpData = GetCpuMpData ();\r
+\r
+ //\r
+ // First, check whether pending StartupAllAPs() exists.\r
+ //\r
+ if (CpuMpData->WaitEvent != NULL) {\r
+\r
+ Status = CheckAllAPs ();\r
+ //\r
+ // If all APs finish for StartupAllAPs(), signal the WaitEvent for it.\r
+ //\r
+ if (Status != EFI_NOT_READY) {\r
+ Status = gBS->SignalEvent (CpuMpData->WaitEvent);\r
+ CpuMpData->WaitEvent = NULL;\r
+ }\r
+ }\r
+\r
+ //\r
+ // Second, check whether pending StartupThisAPs() callings exist.\r
+ //\r
+ for (ProcessorNumber = 0; ProcessorNumber < CpuMpData->CpuCount; ProcessorNumber++) {\r
+\r
+ if (CpuMpData->CpuData[ProcessorNumber].WaitEvent == NULL) {\r
+ continue;\r
+ }\r
+\r
+ Status = CheckThisAP (ProcessorNumber);\r
+\r
+ if (Status != EFI_NOT_READY) {\r
+ gBS->SignalEvent (CpuMpData->CpuData[ProcessorNumber].WaitEvent);\r
+ CpuMpData->CpuData[ProcessorNumber].WaitEvent = NULL;\r
+ }\r
+ }\r
}\r
\r
/**\r
}\r
}\r
\r
+/**\r
+ Get Protected mode code segment from current GDT table.\r
+\r
+ @return Protected mode code segment value.\r
+**/\r
+UINT16\r
+GetProtectedModeCS (\r
+ VOID\r
+ )\r
+{\r
+ IA32_DESCRIPTOR GdtrDesc;\r
+ IA32_SEGMENT_DESCRIPTOR *GdtEntry;\r
+ UINTN GdtEntryCount;\r
+ UINT16 Index;\r
+\r
+ Index = (UINT16) -1;\r
+ AsmReadGdtr (&GdtrDesc);\r
+ GdtEntryCount = (GdtrDesc.Limit + 1) / sizeof (IA32_SEGMENT_DESCRIPTOR);\r
+ GdtEntry = (IA32_SEGMENT_DESCRIPTOR *) GdtrDesc.Base;\r
+ for (Index = 0; Index < GdtEntryCount; Index++) {\r
+ if (GdtEntry->Bits.L == 0) {\r
+ if (GdtEntry->Bits.Type > 8 && GdtEntry->Bits.L == 0) {\r
+ break;\r
+ }\r
+ }\r
+ GdtEntry++;\r
+ }\r
+ ASSERT (Index != -1);\r
+ return Index * 8;\r
+}\r
+\r
+/**\r
+ Do sync on APs.\r
+\r
+ @param[in, out] Buffer Pointer to private data buffer.\r
+**/\r
+VOID\r
+EFIAPI\r
+RelocateApLoop (\r
+ IN OUT VOID *Buffer\r
+ )\r
+{\r
+ CPU_MP_DATA *CpuMpData;\r
+ BOOLEAN MwaitSupport;\r
+ ASM_RELOCATE_AP_LOOP AsmRelocateApLoopFunc;\r
+\r
+ CpuMpData = GetCpuMpData ();\r
+ MwaitSupport = IsMwaitSupport ();\r
+ AsmRelocateApLoopFunc = (ASM_RELOCATE_AP_LOOP) (UINTN) Buffer;\r
+ AsmRelocateApLoopFunc (MwaitSupport, CpuMpData->ApTargetCState, CpuMpData->PmCodeSegment);\r
+ //\r
+ // It should never reach here\r
+ //\r
+ ASSERT (FALSE);\r
+}\r
+\r
+/**\r
+ Callback function for ExitBootServices.\r
+\r
+ @param[in] Event Event whose notification function is being invoked.\r
+ @param[in] Context The pointer to the notification function's context,\r
+ which is implementation-dependent.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+MpInitExitBootServicesCallback (\r
+ IN EFI_EVENT Event,\r
+ IN VOID *Context\r
+ )\r
+{\r
+ CPU_MP_DATA *CpuMpData;\r
+\r
+ CpuMpData = GetCpuMpData ();\r
+ CpuMpData->SaveRestoreFlag = TRUE;\r
+ CpuMpData->PmCodeSegment = GetProtectedModeCS ();\r
+ CpuMpData->ApLoopMode = PcdGet8 (PcdCpuApLoopMode);\r
+ WakeUpAP (CpuMpData, TRUE, 0, RelocateApLoop, mReservedApLoopFunc);\r
+ DEBUG ((DEBUG_INFO, "MpInitExitBootServicesCallback() done!\n"));\r
+}\r
+\r
/**\r
Initialize global data for MP support.\r
\r
\r
SaveCpuMpData (CpuMpData);\r
\r
+ //\r
+ // Avoid APs access invalid buff data which allocated by BootServices,\r
+ // so we will allocate reserved data for AP loop code.\r
+ // Allocating it in advance since memory services are not available in\r
+ // Exit Boot Services callback function.\r
+ //\r
+ mReservedApLoopFunc = AllocateReservedCopyPool (\r
+ CpuMpData->AddressMap.RelocateApLoopFuncSize,\r
+ CpuMpData->AddressMap.RelocateApLoopFuncAddress\r
+ );\r
+ ASSERT (mReservedApLoopFunc != NULL);\r
+\r
Status = gBS->CreateEvent (\r
EVT_TIMER | EVT_NOTIFY_SIGNAL,\r
TPL_NOTIFY,\r
AP_CHECK_INTERVAL\r
);\r
ASSERT_EFI_ERROR (Status);\r
+ Status = gBS->CreateEvent (\r
+ EVT_SIGNAL_EXIT_BOOT_SERVICES,\r
+ TPL_CALLBACK,\r
+ MpInitExitBootServicesCallback,\r
+ NULL,\r
+ &mMpInitExitBootServicesEvent\r
+ );\r
+ ASSERT_EFI_ERROR (Status);\r
}\r
\r
/**\r
OUT UINTN **FailedCpuList OPTIONAL\r
)\r
{\r
- return EFI_UNSUPPORTED;\r
+ EFI_STATUS Status;\r
+\r
+ //\r
+ // Temporarily stop checkAllApsStatus for avoid resource dead-lock.\r
+ //\r
+ mStopCheckAllApsStatus = TRUE;\r
+\r
+ Status = StartupAllAPsWorker (\r
+ Procedure,\r
+ SingleThread,\r
+ WaitEvent,\r
+ TimeoutInMicroseconds,\r
+ ProcedureArgument,\r
+ FailedCpuList\r
+ );\r
+\r
+ //\r
+ // Start checkAllApsStatus\r
+ //\r
+ mStopCheckAllApsStatus = FALSE;\r
+\r
+ return Status;\r
}\r
\r
/**\r
OUT BOOLEAN *Finished OPTIONAL\r
)\r
{\r
- return EFI_UNSUPPORTED;\r
+ EFI_STATUS Status;\r
+\r
+ //\r
+ // temporarily stop checkAllApsStatus for avoid resource dead-lock.\r
+ //\r
+ mStopCheckAllApsStatus = TRUE;\r
+\r
+ Status = StartupThisAPWorker (\r
+ Procedure,\r
+ ProcessorNumber,\r
+ WaitEvent,\r
+ TimeoutInMicroseconds,\r
+ ProcedureArgument,\r
+ Finished\r
+ );\r
+\r
+ mStopCheckAllApsStatus = FALSE;\r
+\r
+ return Status;\r
}\r
\r
/**\r