feat: userspace faults

This commit is contained in:
Zoe
2026-09-07 13:47:25 -05:00
parent bf1a81cf82
commit a4b6e010ec
5 changed files with 41 additions and 46 deletions
+27 -37
View File
@@ -1,7 +1,10 @@
use core::arch::asm;
use super::idt::{self, InterruptFrame, InterruptStackFrame, stub_err, stub_no_err};
use crate::{hcf, println};
use crate::{
hcf, println,
task::tcb::{ExitReason, Fault},
};
stub_no_err!(stub_divide_error, 0);
stub_no_err!(stub_debug, 1);
@@ -22,45 +25,32 @@ stub_no_err!(stub_simd_floating_point, 19);
stub_no_err!(stub_user_test_exit, 0x80);
pub(super) fn handle(frame: &mut InterruptFrame) {
match frame.vector as u8 {
0 => fatal_exception("DIVIDE ERROR", &frame.stack_frame, None),
1 => fatal_exception("DEBUG EXCEPTION", &frame.stack_frame, None),
2 => fatal_exception("NON-MASKABLE INTERRUPT", &frame.stack_frame, None),
3 => report_exception("BREAKPOINT", &frame.stack_frame, None),
6 => fatal_exception("INVALID OPCODE", &frame.stack_frame, None),
7 => fatal_exception("DEVICE NOT AVAILABLE", &frame.stack_frame, None),
8 => fatal_exception("DOUBLE FAULT", &frame.stack_frame, Some(frame.error_code)),
10 => fatal_exception("INVALID TSS", &frame.stack_frame, Some(frame.error_code)),
11 => fatal_exception("SEGMENT NOT PRESENT", &frame.stack_frame, Some(frame.error_code)),
12 => fatal_exception("STACK-SEGMENT FAULT", &frame.stack_frame, Some(frame.error_code)),
13 => fatal_exception(
"GENERAL PROTECTION FAULT",
&frame.stack_frame,
Some(frame.error_code),
),
14 => {
report_exception("PAGE FAULT", &frame.stack_frame, Some(frame.error_code));
println!("Faulting address: {:#X}", read_cr2());
print_page_fault_error(frame.error_code);
hcf();
}
16 => fatal_exception("X87 FLOATING-POINT EXCEPTION", &frame.stack_frame, None),
17 => fatal_exception("ALIGNMENT CHECK", &frame.stack_frame, Some(frame.error_code)),
18 => fatal_exception("MACHINE CHECK", &frame.stack_frame, None),
19 => fatal_exception("SIMD FLOATING-POINT EXCEPTION", &frame.stack_frame, None),
0x80 => {
if frame.stack_frame.code_segment & 0b11 != 3 {
panic!("user_test_exit_handler called from kernel");
}
let is_user = frame.stack_frame.code_segment & 0b11 == 3;
println!("User test exit");
hcf();
}
_ => {
println!("Unhandled exception vector: {:#X}", frame.vector);
hcf();
if !is_user {
match frame.vector as u8 {
8 => fatal_exception("DOUBLE FAULT", &frame.stack_frame, Some(frame.error_code)),
14 => {
report_exception("PAGE FAULT", &frame.stack_frame, Some(frame.error_code));
println!("Faulting address: {:#X}", read_cr2());
print_page_fault_error(frame.error_code);
hcf();
}
_ => fatal_exception("KERNEL FAULT", &frame.stack_frame, Some(frame.error_code)),
}
}
let fault = match frame.vector as u8 {
// Page fault, GPF, Stack/Segment faults -> SegmentationFault
11 | 12 | 13 | 14 => Fault::SegmentationFault,
// Invalid Opcode -> IllegalInstruction
6 => Fault::IllegalInstruction,
// Divide by zero, Alignment check, SIMD/x87 -> Abort
0 | 16 | 17 | 19 => Fault::Abort,
_ => Fault::Abort,
};
crate::task::scheduler::exit_current(ExitReason::Fault(fault));
}
pub(super) fn install(idt: &mut idt::Idt) {
+8 -3
View File
@@ -2,6 +2,8 @@ mod table;
use table::*;
use crate::task::tcb::{ExitReason, Fault};
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
#[repr(u64)]
pub enum Status {
@@ -31,7 +33,7 @@ pub enum SyscallNumber {
}
impl TryFrom<u64> for SyscallNumber {
type Error = Status;
type Error = ();
fn try_from(val: u64) -> Result<Self, Self::Error> {
match val {
1 => Ok(Self::Yield),
@@ -45,14 +47,17 @@ impl TryFrom<u64> for SyscallNumber {
9 => Ok(Self::Map),
10 => Ok(Self::Unmap),
11 => Ok(Self::TaskCreate),
_ => Err(Status::InvalidArgument),
_ => Err(()),
}
}
}
pub fn handle(num: u64, arg0: u64, arg1: u64, arg2: u64, arg3: u64, arg4: u64, _arg5: u64) -> u64 {
let result = (|| -> Result<(), Status> {
let syscall = SyscallNumber::try_from(num)?;
let syscall = SyscallNumber::try_from(num).unwrap_or_else(|_| {
crate::task::scheduler::exit_current(ExitReason::Fault(Fault::BadSystemCall))
});
match syscall {
SyscallNumber::Yield => sys_yield(),
SyscallNumber::Exit => sys_exit(arg0 as usize),
+2 -2
View File
@@ -6,7 +6,7 @@ use crate::{
println,
task::{
scheduler::TaskId,
tcb::{BlockReason, Handle, KernelObject, MAX_MSG_SIZE, Message, Rights},
tcb::{BlockReason, ExitReason, Handle, KernelObject, MAX_MSG_SIZE, Message, Rights},
},
};
@@ -18,7 +18,7 @@ pub fn sys_yield() -> Result<(), Status> {
}
pub fn sys_exit(exit_code: usize) -> ! {
crate::task::scheduler::exit_current(exit_code);
crate::task::scheduler::exit_current(ExitReason::Exited(exit_code));
}
pub fn sys_write(fd: usize, buf_ptr: usize, len: usize, out_ptr: usize) -> Result<(), Status> {
+2 -2
View File
@@ -344,7 +344,7 @@ pub fn yield_current() {
crate::arch::restore_interrupts(interrupt_state);
}
pub fn exit_current(exit_code: usize) -> ! {
pub fn exit_current(reason: ExitReason) -> ! {
crate::arch::disable_interrupts();
let switch = {
@@ -356,7 +356,7 @@ pub fn exit_current(exit_code: usize) -> ! {
};
let current = scheduler.tasks[current_id.0].as_mut().unwrap();
current.state = ThreadState::Dead(ExitReason::Exited(exit_code));
current.state = ThreadState::Dead(reason);
scheduler.tasks[next_id.0].as_mut().unwrap().state = ThreadState::Running;
scheduler.current = Some(next_id);
+2 -2
View File
@@ -40,9 +40,9 @@ pub extern "C" fn _start() -> ! {
map_stack(client_as, STACK_TOP, STACK_PAGES);
let _ = sys_task_create(client_as, client_entry, STACK_TOP).unwrap();
let ptr = 0xDEAD_BEEF as *mut u32;
// call a bogus system call
unsafe {
core::ptr::write_volatile(&mut *ptr, 0xDEAD_BEEF);
core::arch::asm!("syscall", in("rax") 134);
}
sys_exit(0);