minimal cpu exception handling

This commit is contained in:
Benji Dial 2024-01-13 19:14:58 -05:00
parent 4130562b15
commit e9898e829b
6 changed files with 378 additions and 61 deletions

View file

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

View file

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

254
kernel/interrupts.asm Normal file
View file

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

119
kernel/interrupts.cpp Normal file
View file

@ -0,0 +1,119 @@
#include <mercury/kernel/terminal.hpp>
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");
}

View file

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

View file

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