]> git.proxmox.com Git - mirror_edk2.git/blob - UefiCpuPkg/Library/CpuExceptionHandlerLib/PeiDxeSmmCpuException.c
d4bc293db073121eb18019d68864088cd9724202
[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 - 2016, 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 //
20 // Image align size for DXE/SMM
21 //
22 CONST UINTN mImageAlignSize = SIZE_4KB;
23
24 RESERVED_VECTORS_DATA mReservedVectorsData[CPU_EXCEPTION_NUM];
25 EFI_CPU_INTERRUPT_HANDLER mExternalInterruptHandlerTable[CPU_EXCEPTION_NUM];
26 EFI_CPU_INTERRUPT_HANDLER *mExternalInterruptHandler = NULL;
27 UINTN mEnabledInterruptNum = 0;
28
29 /**
30 Internal worker function for common exception handler.
31
32 @param ExceptionType Exception type.
33 @param SystemContext Pointer to EFI_SYSTEM_CONTEXT.
34 @param ExceptionHandlerData Pointer to exception handler data.
35 **/
36 VOID
37 CommonExceptionHandlerWorker (
38 IN EFI_EXCEPTION_TYPE ExceptionType,
39 IN EFI_SYSTEM_CONTEXT SystemContext,
40 IN EXCEPTION_HANDLER_DATA *ExceptionHandlerData
41 )
42 {
43 EXCEPTION_HANDLER_CONTEXT *ExceptionHandlerContext;
44 RESERVED_VECTORS_DATA *ReservedVectors;
45 EFI_CPU_INTERRUPT_HANDLER *ExternalInterruptHandler;
46
47 ExceptionHandlerContext = (EXCEPTION_HANDLER_CONTEXT *) (UINTN) (SystemContext.SystemContextIa32);
48 ReservedVectors = ExceptionHandlerData->ReservedVectors;
49 ExternalInterruptHandler = ExceptionHandlerData->ExternalInterruptHandler;
50
51 switch (ReservedVectors[ExceptionType].Attribute) {
52 case EFI_VECTOR_HANDOFF_HOOK_BEFORE:
53 //
54 // Need to jmp to old IDT handler after this exception handler
55 //
56 ExceptionHandlerContext->ExceptionDataFlag = (mErrorCodeFlag & (1 << ExceptionType)) ? TRUE : FALSE;
57 ExceptionHandlerContext->OldIdtHandler = ReservedVectors[ExceptionType].ExceptonHandler;
58 break;
59 case EFI_VECTOR_HANDOFF_HOOK_AFTER:
60 while (TRUE) {
61 //
62 // If if anyone has gotten SPIN_LOCK for owner running hook after
63 //
64 if (AcquireSpinLockOrFail (&ReservedVectors[ExceptionType].SpinLock)) {
65 //
66 // Need to execute old IDT handler before running this exception handler
67 //
68 ReservedVectors[ExceptionType].ApicId = GetApicId ();
69 ArchSaveExceptionContext (ExceptionType, SystemContext);
70 ExceptionHandlerContext->ExceptionDataFlag = (mErrorCodeFlag & (1 << ExceptionType)) ? TRUE : FALSE;
71 ExceptionHandlerContext->OldIdtHandler = ReservedVectors[ExceptionType].ExceptonHandler;
72 return;
73 }
74 //
75 // If failed to acquire SPIN_LOCK, check if it was locked by processor itself
76 //
77 if (ReservedVectors[ExceptionType].ApicId == GetApicId ()) {
78 //
79 // Old IDT handler has been executed, then retore CPU exception content to
80 // run new exception handler.
81 //
82 ArchRestoreExceptionContext (ExceptionType, SystemContext);
83 //
84 // Rlease spin lock for ApicId
85 //
86 ReleaseSpinLock (&ReservedVectors[ExceptionType].SpinLock);
87 break;
88 }
89 CpuPause ();
90 }
91 break;
92 case 0xffffffff:
93 break;
94 default:
95 //
96 // It should never reach here
97 //
98 CpuDeadLoop ();
99 break;
100 }
101
102 if (ExternalInterruptHandler != NULL &&
103 ExternalInterruptHandler[ExceptionType] != NULL) {
104 (ExternalInterruptHandler[ExceptionType]) (ExceptionType, SystemContext);
105 } else if (ExceptionType < CPU_EXCEPTION_NUM) {
106 //
107 // Get Spinlock to display CPU information
108 //
109 while (!AcquireSpinLockOrFail (&ExceptionHandlerData->DisplayMessageSpinLock)) {
110 CpuPause ();
111 }
112 //
113 // Display ExceptionType, CPU information and Image information
114 //
115 DumpCpuContent (ExceptionType, SystemContext);
116 //
117 // Release Spinlock of output message
118 //
119 ReleaseSpinLock (&ExceptionHandlerData->DisplayMessageSpinLock);
120 //
121 // Enter a dead loop if needn't to execute old IDT handler further
122 //
123 if (ReservedVectors[ExceptionType].Attribute != EFI_VECTOR_HANDOFF_HOOK_BEFORE) {
124 CpuDeadLoop ();
125 }
126 }
127 }
128
129 /**
130 Internal worker function to update IDT entries accordling to vector attributes.
131
132 @param[in] IdtTable Pointer to IDT table.
133 @param[in] TemplateMap Pointer to a buffer where the address map is
134 returned.
135 @param[in] ExceptionHandlerData Pointer to exception handler data.
136
137 **/
138 VOID
139 UpdateIdtTable (
140 IN IA32_IDT_GATE_DESCRIPTOR *IdtTable,
141 IN EXCEPTION_HANDLER_TEMPLATE_MAP *TemplateMap,
142 IN EXCEPTION_HANDLER_DATA *ExceptionHandlerData
143 )
144 {
145 UINT16 CodeSegment;
146 UINTN Index;
147 UINTN InterruptHandler;
148 RESERVED_VECTORS_DATA *ReservedVectors;
149
150 ReservedVectors = ExceptionHandlerData->ReservedVectors;
151 //
152 // Use current CS as the segment selector of interrupt gate in IDT
153 //
154 CodeSegment = AsmReadCs ();
155
156 for (Index = 0; Index < ExceptionHandlerData->IdtEntryCount; Index ++) {
157 IdtTable[Index].Bits.Selector = CodeSegment;
158 //
159 // Check reserved vectors attributes
160 //
161 switch (ReservedVectors[Index].Attribute) {
162 case EFI_VECTOR_HANDOFF_DO_NOT_HOOK:
163 //
164 // Keep original IDT entry
165 //
166 continue;
167 case EFI_VECTOR_HANDOFF_HOOK_AFTER:
168 InitializeSpinLock (&ReservedVectors[Index].SpinLock);
169 CopyMem (
170 (VOID *) ReservedVectors[Index].HookAfterStubHeaderCode,
171 (VOID *) TemplateMap->HookAfterStubHeaderStart,
172 TemplateMap->ExceptionStubHeaderSize
173 );
174 AsmVectorNumFixup (
175 (VOID *) ReservedVectors[Index].HookAfterStubHeaderCode,
176 (UINT8) Index,
177 (VOID *) TemplateMap->HookAfterStubHeaderStart
178 );
179 //
180 // Go on the following code
181 //
182 case EFI_VECTOR_HANDOFF_HOOK_BEFORE:
183 //
184 // Save original IDT handler address
185 //
186 ReservedVectors[Index].ExceptonHandler = ArchGetIdtHandler (&IdtTable[Index]);
187 //
188 // Go on the following code
189 //
190 default:
191 //
192 // Update new IDT entry
193 //
194 InterruptHandler = TemplateMap->ExceptionStart + Index * TemplateMap->ExceptionStubHeaderSize;
195 ArchUpdateIdtEntry (&IdtTable[Index], InterruptHandler);
196 break;
197 }
198 }
199
200 //
201 // Save Interrupt number to global variable used for RegisterCpuInterruptHandler ()
202 //
203 mEnabledInterruptNum = ExceptionHandlerData->IdtEntryCount;
204 }
205
206 /**
207 Internal worker function to initialize exception handler.
208
209 @param[in] VectorInfo Pointer to reserved vector list.
210 @param[in, out] ExceptionHandlerData Pointer to exception handler data.
211
212 @retval EFI_SUCCESS CPU Exception Entries have been successfully initialized
213 with default exception handlers.
214 @retval EFI_INVALID_PARAMETER VectorInfo includes the invalid content if VectorInfo is not NULL.
215 @retval EFI_UNSUPPORTED This function is not supported.
216
217 **/
218 EFI_STATUS
219 InitializeCpuExceptionHandlersWorker (
220 IN EFI_VECTOR_HANDOFF_INFO *VectorInfo OPTIONAL,
221 IN OUT EXCEPTION_HANDLER_DATA *ExceptionHandlerData
222 )
223 {
224 EFI_STATUS Status;
225 IA32_DESCRIPTOR IdtDescriptor;
226 UINTN IdtEntryCount;
227 EXCEPTION_HANDLER_TEMPLATE_MAP TemplateMap;
228 IA32_IDT_GATE_DESCRIPTOR *IdtTable;
229 RESERVED_VECTORS_DATA *ReservedVectors;
230
231 ReservedVectors = ExceptionHandlerData->ReservedVectors;
232 SetMem ((VOID *) ReservedVectors, sizeof (RESERVED_VECTORS_DATA) * CPU_EXCEPTION_NUM, 0xff);
233 if (VectorInfo != NULL) {
234 Status = ReadAndVerifyVectorInfo (VectorInfo, ReservedVectors, CPU_EXCEPTION_NUM);
235 if (EFI_ERROR (Status)) {
236 return EFI_INVALID_PARAMETER;
237 }
238 }
239
240 mExternalInterruptHandler = mExternalInterruptHandlerTable;
241 //
242 // Read IDT descriptor and calculate IDT size
243 //
244 AsmReadIdtr (&IdtDescriptor);
245 IdtEntryCount = (IdtDescriptor.Limit + 1) / sizeof (IA32_IDT_GATE_DESCRIPTOR);
246 if (IdtEntryCount > CPU_EXCEPTION_NUM) {
247 //
248 // CPU exeption library only setup CPU_EXCEPTION_NUM exception handler at most
249 //
250 IdtEntryCount = CPU_EXCEPTION_NUM;
251 }
252
253 IdtTable = (IA32_IDT_GATE_DESCRIPTOR *) IdtDescriptor.Base;
254 AsmGetTemplateAddressMap (&TemplateMap);
255 ASSERT (TemplateMap.ExceptionStubHeaderSize <= HOOKAFTER_STUB_SIZE);
256
257 ExceptionHandlerData->IdtEntryCount = IdtEntryCount;
258 UpdateIdtTable (IdtTable, &TemplateMap, ExceptionHandlerData);
259 mEnabledInterruptNum = IdtEntryCount;
260 return EFI_SUCCESS;
261 }
262
263 /**
264 Registers a function to be called from the processor interrupt handler.
265
266 @param[in] InterruptType Defines which interrupt or exception to hook.
267 @param[in] InterruptHandler A pointer to a function of type EFI_CPU_INTERRUPT_HANDLER that is called
268 when a processor interrupt occurs. If this parameter is NULL, then the handler
269 will be uninstalled
270 @param[in] ExceptionHandlerData Pointer to exception handler data.
271
272 @retval EFI_SUCCESS The handler for the processor interrupt was successfully installed or uninstalled.
273 @retval EFI_ALREADY_STARTED InterruptHandler is not NULL, and a handler for InterruptType was
274 previously installed.
275 @retval EFI_INVALID_PARAMETER InterruptHandler is NULL, and a handler for InterruptType was not
276 previously installed.
277 @retval EFI_UNSUPPORTED The interrupt specified by InterruptType is not supported,
278 or this function is not supported.
279 **/
280 EFI_STATUS
281 RegisterCpuInterruptHandlerWorker (
282 IN EFI_EXCEPTION_TYPE InterruptType,
283 IN EFI_CPU_INTERRUPT_HANDLER InterruptHandler,
284 IN EXCEPTION_HANDLER_DATA *ExceptionHandlerData
285 )
286 {
287 UINTN EnabledInterruptNum;
288 RESERVED_VECTORS_DATA *ReservedVectors;
289 EFI_CPU_INTERRUPT_HANDLER *ExternalInterruptHandler;
290
291 EnabledInterruptNum = ExceptionHandlerData->IdtEntryCount;
292 ReservedVectors = ExceptionHandlerData->ReservedVectors;
293 ExternalInterruptHandler = ExceptionHandlerData->ExternalInterruptHandler;
294
295 if (InterruptType < 0 || InterruptType >= (EFI_EXCEPTION_TYPE)EnabledInterruptNum ||
296 ReservedVectors[InterruptType].Attribute == EFI_VECTOR_HANDOFF_DO_NOT_HOOK) {
297 return EFI_UNSUPPORTED;
298 }
299
300 if (InterruptHandler == NULL && ExternalInterruptHandler[InterruptType] == NULL) {
301 return EFI_INVALID_PARAMETER;
302 }
303
304 if (InterruptHandler != NULL && ExternalInterruptHandler[InterruptType] != NULL) {
305 return EFI_ALREADY_STARTED;
306 }
307
308 ExternalInterruptHandler[InterruptType] = InterruptHandler;
309 return EFI_SUCCESS;
310 }
311