diff --git a/kernel/src/syscall.rs b/kernel/src/syscall.rs deleted file mode 100644 index 17aaa45..0000000 --- a/kernel/src/syscall.rs +++ /dev/null @@ -1,458 +0,0 @@ -//! System call - -use simple_filesystem::{INode, FileInfo, FileType, FsError}; -use core::{slice, str}; -use alloc::{sync::Arc, vec::Vec, string::String}; -use spin::{Mutex, MutexGuard}; -use log::*; -use bitflags::bitflags; -use crate::arch::interrupt::TrapFrame; -use crate::process::*; -use crate::thread; -use crate::util; -use crate::fs::File; - -/// System call dispatcher -pub fn syscall(id: usize, args: [usize; 6], tf: &mut TrapFrame) -> isize { - let ret = match id { - // file - 000 => sys_read(args[0], args[1] as *mut u8, args[2]), - 001 => sys_write(args[0], args[1] as *const u8, args[2]), - 002 => sys_open(args[0] as *const u8, args[1]), - 003 => sys_close(args[0]), -// 004 => sys_stat(), - 005 => sys_fstat(args[0], args[1] as *mut Stat), -// 007 => sys_poll(), -// 008 => sys_lseek(), -// 009 => sys_mmap(), -// 011 => sys_munmap(), -// 013 => sys_sigaction(), -// 019 => sys_readv(), -// 020 => sys_writev(), -// 021 => sys_access(), - 024 => sys_yield(), - 033 => sys_dup2(args[0], args[1]), -// 034 => sys_pause(), - 035 => sys_sleep(args[0]), // TODO: nanosleep - 039 => sys_getpid(), -// 040 => sys_getppid(), -// 041 => sys_socket(), -// 042 => sys_connect(), -// 043 => sys_accept(), -// 044 => sys_sendto(), -// 045 => sys_recvfrom(), -// 046 => sys_sendmsg(), -// 047 => sys_recvmsg(), -// 048 => sys_shutdown(), -// 049 => sys_bind(), -// 050 => sys_listen(), -// 054 => sys_setsockopt(), -// 055 => sys_getsockopt(), -// 056 => sys_clone(), - 057 => sys_fork(tf), - 059 => sys_exec(args[0] as *const u8, args[1] as usize, args[2] as *const *const u8, tf), - 060 => sys_exit(args[0] as isize), - 061 => sys_wait(args[0], args[1] as *mut i32), // TODO: wait4 - 062 => sys_kill(args[0]), -// 072 => sys_fcntl(), -// 074 => sys_fsync(), -// 076 => sys_trunc(), -// 077 => sys_ftrunc(), - 078 => sys_getdirentry(args[0], args[1] as *mut DirEntry), -// 079 => sys_getcwd(), -// 080 => sys_chdir(), -// 082 => sys_rename(), -// 083 => sys_mkdir(), -// 086 => sys_link(), -// 087 => sys_unlink(), - 096 => sys_get_time(), // TODO: sys_gettimeofday -// 097 => sys_getrlimit(), -// 098 => sys_getrusage(), -// 133 => sys_mknod(), - 141 => sys_set_priority(args[0]), -// 160 => sys_setrlimit(), -// 162 => sys_sync(), -// 169 => sys_reboot(), -// 293 => sys_pipe(), - - // for musl: empty impl - 158 => { - warn!("sys_arch_prctl is unimplemented"); - Ok(0) - } - 218 => { - warn!("sys_set_tid_address is unimplemented"); - Ok(0) - } - _ => { - error!("unknown syscall id: {:#x?}, args: {:x?}", id, args); - crate::trap::error(tf); - } - }; - match ret { - Ok(code) => code, - Err(err) => -(err as isize), - } -} - -fn sys_read(fd: usize, base: *mut u8, len: usize) -> SysResult { - // TODO: check ptr - info!("read: fd: {}, base: {:?}, len: {:#x}", fd, base, len); - let slice = unsafe { slice::from_raw_parts_mut(base, len) }; - let mut proc = process(); - let len = get_file(&mut proc, fd)?.read(slice)?; - Ok(len as isize) -} - -fn sys_write(fd: usize, base: *const u8, len: usize) -> SysResult { - // TODO: check ptr - info!("write: fd: {}, base: {:?}, len: {:#x}", fd, base, len); - let slice = unsafe { slice::from_raw_parts(base, len) }; - let mut proc = process(); - let len = get_file(&mut proc, fd)?.write(slice)?; - Ok(len as isize) -} - -fn sys_open(path: *const u8, flags: usize) -> SysResult { - // TODO: check ptr - let path = unsafe { util::from_cstr(path) }; - let flags = VfsFlags::from_ucore_flags(flags); - info!("open: path: {:?}, flags: {:?}", path, flags); - let (fd, inode) = match path { - "stdin:" => (0, crate::fs::STDIN.clone() as Arc), - "stdout:" => (1, crate::fs::STDOUT.clone() as Arc), - _ => { - let fd = (3..).find(|i| !process().files.contains_key(i)).unwrap(); - let inode = crate::fs::ROOT_INODE.lookup(path)?; - (fd, inode) - } - }; - let file = File::new(inode, flags.contains(VfsFlags::READABLE), flags.contains(VfsFlags::WRITABLE)); - process().files.insert(fd, file); - Ok(fd as isize) -} - -fn sys_close(fd: usize) -> SysResult { - info!("close: fd: {:?}", fd); - match process().files.remove(&fd) { - Some(_) => Ok(0), - None => Err(SysError::Inval), - } -} - -fn sys_fstat(fd: usize, stat_ptr: *mut Stat) -> SysResult { - // TODO: check ptr - info!("fstat: {}", fd); - let mut proc = process(); - let file = get_file(&mut proc, fd)?; - let stat = Stat::from(file.info()?); - unsafe { stat_ptr.write(stat); } - Ok(0) -} - -/// entry_id = dentry.offset / 256 -/// dentry.name = entry_name -/// dentry.offset += 256 -fn sys_getdirentry(fd: usize, dentry_ptr: *mut DirEntry) -> SysResult { - // TODO: check ptr - info!("getdirentry: {}", fd); - let mut proc = process(); - let file = get_file(&mut proc, fd)?; - let dentry = unsafe { &mut *dentry_ptr }; - if !dentry.check() { - return Err(SysError::Inval); - } - let info = file.info()?; - if info.type_ != FileType::Dir || info.size <= dentry.entry_id() { - return Err(SysError::Inval); - } - let name = file.get_entry(dentry.entry_id())?; - dentry.set_name(name.as_str()); - Ok(0) -} - -fn sys_dup2(fd1: usize, fd2: usize) -> SysResult { - info!("dup2: {} {}", fd1, fd2); - let mut proc = process(); - let file = get_file(&mut proc, fd1)?; - if process().files.contains_key(&fd2) { - return Err(SysError::Inval); - } - process().files.insert(fd2, file.clone()); - Ok(0) -} - -/// Fork the current process. Return the child's PID. -fn sys_fork(tf: &TrapFrame) -> SysResult { - let context = current_thread().fork(tf); - let pid = processor().manager().add(context, thread::current().id()); - info!("fork: {} -> {}", thread::current().id(), pid); - Ok(pid as isize) -} - -/// Wait the process exit. -/// Return the PID. Store exit code to `code` if it's not null. -fn sys_wait(pid: usize, code: *mut i32) -> SysResult { - // TODO: check ptr - loop { - use alloc::vec; - let wait_procs = match pid { - 0 => processor().manager().get_children(thread::current().id()), - _ => vec![pid], - }; - if wait_procs.is_empty() { - return Ok(-1); - } - for pid in wait_procs { - match processor().manager().get_status(pid) { - Some(Status::Exited(exit_code)) => { - if !code.is_null() { - unsafe { code.write(exit_code as i32); } - } - processor().manager().remove(pid); - info!("wait: {} -> {}", thread::current().id(), pid); - return Ok(0); - } - None => return Ok(-1), - _ => {} - } - } - info!("wait: {} -> {}, sleep", thread::current().id(), pid); - if pid == 0 { - processor().manager().wait_child(thread::current().id()); - processor().yield_now(); - } else { - processor().manager().wait(thread::current().id(), pid); - processor().yield_now(); - } - } -} - -fn sys_exec(name: *const u8, argc: usize, argv: *const *const u8, tf: &mut TrapFrame) -> SysResult { - // TODO: check ptr - let name = if name.is_null() { "" } else { unsafe { util::from_cstr(name) } }; - info!("exec: {:?}, argc: {}, argv: {:?}", name, argc, argv); - // Copy args to kernel - let args: Vec = unsafe { - slice::from_raw_parts(argv, argc).iter() - .map(|&arg| String::from(util::from_cstr(arg))) - .collect() - }; - - if args.len() <= 0 { - return Err(SysError::Inval); - } - // Read program file - let path = args[0].as_str(); - let inode = crate::fs::ROOT_INODE.lookup(path)?; - let size = inode.info()?.size; - let mut buf = Vec::with_capacity(size); - unsafe { buf.set_len(size); } - inode.read_at(0, buf.as_mut_slice())?; - - // Make new Thread - let iter = args.iter().map(|s| s.as_str()); - let mut thread = Thread::new_user(buf.as_slice(), iter); - - // Activate new page table - unsafe { thread.proc.lock().memory_set.activate(); } - - // Modify the TrapFrame - *tf = unsafe { thread.context.get_init_tf() }; - - // Swap Context but keep KStack - ::core::mem::swap(&mut current_thread().kstack, &mut thread.kstack); - ::core::mem::swap(current_thread(), &mut *thread); - - Ok(0) -} - -fn sys_yield() -> SysResult { - thread::yield_now(); - Ok(0) -} - -/// Kill the process -fn sys_kill(pid: usize) -> SysResult { - info!("{} killed: {}", thread::current().id(), pid); - processor().manager().exit(pid, 0x100); - if pid == thread::current().id() { - processor().yield_now(); - } - Ok(0) -} - -/// Get the current process id -fn sys_getpid() -> SysResult { - Ok(thread::current().id() as isize) -} - -/// Exit the current process -fn sys_exit(exit_code: isize) -> SysResult { - let pid = thread::current().id(); - info!("exit: {}, code: {}", pid, exit_code); - processor().manager().exit(pid, exit_code as usize); - processor().yield_now(); - unreachable!(); -} - -fn sys_sleep(time: usize) -> SysResult { - if time >= 1 << 31 { - thread::park(); - } else { - use core::time::Duration; - thread::sleep(Duration::from_millis(time as u64 * 10)); - } - Ok(0) -} - -fn sys_get_time() -> SysResult { - unsafe { Ok(crate::trap::TICK as isize) } -} - -fn sys_set_priority(priority: usize) -> SysResult { - let pid = thread::current().id(); - processor().manager().set_priority(pid, priority as u8); - Ok(0) -} - -fn sys_putc(c: char) -> SysResult { - print!("{}", c); - Ok(0) -} - -fn get_file<'a>(proc: &'a mut MutexGuard<'static, Process>, fd: usize) -> Result<&'a mut File, SysError> { - proc.files.get_mut(&fd).ok_or(SysError::Inval) -} - -pub type SysResult = Result; - -#[repr(isize)] -#[derive(Debug)] -pub enum SysError { - // ucore compatible error code - // note that ucore_plus use another error code table, which is a modified version of the ones used in linux - // name conversion E_XXXXX -> SysError::Xxxxx - // see https://github.com/oscourse-tsinghua/ucore_os_lab/blob/master/labcodes/lab8/libs/error.h - // we only add current used errors here - Inval = 3,// Invalid argument, also Invaild fd number. - Nomem = 4,// Out of memory, also used as no device space in ucore - Noent = 16,// No such file or directory - Isdir = 17,// Fd is a directory - Notdir = 18,// Fd is not a directory - Xdev = 19,// Cross-device link - Unimp = 20,// Not implemented - Exists = 23,// File exists - Notempty = 24,// Directory is not empty - - #[allow(dead_code)] - Unspcified = 1,// A really really unknown error. -} - -impl From for SysError { - fn from(error: FsError) -> Self { - match error { - FsError::NotSupported => SysError::Unimp, - FsError::NotFile => SysError::Isdir, - FsError::IsDir => SysError::Isdir, - FsError::NotDir => SysError::Notdir, - FsError::EntryNotFound => SysError::Noent, - FsError::EntryExist => SysError::Exists, - FsError::NotSameFs => SysError::Xdev, - FsError::InvalidParam => SysError::Inval, - FsError::NoDeviceSpace => SysError::Nomem, - FsError::DirRemoved => SysError::Noent, - FsError::DirNotEmpty => SysError::Notempty, - FsError::WrongFs => SysError::Inval, - } - } -} - -bitflags! { - struct VfsFlags: usize { - // WARNING: different from origin uCore - const READABLE = 1 << 0; - const WRITABLE = 1 << 1; - /// create file if it does not exist - const CREATE = 1 << 2; - /// error if O_CREAT and the file exists - const EXCLUSIVE = 1 << 3; - /// truncate file upon open - const TRUNCATE = 1 << 4; - /// append on each write - const APPEND = 1 << 5; - } -} - -impl VfsFlags { - fn from_ucore_flags(f: usize) -> Self { - assert_ne!(f & 0b11, 0b11); - Self::from_bits_truncate(f + 1) - } -} - -#[repr(C)] -struct DirEntry { - offset: u32, - name: [u8; 256], -} - -impl DirEntry { - fn check(&self) -> bool { - self.offset % 256 == 0 - } - fn entry_id(&self) -> usize { - (self.offset / 256) as usize - } - fn set_name(&mut self, name: &str) { - self.name[..name.len()].copy_from_slice(name.as_bytes()); - self.name[name.len()] = 0; - self.offset += 256; - } -} - -#[repr(C)] -struct Stat { - /// protection mode and file type - mode: StatMode, - /// number of hard links - nlinks: u32, - /// number of blocks file is using - blocks: u32, - /// file size (bytes) - size: u32, -} - -bitflags! { - struct StatMode: u32 { - const NULL = 0; - /// ordinary regular file - const FILE = 0o10000; - /// directory - const DIR = 0o20000; - /// symbolic link - const LINK = 0o30000; - /// character device - const CHAR = 0o40000; - /// block device - const BLOCK = 0o50000; - } -} - -impl From for Stat { - fn from(info: FileInfo) -> Self { - Stat { - mode: match info.type_ { - FileType::File => StatMode::FILE, - FileType::Dir => StatMode::DIR, - // _ => StatMode::NULL, - //Note: we should mark FileType as #[non_exhaustive] - // but it is currently not implemented for enum - // see rust-lang/rust#44109 - }, - nlinks: info.nlinks as u32, - blocks: info.blocks as u32, - size: info.size as u32, - } - } -} diff --git a/kernel/src/syscall/fs.rs b/kernel/src/syscall/fs.rs new file mode 100644 index 0000000..bf9450a --- /dev/null +++ b/kernel/src/syscall/fs.rs @@ -0,0 +1,183 @@ +//! Syscalls for file system + +use super::*; + +pub fn sys_read(fd: usize, base: *mut u8, len: usize) -> SysResult { + // TODO: check ptr + info!("read: fd: {}, base: {:?}, len: {:#x}", fd, base, len); + let slice = unsafe { slice::from_raw_parts_mut(base, len) }; + let mut proc = process(); + let len = get_file(&mut proc, fd)?.read(slice)?; + Ok(len as isize) +} + +pub fn sys_write(fd: usize, base: *const u8, len: usize) -> SysResult { + // TODO: check ptr + info!("write: fd: {}, base: {:?}, len: {:#x}", fd, base, len); + let slice = unsafe { slice::from_raw_parts(base, len) }; + let mut proc = process(); + let len = get_file(&mut proc, fd)?.write(slice)?; + Ok(len as isize) +} + +pub fn sys_open(path: *const u8, flags: usize) -> SysResult { + // TODO: check ptr + let path = unsafe { util::from_cstr(path) }; + let flags = VfsFlags::from_ucore_flags(flags); + info!("open: path: {:?}, flags: {:?}", path, flags); + let (fd, inode) = match path { + "stdin:" => (0, crate::fs::STDIN.clone() as Arc), + "stdout:" => (1, crate::fs::STDOUT.clone() as Arc), + _ => { + let fd = (3..).find(|i| !process().files.contains_key(i)).unwrap(); + let inode = crate::fs::ROOT_INODE.lookup(path)?; + (fd, inode) + } + }; + let file = File::new(inode, flags.contains(VfsFlags::READABLE), flags.contains(VfsFlags::WRITABLE)); + process().files.insert(fd, file); + Ok(fd as isize) +} + +pub fn sys_close(fd: usize) -> SysResult { + info!("close: fd: {:?}", fd); + match process().files.remove(&fd) { + Some(_) => Ok(0), + None => Err(SysError::Inval), + } +} + +pub fn sys_fstat(fd: usize, stat_ptr: *mut Stat) -> SysResult { + // TODO: check ptr + info!("fstat: {}", fd); + let mut proc = process(); + let file = get_file(&mut proc, fd)?; + let stat = Stat::from(file.info()?); + unsafe { stat_ptr.write(stat); } + Ok(0) +} + +/// entry_id = dentry.offset / 256 +/// dentry.name = entry_name +/// dentry.offset += 256 +pub fn sys_getdirentry(fd: usize, dentry_ptr: *mut DirEntry) -> SysResult { + // TODO: check ptr + info!("getdirentry: {}", fd); + let mut proc = process(); + let file = get_file(&mut proc, fd)?; + let dentry = unsafe { &mut *dentry_ptr }; + if !dentry.check() { + return Err(SysError::Inval); + } + let info = file.info()?; + if info.type_ != FileType::Dir || info.size <= dentry.entry_id() { + return Err(SysError::Inval); + } + let name = file.get_entry(dentry.entry_id())?; + dentry.set_name(name.as_str()); + Ok(0) +} + +pub fn sys_dup2(fd1: usize, fd2: usize) -> SysResult { + info!("dup2: {} {}", fd1, fd2); + let mut proc = process(); + if proc.files.contains_key(&fd2) { + return Err(SysError::Inval); + } + let file = get_file(&mut proc, fd1)?.clone(); + proc.files.insert(fd2, file); + Ok(0) +} + +fn get_file<'a>(proc: &'a mut MutexGuard<'static, Process>, fd: usize) -> Result<&'a mut File, SysError> { + proc.files.get_mut(&fd).ok_or(SysError::Inval) +} + +bitflags! { + struct VfsFlags: usize { + // WARNING: different from origin uCore + const READABLE = 1 << 0; + const WRITABLE = 1 << 1; + /// create file if it does not exist + const CREATE = 1 << 2; + /// error if O_CREAT and the file exists + const EXCLUSIVE = 1 << 3; + /// truncate file upon open + const TRUNCATE = 1 << 4; + /// append on each write + const APPEND = 1 << 5; + } +} + +impl VfsFlags { + fn from_ucore_flags(f: usize) -> Self { + assert_ne!(f & 0b11, 0b11); + Self::from_bits_truncate(f + 1) + } +} + +#[repr(C)] +pub struct DirEntry { + offset: u32, + name: [u8; 256], +} + +impl DirEntry { + fn check(&self) -> bool { + self.offset % 256 == 0 + } + fn entry_id(&self) -> usize { + (self.offset / 256) as usize + } + fn set_name(&mut self, name: &str) { + self.name[..name.len()].copy_from_slice(name.as_bytes()); + self.name[name.len()] = 0; + self.offset += 256; + } +} + +#[repr(C)] +pub struct Stat { + /// protection mode and file type + mode: StatMode, + /// number of hard links + nlinks: u32, + /// number of blocks file is using + blocks: u32, + /// file size (bytes) + size: u32, +} + +bitflags! { + pub struct StatMode: u32 { + const NULL = 0; + /// ordinary regular file + const FILE = 0o10000; + /// directory + const DIR = 0o20000; + /// symbolic link + const LINK = 0o30000; + /// character device + const CHAR = 0o40000; + /// block device + const BLOCK = 0o50000; + } +} + +impl From for Stat { + fn from(info: FileInfo) -> Self { + Stat { + mode: match info.type_ { + FileType::File => StatMode::FILE, + FileType::Dir => StatMode::DIR, + // _ => StatMode::NULL, + //Note: we should mark FileType as #[non_exhaustive] + // but it is currently not implemented for enum + // see rust-lang/rust#44109 + }, + nlinks: info.nlinks as u32, + blocks: info.blocks as u32, + size: info.size as u32, + } + } +} diff --git a/kernel/src/syscall/mod.rs b/kernel/src/syscall/mod.rs new file mode 100644 index 0000000..7f1e2ab --- /dev/null +++ b/kernel/src/syscall/mod.rs @@ -0,0 +1,149 @@ +//! System call + +use alloc::{string::String, sync::Arc, vec::Vec}; +use core::{slice, str}; + +use bitflags::bitflags; +use log::*; +use simple_filesystem::{FileInfo, FileType, FsError, INode}; +use spin::{Mutex, MutexGuard}; + +use crate::arch::interrupt::TrapFrame; +use crate::fs::File; +use crate::process::*; +use crate::thread; +use crate::util; + +use self::fs::*; +use self::proc::*; +use self::time::*; + +mod fs; +mod proc; +mod time; + +/// System call dispatcher +pub fn syscall(id: usize, args: [usize; 6], tf: &mut TrapFrame) -> isize { + let ret = match id { + // file + 000 => sys_read(args[0], args[1] as *mut u8, args[2]), + 001 => sys_write(args[0], args[1] as *const u8, args[2]), + 002 => sys_open(args[0] as *const u8, args[1]), + 003 => sys_close(args[0]), +// 004 => sys_stat(), + 005 => sys_fstat(args[0], args[1] as *mut Stat), +// 007 => sys_poll(), +// 008 => sys_lseek(), +// 009 => sys_mmap(), +// 011 => sys_munmap(), +// 013 => sys_sigaction(), +// 019 => sys_readv(), +// 020 => sys_writev(), +// 021 => sys_access(), + 024 => sys_yield(), + 033 => sys_dup2(args[0], args[1]), +// 034 => sys_pause(), + 035 => sys_sleep(args[0]), // TODO: nanosleep + 039 => sys_getpid(), +// 040 => sys_getppid(), +// 041 => sys_socket(), +// 042 => sys_connect(), +// 043 => sys_accept(), +// 044 => sys_sendto(), +// 045 => sys_recvfrom(), +// 046 => sys_sendmsg(), +// 047 => sys_recvmsg(), +// 048 => sys_shutdown(), +// 049 => sys_bind(), +// 050 => sys_listen(), +// 054 => sys_setsockopt(), +// 055 => sys_getsockopt(), +// 056 => sys_clone(), + 057 => sys_fork(tf), + 059 => sys_exec(args[0] as *const u8, args[1] as usize, args[2] as *const *const u8, tf), + 060 => sys_exit(args[0] as isize), + 061 => sys_wait(args[0], args[1] as *mut i32), // TODO: wait4 + 062 => sys_kill(args[0]), +// 072 => sys_fcntl(), +// 074 => sys_fsync(), +// 076 => sys_trunc(), +// 077 => sys_ftrunc(), + 078 => sys_getdirentry(args[0], args[1] as *mut DirEntry), +// 079 => sys_getcwd(), +// 080 => sys_chdir(), +// 082 => sys_rename(), +// 083 => sys_mkdir(), +// 086 => sys_link(), +// 087 => sys_unlink(), + 096 => sys_get_time(), // TODO: sys_gettimeofday +// 097 => sys_getrlimit(), +// 098 => sys_getrusage(), +// 133 => sys_mknod(), + 141 => sys_set_priority(args[0]), +// 160 => sys_setrlimit(), +// 162 => sys_sync(), +// 169 => sys_reboot(), +// 293 => sys_pipe(), + + // for musl: empty impl + 158 => { + warn!("sys_arch_prctl is unimplemented"); + Ok(0) + } + 218 => { + warn!("sys_set_tid_address is unimplemented"); + Ok(0) + } + _ => { + error!("unknown syscall id: {:#x?}, args: {:x?}", id, args); + crate::trap::error(tf); + } + }; + match ret { + Ok(code) => code, + Err(err) => -(err as isize), + } +} + +pub type SysResult = Result; + +#[repr(isize)] +#[derive(Debug)] +pub enum SysError { + // ucore compatible error code + // note that ucore_plus use another error code table, which is a modified version of the ones used in linux + // name conversion E_XXXXX -> SysError::Xxxxx + // see https://github.com/oscourse-tsinghua/ucore_os_lab/blob/master/labcodes/lab8/libs/error.h + // we only add current used errors here + Inval = 3,// Invalid argument, also Invaild fd number. + Nomem = 4,// Out of memory, also used as no device space in ucore + Noent = 16,// No such file or directory + Isdir = 17,// Fd is a directory + Notdir = 18,// Fd is not a directory + Xdev = 19,// Cross-device link + Unimp = 20,// Not implemented + Exists = 23,// File exists + Notempty = 24,// Directory is not empty + + #[allow(dead_code)] + Unspcified = 1,// A really really unknown error. +} + +impl From for SysError { + fn from(error: FsError) -> Self { + match error { + FsError::NotSupported => SysError::Unimp, + FsError::NotFile => SysError::Isdir, + FsError::IsDir => SysError::Isdir, + FsError::NotDir => SysError::Notdir, + FsError::EntryNotFound => SysError::Noent, + FsError::EntryExist => SysError::Exists, + FsError::NotSameFs => SysError::Xdev, + FsError::InvalidParam => SysError::Inval, + FsError::NoDeviceSpace => SysError::Nomem, + FsError::DirRemoved => SysError::Noent, + FsError::DirNotEmpty => SysError::Notempty, + FsError::WrongFs => SysError::Inval, + } + } +} diff --git a/kernel/src/syscall/proc.rs b/kernel/src/syscall/proc.rs new file mode 100644 index 0000000..7810577 --- /dev/null +++ b/kernel/src/syscall/proc.rs @@ -0,0 +1,133 @@ +//! Syscalls for process + +use super::*; + +/// Fork the current process. Return the child's PID. +pub fn sys_fork(tf: &TrapFrame) -> SysResult { + let context = current_thread().fork(tf); + let pid = processor().manager().add(context, thread::current().id()); + info!("fork: {} -> {}", thread::current().id(), pid); + Ok(pid as isize) +} + +/// Wait the process exit. +/// Return the PID. Store exit code to `code` if it's not null. +pub fn sys_wait(pid: usize, code: *mut i32) -> SysResult { + // TODO: check ptr + loop { + use alloc::vec; + let wait_procs = match pid { + 0 => processor().manager().get_children(thread::current().id()), + _ => vec![pid], + }; + if wait_procs.is_empty() { + return Ok(-1); + } + for pid in wait_procs { + match processor().manager().get_status(pid) { + Some(Status::Exited(exit_code)) => { + if !code.is_null() { + unsafe { code.write(exit_code as i32); } + } + processor().manager().remove(pid); + info!("wait: {} -> {}", thread::current().id(), pid); + return Ok(0); + } + None => return Ok(-1), + _ => {} + } + } + info!("wait: {} -> {}, sleep", thread::current().id(), pid); + if pid == 0 { + processor().manager().wait_child(thread::current().id()); + processor().yield_now(); + } else { + processor().manager().wait(thread::current().id(), pid); + processor().yield_now(); + } + } +} + +pub fn sys_exec(name: *const u8, argc: usize, argv: *const *const u8, tf: &mut TrapFrame) -> SysResult { + // TODO: check ptr + let name = if name.is_null() { "" } else { unsafe { util::from_cstr(name) } }; + info!("exec: {:?}, argc: {}, argv: {:?}", name, argc, argv); + // Copy args to kernel + let args: Vec = unsafe { + slice::from_raw_parts(argv, argc).iter() + .map(|&arg| String::from(util::from_cstr(arg))) + .collect() + }; + + if args.len() <= 0 { + return Err(SysError::Inval); + } + // Read program file + let path = args[0].as_str(); + let inode = crate::fs::ROOT_INODE.lookup(path)?; + let size = inode.info()?.size; + let mut buf = Vec::with_capacity(size); + unsafe { buf.set_len(size); } + inode.read_at(0, buf.as_mut_slice())?; + + // Make new Thread + let iter = args.iter().map(|s| s.as_str()); + let mut thread = Thread::new_user(buf.as_slice(), iter); + + // Activate new page table + unsafe { thread.proc.lock().memory_set.activate(); } + + // Modify the TrapFrame + *tf = unsafe { thread.context.get_init_tf() }; + + // Swap Context but keep KStack + ::core::mem::swap(&mut current_thread().kstack, &mut thread.kstack); + ::core::mem::swap(current_thread(), &mut *thread); + + Ok(0) +} + +pub fn sys_yield() -> SysResult { + thread::yield_now(); + Ok(0) +} + +/// Kill the process +pub fn sys_kill(pid: usize) -> SysResult { + info!("{} killed: {}", thread::current().id(), pid); + processor().manager().exit(pid, 0x100); + if pid == thread::current().id() { + processor().yield_now(); + } + Ok(0) +} + +/// Get the current process id +pub fn sys_getpid() -> SysResult { + Ok(thread::current().id() as isize) +} + +/// Exit the current process +pub fn sys_exit(exit_code: isize) -> SysResult { + let pid = thread::current().id(); + info!("exit: {}, code: {}", pid, exit_code); + processor().manager().exit(pid, exit_code as usize); + processor().yield_now(); + unreachable!(); +} + +pub fn sys_sleep(time: usize) -> SysResult { + if time >= 1 << 31 { + thread::park(); + } else { + use core::time::Duration; + thread::sleep(Duration::from_millis(time as u64 * 10)); + } + Ok(0) +} + +pub fn sys_set_priority(priority: usize) -> SysResult { + let pid = thread::current().id(); + processor().manager().set_priority(pid, priority as u8); + Ok(0) +} diff --git a/kernel/src/syscall/time.rs b/kernel/src/syscall/time.rs new file mode 100644 index 0000000..53cb490 --- /dev/null +++ b/kernel/src/syscall/time.rs @@ -0,0 +1,7 @@ +//! Syscalls for time + +use super::*; + +pub fn sys_get_time() -> SysResult { + unsafe { Ok(crate::trap::TICK as isize) } +} \ No newline at end of file