diff options
Diffstat (limited to 'SourceLevelDebugPkg/Library/DebugAgent/DebugAgentCommon')
14 files changed, 5120 insertions, 5120 deletions
diff --git a/SourceLevelDebugPkg/Library/DebugAgent/DebugAgentCommon/DebugAgent.c b/SourceLevelDebugPkg/Library/DebugAgent/DebugAgentCommon/DebugAgent.c index b553a2a9aa..64319a4b31 100644 --- a/SourceLevelDebugPkg/Library/DebugAgent/DebugAgentCommon/DebugAgent.c +++ b/SourceLevelDebugPkg/Library/DebugAgent/DebugAgentCommon/DebugAgent.c @@ -1,2698 +1,2698 @@ -/** @file
- Common 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 ((DEBUG_ERROR, "DebugAgent: Mailbox checksum error, stack or heap crashed!\n"));
- DEBUG ((DEBUG_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 remaining 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 response 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 update 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;
-}
+/** @file + Common 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 ((DEBUG_ERROR, "DebugAgent: Mailbox checksum error, stack or heap crashed!\n")); + DEBUG ((DEBUG_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 remaining 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 response 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 update 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/SourceLevelDebugPkg/Library/DebugAgent/DebugAgentCommon/DebugAgent.h b/SourceLevelDebugPkg/Library/DebugAgent/DebugAgentCommon/DebugAgent.h index 4c72f8f3a9..0e14bcde55 100644 --- a/SourceLevelDebugPkg/Library/DebugAgent/DebugAgentCommon/DebugAgent.h +++ b/SourceLevelDebugPkg/Library/DebugAgent/DebugAgentCommon/DebugAgent.h @@ -1,496 +1,496 @@ -/** @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 remaining 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
+/** @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 remaining 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/SourceLevelDebugPkg/Library/DebugAgent/DebugAgentCommon/DebugMp.c b/SourceLevelDebugPkg/Library/DebugAgent/DebugAgentCommon/DebugMp.c index 89f922aba0..2951c0c59a 100644 --- a/SourceLevelDebugPkg/Library/DebugAgent/DebugAgentCommon/DebugMp.c +++ b/SourceLevelDebugPkg/Library/DebugAgent/DebugAgentCommon/DebugMp.c @@ -1,382 +1,382 @@ -/** @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;
-}
+/** @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/SourceLevelDebugPkg/Library/DebugAgent/DebugAgentCommon/DebugMp.h b/SourceLevelDebugPkg/Library/DebugAgent/DebugAgentCommon/DebugMp.h index a0bc24ebfd..cc75377265 100644 --- a/SourceLevelDebugPkg/Library/DebugAgent/DebugAgentCommon/DebugMp.h +++ b/SourceLevelDebugPkg/Library/DebugAgent/DebugAgentCommon/DebugMp.h @@ -1,215 +1,215 @@ -/** @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
+/** @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/SourceLevelDebugPkg/Library/DebugAgent/DebugAgentCommon/DebugTimer.c b/SourceLevelDebugPkg/Library/DebugAgent/DebugAgentCommon/DebugTimer.c index 833aa76a7d..01eb21578e 100644 --- a/SourceLevelDebugPkg/Library/DebugAgent/DebugAgentCommon/DebugTimer.c +++ b/SourceLevelDebugPkg/Library/DebugAgent/DebugAgentCommon/DebugTimer.c @@ -1,145 +1,145 @@ -/** @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 ((DEBUG_INFO, "Debug Timer: FSB Clock = %d\n", PcdGet32 (PcdFSBClock)));
- DEBUG ((DEBUG_INFO, "Debug Timer: Divisor = %d\n", ApicTimerDivisor));
- DEBUG ((DEBUG_INFO, "Debug Timer: Frequency = %d\n", ApicTimerFrequency));
- DEBUG ((DEBUG_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);
-}
+/** @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 ((DEBUG_INFO, "Debug Timer: FSB Clock = %d\n", PcdGet32 (PcdFSBClock))); + DEBUG ((DEBUG_INFO, "Debug Timer: Divisor = %d\n", ApicTimerDivisor)); + DEBUG ((DEBUG_INFO, "Debug Timer: Frequency = %d\n", ApicTimerFrequency)); + DEBUG ((DEBUG_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/SourceLevelDebugPkg/Library/DebugAgent/DebugAgentCommon/DebugTimer.h b/SourceLevelDebugPkg/Library/DebugAgent/DebugAgentCommon/DebugTimer.h index be9566643f..6c07cfcfb7 100644 --- a/SourceLevelDebugPkg/Library/DebugAgent/DebugAgentCommon/DebugTimer.h +++ b/SourceLevelDebugPkg/Library/DebugAgent/DebugAgentCommon/DebugTimer.h @@ -1,44 +1,44 @@ -/** @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
+/** @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/SourceLevelDebugPkg/Library/DebugAgent/DebugAgentCommon/Ia32/ArchDebugSupport.c b/SourceLevelDebugPkg/Library/DebugAgent/DebugAgentCommon/Ia32/ArchDebugSupport.c index 99b9a7fa98..cb8387db7b 100644 --- a/SourceLevelDebugPkg/Library/DebugAgent/DebugAgentCommon/Ia32/ArchDebugSupport.c +++ b/SourceLevelDebugPkg/Library/DebugAgent/DebugAgentCommon/Ia32/ArchDebugSupport.c @@ -1,111 +1,111 @@ -/** @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);
-}
+/** @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/SourceLevelDebugPkg/Library/DebugAgent/DebugAgentCommon/Ia32/ArchDebugSupport.h b/SourceLevelDebugPkg/Library/DebugAgent/DebugAgentCommon/Ia32/ArchDebugSupport.h index 5205b23046..89874380cd 100644 --- a/SourceLevelDebugPkg/Library/DebugAgent/DebugAgentCommon/Ia32/ArchDebugSupport.h +++ b/SourceLevelDebugPkg/Library/DebugAgent/DebugAgentCommon/Ia32/ArchDebugSupport.h @@ -1,21 +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
+/** @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/SourceLevelDebugPkg/Library/DebugAgent/DebugAgentCommon/Ia32/AsmFuncs.nasm b/SourceLevelDebugPkg/Library/DebugAgent/DebugAgentCommon/Ia32/AsmFuncs.nasm index b5e5a96e34..649a276ef4 100644 --- a/SourceLevelDebugPkg/Library/DebugAgent/DebugAgentCommon/Ia32/AsmFuncs.nasm +++ b/SourceLevelDebugPkg/Library/DebugAgent/DebugAgentCommon/Ia32/AsmFuncs.nasm @@ -1,413 +1,413 @@ -;------------------------------------------------------------------------------
-;
-; Copyright (c) 2010 - 2022, 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
- 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
- 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
-
+;------------------------------------------------------------------------------ +; +; Copyright (c) 2010 - 2022, 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 + 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 + 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/SourceLevelDebugPkg/Library/DebugAgent/DebugAgentCommon/Ia32/DebugException.h b/SourceLevelDebugPkg/Library/DebugAgent/DebugAgentCommon/Ia32/DebugException.h index 05cb45c78e..b6bad9a46d 100644 --- a/SourceLevelDebugPkg/Library/DebugAgent/DebugAgentCommon/Ia32/DebugException.h +++ b/SourceLevelDebugPkg/Library/DebugAgent/DebugAgentCommon/Ia32/DebugException.h @@ -1,30 +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
+/** @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/SourceLevelDebugPkg/Library/DebugAgent/DebugAgentCommon/X64/ArchDebugSupport.c b/SourceLevelDebugPkg/Library/DebugAgent/DebugAgentCommon/X64/ArchDebugSupport.c index bda113ecca..0838b0f5c8 100644 --- a/SourceLevelDebugPkg/Library/DebugAgent/DebugAgentCommon/X64/ArchDebugSupport.c +++ b/SourceLevelDebugPkg/Library/DebugAgent/DebugAgentCommon/X64/ArchDebugSupport.c @@ -1,115 +1,115 @@ -/** @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);
-}
+/** @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/SourceLevelDebugPkg/Library/DebugAgent/DebugAgentCommon/X64/ArchDebugSupport.h b/SourceLevelDebugPkg/Library/DebugAgent/DebugAgentCommon/X64/ArchDebugSupport.h index b795202959..ebb8857fdf 100644 --- a/SourceLevelDebugPkg/Library/DebugAgent/DebugAgentCommon/X64/ArchDebugSupport.h +++ b/SourceLevelDebugPkg/Library/DebugAgent/DebugAgentCommon/X64/ArchDebugSupport.h @@ -1,21 +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
+/** @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/SourceLevelDebugPkg/Library/DebugAgent/DebugAgentCommon/X64/AsmFuncs.nasm b/SourceLevelDebugPkg/Library/DebugAgent/DebugAgentCommon/X64/AsmFuncs.nasm index b1019e017b..cd3b07d829 100644 --- a/SourceLevelDebugPkg/Library/DebugAgent/DebugAgentCommon/X64/AsmFuncs.nasm +++ b/SourceLevelDebugPkg/Library/DebugAgent/DebugAgentCommon/X64/AsmFuncs.nasm @@ -1,399 +1,399 @@ -;------------------------------------------------------------------------------
-;
-; Copyright (c) 2016 - 2022, 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
- 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
- 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
-
+;------------------------------------------------------------------------------ +; +; Copyright (c) 2016 - 2022, 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 + 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 + 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/SourceLevelDebugPkg/Library/DebugAgent/DebugAgentCommon/X64/DebugException.h b/SourceLevelDebugPkg/Library/DebugAgent/DebugAgentCommon/X64/DebugException.h index 05cb45c78e..b6bad9a46d 100644 --- a/SourceLevelDebugPkg/Library/DebugAgent/DebugAgentCommon/X64/DebugException.h +++ b/SourceLevelDebugPkg/Library/DebugAgent/DebugAgentCommon/X64/DebugException.h @@ -1,30 +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
+/** @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 |
