#include <Library/UefiLib.h>\r
#include <Library/UefiBootServicesTableLib.h>\r
#include <Library/DebugAgentLib.h>\r
+#include <Library/DxeServicesTableLib.h>\r
\r
#include <Protocol/Timer.h>\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
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 ((DEBUG_INFO, "Stack Guard set at %lx [cpu%lu]!\n",\r
+ (UINT64)StackBase, (UINT64)Index));\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 (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