misc: Handle CPU exceptions nicely

This commit is contained in:
mintsuki 2021-03-13 03:21:01 +01:00
parent 9e60b1da10
commit 94887a4533
11 changed files with 198 additions and 5 deletions

View File

@ -74,8 +74,7 @@ ifeq ($(TARGET), bios)
-static \
-fno-pie \
-lgcc \
-static-libgcc \
-Wl,--gc-sections
-static-libgcc
endif
.PHONY: all clean builddir

View File

@ -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;

View File

@ -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");

View File

@ -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

View File

@ -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

View File

@ -28,6 +28,7 @@ SECTIONS
*(.stage3_build_id*)
full_map = .;
limine_sys_size = .;
getchar_internal = .;
}
.bss : {

View File

@ -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

View File

@ -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,

27
stage23/sys/idt.h Normal file
View File

@ -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

36
stage23/sys/idt.s2.c Normal file
View File

@ -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

View File

@ -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