/** @file
Commond Debug Agent library implementition. It mainly includes
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
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.
**/
)
{
Mailbox = GetMailboxPointer ();
return TRUE;
} else {
return FALSE;
}
}
/**
Set HOST connect flag in Mailbox.
**/
)
{
Mailbox = GetMailboxPointer ();
}
/**
Set debug flag of Debug Agent in Mailbox.
@param DebugFlag Debug Flag defined by transfer protocol.
**/
)
{
Mailbox = GetMailboxPointer ();
if ((DebugFlag & SOFT_DEBUGGER_SETTING_SMM_ENTRY_BREAK) != 0) {
} else {
}
}
/**
Exectue GO command.
@param[in] CpuContext Pointer to saved CPU context.
**/
)
{
}
/**
Exectue Stepping command.
@param[in] CpuContext Pointer to saved CPU context.
**/
)
{
}
/**
Set debug register for hardware breakpoint.
@param[in] CpuContext Pointer to saved CPU context.
@param[in] SetHwBreakpoint Hardware breakpoint to be set.
**/
)
{
//
// Set debug address
//
//
// Enable Gx, Lx
//
//
// Set RWx and Lenx
//
//
// Enable GE, LE
//
Dr7Value |= 0x300;
}
/**
Clear debug register for hardware breakpoint.
@param[in] CpuContext Pointer to saved CPU context.
@param[in] ClearHwBreakpoint Hardware breakpoint to be cleared.
**/
)
{
CpuContext->Dr0 = 0;
}
CpuContext->Dr1 = 0;
}
CpuContext->Dr2 = 0;
}
CpuContext->Dr3 = 0;
}
}
/**
Send acknowledge packet to HOST.
@param[in] AckCommand Type of Acknowledge packet.
**/
)
{
Handle = GetDebugPortHandle();
}
/**
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.
**/
)
{
Handle = GetDebugPortHandle();
while (TRUE) {
return RETURN_TIMEOUT;
}
if (BreakReceived != NULL) {
*BreakReceived = TRUE;
}
}
break;
}
}
if (DebugPortReadBuffer (Handle, (UINT8 *)&DebugCommonHeader.Command, sizeof (DEBUG_COMMAND_HEADER) - 1, Timeout) == 0) {
return RETURN_TIMEOUT;
}
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.
**/
)
{
while (TRUE) {
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.
**/
)
{
Handle = GetDebugPortHandle();
//
// Find the valid start symbol
//
if (*InputPacket == DEBUG_STARTING_SYMBOL_BREAK) {
*BreakReceived = TRUE;
}
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;
}
//
// Read the payload if has
//
if (DebugHeader->DataLength > 0 && DebugHeader->DataLength < (DEBUG_DATA_MAXIMUM_REAL_DATA - sizeof(DEBUG_COMMAND_HEADER))) {
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
**/
)
{
switch (Vector) {
case DEBUG_INT1_VECTOR:
case DEBUG_INT3_VECTOR:
if (Vector == DEBUG_INT1_VECTOR) {
//
// INT 1
//
//
// If it's single step, no need to check DR0, to ensure single step work in PeCoffExtraActionLib
//
return Cause;
} else {
}
} else {
//
// INT 3
//
}
switch (CpuContext->Dr0) {
case IMAGE_LOAD_SIGNATURE:
case IMAGE_UNLOAD_SIGNATURE:
}
break;
case SOFT_INTERRUPT_SIGNATURE:
CpuContext->Dr0 = 0;
CpuContext->Dr0 = 0;
}
break;
default:
break;
}
break;
case DEBUG_TIMER_VECTOR:
break;
default:
if (Vector < 20) {
}
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.
**/
)
{
Handle = GetDebugPortHandle();
while (TRUE) {
if (DataSize <= DEBUG_DATA_MAXIMUM_REAL_DATA) {
LastPacket = TRUE;
} else {
LastPacket = FALSE;
}
switch (Ack) {
case DEBUG_COMMAND_RESEND:
//
// Send the packet again
//
break;
case DEBUG_COMMAND_CONTINUE:
//
// Send the rest packet
//
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 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.
**/
)
{
Handle = GetDebugPortHandle();
ProcessorIndex = 0;
if (MultiProcessorDebugSupport) {
}
while (TRUE) {
if (MultiProcessorDebugSupport) {
if (mDebugMpContext.RunCommandSet) {
break;
} else {
continue;
}
}
}
if (BreakReceived) {
HaltDeferred = TRUE;
}
if (Status != RETURN_SUCCESS) {
continue;
}
Data8 = 1;
switch (DebugHeader->Command) {
case DEBUG_COMMAND_RESET:
ResetCold ();
//
// Wait for reset
//
CpuDeadLoop ();
break;
case DEBUG_COMMAND_GO:
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
//
CpuPause ();
//
// Set current view to the next breaking processor
//
//
// Send break packet to HOST and exit to wait for command packet from HOST.
//
WaitForAckPacketOK (0, &BreakReceived);
break;
}
//
// If no else processor break, set stop bitmask,
// and set Running flag for all processors.
//
CpuPause ();
//
// Wait for all processors are in running state
//
while (TRUE) {
if (IsAllCpuRunning ()) {
break;
}
}
//
// Set BSP to be current view point.
//
CpuPause ();
//
// Clear breaking processor index and running flag
//
}
//
// Send OK packet to HOST to finish this go command
//
return;
} else {
//
// If reveived HALT command, need to defer the GO command
//
CpuContext->Dr0 = 0;
CpuContext->Dr3 = 0;
}
}
break;
} else {
}
break;
break;
break;
//
// Executing stepping command directly without sending ACK packet.
//
return;
break;
Data8 *= 2;
Data8 *= 2;
Data8 *= 2;
Status = SendDataResponsePacket (CpuContext, (UINT8 *) (UINTN) MemoryRead->Address, (UINT16) (MemoryRead->Count * Data8));
break;
Data8 *= 2;
Data8 *= 2;
Data8 *= 2;
break;
case DEBUG_COMMAND_READ_IO:
case 1:
break;
case 2:
break;
case 4:
break;
case 8:
break;
default:
}
break;
case DEBUG_COMMAND_WRITE_IO:
case 1:
break;
case 2:
break;
case 4:
break;
case 8:
break;
default:
}
break;
RegisterBuffer = ArchReadRegisterBuffer (CpuContext, RegisterRead->Index, RegisterRead->Offset, &Data8);
break;
}
DataN = * ((UINTN *) &RegisterGroupSegBase + (RegisterRead->Index - SOFT_DEBUGGER_REGISTER_CS_BAS));
} else {
switch (RegisterRead->Index) {
break;
break;
break;
break;
}
}
break;
ArchWriteRegisterBuffer (CpuContext, RegisterWrite->Index, RegisterWrite->Offset, RegisterWrite->Length, (UINT8 *)&RegisterWrite->Value);
break;
case DEBUG_COMMAND_ARCH_MODE:
break;
case DEBUG_COMMAND_READ_MSR:
break;
case DEBUG_COMMAND_WRITE_MSR:
break;
break;
break;
Status = SendDataResponsePacket (CpuContext, (UINT8 *) &DebugAgentRevision, (UINT16) sizeof (DEBUG_DATA_RESPONSE_GET_REVISION));
break;
Exception.ExceptionData = 0;
Status = SendDataResponsePacket (CpuContext, (UINT8 *) &Exception, (UINT16) sizeof (DEBUG_DATA_RESPONSE_GET_EXCEPTION));
break;
if (MultiProcessorDebugSupport) {
if (IsCpuStopped (Data32)) {
} else {
//
// If CPU is not halted
//
}
} else if (Data32 == 0) {
} else {
}
break;
break;
default:
break;
}
if (Status == RETURN_UNSUPPORTED) {
} else if (Status != RETURN_SUCCESS) {
}
CpuPause ();
}
}
/**
C function called in interrupt handler.
@param[in] Vector Vector value of exception or interrutp.
@param[in] CpuContext Pointer to save CPU context.
**/
)
{
Handle = GetDebugPortHandle();
ProcessorIndex = 0;
if (MultiProcessorDebugSupport) {
while (mDebugMpContext.RunCommandSet);
}
switch (Vector) {
case DEBUG_INT1_VECTOR:
case DEBUG_INT3_VECTOR:
//
// Init break, if no ack received after 200ms, return
//
break;
}
} else if (BreakCause == DEBUG_DATA_BREAK_CAUSE_STEPPING) {
//
// Stepping is finished, send Ack package.
//
if (MultiProcessorDebugSupport) {
}
} else if (BreakCause == DEBUG_DATA_BREAK_CAUSE_MEMORY_READY) {
//
// Memory is ready
//
WaitForAckPacketOK (0, &BreakReceived);
} else {
if (BreakCause == DEBUG_DATA_BREAK_CAUSE_IMAGE_LOAD || BreakCause == DEBUG_DATA_BREAK_CAUSE_IMAGE_UNLOAD) {
//
// Set AL to DEBUG_AGENT_IMAGE_CONTINUE
//
if (!IsHostConnected ()) {
//
// If HOST is not connected, return
//
break;
}
}
if (MultiProcessorDebugSupport) {
if(!IsAllCpuRunning ()) {
//
// If other processors have been stopped
//
} else {
//
// If no any processor was stopped, try to halt other processors
//
WaitForAckPacketOK (0, &BreakReceived);
}
} else {
WaitForAckPacketOK (0, &BreakReceived);
}
if (Vector == DEBUG_INT3_VECTOR) {
//
// go back address located "0xCC"
//
CpuContext->Eip--;
//
// If this is not a software breakpoint set by HOST,
// restore EIP
//
CpuContext->Eip++;
}
} else {
}
}
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
//
}
}
//
// If current processor is not BSP or this is one IPI sent by AP
//
}
//
// Clear EOI before exiting interrupt process routine.
//
SendApicEoi ();
break;
}
}
//
// Only BSP could run here
//
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.
//
if (InputCharacter == DEBUG_STARTING_SYMBOL_BREAK) {
if (MultiProcessorDebugSupport) {
if(FindCpuNotRunning () != -1) {
} else {
}
}
break;
}
}
//
// Clear EOI before exiting interrupt process routine.
//
SendApicEoi ();
break;
default:
if (Vector <= DEBUG_EXCEPT_SIMD) {
if (MultiProcessorDebugSupport) {
if(FindCpuNotRunning () != -1) {
} else {
}
}
WaitForAckPacketOK (0, &BreakReceived);
}
break;
}
if (MultiProcessorDebugSupport) {
//
// Clear flag and wait for all processors run here
//
while (mDebugMpContext.RunCommandSet);
}
return;
}