]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Universal/Acpi/BootScriptExecutorDxe/X64/SetIdtEntry.c
MdeModulePkg: Apply uncrustify changes
[mirror_edk2.git] / MdeModulePkg / Universal / Acpi / BootScriptExecutorDxe / X64 / SetIdtEntry.c
CommitLineData
be46cd5f 1/** @file\r
2 Set a IDT entry for debug purpose\r
3\r
4 Set a IDT entry for interrupt vector 3 for debug purpose for x64 platform\r
5\r
306a5836 6Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR>\r
ab1a5a58
LD
7Copyright (c) 2017, AMD Incorporated. All rights reserved.<BR>\r
8\r
be46cd5f 9\r
9d510e61 10SPDX-License-Identifier: BSD-2-Clause-Patent\r
be46cd5f 11\r
12**/\r
13#include "ScriptExecute.h"\r
d0bf5623 14\r
c6368abc
SZ
15//\r
16// 8 extra pages for PF handler.\r
17//\r
1436aea4 18#define EXTRA_PAGE_TABLE_PAGES 8\r
c6368abc 19\r
1436aea4
MK
20#define IA32_PG_P BIT0\r
21#define IA32_PG_RW BIT1\r
22#define IA32_PG_PS BIT7\r
d0bf5623 23\r
1436aea4
MK
24UINT64 mPhyMask;\r
25VOID *mOriginalHandler;\r
26UINTN mPageFaultBuffer;\r
27UINTN mPageFaultIndex = 0;\r
c6368abc
SZ
28//\r
29// Store the uplink information for each page being used.\r
30//\r
1436aea4 31UINT64 *mPageFaultUplink[EXTRA_PAGE_TABLE_PAGES];\r
d0bf5623 32\r
54e27ada
JY
33/**\r
34 Page fault handler.\r
35\r
36**/\r
d0bf5623
JY
37VOID\r
38EFIAPI\r
39PageFaultHandlerHook (\r
40 VOID\r
41 );\r
42\r
54e27ada
JY
43/**\r
44 Hook IDT with our page fault handler so that the on-demand paging works on page fault.\r
45\r
46 @param IdtEntry a pointer to IDT entry\r
47\r
48**/\r
d0bf5623
JY
49VOID\r
50HookPageFaultHandler (\r
1436aea4 51 IN IA32_IDT_GATE_DESCRIPTOR *IdtEntry\r
d0bf5623
JY
52 )\r
53{\r
1436aea4
MK
54 UINT32 RegEax;\r
55 UINT8 PhysicalAddressBits;\r
56 UINTN PageFaultHandlerHookAddress;\r
d0bf5623 57\r
59cc677c
SZ
58 AsmCpuid (0x80000000, &RegEax, NULL, NULL, NULL);\r
59 if (RegEax >= 0x80000008) {\r
60 AsmCpuid (0x80000008, &RegEax, NULL, NULL, NULL);\r
1436aea4 61 PhysicalAddressBits = (UINT8)RegEax;\r
59cc677c
SZ
62 } else {\r
63 PhysicalAddressBits = 36;\r
d0bf5623 64 }\r
1436aea4
MK
65\r
66 mPhyMask = LShiftU64 (1, PhysicalAddressBits) - 1;\r
59cc677c 67 mPhyMask &= (1ull << 48) - SIZE_4KB;\r
d0bf5623
JY
68\r
69 //\r
70 // Set Page Fault entry to catch >4G access\r
71 //\r
73f0127f 72 PageFaultHandlerHookAddress = (UINTN)PageFaultHandlerHook;\r
1436aea4
MK
73 mOriginalHandler = (VOID *)(UINTN)(LShiftU64 (IdtEntry->Bits.OffsetUpper, 32) + IdtEntry->Bits.OffsetLow + (IdtEntry->Bits.OffsetHigh << 16));\r
74 IdtEntry->Bits.OffsetLow = (UINT16)PageFaultHandlerHookAddress;\r
75 IdtEntry->Bits.Selector = (UINT16)AsmReadCs ();\r
76 IdtEntry->Bits.Reserved_0 = 0;\r
77 IdtEntry->Bits.GateType = IA32_IDT_GATE_TYPE_INTERRUPT_32;\r
78 IdtEntry->Bits.OffsetHigh = (UINT16)(PageFaultHandlerHookAddress >> 16);\r
79 IdtEntry->Bits.OffsetUpper = (UINT32)(PageFaultHandlerHookAddress >> 32);\r
80 IdtEntry->Bits.Reserved_1 = 0;\r
d0bf5623
JY
81\r
82 if (mPage1GSupport) {\r
1436aea4
MK
83 mPageFaultBuffer = (UINTN)(AsmReadCr3 () & mPhyMask) + EFI_PAGES_TO_SIZE (2);\r
84 } else {\r
85 mPageFaultBuffer = (UINTN)(AsmReadCr3 () & mPhyMask) + EFI_PAGES_TO_SIZE (6);\r
c6368abc 86 }\r
1436aea4 87\r
c6368abc
SZ
88 ZeroMem (mPageFaultUplink, sizeof (mPageFaultUplink));\r
89}\r
90\r
91/**\r
92 The function will check if current waking vector is long mode.\r
93\r
94 @param AcpiS3Context a pointer to a structure of ACPI_S3_CONTEXT\r
95\r
96 @retval TRUE Current context need long mode waking vector.\r
97 @retval FALSE Current context need not long mode waking vector.\r
98**/\r
99BOOLEAN\r
100IsLongModeWakingVector (\r
1436aea4 101 IN ACPI_S3_CONTEXT *AcpiS3Context\r
c6368abc
SZ
102 )\r
103{\r
104 EFI_ACPI_4_0_FIRMWARE_ACPI_CONTROL_STRUCTURE *Facs;\r
105\r
1436aea4 106 Facs = (EFI_ACPI_4_0_FIRMWARE_ACPI_CONTROL_STRUCTURE *)((UINTN)(AcpiS3Context->AcpiFacsTable));\r
c6368abc
SZ
107 if ((Facs == NULL) ||\r
108 (Facs->Signature != EFI_ACPI_4_0_FIRMWARE_ACPI_CONTROL_STRUCTURE_SIGNATURE) ||\r
1436aea4
MK
109 ((Facs->FirmwareWakingVector == 0) && (Facs->XFirmwareWakingVector == 0)))\r
110 {\r
c6368abc
SZ
111 // Something wrong with FACS\r
112 return FALSE;\r
113 }\r
1436aea4 114\r
c6368abc
SZ
115 if (Facs->XFirmwareWakingVector != 0) {\r
116 if ((Facs->Version == EFI_ACPI_4_0_FIRMWARE_ACPI_CONTROL_STRUCTURE_VERSION) &&\r
117 ((Facs->Flags & EFI_ACPI_4_0_64BIT_WAKE_SUPPORTED_F) != 0) &&\r
1436aea4
MK
118 ((Facs->OspmFlags & EFI_ACPI_4_0_OSPM_64BIT_WAKE__F) != 0))\r
119 {\r
c6368abc
SZ
120 // Both BIOS and OS wants 64bit vector\r
121 if (FeaturePcdGet (PcdDxeIplSwitchToLongMode)) {\r
122 return TRUE;\r
123 }\r
124 }\r
d0bf5623 125 }\r
1436aea4 126\r
c6368abc 127 return FALSE;\r
d0bf5623
JY
128}\r
129\r
be46cd5f 130/**\r
131 Set a IDT entry for interrupt vector 3 for debug purpose.\r
132\r
133 @param AcpiS3Context a pointer to a structure of ACPI_S3_CONTEXT\r
134\r
135**/\r
136VOID\r
137SetIdtEntry (\r
1436aea4 138 IN ACPI_S3_CONTEXT *AcpiS3Context\r
be46cd5f 139 )\r
140{\r
1436aea4
MK
141 IA32_IDT_GATE_DESCRIPTOR *IdtEntry;\r
142 IA32_DESCRIPTOR *IdtDescriptor;\r
143 UINTN S3DebugBuffer;\r
144 EFI_STATUS Status;\r
be46cd5f 145\r
146 //\r
147 // Restore IDT for debug\r
148 //\r
1436aea4 149 IdtDescriptor = (IA32_DESCRIPTOR *)(UINTN)(AcpiS3Context->IdtrProfile);\r
1e172d6b 150 AsmWriteIdtr (IdtDescriptor);\r
151\r
152 //\r
153 // Setup the default CPU exception handlers\r
154 //\r
57f360f2
JF
155 Status = InitializeCpuExceptionHandlers (NULL);\r
156 ASSERT_EFI_ERROR (Status);\r
1e172d6b 157\r
db52c7f7 158 DEBUG_CODE_BEGIN ();\r
1436aea4
MK
159 //\r
160 // Update IDT entry INT3 if the instruction is valid in it\r
161 //\r
162 S3DebugBuffer = (UINTN)(AcpiS3Context->S3DebugBufferAddress);\r
163 if (*(UINTN *)S3DebugBuffer != (UINTN)-1) {\r
164 IdtEntry = (IA32_IDT_GATE_DESCRIPTOR *)(IdtDescriptor->Base + (3 * sizeof (IA32_IDT_GATE_DESCRIPTOR)));\r
165 IdtEntry->Bits.OffsetLow = (UINT16)S3DebugBuffer;\r
166 IdtEntry->Bits.Selector = (UINT16)AsmReadCs ();\r
167 IdtEntry->Bits.Reserved_0 = 0;\r
168 IdtEntry->Bits.GateType = IA32_IDT_GATE_TYPE_INTERRUPT_32;\r
169 IdtEntry->Bits.OffsetHigh = (UINT16)(S3DebugBuffer >> 16);\r
170 IdtEntry->Bits.OffsetUpper = (UINT32)(S3DebugBuffer >> 32);\r
171 IdtEntry->Bits.Reserved_1 = 0;\r
172 }\r
173\r
db52c7f7 174 DEBUG_CODE_END ();\r
be46cd5f 175\r
c6368abc
SZ
176 //\r
177 // If both BIOS and OS wants long mode waking vector,\r
178 // S3ResumePei should have established 1:1 Virtual to Physical identity mapping page table,\r
179 // no need to hook page fault handler.\r
180 //\r
181 if (!IsLongModeWakingVector (AcpiS3Context)) {\r
182 IdtEntry = (IA32_IDT_GATE_DESCRIPTOR *)(IdtDescriptor->Base + (14 * sizeof (IA32_IDT_GATE_DESCRIPTOR)));\r
183 HookPageFaultHandler (IdtEntry);\r
184 }\r
d0bf5623
JY
185}\r
186\r
54e27ada 187/**\r
c6368abc 188 Acquire page for page fault.\r
54e27ada 189\r
c6368abc 190 @param[in, out] Uplink Pointer to up page table entry.\r
54e27ada 191\r
54e27ada 192**/\r
c6368abc
SZ
193VOID\r
194AcquirePage (\r
1436aea4 195 IN OUT UINT64 *Uplink\r
d0bf5623
JY
196 )\r
197{\r
1436aea4 198 UINTN Address;\r
c6368abc
SZ
199\r
200 Address = mPageFaultBuffer + EFI_PAGES_TO_SIZE (mPageFaultIndex);\r
1436aea4 201 ZeroMem ((VOID *)Address, EFI_PAGES_TO_SIZE (1));\r
c6368abc
SZ
202\r
203 //\r
204 // Cut the previous uplink if it exists and wasn't overwritten.\r
205 //\r
ab1a5a58 206 if ((mPageFaultUplink[mPageFaultIndex] != NULL) &&\r
1436aea4
MK
207 ((*mPageFaultUplink[mPageFaultIndex] & ~mAddressEncMask & mPhyMask) == Address))\r
208 {\r
c6368abc
SZ
209 *mPageFaultUplink[mPageFaultIndex] = 0;\r
210 }\r
211\r
212 //\r
213 // Link & Record the current uplink.\r
214 //\r
1436aea4 215 *Uplink = Address | mAddressEncMask | IA32_PG_P | IA32_PG_RW;\r
c6368abc
SZ
216 mPageFaultUplink[mPageFaultIndex] = Uplink;\r
217\r
218 mPageFaultIndex = (mPageFaultIndex + 1) % EXTRA_PAGE_TABLE_PAGES;\r
be46cd5f 219}\r
220\r
54e27ada
JY
221/**\r
222 The page fault handler that on-demand read >4G memory/MMIO.\r
d1102dba 223\r
54e27ada
JY
224 @retval TRUE The page fault is correctly handled.\r
225 @retval FALSE The page fault is not handled and is passed through to original handler.\r
226\r
227**/\r
d0bf5623
JY
228BOOLEAN\r
229EFIAPI\r
230PageFaultHandler (\r
231 VOID\r
232 )\r
233{\r
1436aea4
MK
234 UINT64 *PageTable;\r
235 UINT64 PFAddress;\r
236 UINTN PTIndex;\r
d0bf5623
JY
237\r
238 PFAddress = AsmReadCr2 ();\r
558f58e3 239 DEBUG ((DEBUG_INFO, "BootScript - PageFaultHandler: Cr2 - %lx\n", PFAddress));\r
d0bf5623
JY
240\r
241 if (PFAddress >= mPhyMask + SIZE_4KB) {\r
242 return FALSE;\r
243 }\r
1436aea4 244\r
d0bf5623
JY
245 PFAddress &= mPhyMask;\r
246\r
1436aea4 247 PageTable = (UINT64 *)(UINTN)(AsmReadCr3 () & mPhyMask);\r
d0bf5623
JY
248\r
249 PTIndex = BitFieldRead64 (PFAddress, 39, 47);\r
250 // PML4E\r
251 if ((PageTable[PTIndex] & IA32_PG_P) == 0) {\r
c6368abc 252 AcquirePage (&PageTable[PTIndex]);\r
d0bf5623 253 }\r
1436aea4
MK
254\r
255 PageTable = (UINT64 *)(UINTN)(PageTable[PTIndex] & ~mAddressEncMask & mPhyMask);\r
256 PTIndex = BitFieldRead64 (PFAddress, 30, 38);\r
d0bf5623
JY
257 // PDPTE\r
258 if (mPage1GSupport) {\r
ab1a5a58 259 PageTable[PTIndex] = ((PFAddress | mAddressEncMask) & ~((1ull << 30) - 1)) | IA32_PG_P | IA32_PG_RW | IA32_PG_PS;\r
d0bf5623
JY
260 } else {\r
261 if ((PageTable[PTIndex] & IA32_PG_P) == 0) {\r
c6368abc 262 AcquirePage (&PageTable[PTIndex]);\r
d0bf5623 263 }\r
1436aea4
MK
264\r
265 PageTable = (UINT64 *)(UINTN)(PageTable[PTIndex] & ~mAddressEncMask & mPhyMask);\r
266 PTIndex = BitFieldRead64 (PFAddress, 21, 29);\r
d0bf5623 267 // PD\r
ab1a5a58 268 PageTable[PTIndex] = ((PFAddress | mAddressEncMask) & ~((1ull << 21) - 1)) | IA32_PG_P | IA32_PG_RW | IA32_PG_PS;\r
d0bf5623
JY
269 }\r
270\r
271 return TRUE;\r
272}\r