diff --git a/src/kxos-frame-pod-derive/Cargo.toml b/src/kxos-frame-pod-derive/Cargo.toml index fff519277..f1ed8313a 100644 --- a/src/kxos-frame-pod-derive/Cargo.toml +++ b/src/kxos-frame-pod-derive/Cargo.toml @@ -11,4 +11,4 @@ proc-macro = true [dependencies] proc-macro2 = "1.0" quote = "1.0" -syn = "1.0.90" +syn = {version = "1.0.90", features = ["extra-traits"]} diff --git a/src/kxos-frame-pod-derive/src/lib.rs b/src/kxos-frame-pod-derive/src/lib.rs index 80a182497..69d231cd6 100644 --- a/src/kxos-frame-pod-derive/src/lib.rs +++ b/src/kxos-frame-pod-derive/src/lib.rs @@ -1,9 +1,13 @@ -use proc_macro2::TokenStream; +//! This crate is used to provide a procedural macro to derive Pod trait defined in kxos_frame. +//! When use this crate, kxos-frame should also be added as a dependency. +//! This macro should only be used outside +//! When derive Pod trait, we will do a check whether the derive is safe since Pod trait is an unsafe trait. +//! For struct, we will check that the struct has valid repr (e.g,. repr(C), repr(u8)), and each field is Pod type. +//! For union and enum, we only check the valid repr. + +use proc_macro2::{Ident, TokenStream}; use quote::quote; -use syn::{ - parse_macro_input, punctuated::Punctuated, token::Comma, Data, DataEnum, DataStruct, - DeriveInput, Field, Fields, -}; +use syn::{parse_macro_input, Attribute, Data, DataStruct, DeriveInput, Fields, Generics}; #[proc_macro_derive(Pod)] pub fn derive_pod(input_token: proc_macro::TokenStream) -> proc_macro::TokenStream { @@ -11,32 +15,38 @@ pub fn derive_pod(input_token: proc_macro::TokenStream) -> proc_macro::TokenStre expand_derive_pod(input).into() } +const ALLOWED_REPRS: [&'static str; 13] = [ + "C", "u8", "i8", "u16", "i16", "u32", "i32", "u64", "i64", "usize", "isize", "u128", "i128", +]; + fn expand_derive_pod(input: DeriveInput) -> TokenStream { + let attrs = input.attrs; let ident = input.ident; - let fields = match input.data { - Data::Struct(DataStruct { fields, .. }) => match fields { - Fields::Named(fields_named) => fields_named.named, - Fields::Unnamed(fields_unnamed) => fields_unnamed.unnamed, - Fields::Unit => Punctuated::new(), - }, - Data::Enum(DataEnum { variants, .. }) => { - let mut fields: Punctuated = Punctuated::new(); - for var in variants { - fields.extend(match var.fields { - Fields::Named(fields_named) => fields_named.named, - Fields::Unnamed(fields_unnamed) => fields_unnamed.unnamed, - Fields::Unit => Punctuated::new(), - }) - } - fields - } - // Panic on compilation time if one tries to derive pod for enum or union. - // It may not be a good idea, but works now. - _ => panic!("derive pod only works for struct and enum now."), + let generics = input.generics; + match input.data { + Data::Struct(data_struct) => impl_pod_for_struct(data_struct, generics, ident, attrs), + Data::Enum(..) | Data::Union(..) => impl_pod_for_enum_or_union(attrs, generics, ident), + } +} + +fn impl_pod_for_struct( + data_struct: DataStruct, + generics: Generics, + ident: Ident, + attrs: Vec, +) -> TokenStream { + if !has_valid_repr(attrs) { + panic!("{} has invalid repr to implement Pod", ident.to_string()); + } + let DataStruct { fields, .. } = data_struct; + let fields = match fields { + Fields::Named(fields_named) => fields_named.named, + Fields::Unnamed(fields_unnamed) => fields_unnamed.unnamed, + Fields::Unit => panic!("derive pod does not work for struct with unit field"), }; // deal with generics - let (impl_generics, type_generics, where_clause) = input.generics.split_for_impl(); + let (impl_generics, type_generics, where_clause) = generics.split_for_impl(); let pod_where_predicates = fields .into_iter() @@ -61,3 +71,47 @@ fn expand_derive_pod(input: DeriveInput) -> TokenStream { } } } + +fn impl_pod_for_enum_or_union( + attrs: Vec, + generics: Generics, + ident: Ident, +) -> TokenStream { + if !has_valid_repr(attrs) { + panic!( + "{} does not have invalid repr to implement Pod.", + ident.to_string() + ); + } + + // deal with generics + let (impl_generics, type_generics, where_clause) = generics.split_for_impl(); + quote! { + #[automatically_derived] + unsafe impl #impl_generics ::kxos_frame::Pod #type_generics for #ident #where_clause {} + } +} + +fn has_valid_repr(attrs: Vec) -> bool { + for attr in attrs { + if let Some(ident) = attr.path.get_ident() { + if "repr" == ident.to_string().as_str() { + let repr = attr.tokens.to_string(); + let repr = repr.replace("(", "").replace(")", ""); + let reprs = repr + .split(",") + .map(|one_repr| one_repr.trim()) + .collect::>(); + if let Some(_) = ALLOWED_REPRS.iter().position(|allowed_repr| { + reprs + .iter() + .position(|one_repr| one_repr == allowed_repr) + .is_some() + }) { + return true; + } + } + } + } + false +} diff --git a/src/kxos-frame/src/config.rs b/src/kxos-frame/src/config.rs index 99cb14c4a..f62b6c64a 100644 --- a/src/kxos-frame/src/config.rs +++ b/src/kxos-frame/src/config.rs @@ -15,4 +15,4 @@ pub const PAGE_SIZE_BITS: usize = 0xc; pub const KVA_START: usize = (usize::MAX) << PAGE_SIZE_BITS; -pub const DEFAULT_LOG_LEVEL: LogLevel = LogLevel::Info; +pub const DEFAULT_LOG_LEVEL: LogLevel = LogLevel::Close; diff --git a/src/kxos-frame/src/cpu.rs b/src/kxos-frame/src/cpu.rs index 4e86db11f..d780774ae 100644 --- a/src/kxos-frame/src/cpu.rs +++ b/src/kxos-frame/src/cpu.rs @@ -1,10 +1,12 @@ //! CPU. +use core::arch::x86_64::{_fxrstor, _fxsave}; +use core::fmt::Debug; +use core::mem::MaybeUninit; + +use crate::debug; +use crate::trap::{CalleeRegs, CallerRegs, SyscallFrame, TrapFrame}; use crate::vm::Pod; -use crate::{ - impl_pod_for, - trap::{CalleeRegs, CallerRegs, SyscallFrame, TrapFrame}, -}; /// Defines a CPU-local variable. #[macro_export] @@ -29,9 +31,9 @@ pub fn this_cpu() -> u32 { #[derive(Clone, Default, Copy, Debug)] #[repr(C)] pub struct CpuContext { + pub fp_regs: FpRegs, pub gp_regs: GpRegs, pub fs_base: u64, - pub fp_regs: FpRegs, /// trap information, this field is all zero when it is syscall pub trap_information: TrapInformation, } @@ -69,7 +71,10 @@ pub struct GpRegs { pub rflag: u64, } -impl_pod_for!(GpRegs, TrapInformation, CpuContext, FpRegs); +unsafe impl Pod for GpRegs {} +unsafe impl Pod for TrapInformation {} +unsafe impl Pod for CpuContext {} +unsafe impl Pod for FpRegs {} impl From for CpuContext { fn from(syscall: SyscallFrame) -> Self { @@ -204,7 +209,7 @@ impl Into for CpuContext { #[derive(Clone, Copy, Debug)] #[repr(C)] pub struct FpRegs { - //buf: Aligned, + buf: FxsaveArea, is_valid: bool, } @@ -214,18 +219,25 @@ impl FpRegs { /// Note that a newly-created instance's floating point state is not /// initialized, thus considered invalid (i.e., `self.is_valid() == false`). pub fn new() -> Self { - //let buf = Aligned(unsafe { MaybeUninit::uninit().assume_init() }); - //let is_valid = false; - //Self { buf, is_valid } - Self { is_valid: false } - // todo!("import aligned") + // The buffer address requires 16bytes alignment. + Self { + buf: unsafe { MaybeUninit::uninit().assume_init() }, + is_valid: false, + } } /// Save CPU's current floating pointer states into this instance. pub fn save(&mut self) { - // unsafe { - // _fxsave(self.buf.as_mut_ptr() as *mut u8); - // } + debug!("save fpregs"); + debug!("write addr = 0x{:x}", (&mut self.buf) as *mut _ as usize); + let layout = alloc::alloc::Layout::for_value(&self.buf); + debug!("layout: {:?}", layout); + let ptr = unsafe { alloc::alloc::alloc(layout) } as usize; + debug!("ptr = 0x{:x}", ptr); + unsafe { + _fxsave((&mut self.buf.data).as_mut_ptr() as *mut u8); + } + debug!("save fpregs success"); self.is_valid = true; } @@ -238,8 +250,8 @@ impl FpRegs { /// It is the caller's responsibility to ensure that the source slice contains /// data that is in xsave/xrstor format. The slice must have a length of 512 bytes. pub unsafe fn save_from_slice(&mut self, src: &[u8]) { - //(&mut self.buf).copy_from_slice(src); - //self.is_valid = true; + (&mut self.buf.data).copy_from_slice(src); + self.is_valid = true; } /// Returns whether the instance can contains data in valid xsave/xrstor format. @@ -259,16 +271,17 @@ impl FpRegs { /// /// Panic. If the current state is invalid, the method will panic. pub fn restore(&self) { + debug!("restore fpregs"); assert!(self.is_valid); - //unsafe { _fxrstor(self.buf.as_ptr()) }; + unsafe { _fxrstor((&self.buf.data).as_ptr()) }; + debug!("restore fpregs success"); } /// Returns the floating point state as a slice. /// /// Note that the slice may contain garbage if `self.is_valid() == false`. pub fn as_slice(&self) -> &[u8] { - //&*self.buf - todo!() + &self.buf.data } } @@ -277,3 +290,9 @@ impl Default for FpRegs { Self::new() } } + +#[repr(C, align(16))] +#[derive(Debug, Clone, Copy)] +struct FxsaveArea { + data: [u8; 512], // 512 bytes +} diff --git a/src/kxos-frame/src/sync/rcu/mod.rs b/src/kxos-frame/src/sync/rcu/mod.rs index d6dccfeac..360ba8ddb 100644 --- a/src/kxos-frame/src/sync/rcu/mod.rs +++ b/src/kxos-frame/src/sync/rcu/mod.rs @@ -89,7 +89,7 @@ impl

