HyperDbg Debugger
Loading...
Searching...
No Matches
uart16550.c File Reference
#include "common.h"
#include "kdcom.h"

Functions

BOOLEAN Uart16550SetBaud (_Inout_ PCPPORT Port, ULONG Rate)
 
UART_STATUS Uart16550PutByte (_Inout_ PCPPORT Port, UCHAR Byte, BOOLEAN BusyWait)
 
UART_STATUS Uart16550GetByte (_Inout_ PCPPORT Port, _Out_ PUCHAR Byte)
 
VOID KdHyperDbgTest (UINT16 Byte)
 
VOID KdHyperDbgPrepareDebuggeeConnectionPort (UINT32 PortAddress, UINT32 Baudrate)
 
VOID KdHyperDbgSendByte (UCHAR Byte, BOOLEAN BusyWait)
 
BOOLEAN KdHyperDbgRecvByte (PUCHAR RecvByte)
 
BOOLEAN Uart16550InitializePortCommon (_In_opt_ _Null_terminated_ PCHAR LoadOptions, _Inout_ PCPPORT Port, BOOLEAN MemoryMapped, UCHAR AccessSize, UCHAR BitWidth)
 
BOOLEAN Uart16550LegacyInitializePort (_In_opt_ _Null_terminated_ PCHAR LoadOptions, _Inout_ PCPPORT Port, BOOLEAN MemoryMapped, UCHAR AccessSize, UCHAR BitWidth)
 
BOOLEAN Uart16550InitializePort (_In_opt_ _Null_terminated_ PCHAR LoadOptions, _Inout_ PCPPORT Port, BOOLEAN MemoryMapped, UCHAR AccessSize, UCHAR BitWidth)
 
BOOLEAN Uart16550MmInitializePort (_In_opt_ _Null_terminated_ PCHAR LoadOptions, _Inout_ PCPPORT Port, BOOLEAN MemoryMapped, UCHAR AccessSize, UCHAR BitWidth)
 
BOOLEAN Uart16550SetBaudCommon (_Inout_ PCPPORT Port, ULONG Rate, ULONG Clock)
 
BOOLEAN Uart16550RxReady (_Inout_ PCPPORT Port)
 

Variables

CPPORT g_PortDetails = {0}
 
UART_HARDWARE_DRIVER Legacy16550HardwareDriver
 
UART_HARDWARE_DRIVER Uart16550HardwareDriver
 
UART_HARDWARE_DRIVER MM16550HardwareDriver
 

Function Documentation

◆ KdHyperDbgPrepareDebuggeeConnectionPort()

VOID KdHyperDbgPrepareDebuggeeConnectionPort ( UINT32 PortAddress,
UINT32 Baudrate )
105{
106 UINT64 PortAddressUChar = 0ULL;
107 PortAddressUChar = PortAddressUChar | PortAddress;
108
109 g_PortDetails.Address = (PUCHAR)PortAddressUChar;
110 g_PortDetails.BaudRate = Baudrate;
111 g_PortDetails.Flags = 0;
112 g_PortDetails.ByteWidth = 1;
113
114 g_PortDetails.Write = WritePortWithIndex8;
115 g_PortDetails.Read = ReadPortWithIndex8;
116}
unsigned __int64 UINT64
Definition BasicTypes.h:21
CPPORT g_PortDetails
Definition uart16550.c:43

◆ KdHyperDbgRecvByte()

BOOLEAN KdHyperDbgRecvByte ( PUCHAR RecvByte)
126{
127 if (Uart16550GetByte(&g_PortDetails, RecvByte) == UartSuccess)
128 {
129 return TRUE;
130 }
131 return FALSE;
132}
#define TRUE
Definition BasicTypes.h:55
#define FALSE
Definition BasicTypes.h:54
UART_STATUS Uart16550GetByte(_Inout_ PCPPORT Port, _Out_ PUCHAR Byte)
Definition uart16550.c:546

◆ KdHyperDbgSendByte()

VOID KdHyperDbgSendByte ( UCHAR Byte,
BOOLEAN BusyWait )
120{
121 Uart16550PutByte(&g_PortDetails, Byte, BusyWait);
122}
UART_STATUS Uart16550PutByte(_Inout_ PCPPORT Port, UCHAR Byte, BOOLEAN BusyWait)
Definition uart16550.c:645

◆ KdHyperDbgTest()

