singrdk/base/boot/SingLdrPc/blkdcom.cpp

519 lines
9.0 KiB
C++
Raw Normal View History

2008-11-17 18:29:00 -05:00
//++
//
// 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;
}