]> git.proxmox.com Git - mirror_edk2.git/blob - UefiCpuPkg/Library/CpuExceptionHandlerLib/Ia32/ArchExceptionHandler.c
UefiCpuPkg: Move AsmRelocateApLoopStart from Mpfuncs.nasm to AmdSev.nasm
[mirror_edk2.git] / UefiCpuPkg / Library / CpuExceptionHandlerLib / Ia32 / ArchExceptionHandler.c
1 /** @file
2 IA32 CPU Exception Handler functons.
3
4 Copyright (c) 2012 - 2022, Intel Corporation. All rights reserved.<BR>
5 SPDX-License-Identifier: BSD-2-Clause-Patent
6
7 **/
8
9 #include "CpuExceptionCommon.h"
10
11 /**
12 Return address map of exception handler template so that C code can generate
13 exception tables.
14
15 @param IdtEntry Pointer to IDT entry to be updated.
16 @param InterruptHandler IDT handler value.
17
18 **/
19 VOID
20 ArchUpdateIdtEntry (
21 OUT IA32_IDT_GATE_DESCRIPTOR *IdtEntry,
22 IN UINTN InterruptHandler
23 )
24 {
25 IdtEntry->Bits.OffsetLow = (UINT16)(UINTN)InterruptHandler;
26 IdtEntry->Bits.OffsetHigh = (UINT16)((UINTN)InterruptHandler >> 16);
27 IdtEntry->Bits.GateType = IA32_IDT_GATE_TYPE_INTERRUPT_32;
28 }
29
30 /**
31 Read IDT handler value from IDT entry.
32
33 @param IdtEntry Pointer to IDT entry to be read.
34
35 **/
36 UINTN
37 ArchGetIdtHandler (
38 IN IA32_IDT_GATE_DESCRIPTOR *IdtEntry
39 )
40 {
41 return (UINTN)IdtEntry->Bits.OffsetLow + (((UINTN)IdtEntry->Bits.OffsetHigh) << 16);
42 }
43
44 /**
45 Save CPU exception context when handling EFI_VECTOR_HANDOFF_HOOK_AFTER case.
46
47 @param[in] ExceptionType Exception type.
48 @param[in] SystemContext Pointer to EFI_SYSTEM_CONTEXT.
49 @param[in] ExceptionHandlerData Pointer to exception handler data.
50 **/
51 VOID
52 ArchSaveExceptionContext (
53 IN UINTN ExceptionType,
54 IN EFI_SYSTEM_CONTEXT SystemContext,
55 IN EXCEPTION_HANDLER_DATA *ExceptionHandlerData
56 )
57 {
58 IA32_EFLAGS32 Eflags;
59 RESERVED_VECTORS_DATA *ReservedVectors;
60
61 ReservedVectors = ExceptionHandlerData->ReservedVectors;
62 //
63 // Save Exception context in global variable in first entry of the exception handler.
64 // So when original exception handler returns to the new exception handler (second entry),
65 // the Eflags/Cs/Eip/ExceptionData can be used.
66 //
67 ReservedVectors[ExceptionType].OldFlags = SystemContext.SystemContextIa32->Eflags;
68 ReservedVectors[ExceptionType].OldCs = SystemContext.SystemContextIa32->Cs;
69 ReservedVectors[ExceptionType].OldIp = SystemContext.SystemContextIa32->Eip;
70 ReservedVectors[ExceptionType].ExceptionData = SystemContext.SystemContextIa32->ExceptionData;
71 //
72 // Clear IF flag to avoid old IDT handler enable interrupt by IRET
73 //
74 Eflags.UintN = SystemContext.SystemContextIa32->Eflags;
75 Eflags.Bits.IF = 0;
76 SystemContext.SystemContextIa32->Eflags = Eflags.UintN;
77 //
78 // Modify the EIP in stack, then old IDT handler will return to HookAfterStubBegin.
79 //
80 SystemContext.SystemContextIa32->Eip = (UINTN)ReservedVectors[ExceptionType].HookAfterStubHeaderCode;
81 }
82
83 /**
84 Restore CPU exception context when handling EFI_VECTOR_HANDOFF_HOOK_AFTER case.
85
86 @param[in] ExceptionType Exception type.
87 @param[in] SystemContext Pointer to EFI_SYSTEM_CONTEXT.
88 @param[in] ExceptionHandlerData Pointer to exception handler data.
89 **/
90 VOID
91 ArchRestoreExceptionContext (
92 IN UINTN ExceptionType,
93 IN EFI_SYSTEM_CONTEXT SystemContext,
94 IN EXCEPTION_HANDLER_DATA *ExceptionHandlerData
95 )
96 {
97 RESERVED_VECTORS_DATA *ReservedVectors;
98
99 ReservedVectors = ExceptionHandlerData->ReservedVectors;
100 SystemContext.SystemContextIa32->Eflags = ReservedVectors[ExceptionType].OldFlags;
101 SystemContext.SystemContextIa32->Cs = ReservedVectors[ExceptionType].OldCs;
102 SystemContext.SystemContextIa32->Eip = ReservedVectors[ExceptionType].OldIp;
103 SystemContext.SystemContextIa32->ExceptionData = ReservedVectors[ExceptionType].ExceptionData;
104 }
105
106 /**
107 Setup separate stacks for certain exception handlers.
108
109 @param[in] Buffer Point to buffer used to separate exception stack.
110 @param[in, out] BufferSize On input, it indicates the byte size of Buffer.
111 If the size is not enough, the return status will
112 be EFI_BUFFER_TOO_SMALL, and output BufferSize
113 will be the size it needs.
114
115 @retval EFI_SUCCESS The stacks are assigned successfully.
116 @retval EFI_BUFFER_TOO_SMALL This BufferSize is too small.
117 **/
118 EFI_STATUS
119 ArchSetupExceptionStack (
120 IN VOID *Buffer,
121 IN OUT UINTN *BufferSize
122 )
123 {
124 IA32_DESCRIPTOR Gdtr;
125 IA32_DESCRIPTOR Idtr;
126 IA32_IDT_GATE_DESCRIPTOR *IdtTable;
127 IA32_TSS_DESCRIPTOR *TssDesc;
128 IA32_TSS_DESCRIPTOR *TssDescBase;
129 IA32_TASK_STATE_SEGMENT *Tss;
130 VOID *NewGdtTable;
131 UINTN StackTop;
132 UINTN Index;
133 UINTN Vector;
134 UINTN TssBase;
135 UINT8 *StackSwitchExceptions;
136 UINTN NeedBufferSize;
137 EXCEPTION_HANDLER_TEMPLATE_MAP TemplateMap;
138
139 if (BufferSize == NULL) {
140 return EFI_INVALID_PARAMETER;
141 }
142
143 //
144 // Total needed size includes stack size, new GDT table size, TSS size.
145 // Add another DESCRIPTOR size for alignment requiremet.
146 //
147 // Layout of memory needed for each processor:
148 // --------------------------------
149 // | |
150 // | Stack Size | X ExceptionNumber
151 // | |
152 // --------------------------------
153 // | Alignment | (just in case)
154 // --------------------------------
155 // | |
156 // | Original GDT |
157 // | |
158 // --------------------------------
159 // | Current task descriptor |
160 // --------------------------------
161 // | |
162 // | Exception task descriptors | X ExceptionNumber
163 // | |
164 // --------------------------------
165 // | Current task-state segment |
166 // --------------------------------
167 // | |
168 // | Exception task-state segment | X ExceptionNumber
169 // | |
170 // --------------------------------
171 //
172 AsmReadGdtr (&Gdtr);
173 NeedBufferSize = CPU_STACK_SWITCH_EXCEPTION_NUMBER * CPU_KNOWN_GOOD_STACK_SIZE +
174 sizeof (IA32_TSS_DESCRIPTOR) +
175 Gdtr.Limit + 1 + CPU_TSS_DESC_SIZE +
176 CPU_TSS_SIZE;
177
178 if (*BufferSize < NeedBufferSize) {
179 *BufferSize = NeedBufferSize;
180 return EFI_BUFFER_TOO_SMALL;
181 }
182
183 if (Buffer == NULL) {
184 return EFI_INVALID_PARAMETER;
185 }
186
187 AsmReadIdtr (&Idtr);
188 StackSwitchExceptions = CPU_STACK_SWITCH_EXCEPTION_LIST;
189 StackTop = (UINTN)Buffer + CPU_STACK_SWITCH_EXCEPTION_NUMBER * CPU_KNOWN_GOOD_STACK_SIZE;
190 NewGdtTable = ALIGN_POINTER (StackTop, sizeof (IA32_TSS_DESCRIPTOR));
191 TssDesc = (IA32_TSS_DESCRIPTOR *)((UINTN)NewGdtTable + Gdtr.Limit + 1);
192 Tss = (IA32_TASK_STATE_SEGMENT *)((UINTN)TssDesc + CPU_TSS_DESC_SIZE);
193 TssDescBase = TssDesc;
194
195 CopyMem (NewGdtTable, (VOID *)Gdtr.Base, Gdtr.Limit + 1);
196 Gdtr.Base = (UINTN)NewGdtTable;
197 Gdtr.Limit = (UINT16)(Gdtr.Limit + CPU_TSS_DESC_SIZE);
198
199 //
200 // Fixup current task descriptor. Task-state segment for current task will
201 // be filled by processor during task switching.
202 //
203 TssBase = (UINTN)Tss;
204
205 TssDesc->Uint64 = 0;
206 TssDesc->Bits.LimitLow = sizeof (IA32_TASK_STATE_SEGMENT) - 1;
207 TssDesc->Bits.BaseLow = (UINT16)TssBase;
208 TssDesc->Bits.BaseMid = (UINT8)(TssBase >> 16);
209 TssDesc->Bits.Type = IA32_GDT_TYPE_TSS;
210 TssDesc->Bits.P = 1;
211 TssDesc->Bits.LimitHigh = 0;
212 TssDesc->Bits.BaseHigh = (UINT8)(TssBase >> 24);
213
214 //
215 // Fixup exception task descriptor and task-state segment
216 //
217 AsmGetTssTemplateMap (&TemplateMap);
218 //
219 // Plus 1 byte is for compact stack layout in case StackTop is already aligned.
220 //
221 StackTop = StackTop - CPU_STACK_ALIGNMENT + 1;
222 StackTop = (UINTN)ALIGN_POINTER (StackTop, CPU_STACK_ALIGNMENT);
223 IdtTable = (IA32_IDT_GATE_DESCRIPTOR *)Idtr.Base;
224 for (Index = 0; Index < CPU_STACK_SWITCH_EXCEPTION_NUMBER; ++Index) {
225 TssDesc += 1;
226 Tss += 1;
227
228 //
229 // Fixup TSS descriptor
230 //
231 TssBase = (UINTN)Tss;
232
233 TssDesc->Uint64 = 0;
234 TssDesc->Bits.LimitLow = sizeof (IA32_TASK_STATE_SEGMENT) - 1;
235 TssDesc->Bits.BaseLow = (UINT16)TssBase;
236 TssDesc->Bits.BaseMid = (UINT8)(TssBase >> 16);
237 TssDesc->Bits.Type = IA32_GDT_TYPE_TSS;
238 TssDesc->Bits.P = 1;
239 TssDesc->Bits.LimitHigh = 0;
240 TssDesc->Bits.BaseHigh = (UINT8)(TssBase >> 24);
241
242 //
243 // Fixup TSS
244 //
245 Vector = StackSwitchExceptions[Index];
246 if ((Vector >= CPU_EXCEPTION_NUM) ||
247 (Vector >= (Idtr.Limit + 1) / sizeof (IA32_IDT_GATE_DESCRIPTOR)))
248 {
249 continue;
250 }
251
252 ZeroMem (Tss, sizeof (*Tss));
253 Tss->EIP = (UINT32)(TemplateMap.ExceptionStart
254 + Vector * TemplateMap.ExceptionStubHeaderSize);
255 Tss->EFLAGS = 0x2;
256 Tss->ESP = StackTop;
257 Tss->CR3 = AsmReadCr3 ();
258 Tss->ES = AsmReadEs ();
259 Tss->CS = AsmReadCs ();
260 Tss->SS = AsmReadSs ();
261 Tss->DS = AsmReadDs ();
262 Tss->FS = AsmReadFs ();
263 Tss->GS = AsmReadGs ();
264
265 StackTop -= CPU_KNOWN_GOOD_STACK_SIZE;
266
267 //
268 // Update IDT to use Task Gate for given exception
269 //
270 IdtTable[Vector].Bits.OffsetLow = 0;
271 IdtTable[Vector].Bits.Selector = (UINT16)((UINTN)TssDesc - Gdtr.Base);
272 IdtTable[Vector].Bits.Reserved_0 = 0;
273 IdtTable[Vector].Bits.GateType = IA32_IDT_GATE_TYPE_TASK;
274 IdtTable[Vector].Bits.OffsetHigh = 0;
275 }
276
277 //
278 // Publish GDT
279 //
280 AsmWriteGdtr (&Gdtr);
281
282 //
283 // Load current task
284 //
285 AsmWriteTr ((UINT16)((UINTN)TssDescBase - Gdtr.Base));
286
287 return EFI_SUCCESS;
288 }
289
290 /**
291 Display processor context.
292
293 @param[in] ExceptionType Exception type.
294 @param[in] SystemContext Processor context to be display.
295 **/
296 VOID
297 EFIAPI
298 DumpCpuContext (
299 IN EFI_EXCEPTION_TYPE ExceptionType,
300 IN EFI_SYSTEM_CONTEXT SystemContext
301 )
302 {
303 InternalPrintMessage (
304 "!!!! IA32 Exception Type - %02x(%a) CPU Apic ID - %08x !!!!\n",
305 ExceptionType,
306 GetExceptionNameStr (ExceptionType),
307 GetApicId ()
308 );
309 if ((mErrorCodeFlag & (1 << ExceptionType)) != 0) {
310 InternalPrintMessage (
311 "ExceptionData - %08x",
312 SystemContext.SystemContextIa32->ExceptionData
313 );
314 if (ExceptionType == EXCEPT_IA32_PAGE_FAULT) {
315 InternalPrintMessage (
316 " I:%x R:%x U:%x W:%x P:%x PK:%x SS:%x SGX:%x",
317 (SystemContext.SystemContextIa32->ExceptionData & IA32_PF_EC_ID) != 0,
318 (SystemContext.SystemContextIa32->ExceptionData & IA32_PF_EC_RSVD) != 0,
319 (SystemContext.SystemContextIa32->ExceptionData & IA32_PF_EC_US) != 0,
320 (SystemContext.SystemContextIa32->ExceptionData & IA32_PF_EC_WR) != 0,
321 (SystemContext.SystemContextIa32->ExceptionData & IA32_PF_EC_P) != 0,
322 (SystemContext.SystemContextIa32->ExceptionData & IA32_PF_EC_PK) != 0,
323 (SystemContext.SystemContextIa32->ExceptionData & IA32_PF_EC_SS) != 0,
324 (SystemContext.SystemContextIa32->ExceptionData & IA32_PF_EC_SGX) != 0
325 );
326 }
327
328 InternalPrintMessage ("\n");
329 }
330
331 InternalPrintMessage (
332 "EIP - %08x, CS - %08x, EFLAGS - %08x\n",
333 SystemContext.SystemContextIa32->Eip,
334 SystemContext.SystemContextIa32->Cs,
335 SystemContext.SystemContextIa32->Eflags
336 );
337 InternalPrintMessage (
338 "EAX - %08x, ECX - %08x, EDX - %08x, EBX - %08x\n",
339 SystemContext.SystemContextIa32->Eax,
340 SystemContext.SystemContextIa32->Ecx,
341 SystemContext.SystemContextIa32->Edx,
342 SystemContext.SystemContextIa32->Ebx
343 );
344 InternalPrintMessage (
345 "ESP - %08x, EBP - %08x, ESI - %08x, EDI - %08x\n",
346 SystemContext.SystemContextIa32->Esp,
347 SystemContext.SystemContextIa32->Ebp,
348 SystemContext.SystemContextIa32->Esi,
349 SystemContext.SystemContextIa32->Edi
350 );
351 InternalPrintMessage (
352 "DS - %08x, ES - %08x, FS - %08x, GS - %08x, SS - %08x\n",
353 SystemContext.SystemContextIa32->Ds,
354 SystemContext.SystemContextIa32->Es,
355 SystemContext.SystemContextIa32->Fs,
356 SystemContext.SystemContextIa32->Gs,
357 SystemContext.SystemContextIa32->Ss
358 );
359 InternalPrintMessage (
360 "CR0 - %08x, CR2 - %08x, CR3 - %08x, CR4 - %08x\n",
361 SystemContext.SystemContextIa32->Cr0,
362 SystemContext.SystemContextIa32->Cr2,
363 SystemContext.SystemContextIa32->Cr3,
364 SystemContext.SystemContextIa32->Cr4
365 );
366 InternalPrintMessage (
367 "DR0 - %08x, DR1 - %08x, DR2 - %08x, DR3 - %08x\n",
368 SystemContext.SystemContextIa32->Dr0,
369 SystemContext.SystemContextIa32->Dr1,
370 SystemContext.SystemContextIa32->Dr2,
371 SystemContext.SystemContextIa32->Dr3
372 );
373 InternalPrintMessage (
374 "DR6 - %08x, DR7 - %08x\n",
375 SystemContext.SystemContextIa32->Dr6,
376 SystemContext.SystemContextIa32->Dr7
377 );
378 InternalPrintMessage (
379 "GDTR - %08x %08x, IDTR - %08x %08x\n",
380 SystemContext.SystemContextIa32->Gdtr[0],
381 SystemContext.SystemContextIa32->Gdtr[1],
382 SystemContext.SystemContextIa32->Idtr[0],
383 SystemContext.SystemContextIa32->Idtr[1]
384 );
385 InternalPrintMessage (
386 "LDTR - %08x, TR - %08x\n",
387 SystemContext.SystemContextIa32->Ldtr,
388 SystemContext.SystemContextIa32->Tr
389 );
390 InternalPrintMessage (
391 "FXSAVE_STATE - %08x\n",
392 &SystemContext.SystemContextIa32->FxSaveState
393 );
394 }
395
396 /**
397 Display CPU information.
398
399 @param ExceptionType Exception type.
400 @param SystemContext Pointer to EFI_SYSTEM_CONTEXT.
401 **/
402 VOID
403 DumpImageAndCpuContent (
404 IN EFI_EXCEPTION_TYPE ExceptionType,
405 IN EFI_SYSTEM_CONTEXT SystemContext
406 )
407 {
408 DumpCpuContext (ExceptionType, SystemContext);
409 //
410 // Dump module image base and module entry point by EIP
411 //
412 if ((ExceptionType == EXCEPT_IA32_PAGE_FAULT) &&
413 ((SystemContext.SystemContextIa32->ExceptionData & IA32_PF_EC_ID) != 0))
414 {
415 //
416 // The EIP in SystemContext could not be used
417 // if it is page fault with I/D set.
418 //
419 DumpModuleImageInfo ((*(UINTN *)(UINTN)SystemContext.SystemContextIa32->Esp));
420 } else {
421 DumpModuleImageInfo (SystemContext.SystemContextIa32->Eip);
422 }
423 }