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