]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Universal/DebugSupportDxe/Ipf/plDebugSupport.c
Patch to remove STATIC modifier. This is on longer recommended by EFI Framework codin...
[mirror_edk2.git] / MdeModulePkg / Universal / DebugSupportDxe / Ipf / plDebugSupport.c
CommitLineData
c1f23d63 1/**@file\r
2 IPF specific debug support functions\r
3\r
4Copyright (c) 2006, Intel Corporation \r
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
18#include "plDebugSupport.h"\r
19\r
20typedef 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
31typedef struct {\r
32 BUNDLE OrigBundles[NUM_BUNDLES_IN_STUB];\r
33 VOID (*RegisteredCallback) ();\r
34} IVT_ENTRY;\r
35\r
c1f23d63 36EFI_STATUS\r
37ManageIvtEntryTable (\r
38 IN EFI_EXCEPTION_TYPE ExceptionType,\r
39 IN BUNDLE NewBundles[4],\r
40 IN VOID (*NewCallback) ()\r
41 );\r
42\r
c1f23d63 43VOID\r
44HookEntry (\r
45 IN EFI_EXCEPTION_TYPE ExceptionType,\r
46 IN BUNDLE NewBundles[4],\r
47 IN VOID (*NewCallback) ()\r
48 );\r
49\r
c1f23d63 50VOID\r
51UnhookEntry (\r
52 IN EFI_EXCEPTION_TYPE ExceptionType\r
53 );\r
54\r
c1f23d63 55VOID\r
56ChainExternalInterrupt (\r
57 IN VOID (*NewCallback) ()\r
58 );\r
59\r
c1f23d63 60VOID\r
61UnchainExternalInterrupt (\r
62 VOID\r
63 );\r
64\r
c1f23d63 65VOID\r
66GetHandlerEntryPoint (\r
67 UINTN HandlerIndex,\r
68 VOID **EntryPoint\r
69 );\r
70\r
71IVT_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
77UINT8 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
83UINT8 PatchSaveBuffer[0x400];\r
84UINTN ExternalInterruptCount;\r
85\r
86EFI_STATUS\r
87plInitializeDebugSupportDriver (\r
88 VOID\r
89 )\r
90/*++\r
91\r
92Routine Description:\r
93 IPF specific DebugSupport driver initialization. Must be public because it's\r
94 referenced from DebugSupport.c\r
95\r
96Arguments:\r
97\r
98Returns:\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
109EFI_STATUS\r
110EFIAPI\r
111plUnloadDebugSupportDriver (\r
112 IN EFI_HANDLE ImageHandle\r
113 )\r
114/*++\r
115\r
116Routine 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
120Arguments:\r
121 ImageHandle - Image handle\r
122\r
123Returns:\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
138VOID\r
139CommonHandler (\r
140 IN EFI_EXCEPTION_TYPE ExceptionType,\r
141 IN EFI_SYSTEM_CONTEXT Context\r
142 )\r
143/*++\r
144\r
145Routine 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
149Arguments:\r
150 ExceptionType - Exception Type\r
151 Context - System Context\r
152\r
153Returns:\r
154\r
155 Nothing\r
156 \r
157--*/\r
158{\r
fe1e36e5 159 STATIC BOOLEAN InHandler = FALSE;\r
c1f23d63 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
c1f23d63 192VOID\r
193GetHandlerEntryPoint (\r
194 UINTN HandlerIndex,\r
195 VOID **EntryPoint\r
196 )\r
197/*++\r
198\r
199Routine Description:\r
200 Given an integer number, return the physical address of the entry point in the IFT\r
201 \r
202Arguments:\r
203 HandlerIndex - Index of the Handler \r
204 EntryPoint - IFT Entrypoint\r
205\r
206Returns:\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
c1f23d63 234EFI_STATUS\r
235ManageIvtEntryTable (\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
242Routine Description:\r
243 This is the worker function that installs and removes all handlers\r
244 \r
245Arguments:\r
246 ExceptionType - Exception Type\r
247 NewBundles - New Boundles\r
248 NewCallback - New Callback\r
249\r
250Returns:\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
c1f23d63 316VOID\r
317HookEntry (\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
324Routine 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
328Arguments:\r
329 ExceptionType - Exception Type\r
330 NewBundles - New Boundles\r
331 NewCallback - New Callback\r
332\r
333Returns:\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
c1f23d63 370VOID\r
371UnhookEntry (\r
372 IN EFI_EXCEPTION_TYPE ExceptionType\r
373 )\r
374/*++\r
375\r
376Routine Description:\r
377 Restores original IVT contents when unregistering a callback function\r
378 \r
379Arguments:\r
380 ExceptionType - Exception Type\r
381 NewBundles - New Boundles\r
382 NewCallback - New Callback\r
383\r
384Returns:\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
c1f23d63 407VOID\r
408ChainExternalInterrupt (\r
409 IN VOID (*NewCallback) ()\r
410 )\r
411/*++\r
412\r
413Routine 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
417Arguments:\r
418 NewCallback - New Callback\r
419\r
420Returns:\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
c1f23d63 434VOID\r
435UnchainExternalInterrupt (\r
436 VOID\r
437 )\r
438/*++\r
439\r
440Routine 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
444Arguments:\r
445 Nothing\r
446 \r
447Returns:\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
466EFI_STATUS\r
467EFIAPI\r
468GetMaximumProcessorIndex (\r
469 IN EFI_DEBUG_SUPPORT_PROTOCOL *This,\r
470 OUT UINTN *MaxProcessorIndex\r
471 )\r
472/*++\r
473\r
474Routine Description: This is a DebugSupport protocol member function. Hard\r
475 coded to support only 1 processor for now.\r
476\r
477Arguments:\r
478 This - The DebugSupport instance\r
479 MaxProcessorIndex - The maximuim supported processor index\r
480\r
481Returns:\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
490EFI_STATUS\r
491EFIAPI\r
492RegisterPeriodicCallback (\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
499Routine Description:\r
500 DebugSupport protocol member function\r
501\r
502Arguments:\r
503 This - The DebugSupport instance\r
504 ProcessorIndex - Which processor the callback applies to.\r
505 PeriodicCallback - Callback function\r
506\r
507Returns:\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
516EFI_STATUS\r
517EFIAPI\r
518RegisterExceptionCallback (\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
526Routine Description:\r
527 DebugSupport protocol member function\r
528\r
529Arguments:\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
535Returns:\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
548EFI_STATUS\r
549EFIAPI\r
550InvalidateInstructionCache (\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
558Routine Description:\r
559 DebugSupport protocol member function. Calls assembly routine to flush cache.\r
560\r
561Arguments:\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
567Returns:\r
568 EFI_SUCCESS\r
569\r
570--*/\r
571{\r
572 InstructionCacheFlush (Start, Length);\r
573 return (EFI_SUCCESS);\r
574}\r