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
;
58 DEBUG_AGENT_MAILBOX
*Mailbox
;
59 DEBUG_AGENT_MAILBOX
*NewMailbox
;
60 EFI_HOB_GUID_TYPE
*GuidHob
;
61 EFI_VECTOR_HANDOFF_INFO
*VectorHandoffInfo
;
64 // Check persisted vector handoff info
67 GuidHob
= GetFirstGuidHob (&gEfiVectorHandoffInfoPpiGuid
);
68 if (GuidHob
!= NULL
&& !mDxeCoreFlag
) {
70 // Check if configuration table is installed or not if GUIDed HOB existed,
71 // only when Debug Agent is not linked by DXE Core
73 Status
= EfiGetSystemConfigurationTable (&gEfiVectorHandoffTableGuid
, (VOID
**) &VectorHandoffInfo
);
75 if (GuidHob
== NULL
|| Status
!= EFI_SUCCESS
) {
77 // Install configuration table for persisted vector handoff info if GUIDed HOB cannot be found or
78 // configuration table does not exist
80 Status
= gBS
->InstallConfigurationTable (&gEfiVectorHandoffTableGuid
, (VOID
*) &mVectorHandoffInfoDebugAgent
[0]);
81 if (EFI_ERROR (Status
)) {
82 DEBUG ((EFI_D_ERROR
, "DebugAgent: Cannot install configuration table for persisted vector handoff info!\n"));
88 // Install EFI Serial IO protocol on debug port
93 Status
= gBS
->AllocatePages (
96 EFI_SIZE_TO_PAGES (sizeof(DEBUG_AGENT_MAILBOX
) + PcdGet16(PcdDebugPortHandleBufferSize
)),
99 if (EFI_ERROR (Status
)) {
100 DEBUG ((EFI_D_ERROR
, "DebugAgent: Cannot install configuration table for mailbox!\n"));
104 DebugTimerInterruptState
= SaveAndSetDebugTimerInterrupt (FALSE
);
106 NewMailbox
= (DEBUG_AGENT_MAILBOX
*) (UINTN
) Address
;
108 // Copy Mailbox and Debug Port Handle buffer to new location in ACPI NVS memory, because original Mailbox
109 // and Debug Port Handle buffer may be free at runtime, SMM debug agent needs to access them
111 Mailbox
= GetMailboxPointer ();
112 CopyMem (NewMailbox
, Mailbox
, sizeof (DEBUG_AGENT_MAILBOX
));
113 CopyMem (NewMailbox
+ 1, (VOID
*)(UINTN
)Mailbox
->DebugPortHandle
, PcdGet16(PcdDebugPortHandleBufferSize
));
115 // Update Debug Port Handle in new Mailbox
117 UpdateMailboxContent (NewMailbox
, DEBUG_MAILBOX_DEBUG_PORT_HANDLE_INDEX
, (UINT64
)(UINTN
)(NewMailbox
+ 1));
118 mMailboxPointer
= NewMailbox
;
120 DebugTimerInterruptState
= SaveAndSetDebugTimerInterrupt (DebugTimerInterruptState
);
122 Status
= gBS
->InstallConfigurationTable (&gEfiDebugAgentGuid
, (VOID
*) mMailboxPointer
);
123 if (EFI_ERROR (Status
)) {
124 DEBUG ((EFI_D_ERROR
, "DebugAgent: Failed to install configuration for mailbox!\n"));
130 Debug Agent constructor function.
132 @param[in] ImageHandle The firmware allocated handle for the EFI image.
133 @param[in] SystemTable A pointer to the EFI System Table.
135 @retval RETURN_SUCCESS When this function completed.
140 DxeDebugAgentLibConstructor (
141 IN EFI_HANDLE ImageHandle
,
142 IN EFI_SYSTEM_TABLE
*SystemTable
147 // Invoke internal constructor function only when DXE core links this library instance
149 InternalConstructorWorker ();
152 return RETURN_SUCCESS
;
156 Get the pointer to Mailbox from the configuration table.
158 @return Pointer to Mailbox.
161 DEBUG_AGENT_MAILBOX
*
162 GetMailboxFromConfigurationTable (
167 DEBUG_AGENT_MAILBOX
*Mailbox
;
169 Status
= EfiGetSystemConfigurationTable (&gEfiDebugAgentGuid
, (VOID
**) &Mailbox
);
170 if (Status
== EFI_SUCCESS
&& Mailbox
!= NULL
) {
171 VerifyMailboxChecksum (Mailbox
);
179 Get the pointer to Mailbox from the GUIDed HOB.
181 @param[in] HobStart The starting HOB pointer to search from.
183 @return Pointer to Mailbox.
186 DEBUG_AGENT_MAILBOX
*
191 EFI_HOB_GUID_TYPE
*GuidHob
;
192 UINT64
*MailboxLocation
;
193 DEBUG_AGENT_MAILBOX
*Mailbox
;
195 GuidHob
= GetNextGuidHob (&gEfiDebugAgentGuid
, HobStart
);
196 if (GuidHob
== NULL
) {
199 MailboxLocation
= (UINT64
*) (GET_GUID_HOB_DATA(GuidHob
));
200 Mailbox
= (DEBUG_AGENT_MAILBOX
*)(UINTN
)(*MailboxLocation
);
201 VerifyMailboxChecksum (Mailbox
);
207 Get Debug Agent Mailbox pointer.
209 @return Mailbox pointer.
212 DEBUG_AGENT_MAILBOX
*
217 AcquireMpSpinLock (&mDebugMpContext
.MailboxSpinLock
);
218 VerifyMailboxChecksum (mMailboxPointer
);
219 ReleaseMpSpinLock (&mDebugMpContext
.MailboxSpinLock
);
220 return mMailboxPointer
;
224 Get debug port handle.
226 @return Debug port handle.
234 return (DEBUG_PORT_HANDLE
) (UINTN
)(GetMailboxPointer ()->DebugPortHandle
);
238 Worker function to setup IDT table and initialize the IDT entries.
240 @param[in] Mailbox Pointer to Mailbox.
244 SetupDebugAgentEnviroment (
245 IN DEBUG_AGENT_MAILBOX
*Mailbox
248 IA32_DESCRIPTOR Idtr
;
249 UINT16 IdtEntryCount
;
250 UINT64 DebugPortHandle
;
252 if (mMultiProcessorDebugSupport
) {
253 InitializeSpinLock (&mDebugMpContext
.MpContextSpinLock
);
254 InitializeSpinLock (&mDebugMpContext
.DebugPortSpinLock
);
255 InitializeSpinLock (&mDebugMpContext
.MailboxSpinLock
);
257 // Clear Break CPU index value
259 mDebugMpContext
.BreakAtCpuIndex
= (UINT32
) -1;
263 // Get original IDT address and size.
265 AsmReadIdtr ((IA32_DESCRIPTOR
*) &Idtr
);
266 IdtEntryCount
= (UINT16
) ((Idtr
.Limit
+ 1) / sizeof (IA32_IDT_GATE_DESCRIPTOR
));
267 if (IdtEntryCount
< 33) {
268 ZeroMem (&mIdtEntryTable
, sizeof (IA32_IDT_GATE_DESCRIPTOR
) * 33);
270 // Copy original IDT table into new one
272 CopyMem (&mIdtEntryTable
, (VOID
*) Idtr
.Base
, Idtr
.Limit
+ 1);
274 // Load new IDT table
276 Idtr
.Limit
= (UINT16
) (sizeof (IA32_IDT_GATE_DESCRIPTOR
) * 33 - 1);
277 Idtr
.Base
= (UINTN
) &mIdtEntryTable
;
278 AsmWriteIdtr ((IA32_DESCRIPTOR
*) &Idtr
);
282 // Initialize the IDT table entries to support source level debug.
284 InitializeDebugIdt ();
286 if (Mailbox
!= NULL
) {
288 // If Mailbox exists, copy it into one global variable,
290 CopyMem (&mMailbox
, Mailbox
, sizeof (DEBUG_AGENT_MAILBOX
));
292 ZeroMem (&mMailbox
, sizeof (DEBUG_AGENT_MAILBOX
));
295 mMailboxPointer
= &mMailbox
;
297 // Initialize debug communication port
299 DebugPortHandle
= (UINT64
) (UINTN
)DebugPortInitialize ((VOID
*)(UINTN
)mMailboxPointer
->DebugPortHandle
, NULL
);
300 UpdateMailboxContent (mMailboxPointer
, DEBUG_MAILBOX_DEBUG_PORT_HANDLE_INDEX
, DebugPortHandle
);
302 if (Mailbox
== NULL
) {
304 // Trigger one software interrupt to inform HOST
306 TriggerSoftInterrupt (SYSTEM_RESET_SIGNATURE
);
307 SetDebugFlag (DEBUG_AGENT_FLAG_MEMORY_READY
, 1);
309 // Memory has been ready
311 if (IsHostAttached ()) {
313 // Trigger one software interrupt to inform HOST
315 TriggerSoftInterrupt (MEMORY_READY_SIGNATURE
);
322 Initialize debug agent.
324 This function is used to set up debug enviroment for DXE phase.
326 If this function is called by DXE Core, Context must be the pointer
327 to HOB list which will be used to get GUIDed HOB. It will enable
328 interrupt to support break-in feature.
329 If this function is called by DXE module, Context must be NULL. It
330 will enable interrupt to support break-in feature.
332 @param[in] InitFlag Init flag is used to decide initialize process.
333 @param[in] Context Context needed according to InitFlag.
334 @param[in] Function Continue function called by debug agent library; it was
340 InitializeDebugAgent (
342 IN VOID
*Context
, OPTIONAL
343 IN DEBUG_AGENT_CONTINUE Function OPTIONAL
346 UINT64
*MailboxLocation
;
347 DEBUG_AGENT_MAILBOX
*Mailbox
;
348 BOOLEAN InterruptStatus
;
350 IA32_DESCRIPTOR IdtDescriptor
;
351 IA32_DESCRIPTOR
*Ia32Idtr
;
352 IA32_IDT_ENTRY
*Ia32IdtEntry
;
354 if (InitFlag
== DEBUG_AGENT_INIT_DXE_AP
) {
356 // Invoked by AP, enable interrupt to let AP could receive IPI from other processors
363 // Disable Debug Timer interrupt
365 SaveAndSetDebugTimerInterrupt (FALSE
);
367 // Save and disable original interrupt status
369 InterruptStatus
= SaveAndDisableInterrupts ();
372 // Try to get mailbox firstly
376 MailboxLocation
= NULL
;
380 case DEBUG_AGENT_INIT_DXE_LOAD
:
382 // Check if Debug Agent has been initialized before
384 if (IsDebugAgentInitialzed ()) {
385 DEBUG ((EFI_D_INFO
, "Debug Agent: The former agent will be overwritten by the new one!\n"));
388 mMultiProcessorDebugSupport
= TRUE
;
390 // Save original IDT table
392 AsmReadIdtr (&IdtDescriptor
);
393 mSaveIdtTableSize
= IdtDescriptor
.Limit
+ 1;
394 mSavedIdtTable
= AllocateCopyPool (mSaveIdtTableSize
, (VOID
*) IdtDescriptor
.Base
);
396 // Initialize Debug Timer hardware
398 InitializeDebugTimer ();
400 // Check if Debug Agent initialized in DXE phase
402 Mailbox
= GetMailboxFromConfigurationTable ();
403 if (Mailbox
== NULL
) {
405 // Try to get mailbox from GUIDed HOB build in PEI
407 HobList
= GetHobList ();
408 Mailbox
= GetMailboxFromHob (HobList
);
411 // Set up IDT table and prepare for IDT entries
413 SetupDebugAgentEnviroment (Mailbox
);
415 // For DEBUG_AGENT_INIT_S3, needn't to install configuration table and EFI Serial IO protocol
416 // For DEBUG_AGENT_INIT_DXE_CORE, InternalConstructorWorker() will invoked in Constructor()
418 InternalConstructorWorker ();
420 // Enable interrupt to receive Debug Timer interrupt
424 mDebugAgentInitialized
= TRUE
;
425 FindAndReportModuleImageInfo (SIZE_4KB
);
427 *(EFI_STATUS
*)Context
= EFI_SUCCESS
;
429 if (gST
->ConOut
!= NULL
) {
430 Print (L
"Debug Agent: Initialized successfully!\r\n");
431 Print (L
"If the Debug Port is serial port, please make sure this serial port isn't connected by ISA Serial driver\r\n");
432 Print (L
"You could do the following steps to disconnect the serial port:\r\n");
433 Print (L
"1: Shell> drivers\r\n");
435 Print (L
" V VERSION E G G #D #C DRIVER NAME IMAGE NAME\r\n");
436 Print (L
" == ======== = = = == == =================================== ===================\r\n");
437 Print (L
" 8F 0000000A B - - 1 14 PCI Bus Driver PciBusDxe\r\n");
438 Print (L
" 91 00000010 ? - - - - ATA Bus Driver AtaBusDxe\r\n");
440 Print (L
" A7 0000000A B - - 1 1 ISA Serial Driver IsaSerialDxe\r\n");
442 Print (L
"2: Shell> dh -d A7\r\n");
443 Print (L
" A7: Image(IsaSerialDxe) ImageDevPath (..9FB3-11D4-9A3A-0090273FC14D))DriverBinding ComponentName ComponentName2\r\n");
444 Print (L
" Driver Name : ISA Serial Driver\r\n");
445 Print (L
" Image Name : FvFile(93B80003-9FB3-11D4-9A3A-0090273FC14D)\r\n");
446 Print (L
" Driver Version : 0000000A\r\n");
447 Print (L
" Driver Type : BUS\r\n");
448 Print (L
" Configuration : NO\r\n");
449 Print (L
" Diagnostics : NO\r\n");
450 Print (L
" Managing :\r\n");
451 Print (L
" Ctrl[EA] : PciRoot(0x0)/Pci(0x1F,0x0)/Serial(0x0)\r\n");
452 Print (L
" Child[EB] : PciRoot(0x0)/Pci(0x1F,0x0)/Serial(0x0)/Uart(115200,8,N,1)\r\n");
453 Print (L
"3: Shell> disconnect EA\r\n");
454 Print (L
"4: Shell> load -nc DebugAgentDxe.efi\r\n\r\n");
458 case DEBUG_AGENT_INIT_DXE_UNLOAD
:
459 if (mDebugAgentInitialized
) {
460 if (IsHostAttached ()) {
461 Print (L
"Debug Agent: Host is still connected, please de-attach TARGET firstly!\r\n");
462 *(EFI_STATUS
*)Context
= EFI_ACCESS_DENIED
;
464 // Enable Debug Timer interrupt again
466 SaveAndSetDebugTimerInterrupt (TRUE
);
469 // Restore original IDT table
471 AsmReadIdtr (&IdtDescriptor
);
472 IdtDescriptor
.Limit
= (UINT16
) (mSaveIdtTableSize
- 1);
473 CopyMem ((VOID
*) IdtDescriptor
.Base
, mSavedIdtTable
, mSaveIdtTableSize
);
474 AsmWriteIdtr (&IdtDescriptor
);
475 FreePool (mSavedIdtTable
);
476 mDebugAgentInitialized
= FALSE
;
477 *(EFI_STATUS
*)Context
= EFI_SUCCESS
;
480 Print (L
"Debug Agent: It hasn't been initialized, cannot unload it!\r\n");
481 *(EFI_STATUS
*)Context
= EFI_NOT_STARTED
;
485 // Restore interrupt state.
487 SetInterruptState (InterruptStatus
);
490 case DEBUG_AGENT_INIT_DXE_CORE
:
492 mMultiProcessorDebugSupport
= TRUE
;
494 // Initialize Debug Timer hardware
496 InitializeDebugTimer ();
498 // Try to get mailbox from GUIDed HOB build in PEI
501 Mailbox
= GetMailboxFromHob (HobList
);
503 // Set up IDT table and prepare for IDT entries
505 SetupDebugAgentEnviroment (Mailbox
);
507 // Enable interrupt to receive Debug Timer interrupt
513 case DEBUG_AGENT_INIT_S3
:
515 if (Context
!= NULL
) {
516 Ia32Idtr
= (IA32_DESCRIPTOR
*) Context
;
517 Ia32IdtEntry
= (IA32_IDT_ENTRY
*)(Ia32Idtr
->Base
);
518 MailboxLocation
= (UINT64
*) (UINTN
) (Ia32IdtEntry
[DEBUG_MAILBOX_VECTOR
].Bits
.OffsetLow
+
519 (Ia32IdtEntry
[DEBUG_MAILBOX_VECTOR
].Bits
.OffsetHigh
<< 16));
520 Mailbox
= (DEBUG_AGENT_MAILBOX
*)(UINTN
)(*MailboxLocation
);
521 VerifyMailboxChecksum (Mailbox
);
524 // Set up IDT table and prepare for IDT entries
526 SetupDebugAgentEnviroment (Mailbox
);
530 DisableInterrupts ();
531 FindAndReportModuleImageInfo (SIZE_4KB
);
532 if (GetDebugFlag (DEBUG_AGENT_FLAG_BREAK_BOOT_SCRIPT
) == 1) {
534 // If Boot Script entry break is set, code will be break at here.
542 // Only DEBUG_AGENT_INIT_PREMEM_SEC and DEBUG_AGENT_INIT_POSTMEM_SEC are allowed for this
543 // Debug Agent library instance.
545 DEBUG ((EFI_D_ERROR
, "Debug Agent: The InitFlag value is not allowed!\n"));