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
