diff --git a/reactos/drivers/base/directory.rbuild b/reactos/drivers/base/directory.rbuild index 72ad22d9ef9..659f8e69357 100644 --- a/reactos/drivers/base/directory.rbuild +++ b/reactos/drivers/base/directory.rbuild @@ -7,9 +7,16 @@ - - - + + + + + + + + + + diff --git a/reactos/drivers/base/kddll/kdcom.c b/reactos/drivers/base/kddll/kdcom.c new file mode 100644 index 00000000000..409b88e4d91 --- /dev/null +++ b/reactos/drivers/base/kddll/kdcom.c @@ -0,0 +1,291 @@ +/* + * COPYRIGHT: GPL, see COPYING in the top level directory + * PROJECT: ReactOS kernel + * FILE: drivers/base/kddll/kdcom.c + * PURPOSE: COM port functions for the kernel debugger. + * PROGRAMMER: Timo Kreuzer (timo.kreuzer@ewactos.org) + */ + +#include "kddll.h" +#include "kdcom.h" + +/* Define wait timeout value. */ +#define REPEAT_COUNT (1000 * 1000) + +/* serial debug connection */ +#define DEFAULT_DEBUG_PORT 2 /* COM2 */ +#define DEFAULT_DEBUG_COM1_IRQ 4 /* COM1 IRQ */ +#define DEFAULT_DEBUG_COM2_IRQ 3 /* COM2 IRQ */ +#define DEFAULT_DEBUG_BAUD_RATE 115200 /* 115200 Baud */ + +#define DEFAULT_BAUD_RATE 19200 + + +#if defined(_M_IX86) || defined(_M_AMD64) +const ULONG BaseArray[5] = {0, 0x3F8, 0x2F8, 0x3E8, 0x2E8}; +#elif defined(_M_PPC) +const ULONG BaseArray[2] = {0, 0x800003f8}; +#elif defined(_M_MIPS) +const ULONG BaseArray[3] = {0, 0x80006000, 0x80007000}; +#elif defined(_M_ARM) +const ULONG BaseArray[2] = {0, 0xF1012000}; +#else +#error Unknown architecture +#endif + +/* GLOBALS ********************************************************************/ + +PUCHAR ComPortBase; +ULONG ComPortNumber = DEFAULT_DEBUG_PORT; +ULONG ComPortBaudRate = DEFAULT_DEBUG_BAUD_RATE; +ULONG ComPortIrq = 0; + + +NTSTATUS +NTAPI +KdpPortInitialize() +{ + ULONG Mode; + + KDDBGPRINT("KdpPortInitialize\n"); + + /* Enable loop mode (set Bit 4 of the MCR) */ + WRITE_PORT_UCHAR(ComPortBase + COM_MCR, MCR_LOOP); + + /* Clear all modem output bits */ + WRITE_PORT_UCHAR(ComPortBase + COM_MCR, MCR_LOOP); + + /* The upper nibble of the MSR (modem output bits) must be + * equal to the lower nibble of the MCR (modem input bits) */ + if ((READ_PORT_UCHAR(ComPortBase + COM_MSR) & 0xF0) != 0x00) + { + return STATUS_INVALID_PARAMETER; + } + + /* Set all modem output bits */ + WRITE_PORT_UCHAR(ComPortBase + COM_MCR, MCR_ALL); + + /* The upper nibble of the MSR (modem output bits) must be + * equal to the lower nibble of the MCR (modem input bits) */ + if ((READ_PORT_UCHAR(ComPortBase + COM_MSR) & 0xF0) != 0xF0) + { + return STATUS_INVALID_PARAMETER; + } + + /* Enable FIFO */ + WRITE_PORT_UCHAR(ComPortBase + COM_FCR, + FCR_ENABLE_FIFO | FCR_CLEAR_RCVR | FCR_CLEAR_XMIT); + + /* Disable interrupts */ + WRITE_PORT_UCHAR(ComPortBase + COM_LCR, 0); + WRITE_PORT_UCHAR(ComPortBase + COM_IEN, 0); + + /* Enable on DTR and RTS */ + WRITE_PORT_UCHAR(ComPortBase + COM_MCR, MCR_DTR | MCR_RTS); + + /* Set DLAB */ + WRITE_PORT_UCHAR(ComPortBase + COM_LCR, LCR_DLAB); + + /* Set baud rate */ + Mode = 115200 / ComPortBaudRate; + WRITE_PORT_UCHAR(ComPortBase + COM_DLL, (UCHAR)(Mode & 0xff)); + WRITE_PORT_UCHAR(ComPortBase + COM_DLM, (UCHAR)((Mode >> 8) & 0xff)); + + /* Reset DLAB and set 8 data bits, 1 stop bit, no parity, no break */ + WRITE_PORT_UCHAR(ComPortBase + COM_LCR, LCR_CS8 | LCR_ST1 | LCR_PNO); + + /* Check for 16450/16550 scratch register */ + WRITE_PORT_UCHAR(ComPortBase + COM_SCR, 0xff); + if (READ_PORT_UCHAR(ComPortBase + COM_SCR) != 0xff) + { + return STATUS_INVALID_PARAMETER; + } + WRITE_PORT_UCHAR(ComPortBase + COM_SCR, 0x00); + if (READ_PORT_UCHAR(ComPortBase + COM_SCR) != 0x00) + { + return STATUS_INVALID_PARAMETER; + } + + return STATUS_SUCCESS; +} + +/****************************************************************************** + * \name KdDebuggerInitialize0 + * \brief Phase 0 initialization. + * \param [opt] LoaderBlock Pointer to the Loader parameter block. Can be NULL. + * \return Status + */ +NTSTATUS +NTAPI +KdDebuggerInitialize0( + IN PLOADER_PARAMETER_BLOCK LoaderBlock OPTIONAL) +{ + PCHAR CommandLine, PortString, BaudString, IrqString; + ULONG Value; + + /* Check if e have a LoaderBlock */ + if (LoaderBlock) + { + /* Get the Command Line */ + CommandLine = LoaderBlock->LoadOptions; + + /* Upcase it */ + _strupr(CommandLine); + + /* Get the port and baud rate */ + PortString = strstr(CommandLine, "DEBUGPORT"); + BaudString = strstr(CommandLine, "BAUDRATE"); + IrqString = strstr(CommandLine, "IRQ"); + + /* Check if we got the /DEBUGPORT parameter */ + if (PortString) + { + /* Move past the actual string, to reach the port*/ + PortString += strlen("DEBUGPORT"); + + /* Now get past any spaces and skip the equal sign */ + while (*PortString == ' ') PortString++; + PortString++; + + /* Do we have a serial port? */ + if (strncmp(PortString, "COM", 3) != 0) + { + return STATUS_INVALID_PARAMETER; + } + + /* Gheck for a valid Serial Port */ + PortString += 3; + Value = atol(PortString); + if (Value > 4) + { + return STATUS_INVALID_PARAMETER; + } + + /* Set the port to use */ + ComPortNumber = Value; + } + + /* Check if we got a baud rate */ + if (BaudString) + { + /* Move past the actual string, to reach the rate */ + BaudString += strlen("BAUDRATE"); + + /* Now get past any spaces */ + while (*BaudString == ' ') BaudString++; + + /* And make sure we have a rate */ + if (*BaudString) + { + /* Read and set it */ + Value = atol(BaudString + 1); + if (Value) ComPortBaudRate = Value; + } + } + + /* Check Serial Port Settings [IRQ] */ + if (IrqString) + { + /* Move past the actual string, to reach the rate */ + IrqString += strlen("IRQ"); + + /* Now get past any spaces */ + while (*IrqString == ' ') IrqString++; + + /* And make sure we have an IRQ */ + if (*IrqString) + { + /* Read and set it */ + Value = atol(IrqString + 1); + if (Value) ComPortIrq = Value; + } + } + } + + /* Get base address */ + ComPortBase = UlongToPtr(BaseArray[ComPortNumber]); + + /* Initialize the port */ + return KdpPortInitialize(); +} + +VOID +NTAPI +KdpSendByte(IN BYTE Byte) +{ + /* Wait for the port to be ready */ + while ((READ_PORT_UCHAR(ComPortBase + COM_LSR) & LSR_TBE) == 0); + + /* Send the byte */ + WRITE_PORT_UCHAR(ComPortBase + COM_DAT, Byte); +} + +KDP_STATUS +NTAPI +KdpPollByte(OUT PBYTE OutByte) +{ + /* Check if data is available */ + if ((READ_PORT_UCHAR(ComPortBase + COM_LSR) & LSR_DR)) + { + /* Yes, return the byte */ + *OutByte = READ_PORT_UCHAR(ComPortBase + COM_DAT); + return KDP_PACKET_RECEIVED; + } + + /* Timed out */ + return KDP_PACKET_TIMEOUT; +} + +KDP_STATUS +NTAPI +KdpReceiveByte(OUT PBYTE OutByte) +{ + ULONG Repeats = REPEAT_COUNT; + + while (Repeats--) + { + /* Check if data is available */ + if (KdpPollByte(OutByte) == KDP_PACKET_RECEIVED) + { + /* We successfully got a byte */ + return KDP_PACKET_RECEIVED; + } + } + + /* Timed out */ + return KDP_PACKET_TIMEOUT; +} + +KDP_STATUS +NTAPI +KdpPollBreakIn() +{ + UCHAR Byte; + if (KdpPollByte(&Byte) == KDP_PACKET_RECEIVED) + { + if (Byte == BREAKIN_PACKET_BYTE) + { + return KDP_PACKET_RECEIVED; + } + } + return KDP_PACKET_TIMEOUT; +} + +NTSTATUS +NTAPI +KdSave( + IN BOOLEAN SleepTransition) +{ + /* Nothing to do on COM ports */ + return STATUS_SUCCESS; +} + +NTSTATUS +NTAPI +KdRestore( + IN BOOLEAN SleepTransition) +{ + /* Nothing to do on COM ports */ + return STATUS_SUCCESS; +} + diff --git a/reactos/drivers/base/kddll/kdcom.h b/reactos/drivers/base/kddll/kdcom.h new file mode 100644 index 00000000000..b7cc9af04b3 --- /dev/null +++ b/reactos/drivers/base/kddll/kdcom.h @@ -0,0 +1,57 @@ +/* + * COPYRIGHT: GPL, see COPYING in the top level directory + * PROJECT: ReactOS kernel + * FILE: drivers/base/kddll/kdcom.h + * PURPOSE: COM port definitions for the kernel debugger. + * PROGRAMMER: Timo Kreuzer (timo.kreuzer@ewactos.org) + */ + +#ifndef _KDCOM_H_ +#define _KDCOM_H_ + +#define COM_DAT 0x00 +#define COM_IEN 0x01 /* interrupt enable register */ +#define COM_FCR 0x02 /* FIFO Control Register */ +#define COM_LCR 0x03 /* line control registers */ +#define COM_MCR 0x04 /* modem control reg */ +#define COM_LSR 0x05 /* line status register */ +#define COM_MSR 0x06 /* modem status register */ +#define COM_SCR 0x07 /* scratch register */ +#define COM_DLL 0x00 /* divisor latch least sig */ +#define COM_DLM 0x01 /* divisor latch most sig */ + +#define IEN_ERDA 0x01 +#define IEN_ETHRE 0x02 +#define IEN_ERLSI 0x04 +#define IEN_EMS 0x08 +#define IEN_ALL 0x0F +#define FCR_ENABLE_FIFO 0x01 +#define FCR_CLEAR_RCVR 0x02 +#define FCR_CLEAR_XMIT 0x04 +#define LCR_CS5 0x00 +#define LCR_CS6 0x01 +#define LCR_CS7 0x02 +#define LCR_CS8 0x03 +#define LCR_ST1 0x00 +#define LCR_ST2 0x04 +#define LCR_PNO 0x00 +#define LCR_POD 0x08 +#define LCR_PEV 0x18 +#define LCR_PMK 0x28 +#define LCR_PSP 0x38 +#define LCR_BRK 0x40 +#define LCR_DLAB 0x80 +#define MCR_DTR 0x01 +#define MCR_RTS 0x02 +#define MCR_OUT1 0x04 /* general purpose output */ +#define MCR_OUT2 0x08 +#define MCR_LOOP 0x10 /* loopback testing mode */ +#define MCR_ALL (MCR_DTR | MCR_RTS | MCR_OUT1 | MCR_OUT2 | MCR_LOOP) +#define LSR_DR 0x01 +#define LSR_TBE 0x20 +#define MSR_CTS 0x10 /* (complemented) state of clear to send (CTS). */ +#define MSR_DSR 0x20 /* (complemented) state of data set ready (DSR). */ +#define MSR_RI 0x40 /* (complemented) state of ring indicator (RI). */ +#define MSR_DCD 0x80 /* (complemented) state of data carrier detect (DCD). */ + +#endif /* !_KDCOM_H_ */ diff --git a/reactos/drivers/base/kddll/kddll.c b/reactos/drivers/base/kddll/kddll.c new file mode 100644 index 00000000000..4e4c1ebccb1 --- /dev/null +++ b/reactos/drivers/base/kddll/kddll.c @@ -0,0 +1,421 @@ +/* + * COPYRIGHT: GPL, see COPYING in the top level directory + * PROJECT: ReactOS kernel + * FILE: drivers/base/kddll/kddll.c + * PURPOSE: Base functions for the kernel debugger. + * PROGRAMMER: Timo Kreuzer (timo.kreuzer@ewactos.org) + */ + +//#define KDDEBUG /* uncomment to enable debugging this dll */ +#include "kddll.h" + +/* GLOBALS ********************************************************************/ + +PFNDBGPRNT KdpDbgPrint = NULL; +ULONG CurrentPacketId = INITIAL_PACKET_ID | SYNC_PACKET_ID; + + +/* PRIVATE FUNCTIONS **********************************************************/ + +/****************************************************************************** + * \name KdpCalculateChecksum + * \brief Calculates the checksum for the packet data. + * \param Buffer Pointer to the packet data. + * \param Length Length of data in bytes. + * \return The calculated checksum. + * \sa http://www.vista-xp.co.uk/forums/technical-reference-library/2540-basics-debugging.html + */ +ULONG +NTAPI +KdpCalculateChecksum( + IN PVOID Buffer, + IN ULONG Length) +{ + ULONG i, Checksum = 0; + + for (i = 0; i < Length; i++) + { + Checksum += ((PUCHAR)Buffer)[i]; + } + + return Checksum; +} + +VOID +NTAPI +KdpSendControlPacket( + IN USHORT PacketType, + IN ULONG PacketId OPTIONAL) +{ + KD_PACKET Packet; + + Packet.PacketLeader = CONTROL_PACKET_LEADER; + Packet.PacketId = PacketId; + Packet.ByteCount = 0; + Packet.Checksum = 0; + Packet.PacketType = PacketType; + + KdpSendBuffer(&Packet, sizeof(KD_PACKET)); +} + + +/* PUBLIC FUNCTIONS ***********************************************************/ + +NTSTATUS +NTAPI +KdD0Transition(VOID) +{ + return STATUS_SUCCESS; +} + +NTSTATUS +NTAPI +KdD3Transition(VOID) +{ + return STATUS_SUCCESS; +} + + +/****************************************************************************** + * \name KdDebuggerInitialize1 + * \brief Phase 1 initialization. + * \param [opt] LoaderBlock Pointer to the Loader parameter block. Can be NULL. + * \return Status + */ +NTSTATUS +NTAPI +KdDebuggerInitialize1( + IN PLOADER_PARAMETER_BLOCK LoaderBlock OPTIONAL) +{ + // HACK: misuse this function to get a pointer to FrLdrDbgPrint + KdpDbgPrint = (PVOID)LoaderBlock; + KDDBGPRINT("KdDebuggerInitialize1\n"); + + return STATUS_NOT_IMPLEMENTED; +} + + +/****************************************************************************** + * \name KdReceivePacket + * \brief Receive a packet from the KD port. + * \param [in] PacketType Describes the type of the packet to receive. + * This can be one of the PACKET_TYPE_ constants. + * \param [out] MessageHeader Pointer to a STRING structure for the header. + * \param [out] MessageData Pointer to a STRING structure for the data. + * \return KdPacketReceived if successful, KdPacketTimedOut if the receive + * timed out, KdPacketNeedsResend to signal that the last packet needs + * to be sent again. + * \note If PacketType is PACKET_TYPE_KD_POLL_BREAKIN, the function doesn't + * wait for any data, but returns KdPacketTimedOut instantly if no breakin + * packet byte is received. + * \sa http://www.nynaeve.net/?p=169 + */ +KDP_STATUS +NTAPI +KdReceivePacket( + IN ULONG PacketType, + OUT PSTRING MessageHeader, + OUT PSTRING MessageData, + OUT PULONG DataLength, + IN OUT PKD_CONTEXT KdContext) +{ + UCHAR Byte = 0; + KDP_STATUS KdStatus; + KD_PACKET Packet; + ULONG Checksum; + + /* Special handling for breakin packet */ + if(PacketType == PACKET_TYPE_KD_POLL_BREAKIN) + { + return KdpPollBreakIn(); + } + + for (;;) + { + /* Step 1 - Read PacketLeader */ + KdStatus = KdpReceivePacketLeader(&Packet.PacketLeader); + if (KdStatus != KDP_PACKET_RECEIVED) + { + /* Check if we got a breakin */ + if (KdStatus == KDP_PACKET_RESEND) + { + KdContext->BreakInRequested = TRUE; + } + return KdStatus; + } + + /* Step 2 - Read PacketType */ + KdStatus = KdpReceiveBuffer(&Packet.PacketType, sizeof(USHORT)); + if (KdStatus != KDP_PACKET_RECEIVED) + { + /* Didn't receive a PacketType or PacketType is bad. Start over. */ + continue; + } + + /* Step 3 - Read ByteCount */ + KdStatus = KdpReceiveBuffer(&Packet.ByteCount, sizeof(USHORT)); + if (KdStatus != KDP_PACKET_RECEIVED || Packet.ByteCount > PACKET_MAX_SIZE) + { + /* Didn't receive ByteCount or it's too big. Start over. */ + continue; + } + + /* Step 4 - Read PacketId */ + KdStatus = KdpReceiveBuffer(&Packet.PacketId, sizeof(ULONG)); + if (KdStatus != KDP_PACKET_RECEIVED) + { + /* Didn't receive PacketId. Start over. */ + continue; + } + +/* + if (Packet.PacketId != ExpectedPacketId) + { + // Ask for a resend! + continue; + } +*/ + + /* Step 5 - Read Checksum */ + KdStatus = KdpReceiveBuffer(&Packet.Checksum, sizeof(ULONG)); + if (KdStatus != KDP_PACKET_RECEIVED) + { + /* Didn't receive Checksum. Start over. */ + continue; + } + + /* Step 6 - Handle control packets */ + if (Packet.PacketLeader == CONTROL_PACKET_LEADER) + { + switch (Packet.PacketType) + { + case PACKET_TYPE_KD_ACKNOWLEDGE: + /* Are we waiting for an ACK packet? */ + if (PacketType == PACKET_TYPE_KD_ACKNOWLEDGE && + Packet.PacketId == (CurrentPacketId & ~SYNC_PACKET_ID)) + { + /* Remote acknowledges the last packet */ + CurrentPacketId ^= 1; + return KDP_PACKET_RECEIVED; + } + /* That's not what we were waiting for, start over. */ + continue; + + case PACKET_TYPE_KD_RESET: + KDDBGPRINT("KdReceivePacket - got a reset packet\n"); + KdpSendControlPacket(PACKET_TYPE_KD_RESET, 0); + CurrentPacketId = INITIAL_PACKET_ID; + /* Fall through */ + + case PACKET_TYPE_KD_RESEND: + KDDBGPRINT("KdReceivePacket - got PACKET_TYPE_KD_RESEND\n"); + /* Remote wants us to resend the last packet */ + return KDP_PACKET_RESEND; + + default: + KDDBGPRINT("KdReceivePacket - got unknown control packet\n"); + return KDP_PACKET_RESEND; + } + } + + /* Did we wait for an ack packet? */ + if (PacketType == PACKET_TYPE_KD_ACKNOWLEDGE) + { + /* We received something different */ + KdpSendControlPacket(PACKET_TYPE_KD_RESEND, 0); + CurrentPacketId ^= 1; + return KDP_PACKET_RECEIVED; + } + + /* Did we get the right packet type? */ + if (PacketType != Packet.PacketType) + { + /* We received something different, start over */ + KDDBGPRINT("KdReceivePacket - wrong PacketType\n"); + KdpSendControlPacket(PACKET_TYPE_KD_RESEND, 0); + continue; + } + + /* Get size of the message header */ + switch (Packet.PacketType) + { + case PACKET_TYPE_KD_STATE_CHANGE64: + MessageHeader->Length = sizeof(DBGKD_WAIT_STATE_CHANGE64); + break; + + case PACKET_TYPE_KD_STATE_MANIPULATE: + MessageHeader->Length = sizeof(DBGKD_MANIPULATE_STATE64); + break; + + case PACKET_TYPE_KD_DEBUG_IO: + MessageHeader->Length = sizeof(DBGKD_DEBUG_IO); + break; + + default: + KDDBGPRINT("KdReceivePacket - unknown PacketType\n"); + return KDP_PACKET_RESEND; + } + + //KDDBGPRINT("KdReceivePacket - got normal PacketType\n"); + + /* Packet smaller than expected? */ + if (MessageHeader->Length > Packet.ByteCount) + { + KDDBGPRINT("KdReceivePacket - too few data (%d) for type %d\n", + Packet.ByteCount, MessageHeader->Length); + MessageHeader->Length = Packet.ByteCount; + } + + //KDDBGPRINT("KdReceivePacket - got normal PacketType, Buffer = %p\n", MessageHeader->Buffer); + + /* Receive the message header data */ + KdStatus = KdpReceiveBuffer(MessageHeader->Buffer, + MessageHeader->Length); + if (KdStatus != KDP_PACKET_RECEIVED) + { + /* Didn't receive data. Packet needs to be resent. */ + KDDBGPRINT("KdReceivePacket - Didn't receive message header data.\n"); + KdpSendControlPacket(PACKET_TYPE_KD_RESEND, 0); + continue; + } + + //KDDBGPRINT("KdReceivePacket - got normal PacketType 3\n"); + + /* Calculate checksum for the header data */ + Checksum = KdpCalculateChecksum(MessageHeader->Buffer, + MessageHeader->Length); + + /* Calculate the length of the message data */ + *DataLength = Packet.ByteCount - MessageHeader->Length; + + /* Shall we receive messsage data? */ + if (MessageData) + { + /* Set the length of the message data */ + MessageData->Length = *DataLength; + + /* Do we have data? */ + if (MessageData->Length) + { + KDDBGPRINT("KdReceivePacket - got data\n"); + + /* Receive the message data */ + KdStatus = KdpReceiveBuffer(MessageData->Buffer, + MessageData->Length); + if (KdStatus != KDP_PACKET_RECEIVED) + { + /* Didn't receive data. Start over. */ + KDDBGPRINT("KdReceivePacket - Didn't receive message data.\n"); + KdpSendControlPacket(PACKET_TYPE_KD_RESEND, 0); + continue; + } + + /* Add cheksum for message data */ + Checksum += KdpCalculateChecksum(MessageData->Buffer, + MessageData->Length); + } + } + + /* Compare checksum */ + if (Packet.Checksum != Checksum) + { + KDDBGPRINT("KdReceivePacket - wrong cheksum, got %x, calculated %x\n", + Packet.Checksum, Checksum); + KdpSendControlPacket(PACKET_TYPE_KD_RESEND, 0); + continue; + } + + /* We must receive a PACKET_TRAILING_BYTE now */ + KdStatus = KdpReceiveBuffer(&Byte, sizeof(UCHAR)); + if (KdStatus != KDP_PACKET_RECEIVED || Byte != PACKET_TRAILING_BYTE) + { + KDDBGPRINT("KdReceivePacket - wrong trailing byte (0x%x), status 0x%x\n", Byte, KdStatus); + KdpSendControlPacket(PACKET_TYPE_KD_RESEND, 0); + continue; + } + + /* Acknowledge the received packet */ + KdpSendControlPacket(PACKET_TYPE_KD_ACKNOWLEDGE, Packet.PacketId); + + //KDDBGPRINT("KdReceivePacket - all ok\n"); + + return KDP_PACKET_RECEIVED; + } + + return KDP_PACKET_RECEIVED; +} + + +VOID +NTAPI +KdSendPacket( + IN ULONG PacketType, + IN PSTRING MessageHeader, + IN PSTRING MessageData, + IN OUT PKD_CONTEXT Context) +{ + KD_PACKET Packet; + KDP_STATUS KdStatus; + + /* Initialize a KD_PACKET */ + Packet.PacketLeader = PACKET_LEADER; + Packet.PacketType = PacketType; + Packet.ByteCount = MessageHeader->Length; + Packet.Checksum = KdpCalculateChecksum(MessageHeader->Buffer, + MessageHeader->Length); + + /* If we have message data, add it to the packet */ + if (MessageData) + { + Packet.ByteCount += MessageData->Length; + Packet.Checksum += KdpCalculateChecksum(MessageData->Buffer, + MessageData->Length); + } + + for (;;) + { + /* Set the packet id */ + Packet.PacketId = CurrentPacketId; + + /* Send the packet header to the KD port */ + KdpSendBuffer(&Packet, sizeof(KD_PACKET)); + + /* Send the message header */ + KdpSendBuffer(MessageHeader->Buffer, MessageHeader->Length); + + /* If we have meesage data, also send it */ + if (MessageData) + { + KdpSendBuffer(MessageData->Buffer, MessageData->Length); + } + + /* Finalize with a trailing byte */ + KdpSendByte(PACKET_TRAILING_BYTE); + + /* Wait for acknowledge */ + KdStatus = KdReceivePacket(PACKET_TYPE_KD_ACKNOWLEDGE, + NULL, + NULL, + 0, + NULL); + + /* Did we succeed? */ + if (KdStatus == KDP_PACKET_RECEIVED) + { + CurrentPacketId &= ~SYNC_PACKET_ID; + break; + } + + /* PACKET_TYPE_KD_DEBUG_IO is allowed to instantly timeout */ + if (PacketType == PACKET_TYPE_KD_DEBUG_IO) + { + /* No response, silently fail. */ + return; + } + + /* Packet timed out, send it again */ + } + + return; +} + diff --git a/reactos/drivers/base/kddll/kddll.h b/reactos/drivers/base/kddll/kddll.h new file mode 100644 index 00000000000..81a20c5a1b5 --- /dev/null +++ b/reactos/drivers/base/kddll/kddll.h @@ -0,0 +1,85 @@ +/* + * COPYRIGHT: GPL, see COPYING in the top level directory + * PROJECT: ReactOS kernel + * FILE: drivers/base/kddll/kddll.h + * PURPOSE: Base definitions for the kernel debugger. + * PROGRAMMER: Timo Kreuzer (timo.kreuzer@ewactos.org) + */ + +#ifndef _KDDLL_H_ +#define _KDDLL_H_ + +#define NOEXTAPI +#include +#define NDEBUG +#include +#include +#include +#include +#include "arc/arc.h" +#include "windbgkd.h" + +#include +#include /* port intrinsics */ + +typedef UCHAR BYTE, *PBYTE; + +typedef ULONG (*PFNDBGPRNT)(const char *Format, ...); +extern PFNDBGPRNT KdpDbgPrint; + +typedef enum +{ + KDP_PACKET_RECEIVED = 0, + KDP_PACKET_TIMEOUT = 1, + KDP_PACKET_RESEND = 2 +} KDP_STATUS; + +#ifndef KDDEBUG +#define KDDBGPRINT(...) +#else +#define KDDBGPRINT KdpDbgPrint +#endif + +VOID +NTAPI +KdpSendBuffer( + IN PVOID Buffer, + IN ULONG Size); + +KDP_STATUS +NTAPI +KdpReceiveBuffer( + OUT PVOID Buffer, + IN ULONG Size); + +KDP_STATUS +NTAPI +KdpReceivePacketLeader( + OUT PULONG PacketLeader); + +VOID +NTAPI +KdpSendByte(IN BYTE Byte); + +KDP_STATUS +NTAPI +KdpPollByte(OUT PBYTE OutByte); + +KDP_STATUS +NTAPI +KdpReceiveByte(OUT PBYTE OutByte); + +KDP_STATUS +NTAPI +KdpPollBreakIn(); + + +#if 0 +NTSTATUS +NTAPI +KdDebuggerInitialize0( + IN PLOADER_PARAMETER_BLOCK LoaderBlock OPTIONAL); +#endif + + +#endif /* !_KDDLL_H_ */ diff --git a/reactos/drivers/base/kddll/kddll.rbuild b/reactos/drivers/base/kddll/kddll.rbuild new file mode 100644 index 00000000000..4e243beca1c --- /dev/null +++ b/reactos/drivers/base/kddll/kddll.rbuild @@ -0,0 +1,23 @@ + + + + + . + ntoskrnl + hal + kddll.c + + + + . + kdserial.c + + + + + + . + kdlib + kdserial + kdcom.c + diff --git a/reactos/drivers/base/kddll/kddll.spec b/reactos/drivers/base/kddll/kddll.spec new file mode 100644 index 00000000000..4098dd6e2ad --- /dev/null +++ b/reactos/drivers/base/kddll/kddll.spec @@ -0,0 +1,8 @@ +@ stdcall KdD0Transition() +@ stdcall KdD3Transition() +@ stdcall KdDebuggerInitialize0(ptr) +@ stdcall KdDebuggerInitialize1(ptr) +@ stdcall KdReceivePacket(long ptr ptr ptr ptr) +@ stdcall KdRestore(long) +@ stdcall KdSave(long) +@ stdcall KdSendPacket(long ptr ptr ptr) diff --git a/reactos/drivers/base/kddll/kdserial.c b/reactos/drivers/base/kddll/kdserial.c new file mode 100644 index 00000000000..6964ab95ae6 --- /dev/null +++ b/reactos/drivers/base/kddll/kdserial.c @@ -0,0 +1,149 @@ +/* + * COPYRIGHT: GPL, see COPYING in the top level directory + * PROJECT: ReactOS kernel + * FILE: drivers/base/kddll/kdserial.c + * PURPOSE: Serial communication functions for the kernel debugger. + * PROGRAMMER: Timo Kreuzer (timo.kreuzer@ewactos.org) + */ + +#include "kddll.h" + + + +/****************************************************************************** + * \name KdpSendBuffer + * \brief Sends a buffer of data to the serial KD port. + * \param Buffer Pointer to the data. + * \param Size Size of data in bytes. + */ +VOID +NTAPI +KdpSendBuffer( + IN PVOID Buffer, + IN ULONG Size) +{ + INT i; + for (i = 0; i < Size; i++) + { + KdpSendByte(((PUCHAR)Buffer)[i]); + } +} + +/****************************************************************************** + * \name KdpReceiveBuffer + * \brief Recieves data from the KD port and fills a buffer. + * \param Buffer Pointer to a buffer that receives the data. + * \param Size Size of data to receive in bytes. + * \return KDP_PACKET_RECEIVED if successful. + * KDP_PACKET_TIMEOUT if the receice timed out. + */ +KDP_STATUS +NTAPI +KdpReceiveBuffer( + OUT PVOID Buffer, + IN ULONG Size) +{ + ULONG i; + PUCHAR ByteBuffer = Buffer; + KDP_STATUS Status; + + for (i = 0; i < Size; i++) + { + /* Try to get a byte from the port */ + Status = KdpReceiveByte(&ByteBuffer[i]); + + if (Status != KDP_PACKET_RECEIVED) + { + return Status; + } + } + + return KDP_PACKET_RECEIVED; +} + + +/****************************************************************************** + * \name KdpReceivePacketLeader + * \brief Recieves a packet leadr from the KD port. + * \param PacketLeader Pointer to an ULONG that receives the packet leader. + * \return KDP_PACKET_RECEIVED if successful. + * KDP_PACKET_TIMEOUT if the receive timed out. + * KDP_PACKET_RESEND if a breakin byte was detected. + */ +KDP_STATUS +NTAPI +KdpReceivePacketLeader( + OUT PULONG PacketLeader) +{ + UCHAR Index = 0, Byte, Buffer[4]; + KDP_STATUS KdStatus; + + /* Set first character to 0 */ + Buffer[0] = 0; + + do + { + /* Receive a single byte */ + KdStatus = KdpReceiveByte(&Byte); + + /* Check for timeout */ + if (KdStatus == KDP_PACKET_TIMEOUT) + { + /* Check if we already got a breakin byte */ + if (Buffer[0] == BREAKIN_PACKET_BYTE) + { + return KDP_PACKET_RESEND; + } + + /* Report timeout */ + return KDP_PACKET_TIMEOUT; + } + + /* Check if we received a byte */ + if (KdStatus == KDP_PACKET_RECEIVED) + { + /* Check if this is a valid packet leader byte */ + if (Byte == PACKET_LEADER_BYTE || + Byte == CONTROL_PACKET_LEADER_BYTE) + { + /* Check if we match the first byte */ + if (Byte != Buffer[0]) + { + /* No, this is the new byte 0! */ + Index = 0; + } + + /* Store the byte in the buffer */ + Buffer[Index] = Byte; + + /* Continue with next byte */ + Index++; + continue; + } + + /* Check for breakin byte */ + if (Byte == BREAKIN_PACKET_BYTE) + { + KdpDbgPrint("BREAKIN_PACKET_BYTE\n"); + Index = 0; + Buffer[0] = Byte; + continue; + } + } + + /* Restart */ + Index = 0; + Buffer[0] = 0; + } + while (Index < 4); + + /* Enable the debugger */ +// KdDebuggerNotPresent = FALSE; + SharedUserData->KdDebuggerEnabled |= 0x00000002; + + /* Return the received packet leader */ + *PacketLeader = *(PULONG)Buffer; + + return KDP_PACKET_RECEIVED; +} + diff --git a/reactos/include/reactos/windbgkd.h b/reactos/include/reactos/windbgkd.h index bc88bf590f1..38c6ae87df8 100644 --- a/reactos/include/reactos/windbgkd.h +++ b/reactos/include/reactos/windbgkd.h @@ -211,8 +211,8 @@ typedef struct _KD_PACKET // typedef struct _KD_CONTEXT { - ULONG KdpDefaultRetries; - BOOLEAN KdpControlCPending; + ULONG RetryCount; + BOOLEAN BreakInRequested; } KD_CONTEXT, *PKD_CONTEXT; // diff --git a/reactos/ntoskrnl/kd64/kdinit.c b/reactos/ntoskrnl/kd64/kdinit.c index e5c487c8a3b..1b1ac485fbf 100644 --- a/reactos/ntoskrnl/kd64/kdinit.c +++ b/reactos/ntoskrnl/kd64/kdinit.c @@ -284,7 +284,7 @@ KdInitSystem(IN ULONG BootPhase, if (!KdpDebuggerStructuresInitialized) { /* Set the Debug Switch Routine and Retries*/ - KdpContext.KdpDefaultRetries = 20; + KdpContext.RetryCount = 20; KiDebugSwitchRoutine = KdpSwitchProcessor; /* Initialize the Time Slip DPC */ diff --git a/reactos/ntoskrnl/kd64/kdlock.c b/reactos/ntoskrnl/kd64/kdlock.c index f332eb1c016..0afbbf61cb1 100644 --- a/reactos/ntoskrnl/kd64/kdlock.c +++ b/reactos/ntoskrnl/kd64/kdlock.c @@ -40,11 +40,11 @@ KdpPollBreakInWithPortLock(VOID) if (KdDebuggerEnabled) { /* Check if a CTRL-C is in the queue */ - if (KdpContext.KdpControlCPending) + if (KdpContext.BreakInRequested) { /* Set it and prepare for break */ DoBreak = TRUE; - KdpContext.KdpControlCPending = FALSE; + KdpContext.BreakInRequested = FALSE; } else { @@ -83,12 +83,12 @@ KdPollBreakIn(VOID) Enable = KeDisableInterrupts(); /* Check if a CTRL-C is in the queue */ - if (KdpContext.KdpControlCPending) + if (KdpContext.BreakInRequested) { /* Set it and prepare for break */ KdpControlCPressed = TRUE; DoBreak = TRUE; - KdpContext.KdpControlCPending = FALSE; + KdpContext.BreakInRequested = FALSE; } else {