Drop for RcuReclaimer

{ wq.wake_one(); } }); - wq.wait_until(|| Ok(Some(0u8))).unwrap(); + wq.wait_until(|| Some(0u8)); } } diff --git a/src/kxos-frame/src/sync/wait.rs b/src/kxos-frame/src/sync/wait.rs index c7f23d1bf..b888f6d57 100644 --- a/src/kxos-frame/src/sync/wait.rs +++ b/src/kxos-frame/src/sync/wait.rs @@ -35,43 +35,22 @@ impl WaitQueue { /// /// By taking a condition closure, his wait-wakeup mechanism becomes /// more efficient and robust. - pub fn wait_until(&self, mut cond: F) -> Result + pub fn wait_until(&self, mut cond: F) -> R where - F: FnMut() -> Result>, + F: FnMut() -> Option, { let waiter = Arc::new(Waiter::new()); self.enqueue(&waiter); loop { - let ret_value = match cond() { - Ok(Some(ret_value)) => Some(Ok(ret_value)), - Ok(None) => None, - Err(err) => Some(Err(err)), - }; - if let Some(ret_value) = ret_value { + if let Some(res) = cond() { waiter.set_finished(); self.finish_wait(); - return ret_value; - } + return res; + }; waiter.wait(); } } - /// Wait on an waiter with data until the waiter is woken up. - /// Note this func cannot be implemented with wait_until. This func always requires the waiter become woken. - /// While wait_until does not check the waiter if cond is true. - /// TODO: This function can take a timeout param further. - // pub fn wait_on(&self, data: D) { - // let index = self - // .waiters - // .lock() - // .iter() - // .position(|waiter| *waiter.data() == data); - // if let Some(index) = index { - // let waiter = self.waiters.lock().iter().nth(index).unwrap().clone(); - // waiter.wait(); - // } - // } - /// Wake one waiter thread, if there is one. pub fn wake_one(&self) { if let Some(waiter) = self.waiters.lock().front() { @@ -89,107 +68,6 @@ impl WaitQueue { } } - /// Wake all waiters if given condition returns true. - /// The condition will check the data carried by waiter if it satisfy some relation with cond_data - // pub fn wake_all_on_condition(&self, cond_data: &C, cond: F) - // where - // F: Fn(&D, &C) -> bool, - // { - // self.waiters.lock().iter().for_each(|waiter| { - // if cond(waiter.data(), cond_data) { - // waiter.wake_up() - // } - // }) - // } - - /// Wake at most max_count waiters if given condition is true. - /// returns the number of woken waiters - // pub fn batch_wake_and_deque(&self, max_count: usize, cond_data: &C, cond: F) -> usize - // where - // F: Fn(&D, &C) -> bool, - // { - // let mut count = 0; - // let mut waiters_to_wake = Vec::new(); - // self.waiters.lock().retain(|waiter| { - // if count >= max_count || waiter.is_woken_up() || !cond(waiter.data(), cond_data) { - // true - // } else { - // waiters_to_wake.push(waiter.clone()); - // count += 1; - // false - // } - // }); - // waiters_to_wake.into_iter().for_each(|waiter| { - // waiter.wake_up(); - // }); - // return count; - // } - - /// create a waiter with given data, and enqueue - // pub fn enqueue(&self) { - // let waiter = Arc::new(Waiter::new(data)); - // self.enqueue_waiter(&waiter); - // } - - /// dequeue a waiter with given data - // pub fn dequeue(&self, data: D) { - // let waiter = Arc::new(Waiter::new(data)); - // self.dequeue_waiter(&waiter); - // } - - /// update the waiters data - /// if cond(old_data, old_value) is true. - /// The new data should be calculated by get_new_data(old_data, new_value). - // pub fn update_waiters_data( - // &self, - // cond: F1, - // old_value: &C, - // new_value: &C, - // get_new_data: F2, - // max_count: usize, - // ) where - // F1: Fn(&C, &D) -> bool, - // F2: Fn(&D, &C) -> D, - // { - // let mut waiters = self.waiters.lock(); - // let len = waiters.len(); - // let mut count = 0; - // for index in 0..len { - // let waiter = &waiters[index]; - // let old_data = waiter.data(); - // if cond(old_value, waiter.data()) { - // let new_data = get_new_data(old_data, new_value); - // let new_waiter = Arc::new(Waiter::new(new_data)); - // waiters[index] = new_waiter; - // count += 1; - // if count >= max_count { - // break; - // } - // } - // } - // } - - /// remove waiters for which the cond returns true - // pub fn remove_waiters(&self, cond: F, cond_data: &C, max_count: usize) -> Vec - // where - // F: Fn(&D, &C) -> bool, - // { - // let mut removed_waiters = Vec::new(); - // let mut count = 0; - // self.waiters.lock().retain(|waiter| { - // let data = waiter.data(); - // if count >= max_count || !cond(data, cond_data) { - // true - // } else { - // count += 1; - // removed_waiters.push(data.clone()); - // false - // } - // }); - - // removed_waiters - // } - // enqueue a waiter into current waitqueue. If waiter is exclusive, add to the back of waitqueue. // Otherwise, add to the front of waitqueue fn enqueue(&self, waiter: &Arc) { @@ -204,17 +82,6 @@ impl WaitQueue { fn finish_wait(&self) { self.waiters.lock().retain(|waiter| !waiter.is_finished()) } - - // fn dequeue_waiter(&self, waiter_ref: &WaiterRef) { - // let mut waiters_lock = self.waiters.lock(); - // let index = waiters_lock - // .iter() - // .position(|waiter_| *waiter_ref.data() == *waiter_.data()); - // if let Some(index) = index { - // waiters_lock.remove(index); - // } - // drop(waiters_lock); - // } } #[derive(Debug)] diff --git a/src/kxos-frame/src/user.rs b/src/kxos-frame/src/user.rs index 9f810c03c..5725a9123 100644 --- a/src/kxos-frame/src/user.rs +++ b/src/kxos-frame/src/user.rs @@ -119,13 +119,15 @@ impl<'a> UserMode<'a> { self.current.syscall_frame().caller.rcx = self.user_space.cpu_ctx.gp_regs.rip; // write fsbase wrfsbase(self.user_space.cpu_ctx.fs_base); - + let fp_regs = self.user_space.cpu_ctx.fp_regs; + if fp_regs.is_valid() { + fp_regs.restore(); + } self.executed = true; } else { if self.current.inner_exclusive_access().is_from_trap { *self.current.trap_frame() = self.context.into(); } else { - // x86_64_util::wrfsbase(self.context.fs_base); *self.current.syscall_frame() = self.context.into(); self.current.syscall_frame().caller.rcx = self.context.gp_regs.rip; } @@ -135,6 +137,12 @@ impl<'a> UserMode<'a> { debug!("write fsbase: 0x{:x}", self.context.fs_base); wrfsbase(self.context.fs_base); } + + // write fp_regs + // let fp_regs = self.context.fp_regs; + // if fp_regs.is_valid() { + // fp_regs.restore(); + // } } let mut current_task_inner = self.current.inner_exclusive_access(); @@ -152,10 +160,12 @@ impl<'a> UserMode<'a> { if self.current.inner_exclusive_access().is_from_trap { self.context = CpuContext::from(*self.current.trap_frame()); self.context.fs_base = rdfsbase(); + // self.context.fp_regs.save(); UserEvent::Exception } else { self.context = CpuContext::from(*self.current.syscall_frame()); self.context.fs_base = rdfsbase(); + // self.context.fp_regs.save(); // debug!("[kernel] syscall id:{}", self.context.gp_regs.rax); // debug!("[kernel] rsp: 0x{:x}", self.context.gp_regs.rsp); // debug!("[kernel] rcx: 0x{:x}", self.context.gp_regs.rcx); diff --git a/src/kxos-pci/src/lib.rs b/src/kxos-pci/src/lib.rs index 70b3d1f61..f83952167 100644 --- a/src/kxos-pci/src/lib.rs +++ b/src/kxos-pci/src/lib.rs @@ -7,7 +7,6 @@ pub mod msix; pub mod util; extern crate alloc; use kxos_frame::info; -#[macro_use] extern crate kxos_frame_pod_derive; use alloc::{sync::Arc, vec::Vec}; diff --git a/src/kxos-std/src/driver/pci/virtio/block.rs b/src/kxos-std/src/driver/pci/virtio/block.rs index 5a26112c6..981dbc3c5 100644 --- a/src/kxos-std/src/driver/pci/virtio/block.rs +++ b/src/kxos-std/src/driver/pci/virtio/block.rs @@ -4,7 +4,6 @@ use crate::process::Process; use alloc::sync::Arc; use alloc::vec::Vec; use kxos_frame::info; -use kxos_frame_pod_derive::Pod; use kxos_pci::PCIDevice; use kxos_virtio::PCIVirtioDevice; use lazy_static::lazy_static; diff --git a/src/kxos-std/src/error.rs b/src/kxos-std/src/error.rs index 63c819ba0..ed69337b3 100644 --- a/src/kxos-std/src/error.rs +++ b/src/kxos-std/src/error.rs @@ -205,6 +205,12 @@ impl From for Error { } } +impl From for Error { + fn from(_: core::ffi::FromBytesWithNulError) -> Self { + Error::with_message(Errno::E2BIG, "Cannot find null in cstring") + } +} + #[macro_export] macro_rules! return_errno { ($errno: expr) => { diff --git a/src/kxos-std/src/fs/stat.rs b/src/kxos-std/src/fs/stat.rs index 1a473fb2f..73db144f3 100644 --- a/src/kxos-std/src/fs/stat.rs +++ b/src/kxos-std/src/fs/stat.rs @@ -19,6 +19,7 @@ pub const S_IFLNK: u32 = 0o120000; /// File Stat #[derive(Debug, Clone, Copy, Pod, Default)] +#[repr(C)] pub struct Stat { /// ID of device containing file st_dev: dev_t, diff --git a/src/kxos-std/src/process/clone.rs b/src/kxos-std/src/process/clone.rs index df50b660f..aa4b373d5 100644 --- a/src/kxos-std/src/process/clone.rs +++ b/src/kxos-std/src/process/clone.rs @@ -161,7 +161,7 @@ pub fn clone_child(parent_context: CpuContext, clone_args: CloneArgs) -> Result< child.set_process_group(Arc::downgrade(&parent_process_group)); current!().add_child(child.clone()); - table::add_process(child_pid, child.clone()); + table::add_process(child.clone()); deal_with_clone_args(clone_args, &child)?; Ok(child) } diff --git a/src/kxos-std/src/process/mod.rs b/src/kxos-std/src/process/mod.rs index d8231edc9..8c63073a2 100644 --- a/src/kxos-std/src/process/mod.rs +++ b/src/kxos-std/src/process/mod.rs @@ -1,5 +1,6 @@ use core::sync::atomic::{AtomicI32, AtomicUsize, Ordering}; +use self::name::ProcessName; use self::process_group::ProcessGroup; use self::process_vm::mmap_area::MmapArea; use self::process_vm::user_heap::UserHeap; @@ -19,6 +20,7 @@ pub mod clone; pub mod elf; pub mod exception; pub mod fifo_scheduler; +pub mod name; pub mod process_filter; pub mod process_group; pub mod process_vm; @@ -56,6 +58,8 @@ pub struct Process { children: Mutex>>, /// Process group process_group: Mutex>>, + /// Process name + process_name: Mutex>, // Signal sig_dispositions: Mutex, @@ -101,6 +105,11 @@ impl Process { }; let children = BTreeMap::new(); let waiting_children = WaitQueue::new(); + let process_name = exec_filename.as_ref().map(|filename| { + let mut process_name = ProcessName::new(); + process_name.set_name(filename).unwrap(); + process_name + }); Self { pid, task, @@ -113,6 +122,7 @@ impl Process { parent: Mutex::new(parent), children: Mutex::new(children), process_group: Mutex::new(process_group), + process_name: Mutex::new(process_name), sig_dispositions: Mutex::new(sig_dispositions), sig_queues: Mutex::new(sig_queues), sig_mask: Mutex::new(sig_mask), @@ -182,7 +192,7 @@ impl Process { }); // Set process group user_process.create_and_set_process_group(); - table::add_process(pid, user_process.clone()); + table::add_process(user_process.clone()); let parent = user_process .parent() .expect("[Internel error] User process should always have parent"); @@ -214,7 +224,7 @@ impl Process { ) }); kernel_process.create_and_set_process_group(); - table::add_process(pid, kernel_process.clone()); + table::add_process(kernel_process.clone()); if let Some(parent) = kernel_process.parent() { parent.add_child(kernel_process.clone()); } @@ -241,6 +251,10 @@ impl Process { } } + pub fn process_name(&self) -> &Mutex> { + &self.process_name + } + pub fn process_group(&self) -> &Mutex>> { &self.process_group } @@ -259,12 +273,14 @@ impl Process { let _ = self.parent.lock().insert(parent); } + /// Set process group for current process. If old process group exists, + /// remove current process from old process group. pub fn set_process_group(&self, process_group: Weak) { - if self.process_group.lock().is_none() { - let _ = self.process_group.lock().insert(process_group); - } else { - todo!("We should do something with old group") + if let Some(old_process_group) = &*self.process_group().lock() { + let old_process_group = old_process_group.upgrade().unwrap(); + old_process_group.remove_process(self.pid()); } + let _ = self.process_group.lock().insert(process_group); } /// create a new process group for the process and add it to globle table. @@ -273,7 +289,7 @@ impl Process { 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); + table::add_process_group(process_group); } pub fn parent(&self) -> Option> { diff --git a/src/kxos-std/src/process/name.rs b/src/kxos-std/src/process/name.rs new file mode 100644 index 000000000..1dbf2a4d5 --- /dev/null +++ b/src/kxos-std/src/process/name.rs @@ -0,0 +1,31 @@ +use crate::prelude::*; + +pub const MAX_PROCESS_NAME_LEN: usize = 128; +pub struct ProcessName { + inner: [u8; MAX_PROCESS_NAME_LEN], + count: usize, +} + +impl ProcessName { + pub fn new() -> Self { + ProcessName { + inner: [0; MAX_PROCESS_NAME_LEN], + count: 0, + } + } + + pub fn set_name(&mut self, name: &CStr) -> Result<()> { + let bytes = name.to_bytes_with_nul(); + let bytes_len = bytes.len(); + if bytes_len > MAX_PROCESS_NAME_LEN { + return_errno_with_message!(Errno::E2BIG, "process name is too long"); + } + self.count = bytes_len; + self.inner[..bytes_len].clone_from_slice(bytes); + Ok(()) + } + + pub fn get_name(&self) -> Result> { + Ok(Some(&(CStr::from_bytes_with_nul(&self.inner)?))) + } +} diff --git a/src/kxos-std/src/process/process_group.rs b/src/kxos-std/src/process/process_group.rs index 1a422f692..27fc6611d 100644 --- a/src/kxos-std/src/process/process_group.rs +++ b/src/kxos-std/src/process/process_group.rs @@ -43,6 +43,8 @@ impl ProcessGroup { self.inner.lock().processes.insert(process.pid(), process); } + /// remove a process from this process group. + /// If this group contains no processes now, the group itself will be deleted from global table. pub fn remove_process(&self, pid: Pid) { let mut inner_lock = self.inner.lock(); inner_lock.processes.remove(&pid); diff --git a/src/kxos-std/src/process/signal/c_types.rs b/src/kxos-std/src/process/signal/c_types.rs index ad0a74af3..d9fc0a6cd 100644 --- a/src/kxos-std/src/process/signal/c_types.rs +++ b/src/kxos-std/src/process/signal/c_types.rs @@ -89,6 +89,7 @@ pub struct mcontext_t { } #[derive(Debug, Clone, Copy, Pod, Default)] +#[repr(C)] pub struct SignalCpuContext { pub gp_regs: GpRegs, pub fpregs_on_heap: u64, diff --git a/src/kxos-std/src/process/table.rs b/src/kxos-std/src/process/table.rs index 7b06f0d3b..99351589d 100644 --- a/src/kxos-std/src/process/table.rs +++ b/src/kxos-std/src/process/table.rs @@ -13,7 +13,8 @@ lazy_static! { } /// add a process to global table -pub fn add_process(pid: Pid, process: Arc) { +pub fn add_process(process: Arc) { + let pid = process.pid(); PROCESS_TABLE.lock().insert(pid, process); } @@ -40,7 +41,8 @@ pub fn get_all_processes() -> Vec> { } /// add process group to global table -pub fn add_process_group(pgid: Pgid, process_group: Arc) { +pub fn add_process_group(process_group: Arc) { + let pgid = process_group.pgid(); PROCESS_GROUP_TABLE.lock().insert(pgid, process_group); } diff --git a/src/kxos-std/src/process/wait.rs b/src/kxos-std/src/process/wait.rs index 51ab13494..309240267 100644 --- a/src/kxos-std/src/process/wait.rs +++ b/src/kxos-std/src/process/wait.rs @@ -41,7 +41,7 @@ pub fn wait_child_exit( drop(children_lock); if unwaited_children.len() == 0 { - return Err(kxos_frame::Error::NoChild); + return Some(Err(kxos_frame::Error::NoChild)); } // return immediately if we find a zombie child @@ -54,19 +54,19 @@ pub fn wait_child_exit( let exit_code = zombie_child.exit_code(); if wait_options.contains(WaitOptions::WNOWAIT) { // does not reap child, directly return - return Ok(Some((zombie_pid, exit_code))); + return Some(Ok((zombie_pid, exit_code))); } else { let exit_code = current.reap_zombie_child(zombie_pid); - return Ok(Some((zombie_pid, exit_code))); + return Some(Ok((zombie_pid, exit_code))); } } if wait_options.contains(WaitOptions::WNOHANG) { - return Ok(Some((0, 0))); + return Some(Ok((0, 0))); } // wait - Ok(None) + None })?; Ok((pid, exit_code)) diff --git a/src/kxos-std/src/syscall/exit_group.rs b/src/kxos-std/src/syscall/exit_group.rs index cfb084cf4..a72a38c1f 100644 --- a/src/kxos-std/src/syscall/exit_group.rs +++ b/src/kxos-std/src/syscall/exit_group.rs @@ -2,6 +2,7 @@ use crate::prelude::*; use crate::syscall::{SyscallReturn, SYS_EXIT_GROUP}; +/// Exit all thread in a process. pub fn sys_exit_group(exit_code: u64) -> Result { debug!("[syscall][id={}][SYS_EXIT_GROUP]", SYS_EXIT_GROUP); current!().exit(exit_code as _); diff --git a/src/kxos-std/src/syscall/getpgrp.rs b/src/kxos-std/src/syscall/getpgrp.rs new file mode 100644 index 000000000..81890d9da --- /dev/null +++ b/src/kxos-std/src/syscall/getpgrp.rs @@ -0,0 +1,8 @@ +use super::{SyscallReturn, SYS_GETPGRP}; +use crate::prelude::*; + +pub fn sys_getpgrp() -> Result { + debug!("[syscall][id={}][SYS_GETPGRP]", SYS_GETPGRP); + let current = current!(); + Ok(SyscallReturn::Return(current.pgid() as _)) +} diff --git a/src/kxos-std/src/syscall/getppid.rs b/src/kxos-std/src/syscall/getppid.rs new file mode 100644 index 000000000..a5079a864 --- /dev/null +++ b/src/kxos-std/src/syscall/getppid.rs @@ -0,0 +1,14 @@ +use crate::prelude::*; + +use super::SyscallReturn; +use super::SYS_GETPPID; + +pub fn sys_getppid() -> Result { + debug!("[syscall][id={}][SYS_GETPPID]", SYS_GETPPID); + let current = current!(); + let parent = current.parent(); + match parent { + None => Ok(SyscallReturn::Return(0)), + Some(parent) => Ok(SyscallReturn::Return(parent.pid() as _)), + } +} diff --git a/src/kxos-std/src/syscall/mod.rs b/src/kxos-std/src/syscall/mod.rs index 62e055081..35f181b1b 100644 --- a/src/kxos-std/src/syscall/mod.rs +++ b/src/kxos-std/src/syscall/mod.rs @@ -14,17 +14,21 @@ 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::getpgrp::sys_getpgrp; use crate::syscall::getpid::sys_getpid; +use crate::syscall::getppid::sys_getppid; 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::prctl::sys_prctl; 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::setpgid::sys_setpgid; use crate::syscall::tgkill::sys_tgkill; use crate::syscall::uname::sys_uname; use crate::syscall::wait4::sys_wait4; @@ -38,7 +42,7 @@ mod access; mod arch_prctl; mod brk; mod clone; -pub mod constants; +mod constants; mod execve; mod exit; mod exit_group; @@ -48,17 +52,21 @@ mod futex; mod getegid; mod geteuid; mod getgid; +mod getpgrp; mod getpid; +mod getppid; mod gettid; mod getuid; mod kill; mod mmap; mod mprotect; +mod prctl; mod readlink; mod rt_sigaction; mod rt_sigprocmask; mod rt_sigreturn; mod sched_yield; +mod setpgid; mod tgkill; mod uname; mod wait4; @@ -87,13 +95,14 @@ define_syscall_nums!( 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_SETPGID = 109, + SYS_GETPPID = 110, SYS_GETPGRP = 111, SYS_PRCTL = 157, SYS_ARCH_PRCTL = 158, @@ -179,15 +188,16 @@ pub fn syscall_dispatch( 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_SETPGID => syscall_handler!(2, sys_setpgid, args), + SYS_GETPPID => syscall_handler!(0, sys_getppid), + SYS_GETPGRP => syscall_handler!(0, sys_getpgrp), + SYS_PRCTL => syscall_handler!(5, sys_prctl, args), SYS_ARCH_PRCTL => syscall_handler!(2, sys_arch_prctl, args, context), SYS_GETCWD => todo!(), SYS_GETTID => syscall_handler!(0, sys_gettid), diff --git a/src/kxos-std/src/syscall/prctl.rs b/src/kxos-std/src/syscall/prctl.rs new file mode 100644 index 000000000..ea4d3a8e3 --- /dev/null +++ b/src/kxos-std/src/syscall/prctl.rs @@ -0,0 +1,61 @@ +use crate::memory::read_cstring_from_user; +use crate::memory::write_bytes_to_user; +use crate::prelude::*; +use crate::process::name::MAX_PROCESS_NAME_LEN; + +use super::SyscallReturn; +use super::SYS_PRCTL; +pub fn sys_prctl(option: i32, arg2: u64, arg3: u64, arg4: u64, arg5: u64) -> Result { + debug!("[syscall][id={}][SYS_PRCTL]", SYS_PRCTL); + let prctl_cmd = PrctlCmd::from_args(option, arg2, arg3, arg4, arg5)?; + debug!("prctl cmd = {:?}", prctl_cmd); + let current = current!(); + match prctl_cmd { + PrctlCmd::PR_GET_NAME(write_to_addr) => { + let process_name = current.process_name().lock(); + if let Some(process_name) = &*process_name { + if let Some(process_name) = process_name.get_name()? { + write_bytes_to_user(write_to_addr, process_name.to_bytes_with_nul())?; + } + } + } + PrctlCmd::PR_SET_NAME(read_addr) => { + let mut process_name = current.process_name().lock(); + if let Some(process_name) = &mut *process_name { + let new_process_name = read_cstring_from_user(read_addr, MAX_PROCESS_NAME_LEN)?; + process_name.set_name(&new_process_name)?; + } + } + _ => todo!(), + } + Ok(SyscallReturn::Return(0)) +} + +const PR_SET_NAME: i32 = 15; +const PR_GET_NAME: i32 = 16; +const PR_SET_TIMERSLACK: i32 = 29; +const PR_GET_TIMERSLACK: i32 = 30; + +#[allow(non_camel_case_types)] +#[derive(Debug, Clone, Copy)] +pub enum PrctlCmd { + PR_SET_NAME(Vaddr), + PR_GET_NAME(Vaddr), + PR_SET_TIMERSLACK(u64), + PR_GET_TIMERSLACK, +} + +impl PrctlCmd { + fn from_args(option: i32, arg2: u64, arg3: u64, arg4: u64, arg5: u64) -> Result { + match option { + PR_SET_NAME => Ok(PrctlCmd::PR_SET_NAME(arg2 as _)), + PR_GET_NAME => Ok(PrctlCmd::PR_GET_NAME(arg2 as _)), + PR_GET_TIMERSLACK => todo!(), + PR_SET_TIMERSLACK => todo!(), + _ => { + debug!("prctl cmd number: {}", option); + return_errno_with_message!(Errno::EINVAL, "unsupported prctl command"); + } + } + } +} diff --git a/src/kxos-std/src/syscall/setpgid.rs b/src/kxos-std/src/syscall/setpgid.rs new file mode 100644 index 000000000..b904d20cf --- /dev/null +++ b/src/kxos-std/src/syscall/setpgid.rs @@ -0,0 +1,40 @@ +use crate::{ + prelude::*, + process::{process_group::ProcessGroup, table, Pgid, Pid}, +}; + +use super::{SyscallReturn, SYS_SETPGID}; + +pub fn sys_setpgid(pid: Pid, pgid: Pgid) -> Result { + debug!("[syscall][id={}][SYS_PRCTL]", SYS_SETPGID); + let current = current!(); + // if pid is 0, pid should be the pid of current process + let pid = if pid == 0 { current.pid() } else { pid }; + // if pgid is 0, pgid should be pid + let pgid = if pgid == 0 { pid } else { pgid }; + debug!("pid = {}, pgid = {}", pid, pgid); + + if current.pid() != pid { + return_errno_with_message!( + Errno::EACCES, + "cannot set pgid for process other than current" + ); + } + + // only can move process to an existing group or self + if pgid != pid && table::pgid_to_process_group(pgid).is_none() { + return_errno_with_message!(Errno::EPERM, "process group must exist"); + } + + if let Some(new_process_group) = table::pgid_to_process_group(pgid) { + new_process_group.add_process(current.clone()); + current.set_process_group(Arc::downgrade(&new_process_group)); + } else { + let new_process_group = Arc::new(ProcessGroup::new(current.clone())); + new_process_group.add_process(current.clone()); + current.set_process_group(Arc::downgrade(&new_process_group)); + table::add_process_group(new_process_group); + } + + Ok(SyscallReturn::Return(0)) +} diff --git a/src/kxos-virtio/src/block.rs b/src/kxos-virtio/src/block.rs index 56a0f083e..c02127952 100644 --- a/src/kxos-virtio/src/block.rs +++ b/src/kxos-virtio/src/block.rs @@ -1,4 +1,3 @@ -use kxos_frame::Pod; use kxos_pci::capability::vendor::virtio::CapabilityVirtioData; use kxos_pci::util::BAR; use kxos_util::frame_ptr::InFramePtr; diff --git a/src/kxos-virtio/src/queue.rs b/src/kxos-virtio/src/queue.rs index 218794333..e7e1b4c5f 100644 --- a/src/kxos-virtio/src/queue.rs +++ b/src/kxos-virtio/src/queue.rs @@ -5,7 +5,6 @@ use alloc::vec::Vec; use bitflags::bitflags; use core::sync::atomic::{fence, Ordering}; use kxos_frame::offset_of; -use kxos_frame::Pod; use kxos_util::frame_ptr::InFramePtr; #[derive(Debug)] pub enum QueueError { @@ -255,6 +254,7 @@ fn set_buf(inframe_ptr: &InFramePtr, buf: &[u8]) { bitflags! { /// Descriptor flags #[derive(Pod)] + #[repr(C)] struct DescFlags: u16 { const NEXT = 1; const WRITE = 2;