From b0c021d4e934205ccf10b0528da3c9058ba9fa2d Mon Sep 17 00:00:00 2001 From: Max Wash Date: Sat, 30 Dec 2023 09:09:18 +0000 Subject: [PATCH] kernel: add kernel.early-console and kernel.console boot args kernel.early-console is used to specify which output device the kernel boot log should be written to. the first thing the kernel does on boot after initialising the bootstrap processor is initialise the early console, making it useful for debugging problems that occur early in the boot process. this arg accepts a list of hard-coded values for output devices, such as tty0 for the display or ttyS0 for the serial port. the exact values supported will depend on the platform. once all drivers are loaded, the kernel switches to the device specified by kernel.console for output. unlike kernel.early-console, this arg specifies the name of a tty device in /dev/tty. this means that, not only are more devices supported (any device provided by a tty driver), but the kernel can also get input from the user using this console too (not used by the kernel itself, but will be used by the user to interact with userspace programs, like the shell). --- arch/x86_64/init.c | 33 ++++++++++++++-- include/socks/tty.h | 3 ++ init/main.c | 28 +++++++++++-- kernel/tty/device.c | 39 +++++++++++++++---- .../{serial.h => include/socks/serialcon.h} | 2 +- kexts/drivers/tty/serialcon/main.c | 4 +- 6 files changed, 91 insertions(+), 18 deletions(-) rename kexts/drivers/tty/serialcon/{serial.h => include/socks/serialcon.h} (91%) diff --git a/arch/x86_64/init.c b/arch/x86_64/init.c index 54eb216..02256e7 100644 --- a/arch/x86_64/init.c +++ b/arch/x86_64/init.c @@ -13,9 +13,9 @@ #include #include #include +#include #include #include -#include #ifdef KEXT_NET_DOORSTUCK_SOCKS_ACPI #include @@ -25,6 +25,10 @@ #include #endif +#ifdef KEXT_NET_DOORSTUCK_SOCKS_SERIALCON +#include +#endif + #define PTR32(x) ((void *)((uintptr_t)(x))) static ml_cpu_block g_bootstrap_cpu = {0}; @@ -54,6 +58,28 @@ static void early_vm_init(void) printk("memblock: reserved bios+kernel at [0x%016llx-0x%016llx]", 0, (uintptr_t)__pend); } +void early_console_init(void) +{ + const char *dest = arg_value("kernel.early-console"); + if (!dest) { + return; + } + +#ifdef KEXT_NET_DOORSTUCK_SOCKS_FBCON + if (!strcmp(dest, "tty0")) { + early_vgacon_init(); + } +#endif + +#ifdef KEXT_NET_DOORSTUCK_SOCKS_SERIALCON + if (!strncmp(dest, "ttyS0", 5)) { + /* TODO allow specifying baud rate from command line */ + unsigned int baud = 115200; + early_serialcon_init(baud); + } +#endif +} + static void init_bootfb(multiboot_info_t *mb) { __bootfb_varinfo.fb_xres = mb->framebuffer_width; @@ -109,11 +135,10 @@ int ml_init(uintptr_t arg) init_bootfb(mb); bootstrap_cpu_init(); -#ifdef KEXT_NET_DOORSTUCK_SOCKS_FBCON - early_vgacon_init(); -#endif clock_calibrate(500); + early_console_init(); + print_kernel_banner(); early_vm_init(); diff --git a/include/socks/tty.h b/include/socks/tty.h index f3ed714..be46123 100644 --- a/include/socks/tty.h +++ b/include/socks/tty.h @@ -113,6 +113,9 @@ struct tty_device { char *tty_linebuf; }; +extern void register_tty_console(void); +extern void redirect_printk_to_tty(struct device *dest); + extern kern_status_t tty_bootstrap(void); extern struct tty_ldisc *tty_default_line_discipline(void); diff --git a/init/main.c b/init/main.c index 723bac1..15fd9fe 100644 --- a/init/main.c +++ b/init/main.c @@ -1,5 +1,6 @@ #include #include +#include #include #include #include @@ -10,6 +11,7 @@ #include #include #include +#include #include #include @@ -29,7 +31,7 @@ void print_kernel_banner(void) static void hang(void) { while (1) { - //printk("tick"); + printk("%d: tick", this_cpu()); milli_sleep(2000); } } @@ -37,10 +39,10 @@ static void hang(void) void background_thread(void) { printk("background_thread() running on processor %u", this_cpu()); - milli_sleep(500); + milli_sleep(1000); while (1) { - //printk("tock"); + printk("%d: tock", this_cpu()); milli_sleep(2000); } } @@ -99,6 +101,26 @@ void kernel_init(uintptr_t arg) tty_set_foreground(cast_to_device(tty0)); } + const char *console_tty_name = arg_value("kernel.console"); + if (!console_tty_name) { + console_tty_name = "tty0"; + } + + char console_tty_path[128]; + snprintf(console_tty_path, sizeof console_tty_path, "/dev/tty/%s", console_tty_name); + + struct object *console_tty = NULL; + status = object_get(console_tty_path, &console_tty); + + if (status == KERN_OK) { + register_tty_console(); + struct device *console_tty_device = cast_to_device(console_tty); + redirect_printk_to_tty(console_tty_device); + object_deref(console_tty); + } else { + printk("console tty '%s' is unavailable.", console_tty_name); + } + create_kernel_thread(background_thread); struct object *kbd; diff --git a/kernel/tty/device.c b/kernel/tty/device.c index 1a9d5ff..53f87dc 100644 --- a/kernel/tty/device.c +++ b/kernel/tty/device.c @@ -9,10 +9,13 @@ static struct char_device_ops tty_ops = { .write = tty_write, }; -static spin_lock_t foreground_lock; +static spin_lock_t foreground_lock = SPIN_LOCK_INIT; static struct device *foreground = NULL; static struct device *foreground_input = NULL; +static spin_lock_t kernel_console_tty_lock = SPIN_LOCK_INIT; +static struct device *kernel_console_tty = NULL; + static void tty_input_hook_callback(struct device *dev, struct input_event *ev, enum input_event_hook_flags *flags, void *arg) { struct device *fg_tty = foreground; @@ -31,9 +34,9 @@ static struct input_event_hook foreground_input_hook = { static void tty_console_write(struct console *con, const char *s, unsigned int len) { - if (foreground) { + if (kernel_console_tty) { size_t nr_written; - tty_write(foreground, s, 0, len, &nr_written, 0); + tty_write(kernel_console_tty, s, 0, len, &nr_written, 0); } } @@ -42,6 +45,26 @@ static struct console tty_console = { .c_write = tty_console_write, }; +void register_tty_console(void) +{ + console_register(&tty_console); +} + +void redirect_printk_to_tty(struct device *dest) +{ + unsigned long flags; + spin_lock_irqsave(&kernel_console_tty_lock, &flags); + + if (kernel_console_tty) { + device_deref(kernel_console_tty); + kernel_console_tty = NULL; + } + + kernel_console_tty = device_ref(dest); + + spin_unlock_irqrestore(&kernel_console_tty_lock, flags); +} + struct device *tty_device_create(void) { struct char_device *cdev = char_device_create(); @@ -94,17 +117,17 @@ kern_status_t tty_device_register(struct device *dev, struct tty_driver *owner, void tty_set_foreground(struct device *tty) { - bool console_init = false; + unsigned long flags; + spin_lock_irqsave(&foreground_lock, &flags); + if (foreground) { - console_init = true; device_deref(foreground); + foreground = NULL; } foreground = device_ref(tty); - if (!console_init) { - console_register(&tty_console); - } + spin_unlock_irqrestore(&foreground_lock, flags); } kern_status_t tty_connect_foreground_input_device(struct device *input) diff --git a/kexts/drivers/tty/serialcon/serial.h b/kexts/drivers/tty/serialcon/include/socks/serialcon.h similarity index 91% rename from kexts/drivers/tty/serialcon/serial.h rename to kexts/drivers/tty/serialcon/include/socks/serialcon.h index 8daaa8b..2c5da92 100644 --- a/kexts/drivers/tty/serialcon/serial.h +++ b/kexts/drivers/tty/serialcon/include/socks/serialcon.h @@ -18,7 +18,7 @@ extern char serial_recv_byte(int device); extern int serial_rcvd(int device); -extern void serialcon_init(int baud); +extern void early_serialcon_init(int baud); #ifdef __cplusplus } diff --git a/kexts/drivers/tty/serialcon/main.c b/kexts/drivers/tty/serialcon/main.c index e364991..18576eb 100644 --- a/kexts/drivers/tty/serialcon/main.c +++ b/kexts/drivers/tty/serialcon/main.c @@ -5,7 +5,7 @@ #include #include #include -#include "serial.h" +#include #define COM1 0x3F8 #define COM2 0x2F8 @@ -155,7 +155,7 @@ static struct irq_hook irq1_hook = { .irq_callback = serial_irq1, }; -void serialcon_init(int baud) +void early_serialcon_init(int baud) { hook_irq(IRQ4, &irq1_hook); init_serial_port(COM1, baud);