:: commit 8c0c36ea74951187ac7c7ad0e3f381e4e14e3f03

mintsuki <mintsuki@protonmail.com> — 2021-03-01 22:38

parents: 659a6afa18

misc: Change the way stage 2 and 3 are divided

diff --git a/stage23/Makefile b/stage23/Makefile
index 60d4f932..fb312a9f 100644
--- a/stage23/Makefile
+++ b/stage23/Makefile
@@ -66,10 +66,10 @@ limine.sys: limine.elf
 	$(OBJCOPY) -O binary $< $@
 
 limine_nomap.elf: $(OBJ)
-	$(LD) $(OBJ) $(LDFLAGS) $(INTERNAL_LDFLAGS) -Wl,--gc-sections -Tlinker_stage2only.ld -o $@ || \
+	$(LD) $(OBJ) $(LDFLAGS) $(INTERNAL_LDFLAGS) -Tlinker_nomap.ld -o $@
+	$(LD) $(OBJ) $(LDFLAGS) $(INTERNAL_LDFLAGS) -Wl,--gc-sections -Tlinker_stage2only.ld -o limine_stage2only.elf || \
 		( echo "This error means that stage 2 was trying to use stage 3 symbols before loading stage 3" && \
 		  false )
-	$(LD) $(OBJ) $(LDFLAGS) $(INTERNAL_LDFLAGS) -Tlinker_nomap.ld -o $@
 
 limine.elf: $(OBJ) limine.map.o
 	$(LD) $(OBJ) limine.map.o $(LDFLAGS) $(INTERNAL_LDFLAGS) -Tlinker.ld -o $@
diff --git a/stage23/drivers/disk.c b/stage23/drivers/disk.s2.c
similarity index 100%
rename from stage23/drivers/disk.c
rename to stage23/drivers/disk.s2.c
diff --git a/stage23/drivers/vbe.c b/stage23/drivers/vbe.c
index 5d2e7df2..d5b2f5cf 100644
--- a/stage23/drivers/vbe.c
+++ b/stage23/drivers/vbe.c
@@ -17,9 +17,9 @@
 #define VGA_FONT_GLYPHS 256
 #define VGA_FONT_MAX    (VGA_FONT_HEIGHT * VGA_FONT_GLYPHS)
 
-stage3_data static uint8_t *vga_font;
+static uint8_t *vga_font;
 
-stage3_text static void vga_font_retrieve(void) {
+static void vga_font_retrieve(void) {
     struct rm_regs r = {0};
 
     r.eax = 0x1130;
@@ -31,37 +31,37 @@ stage3_text static void vga_font_retrieve(void) {
     memcpy(vga_font, (void *)rm_desegment(r.es, r.ebp), VGA_FONT_MAX);
 }
 
-stage3_data static uint32_t ansi_colours[8];
+static uint32_t ansi_colours[8];
 
-stage3_data static struct vbe_framebuffer_info fbinfo;
-stage3_data static uint32_t *vbe_framebuffer;
-stage3_data static uint16_t  vbe_pitch;
-stage3_data static uint16_t  vbe_width;
-stage3_data static uint16_t  vbe_height;
-stage3_data static uint16_t  vbe_bpp;
+static struct vbe_framebuffer_info fbinfo;
+static uint32_t *vbe_framebuffer;
+static uint16_t  vbe_pitch;
+static uint16_t  vbe_width;
+static uint16_t  vbe_height;
+static uint16_t  vbe_bpp;
 
-stage3_data static int frame_height, frame_width;
+static int frame_height, frame_width;
 
-stage3_data static struct image *background;
+static struct image *background;
 
-stage3_data static struct vbe_char *grid;
-stage3_data static struct vbe_char *front_grid;
+static struct vbe_char *grid;
+static struct vbe_char *front_grid;
 
-stage3_data static bool double_buffer_enabled = false;
+static bool double_buffer_enabled = false;
 
-stage3_data static bool cursor_status = true;
+static bool cursor_status = true;
 
-stage3_data static int cursor_x;
-stage3_data static int cursor_y;
+static int cursor_x;
+static int cursor_y;
 
-stage3_data static uint32_t cursor_fg = 0x00000000;
-stage3_data static uint32_t cursor_bg = 0x00ffffff;
-stage3_data static uint32_t text_fg;
-stage3_data static uint32_t text_bg;
+static uint32_t cursor_fg = 0x00000000;
+static uint32_t cursor_bg = 0x00ffffff;
+static uint32_t text_fg;
+static uint32_t text_bg;
 
-stage3_data static int rows;
-stage3_data static int cols;
-stage3_data static int margin_gradient;
+static int rows;
+static int cols;
+static int margin_gradient;
 
 #define A(rgb) (uint8_t)(rgb >> 24)
 #define R(rgb) (uint8_t)(rgb >> 16)
@@ -69,7 +69,7 @@ stage3_data static int margin_gradient;
 #define B(rgb) (uint8_t)(rgb)
 #define ARGB(a, r, g, b) (a << 24) | ((r & 0xFF) << 16) | ((g & 0xFF) << 8) | (b & 0xFF)
 
-stage3_text static inline uint32_t colour_blend(uint32_t fg, uint32_t bg) {
+static inline uint32_t colour_blend(uint32_t fg, uint32_t bg) {
     unsigned alpha = 255 - A(fg);
     unsigned inv_alpha = A(fg) + 1;
 
@@ -80,19 +80,19 @@ stage3_text static inline uint32_t colour_blend(uint32_t fg, uint32_t bg) {
     return ARGB(0, r, g, b);
 }
 
-stage3_text void vbe_plot_px(int x, int y, uint32_t hex) {
+void vbe_plot_px(int x, int y, uint32_t hex) {
     size_t fb_i = x + (vbe_pitch / sizeof(uint32_t)) * y;
 
     vbe_framebuffer[fb_i] = hex;
 }
 
-stage3_text static void _vbe_plot_bg_blent_px(int x, int y, uint32_t hex) {
+static void _vbe_plot_bg_blent_px(int x, int y, uint32_t hex) {
     vbe_plot_px(x, y, colour_blend(hex, background->get_pixel(background, x, y)));
 }
 
-stage3_data void (*vbe_plot_bg_blent_px)(int x, int y, uint32_t hex) = vbe_plot_px;
+void (*vbe_plot_bg_blent_px)(int x, int y, uint32_t hex) = vbe_plot_px;
 
-stage3_text static uint32_t blend_gradient_from_box(int x, int y, uint32_t hex) {
+static uint32_t blend_gradient_from_box(int x, int y, uint32_t hex) {
     if (x >= frame_width  && x < frame_width  + VGA_FONT_WIDTH  * cols
      && y >= frame_height && y < frame_height + VGA_FONT_HEIGHT * rows) {
         return hex;
@@ -133,7 +133,7 @@ stage3_text static uint32_t blend_gradient_from_box(int x, int y, uint32_t hex)
     return colour_blend((hex & 0xffffff) | (new_alpha << 24), bg_px);
 }
 
-stage3_text void vbe_plot_background(int x, int y, int width, int height) {
+void vbe_plot_background(int x, int y, int width, int height) {
     if (background) {
         for (int yy = 0; yy < height; yy++) {
             for (int xx = 0; xx < width; xx++) {
@@ -149,7 +149,7 @@ stage3_text void vbe_plot_background(int x, int y, int width, int height) {
     }
 }
 
-stage3_text void vbe_plot_rect(int x, int y, int width, int height, uint32_t hex) {
+void vbe_plot_rect(int x, int y, int width, int height, uint32_t hex) {
     for (int yy = 0; yy < height; yy++) {
         for (int xx = 0; xx < width; xx++) {
             vbe_plot_px(x + xx, y + yy, hex);
@@ -157,7 +157,7 @@ stage3_text void vbe_plot_rect(int x, int y, int width, int height, uint32_t hex
     }
 }
 
-stage3_text void vbe_plot_bg_blent_rect(int x, int y, int width, int height, uint32_t hex) {
+void vbe_plot_bg_blent_rect(int x, int y, int width, int height, uint32_t hex) {
     for (int yy = 0; yy < height; yy++) {
         for (int xx = 0; xx < width; xx++) {
             vbe_plot_bg_blent_px(x + xx, y + yy, hex);
@@ -171,7 +171,7 @@ struct vbe_char {
     uint32_t bg;
 };
 
-stage3_text void vbe_plot_char(struct vbe_char *c, int x, int y) {
+void vbe_plot_char(struct vbe_char *c, int x, int y) {
     uint8_t *glyph = &vga_font[(size_t)c->c * VGA_FONT_HEIGHT];
 
     vbe_plot_bg_blent_rect(x, y, VGA_FONT_WIDTH, VGA_FONT_HEIGHT, c->bg);
@@ -184,7 +184,7 @@ stage3_text void vbe_plot_char(struct vbe_char *c, int x, int y) {
     }
 }
 
-stage3_text static void plot_char_grid(struct vbe_char *c, int x, int y) {
+static void plot_char_grid(struct vbe_char *c, int x, int y) {
     if (!double_buffer_enabled) {
         vbe_plot_char(c, x * VGA_FONT_WIDTH + frame_width,
                          y * VGA_FONT_HEIGHT + frame_height);
@@ -192,14 +192,14 @@ stage3_text static void plot_char_grid(struct vbe_char *c, int x, int y) {
     grid[x + y * cols] = *c;
 }
 
-stage3_text static void clear_cursor(void) {
+static void clear_cursor(void) {
     struct vbe_char c = grid[cursor_x + cursor_y * cols];
     c.fg = text_fg;
     c.bg = text_bg;
     plot_char_grid(&c, cursor_x, cursor_y);
 }
 
-stage3_text static void draw_cursor(void) {
+static void draw_cursor(void) {
     if (cursor_status) {
         struct vbe_char c = grid[cursor_x + cursor_y * cols];
         c.fg = cursor_fg;
@@ -208,7 +208,7 @@ stage3_text static void draw_cursor(void) {
     }
 }
 
-stage3_text static void scroll(void) {
+static void scroll(void) {
     clear_cursor();
 
     for (int i = cols; i < rows * cols; i++) {
@@ -227,7 +227,7 @@ stage3_text static void scroll(void) {
     draw_cursor();
 }
 
-stage3_text void vbe_clear(bool move) {
+void vbe_clear(bool move) {
     clear_cursor();
 
     struct vbe_char empty;
@@ -246,37 +246,37 @@ stage3_text void vbe_clear(bool move) {
     draw_cursor();
 }
 
-stage3_text void vbe_enable_cursor(void) {
+void vbe_enable_cursor(void) {
     cursor_status = true;
     draw_cursor();
 }
 
-stage3_text void vbe_disable_cursor(void) {
+void vbe_disable_cursor(void) {
     clear_cursor();
     cursor_status = false;
 }
 
-stage3_text void vbe_set_cursor_pos(int x, int y) {
+void vbe_set_cursor_pos(int x, int y) {
     clear_cursor();
     cursor_x = x;
     cursor_y = y;
     draw_cursor();
 }
 
-stage3_text void vbe_get_cursor_pos(int *x, int *y) {
+void vbe_get_cursor_pos(int *x, int *y) {
     *x = cursor_x;
     *y = cursor_y;
 }
 
-stage3_text void vbe_set_text_fg(int fg) {
+void vbe_set_text_fg(int fg) {
     text_fg = ansi_colours[fg];
 }
 
-stage3_text void vbe_set_text_bg(int bg) {
+void vbe_set_text_bg(int bg) {
     text_bg = ansi_colours[bg];
 }
 
-stage3_text void vbe_double_buffer_flush(void) {
+void vbe_double_buffer_flush(void) {
     for (size_t i = 0; i < (size_t)rows * cols; i++) {
         if (!memcmp(&grid[i], &front_grid[i], sizeof(struct vbe_char)))
             continue;
@@ -291,7 +291,7 @@ stage3_text void vbe_double_buffer_flush(void) {
     }
 }
 
-stage3_text void vbe_double_buffer(bool state) {
+void vbe_double_buffer(bool state) {
     if (state) {
         memcpy(front_grid, grid, rows * cols * sizeof(struct vbe_char));
         double_buffer_enabled = true;
@@ -308,7 +308,7 @@ stage3_text void vbe_double_buffer(bool state) {
     }
 }
 
-stage3_text void vbe_putchar(uint8_t c) {
+void vbe_putchar(uint8_t c) {
     switch (c) {
         case '\b':
             if (cursor_x || cursor_y) {
@@ -354,7 +354,7 @@ stage3_text void vbe_putchar(uint8_t c) {
     }
 }
 
-stage3_text bool vbe_tty_init(int *_rows, int *_cols, uint32_t *_colours, int _margin, int _margin_gradient, struct image *_background) {
+bool vbe_tty_init(int *_rows, int *_cols, uint32_t *_colours, int _margin, int _margin_gradient, struct image *_background) {
     int req_width = 0, req_height = 0, req_bpp = 0;
 
     char *menu_resolution = config_get_value(NULL, 0, "MENU_RESOLUTION");
@@ -495,7 +495,7 @@ struct vbe_mode_info_struct {
     uint8_t  reserved2[189];
 } __attribute__((packed));
 
-stage3_text static void get_vbe_info(struct vbe_info_struct *buf) {
+static void get_vbe_info(struct vbe_info_struct *buf) {
     struct rm_regs r = {0};
 
     r.eax = 0x4f00;
@@ -503,7 +503,7 @@ stage3_text static void get_vbe_info(struct vbe_info_struct *buf) {
     rm_int(0x10, &r, &r);
 }
 
-stage3_text static void get_vbe_mode_info(struct vbe_mode_info_struct *buf,
+static void get_vbe_mode_info(struct vbe_mode_info_struct *buf,
                               uint16_t mode) {
     struct rm_regs r = {0};
 
@@ -513,7 +513,7 @@ stage3_text static void get_vbe_mode_info(struct vbe_mode_info_struct *buf,
     rm_int(0x10, &r, &r);
 }
 
-stage3_text static int set_vbe_mode(uint16_t mode) {
+static int set_vbe_mode(uint16_t mode) {
     struct rm_regs r = {0};
 
     r.eax = 0x4f02;
@@ -550,7 +550,7 @@ struct edid_info_struct {
     uint8_t checksum;
 } __attribute__((packed));
 
-stage3_text static int get_edid_info(struct edid_info_struct *buf) {
+static int get_edid_info(struct edid_info_struct *buf) {
     struct rm_regs r = {0};
 
     r.eax = 0x4f15;
@@ -572,13 +572,13 @@ struct resolution {
     uint16_t bpp;
 };
 
-stage3_data static struct resolution fallback_resolutions[] = {
+static struct resolution fallback_resolutions[] = {
     { 1024, 768, 32 },
     { 800,  600, 32 },
     { 640,  480, 32 }
 };
 
-stage3_text bool init_vbe(struct vbe_framebuffer_info *ret,
+bool init_vbe(struct vbe_framebuffer_info *ret,
               uint16_t target_width, uint16_t target_height, uint16_t target_bpp) {
     print("vbe: Initialising...\n");
 
diff --git a/stage23/drivers/vga_textmode.c b/stage23/drivers/vga_textmode.s2.c
similarity index 100%
rename from stage23/drivers/vga_textmode.c
rename to stage23/drivers/vga_textmode.s2.c
diff --git a/stage23/entry.s2.c b/stage23/entry.s2.c
new file mode 100644
index 00000000..5e009207
--- /dev/null
+++ b/stage23/entry.s2.c
@@ -0,0 +1,107 @@
+#include <lib/term.h>
+#include <lib/real.h>
+#include <lib/blib.h>
+#include <lib/libc.h>
+#include <lib/part.h>
+#include <lib/config.h>
+#include <lib/trace.h>
+#include <sys/e820.h>
+#include <sys/a20.h>
+#include <lib/print.h>
+#include <fs/file.h>
+#include <lib/elf.h>
+#include <mm/pmm.h>
+#include <mm/mtrr.h>
+#include <protos/stivale.h>
+#include <protos/stivale2.h>
+#include <protos/linux.h>
+#include <protos/chainload.h>
+#include <menu.h>
+#include <pxe/pxe.h>
+#include <pxe/tftp.h>
+
+extern uint64_t stage3_build_id;
+
+uint8_t boot_drive;
+int     boot_partition = -1;
+
+bool booted_from_pxe = false;
+bool booted_from_cd = false;
+bool stage3_loaded = false;
+
+extern symbol stage3_addr;
+extern symbol limine_sys_size;
+
+static bool stage3_init(struct volume *part) {
+    struct file_handle stage3;
+
+    if (fopen(&stage3, part, "/limine.sys")
+     && fopen(&stage3, part, "/boot/limine.sys")) {
+        return false;
+    }
+
+    if (stage3.size != (size_t)limine_sys_size) {
+        print("limine.sys size incorrect.\n");
+        return false;
+    }
+
+    fread(&stage3, stage3_addr,
+          (uintptr_t)stage3_addr - 0x8000,
+          stage3.size - ((uintptr_t)stage3_addr - 0x8000));
+
+    if (BUILD_ID != stage3_build_id) {
+        print("limine.sys build ID mismatch.\n");
+        return false;
+    }
+
+    stage3_loaded = true;
+
+    return true;
+}
+
+__attribute__((noreturn))
+void entry(uint8_t _boot_drive, int boot_from) {
+    boot_drive = _boot_drive;
+
+    booted_from_pxe = (boot_from == BOOT_FROM_PXE);
+    booted_from_cd = (boot_from == BOOT_FROM_CD);
+
+    term_textmode();
+
+    print("Limine " LIMINE_VERSION "\n\n");
+
+    if (!a20_enable())
+        panic("Could not enable A20 line");
+
+    init_e820();
+    init_memmap();
+
+    volume_create_index();
+
+    switch (boot_from) {
+        case BOOT_FROM_HDD:
+        case BOOT_FROM_CD: {
+            struct volume boot_volume;
+            volume_get_by_coord(&boot_volume, boot_drive, -1);
+            struct volume part = boot_volume;
+            for (int i = 0; ; i++) {
+                if (stage3_init(&part)) {
+                    print("Stage 3 found and loaded.\n");
+                    break;
+                }
+                int ret = part_get(&part, &boot_volume, i);
+                switch (ret) {
+                    case INVALID_TABLE:
+                    case END_OF_TABLE:
+                        panic("Stage 3 not found.");
+                }
+            }
+            break;
+        }
+    }
+
+    __attribute__((noreturn))
+    void (*stage3)(int boot_from) = (void *)stage3_addr;
+
+    stage3(boot_from);
+}
diff --git a/stage23/main.c b/stage23/entry.s3.c
similarity index 64%
rename from stage23/main.c
rename to stage23/entry.s3.c
index 97c8ceba..c575b5ad 100644
--- a/stage23/main.c
+++ b/stage23/entry.s3.c
@@ -20,61 +20,14 @@
 #include <pxe/pxe.h>
 #include <pxe/tftp.h>
 
-enum {
-	BOOT_FROM_HDD,
-	BOOT_FROM_PXE,
-	BOOT_FROM_CD
-};
-
-__attribute__((noreturn))
-void entry(uint8_t _boot_drive, int boot_from) {
-    boot_drive = _boot_drive;
-
-    booted_from_pxe = (boot_from == BOOT_FROM_PXE);
-    booted_from_cd = (boot_from == BOOT_FROM_CD);
-
-    mtrr_save();
-
-    term_textmode();
-
-    print("Limine " LIMINE_VERSION "\n\n");
-
-    if (!a20_enable())
-        panic("Could not enable A20 line");
-
-    init_e820();
-    init_memmap();
-
-    volume_create_index();
-
-    switch (boot_from) {
-        case BOOT_FROM_HDD:
-        case BOOT_FROM_CD: {
-            struct volume boot_volume;
-            volume_get_by_coord(&boot_volume, boot_drive, -1);
-            struct volume part = boot_volume;
-            for (int i = 0; ; i++) {
-                if (stage3_init(&part)) {
-                    print("Stage 3 found and loaded.\n");
-                    break;
-                }
-                int ret = part_get(&part, &boot_volume, i);
-                switch (ret) {
-                    case INVALID_TABLE:
-                    case END_OF_TABLE:
-                        panic("Stage 3 not found.");
-                }
-            }
-            break;
-        }
-    }
-
-    stage3(boot_from);
-}
+__attribute__((section(".stage3_build_id")))
+uint64_t stage3_build_id = BUILD_ID;
 
 __attribute__((noreturn))
 __attribute__((section(".stage3_entry")))
 void stage3_entry(int boot_from) {
+    mtrr_save();
+
     switch (boot_from) {
         case BOOT_FROM_HDD:
         case BOOT_FROM_CD: {
diff --git a/stage23/fs/echfs.c b/stage23/fs/echfs.s2.c
similarity index 100%
rename from stage23/fs/echfs.c
rename to stage23/fs/echfs.s2.c
diff --git a/stage23/fs/ext2.c b/stage23/fs/ext2.s2.c
similarity index 100%
rename from stage23/fs/ext2.c
rename to stage23/fs/ext2.s2.c
diff --git a/stage23/fs/fat32.c b/stage23/fs/fat32.s2.c
similarity index 100%
rename from stage23/fs/fat32.c
rename to stage23/fs/fat32.s2.c
diff --git a/stage23/fs/file.c b/stage23/fs/file.s2.c
similarity index 100%
rename from stage23/fs/file.c
rename to stage23/fs/file.s2.c
diff --git a/stage23/fs/iso9660.c b/stage23/fs/iso9660.s2.c
similarity index 100%
rename from stage23/fs/iso9660.c
rename to stage23/fs/iso9660.s2.c
diff --git a/stage23/lib/acpi.c b/stage23/lib/acpi.c
index 32a93675..15c41c6b 100644
--- a/stage23/lib/acpi.c
+++ b/stage23/lib/acpi.c
@@ -7,7 +7,6 @@
 #include <lib/print.h>
 
 // Following function based on https://github.com/qword-os/lai/blob/master/helpers/pc-bios.c's function lai_bios_calc_checksum()
-stage3_text
 uint8_t acpi_checksum(void *ptr, size_t size) {
     uint8_t sum = 0, *_ptr = ptr;
     for (size_t i = 0; i < size; i++)
@@ -15,7 +14,6 @@ uint8_t acpi_checksum(void *ptr, size_t size) {
     return sum;
 }
 
-stage3_text
 void *acpi_get_rsdp(void) {
     size_t ebda = EBDA;
 
@@ -34,7 +32,6 @@ void *acpi_get_rsdp(void) {
     return NULL;
 }
 
-stage3_text
 void *acpi_get_table(const char *signature, int index) {
     int cnt = 0;
 
diff --git a/stage23/lib/blib.c b/stage23/lib/blib.c
index be43c562..bdd62d66 100644
--- a/stage23/lib/blib.c
+++ b/stage23/lib/blib.c
@@ -8,50 +8,6 @@
 #include <lib/real.h>
 #include <fs/file.h>
 
-__attribute__((section(".stage3_build_id")))
-uint64_t stage3_build_id = BUILD_ID;
-
-uint8_t boot_drive;
-int     boot_partition = -1;
-
-bool booted_from_pxe = false;
-bool booted_from_cd = false;
-bool stage3_loaded = false;
-
-extern symbol stage3_addr;
-extern symbol limine_sys_size;
-
-__attribute__((noreturn))
-void (*stage3)(int boot_from) = (void *)stage3_addr;
-
-bool stage3_init(struct volume *part) {
-    struct file_handle stage3;
-
-    if (fopen(&stage3, part, "/limine.sys")
-     && fopen(&stage3, part, "/boot/limine.sys")) {
-        return false;
-    }
-
-    if (stage3.size != (size_t)limine_sys_size) {
-        print("limine.sys size incorrect.\n");
-        return false;
-    }
-
-    fread(&stage3, stage3_addr,
-          (uintptr_t)stage3_addr - 0x8000,
-          stage3.size - ((uintptr_t)stage3_addr - 0x8000));
-
-    if (BUILD_ID != stage3_build_id) {
-        print("limine.sys build ID mismatch.\n");
-        return false;
-    }
-
-    stage3_loaded = true;
-
-    return true;
-}
-
-stage3_text
 bool parse_resolution(int *width, int *height, int *bpp, const char *buf) {
     int res[3] = {0};
 
@@ -80,7 +36,6 @@ bool parse_resolution(int *width, int *height, int *bpp, const char *buf) {
 
 // This integer sqrt implementation has been adapted from:
 // https://stackoverflow.com/questions/1100090/looking-for-an-efficient-integer-square-root-algorithm-for-arm-thumb2
-stage3_text
 uint64_t sqrt(uint64_t a_nInput) {
     uint64_t op  = a_nInput;
     uint64_t res = 0;
@@ -102,54 +57,3 @@ uint64_t sqrt(uint64_t a_nInput) {
 
     return res;
 }
-
-stage3_text
-uint8_t bcd_to_int(uint8_t val) {
-    return (val & 0x0f) + ((val & 0xf0) >> 4) * 10;
-}
-
-__attribute__((noreturn)) void panic(const char *fmt, ...) {
-    asm volatile ("cli" ::: "memory");
-
-    va_list args;
-
-    va_start(args, fmt);
-
-    print("\033[31mPANIC\033[37;1m\033[40m: ");
-    vprint(fmt, args);
-
-    va_end(args);
-
-    print("\n");
-    print_stacktrace(NULL);
-
-    rm_hcf();
-}
-
-int digit_to_int(char c) {
-    if (c >= 'a' && c <= 'f') {
-        return (c - 'a') + 10;
-    }
-    if (c >= 'A' && c <= 'F') {
-        return (c - 'A') + 10;
-    }
-    if (c >= '0' && c <= '9'){
-        return c - '0';
-    }
-
-    return -1;
-}
-
-uint64_t strtoui(const char *s, const char **end, int base) {
-    uint64_t n = 0;
-    for (size_t i = 0; ; i++) {
-        int d = digit_to_int(s[i]);
-        if (d == -1) {
-            if (end != NULL)
-                *end = &s[i];
-            break;
-        }
-        n = n * base + d;
-    }
-    return n;
-}
diff --git a/stage23/lib/blib.h b/stage23/lib/blib.h
index f38e84de..b02c74c9 100644
--- a/stage23/lib/blib.h
+++ b/stage23/lib/blib.h
@@ -46,10 +46,10 @@ uint64_t strtoui(const char *s, const char **end, int base);
 
 typedef char symbol[];
 
-#define stage3_text __attribute__((section(".stage3_text")))
-#define stage3_data __attribute__((section(".stage3_data")))
-
-__attribute__((noreturn)) extern void (*stage3)(int boot_from);
-bool stage3_init(struct volume *part);
+enum {
+	BOOT_FROM_HDD,
+	BOOT_FROM_PXE,
+	BOOT_FROM_CD
+};
 
 #endif
diff --git a/stage23/lib/blib.s2.c b/stage23/lib/blib.s2.c
new file mode 100644
index 00000000..de3d3762
--- /dev/null
+++ b/stage23/lib/blib.s2.c
@@ -0,0 +1,35 @@
+#include <stdint.h>
+#include <stddef.h>
+#include <lib/blib.h>
+
+uint8_t bcd_to_int(uint8_t val) {
+    return (val & 0x0f) + ((val & 0xf0) >> 4) * 10;
+}
+
+int digit_to_int(char c) {
+    if (c >= 'a' && c <= 'f') {
+        return (c - 'a') + 10;
+    }
+    if (c >= 'A' && c <= 'F') {
+        return (c - 'A') + 10;
+    }
+    if (c >= '0' && c <= '9'){
+        return c - '0';
+    }
+
+    return -1;
+}
+
+uint64_t strtoui(const char *s, const char **end, int base) {
+    uint64_t n = 0;
+    for (size_t i = 0; ; i++) {
+        int d = digit_to_int(s[i]);
+        if (d == -1) {
+            if (end != NULL)
+                *end = &s[i];
+            break;
+        }
+        n = n * base + d;
+    }
+    return n;
+}
diff --git a/stage23/lib/bmp.c b/stage23/lib/bmp.c
index a1a283d8..5c7a1265 100644
--- a/stage23/lib/bmp.c
+++ b/stage23/lib/bmp.c
@@ -34,7 +34,6 @@ struct bmp_local {
     struct bmp_header header;
 };
 
-stage3_text
 static uint32_t get_pixel(struct image *this, int x, int y) {
     struct bmp_local *local = this->local;
     struct bmp_header *header = &local->header;
@@ -52,7 +51,6 @@ static uint32_t get_pixel(struct image *this, int x, int y) {
     return composite;
 }
 
-stage3_text
 int bmp_open_image(struct image *image, struct file_handle *file) {
     struct bmp_header header;
     fread(file, &header, 0, sizeof(struct bmp_header));
diff --git a/stage23/lib/builtins.asm b/stage23/lib/builtins.s2.asm
similarity index 100%
rename from stage23/lib/builtins.asm
rename to stage23/lib/builtins.s2.asm
diff --git a/stage23/lib/config.c b/stage23/lib/config.c
index 5c53c4db..c9c7fa9b 100644
--- a/stage23/lib/config.c
+++ b/stage23/lib/config.c
@@ -16,7 +16,6 @@ bool config_ready = false;
 
 static char *config_addr;
 
-stage3_text
 int init_config_disk(struct volume *part) {
     struct file_handle f;
 
@@ -35,7 +34,6 @@ int init_config_disk(struct volume *part) {
     return init_config(config_size);
 }
 
-stage3_text
 int init_config_pxe(void) {
     struct tftp_file_handle cfg;
     if (tftp_open(&cfg, 0, 69, "limine.cfg")
@@ -54,7 +52,6 @@ int init_config_pxe(void) {
 #define DIRECT_CHILD   0
 #define INDIRECT_CHILD 1
 
-stage3_text
 static int is_child(char *buf, size_t limit,
                     size_t current_depth, size_t index) {
     if (!config_get_entry_name(buf, index, limit))
@@ -69,7 +66,6 @@ static int is_child(char *buf, size_t limit,
     return DIRECT_CHILD;
 }
 
-stage3_text
 static bool is_directory(char *buf, size_t limit,
                          size_t current_depth, size_t index) {
     switch (is_child(buf, limit, current_depth + 1, index + 1)) {
@@ -83,7 +79,6 @@ static bool is_directory(char *buf, size_t limit,
     }
 }
 
-stage3_text
 static struct menu_entry *create_menu_tree(struct menu_entry *parent,
                                            size_t current_depth, size_t index) {
     struct menu_entry *root = NULL, *prev = NULL;
@@ -131,7 +126,6 @@ static struct menu_entry *create_menu_tree(struct menu_entry *parent,
 
 struct menu_entry *menu_tree = NULL;
 
-stage3_text
 int init_config(size_t config_size) {
     // remove windows carriage returns, if any
     for (size_t i = 0; i < config_size; i++) {
@@ -149,7 +143,6 @@ int init_config(size_t config_size) {
     return 0;
 }
 
-stage3_text
 bool config_get_entry_name(char *ret, size_t index, size_t limit) {
     char *p = config_addr;
 
@@ -177,7 +170,6 @@ bool config_get_entry_name(char *ret, size_t index, size_t limit) {
     return true;
 }
 
-stage3_text
 char *config_get_entry(size_t *size, size_t index) {
     char *ret;
     char *p = config_addr;
@@ -213,7 +205,6 @@ cont:
     return ret;
 }
 
-stage3_text
 char *config_get_value(const char *config, size_t index, const char *key) {
     if (!key)
         return NULL;
diff --git a/stage23/lib/elf.c b/stage23/lib/elf.c
index cc3861b5..f4c52b9c 100644
--- a/stage23/lib/elf.c
+++ b/stage23/lib/elf.c
@@ -114,7 +114,6 @@ struct elf64_rela {
     uint64_t r_addend;
 };
 
-stage3_text
 int elf_bits(struct file_handle *fd) {
     struct elf64_hdr hdr;
     fread(fd, &hdr, 0, 20);
@@ -134,7 +133,6 @@ int elf_bits(struct file_handle *fd) {
     }
 }
 
-stage3_text
 static int elf64_apply_relocations(struct file_handle *fd, struct elf64_hdr *hdr, void *buffer, uint64_t vaddr, size_t size, uint64_t slide) {
     // Find RELA sections
     for (uint16_t i = 0; i < hdr->sh_num; i++) {
@@ -182,7 +180,6 @@ static int elf64_apply_relocations(struct file_handle *fd, struct elf64_hdr *hdr
     return 0;
 }
 
-stage3_text
 int elf64_load_section(struct file_handle *fd, void *buffer, const char *name, size_t limit, uint64_t slide) {
     struct elf64_hdr hdr;
     fread(fd, &hdr, 0, sizeof(struct elf64_hdr));
@@ -227,7 +224,6 @@ int elf64_load_section(struct file_handle *fd, void *buffer, const char *name, s
     return 2;
 }
 
-stage3_text
 int elf32_load_section(struct file_handle *fd, void *buffer, const char *name, size_t limit) {
     struct elf32_hdr hdr;
     fread(fd, &hdr, 0, sizeof(struct elf32_hdr));
@@ -272,7 +268,6 @@ int elf32_load_section(struct file_handle *fd, void *buffer, const char *name, s
     return 2;
 }
 
-stage3_text
 int elf64_load(struct file_handle *fd, uint64_t *entry_point, uint64_t *top, uint64_t slide, uint32_t alloc_type) {
     struct elf64_hdr hdr;
     fread(fd, &hdr, 0, sizeof(struct elf64_hdr));
@@ -334,7 +329,6 @@ int elf64_load(struct file_handle *fd, uint64_t *entry_point, uint64_t *top, uin
     return 0;
 }
 
-stage3_text
 int elf32_load(struct file_handle *fd, uint32_t *entry_point, uint32_t *top, uint32_t alloc_type) {
     struct elf32_hdr hdr;
     fread(fd, &hdr, 0, sizeof(struct elf32_hdr));
diff --git a/stage23/lib/image.c b/stage23/lib/image.c
index a0a40b49..40d83c3f 100644
--- a/stage23/lib/image.c
+++ b/stage23/lib/image.c
@@ -5,7 +5,6 @@
 #include <mm/pmm.h>
 #include <lib/bmp.h>
 
-stage3_text
 int open_image(struct image *image, struct file_handle *file) {
     image->file = file;
 
diff --git a/stage23/lib/libc.c b/stage23/lib/libc.s2.c
similarity index 100%
rename from stage23/lib/libc.c
rename to stage23/lib/libc.s2.c
diff --git a/stage23/lib/panic.s2.c b/stage23/lib/panic.s2.c
new file mode 100644
index 00000000..d86b4e5f
--- /dev/null
+++ b/stage23/lib/panic.s2.c
@@ -0,0 +1,21 @@
+#include <lib/print.h>
+#include <lib/real.h>
+#include <lib/trace.h>
+
+__attribute__((noreturn)) void panic(const char *fmt, ...) {
+    asm volatile ("cli" ::: "memory");
+
+    va_list args;
+
+    va_start(args, fmt);
+
+    print("\033[31mPANIC\033[37;1m\033[40m: ");
+    vprint(fmt, args);
+
+    va_end(args);
+
+    print("\n");
+    print_stacktrace(NULL);
+
+    rm_hcf();
+}
diff --git a/stage23/lib/part.c b/stage23/lib/part.s2.c
similarity index 100%
rename from stage23/lib/part.c
rename to stage23/lib/part.s2.c
diff --git a/stage23/lib/print.c b/stage23/lib/print.s2.c
similarity index 100%
rename from stage23/lib/print.c
rename to stage23/lib/print.s2.c
diff --git a/stage23/lib/rand.c b/stage23/lib/rand.c
index a981a8aa..6ce12f39 100644
--- a/stage23/lib/rand.c
+++ b/stage23/lib/rand.c
@@ -52,7 +52,6 @@ static bool rand_initialised = false;
 static uint32_t *status;
 static int ctr;
 
-stage3_text
 static void init_rand(void) {
     uint32_t seed = ((uint32_t)0xc597060c * rdtsc(uint32_t))
                   * ((uint32_t)0xce86d624)
@@ -74,14 +73,12 @@ static void init_rand(void) {
     rand_initialised = true;
 }
 
-stage3_text
 void srand(uint32_t s) {
     status[0] = s;
     for (ctr = 1; ctr < n; ctr++)
         status[ctr] = (1812433253 * (status[ctr - 1] ^ (status[ctr - 1] >> 30)) + ctr);
 }
 
-stage3_text
 uint32_t rand32(void) {
     if (!rand_initialised)
         init_rand();
@@ -115,7 +112,6 @@ uint32_t rand32(void) {
     return res;
 }
 
-stage3_text
 uint64_t rand64(void) {
     return (((uint64_t)rand32()) << 32) | (uint64_t)rand32();
 }
diff --git a/stage23/lib/readline.c b/stage23/lib/readline.c
index f79fd268..42713d90 100644
--- a/stage23/lib/readline.c
+++ b/stage23/lib/readline.c
@@ -6,7 +6,6 @@
 #include <lib/term.h>
 #include <lib/real.h>
 
-stage3_text
 int getchar_internal(uint32_t eax) {
     switch ((eax >> 8) & 0xff) {
         case 0x44:
@@ -38,14 +37,12 @@ int getchar_internal(uint32_t eax) {
     return c;
 }
 
-stage3_text
 int getchar(void) {
     struct rm_regs r = {0};
     rm_int(0x16, &r, &r);
     return getchar_internal(r.eax);
 }
 
-stage3_text
 static void reprint_string(int x, int y, const char *s) {
     int orig_x, orig_y;
     disable_cursor();
@@ -56,7 +53,6 @@ static void reprint_string(int x, int y, const char *s) {
     enable_cursor();
 }
 
-stage3_text
 static void cursor_back(void) {
     int x, y;
     get_cursor_pos(&x, &y);
@@ -69,7 +65,6 @@ static void cursor_back(void) {
     set_cursor_pos(x, y);
 }
 
-stage3_text
 static void cursor_fwd(void) {
     int x, y;
     get_cursor_pos(&x, &y);
@@ -82,7 +77,6 @@ static void cursor_fwd(void) {
     set_cursor_pos(x, y);
 }
 
-stage3_text
 void readline(const char *orig_str, char *buf, size_t limit) {
     size_t orig_str_len = strlen(orig_str);
     memmove(buf, orig_str, orig_str_len);
diff --git a/stage23/lib/term.c b/stage23/lib/term.c
index d4bffe18..b636f4be 100644
--- a/stage23/lib/term.c
+++ b/stage23/lib/term.c
@@ -2,33 +2,10 @@
 #include <stddef.h>
 #include <stdbool.h>
 #include <lib/term.h>
-#include <lib/real.h>
 #include <lib/image.h>
 #include <lib/blib.h>
-#include <drivers/vga_textmode.h>
 #include <drivers/vbe.h>
 
-static enum {
-    NOT_READY,
-    VBE,
-    TEXTMODE
-} term_backend = NOT_READY;
-
-void (*raw_putchar)(uint8_t c);
-void (*clear)(bool move);
-void (*enable_cursor)(void);
-void (*disable_cursor)(void);
-void (*set_cursor_pos)(int x, int y);
-void (*get_cursor_pos)(int *x, int *y);
-void (*set_text_fg)(int fg);
-void (*set_text_bg)(int bg);
-
-void (*term_double_buffer)(bool status);
-void (*term_double_buffer_flush)(void);
-
-int term_rows, term_cols;
-
-stage3_text
 void term_vbe(uint32_t *colours, int margin, int margin_gradient, struct image *background) {
     term_deinit();
     if (!vbe_tty_init(&term_rows, &term_cols, colours, margin, margin_gradient, background)) {
@@ -51,200 +28,3 @@ void term_vbe(uint32_t *colours, int margin, int margin_gradient, struct image *
 
     term_backend = VBE;
 }
-
-void term_textmode(void) {
-    term_deinit();
-    init_vga_textmode(&term_rows, &term_cols);
-
-    raw_putchar    = text_putchar;
-    clear          = text_clear;
-    enable_cursor  = text_enable_cursor;
-    disable_cursor = text_disable_cursor;
-    set_cursor_pos = text_set_cursor_pos;
-    get_cursor_pos = text_get_cursor_pos;
-    set_text_fg    = text_set_text_fg;
-    set_text_bg    = text_set_text_bg;
-
-    term_double_buffer       = text_double_buffer;
-    term_double_buffer_flush = text_double_buffer_flush;
-
-    term_backend = TEXTMODE;
-}
-
-void term_deinit(void) {
-    struct rm_regs r = {0};
-    r.eax = 0x0003;
-    rm_int(0x10, &r, &r);
-
-    term_backend = NOT_READY;
-}
-
-static void term_putchar(uint8_t c);
-
-void term_write(const char *buf, size_t count) {
-    if (term_backend == NOT_READY)
-        return;
-    for (size_t i = 0; i < count; i++)
-        term_putchar(buf[i]);
-}
-
-static int get_cursor_pos_x(void) {
-    int x, y;
-    get_cursor_pos(&x, &y);
-    return x;
-}
-
-static int get_cursor_pos_y(void) {
-    int x, y;
-    get_cursor_pos(&x, &y);
-    return y;
-}
-
-static void escape_parse(uint8_t c);
-
-static int escape = 0;
-static int esc_value0 = 0;
-static int esc_value1 = 0;
-static int *esc_value = &esc_value0;
-static int esc_default0 = 1;
-static int esc_default1 = 1;
-static int *esc_default = &esc_default0;
-
-static void term_putchar(uint8_t c) {
-    if (escape) {
-        escape_parse(c);
-        return;
-    }
-    switch (c) {
-        case 0x00:
-            break;
-        case 0x1B:
-            escape = 1;
-            return;
-        default:
-            raw_putchar(c);
-            break;
-    }
-}
-
-static void sgr(void) {
-    if (esc_value0 == 0){
-        set_text_bg(0);
-        set_text_fg(7);
-        return;
-    }
-
-    if (esc_value0 >= 30 && esc_value0 <= 37) {
-        set_text_fg(esc_value0 - 30);
-        return;
-    }
-
-    if (esc_value0 >= 40 && esc_value0 <= 47) {
-        set_text_bg(esc_value0 - 40);
-        return;
-    }
-}
-
-static void escape_parse(uint8_t c) {
-    if (c >= '0' && c <= '9') {
-        *esc_value *= 10;
-        *esc_value += c - '0';
-        *esc_default = 0;
-        return;
-    }
-
-    switch (c) {
-        case 0x1b:
-            escape = 0;
-            raw_putchar(0x1b);
-            return;
-        case '[':
-            return;
-        case ';':
-            esc_value = &esc_value1;
-            esc_default = &esc_default1;
-            return;
-        case 'A':
-            if (esc_default0)
-                esc_value0 = 1;
-            if (esc_value0 > get_cursor_pos_y())
-                esc_value0 = get_cursor_pos_y();
-            set_cursor_pos(get_cursor_pos_x(),
-                                get_cursor_pos_y() - esc_value0);
-            break;
-        case 'B':
-            if (esc_default0)
-                esc_value0 = 1;
-            if ((get_cursor_pos_y() + esc_value0) > (term_rows - 1))
-                esc_value0 = (term_rows - 1) - get_cursor_pos_y();
-            set_cursor_pos(get_cursor_pos_x(),
-                                get_cursor_pos_y() + esc_value0);
-            break;
-        case 'C':
-            if (esc_default0)
-                esc_value0 = 1;
-            if ((get_cursor_pos_x() + esc_value0) > (term_cols - 1))
-                esc_value0 = (term_cols - 1) - get_cursor_pos_x();
-            set_cursor_pos(get_cursor_pos_x() + esc_value0,
-                                get_cursor_pos_y());
-            break;
-        case 'D':
-            if (esc_default0)
-                esc_value0 = 1;
-            if (esc_value0 > get_cursor_pos_x())
-                esc_value0 = get_cursor_pos_x();
-            set_cursor_pos(get_cursor_pos_x() - esc_value0,
-                                get_cursor_pos_y());
-            break;
-        case 'H':
-            esc_value0--;
-            esc_value1--;
-            if (esc_default0)
-                esc_value0 = 0;
-            if (esc_default1)
-                esc_value1 = 0;
-            if (esc_value1 >= term_cols)
-                esc_value1 = term_cols - 1;
-            if (esc_value0 >= term_rows)
-                esc_value0 = term_rows - 1;
-            set_cursor_pos(esc_value1, esc_value0);
-            break;
-        case 'm':
-            sgr();
-            break;
-        case 'J':
-            switch (esc_value0) {
-                case 2:
-                    clear(false);
-                    break;
-                default:
-                    break;
-            }
-            break;
-        case 'K':
-            switch (esc_value0) {
-                case 2: {
-                    int x = get_cursor_pos_x();
-                    int y = get_cursor_pos_y();
-                    set_cursor_pos(0, y);
-                    for (int i = 0; i < term_cols; i++)
-                        raw_putchar(' ');
-                    set_cursor_pos(x, y);
-                    break;
-                }
-            }
-            break;
-        default:
-            escape = 0;
-            raw_putchar('?');
-            break;
-    }
-
-    esc_value = &esc_value0;
-    esc_value0 = 0;
-    esc_value1 = 0;
-    esc_default = &esc_default0;
-    esc_default0 = 1;
-    esc_default1 = 1;
-    escape = 0;
-}
diff --git a/stage23/lib/term.h b/stage23/lib/term.h
index fb3c3288..63680e8c 100644
--- a/stage23/lib/term.h
+++ b/stage23/lib/term.h
@@ -24,4 +24,12 @@ void term_write(const char *buf, size_t count);
 
 extern int term_rows, term_cols;
 
+enum {
+    NOT_READY,
+    VBE,
+    TEXTMODE
+};
+
+extern int term_backend;
+
 #endif
diff --git a/stage23/lib/term.s2.c b/stage23/lib/term.s2.c
new file mode 100644
index 00000000..2058deba
--- /dev/null
+++ b/stage23/lib/term.s2.c
@@ -0,0 +1,221 @@
+#include <stdint.h>
+#include <stddef.h>
+#include <stdbool.h>
+#include <lib/term.h>
+#include <lib/real.h>
+#include <lib/image.h>
+#include <lib/blib.h>
+#include <drivers/vga_textmode.h>
+
+int term_backend = NOT_READY;
+
+void (*raw_putchar)(uint8_t c);
+void (*clear)(bool move);
+void (*enable_cursor)(void);
+void (*disable_cursor)(void);
+void (*set_cursor_pos)(int x, int y);
+void (*get_cursor_pos)(int *x, int *y);
+void (*set_text_fg)(int fg);
+void (*set_text_bg)(int bg);
+
+void (*term_double_buffer)(bool status);
+void (*term_double_buffer_flush)(void);
+
+int term_rows, term_cols;
+
+void term_textmode(void) {
+    term_deinit();
+    init_vga_textmode(&term_rows, &term_cols);
+
+    raw_putchar    = text_putchar;
+    clear          = text_clear;
+    enable_cursor  = text_enable_cursor;
+    disable_cursor = text_disable_cursor;
+    set_cursor_pos = text_set_cursor_pos;
+    get_cursor_pos = text_get_cursor_pos;
+    set_text_fg    = text_set_text_fg;
+    set_text_bg    = text_set_text_bg;
+
+    term_double_buffer       = text_double_buffer;
+    term_double_buffer_flush = text_double_buffer_flush;
+
+    term_backend = TEXTMODE;
+}
+
+void term_deinit(void) {
+    struct rm_regs r = {0};
+    r.eax = 0x0003;
+    rm_int(0x10, &r, &r);
+
+    term_backend = NOT_READY;
+}
+
+static void term_putchar(uint8_t c);
+
+void term_write(const char *buf, size_t count) {
+    if (term_backend == NOT_READY)
+        return;
+    for (size_t i = 0; i < count; i++)
+        term_putchar(buf[i]);
+}
+
+static int get_cursor_pos_x(void) {
+    int x, y;
+    get_cursor_pos(&x, &y);
+    return x;
+}
+
+static int get_cursor_pos_y(void) {
+    int x, y;
+    get_cursor_pos(&x, &y);
+    return y;
+}
+
+static void escape_parse(uint8_t c);
+
+static int escape = 0;
+static int esc_value0 = 0;
+static int esc_value1 = 0;
+static int *esc_value = &esc_value0;
+static int esc_default0 = 1;
+static int esc_default1 = 1;
+static int *esc_default = &esc_default0;
+
+static void term_putchar(uint8_t c) {
+    if (escape) {
+        escape_parse(c);
+        return;
+    }
+    switch (c) {
+        case 0x00:
+            break;
+        case 0x1B:
+            escape = 1;
+            return;
+        default:
+            raw_putchar(c);
+            break;
+    }
+}
+
+static void sgr(void) {
+    if (esc_value0 == 0){
+        set_text_bg(0);
+        set_text_fg(7);
+        return;
+    }
+
+    if (esc_value0 >= 30 && esc_value0 <= 37) {
+        set_text_fg(esc_value0 - 30);
+        return;
+    }
+
+    if (esc_value0 >= 40 && esc_value0 <= 47) {
+        set_text_bg(esc_value0 - 40);
+        return;
+    }
+}
+
+static void escape_parse(uint8_t c) {
+    if (c >= '0' && c <= '9') {
+        *esc_value *= 10;
+        *esc_value += c - '0';
+        *esc_default = 0;
+        return;
+    }
+
+    switch (c) {
+        case 0x1b:
+            escape = 0;
+            raw_putchar(0x1b);
+            return;
+        case '[':
+            return;
+        case ';':
+            esc_value = &esc_value1;
+            esc_default = &esc_default1;
+            return;
+        case 'A':
+            if (esc_default0)
+                esc_value0 = 1;
+            if (esc_value0 > get_cursor_pos_y())
+                esc_value0 = get_cursor_pos_y();
+            set_cursor_pos(get_cursor_pos_x(),
+                                get_cursor_pos_y() - esc_value0);
+            break;
+        case 'B':
+            if (esc_default0)
+                esc_value0 = 1;
+            if ((get_cursor_pos_y() + esc_value0) > (term_rows - 1))
+                esc_value0 = (term_rows - 1) - get_cursor_pos_y();
+            set_cursor_pos(get_cursor_pos_x(),
+                                get_cursor_pos_y() + esc_value0);
+            break;
+        case 'C':
+            if (esc_default0)
+                esc_value0 = 1;
+            if ((get_cursor_pos_x() + esc_value0) > (term_cols - 1))
+                esc_value0 = (term_cols - 1) - get_cursor_pos_x();
+            set_cursor_pos(get_cursor_pos_x() + esc_value0,
+                                get_cursor_pos_y());
+            break;
+        case 'D':
+            if (esc_default0)
+                esc_value0 = 1;
+            if (esc_value0 > get_cursor_pos_x())
+                esc_value0 = get_cursor_pos_x();
+            set_cursor_pos(get_cursor_pos_x() - esc_value0,
+                                get_cursor_pos_y());
+            break;
+        case 'H':
+            esc_value0--;
+            esc_value1--;
+            if (esc_default0)
+                esc_value0 = 0;
+            if (esc_default1)
+                esc_value1 = 0;
+            if (esc_value1 >= term_cols)
+                esc_value1 = term_cols - 1;
+            if (esc_value0 >= term_rows)
+                esc_value0 = term_rows - 1;
+            set_cursor_pos(esc_value1, esc_value0);
+            break;
+        case 'm':
+            sgr();
+            break;
+        case 'J':
+            switch (esc_value0) {
+                case 2:
+                    clear(false);
+                    break;
+                default:
+                    break;
+            }
+            break;
+        case 'K':
+            switch (esc_value0) {
+                case 2: {
+                    int x = get_cursor_pos_x();
+                    int y = get_cursor_pos_y();
+                    set_cursor_pos(0, y);
+                    for (int i = 0; i < term_cols; i++)
+                        raw_putchar(' ');
+                    set_cursor_pos(x, y);
+                    break;
+                }
+            }
+            break;
+        default:
+            escape = 0;
+            raw_putchar('?');
+            break;
+    }
+
+    esc_value = &esc_value0;
+    esc_value0 = 0;
+    esc_value1 = 0;
+    esc_default = &esc_default0;
+    esc_default0 = 1;
+    esc_default1 = 1;
+    escape = 0;
+}
diff --git a/stage23/lib/time.c b/stage23/lib/time.c
index fb6d52cc..7120dc95 100644
--- a/stage23/lib/time.c
+++ b/stage23/lib/time.c
@@ -5,7 +5,6 @@
 #include <lib/blib.h>
 
 // Julian date calculation from https://en.wikipedia.org/wiki/Julian_day
-stage3_text
 static uint64_t get_jdn(uint8_t days, uint8_t months, uint16_t years) {
     return (1461 * (years + 4800 + (months - 14)/12))/4 + (367 *
            (months - 2 - 12 * ((months - 14)/12)))/12 -
@@ -13,7 +12,6 @@ static uint64_t get_jdn(uint8_t days, uint8_t months, uint16_t years) {
            + days - 32075;
 }
 
-stage3_text
 static uint64_t get_unix_epoch(uint8_t seconds, uint8_t minutes, uint8_t  hours,
                                uint8_t days,    uint8_t months,  uint16_t years) {
     uint64_t jdn_current = get_jdn(days, months, years);
@@ -24,7 +22,6 @@ static uint64_t get_unix_epoch(uint8_t seconds, uint8_t minutes, uint8_t  hours,
     return (jdn_diff * (60 * 60 * 24)) + hours * 3600 + minutes * 60 + seconds;
 }
 
-stage3_text
 uint64_t time(void) {
     struct rm_regs r = {0};
 
diff --git a/stage23/lib/trace.h b/stage23/lib/trace.h
index d67aa13d..02272a43 100644
--- a/stage23/lib/trace.h
+++ b/stage23/lib/trace.h
@@ -1,7 +1,7 @@
 #ifndef __LIB__TRACE_H__
 #define __LIB__TRACE_H__
 
-#include <stdint.h>
+#include <stddef.h>
 
 char *trace_address(size_t *off, size_t addr);
 void print_stacktrace(size_t *base_ptr);
diff --git a/stage23/lib/trace.c b/stage23/lib/trace.s2.c
similarity index 100%
rename from stage23/lib/trace.c
rename to stage23/lib/trace.s2.c
diff --git a/stage23/lib/uri.c b/stage23/lib/uri.c
index e879899b..883dc09e 100644
--- a/stage23/lib/uri.c
+++ b/stage23/lib/uri.c
@@ -12,7 +12,6 @@
 
 // A URI takes the form of: resource://root/path
 // The following function splits up a URI into its componenets
-stage3_text
 bool uri_resolve(char *uri, char **resource, char **root, char **path) {
     size_t length = strlen(uri) + 1;
     char *buf = ext_mem_alloc(length);
@@ -57,7 +56,6 @@ bool uri_resolve(char *uri, char **resource, char **root, char **path) {
 
 // BIOS partitions are specified in the <BIOS drive>:<partition> form.
 // The drive may be omitted, the partition cannot.
-stage3_text
 static bool parse_bios_partition(char *loc, uint8_t *drive, uint8_t *partition) {
     uint64_t val;
 
@@ -93,7 +91,6 @@ static bool parse_bios_partition(char *loc, uint8_t *drive, uint8_t *partition)
     return true;
 }
 
-stage3_text
 static bool uri_bios_dispatch(struct file_handle *fd, char *loc, char *path) {
     uint8_t drive, partition;
 
@@ -110,7 +107,6 @@ static bool uri_bios_dispatch(struct file_handle *fd, char *loc, char *path) {
     return true;
 }
 
-stage3_text
 static bool uri_guid_dispatch(struct file_handle *fd, char *guid_str, char *path) {
     struct guid guid;
     if (!string_to_guid_be(&guid, guid_str))
@@ -131,7 +127,6 @@ static bool uri_guid_dispatch(struct file_handle *fd, char *guid_str, char *path
     return true;
 }
 
-stage3_text
 static bool uri_tftp_dispatch(struct file_handle *fd, char *root, char *path) {
     uint32_t ip;
     if (!strcmp(root, "")) {
@@ -155,7 +150,6 @@ static bool uri_tftp_dispatch(struct file_handle *fd, char *root, char *path) {
     return true;
 }
 
-stage3_text
 static bool uri_boot_dispatch(struct file_handle *fd, char *s_part, char *path) {
     if (booted_from_pxe)
         return uri_tftp_dispatch(fd, s_part, path);
@@ -184,7 +178,6 @@ static bool uri_boot_dispatch(struct file_handle *fd, char *s_part, char *path)
     return true;
 }
 
-stage3_text
 bool uri_open(struct file_handle *fd, char *uri) {
     bool ret;
 
diff --git a/stage23/linker.ld b/stage23/linker.ld
index fa9e81f3..b99c1e7a 100644
--- a/stage23/linker.ld
+++ b/stage23/linker.ld
@@ -14,23 +14,27 @@ SECTIONS
     }
 
     .stage2.text : {
-        *(.text*)
+        *.s2.o(.text*)
+        *libgcc.a:*(.text*)
     }
 
     .stage2.data : {
-        *(.data*)
-        *(.rodata*)
+        *.s2.o(.data*)
+        *.s2.o(.rodata*)
+        *libgcc.a:*(.data*)
+        *libgcc.a:*(.rodata*)
     }
 
     .stage3.text : {
         stage3_addr = .;
         *(.stage3_entry*)
         *(.stage3_build_id*)
-        *(.stage3_text*)
+        *(.text*)
     }
 
     .stage3.data : {
-        *(.stage3_data*)
+        *(.data*)
+        *(.rodata*)
     }
 
     .map : {
diff --git a/stage23/linker_nomap.ld b/stage23/linker_nomap.ld
index 99d6b439..d6c4226c 100644
--- a/stage23/linker_nomap.ld
+++ b/stage23/linker_nomap.ld
@@ -14,23 +14,27 @@ SECTIONS
     }
 
     .stage2.text : {
-        *(.text*)
+        *.s2.o(.text*)
+        *libgcc.a:*(.text*)
     }
 
     .stage2.data : {
-        *(.data*)
-        *(.rodata*)
+        *.s2.o(.data*)
+        *.s2.o(.rodata*)
+        *libgcc.a:*(.data*)
+        *libgcc.a:*(.rodata*)
     }
 
     .stage3.text : {
         stage3_addr = .;
         *(.stage3_entry*)
         *(.stage3_build_id*)
-        *(.stage3_text*)
+        *(.text*)
     }
 
     .stage3.data : {
-        *(.stage3_data*)
+        *(.data*)
+        *(.rodata*)
     }
 
     .map : {
diff --git a/stage23/linker_stage2only.ld b/stage23/linker_stage2only.ld
index 3e12ccce..16689bf8 100644
--- a/stage23/linker_stage2only.ld
+++ b/stage23/linker_stage2only.ld
@@ -14,12 +14,15 @@ SECTIONS
     }
 
     .stage2.text : {
-        *(.text*)
+        *.s2.o(.text*)
+        *libgcc.a:*(.text*)
     }
 
     .stage2.data : {
-        *(.data*)
-        *(.rodata*)
+        *.s2.o(.data*)
+        *.s2.o(.rodata*)
+        *libgcc.a:*(.data*)
+        *libgcc.a:*(.rodata*)
         stage3_addr = .;
         *(.stage3_build_id*)
         limine_map = .;
diff --git a/stage23/menu.c b/stage23/menu.c
index e855a7a0..51c12455 100644
--- a/stage23/menu.c
+++ b/stage23/menu.c
@@ -12,12 +12,10 @@
 #include <mm/pmm.h>
 #include <drivers/vbe.h>
 
-stage3_data
 static char *menu_branding = NULL;
 
 #define EDITOR_MAX_BUFFER_SIZE 4096
 
-stage3_text
 static size_t get_line_offset(size_t *displacement, size_t index, const char *buffer) {
     size_t offset = 0;
     size_t _index = index;
@@ -32,14 +30,12 @@ static size_t get_line_offset(size_t *displacement, size_t index, const char *bu
     return offset;
 }
 
-stage3_text
 static size_t get_line_length(size_t index, const char *buffer) {
     size_t i;
     for (i = index; buffer[i] != '\n' && buffer[i] != 0; i++);
     return i - index;
 }
 
-stage3_text
 static size_t get_next_line(size_t index, const char *buffer) {
     if (buffer[index] == 0)
         return index;
@@ -57,7 +53,6 @@ static size_t get_next_line(size_t index, const char *buffer) {
     return index + displacement;
 }
 
-stage3_text
 static size_t get_prev_line(size_t index, const char *buffer) {
     size_t offset, displacement, prev_line_offset, prev_line_length;
     offset = get_line_offset(&displacement, index, buffer);
@@ -71,7 +66,6 @@ static size_t get_prev_line(size_t index, const char *buffer) {
     return offset;
 }
 
-stage3_text
 static char *config_entry_editor(const char *orig_entry) {
     size_t cursor_offset  = 0;
     size_t entry_size     = strlen(orig_entry);
@@ -281,7 +275,6 @@ refresh:
     goto refresh;
 }
 
-stage3_text
 static int print_tree(int level, int base_index, int selected_entry,
                       struct menu_entry *current_entry,
                       struct menu_entry **selected_menu_entry) {
@@ -328,7 +321,6 @@ static int print_tree(int level, int base_index, int selected_entry,
     return max_entries;
 }
 
-stage3_text
 char *menu(char **cmdline) {
     menu_branding = config_get_value(NULL, 0, "MENU_BRANDING");
     if (menu_branding == NULL)
diff --git a/stage23/mm/pmm.c b/stage23/mm/pmm.s2.c
similarity index 100%
rename from stage23/mm/pmm.c
rename to stage23/mm/pmm.s2.c
diff --git a/stage23/mm/vmm.c b/stage23/mm/vmm.c
index 841b96fb..46c59eb6 100644
--- a/stage23/mm/vmm.c
+++ b/stage23/mm/vmm.c
@@ -8,7 +8,6 @@
 
 typedef uint64_t pt_entry_t;
 
-stage3_text
 static pt_entry_t *get_next_level(pt_entry_t *current_level, size_t entry) {
     pt_entry_t *ret;
 
@@ -25,7 +24,6 @@ static pt_entry_t *get_next_level(pt_entry_t *current_level, size_t entry) {
     return ret;
 }
 
-stage3_text
 pagemap_t new_pagemap(int lv) {
     pagemap_t pagemap;
     pagemap.levels    = lv;
@@ -33,7 +31,6 @@ pagemap_t new_pagemap(int lv) {
     return pagemap;
 }
 
-stage3_text
 void map_page(pagemap_t pagemap, uint64_t virt_addr, uint64_t phys_addr, uint64_t flags) {
     // Calculate the indices in the various tables using the virtual address
     size_t pml5_entry = (virt_addr & ((uint64_t)0x1ff << 48)) >> 48;
diff --git a/stage23/protos/chainload.c b/stage23/protos/chainload.c
index 5a7061a7..8bcc66eb 100644
--- a/stage23/protos/chainload.c
+++ b/stage23/protos/chainload.c
@@ -46,7 +46,6 @@ static void spinup(uint8_t drive) {
     );
 }
 
-stage3_text
 void chainload(char *config) {
     uint64_t val;
 
diff --git a/stage23/protos/linux.c b/stage23/protos/linux.c
index 0d3ef312..86cafdbe 100644
--- a/stage23/protos/linux.c
+++ b/stage23/protos/linux.c
@@ -54,7 +54,6 @@ static void spinup(uint16_t real_mode_code_seg, uint16_t kernel_entry_seg,
     );
 }
 
-stage3_text
 void linux_load(char *config, char *cmdline) {
     struct file_handle *kernel = ext_mem_alloc(sizeof(struct file_handle));
 
diff --git a/stage23/protos/stivale.c b/stage23/protos/stivale.c
index fda9ea71..26baef6d 100644
--- a/stage23/protos/stivale.c
+++ b/stage23/protos/stivale.c
@@ -24,10 +24,8 @@
 
 #define KASLR_SLIDE_BITMASK 0x000FFF000u
 
-stage3_data
 struct stivale_struct stivale_struct = {0};
 
-stage3_text
 void stivale_load(char *config, char *cmdline) {
     stivale_struct.flags |= (1 << 0);  // set bit 0 since we are BIOS and not UEFI
     stivale_struct.flags |= (1 << 1);  // we give colour information
@@ -205,7 +203,6 @@ void stivale_load(char *config, char *cmdline) {
                    entry_point, &stivale_struct, stivale_hdr.stack);
 }
 
-stage3_text
 pagemap_t stivale_build_pagemap(bool level5pg) {
     pagemap_t pagemap = new_pagemap(level5pg ? 5 : 4);
     uint64_t higher_half_base = level5pg ? 0xff00000000000000 : 0xffff800000000000;
@@ -247,7 +244,6 @@ pagemap_t stivale_build_pagemap(bool level5pg) {
     return pagemap;
 }
 
-stage3_text
 __attribute__((noreturn)) void stivale_spinup(
                  int bits, bool level5pg, pagemap_t pagemap,
                  uint64_t entry_point, void *stivale_struct, uint64_t stack) {
diff --git a/stage23/protos/stivale2.c b/stage23/protos/stivale2.c
index 74ac617c..6f354ff1 100644
--- a/stage23/protos/stivale2.c
+++ b/stage23/protos/stivale2.c
@@ -27,17 +27,14 @@
 
 #define KASLR_SLIDE_BITMASK 0x000FFF000u
 
-stage3_data
 struct stivale2_struct stivale2_struct = {0};
 
-stage3_text
 inline static size_t get_phys_addr(uint64_t addr) {
     if (addr & ((uint64_t)1 << 63))
         return addr - FIXED_HIGHER_HALF_OFFSET_64;
     return addr;
 }
 
-stage3_text
 static void *get_tag(struct stivale2_header *s, uint64_t id) {
     struct stivale2_tag *tag = (void*)get_phys_addr(s->tags);
     for (;;) {
@@ -49,13 +46,11 @@ static void *get_tag(struct stivale2_header *s, uint64_t id) {
     }
 }
 
-stage3_text
 static void append_tag(struct stivale2_struct *s, struct stivale2_tag *tag) {
     tag->next = s->tags;
     s->tags   = (uint64_t)(size_t)tag;
 }
 
-stage3_text
 void stivale2_load(char *config, char *cmdline, bool pxe) {
     struct file_handle *kernel = ext_mem_alloc(sizeof(struct file_handle));
 
diff --git a/stage23/sys/a20.c b/stage23/sys/a20.s2.c
similarity index 100%
rename from stage23/sys/a20.c
rename to stage23/sys/a20.s2.c
diff --git a/stage23/sys/e820.c b/stage23/sys/e820.s2.c
similarity index 100%
rename from stage23/sys/e820.c
rename to stage23/sys/e820.s2.c
diff --git a/stage23/sys/gdt.asm b/stage23/sys/gdt.s2.asm
similarity index 100%
rename from stage23/sys/gdt.asm
rename to stage23/sys/gdt.s2.asm
diff --git a/stage23/sys/lapic.c b/stage23/sys/lapic.c
index 6aefc725..b6d20640 100644
--- a/stage23/sys/lapic.c
+++ b/stage23/sys/lapic.c
@@ -14,7 +14,6 @@ struct dmar {
     symbol  remapping_structures;
 } __attribute__((packed));
 
-stage3_text
 bool lapic_check(void) {
     uint32_t eax, ebx, ecx, edx;
     if (!cpuid(1, 0, &eax, &ebx, &ecx, &edx))
@@ -26,19 +25,16 @@ bool lapic_check(void) {
     return true;
 }
 
-stage3_text
 uint32_t lapic_read(uint32_t reg) {
     size_t lapic_mmio_base = (size_t)(rdmsr(0x1b) & 0xfffff000);
     return mmind(lapic_mmio_base + reg);
 }
 
-stage3_text
 void lapic_write(uint32_t reg, uint32_t data) {
     size_t lapic_mmio_base = (size_t)(rdmsr(0x1b) & 0xfffff000);
     mmoutd(lapic_mmio_base + reg, data);
 }
 
-stage3_text
 bool x2apic_check(void) {
     uint32_t eax, ebx, ecx, edx;
     if (!cpuid(1, 0, &eax, &ebx, &ecx, &edx))
@@ -61,7 +57,6 @@ bool x2apic_check(void) {
     return true;
 }
 
-stage3_text
 bool x2apic_enable(void) {
     if (!x2apic_check())
         return false;
@@ -73,12 +68,10 @@ bool x2apic_enable(void) {
     return true;
 }
 
-stage3_text
 uint64_t x2apic_read(uint32_t reg) {
     return rdmsr(0x800 + (reg >> 4));
 }
 
-stage3_text
 void x2apic_write(uint32_t reg, uint64_t data) {
     wrmsr(0x800 + (reg >> 4), data);
 }
diff --git a/stage23/sys/pic.c b/stage23/sys/pic.c
index 61280be9..8d821816 100644
--- a/stage23/sys/pic.c
+++ b/stage23/sys/pic.c
@@ -5,7 +5,6 @@
 #include <sys/cpu.h>
 #include <lib/blib.h>
 
-stage3_text
 void pic_eoi(int irq) {
     if (irq >= 8) {
         outb(0xa0, 0x20);
@@ -15,13 +14,11 @@ void pic_eoi(int irq) {
 }
 
 // Flush all potentially pending IRQs
-stage3_text
 void pic_flush(void) {
     for (int i = 0; i < 16; i++)
         pic_eoi(i);
 }
 
-stage3_text
 void pic_set_mask(int line, bool status) {
     uint16_t port;
     uint8_t value;
@@ -41,7 +38,6 @@ void pic_set_mask(int line, bool status) {
     outb(port, value);
 }
 
-stage3_text
 void pic_mask_all(void) {
     outb(0xa1, 0xff);
     outb(0x21, 0xff);
diff --git a/stage23/sys/smp.c b/stage23/sys/smp.c
index ece20745..6b5d166f 100644
--- a/stage23/sys/smp.c
+++ b/stage23/sys/smp.c
@@ -42,7 +42,6 @@ struct gdtr {
     uint32_t ptr;
 } __attribute__((packed));
 
-stage3_text
 static void delay(uint32_t cycles) {
     for (uint32_t i = 0; i < cycles; i++)
         inb(0x80);
@@ -55,7 +54,6 @@ uint8_t  smp_tpl_booted_flag;
 uint32_t smp_tpl_pagemap;
 uint8_t  smp_tpl_target_mode;
 
-stage3_text
 static bool smp_start_ap(uint32_t lapic_id, struct gdtr *gdtr,
                          struct smp_information *info_struct,
                          bool longmode, bool lv5, uint32_t pagemap,
@@ -97,7 +95,6 @@ static bool smp_start_ap(uint32_t lapic_id, struct gdtr *gdtr,
     return false;
 }
 
-stage3_text
 struct smp_information *init_smp(size_t    header_hack_size,
                                  void    **header_ptr,
                                  size_t   *cpu_count,
tab: 248 wrap: offon