diff --git a/src/arch/x86_64/interrupt/exception.rs b/src/arch/x86_64/interrupt/exception.rs index 575e256bba..3da86b8a8f 100644 --- a/src/arch/x86_64/interrupt/exception.rs +++ b/src/arch/x86_64/interrupt/exception.rs @@ -1,15 +1,19 @@ +use syscall::Exception; use x86::irq::PageFaultError; use crate::{ - interrupt_error, interrupt_stack, ksignal, memory::GenericPfFlags, paging::VirtualAddress, - panic::stack_trace, ptrace, syscall::flag::*, + arch::x86_shared::interrupt, context::signal::excp_handler, interrupt_error, interrupt_stack, + memory::GenericPfFlags, paging::VirtualAddress, panic::stack_trace, ptrace, syscall::flag::*, }; interrupt_stack!(divide_by_zero, |stack| { println!("Divide by zero"); stack.dump(); stack_trace(); - ksignal(SIGFPE); + excp_handler(Exception { + kind: 0, + ..Default::default() + }); }); interrupt_stack!(debug, @paranoid, |stack| { @@ -31,7 +35,10 @@ interrupt_stack!(debug, @paranoid, |stack| { if !handled { println!("Debug trap"); stack.dump(); - ksignal(SIGTRAP); + excp_handler(Exception { + kind: 1, + ..Default::default() + }); } }); @@ -64,7 +71,10 @@ interrupt_stack!(breakpoint, |stack| { if ptrace::breakpoint_callback(PTRACE_STOP_BREAKPOINT, None).is_none() { println!("Breakpoint trap"); stack.dump(); - ksignal(SIGTRAP); + excp_handler(Exception { + kind: 3, + ..Default::default() + }); } }); @@ -72,63 +82,94 @@ interrupt_stack!(overflow, |stack| { println!("Overflow trap"); stack.dump(); stack_trace(); - ksignal(SIGFPE); + excp_handler(Exception { + kind: 4, + ..Default::default() + }); }); interrupt_stack!(bound_range, |stack| { println!("Bound range exceeded fault"); stack.dump(); stack_trace(); - ksignal(SIGSEGV); + excp_handler(Exception { + kind: 5, + ..Default::default() + }); }); interrupt_stack!(invalid_opcode, |stack| { println!("Invalid opcode fault"); stack.dump(); stack_trace(); - ksignal(SIGILL); + excp_handler(Exception { + kind: 6, + ..Default::default() + }); }); interrupt_stack!(device_not_available, |stack| { println!("Device not available fault"); stack.dump(); stack_trace(); - ksignal(SIGILL); + excp_handler(Exception { + kind: 7, + ..Default::default() + }); }); interrupt_error!(double_fault, |stack, _code| { println!("Double fault"); stack.dump(); stack_trace(); - ksignal(SIGSEGV); + loop { + interrupt::disable(); + interrupt::halt(); + } }); -interrupt_error!(invalid_tss, |stack, _code| { +interrupt_error!(invalid_tss, |stack, code| { println!("Invalid TSS fault"); stack.dump(); stack_trace(); - ksignal(SIGSEGV); + excp_handler(Exception { + kind: 10, + code, + ..Default::default() + }); }); -interrupt_error!(segment_not_present, |stack, _code| { +interrupt_error!(segment_not_present, |stack, code| { println!("Segment not present fault"); stack.dump(); stack_trace(); - ksignal(SIGSEGV); + excp_handler(Exception { + kind: 11, + code, + ..Default::default() + }); }); -interrupt_error!(stack_segment, |stack, _code| { +interrupt_error!(stack_segment, |stack, code| { println!("Stack segment fault"); stack.dump(); stack_trace(); - ksignal(SIGSEGV); + excp_handler(Exception { + kind: 12, + code, + ..Default::default() + }); }); interrupt_error!(protection, |stack, code| { println!("Protection fault code={:#0x}", code); stack.dump(); stack_trace(); - ksignal(SIGSEGV); + excp_handler(Exception { + kind: 13, + code, + ..Default::default() + }); }); interrupt_error!(page, |stack, code| { @@ -161,7 +202,11 @@ interrupt_error!(page, |stack, code| { println!("Page fault: {:>016X} {:#?}", cr2.data(), arch_flags); stack.dump(); stack_trace(); - ksignal(SIGSEGV); + excp_handler(Exception { + kind: 14, + code, + address: cr2.data(), + }); } }); @@ -169,21 +214,31 @@ interrupt_stack!(fpu_fault, |stack| { println!("FPU floating point fault"); stack.dump(); stack_trace(); - ksignal(SIGFPE); + excp_handler(Exception { + kind: 16, + ..Default::default() + }); }); -interrupt_error!(alignment_check, |stack, _code| { +interrupt_error!(alignment_check, |stack, code| { println!("Alignment check fault"); stack.dump(); stack_trace(); - ksignal(SIGBUS); + excp_handler(Exception { + kind: 17, + code, + ..Default::default() + }); }); interrupt_stack!(machine_check, @paranoid, |stack| { println!("Machine check fault"); stack.dump(); stack_trace(); - ksignal(SIGBUS); + loop { + interrupt::disable(); + interrupt::halt(); + } }); interrupt_stack!(simd, |stack| { @@ -193,19 +248,28 @@ interrupt_stack!(simd, |stack| { core::arch::asm!("stmxcsr [{}]", in(reg) core::ptr::addr_of_mut!(mxcsr)); println!("MXCSR {:#0x}", mxcsr); stack_trace(); - ksignal(SIGFPE); + excp_handler(Exception { + kind: 19, + ..Default::default() + }); }); interrupt_stack!(virtualization, |stack| { println!("Virtualization fault"); stack.dump(); stack_trace(); - ksignal(SIGBUS); + loop { + interrupt::disable(); + interrupt::halt(); + } }); interrupt_error!(security, |stack, _code| { println!("Security exception"); stack.dump(); stack_trace(); - ksignal(SIGBUS); + loop { + interrupt::disable(); + interrupt::halt(); + } }); diff --git a/src/context/context.rs b/src/context/context.rs index ffa81befc9..d7184c2c72 100644 --- a/src/context/context.rs +++ b/src/context/context.rs @@ -44,7 +44,9 @@ pub enum Status { HardBlocked { reason: HardBlockedReason, }, - Dead, + Dead { + excp: Option, + }, } impl Status { diff --git a/src/context/signal.rs b/src/context/signal.rs index 83acb3423e..24a161ac2a 100644 --- a/src/context/signal.rs +++ b/src/context/signal.rs @@ -75,15 +75,32 @@ pub fn signal_handler() { Ordering::Release, ); } -pub fn excp_handler(_signal: usize) { +pub fn excp_handler(excp: syscall::Exception) { let current = context::current(); - let context = current.write(); - let Some(_eh) = context.sig.as_ref().and_then(|s| s.excp_handler) else { + let mut context = current.write(); + + let Some(eh) = context.sig.as_ref().and_then(|s| s.excp_handler) else { + // TODO: Let procmgr print this? + log::info!( + "UNHANDLED EXCEPTION, CPU {}, PID {current:p}, NAME {}", + crate::cpu_id(), + context.name + ); drop(context); - drop(current); - crate::syscall::exit_this_context(); + // TODO: Allow exceptions to be caught by tracer etc, without necessarily exiting the + // context (closing files, dropping AddrSpace, etc) + crate::syscall::process::exit_this_context(Some(excp)); }; - - // TODO: call exception handler, similar to the signal handler case + // TODO + /* + let Some(regs) = context.regs_mut() else { + // TODO: unhandled exception in this case too? + return; + }; + let old_ip = regs.instr_pointer(); + let old_archdep_reg = regs.ar + let (tctl, pctl, sigst) = context.sigcontrol().expect("already checked"); + tctl.saved_ip.set(excp.rsp); + tctl.saved_archdep_reg*/ } diff --git a/src/main.rs b/src/main.rs index acb2a3579c..e44f6367f2 100644 --- a/src/main.rs +++ b/src/main.rs @@ -270,18 +270,6 @@ fn run_userspace() -> ! { } } -/// Allow exception handlers to send signal to arch-independent kernel -pub fn ksignal(signal: usize) { - let current = context::current(); - - info!("SIGNAL {signal}, CPU {}, PID {current:p}", cpu_id(),); - { - let context = current.read(); - info!("NAME {}", context.name); - } - crate::context::signal::excp_handler(signal); -} - // TODO: Use this macro on aarch64 too. macro_rules! linker_offsets( diff --git a/src/scheme/proc.rs b/src/scheme/proc.rs index 76d25b8f8d..2fada6fa3e 100644 --- a/src/scheme/proc.rs +++ b/src/scheme/proc.rs @@ -1065,7 +1065,7 @@ impl ContextHandle { let mut guard = context.write(); match guard.status { - Status::Dead => return Err(Error::new(EOWNERDEAD)), + Status::Dead { .. } => return Err(Error::new(EOWNERDEAD)), Status::HardBlocked { reason: HardBlockedReason::AwaitingMmap { .. }, } => todo!(), @@ -1118,7 +1118,7 @@ impl ContextHandle { } } } - crate::syscall::exit_this_context(); + crate::syscall::exit_this_context(None); } else { let mut ctxt = context.write(); //log::trace!("FORCEKILL NONSELF={} {}, SELF={}", ctxt.debug_id, ctxt.pid, context::current().read().debug_id); @@ -1250,8 +1250,17 @@ impl ContextHandle { let status = { let context = context.read(); match context.status { - Status::Dead => ContextStatus::Dead, - Status::Runnable if context.being_sigkilled => ContextStatus::Dead, + Status::Dead { excp: None } => ContextStatus::Dead, + Status::Runnable if context.being_sigkilled => ContextStatus::ForceKilled, + Status::Dead { excp: Some(excp) } => { + let (status, payload) = + buf.split_at(size_of::()).ok_or(Error::new(EINVAL))?; + status.copy_from_slice( + &(ContextStatus::UnhandledExcp as usize).to_ne_bytes(), + )?; + let len = payload.copy_common_bytes_from_slice(&excp)?; + return Ok(size_of::() + len); + } Status::Runnable => ContextStatus::Runnable, Status::Blocked => ContextStatus::Blocked, Status::HardBlocked { diff --git a/src/scheme/sys/context.rs b/src/scheme/sys/context.rs index 6eae0f0527..87ee22754b 100644 --- a/src/scheme/sys/context.rs +++ b/src/scheme/sys/context.rs @@ -53,7 +53,7 @@ pub fn resource() -> Result> { stat_string.push('B'); } } - context::Status::Dead => { + context::Status::Dead { .. } => { stat_string.push('Z'); } } diff --git a/src/syscall/debug.rs b/src/syscall/debug.rs index 75c99dd624..b54fe428b2 100644 --- a/src/syscall/debug.rs +++ b/src/syscall/debug.rs @@ -208,7 +208,7 @@ impl SyscallDebugInfo { } #[cfg(feature = "syscall_debug")] pub fn debug_start([a, b, c, d, e, f]: [usize; 6]) { - let do_debug = if crate::context::current().read().name.contains("bash") { + let do_debug = if false && crate::context::current().read().name.contains("bash") { if a == SYS_CLOCK_GETTIME || a == SYS_YIELD || a == SYS_FUTEX { false } else if (a == SYS_WRITE || a == SYS_FSYNC) && (b == 1 || b == 2) { diff --git a/src/syscall/mod.rs b/src/syscall/mod.rs index d19dacc6ca..62a98258b9 100644 --- a/src/syscall/mod.rs +++ b/src/syscall/mod.rs @@ -216,7 +216,7 @@ pub fn syscall(a: usize, b: usize, c: usize, d: usize, e: usize, f: usize) -> us percpu.inside_syscall.set(false); if percpu.switch_internals.being_sigkilled.get() { - exit_this_context(); + exit_this_context(None); } // errormux turns Result into -errno diff --git a/src/syscall/process.rs b/src/syscall/process.rs index 8e6df328cc..5f4777eda3 100644 --- a/src/syscall/process.rs +++ b/src/syscall/process.rs @@ -23,7 +23,7 @@ use crate::{ use super::usercopy::UserSliceWo; -pub fn exit_this_context() -> ! { +pub fn exit_this_context(excp: Option) -> ! { let close_files; let addrspace_opt; @@ -49,7 +49,7 @@ pub fn exit_this_context() -> ! { // TODO: Should status == Status::HardBlocked be handled differently? let owner = { let mut guard = context_lock.write(); - guard.status = context::Status::Dead; + guard.status = context::Status::Dead { excp }; guard.owner_proc_id }; if let Some(owner) = owner {