]> git.proxmox.com Git - mirror_edk2.git/blame - UefiCpuPkg/Library/CpuExceptionHandlerLib/PeiDxeSmmCpuException.c
UefiCpuPkg: Move AsmRelocateApLoopStart from Mpfuncs.nasm to AmdSev.nasm
[mirror_edk2.git] / UefiCpuPkg / Library / CpuExceptionHandlerLib / PeiDxeSmmCpuException.c
CommitLineData
8f07f895 1/** @file\r
9b4aa760 2 CPU Exception Library provides PEI/DXE/SMM CPU common exception handler.\r
8f07f895 3\r
2a09527e 4Copyright (c) 2012 - 2022, Intel Corporation. All rights reserved.<BR>\r
0acd8697 5SPDX-License-Identifier: BSD-2-Clause-Patent\r
8f07f895 6\r
7**/\r
8\r
e41aad15 9#include <Library/DebugLib.h>\r
a89f558d 10#include <Library/CcExitLib.h>\r
5277540e 11#include "CpuExceptionCommon.h"\r
8f07f895 12\r
8f07f895 13/**\r
44ecbc28 14 Internal worker function for common exception handler.\r
8f07f895 15\r
44ecbc28
JF
16 @param ExceptionType Exception type.\r
17 @param SystemContext Pointer to EFI_SYSTEM_CONTEXT.\r
18 @param ExceptionHandlerData Pointer to exception handler data.\r
8f07f895 19**/\r
20VOID\r
44ecbc28 21CommonExceptionHandlerWorker (\r
053e878b
MK
22 IN EFI_EXCEPTION_TYPE ExceptionType,\r
23 IN EFI_SYSTEM_CONTEXT SystemContext,\r
24 IN EXCEPTION_HANDLER_DATA *ExceptionHandlerData\r
8f07f895 25 )\r
26{\r
de327f7d 27 EFI_STATUS Status;\r
053e878b
MK
28 EXCEPTION_HANDLER_CONTEXT *ExceptionHandlerContext;\r
29 RESERVED_VECTORS_DATA *ReservedVectors;\r
30 EFI_CPU_INTERRUPT_HANDLER *ExternalInterruptHandler;\r
e41aad15 31\r
de327f7d
MX
32 switch (ExceptionType) {\r
33 case VC_EXCEPTION:\r
34 //\r
35 // #VC needs to be handled immediately upon enabling exception handling\r
36 // and therefore can't use the RegisterCpuInterruptHandler() interface.\r
37 //\r
38 // Handle the #VC:\r
39 // On EFI_SUCCESS - Exception has been handled, return\r
40 // On other - ExceptionType contains (possibly new) exception\r
41 // value\r
42 //\r
765ba5bf 43 Status = CcExitHandleVc (&ExceptionType, SystemContext);\r
de327f7d
MX
44 if (!EFI_ERROR (Status)) {\r
45 return;\r
46 }\r
47\r
48 break;\r
49\r
50 case VE_EXCEPTION:\r
51 //\r
52 // #VE needs to be handled immediately upon enabling exception handling\r
53 // and therefore can't use the RegisterCpuInterruptHandler() interface.\r
54 //\r
55 // Handle the #VE:\r
56 // On EFI_SUCCESS - Exception has been handled, return\r
57 // On other - ExceptionType contains (possibly new) exception\r
58 // value\r
59 //\r
765ba5bf 60 Status = CcExitHandleVe (&ExceptionType, SystemContext);\r
de327f7d
MX
61 if (!EFI_ERROR (Status)) {\r
62 return;\r
63 }\r
64\r
65 break;\r
66\r
67 default:\r
68 break;\r
5277540e
TL
69 }\r
70\r
053e878b 71 ExceptionHandlerContext = (EXCEPTION_HANDLER_CONTEXT *)(UINTN)(SystemContext.SystemContextIa32);\r
44ecbc28
JF
72 ReservedVectors = ExceptionHandlerData->ReservedVectors;\r
73 ExternalInterruptHandler = ExceptionHandlerData->ExternalInterruptHandler;\r
e41aad15 74\r
44ecbc28 75 switch (ReservedVectors[ExceptionType].Attribute) {\r
053e878b 76 case EFI_VECTOR_HANDOFF_HOOK_BEFORE:\r
e41aad15 77 //\r
053e878b
MK
78 // The new exception handler registered by RegisterCpuInterruptHandler() is executed BEFORE original handler.\r
79 // Save the original handler to stack so the assembly code can jump to it instead of returning from handler.\r
e41aad15 80 //\r
053e878b
MK
81 ExceptionHandlerContext->ExceptionDataFlag = (mErrorCodeFlag & (1 << ExceptionType)) ? TRUE : FALSE;\r
82 ExceptionHandlerContext->OldIdtHandler = ReservedVectors[ExceptionType].ExceptonHandler;\r
83 break;\r
84 case EFI_VECTOR_HANDOFF_HOOK_AFTER:\r
85 while (TRUE) {\r
e41aad15 86 //\r
053e878b 87 // If spin-lock can be acquired, it's the first time entering here.\r
e41aad15 88 //\r
053e878b
MK
89 if (AcquireSpinLockOrFail (&ReservedVectors[ExceptionType].SpinLock)) {\r
90 //\r
91 // The new exception handler registered by RegisterCpuInterruptHandler() is executed AFTER original handler.\r
92 // Save the original handler to stack but skip running the new handler so the original handler is executed\r
93 // firstly.\r
94 //\r
95 ReservedVectors[ExceptionType].ApicId = GetApicId ();\r
96 ArchSaveExceptionContext (ExceptionType, SystemContext, ExceptionHandlerData);\r
97 ExceptionHandlerContext->ExceptionDataFlag = (mErrorCodeFlag & (1 << ExceptionType)) ? TRUE : FALSE;\r
98 ExceptionHandlerContext->OldIdtHandler = ReservedVectors[ExceptionType].ExceptonHandler;\r
99 return;\r
100 }\r
101\r
e41aad15 102 //\r
053e878b
MK
103 // If spin-lock cannot be acquired, it's the second time entering here.\r
104 // 'break' instead of 'return' is used so the new exception handler can be executed.\r
e41aad15 105 //\r
053e878b
MK
106 if (ReservedVectors[ExceptionType].ApicId == GetApicId ()) {\r
107 //\r
108 // Old IDT handler has been executed, then restore CPU exception content to\r
109 // run new exception handler.\r
110 //\r
111 ArchRestoreExceptionContext (ExceptionType, SystemContext, ExceptionHandlerData);\r
112 //\r
113 // Release spin lock for ApicId\r
114 //\r
115 ReleaseSpinLock (&ReservedVectors[ExceptionType].SpinLock);\r
116 break;\r
117 }\r
118\r
119 CpuPause ();\r
e41aad15 120 }\r
053e878b
MK
121\r
122 break;\r
123 case 0xffffffff:\r
124 break;\r
125 default:\r
126 //\r
127 // It should never reach here\r
128 //\r
129 CpuDeadLoop ();\r
130 break;\r
8f07f895 131 }\r
dd563742 132\r
053e878b
MK
133 if ((ExternalInterruptHandler != NULL) &&\r
134 (ExternalInterruptHandler[ExceptionType] != NULL))\r
135 {\r
136 (ExternalInterruptHandler[ExceptionType])(ExceptionType, SystemContext);\r
f3b113bf 137 } else if (ExceptionType < CPU_EXCEPTION_NUM) {\r
e41aad15
JF
138 //\r
139 // Get Spinlock to display CPU information\r
140 //\r
44ecbc28 141 while (!AcquireSpinLockOrFail (&ExceptionHandlerData->DisplayMessageSpinLock)) {\r
e41aad15
JF
142 CpuPause ();\r
143 }\r
053e878b 144\r
e41aad15 145 //\r
7230212a
RN
146 // Initialize the serial port before dumping.\r
147 //\r
148 SerialPortInitialize ();\r
149 //\r
e41aad15 150 // Display ExceptionType, CPU information and Image information\r
dd563742 151 //\r
1b2f7b3e 152 DumpImageAndCpuContent (ExceptionType, SystemContext);\r
e41aad15
JF
153 //\r
154 // Release Spinlock of output message\r
155 //\r
44ecbc28 156 ReleaseSpinLock (&ExceptionHandlerData->DisplayMessageSpinLock);\r
e41aad15
JF
157 //\r
158 // Enter a dead loop if needn't to execute old IDT handler further\r
159 //\r
44ecbc28 160 if (ReservedVectors[ExceptionType].Attribute != EFI_VECTOR_HANDOFF_HOOK_BEFORE) {\r
e41aad15
JF
161 CpuDeadLoop ();\r
162 }\r
163 }\r
164}\r
8f07f895 165\r
e41aad15
JF
166/**\r
167 Internal worker function to update IDT entries accordling to vector attributes.\r
168\r
9db15f81
JF
169 @param[in] IdtTable Pointer to IDT table.\r
170 @param[in] TemplateMap Pointer to a buffer where the address map is\r
171 returned.\r
172 @param[in] ExceptionHandlerData Pointer to exception handler data.\r
e41aad15
JF
173\r
174**/\r
175VOID\r
176UpdateIdtTable (\r
177 IN IA32_IDT_GATE_DESCRIPTOR *IdtTable,\r
178 IN EXCEPTION_HANDLER_TEMPLATE_MAP *TemplateMap,\r
9db15f81 179 IN EXCEPTION_HANDLER_DATA *ExceptionHandlerData\r
e41aad15
JF
180 )\r
181{\r
053e878b
MK
182 UINT16 CodeSegment;\r
183 UINTN Index;\r
184 UINTN InterruptHandler;\r
185 RESERVED_VECTORS_DATA *ReservedVectors;\r
8f07f895 186\r
9db15f81 187 ReservedVectors = ExceptionHandlerData->ReservedVectors;\r
8f07f895 188 //\r
e41aad15 189 // Use current CS as the segment selector of interrupt gate in IDT\r
8f07f895 190 //\r
e41aad15 191 CodeSegment = AsmReadCs ();\r
8f07f895 192\r
053e878b 193 for (Index = 0; Index < ExceptionHandlerData->IdtEntryCount; Index++) {\r
e41aad15
JF
194 IdtTable[Index].Bits.Selector = CodeSegment;\r
195 //\r
196 // Check reserved vectors attributes\r
197 //\r
9db15f81 198 switch (ReservedVectors[Index].Attribute) {\r
053e878b
MK
199 case EFI_VECTOR_HANDOFF_DO_NOT_HOOK:\r
200 //\r
201 // Keep original IDT entry\r
202 //\r
203 continue;\r
204 case EFI_VECTOR_HANDOFF_HOOK_AFTER:\r
205 InitializeSpinLock (&ReservedVectors[Index].SpinLock);\r
206 CopyMem (\r
207 (VOID *)ReservedVectors[Index].HookAfterStubHeaderCode,\r
208 (VOID *)TemplateMap->HookAfterStubHeaderStart,\r
209 TemplateMap->ExceptionStubHeaderSize\r
210 );\r
211 AsmVectorNumFixup (\r
212 (VOID *)ReservedVectors[Index].HookAfterStubHeaderCode,\r
213 (UINT8)Index,\r
214 (VOID *)TemplateMap->HookAfterStubHeaderStart\r
215 );\r
e41aad15
JF
216 //\r
217 // Go on the following code\r
218 //\r
053e878b
MK
219 case EFI_VECTOR_HANDOFF_HOOK_BEFORE:\r
220 //\r
221 // Save original IDT handler address\r
222 //\r
223 ReservedVectors[Index].ExceptonHandler = ArchGetIdtHandler (&IdtTable[Index]);\r
e41aad15
JF
224 //\r
225 // Go on the following code\r
226 //\r
053e878b
MK
227 default:\r
228 //\r
229 // Update new IDT entry\r
230 //\r
231 InterruptHandler = TemplateMap->ExceptionStart + Index * TemplateMap->ExceptionStubHeaderSize;\r
232 ArchUpdateIdtEntry (&IdtTable[Index], InterruptHandler);\r
233 break;\r
e41aad15
JF
234 }\r
235 }\r
8f07f895 236}\r
237\r
238/**\r
e41aad15 239 Internal worker function to initialize exception handler.\r
8f07f895 240\r
ab95e54d
JF
241 @param[in] VectorInfo Pointer to reserved vector list.\r
242 @param[in, out] ExceptionHandlerData Pointer to exception handler data.\r
dd563742
JF
243\r
244 @retval EFI_SUCCESS CPU Exception Entries have been successfully initialized\r
e41aad15
JF
245 with default exception handlers.\r
246 @retval EFI_INVALID_PARAMETER VectorInfo includes the invalid content if VectorInfo is not NULL.\r
247 @retval EFI_UNSUPPORTED This function is not supported.\r
248\r
8f07f895 249**/\r
e41aad15
JF
250EFI_STATUS\r
251InitializeCpuExceptionHandlersWorker (\r
053e878b
MK
252 IN EFI_VECTOR_HANDOFF_INFO *VectorInfo OPTIONAL,\r
253 IN OUT EXCEPTION_HANDLER_DATA *ExceptionHandlerData\r
8f07f895 254 )\r
255{\r
053e878b
MK
256 EFI_STATUS Status;\r
257 IA32_DESCRIPTOR IdtDescriptor;\r
258 UINTN IdtEntryCount;\r
259 EXCEPTION_HANDLER_TEMPLATE_MAP TemplateMap;\r
260 IA32_IDT_GATE_DESCRIPTOR *IdtTable;\r
261 RESERVED_VECTORS_DATA *ReservedVectors;\r
e41aad15 262\r
ab95e54d 263 ReservedVectors = ExceptionHandlerData->ReservedVectors;\r
2a09527e 264 SetMem ((VOID *)ReservedVectors, sizeof (RESERVED_VECTORS_DATA) * ExceptionHandlerData->IdtEntryCount, 0xff);\r
e41aad15 265 if (VectorInfo != NULL) {\r
2a09527e 266 Status = ReadAndVerifyVectorInfo (VectorInfo, ReservedVectors, ExceptionHandlerData->IdtEntryCount);\r
e41aad15
JF
267 if (EFI_ERROR (Status)) {\r
268 return EFI_INVALID_PARAMETER;\r
269 }\r
270 }\r
e41aad15 271\r
e41aad15 272 //\r
2a09527e
RN
273 // Setup the exception handlers according to IDT size, but no more than\r
274 // ExceptionHandlerData->IdtEntryCount (32 in PEI and SMM, 256 in DXE) handlers.\r
e41aad15
JF
275 //\r
276 AsmReadIdtr (&IdtDescriptor);\r
2a09527e
RN
277 IdtEntryCount = (IdtDescriptor.Limit + 1) / sizeof (IA32_IDT_GATE_DESCRIPTOR);\r
278 ExceptionHandlerData->IdtEntryCount = MIN (IdtEntryCount, ExceptionHandlerData->IdtEntryCount);\r
e41aad15 279\r
053e878b 280 IdtTable = (IA32_IDT_GATE_DESCRIPTOR *)IdtDescriptor.Base;\r
e41aad15
JF
281 AsmGetTemplateAddressMap (&TemplateMap);\r
282 ASSERT (TemplateMap.ExceptionStubHeaderSize <= HOOKAFTER_STUB_SIZE);\r
9db15f81 283\r
9db15f81 284 UpdateIdtTable (IdtTable, &TemplateMap, ExceptionHandlerData);\r
d91225cf 285\r
e41aad15
JF
286 return EFI_SUCCESS;\r
287}\r
288\r
289/**\r
290 Registers a function to be called from the processor interrupt handler.\r
291\r
670f13af
JF
292 @param[in] InterruptType Defines which interrupt or exception to hook.\r
293 @param[in] InterruptHandler A pointer to a function of type EFI_CPU_INTERRUPT_HANDLER that is called\r
294 when a processor interrupt occurs. If this parameter is NULL, then the handler\r
295 will be uninstalled\r
296 @param[in] ExceptionHandlerData Pointer to exception handler data.\r
e41aad15
JF
297\r
298 @retval EFI_SUCCESS The handler for the processor interrupt was successfully installed or uninstalled.\r
299 @retval EFI_ALREADY_STARTED InterruptHandler is not NULL, and a handler for InterruptType was\r
300 previously installed.\r
301 @retval EFI_INVALID_PARAMETER InterruptHandler is NULL, and a handler for InterruptType was not\r
302 previously installed.\r
303 @retval EFI_UNSUPPORTED The interrupt specified by InterruptType is not supported,\r
304 or this function is not supported.\r
3f25e6ea 305**/\r
e41aad15
JF
306EFI_STATUS\r
307RegisterCpuInterruptHandlerWorker (\r
053e878b
MK
308 IN EFI_EXCEPTION_TYPE InterruptType,\r
309 IN EFI_CPU_INTERRUPT_HANDLER InterruptHandler,\r
310 IN EXCEPTION_HANDLER_DATA *ExceptionHandlerData\r
e41aad15
JF
311 )\r
312{\r
053e878b
MK
313 UINTN EnabledInterruptNum;\r
314 RESERVED_VECTORS_DATA *ReservedVectors;\r
315 EFI_CPU_INTERRUPT_HANDLER *ExternalInterruptHandler;\r
670f13af
JF
316\r
317 EnabledInterruptNum = ExceptionHandlerData->IdtEntryCount;\r
318 ReservedVectors = ExceptionHandlerData->ReservedVectors;\r
319 ExternalInterruptHandler = ExceptionHandlerData->ExternalInterruptHandler;\r
320\r
053e878b
MK
321 if ((InterruptType < 0) || (InterruptType >= (EFI_EXCEPTION_TYPE)EnabledInterruptNum) ||\r
322 (ReservedVectors[InterruptType].Attribute == EFI_VECTOR_HANDOFF_DO_NOT_HOOK))\r
323 {\r
e41aad15
JF
324 return EFI_UNSUPPORTED;\r
325 }\r
326\r
053e878b 327 if ((InterruptHandler == NULL) && (ExternalInterruptHandler[InterruptType] == NULL)) {\r
e41aad15
JF
328 return EFI_INVALID_PARAMETER;\r
329 }\r
330\r
053e878b 331 if ((InterruptHandler != NULL) && (ExternalInterruptHandler[InterruptType] != NULL)) {\r
e41aad15
JF
332 return EFI_ALREADY_STARTED;\r
333 }\r
334\r
670f13af 335 ExternalInterruptHandler[InterruptType] = InterruptHandler;\r
e41aad15 336 return EFI_SUCCESS;\r
8f07f895 337}\r