]> git.proxmox.com Git - mirror_edk2.git/blame_incremental - UefiCpuPkg/Library/CpuExceptionHandlerLib/PeiDxeSmmCpuException.c
UefiCpuPkg: Replace BSD License with BSD+Patent License
[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 - 2018, Intel Corporation. All rights reserved.<BR>\r
5SPDX-License-Identifier: BSD-2-Clause-Patent\r
6\r
7**/\r
8\r
9#include "CpuExceptionCommon.h"\r
10#include <Library/DebugLib.h>\r
11\r
12/**\r
13 Internal worker function for common exception handler.\r
14\r
15 @param ExceptionType Exception type.\r
16 @param SystemContext Pointer to EFI_SYSTEM_CONTEXT.\r
17 @param ExceptionHandlerData Pointer to exception handler data.\r
18**/\r
19VOID\r
20CommonExceptionHandlerWorker (\r
21 IN EFI_EXCEPTION_TYPE ExceptionType,\r
22 IN EFI_SYSTEM_CONTEXT SystemContext,\r
23 IN EXCEPTION_HANDLER_DATA *ExceptionHandlerData\r
24 )\r
25{\r
26 EXCEPTION_HANDLER_CONTEXT *ExceptionHandlerContext;\r
27 RESERVED_VECTORS_DATA *ReservedVectors;\r
28 EFI_CPU_INTERRUPT_HANDLER *ExternalInterruptHandler;\r
29\r
30 ExceptionHandlerContext = (EXCEPTION_HANDLER_CONTEXT *) (UINTN) (SystemContext.SystemContextIa32);\r
31 ReservedVectors = ExceptionHandlerData->ReservedVectors;\r
32 ExternalInterruptHandler = ExceptionHandlerData->ExternalInterruptHandler;\r
33\r
34 switch (ReservedVectors[ExceptionType].Attribute) {\r
35 case EFI_VECTOR_HANDOFF_HOOK_BEFORE:\r
36 //\r
37 // The new exception handler registered by RegisterCpuInterruptHandler() is executed BEFORE original handler.\r
38 // Save the original handler to stack so the assembly code can jump to it instead of returning from handler.\r
39 //\r
40 ExceptionHandlerContext->ExceptionDataFlag = (mErrorCodeFlag & (1 << ExceptionType)) ? TRUE : FALSE;\r
41 ExceptionHandlerContext->OldIdtHandler = ReservedVectors[ExceptionType].ExceptonHandler;\r
42 break;\r
43 case EFI_VECTOR_HANDOFF_HOOK_AFTER:\r
44 while (TRUE) {\r
45 //\r
46 // If spin-lock can be acquired, it's the first time entering here.\r
47 //\r
48 if (AcquireSpinLockOrFail (&ReservedVectors[ExceptionType].SpinLock)) {\r
49 //\r
50 // The new exception handler registered by RegisterCpuInterruptHandler() is executed AFTER original handler.\r
51 // Save the original handler to stack but skip running the new handler so the original handler is executed\r
52 // firstly.\r
53 //\r
54 ReservedVectors[ExceptionType].ApicId = GetApicId ();\r
55 ArchSaveExceptionContext (ExceptionType, SystemContext, ExceptionHandlerData);\r
56 ExceptionHandlerContext->ExceptionDataFlag = (mErrorCodeFlag & (1 << ExceptionType)) ? TRUE : FALSE;\r
57 ExceptionHandlerContext->OldIdtHandler = ReservedVectors[ExceptionType].ExceptonHandler;\r
58 return;\r
59 }\r
60 //\r
61 // If spin-lock cannot be acquired, it's the second time entering here.\r
62 // 'break' instead of 'return' is used so the new exception handler can be executed.\r
63 //\r
64 if (ReservedVectors[ExceptionType].ApicId == GetApicId ()) {\r
65 //\r
66 // Old IDT handler has been executed, then restore CPU exception content to\r
67 // run new exception handler.\r
68 //\r
69 ArchRestoreExceptionContext (ExceptionType, SystemContext, ExceptionHandlerData);\r
70 //\r
71 // Rlease spin lock for ApicId\r
72 //\r
73 ReleaseSpinLock (&ReservedVectors[ExceptionType].SpinLock);\r
74 break;\r
75 }\r
76 CpuPause ();\r
77 }\r
78 break;\r
79 case 0xffffffff:\r
80 break;\r
81 default:\r
82 //\r
83 // It should never reach here\r
84 //\r
85 CpuDeadLoop ();\r
86 break;\r
87 }\r
88\r
89 if (ExternalInterruptHandler != NULL &&\r
90 ExternalInterruptHandler[ExceptionType] != NULL) {\r
91 (ExternalInterruptHandler[ExceptionType]) (ExceptionType, SystemContext);\r
92 } else if (ExceptionType < CPU_EXCEPTION_NUM) {\r
93 //\r
94 // Get Spinlock to display CPU information\r
95 //\r
96 while (!AcquireSpinLockOrFail (&ExceptionHandlerData->DisplayMessageSpinLock)) {\r
97 CpuPause ();\r
98 }\r
99 //\r
100 // Initialize the serial port before dumping.\r
101 //\r
102 SerialPortInitialize ();\r
103 //\r
104 // Display ExceptionType, CPU information and Image information\r
105 //\r
106 DumpImageAndCpuContent (ExceptionType, SystemContext);\r
107 //\r
108 // Release Spinlock of output message\r
109 //\r
110 ReleaseSpinLock (&ExceptionHandlerData->DisplayMessageSpinLock);\r
111 //\r
112 // Enter a dead loop if needn't to execute old IDT handler further\r
113 //\r
114 if (ReservedVectors[ExceptionType].Attribute != EFI_VECTOR_HANDOFF_HOOK_BEFORE) {\r
115 CpuDeadLoop ();\r
116 }\r
117 }\r
118}\r
119\r
120/**\r
121 Internal worker function to update IDT entries accordling to vector attributes.\r
122\r
123 @param[in] IdtTable Pointer to IDT table.\r
124 @param[in] TemplateMap Pointer to a buffer where the address map is\r
125 returned.\r
126 @param[in] ExceptionHandlerData Pointer to exception handler data.\r
127\r
128**/\r
129VOID\r
130UpdateIdtTable (\r
131 IN IA32_IDT_GATE_DESCRIPTOR *IdtTable,\r
132 IN EXCEPTION_HANDLER_TEMPLATE_MAP *TemplateMap,\r
133 IN EXCEPTION_HANDLER_DATA *ExceptionHandlerData\r
134 )\r
135{\r
136 UINT16 CodeSegment;\r
137 UINTN Index;\r
138 UINTN InterruptHandler;\r
139 RESERVED_VECTORS_DATA *ReservedVectors;\r
140\r
141 ReservedVectors = ExceptionHandlerData->ReservedVectors;\r
142 //\r
143 // Use current CS as the segment selector of interrupt gate in IDT\r
144 //\r
145 CodeSegment = AsmReadCs ();\r
146\r
147 for (Index = 0; Index < ExceptionHandlerData->IdtEntryCount; Index ++) {\r
148 IdtTable[Index].Bits.Selector = CodeSegment;\r
149 //\r
150 // Check reserved vectors attributes\r
151 //\r
152 switch (ReservedVectors[Index].Attribute) {\r
153 case EFI_VECTOR_HANDOFF_DO_NOT_HOOK:\r
154 //\r
155 // Keep original IDT entry\r
156 //\r
157 continue;\r
158 case EFI_VECTOR_HANDOFF_HOOK_AFTER:\r
159 InitializeSpinLock (&ReservedVectors[Index].SpinLock);\r
160 CopyMem (\r
161 (VOID *) ReservedVectors[Index].HookAfterStubHeaderCode,\r
162 (VOID *) TemplateMap->HookAfterStubHeaderStart,\r
163 TemplateMap->ExceptionStubHeaderSize\r
164 );\r
165 AsmVectorNumFixup (\r
166 (VOID *) ReservedVectors[Index].HookAfterStubHeaderCode,\r
167 (UINT8) Index,\r
168 (VOID *) TemplateMap->HookAfterStubHeaderStart\r
169 );\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 ReservedVectors[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
191\r
192/**\r
193 Internal worker function to initialize exception handler.\r
194\r
195 @param[in] VectorInfo Pointer to reserved vector list.\r
196 @param[in, out] ExceptionHandlerData Pointer to exception handler data.\r
197\r
198 @retval EFI_SUCCESS CPU Exception Entries have been successfully initialized\r
199 with default exception handlers.\r
200 @retval EFI_INVALID_PARAMETER VectorInfo includes the invalid content if VectorInfo is not NULL.\r
201 @retval EFI_UNSUPPORTED This function is not supported.\r
202\r
203**/\r
204EFI_STATUS\r
205InitializeCpuExceptionHandlersWorker (\r
206 IN EFI_VECTOR_HANDOFF_INFO *VectorInfo OPTIONAL,\r
207 IN OUT EXCEPTION_HANDLER_DATA *ExceptionHandlerData\r
208 )\r
209{\r
210 EFI_STATUS Status;\r
211 IA32_DESCRIPTOR IdtDescriptor;\r
212 UINTN IdtEntryCount;\r
213 EXCEPTION_HANDLER_TEMPLATE_MAP TemplateMap;\r
214 IA32_IDT_GATE_DESCRIPTOR *IdtTable;\r
215 RESERVED_VECTORS_DATA *ReservedVectors;\r
216\r
217 ReservedVectors = ExceptionHandlerData->ReservedVectors;\r
218 SetMem ((VOID *) ReservedVectors, sizeof (RESERVED_VECTORS_DATA) * CPU_EXCEPTION_NUM, 0xff);\r
219 if (VectorInfo != NULL) {\r
220 Status = ReadAndVerifyVectorInfo (VectorInfo, ReservedVectors, CPU_EXCEPTION_NUM);\r
221 if (EFI_ERROR (Status)) {\r
222 return EFI_INVALID_PARAMETER;\r
223 }\r
224 }\r
225\r
226 //\r
227 // Read IDT descriptor and calculate IDT size\r
228 //\r
229 AsmReadIdtr (&IdtDescriptor);\r
230 IdtEntryCount = (IdtDescriptor.Limit + 1) / sizeof (IA32_IDT_GATE_DESCRIPTOR);\r
231 if (IdtEntryCount > CPU_EXCEPTION_NUM) {\r
232 //\r
233 // CPU exeption library only setup CPU_EXCEPTION_NUM exception handler at most\r
234 //\r
235 IdtEntryCount = CPU_EXCEPTION_NUM;\r
236 }\r
237\r
238 IdtTable = (IA32_IDT_GATE_DESCRIPTOR *) IdtDescriptor.Base;\r
239 AsmGetTemplateAddressMap (&TemplateMap);\r
240 ASSERT (TemplateMap.ExceptionStubHeaderSize <= HOOKAFTER_STUB_SIZE);\r
241\r
242 ExceptionHandlerData->IdtEntryCount = IdtEntryCount;\r
243 UpdateIdtTable (IdtTable, &TemplateMap, ExceptionHandlerData);\r
244\r
245 return EFI_SUCCESS;\r
246}\r
247\r
248/**\r
249 Registers a function to be called from the processor interrupt handler.\r
250\r
251 @param[in] InterruptType Defines which interrupt or exception to hook.\r
252 @param[in] InterruptHandler A pointer to a function of type EFI_CPU_INTERRUPT_HANDLER that is called\r
253 when a processor interrupt occurs. If this parameter is NULL, then the handler\r
254 will be uninstalled\r
255 @param[in] ExceptionHandlerData Pointer to exception handler data.\r
256\r
257 @retval EFI_SUCCESS The handler for the processor interrupt was successfully installed or uninstalled.\r
258 @retval EFI_ALREADY_STARTED InterruptHandler is not NULL, and a handler for InterruptType was\r
259 previously installed.\r
260 @retval EFI_INVALID_PARAMETER InterruptHandler is NULL, and a handler for InterruptType was not\r
261 previously installed.\r
262 @retval EFI_UNSUPPORTED The interrupt specified by InterruptType is not supported,\r
263 or this function is not supported.\r
264**/\r
265EFI_STATUS\r
266RegisterCpuInterruptHandlerWorker (\r
267 IN EFI_EXCEPTION_TYPE InterruptType,\r
268 IN EFI_CPU_INTERRUPT_HANDLER InterruptHandler,\r
269 IN EXCEPTION_HANDLER_DATA *ExceptionHandlerData\r
270 )\r
271{\r
272 UINTN EnabledInterruptNum;\r
273 RESERVED_VECTORS_DATA *ReservedVectors;\r
274 EFI_CPU_INTERRUPT_HANDLER *ExternalInterruptHandler;\r
275\r
276 EnabledInterruptNum = ExceptionHandlerData->IdtEntryCount;\r
277 ReservedVectors = ExceptionHandlerData->ReservedVectors;\r
278 ExternalInterruptHandler = ExceptionHandlerData->ExternalInterruptHandler;\r
279\r
280 if (InterruptType < 0 || InterruptType >= (EFI_EXCEPTION_TYPE)EnabledInterruptNum ||\r
281 ReservedVectors[InterruptType].Attribute == EFI_VECTOR_HANDOFF_DO_NOT_HOOK) {\r
282 return EFI_UNSUPPORTED;\r
283 }\r
284\r
285 if (InterruptHandler == NULL && ExternalInterruptHandler[InterruptType] == NULL) {\r
286 return EFI_INVALID_PARAMETER;\r
287 }\r
288\r
289 if (InterruptHandler != NULL && ExternalInterruptHandler[InterruptType] != NULL) {\r
290 return EFI_ALREADY_STARTED;\r
291 }\r
292\r
293 ExternalInterruptHandler[InterruptType] = InterruptHandler;\r
294 return EFI_SUCCESS;\r
295}\r
296\r