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