]> git.proxmox.com Git - mirror_edk2.git/blame - UefiCpuPkg/Library/CpuExceptionHandlerLib/PeiDxeSmmCpuException.c
UefiCpuPkg/ExceptionLib: Rename DxeSmmCpuException.c
[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
e41aad15 204 @param[in] VectorInfo Pointer to reserved vector list.\r
8f07f895 205 \r
e41aad15
JF
206 @retval EFI_SUCCESS CPU Exception Entries have been successfully initialized \r
207 with default exception handlers.\r
208 @retval EFI_INVALID_PARAMETER VectorInfo includes the invalid content if VectorInfo is not NULL.\r
209 @retval EFI_UNSUPPORTED This function is not supported.\r
210\r
8f07f895 211**/\r
e41aad15
JF
212EFI_STATUS\r
213InitializeCpuExceptionHandlersWorker (\r
214 IN EFI_VECTOR_HANDOFF_INFO *VectorInfo OPTIONAL\r
8f07f895 215 )\r
216{\r
e41aad15
JF
217 EFI_STATUS Status;\r
218 IA32_DESCRIPTOR IdtDescriptor;\r
219 UINTN IdtEntryCount;\r
220 EXCEPTION_HANDLER_TEMPLATE_MAP TemplateMap;\r
221 IA32_IDT_GATE_DESCRIPTOR *IdtTable;\r
222\r
223 mReservedVectors = mReservedVectorsData;\r
224 SetMem ((VOID *) mReservedVectors, sizeof (RESERVED_VECTORS_DATA) * CPU_EXCEPTION_NUM, 0xff);\r
225 if (VectorInfo != NULL) {\r
226 Status = ReadAndVerifyVectorInfo (VectorInfo, mReservedVectors, CPU_EXCEPTION_NUM);\r
227 if (EFI_ERROR (Status)) {\r
228 return EFI_INVALID_PARAMETER;\r
229 }\r
230 }\r
8f07f895 231 InitializeSpinLock (&mDisplayMessageSpinLock);\r
e41aad15
JF
232\r
233 mExternalInterruptHandler = mExternalInterruptHandlerTable;\r
234 //\r
235 // Read IDT descriptor and calculate IDT size\r
236 //\r
237 AsmReadIdtr (&IdtDescriptor);\r
238 IdtEntryCount = (IdtDescriptor.Limit + 1) / sizeof (IA32_IDT_GATE_DESCRIPTOR);\r
239 if (IdtEntryCount > CPU_EXCEPTION_NUM) {\r
240 //\r
241 // CPU exeption library only setup CPU_EXCEPTION_NUM exception handler at most\r
242 //\r
243 IdtEntryCount = CPU_EXCEPTION_NUM;\r
244 }\r
245\r
246 IdtTable = (IA32_IDT_GATE_DESCRIPTOR *) IdtDescriptor.Base;\r
247 AsmGetTemplateAddressMap (&TemplateMap);\r
248 ASSERT (TemplateMap.ExceptionStubHeaderSize <= HOOKAFTER_STUB_SIZE);\r
249 UpdateIdtTable (IdtTable, &TemplateMap, IdtEntryCount);\r
250 mEnabledInterruptNum = IdtEntryCount;\r
251 return EFI_SUCCESS;\r
252}\r
253\r
254/**\r
255 Registers a function to be called from the processor interrupt handler.\r
256\r
257 @param[in] InterruptType Defines which interrupt or exception to hook.\r
258 @param[in] InterruptHandler A pointer to a function of type EFI_CPU_INTERRUPT_HANDLER that is called\r
259 when a processor interrupt occurs. If this parameter is NULL, then the handler\r
260 will be uninstalled.\r
261\r
262 @retval EFI_SUCCESS The handler for the processor interrupt was successfully installed or uninstalled.\r
263 @retval EFI_ALREADY_STARTED InterruptHandler is not NULL, and a handler for InterruptType was\r
264 previously installed.\r
265 @retval EFI_INVALID_PARAMETER InterruptHandler is NULL, and a handler for InterruptType was not\r
266 previously installed.\r
267 @retval EFI_UNSUPPORTED The interrupt specified by InterruptType is not supported,\r
268 or this function is not supported.\r
3f25e6ea 269**/\r
e41aad15
JF
270EFI_STATUS\r
271RegisterCpuInterruptHandlerWorker (\r
272 IN EFI_EXCEPTION_TYPE InterruptType,\r
273 IN EFI_CPU_INTERRUPT_HANDLER InterruptHandler\r
274 )\r
275{\r
f3b113bf 276 if (InterruptType < 0 || InterruptType >= (EFI_EXCEPTION_TYPE)mEnabledInterruptNum ||\r
e41aad15
JF
277 mReservedVectors[InterruptType].Attribute == EFI_VECTOR_HANDOFF_DO_NOT_HOOK) {\r
278 return EFI_UNSUPPORTED;\r
279 }\r
280\r
281 if (InterruptHandler == NULL && mExternalInterruptHandler[InterruptType] == NULL) {\r
282 return EFI_INVALID_PARAMETER;\r
283 }\r
284\r
285 if (InterruptHandler != NULL && mExternalInterruptHandler[InterruptType] != NULL) {\r
286 return EFI_ALREADY_STARTED;\r
287 }\r
288\r
289 mExternalInterruptHandler[InterruptType] = InterruptHandler;\r
290 return EFI_SUCCESS;\r
8f07f895 291}\r
292\r