2 Set a IDT entry for debug purpose
4 Set a IDT entry for interrupt vector 3 for debug purpose for x64 platform
6 Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR>
7 Copyright (c) 2017, AMD Incorporated. All rights reserved.<BR>
10 SPDX-License-Identifier: BSD-2-Clause-Patent
13 #include "ScriptExecute.h"
16 // 8 extra pages for PF handler.
18 #define EXTRA_PAGE_TABLE_PAGES 8
20 #define IA32_PG_P BIT0
21 #define IA32_PG_RW BIT1
22 #define IA32_PG_PS BIT7
25 VOID
*mOriginalHandler
;
26 UINTN mPageFaultBuffer
;
27 UINTN mPageFaultIndex
= 0;
29 // Store the uplink information for each page being used.
31 UINT64
*mPageFaultUplink
[EXTRA_PAGE_TABLE_PAGES
];
39 PageFaultHandlerHook (
44 Hook IDT with our page fault handler so that the on-demand paging works on page fault.
46 @param IdtEntry a pointer to IDT entry
50 HookPageFaultHandler (
51 IN IA32_IDT_GATE_DESCRIPTOR
*IdtEntry
55 UINT8 PhysicalAddressBits
;
56 UINTN PageFaultHandlerHookAddress
;
58 AsmCpuid (0x80000000, &RegEax
, NULL
, NULL
, NULL
);
59 if (RegEax
>= 0x80000008) {
60 AsmCpuid (0x80000008, &RegEax
, NULL
, NULL
, NULL
);
61 PhysicalAddressBits
= (UINT8
) RegEax
;
63 PhysicalAddressBits
= 36;
65 mPhyMask
= LShiftU64 (1, PhysicalAddressBits
) - 1;
66 mPhyMask
&= (1ull << 48) - SIZE_4KB
;
69 // Set Page Fault entry to catch >4G access
71 PageFaultHandlerHookAddress
= (UINTN
)PageFaultHandlerHook
;
72 mOriginalHandler
= (VOID
*)(UINTN
)(LShiftU64 (IdtEntry
->Bits
.OffsetUpper
, 32) + IdtEntry
->Bits
.OffsetLow
+ (IdtEntry
->Bits
.OffsetHigh
<< 16));
73 IdtEntry
->Bits
.OffsetLow
= (UINT16
)PageFaultHandlerHookAddress
;
74 IdtEntry
->Bits
.Selector
= (UINT16
)AsmReadCs ();
75 IdtEntry
->Bits
.Reserved_0
= 0;
76 IdtEntry
->Bits
.GateType
= IA32_IDT_GATE_TYPE_INTERRUPT_32
;
77 IdtEntry
->Bits
.OffsetHigh
= (UINT16
)(PageFaultHandlerHookAddress
>> 16);
78 IdtEntry
->Bits
.OffsetUpper
= (UINT32
)(PageFaultHandlerHookAddress
>> 32);
79 IdtEntry
->Bits
.Reserved_1
= 0;
82 mPageFaultBuffer
= (UINTN
)(AsmReadCr3 () & mPhyMask
) + EFI_PAGES_TO_SIZE(2);
84 mPageFaultBuffer
= (UINTN
)(AsmReadCr3 () & mPhyMask
) + EFI_PAGES_TO_SIZE(6);
86 ZeroMem (mPageFaultUplink
, sizeof (mPageFaultUplink
));
90 The function will check if current waking vector is long mode.
92 @param AcpiS3Context a pointer to a structure of ACPI_S3_CONTEXT
94 @retval TRUE Current context need long mode waking vector.
95 @retval FALSE Current context need not long mode waking vector.
98 IsLongModeWakingVector (
99 IN ACPI_S3_CONTEXT
*AcpiS3Context
102 EFI_ACPI_4_0_FIRMWARE_ACPI_CONTROL_STRUCTURE
*Facs
;
104 Facs
= (EFI_ACPI_4_0_FIRMWARE_ACPI_CONTROL_STRUCTURE
*) ((UINTN
) (AcpiS3Context
->AcpiFacsTable
));
105 if ((Facs
== NULL
) ||
106 (Facs
->Signature
!= EFI_ACPI_4_0_FIRMWARE_ACPI_CONTROL_STRUCTURE_SIGNATURE
) ||
107 ((Facs
->FirmwareWakingVector
== 0) && (Facs
->XFirmwareWakingVector
== 0)) ) {
108 // Something wrong with FACS
111 if (Facs
->XFirmwareWakingVector
!= 0) {
112 if ((Facs
->Version
== EFI_ACPI_4_0_FIRMWARE_ACPI_CONTROL_STRUCTURE_VERSION
) &&
113 ((Facs
->Flags
& EFI_ACPI_4_0_64BIT_WAKE_SUPPORTED_F
) != 0) &&
114 ((Facs
->OspmFlags
& EFI_ACPI_4_0_OSPM_64BIT_WAKE__F
) != 0)) {
115 // Both BIOS and OS wants 64bit vector
116 if (FeaturePcdGet (PcdDxeIplSwitchToLongMode
)) {
125 Set a IDT entry for interrupt vector 3 for debug purpose.
127 @param AcpiS3Context a pointer to a structure of ACPI_S3_CONTEXT
132 IN ACPI_S3_CONTEXT
*AcpiS3Context
135 IA32_IDT_GATE_DESCRIPTOR
*IdtEntry
;
136 IA32_DESCRIPTOR
*IdtDescriptor
;
141 // Restore IDT for debug
143 IdtDescriptor
= (IA32_DESCRIPTOR
*) (UINTN
) (AcpiS3Context
->IdtrProfile
);
144 AsmWriteIdtr (IdtDescriptor
);
147 // Setup the default CPU exception handlers
149 Status
= InitializeCpuExceptionHandlers (NULL
);
150 ASSERT_EFI_ERROR (Status
);
154 // Update IDT entry INT3 if the instruction is valid in it
156 S3DebugBuffer
= (UINTN
) (AcpiS3Context
->S3DebugBufferAddress
);
157 if (*(UINTN
*)S3DebugBuffer
!= (UINTN
) -1) {
158 IdtEntry
= (IA32_IDT_GATE_DESCRIPTOR
*)(IdtDescriptor
->Base
+ (3 * sizeof (IA32_IDT_GATE_DESCRIPTOR
)));
159 IdtEntry
->Bits
.OffsetLow
= (UINT16
)S3DebugBuffer
;
160 IdtEntry
->Bits
.Selector
= (UINT16
)AsmReadCs ();
161 IdtEntry
->Bits
.Reserved_0
= 0;
162 IdtEntry
->Bits
.GateType
= IA32_IDT_GATE_TYPE_INTERRUPT_32
;
163 IdtEntry
->Bits
.OffsetHigh
= (UINT16
)(S3DebugBuffer
>> 16);
164 IdtEntry
->Bits
.OffsetUpper
= (UINT32
)(S3DebugBuffer
>> 32);
165 IdtEntry
->Bits
.Reserved_1
= 0;
170 // If both BIOS and OS wants long mode waking vector,
171 // S3ResumePei should have established 1:1 Virtual to Physical identity mapping page table,
172 // no need to hook page fault handler.
174 if (!IsLongModeWakingVector (AcpiS3Context
)) {
175 IdtEntry
= (IA32_IDT_GATE_DESCRIPTOR
*)(IdtDescriptor
->Base
+ (14 * sizeof (IA32_IDT_GATE_DESCRIPTOR
)));
176 HookPageFaultHandler (IdtEntry
);
181 Acquire page for page fault.
183 @param[in, out] Uplink Pointer to up page table entry.
188 IN OUT UINT64
*Uplink
193 Address
= mPageFaultBuffer
+ EFI_PAGES_TO_SIZE (mPageFaultIndex
);
194 ZeroMem ((VOID
*) Address
, EFI_PAGES_TO_SIZE (1));
197 // Cut the previous uplink if it exists and wasn't overwritten.
199 if ((mPageFaultUplink
[mPageFaultIndex
] != NULL
) &&
200 ((*mPageFaultUplink
[mPageFaultIndex
] & ~mAddressEncMask
& mPhyMask
) == Address
)) {
201 *mPageFaultUplink
[mPageFaultIndex
] = 0;
205 // Link & Record the current uplink.
207 *Uplink
= Address
| mAddressEncMask
| IA32_PG_P
| IA32_PG_RW
;
208 mPageFaultUplink
[mPageFaultIndex
] = Uplink
;
210 mPageFaultIndex
= (mPageFaultIndex
+ 1) % EXTRA_PAGE_TABLE_PAGES
;
214 The page fault handler that on-demand read >4G memory/MMIO.
216 @retval TRUE The page fault is correctly handled.
217 @retval FALSE The page fault is not handled and is passed through to original handler.
230 PFAddress
= AsmReadCr2 ();
231 DEBUG ((DEBUG_INFO
, "BootScript - PageFaultHandler: Cr2 - %lx\n", PFAddress
));
233 if (PFAddress
>= mPhyMask
+ SIZE_4KB
) {
236 PFAddress
&= mPhyMask
;
238 PageTable
= (UINT64
*)(UINTN
)(AsmReadCr3 () & mPhyMask
);
240 PTIndex
= BitFieldRead64 (PFAddress
, 39, 47);
242 if ((PageTable
[PTIndex
] & IA32_PG_P
) == 0) {
243 AcquirePage (&PageTable
[PTIndex
]);
245 PageTable
= (UINT64
*)(UINTN
)(PageTable
[PTIndex
] & ~mAddressEncMask
& mPhyMask
);
246 PTIndex
= BitFieldRead64 (PFAddress
, 30, 38);
248 if (mPage1GSupport
) {
249 PageTable
[PTIndex
] = ((PFAddress
| mAddressEncMask
) & ~((1ull << 30) - 1)) | IA32_PG_P
| IA32_PG_RW
| IA32_PG_PS
;
251 if ((PageTable
[PTIndex
] & IA32_PG_P
) == 0) {
252 AcquirePage (&PageTable
[PTIndex
]);
254 PageTable
= (UINT64
*)(UINTN
)(PageTable
[PTIndex
] & ~mAddressEncMask
& mPhyMask
);
255 PTIndex
= BitFieldRead64 (PFAddress
, 21, 29);
257 PageTable
[PTIndex
] = ((PFAddress
| mAddressEncMask
) & ~((1ull << 21) - 1)) | IA32_PG_P
| IA32_PG_RW
| IA32_PG_PS
;