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