1034 lines
26 KiB
C++
1034 lines
26 KiB
C++
///////////////////////////////////////////////////////////////////////////////
|
||
//
|
||
// Microsoft Research Singularity
|
||
//
|
||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||
//
|
||
// debug.cpp: runtime support for debugging
|
||
//
|
||
|
||
#ifndef IN
|
||
#define IN
|
||
#endif
|
||
#ifndef OUT
|
||
#define OUT
|
||
#endif
|
||
|
||
// Define the maximum number of retries for packet sends.
|
||
//
|
||
#define BD_MAXIMUM_RETRIES 20
|
||
|
||
// Define packet waiting status codes.
|
||
//
|
||
#define BD_PACKET_RECEIVED 0
|
||
#define BD_PACKET_TIMEOUT 1
|
||
#define BD_PACKET_RESEND 2
|
||
|
||
typedef struct _STRING {
|
||
UINT16 Length;
|
||
UINT16 MaximumLength;
|
||
PUINT8 Buffer;
|
||
} STRING, *PSTRING;
|
||
|
||
//======================================================================
|
||
// Selected structs and defines used by the KD protocol
|
||
//
|
||
|
||
//
|
||
// If the packet type is PACKET_TYPE_KD_DEBUG_IO, then
|
||
// the format of the packet data is as follows:
|
||
//
|
||
|
||
#define DbgKdPrintStringApi 0x00003230L
|
||
|
||
//
|
||
// For get string, the Null terminated prompt string
|
||
// immediately follows the message. The LengthOfStringRead
|
||
// field initially contains the maximum number of characters
|
||
// to read. Upon reply, this contains the number of bytes actually
|
||
// read. The data read immediately follows the message.
|
||
//
|
||
//
|
||
typedef struct _DBGKD_DEBUG_IO {
|
||
UINT32 ApiNumber;
|
||
UINT16 ProcessorLevel;
|
||
UINT16 Processor;
|
||
UINT32 LengthOfString;
|
||
UINT32 LengthOfStringRead;
|
||
} DBGKD_DEBUG_IO, *PDBGKD_DEBUG_IO;
|
||
|
||
//
|
||
// DbgKd APIs are for the portable kernel debugger
|
||
//
|
||
|
||
//
|
||
// KD_PACKETS are the low level data format used in KD. All packets
|
||
// begin with a packet leader, byte count, packet type. The sequence
|
||
// for accepting a packet is:
|
||
//
|
||
// - read 4 bytes to get packet leader. If read times out (10 seconds)
|
||
// with a short read, or if packet leader is incorrect, then retry
|
||
// the read.
|
||
//
|
||
// - next read 2 byte packet type. If read times out (10 seconds) with
|
||
// a short read, or if packet type is bad, then start again looking
|
||
// for a packet leader.
|
||
//
|
||
// - next read 4 byte packet Id. If read times out (10 seconds)
|
||
// with a short read, or if packet Id is not what we expect, then
|
||
// ask for resend and restart again looking for a packet leader.
|
||
//
|
||
// - next read 2 byte count. If read times out (10 seconds) with
|
||
// a short read, or if byte count is greater than PACKET_MAX_SIZE,
|
||
// then start again looking for a packet leader.
|
||
//
|
||
// - next read 4 byte packet data checksum.
|
||
//
|
||
// - The packet data immediately follows the packet. There should be
|
||
// ByteCount bytes following the packet header. Read the packet
|
||
// data, if read times out (10 seconds) then start again looking for
|
||
// a packet leader.
|
||
//
|
||
|
||
typedef struct _KD_PACKET {
|
||
UINT32 PacketLeader;
|
||
UINT16 PacketType;
|
||
UINT16 ByteCount;
|
||
UINT32 PacketId;
|
||
UINT32 Checksum;
|
||
} KD_PACKET, *PKD_PACKET;
|
||
|
||
#define PACKET_MAX_SIZE 4000
|
||
#define INITIAL_PACKET_ID 0x80800000 // Don't use 0
|
||
#define SYNC_PACKET_ID 0x00000800 // Or in with INITIAL_PACKET_ID
|
||
// to force a packet ID reset.
|
||
|
||
//
|
||
// Packet lead in sequence
|
||
//
|
||
|
||
#define PACKET_LEADER 0x30303030 //0x77000077
|
||
#define PACKET_LEADER_BYTE 0x30
|
||
|
||
#define CONTROL_PACKET_LEADER 0x69696969
|
||
#define CONTROL_PACKET_LEADER_BYTE 0x69
|
||
|
||
//
|
||
// Packet Trailing Byte
|
||
//
|
||
|
||
#define PACKET_TRAILING_BYTE 0xAA
|
||
|
||
//
|
||
// Packet Types
|
||
//
|
||
|
||
#define PACKET_TYPE_KD_DEBUG_IO 3
|
||
#define PACKET_TYPE_KD_ACKNOWLEDGE 4 // Packet-control type
|
||
#define PACKET_TYPE_KD_RESEND 5 // Packet-control type
|
||
#define PACKET_TYPE_KD_RESET 6 // Packet-control type
|
||
#define PACKET_TYPE_MAX 12
|
||
|
||
//
|
||
// Status Constants for reading data from comport
|
||
//
|
||
|
||
#define DBGKD_64BIT_PROTOCOL_VERSION2 6
|
||
|
||
//
|
||
// Communication functions (comio.c)
|
||
//
|
||
|
||
static
|
||
UINT32
|
||
BdComputeChecksum(
|
||
IN PUINT8 Buffer,
|
||
IN UINT32 Length
|
||
);
|
||
|
||
static
|
||
UINT16
|
||
BdReceivePacketLeader(
|
||
IN UINT32 PacketType,
|
||
OUT PUINT32 PacketLeader
|
||
);
|
||
|
||
static
|
||
void
|
||
BdSendControlPacket(
|
||
IN UINT16 PacketType,
|
||
IN UINT32 PacketId
|
||
);
|
||
|
||
static
|
||
UINT32
|
||
BdReceivePacket(
|
||
IN UINT32 ExpectedPacketType,
|
||
OUT PSTRING MessageHeader,
|
||
OUT PSTRING MessageData,
|
||
OUT PUINT32 DataLength
|
||
);
|
||
|
||
static
|
||
void
|
||
BdSendPacket(
|
||
IN UINT32 PacketType,
|
||
IN PSTRING MessageHeader,
|
||
IN PSTRING MessageData
|
||
);
|
||
|
||
static
|
||
UINT32
|
||
BdReceiveString(
|
||
OUT PUINT8 Destination,
|
||
IN UINT32 Length
|
||
);
|
||
|
||
static
|
||
void
|
||
BdSendString(
|
||
IN PUINT8 Source,
|
||
IN UINT32 Length
|
||
);
|
||
|
||
static
|
||
void
|
||
BdSendControlPacket(
|
||
IN UINT16 PacketType,
|
||
IN UINT32 PacketId
|
||
);
|
||
|
||
// Debugger enabled and present.
|
||
//
|
||
static BOOL BdDebuggerNotPresent = 0;
|
||
|
||
// Next packet id to send and next packet id to expect.
|
||
//
|
||
static UINT32 BdPacketIdExpected;
|
||
static UINT32 BdNextPacketIdToSend;
|
||
|
||
// Number of retries and the retry count.
|
||
//
|
||
static UINT32 BdNumberRetries = BD_MAXIMUM_RETRIES;
|
||
static UINT32 BdRetryCount = BD_MAXIMUM_RETRIES;
|
||
|
||
//////////////////////////////////////////////////////////////////////////////
|
||
|
||
static
|
||
UINT32
|
||
BdComputeChecksum(
|
||
IN PUINT8 Buffer,
|
||
IN UINT32 Length
|
||
)
|
||
|
||
//++
|
||
//
|
||
//Routine Description:
|
||
//
|
||
// This routine computes the checksum of the specified buffer.
|
||
//
|
||
//Arguments:
|
||
//
|
||
// Buffer - Supplies a pointer to the buffer.
|
||
//
|
||
// Length - Supplies the length of the buffer.
|
||
//
|
||
//Return Value:
|
||
//
|
||
// A UINT32 is return as the checksum for the input string.
|
||
//
|
||
//--
|
||
|
||
{
|
||
|
||
UINT32 Checksum = 0;
|
||
|
||
while (Length > 0) {
|
||
Checksum = Checksum + (UINT32)*Buffer++;
|
||
Length--;
|
||
}
|
||
|
||
return Checksum;
|
||
}
|
||
|
||
static
|
||
UINT16
|
||
BdReceivePacketLeader(
|
||
IN UINT32 /* PacketType */,
|
||
OUT PUINT32 PacketLeader
|
||
)
|
||
|
||
//++
|
||
//
|
||
//Routine Description:
|
||
//
|
||
// This routine waits for a packet header leader.
|
||
//
|
||
//Arguments:
|
||
//
|
||
// PacketType - supplies the type of packet we are expecting.
|
||
//
|
||
// PacketLeader - supplies a pointer to a ulong variable to receive
|
||
// packet leader bytes.
|
||
//
|
||
//Return Value:
|
||
//
|
||
// BD_PACKET_RESEND - if resend is required.
|
||
// BD_PAKCET_TIMEOUT - if timeout.
|
||
// BD_PACKET_RECEIVED - if packet received.
|
||
//
|
||
//--
|
||
|
||
{
|
||
|
||
UINT8 Input, PreviousByte = 0;
|
||
UINT32 PacketId = 0;
|
||
UINT32 Index;
|
||
UINT32 ReturnCode;
|
||
|
||
// NOTE - With all the interrupts being off, it is very hard
|
||
// to implement the actual timeout code. (Maybe, by reading the CMOS.)
|
||
// Here we use a loop count to wait about 3 seconds. The CpGetByte
|
||
// will return with error code = CP_GET_NODATA if it cannot find data
|
||
// byte within 1 second. Kernel debugger's timeout period is 5 seconds.
|
||
//
|
||
Index = 0;
|
||
do {
|
||
ReturnCode = BdPortGetByte(&Input);
|
||
if (ReturnCode == CP_GET_NODATA) {
|
||
return BD_PACKET_TIMEOUT;
|
||
} else if (ReturnCode == CP_GET_ERROR) {
|
||
Index = 0;
|
||
continue;
|
||
|
||
} else { // if (ReturnCode == CP_GET_SUCCESS)
|
||
if ( Input == PACKET_LEADER_BYTE ||
|
||
Input == CONTROL_PACKET_LEADER_BYTE ) {
|
||
if ( Index == 0 ) {
|
||
PreviousByte = Input;
|
||
Index++;
|
||
} else if (Input == PreviousByte ) {
|
||
Index++;
|
||
} else {
|
||
PreviousByte = Input;
|
||
Index = 1;
|
||
}
|
||
} else {
|
||
|
||
Index = 0;
|
||
}
|
||
}
|
||
} while ( Index < 4 );
|
||
|
||
// return the packet leader and FALSE to indicate no resend is needed.
|
||
//
|
||
if ( Input == PACKET_LEADER_BYTE ) {
|
||
*PacketLeader = PACKET_LEADER;
|
||
|
||
} else {
|
||
*PacketLeader = CONTROL_PACKET_LEADER;
|
||
}
|
||
|
||
BdDebuggerNotPresent = 0;
|
||
return BD_PACKET_RECEIVED;
|
||
}
|
||
|
||
static
|
||
void
|
||
BdSendControlPacket(
|
||
IN UINT16 PacketType,
|
||
IN UINT32 PacketId
|
||
)
|
||
|
||
//++
|
||
//
|
||
//Routine Description:
|
||
//
|
||
// This routine sends a control packet to the host machine that is running the
|
||
// kernel debugger and waits for an ACK.
|
||
//
|
||
//Arguments:
|
||
//
|
||
// PacketType - Supplies the type of packet to send.
|
||
//
|
||
// PacketId - Supplies packet id, optionally.
|
||
//
|
||
//Return Value:
|
||
//
|
||
// None.
|
||
//
|
||
//--
|
||
|
||
{
|
||
|
||
KD_PACKET PacketHeader;
|
||
|
||
// Initialize and send the packet header.
|
||
//
|
||
PacketHeader.PacketLeader = CONTROL_PACKET_LEADER;
|
||
if (PacketId != 0) {
|
||
PacketHeader.PacketId = PacketId;
|
||
}
|
||
|
||
PacketHeader.ByteCount = 0;
|
||
PacketHeader.Checksum = 0;
|
||
PacketHeader.PacketType = PacketType;
|
||
BdSendString((PUINT8)&PacketHeader, sizeof(KD_PACKET));
|
||
return;
|
||
}
|
||
|
||
static
|
||
UINT32
|
||
BdReceivePacket(
|
||
IN UINT32 PacketType,
|
||
OUT PSTRING MessageHeader,
|
||
OUT PSTRING MessageData,
|
||
OUT PUINT32 DataLength
|
||
)
|
||
|
||
//++
|
||
//
|
||
//Routine Description:
|
||
//
|
||
// This routine receives a packet from the host machine that is running
|
||
// the kernel debugger UI. This routine is ALWAYS called after packet being
|
||
// sent by caller. It first waits for ACK packet for the packet sent and
|
||
// then waits for the packet desired.
|
||
//
|
||
// N.B. If caller is BdrintString, the parameter PacketType is
|
||
// PACKET_TYPE_KD_ACKNOWLEDGE. In this case, this routine will return
|
||
// right after the ack packet is received.
|
||
//
|
||
//Arguments:
|
||
//
|
||
// PacketType - Supplies the type of packet that is excepted.
|
||
//
|
||
// MessageHeader - Supplies a pointer to a string descriptor for the input
|
||
// message.
|
||
//
|
||
// MessageData - Supplies a pointer to a string descriptor for the input data.
|
||
//
|
||
// DataLength - Supplies pointer to UINT32 to receive length of recv. data.
|
||
//
|
||
//Return Value:
|
||
//
|
||
// BD_PACKET_RESEND - if resend is required.
|
||
// BD_PAKCET_TIMEOUT - if timeout.
|
||
// BD_PACKET_RECEIVED - if packet received.
|
||
//
|
||
//--
|
||
|
||
{
|
||
|
||
UINT8 Input;
|
||
UINT32 MessageLength;
|
||
KD_PACKET PacketHeader;
|
||
UINT32 ReturnCode;
|
||
UINT32 Checksum;
|
||
|
||
WaitForPacketLeader:
|
||
|
||
//
|
||
// Read Packet Leader
|
||
//
|
||
|
||
ReturnCode = BdReceivePacketLeader(PacketType, &PacketHeader.PacketLeader);
|
||
|
||
//
|
||
// If we can successfully read packet leader, it has high possibility that
|
||
// kernel debugger is alive. So reset count.
|
||
//
|
||
|
||
if (ReturnCode != BD_PACKET_TIMEOUT) {
|
||
BdNumberRetries = BdRetryCount;
|
||
}
|
||
if (ReturnCode != BD_PACKET_RECEIVED) {
|
||
return ReturnCode;
|
||
}
|
||
|
||
//
|
||
// Read packet type.
|
||
//
|
||
|
||
ReturnCode = BdReceiveString((PUINT8)&PacketHeader.PacketType,
|
||
sizeof(PacketHeader.PacketType));
|
||
|
||
if (ReturnCode == CP_GET_NODATA) {
|
||
return BD_PACKET_TIMEOUT;
|
||
|
||
} else if (ReturnCode == CP_GET_ERROR) {
|
||
if (PacketHeader.PacketLeader == CONTROL_PACKET_LEADER) {
|
||
|
||
//
|
||
// If read error and it is for a control packet, simply
|
||
// pretend that we have not seen this packet. Hopefully
|
||
// we will receive the packet we desire which automatically acks
|
||
// the packet we just sent.
|
||
//
|
||
|
||
goto WaitForPacketLeader;
|
||
|
||
} else {
|
||
|
||
//
|
||
// if read error while reading data packet, we have to ask
|
||
// kernel debugger to resend us the packet.
|
||
//
|
||
|
||
goto SendResendPacket;
|
||
}
|
||
}
|
||
|
||
//
|
||
// if the packet we received is a resend request, we return true and
|
||
// let caller resend the packet.
|
||
//
|
||
|
||
if ( PacketHeader.PacketLeader == CONTROL_PACKET_LEADER &&
|
||
PacketHeader.PacketType == PACKET_TYPE_KD_RESEND ) {
|
||
return BD_PACKET_RESEND;
|
||
}
|
||
|
||
//
|
||
// Read data length.
|
||
//
|
||
|
||
ReturnCode = BdReceiveString((PUINT8)&PacketHeader.ByteCount,
|
||
sizeof(PacketHeader.ByteCount));
|
||
|
||
if (ReturnCode == CP_GET_NODATA) {
|
||
return BD_PACKET_TIMEOUT;
|
||
} else if (ReturnCode == CP_GET_ERROR) {
|
||
if (PacketHeader.PacketLeader == CONTROL_PACKET_LEADER) {
|
||
goto WaitForPacketLeader;
|
||
} else {
|
||
goto SendResendPacket;
|
||
}
|
||
}
|
||
|
||
//
|
||
// Read Packet Id.
|
||
//
|
||
|
||
ReturnCode = BdReceiveString((PUINT8)&PacketHeader.PacketId,
|
||
sizeof(PacketHeader.PacketId));
|
||
|
||
if (ReturnCode == CP_GET_NODATA) {
|
||
return BD_PACKET_TIMEOUT;
|
||
} else if (ReturnCode == CP_GET_ERROR) {
|
||
if (PacketHeader.PacketLeader == CONTROL_PACKET_LEADER) {
|
||
goto WaitForPacketLeader;
|
||
} else {
|
||
goto SendResendPacket;
|
||
}
|
||
}
|
||
|
||
//
|
||
// Read packet checksum.
|
||
//
|
||
|
||
ReturnCode = BdReceiveString((PUINT8)&PacketHeader.Checksum,
|
||
sizeof(PacketHeader.Checksum));
|
||
|
||
if (ReturnCode == CP_GET_NODATA) {
|
||
return BD_PACKET_TIMEOUT;
|
||
|
||
} else if (ReturnCode == CP_GET_ERROR) {
|
||
if (PacketHeader.PacketLeader == CONTROL_PACKET_LEADER) {
|
||
goto WaitForPacketLeader;
|
||
} else {
|
||
goto SendResendPacket;
|
||
}
|
||
}
|
||
|
||
//
|
||
// A complete packet header is received. Check its validity and
|
||
// perform appropriate action depending on packet type.
|
||
//
|
||
|
||
if (PacketHeader.PacketLeader == CONTROL_PACKET_LEADER ) {
|
||
if (PacketHeader.PacketType == PACKET_TYPE_KD_ACKNOWLEDGE ) {
|
||
|
||
//
|
||
// If we received an expected ACK packet and we are not
|
||
// waiting for any new packet, update outgoing packet id
|
||
// and return. If we are NOT waiting for ACK packet
|
||
// we will keep on waiting. If the ACK packet
|
||
// is not for the packet we send, ignore it and keep on waiting.
|
||
//
|
||
|
||
if (PacketHeader.PacketId !=
|
||
(BdNextPacketIdToSend & ~SYNC_PACKET_ID)) {
|
||
goto WaitForPacketLeader;
|
||
|
||
} else if (PacketType == PACKET_TYPE_KD_ACKNOWLEDGE) {
|
||
BdNextPacketIdToSend ^= 1;
|
||
return BD_PACKET_RECEIVED;
|
||
|
||
} else {
|
||
goto WaitForPacketLeader;
|
||
}
|
||
|
||
} else if (PacketHeader.PacketType == PACKET_TYPE_KD_RESET) {
|
||
|
||
//
|
||
// if we received Reset packet, reset the packet control variables
|
||
// and resend earlier packet.
|
||
//
|
||
|
||
BdNextPacketIdToSend = INITIAL_PACKET_ID;
|
||
BdPacketIdExpected = INITIAL_PACKET_ID;
|
||
BdSendControlPacket(PACKET_TYPE_KD_RESET, 0L);
|
||
return BD_PACKET_RESEND;
|
||
|
||
} else if (PacketHeader.PacketType == PACKET_TYPE_KD_RESEND) {
|
||
return BD_PACKET_RESEND;
|
||
|
||
} else {
|
||
|
||
//
|
||
// Invalid packet header, ignore it.
|
||
//
|
||
|
||
goto WaitForPacketLeader;
|
||
}
|
||
|
||
//
|
||
// The packet header is for data packet (not control packet).
|
||
//
|
||
|
||
} else if (PacketType == PACKET_TYPE_KD_ACKNOWLEDGE) {
|
||
|
||
//
|
||
// if we are waiting for ACK packet ONLY
|
||
// and we receive a data packet header, check if the packet id
|
||
// is what we expected. If yes, assume the acknowledge is lost (but
|
||
// sent), ask sender to resend and return with PACKET_RECEIVED.
|
||
//
|
||
|
||
if (PacketHeader.PacketId == BdPacketIdExpected) {
|
||
BdSendControlPacket(PACKET_TYPE_KD_RESEND, 0L);
|
||
BdNextPacketIdToSend ^= 1;
|
||
return BD_PACKET_RECEIVED;
|
||
|
||
} else {
|
||
BdSendControlPacket(PACKET_TYPE_KD_ACKNOWLEDGE,
|
||
PacketHeader.PacketId);
|
||
|
||
goto WaitForPacketLeader;
|
||
}
|
||
}
|
||
|
||
//
|
||
// we are waiting for data packet and we received the packet header
|
||
// for data packet. Perform the following checks to make sure
|
||
// it is the packet we are waiting for.
|
||
//
|
||
// Check ByteCount received is valid
|
||
//
|
||
|
||
MessageLength = MessageHeader->MaximumLength;
|
||
if ((PacketHeader.ByteCount > (UINT16)PACKET_MAX_SIZE) ||
|
||
(PacketHeader.ByteCount < (UINT16)MessageLength)) {
|
||
goto SendResendPacket;
|
||
}
|
||
|
||
*DataLength = PacketHeader.ByteCount - MessageLength;
|
||
|
||
//
|
||
// Read the message header.
|
||
//
|
||
|
||
ReturnCode = BdReceiveString(MessageHeader->Buffer, MessageLength);
|
||
if (ReturnCode != CP_GET_SUCCESS) {
|
||
goto SendResendPacket;
|
||
}
|
||
|
||
MessageHeader->Length = (UINT16)MessageLength;
|
||
|
||
//
|
||
// Read the message data.
|
||
//
|
||
|
||
ReturnCode = BdReceiveString(MessageData->Buffer, *DataLength);
|
||
if (ReturnCode != CP_GET_SUCCESS) {
|
||
goto SendResendPacket;
|
||
}
|
||
|
||
MessageData->Length = (UINT16)*DataLength;
|
||
|
||
//
|
||
// Read packet trailing byte
|
||
//
|
||
|
||
ReturnCode = BdPortGetByte(&Input);
|
||
if (ReturnCode != CP_GET_SUCCESS || Input != PACKET_TRAILING_BYTE) {
|
||
goto SendResendPacket;
|
||
}
|
||
|
||
//
|
||
// Check PacketType is what we are waiting for.
|
||
//
|
||
|
||
if (PacketType != PacketHeader.PacketType) {
|
||
BdSendControlPacket(PACKET_TYPE_KD_ACKNOWLEDGE,
|
||
PacketHeader.PacketId
|
||
);
|
||
goto WaitForPacketLeader;
|
||
}
|
||
|
||
//
|
||
// Check PacketId is valid.
|
||
//
|
||
|
||
if (PacketHeader.PacketId == INITIAL_PACKET_ID ||
|
||
PacketHeader.PacketId == (INITIAL_PACKET_ID ^ 1)) {
|
||
if (PacketHeader.PacketId != BdPacketIdExpected) {
|
||
BdSendControlPacket(PACKET_TYPE_KD_ACKNOWLEDGE,
|
||
PacketHeader.PacketId
|
||
);
|
||
goto WaitForPacketLeader;
|
||
}
|
||
|
||
} else {
|
||
goto SendResendPacket;
|
||
}
|
||
|
||
//
|
||
// Check checksum is valid.
|
||
//
|
||
|
||
Checksum = BdComputeChecksum(MessageHeader->Buffer,
|
||
MessageHeader->Length);
|
||
|
||
|
||
Checksum += BdComputeChecksum(MessageData->Buffer,
|
||
MessageData->Length);
|
||
|
||
if (Checksum != PacketHeader.Checksum) {
|
||
goto SendResendPacket;
|
||
}
|
||
|
||
//
|
||
// Send Acknowledge byte and the Id of the packet received.
|
||
// Then, update the ExpectId for next incoming packet.
|
||
//
|
||
|
||
BdSendControlPacket(PACKET_TYPE_KD_ACKNOWLEDGE,
|
||
PacketHeader.PacketId);
|
||
|
||
//
|
||
// We have successfully received the packet so update the
|
||
// packet control variables and return success.
|
||
//
|
||
|
||
BdPacketIdExpected ^= 1;
|
||
return BD_PACKET_RECEIVED;
|
||
|
||
SendResendPacket:
|
||
BdSendControlPacket(PACKET_TYPE_KD_RESEND, 0L);
|
||
goto WaitForPacketLeader;
|
||
}
|
||
|
||
static
|
||
void
|
||
BdSendPacket(
|
||
IN UINT32 PacketType,
|
||
IN PSTRING MessageHeader,
|
||
IN PSTRING MessageData
|
||
)
|
||
|
||
//++
|
||
//
|
||
//Routine Description:
|
||
//
|
||
// This routine sends a packet to the host machine that is running the
|
||
// kernel debugger and waits for an ACK.
|
||
//
|
||
//Arguments:
|
||
//
|
||
// PacketType - Supplies the type of packet to send.
|
||
//
|
||
// MessageHeader - Supplies a pointer to a string descriptor that describes
|
||
// the message information.
|
||
//
|
||
// MessageData - Supplies a pointer to a string descriptor that describes
|
||
// the optional message data.
|
||
//
|
||
//Return Value:
|
||
//
|
||
// None.
|
||
//
|
||
//--
|
||
|
||
{
|
||
|
||
KD_PACKET PacketHeader;
|
||
UINT32 MessageDataLength;
|
||
UINT32 ReturnCode;
|
||
PDBGKD_DEBUG_IO DebugIo;
|
||
|
||
if (MessageData != NULL) {
|
||
MessageDataLength = MessageData->Length;
|
||
PacketHeader.Checksum = BdComputeChecksum(MessageData->Buffer,
|
||
MessageData->Length);
|
||
|
||
} else {
|
||
MessageDataLength = 0;
|
||
PacketHeader.Checksum = 0;
|
||
}
|
||
|
||
PacketHeader.Checksum += BdComputeChecksum(MessageHeader->Buffer,
|
||
MessageHeader->Length);
|
||
|
||
//
|
||
// Initialize and send the packet header.
|
||
//
|
||
|
||
PacketHeader.PacketLeader = PACKET_LEADER;
|
||
PacketHeader.ByteCount = (UINT16)(MessageHeader->Length + MessageDataLength);
|
||
PacketHeader.PacketType = (UINT16)PacketType;
|
||
BdNumberRetries = BdRetryCount;
|
||
do {
|
||
if (BdNumberRetries == 0) {
|
||
|
||
//
|
||
// If the packet is not for reporting exception, we give up
|
||
// and declare debugger not present.
|
||
//
|
||
|
||
if (PacketType == PACKET_TYPE_KD_DEBUG_IO) {
|
||
DebugIo = (PDBGKD_DEBUG_IO)MessageHeader->Buffer;
|
||
if (DebugIo->ApiNumber == DbgKdPrintStringApi) {
|
||
BdDebuggerNotPresent = 1;
|
||
BdNextPacketIdToSend = INITIAL_PACKET_ID | SYNC_PACKET_ID;
|
||
BdPacketIdExpected = INITIAL_PACKET_ID;
|
||
return;
|
||
}
|
||
}
|
||
}
|
||
|
||
//
|
||
// Setting PacketId has to be in the do loop in case Packet Id was
|
||
// reset.
|
||
//
|
||
|
||
PacketHeader.PacketId = BdNextPacketIdToSend;
|
||
BdSendString((PUINT8)&PacketHeader, sizeof(KD_PACKET));
|
||
|
||
//
|
||
// Output message header.
|
||
//
|
||
|
||
BdSendString(MessageHeader->Buffer, MessageHeader->Length);
|
||
|
||
//
|
||
// Output message data.
|
||
//
|
||
|
||
if ( MessageDataLength ) {
|
||
BdSendString(MessageData->Buffer, MessageData->Length);
|
||
}
|
||
|
||
//
|
||
// Output a packet trailing byte
|
||
//
|
||
|
||
BdPortPutByte(PACKET_TRAILING_BYTE);
|
||
|
||
//
|
||
// Wait for the Ack Packet
|
||
//
|
||
|
||
ReturnCode = BdReceivePacket(PACKET_TYPE_KD_ACKNOWLEDGE,
|
||
NULL,
|
||
NULL,
|
||
NULL);
|
||
|
||
if (ReturnCode == BD_PACKET_TIMEOUT) {
|
||
BdNumberRetries--;
|
||
}
|
||
|
||
} while (ReturnCode != BD_PACKET_RECEIVED);
|
||
|
||
//
|
||
// Reset Sync bit in packet id. The packet we sent may have Sync bit set
|
||
//
|
||
|
||
BdNextPacketIdToSend &= ~SYNC_PACKET_ID;
|
||
|
||
//
|
||
// Since we are able to talk to debugger, the retrycount is set to
|
||
// maximum value.
|
||
//
|
||
|
||
BdRetryCount = BD_MAXIMUM_RETRIES;
|
||
}
|
||
|
||
static
|
||
UINT32
|
||
BdReceiveString(
|
||
OUT PUINT8 Destination,
|
||
IN UINT32 Length
|
||
)
|
||
|
||
//++
|
||
//
|
||
//Routine Description:
|
||
//
|
||
// This routine reads a string from the kernel debugger port.
|
||
//
|
||
//Arguments:
|
||
//
|
||
// Destination - Supplies a pointer to the input string.
|
||
//
|
||
// Length - Supplies the length of the string to be read.
|
||
//
|
||
//Return Value:
|
||
//
|
||
// CP_GET_SUCCESS is returned if string is successfully read from the
|
||
// kernel debugger line.
|
||
// CP_GET_ERROR is returned if error encountered during reading.
|
||
// CP_GET_NODATA is returned if timeout.
|
||
//
|
||
//--
|
||
|
||
{
|
||
|
||
UINT8 Input;
|
||
UINT32 ReturnCode;
|
||
|
||
//
|
||
// Read bytes until either an error is encountered or the entire string
|
||
// has been read.
|
||
//
|
||
while (Length > 0) {
|
||
ReturnCode = BdPortGetByte(&Input);
|
||
if (ReturnCode != CP_GET_SUCCESS) {
|
||
return ReturnCode;
|
||
} else {
|
||
*Destination++ = Input;
|
||
Length -= 1;
|
||
}
|
||
}
|
||
|
||
return CP_GET_SUCCESS;
|
||
}
|
||
|
||
static
|
||
void
|
||
BdSendString(
|
||
IN PUINT8 Source,
|
||
IN UINT32 Length
|
||
)
|
||
|
||
//++
|
||
//
|
||
//Routine Description:
|
||
//
|
||
// This routine writes a string to the kernel debugger port.
|
||
//
|
||
//Arguments:
|
||
//
|
||
// Source - Supplies a pointer to the output string.
|
||
//
|
||
// Length - Supplies the length of the string to be written.
|
||
//
|
||
//Return Value:
|
||
//
|
||
// None.
|
||
//
|
||
//--
|
||
|
||
{
|
||
|
||
UINT8 Output;
|
||
|
||
//
|
||
// Write bytes to the kernel debugger port.
|
||
//
|
||
|
||
while (Length > 0) {
|
||
Output = *Source++;
|
||
BdPortPutByte(Output);
|
||
Length -= 1;
|
||
}
|
||
|
||
return;
|
||
}
|
||
|
||
void BdPrintString(char *Output, UINT Length)
|
||
|
||
//++
|
||
//
|
||
//Routine Description:
|
||
//
|
||
// This routine prints a string.
|
||
//
|
||
//Arguments:
|
||
//
|
||
// Output - Supplies a pointer to a string descriptor for the output string.
|
||
//
|
||
//--
|
||
|
||
{
|
||
|
||
STRING MessageData;
|
||
STRING MessageHeader;
|
||
DBGKD_DEBUG_IO DebugIo;
|
||
|
||
if (BdDebuggerNotPresent) {
|
||
return;
|
||
}
|
||
|
||
// If the total message length is greater than the maximum packet size,
|
||
// then truncate the output string.
|
||
//
|
||
if ((sizeof(DBGKD_DEBUG_IO) + Length) > PACKET_MAX_SIZE) {
|
||
Length = PACKET_MAX_SIZE - sizeof(DBGKD_DEBUG_IO);
|
||
}
|
||
|
||
// Construct the print string message and message descriptor.
|
||
//
|
||
DebugIo.ApiNumber = DbgKdPrintStringApi;
|
||
DebugIo.ProcessorLevel = 0;
|
||
DebugIo.Processor = 0;
|
||
DebugIo.LengthOfString = Length;
|
||
MessageHeader.Length = sizeof(DBGKD_DEBUG_IO);
|
||
MessageHeader.Buffer = (PUINT8)&DebugIo;
|
||
|
||
// Construct the print string data and data descriptor.
|
||
//
|
||
MessageData.Length = (UINT16)Length;
|
||
MessageData.Buffer = (PUINT8)Output;
|
||
|
||
// Send packet to the kernel debugger on the host machine.
|
||
//
|
||
BdSendPacket(PACKET_TYPE_KD_DEBUG_IO, &MessageHeader, &MessageData);
|
||
}
|
||
|
||
bool BdInitDebugger(bool present)
|
||
{
|
||
// Configure debugger state based on presence of transport layer.
|
||
//
|
||
if (present) {
|
||
BdDebuggerNotPresent = 0;
|
||
|
||
// Initialize the ID for the NEXT packet to send and the Expect
|
||
// ID of next incoming packet.
|
||
//
|
||
BdNextPacketIdToSend = INITIAL_PACKET_ID | SYNC_PACKET_ID;
|
||
BdPacketIdExpected = INITIAL_PACKET_ID;
|
||
|
||
// Number of retries and the retry count.
|
||
//
|
||
BdNumberRetries = 5;
|
||
BdRetryCount = 5;
|
||
|
||
return 1;
|
||
}
|
||
|
||
BdDebuggerNotPresent = 1;
|
||
return 0;
|
||
}
|