klange / toaruos

A completely-from-scratch hobby operating system: bootloader, kernel, drivers, C library, and userspace including a composited graphical UI, dynamic linker, syntax-highlighting text editor, network stack, etc.
https://toaruos.org/
University of Illinois/NCSA Open Source License
6.09k stars 477 forks source link

View printf's by kernel #198

Closed JetStarBlues closed 3 years ago

JetStarBlues commented 3 years ago

As the system starts up, a bunch of things are printed to the screen. However, they fly by too fast to be able to read them. Is there somewhere these messages are stored?

Or alternatively, is there a way to open a second terminal when running the ISO with QEMU, that can receive these messages?

For example, all the messages outputted by debug_print when executing kernel/main.c.

klange commented 3 years ago

Messages from the kernel using debug_print are not shown by default and do not get displayed on the screen anyway. All the kernel debug messages go to serial (which can be printed to your host terminal with either -serial stdio, or I find -serial mon:stdio more useful), if you have them enabled (check "Debug output" in the boot menu; "Debug on serial" is not necessary, that's for the kdebug shell). There are also some early debug_print calls which happen before the command-line boot parameters for the kernel are read, which require the kernel to be modified and rebuilt to enable, but they track very low-level early startup processes and aren't very interesting.

The only messages on startup displayed on the screen are the boot progress messages, which primarily consist of the names of files being copied from the static ramdisk into a modifiable tmpfs by the migrate userspace application. Those are printed, either to the framebuffer or the VGA text mode character memory directly, by the splash-log daemon which uses a pex socket to receive messages from the startup scripts (/dev/pex/splash; the scripts just call echo -n "Some message" >> /dev/pex/splash).

I haven't implemented a mechanism for these messages to be written to serial, but it could be a quick check of a boot parameter and an addition of write of each update message to /dev/ttyS0; they are intended to allow for quick debugging of boot stages if things freeze in the middle, but aren't a log that should need to be read. If you boot the OS in something slow like bochs you can probably read them in real time. Even QEMU without KVM should be slow enough if you can read quickly (or record a video and look frame-by-frame).

Here's a simple patch to write the splash messages to serial, and here is sample output.

diff --git a/apps/splash-log.c b/apps/splash-log.c
index e5fcab14..8b44e4f8 100644
--- a/apps/splash-log.c
+++ b/apps/splash-log.c
@@ -18,6 +18,8 @@

 #include "terminal-font.h"

+static FILE * serial;
+
 /**
  * For legacy backwards-compatibility reasons, the VGA
  * text-mode window is normalled mapped 1:1. If this
@@ -65,6 +67,7 @@ static void write_char(int x, int y, int val, uint32_t color) {
 }

 static void update_message(char * c, int line) {
+   if (serial && *c) fprintf(serial, "%s%s\n", (line == 1) ? "> " : "", c);
    if (framebuffer_fd != -1) {
        int x = 20;
        int y = 20 + char_height * line;
@@ -135,6 +138,8 @@ int main(int argc, char * argv[]) {
        return 1;
    }

+   serial = fopen("/dev/ttyS0","w");
+
    open_socket();

    if (!fork()) {
JetStarBlues commented 3 years ago

Thank you for the very detailed reply! I was able to replicate it locally (and learn a bit about how things work).

There are also some early debug_print calls which happen before the command-line boot parameters for the kernel are read, which require the kernel to be modified and rebuilt to enable

How exactly would you do this? Is it a few lines that need to be changed?

klange commented 3 years ago

How exactly would you do this? Is it a few lines that need to be changed?

In kernel/main.c there is a line #ifdef EARLY_BOOT_LOG - insert #define EARLY_BOOT_LOG before that and rebuild. It uses a QEMU/Bochs-specific debug routine rather than serial until the kernel command line arguments are read from the bootloader and logs at the INFO level.

JetStarBlues commented 3 years ago

I see. Thank you!