mirror of
https://github.com/reactos/reactos.git
synced 2026-07-02 00:54:22 +08:00
This is the same feature as the one that already exists in the NTOS:KD!kdmain.c module used by the in-kernel KDBG debugger (GCC builds), first introduced in commit4ce30245de(r54473), and documented at: https://reactos.org/wiki/Debugging#Changing_the_serial_port_address This feature is useful if one uses a PCI, PCIe, PCMCIA, or ExpressCard serial card on real hardware (these cards are used e.g. with laptops without a built-in serial port), or with AMT serial over LAN. After determining the serial port I/O address (say, 0xCC00), specify the debug port as follows: /DEBUGPORT=COM:0xCC00 instead of the usual syntax: /DEBUGPORT=COMn (n an integer). The same syntax can be used for debugging FreeLoader as well: in the FREELDR.INI file, add a "Debug" line in the "FREELOADER" section, as follows: ``` [FREELOADER] Debug=/DEBUG /DEBUGPORT=COM:0xCC00 /BAUDRATE=115200 ``` ---- NOTE for KDCOM/KDGDB: Since `strtoul()` is used, but isn't exported by ntoskrnl, link against the "strtol" static library that has been introduced in commitd317d4fbcc(r71481).
310 lines
7.2 KiB
C
310 lines
7.2 KiB
C
/*
|
|
* COPYRIGHT: GPL, see COPYING in the top level directory
|
|
* PROJECT: ReactOS kernel
|
|
* FILE: drivers/base/kdcom/kdcom.c
|
|
* PURPOSE: COM port functions for the kernel debugger.
|
|
* PROGRAMMER: Timo Kreuzer (timo.kreuzer@reactos.org)
|
|
*/
|
|
|
|
#include "kddll.h"
|
|
|
|
#include <arc/arc.h>
|
|
#include <stdlib.h>
|
|
#include <ndk/halfuncs.h>
|
|
|
|
#include <cportlib/cportlib.h>
|
|
#include <cportlib/uartinfo.h>
|
|
|
|
/* GLOBALS ********************************************************************/
|
|
|
|
CPPORT KdComPort;
|
|
#ifdef KDDEBUG
|
|
CPPORT KdDebugComPort;
|
|
#endif
|
|
|
|
/* DEBUGGING ******************************************************************/
|
|
|
|
#ifdef KDDEBUG
|
|
#include <stdio.h>
|
|
ULONG KdpDbgPrint(const char *Format, ...)
|
|
{
|
|
va_list ap;
|
|
int Length;
|
|
char* ptr;
|
|
CHAR Buffer[512];
|
|
|
|
va_start(ap, Format);
|
|
Length = _vsnprintf(Buffer, sizeof(Buffer), Format, ap);
|
|
va_end(ap);
|
|
|
|
/* Check if we went past the buffer */
|
|
if (Length == -1)
|
|
{
|
|
/* Terminate it if we went over-board */
|
|
Buffer[sizeof(Buffer) - 1] = '\n';
|
|
|
|
/* Put maximum */
|
|
Length = sizeof(Buffer);
|
|
}
|
|
|
|
ptr = Buffer;
|
|
while (Length--)
|
|
{
|
|
if (*ptr == '\n')
|
|
CpPutByte(&KdDebugComPort, '\r');
|
|
|
|
CpPutByte(&KdDebugComPort, *ptr++);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
#endif
|
|
|
|
/* FUNCTIONS ******************************************************************/
|
|
|
|
NTSTATUS
|
|
NTAPI
|
|
KdD0Transition(VOID)
|
|
{
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
NTSTATUS
|
|
NTAPI
|
|
KdD3Transition(VOID)
|
|
{
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
NTSTATUS
|
|
NTAPI
|
|
KdpPortInitialize(
|
|
_In_ PUCHAR PortAddress,
|
|
_In_ ULONG BaudRate)
|
|
{
|
|
NTSTATUS Status;
|
|
|
|
Status = CpInitialize(&KdComPort, PortAddress, BaudRate);
|
|
if (!NT_SUCCESS(Status))
|
|
return STATUS_INVALID_PARAMETER;
|
|
|
|
KdComPortInUse = KdComPort.Address;
|
|
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)
|
|
{
|
|
#define CONST_STR_LEN(x) (sizeof(x)/sizeof(x[0]) - 1)
|
|
|
|
ULONG ComPortNumber = DEFAULT_DEBUG_PORT;
|
|
ULONG ComPortBaudRate = DEFAULT_DEBUG_BAUD_RATE;
|
|
PUCHAR ComPortAddress = NULL;
|
|
|
|
PSTR CommandLine, PortString, BaudString;
|
|
ULONG Value;
|
|
|
|
/* Check if we 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");
|
|
|
|
/* Check if we got the DEBUGPORT parameter */
|
|
if (PortString)
|
|
{
|
|
/* Move past the actual string and any spaces */
|
|
PortString += CONST_STR_LEN("DEBUGPORT");
|
|
while (*PortString == ' ') ++PortString;
|
|
/* Skip the equals sign */
|
|
if (*PortString) ++PortString;
|
|
|
|
/* Do we have a serial port? */
|
|
if (_strnicmp(PortString, "COM", CONST_STR_LEN("COM")) != 0)
|
|
return STATUS_INVALID_PARAMETER;
|
|
|
|
/* Check for a valid serial port */
|
|
PortString += CONST_STR_LEN("COM");
|
|
if (*PortString != ':')
|
|
{
|
|
Value = (ULONG)atol(PortString);
|
|
if (Value > MAX_COM_PORTS)
|
|
return STATUS_INVALID_PARAMETER;
|
|
// if (Value > 0 && Value <= MAX_COM_PORTS)
|
|
/* Set the port to use */
|
|
ComPortNumber = Value;
|
|
}
|
|
else
|
|
{
|
|
/* Retrieve and set its address */
|
|
Value = strtoul(PortString + 1, NULL, 0);
|
|
if (Value)
|
|
{
|
|
ComPortNumber = 0;
|
|
ComPortAddress = UlongToPtr(Value);
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Check if we got a baud rate */
|
|
if (BaudString)
|
|
{
|
|
/* Move past the actual string and any spaces */
|
|
BaudString += CONST_STR_LEN("BAUDRATE");
|
|
while (*BaudString == ' ') ++BaudString;
|
|
|
|
/* Make sure we have a rate */
|
|
if (*BaudString)
|
|
{
|
|
/* Read and set it */
|
|
Value = (ULONG)atol(BaudString + 1);
|
|
if (Value) ComPortBaudRate = Value;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!ComPortAddress)
|
|
ComPortAddress = UlongToPtr(BaseArray[ComPortNumber]);
|
|
|
|
#ifdef KDDEBUG
|
|
/*
|
|
* Try to find a free COM port and use it as the KD debugging port.
|
|
* NOTE: Inspired by freeldr/comm/rs232.c, Rs232PortInitialize(...)
|
|
*/
|
|
{
|
|
/*
|
|
* Enumerate COM ports from the last to the first one, and stop
|
|
* when we find a valid port. If we reach the first list element
|
|
* (the undefined COM port), no valid port was found.
|
|
*/
|
|
PUCHAR Address = NULL;
|
|
ULONG ComPort;
|
|
for (ComPort = MAX_COM_PORTS; ComPort > 0; ComPort--)
|
|
{
|
|
/* Check if the port exist; skip the KD port */
|
|
Address = UlongToPtr(BaseArray[ComPort]);
|
|
if ((Address != ComPortAddress) && CpDoesPortExist(Address))
|
|
break;
|
|
}
|
|
if (ComPort != 0 && Address != NULL)
|
|
CpInitialize(&KdDebugComPort, Address, DEFAULT_BAUD_RATE);
|
|
}
|
|
#endif
|
|
|
|
/* Initialize the port */
|
|
return KdpPortInitialize(ComPortAddress, ComPortBaudRate);
|
|
}
|
|
|
|
/******************************************************************************
|
|
* \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)
|
|
{
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
|
|
VOID
|
|
NTAPI
|
|
KdpSendByte(IN UCHAR Byte)
|
|
{
|
|
/* Send the byte */
|
|
CpPutByte(&KdComPort, Byte);
|
|
}
|
|
|
|
KDP_STATUS
|
|
NTAPI
|
|
KdpPollByte(OUT PUCHAR OutByte)
|
|
{
|
|
USHORT Status;
|
|
|
|
/* Poll the byte */
|
|
Status = CpGetByte(&KdComPort, OutByte, FALSE, FALSE);
|
|
switch (Status)
|
|
{
|
|
case CP_GET_SUCCESS:
|
|
return KDP_PACKET_RECEIVED;
|
|
|
|
case CP_GET_NODATA:
|
|
return KDP_PACKET_TIMEOUT;
|
|
|
|
case CP_GET_ERROR:
|
|
default:
|
|
return KDP_PACKET_RESEND;
|
|
}
|
|
}
|
|
|
|
KDP_STATUS
|
|
NTAPI
|
|
KdpReceiveByte(OUT PUCHAR OutByte)
|
|
{
|
|
USHORT Status;
|
|
|
|
/* Get the byte */
|
|
Status = CpGetByte(&KdComPort, OutByte, TRUE, FALSE);
|
|
switch (Status)
|
|
{
|
|
case CP_GET_SUCCESS:
|
|
return KDP_PACKET_RECEIVED;
|
|
|
|
case CP_GET_NODATA:
|
|
return KDP_PACKET_TIMEOUT;
|
|
|
|
case CP_GET_ERROR:
|
|
default:
|
|
return KDP_PACKET_RESEND;
|
|
}
|
|
}
|
|
|
|
KDP_STATUS
|
|
NTAPI
|
|
KdpPollBreakIn(VOID)
|
|
{
|
|
KDP_STATUS KdStatus;
|
|
UCHAR Byte;
|
|
|
|
KdStatus = KdpPollByte(&Byte);
|
|
if ((KdStatus == KDP_PACKET_RECEIVED) && (Byte == BREAKIN_PACKET_BYTE))
|
|
{
|
|
return KDP_PACKET_RECEIVED;
|
|
}
|
|
return KDP_PACKET_TIMEOUT;
|
|
}
|
|
|
|
/* EOF */
|