mirror of
https://github.com/asterinas/asterinas.git
synced 2025-06-21 16:33:24 +00:00
Merge pull request #38 from StevenJiang1110/signal
Add basic support for signal
This commit is contained in:
3
.gitattributes
vendored
3
.gitattributes
vendored
@ -4,3 +4,6 @@ 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
|
||||
src/kxos-user/signal_c/sig_action filter=lfs diff=lfs merge=lfs -text
|
4
src/Cargo.lock
generated
4
src/Cargo.lock
generated
@ -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"
|
||||
|
@ -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]
|
||||
|
@ -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<D: Clone + Eq + PartialEq> Waiter<D> {
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
@ -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,
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
);
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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)?;
|
||||
|
14
src/kxos-std/src/process/exception.rs
Normal file
14
src/kxos-std/src/process/exception.rs
Normal file
@ -0,0 +1,14 @@
|
||||
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);
|
||||
debug!("cpu context = {:x?}", context);
|
||||
let signal = Box::new(FaultSignal::new(&trap_info));
|
||||
current.sig_queues().lock().enqueue(signal);
|
||||
}
|
@ -5,17 +5,27 @@ 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::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::signal::SigContext;
|
||||
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;
|
||||
pub mod process_vm;
|
||||
pub mod signal;
|
||||
pub mod status;
|
||||
pub mod table;
|
||||
pub mod task;
|
||||
@ -47,6 +57,16 @@ pub struct Process {
|
||||
parent: Mutex<Option<Weak<Process>>>,
|
||||
/// Children processes
|
||||
children: Mutex<BTreeMap<usize, Arc<Process>>>,
|
||||
/// Process group
|
||||
process_group: Mutex<Option<Weak<ProcessGroup>>>,
|
||||
|
||||
// Signal
|
||||
sig_dispositions: Mutex<SigDispositions>,
|
||||
sig_queues: Mutex<SigQueues>,
|
||||
/// Process-level sigmask
|
||||
sig_mask: Mutex<SigMask>,
|
||||
/// Signal handler Context
|
||||
sig_context: Mutex<Option<SigContext>>,
|
||||
}
|
||||
|
||||
impl Process {
|
||||
@ -69,6 +89,10 @@ impl Process {
|
||||
exec_filename: Option<CString>,
|
||||
user_vm: Option<UserVm>,
|
||||
user_space: Option<Arc<UserSpace>>,
|
||||
process_group: Option<Weak<ProcessGroup>>,
|
||||
sig_dispositions: SigDispositions,
|
||||
sig_queues: SigQueues,
|
||||
sig_mask: SigMask,
|
||||
) -> Self {
|
||||
let parent = if pid == 0 {
|
||||
debug!("Init process does not has parent");
|
||||
@ -91,6 +115,11 @@ 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),
|
||||
sig_context: Mutex::new(None),
|
||||
}
|
||||
}
|
||||
|
||||
@ -124,8 +153,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 +182,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 +209,25 @@ 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<Option<Weak<ProcessGroup>>> {
|
||||
&self.process_group
|
||||
}
|
||||
|
||||
pub fn sig_context(&self) -> &Mutex<Option<SigContext>> {
|
||||
&self.sig_context
|
||||
}
|
||||
|
||||
/// add a child process
|
||||
@ -165,6 +241,23 @@ impl Process {
|
||||
let _ = self.parent.lock().insert(parent);
|
||||
}
|
||||
|
||||
pub fn set_process_group(&self, process_group: Weak<ProcessGroup>) {
|
||||
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<Self>) {
|
||||
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<Arc<Process>> {
|
||||
self.parent
|
||||
.lock()
|
||||
@ -173,17 +266,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() {
|
||||
@ -194,8 +283,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| {
|
||||
@ -263,19 +355,24 @@ 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() == ProcessStatus::Zombie);
|
||||
table::delete_process(child_process.pid());
|
||||
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()
|
||||
}
|
||||
|
||||
/// Get any zombie child
|
||||
pub fn get_zombie_child(&self) -> Option<Arc<Process>> {
|
||||
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 +392,20 @@ impl Process {
|
||||
self.filename.as_ref()
|
||||
}
|
||||
|
||||
pub fn status(&self) -> ProcessStatus {
|
||||
self.status.lock().clone()
|
||||
pub fn status(&self) -> &Mutex<ProcessStatus> {
|
||||
&self.status
|
||||
}
|
||||
|
||||
pub fn sig_dispositions(&self) -> &Mutex<SigDispositions> {
|
||||
&self.sig_dispositions
|
||||
}
|
||||
|
||||
pub fn sig_queues(&self) -> &Mutex<SigQueues> {
|
||||
&self.sig_queues
|
||||
}
|
||||
|
||||
pub fn sig_mask(&self) -> &Mutex<SigMask> {
|
||||
&self.sig_mask
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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: 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 {
|
||||
// process group ID is equal to the absolute value of pid.
|
||||
ProcessFilter::WithPgid((-wait_pid) as Pgid)
|
||||
|
61
src/kxos-std/src/process/process_group.rs
Normal file
61
src/kxos-std/src/process/process_group.rs
Normal file
@ -0,0 +1,61 @@
|
||||
use super::{table, Pgid, Pid, Process};
|
||||
use crate::prelude::*;
|
||||
|
||||
pub struct ProcessGroup {
|
||||
inner: Mutex<ProcessGroupInner>,
|
||||
}
|
||||
|
||||
struct ProcessGroupInner {
|
||||
pgid: Pgid,
|
||||
processes: BTreeMap<Pid, Arc<Process>>,
|
||||
leader_process: Option<Arc<Process>>,
|
||||
}
|
||||
|
||||
impl ProcessGroup {
|
||||
fn default() -> Self {
|
||||
ProcessGroup {
|
||||
inner: Mutex::new(ProcessGroupInner {
|
||||
pgid: 0,
|
||||
processes: BTreeMap::new(),
|
||||
leader_process: None,
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new(process: Arc<Process>) -> 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<Process>) {
|
||||
self.inner.lock().leader_process = Some(leader_process);
|
||||
}
|
||||
|
||||
pub fn add_process(&self, process: Arc<Process>) {
|
||||
self.inner.lock().processes.insert(process.pid(), process);
|
||||
}
|
||||
|
||||
pub fn remove_process(&self, pid: 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 {
|
||||
self.inner.lock().pgid
|
||||
}
|
||||
}
|
13
src/kxos-std/src/process/signal/c_types.rs
Normal file
13
src/kxos-std/src/process/signal/c_types.rs
Normal file
@ -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,
|
||||
}
|
103
src/kxos-std/src/process/signal/constants.rs
Normal file
103
src/kxos-std/src/process/signal/constants.rs
Normal file
@ -0,0 +1,103 @@
|
||||
/// 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)
|
||||
}
|
||||
|
||||
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;
|
171
src/kxos-std/src/process/signal/mod.rs
Normal file
171
src/kxos-std/src/process/signal/mod.rs
Normal file
@ -0,0 +1,171 @@
|
||||
pub mod c_types;
|
||||
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 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(context: &mut CpuContext) {
|
||||
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_name = {}", sig_num, sig_num.sig_name());
|
||||
let sig_action = current.sig_dispositions().lock().get(sig_num);
|
||||
debug!("sig action: {:x?}", sig_action);
|
||||
match sig_action {
|
||||
SigAction::Ign => {
|
||||
debug!("Ignore signal {:?}", sig_num);
|
||||
}
|
||||
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);
|
||||
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 => {
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
}
|
148
src/kxos-std/src/process/signal/sig_action.rs
Normal file
148
src/kxos-std/src/process/signal/sig_action.rs
Normal file
@ -0,0 +1,148 @@
|
||||
use super::{c_types::sigaction_t, constants::*, sig_mask::SigMask, sig_num::SigNum};
|
||||
use crate::prelude::*;
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<sigaction_t> for SigAction {
|
||||
type Error = Error;
|
||||
|
||||
fn try_from(input: sigaction_t) -> Result<Self> {
|
||||
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;
|
||||
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<u32> for SigActionFlags {
|
||||
type Error = Error;
|
||||
|
||||
fn try_from(bits: u32) -> Result<Self> {
|
||||
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");
|
||||
}
|
||||
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,
|
||||
}
|
||||
}
|
||||
}
|
49
src/kxos-std/src/process/signal/sig_disposition.rs
Normal file
49
src/kxos-std/src/process/signal/sig_disposition.rs
Normal file
@ -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
|
||||
}
|
||||
}
|
59
src/kxos-std/src/process/signal/sig_mask.rs
Normal file
59
src/kxos-std/src/process/signal/sig_mask.rs
Normal file
@ -0,0 +1,59 @@
|
||||
use super::{constants::MIN_STD_SIG_NUM, sig_num::SigNum};
|
||||
|
||||
#[derive(Debug, Copy, Clone, Default, PartialEq, Eq)]
|
||||
pub struct SigMask {
|
||||
bits: u64,
|
||||
}
|
||||
|
||||
impl From<u64> for SigMask {
|
||||
fn from(bits: u64) -> Self {
|
||||
SigMask { bits }
|
||||
}
|
||||
}
|
||||
|
||||
impl SigMask {
|
||||
pub fn new_empty() -> Self {
|
||||
SigMask::from(0u64)
|
||||
}
|
||||
|
||||
pub fn new_full() -> Self {
|
||||
SigMask::from(!0u64)
|
||||
}
|
||||
|
||||
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 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
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
}
|
77
src/kxos-std/src/process/signal/sig_num.rs
Normal file
77
src/kxos-std/src/process/signal/sig_num.rs
Normal file
@ -0,0 +1,77 @@
|
||||
use super::constants::*;
|
||||
use crate::prelude::*;
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub struct SigNum {
|
||||
sig_num: u8,
|
||||
}
|
||||
|
||||
impl TryFrom<u8> for SigNum {
|
||||
type Error = Error;
|
||||
|
||||
fn try_from(sig_num: u8) -> Result<Self> {
|
||||
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 {
|
||||
/// 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 {
|
||||
panic!("invalid signal number")
|
||||
}
|
||||
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
|
||||
}
|
||||
|
||||
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",
|
||||
}
|
||||
}
|
||||
}
|
143
src/kxos-std/src/process/signal/sig_queues.rs
Normal file
143
src/kxos-std/src/process/signal/sig_queues.rs
Normal file
@ -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<Option<Box<dyn Signal>>>,
|
||||
rt_queues: Vec<VecDeque<Box<dyn Signal>>>,
|
||||
}
|
||||
|
||||
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<dyn Signal>) {
|
||||
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<Box<dyn Signal>> {
|
||||
// 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::try_from(signum).unwrap();
|
||||
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<Box<dyn Signal>> {
|
||||
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<Box<dyn Signal>> {
|
||||
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()
|
||||
}
|
||||
}
|
51
src/kxos-std/src/process/signal/signals/fault.rs
Normal file
51
src/kxos-std/src/process/signal/signals/fault.rs
Normal file
@ -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<u64>,
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
}
|
20
src/kxos-std/src/process/signal/signals/kernel.rs
Normal file
20
src/kxos-std/src/process/signal/signals/kernel.rs
Normal file
@ -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
|
||||
}
|
||||
}
|
12
src/kxos-std/src/process/signal/signals/mod.rs
Normal file
12
src/kxos-std/src/process/signal/signals/mod.rs
Normal file
@ -0,0 +1,12 @@
|
||||
pub mod fault;
|
||||
pub mod kernel;
|
||||
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;
|
||||
}
|
49
src/kxos-std/src/process/signal/signals/user.rs
Normal file
49
src/kxos-std/src/process/signal/signals/user.rs
Normal file
@ -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
|
||||
}
|
||||
}
|
@ -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
|
||||
}
|
||||
}
|
||||
|
@ -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<BTreeMap<Pid, Arc<Process>>> = Mutex::new(BTreeMap::new());
|
||||
static ref PROCESS_GROUP_TABLE: Mutex<BTreeMap<Pgid, Arc<ProcessGroup>>> =
|
||||
Mutex::new(BTreeMap::new());
|
||||
}
|
||||
|
||||
/// add a process to global table
|
||||
@ -15,8 +17,8 @@ pub fn add_process(pid: Pid, process: Arc<Process>) {
|
||||
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<Arc<Process>> {
|
||||
.map(|(_, process)| process.clone())
|
||||
.collect()
|
||||
}
|
||||
|
||||
/// add process group to global table
|
||||
pub fn add_process_group(pgid: Pgid, process_group: Arc<ProcessGroup>) {
|
||||
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<Arc<ProcessGroup>> {
|
||||
PROCESS_GROUP_TABLE
|
||||
.lock()
|
||||
.get(&pgid)
|
||||
.map(|process_group| process_group.clone())
|
||||
}
|
||||
|
@ -7,9 +7,12 @@ use kxos_frame::{
|
||||
vm::VmSpace,
|
||||
};
|
||||
|
||||
use crate::prelude::*;
|
||||
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};
|
||||
|
||||
@ -47,28 +50,35 @@ pub fn create_new_task(userspace: Arc<UserSpace>, parent: Weak<Process>) -> 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(context);
|
||||
if current.status().lock().is_zombie() {
|
||||
debug!("exit due to signal");
|
||||
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(context);
|
||||
}
|
||||
}
|
||||
let current_process = Process::current();
|
||||
current_process.exit();
|
||||
debug!("exit user loop");
|
||||
}
|
||||
|
||||
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::Syscall => handle_syscall(context),
|
||||
UserEvent::Fault => todo!(),
|
||||
UserEvent::Exception => todo!(),
|
||||
UserEvent::Exception => handle_exception(context),
|
||||
}
|
||||
}
|
||||
|
||||
pub enum HandlerResult {
|
||||
Exit,
|
||||
Continue,
|
||||
}
|
||||
|
@ -1,13 +1,12 @@
|
||||
use super::constants::*;
|
||||
use super::SyscallResult;
|
||||
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) -> SyscallResult {
|
||||
pub fn sys_access(filename_ptr: Vaddr, file_mode: u64) -> Result<SyscallReturn> {
|
||||
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(SyscallReturn::Return(0))
|
||||
}
|
||||
|
@ -1,7 +1,9 @@
|
||||
use kxos_frame::cpu::CpuContext;
|
||||
|
||||
use crate::prelude::*;
|
||||
use crate::syscall::{SyscallResult, SYS_ARCH_PRCTL};
|
||||
use crate::syscall::SYS_ARCH_PRCTL;
|
||||
|
||||
use super::SyscallReturn;
|
||||
|
||||
#[allow(non_camel_case_types)]
|
||||
#[derive(Debug)]
|
||||
@ -26,17 +28,12 @@ impl TryFrom<u64> 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<SyscallReturn> {
|
||||
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(SyscallReturn::Return(res as _))
|
||||
}
|
||||
|
||||
pub fn do_arch_prctl(code: ArchPrctlCode, addr: u64, context: &mut CpuContext) -> Result<u64> {
|
||||
|
@ -1,12 +1,10 @@
|
||||
use crate::prelude::*;
|
||||
|
||||
use crate::{
|
||||
process::Process,
|
||||
syscall::{SyscallResult, SYS_BRK},
|
||||
};
|
||||
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) -> SyscallResult {
|
||||
pub fn sys_brk(heap_end: u64) -> Result<SyscallReturn> {
|
||||
debug!("[syscall][id={}][SYS_BRK]", SYS_BRK);
|
||||
let current = Process::current();
|
||||
let new_heap_end = if heap_end == 0 {
|
||||
@ -23,5 +21,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(SyscallReturn::Return(new_heap_end as _))
|
||||
}
|
||||
|
@ -1,9 +1,10 @@
|
||||
use kxos_frame::cpu::CpuContext;
|
||||
|
||||
use super::SyscallResult;
|
||||
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(
|
||||
@ -13,7 +14,7 @@ pub fn sys_clone(
|
||||
child_tidptr: Vaddr,
|
||||
tls: usize,
|
||||
parent_context: CpuContext,
|
||||
) -> SyscallResult {
|
||||
) -> Result<SyscallReturn> {
|
||||
debug!("[syscall][id={}][SYS_CLONE]", SYS_CLONE);
|
||||
debug!("flags = {}", clone_flags);
|
||||
let clone_flags = CloneFlags::from(clone_flags);
|
||||
@ -29,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);
|
||||
SyscallResult::Return(child_pid as _)
|
||||
Ok(SyscallReturn::Return(child_pid as _))
|
||||
}
|
||||
|
@ -1,7 +1,6 @@
|
||||
use kxos_frame::cpu::CpuContext;
|
||||
|
||||
use super::constants::*;
|
||||
use super::SyscallResult;
|
||||
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};
|
||||
|
||||
@ -10,7 +9,7 @@ pub fn sys_execve(
|
||||
argv_ptr_ptr: Vaddr,
|
||||
envp_ptr_ptr: Vaddr,
|
||||
context: &mut CpuContext,
|
||||
) -> SyscallResult {
|
||||
) -> Result<SyscallReturn> {
|
||||
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);
|
||||
@ -35,15 +34,18 @@ 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;
|
||||
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());
|
||||
SyscallResult::Return(0)
|
||||
Ok(SyscallReturn::NoReturn)
|
||||
}
|
||||
|
@ -1,11 +1,9 @@
|
||||
use crate::prelude::*;
|
||||
|
||||
use crate::{process::Process, syscall::SYS_EXIT};
|
||||
use crate::syscall::{SyscallReturn, SYS_EXIT};
|
||||
|
||||
use super::SyscallResult;
|
||||
|
||||
pub fn sys_exit(exit_code: i32) -> SyscallResult {
|
||||
pub fn sys_exit(exit_code: i32) -> Result<SyscallReturn> {
|
||||
debug!("[syscall][id={}][SYS_EXIT]", SYS_EXIT);
|
||||
Process::current().set_exit_code(exit_code);
|
||||
SyscallResult::Exit(exit_code)
|
||||
current!().exit(exit_code);
|
||||
Ok(SyscallReturn::Return(0))
|
||||
}
|
||||
|
@ -1,12 +1,9 @@
|
||||
use crate::prelude::*;
|
||||
|
||||
use crate::{
|
||||
process::Process,
|
||||
syscall::{SyscallResult, SYS_EXIT_GROUP},
|
||||
};
|
||||
use crate::syscall::{SyscallReturn, SYS_EXIT_GROUP};
|
||||
|
||||
pub fn sys_exit_group(exit_code: u64) -> SyscallResult {
|
||||
pub fn sys_exit_group(exit_code: u64) -> Result<SyscallReturn> {
|
||||
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 _);
|
||||
Ok(SyscallReturn::Return(0))
|
||||
}
|
||||
|
@ -6,12 +6,12 @@ use kxos_frame::cpu::CpuContext;
|
||||
|
||||
use crate::{process::Process, syscall::SYS_FORK};
|
||||
|
||||
use super::SyscallResult;
|
||||
use super::SyscallReturn;
|
||||
|
||||
pub fn sys_fork(parent_context: CpuContext) -> SyscallResult {
|
||||
pub fn sys_fork(parent_context: CpuContext) -> Result<SyscallReturn> {
|
||||
debug!("[syscall][id={}][SYS_FORK]", SYS_FORK);
|
||||
let child_process = fork(parent_context);
|
||||
SyscallResult::Return(child_process.pid() as _)
|
||||
Ok(SyscallReturn::Return(child_process.pid() as _))
|
||||
}
|
||||
|
||||
/// Fork a child process
|
||||
|
@ -3,12 +3,12 @@ use kxos_frame::vm::VmIo;
|
||||
use crate::fs::stat::Stat;
|
||||
use crate::prelude::*;
|
||||
|
||||
use crate::syscall::{SyscallResult, SYS_FSTAT};
|
||||
use crate::syscall::{SyscallReturn, SYS_FSTAT};
|
||||
|
||||
pub fn sys_fstat(fd: u64, stat_buf_addr: Vaddr) -> SyscallResult {
|
||||
pub fn sys_fstat(fd: u64, stat_buf_ptr: Vaddr) -> Result<SyscallReturn> {
|
||||
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,10 +17,10 @@ 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);
|
||||
return Ok(SyscallReturn::Return(0));
|
||||
}
|
||||
warn!("TODO: fstat only returns fake result now.");
|
||||
SyscallResult::Return(0)
|
||||
Ok(SyscallReturn::Return(0))
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
use crate::syscall::SyscallReturn;
|
||||
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 +18,7 @@ pub fn sys_futex(
|
||||
utime_addr: u64,
|
||||
futex_new_addr: u64,
|
||||
bitset: u64,
|
||||
) -> SyscallResult {
|
||||
) -> Result<SyscallReturn> {
|
||||
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 +70,7 @@ pub fn sys_futex(
|
||||
}
|
||||
.unwrap();
|
||||
|
||||
SyscallResult::Return(res as _)
|
||||
Ok(SyscallReturn::Return(res as _))
|
||||
}
|
||||
|
||||
/// do futex wait
|
||||
|
9
src/kxos-std/src/syscall/getegid.rs
Normal file
9
src/kxos-std/src/syscall/getegid.rs
Normal file
@ -0,0 +1,9 @@
|
||||
use crate::{prelude::*, syscall::SYS_GETEGID};
|
||||
|
||||
use super::SyscallReturn;
|
||||
|
||||
pub fn sys_getegid() -> Result<SyscallReturn> {
|
||||
debug!("[syscall][id={}][SYS_GETEGID]", SYS_GETEGID);
|
||||
warn!("TODO: getegid only return a fake egid now");
|
||||
Ok(SyscallReturn::Return(0))
|
||||
}
|
9
src/kxos-std/src/syscall/geteuid.rs
Normal file
9
src/kxos-std/src/syscall/geteuid.rs
Normal file
@ -0,0 +1,9 @@
|
||||
use crate::{prelude::*, syscall::SYS_GETEUID};
|
||||
|
||||
use super::SyscallReturn;
|
||||
|
||||
pub fn sys_geteuid() -> Result<SyscallReturn> {
|
||||
debug!("[syscall][id={}][SYS_GETEUID]", SYS_GETEUID);
|
||||
warn!("TODO: geteuid only return a fake euid now");
|
||||
Ok(SyscallReturn::Return(0))
|
||||
}
|
9
src/kxos-std/src/syscall/getgid.rs
Normal file
9
src/kxos-std/src/syscall/getgid.rs
Normal file
@ -0,0 +1,9 @@
|
||||
use crate::{prelude::*, syscall::SYS_GETGID};
|
||||
|
||||
use super::SyscallReturn;
|
||||
|
||||
pub fn sys_getgid() -> Result<SyscallReturn> {
|
||||
debug!("[syscall][id={}][SYS_GETGID]", SYS_GETGID);
|
||||
warn!("TODO: getgid only return a fake gid now");
|
||||
Ok(SyscallReturn::Return(0))
|
||||
}
|
@ -2,11 +2,11 @@ use crate::prelude::*;
|
||||
|
||||
use crate::{process::Process, syscall::SYS_GETPID};
|
||||
|
||||
use super::SyscallResult;
|
||||
use super::SyscallReturn;
|
||||
|
||||
pub fn sys_getpid() -> SyscallResult {
|
||||
pub fn sys_getpid() -> Result<SyscallReturn> {
|
||||
debug!("[syscall][id={}][SYS_GETPID]", SYS_GETPID);
|
||||
let pid = Process::current().pid();
|
||||
info!("[sys_getpid]: pid = {}", pid);
|
||||
SyscallResult::Return(pid as _)
|
||||
Ok(SyscallReturn::Return(pid as _))
|
||||
}
|
||||
|
@ -2,11 +2,11 @@ use crate::prelude::*;
|
||||
|
||||
use crate::{process::Process, syscall::SYS_GETTID};
|
||||
|
||||
use super::SyscallResult;
|
||||
use super::SyscallReturn;
|
||||
|
||||
pub fn sys_gettid() -> SyscallResult {
|
||||
pub fn sys_gettid() -> Result<SyscallReturn> {
|
||||
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(SyscallReturn::Return(tid as _))
|
||||
}
|
||||
|
9
src/kxos-std/src/syscall/getuid.rs
Normal file
9
src/kxos-std/src/syscall/getuid.rs
Normal file
@ -0,0 +1,9 @@
|
||||
use crate::{prelude::*, syscall::SYS_GETUID};
|
||||
|
||||
use super::SyscallReturn;
|
||||
|
||||
pub fn sys_getuid() -> Result<SyscallReturn> {
|
||||
debug!("[syscall][id={}][SYS_GETUID]", SYS_GETUID);
|
||||
warn!("TODO: getuid only return a fake uid now");
|
||||
Ok(SyscallReturn::Return(0))
|
||||
}
|
55
src/kxos-std/src/syscall/kill.rs
Normal file
55
src/kxos-std/src/syscall/kill.rs
Normal file
@ -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::SyscallReturn;
|
||||
|
||||
pub fn sys_kill(process_filter: u64, sig_num: u64) -> Result<SyscallReturn> {
|
||||
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(SyscallReturn::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<Vec<Arc<Process>>> {
|
||||
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)
|
||||
}
|
@ -6,7 +6,7 @@ use kxos_frame::vm::VmPerm;
|
||||
|
||||
use crate::{process::Process, syscall::SYS_MMAP};
|
||||
|
||||
use super::SyscallResult;
|
||||
use super::SyscallReturn;
|
||||
|
||||
pub fn sys_mmap(
|
||||
addr: u64,
|
||||
@ -15,7 +15,7 @@ pub fn sys_mmap(
|
||||
flags: u64,
|
||||
fd: u64,
|
||||
offset: u64,
|
||||
) -> SyscallResult {
|
||||
) -> Result<SyscallReturn> {
|
||||
debug!("[syscall][id={}][SYS_MMAP]", SYS_MMAP);
|
||||
let perms = VmPerm::try_from(perms).unwrap();
|
||||
let flags = MMapFlags::try_from(flags).unwrap();
|
||||
@ -27,7 +27,7 @@ pub fn sys_mmap(
|
||||
fd as usize,
|
||||
offset as usize,
|
||||
);
|
||||
SyscallResult::Return(res as _)
|
||||
Ok(SyscallReturn::Return(res as _))
|
||||
}
|
||||
|
||||
pub fn do_sys_mmap(
|
||||
|
@ -1,32 +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 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;
|
||||
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;
|
||||
@ -39,11 +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;
|
||||
@ -52,44 +66,56 @@ 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_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],
|
||||
}
|
||||
|
||||
pub enum SyscallResult {
|
||||
Exit(i32),
|
||||
Return(i32),
|
||||
ReturnNothing, // execve return nothing
|
||||
/// 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 {
|
||||
@ -109,19 +135,21 @@ impl SyscallArgument {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn syscall_handler(context: &mut CpuContext) -> HandlerResult {
|
||||
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);
|
||||
|
||||
match syscall_return {
|
||||
SyscallResult::Return(return_value) => {
|
||||
// FIXME: set return value?
|
||||
context.gp_regs.rax = return_value as u64;
|
||||
HandlerResult::Continue
|
||||
Ok(return_value) => {
|
||||
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
|
||||
}
|
||||
SyscallResult::Exit(exit_code) => HandlerResult::Exit,
|
||||
SyscallResult::ReturnNothing => HandlerResult::Continue,
|
||||
}
|
||||
}
|
||||
|
||||
@ -129,78 +157,76 @@ pub fn syscall_dispatch(
|
||||
syscall_number: u64,
|
||||
args: [u64; 6],
|
||||
context: &mut CpuContext,
|
||||
) -> SyscallResult {
|
||||
) -> Result<SyscallReturn> {
|
||||
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(),
|
||||
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_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() -> SyscallResult {
|
||||
debug!("[syscall][id={}][SYS_RT_SIGACTION]", SYS_RT_SIGACTION);
|
||||
warn!("TODO: rt_sigaction only return a fake result");
|
||||
SyscallResult::Return(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_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");
|
||||
SyscallResult::Return(0)
|
||||
}
|
||||
|
||||
pub fn sys_getgid() -> SyscallResult {
|
||||
debug!("[syscall][id={}][SYS_GETGID]", SYS_GETUID);
|
||||
warn!("TODO: getgid only return a fake gid now");
|
||||
SyscallResult::Return(0)
|
||||
}
|
||||
|
||||
pub fn sys_geteuid() -> SyscallResult {
|
||||
debug!("[syscall][id={}][SYS_GETEUID]", SYS_GETEUID);
|
||||
warn!("TODO: geteuid only return a fake euid now");
|
||||
SyscallResult::Return(0)
|
||||
}
|
||||
|
||||
pub fn sys_getegid() -> SyscallResult {
|
||||
debug!("[syscall][id={}][SYS_GETEGID]", SYS_GETEGID);
|
||||
warn!("TODO: getegid only return a fake egid now");
|
||||
SyscallResult::Return(0)
|
||||
#[macro_export]
|
||||
macro_rules! define_syscall_nums {
|
||||
( $( $name: ident = $num: expr ),+ ) => {
|
||||
$(
|
||||
const $name: u64 = $num;
|
||||
)*
|
||||
}
|
||||
}
|
||||
|
@ -4,13 +4,13 @@ use crate::prelude::*;
|
||||
|
||||
use crate::syscall::SYS_MPROTECT;
|
||||
|
||||
use super::SyscallResult;
|
||||
use super::SyscallReturn;
|
||||
|
||||
pub fn sys_mprotect(vaddr: u64, len: u64, perms: u64) -> SyscallResult {
|
||||
pub fn sys_mprotect(vaddr: u64, len: u64, perms: u64) -> Result<SyscallReturn> {
|
||||
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(SyscallReturn::Return(0))
|
||||
}
|
||||
|
||||
pub fn do_sys_mprotect(addr: Vaddr, len: usize, perms: VmPerm) -> isize {
|
||||
|
@ -6,18 +6,22 @@ use crate::{
|
||||
syscall::SYS_READLINK,
|
||||
};
|
||||
|
||||
use super::SyscallResult;
|
||||
use super::SyscallReturn;
|
||||
|
||||
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<SyscallReturn> {
|
||||
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(SyscallReturn::Return(res as _))
|
||||
}
|
||||
|
||||
/// do sys readlink
|
||||
|
36
src/kxos-std/src/syscall/rt_sigaction.rs
Normal file
36
src/kxos-std/src/syscall/rt_sigaction.rs
Normal file
@ -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<SyscallReturn> {
|
||||
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::<sigaction_t>(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))
|
||||
}
|
75
src/kxos-std/src/syscall/rt_sigprocmask.rs
Normal file
75
src/kxos-std/src/syscall/rt_sigprocmask.rs
Normal file
@ -0,0 +1,75 @@
|
||||
use kxos_frame::vm::VmIo;
|
||||
|
||||
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<SyscallReturn> {
|
||||
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();
|
||||
Ok(SyscallReturn::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::<u64>(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<u32> for MaskOp {
|
||||
type Error = Error;
|
||||
|
||||
fn try_from(value: u32) -> Result<Self> {
|
||||
let op = match value {
|
||||
0 => MaskOp::Block,
|
||||
1 => MaskOp::Unblock,
|
||||
2 => MaskOp::SetMask,
|
||||
_ => return_errno_with_message!(Errno::EINVAL, "invalid mask op"),
|
||||
};
|
||||
Ok(op)
|
||||
}
|
||||
}
|
14
src/kxos-std/src/syscall/rt_sigreturn.rs
Normal file
14
src/kxos-std/src/syscall/rt_sigreturn.rs
Normal file
@ -0,0 +1,14 @@
|
||||
use crate::prelude::*;
|
||||
use kxos_frame::cpu::CpuContext;
|
||||
|
||||
use super::SyscallReturn;
|
||||
|
||||
pub fn sys_rt_sigreturn(context: &mut CpuContext) -> Result<SyscallReturn> {
|
||||
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)
|
||||
}
|
@ -2,10 +2,10 @@ use crate::prelude::*;
|
||||
|
||||
use crate::{process::Process, syscall::SYS_SCHED_YIELD};
|
||||
|
||||
use super::SyscallResult;
|
||||
use super::SyscallReturn;
|
||||
|
||||
pub fn sys_sched_yield() -> SyscallResult {
|
||||
pub fn sys_sched_yield() -> Result<SyscallReturn> {
|
||||
debug!("[syscall][id={}][SYS_SCHED_YIELD]", SYS_SCHED_YIELD);
|
||||
Process::yield_now();
|
||||
SyscallResult::Return(0)
|
||||
Ok(SyscallReturn::Return(0))
|
||||
}
|
||||
|
@ -1,11 +1,13 @@
|
||||
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 {
|
||||
use super::SyscallReturn;
|
||||
|
||||
pub fn sys_tgkill(tgid: u64, pid: u64, signal: u64) -> Result<SyscallReturn> {
|
||||
debug!("[syscall][id={}][SYS_TGKILL]", SYS_TGKILL);
|
||||
debug!("tgid = {}", tgid);
|
||||
debug!("pid = {}", pid);
|
||||
warn!("TODO: tgkill do nothing now");
|
||||
SyscallResult::Return(0)
|
||||
Ok(SyscallReturn::Return(0))
|
||||
}
|
||||
|
@ -1,9 +1,8 @@
|
||||
use crate::prelude::*;
|
||||
|
||||
use crate::{
|
||||
memory::write_val_to_user,
|
||||
syscall::{SyscallResult, SYS_UNAME},
|
||||
};
|
||||
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.
|
||||
@ -59,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) -> SyscallResult {
|
||||
pub fn sys_uname(old_uname_addr: u64) -> Result<SyscallReturn> {
|
||||
debug!("[syscall][id={}][SYS_UNAME]", SYS_UNAME);
|
||||
do_sys_uname(old_uname_addr as Vaddr);
|
||||
SyscallResult::Return(0)
|
||||
Ok(SyscallReturn::Return(0))
|
||||
}
|
||||
|
||||
pub fn do_sys_uname(old_uname_addr: Vaddr) -> usize {
|
||||
|
@ -4,21 +4,21 @@ 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 {
|
||||
use super::SyscallReturn;
|
||||
|
||||
pub fn sys_wait4(wait_pid: u64, exit_status_ptr: u64, wait_options: u64) -> Result<SyscallReturn> {
|
||||
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_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);
|
||||
}
|
||||
|
||||
SyscallResult::Return(return_pid as _)
|
||||
Ok(SyscallReturn::Return(return_pid as _))
|
||||
}
|
||||
|
@ -1,18 +1,20 @@
|
||||
use crate::prelude::*;
|
||||
use crate::process::{process_filter::ProcessFilter, wait::wait_child_exit};
|
||||
|
||||
use super::SyscallResult;
|
||||
use crate::process::wait::WaitOptions;
|
||||
|
||||
use super::SyscallReturn;
|
||||
|
||||
pub fn sys_waitid(
|
||||
which: u64,
|
||||
upid: u64,
|
||||
infoq_addr: u64,
|
||||
options: u64,
|
||||
rusage_addr: u64,
|
||||
) -> SyscallResult {
|
||||
) -> Result<SyscallReturn> {
|
||||
// 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(SyscallReturn::Return(pid as _))
|
||||
}
|
||||
|
@ -2,12 +2,12 @@ use crate::prelude::*;
|
||||
|
||||
use crate::{memory::read_bytes_from_user, syscall::SYS_WRITE};
|
||||
|
||||
use super::SyscallResult;
|
||||
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) -> SyscallResult {
|
||||
pub fn sys_write(fd: u64, user_buf_ptr: u64, user_buf_len: u64) -> Result<SyscallReturn> {
|
||||
// only suppprt STDOUT now.
|
||||
debug!("[syscall][id={}][SYS_WRITE]", SYS_WRITE);
|
||||
|
||||
@ -20,8 +20,7 @@ pub fn sys_write(fd: u64, user_buf_ptr: u64, user_buf_len: u64) -> SyscallResult
|
||||
} else {
|
||||
info!("Error message from user mode: {:?}", content);
|
||||
}
|
||||
|
||||
SyscallResult::Return(user_buf_len as _)
|
||||
Ok(SyscallReturn::Return(user_buf_len as _))
|
||||
} else {
|
||||
panic!("Unsupported fd number {}", fd);
|
||||
}
|
||||
|
@ -5,7 +5,7 @@ use crate::{
|
||||
syscall::SYS_WRITEV,
|
||||
};
|
||||
|
||||
use super::SyscallResult;
|
||||
use super::SyscallReturn;
|
||||
|
||||
const IOVEC_MAX: usize = 256;
|
||||
|
||||
@ -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) -> Result<SyscallReturn> {
|
||||
debug!("[syscall][id={}][SYS_WRITEV]", SYS_WRITEV);
|
||||
let res = do_sys_writev(fd, io_vec_addr as Vaddr, io_vec_count as usize);
|
||||
SyscallResult::Return(res as _)
|
||||
let res = do_sys_writev(fd, io_vec_ptr as Vaddr, io_vec_count as usize);
|
||||
Ok(SyscallReturn::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::<IoVec>(io_vec_addr + i * 8);
|
||||
let io_vec = read_val_from_user::<IoVec>(io_vec_ptr + i * 8);
|
||||
let base = io_vec.base;
|
||||
let len = io_vec.len;
|
||||
debug!("base = 0x{:x}", base);
|
||||
|
@ -24,7 +24,7 @@ impl UserApp {
|
||||
}
|
||||
|
||||
pub fn get_all_apps() -> Vec<UserApp> {
|
||||
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,18 @@ pub fn get_all_apps() -> Vec<UserApp> {
|
||||
let app5 = UserApp::new("/fork", read_fork_c_content());
|
||||
res.push(app5);
|
||||
|
||||
// Set 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
|
||||
}
|
||||
|
||||
@ -74,3 +86,15 @@ 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_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")
|
||||
}
|
||||
|
@ -1,3 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:f98928f25e8223fd76d5d19db68e83913b48ea8b3cf6ae8d3120971e7271c93b
|
||||
oid sha256:afc9465a8ae782da4e049d2b660a27b678394e683814c29a9601bc135126a0e5
|
||||
size 871952
|
||||
|
@ -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;
|
||||
}
|
@ -1,3 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:4f3b6fe8b52f200c469170223ea0cb2d06dbab6a5eb757e007eb0a751c5e1e81
|
||||
oid sha256:ca7a77a72da160f11670a04a16b623944295b9059399da45f57668f121b00d11
|
||||
size 877152
|
||||
|
@ -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;
|
||||
|
10
src/kxos-user/signal_c/Makefile
Normal file
10
src/kxos-user/signal_c/Makefile
Normal file
@ -0,0 +1,10 @@
|
||||
.PHONY: build clean run
|
||||
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 sig_action
|
||||
run: build
|
||||
@./sig_procmask
|
||||
@./sig_action
|
3
src/kxos-user/signal_c/divide_zero
Executable file
3
src/kxos-user/signal_c/divide_zero
Executable file
@ -0,0 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:07eb07c6387a9afd68a5b8a8bba9b48e1362b9c3b8f18ce30e744640a4dfa546
|
||||
size 871776
|
7
src/kxos-user/signal_c/divide_zero.c
Normal file
7
src/kxos-user/signal_c/divide_zero.c
Normal file
@ -0,0 +1,7 @@
|
||||
#include<stdio.h>
|
||||
|
||||
int main() {
|
||||
int a = 2 - 2;
|
||||
int b = 1 / a;
|
||||
return 0;
|
||||
}
|
3
src/kxos-user/signal_c/sig_action
Executable file
3
src/kxos-user/signal_c/sig_action
Executable file
@ -0,0 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:1938c6e8abd70c400780dd8aa089d768a8662d54bac2a658936790d5537e868c
|
||||
size 877544
|
29
src/kxos-user/signal_c/sig_action.c
Normal file
29
src/kxos-user/signal_c/sig_action.c
Normal file
@ -0,0 +1,29 @@
|
||||
#include <stdio.h>
|
||||
#include <signal.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <sys/wait.h>
|
||||
|
||||
int sigchld = 0;
|
||||
|
||||
void proc_exit() {
|
||||
sigchld = sigchld + 1;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
3
src/kxos-user/signal_c/sig_procmask
Executable file
3
src/kxos-user/signal_c/sig_procmask
Executable file
@ -0,0 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:6faf986f058a2480297fb323a536319f9c7dde76efe4ed0472f09a4ad2960c9b
|
||||
size 871848
|
19
src/kxos-user/signal_c/sig_procmask.c
Normal file
19
src/kxos-user/signal_c/sig_procmask.c
Normal file
@ -0,0 +1,19 @@
|
||||
/// This code is from CSAPP
|
||||
/// We use this codes to test sigprocmask
|
||||
#include <stdio.h>
|
||||
#include <signal.h>
|
||||
|
||||
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;
|
||||
}
|
Reference in New Issue
Block a user