NKLegacy provides a serial driver for early-boot and ongoing debug output over COM1 (Documentation Index
Fetch the complete documentation index at: https://mintlify.com/pastaboy12345/NKLegacy/llms.txt
Use this file to discover all available pages before exploring further.
0x3F8) at 115200 baud 8-N-1. kmain.c calls serial_init(COM1) as the very first hardware operation — before VGA is cleared, before GDT/IDT are loaded — making COM1 the earliest observable debug channel. All kernel boot messages are written to COM1 via serial_print, and the shell loop polls serial_getchar(COM1) so commands can be typed over the serial connection as well as the PS/2 keyboard.
Port Constants
| Constant | Value | Description |
|---|---|---|
COM1 | 0x3F8 | I/O base address for COM1 |
COM2 | 0x2F8 | I/O base address for COM2 |
uint16_t port parameter so they work with either port without duplication.
API Reference
void serial_init(uint16_t port)
Configures the UART at port for 115200 baud, 8 data bits, no parity, 1 stop bit, with the FIFO enabled. The initialization sequence is:
Disable interrupts
Write
0x00 to port + 1 to suppress UART-generated IRQs (the kernel uses polled I/O).Set baud rate divisor
Enable DLAB by writing
0x80 to port + 3 (Line Control Register), then write divisor low byte 0x01 to port + 0 and high byte 0x00 to port + 1. A divisor of 1 selects 115200 baud.Enable FIFO
Write
0xC7 to port + 2 (FIFO Control Register): enable FIFO, clear transmit and receive FIFOs, set 14-byte trigger threshold.void serial_putchar(uint16_t port, char c)
Polls the Line Status Register (port + 5) until bit 5 (Transmitter Holding Register Empty) is set, then writes the byte to the transmit register (port + 0). The function sends exactly the byte it is given with no translation — CR+LF conversion is handled by serial_print, not here.
void serial_print(uint16_t port, const char *str)
Iterates over the NUL-terminated string str. For each \n byte it first sends \r (CR+LF conversion), then sends the byte itself via serial_putchar.
char serial_getchar(uint16_t port)
Non-blocking read. Checks bit 0 of the Line Status Register (port + 5): if data is available it reads and returns the byte from port + 0; if no data is ready it returns 0 immediately without blocking.
QEMU Serial Monitoring
Themake run target passes -serial stdio to QEMU, connecting the guest COM1 port directly to the host terminal’s standard I/O:
serial_print call appears inline in the same terminal window you launched QEMU from. The expected early-boot serial log is:
make run-serial:
Usage Examples
Early debug before VGA is available
Serial fallback in the shell input loop
The shell incmd.c reads from keyboard_getchar() first. If no PS/2 key is available it falls back to serial_getchar(COM1), allowing commands to be entered over the serial link: