:: commit 7abb7348a9e3532d916588aaff11046578f408a8

mintsuki <mintsuki@protonmail.com> — 2021-04-07 00:10

parents: 4c5ff180d7

stivale2: Implement terminal

diff --git a/stage23/fs/file.s2.c b/stage23/fs/file.s2.c
index bd7a9628..1e651390 100644
--- a/stage23/fs/file.s2.c
+++ b/stage23/fs/file.s2.c
@@ -113,7 +113,7 @@ int fread(struct file_handle *fd, void *buf, uint64_t loc, uint64_t count) {
 
 void *freadall(struct file_handle *fd, uint32_t type) {
     if (fd->is_memfile) {
-        memmap_alloc_range((uint64_t)(size_t)fd->fd, fd->size, type, false, true, false);
+        memmap_alloc_range((uint64_t)(size_t)fd->fd, fd->size, type, false, true, false, false);
         return fd->fd;
     } else {
         void *ret = ext_mem_alloc_aligned_type(fd->size, 4096, type);
diff --git a/stage23/lib/elf.c b/stage23/lib/elf.c
index e8e92854..1977c8ee 100644
--- a/stage23/lib/elf.c
+++ b/stage23/lib/elf.c
@@ -340,7 +340,7 @@ final:
 
         load_vaddr += slide;
 
-        if (!memmap_alloc_range((size_t)load_vaddr, (size_t)phdr.p_memsz, alloc_type, true, false, simulation)) {
+        if (!memmap_alloc_range((size_t)load_vaddr, (size_t)phdr.p_memsz, alloc_type, true, false, simulation, false)) {
             if (++try_count == max_simulated_tries || simulation == false)
                 return -1;
             goto again;
@@ -397,7 +397,7 @@ int elf32_load(uint8_t *elf, uint32_t *entry_point, uint32_t alloc_type) {
         if (phdr.p_type != PT_LOAD)
             continue;
 
-        memmap_alloc_range((size_t)phdr.p_paddr, (size_t)phdr.p_memsz, alloc_type, true, true, false);
+        memmap_alloc_range((size_t)phdr.p_paddr, (size_t)phdr.p_memsz, alloc_type, true, true, false, false);
 
         memcpy((void *)(uintptr_t)phdr.p_paddr, elf + (phdr.p_offset), phdr.p_filesz);
 
diff --git a/stage23/lib/fb.c b/stage23/lib/fb.c
index c51107cf..f3a66033 100644
--- a/stage23/lib/fb.c
+++ b/stage23/lib/fb.c
@@ -4,14 +4,23 @@
 #include <lib/fb.h>
 #include <drivers/vbe.h>
 #include <drivers/gop.h>
+#include <mm/pmm.h>
 
 bool fb_init(struct fb_info *ret,
              uint16_t target_width, uint16_t target_height, uint16_t target_bpp) {
+    bool r;
+
 #if defined (bios)
-    return init_vbe(ret, target_width, target_height, target_bpp);
+    r = init_vbe(ret, target_width, target_height, target_bpp);
 #elif defined (uefi)
-    return init_gop(ret, target_width, target_height, target_bpp);
+    r = init_gop(ret, target_width, target_height, target_bpp);
 #endif
+
+    memmap_alloc_range(ret->framebuffer_addr,
+                       (uint64_t)ret->framebuffer_pitch * ret->framebuffer_height,
+                       MEMMAP_FRAMEBUFFER, false, false, false, true);
+
+    return r;
 }
 
 void fb_clear(struct fb_info *fb) {
diff --git a/stage23/lib/gterm.c b/stage23/lib/gterm.c
index f9d1e73e..3a03acff 100644
--- a/stage23/lib/gterm.c
+++ b/stage23/lib/gterm.c
@@ -15,7 +15,7 @@
 #define VGA_FONT_GLYPHS 256
 #define VGA_FONT_MAX    (VGA_FONT_HEIGHT * VGA_FONT_GLYPHS)
 
-static struct fb_info fbinfo;
+struct fb_info fbinfo;
 static uint32_t *gterm_framebuffer;
 static uint16_t  gterm_pitch;
 static uint16_t  gterm_width;
diff --git a/stage23/lib/gterm.h b/stage23/lib/gterm.h
index 65b7565c..382b85b9 100644
--- a/stage23/lib/gterm.h
+++ b/stage23/lib/gterm.h
@@ -6,6 +6,8 @@
 #include <lib/image.h>
 #include <drivers/vbe.h>
 
+extern struct fb_info fbinfo;
+
 bool gterm_init(int *rows, int *cols, uint32_t *colours, int margin,
                 int margin_gradient, struct image *background);
 
diff --git a/stage23/mm/pmm.h b/stage23/mm/pmm.h
index 5d3d057c..251c4aa1 100644
--- a/stage23/mm/pmm.h
+++ b/stage23/mm/pmm.h
@@ -14,6 +14,7 @@
 #define MEMMAP_BAD_MEMORY             5
 #define MEMMAP_BOOTLOADER_RECLAIMABLE 0x1000
 #define MEMMAP_KERNEL_AND_MODULES     0x1001
+#define MEMMAP_FRAMEBUFFER            0x1002
 #define MEMMAP_EFI_RECLAIMABLE        0x2000
 
 extern size_t bump_allocator_base;
@@ -25,7 +26,7 @@ extern size_t memmap_entries;
 void init_memmap(void);
 struct e820_entry_t *get_memmap(size_t *entries);
 void print_memmap(struct e820_entry_t *mm, size_t size);
-bool memmap_alloc_range(uint64_t base, uint64_t length, uint32_t type, bool free_only, bool panic, bool simulation);
+bool memmap_alloc_range(uint64_t base, uint64_t length, uint32_t type, bool free_only, bool panic, bool simulation, bool new_entry);
 
 void *ext_mem_alloc(size_t count);
 void *ext_mem_alloc_type(size_t count, uint32_t type);
diff --git a/stage23/mm/pmm.s2.c b/stage23/mm/pmm.s2.c
index d39bbaea..1f54e2d7 100644
--- a/stage23/mm/pmm.s2.c
+++ b/stage23/mm/pmm.s2.c
@@ -342,7 +342,7 @@ void init_memmap(void) {
 
     memmap_alloc_range(bump_allocator_base,
                        bump_allocator_limit - bump_allocator_base,
-                       MEMMAP_REMOVE_RANGE, true, true, false);
+                       MEMMAP_REMOVE_RANGE, true, true, false, false);
 
     print("pmm: Conventional mem allocator base:  %X\n", bump_allocator_base);
     print("pmm: Conventional mem allocator limit: %X\n", bump_allocator_limit);
@@ -399,7 +399,7 @@ void *ext_mem_alloc_aligned_type(size_t count, size_t alignment, uint32_t type)
 
         // We now reserve the range we need.
         int64_t aligned_length = entry_top - alloc_base;
-        memmap_alloc_range((uint64_t)alloc_base, (uint64_t)aligned_length, type, true, true, false);
+        memmap_alloc_range((uint64_t)alloc_base, (uint64_t)aligned_length, type, true, true, false, false);
 
         void *ret = (void *)(size_t)alloc_base;
 
@@ -414,7 +414,7 @@ void *ext_mem_alloc_aligned_type(size_t count, size_t alignment, uint32_t type)
     panic("High memory allocator: Out of memory");
 }
 
-bool memmap_alloc_range(uint64_t base, uint64_t length, uint32_t type, bool free_only, bool do_panic, bool simulation) {
+bool memmap_alloc_range(uint64_t base, uint64_t length, uint32_t type, bool free_only, bool do_panic, bool simulation, bool new_entry) {
     if (length == 0)
         return true;
 
@@ -499,8 +499,19 @@ bool memmap_alloc_range(uint64_t base, uint64_t length, uint32_t type, bool free
         }
     }
 
-    if (do_panic)
+    if (!new_entry && do_panic)
         panic("Out of memory");
 
+    if (new_entry) {
+        if (memmap_entries >= MEMMAP_MAX_ENTRIES)
+            panic("Memory map exhausted.");
+
+        struct e820_entry_t *target = &memmap[memmap_entries++];
+
+        target->type = type;
+        target->base = base;
+        target->length = length;
+    }
+
     return false;
 }
diff --git a/stage23/protos/linux.c b/stage23/protos/linux.c
index 513197e1..68a61636 100644
--- a/stage23/protos/linux.c
+++ b/stage23/protos/linux.c
@@ -417,7 +417,7 @@ void linux_load(char *config, char *cmdline) {
     for (;;) {
         if (memmap_alloc_range(kernel_load_addr,
                 kernel->size - real_mode_code_size,
-                MEMMAP_BOOTLOADER_RECLAIMABLE, true, false, false))
+                MEMMAP_BOOTLOADER_RECLAIMABLE, true, false, false, false))
             break;
 
         kernel_load_addr += 0x100000;
@@ -451,7 +451,7 @@ void linux_load(char *config, char *cmdline) {
 
     for (;;) {
         if (memmap_alloc_range(modules_mem_base, size_of_all_modules,
-                               MEMMAP_BOOTLOADER_RECLAIMABLE, true, false, false))
+                               MEMMAP_BOOTLOADER_RECLAIMABLE, true, false, false, false))
             break;
         modules_mem_base -= 4096;
     }
diff --git a/stage23/protos/stivale2.c b/stage23/protos/stivale2.c
index 5d167c94..26b263ee 100644
--- a/stage23/protos/stivale2.c
+++ b/stage23/protos/stivale2.c
@@ -11,6 +11,7 @@
 #include <lib/print.h>
 #include <lib/real.h>
 #include <lib/libc.h>
+#include <lib/gterm.h>
 #include <lib/uri.h>
 #include <sys/smp.h>
 #include <sys/cpu.h>
@@ -50,6 +51,10 @@ static void append_tag(struct stivale2_struct *s, struct stivale2_tag *tag) {
     s->tags   = (uint64_t)(size_t)tag;
 }
 
+#if defined (bios)
+extern symbol stivale2_term_write_entry;
+#endif
+
 void stivale2_load(char *config, char *cmdline, bool pxe, void *efi_system_table) {
     struct file_handle *kernel_file = ext_mem_alloc(sizeof(struct file_handle));
 
@@ -261,11 +266,36 @@ void stivale2_load(char *config, char *cmdline, bool pxe, void *efi_system_table
     // Create framebuffer struct tag
     //////////////////////////////////////////////
     {
-    term_deinit();
+
+    struct fb_info *fb = NULL;
+    struct fb_info _fb;
+
+    struct stivale2_header_tag_terminal *terminal_hdr_tag = get_tag(&stivale2_hdr, STIVALE2_HEADER_TAG_TERMINAL_ID);
 
     struct stivale2_header_tag_framebuffer *hdrtag = get_tag(&stivale2_hdr, STIVALE2_HEADER_TAG_FRAMEBUFFER_ID);
 
+    if (bits == 64 && terminal_hdr_tag != NULL && current_video_mode >= 0 && hdrtag != NULL) {
+        fb = &fbinfo;
+
+        struct stivale2_struct_tag_terminal *tag = ext_mem_alloc(sizeof(struct stivale2_struct_tag_terminal));
+        tag->tag.identifier = STIVALE2_STRUCT_TAG_TERMINAL_ID;
+
+#if defined (bios)
+        tag->term_write = (uintptr_t)(void *)stivale2_term_write_entry;
+#elif defined (uefi)
+        tag->term_write = (uintptr_t)term_write;
+#endif
+
+        append_tag(&stivale2_struct, (struct stivale2_tag *)tag);
+
+        goto skip_modeset;
+    } else {
+        fb = &_fb;
+    }
+
     if (hdrtag != NULL) {
+        term_deinit();
+
         int req_width  = hdrtag->framebuffer_width;
         int req_height = hdrtag->framebuffer_height;
         int req_bpp    = hdrtag->framebuffer_bpp;
@@ -274,27 +304,27 @@ void stivale2_load(char *config, char *cmdline, bool pxe, void *efi_system_table
         if (resolution != NULL)
             parse_resolution(&req_width, &req_height, &req_bpp, resolution);
 
-        struct fb_info fbinfo;
-        if (fb_init(&fbinfo, req_width, req_height, req_bpp)) {
+        if (fb_init(fb, req_width, req_height, req_bpp)) {
+skip_modeset:;
             struct stivale2_struct_tag_framebuffer *tag = ext_mem_alloc(sizeof(struct stivale2_struct_tag_framebuffer));
             tag->tag.identifier = STIVALE2_STRUCT_TAG_FRAMEBUFFER_ID;
 
             tag->memory_model       = STIVALE2_FBUF_MMODEL_RGB;
-            tag->framebuffer_addr   = fbinfo.framebuffer_addr;
-            tag->framebuffer_width  = fbinfo.framebuffer_width;
-            tag->framebuffer_height = fbinfo.framebuffer_height;
-            tag->framebuffer_bpp    = fbinfo.framebuffer_bpp;
-            tag->framebuffer_pitch  = fbinfo.framebuffer_pitch;
-            tag->red_mask_size      = fbinfo.red_mask_size;
-            tag->red_mask_shift     = fbinfo.red_mask_shift;
-            tag->green_mask_size    = fbinfo.green_mask_size;
-            tag->green_mask_shift   = fbinfo.green_mask_shift;
-            tag->blue_mask_size     = fbinfo.blue_mask_size;
-            tag->blue_mask_shift    = fbinfo.blue_mask_shift;
+            tag->framebuffer_addr   = fb->framebuffer_addr;
+            tag->framebuffer_width  = fb->framebuffer_width;
+            tag->framebuffer_height = fb->framebuffer_height;
+            tag->framebuffer_bpp    = fb->framebuffer_bpp;
+            tag->framebuffer_pitch  = fb->framebuffer_pitch;
+            tag->red_mask_size      = fb->red_mask_size;
+            tag->red_mask_shift     = fb->red_mask_shift;
+            tag->green_mask_size    = fb->green_mask_size;
+            tag->green_mask_shift   = fb->green_mask_shift;
+            tag->blue_mask_size     = fb->blue_mask_size;
+            tag->blue_mask_shift    = fb->blue_mask_shift;
 
             append_tag(&stivale2_struct, (struct stivale2_tag *)tag);
 
-            if (get_tag(&stivale2_hdr, STIVALE2_HEADER_TAG_FB_MTRR_ID) != NULL) {
+            if (terminal_hdr_tag == NULL && get_tag(&stivale2_hdr, STIVALE2_HEADER_TAG_FB_MTRR_ID) != NULL) {
                 mtrr_restore();
                 bool ret = mtrr_set_range(tag->framebuffer_addr,
                     (uint64_t)tag->framebuffer_pitch * tag->framebuffer_height,
diff --git a/stage23/protos/stivale2_rt.asm b/stage23/protos/stivale2_rt.asm
new file mode 100644
index 00000000..8c867044
--- /dev/null
+++ b/stage23/protos/stivale2_rt.asm
@@ -0,0 +1,68 @@
+section .bss
+
+user_stack:
+    resq 1
+
+term_buf:
+    resb 1024
+
+section .text
+
+extern term_write
+
+bits 64
+global stivale2_term_write_entry
+stivale2_term_write_entry:
+    push rbx
+    push rbp
+    push r12
+    push r13
+    push r14
+    push r15
+
+    mov [user_stack], rsp
+    mov rsp, 0x7c00
+
+    push rsi
+    mov rcx, rsi
+    mov rsi, rdi
+    mov rdi, term_buf
+    rep movsb
+    pop rsi
+
+    push 0x18
+    push .mode32
+    retfq
+bits 32
+  .mode32:
+    mov eax, 0x20
+    mov ds, ax
+    mov es, ax
+    mov fs, ax
+    mov gs, ax
+    mov ss, ax
+    push esi
+    push term_buf
+    call term_write
+    add esp, 8
+    push 0x28
+    push .mode64
+    retfd
+bits 64
+  .mode64:
+    mov eax, 0x30
+    mov ds, ax
+    mov es, ax
+    mov fs, ax
+    mov gs, ax
+    mov ss, ax
+    mov rsp, [user_stack]
+
+    pop r15
+    pop r14
+    pop r13
+    pop r12
+    pop rbp
+    pop rbx
+
+    ret
diff --git a/test/e9print.c b/test/e9print.c
index f027e4ec..30450f5c 100644
--- a/test/e9print.c
+++ b/test/e9print.c
@@ -1,9 +1,13 @@
 #include <e9print.h>
 #include <stddef.h>
 
+void (*stivale2_print)(const char *buf, size_t size) = NULL;
+
 static const char CONVERSION_TABLE[] = "0123456789abcdef";
 
 void e9_putc(char c) {
+    if (stivale2_print != NULL)
+        stivale2_print(&c, 1);
     asm volatile ("out dx, al" :: "a" (c), "d" (0xE9) : "memory");
 }
 
@@ -70,7 +74,7 @@ void e9_printf(const char *format, ...) {
                 e9_printdec(va_arg(argp, size_t));
             } else if (*format == 's') {
                 e9_print(va_arg(argp, char*));
-            } 
+            }
         } else {
             e9_putc(*format);
         }
diff --git a/test/e9print.h b/test/e9print.h
index 44ac8e2f..052dbac4 100644
--- a/test/e9print.h
+++ b/test/e9print.h
@@ -1,6 +1,9 @@
 #pragma once
 
 #include <stdarg.h>
+#include <stddef.h>
+
+extern void (*stivale2_print)(const char *buf, size_t size);
 
 void e9_putc(char c);
 void e9_print(const char *msg);
diff --git a/test/stivale2.c b/test/stivale2.c
index 04711887..2ad1be1c 100644
--- a/test/stivale2.c
+++ b/test/stivale2.c
@@ -7,10 +7,18 @@ typedef uint8_t stack[4096];
 static stack stacks[10] = {0};
 void stivale2_main(struct stivale2_struct *info);
 
+struct stivale2_header_tag_terminal terminal_request = {
+    .tag = {
+        .identifier = STIVALE2_HEADER_TAG_TERMINAL_ID,
+        .next       = 0
+    },
+    .flags = 0
+};
+
 struct stivale2_header_tag_smp smp_request = {
     .tag = {
         .identifier = STIVALE2_HEADER_TAG_SMP_ID,
-        .next       = 0
+        .next       = (uint64_t)&terminal_request
     },
     .flags = 0
 };
@@ -41,92 +49,110 @@ struct stivale2_header header2 = {
 static volatile int cpu_up = 0;
 
 static void ap_entry(struct stivale2_smp_info *s) {
-    e9_printf("\t\t\tAP %d started", s->lapic_id);
+    e9_printf("            AP %d started", s->lapic_id);
     cpu_up = 1;
     for (;;) asm("hlt");
 }
 
 void stivale2_main(struct stivale2_struct *info) {
+    // Print the tags.
+    struct stivale2_tag *tag = (struct stivale2_tag *)info->tags;
+
+    while (tag != NULL) {
+        if (tag->identifier == STIVALE2_STRUCT_TAG_TERMINAL_ID) {
+            struct stivale2_struct_tag_terminal *t = (void *)tag;
+            stivale2_print = (void *)(uintptr_t)t->term_write;
+        }
+        tag = (void *)tag->next;
+    }
+
     // Print stuff.
     e9_puts("Stivale2 info passed to the kernel:");
     e9_printf("Bootloader brand:   %s", info->bootloader_brand);
     e9_printf("Bootloader version: %s", info->bootloader_version);
 
     // Print the tags.
-    struct stivale2_tag *tag = (struct stivale2_tag *)info->tags;
+    tag = (struct stivale2_tag *)info->tags;
 
     while (tag != NULL) {
         switch (tag->identifier) {
             case STIVALE2_STRUCT_TAG_CMDLINE_ID: {
                 struct stivale2_struct_tag_cmdline *c = (struct stivale2_struct_tag_cmdline *)tag;
                 e9_puts("Commandline tag:");
-                e9_printf("\tCmdline: %s", (char*)(c->cmdline));
+                e9_printf("    Cmdline: %s", (char*)(c->cmdline));
                 break;
             }
             case STIVALE2_STRUCT_TAG_MEMMAP_ID: {
                 struct stivale2_struct_tag_memmap *m = (struct stivale2_struct_tag_memmap *)tag;
                 e9_puts("Memmap tag:");
-                e9_printf("\tEntries: %d", m->entries);
+                e9_printf("    Entries: %d", m->entries);
                 for (size_t i = 0; i < m->entries; i++) {
                     struct stivale2_mmap_entry me = m->memmap[i];
-                    e9_printf("\t\t[%x+%x] %x", me.base, me.length, me.type);
+                    e9_printf("        [%x+%x] %x", me.base, me.length, me.type);
                 }
                 break;
             }
             case STIVALE2_STRUCT_TAG_FRAMEBUFFER_ID: {
                 struct stivale2_struct_tag_framebuffer *f = (struct stivale2_struct_tag_framebuffer *)tag;
                 e9_puts("Framebuffer tag:");
-                e9_printf("\tAddress: %x", f->framebuffer_addr);
-                e9_printf("\tWidth:   %d", f->framebuffer_width);
-                e9_printf("\tHeight:  %d", f->framebuffer_height);
-                e9_printf("\tPitch:   %d", f->framebuffer_pitch);
-                e9_printf("\tBPP:     %d", f->framebuffer_bpp);
-                e9_printf("\tMemory model:    %d", f->memory_model);
-                e9_printf("\tRed mask size:   %d", f->red_mask_size);
-                e9_printf("\tRed mask size:   %d", f->red_mask_shift);
-                e9_printf("\tGreen mask size: %d", f->green_mask_size);
-                e9_printf("\tGreen mask size: %d", f->green_mask_shift);
-                e9_printf("\tBlue mask size:  %d", f->blue_mask_size);
-                e9_printf("\tBlue mask size:  %d", f->blue_mask_shift);
+                e9_printf("    Address: %x", f->framebuffer_addr);
+                e9_printf("    Width:   %d", f->framebuffer_width);
+                e9_printf("    Height:  %d", f->framebuffer_height);
+                e9_printf("    Pitch:   %d", f->framebuffer_pitch);
+                e9_printf("    BPP:     %d", f->framebuffer_bpp);
+                e9_printf("    Memory model:    %d", f->memory_model);
+                e9_printf("    Red mask size:   %d", f->red_mask_size);
+                e9_printf("    Red mask size:   %d", f->red_mask_shift);
+                e9_printf("    Green mask size: %d", f->green_mask_size);
+                e9_printf("    Green mask size: %d", f->green_mask_shift);
+                e9_printf("    Blue mask size:  %d", f->blue_mask_size);
+                e9_printf("    Blue mask size:  %d", f->blue_mask_shift);
                 break;
             }
             case STIVALE2_STRUCT_TAG_EDID_ID: {
                 struct stivale2_struct_tag_edid *edid = (struct stivale2_struct_tag_edid *)tag;
 
                 e9_printf("EDID information at %x:", edid->edid_information);
-                e9_printf("\tSize: %d", edid->edid_size);
+                e9_printf("    Size: %d", edid->edid_size);
             }
             case STIVALE2_STRUCT_TAG_FB_MTRR_ID: {
                 e9_puts("Framebuffer WC MTRR tag:");
-                e9_puts("\tFramebuffer WC MTRR enabled");
+                e9_puts("    Framebuffer WC MTRR enabled");
+                break;
+            }
+            case STIVALE2_STRUCT_TAG_TERMINAL_ID: {
+                struct stivale2_struct_tag_terminal *term = (struct stivale2_struct_tag_terminal *)tag;
+
+                e9_puts("Terminal tag:");
+                e9_printf("    Terminal write entry point at: %x", term->term_write);
                 break;
             }
             case STIVALE2_STRUCT_TAG_MODULES_ID: {
                 struct stivale2_struct_tag_modules *m = (struct stivale2_struct_tag_modules *)tag;
                 e9_puts("Modules tag:");
-                e9_printf("\tCount: %d", m->module_count);
+                e9_printf("    Count: %d", m->module_count);
                 for (size_t i = 0; i < m->module_count; i++) {
                     struct stivale2_module me = m->modules[i];
-                    e9_printf("\t\t[%x+%x] %s", me.begin, me.end, me.string);
+                    e9_printf("        [%x+%x] %s", me.begin, me.end, me.string);
                 }
                 break;
             }
             case STIVALE2_STRUCT_TAG_RSDP_ID: {
                 struct stivale2_struct_tag_rsdp *r = (struct stivale2_struct_tag_rsdp *)tag;
                 e9_puts("RSDP tag:");
-                e9_printf("\tRSDP: %x", r->rsdp);
+                e9_printf("    RSDP: %x", r->rsdp);
                 break;
             }
             case STIVALE2_STRUCT_TAG_EPOCH_ID: {
                 struct stivale2_struct_tag_epoch *e = (struct stivale2_struct_tag_epoch *)tag;
                 e9_puts("Epoch tag:");
-                e9_printf("\tEpoch: %x", e->epoch);
+                e9_printf("    Epoch: %x", e->epoch);
                 break;
             }
             case STIVALE2_STRUCT_TAG_FIRMWARE_ID: {
                 struct stivale2_struct_tag_firmware *f = (struct stivale2_struct_tag_firmware *)tag;
                 e9_puts("Firmware tag:");
-                e9_printf("\tFlags: %x", f->flags);
+                e9_printf("    Flags: %x", f->flags);
                 break;
             }
             case STIVALE2_STRUCT_TAG_EFI_SYSTEM_TABLE_ID: {
@@ -147,16 +173,16 @@ void stivale2_main(struct stivale2_struct *info) {
             case STIVALE2_STRUCT_TAG_SMP_ID: {
                 struct stivale2_struct_tag_smp *s = (struct stivale2_struct_tag_smp *)tag;
                 e9_puts("SMP tag:");
-                e9_printf("\tFlags:        %x", s->flags);
-                e9_printf("\tBSP LAPIC ID: %d", s->bsp_lapic_id);
-                e9_printf("\tCPU Count:    %d", s->cpu_count);
+                e9_printf("    Flags:        %x", s->flags);
+                e9_printf("    BSP LAPIC ID: %d", s->bsp_lapic_id);
+                e9_printf("    CPU Count:    %d", s->cpu_count);
                 for (size_t i = 0; i < s->cpu_count; i++) {
                     struct stivale2_smp_info *in = &s->smp_info[i];
-                    e9_printf("\t\tProcessor ID:   %d", in->processor_id);
-                    e9_printf("\t\tLAPIC ID:       %d", in->lapic_id);
-                    e9_printf("\t\tTarget Stack:   %x", in->target_stack);
-                    e9_printf("\t\tGOTO Address:   %x", in->goto_address);
-                    e9_printf("\t\tExtra Argument: %x", in->extra_argument);
+                    e9_printf("        Processor ID:   %d", in->processor_id);
+                    e9_printf("        LAPIC ID:       %d", in->lapic_id);
+                    e9_printf("        Target Stack:   %x", in->target_stack);
+                    e9_printf("        GOTO Address:   %x", in->goto_address);
+                    e9_printf("        Extra Argument: %x", in->extra_argument);
                     if (in->lapic_id != s->bsp_lapic_id) {
                         in->target_stack = (uintptr_t)stacks[in->lapic_id] + sizeof(stack);
                         in->goto_address = (uintptr_t)ap_entry;
@@ -167,7 +193,7 @@ void stivale2_main(struct stivale2_struct *info) {
                 break;
             }
             default:
-                e9_printf("BUG: Unidentifier tag %x", tag->identifier);
+                e9_printf("BUG: Unidentified tag %x", tag->identifier);
         }
 
         tag = (struct stivale2_tag *)tag->next;
tab: 248 wrap: offon