:: commit a5073b9a6ce100d7d8892dbe5a4e062f3b1210e8

mintsuki <mintsuki@protonmail.com> — 2021-12-12 17:25

parents: b70966e12d

Revert "Revert "misc: Allow recovering from panics""

This reverts commit 5f9ed4c78f744cbfcb408b7ed8ed567b139b7d29.
diff --git a/stage23/drivers/disk.s2.c b/stage23/drivers/disk.s2.c
index 4aaf3dfd..1507cdcb 100644
--- a/stage23/drivers/disk.s2.c
+++ b/stage23/drivers/disk.s2.c
@@ -92,7 +92,7 @@ bool disk_read_sectors(struct volume *volume, void *buf, uint64_t block, size_t
     struct dap dap = {0};
 
     if (count * volume->sector_size > XFER_BUF_SIZE)
-        panic("XFER");
+        panic(false, "XFER");
 
     if (xfer_buf == NULL)
         xfer_buf = conv_mem_alloc(XFER_BUF_SIZE);
@@ -117,7 +117,7 @@ bool disk_read_sectors(struct volume *volume, void *buf, uint64_t block, size_t
             case 0x0c:
                 return false;
             default:
-                panic("Disk error %x. Drive %x, LBA %x.",
+                panic(false, "Disk error %x. Drive %x, LBA %x.",
                       ah, volume->drive, dap.lba);
         }
     }
diff --git a/stage23/drivers/gop.c b/stage23/drivers/gop.c
index d6448cb0..52b2af10 100644
--- a/stage23/drivers/gop.c
+++ b/stage23/drivers/gop.c
@@ -86,7 +86,7 @@ static bool try_mode(struct fb_info *ret, size_t mode, int width, int height, in
                                       mode_info->PixelInformation.BlueMask);
             break;
         default:
-            panic("gop: Invalid PixelFormat");
+            panic(false, "gop: Invalid PixelFormat");
     }
 
     if (width != 0 && height != 0 && bpp != 0) {
@@ -149,7 +149,7 @@ bool init_gop(struct fb_info *ret,
     }
 
     if (status) {
-        panic("gop: Initialisation failed");
+        panic(false, "gop: Initialisation failed");
     }
 
     if (preset_mode == INVALID_PRESET_MODE)
diff --git a/stage23/entry.s2.c b/stage23/entry.s2.c
index 4385042a..5a608194 100644
--- a/stage23/entry.s2.c
+++ b/stage23/entry.s2.c
@@ -68,20 +68,19 @@ static bool stage3_init(struct volume *part) {
 }
 
 enum {
-	BOOTED_FROM_HDD,
-	BOOTED_FROM_PXE,
-	BOOTED_FROM_CD
+    BOOTED_FROM_HDD,
+    BOOTED_FROM_PXE,
+    BOOTED_FROM_CD
 };
 
 __attribute__((noreturn))
 void entry(uint8_t boot_drive, int boot_from) {
     // XXX DO NOT MOVE A20 ENABLE CALL
     if (!a20_enable())
-        panic("Could not enable A20 line");
+        panic(false, "Could not enable A20 line");
 
     term_notready();
 
-#if bios == 1
     {
     struct rm_regs r = {0};
     r.eax = 0x0003;
@@ -92,7 +91,6 @@ void entry(uint8_t boot_drive, int boot_from) {
     outb(0x3d4, 0x0a);
     outb(0x3d5, 0x20);
     }
-#endif
 
     init_e820();
     init_memmap();
@@ -123,13 +121,10 @@ void entry(uint8_t boot_drive, int boot_from) {
     }
 
     if (!stage3_loaded) {
-        panic("Failed to load stage 3.");
+        panic(false, "Failed to load stage 3.");
     }
 
-    __attribute__((noreturn))
-    void (*stage3)(int boot_from) = (void *)stage3_addr;
-
-    stage3(boot_from);
+    stage3_common();
 }
 
 #endif
diff --git a/stage23/entry.s3.c b/stage23/entry.s3.c
index d9544695..08a4edec 100644
--- a/stage23/entry.s3.c
+++ b/stage23/entry.s3.c
@@ -101,7 +101,7 @@ void uefi_entry(EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE *SystemTable) {
             if (boot_volume != NULL)
                 stage3_common();
 
-            panic("No volume contained a Limine configuration file");
+            panic(false, "No volume contained a Limine configuration file");
         }
 
         EFI_GUID loaded_img_prot_guid = EFI_LOADED_IMAGE_PROTOCOL_GUID;
@@ -111,7 +111,7 @@ void uefi_entry(EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE *SystemTable) {
                                      (void **)&loaded_image);
 
         if (status) {
-            panic("HandleProtocol failure (%x)", status);
+            panic(false, "HandleProtocol failure (%x)", status);
         }
 
         boot_volume = disk_volume_from_efi_handle(loaded_image->DeviceHandle);
@@ -124,38 +124,10 @@ void uefi_entry(EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE *SystemTable) {
 }
 #endif
 
-#if bios == 1
-__attribute__((section(".stage3_entry")))
-#endif
 __attribute__((noreturn))
 void stage3_common(void) {
-    volume_iterate_parts(boot_volume,
-        if (!init_config_disk(_PART)) {
-            boot_volume = _PART;
-            break;
-        }
-    );
-
-    char *quiet_str = config_get_value(NULL, 0, "QUIET");
-    quiet = quiet_str != NULL && strcmp(quiet_str, "yes") == 0;
-
-    char *verbose_str = config_get_value(NULL, 0, "VERBOSE");
-    verbose = verbose_str != NULL && strcmp(verbose_str, "yes") == 0;
-
-    char *randomise_mem_str = config_get_value(NULL, 0, "RANDOMISE_MEMORY");
-    if (randomise_mem_str == NULL)
-        randomise_mem_str = config_get_value(NULL, 0, "RANDOMIZE_MEMORY");
-    bool randomise_mem = randomise_mem_str != NULL && strcmp(randomise_mem_str, "yes") == 0;
-    if (randomise_mem)
-        pmm_randomise_memory();
-
     init_flush_irqs();
     init_io_apics();
 
-    if (verbose) {
-        print("Boot drive: %d\n", boot_volume->index);
-        print("Boot partition: %d\n", boot_volume->partition);
-    }
-
     menu(true);
 }
diff --git a/stage23/fs/ext2.s2.c b/stage23/fs/ext2.s2.c
index 6a617e6c..93ea837f 100644
--- a/stage23/fs/ext2.s2.c
+++ b/stage23/fs/ext2.s2.c
@@ -319,7 +319,7 @@ bool ext2_open(struct ext2_file_handle *ret, struct volume *part, const char *pa
     struct ext2_superblock *sb = &ret->sb;
 
     if (sb->s_state == EXT2_FS_UNRECOVERABLE_ERRORS)
-        panic("ext2: unrecoverable errors found");
+        panic(false, "ext2: unrecoverable errors found");
 
     ret->block_size = ((uint64_t)1024 << ret->sb.s_log_block_size);
 
@@ -367,7 +367,7 @@ static struct ext4_extent_header* ext4_find_leaf(struct ext4_extent_header* ext_
 
         #define EXT4_EXT_MAGIC 0xf30a
         if (ext_block->magic != EXT4_EXT_MAGIC)
-            panic("invalid extent magic");
+            panic(false, "invalid extent magic");
 
         if (ext_block->depth == 0) {
             return ext_block;
@@ -380,7 +380,7 @@ static struct ext4_extent_header* ext4_find_leaf(struct ext4_extent_header* ext_
         }
 
         if (--i < 0)
-            panic("extent not found");
+            panic(false, "extent not found");
 
         uint64_t block = ((uint64_t)index[i].leaf_hi << 32) | index[i].leaf;
         if(!buf)
@@ -411,7 +411,7 @@ static int inode_read(void *buf, uint64_t loc, uint64_t count,
             leaf = ext4_find_leaf((struct ext4_extent_header*)inode->i_blocks, block, fd->block_size, fd->part);
 
             if (!leaf)
-                panic("invalid extent");
+                panic(false, "invalid extent");
             ext = (struct ext4_extent*)((size_t)leaf + 12);
 
             for (i = 0; i < leaf->entries; i++) {
@@ -423,13 +423,13 @@ static int inode_read(void *buf, uint64_t loc, uint64_t count,
             if (--i >= 0) {
                 block -= ext[i].block;
                 if (block >= ext[i].len) {
-                    panic("block longer than extent");
+                    panic(false, "block longer than extent");
                 } else {
                     uint64_t start = ((uint64_t)ext[i].start_hi << 32) + ext[i].start;
                     block_index = start + block;
                 }
             } else {
-                panic("extent for block not found");
+                panic(false, "extent for block not found");
             }
 
             pmm_free(leaf, fd->block_size);
@@ -462,7 +462,7 @@ int ext2_check_signature(struct volume *part) {
         sb.s_feature_incompat & EXT2_IF_INLINE_DATA ||
         sb.s_feature_incompat & EXT2_FEATURE_INCOMPAT_META_BG ||
         sb.s_feature_incompat & EXT2_IF_ENCRYPT)
-        panic("EXT2: filesystem has unsupported features %x", sb.s_feature_incompat);
+        panic(false, "EXT2: filesystem has unsupported features %x", sb.s_feature_incompat);
 
     return 1;
 }
diff --git a/stage23/fs/iso9660.s2.c b/stage23/fs/iso9660.s2.c
index f8cedce2..ad5cf567 100644
--- a/stage23/fs/iso9660.s2.c
+++ b/stage23/fs/iso9660.s2.c
@@ -88,7 +88,7 @@ static void iso9660_find_PVD(struct iso9660_volume_descriptor *desc, struct volu
         case ISO9660_VDT_PRIMARY:
             return;
         case ISO9660_VDT_TERMINATOR:
-            panic("ISO9660: no primary volume descriptor");
+            panic(false, "ISO9660: no primary volume descriptor");
             break;
         }
 
diff --git a/stage23/lib/blib.c b/stage23/lib/blib.c
index 0611d7fa..a9f7f2f5 100644
--- a/stage23/lib/blib.c
+++ b/stage23/lib/blib.c
@@ -230,7 +230,7 @@ bool efi_exit_boot_services(void) {
 
                     efi_copy_i++;
                     if (efi_copy_i == EFI_COPY_MAX_ENTRIES) {
-                        panic("efi: New memory map exhausted");
+                        panic(false, "efi: New memory map exhausted");
                     }
                     new_entry = (void *)efi_copy + efi_copy_i * efi_desc_size;
                     memcpy(new_entry, orig_entry, efi_desc_size);
@@ -245,7 +245,7 @@ bool efi_exit_boot_services(void) {
                 }
 
                 if (length < untouched_memmap[j].length) {
-                    panic("efi: Memory map corruption");
+                    panic(false, "efi: Memory map corruption");
                 }
 
                 new_entry->Type = EfiConventionalMemory;
@@ -259,7 +259,7 @@ bool efi_exit_boot_services(void) {
 
                 efi_copy_i++;
                 if (efi_copy_i == EFI_COPY_MAX_ENTRIES) {
-                    panic("efi: New memory map exhausted");
+                    panic(false, "efi: New memory map exhausted");
                 }
                 new_entry = (void *)efi_copy + efi_copy_i * efi_desc_size;
                 memcpy(new_entry, orig_entry, efi_desc_size);
@@ -274,7 +274,7 @@ bool efi_exit_boot_services(void) {
 
         efi_copy_i++;
         if (efi_copy_i == EFI_COPY_MAX_ENTRIES) {
-            panic("efi: New memory map exhausted");
+            panic(false, "efi: New memory map exhausted");
         }
     }
 
@@ -288,7 +288,7 @@ bool efi_exit_boot_services(void) {
     return true;
 
 fail:
-    panic("efi: Failed to exit boot services");
+    panic(false, "efi: Failed to exit boot services");
 }
 
 #endif
diff --git a/stage23/lib/blib.h b/stage23/lib/blib.h
index 6df048fd..83d1a228 100644
--- a/stage23/lib/blib.h
+++ b/stage23/lib/blib.h
@@ -48,7 +48,7 @@ int digit_to_int(char c);
 uint8_t bcd_to_int(uint8_t val);
 uint8_t int_to_bcd(uint8_t val);
 
-__attribute__((noreturn)) void panic(const char *fmt, ...);
+__attribute__((noreturn)) void panic(bool allow_menu, const char *fmt, ...);
 
 int pit_sleep_and_quit_on_keypress(int seconds);
 
@@ -80,6 +80,8 @@ void memcpy32to64(uint64_t, uint64_t, uint64_t);
 
 typedef char symbol[];
 
+__attribute__((noreturn)) void stage3_common(void);
+
 __attribute__((noreturn)) void common_spinup(void *fnptr, int args, ...);
 
 #endif
diff --git a/stage23/lib/config.c b/stage23/lib/config.c
index 9be23996..182e9f35 100644
--- a/stage23/lib/config.c
+++ b/stage23/lib/config.c
@@ -13,6 +13,8 @@
 
 #define SEPARATOR '\n'
 
+extern bool *bad_config;
+
 bool config_ready = false;
 
 static char *config_addr;
@@ -78,7 +80,8 @@ static bool is_directory(char *buf, size_t limit,
         case NOT_CHILD:
             return false;
         case INDIRECT_CHILD:
-            panic("config: Malformed config file. Parentless child.");
+            *bad_config = true;
+            panic(true, "config: Malformed config file. Parentless child.");
         case DIRECT_CHILD:
             return true;
     }
diff --git a/stage23/lib/elf.c b/stage23/lib/elf.c
index 196fe18f..d8601ade 100644
--- a/stage23/lib/elf.c
+++ b/stage23/lib/elf.c
@@ -344,7 +344,7 @@ static uint64_t elf64_max_align(uint8_t *elf) {
     }
 
     if (ret == 0) {
-        panic("elf: Executable has no loadable segments");
+        panic(true, "elf: Executable has no loadable segments");
     }
 
     return ret;
@@ -372,7 +372,7 @@ static void elf64_get_ranges(uint8_t *elf, uint64_t slide, bool use_paddr, struc
     }
 
     if (ranges_count == 0) {
-        panic("elf: Attempted to use PMRs but no higher half PHDRs exist");
+        panic(true, "elf: Attempted to use PMRs but no higher half PHDRs exist");
     }
 
     struct elf_range *ranges = ext_mem_alloc(ranges_count * sizeof(struct elf_range));
@@ -423,11 +423,11 @@ int elf64_load(uint8_t *elf, uint64_t *entry_point, uint64_t *top, uint64_t *_sl
     }
 
     if (hdr.ident[EI_DATA] != BITS_LE) {
-        panic("elf: Not a Little-endian ELF file.\n");
+        panic(true, "elf: Not a Little-endian ELF file.\n");
     }
 
     if (hdr.machine != ARCH_X86_64) {
-        panic("elf: Not an x86_64 ELF file.\n");
+        panic(true, "elf: Not an x86_64 ELF file.\n");
     }
 
     uint64_t slide = 0;
@@ -471,7 +471,7 @@ int elf64_load(uint8_t *elf, uint64_t *entry_point, uint64_t *top, uint64_t *_sl
         }
 
         if (max_vaddr == 0 || min_vaddr == (uint64_t)-1) {
-            panic("elf: Attempted to use fully virtual mappings but no higher half PHDRs exist");
+            panic(true, "elf: Attempted to use fully virtual mappings but no higher half PHDRs exist");
         }
 
         image_size = max_vaddr - min_vaddr;
@@ -492,7 +492,7 @@ again:
         if (fully_virtual) {
             if ((*virtual_base - FIXED_HIGHER_HALF_OFFSET_64) + slide + image_size >= 0x80000000) {
                 if (++try_count == max_simulated_tries) {
-                    panic("elf: Image wants to load too high");
+                    panic(true, "elf: Image wants to load too high");
                 }
                 goto again;
             }
@@ -560,7 +560,7 @@ final:
             ((higher_half == true && this_top > 0x80000000)
           || !memmap_alloc_range((size_t)mem_base, (size_t)mem_size, alloc_type, true, false, simulation, false))) {
             if (++try_count == max_simulated_tries || simulation == false) {
-                panic("elf: Failed to allocate necessary memory range (%X-%X)", mem_base, mem_base + mem_size);
+                panic(true, "elf: Failed to allocate necessary memory range (%X-%X)", mem_base, mem_base + mem_size);
             }
             if (!kaslr) {
                 slide += max_align;
@@ -578,7 +578,7 @@ final:
         }
 
         if (elf64_apply_relocations(elf, &hdr, (void *)(uintptr_t)load_addr, phdr.p_vaddr, phdr.p_memsz, slide)) {
-            panic("elf: Failed to apply relocations");
+            panic(true, "elf: Failed to apply relocations");
         }
 
         if (use_paddr) {
diff --git a/stage23/lib/panic.s2.c b/stage23/lib/panic.s2.c
index 6cb2e788..564458a2 100644
--- a/stage23/lib/panic.s2.c
+++ b/stage23/lib/panic.s2.c
@@ -1,3 +1,5 @@
+#include <stddef.h>
+#include <stdbool.h>
 #include <lib/print.h>
 #include <lib/real.h>
 #include <lib/trace.h>
@@ -9,8 +11,9 @@
 #include <lib/gterm.h>
 #include <lib/term.h>
 #include <mm/pmm.h>
+#include <menu.h>
 
-__attribute__((noreturn)) void panic(const char *fmt, ...) {
+__attribute__((noreturn)) void panic(bool allow_menu, const char *fmt, ...) {
     va_list args;
 
     va_start(args, fmt);
@@ -33,24 +36,33 @@ __attribute__((noreturn)) void panic(const char *fmt, ...) {
     print("\n");
     print_stacktrace(NULL);
 
+    if (
 #if bios == 1
-    print("Press CTRL+ALT+DEL to reboot.");
-    rm_hcf();
-#elif uefi == 1
-    if (efi_boot_services_exited == false) {
-        print("Press [ENTER] to return to firmware.");
-        while (getchar() != '\n');
+      stage3_loaded == true &&
+#endif
+      allow_menu == true) {
+        print("Press a key to return to menu.");
+
+        getchar();
+
+        menu(false);
+        __builtin_unreachable();
+/*
         fb_clear(&fbinfo);
 
         // release all uefi memory and return to firmware
         pmm_release_uefi_mem();
         gBS->Exit(efi_image_handle, EFI_ABORTED, 0, NULL);
-        __builtin_unreachable();
+*/
     } else {
+#if bios == 1
+        print("Press CTRL+ALT+DEL to reboot.");
+        rm_hcf();
+#elif uefi == 1
         print("System halted.");
         for (;;) {
             asm ("hlt");
         }
-    }
 #endif
+    }
 }
diff --git a/stage23/lib/part.s2.c b/stage23/lib/part.s2.c
index 5e187a25..b4a4adcf 100644
--- a/stage23/lib/part.s2.c
+++ b/stage23/lib/part.s2.c
@@ -45,7 +45,7 @@ static bool cache_block(struct volume *volume, uint64_t block) {
 
 bool volume_read(struct volume *volume, void *buffer, uint64_t loc, uint64_t count) {
     if (volume->pxe) {
-        panic("Attempted volume_read() on pxe");
+        panic(false, "Attempted volume_read() on pxe");
     }
 
     uint64_t block_size = volume->fastest_xfer_size * volume->sector_size;
diff --git a/stage23/lib/readline.c b/stage23/lib/readline.c
index 2979a6ab..c810dab8 100644
--- a/stage23/lib/readline.c
+++ b/stage23/lib/readline.c
@@ -134,7 +134,7 @@ int getchar(void) {
 
     if (gBS->HandleProtocol(gST->ConsoleInHandle, &exproto_guid, (void **)&exproto) != EFI_SUCCESS) {
         if (gBS->HandleProtocol(gST->ConsoleInHandle, &sproto_guid, (void **)&sproto) != EFI_SUCCESS) {
-            panic("Your input device doesn't have an input protocol!");
+            panic(false, "Your input device doesn't have an input protocol!");
         }
 
         events[0] = sproto->WaitForKey;
@@ -186,7 +186,7 @@ int pit_sleep_and_quit_on_keypress(int seconds) {
 
     if (gBS->HandleProtocol(gST->ConsoleInHandle, &exproto_guid, (void **)&exproto) != EFI_SUCCESS) {
         if (gBS->HandleProtocol(gST->ConsoleInHandle, &sproto_guid, (void **)&sproto) != EFI_SUCCESS) {
-            panic("Your input device doesn't have an input protocol!");
+            panic(false, "Your input device doesn't have an input protocol!");
         }
 
         events[0] = sproto->WaitForKey;
diff --git a/stage23/lib/uri.c b/stage23/lib/uri.c
index c6d4dba5..ff680862 100644
--- a/stage23/lib/uri.c
+++ b/stage23/lib/uri.c
@@ -65,11 +65,11 @@ static bool parse_bios_partition(char *loc, int *drive, int *partition) {
         if (loc[i] == ':') {
             loc[i] = 0;
             if (*loc == 0) {
-                panic("Drive number cannot be omitted for hdd:// and odd://");
+                panic(true, "Drive number cannot be omitted for hdd:// and odd://");
             } else {
                 val = strtoui(loc, NULL, 10);
                 if (val < 1 || val > 256) {
-                    panic("Drive number outside range 1-256");
+                    panic(true, "Drive number outside range 1-256");
                 }
                 *drive = val;
             }
@@ -80,7 +80,7 @@ static bool parse_bios_partition(char *loc, int *drive, int *partition) {
 
     val = strtoui(loc, NULL, 10);
     if (val > 256) {
-        panic("Partition number outside range 0-256");
+        panic(true, "Partition number outside range 0-256");
     }
     *partition = val;
 
@@ -173,7 +173,7 @@ static struct file_handle *uri_boot_dispatch(char *s_part, char *path) {
     if (s_part[0] != '\0') {
         uint64_t val = strtoui(s_part, NULL, 10);
         if (val > 256) {
-            panic("Partition number outside range 0-256");
+            panic(true, "Partition number outside range 0-256");
         }
         partition = val;
     } else {
@@ -205,7 +205,7 @@ struct file_handle *uri_open(char *uri) {
     }
 
     if (!strcmp(resource, "bios")) {
-        panic("bios:// resource is no longer supported. Check CONFIG.md for hdd:// and odd://");
+        panic(true, "bios:// resource is no longer supported. Check CONFIG.md for hdd:// and odd://");
     } else if (!strcmp(resource, "hdd")) {
         ret = uri_hdd_dispatch(root, path);
     } else if (!strcmp(resource, "odd")) {
@@ -222,7 +222,9 @@ struct file_handle *uri_open(char *uri) {
 #endif
 	// note: fwcfg MUST be the last on the list due to fwcfg simple mode.
     } else if (!strcmp(resource, "fwcfg")) {
-		if (*root != 0) panic("no root supported in an fwcfg:// uri!");
+		if (*root != 0) {
+		    panic(true, "No root supported in an fwcfg:// uri!");
+		}
         ret = uri_fwcfg_dispatch(path);
     } else {
         panic("Resource `%s` not valid.", resource);
@@ -233,8 +235,9 @@ struct file_handle *uri_open(char *uri) {
         fread(ret, &compressed_fd->size, ret->size - 4, sizeof(uint32_t));
         compressed_fd->fd = ext_mem_alloc(compressed_fd->size);
         void *src = freadall(ret, MEMMAP_BOOTLOADER_RECLAIMABLE);
-        if (tinf_gzip_uncompress(compressed_fd->fd, src, ret->size))
-            panic("tinf error");
+        if (tinf_gzip_uncompress(compressed_fd->fd, src, ret->size)) {
+            panic(true, "tinf error");
+        }
         fclose(ret);
         compressed_fd->is_memfile = true;
         ret = compressed_fd;
diff --git a/stage23/linker.ld b/stage23/linker.ld
index 398f627e..9aa94f5d 100644
--- a/stage23/linker.ld
+++ b/stage23/linker.ld
@@ -30,7 +30,6 @@ SECTIONS
 
     .stage3.text : {
         stage3_addr = .;
-        *(.stage3_entry*)
         *(.text*)
     }
 
diff --git a/stage23/linker_dbg.ld b/stage23/linker_dbg.ld
index 62d5c27c..3082dcfc 100644
--- a/stage23/linker_dbg.ld
+++ b/stage23/linker_dbg.ld
@@ -30,7 +30,6 @@ SECTIONS
 
     .stage3.text : {
         stage3_addr = .;
-        *(.stage3_entry*)
         *(.text*)
     }
 
diff --git a/stage23/linker_nomap.ld b/stage23/linker_nomap.ld
index cd33c4e8..17dc2115 100644
--- a/stage23/linker_nomap.ld
+++ b/stage23/linker_nomap.ld
@@ -30,7 +30,6 @@ SECTIONS
 
     .stage3.text : {
         stage3_addr = .;
-        *(.stage3_entry*)
         *(.text*)
     }
 
diff --git a/stage23/linker_stage2only.ld b/stage23/linker_stage2only.ld
index 2163dfff..f6dceda8 100644
--- a/stage23/linker_stage2only.ld
+++ b/stage23/linker_stage2only.ld
@@ -26,10 +26,13 @@ SECTIONS
         *.s2.o(.data*)
         *.s2.o(.rodata*)
         stage2_map = .;
-        stage3_addr = .;
+        stage3_common = .;
         full_map = .;
         limine_sys_size = .;
         getchar_internal = .;
+        getchar = .;
+        menu = .;
+        stage3_addr = .;
     }
 
     .stage3.build-id : {
diff --git a/stage23/linker_uefi.ld b/stage23/linker_uefi.ld
index 4e2d0036..20d0fbe3 100644
--- a/stage23/linker_uefi.ld
+++ b/stage23/linker_uefi.ld
@@ -42,11 +42,13 @@ SECTIONS
    *(.sdata)
    /* the EFI loader doesn't seem to like a .bss section, so we stick
       it all into .data: */
+   bss_begin = .;
    *(.sbss)
    *(.scommon)
    *(.dynbss)
    *(.bss)
    *(COMMON)
+   bss_end = .;
    *(.rel.local)
    *(.full_map*)
   }
diff --git a/stage23/linker_uefi32.ld b/stage23/linker_uefi32.ld
index 1b323d82..38cf08c9 100644
--- a/stage23/linker_uefi32.ld
+++ b/stage23/linker_uefi32.ld
@@ -44,11 +44,13 @@ SECTIONS
    *(.got)
    /* the EFI loader doesn't seem to like a .bss section, so we stick
       it all into .data: */
+   bss_begin = .;
    *(.sbss)
    *(.scommon)
    *(.dynbss)
    *(.bss)
    *(COMMON)
+   bss_end = .;
    *(.full_map*)
   }
   .note.gnu.build-id : { *(.note.gnu.build-id) }
diff --git a/stage23/linker_uefi32_nomap.ld b/stage23/linker_uefi32_nomap.ld
index 0b33c71e..05add6f1 100644
--- a/stage23/linker_uefi32_nomap.ld
+++ b/stage23/linker_uefi32_nomap.ld
@@ -44,11 +44,13 @@ SECTIONS
    *(.got)
    /* the EFI loader doesn't seem to like a .bss section, so we stick
       it all into .data: */
+   bss_begin = .;
    *(.sbss)
    *(.scommon)
    *(.dynbss)
    *(.bss)
    *(COMMON)
+   bss_end = .;
    full_map = .;
   }
   .note.gnu.build-id : { *(.note.gnu.build-id) }
diff --git a/stage23/linker_uefi_nomap.ld b/stage23/linker_uefi_nomap.ld
index 3e67b4aa..bb65e9c4 100644
--- a/stage23/linker_uefi_nomap.ld
+++ b/stage23/linker_uefi_nomap.ld
@@ -42,11 +42,13 @@ SECTIONS
    *(.sdata)
    /* the EFI loader doesn't seem to like a .bss section, so we stick
       it all into .data: */
+   bss_begin = .;
    *(.sbss)
    *(.scommon)
    *(.dynbss)
    *(.bss)
    *(COMMON)
+   bss_end = .;
    *(.rel.local)
    full_map = .;
   }
diff --git a/stage23/menu.c b/stage23/menu.c
index b04c1066..bcb7a3b2 100644
--- a/stage23/menu.c
+++ b/stage23/menu.c
@@ -203,7 +203,7 @@ char *config_entry_editor(const char *title, const char *orig_entry) {
     }
 
     if (entry_size >= EDITOR_MAX_BUFFER_SIZE) {
-        panic("Entry is too big to be edited.");
+        panic(true, "Entry is too big to be edited.");
     }
 
     bool syntax_highlighting_enabled = true;
@@ -539,6 +539,7 @@ __attribute__((noreturn, naked))
 void menu(__attribute__((unused)) bool timeout_enabled) {
 #if defined (__i386__)
     asm volatile (
+        "pop %eax\n\t"
         "call 1f\n\t"
         "1:\n\t"
         "pop %eax\n\t"
@@ -546,14 +547,17 @@ void menu(__attribute__((unused)) bool timeout_enabled) {
         "cmpl $0, (%eax)\n\t"
         "jne 1f\n\t"
         "mov %esp, (%eax)\n\t"
-        "jmp _menu\n\t"
+        "jmp 3f\n\t"
         "1:\n\t"
         "mov (%esp), %edi\n\t"
         "mov (%eax), %esp\n\t"
         "push %edi\n\t"
-        "call _menu\n\t"
+        "jmp 3f\n\t"
         "2:\n\t"
-        ".long 0"
+        ".long 0\n\t"
+        "3:\n\t"
+        "push $0\n\t"
+        "jmp _menu"
     );
 #elif defined (__x86_64__)
     asm volatile (
@@ -561,16 +565,60 @@ void menu(__attribute__((unused)) bool timeout_enabled) {
         "cmp %rax, stack_at_first_entry(%rip)\n\t"
         "jne 1f\n\t"
         "mov %rsp, stack_at_first_entry(%rip)\n\t"
-        "jmp _menu\n\t"
+        "jmp 2f\n\t"
         "1:\n\t"
         "mov stack_at_first_entry(%rip), %rsp\n\t"
+        "2:\n\t"
+        "push $0\n\t"
         "jmp _menu"
     );
 #endif
 }
 
+static struct e820_entry_t *rewound_memmap = NULL;
+static size_t rewound_memmap_entries = 0;
+static uint8_t *rewound_bss;
+
+extern symbol bss_begin;
+extern symbol bss_end;
+
+bool *bad_config = NULL;
+
 __attribute__((noreturn, used))
 static void _menu(bool timeout_enabled) {
+    if (bad_config == NULL) {
+        bad_config = ext_mem_alloc(1);
+    }
+
+    size_t bss_size = (uintptr_t)bss_end - (uintptr_t)bss_begin;
+
+    if (rewound_memmap != NULL) {
+        memcpy(bss_begin, rewound_bss, bss_size);
+        memcpy(memmap, rewound_memmap, rewound_memmap_entries * sizeof(struct e820_entry_t));
+        memmap_entries = rewound_memmap_entries;
+    } else {
+        rewound_bss = ext_mem_alloc(bss_size);
+        rewound_memmap = ext_mem_alloc(256 * sizeof(struct e820_entry_t));
+        memcpy(rewound_memmap, memmap, memmap_entries * sizeof(struct e820_entry_t));
+        rewound_memmap_entries = memmap_entries;
+        memcpy(rewound_bss, bss_begin, bss_size);
+    }
+
+    if (*bad_config == false) {
+        volume_iterate_parts(boot_volume,
+            if (!init_config_disk(_PART)) {
+                boot_volume = _PART;
+                break;
+            }
+        );
+    }
+
+    char *quiet_str = config_get_value(NULL, 0, "QUIET");
+    quiet = quiet_str != NULL && strcmp(quiet_str, "yes") == 0;
+
+    char *verbose_str = config_get_value(NULL, 0, "VERBOSE");
+    verbose = verbose_str != NULL && strcmp(verbose_str, "yes") == 0;
+
     menu_branding = config_get_value(NULL, 0, "MENU_BRANDING");
     if (menu_branding == NULL)
         menu_branding = "Limine " LIMINE_VERSION;
@@ -821,7 +869,7 @@ autodetect:
         multiboot2_load(config, cmdline);
         multiboot1_load(config, cmdline);
         linux_load(config, cmdline);
-        panic("Kernel protocol autodetection failed");
+        panic(true, "Kernel protocol autodetection failed");
     }
 
     bool ret = true;
diff --git a/stage23/mm/pmm.s2.c b/stage23/mm/pmm.s2.c
index 2f444937..037d27e6 100644
--- a/stage23/mm/pmm.s2.c
+++ b/stage23/mm/pmm.s2.c
@@ -24,13 +24,13 @@ void *conv_mem_alloc(size_t count) {
     static uintptr_t base = 4096;
 
     if (allocations_disallowed)
-        panic("Memory allocations disallowed");
+        panic(false, "Memory allocations disallowed");
 
     count = ALIGN_UP(count, 4096);
 
     for (;;) {
         if (base + count > 0x100000)
-            panic("Conventional memory allocation failed");
+            panic(false, "Conventional memory allocation failed");
 
         if (memmap_alloc_range(base, count, MEMMAP_BOOTLOADER_RECLAIMABLE, true, false, false, false)) {
             void *ret = (void *)base;
@@ -143,7 +143,7 @@ static void sanitise_entries(struct e820_entry_t *m, size_t *_count, bool align_
             // TODO actually handle splitting off usable chunks
             if ( (res_base >= base && res_base < top)
               && (res_top  >= base && res_top  < top) ) {
-                panic("A non-usable e820 entry is inside a usable section.");
+                panic(false, "A non-usable e820 entry is inside a usable section.");
             }
 
             if (res_base >= base && res_base < top) {
@@ -239,7 +239,7 @@ struct e820_entry_t *get_memmap(size_t *entries) {
 void init_memmap(void) {
     for (size_t i = 0; i < e820_entries; i++) {
         if (memmap_entries == memmap_max_entries) {
-            panic("Memory map exhausted.");
+            panic(false, "Memory map exhausted.");
         }
 
         memmap[memmap_entries] = e820_map[i];
@@ -394,7 +394,7 @@ void init_memmap(void) {
     return;
 
 fail:
-    panic("pmm: Failure initialising memory map");
+    panic(false, "pmm: Failure initialising memory map");
 }
 
 void pmm_reclaim_uefi_mem(void) {
@@ -523,7 +523,7 @@ void pmm_release_uefi_mem(void) {
         status = gBS->FreePages(untouched_memmap[i].base, untouched_memmap[i].length / 4096);
 
         if (status) {
-            panic("pmm: FreePages failure (%x)", status);
+            panic(false, "pmm: FreePages failure (%x)", status);
         }
     }
 
@@ -589,7 +589,7 @@ struct e820_entry_t *get_raw_memmap(size_t *entry_count) {
 void pmm_free(void *ptr, size_t count) {
     count = ALIGN_UP(count, 4096);
     if (allocations_disallowed)
-        panic("Memory allocations disallowed");
+        panic(false, "Memory allocations disallowed");
     memmap_alloc_range((uintptr_t)ptr, count, MEMMAP_USABLE, false, false, false, false);
 }
 
@@ -606,7 +606,7 @@ void *ext_mem_alloc_type_aligned(size_t count, uint32_t type, size_t alignment)
     count = ALIGN_UP(count, alignment);
 
     if (allocations_disallowed)
-        panic("Memory allocations disallowed");
+        panic(false, "Memory allocations disallowed");
 
     for (int i = memmap_entries - 1; i >= 0; i--) {
         if (memmap[i].type != 1)
@@ -642,7 +642,7 @@ void *ext_mem_alloc_type_aligned(size_t count, uint32_t type, size_t alignment)
         return ret;
     }
 
-    panic("High memory allocator: Out of memory");
+    panic(false, "High memory allocator: Out of memory");
 }
 
 /// Compute and returns the amount of upper and lower memory till
@@ -714,7 +714,7 @@ static bool pmm_new_entry(uint64_t base, uint64_t length, uint32_t type) {
 
             // Now we need to create a new entry
             if (memmap_entries >= memmap_max_entries)
-                panic("Memory map exhausted.");
+                panic(false, "Memory map exhausted.");
 
             struct e820_entry_t *new_entry = &memmap[memmap_entries++];
 
@@ -727,7 +727,7 @@ static bool pmm_new_entry(uint64_t base, uint64_t length, uint32_t type) {
     }
 
     if (memmap_entries >= memmap_max_entries)
-        panic("Memory map exhausted.");
+        panic(false, "Memory map exhausted.");
 
     struct e820_entry_t *target = &memmap[memmap_entries++];
 
@@ -766,7 +766,7 @@ bool memmap_alloc_range(uint64_t base, uint64_t length, uint32_t type, bool free
                 target = &memmap[i];
             } else {
                 if (memmap_entries >= memmap_max_entries)
-                    panic("Memory map exhausted.");
+                    panic(false, "Memory map exhausted.");
 
                 target = &memmap[memmap_entries++];
             }
@@ -777,7 +777,7 @@ bool memmap_alloc_range(uint64_t base, uint64_t length, uint32_t type, bool free
 
             if (top < entry_top) {
                 if (memmap_entries >= memmap_max_entries)
-                    panic("Memory map exhausted.");
+                    panic(false, "Memory map exhausted.");
 
                 target = &memmap[memmap_entries++];
 
@@ -793,7 +793,7 @@ bool memmap_alloc_range(uint64_t base, uint64_t length, uint32_t type, bool free
     }
 
     if (!new_entry && do_panic)
-        panic("Memory allocation failure.");
+        panic(false, "Memory allocation failure.");
 
     if (new_entry) {
         return pmm_new_entry(base, length, type);
diff --git a/stage23/mm/vmm.c b/stage23/mm/vmm.c
index 76f51394..5c76384d 100644
--- a/stage23/mm/vmm.c
+++ b/stage23/mm/vmm.c
@@ -12,7 +12,7 @@ typedef uint64_t pt_entry_t;
 void vmm_assert_nx(void) {
     uint32_t a, b, c, d;
     if (!cpuid(0x80000001, 0, &a, &b, &c, &d) || !(d & (1 << 20))) {
-        panic("vmm: NX functionality not available on this CPU.");
+        panic(false, "vmm: NX functionality not available on this CPU.");
     }
 }
 
@@ -58,7 +58,7 @@ void map_page(pagemap_t pagemap, uint64_t virt_addr, uint64_t phys_addr, uint64_
             pml4 = pagemap.top_level;
             goto level4;
         default:
-            panic("");
+            __builtin_unreachable();
     }
 
 level5:
diff --git a/stage23/protos/chainload.c b/stage23/protos/chainload.c
index 9f8876b1..5f89fd6d 100644
--- a/stage23/protos/chainload.c
+++ b/stage23/protos/chainload.c
@@ -80,7 +80,7 @@ void chainload(char *config) {
         } else {
             val = strtoui(part_config, NULL, 10);
             if (val > 256) {
-                panic("BIOS partition number outside range 0-256");
+                panic(true, "chainload: BIOS partition number outside range 0-256");
             }
             part = val;
         }
@@ -88,11 +88,11 @@ void chainload(char *config) {
     int drive; {
         char *drive_config = config_get_value(config, 0, "DRIVE");
         if (drive_config == NULL) {
-            panic("DRIVE not specified");
+            panic(true, "chainload: DRIVE not specified");
         }
         val = strtoui(drive_config, NULL, 10);
         if (val < 1 || val > 256) {
-            panic("BIOS drive number outside range 1-256");
+            panic(true, "chainload: BIOS drive number outside range 1-256");
         }
         drive = val;
     }
@@ -114,11 +114,11 @@ void chainload(char *config) {
 
     char *image_path = config_get_value(config, 0, "IMAGE_PATH");
     if (image_path == NULL)
-        panic("chainload: IMAGE_PATH not specified");
+        panic(true, "chainload: IMAGE_PATH not specified");
 
     struct file_handle *image;
     if ((image = uri_open(image_path)) == NULL)
-        panic("chainload: Failed to open image with path `%s`. Is the path correct?", image_path);
+        panic(true, "chainload: Failed to open image with path `%s`. Is the path correct?", image_path);
 
     EFI_HANDLE efi_part_handle = image->efi_part_handle;
 
@@ -127,7 +127,7 @@ void chainload(char *config) {
     void *ptr;
     status = gBS->AllocatePool(EfiLoaderData, image_size, &ptr);
     if (status)
-        panic("chainload: Allocation failure");
+        panic(true, "chainload: Allocation failure");
     memcpy(ptr, _ptr, image_size);
 
     pmm_free(_ptr, image->size);
@@ -143,7 +143,7 @@ void chainload(char *config) {
 
     struct fb_info fbinfo;
     if (!fb_init(&fbinfo, req_width, req_height, req_bpp))
-        panic("chainload: Unable to set video mode");
+        panic(true, "chainload: Unable to set video mode");
 
     pmm_release_uefi_mem();
 
@@ -169,7 +169,7 @@ void chainload(char *config) {
                             (EFI_DEVICE_PATH *)memdev_path,
                             ptr, image_size, &new_handle);
     if (status) {
-        panic("chainload: LoadImage failure (%x)", status);
+        panic(false, "chainload: LoadImage failure (%x)", status);
     }
 
     // Apparently we need to make sure that the DeviceHandle field is the same
@@ -180,7 +180,7 @@ void chainload(char *config) {
     status = gBS->HandleProtocol(new_handle, &loaded_img_prot_guid,
                                  (void **)&new_handle_loaded_image);
     if (status) {
-        panic("chainload: HandleProtocol failure (%x)", status);
+        panic(false, "chainload: HandleProtocol failure (%x)", status);
     }
 
     if (efi_part_handle != 0) {
@@ -193,7 +193,7 @@ void chainload(char *config) {
 
     status = gBS->Exit(efi_image_handle, exit_status, exit_data_size, exit_data);
     if (status) {
-        panic("chainload: Exit failure (%x)", status);
+        panic(false, "chainload: Exit failure (%x)", status);
     }
 
     __builtin_unreachable();
diff --git a/stage23/protos/linux.c b/stage23/protos/linux.c
index d4b3a123..817d0bb2 100644
--- a/stage23/protos/linux.c
+++ b/stage23/protos/linux.c
@@ -351,10 +351,10 @@ bool linux_load(char *config, char *cmdline) {
 
     char *kernel_path = config_get_value(config, 0, "KERNEL_PATH");
     if (kernel_path == NULL)
-        panic("linux: KERNEL_PATH not specified");
+        panic(true, "linux: KERNEL_PATH not specified");
 
     if ((kernel_file = uri_open(kernel_path)) == NULL)
-        panic("linux: Failed to open kernel with path `%s`. Is the path correct?", kernel_path);
+        panic(true, "linux: Failed to open kernel with path `%s`. Is the path correct?", kernel_path);
 
     uint32_t signature;
     fread(kernel_file, &signature, 0x202, sizeof(uint32_t));
@@ -391,7 +391,7 @@ bool linux_load(char *config, char *cmdline) {
            setup_header->version >> 8, setup_header->version & 0xff);
 
     if (setup_header->version < 0x203) {
-        panic("linux: Protocols < 2.03 are not supported");
+        panic(true, "linux: Protocols < 2.03 are not supported");
     }
 
     setup_header->cmd_line_ptr = (uint32_t)(uintptr_t)cmdline;
@@ -411,7 +411,7 @@ bool linux_load(char *config, char *cmdline) {
     setup_header->type_of_loader = 0xff;
 
     if (!(setup_header->loadflags & (1 << 0))) {
-        panic("linux: Kernels that load at 0x10000 are not supported");
+        panic(true, "linux: Kernels that load at 0x10000 are not supported");
     }
 
     setup_header->loadflags &= ~(1 << 5);     // print early messages
@@ -448,7 +448,7 @@ bool linux_load(char *config, char *cmdline) {
 
         struct file_handle *module;
         if ((module = uri_open(module_path)) == NULL)
-            panic("linux: Failed to open module with path `%s`. Is the path correct?", module_path);
+            panic(true, "linux: Failed to open module with path `%s`. Is the path correct?", module_path);
 
         size_of_all_modules += module->size;
 
@@ -475,7 +475,7 @@ bool linux_load(char *config, char *cmdline) {
 
         struct file_handle *module;
         if ((module = uri_open(module_path)) == NULL)
-            panic("linux: Could not open `%s`", module_path);
+            panic(true, "linux: Could not open `%s`", module_path);
 
         fread(module, (void *)_modules_mem_base, 0, module->size);
 
@@ -514,7 +514,7 @@ bool linux_load(char *config, char *cmdline) {
     struct fb_info fbinfo;
     if (!fb_init(&fbinfo, req_width, req_height, req_bpp)) {
 #if uefi == 1
-        panic("linux: Unable to set video mode");
+        panic(true, "linux: Unable to set video mode");
 #elif bios == 1
 set_textmode:;
         size_t rows, cols;
diff --git a/stage23/protos/multiboot1.c b/stage23/protos/multiboot1.c
index 42198b3b..dbdbacca 100644
--- a/stage23/protos/multiboot1.c
+++ b/stage23/protos/multiboot1.c
@@ -26,10 +26,10 @@ bool multiboot1_load(char *config, char *cmdline) {
 
     char *kernel_path = config_get_value(config, 0, "KERNEL_PATH");
     if (kernel_path == NULL)
-        panic("multiboot1: KERNEL_PATH not specified");
+        panic(true, "multiboot1: KERNEL_PATH not specified");
 
     if ((kernel_file = uri_open(kernel_path)) == NULL)
-        panic("multiboot1: Failed to open kernel with path `%s`. Is the path correct?", kernel_path);
+        panic(true, "multiboot1: Failed to open kernel with path `%s`. Is the path correct?", kernel_path);
 
     uint8_t *kernel = freadall(kernel_file, MEMMAP_KERNEL_AND_MODULES);
 
@@ -60,14 +60,14 @@ bool multiboot1_load(char *config, char *cmdline) {
     struct multiboot1_info *multiboot1_info = conv_mem_alloc(sizeof(struct multiboot1_info));
 
     if (header.magic + header.flags + header.checksum)
-        panic("multiboot1: Header checksum is invalid");
+        panic(true, "multiboot1: Header checksum is invalid");
 
     uint32_t entry_point;
     uint32_t kernel_top;
 
     if (header.flags & (1 << 16)) {
         if (header.load_addr > header.header_addr)
-            panic("multiboot1: Illegal load address");
+            panic(true, "multiboot1: Illegal load address");
 
         size_t load_size = 0;
 
@@ -85,7 +85,7 @@ bool multiboot1_load(char *config, char *cmdline) {
         if (header.bss_end_addr) {
             uintptr_t bss_addr = header.load_addr + load_size;
             if (header.bss_end_addr < bss_addr)
-                panic("multiboot1: Illegal bss end address");
+                panic(true, "multiboot1: Illegal bss end address");
 
             uint32_t bss_size = header.bss_end_addr - bss_addr;
 
@@ -102,19 +102,19 @@ bool multiboot1_load(char *config, char *cmdline) {
         switch (bits) {
             case 32:
                 if (elf32_load(kernel, &entry_point, &kernel_top, MEMMAP_KERNEL_AND_MODULES))
-                    panic("multiboot1: ELF32 load failure");
+                    panic(true, "multiboot1: ELF32 load failure");
                 break;
             case 64: {
                 uint64_t e, t;
                 if (elf64_load(kernel, &e, &t, NULL, MEMMAP_KERNEL_AND_MODULES, false, true, NULL, NULL, false, NULL, NULL))
-                    panic("multiboot1: ELF64 load failure");
+                    panic(true, "multiboot1: ELF64 load failure");
                 entry_point = e;
                 kernel_top = t;
 
                 break;
             }
             default:
-                panic("multiboot1: Invalid ELF file bitness");
+                panic(true, "multiboot1: Invalid ELF file bitness");
         }
     }
 
@@ -136,13 +136,13 @@ bool multiboot1_load(char *config, char *cmdline) {
 
             char *module_path = config_get_value(config, i, "MODULE_PATH");
             if (module_path == NULL)
-                panic("multiboot1: Module disappeared unexpectedly");
+                panic(true, "multiboot1: Module disappeared unexpectedly");
 
             print("multiboot1: Loading module `%s`...\n", module_path);
 
             struct file_handle *f;
             if ((f = uri_open(module_path)) == NULL)
-                panic("multiboot1: Failed to open module with path `%s`. Is the path correct?", module_path);
+                panic(true, "multiboot1: Failed to open module with path `%s`. Is the path correct?", module_path);
 
             char *module_cmdline = config_get_value(config, i, "MODULE_STRING");
             char *lowmem_modstr = conv_mem_alloc(strlen(module_cmdline) + 1);
@@ -218,7 +218,7 @@ bool multiboot1_load(char *config, char *cmdline) {
         } else if (header.fb_mode == 1) {
 nofb:;
 #if uefi == 1
-            panic("multiboot1: Cannot use text mode with UEFI.");
+            panic(true, "multiboot1: Cannot use text mode with UEFI.");
 #elif bios == 1
             size_t rows, cols;
             init_vga_textmode(&rows, &cols, false);
@@ -231,13 +231,13 @@ nofb:;
             multiboot1_info->fb_type    = 2;
 #endif
         } else {
-            panic("multiboot1: Illegal framebuffer type requested");
+            panic(true, "multiboot1: Illegal framebuffer type requested");
         }
 
         multiboot1_info->flags |= (1 << 12);
     } else {
 #if uefi == 1
-        panic("multiboot1: Cannot use text mode with UEFI.");
+        panic(true, "multiboot1: Cannot use text mode with UEFI.");
 #elif bios == 1
         size_t rows, cols;
         init_vga_textmode(&rows, &cols, false);
diff --git a/stage23/protos/multiboot2.c b/stage23/protos/multiboot2.c
index c5162f1d..d49d3aff 100644
--- a/stage23/protos/multiboot2.c
+++ b/stage23/protos/multiboot2.c
@@ -57,10 +57,10 @@ bool multiboot2_load(char *config, char* cmdline) {
 
     char *kernel_path = config_get_value(config, 0, "KERNEL_PATH");
     if (kernel_path == NULL)
-        panic("multiboot2: KERNEL_PATH not specified");
+        panic(true, "multiboot2: KERNEL_PATH not specified");
 
     if ((kernel_file = uri_open(kernel_path)) == NULL)
-        panic("multiboot2: Failed to open kernel with path `%s`. Is the path correct?", kernel_path);
+        panic(true, "multiboot2: Failed to open kernel with path `%s`. Is the path correct?", kernel_path);
 
     uint8_t *kernel = freadall(kernel_file, MEMMAP_KERNEL_AND_MODULES);
 
@@ -86,7 +86,7 @@ bool multiboot2_load(char *config, char* cmdline) {
     print("multiboot2: Loading kernel `%s`...\n", kernel_path);
 
     if (header->magic + header->architecture + header->checksum + header->header_length) {
-        panic("multiboot2: Header checksum is invalid");
+        panic(true, "multiboot2: Header checksum is invalid");
     }
 
     struct multiboot_header_tag_address *addresstag = NULL;
@@ -144,7 +144,7 @@ bool multiboot2_load(char *config, char* cmdline) {
                             break;
                         default:
                             if (is_required)
-                                panic("multiboot2: Requested tag `%d` which is not supported", r);
+                                panic(true, "multiboot2: Requested tag `%d` which is not supported", r);
                             break;
                     }
                 }
@@ -168,7 +168,7 @@ bool multiboot2_load(char *config, char* cmdline) {
             case MULTIBOOT_HEADER_TAG_EFI_BS:
                 break;
 
-            default: panic("multiboot2: Unknown header tag type");
+            default: panic(true, "multiboot2: Unknown header tag type");
         }
     }
 
@@ -176,7 +176,7 @@ bool multiboot2_load(char *config, char* cmdline) {
 
     if (addresstag != NULL) {
         if (addresstag->load_addr > addresstag->header_addr)
-            panic("multiboot2: Illegal load address");
+            panic(true, "multiboot2: Illegal load address");
 
         size_t load_size = 0;
 
@@ -196,7 +196,7 @@ bool multiboot2_load(char *config, char* cmdline) {
         if (addresstag->bss_end_addr) {
             uintptr_t bss_addr = addresstag->load_addr + load_size;
             if (addresstag->bss_end_addr < bss_addr)
-                panic("multiboot2: Illegal bss end address");
+                panic(true, "multiboot2: Illegal bss end address");
 
             uint32_t bss_size = addresstag->bss_end_addr - bss_addr;
 
@@ -212,17 +212,17 @@ bool multiboot2_load(char *config, char* cmdline) {
         switch (bits) {
             case 32:
                 if (elf32_load(kernel, (uint32_t *)&e, (uint32_t *)&t, MEMMAP_KERNEL_AND_MODULES))
-                    panic("multiboot2: ELF32 load failure");
+                    panic(true, "multiboot2: ELF32 load failure");
 
                 break;
             case 64: {
                 if (elf64_load(kernel, &e, &t, NULL, MEMMAP_KERNEL_AND_MODULES, false, true, NULL, NULL, false, NULL, NULL))
-                    panic("multiboot2: ELF64 load failure");
+                    panic(true, "multiboot2: ELF64 load failure");
 
                 break;
             }
             default:
-                panic("multiboot2: Invalid ELF file bitness");
+                panic(true, "multiboot2: Invalid ELF file bitness");
         }
 
         if (entry_point == 0xffffffff) {
@@ -293,13 +293,13 @@ bool multiboot2_load(char *config, char* cmdline) {
     for (size_t i = 0; i < n_modules; i++) {
         char *module_path = config_get_value(config, i, "MODULE_PATH");
         if (module_path == NULL)
-            panic("multiboot2: Module disappeared unexpectedly");
+            panic(true, "multiboot2: Module disappeared unexpectedly");
 
         print("multiboot2: Loading module `%s`...\n", module_path);
 
         struct file_handle *f;
         if ((f = uri_open(module_path)) == NULL)
-            panic("multiboot2: Failed to open module with path `%s`. Is the path correct?", module_path);
+            panic(true, "multiboot2: Failed to open module with path `%s`. Is the path correct?", module_path);
 
         char *module_cmdline = config_get_value(config, i, "MODULE_STRING");
         void *module_addr = (void *)(uintptr_t)ALIGN_UP(kernel_top, 4096);
@@ -418,7 +418,7 @@ bool multiboot2_load(char *config, char* cmdline) {
                 tag->common.framebuffer_bpp = 16;
                 tag->common.framebuffer_type = MULTIBOOT_FRAMEBUFFER_TYPE_EGA_TEXT;
 #elif uefi == 1
-                panic("multiboot2: Cannot use text mode with UEFI");
+                panic(true, "multiboot2: Cannot use text mode with UEFI");
 #endif
             } else {
                 tag->common.type = MULTIBOOT_TAG_TYPE_FRAMEBUFFER;
@@ -441,7 +441,7 @@ bool multiboot2_load(char *config, char* cmdline) {
             append_tag(info_idx, &tag->common);
         } else {
 #if uefi == 1
-            panic("multiboot2: Cannot use text mode with UEFI");
+            panic(true, "multiboot2: Cannot use text mode with UEFI");
 #elif bios == 1
             size_t rows, cols;
             init_vga_textmode(&rows, &cols, false);
@@ -465,7 +465,7 @@ bool multiboot2_load(char *config, char* cmdline) {
             memcpy(tag->rsdp, new_rsdp, sizeof(struct rsdp));
             append_tag(info_idx, tag);
         } else if (is_new_acpi_required) {
-            panic("multiboot2: XSDP requested but not found");
+            panic(true, "multiboot2: XSDP requested but not found");
         }
     }
 
@@ -485,7 +485,7 @@ bool multiboot2_load(char *config, char* cmdline) {
             memcpy(tag->rsdp, old_rsdp, 20);
             append_tag(info_idx, tag);
         } else if (is_old_acpi_required) {
-            panic("multiboot2: RSDP requested but not found");
+            panic(true, "multiboot2: RSDP requested but not found");
         }
     }
 
@@ -558,7 +558,7 @@ bool multiboot2_load(char *config, char* cmdline) {
     {
         if (section_hdr_info == NULL) {
             if (is_elf_info_requested) {
-                panic("multiboot2: Cannot return ELF file information");
+                panic(true, "multiboot2: Cannot return ELF file information");
             }
         } else {
             uint32_t size = sizeof(struct multiboot_tag_elf_sections) + section_hdr_info->section_hdr_size;
@@ -588,7 +588,7 @@ bool multiboot2_load(char *config, char* cmdline) {
     //////////////////////////////////////////////
     {
         if (mb_mmap_count > 256) {
-            panic("multiboot2: too many memory map entries");
+            panic(false, "multiboot2: too many memory map entries");
         }
 
         // Create the normal memory map tag.
@@ -635,7 +635,7 @@ bool multiboot2_load(char *config, char* cmdline) {
 #if uefi == 1
     {
         if ((efi_mmap_size / efi_desc_size) > 256) {
-            panic("multiboot2: too many EFI memory map entries");
+            panic(false, "multiboot2: too many EFI memory map entries");
         }
 
         // Create the EFI memory map tag.
diff --git a/stage23/protos/stivale.c b/stage23/protos/stivale.c
index 8dfd10c6..0f93ab4f 100644
--- a/stage23/protos/stivale.c
+++ b/stage23/protos/stivale.c
@@ -70,10 +70,10 @@ bool stivale_load(char *config, char *cmdline) {
 
     char *kernel_path = config_get_value(config, 0, "KERNEL_PATH");
     if (kernel_path == NULL)
-        panic("stivale: KERNEL_PATH not specified");
+        panic(true, "stivale: KERNEL_PATH not specified");
 
     if ((kernel_file = uri_open(kernel_path)) == NULL)
-        panic("stivale: Failed to open kernel with path `%s`. Is the path correct?", kernel_path);
+        panic(true, "stivale: Failed to open kernel with path `%s`. Is the path correct?", kernel_path);
 
     char *kaslr_s = config_get_value(config, 0, "KASLR");
     bool kaslr = true;
@@ -131,7 +131,7 @@ bool stivale_load(char *config, char *cmdline) {
             // Check if 64 bit CPU
             uint32_t eax, ebx, ecx, edx;
             if (!cpuid(0x80000001, 0, &eax, &ebx, &ecx, &edx) || !(edx & (1 << 29))) {
-                panic("stivale: This CPU does not support 64-bit mode.");
+                panic(true, "stivale: This CPU does not support 64-bit mode.");
             }
             // Check if 5-level paging is available
             if (cpuid(0x00000007, 0, &eax, &ebx, &ecx, &edx) && (ecx & (1 << 16))) {
@@ -143,7 +143,7 @@ bool stivale_load(char *config, char *cmdline) {
                 if (elf64_load(kernel, &entry_point, NULL, &slide,
                                STIVALE_MMAP_KERNEL_AND_MODULES, kaslr, false,
                                NULL, NULL, false, NULL, NULL))
-                    panic("stivale: ELF64 load failure");
+                    panic(true, "stivale: ELF64 load failure");
 
                 ret = elf64_load_section(kernel, &stivale_hdr, ".stivalehdr",
                                          sizeof(struct stivale_header), slide);
@@ -154,7 +154,7 @@ bool stivale_load(char *config, char *cmdline) {
         case 32: {
             if (!loaded_by_anchor) {
                 if (elf32_load(kernel, (uint32_t *)&entry_point, NULL, 10))
-                    panic("stivale: ELF32 load failure");
+                    panic(true, "stivale: ELF32 load failure");
 
                 ret = elf32_load_section(kernel, &stivale_hdr, ".stivalehdr",
                                          sizeof(struct stivale_header));
@@ -163,24 +163,24 @@ bool stivale_load(char *config, char *cmdline) {
             break;
         }
         default:
-            panic("stivale: Not 32 nor 64-bit kernel. What is this?");
+            panic(true, "stivale: Not 32 nor 64-bit kernel. What is this?");
     }
 
     printv("stivale: %u-bit kernel detected\n", bits);
 
     switch (ret) {
         case 1:
-            panic("stivale: File is not a valid ELF.");
+            panic(true, "stivale: File is not a valid ELF.");
         case 2:
-            panic("stivale: Section .stivalehdr not found.");
+            panic(true, "stivale: Section .stivalehdr not found.");
         case 3:
-            panic("stivale: Section .stivalehdr exceeds the size of the struct.");
+            panic(true, "stivale: Section .stivalehdr exceeds the size of the struct.");
         case 4:
-            panic("stivale: Section .stivalehdr is smaller than size of the struct.");
+            panic(true, "stivale: Section .stivalehdr is smaller than size of the struct.");
     }
 
     if ((stivale_hdr.flags & (1 << 3)) && bits == 32) {
-        panic("stivale: Higher half addresses header flag not supported in 32-bit mode.");
+        panic(true, "stivale: Higher half addresses header flag not supported in 32-bit mode.");
     }
 
     bool want_5lv = level5pg && (stivale_hdr.flags & (1 << 1));
@@ -215,7 +215,7 @@ bool stivale_load(char *config, char *cmdline) {
 
     // It also says the stack cannot be NULL for 32-bit kernels
     if (bits == 32 && stivale_hdr.stack == 0) {
-        panic("stivale: The stack cannot be 0 for 32-bit kernels");
+        panic(true, "stivale: The stack cannot be 0 for 32-bit kernels");
     }
 
     stivale_struct->module_count = 0;
@@ -258,7 +258,7 @@ bool stivale_load(char *config, char *cmdline) {
 
         struct file_handle *f;
         if ((f = uri_open(module_path)) == NULL)
-            panic("stivale: Failed to open module with path `%s`. Is the path correct?", module_path);
+            panic(true, "stivale: Failed to open module with path `%s`. Is the path correct?", module_path);
 
         m->begin = REPORTED_ADDR((uint64_t)(size_t)freadall(f, STIVALE_MMAP_KERNEL_AND_MODULES));
         m->end   = m->begin + f->size;
@@ -309,7 +309,7 @@ bool stivale_load(char *config, char *cmdline) {
 
         struct fb_info fbinfo;
         if (!fb_init(&fbinfo, req_width, req_height, req_bpp))
-            panic("stivale: Unable to set video mode");
+            panic(true, "stivale: Unable to set video mode");
 
         memmap_alloc_range(fbinfo.framebuffer_addr,
                            (uint64_t)fbinfo.framebuffer_pitch * fbinfo.framebuffer_height,
@@ -329,7 +329,7 @@ bool stivale_load(char *config, char *cmdline) {
         stivale_struct->fb_blue_mask_shift  = fbinfo.blue_mask_shift;
     } else {
 #if uefi == 1
-        panic("stivale: Cannot use text mode with UEFI.");
+        panic(true, "stivale: Cannot use text mode with UEFI.");
 #elif bios == 1
         size_t rows, cols;
         init_vga_textmode(&rows, &cols, false);
@@ -347,7 +347,7 @@ bool stivale_load(char *config, char *cmdline) {
     // Reserve 32K at 0x70000 if possible
     if (!memmap_alloc_range(0x70000, 0x8000, MEMMAP_USABLE, true, false, false, false)) {
         if ((stivale_hdr.flags & (1 << 4)) == 0) {
-            panic("stivale: Could not allocate low memory area");
+            panic(false, "stivale: Could not allocate low memory area");
         }
     }
 
@@ -357,7 +357,7 @@ bool stivale_load(char *config, char *cmdline) {
     struct e820_entry_t *mmap = get_memmap(&mmap_entries);
 
     if (mmap_entries > 256) {
-        panic("stivale: Too many memory map entries!");
+        panic(false, "stivale: Too many memory map entries!");
     }
 
     memcpy(mmap_copy, mmap, mmap_entries * sizeof(struct e820_entry_t));
@@ -399,7 +399,7 @@ pagemap_t stivale_build_pagemap(bool level5pg, bool unmap_null, struct elf_range
                     phys = virt - FIXED_HIGHER_HALF_OFFSET_64;
                 }
             } else {
-                panic("stivale2: Protected memory ranges are only supported for higher half kernels");
+                panic(false, "stivale2: Protected memory ranges are only supported for higher half kernels");
             }
 
             uint64_t pf = VMM_FLAG_PRESENT |
diff --git a/stage23/protos/stivale2.c b/stage23/protos/stivale2.c
index 164144b6..7f8758af 100644
--- a/stage23/protos/stivale2.c
+++ b/stage23/protos/stivale2.c
@@ -82,10 +82,10 @@ bool stivale2_load(char *config, char *cmdline) {
 
     char *kernel_path = config_get_value(config, 0, "KERNEL_PATH");
     if (kernel_path == NULL)
-        panic("stivale2: KERNEL_PATH not specified");
+        panic(true, "stivale2: KERNEL_PATH not specified");
 
     if ((kernel_file = uri_open(kernel_path)) == NULL)
-        panic("stivale2: Failed to open kernel with path `%s`. Is the path correct?", kernel_path);
+        panic(true, "stivale2: Failed to open kernel with path `%s`. Is the path correct?", kernel_path);
 
     char *kaslr_s = config_get_value(config, 0, "KASLR");
     bool kaslr = true;
@@ -153,7 +153,7 @@ bool stivale2_load(char *config, char *cmdline) {
             // Check if 64 bit CPU
             uint32_t eax, ebx, ecx, edx;
             if (!cpuid(0x80000001, 0, &eax, &ebx, &ecx, &edx) || !(edx & (1 << 29))) {
-                panic("stivale2: This CPU does not support 64-bit mode.");
+                panic(true, "stivale2: This CPU does not support 64-bit mode.");
             }
             // Check if 5-level paging is available
             if (cpuid(0x00000007, 0, &eax, &ebx, &ecx, &edx) && (ecx & (1 << 16))) {
@@ -170,9 +170,9 @@ bool stivale2_load(char *config, char *cmdline) {
 
                 if ((stivale2_hdr.flags & (1 << 2))) {
                     if (bits == 32) {
-                        panic("stivale2: PMRs are not supported for 32-bit kernels");
+                        panic(true, "stivale2: PMRs are not supported for 32-bit kernels");
                     } else if (loaded_by_anchor) {
-                        panic("stivale2: PMRs are not supported for anchored kernels");
+                        panic(true, "stivale2: PMRs are not supported for anchored kernels");
                     }
                     want_pmrs = true;
                 }
@@ -186,7 +186,7 @@ bool stivale2_load(char *config, char *cmdline) {
                                want_pmrs ? &ranges : NULL,
                                want_pmrs ? &ranges_count : NULL,
                                want_fully_virtual, &physical_base, &virtual_base))
-                    panic("stivale2: ELF64 load failure");
+                    panic(true, "stivale2: ELF64 load failure");
 
                 if (want_fully_virtual) {
                     printv("stivale2: Physical base: %X\n", physical_base);
@@ -202,7 +202,7 @@ bool stivale2_load(char *config, char *cmdline) {
         case 32: {
             if (!loaded_by_anchor) {
                 if (elf32_load(kernel, (uint32_t *)&entry_point, NULL, 10))
-                    panic("stivale2: ELF32 load failure");
+                    panic(true, "stivale2: ELF32 load failure");
 
                 ret = elf32_load_section(kernel, &stivale2_hdr, ".stivale2hdr",
                                          sizeof(struct stivale2_header));
@@ -211,7 +211,7 @@ bool stivale2_load(char *config, char *cmdline) {
             break;
         }
         default:
-            panic("stivale2: Not 32 nor 64-bit kernel. What is this?");
+            panic(true, "stivale2: Not 32 nor 64-bit kernel. What is this?");
     }
 
     printv("stivale2: %u-bit kernel detected\n", bits);
@@ -219,17 +219,17 @@ bool stivale2_load(char *config, char *cmdline) {
 failed_to_load_header_section:
     switch (ret) {
         case 1:
-            panic("stivale2: File is not a valid ELF.");
+            panic(true, "stivale2: File is not a valid ELF.");
         case 2:
-            panic("stivale2: Section .stivale2hdr not found.");
+            panic(true, "stivale2: Section .stivale2hdr not found.");
         case 3:
-            panic("stivale2: Section .stivale2hdr exceeds the size of the struct.");
+            panic(true, "stivale2: Section .stivale2hdr exceeds the size of the struct.");
         case 4:
-            panic("stivale2: Section .stivale2hdr is smaller than size of the struct.");
+            panic(true, "stivale2: Section .stivale2hdr is smaller than size of the struct.");
     }
 
     if ((stivale2_hdr.flags & (1 << 1)) && bits == 32) {
-        panic("stivale2: Higher half addresses header flag not supported in 32-bit mode.");
+        panic(true, "stivale2: Higher half addresses header flag not supported in 32-bit mode.");
     }
 
     bool want_5lv = (get_tag(&stivale2_hdr, STIVALE2_HEADER_TAG_5LV_PAGING_ID) ? true : false) && level5pg;
@@ -240,7 +240,7 @@ failed_to_load_header_section:
         struct stivale2_header_tag_slide_hhdm *slt = get_tag(&stivale2_hdr, STIVALE2_HEADER_TAG_SLIDE_HHDM_ID);
         if (slt != NULL) {
             if (slt->alignment % 0x200000 != 0 || slt->alignment == 0) {
-                panic("stivale2: Requested HHDM slide alignment is not a multiple of 2MiB");
+                panic(true, "stivale2: Requested HHDM slide alignment is not a multiple of 2MiB");
             }
 
             direct_map_offset += (rand64() & ~(slt->alignment - 1)) & 0xffffffffff;
@@ -275,7 +275,7 @@ failed_to_load_header_section:
 
     // It also says the stack cannot be NULL for 32-bit kernels
     if (bits == 32 && stivale2_hdr.stack == 0) {
-        panic("stivale2: The stack cannot be 0 for 32-bit kernels");
+        panic(true, "stivale2: The stack cannot be 0 for 32-bit kernels");
     }
 
     strcpy(stivale2_struct->bootloader_brand, "Limine");
@@ -402,7 +402,7 @@ failed_to_load_header_section:
 
         struct file_handle *f;
         if ((f = uri_open(module_path)) == NULL)
-            panic("stivale2: Failed to open module with path `%s`. Is the path correct?", module_path);
+            panic(true, "stivale2: Failed to open module with path `%s`. Is the path correct?", module_path);
 
         m->begin = REPORTED_ADDR((uint64_t)(size_t)freadall(f, STIVALE2_MMAP_KERNEL_AND_MODULES));
         m->end   = m->begin + f->size;
@@ -504,7 +504,7 @@ failed_to_load_header_section:
 
 #if uefi == 1
     if (hdrtag == NULL && avtag == NULL) {
-        panic("stivale2: Cannot use text mode with UEFI.");
+        panic(true, "stivale2: Cannot use text mode with UEFI.");
     }
 #endif
 
@@ -529,7 +529,7 @@ failed_to_load_header_section:
             term_vbe(req_width, req_height);
 
             if (current_video_mode < 0) {
-                panic("stivale2: Failed to initialise terminal");
+                panic(true, "stivale2: Failed to initialise terminal");
             }
 
             fb = &fbinfo;
@@ -775,7 +775,7 @@ have_tm_tag:;
     // Reserve 32K at 0x70000, if possible
     if (!memmap_alloc_range(0x70000, 0x8000, MEMMAP_USABLE, true, false, false, false)) {
         if ((stivale2_hdr.flags & (1 << 4)) == 0) {
-            panic("stivale2: Could not allocate low memory area");
+            panic(false, "stivale2: Could not allocate low memory area");
         }
     }
 
@@ -783,7 +783,7 @@ have_tm_tag:;
     struct e820_entry_t *mmap = get_memmap(&mmap_entries);
 
     if (mmap_entries > 256) {
-        panic("stivale2: Too many memory map entries!");
+        panic(false, "stivale2: Too many memory map entries!");
     }
 
     tag->tag.identifier = STIVALE2_STRUCT_TAG_MEMMAP_ID;
diff --git a/stage23/pxe/pxe.s2.c b/stage23/pxe/pxe.s2.c
index 2516e225..0b229802 100644
--- a/stage23/pxe/pxe.s2.c
+++ b/stage23/pxe/pxe.s2.c
@@ -27,19 +27,19 @@ void pxe_init(void) {
 
     rm_int(0x1a, &r, &r);
     if ((r.eax & 0xffff) != 0x564e) {
-        panic("PXE installation check failed");
+        panic(false, "PXE installation check failed");
     }
 
     struct pxenv* pxenv = { 0 };
 
     pxenv = (struct pxenv*)((r.es << 4) + (r.ebx & 0xffff));
     if (memcmp(pxenv->signature, PXE_SIGNATURE, sizeof(pxenv->signature)) != 0) {
-        panic("PXENV structure signature corrupted");
+        panic(false, "PXENV structure signature corrupted");
     }
 
     if (pxenv->version < 0x201) {
         //we won't support pxe < 2.1, grub does this too and it seems to work fine
-        panic("pxe version too old");
+        panic(false, "pxe version too old");
     }
 
     struct bangpxe* bangpxe = (struct bangpxe*)((((pxenv->pxe_ptr & 0xffff0000) >> 16) << 4) + (pxenv->pxe_ptr & 0xffff));
@@ -47,7 +47,7 @@ void pxe_init(void) {
     if (memcmp(bangpxe->signature, PXE_BANGPXE_SIGNATURE,
             sizeof(bangpxe->signature))
         != 0) {
-        panic("!pxe signature corrupted");
+        panic(false, "!pxe signature corrupted");
     }
     set_pxe_fp(bangpxe->rm_entry);
     printv("pxe: Successfully initialized\n");
diff --git a/stage23/pxe/tftp.s2.c b/stage23/pxe/tftp.s2.c
index cfe27b3c..24f24584 100644
--- a/stage23/pxe/tftp.s2.c
+++ b/stage23/pxe/tftp.s2.c
@@ -75,7 +75,7 @@ bool tftp_open(struct file_handle *handle, uint32_t server_ip, uint16_t server_p
 
         ret = pxe_call(TFTP_READ, ((uint16_t)rm_seg(&read)), (uint16_t)rm_off(&read));
         if (ret) {
-            panic("tftp: Read failure");
+            panic(false, "tftp: Read failure");
         }
 
         memcpy(handle->fd + progress, buf, read.bsize);
@@ -91,7 +91,7 @@ bool tftp_open(struct file_handle *handle, uint32_t server_ip, uint16_t server_p
     uint16_t close = 0;
     ret = pxe_call(TFTP_CLOSE, ((uint16_t)rm_seg(&close)), (uint16_t)rm_off(&close));
     if (ret) {
-        panic("tftp: Close failure");
+        panic(false, "tftp: Close failure");
     }
 
     pmm_free(buf, mtu);
diff --git a/stage23/sys/e820.s2.c b/stage23/sys/e820.s2.c
index 03339457..b285db1c 100644
--- a/stage23/sys/e820.s2.c
+++ b/stage23/sys/e820.s2.c
@@ -38,7 +38,7 @@ void init_e820(void) {
         }
     }
 
-    panic("Too many E820 entries!");
+    panic(false, "Too many E820 entries!");
 }
 
 #endif
diff --git a/stage23/sys/idt.c b/stage23/sys/idt.c
index b68657ff..e27d7fd7 100644
--- a/stage23/sys/idt.c
+++ b/stage23/sys/idt.c
@@ -43,7 +43,7 @@ void flush_irqs(void) {
         case IRQ_PIC_APIC_FLUSH:
             break;
         default:
-            panic("Invalid IRQ flush type");
+            panic(false, "Invalid IRQ flush type");
     }
 
     struct idtr old_idt;
tab: 248 wrap: offon