519 lines
9.0 KiB
C++
519 lines
9.0 KiB
C++
//++
|
|
//
|
|
// Copyright (c) Microsoft Corporation
|
|
//
|
|
// Module Name:
|
|
//
|
|
// blkdcom.cpp
|
|
//
|
|
// Abstract:
|
|
//
|
|
// This module implements the com port transport for KD.
|
|
//
|
|
//--
|
|
|
|
#include "bl.h"
|
|
|
|
#define KD_DELAY_LOOP 0x00010000
|
|
|
|
#define KD_INITIAL_PACKET_ID 0x80800000
|
|
#define KD_SYNC_PACKET_ID 0x00000800
|
|
|
|
#define KD_PACKET_TRAILING_BYTE 0xAA
|
|
|
|
struct {
|
|
KD_PACKET Header;
|
|
UINT8 Data[PAGE_SIZE - sizeof(KD_PACKET)];
|
|
} BlKdStaticPacket;
|
|
|
|
UINT8 BlKdComPort;
|
|
|
|
BOOLEAN
|
|
BlKdComReceiveByte(
|
|
PUINT8 Byte
|
|
)
|
|
|
|
//++
|
|
//
|
|
// Routine Description:
|
|
//
|
|
// This function receives a byte from the KD.
|
|
//
|
|
// Arguments:
|
|
//
|
|
// Byte - Receives the byte from KD.
|
|
//
|
|
// Return Value:
|
|
//
|
|
// TRUE, if receive operation was successful.
|
|
// FALSE, otherwise.
|
|
//
|
|
//--
|
|
|
|
{
|
|
volatile UINT32 Count;
|
|
|
|
if (BlKdComPort != 0) {
|
|
|
|
Count = KD_DELAY_LOOP;
|
|
|
|
while (Count > 0) {
|
|
|
|
if (BlComDataAvailable(BlKdComPort) != FALSE) {
|
|
|
|
*Byte = BlComReceiveByte(BlKdComPort);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
Count -= 1;
|
|
}
|
|
|
|
#if KD_VERBOSE
|
|
|
|
BlVideoPrintf("KD: Receive timeout!\n");
|
|
|
|
#endif
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
BOOLEAN
|
|
BlKdComSendData(
|
|
PCVOID Buffer,
|
|
UINT32 Length
|
|
)
|
|
|
|
//++
|
|
//
|
|
// Routine Description:
|
|
//
|
|
// This function sends data to the KD.
|
|
//
|
|
// Arguments:
|
|
//
|
|
// Buffer - Supplies a pointer to the buffer to send.
|
|
//
|
|
// Length - Supplies the length of the buffer to send.
|
|
//
|
|
// Return Value:
|
|
//
|
|
// TRUE, if send operation was successful.
|
|
// FALSE, otherwise.
|
|
//
|
|
//--
|
|
|
|
{
|
|
UINT32 Index;
|
|
|
|
for (Index = 0; Index < Length; Index += 1) {
|
|
|
|
if (BlComSendByte(BlKdComPort, ((PUINT8) Buffer)[Index]) == FALSE) {
|
|
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
BOOLEAN
|
|
BlKdComReceiveData(
|
|
PVOID Buffer,
|
|
UINT32 Length
|
|
)
|
|
|
|
//++
|
|
//
|
|
// Routine Description:
|
|
//
|
|
// This function receives data from the KD.
|
|
//
|
|
// Arguments:
|
|
//
|
|
// Buffer - Receives data.
|
|
//
|
|
// Length - Supplies the length of the buffer to receive.
|
|
//
|
|
// Return Value:
|
|
//
|
|
// TRUE, if receive operation was successful.
|
|
// FALSE, otherwise.
|
|
//
|
|
//--
|
|
|
|
{
|
|
UINT32 Index;
|
|
|
|
for (Index = 0; Index < Length; Index += 1) {
|
|
|
|
if (BlKdComReceiveByte(&(((PUINT8) Buffer)[Index])) == FALSE) {
|
|
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
BOOLEAN
|
|
BlKdComSendControlPacket(
|
|
UINT16 PacketType,
|
|
UINT32 PacketId
|
|
)
|
|
|
|
//++
|
|
//
|
|
// Routine Description:
|
|
//
|
|
// This function sends a control packet to the KD.
|
|
//
|
|
// Arguments:
|
|
//
|
|
// PacketType - Supplies the packet type.
|
|
//
|
|
// PacketId - Supplies the packet ID.
|
|
//
|
|
// Return Value:
|
|
//
|
|
// TRUE, if send operation was successful.
|
|
// FALSE, otherwise.
|
|
//
|
|
//--
|
|
|
|
{
|
|
KD_PACKET Header;
|
|
|
|
BlRtlZeroMemory(&Header, sizeof(Header));
|
|
|
|
Header.PacketLeader = KD_CONTROL_PACKET_LEADER;
|
|
Header.PacketType = PacketType;
|
|
Header.PacketId = PacketId;
|
|
|
|
if (BlKdComSendData(&Header, sizeof(Header)) == FALSE) {
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
#if KD_VERBOSE
|
|
|
|
BlVideoPrintf("KD: Sent type %u control packet.\n", PacketType);
|
|
|
|
#endif
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
BOOLEAN
|
|
BlKdComReceivePacket(
|
|
VOID
|
|
)
|
|
|
|
//++
|
|
//
|
|
// Routine Description:
|
|
//
|
|
// This function receives the next packet from the KD.
|
|
//
|
|
// Return Value:
|
|
//
|
|
// TRUE, if receive operation was successful.
|
|
// FALSE, otherwise.
|
|
//
|
|
//--
|
|
|
|
{
|
|
PKD_PACKET Header;
|
|
UINT8 TrailingByte;
|
|
|
|
Header = &BlKdStaticPacket.Header;
|
|
|
|
Retry:
|
|
|
|
for (;;) {
|
|
|
|
if (BlKdComReceiveData(&Header->PacketLeader, sizeof(Header->PacketLeader)) == FALSE) {
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
if (Header->PacketLeader == KD_PACKET_LEADER) {
|
|
|
|
break;
|
|
}
|
|
|
|
if (Header->PacketLeader == KD_CONTROL_PACKET_LEADER) {
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (BlKdComReceiveData(&Header->PacketType, sizeof(Header->PacketType)) == FALSE) {
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
if (BlKdComReceiveData(&Header->ByteCount, sizeof(Header->ByteCount)) == FALSE) {
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
if (BlKdComReceiveData(&Header->PacketId, sizeof(Header->PacketId)) == FALSE) {
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
if (BlKdComReceiveData(&Header->Checksum, sizeof(Header->Checksum)) == FALSE) {
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
if (Header->ByteCount > sizeof(BlKdStaticPacket.Data)) {
|
|
|
|
goto Retry;
|
|
}
|
|
|
|
if (Header->ByteCount > 0) {
|
|
|
|
if (BlKdComReceiveData(BlKdStaticPacket.Data, Header->ByteCount) == FALSE) {
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
if (BlKdComReceiveByte(&TrailingByte) == FALSE) {
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
if (TrailingByte != KD_PACKET_TRAILING_BYTE) {
|
|
|
|
goto Retry;
|
|
}
|
|
}
|
|
|
|
#if KD_VERBOSE
|
|
|
|
BlVideoPrintf("KD: Received type %u packet.\n", Header->PacketType);
|
|
|
|
#endif
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
BOOLEAN
|
|
BlKdComSendPacket(
|
|
UINT16 PacketType,
|
|
PCVOID Header,
|
|
UINT16 HeaderSize,
|
|
PCVOID Data,
|
|
UINT16 DataSize
|
|
)
|
|
|
|
//++
|
|
//
|
|
// Routine Description:
|
|
//
|
|
// This function sends a packet to the KD.
|
|
//
|
|
// Arguments:
|
|
//
|
|
// PacketType - Supplies the type of the packet to send.
|
|
//
|
|
// Header - Supplies a pointer to the header.
|
|
//
|
|
// HeaderSize - Supplies the size of the header.
|
|
//
|
|
// Data - Supplies a pointer to the data.
|
|
//
|
|
// DataSize - Supplies the size of the data.
|
|
//
|
|
// Return Value:
|
|
//
|
|
// TRUE, if send operation was successful.
|
|
// FALSE, otherwise.
|
|
//
|
|
//--
|
|
|
|
{
|
|
UINT16 ByteCount;
|
|
UINT32 Checksum;
|
|
KD_PACKET Packet;
|
|
|
|
BLASSERT(HeaderSize > 0);
|
|
|
|
Resend:
|
|
|
|
//
|
|
// Calculate byte count and checksum.
|
|
//
|
|
|
|
ByteCount = HeaderSize;
|
|
Checksum = BlKdComputeChecksum(Header, HeaderSize);
|
|
|
|
if (Data != NULL) {
|
|
|
|
BLASSERT(DataSize > 0);
|
|
|
|
ByteCount = ByteCount + DataSize;
|
|
Checksum += BlKdComputeChecksum(Data, DataSize);
|
|
}
|
|
|
|
//
|
|
// Send packet.
|
|
//
|
|
|
|
Packet.PacketLeader = KD_PACKET_LEADER;
|
|
Packet.PacketId = BlKdNextPacketId;
|
|
Packet.PacketType = PacketType;
|
|
Packet.ByteCount = ByteCount;
|
|
Packet.Checksum = Checksum;
|
|
|
|
if (BlKdComSendData(&Packet, sizeof(Packet)) == FALSE) {
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
if (BlKdComSendData(Header, HeaderSize) == FALSE) {
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
if (Data != NULL) {
|
|
|
|
if (BlKdComSendData(Data, DataSize) == FALSE) {
|
|
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
if (BlComSendByte(BlKdComPort, KD_PACKET_TRAILING_BYTE) == FALSE) {
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
#if KD_VERBOSE
|
|
|
|
BlVideoPrintf("KD: Sent type %u packet.\n", Packet.PacketType);
|
|
|
|
#endif
|
|
|
|
//
|
|
// Update packet ID.
|
|
//
|
|
|
|
BlKdNextPacketId &= (~KD_SYNC_PACKET_ID);
|
|
BlKdNextPacketId ^= 1;
|
|
|
|
if (BlKdComReceivePacket() != FALSE) {
|
|
|
|
switch (BlKdStaticPacket.Header.PacketType) {
|
|
|
|
case KD_PACKET_TYPE_KD_RESET: {
|
|
|
|
#if KD_VERBOSE
|
|
|
|
BlVideoPrintf("KD: Received RESET after send.\n");
|
|
|
|
#endif
|
|
|
|
BlKdComSendControlPacket(KD_PACKET_TYPE_KD_RESET, 0);
|
|
|
|
goto Resend;
|
|
}
|
|
|
|
case KD_PACKET_TYPE_KD_RESEND: {
|
|
|
|
#if KD_VERBOSE
|
|
|
|
BlVideoPrintf("KD: Received RESEND after send.\n");
|
|
|
|
#endif
|
|
|
|
goto Resend;
|
|
}
|
|
}
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
BOOLEAN
|
|
BlKdComConnect(
|
|
VOID
|
|
)
|
|
|
|
//++
|
|
//
|
|
// Routine Description:
|
|
//
|
|
// This function tries to connect to the KD through a COM port.
|
|
//
|
|
// Return Value:
|
|
//
|
|
// TRUE, if connection was successful.
|
|
// FALSE, otherwise.
|
|
//
|
|
//--
|
|
|
|
{
|
|
UINT8 Index;
|
|
BOOLEAN Present[COM_MAX_PORT + 1];
|
|
UINT32 Retry;
|
|
|
|
|
|
//
|
|
// Find all COM ports on the system.
|
|
//
|
|
|
|
for (Index = 1; Index <= COM_MAX_PORT; Index += 1) {
|
|
|
|
Present[Index] = BlComInitialize(Index, 115200);
|
|
|
|
#if KD_VERBOSE
|
|
|
|
BlVideoPrintf("KD: COM%u %s\n",
|
|
Index,
|
|
Present[Index] ? "found." : "not found.");
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
//
|
|
// Set initial packet ID.
|
|
//
|
|
|
|
BlKdNextPacketId = KD_INITIAL_PACKET_ID | KD_SYNC_PACKET_ID;
|
|
|
|
for (Retry = 0; Retry < KD_RETRY_COUNT; Retry += 1) {
|
|
|
|
for (Index = 1; Index <= COM_MAX_PORT; Index += 1) {
|
|
|
|
if (Present[Index] != FALSE) {
|
|
|
|
#if KD_VERBOSE
|
|
|
|
BlVideoPrintf("KD: Trying COM%u ...\n", Index);
|
|
|
|
#endif
|
|
|
|
BlKdComPort = Index;
|
|
|
|
BlKdComSendControlPacket(KD_PACKET_TYPE_KD_RESET, 0);
|
|
|
|
if (BlKdComReceivePacket() != FALSE) {
|
|
|
|
return TRUE;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
BlKdComPort = 0;
|
|
|
|
return FALSE;
|
|
}
|