/** @file
Commond Debug Agent library implementition. 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, Intel Corporation. All rights reserved.<BR>
This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php.
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
**/
#include "DebugAgent.h"
#include "Ia32/DebugException.h"
/**
Check if HOST is connected based on Mailbox.
@retval TRUE HOST is connected.
@retval FALSE HOST is not connected.
**/
BOOLEAN
IsHostConnected (
VOID
)
{
DEBUG_AGENT_MAILBOX *Mailbox;
Mailbox = GetMailboxPointer ();
if (Mailbox->DebugFlag.Bits.HostPresent == 1) {
return TRUE;
} else {
return FALSE;
}
}
/**
Set HOST connect flag in Mailbox.
**/
VOID
SetHostConnectedFlag (
VOID
)
{
DEBUG_AGENT_MAILBOX *Mailbox;
Mailbox = GetMailboxPointer ();
Mailbox->DebugFlag.Bits.HostPresent = 1;
}
/**
Set debug flag of Debug Agent in Mailbox.
@param DebugFlag Debug Flag defined by transfer protocol.
**/
VOID
SetDebugFlag (
IN UINT32 DebugFlag
)
{
DEBUG_AGENT_MAILBOX *Mailbox;
Mailbox = GetMailboxPointer ();
if ((DebugFlag & SOFT_DEBUGGER_SETTING_SMM_ENTRY_BREAK) != 0) {
Mailbox->DebugFlag.Bits.BreakOnNextSmi = 1;
} else {
Mailbox->DebugFlag.Bits.BreakOnNextSmi = 0;
}
}
/**
Exectue 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;
}
/**
Exectue 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;
}
/**
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 |= 0x3 << (RegisterIndex * 2);
//
// Set RWx and Lenx
//
Dr7Value &= ~(0xf0000 << (RegisterIndex * 4));
Dr7Value |= (SetHwBreakpoint->Type.Length | SetHwBreakpoint->Type.Access) << (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 &= ~(0x3 << 0);
}
if ((ClearHwBreakpoint->IndexMask & BIT1) != 0) {
CpuContext->Dr1 = 0;
CpuContext->Dr7 &= ~(0x3 << 2);
}
if ((ClearHwBreakpoint->IndexMask & BIT2) != 0) {
CpuContext->Dr2 = 0;
CpuContext->Dr7 &= ~(0x3 << 4);
}
if ((ClearHwBreakpoint->IndexMask & BIT3) != 0) {
CpuContext->Dr3 = 0;
CpuContext->Dr7 &= ~(0x3 << 6);
}
}
/**
Send acknowledge packet to HOST.
@param[in] AckCommand Type of Acknowledge packet.
**/
VOID
SendAckPacket (
IN UINT8 AckCommand
)
{
DEBUG_COMMAND_HEADER DebugCommonHeader;
DEBUG_PORT_HANDLE Handle;
Handle = GetDebugPortHandle();
DebugCommonHeader.StartSymbol = DEBUG_STARTING_SYMBOL_NORMAL;
DebugCommonHeader.Command = AckCommand;
DebugCommonHeader.DataLength = 0;
DebugPortWriteBuffer (Handle, (UINT8 *) &DebugCommonHeader, sizeof (DEBUG_COMMAND_HEADER));
}
/**
Receive acknowledge packet from HOST in specified time.
@param[out] Ack Returned acknowlege type from HOST.
@param[in] Timeout Time out value to wait for acknowlege from HOST.
The unit is microsecond.
@param[out] BreakReceived If BreakReceived is not NULL,
TRUE is retured if break-in symbol received.
FALSE is retured if break-in symbol not received.
@retval RETRUEN_SUCCESS Succeed to receive acknowlege packet from HOST,
the type of acknowlege packet saved in Ack.
@retval RETURN_TIMEOUT Specified timeout value was up.
**/
RETURN_STATUS
ReceiveAckPacket (
OUT UINT8 *Ack,
IN UINTN Timeout,
OUT BOOLEAN *BreakReceived OPTIONAL
)
{
DEBUG_COMMAND_HEADER DebugCommonHeader;
DEBUG_PORT_HANDLE Handle;
Handle = GetDebugPortHandle();
while (TRUE) {
if (DebugPortReadBuffer (Handle, (UINT8 *) &DebugCommonHeader.StartSymbol, 1, Timeout) == 0) {
return RETURN_TIMEOUT;
}
if (DebugCommonHeader.StartSymbol == DEBUG_STARTING_SYMBOL_BREAK) {
if (BreakReceived != NULL) {
SendAckPacket (DEBUG_COMMAND_HALT_DEFERRED);
*BreakReceived = TRUE;
}
}
if (DebugCommonHeader.StartSymbol == DEBUG_STARTING_SYMBOL_NORMAL) {
break;
}
}
if (DebugPortReadBuffer (Handle, (UINT8 *)&DebugCommonHeader.Command, sizeof (DEBUG_COMMAND_HEADER) - 1, Timeout) == 0) {
return RETURN_TIMEOUT;
}
*Ack = DebugCommonHeader.Command;
return RETURN_SUCCESS;
}
/**
Receive acknowledge packet OK from HOST in specified time.
@param[in] Timeout Time out value to wait for acknowlege from HOST.
The unit is microsecond.
@param[out] BreakReceived If BreakReceived is not NULL,
TRUE is retured if break-in symbol received.
FALSE is retured if break-in symbol not received.
@retval RETRUEN_SUCCESS Succeed to receive acknowlege packet from HOST,
the type of acknowlege packet saved in Ack.
@retval RETURN_TIMEOUT Specified timeout value was up.
**/
RETURN_STATUS
WaitForAckPacketOK (
IN UINTN Timeout,
OUT BOOLEAN *BreakReceived OPTIONAL
)
{
RETURN_STATUS Status;
UINT8 Ack;
while (TRUE) {
Status = ReceiveAckPacket (&Ack, Timeout, BreakReceived);
if ((Status == RETURN_SUCCESS && Ack == DEBUG_COMMAND_OK) ||
Status == RETURN_TIMEOUT) {
break;
}
}
return Status;
}
/**
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.
@retval RETURN_SUCCESS A valid package was reveived in InputPacket.
@retval RETURN_NOT_READY No valid start symbol received.
@retval RETURN_TIMEOUT Timeout occurs.
**/
RETURN_STATUS
ReceivePacket (
OUT UINT8 *InputPacket,
OUT BOOLEAN *BreakReceived
)
{
DEBUG_COMMAND_HEADER *DebugHeader;
UINTN Received;
DEBUG_PORT_HANDLE Handle;
Handle = GetDebugPortHandle();
//
// Find the valid start symbol
//
DebugPortReadBuffer (Handle, InputPacket, 1, 0);
if (*InputPacket == DEBUG_STARTING_SYMBOL_BREAK) {
*BreakReceived = TRUE;
SendAckPacket (DEBUG_COMMAND_HALT_DEFERRED);
}
if (*InputPacket != DEBUG_STARTING_SYMBOL_NORMAL) {
return RETURN_NOT_READY;
}
//
// Read Package header
//
Received = DebugPortReadBuffer (Handle, InputPacket + 1, sizeof(DEBUG_COMMAND_HEADER_NO_START_SYMBOL), 0);
if (Received == 0) {
return RETURN_TIMEOUT;
}
DebugHeader = (DEBUG_COMMAND_HEADER *) InputPacket;
//
// Read the payload if has
//
if (DebugHeader->DataLength > 0 && DebugHeader->DataLength < (DEBUG_DATA_MAXIMUM_REAL_DATA - sizeof(DEBUG_COMMAND_HEADER))) {
InputPacket = InputPacket + 1 + Received;
Received = DebugPortReadBuffer (Handle, InputPacket, DebugHeader->DataLength, 0);
if (Received == 0) {
return RETURN_TIMEOUT;
}
}
return RETURN_SUCCESS;
}
/**
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;
//
// If it's 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) {
Cause = DEBUG_DATA_BREAK_CAUSE_EXCEPTION;
}
break;
}
return Cause;
}
/**
Send packet with response data to HOST.
@param[in] CpuContext Pointer to saved CPU context.
@param[in] Data Pointer to response data buffer.
@param[in] DataSize Size of response data in byte.
@retval RETURN_SUCCESS Response data was sent successfully.
@retval RETURN_DEVICE_ERROR Cannot receive DEBUG_COMMAND_OK from HOST.
**/
RETURN_STATUS
SendDataResponsePacket (
IN DEBUG_CPU_CONTEXT *CpuContext,
IN UINT8 *Data,
IN UINT16 DataSize
)
{
UINT8 PacketHeader[DEBUG_DATA_MAXIMUM_LENGTH_FOR_SMALL_COMMANDS];
BOOLEAN LastPacket;
UINT8 Ack;
UINT8 PacketData[DEBUG_DATA_MAXIMUM_REAL_DATA];
DEBUG_PORT_HANDLE Handle;
Handle = GetDebugPortHandle();
((DEBUG_COMMAND_HEADER *)PacketHeader)->StartSymbol = DEBUG_STARTING_SYMBOL_NORMAL;
while (TRUE) {
if (DataSize <= DEBUG_DATA_MAXIMUM_REAL_DATA) {
LastPacket = TRUE;
((DEBUG_COMMAND_HEADER *)PacketHeader)->Command = DEBUG_COMMAND_OK;
((DEBUG_COMMAND_HEADER *)PacketHeader)->DataLength = (UINT8) DataSize;
CopyMem (PacketData, Data, DataSize);
} else {
LastPacket = FALSE;
((DEBUG_COMMAND_HEADER *)PacketHeader)->Command = DEBUG_COMMAND_IN_PROGRESS;
((DEBUG_COMMAND_HEADER *)PacketHeader)->DataLength = DEBUG_DATA_MAXIMUM_REAL_DATA;
CopyMem (PacketData, Data, DEBUG_DATA_MAXIMUM_REAL_DATA);
}
DebugPortWriteBuffer (Handle, PacketHeader, sizeof (DEBUG_COMMAND_HEADER));
DebugPortWriteBuffer (Handle, PacketData, ((DEBUG_COMMAND_HEADER *)PacketHeader)->DataLength);
ReceiveAckPacket(&Ack, 0, NULL);
switch (Ack) {
case DEBUG_COMMAND_RESEND:
//
// Send the packet again
//
break;
case DEBUG_COMMAND_CONTINUE:
//
// Send the rest packet
//
Data += DEBUG_DATA_MAXIMUM_REAL_DATA;
DataSize -= DEBUG_DATA_MAXIMUM_REAL_DATA;
break;
case DEBUG_COMMAND_OK:
if (LastPacket) {
//
// If this is the last packet, return RETURN_SUCCESS.
//
return RETURN_SUCCESS;
} else {
return RETURN_DEVICE_ERROR;
}
default:
return RETURN_DEVICE_ERROR;
}
}
}
/**
Send break cause packet to HOST.
@param[in] Vector Vector value of exception or interrutp.
@param[in] CpuContext Pointer to save CPU context.
@retval RETURN_SUCCESS Response data was sent successfully.
@retval RETURN_DEVICE_ERROR Cannot receive DEBUG_COMMAND_OK from HOST.
**/
RETURN_STATUS
SendBreakCausePacket (
IN UINTN Vector,
IN DEBUG_CPU_CONTEXT *CpuContext
)
{
DEBUG_DATA_RESPONSE_BREAK_CAUSE DebugDataBreakCause;
DebugDataBreakCause.StopAddress = CpuContext->Eip;
DebugDataBreakCause.Cause = GetBreakCause (Vector, CpuContext);
return SendDataResponsePacket (CpuContext, (UINT8 *) &DebugDataBreakCause, (UINT16) sizeof (DEBUG_DATA_RESPONSE_BREAK_CAUSE));
}
/**
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 interrutp.
@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_MAXIMUM_LENGTH_FOR_SMALL_COMMANDS];
DEBUG_COMMAND_HEADER *DebugHeader;
UINT8 Data8;
UINT32 Data32;
UINT64 Data64;
UINTN DataN;
DEBUG_DATA_READ_MEMORY_8 *MemoryRead;
DEBUG_DATA_WRITE_MEMORY_8 *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_REPONSE_READ_REGISTER_GROUP_SEGLIM RegisterGroupSegLim;
DEBUG_DATA_REPONSE_READ_REGISTER_GROUP_SEGBASE RegisterGroupSegBase;
DEBUG_DATA_RESPONSE_GET_REVISION DebugAgentRevision;
BOOLEAN HaltDeferred;
DEBUG_DATA_RESPONSE_GET_EXCEPTION Exception;
UINT32 ProcessorIndex;
DEBUG_PORT_HANDLE Handle;
Handle = GetDebugPortHandle();
ProcessorIndex = 0;
HaltDeferred = BreakReceived;
if (MultiProcessorDebugSupport) {
ProcessorIndex = GetProcessorIndex ();
SetCpuStopFlagByIndex (ProcessorIndex, TRUE);
}
while (TRUE) {
if (MultiProcessorDebugSupport) {
if (mDebugMpContext.ViewPointIndex != ProcessorIndex) {
if (mDebugMpContext.RunCommandSet) {
SetCpuStopFlagByIndex (ProcessorIndex, FALSE);
CommandGo (CpuContext);
break;
} else {
continue;
}
}
}
AcquireDebugPortControl ();
Status = ReceivePacket (InputPacketBuffer, &BreakReceived);
if (BreakReceived) {
HaltDeferred = TRUE;
BreakReceived = FALSE;
}
if (Status != RETURN_SUCCESS) {
ReleaseDebugPortControl ();
continue;
}
Data8 = 1;
DebugHeader =(DEBUG_COMMAND_HEADER *) InputPacketBuffer;
switch (DebugHeader->Command) {
case DEBUG_COMMAND_RESET:
SendAckPacket (DEBUG_COMMAND_OK);
ReleaseDebugPortControl ();
ResetCold ();
//
// Wait for reset
//
CpuDeadLoop ();
break;
case DEBUG_COMMAND_GO:
CommandGo (CpuContext);
if (!HaltDeferred) {
//
// If no HALT command received when being in-active mode
//
if (MultiProcessorDebugSupport) {
Data32 = FindCpuNotRunning ();
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 and exit to wait for command packet from HOST.
//
SendAckPacket (DEBUG_COMMAND_BREAK_POINT);
WaitForAckPacketOK (0, &BreakReceived);
ReleaseDebugPortControl ();
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);
ReleaseDebugPortControl ();
return;
} else {
//
// If reveived HALT command, need to defer the GO command
//
SendAckPacket (DEBUG_COMMAND_HALT_PROCESSED);
HaltDeferred = FALSE;
Data8 = GetBreakCause (Vector, CpuContext);
if (Data8 == DEBUG_DATA_BREAK_CAUSE_IMAGE_LOAD || Data8 == DEBUG_DATA_BREAK_CAUSE_IMAGE_UNLOAD) {
CpuContext->Dr0 = 0;
CpuContext->Dr3 = 0;
}
Vector = DEBUG_TIMER_VECTOR;
}
break;
case DEBUG_COMMAND_BREAK_CAUSE:
if (MultiProcessorDebugSupport && ProcessorIndex != mDebugMpContext.BreakAtCpuIndex) {
Status = SendBreakCausePacket (DEBUG_TIMER_VECTOR, CpuContext);
} else {
Status = SendBreakCausePacket (Vector, CpuContext);
}
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);
mDebugMpContext.BreakAtCpuIndex = (UINT32) (-1);
ReleaseDebugPortControl ();
//
// Executing stepping command directly without sending ACK packet.
//
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 (CpuContext, (UINT8 *) &Data8, (UINT16) sizeof (UINT8));
break;
case DEBUG_COMMAND_READ_MEMORY_64:
Data8 *= 2;
case DEBUG_COMMAND_READ_MEMORY_32:
Data8 *= 2;
case DEBUG_COMMAND_READ_MEMORY_16:
Data8 *= 2;
case DEBUG_COMMAND_READ_MEMORY_8:
MemoryRead = (DEBUG_DATA_READ_MEMORY_8 *) (DebugHeader + 1);
Status = SendDataResponsePacket (CpuContext, (UINT8 *) (UINTN) MemoryRead->Address, (UINT16) (MemoryRead->Count * Data8));
break;
case DEBUG_COMMAND_WRITE_MEMORY_64:
Data8 *= 2;
case DEBUG_COMMAND_WRITE_MEMORY_32:
Data8 *= 2;
case DEBUG_COMMAND_WRITE_MEMORY_16:
Data8 *= 2;
case DEBUG_COMMAND_WRITE_MEMORY_8:
MemoryWrite = (DEBUG_DATA_WRITE_MEMORY_8 *) (DebugHeader + 1);
CopyMem ((VOID *) (UINTN) MemoryWrite->Address, &MemoryWrite->Data, MemoryWrite->Count * Data8);
SendAckPacket (DEBUG_COMMAND_OK);
break;
case DEBUG_COMMAND_READ_IO:
IoRead = (DEBUG_DATA_READ_IO *) (DebugHeader + 1);
switch (IoRead->Width) {
case 1:
Data64 = IoRead8 (IoRead->Port);
break;
case 2:
Data64 = IoRead16 (IoRead->Port);
break;
case 4:
Data64 = IoRead32 (IoRead->Port);
break;
case 8:
Data64 = IoRead64 (IoRead->Port);
break;
default:
Data64 = (UINT64) -1;
}
Status = SendDataResponsePacket (CpuContext, (UINT8 *) &Data64, IoRead->Width);
break;
case DEBUG_COMMAND_WRITE_IO:
IoWrite = (DEBUG_DATA_WRITE_IO *) (DebugHeader + 1);
switch (IoWrite->Width) {
case 1:
Data64 = IoWrite8 (IoWrite->Port, *(UINT8 *) &IoWrite->Data);
break;
case 2:
Data64 = IoWrite16 (IoWrite->Port, *(UINT16 *) &IoWrite->Data);
break;
case 4:
Data64 = IoWrite32 (IoWrite->Port, *(UINT32 *) &IoWrite->Data);
break;
case 8:
Data64 = IoWrite64 (IoWrite->Port, *(UINT64 *) &IoWrite->Data);
break;
default:
Data64 = (UINT64) -1;
}
SendAckPacket (DEBUG_COMMAND_OK);
break;
case DEBUG_COMMAND_READ_REGISTER:
RegisterRead = (DEBUG_DATA_READ_REGISTER *) (DebugHeader + 1);
if (RegisterRead->Index < SOFT_DEBUGGER_REGISTER_OTHERS_BASE) {
Data8 = RegisterRead->Length;
RegisterBuffer = ArchReadRegisterBuffer (CpuContext, RegisterRead->Index, RegisterRead->Offset, &Data8);
Status = SendDataResponsePacket (CpuContext, RegisterBuffer, Data8);
break;
}
if (RegisterRead->Index <= SOFT_DEBUGGER_REGISTER_TSS_LIM) {
ReadRegisterGroupSegLim (CpuContext, &RegisterGroupSegLim);
DataN = * ((UINTN *) &RegisterGroupSegLim + (RegisterRead->Index - SOFT_DEBUGGER_REGISTER_CS_LIM));
Status = SendDataResponsePacket (CpuContext, (UINT8 *) &DataN, (UINT16) sizeof (UINTN));
} else if (RegisterRead->Index <= SOFT_DEBUGGER_REGISTER_TSS_BAS) {
ReadRegisterGroupSegBase (CpuContext, &RegisterGroupSegBase);
DataN = * ((UINTN *) &RegisterGroupSegBase + (RegisterRead->Index - SOFT_DEBUGGER_REGISTER_CS_BAS));
Status = SendDataResponsePacket (CpuContext, (UINT8 *) &DataN, (UINT16) sizeof (UINTN));
} else if (RegisterRead->Index < SOFT_DEBUGGER_REGISTER_IDT_LIM) {
Data64 = ReadRegisterSelectorByIndex (CpuContext, RegisterRead->Index);
Status = SendDataResponsePacket (CpuContext, (UINT8 *) &Data64, (UINT16) sizeof (UINT64));
} else {
switch (RegisterRead->Index) {
case SOFT_DEBUGGER_REGISTER_IDT_LIM:
DataN = (UINTN) (CpuContext->Idtr[0] & 0xffff);
SendDataResponsePacket (CpuContext, (UINT8 *) &DataN, (UINT16) sizeof (UINTN));
break;
case SOFT_DEBUGGER_REGISTER_GDT_LIM:
DataN = (UINTN) (CpuContext->Gdtr[0] & 0xffff);
SendDataResponsePacket (CpuContext, (UINT8 *) &DataN, (UINT16) sizeof (UINTN));
break;
case SOFT_DEBUGGER_REGISTER_IDT_BAS:
DataN = (UINTN) RShiftU64 (CpuContext->Idtr[0], 16);
DataN |= (UINTN) LShiftU64 (CpuContext->Idtr[1], (UINT16) (sizeof (UINTN) * 8 - 16));
SendDataResponsePacket (CpuContext, (UINT8 *) &DataN, (UINT16) sizeof (UINTN));
break;
case SOFT_DEBUGGER_REGISTER_GDT_BAS:
DataN = (UINTN) RShiftU64 (CpuContext->Gdtr[0], 16);
DataN |= (UINTN) LShiftU64 (CpuContext->Gdtr[1], (UINT16) (sizeof (UINTN) * 8 - 16));
SendDataResponsePacket (CpuContext, (UINT8 *) &DataN, (UINT16) sizeof (UINTN));
break;
}
}
break;
case DEBUG_COMMAND_WRITE_REGISTER:
RegisterWrite = (DEBUG_DATA_WRITE_REGISTER *) (DebugHeader + 1);
ArchWriteRegisterBuffer (CpuContext, RegisterWrite->Index, RegisterWrite->Offset, RegisterWrite->Length, (UINT8 *)&RegisterWrite->Value);
SendAckPacket (DEBUG_COMMAND_OK);
break;
case DEBUG_COMMAND_ARCH_MODE:
Data8 = DEBUG_ARCH_SYMBOL;
Status = SendDataResponsePacket (CpuContext, (UINT8 *) &Data8, (UINT16) sizeof (UINT8));
break;
case DEBUG_COMMAND_READ_MSR:
MsrRegisterRead = (DEBUG_DATA_READ_MSR *) (DebugHeader + 1);
Data64 = AsmReadMsr64 (MsrRegisterRead->Index);
Status = SendDataResponsePacket (CpuContext, (UINT8 *) &Data64, (UINT16) sizeof (UINT64));
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_READ_REGISTER_GROUP:
Data8 = *(UINT8 *) (DebugHeader + 1);
Status = ArchReadRegisterGroup (CpuContext, Data8);
break;
case DEBUG_COMMAND_SET_DEBUG_FLAG:
Data32 = *(UINT32 *) (DebugHeader + 1);
SetDebugFlag (Data32);
SendAckPacket (DEBUG_COMMAND_OK);
break;
case DEBUG_COMMAND_GET_REVISION:
DebugAgentRevision.Revision = DEBUG_AGENT_REVISION;
DebugAgentRevision.Capabilities = DEBUG_AGENT_CAPABILITIES;
Status = SendDataResponsePacket (CpuContext, (UINT8 *) &DebugAgentRevision, (UINT16) sizeof (DEBUG_DATA_RESPONSE_GET_REVISION));
break;
case DEBUG_COMMAND_GET_EXCEPTION:
Exception.ExceptionNum = (UINT8) Vector;
Exception.ExceptionData = 0;
Status = SendDataResponsePacket (CpuContext, (UINT8 *) &Exception, (UINT16) sizeof (DEBUG_DATA_RESPONSE_GET_EXCEPTION));
break;
case DEBUG_COMMAND_SET_VIEWPOINT:
Data32 = *(UINT32 *) (DebugHeader + 1);
if (MultiProcessorDebugSupport) {
if (IsCpuStopped (Data32)) {
SetDebugViewPoint (Data32);
SendAckPacket (DEBUG_COMMAND_OK);
} else {
//
// If CPU is not halted
//
SendAckPacket (DEBUG_COMMAND_NOT_SUPPORTED);
}
} else if (Data32 == 0) {
SendAckPacket (DEBUG_COMMAND_OK);
} else {
SendAckPacket (DEBUG_COMMAND_NOT_SUPPORTED);
}
break;
case DEBUG_COMMAND_GET_VIEWPOINT:
Data32 = mDebugMpContext.ViewPointIndex;
SendDataResponsePacket(CpuContext, (UINT8 *) &Data32, (UINT16) sizeof (UINT32));
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);
}
ReleaseDebugPortControl ();
CpuPause ();
}
}
/**
C function called in interrupt handler.
@param[in] Vector Vector value of exception or interrutp.
@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;
Handle = GetDebugPortHandle();
ProcessorIndex = 0;
BreakReceived = FALSE;
if (MultiProcessorDebugSupport) {
ProcessorIndex = GetProcessorIndex ();
while (mDebugMpContext.RunCommandSet);
}
switch (Vector) {
case DEBUG_INT1_VECTOR:
case DEBUG_INT3_VECTOR:
BreakCause = GetBreakCause (Vector, CpuContext);
if (BreakCause == DEBUG_DATA_BREAK_CAUSE_SYSTEM_RESET) {
//
// Init break, if no ack received after 200ms, return
//
SendAckPacket (DEBUG_COMMAND_INIT_BREAK);
if (WaitForAckPacketOK (200 * 1000, &BreakReceived) != RETURN_SUCCESS) {
break;
}
SetHostConnectedFlag ();
CommandCommunication (Vector, CpuContext, BreakReceived);
} else if (BreakCause == DEBUG_DATA_BREAK_CAUSE_STEPPING) {
//
// Stepping is finished, send Ack package.
//
if (MultiProcessorDebugSupport) {
mDebugMpContext.BreakAtCpuIndex = ProcessorIndex;
}
SendAckPacket (DEBUG_COMMAND_OK);
CommandCommunication (Vector, CpuContext, BreakReceived);
} else if (BreakCause == DEBUG_DATA_BREAK_CAUSE_MEMORY_READY) {
//
// Memory is ready
//
SendAckPacket (DEBUG_COMMAND_MEMORY_READY);
WaitForAckPacketOK (0, &BreakReceived);
CommandCommunication (Vector, CpuContext, BreakReceived);
} else {
if (BreakCause == DEBUG_DATA_BREAK_CAUSE_IMAGE_LOAD || BreakCause == DEBUG_DATA_BREAK_CAUSE_IMAGE_UNLOAD) {
//
// Set AL to DEBUG_AGENT_IMAGE_CONTINUE
//
Data8 = DEBUG_AGENT_IMAGE_CONTINUE;
ArchWriteRegisterBuffer (CpuContext, SOFT_DEBUGGER_REGISTER_AX, 0, 1, &Data8);
if (!IsHostConnected ()) {
//
// If HOST is not connected, return
//
break;
}
}
AcquireDebugPortControl ();
if (MultiProcessorDebugSupport) {
if(!IsAllCpuRunning ()) {
//
// If other processors have been stopped
//
SetCpuBreakFlagByIndex (ProcessorIndex, TRUE);
} else {
//
// If no any processor was stopped, try to halt other processors
//
HaltOtherProcessors (ProcessorIndex);
SendAckPacket (DEBUG_COMMAND_BREAK_POINT);
WaitForAckPacketOK (0, &BreakReceived);
}
} else {
SendAckPacket (DEBUG_COMMAND_BREAK_POINT);
WaitForAckPacketOK (0, &BreakReceived);
}
ReleaseDebugPortControl ();
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;
case DEBUG_TIMER_VECTOR:
if (MultiProcessorDebugSupport) {
if (IsBsp (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 ();
}
}
if (!IsBsp (ProcessorIndex) || mDebugMpContext.IpiSentByAp) {
//
// 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
//
AcquireDebugPortControl ();
while (DebugPortPollBuffer (Handle)) {
//
// If there is data in debug port, will check whether it is break-in symbol,
// If yes, go into communication mode with HOST.
// If no, exit interrupt process.
//
DebugPortReadBuffer (Handle, &InputCharacter, 1, 0);
if (InputCharacter == DEBUG_STARTING_SYMBOL_BREAK) {
SendAckPacket (DEBUG_COMMAND_OK);
if (MultiProcessorDebugSupport) {
if(FindCpuNotRunning () != -1) {
SetCpuBreakFlagByIndex (ProcessorIndex, TRUE);
} else {
HaltOtherProcessors (ProcessorIndex);
}
}
ReleaseDebugPortControl ();
CommandCommunication (Vector, CpuContext, BreakReceived);
AcquireDebugPortControl ();
break;
}
}
//
// Clear EOI before exiting interrupt process routine.
//
SendApicEoi ();
ReleaseDebugPortControl ();
break;
default:
if (Vector <= DEBUG_EXCEPT_SIMD) {
AcquireDebugPortControl ();
if (MultiProcessorDebugSupport) {
if(FindCpuNotRunning () != -1) {
SetCpuBreakFlagByIndex (ProcessorIndex, TRUE);
} else {
HaltOtherProcessors (ProcessorIndex);
}
}
SendAckPacket (DEBUG_COMMAND_BREAK_POINT);
WaitForAckPacketOK (0, &BreakReceived);
ReleaseDebugPortControl ();
CommandCommunication (Vector, CpuContext, BreakReceived);
}
break;
}
if (MultiProcessorDebugSupport) {
//
// Clear flag and wait for all processors run here
//
SetIpiSentByApFlag (FALSE);
while (mDebugMpContext.RunCommandSet);
}
return;
}