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
11 /* INCLUDES *****************************************************************/
23 #include <ioaccess.h> /* port intrinsics */
25 typedef struct _KD_PORT_INFORMATION
29 ULONG_PTR BaseAddress
;
30 } KD_PORT_INFORMATION
, *PKD_PORT_INFORMATION
;
35 IN PKD_PORT_INFORMATION PortInformation
,
42 IN PKD_PORT_INFORMATION PortInformation
,
43 OUT PUCHAR ByteReceived
);
48 IN PKD_PORT_INFORMATION PortInformation
,
49 OUT PUCHAR ByteReceived
);
54 IN PKD_PORT_INFORMATION PortInformation
,
57 /* serial debug connection */
58 #define DEFAULT_DEBUG_PORT 2 /* COM2 */
59 #define DEFAULT_DEBUG_COM1_IRQ 4 /* COM1 IRQ */
60 #define DEFAULT_DEBUG_COM2_IRQ 3 /* COM2 IRQ */
61 #define DEFAULT_DEBUG_BAUD_RATE 115200 /* 115200 Baud */
63 #define DEFAULT_BAUD_RATE 19200
66 const ULONG BaseArray
[5] = {0, 0x3F8, 0x2F8, 0x3E8, 0x2E8};
68 const ULONG BaseArray
[2] = {0, 0x800003f8};
69 #elif defined(_M_MIPS)
70 const ULONG BaseArray
[3] = {0, 0x80006000, 0x80007000};
72 const ULONG BaseArray
[2] = {0, 0xF1012000};
73 #elif defined(_M_AMD64)
74 const ULONG BaseArray
[5] = {0, 0x3F8, 0x2F8, 0x3E8, 0x2E8};
76 #error Unknown architecture
79 /* MACROS *******************************************************************/
81 #define SER_RBR(x) ((PUCHAR)(x)+0)
82 #define SER_THR(x) ((PUCHAR)(x)+0)
83 #define SER_DLL(x) ((PUCHAR)(x)+0)
84 #define SER_IER(x) ((PUCHAR)(x)+1)
85 #define SR_IER_ERDA 0x01
86 #define SR_IER_ETHRE 0x02
87 #define SR_IER_ERLSI 0x04
88 #define SR_IER_EMS 0x08
89 #define SR_IER_ALL 0x0F
90 #define SER_DLM(x) ((PUCHAR)(x)+1)
91 #define SER_IIR(x) ((PUCHAR)(x)+2)
92 #define SER_FCR(x) ((PUCHAR)(x)+2)
93 #define SR_FCR_ENABLE_FIFO 0x01
94 #define SR_FCR_CLEAR_RCVR 0x02
95 #define SR_FCR_CLEAR_XMIT 0x04
96 #define SER_LCR(x) ((PUCHAR)(x)+3)
97 #define SR_LCR_CS5 0x00
98 #define SR_LCR_CS6 0x01
99 #define SR_LCR_CS7 0x02
100 #define SR_LCR_CS8 0x03
101 #define SR_LCR_ST1 0x00
102 #define SR_LCR_ST2 0x04
103 #define SR_LCR_PNO 0x00
104 #define SR_LCR_POD 0x08
105 #define SR_LCR_PEV 0x18
106 #define SR_LCR_PMK 0x28
107 #define SR_LCR_PSP 0x38
108 #define SR_LCR_BRK 0x40
109 #define SR_LCR_DLAB 0x80
110 #define SER_MCR(x) ((PUCHAR)(x)+4)
111 #define SR_MCR_DTR 0x01
112 #define SR_MCR_RTS 0x02
113 #define SR_MCR_OUT1 0x04
114 #define SR_MCR_OUT2 0x08
115 #define SR_MCR_LOOP 0x10
116 #define SER_LSR(x) ((PUCHAR)(x)+5)
117 #define SR_LSR_DR 0x01
118 #define SR_LSR_TBE 0x20
119 #define SER_MSR(x) ((PUCHAR)(x)+6)
120 #define SR_MSR_CTS 0x10
121 #define SR_MSR_DSR 0x20
122 #define SER_SCR(x) ((PUCHAR)(x)+7)
125 /* GLOBAL VARIABLES *********************************************************/
127 /* STATIC VARIABLES *********************************************************/
129 static KD_PORT_INFORMATION DefaultPort
= { 0, 0, 0 };
131 /* The com port must only be initialized once! */
132 static BOOLEAN PortInitialized
= FALSE
;
137 /* STATIC FUNCTIONS *********************************************************/
141 IN ULONG_PTR BaseAddress
)
149 /* save Modem Control Register (MCR) */
150 mcr
= READ_PORT_UCHAR(SER_MCR(BaseAddress
));
152 /* enable loop mode (set Bit 4 of the MCR) */
153 WRITE_PORT_UCHAR(SER_MCR(BaseAddress
), SR_MCR_LOOP
);
155 /* clear all modem output bits */
156 WRITE_PORT_UCHAR(SER_MCR(BaseAddress
), SR_MCR_LOOP
);
158 /* read the Modem Status Register */
159 msr
= READ_PORT_UCHAR(SER_MSR(BaseAddress
));
162 * the upper nibble of the MSR (modem output bits) must be
163 * equal to the lower nibble of the MCR (modem input bits)
165 if ((msr
& 0xF0) == 0x00)
167 /* set all modem output bits */
168 WRITE_PORT_UCHAR(SER_MCR(BaseAddress
), SR_MCR_DTR
| SR_MCR_RTS
| SR_MCR_OUT1
| SR_MCR_OUT2
| SR_MCR_LOOP
);
170 /* read the Modem Status Register */
171 msr
= READ_PORT_UCHAR(SER_MSR(BaseAddress
));
174 * the upper nibble of the MSR (modem output bits) must be
175 * equal to the lower nibble of the MCR (modem input bits)
177 if ((msr
& 0xF0) == 0xF0)
180 * setup a resonable state for the port:
181 * enable fifo and clear recieve/transmit buffers
183 WRITE_PORT_UCHAR(SER_FCR(BaseAddress
),
184 (SR_FCR_ENABLE_FIFO
| SR_FCR_CLEAR_RCVR
| SR_FCR_CLEAR_XMIT
));
185 WRITE_PORT_UCHAR(SER_FCR(BaseAddress
), 0);
186 READ_PORT_UCHAR(SER_RBR(BaseAddress
));
187 WRITE_PORT_UCHAR(SER_IER(BaseAddress
), 0);
193 WRITE_PORT_UCHAR(SER_MCR(BaseAddress
), mcr
);
199 /* FUNCTIONS ****************************************************************/
203 IN PDRIVER_OBJECT DriverObject
,
204 IN PUNICODE_STRING RegistryPath
)
206 return STATUS_SUCCESS
;
209 /* HAL.KdPortInitialize */
213 IN PKD_PORT_INFORMATION PortInformation
,
220 if (!PortInitialized
)
222 DefaultPort
.BaudRate
= PortInformation
->BaudRate
;
224 if (PortInformation
->ComPort
== 0)
226 for (i
= sizeof(BaseArray
) / sizeof(BaseArray
[0]) - 1; i
> 0; i
--)
228 if (KdpDoesComPortExist(BaseArray
[i
]))
230 DefaultPort
.BaseAddress
= BaseArray
[i
];
231 DefaultPort
.ComPort
= i
;
232 PortInformation
->BaseAddress
= DefaultPort
.BaseAddress
;
233 PortInformation
->ComPort
= DefaultPort
.ComPort
;
240 "\nKernel Debugger: No COM port found!\n\n");
241 HalDisplayString(buffer
);
246 PortInitialized
= TRUE
;
249 /* initialize port */
250 if (!KdPortInitializeEx(&DefaultPort
, Unknown1
, Unknown2
))
253 /* set global info */
254 *KdComPortInUse
= (PUCHAR
)DefaultPort
.BaseAddress
;
260 /* HAL.KdPortInitializeEx */
264 IN PKD_PORT_INFORMATION PortInformation
,
268 ULONG_PTR ComPortBase
;
278 if (PortInformation
->BaudRate
== 0)
279 PortInformation
->BaudRate
= DEFAULT_BAUD_RATE
;
281 if (PortInformation
->ComPort
== 0)
284 if (!KdpDoesComPortExist(BaseArray
[PortInformation
->ComPort
]))
287 "\nKernel Debugger: Serial port not found!\n\n");
288 HalDisplayString(buffer
);
292 ComPortBase
= BaseArray
[PortInformation
->ComPort
];
293 PortInformation
->BaseAddress
= ComPortBase
;
296 "\nSerial port COM%ld found at 0x%lx\n",
297 PortInformation
->ComPort
,
299 HalDisplayString(buffer
);
302 /* set baud rate and data format (8N1) */
304 /* turn on DTR and RTS */
305 WRITE_PORT_UCHAR(SER_MCR(ComPortBase
), SR_MCR_DTR
| SR_MCR_RTS
);
308 lcr
= READ_PORT_UCHAR(SER_LCR(ComPortBase
)) | SR_LCR_DLAB
;
309 WRITE_PORT_UCHAR(SER_LCR(ComPortBase
), lcr
);
312 divisor
= 115200 / PortInformation
->BaudRate
;
313 WRITE_PORT_UCHAR(SER_DLL(ComPortBase
), (UCHAR
)(divisor
& 0xff));
314 WRITE_PORT_UCHAR(SER_DLM(ComPortBase
), (UCHAR
)((divisor
>> 8) & 0xff));
316 /* reset DLAB and set 8N1 format */
317 WRITE_PORT_UCHAR(SER_LCR(ComPortBase
),
318 SR_LCR_CS8
| SR_LCR_ST1
| SR_LCR_PNO
);
320 /* read junk out of the RBR */
321 lcr
= READ_PORT_UCHAR(SER_RBR(ComPortBase
));
324 /* print message to blue screen */
326 "\nKernel Debugger: COM%ld (Port 0x%lx) BaudRate %ld\n\n",
327 PortInformation
->ComPort
,
329 PortInformation
->BaudRate
);
331 HalDisplayString(buffer
);
338 /* HAL.KdPortGetByte */
342 OUT PUCHAR ByteReceived
)
344 if (!PortInitialized
)
346 return KdPortGetByteEx(&DefaultPort
, ByteReceived
);
350 /* HAL.KdPortGetByteEx */
354 IN PKD_PORT_INFORMATION PortInformation
,
355 OUT PUCHAR ByteReceived
)
357 PUCHAR ComPortBase
= (PUCHAR
)PortInformation
->BaseAddress
;
359 if ((READ_PORT_UCHAR(SER_LSR(ComPortBase
)) & SR_LSR_DR
))
361 *ByteReceived
= READ_PORT_UCHAR(SER_RBR(ComPortBase
));
369 /* HAL.KdPortPollByte */
373 OUT PUCHAR ByteReceived
)
375 if (!PortInitialized
)
377 return KdPortPollByteEx(&DefaultPort
, ByteReceived
);
381 /* HAL.KdPortPollByteEx */
385 IN PKD_PORT_INFORMATION PortInformation
,
386 OUT PUCHAR ByteReceived
)
388 PUCHAR ComPortBase
= (PUCHAR
)PortInformation
->BaseAddress
;
390 while ((READ_PORT_UCHAR(SER_LSR(ComPortBase
)) & SR_LSR_DR
) == 0)
393 *ByteReceived
= READ_PORT_UCHAR(SER_RBR(ComPortBase
));
399 /* HAL.KdPortPutByte */
405 if (!PortInitialized
)
407 KdPortPutByteEx(&DefaultPort
, ByteToSend
);
410 /* HAL.KdPortPutByteEx */
414 IN PKD_PORT_INFORMATION PortInformation
,
417 PUCHAR ComPortBase
= (PUCHAR
)PortInformation
->BaseAddress
;
419 while ((READ_PORT_UCHAR(SER_LSR(ComPortBase
)) & SR_LSR_TBE
) == 0)
422 WRITE_PORT_UCHAR(SER_THR(ComPortBase
), ByteToSend
);
426 /* HAL.KdPortRestore */
444 /* HAL.KdPortDisableInterrupts */
447 KdPortDisableInterrupts(VOID
)
451 if (!PortInitialized
)
454 ch
= READ_PORT_UCHAR(SER_MCR(DefaultPort
.BaseAddress
));
455 ch
&= (~(SR_MCR_OUT1
| SR_MCR_OUT2
));
456 WRITE_PORT_UCHAR(SER_MCR(DefaultPort
.BaseAddress
), ch
);
458 ch
= READ_PORT_UCHAR(SER_IER(DefaultPort
.BaseAddress
));
460 WRITE_PORT_UCHAR(SER_IER(DefaultPort
.BaseAddress
), ch
);
466 /* HAL.KdPortEnableInterrupts */
469 KdPortEnableInterrupts(VOID
)
473 if (PortInitialized
== FALSE
)
476 ch
= READ_PORT_UCHAR(SER_IER(DefaultPort
.BaseAddress
));
479 WRITE_PORT_UCHAR(SER_IER(DefaultPort
.BaseAddress
), ch
);
481 ch
= READ_PORT_UCHAR(SER_MCR(DefaultPort
.BaseAddress
));
482 ch
&= (~SR_MCR_LOOP
);
483 ch
|= (SR_MCR_OUT1
| SR_MCR_OUT2
);
484 WRITE_PORT_UCHAR(SER_MCR(DefaultPort
.BaseAddress
), ch
);
489 /* NEW INTERNAL FUNCTIONS ****************************************************/
491 /******************************************************************************
492 * \name KdpCalculateChecksum
493 * \brief Calculates the checksum for the packet data.
494 * \param Buffer Pointer to the packet data.
495 * \param Length Length of data in bytes.
496 * \return The calculated checksum.
497 * \sa http://www.vista-xp.co.uk/forums/technical-reference-library/2540-basics-debugging.html
501 KdpCalculateChecksum(
505 ULONG i
, Checksum
= 0;
507 for (i
= 0; i
< Length
; i
++)
509 Checksum
+= ((PUCHAR
)Buffer
)[i
];
514 /******************************************************************************
515 * \name KdpSendBuffer
516 * \brief Sends a buffer of data to the KD port.
517 * \param Buffer Pointer to the data.
518 * \param Size Size of data in bytes.
527 for (i
= 0; i
< Size
; i
++)
529 KdPortPutByteEx(&DefaultPort
, ((PUCHAR
)Buffer
)[i
]);
533 /******************************************************************************
534 * \name KdDebuggerInitialize0
535 * \brief Phase 0 initialization.
536 * \param [opt] LoaderBlock Pointer to the Loader parameter block. Can be NULL.
541 KdDebuggerInitialize0(
542 IN PLOADER_PARAMETER_BLOCK LoaderBlock OPTIONAL
)
545 PCHAR CommandLine
, Port
, BaudRate
, Irq
;
547 /* Apply default values */
549 DefaultPort
.ComPort
= DEFAULT_DEBUG_PORT
;
550 DefaultPort
.BaudRate
= DEFAULT_DEBUG_BAUD_RATE
;
552 /* Check if e have a LoaderBlock */
555 /* Get the Command Line */
556 CommandLine
= LoaderBlock
->LoadOptions
;
559 _strupr(CommandLine
);
561 /* Get the port and baud rate */
562 Port
= strstr(CommandLine
, "DEBUGPORT");
563 BaudRate
= strstr(CommandLine
, "BAUDRATE");
564 Irq
= strstr(CommandLine
, "IRQ");
566 /* Check if we got the /DEBUGPORT parameter */
569 /* Move past the actual string, to reach the port*/
570 Port
+= strlen("DEBUGPORT");
572 /* Now get past any spaces and skip the equal sign */
573 while (*Port
== ' ') Port
++;
576 /* Do we have a serial port? */
577 if (strncmp(Port
, "COM", 3) != 0)
579 return STATUS_INVALID_PARAMETER
;
582 /* Gheck for a valid Serial Port */
587 return STATUS_INVALID_PARAMETER
;
590 /* Set the port to use */
591 DefaultPort
.ComPort
= Value
;
594 /* Check if we got a baud rate */
597 /* Move past the actual string, to reach the rate */
598 BaudRate
+= strlen("BAUDRATE");
600 /* Now get past any spaces */
601 while (*BaudRate
== ' ') BaudRate
++;
603 /* And make sure we have a rate */
606 /* Read and set it */
607 Value
= atol(BaudRate
+ 1);
608 if (Value
) DefaultPort
.BaudRate
= Value
;
612 /* Check Serial Port Settings [IRQ] */
615 /* Move past the actual string, to reach the rate */
616 Irq
+= strlen("IRQ");
618 /* Now get past any spaces */
619 while (*Irq
== ' ') Irq
++;
621 /* And make sure we have an IRQ */
624 /* Read and set it */
625 Value
= atol(Irq
+ 1);
626 if (Value
) KdpPortIrq
= Value
;
631 /* Get base address */
632 DefaultPort
.BaseAddress
= BaseArray
[DefaultPort
.ComPort
];
634 /* Check if the COM port does exist */
635 if (!KdpDoesComPortExist(DefaultPort
.BaseAddress
))
637 return STATUS_INVALID_PARAMETER
;
640 /* Initialize the port */
641 KdPortInitializeEx(&DefaultPort
, 0, 0);
643 return STATUS_SUCCESS
;
646 /******************************************************************************
647 * \name KdDebuggerInitialize0
648 * \brief Phase 0 initialization.
649 * \param [opt] LoaderBlock Pointer to the Loader parameter block. Can be NULL.
654 KdDebuggerInitialize1(
655 IN PLOADER_PARAMETER_BLOCK LoaderBlock OPTIONAL
)
658 return STATUS_NOT_IMPLEMENTED
;
667 IN BOOLEAN SleepTransition
)
669 /* Nothing to do on COM ports */
670 return STATUS_SUCCESS
;
679 IN BOOLEAN SleepTransition
)
681 /* Nothing to do on COM ports */
682 return STATUS_SUCCESS
;
692 IN PSTRING MessageHeader
,
693 IN PSTRING MessageData
,
694 IN OUT PKD_CONTEXT Context
)
700 case PACKET_TYPE_KD_DEBUG_IO
:
701 /* Copy Message to COM port */
702 for (i
= 0; i
< MessageData
->Length
; i
++)
704 char c
= MessageData
->Buffer
[i
];
707 KdPortPutByteEx(&DefaultPort
, 13);
708 KdPortPutByteEx(&DefaultPort
, 10);
712 KdPortPutByteEx(&DefaultPort
, c
);
731 OUT PSTRING MessageHeader
,
732 OUT PSTRING MessageData
,
733 OUT PULONG DataLength
,
734 IN OUT PKD_CONTEXT Context
)