From e9898e829b8df7c0b16faec1ce490369c53fd78e Mon Sep 17 00:00:00 2001 From: Benji Dial Date: Sat, 13 Jan 2024 19:14:58 -0500 Subject: minimal cpu exception handling --- applications/init/main.cpp | 4 +- kernel/entry.cpp | 23 ---- kernel/interrupts.asm | 254 +++++++++++++++++++++++++++++++++++++++++++++ kernel/interrupts.cpp | 119 +++++++++++++++++++++ kernel/syscall.asm | 36 ------- makefile | 3 +- 6 files changed, 378 insertions(+), 61 deletions(-) create mode 100644 kernel/interrupts.asm create mode 100644 kernel/interrupts.cpp diff --git a/applications/init/main.cpp b/applications/init/main.cpp index 7aa2a38..a3f75e4 100644 --- a/applications/init/main.cpp +++ b/applications/init/main.cpp @@ -9,6 +9,7 @@ uint32_t fb_height; uint32_t fb_pitch; int main(int, char **) { + mercury::syscall::get_framebuffer(fb, fb_width, fb_height, fb_pitch); for (uint32_t y = 0; y < fb_height; ++y) for (uint32_t x = 0; x < fb_width; ++x) { @@ -20,5 +21,6 @@ int main(int, char **) { fb[y * fb_pitch + x] = mercury::syscall::encode_color(c); } mercury::syscall::draw_framebuffer(); - return 0; + + return 1 / 0; } diff --git a/kernel/entry.cpp b/kernel/entry.cpp index f7ba71d..cce8066 100644 --- a/kernel/entry.cpp +++ b/kernel/entry.cpp @@ -184,15 +184,6 @@ extern "C" [[noreturn]] void entry() { } -static void print_mem() { - uint64_t used_vram_mib = (paging::get_used_vram_page_count() + 128) / 256; - uint64_t free_pram_mib = (paging::get_free_pram_page_count() + 128) / 256; - terminal::put_int_decimal(used_vram_mib); - terminal::put_string_sz(" MiB kernel memory mapped.\n"); - terminal::put_int_decimal(free_pram_mib); - terminal::put_string_sz(" MiB physical memory free.\n"); -} - [[noreturn]] static void print_and_halt(const char *msg) { terminal::put_string_sz(msg); while (1) @@ -230,25 +221,11 @@ extern "C" [[noreturn]] void start_user_mode( if (!init_file) print_and_halt("/bin/init.elf does not exist."); - terminal::put_string_sz("/bin/init.elf is "); - terminal::put_int_decimal(init_file->dir_entry.length); - terminal::put_string_sz(" bytes long.\n"); - application::app_instance *init; if (application::create_app(*init_file, init) != application::create_app_result::success) print_and_halt("failed to parse /bin/init.elf."); - terminal::put_string_sz("/bin/init.elf loaded:\n instruction pointer 0x"); - terminal::put_int_hex(init->saved_regs.rip, 8); - terminal::put_string_sz("\n stack pointer 0x"); - terminal::put_int_hex(init->saved_regs.rsp, 8); - terminal::put_string_sz("\n "); - terminal::put_int_decimal(init->count_mapped_vram_pages() * 2); - terminal::put_string_sz(" MiB userspace memory used\n"); - - print_mem(); - terminal::put_string_sz("switching to /bin/init.elf.\n"); application::running_app = init; start_user_mode(init->saved_regs.rip, init->saved_regs.rsp, init->p4_paddr); diff --git a/kernel/interrupts.asm b/kernel/interrupts.asm new file mode 100644 index 0000000..c375ee4 --- /dev/null +++ b/kernel/interrupts.asm @@ -0,0 +1,254 @@ +bits 64 + +global load_gdt_and_idt + +section .rodata + +;0x28 picked to align with limine choice + +;0x18 - tss +;0x28 - kernel code +;0x30 - kernel data +;0x38 - user data +;0x40 - user code + +tss: + times 9 dd 0 + dq 0xffffffffffeff000 + times 15 dd 0 + +gdtr: + dw 0x47 + dq gdt + +idtr: + dw 4095 + dq idt + +section .bss + +idt: + resq 512 + +global exception_info +exception_info: +.rax: + resq 1 +.rbx: + resq 1 +.rcx: + resq 1 +.rdx: + resq 1 +.rdi: + resq 1 +.rsi: + resq 1 +.rbp: + resq 1 +.rsp: + resq 1 +.r8: + resq 1 +.r9: + resq 1 +.r10: + resq 1 +.r11: + resq 1 +.r12: + resq 1 +.r13: + resq 1 +.r14: + resq 1 +.r15: + resq 1 +.cr3: + resq 1 +.rip: + resq 1 +.rflags: + resq 1 +.error: + resq 1 +.has_error: + resb 1 +.exception_number: + resb 1 + +section .rodata + +has_error_code: + db 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, 0 + +exception_isrs: + dq exception_00, exception_01, exception_02, exception_03 + dq exception_04, exception_05, exception_06, exception_07 + dq exception_08, exception_09, exception_0a, exception_0b + dq exception_0c, exception_0d, exception_0e, exception_0f + +section .text + +extern print_exception + +exception_00: + mov byte [exception_info.exception_number], 0x00 + jmp exception_common +exception_01: + mov byte [exception_info.exception_number], 0x01 + jmp exception_common +exception_02: + mov byte [exception_info.exception_number], 0x02 + jmp exception_common +exception_03: + mov byte [exception_info.exception_number], 0x03 + jmp exception_common +exception_04: + mov byte [exception_info.exception_number], 0x04 + jmp exception_common +exception_05: + mov byte [exception_info.exception_number], 0x05 + jmp exception_common +exception_06: + mov byte [exception_info.exception_number], 0x06 + jmp exception_common +exception_07: + mov byte [exception_info.exception_number], 0x07 + jmp exception_common +exception_08: + mov byte [exception_info.exception_number], 0x08 + jmp exception_common +exception_09: + mov byte [exception_info.exception_number], 0x09 + jmp exception_common +exception_0a: + mov byte [exception_info.exception_number], 0x0a + jmp exception_common +exception_0b: + mov byte [exception_info.exception_number], 0x0b + jmp exception_common +exception_0c: + mov byte [exception_info.exception_number], 0x0c + jmp exception_common +exception_0d: + mov byte [exception_info.exception_number], 0x0d + jmp exception_common +exception_0e: + mov byte [exception_info.exception_number], 0x0e + jmp exception_common +exception_0f: + mov byte [exception_info.exception_number], 0x0f + jmp exception_common + +exception_common: + mov qword [exception_info.rax], rax + + movzx rax, byte [exception_info.exception_number] + mov al, byte [has_error_code + rax] + test al, al + jz .no_error_code + + mov byte [exception_info.has_error], 1 + pop rax + mov qword [exception_info.error], rax + jmp .post_error_code + +.no_error_code: + mov byte [exception_info.has_error], 0 + +.post_error_code: + mov qword [exception_info.rbx], rbx + mov qword [exception_info.rcx], rcx + mov qword [exception_info.rdx], rdx + mov qword [exception_info.rdi], rdi + mov qword [exception_info.rsi], rsi + mov qword [exception_info.rbp], rbp + mov qword [exception_info.r8], r8 + mov qword [exception_info.r9], r9 + mov qword [exception_info.r10], r10 + mov qword [exception_info.r11], r11 + mov qword [exception_info.r12], r12 + mov qword [exception_info.r13], r13 + mov qword [exception_info.r14], r14 + mov qword [exception_info.r15], r15 + + pop rax + mov qword [exception_info.rip], rax + pop rax + pop rax + mov qword [exception_info.rflags], rax + pop rax + mov qword [exception_info.rsp], rax + + mov rax, cr3 + mov qword [exception_info.cr3], rax + + jmp print_exception + +set_isr: +;rdi - index +;sil - 1 if this is a trap, 0 if it is an interrupt +;rdx - isr pointer + + shl rdi, 4 + add rdi, idt + + mov word [rdi], dx + shr rdx, 16 + mov word [rdi + 6], dx + shr rdx, 16 + mov dword [rdi + 8], edx + + or sil, 0xef + mov byte [rdi + 5], sil + mov word [rdi + 2], 0x28 + mov byte [rdi + 4], 1 + + ret + +section .data + +gdt: + dq 0 + dq 0 + dq 0 +.tss: + dq 0x0000e90000000067 + dq 0;tss is 2 qwords wide + dq 0x00209b0000000000 + dq 0x00009b0000000000 + dq 0x0000fb0000000000 + dq 0x0020fb0000000000 + +section .text + +load_gdt_and_idt: + + mov rcx, 8 + +.loop: + + mov rdi, rcx + dec rdi + mov sil, 1 + mov rdx, qword [exception_isrs + rdi * 8] + call set_isr + + loop .loop + + mov rax, tss + + mov word [gdt.tss + 2], ax + shr rax, 16 + mov byte [gdt.tss + 4], al + mov byte [gdt.tss + 7], ah + shr rax, 16 + mov dword [gdt.tss + 8], eax + + lgdt [gdtr] + lidt [idtr] + mov ax, 0x18 + ltr ax + + ret diff --git a/kernel/interrupts.cpp b/kernel/interrupts.cpp new file mode 100644 index 0000000..65daf91 --- /dev/null +++ b/kernel/interrupts.cpp @@ -0,0 +1,119 @@ +#include + +using namespace mercury::kernel; + +struct [[gnu::packed]] exception_info_t { + + uint64_t rax; + uint64_t rbx; + uint64_t rcx; + uint64_t rdx; + uint64_t rdi; + uint64_t rsi; + uint64_t rbp; + uint64_t rsp; + uint64_t r8; + uint64_t r9; + uint64_t r10; + uint64_t r11; + uint64_t r12; + uint64_t r13; + uint64_t r14; + uint64_t r15; + + uint64_t cr3; + uint64_t rip; + uint64_t rflags; + + uint64_t error; + uint8_t has_error;//0 or 1 + uint8_t exception_number; + +}; + +extern exception_info_t exception_info; + +const char *exception_types[] = { + "division error", + "", + "non-maskable interrupt", + "", + "", + "", + "invalid opcode", + "", + "double fault (uh oh)", + "", + "", + "", + "stack fault", + "general protection fault", + "page fault", + "" +}; + +const char *flag_names[] = { + " cf", + "", + " pf", + "", + " af", + "", + " zf", + " sf", + " tf", + " if", + " df", + " of", + "", + "", + " nt", + " md" +}; + +void print_line(const char *r1, const char *r2, uint64_t r1v, uint64_t r2v) { + terminal::put_string_sz("\n "); + terminal::put_string_sz(r1); + terminal::put_string_sz(": 0x"); + terminal::put_int_hex(r1v, 16); + terminal::put_string_sz(" "); + terminal::put_string_sz(r2); + terminal::put_string_sz(": 0x"); + terminal::put_int_hex(r2v, 16); +} + +extern "C" [[noreturn]] void print_exception() { + + terminal::put_string_sz("exception handler:\n type: "); + terminal::put_string_sz(exception_types[exception_info.exception_number]); + terminal::put_string_sz(" (0x"); + terminal::put_int_hex(exception_info.exception_number, 2); + terminal::put_char(')'); + + if (exception_info.has_error == 1) { + terminal::put_string_sz("\n error code: 0x"); + terminal::put_int_hex(exception_info.error, 16); + } + + terminal::put_string_sz("\n flags:"); + if (exception_info.rflags == 0) + terminal::put_string_sz(" [none]"); + else + for (int i = 0; i < 16; ++i) + if (((exception_info.rflags >> i) & 1) == 1) + terminal::put_string_sz(flag_names[i]); + + print_line("rip", "cr3", exception_info.rip, exception_info.cr3); + print_line("rax", "rbx", exception_info.rax, exception_info.rbx); + print_line("rcx", "rdx", exception_info.rcx, exception_info.rdx); + print_line("rdi", "rsi", exception_info.rdi, exception_info.rsi); + print_line("rbp", "rsp", exception_info.rbp, exception_info.rsp); + print_line("r8 ", "r9 ", exception_info.r8 , exception_info.r9 ); + print_line("r10", "r11", exception_info.r10, exception_info.r11); + print_line("r12", "r13", exception_info.r12, exception_info.r13); + print_line("r14", "r15", exception_info.r14, exception_info.r15); + + while (1) + asm ("hlt"); + +} diff --git a/kernel/syscall.asm b/kernel/syscall.asm index 56be8a4..e4e0d77 100644 --- a/kernel/syscall.asm +++ b/kernel/syscall.asm @@ -1,45 +1,9 @@ bits 64 -global load_gdt_and_idt global start_user_mode -section .rodata - -;0x28 picked to align with limine choice -;0x28 - kernel code -;0x30 - kernel data -;0x38 - user data -;0x40 - user code - -gdtr: - dw 0x47 - dq gdt - -gdt: - dq 0 - dq 0 - dq 0 - dq 0 - dq 0 - dq 0x00209b0000000000 - dq 0x00009b0000000000 - dq 0x0000fb0000000000 - dq 0x0020fb0000000000 - -idtr: - dw 4095 - dq idt - -idt: - times 256 - ($ - idt) / 16 dq 0 - section .text -load_gdt_and_idt: - lgdt [gdtr] - lidt [idtr] - ret - extern syscall_encode_color encode_color_syscall: diff --git a/makefile b/makefile index 7b14369..2d103b3 100644 --- a/makefile +++ b/makefile @@ -41,7 +41,8 @@ obj/kernel/%.asm.o: kernel/%.asm KERNEL_OBJECTS = allocator.cpp application.cpp entry.cpp framebuffer.cpp \ paging.asm paging.cpp storage.cpp storage/bd/memory.cpp terminal.cpp \ - storage/fs/tarfs.cpp utility.cpp vfile.cpp syscall.asm syscall.cpp + storage/fs/tarfs.cpp utility.cpp vfile.cpp syscall.asm syscall.cpp \ + interrupts.asm interrupts.cpp obj/kernel.elf: ${KERNEL_OBJECTS:%=obj/kernel/%.o} ld ${KLD_ARGS} $^ -o $@ -- cgit v1.2.3