:: commit 94887a4533120adbe072b0ac91c1c2db2d7fdaf5

mintsuki <mintsuki@protonmail.com> — 2021-03-13 02:21

parents: 9e60b1da10

misc: Handle CPU exceptions nicely

diff --git a/stage23/Makefile b/stage23/Makefile
index 08e0a62b..304d7a30 100644
--- a/stage23/Makefile
+++ b/stage23/Makefile
@@ -74,8 +74,7 @@ ifeq ($(TARGET), bios)
 		-static \
 		-fno-pie \
 		-lgcc \
-		-static-libgcc \
-		-Wl,--gc-sections
+		-static-libgcc
 endif
 
 .PHONY: all clean builddir
diff --git a/stage23/entry.s2.c b/stage23/entry.s2.c
index c6b08fe9..d8f91aae 100644
--- a/stage23/entry.s2.c
+++ b/stage23/entry.s2.c
@@ -20,6 +20,7 @@
 #include <pxe/pxe.h>
 #include <pxe/tftp.h>
 #include <drivers/disk.h>
+#include <sys/idt.h>
 
 extern uint64_t stage3_build_id;
 
@@ -74,6 +75,8 @@ void entry(uint8_t boot_drive, int boot_from) {
     if (!a20_enable())
         panic("Could not enable A20 line");
 
+    init_idt();
+
     init_e820();
     init_memmap();
 
@@ -90,7 +93,7 @@ void entry(uint8_t boot_drive, int boot_from) {
     );
 
     if (!stage3_loaded)
-        panic("Failed to load stage 3.\n");
+        panic("Failed to load stage 3.");
 
     __attribute__((noreturn))
     void (*stage3)(int boot_from) = (void *)stage3_addr;
diff --git a/stage23/lib/blib.c b/stage23/lib/blib.c
index 3252c502..bf9d4f41 100644
--- a/stage23/lib/blib.c
+++ b/stage23/lib/blib.c
@@ -83,7 +83,7 @@ bool efi_exit_boot_services(void) {
     status = uefi_call_wrapper(gBS->ExitBootServices, 2, efi_image_handle, mmap_key);
 
     if (status)
-        panic("efi: Failed to exit boot services\n");
+        panic("efi: Failed to exit boot services");
 
     asm volatile ("cli" ::: "memory");
 
diff --git a/stage23/lib/real.asm b/stage23/lib/real.asm
index 911c3101..4c43af98 100644
--- a/stage23/lib/real.asm
+++ b/stage23/lib/real.asm
@@ -2,6 +2,9 @@ section .realmode
 
 global rm_hcf
 rm_hcf:
+    ; Load BIOS IVT
+    lidt [.rm_idt]
+
     ; Jump to real mode
     jmp 0x08:.bits16
   .bits16:
@@ -30,6 +33,9 @@ rm_hcf:
     jmp .hang
     bits 32
 
+  .rm_idt:   dw 0x3ff
+             dd 0
+
 global rm_int
 rm_int:
     ; Self-modifying code: int $int_no
@@ -47,6 +53,12 @@ rm_int:
     ; Save GDT in case BIOS overwrites it
     sgdt [.gdt]
 
+    ; Save IDT
+    sidt [.idt]
+
+    ; Load BIOS IVT
+    lidt [.rm_idt]
+
     ; Save non-scratch GPRs
     push ebx
     push esi
@@ -116,7 +128,10 @@ rm_int:
     mov esp, dword [ss:.esp]
 
     ; Restore GDT
-    lgdt [ss:.gdt]
+    o32 lgdt [ss:.gdt]
+
+    ; Restore IDT
+    o32 lidt [ss:.idt]
 
     ; Jump back to pmode
     mov eax, cr0
@@ -146,3 +161,6 @@ align 16
   .out_regs: dd 0
   .in_regs:  dd 0
   .gdt:      dq 0
+  .idt:      dq 0
+  .rm_idt:   dw 0x3ff
+             dd 0
diff --git a/stage23/lib/sleep.asm b/stage23/lib/sleep.asm
index 470a429b..0cc2ab5b 100644
--- a/stage23/lib/sleep.asm
+++ b/stage23/lib/sleep.asm
@@ -26,6 +26,15 @@ _pit_sleep_and_quit_on_keypress:
 
     mov dword [int_08_ticks_counter], 0
 
+    ; Save GDT in case BIOS overwrites it
+    sgdt [.gdt]
+
+    ; Save IDT
+    sidt [.idt]
+
+    ; Load BIOS IVT
+    lidt [.rm_idt]
+
     ; Save non-scratch GPRs
     push ebx
     push esi
@@ -81,6 +90,12 @@ _pit_sleep_and_quit_on_keypress:
   .done:
     cli
 
+    ; Restore GDT
+    o32 lgdt [ss:.gdt]
+
+    ; Restore IDT
+    o32 lidt [ss:.idt]
+
     ; Jump back to pmode
     mov ebx, cr0
     or bl, 1
@@ -115,3 +130,8 @@ _pit_sleep_and_quit_on_keypress:
     pop edx
 
     ret
+
+  .gdt:      dq 0
+  .idt:      dq 0
+  .rm_idt:   dw 0x3ff
+             dd 0
diff --git a/stage23/linker_stage2only.ld b/stage23/linker_stage2only.ld
index f2739603..aa27c5d5 100644
--- a/stage23/linker_stage2only.ld
+++ b/stage23/linker_stage2only.ld
@@ -28,6 +28,7 @@ SECTIONS
         *(.stage3_build_id*)
         full_map = .;
         limine_sys_size = .;
+        getchar_internal = .;
     }
 
     .bss : {
diff --git a/stage23/sys/exceptions.s2.c b/stage23/sys/exceptions.s2.c
new file mode 100644
index 00000000..ea51d3cf
--- /dev/null
+++ b/stage23/sys/exceptions.s2.c
@@ -0,0 +1,47 @@
+#include <stdint.h>
+#include <lib/blib.h>
+#include <lib/trace.h>
+#include <lib/print.h>
+
+#if defined (bios)
+
+static const char *exception_names[] = {
+    "Division by 0",
+    "Debug",
+    "NMI",
+    "Breakpoint",
+    "Overflow",
+    "Bound range exceeded",
+    "Invalid opcode",
+    "Device not available",
+    "Double fault",
+    "???",
+    "Invalid TSS",
+    "Segment not present",
+    "Stack-segment fault",
+    "General protection fault",
+    "Page fault",
+    "???",
+    "x87 exception",
+    "Alignment check",
+    "Machine check",
+    "SIMD exception",
+    "Virtualisation",
+    "???",
+    "???",
+    "???",
+    "???",
+    "???",
+    "???",
+    "???",
+    "???",
+    "???",
+    "Security"
+};
+
+void except(uint32_t exception, uint32_t error_code, uint32_t ebp, uint32_t eip) {
+    (void)ebp;
+    panic("%s at %x. Error code: %x", exception_names[exception], eip, error_code);
+}
+
+#endif
diff --git a/stage23/sys/gdt.s2.c b/stage23/sys/gdt.s2.c
index f918573f..bf2f2ebd 100644
--- a/stage23/sys/gdt.s2.c
+++ b/stage23/sys/gdt.s2.c
@@ -59,6 +59,9 @@ static struct gdt_desc gdt_descs[] = {
     }
 };
 
+#if defined (bios)
+__attribute__((section(".realmode")))
+#endif
 struct gdtr gdt = {
     sizeof(gdt_descs) - 1,
     (uintptr_t)gdt_descs,
diff --git a/stage23/sys/idt.h b/stage23/sys/idt.h
new file mode 100644
index 00000000..856a4a7c
--- /dev/null
+++ b/stage23/sys/idt.h
@@ -0,0 +1,27 @@
+#ifndef __SYS__IDT_H__
+#define __SYS__IDT_H__
+
+#include <stdint.h>
+
+#if defined (bios)
+
+struct idtr {
+    uint16_t limit;
+    uint32_t ptr;
+} __attribute__((packed));
+
+struct idt_entry {
+    uint16_t offset_lo;
+    uint16_t selector;
+    uint8_t  unused;
+    uint8_t  type_attr;
+    uint16_t offset_hi;
+} __attribute__((packed));
+
+extern struct idtr idt;
+
+void init_idt(void);
+
+#endif
+
+#endif
diff --git a/stage23/sys/idt.s2.c b/stage23/sys/idt.s2.c
new file mode 100644
index 00000000..cc514042
--- /dev/null
+++ b/stage23/sys/idt.s2.c
@@ -0,0 +1,36 @@
+#include <stddef.h>
+#include <stdint.h>
+#include <sys/idt.h>
+#include <lib/blib.h>
+
+#if defined (bios)
+
+__attribute__((section(".realmode")))
+static struct idt_entry idt_entries[32];
+
+__attribute__((section(".realmode")))
+struct idtr idt = {
+    sizeof(idt_entries) - 1,
+    (uintptr_t)idt_entries
+};
+
+static void register_interrupt_handler(size_t vec, void *handler, uint8_t type) {
+    uint32_t p = (uint32_t)handler;
+
+    idt_entries[vec].offset_lo = (uint16_t)p;
+    idt_entries[vec].selector = 0x18;
+    idt_entries[vec].unused = 0;
+    idt_entries[vec].type_attr = type;
+    idt_entries[vec].offset_hi = (uint16_t)(p >> 16);
+}
+
+extern void *exceptions[];
+
+void init_idt(void) {
+    for (size_t i = 0; i < SIZEOF_ARRAY(idt_entries); i++)
+        register_interrupt_handler(i, exceptions[i], 0x8e);
+
+    asm volatile ("lidt %0" :: "m"(idt) : "memory");
+}
+
+#endif
diff --git a/stage23/sys/int_thunks.s2.asm b/stage23/sys/int_thunks.s2.asm
new file mode 100644
index 00000000..7c82a000
--- /dev/null
+++ b/stage23/sys/int_thunks.s2.asm
@@ -0,0 +1,39 @@
+section .text
+
+extern except
+
+%macro raise_exception 1
+align 16
+raise_exception_%1:
+    cld
+%if %1 == 8 || %1 == 10 || %1 == 11 || %1 == 12 || %1 == 13 || %1 == 14 || %1 == 17 || %1 == 30
+    pop eax
+%else
+    xor eax, eax
+%endif
+    push ebp
+    mov ebp, esp
+    push eax
+    push %1
+    call except
+%endmacro
+
+%assign i 0
+%rep 32
+raise_exception i
+%assign i i+1
+%endrep
+
+section .rodata
+
+%macro raise_exception_getaddr 1
+dd raise_exception_%1
+%endmacro
+
+global exceptions
+exceptions:
+%assign i 0
+%rep 32
+raise_exception_getaddr i
+%assign i i+1
+%endrep
tab: 248 wrap: offon