2 IPF specific functions to support Debug Support protocol.
4 Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.<BR>
5 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.
15 #include "PlDebugSupport.h"
17 BOOLEAN mInHandler
= FALSE
;
20 // number of bundles to swap in ivt
22 #define NUM_BUNDLES_IN_STUB 5
23 #define NUM_IVT_ENTRIES 64
26 BUNDLE OrigBundles
[NUM_BUNDLES_IN_STUB
];
27 CALLBACK_FUNC RegisteredCallback
;
30 IVT_ENTRY IvtEntryTable
[NUM_IVT_ENTRIES
];
33 // IPF context record is overallocated by 512 bytes to guarantee a 512 byte alignment exists
34 // within the buffer and still have a large enough buffer to hold a whole IPF context record.
36 UINT8 IpfContextBuf
[sizeof (EFI_SYSTEM_CONTEXT_IPF
) + 512];
39 // The PatchSaveBuffer is used to store the original bundles from the IVT where it is patched
40 // with the common handler.
42 UINT8 PatchSaveBuffer
[0x400];
43 UINTN ExternalInterruptCount
;
47 IPF specific DebugSupport driver initialization.
49 Must be public because it's referenced from DebugSupport.c
51 @retval EFI_SUCCESS Always.
55 PlInitializeDebugSupportDriver (
59 ZeroMem (IvtEntryTable
, sizeof (IvtEntryTable
));
60 ExternalInterruptCount
= 0;
65 Unload handler that is called during UnloadImage() - deallocates pool memory
68 Must be public because it's referenced from DebugSuport.c
70 @param ImageHandle The firmware allocated handle for the EFI image.
72 @retval EFI_SUCCESS Always.
77 PlUnloadDebugSupportDriver (
78 IN EFI_HANDLE ImageHandle
81 EFI_EXCEPTION_TYPE ExceptionType
;
83 for (ExceptionType
= 0; ExceptionType
< NUM_IVT_ENTRIES
; ExceptionType
++) {
84 ManageIvtEntryTable (ExceptionType
, NULL
, NULL
);
91 C routine that is called for all registered exceptions. This is the main
94 Must be public because it's referenced from AsmFuncs.s.
96 @param ExceptionType Specifies which processor exception.
97 @param Context System Context.
101 IN EFI_EXCEPTION_TYPE ExceptionType
,
102 IN EFI_SYSTEM_CONTEXT Context
107 DEBUG ((EFI_D_INFO
, "ERROR: Re-entered debugger!\n"
108 " ExceptionType == %X\n"
110 " Context.SystemContextIpf->CrIip == %LX\n"
111 " Context.SystemContextIpf->CrIpsr == %LX\n"
112 " mInHandler == %X\n",
113 (INT32
)ExceptionType
,
115 Context
.SystemContextIpf
->CrIip
,
116 Context
.SystemContextIpf
->CrIpsr
,
121 ASSERT (!mInHandler
);
123 if (IvtEntryTable
[ExceptionType
].RegisteredCallback
!= NULL
) {
124 if (ExceptionType
!= EXCEPT_IPF_EXTERNAL_INTERRUPT
) {
125 IvtEntryTable
[ExceptionType
].RegisteredCallback (ExceptionType
, Context
.SystemContextIpf
);
127 IvtEntryTable
[ExceptionType
].RegisteredCallback (Context
.SystemContextIpf
);
137 Given an integer number, return the physical address of the entry point in the IFT.
139 @param HandlerIndex Index of the Handler
140 @param EntryPoint IFT Entrypoint
144 GetHandlerEntryPoint (
152 // get base address of IVT
156 if (HandlerIndex
< 20) {
158 // first 20 provide 64 bundles per vector
160 TempPtr
+= 0x400 * HandlerIndex
;
163 // the rest provide 16 bundles per vector
165 TempPtr
+= 0x5000 + 0x100 * (HandlerIndex
- 20);
168 *EntryPoint
= (VOID
*) TempPtr
;
172 This is the worker function that uninstalls and removes all handlers.
174 @param ExceptionType Specifies which processor exception.
175 @param NewBundles New Boundles.
176 @param NewCallback A pointer to the new function to be registered.
178 @retval EFI_ALEADY_STARTED Ivt already hooked.
179 @retval EFI_SUCCESS Successfully uninstalled.
183 ManageIvtEntryTable (
184 IN EFI_EXCEPTION_TYPE ExceptionType
,
185 IN BUNDLE NewBundles
[NUM_BUNDLES_IN_STUB
],
186 IN CALLBACK_FUNC 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 Specifies which processor exception.
252 @param NewBundles New Boundles.
253 @param NewCallback A pointer to the new function to be hooked.
258 IN EFI_EXCEPTION_TYPE ExceptionType
,
259 IN BUNDLE NewBundles
[4],
260 IN CALLBACK_FUNC 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 Specifies which processor exception.
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 A pointer to the interrupt handle.
331 ChainExternalInterrupt (
332 IN CALLBACK_FUNC 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 Returns the maximum value that may be used for the ProcessorIndex parameter in
363 RegisterPeriodicCallback() and RegisterExceptionCallback().
365 Hard coded to support only 1 processor for now.
367 @param This A pointer to the EFI_DEBUG_SUPPORT_PROTOCOL instance.
368 @param MaxProcessorIndex Pointer to a caller-allocated UINTN in which the maximum supported
369 processor index is returned. Always 0 returned.
371 @retval EFI_SUCCESS Always returned with **MaxProcessorIndex set to 0.
376 GetMaximumProcessorIndex (
377 IN EFI_DEBUG_SUPPORT_PROTOCOL
*This
,
378 OUT UINTN
*MaxProcessorIndex
381 *MaxProcessorIndex
= 0;
382 return (EFI_SUCCESS
);
386 Registers a function to be called back periodically in interrupt context.
388 @param This A pointer to the EFI_DEBUG_SUPPORT_PROTOCOL instance.
389 @param ProcessorIndex Specifies which processor the callback function applies to.
390 @param PeriodicCallback A pointer to a function of type PERIODIC_CALLBACK that is the main
391 periodic entry point of the debug agent.
393 @retval EFI_SUCCESS The function completed successfully.
394 @retval EFI_ALREADY_STARTED Non-NULL PeriodicCallback parameter when a callback
395 function was previously registered.
396 @retval EFI_OUT_OF_RESOURCES System has insufficient memory resources to register new callback
401 RegisterPeriodicCallback (
402 IN EFI_DEBUG_SUPPORT_PROTOCOL
*This
,
403 IN UINTN ProcessorIndex
,
404 IN EFI_PERIODIC_CALLBACK PeriodicCallback
407 return ManageIvtEntryTable (EXCEPT_IPF_EXTERNAL_INTERRUPT
, NULL
, PeriodicCallback
);
411 Registers a function to be called when a given processor exception occurs.
413 This code executes in boot services context.
415 @param This A pointer to the EFI_DEBUG_SUPPORT_PROTOCOL instance.
416 @param ProcessorIndex Specifies which processor the callback function applies to.
417 @param ExceptionCallback A pointer to a function of type EXCEPTION_CALLBACK that is called
418 when the processor exception specified by ExceptionType occurs.
419 @param ExceptionType Specifies which processor exception to hook.
421 @retval EFI_SUCCESS The function completed successfully.
422 @retval EFI_ALREADY_STARTED Non-NULL PeriodicCallback parameter when a callback
423 function was previously registered.
424 @retval EFI_OUT_OF_RESOURCES System has insufficient memory resources to register new callback
429 RegisterExceptionCallback (
430 IN EFI_DEBUG_SUPPORT_PROTOCOL
*This
,
431 IN UINTN ProcessorIndex
,
432 IN EFI_EXCEPTION_CALLBACK ExceptionCallback
,
433 IN EFI_EXCEPTION_TYPE ExceptionType
436 return ManageIvtEntryTable (
438 (BUNDLE
*) ((EFI_PLABEL
*) HookStub
)->EntryPoint
,
444 Invalidates processor instruction cache for a memory range. Subsequent execution in this range
445 causes a fresh memory fetch to retrieve code to be executed.
447 @param This A pointer to the EFI_DEBUG_SUPPORT_PROTOCOL instance.
448 @param ProcessorIndex Specifies which processor's instruction cache is to be invalidated.
449 @param Start Specifies the physical base of the memory range to be invalidated.
450 @param Length Specifies the minimum number of bytes in the processor's instruction
453 @retval EFI_SUCCESS Always returned.
458 InvalidateInstructionCache (
459 IN EFI_DEBUG_SUPPORT_PROTOCOL
*This
,
460 IN UINTN ProcessorIndex
,
465 InstructionCacheFlush (Start
, Length
);