/** @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
}\r
\r
/**\r
- Get available system memory below 1MB by specified size.\r
+ Get available system memory below 0x88000 by specified size.\r
\r
@param[in] WakeupBufferSize Wakeup buffer size required\r
\r
EFI_STATUS Status;\r
EFI_PHYSICAL_ADDRESS StartAddress;\r
\r
- StartAddress = BASE_1MB;\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
+ StartAddress = 0x88000;\r
Status = gBS->AllocatePages (\r
AllocateMaxAddress,\r
EfiBootServicesData,\r
&StartAddress\r
);\r
ASSERT_EFI_ERROR (Status);\r
- if (!EFI_ERROR (Status)) {\r
- Status = gBS->FreePages(\r
- StartAddress,\r
- EFI_SIZE_TO_PAGES (WakeupBufferSize)\r
- );\r
- ASSERT_EFI_ERROR (Status);\r
- DEBUG ((DEBUG_INFO, "WakeupBufferStart = %x, WakeupBufferSize = %x\n",\r
- (UINTN) StartAddress, WakeupBufferSize));\r
- } else {\r
+ if (EFI_ERROR (Status)) {\r
StartAddress = (EFI_PHYSICAL_ADDRESS) -1;\r
}\r
+\r
+ DEBUG ((DEBUG_INFO, "WakeupBufferStart = %x, WakeupBufferSize = %x\n",\r
+ (UINTN) StartAddress, WakeupBufferSize));\r
+\r
return (UINTN) StartAddress;\r
}\r
\r
+/**\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] 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
+UINTN\r
+GetModeTransitionBuffer (\r
+ IN UINTN BufferSize\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_PHYSICAL_ADDRESS StartAddress;\r
+\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
Checks APs status and updates APs status if needed.\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
}\r
GdtEntry++;\r
}\r
- ASSERT (Index != -1);\r
+ ASSERT (Index != GdtEntryCount);\r
return Index * 8;\r
}\r
\r
ASM_RELOCATE_AP_LOOP AsmRelocateApLoopFunc;\r
UINTN ProcessorNumber;\r
\r
- MpInitLibWhoAmI (&ProcessorNumber); \r
+ MpInitLibWhoAmI (&ProcessorNumber);\r
CpuMpData = GetCpuMpData ();\r
MwaitSupport = IsMwaitSupport ();\r
AsmRelocateApLoopFunc = (ASM_RELOCATE_AP_LOOP) (UINTN) mReservedApLoopFunc;\r
CpuMpData->PmCodeSegment = GetProtectedModeCS ();\r
CpuMpData->ApLoopMode = PcdGet8 (PcdCpuApLoopMode);\r
mNumberToFinish = CpuMpData->CpuCount - 1;\r
- WakeUpAP (CpuMpData, TRUE, 0, RelocateApLoop, NULL);\r
+ WakeUpAP (CpuMpData, TRUE, 0, RelocateApLoop, NULL, TRUE);\r
while (mNumberToFinish > 0) {\r
CpuPause ();\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 = CpuInfoInHob[Index].ApTopOfStack - CpuMpData->CpuApStackSize;\r
+ StackBase = (UINTN)CpuInfoInHob[Index].ApTopOfStack - CpuMpData->CpuApStackSize;\r
} else {\r
StackBase = CpuMpData->Buffer + Index * CpuMpData->CpuApStackSize;\r
}\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 (EFI_SIZE_TO_PAGES (\r
+ CpuMpData->AddressMap.RelocateApLoopFuncSize\r
+ ));\r
Address = BASE_4GB - 1;\r
Status = gBS->AllocatePages (\r
AllocateMaxAddress,\r
&Address\r
);\r
ASSERT_EFI_ERROR (Status);\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 (EFI_SIZE_TO_PAGES (\r
+ CpuMpData->CpuCount * AP_SAFE_STACK_SIZE\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
//\r
mStopCheckAllApsStatus = TRUE;\r
\r
- Status = StartupAllAPsWorker (\r
+ Status = StartupAllCPUsWorker (\r
Procedure,\r
SingleThread,\r
+ TRUE,\r
WaitEvent,\r
TimeoutInMicroseconds,\r
ProcedureArgument,\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] 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