/** @file\r
MP initialize support functions for DXE phase.\r
\r
- Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>\r
+ Copyright (c) 2016 - 2018, 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
}\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
// 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