2 X64 specific debug support functions
4 Copyright (c) 2006 - 2007, 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"
21 // This the global main table to keep track of the interrupts
23 IDT_ENTRY
*IdtEntryTable
= NULL
;
24 DESCRIPTOR NullDesc
= {0, 0};
28 IN EFI_EXCEPTION_TYPE ExceptionType
,
33 Routine Description: Allocate pool for a new IDT entry stub. Copy the generic
34 stub into the new buffer and fixup the vector number and jump target address.
37 ExceptionType - This is the exception type that the new stub will be created
39 Stub - On successful exit, *Stub contains the newly allocated entry stub.
42 other possibilities are passed through from AllocatePool
51 // Fixup the stub code for this vector
54 // The stub code looks like this:
56 // 00000000 6A 00 push 0 ; push vector number - will be modified before installed
57 // 00000002 E9 db 0e9h ; jump rel32
58 // 00000003 00000000 dd 0 ; fixed up to relative address of CommonIdtEntry
62 // poke in the exception type so the second push pushes the exception type
64 StubCopy
[0x1] = (UINT8
) ExceptionType
;
67 // fixup the jump target to point to the common entry
69 *(UINT32
*) &StubCopy
[0x3] = (UINT32
)((UINTN
) CommonIdtEntry
- (UINTN
) &StubCopy
[StubSize
]);
76 IN EFI_EXCEPTION_TYPE ExceptionType
,
77 IN
VOID (*NewCallback
) ()
82 Creates a nes entry stub. Then saves the current IDT entry and replaces it
83 with an interrupt gate for the new entry point. The IdtEntryTable is updated
84 with the new registered function.
86 This code executes in boot services context. The stub entry executes in interrupt
90 ExceptionType - specifies which vector to hook.
91 NewCallback - a pointer to the new function to be registered.
95 Other possibilities are passed through by CreateEntryStub
99 BOOLEAN OldIntFlagState
;
102 Status
= CreateEntryStub (ExceptionType
, (VOID
**) &IdtEntryTable
[ExceptionType
].StubEntry
);
103 if (Status
== EFI_SUCCESS
) {
104 OldIntFlagState
= WriteInterruptFlag (0);
105 ReadIdt (ExceptionType
, &(IdtEntryTable
[ExceptionType
].OrigDesc
));
107 ((UINT16
*) &IdtEntryTable
[ExceptionType
].OrigVector
)[0] = ((UINT16
*) &IdtEntryTable
[ExceptionType
].OrigDesc
.Low
)[0];
108 ((UINT16
*) &IdtEntryTable
[ExceptionType
].OrigVector
)[1] = ((UINT16
*) &IdtEntryTable
[ExceptionType
].OrigDesc
.Low
)[3];
109 ((UINT32
*) &IdtEntryTable
[ExceptionType
].OrigVector
)[1] = ((UINT32
*) &IdtEntryTable
[ExceptionType
].OrigDesc
.High
)[0];
111 Vect2Desc (&IdtEntryTable
[ExceptionType
].NewDesc
, IdtEntryTable
[ExceptionType
].StubEntry
);
112 IdtEntryTable
[ExceptionType
].RegisteredCallback
= NewCallback
;
113 WriteIdt (ExceptionType
, &(IdtEntryTable
[ExceptionType
].NewDesc
));
114 WriteInterruptFlag (OldIntFlagState
);
122 IN EFI_EXCEPTION_TYPE ExceptionType
127 Undoes HookEntry. This code executes in boot services context.
130 ExceptionType - specifies which entry to unhook
137 BOOLEAN OldIntFlagState
;
139 OldIntFlagState
= WriteInterruptFlag (0);
140 WriteIdt (ExceptionType
, &(IdtEntryTable
[ExceptionType
].OrigDesc
));
141 WriteInterruptFlag (OldIntFlagState
);
147 ManageIdtEntryTable (
148 VOID (*NewCallback
)(),
149 EFI_EXCEPTION_TYPE ExceptionType
154 This is the main worker function that manages the state of the interrupt
155 handlers. It both installs and uninstalls interrupt handlers based on the
156 value of NewCallback. If NewCallback is NULL, then uninstall is indicated.
157 If NewCallback is non-NULL, then install is indicated.
160 NewCallback - If non-NULL, NewCallback specifies the new handler to register.
161 If NULL, specifies that the previously registered handler should
163 ExceptionType - Indicates which entry to manage
167 EFI_INVALID_PARAMETER - requested uninstalling a handler from a vector that has
168 no handler registered for it
169 EFI_ALREADY_STARTED - requested install to a vector that already has a handler registered.
171 Other possible return values are passed through from UnHookEntry and HookEntry.
177 Status
= EFI_SUCCESS
;
179 if (CompareDescriptor (&IdtEntryTable
[ExceptionType
].NewDesc
, &NullDesc
)) {
181 // we've already installed to this vector
183 if (NewCallback
!= NULL
) {
185 // if the input handler is non-null, error
187 Status
= EFI_ALREADY_STARTED
;
189 Status
= UnhookEntry (ExceptionType
);
193 // no user handler installed on this vector
195 if (NewCallback
== NULL
) {
197 // if the input handler is null, error
199 Status
= EFI_INVALID_PARAMETER
;
201 Status
= HookEntry (ExceptionType
, NewCallback
);
210 GetMaximumProcessorIndex (
211 IN EFI_DEBUG_SUPPORT_PROTOCOL
*This
,
212 OUT UINTN
*MaxProcessorIndex
216 Routine Description: This is a DebugSupport protocol member function.
219 This - The DebugSupport instance
220 MaxProcessorIndex - The maximuim supported processor index
223 Always returns EFI_SUCCESS with *MaxProcessorIndex set to 0
227 *MaxProcessorIndex
= 0;
228 return (EFI_SUCCESS
);
233 RegisterPeriodicCallback (
234 IN EFI_DEBUG_SUPPORT_PROTOCOL
*This
,
235 IN UINTN ProcessorIndex
,
236 IN EFI_PERIODIC_CALLBACK PeriodicCallback
240 Routine Description: This is a DebugSupport protocol member function.
243 This - The DebugSupport instance
244 ProcessorIndex - Which processor the callback applies to.
245 PeriodicCallback - Callback function
250 EFI_INVALID_PARAMETER - requested uninstalling a handler from a vector that has
251 no handler registered for it
252 EFI_ALREADY_STARTED - requested install to a vector that already has a handler registered.
254 Other possible return values are passed through from UnHookEntry and HookEntry.
258 return ManageIdtEntryTable (PeriodicCallback
, SYSTEM_TIMER_VECTOR
);
263 RegisterExceptionCallback (
264 IN EFI_DEBUG_SUPPORT_PROTOCOL
*This
,
265 IN UINTN ProcessorIndex
,
266 IN EFI_EXCEPTION_CALLBACK NewCallback
,
267 IN EFI_EXCEPTION_TYPE ExceptionType
272 This is a DebugSupport protocol member function.
274 This code executes in boot services context.
277 This - The DebugSupport instance
278 ProcessorIndex - Which processor the callback applies to.
279 NewCallback - Callback function
280 ExceptionType - Which exception to hook
285 EFI_INVALID_PARAMETER - requested uninstalling a handler from a vector that has
286 no handler registered for it
287 EFI_ALREADY_STARTED - requested install to a vector that already has a handler registered.
289 Other possible return values are passed through from UnHookEntry and HookEntry.
293 return ManageIdtEntryTable (NewCallback
, ExceptionType
);
298 InvalidateInstructionCache (
299 IN EFI_DEBUG_SUPPORT_PROTOCOL
*This
,
300 IN UINTN ProcessorIndex
,
307 This is a DebugSupport protocol member function.
308 Calls assembly routine to flush cache.
311 This - The DebugSupport instance
312 ProcessorIndex - Which processor the callback applies to.
313 Start - Physical base of the memory range to be invalidated
314 Length - mininum number of bytes in instruction cache to invalidate
318 EFI_SUCCESS - always return success
327 plInitializeDebugSupportDriver (
333 Initializes driver's handler registration database.
335 This code executes in boot services context.
342 EFI_UNSUPPORTED - if X64 processor does not support FXSTOR/FXRSTOR instructions,
343 the context save will fail, so these processor's are not supported.
344 EFI_OUT_OF_RESOURCES - not resource to finish initialization
348 EFI_EXCEPTION_TYPE ExceptionType
;
350 if (!FxStorSupport ()) {
351 return EFI_UNSUPPORTED
;
354 IdtEntryTable
= AllocateZeroPool (sizeof (IDT_ENTRY
) * NUM_IDT_ENTRIES
);
355 if (IdtEntryTable
== NULL
) {
356 return EFI_OUT_OF_RESOURCES
;
359 for (ExceptionType
= 0; ExceptionType
< NUM_IDT_ENTRIES
; ExceptionType
++) {
360 IdtEntryTable
[ExceptionType
].StubEntry
= (DEBUG_PROC
) (UINTN
) AllocatePool (StubSize
);
361 if (IdtEntryTable
[ExceptionType
].StubEntry
== NULL
) {
365 CopyMem ((VOID
*)(UINTN
)IdtEntryTable
[ExceptionType
].StubEntry
, InterruptEntryStub
, StubSize
);
371 for (ExceptionType
= 0; ExceptionType
< NUM_IDT_ENTRIES
; ExceptionType
++) {
372 if (IdtEntryTable
[ExceptionType
].StubEntry
!= NULL
) {
373 FreePool ((VOID
*)(UINTN
)IdtEntryTable
[ExceptionType
].StubEntry
);
376 FreePool (IdtEntryTable
);
378 return EFI_OUT_OF_RESOURCES
;
383 plUnloadDebugSupportDriver (
384 IN EFI_HANDLE ImageHandle
389 This is the callback that is written to the LoadedImage protocol instance
390 on the image handle. It uninstalls all registered handlers and frees all entry
393 This code executes in boot services context.
396 ImageHandle - The image handle of the unload handler
400 EFI_SUCCESS - always return success
404 EFI_EXCEPTION_TYPE ExceptionType
;
406 for (ExceptionType
= 0; ExceptionType
< NUM_IDT_ENTRIES
; ExceptionType
++) {
407 ManageIdtEntryTable (NULL
, ExceptionType
);
410 FreePool (IdtEntryTable
);
415 InterruptDistrubutionHub (
416 EFI_EXCEPTION_TYPE ExceptionType
,
417 EFI_SYSTEM_CONTEXT_IA32
*ContextRecord
421 Routine Description: Common piece of code that invokes the registered handlers.
423 This code executes in exception context so no efi calls are allowed.
426 ExceptionType - exception type
427 ContextRecord - system context
435 if (IdtEntryTable
[ExceptionType
].RegisteredCallback
!= NULL
) {
436 if (ExceptionType
!= SYSTEM_TIMER_VECTOR
) {
437 IdtEntryTable
[ExceptionType
].RegisteredCallback (ExceptionType
, ContextRecord
);
439 OrigVector
= IdtEntryTable
[ExceptionType
].OrigVector
;
440 IdtEntryTable
[ExceptionType
].RegisteredCallback (ContextRecord
);