]> git.proxmox.com Git - mirror_edk2.git/blobdiff - MdeModulePkg/Universal/Acpi/BootScriptExecutorDxe/X64/SetIdtEntry.c
MdeModulePkg/Universal/Acpi/BootScriptExecutorDxe: Add support for PCD PcdPteMemoryEn...
[mirror_edk2.git] / MdeModulePkg / Universal / Acpi / BootScriptExecutorDxe / X64 / SetIdtEntry.c
index e42e6d4fe198eac45ef6d6c984a9eaba4e9ea6b5..d433cf128ccff9f89cdb9474ee285a875c2fb035 100644 (file)
@@ -3,7 +3,9 @@
 \r
   Set a IDT entry for interrupt vector 3 for debug purpose for x64 platform\r
 \r
-Copyright (c) 2006 - 2013, Intel Corporation. All rights reserved.<BR>\r
+Copyright (c) 2006 - 2015, Intel Corporation. All rights reserved.<BR>\r
+Copyright (c) 2017, AMD Incorporated. All rights reserved.<BR>\r
+\r
 \r
 This program and the accompanying materials\r
 are licensed and made available under the terms and conditions of the BSD License\r
@@ -16,13 +18,23 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
 **/\r
 #include "ScriptExecute.h"\r
 \r
+//\r
+// 8 extra pages for PF handler.\r
+//\r
+#define EXTRA_PAGE_TABLE_PAGES      8\r
+\r
 #define IA32_PG_P                   BIT0\r
 #define IA32_PG_RW                  BIT1\r
 #define IA32_PG_PS                  BIT7\r
 \r
-UINT64                             mPhyMask;\r
-VOID                               *mOriginalHandler;\r
-UINTN                              mS3NvsPageTableAddress;\r
+UINT64                              mPhyMask;\r
+VOID                                *mOriginalHandler;\r
+UINTN                               mPageFaultBuffer;\r
+UINTN                               mPageFaultIndex = 0;\r
+//\r
+// Store the uplink information for each page being used.\r
+//\r
+UINT64                              *mPageFaultUplink[EXTRA_PAGE_TABLE_PAGES];\r
 \r
 /**\r
   Page fault handler.\r
@@ -73,10 +85,46 @@ HookPageFaultHandler (
   IdtEntry->Bits.Reserved_1     = 0;\r
 \r
   if (mPage1GSupport) {\r
-    mS3NvsPageTableAddress = (UINTN)(AsmReadCr3 () & mPhyMask) + EFI_PAGES_TO_SIZE(2);\r
+    mPageFaultBuffer = (UINTN)(AsmReadCr3 () & mPhyMask) + EFI_PAGES_TO_SIZE(2);\r
   }else {\r
-    mS3NvsPageTableAddress = (UINTN)(AsmReadCr3 () & mPhyMask) + EFI_PAGES_TO_SIZE(6);\r
+    mPageFaultBuffer = (UINTN)(AsmReadCr3 () & mPhyMask) + EFI_PAGES_TO_SIZE(6);\r
   }\r
+  ZeroMem (mPageFaultUplink, sizeof (mPageFaultUplink));\r
+}\r
+\r
+/**\r
+  The function will check if current waking vector is long mode.\r
+\r
+  @param  AcpiS3Context                 a pointer to a structure of ACPI_S3_CONTEXT\r
+\r
+  @retval TRUE   Current context need long mode waking vector.\r
+  @retval FALSE  Current context need not long mode waking vector.\r
+**/\r
+BOOLEAN\r
+IsLongModeWakingVector (\r
+  IN ACPI_S3_CONTEXT                *AcpiS3Context\r
+  )\r
+{\r
+  EFI_ACPI_4_0_FIRMWARE_ACPI_CONTROL_STRUCTURE  *Facs;\r
+\r
+  Facs = (EFI_ACPI_4_0_FIRMWARE_ACPI_CONTROL_STRUCTURE *) ((UINTN) (AcpiS3Context->AcpiFacsTable));\r
+  if ((Facs == NULL) ||\r
+      (Facs->Signature != EFI_ACPI_4_0_FIRMWARE_ACPI_CONTROL_STRUCTURE_SIGNATURE) ||\r
+      ((Facs->FirmwareWakingVector == 0) && (Facs->XFirmwareWakingVector == 0)) ) {\r
+    // Something wrong with FACS\r
+    return FALSE;\r
+  }\r
+  if (Facs->XFirmwareWakingVector != 0) {\r
+    if ((Facs->Version == EFI_ACPI_4_0_FIRMWARE_ACPI_CONTROL_STRUCTURE_VERSION) &&\r
+        ((Facs->Flags & EFI_ACPI_4_0_64BIT_WAKE_SUPPORTED_F) != 0) &&\r
+        ((Facs->Flags & EFI_ACPI_4_0_OSPM_64BIT_WAKE__F) != 0)) {\r
+      // Both BIOS and OS wants 64bit vector\r
+      if (FeaturePcdGet (PcdDxeIplSwitchToLongMode)) {\r
+        return TRUE;\r
+      }\r
+    }\r
+  }\r
+  return FALSE;\r
 }\r
 \r
 /**\r
@@ -124,27 +172,48 @@ SetIdtEntry (
     }\r
   );\r
 \r
-  IdtEntry = (IA32_IDT_GATE_DESCRIPTOR *)(IdtDescriptor->Base + (14 * sizeof (IA32_IDT_GATE_DESCRIPTOR)));\r
-  HookPageFaultHandler (IdtEntry);\r
+  //\r
+  // If both BIOS and OS wants long mode waking vector,\r
+  // S3ResumePei should have established 1:1 Virtual to Physical identity mapping page table,\r
+  // no need to hook page fault handler.\r
+  //\r
+  if (!IsLongModeWakingVector (AcpiS3Context)) {\r
+    IdtEntry = (IA32_IDT_GATE_DESCRIPTOR *)(IdtDescriptor->Base + (14 * sizeof (IA32_IDT_GATE_DESCRIPTOR)));\r
+    HookPageFaultHandler (IdtEntry);\r
+  }\r
 }\r
 \r
 /**\r
-  Get new page address.\r
+  Acquire page for page fault.\r
 \r
-  @param  PageNum  new page number needed\r
+  @param[in, out] Uplink        Pointer to up page table entry.\r
 \r
-  @return new page address\r
 **/\r
