]> git.proxmox.com Git - mirror_edk2.git/blobdiff - MdeModulePkg/Core/DxeIplPeim/Ia32/DxeLoadFunc.c
MdeModulePkg DxeIpl: Add stack NX support
[mirror_edk2.git] / MdeModulePkg / Core / DxeIplPeim / Ia32 / DxeLoadFunc.c
index 38832cc364e35ebade3e51ee8589244f131e635b..c1ff4b7e64340526485ed7d6467f15834e5c70f3 100644 (file)
@@ -1,7 +1,7 @@
 /** @file\r
   Ia32-specific functionality for DxeLoad.\r
 \r
-Copyright (c) 2006 - 2013, Intel Corporation. All rights reserved.<BR>\r
+Copyright (c) 2006 - 2015, 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
@@ -56,6 +56,151 @@ 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
+\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) AllocatePages (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;\r
+    PageDirectoryPointerEntry->Bits.Present = 1;\r
+\r
+    for (IndexOfPageDirectoryEntries = 0; IndexOfPageDirectoryEntries < 512; IndexOfPageDirectoryEntries++, PageDirectoryEntry++, PhysicalAddress += SIZE_2MB) {\r
+      if ((PhysicalAddress < StackBase + StackSize) && ((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;\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
+  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 Execute Disable Bit is available.\r
+\r
+  @retval TRUE      Execute Disable Bit is available.\r
+  @retval FALSE     Execute Disable Bit is not available.\r
+\r
+**/\r
+BOOLEAN\r
+IsExecuteDisableBitAvailable (\r
+  VOID\r
+  )\r
+{\r
+  UINT32            RegEax;\r
+  UINT32            RegEdx;\r
+  BOOLEAN           Available;\r
+\r
+  Available = FALSE;\r
+  AsmCpuid (0x80000000, &RegEax, NULL, NULL, NULL);\r
+  if (RegEax >= 0x80000001) {\r
+    AsmCpuid (0x80000001, NULL, NULL, NULL, &RegEdx);\r
+    if ((RegEdx & BIT20) != 0) {\r
+      //\r
+      // Bit 20: Execute Disable Bit available.\r
+      //\r
+      Available = TRUE;\r
+    }\r
+  }\r
+\r
+  return Available;\r
+}\r
+\r
 /**\r
    Transfers control to DxeCore.\r
 \r
@@ -85,6 +230,7 @@ HandOffToDxeCore (
   X64_IDT_TABLE             *IdtTableForX64;\r
   EFI_VECTOR_HANDOFF_INFO   *VectorInfo;\r
   EFI_PEI_VECTOR_HANDOFF_INFO_PPI *VectorHandoffInfoPpi;\r
+  BOOLEAN                   BuildPageTablesIa32Pae;\r
 \r
   Status = PeiServicesAllocatePages (EfiBootServicesData, EFI_SIZE_TO_PAGES (STACK_SIZE), &BaseOfStack);\r
   ASSERT_EFI_ERROR (Status);\r
@@ -114,7 +260,7 @@ 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
@@ -215,12 +361,26 @@ 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
+    BuildPageTablesIa32Pae = (BOOLEAN) (PcdGetBool (PcdSetNxForStack) && IsIa32PaeSupport () && IsExecuteDisableBitAvailable ());\r
+    if (BuildPageTablesIa32Pae) {\r
+      PageTables = Create4GPageTablesIa32Pae (BaseOfStack, STACK_SIZE);\r
+      EnableExecuteDisableBit ();\r
+    }\r
+\r
     //\r
     // End of PEI phase signal\r
     //\r
     Status = PeiServicesInstallPpi (&gEndOfPeiSignalPpi);\r
     ASSERT_EFI_ERROR (Status);\r
 \r
+    if (BuildPageTablesIa32Pae) {\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
@@ -229,12 +389,21 @@ HandOffToDxeCore (
     //\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