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