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