]> git.proxmox.com Git - mirror_edk2.git/blobdiff - MdeModulePkg/Core/DxeIplPeim/Ia32/DxeLoadFunc.c
MdeModulePkg/DxeIplPeim: reserve page 0 for NULL pointer detection
[mirror_edk2.git] / MdeModulePkg / Core / DxeIplPeim / Ia32 / DxeLoadFunc.c
index 38832cc364e35ebade3e51ee8589244f131e635b..6e8ca824d469e9db51405fc673c41d539e750436 100644 (file)
@@ -1,14 +1,10 @@
 /** @file\r
   Ia32-specific functionality for DxeLoad.\r
 \r
-Copyright (c) 2006 - 2013, 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
+Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>\r
+Copyright (c) 2017, AMD Incorporated. All rights reserved.<BR>\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
+SPDX-License-Identifier: BSD-2-Clause-Patent\r
 \r
 **/\r
 \r
@@ -56,6 +52,169 @@ GLOBAL_REMOVE_IF_UNREFERENCED  IA32_DESCRIPTOR gLidtDescriptor = {
   0\r
 };\r
 \r
+/**\r
+  Allocates and fills in the Page Directory and Page Table Entries to\r
+  establish a 4G page table.\r
+\r
+  @param[in] StackBase  Stack base address.\r
+  @param[in] StackSize  Stack size.\r
+\r
+  @return The address of page table.\r
+\r
+**/\r
+UINTN\r
+Create4GPageTablesIa32Pae (\r
+  IN EFI_PHYSICAL_ADDRESS   StackBase,\r
+  IN UINTN                  StackSize\r
+  )\r
+{\r
+  UINT8                                         PhysicalAddressBits;\r
+  EFI_PHYSICAL_ADDRESS                          PhysicalAddress;\r
+  UINTN                                         IndexOfPdpEntries;\r
+  UINTN                                         IndexOfPageDirectoryEntries;\r
+  UINT32                                        NumberOfPdpEntriesNeeded;\r
+  PAGE_MAP_AND_DIRECTORY_POINTER                *PageMap;\r
+  PAGE_MAP_AND_DIRECTORY_POINTER                *PageDirectoryPointerEntry;\r
+  PAGE_TABLE_ENTRY                              *PageDirectoryEntry;\r
+  UINTN                                         TotalPagesNum;\r
+  UINTN                                         PageAddress;\r
+  UINT64                                        AddressEncMask;\r
+\r
+  //\r
+  // Make sure AddressEncMask is contained to smallest supported address field\r
+  //\r
+  AddressEncMask = PcdGet64 (PcdPteMemoryEncryptionAddressOrMask) & PAGING_1G_ADDRESS_MASK_64;\r
+\r
+  PhysicalAddressBits = 32;\r
+\r
+  //\r
+  // Calculate the table entries needed.\r
+  //\r
+  NumberOfPdpEntriesNeeded = (UINT32) LShiftU64 (1, (PhysicalAddressBits - 30));\r
+\r
+  TotalPagesNum = NumberOfPdpEntriesNeeded + 1;\r
+  PageAddress = (UINTN) AllocatePageTableMemory (TotalPagesNum);\r
+  ASSERT (PageAddress != 0);\r
+\r
+  PageMap = (VOID *) PageAddress;\r
+  PageAddress += SIZE_4KB;\r
+\r
+  PageDirectoryPointerEntry = PageMap;\r
+  PhysicalAddress = 0;\r
+\r
+  for (IndexOfPdpEntries = 0; IndexOfPdpEntries < NumberOfPdpEntriesNeeded; IndexOfPdpEntries++, PageDirectoryPointerEntry++) {\r
+    //\r
+    // Each Directory Pointer entries points to a page of Page Directory entires.\r
+    // So allocate space for them and fill them in in the IndexOfPageDirectoryEntries loop.\r
+    //\r
+    PageDirectoryEntry = (VOID *) PageAddress;\r
+    PageAddress += SIZE_4KB;\r
+\r
+    //\r
+    // Fill in a Page Directory Pointer Entries\r
+    //\r
+    PageDirectoryPointerEntry->Uint64 = (UINT64) (UINTN) PageDirectoryEntry | AddressEncMask;\r
+    PageDirectoryPointerEntry->Bits.Present = 1;\r
+\r
+    for (IndexOfPageDirectoryEntries = 0; IndexOfPageDirectoryEntries < 512; IndexOfPageDirectoryEntries++, PageDirectoryEntry++, PhysicalAddress += SIZE_2MB) {\r
+      if ((IsNullDetectionEnabled () && PhysicalAddress == 0)\r
+          || ((PhysicalAddress < StackBase + StackSize)\r
+              && ((PhysicalAddress + SIZE_2MB) > StackBase))) {\r
+        //\r
+        // Need to split this 2M page that covers stack range.\r
+        //\r
+        Split2MPageTo4K (PhysicalAddress, (UINT64 *) PageDirectoryEntry, StackBase, StackSize);\r
+      } else {\r
+        //\r
+        // Fill in the Page Directory entries\r
+        //\r
+        PageDirectoryEntry->Uint64 = (UINT64) PhysicalAddress | AddressEncMask;\r
+        PageDirectoryEntry->Bits.ReadWrite = 1;\r
+        PageDirectoryEntry->Bits.Present = 1;\r
+        PageDirectoryEntry->Bits.MustBe1 = 1;\r
+      }\r
+    }\r
+  }\r
+\r
+  for (; IndexOfPdpEntries < 512; IndexOfPdpEntries++, PageDirectoryPointerEntry++) {\r
+    ZeroMem (\r
+      PageDirectoryPointerEntry,\r
+      sizeof (PAGE_MAP_AND_DIRECTORY_POINTER)\r
+      );\r
+  }\r
+\r
+  //\r
+  // Protect the page table by marking the memory used for page table to be\r
+  // read-only.\r
+  //\r
+  EnablePageTableProtection ((UINTN)PageMap, FALSE);\r
+\r
+  return (UINTN) PageMap;\r
+}\r
+\r
+/**\r
+  The function will check if IA32 PAE is supported.\r
+\r
+  @retval TRUE      IA32 PAE is supported.\r
+  @retval FALSE     IA32 PAE is not supported.\r
+\r
+**/\r
+BOOLEAN\r
+IsIa32PaeSupport (\r
+  VOID\r
+  )\r
+{\r
+  UINT32            RegEax;\r
+  UINT32            RegEdx;\r
+  BOOLEAN           Ia32PaeSupport;\r
+\r
+  Ia32PaeSupport = FALSE;\r
+  AsmCpuid (0x0, &RegEax, NULL, NULL, NULL);\r
+  if (RegEax >= 0x1) {\r
+    AsmCpuid (0x1, NULL, NULL, NULL, &RegEdx);\r
+    if ((RegEdx & BIT6) != 0) {\r
+      Ia32PaeSupport = TRUE;\r
+    }\r
+  }\r
+\r
+  return Ia32PaeSupport;\r
+}\r
+\r
+/**\r
+  The function will check if page table should be setup or not.\r
+\r
+  @retval TRUE      Page table should be created.\r
+  @retval FALSE     Page table should not be created.\r
+\r
+**/\r
+BOOLEAN\r
+ToBuildPageTable (\r
+  VOID\r
+  )\r
+{\r
+  if (!IsIa32PaeSupport ()) {\r
+    return FALSE;\r
+  }\r
+\r
+  if (IsNullDetectionEnabled ()) {\r
+    return TRUE;\r
+  }\r
+\r
+  if (PcdGet8 (PcdHeapGuardPropertyMask) != 0) {\r
+    return TRUE;\r
+  }\r
+\r
+  if (PcdGetBool (PcdCpuStackGuard)) {\r
+    return TRUE;\r
+  }\r
+\r
+  if (IsEnableNonExecNeeded ()) {\r
+    return TRUE;\r
+  }\r
+\r
+  return FALSE;\r
+}\r
+\r
 /**\r
    Transfers control to DxeCore.\r
 \r
@@ -85,6 +244,15 @@ HandOffToDxeCore (
   X64_IDT_TABLE             *IdtTableForX64;\r
   EFI_VECTOR_HANDOFF_INFO   *VectorInfo;\r
   EFI_PEI_VECTOR_HANDOFF_INFO_PPI *VectorHandoffInfoPpi;\r
+  BOOLEAN                   BuildPageTablesIa32Pae;\r
+\r
+  //\r
+  // Clear page 0 and mark it as allocated if NULL pointer detection is enabled.\r
+  //\r
+  if (IsNullDetectionEnabled ()) {\r
+    ClearFirst4KPage (HobList.Raw);\r
+    BuildMemoryAllocationHob (0, EFI_PAGES_TO_SIZE (1), EfiBootServicesData);\r
+  }\r
 \r
   Status = PeiServicesAllocatePages (EfiBootServicesData, EFI_SIZE_TO_PAGES (STACK_SIZE), &BaseOfStack);\r
   ASSERT_EFI_ERROR (Status);\r
@@ -114,14 +282,21 @@ HandOffToDxeCore (
     //\r
     // Create page table and save PageMapLevel4 to CR3\r
     //\r
-    PageTables = CreateIdentityMappingPageTables ();\r
+    PageTables = CreateIdentityMappingPageTables (BaseOfStack, STACK_SIZE);\r
 \r
     //\r
     // End of PEI phase signal\r
     //\r
+    PERF_EVENT_SIGNAL_BEGIN (gEndOfPeiSignalPpi.Guid);\r
     Status = PeiServicesInstallPpi (&gEndOfPeiSignalPpi);\r
+    PERF_EVENT_SIGNAL_END (gEndOfPeiSignalPpi.Guid);\r
     ASSERT_EFI_ERROR (Status);\r
 \r
+    //\r
+    // Paging might be already enabled. To avoid conflict configuration,\r
+    // disable paging first anyway.\r
+    //\r
+    AsmWriteCr0 (AsmReadCr0 () & (~BIT31));\r
     AsmWriteCr3 (PageTables);\r
 \r
     //\r
@@ -134,7 +309,7 @@ HandOffToDxeCore (
     Status = PeiServicesAllocatePages (\r
                EfiBootServicesData,\r
                EFI_SIZE_TO_PAGES(sizeof (X64_IDT_TABLE) + SizeOfTemplate * IDT_ENTRY_COUNT),\r
-               (EFI_PHYSICAL_ADDRESS *) &IdtTableForX64\r
+               &VectorAddress\r
                );\r
     ASSERT_EFI_ERROR (Status);\r
 \r
@@ -142,6 +317,7 @@ HandOffToDxeCore (
     // Store EFI_PEI_SERVICES** in the 4 bytes immediately preceding IDT to avoid that\r
     // it may not be gotten correctly after IDT register is re-written.\r
     //\r
+    IdtTableForX64 = (X64_IDT_TABLE *) (UINTN) VectorAddress;\r
     IdtTableForX64->PeiService = GetPeiServicesTablePointer ();\r
 \r
     VectorAddress = (EFI_PHYSICAL_ADDRESS) (UINTN) (IdtTableForX64 + 1);\r
@@ -171,6 +347,14 @@ HandOffToDxeCore (
 \r
     AsmWriteIdtr (&gLidtDescriptor);\r
 \r
+    DEBUG ((\r
+      DEBUG_INFO,\r
+      "%a() Stack Base: 0x%lx, Stack Size: 0x%x\n",\r
+      __FUNCTION__,\r
+      BaseOfStack,\r
+      STACK_SIZE\r
+      ));\r
+\r
     //\r
     // Go to Long Mode and transfer control to DxeCore.\r
     // Interrupts will not get turned on until the CPU AP is loaded.\r
@@ -215,26 +399,67 @@ HandOffToDxeCore (
     TopOfStack = BaseOfStack + EFI_SIZE_TO_PAGES (STACK_SIZE) * EFI_PAGE_SIZE - CPU_STACK_ALIGNMENT;\r
     TopOfStack = (EFI_PHYSICAL_ADDRESS) (UINTN) ALIGN_POINTER (TopOfStack, CPU_STACK_ALIGNMENT);\r
 \r
+    PageTables = 0;\r
+    BuildPageTablesIa32Pae = ToBuildPageTable ();\r
+    if (BuildPageTablesIa32Pae) {\r
+      PageTables = Create4GPageTablesIa32Pae (BaseOfStack, STACK_SIZE);\r
+      if (IsEnableNonExecNeeded ()) {\r
+        EnableExecuteDisableBit();\r
+      }\r
+    }\r
+\r
     //\r
     // End of PEI phase signal\r
     //\r
+    PERF_EVENT_SIGNAL_BEGIN (gEndOfPeiSignalPpi.Guid);\r
     Status = PeiServicesInstallPpi (&gEndOfPeiSignalPpi);\r
+    PERF_EVENT_SIGNAL_END (gEndOfPeiSignalPpi.Guid);\r
     ASSERT_EFI_ERROR (Status);\r
 \r
+    if (BuildPageTablesIa32Pae) {\r
+      //\r
+      // Paging might be already enabled. To avoid conflict configuration,\r
+      // disable paging first anyway.\r
+      //\r
+      AsmWriteCr0 (AsmReadCr0 () & (~BIT31));\r
+      AsmWriteCr3 (PageTables);\r
+      //\r
+      // Set Physical Address Extension (bit 5 of CR4).\r
+      //\r
+      AsmWriteCr4 (AsmReadCr4 () | BIT5);\r
+    }\r
+\r
     //\r
     // Update the contents of BSP stack HOB to reflect the real stack info passed to DxeCore.\r
     //\r
     UpdateStackHob (BaseOfStack, STACK_SIZE);\r
 \r
+    DEBUG ((\r
+      DEBUG_INFO,\r
+      "%a() Stack Base: 0x%lx, Stack Size: 0x%x\n",\r
+      __FUNCTION__,\r
+      BaseOfStack,\r
+      STACK_SIZE\r
+      ));\r
+\r
     //\r
     // Transfer the control to the entry point of DxeCore.\r
     //\r
-    SwitchStack (\r
-      (SWITCH_STACK_ENTRY_POINT)(UINTN)DxeCoreEntryPoint,\r
-      HobList.Raw,\r
-      NULL,\r
-      (VOID *) (UINTN) TopOfStack\r
-      );\r
+    if (BuildPageTablesIa32Pae) {\r
+      AsmEnablePaging32 (\r
+        (SWITCH_STACK_ENTRY_POINT)(UINTN)DxeCoreEntryPoint,\r
+        HobList.Raw,\r
+        NULL,\r
+        (VOID *) (UINTN) TopOfStack\r
+        );\r
+    } else {\r
+      SwitchStack (\r
+        (SWITCH_STACK_ENTRY_POINT)(UINTN)DxeCoreEntryPoint,\r
+        HobList.Raw,\r
+        NULL,\r
+        (VOID *) (UINTN) TopOfStack\r
+        );\r
+    }\r
   }\r
 }\r
 \r