]> git.proxmox.com Git - mirror_edk2.git/commitdiff
Create 4G page table by default, and using PF to handle >4G MMIO access, to improve...
authorjyao1 <jyao1@6f19259b-4bc3-4df7-8a09-765794883524>
Tue, 14 Aug 2012 04:42:50 +0000 (04:42 +0000)
committerjyao1 <jyao1@6f19259b-4bc3-4df7-8a09-765794883524>
Tue, 14 Aug 2012 04:42:50 +0000 (04:42 +0000)
signed-off-by: jiewen.yao@intel.com
reviewed-by: rui.sun@intel.com

git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@13631 6f19259b-4bc3-4df7-8a09-765794883524

MdeModulePkg/Universal/Acpi/BootScriptExecutorDxe/BootScriptExecutorDxe.inf
MdeModulePkg/Universal/Acpi/BootScriptExecutorDxe/IA32/SetIdtEntry.c
MdeModulePkg/Universal/Acpi/BootScriptExecutorDxe/X64/S3Asm.S
MdeModulePkg/Universal/Acpi/BootScriptExecutorDxe/X64/S3Asm.asm
MdeModulePkg/Universal/Acpi/BootScriptExecutorDxe/X64/SetIdtEntry.c
UefiCpuPkg/Universal/Acpi/S3Resume2Pei/S3Resume.c

index 2fbbdb2e315029166e929a33c23eeb41a7a4c99f..04d4893a97c1c920de4937bf7d2d8cd9ed7959bd 100644 (file)
@@ -78,6 +78,9 @@
 [FeaturePcd]\r
   gEfiMdeModulePkgTokenSpaceGuid.PcdDxeIplSwitchToLongMode\r
 \r
+[Pcd]\r
+  gEfiMdeModulePkgTokenSpaceGuid.PcdUse1GPageTable\r
+\r
 [Depex]\r
   gEfiLockBoxProtocolGuid\r
 \r
index 8221be6c8729e44d963fb09cd6eace399a4927f9..9f04959cd98404751e5164c9003b1f13c1698c9d 100644 (file)
@@ -3,7 +3,7 @@
 \r
   Set a IDT entry for interrupt vector 3 for debug purpose for IA32 platform\r
 \r
-Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.<BR>\r
+Copyright (c) 2006 - 2012, Intel Corporation. All rights reserved.<BR>\r
 \r
 This program and the accompanying materials\r
 are licensed and made available under the terms and conditions of the BSD License\r
