]> git.proxmox.com Git - mirror_edk2.git/blame - UefiCpuPkg/Library/CpuExceptionHandlerLib/DxeSmmCpuException.c
1. Separated DxeSmmCpuExceptionHandlerLib.inf into 2 instance DxeCpuExceptionHandlerL...
[mirror_edk2.git] / UefiCpuPkg / Library / CpuExceptionHandlerLib / DxeSmmCpuException.c
CommitLineData
8f07f895 1/** @file\r
e41aad15 2 CPU Exception Library provides DXE/SMM CPU common exception handler.\r
8f07f895 3\r
e41aad15 4Copyright (c) 2012 - 2013, 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
103 } else {\r
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
169 AsmVectorNumFixup ((VOID *) mReservedVectors[Index].HookAfterStubHeaderCode, (UINT8) Index);\r
170 //\r
171 // Go on the following code\r
172 //\r
173 case EFI_VECTOR_HANDOFF_HOOK_BEFORE:\r
174 //\r
175 // Save original IDT handler address\r
176 //\r
177 mReservedVectors[Index].ExceptonHandler = ArchGetIdtHandler (&IdtTable[Index]);\r
178 //\r
179 // Go on the following code\r
180 //\r
181 default:\r
182 //\r
183 // Update new IDT entry\r
184 //\r
185 InterruptHandler = TemplateMap->ExceptionStart + Index * TemplateMap->ExceptionStubHeaderSize;\r
186 ArchUpdateIdtEntry (&IdtTable[Index], InterruptHandler);\r
187 break;\r
188 }\r
189 }\r
190 \r
8f07f895 191 //\r
e41aad15 192 // Save Interrupt number to global variable used for RegisterCpuInterruptHandler ()\r
8f07f895 193 //\r
e41aad15 194 mEnabledInterruptNum = IdtEntryCount;\r
8f07f895 195}\r
196\r
197/**\r
e41aad15 198 Internal worker function to initialize exception handler.\r
8f07f895 199\r
e41aad15 200 @param[in] VectorInfo Pointer to reserved vector list.\r
8f07f895 201 \r
e41aad15
JF
202 @retval EFI_SUCCESS CPU Exception Entries have been successfully initialized \r
203 with default exception handlers.\r
204 @retval EFI_INVALID_PARAMETER VectorInfo includes the invalid content if VectorInfo is not NULL.\r
205 @retval EFI_UNSUPPORTED This function is not supported.\r
206\r
8f07f895 207**/\r
e41aad15
JF
208EFI_STATUS\r
209InitializeCpuExceptionHandlersWorker (\r
210 IN EFI_VECTOR_HANDOFF_INFO *VectorInfo OPTIONAL\r
8f07f895 211 )\r
212{\r
e41aad15
JF
213 EFI_STATUS Status;\r
214 IA32_DESCRIPTOR IdtDescriptor;\r
215 UINTN IdtEntryCount;\r
216 EXCEPTION_HANDLER_TEMPLATE_MAP TemplateMap;\r
217 IA32_IDT_GATE_DESCRIPTOR *IdtTable;\r
218\r
219 mReservedVectors = mReservedVectorsData;\r
220 SetMem ((VOID *) mReservedVectors, sizeof (RESERVED_VECTORS_DATA) * CPU_EXCEPTION_NUM, 0xff);\r
221 if (VectorInfo != NULL) {\r
222 Status = ReadAndVerifyVectorInfo (VectorInfo, mReservedVectors, CPU_EXCEPTION_NUM);\r
223 if (EFI_ERROR (Status)) {\r
224 return EFI_INVALID_PARAMETER;\r
225 }\r
226 }\r
8f07f895 227 InitializeSpinLock (&mDisplayMessageSpinLock);\r
e41aad15
JF
228\r
229 mExternalInterruptHandler = mExternalInterruptHandlerTable;\r
230 //\r
231 // Read IDT descriptor and calculate IDT size\r
232 //\r
233 AsmReadIdtr (&IdtDescriptor);\r
234 IdtEntryCount = (IdtDescriptor.Limit + 1) / sizeof (IA32_IDT_GATE_DESCRIPTOR);\r
235 if (IdtEntryCount > CPU_EXCEPTION_NUM) {\r
236 //\r
237 // CPU exeption library only setup CPU_EXCEPTION_NUM exception handler at most\r
238 //\r
239 IdtEntryCount = CPU_EXCEPTION_NUM;\r
240 }\r
241\r
242 IdtTable = (IA32_IDT_GATE_DESCRIPTOR *) IdtDescriptor.Base;\r
243 AsmGetTemplateAddressMap (&TemplateMap);\r
244 ASSERT (TemplateMap.ExceptionStubHeaderSize <= HOOKAFTER_STUB_SIZE);\r
245 UpdateIdtTable (IdtTable, &TemplateMap, IdtEntryCount);\r
246 mEnabledInterruptNum = IdtEntryCount;\r
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
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\r
258 @retval EFI_SUCCESS The handler for the processor interrupt was successfully installed or uninstalled.\r
259 @retval EFI_ALREADY_STARTED InterruptHandler is not NULL, and a handler for InterruptType was\r
260 previously installed.\r
261 @retval EFI_INVALID_PARAMETER InterruptHandler is NULL, and a handler for InterruptType was not\r
262 previously installed.\r
263 @retval EFI_UNSUPPORTED The interrupt specified by InterruptType is not supported,\r
264 or this function is not supported.\r
265*/\r
266EFI_STATUS\r
267RegisterCpuInterruptHandlerWorker (\r
268 IN EFI_EXCEPTION_TYPE InterruptType,\r
269 IN EFI_CPU_INTERRUPT_HANDLER InterruptHandler\r
270 )\r
271{\r
272 if (InterruptType < 0 || InterruptType > (EFI_EXCEPTION_TYPE)mEnabledInterruptNum ||\r
273 mReservedVectors[InterruptType].Attribute == EFI_VECTOR_HANDOFF_DO_NOT_HOOK) {\r
274 return EFI_UNSUPPORTED;\r
275 }\r
276\r
277 if (InterruptHandler == NULL && mExternalInterruptHandler[InterruptType] == NULL) {\r
278 return EFI_INVALID_PARAMETER;\r
279 }\r
280\r
281 if (InterruptHandler != NULL && mExternalInterruptHandler[InterruptType] != NULL) {\r
282 return EFI_ALREADY_STARTED;\r
283 }\r
284\r
285 mExternalInterruptHandler[InterruptType] = InterruptHandler;\r
286 return EFI_SUCCESS;\r
8f07f895 287}\r
288\r