VOID KdHyperDbgTest ( UINT16 Byte)
78{
79 UNREFERENCED_PARAMETER(Byte);
80 //
81 // *** This function is for internal use and test
82 // don't use it ***
83 //
84
85 CPPORT TempPort = {0};
86 TempPort.Address = (PUCHAR)0x2f8;
87 TempPort.BaudRate = 0x01c200; // 115200
88 TempPort.Flags = 0;
89 TempPort.ByteWidth = 1;
90
91 TempPort.Write = WritePortWithIndex8;
92 TempPort.Read = ReadPortWithIndex8;
93
94 Uart16550PutByte(&TempPort, 0x42, TRUE);
95
96 for (size_t i = 0; i < 100; i++)
97 {
98 // char RecvByte = 0;
99 // Uart16550GetByte(&TempPort,&RecvByte);
100 }
101}

◆ Uart16550GetByte()

UART_STATUS Uart16550GetByte ( _Inout_ PCPPORT Port,
_Out_ PUCHAR Byte )
568{
569 UCHAR Data;
570 UCHAR Lsr;
571 UCHAR Msr;
572
573 *Byte = 0;
574
575 if ((Port == NULL) || (Port->Address == NULL))
576 {
577 return UartNotReady;
578 }
579
580 //
581 // Check to see if all bits are set in LSR. If this is the case, it means
582 // the port I/O address is invalid as 0xFF is nonsense for LSR.
583 //
584
585 Lsr = Port->Read(Port, COM_LSR);
586 if (Lsr == SERIAL_LSR_NOT_PRESENT)
587 {
588 return UartNotReady;
589 }
590
591 if (CHECK_FLAG(Lsr, COM_DATRDY))
592 {
593 //
594 // Return unsuccessfully if any errors are indicated by the
595 // LSR.
596 //
597
598 if (CHECK_FLAG(Lsr, COM_PE) ||
599 CHECK_FLAG(Lsr, COM_FE) ||
600 CHECK_FLAG(Lsr, COM_OE))
601 {
602 return UartError;
603 }
604
605 Data = Port->Read(Port, COM_DAT);
606
607 //
608 // When using modem control, ignore any bytes that don't have
609 // the carrier detect flag set.
610 //
611
612 if (CHECK_FLAG(Port->Flags, PORT_MODEM_CONTROL))
613 {
614 Msr = Port->Read(Port, COM_MSR);
615 if (CHECK_FLAG(Msr, MS_CD) == FALSE)
616 {
617 return UartNoData;
618 }
619 }
620
621 *Byte = Data;
622 return UartSuccess;
623 }
624 else
625 {
626 //
627 // Data is not available. Determine if the ring indicator has toggled.
628 // If so, enable modem control.
629 //
630
631 Msr = Port->Read(Port, COM_MSR);
632 if ((CHECK_FLAG(Port->Flags, PORT_RING_INDICATOR) &&
633 !CHECK_FLAG(Msr, SERIAL_MSR_RI)) ||
634 (!CHECK_FLAG(Port->Flags, PORT_RING_INDICATOR) &&
636 {
637 Port->Flags |= PORT_MODEM_CONTROL;
638 }
639
640 return UartNoData;
641 }
642}
unsigned char UCHAR
Definition BasicTypes.h:35
#define COM_LSR
Definition kdcom.h:36
#define COM_PE
Definition kdcom.h:44
#define COM_FE
Definition kdcom.h:43
#define COM_OE
Definition kdcom.h:45
#define COM_MSR
Definition kdcom.h:37
#define SERIAL_MSR_RI
Definition kdcom.h:107
#define COM_DATRDY
Definition kdcom.h:60
#define COM_DAT
Definition kdcom.h:31
#define MS_CD
Definition kdcom.h:53
#define SERIAL_LSR_NOT_PRESENT
Definition kdcom.h:116
Start of Optional Data
Definition script_buffer.hex.txt:8
#define CHECK_FLAG(_x, _f)
Definition uartp.h:27

◆ Uart16550InitializePort()

BOOLEAN Uart16550InitializePort ( _In_opt_ _Null_terminated_ PCHAR LoadOptions,
_Inout_ PCPPORT Port,
BOOLEAN MemoryMapped,
UCHAR AccessSize,
UCHAR BitWidth )
346{
347 UCHAR RegisterBitWidth;
348
349 UNREFERENCED_PARAMETER(AccessSize);
350 UNREFERENCED_PARAMETER(BitWidth);
351
352#if defined(_ARM_) || defined(_ARM64_)
353
354 //
355 // ARM-based systems are by definition MMIO and tend to space the ports
356 // apart at 4-byte intervals. Expand to DWORD boundaries for ARM devices.
357 //
358
359 RegisterBitWidth = 32;
360 if (MemoryMapped == FALSE)
361 {
362 return FALSE;
363 }
364
365 //
366 // ARM-based systems typically have non-standard dividends for baud rate.
367 // It is deemed safest to assume the UEFI firmware has already set up
368 // the serial port properly and just inherit the baud rate that is already
369 // set.
370 //
371
372 Port->Flags = PORT_DEFAULT_RATE;
373
374#else
375
376 RegisterBitWidth = 8;
377 Port->Flags = 0;
378
379#endif
380
381 return Uart16550InitializePortCommon(LoadOptions,
382 Port,
383 MemoryMapped,
385 RegisterBitWidth);
386}
BOOLEAN Uart16550InitializePortCommon(_In_opt_ _Null_terminated_ PCHAR LoadOptions, _Inout_ PCPPORT Port, BOOLEAN MemoryMapped, UCHAR AccessSize, UCHAR BitWidth)
Definition uart16550.c:137
@ AcpiGenericAccessSizeByte
Definition uartp.h:51

◆ Uart16550InitializePortCommon()

BOOLEAN Uart16550InitializePortCommon ( _In_opt_ _Null_terminated_ PCHAR LoadOptions,
_Inout_ PCPPORT Port,
BOOLEAN MemoryMapped,
UCHAR AccessSize,
UCHAR BitWidth )
171{
172 UCHAR RegisterValue;
173
174 UNREFERENCED_PARAMETER(LoadOptions);
175
176 //
177 // Set the Read / Write function pointers for this serial port.
178 //
179
180 UartpSetAccess(Port, MemoryMapped, AccessSize, BitWidth);
181
182 //
183 // Set DLAB to zero. The DLAB controls the meaning of the first two
184 // registers. When zero, the first register is used for all byte transfers
185 // and the second register controls device interrupts.
186 //
187
188 RegisterValue = Port->Read(Port, COM_LCR);
189 RegisterValue &= ~LC_DLAB;
190 Port->Write(Port, COM_LCR, RegisterValue);
191
192 //
193 // Disable device interrupts. This implementation will handle state
194 // transitions by request only.
195 //
196
197 Port->Write(Port, COM_IEN, 0);
198
199 //
200 // Reset and disable the FIFO queue.
201 // N.B. FIFO will be re-enabled before returning from this routine.
202 //
203
204 Port->Write(Port, COM_FCR, FC_CLEAR_TRANSMIT | FC_CLEAR_RECEIVE);
205
206 //
207 // Configure the baud rate and mode.
208 //
209
210 Uart16550SetBaud(Port, Port->BaudRate);
211
212 //
213 // Enable the FIFO.
214 //
215
216 Port->Write(Port, COM_FCR, FC_ENABLE);
217
218 //
219 // Assert DTR, RTS. Disable loopback. Indicate to the device that
220 // we are able to send and receive data.
221 //
222
223 Port->Write(Port, COM_MCR, MC_DTRRTS);
224
225 //
226 // Initialize ring indicator bit based on hardware state.
227 //
228
229 RegisterValue = Port->Read(Port, COM_MSR);
230 if (CHECK_FLAG(RegisterValue, SERIAL_MSR_RI))
231 {
232 Port->Flags |= PORT_RING_INDICATOR;
233 }
234
235 return TRUE;
236}
#define FC_CLEAR_TRANSMIT
Definition kdcom.h:57
#define FC_CLEAR_RECEIVE
Definition kdcom.h:56
#define COM_IEN
Definition kdcom.h:32
#define FC_ENABLE
Definition kdcom.h:55
#define MC_DTRRTS
Definition kdcom.h:51
#define COM_MCR
Definition kdcom.h:35
#define COM_FCR
Definition kdcom.h:33
#define COM_LCR
Definition kdcom.h:34
BOOLEAN Uart16550SetBaud(_Inout_ PCPPORT Port, ULONG Rate)
Definition uart16550.c:514
BOOLEAN UartpSetAccess(_Inout_ PCPPORT Port, const BOOLEAN MemoryMapped, const UCHAR AccessSize, const UCHAR BitWidth)
Definition uartio.c:225

◆ Uart16550LegacyInitializePort()

BOOLEAN Uart16550LegacyInitializePort ( _In_opt_ _Null_terminated_ PCHAR LoadOptions,
_Inout_ PCPPORT Port,
BOOLEAN MemoryMapped,
UCHAR AccessSize,
UCHAR BitWidth )
275{
276 UNREFERENCED_PARAMETER(AccessSize);
277 UNREFERENCED_PARAMETER(BitWidth);
278 UNREFERENCED_PARAMETER(MemoryMapped);
279
280 switch ((ULONG_PTR)Port->Address)
281 {
282 case 1:
283 Port->Address = (PUCHAR)COM1_PORT;
284 break;
285
286 case 2:
287 Port->Address = (PUCHAR)COM2_PORT;
288 break;
289
290 case 3:
291 Port->Address = (PUCHAR)COM3_PORT;
292 break;
293
294 case 4:
295 Port->Address = (PUCHAR)COM4_PORT;
296 break;
297
298 default:
299 return FALSE;
300 }
301
302 Port->Flags = 0;
303 return Uart16550InitializePortCommon(LoadOptions,
304 Port,
305 FALSE,
307 8);
308}
#define COM4_PORT
Definition SerialConnection.h:93
#define COM3_PORT
Definition SerialConnection.h:92
#define COM2_PORT
Definition SerialConnection.h:91
#define COM1_PORT
Definition SerialConnection.h:90

◆ Uart16550MmInitializePort()

BOOLEAN Uart16550MmInitializePort ( _In_opt_ _Null_terminated_ PCHAR LoadOptions,
_Inout_ PCPPORT Port,
BOOLEAN MemoryMapped,
UCHAR AccessSize,
UCHAR BitWidth )
426{
427 Port->Flags = PORT_DEFAULT_RATE;
428 return Uart16550InitializePortCommon(LoadOptions,
429 Port,
430 MemoryMapped,
431 AccessSize,
432 BitWidth);
433}

◆ Uart16550PutByte()

UART_STATUS Uart16550PutByte ( _Inout_ PCPPORT Port,
UCHAR Byte,
BOOLEAN BusyWait )
667{
668 UCHAR Lsr;
669 UCHAR Msr;
670
671 if ((Port == NULL) || (Port->Address == NULL))
672 {
673 return UartNotReady;
674 }
675
676 //
677 // When using modem control, DSR, CTS, and CD flags must all be set before
678 // sending any data.
679 //
680
681 if (CHECK_FLAG(Port->Flags, PORT_MODEM_CONTROL))
682 {
683 Msr = Port->Read(Port, COM_MSR);
684 while ((Msr & MS_DSRCTSCD) != MS_DSRCTSCD)
685 {
686 //
687 // If there's a byte ready, discard it from the input queue.
688 //
689
690 if (!CHECK_FLAG(Msr, MS_CD))
691 {
692 Lsr = Port->Read(Port, COM_LSR);
693 if (CHECK_FLAG(Port->Flags, COM_DATRDY))
694 {
695 Port->Read(Port, COM_DAT);
696 }
697 }
698
699 Msr = Port->Read(Port, COM_MSR);
700 }
701 }
702
703 //
704 // Check to see if all bits are set in LSR. If this is the case, it means
705 // the port I/O address is invalid as 0xFF is nonsense for LSR. This
706 // prevents writing a byte to non-existent hardware.
707 //
708
709 Lsr = Port->Read(Port, COM_LSR);
710 if (Lsr == SERIAL_LSR_NOT_PRESENT)
711 {
712 return UartNotReady;
713 }
714
715 //
716 // The port must be ready to accept a byte for output before continuing.
717 //
718
719 while (!CHECK_FLAG(Lsr, COM_OUTRDY))
720 {
721 //
722 // Determine if the ring indicator has toggled.
723 // If so, enable modem control.
724 //
725
726 Msr = Port->Read(Port, COM_MSR);
727 if ((CHECK_FLAG(Port->Flags, PORT_RING_INDICATOR) &&
728 !CHECK_FLAG(Msr, SERIAL_MSR_RI)) ||
729 (!CHECK_FLAG(Port->Flags, PORT_RING_INDICATOR) &&
731 {
732 Port->Flags |= PORT_MODEM_CONTROL;
733 }
734
735 if (BusyWait == FALSE)
736 {
737 return UartNotReady;
738 }
739
740 Lsr = Port->Read(Port, COM_LSR);
741 }
742
743 //
744 // Transmitter holding register is empty. Send the byte.
745 //
746
747 Port->Write(Port, COM_DAT, Byte);
748 return UartSuccess;
749}
#define MS_DSRCTSCD
Definition kdcom.h:52
#define COM_OUTRDY
Definition kdcom.h:59

◆ Uart16550RxReady()

BOOLEAN Uart16550RxReady ( _Inout_ PCPPORT Port)
771{
772 UCHAR Lsr;
773
774 if ((Port == NULL) || (Port->Address == NULL))
775 {
776 return FALSE;
777 }
778
779 //
780 // Check to see if all bits are set in LSR. If this is the case, it means
781 // the port I/O address is invalid as 0xFF is nonsense for LSR. This
782 // prevents the DATRDY check below from returning TRUE, which could cause
783 // a caller to think that data is pending when in actuality there is no
784 // UART present.
785 //
786
787 Lsr = Port->Read(Port, COM_LSR);
788 if (Lsr == SERIAL_LSR_NOT_PRESENT)
789 {
790 return FALSE;
791 }
792
793 //
794 // Look at the Line Status Register to determine if there is pending data.
795 //
796
797 if (CHECK_FLAG(Lsr, COM_DATRDY))
798 {
799 return TRUE;
800 }
801
802 return FALSE;
803}

◆ Uart16550SetBaud()

BOOLEAN Uart16550SetBaud ( _Inout_ PCPPORT Port,
ULONG Rate )
536{
537 if (CHECK_FLAG(Port->Flags, PORT_DEFAULT_RATE))
538 {
539 return FALSE;
540 }
541
542 return Uart16550SetBaudCommon(Port, Rate, CLOCK_RATE);
543}
#define CLOCK_RATE
Definition apm88xxxx.c:24
BOOLEAN Uart16550SetBaudCommon(_Inout_ PCPPORT Port, ULONG Rate, ULONG Clock)
Definition uart16550.c:436

◆ Uart16550SetBaudCommon()

BOOLEAN Uart16550SetBaudCommon ( _Inout_ PCPPORT Port,
ULONG Rate,
ULONG Clock )
461{
462 UCHAR Lcr;
463
464 if ((Port == NULL) || (Port->Address == NULL))
465 {
466 return FALSE;
467 }
468
469 if ((Rate == 0) || (Clock == 0))
470 {
471 return FALSE;
472 }
473
474 //
475 // A device's baud rate is written to DLL and DLM. The values of these
476 // registers are the resultant when the max rate (clock) is divided by the
477 // device's desired operating rate.
478 //
479
480 const ULONG DivisorLatch = Clock / Rate;
481
482 //
483 // Set the divisor latch access bit (DLAB) in the line control register.
484 // When non-zero, the first two registers become DLL and DLM.
485 //
486
487 Lcr = Port->Read(Port, COM_LCR);
488 Lcr |= LC_DLAB;
489 Port->Write(Port, COM_LCR, Lcr);
490
491 //
492 // Set the divisor latch value (MSB first, then LSB).
493 //
494
495 Port->Write(Port, COM_DLM, (UCHAR)((DivisorLatch >> 8) & 0xFF));
496 Port->Write(Port, COM_DLL, (UCHAR)(DivisorLatch & 0xFF));
497
498 //
499 // Set Line Control Register to 8N1 (no parity, 8 data bits, 1 stop bit).
500 // This also sets the DLAB back to zero.
501 //
502
503 Port->Write(Port, COM_LCR, 3);
504
505 //
506 // Remember the baud rate.
507 //
508
509 Port->BaudRate = Rate;
510 return TRUE;
511}
unsigned long ULONG
Definition BasicTypes.h:37
#define COM_DLL
Definition kdcom.h:39
#define LC_DLAB
Definition kdcom.h:47
#define COM_DLM
Definition kdcom.h:40

Variable Documentation

◆ g_PortDetails

CPPORT g_PortDetails = {0}
43{0};

◆ Legacy16550HardwareDriver

UART_HARDWARE_DRIVER Legacy16550HardwareDriver
Initial value:
= {
BOOLEAN Uart16550RxReady(_Inout_ PCPPORT Port)
Definition uart16550.c:752
BOOLEAN Uart16550LegacyInitializePort(_In_opt_ _Null_terminated_ PCHAR LoadOptions, _Inout_ PCPPORT Port, BOOLEAN MemoryMapped, UCHAR AccessSize, UCHAR BitWidth)
Definition uart16550.c:239

◆ MM16550HardwareDriver

UART_HARDWARE_DRIVER MM16550HardwareDriver
Initial value:
= {
BOOLEAN Uart16550MmInitializePort(_In_opt_ _Null_terminated_ PCHAR LoadOptions, _Inout_ PCPPORT Port, BOOLEAN MemoryMapped, UCHAR AccessSize, UCHAR BitWidth)
Definition uart16550.c:389

◆ Uart16550HardwareDriver

UART_HARDWARE_DRIVER Uart16550HardwareDriver
Initial value:
= {
BOOLEAN Uart16550InitializePort(_In_opt_ _Null_terminated_ PCHAR LoadOptions, _Inout_ PCPPORT Port, BOOLEAN MemoryMapped, UCHAR AccessSize, UCHAR BitWidth)
Definition uart16550.c:311