]> git.proxmox.com Git - mirror_edk2.git/blobdiff - UefiCpuPkg/Library/MpInitLib/DxeMpLib.c
UefiCpuPkg: Clean up source files
[mirror_edk2.git] / UefiCpuPkg / Library / MpInitLib / DxeMpLib.c
index 5e50b4c391df7029b52004407b7fc9f8568bc274..d82e9aea45c0c0a4bfc607c691b7f23350606068 100644 (file)
@@ -1,7 +1,7 @@
 /** @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
@@ -17,6 +17,7 @@
 #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
@@ -75,72 +76,75 @@ SaveCpuMpData (
 }\r
 \r
 /**\r
-  Allocate reset vector buffer.\r
+  Get available system memory below 1MB 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
-\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
+  EFI_STATUS              Status;\r
+  EFI_PHYSICAL_ADDRESS    StartAddress;\r
+\r
+  StartAddress = BASE_1MB;\r
+  Status = gBS->AllocatePages (\r
+                  AllocateMaxAddress,\r
+                  EfiBootServicesData,\r
+                  EFI_SIZE_TO_PAGES (WakeupBufferSize),\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
-\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
+    DEBUG ((DEBUG_INFO, "WakeupBufferStart = %x, WakeupBufferSize = %x\n",\r
+                        (UINTN) StartAddress, WakeupBufferSize));\r
+  } else {\r
+    StartAddress = (EFI_PHYSICAL_ADDRESS) -1;\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
-\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
+  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
@@ -264,7 +268,7 @@ RelocateApLoop (
   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
@@ -299,7 +303,6 @@ MpInitChangeApLoopCallback (
   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
@@ -320,9 +323,13 @@ InitMpGlobalData (
   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
@@ -333,6 +340,46 @@ InitMpGlobalData (
     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
@@ -341,9 +388,9 @@ InitMpGlobalData (
   // 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
@@ -352,9 +399,39 @@ InitMpGlobalData (
                    &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
@@ -651,6 +728,7 @@ MpInitLibSwitchBSP (
   EFI_TIMER_ARCH_PROTOCOL      *Timer;\r
   UINT64                       TimerPeriod;\r
 \r
+  TimerPeriod = 0;\r
   //\r
   // Locate Timer Arch Protocol\r
   //\r