2 IPF specific debug support functions
4 Copyright (c) 2006 - 2008, 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"
20 BOOLEAN mInHandler
= FALSE
;
23 // number of bundles to swap in ivt
25 #define NUM_BUNDLES_IN_STUB 5
26 #define NUM_IVT_ENTRIES 64
29 BUNDLE OrigBundles
[NUM_BUNDLES_IN_STUB
];
30 VOID (*RegisteredCallback
) ();
33 IVT_ENTRY IvtEntryTable
[NUM_IVT_ENTRIES
];
36 // IPF context record is overallocated by 512 bytes to guarantee a 512 byte alignment exists
37 // within the buffer and still have a large enough buffer to hold a whole IPF context record.
39 UINT8 IpfContextBuf
[sizeof (EFI_SYSTEM_CONTEXT_IPF
) + 512];
42 // The PatchSaveBuffer is used to store the original bundles from the IVT where it is patched
43 // with the common handler.
45 UINT8 PatchSaveBuffer
[0x400];
46 UINTN ExternalInterruptCount
;
50 IPF specific DebugSupport driver initialization.
52 Must be public because it's referenced from DebugSupport.c
54 @retval EFI_SUCCESS Always.
58 PlInitializeDebugSupportDriver (
62 ZeroMem (IvtEntryTable
, sizeof (IvtEntryTable
));
63 ExternalInterruptCount
= 0;
68 Unload handler that is called during UnloadImage() - deallocates pool memory
69 used by the driver. Must be public because it's referenced from DebugSuport.c
71 @param ImageHandle The firmware allocated handle for the EFI image.
73 @retval EFI_SUCCESS Always.
78 PlUnloadDebugSupportDriver (
79 IN EFI_HANDLE ImageHandle
82 EFI_EXCEPTION_TYPE ExceptionType
;
84 for (ExceptionType
= 0; ExceptionType
< NUM_IVT_ENTRIES
; ExceptionType
++) {
85 ManageIvtEntryTable (ExceptionType
, NULL
, NULL
);
92 C routine that is called for all registered exceptions. This is the main
93 exception dispatcher. Must be public because it's referenced from AsmFuncs.s.
95 @param ExceptionType Exception Type
96 @param Context System Context
100 IN EFI_EXCEPTION_TYPE ExceptionType
,
101 IN EFI_SYSTEM_CONTEXT Context
106 DEBUG ((EFI_D_INFO
, "ERROR: Re-entered debugger!\n"
107 " ExceptionType == %X\n"
109 " Context.SystemContextIpf->CrIip == %X\n"
110 " Context.SystemContextIpf->CrIpsr == %X\n"
111 " mInHandler == %X\n",
114 Context
.SystemContextIpf
->CrIip
,
115 Context
.SystemContextIpf
->CrIpsr
,
120 ASSERT (!mInHandler
);
122 if (IvtEntryTable
[ExceptionType
].RegisteredCallback
!= NULL
) {
123 if (ExceptionType
!= EXCEPT_IPF_EXTERNAL_INTERRUPT
) {
124 IvtEntryTable
[ExceptionType
].RegisteredCallback (ExceptionType
, Context
.SystemContextIpf
);
126 IvtEntryTable
[ExceptionType
].RegisteredCallback (Context
.SystemContextIpf
);
136 Given an integer number, return the physical address of the entry point in the IFT.
138 @param HandlerIndex Index of the Handler
139 @param EntryPoint IFT Entrypoint
143 GetHandlerEntryPoint (
151 // get base address of IVT
155 if (HandlerIndex
< 20) {
157 // first 20 provide 64 bundles per vector
159 TempPtr
+= 0x400 * HandlerIndex
;
162 // the rest provide 16 bundles per vector
164 TempPtr
+= 0x5000 + 0x100 * (HandlerIndex
- 20);
167 *EntryPoint
= (VOID
*) TempPtr
;
171 This is the worker function that uninstalls and removes all handlers.
173 @param ExceptionType Exception Type
174 @param NewBundles New Boundles
175 @param NewCallback New Callback
177 @retval EFI_ALEADY_STARTED Ivt already hooked.
178 @retval others Indicates the request was not satisfied.
179 @retval EFI_SUCCESS Successfully uninstalled.
183 ManageIvtEntryTable (
184 IN EFI_EXCEPTION_TYPE ExceptionType
,
185 IN BUNDLE NewBundles
[NUM_BUNDLES_IN_STUB
],
186 IN
VOID (*NewCallback
) ()
190 UINT64 InterruptFlags
;
194 // Get address of bundle 0
196 GetHandlerEntryPoint (ExceptionType
, (VOID
**) &B0Ptr
);
198 if (IvtEntryTable
[ExceptionType
].RegisteredCallback
!= NULL
) {
200 // we've already installed to this vector
202 if (NewCallback
!= NULL
) {
204 // if the input handler is non-null, error
206 return EFI_ALREADY_STARTED
;
209 // else remove the previously installed handler
211 OldTpl
= gBS
->RaiseTPL (TPL_HIGH_LEVEL
);
212 InterruptFlags
= ProgramInterruptFlags (DISABLE_INTERRUPTS
);
213 if (ExceptionType
== EXCEPT_IPF_EXTERNAL_INTERRUPT
) {
214 UnchainExternalInterrupt ();
216 UnhookEntry (ExceptionType
);
219 ProgramInterruptFlags (InterruptFlags
);
220 gBS
->RestoreTPL (OldTpl
);
222 // re-init IvtEntryTable
224 ZeroMem (&IvtEntryTable
[ExceptionType
], sizeof (IVT_ENTRY
));
228 // no user handler installed on this vector
230 if (NewCallback
!= NULL
) {
231 OldTpl
= gBS
->RaiseTPL (TPL_HIGH_LEVEL
);
232 InterruptFlags
= ProgramInterruptFlags (DISABLE_INTERRUPTS
);
233 if (ExceptionType
== EXCEPT_IPF_EXTERNAL_INTERRUPT
) {
234 ChainExternalInterrupt (NewCallback
);
236 HookEntry (ExceptionType
, NewBundles
, NewCallback
);
239 ProgramInterruptFlags (InterruptFlags
);
240 gBS
->RestoreTPL (OldTpl
);
248 Saves original IVT contents and inserts a few new bundles which are fixed up
249 to store the ExceptionType and then call the common handler.
251 @param ExceptionType Exception Type
252 @param NewBundles New Boundles
253 @param NewCallback New Callback
258 IN EFI_EXCEPTION_TYPE ExceptionType
,
259 IN BUNDLE NewBundles
[4],
260 IN
VOID (*NewCallback
) ()
267 // Get address of bundle 0
269 GetHandlerEntryPoint (ExceptionType
, (VOID
**) &B0Ptr
);
272 // copy original bundles from IVT to IvtEntryTable so we can restore them later
275 IvtEntryTable
[ExceptionType
].OrigBundles
,
277 sizeof (BUNDLE
) * NUM_BUNDLES_IN_STUB
282 CopyMem (B0Ptr
, NewBundles
, sizeof (BUNDLE
) * NUM_BUNDLES_IN_STUB
);
285 // fixup IVT entry so it stores its index and whether or not to chain...
287 FixupBundle
= B0Ptr
+ 2;
288 FixupBundle
->high
|= ExceptionType
<< 36;
290 InstructionCacheFlush (B0Ptr
, 5);
291 IvtEntryTable
[ExceptionType
].RegisteredCallback
= NewCallback
;
295 Restores original IVT contents when unregistering a callback function.
297 @param ExceptionType Exception Type
302 IN EFI_EXCEPTION_TYPE ExceptionType
308 // Get address of bundle 0
310 GetHandlerEntryPoint (ExceptionType
, (VOID
**) &B0Ptr
);
312 // restore original bundles in IVT
316 IvtEntryTable
[ExceptionType
].OrigBundles
,
317 sizeof (BUNDLE
) * NUM_BUNDLES_IN_STUB
319 InstructionCacheFlush (B0Ptr
, 5);
323 Sets up cache flush and calls assembly function to chain external interrupt.
325 Records new callback in IvtEntryTable.
327 @param NewCallback New Callback
331 ChainExternalInterrupt (
332 IN
VOID (*NewCallback
) ()
337 Start
= (VOID
*) ((UINT8
*) GetIva () + 0x400 * EXCEPT_IPF_EXTERNAL_INTERRUPT
+ 0x400);
338 IvtEntryTable
[EXCEPT_IPF_EXTERNAL_INTERRUPT
].RegisteredCallback
= NewCallback
;
340 InstructionCacheFlush (Start
, 0x400);
344 Sets up cache flush and calls assembly function to restore external interrupt.
345 Removes registered callback from IvtEntryTable.
349 UnchainExternalInterrupt (
355 Start
= (VOID
*) ((UINT8
*) GetIva () + 0x400 * EXCEPT_IPF_EXTERNAL_INTERRUPT
+ 0x400);
357 InstructionCacheFlush (Start
, 0x400);
358 IvtEntryTable
[EXCEPT_IPF_EXTERNAL_INTERRUPT
].RegisteredCallback
= NULL
;
362 // The rest of the functions in this file are all member functions for the
363 // DebugSupport protocol
367 This is a DebugSupport protocol member function, hard
368 coded to support only 1 processor for now.
370 @param This The DebugSupport instance
371 @param MaxProcessorIndex The maximuim supported processor index
373 @retval EFI_SUCCESS Always returned with **MaxProcessorIndex set to 0.
378 GetMaximumProcessorIndex (
379 IN EFI_DEBUG_SUPPORT_PROTOCOL
*This
,
380 OUT UINTN
*MaxProcessorIndex
383 *MaxProcessorIndex
= 0;
384 return (EFI_SUCCESS
);
388 DebugSupport protocol member function.
390 @param This The DebugSupport instance
391 @param ProcessorIndex Which processor the callback applies to.
392 @param PeriodicCallback Callback function
394 @retval EFI_SUCCESS Indicates the callback was registered.
395 @retval others Callback was not registered.
400 RegisterPeriodicCallback (
401 IN EFI_DEBUG_SUPPORT_PROTOCOL
*This
,
402 IN UINTN ProcessorIndex
,
403 IN EFI_PERIODIC_CALLBACK PeriodicCallback
406 return ManageIvtEntryTable (EXCEPT_IPF_EXTERNAL_INTERRUPT
, NULL
, PeriodicCallback
);
410 DebugSupport protocol member function.
412 @param This The DebugSupport instance
413 @param ProcessorIndex Which processor the callback applies to.
414 @param NewCallback Callback function
415 @param ExceptionType Which exception to hook
417 @retval EFI_SUCCESS Indicates the callback was registered.
418 @retval others Callback was not registered.
423 RegisterExceptionCallback (
424 IN EFI_DEBUG_SUPPORT_PROTOCOL
*This
,
425 IN UINTN ProcessorIndex
,
426 IN EFI_EXCEPTION_CALLBACK NewCallback
,
427 IN EFI_EXCEPTION_TYPE ExceptionType
430 return ManageIvtEntryTable (
432 (BUNDLE
*) ((EFI_PLABEL
*) HookStub
)->EntryPoint
,
438 DebugSupport protocol member function. Calls assembly routine to flush cache.
440 @param This The DebugSupport instance
441 @param ProcessorIndex Which processor the callback applies to.
442 @param Start Physical base of the memory range to be invalidated
443 @param Length mininum number of bytes in instruction cache to invalidate
445 @retval EFI_SUCCESS Always returned.
450 InvalidateInstructionCache (
451 IN EFI_DEBUG_SUPPORT_PROTOCOL
*This
,
452 IN UINTN ProcessorIndex
,
457 InstructionCacheFlush (Start
, Length
);