From f86cd1e6bc151451e41508d8a1a6e37ac837b24f Mon Sep 17 00:00:00 2001 From: Jianfeng Jiang Date: Mon, 31 Oct 2022 16:14:41 +0800 Subject: [PATCH 1/4] add basic support for signal --- src/kxos-std/src/prelude.rs | 3 +- src/kxos-std/src/process/clone.rs | 24 ++- src/kxos-std/src/process/mod.rs | 126 ++++++++++++--- src/kxos-std/src/process/process_filter.rs | 5 +- src/kxos-std/src/process/process_group.rs | 53 +++++++ src/kxos-std/src/process/signal/constants.rs | 57 +++++++ src/kxos-std/src/process/signal/mod.rs | 59 ++++++++ src/kxos-std/src/process/signal/sig_action.rs | 94 ++++++++++++ .../src/process/signal/sig_disposition.rs | 49 ++++++ src/kxos-std/src/process/signal/sig_mask.rs | 45 ++++++ src/kxos-std/src/process/signal/sig_num.rs | 28 ++++ src/kxos-std/src/process/signal/sig_queues.rs | 143 ++++++++++++++++++ .../src/process/signal/signals/mod.rs | 10 ++ .../src/process/signal/signals/user.rs | 49 ++++++ src/kxos-std/src/process/status.rs | 20 +++ src/kxos-std/src/process/table.rs | 26 +++- src/kxos-std/src/process/task.rs | 29 ++-- src/kxos-std/src/syscall/execve.rs | 2 + src/kxos-std/src/syscall/exit.rs | 6 +- src/kxos-std/src/syscall/exit_group.rs | 9 +- src/kxos-std/src/syscall/kill.rs | 55 +++++++ src/kxos-std/src/syscall/mod.rs | 21 ++- src/kxos-std/src/syscall/wait4.rs | 2 +- 23 files changed, 855 insertions(+), 60 deletions(-) create mode 100644 src/kxos-std/src/process/process_group.rs create mode 100644 src/kxos-std/src/process/signal/constants.rs create mode 100644 src/kxos-std/src/process/signal/mod.rs create mode 100644 src/kxos-std/src/process/signal/sig_action.rs create mode 100644 src/kxos-std/src/process/signal/sig_disposition.rs create mode 100644 src/kxos-std/src/process/signal/sig_mask.rs create mode 100644 src/kxos-std/src/process/signal/sig_num.rs create mode 100644 src/kxos-std/src/process/signal/sig_queues.rs create mode 100644 src/kxos-std/src/process/signal/signals/mod.rs create mode 100644 src/kxos-std/src/process/signal/signals/user.rs create mode 100644 src/kxos-std/src/syscall/kill.rs diff --git a/src/kxos-std/src/prelude.rs b/src/kxos-std/src/prelude.rs index c8500616c..a05ad1e94 100644 --- a/src/kxos-std/src/prelude.rs +++ b/src/kxos-std/src/prelude.rs @@ -2,18 +2,17 @@ pub(crate) use alloc::boxed::Box; pub(crate) use alloc::collections::BTreeMap; +pub(crate) use alloc::collections::LinkedList; pub(crate) use alloc::collections::VecDeque; pub(crate) use alloc::ffi::CString; pub(crate) use alloc::sync::Arc; pub(crate) use alloc::sync::Weak; -#[allow(unused)] pub(crate) use alloc::vec; pub(crate) use alloc::vec::Vec; pub(crate) use bitflags::bitflags; pub(crate) use core::ffi::CStr; pub(crate) use kxos_frame::config::PAGE_SIZE; pub(crate) use kxos_frame::vm::Vaddr; -#[allow(unused)] pub(crate) use kxos_frame::{debug, error, info, trace, warn}; pub(crate) use spin::Mutex; diff --git a/src/kxos-std/src/process/clone.rs b/src/kxos-std/src/process/clone.rs index c647f1d4e..cfaa97d31 100644 --- a/src/kxos-std/src/process/clone.rs +++ b/src/kxos-std/src/process/clone.rs @@ -6,7 +6,7 @@ use kxos_frame::{ use crate::{ prelude::*, - process::{new_pid, table, task::create_new_task}, + process::{new_pid, signal::sig_queues::SigQueues, table, task::create_new_task}, }; use super::Process; @@ -127,6 +127,13 @@ pub fn clone_child(parent_context: CpuContext, clone_args: CloneArgs) -> Result< debug!("child process pid: {}", child_pid); debug!("rip = 0x{:x}", child_cpu_context.gp_regs.rip); + // inherit parent's sig disposition + let child_sig_dispositions = current.sig_dispositions().lock().clone(); + // sig queue is set empty + let child_sig_queues = SigQueues::new(); + // inherit parent's sig mask + let child_sig_mask = current.sig_mask().lock().clone(); + let child = Arc::new_cyclic(|child_process_ref| { let weak_child_process = child_process_ref.clone(); let child_task = create_new_task(child_user_space.clone(), weak_child_process); @@ -136,8 +143,23 @@ pub fn clone_child(parent_context: CpuContext, clone_args: CloneArgs) -> Result< child_file_name, child_user_vm, Some(child_user_space), + None, + child_sig_dispositions, + child_sig_queues, + child_sig_mask, ) }); + // Inherit parent's process group + let parent_process_group = current + .process_group() + .lock() + .as_ref() + .map(|ppgrp| ppgrp.upgrade()) + .flatten() + .unwrap(); + parent_process_group.add_process(child.clone()); + child.set_process_group(Arc::downgrade(&parent_process_group)); + Process::current().add_child(child.clone()); table::add_process(child_pid, child.clone()); deal_with_clone_args(clone_args, &child)?; diff --git a/src/kxos-std/src/process/mod.rs b/src/kxos-std/src/process/mod.rs index f3dddd5c0..b34fca73c 100644 --- a/src/kxos-std/src/process/mod.rs +++ b/src/kxos-std/src/process/mod.rs @@ -5,9 +5,13 @@ use kxos_frame::sync::WaitQueue; use kxos_frame::{task::Task, user::UserSpace, vm::VmSpace}; use self::process_filter::ProcessFilter; +use self::process_group::ProcessGroup; use self::process_vm::mmap_area::MmapArea; use self::process_vm::user_heap::UserHeap; use self::process_vm::UserVm; +use self::signal::sig_disposition::SigDispositions; +use self::signal::sig_mask::SigMask; +use self::signal::sig_queues::SigQueues; use self::status::ProcessStatus; use self::task::create_user_task_from_elf; @@ -15,7 +19,9 @@ pub mod clone; pub mod elf; pub mod fifo_scheduler; pub mod process_filter; +pub mod process_group; pub mod process_vm; +pub mod signal; pub mod status; pub mod table; pub mod task; @@ -47,6 +53,14 @@ pub struct Process { parent: Mutex>>, /// Children processes children: Mutex>>, + /// Process group + process_group: Mutex>>, + + // Signal + sig_dispositions: Mutex, + sig_queues: Mutex, + /// Process-level sigmask + sig_mask: Mutex, } impl Process { @@ -69,6 +83,10 @@ impl Process { exec_filename: Option, user_vm: Option, user_space: Option>, + process_group: Option>, + sig_dispositions: SigDispositions, + sig_queues: SigQueues, + sig_mask: SigMask, ) -> Self { let parent = if pid == 0 { debug!("Init process does not has parent"); @@ -91,6 +109,10 @@ impl Process { status: Mutex::new(ProcessStatus::Runnable), parent: Mutex::new(parent), children: Mutex::new(children), + process_group: Mutex::new(process_group), + sig_dispositions: Mutex::new(sig_dispositions), + sig_queues: Mutex::new(sig_queues), + sig_mask: Mutex::new(sig_mask), } } @@ -124,8 +146,23 @@ impl Process { let task = create_user_task_from_elf(filename, elf_file_content, weak_process); let user_space = task.user_space().map(|user_space| user_space.clone()); let user_vm = UserVm::new(); - Process::new(pid, task, cloned_filename, Some(user_vm), user_space) + let sig_dispositions = SigDispositions::new(); + let sig_queues = SigQueues::new(); + let sig_mask = SigMask::new_empty(); + Process::new( + pid, + task, + cloned_filename, + Some(user_vm), + user_space, + None, + sig_dispositions, + sig_queues, + sig_mask, + ) }); + // Set process group + user_process.create_and_set_process_group(); table::add_process(pid, user_process.clone()); user_process } @@ -138,8 +175,22 @@ impl Process { let kernel_process = Arc::new_cyclic(|weak_process_ref| { let weak_process = weak_process_ref.clone(); let task = Task::new(task_fn, weak_process, None).expect("spawn kernel task failed"); - Process::new(pid, task, None, None, None) + let sig_dispositions = SigDispositions::new(); + let sig_queues = SigQueues::new(); + let sig_mask = SigMask::new_empty(); + Process::new( + pid, + task, + None, + None, + None, + None, + sig_dispositions, + sig_queues, + sig_mask, + ) }); + kernel_process.create_and_set_process_group(); table::add_process(pid, kernel_process.clone()); kernel_process } @@ -151,7 +202,21 @@ impl Process { /// returns the process group id of the process pub fn pgid(&self) -> Pgid { - todo!() + if let Some(process_group) = self + .process_group + .lock() + .as_ref() + .map(|process_group| process_group.upgrade()) + .flatten() + { + process_group.pgid() + } else { + 0 + } + } + + pub fn process_group(&self) -> &Mutex>> { + &self.process_group } /// add a child process @@ -165,6 +230,23 @@ impl Process { let _ = self.parent.lock().insert(parent); } + pub fn set_process_group(&self, process_group: Weak) { + if self.process_group.lock().is_none() { + let _ = self.process_group.lock().insert(process_group); + } else { + todo!("We should do something with old group") + } + } + + /// create a new process group for the process and add it to globle table. + /// Then set the process group for current process. + fn create_and_set_process_group(self: &Arc) { + let process_group = Arc::new(ProcessGroup::new(self.clone())); + let pgid = process_group.pgid(); + self.set_process_group(Arc::downgrade(&process_group)); + table::add_process_group(pgid, process_group); + } + fn parent(&self) -> Option> { self.parent .lock() @@ -173,17 +255,13 @@ impl Process { .flatten() } - /// Set the exit code when calling exit or exit_group - pub fn set_exit_code(&self, exit_code: i32) { - self.exit_code.store(exit_code, Ordering::Relaxed); - } - - /// Exit current process - /// Set the status of current process as Zombie - /// Move all children to init process - /// Wake up the parent wait queue if parent is waiting for self - pub fn exit(&self) { + /// Exit current process. + /// Set the status of current process as Zombie and set exit code. + /// Move all children to init process. + /// Wake up the parent wait queue if parent is waiting for self. + pub fn exit(&self, exit_code: i32) { self.status.lock().set_zombie(); + self.exit_code.store(exit_code, Ordering::Relaxed); // move children to the init process let current_process = Process::current(); if !current_process.is_init_process() { @@ -267,15 +345,15 @@ impl Process { /// We current just remove the child from the children map. pub fn reap_zombie_child(&self, pid: Pid) -> i32 { let child_process = self.children.lock().remove(&pid).unwrap(); - assert!(child_process.status() == ProcessStatus::Zombie); - table::delete_process(child_process.pid()); + assert!(child_process.status().lock().is_zombie()); + table::remove_process(child_process.pid()); child_process.exit_code() } /// Get any zombie child pub fn get_zombie_child(&self) -> Option> { for (_, child_process) in self.children.lock().iter() { - if child_process.status().is_zombie() { + if child_process.status().lock().is_zombie() { return Some(child_process.clone()); } } @@ -295,8 +373,20 @@ impl Process { self.filename.as_ref() } - pub fn status(&self) -> ProcessStatus { - self.status.lock().clone() + pub fn status(&self) -> &Mutex { + &self.status + } + + pub fn sig_dispositions(&self) -> &Mutex { + &self.sig_dispositions + } + + pub fn sig_queues(&self) -> &Mutex { + &self.sig_queues + } + + pub fn sig_mask(&self) -> &Mutex { + &self.sig_mask } } diff --git a/src/kxos-std/src/process/process_filter.rs b/src/kxos-std/src/process/process_filter.rs index 6c7054d8c..4db223100 100644 --- a/src/kxos-std/src/process/process_filter.rs +++ b/src/kxos-std/src/process/process_filter.rs @@ -20,9 +20,10 @@ impl ProcessFilter { } } - // used for wait4 - pub fn from_wait_pid(wait_pid: isize) -> Self { + // used for wait4 and kill + pub fn from_id(wait_pid: isize) -> Self { // https://man7.org/linux/man-pages/man2/waitpid.2.html + // https://man7.org/linux/man-pages/man2/kill.2.html if wait_pid < -1 { // process group ID is equal to the absolute value of pid. ProcessFilter::WithPgid((-wait_pid) as Pgid) diff --git a/src/kxos-std/src/process/process_group.rs b/src/kxos-std/src/process/process_group.rs new file mode 100644 index 000000000..8444fe683 --- /dev/null +++ b/src/kxos-std/src/process/process_group.rs @@ -0,0 +1,53 @@ +use super::{Pgid, Pid, Process}; +use crate::prelude::*; + +pub struct ProcessGroup { + inner: Mutex, +} + +struct ProcessGroupInner { + pgid: Pgid, + processes: BTreeMap>, + leader_process: Option>, +} + +impl ProcessGroup { + fn default() -> Self { + ProcessGroup { + inner: Mutex::new(ProcessGroupInner { + pgid: 0, + processes: BTreeMap::new(), + leader_process: None, + }), + } + } + + pub fn new(process: Arc) -> Self { + let process_group = ProcessGroup::default(); + let pid = process.pid(); + process_group.set_pgid(pid); + process_group.add_process(process.clone()); + process_group.set_leader_process(process); + process_group + } + + pub fn set_pgid(&self, pgid: Pgid) { + self.inner.lock().pgid = pgid; + } + + pub fn set_leader_process(&self, leader_process: Arc) { + self.inner.lock().leader_process = Some(leader_process); + } + + pub fn add_process(&self, process: Arc) { + self.inner.lock().processes.insert(process.pid(), process); + } + + pub fn remove_process(&self, pid: Pid) { + self.inner.lock().processes.remove(&pid); + } + + pub fn pgid(&self) -> Pgid { + self.inner.lock().pgid + } +} diff --git a/src/kxos-std/src/process/signal/constants.rs b/src/kxos-std/src/process/signal/constants.rs new file mode 100644 index 000000000..7f2a3752c --- /dev/null +++ b/src/kxos-std/src/process/signal/constants.rs @@ -0,0 +1,57 @@ +/// Standard signals +pub(super) const MIN_STD_SIG_NUM: u8 = 1; +pub(super) const MAX_STD_SIG_NUM: u8 = 31; // inclusive +/// Real-time signals +pub(super) const MIN_RT_SIG_NUM: u8 = 32; +pub(super) const MAX_RT_SIG_NUM: u8 = 64; // inclusive +/// Count the number of signals +pub(super) const COUNT_STD_SIGS: usize = 31; +pub(super) const COUNT_RT_SIGS: usize = 33; +pub(super) const COUNT_ALL_SIGS: usize = 64; + +pub const SIG_DFL: usize = 0; +pub const SIG_IGN: usize = 1; + +use super::sig_num::SigNum; + +macro_rules! define_std_signums { + ( $( $name: ident = $num: expr ),+, ) => { + $( + pub const $name : SigNum = SigNum::from_u8($num); + )* + } +} + +define_std_signums! { + SIGHUP = 1, // Hangup detected on controlling terminal or death of controlling process + SIGINT = 2, // Interrupt from keyboard + SIGQUIT = 3, // Quit from keyboard + SIGILL = 4, // Illegal Instruction + SIGTRAP = 5, // Trace/breakpoint trap + SIGABRT = 6, // Abort signal from abort(3) + SIGBUS = 7, // Bus error (bad memory access) + SIGFPE = 8, // Floating-point exception + SIGKILL = 9, // Kill signal + SIGUSR1 = 10, // User-defined signal 1 + SIGSEGV = 11, // Invalid memory reference + SIGUSR2 = 12, // User-defined signal 2 + SIGPIPE = 13, // Broken pipe: write to pipe with no readers; see pipe(7) + SIGALRM = 14, // Timer signal from alarm(2) + SIGTERM = 15, // Termination signal + SIGSTKFLT = 16, // Stack fault on coprocessor (unused) + SIGCHLD = 17, // Child stopped or terminated + SIGCONT = 18, // Continue if stopped + SIGSTOP = 19, // Stop process + SIGTSTP = 20, // Stop typed at terminal + SIGTTIN = 21, // Terminal input for background process + SIGTTOU = 22, // Terminal output for background process + SIGURG = 23, // Urgent condition on socket (4.2BSD) + SIGXCPU = 24, // CPU time limit exceeded (4.2BSD); see setrlimit(2) + SIGXFSZ = 25, // File size limit exceeded (4.2BSD); see setrlimit(2) + SIGVTALRM = 26, // Virtual alarm clock (4.2BSD) + SIGPROF = 27, // Profiling timer expired + SIGWINCH = 28, // Window resize signal (4.3BSD, Sun) + SIGIO = 29, // I/O now possible (4.2BSD) + SIGPWR = 30, // Power failure (System V) + SIGSYS = 31, // Bad system call (SVr4); see also seccomp(2) +} diff --git a/src/kxos-std/src/process/signal/mod.rs b/src/kxos-std/src/process/signal/mod.rs new file mode 100644 index 000000000..2743e79b3 --- /dev/null +++ b/src/kxos-std/src/process/signal/mod.rs @@ -0,0 +1,59 @@ +pub mod constants; +pub mod sig_action; +pub mod sig_disposition; +pub mod sig_mask; +pub mod sig_num; +pub mod sig_queues; +pub mod signals; + +use crate::{ + prelude::*, + process::signal::sig_action::{SigAction, SigDefaultAction}, +}; + +/// Handle pending signal for current process +pub fn handle_pending_signal() { + let current = current!(); + let sig_queues = current.sig_queues(); + let mut sig_queues_guard = sig_queues.lock(); + let sig_mask = current.sig_mask().lock().clone(); + if let Some(signal) = sig_queues_guard.dequeue(&sig_mask) { + let sig_num = signal.num(); + debug!("sig_num = {:?}", sig_num); + let sig_action = current.sig_dispositions().lock().get(sig_num); + match sig_action { + SigAction::Ign => { + debug!("Ignore signal {:?}", sig_num); + } + SigAction::User { .. } => todo!(), + SigAction::Dfl => { + let sig_default_action = SigDefaultAction::from_signum(sig_num); + match sig_default_action { + SigDefaultAction::Core | SigDefaultAction::Term => { + // FIXME: How to set correct status if process is terminated + current.exit(1); + } + SigDefaultAction::Ign => {} + SigDefaultAction::Stop => { + let mut status_guard = current.status().lock(); + if status_guard.is_runnable() { + status_guard.set_suspend(); + } else { + panic!("Try to suspend a not running process.") + } + drop(status_guard); + } + SigDefaultAction::Cont => { + let mut status_guard = current.status().lock(); + if status_guard.is_suspend() { + status_guard.set_runnable(); + } else { + panic!("Try to continue a not suspended process.") + } + drop(status_guard); + } + } + } + } + } +} diff --git a/src/kxos-std/src/process/signal/sig_action.rs b/src/kxos-std/src/process/signal/sig_action.rs new file mode 100644 index 000000000..27a9e3a2a --- /dev/null +++ b/src/kxos-std/src/process/signal/sig_action.rs @@ -0,0 +1,94 @@ +use super::{constants::*, sig_mask::SigMask, sig_num::SigNum}; +use bitflags::bitflags; +use kxos_frame::warn; + +#[derive(Debug, Copy, Clone, PartialEq, Eq)] +pub enum SigAction { + Dfl, // Default action + Ign, // Ignore this signal + User { + // User-given handler + handler_addr: usize, + flags: SigActionFlags, + restorer_addr: usize, + mask: SigMask, + }, +} + +impl Default for SigAction { + fn default() -> Self { + SigAction::Dfl + } +} + +bitflags! { + pub struct SigActionFlags: u32 { + const SA_NOCLDSTOP = 1; + const SA_NOCLDWAIT = 2; + const SA_SIGINFO = 4; + const SA_ONSTACK = 0x08000000; + const SA_RESTART = 0x10000000; + const SA_NODEFER = 0x40000000; + const SA_RESETHAND = 0x80000000; + const SA_RESTORER = 0x04000000; + } +} + +impl TryFrom for SigActionFlags { + type Error = &'static str; + + fn try_from(bits: u32) -> Result { + let flags = SigActionFlags::from_bits(bits).ok_or_else(|| "invalid sigaction flags")?; + if flags.contains(SigActionFlags::SA_RESTART) { + warn!("SA_RESTART is not supported"); + } + Ok(flags) + } +} + +impl SigActionFlags { + pub fn to_u32(&self) -> u32 { + self.bits() + } +} + +/// The default action to signals +#[derive(Debug, Copy, Clone)] +pub enum SigDefaultAction { + Term, // Default action is to terminate the process. + Ign, // Default action is to ignore the signal. + Core, // Default action is to terminate the process and dump core (see core(5)). + Stop, // Default action is to stop the process. + Cont, // Default action is to continue the process if it is currently stopped. +} + +impl SigDefaultAction { + pub fn from_signum(num: SigNum) -> SigDefaultAction { + match num { + SIGABRT | // = SIGIOT + SIGBUS | + SIGFPE | + SIGILL | + SIGQUIT | + SIGSEGV | + SIGSYS | // = SIGUNUSED + SIGTRAP | + SIGXCPU | + SIGXFSZ + => SigDefaultAction::Core, + SIGCHLD | + SIGURG | + SIGWINCH + => SigDefaultAction::Ign, + SIGCONT + => SigDefaultAction::Cont, + SIGSTOP | + SIGTSTP | + SIGTTIN | + SIGTTOU + => SigDefaultAction::Stop, + _ + => SigDefaultAction::Term, + } + } +} diff --git a/src/kxos-std/src/process/signal/sig_disposition.rs b/src/kxos-std/src/process/signal/sig_disposition.rs new file mode 100644 index 000000000..1c67904d2 --- /dev/null +++ b/src/kxos-std/src/process/signal/sig_disposition.rs @@ -0,0 +1,49 @@ +use super::{constants::*, sig_action::SigAction, sig_num::SigNum}; + +#[derive(Copy, Clone)] +pub struct SigDispositions { + // SigNum -> SigAction + map: [SigAction; COUNT_ALL_SIGS], +} + +impl SigDispositions { + pub fn new() -> Self { + Self { + map: [SigAction::default(); COUNT_ALL_SIGS], + } + } + + pub fn get(&self, num: SigNum) -> SigAction { + let idx = Self::num_to_idx(num); + self.map[idx] + } + + pub fn set(&mut self, num: SigNum, sa: SigAction) { + let idx = Self::num_to_idx(num); + self.map[idx] = sa; + } + + pub fn set_default(&mut self, num: SigNum) { + let idx = Self::num_to_idx(num); + self.map[idx] = SigAction::Dfl; + } + + /// man 7 signal: + /// When execve, the handled signals are reset to the default; the dispositions of + /// ignored signals are left unchanged. + /// This function should be used when execve. + pub fn inherit(&mut self) { + for sigaction in &mut self.map { + match sigaction { + SigAction::User { .. } => { + *sigaction = SigAction::Dfl; + } + _ => {} + } + } + } + + fn num_to_idx(num: SigNum) -> usize { + (num.as_u8() - MIN_STD_SIG_NUM) as usize + } +} diff --git a/src/kxos-std/src/process/signal/sig_mask.rs b/src/kxos-std/src/process/signal/sig_mask.rs new file mode 100644 index 000000000..0b0d998f2 --- /dev/null +++ b/src/kxos-std/src/process/signal/sig_mask.rs @@ -0,0 +1,45 @@ +use super::{constants::MIN_STD_SIG_NUM, sig_num::SigNum}; + +#[derive(Debug, Copy, Clone, Default, PartialEq, Eq)] +pub struct SigMask { + bits: u64, +} + +impl SigMask { + pub const fn from_u64(bits: u64) -> Self { + SigMask { bits } + } + + pub const fn new_empty() -> Self { + SigMask::from_u64(0) + } + + pub const fn new_full() -> Self { + SigMask::from_u64(!0) + } + + pub const fn as_u64(&self) -> u64 { + self.bits + } + + pub const fn empty(&self) -> bool { + self.bits == 0 + } + + pub const fn full(&self) -> bool { + self.bits == !0 + } + + pub fn count(&self) -> usize { + self.bits.count_ones() as usize + } + + pub fn contains(&self, signum: SigNum) -> bool { + let idx = Self::num_to_idx(signum); + (self.bits & (1_u64 << idx)) != 0 + } + + fn num_to_idx(num: SigNum) -> usize { + (num.as_u8() - MIN_STD_SIG_NUM) as usize + } +} diff --git a/src/kxos-std/src/process/signal/sig_num.rs b/src/kxos-std/src/process/signal/sig_num.rs new file mode 100644 index 000000000..1facf40ab --- /dev/null +++ b/src/kxos-std/src/process/signal/sig_num.rs @@ -0,0 +1,28 @@ +use super::constants::*; + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct SigNum { + sig_num: u8, +} + +impl SigNum { + // Safety: This function should only be used when signum is ensured to be valid. + pub const fn from_u8(sig_num: u8) -> Self { + if sig_num > MAX_RT_SIG_NUM || sig_num < MIN_STD_SIG_NUM { + unreachable!() + } + SigNum { sig_num } + } + + pub const fn as_u8(&self) -> u8 { + self.sig_num + } + + pub fn is_std(&self) -> bool { + self.sig_num <= MAX_STD_SIG_NUM + } + + pub fn is_real_time(&self) -> bool { + self.sig_num >= MIN_RT_SIG_NUM + } +} diff --git a/src/kxos-std/src/process/signal/sig_queues.rs b/src/kxos-std/src/process/signal/sig_queues.rs new file mode 100644 index 000000000..eef4db07b --- /dev/null +++ b/src/kxos-std/src/process/signal/sig_queues.rs @@ -0,0 +1,143 @@ +use super::constants::*; +use crate::prelude::*; + +use super::sig_mask::SigMask; +use super::sig_num::SigNum; +use super::signals::Signal; + +pub struct SigQueues { + count: usize, + std_queues: Vec>>, + rt_queues: Vec>>, +} + +impl SigQueues { + pub fn new() -> Self { + let count = 0; + let std_queues = (0..COUNT_STD_SIGS).map(|_| None).collect(); + let rt_queues = (0..COUNT_RT_SIGS).map(|_| Default::default()).collect(); + // let notifier = Notifier::new(); + SigQueues { + count, + std_queues, + rt_queues, + } + } + + pub fn empty(&self) -> bool { + self.count == 0 + } + + pub fn enqueue(&mut self, signal: Box) { + let signum = signal.num(); + if signum.is_std() { + // Standard signals + // + // From signal(7): + // + // Standard signals do not queue. If multiple instances of a standard + // signal are generated while that signal is blocked, then only one + // instance of the signal is marked as pending (and the signal will be + // delivered just once when it is unblocked). In the case where a + // standard signal is already pending, the siginfo_t structure (see + // sigaction(2)) associated with that signal is not overwritten on + // arrival of subsequent instances of the same signal. Thus, the + // process will receive the information associated with the first + // instance of the signal. + let queue = self.get_std_queue_mut(signum); + if queue.is_some() { + // If there is already a signal pending, just ignore all subsequent signals + return; + } + *queue = Some(signal); + self.count += 1; + } else { + // Real-time signals + let queue = self.get_rt_queue_mut(signum); + queue.push_back(signal); + self.count += 1; + } + + // self.notifier.broadcast(&signum); + } + + pub fn dequeue(&mut self, blocked: &SigMask) -> Option> { + // Fast path for the common case of no pending signals + if self.empty() { + return None; + } + + // Deliver standard signals. + // + // According to signal(7): + // If both standard and real-time signals are pending for a process, + // POSIX leaves it unspecified which is delivered first. Linux, like + // many other implementations, gives priority to standard signals in + // this case. + + // POSIX leaves unspecified which to deliver first if there are multiple + // pending standard signals. So we are free to define our own. The + // principle is to give more urgent signals higher priority (like SIGKILL). + const ORDERED_STD_SIGS: [SigNum; COUNT_STD_SIGS] = [ + SIGKILL, SIGTERM, SIGSTOP, SIGCONT, SIGSEGV, SIGILL, SIGHUP, SIGINT, SIGQUIT, SIGTRAP, + SIGABRT, SIGBUS, SIGFPE, SIGUSR1, SIGUSR2, SIGPIPE, SIGALRM, SIGSTKFLT, SIGCHLD, + SIGTSTP, SIGTTIN, SIGTTOU, SIGURG, SIGXCPU, SIGXFSZ, SIGVTALRM, SIGPROF, SIGWINCH, + SIGIO, SIGPWR, SIGSYS, + ]; + for &signum in &ORDERED_STD_SIGS { + if blocked.contains(signum) { + continue; + } + + let queue = self.get_std_queue_mut(signum); + let signal = queue.take(); + if signal.is_some() { + self.count -= 1; + return signal; + } + } + + // If no standard signals, then deliver real-time signals. + // + // According to signal (7): + // Real-time signals are delivered in a guaranteed order. Multiple + // real-time signals of the same type are delivered in the order + // they were sent. If different real-time signals are sent to a + // process, they are delivered starting with the lowest-numbered + // signal. (I.e., low-numbered signals have highest priority.) + for signum in MIN_RT_SIG_NUM..=MAX_RT_SIG_NUM { + let signum = SigNum::from_u8(signum); + if blocked.contains(signum) { + continue; + } + + let queue = self.get_rt_queue_mut(signum); + let signal = queue.pop_front(); + if signal.is_some() { + self.count -= 1; + return signal; + } + } + + // There must be pending but blocked signals + None + } + + fn get_std_queue_mut(&mut self, signum: SigNum) -> &mut Option> { + debug_assert!(signum.is_std()); + let idx = (signum.as_u8() - MIN_STD_SIG_NUM) as usize; + &mut self.std_queues[idx] + } + + fn get_rt_queue_mut(&mut self, signum: SigNum) -> &mut VecDeque> { + debug_assert!(signum.is_real_time()); + let idx = (signum.as_u8() - MIN_RT_SIG_NUM) as usize; + &mut self.rt_queues[idx] + } +} + +impl Default for SigQueues { + fn default() -> Self { + Self::new() + } +} diff --git a/src/kxos-std/src/process/signal/signals/mod.rs b/src/kxos-std/src/process/signal/signals/mod.rs new file mode 100644 index 000000000..064f1c127 --- /dev/null +++ b/src/kxos-std/src/process/signal/signals/mod.rs @@ -0,0 +1,10 @@ +pub mod user; + +use core::fmt::Debug; + +use super::sig_num::SigNum; + +pub trait Signal: Send + Sync + Debug { + /// Returns the number of the signal. + fn num(&self) -> SigNum; +} diff --git a/src/kxos-std/src/process/signal/signals/user.rs b/src/kxos-std/src/process/signal/signals/user.rs new file mode 100644 index 000000000..cf0fa115f --- /dev/null +++ b/src/kxos-std/src/process/signal/signals/user.rs @@ -0,0 +1,49 @@ +use crate::process::{signal::sig_num::SigNum, Pid}; + +use super::Signal; + +pub type Uid = usize; + +#[derive(Debug, Clone, Copy)] +pub struct UserSignal { + num: SigNum, + pid: Pid, + uid: Uid, + kind: UserSignalKind, +} + +#[derive(Debug, Copy, Clone)] +pub enum UserSignalKind { + Kill, + Tkill, + Sigqueue, +} + +impl UserSignal { + pub fn new(num: SigNum, kind: UserSignalKind, pid: Pid, uid: Uid) -> Self { + Self { + num, + kind, + pid, + uid, + } + } + + pub fn pid(&self) -> Pid { + self.pid + } + + pub fn uid(&self) -> Uid { + self.uid + } + + pub fn kind(&self) -> UserSignalKind { + self.kind + } +} + +impl Signal for UserSignal { + fn num(&self) -> SigNum { + self.num + } +} diff --git a/src/kxos-std/src/process/status.rs b/src/kxos-std/src/process/status.rs index 7f60f7e63..f9c666ed1 100644 --- a/src/kxos-std/src/process/status.rs +++ b/src/kxos-std/src/process/status.rs @@ -2,7 +2,11 @@ #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum ProcessStatus { + /// Can be scheduled to run Runnable, + /// Suspend until be woken by SIGCONT signal + SuspendSignalable, + /// Exit while not reaped by parent Zombie, } @@ -14,4 +18,20 @@ impl ProcessStatus { pub fn is_zombie(&self) -> bool { *self == ProcessStatus::Zombie } + + pub fn set_suspend(&mut self) { + *self = ProcessStatus::SuspendSignalable; + } + + pub fn is_suspend(&self) -> bool { + *self == ProcessStatus::SuspendSignalable + } + + pub fn set_runnable(&mut self) { + *self = ProcessStatus::Runnable; + } + + pub fn is_runnable(&self) -> bool { + *self == ProcessStatus::Runnable + } } diff --git a/src/kxos-std/src/process/table.rs b/src/kxos-std/src/process/table.rs index 386381cfb..7b06f0d3b 100644 --- a/src/kxos-std/src/process/table.rs +++ b/src/kxos-std/src/process/table.rs @@ -4,10 +4,12 @@ use crate::prelude::*; -use super::{Pid, Process}; +use super::{process_group::ProcessGroup, Pgid, Pid, Process}; lazy_static! { static ref PROCESS_TABLE: Mutex>> = Mutex::new(BTreeMap::new()); + static ref PROCESS_GROUP_TABLE: Mutex>> = + Mutex::new(BTreeMap::new()); } /// add a process to global table @@ -15,8 +17,8 @@ pub fn add_process(pid: Pid, process: Arc) { PROCESS_TABLE.lock().insert(pid, process); } -/// delete a process from global table -pub fn delete_process(pid: Pid) { +/// remove a process from global table +pub fn remove_process(pid: Pid) { PROCESS_TABLE.lock().remove(&pid); } @@ -36,3 +38,21 @@ pub fn get_all_processes() -> Vec> { .map(|(_, process)| process.clone()) .collect() } + +/// add process group to global table +pub fn add_process_group(pgid: Pgid, process_group: Arc) { + PROCESS_GROUP_TABLE.lock().insert(pgid, process_group); +} + +/// remove process group from global table +pub fn remove_process_group(pgid: Pgid) { + PROCESS_GROUP_TABLE.lock().remove(&pgid); +} + +/// get a process group with pgid +pub fn pgid_to_process_group(pgid: Pgid) -> Option> { + PROCESS_GROUP_TABLE + .lock() + .get(&pgid) + .map(|process_group| process_group.clone()) +} diff --git a/src/kxos-std/src/process/task.rs b/src/kxos-std/src/process/task.rs index c4cc4fbcd..286e4eea6 100644 --- a/src/kxos-std/src/process/task.rs +++ b/src/kxos-std/src/process/task.rs @@ -7,7 +7,7 @@ use kxos_frame::{ vm::VmSpace, }; -use crate::prelude::*; +use crate::{prelude::*, process::signal::handle_pending_signal}; use crate::syscall::syscall_handler; @@ -47,28 +47,33 @@ pub fn create_new_task(userspace: Arc, parent: Weak) -> Arc< loop { let user_event = user_mode.execute(); let context = user_mode.context_mut(); - if let HandlerResult::Exit = handle_user_event(user_event, context) { - // FIXME: How to set task status? How to set exit code of process? + // handle user event: + handle_user_event(user_event, context); + let current = current!(); + // should be do this comparison before handle signal? + if current.status().lock().is_zombie() { break; } - // debug!("before return to user space: {:#x?}", context); + handle_pending_signal(); + if current.status().lock().is_zombie() { + break; + } + // If current is suspended, wait for a signal to wake up self + while current.status().lock().is_suspend() { + Process::yield_now(); + debug!("{} is suspended.", current.pid()); + handle_pending_signal(); + } } - let current_process = Process::current(); - current_process.exit(); } Task::new(user_task_entry, parent, Some(userspace)).expect("spawn task failed") } -fn handle_user_event(user_event: UserEvent, context: &mut CpuContext) -> HandlerResult { +fn handle_user_event(user_event: UserEvent, context: &mut CpuContext) { match user_event { UserEvent::Syscall => syscall_handler(context), UserEvent::Fault => todo!(), UserEvent::Exception => todo!(), } } - -pub enum HandlerResult { - Exit, - Continue, -} diff --git a/src/kxos-std/src/syscall/execve.rs b/src/kxos-std/src/syscall/execve.rs index df6dc92da..fb2f6e1d1 100644 --- a/src/kxos-std/src/syscall/execve.rs +++ b/src/kxos-std/src/syscall/execve.rs @@ -35,6 +35,8 @@ pub fn sys_execve( let elf_load_info = load_elf_to_vm_space(filename, elf_file_content, &vm_space).expect("load elf failed"); debug!("load elf in execve succeeds"); + // set signal disposition to default + current.sig_dispositions().lock().inherit(); // set cpu context to default let defalut_content = CpuContext::default(); context.gp_regs = defalut_content.gp_regs; diff --git a/src/kxos-std/src/syscall/exit.rs b/src/kxos-std/src/syscall/exit.rs index 6c6e87d48..3d0682ff6 100644 --- a/src/kxos-std/src/syscall/exit.rs +++ b/src/kxos-std/src/syscall/exit.rs @@ -1,11 +1,11 @@ use crate::prelude::*; -use crate::{process::Process, syscall::SYS_EXIT}; +use crate::syscall::SYS_EXIT; use super::SyscallResult; pub fn sys_exit(exit_code: i32) -> SyscallResult { debug!("[syscall][id={}][SYS_EXIT]", SYS_EXIT); - Process::current().set_exit_code(exit_code); - SyscallResult::Exit(exit_code) + current!().exit(exit_code); + SyscallResult::NotReturn } diff --git a/src/kxos-std/src/syscall/exit_group.rs b/src/kxos-std/src/syscall/exit_group.rs index 5d292d30c..1ac7bd7cb 100644 --- a/src/kxos-std/src/syscall/exit_group.rs +++ b/src/kxos-std/src/syscall/exit_group.rs @@ -1,12 +1,9 @@ use crate::prelude::*; -use crate::{ - process::Process, - syscall::{SyscallResult, SYS_EXIT_GROUP}, -}; +use crate::syscall::{SyscallResult, SYS_EXIT_GROUP}; pub fn sys_exit_group(exit_code: u64) -> SyscallResult { debug!("[syscall][id={}][SYS_EXIT_GROUP]", SYS_EXIT_GROUP); - Process::current().set_exit_code(exit_code as _); - SyscallResult::Exit(exit_code as _) + current!().exit(exit_code as _); + SyscallResult::NotReturn } diff --git a/src/kxos-std/src/syscall/kill.rs b/src/kxos-std/src/syscall/kill.rs new file mode 100644 index 000000000..e4af4f220 --- /dev/null +++ b/src/kxos-std/src/syscall/kill.rs @@ -0,0 +1,55 @@ +use crate::prelude::*; + +use crate::process::signal::signals::user::{UserSignal, UserSignalKind}; +use crate::process::{table, Process}; +use crate::{ + process::{process_filter::ProcessFilter, signal::sig_num::SigNum}, + syscall::SYS_KILL, +}; + +use super::SyscallResult; + +pub fn sys_kill(process_filter: u64, sig_num: u64) -> SyscallResult { + debug!("[syscall][id={}][SYS_KILL]", SYS_KILL); + let process_filter = ProcessFilter::from_id(process_filter as _); + let sig_num = SigNum::from_u8(sig_num as _); + let _ = do_sys_kill(process_filter, sig_num); + SyscallResult::Return(0) +} + +pub fn do_sys_kill(process_filter: ProcessFilter, sig_num: SigNum) -> Result<()> { + let current = current!(); + let pid = current.pid(); + // FIXME: use the correct uid + let uid = 0; + let processes = get_processes(&process_filter)?; + for process in processes.iter() { + if process.status().lock().is_zombie() { + continue; + } + + let signal = Box::new(UserSignal::new(sig_num, UserSignalKind::Kill, pid, uid)); + let sig_queues = process.sig_queues(); + sig_queues.lock().enqueue(signal); + } + Ok(()) +} + +fn get_processes(filter: &ProcessFilter) -> Result>> { + let processes = match filter { + ProcessFilter::Any => { + let mut processes = table::get_all_processes(); + processes.retain(|process| process.pid() != 0); + processes + } + ProcessFilter::WithPid(pid) => { + let process = table::pid_to_process(*pid); + match process { + None => return_errno!(Errno::ESRCH), + Some(process) => vec![process], + } + } + ProcessFilter::WithPgid(_) => todo!(), + }; + Ok(processes) +} diff --git a/src/kxos-std/src/syscall/mod.rs b/src/kxos-std/src/syscall/mod.rs index d0ea5dc98..64e283354 100644 --- a/src/kxos-std/src/syscall/mod.rs +++ b/src/kxos-std/src/syscall/mod.rs @@ -3,10 +3,10 @@ use crate::prelude::*; use crate::syscall::clone::sys_clone; +use crate::syscall::kill::sys_kill; use alloc::borrow::ToOwned; use kxos_frame::cpu::CpuContext; -use crate::process::task::HandlerResult; use crate::syscall::access::sys_access; use crate::syscall::arch_prctl::sys_arch_prctl; use crate::syscall::brk::sys_brk; @@ -41,6 +41,7 @@ mod fstat; mod futex; mod getpid; mod gettid; +mod kill; mod mmap; mod mprotect; mod readlink; @@ -68,6 +69,7 @@ const SYS_FORK: u64 = 57; const SYS_EXECVE: u64 = 59; const SYS_EXIT: u64 = 60; const SYS_WAIT4: u64 = 61; +const SYS_KILL: u64 = 62; const SYS_UNAME: u64 = 63; const SYS_READLINK: u64 = 89; const SYS_GETUID: u64 = 102; @@ -87,9 +89,8 @@ pub struct SyscallArgument { } pub enum SyscallResult { - Exit(i32), Return(i32), - ReturnNothing, // execve return nothing + NotReturn, } impl SyscallArgument { @@ -109,19 +110,14 @@ impl SyscallArgument { } } -pub fn syscall_handler(context: &mut CpuContext) -> HandlerResult { +pub fn syscall_handler(context: &mut CpuContext) { let syscall_frame = SyscallArgument::new_from_context(context); let syscall_return = syscall_dispatch(syscall_frame.syscall_number, syscall_frame.args, context); - match syscall_return { - SyscallResult::Return(return_value) => { - // FIXME: set return value? - context.gp_regs.rax = return_value as u64; - HandlerResult::Continue - } - SyscallResult::Exit(exit_code) => HandlerResult::Exit, - SyscallResult::ReturnNothing => HandlerResult::Continue, + if let SyscallResult::Return(return_value) = syscall_return { + // FIXME: set return value? + context.gp_regs.rax = return_value as u64; } } @@ -153,6 +149,7 @@ pub fn syscall_dispatch( SYS_EXECVE => sys_execve(args[0] as _, args[1] as _, args[2] as _, context), SYS_EXIT => sys_exit(args[0] as _), SYS_WAIT4 => sys_wait4(args[0], args[1], args[2]), + SYS_KILL => sys_kill(args[0], args[1]), SYS_UNAME => sys_uname(args[0]), SYS_READLINK => sys_readlink(args[0], args[1], args[2]), SYS_GETUID => sys_getuid(), diff --git a/src/kxos-std/src/syscall/wait4.rs b/src/kxos-std/src/syscall/wait4.rs index 1610ee4b1..71f9d7b87 100644 --- a/src/kxos-std/src/syscall/wait4.rs +++ b/src/kxos-std/src/syscall/wait4.rs @@ -14,7 +14,7 @@ pub fn sys_wait4(wait_pid: u64, exit_status_ptr: u64, wait_options: u64) -> Sysc debug!("pid = {}", wait_pid as isize); debug!("exit_status_ptr = {}", exit_status_ptr); debug!("wait_options: {:?}", wait_options); - let process_filter = ProcessFilter::from_wait_pid(wait_pid as _); + let process_filter = ProcessFilter::from_id(wait_pid as _); let (return_pid, exit_code) = wait_child_exit(process_filter, wait_options); if return_pid != 0 && exit_status_ptr != 0 { write_val_to_user(exit_status_ptr as _, &exit_code); From 149f72e31f057d301ce2b730c6c18f7997afa28b Mon Sep 17 00:00:00 2001 From: Jianfeng Jiang Date: Wed, 2 Nov 2022 15:16:37 +0800 Subject: [PATCH 2/4] add syscall rt_procmask --- .gitattributes | 2 + src/kxos-std/src/process/signal/sig_mask.rs | 26 ++++++-- src/kxos-std/src/process/signal/sig_num.rs | 16 ++++- src/kxos-std/src/process/signal/sig_queues.rs | 2 +- src/kxos-std/src/syscall/fstat.rs | 6 +- src/kxos-std/src/syscall/kill.rs | 2 +- src/kxos-std/src/syscall/mod.rs | 10 +-- src/kxos-std/src/syscall/rt_sigprocmask.rs | 63 +++++++++++++++++++ src/kxos-std/src/syscall/writev.rs | 10 +-- src/kxos-std/src/user_apps.rs | 10 ++- src/kxos-user/signal_c/Makefile | 9 +++ src/kxos-user/signal_c/divide_zero | 3 + src/kxos-user/signal_c/divide_zero.c | 7 +++ src/kxos-user/signal_c/sig_action.c | 0 src/kxos-user/signal_c/sig_procmask | 3 + src/kxos-user/signal_c/sig_procmask.c | 19 ++++++ 16 files changed, 162 insertions(+), 26 deletions(-) create mode 100644 src/kxos-std/src/syscall/rt_sigprocmask.rs create mode 100644 src/kxos-user/signal_c/Makefile create mode 100755 src/kxos-user/signal_c/divide_zero create mode 100644 src/kxos-user/signal_c/divide_zero.c create mode 100644 src/kxos-user/signal_c/sig_action.c create mode 100755 src/kxos-user/signal_c/sig_procmask create mode 100644 src/kxos-user/signal_c/sig_procmask.c diff --git a/.gitattributes b/.gitattributes index 96915b308..39e2684c8 100644 --- a/.gitattributes +++ b/.gitattributes @@ -4,3 +4,5 @@ src/kxos-user/hello_c/hello filter=lfs diff=lfs merge=lfs -text src/kxos-user/execve/execve filter=lfs diff=lfs merge=lfs -text src/kxos-user/execve/hello filter=lfs diff=lfs merge=lfs -text src/kxos-user/fork_c/fork filter=lfs diff=lfs merge=lfs -text +src/kxos-user/signal_c/divide_zero filter=lfs diff=lfs merge=lfs -text +src/kxos-user/signal_c/sig_procmask filter=lfs diff=lfs merge=lfs -text \ No newline at end of file diff --git a/src/kxos-std/src/process/signal/sig_mask.rs b/src/kxos-std/src/process/signal/sig_mask.rs index 0b0d998f2..301cc9f90 100644 --- a/src/kxos-std/src/process/signal/sig_mask.rs +++ b/src/kxos-std/src/process/signal/sig_mask.rs @@ -5,17 +5,19 @@ pub struct SigMask { bits: u64, } -impl SigMask { - pub const fn from_u64(bits: u64) -> Self { +impl From for SigMask { + fn from(bits: u64) -> Self { SigMask { bits } } +} - pub const fn new_empty() -> Self { - SigMask::from_u64(0) +impl SigMask { + pub fn new_empty() -> Self { + SigMask::from(0u64) } - pub const fn new_full() -> Self { - SigMask::from_u64(!0) + pub fn new_full() -> Self { + SigMask::from(!0u64) } pub const fn as_u64(&self) -> u64 { @@ -30,6 +32,18 @@ impl SigMask { self.bits == !0 } + pub fn block(&mut self, block_sets: u64) { + self.bits |= block_sets; + } + + pub fn unblock(&mut self, unblock_sets: u64) { + self.bits &= !unblock_sets; + } + + pub fn set(&mut self, new_set:u64) { + self.bits = new_set; + } + pub fn count(&self) -> usize { self.bits.count_ones() as usize } diff --git a/src/kxos-std/src/process/signal/sig_num.rs b/src/kxos-std/src/process/signal/sig_num.rs index 1facf40ab..27963f9ee 100644 --- a/src/kxos-std/src/process/signal/sig_num.rs +++ b/src/kxos-std/src/process/signal/sig_num.rs @@ -1,15 +1,27 @@ use super::constants::*; +use crate::prelude::*; #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub struct SigNum { sig_num: u8, } +impl TryFrom for SigNum { + type Error = Error; + + fn try_from(sig_num: u8) -> Result { + if sig_num > MAX_RT_SIG_NUM || sig_num < MIN_STD_SIG_NUM { + return_errno_with_message!(Errno::EINVAL, "invalid signal number"); + } + Ok(SigNum { sig_num }) + } +} + impl SigNum { - // Safety: This function should only be used when signum is ensured to be valid. + /// Caller must ensure the sig_num is valid. otherweise, use try_from will check sig_num and does not panic. pub const fn from_u8(sig_num: u8) -> Self { if sig_num > MAX_RT_SIG_NUM || sig_num < MIN_STD_SIG_NUM { - unreachable!() + panic!("invalid signal number") } SigNum { sig_num } } diff --git a/src/kxos-std/src/process/signal/sig_queues.rs b/src/kxos-std/src/process/signal/sig_queues.rs index eef4db07b..7918daa8f 100644 --- a/src/kxos-std/src/process/signal/sig_queues.rs +++ b/src/kxos-std/src/process/signal/sig_queues.rs @@ -106,7 +106,7 @@ impl SigQueues { // process, they are delivered starting with the lowest-numbered // signal. (I.e., low-numbered signals have highest priority.) for signum in MIN_RT_SIG_NUM..=MAX_RT_SIG_NUM { - let signum = SigNum::from_u8(signum); + let signum = SigNum::try_from(signum).unwrap(); if blocked.contains(signum) { continue; } diff --git a/src/kxos-std/src/syscall/fstat.rs b/src/kxos-std/src/syscall/fstat.rs index 3cf237b50..1581ad7c4 100644 --- a/src/kxos-std/src/syscall/fstat.rs +++ b/src/kxos-std/src/syscall/fstat.rs @@ -5,10 +5,10 @@ use crate::prelude::*; use crate::syscall::{SyscallResult, SYS_FSTAT}; -pub fn sys_fstat(fd: u64, stat_buf_addr: Vaddr) -> SyscallResult { +pub fn sys_fstat(fd: u64, stat_buf_ptr: Vaddr) -> SyscallResult { debug!("[syscall][id={}][SYS_FSTAT]", SYS_FSTAT); debug!("fd = {}", fd); - debug!("stat_buf_addr = 0x{:x}", stat_buf_addr); + debug!("stat_buf_addr = 0x{:x}", stat_buf_ptr); let current = current!(); let vm_space = current @@ -17,7 +17,7 @@ pub fn sys_fstat(fd: u64, stat_buf_addr: Vaddr) -> SyscallResult { if fd == 1 { let stat = Stat::stdout_stat(); vm_space - .write_val(stat_buf_addr, &stat) + .write_val(stat_buf_ptr, &stat) .expect("Write value failed"); return SyscallResult::Return(0); } diff --git a/src/kxos-std/src/syscall/kill.rs b/src/kxos-std/src/syscall/kill.rs index e4af4f220..96ab2bac3 100644 --- a/src/kxos-std/src/syscall/kill.rs +++ b/src/kxos-std/src/syscall/kill.rs @@ -12,7 +12,7 @@ use super::SyscallResult; pub fn sys_kill(process_filter: u64, sig_num: u64) -> SyscallResult { debug!("[syscall][id={}][SYS_KILL]", SYS_KILL); let process_filter = ProcessFilter::from_id(process_filter as _); - let sig_num = SigNum::from_u8(sig_num as _); + let sig_num = SigNum::try_from(sig_num as u8).unwrap(); let _ = do_sys_kill(process_filter, sig_num); SyscallResult::Return(0) } diff --git a/src/kxos-std/src/syscall/mod.rs b/src/kxos-std/src/syscall/mod.rs index 64e283354..1c17291a0 100644 --- a/src/kxos-std/src/syscall/mod.rs +++ b/src/kxos-std/src/syscall/mod.rs @@ -4,6 +4,7 @@ use crate::prelude::*; use crate::syscall::clone::sys_clone; use crate::syscall::kill::sys_kill; +use crate::syscall::rt_sigprocmask::sys_rt_sigprocmask; use alloc::borrow::ToOwned; use kxos_frame::cpu::CpuContext; @@ -52,6 +53,7 @@ mod wait4; mod waitid; mod write; mod writev; +mod rt_sigprocmask; const SYS_WRITE: u64 = 1; const SYS_FSTAT: u64 = 5; @@ -133,7 +135,7 @@ pub fn syscall_dispatch( SYS_MPROTECT => sys_mprotect(args[0], args[1], args[2]), SYS_BRK => sys_brk(args[0]), SYS_RT_SIGACTION => sys_rt_sigaction(), - SYS_RT_SIGPROCMASK => sys_rt_sigprocmask(), + SYS_RT_SIGPROCMASK => sys_rt_sigprocmask(args[0] as _, args[1] as _, args[2] as _, args[3] as _), SYS_WRITEV => sys_writev(args[0], args[1], args[2]), SYS_ACCESS => sys_access(args[0] as _, args[1]), SYS_GETPID => sys_getpid(), @@ -172,12 +174,6 @@ pub fn sys_rt_sigaction() -> SyscallResult { SyscallResult::Return(0) } -pub fn sys_rt_sigprocmask() -> SyscallResult { - debug!("[syscall][id={}][SYS_RT_SIGPROCMASK]", SYS_RT_SIGPROCMASK); - warn!("TODO: rt_sigprocmask only return a fake result"); - SyscallResult::Return(0) -} - pub fn sys_getuid() -> SyscallResult { debug!("[syscall][id={}][SYS_GETUID]", SYS_GETUID); warn!("TODO: getuid only return a fake uid now"); diff --git a/src/kxos-std/src/syscall/rt_sigprocmask.rs b/src/kxos-std/src/syscall/rt_sigprocmask.rs new file mode 100644 index 000000000..2da276635 --- /dev/null +++ b/src/kxos-std/src/syscall/rt_sigprocmask.rs @@ -0,0 +1,63 @@ +use kxos_frame::vm::VmIo; + +use crate::{prelude::*, syscall::SYS_RT_SIGPROCMASK}; + +use super::SyscallResult; +pub fn sys_rt_sigprocmask(how: u32, set_ptr: Vaddr, oldset_ptr: Vaddr, sigset_size: usize) -> SyscallResult { + debug!("[syscall][id={}][SYS_RT_SIGPROCMASK]", SYS_RT_SIGPROCMASK); + let mask_op = MaskOp::try_from(how).unwrap(); + debug!("mask op = {:?}", mask_op); + debug!("set_ptr = 0x{:x}", set_ptr); + debug!("oldset_ptr = 0x{:x}", oldset_ptr); + debug!("sigset_size = {}", sigset_size); + if sigset_size != 8 { + warn!("sigset size is not equal to 8"); + } + do_rt_sigprocmask(mask_op, set_ptr, oldset_ptr, sigset_size).unwrap(); + SyscallResult::Return(0) +} + +fn do_rt_sigprocmask(mask_op: MaskOp, set_ptr: Vaddr, oldset_ptr: Vaddr, sigset_size: usize) -> Result<()>{ + let current = current!(); + let vm_space = current.vm_space().unwrap(); + let mut sig_mask = current.sig_mask().lock(); + let old_sig_mask_value = sig_mask.as_u64(); + debug!("old sig mask value: 0x{:x}", old_sig_mask_value); + if oldset_ptr != 0 { + vm_space.write_val(oldset_ptr, &old_sig_mask_value)?; + } + if set_ptr != 0 { + let new_set = vm_space.read_val::(set_ptr)?; + debug!("new set = 0x{:x}", new_set); + match mask_op { + MaskOp::Block => sig_mask.block(new_set ), + MaskOp::Unblock => sig_mask.unblock(new_set), + MaskOp::SetMask => sig_mask.set(new_set), + } + } + debug!("new set = {:x?}", &sig_mask); + + Ok(()) +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[repr(u32)] +pub enum MaskOp { + Block = 0, + Unblock = 1, + SetMask = 2, +} + +impl TryFrom for MaskOp { + type Error = Error; + + fn try_from(value: u32) -> Result { + let op = match value { + 0 => MaskOp::Block, + 1 => MaskOp::Unblock, + 2 => MaskOp::SetMask, + _ => return_errno_with_message!(Errno::EINVAL, "invalid mask op"), + }; + Ok(op) + } +} \ No newline at end of file diff --git a/src/kxos-std/src/syscall/writev.rs b/src/kxos-std/src/syscall/writev.rs index 1e66efc51..ae3c1d9f9 100644 --- a/src/kxos-std/src/syscall/writev.rs +++ b/src/kxos-std/src/syscall/writev.rs @@ -16,19 +16,19 @@ pub struct IoVec { len: usize, } -pub fn sys_writev(fd: u64, io_vec_addr: u64, io_vec_count: u64) -> SyscallResult { +pub fn sys_writev(fd: u64, io_vec_ptr: u64, io_vec_count: u64) -> SyscallResult { debug!("[syscall][id={}][SYS_WRITEV]", SYS_WRITEV); - let res = do_sys_writev(fd, io_vec_addr as Vaddr, io_vec_count as usize); + let res = do_sys_writev(fd, io_vec_ptr as Vaddr, io_vec_count as usize); SyscallResult::Return(res as _) } -pub fn do_sys_writev(fd: u64, io_vec_addr: Vaddr, io_vec_count: usize) -> usize { +pub fn do_sys_writev(fd: u64, io_vec_ptr: Vaddr, io_vec_count: usize) -> usize { debug!("fd = {}", fd); - debug!("io_vec_addr = 0x{:x}", io_vec_addr); + debug!("io_vec_ptr = 0x{:x}", io_vec_ptr); debug!("io_vec_counter = 0x{:x}", io_vec_count); let mut write_len = 0; for i in 0..io_vec_count { - let io_vec = read_val_from_user::(io_vec_addr + i * 8); + let io_vec = read_val_from_user::(io_vec_ptr + i * 8); let base = io_vec.base; let len = io_vec.len; debug!("base = 0x{:x}", base); diff --git a/src/kxos-std/src/user_apps.rs b/src/kxos-std/src/user_apps.rs index 813cd286a..f91fe1360 100644 --- a/src/kxos-std/src/user_apps.rs +++ b/src/kxos-std/src/user_apps.rs @@ -24,7 +24,7 @@ impl UserApp { } pub fn get_all_apps() -> Vec { - let mut res = Vec::new(); + let mut res = Vec::with_capacity(16); // Most simple hello world, written in assembly let app1 = UserApp::new("hello_world", read_hello_world_content()); @@ -48,6 +48,10 @@ pub fn get_all_apps() -> Vec { let app5 = UserApp::new("/fork", read_fork_c_content()); res.push(app5); + // Set sig procmask + let app6 = UserApp::new("/sig_procmask", read_sig_procmask()); + res.push(app6); + res } @@ -74,3 +78,7 @@ pub fn read_execve_hello_content() -> &'static [u8] { fn read_fork_c_content() -> &'static [u8] { include_bytes!("../../kxos-user/fork_c/fork") } + +fn read_sig_procmask() -> &'static [u8] { + include_bytes!("../../kxos-user/signal_c/sig_procmask") +} diff --git a/src/kxos-user/signal_c/Makefile b/src/kxos-user/signal_c/Makefile new file mode 100644 index 000000000..bc903b97f --- /dev/null +++ b/src/kxos-user/signal_c/Makefile @@ -0,0 +1,9 @@ +.PHONY: build clean run +build: divide_zero.c sig_procmask.c + @gcc -static divide_zero.c -o divide_zero + @gcc -static sig_procmask.c -o sig_procmask +clean: + @rm divide_zero sig_procmask +run: build + @./sig_procmask + @./divide_zero diff --git a/src/kxos-user/signal_c/divide_zero b/src/kxos-user/signal_c/divide_zero new file mode 100755 index 000000000..cad40895a --- /dev/null +++ b/src/kxos-user/signal_c/divide_zero @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:07eb07c6387a9afd68a5b8a8bba9b48e1362b9c3b8f18ce30e744640a4dfa546 +size 871776 diff --git a/src/kxos-user/signal_c/divide_zero.c b/src/kxos-user/signal_c/divide_zero.c new file mode 100644 index 000000000..15be02cfe --- /dev/null +++ b/src/kxos-user/signal_c/divide_zero.c @@ -0,0 +1,7 @@ +#include + +int main() { + int a = 2 - 2; + int b = 1 / a; + return 0; +} \ No newline at end of file diff --git a/src/kxos-user/signal_c/sig_action.c b/src/kxos-user/signal_c/sig_action.c new file mode 100644 index 000000000..e69de29bb diff --git a/src/kxos-user/signal_c/sig_procmask b/src/kxos-user/signal_c/sig_procmask new file mode 100755 index 000000000..845c7aeb7 --- /dev/null +++ b/src/kxos-user/signal_c/sig_procmask @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:6faf986f058a2480297fb323a536319f9c7dde76efe4ed0472f09a4ad2960c9b +size 871848 diff --git a/src/kxos-user/signal_c/sig_procmask.c b/src/kxos-user/signal_c/sig_procmask.c new file mode 100644 index 000000000..3cd034bf0 --- /dev/null +++ b/src/kxos-user/signal_c/sig_procmask.c @@ -0,0 +1,19 @@ +/// This code is from CSAPP +/// We use this codes to test sigprocmask +#include +#include + +int main() { + sigset_t mask, prev_mask; + sigemptyset(&mask); + sigaddset(&mask, SIGINT); + sigaddset(&mask, SIGCHLD); + + /* Block SIGINT and save previous blocked set */ + sigprocmask(SIG_BLOCK, &mask, &prev_mask); + + // Code region that will not be interrupted by SIGINT and SIGCHILD + /* Restore previous blocked set, unblocking SIGINT */ + sigprocmask(SIG_SETMASK, &prev_mask, NULL); + return 0; +} \ No newline at end of file From 288cba2832c3e0a6f5646ee4b0e4edb4d1a5d66a Mon Sep 17 00:00:00 2001 From: Jianfeng Jiang Date: Wed, 2 Nov 2022 19:35:39 +0800 Subject: [PATCH 3/4] move exception handling to kxos-std --- .gitattributes | 3 +- src/Cargo.lock | 4 +- src/kxos-frame/src/lib.rs | 2 +- src/kxos-frame/src/trap/handler.rs | 64 +++++++++++++++---- src/kxos-frame/src/trap/mod.rs | 37 +++++++++++ src/kxos-std/src/process/exception.rs | 13 ++++ src/kxos-std/src/process/mod.rs | 17 ++++- src/kxos-std/src/process/process_group.rs | 12 +++- src/kxos-std/src/process/signal/constants.rs | 46 +++++++++++++ src/kxos-std/src/process/signal/mod.rs | 15 ++++- src/kxos-std/src/process/signal/sig_mask.rs | 2 +- src/kxos-std/src/process/signal/sig_num.rs | 37 +++++++++++ .../src/process/signal/signals/fault.rs | 51 +++++++++++++++ .../src/process/signal/signals/kernel.rs | 20 ++++++ .../src/process/signal/signals/mod.rs | 2 + src/kxos-std/src/process/task.rs | 13 ++-- src/kxos-std/src/syscall/access.rs | 5 +- src/kxos-std/src/syscall/arch_prctl.rs | 22 ++++--- src/kxos-std/src/syscall/brk.rs | 9 +-- src/kxos-std/src/syscall/clone.rs | 5 +- src/kxos-std/src/syscall/execve.rs | 5 +- src/kxos-std/src/syscall/exit.rs | 6 +- src/kxos-std/src/syscall/exit_group.rs | 6 +- src/kxos-std/src/syscall/fork.rs | 6 +- src/kxos-std/src/syscall/fstat.rs | 8 +-- src/kxos-std/src/syscall/futex.rs | 5 +- src/kxos-std/src/syscall/getpid.rs | 6 +- src/kxos-std/src/syscall/gettid.rs | 6 +- src/kxos-std/src/syscall/kill.rs | 8 +-- src/kxos-std/src/syscall/mmap.rs | 6 +- src/kxos-std/src/syscall/mod.rs | 52 ++++++++------- src/kxos-std/src/syscall/mprotect.rs | 6 +- src/kxos-std/src/syscall/readlink.rs | 6 +- src/kxos-std/src/syscall/rt_sigprocmask.rs | 21 ++++-- src/kxos-std/src/syscall/sched_yield.rs | 6 +- src/kxos-std/src/syscall/tgkill.rs | 6 +- src/kxos-std/src/syscall/uname.rs | 9 +-- src/kxos-std/src/syscall/wait4.rs | 5 +- src/kxos-std/src/syscall/waitid.rs | 6 +- src/kxos-std/src/syscall/write.rs | 6 +- src/kxos-std/src/syscall/writev.rs | 6 +- src/kxos-std/src/user_apps.rs | 20 +++++- src/kxos-user/signal_c/Makefile | 7 +- src/kxos-user/signal_c/sig_action | 3 + src/kxos-user/signal_c/sig_action.c | 29 +++++++++ 45 files changed, 472 insertions(+), 157 deletions(-) create mode 100644 src/kxos-std/src/process/exception.rs create mode 100644 src/kxos-std/src/process/signal/signals/fault.rs create mode 100644 src/kxos-std/src/process/signal/signals/kernel.rs create mode 100755 src/kxos-user/signal_c/sig_action diff --git a/.gitattributes b/.gitattributes index 39e2684c8..512faf1f9 100644 --- a/.gitattributes +++ b/.gitattributes @@ -5,4 +5,5 @@ src/kxos-user/execve/execve filter=lfs diff=lfs merge=lfs -text src/kxos-user/execve/hello filter=lfs diff=lfs merge=lfs -text src/kxos-user/fork_c/fork filter=lfs diff=lfs merge=lfs -text src/kxos-user/signal_c/divide_zero filter=lfs diff=lfs merge=lfs -text -src/kxos-user/signal_c/sig_procmask filter=lfs diff=lfs merge=lfs -text \ No newline at end of file +src/kxos-user/signal_c/sig_procmask filter=lfs diff=lfs merge=lfs -text +src/kxos-user/signal_c/sig_action filter=lfs diff=lfs merge=lfs -text \ No newline at end of file diff --git a/src/Cargo.lock b/src/Cargo.lock index 6d3c457b8..1f64b119b 100644 --- a/src/Cargo.lock +++ b/src/Cargo.lock @@ -4,9 +4,9 @@ version = 3 [[package]] name = "anyhow" -version = "1.0.63" +version = "1.0.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a26fa4d7e3f2eebadf743988fc8aec9fa9a9e82611acafd77c1462ed6262440a" +checksum = "6b602bfe940d21c130f3895acd65221e8a61270debe89d628b9cb4e3ccb8569b" [[package]] name = "autocfg" diff --git a/src/kxos-frame/src/lib.rs b/src/kxos-frame/src/lib.rs index f59e5c414..be481f248 100644 --- a/src/kxos-frame/src/lib.rs +++ b/src/kxos-frame/src/lib.rs @@ -23,7 +23,7 @@ pub mod prelude; pub mod sync; pub mod task; pub mod timer; -pub(crate) mod trap; +pub mod trap; pub mod user; mod util; #[macro_use] diff --git a/src/kxos-frame/src/trap/handler.rs b/src/kxos-frame/src/trap/handler.rs index d7e30cee1..c6fbf5cbc 100644 --- a/src/kxos-frame/src/trap/handler.rs +++ b/src/kxos-frame/src/trap/handler.rs @@ -19,24 +19,29 @@ pub(crate) extern "C" fn syscall_handler(f: &'static mut SyscallFrame) -> isize -1 } -const DIVIDE_BY_ZERO: usize = 0; -const INVALID_OPCODE: usize = 6; -const SEGMENT_NOT_PRESENT: usize = 11; -const STACK_SEGMENT_FAULT: usize = 12; -const GENERAL_PROTECTION_FAULT: usize = 13; -const PAGE_FAULT: usize = 14; -const TIMER: usize = 32; - #[no_mangle] pub(crate) extern "C" fn trap_handler(f: &'static mut TrapFrame) { if !is_from_kernel(f.cs) { let current = Task::current(); current.inner_exclusive_access().is_from_trap = true; - } - let irq_line = IRQ_LIST.get(f.id as usize).unwrap(); - let callback_functions = irq_line.callback_list(); - for callback_function in callback_functions.iter() { - callback_function.call(f.clone()); + *current.trap_frame() = *SWITCH_TO_USER_SPACE_TASK.trap_frame(); + if is_cpu_fault(current.trap_frame()) { + // if is cpu fault, we will pass control to trap handler in kxos std + unsafe { + context_switch( + get_idle_task_cx_ptr() as *mut TaskContext, + &Task::current().inner_ctx() as *const TaskContext, + ) + } + } else { + let irq_line = IRQ_LIST.get(f.id as usize).unwrap(); + let callback_functions = irq_line.callback_list(); + for callback_function in callback_functions.iter() { + callback_function.call(f.clone()); + } + } + } else { + panic!("cannot handle kernel exception now"); } } @@ -47,3 +52,36 @@ fn is_from_kernel(cs: u64) -> bool { false } } + +/// As Osdev Wiki defines(https://wiki.osdev.org/Exceptions): +/// CPU exceptions are classified as: + +/// Faults: These can be corrected and the program may continue as if nothing happened. +/// Traps: Traps are reported immediately after the execution of the trapping instruction. +/// Aborts: Some severe unrecoverable error. + +/// This function will determine a trap is a CPU faults. +/// We will pass control to kxos-std if the trap is **faults**. +pub fn is_cpu_fault(trap_frame: &TrapFrame) -> bool { + match trap_frame.id { + DIVIDE_BY_ZERO + | DEBUG + | BOUND_RANGE_EXCEEDED + | INVALID_OPCODE + | DEVICE_NOT_AVAILABLE + | INVAILD_TSS + | SEGMENT_NOT_PRESENT + | STACK_SEGMENT_FAULT + | GENERAL_PROTECTION_FAULT + | PAGE_FAULT + | X87_FLOATING_POINT_EXCEPTION + | ALIGNMENT_CHECK + | SIMD_FLOATING_POINT_EXCEPTION + | VIRTUALIZATION_EXCEPTION + | CONTROL_PROTECTION_EXCEPTION + | HYPERVISOR_INJECTION_EXCEPTION + | VMM_COMMUNICATION_EXCEPTION + | SECURITY_EXCEPTION => true, + _ => false, + } +} diff --git a/src/kxos-frame/src/trap/mod.rs b/src/kxos-frame/src/trap/mod.rs index 1d3ebf954..453cb151f 100644 --- a/src/kxos-frame/src/trap/mod.rs +++ b/src/kxos-frame/src/trap/mod.rs @@ -144,3 +144,40 @@ pub(crate) fn init() { }) } } + +macro_rules! define_cpu_exception { + ( $( $name: ident = $exception_num: expr ),* ) => { + $( + pub const $name : u64 = $exception_num; + )* + } +} + +define_cpu_exception!( + DIVIDE_BY_ZERO = 0, + DEBUG = 1, + NON_MASKABLE_INTERRUPT = 2, + BREAKPOINT = 3, + OVERFLOW = 4, + BOUND_RANGE_EXCEEDED = 5, + INVALID_OPCODE = 6, + DEVICE_NOT_AVAILABLE = 7, + DOUBLE_FAULT = 8, + COPROCESSOR_SEGMENT_OVERRUN = 9, + INVAILD_TSS = 10, + SEGMENT_NOT_PRESENT = 11, + STACK_SEGMENT_FAULT = 12, + GENERAL_PROTECTION_FAULT = 13, + PAGE_FAULT = 14, + // 15 reserved + X87_FLOATING_POINT_EXCEPTION = 16, + ALIGNMENT_CHECK = 17, + MACHINE_CHECK = 18, + SIMD_FLOATING_POINT_EXCEPTION = 19, + VIRTUALIZATION_EXCEPTION = 20, + CONTROL_PROTECTION_EXCEPTION = 21, + // 22-27 reserved + HYPERVISOR_INJECTION_EXCEPTION = 28, + VMM_COMMUNICATION_EXCEPTION = 29, + SECURITY_EXCEPTION = 30 // 31 reserved +); diff --git a/src/kxos-std/src/process/exception.rs b/src/kxos-std/src/process/exception.rs new file mode 100644 index 000000000..86cd1a4ca --- /dev/null +++ b/src/kxos-std/src/process/exception.rs @@ -0,0 +1,13 @@ +use kxos_frame::cpu::CpuContext; + +use crate::{prelude::*, process::signal::signals::fault::FaultSignal}; + +/// We can't handle most exceptions, just send self a signal to force the process exit before return to user space. +pub fn handle_exception(context: &mut CpuContext) { + let trap_info = context.trap_information.clone(); + let current = current!(); + let pid = current.pid(); + debug!("trap info = {:x?}", trap_info); + let signal = Box::new(FaultSignal::new(&trap_info)); + current.sig_queues().lock().enqueue(signal); +} diff --git a/src/kxos-std/src/process/mod.rs b/src/kxos-std/src/process/mod.rs index b34fca73c..05187c07d 100644 --- a/src/kxos-std/src/process/mod.rs +++ b/src/kxos-std/src/process/mod.rs @@ -9,14 +9,17 @@ use self::process_group::ProcessGroup; use self::process_vm::mmap_area::MmapArea; use self::process_vm::user_heap::UserHeap; use self::process_vm::UserVm; +use self::signal::constants::SIGCHLD; use self::signal::sig_disposition::SigDispositions; use self::signal::sig_mask::SigMask; use self::signal::sig_queues::SigQueues; +use self::signal::signals::kernel::KernelSignal; use self::status::ProcessStatus; use self::task::create_user_task_from_elf; pub mod clone; pub mod elf; +pub mod exception; pub mod fifo_scheduler; pub mod process_filter; pub mod process_group; @@ -272,8 +275,11 @@ impl Process { } } - // wake up parent waiting children, if any if let Some(parent) = current_process.parent() { + // set parent sig child + let signal = Box::new(KernelSignal::new(SIGCHLD)); + parent.sig_queues().lock().enqueue(signal); + // wake up parent waiting children, if any parent .waiting_children() .wake_all_on_condition(¤t_process.pid(), |filter, pid| { @@ -341,12 +347,17 @@ impl Process { None } - /// free zombie child with pid, returns the exit code of child process - /// We current just remove the child from the children map. + /// free zombie child with pid, returns the exit code of child process. + /// remove process from process group. pub fn reap_zombie_child(&self, pid: Pid) -> i32 { let child_process = self.children.lock().remove(&pid).unwrap(); assert!(child_process.status().lock().is_zombie()); table::remove_process(child_process.pid()); + if let Some(process_group) = child_process.process_group().lock().as_ref() { + if let Some(process_group) = process_group.upgrade() { + process_group.remove_process(child_process.pid); + } + } child_process.exit_code() } diff --git a/src/kxos-std/src/process/process_group.rs b/src/kxos-std/src/process/process_group.rs index 8444fe683..1a422f692 100644 --- a/src/kxos-std/src/process/process_group.rs +++ b/src/kxos-std/src/process/process_group.rs @@ -1,4 +1,4 @@ -use super::{Pgid, Pid, Process}; +use super::{table, Pgid, Pid, Process}; use crate::prelude::*; pub struct ProcessGroup { @@ -44,7 +44,15 @@ impl ProcessGroup { } pub fn remove_process(&self, pid: Pid) { - self.inner.lock().processes.remove(&pid); + let mut inner_lock = self.inner.lock(); + inner_lock.processes.remove(&pid); + let len = inner_lock.processes.len(); + let pgid = inner_lock.pgid; + // if self contains no process, remove self from table + if len == 0 { + // this must be the last statement + table::remove_process_group(pgid); + } } pub fn pgid(&self) -> Pgid { diff --git a/src/kxos-std/src/process/signal/constants.rs b/src/kxos-std/src/process/signal/constants.rs index 7f2a3752c..9c4593e1a 100644 --- a/src/kxos-std/src/process/signal/constants.rs +++ b/src/kxos-std/src/process/signal/constants.rs @@ -55,3 +55,49 @@ define_std_signums! { SIGPWR = 30, // Power failure (System V) SIGSYS = 31, // Bad system call (SVr4); see also seccomp(2) } + +pub const SI_ASYNCNL: i32 = -60; +pub const SI_TKILL: i32 = -6; +pub const SI_SIGIO: i32 = -5; +pub const SI_ASYNCIO: i32 = -4; +pub const SI_MESGQ: i32 = -3; +pub const SI_TIMER: i32 = -2; +pub const SI_QUEUE: i32 = -1; +pub const SI_USER: i32 = 0; +pub const SI_KERNEL: i32 = 128; + +pub const FPE_INTDIV: i32 = 1; +pub const FPE_INTOVF: i32 = 2; +pub const FPE_FLTDIV: i32 = 3; +pub const FPE_FLTOVF: i32 = 4; +pub const FPE_FLTUND: i32 = 5; +pub const FPE_FLTRES: i32 = 6; +pub const FPE_FLTINV: i32 = 7; +pub const FPE_FLTSUB: i32 = 8; + +pub const ILL_ILLOPC: i32 = 1; +pub const ILL_ILLOPN: i32 = 2; +pub const ILL_ILLADR: i32 = 3; +pub const ILL_ILLTRP: i32 = 4; +pub const ILL_PRVOPC: i32 = 5; +pub const ILL_PRVREG: i32 = 6; +pub const ILL_COPROC: i32 = 7; +pub const ILL_BADSTK: i32 = 8; + +pub const SEGV_MAPERR: i32 = 1; +pub const SEGV_ACCERR: i32 = 2; +pub const SEGV_BNDERR: i32 = 3; +pub const SEGV_PKUERR: i32 = 4; + +pub const BUS_ADRALN: i32 = 1; +pub const BUS_ADRERR: i32 = 2; +pub const BUS_OBJERR: i32 = 3; +pub const BUS_MCEERR_AR: i32 = 4; +pub const BUS_MCEERR_AO: i32 = 5; + +pub const CLD_EXITED: i32 = 1; +pub const CLD_KILLED: i32 = 2; +pub const CLD_DUMPED: i32 = 3; +pub const CLD_TRAPPED: i32 = 4; +pub const CLD_STOPPED: i32 = 5; +pub const CLD_CONTINUED: i32 = 6; diff --git a/src/kxos-std/src/process/signal/mod.rs b/src/kxos-std/src/process/signal/mod.rs index 2743e79b3..bacf7daab 100644 --- a/src/kxos-std/src/process/signal/mod.rs +++ b/src/kxos-std/src/process/signal/mod.rs @@ -6,6 +6,8 @@ pub mod sig_num; pub mod sig_queues; pub mod signals; +use kxos_frame::task::Task; + use crate::{ prelude::*, process::signal::sig_action::{SigAction, SigDefaultAction}, @@ -14,13 +16,16 @@ use crate::{ /// Handle pending signal for current process pub fn handle_pending_signal() { let current = current!(); + let pid = current.pid(); + let process_name = current.filename().unwrap(); let sig_queues = current.sig_queues(); let mut sig_queues_guard = sig_queues.lock(); let sig_mask = current.sig_mask().lock().clone(); if let Some(signal) = sig_queues_guard.dequeue(&sig_mask) { let sig_num = signal.num(); - debug!("sig_num = {:?}", sig_num); + debug!("sig_num = {:?}, sig_name = {}", sig_num, sig_num.sig_name()); let sig_action = current.sig_dispositions().lock().get(sig_num); + debug!("sig action: {:?}", sig_action); match sig_action { SigAction::Ign => { debug!("Ignore signal {:?}", sig_num); @@ -28,10 +33,18 @@ pub fn handle_pending_signal() { SigAction::User { .. } => todo!(), SigAction::Dfl => { let sig_default_action = SigDefaultAction::from_signum(sig_num); + debug!("sig_default_action: {:?}", sig_default_action); match sig_default_action { SigDefaultAction::Core | SigDefaultAction::Term => { + error!( + "{:?}: terminating on signal {}", + process_name, + sig_num.sig_name() + ); // FIXME: How to set correct status if process is terminated current.exit(1); + // We should exit current here, since we cannot restore a valid status from trap now. + Task::current().exit(); } SigDefaultAction::Ign => {} SigDefaultAction::Stop => { diff --git a/src/kxos-std/src/process/signal/sig_mask.rs b/src/kxos-std/src/process/signal/sig_mask.rs index 301cc9f90..d80f971bc 100644 --- a/src/kxos-std/src/process/signal/sig_mask.rs +++ b/src/kxos-std/src/process/signal/sig_mask.rs @@ -40,7 +40,7 @@ impl SigMask { self.bits &= !unblock_sets; } - pub fn set(&mut self, new_set:u64) { + pub fn set(&mut self, new_set: u64) { self.bits = new_set; } diff --git a/src/kxos-std/src/process/signal/sig_num.rs b/src/kxos-std/src/process/signal/sig_num.rs index 27963f9ee..2c7329fc0 100644 --- a/src/kxos-std/src/process/signal/sig_num.rs +++ b/src/kxos-std/src/process/signal/sig_num.rs @@ -37,4 +37,41 @@ impl SigNum { pub fn is_real_time(&self) -> bool { self.sig_num >= MIN_RT_SIG_NUM } + + pub const fn sig_name(&self) -> &'static str { + match *self { + SIGHUP => "SIGHUP", + SIGINT => "SIGINT", + SIGQUIT => "SIGQUIT", + SIGILL => "SIGILL", + SIGTRAP => "SIGTRAP", + SIGABRT => "SIGABRT", + SIGBUS => "SIGBUS", + SIGFPE => "SIGFPE", + SIGKILL => "SIGKILL", + SIGUSR1 => "SIGUSR1", + SIGSEGV => "SIGSEGV", + SIGUSR2 => "SIGUSR2", + SIGPIPE => "SIGPIPE", + SIGALRM => "SIGALRM", + SIGTERM => "SIGTERM", + SIGSTKFLT => "SIGSTKFLT", + SIGCHLD => "SIGCHLD", + SIGCONT => "SIGCONT", + SIGSTOP => "SIGSTOP", + SIGTSTP => "SIGTSTP", + SIGTTIN => "SIGTTIN", + SIGTTOU => "SIGTTOU", + SIGURG => "SIGURG", + SIGXCPU => "SIGXCPU", + SIGXFSZ => "SIGXFSZ", + SIGVTALRM => "SIGVTALRM", + SIGPROF => "SIGPROF", + SIGWINCH => "SIGWINCH", + SIGIO => "SIGIO", + SIGPWR => "SIGPWR", + SIGSYS => "SIGSYS", + _ => "Realtime Signal", + } + } } diff --git a/src/kxos-std/src/process/signal/signals/fault.rs b/src/kxos-std/src/process/signal/signals/fault.rs new file mode 100644 index 000000000..71477cb65 --- /dev/null +++ b/src/kxos-std/src/process/signal/signals/fault.rs @@ -0,0 +1,51 @@ +use kxos_frame::cpu::TrapInformation; +use kxos_frame::trap::{ + ALIGNMENT_CHECK, BOUND_RANGE_EXCEEDED, DIVIDE_BY_ZERO, GENERAL_PROTECTION_FAULT, + INVALID_OPCODE, PAGE_FAULT, SIMD_FLOATING_POINT_EXCEPTION, X87_FLOATING_POINT_EXCEPTION, +}; + +use crate::prelude::*; +use crate::process::signal::constants::*; +use crate::process::signal::sig_num::SigNum; + +use super::Signal; +#[derive(Debug, Clone, Copy, PartialEq)] +pub struct FaultSignal { + num: SigNum, + code: i32, + addr: Option, +} + +impl FaultSignal { + pub fn new(trap_info: &TrapInformation) -> FaultSignal { + debug!("Trap id: {}", trap_info.id); + let (num, code, addr) = match trap_info.id { + DIVIDE_BY_ZERO => (SIGFPE, FPE_INTDIV, None), + X87_FLOATING_POINT_EXCEPTION | SIMD_FLOATING_POINT_EXCEPTION => { + (SIGFPE, FPE_FLTDIV, None) + } + BOUND_RANGE_EXCEEDED => (SIGSEGV, SEGV_BNDERR, None), + ALIGNMENT_CHECK => (SIGBUS, BUS_ADRALN, None), + INVALID_OPCODE => (SIGILL, ILL_ILLOPC, None), + GENERAL_PROTECTION_FAULT => (SIGBUS, BUS_ADRERR, None), + PAGE_FAULT => { + const PF_ERR_FLAG_PRESENT: u64 = 1u64 << 0; + let code = if trap_info.err & PF_ERR_FLAG_PRESENT != 0 { + SEGV_ACCERR + } else { + SEGV_MAPERR + }; + let addr = Some(trap_info.cr2); + (SIGSEGV, code, addr) + } + _ => panic!("Exception cannnot be a signal"), + }; + FaultSignal { num, code, addr } + } +} + +impl Signal for FaultSignal { + fn num(&self) -> SigNum { + self.num + } +} diff --git a/src/kxos-std/src/process/signal/signals/kernel.rs b/src/kxos-std/src/process/signal/signals/kernel.rs new file mode 100644 index 000000000..c0cec7527 --- /dev/null +++ b/src/kxos-std/src/process/signal/signals/kernel.rs @@ -0,0 +1,20 @@ +use crate::process::signal::sig_num::SigNum; + +use super::Signal; + +#[derive(Debug, Clone, Copy, PartialEq)] +pub struct KernelSignal { + num: SigNum, +} + +impl KernelSignal { + pub const fn new(num: SigNum) -> Self { + Self { num } + } +} + +impl Signal for KernelSignal { + fn num(&self) -> SigNum { + self.num + } +} diff --git a/src/kxos-std/src/process/signal/signals/mod.rs b/src/kxos-std/src/process/signal/signals/mod.rs index 064f1c127..71452ea2b 100644 --- a/src/kxos-std/src/process/signal/signals/mod.rs +++ b/src/kxos-std/src/process/signal/signals/mod.rs @@ -1,3 +1,5 @@ +pub mod fault; +pub mod kernel; pub mod user; use core::fmt::Debug; diff --git a/src/kxos-std/src/process/task.rs b/src/kxos-std/src/process/task.rs index 286e4eea6..8c6b886d9 100644 --- a/src/kxos-std/src/process/task.rs +++ b/src/kxos-std/src/process/task.rs @@ -7,9 +7,12 @@ use kxos_frame::{ vm::VmSpace, }; -use crate::{prelude::*, process::signal::handle_pending_signal}; +use crate::{ + prelude::*, + process::{exception::handle_exception, signal::handle_pending_signal}, +}; -use crate::syscall::syscall_handler; +use crate::syscall::handle_syscall; use super::{elf::load_elf_to_vm_space, Process}; @@ -56,6 +59,7 @@ pub fn create_new_task(userspace: Arc, parent: Weak) -> Arc< } handle_pending_signal(); if current.status().lock().is_zombie() { + debug!("exit due to signal"); break; } // If current is suspended, wait for a signal to wake up self @@ -65,6 +69,7 @@ pub fn create_new_task(userspace: Arc, parent: Weak) -> Arc< handle_pending_signal(); } } + debug!("exit user loop"); } Task::new(user_task_entry, parent, Some(userspace)).expect("spawn task failed") @@ -72,8 +77,8 @@ pub fn create_new_task(userspace: Arc, parent: Weak) -> Arc< fn handle_user_event(user_event: UserEvent, context: &mut CpuContext) { match user_event { - UserEvent::Syscall => syscall_handler(context), + UserEvent::Syscall => handle_syscall(context), UserEvent::Fault => todo!(), - UserEvent::Exception => todo!(), + UserEvent::Exception => handle_exception(context), } } diff --git a/src/kxos-std/src/syscall/access.rs b/src/kxos-std/src/syscall/access.rs index 452fb65e9..cc066ecb1 100644 --- a/src/kxos-std/src/syscall/access.rs +++ b/src/kxos-std/src/syscall/access.rs @@ -1,13 +1,12 @@ use super::constants::*; -use super::SyscallResult; use crate::{memory::read_bytes_from_user, prelude::*, syscall::SYS_ACCESS}; -pub fn sys_access(filename_ptr: Vaddr, file_mode: u64) -> SyscallResult { +pub fn sys_access(filename_ptr: Vaddr, file_mode: u64) -> Result { debug!("[syscall][id={}][SYS_ACCESS]", SYS_ACCESS); let mut filename_buffer = vec![0u8; MAX_FILENAME_LEN]; read_bytes_from_user(filename_ptr, &mut filename_buffer); let filename = CString::from(CStr::from_bytes_until_nul(&filename_buffer).unwrap()); debug!("filename: {:?}", filename); warn!("access currenly does not check and just return success"); - SyscallResult::Return(0) + Ok(0) } diff --git a/src/kxos-std/src/syscall/arch_prctl.rs b/src/kxos-std/src/syscall/arch_prctl.rs index 09accf2a4..8aeccbcb2 100644 --- a/src/kxos-std/src/syscall/arch_prctl.rs +++ b/src/kxos-std/src/syscall/arch_prctl.rs @@ -1,7 +1,7 @@ use kxos_frame::cpu::CpuContext; use crate::prelude::*; -use crate::syscall::{SyscallResult, SYS_ARCH_PRCTL}; +use crate::syscall::SYS_ARCH_PRCTL; #[allow(non_camel_case_types)] #[derive(Debug)] @@ -26,17 +26,19 @@ impl TryFrom for ArchPrctlCode { } } -pub fn sys_arch_prctl(code: u64, addr: u64, context: &mut CpuContext) -> SyscallResult { +pub fn sys_arch_prctl(code: u64, addr: u64, context: &mut CpuContext) -> Result { debug!("[syscall][id={}][SYS_ARCH_PRCTL]", SYS_ARCH_PRCTL); - let arch_prctl_code = ArchPrctlCode::try_from(code); + let arch_prctl_code = ArchPrctlCode::try_from(code)?; debug!("arch_prctl_code: {:?}", arch_prctl_code); - match arch_prctl_code { - Err(_) => SyscallResult::Return(-1), - Ok(code) => { - let res = do_arch_prctl(code, addr, context).unwrap(); - SyscallResult::Return(res as _) - } - } + let res = do_arch_prctl(arch_prctl_code, addr, context).unwrap(); + Ok(res as _) + // match arch_prctl_code { + // Err(_) => SyscallResult::Return(-1), + // Ok(code) => { + // let res = do_arch_prctl(code, addr, context).unwrap(); + // SyscallResult::Return(res as _) + // } + // } } pub fn do_arch_prctl(code: ArchPrctlCode, addr: u64, context: &mut CpuContext) -> Result { diff --git a/src/kxos-std/src/syscall/brk.rs b/src/kxos-std/src/syscall/brk.rs index 906570377..b9dd71e53 100644 --- a/src/kxos-std/src/syscall/brk.rs +++ b/src/kxos-std/src/syscall/brk.rs @@ -1,12 +1,9 @@ use crate::prelude::*; -use crate::{ - process::Process, - syscall::{SyscallResult, SYS_BRK}, -}; +use crate::{process::Process, syscall::SYS_BRK}; /// expand the user heap to new heap end, returns the new heap end if expansion succeeds. -pub fn sys_brk(heap_end: u64) -> SyscallResult { +pub fn sys_brk(heap_end: u64) -> Result { debug!("[syscall][id={}][SYS_BRK]", SYS_BRK); let current = Process::current(); let new_heap_end = if heap_end == 0 { @@ -23,5 +20,5 @@ pub fn sys_brk(heap_end: u64) -> SyscallResult { .expect("brk should work on process with user space"); let new_heap_end = user_heap.brk(new_heap_end, vm_space); - SyscallResult::Return(new_heap_end as _) + Ok(new_heap_end as _) } diff --git a/src/kxos-std/src/syscall/clone.rs b/src/kxos-std/src/syscall/clone.rs index f52fbefc1..e60b0b4bf 100644 --- a/src/kxos-std/src/syscall/clone.rs +++ b/src/kxos-std/src/syscall/clone.rs @@ -1,6 +1,5 @@ use kxos_frame::cpu::CpuContext; -use super::SyscallResult; use crate::process::clone::{clone_child, CloneArgs, CloneFlags}; use crate::{prelude::*, syscall::SYS_CLONE}; @@ -13,7 +12,7 @@ pub fn sys_clone( child_tidptr: Vaddr, tls: usize, parent_context: CpuContext, -) -> SyscallResult { +) -> Result { debug!("[syscall][id={}][SYS_CLONE]", SYS_CLONE); debug!("flags = {}", clone_flags); let clone_flags = CloneFlags::from(clone_flags); @@ -29,5 +28,5 @@ pub fn sys_clone( debug!("*********schedule child process, pid = {}**********", pid); child_process.send_to_scheduler(); debug!("*********return to parent process, pid = {}*********", pid); - SyscallResult::Return(child_pid as _) + Ok(child_pid as _) } diff --git a/src/kxos-std/src/syscall/execve.rs b/src/kxos-std/src/syscall/execve.rs index fb2f6e1d1..240dbff2f 100644 --- a/src/kxos-std/src/syscall/execve.rs +++ b/src/kxos-std/src/syscall/execve.rs @@ -1,7 +1,6 @@ use kxos_frame::cpu::CpuContext; use super::constants::*; -use super::SyscallResult; use crate::process::elf::load_elf_to_vm_space; use crate::{memory::read_bytes_from_user, prelude::*, process::Process, syscall::SYS_EXECVE}; @@ -10,7 +9,7 @@ pub fn sys_execve( argv_ptr_ptr: Vaddr, envp_ptr_ptr: Vaddr, context: &mut CpuContext, -) -> SyscallResult { +) -> Result { debug!("[syscall][id={}][SYS_EXECVE]", SYS_EXECVE); let mut filename_buffer = vec![0u8; MAX_FILENAME_LEN]; read_bytes_from_user(filename_ptr, &mut filename_buffer); @@ -47,5 +46,5 @@ pub fn sys_execve( // set new user stack top context.gp_regs.rsp = elf_load_info.user_stack_top(); debug!("user stack top: 0x{:x}", elf_load_info.user_stack_top()); - SyscallResult::Return(0) + Ok(0) } diff --git a/src/kxos-std/src/syscall/exit.rs b/src/kxos-std/src/syscall/exit.rs index 3d0682ff6..3c8a11c0c 100644 --- a/src/kxos-std/src/syscall/exit.rs +++ b/src/kxos-std/src/syscall/exit.rs @@ -2,10 +2,8 @@ use crate::prelude::*; use crate::syscall::SYS_EXIT; -use super::SyscallResult; - -pub fn sys_exit(exit_code: i32) -> SyscallResult { +pub fn sys_exit(exit_code: i32) -> Result { debug!("[syscall][id={}][SYS_EXIT]", SYS_EXIT); current!().exit(exit_code); - SyscallResult::NotReturn + Ok(0) } diff --git a/src/kxos-std/src/syscall/exit_group.rs b/src/kxos-std/src/syscall/exit_group.rs index 1ac7bd7cb..0d8ee732a 100644 --- a/src/kxos-std/src/syscall/exit_group.rs +++ b/src/kxos-std/src/syscall/exit_group.rs @@ -1,9 +1,9 @@ use crate::prelude::*; -use crate::syscall::{SyscallResult, SYS_EXIT_GROUP}; +use crate::syscall::SYS_EXIT_GROUP; -pub fn sys_exit_group(exit_code: u64) -> SyscallResult { +pub fn sys_exit_group(exit_code: u64) -> Result { debug!("[syscall][id={}][SYS_EXIT_GROUP]", SYS_EXIT_GROUP); current!().exit(exit_code as _); - SyscallResult::NotReturn + Ok(0) } diff --git a/src/kxos-std/src/syscall/fork.rs b/src/kxos-std/src/syscall/fork.rs index 6a8ac24d5..37fe5961b 100644 --- a/src/kxos-std/src/syscall/fork.rs +++ b/src/kxos-std/src/syscall/fork.rs @@ -6,12 +6,10 @@ use kxos_frame::cpu::CpuContext; use crate::{process::Process, syscall::SYS_FORK}; -use super::SyscallResult; - -pub fn sys_fork(parent_context: CpuContext) -> SyscallResult { +pub fn sys_fork(parent_context: CpuContext) -> Result { debug!("[syscall][id={}][SYS_FORK]", SYS_FORK); let child_process = fork(parent_context); - SyscallResult::Return(child_process.pid() as _) + Ok(child_process.pid() as _) } /// Fork a child process diff --git a/src/kxos-std/src/syscall/fstat.rs b/src/kxos-std/src/syscall/fstat.rs index 1581ad7c4..934e7cac9 100644 --- a/src/kxos-std/src/syscall/fstat.rs +++ b/src/kxos-std/src/syscall/fstat.rs @@ -3,9 +3,9 @@ use kxos_frame::vm::VmIo; use crate::fs::stat::Stat; use crate::prelude::*; -use crate::syscall::{SyscallResult, SYS_FSTAT}; +use crate::syscall::SYS_FSTAT; -pub fn sys_fstat(fd: u64, stat_buf_ptr: Vaddr) -> SyscallResult { +pub fn sys_fstat(fd: u64, stat_buf_ptr: Vaddr) -> Result { debug!("[syscall][id={}][SYS_FSTAT]", SYS_FSTAT); debug!("fd = {}", fd); debug!("stat_buf_addr = 0x{:x}", stat_buf_ptr); @@ -19,8 +19,8 @@ pub fn sys_fstat(fd: u64, stat_buf_ptr: Vaddr) -> SyscallResult { vm_space .write_val(stat_buf_ptr, &stat) .expect("Write value failed"); - return SyscallResult::Return(0); + return Ok(0); } warn!("TODO: fstat only returns fake result now."); - SyscallResult::Return(0) + Ok(0) } diff --git a/src/kxos-std/src/syscall/futex.rs b/src/kxos-std/src/syscall/futex.rs index 9f4aa452a..b71f153e4 100644 --- a/src/kxos-std/src/syscall/futex.rs +++ b/src/kxos-std/src/syscall/futex.rs @@ -1,6 +1,5 @@ use crate::{memory::read_val_from_user, syscall::SYS_FUTEX}; -use super::SyscallResult; use crate::prelude::*; use kxos_frame::{cpu::num_cpus, sync::WaitQueue}; @@ -18,7 +17,7 @@ pub fn sys_futex( utime_addr: u64, futex_new_addr: u64, bitset: u64, -) -> SyscallResult { +) -> Result { debug!("[syscall][id={}][SYS_FUTEX]", SYS_FUTEX); // FIXME: we current ignore futex flags let (futex_op, futex_flags) = futex_op_and_flags_from_u32(futex_op as _).unwrap(); @@ -70,7 +69,7 @@ pub fn sys_futex( } .unwrap(); - SyscallResult::Return(res as _) + Ok(res as _) } /// do futex wait diff --git a/src/kxos-std/src/syscall/getpid.rs b/src/kxos-std/src/syscall/getpid.rs index 136760824..1b5ab04d6 100644 --- a/src/kxos-std/src/syscall/getpid.rs +++ b/src/kxos-std/src/syscall/getpid.rs @@ -2,11 +2,9 @@ use crate::prelude::*; use crate::{process::Process, syscall::SYS_GETPID}; -use super::SyscallResult; - -pub fn sys_getpid() -> SyscallResult { +pub fn sys_getpid() -> Result { debug!("[syscall][id={}][SYS_GETPID]", SYS_GETPID); let pid = Process::current().pid(); info!("[sys_getpid]: pid = {}", pid); - SyscallResult::Return(pid as _) + Ok(pid as _) } diff --git a/src/kxos-std/src/syscall/gettid.rs b/src/kxos-std/src/syscall/gettid.rs index 1f5b7bd7d..c1d8e9622 100644 --- a/src/kxos-std/src/syscall/gettid.rs +++ b/src/kxos-std/src/syscall/gettid.rs @@ -2,11 +2,9 @@ use crate::prelude::*; use crate::{process::Process, syscall::SYS_GETTID}; -use super::SyscallResult; - -pub fn sys_gettid() -> SyscallResult { +pub fn sys_gettid() -> Result { debug!("[syscall][id={}][SYS_GETTID]", SYS_GETTID); // For single-thread process, tid is equal to pid let tid = Process::current().pid(); - SyscallResult::Return(tid as _) + Ok(tid as _) } diff --git a/src/kxos-std/src/syscall/kill.rs b/src/kxos-std/src/syscall/kill.rs index 96ab2bac3..90e347c4e 100644 --- a/src/kxos-std/src/syscall/kill.rs +++ b/src/kxos-std/src/syscall/kill.rs @@ -7,14 +7,12 @@ use crate::{ syscall::SYS_KILL, }; -use super::SyscallResult; - -pub fn sys_kill(process_filter: u64, sig_num: u64) -> SyscallResult { +pub fn sys_kill(process_filter: u64, sig_num: u64) -> Result { debug!("[syscall][id={}][SYS_KILL]", SYS_KILL); let process_filter = ProcessFilter::from_id(process_filter as _); let sig_num = SigNum::try_from(sig_num as u8).unwrap(); - let _ = do_sys_kill(process_filter, sig_num); - SyscallResult::Return(0) + do_sys_kill(process_filter, sig_num)?; + Ok(0) } pub fn do_sys_kill(process_filter: ProcessFilter, sig_num: SigNum) -> Result<()> { diff --git a/src/kxos-std/src/syscall/mmap.rs b/src/kxos-std/src/syscall/mmap.rs index 64fad283b..073862b82 100644 --- a/src/kxos-std/src/syscall/mmap.rs +++ b/src/kxos-std/src/syscall/mmap.rs @@ -6,8 +6,6 @@ use kxos_frame::vm::VmPerm; use crate::{process::Process, syscall::SYS_MMAP}; -use super::SyscallResult; - pub fn sys_mmap( addr: u64, len: u64, @@ -15,7 +13,7 @@ pub fn sys_mmap( flags: u64, fd: u64, offset: u64, -) -> SyscallResult { +) -> Result { debug!("[syscall][id={}][SYS_MMAP]", SYS_MMAP); let perms = VmPerm::try_from(perms).unwrap(); let flags = MMapFlags::try_from(flags).unwrap(); @@ -27,7 +25,7 @@ pub fn sys_mmap( fd as usize, offset as usize, ); - SyscallResult::Return(res as _) + Ok(res as _) } pub fn do_sys_mmap( diff --git a/src/kxos-std/src/syscall/mod.rs b/src/kxos-std/src/syscall/mod.rs index 1c17291a0..bf62fa450 100644 --- a/src/kxos-std/src/syscall/mod.rs +++ b/src/kxos-std/src/syscall/mod.rs @@ -46,6 +46,7 @@ mod kill; mod mmap; mod mprotect; mod readlink; +mod rt_sigprocmask; mod sched_yield; mod tgkill; mod uname; @@ -53,7 +54,6 @@ mod wait4; mod waitid; mod write; mod writev; -mod rt_sigprocmask; const SYS_WRITE: u64 = 1; const SYS_FSTAT: u64 = 5; @@ -90,11 +90,6 @@ pub struct SyscallArgument { args: [u64; 6], } -pub enum SyscallResult { - Return(i32), - NotReturn, -} - impl SyscallArgument { fn new_from_context(context: &CpuContext) -> Self { let syscall_number = context.gp_regs.rax; @@ -112,22 +107,31 @@ impl SyscallArgument { } } -pub fn syscall_handler(context: &mut CpuContext) { +pub fn handle_syscall(context: &mut CpuContext) { let syscall_frame = SyscallArgument::new_from_context(context); let syscall_return = syscall_dispatch(syscall_frame.syscall_number, syscall_frame.args, context); - if let SyscallResult::Return(return_value) = syscall_return { - // FIXME: set return value? - context.gp_regs.rax = return_value as u64; + match syscall_return { + Ok(return_value) => { + context.gp_regs.rax = return_value as u64; + } + Err(err) => { + let errno = err.error() as i32; + context.gp_regs.rax = (-errno) as u64 + } } + // if let Syscal(return_value) = syscall_return { + // // FIXME: set return value? + // context.gp_regs.rax = return_value as u64; + // } } pub fn syscall_dispatch( syscall_number: u64, args: [u64; 6], context: &mut CpuContext, -) -> SyscallResult { +) -> Result { match syscall_number { SYS_WRITE => sys_write(args[0], args[1], args[2]), SYS_FSTAT => sys_fstat(args[0], args[1] as _), @@ -135,7 +139,9 @@ pub fn syscall_dispatch( SYS_MPROTECT => sys_mprotect(args[0], args[1], args[2]), SYS_BRK => sys_brk(args[0]), SYS_RT_SIGACTION => sys_rt_sigaction(), - SYS_RT_SIGPROCMASK => sys_rt_sigprocmask(args[0] as _, args[1] as _, args[2] as _, args[3] as _), + SYS_RT_SIGPROCMASK => { + sys_rt_sigprocmask(args[0] as _, args[1] as _, args[2] as _, args[3] as _) + } SYS_WRITEV => sys_writev(args[0], args[1], args[2]), SYS_ACCESS => sys_access(args[0] as _, args[1]), SYS_GETPID => sys_getpid(), @@ -168,32 +174,32 @@ pub fn syscall_dispatch( } } -pub fn sys_rt_sigaction() -> SyscallResult { +pub fn sys_rt_sigaction() -> Result { debug!("[syscall][id={}][SYS_RT_SIGACTION]", SYS_RT_SIGACTION); warn!("TODO: rt_sigaction only return a fake result"); - SyscallResult::Return(0) + Ok(0) } -pub fn sys_getuid() -> SyscallResult { +pub fn sys_getuid() -> Result { debug!("[syscall][id={}][SYS_GETUID]", SYS_GETUID); warn!("TODO: getuid only return a fake uid now"); - SyscallResult::Return(0) + Ok(0) } -pub fn sys_getgid() -> SyscallResult { - debug!("[syscall][id={}][SYS_GETGID]", SYS_GETUID); +pub fn sys_getgid() -> Result { + debug!("[syscall][id={}][SYS_GETGID]", SYS_GETGID); warn!("TODO: getgid only return a fake gid now"); - SyscallResult::Return(0) + Ok(0) } -pub fn sys_geteuid() -> SyscallResult { +pub fn sys_geteuid() -> Result { debug!("[syscall][id={}][SYS_GETEUID]", SYS_GETEUID); warn!("TODO: geteuid only return a fake euid now"); - SyscallResult::Return(0) + Ok(0) } -pub fn sys_getegid() -> SyscallResult { +pub fn sys_getegid() -> Result { debug!("[syscall][id={}][SYS_GETEGID]", SYS_GETEGID); warn!("TODO: getegid only return a fake egid now"); - SyscallResult::Return(0) + Ok(0) } diff --git a/src/kxos-std/src/syscall/mprotect.rs b/src/kxos-std/src/syscall/mprotect.rs index 259f10a53..23b101858 100644 --- a/src/kxos-std/src/syscall/mprotect.rs +++ b/src/kxos-std/src/syscall/mprotect.rs @@ -4,13 +4,11 @@ use crate::prelude::*; use crate::syscall::SYS_MPROTECT; -use super::SyscallResult; - -pub fn sys_mprotect(vaddr: u64, len: u64, perms: u64) -> SyscallResult { +pub fn sys_mprotect(vaddr: u64, len: u64, perms: u64) -> Result { debug!("[syscall][id={}][SYS_MPROTECT]", SYS_MPROTECT); let perms = VmPerm::try_from(perms).unwrap(); do_sys_mprotect(vaddr as Vaddr, len as usize, perms); - SyscallResult::Return(0) + Ok(0) } pub fn do_sys_mprotect(addr: Vaddr, len: usize, perms: VmPerm) -> isize { diff --git a/src/kxos-std/src/syscall/readlink.rs b/src/kxos-std/src/syscall/readlink.rs index c9ae7da13..de76fca8e 100644 --- a/src/kxos-std/src/syscall/readlink.rs +++ b/src/kxos-std/src/syscall/readlink.rs @@ -6,18 +6,16 @@ use crate::{ syscall::SYS_READLINK, }; -use super::SyscallResult; - const MAX_FILENAME_LEN: usize = 128; -pub fn sys_readlink(filename_ptr: u64, user_buf_ptr: u64, user_buf_len: u64) -> SyscallResult { +pub fn sys_readlink(filename_ptr: u64, user_buf_ptr: u64, user_buf_len: u64) -> Result { debug!("[syscall][id={}][SYS_READLINK]", SYS_READLINK); let res = do_sys_readlink( filename_ptr as Vaddr, user_buf_ptr as Vaddr, user_buf_len as usize, ); - SyscallResult::Return(res as _) + Ok(res as _) } /// do sys readlink diff --git a/src/kxos-std/src/syscall/rt_sigprocmask.rs b/src/kxos-std/src/syscall/rt_sigprocmask.rs index 2da276635..ee2052d12 100644 --- a/src/kxos-std/src/syscall/rt_sigprocmask.rs +++ b/src/kxos-std/src/syscall/rt_sigprocmask.rs @@ -2,8 +2,12 @@ use kxos_frame::vm::VmIo; use crate::{prelude::*, syscall::SYS_RT_SIGPROCMASK}; -use super::SyscallResult; -pub fn sys_rt_sigprocmask(how: u32, set_ptr: Vaddr, oldset_ptr: Vaddr, sigset_size: usize) -> SyscallResult { +pub fn sys_rt_sigprocmask( + how: u32, + set_ptr: Vaddr, + oldset_ptr: Vaddr, + sigset_size: usize, +) -> Result { debug!("[syscall][id={}][SYS_RT_SIGPROCMASK]", SYS_RT_SIGPROCMASK); let mask_op = MaskOp::try_from(how).unwrap(); debug!("mask op = {:?}", mask_op); @@ -14,10 +18,15 @@ pub fn sys_rt_sigprocmask(how: u32, set_ptr: Vaddr, oldset_ptr: Vaddr, sigset_si warn!("sigset size is not equal to 8"); } do_rt_sigprocmask(mask_op, set_ptr, oldset_ptr, sigset_size).unwrap(); - SyscallResult::Return(0) + Ok(0) } -fn do_rt_sigprocmask(mask_op: MaskOp, set_ptr: Vaddr, oldset_ptr: Vaddr, sigset_size: usize) -> Result<()>{ +fn do_rt_sigprocmask( + mask_op: MaskOp, + set_ptr: Vaddr, + oldset_ptr: Vaddr, + sigset_size: usize, +) -> Result<()> { let current = current!(); let vm_space = current.vm_space().unwrap(); let mut sig_mask = current.sig_mask().lock(); @@ -30,7 +39,7 @@ fn do_rt_sigprocmask(mask_op: MaskOp, set_ptr: Vaddr, oldset_ptr: Vaddr, sigset_ let new_set = vm_space.read_val::(set_ptr)?; debug!("new set = 0x{:x}", new_set); match mask_op { - MaskOp::Block => sig_mask.block(new_set ), + MaskOp::Block => sig_mask.block(new_set), MaskOp::Unblock => sig_mask.unblock(new_set), MaskOp::SetMask => sig_mask.set(new_set), } @@ -60,4 +69,4 @@ impl TryFrom for MaskOp { }; Ok(op) } -} \ No newline at end of file +} diff --git a/src/kxos-std/src/syscall/sched_yield.rs b/src/kxos-std/src/syscall/sched_yield.rs index d58217f84..2768661f3 100644 --- a/src/kxos-std/src/syscall/sched_yield.rs +++ b/src/kxos-std/src/syscall/sched_yield.rs @@ -2,10 +2,8 @@ use crate::prelude::*; use crate::{process::Process, syscall::SYS_SCHED_YIELD}; -use super::SyscallResult; - -pub fn sys_sched_yield() -> SyscallResult { +pub fn sys_sched_yield() -> Result { debug!("[syscall][id={}][SYS_SCHED_YIELD]", SYS_SCHED_YIELD); Process::yield_now(); - SyscallResult::Return(0) + Ok(0) } diff --git a/src/kxos-std/src/syscall/tgkill.rs b/src/kxos-std/src/syscall/tgkill.rs index de9e419cc..0bdd713b6 100644 --- a/src/kxos-std/src/syscall/tgkill.rs +++ b/src/kxos-std/src/syscall/tgkill.rs @@ -1,11 +1,11 @@ use crate::prelude::*; -use crate::syscall::{SyscallResult, SYS_TGKILL}; +use crate::syscall::SYS_TGKILL; -pub fn sys_tgkill(tgid: u64, pid: u64, signal: u64) -> SyscallResult { +pub fn sys_tgkill(tgid: u64, pid: u64, signal: u64) -> Result { debug!("[syscall][id={}][SYS_TGKILL]", SYS_TGKILL); debug!("tgid = {}", tgid); debug!("pid = {}", pid); warn!("TODO: tgkill do nothing now"); - SyscallResult::Return(0) + Ok(0) } diff --git a/src/kxos-std/src/syscall/uname.rs b/src/kxos-std/src/syscall/uname.rs index 5bcb08eaa..6d6140216 100644 --- a/src/kxos-std/src/syscall/uname.rs +++ b/src/kxos-std/src/syscall/uname.rs @@ -1,9 +1,6 @@ use crate::prelude::*; -use crate::{ - memory::write_val_to_user, - syscall::{SyscallResult, SYS_UNAME}, -}; +use crate::{memory::write_val_to_user, syscall::SYS_UNAME}; // We don't use the real name and version of our os here. Instead, we pick up fake values witch is the same as the ones of linux. // The values are used to fool glibc since glibc will check the version and os name. @@ -59,10 +56,10 @@ fn copy_cstring_to_u8_slice(src: &CStr, dst: &mut [u8]) { dst[..len].copy_from_slice(&src[..len]); } -pub fn sys_uname(old_uname_addr: u64) -> SyscallResult { +pub fn sys_uname(old_uname_addr: u64) -> Result { debug!("[syscall][id={}][SYS_UNAME]", SYS_UNAME); do_sys_uname(old_uname_addr as Vaddr); - SyscallResult::Return(0) + Ok(0) } pub fn do_sys_uname(old_uname_addr: Vaddr) -> usize { diff --git a/src/kxos-std/src/syscall/wait4.rs b/src/kxos-std/src/syscall/wait4.rs index 71f9d7b87..41dabeebe 100644 --- a/src/kxos-std/src/syscall/wait4.rs +++ b/src/kxos-std/src/syscall/wait4.rs @@ -4,11 +4,10 @@ use crate::{ syscall::SYS_WAIT4, }; -use super::SyscallResult; use crate::prelude::*; use crate::process::wait::WaitOptions; -pub fn sys_wait4(wait_pid: u64, exit_status_ptr: u64, wait_options: u64) -> SyscallResult { +pub fn sys_wait4(wait_pid: u64, exit_status_ptr: u64, wait_options: u64) -> Result { debug!("[syscall][id={}][SYS_WAIT4]", SYS_WAIT4); let wait_options = WaitOptions::from_bits(wait_options as u32).expect("Unknown wait options"); debug!("pid = {}", wait_pid as isize); @@ -20,5 +19,5 @@ pub fn sys_wait4(wait_pid: u64, exit_status_ptr: u64, wait_options: u64) -> Sysc write_val_to_user(exit_status_ptr as _, &exit_code); } - SyscallResult::Return(return_pid as _) + Ok(return_pid as _) } diff --git a/src/kxos-std/src/syscall/waitid.rs b/src/kxos-std/src/syscall/waitid.rs index f7e1d77f7..04dbc5486 100644 --- a/src/kxos-std/src/syscall/waitid.rs +++ b/src/kxos-std/src/syscall/waitid.rs @@ -1,6 +1,6 @@ +use crate::prelude::*; use crate::process::{process_filter::ProcessFilter, wait::wait_child_exit}; -use super::SyscallResult; use crate::process::wait::WaitOptions; pub fn sys_waitid( @@ -9,10 +9,10 @@ pub fn sys_waitid( infoq_addr: u64, options: u64, rusage_addr: u64, -) -> SyscallResult { +) -> Result { // FIXME: what does infoq and rusage use for? let process_filter = ProcessFilter::from_which_and_id(which, upid); let wait_options = WaitOptions::from_bits(options as u32).expect("Unknown wait options"); let (exit_code, pid) = wait_child_exit(process_filter, wait_options); - SyscallResult::Return(pid) + Ok(pid as _) } diff --git a/src/kxos-std/src/syscall/write.rs b/src/kxos-std/src/syscall/write.rs index 1d13d2551..f2aed5df6 100644 --- a/src/kxos-std/src/syscall/write.rs +++ b/src/kxos-std/src/syscall/write.rs @@ -2,12 +2,10 @@ use crate::prelude::*; use crate::{memory::read_bytes_from_user, syscall::SYS_WRITE}; -use super::SyscallResult; - const STDOUT: u64 = 1; const STDERR: u64 = 2; -pub fn sys_write(fd: u64, user_buf_ptr: u64, user_buf_len: u64) -> SyscallResult { +pub fn sys_write(fd: u64, user_buf_ptr: u64, user_buf_len: u64) -> Result { // only suppprt STDOUT now. debug!("[syscall][id={}][SYS_WRITE]", SYS_WRITE); @@ -21,7 +19,7 @@ pub fn sys_write(fd: u64, user_buf_ptr: u64, user_buf_len: u64) -> SyscallResult info!("Error message from user mode: {:?}", content); } - SyscallResult::Return(user_buf_len as _) + Ok(user_buf_len as _) } else { panic!("Unsupported fd number {}", fd); } diff --git a/src/kxos-std/src/syscall/writev.rs b/src/kxos-std/src/syscall/writev.rs index ae3c1d9f9..f70ab37b5 100644 --- a/src/kxos-std/src/syscall/writev.rs +++ b/src/kxos-std/src/syscall/writev.rs @@ -5,8 +5,6 @@ use crate::{ syscall::SYS_WRITEV, }; -use super::SyscallResult; - const IOVEC_MAX: usize = 256; #[repr(C)] @@ -16,10 +14,10 @@ pub struct IoVec { len: usize, } -pub fn sys_writev(fd: u64, io_vec_ptr: u64, io_vec_count: u64) -> SyscallResult { +pub fn sys_writev(fd: u64, io_vec_ptr: u64, io_vec_count: u64) -> Result { debug!("[syscall][id={}][SYS_WRITEV]", SYS_WRITEV); let res = do_sys_writev(fd, io_vec_ptr as Vaddr, io_vec_count as usize); - SyscallResult::Return(res as _) + Ok(res as _) } pub fn do_sys_writev(fd: u64, io_vec_ptr: Vaddr, io_vec_count: usize) -> usize { diff --git a/src/kxos-std/src/user_apps.rs b/src/kxos-std/src/user_apps.rs index f91fe1360..10ad61f9c 100644 --- a/src/kxos-std/src/user_apps.rs +++ b/src/kxos-std/src/user_apps.rs @@ -49,9 +49,17 @@ pub fn get_all_apps() -> Vec { res.push(app5); // Set sig procmask - let app6 = UserApp::new("/sig_procmask", read_sig_procmask()); + let app6 = UserApp::new("/sig_procmask", read_sig_procmask_content()); res.push(app6); + // divide zero + let app7 = UserApp::new("/divide_zero", read_divide_zero_content()); + res.push(app7); + + // sig_action + let app8 = UserApp::new("/sig_action", read_sig_action_content()); + res.push(app8); + res } @@ -79,6 +87,14 @@ fn read_fork_c_content() -> &'static [u8] { include_bytes!("../../kxos-user/fork_c/fork") } -fn read_sig_procmask() -> &'static [u8] { +fn read_sig_procmask_content() -> &'static [u8] { include_bytes!("../../kxos-user/signal_c/sig_procmask") } + +fn read_divide_zero_content() -> &'static [u8] { + include_bytes!("../../kxos-user/signal_c/divide_zero") +} + +fn read_sig_action_content() -> &'static [u8] { + include_bytes!("../../kxos-user/signal_c/sig_action") +} diff --git a/src/kxos-user/signal_c/Makefile b/src/kxos-user/signal_c/Makefile index bc903b97f..090aaaf3d 100644 --- a/src/kxos-user/signal_c/Makefile +++ b/src/kxos-user/signal_c/Makefile @@ -1,9 +1,10 @@ .PHONY: build clean run -build: divide_zero.c sig_procmask.c +build: divide_zero.c sig_procmask.c sig_action.c @gcc -static divide_zero.c -o divide_zero @gcc -static sig_procmask.c -o sig_procmask + @gcc -static sig_action.c -o sig_action clean: - @rm divide_zero sig_procmask + @rm divide_zero sig_procmask sig_action run: build @./sig_procmask - @./divide_zero + @./sig_action diff --git a/src/kxos-user/signal_c/sig_action b/src/kxos-user/signal_c/sig_action new file mode 100755 index 000000000..42d39e3a8 --- /dev/null +++ b/src/kxos-user/signal_c/sig_action @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:08b21d340c8d144c1bfb86097e46ceda6d690041269cf56fee5bd8918e8253fa +size 877544 diff --git a/src/kxos-user/signal_c/sig_action.c b/src/kxos-user/signal_c/sig_action.c index e69de29bb..c1927c1f7 100644 --- a/src/kxos-user/signal_c/sig_action.c +++ b/src/kxos-user/signal_c/sig_action.c @@ -0,0 +1,29 @@ +#include +#include +#include +#include +#include + +int sigchld = 0; + +void proc_exit() { + sigchld = 999; +} + +int main() { + signal(SIGCHLD, proc_exit); + printf("Run a parent process has pid = %d\n", getpid()); + fflush(stdout); + int pid = fork(); + if(pid == 0) { + // child process + printf("create a new proces successfully (pid = %d)\n", getpid()); + fflush(stdout); + } else { + // parent process + wait(NULL); + printf("sigchld = %d\n", sigchld); + fflush(stdout); + } + return 0; +} \ No newline at end of file From 634d4a5016ddfbf84e22833ecff2a0e07bc0f85b Mon Sep 17 00:00:00 2001 From: Jianfeng Jiang Date: Fri, 4 Nov 2022 14:22:28 +0800 Subject: [PATCH 4/4] add syscall rt_sigaction and rt_sigreturn --- src/kxos-frame/src/sync/wait.rs | 4 +- src/kxos-std/src/process/exception.rs | 1 + src/kxos-std/src/process/mod.rs | 8 + src/kxos-std/src/process/process_filter.rs | 2 +- src/kxos-std/src/process/signal/c_types.rs | 13 + src/kxos-std/src/process/signal/mod.rs | 107 +++++++- src/kxos-std/src/process/signal/sig_action.rs | 62 ++++- src/kxos-std/src/process/task.rs | 4 +- src/kxos-std/src/syscall/access.rs | 6 +- src/kxos-std/src/syscall/arch_prctl.rs | 13 +- src/kxos-std/src/syscall/brk.rs | 5 +- src/kxos-std/src/syscall/clone.rs | 6 +- src/kxos-std/src/syscall/execve.rs | 7 +- src/kxos-std/src/syscall/exit.rs | 6 +- src/kxos-std/src/syscall/exit_group.rs | 6 +- src/kxos-std/src/syscall/fork.rs | 6 +- src/kxos-std/src/syscall/fstat.rs | 8 +- src/kxos-std/src/syscall/futex.rs | 5 +- src/kxos-std/src/syscall/getegid.rs | 9 + src/kxos-std/src/syscall/geteuid.rs | 9 + src/kxos-std/src/syscall/getgid.rs | 9 + src/kxos-std/src/syscall/getpid.rs | 6 +- src/kxos-std/src/syscall/gettid.rs | 6 +- src/kxos-std/src/syscall/getuid.rs | 9 + src/kxos-std/src/syscall/kill.rs | 6 +- src/kxos-std/src/syscall/mmap.rs | 6 +- src/kxos-std/src/syscall/mod.rs | 237 ++++++++++-------- src/kxos-std/src/syscall/mprotect.rs | 6 +- src/kxos-std/src/syscall/readlink.rs | 10 +- src/kxos-std/src/syscall/rt_sigaction.rs | 36 +++ src/kxos-std/src/syscall/rt_sigprocmask.rs | 9 +- src/kxos-std/src/syscall/rt_sigreturn.rs | 14 ++ src/kxos-std/src/syscall/sched_yield.rs | 6 +- src/kxos-std/src/syscall/tgkill.rs | 6 +- src/kxos-std/src/syscall/uname.rs | 6 +- src/kxos-std/src/syscall/wait4.rs | 9 +- src/kxos-std/src/syscall/waitid.rs | 6 +- src/kxos-std/src/syscall/write.rs | 7 +- src/kxos-std/src/syscall/writev.rs | 6 +- src/kxos-user/execve/execve | 2 +- src/kxos-user/execve/execve.c | 3 +- src/kxos-user/fork_c/fork | 2 +- src/kxos-user/fork_c/fork.c | 4 +- src/kxos-user/signal_c/sig_action | 2 +- src/kxos-user/signal_c/sig_action.c | 2 +- 45 files changed, 512 insertions(+), 190 deletions(-) create mode 100644 src/kxos-std/src/process/signal/c_types.rs create mode 100644 src/kxos-std/src/syscall/getegid.rs create mode 100644 src/kxos-std/src/syscall/geteuid.rs create mode 100644 src/kxos-std/src/syscall/getgid.rs create mode 100644 src/kxos-std/src/syscall/getuid.rs create mode 100644 src/kxos-std/src/syscall/rt_sigaction.rs create mode 100644 src/kxos-std/src/syscall/rt_sigreturn.rs diff --git a/src/kxos-frame/src/sync/wait.rs b/src/kxos-frame/src/sync/wait.rs index 829292d01..ef3fd0311 100644 --- a/src/kxos-frame/src/sync/wait.rs +++ b/src/kxos-frame/src/sync/wait.rs @@ -3,7 +3,7 @@ use core::sync::atomic::{AtomicBool, Ordering}; use alloc::{collections::VecDeque, sync::Arc, vec::Vec}; use spin::mutex::Mutex; -use crate::{debug, task::Task}; +use crate::task::Task; /// A wait queue. /// @@ -214,7 +214,7 @@ impl Waiter { pub fn wait(&self) { while !self.is_woken_up.load(Ordering::Relaxed) { // yield the execution, to allow other task to contine - debug!("Waiter: wait"); + // debug!("Waiter: wait"); Task::yield_now(); } } diff --git a/src/kxos-std/src/process/exception.rs b/src/kxos-std/src/process/exception.rs index 86cd1a4ca..1c4b9b8fa 100644 --- a/src/kxos-std/src/process/exception.rs +++ b/src/kxos-std/src/process/exception.rs @@ -8,6 +8,7 @@ pub fn handle_exception(context: &mut CpuContext) { let current = current!(); let pid = current.pid(); debug!("trap info = {:x?}", trap_info); + debug!("cpu context = {:x?}", context); let signal = Box::new(FaultSignal::new(&trap_info)); current.sig_queues().lock().enqueue(signal); } diff --git a/src/kxos-std/src/process/mod.rs b/src/kxos-std/src/process/mod.rs index 05187c07d..6e27949c8 100644 --- a/src/kxos-std/src/process/mod.rs +++ b/src/kxos-std/src/process/mod.rs @@ -14,6 +14,7 @@ use self::signal::sig_disposition::SigDispositions; use self::signal::sig_mask::SigMask; use self::signal::sig_queues::SigQueues; use self::signal::signals::kernel::KernelSignal; +use self::signal::SigContext; use self::status::ProcessStatus; use self::task::create_user_task_from_elf; @@ -64,6 +65,8 @@ pub struct Process { sig_queues: Mutex, /// Process-level sigmask sig_mask: Mutex, + /// Signal handler Context + sig_context: Mutex>, } impl Process { @@ -116,6 +119,7 @@ impl Process { sig_dispositions: Mutex::new(sig_dispositions), sig_queues: Mutex::new(sig_queues), sig_mask: Mutex::new(sig_mask), + sig_context: Mutex::new(None), } } @@ -222,6 +226,10 @@ impl Process { &self.process_group } + pub fn sig_context(&self) -> &Mutex> { + &self.sig_context + } + /// add a child process pub fn add_child(&self, child: Arc) { debug!("process: {}, add child: {} ", self.pid(), child.pid()); diff --git a/src/kxos-std/src/process/process_filter.rs b/src/kxos-std/src/process/process_filter.rs index 4db223100..968f50d16 100644 --- a/src/kxos-std/src/process/process_filter.rs +++ b/src/kxos-std/src/process/process_filter.rs @@ -21,7 +21,7 @@ impl ProcessFilter { } // used for wait4 and kill - pub fn from_id(wait_pid: isize) -> Self { + pub fn from_id(wait_pid: i32) -> Self { // https://man7.org/linux/man-pages/man2/waitpid.2.html // https://man7.org/linux/man-pages/man2/kill.2.html if wait_pid < -1 { diff --git a/src/kxos-std/src/process/signal/c_types.rs b/src/kxos-std/src/process/signal/c_types.rs new file mode 100644 index 000000000..d30bf3def --- /dev/null +++ b/src/kxos-std/src/process/signal/c_types.rs @@ -0,0 +1,13 @@ +#![allow(non_camel_case_types)] +use crate::prelude::*; + +pub type sigset_t = u64; + +#[derive(Debug, Clone, Copy, Pod)] +#[repr(C)] +pub struct sigaction_t { + pub handler_ptr: Vaddr, + pub flags: u32, + pub restorer_ptr: Vaddr, + pub mask: sigset_t, +} diff --git a/src/kxos-std/src/process/signal/mod.rs b/src/kxos-std/src/process/signal/mod.rs index bacf7daab..dcde0ced7 100644 --- a/src/kxos-std/src/process/signal/mod.rs +++ b/src/kxos-std/src/process/signal/mod.rs @@ -1,3 +1,4 @@ +pub mod c_types; pub mod constants; pub mod sig_action; pub mod sig_disposition; @@ -6,15 +7,19 @@ pub mod sig_num; pub mod sig_queues; pub mod signals; -use kxos_frame::task::Task; +use kxos_frame::{cpu::CpuContext, task::Task}; +use self::sig_mask::SigMask; +use self::sig_num::SigNum; +use crate::memory::{write_bytes_to_user, write_val_to_user}; +use crate::process::signal::sig_action::SigActionFlags; use crate::{ prelude::*, process::signal::sig_action::{SigAction, SigDefaultAction}, }; /// Handle pending signal for current process -pub fn handle_pending_signal() { +pub fn handle_pending_signal(context: &mut CpuContext) { let current = current!(); let pid = current.pid(); let process_name = current.filename().unwrap(); @@ -25,12 +30,24 @@ pub fn handle_pending_signal() { let sig_num = signal.num(); debug!("sig_num = {:?}, sig_name = {}", sig_num, sig_num.sig_name()); let sig_action = current.sig_dispositions().lock().get(sig_num); - debug!("sig action: {:?}", sig_action); + debug!("sig action: {:x?}", sig_action); match sig_action { SigAction::Ign => { debug!("Ignore signal {:?}", sig_num); } - SigAction::User { .. } => todo!(), + SigAction::User { + handler_addr, + flags, + restorer_addr, + mask, + } => handle_user_signal_handler( + sig_num, + handler_addr, + flags, + restorer_addr, + mask, + context, + ), SigAction::Dfl => { let sig_default_action = SigDefaultAction::from_signum(sig_num); debug!("sig_default_action: {:?}", sig_default_action); @@ -70,3 +87,85 @@ pub fn handle_pending_signal() { } } } + +pub fn handle_user_signal_handler( + sig_num: SigNum, + handler_addr: Vaddr, + flags: SigActionFlags, + restorer_addr: Vaddr, + mask: SigMask, + context: &mut CpuContext, +) { + debug!("sig_num = {:?}", sig_num); + debug!("handler_addr = 0x{:x}", handler_addr); + debug!("flags = {:?}", flags); + debug!("restorer_addr = 0x{:x}", restorer_addr); + // FIXME: How to respect flags + if flags.intersects(!(SigActionFlags::SA_RESTART | SigActionFlags::SA_RESTORER)) { + panic!("Unsupported Signal flags"); + } + let current = current!(); + // block signals in sigmask when running signal handler + current.sig_mask().lock().block(mask.as_u64()); + // store context in current process + let sig_context = SigContext::new(context.clone(), mask); + *(current.sig_context().lock()) = Some(sig_context); + // set up signal stack in user stack + let mut user_rsp = context.gp_regs.rsp; + // avoid corrupt user stack, we minus 128 first. + user_rsp = user_rsp - 128; + // Copy the trampoline code. + if flags.contains(SigActionFlags::SA_RESTORER) { + // If contains SA_RESTORER flag, trampoline code is provided by libc in restorer_addr. + // We just store restorer_addr on user stack to allow user code just to trampoline code. + user_rsp = write_u64_to_user_stack(user_rsp, restorer_addr as u64); + } else { + // Otherwise we create + const TRAMPOLINE: &[u8] = &[ + 0xb8, 0x0f, 0x00, 0x00, 0x00, // mov eax, 15(syscall number of rt_sigreturn) + 0x0f, 0x05, // syscall (call rt_sigreturn) + 0x90, // nop (for alignment) + ]; + user_rsp = user_rsp - TRAMPOLINE.len() as u64; + let trampoline_rip = user_rsp; + write_bytes_to_user(user_rsp as Vaddr, TRAMPOLINE); + user_rsp = write_u64_to_user_stack(user_rsp, trampoline_rip); + } + context.gp_regs.rip = handler_addr as _; + context.gp_regs.rsp = user_rsp; + // parameters of signal handler + context.gp_regs.rdi = sig_num.as_u8() as u64; // signal number + context.gp_regs.rsi = 0; // siginfo_t* siginfo + context.gp_regs.rdx = 0; // void* ctx +} + +fn write_u64_to_user_stack(rsp: u64, value: u64) -> u64 { + let rsp = rsp - 8; + write_val_to_user(rsp as Vaddr, &value); + rsp +} + +/// Used to store process context before running signal handler. +/// In rt_sigreturn, this context is used to restore process context. +#[derive(Debug, Clone, Copy)] +pub struct SigContext { + cpu_context: CpuContext, + sig_mask: SigMask, +} + +impl SigContext { + pub const fn new(cpu_context: CpuContext, sig_mask: SigMask) -> SigContext { + Self { + cpu_context, + sig_mask, + } + } + + pub fn cpu_context(&self) -> &CpuContext { + &self.cpu_context + } + + pub fn sig_mask(&self) -> &SigMask { + &self.sig_mask + } +} diff --git a/src/kxos-std/src/process/signal/sig_action.rs b/src/kxos-std/src/process/signal/sig_action.rs index 27a9e3a2a..3c8150463 100644 --- a/src/kxos-std/src/process/signal/sig_action.rs +++ b/src/kxos-std/src/process/signal/sig_action.rs @@ -1,4 +1,5 @@ -use super::{constants::*, sig_mask::SigMask, sig_num::SigNum}; +use super::{c_types::sigaction_t, constants::*, sig_mask::SigMask, sig_num::SigNum}; +use crate::prelude::*; use bitflags::bitflags; use kxos_frame::warn; @@ -21,6 +22,58 @@ impl Default for SigAction { } } +impl TryFrom for SigAction { + type Error = Error; + + fn try_from(input: sigaction_t) -> Result { + let action = match input.handler_ptr { + SIG_DFL => SigAction::Dfl, + SIG_IGN => SigAction::Ign, + _ => { + let flags = SigActionFlags::from_bits_truncate(input.flags); + let mask = SigMask::from(input.mask); + SigAction::User { + handler_addr: input.handler_ptr, + flags, + restorer_addr: input.restorer_ptr, + mask, + } + } + }; + Ok(action) + } +} + +impl SigAction { + pub fn to_c(&self) -> sigaction_t { + match self { + SigAction::Dfl => sigaction_t { + handler_ptr: SIG_DFL, + flags: 0, + restorer_ptr: 0, + mask: 0, + }, + SigAction::Ign => sigaction_t { + handler_ptr: SIG_IGN, + flags: 0, + restorer_ptr: 0, + mask: 0, + }, + SigAction::User { + handler_addr, + flags, + restorer_addr, + mask, + } => sigaction_t { + handler_ptr: *handler_addr, + flags: flags.to_u32(), + restorer_ptr: *restorer_addr, + mask: mask.as_u64(), + }, + } + } +} + bitflags! { pub struct SigActionFlags: u32 { const SA_NOCLDSTOP = 1; @@ -35,10 +88,11 @@ bitflags! { } impl TryFrom for SigActionFlags { - type Error = &'static str; + type Error = Error; - fn try_from(bits: u32) -> Result { - let flags = SigActionFlags::from_bits(bits).ok_or_else(|| "invalid sigaction flags")?; + fn try_from(bits: u32) -> Result { + let flags = SigActionFlags::from_bits(bits) + .ok_or_else(|| Error::with_message(Errno::EINVAL, "invalid sig action flag"))?; if flags.contains(SigActionFlags::SA_RESTART) { warn!("SA_RESTART is not supported"); } diff --git a/src/kxos-std/src/process/task.rs b/src/kxos-std/src/process/task.rs index 8c6b886d9..229c312dd 100644 --- a/src/kxos-std/src/process/task.rs +++ b/src/kxos-std/src/process/task.rs @@ -57,7 +57,7 @@ pub fn create_new_task(userspace: Arc, parent: Weak) -> Arc< if current.status().lock().is_zombie() { break; } - handle_pending_signal(); + handle_pending_signal(context); if current.status().lock().is_zombie() { debug!("exit due to signal"); break; @@ -66,7 +66,7 @@ pub fn create_new_task(userspace: Arc, parent: Weak) -> Arc< while current.status().lock().is_suspend() { Process::yield_now(); debug!("{} is suspended.", current.pid()); - handle_pending_signal(); + handle_pending_signal(context); } } debug!("exit user loop"); diff --git a/src/kxos-std/src/syscall/access.rs b/src/kxos-std/src/syscall/access.rs index cc066ecb1..81319de7f 100644 --- a/src/kxos-std/src/syscall/access.rs +++ b/src/kxos-std/src/syscall/access.rs @@ -1,12 +1,12 @@ -use super::constants::*; +use super::{constants::*, SyscallReturn}; use crate::{memory::read_bytes_from_user, prelude::*, syscall::SYS_ACCESS}; -pub fn sys_access(filename_ptr: Vaddr, file_mode: u64) -> Result { +pub fn sys_access(filename_ptr: Vaddr, file_mode: u64) -> Result { debug!("[syscall][id={}][SYS_ACCESS]", SYS_ACCESS); let mut filename_buffer = vec![0u8; MAX_FILENAME_LEN]; read_bytes_from_user(filename_ptr, &mut filename_buffer); let filename = CString::from(CStr::from_bytes_until_nul(&filename_buffer).unwrap()); debug!("filename: {:?}", filename); warn!("access currenly does not check and just return success"); - Ok(0) + Ok(SyscallReturn::Return(0)) } diff --git a/src/kxos-std/src/syscall/arch_prctl.rs b/src/kxos-std/src/syscall/arch_prctl.rs index 8aeccbcb2..6be34263b 100644 --- a/src/kxos-std/src/syscall/arch_prctl.rs +++ b/src/kxos-std/src/syscall/arch_prctl.rs @@ -3,6 +3,8 @@ use kxos_frame::cpu::CpuContext; use crate::prelude::*; use crate::syscall::SYS_ARCH_PRCTL; +use super::SyscallReturn; + #[allow(non_camel_case_types)] #[derive(Debug)] pub enum ArchPrctlCode { @@ -26,19 +28,12 @@ impl TryFrom for ArchPrctlCode { } } -pub fn sys_arch_prctl(code: u64, addr: u64, context: &mut CpuContext) -> Result { +pub fn sys_arch_prctl(code: u64, addr: u64, context: &mut CpuContext) -> Result { debug!("[syscall][id={}][SYS_ARCH_PRCTL]", SYS_ARCH_PRCTL); let arch_prctl_code = ArchPrctlCode::try_from(code)?; debug!("arch_prctl_code: {:?}", arch_prctl_code); let res = do_arch_prctl(arch_prctl_code, addr, context).unwrap(); - Ok(res as _) - // match arch_prctl_code { - // Err(_) => SyscallResult::Return(-1), - // Ok(code) => { - // let res = do_arch_prctl(code, addr, context).unwrap(); - // SyscallResult::Return(res as _) - // } - // } + Ok(SyscallReturn::Return(res as _)) } pub fn do_arch_prctl(code: ArchPrctlCode, addr: u64, context: &mut CpuContext) -> Result { diff --git a/src/kxos-std/src/syscall/brk.rs b/src/kxos-std/src/syscall/brk.rs index b9dd71e53..d9c4c83e9 100644 --- a/src/kxos-std/src/syscall/brk.rs +++ b/src/kxos-std/src/syscall/brk.rs @@ -1,9 +1,10 @@ use crate::prelude::*; +use crate::syscall::SyscallReturn; use crate::{process::Process, syscall::SYS_BRK}; /// expand the user heap to new heap end, returns the new heap end if expansion succeeds. -pub fn sys_brk(heap_end: u64) -> Result { +pub fn sys_brk(heap_end: u64) -> Result { debug!("[syscall][id={}][SYS_BRK]", SYS_BRK); let current = Process::current(); let new_heap_end = if heap_end == 0 { @@ -20,5 +21,5 @@ pub fn sys_brk(heap_end: u64) -> Result { .expect("brk should work on process with user space"); let new_heap_end = user_heap.brk(new_heap_end, vm_space); - Ok(new_heap_end as _) + Ok(SyscallReturn::Return(new_heap_end as _)) } diff --git a/src/kxos-std/src/syscall/clone.rs b/src/kxos-std/src/syscall/clone.rs index e60b0b4bf..80de9fa56 100644 --- a/src/kxos-std/src/syscall/clone.rs +++ b/src/kxos-std/src/syscall/clone.rs @@ -3,6 +3,8 @@ use kxos_frame::cpu::CpuContext; use crate::process::clone::{clone_child, CloneArgs, CloneFlags}; use crate::{prelude::*, syscall::SYS_CLONE}; +use super::SyscallReturn; + // The order of arguments for clone differs in different architecture. // This order we use here is the order for x86_64. See https://man7.org/linux/man-pages/man2/clone.2.html. pub fn sys_clone( @@ -12,7 +14,7 @@ pub fn sys_clone( child_tidptr: Vaddr, tls: usize, parent_context: CpuContext, -) -> Result { +) -> Result { debug!("[syscall][id={}][SYS_CLONE]", SYS_CLONE); debug!("flags = {}", clone_flags); let clone_flags = CloneFlags::from(clone_flags); @@ -28,5 +30,5 @@ pub fn sys_clone( debug!("*********schedule child process, pid = {}**********", pid); child_process.send_to_scheduler(); debug!("*********return to parent process, pid = {}*********", pid); - Ok(child_pid as _) + Ok(SyscallReturn::Return(child_pid as _)) } diff --git a/src/kxos-std/src/syscall/execve.rs b/src/kxos-std/src/syscall/execve.rs index 240dbff2f..af5592873 100644 --- a/src/kxos-std/src/syscall/execve.rs +++ b/src/kxos-std/src/syscall/execve.rs @@ -1,6 +1,6 @@ use kxos_frame::cpu::CpuContext; -use super::constants::*; +use super::{constants::*, SyscallReturn}; use crate::process::elf::load_elf_to_vm_space; use crate::{memory::read_bytes_from_user, prelude::*, process::Process, syscall::SYS_EXECVE}; @@ -9,7 +9,7 @@ pub fn sys_execve( argv_ptr_ptr: Vaddr, envp_ptr_ptr: Vaddr, context: &mut CpuContext, -) -> Result { +) -> Result { debug!("[syscall][id={}][SYS_EXECVE]", SYS_EXECVE); let mut filename_buffer = vec![0u8; MAX_FILENAME_LEN]; read_bytes_from_user(filename_ptr, &mut filename_buffer); @@ -40,11 +40,12 @@ pub fn sys_execve( let defalut_content = CpuContext::default(); context.gp_regs = defalut_content.gp_regs; context.fs_base = defalut_content.fs_base; + context.fp_regs = defalut_content.fp_regs; // set new entry point context.gp_regs.rip = elf_load_info.entry_point(); debug!("entry_point: 0x{:x}", elf_load_info.entry_point()); // set new user stack top context.gp_regs.rsp = elf_load_info.user_stack_top(); debug!("user stack top: 0x{:x}", elf_load_info.user_stack_top()); - Ok(0) + Ok(SyscallReturn::NoReturn) } diff --git a/src/kxos-std/src/syscall/exit.rs b/src/kxos-std/src/syscall/exit.rs index 3c8a11c0c..8e60803c1 100644 --- a/src/kxos-std/src/syscall/exit.rs +++ b/src/kxos-std/src/syscall/exit.rs @@ -1,9 +1,9 @@ use crate::prelude::*; -use crate::syscall::SYS_EXIT; +use crate::syscall::{SyscallReturn, SYS_EXIT}; -pub fn sys_exit(exit_code: i32) -> Result { +pub fn sys_exit(exit_code: i32) -> Result { debug!("[syscall][id={}][SYS_EXIT]", SYS_EXIT); current!().exit(exit_code); - Ok(0) + Ok(SyscallReturn::Return(0)) } diff --git a/src/kxos-std/src/syscall/exit_group.rs b/src/kxos-std/src/syscall/exit_group.rs index 0d8ee732a..cfb084cf4 100644 --- a/src/kxos-std/src/syscall/exit_group.rs +++ b/src/kxos-std/src/syscall/exit_group.rs @@ -1,9 +1,9 @@ use crate::prelude::*; -use crate::syscall::SYS_EXIT_GROUP; +use crate::syscall::{SyscallReturn, SYS_EXIT_GROUP}; -pub fn sys_exit_group(exit_code: u64) -> Result { +pub fn sys_exit_group(exit_code: u64) -> Result { debug!("[syscall][id={}][SYS_EXIT_GROUP]", SYS_EXIT_GROUP); current!().exit(exit_code as _); - Ok(0) + Ok(SyscallReturn::Return(0)) } diff --git a/src/kxos-std/src/syscall/fork.rs b/src/kxos-std/src/syscall/fork.rs index 37fe5961b..cfc0858b4 100644 --- a/src/kxos-std/src/syscall/fork.rs +++ b/src/kxos-std/src/syscall/fork.rs @@ -6,10 +6,12 @@ use kxos_frame::cpu::CpuContext; use crate::{process::Process, syscall::SYS_FORK}; -pub fn sys_fork(parent_context: CpuContext) -> Result { +use super::SyscallReturn; + +pub fn sys_fork(parent_context: CpuContext) -> Result { debug!("[syscall][id={}][SYS_FORK]", SYS_FORK); let child_process = fork(parent_context); - Ok(child_process.pid() as _) + Ok(SyscallReturn::Return(child_process.pid() as _)) } /// Fork a child process diff --git a/src/kxos-std/src/syscall/fstat.rs b/src/kxos-std/src/syscall/fstat.rs index 934e7cac9..2ecb99ddf 100644 --- a/src/kxos-std/src/syscall/fstat.rs +++ b/src/kxos-std/src/syscall/fstat.rs @@ -3,9 +3,9 @@ use kxos_frame::vm::VmIo; use crate::fs::stat::Stat; use crate::prelude::*; -use crate::syscall::SYS_FSTAT; +use crate::syscall::{SyscallReturn, SYS_FSTAT}; -pub fn sys_fstat(fd: u64, stat_buf_ptr: Vaddr) -> Result { +pub fn sys_fstat(fd: u64, stat_buf_ptr: Vaddr) -> Result { debug!("[syscall][id={}][SYS_FSTAT]", SYS_FSTAT); debug!("fd = {}", fd); debug!("stat_buf_addr = 0x{:x}", stat_buf_ptr); @@ -19,8 +19,8 @@ pub fn sys_fstat(fd: u64, stat_buf_ptr: Vaddr) -> Result { vm_space .write_val(stat_buf_ptr, &stat) .expect("Write value failed"); - return Ok(0); + return Ok(SyscallReturn::Return(0)); } warn!("TODO: fstat only returns fake result now."); - Ok(0) + Ok(SyscallReturn::Return(0)) } diff --git a/src/kxos-std/src/syscall/futex.rs b/src/kxos-std/src/syscall/futex.rs index b71f153e4..6103533e4 100644 --- a/src/kxos-std/src/syscall/futex.rs +++ b/src/kxos-std/src/syscall/futex.rs @@ -1,3 +1,4 @@ +use crate::syscall::SyscallReturn; use crate::{memory::read_val_from_user, syscall::SYS_FUTEX}; use crate::prelude::*; @@ -17,7 +18,7 @@ pub fn sys_futex( utime_addr: u64, futex_new_addr: u64, bitset: u64, -) -> Result { +) -> Result { debug!("[syscall][id={}][SYS_FUTEX]", SYS_FUTEX); // FIXME: we current ignore futex flags let (futex_op, futex_flags) = futex_op_and_flags_from_u32(futex_op as _).unwrap(); @@ -69,7 +70,7 @@ pub fn sys_futex( } .unwrap(); - Ok(res as _) + Ok(SyscallReturn::Return(res as _)) } /// do futex wait diff --git a/src/kxos-std/src/syscall/getegid.rs b/src/kxos-std/src/syscall/getegid.rs new file mode 100644 index 000000000..d1e9f2c85 --- /dev/null +++ b/src/kxos-std/src/syscall/getegid.rs @@ -0,0 +1,9 @@ +use crate::{prelude::*, syscall::SYS_GETEGID}; + +use super::SyscallReturn; + +pub fn sys_getegid() -> Result { + debug!("[syscall][id={}][SYS_GETEGID]", SYS_GETEGID); + warn!("TODO: getegid only return a fake egid now"); + Ok(SyscallReturn::Return(0)) +} diff --git a/src/kxos-std/src/syscall/geteuid.rs b/src/kxos-std/src/syscall/geteuid.rs new file mode 100644 index 000000000..1c11f4dcc --- /dev/null +++ b/src/kxos-std/src/syscall/geteuid.rs @@ -0,0 +1,9 @@ +use crate::{prelude::*, syscall::SYS_GETEUID}; + +use super::SyscallReturn; + +pub fn sys_geteuid() -> Result { + debug!("[syscall][id={}][SYS_GETEUID]", SYS_GETEUID); + warn!("TODO: geteuid only return a fake euid now"); + Ok(SyscallReturn::Return(0)) +} diff --git a/src/kxos-std/src/syscall/getgid.rs b/src/kxos-std/src/syscall/getgid.rs new file mode 100644 index 000000000..eefe27ed2 --- /dev/null +++ b/src/kxos-std/src/syscall/getgid.rs @@ -0,0 +1,9 @@ +use crate::{prelude::*, syscall::SYS_GETGID}; + +use super::SyscallReturn; + +pub fn sys_getgid() -> Result { + debug!("[syscall][id={}][SYS_GETGID]", SYS_GETGID); + warn!("TODO: getgid only return a fake gid now"); + Ok(SyscallReturn::Return(0)) +} diff --git a/src/kxos-std/src/syscall/getpid.rs b/src/kxos-std/src/syscall/getpid.rs index 1b5ab04d6..493b7371f 100644 --- a/src/kxos-std/src/syscall/getpid.rs +++ b/src/kxos-std/src/syscall/getpid.rs @@ -2,9 +2,11 @@ use crate::prelude::*; use crate::{process::Process, syscall::SYS_GETPID}; -pub fn sys_getpid() -> Result { +use super::SyscallReturn; + +pub fn sys_getpid() -> Result { debug!("[syscall][id={}][SYS_GETPID]", SYS_GETPID); let pid = Process::current().pid(); info!("[sys_getpid]: pid = {}", pid); - Ok(pid as _) + Ok(SyscallReturn::Return(pid as _)) } diff --git a/src/kxos-std/src/syscall/gettid.rs b/src/kxos-std/src/syscall/gettid.rs index c1d8e9622..028d6e891 100644 --- a/src/kxos-std/src/syscall/gettid.rs +++ b/src/kxos-std/src/syscall/gettid.rs @@ -2,9 +2,11 @@ use crate::prelude::*; use crate::{process::Process, syscall::SYS_GETTID}; -pub fn sys_gettid() -> Result { +use super::SyscallReturn; + +pub fn sys_gettid() -> Result { debug!("[syscall][id={}][SYS_GETTID]", SYS_GETTID); // For single-thread process, tid is equal to pid let tid = Process::current().pid(); - Ok(tid as _) + Ok(SyscallReturn::Return(tid as _)) } diff --git a/src/kxos-std/src/syscall/getuid.rs b/src/kxos-std/src/syscall/getuid.rs new file mode 100644 index 000000000..f9bef9ddc --- /dev/null +++ b/src/kxos-std/src/syscall/getuid.rs @@ -0,0 +1,9 @@ +use crate::{prelude::*, syscall::SYS_GETUID}; + +use super::SyscallReturn; + +pub fn sys_getuid() -> Result { + debug!("[syscall][id={}][SYS_GETUID]", SYS_GETUID); + warn!("TODO: getuid only return a fake uid now"); + Ok(SyscallReturn::Return(0)) +} diff --git a/src/kxos-std/src/syscall/kill.rs b/src/kxos-std/src/syscall/kill.rs index 90e347c4e..452e7abd1 100644 --- a/src/kxos-std/src/syscall/kill.rs +++ b/src/kxos-std/src/syscall/kill.rs @@ -7,12 +7,14 @@ use crate::{ syscall::SYS_KILL, }; -pub fn sys_kill(process_filter: u64, sig_num: u64) -> Result { +use super::SyscallReturn; + +pub fn sys_kill(process_filter: u64, sig_num: u64) -> Result { debug!("[syscall][id={}][SYS_KILL]", SYS_KILL); let process_filter = ProcessFilter::from_id(process_filter as _); let sig_num = SigNum::try_from(sig_num as u8).unwrap(); do_sys_kill(process_filter, sig_num)?; - Ok(0) + Ok(SyscallReturn::Return(0)) } pub fn do_sys_kill(process_filter: ProcessFilter, sig_num: SigNum) -> Result<()> { diff --git a/src/kxos-std/src/syscall/mmap.rs b/src/kxos-std/src/syscall/mmap.rs index 073862b82..4af368cde 100644 --- a/src/kxos-std/src/syscall/mmap.rs +++ b/src/kxos-std/src/syscall/mmap.rs @@ -6,6 +6,8 @@ use kxos_frame::vm::VmPerm; use crate::{process::Process, syscall::SYS_MMAP}; +use super::SyscallReturn; + pub fn sys_mmap( addr: u64, len: u64, @@ -13,7 +15,7 @@ pub fn sys_mmap( flags: u64, fd: u64, offset: u64, -) -> Result { +) -> Result { debug!("[syscall][id={}][SYS_MMAP]", SYS_MMAP); let perms = VmPerm::try_from(perms).unwrap(); let flags = MMapFlags::try_from(flags).unwrap(); @@ -25,7 +27,7 @@ pub fn sys_mmap( fd as usize, offset as usize, ); - Ok(res as _) + Ok(SyscallReturn::Return(res as _)) } pub fn do_sys_mmap( diff --git a/src/kxos-std/src/syscall/mod.rs b/src/kxos-std/src/syscall/mod.rs index bf62fa450..62e055081 100644 --- a/src/kxos-std/src/syscall/mod.rs +++ b/src/kxos-std/src/syscall/mod.rs @@ -1,33 +1,38 @@ //! Read the Cpu context content then dispatch syscall to corrsponding handler //! The each sub module contains functions that handle real syscall logic. - use crate::prelude::*; -use crate::syscall::clone::sys_clone; -use crate::syscall::kill::sys_kill; -use crate::syscall::rt_sigprocmask::sys_rt_sigprocmask; -use alloc::borrow::ToOwned; -use kxos_frame::cpu::CpuContext; - use crate::syscall::access::sys_access; use crate::syscall::arch_prctl::sys_arch_prctl; use crate::syscall::brk::sys_brk; +use crate::syscall::clone::sys_clone; use crate::syscall::execve::sys_execve; use crate::syscall::exit::sys_exit; use crate::syscall::exit_group::sys_exit_group; use crate::syscall::fork::sys_fork; use crate::syscall::fstat::sys_fstat; use crate::syscall::futex::sys_futex; +use crate::syscall::getegid::sys_getegid; +use crate::syscall::geteuid::sys_geteuid; +use crate::syscall::getgid::sys_getgid; use crate::syscall::getpid::sys_getpid; use crate::syscall::gettid::sys_gettid; +use crate::syscall::getuid::sys_getuid; +use crate::syscall::kill::sys_kill; use crate::syscall::mmap::sys_mmap; use crate::syscall::mprotect::sys_mprotect; use crate::syscall::readlink::sys_readlink; +use crate::syscall::rt_sigaction::sys_rt_sigaction; +use crate::syscall::rt_sigprocmask::sys_rt_sigprocmask; +use crate::syscall::rt_sigreturn::sys_rt_sigreturn; +use crate::syscall::sched_yield::sys_sched_yield; use crate::syscall::tgkill::sys_tgkill; use crate::syscall::uname::sys_uname; use crate::syscall::wait4::sys_wait4; use crate::syscall::waitid::sys_waitid; use crate::syscall::write::sys_write; use crate::syscall::writev::sys_writev; +use crate::{define_syscall_nums, syscall_handler}; +use kxos_frame::cpu::CpuContext; mod access; mod arch_prctl; @@ -40,13 +45,19 @@ mod exit_group; mod fork; mod fstat; mod futex; +mod getegid; +mod geteuid; +mod getgid; mod getpid; mod gettid; +mod getuid; mod kill; mod mmap; mod mprotect; mod readlink; +mod rt_sigaction; mod rt_sigprocmask; +mod rt_sigreturn; mod sched_yield; mod tgkill; mod uname; @@ -55,41 +66,58 @@ mod waitid; mod write; mod writev; -const SYS_WRITE: u64 = 1; -const SYS_FSTAT: u64 = 5; -const SYS_MMAP: u64 = 9; -const SYS_MPROTECT: u64 = 10; -const SYS_BRK: u64 = 12; -const SYS_RT_SIGACTION: u64 = 13; -const SYS_RT_SIGPROCMASK: u64 = 14; -const SYS_WRITEV: u64 = 20; -const SYS_ACCESS: u64 = 21; -const SYS_SCHED_YIELD: u64 = 24; -const SYS_GETPID: u64 = 39; -const SYS_CLONE: u64 = 56; -const SYS_FORK: u64 = 57; -const SYS_EXECVE: u64 = 59; -const SYS_EXIT: u64 = 60; -const SYS_WAIT4: u64 = 61; -const SYS_KILL: u64 = 62; -const SYS_UNAME: u64 = 63; -const SYS_READLINK: u64 = 89; -const SYS_GETUID: u64 = 102; -const SYS_GETGID: u64 = 104; -const SYS_GETEUID: u64 = 107; -const SYS_GETEGID: u64 = 108; -const SYS_ARCH_PRCTL: u64 = 158; -const SYS_GETTID: u64 = 186; -const SYS_FUTEX: u64 = 202; -const SYS_EXIT_GROUP: u64 = 231; -const SYS_TGKILL: u64 = 234; -const SYS_WAITID: u64 = 247; +define_syscall_nums!( + SYS_WRITE = 1, + SYS_FSTAT = 5, + SYS_MMAP = 9, + SYS_MPROTECT = 10, + SYS_BRK = 12, + SYS_RT_SIGACTION = 13, + SYS_RT_SIGPROCMASK = 14, + SYS_RT_SIGRETRUN = 15, + SYS_WRITEV = 20, + SYS_ACCESS = 21, + SYS_SCHED_YIELD = 24, + SYS_IOCTL = 29, + SYS_GETPID = 39, + SYS_CLONE = 56, + SYS_FORK = 57, + SYS_EXECVE = 59, + SYS_EXIT = 60, + SYS_WAIT4 = 61, + SYS_KILL = 62, + SYS_UNAME = 63, + SYS_GETPPID = 64, + SYS_FCNTL = 72, + SYS_READLINK = 89, + SYS_GETUID = 102, + SYS_GETGID = 104, + SYS_GETEUID = 107, + SYS_GETEGID = 108, + SYS_GETPGRP = 111, + SYS_PRCTL = 157, + SYS_ARCH_PRCTL = 158, + SYS_GETCWD = 183, + SYS_GETTID = 186, + SYS_FUTEX = 202, + SYS_EXIT_GROUP = 231, + SYS_TGKILL = 234, + SYS_WAITID = 247 +); pub struct SyscallArgument { syscall_number: u64, args: [u64; 6], } +/// Syscall return +pub enum SyscallReturn { + /// return isize, this value will be used to set rax + Return(isize), + /// does not need to set rax + NoReturn, +} + impl SyscallArgument { fn new_from_context(context: &CpuContext) -> Self { let syscall_number = context.gp_regs.rax; @@ -114,92 +142,91 @@ pub fn handle_syscall(context: &mut CpuContext) { match syscall_return { Ok(return_value) => { - context.gp_regs.rax = return_value as u64; + if let SyscallReturn::Return(return_value) = return_value { + context.gp_regs.rax = return_value as u64; + } } Err(err) => { let errno = err.error() as i32; context.gp_regs.rax = (-errno) as u64 } } - // if let Syscal(return_value) = syscall_return { - // // FIXME: set return value? - // context.gp_regs.rax = return_value as u64; - // } } pub fn syscall_dispatch( syscall_number: u64, args: [u64; 6], context: &mut CpuContext, -) -> Result { +) -> Result { match syscall_number { - SYS_WRITE => sys_write(args[0], args[1], args[2]), - SYS_FSTAT => sys_fstat(args[0], args[1] as _), - SYS_MMAP => sys_mmap(args[0], args[1], args[2], args[3], args[4], args[5]), - SYS_MPROTECT => sys_mprotect(args[0], args[1], args[2]), - SYS_BRK => sys_brk(args[0]), - SYS_RT_SIGACTION => sys_rt_sigaction(), - SYS_RT_SIGPROCMASK => { - sys_rt_sigprocmask(args[0] as _, args[1] as _, args[2] as _, args[3] as _) - } - SYS_WRITEV => sys_writev(args[0], args[1], args[2]), - SYS_ACCESS => sys_access(args[0] as _, args[1]), - SYS_GETPID => sys_getpid(), - SYS_CLONE => sys_clone( - args[0], - args[1] as _, - args[2] as _, - args[3] as _, - args[4] as _, - context.to_owned(), - ), - SYS_FORK => sys_fork(context.to_owned()), - SYS_EXECVE => sys_execve(args[0] as _, args[1] as _, args[2] as _, context), - SYS_EXIT => sys_exit(args[0] as _), - SYS_WAIT4 => sys_wait4(args[0], args[1], args[2]), - SYS_KILL => sys_kill(args[0], args[1]), - SYS_UNAME => sys_uname(args[0]), - SYS_READLINK => sys_readlink(args[0], args[1], args[2]), - SYS_GETUID => sys_getuid(), - SYS_GETGID => sys_getgid(), - SYS_GETEUID => sys_geteuid(), - SYS_GETEGID => sys_getegid(), - SYS_ARCH_PRCTL => sys_arch_prctl(args[0], args[1], context), - SYS_GETTID => sys_gettid(), - SYS_FUTEX => sys_futex(args[0], args[1], args[2], args[3], args[4], args[5]), - SYS_EXIT_GROUP => sys_exit_group(args[0]), - SYS_TGKILL => sys_tgkill(args[0], args[1], args[2]), - SYS_WAITID => sys_waitid(args[0], args[1], args[2], args[3], args[4]), + SYS_WRITE => syscall_handler!(3, sys_write, args), + SYS_FSTAT => syscall_handler!(2, sys_fstat, args), + SYS_MMAP => syscall_handler!(6, sys_mmap, args), + SYS_MPROTECT => syscall_handler!(3, sys_mprotect, args), + SYS_BRK => syscall_handler!(1, sys_brk, args), + SYS_RT_SIGACTION => syscall_handler!(4, sys_rt_sigaction, args), + SYS_RT_SIGPROCMASK => syscall_handler!(4, sys_rt_sigprocmask, args), + SYS_RT_SIGRETRUN => syscall_handler!(0, sys_rt_sigreturn, context), + SYS_WRITEV => syscall_handler!(3, sys_writev, args), + SYS_ACCESS => syscall_handler!(2, sys_access, args), + SYS_SCHED_YIELD => syscall_handler!(0, sys_sched_yield), + SYS_IOCTL => todo!(), + SYS_GETPID => syscall_handler!(0, sys_getpid), + SYS_CLONE => syscall_handler!(5, sys_clone, args, context.clone()), + SYS_FORK => syscall_handler!(0, sys_fork, context.clone()), + SYS_EXECVE => syscall_handler!(3, sys_execve, args, context), + SYS_EXIT => syscall_handler!(1, sys_exit, args), + SYS_WAIT4 => syscall_handler!(3, sys_wait4, args), + SYS_KILL => syscall_handler!(2, sys_kill, args), + SYS_UNAME => syscall_handler!(1, sys_uname, args), + SYS_GETPPID => todo!(), + SYS_FCNTL => todo!(), + SYS_READLINK => syscall_handler!(3, sys_readlink, args), + SYS_GETUID => syscall_handler!(0, sys_getuid), + SYS_GETGID => syscall_handler!(0, sys_getgid), + SYS_GETEUID => syscall_handler!(0, sys_geteuid), + SYS_GETEGID => syscall_handler!(0, sys_getegid), + SYS_GETPGRP => todo!(), + SYS_PRCTL => todo!(), + SYS_ARCH_PRCTL => syscall_handler!(2, sys_arch_prctl, args, context), + SYS_GETCWD => todo!(), + SYS_GETTID => syscall_handler!(0, sys_gettid), + SYS_FUTEX => syscall_handler!(6, sys_futex, args), + SYS_EXIT_GROUP => syscall_handler!(1, sys_exit_group, args), + SYS_TGKILL => syscall_handler!(3, sys_tgkill, args), + SYS_WAITID => syscall_handler!(5, sys_waitid, args), _ => panic!("Unsupported syscall number: {}", syscall_number), } } -pub fn sys_rt_sigaction() -> Result { - debug!("[syscall][id={}][SYS_RT_SIGACTION]", SYS_RT_SIGACTION); - warn!("TODO: rt_sigaction only return a fake result"); - Ok(0) +/// This macro is used to define syscall handler. +/// The first param is ths number of parameters, +/// The second param is the function name of syscall handler, +/// The third is optional, means the args(if parameter number > 0), +/// The third is optional, means if cpu context is required. +#[macro_export] +macro_rules! syscall_handler { + (0, $fn_name: ident) => { $fn_name() }; + (0, $fn_name: ident, $context: expr) => { $fn_name($context) }; + (1, $fn_name: ident, $args: ident) => { $fn_name($args[0] as _) }; + (1, $fn_name: ident, $args: ident, $context: expr) => { $fn_name($args[0] as _, $context) }; + (2, $fn_name: ident, $args: ident) => { $fn_name($args[0] as _, $args[1] as _)}; + (2, $fn_name: ident, $args: ident, $context: expr) => { $fn_name($args[0] as _, $args[1] as _, $context)}; + (3, $fn_name: ident, $args: ident) => { $fn_name($args[0] as _, $args[1] as _, $args[2] as _)}; + (3, $fn_name: ident, $args: ident, $context: expr) => { $fn_name($args[0] as _, $args[1] as _, $args[2] as _, $context)}; + (4, $fn_name: ident, $args: ident) => { $fn_name($args[0] as _, $args[1] as _, $args[2] as _, $args[3] as _)}; + (4, $fn_name: ident, $args: ident, $context: expr) => { $fn_name($args[0] as _, $args[1] as _, $args[2] as _, $args[3] as _), $context}; + (5, $fn_name: ident, $args: ident) => { $fn_name($args[0] as _, $args[1] as _, $args[2] as _, $args[3] as _, $args[4] as _)}; + (5, $fn_name: ident, $args: ident, $context: expr) => { $fn_name($args[0] as _, $args[1] as _, $args[2] as _, $args[3] as _, $args[4] as _, $context)}; + (6, $fn_name: ident, $args: ident) => { $fn_name($args[0] as _, $args[1] as _, $args[2] as _, $args[3] as _, $args[4] as _, $args[5] as _)}; + (6, $fn_name: ident, $args: ident, $context: expr) => { $fn_name($args[0] as _, $args[1] as _, $args[2] as _, $args[3] as _, $args[4] as _, $args[5] as _, $context)}; } -pub fn sys_getuid() -> Result { - debug!("[syscall][id={}][SYS_GETUID]", SYS_GETUID); - warn!("TODO: getuid only return a fake uid now"); - Ok(0) -} - -pub fn sys_getgid() -> Result { - debug!("[syscall][id={}][SYS_GETGID]", SYS_GETGID); - warn!("TODO: getgid only return a fake gid now"); - Ok(0) -} - -pub fn sys_geteuid() -> Result { - debug!("[syscall][id={}][SYS_GETEUID]", SYS_GETEUID); - warn!("TODO: geteuid only return a fake euid now"); - Ok(0) -} - -pub fn sys_getegid() -> Result { - debug!("[syscall][id={}][SYS_GETEGID]", SYS_GETEGID); - warn!("TODO: getegid only return a fake egid now"); - Ok(0) +#[macro_export] +macro_rules! define_syscall_nums { + ( $( $name: ident = $num: expr ),+ ) => { + $( + const $name: u64 = $num; + )* + } } diff --git a/src/kxos-std/src/syscall/mprotect.rs b/src/kxos-std/src/syscall/mprotect.rs index 23b101858..48c9df88e 100644 --- a/src/kxos-std/src/syscall/mprotect.rs +++ b/src/kxos-std/src/syscall/mprotect.rs @@ -4,11 +4,13 @@ use crate::prelude::*; use crate::syscall::SYS_MPROTECT; -pub fn sys_mprotect(vaddr: u64, len: u64, perms: u64) -> Result { +use super::SyscallReturn; + +pub fn sys_mprotect(vaddr: u64, len: u64, perms: u64) -> Result { debug!("[syscall][id={}][SYS_MPROTECT]", SYS_MPROTECT); let perms = VmPerm::try_from(perms).unwrap(); do_sys_mprotect(vaddr as Vaddr, len as usize, perms); - Ok(0) + Ok(SyscallReturn::Return(0)) } pub fn do_sys_mprotect(addr: Vaddr, len: usize, perms: VmPerm) -> isize { diff --git a/src/kxos-std/src/syscall/readlink.rs b/src/kxos-std/src/syscall/readlink.rs index de76fca8e..39434cd13 100644 --- a/src/kxos-std/src/syscall/readlink.rs +++ b/src/kxos-std/src/syscall/readlink.rs @@ -6,16 +6,22 @@ use crate::{ syscall::SYS_READLINK, }; +use super::SyscallReturn; + const MAX_FILENAME_LEN: usize = 128; -pub fn sys_readlink(filename_ptr: u64, user_buf_ptr: u64, user_buf_len: u64) -> Result { +pub fn sys_readlink( + filename_ptr: u64, + user_buf_ptr: u64, + user_buf_len: u64, +) -> Result { debug!("[syscall][id={}][SYS_READLINK]", SYS_READLINK); let res = do_sys_readlink( filename_ptr as Vaddr, user_buf_ptr as Vaddr, user_buf_len as usize, ); - Ok(res as _) + Ok(SyscallReturn::Return(res as _)) } /// do sys readlink diff --git a/src/kxos-std/src/syscall/rt_sigaction.rs b/src/kxos-std/src/syscall/rt_sigaction.rs new file mode 100644 index 000000000..3205fa00f --- /dev/null +++ b/src/kxos-std/src/syscall/rt_sigaction.rs @@ -0,0 +1,36 @@ +use crate::{ + memory::{read_val_from_user, write_val_to_user}, + prelude::*, + process::signal::{c_types::sigaction_t, sig_action::SigAction, sig_num::SigNum}, + syscall::SYS_RT_SIGACTION, +}; + +use super::SyscallReturn; + +pub fn sys_rt_sigaction( + sig_num: u8, + sig_action_ptr: Vaddr, + old_sig_action_ptr: Vaddr, + sigset_size: u64, +) -> Result { + debug!("[syscall][id={}][SYS_RT_SIGACTION]", SYS_RT_SIGACTION); + let sig_num = SigNum::try_from(sig_num)?; + debug!("sig_num = {}", sig_num.sig_name()); + debug!("sig_action_ptr = 0x{:x}", sig_action_ptr); + debug!("old_sig_action_ptr = 0x{:x}", old_sig_action_ptr); + debug!("sigset_size = {}", sigset_size); + let sig_action_c = read_val_from_user::(sig_action_ptr); + debug!("sig_action_c = {:?}", sig_action_c); + let sig_action = SigAction::try_from(sig_action_c).unwrap(); + debug!("sig_action = {:x?}", sig_action); + + let current = current!(); + let mut sig_dispositions = current.sig_dispositions().lock(); + let old_action = sig_dispositions.get(sig_num); + debug!("old_action = {:x?}", old_action); + let old_action_c = old_action.to_c(); + debug!("old_action_c = {:x?}", old_action_c); + sig_dispositions.set(sig_num, sig_action); + write_val_to_user(old_sig_action_ptr, &old_action_c); + Ok(SyscallReturn::Return(0)) +} diff --git a/src/kxos-std/src/syscall/rt_sigprocmask.rs b/src/kxos-std/src/syscall/rt_sigprocmask.rs index ee2052d12..7ce7d29eb 100644 --- a/src/kxos-std/src/syscall/rt_sigprocmask.rs +++ b/src/kxos-std/src/syscall/rt_sigprocmask.rs @@ -1,13 +1,16 @@ use kxos_frame::vm::VmIo; -use crate::{prelude::*, syscall::SYS_RT_SIGPROCMASK}; +use crate::{ + prelude::*, + syscall::{SyscallReturn, SYS_RT_SIGPROCMASK}, +}; pub fn sys_rt_sigprocmask( how: u32, set_ptr: Vaddr, oldset_ptr: Vaddr, sigset_size: usize, -) -> Result { +) -> Result { debug!("[syscall][id={}][SYS_RT_SIGPROCMASK]", SYS_RT_SIGPROCMASK); let mask_op = MaskOp::try_from(how).unwrap(); debug!("mask op = {:?}", mask_op); @@ -18,7 +21,7 @@ pub fn sys_rt_sigprocmask( warn!("sigset size is not equal to 8"); } do_rt_sigprocmask(mask_op, set_ptr, oldset_ptr, sigset_size).unwrap(); - Ok(0) + Ok(SyscallReturn::Return(0)) } fn do_rt_sigprocmask( diff --git a/src/kxos-std/src/syscall/rt_sigreturn.rs b/src/kxos-std/src/syscall/rt_sigreturn.rs new file mode 100644 index 000000000..32df4110c --- /dev/null +++ b/src/kxos-std/src/syscall/rt_sigreturn.rs @@ -0,0 +1,14 @@ +use crate::prelude::*; +use kxos_frame::cpu::CpuContext; + +use super::SyscallReturn; + +pub fn sys_rt_sigreturn(context: &mut CpuContext) -> Result { + let current = current!(); + let sig_context = current.sig_context().lock().as_ref().unwrap().clone(); + *context = *sig_context.cpu_context(); + // unblock sig mask + let sig_mask = sig_context.sig_mask(); + current.sig_mask().lock().unblock(sig_mask.as_u64()); + Ok(SyscallReturn::NoReturn) +} diff --git a/src/kxos-std/src/syscall/sched_yield.rs b/src/kxos-std/src/syscall/sched_yield.rs index 2768661f3..074ba9bd7 100644 --- a/src/kxos-std/src/syscall/sched_yield.rs +++ b/src/kxos-std/src/syscall/sched_yield.rs @@ -2,8 +2,10 @@ use crate::prelude::*; use crate::{process::Process, syscall::SYS_SCHED_YIELD}; -pub fn sys_sched_yield() -> Result { +use super::SyscallReturn; + +pub fn sys_sched_yield() -> Result { debug!("[syscall][id={}][SYS_SCHED_YIELD]", SYS_SCHED_YIELD); Process::yield_now(); - Ok(0) + Ok(SyscallReturn::Return(0)) } diff --git a/src/kxos-std/src/syscall/tgkill.rs b/src/kxos-std/src/syscall/tgkill.rs index 0bdd713b6..7312f7899 100644 --- a/src/kxos-std/src/syscall/tgkill.rs +++ b/src/kxos-std/src/syscall/tgkill.rs @@ -2,10 +2,12 @@ use crate::prelude::*; use crate::syscall::SYS_TGKILL; -pub fn sys_tgkill(tgid: u64, pid: u64, signal: u64) -> Result { +use super::SyscallReturn; + +pub fn sys_tgkill(tgid: u64, pid: u64, signal: u64) -> Result { debug!("[syscall][id={}][SYS_TGKILL]", SYS_TGKILL); debug!("tgid = {}", tgid); debug!("pid = {}", pid); warn!("TODO: tgkill do nothing now"); - Ok(0) + Ok(SyscallReturn::Return(0)) } diff --git a/src/kxos-std/src/syscall/uname.rs b/src/kxos-std/src/syscall/uname.rs index 6d6140216..5b32b8391 100644 --- a/src/kxos-std/src/syscall/uname.rs +++ b/src/kxos-std/src/syscall/uname.rs @@ -2,6 +2,8 @@ use crate::prelude::*; use crate::{memory::write_val_to_user, syscall::SYS_UNAME}; +use super::SyscallReturn; + // We don't use the real name and version of our os here. Instead, we pick up fake values witch is the same as the ones of linux. // The values are used to fool glibc since glibc will check the version and os name. lazy_static! { @@ -56,10 +58,10 @@ fn copy_cstring_to_u8_slice(src: &CStr, dst: &mut [u8]) { dst[..len].copy_from_slice(&src[..len]); } -pub fn sys_uname(old_uname_addr: u64) -> Result { +pub fn sys_uname(old_uname_addr: u64) -> Result { debug!("[syscall][id={}][SYS_UNAME]", SYS_UNAME); do_sys_uname(old_uname_addr as Vaddr); - Ok(0) + Ok(SyscallReturn::Return(0)) } pub fn do_sys_uname(old_uname_addr: Vaddr) -> usize { diff --git a/src/kxos-std/src/syscall/wait4.rs b/src/kxos-std/src/syscall/wait4.rs index 41dabeebe..8e72e8e55 100644 --- a/src/kxos-std/src/syscall/wait4.rs +++ b/src/kxos-std/src/syscall/wait4.rs @@ -7,10 +7,12 @@ use crate::{ use crate::prelude::*; use crate::process::wait::WaitOptions; -pub fn sys_wait4(wait_pid: u64, exit_status_ptr: u64, wait_options: u64) -> Result { +use super::SyscallReturn; + +pub fn sys_wait4(wait_pid: u64, exit_status_ptr: u64, wait_options: u64) -> Result { debug!("[syscall][id={}][SYS_WAIT4]", SYS_WAIT4); let wait_options = WaitOptions::from_bits(wait_options as u32).expect("Unknown wait options"); - debug!("pid = {}", wait_pid as isize); + debug!("pid = {}", wait_pid as i32); debug!("exit_status_ptr = {}", exit_status_ptr); debug!("wait_options: {:?}", wait_options); let process_filter = ProcessFilter::from_id(wait_pid as _); @@ -18,6 +20,5 @@ pub fn sys_wait4(wait_pid: u64, exit_status_ptr: u64, wait_options: u64) -> Resu if return_pid != 0 && exit_status_ptr != 0 { write_val_to_user(exit_status_ptr as _, &exit_code); } - - Ok(return_pid as _) + Ok(SyscallReturn::Return(return_pid as _)) } diff --git a/src/kxos-std/src/syscall/waitid.rs b/src/kxos-std/src/syscall/waitid.rs index 04dbc5486..aa74091ed 100644 --- a/src/kxos-std/src/syscall/waitid.rs +++ b/src/kxos-std/src/syscall/waitid.rs @@ -3,16 +3,18 @@ use crate::process::{process_filter::ProcessFilter, wait::wait_child_exit}; use crate::process::wait::WaitOptions; +use super::SyscallReturn; + pub fn sys_waitid( which: u64, upid: u64, infoq_addr: u64, options: u64, rusage_addr: u64, -) -> Result { +) -> Result { // FIXME: what does infoq and rusage use for? let process_filter = ProcessFilter::from_which_and_id(which, upid); let wait_options = WaitOptions::from_bits(options as u32).expect("Unknown wait options"); let (exit_code, pid) = wait_child_exit(process_filter, wait_options); - Ok(pid as _) + Ok(SyscallReturn::Return(pid as _)) } diff --git a/src/kxos-std/src/syscall/write.rs b/src/kxos-std/src/syscall/write.rs index f2aed5df6..291d582e8 100644 --- a/src/kxos-std/src/syscall/write.rs +++ b/src/kxos-std/src/syscall/write.rs @@ -2,10 +2,12 @@ use crate::prelude::*; use crate::{memory::read_bytes_from_user, syscall::SYS_WRITE}; +use super::SyscallReturn; + const STDOUT: u64 = 1; const STDERR: u64 = 2; -pub fn sys_write(fd: u64, user_buf_ptr: u64, user_buf_len: u64) -> Result { +pub fn sys_write(fd: u64, user_buf_ptr: u64, user_buf_len: u64) -> Result { // only suppprt STDOUT now. debug!("[syscall][id={}][SYS_WRITE]", SYS_WRITE); @@ -18,8 +20,7 @@ pub fn sys_write(fd: u64, user_buf_ptr: u64, user_buf_len: u64) -> Result } else { info!("Error message from user mode: {:?}", content); } - - Ok(user_buf_len as _) + Ok(SyscallReturn::Return(user_buf_len as _)) } else { panic!("Unsupported fd number {}", fd); } diff --git a/src/kxos-std/src/syscall/writev.rs b/src/kxos-std/src/syscall/writev.rs index f70ab37b5..490488a54 100644 --- a/src/kxos-std/src/syscall/writev.rs +++ b/src/kxos-std/src/syscall/writev.rs @@ -5,6 +5,8 @@ use crate::{ syscall::SYS_WRITEV, }; +use super::SyscallReturn; + const IOVEC_MAX: usize = 256; #[repr(C)] @@ -14,10 +16,10 @@ pub struct IoVec { len: usize, } -pub fn sys_writev(fd: u64, io_vec_ptr: u64, io_vec_count: u64) -> Result { +pub fn sys_writev(fd: u64, io_vec_ptr: u64, io_vec_count: u64) -> Result { debug!("[syscall][id={}][SYS_WRITEV]", SYS_WRITEV); let res = do_sys_writev(fd, io_vec_ptr as Vaddr, io_vec_count as usize); - Ok(res as _) + Ok(SyscallReturn::Return(res as _)) } pub fn do_sys_writev(fd: u64, io_vec_ptr: Vaddr, io_vec_count: usize) -> usize { diff --git a/src/kxos-user/execve/execve b/src/kxos-user/execve/execve index 85ed4d0b3..673f205d3 100755 --- a/src/kxos-user/execve/execve +++ b/src/kxos-user/execve/execve @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:f98928f25e8223fd76d5d19db68e83913b48ea8b3cf6ae8d3120971e7271c93b +oid sha256:afc9465a8ae782da4e049d2b660a27b678394e683814c29a9601bc135126a0e5 size 871952 diff --git a/src/kxos-user/execve/execve.c b/src/kxos-user/execve/execve.c index 1db4a5ab9..547d9dae7 100644 --- a/src/kxos-user/execve/execve.c +++ b/src/kxos-user/execve/execve.c @@ -5,9 +5,10 @@ int main() { char* argv[] = { NULL }; char* envp[] = { NULL }; printf("Execve a new file ./hello:\n"); - // flust the stdout content to ensure the content print to console + // flush the stdout content to ensure the content print to console fflush(stdout); execve("./hello", argv, envp); printf("Should not print\n"); + fflush(stdout); return 0; } \ No newline at end of file diff --git a/src/kxos-user/fork_c/fork b/src/kxos-user/fork_c/fork index aacd152b4..8d7f960c3 100755 --- a/src/kxos-user/fork_c/fork +++ b/src/kxos-user/fork_c/fork @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:4f3b6fe8b52f200c469170223ea0cb2d06dbab6a5eb757e007eb0a751c5e1e81 +oid sha256:ca7a77a72da160f11670a04a16b623944295b9059399da45f57668f121b00d11 size 877152 diff --git a/src/kxos-user/fork_c/fork.c b/src/kxos-user/fork_c/fork.c index bac7950d0..dfbfc2efc 100644 --- a/src/kxos-user/fork_c/fork.c +++ b/src/kxos-user/fork_c/fork.c @@ -5,9 +5,9 @@ int main() { printf("before fork\n"); fflush(stdout); if(fork() == 0) { - printf("after fork: Hello from parent\n"); + printf("after fork: Hello from child\n"); } else { - printf("after fork: Hello from child\n"); + printf("after fork: Hello from parent\n"); } fflush(stdout); return 0; diff --git a/src/kxos-user/signal_c/sig_action b/src/kxos-user/signal_c/sig_action index 42d39e3a8..348d203fc 100755 --- a/src/kxos-user/signal_c/sig_action +++ b/src/kxos-user/signal_c/sig_action @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:08b21d340c8d144c1bfb86097e46ceda6d690041269cf56fee5bd8918e8253fa +oid sha256:1938c6e8abd70c400780dd8aa089d768a8662d54bac2a658936790d5537e868c size 877544 diff --git a/src/kxos-user/signal_c/sig_action.c b/src/kxos-user/signal_c/sig_action.c index c1927c1f7..7f33bb9e7 100644 --- a/src/kxos-user/signal_c/sig_action.c +++ b/src/kxos-user/signal_c/sig_action.c @@ -7,7 +7,7 @@ int sigchld = 0; void proc_exit() { - sigchld = 999; + sigchld = sigchld + 1; } int main() {