]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Universal/DebugSupportDxe/Ia32/PlDebugSupport.c
UefiCpuPkg: Move AsmRelocateApLoopStart from Mpfuncs.nasm to AmdSev.nasm
[mirror_edk2.git] / MdeModulePkg / Universal / DebugSupportDxe / Ia32 / PlDebugSupport.c
CommitLineData
9e604fe4 1/** @file\r
509bc208 2 IA32/x64 generic functions to support Debug Support protocol.\r
c1f23d63 3\r
d1102dba 4Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>\r
9d510e61 5SPDX-License-Identifier: BSD-2-Clause-Patent\r
c1f23d63 6\r
7**/\r
8\r
6e8a984e 9#include "DebugSupport.h"\r
c1f23d63 10\r
11//\r
12// This the global main table to keep track of the interrupts\r
13//\r
1436aea4 14IDT_ENTRY *IdtEntryTable = NULL;\r
c1f23d63 15\r
9e604fe4 16/**\r
6e8a984e 17 Read IDT Gate Descriptor from IDT Table.\r
9e604fe4 18\r
6e8a984e 19 @param Vector Specifies vector number.\r
c84507ab 20 @param IdtGateDescriptor Pointer to IDT Gate Descriptor read from IDT Table.\r
9e604fe4 21\r
22**/\r
c84507ab 23VOID\r
24ReadIdtGateDescriptor (\r
6e8a984e 25 IN EFI_EXCEPTION_TYPE Vector,\r
c84507ab 26 OUT IA32_IDT_GATE_DESCRIPTOR *IdtGateDescriptor\r
c1f23d63 27 )\r
c1f23d63 28{\r
1436aea4
MK
29 IA32_DESCRIPTOR IdtrValue;\r
30 IA32_IDT_GATE_DESCRIPTOR *IdtTable;\r
c1f23d63 31\r
1436aea4
MK
32 AsmReadIdtr (&IdtrValue);\r
33 IdtTable = (IA32_IDT_GATE_DESCRIPTOR *)IdtrValue.Base;\r
c1f23d63 34\r
1436aea4 35 CopyMem ((VOID *)IdtGateDescriptor, (VOID *)&(IdtTable)[Vector], sizeof (IA32_IDT_GATE_DESCRIPTOR));\r
6e8a984e 36}\r
c84507ab 37\r
6e8a984e 38/**\r
39 Write IDT Gate Descriptor into IDT Table.\r
c1f23d63 40\r
6e8a984e 41 @param Vector Specifies vector number.\r
c84507ab 42 @param IdtGateDescriptor Pointer to IDT Gate Descriptor written into IDT Table.\r
c1f23d63 43\r
6e8a984e 44**/\r
c84507ab 45VOID\r
46WriteIdtGateDescriptor (\r
6e8a984e 47 EFI_EXCEPTION_TYPE Vector,\r
c84507ab 48 IA32_IDT_GATE_DESCRIPTOR *IdtGateDescriptor\r
6e8a984e 49 )\r
50{\r
1436aea4
MK
51 IA32_DESCRIPTOR IdtrValue;\r
52 IA32_IDT_GATE_DESCRIPTOR *IdtTable;\r
c1f23d63 53\r
1436aea4
MK
54 AsmReadIdtr (&IdtrValue);\r
55 IdtTable = (IA32_IDT_GATE_DESCRIPTOR *)IdtrValue.Base;\r
c1f23d63 56\r
1436aea4 57 CopyMem ((VOID *)&(IdtTable)[Vector], (VOID *)IdtGateDescriptor, sizeof (IA32_IDT_GATE_DESCRIPTOR));\r
c1f23d63 58}\r
59\r
9e604fe4 60/**\r
c1f23d63 61 Creates a nes entry stub. Then saves the current IDT entry and replaces it\r
62 with an interrupt gate for the new entry point. The IdtEntryTable is updated\r
63 with the new registered function.\r
64\r
65 This code executes in boot services context. The stub entry executes in interrupt\r
66 context.\r
67\r
9e604fe4 68 @param ExceptionType Specifies which vector to hook.\r
69 @param NewCallback A pointer to the new function to be registered.\r
c1f23d63 70\r
9e604fe4 71**/\r
c84507ab 72VOID\r
9e604fe4 73HookEntry (\r
1436aea4
MK
74 IN EFI_EXCEPTION_TYPE ExceptionType,\r
75 IN CALLBACK_FUNC NewCallback\r
9e604fe4 76 )\r
c1f23d63 77{\r
1436aea4 78 BOOLEAN OldIntFlagState;\r
c1f23d63 79\r
1436aea4 80 CreateEntryStub (ExceptionType, (VOID **)&IdtEntryTable[ExceptionType].StubEntry);\r
d1102dba 81\r
c84507ab 82 //\r
83 // Disables CPU interrupts and returns the previous interrupt state\r
84 //\r
85 OldIntFlagState = SaveAndDisableInterrupts ();\r
c1f23d63 86\r
509bc208 87 //\r
88 // gets IDT Gate descriptor by index\r
89 //\r
c84507ab 90 ReadIdtGateDescriptor (ExceptionType, &(IdtEntryTable[ExceptionType].OrigDesc));\r
509bc208 91 //\r
d1102dba 92 // stores orignal interrupt handle\r
509bc208 93 //\r
1436aea4 94 IdtEntryTable[ExceptionType].OrigVector = (DEBUG_PROC)GetInterruptHandleFromIdt (&(IdtEntryTable[ExceptionType].OrigDesc));\r
c1f23d63 95\r
d1102dba
LG
96 //\r
97 // encodes new IDT Gate descriptor by stub entry\r
509bc208 98 //\r
c84507ab 99 Vect2Desc (&IdtEntryTable[ExceptionType].NewDesc, IdtEntryTable[ExceptionType].StubEntry);\r
509bc208 100 //\r
101 // stores NewCallback\r
102 //\r
c84507ab 103 IdtEntryTable[ExceptionType].RegisteredCallback = NewCallback;\r
509bc208 104\r
105 //\r
106 // writes back new IDT Gate descriptor\r
107 //\r
c84507ab 108 WriteIdtGateDescriptor (ExceptionType, &(IdtEntryTable[ExceptionType].NewDesc));\r
109\r
110 //\r
111 // restore interrupt state\r
112 //\r
113 SetInterruptState (OldIntFlagState);\r
c1f23d63 114\r
1436aea4 115 return;\r
c1f23d63 116}\r
117\r
9e604fe4 118/**\r
c1f23d63 119 Undoes HookEntry. This code executes in boot services context.\r
120\r
9e604fe4 121 @param ExceptionType Specifies which entry to unhook\r
c1f23d63 122\r
9e604fe4 123**/\r
c84507ab 124VOID\r
9e604fe4 125UnhookEntry (\r
1436aea4 126 IN EFI_EXCEPTION_TYPE ExceptionType\r
9e604fe4 127 )\r
c1f23d63 128{\r
1436aea4 129 BOOLEAN OldIntFlagState;\r
c1f23d63 130\r
c84507ab 131 //\r
132 // Disables CPU interrupts and returns the previous interrupt state\r
133 //\r
134 OldIntFlagState = SaveAndDisableInterrupts ();\r
c1f23d63 135\r
c84507ab 136 //\r
137 // restore the default IDT Date Descriptor\r
138 //\r
139 WriteIdtGateDescriptor (ExceptionType, &(IdtEntryTable[ExceptionType].OrigDesc));\r
140\r
141 //\r
142 // restore interrupt state\r
143 //\r
144 SetInterruptState (OldIntFlagState);\r
145\r
1436aea4 146 return;\r
c1f23d63 147}\r
148\r
9e604fe4 149/**\r
c84507ab 150 Returns the maximum value that may be used for the ProcessorIndex parameter in\r
d1102dba
LG
151 RegisterPeriodicCallback() and RegisterExceptionCallback().\r
152\r
c84507ab 153 Hard coded to support only 1 processor for now.\r
9e604fe4 154\r
c84507ab 155 @param This A pointer to the EFI_DEBUG_SUPPORT_PROTOCOL instance.\r
156 @param MaxProcessorIndex Pointer to a caller-allocated UINTN in which the maximum supported\r
d1102dba
LG
157 processor index is returned. Always 0 returned.\r
158\r
c84507ab 159 @retval EFI_SUCCESS Always returned with **MaxProcessorIndex set to 0.\r
9e604fe4 160\r
161**/\r
c1f23d63 162EFI_STATUS\r
163EFIAPI\r
164GetMaximumProcessorIndex (\r
1436aea4
MK
165 IN EFI_DEBUG_SUPPORT_PROTOCOL *This,\r
166 OUT UINTN *MaxProcessorIndex\r
c1f23d63 167 )\r
c1f23d63 168{\r
169 *MaxProcessorIndex = 0;\r
c84507ab 170 return EFI_SUCCESS;\r
c1f23d63 171}\r
172\r
9e604fe4 173/**\r
c84507ab 174 Registers a function to be called back periodically in interrupt context.\r
d1102dba 175\r
c84507ab 176 @param This A pointer to the EFI_DEBUG_SUPPORT_PROTOCOL instance.\r
177 @param ProcessorIndex Specifies which processor the callback function applies to.\r
178 @param PeriodicCallback A pointer to a function of type PERIODIC_CALLBACK that is the main\r
179 periodic entry point of the debug agent.\r
d1102dba
LG
180\r
181 @retval EFI_SUCCESS The function completed successfully.\r
c84507ab 182 @retval EFI_ALREADY_STARTED Non-NULL PeriodicCallback parameter when a callback\r
d1102dba
LG
183 function was previously registered.\r
184 @retval EFI_OUT_OF_RESOURCES System has insufficient memory resources to register new callback\r
185 function.\r
9e604fe4 186**/\r
c1f23d63 187EFI_STATUS\r
188EFIAPI\r
189RegisterPeriodicCallback (\r
1436aea4
MK
190 IN EFI_DEBUG_SUPPORT_PROTOCOL *This,\r
191 IN UINTN ProcessorIndex,\r
192 IN EFI_PERIODIC_CALLBACK PeriodicCallback\r
c1f23d63 193 )\r
9e604fe4 194{\r
195 return ManageIdtEntryTable (PeriodicCallback, SYSTEM_TIMER_VECTOR);\r
196}\r
c1f23d63 197\r
9e604fe4 198/**\r
c84507ab 199 Registers a function to be called when a given processor exception occurs.\r
c1f23d63 200\r
9e604fe4 201 This code executes in boot services context.\r
d1102dba 202\r
c84507ab 203 @param This A pointer to the EFI_DEBUG_SUPPORT_PROTOCOL instance.\r
204 @param ProcessorIndex Specifies which processor the callback function applies to.\r
205 @param ExceptionCallback A pointer to a function of type EXCEPTION_CALLBACK that is called\r
d1102dba
LG
206 when the processor exception specified by ExceptionType occurs.\r
207 @param ExceptionType Specifies which processor exception to hook.\r
208\r
209 @retval EFI_SUCCESS The function completed successfully.\r
c84507ab 210 @retval EFI_ALREADY_STARTED Non-NULL PeriodicCallback parameter when a callback\r
d1102dba
LG
211 function was previously registered.\r
212 @retval EFI_OUT_OF_RESOURCES System has insufficient memory resources to register new callback\r
c84507ab 213 function.\r
9e604fe4 214**/\r
c1f23d63 215EFI_STATUS\r
216EFIAPI\r
217RegisterExceptionCallback (\r
1436aea4
MK
218 IN EFI_DEBUG_SUPPORT_PROTOCOL *This,\r
219 IN UINTN ProcessorIndex,\r
220 IN EFI_EXCEPTION_CALLBACK ExceptionCallback,\r
221 IN EFI_EXCEPTION_TYPE ExceptionType\r
c1f23d63 222 )\r
c1f23d63 223{\r
c84507ab 224 return ManageIdtEntryTable (ExceptionCallback, ExceptionType);\r
c1f23d63 225}\r
226\r
9e604fe4 227/**\r
c84507ab 228 Invalidates processor instruction cache for a memory range. Subsequent execution in this range\r
d1102dba
LG
229 causes a fresh memory fetch to retrieve code to be executed.\r
230\r
c84507ab 231 @param This A pointer to the EFI_DEBUG_SUPPORT_PROTOCOL instance.\r
232 @param ProcessorIndex Specifies which processor's instruction cache is to be invalidated.\r
d1102dba 233 @param Start Specifies the physical base of the memory range to be invalidated.\r
c84507ab 234 @param Length Specifies the minimum number of bytes in the processor's instruction\r
d1102dba
LG
235 cache to invalidate.\r
236\r
c84507ab 237 @retval EFI_SUCCESS Always returned.\r
9e604fe4 238\r
239**/\r
c1f23d63 240EFI_STATUS\r
241EFIAPI\r
242InvalidateInstructionCache (\r
1436aea4
MK
243 IN EFI_DEBUG_SUPPORT_PROTOCOL *This,\r
244 IN UINTN ProcessorIndex,\r
245 IN VOID *Start,\r
246 IN UINT64 Length\r
c1f23d63 247 )\r
c1f23d63 248{\r
249 AsmWbinvd ();\r
250 return EFI_SUCCESS;\r
251}\r
252\r
9e604fe4 253/**\r
c84507ab 254 Common piece of code that invokes the registered handlers.\r
9e604fe4 255\r
c84507ab 256 This code executes in exception context so no efi calls are allowed.\r
509bc208 257 This code is called from assembly file.\r
c84507ab 258\r
259 @param ExceptionType Exception type\r
260 @param ContextRecord System context\r
9e604fe4 261\r
262**/\r
c84507ab 263VOID\r
264InterruptDistrubutionHub (\r
1436aea4
MK
265 EFI_EXCEPTION_TYPE ExceptionType,\r
266 EFI_SYSTEM_CONTEXT_IA32 *ContextRecord\r
c1f23d63 267 )\r
c1f23d63 268{\r
c84507ab 269 if (IdtEntryTable[ExceptionType].RegisteredCallback != NULL) {\r
270 if (ExceptionType != SYSTEM_TIMER_VECTOR) {\r
271 IdtEntryTable[ExceptionType].RegisteredCallback (ExceptionType, ContextRecord);\r
272 } else {\r
273 OrigVector = IdtEntryTable[ExceptionType].OrigVector;\r
274 IdtEntryTable[ExceptionType].RegisteredCallback (ContextRecord);\r
c1f23d63 275 }\r
276 }\r
c1f23d63 277}\r
278\r
9e604fe4 279/**\r
c84507ab 280 This is the callback that is written to the Loaded Image protocol instance\r
c1f23d63 281 on the image handle. It uninstalls all registered handlers and frees all entry\r
282 stub memory.\r
283\r
9e604fe4 284 @param ImageHandle The firmware allocated handle for the EFI image.\r
c1f23d63 285\r
9e604fe4 286 @retval EFI_SUCCESS Always.\r
c1f23d63 287\r
9e604fe4 288**/\r
289EFI_STATUS\r
290EFIAPI\r
291PlUnloadDebugSupportDriver (\r
1436aea4 292 IN EFI_HANDLE ImageHandle\r
9e604fe4 293 )\r
c1f23d63 294{\r
295 EFI_EXCEPTION_TYPE ExceptionType;\r
296\r
297 for (ExceptionType = 0; ExceptionType < NUM_IDT_ENTRIES; ExceptionType++) {\r
298 ManageIdtEntryTable (NULL, ExceptionType);\r
c84507ab 299 //\r
300 // Free space for each Interrupt Stub precedure.\r
301 //\r
302 if (IdtEntryTable[ExceptionType].StubEntry != NULL) {\r
303 FreePool ((VOID *)(UINTN)IdtEntryTable[ExceptionType].StubEntry);\r
304 }\r
c1f23d63 305 }\r
306\r
307 FreePool (IdtEntryTable);\r
c84507ab 308\r
c1f23d63 309 return EFI_SUCCESS;\r
310}\r
311\r
9e604fe4 312/**\r
d1102dba
LG
313 Initializes driver's handler registration database.\r
314\r
c84507ab 315 This code executes in boot services context.\r
316 Must be public because it's referenced from DebugSupport.c\r
9e604fe4 317\r
c84507ab 318 @retval EFI_UNSUPPORTED If IA32/x64 processor does not support FXSTOR/FXRSTOR instructions,\r
319 the context save will fail, so these processors are not supported.\r
320 @retval EFI_OUT_OF_RESOURCES Fails to allocate memory.\r
321 @retval EFI_SUCCESS Initializes successfully.\r
9e604fe4 322\r
323**/\r
c84507ab 324EFI_STATUS\r
325PlInitializeDebugSupportDriver (\r
326 VOID\r
c1f23d63 327 )\r
c1f23d63 328{\r
c84507ab 329 EFI_EXCEPTION_TYPE ExceptionType;\r
330\r
331 //\r
332 // Check whether FxStor instructions are supported.\r
333 //\r
334 if (!FxStorSupport ()) {\r
335 return EFI_UNSUPPORTED;\r
336 }\r
337\r
338 IdtEntryTable = AllocateZeroPool (sizeof (IDT_ENTRY) * NUM_IDT_ENTRIES);\r
339 if (IdtEntryTable == NULL) {\r
340 return EFI_OUT_OF_RESOURCES;\r
341 }\r
342\r
1436aea4
MK
343 for (ExceptionType = 0; ExceptionType < NUM_IDT_ENTRIES; ExceptionType++) {\r
344 IdtEntryTable[ExceptionType].StubEntry = (DEBUG_PROC)(UINTN)AllocatePool (StubSize);\r
c84507ab 345 if (IdtEntryTable[ExceptionType].StubEntry == NULL) {\r
346 goto ErrorCleanup;\r
347 }\r
d1102dba 348\r
c84507ab 349 //\r
350 // Copy Interrupt stub code.\r
351 //\r
352 CopyMem ((VOID *)(UINTN)IdtEntryTable[ExceptionType].StubEntry, InterruptEntryStub, StubSize);\r
353 }\r
1436aea4 354\r
c84507ab 355 return EFI_SUCCESS;\r
356\r
357ErrorCleanup:\r
358\r
359 for (ExceptionType = 0; ExceptionType < NUM_IDT_ENTRIES; ExceptionType++) {\r
360 if (IdtEntryTable[ExceptionType].StubEntry != NULL) {\r
361 FreePool ((VOID *)(UINTN)IdtEntryTable[ExceptionType].StubEntry);\r
c1f23d63 362 }\r
363 }\r
1436aea4 364\r
c84507ab 365 FreePool (IdtEntryTable);\r
366\r
367 return EFI_OUT_OF_RESOURCES;\r
c1f23d63 368}\r