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