/** @file\r
MP initialize support functions for DXE phase.\r
\r
- Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>\r
- This program and the accompanying materials\r
- are licensed and made available under the terms and conditions of the BSD License\r
- which accompanies this distribution. The full text of the license may be found at\r
- http://opensource.org/licenses/bsd-license.php\r
-\r
- THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
- WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+ Copyright (c) 2016 - 2020, Intel Corporation. All rights reserved.<BR>\r
+ SPDX-License-Identifier: BSD-2-Clause-Patent\r
\r
**/\r
\r
#include <Library/UefiLib.h>\r
#include <Library/UefiBootServicesTableLib.h>\r
#include <Library/DebugAgentLib.h>\r
+#include <Library/DxeServicesTableLib.h>\r
+#include <Library/VmgExitLib.h>\r
+#include <Register/Amd/Fam17Msr.h>\r
+#include <Register/Amd/Ghcb.h>\r
+\r
+#include <Protocol/Timer.h>\r
+\r
+#define AP_SAFE_STACK_SIZE 128\r
\r
-#define AP_CHECK_INTERVAL (EFI_TIMER_PERIOD_MILLISECONDS (100))\r
-#define AP_SAFE_STACK_SIZE 128\r
+CPU_MP_DATA *mCpuMpData = NULL;\r
+EFI_EVENT mCheckAllApsEvent = NULL;\r
+EFI_EVENT mMpInitExitBootServicesEvent = NULL;\r
+EFI_EVENT mLegacyBootEvent = NULL;\r
+volatile BOOLEAN mStopCheckAllApsStatus = TRUE;\r
+VOID *mReservedApLoopFunc = NULL;\r
+UINTN mReservedTopOfApStack;\r
+volatile UINT32 mNumberToFinish = 0;\r
\r
-CPU_MP_DATA *mCpuMpData = NULL;\r
-EFI_EVENT mCheckAllApsEvent = NULL;\r
-EFI_EVENT mMpInitExitBootServicesEvent = NULL;\r
-EFI_EVENT mLegacyBootEvent = NULL;\r
-volatile BOOLEAN mStopCheckAllApsStatus = TRUE;\r
-VOID *mReservedApLoopFunc = NULL;\r
-UINTN mReservedTopOfApStack;\r
-volatile UINT32 mNumberToFinish = 0;\r
+//\r
+// Begin wakeup buffer allocation below 0x88000\r
+//\r
+STATIC EFI_PHYSICAL_ADDRESS mSevEsDxeWakeupBuffer = 0x88000;\r
\r
/**\r
Enable Debug Agent to support source debugging on AP function.\r
**/\r
VOID\r
SaveCpuMpData (\r
- IN CPU_MP_DATA *CpuMpData\r
+ IN CPU_MP_DATA *CpuMpData\r
)\r
{\r
mCpuMpData = CpuMpData;\r
}\r
\r
/**\r
- Allocate reset vector buffer.\r
+ Get available system memory below 0x88000 by specified size.\r
\r
- @param[in, out] CpuMpData The pointer to CPU MP Data structure.\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
-VOID\r
-AllocateResetVector (\r
- IN OUT CPU_MP_DATA *CpuMpData\r
+UINTN\r
+GetWakeupBuffer (\r
+ IN UINTN WakeupBufferSize\r
)\r
{\r
EFI_STATUS Status;\r
- UINTN ApResetVectorSize;\r
EFI_PHYSICAL_ADDRESS StartAddress;\r
+ EFI_MEMORY_TYPE MemoryType;\r
\r
- if (CpuMpData->SaveRestoreFlag) {\r
- BackupAndPrepareWakeupBuffer (CpuMpData);\r
+ if (ConfidentialComputingGuestHas (CCAttrAmdSevEs)) {\r
+ MemoryType = EfiReservedMemoryType;\r
+ } else {\r
+ MemoryType = EfiBootServicesData;\r
+ }\r
+\r
+ //\r
+ // Try to allocate buffer below 1M for waking vector.\r
+ // LegacyBios driver only reports warning when page allocation in range\r
+ // [0x60000, 0x88000) fails.\r
+ // This library is consumed by CpuDxe driver to produce CPU Arch protocol.\r
+ // LagacyBios driver depends on CPU Arch protocol which guarantees below\r
+ // allocation runs earlier than LegacyBios driver.\r
+ //\r
+ if (ConfidentialComputingGuestHas (CCAttrAmdSevEs)) {\r
+ //\r
+ // SEV-ES Wakeup buffer should be under 0x88000 and under any previous one\r
+ //\r
+ StartAddress = mSevEsDxeWakeupBuffer;\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
+ StartAddress = 0x88000;\r
+ }\r
+\r
+ Status = gBS->AllocatePages (\r
+ AllocateMaxAddress,\r
+ MemoryType,\r
+ EFI_SIZE_TO_PAGES (WakeupBufferSize),\r
+ &StartAddress\r
+ );\r
+ ASSERT_EFI_ERROR (Status);\r
+ if (EFI_ERROR (Status)) {\r
+ StartAddress = (EFI_PHYSICAL_ADDRESS)-1;\r
+ } else if (ConfidentialComputingGuestHas (CCAttrAmdSevEs)) {\r
//\r
- // copy AP reset code in it\r
+ // Next SEV-ES wakeup buffer allocation must be below this allocation\r
//\r
- CopyMem (\r
- (VOID *) CpuMpData->WakeupBuffer,\r
- (VOID *) CpuMpData->AddressMap.RendezvousFunnelAddress,\r
- CpuMpData->AddressMap.RendezvousFunnelSize\r
- );\r
+ mSevEsDxeWakeupBuffer = StartAddress;\r
}\r
+\r
+ DEBUG ((\r
+ DEBUG_INFO,\r
+ "WakeupBufferStart = %x, WakeupBufferSize = %x\n",\r
+ (UINTN)StartAddress,\r
+ WakeupBufferSize\r
+ ));\r
+\r
+ return (UINTN)StartAddress;\r
}\r
\r
/**\r
- Free AP reset vector buffer.\r
+ Get available EfiBootServicesCode memory below 4GB by specified size.\r
+\r
+ This buffer is required to safely transfer AP from real address mode to\r
+ protected mode or long mode, due to the fact that the buffer returned by\r
+ GetWakeupBuffer() may be marked as non-executable.\r
\r
- @param[in] CpuMpData The pointer to CPU MP Data structure.\r
+ @param[in] BufferSize Wakeup transition buffer size.\r
+\r
+ @retval other Return wakeup transition buffer address below 4GB.\r
+ @retval 0 Cannot find free memory below 4GB.\r
**/\r
-VOID\r
-FreeResetVector (\r
- IN CPU_MP_DATA *CpuMpData\r
+UINTN\r
+GetModeTransitionBuffer (\r
+ IN UINTN BufferSize\r
)\r
{\r
EFI_STATUS Status;\r
- UINTN ApResetVectorSize;\r
+ EFI_PHYSICAL_ADDRESS StartAddress;\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
+ StartAddress = BASE_4GB - 1;\r
+ Status = gBS->AllocatePages (\r
+ AllocateMaxAddress,\r
+ EfiBootServicesCode,\r
+ EFI_SIZE_TO_PAGES (BufferSize),\r
+ &StartAddress\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ StartAddress = 0;\r
}\r
+\r
+ return (UINTN)StartAddress;\r
+}\r
+\r
+/**\r
+ Return the address of the SEV-ES AP jump table.\r
+\r
+ This buffer is required in order for an SEV-ES guest to transition from\r
+ UEFI into an OS.\r
+\r
+ @return Return SEV-ES AP jump table buffer\r
+**/\r
+UINTN\r
+GetSevEsAPMemory (\r
+ VOID\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_PHYSICAL_ADDRESS StartAddress;\r
+ MSR_SEV_ES_GHCB_REGISTER Msr;\r
+ GHCB *Ghcb;\r
+ BOOLEAN InterruptState;\r
+\r
+ //\r
+ // Allocate 1 page for AP jump table page\r
+ //\r
+ StartAddress = BASE_4GB - 1;\r
+ Status = gBS->AllocatePages (\r
+ AllocateMaxAddress,\r
+ EfiReservedMemoryType,\r
+ 1,\r
+ &StartAddress\r
+ );\r
+ ASSERT_EFI_ERROR (Status);\r
+\r
+ DEBUG ((DEBUG_INFO, "Dxe: SevEsAPMemory = %lx\n", (UINTN)StartAddress));\r
+\r
+ //\r
+ // Save the SevEsAPMemory as the AP jump table.\r
+ //\r
+ Msr.GhcbPhysicalAddress = AsmReadMsr64 (MSR_SEV_ES_GHCB);\r
+ Ghcb = Msr.Ghcb;\r
+\r
+ VmgInit (Ghcb, &InterruptState);\r
+ VmgExit (Ghcb, SVM_EXIT_AP_JUMP_TABLE, 0, (UINT64)(UINTN)StartAddress);\r
+ VmgDone (Ghcb, InterruptState);\r
+\r
+ return (UINTN)StartAddress;\r
}\r
\r
/**\r
VOID\r
)\r
{\r
- UINTN ProcessorNumber;\r
- EFI_STATUS Status;\r
- CPU_MP_DATA *CpuMpData;\r
+ UINTN ProcessorNumber;\r
+ EFI_STATUS Status;\r
+ CPU_MP_DATA *CpuMpData;\r
\r
CpuMpData = GetCpuMpData ();\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
+ Status = gBS->SignalEvent (CpuMpData->WaitEvent);\r
CpuMpData->WaitEvent = NULL;\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
if (Status != EFI_NOT_READY) {\r
gBS->SignalEvent (CpuMpData->CpuData[ProcessorNumber].WaitEvent);\r
- CpuMpData->CpuData[ProcessorNumber].WaitEvent = NULL;\r
+ CpuMpData->CpuData[ProcessorNumber].WaitEvent = NULL;\r
}\r
}\r
}\r
VOID\r
EFIAPI\r
CheckApsStatus (\r
- IN EFI_EVENT Event,\r
- IN VOID *Context\r
+ IN EFI_EVENT Event,\r
+ IN VOID *Context\r
)\r
{\r
//\r
}\r
}\r
\r
+/**\r
+ Get Protected mode code segment with 16-bit default addressing\r
+ from current GDT table.\r
+\r
+ @return Protected mode 16-bit code segment value.\r
+**/\r
+UINT16\r
+GetProtectedMode16CS (\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.DB == 0)) {\r
+ break;\r
+ }\r
+ }\r
+\r
+ GdtEntry++;\r
+ }\r
+\r
+ ASSERT (Index != GdtEntryCount);\r
+ return Index * 8;\r
+}\r
+\r
/**\r
Get Protected mode code segment from current GDT table.\r
\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
+ 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
+ if ((GdtEntry->Bits.Type > 8) && (GdtEntry->Bits.DB == 1)) {\r
break;\r
}\r
}\r
+\r
GdtEntry++;\r
}\r
- ASSERT (Index != -1);\r
+\r
+ ASSERT (Index != GdtEntryCount);\r
return Index * 8;\r
}\r
\r
IN OUT VOID *Buffer\r
)\r
{\r
- CPU_MP_DATA *CpuMpData;\r
- BOOLEAN MwaitSupport;\r
- ASM_RELOCATE_AP_LOOP AsmRelocateApLoopFunc;\r
- UINTN ProcessorNumber;\r
+ CPU_MP_DATA *CpuMpData;\r
+ BOOLEAN MwaitSupport;\r
+ ASM_RELOCATE_AP_LOOP AsmRelocateApLoopFunc;\r
+ UINTN ProcessorNumber;\r
+ UINTN StackStart;\r
\r
- MpInitLibWhoAmI (&ProcessorNumber); \r
+ MpInitLibWhoAmI (&ProcessorNumber);\r
CpuMpData = GetCpuMpData ();\r
MwaitSupport = IsMwaitSupport ();\r
- AsmRelocateApLoopFunc = (ASM_RELOCATE_AP_LOOP) (UINTN) mReservedApLoopFunc;\r
+ if (CpuMpData->SevEsIsEnabled) {\r
+ StackStart = CpuMpData->SevEsAPResetStackStart;\r
+ } else {\r
+ StackStart = mReservedTopOfApStack;\r
+ }\r
+\r
+ AsmRelocateApLoopFunc = (ASM_RELOCATE_AP_LOOP)(UINTN)mReservedApLoopFunc;\r
AsmRelocateApLoopFunc (\r
MwaitSupport,\r
CpuMpData->ApTargetCState,\r
CpuMpData->PmCodeSegment,\r
- mReservedTopOfApStack - ProcessorNumber * AP_SAFE_STACK_SIZE,\r
- (UINTN) &mNumberToFinish\r
+ StackStart - ProcessorNumber * AP_SAFE_STACK_SIZE,\r
+ (UINTN)&mNumberToFinish,\r
+ CpuMpData->Pm16CodeSegment,\r
+ CpuMpData->SevEsAPBuffer,\r
+ CpuMpData->WakeupBuffer\r
);\r
//\r
// It should never reach here\r
VOID\r
EFIAPI\r
MpInitChangeApLoopCallback (\r
- IN EFI_EVENT Event,\r
- IN VOID *Context\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
- mNumberToFinish = CpuMpData->CpuCount - 1;\r
- WakeUpAP (CpuMpData, TRUE, 0, RelocateApLoop, NULL);\r
+ CPU_MP_DATA *CpuMpData;\r
+\r
+ CpuMpData = GetCpuMpData ();\r
+ CpuMpData->PmCodeSegment = GetProtectedModeCS ();\r
+ CpuMpData->Pm16CodeSegment = GetProtectedMode16CS ();\r
+ CpuMpData->ApLoopMode = PcdGet8 (PcdCpuApLoopMode);\r
+ mNumberToFinish = CpuMpData->CpuCount - 1;\r
+ WakeUpAP (CpuMpData, TRUE, 0, RelocateApLoop, NULL, TRUE);\r
while (mNumberToFinish > 0) {\r
CpuPause ();\r
}\r
+\r
+ if (CpuMpData->SevEsIsEnabled && (CpuMpData->WakeupBuffer != (UINTN)-1)) {\r
+ //\r
+ // There are APs present. Re-use reserved memory area below 1MB from\r
+ // WakeupBuffer as the area to be used for transitioning to 16-bit mode\r
+ // in support of booting of the AP by an OS.\r
+ //\r
+ CopyMem (\r
+ (VOID *)CpuMpData->WakeupBuffer,\r
+ (VOID *)(CpuMpData->AddressMap.RendezvousFunnelAddress +\r
+ CpuMpData->AddressMap.SwitchToRealPM16ModeOffset),\r
+ CpuMpData->AddressMap.SwitchToRealPM16ModeSize\r
+ );\r
+ }\r
+\r
DEBUG ((DEBUG_INFO, "%a() done!\n", __FUNCTION__));\r
}\r
\r
**/\r
VOID\r
InitMpGlobalData (\r
- IN CPU_MP_DATA *CpuMpData\r
+ IN CPU_MP_DATA *CpuMpData\r
)\r
{\r
- EFI_STATUS Status;\r
- EFI_PHYSICAL_ADDRESS Address;\r
- UINTN ApSafeBufferSize;\r
+ EFI_STATUS Status;\r
+ EFI_PHYSICAL_ADDRESS Address;\r
+ UINTN ApSafeBufferSize;\r
+ UINTN Index;\r
+ EFI_GCD_MEMORY_SPACE_DESCRIPTOR MemDesc;\r
+ UINTN StackBase;\r
+ CPU_INFO_IN_HOB *CpuInfoInHob;\r
\r
SaveCpuMpData (CpuMpData);\r
\r
return;\r
}\r
\r
+ if (PcdGetBool (PcdCpuStackGuard)) {\r
+ //\r
+ // One extra page at the bottom of the stack is needed for Guard page.\r
+ //\r
+ if (CpuMpData->CpuApStackSize <= EFI_PAGE_SIZE) {\r
+ DEBUG ((DEBUG_ERROR, "PcdCpuApStackSize is not big enough for Stack Guard!\n"));\r
+ ASSERT (FALSE);\r
+ }\r
+\r
+ //\r
+ // DXE will reuse stack allocated for APs at PEI phase if it's available.\r
+ // Let's check it here.\r
+ //\r
+ // Note: BSP's stack guard is set at DxeIpl phase. But for the sake of\r
+ // BSP/AP exchange, stack guard for ApTopOfStack of cpu 0 will still be\r
+ // set here.\r
+ //\r
+ CpuInfoInHob = (CPU_INFO_IN_HOB *)(UINTN)CpuMpData->CpuInfoInHob;\r
+ for (Index = 0; Index < CpuMpData->CpuCount; ++Index) {\r
+ if ((CpuInfoInHob != NULL) && (CpuInfoInHob[Index].ApTopOfStack != 0)) {\r
+ StackBase = (UINTN)CpuInfoInHob[Index].ApTopOfStack - CpuMpData->CpuApStackSize;\r
+ } else {\r
+ StackBase = CpuMpData->Buffer + Index * CpuMpData->CpuApStackSize;\r
+ }\r
+\r
+ Status = gDS->GetMemorySpaceDescriptor (StackBase, &MemDesc);\r
+ ASSERT_EFI_ERROR (Status);\r
+\r
+ Status = gDS->SetMemorySpaceAttributes (\r
+ StackBase,\r
+ EFI_PAGES_TO_SIZE (1),\r
+ MemDesc.Attributes | EFI_MEMORY_RP\r
+ );\r
+ ASSERT_EFI_ERROR (Status);\r
+\r
+ DEBUG ((\r
+ DEBUG_INFO,\r
+ "Stack Guard set at %lx [cpu%lu]!\n",\r
+ (UINT64)StackBase,\r
+ (UINT64)Index\r
+ ));\r
+ }\r
+ }\r
+\r
//\r
// Avoid APs access invalid buffer data which allocated by BootServices,\r
// so we will allocate reserved data for AP loop code. We also need to\r
// Allocating it in advance since memory services are not available in\r
// Exit Boot Services callback function.\r
//\r
- ApSafeBufferSize = CpuMpData->AddressMap.RelocateApLoopFuncSize;\r
- ApSafeBufferSize += CpuMpData->CpuCount * AP_SAFE_STACK_SIZE;\r
-\r
+ ApSafeBufferSize = EFI_PAGES_TO_SIZE (\r
+ EFI_SIZE_TO_PAGES (\r
+ CpuMpData->AddressMap.RelocateApLoopFuncSize\r
+ )\r
+ );\r
Address = BASE_4GB - 1;\r
Status = gBS->AllocatePages (\r
AllocateMaxAddress,\r
&Address\r
);\r
ASSERT_EFI_ERROR (Status);\r
- mReservedApLoopFunc = (VOID *) (UINTN) Address;\r
+\r
+ mReservedApLoopFunc = (VOID *)(UINTN)Address;\r
ASSERT (mReservedApLoopFunc != NULL);\r
- mReservedTopOfApStack = (UINTN) Address + EFI_PAGES_TO_SIZE (EFI_SIZE_TO_PAGES (ApSafeBufferSize));\r
+\r
+ //\r
+ // Make sure that the buffer memory is executable if NX protection is enabled\r
+ // for EfiReservedMemoryType.\r
+ //\r
+ // TODO: Check EFI_MEMORY_XP bit set or not once it's available in DXE GCD\r
+ // service.\r
+ //\r
+ Status = gDS->GetMemorySpaceDescriptor (Address, &MemDesc);\r
+ if (!EFI_ERROR (Status)) {\r
+ gDS->SetMemorySpaceAttributes (\r
+ Address,\r
+ ApSafeBufferSize,\r
+ MemDesc.Attributes & (~EFI_MEMORY_XP)\r
+ );\r
+ }\r
+\r
+ ApSafeBufferSize = EFI_PAGES_TO_SIZE (\r
+ EFI_SIZE_TO_PAGES (\r
+ CpuMpData->CpuCount * AP_SAFE_STACK_SIZE\r
+ )\r
+ );\r
+ Address = BASE_4GB - 1;\r
+ Status = gBS->AllocatePages (\r
+ AllocateMaxAddress,\r
+ EfiReservedMemoryType,\r
+ EFI_SIZE_TO_PAGES (ApSafeBufferSize),\r
+ &Address\r
+ );\r
+ ASSERT_EFI_ERROR (Status);\r
+\r
+ mReservedTopOfApStack = (UINTN)Address + ApSafeBufferSize;\r
ASSERT ((mReservedTopOfApStack & (UINTN)(CPU_STACK_ALIGNMENT - 1)) == 0);\r
CopyMem (\r
mReservedApLoopFunc,\r
Status = gBS->SetTimer (\r
mCheckAllApsEvent,\r
TimerPeriodic,\r
- AP_CHECK_INTERVAL\r
+ EFI_TIMER_PERIOD_MICROSECONDS (\r
+ PcdGet32 (PcdCpuApStatusCheckIntervalInMicroSeconds)\r
+ )\r
);\r
ASSERT_EFI_ERROR (Status);\r
\r
EFI_STATUS\r
EFIAPI\r
MpInitLibStartupAllAPs (\r
- IN EFI_AP_PROCEDURE Procedure,\r
- IN BOOLEAN SingleThread,\r
- IN EFI_EVENT WaitEvent OPTIONAL,\r
- IN UINTN TimeoutInMicroseconds,\r
- IN VOID *ProcedureArgument OPTIONAL,\r
- OUT UINTN **FailedCpuList OPTIONAL\r
+ IN EFI_AP_PROCEDURE Procedure,\r
+ IN BOOLEAN SingleThread,\r
+ IN EFI_EVENT WaitEvent OPTIONAL,\r
+ IN UINTN TimeoutInMicroseconds,\r
+ IN VOID *ProcedureArgument OPTIONAL,\r
+ OUT UINTN **FailedCpuList OPTIONAL\r
)\r
{\r
- EFI_STATUS Status;\r
+ EFI_STATUS Status;\r
\r
//\r
// Temporarily stop checkAllApsStatus for avoid resource dead-lock.\r
//\r
mStopCheckAllApsStatus = TRUE;\r
\r
- Status = StartupAllAPsWorker (\r
+ Status = StartupAllCPUsWorker (\r
Procedure,\r
SingleThread,\r
+ TRUE,\r
WaitEvent,\r
TimeoutInMicroseconds,\r
ProcedureArgument,\r
EFI_STATUS\r
EFIAPI\r
MpInitLibStartupThisAP (\r
- IN EFI_AP_PROCEDURE Procedure,\r
- IN UINTN ProcessorNumber,\r
- IN EFI_EVENT WaitEvent OPTIONAL,\r
- IN UINTN TimeoutInMicroseconds,\r
- IN VOID *ProcedureArgument OPTIONAL,\r
- OUT BOOLEAN *Finished OPTIONAL\r
+ IN EFI_AP_PROCEDURE Procedure,\r
+ IN UINTN ProcessorNumber,\r
+ IN EFI_EVENT WaitEvent OPTIONAL,\r
+ IN UINTN TimeoutInMicroseconds,\r
+ IN VOID *ProcedureArgument OPTIONAL,\r
+ OUT BOOLEAN *Finished OPTIONAL\r
)\r
{\r
- EFI_STATUS Status;\r
+ EFI_STATUS Status;\r
\r
//\r
// temporarily stop checkAllApsStatus for avoid resource dead-lock.\r
EFI_STATUS\r
EFIAPI\r
MpInitLibSwitchBSP (\r
- IN UINTN ProcessorNumber,\r
- IN BOOLEAN EnableOldBSP\r
+ IN UINTN ProcessorNumber,\r
+ IN BOOLEAN EnableOldBSP\r
)\r
{\r
- EFI_STATUS Status;\r
- BOOLEAN OldInterruptState;\r
+ EFI_STATUS Status;\r
+ EFI_TIMER_ARCH_PROTOCOL *Timer;\r
+ UINT64 TimerPeriod;\r
\r
+ TimerPeriod = 0;\r
//\r
- // Before send both BSP and AP to a procedure to exchange their roles,\r
- // interrupt must be disabled. This is because during the exchange role\r
- // process, 2 CPU may use 1 stack. If interrupt happens, the stack will\r
- // be corrupted, since interrupt return address will be pushed to stack\r
- // by hardware.\r
+ // Locate Timer Arch Protocol\r
//\r
- OldInterruptState = SaveAndDisableInterrupts ();\r
+ Status = gBS->LocateProtocol (&gEfiTimerArchProtocolGuid, NULL, (VOID **)&Timer);\r
+ if (EFI_ERROR (Status)) {\r
+ Timer = NULL;\r
+ }\r
\r
- //\r
- // Mask LINT0 & LINT1 for the old BSP\r
- //\r
- DisableLvtInterrupts ();\r
+ if (Timer != NULL) {\r
+ //\r
+ // Save current rate of DXE Timer\r
+ //\r
+ Timer->GetTimerPeriod (Timer, &TimerPeriod);\r
+ //\r
+ // Disable DXE Timer and drain pending interrupts\r
+ //\r
+ Timer->SetTimerPeriod (Timer, 0);\r
+ }\r
\r
Status = SwitchBSPWorker (ProcessorNumber, EnableOldBSP);\r
\r
- //\r
- // Restore interrupt state.\r
- //\r
- SetInterruptState (OldInterruptState);\r
+ if (Timer != NULL) {\r
+ //\r
+ // Enable and restore rate of DXE Timer\r
+ //\r
+ Timer->SetTimerPeriod (Timer, TimerPeriod);\r
+ }\r
\r
return Status;\r
}\r
EFI_STATUS\r
EFIAPI\r
MpInitLibEnableDisableAP (\r
- IN UINTN ProcessorNumber,\r
- IN BOOLEAN EnableAP,\r
- IN UINT32 *HealthFlag OPTIONAL\r
+ IN UINTN ProcessorNumber,\r
+ IN BOOLEAN EnableAP,\r
+ IN UINT32 *HealthFlag OPTIONAL\r
)\r
{\r
- EFI_STATUS Status;\r
- BOOLEAN TempStopCheckState;\r
+ EFI_STATUS Status;\r
+ BOOLEAN TempStopCheckState;\r
\r
TempStopCheckState = FALSE;\r
//\r
\r
return Status;\r
}\r
+\r
+/**\r
+ This funtion will try to invoke platform specific microcode shadow logic to\r
+ relocate microcode update patches into memory.\r
+\r
+ @param[in, out] CpuMpData The pointer to CPU MP Data structure.\r
+\r
+ @retval EFI_SUCCESS Shadow microcode success.\r
+ @retval EFI_OUT_OF_RESOURCES No enough resource to complete the operation.\r
+ @retval EFI_UNSUPPORTED Can't find platform specific microcode shadow\r
+ PPI/Protocol.\r
+**/\r
+EFI_STATUS\r
+PlatformShadowMicrocode (\r
+ IN OUT CPU_MP_DATA *CpuMpData\r
+ )\r
+{\r
+ //\r
+ // There is no DXE version of platform shadow microcode protocol so far.\r
+ // A platform which only uses DxeMpInitLib instance could only supports\r
+ // the PCD based microcode shadowing.\r
+ //\r
+ return EFI_UNSUPPORTED;\r
+}\r