2 Debug Agent library implementition for Dxe Core and Dxr modules.
4 Copyright (c) 2010 - 2013, 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 "DxeDebugAgentLib.h"
17 DEBUG_AGENT_MAILBOX mMailbox
;
18 DEBUG_AGENT_MAILBOX
*mMailboxPointer
= NULL
;
19 IA32_IDT_GATE_DESCRIPTOR mIdtEntryTable
[33];
20 BOOLEAN mDxeCoreFlag
= FALSE
;
21 BOOLEAN mMultiProcessorDebugSupport
= FALSE
;
22 VOID
*mSavedIdtTable
= NULL
;
23 UINTN mSaveIdtTableSize
= 0;
24 BOOLEAN mDebugAgentInitialized
= FALSE
;
25 BOOLEAN mSkipBreakpoint
= FALSE
;
28 Check if debug agent support multi-processor.
30 @retval TRUE Multi-processor is supported.
31 @retval FALSE Multi-processor is not supported.
35 MultiProcessorDebugSupport (
39 return mMultiProcessorDebugSupport
;
43 Internal constructor worker function.
45 It will register one callback function on EFI PCD Protocol.
46 It will allocate the NVS memory to store Mailbox and install configuration table
47 in system table to store its pointer.
51 InternalConstructorWorker (
56 EFI_PHYSICAL_ADDRESS Address
;
57 BOOLEAN DebugTimerInterruptState
;
60 // Install EFI Serial IO protocol on debug port
65 Status
= gBS
->AllocatePages (
68 EFI_SIZE_TO_PAGES (sizeof (DEBUG_AGENT_MAILBOX
)),
71 ASSERT_EFI_ERROR (Status
);
73 DebugTimerInterruptState
= SaveAndSetDebugTimerInterrupt (FALSE
);
75 (UINT8
*) (UINTN
) Address
,
76 (UINT8
*) (UINTN
) GetMailboxPointer (),
77 sizeof (DEBUG_AGENT_MAILBOX
)
79 DebugTimerInterruptState
= SaveAndSetDebugTimerInterrupt (DebugTimerInterruptState
);
81 mMailboxPointer
= (DEBUG_AGENT_MAILBOX
*) (UINTN
) Address
;
83 Status
= gBS
->InstallConfigurationTable (&gEfiDebugAgentGuid
, (VOID
*) mMailboxPointer
);
84 ASSERT_EFI_ERROR (Status
);
88 Debug Agent constructor function.
90 @param[in] ImageHandle The firmware allocated handle for the EFI image.
91 @param[in] SystemTable A pointer to the EFI System Table.
93 @retval RETURN_SUCCESS When this function completed.
98 DxeDebugAgentLibConstructor (
99 IN EFI_HANDLE ImageHandle
,
100 IN EFI_SYSTEM_TABLE
*SystemTable
105 // Invoke internal constructor function only when DXE core links this library instance
107 InternalConstructorWorker ();
110 return RETURN_SUCCESS
;
114 Get the pointer to Mailbox from the configuration table.
116 @return Pointer to Mailbox.
119 DEBUG_AGENT_MAILBOX
*
120 GetMailboxFromConfigurationTable (
125 DEBUG_AGENT_MAILBOX
*Mailbox
;
127 Status
= EfiGetSystemConfigurationTable (&gEfiDebugAgentGuid
, (VOID
**) &Mailbox
);
128 if (Status
== EFI_SUCCESS
&& Mailbox
!= NULL
) {
129 VerifyMailboxChecksum (Mailbox
);
137 Get the pointer to Mailbox from the GUIDed HOB.
139 @param[in] HobStart The starting HOB pointer to search from.
141 @return Pointer to Mailbox.
144 DEBUG_AGENT_MAILBOX
*
149 EFI_HOB_GUID_TYPE
*GuidHob
;
150 UINT64
*MailboxLocation
;
151 DEBUG_AGENT_MAILBOX
*Mailbox
;
153 GuidHob
= GetNextGuidHob (&gEfiDebugAgentGuid
, HobStart
);
154 if (GuidHob
== NULL
) {
157 MailboxLocation
= (UINT64
*) (GET_GUID_HOB_DATA(GuidHob
));
158 Mailbox
= (DEBUG_AGENT_MAILBOX
*)(UINTN
)(*MailboxLocation
);
159 VerifyMailboxChecksum (Mailbox
);
165 Get Debug Agent Mailbox pointer.
167 @return Mailbox pointer.
170 DEBUG_AGENT_MAILBOX
*
175 AcquireMpSpinLock (&mDebugMpContext
.MailboxSpinLock
);
176 VerifyMailboxChecksum (mMailboxPointer
);
177 ReleaseMpSpinLock (&mDebugMpContext
.MailboxSpinLock
);
178 return mMailboxPointer
;
182 Get debug port handle.
184 @return Debug port handle.
192 return (DEBUG_PORT_HANDLE
) (UINTN
)(GetMailboxPointer ()->DebugPortHandle
);
196 Worker function to setup IDT table and initialize the IDT entries.
198 @param[in] Mailbox Pointer to Mailbox.
202 SetupDebugAgentEnviroment (
203 IN DEBUG_AGENT_MAILBOX
*Mailbox
206 IA32_DESCRIPTOR Idtr
;
207 UINT16 IdtEntryCount
;
208 UINT64 DebugPortHandle
;
210 if (mMultiProcessorDebugSupport
) {
211 InitializeSpinLock (&mDebugMpContext
.MpContextSpinLock
);
212 InitializeSpinLock (&mDebugMpContext
.DebugPortSpinLock
);
213 InitializeSpinLock (&mDebugMpContext
.MailboxSpinLock
);
215 // Clear Break CPU index value
217 mDebugMpContext
.BreakAtCpuIndex
= (UINT32
) -1;
221 // Get original IDT address and size.
223 AsmReadIdtr ((IA32_DESCRIPTOR
*) &Idtr
);
224 IdtEntryCount
= (UINT16
) ((Idtr
.Limit
+ 1) / sizeof (IA32_IDT_GATE_DESCRIPTOR
));
225 if (IdtEntryCount
< 33) {
226 Idtr
.Limit
= (UINT16
) (sizeof (IA32_IDT_GATE_DESCRIPTOR
) * 33 - 1);
227 Idtr
.Base
= (UINTN
) &mIdtEntryTable
;
228 ZeroMem (&mIdtEntryTable
, Idtr
.Limit
+ 1);
229 AsmWriteIdtr ((IA32_DESCRIPTOR
*) &Idtr
);
233 // Initialize the IDT table entries to support source level debug.
235 InitializeDebugIdt ();
237 if (Mailbox
!= NULL
) {
239 // If Mailbox exists, copy it into one global variable,
241 CopyMem (&mMailbox
, Mailbox
, sizeof (DEBUG_AGENT_MAILBOX
));
243 ZeroMem (&mMailbox
, sizeof (DEBUG_AGENT_MAILBOX
));
246 mMailboxPointer
= &mMailbox
;
248 // Initialize debug communication port
250 DebugPortHandle
= (UINT64
) (UINTN
)DebugPortInitialize ((VOID
*)(UINTN
)mMailboxPointer
->DebugPortHandle
, NULL
);
251 UpdateMailboxContent (mMailboxPointer
, DEBUG_MAILBOX_DEBUG_PORT_HANDLE_INDEX
, DebugPortHandle
);
253 if (Mailbox
== NULL
) {
255 // Trigger one software interrupt to inform HOST
257 TriggerSoftInterrupt (SYSTEM_RESET_SIGNATURE
);
258 SetDebugFlag (DEBUG_AGENT_FLAG_MEMORY_READY
, 1);
260 // Memory has been ready
262 if (IsHostAttached ()) {
264 // Trigger one software interrupt to inform HOST
266 TriggerSoftInterrupt (MEMORY_READY_SIGNATURE
);
273 Initialize debug agent.
275 This function is used to set up debug enviroment for DXE phase.
277 If this function is called by DXE Core, Context must be the pointer
278 to HOB list which will be used to get GUIDed HOB. It will enable
279 interrupt to support break-in feature.
280 If this function is called by DXE module, Context must be NULL. It
281 will enable interrupt to support break-in feature.
283 @param[in] InitFlag Init flag is used to decide initialize process.
284 @param[in] Context Context needed according to InitFlag.
285 @param[in] Function Continue function called by debug agent library; it was
291 InitializeDebugAgent (
293 IN VOID
*Context
, OPTIONAL
294 IN DEBUG_AGENT_CONTINUE Function OPTIONAL
297 UINT64
*MailboxLocation
;
298 DEBUG_AGENT_MAILBOX
*Mailbox
;
299 BOOLEAN InterruptStatus
;
301 IA32_DESCRIPTOR IdtDescriptor
;
302 IA32_DESCRIPTOR
*Ia32Idtr
;
303 IA32_IDT_ENTRY
*Ia32IdtEntry
;
305 if (InitFlag
== DEBUG_AGENT_INIT_DXE_AP
) {
307 // Invoked by AP, enable interrupt to let AP could receive IPI from other processors
314 // Disable Debug Timer interrupt
316 SaveAndSetDebugTimerInterrupt (FALSE
);
318 // Save and disable original interrupt status
320 InterruptStatus
= SaveAndDisableInterrupts ();
323 // Try to get mailbox firstly
327 MailboxLocation
= NULL
;
331 case DEBUG_AGENT_INIT_DXE_LOAD
:
333 // Check if Debug Agent has been initialized before
335 if (IsDebugAgentInitialzed ()) {
336 DEBUG ((EFI_D_INFO
, "Debug Agent: The former agent will be overwritten by the new one!\n"));
339 mMultiProcessorDebugSupport
= TRUE
;
341 // Save original IDT table
343 AsmReadIdtr (&IdtDescriptor
);
344 mSaveIdtTableSize
= IdtDescriptor
.Limit
+ 1;
345 mSavedIdtTable
= AllocateCopyPool (mSaveIdtTableSize
, (VOID
*) IdtDescriptor
.Base
);
347 // Initialize Debug Timer hardware
349 InitializeDebugTimer ();
351 // Check if Debug Agent initialized in DXE phase
353 Mailbox
= GetMailboxFromConfigurationTable ();
354 if (Mailbox
== NULL
) {
356 // Try to get mailbox from GUIDed HOB build in PEI
358 HobList
= GetHobList ();
359 Mailbox
= GetMailboxFromHob (HobList
);
362 // Set up IDT table and prepare for IDT entries
364 SetupDebugAgentEnviroment (Mailbox
);
366 // For DEBUG_AGENT_INIT_S3, needn't to install configuration table and EFI Serial IO protocol
367 // For DEBUG_AGENT_INIT_DXE_CORE, InternalConstructorWorker() will invoked in Constructor()
369 InternalConstructorWorker ();
371 // Enable interrupt to receive Debug Timer interrupt
375 mDebugAgentInitialized
= TRUE
;
376 FindAndReportModuleImageInfo (SIZE_4KB
);
378 *(EFI_STATUS
*)Context
= EFI_SUCCESS
;
380 if (gST
->ConOut
!= NULL
) {
381 Print (L
"Debug Agent: Initialized successfully!\r\n");
382 Print (L
"If the Debug Port is serial port, please make sure this serial port isn't connected by ISA Serial driver\r\n");
383 Print (L
"You could do the following steps to disconnect the serial port:\r\n");
384 Print (L
"1: Shell> drivers\r\n");
386 Print (L
" V VERSION E G G #D #C DRIVER NAME IMAGE NAME\r\n");
387 Print (L
" == ======== = = = == == =================================== ===================\r\n");
388 Print (L
" 8F 0000000A B - - 1 14 PCI Bus Driver PciBusDxe\r\n");
389 Print (L
" 91 00000010 ? - - - - ATA Bus Driver AtaBusDxe\r\n");
391 Print (L
" A7 0000000A B - - 1 1 ISA Serial Driver IsaSerialDxe\r\n");
393 Print (L
"2: Shell> dh -d A7\r\n");
394 Print (L
" A7: Image(IsaSerialDxe) ImageDevPath (..9FB3-11D4-9A3A-0090273FC14D))DriverBinding ComponentName ComponentName2\r\n");
395 Print (L
" Driver Name : ISA Serial Driver\r\n");
396 Print (L
" Image Name : FvFile(93B80003-9FB3-11D4-9A3A-0090273FC14D)\r\n");
397 Print (L
" Driver Version : 0000000A\r\n");
398 Print (L
" Driver Type : BUS\r\n");
399 Print (L
" Configuration : NO\r\n");
400 Print (L
" Diagnostics : NO\r\n");
401 Print (L
" Managing :\r\n");
402 Print (L
" Ctrl[EA] : PciRoot(0x0)/Pci(0x1F,0x0)/Serial(0x0)\r\n");
403 Print (L
" Child[EB] : PciRoot(0x0)/Pci(0x1F,0x0)/Serial(0x0)/Uart(115200,8,N,1)\r\n");
404 Print (L
"3: Shell> disconnect EA\r\n");
405 Print (L
"4: Shell> load -nc DebugAgentDxe.efi\r\n\r\n");
409 case DEBUG_AGENT_INIT_DXE_UNLOAD
:
410 if (mDebugAgentInitialized
) {
411 if (IsHostAttached ()) {
412 Print (L
"Debug Agent: Host is still connected, please de-attach TARGET firstly!\r\n");
413 *(EFI_STATUS
*)Context
= EFI_ACCESS_DENIED
;
415 // Enable Debug Timer interrupt again
417 SaveAndSetDebugTimerInterrupt (TRUE
);
420 // Restore original IDT table
422 AsmReadIdtr (&IdtDescriptor
);
423 IdtDescriptor
.Limit
= (UINT16
) (mSaveIdtTableSize
- 1);
424 CopyMem ((VOID
*) IdtDescriptor
.Base
, mSavedIdtTable
, mSaveIdtTableSize
);
425 AsmWriteIdtr (&IdtDescriptor
);
426 FreePool (mSavedIdtTable
);
427 mDebugAgentInitialized
= FALSE
;
428 *(EFI_STATUS
*)Context
= EFI_SUCCESS
;
431 Print (L
"Debug Agent: It hasn't been initialized, cannot unload it!\r\n");
432 *(EFI_STATUS
*)Context
= EFI_NOT_STARTED
;
436 // Restore interrupt state.
438 SetInterruptState (InterruptStatus
);
441 case DEBUG_AGENT_INIT_DXE_CORE
:
443 mMultiProcessorDebugSupport
= TRUE
;
445 // Initialize Debug Timer hardware
447 InitializeDebugTimer ();
449 // Try to get mailbox from GUIDed HOB build in PEI
452 Mailbox
= GetMailboxFromHob (HobList
);
454 // Set up IDT table and prepare for IDT entries
456 SetupDebugAgentEnviroment (Mailbox
);
458 // Enable interrupt to receive Debug Timer interrupt
464 case DEBUG_AGENT_INIT_S3
:
466 if (Context
!= NULL
) {
467 Ia32Idtr
= (IA32_DESCRIPTOR
*) Context
;
468 Ia32IdtEntry
= (IA32_IDT_ENTRY
*)(Ia32Idtr
->Base
);
469 MailboxLocation
= (UINT64
*) (UINTN
) (Ia32IdtEntry
[DEBUG_MAILBOX_VECTOR
].Bits
.OffsetLow
+
470 (Ia32IdtEntry
[DEBUG_MAILBOX_VECTOR
].Bits
.OffsetHigh
<< 16));
471 Mailbox
= (DEBUG_AGENT_MAILBOX
*)(UINTN
)(*MailboxLocation
);
472 VerifyMailboxChecksum (Mailbox
);
475 // Set up IDT table and prepare for IDT entries
477 SetupDebugAgentEnviroment (Mailbox
);
481 DisableInterrupts ();
482 FindAndReportModuleImageInfo (SIZE_4KB
);
483 if (GetDebugFlag (DEBUG_AGENT_FLAG_BREAK_BOOT_SCRIPT
) == 1) {
485 // If Boot Script entry break is set, code will be break at here.
493 // Only DEBUG_AGENT_INIT_PREMEM_SEC and DEBUG_AGENT_INIT_POSTMEM_SEC are allowed for this
494 // Debug Agent library instance.
496 DEBUG ((EFI_D_ERROR
, "Debug Agent: The InitFlag value is not allowed!\n"));