diff options
Diffstat (limited to 'src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Library/DebugAgent/SmmDebugAgent/SmmDebugAgentLib.c')
-rw-r--r-- | src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Library/DebugAgent/SmmDebugAgent/SmmDebugAgentLib.c | 386 |
1 files changed, 386 insertions, 0 deletions
diff --git a/src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Library/DebugAgent/SmmDebugAgent/SmmDebugAgentLib.c b/src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Library/DebugAgent/SmmDebugAgent/SmmDebugAgentLib.c new file mode 100644 index 00000000..9cac45ab --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Library/DebugAgent/SmmDebugAgent/SmmDebugAgentLib.c @@ -0,0 +1,386 @@ +/** @file + Debug Agent library implementation. + + Copyright (c) 2010 - 2018, Intel Corporation. All rights reserved.<BR> + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "SmmDebugAgentLib.h" + +DEBUG_AGENT_MAILBOX *mMailboxPointer = NULL; +DEBUG_AGENT_MAILBOX mLocalMailbox; +UINTN mSavedDebugRegisters[6]; +IA32_IDT_GATE_DESCRIPTOR mIdtEntryTable[33]; +BOOLEAN mSkipBreakpoint = FALSE; +BOOLEAN mSmmDebugIdtInitFlag = FALSE; +BOOLEAN mApicTimerRestore = FALSE; +BOOLEAN mPeriodicMode; +UINT32 mTimerCycle; +UINTN mApicTimerDivisor; +UINT8 mVector; + +CHAR8 mWarningMsgIgnoreSmmEntryBreak[] = "Ignore smmentrybreak setting for SMI issued during DXE debugging!\r\n"; + +/** + Check if debug agent support multi-processor. + + @retval TRUE Multi-processor is supported. + @retval FALSE Multi-processor is not supported. + +**/ +BOOLEAN +MultiProcessorDebugSupport ( + VOID + ) +{ + return FALSE; +} + +/** + Read the Attach/Break-in symbols from the debug port. + + @param[in] Handle Pointer to Debug Port handle. + @param[out] BreakSymbol Returned break symbol. + + @retval EFI_SUCCESS Read the symbol in BreakSymbol. + @retval EFI_NOT_FOUND No read the break symbol. + +**/ +EFI_STATUS +DebugReadBreakSymbol ( + IN DEBUG_PORT_HANDLE Handle, + OUT UINT8 *BreakSymbol + ) +{ + // + // Smm instance has no debug timer to poll break symbol. + // + return EFI_NOT_FOUND; +} + +/** + Get the pointer to Mailbox from the GUIDed HOB. + + @return Pointer to Mailbox. + +**/ +DEBUG_AGENT_MAILBOX * +GetMailboxFromHob ( + VOID + ) +{ + EFI_HOB_GUID_TYPE *GuidHob; + UINT64 *MailboxLocation; + DEBUG_AGENT_MAILBOX *Mailbox; + + GuidHob = GetFirstGuidHob (&gEfiDebugAgentGuid); + 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 + ) +{ + VerifyMailboxChecksum (mMailboxPointer); + return mMailboxPointer; +} + +/** + Get debug port handle. + + @return Debug port handle. + +**/ +DEBUG_PORT_HANDLE +GetDebugPortHandle ( + VOID + ) +{ + return (DEBUG_PORT_HANDLE) (UINTN)(GetMailboxPointer()->DebugPortHandle); +} + +/** + Store debug register when SMI exit. + +**/ +VOID +SaveDebugRegister ( + VOID + ) +{ + mSavedDebugRegisters[0] = AsmReadDr0 (); + mSavedDebugRegisters[1] = AsmReadDr1 (); + mSavedDebugRegisters[2] = AsmReadDr2 (); + mSavedDebugRegisters[3] = AsmReadDr3 (); + mSavedDebugRegisters[4] = AsmReadDr6 (); + mSavedDebugRegisters[5] = AsmReadDr7 (); +} + +/** + Restore debug register when SMI exit. + +**/ +VOID +RestoreDebugRegister ( + VOID + ) +{ + AsmWriteDr7 (0); + AsmWriteDr0 (mSavedDebugRegisters[0]); + AsmWriteDr1 (mSavedDebugRegisters[1]); + AsmWriteDr2 (mSavedDebugRegisters[2]); + AsmWriteDr3 (mSavedDebugRegisters[3]); + AsmWriteDr6 (mSavedDebugRegisters[4]); + AsmWriteDr7 (mSavedDebugRegisters[5]); +} + +/** + Initialize debug agent. + + This function is used to set up debug environment for source level debug + in SMM code. + + If InitFlag is DEBUG_AGENT_INIT_SMM, it will override IDT table entries + and initialize debug port. It will get debug agent Mailbox from GUIDed HOB, + it it exists, debug agent wiil copied it into the local Mailbox in SMM space. + it will override IDT table entries and initialize debug port. Context will be + NULL. + If InitFlag is DEBUG_AGENT_INIT_ENTER_SMI, debug agent will save Debug + Registers and get local Mailbox in SMM space. Context will be NULL. + If InitFlag is DEBUG_AGENT_INIT_EXIT_SMI, debug agent will restore Debug + Registers. Context will be NULL. + + @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 + ) +{ + EFI_STATUS Status; + UINT64 DebugPortHandle; + IA32_IDT_GATE_DESCRIPTOR IdtEntry[33]; + IA32_DESCRIPTOR IdtDescriptor; + IA32_DESCRIPTOR *Ia32Idtr; + IA32_IDT_ENTRY *Ia32IdtEntry; + IA32_DESCRIPTOR Idtr; + UINT16 IdtEntryCount; + DEBUG_AGENT_MAILBOX *Mailbox; + UINT64 *MailboxLocation; + UINT32 DebugTimerFrequency; + + switch (InitFlag) { + case DEBUG_AGENT_INIT_SMM: + // + // Install configuration table for persisted vector handoff info + // + Status = gSmst->SmmInstallConfigurationTable ( + gSmst, + &gEfiVectorHandoffTableGuid, + (VOID *) &mVectorHandoffInfoDebugAgent[0], + sizeof (EFI_VECTOR_HANDOFF_INFO) * mVectorHandoffInfoCount + ); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "DebugAgent: Cannot install configuration table for persisted vector handoff info!\n")); + CpuDeadLoop (); + } + // + // Check if Debug Agent initialized in DXE phase + // + Status = EfiGetSystemConfigurationTable (&gEfiDebugAgentGuid, (VOID **) &Mailbox); + if (Status == EFI_SUCCESS && Mailbox != NULL) { + VerifyMailboxChecksum (Mailbox); + mMailboxPointer = Mailbox; + break; + } + // + // Check if Debug Agent initialized in SEC/PEI phase + // + Mailbox = GetMailboxFromHob (); + if (Mailbox != NULL) { + mMailboxPointer = Mailbox; + break; + } + // + // Debug Agent was not initialized before, use the local mailbox. + // + ZeroMem (&mLocalMailbox, sizeof (DEBUG_AGENT_MAILBOX)); + Mailbox = &mLocalMailbox; + // + // Save original IDT entries + // + AsmReadIdtr (&IdtDescriptor); + CopyMem (&IdtEntry, (VOID *)IdtDescriptor.Base, 33 * sizeof(IA32_IDT_GATE_DESCRIPTOR)); + // + // Initialized Debug Agent + // + InitializeDebugIdt (); + // + // Initialize Debug Timer hardware and save its frequency + // + InitializeDebugTimer (&DebugTimerFrequency, TRUE); + UpdateMailboxContent (Mailbox, DEBUG_MAILBOX_DEBUG_TIMER_FREQUENCY, DebugTimerFrequency); + + DebugPortHandle = (UINT64) (UINTN)DebugPortInitialize ((DEBUG_PORT_HANDLE) (UINTN)Mailbox->DebugPortHandle, NULL); + UpdateMailboxContent (Mailbox, DEBUG_MAILBOX_DEBUG_PORT_HANDLE_INDEX, DebugPortHandle); + mMailboxPointer = Mailbox; + // + // 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); + } + // + // Find and report PE/COFF image info to HOST + // + FindAndReportModuleImageInfo (SIZE_4KB); + // + // Restore saved IDT entries + // + CopyMem ((VOID *)IdtDescriptor.Base, &IdtEntry, 33 * sizeof(IA32_IDT_GATE_DESCRIPTOR)); + + break; + + case DEBUG_AGENT_INIT_ENTER_SMI: + SaveDebugRegister (); + if (!mSmmDebugIdtInitFlag) { + // + // We only need to initialize Debug IDT table at first SMI entry + // after SMM relocation. + // + InitializeDebugIdt (); + mSmmDebugIdtInitFlag = TRUE; + } + // + // Check if CPU APIC Timer is working, otherwise initialize it. + // + InitializeLocalApicSoftwareEnable (TRUE); + GetApicTimerState (&mApicTimerDivisor, &mPeriodicMode, &mVector); + mTimerCycle = GetApicTimerInitCount (); + if (!mPeriodicMode || mTimerCycle == 0) { + mApicTimerRestore = TRUE; + InitializeDebugTimer (NULL, FALSE); + } + Mailbox = GetMailboxPointer (); + if (GetDebugFlag (DEBUG_AGENT_FLAG_AGENT_IN_PROGRESS) == 1) { + // + // If Debug Agent has been communication state with HOST, we need skip + // any break points set in SMM, set Skip Breakpoint flag + // + mSkipBreakpoint = TRUE; + } + if (GetDebugFlag (DEBUG_AGENT_FLAG_BREAK_ON_NEXT_SMI) == 1) { + if (mSkipBreakpoint) { + // + // Print warning message if ignore smm entry break + // + DebugPortWriteBuffer ((DEBUG_PORT_HANDLE) (UINTN)Mailbox->DebugPortHandle, + (UINT8 *)mWarningMsgIgnoreSmmEntryBreak, + AsciiStrLen (mWarningMsgIgnoreSmmEntryBreak) + ); + } else { + // + // If SMM entry break is set, SMM code will be break at here. + // + CpuBreakpoint (); + } + } + break; + + case DEBUG_AGENT_INIT_EXIT_SMI: + Mailbox = GetMailboxPointer (); + // + // Clear Skip Breakpoint flag + // + mSkipBreakpoint = FALSE; + RestoreDebugRegister (); + // + // Restore APIC Timer + // + if (mApicTimerRestore) { + InitializeApicTimer (mApicTimerDivisor, mTimerCycle, mPeriodicMode, mVector); + mApicTimerRestore = FALSE; + } + break; + + case DEBUG_AGENT_INIT_THUNK_PEI_IA32TOX64: + if (Context == NULL) { + DEBUG ((EFI_D_ERROR, "DebugAgent: Input parameter Context cannot be NULL!\n")); + CpuDeadLoop (); + } else { + 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)); + mMailboxPointer = (DEBUG_AGENT_MAILBOX *)(UINTN)(*MailboxLocation); + VerifyMailboxChecksum (mMailboxPointer); + // + // Get original IDT address and size. + // + AsmReadIdtr ((IA32_DESCRIPTOR *) &Idtr); + IdtEntryCount = (UINT16) ((Idtr.Limit + 1) / sizeof (IA32_IDT_GATE_DESCRIPTOR)); + if (IdtEntryCount < 33) { + Idtr.Limit = (UINT16) (sizeof (IA32_IDT_GATE_DESCRIPTOR) * 33 - 1); + Idtr.Base = (UINTN) &mIdtEntryTable; + ZeroMem (&mIdtEntryTable, Idtr.Limit + 1); + AsmWriteIdtr ((IA32_DESCRIPTOR *) &Idtr); + } + + InitializeDebugIdt (); + // + // Initialize Debug Timer hardware and save its frequency + // + InitializeDebugTimer (&DebugTimerFrequency, TRUE); + UpdateMailboxContent (mMailboxPointer, DEBUG_MAILBOX_DEBUG_TIMER_FREQUENCY, DebugTimerFrequency); + // + // Enable Debug Timer interrupt and CPU interrupt + // + SaveAndSetDebugTimerInterrupt (TRUE); + EnableInterrupts (); + + FindAndReportModuleImageInfo (SIZE_4KB); + } + break; + + default: + // + // Only DEBUG_AGENT_INIT_PREMEM_SEC and DEBUG_AGENT_INIT_POSTMEM_SEC are allowed for this + // Debug Agent library instance. + // + DEBUG ((EFI_D_ERROR, "Debug Agent: The InitFlag value is not allowed!\n")); + CpuDeadLoop (); + break; + } +} + |