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