We now also implement InterlockedExchange (Fixes rtl build).
[reactos.git] / reactos / drivers / base / kdcom / kdbg.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * FILE: drivers/base/kdcom/kdbg.c
5 * PURPOSE: Serial i/o functions for the kernel debugger.
6 * PROGRAMMER: Alex Ionescu
7 * Hervé Poussineau
8 */
9
10 /* INCLUDES *****************************************************************/
11
12 #define NOEXTAPI
13 #include <ntddk.h>
14 #define NDEBUG
15 #include <halfuncs.h>
16 #include <stdio.h>
17 #include <debug.h>
18 #include "arc/arc.h"
19 #include "windbgkd.h"
20 #include <kddll.h>
21
22 typedef struct _KD_PORT_INFORMATION
23 {
24 ULONG ComPort;
25 ULONG BaudRate;
26 ULONG BaseAddress;
27 } KD_PORT_INFORMATION, *PKD_PORT_INFORMATION;
28
29 BOOLEAN
30 NTAPI
31 KdPortInitializeEx(
32 IN PKD_PORT_INFORMATION PortInformation,
33 IN ULONG Unknown1,
34 IN ULONG Unknown2);
35
36 BOOLEAN
37 NTAPI
38 KdPortGetByteEx(
39 IN PKD_PORT_INFORMATION PortInformation,
40 OUT PUCHAR ByteReceived);
41
42 BOOLEAN
43 NTAPI
44 KdPortPollByteEx(
45 IN PKD_PORT_INFORMATION PortInformation,
46 OUT PUCHAR ByteReceived);
47
48 VOID
49 NTAPI
50 KdPortPutByteEx(
51 IN PKD_PORT_INFORMATION PortInformation,
52 IN UCHAR ByteToSend);
53
54 #define DEFAULT_BAUD_RATE 19200
55
56 #ifdef _M_IX86
57 const ULONG BaseArray[5] = {0, 0x3F8, 0x2F8, 0x3E8, 0x2E8};
58 #elif defined(_M_PPC)
59 const ULONG BaseArray[2] = {0, 0x800003f8};
60 #elif defined(_M_MIPS)
61 const ULONG BaseArray[3] = {0, 0x80006000, 0x80007000};
62 #elif defined(_M_ARM)
63 const ULONG BaseArray[2] = {0, 0xF1012000};
64 #else
65 #error Unknown architecture
66 #endif
67
68 /* MACROS *******************************************************************/
69
70 #define SER_RBR(x) ((PUCHAR)(x)+0)
71 #define SER_THR(x) ((PUCHAR)(x)+0)
72 #define SER_DLL(x) ((PUCHAR)(x)+0)
73 #define SER_IER(x) ((PUCHAR)(x)+1)
74 #define SR_IER_ERDA 0x01
75 #define SR_IER_ETHRE 0x02
76 #define SR_IER_ERLSI 0x04
77 #define SR_IER_EMS 0x08
78 #define SR_IER_ALL 0x0F
79 #define SER_DLM(x) ((PUCHAR)(x)+1)
80 #define SER_IIR(x) ((PUCHAR)(x)+2)
81 #define SER_FCR(x) ((PUCHAR)(x)+2)
82 #define SR_FCR_ENABLE_FIFO 0x01
83 #define SR_FCR_CLEAR_RCVR 0x02
84 #define SR_FCR_CLEAR_XMIT 0x04
85 #define SER_LCR(x) ((PUCHAR)(x)+3)
86 #define SR_LCR_CS5 0x00
87 #define SR_LCR_CS6 0x01
88 #define SR_LCR_CS7 0x02
89 #define SR_LCR_CS8 0x03
90 #define SR_LCR_ST1 0x00
91 #define SR_LCR_ST2 0x04
92 #define SR_LCR_PNO 0x00
93 #define SR_LCR_POD 0x08
94 #define SR_LCR_PEV 0x18
95 #define SR_LCR_PMK 0x28
96 #define SR_LCR_PSP 0x38
97 #define SR_LCR_BRK 0x40
98 #define SR_LCR_DLAB 0x80
99 #define SER_MCR(x) ((PUCHAR)(x)+4)
100 #define SR_MCR_DTR 0x01
101 #define SR_MCR_RTS 0x02
102 #define SR_MCR_OUT1 0x04
103 #define SR_MCR_OUT2 0x08
104 #define SR_MCR_LOOP 0x10
105 #define SER_LSR(x) ((PUCHAR)(x)+5)
106 #define SR_LSR_DR 0x01
107 #define SR_LSR_TBE 0x20
108 #define SER_MSR(x) ((PUCHAR)(x)+6)
109 #define SR_MSR_CTS 0x10
110 #define SR_MSR_DSR 0x20
111 #define SER_SCR(x) ((PUCHAR)(x)+7)
112
113
114 /* GLOBAL VARIABLES *********************************************************/
115
116 /* STATIC VARIABLES *********************************************************/
117
118 static KD_PORT_INFORMATION DefaultPort = { 0, 0, 0 };
119
120 /* The com port must only be initialized once! */
121 static BOOLEAN PortInitialized = FALSE;
122
123
124 /* STATIC FUNCTIONS *********************************************************/
125
126 static BOOLEAN
127 KdpDoesComPortExist(
128 IN ULONG BaseAddress)
129 {
130 BOOLEAN found;
131 UCHAR mcr;
132 UCHAR msr;
133
134 found = FALSE;
135
136 /* save Modem Control Register (MCR) */
137 mcr = READ_PORT_UCHAR(SER_MCR(BaseAddress));
138
139 /* enable loop mode (set Bit 4 of the MCR) */
140 WRITE_PORT_UCHAR(SER_MCR(BaseAddress), SR_MCR_LOOP);
141
142 /* clear all modem output bits */
143 WRITE_PORT_UCHAR(SER_MCR(BaseAddress), SR_MCR_LOOP);
144
145 /* read the Modem Status Register */
146 msr = READ_PORT_UCHAR(SER_MSR(BaseAddress));
147
148 /*
149 * the upper nibble of the MSR (modem output bits) must be
150 * equal to the lower nibble of the MCR (modem input bits)
151 */
152 if ((msr & 0xF0) == 0x00)
153 {
154 /* set all modem output bits */
155 WRITE_PORT_UCHAR(SER_MCR(BaseAddress), SR_MCR_DTR | SR_MCR_RTS | SR_MCR_OUT1 | SR_MCR_OUT2 | SR_MCR_LOOP);
156
157 /* read the Modem Status Register */
158 msr = READ_PORT_UCHAR(SER_MSR(BaseAddress));
159
160 /*
161 * the upper nibble of the MSR (modem output bits) must be
162 * equal to the lower nibble of the MCR (modem input bits)
163 */
164 if ((msr & 0xF0) == 0xF0)
165 {
166 /*
167 * setup a resonable state for the port:
168 * enable fifo and clear recieve/transmit buffers
169 */
170 WRITE_PORT_UCHAR(SER_FCR(BaseAddress),
171 (SR_FCR_ENABLE_FIFO | SR_FCR_CLEAR_RCVR | SR_FCR_CLEAR_XMIT));
172 WRITE_PORT_UCHAR(SER_FCR(BaseAddress), 0);
173 READ_PORT_UCHAR(SER_RBR(BaseAddress));
174 WRITE_PORT_UCHAR(SER_IER(BaseAddress), 0);
175 found = TRUE;
176 }
177 }
178
179 /* restore MCR */
180 WRITE_PORT_UCHAR(SER_MCR(BaseAddress), mcr);
181
182 return found;
183 }
184
185
186 /* FUNCTIONS ****************************************************************/
187
188 /* HAL.KdPortInitialize */
189 BOOLEAN
190 NTAPI
191 KdPortInitialize(
192 IN PKD_PORT_INFORMATION PortInformation,
193 IN ULONG Unknown1,
194 IN ULONG Unknown2)
195 {
196 SIZE_T i;
197 CHAR buffer[80];
198
199 if (!PortInitialized)
200 {
201 DefaultPort.BaudRate = PortInformation->BaudRate;
202
203 if (PortInformation->ComPort == 0)
204 {
205 for (i = sizeof(BaseArray) / sizeof(BaseArray[0]) - 1; i > 0; i--)
206 {
207 if (KdpDoesComPortExist(BaseArray[i]))
208 {
209 DefaultPort.BaseAddress = BaseArray[i];
210 DefaultPort.ComPort = i;
211 PortInformation->BaseAddress = DefaultPort.BaseAddress;
212 PortInformation->ComPort = DefaultPort.ComPort;
213 break;
214 }
215 }
216 if (i == 0)
217 {
218 sprintf(buffer,
219 "\nKernel Debugger: No COM port found!\n\n");
220 HalDisplayString(buffer);
221 return FALSE;
222 }
223 }
224
225 PortInitialized = TRUE;
226 }
227
228 /* initialize port */
229 if (!KdPortInitializeEx(&DefaultPort, Unknown1, Unknown2))
230 return FALSE;
231
232 /* set global info */
233 *KdComPortInUse = (PUCHAR)DefaultPort.BaseAddress;
234
235 return TRUE;
236 }
237
238
239 /* HAL.KdPortInitializeEx */
240 BOOLEAN
241 NTAPI
242 KdPortInitializeEx(
243 IN PKD_PORT_INFORMATION PortInformation,
244 IN ULONG Unknown1,
245 IN ULONG Unknown2)
246 {
247 ULONG ComPortBase;
248 CHAR buffer[80];
249 ULONG divisor;
250 UCHAR lcr;
251
252 if (PortInformation->BaudRate == 0)
253 PortInformation->BaudRate = DEFAULT_BAUD_RATE;
254
255 if (PortInformation->ComPort == 0)
256 return FALSE;
257
258 if (!KdpDoesComPortExist(BaseArray[PortInformation->ComPort]))
259 {
260 sprintf(buffer,
261 "\nKernel Debugger: Serial port not found!\n\n");
262 HalDisplayString(buffer);
263 return FALSE;
264 }
265
266 ComPortBase = BaseArray[PortInformation->ComPort];
267 PortInformation->BaseAddress = ComPortBase;
268 #ifndef NDEBUG
269 sprintf(buffer,
270 "\nSerial port COM%ld found at 0x%lx\n",
271 PortInformation->ComPort,
272 ComPortBase];
273 HalDisplayString(buffer);
274 #endif /* NDEBUG */
275
276 /* set baud rate and data format (8N1) */
277
278 /* turn on DTR and RTS */
279 WRITE_PORT_UCHAR(SER_MCR(ComPortBase), SR_MCR_DTR | SR_MCR_RTS);
280
281 /* set DLAB */
282 lcr = READ_PORT_UCHAR(SER_LCR(ComPortBase)) | SR_LCR_DLAB;
283 WRITE_PORT_UCHAR(SER_LCR(ComPortBase), lcr);
284
285 /* set baud rate */
286 divisor = 115200 / PortInformation->BaudRate;
287 WRITE_PORT_UCHAR(SER_DLL(ComPortBase), (UCHAR)(divisor & 0xff));
288 WRITE_PORT_UCHAR(SER_DLM(ComPortBase), (UCHAR)((divisor >> 8) & 0xff));
289
290 /* reset DLAB and set 8N1 format */
291 WRITE_PORT_UCHAR(SER_LCR(ComPortBase),
292 SR_LCR_CS8 | SR_LCR_ST1 | SR_LCR_PNO);
293
294 /* read junk out of the RBR */
295 lcr = READ_PORT_UCHAR(SER_RBR(ComPortBase));
296
297 #ifndef NDEBUG
298 /* print message to blue screen */
299 sprintf(buffer,
300 "\nKernel Debugger: COM%ld (Port 0x%lx) BaudRate %ld\n\n",
301 PortInformation->ComPort,
302 ComPortBase,
303 PortInformation->BaudRate);
304
305 HalDisplayString(buffer);
306 #endif /* NDEBUG */
307
308 return TRUE;
309 }
310
311
312 /* HAL.KdPortGetByte */
313 BOOLEAN
314 NTAPI
315 KdPortGetByte(
316 OUT PUCHAR ByteReceived)
317 {
318 if (!PortInitialized)
319 return FALSE;
320 return KdPortGetByteEx(&DefaultPort, ByteReceived);
321 }
322
323
324 /* HAL.KdPortGetByteEx */
325 BOOLEAN
326 NTAPI
327 KdPortGetByteEx(
328 IN PKD_PORT_INFORMATION PortInformation,
329 OUT PUCHAR ByteReceived)
330 {
331 PUCHAR ComPortBase = (PUCHAR)PortInformation->BaseAddress;
332
333 if ((READ_PORT_UCHAR(SER_LSR(ComPortBase)) & SR_LSR_DR))
334 {
335 *ByteReceived = READ_PORT_UCHAR(SER_RBR(ComPortBase));
336 return TRUE;
337 }
338
339 return FALSE;
340 }
341
342
343 /* HAL.KdPortPollByte */
344 BOOLEAN
345 NTAPI
346 KdPortPollByte(
347 OUT PUCHAR ByteReceived)
348 {
349 if (!PortInitialized)
350 return FALSE;
351 return KdPortPollByteEx(&DefaultPort, ByteReceived);
352 }
353
354
355 /* HAL.KdPortPollByteEx */
356 BOOLEAN
357 NTAPI
358 KdPortPollByteEx(
359 IN PKD_PORT_INFORMATION PortInformation,
360 OUT PUCHAR ByteReceived)
361 {
362 PUCHAR ComPortBase = (PUCHAR)PortInformation->BaseAddress;
363
364 while ((READ_PORT_UCHAR(SER_LSR(ComPortBase)) & SR_LSR_DR) == 0)
365 ;
366
367 *ByteReceived = READ_PORT_UCHAR(SER_RBR(ComPortBase));
368
369 return TRUE;
370 }
371
372
373 /* HAL.KdPortPutByte */
374 VOID
375 NTAPI
376 KdPortPutByte(
377 IN UCHAR ByteToSend)
378 {
379 if (!PortInitialized)
380 return;
381 KdPortPutByteEx(&DefaultPort, ByteToSend);
382 }
383
384 /* HAL.KdPortPutByteEx */
385 VOID
386 NTAPI
387 KdPortPutByteEx(
388 IN PKD_PORT_INFORMATION PortInformation,
389 IN UCHAR ByteToSend)
390 {
391 PUCHAR ComPortBase = (PUCHAR)PortInformation->BaseAddress;
392
393 while ((READ_PORT_UCHAR(SER_LSR(ComPortBase)) & SR_LSR_TBE) == 0)
394 ;
395
396 WRITE_PORT_UCHAR(SER_THR(ComPortBase), ByteToSend);
397 }
398
399
400 /* HAL.KdPortRestore */
401 VOID
402 NTAPI
403 KdPortRestore(VOID)
404 {
405 UNIMPLEMENTED;
406 }
407
408
409 /* HAL.KdPortSave */
410 VOID
411 NTAPI
412 KdPortSave(VOID)
413 {
414 UNIMPLEMENTED;
415 }
416
417
418 /* HAL.KdPortDisableInterrupts */
419 BOOLEAN
420 NTAPI
421 KdPortDisableInterrupts(VOID)
422 {
423 UCHAR ch;
424
425 if (!PortInitialized)
426 return FALSE;
427
428 ch = READ_PORT_UCHAR(SER_MCR(DefaultPort.BaseAddress));
429 ch &= (~(SR_MCR_OUT1 | SR_MCR_OUT2));
430 WRITE_PORT_UCHAR(SER_MCR(DefaultPort.BaseAddress), ch);
431
432 ch = READ_PORT_UCHAR(SER_IER(DefaultPort.BaseAddress));
433 ch &= (~SR_IER_ALL);
434 WRITE_PORT_UCHAR(SER_IER(DefaultPort.BaseAddress), ch);
435
436 return TRUE;
437 }
438
439
440 /* HAL.KdPortEnableInterrupts */
441 BOOLEAN
442 NTAPI
443 KdPortEnableInterrupts(VOID)
444 {
445 UCHAR ch;
446
447 if (PortInitialized == FALSE)
448 return FALSE;
449
450 ch = READ_PORT_UCHAR(SER_IER(DefaultPort.BaseAddress));
451 ch &= (~SR_IER_ALL);
452 ch |= SR_IER_ERDA;
453 WRITE_PORT_UCHAR(SER_IER(DefaultPort.BaseAddress), ch);
454
455 ch = READ_PORT_UCHAR(SER_MCR(DefaultPort.BaseAddress));
456 ch &= (~SR_MCR_LOOP);
457 ch |= (SR_MCR_OUT1 | SR_MCR_OUT2);
458 WRITE_PORT_UCHAR(SER_MCR(DefaultPort.BaseAddress), ch);
459
460 return TRUE;
461 }
462
463 /*
464 * @unimplemented
465 */
466 NTSTATUS
467 NTAPI
468 KdDebuggerInitialize0(
469 IN PLOADER_PARAMETER_BLOCK LoaderBlock OPTIONAL)
470 {
471 UNIMPLEMENTED;
472 return STATUS_NOT_IMPLEMENTED;
473 }
474
475 /*
476 * @unimplemented
477 */
478 NTSTATUS
479 NTAPI
480 KdDebuggerInitialize1(
481 IN PLOADER_PARAMETER_BLOCK LoaderBlock OPTIONAL)
482 {
483 UNIMPLEMENTED;
484 return STATUS_NOT_IMPLEMENTED;
485 }
486
487 /*
488 * @implemented
489 */
490 NTSTATUS
491 NTAPI
492 KdSave(
493 IN BOOLEAN SleepTransition)
494 {
495 /* Nothing to do on COM ports */
496 return STATUS_SUCCESS;
497 }
498
499 /*
500 * @implemented
501 */
502 NTSTATUS
503 NTAPI
504 KdRestore(
505 IN BOOLEAN SleepTransition)
506 {
507 /* Nothing to do on COM ports */
508 return STATUS_SUCCESS;
509 }
510
511 /*
512 * @unimplemented
513 */
514 VOID
515 NTAPI
516 KdSendPacket(
517 IN ULONG PacketType,
518 IN PSTRING MessageHeader,
519 IN PSTRING MessageData,
520 IN OUT PKD_CONTEXT Context)
521 {
522 UNIMPLEMENTED;
523 return;
524 }
525
526 /*
527 * @unimplemented
528 */
529 KDSTATUS
530 NTAPI
531 KdReceivePacket(
532 IN ULONG PacketType,
533 OUT PSTRING MessageHeader,
534 OUT PSTRING MessageData,
535 OUT PULONG DataLength,
536 IN OUT PKD_CONTEXT Context)
537 {
538 UNIMPLEMENTED;
539 return 0;
540 }
541
542 /* EOF */