diff options
Diffstat (limited to 'SourceLevelDebugPkg/Library/DebugAgent/DxeDebugAgent/DxeDebugAgentLib.c')
| -rw-r--r-- | SourceLevelDebugPkg/Library/DebugAgent/DxeDebugAgent/DxeDebugAgentLib.c | 1098 |
1 files changed, 549 insertions, 549 deletions
diff --git a/SourceLevelDebugPkg/Library/DebugAgent/DxeDebugAgent/DxeDebugAgentLib.c b/SourceLevelDebugPkg/Library/DebugAgent/DxeDebugAgent/DxeDebugAgentLib.c index a41bba2c4b..7bea778378 100644 --- a/SourceLevelDebugPkg/Library/DebugAgent/DxeDebugAgent/DxeDebugAgentLib.c +++ b/SourceLevelDebugPkg/Library/DebugAgent/DxeDebugAgent/DxeDebugAgentLib.c @@ -1,549 +1,549 @@ -/** @file
- Debug Agent library implementation for Dxe Core and Dxr modules.
-
- Copyright (c) 2010 - 2018, Intel Corporation. All rights reserved.<BR>
- SPDX-License-Identifier: BSD-2-Clause-Patent
-
-**/
-
-#include "DxeDebugAgentLib.h"
-
-DEBUG_AGENT_MAILBOX mMailbox;
-DEBUG_AGENT_MAILBOX *mMailboxPointer = NULL;
-IA32_IDT_GATE_DESCRIPTOR mIdtEntryTable[33];
-BOOLEAN mDxeCoreFlag = FALSE;
-BOOLEAN mMultiProcessorDebugSupport = FALSE;
-VOID *mSavedIdtTable = NULL;
-UINTN mSaveIdtTableSize = 0;
-BOOLEAN mDebugAgentInitialized = FALSE;
-BOOLEAN mSkipBreakpoint = FALSE;
-
-/**
- Check if debug agent support multi-processor.
-
- @retval TRUE Multi-processor is supported.
- @retval FALSE Multi-processor is not supported.
-
-**/
-BOOLEAN
-MultiProcessorDebugSupport (
- VOID
- )
-{
- return mMultiProcessorDebugSupport;
-}
-
-/**
- Internal constructor worker function.
-
- It will register one callback function on EFI PCD Protocol.
- It will allocate the NVS memory to store Mailbox and install configuration table
- in system table to store its pointer.
-
-**/
-VOID
-InternalConstructorWorker (
- VOID
- )
-{
- EFI_STATUS Status;
- EFI_PHYSICAL_ADDRESS Address;
- BOOLEAN DebugTimerInterruptState;
- DEBUG_AGENT_MAILBOX *Mailbox;
- DEBUG_AGENT_MAILBOX *NewMailbox;
- EFI_HOB_GUID_TYPE *GuidHob;
- EFI_VECTOR_HANDOFF_INFO *VectorHandoffInfo;
-
- //
- // Check persisted vector handoff info
- //
- Status = EFI_SUCCESS;
- GuidHob = GetFirstGuidHob (&gEfiVectorHandoffInfoPpiGuid);
- if ((GuidHob != NULL) && !mDxeCoreFlag) {
- //
- // Check if configuration table is installed or not if GUIDed HOB existed,
- // only when Debug Agent is not linked by DXE Core
- //
- Status = EfiGetSystemConfigurationTable (&gEfiVectorHandoffTableGuid, (VOID **)&VectorHandoffInfo);
- }
-
- if ((GuidHob == NULL) || (Status != EFI_SUCCESS)) {
- //
- // Install configuration table for persisted vector handoff info if GUIDed HOB cannot be found or
- // configuration table does not exist
- //
- Status = gBS->InstallConfigurationTable (&gEfiVectorHandoffTableGuid, (VOID *)&mVectorHandoffInfoDebugAgent[0]);
- if (EFI_ERROR (Status)) {
- DEBUG ((DEBUG_ERROR, "DebugAgent: Cannot install configuration table for persisted vector handoff info!\n"));
- CpuDeadLoop ();
- }
- }
-
- //
- // Install EFI Serial IO protocol on debug port
- //
- InstallSerialIo ();
-
- Address = 0;
- Status = gBS->AllocatePages (
- AllocateAnyPages,
- EfiACPIMemoryNVS,
- EFI_SIZE_TO_PAGES (sizeof (DEBUG_AGENT_MAILBOX) + PcdGet16 (PcdDebugPortHandleBufferSize)),
- &Address
- );
- if (EFI_ERROR (Status)) {
- DEBUG ((DEBUG_ERROR, "DebugAgent: Cannot install configuration table for mailbox!\n"));
- CpuDeadLoop ();
- }
-
- DebugTimerInterruptState = SaveAndSetDebugTimerInterrupt (FALSE);
-
- NewMailbox = (DEBUG_AGENT_MAILBOX *)(UINTN)Address;
- //
- // Copy Mailbox and Debug Port Handle buffer to new location in ACPI NVS memory, because original Mailbox
- // and Debug Port Handle buffer may be free at runtime, SMM debug agent needs to access them
- //
- Mailbox = GetMailboxPointer ();
- CopyMem (NewMailbox, Mailbox, sizeof (DEBUG_AGENT_MAILBOX));
- CopyMem (NewMailbox + 1, (VOID *)(UINTN)Mailbox->DebugPortHandle, PcdGet16 (PcdDebugPortHandleBufferSize));
- //
- // Update Debug Port Handle in new Mailbox
- //
- UpdateMailboxContent (NewMailbox, DEBUG_MAILBOX_DEBUG_PORT_HANDLE_INDEX, (UINT64)(UINTN)(NewMailbox + 1));
- mMailboxPointer = NewMailbox;
-
- DebugTimerInterruptState = SaveAndSetDebugTimerInterrupt (DebugTimerInterruptState);
-
- Status = gBS->InstallConfigurationTable (&gEfiDebugAgentGuid, (VOID *)mMailboxPointer);
- if (EFI_ERROR (Status)) {
- DEBUG ((DEBUG_ERROR, "DebugAgent: Failed to install configuration for mailbox!\n"));
- CpuDeadLoop ();
- }
-}
-
-/**
- Debug Agent constructor function.
-
- @param[in] ImageHandle The firmware allocated handle for the EFI image.
- @param[in] SystemTable A pointer to the EFI System Table.
-
- @retval RETURN_SUCCESS When this function completed.
-
-**/
-RETURN_STATUS
-EFIAPI
-DxeDebugAgentLibConstructor (
- IN EFI_HANDLE ImageHandle,
- IN EFI_SYSTEM_TABLE *SystemTable
- )
-{
- if (mDxeCoreFlag) {
- //
- // Invoke internal constructor function only when DXE core links this library instance
- //
- InternalConstructorWorker ();
- }
-
- return RETURN_SUCCESS;
-}
-
-/**
- Get the pointer to Mailbox from the configuration table.
-
- @return Pointer to Mailbox.
-
-**/
-DEBUG_AGENT_MAILBOX *
-GetMailboxFromConfigurationTable (
- VOID
- )
-{
- EFI_STATUS Status;
- DEBUG_AGENT_MAILBOX *Mailbox;
-
- Status = EfiGetSystemConfigurationTable (&gEfiDebugAgentGuid, (VOID **)&Mailbox);
- if ((Status == EFI_SUCCESS) && (Mailbox != NULL)) {
- VerifyMailboxChecksum (Mailbox);
- return Mailbox;
- } else {
- return NULL;
- }
-}
-
-/**
- Get the pointer to Mailbox from the GUIDed HOB.
-
- @param[in] HobStart The starting HOB pointer to search from.
-
- @return Pointer to Mailbox.
-
-**/
-DEBUG_AGENT_MAILBOX *
-GetMailboxFromHob (
- IN VOID *HobStart
- )
-{
- EFI_HOB_GUID_TYPE *GuidHob;
- UINT64 *MailboxLocation;
- DEBUG_AGENT_MAILBOX *Mailbox;
-
- GuidHob = GetNextGuidHob (&gEfiDebugAgentGuid, HobStart);
- if (GuidHob == NULL) {
- return NULL;
- }
-
- MailboxLocation = (UINT64 *)(GET_GUID_HOB_DATA (GuidHob));
- Mailbox = (DEBUG_AGENT_MAILBOX *)(UINTN)(*MailboxLocation);
- VerifyMailboxChecksum (Mailbox);
-
- return Mailbox;
-}
-
-/**
- Get Debug Agent Mailbox pointer.
-
- @return Mailbox pointer.
-
-**/
-DEBUG_AGENT_MAILBOX *
-GetMailboxPointer (
- VOID
- )
-{
- AcquireMpSpinLock (&mDebugMpContext.MailboxSpinLock);
- VerifyMailboxChecksum (mMailboxPointer);
- ReleaseMpSpinLock (&mDebugMpContext.MailboxSpinLock);
- return mMailboxPointer;
-}
-
-/**
- Get debug port handle.
-
- @return Debug port handle.
-
-**/
-DEBUG_PORT_HANDLE
-GetDebugPortHandle (
- VOID
- )
-{
- return (DEBUG_PORT_HANDLE)(UINTN)(GetMailboxPointer ()->DebugPortHandle);
-}
-
-/**
- Worker function to set up Debug Agent environment.
-
- This function will set up IDT table and initialize the IDT entries and
- initialize CPU LOCAL APIC timer.
- It also tries to connect HOST if Debug Agent was not initialized before.
-
- @param[in] Mailbox Pointer to Mailbox.
-
-**/
-VOID
-SetupDebugAgentEnvironment (
- IN DEBUG_AGENT_MAILBOX *Mailbox
- )
-{
- IA32_DESCRIPTOR Idtr;
- UINT16 IdtEntryCount;
- UINT64 DebugPortHandle;
- UINT32 DebugTimerFrequency;
-
- if (mMultiProcessorDebugSupport) {
- InitializeSpinLock (&mDebugMpContext.MpContextSpinLock);
- InitializeSpinLock (&mDebugMpContext.DebugPortSpinLock);
- InitializeSpinLock (&mDebugMpContext.MailboxSpinLock);
- //
- // Clear Break CPU index value
- //
- mDebugMpContext.BreakAtCpuIndex = (UINT32)-1;
- }
-
- //
- // Get original IDT address and size.
- //
- AsmReadIdtr ((IA32_DESCRIPTOR *)&Idtr);
- IdtEntryCount = (UINT16)((Idtr.Limit + 1) / sizeof (IA32_IDT_GATE_DESCRIPTOR));
- if (IdtEntryCount < 33) {
- ZeroMem (&mIdtEntryTable, sizeof (IA32_IDT_GATE_DESCRIPTOR) * 33);
- //
- // Copy original IDT table into new one
- //
- CopyMem (&mIdtEntryTable, (VOID *)Idtr.Base, Idtr.Limit + 1);
- //
- // Load new IDT table
- //
- Idtr.Limit = (UINT16)(sizeof (IA32_IDT_GATE_DESCRIPTOR) * 33 - 1);
- Idtr.Base = (UINTN)&mIdtEntryTable;
- AsmWriteIdtr ((IA32_DESCRIPTOR *)&Idtr);
- }
-
- //
- // Initialize the IDT table entries to support source level debug.
- //
- InitializeDebugIdt ();
-
- //
- // If mMailboxPointer is not set before, set it
- //
- if (mMailboxPointer == NULL) {
- if (Mailbox != NULL) {
- //
- // If Mailbox exists, copy it into one global variable
- //
- CopyMem (&mMailbox, Mailbox, sizeof (DEBUG_AGENT_MAILBOX));
- } else {
- ZeroMem (&mMailbox, sizeof (DEBUG_AGENT_MAILBOX));
- }
-
- mMailboxPointer = &mMailbox;
- }
-
- //
- // Initialize Debug Timer hardware and save its initial count and frequency
- //
- mDebugMpContext.DebugTimerInitCount = InitializeDebugTimer (&DebugTimerFrequency, TRUE);
- UpdateMailboxContent (mMailboxPointer, DEBUG_MAILBOX_DEBUG_TIMER_FREQUENCY, DebugTimerFrequency);
- //
- // Initialize debug communication port
- //
- DebugPortHandle = (UINT64)(UINTN)DebugPortInitialize ((VOID *)(UINTN)mMailboxPointer->DebugPortHandle, NULL);
- UpdateMailboxContent (mMailboxPointer, DEBUG_MAILBOX_DEBUG_PORT_HANDLE_INDEX, DebugPortHandle);
-
- if (Mailbox == NULL) {
- //
- // Trigger one software interrupt to inform HOST
- //
- TriggerSoftInterrupt (SYSTEM_RESET_SIGNATURE);
- SetDebugFlag (DEBUG_AGENT_FLAG_MEMORY_READY, 1);
- //
- // Memory has been ready
- //
- if (IsHostAttached ()) {
- //
- // Trigger one software interrupt to inform HOST
- //
- TriggerSoftInterrupt (MEMORY_READY_SIGNATURE);
- }
- }
-}
-
-/**
- Initialize debug agent.
-
- This function is used to set up debug environment for DXE phase.
-
- If this function is called by DXE Core, Context must be the pointer
- to HOB list which will be used to get GUIDed HOB. It will enable
- interrupt to support break-in feature.
- If this function is called by DXE module, Context must be NULL. It
- will enable interrupt to support break-in feature.
-
- @param[in] InitFlag Init flag is used to decide initialize process.
- @param[in] Context Context needed according to InitFlag.
- @param[in] Function Continue function called by debug agent library; it was
- optional.
-
-**/
-VOID
-EFIAPI
-InitializeDebugAgent (
- IN UINT32 InitFlag,
- IN VOID *Context OPTIONAL,
- IN DEBUG_AGENT_CONTINUE Function OPTIONAL
- )
-{
- UINT64 *MailboxLocation;
- DEBUG_AGENT_MAILBOX *Mailbox;
- BOOLEAN InterruptStatus;
- VOID *HobList;
- IA32_DESCRIPTOR IdtDescriptor;
- IA32_DESCRIPTOR *Ia32Idtr;
- IA32_IDT_ENTRY *Ia32IdtEntry;
- BOOLEAN PeriodicMode;
- UINTN TimerCycle;
-
- if (InitFlag == DEBUG_AGENT_INIT_DXE_AP) {
- //
- // Check if CPU APIC Timer is working, otherwise initialize it.
- //
- InitializeLocalApicSoftwareEnable (TRUE);
- GetApicTimerState (NULL, &PeriodicMode, NULL);
- TimerCycle = GetApicTimerInitCount ();
- if (!PeriodicMode || (TimerCycle == 0)) {
- InitializeDebugTimer (NULL, FALSE);
- }
-
- //
- // Invoked by AP, enable interrupt to let AP could receive IPI from other processors
- //
- EnableInterrupts ();
- return;
- }
-
- //
- // Disable Debug Timer interrupt
- //
- SaveAndSetDebugTimerInterrupt (FALSE);
- //
- // Save and disable original interrupt status
- //
- InterruptStatus = SaveAndDisableInterrupts ();
-
- //
- // Try to get mailbox firstly
- //
- HobList = NULL;
- Mailbox = NULL;
- MailboxLocation = NULL;
-
- switch (InitFlag) {
- case DEBUG_AGENT_INIT_DXE_LOAD:
- //
- // Check if Debug Agent has been initialized before
- //
- if (IsDebugAgentInitialzed ()) {
- DEBUG ((DEBUG_INFO, "Debug Agent: The former agent will be overwritten by the new one!\n"));
- }
-
- mMultiProcessorDebugSupport = TRUE;
- //
- // Save original IDT table
- //
- AsmReadIdtr (&IdtDescriptor);
- mSaveIdtTableSize = IdtDescriptor.Limit + 1;
- mSavedIdtTable = AllocateCopyPool (mSaveIdtTableSize, (VOID *)IdtDescriptor.Base);
- //
- // Check if Debug Agent initialized in DXE phase
- //
- Mailbox = GetMailboxFromConfigurationTable ();
- if (Mailbox == NULL) {
- //
- // Try to get mailbox from GUIDed HOB build in PEI
- //
- HobList = GetHobList ();
- Mailbox = GetMailboxFromHob (HobList);
- }
-
- //
- // Set up Debug Agent Environment and try to connect HOST if required
- //
- SetupDebugAgentEnvironment (Mailbox);
- //
- // For DEBUG_AGENT_INIT_S3, needn't to install configuration table and EFI Serial IO protocol
- // For DEBUG_AGENT_INIT_DXE_CORE, InternalConstructorWorker() will invoked in Constructor()
- //
- InternalConstructorWorker ();
- //
- // Enable Debug Timer interrupt
- //
- SaveAndSetDebugTimerInterrupt (TRUE);
- //
- // Enable interrupt to receive Debug Timer interrupt
- //
- EnableInterrupts ();
-
- mDebugAgentInitialized = TRUE;
- FindAndReportModuleImageInfo (SIZE_4KB);
-
- *(EFI_STATUS *)Context = EFI_SUCCESS;
-
- break;
-
- case DEBUG_AGENT_INIT_DXE_UNLOAD:
- if (mDebugAgentInitialized) {
- if (IsHostAttached ()) {
- *(EFI_STATUS *)Context = EFI_ACCESS_DENIED;
- //
- // Enable Debug Timer interrupt again
- //
- SaveAndSetDebugTimerInterrupt (TRUE);
- } else {
- //
- // Restore original IDT table
- //
- AsmReadIdtr (&IdtDescriptor);
- IdtDescriptor.Limit = (UINT16)(mSaveIdtTableSize - 1);
- CopyMem ((VOID *)IdtDescriptor.Base, mSavedIdtTable, mSaveIdtTableSize);
- AsmWriteIdtr (&IdtDescriptor);
- FreePool (mSavedIdtTable);
- mDebugAgentInitialized = FALSE;
- *(EFI_STATUS *)Context = EFI_SUCCESS;
- }
- } else {
- *(EFI_STATUS *)Context = EFI_NOT_STARTED;
- }
-
- //
- // Restore interrupt state.
- //
- SetInterruptState (InterruptStatus);
- break;
-
- case DEBUG_AGENT_INIT_DXE_CORE:
- mDxeCoreFlag = TRUE;
- mMultiProcessorDebugSupport = TRUE;
- //
- // Try to get mailbox from GUIDed HOB build in PEI
- //
- HobList = Context;
- Mailbox = GetMailboxFromHob (HobList);
- //
- // Set up Debug Agent Environment and try to connect HOST if required
- //
- SetupDebugAgentEnvironment (Mailbox);
- //
- // Enable Debug Timer interrupt
- //
- SaveAndSetDebugTimerInterrupt (TRUE);
- //
- // Enable interrupt to receive Debug Timer interrupt
- //
- EnableInterrupts ();
-
- break;
-
- case DEBUG_AGENT_INIT_S3:
-
- if (Context != NULL) {
- Ia32Idtr = (IA32_DESCRIPTOR *)Context;
- Ia32IdtEntry = (IA32_IDT_ENTRY *)(Ia32Idtr->Base);
- MailboxLocation = (UINT64 *)((UINTN)Ia32IdtEntry[DEBUG_MAILBOX_VECTOR].Bits.OffsetLow +
- ((UINTN)Ia32IdtEntry[DEBUG_MAILBOX_VECTOR].Bits.OffsetHigh << 16));
- Mailbox = (DEBUG_AGENT_MAILBOX *)(UINTN)(*MailboxLocation);
- VerifyMailboxChecksum (Mailbox);
- }
-
- //
- // Save Mailbox pointer in global variable
- //
- mMailboxPointer = Mailbox;
- //
- // Set up Debug Agent Environment and try to connect HOST if required
- //
- SetupDebugAgentEnvironment (Mailbox);
- //
- // Disable interrupt
- //
- DisableInterrupts ();
- FindAndReportModuleImageInfo (SIZE_4KB);
- if (GetDebugFlag (DEBUG_AGENT_FLAG_BREAK_BOOT_SCRIPT) == 1) {
- //
- // If Boot Script entry break is set, code will be break at here.
- //
- CpuBreakpoint ();
- }
-
- break;
-
- default:
- //
- // Only DEBUG_AGENT_INIT_PREMEM_SEC and DEBUG_AGENT_INIT_POSTMEM_SEC are allowed for this
- // Debug Agent library instance.
- //
- DEBUG ((DEBUG_ERROR, "Debug Agent: The InitFlag value is not allowed!\n"));
- CpuDeadLoop ();
- break;
- }
-}
+/** @file + Debug Agent library implementation for Dxe Core and Dxr modules. + + Copyright (c) 2010 - 2018, Intel Corporation. All rights reserved.<BR> + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "DxeDebugAgentLib.h" + +DEBUG_AGENT_MAILBOX mMailbox; +DEBUG_AGENT_MAILBOX *mMailboxPointer = NULL; +IA32_IDT_GATE_DESCRIPTOR mIdtEntryTable[33]; +BOOLEAN mDxeCoreFlag = FALSE; +BOOLEAN mMultiProcessorDebugSupport = FALSE; +VOID *mSavedIdtTable = NULL; +UINTN mSaveIdtTableSize = 0; +BOOLEAN mDebugAgentInitialized = FALSE; +BOOLEAN mSkipBreakpoint = FALSE; + +/** + Check if debug agent support multi-processor. + + @retval TRUE Multi-processor is supported. + @retval FALSE Multi-processor is not supported. + +**/ +BOOLEAN +MultiProcessorDebugSupport ( + VOID + ) +{ + return mMultiProcessorDebugSupport; +} + +/** + Internal constructor worker function. + + It will register one callback function on EFI PCD Protocol. + It will allocate the NVS memory to store Mailbox and install configuration table + in system table to store its pointer. + +**/ +VOID +InternalConstructorWorker ( + VOID + ) +{ + EFI_STATUS Status; + EFI_PHYSICAL_ADDRESS Address; + BOOLEAN DebugTimerInterruptState; + DEBUG_AGENT_MAILBOX *Mailbox; + DEBUG_AGENT_MAILBOX *NewMailbox; + EFI_HOB_GUID_TYPE *GuidHob; + EFI_VECTOR_HANDOFF_INFO *VectorHandoffInfo; + + // + // Check persisted vector handoff info + // + Status = EFI_SUCCESS; + GuidHob = GetFirstGuidHob (&gEfiVectorHandoffInfoPpiGuid); + if ((GuidHob != NULL) && !mDxeCoreFlag) { + // + // Check if configuration table is installed or not if GUIDed HOB existed, + // only when Debug Agent is not linked by DXE Core + // + Status = EfiGetSystemConfigurationTable (&gEfiVectorHandoffTableGuid, (VOID **)&VectorHandoffInfo); + } + + if ((GuidHob == NULL) || (Status != EFI_SUCCESS)) { + // + // Install configuration table for persisted vector handoff info if GUIDed HOB cannot be found or + // configuration table does not exist + // + Status = gBS->InstallConfigurationTable (&gEfiVectorHandoffTableGuid, (VOID *)&mVectorHandoffInfoDebugAgent[0]); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "DebugAgent: Cannot install configuration table for persisted vector handoff info!\n")); + CpuDeadLoop (); + } + } + + // + // Install EFI Serial IO protocol on debug port + // + InstallSerialIo (); + + Address = 0; + Status = gBS->AllocatePages ( + AllocateAnyPages, + EfiACPIMemoryNVS, + EFI_SIZE_TO_PAGES (sizeof (DEBUG_AGENT_MAILBOX) + PcdGet16 (PcdDebugPortHandleBufferSize)), + &Address + ); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "DebugAgent: Cannot install configuration table for mailbox!\n")); + CpuDeadLoop (); + } + + DebugTimerInterruptState = SaveAndSetDebugTimerInterrupt (FALSE); + + NewMailbox = (DEBUG_AGENT_MAILBOX *)(UINTN)Address; + // + // Copy Mailbox and Debug Port Handle buffer to new location in ACPI NVS memory, because original Mailbox + // and Debug Port Handle buffer may be free at runtime, SMM debug agent needs to access them + // + Mailbox = GetMailboxPointer (); + CopyMem (NewMailbox, Mailbox, sizeof (DEBUG_AGENT_MAILBOX)); + CopyMem (NewMailbox + 1, (VOID *)(UINTN)Mailbox->DebugPortHandle, PcdGet16 (PcdDebugPortHandleBufferSize)); + // + // Update Debug Port Handle in new Mailbox + // + UpdateMailboxContent (NewMailbox, DEBUG_MAILBOX_DEBUG_PORT_HANDLE_INDEX, (UINT64)(UINTN)(NewMailbox + 1)); + mMailboxPointer = NewMailbox; + + DebugTimerInterruptState = SaveAndSetDebugTimerInterrupt (DebugTimerInterruptState); + + Status = gBS->InstallConfigurationTable (&gEfiDebugAgentGuid, (VOID *)mMailboxPointer); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "DebugAgent: Failed to install configuration for mailbox!\n")); + CpuDeadLoop (); + } +} + +/** + Debug Agent constructor function. + + @param[in] ImageHandle The firmware allocated handle for the EFI image. + @param[in] SystemTable A pointer to the EFI System Table. + + @retval RETURN_SUCCESS When this function completed. + +**/ +RETURN_STATUS +EFIAPI +DxeDebugAgentLibConstructor ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + if (mDxeCoreFlag) { + // + // Invoke internal constructor function only when DXE core links this library instance + // + InternalConstructorWorker (); + } + + return RETURN_SUCCESS; +} + +/** + Get the pointer to Mailbox from the configuration table. + + @return Pointer to Mailbox. + +**/ +DEBUG_AGENT_MAILBOX * +GetMailboxFromConfigurationTable ( + VOID + ) +{ + EFI_STATUS Status; + DEBUG_AGENT_MAILBOX *Mailbox; + + Status = EfiGetSystemConfigurationTable (&gEfiDebugAgentGuid, (VOID **)&Mailbox); + if ((Status == EFI_SUCCESS) && (Mailbox != NULL)) { + VerifyMailboxChecksum (Mailbox); + return Mailbox; + } else { + return NULL; + } +} + +/** + Get the pointer to Mailbox from the GUIDed HOB. + + @param[in] HobStart The starting HOB pointer to search from. + + @return Pointer to Mailbox. + +**/ +DEBUG_AGENT_MAILBOX * +GetMailboxFromHob ( + IN VOID *HobStart + ) +{ + EFI_HOB_GUID_TYPE *GuidHob; + UINT64 *MailboxLocation; + DEBUG_AGENT_MAILBOX *Mailbox; + + GuidHob = GetNextGuidHob (&gEfiDebugAgentGuid, HobStart); + if (GuidHob == NULL) { + return NULL; + } + + MailboxLocation = (UINT64 *)(GET_GUID_HOB_DATA (GuidHob)); + Mailbox = (DEBUG_AGENT_MAILBOX *)(UINTN)(*MailboxLocation); + VerifyMailboxChecksum (Mailbox); + + return Mailbox; +} + +/** + Get Debug Agent Mailbox pointer. + + @return Mailbox pointer. + +**/ +DEBUG_AGENT_MAILBOX * +GetMailboxPointer ( + VOID + ) +{ + AcquireMpSpinLock (&mDebugMpContext.MailboxSpinLock); + VerifyMailboxChecksum (mMailboxPointer); + ReleaseMpSpinLock (&mDebugMpContext.MailboxSpinLock); + return mMailboxPointer; +} + +/** + Get debug port handle. + + @return Debug port handle. + +**/ +DEBUG_PORT_HANDLE +GetDebugPortHandle ( + VOID + ) +{ + return (DEBUG_PORT_HANDLE)(UINTN)(GetMailboxPointer ()->DebugPortHandle); +} + +/** + Worker function to set up Debug Agent environment. + + This function will set up IDT table and initialize the IDT entries and + initialize CPU LOCAL APIC timer. + It also tries to connect HOST if Debug Agent was not initialized before. + + @param[in] Mailbox Pointer to Mailbox. + +**/ +VOID +SetupDebugAgentEnvironment ( + IN DEBUG_AGENT_MAILBOX *Mailbox + ) +{ + IA32_DESCRIPTOR Idtr; + UINT16 IdtEntryCount; + UINT64 DebugPortHandle; + UINT32 DebugTimerFrequency; + + if (mMultiProcessorDebugSupport) { + InitializeSpinLock (&mDebugMpContext.MpContextSpinLock); + InitializeSpinLock (&mDebugMpContext.DebugPortSpinLock); + InitializeSpinLock (&mDebugMpContext.MailboxSpinLock); + // + // Clear Break CPU index value + // + mDebugMpContext.BreakAtCpuIndex = (UINT32)-1; + } + + // + // Get original IDT address and size. + // + AsmReadIdtr ((IA32_DESCRIPTOR *)&Idtr); + IdtEntryCount = (UINT16)((Idtr.Limit + 1) / sizeof (IA32_IDT_GATE_DESCRIPTOR)); + if (IdtEntryCount < 33) { + ZeroMem (&mIdtEntryTable, sizeof (IA32_IDT_GATE_DESCRIPTOR) * 33); + // + // Copy original IDT table into new one + // + CopyMem (&mIdtEntryTable, (VOID *)Idtr.Base, Idtr.Limit + 1); + // + // Load new IDT table + // + Idtr.Limit = (UINT16)(sizeof (IA32_IDT_GATE_DESCRIPTOR) * 33 - 1); + Idtr.Base = (UINTN)&mIdtEntryTable; + AsmWriteIdtr ((IA32_DESCRIPTOR *)&Idtr); + } + + // + // Initialize the IDT table entries to support source level debug. + // + InitializeDebugIdt (); + + // + // If mMailboxPointer is not set before, set it + // + if (mMailboxPointer == NULL) { + if (Mailbox != NULL) { + // + // If Mailbox exists, copy it into one global variable + // + CopyMem (&mMailbox, Mailbox, sizeof (DEBUG_AGENT_MAILBOX)); + } else { + ZeroMem (&mMailbox, sizeof (DEBUG_AGENT_MAILBOX)); + } + + mMailboxPointer = &mMailbox; + } + + // + // Initialize Debug Timer hardware and save its initial count and frequency + // + mDebugMpContext.DebugTimerInitCount = InitializeDebugTimer (&DebugTimerFrequency, TRUE); + UpdateMailboxContent (mMailboxPointer, DEBUG_MAILBOX_DEBUG_TIMER_FREQUENCY, DebugTimerFrequency); + // + // Initialize debug communication port + // + DebugPortHandle = (UINT64)(UINTN)DebugPortInitialize ((VOID *)(UINTN)mMailboxPointer->DebugPortHandle, NULL); + UpdateMailboxContent (mMailboxPointer, DEBUG_MAILBOX_DEBUG_PORT_HANDLE_INDEX, DebugPortHandle); + + if (Mailbox == NULL) { + // + // Trigger one software interrupt to inform HOST + // + TriggerSoftInterrupt (SYSTEM_RESET_SIGNATURE); + SetDebugFlag (DEBUG_AGENT_FLAG_MEMORY_READY, 1); + // + // Memory has been ready + // + if (IsHostAttached ()) { + // + // Trigger one software interrupt to inform HOST + // + TriggerSoftInterrupt (MEMORY_READY_SIGNATURE); + } + } +} + +/** + Initialize debug agent. + + This function is used to set up debug environment for DXE phase. + + If this function is called by DXE Core, Context must be the pointer + to HOB list which will be used to get GUIDed HOB. It will enable + interrupt to support break-in feature. + If this function is called by DXE module, Context must be NULL. It + will enable interrupt to support break-in feature. + + @param[in] InitFlag Init flag is used to decide initialize process. + @param[in] Context Context needed according to InitFlag. + @param[in] Function Continue function called by debug agent library; it was + optional. + +**/ +VOID +EFIAPI +InitializeDebugAgent ( + IN UINT32 InitFlag, + IN VOID *Context OPTIONAL, + IN DEBUG_AGENT_CONTINUE Function OPTIONAL + ) +{ + UINT64 *MailboxLocation; + DEBUG_AGENT_MAILBOX *Mailbox; + BOOLEAN InterruptStatus; + VOID *HobList; + IA32_DESCRIPTOR IdtDescriptor; + IA32_DESCRIPTOR *Ia32Idtr; + IA32_IDT_ENTRY *Ia32IdtEntry; + BOOLEAN PeriodicMode; + UINTN TimerCycle; + + if (InitFlag == DEBUG_AGENT_INIT_DXE_AP) { + // + // Check if CPU APIC Timer is working, otherwise initialize it. + // + InitializeLocalApicSoftwareEnable (TRUE); + GetApicTimerState (NULL, &PeriodicMode, NULL); + TimerCycle = GetApicTimerInitCount (); + if (!PeriodicMode || (TimerCycle == 0)) { + InitializeDebugTimer (NULL, FALSE); + } + + // + // Invoked by AP, enable interrupt to let AP could receive IPI from other processors + // + EnableInterrupts (); + return; + } + + // + // Disable Debug Timer interrupt + // + SaveAndSetDebugTimerInterrupt (FALSE); + // + // Save and disable original interrupt status + // + InterruptStatus = SaveAndDisableInterrupts (); + + // + // Try to get mailbox firstly + // + HobList = NULL; + Mailbox = NULL; + MailboxLocation = NULL; + + switch (InitFlag) { + case DEBUG_AGENT_INIT_DXE_LOAD: + // + // Check if Debug Agent has been initialized before + // + if (IsDebugAgentInitialzed ()) { + DEBUG ((DEBUG_INFO, "Debug Agent: The former agent will be overwritten by the new one!\n")); + } + + mMultiProcessorDebugSupport = TRUE; + // + // Save original IDT table + // + AsmReadIdtr (&IdtDescriptor); + mSaveIdtTableSize = IdtDescriptor.Limit + 1; + mSavedIdtTable = AllocateCopyPool (mSaveIdtTableSize, (VOID *)IdtDescriptor.Base); + // + // Check if Debug Agent initialized in DXE phase + // + Mailbox = GetMailboxFromConfigurationTable (); + if (Mailbox == NULL) { + // + // Try to get mailbox from GUIDed HOB build in PEI + // + HobList = GetHobList (); + Mailbox = GetMailboxFromHob (HobList); + } + + // + // Set up Debug Agent Environment and try to connect HOST if required + // + SetupDebugAgentEnvironment (Mailbox); + // + // For DEBUG_AGENT_INIT_S3, needn't to install configuration table and EFI Serial IO protocol + // For DEBUG_AGENT_INIT_DXE_CORE, InternalConstructorWorker() will invoked in Constructor() + // + InternalConstructorWorker (); + // + // Enable Debug Timer interrupt + // + SaveAndSetDebugTimerInterrupt (TRUE); + // + // Enable interrupt to receive Debug Timer interrupt + // + EnableInterrupts (); + + mDebugAgentInitialized = TRUE; + FindAndReportModuleImageInfo (SIZE_4KB); + + *(EFI_STATUS *)Context = EFI_SUCCESS; + + break; + + case DEBUG_AGENT_INIT_DXE_UNLOAD: + if (mDebugAgentInitialized) { + if (IsHostAttached ()) { + *(EFI_STATUS *)Context = EFI_ACCESS_DENIED; + // + // Enable Debug Timer interrupt again + // + SaveAndSetDebugTimerInterrupt (TRUE); + } else { + // + // Restore original IDT table + // + AsmReadIdtr (&IdtDescriptor); + IdtDescriptor.Limit = (UINT16)(mSaveIdtTableSize - 1); + CopyMem ((VOID *)IdtDescriptor.Base, mSavedIdtTable, mSaveIdtTableSize); + AsmWriteIdtr (&IdtDescriptor); + FreePool (mSavedIdtTable); + mDebugAgentInitialized = FALSE; + *(EFI_STATUS *)Context = EFI_SUCCESS; + } + } else { + *(EFI_STATUS *)Context = EFI_NOT_STARTED; + } + + // + // Restore interrupt state. + // + SetInterruptState (InterruptStatus); + break; + + case DEBUG_AGENT_INIT_DXE_CORE: + mDxeCoreFlag = TRUE; + mMultiProcessorDebugSupport = TRUE; + // + // Try to get mailbox from GUIDed HOB build in PEI + // + HobList = Context; + Mailbox = GetMailboxFromHob (HobList); + // + // Set up Debug Agent Environment and try to connect HOST if required + // + SetupDebugAgentEnvironment (Mailbox); + // + // Enable Debug Timer interrupt + // + SaveAndSetDebugTimerInterrupt (TRUE); + // + // Enable interrupt to receive Debug Timer interrupt + // + EnableInterrupts (); + + break; + + case DEBUG_AGENT_INIT_S3: + + if (Context != NULL) { + Ia32Idtr = (IA32_DESCRIPTOR *)Context; + Ia32IdtEntry = (IA32_IDT_ENTRY *)(Ia32Idtr->Base); + MailboxLocation = (UINT64 *)((UINTN)Ia32IdtEntry[DEBUG_MAILBOX_VECTOR].Bits.OffsetLow + + ((UINTN)Ia32IdtEntry[DEBUG_MAILBOX_VECTOR].Bits.OffsetHigh << 16)); + Mailbox = (DEBUG_AGENT_MAILBOX *)(UINTN)(*MailboxLocation); + VerifyMailboxChecksum (Mailbox); + } + + // + // Save Mailbox pointer in global variable + // + mMailboxPointer = Mailbox; + // + // Set up Debug Agent Environment and try to connect HOST if required + // + SetupDebugAgentEnvironment (Mailbox); + // + // Disable interrupt + // + DisableInterrupts (); + FindAndReportModuleImageInfo (SIZE_4KB); + if (GetDebugFlag (DEBUG_AGENT_FLAG_BREAK_BOOT_SCRIPT) == 1) { + // + // If Boot Script entry break is set, code will be break at here. + // + CpuBreakpoint (); + } + + break; + + default: + // + // Only DEBUG_AGENT_INIT_PREMEM_SEC and DEBUG_AGENT_INIT_POSTMEM_SEC are allowed for this + // Debug Agent library instance. + // + DEBUG ((DEBUG_ERROR, "Debug Agent: The InitFlag value is not allowed!\n")); + CpuDeadLoop (); + break; + } +} |
