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