diff --git a/Kernel/grub.cfg b/Kernel/grub.cfg index 9348f629c9..9daee90c41 100644 --- a/Kernel/grub.cfg +++ b/Kernel/grub.cfg @@ -1,6 +1,11 @@ -timeout=0 +timeout=1 -menuentry 'Serenity' { +menuentry 'Serenity (normal)' { root=hd0,1 multiboot /boot/kernel root=/dev/hda1 } + +menuentry 'Serenity (with serial debug)' { + root=hd0,1 + multiboot /boot/kernel serial_debug root=/dev/hda1 +} diff --git a/Kernel/init.cpp b/Kernel/init.cpp index eff913e8b0..e846d0da77 100644 --- a/Kernel/init.cpp +++ b/Kernel/init.cpp @@ -4,6 +4,7 @@ #include "RTC.h" #include "Scheduler.h" #include "kmalloc.h" +#include "kstdio.h" #include #include #include @@ -155,6 +156,25 @@ multiboot_info_t* multiboot_info_ptr; extern "C" [[noreturn]] void init() { + // this is only used one time, directly below here. we can't use this part + // of libc at this point in the boot process, or we'd just pull strstr in + // from . + auto bad_prefix_check = [](const char *str, const char *search) -> bool { + while (*search) + if (*search++ != *str++) + return false; + + return true; + }; + + // serial_debug will output all the kprintf and dbgprintf data to COM1 at + // 8-N-1 57600 baud. this is particularly useful for debugging the boot + // process on live hardware. + // + // note: it must be the first option in the boot cmdline. + if (multiboot_info_ptr->cmdline && bad_prefix_check(reinterpret_cast(multiboot_info_ptr->cmdline), "serial_debug")) + set_serial_debug(true); + sse_init(); kmalloc_init(); @@ -177,7 +197,8 @@ extern "C" [[noreturn]] void init() ps2mouse = new PS2MouseDevice; sb16 = new SB16; dev_null = new NullDevice; - ttyS0 = new SerialDevice(SERIAL_COM1_ADDR, 64); + if (!get_serial_debug()) + ttyS0 = new SerialDevice(SERIAL_COM1_ADDR, 64); ttyS1 = new SerialDevice(SERIAL_COM2_ADDR, 65); ttyS2 = new SerialDevice(SERIAL_COM3_ADDR, 66); ttyS3 = new SerialDevice(SERIAL_COM4_ADDR, 67); diff --git a/Kernel/kprintf.cpp b/Kernel/kprintf.cpp index 468ce55ab7..0cf012ed40 100644 --- a/Kernel/kprintf.cpp +++ b/Kernel/kprintf.cpp @@ -6,6 +6,18 @@ #include #include +static bool serial_debug; + +void set_serial_debug(bool on_or_off) +{ + serial_debug = on_or_off; +} + +int get_serial_debug() +{ + return serial_debug; +} + static void color_on() { IO::out8(0xe9, 0x1b); @@ -22,8 +34,42 @@ static void color_off() IO::out8(0xe9, '0'); IO::out8(0xe9, 'm'); } + +static void serial_putch(char ch) +{ + static bool serial_ready = false; + static bool was_cr = false; + + if (!serial_ready) { + IO::out8(0x3F8 + 1, 0x00); + IO::out8(0x3F8 + 3, 0x80); + IO::out8(0x3F8 + 0, 0x02); + IO::out8(0x3F8 + 1, 0x00); + IO::out8(0x3F8 + 3, 0x03); + IO::out8(0x3F8 + 2, 0xC7); + IO::out8(0x3F8 + 4, 0x0B); + + serial_ready = true; + } + + while ((IO::in8(0x3F8 + 5) & 0x20) == 0) + ; + + if (ch == '\n' && !was_cr) + IO::out8(0x3F8, '\r'); + + IO::out8(0x3F8, ch); + + if (ch == '\r') + was_cr = true; + else + was_cr = false; +} + static void console_putch(char*&, char ch) { + if (serial_debug) + serial_putch(ch); if (!current) { IO::out8(0xe9, ch); return; @@ -57,16 +103,23 @@ int ksprintf(char* buffer, const char* fmt, ...) return ret; } -extern "C" int dbgputstr(const char* characters, int length) +static void debugger_out(char ch) { - for (int i = 0; i < length; ++i) - IO::out8(0xe9, characters[i]); - return 0; + if (serial_debug) + serial_putch(ch); + IO::out8(0xe9, ch); } static void debugger_putch(char*&, char ch) { - IO::out8(0xe9, ch); + debugger_out(ch); +} + +extern "C" int dbgputstr(const char* characters, int length) +{ + for (int i = 0; i < length; ++i) + debugger_out(characters[i]); + return 0; } extern "C" int dbgprintf(const char* fmt, ...) diff --git a/Kernel/kstdio.h b/Kernel/kstdio.h index ce7d6fdae4..db41888c26 100644 --- a/Kernel/kstdio.h +++ b/Kernel/kstdio.h @@ -7,6 +7,8 @@ int dbgprintf(const char* fmt, ...); int dbgputstr(const char*, int); int kprintf(const char* fmt, ...); int ksprintf(char* buf, const char* fmt, ...); +void set_serial_debug(bool on_or_off); +int get_serial_debug(); } #ifndef USERLAND