summaryrefslogtreecommitdiffstats
path: root/src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Library/DebugAgent/DebugAgentCommon
diff options
context:
space:
mode:
Diffstat (limited to 'src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Library/DebugAgent/DebugAgentCommon')
-rw-r--r--src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Library/DebugAgent/DebugAgentCommon/DebugAgent.c2640
-rw-r--r--src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Library/DebugAgent/DebugAgentCommon/DebugAgent.h498
-rw-r--r--src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Library/DebugAgent/DebugAgentCommon/DebugMp.c377
-rw-r--r--src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Library/DebugAgent/DebugAgentCommon/DebugMp.h216
-rw-r--r--src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Library/DebugAgent/DebugAgentCommon/DebugTimer.c143
-rw-r--r--src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Library/DebugAgent/DebugAgentCommon/DebugTimer.h45
-rw-r--r--src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Library/DebugAgent/DebugAgentCommon/Ia32/ArchDebugSupport.c110
-rw-r--r--src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Library/DebugAgent/DebugAgentCommon/Ia32/ArchDebugSupport.h21
-rw-r--r--src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Library/DebugAgent/DebugAgentCommon/Ia32/AsmFuncs.nasm413
-rw-r--r--src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Library/DebugAgent/DebugAgentCommon/Ia32/DebugException.h30
-rw-r--r--src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Library/DebugAgent/DebugAgentCommon/X64/ArchDebugSupport.c114
-rw-r--r--src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Library/DebugAgent/DebugAgentCommon/X64/ArchDebugSupport.h21
-rw-r--r--src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Library/DebugAgent/DebugAgentCommon/X64/AsmFuncs.nasm399
-rw-r--r--src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Library/DebugAgent/DebugAgentCommon/X64/DebugException.h30
14 files changed, 5057 insertions, 0 deletions
diff --git a/src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Library/DebugAgent/DebugAgentCommon/DebugAgent.c b/src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Library/DebugAgent/DebugAgentCommon/DebugAgent.c
new file mode 100644
index 00000000..1ee01e02
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Library/DebugAgent/DebugAgentCommon/DebugAgent.c
@@ -0,0 +1,2640 @@
+/** @file
+ Commond Debug Agent library implementation. It mainly includes
+ the first C function called by exception/interrupt handlers,
+ read/write debug packet to communication with HOST based on transfer
+ protocol.
+
+ Copyright (c) 2010 - 2018, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "DebugAgent.h"
+#include "Ia32/DebugException.h"
+
+GLOBAL_REMOVE_IF_UNREFERENCED CHAR8 mErrorMsgVersionAlert[] = "\rThe SourceLevelDebugPkg you are using requires a newer version of the Intel(R) UDK Debugger Tool.\r\n";
+GLOBAL_REMOVE_IF_UNREFERENCED CHAR8 mErrorMsgSendInitPacket[] = "\rSend INIT break packet and try to connect the HOST (Intel(R) UDK Debugger Tool v1.5) ...\r\n";
+GLOBAL_REMOVE_IF_UNREFERENCED CHAR8 mErrorMsgConnectOK[] = "HOST connection is successful!\r\n";
+GLOBAL_REMOVE_IF_UNREFERENCED CHAR8 mErrorMsgConnectFail[] = "HOST connection is failed!\r\n";
+GLOBAL_REMOVE_IF_UNREFERENCED CHAR8 mWarningMsgIngoreBreakpoint[] = "Ignore break point in SMM for SMI issued during DXE debugging!\r\n";
+
+//
+// Vector Handoff Info list used by Debug Agent for persist
+//
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_VECTOR_HANDOFF_INFO mVectorHandoffInfoDebugAgent[] = {
+ {
+ DEBUG_EXCEPT_DIVIDE_ERROR, // Vector 0
+ EFI_VECTOR_HANDOFF_HOOK_BEFORE,
+ EFI_DEBUG_AGENT_GUID
+ },
+ {
+ DEBUG_EXCEPT_DEBUG, // Vector 1
+ EFI_VECTOR_HANDOFF_DO_NOT_HOOK,
+ EFI_DEBUG_AGENT_GUID
+ },
+ {
+ DEBUG_EXCEPT_NMI, // Vector 2
+ EFI_VECTOR_HANDOFF_HOOK_BEFORE,
+ EFI_DEBUG_AGENT_GUID
+ },
+ {
+ DEBUG_EXCEPT_BREAKPOINT, // Vector 3
+ EFI_VECTOR_HANDOFF_DO_NOT_HOOK,
+ EFI_DEBUG_AGENT_GUID
+ },
+ {
+ DEBUG_EXCEPT_OVERFLOW, // Vector 4
+ EFI_VECTOR_HANDOFF_HOOK_BEFORE,
+ EFI_DEBUG_AGENT_GUID
+ },
+ {
+ DEBUG_EXCEPT_BOUND, // Vector 5
+ EFI_VECTOR_HANDOFF_HOOK_BEFORE,
+ EFI_DEBUG_AGENT_GUID
+ },
+ {
+ DEBUG_EXCEPT_INVALID_OPCODE, // Vector 6
+ EFI_VECTOR_HANDOFF_HOOK_BEFORE,
+ EFI_DEBUG_AGENT_GUID
+ },
+ {
+ DEBUG_EXCEPT_DOUBLE_FAULT, // Vector 8
+ EFI_VECTOR_HANDOFF_HOOK_BEFORE,
+ EFI_DEBUG_AGENT_GUID
+ },
+ {
+ DEBUG_EXCEPT_INVALID_TSS, // Vector 10
+ EFI_VECTOR_HANDOFF_HOOK_BEFORE,
+ EFI_DEBUG_AGENT_GUID
+ },
+ {
+ DEBUG_EXCEPT_SEG_NOT_PRESENT, // Vector 11
+ EFI_VECTOR_HANDOFF_HOOK_BEFORE,
+ EFI_DEBUG_AGENT_GUID
+ },
+ {
+ DEBUG_EXCEPT_STACK_FAULT, // Vector 12
+ EFI_VECTOR_HANDOFF_HOOK_BEFORE,
+ EFI_DEBUG_AGENT_GUID
+ },
+ {
+ DEBUG_EXCEPT_GP_FAULT, // Vector 13
+ EFI_VECTOR_HANDOFF_HOOK_BEFORE,
+ EFI_DEBUG_AGENT_GUID
+ },
+ {
+ DEBUG_EXCEPT_PAGE_FAULT, // Vector 14
+ EFI_VECTOR_HANDOFF_HOOK_BEFORE,
+ EFI_DEBUG_AGENT_GUID
+ },
+ {
+ DEBUG_EXCEPT_FP_ERROR, // Vector 16
+ EFI_VECTOR_HANDOFF_HOOK_BEFORE,
+ EFI_DEBUG_AGENT_GUID
+ },
+ {
+ DEBUG_EXCEPT_ALIGNMENT_CHECK, // Vector 17
+ EFI_VECTOR_HANDOFF_HOOK_BEFORE,
+ EFI_DEBUG_AGENT_GUID
+ },
+ {
+ DEBUG_EXCEPT_MACHINE_CHECK, // Vector 18
+ EFI_VECTOR_HANDOFF_HOOK_BEFORE,
+ EFI_DEBUG_AGENT_GUID
+ },
+ {
+ DEBUG_EXCEPT_SIMD, // Vector 19
+ EFI_VECTOR_HANDOFF_HOOK_BEFORE,
+ EFI_DEBUG_AGENT_GUID
+ },
+ {
+ DEBUG_TIMER_VECTOR, // Vector 32
+ EFI_VECTOR_HANDOFF_DO_NOT_HOOK,
+ EFI_DEBUG_AGENT_GUID
+ },
+ {
+ DEBUG_MAILBOX_VECTOR, // Vector 33
+ EFI_VECTOR_HANDOFF_DO_NOT_HOOK,
+ EFI_DEBUG_AGENT_GUID
+ },
+ {
+ 0,
+ EFI_VECTOR_HANDOFF_LAST_ENTRY,
+ { 0 }
+ }
+};
+
+GLOBAL_REMOVE_IF_UNREFERENCED UINTN mVectorHandoffInfoCount = sizeof (mVectorHandoffInfoDebugAgent) / sizeof (EFI_VECTOR_HANDOFF_INFO);
+
+/**
+ Calculate CRC16 for target data.
+
+ @param[in] Data The target data.
+ @param[in] DataSize The target data size.
+ @param[in] Crc Initial CRC.
+
+ @return UINT16 The CRC16 value.
+
+**/
+UINT16
+CalculateCrc16 (
+ IN UINT8 *Data,
+ IN UINTN DataSize,
+ IN UINT16 Crc
+ )
+{
+ UINTN Index;
+ UINTN BitIndex;
+
+ for (Index = 0; Index < DataSize; Index++) {
+ Crc ^= (UINT16)Data[Index];
+ for (BitIndex = 0; BitIndex < 8; BitIndex++) {
+ if ((Crc & 0x8000) != 0) {
+ Crc <<= 1;
+ Crc ^= 0x1021;
+ } else {
+ Crc <<= 1;
+ }
+ }
+ }
+ return Crc;
+}
+
+
+/**
+ Read IDT entry to check if IDT entries are setup by Debug Agent.
+
+ @retval TRUE IDT entries were setup by Debug Agent.
+ @retval FALSE IDT entries were not setup by Debug Agent.
+
+**/
+BOOLEAN
+IsDebugAgentInitialzed (
+ VOID
+ )
+{
+ UINTN InterruptHandler;
+
+ InterruptHandler = (UINTN) GetExceptionHandlerInIdtEntry (0);
+ if (InterruptHandler >= 4 && *(UINT32 *)(InterruptHandler - 4) == AGENT_HANDLER_SIGNATURE) {
+ return TRUE;
+ } else {
+ return FALSE;
+ }
+}
+
+/**
+ Find and report module image info to HOST.
+
+ @param[in] AlignSize Image aligned size.
+
+**/
+VOID
+FindAndReportModuleImageInfo (
+ IN UINTN AlignSize
+ )
+{
+ UINTN Pe32Data;
+ PE_COFF_LOADER_IMAGE_CONTEXT ImageContext;
+
+ //
+ // Find Image Base
+ //
+ Pe32Data = PeCoffSearchImageBase ((UINTN) mErrorMsgVersionAlert);
+ if (Pe32Data != 0) {
+ ImageContext.ImageAddress = Pe32Data;
+ ImageContext.PdbPointer = PeCoffLoaderGetPdbPointer ((VOID*) (UINTN) ImageContext.ImageAddress);
+ PeCoffLoaderRelocateImageExtraAction (&ImageContext);
+ }
+}
+
+/**
+ Trigger one software interrupt to debug agent to handle it.
+
+ @param[in] Signature Software interrupt signature.
+
+**/
+VOID
+TriggerSoftInterrupt (
+ IN UINT32 Signature
+ )
+{
+ UINTN Dr0;
+ UINTN Dr1;
+
+ //
+ // Save Debug Register State
+ //
+ Dr0 = AsmReadDr0 ();
+ Dr1 = AsmReadDr1 ();
+
+ //
+ // DR0 = Signature
+ //
+ AsmWriteDr0 (SOFT_INTERRUPT_SIGNATURE);
+ AsmWriteDr1 (Signature);
+
+ //
+ // Do INT3 to communicate with HOST side
+ //
+ CpuBreakpoint ();
+
+ //
+ // Restore Debug Register State only when Host didn't change it inside exception handler.
+ // Dr registers can only be changed by setting the HW breakpoint.
+ //
+ AsmWriteDr0 (Dr0);
+ AsmWriteDr1 (Dr1);
+
+}
+
+/**
+ Calculate Mailbox checksum and update the checksum field.
+
+ @param[in] Mailbox Debug Agent Mailbox pointer.
+
+**/
+VOID
+UpdateMailboxChecksum (
+ IN DEBUG_AGENT_MAILBOX *Mailbox
+ )
+{
+ Mailbox->CheckSum = CalculateCheckSum8 ((UINT8 *)Mailbox, sizeof (DEBUG_AGENT_MAILBOX) - 2);
+}
+
+/**
+ Verify Mailbox checksum.
+
+ If checksum error, print debug message and run init dead loop.
+
+ @param[in] Mailbox Debug Agent Mailbox pointer.
+
+**/
+VOID
+VerifyMailboxChecksum (
+ IN DEBUG_AGENT_MAILBOX *Mailbox
+ )
+{
+ UINT8 CheckSum;
+
+ CheckSum = CalculateCheckSum8 ((UINT8 *) Mailbox, sizeof (DEBUG_AGENT_MAILBOX) - 2);
+ //
+ // The checksum updating process may be disturbed by hardware SMI, we need to check CheckSum field
+ // and ToBeCheckSum field to validate the mail box.
+ //
+ if (CheckSum != Mailbox->CheckSum && CheckSum != Mailbox->ToBeCheckSum) {
+ DEBUG ((EFI_D_ERROR, "DebugAgent: Mailbox checksum error, stack or heap crashed!\n"));
+ DEBUG ((EFI_D_ERROR, "DebugAgent: CheckSum = %x, Mailbox->CheckSum = %x, Mailbox->ToBeCheckSum = %x\n", CheckSum, Mailbox->CheckSum, Mailbox->ToBeCheckSum));
+ CpuDeadLoop ();
+ }
+}
+
+/**
+ Update Mailbox content by index.
+
+ @param[in] Mailbox Debug Agent Mailbox pointer.
+ @param[in] Index Mailbox content index.
+ @param[in] Value Value to be set into Mailbox.
+
+**/
+VOID
+UpdateMailboxContent (
+ IN DEBUG_AGENT_MAILBOX *Mailbox,
+ IN UINTN Index,
+ IN UINT64 Value
+ )
+{
+ AcquireMpSpinLock (&mDebugMpContext.MailboxSpinLock);
+ switch (Index) {
+ case DEBUG_MAILBOX_DEBUG_FLAG_INDEX:
+ Mailbox->ToBeCheckSum = Mailbox->CheckSum + CalculateSum8 ((UINT8 *)&Mailbox->DebugFlag.Uint64, sizeof(UINT64))
+ - CalculateSum8 ((UINT8 *)&Value, sizeof(UINT64));
+ Mailbox->DebugFlag.Uint64 = Value;
+ break;
+ case DEBUG_MAILBOX_DEBUG_PORT_HANDLE_INDEX:
+ Mailbox->ToBeCheckSum = Mailbox->CheckSum + CalculateSum8 ((UINT8 *)&Mailbox->DebugPortHandle, sizeof(UINTN))
+ - CalculateSum8 ((UINT8 *)&Value, sizeof(UINTN));
+ Mailbox->DebugPortHandle = (UINTN) Value;
+ break;
+ case DEBUG_MAILBOX_EXCEPTION_BUFFER_POINTER_INDEX:
+ Mailbox->ToBeCheckSum = Mailbox->CheckSum + CalculateSum8 ((UINT8 *)&Mailbox->ExceptionBufferPointer, sizeof(UINTN))
+ - CalculateSum8 ((UINT8 *)&Value, sizeof(UINTN));
+ Mailbox->ExceptionBufferPointer = (UINTN) Value;
+ break;
+ case DEBUG_MAILBOX_LAST_ACK:
+ Mailbox->ToBeCheckSum = Mailbox->CheckSum + CalculateSum8 ((UINT8 *)&Mailbox->LastAck, sizeof(UINT8))
+ - CalculateSum8 ((UINT8 *)&Value, sizeof(UINT8));
+ Mailbox->LastAck = (UINT8) Value;
+ break;
+ case DEBUG_MAILBOX_SEQUENCE_NO_INDEX:
+ Mailbox->ToBeCheckSum = Mailbox->CheckSum + CalculateSum8 ((UINT8 *)&Mailbox->SequenceNo, sizeof(UINT8))
+ - CalculateSum8 ((UINT8 *)&Value, sizeof(UINT8));
+ Mailbox->SequenceNo = (UINT8) Value;
+ break;
+ case DEBUG_MAILBOX_HOST_SEQUENCE_NO_INDEX:
+ Mailbox->ToBeCheckSum = Mailbox->CheckSum + CalculateSum8 ((UINT8 *)&Mailbox->HostSequenceNo, sizeof(UINT8))
+ - CalculateSum8 ((UINT8 *)&Value, sizeof(UINT8));
+ Mailbox->HostSequenceNo = (UINT8) Value;
+ break;
+ case DEBUG_MAILBOX_DEBUG_TIMER_FREQUENCY:
+ Mailbox->ToBeCheckSum = Mailbox->CheckSum + CalculateSum8 ((UINT8 *)&Mailbox->DebugTimerFrequency, sizeof(UINT32))
+ - CalculateSum8 ((UINT8 *)&Value, sizeof(UINT32));
+ Mailbox->DebugTimerFrequency = (UINT32) Value;
+ break;
+ }
+ UpdateMailboxChecksum (Mailbox);
+ ReleaseMpSpinLock (&mDebugMpContext.MailboxSpinLock);
+}
+
+/**
+ Read data from debug device and save the data in buffer.
+
+ Reads NumberOfBytes data bytes from a debug device into the buffer
+ specified by Buffer. The number of bytes actually read is returned.
+ If the return value is less than NumberOfBytes, then the rest operation failed.
+ If NumberOfBytes is zero, then return 0.
+
+ @param Handle Debug port handle.
+ @param Buffer Pointer to the data buffer to store the data read from the debug device.
+ @param NumberOfBytes Number of bytes which will be read.
+ @param Timeout Timeout value for reading from debug device. It unit is Microsecond.
+
+ @retval 0 Read data failed, no data is to be read.
+ @retval >0 Actual number of bytes read from debug device.
+
+**/
+UINTN
+DebugAgentReadBuffer (
+ IN DEBUG_PORT_HANDLE Handle,
+ IN UINT8 *Buffer,
+ IN UINTN NumberOfBytes,
+ IN UINTN Timeout
+ )
+{
+ UINTN Index;
+ UINT32 Begin;
+ UINT32 TimeoutTicker;
+ UINT32 TimerRound;
+ UINT32 TimerFrequency;
+ UINT32 TimerCycle;
+
+ Begin = 0;
+ TimeoutTicker = 0;
+ TimerRound = 0;
+ TimerFrequency = GetMailboxPointer()->DebugTimerFrequency;
+ TimerCycle = GetApicTimerInitCount ();
+
+ if (Timeout != 0) {
+ Begin = GetApicTimerCurrentCount ();
+ TimeoutTicker = (UINT32) DivU64x32 (
+ MultU64x64 (
+ TimerFrequency,
+ Timeout
+ ),
+ 1000000u
+ );
+ TimerRound = (UINT32) DivU64x32Remainder (TimeoutTicker, TimerCycle / 2, &TimeoutTicker);
+ }
+ Index = 0;
+ while (Index < NumberOfBytes) {
+ if (DebugPortPollBuffer (Handle)) {
+ DebugPortReadBuffer (Handle, Buffer + Index, 1, 0);
+ Index ++;
+ continue;
+ }
+ if (Timeout != 0) {
+ if (TimerRound == 0) {
+ if (IsDebugTimerTimeout (TimerCycle, Begin, TimeoutTicker)) {
+ //
+ // If time out occurs.
+ //
+ return 0;
+ }
+ } else {
+ if (IsDebugTimerTimeout (TimerCycle, Begin, TimerCycle / 2)) {
+ TimerRound --;
+ Begin = GetApicTimerCurrentCount ();
+ }
+ }
+ }
+ }
+
+ return Index;
+}
+
+/**
+ Set debug flag in mailbox.
+
+ @param[in] FlagMask Debug flag mask value.
+ @param[in] FlagValue Debug flag value.
+
+**/
+VOID
+SetDebugFlag (
+ IN UINT64 FlagMask,
+ IN UINT32 FlagValue
+ )
+{
+ DEBUG_AGENT_MAILBOX *Mailbox;
+ UINT64 Data64;
+
+ Mailbox = GetMailboxPointer ();
+ Data64 = (Mailbox->DebugFlag.Uint64 & ~FlagMask) |
+ (LShiftU64 ((UINT64)FlagValue, LowBitSet64 (FlagMask)) & FlagMask);
+ UpdateMailboxContent (Mailbox, DEBUG_MAILBOX_DEBUG_FLAG_INDEX, Data64);
+}
+
+/**
+ Get debug flag in mailbox.
+
+ @param[in] FlagMask Debug flag mask value.
+
+ @return Debug flag value.
+
+**/
+UINT32
+GetDebugFlag (
+ IN UINT64 FlagMask
+ )
+{
+ DEBUG_AGENT_MAILBOX *Mailbox;
+ UINT32 DebugFlag;
+
+ Mailbox = GetMailboxPointer ();
+ DebugFlag = (UINT32) RShiftU64 (Mailbox->DebugFlag.Uint64 & FlagMask, LowBitSet64 (FlagMask));
+
+ return DebugFlag;
+}
+
+/**
+ Send a debug message packet to the debug port.
+
+ @param[in] Buffer The debug message.
+ @param[in] Length The length of debug message.
+
+**/
+VOID
+SendDebugMsgPacket (
+ IN CHAR8 *Buffer,
+ IN UINTN Length
+ )
+{
+ DEBUG_PACKET_HEADER DebugHeader;
+ DEBUG_PORT_HANDLE Handle;
+
+ Handle = GetDebugPortHandle();
+
+ DebugHeader.StartSymbol = DEBUG_STARTING_SYMBOL_NORMAL;
+ DebugHeader.Command = DEBUG_COMMAND_PRINT_MESSAGE;
+ DebugHeader.Length = sizeof (DEBUG_PACKET_HEADER) + (UINT8) Length;
+ DebugHeader.SequenceNo = 0xEE;
+ DebugHeader.Crc = 0;
+ DebugHeader.Crc = CalculateCrc16 (
+ (UINT8 *)Buffer, Length,
+ CalculateCrc16 ((UINT8 *)&DebugHeader, sizeof (DEBUG_PACKET_HEADER), 0)
+ );
+
+ DebugPortWriteBuffer (Handle, (UINT8 *)&DebugHeader, sizeof (DEBUG_PACKET_HEADER));
+ DebugPortWriteBuffer (Handle, (UINT8 *)Buffer, Length);
+}
+
+/**
+ Prints a debug message to the debug port if the specified error level is enabled.
+
+ If any bit in ErrorLevel is also set in Mainbox, then print the message specified
+ by Format and the associated variable argument list to the debug port.
+
+ @param[in] ErrorLevel The error level of the debug message.
+ @param[in] Format Format string for the debug message to print.
+ @param[in] ... Variable argument list whose contents are accessed
+ based on the format string specified by Format.
+
+**/
+VOID
+EFIAPI
+DebugAgentMsgPrint (
+ IN UINT8 ErrorLevel,
+ IN CHAR8 *Format,
+ ...
+ )
+{
+ CHAR8 Buffer[DEBUG_DATA_MAXIMUM_REAL_DATA];
+ VA_LIST Marker;
+
+ //
+ // Check driver debug mask value and global mask
+ //
+ if ((ErrorLevel & GetDebugFlag (DEBUG_AGENT_FLAG_PRINT_ERROR_LEVEL)) == 0) {
+ return;
+ }
+
+ //
+ // Convert the DEBUG() message to an ASCII String
+ //
+ VA_START (Marker, Format);
+ AsciiVSPrint (Buffer, sizeof (Buffer), Format, Marker);
+ VA_END (Marker);
+
+ SendDebugMsgPacket (Buffer, AsciiStrLen (Buffer));
+}
+
+/**
+ Prints a debug message to the debug output device if the specified error level is enabled.
+
+ If any bit in ErrorLevel is also set in DebugPrintErrorLevelLib function
+ GetDebugPrintErrorLevel (), then print the message specified by Format and the
+ associated variable argument list to the debug output device.
+
+ If Format is NULL, then ASSERT().
+
+ @param[in] ErrorLevel The error level of the debug message.
+ @param[in] IsSend Flag of debug message to declare that the data is being sent or being received.
+ @param[in] Data Variable argument list whose contents are accessed
+ @param[in] Length based on the format string specified by Format.
+
+**/
+VOID
+EFIAPI
+DebugAgentDataMsgPrint (
+ IN UINT8 ErrorLevel,
+ IN BOOLEAN IsSend,
+ IN UINT8 *Data,
+ IN UINT8 Length
+ )
+{
+ CHAR8 Buffer[DEBUG_DATA_MAXIMUM_REAL_DATA];
+ CHAR8 *DestBuffer;
+ UINTN Index;
+
+ //
+ // Check driver debug mask value and global mask
+ //
+ if ((ErrorLevel & GetDebugFlag (DEBUG_AGENT_FLAG_PRINT_ERROR_LEVEL)) == 0) {
+ return;
+ }
+
+ DestBuffer = Buffer;
+ if (IsSend) {
+ DestBuffer += AsciiSPrint (DestBuffer, DEBUG_DATA_MAXIMUM_REAL_DATA, "Sent data [ ");
+ } else {
+ DestBuffer += AsciiSPrint (DestBuffer, DEBUG_DATA_MAXIMUM_REAL_DATA, "Received data [ ");
+ }
+
+ Index = 0;
+ while (TRUE) {
+ if (DestBuffer - Buffer > DEBUG_DATA_MAXIMUM_REAL_DATA - 6) {
+ //
+ // If there was no enough space in buffer, send out the debug message,
+ // reserving 6 bytes is for the last data and end characters "]\n".
+ //
+ SendDebugMsgPacket (Buffer, DestBuffer - Buffer);
+ DestBuffer = Buffer;
+ }
+ DestBuffer += AsciiSPrint (DestBuffer, DEBUG_DATA_MAXIMUM_REAL_DATA - (DestBuffer - Buffer), "%02x ", Data[Index]);
+ Index ++;
+ if (Index >= Length) {
+ //
+ // The last character of debug message has been formatted in buffer
+ //
+ DestBuffer += AsciiSPrint(DestBuffer, DEBUG_DATA_MAXIMUM_REAL_DATA - (DestBuffer - Buffer), "]\n");
+ SendDebugMsgPacket (Buffer, DestBuffer - Buffer);
+ break;
+ }
+ }
+}
+
+/**
+ Read remaing debug packet except for the start symbol
+
+ @param[in] Handle Pointer to Debug Port handle.
+ @param[in, out] DebugHeader Debug header buffer including start symbol.
+
+ @retval EFI_SUCCESS Read the symbol in BreakSymbol.
+ @retval EFI_CRC_ERROR CRC check fail.
+ @retval EFI_TIMEOUT Timeout occurs when reading debug packet.
+ @retval EFI_DEVICE_ERROR Receive the old or responsed packet.
+
+**/
+EFI_STATUS
+ReadRemainingBreakPacket (
+ IN DEBUG_PORT_HANDLE Handle,
+ IN OUT DEBUG_PACKET_HEADER *DebugHeader
+ )
+{
+ UINT16 Crc;
+ DEBUG_AGENT_MAILBOX *Mailbox;
+
+ //
+ // Has received start symbol, try to read the rest part
+ //
+ if (DebugAgentReadBuffer (Handle, (UINT8 *)DebugHeader + OFFSET_OF (DEBUG_PACKET_HEADER, Command), sizeof (DEBUG_PACKET_HEADER) - OFFSET_OF (DEBUG_PACKET_HEADER, Command), READ_PACKET_TIMEOUT) == 0) {
+ //
+ // Timeout occur, exit
+ //
+ DebugAgentMsgPrint (DEBUG_AGENT_WARNING, "Timeout in Debug Timer interrupt\n");
+ return EFI_TIMEOUT;
+ }
+
+ Crc = DebugHeader->Crc;
+ DebugHeader->Crc = 0;
+ if (CalculateCrc16 ((UINT8 *)DebugHeader, DebugHeader->Length, 0) != Crc) {
+ DebugAgentMsgPrint (DEBUG_AGENT_WARNING, "Debug Timer CRC (%x) against (%x)\n", Crc, CalculateCrc16 ((UINT8 *) &DebugHeader, DebugHeader->Length, 0));
+ DebugAgentDataMsgPrint (DEBUG_AGENT_VERBOSE, FALSE, (UINT8 *)DebugHeader, DebugHeader->Length);
+ return EFI_CRC_ERROR;
+ }
+ Mailbox = GetMailboxPointer();
+ if (IS_REQUEST (DebugHeader)) {
+ if (DebugHeader->SequenceNo == (UINT8) (Mailbox->HostSequenceNo + 1)) {
+ //
+ // Only updagte HostSequenceNo for new command packet
+ //
+ UpdateMailboxContent (Mailbox, DEBUG_MAILBOX_HOST_SEQUENCE_NO_INDEX, DebugHeader->SequenceNo);
+ return EFI_SUCCESS;
+ }
+ if (DebugHeader->SequenceNo == Mailbox->HostSequenceNo) {
+ return EFI_SUCCESS;
+ }
+ }
+
+ return EFI_DEVICE_ERROR;
+}
+
+/**
+ Check if HOST is attached based on Mailbox.
+
+ @retval TRUE HOST is attached.
+ @retval FALSE HOST is not attached.
+
+**/
+BOOLEAN
+IsHostAttached (
+ VOID
+ )
+{
+ return (BOOLEAN) (GetDebugFlag (DEBUG_AGENT_FLAG_HOST_ATTACHED) == 1);
+}
+
+/**
+ Set HOST connect flag in Mailbox.
+
+ @param[in] Attached Attach status.
+
+**/
+VOID
+SetHostAttached (
+ IN BOOLEAN Attached
+ )
+{
+ DebugAgentMsgPrint (DEBUG_AGENT_INFO, "Attach status is %d\n", Attached);
+ SetDebugFlag (DEBUG_AGENT_FLAG_HOST_ATTACHED, (UINT32)Attached);
+}
+
+/**
+ Set debug setting of Debug Agent in Mailbox.
+
+ @param DebugSetting Pointer to Debug Setting defined by transfer protocol.
+
+ @retval RETURN_SUCCESS The setting is set successfully.
+ @retval RETURN_UNSUPPORTED The Key value is not supported.
+
+**/
+RETURN_STATUS
+SetDebugSetting (
+ IN DEBUG_DATA_SET_DEBUG_SETTING *DebugSetting
+ )
+{
+ RETURN_STATUS Status;
+
+ Status = RETURN_SUCCESS;
+ switch (DebugSetting->Key) {
+ case DEBUG_AGENT_SETTING_SMM_ENTRY_BREAK:
+ SetDebugFlag (DEBUG_AGENT_FLAG_BREAK_ON_NEXT_SMI, DebugSetting->Value);
+ break;
+ case DEBUG_AGENT_SETTING_PRINT_ERROR_LEVEL:
+ SetDebugFlag (DEBUG_AGENT_FLAG_PRINT_ERROR_LEVEL, DebugSetting->Value);
+ break;
+ case DEBUG_AGENT_SETTING_BOOT_SCRIPT_ENTRY_BREAK:
+ SetDebugFlag (DEBUG_AGENT_FLAG_BREAK_BOOT_SCRIPT, DebugSetting->Value);
+ break;
+ default:
+ Status = RETURN_UNSUPPORTED;
+ }
+ return Status;
+}
+
+/**
+ Execute GO command.
+
+ @param[in] CpuContext Pointer to saved CPU context.
+
+**/
+VOID
+CommandGo (
+ IN DEBUG_CPU_CONTEXT *CpuContext
+ )
+{
+ IA32_EFLAGS32 *Eflags;
+
+ Eflags = (IA32_EFLAGS32 *) &CpuContext->Eflags;
+ Eflags->Bits.TF = 0;
+ Eflags->Bits.RF = 1;
+}
+
+/**
+ Execute Stepping command.
+
+ @param[in] CpuContext Pointer to saved CPU context.
+
+**/
+VOID
+CommandStepping (
+ IN DEBUG_CPU_CONTEXT *CpuContext
+ )
+{
+ IA32_EFLAGS32 *Eflags;
+
+ Eflags = (IA32_EFLAGS32 *) &CpuContext->Eflags;
+ Eflags->Bits.TF = 1;
+ Eflags->Bits.RF = 1;
+ //
+ // Save and clear EFLAGS.IF to avoid interrupt happen when executing Stepping
+ //
+ SetDebugFlag (DEBUG_AGENT_FLAG_INTERRUPT_FLAG, Eflags->Bits.IF);
+ Eflags->Bits.IF = 0;
+ //
+ // Set Stepping Flag
+ //
+ SetDebugFlag (DEBUG_AGENT_FLAG_STEPPING, 1);
+}
+
+/**
+ Do some cleanup after Stepping command done.
+
+ @param[in] CpuContext Pointer to saved CPU context.
+
+**/
+VOID
+CommandSteppingCleanup (
+ IN DEBUG_CPU_CONTEXT *CpuContext
+ )
+{
+ IA32_EFLAGS32 *Eflags;
+
+ Eflags = (IA32_EFLAGS32 *) &CpuContext->Eflags;
+ //
+ // Restore EFLAGS.IF
+ //
+ Eflags->Bits.IF = GetDebugFlag (DEBUG_AGENT_FLAG_INTERRUPT_FLAG);
+ //
+ // Clear Stepping flag
+ //
+ SetDebugFlag (DEBUG_AGENT_FLAG_STEPPING, 0);
+}
+
+/**
+ Set debug register for hardware breakpoint.
+
+ @param[in] CpuContext Pointer to saved CPU context.
+ @param[in] SetHwBreakpoint Hardware breakpoint to be set.
+
+**/
+VOID
+SetDebugRegister (
+ IN DEBUG_CPU_CONTEXT *CpuContext,
+ IN DEBUG_DATA_SET_HW_BREAKPOINT *SetHwBreakpoint
+ )
+{
+ UINT8 RegisterIndex;
+ UINTN Dr7Value;
+
+ RegisterIndex = SetHwBreakpoint->Type.Index;
+
+ //
+ // Set debug address
+ //
+ * ((UINTN *) &CpuContext->Dr0 + RegisterIndex) = (UINTN) SetHwBreakpoint->Address;
+
+ Dr7Value = CpuContext->Dr7;
+
+ //
+ // Enable Gx, Lx
+ //
+ Dr7Value |= (UINTN) (0x3 << (RegisterIndex * 2));
+ //
+ // Set RWx and Lenx
+ //
+ Dr7Value &= (UINTN) (~(0xf << (16 + RegisterIndex * 4)));
+ Dr7Value |= (UINTN) ((SetHwBreakpoint->Type.Length << 2) | SetHwBreakpoint->Type.Access) << (16 + RegisterIndex * 4);
+ //
+ // Enable GE, LE
+ //
+ Dr7Value |= 0x300;
+
+ CpuContext->Dr7 = Dr7Value;
+}
+
+/**
+ Clear debug register for hardware breakpoint.
+
+ @param[in] CpuContext Pointer to saved CPU context.
+ @param[in] ClearHwBreakpoint Hardware breakpoint to be cleared.
+
+**/
+VOID
+ClearDebugRegister (
+ IN DEBUG_CPU_CONTEXT *CpuContext,
+ IN DEBUG_DATA_CLEAR_HW_BREAKPOINT *ClearHwBreakpoint
+ )
+{
+ if ((ClearHwBreakpoint->IndexMask & BIT0) != 0) {
+ CpuContext->Dr0 = 0;
+ CpuContext->Dr7 &= (UINTN)(~(0x3 << 0));
+ }
+ if ((ClearHwBreakpoint->IndexMask & BIT1) != 0) {
+ CpuContext->Dr1 = 0;
+ CpuContext->Dr7 &= (UINTN)(~(0x3 << 2));
+ }
+ if ((ClearHwBreakpoint->IndexMask & BIT2) != 0) {
+ CpuContext->Dr2 = 0;
+ CpuContext->Dr7 &= (UINTN)(~(0x3 << 4));
+ }
+ if ((ClearHwBreakpoint->IndexMask & BIT3) != 0) {
+ CpuContext->Dr3 = 0;
+ CpuContext->Dr7 &= (UINTN)(~(0x3 << 6));
+ }
+}
+
+
+/**
+ Return the offset of FP / MMX / XMM registers in the FPU saved state by register index.
+
+ @param[in] Index Register index.
+ @param[out] Width Register width returned.
+
+ @return Offset in the FPU Save State.
+
+**/
+UINT16
+ArchReadFxStatOffset (
+ IN UINT8 Index,
+ OUT UINT8 *Width
+ )
+{
+ if (Index < SOFT_DEBUGGER_REGISTER_ST0) {
+ switch (Index) {
+ case SOFT_DEBUGGER_REGISTER_FP_FCW:
+ *Width = (UINT8) sizeof (UINT16);
+ return OFFSET_OF(DEBUG_DATA_FX_SAVE_STATE, Fcw);
+
+ case SOFT_DEBUGGER_REGISTER_FP_FSW:
+ *Width = (UINT8) sizeof (UINT16);
+ return OFFSET_OF(DEBUG_DATA_FX_SAVE_STATE, Fsw);
+
+ case SOFT_DEBUGGER_REGISTER_FP_FTW:
+ *Width = (UINT8) sizeof (UINT16);
+ return OFFSET_OF(DEBUG_DATA_FX_SAVE_STATE, Ftw);
+
+ case SOFT_DEBUGGER_REGISTER_FP_OPCODE:
+ *Width = (UINT8) sizeof (UINT16);
+ return OFFSET_OF(DEBUG_DATA_FX_SAVE_STATE, Opcode);
+
+ case SOFT_DEBUGGER_REGISTER_FP_EIP:
+ *Width = (UINT8) sizeof (UINT32);
+ return OFFSET_OF(DEBUG_DATA_FX_SAVE_STATE, Eip);
+
+ case SOFT_DEBUGGER_REGISTER_FP_CS:
+ *Width = (UINT8) sizeof (UINT16);
+ return OFFSET_OF(DEBUG_DATA_FX_SAVE_STATE, Cs);
+
+ case SOFT_DEBUGGER_REGISTER_FP_DATAOFFSET:
+ *Width = (UINT8) sizeof (UINT32);
+ return OFFSET_OF(DEBUG_DATA_FX_SAVE_STATE, DataOffset);
+
+ case SOFT_DEBUGGER_REGISTER_FP_DS:
+ *Width = (UINT8) sizeof (UINT16);
+ return OFFSET_OF(DEBUG_DATA_FX_SAVE_STATE, Ds);
+
+ case SOFT_DEBUGGER_REGISTER_FP_MXCSR:
+ *Width = (UINT8) sizeof (UINT32);
+ return OFFSET_OF(DEBUG_DATA_FX_SAVE_STATE, Mxcsr);
+
+ case SOFT_DEBUGGER_REGISTER_FP_MXCSR_MASK:
+ *Width = (UINT8) sizeof (UINT32);
+ return OFFSET_OF(DEBUG_DATA_FX_SAVE_STATE, Mxcsr_Mask);
+ }
+ }
+
+ if (Index <= SOFT_DEBUGGER_REGISTER_ST7) {
+ *Width = 10;
+ } else if (Index <= SOFT_DEBUGGER_REGISTER_XMM15) {
+ *Width = 16;
+ } else {
+ //
+ // MMX register
+ //
+ *Width = 8;
+ Index -= SOFT_DEBUGGER_REGISTER_MM0 - SOFT_DEBUGGER_REGISTER_ST0;
+ }
+
+ return OFFSET_OF (DEBUG_DATA_FX_SAVE_STATE, St0Mm0) + (Index - SOFT_DEBUGGER_REGISTER_ST0) * 16;
+}
+
+/**
+ Return the pointer of the register value in the CPU saved context.
+
+ @param[in] CpuContext Pointer to saved CPU context.
+ @param[in] Index Register index value.
+ @param[out] Width Data width to read.
+
+ @return The pointer in the CPU saved context.
+
+**/
+UINT8 *
+ArchReadRegisterBuffer (
+ IN DEBUG_CPU_CONTEXT *CpuContext,
+ IN UINT8 Index,
+ OUT UINT8 *Width
+ )
+{
+ UINT8 *Buffer;
+
+ if (Index < SOFT_DEBUGGER_REGISTER_FP_BASE) {
+ Buffer = (UINT8 *) CpuContext + OFFSET_OF (DEBUG_CPU_CONTEXT, Dr0) + Index * sizeof (UINTN);
+ *Width = (UINT8) sizeof (UINTN);
+ } else {
+ //
+ // FPU/MMX/XMM registers
+ //
+ Buffer = (UINT8 *) CpuContext + OFFSET_OF (DEBUG_CPU_CONTEXT, FxSaveState) + ArchReadFxStatOffset (Index, Width);
+ }
+
+ return Buffer;
+}
+
+/**
+ Send the packet without data to HOST.
+
+ @param[in] CommandType Type of Command.
+ @param[in] SequenceNo Sequence number.
+
+**/
+VOID
+SendPacketWithoutData (
+ IN UINT8 CommandType,
+ IN UINT8 SequenceNo
+ )
+{
+ DEBUG_PACKET_HEADER DebugHeader;
+ DEBUG_PORT_HANDLE Handle;
+
+ Handle = GetDebugPortHandle();
+
+ DebugHeader.StartSymbol = DEBUG_STARTING_SYMBOL_NORMAL;
+ DebugHeader.Command = CommandType;
+ DebugHeader.Length = sizeof (DEBUG_PACKET_HEADER);
+ DebugHeader.SequenceNo = SequenceNo;
+ DebugHeader.Crc = 0;
+ DebugHeader.Crc = CalculateCrc16 ((UINT8 *)&DebugHeader, sizeof (DEBUG_PACKET_HEADER), 0);
+
+ DebugAgentDataMsgPrint (DEBUG_AGENT_VERBOSE, TRUE, (UINT8 *) &DebugHeader, DebugHeader.Length);
+ DebugPortWriteBuffer (Handle, (UINT8 *) &DebugHeader, DebugHeader.Length);
+}
+
+/**
+ Send acknowledge packet to HOST.
+
+ @param[in] AckCommand Type of Acknowledge packet.
+
+**/
+VOID
+SendAckPacket (
+ IN UINT8 AckCommand
+ )
+{
+ UINT8 SequenceNo;
+ DEBUG_AGENT_MAILBOX *Mailbox;
+
+ if (AckCommand != DEBUG_COMMAND_OK) {
+ //
+ // This is not ACK OK packet
+ //
+ DebugAgentMsgPrint (DEBUG_AGENT_ERROR, "Send ACK(%d)\n", AckCommand);
+ }
+ Mailbox = GetMailboxPointer();
+ SequenceNo = Mailbox->HostSequenceNo;
+ DebugAgentMsgPrint (DEBUG_AGENT_INFO, "SendAckPacket: SequenceNo = %x\n", SequenceNo);
+ SendPacketWithoutData (AckCommand, SequenceNo);
+ UpdateMailboxContent (Mailbox, DEBUG_MAILBOX_LAST_ACK, AckCommand);
+}
+
+/**
+ Decompress the Data in place.
+
+ @param[in, out] Data The compressed data buffer.
+ The buffer is assumed large enough to hold the uncompressed data.
+ @param[in] Length The length of the compressed data buffer.
+
+ @return The length of the uncompressed data buffer.
+**/
+UINT8
+DecompressDataInPlace (
+ IN OUT UINT8 *Data,
+ IN UINTN Length
+ )
+{
+ UINTN Index;
+ UINT16 LastChar;
+ UINTN LastCharCount;
+ UINT8 CurrentChar;
+
+ LastChar = (UINT16) -1;
+ LastCharCount = 0;
+ for (Index = 0; Index < Length; Index++) {
+ CurrentChar = Data[Index];
+ if (LastCharCount == 2) {
+ LastCharCount = 0;
+ CopyMem (&Data[Index + CurrentChar], &Data[Index + 1], Length - Index - 1);
+ SetMem (&Data[Index], CurrentChar, (UINT8) LastChar);
+ LastChar = (UINT16) -1;
+ Index += CurrentChar - 1;
+ Length += CurrentChar - 1;
+ } else {
+ if (LastChar != CurrentChar) {
+ LastCharCount = 0;
+ }
+ LastCharCount++;
+ LastChar = CurrentChar;
+ }
+ }
+
+ ASSERT (Length <= DEBUG_DATA_MAXIMUM_REAL_DATA);
+
+ return (UINT8) Length;
+}
+
+/**
+ Receive valid packet from HOST.
+
+ @param[out] InputPacket Buffer to receive packet.
+ @param[out] BreakReceived TRUE means break-in symbol received.
+ FALSE means break-in symbol not received.
+ @param[out] IncompatibilityFlag If IncompatibilityFlag is not NULL, return
+ TRUE: Compatible packet received.
+ FALSE: Incompatible packet received.
+ @param[in] Timeout Time out value to wait for acknowledge from HOST.
+ The unit is microsecond.
+ @param[in] SkipStartSymbol TRUE: Skip time out when reading start symbol.
+ FALSE: Does not Skip time out when reading start symbol.
+
+ @retval RETURN_SUCCESS A valid package was received in InputPacket.
+ @retval RETURN_TIMEOUT Timeout occurs.
+
+**/
+RETURN_STATUS
+ReceivePacket (
+ OUT UINT8 *InputPacket,
+ OUT BOOLEAN *BreakReceived,
+ OUT BOOLEAN *IncompatibilityFlag, OPTIONAL
+ IN UINTN Timeout,
+ IN BOOLEAN SkipStartSymbol
+ )
+{
+ DEBUG_PACKET_HEADER *DebugHeader;
+ UINTN Received;
+ DEBUG_PORT_HANDLE Handle;
+ UINT16 Crc;
+ UINTN TimeoutForStartSymbol;
+
+ Handle = GetDebugPortHandle();
+ if (SkipStartSymbol) {
+ TimeoutForStartSymbol = 0;
+ } else {
+ TimeoutForStartSymbol = Timeout;
+ }
+
+ DebugHeader = (DEBUG_PACKET_HEADER *) InputPacket;
+ while (TRUE) {
+ //
+ // Find the valid start symbol
+ //
+ Received = DebugAgentReadBuffer (Handle, &DebugHeader->StartSymbol, sizeof (DebugHeader->StartSymbol), TimeoutForStartSymbol);
+ if (Received < sizeof (DebugHeader->StartSymbol)) {
+ DebugAgentMsgPrint (DEBUG_AGENT_WARNING, "DebugAgentReadBuffer(StartSymbol) timeout\n");
+ return RETURN_TIMEOUT;
+ }
+
+ if ((DebugHeader->StartSymbol != DEBUG_STARTING_SYMBOL_NORMAL) && (DebugHeader->StartSymbol != DEBUG_STARTING_SYMBOL_COMPRESS)) {
+ DebugAgentMsgPrint (DEBUG_AGENT_WARNING, "Invalid start symbol received [%02x]\n", DebugHeader->StartSymbol);
+ continue;
+ }
+
+ //
+ // Read Package header till field Length
+ //
+ Received = DebugAgentReadBuffer (
+ Handle,
+ (UINT8 *) DebugHeader + OFFSET_OF (DEBUG_PACKET_HEADER, Command),
+ OFFSET_OF (DEBUG_PACKET_HEADER, Length) + sizeof (DebugHeader->Length) - sizeof (DebugHeader->StartSymbol),
+ Timeout
+ );
+ if (Received == 0) {
+ DebugAgentMsgPrint (DEBUG_AGENT_ERROR, "DebugAgentReadBuffer(Command) timeout\n");
+ return RETURN_TIMEOUT;
+ }
+ if (DebugHeader->Length < sizeof (DEBUG_PACKET_HEADER)) {
+ if (IncompatibilityFlag != NULL) {
+ //
+ // This is one old version debug packet format, set Incompatibility flag
+ //
+ *IncompatibilityFlag = TRUE;
+ } else {
+ //
+ // Skip the bad small packet
+ //
+ continue;
+ }
+ } else {
+ //
+ // Read the payload data include the CRC field
+ //
+ Received = DebugAgentReadBuffer (Handle, &DebugHeader->SequenceNo, (UINT8) (DebugHeader->Length - OFFSET_OF (DEBUG_PACKET_HEADER, SequenceNo)), Timeout);
+ if (Received == 0) {
+ DebugAgentMsgPrint (DEBUG_AGENT_ERROR, "DebugAgentReadBuffer(SequenceNo) timeout\n");
+ return RETURN_TIMEOUT;
+ }
+ //
+ // Calculate the CRC of Debug Packet
+ //
+ Crc = DebugHeader->Crc;
+ DebugHeader->Crc = 0;
+ if (Crc == CalculateCrc16 ((UINT8 *) DebugHeader, DebugHeader->Length, 0)) {
+ break;
+ }
+ DebugAgentMsgPrint (DEBUG_AGENT_WARNING, "CRC Error (received CRC is %x)\n", Crc);
+ DebugAgentDataMsgPrint (DEBUG_AGENT_VERBOSE, FALSE, (UINT8 *) DebugHeader, DebugHeader->Length);
+ }
+ }
+
+ DebugAgentDataMsgPrint (DEBUG_AGENT_VERBOSE, FALSE, (UINT8 *) DebugHeader, DebugHeader->Length);
+
+ if (DebugHeader->StartSymbol == DEBUG_STARTING_SYMBOL_COMPRESS) {
+ DebugHeader->StartSymbol = DEBUG_STARTING_SYMBOL_NORMAL;
+ DebugHeader->Length = DecompressDataInPlace (
+ (UINT8 *) (DebugHeader + 1), DebugHeader->Length - sizeof (DEBUG_PACKET_HEADER)
+ ) + sizeof (DEBUG_PACKET_HEADER);
+ }
+ return RETURN_SUCCESS;
+}
+
+/**
+ Receive acknowledge packet OK from HOST in specified time.
+
+ @param[in] Command The command type issued by TARGET.
+ @param[in] Timeout Time out value to wait for acknowledge from HOST.
+ The unit is microsecond.
+ @param[out] BreakReceived If BreakReceived is not NULL,
+ TRUE is returned if break-in symbol received.
+ FALSE is returned if break-in symbol not received.
+ @param[out] IncompatibilityFlag If IncompatibilityFlag is not NULL, return
+ TRUE: Compatible packet received.
+ FALSE: Incompatible packet received.
+
+ @retval RETURN_SUCCESS Succeed to receive acknowledge packet from HOST,
+ the type of acknowledge packet saved in Ack.
+ @retval RETURN_TIMEOUT Specified timeout value was up.
+
+**/
+RETURN_STATUS
+SendCommandAndWaitForAckOK (
+ IN UINT8 Command,
+ IN UINTN Timeout,
+ OUT BOOLEAN *BreakReceived, OPTIONAL
+ OUT BOOLEAN *IncompatibilityFlag OPTIONAL
+ )
+{
+ RETURN_STATUS Status;
+ UINT8 InputPacketBuffer[DEBUG_DATA_UPPER_LIMIT];
+ DEBUG_PACKET_HEADER *DebugHeader;
+ UINT8 SequenceNo;
+ UINT8 HostSequenceNo;
+ UINT8 RetryCount;
+
+ RetryCount = 3;
+ DebugHeader = (DEBUG_PACKET_HEADER *) InputPacketBuffer;
+ Status = RETURN_TIMEOUT;
+ while (RetryCount > 0) {
+ SequenceNo = GetMailboxPointer()->SequenceNo;
+ HostSequenceNo = GetMailboxPointer()->HostSequenceNo;
+ SendPacketWithoutData (Command, SequenceNo);
+ Status = ReceivePacket ((UINT8 *) DebugHeader, BreakReceived, IncompatibilityFlag, Timeout, FALSE);
+ if (Status == RETURN_TIMEOUT) {
+ if (Command == DEBUG_COMMAND_INIT_BREAK) {
+ RetryCount--;
+ } else {
+ DebugAgentMsgPrint (DEBUG_AGENT_WARNING, "TARGET: Timeout when waiting for ACK packet.\n");
+ }
+ continue;
+ }
+ ASSERT_EFI_ERROR (Status);
+ //
+ // Status == RETURN_SUCCESS
+ //
+ if (DebugHeader->Command == DEBUG_COMMAND_OK && DebugHeader->SequenceNo == SequenceNo) {
+ //
+ // Received Ack OK
+ //
+ UpdateMailboxContent (GetMailboxPointer(), DEBUG_MAILBOX_SEQUENCE_NO_INDEX, ++SequenceNo);
+ return Status;
+ }
+ if (DebugHeader->Command == DEBUG_COMMAND_GO && (DebugHeader->SequenceNo == HostSequenceNo || Command == DEBUG_COMMAND_INIT_BREAK)) {
+ //
+ // Received Old GO
+ //
+ if (Command == DEBUG_COMMAND_INIT_BREAK) {
+ DebugAgentMsgPrint (DEBUG_AGENT_WARNING, "TARGET: Receive GO() in last boot\n");
+ }
+ SendPacketWithoutData (DEBUG_COMMAND_OK, DebugHeader->SequenceNo);
+ }
+ }
+
+ ASSERT (Command == DEBUG_COMMAND_INIT_BREAK);
+ return Status;
+}
+
+/**
+ Get current break cause.
+
+ @param[in] Vector Vector value of exception or interrupt.
+ @param[in] CpuContext Pointer to save CPU context.
+
+ @return The type of break cause defined by XXXX
+
+**/
+UINT8
+GetBreakCause (
+ IN UINTN Vector,
+ IN DEBUG_CPU_CONTEXT *CpuContext
+ )
+{
+ UINT8 Cause;
+
+ Cause = DEBUG_DATA_BREAK_CAUSE_UNKNOWN;
+
+ switch (Vector) {
+ case DEBUG_INT1_VECTOR:
+ case DEBUG_INT3_VECTOR:
+
+ if (Vector == DEBUG_INT1_VECTOR) {
+ //
+ // INT 1
+ //
+ if ((CpuContext->Dr6 & BIT14) != 0) {
+ Cause = DEBUG_DATA_BREAK_CAUSE_STEPPING;
+ //
+ // DR6.BIT14 Indicates (when set) that the debug exception was
+ // triggered by the single step execution mode.
+ // The single-step mode is the highest priority debug exception.
+ // This is single step, no need to check DR0, to ensure single step
+ // work in PeCoffExtraActionLib (right after triggering a breakpoint
+ // to report image load/unload).
+ //
+ return Cause;
+
+ } else {
+ Cause = DEBUG_DATA_BREAK_CAUSE_HW_BREAKPOINT;
+ }
+ } else {
+ //
+ // INT 3
+ //
+ Cause = DEBUG_DATA_BREAK_CAUSE_SW_BREAKPOINT;
+ }
+
+ switch (CpuContext->Dr0) {
+ case IMAGE_LOAD_SIGNATURE:
+ case IMAGE_UNLOAD_SIGNATURE:
+
+ if (CpuContext->Dr3 == IO_PORT_BREAKPOINT_ADDRESS) {
+
+ Cause = (UINT8) ((CpuContext->Dr0 == IMAGE_LOAD_SIGNATURE) ?
+ DEBUG_DATA_BREAK_CAUSE_IMAGE_LOAD : DEBUG_DATA_BREAK_CAUSE_IMAGE_UNLOAD);
+ }
+ break;
+
+ case SOFT_INTERRUPT_SIGNATURE:
+
+ if (CpuContext->Dr1 == MEMORY_READY_SIGNATURE) {
+ Cause = DEBUG_DATA_BREAK_CAUSE_MEMORY_READY;
+ CpuContext->Dr0 = 0;
+ } else if (CpuContext->Dr1 == SYSTEM_RESET_SIGNATURE) {
+ Cause = DEBUG_DATA_BREAK_CAUSE_SYSTEM_RESET;
+ CpuContext->Dr0 = 0;
+ }
+ break;
+
+ default:
+ break;
+
+ }
+
+ break;
+
+ case DEBUG_TIMER_VECTOR:
+ Cause = DEBUG_DATA_BREAK_CAUSE_USER_HALT;
+ break;
+
+ default:
+ if (Vector < 20) {
+ if (GetDebugFlag (DEBUG_AGENT_FLAG_STEPPING) == 1) {
+ //
+ // If stepping command is executing
+ //
+ Cause = DEBUG_DATA_BREAK_CAUSE_STEPPING;
+ } else {
+ Cause = DEBUG_DATA_BREAK_CAUSE_EXCEPTION;
+ }
+ }
+ break;
+ }
+
+ return Cause;
+}
+
+/**
+ Copy memory from source to destination with specified width.
+
+ @param[out] Dest A pointer to the destination buffer of the memory copy.
+ @param[in] Src A pointer to the source buffer of the memory copy.
+ @param[in] Count The number of data with specified width to copy from source to destination.
+ @param[in] Width Data width in byte.
+
+**/
+VOID
+CopyMemByWidth (
+ OUT UINT8 *Dest,
+ IN UINT8 *Src,
+ IN UINT16 Count,
+ IN UINT8 Width
+ )
+{
+ UINT8 *Destination;
+ UINT8 *Source;
+ INT8 Step;
+
+ if (Src > Dest) {
+ Destination = Dest;
+ Source = Src;
+ Step = Width;
+ } else {
+ //
+ // Copy memory from tail to avoid memory overlap
+ //
+ Destination = Dest + (Count - 1) * Width;
+ Source = Src + (Count - 1) * Width;
+ Step = -Width;
+ }
+
+ while (Count-- != 0) {
+ switch (Width) {
+ case 1:
+ *(UINT8 *) Destination = MmioRead8 ((UINTN) Source);
+ break;
+ case 2:
+ *(UINT16 *) Destination = MmioRead16 ((UINTN) Source);
+ break;
+ case 4:
+ *(UINT32 *) Destination = MmioRead32 ((UINTN) Source);
+ break;
+ case 8:
+ *(UINT64 *) Destination = MmioRead64 ((UINTN) Source);
+ break;
+ default:
+ ASSERT (FALSE);
+ }
+ Source += Step;
+ Destination += Step;
+ }
+}
+
+/**
+ Compress the data buffer but do not modify the original buffer.
+
+ The compressed data is directly send to the debug channel.
+ Compressing in place doesn't work because the data may become larger
+ during compressing phase. ("3 3 ..." --> "3 3 0 ...")
+ The routine is expected to be called three times:
+ 1. Compute the length of the compressed data buffer;
+ 2. Compute the CRC of the compressed data buffer;
+ 3. Compress the data and send to the debug channel.
+
+ @param[in] Handle The debug channel handle to send the compressed data buffer.
+ @param[in] Data The data buffer.
+ @param[in] Length The length of the data buffer.
+ @param[in] Send TRUE to send the compressed data buffer.
+ @param[out] CompressedLength Return the length of the compressed data buffer.
+ It may be larger than the Length in some cases.
+ @param[out] CompressedCrc Return the CRC of the compressed data buffer.
+**/
+VOID
+CompressData (
+ IN DEBUG_PORT_HANDLE Handle,
+ IN UINT8 *Data,
+ IN UINT8 Length,
+ IN BOOLEAN Send,
+ OUT UINTN *CompressedLength, OPTIONAL
+ OUT UINT16 *CompressedCrc OPTIONAL
+ )
+{
+ UINTN Index;
+ UINT8 LastChar;
+ UINT8 LastCharCount;
+ UINT8 CurrentChar;
+ UINTN CompressedIndex;
+
+ ASSERT (Length > 0);
+ LastChar = Data[0] + 1; // Just ensure it's different from the first byte.
+ LastCharCount = 0;
+
+ for (Index = 0, CompressedIndex = 0; Index <= Length; Index++) {
+ if (Index < Length) {
+ CurrentChar = Data[Index];
+ } else {
+ CurrentChar = (UINT8) LastChar + 1; // just ensure it's different from LastChar
+ }
+ if (LastChar != CurrentChar) {
+ if (LastCharCount == 1) {
+ CompressedIndex++;
+ if (CompressedCrc != NULL) {
+ *CompressedCrc = CalculateCrc16 (&LastChar, 1, *CompressedCrc);
+ }
+ if (Send) {
+ DebugPortWriteBuffer (Handle, &LastChar, 1);
+ }
+
+ } else if (LastCharCount >= 2) {
+ CompressedIndex += 3;
+ LastCharCount -= 2;
+ if (CompressedCrc != NULL) {
+ *CompressedCrc = CalculateCrc16 (&LastChar, 1, *CompressedCrc);
+ *CompressedCrc = CalculateCrc16 (&LastChar, 1, *CompressedCrc);
+ *CompressedCrc = CalculateCrc16 (&LastCharCount, 1, *CompressedCrc);
+ }
+ if (Send) {
+ DebugPortWriteBuffer (Handle, &LastChar, 1);
+ DebugPortWriteBuffer (Handle, &LastChar, 1);
+ DebugPortWriteBuffer (Handle, &LastCharCount, 1);
+ }
+ }
+ LastCharCount = 0;
+ }
+ LastCharCount++;
+ LastChar = CurrentChar;
+ }
+
+ if (CompressedLength != NULL) {
+ *CompressedLength = CompressedIndex;
+ }
+}
+
+/**
+ Read memory with specified width and send packet with response data to HOST.
+
+ @param[in] Data Pointer to response data buffer.
+ @param[in] Count The number of data with specified Width.
+ @param[in] Width Data width in byte.
+ @param[in] DebugHeader Pointer to a buffer for creating response packet and receiving ACK packet,
+ to minimize the stack usage.
+
+ @retval RETURN_SUCCESS Response data was sent successfully.
+
+**/
+RETURN_STATUS
+ReadMemoryAndSendResponsePacket (
+ IN UINT8 *Data,
+ IN UINT16 Count,
+ IN UINT8 Width,
+ IN DEBUG_PACKET_HEADER *DebugHeader
+ )
+{
+ RETURN_STATUS Status;
+ BOOLEAN LastPacket;
+ DEBUG_PORT_HANDLE Handle;
+ UINT8 SequenceNo;
+ UINTN RemainingDataSize;
+ UINT8 CurrentDataSize;
+ UINTN CompressedDataSize;
+
+ Handle = GetDebugPortHandle();
+
+ RemainingDataSize = Count * Width;
+ while (TRUE) {
+ SequenceNo = GetMailboxPointer()->HostSequenceNo;
+ if (RemainingDataSize <= DEBUG_DATA_MAXIMUM_REAL_DATA) {
+ //
+ // If the remaining data is less one real packet size, this is the last data packet
+ //
+ CurrentDataSize = (UINT8) RemainingDataSize;
+ LastPacket = TRUE;
+ DebugHeader->Command = DEBUG_COMMAND_OK;
+ } else {
+ //
+ // Data is too larger to be sent in one packet, calculate the actual data size could
+ // be sent in one Maximum data packet
+ //
+ CurrentDataSize = (DEBUG_DATA_MAXIMUM_REAL_DATA / Width) * Width;
+ LastPacket = FALSE;
+ DebugHeader->Command = DEBUG_COMMAND_IN_PROGRESS;
+ }
+ //
+ // Construct the rest Debug header
+ //
+ DebugHeader->StartSymbol = DEBUG_STARTING_SYMBOL_NORMAL;
+ DebugHeader->Length = CurrentDataSize + sizeof (DEBUG_PACKET_HEADER);
+ DebugHeader->SequenceNo = SequenceNo;
+ DebugHeader->Crc = 0;
+ CopyMemByWidth ((UINT8 *) (DebugHeader + 1), Data, CurrentDataSize / Width, Width);
+
+ //
+ // Compression/decompression support was added since revision 0.4.
+ // Revision 0.3 shouldn't compress the packet.
+ //
+ if (PcdGet32(PcdTransferProtocolRevision) >= DEBUG_AGENT_REVISION_04) {
+ //
+ // Get the compressed data size without modifying the packet.
+ //
+ CompressData (
+ Handle,
+ (UINT8 *) (DebugHeader + 1),
+ CurrentDataSize,
+ FALSE,
+ &CompressedDataSize,
+ NULL
+ );
+ } else {
+ CompressedDataSize = CurrentDataSize;
+ }
+ if (CompressedDataSize < CurrentDataSize) {
+ DebugHeader->Length = (UINT8) CompressedDataSize + sizeof (DEBUG_PACKET_HEADER);
+ DebugHeader->StartSymbol = DEBUG_STARTING_SYMBOL_COMPRESS;
+ //
+ // Compute the CRC of the packet head without modifying the packet.
+ //
+ DebugHeader->Crc = CalculateCrc16 ((UINT8 *) DebugHeader, sizeof (DEBUG_PACKET_HEADER), 0);
+ CompressData (
+ Handle,
+ (UINT8 *) (DebugHeader + 1),
+ CurrentDataSize,
+ FALSE,
+ NULL,
+ &DebugHeader->Crc
+ );
+ //
+ // Send out the packet head.
+ //
+ DebugPortWriteBuffer (Handle, (UINT8 *) DebugHeader, sizeof (DEBUG_PACKET_HEADER));
+ //
+ // Compress and send out the packet data.
+ //
+ CompressData (
+ Handle,
+ (UINT8 *) (DebugHeader + 1),
+ CurrentDataSize,
+ TRUE,
+ NULL,
+ NULL
+ );
+ } else {
+
+ //
+ // Calculate and fill the checksum, DebugHeader->Crc should be 0 before invoking CalculateCrc16 ()
+ //
+ DebugHeader->Crc = CalculateCrc16 ((UINT8 *) DebugHeader, DebugHeader->Length, 0);
+
+ DebugAgentDataMsgPrint (DEBUG_AGENT_VERBOSE, TRUE, (UINT8 *) DebugHeader, DebugHeader->Length);
+
+ DebugPortWriteBuffer (Handle, (UINT8 *) DebugHeader, DebugHeader->Length);
+ }
+
+ while (TRUE) {
+ Status = ReceivePacket ((UINT8 *) DebugHeader, NULL, NULL, READ_PACKET_TIMEOUT, FALSE);
+ if (Status == RETURN_TIMEOUT) {
+ DebugAgentMsgPrint (DEBUG_AGENT_WARNING, "TARGET: Timeout in SendDataResponsePacket()\n");
+ break;
+ }
+ if ((DebugHeader->Command == DEBUG_COMMAND_OK) && (DebugHeader->SequenceNo == SequenceNo) && LastPacket) {
+ //
+ // If this is the last packet, return RETURN_SUCCESS.
+ //
+ return RETURN_SUCCESS;
+ }
+ if ((DebugHeader->Command == DEBUG_COMMAND_CONTINUE) && (DebugHeader->SequenceNo == (UINT8) (SequenceNo + 1))) {
+ //
+ // Calculate the rest data size
+ //
+ Data += CurrentDataSize;
+ RemainingDataSize -= CurrentDataSize;
+ UpdateMailboxContent (GetMailboxPointer(), DEBUG_MAILBOX_HOST_SEQUENCE_NO_INDEX, DebugHeader->SequenceNo);
+ break;
+ }
+ if (DebugHeader->SequenceNo >= SequenceNo) {
+ DebugAgentMsgPrint (DEBUG_AGENT_WARNING, "TARGET: Received one old or new command(SequenceNo is %x, last SequenceNo is %x)\n", SequenceNo, DebugHeader->SequenceNo);
+ break;
+ }
+ }
+ }
+}
+
+/**
+ Send packet with response data to HOST.
+
+ @param[in] Data Pointer to response data buffer.
+ @param[in] DataSize Size of response data in byte.
+ @param[in, out] DebugHeader Pointer to a buffer for creating response packet and receiving ACK packet,
+ to minimize the stack usage.
+
+ @retval RETURN_SUCCESS Response data was sent successfully.
+
+**/
+RETURN_STATUS
+SendDataResponsePacket (
+ IN UINT8 *Data,
+ IN UINT16 DataSize,
+ IN OUT DEBUG_PACKET_HEADER *DebugHeader
+ )
+{
+ return ReadMemoryAndSendResponsePacket (Data, DataSize, 1, DebugHeader);
+}
+
+/**
+ Try to attach the HOST.
+
+ Send init break packet to HOST:
+ If no acknowledge received in specified Timeout, return RETURN_TIMEOUT.
+ If received acknowledge, check the revision of HOST.
+ Set Attach Flag if attach successfully.
+
+ @param[in] BreakCause Break cause of this break event.
+ @param[in] Timeout Time out value to wait for acknowledge from HOST.
+ The unit is microsecond.
+ @param[out] BreakReceived If BreakReceived is not NULL,
+ TRUE is returned if break-in symbol received.
+ FALSE is returned if break-in symbol not received.
+**/
+RETURN_STATUS
+AttachHost (
+ IN UINT8 BreakCause,
+ IN UINTN Timeout,
+ OUT BOOLEAN *BreakReceived
+ )
+{
+ RETURN_STATUS Status;
+ DEBUG_PORT_HANDLE Handle;
+ BOOLEAN IncompatibilityFlag;
+
+ IncompatibilityFlag = FALSE;
+ Handle = GetDebugPortHandle();
+
+ //
+ // Send init break and wait ack in Timeout
+ //
+ DebugPortWriteBuffer (Handle, (UINT8 *) mErrorMsgSendInitPacket, AsciiStrLen (mErrorMsgSendInitPacket));
+ if (BreakCause == DEBUG_DATA_BREAK_CAUSE_SYSTEM_RESET) {
+ Status = SendCommandAndWaitForAckOK (DEBUG_COMMAND_INIT_BREAK, Timeout, BreakReceived, &IncompatibilityFlag);
+ } else {
+ Status = SendCommandAndWaitForAckOK (DEBUG_COMMAND_ATTACH_BREAK, Timeout, BreakReceived, &IncompatibilityFlag);
+ }
+ if (IncompatibilityFlag) {
+ //
+ // If the incompatible Debug Packet received, the HOST should be running transfer protocol before PcdTransferProtocolRevision.
+ // It could be UDK Debugger for Windows v1.1/v1.2 or for Linux v0.8/v1.2.
+ //
+ DebugPortWriteBuffer (Handle, (UINT8 *) mErrorMsgVersionAlert, AsciiStrLen (mErrorMsgVersionAlert));
+ CpuDeadLoop ();
+ }
+
+ if (RETURN_ERROR (Status)) {
+ DebugPortWriteBuffer (Handle, (UINT8 *) mErrorMsgConnectFail, AsciiStrLen (mErrorMsgConnectFail));
+ } else {
+ DebugPortWriteBuffer (Handle, (UINT8 *) mErrorMsgConnectOK, AsciiStrLen (mErrorMsgConnectOK));
+ //
+ // Set Attach flag
+ //
+ SetHostAttached (TRUE);
+ }
+ return Status;
+}
+
+/**
+ Send Break point packet to HOST.
+
+ Only the first breaking processor could sent BREAK_POINT packet.
+
+ @param[in] BreakCause Break cause of this break event.
+ @param[in] ProcessorIndex Processor index value.
+ @param[out] BreakReceived If BreakReceived is not NULL,
+ TRUE is returned if break-in symbol received.
+ FALSE is returned if break-in symbol not received.
+
+**/
+VOID
+SendBreakPacketToHost (
+ IN UINT8 BreakCause,
+ IN UINT32 ProcessorIndex,
+ OUT BOOLEAN *BreakReceived
+ )
+{
+ UINT8 InputCharacter;
+ DEBUG_PORT_HANDLE Handle;
+
+ Handle = GetDebugPortHandle();
+
+ if (IsHostAttached ()) {
+ DebugAgentMsgPrint (DEBUG_AGENT_INFO, "processor[%x]:Send Break Packet to HOST.\n", ProcessorIndex);
+ SendCommandAndWaitForAckOK (DEBUG_COMMAND_BREAK_POINT, READ_PACKET_TIMEOUT, BreakReceived, NULL);
+ } else {
+ DebugAgentMsgPrint (DEBUG_AGENT_INFO, "processor[%x]:Try to attach HOST.\n", ProcessorIndex);
+ //
+ // If HOST is not attached, try to attach it firstly.
+ //
+ //
+ // Poll Attach symbols from HOST and ack OK
+ //
+ do {
+ DebugAgentReadBuffer (Handle, &InputCharacter, 1, 0);
+ } while (InputCharacter != DEBUG_STARTING_SYMBOL_ATTACH);
+ SendAckPacket (DEBUG_COMMAND_OK);
+
+ //
+ // Try to attach HOST
+ //
+ while (AttachHost (BreakCause, 0, NULL) != RETURN_SUCCESS);
+
+ }
+}
+
+/**
+ The main function to process communication with HOST.
+
+ It received the command packet from HOST, and sent response data packet to HOST.
+
+ @param[in] Vector Vector value of exception or interrupt.
+ @param[in, out] CpuContext Pointer to saved CPU context.
+ @param[in] BreakReceived TRUE means break-in symbol received.
+ FALSE means break-in symbol not received.
+
+**/
+VOID
+CommandCommunication (
+ IN UINTN Vector,
+ IN OUT DEBUG_CPU_CONTEXT *CpuContext,
+ IN BOOLEAN BreakReceived
+ )
+{
+ RETURN_STATUS Status;
+ UINT8 InputPacketBuffer[DEBUG_DATA_UPPER_LIMIT + sizeof (UINT64) - 1];
+ DEBUG_PACKET_HEADER *DebugHeader;
+ UINT8 Width;
+ UINT8 Data8;
+ UINT32 Data32;
+ UINT64 Data64;
+ DEBUG_DATA_READ_MEMORY *MemoryRead;
+ DEBUG_DATA_WRITE_MEMORY *MemoryWrite;
+ DEBUG_DATA_READ_IO *IoRead;
+ DEBUG_DATA_WRITE_IO *IoWrite;
+ DEBUG_DATA_READ_REGISTER *RegisterRead;
+ DEBUG_DATA_WRITE_REGISTER *RegisterWrite;
+ UINT8 *RegisterBuffer;
+ DEBUG_DATA_READ_MSR *MsrRegisterRead;
+ DEBUG_DATA_WRITE_MSR *MsrRegisterWrite;
+ DEBUG_DATA_CPUID *Cpuid;
+ DEBUG_DATA_RESPONSE_BREAK_CAUSE BreakCause;
+ DEBUG_DATA_RESPONSE_CPUID CpuidResponse;
+ DEBUG_DATA_SEARCH_SIGNATURE *SearchSignature;
+ DEBUG_DATA_RESPONSE_GET_EXCEPTION Exception;
+ DEBUG_DATA_RESPONSE_GET_REVISION DebugAgentRevision;
+ DEBUG_DATA_SET_VIEWPOINT *SetViewPoint;
+ BOOLEAN HaltDeferred;
+ UINT32 ProcessorIndex;
+ DEBUG_AGENT_EXCEPTION_BUFFER AgentExceptionBuffer;
+ UINT32 IssuedViewPoint;
+ DEBUG_AGENT_MAILBOX *Mailbox;
+ UINT8 *AlignedDataPtr;
+
+ ProcessorIndex = 0;
+ IssuedViewPoint = 0;
+ HaltDeferred = BreakReceived;
+
+ if (MultiProcessorDebugSupport()) {
+ ProcessorIndex = GetProcessorIndex ();
+ SetCpuStopFlagByIndex (ProcessorIndex, TRUE);
+ if (mDebugMpContext.ViewPointIndex == ProcessorIndex) {
+ //
+ // Only the current view processor could set AgentInProgress Flag.
+ //
+ IssuedViewPoint = ProcessorIndex;
+ }
+ }
+
+ if (IssuedViewPoint == ProcessorIndex) {
+ //
+ // Set AgentInProgress Flag.
+ //
+ SetDebugFlag (DEBUG_AGENT_FLAG_AGENT_IN_PROGRESS, 1);
+ }
+
+ while (TRUE) {
+
+ if (MultiProcessorDebugSupport()) {
+ //
+ // Check if the current processor is HOST view point
+ //
+ if (mDebugMpContext.ViewPointIndex != ProcessorIndex) {
+ if (mDebugMpContext.RunCommandSet) {
+ //
+ // If HOST view point sets RUN flag, run GO command to leave
+ //
+ SetCpuStopFlagByIndex (ProcessorIndex, FALSE);
+ CommandGo (CpuContext);
+ break;
+ } else {
+ //
+ // Run into loop again
+ //
+ CpuPause ();
+ continue;
+ }
+ }
+ }
+
+ AcquireMpSpinLock (&mDebugMpContext.DebugPortSpinLock);
+
+ DebugHeader =(DEBUG_PACKET_HEADER *) InputPacketBuffer;
+
+ DebugAgentMsgPrint (DEBUG_AGENT_INFO, "TARGET: Try to get command from HOST...\n");
+ Status = ReceivePacket ((UINT8 *) DebugHeader, &BreakReceived, NULL, READ_PACKET_TIMEOUT, TRUE);
+ if (Status != RETURN_SUCCESS || !IS_REQUEST (DebugHeader)) {
+ DebugAgentMsgPrint (DEBUG_AGENT_WARNING, "TARGET: Get command[%x] sequenceno[%x] returned status is [%x] \n", DebugHeader->Command, DebugHeader->SequenceNo, Status);
+ DebugAgentMsgPrint (DEBUG_AGENT_WARNING, "TARGET: Get command failed or it's response packet not expected! \n");
+ ReleaseMpSpinLock (&mDebugMpContext.DebugPortSpinLock);
+ continue;
+ }
+
+ Mailbox = GetMailboxPointer ();
+ if (DebugHeader->SequenceNo == Mailbox->HostSequenceNo) {
+ DebugAgentMsgPrint (DEBUG_AGENT_WARNING, "TARGET: Receive one old command[%x] against command[%x]\n", DebugHeader->SequenceNo, Mailbox->HostSequenceNo);
+ SendAckPacket (Mailbox->LastAck);
+ ReleaseMpSpinLock (&mDebugMpContext.DebugPortSpinLock);
+ continue;
+ } else if (DebugHeader->SequenceNo == (UINT8) (Mailbox->HostSequenceNo + 1)) {
+ UpdateMailboxContent (Mailbox, DEBUG_MAILBOX_HOST_SEQUENCE_NO_INDEX, (UINT8) DebugHeader->SequenceNo);
+ } else {
+ DebugAgentMsgPrint (DEBUG_AGENT_WARNING, "Receive one invalid command[%x] against command[%x]\n", DebugHeader->SequenceNo, Mailbox->HostSequenceNo);
+ ReleaseMpSpinLock (&mDebugMpContext.DebugPortSpinLock);
+ continue;
+ }
+
+ //
+ // Save CPU content before executing HOST command
+ //
+ UpdateMailboxContent (Mailbox, DEBUG_MAILBOX_EXCEPTION_BUFFER_POINTER_INDEX, (UINT64)(UINTN) &AgentExceptionBuffer.JumpBuffer);
+ if (SetJump (&AgentExceptionBuffer.JumpBuffer) != 0) {
+ //
+ // If HOST command failed, continue to wait for HOST's next command
+ // If needed, agent could send exception info to HOST.
+ //
+ SendAckPacket (DEBUG_COMMAND_ABORT);
+ ReleaseMpSpinLock (&mDebugMpContext.DebugPortSpinLock);
+ continue;
+ }
+
+ DebugAgentMsgPrint (DEBUG_AGENT_INFO, "Processor[%x]:Received one command(%x)\n", mDebugMpContext.ViewPointIndex, DebugHeader->Command);
+
+ switch (DebugHeader->Command) {
+
+ case DEBUG_COMMAND_HALT:
+ SendAckPacket (DEBUG_COMMAND_HALT_DEFERRED);
+ HaltDeferred = TRUE;
+ BreakReceived = FALSE;
+ Status = RETURN_SUCCESS;
+ break;
+
+ case DEBUG_COMMAND_RESET:
+ SendAckPacket (DEBUG_COMMAND_OK);
+ SendAckPacket (DEBUG_COMMAND_OK);
+ SendAckPacket (DEBUG_COMMAND_OK);
+ ReleaseMpSpinLock (&mDebugMpContext.DebugPortSpinLock);
+
+ ResetCold ();
+ //
+ // Assume system resets in 2 seconds, otherwise send TIMEOUT packet.
+ // PCD can be used if 2 seconds isn't long enough for some platforms.
+ //
+ MicroSecondDelay (2000000);
+ UpdateMailboxContent (Mailbox, DEBUG_MAILBOX_HOST_SEQUENCE_NO_INDEX, Mailbox->HostSequenceNo + 1);
+ SendAckPacket (DEBUG_COMMAND_TIMEOUT);
+ SendAckPacket (DEBUG_COMMAND_TIMEOUT);
+ SendAckPacket (DEBUG_COMMAND_TIMEOUT);
+ break;
+
+ case DEBUG_COMMAND_GO:
+ CommandGo (CpuContext);
+ //
+ // Clear Dr0 to avoid to be recognized as IMAGE_LOAD/_UNLOAD again when hitting a breakpoint after GO
+ // If HOST changed Dr0 before GO, we will not change Dr0 here
+ //
+ Data8 = GetBreakCause (Vector, CpuContext);
+ if (Data8 == DEBUG_DATA_BREAK_CAUSE_IMAGE_LOAD || Data8 == DEBUG_DATA_BREAK_CAUSE_IMAGE_UNLOAD) {
+ CpuContext->Dr0 = 0;
+ }
+
+ if (!HaltDeferred) {
+ //
+ // If no HALT command received when being in-active mode
+ //
+ if (MultiProcessorDebugSupport()) {
+ Data32 = FindNextPendingBreakCpu ();
+ if (Data32 != -1) {
+ //
+ // If there are still others processors being in break state,
+ // send OK packet to HOST to finish this go command
+ //
+ SendAckPacket (DEBUG_COMMAND_OK);
+ CpuPause ();
+ //
+ // Set current view to the next breaking processor
+ //
+ mDebugMpContext.ViewPointIndex = Data32;
+ mDebugMpContext.BreakAtCpuIndex = mDebugMpContext.ViewPointIndex;
+ SetCpuBreakFlagByIndex (mDebugMpContext.ViewPointIndex, FALSE);
+ //
+ // Send break packet to HOST to let HOST break again
+ //
+ SendBreakPacketToHost (DEBUG_DATA_BREAK_CAUSE_UNKNOWN, mDebugMpContext.BreakAtCpuIndex, &BreakReceived);
+ //
+ // Continue to run into loop to read command packet from HOST
+ //
+ ReleaseMpSpinLock (&mDebugMpContext.DebugPortSpinLock);
+ break;
+ }
+
+ //
+ // If no else processor break, set stop bitmask,
+ // and set Running flag for all processors.
+ //
+ SetCpuStopFlagByIndex (ProcessorIndex, FALSE);
+ SetCpuRunningFlag (TRUE);
+ CpuPause ();
+ //
+ // Wait for all processors are in running state
+ //
+ while (TRUE) {
+ if (IsAllCpuRunning ()) {
+ break;
+ }
+ }
+ //
+ // Set BSP to be current view point.
+ //
+ SetDebugViewPoint (mDebugMpContext.BspIndex);
+ CpuPause ();
+ //
+ // Clear breaking processor index and running flag
+ //
+ mDebugMpContext.BreakAtCpuIndex = (UINT32) (-1);
+ SetCpuRunningFlag (FALSE);
+ }
+
+ //
+ // Send OK packet to HOST to finish this go command
+ //
+ SendAckPacket (DEBUG_COMMAND_OK);
+
+ ReleaseMpSpinLock (&mDebugMpContext.DebugPortSpinLock);
+
+ if (!IsHostAttached()) {
+ UpdateMailboxContent (Mailbox, DEBUG_MAILBOX_SEQUENCE_NO_INDEX, 0);
+ UpdateMailboxContent (Mailbox, DEBUG_MAILBOX_HOST_SEQUENCE_NO_INDEX, 0);
+ }
+ return;
+
+ } else {
+ //
+ // If received HALT command, need to defer the GO command
+ //
+ SendAckPacket (DEBUG_COMMAND_HALT_PROCESSED);
+ HaltDeferred = FALSE;
+
+ Vector = DEBUG_TIMER_VECTOR;
+ }
+ break;
+
+ case DEBUG_COMMAND_BREAK_CAUSE:
+ BreakCause.StopAddress = CpuContext->Eip;
+ if (MultiProcessorDebugSupport() && ProcessorIndex != mDebugMpContext.BreakAtCpuIndex) {
+ BreakCause.Cause = GetBreakCause (DEBUG_TIMER_VECTOR, CpuContext);
+ } else {
+ BreakCause.Cause = GetBreakCause (Vector, CpuContext);
+ }
+ SendDataResponsePacket ((UINT8 *) &BreakCause, (UINT16) sizeof (DEBUG_DATA_RESPONSE_BREAK_CAUSE), DebugHeader);
+ break;
+
+ case DEBUG_COMMAND_SET_HW_BREAKPOINT:
+ SetDebugRegister (CpuContext, (DEBUG_DATA_SET_HW_BREAKPOINT *) (DebugHeader + 1));
+ SendAckPacket (DEBUG_COMMAND_OK);
+ break;
+
+ case DEBUG_COMMAND_CLEAR_HW_BREAKPOINT:
+ ClearDebugRegister (CpuContext, (DEBUG_DATA_CLEAR_HW_BREAKPOINT *) (DebugHeader + 1));
+ SendAckPacket (DEBUG_COMMAND_OK);
+ break;
+
+ case DEBUG_COMMAND_SINGLE_STEPPING:
+ CommandStepping (CpuContext);
+ //
+ // Clear Dr0 to avoid to be recognized as IMAGE_LOAD/_UNLOAD again when hitting a breakpoint after GO
+ // If HOST changed Dr0 before GO, we will not change Dr0 here
+ //
+ Data8 = GetBreakCause (Vector, CpuContext);
+ if (Data8 == DEBUG_DATA_BREAK_CAUSE_IMAGE_LOAD || Data8 == DEBUG_DATA_BREAK_CAUSE_IMAGE_UNLOAD) {
+ CpuContext->Dr0 = 0;
+ }
+
+ mDebugMpContext.BreakAtCpuIndex = (UINT32) (-1);
+ ReleaseMpSpinLock (&mDebugMpContext.DebugPortSpinLock);
+ //
+ // Executing stepping command directly without sending ACK packet,
+ // ACK packet will be sent after stepping done.
+ //
+ return;
+
+ case DEBUG_COMMAND_SET_SW_BREAKPOINT:
+ Data64 = (UINTN) (((DEBUG_DATA_SET_SW_BREAKPOINT *) (DebugHeader + 1))->Address);
+ Data8 = *(UINT8 *) (UINTN) Data64;
+ *(UINT8 *) (UINTN) Data64 = DEBUG_SW_BREAKPOINT_SYMBOL;
+ Status = SendDataResponsePacket ((UINT8 *) &Data8, (UINT16) sizeof (UINT8), DebugHeader);
+ break;
+
+ case DEBUG_COMMAND_READ_MEMORY:
+ MemoryRead = (DEBUG_DATA_READ_MEMORY *) (DebugHeader + 1);
+ Status = ReadMemoryAndSendResponsePacket ((UINT8 *) (UINTN) MemoryRead->Address, MemoryRead->Count, MemoryRead->Width, DebugHeader);
+ break;
+
+ case DEBUG_COMMAND_WRITE_MEMORY:
+ MemoryWrite = (DEBUG_DATA_WRITE_MEMORY *) (DebugHeader + 1);
+ //
+ // Copy data into one memory with 8-byte alignment address
+ //
+ AlignedDataPtr = ALIGN_POINTER ((UINT8 *) &MemoryWrite->Data, sizeof (UINT64));
+ if (AlignedDataPtr != (UINT8 *) &MemoryWrite->Data) {
+ CopyMem (AlignedDataPtr, (UINT8 *) &MemoryWrite->Data, MemoryWrite->Count * MemoryWrite->Width);
+ }
+ CopyMemByWidth ((UINT8 *) (UINTN) MemoryWrite->Address, AlignedDataPtr, MemoryWrite->Count, MemoryWrite->Width);
+ SendAckPacket (DEBUG_COMMAND_OK);
+ break;
+
+ case DEBUG_COMMAND_READ_IO:
+ IoRead = (DEBUG_DATA_READ_IO *) (DebugHeader + 1);
+ switch (IoRead->Width) {
+ case 1:
+ Data64 = IoRead8 ((UINTN) IoRead->Port);
+ break;
+ case 2:
+ Data64 = IoRead16 ((UINTN) IoRead->Port);
+ break;
+ case 4:
+ Data64 = IoRead32 ((UINTN) IoRead->Port);
+ break;
+ case 8:
+ Data64 = IoRead64 ((UINTN) IoRead->Port);
+ break;
+ default:
+ Data64 = (UINT64) -1;
+ }
+ Status = SendDataResponsePacket ((UINT8 *) &Data64, IoRead->Width, DebugHeader);
+ break;
+
+ case DEBUG_COMMAND_WRITE_IO:
+ IoWrite = (DEBUG_DATA_WRITE_IO *) (DebugHeader + 1);
+ switch (IoWrite->Width) {
+ case 1:
+ Data64 = IoWrite8 ((UINTN) IoWrite->Port, *(UINT8 *) &IoWrite->Data);
+ break;
+ case 2:
+ Data64 = IoWrite16 ((UINTN) IoWrite->Port, *(UINT16 *) &IoWrite->Data);
+ break;
+ case 4:
+ Data64 = IoWrite32 ((UINTN) IoWrite->Port, *(UINT32 *) &IoWrite->Data);
+ break;
+ case 8:
+ Data64 = IoWrite64 ((UINTN) IoWrite->Port, *(UINT64 *) &IoWrite->Data);
+ break;
+ default:
+ Data64 = (UINT64) -1;
+ }
+ SendAckPacket (DEBUG_COMMAND_OK);
+ break;
+
+ case DEBUG_COMMAND_READ_ALL_REGISTERS:
+ Status = SendDataResponsePacket ((UINT8 *) CpuContext, sizeof (*CpuContext), DebugHeader);
+ break;
+
+ case DEBUG_COMMAND_READ_REGISTER:
+ RegisterRead = (DEBUG_DATA_READ_REGISTER *) (DebugHeader + 1);
+
+ if (RegisterRead->Index <= SOFT_DEBUGGER_REGISTER_MAX) {
+ RegisterBuffer = ArchReadRegisterBuffer (CpuContext, RegisterRead->Index, &Width);
+ Status = SendDataResponsePacket (RegisterBuffer, Width, DebugHeader);
+ } else {
+ Status = RETURN_UNSUPPORTED;
+ }
+ break;
+
+ case DEBUG_COMMAND_WRITE_REGISTER:
+ RegisterWrite = (DEBUG_DATA_WRITE_REGISTER *) (DebugHeader + 1);
+ if (RegisterWrite->Index <= SOFT_DEBUGGER_REGISTER_MAX) {
+ RegisterBuffer = ArchReadRegisterBuffer (CpuContext, RegisterWrite->Index, &Width);
+ ASSERT (Width == RegisterWrite->Length);
+ CopyMem (RegisterBuffer, RegisterWrite->Data, Width);
+ SendAckPacket (DEBUG_COMMAND_OK);
+ } else {
+ Status = RETURN_UNSUPPORTED;
+ }
+ break;
+
+ case DEBUG_COMMAND_ARCH_MODE:
+ Data8 = DEBUG_ARCH_SYMBOL;
+ Status = SendDataResponsePacket ((UINT8 *) &Data8, (UINT16) sizeof (UINT8), DebugHeader);
+ break;
+
+ case DEBUG_COMMAND_READ_MSR:
+ MsrRegisterRead = (DEBUG_DATA_READ_MSR *) (DebugHeader + 1);
+ Data64 = AsmReadMsr64 (MsrRegisterRead->Index);
+ Status = SendDataResponsePacket ((UINT8 *) &Data64, (UINT16) sizeof (UINT64), DebugHeader);
+ break;
+
+ case DEBUG_COMMAND_WRITE_MSR:
+ MsrRegisterWrite = (DEBUG_DATA_WRITE_MSR *) (DebugHeader + 1);
+ AsmWriteMsr64 (MsrRegisterWrite->Index, MsrRegisterWrite->Value);
+ SendAckPacket (DEBUG_COMMAND_OK);
+ break;
+
+ case DEBUG_COMMAND_SET_DEBUG_SETTING:
+ Status = SetDebugSetting ((DEBUG_DATA_SET_DEBUG_SETTING *)(DebugHeader + 1));
+ if (Status == RETURN_SUCCESS) {
+ SendAckPacket (DEBUG_COMMAND_OK);
+ }
+ break;
+
+ case DEBUG_COMMAND_GET_REVISION:
+ DebugAgentRevision.Revision = PcdGet32(PcdTransferProtocolRevision);
+ DebugAgentRevision.Capabilities = DEBUG_AGENT_CAPABILITIES;
+ Status = SendDataResponsePacket ((UINT8 *) &DebugAgentRevision, (UINT16) sizeof (DEBUG_DATA_RESPONSE_GET_REVISION), DebugHeader);
+ break;
+
+ case DEBUG_COMMAND_GET_EXCEPTION:
+ Exception.ExceptionNum = (UINT8) Vector;
+ Exception.ExceptionData = (UINT32) CpuContext->ExceptionData;
+ Status = SendDataResponsePacket ((UINT8 *) &Exception, (UINT16) sizeof (DEBUG_DATA_RESPONSE_GET_EXCEPTION), DebugHeader);
+ break;
+
+ case DEBUG_COMMAND_SET_VIEWPOINT:
+ SetViewPoint = (DEBUG_DATA_SET_VIEWPOINT *) (DebugHeader + 1);
+ if (MultiProcessorDebugSupport()) {
+ if (IsCpuStopped (SetViewPoint->ViewPoint)) {
+ SetDebugViewPoint (SetViewPoint->ViewPoint);
+ SendAckPacket (DEBUG_COMMAND_OK);
+ } else {
+ //
+ // If CPU is not halted
+ //
+ SendAckPacket (DEBUG_COMMAND_NOT_SUPPORTED);
+ }
+ } else if (SetViewPoint->ViewPoint == 0) {
+ SendAckPacket (DEBUG_COMMAND_OK);
+
+ } else {
+ SendAckPacket (DEBUG_COMMAND_NOT_SUPPORTED);
+ }
+
+ break;
+
+ case DEBUG_COMMAND_GET_VIEWPOINT:
+ Data32 = mDebugMpContext.ViewPointIndex;
+ SendDataResponsePacket((UINT8 *) &Data32, (UINT16) sizeof (UINT32), DebugHeader);
+ break;
+
+ case DEBUG_COMMAND_MEMORY_READY:
+ Data8 = (UINT8) GetDebugFlag (DEBUG_AGENT_FLAG_MEMORY_READY);
+ SendDataResponsePacket (&Data8, (UINT16) sizeof (UINT8), DebugHeader);
+ break;
+
+ case DEBUG_COMMAND_DETACH:
+ SetHostAttached (FALSE);
+ SendAckPacket (DEBUG_COMMAND_OK);
+ break;
+
+ case DEBUG_COMMAND_CPUID:
+ Cpuid = (DEBUG_DATA_CPUID *) (DebugHeader + 1);
+ AsmCpuidEx (
+ Cpuid->Eax, Cpuid->Ecx,
+ &CpuidResponse.Eax, &CpuidResponse.Ebx,
+ &CpuidResponse.Ecx, &CpuidResponse.Edx
+ );
+ SendDataResponsePacket ((UINT8 *) &CpuidResponse, (UINT16) sizeof (CpuidResponse), DebugHeader);
+ break;
+
+ case DEBUG_COMMAND_SEARCH_SIGNATURE:
+ SearchSignature = (DEBUG_DATA_SEARCH_SIGNATURE *) (DebugHeader + 1);
+ if ((SearchSignature->Alignment != 0) &&
+ (SearchSignature->Alignment == GetPowerOfTwo32 (SearchSignature->Alignment))
+ ) {
+ if (SearchSignature->Positive) {
+ for (
+ Data64 = ALIGN_VALUE ((UINTN) SearchSignature->Start, SearchSignature->Alignment);
+ Data64 <= SearchSignature->Start + SearchSignature->Count - SearchSignature->DataLength;
+ Data64 += SearchSignature->Alignment
+ ) {
+ if (CompareMem ((VOID *) (UINTN) Data64, &SearchSignature->Data, SearchSignature->DataLength) == 0) {
+ break;
+ }
+ }
+ if (Data64 > SearchSignature->Start + SearchSignature->Count - SearchSignature->DataLength) {
+ Data64 = (UINT64) -1;
+ }
+ } else {
+ for (
+ Data64 = ALIGN_VALUE ((UINTN) SearchSignature->Start - SearchSignature->Alignment, SearchSignature->Alignment);
+ Data64 >= SearchSignature->Start - SearchSignature->Count;
+ Data64 -= SearchSignature->Alignment
+ ) {
+ if (CompareMem ((VOID *) (UINTN) Data64, &SearchSignature->Data, SearchSignature->DataLength) == 0) {
+ break;
+ }
+ }
+ if (Data64 < SearchSignature->Start - SearchSignature->Count) {
+ Data64 = (UINT64) -1;
+ }
+ }
+ SendDataResponsePacket ((UINT8 *) &Data64, (UINT16) sizeof (Data64), DebugHeader);
+ } else {
+ Status = RETURN_UNSUPPORTED;
+ }
+ break;
+
+ default:
+ SendAckPacket (DEBUG_COMMAND_NOT_SUPPORTED);
+ break;
+ }
+
+ if (Status == RETURN_UNSUPPORTED) {
+ SendAckPacket (DEBUG_COMMAND_NOT_SUPPORTED);
+ } else if (Status != RETURN_SUCCESS) {
+ SendAckPacket (DEBUG_COMMAND_ABORT);
+ }
+
+ ReleaseMpSpinLock (&mDebugMpContext.DebugPortSpinLock);
+ CpuPause ();
+ }
+}
+
+/**
+ C function called in interrupt handler.
+
+ @param[in] Vector Vector value of exception or interrupt.
+ @param[in] CpuContext Pointer to save CPU context.
+
+**/
+VOID
+EFIAPI
+InterruptProcess (
+ IN UINT32 Vector,
+ IN DEBUG_CPU_CONTEXT *CpuContext
+ )
+{
+ UINT8 InputCharacter;
+ UINT8 BreakCause;
+ UINTN SavedEip;
+ BOOLEAN BreakReceived;
+ UINT32 ProcessorIndex;
+ UINT32 CurrentDebugTimerInitCount;
+ DEBUG_PORT_HANDLE Handle;
+ UINT8 Data8;
+ UINT8 *Al;
+ UINT32 IssuedViewPoint;
+ DEBUG_AGENT_EXCEPTION_BUFFER *ExceptionBuffer;
+
+ InputCharacter = 0;
+ ProcessorIndex = 0;
+ IssuedViewPoint = 0;
+ BreakReceived = FALSE;
+
+ if (mSkipBreakpoint) {
+ //
+ // If Skip Breakpoint flag is set, means communication is disturbed by hardware SMI, we need to ignore the break points in SMM
+ //
+ if ((Vector == DEBUG_INT1_VECTOR) || (Vector == DEBUG_INT3_VECTOR)) {
+ DebugPortWriteBuffer (GetDebugPortHandle(), (UINT8 *) mWarningMsgIngoreBreakpoint, AsciiStrLen (mWarningMsgIngoreBreakpoint));
+ return;
+ }
+ }
+
+ if (MultiProcessorDebugSupport()) {
+ ProcessorIndex = GetProcessorIndex ();
+ //
+ // If this processor has already halted before, need to check it later
+ //
+ if (IsCpuStopped (ProcessorIndex)) {
+ IssuedViewPoint = ProcessorIndex;
+ }
+ }
+
+ if (IssuedViewPoint == ProcessorIndex && GetDebugFlag (DEBUG_AGENT_FLAG_STEPPING) != 1) {
+ //
+ // Check if this exception is issued by Debug Agent itself
+ // If yes, fill the debug agent exception buffer and LongJump() back to
+ // the saved CPU content in CommandCommunication()
+ // If exception is issued when executing Stepping, will be handled in
+ // exception handle procedure.
+ //
+ if (GetDebugFlag (DEBUG_AGENT_FLAG_AGENT_IN_PROGRESS) == 1) {
+ DebugAgentMsgPrint (
+ DEBUG_AGENT_ERROR,
+ "Debug agent meet one Exception, ExceptionNum is %d, EIP = 0x%x.\n",
+ Vector,
+ (UINTN)CpuContext->Eip
+ );
+ ExceptionBuffer = (DEBUG_AGENT_EXCEPTION_BUFFER *) (UINTN) GetMailboxPointer()->ExceptionBufferPointer;
+ ExceptionBuffer->ExceptionContent.ExceptionNum = (UINT8) Vector;
+ ExceptionBuffer->ExceptionContent.ExceptionData = (UINT32) CpuContext->ExceptionData;
+ LongJump ((BASE_LIBRARY_JUMP_BUFFER *)(UINTN)(ExceptionBuffer), 1);
+ }
+ }
+
+ if (MultiProcessorDebugSupport()) {
+ //
+ // If RUN command is executing, wait for it done.
+ //
+ while (mDebugMpContext.RunCommandSet) {
+ CpuPause ();
+ }
+ }
+
+ Handle = GetDebugPortHandle();
+ BreakCause = GetBreakCause (Vector, CpuContext);
+ switch (Vector) {
+ case DEBUG_INT1_VECTOR:
+ case DEBUG_INT3_VECTOR:
+ switch (BreakCause) {
+ case DEBUG_DATA_BREAK_CAUSE_SYSTEM_RESET:
+ if (AttachHost (BreakCause, READ_PACKET_TIMEOUT, &BreakReceived) != RETURN_SUCCESS) {
+ //
+ // Try to connect HOST, return if fails
+ //
+ break;
+ }
+ CommandCommunication (Vector, CpuContext, BreakReceived);
+ break;
+
+ case DEBUG_DATA_BREAK_CAUSE_STEPPING:
+ //
+ // Stepping is finished, send Ack package.
+ //
+ if (MultiProcessorDebugSupport()) {
+ mDebugMpContext.BreakAtCpuIndex = ProcessorIndex;
+ }
+ //
+ // Clear Stepping Flag and restore EFLAGS.IF
+ //
+ CommandSteppingCleanup (CpuContext);
+ SendAckPacket (DEBUG_COMMAND_OK);
+ CommandCommunication (Vector, CpuContext, BreakReceived);
+ break;
+
+ case DEBUG_DATA_BREAK_CAUSE_MEMORY_READY:
+ //
+ // Memory is ready
+ //
+ SendCommandAndWaitForAckOK (DEBUG_COMMAND_MEMORY_READY, READ_PACKET_TIMEOUT, &BreakReceived, NULL);
+ CommandCommunication (Vector, CpuContext, BreakReceived);
+ break;
+
+ case DEBUG_DATA_BREAK_CAUSE_IMAGE_LOAD:
+ case DEBUG_DATA_BREAK_CAUSE_IMAGE_UNLOAD:
+ //
+ // Set AL to DEBUG_AGENT_IMAGE_CONTINUE
+ //
+ Al = ArchReadRegisterBuffer (CpuContext, SOFT_DEBUGGER_REGISTER_AX, &Data8);
+ *Al = DEBUG_AGENT_IMAGE_CONTINUE;
+
+ if (!IsHostAttached ()) {
+ //
+ // If HOST is not connected for image load/unload, return
+ //
+ break;
+ }
+ //
+ // Continue to run the following common code
+ //
+
+ case DEBUG_DATA_BREAK_CAUSE_HW_BREAKPOINT:
+ case DEBUG_DATA_BREAK_CAUSE_SW_BREAKPOINT:
+ default:
+ //
+ // Send Break packet to HOST
+ //
+ AcquireMpSpinLock (&mDebugMpContext.DebugPortSpinLock);
+ //
+ // Only the first breaking processor could send BREAK_POINT to HOST
+ //
+ if (IsFirstBreakProcessor (ProcessorIndex)) {
+ SendBreakPacketToHost (BreakCause, ProcessorIndex, &BreakReceived);
+ }
+ ReleaseMpSpinLock (&mDebugMpContext.DebugPortSpinLock);
+
+ if (Vector == DEBUG_INT3_VECTOR) {
+ //
+ // go back address located "0xCC"
+ //
+ CpuContext->Eip--;
+ SavedEip = CpuContext->Eip;
+ CommandCommunication (Vector, CpuContext, BreakReceived);
+ if ((SavedEip == CpuContext->Eip) &&
+ (*(UINT8 *) (UINTN) CpuContext->Eip == DEBUG_SW_BREAKPOINT_SYMBOL)) {
+ //
+ // If this is not a software breakpoint set by HOST,
+ // restore EIP
+ //
+ CpuContext->Eip++;
+ }
+ } else {
+ CommandCommunication (Vector, CpuContext, BreakReceived);
+ }
+ break;
+ }
+
+ break;
+
+ case DEBUG_TIMER_VECTOR:
+
+ AcquireMpSpinLock (&mDebugMpContext.DebugPortSpinLock);
+
+ if (MultiProcessorDebugSupport()) {
+ if (DebugAgentIsBsp (ProcessorIndex)) {
+ //
+ // If current processor is BSP, check Apic timer's init count if changed,
+ // it may be re-written when switching BSP.
+ // If it changed, re-initialize debug timer
+ //
+ CurrentDebugTimerInitCount = GetApicTimerInitCount ();
+ if (mDebugMpContext.DebugTimerInitCount != CurrentDebugTimerInitCount) {
+ InitializeDebugTimer (NULL, FALSE);
+ SaveAndSetDebugTimerInterrupt (TRUE);
+ }
+ }
+
+ if (!DebugAgentIsBsp (ProcessorIndex) || mDebugMpContext.IpiSentByAp) {
+ ReleaseMpSpinLock (&mDebugMpContext.DebugPortSpinLock);
+ //
+ // If current processor is not BSP or this is one IPI sent by AP
+ //
+ if (mDebugMpContext.BreakAtCpuIndex != (UINT32) (-1)) {
+ CommandCommunication (Vector, CpuContext, FALSE);
+ }
+
+ //
+ // Clear EOI before exiting interrupt process routine.
+ //
+ SendApicEoi ();
+ break;
+ }
+ }
+
+ //
+ // Only BSP could run here
+ //
+ while (TRUE) {
+ //
+ // If there is data in debug port, will check whether it is break(attach/break-in) symbol,
+ // If yes, go into communication mode with HOST.
+ // If no, exit interrupt process.
+ //
+ if (DebugReadBreakSymbol (Handle, &InputCharacter) == EFI_NOT_FOUND) {
+ break;
+ }
+
+ if ((!IsHostAttached () && (InputCharacter == DEBUG_STARTING_SYMBOL_ATTACH)) ||
+ (IsHostAttached () && (InputCharacter == DEBUG_COMMAND_HALT)) ||
+ (IsHostAttached () && (InputCharacter == DEBUG_COMMAND_GO))
+ ) {
+ DebugAgentMsgPrint (DEBUG_AGENT_VERBOSE, "Received data [%02x]\n", InputCharacter);
+ //
+ // Ack OK for break-in symbol
+ //
+ SendAckPacket (DEBUG_COMMAND_OK);
+
+ //
+ // If receive GO command in Debug Timer, means HOST may lost ACK packet before.
+ //
+ if (InputCharacter == DEBUG_COMMAND_GO) {
+ break;
+ }
+
+ if (!IsHostAttached ()) {
+ //
+ // Try to attach HOST, if no ack received after 200ms, return
+ //
+ if (AttachHost (BreakCause, READ_PACKET_TIMEOUT, &BreakReceived) != RETURN_SUCCESS) {
+ break;
+ }
+ }
+
+ if (MultiProcessorDebugSupport()) {
+ if(FindNextPendingBreakCpu () != -1) {
+ SetCpuBreakFlagByIndex (ProcessorIndex, TRUE);
+ } else {
+ HaltOtherProcessors (ProcessorIndex);
+ }
+ }
+ ReleaseMpSpinLock (&mDebugMpContext.DebugPortSpinLock);
+ CommandCommunication (Vector, CpuContext, BreakReceived);
+ AcquireMpSpinLock (&mDebugMpContext.DebugPortSpinLock);
+ break;
+ }
+ }
+
+ //
+ // Clear EOI before exiting interrupt process routine.
+ //
+ SendApicEoi ();
+
+ ReleaseMpSpinLock (&mDebugMpContext.DebugPortSpinLock);
+
+ break;
+
+ default:
+ if (Vector <= DEBUG_EXCEPT_SIMD) {
+ DebugAgentMsgPrint (
+ DEBUG_AGENT_ERROR,
+ "Exception happened, ExceptionNum is %d, EIP = 0x%x.\n",
+ Vector,
+ (UINTN) CpuContext->Eip
+ );
+ if (BreakCause == DEBUG_DATA_BREAK_CAUSE_STEPPING) {
+ //
+ // If exception happened when executing Stepping, send Ack package.
+ // HOST consider Stepping command was finished.
+ //
+ if (MultiProcessorDebugSupport()) {
+ mDebugMpContext.BreakAtCpuIndex = ProcessorIndex;
+ }
+ //
+ // Clear Stepping flag and restore EFLAGS.IF
+ //
+ CommandSteppingCleanup (CpuContext);
+ SendAckPacket (DEBUG_COMMAND_OK);
+ } else {
+ //
+ // Exception occurs, send Break packet to HOST
+ //
+ AcquireMpSpinLock (&mDebugMpContext.DebugPortSpinLock);
+ //
+ // Only the first breaking processor could send BREAK_POINT to HOST
+ //
+ if (IsFirstBreakProcessor (ProcessorIndex)) {
+ SendBreakPacketToHost (BreakCause, ProcessorIndex, &BreakReceived);
+ }
+ ReleaseMpSpinLock (&mDebugMpContext.DebugPortSpinLock);
+ }
+
+ CommandCommunication (Vector, CpuContext, BreakReceived);
+ }
+ break;
+ }
+
+ if (MultiProcessorDebugSupport()) {
+ //
+ // Clear flag and wait for all processors run here
+ //
+ SetIpiSentByApFlag (FALSE);
+ while (mDebugMpContext.RunCommandSet) {
+ CpuPause ();
+ }
+
+ //
+ // Only current (view) processor could clean up AgentInProgress flag.
+ //
+ if (mDebugMpContext.ViewPointIndex == ProcessorIndex) {
+ IssuedViewPoint = mDebugMpContext.ViewPointIndex;
+ }
+ }
+
+ if (IssuedViewPoint == ProcessorIndex && GetDebugFlag (DEBUG_AGENT_FLAG_STEPPING) != 1) {
+ //
+ // If the command is not stepping, clean up AgentInProgress flag
+ //
+ SetDebugFlag (DEBUG_AGENT_FLAG_AGENT_IN_PROGRESS, 0);
+ }
+
+ return;
+}
+
diff --git a/src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Library/DebugAgent/DebugAgentCommon/DebugAgent.h b/src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Library/DebugAgent/DebugAgentCommon/DebugAgent.h
new file mode 100644
index 00000000..672794bb
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Library/DebugAgent/DebugAgentCommon/DebugAgent.h
@@ -0,0 +1,498 @@
+/** @file
+ Command header of for Debug Agent library instance.
+
+ Copyright (c) 2010 - 2018, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _DEBUG_AGENT_H_
+#define _DEBUG_AGENT_H_
+
+#include <Register/LocalApic.h>
+#include <Guid/DebugAgentGuid.h>
+#include <Guid/VectorHandoffTable.h>
+#include <Ppi/VectorHandoffInfo.h>
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/ResetSystemLib.h>
+#include <Library/IoLib.h>
+#include <Library/HobLib.h>
+#include <Library/DebugCommunicationLib.h>
+#include <Library/DebugAgentLib.h>
+#include <Library/PcdLib.h>
+#include <Library/SynchronizationLib.h>
+#include <Library/LocalApicLib.h>
+#include <Library/DebugLib.h>
+#include <Library/TimerLib.h>
+#include <Library/PrintLib.h>
+#include <Library/PeCoffGetEntryPointLib.h>
+#include <Library/PeCoffExtraActionLib.h>
+#include <Register/ArchitecturalMsr.h>
+
+#include <TransferProtocol.h>
+#include <ImageDebugSupport.h>
+
+#include "DebugMp.h"
+#include "DebugTimer.h"
+#include "ArchDebugSupport.h"
+#include "DebugException.h"
+
+//
+// These macros may be already defined in DebugAgentLib.h
+//
+#define DEBUG_AGENT_INIT_PEI 9
+#define DEBUG_AGENT_INIT_DXE_LOAD 10
+#define DEBUG_AGENT_INIT_DXE_UNLOAD 11
+#define DEBUG_AGENT_INIT_THUNK_PEI_IA32TOX64 12
+
+#define DEBUG_INT1_VECTOR DEBUG_EXCEPT_DEBUG
+#define DEBUG_INT3_VECTOR DEBUG_EXCEPT_BREAKPOINT
+#define DEBUG_TIMER_VECTOR 32
+#define DEBUG_MAILBOX_VECTOR 33
+
+//
+// Timeout value for reading packet (unit is microsecond)
+//
+#define READ_PACKET_TIMEOUT (500 * 1000)
+#define DEBUG_TIMER_INTERVAL (100 * 1000)
+
+#define SOFT_INTERRUPT_SIGNATURE SIGNATURE_32('S','O','F','T')
+#define SYSTEM_RESET_SIGNATURE SIGNATURE_32('S','Y','S','R')
+#define MEMORY_READY_SIGNATURE SIGNATURE_32('M','E','M','R')
+
+extern UINTN Exception0Handle;
+extern UINTN TimerInterruptHandle;
+extern UINT32 ExceptionStubHeaderSize;
+extern BOOLEAN mSkipBreakpoint;
+extern EFI_VECTOR_HANDOFF_INFO mVectorHandoffInfoDebugAgent[];
+extern UINTN mVectorHandoffInfoCount;
+
+//
+// CPU exception information issued by debug agent
+//
+typedef struct {
+ //
+ // This field is used to save CPU content before executing HOST command
+ //
+ BASE_LIBRARY_JUMP_BUFFER JumpBuffer;
+ //
+ // This field returns the exception information issued by the HOST command
+ //
+ DEBUG_DATA_RESPONSE_GET_EXCEPTION ExceptionContent;
+} DEBUG_AGENT_EXCEPTION_BUFFER;
+
+#define DEBUG_AGENT_FLAG_HOST_ATTACHED BIT0
+#define DEBUG_AGENT_FLAG_AGENT_IN_PROGRESS BIT1
+#define DEBUG_AGENT_FLAG_MEMORY_READY BIT2
+#define DEBUG_AGENT_FLAG_STEPPING BIT3
+#define DEBUG_AGENT_FLAG_CHECK_MAILBOX_IN_HOB BIT4
+#define DEBUG_AGENT_FLAG_INIT_ARCH BIT5|BIT6
+#define DEBUG_AGENT_FLAG_INTERRUPT_FLAG BIT7
+#define DEBUG_AGENT_FLAG_BREAK_ON_NEXT_SMI BIT32
+#define DEBUG_AGENT_FLAG_PRINT_ERROR_LEVEL (BIT33|BIT34|BIT35|BIT36)
+#define DEBUG_AGENT_FLAG_BREAK_BOOT_SCRIPT BIT37
+
+#define DEBUG_MAILBOX_DEBUG_FLAG_INDEX 1
+#define DEBUG_MAILBOX_DEBUG_PORT_HANDLE_INDEX 2
+#define DEBUG_MAILBOX_EXCEPTION_BUFFER_POINTER_INDEX 3
+#define DEBUG_MAILBOX_LAST_ACK 4
+#define DEBUG_MAILBOX_SEQUENCE_NO_INDEX 5
+#define DEBUG_MAILBOX_HOST_SEQUENCE_NO_INDEX 6
+#define DEBUG_MAILBOX_DEBUG_TIMER_FREQUENCY 7
+
+#pragma pack(1)
+typedef union {
+ struct {
+ //
+ // Lower 32 bits to store the status of DebugAgent
+ //
+ UINT32 HostAttached : 1; // 1: HOST is attached
+ UINT32 AgentInProgress : 1; // 1: Debug Agent is communicating with HOST
+ UINT32 MemoryReady : 1; // 1: Memory is ready
+ UINT32 SteppingFlag : 1; // 1: Agent is running stepping command
+ UINT32 CheckMailboxInHob : 1; // 1: Need to check mailbox saved in HOB
+ UINT32 InitArch : 2; // value of DEBUG_DATA_RESPONSE_ARCH_MODE
+ UINT32 InterruptFlag : 1; // 1: EFLAGS.IF is set
+ UINT32 Reserved1 : 24;
+ //
+ // Higher 32bits to control the behavior of DebugAgent
+ //
+ UINT32 BreakOnNextSmi : 1; // 1: Break on next SMI
+ UINT32 PrintErrorLevel : 4; // Bitmask of print error level for debug message
+ UINT32 BreakOnBootScript : 1; // 1: Break before executing boot script
+ UINT32 Reserved2 : 26;
+ } Bits;
+ UINT64 Uint64;
+} DEBUG_AGENT_FLAG;
+
+typedef struct {
+ DEBUG_AGENT_FLAG DebugFlag;
+ UINT64 DebugPortHandle;
+ //
+ // Pointer to DEBUG_AGENT_EXCEPTION_BUFFER
+ //
+ UINT64 ExceptionBufferPointer;
+ UINT8 LastAck; // The last ack packet type
+ UINT8 SequenceNo;
+ UINT8 HostSequenceNo;
+ UINT32 DebugTimerFrequency;
+ UINT8 CheckSum; // Mailbox checksum
+ UINT8 ToBeCheckSum; // To be Mailbox checksum at the next
+} DEBUG_AGENT_MAILBOX;
+#pragma pack()
+
+///
+/// Byte packed structure for an IA-32 Interrupt Gate Descriptor.
+///
+typedef union {
+ struct {
+ UINT32 OffsetLow:16; ///< Offset bits 15..0.
+ UINT32 Selector:16; ///< Selector.
+ UINT32 Reserved_0:8; ///< Reserved.
+ UINT32 GateType:8; ///< Gate Type. See #defines above.
+ UINT32 OffsetHigh:16; ///< Offset bits 31..16.
+ } Bits;
+ UINT64 Uint64;
+} IA32_IDT_ENTRY;
+
+
+typedef union {
+ struct {
+ UINT32 LimitLow : 16;
+ UINT32 BaseLow : 16;
+ UINT32 BaseMid : 8;
+ UINT32 Type : 4;
+ UINT32 System : 1;
+ UINT32 Dpl : 2;
+ UINT32 Present : 1;
+ UINT32 LimitHigh : 4;
+ UINT32 Software : 1;
+ UINT32 Reserved : 1;
+ UINT32 DefaultSize : 1;
+ UINT32 Granularity : 1;
+ UINT32 BaseHigh : 8;
+ } Bits;
+ UINT64 Uint64;
+} IA32_GDT;
+
+/**
+ Initialize IDT entries to support source level debug.
+
+**/
+VOID
+InitializeDebugIdt (
+ VOID
+ );
+
+/**
+ Read register value from saved CPU context.
+
+ @param[in] CpuContext Pointer to saved CPU context.
+ @param[in] Index Register index value.
+ @param[in] Width Data width to read.
+
+ @return The address of register value.
+
+**/
+UINT8 *
+ArchReadRegisterBuffer (
+ IN DEBUG_CPU_CONTEXT *CpuContext,
+ IN UINT8 Index,
+ IN UINT8 *Width
+ );
+
+/**
+ Send packet with response data to HOST.
+
+ @param[in] Data Pointer to response data buffer.
+ @param[in] DataSize Size of response data in byte.
+ @param[in, out] DebugHeader Pointer to a buffer for creating response packet and receiving ACK packet,
+ to minimize the stack usage.
+
+ @retval RETURN_SUCCESS Response data was sent successfully.
+ @retval RETURN_DEVICE_ERROR Cannot receive DEBUG_COMMAND_OK from HOST.
+
+**/
+RETURN_STATUS
+SendDataResponsePacket (
+ IN UINT8 *Data,
+ IN UINT16 DataSize,
+ IN OUT DEBUG_PACKET_HEADER *DebugHeader
+ );
+
+/**
+ Check if HOST is attached based on Mailbox.
+
+ @retval TRUE HOST is attached.
+ @retval FALSE HOST is not attached.
+
+**/
+BOOLEAN
+IsHostAttached (
+ VOID
+ );
+
+/**
+ Get Debug Agent Mailbox pointer.
+
+ @return Mailbox pointer.
+
+**/
+DEBUG_AGENT_MAILBOX *
+GetMailboxPointer (
+ VOID
+ );
+
+/**
+ Get debug port handle.
+
+ @return Debug port handle.
+
+**/
+DEBUG_PORT_HANDLE
+GetDebugPortHandle (
+ VOID
+ );
+
+/**
+ 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
+ );
+
+/**
+ Prints a debug message to the debug port if the specified error level is enabled.
+
+ If any bit in ErrorLevel is also set in Mainbox, then print the message specified
+ by Format and the associated variable argument list to the debug port.
+
+ @param[in] ErrorLevel The error level of the debug message.
+ @param[in] Format Format string for the debug message to print.
+ @param[in] ... Variable argument list whose contents are accessed
+ based on the format string specified by Format.
+
+**/
+VOID
+EFIAPI
+DebugAgentMsgPrint (
+ IN UINT8 ErrorLevel,
+ IN CHAR8 *Format,
+ ...
+ );
+
+/**
+ Trigger one software interrupt to debug agent to handle it.
+
+ @param[in] Signature Software interrupt signature.
+
+**/
+VOID
+TriggerSoftInterrupt (
+ IN UINT32 Signature
+ );
+
+/**
+ Check if debug agent support multi-processor.
+
+ @retval TRUE Multi-processor is supported.
+ @retval FALSE Multi-processor is not supported.
+
+**/
+BOOLEAN
+MultiProcessorDebugSupport (
+ VOID
+ );
+
+/**
+ Find and report module image info to HOST.
+
+ @param[in] AlignSize Image aligned size.
+
+**/
+VOID
+FindAndReportModuleImageInfo (
+ IN UINTN AlignSize
+ );
+
+/**
+ Read IDT entry to check if IDT entries are setup by Debug Agent.
+
+ @retval TRUE IDT entries were setup by Debug Agent.
+ @retval FALSE IDT entries were not setup by Debug Agent.
+
+**/
+BOOLEAN
+IsDebugAgentInitialzed (
+ VOID
+ );
+
+/**
+ Calculate Mailbox checksum and update the checksum field.
+
+ @param[in] Mailbox Debug Agent Mailbox pointer.
+
+**/
+VOID
+UpdateMailboxChecksum (
+ IN DEBUG_AGENT_MAILBOX *Mailbox
+ );
+
+/**
+ Verify Mailbox checksum.
+
+ If checksum error, print debug message and run init dead loop.
+
+ @param[in] Mailbox Debug Agent Mailbox pointer.
+
+**/
+VOID
+VerifyMailboxChecksum (
+ IN DEBUG_AGENT_MAILBOX *Mailbox
+ );
+
+/**
+ Set debug flag in mailbox.
+
+ @param[in] FlagMask Debug flag mask value.
+ @param[in] FlagValue Debug flag value.
+
+**/
+VOID
+SetDebugFlag (
+ IN UINT64 FlagMask,
+ IN UINT32 FlagValue
+ );
+
+/**
+ Get debug flag in mailbox.
+
+ @param[in] FlagMask Debug flag mask value.
+
+ @return Debug flag value.
+
+**/
+UINT32
+GetDebugFlag (
+ IN UINT64 FlagMask
+ );
+
+/**
+ Update Mailbox content by index.
+
+ @param[in] Mailbox Debug Agent Mailbox pointer.
+ @param[in] Index Mailbox content index.
+ @param[in] Value Value to be set into mail box.
+
+**/
+VOID
+UpdateMailboxContent (
+ IN DEBUG_AGENT_MAILBOX *Mailbox,
+ IN UINTN Index,
+ IN UINT64 Value
+ );
+
+/**
+ Retrieve exception handler from IDT table by ExceptionNum.
+
+ @param[in] ExceptionNum Exception number
+
+ @return Exception handler
+
+**/
+VOID *
+GetExceptionHandlerInIdtEntry (
+ IN UINTN ExceptionNum
+ );
+
+/**
+ Set exception handler in IDT table by ExceptionNum.
+
+ @param[in] ExceptionNum Exception number
+ @param[in] ExceptionHandler Exception Handler to be set
+
+**/
+VOID
+SetExceptionHandlerInIdtEntry (
+ IN UINTN ExceptionNum,
+ IN VOID *ExceptionHandler
+ );
+
+/**
+ Prints a debug message to the debug output device if the specified error level is enabled.
+
+ If any bit in ErrorLevel is also set in DebugPrintErrorLevelLib function
+ GetDebugPrintErrorLevel (), then print the message specified by Format and the
+ associated variable argument list to the debug output device.
+
+ If Format is NULL, then ASSERT().
+
+ @param[in] ErrorLevel The error level of the debug message.
+ @param[in] IsSend Flag of debug message to declare that the data is being sent or being received.
+ @param[in] Data Variable argument list whose contents are accessed
+ @param[in] Length based on the format string specified by Format.
+
+**/
+VOID
+EFIAPI
+DebugAgentDataMsgPrint (
+ IN UINT8 ErrorLevel,
+ IN BOOLEAN IsSend,
+ IN UINT8 *Data,
+ IN UINT8 Length
+ );
+
+/**
+ Read remaing debug packet except for the start symbol
+
+ @param[in] Handle Pointer to Debug Port handle.
+ @param[in, out] DebugHeader Debug header buffer including start symbol.
+
+ @retval EFI_SUCCESS Read the symbol in BreakSymbol.
+ @retval EFI_CRC_ERROR CRC check fail.
+ @retval EFI_TIMEOUT Timeout occurs when reading debug packet.
+
+**/
+EFI_STATUS
+ReadRemainingBreakPacket (
+ IN DEBUG_PORT_HANDLE Handle,
+ IN OUT DEBUG_PACKET_HEADER *DebugHeader
+ );
+
+/**
+ Read data from debug channel and save the data in buffer.
+
+ Reads NumberOfBytes data bytes from a debug device into the buffer
+ specified by Buffer. The number of bytes actually read is returned.
+ If the return value is less than NumberOfBytes, then the rest operation failed.
+ If NumberOfBytes is zero, then return 0.
+
+ @param Handle Debug port handle.
+ @param Buffer Pointer to the data buffer to store the data read from the debug device.
+ @param NumberOfBytes Number of bytes which will be read.
+ @param Timeout Timeout value for reading from debug device. It unit is Microsecond.
+
+ @retval 0 Read data failed, no data is to be read.
+ @retval >0 Actual number of bytes read from debug device.
+
+**/
+UINTN
+DebugAgentReadBuffer (
+ IN DEBUG_PORT_HANDLE Handle,
+ IN OUT UINT8 *Buffer,
+ IN UINTN NumberOfBytes,
+ IN UINTN Timeout
+ );
+
+#endif
+
diff --git a/src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Library/DebugAgent/DebugAgentCommon/DebugMp.c b/src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Library/DebugAgent/DebugAgentCommon/DebugMp.c
new file mode 100644
index 00000000..30ee5205
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Library/DebugAgent/DebugAgentCommon/DebugMp.c
@@ -0,0 +1,377 @@
+/** @file
+ Multi-Processor support functions implementation.
+
+ Copyright (c) 2010 - 2018, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "DebugAgent.h"
+
+GLOBAL_REMOVE_IF_UNREFERENCED DEBUG_MP_CONTEXT volatile mDebugMpContext = {0,0,0,{0},{0},0,0,0,0,FALSE,FALSE};
+
+GLOBAL_REMOVE_IF_UNREFERENCED DEBUG_CPU_DATA volatile mDebugCpuData = {0};
+
+/**
+ Acquire a spin lock when Multi-processor supported.
+
+ It will block in the function if cannot get the access control.
+ If Multi-processor is not supported, return directly.
+
+ @param[in, out] MpSpinLock A pointer to the spin lock.
+
+**/
+VOID
+AcquireMpSpinLock (
+ IN OUT SPIN_LOCK *MpSpinLock
+ )
+{
+ if (!MultiProcessorDebugSupport()) {
+ return;
+ }
+
+ while (TRUE) {
+ if (AcquireSpinLockOrFail (MpSpinLock)) {
+ break;
+ }
+ CpuPause ();
+ continue;
+ }
+}
+
+/**
+ Release a spin lock when Multi-processor supported.
+
+ @param[in, out] MpSpinLock A pointer to the spin lock.
+
+**/
+VOID
+ReleaseMpSpinLock (
+ IN OUT SPIN_LOCK *MpSpinLock
+ )
+{
+ if (!MultiProcessorDebugSupport()) {
+ return;
+ }
+
+ ReleaseSpinLock (MpSpinLock);
+}
+
+/**
+ Break the other processor by send IPI.
+
+ @param[in] CurrentProcessorIndex Current processor index value.
+
+**/
+VOID
+HaltOtherProcessors (
+ IN UINT32 CurrentProcessorIndex
+ )
+{
+ DebugAgentMsgPrint (DEBUG_AGENT_INFO, "processor[%x]:Try to halt other processors.\n", CurrentProcessorIndex);
+ if (!DebugAgentIsBsp (CurrentProcessorIndex)) {
+ SetIpiSentByApFlag (TRUE);;
+ }
+
+ mDebugMpContext.BreakAtCpuIndex = CurrentProcessorIndex;
+
+ //
+ // Set the debug viewpoint to the current breaking CPU.
+ //
+ SetDebugViewPoint (CurrentProcessorIndex);
+
+ //
+ // Send fixed IPI to other processors.
+ //
+ SendFixedIpiAllExcludingSelf (DEBUG_TIMER_VECTOR);
+
+}
+
+/**
+ Get the current processor's index.
+
+ @return Processor index value.
+
+**/
+UINT32
+GetProcessorIndex (
+ VOID
+ )
+{
+ UINT32 Index;
+ UINT16 LocalApicID;
+
+ LocalApicID = (UINT16) GetApicId ();
+
+ AcquireMpSpinLock (&mDebugMpContext.MpContextSpinLock);
+
+ for (Index = 0; Index < mDebugCpuData.CpuCount; Index ++) {
+ if (mDebugCpuData.ApicID[Index] == LocalApicID) {
+ break;
+ }
+ }
+
+ if (Index == mDebugCpuData.CpuCount) {
+ mDebugCpuData.ApicID[Index] = LocalApicID;
+ mDebugCpuData.CpuCount ++ ;
+ }
+
+ ReleaseMpSpinLock (&mDebugMpContext.MpContextSpinLock);
+
+ return Index;
+}
+
+/**
+ Check if the specified processor is BSP or not.
+
+ @param[in] ProcessorIndex Processor index value.
+
+ @retval TRUE It is BSP.
+ @retval FALSE It isn't BSP.
+
+**/
+BOOLEAN
+DebugAgentIsBsp (
+ IN UINT32 ProcessorIndex
+ )
+{
+ MSR_IA32_APIC_BASE_REGISTER MsrApicBase;
+
+ //
+ // If there are less than 2 CPUs detected, then the currently executing CPU
+ // must be the BSP. This avoids an access to an MSR that may not be supported
+ // on single core CPUs.
+ //
+ if (mDebugCpuData.CpuCount < 2) {
+ return TRUE;
+ }
+
+ MsrApicBase.Uint64 = AsmReadMsr64 (MSR_IA32_APIC_BASE);
+ if (MsrApicBase.Bits.BSP == 1) {
+ if (mDebugMpContext.BspIndex != ProcessorIndex) {
+ AcquireMpSpinLock (&mDebugMpContext.MpContextSpinLock);
+ mDebugMpContext.BspIndex = ProcessorIndex;
+ ReleaseMpSpinLock (&mDebugMpContext.MpContextSpinLock);
+ }
+ return TRUE;
+ } else {
+ return FALSE;
+ }
+}
+
+/**
+ Set processor stop flag bitmask in MP context.
+
+ @param[in] ProcessorIndex Processor index value.
+ @param[in] StopFlag TRUE means set stop flag.
+ FALSE means clean break flag.
+
+**/
+VOID
+SetCpuStopFlagByIndex (
+ IN UINT32 ProcessorIndex,
+ IN BOOLEAN StopFlag
+ )
+{
+ UINT8 Value;
+ UINTN Index;
+
+ AcquireMpSpinLock (&mDebugMpContext.MpContextSpinLock);
+
+ Value = mDebugMpContext.CpuStopStatusMask[ProcessorIndex / 8];
+ Index = ProcessorIndex % 8;
+ if (StopFlag) {
+ Value = BitFieldWrite8 (Value, Index, Index, 1);
+ } else {
+ Value = BitFieldWrite8 (Value, Index, Index, 0);
+ }
+ mDebugMpContext.CpuStopStatusMask[ProcessorIndex / 8] = Value;
+
+ ReleaseMpSpinLock (&mDebugMpContext.MpContextSpinLock);
+}
+
+/**
+ Set processor break flag bitmask in MP context.
+
+ @param[in] ProcessorIndex Processor index value.
+ @param[in] BreakFlag TRUE means set break flag.
+ FALSE means clean break flag.
+
+**/
+VOID
+SetCpuBreakFlagByIndex (
+ IN UINT32 ProcessorIndex,
+ IN BOOLEAN BreakFlag
+ )
+{
+ UINT8 Value;
+ UINTN Index;
+
+ AcquireMpSpinLock (&mDebugMpContext.MpContextSpinLock);
+
+ Value = mDebugMpContext.CpuBreakMask[ProcessorIndex / 8];
+ Index = ProcessorIndex % 8;
+ if (BreakFlag) {
+ Value = BitFieldWrite8 (Value, Index, Index, 1);
+ } else {
+ Value = BitFieldWrite8 (Value, Index, Index, 0);
+ }
+ mDebugMpContext.CpuBreakMask[ProcessorIndex / 8] = Value;
+
+ ReleaseMpSpinLock (&mDebugMpContext.MpContextSpinLock);
+}
+
+/**
+ Check if processor is stopped already.
+
+ @param[in] ProcessorIndex Processor index value.
+
+ @retval TRUE Processor is stopped already.
+ @retval TRUE Processor isn't stopped.
+
+**/
+BOOLEAN
+IsCpuStopped (
+ IN UINT32 ProcessorIndex
+ )
+{
+ UINT8 CpuMask;
+
+ CpuMask = (UINT8) (1 << (ProcessorIndex % 8));
+
+ if ((mDebugMpContext.CpuStopStatusMask[ProcessorIndex / 8] & CpuMask) != 0) {
+ return TRUE;
+ } else {
+ return FALSE;
+ }
+}
+
+/**
+ Set the run command flag.
+
+ @param[in] RunningFlag TRUE means run command flag is set.
+ FALSE means run command flag is cleared.
+
+**/
+VOID
+SetCpuRunningFlag (
+ IN BOOLEAN RunningFlag
+ )
+{
+ AcquireMpSpinLock (&mDebugMpContext.MpContextSpinLock);
+ mDebugMpContext.RunCommandSet = RunningFlag;
+ ReleaseMpSpinLock (&mDebugMpContext.MpContextSpinLock);
+}
+
+/**
+ Set the current view point to be debugged.
+
+ @param[in] ProcessorIndex Processor index value.
+
+**/
+VOID
+SetDebugViewPoint (
+ IN UINT32 ProcessorIndex
+ )
+{
+ AcquireMpSpinLock (&mDebugMpContext.MpContextSpinLock);
+ mDebugMpContext.ViewPointIndex = ProcessorIndex;
+ ReleaseMpSpinLock (&mDebugMpContext.MpContextSpinLock);
+}
+
+/**
+ Set the IPI send by BPS/AP flag.
+
+ @param[in] IpiSentByApFlag TRUE means this IPI is sent by AP.
+ FALSE means this IPI is sent by BSP.
+
+**/
+VOID
+SetIpiSentByApFlag (
+ IN BOOLEAN IpiSentByApFlag
+ )
+{
+ AcquireMpSpinLock (&mDebugMpContext.MpContextSpinLock);
+ mDebugMpContext.IpiSentByAp = IpiSentByApFlag;
+ ReleaseMpSpinLock (&mDebugMpContext.MpContextSpinLock);
+}
+
+/**
+ Check the next pending breaking CPU.
+
+ @retval others There is at least one processor broken, the minimum
+ index number of Processor returned.
+ @retval -1 No any processor broken.
+
+**/
+UINT32
+FindNextPendingBreakCpu (
+ VOID
+ )
+{
+ UINT32 Index;
+
+ for (Index = 0; Index < DEBUG_CPU_MAX_COUNT / 8; Index ++) {
+ if (mDebugMpContext.CpuBreakMask[Index] != 0) {
+ return (UINT32) LowBitSet32 (mDebugMpContext.CpuBreakMask[Index]) + Index * 8;
+ }
+ }
+ return (UINT32)-1;
+}
+
+/**
+ Check if all processors are in running status.
+
+ @retval TRUE All processors run.
+ @retval FALSE At least one processor does not run.
+
+**/
+BOOLEAN
+IsAllCpuRunning (
+ VOID
+ )
+{
+ UINTN Index;
+
+ for (Index = 0; Index < DEBUG_CPU_MAX_COUNT / 8; Index ++) {
+ if (mDebugMpContext.CpuStopStatusMask[Index] != 0) {
+ return FALSE;
+ }
+ }
+ return TRUE;
+}
+
+/**
+ Check if the current processor is the first breaking processor.
+
+ If yes, halt other processors.
+
+ @param[in] ProcessorIndex Processor index value.
+
+ @return TRUE This processor is the first breaking processor.
+ @return FALSE This processor is not the first breaking processor.
+
+**/
+BOOLEAN
+IsFirstBreakProcessor (
+ IN UINT32 ProcessorIndex
+ )
+{
+ if (MultiProcessorDebugSupport()) {
+ if (mDebugMpContext.BreakAtCpuIndex != (UINT32) -1) {
+ //
+ // The current processor is not the first breaking one.
+ //
+ SetCpuBreakFlagByIndex (ProcessorIndex, TRUE);
+ return FALSE;
+ } else {
+ //
+ // If no any processor breaks, try to halt other processors
+ //
+ HaltOtherProcessors (ProcessorIndex);
+ return TRUE;
+ }
+ }
+ return TRUE;
+}
+
diff --git a/src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Library/DebugAgent/DebugAgentCommon/DebugMp.h b/src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Library/DebugAgent/DebugAgentCommon/DebugMp.h
new file mode 100644
index 00000000..a169edd0
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Library/DebugAgent/DebugAgentCommon/DebugMp.h
@@ -0,0 +1,216 @@
+/** @file
+ Header file for Multi-Processor support.
+
+ Copyright (c) 2010 - 2018, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _DEBUG_MP_H_
+#define _DEBUG_MP_H_
+
+#define DEBUG_CPU_MAX_COUNT 256
+
+typedef struct {
+ UINT32 CpuCount; ///< Processor count
+ UINT16 ApicID[DEBUG_CPU_MAX_COUNT]; ///< Record the local apic id for each processor
+} DEBUG_CPU_DATA;
+
+typedef struct {
+ SPIN_LOCK MpContextSpinLock; ///< Lock for writing MP context
+ SPIN_LOCK DebugPortSpinLock; ///< Lock for access debug port
+ SPIN_LOCK MailboxSpinLock; ///< Lock for accessing mail box
+ UINT8 CpuBreakMask[DEBUG_CPU_MAX_COUNT/8]; ///< Bitmask of all breaking CPUs
+ UINT8 CpuStopStatusMask[DEBUG_CPU_MAX_COUNT/8]; ///< Bitmask of CPU stop status
+ UINT32 ViewPointIndex; ///< Current view point to be debugged
+ UINT32 BspIndex; ///< Processor index value of BSP
+ UINT32 BreakAtCpuIndex; ///< Processor index value of the current breaking CPU
+ UINT32 DebugTimerInitCount; ///< Record BSP's init timer count
+ BOOLEAN IpiSentByAp; ///< TRUE: IPI is sent by AP. FALSE: IPI is sent by BSP
+ BOOLEAN RunCommandSet; ///< TRUE: RUN command is executing. FALSE: RUN command has been executed.
+} DEBUG_MP_CONTEXT;
+
+extern DEBUG_MP_CONTEXT volatile mDebugMpContext;
+extern DEBUG_CPU_DATA volatile mDebugCpuData;
+
+/**
+ Break the other processor by send IPI.
+
+ @param[in] CurrentProcessorIndex Current processor index value.
+
+**/
+VOID
+HaltOtherProcessors (
+ IN UINT32 CurrentProcessorIndex
+ );
+
+/**
+ Get the current processor's index.
+
+ @return Processor index value.
+
+**/
+UINT32
+GetProcessorIndex (
+ VOID
+ );
+
+/**
+ Acquire a spin lock when Multi-processor supported.
+
+ It will block in the function if cannot get the access control.
+ If Multi-processor is not supported, return directly.
+
+ @param[in, out] MpSpinLock A pointer to the spin lock.
+
+**/
+VOID
+AcquireMpSpinLock (
+ IN OUT SPIN_LOCK *MpSpinLock
+ );
+
+/**
+ Release a spin lock when Multi-processor supported.
+
+ @param[in, out] MpSpinLock A pointer to the spin lock.
+
+**/
+VOID
+ReleaseMpSpinLock (
+ IN OUT SPIN_LOCK *MpSpinLock
+ );
+
+/**
+ Check if the specified processor is BSP or not.
+
+ @param[in] ProcessorIndex Processor index value.
+
+ @retval TRUE It is BSP.
+ @retval FALSE It isn't BSP.
+
+**/
+BOOLEAN
+DebugAgentIsBsp (
+ IN UINT32 ProcessorIndex
+ );
+
+/**
+ Set processor stop flag bitmask in MP context.
+
+ @param[in] ProcessorIndex Processor index value.
+ @param[in] StopFlag TRUE means set stop flag.
+ FALSE means clean break flag.
+
+**/
+VOID
+SetCpuStopFlagByIndex (
+ IN UINT32 ProcessorIndex,
+ IN BOOLEAN StopFlag
+ );
+
+/**
+ Set processor break flag bitmask in MP context.
+
+ @param[in] ProcessorIndex Processor index value.
+ @param[in] BreakFlag TRUE means set break flag.
+ FALSE means clean break flag.
+
+**/
+VOID
+SetCpuBreakFlagByIndex (
+ IN UINT32 ProcessorIndex,
+ IN BOOLEAN BreakFlag
+ );
+
+/**
+ Check if processor is stopped already.
+
+ @param[in] ProcessorIndex Processor index value.
+
+ @retval TRUE Processor is stopped already.
+ @retval FALSE Processor isn't stopped.
+
+**/
+BOOLEAN
+IsCpuStopped (
+ IN UINT32 ProcessorIndex
+ );
+
+/**
+ Set the run command flag.
+
+ @param[in] RunningFlag TRUE means run command flag is set.
+ FALSE means run command flag is cleared.
+
+**/
+VOID
+SetCpuRunningFlag (
+ IN BOOLEAN RunningFlag
+ );
+
+/**
+ Set the current view point to be debugged.
+
+ @param[in] ProcessorIndex Processor index value.
+
+**/
+VOID
+SetDebugViewPoint (
+ IN UINT32 ProcessorIndex
+ );
+
+/**
+ Set the IPI send by BPS/AP flag.
+
+ @param[in] IpiSentByApFlag TRUE means this IPI is sent by AP.
+ FALSE means this IPI is sent by BSP.
+
+**/
+VOID
+SetIpiSentByApFlag (
+ IN BOOLEAN IpiSentByApFlag
+ );
+
+/**
+ Check the next pending breaking CPU.
+
+ @retval others There is at least one processor broken, the minimum
+ index number of Processor returned.
+ @retval -1 No any processor broken.
+
+**/
+UINT32
+FindNextPendingBreakCpu (
+ VOID
+ );
+
+/**
+ Check if all processors are in running status.
+
+ @retval TRUE All processors run.
+ @retval FALSE At least one processor does not run.
+
+**/
+BOOLEAN
+IsAllCpuRunning (
+ VOID
+ );
+
+/**
+ Check if the current processor is the first breaking processor.
+
+ If yes, halt other processors.
+
+ @param[in] ProcessorIndex Processor index value.
+
+ @return TRUE This processor is the first breaking processor.
+ @return FALSE This processor is not the first breaking processor.
+
+**/
+BOOLEAN
+IsFirstBreakProcessor (
+ IN UINT32 ProcessorIndex
+ );
+
+#endif
+
diff --git a/src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Library/DebugAgent/DebugAgentCommon/DebugTimer.c b/src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Library/DebugAgent/DebugAgentCommon/DebugTimer.c
new file mode 100644
index 00000000..19c2afe9
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Library/DebugAgent/DebugAgentCommon/DebugTimer.c
@@ -0,0 +1,143 @@
+/** @file
+ Code for debug timer to support debug agent library implementation.
+
+ Copyright (c) 2010 - 2015, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "DebugAgent.h"
+
+/**
+ Initialize CPU local APIC timer.
+
+ @param[out] TimerFrequency Local APIC timer frequency returned.
+ @param[in] DumpFlag If TRUE, dump Local APIC timer's parameter.
+
+ @return 32-bit Local APIC timer init count.
+**/
+UINT32
+InitializeDebugTimer (
+ OUT UINT32 *TimerFrequency,
+ IN BOOLEAN DumpFlag
+ )
+{
+ UINTN ApicTimerDivisor;
+ UINT32 InitialCount;
+ UINT32 ApicTimerFrequency;
+
+ InitializeLocalApicSoftwareEnable (TRUE);
+ GetApicTimerState (&ApicTimerDivisor, NULL, NULL);
+ ApicTimerFrequency = PcdGet32(PcdFSBClock) / (UINT32)ApicTimerDivisor;
+ //
+ // Cpu Local Apic timer interrupt frequency, it is set to 0.1s
+ //
+ InitialCount = (UINT32)DivU64x32 (
+ MultU64x64 (
+ ApicTimerFrequency,
+ DEBUG_TIMER_INTERVAL
+ ),
+ 1000000u
+ );
+
+ InitializeApicTimer (ApicTimerDivisor, InitialCount, TRUE, DEBUG_TIMER_VECTOR);
+ //
+ // Disable Debug Timer interrupt to avoid it is delivered before Debug Port
+ // is initialized
+ //
+ DisableApicTimerInterrupt ();
+
+ if (DumpFlag) {
+ DEBUG ((EFI_D_INFO, "Debug Timer: FSB Clock = %d\n", PcdGet32(PcdFSBClock)));
+ DEBUG ((EFI_D_INFO, "Debug Timer: Divisor = %d\n", ApicTimerDivisor));
+ DEBUG ((EFI_D_INFO, "Debug Timer: Frequency = %d\n", ApicTimerFrequency));
+ DEBUG ((EFI_D_INFO, "Debug Timer: InitialCount = %d\n", InitialCount));
+ }
+ if (TimerFrequency != NULL) {
+ *TimerFrequency = ApicTimerFrequency;
+ }
+ return InitialCount;
+}
+
+/**
+ Enable/Disable the interrupt of debug timer and return the interrupt state
+ prior to the operation.
+
+ If EnableStatus is TRUE, enable the interrupt of debug timer.
+ If EnableStatus is FALSE, disable the interrupt of debug timer.
+
+ @param[in] EnableStatus Enable/Disable.
+
+ @retval TRUE Debug timer interrupt were enabled on entry to this call.
+ @retval FALSE Debug timer interrupt were disabled on entry to this call.
+
+**/
+BOOLEAN
+EFIAPI
+SaveAndSetDebugTimerInterrupt (
+ IN BOOLEAN EnableStatus
+ )
+{
+ BOOLEAN OldDebugTimerInterruptState;
+
+ OldDebugTimerInterruptState = GetApicTimerInterruptState ();
+
+ if (OldDebugTimerInterruptState != EnableStatus) {
+ if (EnableStatus) {
+ EnableApicTimerInterrupt ();
+ } else {
+ DisableApicTimerInterrupt ();
+ }
+ //
+ // Validate the Debug Timer interrupt state
+ // This will make additional delay after Local Apic Timer interrupt state is changed.
+ // Thus, CPU could handle the potential pending interrupt of Local Apic timer.
+ //
+ while (GetApicTimerInterruptState () != EnableStatus) {
+ CpuPause ();
+ }
+ }
+
+ return OldDebugTimerInterruptState;
+}
+
+/**
+ Check if the timer is time out.
+
+ @param[in] TimerCycle Timer initial count.
+ @param[in] Timer The start timer from the begin.
+ @param[in] TimeoutTicker Ticker number need time out.
+
+ @return TRUE Timer time out occurs.
+ @retval FALSE Timer does not time out.
+
+**/
+BOOLEAN
+IsDebugTimerTimeout (
+ IN UINT32 TimerCycle,
+ IN UINT32 Timer,
+ IN UINT32 TimeoutTicker
+ )
+{
+ UINT64 CurrentTimer;
+ UINT64 Delta;
+
+ CurrentTimer = GetApicTimerCurrentCount ();
+
+ //
+ // This timer counter counts down. Check for roll over condition.
+ // If CurrentTimer is equal to Timer, it does not mean that roll over
+ // happened.
+ //
+ if (CurrentTimer <= Timer) {
+ Delta = Timer - CurrentTimer;
+ } else {
+ //
+ // Handle one roll-over.
+ //
+ Delta = TimerCycle - (CurrentTimer - Timer) + 1;
+ }
+
+ return (BOOLEAN) (Delta >= TimeoutTicker);
+}
+
diff --git a/src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Library/DebugAgent/DebugAgentCommon/DebugTimer.h b/src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Library/DebugAgent/DebugAgentCommon/DebugTimer.h
new file mode 100644
index 00000000..19192d26
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Library/DebugAgent/DebugAgentCommon/DebugTimer.h
@@ -0,0 +1,45 @@
+/** @file
+ Header file for debug timer to support debug agent library implementation.
+
+ Copyright (c) 2010 - 2015, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _DEBUG_TIMER_H_
+#define _DEBUG_TIMER_H_
+
+/**
+ Initialize CPU local APIC timer.
+
+ @param[out] TimerFrequency Local APIC timer frequency returned.
+ @param[in] DumpFlag If TRUE, dump Local APIC timer's parameter.
+
+ @return 32-bit Local APIC timer init count.
+**/
+UINT32
+InitializeDebugTimer (
+ OUT UINT32 *TimerFrequency,
+ IN BOOLEAN DumpFlag
+ );
+
+/**
+ Check if the timer is time out.
+
+ @param[in] TimerCycle Timer initial count.
+ @param[in] Timer The start timer from the begin.
+ @param[in] TimeoutTicker Ticker number need time out.
+
+ @return TRUE Timer time out occurs.
+ @retval FALSE Timer does not time out.
+
+**/
+BOOLEAN
+IsDebugTimerTimeout (
+ IN UINT32 TimerCycle,
+ IN UINT32 Timer,
+ IN UINT32 TimeoutTicker
+ );
+
+#endif
+
diff --git a/src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Library/DebugAgent/DebugAgentCommon/Ia32/ArchDebugSupport.c b/src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Library/DebugAgent/DebugAgentCommon/Ia32/ArchDebugSupport.c
new file mode 100644
index 00000000..97c3d2d5
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Library/DebugAgent/DebugAgentCommon/Ia32/ArchDebugSupport.c
@@ -0,0 +1,110 @@
+/** @file
+ Supporting functions for IA32 architecture.
+
+ Copyright (c) 2010 - 2018, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "DebugAgent.h"
+
+/**
+ Initialize IDT entries to support source level debug.
+
+**/
+VOID
+InitializeDebugIdt (
+ VOID
+ )
+{
+ IA32_IDT_GATE_DESCRIPTOR *IdtEntry;
+ UINTN InterruptHandler;
+ IA32_DESCRIPTOR IdtDescriptor;
+ UINTN Index;
+ UINT16 CodeSegment;
+ UINT32 RegEdx;
+
+ AsmReadIdtr (&IdtDescriptor);
+
+ //
+ // Use current CS as the segment selector of interrupt gate in IDT
+ //
+ CodeSegment = AsmReadCs ();
+
+ IdtEntry = (IA32_IDT_GATE_DESCRIPTOR *) IdtDescriptor.Base;
+
+ for (Index = 0; Index < 20; Index ++) {
+ if (((PcdGet32 (PcdExceptionsIgnoredByDebugger) & ~(BIT1 | BIT3)) & (1 << Index)) != 0) {
+ //
+ // If the exception is masked to be reserved except for INT1 and INT3, skip it
+ //
+ continue;
+ }
+ InterruptHandler = (UINTN)&Exception0Handle + Index * ExceptionStubHeaderSize;
+ IdtEntry[Index].Bits.OffsetLow = (UINT16)(UINTN)InterruptHandler;
+ IdtEntry[Index].Bits.OffsetHigh = (UINT16)((UINTN)InterruptHandler >> 16);
+ IdtEntry[Index].Bits.Selector = CodeSegment;
+ IdtEntry[Index].Bits.GateType = IA32_IDT_GATE_TYPE_INTERRUPT_32;
+ }
+
+ InterruptHandler = (UINTN) &TimerInterruptHandle;
+ IdtEntry[DEBUG_TIMER_VECTOR].Bits.OffsetLow = (UINT16)(UINTN)InterruptHandler;
+ IdtEntry[DEBUG_TIMER_VECTOR].Bits.OffsetHigh = (UINT16)((UINTN)InterruptHandler >> 16);
+ IdtEntry[DEBUG_TIMER_VECTOR].Bits.Selector = CodeSegment;
+ IdtEntry[DEBUG_TIMER_VECTOR].Bits.GateType = IA32_IDT_GATE_TYPE_INTERRUPT_32;
+
+ //
+ // If the CPU supports Debug Extensions(CPUID:01 EDX:BIT2), then
+ // Set DE flag in CR4 to enable IO breakpoint
+ //
+ AsmCpuid (1, NULL, NULL, NULL, &RegEdx);
+ if ((RegEdx & BIT2) != 0) {
+ AsmWriteCr4 (AsmReadCr4 () | BIT3);
+ }
+}
+
+/**
+ Retrieve exception handler from IDT table by ExceptionNum.
+
+ @param[in] ExceptionNum Exception number
+
+ @return Exception handler
+
+**/
+VOID *
+GetExceptionHandlerInIdtEntry (
+ IN UINTN ExceptionNum
+ )
+{
+ IA32_IDT_GATE_DESCRIPTOR *IdtEntry;
+ IA32_DESCRIPTOR IdtDescriptor;
+
+ AsmReadIdtr (&IdtDescriptor);
+ IdtEntry = (IA32_IDT_GATE_DESCRIPTOR *) IdtDescriptor.Base;
+
+ return (VOID *) (((UINTN)IdtEntry[ExceptionNum].Bits.OffsetLow) |
+ (((UINTN)IdtEntry[ExceptionNum].Bits.OffsetHigh) << 16));
+}
+
+/**
+ Set exception handler in IDT table by ExceptionNum.
+
+ @param[in] ExceptionNum Exception number
+ @param[in] ExceptionHandler Exception Handler to be set
+
+**/
+VOID
+SetExceptionHandlerInIdtEntry (
+ IN UINTN ExceptionNum,
+ IN VOID *ExceptionHandler
+ )
+{
+ IA32_IDT_GATE_DESCRIPTOR *IdtEntry;
+ IA32_DESCRIPTOR IdtDescriptor;
+
+ AsmReadIdtr (&IdtDescriptor);
+ IdtEntry = (IA32_IDT_GATE_DESCRIPTOR *) IdtDescriptor.Base;
+
+ IdtEntry[ExceptionNum].Bits.OffsetLow = (UINT16)(UINTN)ExceptionHandler;
+ IdtEntry[ExceptionNum].Bits.OffsetHigh = (UINT16)((UINTN)ExceptionHandler >> 16);
+}
diff --git a/src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Library/DebugAgent/DebugAgentCommon/Ia32/ArchDebugSupport.h b/src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Library/DebugAgent/DebugAgentCommon/Ia32/ArchDebugSupport.h
new file mode 100644
index 00000000..f3edd0bd
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Library/DebugAgent/DebugAgentCommon/Ia32/ArchDebugSupport.h
@@ -0,0 +1,21 @@
+/** @file
+ IA32 specific definitions for debug agent library instance.
+
+ Copyright (c) 2010 - 2012, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _ARCH_DEBUG_SUPPORT_H_
+#define _ARCH_DEBUG_SUPPORT_H_
+
+#include "ProcessorContext.h"
+#include "TransferProtocol.h"
+
+#define DEBUG_SW_BREAKPOINT_SYMBOL 0xcc
+#define DEBUG_ARCH_SYMBOL DEBUG_DATA_BREAK_CPU_ARCH_IA32
+
+typedef DEBUG_DATA_IA32_FX_SAVE_STATE DEBUG_DATA_FX_SAVE_STATE;
+typedef DEBUG_DATA_IA32_SYSTEM_CONTEXT DEBUG_CPU_CONTEXT;
+
+#endif
diff --git a/src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Library/DebugAgent/DebugAgentCommon/Ia32/AsmFuncs.nasm b/src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Library/DebugAgent/DebugAgentCommon/Ia32/AsmFuncs.nasm
new file mode 100644
index 00000000..36ad0c2e
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Library/DebugAgent/DebugAgentCommon/Ia32/AsmFuncs.nasm
@@ -0,0 +1,413 @@
+;------------------------------------------------------------------------------
+;
+; Copyright (c) 2010 - 2015, Intel Corporation. All rights reserved.<BR>
+; SPDX-License-Identifier: BSD-2-Clause-Patent
+;
+; Module Name:
+;
+; AsmFuncs.nasm
+;
+; Abstract:
+;
+; Debug interrupt handle functions.
+;
+;------------------------------------------------------------------------------
+
+#include "DebugException.h"
+
+;
+; InterruptProcess()
+;
+extern ASM_PFX(InterruptProcess)
+
+global ASM_PFX(Exception0Handle)
+global ASM_PFX(TimerInterruptHandle)
+global ASM_PFX(ExceptionStubHeaderSize)
+
+%macro AGENT_HANDLER_SIGNATURE 0
+ db 0x41, 0x47, 0x54, 0x48 ; SIGNATURE_32('A','G','T','H')
+%endmacro
+
+SECTION .data
+
+ASM_PFX(ExceptionStubHeaderSize): DD Exception1Handle - ASM_PFX(Exception0Handle)
+CommonEntryAddr: DD CommonEntry
+
+SECTION .text
+
+AGENT_HANDLER_SIGNATURE
+ASM_PFX(Exception0Handle):
+ cli
+ push eax
+ mov eax, 0
+ jmp dword [CommonEntryAddr]
+AGENT_HANDLER_SIGNATURE
+Exception1Handle:
+ cli
+ push eax
+ mov eax, 1
+ jmp dword [CommonEntryAddr]
+AGENT_HANDLER_SIGNATURE
+Exception2Handle:
+ cli
+ push eax
+ mov eax, 2
+ jmp dword [CommonEntryAddr]
+AGENT_HANDLER_SIGNATURE
+Exception3Handle:
+ cli
+ push eax
+ mov eax, 3
+ jmp dword [CommonEntryAddr]
+AGENT_HANDLER_SIGNATURE
+Exception4Handle:
+ cli
+ push eax
+ mov eax, 4
+ jmp dword [CommonEntryAddr]
+AGENT_HANDLER_SIGNATURE
+Exception5Handle:
+ cli
+ push eax
+ mov eax, 5
+ jmp dword [CommonEntryAddr]
+AGENT_HANDLER_SIGNATURE
+Exception6Handle:
+ cli
+ push eax
+ mov eax, 6
+ jmp dword [CommonEntryAddr]
+AGENT_HANDLER_SIGNATURE
+Exception7Handle:
+ cli
+ push eax
+ mov eax, 7
+ jmp dword [CommonEntryAddr]
+AGENT_HANDLER_SIGNATURE
+Exception8Handle:
+ cli
+ push eax
+ mov eax, 8
+ jmp dword [CommonEntryAddr]
+AGENT_HANDLER_SIGNATURE
+Exception9Handle:
+ cli
+ push eax
+ mov eax, 9
+ jmp dword [CommonEntryAddr]
+AGENT_HANDLER_SIGNATURE
+Exception10Handle:
+ cli
+ push eax
+ mov eax, 10
+ jmp dword [CommonEntryAddr]
+AGENT_HANDLER_SIGNATURE
+Exception11Handle:
+ cli
+ push eax
+ mov eax, 11
+ jmp dword [CommonEntryAddr]
+AGENT_HANDLER_SIGNATURE
+Exception12Handle:
+ cli
+ push eax
+ mov eax, 12
+ jmp dword [CommonEntryAddr]
+AGENT_HANDLER_SIGNATURE
+Exception13Handle:
+ cli
+ push eax
+ mov eax, 13
+ jmp dword [CommonEntryAddr]
+AGENT_HANDLER_SIGNATURE
+Exception14Handle:
+ cli
+ push eax
+ mov eax, 14
+ jmp dword [CommonEntryAddr]
+AGENT_HANDLER_SIGNATURE
+Exception15Handle:
+ cli
+ push eax
+ mov eax, 15
+ jmp dword [CommonEntryAddr]
+AGENT_HANDLER_SIGNATURE
+Exception16Handle:
+ cli
+ push eax
+ mov eax, 16
+ jmp dword [CommonEntryAddr]
+AGENT_HANDLER_SIGNATURE
+Exception17Handle:
+ cli
+ push eax
+ mov eax, 17
+ jmp dword [CommonEntryAddr]
+AGENT_HANDLER_SIGNATURE
+Exception18Handle:
+ cli
+ push eax
+ mov eax, 18
+ jmp dword [CommonEntryAddr]
+AGENT_HANDLER_SIGNATURE
+Exception19Handle:
+ cli
+ push eax
+ mov eax, 19
+ jmp dword [CommonEntryAddr]
+AGENT_HANDLER_SIGNATURE
+ASM_PFX(TimerInterruptHandle):
+ cli
+ push eax
+ mov eax, 32
+ jmp dword [CommonEntryAddr]
+
+CommonEntry:
+;
+; +---------------------+
+; + EFlags +
+; +---------------------+
+; + CS +
+; +---------------------+
+; + EIP +
+; +---------------------+
+; + Error Code +
+; +---------------------+
+; + EAX / Vector Number +
+; +---------------------+
+; + EBP +
+; +---------------------+ <-- EBP
+;
+ cmp eax, DEBUG_EXCEPT_DOUBLE_FAULT
+ je NoExtrPush
+ cmp eax, DEBUG_EXCEPT_INVALID_TSS
+ je NoExtrPush
+ cmp eax, DEBUG_EXCEPT_SEG_NOT_PRESENT
+ je NoExtrPush
+ cmp eax, DEBUG_EXCEPT_STACK_FAULT
+ je NoExtrPush
+ cmp eax, DEBUG_EXCEPT_GP_FAULT
+ je NoExtrPush
+ cmp eax, DEBUG_EXCEPT_PAGE_FAULT
+ je NoExtrPush
+ cmp eax, DEBUG_EXCEPT_ALIGNMENT_CHECK
+ je NoExtrPush
+
+ push dword [esp]
+ mov dword [esp + 4], 0
+
+NoExtrPush:
+
+ push ebp
+ mov ebp, esp ; save esp in ebp
+ ;
+ ; Make stack 16-byte alignment to make sure save fxrstor later
+ ;
+ and esp, 0xfffffff0
+ sub esp, 12
+
+ ; store UINT32 Edi, Esi, Ebp, Ebx, Edx, Ecx, Eax;
+ push dword [ebp + 4] ; original eax
+ push ebx
+ push ecx
+ push edx
+ mov ebx, eax ; save vector in ebx
+ mov eax, ebp
+ add eax, 4 * 6
+ push eax ; original ESP
+ push dword [ebp] ; EBP
+ push esi
+ push edi
+
+ ;; UINT32 Cr0, Cr1, Cr2, Cr3, Cr4;
+ ;; insure FXSAVE/FXRSTOR is enabled in CR4...
+ ;; ... while we're at it, make sure DE is also enabled...
+ mov eax, 1
+ push ebx ; temporarily save value of ebx on stack
+ cpuid ; use CPUID to determine if FXSAVE/FXRESTOR and
+ ; DE are supported
+ pop ebx ; restore value of ebx that was overwritten by CPUID
+ mov eax, cr4
+ push eax ; push cr4 firstly
+ test edx, BIT24 ; Test for FXSAVE/FXRESTOR support
+ jz .0
+ or eax, BIT9 ; Set CR4.OSFXSR
+.0:
+ test edx, BIT2 ; Test for Debugging Extensions support
+ jz .1
+ or eax, BIT3 ; Set CR4.DE
+.1:
+ mov cr4, eax
+ mov eax, cr3
+ push eax
+ mov eax, cr2
+ push eax
+ push 0 ; cr0 will not saved???
+ mov eax, cr0
+ push eax
+
+ xor ecx, ecx
+ mov ecx, Ss
+ push ecx
+ mov ecx, Cs
+ push ecx
+ mov ecx, Ds
+ push ecx
+ mov ecx, Es
+ push ecx
+ mov ecx, Fs
+ push ecx
+ mov ecx, Gs
+ push ecx
+
+ ;; EIP
+ mov ecx, [ebp + 4 * 3] ; EIP
+ push ecx
+
+ ;; UINT32 Gdtr[2], Idtr[2];
+ sub esp, 8
+ sidt [esp]
+ sub esp, 8
+ sgdt [esp]
+
+ ;; UINT32 Ldtr, Tr;
+ xor eax, eax
+ str ax
+ push eax
+ sldt ax
+ push eax
+
+ ;; EFlags
+ mov ecx, [ebp + 4 * 5]
+ push ecx
+
+ ;; UINT32 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7;
+ mov eax, dr7
+ push eax
+
+ ;; clear Dr7 while executing debugger itself
+ xor eax, eax
+ mov dr7, eax
+
+ ;; Dr6
+ mov eax, dr6
+ push eax
+
+ ;; insure all status bits in dr6 are clear...
+ xor eax, eax
+ mov dr6, eax
+
+ mov eax, dr3
+ push eax
+ mov eax, dr2
+ push eax
+ mov eax, dr1
+ push eax
+ mov eax, dr0
+ push eax
+
+ ;; Clear Direction Flag
+ cld
+
+ ;; FX_SAVE_STATE_IA32 FxSaveState;
+ sub esp, 512
+ mov edi, esp
+ ;; Clear the buffer
+ xor eax, eax
+ mov ecx, 128 ;= 512 / 4
+ rep stosd
+ mov edi, esp
+
+ test edx, BIT24 ; Test for FXSAVE/FXRESTOR support.
+ ; edx still contains result from CPUID above
+ jz .2
+ db 0xf, 0xae, 00000111y ;fxsave [edi]
+.2:
+
+ ;; save the exception data
+ push dword [ebp + 8]
+
+ ; call the C interrupt process function
+ push esp ; Structure
+ push ebx ; vector
+ call ASM_PFX(InterruptProcess)
+ add esp, 8
+
+ ; skip the exception data
+ add esp, 4
+
+ ;; FX_SAVE_STATE_IA32 FxSaveState;
+ mov esi, esp
+ mov eax, 1
+ cpuid ; use CPUID to determine if FXSAVE/FXRESTOR are supported
+ test edx, BIT24 ; Test for FXSAVE/FXRESTOR support
+ jz .3
+ db 0xf, 0xae, 00001110y ; fxrstor [esi]
+.3:
+ add esp, 512
+
+ ;; UINT32 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7;
+ pop eax
+ mov dr0, eax
+ pop eax
+ mov dr1, eax
+ pop eax
+ mov dr2, eax
+ pop eax
+ mov dr3, eax
+ ;; skip restore of dr6. We cleared dr6 during the context save.
+ add esp, 4
+ pop eax
+ mov dr7, eax
+
+ ;; set EFlags
+ pop dword [ebp + 4 * 5] ; set EFLAGS in stack
+
+ ;; UINT32 Ldtr, Tr;
+ ;; UINT32 Gdtr[2], Idtr[2];
+ ;; Best not let anyone mess with these particular registers...
+ add esp, 24
+
+ ;; UINT32 Eip;
+ pop dword [ebp + 4 * 3] ; set EIP in stack
+
+ ;; UINT32 Gs, Fs, Es, Ds, Cs, Ss;
+ ;; NOTE - modified segment registers could hang the debugger... We
+ ;; could attempt to insulate ourselves against this possibility,
+ ;; but that poses risks as well.
+ ;;
+ pop gs
+ pop fs
+ pop es
+ pop ds
+ pop dword [ebp + 4 * 4] ; set CS in stack
+ pop ss
+
+ ;; UINT32 Cr0, Cr1, Cr2, Cr3, Cr4;
+ pop eax
+ mov cr0, eax
+ add esp, 4 ; skip for Cr1
+ pop eax
+ mov cr2, eax
+ pop eax
+ mov cr3, eax
+ pop eax
+ mov cr4, eax
+
+ ;; restore general register
+ pop edi
+ pop esi
+ pop dword [ebp] ; save updated ebp
+ pop dword [ebp + 4] ; save updated esp
+ pop edx
+ pop ecx
+ pop ebx
+ pop eax
+
+ mov esp, ebp
+ pop ebp ; restore ebp maybe updated
+ pop esp ; restore esp maybe updated
+ sub esp, 4 * 3 ; restore interrupt pushced stack
+
+ iretd
+
diff --git a/src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Library/DebugAgent/DebugAgentCommon/Ia32/DebugException.h b/src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Library/DebugAgent/DebugAgentCommon/Ia32/DebugException.h
new file mode 100644
index 00000000..1648b7c7
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Library/DebugAgent/DebugAgentCommon/Ia32/DebugException.h
@@ -0,0 +1,30 @@
+/** @file
+ Exception definitions.
+
+ Copyright (c) 2010, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _DEBUG_EXCEPTION_H_
+#define _DEBUG_EXCEPTION_H_
+
+#define DEBUG_EXCEPT_DIVIDE_ERROR 0
+#define DEBUG_EXCEPT_DEBUG 1
+#define DEBUG_EXCEPT_NMI 2
+#define DEBUG_EXCEPT_BREAKPOINT 3
+#define DEBUG_EXCEPT_OVERFLOW 4
+#define DEBUG_EXCEPT_BOUND 5
+#define DEBUG_EXCEPT_INVALID_OPCODE 6
+#define DEBUG_EXCEPT_DOUBLE_FAULT 8
+#define DEBUG_EXCEPT_INVALID_TSS 10
+#define DEBUG_EXCEPT_SEG_NOT_PRESENT 11
+#define DEBUG_EXCEPT_STACK_FAULT 12
+#define DEBUG_EXCEPT_GP_FAULT 13
+#define DEBUG_EXCEPT_PAGE_FAULT 14
+#define DEBUG_EXCEPT_FP_ERROR 16
+#define DEBUG_EXCEPT_ALIGNMENT_CHECK 17
+#define DEBUG_EXCEPT_MACHINE_CHECK 18
+#define DEBUG_EXCEPT_SIMD 19
+
+#endif
diff --git a/src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Library/DebugAgent/DebugAgentCommon/X64/ArchDebugSupport.c b/src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Library/DebugAgent/DebugAgentCommon/X64/ArchDebugSupport.c
new file mode 100644
index 00000000..eaf57521
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Library/DebugAgent/DebugAgentCommon/X64/ArchDebugSupport.c
@@ -0,0 +1,114 @@
+/** @file
+ Supporting functions for X64 architecture.
+
+ Copyright (c) 2010 - 2018, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "DebugAgent.h"
+
+/**
+ Initialize IDT entries to support source level debug.
+
+**/
+VOID
+InitializeDebugIdt (
+ VOID
+ )
+{
+ IA32_IDT_GATE_DESCRIPTOR *IdtEntry;
+ UINTN InterruptHandler;
+ IA32_DESCRIPTOR IdtDescriptor;
+ UINTN Index;
+ UINT16 CodeSegment;
+ UINT32 RegEdx;
+
+ AsmReadIdtr (&IdtDescriptor);
+
+ //
+ // Use current CS as the segment selector of interrupt gate in IDT
+ //
+ CodeSegment = AsmReadCs ();
+
+ IdtEntry = (IA32_IDT_GATE_DESCRIPTOR *) IdtDescriptor.Base;
+
+ for (Index = 0; Index < 20; Index ++) {
+ if (((PcdGet32 (PcdExceptionsIgnoredByDebugger) & ~(BIT1 | BIT3)) & (1 << Index)) != 0) {
+ //
+ // If the exception is masked to be reserved except for INT1 and INT3, skip it
+ //
+ continue;
+ }
+ InterruptHandler = (UINTN)&Exception0Handle + Index * ExceptionStubHeaderSize;
+ IdtEntry[Index].Bits.OffsetLow = (UINT16)(UINTN)InterruptHandler;
+ IdtEntry[Index].Bits.OffsetHigh = (UINT16)((UINTN)InterruptHandler >> 16);
+ IdtEntry[Index].Bits.OffsetUpper = (UINT32)((UINTN)InterruptHandler >> 32);
+ IdtEntry[Index].Bits.Selector = CodeSegment;
+ IdtEntry[Index].Bits.GateType = IA32_IDT_GATE_TYPE_INTERRUPT_32;
+ }
+
+ InterruptHandler = (UINTN) &TimerInterruptHandle;
+ IdtEntry[DEBUG_TIMER_VECTOR].Bits.OffsetLow = (UINT16)(UINTN)InterruptHandler;
+ IdtEntry[DEBUG_TIMER_VECTOR].Bits.OffsetHigh = (UINT16)((UINTN)InterruptHandler >> 16);
+ IdtEntry[DEBUG_TIMER_VECTOR].Bits.OffsetUpper = (UINT32)((UINTN)InterruptHandler >> 32);
+ IdtEntry[DEBUG_TIMER_VECTOR].Bits.Selector = CodeSegment;
+ IdtEntry[DEBUG_TIMER_VECTOR].Bits.GateType = IA32_IDT_GATE_TYPE_INTERRUPT_32;
+
+ //
+ // If the CPU supports Debug Extensions(CPUID:01 EDX:BIT2), then
+ // Set DE flag in CR4 to enable IO breakpoint
+ //
+ AsmCpuid (1, NULL, NULL, NULL, &RegEdx);
+ if ((RegEdx & BIT2) != 0) {
+ AsmWriteCr4 (AsmReadCr4 () | BIT3);
+ }
+}
+
+/**
+ Retrieve exception handler from IDT table by ExceptionNum.
+
+ @param[in] ExceptionNum Exception number
+
+ @return Exception handler
+
+**/
+VOID *
+GetExceptionHandlerInIdtEntry (
+ IN UINTN ExceptionNum
+ )
+{
+ IA32_IDT_GATE_DESCRIPTOR *IdtEntry;
+ IA32_DESCRIPTOR IdtDescriptor;
+
+ AsmReadIdtr (&IdtDescriptor);
+ IdtEntry = (IA32_IDT_GATE_DESCRIPTOR *) IdtDescriptor.Base;
+
+ return (VOID *) (IdtEntry[ExceptionNum].Bits.OffsetLow |
+ (((UINTN)IdtEntry[ExceptionNum].Bits.OffsetHigh) << 16) |
+ (((UINTN)IdtEntry[ExceptionNum].Bits.OffsetUpper) << 32));
+}
+
+/**
+ Set exception handler in IDT table by ExceptionNum.
+
+ @param[in] ExceptionNum Exception number
+ @param[in] ExceptionHandler Exception Handler to be set
+
+**/
+VOID
+SetExceptionHandlerInIdtEntry (
+ IN UINTN ExceptionNum,
+ IN VOID *ExceptionHandler
+ )
+{
+ IA32_IDT_GATE_DESCRIPTOR *IdtEntry;
+ IA32_DESCRIPTOR IdtDescriptor;
+
+ AsmReadIdtr (&IdtDescriptor);
+ IdtEntry = (IA32_IDT_GATE_DESCRIPTOR *) IdtDescriptor.Base;
+
+ IdtEntry[ExceptionNum].Bits.OffsetLow = (UINT16)(UINTN)ExceptionHandler;
+ IdtEntry[ExceptionNum].Bits.OffsetHigh = (UINT16)((UINTN)ExceptionHandler >> 16);
+ IdtEntry[ExceptionNum].Bits.OffsetUpper = (UINT32)((UINTN)ExceptionHandler >> 32);
+}
diff --git a/src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Library/DebugAgent/DebugAgentCommon/X64/ArchDebugSupport.h b/src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Library/DebugAgent/DebugAgentCommon/X64/ArchDebugSupport.h
new file mode 100644
index 00000000..07eec01c
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Library/DebugAgent/DebugAgentCommon/X64/ArchDebugSupport.h
@@ -0,0 +1,21 @@
+/** @file
+ X64 specific definitions for debug agent library instance.
+
+ Copyright (c) 2010 - 2012, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _ARCH_DEBUG_SUPPORT_H_
+#define _ARCH_DEBUG_SUPPORT_H_
+
+#include "ProcessorContext.h"
+#include "TransferProtocol.h"
+
+#define DEBUG_SW_BREAKPOINT_SYMBOL 0xcc
+#define DEBUG_ARCH_SYMBOL DEBUG_DATA_BREAK_CPU_ARCH_X64
+
+typedef DEBUG_DATA_X64_FX_SAVE_STATE DEBUG_DATA_FX_SAVE_STATE;
+typedef DEBUG_DATA_X64_SYSTEM_CONTEXT DEBUG_CPU_CONTEXT;
+
+#endif
diff --git a/src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Library/DebugAgent/DebugAgentCommon/X64/AsmFuncs.nasm b/src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Library/DebugAgent/DebugAgentCommon/X64/AsmFuncs.nasm
new file mode 100644
index 00000000..508c1116
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Library/DebugAgent/DebugAgentCommon/X64/AsmFuncs.nasm
@@ -0,0 +1,399 @@
+;------------------------------------------------------------------------------
+;
+; Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>
+; SPDX-License-Identifier: BSD-2-Clause-Patent
+;
+; Module Name:
+;
+; AsmFuncs.nasm
+;
+; Abstract:
+;
+; Debug interrupt handle functions.
+;
+;------------------------------------------------------------------------------
+
+#include "DebugException.h"
+
+SECTION .data
+
+extern ASM_PFX(InterruptProcess)
+global ASM_PFX(Exception0Handle)
+global ASM_PFX(TimerInterruptHandle)
+global ASM_PFX(ExceptionStubHeaderSize)
+
+%macro AGENT_HANDLER_SIGNATURE 0
+ db 0x41, 0x47, 0x54, 0x48 ; SIGNATURE_32('A','G','T','H')
+%endmacro
+
+ASM_PFX(ExceptionStubHeaderSize): dd Exception1Handle - ASM_PFX(Exception0Handle) ;
+CommonEntryAddr: dq CommonEntry ;
+
+DEFAULT REL
+SECTION .text
+
+AGENT_HANDLER_SIGNATURE
+ASM_PFX(Exception0Handle):
+ cli
+ push rcx
+ mov rcx, dword 0
+ jmp qword [CommonEntryAddr]
+AGENT_HANDLER_SIGNATURE
+Exception1Handle:
+ cli
+ push rcx
+ mov rcx, dword 1
+ jmp qword [CommonEntryAddr]
+AGENT_HANDLER_SIGNATURE
+Exception2Handle:
+ cli
+ push rcx
+ mov rcx, dword 2
+ jmp qword [CommonEntryAddr]
+AGENT_HANDLER_SIGNATURE
+Exception3Handle:
+ cli
+ push rcx
+ mov rcx, dword 3
+ jmp qword [CommonEntryAddr]
+AGENT_HANDLER_SIGNATURE
+Exception4Handle:
+ cli
+ push rcx
+ mov rcx, dword 4
+ jmp qword [CommonEntryAddr]
+AGENT_HANDLER_SIGNATURE
+Exception5Handle:
+ cli
+ push rcx
+ mov rcx, dword 5
+ jmp qword [CommonEntryAddr]
+AGENT_HANDLER_SIGNATURE
+Exception6Handle:
+ cli
+ push rcx
+ mov rcx, dword 6
+ jmp qword [CommonEntryAddr]
+AGENT_HANDLER_SIGNATURE
+Exception7Handle:
+ cli
+ push rcx
+ mov rcx, dword 7
+ jmp qword [CommonEntryAddr]
+AGENT_HANDLER_SIGNATURE
+Exception8Handle:
+ cli
+ push rcx
+ mov rcx, dword 8
+ jmp qword [CommonEntryAddr]
+AGENT_HANDLER_SIGNATURE
+Exception9Handle:
+ cli
+ push rcx
+ mov rcx, dword 9
+ jmp qword [CommonEntryAddr]
+AGENT_HANDLER_SIGNATURE
+Exception10Handle:
+ cli
+ push rcx
+ mov rcx, dword 10
+ jmp qword [CommonEntryAddr]
+AGENT_HANDLER_SIGNATURE
+Exception11Handle:
+ cli
+ push rcx
+ mov rcx, dword 11
+ jmp qword [CommonEntryAddr]
+AGENT_HANDLER_SIGNATURE
+Exception12Handle:
+ cli
+ push rcx
+ mov rcx, dword 12
+ jmp qword [CommonEntryAddr]
+AGENT_HANDLER_SIGNATURE
+Exception13Handle:
+ cli
+ push rcx
+ mov rcx, dword 13
+ jmp qword [CommonEntryAddr]
+AGENT_HANDLER_SIGNATURE
+Exception14Handle:
+ cli
+ push rcx
+ mov rcx, dword 14
+ jmp qword [CommonEntryAddr]
+AGENT_HANDLER_SIGNATURE
+Exception15Handle:
+ cli
+ push rcx
+ mov rcx, dword 15
+ jmp qword [CommonEntryAddr]
+AGENT_HANDLER_SIGNATURE
+Exception16Handle:
+ cli
+ push rcx
+ mov rcx, dword 16
+ jmp qword [CommonEntryAddr]
+AGENT_HANDLER_SIGNATURE
+Exception17Handle:
+ cli
+ push rcx
+ mov rcx, dword 17
+ jmp qword [CommonEntryAddr]
+AGENT_HANDLER_SIGNATURE
+Exception18Handle:
+ cli
+ push rcx
+ mov rcx, dword 18
+ jmp qword [CommonEntryAddr]
+AGENT_HANDLER_SIGNATURE
+Exception19Handle:
+ cli
+ push rcx
+ mov rcx, dword 19
+ jmp qword [CommonEntryAddr]
+AGENT_HANDLER_SIGNATURE
+ASM_PFX(TimerInterruptHandle):
+ cli
+ push rcx
+ mov rcx, dword 32
+ jmp qword [CommonEntryAddr]
+
+CommonEntry:
+ ; We need to determine if any extra data was pushed by the exception
+ cmp rcx, DEBUG_EXCEPT_DOUBLE_FAULT
+ je NoExtrPush
+ cmp rcx, DEBUG_EXCEPT_INVALID_TSS
+ je NoExtrPush
+ cmp rcx, DEBUG_EXCEPT_SEG_NOT_PRESENT
+ je NoExtrPush
+ cmp rcx, DEBUG_EXCEPT_STACK_FAULT
+ je NoExtrPush
+ cmp rcx, DEBUG_EXCEPT_GP_FAULT
+ je NoExtrPush
+ cmp rcx, DEBUG_EXCEPT_PAGE_FAULT
+ je NoExtrPush
+ cmp rcx, DEBUG_EXCEPT_ALIGNMENT_CHECK
+ je NoExtrPush
+
+ push qword [rsp]
+ mov qword [rsp + 8], 0
+
+NoExtrPush:
+ push rbp
+ mov rbp, rsp
+
+ ; store UINT64 r8, r9, r10, r11, r12, r13, r14, r15;
+ push r15
+ push r14
+ push r13
+ push r12
+ push r11
+ push r10
+ push r9
+ push r8
+
+ mov r8, cr8
+ push r8
+
+ ; store UINT64 Rdi, Rsi, Rbp, Rsp, Rdx, Rcx, Rbx, Rax;
+ push rax
+ push rbx
+ push qword [rbp + 8] ; original rcx
+ push rdx
+ push qword [rbp + 6 * 8] ; original rsp
+ push qword [rbp] ; original rbp
+ push rsi
+ push rdi
+
+ ;; UINT32 Cr0, Cr1, Cr2, Cr3, Cr4;
+ ;; insure FXSAVE/FXRSTOR is enabled in CR4...
+ ;; ... while we're at it, make sure DE is also enabled...
+ mov rax, cr4
+ or rax, 0x208
+ mov cr4, rax
+ push rax
+ mov rax, cr3
+ push rax
+ mov rax, cr2
+ push rax
+ push 0
+ mov rax, cr0
+ push rax
+
+ xor rax, rax
+ mov rax, Ss
+ push rax
+ mov rax, Cs
+ push rax
+ mov rax, Ds
+ push rax
+ mov rax, Es
+ push rax
+ mov rax, Fs
+ push rax
+ mov rax, Gs
+ push rax
+
+ ;; EIP
+ mov rax, [rbp + 8 * 3] ; EIP
+ push rax
+
+ ;; UINT64 Gdtr[2], Idtr[2];
+ sub rsp, 16
+ sidt [rsp]
+ sub rsp, 16
+ sgdt [rsp]
+
+ ;; UINT64 Ldtr, Tr;
+ xor rax, rax
+ str ax
+ push rax
+ sldt ax
+ push rax
+
+ ;; EFlags
+ mov rax, [rbp + 8 * 5]
+ push rax
+
+ ;; UINT64 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7;
+ mov rax, dr7
+ push rax
+
+ ;; clear Dr7 while executing debugger itself
+ xor rax, rax
+ mov dr7, rax
+
+ ;; Dr6
+ mov rax, dr6
+ push rax
+
+ ;; insure all status bits in dr6 are clear...
+ xor rax, rax
+ mov dr6, rax
+
+ mov rax, dr3
+ push rax
+ mov rax, dr2
+ push rax
+ mov rax, dr1
+ push rax
+ mov rax, dr0
+ push rax
+
+ ;; Clear Direction Flag
+ cld
+
+ sub rsp, 512
+ mov rdi, rsp
+ ;; Clear the buffer
+ xor rax, rax
+ push rcx
+ mov rcx, dword 64 ;= 512 / 8
+ rep stosq
+ pop rcx
+ mov rdi, rsp
+ db 0xf, 0xae, 00000111y ;fxsave [rdi]
+
+ ;; save the exception data
+ push qword [rbp + 16]
+
+ ; call the C interrupt process function
+ mov rdx, rsp ; Structure
+ mov r15, rcx ; save vector in r15
+
+ ;
+ ; Per X64 calling convention, allocate maximum parameter stack space
+ ; and make sure RSP is 16-byte aligned
+ ;
+ sub rsp, 32 + 8
+ call ASM_PFX(InterruptProcess)
+ add rsp, 32 + 8
+
+ ;; skip the exception data
+ add rsp, 8
+
+ mov rsi, rsp
+ db 0xf, 0xae, 00001110y ; fxrstor [rsi]
+ add rsp, 512
+
+ ;; UINT64 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7;
+ pop rax
+ mov dr0, rax
+ pop rax
+ mov dr1, rax
+ pop rax
+ mov dr2, rax
+ pop rax
+ mov dr3, rax
+ ;; skip restore of dr6. We cleared dr6 during the context save.
+ add rsp, 8
+ pop rax
+ mov dr7, rax
+
+ ;; set EFlags
+ pop qword [rbp + 8 * 5]
+
+ ;; UINT64 Ldtr, Tr;
+ ;; UINT64 Gdtr[2], Idtr[2];
+ ;; Best not let anyone mess with these particular registers...
+ add rsp, 24 * 2
+
+ ;; UINT64 Eip;
+ pop qword [rbp + 8 * 3] ; set EIP in stack
+
+ ;; UINT64 Gs, Fs, Es, Ds, Cs, Ss;
+ ;; NOTE - modified segment registers could hang the debugger... We
+ ;; could attempt to insulate ourselves against this possibility,
+ ;; but that poses risks as well.
+ ;;
+ pop rax
+ pop rax
+ pop rax
+ mov es, rax
+ pop rax
+ mov ds, rax
+ pop qword [rbp + 8 * 4] ; Set CS in stack
+ pop rax
+ mov ss, rax
+
+ ;; UINT64 Cr0, Cr1, Cr2, Cr3, Cr4;
+ pop rax
+ mov cr0, rax
+ add rsp, 8 ; skip for Cr1
+ pop rax
+ mov cr2, rax
+ pop rax
+ mov cr3, rax
+ pop rax
+ mov cr4, rax
+
+ ;; restore general register
+ pop rdi
+ pop rsi
+ add rsp, 8 ; skip rbp
+ add rsp, 8 ; skip rsp
+ pop rdx
+ pop rcx
+ pop rbx
+ pop rax
+
+ pop r8
+ mov cr8, r8
+
+ ; store UINT64 r8, r9, r10, r11, r12, r13, r14, r15;
+ pop r8
+ pop r9
+ pop r10
+ pop r11
+ pop r12
+ pop r13
+ pop r14
+ pop r15
+
+ mov rsp, rbp
+ pop rbp
+ add rsp, 16 ; skip rcx and error code
+
+ iretq
+
diff --git a/src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Library/DebugAgent/DebugAgentCommon/X64/DebugException.h b/src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Library/DebugAgent/DebugAgentCommon/X64/DebugException.h
new file mode 100644
index 00000000..1648b7c7
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Library/DebugAgent/DebugAgentCommon/X64/DebugException.h
@@ -0,0 +1,30 @@
+/** @file
+ Exception definitions.
+
+ Copyright (c) 2010, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _DEBUG_EXCEPTION_H_
+#define _DEBUG_EXCEPTION_H_
+
+#define DEBUG_EXCEPT_DIVIDE_ERROR 0
+#define DEBUG_EXCEPT_DEBUG 1
+#define DEBUG_EXCEPT_NMI 2
+#define DEBUG_EXCEPT_BREAKPOINT 3
+#define DEBUG_EXCEPT_OVERFLOW 4
+#define DEBUG_EXCEPT_BOUND 5
+#define DEBUG_EXCEPT_INVALID_OPCODE 6
+#define DEBUG_EXCEPT_DOUBLE_FAULT 8
+#define DEBUG_EXCEPT_INVALID_TSS 10
+#define DEBUG_EXCEPT_SEG_NOT_PRESENT 11
+#define DEBUG_EXCEPT_STACK_FAULT 12
+#define DEBUG_EXCEPT_GP_FAULT 13
+#define DEBUG_EXCEPT_PAGE_FAULT 14
+#define DEBUG_EXCEPT_FP_ERROR 16
+#define DEBUG_EXCEPT_ALIGNMENT_CHECK 17
+#define DEBUG_EXCEPT_MACHINE_CHECK 18
+#define DEBUG_EXCEPT_SIMD 19
+
+#endif