xref: /reactos/drivers/base/kdgdb/kdcom.c (revision 37b2c145)
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