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