diff --git a/kernel/core/main.c b/kernel/core/main.c index 70b87ba..2381433 100644 --- a/kernel/core/main.c +++ b/kernel/core/main.c @@ -1,6 +1,7 @@ #include "types.h" #include "defs.h" #include "vt.h" +#include "gfx.h" #include "param.h" #include "memlayout.h" #include "mmu.h" @@ -31,6 +32,46 @@ kmain(uint32 fb_addr) { boot_verbose = *(uchar*)P2V(SCHBOOT_VERBOSE_FLAG); + // On a verbose boot, put the kernel log on the screen from the first line. + // + // Everything below talks to the serial port and nothing else until the first + // exec calls console_takeover(). That is fine on a machine with a UART and + // useless on one without -- and a laptop, a Chromebox, anything built this + // century has no 16550 at 0x3f8. The screen showed the loader's progress bar + // and then nothing at all, for the whole of boot, on exactly the machines + // where something was going wrong. + // + // The loader has already put a framebuffer on the screen and described it in + // the boot block, so there is a perfectly good console sitting there unused. + // Attaching it here costs one struct and makes the difference between "it + // froze" and knowing which line it froze after. + // + // Unconditional, not just on a verbose boot. F8 is no use to someone whose + // machine resets before they can read anything, and "it froze after the + // loading bar" is a bug report nobody can act on. This is what Linux does + // too: the log is the default and `quiet splash` is the thing you ask for. + // + // The splash stays on screen until the kernel's first message, and a boot + // that succeeds clears the whole lot when the first program starts -- so + // the only time anyone sees this is the only time anyone needs it. + { + struct fb_info bi; + bi.ptr = (volatile uchar *)P2V((uint64)*(uint32*)P2V(SCHBOOT_VBE_LFB)); + bi.width = *(uint16*)P2V(SCHBOOT_VBE_WIDTH); + bi.height = *(uint16*)P2V(SCHBOOT_VBE_HEIGHT); + bi.stride = *(uint16*)P2V(SCHBOOT_VBE_STRIDE); + bi.bpp = *(uchar *)P2V(SCHBOOT_VBE_BPP); + // Only if the loader actually described something. A zero here means the + // BIOS path or a firmware that gave no GOP, and drawing into address zero + // is a worse failure than staying quiet. + if (bi.ptr && bi.width && bi.height && bi.stride && bi.bpp >= 16) { + gfx_attach_scanout(&bi); + vt_init(); + gfx_clear(0x0C0E13); /* SCH_BG; theme.h is not included here */ + cons_serial_only = 0; + } + } + uartearlyinit(); if (boot_verbose) cprintf("verbose boot: uartearlyinit done\n"); // The DMA arena is carved off the top of physical memory *before* kalloc is diff --git a/kernel/dev/vt.c b/kernel/dev/vt.c index 87d5dca..ba30635 100644 --- a/kernel/dev/vt.c +++ b/kernel/dev/vt.c @@ -140,6 +140,15 @@ void vt_init(void) { int cols, rows; + + // Idempotent. A verbose boot brings the terminals up early, before the PCI + // bus is walked, so that the kernel log has somewhere to go; main() then + // calls this again in its usual place. The second call must not wipe six + // screens of boot messages. + if (vt_ready) { + vt_resize(); + return; + } measure(&cols, &rows); for (int i = 0; i < NVT; i++) {