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