]> git.proxmox.com Git - mirror_edk2.git/blob - UefiCpuPkg/Library/CpuExceptionHandlerLib/DxeSmmCpuException.c
1. Separated DxeSmmCpuExceptionHandlerLib.inf into 2 instance DxeCpuExceptionHandlerL...
[mirror_edk2.git] / UefiCpuPkg / Library / CpuExceptionHandlerLib / DxeSmmCpuException.c
1 /** @file
2 CPU Exception Library provides DXE/SMM CPU common exception handler.
3
4 Copyright (c) 2012 - 2013, 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 {
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 ((VOID *) mReservedVectors[Index].HookAfterStubHeaderCode, (UINT8) Index);
170 //
171 // Go on the following code
172 //
173 case EFI_VECTOR_HANDOFF_HOOK_BEFORE:
174 //
175 // Save original IDT handler address
176 //
177 mReservedVectors[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 // Save Interrupt number to global variable used for RegisterCpuInterruptHandler ()
193 //
194 mEnabledInterruptNum = IdtEntryCount;
195 }
196
197 /**
198 Internal worker function to initialize exception handler.
199
200 @param[in] VectorInfo Pointer to reserved vector list.
201
202 @retval EFI_SUCCESS CPU Exception Entries have been successfully initialized
203 with default exception handlers.
204 @retval EFI_INVALID_PARAMETER VectorInfo includes the invalid content if VectorInfo is not NULL.
205 @retval EFI_UNSUPPORTED This function is not supported.
206
207 **/
208 EFI_STATUS
209 InitializeCpuExceptionHandlersWorker (
210 IN EFI_VECTOR_HANDOFF_INFO *VectorInfo OPTIONAL
211 )
212 {
213 EFI_STATUS Status;
214 IA32_DESCRIPTOR IdtDescriptor;
215 UINTN IdtEntryCount;
216 EXCEPTION_HANDLER_TEMPLATE_MAP TemplateMap;
217 IA32_IDT_GATE_DESCRIPTOR *IdtTable;
218
219 mReservedVectors = mReservedVectorsData;
220 SetMem ((VOID *) mReservedVectors, sizeof (RESERVED_VECTORS_DATA) * CPU_EXCEPTION_NUM, 0xff);
221 if (VectorInfo != NULL) {
222 Status = ReadAndVerifyVectorInfo (VectorInfo, mReservedVectors, CPU_EXCEPTION_NUM);
223 if (EFI_ERROR (Status)) {
224 return EFI_INVALID_PARAMETER;
225 }
226 }
227 InitializeSpinLock (&mDisplayMessageSpinLock);
228
229 mExternalInterruptHandler = mExternalInterruptHandlerTable;
230 //
231 // Read IDT descriptor and calculate IDT size
232 //
233 AsmReadIdtr (&IdtDescriptor);
234 IdtEntryCount = (IdtDescriptor.Limit + 1) / sizeof (IA32_IDT_GATE_DESCRIPTOR);
235 if (IdtEntryCount > CPU_EXCEPTION_NUM) {
236 //
237 // CPU exeption library only setup CPU_EXCEPTION_NUM exception handler at most
238 //
239 IdtEntryCount = CPU_EXCEPTION_NUM;
240 }
241
242 IdtTable = (IA32_IDT_GATE_DESCRIPTOR *) IdtDescriptor.Base;
243 AsmGetTemplateAddressMap (&TemplateMap);
244 ASSERT (TemplateMap.ExceptionStubHeaderSize <= HOOKAFTER_STUB_SIZE);
245 UpdateIdtTable (IdtTable, &TemplateMap, IdtEntryCount);
246 mEnabledInterruptNum = IdtEntryCount;
247 return EFI_SUCCESS;
248 }
249
250 /**
251 Registers a function to be called from the processor interrupt handler.
252
253 @param[in] InterruptType Defines which interrupt or exception to hook.
254 @param[in] InterruptHandler A pointer to a function of type EFI_CPU_INTERRUPT_HANDLER that is called
255 when a processor interrupt occurs. If this parameter is NULL, then the handler
256 will be uninstalled.
257
258 @retval EFI_SUCCESS The handler for the processor interrupt was successfully installed or uninstalled.
259 @retval EFI_ALREADY_STARTED InterruptHandler is not NULL, and a handler for InterruptType was
260 previously installed.
261 @retval EFI_INVALID_PARAMETER InterruptHandler is NULL, and a handler for InterruptType was not
262 previously installed.
263 @retval EFI_UNSUPPORTED The interrupt specified by InterruptType is not supported,
264 or this function is not supported.
265 */
266 EFI_STATUS
267 RegisterCpuInterruptHandlerWorker (
268 IN EFI_EXCEPTION_TYPE InterruptType,
269 IN EFI_CPU_INTERRUPT_HANDLER InterruptHandler
270 )
271 {
272 if (InterruptType < 0 || InterruptType > (EFI_EXCEPTION_TYPE)mEnabledInterruptNum ||
273 mReservedVectors[InterruptType].Attribute == EFI_VECTOR_HANDOFF_DO_NOT_HOOK) {
274 return EFI_UNSUPPORTED;
275 }
276
277 if (InterruptHandler == NULL && mExternalInterruptHandler[InterruptType] == NULL) {
278 return EFI_INVALID_PARAMETER;
279 }
280
281 if (InterruptHandler != NULL && mExternalInterruptHandler[InterruptType] != NULL) {
282 return EFI_ALREADY_STARTED;
283 }
284
285 mExternalInterruptHandler[InterruptType] = InterruptHandler;
286 return EFI_SUCCESS;
287 }
288