[FeaturePcd]\r
gEfiMdeModulePkgTokenSpaceGuid.PcdDxeIplSwitchToLongMode\r
\r
+[Pcd]\r
+ gEfiMdeModulePkgTokenSpaceGuid.PcdUse1GPageTable\r
+\r
[Depex]\r
gEfiLockBoxProtocolGuid\r
\r
\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
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
# 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
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
; 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
;\r
;;\r
\r
+EXTERN mOriginalHandler:QWORD\r
+EXTERN PageFaultHandler:PROC\r
+\r
.code\r
\r
EXTERNDEF AsmFixAddress16:DWORD\r
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
#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
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
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
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
//\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
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
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
//\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