aboutsummaryrefslogtreecommitdiffstats
path: root/roms/edk2/MdeModulePkg/Universal/Acpi/BootScriptExecutorDxe/X64
diff options
context:
space:
mode:
Diffstat (limited to 'roms/edk2/MdeModulePkg/Universal/Acpi/BootScriptExecutorDxe/X64')
-rw-r--r--roms/edk2/MdeModulePkg/Universal/Acpi/BootScriptExecutorDxe/X64/S3Asm.nasm130
-rw-r--r--roms/edk2/MdeModulePkg/Universal/Acpi/BootScriptExecutorDxe/X64/SetIdtEntry.c261
2 files changed, 391 insertions, 0 deletions
diff --git a/roms/edk2/MdeModulePkg/Universal/Acpi/BootScriptExecutorDxe/X64/S3Asm.nasm b/roms/edk2/MdeModulePkg/Universal/Acpi/BootScriptExecutorDxe/X64/S3Asm.nasm
new file mode 100644
index 000000000..713fd7b2e
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/Acpi/BootScriptExecutorDxe/X64/S3Asm.nasm
@@ -0,0 +1,130 @@
+;; @file
+; This is the assembly code for transferring to control to OS S3 waking vector
+; for X64 platform
+;
+; Copyright (c) 2006 - 2012, Intel Corporation. All rights reserved.<BR>
+;
+; SPDX-License-Identifier: BSD-2-Clause-Patent
+;
+;;
+
+extern ASM_PFX(mOriginalHandler)
+extern ASM_PFX(PageFaultHandler)
+
+ DEFAULT REL
+ SECTION .text
+
+global ASM_PFX(AsmFixAddress16)
+global ASM_PFX(AsmJmpAddr32)
+
+global ASM_PFX(AsmTransferControl)
+ASM_PFX(AsmTransferControl):
+ ; rcx S3WakingVector :DWORD
+ ; rdx AcpiLowMemoryBase :DWORD
+ lea eax, [.0]
+ mov r8, 0x2800000000
+ or rax, r8
+ push rax
+ shrd ebx, ecx, 20
+ and ecx, 0xf
+ mov bx, cx
+ mov [@jmp_addr + 1], ebx
+ retf
+BITS 16
+.0:
+ mov ax, 0x30
+ mov ds, ax
+ mov es, ax
+ mov fs, ax
+ mov gs, ax
+ mov ss, ax
+ mov eax, cr0
+ mov ebx, cr4
+ and eax, ((~ 0x80000001) & 0xffffffff)
+ and bl, ~ (1 << 5)
+ mov cr0, eax
+ mov ecx, 0xc0000080
+ rdmsr
+ and ah, ~ 1
+ wrmsr
+ mov cr4, ebx
+@jmp_addr:
+ jmp 0x0:0x0
+
+global ASM_PFX(AsmTransferControl32)
+ASM_PFX(AsmTransferControl32):
+BITS 32
+ ; S3WakingVector :DWORD
+ ; AcpiLowMemoryBase :DWORD
+ push ebp
+ mov ebp, esp
+ DB 0x8d, 0x5 ; lea eax, AsmTransferControl16
+ASM_PFX(AsmFixAddress16): DD 0
+ push 0x28 ; CS
+ push eax
+ retf
+
+global ASM_PFX(AsmTransferControl16)
+ASM_PFX(AsmTransferControl16):
+BITS 16
+ mov ax, 0x30
+o32 mov ds, eax
+o32 mov es, eax
+o32 mov fs, eax
+o32 mov gs, eax
+o32 mov ss, eax
+ mov eax, cr0 ; Get control register 0
+ and eax, 0fffffffeh ; Clear PE bit (bit #0)
+ mov cr0, eax ; Activate real mode
+ DB 0xea ; jmp far AsmJmpAddr32
+ASM_PFX(AsmJmpAddr32): DD 0
+
+global ASM_PFX(PageFaultHandlerHook)
+ASM_PFX(PageFaultHandlerHook):
+BITS 64
+ push rax ; save all volatile registers
+ push rcx
+ push rdx
+ push r8
+ push r9
+ push r10
+ push r11
+ ; save volatile fp registers
+ add rsp, -0x68
+ stmxcsr [rsp + 0x60]
+ movdqa [rsp + 0x0], xmm0
+ movdqa [rsp + 0x10], xmm1
+ movdqa [rsp + 0x20], xmm2
+ movdqa [rsp + 0x30], xmm3
+ movdqa [rsp + 0x40], xmm4
+ movdqa [rsp + 0x50], xmm5
+
+ add rsp, -0x20
+ call ASM_PFX(PageFaultHandler)
+ add rsp, 0x20
+
+ ; load volatile fp registers
+ ldmxcsr [rsp + 0x60]
+ movdqa xmm0, [rsp + 0x0]
+ movdqa xmm1, [rsp + 0x10]
+ movdqa xmm2, [rsp + 0x20]
+ movdqa xmm3, [rsp + 0x30]
+ movdqa xmm4, [rsp + 0x40]
+ movdqa xmm5, [rsp + 0x50]
+ add rsp, 0x68
+
+ test al, al
+
+ pop r11
+ pop r10
+ pop r9
+ pop r8
+ pop rdx
+ pop rcx
+ pop rax ; restore all volatile registers
+ jnz .1
+ jmp qword [ASM_PFX(mOriginalHandler)]
+.1:
+ add rsp, 0x8 ; skip error code for PF
+ iretq
+
diff --git a/roms/edk2/MdeModulePkg/Universal/Acpi/BootScriptExecutorDxe/X64/SetIdtEntry.c b/roms/edk2/MdeModulePkg/Universal/Acpi/BootScriptExecutorDxe/X64/SetIdtEntry.c
new file mode 100644
index 000000000..0d448cc60
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/Acpi/BootScriptExecutorDxe/X64/SetIdtEntry.c
@@ -0,0 +1,261 @@
+/** @file
+ Set a IDT entry for debug purpose
+
+ Set a IDT entry for interrupt vector 3 for debug purpose for x64 platform
+
+Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR>
+Copyright (c) 2017, AMD Incorporated. All rights reserved.<BR>
+
+
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+#include "ScriptExecute.h"
+
+//
+// 8 extra pages for PF handler.
+//
+#define EXTRA_PAGE_TABLE_PAGES 8
+
+#define IA32_PG_P BIT0
+#define IA32_PG_RW BIT1
+#define IA32_PG_PS BIT7
+
+UINT64 mPhyMask;
+VOID *mOriginalHandler;
+UINTN mPageFaultBuffer;
+UINTN mPageFaultIndex = 0;
+//
+// Store the uplink information for each page being used.
+//
+UINT64 *mPageFaultUplink[EXTRA_PAGE_TABLE_PAGES];
+
+/**
+ Page fault handler.
+
+**/
+VOID
+EFIAPI
+PageFaultHandlerHook (
+ VOID
+ );
+
+/**
+ Hook IDT with our page fault handler so that the on-demand paging works on page fault.
+
+ @param IdtEntry a pointer to IDT entry
+
+**/
+VOID
+HookPageFaultHandler (
+ IN IA32_IDT_GATE_DESCRIPTOR *IdtEntry
+ )
+{
+ UINT32 RegEax;
+ UINT8 PhysicalAddressBits;
+ UINTN PageFaultHandlerHookAddress;
+
+ AsmCpuid (0x80000000, &RegEax, NULL, NULL, NULL);
+ if (RegEax >= 0x80000008) {
+ AsmCpuid (0x80000008, &RegEax, NULL, NULL, NULL);
+ PhysicalAddressBits = (UINT8) RegEax;
+ } else {
+ PhysicalAddressBits = 36;
+ }
+ mPhyMask = LShiftU64 (1, PhysicalAddressBits) - 1;
+ mPhyMask &= (1ull << 48) - SIZE_4KB;
+
+ //
+ // Set Page Fault entry to catch >4G access
+ //
+ PageFaultHandlerHookAddress = (UINTN)PageFaultHandlerHook;
+ mOriginalHandler = (VOID *)(UINTN)(LShiftU64 (IdtEntry->Bits.OffsetUpper, 32) + IdtEntry->Bits.OffsetLow + (IdtEntry->Bits.OffsetHigh << 16));
+ IdtEntry->Bits.OffsetLow = (UINT16)PageFaultHandlerHookAddress;
+ IdtEntry->Bits.Selector = (UINT16)AsmReadCs ();
+ IdtEntry->Bits.Reserved_0 = 0;
+ IdtEntry->Bits.GateType = IA32_IDT_GATE_TYPE_INTERRUPT_32;
+ IdtEntry->Bits.OffsetHigh = (UINT16)(PageFaultHandlerHookAddress >> 16);
+ IdtEntry->Bits.OffsetUpper = (UINT32)(PageFaultHandlerHookAddress >> 32);
+ IdtEntry->Bits.Reserved_1 = 0;
+
+ if (mPage1GSupport) {
+ mPageFaultBuffer = (UINTN)(AsmReadCr3 () & mPhyMask) + EFI_PAGES_TO_SIZE(2);
+ }else {
+ mPageFaultBuffer = (UINTN)(AsmReadCr3 () & mPhyMask) + EFI_PAGES_TO_SIZE(6);
+ }
+ ZeroMem (mPageFaultUplink, sizeof (mPageFaultUplink));
+}
+
+/**
+ The function will check if current waking vector is long mode.
+
+ @param AcpiS3Context a pointer to a structure of ACPI_S3_CONTEXT
+
+ @retval TRUE Current context need long mode waking vector.
+ @retval FALSE Current context need not long mode waking vector.
+**/
+BOOLEAN
+IsLongModeWakingVector (
+ IN ACPI_S3_CONTEXT *AcpiS3Context
+ )
+{
+ EFI_ACPI_4_0_FIRMWARE_ACPI_CONTROL_STRUCTURE *Facs;
+
+ Facs = (EFI_ACPI_4_0_FIRMWARE_ACPI_CONTROL_STRUCTURE *) ((UINTN) (AcpiS3Context->AcpiFacsTable));
+ if ((Facs == NULL) ||
+ (Facs->Signature != EFI_ACPI_4_0_FIRMWARE_ACPI_CONTROL_STRUCTURE_SIGNATURE) ||
+ ((Facs->FirmwareWakingVector == 0) && (Facs->XFirmwareWakingVector == 0)) ) {
+ // Something wrong with FACS
+ return FALSE;
+ }
+ if (Facs->XFirmwareWakingVector != 0) {
+ if ((Facs->Version == EFI_ACPI_4_0_FIRMWARE_ACPI_CONTROL_STRUCTURE_VERSION) &&
+ ((Facs->Flags & EFI_ACPI_4_0_64BIT_WAKE_SUPPORTED_F) != 0) &&
+ ((Facs->OspmFlags & EFI_ACPI_4_0_OSPM_64BIT_WAKE__F) != 0)) {
+ // Both BIOS and OS wants 64bit vector
+ if (FeaturePcdGet (PcdDxeIplSwitchToLongMode)) {
+ return TRUE;
+ }
+ }
+ }
+ return FALSE;
+}
+
+/**
+ Set a IDT entry for interrupt vector 3 for debug purpose.
+
+ @param AcpiS3Context a pointer to a structure of ACPI_S3_CONTEXT
+
+**/
+VOID
+SetIdtEntry (
+ IN ACPI_S3_CONTEXT *AcpiS3Context
+ )
+{
+ IA32_IDT_GATE_DESCRIPTOR *IdtEntry;
+ IA32_DESCRIPTOR *IdtDescriptor;
+ UINTN S3DebugBuffer;
+ EFI_STATUS Status;
+
+ //
+ // Restore IDT for debug
+ //
+ IdtDescriptor = (IA32_DESCRIPTOR *) (UINTN) (AcpiS3Context->IdtrProfile);
+ AsmWriteIdtr (IdtDescriptor);
+
+ //
+ // Setup the default CPU exception handlers
+ //
+ Status = InitializeCpuExceptionHandlers (NULL);
+ ASSERT_EFI_ERROR (Status);
+
+ DEBUG_CODE (
+ //
+ // Update IDT entry INT3 if the instruction is valid in it
+ //
+ S3DebugBuffer = (UINTN) (AcpiS3Context->S3DebugBufferAddress);
+ if (*(UINTN *)S3DebugBuffer != (UINTN) -1) {
+ IdtEntry = (IA32_IDT_GATE_DESCRIPTOR *)(IdtDescriptor->Base + (3 * sizeof (IA32_IDT_GATE_DESCRIPTOR)));
+ IdtEntry->Bits.OffsetLow = (UINT16)S3DebugBuffer;
+ IdtEntry->Bits.Selector = (UINT16)AsmReadCs ();
+ IdtEntry->Bits.Reserved_0 = 0;
+ IdtEntry->Bits.GateType = IA32_IDT_GATE_TYPE_INTERRUPT_32;
+ IdtEntry->Bits.OffsetHigh = (UINT16)(S3DebugBuffer >> 16);
+ IdtEntry->Bits.OffsetUpper = (UINT32)(S3DebugBuffer >> 32);
+ IdtEntry->Bits.Reserved_1 = 0;
+ }
+ );
+
+ //
+ // If both BIOS and OS wants long mode waking vector,
+ // S3ResumePei should have established 1:1 Virtual to Physical identity mapping page table,
+ // no need to hook page fault handler.
+ //
+ if (!IsLongModeWakingVector (AcpiS3Context)) {
+ IdtEntry = (IA32_IDT_GATE_DESCRIPTOR *)(IdtDescriptor->Base + (14 * sizeof (IA32_IDT_GATE_DESCRIPTOR)));
+ HookPageFaultHandler (IdtEntry);
+ }
+}
+
+/**
+ Acquire page for page fault.
+
+ @param[in, out] Uplink Pointer to up page table entry.
+
+**/
+VOID
+AcquirePage (
+ IN OUT UINT64 *Uplink
+ )
+{
+ UINTN Address;
+
+ Address = mPageFaultBuffer + EFI_PAGES_TO_SIZE (mPageFaultIndex);
+ ZeroMem ((VOID *) Address, EFI_PAGES_TO_SIZE (1));
+
+ //
+ // Cut the previous uplink if it exists and wasn't overwritten.
+ //
+ if ((mPageFaultUplink[mPageFaultIndex] != NULL) &&
+ ((*mPageFaultUplink[mPageFaultIndex] & ~mAddressEncMask & mPhyMask) == Address)) {
+ *mPageFaultUplink[mPageFaultIndex] = 0;
+ }
+
+ //
+ // Link & Record the current uplink.
+ //
+ *Uplink = Address | mAddressEncMask | IA32_PG_P | IA32_PG_RW;
+ mPageFaultUplink[mPageFaultIndex] = Uplink;
+
+ mPageFaultIndex = (mPageFaultIndex + 1) % EXTRA_PAGE_TABLE_PAGES;
+}
+
+/**
+ The page fault handler that on-demand read >4G memory/MMIO.
+
+ @retval TRUE The page fault is correctly handled.
+ @retval FALSE The page fault is not handled and is passed through to original handler.
+
+**/
+BOOLEAN
+EFIAPI
+PageFaultHandler (
+ VOID
+ )
+{
+ UINT64 *PageTable;
+ UINT64 PFAddress;
+ UINTN PTIndex;
+
+ PFAddress = AsmReadCr2 ();
+ DEBUG ((DEBUG_INFO, "BootScript - PageFaultHandler: Cr2 - %lx\n", PFAddress));
+
+ if (PFAddress >= mPhyMask + SIZE_4KB) {
+ return FALSE;
+ }
+ PFAddress &= mPhyMask;
+
+ PageTable = (UINT64*)(UINTN)(AsmReadCr3 () & mPhyMask);
+
+ PTIndex = BitFieldRead64 (PFAddress, 39, 47);
+ // PML4E
+ if ((PageTable[PTIndex] & IA32_PG_P) == 0) {
+ AcquirePage (&PageTable[PTIndex]);
+ }
+ PageTable = (UINT64*)(UINTN)(PageTable[PTIndex] & ~mAddressEncMask & mPhyMask);
+ PTIndex = BitFieldRead64 (PFAddress, 30, 38);
+ // PDPTE
+ if (mPage1GSupport) {
+ PageTable[PTIndex] = ((PFAddress | mAddressEncMask) & ~((1ull << 30) - 1)) | IA32_PG_P | IA32_PG_RW | IA32_PG_PS;
+ } else {
+ if ((PageTable[PTIndex] & IA32_PG_P) == 0) {
+ AcquirePage (&PageTable[PTIndex]);
+ }
+ PageTable = (UINT64*)(UINTN)(PageTable[PTIndex] & ~mAddressEncMask & mPhyMask);
+ PTIndex = BitFieldRead64 (PFAddress, 21, 29);
+ // PD
+ PageTable[PTIndex] = ((PFAddress | mAddressEncMask) & ~((1ull << 21) - 1)) | IA32_PG_P | IA32_PG_RW | IA32_PG_PS;
+ }
+
+ return TRUE;
+}