2 IPF specific debug support functions
4 Copyright (c) 2006, Intel Corporation
5 All rights reserved. This program and the accompanying materials
6 are licensed and made available under the terms and conditions of the BSD License
7 which accompanies this distribution. The full text of the license may be found at
8 http://opensource.org/licenses/bsd-license.php
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
16 // private header files
18 #include "plDebugSupport.h"
26 // number of bundles to swap in ivt
28 #define NUM_BUNDLES_IN_STUB 5
29 #define NUM_IVT_ENTRIES 64
32 BUNDLE OrigBundles
[NUM_BUNDLES_IN_STUB
];
33 VOID (*RegisteredCallback
) ();
38 IN EFI_EXCEPTION_TYPE ExceptionType
,
39 IN BUNDLE NewBundles
[4],
40 IN
VOID (*NewCallback
) ()
45 IN EFI_EXCEPTION_TYPE ExceptionType
,
46 IN BUNDLE NewBundles
[4],
47 IN
VOID (*NewCallback
) ()
52 IN EFI_EXCEPTION_TYPE ExceptionType
56 ChainExternalInterrupt (
57 IN
VOID (*NewCallback
) ()
61 UnchainExternalInterrupt (
66 GetHandlerEntryPoint (
71 IVT_ENTRY IvtEntryTable
[NUM_IVT_ENTRIES
];
74 // IPF context record is overallocated by 512 bytes to guarantee a 512 byte alignment exists
75 // within the buffer and still have a large enough buffer to hold a whole IPF context record.
77 UINT8 IpfContextBuf
[sizeof (EFI_SYSTEM_CONTEXT_IPF
) + 512];
80 // The PatchSaveBuffer is used to store the original bundles from the IVT where it is patched
81 // with the common handler.
83 UINT8 PatchSaveBuffer
[0x400];
84 UINTN ExternalInterruptCount
;
87 plInitializeDebugSupportDriver (
93 IPF specific DebugSupport driver initialization. Must be public because it's
94 referenced from DebugSupport.c
104 SetMem (IvtEntryTable
, sizeof (IvtEntryTable
), 0);
105 ExternalInterruptCount
= 0;
111 plUnloadDebugSupportDriver (
112 IN EFI_HANDLE ImageHandle
117 Unload handler that is called during UnloadImage() - deallocates pool memory
118 used by the driver. Must be public because it's referenced from DebugSuport.c
121 ImageHandle - Image handle
125 EFI_STATUS - anything other than EFI_SUCCESS indicates the callback was not registered.
129 EFI_EXCEPTION_TYPE ExceptionType
;
131 for (ExceptionType
= 0; ExceptionType
< NUM_IVT_ENTRIES
; ExceptionType
++) {
132 ManageIvtEntryTable (ExceptionType
, NULL
, NULL
);
140 IN EFI_EXCEPTION_TYPE ExceptionType
,
141 IN EFI_SYSTEM_CONTEXT Context
146 C routine that is called for all registered exceptions. This is the main
147 exception dispatcher. Must be public because it's referenced from AsmFuncs.s.
150 ExceptionType - Exception Type
151 Context - System Context
159 STATIC BOOLEAN InHandler
= FALSE
;
163 DEBUG ((EFI_D_INFO
, "ERROR: Re-entered debugger!\n"
164 " ExceptionType == %X\n"
166 " Context.SystemContextIpf->CrIip == %X\n"
167 " Context.SystemContextIpf->CrIpsr == %X\n"
168 " InHandler == %X\n",
171 Context
.SystemContextIpf
->CrIip
,
172 Context
.SystemContextIpf
->CrIpsr
,
179 if (IvtEntryTable
[ExceptionType
].RegisteredCallback
!= NULL
) {
180 if (ExceptionType
!= EXCEPT_IPF_EXTERNAL_INTERRUPT
) {
181 IvtEntryTable
[ExceptionType
].RegisteredCallback (ExceptionType
, Context
.SystemContextIpf
);
183 IvtEntryTable
[ExceptionType
].RegisteredCallback (Context
.SystemContextIpf
);
193 GetHandlerEntryPoint (
200 Given an integer number, return the physical address of the entry point in the IFT
203 HandlerIndex - Index of the Handler
204 EntryPoint - IFT Entrypoint
215 // get base address of IVT
219 if (HandlerIndex
< 20) {
221 // first 20 provide 64 bundles per vector
223 TempPtr
+= 0x400 * HandlerIndex
;
226 // the rest provide 16 bundles per vector
228 TempPtr
+= 0x5000 + 0x100 * (HandlerIndex
- 20);
231 *EntryPoint
= (VOID
*) TempPtr
;
235 ManageIvtEntryTable (
236 IN EFI_EXCEPTION_TYPE ExceptionType
,
237 IN BUNDLE NewBundles
[NUM_BUNDLES_IN_STUB
],
238 IN
VOID (*NewCallback
) ()
243 This is the worker function that installs and removes all handlers
246 ExceptionType - Exception Type
247 NewBundles - New Boundles
248 NewCallback - New Callback
252 EFI_STATUS - any return other than EFI_SUCCESS indicates the request was not
254 EFI_ALEADY_STARTED - Ivt already hooked.
259 UINT64 InterruptFlags
;
263 // Get address of bundle 0
265 GetHandlerEntryPoint (ExceptionType
, (VOID
**) &B0Ptr
);
267 if (IvtEntryTable
[ExceptionType
].RegisteredCallback
!= NULL
) {
269 // we've already installed to this vector
271 if (NewCallback
!= NULL
) {
273 // if the input handler is non-null, error
275 return EFI_ALREADY_STARTED
;
278 // else remove the previously installed handler
280 OldTpl
= gBS
->RaiseTPL (TPL_HIGH_LEVEL
);
281 InterruptFlags
= ProgramInterruptFlags (DISABLE_INTERRUPTS
);
282 if (ExceptionType
== EXCEPT_IPF_EXTERNAL_INTERRUPT
) {
283 UnchainExternalInterrupt ();
285 UnhookEntry (ExceptionType
);
288 ProgramInterruptFlags (InterruptFlags
);
289 gBS
->RestoreTPL (OldTpl
);
291 // re-init IvtEntryTable
293 SetMem (&IvtEntryTable
[ExceptionType
], sizeof (IVT_ENTRY
), 0);
297 // no user handler installed on this vector
299 if (NewCallback
!= NULL
) {
300 OldTpl
= gBS
->RaiseTPL (TPL_HIGH_LEVEL
);
301 InterruptFlags
= ProgramInterruptFlags (DISABLE_INTERRUPTS
);
302 if (ExceptionType
== EXCEPT_IPF_EXTERNAL_INTERRUPT
) {
303 ChainExternalInterrupt (NewCallback
);
305 HookEntry (ExceptionType
, NewBundles
, NewCallback
);
308 ProgramInterruptFlags (InterruptFlags
);
309 gBS
->RestoreTPL (OldTpl
);
318 IN EFI_EXCEPTION_TYPE ExceptionType
,
319 IN BUNDLE NewBundles
[4],
320 IN
VOID (*NewCallback
) ()
325 Saves original IVT contents and inserts a few new bundles which are fixed up
326 to store the ExceptionType and then call the common handler.
329 ExceptionType - Exception Type
330 NewBundles - New Boundles
331 NewCallback - New Callback
343 // Get address of bundle 0
345 GetHandlerEntryPoint (ExceptionType
, (VOID
**) &B0Ptr
);
348 // copy original bundles from IVT to IvtEntryTable so we can restore them later
351 IvtEntryTable
[ExceptionType
].OrigBundles
,
353 sizeof (BUNDLE
) * NUM_BUNDLES_IN_STUB
358 CopyMem (B0Ptr
, NewBundles
, sizeof (BUNDLE
) * NUM_BUNDLES_IN_STUB
);
361 // fixup IVT entry so it stores its index and whether or not to chain...
363 FixupBundle
= B0Ptr
+ 2;
364 FixupBundle
->high
|= ExceptionType
<< 36;
366 InstructionCacheFlush (B0Ptr
, 5);
367 IvtEntryTable
[ExceptionType
].RegisteredCallback
= NewCallback
;
372 IN EFI_EXCEPTION_TYPE ExceptionType
377 Restores original IVT contents when unregistering a callback function
380 ExceptionType - Exception Type
381 NewBundles - New Boundles
382 NewCallback - New Callback
393 // Get address of bundle 0
395 GetHandlerEntryPoint (ExceptionType
, (VOID
**) &B0Ptr
);
397 // restore original bundles in IVT
401 IvtEntryTable
[ExceptionType
].OrigBundles
,
402 sizeof (BUNDLE
) * NUM_BUNDLES_IN_STUB
404 InstructionCacheFlush (B0Ptr
, 5);
408 ChainExternalInterrupt (
409 IN
VOID (*NewCallback
) ()
414 Sets up cache flush and calls assembly function to chain external interrupt.
415 Records new callback in IvtEntryTable.
418 NewCallback - New Callback
428 Start
= (VOID
*) ((UINT8
*) GetIva () + 0x400 * EXCEPT_IPF_EXTERNAL_INTERRUPT
+ 0x400);
429 IvtEntryTable
[EXCEPT_IPF_EXTERNAL_INTERRUPT
].RegisteredCallback
= NewCallback
;
431 InstructionCacheFlush (Start
, 0x400);
435 UnchainExternalInterrupt (
441 Sets up cache flush and calls assembly function to restore external interrupt.
442 Removes registered callback from IvtEntryTable.
455 Start
= (VOID
*) ((UINT8
*) GetIva () + 0x400 * EXCEPT_IPF_EXTERNAL_INTERRUPT
+ 0x400);
457 InstructionCacheFlush (Start
, 0x400);
458 IvtEntryTable
[EXCEPT_IPF_EXTERNAL_INTERRUPT
].RegisteredCallback
= NULL
;
462 // The rest of the functions in this file are all member functions for the
463 // DebugSupport protocol
468 GetMaximumProcessorIndex (
469 IN EFI_DEBUG_SUPPORT_PROTOCOL
*This
,
470 OUT UINTN
*MaxProcessorIndex
474 Routine Description: This is a DebugSupport protocol member function. Hard
475 coded to support only 1 processor for now.
478 This - The DebugSupport instance
479 MaxProcessorIndex - The maximuim supported processor index
482 Always returns EFI_SUCCESS with *MaxProcessorIndex set to 0
486 *MaxProcessorIndex
= 0;
487 return (EFI_SUCCESS
);
492 RegisterPeriodicCallback (
493 IN EFI_DEBUG_SUPPORT_PROTOCOL
*This
,
494 IN UINTN ProcessorIndex
,
495 IN EFI_PERIODIC_CALLBACK NewPeriodicCallback
500 DebugSupport protocol member function
503 This - The DebugSupport instance
504 ProcessorIndex - Which processor the callback applies to.
505 PeriodicCallback - Callback function
509 EFI_STATUS - anything other than EFI_SUCCESS indicates the callback was not registered.
513 return ManageIvtEntryTable (EXCEPT_IPF_EXTERNAL_INTERRUPT
, NULL
, NewPeriodicCallback
);
518 RegisterExceptionCallback (
519 IN EFI_DEBUG_SUPPORT_PROTOCOL
*This
,
520 IN UINTN ProcessorIndex
,
521 IN EFI_EXCEPTION_CALLBACK NewCallback
,
522 IN EFI_EXCEPTION_TYPE ExceptionType
527 DebugSupport protocol member function
530 This - The DebugSupport instance
531 ProcessorIndex - Which processor the callback applies to.
532 NewCallback - Callback function
533 ExceptionType - Which exception to hook
537 EFI_STATUS - anything other than EFI_SUCCESS indicates the callback was not registered.
541 return ManageIvtEntryTable (
543 (BUNDLE
*) ((EFI_PLABEL
*) HookStub
)->EntryPoint
,
550 InvalidateInstructionCache (
551 IN EFI_DEBUG_SUPPORT_PROTOCOL
*This
,
552 IN UINTN ProcessorIndex
,
559 DebugSupport protocol member function. Calls assembly routine to flush cache.
562 This - The DebugSupport instance
563 ProcessorIndex - Which processor the callback applies to.
564 Start - Physical base of the memory range to be invalidated
565 Length - mininum number of bytes in instruction cache to invalidate
572 InstructionCacheFlush (Start
, Length
);
573 return (EFI_SUCCESS
);