From 294529d1d8800c6967ce4e53ae44a1c76648174b Mon Sep 17 00:00:00 2001 From: longjin Date: Mon, 13 Nov 2023 14:24:23 +0000 Subject: [PATCH] =?UTF-8?q?1.=20=E6=96=B0=E5=A2=9E=E4=BB=A5=E4=B8=8B?= =?UTF-8?q?=E7=B3=BB=E7=BB=9F=E8=B0=83=E7=94=A8=20=20=20=20=20=20=20=20=20?= =?UTF-8?q?=20=20=20=20-=20SYS=5FLSTAT=20=20=20=20=20=20=20=20=20=20=20=20?= =?UTF-8?q?=20-=20SYS=5FREADV=20=20=20=20=20=20=20=20=20=20=20=20=20-=20SY?= =?UTF-8?q?S=5FACCESS=20=20=20=20=20=20=20=20=20=20=20=20=20-=20SYS=5FUNLI?= =?UTF-8?q?NK=20=20=20=20=20=20=20=20=20=20=20=20=20-=20SYS=5FCHMOD=20=20?= =?UTF-8?q?=20=20=20=20=20=20=20=20=20=20=20-=20SYS=5FFCHMOD=20=20=20=20?= =?UTF-8?q?=20=20=20=20=20=20=20=20=20-=20SYS=5FUMASK=20=20=20=20=20=20=20?= =?UTF-8?q?=20=20=20=20=20=20-=20SYS=5FSYSINFO=20=20=20=20=20=20=20=20=20?= =?UTF-8?q?=20=20=20=20-=20SYS=5FCLOCK=5FGETTIME=20=20=20=20=20=20=20=20?= =?UTF-8?q?=20=20=20=20=20-=20SYS=5FFCHMODAT=20=20=20=20=20=20=20=20=20=20?= =?UTF-8?q?=20=20=20-=20SYS=5FFACCESSAT?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 2. 修改sys_wait4,使得其部分符合Linux的行为(还是有些地方不符合的,详情请对比linux-6.1.9的sys_wait4接口) --- kernel/src/arch/x86_64/ipc/signal.rs | 36 +++ kernel/src/arch/x86_64/process/syscall.rs | 21 +- kernel/src/arch/x86_64/syscall.rs | 40 +++- kernel/src/filesystem/vfs/core.rs | 30 ++- kernel/src/filesystem/vfs/file.rs | 3 + kernel/src/filesystem/vfs/mod.rs | 6 +- kernel/src/filesystem/vfs/open.rs | 45 +++- kernel/src/filesystem/vfs/syscall.rs | 124 ++++++++--- kernel/src/filesystem/vfs/utils.rs | 3 +- kernel/src/ipc/pipe.rs | 16 +- kernel/src/ipc/signal_types.rs | 5 + kernel/src/lib.rs | 1 + kernel/src/process/exit.rs | 253 ++++++++++++++++++++++ kernel/src/process/mod.rs | 15 ++ kernel/src/process/syscall.rs | 151 ++++--------- kernel/src/syscall/misc.rs | 57 +++++ kernel/src/syscall/mod.rs | 70 +++++- kernel/src/syscall/user_access.rs | 11 + kernel/src/time/syscall.rs | 43 ++++ 19 files changed, 758 insertions(+), 172 deletions(-) create mode 100644 kernel/src/process/exit.rs create mode 100644 kernel/src/syscall/misc.rs diff --git a/kernel/src/arch/x86_64/ipc/signal.rs b/kernel/src/arch/x86_64/ipc/signal.rs index 960ae1b17..70c31ae07 100644 --- a/kernel/src/arch/x86_64/ipc/signal.rs +++ b/kernel/src/arch/x86_64/ipc/signal.rs @@ -277,6 +277,42 @@ bitflags! { } } +/// SIGCHLD si_codes +#[derive(Debug, Clone, Copy, PartialEq, Eq, ToPrimitive)] +#[allow(dead_code)] +pub enum SigChildCode { + /// child has exited + /// + /// CLD_EXITED + Exited = 1, + /// child was killed + /// + /// CLD_KILLED + Killed = 2, + /// child terminated abnormally + /// + /// CLD_DUMPED + Dumped = 3, + /// traced child has trapped + /// + /// CLD_TRAPPED + Trapped = 4, + /// child has stopped + /// + /// CLD_STOPPED + Stopped = 5, + /// stopped child has continued + /// + /// CLD_CONTINUED + Continued = 6, +} + +impl Into for SigChildCode { + fn into(self) -> i32 { + self as i32 + } +} + #[repr(C, align(16))] #[derive(Debug, Clone, Copy)] pub struct SigFrame { diff --git a/kernel/src/arch/x86_64/process/syscall.rs b/kernel/src/arch/x86_64/process/syscall.rs index 2d66e7aaf..2d45e2ff1 100644 --- a/kernel/src/arch/x86_64/process/syscall.rs +++ b/kernel/src/arch/x86_64/process/syscall.rs @@ -22,15 +22,16 @@ impl Syscall { envp: Vec, regs: &mut TrapFrame, ) -> Result<(), SystemError> { - // kdebug!( - // "tmp_rs_execve: path: {:?}, argv: {:?}, envp: {:?}\n", - // path, - // argv, - // envp - // ); // 关中断,防止在设置地址空间的时候,发生中断,然后进调度器,出现错误。 let irq_guard = unsafe { CurrentIrqArch::save_and_disable_irq() }; let pcb = ProcessManager::current_pcb(); + crate::kdebug!( + "pid: {:?} do_execve: path: {:?}, argv: {:?}, envp: {:?}\n", + pcb.pid(), + path, + argv, + envp + ); let mut basic_info = pcb.basic_mut(); // 暂存原本的用户地址空间的引用(因为如果在切换页表之前释放了它,可能会造成内存use after free) @@ -109,10 +110,10 @@ impl Syscall { // kdebug!("regs: {:?}\n", regs); - // kdebug!( - // "tmp_rs_execve: done, load_result.entry_point()={:?}", - // load_result.entry_point() - // ); + crate::kdebug!( + "tmp_rs_execve: done, load_result.entry_point()={:?}", + load_result.entry_point() + ); return Ok(()); } diff --git a/kernel/src/arch/x86_64/syscall.rs b/kernel/src/arch/x86_64/syscall.rs index 0e915a1fd..e1943c215 100644 --- a/kernel/src/arch/x86_64/syscall.rs +++ b/kernel/src/arch/x86_64/syscall.rs @@ -7,15 +7,25 @@ use crate::{ ipc::signal_types::SignalArch, libs::align::SafeForZero, mm::VirtAddr, + process::ProcessManager, syscall::{Syscall, SystemError, SYS_RT_SIGRETURN}, }; use alloc::string::String; use super::{interrupt::TrapFrame, mm::barrier::mfence}; +pub const SYS_LSTAT: usize = 6; +pub const SYS_READV: usize = 19; pub const SYS_ACCESS: usize = 21; -pub const SYS_PRLIMIT64: usize = 302; +pub const SYS_UNLINK: usize = 87; +pub const SYS_CHMOD: usize = 90; +pub const SYS_FCHMOD: usize = 91; +pub const SYS_UMASK: usize = 95; +pub const SYS_SYSINFO: usize = 99; +pub const SYS_CLOCK_GETTIME: usize = 228; +pub const SYS_FCHMODAT: usize = 268; pub const SYS_FACCESSAT: usize = 269; +pub const SYS_PRLIMIT64: usize = 302; pub const SYS_FACCESSAT2: usize = 439; /// ### 存储PCB系统调用栈以及在syscall过程中暂存用户态rsp的结构体 @@ -44,9 +54,15 @@ extern "C" { } macro_rules! syscall_return { - ($val:expr, $regs:expr) => {{ + ($val:expr, $regs:expr, $show:expr) => {{ let ret = $val; $regs.rax = ret as u64; + + if $show { + let pid = ProcessManager::current_pcb().pid(); + crate::kdebug!("syscall return:pid={:?},ret= {:?}\n", pid, ret as isize); + } + unsafe { CurrentIrqArch::interrupt_disable(); } @@ -69,18 +85,34 @@ pub extern "sysv64" fn syscall_handler(frame: &mut TrapFrame) -> () { frame.r9 as usize, ]; mfence(); + let pid = ProcessManager::current_pcb().pid(); + let show = false; + // let show = if syscall_num != SYS_SCHED && pid.data() > 3 { + // true + // } else { + // false + // }; + + if show { + crate::kdebug!("syscall: pid: {:?}, num={:?}\n", pid, syscall_num); + } // Arch specific syscall match syscall_num { SYS_RT_SIGRETURN => { - syscall_return!(X86_64SignalArch::sys_rt_sigreturn(frame) as usize, frame); + syscall_return!( + X86_64SignalArch::sys_rt_sigreturn(frame) as usize, + frame, + show + ); } _ => {} } syscall_return!( Syscall::handle(syscall_num, &args, frame).unwrap_or_else(|e| e.to_posix_errno() as usize) as u64, - frame + frame, + show ); } diff --git a/kernel/src/filesystem/vfs/core.rs b/kernel/src/filesystem/vfs/core.rs index 53ccdce09..2225d45e1 100644 --- a/kernel/src/filesystem/vfs/core.rs +++ b/kernel/src/filesystem/vfs/core.rs @@ -16,10 +16,15 @@ use crate::{ vfs::{mount::MountFS, syscall::ModeType, AtomicInodeId, FileSystem, FileType}, }, kdebug, kerror, kinfo, + process::ProcessManager, syscall::SystemError, }; -use super::{file::FileMode, utils::rsplit_path, IndexNode, InodeId, MAX_PATHLEN}; +use super::{ + file::FileMode, + utils::{rsplit_path, user_path_at}, + IndexNode, InodeId, MAX_PATHLEN, VFS_MAX_FOLLOW_SYMLINK_TIMES, +}; /// @brief 原子地生成新的Inode号。 /// 请注意,所有的inode号都需要通过该函数来生成.全局的inode号,除了以下两个特殊的以外,都是唯一的 @@ -206,13 +211,17 @@ pub fn do_mkdir(path: &str, _mode: FileMode) -> Result { } /// @brief 删除文件夹 -pub fn do_remove_dir(path: &str) -> Result { +pub fn do_remove_dir(dirfd: i32, path: &str) -> Result { // 文件名过长 if path.len() > MAX_PATHLEN as usize { return Err(SystemError::ENAMETOOLONG); } - let inode: Result, SystemError> = ROOT_INODE().lookup(path); + let pcb = ProcessManager::current_pcb(); + let (inode_begin, remain_path) = user_path_at(&pcb, dirfd, path.to_string())?; + + let inode: Result, SystemError> = + inode_begin.lookup_follow_symlink(remain_path.as_str(), VFS_MAX_FOLLOW_SYMLINK_TIMES); if inode.is_err() { let errno = inode.unwrap_err(); @@ -222,9 +231,10 @@ pub fn do_remove_dir(path: &str) -> Result { } } - let (filename, parent_path) = rsplit_path(path); + let (filename, parent_path) = rsplit_path(&remain_path); // 查找父目录 - let parent_inode: Arc = ROOT_INODE().lookup(parent_path.unwrap_or("/"))?; + let parent_inode: Arc = inode_begin + .lookup_follow_symlink(parent_path.unwrap_or("/"), VFS_MAX_FOLLOW_SYMLINK_TIMES)?; if parent_inode.metadata()?.file_type != FileType::Dir { return Err(SystemError::ENOTDIR); @@ -242,13 +252,16 @@ pub fn do_remove_dir(path: &str) -> Result { } /// @brief 删除文件 -pub fn do_unlink_at(path: &str, _mode: FileMode) -> Result { +pub fn do_unlink_at(dirfd: i32, path: &str) -> Result { // 文件名过长 if path.len() > MAX_PATHLEN as usize { return Err(SystemError::ENAMETOOLONG); } + let pcb = ProcessManager::current_pcb(); + let (inode_begin, remain_path) = user_path_at(&pcb, dirfd, path.to_string())?; - let inode: Result, SystemError> = ROOT_INODE().lookup(path); + let inode: Result, SystemError> = + inode_begin.lookup_follow_symlink(&remain_path, VFS_MAX_FOLLOW_SYMLINK_TIMES); if inode.is_err() { let errno = inode.clone().unwrap_err(); @@ -264,7 +277,8 @@ pub fn do_unlink_at(path: &str, _mode: FileMode) -> Result { let (filename, parent_path) = rsplit_path(path); // 查找父目录 - let parent_inode: Arc = ROOT_INODE().lookup(parent_path.unwrap_or("/"))?; + let parent_inode: Arc = inode_begin + .lookup_follow_symlink(parent_path.unwrap_or("/"), VFS_MAX_FOLLOW_SYMLINK_TIMES)?; if parent_inode.metadata()?.file_type != FileType::Dir { return Err(SystemError::ENOTDIR); diff --git a/kernel/src/filesystem/vfs/file.rs b/kernel/src/filesystem/vfs/file.rs index e21aabc48..ceb27bc9b 100644 --- a/kernel/src/filesystem/vfs/file.rs +++ b/kernel/src/filesystem/vfs/file.rs @@ -19,6 +19,7 @@ use super::{Dirent, FileType, IndexNode, InodeId, Metadata, SpecialNodeData}; /// 文件私有信息的枚举类型 #[derive(Debug, Clone)] +#[allow(dead_code)] pub enum FilePrivateData { /// 管道文件私有信息 Pipefs(PipeFsPrivateData), @@ -198,6 +199,7 @@ impl File { } /// @brief 根据inode号获取子目录项的名字 + #[allow(dead_code)] pub fn get_entry_name(&self, ino: InodeId) -> Result { return self.inode.get_entry_name(ino); } @@ -535,6 +537,7 @@ impl FileDescriptorVec { return Ok(()); } + #[allow(dead_code)] pub fn iter(&self) -> FileDescriptorIterator { return FileDescriptorIterator::new(self); } diff --git a/kernel/src/filesystem/vfs/mod.rs b/kernel/src/filesystem/vfs/mod.rs index 617560245..15b8387f3 100644 --- a/kernel/src/filesystem/vfs/mod.rs +++ b/kernel/src/filesystem/vfs/mod.rs @@ -1,5 +1,3 @@ -#![allow(dead_code)] - pub mod core; pub mod fcntl; pub mod file; @@ -50,6 +48,7 @@ pub enum FileType { Socket, } +#[allow(dead_code)] #[derive(Debug, Clone)] pub enum SpecialNodeData { /// 管道文件 @@ -62,6 +61,7 @@ pub enum SpecialNodeData { /* these are defined by POSIX and also present in glibc's dirent.h */ /// 完整含义请见 http://www.gnu.org/software/libc/manual/html_node/Directory-Entries.html +#[allow(dead_code)] pub const DT_UNKNOWN: u16 = 0; /// 命名管道,或者FIFO pub const DT_FIFO: u16 = 1; @@ -78,7 +78,9 @@ pub const DT_LNK: u16 = 10; // 是一个socket pub const DT_SOCK: u16 = 12; // 这个是抄Linux的,还不知道含义 +#[allow(dead_code)] pub const DT_WHT: u16 = 14; +#[allow(dead_code)] pub const DT_MAX: u16 = 16; /// vfs容许的最大的符号链接跳转次数 diff --git a/kernel/src/filesystem/vfs/open.rs b/kernel/src/filesystem/vfs/open.rs index 2cbfa123e..c918ea92b 100644 --- a/kernel/src/filesystem/vfs/open.rs +++ b/kernel/src/filesystem/vfs/open.rs @@ -1,14 +1,20 @@ -use crate::syscall::SystemError; +use crate::{ + process::ProcessManager, + syscall::{user_access::check_and_clone_cstr, SystemError}, +}; -use super::{fcntl::AtFlags, syscall::ModeType}; +use super::{ + fcntl::AtFlags, syscall::ModeType, utils::user_path_at, MAX_PATHLEN, + VFS_MAX_FOLLOW_SYMLINK_TIMES, +}; pub(super) fn do_faccessat( - _dirfd: i32, - _pathname: *const u8, + dirfd: i32, + path: *const u8, mode: ModeType, flags: u32, ) -> Result { - if (mode.bits() & (!ModeType::S_IXUGO.bits())) != 0 { + if (mode.bits() & (!ModeType::S_IRWXO.bits())) != 0 { return Err(SystemError::EINVAL); } @@ -22,6 +28,35 @@ pub(super) fn do_faccessat( // let follow_symlink = flags & AtFlags::AT_SYMLINK_NOFOLLOW.bits() as u32 == 0; + let path = check_and_clone_cstr(path, Some(MAX_PATHLEN))?; + + if path.len() == 0 { + return Err(SystemError::EINVAL); + } + + let (inode, path) = user_path_at(&ProcessManager::current_pcb(), dirfd, path)?; + + // 如果找不到文件,则返回错误码ENOENT + let _inode = inode.lookup_follow_symlink(path.as_str(), VFS_MAX_FOLLOW_SYMLINK_TIMES)?; + // todo: 接着完善(可以借鉴linux 6.1.9的do_faccessat) return Ok(0); } + +pub fn do_fchmodat(dirfd: i32, path: *const u8, _mode: ModeType) -> Result { + let path = check_and_clone_cstr(path, Some(MAX_PATHLEN))?; + + if path.len() == 0 { + return Err(SystemError::EINVAL); + } + + let (inode, path) = user_path_at(&ProcessManager::current_pcb(), dirfd, path)?; + + // 如果找不到文件,则返回错误码ENOENT + let _inode = inode.lookup_follow_symlink(path.as_str(), VFS_MAX_FOLLOW_SYMLINK_TIMES)?; + + kwarn!("do_fchmodat: not implemented yet\n"); + // todo: 真正去改变文件的权限 + + return Ok(0); +} diff --git a/kernel/src/filesystem/vfs/syscall.rs b/kernel/src/filesystem/vfs/syscall.rs index 40e4a52fb..58b6cddad 100644 --- a/kernel/src/filesystem/vfs/syscall.rs +++ b/kernel/src/filesystem/vfs/syscall.rs @@ -9,7 +9,7 @@ use alloc::{ use crate::{ driver::base::{block::SeekFrom, device::DeviceNumber}, filesystem::vfs::file::FileDescriptorVec, - include::bindings::bindings::{verify_area, AT_REMOVEDIR, PROC_MAX_FD_NUM}, + include::bindings::bindings::{verify_area, PROC_MAX_FD_NUM}, kerror, libs::rwlock::RwLockWriteGuard, mm::VirtAddr, @@ -25,7 +25,7 @@ use super::{ core::{do_mkdir, do_remove_dir, do_unlink_at}, fcntl::{AtFlags, FcntlCommand, FD_CLOEXEC}, file::{File, FileMode}, - open::do_faccessat, + open::{do_faccessat, do_fchmodat}, utils::{rsplit_path, user_path_at}, Dirent, FileType, IndexNode, MAX_PATHLEN, ROOT_INODE, VFS_MAX_FOLLOW_SYMLINK_TIMES, }; @@ -153,15 +153,21 @@ impl Syscall { /// @param o_flags 打开文件的标志位 /// /// @return 文件描述符编号,或者是错误码 - pub fn open(path: &str, mode: FileMode) -> Result { + pub fn open(path: &str, mode: FileMode, follow_symlink: bool) -> Result { // kdebug!("open: path: {}, mode: {:?}", path, mode); // 文件名过长 if path.len() > MAX_PATHLEN as usize { return Err(SystemError::ENAMETOOLONG); } - let inode: Result, SystemError> = - ROOT_INODE().lookup_follow_symlink(path, VFS_MAX_FOLLOW_SYMLINK_TIMES); + let inode: Result, SystemError> = ROOT_INODE().lookup_follow_symlink( + path, + if follow_symlink { + VFS_MAX_FOLLOW_SYMLINK_TIMES + } else { + 0 + }, + ); let inode: Arc = if inode.is_err() { let errno = inode.unwrap_err(); @@ -457,15 +463,12 @@ impl Syscall { /// - `flags`:标志位 /// /// - pub fn unlinkat(_dirfd: i32, pathname: &str, flags: u32) -> Result { - // kdebug!("sys_unlink_at={path:?}"); - if (flags & (!AT_REMOVEDIR)) != 0 { - return Err(SystemError::EINVAL); - } + pub fn unlinkat(dirfd: i32, pathname: &str, flags: u32) -> Result { + let flags = AtFlags::from_bits(flags as i32).ok_or(SystemError::EINVAL)?; - if (flags & AT_REMOVEDIR) > 0 { + if flags.contains(AtFlags::AT_REMOVEDIR) { // kdebug!("rmdir"); - match do_remove_dir(&pathname) { + match do_remove_dir(dirfd, &pathname) { Err(err) => { kerror!("Failed to Remove Directory, Error Code = {:?}", err); return Err(err); @@ -476,7 +479,7 @@ impl Syscall { } } - match do_unlink_at(&pathname, FileMode::from_bits_truncate(flags as u32)) { + match do_unlink_at(dirfd, &pathname) { Err(err) => { kerror!("Failed to Remove Directory, Error Code = {:?}", err); return Err(err); @@ -487,6 +490,25 @@ impl Syscall { } } + pub fn unlink(pathname: *const u8) -> Result { + if pathname.is_null() { + return Err(SystemError::EFAULT); + } + let ureader = UserBufferReader::new(pathname, MAX_PATHLEN, true)?; + + let buf: &[u8] = ureader.buffer(0).unwrap(); + + let pathname: &CStr = CStr::from_bytes_until_nul(buf).map_err(|_| SystemError::EINVAL)?; + + let pathname: &str = pathname.to_str().map_err(|_| SystemError::EINVAL)?; + if pathname.len() >= MAX_PATHLEN { + return Err(SystemError::ENAMETOOLONG); + } + let pathname = pathname.trim(); + + return do_unlink_at(AtFlags::AT_FDCWD.bits(), pathname).map(|v| v as usize); + } + /// @brief 根据提供的文件描述符的fd,复制对应的文件结构体,并返回新复制的文件结构体对应的fd pub fn dup(oldfd: i32) -> Result { let binding = ProcessManager::current_pcb().fd_table(); @@ -730,13 +752,6 @@ impl Syscall { return Ok(kstat); } - fn do_stat(path: &str) -> Result { - let fd = Self::open(path, FileMode::O_RDONLY)?; - let ret = Self::do_fstat(fd as i32); - Self::close(fd)?; - ret - } - pub fn fstat(fd: i32, usr_kstat: *mut PosixKstat) -> Result { let kstat = Self::do_fstat(fd)?; if usr_kstat.is_null() { @@ -749,11 +764,17 @@ impl Syscall { } pub fn stat(path: &str, user_kstat: *mut PosixKstat) -> Result { - let fd = Self::open(path, FileMode::O_RDONLY)?; - Self::fstat(fd as i32, user_kstat).map_err(|e| { - Self::close(fd).ok(); - e - }) + let fd = Self::open(path, FileMode::O_RDONLY, true)?; + let r = Self::fstat(fd as i32, user_kstat); + Self::close(fd).ok(); + return r; + } + + pub fn lstat(path: &str, user_kstat: *mut PosixKstat) -> Result { + let fd = Self::open(path, FileMode::O_RDONLY, false)?; + let r = Self::fstat(fd as i32, user_kstat); + Self::close(fd).ok(); + return r; } pub fn mknod( @@ -799,6 +820,20 @@ impl Syscall { Self::write(fd, &data) } + pub fn readv(fd: i32, iov: usize, count: usize) -> Result { + // IoVecs会进行用户态检验 + let mut iovecs = unsafe { IoVecs::from_user(iov as *const IoVec, count, true) }?; + + let mut data = Vec::new(); + data.resize(iovecs.0.iter().map(|x| x.len()).sum(), 0); + + let len = Self::read(fd, &mut data)?; + + iovecs.scatter(&data[..len]); + + return Ok(len); + } + pub fn readlink_at( dirfd: i32, path: *const u8, @@ -840,7 +875,7 @@ impl Syscall { return do_faccessat( AtFlags::AT_FDCWD.bits(), pathname, - ModeType::from_bits_truncate(mode), + ModeType::from_bits(mode).ok_or(SystemError::EINVAL)?, 0, ); } @@ -851,7 +886,42 @@ impl Syscall { mode: u32, flags: u32, ) -> Result { - return do_faccessat(dirfd, pathname, ModeType::from_bits_truncate(mode), flags); + return do_faccessat( + dirfd, + pathname, + ModeType::from_bits(mode).ok_or(SystemError::EINVAL)?, + flags, + ); + } + + pub fn chmod(pathname: *const u8, mode: u32) -> Result { + return do_fchmodat( + AtFlags::AT_FDCWD.bits(), + pathname, + ModeType::from_bits(mode).ok_or(SystemError::EINVAL)?, + ); + } + + pub fn fchmodat(dirfd: i32, pathname: *const u8, mode: u32) -> Result { + return do_fchmodat( + dirfd, + pathname, + ModeType::from_bits(mode).ok_or(SystemError::EINVAL)?, + ); + } + + pub fn fchmod(fd: i32, mode: u32) -> Result { + let _mode = ModeType::from_bits(mode).ok_or(SystemError::EINVAL)?; + let binding = ProcessManager::current_pcb().fd_table(); + let fd_table_guard = binding.read(); + let _file = fd_table_guard + .get_file_by_fd(fd) + .ok_or(SystemError::EBADF)?; + + // fchmod没完全实现,因此不修改文件的权限 + // todo: 实现fchmod + kwarn!("fchmod not fully implemented"); + return Ok(0); } } diff --git a/kernel/src/filesystem/vfs/utils.rs b/kernel/src/filesystem/vfs/utils.rs index 237b4fc06..c8171a65b 100644 --- a/kernel/src/filesystem/vfs/utils.rs +++ b/kernel/src/filesystem/vfs/utils.rs @@ -7,6 +7,7 @@ use super::{fcntl::AtFlags, FileType, IndexNode, ROOT_INODE}; /// @brief 切分路径字符串,返回最左侧那一级的目录名和剩余的部分。 /// /// 举例:对于 /123/456/789/ 本函数返回的第一个值为123, 第二个值为456/789 +#[allow(dead_code)] pub fn split_path(path: &str) -> (&str, Option<&str>) { let mut path_split: core::str::SplitN<&str> = path.trim_matches('/').splitn(2, "/"); let comp = path_split.next().unwrap_or(""); @@ -30,7 +31,7 @@ pub fn rsplit_path(path: &str) -> (&str, Option<&str>) { /// /// ## 返回值 /// -/// 返回值为(需要lookup的inode, 剩余的path) +/// 返回值为(需要执行lookup的inode, 剩余的path) pub fn user_path_at( pcb: &Arc, dirfd: i32, diff --git a/kernel/src/ipc/pipe.rs b/kernel/src/ipc/pipe.rs index b46b49f7d..50ed610eb 100644 --- a/kernel/src/ipc/pipe.rs +++ b/kernel/src/ipc/pipe.rs @@ -6,7 +6,7 @@ use crate::{ FileType, IndexNode, Metadata, PollStatus, }, libs::{spinlock::SpinLock, wait_queue::WaitQueue}, - process::ProcessState, + process::{ProcessManager, ProcessState}, syscall::SystemError, time::TimeSpec, }; @@ -94,6 +94,14 @@ impl IndexNode for LockedPipeInode { buf: &mut [u8], data: &mut FilePrivateData, ) -> Result { + let pcb = ProcessManager::current_pcb(); + let show = if pcb.pid().data() > 3 { true } else { false }; + if show { + kdebug!( + "locked_pipe_inode begin read_at: preempt={}", + ProcessManager::current_pcb().preempt_count() + ); + } // 获取mode let mode: FileMode; if let FilePrivateData::Pipefs(pdata) = data { @@ -128,6 +136,12 @@ impl IndexNode for LockedPipeInode { // 否则在读等待队列中睡眠,并释放锁 unsafe { let irq_guard = CurrentIrqArch::save_and_disable_irq(); + if show { + kdebug!( + "locked_pipe_inode begin to sleep without sched: preempt={}", + ProcessManager::current_pcb().preempt_count() + ); + } inode.read_wait_queue.sleep_without_schedule(); drop(inode); diff --git a/kernel/src/ipc/signal_types.rs b/kernel/src/ipc/signal_types.rs index 43654a2ed..8c3cabb5f 100644 --- a/kernel/src/ipc/signal_types.rs +++ b/kernel/src/ipc/signal_types.rs @@ -335,6 +335,11 @@ impl Default for SigPending { } impl SigPending { + /// 判断是否有待处理的信号 + pub fn has_pending(&self) -> bool { + return !self.signal.is_empty(); + } + pub fn signal(&self) -> SigSet { self.signal } diff --git a/kernel/src/lib.rs b/kernel/src/lib.rs index f980a436c..e8ed7d1bf 100644 --- a/kernel/src/lib.rs +++ b/kernel/src/lib.rs @@ -7,6 +7,7 @@ #![feature(const_trait_impl)] #![feature(const_refs_to_cell)] #![feature(core_intrinsics)] +#![feature(cstr_from_bytes_until_nul)] #![feature(c_void_variant)] #![feature(drain_filter)] #![feature(inline_const)] diff --git a/kernel/src/process/exit.rs b/kernel/src/process/exit.rs new file mode 100644 index 000000000..f05649e92 --- /dev/null +++ b/kernel/src/process/exit.rs @@ -0,0 +1,253 @@ +use core::intrinsics::likely; + +use alloc::sync::Arc; + +use crate::{ + arch::{ + ipc::signal::{SigChildCode, Signal}, + sched::sched, + CurrentIrqArch, + }, + exception::InterruptArch, + syscall::{user_access::UserBufferWriter, SystemError}, +}; + +use super::{ + abi::WaitOption, pid::PidType, resource::RUsage, Pid, ProcessControlBlock, ProcessManager, + ProcessState, +}; + +/// 内核wait4时的参数 +#[derive(Debug)] +pub struct KernelWaitOption<'a> { + pub pid_type: PidType, + pub pid: Pid, + pub options: WaitOption, + pub ret_status: i32, + pub ret_info: Option, + pub ret_rusage: Option<&'a mut RUsage>, + pub no_task_error: Option, +} + +#[derive(Debug, Clone)] +pub struct WaitIdInfo { + pub pid: Pid, + pub status: i32, + pub cause: i32, +} + +impl<'a> KernelWaitOption<'a> { + pub fn new(pid_type: PidType, pid: Pid, options: WaitOption) -> Self { + Self { + pid_type, + pid, + options, + ret_status: 0, + ret_info: None, + ret_rusage: None, + no_task_error: None, + } + } +} + +pub fn kernel_wait4( + mut pid: i64, + wstatus_buf: Option>, + options: WaitOption, + rusage_buf: Option<&mut RUsage>, +) -> Result { + // i64::MIN is not defined + if pid == i64::MIN { + return Err(SystemError::ESRCH); + } + + // 判断pid类型 + let pidtype: PidType; + + if pid == -1 { + pidtype = PidType::MAX; + } else if pid < 0 { + pidtype = PidType::PGID; + kwarn!("kernel_wait4: currently not support pgid, default to wait for pid\n"); + pid = -pid; + } else if pid == 0 { + pidtype = PidType::PGID; + kwarn!("kernel_wait4: currently not support pgid, default to wait for pid\n"); + pid = ProcessManager::current_pcb().pid().data() as i64; + } else { + pidtype = PidType::PID; + } + + let pid = Pid(pid as usize); + + // 构造参数 + let mut kwo = KernelWaitOption::new(pidtype, pid, options); + + kwo.options.insert(WaitOption::WEXITED); + kwo.ret_rusage = rusage_buf; + + // 调用do_wait,执行等待 + let r = do_wait(&mut kwo)?; + + // 如果有wstatus_buf,则将wstatus写入用户空间 + if let Some(mut wstatus_buf) = wstatus_buf { + let wstatus = if let Some(ret_info) = &kwo.ret_info { + ret_info.status + } else { + kwo.ret_status + }; + wstatus_buf.copy_one_to_user(&wstatus, 0)?; + } + + return Ok(r); +} + +/// 参考 https://opengrok.ringotek.cn/xref/linux-6.1.9/kernel/exit.c#1573 +fn do_wait(kwo: &mut KernelWaitOption) -> Result { + let mut retval: Result; + // todo: 在signal struct里面增加等待队列,并在这里初始化子进程退出的回调,使得子进程退出时,能唤醒当前进程。 + + loop { + kwo.no_task_error = Some(SystemError::ECHILD); + let child_pcb = ProcessManager::find(kwo.pid).ok_or(SystemError::ECHILD); + if kwo.pid_type != PidType::MAX && child_pcb.is_err() { + if let Some(err) = &kwo.no_task_error { + retval = Err(err.clone()); + } else { + retval = Ok(0); + } + + if !kwo.options.contains(WaitOption::WNOHANG) { + retval = Err(SystemError::ERESTARTSYS); + if ProcessManager::current_pcb() + .sig_info_irqsave() + .sig_pending() + .has_pending() + == false + { + // todo: 增加子进程退出的回调后,这里可以直接等待在自身的child_wait等待队列上。 + continue; + } else { + break; + } + } else { + break; + } + } + + if kwo.pid_type == PidType::PID { + let child_pcb = child_pcb.unwrap(); + // 获取weak引用,以便于在do_waitpid中能正常drop pcb + let child_weak = Arc::downgrade(&child_pcb); + let r = do_waitpid(child_pcb, kwo); + if r.is_some() { + return r.unwrap(); + } else { + child_weak.upgrade().unwrap().wait_queue.sleep(); + } + } else if kwo.pid_type == PidType::MAX { + // 等待任意子进程 + // todo: 这里有问题!如果正在for循环的过程中,子进程退出了,可能会导致父进程永远等待。 + let current_pcb = ProcessManager::current_pcb(); + let rd_childen = current_pcb.children.read(); + let irq_guard = unsafe { CurrentIrqArch::save_and_disable_irq() }; + for pid in rd_childen.iter() { + let pcb = ProcessManager::find(*pid).ok_or(SystemError::ECHILD)?; + if pcb.sched_info().state().is_exited() { + kwo.ret_status = pcb.sched_info().state().exit_code().unwrap() as i32; + drop(pcb); + unsafe { ProcessManager::release(pid.clone()) }; + return Ok(pid.clone().into()); + } else { + unsafe { pcb.wait_queue.sleep_without_schedule() }; + } + } + drop(irq_guard); + sched(); + } else { + // todo: 对于pgid的处理 + kwarn!("kernel_wait4: currently not support {:?}", kwo.pid_type); + return Err(SystemError::EINVAL); + } + } + + return retval; +} + +fn do_waitpid( + child_pcb: Arc, + kwo: &mut KernelWaitOption, +) -> Option> { + let state = child_pcb.sched_info().state(); + // 获取退出码 + match state { + ProcessState::Runnable => { + if kwo.options.contains(WaitOption::WNOHANG) + || kwo.options.contains(WaitOption::WNOWAIT) + { + if let Some(info) = &mut kwo.ret_info { + *info = WaitIdInfo { + pid: child_pcb.pid(), + status: Signal::SIGCONT as i32, + cause: SigChildCode::Continued.into(), + }; + } else { + kwo.ret_status = 0xffff; + } + + return Some(Ok(0)); + } + } + ProcessState::Blocked(_) | ProcessState::Stopped => { + // todo: 在stopped里面,添加code字段,表示停止的原因 + let exitcode = 0; + // 由于目前不支持ptrace,因此这个值为false + let ptrace = false; + + if (!ptrace) && (!kwo.options.contains(WaitOption::WUNTRACED)) { + kwo.ret_status = 0; + return Some(Ok(0)); + } + + if likely(!(kwo.options.contains(WaitOption::WNOWAIT))) { + kwo.ret_status = (exitcode << 8) | 0x7f; + } + if let Some(infop) = &mut kwo.ret_info { + *infop = WaitIdInfo { + pid: child_pcb.pid(), + status: exitcode, + cause: SigChildCode::Stopped.into(), + }; + } + + return Some(Ok(child_pcb.pid().data())); + } + ProcessState::Exited(status) => { + let pid = child_pcb.pid(); + kdebug!("wait4: child exited, pid: {:?}, status: {status}\n", pid); + + if likely(!kwo.options.contains(WaitOption::WEXITED)) { + return None; + } + + // todo: 增加对线程组的group leader的处理 + + if let Some(infop) = &mut kwo.ret_info { + *infop = WaitIdInfo { + pid, + status: status as i32, + cause: SigChildCode::Exited.into(), + }; + } + + kwo.ret_status = status as i32; + + drop(child_pcb); + // kdebug!("wait4: to release {pid:?}"); + unsafe { ProcessManager::release(pid) }; + return Some(Ok(pid.into())); + } + }; + + return None; +} diff --git a/kernel/src/process/mod.rs b/kernel/src/process/mod.rs index 9c064b9b7..84c2a2e28 100644 --- a/kernel/src/process/mod.rs +++ b/kernel/src/process/mod.rs @@ -55,6 +55,7 @@ use self::kthread::WorkerPrivate; pub mod abi; pub mod c_adapter; pub mod exec; +pub mod exit; pub mod fork; pub mod idle; pub mod init; @@ -473,6 +474,7 @@ impl ProcessState { return matches!(self, ProcessState::Blocked(true)); } + /// Returns `true` if the process state is [`Exited`]. #[inline(always)] pub fn is_exited(&self) -> bool { return matches!(self, ProcessState::Exited(_)); @@ -485,6 +487,15 @@ impl ProcessState { pub fn is_stopped(&self) -> bool { matches!(self, ProcessState::Stopped) } + + /// Returns exit code if the process state is [`Exited`]. + #[inline(always)] + pub fn exit_code(&self) -> Option { + match self { + ProcessState::Exited(code) => Some(*code), + _ => None, + } + } } bitflags! { @@ -848,6 +859,10 @@ impl ProcessControlBlock { self.sig_info.read() } + pub fn sig_info_irqsave(&self) -> RwLockReadGuard { + self.sig_info.read_irqsave() + } + pub fn try_siginfo(&self, times: u8) -> Option> { for _ in 0..times { if let Some(r) = self.sig_info.try_read() { diff --git a/kernel/src/process/syscall.rs b/kernel/src/process/syscall.rs index aeee06077..c32699c25 100644 --- a/kernel/src/process/syscall.rs +++ b/kernel/src/process/syscall.rs @@ -8,13 +8,13 @@ use alloc::{ use super::{ abi::WaitOption, + exit::kernel_wait4, fork::{CloneFlags, KernelCloneArgs}, resource::{RLimit64, RLimitID, RUsage, RUsageWho}, - KernelStack, Pid, ProcessManager, ProcessState, + KernelStack, Pid, ProcessManager, }; use crate::{ - arch::{interrupt::TrapFrame, sched::sched, CurrentIrqArch, MMArch}, - exception::InterruptArch, + arch::{interrupt::TrapFrame, MMArch}, filesystem::{ procfs::procfs_register_pid, vfs::{file::FileDescriptorVec, MAX_PATHLEN}, @@ -24,9 +24,7 @@ use crate::{ process::ProcessControlBlock, sched::completion::Completion, syscall::{ - user_access::{ - check_and_clone_cstr, check_and_clone_cstr_array, UserBufferReader, UserBufferWriter, - }, + user_access::{check_and_clone_cstr, check_and_clone_cstr_array, UserBufferWriter}, Syscall, SystemError, }, }; @@ -34,15 +32,25 @@ use crate::{ impl Syscall { pub fn fork(frame: &mut TrapFrame) -> Result { let r = ProcessManager::fork(frame, CloneFlags::empty()).map(|pid| pid.into()); + kdebug!( + "fork: current pid: {:?}, return: {:?}\n", + ProcessManager::current_pcb().pid(), + r + ); return r; } pub fn vfork(frame: &mut TrapFrame) -> Result { - ProcessManager::fork( - frame, - CloneFlags::CLONE_VM | CloneFlags::CLONE_FS | CloneFlags::CLONE_SIGNAL, - ) - .map(|pid| pid.into()) + // 由于Linux vfork需要保证子进程先运行(除非子进程调用execve或者exit), + // 而我们目前没有实现这个特性,所以暂时使用fork代替vfork(linux文档表示这样也是也可以的) + Self::fork(frame) + + // 下面是以前的实现,除非我们实现了子进程先运行的特性,否则不要使用,不然会导致父进程数据损坏 + // ProcessManager::fork( + // frame, + // CloneFlags::CLONE_VM | CloneFlags::CLONE_FS | CloneFlags::CLONE_SIGNAL, + // ) + // .map(|pid| pid.into()) } pub fn execve( @@ -100,98 +108,35 @@ impl Syscall { options: i32, rusage: *mut c_void, ) -> Result { - let ret = WaitOption::from_bits(options as u32); - let options = match ret { - Some(options) => options, - None => { - return Err(SystemError::EINVAL); - } + let options = WaitOption::from_bits(options as u32).ok_or(SystemError::EINVAL)?; + + let wstatus_buf = if wstatus.is_null() { + None + } else { + Some(UserBufferWriter::new( + wstatus, + core::mem::size_of::(), + true, + )?) }; - let mut _rusage_buf = - UserBufferReader::new::(rusage, core::mem::size_of::(), true)?; - - let mut wstatus_buf = - UserBufferWriter::new::(wstatus, core::mem::size_of::(), true)?; - - let cur_pcb = ProcessManager::current_pcb(); - let rd_childen = cur_pcb.children.read(); - - if pid > 0 { - let pid = Pid(pid as usize); - let child_pcb = ProcessManager::find(pid).ok_or(SystemError::ECHILD)?; - drop(rd_childen); - - loop { - let state = child_pcb.sched_info().state(); - // 获取退出码 - match state { - ProcessState::Runnable => { - if options.contains(WaitOption::WNOHANG) - || options.contains(WaitOption::WNOWAIT) - { - if !wstatus.is_null() { - wstatus_buf.copy_one_to_user(&WaitOption::WCONTINUED.bits(), 0)?; - } - return Ok(0); - } - } - ProcessState::Blocked(_) | ProcessState::Stopped => { - // 指定WUNTRACED则等待暂停的进程,不指定则返回0 - if !options.contains(WaitOption::WUNTRACED) - || options.contains(WaitOption::WNOWAIT) - { - if !wstatus.is_null() { - wstatus_buf.copy_one_to_user(&WaitOption::WSTOPPED.bits(), 0)?; - } - return Ok(0); - } - } - ProcessState::Exited(status) => { - // kdebug!("wait4: child exited, pid: {:?}, status: {status}\n", pid); - if !wstatus.is_null() { - wstatus_buf.copy_one_to_user( - &(status as u32 | WaitOption::WEXITED.bits()), - 0, - )?; - } - drop(child_pcb); - // kdebug!("wait4: to release {pid:?}"); - unsafe { ProcessManager::release(pid) }; - return Ok(pid.into()); - } - }; - - // 等待指定进程 - child_pcb.wait_queue.sleep(); - } - } else if pid < -1 { - // TODO 判断是否pgid == -pid(等待指定组任意进程) - // 暂时不支持 - return Err(SystemError::EINVAL); - } else if pid == 0 { - // TODO 判断是否pgid == current_pgid(等待当前组任意进程) - // 暂时不支持 - return Err(SystemError::EINVAL); + let mut tmp_rusage = if rusage.is_null() { + None } else { - // 等待任意子进程(这两) - let irq_guard = unsafe { CurrentIrqArch::save_and_disable_irq() }; - for pid in rd_childen.iter() { - let pcb = ProcessManager::find(*pid).ok_or(SystemError::ECHILD)?; - if pcb.sched_info().state().is_exited() { - if !wstatus.is_null() { - wstatus_buf.copy_one_to_user(&0, 0)?; - } - return Ok(pid.clone().into()); - } else { - unsafe { pcb.wait_queue.sleep_without_schedule() }; - } - } - drop(irq_guard); - sched(); - } + Some(RUsage::default()) + }; - return Ok(0); + let r = kernel_wait4(pid, wstatus_buf, options, tmp_rusage.as_mut())?; + + if !rusage.is_null() { + let mut rusage_buf = UserBufferWriter::new::( + rusage as *mut RUsage, + core::mem::size_of::(), + true, + )?; + rusage_buf.copy_one_to_user(&tmp_rusage.unwrap(), 0)?; + } + return Ok(r); } /// # 退出进程 @@ -356,16 +301,12 @@ impl Syscall { pub fn prlimit64( _pid: Pid, resource: usize, - new_limit: *const RLimit64, + _new_limit: *const RLimit64, old_limit: *mut RLimit64, ) -> Result { let resource = RLimitID::try_from(resource)?; let mut writer = None; - if new_limit.is_null() { - return Err(SystemError::EINVAL); - } - if !old_limit.is_null() { writer = Some(UserBufferWriter::new( old_limit, @@ -374,8 +315,6 @@ impl Syscall { )?); } - let _reader = UserBufferReader::new(new_limit, core::mem::size_of::(), true)?; - match resource { RLimitID::Stack => { if let Some(mut writer) = writer { diff --git a/kernel/src/syscall/misc.rs b/kernel/src/syscall/misc.rs new file mode 100644 index 000000000..c4e4929b6 --- /dev/null +++ b/kernel/src/syscall/misc.rs @@ -0,0 +1,57 @@ +use crate::arch::mm::LockedFrameAllocator; + +use super::{user_access::UserBufferWriter, Syscall, SystemError}; + +#[repr(C)] + +/// 系统信息 +/// +/// 参考 https://opengrok.ringotek.cn/xref/linux-6.1.9/include/uapi/linux/sysinfo.h#8 +#[derive(Debug, Default, Copy, Clone)] +pub struct SysInfo { + uptime: u64, + loads: [u64; 3], + totalram: u64, + freeram: u64, + sharedram: u64, + bufferram: u64, + totalswap: u64, + freeswap: u64, + procs: u16, + pad: u16, + totalhigh: u64, + freehigh: u64, + mem_unit: u32, + // 这后面还有一小段,但是我们不需要 +} + +impl Syscall { + pub fn sysinfo(info: *mut SysInfo) -> Result { + let mut writer = UserBufferWriter::new(info, core::mem::size_of::(), true)?; + let mut sysinfo = SysInfo::default(); + + let mem = LockedFrameAllocator.get_usage(); + sysinfo.uptime = 0; + sysinfo.loads = [0; 3]; + sysinfo.totalram = mem.total().bytes() as u64; + sysinfo.freeram = mem.free().bytes() as u64; + sysinfo.sharedram = 0; + sysinfo.bufferram = 0; + sysinfo.totalswap = 0; + sysinfo.freeswap = 0; + sysinfo.procs = 0; + sysinfo.pad = 0; + sysinfo.totalhigh = 0; + sysinfo.freehigh = 0; + sysinfo.mem_unit = 0; + + writer.copy_one_to_user(&sysinfo, 0)?; + + return Ok(0); + } + + pub fn umask(_mask: u32) -> Result { + kwarn!("SYS_UMASK has not yet been implemented\n"); + return Ok(0o777); + } +} diff --git a/kernel/src/syscall/mod.rs b/kernel/src/syscall/mod.rs index 92a4fd74a..0987c42f7 100644 --- a/kernel/src/syscall/mod.rs +++ b/kernel/src/syscall/mod.rs @@ -4,7 +4,10 @@ use core::{ }; use crate::{ - arch::syscall::{SYS_ACCESS, SYS_FACCESSAT, SYS_FACCESSAT2, SYS_PRLIMIT64}, + arch::syscall::{ + SYS_ACCESS, SYS_CHMOD, SYS_CLOCK_GETTIME, SYS_FACCESSAT, SYS_FACCESSAT2, SYS_FCHMOD, + SYS_FCHMODAT, SYS_LSTAT, SYS_PRLIMIT64, SYS_READV, SYS_SYSINFO, SYS_UMASK, SYS_UNLINK, + }, libs::{futex::constant::FutexFlag, rand::GRandFlags}, process::{ fork::KernelCloneArgs, @@ -35,8 +38,12 @@ use crate::{ }, }; -use self::user_access::{UserBufferReader, UserBufferWriter}; +use self::{ + misc::SysInfo, + user_access::{UserBufferReader, UserBufferWriter}, +}; +pub mod misc; pub mod user_access; #[repr(i32)] @@ -317,6 +324,9 @@ pub enum SystemError { EVMPRTLDFailed = 135, EVMLAUNCHFailed = 136, KVM_HVA_ERR_BAD = 137, + + // === 以下错误码不应该被用户态程序使用 === + ERESTARTSYS = 512, } impl SystemError { @@ -383,7 +393,6 @@ pub const SYS_SOCKET_PAIR: usize = 53; pub const SYS_SETSOCKOPT: usize = 54; pub const SYS_GETSOCKOPT: usize = 55; -#[allow(dead_code)] pub const SYS_CLONE: usize = 56; pub const SYS_FORK: usize = 57; pub const SYS_VFORK: usize = 58; @@ -507,7 +516,7 @@ impl Syscall { let flags = args[1]; let open_flags: FileMode = FileMode::from_bits_truncate(flags as u32); - Self::open(path, open_flags) + Self::open(path, open_flags, true) }; res } @@ -657,13 +666,13 @@ impl Syscall { } } SYS_WAIT4 => { - let pid = args[0] as i64; + let pid = args[0] as i32; let wstatus = args[1] as *mut i32; let options = args[2] as c_int; let rusage = args[3] as *mut c_void; // 权限校验 // todo: 引入rusage之后,更正以下权限校验代码中,rusage的大小 - Self::wait4(pid, wstatus, options, rusage) + Self::wait4(pid.into(), wstatus, options, rusage) } SYS_EXIT => { @@ -754,6 +763,11 @@ impl Syscall { } } } + + SYS_UNLINK => { + let pathname = args[0] as *const u8; + Self::unlink(pathname) + } SYS_KILL => { let pid = Pid::new(args[0]); let sig = args[1] as c_int; @@ -1093,13 +1107,14 @@ impl Syscall { Self::do_futex(uaddr, operation, val, timespec, uaddr2, utime as u32, val3) } + SYS_READV => Self::readv(args[0] as i32, args[1], args[2]), SYS_WRITEV => Self::writev(args[0] as i32, args[1], args[2]), SYS_ARCH_PRCTL => Self::arch_prctl(args[0], args[1]), SYS_SET_TID_ADDR => Self::set_tid_address(args[0]), - SYS_STAT => { + SYS_STAT | SYS_LSTAT => { let path: &CStr = unsafe { CStr::from_ptr(args[0] as *const c_char) }; let path: Result<&str, core::str::Utf8Error> = path.to_str(); let res = if path.is_err() { @@ -1109,7 +1124,13 @@ impl Syscall { let kstat = args[1] as *mut PosixKstat; let vaddr = VirtAddr::new(kstat as usize); match verify_area(vaddr, core::mem::size_of::()) { - Ok(_) => Self::stat(path, kstat), + Ok(_) => { + if syscall_num == SYS_STAT { + Self::stat(path, kstat) + } else { + Self::lstat(path, kstat) + } + } Err(e) => Err(e), } }; @@ -1225,6 +1246,39 @@ impl Syscall { Self::faccessat2(dirfd, pathname, mode, flags) } + SYS_CLOCK_GETTIME => { + let clockid = args[0] as i32; + let timespec = args[1] as *mut TimeSpec; + Self::clock_gettime(clockid, timespec) + } + + SYS_SYSINFO => { + let info = args[0] as *mut SysInfo; + Self::sysinfo(info) + } + + SYS_UMASK => { + let mask = args[0] as u32; + Self::umask(mask) + } + + SYS_CHMOD => { + let pathname = args[0] as *const u8; + let mode = args[1] as u32; + Self::chmod(pathname, mode) + } + SYS_FCHMOD => { + let fd = args[0] as i32; + let mode = args[1] as u32; + Self::fchmod(fd, mode) + } + SYS_FCHMODAT => { + let dirfd = args[0] as i32; + let pathname = args[1] as *const u8; + let mode = args[2] as u32; + Self::fchmodat(dirfd, pathname, mode) + } + _ => panic!("Unsupported syscall ID: {}", syscall_num), }; return r; diff --git a/kernel/src/syscall/user_access.rs b/kernel/src/syscall/user_access.rs index 899d8a134..9f83a30db 100644 --- a/kernel/src/syscall/user_access.rs +++ b/kernel/src/syscall/user_access.rs @@ -223,6 +223,17 @@ impl<'a> UserBufferReader<'a> { return Ok(()); } + /// 把用户空间的数据转换成指定类型的切片 + /// + /// ## 参数 + /// + /// - `offset`:字节偏移量 + pub fn buffer(&self, offset: usize) -> Result<&[T], SystemError> { + Ok(self + .convert_with_offset::(self.buffer, offset) + .map_err(|_| SystemError::EINVAL)?) + } + fn convert_with_offset(&self, src: &[u8], offset: usize) -> Result<&[T], SystemError> { if offset >= src.len() { return Err(SystemError::EINVAL); diff --git a/kernel/src/time/syscall.rs b/kernel/src/time/syscall.rs index 8df5edd2f..064dbc30d 100644 --- a/kernel/src/time/syscall.rs +++ b/kernel/src/time/syscall.rs @@ -3,6 +3,8 @@ use core::{ ptr::null_mut, }; +use num_traits::FromPrimitive; + use crate::{ syscall::{user_access::UserBufferWriter, Syscall, SystemError}, time::{sleep::nanosleep, TimeSpec}, @@ -36,6 +38,29 @@ pub const SYS_TIMEZONE: PosixTimeZone = PosixTimeZone { tz_dsttime: 0, }; +/// The IDs of the various system clocks (for POSIX.1b interval timers): +#[derive(Debug, Copy, Clone, PartialEq, Eq, FromPrimitive)] +pub enum PosixClockID { + Realtime = 0, + Monotonic = 1, + ProcessCPUTimeID = 2, + ThreadCPUTimeID = 3, + MonotonicRaw = 4, + RealtimeCoarse = 5, + MonotonicCoarse = 6, + Boottime = 7, + RealtimeAlarm = 8, + BoottimeAlarm = 9, +} + +impl TryFrom for PosixClockID { + type Error = SystemError; + + fn try_from(value: i32) -> Result { + ::from_i32(value).ok_or(SystemError::EINVAL) + } +} + impl Syscall { /// @brief 休眠指定时间(单位:纳秒)(提供给C的接口) /// @@ -107,4 +132,22 @@ impl Syscall { return Ok(0); } + + pub fn clock_gettime(clock_id: c_int, tp: *mut TimeSpec) -> Result { + let clock_id = PosixClockID::try_from(clock_id)?; + if clock_id != PosixClockID::Realtime { + kwarn!("clock_gettime: currently only support Realtime clock, but got {:?}. Defaultly return realtime!!!\n", clock_id); + } + if tp.is_null() { + return Err(SystemError::EFAULT); + } + let mut tp_buf = + UserBufferWriter::new::(tp, core::mem::size_of::(), true)?; + + let posix_time = do_gettimeofday(); + + tp_buf.copy_one_to_user(&posix_time, 0)?; + + return Ok(0); + } }