TianoCore EDK2 master
Loading...
Searching...
No Matches
X64Entry.c
Go to the documentation of this file.
1
11#include <Library/DebugLib.h>
15#include "CommonHeader.h"
16
17#define EXCEPTION_VECTOR_NUMBER 0x22
18
19#define IA32_PG_P BIT0
20#define IA32_PG_RW BIT1
21#define IA32_PG_PS BIT7
22
23typedef struct _PAGE_FAULT_CONTEXT {
24 BOOLEAN Page1GSupport;
25 UINT64 PhyMask;
26 UINTN PageFaultBuffer;
27 UINTN PageFaultIndex;
28 UINT64 AddressEncMask;
29 //
30 // Store the uplink information for each page being used.
31 //
32 UINT64 *PageFaultUplink[EXTRA_PAGE_TABLE_PAGES];
33 VOID *OriginalHandler;
35
36typedef struct _PAGE_FAULT_IDT_TABLE {
37 PAGE_FAULT_CONTEXT PageFaultContext;
38 IA32_IDT_GATE_DESCRIPTOR IdtEntryTable[EXCEPTION_VECTOR_NUMBER];
40
45VOID
46EFIAPI
48 VOID
49 );
50
58VOID
60 IN OUT IA32_IDT_GATE_DESCRIPTOR *IdtEntry,
61 IN OUT PAGE_FAULT_CONTEXT *PageFaultContext
62 )
63{
64 UINT32 RegEax;
65 UINT8 PhysicalAddressBits;
66 UINTN PageFaultHandlerHookAddress;
67
68 AsmCpuid (0x80000000, &RegEax, NULL, NULL, NULL);
69 if (RegEax >= 0x80000008) {
70 AsmCpuid (0x80000008, &RegEax, NULL, NULL, NULL);
71 PhysicalAddressBits = (UINT8)RegEax;
72 } else {
73 PhysicalAddressBits = 36;
74 }
75
76 PageFaultContext->PhyMask = LShiftU64 (1, PhysicalAddressBits) - 1;
77 PageFaultContext->PhyMask &= (1ull << 48) - SIZE_4KB;
78
79 //
80 // Set Page Fault entry to catch >4G access
81 //
82 PageFaultHandlerHookAddress = (UINTN)PageFaultHandlerHook;
83 PageFaultContext->OriginalHandler = (VOID *)(UINTN)(LShiftU64 (IdtEntry->Bits.OffsetUpper, 32) + IdtEntry->Bits.OffsetLow + (IdtEntry->Bits.OffsetHigh << 16));
84 IdtEntry->Bits.OffsetLow = (UINT16)PageFaultHandlerHookAddress;
85 IdtEntry->Bits.Selector = (UINT16)AsmReadCs ();
86 IdtEntry->Bits.Reserved_0 = 0;
87 IdtEntry->Bits.GateType = IA32_IDT_GATE_TYPE_INTERRUPT_32;
88 IdtEntry->Bits.OffsetHigh = (UINT16)(PageFaultHandlerHookAddress >> 16);
89 IdtEntry->Bits.OffsetUpper = (UINT32)(PageFaultHandlerHookAddress >> 32);
90 IdtEntry->Bits.Reserved_1 = 0;
91
92 if (PageFaultContext->Page1GSupport) {
93 PageFaultContext->PageFaultBuffer = (UINTN)(AsmReadCr3 () & PageFaultContext->PhyMask) + EFI_PAGES_TO_SIZE (2);
94 } else {
95 PageFaultContext->PageFaultBuffer = (UINTN)(AsmReadCr3 () & PageFaultContext->PhyMask) + EFI_PAGES_TO_SIZE (6);
96 }
97
98 PageFaultContext->PageFaultIndex = 0;
99 ZeroMem (PageFaultContext->PageFaultUplink, sizeof (PageFaultContext->PageFaultUplink));
100}
101
109VOID
111 IN OUT PAGE_FAULT_CONTEXT *PageFaultContext,
112 IN OUT UINT64 *Uplink
113 )
114{
115 UINTN Address;
116 UINT64 AddressEncMask;
117
118 Address = PageFaultContext->PageFaultBuffer + EFI_PAGES_TO_SIZE (PageFaultContext->PageFaultIndex);
119 ZeroMem ((VOID *)Address, EFI_PAGES_TO_SIZE (1));
120
121 AddressEncMask = PageFaultContext->AddressEncMask;
122
123 //
124 // Cut the previous uplink if it exists and wasn't overwritten.
125 //
126 if ((PageFaultContext->PageFaultUplink[PageFaultContext->PageFaultIndex] != NULL) &&
127 ((*PageFaultContext->PageFaultUplink[PageFaultContext->PageFaultIndex] & ~AddressEncMask & PageFaultContext->PhyMask) == Address))
128 {
129 *PageFaultContext->PageFaultUplink[PageFaultContext->PageFaultIndex] = 0;
130 }
131
132 //
133 // Link & Record the current uplink.
134 //
135 *Uplink = Address | AddressEncMask | IA32_PG_P | IA32_PG_RW;
136 PageFaultContext->PageFaultUplink[PageFaultContext->PageFaultIndex] = Uplink;
137
138 PageFaultContext->PageFaultIndex = (PageFaultContext->PageFaultIndex + 1) % EXTRA_PAGE_TABLE_PAGES;
139}
140
148VOID *
149EFIAPI
151 VOID
152 )
153{
154 IA32_DESCRIPTOR Idtr;
155 PAGE_FAULT_CONTEXT *PageFaultContext;
156 UINT64 PhyMask;
157 UINT64 *PageTable;
158 UINT64 PFAddress;
159 UINTN PTIndex;
160 UINT64 AddressEncMask;
161
162 //
163 // Get the IDT Descriptor.
164 //
165 AsmReadIdtr ((IA32_DESCRIPTOR *)&Idtr);
166 //
167 // Then get page fault context by IDT Descriptor.
168 //
169 PageFaultContext = (PAGE_FAULT_CONTEXT *)(UINTN)(Idtr.Base - sizeof (PAGE_FAULT_CONTEXT));
170 PhyMask = PageFaultContext->PhyMask;
171 AddressEncMask = PageFaultContext->AddressEncMask;
172
173 PFAddress = AsmReadCr2 ();
174 DEBUG ((DEBUG_ERROR, "CapsuleX64 - PageFaultHandler: Cr2 - %lx\n", PFAddress));
175
176 if (PFAddress >= PhyMask + SIZE_4KB) {
177 return PageFaultContext->OriginalHandler;
178 }
179
180 PFAddress &= PhyMask;
181
182 PageTable = (UINT64 *)(UINTN)(AsmReadCr3 () & PhyMask);
183
184 PTIndex = BitFieldRead64 (PFAddress, 39, 47);
185 // PML4E
186 if ((PageTable[PTIndex] & IA32_PG_P) == 0) {
187 AcquirePage (PageFaultContext, &PageTable[PTIndex]);
188 }
189
190 PageTable = (UINT64 *)(UINTN)(PageTable[PTIndex] & ~AddressEncMask & PhyMask);
191 PTIndex = BitFieldRead64 (PFAddress, 30, 38);
192 // PDPTE
193 if (PageFaultContext->Page1GSupport) {
194 PageTable[PTIndex] = ((PFAddress | AddressEncMask) & ~((1ull << 30) - 1)) | IA32_PG_P | IA32_PG_RW | IA32_PG_PS;
195 } else {
196 if ((PageTable[PTIndex] & IA32_PG_P) == 0) {
197 AcquirePage (PageFaultContext, &PageTable[PTIndex]);
198 }
199
200 PageTable = (UINT64 *)(UINTN)(PageTable[PTIndex] & ~AddressEncMask & PhyMask);
201 PTIndex = BitFieldRead64 (PFAddress, 21, 29);
202 // PD
203 PageTable[PTIndex] = ((PFAddress | AddressEncMask) & ~((1ull << 21) - 1)) | IA32_PG_P | IA32_PG_RW | IA32_PG_PS;
204 }
205
206 return NULL;
207}
208
220EFIAPI
222 SWITCH_32_TO_64_CONTEXT *EntrypointContext,
223 SWITCH_64_TO_32_CONTEXT *ReturnContext
224 )
225{
226 EFI_STATUS Status;
227 IA32_DESCRIPTOR Ia32Idtr;
228 IA32_DESCRIPTOR X64Idtr;
229 PAGE_FAULT_IDT_TABLE PageFaultIdtTable;
230 IA32_IDT_GATE_DESCRIPTOR *IdtEntry;
231
232 //
233 // Save the IA32 IDT Descriptor
234 //
235 AsmReadIdtr ((IA32_DESCRIPTOR *)&Ia32Idtr);
236
237 //
238 // Setup X64 IDT table
239 //
240 ZeroMem (PageFaultIdtTable.IdtEntryTable, sizeof (IA32_IDT_GATE_DESCRIPTOR) * EXCEPTION_VECTOR_NUMBER);
241 X64Idtr.Base = (UINTN)PageFaultIdtTable.IdtEntryTable;
242 X64Idtr.Limit = (UINT16)(sizeof (IA32_IDT_GATE_DESCRIPTOR) * EXCEPTION_VECTOR_NUMBER - 1);
243 AsmWriteIdtr ((IA32_DESCRIPTOR *)&X64Idtr);
244
245 //
246 // Setup the default CPU exception handlers
247 //
248 Status = InitializeCpuExceptionHandlers (NULL);
249 ASSERT_EFI_ERROR (Status);
250
251 //
252 // Hook page fault handler to handle >4G request.
253 //
254 PageFaultIdtTable.PageFaultContext.Page1GSupport = EntrypointContext->Page1GSupport;
255 PageFaultIdtTable.PageFaultContext.AddressEncMask = EntrypointContext->AddressEncMask;
256 IdtEntry = (IA32_IDT_GATE_DESCRIPTOR *)(X64Idtr.Base + (14 * sizeof (IA32_IDT_GATE_DESCRIPTOR)));
257 HookPageFaultHandler (IdtEntry, &(PageFaultIdtTable.PageFaultContext));
258
259 //
260 // Initialize Debug Agent to support source level debug
261 //
262 InitializeDebugAgent (DEBUG_AGENT_INIT_THUNK_PEI_IA32TOX64, (VOID *)&Ia32Idtr, NULL);
263
264 //
265 // Call CapsuleDataCoalesce to process capsule.
266 //
267 Status = CapsuleDataCoalesce (
268 NULL,
269 (EFI_PHYSICAL_ADDRESS *)(UINTN)EntrypointContext->BlockListAddr,
270 (MEMORY_RESOURCE_DESCRIPTOR *)(UINTN)EntrypointContext->MemoryResource,
271 (VOID **)(UINTN)EntrypointContext->MemoryBase64Ptr,
272 (UINTN *)(UINTN)EntrypointContext->MemorySize64Ptr
273 );
274
275 ReturnContext->ReturnStatus = Status;
276
277 DEBUG ((
278 DEBUG_INFO,
279 "%a() Stack Base: 0x%lx, Stack Size: 0x%lx\n",
280 __func__,
281 EntrypointContext->StackBufferBase,
282 EntrypointContext->StackBufferLength
283 ));
284
285 //
286 // Disable interrupt of Debug timer, since the new IDT table cannot work in long mode
287 //
289 //
290 // Restore IA32 IDT table
291 //
292 AsmWriteIdtr ((IA32_DESCRIPTOR *)&Ia32Idtr);
293
294 //
295 // Finish to coalesce capsule, and return to 32-bit mode.
296 //
298 ReturnContext->ReturnCs,
299 (UINT32)ReturnContext->ReturnEntryPoint,
300 (UINT32)(UINTN)EntrypointContext,
301 (UINT32)(UINTN)ReturnContext,
302 (UINT32)(EntrypointContext->StackBufferBase + EntrypointContext->StackBufferLength)
303 );
304
305 //
306 // Should never be here.
307 //
308 ASSERT (FALSE);
309 return EFI_SUCCESS;
310}
UINT64 UINTN
UINT64 EFIAPI BitFieldRead64(IN UINT64 Operand, IN UINTN StartBit, IN UINTN EndBit)
Definition: BitField.c:719
UINT64 EFIAPI LShiftU64(IN UINT64 Operand, IN UINTN Count)
Definition: LShiftU64.c:28
VOID *EFIAPI ZeroMem(OUT VOID *Buffer, IN UINTN Length)
EFI_STATUS EFIAPI CapsuleDataCoalesce(IN EFI_PEI_SERVICES **PeiServices, IN EFI_PHYSICAL_ADDRESS *BlockListBuffer, IN MEMORY_RESOURCE_DESCRIPTOR *MemoryResource, IN OUT VOID **MemoryBase, IN OUT UINTN *MemorySize)
BOOLEAN EFIAPI SaveAndSetDebugTimerInterrupt(IN BOOLEAN EnableStatus)
VOID EFIAPI InitializeDebugAgent(IN UINT32 InitFlag, IN VOID *Context OPTIONAL, IN DEBUG_AGENT_CONTINUE Function OPTIONAL)
UINTN EFIAPI AsmReadCr3(VOID)
UINTN EFIAPI AsmReadCr2(VOID)
UINT16 EFIAPI AsmReadCs(VOID)
#define NULL
Definition: Base.h:319
#define FALSE
Definition: Base.h:307
#define IN
Definition: Base.h:279
#define OUT
Definition: Base.h:284
#define ASSERT_EFI_ERROR(StatusParameter)
Definition: DebugLib.h:462
#define DEBUG(Expression)
Definition: DebugLib.h:434
UINT32 EFIAPI AsmCpuid(IN UINT32 Index, OUT UINT32 *RegisterEax OPTIONAL, OUT UINT32 *RegisterEbx OPTIONAL, OUT UINT32 *RegisterEcx OPTIONAL, OUT UINT32 *RegisterEdx OPTIONAL)
Definition: CpuId.c:36
UINT64 EFI_PHYSICAL_ADDRESS
Definition: UefiBaseType.h:50
#define EFI_PAGES_TO_SIZE(Pages)
Definition: UefiBaseType.h:213
RETURN_STATUS EFI_STATUS
Definition: UefiBaseType.h:29
#define EFI_SUCCESS
Definition: UefiBaseType.h:112
VOID EFIAPI PageFaultHandlerHook(VOID)
VOID HookPageFaultHandler(IN OUT IA32_IDT_GATE_DESCRIPTOR *IdtEntry, IN OUT PAGE_FAULT_CONTEXT *PageFaultContext)
Definition: X64Entry.c:59
VOID AcquirePage(IN OUT PAGE_FAULT_CONTEXT *PageFaultContext, IN OUT UINT64 *Uplink)
Definition: X64Entry.c:110
EFI_STATUS EFIAPI _ModuleEntryPoint(SWITCH_32_TO_64_CONTEXT *EntrypointContext, SWITCH_64_TO_32_CONTEXT *ReturnContext)
Definition: X64Entry.c:221
VOID *EFIAPI PageFaultHandler(VOID)
Definition: X64Entry.c:150
VOID EFIAPI AsmDisablePaging64(IN UINT16 Cs, IN UINT32 EntryPoint, IN UINT32 Context1 OPTIONAL, IN UINT32 Context2 OPTIONAL, IN UINT32 NewStack)
VOID EFIAPI AsmReadIdtr(OUT IA32_DESCRIPTOR *Idtr)
Definition: X86ReadIdtr.c:24
VOID EFIAPI AsmWriteIdtr(IN CONST IA32_DESCRIPTOR *Idtr)