]> git.proxmox.com Git - mirror_edk2.git/blame - UefiCpuPkg/Library/CpuExceptionHandlerLib/DxeException.c
UefiCpuPkg/MpInitLib: Avoid calling PEI services from AP
[mirror_edk2.git] / UefiCpuPkg / Library / CpuExceptionHandlerLib / DxeException.c
CommitLineData
e41aad15
JF
1/** @file\r
2 CPU exception handler library implemenation for DXE modules.\r
3\r
1b2f7b3e 4 Copyright (c) 2013 - 2017, Intel Corporation. All rights reserved.<BR>\r
e41aad15
JF
5 This program and the accompanying materials\r
6 are licensed and made available under the terms and conditions of the BSD License\r
7 which accompanies this distribution. The full text of the license may be found at\r
8 http://opensource.org/licenses/bsd-license.php\r
9\r
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
12\r
13**/\r
14\r
15#include <PiDxe.h>\r
16#include "CpuExceptionCommon.h"\r
17#include <Library/DebugLib.h>\r
18#include <Library/MemoryAllocationLib.h>\r
fceafda5 19#include <Library/UefiBootServicesTableLib.h>\r
e41aad15
JF
20\r
21CONST UINTN mDoFarReturnFlag = 0;\r
22\r
d91225cf
JF
23RESERVED_VECTORS_DATA mReservedVectorsData[CPU_EXCEPTION_NUM];\r
24EFI_CPU_INTERRUPT_HANDLER mExternalInterruptHandlerTable[CPU_EXCEPTION_NUM];\r
25UINTN mEnabledInterruptNum = 0;\r
26\r
2c5873fe 27EXCEPTION_HANDLER_DATA mExceptionHandlerData;\r
e41aad15 28\r
0ff5aa9c
JW
29UINT8 mNewStack[CPU_STACK_SWITCH_EXCEPTION_NUMBER *\r
30 CPU_KNOWN_GOOD_STACK_SIZE];\r
31UINT8 mNewGdt[CPU_TSS_GDT_SIZE];\r
32\r
44ecbc28
JF
33/**\r
34 Common exception handler.\r
35\r
36 @param ExceptionType Exception type.\r
37 @param SystemContext Pointer to EFI_SYSTEM_CONTEXT.\r
38**/\r
39VOID\r
40EFIAPI\r
41CommonExceptionHandler (\r
dd563742 42 IN EFI_EXCEPTION_TYPE ExceptionType,\r
44ecbc28
JF
43 IN EFI_SYSTEM_CONTEXT SystemContext\r
44 )\r
45{\r
46 CommonExceptionHandlerWorker (ExceptionType, SystemContext, &mExceptionHandlerData);\r
47}\r
48\r
e41aad15
JF
49/**\r
50 Initializes all CPU exceptions entries and provides the default exception handlers.\r
dd563742 51\r
e41aad15
JF
52 Caller should try to get an array of interrupt and/or exception vectors that are in use and need to\r
53 persist by EFI_VECTOR_HANDOFF_INFO defined in PI 1.3 specification.\r
dd563742 54 If caller cannot get reserved vector list or it does not exists, set VectorInfo to NULL.\r
e41aad15
JF
55 If VectorInfo is not NULL, the exception vectors will be initialized per vector attribute accordingly.\r
56\r
57 @param[in] VectorInfo Pointer to reserved vector list.\r
dd563742
JF
58\r
59 @retval EFI_SUCCESS CPU Exception Entries have been successfully initialized\r
e41aad15
JF
60 with default exception handlers.\r
61 @retval EFI_INVALID_PARAMETER VectorInfo includes the invalid content if VectorInfo is not NULL.\r
62 @retval EFI_UNSUPPORTED This function is not supported.\r
63\r
64**/\r
65EFI_STATUS\r
66EFIAPI\r
67InitializeCpuExceptionHandlers (\r
68 IN EFI_VECTOR_HANDOFF_INFO *VectorInfo OPTIONAL\r
69 )\r
70{\r
ab95e54d
JF
71 mExceptionHandlerData.ReservedVectors = mReservedVectorsData;\r
72 mExceptionHandlerData.ExternalInterruptHandler = mExternalInterruptHandlerTable;\r
73 InitializeSpinLock (&mExceptionHandlerData.DisplayMessageSpinLock);\r
74 return InitializeCpuExceptionHandlersWorker (VectorInfo, &mExceptionHandlerData);\r
e41aad15
JF
75}\r
76\r
77/**\r
78 Initializes all CPU interrupt/exceptions entries and provides the default interrupt/exception handlers.\r
dd563742 79\r
e41aad15
JF
80 Caller should try to get an array of interrupt and/or exception vectors that are in use and need to\r
81 persist by EFI_VECTOR_HANDOFF_INFO defined in PI 1.3 specification.\r
dd563742 82 If caller cannot get reserved vector list or it does not exists, set VectorInfo to NULL.\r
e41aad15
JF
83 If VectorInfo is not NULL, the exception vectors will be initialized per vector attribute accordingly.\r
84\r
85 @param[in] VectorInfo Pointer to reserved vector list.\r
dd563742
JF
86\r
87 @retval EFI_SUCCESS All CPU interrupt/exception entries have been successfully initialized\r
e41aad15
JF
88 with default interrupt/exception handlers.\r
89 @retval EFI_INVALID_PARAMETER VectorInfo includes the invalid content if VectorInfo is not NULL.\r
90 @retval EFI_UNSUPPORTED This function is not supported.\r
91\r
92**/\r
93EFI_STATUS\r
94EFIAPI\r
95InitializeCpuInterruptHandlers (\r
96 IN EFI_VECTOR_HANDOFF_INFO *VectorInfo OPTIONAL\r
97 )\r
98{\r
99 EFI_STATUS Status;\r
100 IA32_IDT_GATE_DESCRIPTOR *IdtTable;\r
101 IA32_DESCRIPTOR IdtDescriptor;\r
102 UINTN IdtEntryCount;\r
103 EXCEPTION_HANDLER_TEMPLATE_MAP TemplateMap;\r
104 UINTN Index;\r
105 UINTN InterruptEntry;\r
106 UINT8 *InterruptEntryCode;\r
9db15f81
JF
107 RESERVED_VECTORS_DATA *ReservedVectors;\r
108 EFI_CPU_INTERRUPT_HANDLER *ExternalInterruptHandler;\r
e41aad15 109\r
fceafda5
JW
110 Status = gBS->AllocatePool (\r
111 EfiBootServicesCode,\r
112 sizeof (RESERVED_VECTORS_DATA) * CPU_INTERRUPT_NUM,\r
113 (VOID **)&ReservedVectors\r
114 );\r
115 ASSERT (!EFI_ERROR (Status) && ReservedVectors != NULL);\r
9db15f81 116 SetMem ((VOID *) ReservedVectors, sizeof (RESERVED_VECTORS_DATA) * CPU_INTERRUPT_NUM, 0xff);\r
e41aad15 117 if (VectorInfo != NULL) {\r
9db15f81 118 Status = ReadAndVerifyVectorInfo (VectorInfo, ReservedVectors, CPU_INTERRUPT_NUM);\r
e41aad15 119 if (EFI_ERROR (Status)) {\r
9db15f81 120 FreePool (ReservedVectors);\r
e41aad15
JF
121 return EFI_INVALID_PARAMETER;\r
122 }\r
123 }\r
44ecbc28 124\r
9db15f81
JF
125 ExternalInterruptHandler = AllocateZeroPool (sizeof (EFI_CPU_INTERRUPT_HANDLER) * CPU_INTERRUPT_NUM);\r
126 ASSERT (ExternalInterruptHandler != NULL);\r
e41aad15
JF
127\r
128 //\r
129 // Read IDT descriptor and calculate IDT size\r
130 //\r
131 AsmReadIdtr (&IdtDescriptor);\r
132 IdtEntryCount = (IdtDescriptor.Limit + 1) / sizeof (IA32_IDT_GATE_DESCRIPTOR);\r
133 if (IdtEntryCount > CPU_INTERRUPT_NUM) {\r
134 IdtEntryCount = CPU_INTERRUPT_NUM;\r
135 }\r
136 //\r
137 // Create Interrupt Descriptor Table and Copy the old IDT table in\r
138 //\r
139 IdtTable = AllocateZeroPool (sizeof (IA32_IDT_GATE_DESCRIPTOR) * CPU_INTERRUPT_NUM);\r
140 ASSERT (IdtTable != NULL);\r
141 CopyMem (IdtTable, (VOID *)IdtDescriptor.Base, sizeof (IA32_IDT_GATE_DESCRIPTOR) * IdtEntryCount);\r
142\r
143 AsmGetTemplateAddressMap (&TemplateMap);\r
144 ASSERT (TemplateMap.ExceptionStubHeaderSize <= HOOKAFTER_STUB_SIZE);\r
fceafda5
JW
145\r
146 Status = gBS->AllocatePool (\r
147 EfiBootServicesCode,\r
148 TemplateMap.ExceptionStubHeaderSize * CPU_INTERRUPT_NUM,\r
149 (VOID **)&InterruptEntryCode\r
150 );\r
151 ASSERT (!EFI_ERROR (Status) && InterruptEntryCode != NULL);\r
dd563742 152\r
e41aad15
JF
153 InterruptEntry = (UINTN) InterruptEntryCode;\r
154 for (Index = 0; Index < CPU_INTERRUPT_NUM; Index ++) {\r
155 CopyMem (\r
156 (VOID *) InterruptEntry,\r
157 (VOID *) TemplateMap.ExceptionStart,\r
158 TemplateMap.ExceptionStubHeaderSize\r
159 );\r
07da1ac8 160 AsmVectorNumFixup ((VOID *) InterruptEntry, (UINT8) Index, (VOID *) TemplateMap.ExceptionStart);\r
e41aad15
JF
161 InterruptEntry += TemplateMap.ExceptionStubHeaderSize;\r
162 }\r
163\r
164 TemplateMap.ExceptionStart = (UINTN) InterruptEntryCode;\r
9db15f81
JF
165 mExceptionHandlerData.IdtEntryCount = CPU_INTERRUPT_NUM;\r
166 mExceptionHandlerData.ReservedVectors = ReservedVectors;\r
167 mExceptionHandlerData.ExternalInterruptHandler = ExternalInterruptHandler;\r
168 InitializeSpinLock (&mExceptionHandlerData.DisplayMessageSpinLock);\r
169\r
170 UpdateIdtTable (IdtTable, &TemplateMap, &mExceptionHandlerData);\r
e41aad15
JF
171\r
172 //\r
173 // Load Interrupt Descriptor Table\r
174 //\r
175 IdtDescriptor.Base = (UINTN) IdtTable;\r
176 IdtDescriptor.Limit = (UINT16) (sizeof (IA32_IDT_GATE_DESCRIPTOR) * CPU_INTERRUPT_NUM - 1);\r
177 AsmWriteIdtr ((IA32_DESCRIPTOR *) &IdtDescriptor);\r
178\r
179 return EFI_SUCCESS;\r
180}\r
181\r
182/**\r
183 Registers a function to be called from the processor interrupt handler.\r
184\r
dd563742
JF
185 This function registers and enables the handler specified by InterruptHandler for a processor\r
186 interrupt or exception type specified by InterruptType. If InterruptHandler is NULL, then the\r
187 handler for the processor interrupt or exception type specified by InterruptType is uninstalled.\r
e41aad15
JF
188 The installed handler is called once for each processor interrupt or exception.\r
189 NOTE: This function should be invoked after InitializeCpuExceptionHandlers() or\r
190 InitializeCpuInterruptHandlers() invoked, otherwise EFI_UNSUPPORTED returned.\r
191\r
192 @param[in] InterruptType Defines which interrupt or exception to hook.\r
193 @param[in] InterruptHandler A pointer to a function of type EFI_CPU_INTERRUPT_HANDLER that is called\r
194 when a processor interrupt occurs. If this parameter is NULL, then the handler\r
195 will be uninstalled.\r
196\r
197 @retval EFI_SUCCESS The handler for the processor interrupt was successfully installed or uninstalled.\r
198 @retval EFI_ALREADY_STARTED InterruptHandler is not NULL, and a handler for InterruptType was\r
199 previously installed.\r
200 @retval EFI_INVALID_PARAMETER InterruptHandler is NULL, and a handler for InterruptType was not\r
201 previously installed.\r
202 @retval EFI_UNSUPPORTED The interrupt specified by InterruptType is not supported,\r
203 or this function is not supported.\r
3f25e6ea 204**/\r
e41aad15
JF
205EFI_STATUS\r
206EFIAPI\r
207RegisterCpuInterruptHandler (\r
208 IN EFI_EXCEPTION_TYPE InterruptType,\r
209 IN EFI_CPU_INTERRUPT_HANDLER InterruptHandler\r
210 )\r
211{\r
670f13af 212 return RegisterCpuInterruptHandlerWorker (InterruptType, InterruptHandler, &mExceptionHandlerData);\r
e41aad15 213}\r
0ff5aa9c
JW
214\r
215/**\r
216 Initializes CPU exceptions entries and setup stack switch for given exceptions.\r
217\r
218 This method will call InitializeCpuExceptionHandlers() to setup default\r
219 exception handlers unless indicated not to do it explicitly.\r
220\r
221 If InitData is passed with NULL, this method will use the resource reserved\r
222 by global variables to initialize it; Otherwise it will use data in InitData\r
223 to setup stack switch. This is for the different use cases in DxeCore and\r
224 Cpu MP exception initialization.\r
225\r
226 @param[in] VectorInfo Pointer to reserved vector list.\r
227 @param[in] InitData Pointer to data required to setup stack switch for\r
228 given exceptions.\r
229\r
230 @retval EFI_SUCCESS The exceptions have been successfully\r
231 initialized.\r
232 @retval EFI_INVALID_PARAMETER VectorInfo or InitData contains invalid\r
233 content.\r
234\r
235**/\r
236EFI_STATUS\r
237EFIAPI\r
238InitializeCpuExceptionHandlersEx (\r
239 IN EFI_VECTOR_HANDOFF_INFO *VectorInfo OPTIONAL,\r
240 IN CPU_EXCEPTION_INIT_DATA *InitData OPTIONAL\r
241 )\r
242{\r
243 EFI_STATUS Status;\r
244 CPU_EXCEPTION_INIT_DATA EssData;\r
245 IA32_DESCRIPTOR Idtr;\r
246 IA32_DESCRIPTOR Gdtr;\r
247\r
248 //\r
249 // To avoid repeat initialization of default handlers, the caller should pass\r
250 // an extended init data with InitDefaultHandlers set to FALSE. There's no\r
251 // need to call this method to just initialize default handlers. Call non-ex\r
252 // version instead; or this method must be implemented as a simple wrapper of\r
253 // non-ex version of it, if this version has to be called.\r
254 //\r
255 if (InitData == NULL || InitData->X64.InitDefaultHandlers) {\r
256 Status = InitializeCpuExceptionHandlers (VectorInfo);\r
257 } else {\r
258 Status = EFI_SUCCESS;\r
259 }\r
260\r
261 if (!EFI_ERROR (Status)) {\r
262 //\r
263 // Initializing stack switch is only necessary for Stack Guard functionality.\r
264 //\r
265 if (PcdGetBool (PcdCpuStackGuard)) {\r
266 if (InitData == NULL) {\r
267 SetMem (mNewGdt, sizeof (mNewGdt), 0);\r
268\r
269 AsmReadIdtr (&Idtr);\r
270 AsmReadGdtr (&Gdtr);\r
271\r
272 EssData.X64.Revision = CPU_EXCEPTION_INIT_DATA_REV;\r
d429d00f 273 EssData.X64.KnownGoodStackTop = (UINTN)mNewStack + sizeof (mNewStack);\r
0ff5aa9c
JW
274 EssData.X64.KnownGoodStackSize = CPU_KNOWN_GOOD_STACK_SIZE;\r
275 EssData.X64.StackSwitchExceptions = CPU_STACK_SWITCH_EXCEPTION_LIST;\r
276 EssData.X64.StackSwitchExceptionNumber = CPU_STACK_SWITCH_EXCEPTION_NUMBER;\r
277 EssData.X64.IdtTable = (VOID *)Idtr.Base;\r
278 EssData.X64.IdtTableSize = Idtr.Limit + 1;\r
279 EssData.X64.GdtTable = mNewGdt;\r
280 EssData.X64.GdtTableSize = sizeof (mNewGdt);\r
281 EssData.X64.ExceptionTssDesc = mNewGdt + Gdtr.Limit + 1;\r
282 EssData.X64.ExceptionTssDescSize = CPU_TSS_DESC_SIZE;\r
283 EssData.X64.ExceptionTss = mNewGdt + Gdtr.Limit + 1 + CPU_TSS_DESC_SIZE;\r
284 EssData.X64.ExceptionTssSize = CPU_TSS_SIZE;\r
285\r
286 InitData = &EssData;\r
287 }\r
288 Status = ArchSetupExcpetionStack (InitData);\r
289 }\r
290 }\r
291\r
292 return Status;\r
293}\r