]> git.proxmox.com Git - mirror_edk2.git/blame - UefiCpuPkg/Library/CpuExceptionHandlerLib/PeiDxeSmmCpuException.c
UefiCpuPkg/ExceptionLib: Update UpdateIdtTable()
[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
9db15f81
JF
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
e41aad15
JF
134\r
135**/\r
136VOID\r
137UpdateIdtTable (\r
138 IN IA32_IDT_GATE_DESCRIPTOR *IdtTable,\r
139 IN EXCEPTION_HANDLER_TEMPLATE_MAP *TemplateMap,\r
9db15f81 140 IN EXCEPTION_HANDLER_DATA *ExceptionHandlerData\r
e41aad15
JF
141 )\r
142{\r
143 UINT16 CodeSegment;\r
144 UINTN Index;\r
145 UINTN InterruptHandler;\r
9db15f81 146 RESERVED_VECTORS_DATA *ReservedVectors;\r
8f07f895 147\r
9db15f81 148 ReservedVectors = ExceptionHandlerData->ReservedVectors;\r
8f07f895 149 //\r
e41aad15 150 // Use current CS as the segment selector of interrupt gate in IDT\r
8f07f895 151 //\r
e41aad15 152 CodeSegment = AsmReadCs ();\r
8f07f895 153\r
9db15f81 154 for (Index = 0; Index < ExceptionHandlerData->IdtEntryCount; Index ++) {\r
e41aad15
JF
155 IdtTable[Index].Bits.Selector = CodeSegment;\r
156 //\r
157 // Check reserved vectors attributes\r
158 //\r
9db15f81 159 switch (ReservedVectors[Index].Attribute) {\r
e41aad15
JF
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
9db15f81 166 InitializeSpinLock (&ReservedVectors[Index].SpinLock);\r
e41aad15 167 CopyMem (\r
9db15f81 168 (VOID *) ReservedVectors[Index].HookAfterStubHeaderCode,\r
e41aad15
JF
169 (VOID *) TemplateMap->HookAfterStubHeaderStart,\r
170 TemplateMap->ExceptionStubHeaderSize\r
171 );\r
07da1ac8 172 AsmVectorNumFixup (\r
9db15f81 173 (VOID *) ReservedVectors[Index].HookAfterStubHeaderCode,\r
07da1ac8
AF
174 (UINT8) Index,\r
175 (VOID *) TemplateMap->HookAfterStubHeaderStart\r
176 );\r
e41aad15
JF
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
9db15f81 184 ReservedVectors[Index].ExceptonHandler = ArchGetIdtHandler (&IdtTable[Index]);\r
e41aad15
JF
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
8f07f895 198 //\r
e41aad15 199 // Save Interrupt number to global variable used for RegisterCpuInterruptHandler ()\r
8f07f895 200 //\r
9db15f81 201 mEnabledInterruptNum = ExceptionHandlerData->IdtEntryCount;\r
8f07f895 202}\r
203\r
204/**\r
e41aad15 205 Internal worker function to initialize exception handler.\r
8f07f895 206\r
ab95e54d
JF
207 @param[in] VectorInfo Pointer to reserved vector list.\r
208 @param[in, out] ExceptionHandlerData Pointer to exception handler data.\r
8f07f895 209 \r
e41aad15
JF
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
8f07f895 215**/\r
e41aad15
JF
216EFI_STATUS\r
217InitializeCpuExceptionHandlersWorker (\r
ab95e54d
JF
218 IN EFI_VECTOR_HANDOFF_INFO *VectorInfo OPTIONAL,\r
219 IN OUT EXCEPTION_HANDLER_DATA *ExceptionHandlerData\r
8f07f895 220 )\r
221{\r
e41aad15
JF
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
ab95e54d 227 RESERVED_VECTORS_DATA *ReservedVectors;\r
e41aad15 228\r
ab95e54d
JF
229 ReservedVectors = ExceptionHandlerData->ReservedVectors;\r
230 SetMem ((VOID *) ReservedVectors, sizeof (RESERVED_VECTORS_DATA) * CPU_EXCEPTION_NUM, 0xff);\r
e41aad15 231 if (VectorInfo != NULL) {\r
ab95e54d 232 Status = ReadAndVerifyVectorInfo (VectorInfo, ReservedVectors, CPU_EXCEPTION_NUM);\r
e41aad15
JF
233 if (EFI_ERROR (Status)) {\r
234 return EFI_INVALID_PARAMETER;\r
235 }\r
236 }\r
8f07f895 237 InitializeSpinLock (&mDisplayMessageSpinLock);\r
e41aad15
JF
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
9db15f81
JF
255\r
256 ExceptionHandlerData->IdtEntryCount = IdtEntryCount;\r
257 UpdateIdtTable (IdtTable, &TemplateMap, ExceptionHandlerData);\r
e41aad15
JF
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
3f25e6ea 277**/\r
e41aad15
JF
278EFI_STATUS\r
279RegisterCpuInterruptHandlerWorker (\r
280 IN EFI_EXCEPTION_TYPE InterruptType,\r
281 IN EFI_CPU_INTERRUPT_HANDLER InterruptHandler\r
282 )\r
283{\r
f3b113bf 284 if (InterruptType < 0 || InterruptType >= (EFI_EXCEPTION_TYPE)mEnabledInterruptNum ||\r
e41aad15
JF
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
8f07f895 299}\r
300\r