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