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