SilverOS uses the first COM port (COM1) as its primary debug output channel. The serial driver is initialized early in the boot sequence — before the GDT is reloaded, before the IDT is set up, and before the framebuffer is available — so any log message emitted by any subsystem can be captured from the very first instruction the kernel runs. All structured boot messages, driver initialization confirmations, and runtime diagnostics flow through this channel using a consistentDocumentation Index
Fetch the complete documentation index at: https://mintlify.com/pastaboy12345/SilverOS/llms.txt
Use this file to discover all available pages before exploring further.
[TAG] message convention.
Serial API
The full serial interface is declared inserial.h:
| Function | Description |
|---|---|
serial_init | Programs the COM1 UART at I/O base 0x3F8 for 115200 baud, 8 data bits, no parity, 1 stop bit (8N1). Sets the DLAB bit to write the divisor, then clears DLAB and configures the FIFO control and modem control registers. |
serial_putc | Polls the line status register (offset +5 from the base port) until the transmit-holding-register-empty bit is set, then writes the character. Converts \n to \r\n automatically so output renders correctly in terminal emulators. |
serial_puts | Calls serial_putc for each character in the null-terminated string. |
serial_printf | Formats a message into a stack buffer using vsnprintf, then calls serial_puts. Accepts the same format specifiers as standard printf (%d, %u, %x, %s, %c, etc.). |
115200 / 115200 = 1, written as a 16-bit value to the divisor latch registers (0x3F8 low byte, 0x3F9 high byte) while the DLAB bit in the line control register is set.
How to view serial output
QEMU maps COM1 to the host’s standard I/O streams when launched with the-serial stdio flag. All characters written by the kernel appear directly in the terminal running QEMU.
Boot log format
Every subsystem prefixes its serial messages with a short uppercase tag in square brackets. This makes it easy togrep the log for a specific component and to spot initialization order problems at a glance. A typical boot sequence looks like this:
serial_printf with its own tag inside its _init function. The tags used by the built-in drivers are:
| Tag | Subsystem |
|---|---|
[BOOT] | Early kernel entry, Multiboot2 validation |
[FB] | Framebuffer driver (fb_init) |
[INIT] | GDT, PIC, IDT initialization |
[PMM] | Physical memory manager |
[HEAP] | Kernel heap allocator |
[KEYBOARD] | PS/2 keyboard driver |
[SilverFS] | Filesystem mount |
[NET] | Network stack |
Kernel printf
kprintf, declared in console.h, is the everyday logging function once the framebuffer is available. Internally it calls both console_puts (which writes to the framebuffer console and calls fb_swap_buffers()) and serial_puts, so a single kprintf call produces output in both places simultaneously:
serial_printf is the lower-level alternative used before fb_init has been called or in contexts where writing to the framebuffer would be unsafe (such as inside an exception handler). The rule of thumb is:
- Use
serial_printfin drivers that initialize before the framebuffer, in interrupt handlers, and in panic paths. - Use
kprintfeverywhere else — it routes to serial automatically, so you never lose the message.