]> git.proxmox.com Git - mirror_edk2.git/blame_incremental - UefiCpuPkg/Library/CpuExceptionHandlerLib/PeiDxeSmmCpuException.c
UefiCpuPkg/ExceptionLib: Add CommonExceptionHandlerWorker()
[mirror_edk2.git] / UefiCpuPkg / Library / CpuExceptionHandlerLib / PeiDxeSmmCpuException.c
... / ...
CommitLineData
1/** @file\r
2 CPU Exception Library provides PEI/DXE/SMM CPU common exception handler.\r
3\r
4Copyright (c) 2012 - 2016, Intel Corporation. All rights reserved.<BR>\r
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
15#include "CpuExceptionCommon.h"\r
16#include <Library/DebugLib.h>\r
17\r
18\r
19//\r
20// Image align size for DXE/SMM\r
21//\r
22CONST UINTN mImageAlignSize = SIZE_4KB;\r
23\r
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
29/**\r
30 Internal worker function for common exception handler.\r
31\r
32 @param ExceptionType Exception type.\r
33 @param SystemContext Pointer to EFI_SYSTEM_CONTEXT.\r
34 @param ExceptionHandlerData Pointer to exception handler data.\r
35**/\r
36VOID\r
37CommonExceptionHandlerWorker (\r
38 IN EFI_EXCEPTION_TYPE ExceptionType, \r
39 IN EFI_SYSTEM_CONTEXT SystemContext,\r
40 IN EXCEPTION_HANDLER_DATA *ExceptionHandlerData\r
41 )\r
42{\r
43 EXCEPTION_HANDLER_CONTEXT *ExceptionHandlerContext;\r
44 RESERVED_VECTORS_DATA *ReservedVectors;\r
45 EFI_CPU_INTERRUPT_HANDLER *ExternalInterruptHandler;\r
46\r
47 ExceptionHandlerContext = (EXCEPTION_HANDLER_CONTEXT *) (UINTN) (SystemContext.SystemContextIa32);\r
48 ReservedVectors = ExceptionHandlerData->ReservedVectors;\r
49 ExternalInterruptHandler = ExceptionHandlerData->ExternalInterruptHandler;\r
50\r
51 switch (ReservedVectors[ExceptionType].Attribute) {\r
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
57 ExceptionHandlerContext->OldIdtHandler = ReservedVectors[ExceptionType].ExceptonHandler;\r
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
64 if (AcquireSpinLockOrFail (&ReservedVectors[ExceptionType].SpinLock)) {\r
65 //\r
66 // Need to execute old IDT handler before running this exception handler\r
67 //\r
68 ReservedVectors[ExceptionType].ApicId = GetApicId ();\r
69 ArchSaveExceptionContext (ExceptionType, SystemContext);\r
70 ExceptionHandlerContext->ExceptionDataFlag = (mErrorCodeFlag & (1 << ExceptionType)) ? TRUE : FALSE;\r
71 ExceptionHandlerContext->OldIdtHandler = ReservedVectors[ExceptionType].ExceptonHandler;\r
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
77 if (ReservedVectors[ExceptionType].ApicId == GetApicId ()) {\r
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
86 ReleaseSpinLock (&ReservedVectors[ExceptionType].SpinLock);\r
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
100 }\r
101 \r
102 if (ExternalInterruptHandler != NULL &&\r
103 ExternalInterruptHandler[ExceptionType] != NULL) {\r
104 (ExternalInterruptHandler[ExceptionType]) (ExceptionType, SystemContext);\r
105 } else if (ExceptionType < CPU_EXCEPTION_NUM) {\r
106 //\r
107 // Get Spinlock to display CPU information\r
108 //\r
109 while (!AcquireSpinLockOrFail (&ExceptionHandlerData->DisplayMessageSpinLock)) {\r
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
119 ReleaseSpinLock (&ExceptionHandlerData->DisplayMessageSpinLock);\r
120 //\r
121 // Enter a dead loop if needn't to execute old IDT handler further\r
122 //\r
123 if (ReservedVectors[ExceptionType].Attribute != EFI_VECTOR_HANDOFF_HOOK_BEFORE) {\r
124 CpuDeadLoop ();\r
125 }\r
126 }\r
127}\r
128\r
129/**\r
130 Internal worker function to update IDT entries accordling to vector attributes.\r
131\r
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
136\r
137**/\r
138VOID\r
139UpdateIdtTable (\r
140 IN IA32_IDT_GATE_DESCRIPTOR *IdtTable,\r
141 IN EXCEPTION_HANDLER_TEMPLATE_MAP *TemplateMap,\r
142 IN EXCEPTION_HANDLER_DATA *ExceptionHandlerData\r
143 )\r
144{\r
145 UINT16 CodeSegment;\r
146 UINTN Index;\r
147 UINTN InterruptHandler;\r
148 RESERVED_VECTORS_DATA *ReservedVectors;\r
149\r
150 ReservedVectors = ExceptionHandlerData->ReservedVectors;\r
151 //\r
152 // Use current CS as the segment selector of interrupt gate in IDT\r
153 //\r
154 CodeSegment = AsmReadCs ();\r
155\r
156 for (Index = 0; Index < ExceptionHandlerData->IdtEntryCount; Index ++) {\r
157 IdtTable[Index].Bits.Selector = CodeSegment;\r
158 //\r
159 // Check reserved vectors attributes\r
160 //\r
161 switch (ReservedVectors[Index].Attribute) {\r
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
168 InitializeSpinLock (&ReservedVectors[Index].SpinLock);\r
169 CopyMem (\r
170 (VOID *) ReservedVectors[Index].HookAfterStubHeaderCode,\r
171 (VOID *) TemplateMap->HookAfterStubHeaderStart,\r
172 TemplateMap->ExceptionStubHeaderSize\r
173 );\r
174 AsmVectorNumFixup (\r
175 (VOID *) ReservedVectors[Index].HookAfterStubHeaderCode,\r
176 (UINT8) Index,\r
177 (VOID *) TemplateMap->HookAfterStubHeaderStart\r
178 );\r
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
186 ReservedVectors[Index].ExceptonHandler = ArchGetIdtHandler (&IdtTable[Index]);\r
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
200 //\r
201 // Save Interrupt number to global variable used for RegisterCpuInterruptHandler ()\r
202 //\r
203 mEnabledInterruptNum = ExceptionHandlerData->IdtEntryCount;\r
204}\r
205\r
206/**\r
207 Internal worker function to initialize exception handler.\r
208\r
209 @param[in] VectorInfo Pointer to reserved vector list.\r
210 @param[in, out] ExceptionHandlerData Pointer to exception handler data.\r
211 \r
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
217**/\r
218EFI_STATUS\r
219InitializeCpuExceptionHandlersWorker (\r
220 IN EFI_VECTOR_HANDOFF_INFO *VectorInfo OPTIONAL,\r
221 IN OUT EXCEPTION_HANDLER_DATA *ExceptionHandlerData\r
222 )\r
223{\r
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
229 RESERVED_VECTORS_DATA *ReservedVectors;\r
230\r
231 ReservedVectors = ExceptionHandlerData->ReservedVectors;\r
232 SetMem ((VOID *) ReservedVectors, sizeof (RESERVED_VECTORS_DATA) * CPU_EXCEPTION_NUM, 0xff);\r
233 if (VectorInfo != NULL) {\r
234 Status = ReadAndVerifyVectorInfo (VectorInfo, ReservedVectors, CPU_EXCEPTION_NUM);\r
235 if (EFI_ERROR (Status)) {\r
236 return EFI_INVALID_PARAMETER;\r
237 }\r
238 }\r
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
256\r
257 ExceptionHandlerData->IdtEntryCount = IdtEntryCount;\r
258 UpdateIdtTable (IdtTable, &TemplateMap, ExceptionHandlerData);\r
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
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
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
279**/\r
280EFI_STATUS\r
281RegisterCpuInterruptHandlerWorker (\r
282 IN EFI_EXCEPTION_TYPE InterruptType,\r
283 IN EFI_CPU_INTERRUPT_HANDLER InterruptHandler,\r
284 IN EXCEPTION_HANDLER_DATA *ExceptionHandlerData\r
285 )\r
286{\r
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
297 return EFI_UNSUPPORTED;\r
298 }\r
299\r
300 if (InterruptHandler == NULL && ExternalInterruptHandler[InterruptType] == NULL) {\r
301 return EFI_INVALID_PARAMETER;\r
302 }\r
303\r
304 if (InterruptHandler != NULL && ExternalInterruptHandler[InterruptType] != NULL) {\r
305 return EFI_ALREADY_STARTED;\r
306 }\r
307\r
308 ExternalInterruptHandler[InterruptType] = InterruptHandler;\r
309 return EFI_SUCCESS;\r
310}\r
311\r