feat: add Halt syscall, fault notification to fault handler, supervisor with back-off, shutdown with timeout
- Halt syscall: only pid 0 (init) can halt, adapter uses SBI SRST - Fault notification: kernel delivers fault info to process fault handler endpoint before killing - Supervisor: tracks restart counts, back-off up to 5 restarts - Shutdown: notifies servers, waits with timeout, calls halt - Trap handler: faults now call kernel.handle_fault instead of halting
This commit is contained in:
66
crates/kernel/src/syscall/fault.rs
Normal file
66
crates/kernel/src/syscall/fault.rs
Normal file
@@ -0,0 +1,66 @@
|
||||
use platform::Platform;
|
||||
|
||||
use crate::Kernel;
|
||||
|
||||
impl<P: Platform> Kernel<P> {
|
||||
pub fn handle_fault(
|
||||
&mut self,
|
||||
tid: types::id::ThreadId,
|
||||
fault: domain::fault::Fault,
|
||||
fault_pc: usize,
|
||||
) {
|
||||
let pid = match self.threads.get(tid) {
|
||||
Ok(t) => t.process(),
|
||||
Err(_) => return,
|
||||
};
|
||||
|
||||
if let Ok(process) = self.processes.get(pid) {
|
||||
if let Some(handler_slot) = process.fault_handler() {
|
||||
if let Ok(cap) = process.capabilities().get(handler_slot) {
|
||||
if let domain::resource::Resource::Endpoint(ep_id) = cap.resource() {
|
||||
let msg = domain::message::Message::from_words([
|
||||
pid.raw() as usize,
|
||||
fault.code(),
|
||||
fault.address(),
|
||||
fault_pc,
|
||||
]);
|
||||
|
||||
if let Some(ep) = self.endpoints.get_mut(*ep_id) {
|
||||
if ep.has_waiting_receiver() {
|
||||
if let Some(receiver_tid) = ep.dequeue_receiver() {
|
||||
self.pending_results[receiver_tid.raw() as usize] =
|
||||
Some(crate::SyscallResult::Message(msg));
|
||||
|
||||
if let Ok(receiver) = self.threads.get_mut(receiver_tid) {
|
||||
let priority = receiver.priority();
|
||||
let _ = receiver.unblock();
|
||||
let core = self.platform.core_id();
|
||||
use domain::scheduler::Scheduler;
|
||||
self.scheduler.add(receiver_tid, priority, core);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let thread_ids: [Option<types::id::ThreadId>; 4] = {
|
||||
match self.processes.get(pid) {
|
||||
Ok(p) => {
|
||||
let mut ids = [None; 4];
|
||||
for (i, t) in p.thread_ids().enumerate() {
|
||||
if i < 4 { ids[i] = Some(t); }
|
||||
}
|
||||
ids
|
||||
}
|
||||
Err(_) => return,
|
||||
}
|
||||
};
|
||||
|
||||
self.cleanup_threads(&thread_ids);
|
||||
let _ = self.processes.destroy(pid);
|
||||
self.process_memory[pid.raw() as usize] = None;
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
mod capability;
|
||||
mod fault;
|
||||
mod ipc;
|
||||
mod lifecycle;
|
||||
mod memory;
|
||||
@@ -53,6 +54,7 @@ impl<P: Platform> Kernel<P> {
|
||||
Syscall::WaitForInterrupt { irq } => self.handle_wait_for_interrupt(tid, pid, irq),
|
||||
Syscall::AcknowledgeInterrupt { irq } => self.handle_ack_interrupt(pid, irq),
|
||||
Syscall::WaitAny { sources } => self.handle_wait_any(tid, pid, sources),
|
||||
Syscall::Halt => self.handle_halt(pid),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -92,4 +92,16 @@ impl<P: Platform> Kernel<P> {
|
||||
|
||||
SyscallOutcome::TerminateCaller
|
||||
}
|
||||
|
||||
pub(crate) fn handle_halt(
|
||||
&mut self,
|
||||
pid: types::id::ProcessId,
|
||||
) -> SyscallOutcome {
|
||||
if pid.raw() != 0 {
|
||||
return SyscallOutcome::Complete(SyscallResult::Error(
|
||||
domain::error::KernelError::ProcessCreateDenied,
|
||||
));
|
||||
}
|
||||
self.platform.halt();
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user