]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Universal/DebugSupportDxe/Ipf/PlDebugSupport.c
Clean up to fix build break.
[mirror_edk2.git] / MdeModulePkg / Universal / DebugSupportDxe / Ipf / PlDebugSupport.c
CommitLineData
9e604fe4 1/** @file\r
c1f23d63 2 IPF specific debug support functions\r
3\r
19b15d63 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
15//\r
16// private header files\r
17//\r
e9f9d09a 18#include "PlDebugSupport.h"\r
c1f23d63 19\r
19b15d63 20BOOLEAN mInHandler = FALSE;\r
21\r
c1f23d63 22typedef struct {\r
23 UINT64 low;\r
24 UINT64 high;\r
25} BUNDLE;\r
26\r
27//\r
28// number of bundles to swap in ivt\r
29//\r
30#define NUM_BUNDLES_IN_STUB 5\r
31#define NUM_IVT_ENTRIES 64\r
32\r
33typedef struct {\r
34 BUNDLE OrigBundles[NUM_BUNDLES_IN_STUB];\r
35 VOID (*RegisteredCallback) ();\r
36} IVT_ENTRY;\r
37\r
9e604fe4 38/**\r
39 This is the worker function that uninstalls and removes all handlers.\r
40\r
41 @param ExceptionType Exception Type\r
42 @param NewBundles New Boundles\r
43 @param NewCallback New Callback\r
44\r
45 @retval EFI_ALEADY_STARTED Ivt already hooked.\r
46 @retval others Indicates the request was not satisfied.\r
47 @retval EFI_SUCCESS Successfully uninstalled.\r
48\r
49**/\r
c1f23d63 50EFI_STATUS\r
51ManageIvtEntryTable (\r
9e604fe4 52 IN EFI_EXCEPTION_TYPE ExceptionType,\r
c1f23d63 53 IN BUNDLE NewBundles[4],\r
54 IN VOID (*NewCallback) ()\r
55 );\r
56\r
9e604fe4 57/**\r
58 Saves original IVT contents and inserts a few new bundles which are fixed up\r
59 to store the ExceptionType and then call the common handler.\r
60\r
61 @param ExceptionType Exception Type\r
62 @param NewBundles New Boundles\r
63 @param NewCallback New Callback\r
64\r
65**/\r
c1f23d63 66VOID\r
67HookEntry (\r
9e604fe4 68 IN EFI_EXCEPTION_TYPE ExceptionType,\r
c1f23d63 69 IN BUNDLE NewBundles[4],\r
70 IN VOID (*NewCallback) ()\r
71 );\r
72\r
9e604fe4 73/**\r
74 Restores original IVT contents when unregistering a callback function.\r
75\r
76 @param ExceptionType Exception Type\r
77\r
78**/\r
c1f23d63 79VOID\r
80UnhookEntry (\r
81 IN EFI_EXCEPTION_TYPE ExceptionType\r
82 );\r
83\r
9e604fe4 84/**\r
85 Sets up cache flush and calls assembly function to chain external interrupt.\r
86\r
87 Records new callback in IvtEntryTable.\r
88\r
89 @param NewCallback New Callback.\r
90\r
91**/\r
c1f23d63 92VOID\r
93ChainExternalInterrupt (\r
94 IN VOID (*NewCallback) ()\r
95 );\r
96\r
9e604fe4 97/**\r
98 Sets up cache flush and calls assembly function to restore external interrupt.\r
99 Removes registered callback from IvtEntryTable.\r
100\r
101**/\r
c1f23d63 102VOID\r
103UnchainExternalInterrupt (\r
104 VOID\r
105 );\r
106\r
9e604fe4 107/**\r
108 Given an integer number, return the physical address of the entry point in the IFT.\r
109\r
110 @param HandlerIndex Index of the Handler \r
111 @param EntryPoint IFT Entrypoint\r
112\r
113**/\r
c1f23d63 114VOID\r
115GetHandlerEntryPoint (\r
116 UINTN HandlerIndex,\r
117 VOID **EntryPoint\r
118 );\r
119\r
120IVT_ENTRY IvtEntryTable[NUM_IVT_ENTRIES];\r
121\r
122//\r
123// IPF context record is overallocated by 512 bytes to guarantee a 512 byte alignment exists\r
124// within the buffer and still have a large enough buffer to hold a whole IPF context record.\r
125//\r
126UINT8 IpfContextBuf[sizeof (EFI_SYSTEM_CONTEXT_IPF) + 512];\r
127\r
128//\r
129// The PatchSaveBuffer is used to store the original bundles from the IVT where it is patched\r
130// with the common handler.\r
131//\r
132UINT8 PatchSaveBuffer[0x400];\r
133UINTN ExternalInterruptCount;\r
134\r
9e604fe4 135/**\r
136 IPF specific DebugSupport driver initialization. \r
c1f23d63 137\r
9e604fe4 138 Must be public because it's referenced from DebugSupport.c\r
c1f23d63 139\r
9e604fe4 140 @retval EFI_SUCCESS Always.\r
c1f23d63 141\r
9e604fe4 142**/\r
143EFI_STATUS\r
144PlInitializeDebugSupportDriver (\r
145 VOID\r
146 )\r
c1f23d63 147{\r
519f076a 148 ZeroMem (IvtEntryTable, sizeof (IvtEntryTable));\r
c1f23d63 149 ExternalInterruptCount = 0;\r
150 return EFI_SUCCESS;\r
151}\r
152\r
9e604fe4 153/**\r
c1f23d63 154 Unload handler that is called during UnloadImage() - deallocates pool memory\r
155 used by the driver. Must be public because it's referenced from DebugSuport.c\r
156\r
9e604fe4 157 @param ImageHandle The firmware allocated handle for the EFI image.\r
c1f23d63 158\r
9e604fe4 159 @retval EFI_SUCCESS Always.\r
c1f23d63 160\r
9e604fe4 161**/\r
162EFI_STATUS\r
163EFIAPI\r
164PlUnloadDebugSupportDriver (\r
165 IN EFI_HANDLE ImageHandle\r
166 )\r
c1f23d63 167{\r
168 EFI_EXCEPTION_TYPE ExceptionType;\r
169\r
170 for (ExceptionType = 0; ExceptionType < NUM_IVT_ENTRIES; ExceptionType++) {\r
171 ManageIvtEntryTable (ExceptionType, NULL, NULL);\r
172 }\r
173\r
174 return EFI_SUCCESS;\r
175}\r
176\r
9e604fe4 177/**\r
178 C routine that is called for all registered exceptions. This is the main\r
179 exception dispatcher. Must be public because it's referenced from AsmFuncs.s.\r
180\r
181 @param ExceptionType Exception Type\r
182 @param Context System Context\r
183**/\r
c1f23d63 184VOID\r
185CommonHandler (\r
186 IN EFI_EXCEPTION_TYPE ExceptionType,\r
187 IN EFI_SYSTEM_CONTEXT Context\r
188 )\r
c1f23d63 189{\r
c1f23d63 190 DEBUG_CODE_BEGIN ();\r
19b15d63 191 if (mInHandler) {\r
c1f23d63 192 DEBUG ((EFI_D_INFO, "ERROR: Re-entered debugger!\n"\r
193 " ExceptionType == %X\n"\r
194 " Context == %X\n"\r
195 " Context.SystemContextIpf->CrIip == %X\n"\r
196 " Context.SystemContextIpf->CrIpsr == %X\n"\r
19b15d63 197 " mInHandler == %X\n",\r
c1f23d63 198 ExceptionType, \r
199 Context, \r
200 Context.SystemContextIpf->CrIip,\r
201 Context.SystemContextIpf->CrIpsr,\r
19b15d63 202 mInHandler));\r
c1f23d63 203 }\r
204 DEBUG_CODE_END ();\r
205\r
19b15d63 206 ASSERT (!mInHandler);\r
207 mInHandler = TRUE;\r
c1f23d63 208 if (IvtEntryTable[ExceptionType].RegisteredCallback != NULL) {\r
209 if (ExceptionType != EXCEPT_IPF_EXTERNAL_INTERRUPT) {\r
210 IvtEntryTable[ExceptionType].RegisteredCallback (ExceptionType, Context.SystemContextIpf);\r
211 } else {\r
212 IvtEntryTable[ExceptionType].RegisteredCallback (Context.SystemContextIpf);\r
213 }\r
214 } else {\r
215 ASSERT (0);\r
216 }\r
217\r
19b15d63 218 mInHandler = FALSE;\r
c1f23d63 219}\r
220\r
9e604fe4 221/**\r
222 Given an integer number, return the physical address of the entry point in the IFT.\r
223\r
224 @param HandlerIndex Index of the Handler \r
225 @param EntryPoint IFT Entrypoint\r
226\r
227**/\r
c1f23d63 228VOID\r
229GetHandlerEntryPoint (\r
230 UINTN HandlerIndex,\r
231 VOID **EntryPoint\r
232 )\r
c1f23d63 233{\r
234 UINT8 *TempPtr;\r
235\r
236 //\r
237 // get base address of IVT\r
238 //\r
239 TempPtr = GetIva ();\r
240\r
241 if (HandlerIndex < 20) {\r
242 //\r
243 // first 20 provide 64 bundles per vector\r
244 //\r
245 TempPtr += 0x400 * HandlerIndex;\r
246 } else {\r
247 //\r
248 // the rest provide 16 bundles per vector\r
249 //\r
250 TempPtr += 0x5000 + 0x100 * (HandlerIndex - 20);\r
251 }\r
252\r
253 *EntryPoint = (VOID *) TempPtr;\r
254}\r
255\r
9e604fe4 256/**\r
257 This is the worker function that uninstalls and removes all handlers.\r
258\r
259 @param ExceptionType Exception Type\r
260 @param NewBundles New Boundles\r
261 @param NewCallback New Callback\r
262\r
263 @retval EFI_ALEADY_STARTED Ivt already hooked.\r
264 @retval others Indicates the request was not satisfied.\r
265 @retval EFI_SUCCESS Successfully uninstalled.\r
266\r
267**/\r
c1f23d63 268EFI_STATUS\r
269ManageIvtEntryTable (\r
9e604fe4 270 IN EFI_EXCEPTION_TYPE ExceptionType,\r
c1f23d63 271 IN BUNDLE NewBundles[NUM_BUNDLES_IN_STUB],\r
272 IN VOID (*NewCallback) ()\r
273 )\r
c1f23d63 274{\r
275 BUNDLE *B0Ptr;\r
276 UINT64 InterruptFlags;\r
277 EFI_TPL OldTpl;\r
278\r
279 //\r
280 // Get address of bundle 0\r
281 //\r
282 GetHandlerEntryPoint (ExceptionType, (VOID **) &B0Ptr);\r
283\r
284 if (IvtEntryTable[ExceptionType].RegisteredCallback != NULL) {\r
285 //\r
286 // we've already installed to this vector\r
287 //\r
288 if (NewCallback != NULL) {\r
289 //\r
290 // if the input handler is non-null, error\r
291 //\r
292 return EFI_ALREADY_STARTED;\r
293 } else {\r
294 //\r
295 // else remove the previously installed handler\r
296 //\r
297 OldTpl = gBS->RaiseTPL (TPL_HIGH_LEVEL);\r
298 InterruptFlags = ProgramInterruptFlags (DISABLE_INTERRUPTS);\r
299 if (ExceptionType == EXCEPT_IPF_EXTERNAL_INTERRUPT) {\r
300 UnchainExternalInterrupt ();\r
301 } else {\r
302 UnhookEntry (ExceptionType);\r
303 }\r
304\r
305 ProgramInterruptFlags (InterruptFlags);\r
306 gBS->RestoreTPL (OldTpl);\r
307 //\r
308 // re-init IvtEntryTable\r
309 //\r
519f076a 310 ZeroMem (&IvtEntryTable[ExceptionType], sizeof (IVT_ENTRY));\r
c1f23d63 311 }\r
312 } else {\r
313 //\r
314 // no user handler installed on this vector\r
315 //\r
316 if (NewCallback != NULL) {\r
317 OldTpl = gBS->RaiseTPL (TPL_HIGH_LEVEL);\r
318 InterruptFlags = ProgramInterruptFlags (DISABLE_INTERRUPTS);\r
319 if (ExceptionType == EXCEPT_IPF_EXTERNAL_INTERRUPT) {\r
320 ChainExternalInterrupt (NewCallback);\r
321 } else {\r
322 HookEntry (ExceptionType, NewBundles, NewCallback);\r
323 }\r
324\r
325 ProgramInterruptFlags (InterruptFlags);\r
326 gBS->RestoreTPL (OldTpl);\r
327 }\r
328 }\r
329\r
330 return EFI_SUCCESS;\r
331}\r
332\r
9e604fe4 333/**\r
334 Saves original IVT contents and inserts a few new bundles which are fixed up\r
335 to store the ExceptionType and then call the common handler.\r
336\r
337 @param ExceptionType Exception Type\r
338 @param NewBundles New Boundles\r
339 @param NewCallback New Callback\r
340\r
341**/\r
c1f23d63 342VOID\r
343HookEntry (\r
344 IN EFI_EXCEPTION_TYPE ExceptionType,\r
345 IN BUNDLE NewBundles[4],\r
346 IN VOID (*NewCallback) ()\r
347 )\r
c1f23d63 348{\r
349 BUNDLE *FixupBundle;\r
350 BUNDLE *B0Ptr;\r
351\r
352 //\r
353 // Get address of bundle 0\r
354 //\r
355 GetHandlerEntryPoint (ExceptionType, (VOID **) &B0Ptr);\r
356\r
357 //\r
358 // copy original bundles from IVT to IvtEntryTable so we can restore them later\r
359 //\r
360 CopyMem (\r
361 IvtEntryTable[ExceptionType].OrigBundles,\r
362 B0Ptr,\r
363 sizeof (BUNDLE) * NUM_BUNDLES_IN_STUB\r
364 );\r
365 //\r
366 // insert new B0\r
367 //\r
368 CopyMem (B0Ptr, NewBundles, sizeof (BUNDLE) * NUM_BUNDLES_IN_STUB);\r
369\r
370 //\r
371 // fixup IVT entry so it stores its index and whether or not to chain...\r
372 //\r
373 FixupBundle = B0Ptr + 2;\r
374 FixupBundle->high |= ExceptionType << 36;\r
375\r
376 InstructionCacheFlush (B0Ptr, 5);\r
377 IvtEntryTable[ExceptionType].RegisteredCallback = NewCallback;\r
378}\r
379\r
9e604fe4 380/**\r
381 Restores original IVT contents when unregistering a callback function.\r
382\r
383 @param ExceptionType Exception Type\r
384\r
385**/\r
c1f23d63 386VOID\r
387UnhookEntry (\r
388 IN EFI_EXCEPTION_TYPE ExceptionType\r
389 )\r
c1f23d63 390{\r
391 BUNDLE *B0Ptr;\r
392\r
393 //\r
394 // Get address of bundle 0\r
395 //\r
396 GetHandlerEntryPoint (ExceptionType, (VOID **) &B0Ptr);\r
397 //\r
398 // restore original bundles in IVT\r
399 //\r
400 CopyMem (\r
401 B0Ptr,\r
402 IvtEntryTable[ExceptionType].OrigBundles,\r
403 sizeof (BUNDLE) * NUM_BUNDLES_IN_STUB\r
404 );\r
405 InstructionCacheFlush (B0Ptr, 5);\r
406}\r
407\r
9e604fe4 408/**\r
c1f23d63 409 Sets up cache flush and calls assembly function to chain external interrupt.\r
9e604fe4 410\r
c1f23d63 411 Records new callback in IvtEntryTable.\r
c1f23d63 412\r
9e604fe4 413 @param NewCallback New Callback\r
c1f23d63 414\r
9e604fe4 415**/\r
416VOID\r
417ChainExternalInterrupt (\r
418 IN VOID (*NewCallback) ()\r
419 )\r
c1f23d63 420{\r
421 VOID *Start;\r
422\r
423 Start = (VOID *) ((UINT8 *) GetIva () + 0x400 * EXCEPT_IPF_EXTERNAL_INTERRUPT + 0x400);\r
424 IvtEntryTable[EXCEPT_IPF_EXTERNAL_INTERRUPT].RegisteredCallback = NewCallback;\r
425 ChainHandler ();\r
426 InstructionCacheFlush (Start, 0x400);\r
427}\r
428\r
9e604fe4 429/**\r
430 Sets up cache flush and calls assembly function to restore external interrupt.\r
431 Removes registered callback from IvtEntryTable.\r
432\r
433**/\r
c1f23d63 434VOID\r
435UnchainExternalInterrupt (\r
436 VOID\r
437 )\r
c1f23d63 438{\r
439 VOID *Start;\r
440\r
441 Start = (VOID *) ((UINT8 *) GetIva () + 0x400 * EXCEPT_IPF_EXTERNAL_INTERRUPT + 0x400);\r
442 UnchainHandler ();\r
443 InstructionCacheFlush (Start, 0x400);\r
444 IvtEntryTable[EXCEPT_IPF_EXTERNAL_INTERRUPT].RegisteredCallback = NULL;\r
445}\r
446\r
447//\r
448// The rest of the functions in this file are all member functions for the\r
449// DebugSupport protocol\r
450//\r
451\r
9e604fe4 452/**\r
453 This is a DebugSupport protocol member function, hard\r
454 coded to support only 1 processor for now.\r
455\r
456 @param This The DebugSupport instance\r
457 @param MaxProcessorIndex The maximuim supported processor index\r
458\r
459 @retval EFI_SUCCESS Always returned with **MaxProcessorIndex set to 0.\r
460\r
461**/\r
c1f23d63 462EFI_STATUS\r
463EFIAPI\r
464GetMaximumProcessorIndex (\r
465 IN EFI_DEBUG_SUPPORT_PROTOCOL *This,\r
466 OUT UINTN *MaxProcessorIndex\r
467 )\r
c1f23d63 468{\r
469 *MaxProcessorIndex = 0;\r
470 return (EFI_SUCCESS);\r
471}\r
472\r
9e604fe4 473/**\r
474 DebugSupport protocol member function.\r
475\r
476 @param This The DebugSupport instance\r
477 @param ProcessorIndex Which processor the callback applies to.\r
478 @param PeriodicCallback Callback function\r
479\r
480 @retval EFI_SUCCESS Indicates the callback was registered.\r
481 @retval others Callback was not registered.\r
482\r
483**/\r
c1f23d63 484EFI_STATUS\r
485EFIAPI\r
486RegisterPeriodicCallback (\r
487 IN EFI_DEBUG_SUPPORT_PROTOCOL *This,\r
488 IN UINTN ProcessorIndex,\r
9e604fe4 489 IN EFI_PERIODIC_CALLBACK PeriodicCallback\r
c1f23d63 490 )\r
9e604fe4 491{\r
492 return ManageIvtEntryTable (EXCEPT_IPF_EXTERNAL_INTERRUPT, NULL, PeriodicCallback);\r
493}\r
c1f23d63 494\r
9e604fe4 495/**\r
496 DebugSupport protocol member function.\r
c1f23d63 497\r
9e604fe4 498 @param This The DebugSupport instance\r
499 @param ProcessorIndex Which processor the callback applies to.\r
500 @param NewCallback Callback function\r
501 @param ExceptionType Which exception to hook\r
c1f23d63 502\r
9e604fe4 503 @retval EFI_SUCCESS Indicates the callback was registered.\r
504 @retval others Callback was not registered.\r
c1f23d63 505\r
9e604fe4 506**/\r
c1f23d63 507EFI_STATUS\r
508EFIAPI\r
509RegisterExceptionCallback (\r
510 IN EFI_DEBUG_SUPPORT_PROTOCOL *This,\r
511 IN UINTN ProcessorIndex,\r
512 IN EFI_EXCEPTION_CALLBACK NewCallback,\r
513 IN EFI_EXCEPTION_TYPE ExceptionType\r
514 )\r
c1f23d63 515{\r
516 return ManageIvtEntryTable (\r
517 ExceptionType,\r
518 (BUNDLE *) ((EFI_PLABEL *) HookStub)->EntryPoint,\r
519 NewCallback\r
520 );\r
521}\r
522\r
9e604fe4 523/**\r
524 DebugSupport protocol member function. Calls assembly routine to flush cache.\r
525\r
526 @param This The DebugSupport instance\r
527 @param ProcessorIndex Which processor the callback applies to.\r
528 @param Start Physical base of the memory range to be invalidated\r
529 @param Length mininum number of bytes in instruction cache to invalidate\r
530\r
531 @retval EFI_SUCCESS Always returned.\r
532\r
533**/\r
c1f23d63 534EFI_STATUS\r
535EFIAPI\r
536InvalidateInstructionCache (\r
537 IN EFI_DEBUG_SUPPORT_PROTOCOL *This,\r
538 IN UINTN ProcessorIndex,\r
539 IN VOID *Start,\r
540 IN UINTN Length\r
541 )\r
c1f23d63 542{\r
543 InstructionCacheFlush (Start, Length);\r
9e604fe4 544 return EFI_SUCCESS;\r
c1f23d63 545}\r