Add early VGA boot diagnostics for UTM debugging
Write boot milestones directly to VGA text buffer (0xB8000) at each init stage so the user can see exactly where the kernel stops on platforms where the VGA driver may not initialize. Milestones: Magic OK, GDT, IDT, PIC, PMM, PAGING, HEAP, CPIO, VFS, INITRD, TSS. Each appears as white-on-blue text. If the multiboot2 magic check fails, display the received magic value in red-on-white on screen and halt (instead of silently returning). This helps diagnose if GRUB matched the multiboot1 header instead.
This commit is contained in:
58
src/kernel.c
58
src/kernel.c
@@ -69,36 +69,65 @@ void kernel_main(uint32_t magic, uint32_t addr) {
|
||||
/* Initialize serial port first so all debug output goes to COM1 too */
|
||||
serial_init();
|
||||
|
||||
/* Early canary: write directly to VGA text buffer at 0xB8000.
|
||||
* If the display is in text mode, this will show a bright magenta 'C'
|
||||
* in the top-left corner before any subsystem is initialized. */
|
||||
{
|
||||
volatile uint16_t *vga = (volatile uint16_t *)0xB8000;
|
||||
vga[0] = (uint16_t)'C' | (0x5F << 8); /* magenta on magenta = visible block */
|
||||
vga[1] = (uint16_t)'O' | (0x5F << 8);
|
||||
vga[2] = (uint16_t)'S' | (0x5F << 8);
|
||||
}
|
||||
/* Early VGA: write directly to the text buffer at 0xB8000 for boot
|
||||
* progress that is visible even without the VGA driver initialized.
|
||||
* Attribute 0x1F = white on blue. */
|
||||
volatile uint16_t *early_vga = (volatile uint16_t *)0xB8000;
|
||||
int early_pos = 0;
|
||||
|
||||
/* Helper macro: write a short string to early VGA */
|
||||
#define EARLY_PRINT(s) do { \
|
||||
const char *_p = (s); \
|
||||
while (*_p) { \
|
||||
early_vga[early_pos++] = (uint16_t)(unsigned char)*_p | (0x1F << 8); \
|
||||
_p++; \
|
||||
} \
|
||||
} while(0)
|
||||
|
||||
/* Clear screen to blue */
|
||||
for (int i = 0; i < 80 * 25; i++)
|
||||
early_vga[i] = (uint16_t)' ' | (0x1F << 8);
|
||||
|
||||
EARLY_PRINT("ClaudeOS early boot");
|
||||
early_pos = 80; /* Move to line 2 */
|
||||
|
||||
if (magic != MULTIBOOT2_BOOTLOADER_MAGIC) {
|
||||
EARLY_PRINT("ERROR: Bad magic=0x");
|
||||
/* Print magic in hex */
|
||||
const char *hex = "0123456789ABCDEF";
|
||||
for (int i = 28; i >= 0; i -= 4)
|
||||
early_vga[early_pos++] = (uint16_t)(unsigned char)hex[(magic >> i) & 0xF] | (0x4F << 8);
|
||||
early_pos = 80 * 3;
|
||||
EARLY_PRINT("Expected 0x36D76289 (Multiboot2)");
|
||||
early_pos = 80 * 4;
|
||||
EARLY_PRINT("Got MB1 magic? Checking grub.cfg...");
|
||||
|
||||
offset_print("Invalid magic number: ");
|
||||
print_hex(magic);
|
||||
return;
|
||||
|
||||
/* Hang with interrupts disabled so user can see the message */
|
||||
for (;;) __asm__ volatile("hlt");
|
||||
}
|
||||
|
||||
EARLY_PRINT("Magic OK ");
|
||||
offset_print("Booting...\n");
|
||||
|
||||
init_gdt();
|
||||
EARLY_PRINT("GDT ");
|
||||
offset_print("GDT initialized\n");
|
||||
|
||||
init_idt();
|
||||
EARLY_PRINT("IDT ");
|
||||
offset_print("IDT initialized\n");
|
||||
|
||||
init_pic();
|
||||
/* Unmask timer IRQ (IRQ0) explicitly */
|
||||
pic_clear_mask(0);
|
||||
EARLY_PRINT("PIC ");
|
||||
offset_print("PIC initialized\n");
|
||||
|
||||
init_pmm(addr);
|
||||
EARLY_PRINT("PMM ");
|
||||
offset_print("PMM initialized\n");
|
||||
|
||||
/* Scan Multiboot2 tags for the initrd module and framebuffer info */
|
||||
@@ -152,6 +181,7 @@ void kernel_main(uint32_t magic, uint32_t addr) {
|
||||
}
|
||||
|
||||
init_paging();
|
||||
EARLY_PRINT("PAGING ");
|
||||
offset_print("Paging initialized\n");
|
||||
|
||||
/* If GRUB provided a graphical framebuffer, identity-map it so
|
||||
@@ -182,21 +212,25 @@ void kernel_main(uint32_t magic, uint32_t addr) {
|
||||
}
|
||||
|
||||
init_kmalloc();
|
||||
EARLY_PRINT("HEAP ");
|
||||
offset_print("Memory allocator initialized\n");
|
||||
|
||||
/* Initialize CPIO ramdisk if module was loaded */
|
||||
if (initrd_start != 0) {
|
||||
cpio_init((const void *)initrd_start, initrd_end - initrd_start);
|
||||
EARLY_PRINT("CPIO ");
|
||||
offset_print("CPIO ramdisk initialized\n");
|
||||
} else {
|
||||
offset_print("No initrd module found\n");
|
||||
}
|
||||
|
||||
init_vfs();
|
||||
EARLY_PRINT("VFS ");
|
||||
offset_print("VFS initialized\n");
|
||||
|
||||
if (initrd_start != 0) {
|
||||
init_initrd_fs();
|
||||
EARLY_PRINT("INITRD ");
|
||||
offset_print("Initrd filesystem mounted\n");
|
||||
|
||||
/* Test VFS: read a file from the initrd */
|
||||
@@ -214,6 +248,7 @@ void kernel_main(uint32_t magic, uint32_t addr) {
|
||||
}
|
||||
|
||||
init_tss();
|
||||
EARLY_PRINT("TSS ");
|
||||
offset_print("TSS initialized\n");
|
||||
|
||||
init_syscalls();
|
||||
@@ -228,6 +263,9 @@ void kernel_main(uint32_t magic, uint32_t addr) {
|
||||
init_drivers();
|
||||
offset_print("Drivers initialized\n");
|
||||
|
||||
/* At this point the VGA driver has been initialized and taken over
|
||||
* the display. The early VGA text is no longer visible. */
|
||||
|
||||
/* Show memory statistics and boot progress on VGA */
|
||||
vga_show_mem_stats();
|
||||
vga_puts("Boot complete.\n\n");
|
||||
|
||||
Reference in New Issue
Block a user