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