1 /* 2 * COPYRIGHT: GPL, see COPYING in the top level directory 3 * PROJECT: ReactOS kernel 4 * FILE: drivers/base/kdgdb/kdcom.c 5 * PURPOSE: COM port functions for the kernel debugger. 6 */ 7 8 #include "kdgdb.h" 9 10 #include <cportlib/cportlib.h> 11 #include <arc/arc.h> 12 #include <stdlib.h> 13 #include <ndk/halfuncs.h> 14 15 /* Serial debug connection */ 16 #define DEFAULT_DEBUG_PORT 2 /* COM2 */ 17 #define DEFAULT_DEBUG_COM1_IRQ 4 /* COM1 IRQ */ 18 #define DEFAULT_DEBUG_COM2_IRQ 3 /* COM2 IRQ */ 19 #define DEFAULT_DEBUG_BAUD_RATE 115200 /* 115200 Baud */ 20 21 #define DEFAULT_BAUD_RATE 19200 22 23 #if defined(_M_IX86) || defined(_M_AMD64) 24 #if defined(SARCH_PC98) 25 const ULONG BaseArray[] = {0, 0x30, 0x238}; 26 #else 27 const ULONG BaseArray[] = {0, 0x3F8, 0x2F8, 0x3E8, 0x2E8}; 28 #endif 29 #elif defined(_M_PPC) 30 const ULONG BaseArray[] = {0, 0x800003F8}; 31 #elif defined(_M_MIPS) 32 const ULONG BaseArray[] = {0, 0x80006000, 0x80007000}; 33 #elif defined(_M_ARM) 34 const ULONG BaseArray[] = {0, 0xF1012000}; 35 #else 36 #error Unknown architecture 37 #endif 38 39 #define MAX_COM_PORTS (sizeof(BaseArray) / sizeof(BaseArray[0]) - 1) 40 41 /* GLOBALS ********************************************************************/ 42 43 CPPORT KdComPort; 44 ULONG KdComPortIrq = 0; // Not used at the moment. 45 #ifdef KDDEBUG 46 CPPORT KdDebugComPort; 47 #endif 48 49 /* DEBUGGING ******************************************************************/ 50 51 #ifdef KDDEBUG 52 ULONG KdpDbgPrint(const char *Format, ...) 53 { 54 va_list ap; 55 int Length; 56 char* ptr; 57 CHAR Buffer[512]; 58 59 va_start(ap, Format); 60 Length = _vsnprintf(Buffer, sizeof(Buffer), Format, ap); 61 va_end(ap); 62 63 /* Check if we went past the buffer */ 64 if (Length == -1) 65 { 66 /* Terminate it if we went over-board */ 67 Buffer[sizeof(Buffer) - 1] = '\n'; 68 69 /* Put maximum */ 70 Length = sizeof(Buffer); 71 } 72 73 ptr = Buffer; 74 while (Length--) 75 { 76 if (*ptr == '\n') 77 CpPutByte(&KdDebugComPort, '\r'); 78 79 CpPutByte(&KdDebugComPort, *ptr++); 80 } 81 82 return 0; 83 } 84 #endif 85 86 /* FUNCTIONS ******************************************************************/ 87 88 NTSTATUS 89 NTAPI 90 KdD0Transition(VOID) 91 { 92 return STATUS_SUCCESS; 93 } 94 95 NTSTATUS 96 NTAPI 97 KdD3Transition(VOID) 98 { 99 return STATUS_SUCCESS; 100 } 101 102 NTSTATUS 103 NTAPI 104 KdSave(IN BOOLEAN SleepTransition) 105 { 106 /* Nothing to do on COM ports */ 107 return STATUS_SUCCESS; 108 } 109 110 NTSTATUS 111 NTAPI 112 KdRestore(IN BOOLEAN SleepTransition) 113 { 114 /* Nothing to do on COM ports */ 115 return STATUS_SUCCESS; 116 } 117 118 NTSTATUS 119 NTAPI 120 KdpPortInitialize(IN ULONG ComPortNumber, 121 IN ULONG ComPortBaudRate) 122 { 123 NTSTATUS Status; 124 125 Status = CpInitialize(&KdComPort, 126 UlongToPtr(BaseArray[ComPortNumber]), 127 ComPortBaudRate); 128 if (!NT_SUCCESS(Status)) 129 { 130 return STATUS_INVALID_PARAMETER; 131 } 132 133 KdComPortInUse = KdComPort.Address; 134 return STATUS_SUCCESS; 135 } 136 137 /****************************************************************************** 138 * \name KdDebuggerInitialize0 139 * \brief Phase 0 initialization. 140 * \param [opt] LoaderBlock Pointer to the Loader parameter block. Can be NULL. 141 * \return Status 142 */ 143 NTSTATUS 144 NTAPI 145 KdDebuggerInitialize0(IN PLOADER_PARAMETER_BLOCK LoaderBlock OPTIONAL) 146 { 147 ULONG ComPortNumber = DEFAULT_DEBUG_PORT; 148 ULONG ComPortBaudRate = DEFAULT_DEBUG_BAUD_RATE; 149 150 PCHAR CommandLine, PortString, BaudString, IrqString; 151 ULONG Value; 152 153 /* Check if we have a LoaderBlock */ 154 if (LoaderBlock) 155 { 156 /* Get the Command Line */ 157 CommandLine = LoaderBlock->LoadOptions; 158 159 /* Upcase it */ 160 _strupr(CommandLine); 161 162 /* Get the port and baud rate */ 163 PortString = strstr(CommandLine, "DEBUGPORT"); 164 BaudString = strstr(CommandLine, "BAUDRATE"); 165 IrqString = strstr(CommandLine, "IRQ"); 166 167 /* Check if we got the /DEBUGPORT parameter */ 168 if (PortString) 169 { 170 /* Move past the actual string, to reach the port*/ 171 PortString += strlen("DEBUGPORT"); 172 173 /* Now get past any spaces and skip the equal sign */ 174 while (*PortString == ' ') PortString++; 175 PortString++; 176 177 /* Do we have a serial port? */ 178 if (strncmp(PortString, "COM", 3) != 0) 179 { 180 return STATUS_INVALID_PARAMETER; 181 } 182 183 /* Check for a valid Serial Port */ 184 PortString += 3; 185 Value = atol(PortString); 186 if (Value >= sizeof(BaseArray) / sizeof(BaseArray[0])) 187 { 188 return STATUS_INVALID_PARAMETER; 189 } 190 191 /* Set the port to use */ 192 ComPortNumber = Value; 193 } 194 195 /* Check if we got a baud rate */ 196 if (BaudString) 197 { 198 /* Move past the actual string, to reach the rate */ 199 BaudString += strlen("BAUDRATE"); 200 201 /* Now get past any spaces */ 202 while (*BaudString == ' ') BaudString++; 203 204 /* And make sure we have a rate */ 205 if (*BaudString) 206 { 207 /* Read and set it */ 208 Value = atol(BaudString + 1); 209 if (Value) ComPortBaudRate = Value; 210 } 211 } 212 213 /* Check Serial Port Settings [IRQ] */ 214 if (IrqString) 215 { 216 /* Move past the actual string, to reach the rate */ 217 IrqString += strlen("IRQ"); 218 219 /* Now get past any spaces */ 220 while (*IrqString == ' ') IrqString++; 221 222 /* And make sure we have an IRQ */ 223 if (*IrqString) 224 { 225 /* Read and set it */ 226 Value = atol(IrqString + 1); 227 if (Value) KdComPortIrq = Value; 228 } 229 } 230 } 231 232 #ifdef KDDEBUG 233 /* 234 * Try to find a free COM port and use it as the KD debugging port. 235 * NOTE: Inspired by reactos/boot/freeldr/freeldr/comm/rs232.c, Rs232PortInitialize(...) 236 */ 237 { 238 /* 239 * Start enumerating COM ports from the last one to the first one, 240 * and break when we find a valid port. 241 * If we reach the first element of the list, the invalid COM port, 242 * then it means that no valid port was found. 243 */ 244 ULONG ComPort; 245 for (ComPort = MAX_COM_PORTS; ComPort > 0; ComPort--) 246 { 247 /* Check if the port exist; skip the KD port */ 248 if ((ComPort != ComPortNumber) && CpDoesPortExist(UlongToPtr(BaseArray[ComPort]))) 249 break; 250 } 251 if (ComPort != 0) 252 CpInitialize(&KdDebugComPort, UlongToPtr(BaseArray[ComPort]), DEFAULT_BAUD_RATE); 253 } 254 #endif 255 256 /* Initialize the port */ 257 return KdpPortInitialize(ComPortNumber, ComPortBaudRate); 258 } 259 260 /****************************************************************************** 261 * \name KdDebuggerInitialize1 262 * \brief Phase 1 initialization. 263 * \param [opt] LoaderBlock Pointer to the Loader parameter block. Can be NULL. 264 * \return Status 265 */ 266 NTSTATUS 267 NTAPI 268 KdDebuggerInitialize1(IN PLOADER_PARAMETER_BLOCK LoaderBlock OPTIONAL) 269 { 270 return STATUS_SUCCESS; 271 } 272 273 274 VOID 275 NTAPI 276 KdpSendByte(_In_ UCHAR Byte) 277 { 278 /* Send the byte */ 279 CpPutByte(&KdComPort, Byte); 280 } 281 282 KDSTATUS 283 NTAPI 284 KdpPollByte(OUT PUCHAR OutByte) 285 { 286 /* Poll the byte */ 287 if (CpGetByte(&KdComPort, OutByte, FALSE, FALSE) == CP_GET_SUCCESS) 288 { 289 return KdPacketReceived; 290 } 291 else 292 { 293 return KdPacketTimedOut; 294 } 295 } 296 297 KDSTATUS 298 NTAPI 299 KdpReceiveByte(_Out_ PUCHAR OutByte) 300 { 301 USHORT CpStatus; 302 303 do 304 { 305 CpStatus = CpGetByte(&KdComPort, OutByte, TRUE, FALSE); 306 } while (CpStatus == CP_GET_NODATA); 307 308 /* Get the byte */ 309 if (CpStatus == CP_GET_SUCCESS) 310 { 311 return KdPacketReceived; 312 } 313 314 return KdPacketTimedOut; 315 } 316 317 KDSTATUS 318 NTAPI 319 KdpPollBreakIn(VOID) 320 { 321 KDSTATUS KdStatus; 322 UCHAR Byte; 323 324 KdStatus = KdpPollByte(&Byte); 325 if (KdStatus == KdPacketReceived) 326 { 327 if (Byte == 0x03) 328 { 329 KDDBGPRINT("BreakIn Polled.\n"); 330 return KdPacketReceived; 331 } 332 else if (Byte == '$') 333 { 334 /* GDB tried to send a new packet. N-ack it. */ 335 KdpSendByte('-'); 336 } 337 } 338 return KdPacketTimedOut; 339 } 340 341 /* EOF */ 342