]> git.proxmox.com Git - mirror_edk2.git/blame_incremental - UefiCpuPkg/Library/CpuExceptionHandlerLib/PeiDxeSmmCpuException.c
UefiCpuPkg/ExceptionLib: Update UpdateIdtTable()
[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// 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
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
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
42 IN EFI_EXCEPTION_TYPE ExceptionType, \r
43 IN EFI_SYSTEM_CONTEXT SystemContext\r
44 )\r
45{\r
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
99 }\r
100 \r
101 if (mExternalInterruptHandler[ExceptionType] != NULL) {\r
102 (mExternalInterruptHandler[ExceptionType]) (ExceptionType, SystemContext);\r
103 } else if (ExceptionType < CPU_EXCEPTION_NUM) {\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
126\r
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\r
132 returned.\r
133 @param[in] ExceptionHandlerData Pointer to exception handler data.\r
134\r
135**/\r
136VOID\r
137UpdateIdtTable (\r
138 IN IA32_IDT_GATE_DESCRIPTOR *IdtTable,\r
139 IN EXCEPTION_HANDLER_TEMPLATE_MAP *TemplateMap,\r
140 IN EXCEPTION_HANDLER_DATA *ExceptionHandlerData\r
141 )\r
142{\r
143 UINT16 CodeSegment;\r
144 UINTN Index;\r
145 UINTN InterruptHandler;\r
146 RESERVED_VECTORS_DATA *ReservedVectors;\r
147\r
148 ReservedVectors = ExceptionHandlerData->ReservedVectors;\r
149 //\r
150 // Use current CS as the segment selector of interrupt gate in IDT\r
151 //\r
152 CodeSegment = AsmReadCs ();\r
153\r
154 for (Index = 0; Index < ExceptionHandlerData->IdtEntryCount; Index ++) {\r
155 IdtTable[Index].Bits.Selector = CodeSegment;\r
156 //\r
157 // Check reserved vectors attributes\r
158 //\r
159 switch (ReservedVectors[Index].Attribute) {\r
160 case EFI_VECTOR_HANDOFF_DO_NOT_HOOK:\r
161 //\r
162 // Keep original IDT entry\r
163 //\r
164 continue;\r
165 case EFI_VECTOR_HANDOFF_HOOK_AFTER:\r
166 InitializeSpinLock (&ReservedVectors[Index].SpinLock);\r
167 CopyMem (\r
168 (VOID *) ReservedVectors[Index].HookAfterStubHeaderCode,\r
169 (VOID *) TemplateMap->HookAfterStubHeaderStart,\r
170 TemplateMap->ExceptionStubHeaderSize\r
171 );\r
172 AsmVectorNumFixup (\r
173 (VOID *) ReservedVectors[Index].HookAfterStubHeaderCode,\r
174 (UINT8) Index,\r
175 (VOID *) TemplateMap->HookAfterStubHeaderStart\r
176 );\r
177 //\r
178 // Go on the following code\r
179 //\r
180 case EFI_VECTOR_HANDOFF_HOOK_BEFORE:\r
181 //\r
182 // Save original IDT handler address\r
183 //\r
184 ReservedVectors[Index].ExceptonHandler = ArchGetIdtHandler (&IdtTable[Index]);\r
185 //\r
186 // Go on the following code\r
187 //\r
188 default:\r
189 //\r
190 // Update new IDT entry\r
191 //\r
192 InterruptHandler = TemplateMap->ExceptionStart + Index * TemplateMap->ExceptionStubHeaderSize;\r
193 ArchUpdateIdtEntry (&IdtTable[Index], InterruptHandler);\r
194 break;\r
195 }\r
196 }\r
197 \r
198 //\r
199 // Save Interrupt number to global variable used for RegisterCpuInterruptHandler ()\r
200 //\r
201 mEnabledInterruptNum = ExceptionHandlerData->IdtEntryCount;\r
202}\r
203\r
204/**\r
205 Internal worker function to initialize exception handler.\r
206\r
207 @param[in] VectorInfo Pointer to reserved vector list.\r
208 @param[in, out] ExceptionHandlerData Pointer to exception handler data.\r
209 \r
210 @retval EFI_SUCCESS CPU Exception Entries have been successfully initialized \r
211 with default exception handlers.\r
212 @retval EFI_INVALID_PARAMETER VectorInfo includes the invalid content if VectorInfo is not NULL.\r
213 @retval EFI_UNSUPPORTED This function is not supported.\r
214\r
215**/\r
216EFI_STATUS\r
217InitializeCpuExceptionHandlersWorker (\r
218 IN EFI_VECTOR_HANDOFF_INFO *VectorInfo OPTIONAL,\r
219 IN OUT EXCEPTION_HANDLER_DATA *ExceptionHandlerData\r
220 )\r
221{\r
222 EFI_STATUS Status;\r
223 IA32_DESCRIPTOR IdtDescriptor;\r
224 UINTN IdtEntryCount;\r
225 EXCEPTION_HANDLER_TEMPLATE_MAP TemplateMap;\r
226 IA32_IDT_GATE_DESCRIPTOR *IdtTable;\r
227 RESERVED_VECTORS_DATA *ReservedVectors;\r
228\r
229 ReservedVectors = ExceptionHandlerData->ReservedVectors;\r
230 SetMem ((VOID *) ReservedVectors, sizeof (RESERVED_VECTORS_DATA) * CPU_EXCEPTION_NUM, 0xff);\r
231 if (VectorInfo != NULL) {\r
232 Status = ReadAndVerifyVectorInfo (VectorInfo, ReservedVectors, CPU_EXCEPTION_NUM);\r
233 if (EFI_ERROR (Status)) {\r
234 return EFI_INVALID_PARAMETER;\r
235 }\r
236 }\r
237 InitializeSpinLock (&mDisplayMessageSpinLock);\r
238\r
239 mExternalInterruptHandler = mExternalInterruptHandlerTable;\r
240 //\r
241 // Read IDT descriptor and calculate IDT size\r
242 //\r
243 AsmReadIdtr (&IdtDescriptor);\r
244 IdtEntryCount = (IdtDescriptor.Limit + 1) / sizeof (IA32_IDT_GATE_DESCRIPTOR);\r
245 if (IdtEntryCount > CPU_EXCEPTION_NUM) {\r
246 //\r
247 // CPU exeption library only setup CPU_EXCEPTION_NUM exception handler at most\r
248 //\r
249 IdtEntryCount = CPU_EXCEPTION_NUM;\r
250 }\r
251\r
252 IdtTable = (IA32_IDT_GATE_DESCRIPTOR *) IdtDescriptor.Base;\r
253 AsmGetTemplateAddressMap (&TemplateMap);\r
254 ASSERT (TemplateMap.ExceptionStubHeaderSize <= HOOKAFTER_STUB_SIZE);\r
255\r
256 ExceptionHandlerData->IdtEntryCount = IdtEntryCount;\r
257 UpdateIdtTable (IdtTable, &TemplateMap, ExceptionHandlerData);\r
258 mEnabledInterruptNum = IdtEntryCount;\r
259 return EFI_SUCCESS;\r
260}\r
261\r
262/**\r
263 Registers a function to be called from the processor interrupt handler.\r
264\r
265 @param[in] InterruptType Defines which interrupt or exception to hook.\r
266 @param[in] InterruptHandler A pointer to a function of type EFI_CPU_INTERRUPT_HANDLER that is called\r
267 when a processor interrupt occurs. If this parameter is NULL, then the handler\r
268 will be uninstalled.\r
269\r
270 @retval EFI_SUCCESS The handler for the processor interrupt was successfully installed or uninstalled.\r
271 @retval EFI_ALREADY_STARTED InterruptHandler is not NULL, and a handler for InterruptType was\r
272 previously installed.\r
273 @retval EFI_INVALID_PARAMETER InterruptHandler is NULL, and a handler for InterruptType was not\r
274 previously installed.\r
275 @retval EFI_UNSUPPORTED The interrupt specified by InterruptType is not supported,\r
276 or this function is not supported.\r
277**/\r
278EFI_STATUS\r
279RegisterCpuInterruptHandlerWorker (\r
280 IN EFI_EXCEPTION_TYPE InterruptType,\r
281 IN EFI_CPU_INTERRUPT_HANDLER InterruptHandler\r
282 )\r
283{\r
284 if (InterruptType < 0 || InterruptType >= (EFI_EXCEPTION_TYPE)mEnabledInterruptNum ||\r
285 mReservedVectors[InterruptType].Attribute == EFI_VECTOR_HANDOFF_DO_NOT_HOOK) {\r
286 return EFI_UNSUPPORTED;\r
287 }\r
288\r
289 if (InterruptHandler == NULL && mExternalInterruptHandler[InterruptType] == NULL) {\r
290 return EFI_INVALID_PARAMETER;\r
291 }\r
292\r
293 if (InterruptHandler != NULL && mExternalInterruptHandler[InterruptType] != NULL) {\r
294 return EFI_ALREADY_STARTED;\r
295 }\r
296\r
297 mExternalInterruptHandler[InterruptType] = InterruptHandler;\r
298 return EFI_SUCCESS;\r
299}\r
300\r