@@ -54,7 +54,7 @@ SetIdtEntry (
   S3DebugBuffer = (UINTN) (AcpiS3Context->S3DebugBufferAddress);\r
 \r
   IdtEntry->OffsetLow       = (UINT16)S3DebugBuffer;\r
-  IdtEntry->SegmentSelector = (UINT16)AsmReadCs ();;\r
+  IdtEntry->SegmentSelector = (UINT16)AsmReadCs ();\r
   IdtEntry->Attributes      = (UINT16)INTERRUPT_GATE_ATTRIBUTE;\r
   IdtEntry->OffsetHigh      = (UINT16)(S3DebugBuffer >> 16);\r
 \r
index 7f5bdebfd214fbf1e5775132bf8e8a076a07c8f6..dcce6fb6aefd201fc446bb8b49ee1ccc4803e9d3 100644 (file)
@@ -2,7 +2,7 @@
 #   This is the assembly code for transferring to control to OS S3 waking vector\r
 #   for X64 platform\r
 #\r
-# Copyright (c) 2006, Intel Corporation. All rights reserved.<BR>\r
+# Copyright (c) 2006 - 2012, Intel Corporation. All rights reserved.<BR>\r
 #\r
 # This program and the accompanying materials are\r
 # licensed and made available under the terms and conditions of the BSD License\r
@@ -80,3 +80,51 @@ ASM_PFX(AsmTransferControl16):
 ASM_GLOBAL ASM_PFX(AsmJmpAddr32)\r
 ASM_PFX(AsmJmpAddr32):\r
     .long    0\r
+\r
+ASM_GLOBAL ASM_PFX(PageFaultHandlerHook)\r
+ASM_PFX(PageFaultHandlerHook):\r
+    pushq    %rax                         # save all volatile registers\r
+    pushq    %rcx\r
+    pushq    %rdx\r
+    pushq    %r8\r
+    pushq    %r9\r
+    pushq    %r10\r
+    pushq    %r11\r
+    # save volatile fp registers\r
+    addq     $-0x68, %rsp\r
+    stmxcsr  0x60(%rsp)\r
+    movdqa   %xmm0, 0x0(%rsp) \r
+    movdqa   %xmm1, 0x10(%rsp) \r
+    movdqa   %xmm2, 0x20(%rsp) \r
+    movdqa   %xmm3, 0x30(%rsp) \r
+    movdqa   %xmm4, 0x40(%rsp) \r
+    movdqa   %xmm5, 0x50(%rsp) \r
+\r
+    addq     $-0x20, %rsp\r
+    call     ASM_PFX(PageFaultHandler)\r
+    addq     $0x20, %rsp\r
+\r
+    # load volatile fp registers\r
+    ldmxcsr  0x60(%rsp)\r
+    movdqa   0x0(%rsp), %xmm0\r
+    movdqa   0x10(%rsp), %xmm1\r
+    movdqa   0x20(%rsp), %xmm2\r
+    movdqa   0x30(%rsp), %xmm3\r
+    movdqa   0x40(%rsp), %xmm4\r
+    movdqa   0x50(%rsp), %xmm5\r
+    addq     $0x68, %rsp\r
+\r
+    testb    %al, %al\r
+\r
+    popq     %r11\r
+    popq     %r10\r
+    popq     %r9\r
+    popq     %r8\r
+    popq     %rdx\r
+    popq     %rcx\r
+    popq     %rax                         # restore all volatile registers\r
+    jnz      L1\r
+    jmpq     *ASM_PFX(mOriginalHandler)\r
+L1:\r
+    addq     $0x08, %rsp                  # skip error code for PF\r
+    iretq\r
index f3d327df75c894699aa02a5ffa5bb8a881dceea7..0b7432daf7cfe99e6d61d6c949f4fa4cfec716f0 100644 (file)
@@ -2,7 +2,7 @@
 ;   This is the assembly code for transferring to control to OS S3 waking vector\r
 ;   for X64 platform\r
 ;\r
-; Copyright (c) 2006, Intel Corporation. All rights reserved.<BR>\r
+; Copyright (c) 2006 - 2012, Intel Corporation. All rights reserved.<BR>\r
 ;\r
 ; This program and the accompanying materials\r
 ; are licensed and made available under the terms and conditions of the BSD License\r
@@ -14,6 +14,9 @@
 ;\r
 ;;\r
 \r
+EXTERN mOriginalHandler:QWORD\r
+EXTERN PageFaultHandler:PROC\r
+\r
     .code\r
     \r
 EXTERNDEF   AsmFixAddress16:DWORD\r
@@ -81,4 +84,52 @@ AsmTransferControl16  PROC
 AsmJmpAddr32 DD  ?\r
 AsmTransferControl16  ENDP\r
 \r
+PageFaultHandlerHook PROC\r
+    push    rax                         ; save all volatile registers\r
+    push    rcx\r
+    push    rdx\r
+    push    r8\r
+    push    r9\r
+    push    r10\r
+    push    r11\r
+    ; save volatile fp registers\r
+    add     rsp, -68h\r
+    stmxcsr [rsp + 60h]\r
+    movdqa  [rsp + 0h], xmm0\r
+    movdqa  [rsp + 10h], xmm1\r
+    movdqa  [rsp + 20h], xmm2\r
+    movdqa  [rsp + 30h], xmm3\r
+    movdqa  [rsp + 40h], xmm4\r
+    movdqa  [rsp + 50h], xmm5\r
+\r
+    add     rsp, -20h\r
+    call    PageFaultHandler\r
+    add     rsp, 20h\r
+    \r
+    ; load volatile fp registers\r
+    ldmxcsr [rsp + 60h]\r
+    movdqa  xmm0,  [rsp + 0h]\r
+    movdqa  xmm1,  [rsp + 10h]\r
+    movdqa  xmm2,  [rsp + 20h]\r
+    movdqa  xmm3,  [rsp + 30h]\r
+    movdqa  xmm4,  [rsp + 40h]\r
+    movdqa  xmm5,  [rsp + 50h]\r
+    add     rsp, 68h\r
+\r
+    test    al, al\r
+    \r
+    pop     r11\r
+    pop     r10\r
+    pop     r9\r
+    pop     r8\r
+    pop     rdx\r
+    pop     rcx\r
+    pop     rax                         ; restore all volatile registers\r
+    jnz     @F\r
+    jmp     mOriginalHandler\r
+@@:\r
+    add     rsp, 08h                    ; skip error code for PF\r
+    iretq\r
+PageFaultHandlerHook ENDP\r
+\r
     END\r
index 975cf3a561757f5c1c8b034ca7b12b329e27d463..db11697e7c00c7f5a1ed90d7ba0e08caa3b97a4d 100644 (file)
@@ -33,6 +33,63 @@ typedef struct {
 #define INTERRUPT_GATE_ATTRIBUTE   0x8e00\r
 \r
 #pragma pack()\r
+\r
+#define IA32_PG_P                   BIT0\r
+#define IA32_PG_RW                  BIT1\r
+#define IA32_PG_PS                  BIT7\r
+\r
+UINT64                             mPhyMask;\r
+BOOLEAN                            mPage1GSupport;\r
+VOID                               *mOriginalHandler;\r
+UINTN                              mS3NvsPageTableAddress;\r
+\r
+VOID\r
+EFIAPI\r
+PageFaultHandlerHook (\r
+  VOID\r
+  );\r
+\r
+VOID\r
+HookPageFaultHandler (\r
+  IN INTERRUPT_GATE_DESCRIPTOR                     *IdtEntry\r
+  )\r
+{\r
+  UINT32         RegEax;\r
+  UINT32         RegEdx;\r
+\r
+  AsmCpuid (0x80000008, &RegEax, NULL, NULL, NULL);\r
+  mPhyMask = LShiftU64 (1, (UINT8)RegEax) - 1;\r
+  mPhyMask &= (1ull << 48) - SIZE_4KB;\r
+\r
+  mPage1GSupport = FALSE;\r
+  if (PcdGetBool(PcdUse1GPageTable)) {\r
+    AsmCpuid (0x80000000, &RegEax, NULL, NULL, NULL);\r
+    if (RegEax >= 0x80000001) {\r
+      AsmCpuid (0x80000001, NULL, NULL, NULL, &RegEdx);\r
+      if ((RegEdx & BIT26) != 0) {\r
+        mPage1GSupport = TRUE;\r
+      }\r
+    }\r
+  }\r
+\r
+  //\r
+  // Set Page Fault entry to catch >4G access\r
+  //\r
+  mOriginalHandler = (VOID *)(UINTN)(LShiftU64 (IdtEntry->Offset63To32, 32) + IdtEntry->Offset15To0 + (IdtEntry->Offset31To16 << 16));\r
+  IdtEntry->Offset15To0     = (UINT16)((UINTN)PageFaultHandlerHook);\r
+  IdtEntry->SegmentSelector = (UINT16)AsmReadCs ();\r
+  IdtEntry->Attributes      = (UINT16)INTERRUPT_GATE_ATTRIBUTE;\r
+  IdtEntry->Offset31To16    = (UINT16)((UINTN)PageFaultHandlerHook >> 16);\r
+  IdtEntry->Offset63To32    = (UINT32)((UINTN)PageFaultHandlerHook >> 32);\r
+  IdtEntry->Reserved        = 0;\r
+\r
+  if (mPage1GSupport) {\r
+    mS3NvsPageTableAddress = (UINTN)(AsmReadCr3 () & mPhyMask) + EFI_PAGES_TO_SIZE(2);\r
+  }else {\r
+    mS3NvsPageTableAddress = (UINTN)(AsmReadCr3 () & mPhyMask) + EFI_PAGES_TO_SIZE(6);\r
+  }\r
+}\r
+\r
 /**\r
   Set a IDT entry for interrupt vector 3 for debug purpose.\r
 \r
@@ -66,11 +123,69 @@ SetIdtEntry (
   S3DebugBuffer = (UINTN) (AcpiS3Context->S3DebugBufferAddress);\r
 \r
   IdtEntry->Offset15To0     = (UINT16)S3DebugBuffer;\r
-  IdtEntry->SegmentSelector = (UINT16)AsmReadCs ();;\r
+  IdtEntry->SegmentSelector = (UINT16)AsmReadCs ();\r
   IdtEntry->Attributes      = (UINT16)INTERRUPT_GATE_ATTRIBUTE;\r
   IdtEntry->Offset31To16    = (UINT16)(S3DebugBuffer >> 16);\r
   IdtEntry->Offset63To32    = (UINT32)(S3DebugBuffer >> 32);\r
   IdtEntry->Reserved        = 0;\r
 \r
+  IdtEntry = (INTERRUPT_GATE_DESCRIPTOR *)(IdtDescriptor->Base + (14 * sizeof (INTERRUPT_GATE_DESCRIPTOR)));\r
+  HookPageFaultHandler (IdtEntry);\r
+\r
+  AsmWriteIdtr (IdtDescriptor);\r
+}\r
+\r
+UINTN\r
+GetNewPage (\r
+  IN UINTN  PageNum\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
 }\r
 \r
+BOOLEAN\r
+EFIAPI\r
+PageFaultHandler (\r
+  VOID\r
+  )\r
+{\r
+  UINT64         *PageTable;\r
+  UINT64         PFAddress;\r
+  UINTN          PTIndex;\r
+\r
+  PFAddress = AsmReadCr2 ();\r
+  DEBUG ((EFI_D_ERROR, "BootScript - PageFaultHandler: Cr2 - %lx\n", PFAddress));\r
+\r
+  if (PFAddress >= mPhyMask + SIZE_4KB) {\r
+    return FALSE;\r
+  }\r
+  PFAddress &= mPhyMask;\r
+\r
+  PageTable = (UINT64*)(UINTN)(AsmReadCr3 () & mPhyMask);\r
+\r
+  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
+  }\r
+  PageTable = (UINT64*)(UINTN)(PageTable[PTIndex] & 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
+  } else {\r
+    if ((PageTable[PTIndex] & IA32_PG_P) == 0) {\r
+      PageTable[PTIndex] = GetNewPage (1) | IA32_PG_P | IA32_PG_RW;\r
+    }\r
+    PageTable = (UINT64*)(UINTN)(PageTable[PTIndex] & mPhyMask);\r
+    PTIndex = BitFieldRead64 (PFAddress, 21, 29);\r
+    // PD\r
+    PageTable[PTIndex] = PFAddress | IA32_PG_P | IA32_PG_RW | IA32_PG_PS;\r
+  }\r
+\r
+  return TRUE;\r
+}\r
index 189f0c50c4a784ffa8394f5a040c27fda8d8c4af..de3aec85e185375cce9660e05c219160d461b741 100644 (file)
@@ -367,6 +367,41 @@ WriteToOsS3PerformanceData (
   PerfHeader->S3EntryNum = (UINT32) Index;\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
   Jump to OS waking vector.\r
   The function will install boot script done PPI, report S3 resume status code, and then jump to OS waking vector.\r
@@ -483,10 +518,12 @@ S3ResumeBootOs (
   If BootScriptExector driver will not run in 64-bit mode, this function will do nothing. \r
 \r
   @param S3NvsPageTableAddress   PageTableAddress in ACPINvs\r
+  @param Build4GPageTableOnly    If BIOS just build 4G page table only\r
 **/\r
 VOID\r
 RestoreS3PageTables (\r
-  IN UINTN                                         S3NvsPageTableAddress\r
+  IN UINTN                                         S3NvsPageTableAddress,\r
+  IN BOOLEAN                                       Build4GPageTableOnly\r
   )\r
 {\r
   if (FeaturePcdGet (PcdDxeIplSwitchToLongMode)) {\r
@@ -513,7 +550,7 @@ RestoreS3PageTables (
     //\r
     // The assumption is : whole page table is allocated in CONTINOUS memory and CR3 points to TOP page.\r
     //\r
-    DEBUG ((EFI_D_ERROR, "S3NvsPageTableAddress - %x\n", S3NvsPageTableAddress));\r
+    DEBUG ((EFI_D_ERROR, "S3NvsPageTableAddress - %x (%x)\n", (UINTN)S3NvsPageTableAddress, (UINTN)Build4GPageTableOnly));\r
 \r
     //\r
     // By architecture only one PageMapLevel4 exists - so lets allocate storgage for it.\r
@@ -556,6 +593,14 @@ RestoreS3PageTables (
       PhysicalAddressBits = 48;\r
     }\r
 \r
+    //\r
+    // NOTE: In order to save time to create full page table, we just create 4G page table by default.\r
+    // And let PF handler in BootScript driver to create more on request.\r
+    //\r
+    if (Build4GPageTableOnly) {\r
+      PhysicalAddressBits = 32;\r
+      ZeroMem (PageMap, EFI_PAGES_TO_SIZE(2));\r
+    }\r
     //\r
     // Calculate the table entries needed.\r
     //\r
@@ -827,6 +872,7 @@ S3RestoreConfig2 (
   EFI_SMRAM_DESCRIPTOR                          *SmramDescriptor;\r
   SMM_S3_RESUME_STATE                           *SmmS3ResumeState;\r
   VOID                                          *GuidHob;\r
+  BOOLEAN                                       Build4GPageTableOnly;\r
 \r
   DEBUG ((EFI_D_ERROR, "Enter S3 PEIM\r\n"));\r
 \r
@@ -888,7 +934,12 @@ S3RestoreConfig2 (
     //\r
     // Need reconstruct page table here, since we do not trust ACPINvs.\r
     //\r
-    RestoreS3PageTables ((UINTN)AcpiS3Context->S3NvsPageTableAddress);\r
+    if (IsLongModeWakingVector (AcpiS3Context)) {\r
+      Build4GPageTableOnly = FALSE;\r
+    } else {\r
+      Build4GPageTableOnly = TRUE;\r
+    }\r
+    RestoreS3PageTables ((UINTN)AcpiS3Context->S3NvsPageTableAddress, Build4GPageTableOnly);\r
   }\r
 \r
   //\r