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