-UINTN\r
-GetNewPage (\r
-  IN UINTN  PageNum\r
+VOID\r
+AcquirePage (\r
+  IN OUT UINT64                 *Uplink\r
   )\r
 {\r
-  UINTN  NewPage;\r
-  NewPage = mS3NvsPageTableAddress;\r
-  ZeroMem ((VOID *)NewPage, EFI_PAGES_TO_SIZE(PageNum));\r
-  mS3NvsPageTableAddress += EFI_PAGES_TO_SIZE(PageNum);\r
-  return NewPage;\r
+  UINTN             Address;\r
+\r
+  Address = mPageFaultBuffer + EFI_PAGES_TO_SIZE (mPageFaultIndex);\r
+  ZeroMem ((VOID *) Address, EFI_PAGES_TO_SIZE (1));\r
+\r
+  //\r
+  // Cut the previous uplink if it exists and wasn't overwritten.\r
+  //\r
+  if ((mPageFaultUplink[mPageFaultIndex] != NULL) &&\r
+     ((*mPageFaultUplink[mPageFaultIndex] & ~mAddressEncMask & mPhyMask) == Address)) {\r
+    *mPageFaultUplink[mPageFaultIndex] = 0;\r
+  }\r
+\r
+  //\r
+  // Link & Record the current uplink.\r
+  //\r
+  *Uplink = Address | mAddressEncMask | IA32_PG_P | IA32_PG_RW;\r
+  mPageFaultUplink[mPageFaultIndex] = Uplink;\r
+\r
+  mPageFaultIndex = (mPageFaultIndex + 1) % EXTRA_PAGE_TABLE_PAGES;\r
 }\r
 \r
 /**\r
@@ -177,21 +246,21 @@ PageFaultHandler (
   PTIndex = BitFieldRead64 (PFAddress, 39, 47);\r
   // PML4E\r
   if ((PageTable[PTIndex] & IA32_PG_P) == 0) {\r
-    PageTable[PTIndex] = GetNewPage (1) | IA32_PG_P | IA32_PG_RW;\r
+    AcquirePage (&PageTable[PTIndex]);\r
   }\r
-  PageTable = (UINT64*)(UINTN)(PageTable[PTIndex] & mPhyMask);\r
+  PageTable = (UINT64*)(UINTN)(PageTable[PTIndex] & ~mAddressEncMask & mPhyMask);\r
   PTIndex = BitFieldRead64 (PFAddress, 30, 38);\r
   // PDPTE\r
   if (mPage1GSupport) {\r
-    PageTable[PTIndex] = PFAddress | IA32_PG_P | IA32_PG_RW | IA32_PG_PS;\r
+    PageTable[PTIndex] = ((PFAddress | mAddressEncMask) & ~((1ull << 30) - 1)) | IA32_PG_P | IA32_PG_RW | IA32_PG_PS;\r
   } else {\r
     if ((PageTable[PTIndex] & IA32_PG_P) == 0) {\r
-      PageTable[PTIndex] = GetNewPage (1) | IA32_PG_P | IA32_PG_RW;\r
+      AcquirePage (&PageTable[PTIndex]);\r
     }\r
-    PageTable = (UINT64*)(UINTN)(PageTable[PTIndex] & mPhyMask);\r
+    PageTable = (UINT64*)(UINTN)(PageTable[PTIndex] & ~mAddressEncMask & mPhyMask);\r
     PTIndex = BitFieldRead64 (PFAddress, 21, 29);\r
     // PD\r
-    PageTable[PTIndex] = PFAddress | IA32_PG_P | IA32_PG_RW | IA32_PG_PS;\r
+    PageTable[PTIndex] = ((PFAddress | mAddressEncMask) & ~((1ull << 21) - 1)) | IA32_PG_P | IA32_PG_RW | IA32_PG_PS;\r
   }\r
 \r
   return TRUE;\r