From da58486be5b5c772dc9fe64befa56c04d5022973 Mon Sep 17 00:00:00 2001 From: WangRunji Date: Sat, 4 May 2019 13:16:42 +0800 Subject: [PATCH] refactor syscall: move all context and functions to struct Syscall --- kernel/src/memory.rs | 10 +- kernel/src/process/mod.rs | 22 +- kernel/src/syscall/custom.rs | 84 +-- kernel/src/syscall/fs.rs | 1258 +++++++++++++++++----------------- kernel/src/syscall/mem.rs | 160 ++--- kernel/src/syscall/misc.rs | 312 ++++----- kernel/src/syscall/mod.rs | 634 ++++++++--------- kernel/src/syscall/net.rs | 473 ++++++------- kernel/src/syscall/proc.rs | 591 ++++++++-------- kernel/src/syscall/time.rs | 156 ++--- 10 files changed, 1869 insertions(+), 1831 deletions(-) diff --git a/kernel/src/memory.rs b/kernel/src/memory.rs index b3b013a..5b69ab8 100644 --- a/kernel/src/memory.rs +++ b/kernel/src/memory.rs @@ -15,7 +15,6 @@ use super::HEAP_ALLOCATOR; pub use crate::arch::paging::*; use crate::consts::{KERNEL_OFFSET, MEMORY_OFFSET}; -use crate::process::process_unsafe; use crate::sync::SpinNoIrqLock; use alloc::boxed::Box; use bitmap_allocator::BitAlloc; @@ -25,6 +24,7 @@ use log::*; pub use rcore_memory::memory_set::{handler::*, MemoryArea, MemoryAttr}; use rcore_memory::paging::PageTable; use rcore_memory::*; +use crate::process::current_thread; pub type MemorySet = rcore_memory::memory_set::MemorySet; @@ -132,8 +132,12 @@ impl Drop for KernelStack { pub fn handle_page_fault(addr: usize) -> bool { debug!("page fault @ {:#x}", addr); - // This is safe as long as page fault never happens in page fault handler - unsafe { process_unsafe().vm.handle_page_fault(addr) } + // FIXME: fix racing caused by force_unlock + unsafe { + let thread = current_thread(); + thread.proc.force_unlock(); + thread.proc.lock().vm.handle_page_fault(addr) + } } pub fn init_heap() { diff --git a/kernel/src/process/mod.rs b/kernel/src/process/mod.rs index d9908a9..494f7b7 100644 --- a/kernel/src/process/mod.rs +++ b/kernel/src/process/mod.rs @@ -109,25 +109,13 @@ static PROCESSORS: [Processor; MAX_CPU_NUM] = [ // Processor::new(), Processor::new(), Processor::new(), Processor::new(), ]; -/// Get current process -pub fn process() -> MutexGuard<'static, Process, SpinNoIrq> { - current_thread().proc.lock() -} - -/// Get current process, ignoring its lock -/// Only use this when necessary -pub unsafe fn process_unsafe() -> MutexGuard<'static, Process, SpinNoIrq> { - let thread = current_thread(); - thread.proc.force_unlock(); - thread.proc.lock() -} - /// Get current thread /// -/// FIXME: It's obviously unsafe to get &mut ! -pub fn current_thread() -> &'static mut Thread { - use core::mem::transmute; - let (process, _): (&mut Thread, *const ()) = unsafe { transmute(processor().context()) }; +/// `Thread` is a thread-local object. +/// It is safe to call this once, and pass `&mut Thread` as a function argument. +pub unsafe fn current_thread() -> &'static mut Thread { + // trick: force downcast from trait object + let (process, _): (&mut Thread, *const ()) = core::mem::transmute(processor().context()); process } diff --git a/kernel/src/syscall/custom.rs b/kernel/src/syscall/custom.rs index d774b91..770ddd2 100644 --- a/kernel/src/syscall/custom.rs +++ b/kernel/src/syscall/custom.rs @@ -3,51 +3,53 @@ use super::*; use rcore_memory::memory_set::handler::Linear; use rcore_memory::memory_set::MemoryAttr; -/// Allocate this PCI device to user space -/// The kernel driver using the PCI device will be unloaded -#[cfg(target_arch = "x86_64")] -pub fn sys_map_pci_device(vendor: usize, product: usize) -> SysResult { - use crate::drivers::bus::pci; - info!( - "map_pci_device: vendor: {:x}, product: {:x}", - vendor, product - ); +impl Syscall<'_> { + /// Allocate this PCI device to user space + /// The kernel driver using the PCI device will be unloaded + #[cfg(target_arch = "x86_64")] + pub fn sys_map_pci_device(&mut self, vendor: usize, product: usize) -> SysResult { + use crate::drivers::bus::pci; + info!( + "map_pci_device: vendor: {:x}, product: {:x}", + vendor, product + ); - let tag = pci::find_device(vendor as u16, product as u16).ok_or(SysError::ENOENT)?; - if pci::detach_driver(&tag) { - info!("Kernel driver detached"); - } + let tag = pci::find_device(vendor as u16, product as u16).ok_or(SysError::ENOENT)?; + if pci::detach_driver(&tag) { + info!("Kernel driver detached"); + } - // Get BAR0 memory - let (base, len) = pci::get_bar0_mem(tag).ok_or(SysError::ENOENT)?; + // Get BAR0 memory + let (base, len) = pci::get_bar0_mem(tag).ok_or(SysError::ENOENT)?; - let mut proc = process(); - let virt_addr = proc.vm.find_free_area(0, len); - let attr = MemoryAttr::default().user(); - proc.vm.push( - virt_addr, - virt_addr + len, - attr, - Linear::new(base as isize - virt_addr as isize), - "pci", - ); - Ok(virt_addr) -} + let mut proc = self.process(); + let virt_addr = proc.vm.find_free_area(0, len); + let attr = MemoryAttr::default().user(); + proc.vm.push( + virt_addr, + virt_addr + len, + attr, + Linear::new(base as isize - virt_addr as isize), + "pci", + ); + Ok(virt_addr) + } -#[cfg(not(target_arch = "x86_64"))] -pub fn sys_map_pci_device(vendor: usize, product: usize) -> SysResult { - Err(SysError::ENOSYS) -} + #[cfg(not(target_arch = "x86_64"))] + pub fn sys_map_pci_device(&mut self, vendor: usize, product: usize) -> SysResult { + Err(SysError::ENOSYS) + } -/// Get start physical addresses of frames -/// mapped to a list of virtual addresses. -pub fn sys_get_paddr(vaddrs: *const u64, paddrs: *mut u64, count: usize) -> SysResult { - let mut proc = process(); - let vaddrs = unsafe { proc.vm.check_read_array(vaddrs, count)? }; - let paddrs = unsafe { proc.vm.check_write_array(paddrs, count)? }; - for i in 0..count { - let paddr = proc.vm.translate(vaddrs[i] as usize).unwrap_or(0); - paddrs[i] = paddr as u64; + /// Get start physical addresses of frames + /// mapped to a list of virtual addresses. + pub fn sys_get_paddr(&mut self, vaddrs: *const u64, paddrs: *mut u64, count: usize) -> SysResult { + let mut proc = self.process(); + let vaddrs = unsafe { proc.vm.check_read_array(vaddrs, count)? }; + let paddrs = unsafe { proc.vm.check_write_array(paddrs, count)? }; + for i in 0..count { + let paddr = proc.vm.translate(vaddrs[i] as usize).unwrap_or(0); + paddrs[i] = paddr as u64; + } + Ok(0) } - Ok(0) } diff --git a/kernel/src/syscall/fs.rs b/kernel/src/syscall/fs.rs index 9cbc74b..6a5a18e 100644 --- a/kernel/src/syscall/fs.rs +++ b/kernel/src/syscall/fs.rs @@ -15,733 +15,739 @@ use bitvec::prelude::{BitSlice, BitVec, LittleEndian}; use super::*; -pub fn sys_read(fd: usize, base: *mut u8, len: usize) -> SysResult { - let mut proc = process(); - if !proc.pid.is_init() { - // we trust pid 0 process - info!("read: fd: {}, base: {:?}, len: {:#x}", fd, base, len); - } - let slice = unsafe { proc.vm.check_write_array(base, len)? }; - let file_like = proc.get_file_like(fd)?; - let len = file_like.read(slice)?; - Ok(len) -} - -pub fn sys_write(fd: usize, base: *const u8, len: usize) -> SysResult { - let mut proc = process(); - if !proc.pid.is_init() { - // we trust pid 0 process - info!("write: fd: {}, base: {:?}, len: {:#x}", fd, base, len); +impl Syscall<'_> { + pub fn sys_read(&mut self, fd: usize, base: *mut u8, len: usize) -> SysResult { + let mut proc = self.process(); + if !proc.pid.is_init() { + // we trust pid 0 process + info!("read: fd: {}, base: {:?}, len: {:#x}", fd, base, len); + } + let slice = unsafe { proc.vm.check_write_array(base, len)? }; + let file_like = proc.get_file_like(fd)?; + let len = file_like.read(slice)?; + Ok(len) } - let slice = unsafe { proc.vm.check_read_array(base, len)? }; - let file_like = proc.get_file_like(fd)?; - let len = file_like.write(slice)?; - Ok(len) -} - -pub fn sys_pread(fd: usize, base: *mut u8, len: usize, offset: usize) -> SysResult { - info!( - "pread: fd: {}, base: {:?}, len: {}, offset: {}", - fd, base, len, offset - ); - let mut proc = process(); - let slice = unsafe { proc.vm.check_write_array(base, len)? }; - let len = proc.get_file(fd)?.read_at(offset, slice)?; - Ok(len) -} -pub fn sys_pwrite(fd: usize, base: *const u8, len: usize, offset: usize) -> SysResult { - info!( - "pwrite: fd: {}, base: {:?}, len: {}, offset: {}", - fd, base, len, offset - ); - let mut proc = process(); - let slice = unsafe { proc.vm.check_read_array(base, len)? }; - let len = proc.get_file(fd)?.write_at(offset, slice)?; - Ok(len) -} + pub fn sys_write(&mut self, fd: usize, base: *const u8, len: usize) -> SysResult { + let mut proc = self.process(); + if !proc.pid.is_init() { + // we trust pid 0 process + info!("write: fd: {}, base: {:?}, len: {:#x}", fd, base, len); + } + let slice = unsafe { proc.vm.check_read_array(base, len)? }; + let file_like = proc.get_file_like(fd)?; + let len = file_like.write(slice)?; + Ok(len) + } -pub fn sys_ppoll(ufds: *mut PollFd, nfds: usize, timeout: *const TimeSpec) -> SysResult { - let proc = process(); - let timeout_msecs = if timeout.is_null() { - 1 << 31 // infinity - } else { - let timeout = unsafe { proc.vm.check_read_ptr(timeout)? }; - timeout.to_msec() - }; - drop(proc); - - sys_poll(ufds, nfds, timeout_msecs as usize) -} + pub fn sys_pread(&mut self, fd: usize, base: *mut u8, len: usize, offset: usize) -> SysResult { + info!( + "pread: fd: {}, base: {:?}, len: {}, offset: {}", + fd, base, len, offset + ); + let mut proc = self.process(); + let slice = unsafe { proc.vm.check_write_array(base, len)? }; + let len = proc.get_file(fd)?.read_at(offset, slice)?; + Ok(len) + } -pub fn sys_poll(ufds: *mut PollFd, nfds: usize, timeout_msecs: usize) -> SysResult { - let proc = process(); - if !proc.pid.is_init() { - // we trust pid 0 process + pub fn sys_pwrite(&mut self, fd: usize, base: *const u8, len: usize, offset: usize) -> SysResult { info!( - "poll: ufds: {:?}, nfds: {}, timeout_msecs: {:#x}", - ufds, nfds, timeout_msecs + "pwrite: fd: {}, base: {:?}, len: {}, offset: {}", + fd, base, len, offset ); + let mut proc = self.process(); + let slice = unsafe { proc.vm.check_read_array(base, len)? }; + let len = proc.get_file(fd)?.write_at(offset, slice)?; + Ok(len) } - let polls = unsafe { proc.vm.check_write_array(ufds, nfds)? }; - for poll in polls.iter() { - if proc.files.get(&(poll.fd as usize)).is_none() { - return Err(SysError::EINVAL); + pub fn sys_ppoll(&mut self, ufds: *mut PollFd, nfds: usize, timeout: *const TimeSpec) -> SysResult { + let proc = self.process(); + let timeout_msecs = if timeout.is_null() { + 1 << 31 // infinity + } else { + let timeout = unsafe { proc.vm.check_read_ptr(timeout)? }; + timeout.to_msec() + }; + drop(proc); + + self.sys_poll(ufds, nfds, timeout_msecs as usize) + } + + pub fn sys_poll(&mut self, ufds: *mut PollFd, nfds: usize, timeout_msecs: usize) -> SysResult { + let proc = self.process(); + if !proc.pid.is_init() { + // we trust pid 0 process + info!( + "poll: ufds: {:?}, nfds: {}, timeout_msecs: {:#x}", + ufds, nfds, timeout_msecs + ); + } + + let polls = unsafe { proc.vm.check_write_array(ufds, nfds)? }; + for poll in polls.iter() { + if proc.files.get(&(poll.fd as usize)).is_none() { + return Err(SysError::EINVAL); + } + } + drop(proc); + + let begin_time_ms = crate::trap::uptime_msec(); + loop { + use PollEvents as PE; + let proc = self.process(); + let mut events = 0; + for poll in polls.iter_mut() { + poll.revents = PE::empty(); + if let Some(file_like) = proc.files.get(&(poll.fd as usize)) { + let status = file_like.poll()?; + if status.error { + poll.revents |= PE::HUP; + events += 1; + } + if status.read && poll.events.contains(PE::IN) { + poll.revents |= PE::IN; + events += 1; + } + if status.write && poll.events.contains(PE::OUT) { + poll.revents |= PE::OUT; + events += 1; + } + } else { + poll.revents |= PE::ERR; + events += 1; + } + } + drop(proc); + + if events > 0 { + return Ok(events); + } + + let current_time_ms = crate::trap::uptime_msec(); + if timeout_msecs < (1 << 31) && current_time_ms - begin_time_ms > timeout_msecs { + return Ok(0); + } + + Condvar::wait_any(&[&STDIN.pushed, &(*SOCKET_ACTIVITY)]); } } - drop(proc); - let begin_time_ms = crate::trap::uptime_msec(); - loop { - use PollEvents as PE; - let proc = process(); - let mut events = 0; - for poll in polls.iter_mut() { - poll.revents = PE::empty(); - if let Some(file_like) = proc.files.get(&(poll.fd as usize)) { + pub fn sys_select( + &mut self, + nfds: usize, + read: *mut u32, + write: *mut u32, + err: *mut u32, + timeout: *const TimeVal, + ) -> SysResult { + info!( + "select: nfds: {}, read: {:?}, write: {:?}, err: {:?}, timeout: {:?}", + nfds, read, write, err, timeout + ); + + let proc = self.process(); + let mut read_fds = FdSet::new(&proc.vm, read, nfds)?; + let mut write_fds = FdSet::new(&proc.vm, write, nfds)?; + let mut err_fds = FdSet::new(&proc.vm, err, nfds)?; + let timeout_msecs = if !timeout.is_null() { + let timeout = unsafe { proc.vm.check_read_ptr(timeout)? }; + timeout.to_msec() + } else { + // infinity + 1 << 31 + }; + + // for debugging + if cfg!(debug_assertions) { + debug!("files before select {:#?}", proc.files); + } + drop(proc); + + let begin_time_ms = crate::trap::uptime_msec(); + loop { + let proc = self.process(); + let mut events = 0; + for (&fd, file_like) in proc.files.iter() { + if fd >= nfds { + continue; + } + if !err_fds.contains(fd) && !read_fds.contains(fd) && !write_fds.contains(fd) { + continue; + } let status = file_like.poll()?; - if status.error { - poll.revents |= PE::HUP; + if status.error && err_fds.contains(fd) { + err_fds.set(fd); events += 1; } - if status.read && poll.events.contains(PE::IN) { - poll.revents |= PE::IN; + if status.read && read_fds.contains(fd) { + read_fds.set(fd); events += 1; } - if status.write && poll.events.contains(PE::OUT) { - poll.revents |= PE::OUT; + if status.write && write_fds.contains(fd) { + write_fds.set(fd); events += 1; } - } else { - poll.revents |= PE::ERR; - events += 1; } - } - drop(proc); - - if events > 0 { - return Ok(events); - } + drop(proc); - let current_time_ms = crate::trap::uptime_msec(); - if timeout_msecs < (1 << 31) && current_time_ms - begin_time_ms > timeout_msecs { - return Ok(0); - } - - Condvar::wait_any(&[&STDIN.pushed, &(*SOCKET_ACTIVITY)]); - } -} - -pub fn sys_select( - nfds: usize, - read: *mut u32, - write: *mut u32, - err: *mut u32, - timeout: *const TimeVal, -) -> SysResult { - info!( - "select: nfds: {}, read: {:?}, write: {:?}, err: {:?}, timeout: {:?}", - nfds, read, write, err, timeout - ); - - let proc = process(); - let mut read_fds = FdSet::new(&proc.vm, read, nfds)?; - let mut write_fds = FdSet::new(&proc.vm, write, nfds)?; - let mut err_fds = FdSet::new(&proc.vm, err, nfds)?; - let timeout_msecs = if !timeout.is_null() { - let timeout = unsafe { proc.vm.check_read_ptr(timeout)? }; - timeout.to_msec() - } else { - // infinity - 1 << 31 - }; - - // for debugging - if cfg!(debug_assertions) { - debug!("files before select {:#?}", proc.files); - } - drop(proc); - - let begin_time_ms = crate::trap::uptime_msec(); - loop { - let proc = process(); - let mut events = 0; - for (&fd, file_like) in proc.files.iter() { - if fd >= nfds { - continue; - } - if !err_fds.contains(fd) && !read_fds.contains(fd) && !write_fds.contains(fd) { - continue; - } - let status = file_like.poll()?; - if status.error && err_fds.contains(fd) { - err_fds.set(fd); - events += 1; - } - if status.read && read_fds.contains(fd) { - read_fds.set(fd); - events += 1; - } - if status.write && write_fds.contains(fd) { - write_fds.set(fd); - events += 1; + if events > 0 { + return Ok(events); } - } - drop(proc); - if events > 0 { - return Ok(events); - } + if timeout_msecs == 0 { + // no timeout, return now; + return Ok(0); + } - if timeout_msecs == 0 { - // no timeout, return now; - return Ok(0); - } + let current_time_ms = crate::trap::uptime_msec(); + // infinity check + if timeout_msecs < (1 << 31) && current_time_ms - begin_time_ms > timeout_msecs as usize { + return Ok(0); + } - let current_time_ms = crate::trap::uptime_msec(); - // infinity check - if timeout_msecs < (1 << 31) && current_time_ms - begin_time_ms > timeout_msecs as usize { - return Ok(0); + Condvar::wait_any(&[&STDIN.pushed, &(*SOCKET_ACTIVITY)]); } - - Condvar::wait_any(&[&STDIN.pushed, &(*SOCKET_ACTIVITY)]); } -} - -pub fn sys_readv(fd: usize, iov_ptr: *const IoVec, iov_count: usize) -> SysResult { - info!( - "readv: fd: {}, iov: {:?}, count: {}", - fd, iov_ptr, iov_count - ); - let mut proc = process(); - let mut iovs = unsafe { IoVecs::check_and_new(iov_ptr, iov_count, &proc.vm, true)? }; - - // read all data to a buf - let file_like = proc.get_file_like(fd)?; - let mut buf = iovs.new_buf(true); - let len = file_like.read(buf.as_mut_slice())?; - // copy data to user - iovs.write_all_from_slice(&buf[..len]); - Ok(len) -} -pub fn sys_writev(fd: usize, iov_ptr: *const IoVec, iov_count: usize) -> SysResult { - let mut proc = process(); - if !proc.pid.is_init() { - // we trust pid 0 process + pub fn sys_readv(&mut self, fd: usize, iov_ptr: *const IoVec, iov_count: usize) -> SysResult { info!( - "writev: fd: {}, iov: {:?}, count: {}", + "readv: fd: {}, iov: {:?}, count: {}", fd, iov_ptr, iov_count ); + let mut proc = self.process(); + let mut iovs = unsafe { IoVecs::check_and_new(iov_ptr, iov_count, &proc.vm, true)? }; + + // read all data to a buf + let file_like = proc.get_file_like(fd)?; + let mut buf = iovs.new_buf(true); + let len = file_like.read(buf.as_mut_slice())?; + // copy data to user + iovs.write_all_from_slice(&buf[..len]); + Ok(len) } - let iovs = unsafe { IoVecs::check_and_new(iov_ptr, iov_count, &proc.vm, false)? }; - let buf = iovs.read_all_to_vec(); - let len = buf.len(); + pub fn sys_writev(&mut self, fd: usize, iov_ptr: *const IoVec, iov_count: usize) -> SysResult { + let mut proc = self.process(); + if !proc.pid.is_init() { + // we trust pid 0 process + info!( + "writev: fd: {}, iov: {:?}, count: {}", + fd, iov_ptr, iov_count + ); + } + let iovs = unsafe { IoVecs::check_and_new(iov_ptr, iov_count, &proc.vm, false)? }; - let file_like = proc.get_file_like(fd)?; - let len = file_like.write(buf.as_slice())?; - Ok(len) -} + let buf = iovs.read_all_to_vec(); + let len = buf.len(); -pub fn sys_open(path: *const u8, flags: usize, mode: usize) -> SysResult { - sys_openat(AT_FDCWD, path, flags, mode) -} + let file_like = proc.get_file_like(fd)?; + let len = file_like.write(buf.as_slice())?; + Ok(len) + } -pub fn sys_openat(dir_fd: usize, path: *const u8, flags: usize, mode: usize) -> SysResult { - let mut proc = process(); - let path = unsafe { proc.vm.check_and_clone_cstr(path)? }; - let flags = OpenFlags::from_bits_truncate(flags); - info!( - "openat: dir_fd: {}, path: {:?}, flags: {:?}, mode: {:#o}", - dir_fd as isize, path, flags, mode - ); + pub fn sys_open(&mut self, path: *const u8, flags: usize, mode: usize) -> SysResult { + self.sys_openat(AT_FDCWD, path, flags, mode) + } - let inode = if flags.contains(OpenFlags::CREATE) { - let (dir_path, file_name) = split_path(&path); - // relative to cwd - let dir_inode = proc.lookup_inode_at(dir_fd, dir_path, true)?; - match dir_inode.find(file_name) { - Ok(file_inode) => { - if flags.contains(OpenFlags::EXCLUSIVE) { - return Err(SysError::EEXIST); + pub fn sys_openat(&mut self, dir_fd: usize, path: *const u8, flags: usize, mode: usize) -> SysResult { + let mut proc = self.process(); + let path = unsafe { proc.vm.check_and_clone_cstr(path)? }; + let flags = OpenFlags::from_bits_truncate(flags); + info!( + "openat: dir_fd: {}, path: {:?}, flags: {:?}, mode: {:#o}", + dir_fd as isize, path, flags, mode + ); + + let inode = if flags.contains(OpenFlags::CREATE) { + let (dir_path, file_name) = split_path(&path); + // relative to cwd + let dir_inode = proc.lookup_inode_at(dir_fd, dir_path, true)?; + match dir_inode.find(file_name) { + Ok(file_inode) => { + if flags.contains(OpenFlags::EXCLUSIVE) { + return Err(SysError::EEXIST); + } + file_inode } - file_inode - } - Err(FsError::EntryNotFound) => { - dir_inode.create(file_name, FileType::File, mode as u32)? + Err(FsError::EntryNotFound) => { + dir_inode.create(file_name, FileType::File, mode as u32)? + } + Err(e) => return Err(SysError::from(e)), } - Err(e) => return Err(SysError::from(e)), + } else { + proc.lookup_inode_at(dir_fd, &path, true)? + }; + + let mut file = FileHandle::new(inode, flags.to_options(), String::from(path)); + + // for debugging + if cfg!(debug_assertions) { + debug!("files before open {:#?}", proc.files); } - } else { - proc.lookup_inode_at(dir_fd, &path, true)? - }; - let mut file = FileHandle::new(inode, flags.to_options(), String::from(path)); + let fd = proc.add_file(FileLike::File(file)); + Ok(fd) + } + + pub fn sys_close(&mut self, fd: usize) -> SysResult { + info!("close: fd: {:?}", fd); + let mut proc = self.process(); - // for debugging - if cfg!(debug_assertions) { - debug!("files before open {:#?}", proc.files); + // for debugging + if cfg!(debug_assertions) { + debug!("files before close {:#?}", proc.files); + } + + proc.files.remove(&fd).ok_or(SysError::EBADF)?; + Ok(0) } - let fd = proc.add_file(FileLike::File(file)); - Ok(fd) -} + pub fn sys_access(&mut self, path: *const u8, mode: usize) -> SysResult { + self.sys_faccessat(AT_FDCWD, path, mode, 0) + } -pub fn sys_close(fd: usize) -> SysResult { - info!("close: fd: {:?}", fd); - let mut proc = process(); + pub fn sys_faccessat(&mut self, dirfd: usize, path: *const u8, mode: usize, flags: usize) -> SysResult { + // TODO: check permissions based on uid/gid + let proc = self.process(); + let path = unsafe { proc.vm.check_and_clone_cstr(path)? }; + let flags = AtFlags::from_bits_truncate(flags); + if !proc.pid.is_init() { + // we trust pid 0 process + info!( + "faccessat: dirfd: {}, path: {:?}, mode: {:#o}, flags: {:?}", + dirfd as isize, path, mode, flags + ); + } + let inode = proc.lookup_inode_at(dirfd, &path, !flags.contains(AtFlags::SYMLINK_NOFOLLOW))?; + Ok(0) + } - // for debugging - if cfg!(debug_assertions) { - debug!("files before close {:#?}", proc.files); + pub fn sys_getcwd(&mut self, buf: *mut u8, len: usize) -> SysResult { + let proc = self.process(); + if !proc.pid.is_init() { + // we trust pid 0 process + info!("getcwd: buf: {:?}, len: {:#x}", buf, len); + } + let buf = unsafe { proc.vm.check_write_array(buf, len)? }; + if proc.cwd.len() + 1 > len { + return Err(SysError::ERANGE); + } + unsafe { util::write_cstr(buf.as_mut_ptr(), &proc.cwd) } + Ok(buf.as_ptr() as usize) } - proc.files.remove(&fd).ok_or(SysError::EBADF)?; - Ok(0) -} + pub fn sys_lstat(&mut self, path: *const u8, stat_ptr: *mut Stat) -> SysResult { + self.sys_fstatat(AT_FDCWD, path, stat_ptr, AtFlags::SYMLINK_NOFOLLOW.bits()) + } -pub fn sys_access(path: *const u8, mode: usize) -> SysResult { - sys_faccessat(AT_FDCWD, path, mode, 0) -} + pub fn sys_fstat(&mut self, fd: usize, stat_ptr: *mut Stat) -> SysResult { + info!("fstat: fd: {}, stat_ptr: {:?}", fd, stat_ptr); + let mut proc = self.process(); + let stat_ref = unsafe { proc.vm.check_write_ptr(stat_ptr)? }; + let file = proc.get_file(fd)?; + let stat = Stat::from(file.metadata()?); + *stat_ref = stat; + Ok(0) + } -pub fn sys_faccessat(dirfd: usize, path: *const u8, mode: usize, flags: usize) -> SysResult { - // TODO: check permissions based on uid/gid - let proc = process(); - let path = unsafe { proc.vm.check_and_clone_cstr(path)? }; - let flags = AtFlags::from_bits_truncate(flags); - if !proc.pid.is_init() { - // we trust pid 0 process + pub fn sys_fstatat(&mut self, dirfd: usize, path: *const u8, stat_ptr: *mut Stat, flags: usize) -> SysResult { + let proc = self.process(); + let path = unsafe { proc.vm.check_and_clone_cstr(path)? }; + let stat_ref = unsafe { proc.vm.check_write_ptr(stat_ptr)? }; + let flags = AtFlags::from_bits_truncate(flags); info!( - "faccessat: dirfd: {}, path: {:?}, mode: {:#o}, flags: {:?}", - dirfd as isize, path, mode, flags + "fstatat: dirfd: {}, path: {:?}, stat_ptr: {:?}, flags: {:?}", + dirfd as isize, path, stat_ptr, flags ); + + let inode = proc.lookup_inode_at(dirfd, &path, !flags.contains(AtFlags::SYMLINK_NOFOLLOW))?; + let stat = Stat::from(inode.metadata()?); + *stat_ref = stat; + Ok(0) } - let inode = proc.lookup_inode_at(dirfd, &path, !flags.contains(AtFlags::SYMLINK_NOFOLLOW))?; - Ok(0) -} -pub fn sys_getcwd(buf: *mut u8, len: usize) -> SysResult { - let proc = process(); - if !proc.pid.is_init() { - // we trust pid 0 process - info!("getcwd: buf: {:?}, len: {:#x}", buf, len); + pub fn sys_stat(&mut self, path: *const u8, stat_ptr: *mut Stat) -> SysResult { + self.sys_fstatat(AT_FDCWD, path, stat_ptr, 0) } - let buf = unsafe { proc.vm.check_write_array(buf, len)? }; - if proc.cwd.len() + 1 > len { - return Err(SysError::ERANGE); + + pub fn sys_readlink(&mut self, path: *const u8, base: *mut u8, len: usize) -> SysResult { + self.sys_readlinkat(AT_FDCWD, path, base, len) } - unsafe { util::write_cstr(buf.as_mut_ptr(), &proc.cwd) } - Ok(buf.as_ptr() as usize) -} -pub fn sys_lstat(path: *const u8, stat_ptr: *mut Stat) -> SysResult { - sys_fstatat(AT_FDCWD, path, stat_ptr, AtFlags::SYMLINK_NOFOLLOW.bits()) -} + pub fn sys_readlinkat(&mut self, dirfd: usize, path: *const u8, base: *mut u8, len: usize) -> SysResult { + let proc = self.process(); + let path = unsafe { proc.vm.check_and_clone_cstr(path)? }; + let slice = unsafe { proc.vm.check_write_array(base, len)? }; + info!( + "readlinkat: dirfd: {}, path: {:?}, base: {:?}, len: {}", + dirfd as isize, path, base, len + ); -pub fn sys_fstat(fd: usize, stat_ptr: *mut Stat) -> SysResult { - info!("fstat: fd: {}, stat_ptr: {:?}", fd, stat_ptr); - let mut proc = process(); - let stat_ref = unsafe { proc.vm.check_write_ptr(stat_ptr)? }; - let file = proc.get_file(fd)?; - let stat = Stat::from(file.metadata()?); - *stat_ref = stat; - Ok(0) -} + let inode = proc.lookup_inode_at(dirfd, &path, false)?; + if inode.metadata()?.type_ == FileType::SymLink { + // TODO: recursive link resolution and loop detection + let len = inode.read_at(0, slice)?; + Ok(len) + } else { + Err(SysError::EINVAL) + } + } -pub fn sys_fstatat(dirfd: usize, path: *const u8, stat_ptr: *mut Stat, flags: usize) -> SysResult { - let proc = process(); - let path = unsafe { proc.vm.check_and_clone_cstr(path)? }; - let stat_ref = unsafe { proc.vm.check_write_ptr(stat_ptr)? }; - let flags = AtFlags::from_bits_truncate(flags); - info!( - "fstatat: dirfd: {}, path: {:?}, stat_ptr: {:?}, flags: {:?}", - dirfd as isize, path, stat_ptr, flags - ); - - let inode = proc.lookup_inode_at(dirfd, &path, !flags.contains(AtFlags::SYMLINK_NOFOLLOW))?; - let stat = Stat::from(inode.metadata()?); - *stat_ref = stat; - Ok(0) -} + pub fn sys_lseek(&mut self, fd: usize, offset: i64, whence: u8) -> SysResult { + let pos = match whence { + SEEK_SET => SeekFrom::Start(offset as u64), + SEEK_END => SeekFrom::End(offset), + SEEK_CUR => SeekFrom::Current(offset), + _ => return Err(SysError::EINVAL), + }; + info!("lseek: fd: {}, pos: {:?}", fd, pos); -pub fn sys_stat(path: *const u8, stat_ptr: *mut Stat) -> SysResult { - sys_fstatat(AT_FDCWD, path, stat_ptr, 0) -} + let mut proc = self.process(); + let file = proc.get_file(fd)?; + let offset = file.seek(pos)?; + Ok(offset as usize) + } -pub fn sys_readlink(path: *const u8, base: *mut u8, len: usize) -> SysResult { - sys_readlinkat(AT_FDCWD, path, base, len) -} + pub fn sys_fsync(&mut self, fd: usize) -> SysResult { + info!("fsync: fd: {}", fd); + self.process().get_file(fd)?.sync_all()?; + Ok(0) + } -pub fn sys_readlinkat(dirfd: usize, path: *const u8, base: *mut u8, len: usize) -> SysResult { - let proc = process(); - let path = unsafe { proc.vm.check_and_clone_cstr(path)? }; - let slice = unsafe { proc.vm.check_write_array(base, len)? }; - info!( - "readlinkat: dirfd: {}, path: {:?}, base: {:?}, len: {}", - dirfd as isize, path, base, len - ); - - let inode = proc.lookup_inode_at(dirfd, &path, false)?; - if inode.metadata()?.type_ == FileType::SymLink { - // TODO: recursive link resolution and loop detection - let len = inode.read_at(0, slice)?; - Ok(len) - } else { - Err(SysError::EINVAL) + pub fn sys_fdatasync(&mut self, fd: usize) -> SysResult { + info!("fdatasync: fd: {}", fd); + self.process().get_file(fd)?.sync_data()?; + Ok(0) } -} -pub fn sys_lseek(fd: usize, offset: i64, whence: u8) -> SysResult { - let pos = match whence { - SEEK_SET => SeekFrom::Start(offset as u64), - SEEK_END => SeekFrom::End(offset), - SEEK_CUR => SeekFrom::Current(offset), - _ => return Err(SysError::EINVAL), - }; - info!("lseek: fd: {}, pos: {:?}", fd, pos); - - let mut proc = process(); - let file = proc.get_file(fd)?; - let offset = file.seek(pos)?; - Ok(offset as usize) -} + pub fn sys_truncate(&mut self, path: *const u8, len: usize) -> SysResult { + let proc = self.process(); + let path = unsafe { proc.vm.check_and_clone_cstr(path)? }; + info!("truncate: path: {:?}, len: {}", path, len); + proc.lookup_inode(&path)?.resize(len)?; + Ok(0) + } -pub fn sys_fsync(fd: usize) -> SysResult { - info!("fsync: fd: {}", fd); - process().get_file(fd)?.sync_all()?; - Ok(0) -} + pub fn sys_ftruncate(&mut self, fd: usize, len: usize) -> SysResult { + info!("ftruncate: fd: {}, len: {}", fd, len); + self.process().get_file(fd)?.set_len(len as u64)?; + Ok(0) + } -pub fn sys_fdatasync(fd: usize) -> SysResult { - info!("fdatasync: fd: {}", fd); - process().get_file(fd)?.sync_data()?; - Ok(0) -} + pub fn sys_getdents64(&mut self, fd: usize, buf: *mut LinuxDirent64, buf_size: usize) -> SysResult { + info!( + "getdents64: fd: {}, ptr: {:?}, buf_size: {}", + fd, buf, buf_size + ); + let mut proc = self.process(); + let buf = unsafe { proc.vm.check_write_array(buf as *mut u8, buf_size)? }; + let file = proc.get_file(fd)?; + let info = file.metadata()?; + if info.type_ != FileType::Dir { + return Err(SysError::ENOTDIR); + } + let mut writer = DirentBufWriter::new(buf); + loop { + let name = match file.read_entry() { + Err(FsError::EntryNotFound) => break, + r => r, + }?; + // TODO: get ino from dirent + let ok = writer.try_write(0, DirentType::from_type(&info.type_).bits(), &name); + if !ok { + break; + } + } + Ok(writer.written_size) + } -pub fn sys_truncate(path: *const u8, len: usize) -> SysResult { - let proc = process(); - let path = unsafe { proc.vm.check_and_clone_cstr(path)? }; - info!("truncate: path: {:?}, len: {}", path, len); - proc.lookup_inode(&path)?.resize(len)?; - Ok(0) -} + pub fn sys_dup2(&mut self, fd1: usize, fd2: usize) -> SysResult { + info!("dup2: from {} to {}", fd1, fd2); + let mut proc = self.process(); + // close fd2 first if it is opened + proc.files.remove(&fd2); -pub fn sys_ftruncate(fd: usize, len: usize) -> SysResult { - info!("ftruncate: fd: {}, len: {}", fd, len); - process().get_file(fd)?.set_len(len as u64)?; - Ok(0) -} + let file_like = proc.get_file_like(fd1)?.clone(); + proc.files.insert(fd2, file_like); + Ok(fd2) + } -pub fn sys_getdents64(fd: usize, buf: *mut LinuxDirent64, buf_size: usize) -> SysResult { - info!( - "getdents64: fd: {}, ptr: {:?}, buf_size: {}", - fd, buf, buf_size - ); - let mut proc = process(); - let buf = unsafe { proc.vm.check_write_array(buf as *mut u8, buf_size)? }; - let file = proc.get_file(fd)?; - let info = file.metadata()?; - if info.type_ != FileType::Dir { - return Err(SysError::ENOTDIR); - } - let mut writer = DirentBufWriter::new(buf); - loop { - let name = match file.read_entry() { - Err(FsError::EntryNotFound) => break, - r => r, - }?; - // TODO: get ino from dirent - let ok = writer.try_write(0, DirentType::from_type(&info.type_).bits(), &name); - if !ok { - break; - } + pub fn sys_ioctl(&mut self, fd: usize, request: usize, arg1: usize, arg2: usize, arg3: usize) -> SysResult { + info!( + "ioctl: fd: {}, request: {:x}, args: {} {} {}", + fd, request, arg1, arg2, arg3 + ); + let mut proc = self.process(); + let file_like = proc.get_file_like(fd)?; + file_like.ioctl(request, arg1, arg2, arg3) } - Ok(writer.written_size) -} -pub fn sys_dup2(fd1: usize, fd2: usize) -> SysResult { - info!("dup2: from {} to {}", fd1, fd2); - let mut proc = process(); - // close fd2 first if it is opened - proc.files.remove(&fd2); + pub fn sys_chdir(&mut self, path: *const u8) -> SysResult { + let mut proc = self.process(); + let path = unsafe { proc.vm.check_and_clone_cstr(path)? }; + if !proc.pid.is_init() { + // we trust pid 0 process + info!("chdir: path: {:?}", path); + } - let file_like = proc.get_file_like(fd1)?.clone(); - proc.files.insert(fd2, file_like); - Ok(fd2) -} + let inode = proc.lookup_inode(&path)?; + let info = inode.metadata()?; + if info.type_ != FileType::Dir { + return Err(SysError::ENOTDIR); + } -pub fn sys_ioctl(fd: usize, request: usize, arg1: usize, arg2: usize, arg3: usize) -> SysResult { - info!( - "ioctl: fd: {}, request: {:x}, args: {} {} {}", - fd, request, arg1, arg2, arg3 - ); - let mut proc = process(); - let file_like = proc.get_file_like(fd)?; - file_like.ioctl(request, arg1, arg2, arg3) -} + // BUGFIX: '..' and '.' + if path.len() > 0 { + let cwd = match path.as_bytes()[0] { + b'/' => String::from("/"), + _ => proc.cwd.clone(), + }; + let mut cwd_vec: Vec<_> = cwd.split("/").filter(|&x| x != "").collect(); + let path_split = path.split("/").filter(|&x| x != ""); + for seg in path_split { + if seg == ".." { + cwd_vec.pop(); + } else if seg == "." { + // nothing to do here. + } else { + cwd_vec.push(seg); + } + } + proc.cwd = String::from(""); + for seg in cwd_vec { + proc.cwd.push_str("/"); + proc.cwd.push_str(seg); + } + if proc.cwd == "" { + proc.cwd = String::from("/"); + } + } + Ok(0) + } -pub fn sys_chdir(path: *const u8) -> SysResult { - let mut proc = process(); - let path = unsafe { proc.vm.check_and_clone_cstr(path)? }; - if !proc.pid.is_init() { - // we trust pid 0 process - info!("chdir: path: {:?}", path); + pub fn sys_rename(&mut self, oldpath: *const u8, newpath: *const u8) -> SysResult { + self.sys_renameat(AT_FDCWD, oldpath, AT_FDCWD, newpath) } - let inode = proc.lookup_inode(&path)?; - let info = inode.metadata()?; - if info.type_ != FileType::Dir { - return Err(SysError::ENOTDIR); + pub fn sys_renameat( + &mut self, + olddirfd: usize, + oldpath: *const u8, + newdirfd: usize, + newpath: *const u8, + ) -> SysResult { + let mut proc = self.process(); + let oldpath = unsafe { proc.vm.check_and_clone_cstr(oldpath)? }; + let newpath = unsafe { proc.vm.check_and_clone_cstr(newpath)? }; + info!( + "renameat: olddirfd: {}, oldpath: {:?}, newdirfd: {}, newpath: {:?}", + olddirfd as isize, oldpath, newdirfd as isize, newpath + ); + + let (old_dir_path, old_file_name) = split_path(&oldpath); + let (new_dir_path, new_file_name) = split_path(&newpath); + let old_dir_inode = proc.lookup_inode_at(olddirfd, old_dir_path, false)?; + let new_dir_inode = proc.lookup_inode_at(newdirfd, new_dir_path, false)?; + old_dir_inode.move_(old_file_name, &new_dir_inode, new_file_name)?; + Ok(0) } - // BUGFIX: '..' and '.' - if path.len() > 0 { - let cwd = match path.as_bytes()[0] { - b'/' => String::from("/"), - _ => proc.cwd.clone(), - }; - let mut cwd_vec: Vec<_> = cwd.split("/").filter(|&x| x != "").collect(); - let path_split = path.split("/").filter(|&x| x != ""); - for seg in path_split { - if seg == ".." { - cwd_vec.pop(); - } else if seg == "." { - // nothing to do here. - } else { - cwd_vec.push(seg); - } - } - proc.cwd = String::from(""); - for seg in cwd_vec { - proc.cwd.push_str("/"); - proc.cwd.push_str(seg); - } - if proc.cwd == "" { - proc.cwd = String::from("/"); - } + pub fn sys_mkdir(&mut self, path: *const u8, mode: usize) -> SysResult { + self.sys_mkdirat(AT_FDCWD, path, mode) } - Ok(0) -} -pub fn sys_rename(oldpath: *const u8, newpath: *const u8) -> SysResult { - sys_renameat(AT_FDCWD, oldpath, AT_FDCWD, newpath) -} + pub fn sys_mkdirat(&mut self, dirfd: usize, path: *const u8, mode: usize) -> SysResult { + let proc = self.process(); + let path = unsafe { proc.vm.check_and_clone_cstr(path)? }; + // TODO: check pathname + info!( + "mkdirat: dirfd: {}, path: {:?}, mode: {:#o}", + dirfd as isize, path, mode + ); -pub fn sys_renameat( - olddirfd: usize, - oldpath: *const u8, - newdirfd: usize, - newpath: *const u8, -) -> SysResult { - let mut proc = process(); - let oldpath = unsafe { proc.vm.check_and_clone_cstr(oldpath)? }; - let newpath = unsafe { proc.vm.check_and_clone_cstr(newpath)? }; - info!( - "renameat: olddirfd: {}, oldpath: {:?}, newdirfd: {}, newpath: {:?}", - olddirfd as isize, oldpath, newdirfd as isize, newpath - ); - - let (old_dir_path, old_file_name) = split_path(&oldpath); - let (new_dir_path, new_file_name) = split_path(&newpath); - let old_dir_inode = proc.lookup_inode_at(olddirfd, old_dir_path, false)?; - let new_dir_inode = proc.lookup_inode_at(newdirfd, new_dir_path, false)?; - old_dir_inode.move_(old_file_name, &new_dir_inode, new_file_name)?; - Ok(0) -} + let (dir_path, file_name) = split_path(&path); + let inode = proc.lookup_inode_at(dirfd, dir_path, true)?; + if inode.find(file_name).is_ok() { + return Err(SysError::EEXIST); + } + inode.create(file_name, FileType::Dir, mode as u32)?; + Ok(0) + } -pub fn sys_mkdir(path: *const u8, mode: usize) -> SysResult { - sys_mkdirat(AT_FDCWD, path, mode) -} + pub fn sys_rmdir(&mut self, path: *const u8) -> SysResult { + let proc = self.process(); + let path = unsafe { proc.vm.check_and_clone_cstr(path)? }; + info!("rmdir: path: {:?}", path); -pub fn sys_mkdirat(dirfd: usize, path: *const u8, mode: usize) -> SysResult { - let proc = process(); - let path = unsafe { proc.vm.check_and_clone_cstr(path)? }; - // TODO: check pathname - info!( - "mkdirat: dirfd: {}, path: {:?}, mode: {:#o}", - dirfd as isize, path, mode - ); - - let (dir_path, file_name) = split_path(&path); - let inode = proc.lookup_inode_at(dirfd, dir_path, true)?; - if inode.find(file_name).is_ok() { - return Err(SysError::EEXIST); - } - inode.create(file_name, FileType::Dir, mode as u32)?; - Ok(0) -} + let (dir_path, file_name) = split_path(&path); + let dir_inode = proc.lookup_inode(dir_path)?; + let file_inode = dir_inode.find(file_name)?; + if file_inode.metadata()?.type_ != FileType::Dir { + return Err(SysError::ENOTDIR); + } + dir_inode.unlink(file_name)?; + Ok(0) + } -pub fn sys_rmdir(path: *const u8) -> SysResult { - let proc = process(); - let path = unsafe { proc.vm.check_and_clone_cstr(path)? }; - info!("rmdir: path: {:?}", path); + pub fn sys_link(&mut self, oldpath: *const u8, newpath: *const u8) -> SysResult { + self.sys_linkat(AT_FDCWD, oldpath, AT_FDCWD, newpath, 0) + } - let (dir_path, file_name) = split_path(&path); - let dir_inode = proc.lookup_inode(dir_path)?; - let file_inode = dir_inode.find(file_name)?; - if file_inode.metadata()?.type_ != FileType::Dir { - return Err(SysError::ENOTDIR); + pub fn sys_linkat( + &mut self, + olddirfd: usize, + oldpath: *const u8, + newdirfd: usize, + newpath: *const u8, + flags: usize, + ) -> SysResult { + let proc = self.process(); + let oldpath = unsafe { proc.vm.check_and_clone_cstr(oldpath)? }; + let newpath = unsafe { proc.vm.check_and_clone_cstr(newpath)? }; + let flags = AtFlags::from_bits_truncate(flags); + info!( + "linkat: olddirfd: {}, oldpath: {:?}, newdirfd: {}, newpath: {:?}, flags: {:?}", + olddirfd as isize, oldpath, newdirfd as isize, newpath, flags + ); + + let (new_dir_path, new_file_name) = split_path(&newpath); + let inode = proc.lookup_inode_at(olddirfd, &oldpath, true)?; + let new_dir_inode = proc.lookup_inode_at(newdirfd, new_dir_path, true)?; + new_dir_inode.link(new_file_name, &inode)?; + Ok(0) } - dir_inode.unlink(file_name)?; - Ok(0) -} -pub fn sys_link(oldpath: *const u8, newpath: *const u8) -> SysResult { - sys_linkat(AT_FDCWD, oldpath, AT_FDCWD, newpath, 0) -} + pub fn sys_unlink(&mut self, path: *const u8) -> SysResult { + self.sys_unlinkat(AT_FDCWD, path, 0) + } -pub fn sys_linkat( - olddirfd: usize, - oldpath: *const u8, - newdirfd: usize, - newpath: *const u8, - flags: usize, -) -> SysResult { - let proc = process(); - let oldpath = unsafe { proc.vm.check_and_clone_cstr(oldpath)? }; - let newpath = unsafe { proc.vm.check_and_clone_cstr(newpath)? }; - let flags = AtFlags::from_bits_truncate(flags); - info!( - "linkat: olddirfd: {}, oldpath: {:?}, newdirfd: {}, newpath: {:?}, flags: {:?}", - olddirfd as isize, oldpath, newdirfd as isize, newpath, flags - ); - - let (new_dir_path, new_file_name) = split_path(&newpath); - let inode = proc.lookup_inode_at(olddirfd, &oldpath, true)?; - let new_dir_inode = proc.lookup_inode_at(newdirfd, new_dir_path, true)?; - new_dir_inode.link(new_file_name, &inode)?; - Ok(0) -} + pub fn sys_unlinkat(&mut self, dirfd: usize, path: *const u8, flags: usize) -> SysResult { + let proc = self.process(); + let path = unsafe { proc.vm.check_and_clone_cstr(path)? }; + let flags = AtFlags::from_bits_truncate(flags); + info!( + "unlinkat: dirfd: {}, path: {:?}, flags: {:?}", + dirfd as isize, path, flags + ); -pub fn sys_unlink(path: *const u8) -> SysResult { - sys_unlinkat(AT_FDCWD, path, 0) -} + let (dir_path, file_name) = split_path(&path); + let dir_inode = proc.lookup_inode_at(dirfd, dir_path, true)?; + let file_inode = dir_inode.find(file_name)?; + if file_inode.metadata()?.type_ == FileType::Dir { + return Err(SysError::EISDIR); + } + dir_inode.unlink(file_name)?; + Ok(0) + } -pub fn sys_unlinkat(dirfd: usize, path: *const u8, flags: usize) -> SysResult { - let proc = process(); - let path = unsafe { proc.vm.check_and_clone_cstr(path)? }; - let flags = AtFlags::from_bits_truncate(flags); - info!( - "unlinkat: dirfd: {}, path: {:?}, flags: {:?}", - dirfd as isize, path, flags - ); - - let (dir_path, file_name) = split_path(&path); - let dir_inode = proc.lookup_inode_at(dirfd, dir_path, true)?; - let file_inode = dir_inode.find(file_name)?; - if file_inode.metadata()?.type_ == FileType::Dir { - return Err(SysError::EISDIR); - } - dir_inode.unlink(file_name)?; - Ok(0) -} + pub fn sys_pipe(&mut self, fds: *mut u32) -> SysResult { + info!("pipe: fds: {:?}", fds); -pub fn sys_pipe(fds: *mut u32) -> SysResult { - info!("pipe: fds: {:?}", fds); + let mut proc = self.process(); + let fds = unsafe { proc.vm.check_write_array(fds, 2)? }; + let (read, write) = Pipe::create_pair(); - let mut proc = process(); - let fds = unsafe { proc.vm.check_write_array(fds, 2)? }; - let (read, write) = Pipe::create_pair(); + let read_fd = proc.add_file(FileLike::File(FileHandle::new( + Arc::new(read), + OpenOptions { + read: true, + write: false, + append: false, + }, + String::from("pipe_r:[]"), + ))); + + let write_fd = proc.add_file(FileLike::File(FileHandle::new( + Arc::new(write), + OpenOptions { + read: false, + write: true, + append: false, + }, + String::from("pipe_w:[]"), + ))); - let read_fd = proc.add_file(FileLike::File(FileHandle::new( - Arc::new(read), - OpenOptions { - read: true, - write: false, - append: false, - }, - String::from("pipe_r:[]"), - ))); - - let write_fd = proc.add_file(FileLike::File(FileHandle::new( - Arc::new(write), - OpenOptions { - read: false, - write: true, - append: false, - }, - String::from("pipe_w:[]"), - ))); + fds[0] = read_fd as u32; + fds[1] = write_fd as u32; - fds[0] = read_fd as u32; - fds[1] = write_fd as u32; + info!("pipe: created rfd: {} wfd: {}", read_fd, write_fd); - info!("pipe: created rfd: {} wfd: {}", read_fd, write_fd); + Ok(0) + } - Ok(0) -} + pub fn sys_sync(&mut self) -> SysResult { + ROOT_INODE.fs().sync()?; + Ok(0) + } -pub fn sys_sync() -> SysResult { - ROOT_INODE.fs().sync()?; - Ok(0) -} + pub fn sys_sendfile( + &mut self, + out_fd: usize, + in_fd: usize, + offset_ptr: *mut usize, + count: usize, + ) -> SysResult { + info!( + "sendfile:BEG out: {}, in: {}, offset_ptr: {:?}, count: {}", + out_fd, in_fd, offset_ptr, count + ); + let proc = self.process(); + // We know it's save, pacify the borrow checker + let proc_cell = UnsafeCell::new(proc); + let in_file = unsafe { (*proc_cell.get()).get_file(in_fd)? }; + let out_file = unsafe { (*proc_cell.get()).get_file(out_fd)? }; + let mut buffer = [0u8; 1024]; + + let mut read_offset = if !offset_ptr.is_null() { + unsafe { *(*proc_cell.get()).vm.check_read_ptr(offset_ptr)? } + } else { + in_file.seek(SeekFrom::Current(0))? as usize + }; -pub fn sys_sendfile( - out_fd: usize, - in_fd: usize, - offset_ptr: *mut usize, - count: usize, -) -> SysResult { - info!( - "sendfile:BEG out: {}, in: {}, offset_ptr: {:?}, count: {}", - out_fd, in_fd, offset_ptr, count - ); - let proc = process(); - // We know it's save, pacify the borrow checker - let proc_cell = UnsafeCell::new(proc); - let in_file = unsafe { (*proc_cell.get()).get_file(in_fd)? }; - let out_file = unsafe { (*proc_cell.get()).get_file(out_fd)? }; - let mut buffer = [0u8; 1024]; - - let mut read_offset = if !offset_ptr.is_null() { - unsafe { *(*proc_cell.get()).vm.check_read_ptr(offset_ptr)? } - } else { - in_file.seek(SeekFrom::Current(0))? as usize - }; - - // read from specified offset and write new offset back - let mut bytes_read = 0; - let mut total_written = 0; - while bytes_read < count { - let len = min(buffer.len(), count - bytes_read); - let read_len = in_file.read_at(read_offset, &mut buffer[..len])?; - if read_len == 0 { - break; - } - bytes_read += read_len; - read_offset += read_len; - - let mut bytes_written = 0; - let mut rlen = read_len; - while bytes_written < read_len { - let write_len = out_file.write(&buffer[bytes_written..(bytes_written + rlen)])?; - if write_len == 0 { - info!( - "sendfile:END_ERR out: {}, in: {}, offset_ptr: {:?}, count: {} = bytes_read {}, bytes_written {}, write_len {}", - out_fd, in_fd, offset_ptr, count, bytes_read, bytes_written, write_len - ); - return Err(SysError::EBADF); + // read from specified offset and write new offset back + let mut bytes_read = 0; + let mut total_written = 0; + while bytes_read < count { + let len = min(buffer.len(), count - bytes_read); + let read_len = in_file.read_at(read_offset, &mut buffer[..len])?; + if read_len == 0 { + break; } - bytes_written += write_len; - rlen -= write_len; + bytes_read += read_len; + read_offset += read_len; + + let mut bytes_written = 0; + let mut rlen = read_len; + while bytes_written < read_len { + let write_len = out_file.write(&buffer[bytes_written..(bytes_written + rlen)])?; + if write_len == 0 { + info!( + "sendfile:END_ERR out: {}, in: {}, offset_ptr: {:?}, count: {} = bytes_read {}, bytes_written {}, write_len {}", + out_fd, in_fd, offset_ptr, count, bytes_read, bytes_written, write_len + ); + return Err(SysError::EBADF); + } + bytes_written += write_len; + rlen -= write_len; + } + total_written += bytes_written; } - total_written += bytes_written; - } - if !offset_ptr.is_null() { - unsafe { - offset_ptr.write(read_offset); + if !offset_ptr.is_null() { + unsafe { + offset_ptr.write(read_offset); + } + } else { + in_file.seek(SeekFrom::Current(bytes_read as i64))?; } - } else { - in_file.seek(SeekFrom::Current(bytes_read as i64))?; - } - info!( - "sendfile:END out: {}, in: {}, offset_ptr: {:?}, count: {} = bytes_read {}, total_written {}", - out_fd, in_fd, offset_ptr, count, bytes_read, total_written - ); - return Ok(total_written); + info!( + "sendfile:END out: {}, in: {}, offset_ptr: {:?}, count: {} = bytes_read {}, total_written {}", + out_fd, in_fd, offset_ptr, count, bytes_read, total_written + ); + return Ok(total_written); + } } impl Process { diff --git a/kernel/src/syscall/mem.rs b/kernel/src/syscall/mem.rs index 9884264..7195ea9 100644 --- a/kernel/src/syscall/mem.rs +++ b/kernel/src/syscall/mem.rs @@ -8,96 +8,98 @@ use crate::memory::GlobalFrameAlloc; use super::*; -pub fn sys_mmap( - mut addr: usize, - len: usize, - prot: usize, - flags: usize, - fd: usize, - offset: usize, -) -> SysResult { - let prot = MmapProt::from_bits_truncate(prot); - let flags = MmapFlags::from_bits_truncate(flags); - info!( - "mmap: addr={:#x}, size={:#x}, prot={:?}, flags={:?}, fd={}, offset={:#x}", - addr, len, prot, flags, fd, offset - ); +impl Syscall<'_> { + pub fn sys_mmap( + &mut self, + mut addr: usize, + len: usize, + prot: usize, + flags: usize, + fd: usize, + offset: usize, + ) -> SysResult { + let prot = MmapProt::from_bits_truncate(prot); + let flags = MmapFlags::from_bits_truncate(flags); + info!( + "mmap: addr={:#x}, size={:#x}, prot={:?}, flags={:?}, fd={}, offset={:#x}", + addr, len, prot, flags, fd, offset + ); - let mut proc = process(); - if addr == 0 { - // although NULL can be a valid address - // but in C, NULL is regarded as allocation failure - // so just skip it - addr = PAGE_SIZE; - } + let mut proc = self.process(); + if addr == 0 { + // although NULL can be a valid address + // but in C, NULL is regarded as allocation failure + // so just skip it + addr = PAGE_SIZE; + } - if flags.contains(MmapFlags::FIXED) { - // we have to map it to addr, so remove the old mapping first - proc.vm.pop_with_split(addr, addr + len); - } else { - addr = proc.vm.find_free_area(addr, len); - } + if flags.contains(MmapFlags::FIXED) { + // we have to map it to addr, so remove the old mapping first + proc.vm.pop_with_split(addr, addr + len); + } else { + addr = proc.vm.find_free_area(addr, len); + } - if flags.contains(MmapFlags::ANONYMOUS) { - if flags.contains(MmapFlags::SHARED) { - return Err(SysError::EINVAL); + if flags.contains(MmapFlags::ANONYMOUS) { + if flags.contains(MmapFlags::SHARED) { + return Err(SysError::EINVAL); + } + proc.vm.push( + addr, + addr + len, + prot.to_attr(), + Delay::new(GlobalFrameAlloc), + "mmap_anon", + ); + return Ok(addr); + } else { + let inode = proc.get_file(fd)?.inode(); + proc.vm.push( + addr, + addr + len, + prot.to_attr(), + File { + file: INodeForMap(inode), + mem_start: addr, + file_start: offset, + file_end: offset + len, + allocator: GlobalFrameAlloc, + }, + "mmap_file", + ); + return Ok(addr); } - proc.vm.push( - addr, - addr + len, - prot.to_attr(), - Delay::new(GlobalFrameAlloc), - "mmap_anon", - ); - return Ok(addr); - } else { - let inode = proc.get_file(fd)?.inode(); - proc.vm.push( - addr, - addr + len, - prot.to_attr(), - File { - file: INodeForMap(inode), - mem_start: addr, - file_start: offset, - file_end: offset + len, - allocator: GlobalFrameAlloc, - }, - "mmap_file", - ); - return Ok(addr); } -} -pub fn sys_mprotect(addr: usize, len: usize, prot: usize) -> SysResult { - let prot = MmapProt::from_bits_truncate(prot); - info!( - "mprotect: addr={:#x}, size={:#x}, prot={:?}", - addr, len, prot - ); + pub fn sys_mprotect(&mut self, addr: usize, len: usize, prot: usize) -> SysResult { + let prot = MmapProt::from_bits_truncate(prot); + info!( + "mprotect: addr={:#x}, size={:#x}, prot={:?}", + addr, len, prot + ); - let mut proc = process(); - let attr = prot.to_attr(); + let mut proc = self.process(); + let attr = prot.to_attr(); - // FIXME: properly set the attribute of the area - // now some mut ptr check is fault - let memory_area = proc - .vm - .iter() - .find(|area| area.is_overlap_with(addr, addr + len)); - if memory_area.is_none() { - return Err(SysError::ENOMEM); + // FIXME: properly set the attribute of the area + // now some mut ptr check is fault + let memory_area = proc + .vm + .iter() + .find(|area| area.is_overlap_with(addr, addr + len)); + if memory_area.is_none() { + return Err(SysError::ENOMEM); + } + Ok(0) } - Ok(0) -} -pub fn sys_munmap(addr: usize, len: usize) -> SysResult { - info!("munmap addr={:#x}, size={:#x}", addr, len); - let mut proc = process(); - proc.vm.pop_with_split(addr, addr + len); - Ok(0) + pub fn sys_munmap(&mut self, addr: usize, len: usize) -> SysResult { + info!("munmap addr={:#x}, size={:#x}", addr, len); + let mut proc = self.process(); + proc.vm.pop_with_split(addr, addr + len); + Ok(0) + } } - bitflags! { pub struct MmapProt: usize { /// Data cannot be accessed diff --git a/kernel/src/syscall/misc.rs b/kernel/src/syscall/misc.rs index 54c7925..886761b 100644 --- a/kernel/src/syscall/misc.rs +++ b/kernel/src/syscall/misc.rs @@ -4,119 +4,185 @@ use crate::consts::USER_STACK_SIZE; use core::mem::size_of; use core::sync::atomic::{AtomicI32, Ordering}; -pub fn sys_arch_prctl(code: i32, addr: usize, tf: &mut TrapFrame) -> SysResult { - const ARCH_SET_FS: i32 = 0x1002; - match code { - #[cfg(target_arch = "x86_64")] - ARCH_SET_FS => { - info!("sys_arch_prctl: set FS to {:#x}", addr); - tf.fsbase = addr; - Ok(0) +impl Syscall<'_> { + #[cfg(target_arch = "x86_64")] + pub fn sys_arch_prctl(&mut self, code: i32, addr: usize) -> SysResult { + const ARCH_SET_FS: i32 = 0x1002; + match code { + ARCH_SET_FS => { + info!("sys_arch_prctl: set FSBASE to {:#x}", addr); + self.tf.fsbase = addr; + Ok(0) + } + _ => Err(SysError::EINVAL), } - _ => Err(SysError::EINVAL), } -} -pub fn sys_uname(buf: *mut u8) -> SysResult { - info!("uname: buf: {:?}", buf); + pub fn sys_uname(&mut self, buf: *mut u8) -> SysResult { + info!("uname: buf: {:?}", buf); - let offset = 65; - let strings = ["rCore", "orz", "0.1.0", "1", "machine", "domain"]; - let proc = process(); - let buf = unsafe { proc.vm.check_write_array(buf, strings.len() * offset)? }; + let offset = 65; + let strings = ["rCore", "orz", "0.1.0", "1", "machine", "domain"]; + let proc = self.process(); + let buf = unsafe { proc.vm.check_write_array(buf, strings.len() * offset)? }; - for i in 0..strings.len() { - unsafe { - util::write_cstr(&mut buf[i * offset], &strings[i]); + for i in 0..strings.len() { + unsafe { + util::write_cstr(&mut buf[i * offset], &strings[i]); + } } + Ok(0) } - Ok(0) -} - -pub fn sys_sched_getaffinity(pid: usize, size: usize, mask: *mut u32) -> SysResult { - info!( - "sched_getaffinity: pid: {}, size: {}, mask: {:?}", - pid, size, mask - ); - let proc = process(); - let mask = unsafe { proc.vm.check_write_array(mask, size / size_of::())? }; - - // we only have 4 cpu at most. - // so just set it. - mask[0] = 0b1111; - Ok(0) -} -pub fn sys_sysinfo(sys_info: *mut SysInfo) -> SysResult { - let proc = process(); - let sys_info = unsafe { proc.vm.check_write_ptr(sys_info)? }; + pub fn sys_sched_getaffinity(&mut self, pid: usize, size: usize, mask: *mut u32) -> SysResult { + info!( + "sched_getaffinity: pid: {}, size: {}, mask: {:?}", + pid, size, mask + ); + let proc = self.process(); + let mask = unsafe { proc.vm.check_write_array(mask, size / size_of::())? }; + + // we only have 4 cpu at most. + // so just set it. + mask[0] = 0b1111; + Ok(0) + } - let sysinfo = SysInfo::default(); - *sys_info = sysinfo; - Ok(0) -} + pub fn sys_sysinfo(&mut self, sys_info: *mut SysInfo) -> SysResult { + let proc = self.process(); + let sys_info = unsafe { proc.vm.check_write_ptr(sys_info)? }; -pub fn sys_futex(uaddr: usize, op: u32, val: i32, timeout: *const TimeSpec) -> SysResult { - info!( - "futex: [{}] uaddr: {:#x}, op: {:#x}, val: {}, timeout_ptr: {:?}", - thread::current().id(), - uaddr, - op, - val, - timeout - ); - // if op & OP_PRIVATE == 0 { - // unimplemented!("futex only support process-private"); - // return Err(SysError::ENOSYS); - // } - if uaddr % size_of::() != 0 { - return Err(SysError::EINVAL); + let sysinfo = SysInfo::default(); + *sys_info = sysinfo; + Ok(0) } - let atomic = unsafe { process().vm.check_write_ptr(uaddr as *mut AtomicI32)? }; - let _timeout = if timeout.is_null() { - None - } else { - Some(unsafe { *process().vm.check_read_ptr(timeout)? }) - }; - - const OP_WAIT: u32 = 0; - const OP_WAKE: u32 = 1; - const OP_PRIVATE: u32 = 128; - - let queue = process().get_futex(uaddr); - - match op & 0xf { - OP_WAIT => { - if atomic.load(Ordering::Acquire) != val { - return Err(SysError::EAGAIN); + + pub fn sys_futex(&mut self, uaddr: usize, op: u32, val: i32, timeout: *const TimeSpec) -> SysResult { + info!( + "futex: [{}] uaddr: {:#x}, op: {:#x}, val: {}, timeout_ptr: {:?}", + thread::current().id(), + uaddr, + op, + val, + timeout + ); + // if op & OP_PRIVATE == 0 { + // unimplemented!("futex only support process-private"); + // return Err(SysError::ENOSYS); + // } + if uaddr % size_of::() != 0 { + return Err(SysError::EINVAL); + } + let atomic = unsafe { self.process().vm.check_write_ptr(uaddr as *mut AtomicI32)? }; + let _timeout = if timeout.is_null() { + None + } else { + Some(unsafe { *self.process().vm.check_read_ptr(timeout)? }) + }; + + const OP_WAIT: u32 = 0; + const OP_WAKE: u32 = 1; + const OP_PRIVATE: u32 = 128; + + let queue = self.process().get_futex(uaddr); + + match op & 0xf { + OP_WAIT => { + if atomic.load(Ordering::Acquire) != val { + return Err(SysError::EAGAIN); + } + // FIXME: support timeout + // FIXME: fix racing + queue._wait(); + Ok(0) + } + OP_WAKE => { + let woken_up_count = queue.notify_n(val as usize); + Ok(woken_up_count) + } + _ => { + warn!("unsupported futex operation: {}", op); + Err(SysError::ENOSYS) } - // FIXME: support timeout - // FIXME: fix racing - queue._wait(); - Ok(0) } - OP_WAKE => { - let woken_up_count = queue.notify_n(val as usize); - Ok(woken_up_count) + } + + pub fn sys_reboot(&mut self, _magic: u32, magic2: u32, cmd: u32, _arg: *const u8) -> SysResult { + // we will skip verifying magic + if cmd == LINUX_REBOOT_CMD_HALT { + unsafe { + cpu::exit_in_qemu(1); + } } - _ => { - warn!("unsupported futex operation: {}", op); - Err(SysError::ENOSYS) + Ok(0) + } + + pub fn sys_prlimit64( + &mut self, + pid: usize, + resource: usize, + new_limit: *const RLimit, + old_limit: *mut RLimit, + ) -> SysResult { + let proc = self.process(); + info!( + "prlimit64: pid: {}, resource: {}, new_limit: {:x?}, old_limit: {:x?}", + pid, resource, new_limit, old_limit + ); + match resource { + RLIMIT_STACK => { + if !old_limit.is_null() { + let old_limit = unsafe { proc.vm.check_write_ptr(old_limit)? }; + *old_limit = RLimit { + cur: USER_STACK_SIZE as u64, + max: USER_STACK_SIZE as u64, + }; + } + Ok(0) + } + RLIMIT_NOFILE => { + if !old_limit.is_null() { + let old_limit = unsafe { proc.vm.check_write_ptr(old_limit)? }; + *old_limit = RLimit { + cur: 1024, + max: 1024, + }; + } + Ok(0) + } + RLIMIT_RSS | RLIMIT_AS => { + if !old_limit.is_null() { + let old_limit = unsafe { proc.vm.check_write_ptr(old_limit)? }; + // 1GB + *old_limit = RLimit { + cur: 1024 * 1024 * 1024, + max: 1024 * 1024 * 1024, + }; + } + Ok(0) + } + _ => Err(SysError::ENOSYS), } } -} -const LINUX_REBOOT_CMD_HALT: u32 = 0xcdef0123; -pub fn sys_reboot(_magic: u32, magic2: u32, cmd: u32, _arg: *const u8) -> SysResult { - // we will skip verifying magic - if cmd == LINUX_REBOOT_CMD_HALT { - unsafe { - cpu::exit_in_qemu(1); + pub fn sys_getrandom(&mut self, buf: *mut u8, len: usize, flag: u32) -> SysResult { + //info!("getrandom: buf: {:?}, len: {:?}, falg {:?}", buf, len,flag); + let mut proc = self.process(); + let slice = unsafe { proc.vm.check_write_array(buf, len)? }; + let mut i = 0; + for elm in slice { + unsafe { + *elm = i + crate::trap::TICK as u8; + } + i += 1; } + + Ok(len) } - Ok(0) } +const LINUX_REBOOT_CMD_HALT: u32 = 0xcdef0123; + #[repr(C)] #[derive(Debug, Default)] pub struct SysInfo { @@ -139,71 +205,9 @@ const RLIMIT_RSS: usize = 5; const RLIMIT_NOFILE: usize = 7; const RLIMIT_AS: usize = 9; -pub fn sys_prlimit64( - pid: usize, - resource: usize, - new_limit: *const RLimit, - old_limit: *mut RLimit, -) -> SysResult { - let proc = process(); - info!( - "prlimit64: pid: {}, resource: {}, new_limit: {:x?}, old_limit: {:x?}", - pid, resource, new_limit, old_limit - ); - match resource { - RLIMIT_STACK => { - if !old_limit.is_null() { - let old_limit = unsafe { proc.vm.check_write_ptr(old_limit)? }; - *old_limit = RLimit { - cur: USER_STACK_SIZE as u64, - max: USER_STACK_SIZE as u64, - }; - } - Ok(0) - } - RLIMIT_NOFILE => { - if !old_limit.is_null() { - let old_limit = unsafe { proc.vm.check_write_ptr(old_limit)? }; - *old_limit = RLimit { - cur: 1024, - max: 1024, - }; - } - Ok(0) - } - RLIMIT_RSS | RLIMIT_AS => { - if !old_limit.is_null() { - let old_limit = unsafe { proc.vm.check_write_ptr(old_limit)? }; - // 1GB - *old_limit = RLimit { - cur: 1024 * 1024 * 1024, - max: 1024 * 1024 * 1024, - }; - } - Ok(0) - } - _ => Err(SysError::ENOSYS), - } -} - #[repr(C)] #[derive(Debug, Default)] pub struct RLimit { cur: u64, // soft limit max: u64, // hard limit } - -pub fn sys_getrandom(buf: *mut u8, len: usize, flag: u32) -> SysResult { - //info!("getrandom: buf: {:?}, len: {:?}, falg {:?}", buf, len,flag); - let mut proc = process(); - let slice = unsafe { proc.vm.check_write_array(buf, len)? }; - let mut i = 0; - for elm in slice { - unsafe { - *elm = i + crate::trap::TICK as u8; - } - i += 1; - } - - Ok(len) -} diff --git a/kernel/src/syscall/mod.rs b/kernel/src/syscall/mod.rs index 7303ae7..f087690 100644 --- a/kernel/src/syscall/mod.rs +++ b/kernel/src/syscall/mod.rs @@ -11,7 +11,7 @@ use crate::arch::cpu; use crate::arch::interrupt::TrapFrame; use crate::arch::syscall::*; use crate::process::*; -use crate::sync::Condvar; +use crate::sync::{Condvar, SpinNoIrq, MutexGuard}; use crate::thread; use crate::util; @@ -40,330 +40,348 @@ lazy_static! { } /// System call dispatcher -// This #[deny(unreachable_patterns)] checks if each match arm is defined -// See discussion in https://github.com/oscourse-tsinghua/rcore_plus/commit/17e644e54e494835f1a49b34b80c2c4f15ed0dbe. -#[deny(unreachable_patterns)] pub fn syscall(id: usize, args: [usize; 6], tf: &mut TrapFrame) -> isize { - #[cfg(feature = "profile")] - let begin_time = unsafe { core::arch::x86_64::_rdtsc() }; - let cid = cpu::id(); - let pid = process().pid.clone(); - let tid = processor().tid(); - if !pid.is_init() { - // we trust pid 0 process - debug!("{}:{}:{} syscall id {} begin", cid, pid, tid, id); + let thread = unsafe { current_thread() }; + let mut syscall = Syscall { thread, tf }; + syscall.syscall(id, args) +} + +/// All context needed for syscall +struct Syscall<'a> { + thread: &'a mut Thread, + tf: &'a mut TrapFrame, +} + +impl Syscall<'_> { + /// Get current process + pub fn process(&self) -> MutexGuard<'_, Process, SpinNoIrq> { + self.thread.proc.lock() } - // use platform-specific syscal numbers - // See https://filippo.io/linux-syscall-table/ - // And https://fedora.juszkiewicz.com.pl/syscalls.html. - let ret = match id { - // file - SYS_READ => sys_read(args[0], args[1] as *mut u8, args[2]), - SYS_WRITE => sys_write(args[0], args[1] as *const u8, args[2]), - SYS_OPENAT => sys_openat(args[0], args[1] as *const u8, args[2], args[3]), - SYS_CLOSE => sys_close(args[0]), - SYS_FSTAT => sys_fstat(args[0], args[1] as *mut Stat), - SYS_NEWFSTATAT => sys_fstatat(args[0], args[1] as *const u8, args[2] as *mut Stat, args[3]), - SYS_LSEEK => sys_lseek(args[0], args[1] as i64, args[2] as u8), - SYS_IOCTL => sys_ioctl(args[0], args[1], args[2], args[3], args[4]), - SYS_PREAD64 => sys_pread(args[0], args[1] as *mut u8, args[2], args[3]), - SYS_PWRITE64 => sys_pwrite(args[0], args[1] as *const u8, args[2], args[3]), - SYS_READV => sys_readv(args[0], args[1] as *const IoVec, args[2]), - SYS_WRITEV => sys_writev(args[0], args[1] as *const IoVec, args[2]), - SYS_SENDFILE => sys_sendfile(args[0], args[1], args[2] as *mut usize, args[3]), - SYS_FCNTL => unimplemented("fcntl", Ok(0)), - SYS_FLOCK => unimplemented("flock", Ok(0)), - SYS_FSYNC => sys_fsync(args[0]), - SYS_FDATASYNC => sys_fdatasync(args[0]), - SYS_TRUNCATE => sys_truncate(args[0] as *const u8, args[1]), - SYS_FTRUNCATE => sys_ftruncate(args[0], args[1]), - SYS_GETDENTS64 => sys_getdents64(args[0], args[1] as *mut LinuxDirent64, args[2]), - SYS_GETCWD => sys_getcwd(args[0] as *mut u8, args[1]), - SYS_CHDIR => sys_chdir(args[0] as *const u8), - SYS_RENAMEAT => sys_renameat(args[0], args[1] as *const u8, args[2], args[3] as *const u8), - SYS_MKDIRAT => sys_mkdirat(args[0], args[1] as *const u8, args[2]), - SYS_LINKAT => sys_linkat( - args[0], - args[1] as *const u8, - args[2], - args[3] as *const u8, - args[4], - ), - SYS_UNLINKAT => sys_unlinkat(args[0], args[1] as *const u8, args[2]), - SYS_SYMLINKAT => unimplemented("symlinkat", Err(SysError::EACCES)), - SYS_READLINKAT => { - sys_readlinkat(args[0], args[1] as *const u8, args[2] as *mut u8, args[3]) + /// System call dispatcher + // This #[deny(unreachable_patterns)] checks if each match arm is defined + // See discussion in https://github.com/oscourse-tsinghua/rcore_plus/commit/17e644e54e494835f1a49b34b80c2c4f15ed0dbe. + #[deny(unreachable_patterns)] + fn syscall(&mut self, id: usize, args: [usize; 6]) -> isize { + #[cfg(feature = "profile")] + let begin_time = unsafe { core::arch::x86_64::_rdtsc() }; + let cid = cpu::id(); + let pid = self.process().pid.clone(); + let tid = processor().tid(); + if !pid.is_init() { + // we trust pid 0 process + debug!("{}:{}:{} syscall id {} begin", cid, pid, tid, id); } - SYS_FCHMOD => unimplemented("fchmod", Ok(0)), - SYS_FCHMODAT => unimplemented("fchmodat", Ok(0)), - SYS_FCHOWN => unimplemented("fchown", Ok(0)), - SYS_FCHOWNAT => unimplemented("fchownat", Ok(0)), - SYS_FACCESSAT => sys_faccessat(args[0], args[1] as *const u8, args[2], args[3]), - SYS_DUP3 => sys_dup2(args[0], args[1]), // TODO: handle `flags` - SYS_PIPE2 => sys_pipe(args[0] as *mut u32), // TODO: handle `flags` - SYS_UTIMENSAT => unimplemented("utimensat", Ok(0)), - - // io multiplexing - SYS_PPOLL => sys_ppoll(args[0] as *mut PollFd, args[1], args[2] as *const TimeSpec), // ignore sigmask - SYS_EPOLL_CREATE1 => unimplemented("epoll_create1", Err(SysError::ENOSYS)), - - // file system - SYS_STATFS => unimplemented("statfs", Err(SysError::EACCES)), - SYS_FSTATFS => unimplemented("fstatfs", Err(SysError::EACCES)), - SYS_SYNC => sys_sync(), - SYS_MOUNT => unimplemented("mount", Err(SysError::EACCES)), - SYS_UMOUNT2 => unimplemented("umount2", Err(SysError::EACCES)), - - // memory - SYS_BRK => unimplemented("brk", Err(SysError::ENOMEM)), - SYS_MMAP => sys_mmap(args[0], args[1], args[2], args[3], args[4], args[5]), - SYS_MPROTECT => sys_mprotect(args[0], args[1], args[2]), - SYS_MUNMAP => sys_munmap(args[0], args[1]), - SYS_MADVISE => unimplemented("madvise", Ok(0)), - - // signal - SYS_RT_SIGACTION => unimplemented("sigaction", Ok(0)), - SYS_RT_SIGPROCMASK => unimplemented("sigprocmask", Ok(0)), - SYS_SIGALTSTACK => unimplemented("sigaltstack", Ok(0)), - SYS_KILL => sys_kill(args[0], args[1]), - - // schedule - SYS_SCHED_YIELD => sys_yield(), - SYS_SCHED_GETAFFINITY => sys_sched_getaffinity(args[0], args[1], args[2] as *mut u32), - - // socket - SYS_SOCKET => sys_socket(args[0], args[1], args[2]), - SYS_CONNECT => sys_connect(args[0], args[1] as *const SockAddr, args[2]), - SYS_ACCEPT => sys_accept(args[0], args[1] as *mut SockAddr, args[2] as *mut u32), - SYS_ACCEPT4 => sys_accept(args[0], args[1] as *mut SockAddr, args[2] as *mut u32), // use accept for accept4 - SYS_SENDTO => sys_sendto( - args[0], - args[1] as *const u8, - args[2], - args[3], - args[4] as *const SockAddr, - args[5], - ), - SYS_RECVFROM => sys_recvfrom( - args[0], - args[1] as *mut u8, - args[2], - args[3], - args[4] as *mut SockAddr, - args[5] as *mut u32, - ), - // SYS_SENDMSG => sys_sendmsg(), - SYS_RECVMSG => sys_recvmsg(args[0], args[1] as *mut MsgHdr, args[2]), - SYS_SHUTDOWN => sys_shutdown(args[0], args[1]), - SYS_BIND => sys_bind(args[0], args[1] as *const SockAddr, args[2]), - SYS_LISTEN => sys_listen(args[0], args[1]), - SYS_GETSOCKNAME => sys_getsockname(args[0], args[1] as *mut SockAddr, args[2] as *mut u32), - SYS_GETPEERNAME => sys_getpeername(args[0], args[1] as *mut SockAddr, args[2] as *mut u32), - SYS_SETSOCKOPT => sys_setsockopt(args[0], args[1], args[2], args[3] as *const u8, args[4]), - SYS_GETSOCKOPT => sys_getsockopt( - args[0], - args[1], - args[2], - args[3] as *mut u8, - args[4] as *mut u32, - ), - - // process - SYS_CLONE => sys_clone( - args[0], - args[1], - args[2] as *mut u32, - args[3] as *mut u32, - args[4], - tf, - ), - SYS_EXECVE => sys_exec( - args[0] as *const u8, - args[1] as *const *const u8, - args[2] as *const *const u8, - tf, - ), - SYS_EXIT => sys_exit(args[0] as usize), - SYS_EXIT_GROUP => sys_exit_group(args[0]), - SYS_WAIT4 => sys_wait4(args[0] as isize, args[1] as *mut i32), // TODO: wait4 - SYS_SET_TID_ADDRESS => sys_set_tid_address(args[0] as *mut u32), - SYS_FUTEX => sys_futex( - args[0], - args[1] as u32, - args[2] as i32, - args[3] as *const TimeSpec, - ), - - // time - SYS_NANOSLEEP => sys_nanosleep(args[0] as *const TimeSpec), - SYS_SETITIMER => unimplemented("setitimer", Ok(0)), - SYS_GETTIMEOFDAY => sys_gettimeofday(args[0] as *mut TimeVal, args[1] as *const u8), - SYS_CLOCK_GETTIME => sys_clock_gettime(args[0], args[1] as *mut TimeSpec), - - // system - SYS_GETPID => sys_getpid(), - SYS_GETTID => sys_gettid(), - SYS_UNAME => sys_uname(args[0] as *mut u8), - SYS_UMASK => unimplemented("umask", Ok(0o777)), - // SYS_GETRLIMIT => sys_getrlimit(), - // SYS_SETRLIMIT => sys_setrlimit(), - SYS_GETRUSAGE => sys_getrusage(args[0], args[1] as *mut RUsage), - SYS_SYSINFO => sys_sysinfo(args[0] as *mut SysInfo), - SYS_TIMES => sys_times(args[0] as *mut Tms), - SYS_GETUID => unimplemented("getuid", Ok(0)), - SYS_GETGID => unimplemented("getgid", Ok(0)), - SYS_SETUID => unimplemented("setuid", Ok(0)), - SYS_GETEUID => unimplemented("geteuid", Ok(0)), - SYS_GETEGID => unimplemented("getegid", Ok(0)), - SYS_SETPGID => unimplemented("setpgid", Ok(0)), - SYS_GETPPID => sys_getppid(), - SYS_SETSID => unimplemented("setsid", Ok(0)), - SYS_GETPGID => unimplemented("getpgid", Ok(0)), - SYS_GETGROUPS => unimplemented("getgroups", Ok(0)), - SYS_SETGROUPS => unimplemented("setgroups", Ok(0)), - SYS_SETPRIORITY => sys_set_priority(args[0]), - SYS_PRCTL => unimplemented("prctl", Ok(0)), - SYS_PRLIMIT64 => sys_prlimit64( - args[0], - args[1], - args[2] as *const RLimit, - args[3] as *mut RLimit, - ), - SYS_REBOOT => sys_reboot( - args[0] as u32, - args[1] as u32, - args[2] as u32, - args[3] as *const u8, - ), - - // custom - SYS_MAP_PCI_DEVICE => sys_map_pci_device(args[0], args[1]), - SYS_GET_PADDR => sys_get_paddr(args[0] as *const u64, args[1] as *mut u64, args[2]), - //SYS_GETRANDOM => unimplemented("getrandom", Err(SysError::EINVAL)), - SYS_GETRANDOM => sys_getrandom(args[0] as *mut u8, args[1] as usize, args[2] as u32), - SYS_TKILL => unimplemented("tkill", Ok(0)), - _ => { - let ret = match () { - #[cfg(target_arch = "x86_64")] - () => x86_64_syscall(id, args, tf), - #[cfg(target_arch = "mips")] - () => mips_syscall(id, args, tf), - #[cfg(all(not(target_arch = "x86_64"), not(target_arch = "mips")))] - () => None, - }; - if let Some(ret) = ret { - ret - } else { - error!("unknown syscall id: {}, args: {:x?}", id, args); - crate::trap::error(tf); + + // use platform-specific syscal numbers + // See https://filippo.io/linux-syscall-table/ + // And https://fedora.juszkiewicz.com.pl/syscalls.html. + let ret = match id { + // file + SYS_READ => self.sys_read(args[0], args[1] as *mut u8, args[2]), + SYS_WRITE => self.sys_write(args[0], args[1] as *const u8, args[2]), + SYS_OPENAT => self.sys_openat(args[0], args[1] as *const u8, args[2], args[3]), + SYS_CLOSE => self.sys_close(args[0]), + SYS_FSTAT => self.sys_fstat(args[0], args[1] as *mut Stat), + SYS_NEWFSTATAT => self.sys_fstatat(args[0], args[1] as *const u8, args[2] as *mut Stat, args[3]), + SYS_LSEEK => self.sys_lseek(args[0], args[1] as i64, args[2] as u8), + SYS_IOCTL => self.sys_ioctl(args[0], args[1], args[2], args[3], args[4]), + SYS_PREAD64 => self.sys_pread(args[0], args[1] as *mut u8, args[2], args[3]), + SYS_PWRITE64 => self.sys_pwrite(args[0], args[1] as *const u8, args[2], args[3]), + SYS_READV => self.sys_readv(args[0], args[1] as *const IoVec, args[2]), + SYS_WRITEV => self.sys_writev(args[0], args[1] as *const IoVec, args[2]), + SYS_SENDFILE => self.sys_sendfile(args[0], args[1], args[2] as *mut usize, args[3]), + SYS_FCNTL => self.unimplemented("fcntl", Ok(0)), + SYS_FLOCK => self.unimplemented("flock", Ok(0)), + SYS_FSYNC => self.sys_fsync(args[0]), + SYS_FDATASYNC => self.sys_fdatasync(args[0]), + SYS_TRUNCATE => self.sys_truncate(args[0] as *const u8, args[1]), + SYS_FTRUNCATE => self.sys_ftruncate(args[0], args[1]), + SYS_GETDENTS64 => self.sys_getdents64(args[0], args[1] as *mut LinuxDirent64, args[2]), + SYS_GETCWD => self.sys_getcwd(args[0] as *mut u8, args[1]), + SYS_CHDIR => self.sys_chdir(args[0] as *const u8), + SYS_RENAMEAT => self.sys_renameat(args[0], args[1] as *const u8, args[2], args[3] as *const u8), + SYS_MKDIRAT => self.sys_mkdirat(args[0], args[1] as *const u8, args[2]), + SYS_LINKAT => self.sys_linkat( + args[0], + args[1] as *const u8, + args[2], + args[3] as *const u8, + args[4], + ), + SYS_UNLINKAT => self.sys_unlinkat(args[0], args[1] as *const u8, args[2]), + SYS_SYMLINKAT => self.unimplemented("symlinkat", Err(SysError::EACCES)), + SYS_READLINKAT => { + self.sys_readlinkat(args[0], args[1] as *const u8, args[2] as *mut u8, args[3]) + } + SYS_FCHMOD => self.unimplemented("fchmod", Ok(0)), + SYS_FCHMODAT => self.unimplemented("fchmodat", Ok(0)), + SYS_FCHOWN => self.unimplemented("fchown", Ok(0)), + SYS_FCHOWNAT => self.unimplemented("fchownat", Ok(0)), + SYS_FACCESSAT => self.sys_faccessat(args[0], args[1] as *const u8, args[2], args[3]), + SYS_DUP3 => self.sys_dup2(args[0], args[1]), // TODO: handle `flags` + SYS_PIPE2 => self.sys_pipe(args[0] as *mut u32), // TODO: handle `flags` + SYS_UTIMENSAT => self.unimplemented("utimensat", Ok(0)), + + // io multiplexing + SYS_PPOLL => self.sys_ppoll(args[0] as *mut PollFd, args[1], args[2] as *const TimeSpec), // ignore sigmask + SYS_EPOLL_CREATE1 => self.unimplemented("epoll_create1", Err(SysError::ENOSYS)), + + // file system + SYS_STATFS => self.unimplemented("statfs", Err(SysError::EACCES)), + SYS_FSTATFS => self.unimplemented("fstatfs", Err(SysError::EACCES)), + SYS_SYNC => self.sys_sync(), + SYS_MOUNT => self.unimplemented("mount", Err(SysError::EACCES)), + SYS_UMOUNT2 => self.unimplemented("umount2", Err(SysError::EACCES)), + + // memory + SYS_BRK => self.unimplemented("brk", Err(SysError::ENOMEM)), + SYS_MMAP => self.sys_mmap(args[0], args[1], args[2], args[3], args[4], args[5]), + SYS_MPROTECT => self.sys_mprotect(args[0], args[1], args[2]), + SYS_MUNMAP => self.sys_munmap(args[0], args[1]), + SYS_MADVISE => self.unimplemented("madvise", Ok(0)), + + // signal + SYS_RT_SIGACTION => self.unimplemented("sigaction", Ok(0)), + SYS_RT_SIGPROCMASK => self.unimplemented("sigprocmask", Ok(0)), + SYS_SIGALTSTACK => self.unimplemented("sigaltstack", Ok(0)), + SYS_KILL => self.sys_kill(args[0], args[1]), + + // schedule + SYS_SCHED_YIELD => self.sys_yield(), + SYS_SCHED_GETAFFINITY => self.sys_sched_getaffinity(args[0], args[1], args[2] as *mut u32), + + // socket + SYS_SOCKET => self.sys_socket(args[0], args[1], args[2]), + SYS_CONNECT => self.sys_connect(args[0], args[1] as *const SockAddr, args[2]), + SYS_ACCEPT => self.sys_accept(args[0], args[1] as *mut SockAddr, args[2] as *mut u32), + SYS_ACCEPT4 => self.sys_accept(args[0], args[1] as *mut SockAddr, args[2] as *mut u32), // use accept for accept4 + SYS_SENDTO => self.sys_sendto( + args[0], + args[1] as *const u8, + args[2], + args[3], + args[4] as *const SockAddr, + args[5], + ), + SYS_RECVFROM => self.sys_recvfrom( + args[0], + args[1] as *mut u8, + args[2], + args[3], + args[4] as *mut SockAddr, + args[5] as *mut u32, + ), + // SYS_SENDMSG => self.sys_sendmsg(), + SYS_RECVMSG => self.sys_recvmsg(args[0], args[1] as *mut MsgHdr, args[2]), + SYS_SHUTDOWN => self.sys_shutdown(args[0], args[1]), + SYS_BIND => self.sys_bind(args[0], args[1] as *const SockAddr, args[2]), + SYS_LISTEN => self.sys_listen(args[0], args[1]), + SYS_GETSOCKNAME => self.sys_getsockname(args[0], args[1] as *mut SockAddr, args[2] as *mut u32), + SYS_GETPEERNAME => self.sys_getpeername(args[0], args[1] as *mut SockAddr, args[2] as *mut u32), + SYS_SETSOCKOPT => self.sys_setsockopt(args[0], args[1], args[2], args[3] as *const u8, args[4]), + SYS_GETSOCKOPT => self.sys_getsockopt( + args[0], + args[1], + args[2], + args[3] as *mut u8, + args[4] as *mut u32, + ), + + // process + SYS_CLONE => self.sys_clone( + args[0], + args[1], + args[2] as *mut u32, + args[3] as *mut u32, + args[4], + ), + SYS_EXECVE => self.sys_exec( + args[0] as *const u8, + args[1] as *const *const u8, + args[2] as *const *const u8, + ), + SYS_EXIT => self.sys_exit(args[0] as usize), + SYS_EXIT_GROUP => self.sys_exit_group(args[0]), + SYS_WAIT4 => self.sys_wait4(args[0] as isize, args[1] as *mut i32), // TODO: wait4 + SYS_SET_TID_ADDRESS => self.sys_set_tid_address(args[0] as *mut u32), + SYS_FUTEX => self.sys_futex( + args[0], + args[1] as u32, + args[2] as i32, + args[3] as *const TimeSpec, + ), + + // time + SYS_NANOSLEEP => self.sys_nanosleep(args[0] as *const TimeSpec), + SYS_SETITIMER => self.unimplemented("setitimer", Ok(0)), + SYS_GETTIMEOFDAY => self.sys_gettimeofday(args[0] as *mut TimeVal, args[1] as *const u8), + SYS_CLOCK_GETTIME => self.sys_clock_gettime(args[0], args[1] as *mut TimeSpec), + + // system + SYS_GETPID => self.sys_getpid(), + SYS_GETTID => self.sys_gettid(), + SYS_UNAME => self.sys_uname(args[0] as *mut u8), + SYS_UMASK => self.unimplemented("umask", Ok(0o777)), + // SYS_GETRLIMIT => self.sys_getrlimit(), + // SYS_SETRLIMIT => self.sys_setrlimit(), + SYS_GETRUSAGE => self.sys_getrusage(args[0], args[1] as *mut RUsage), + SYS_SYSINFO => self.sys_sysinfo(args[0] as *mut SysInfo), + SYS_TIMES => self.sys_times(args[0] as *mut Tms), + SYS_GETUID => self.unimplemented("getuid", Ok(0)), + SYS_GETGID => self.unimplemented("getgid", Ok(0)), + SYS_SETUID => self.unimplemented("setuid", Ok(0)), + SYS_GETEUID => self.unimplemented("geteuid", Ok(0)), + SYS_GETEGID => self.unimplemented("getegid", Ok(0)), + SYS_SETPGID => self.unimplemented("setpgid", Ok(0)), + SYS_GETPPID => self.sys_getppid(), + SYS_SETSID => self.unimplemented("setsid", Ok(0)), + SYS_GETPGID => self.unimplemented("getpgid", Ok(0)), + SYS_GETGROUPS => self.unimplemented("getgroups", Ok(0)), + SYS_SETGROUPS => self.unimplemented("setgroups", Ok(0)), + SYS_SETPRIORITY => self.sys_set_priority(args[0]), + SYS_PRCTL => self.unimplemented("prctl", Ok(0)), + SYS_PRLIMIT64 => self.sys_prlimit64( + args[0], + args[1], + args[2] as *const RLimit, + args[3] as *mut RLimit, + ), + SYS_REBOOT => self.sys_reboot( + args[0] as u32, + args[1] as u32, + args[2] as u32, + args[3] as *const u8, + ), + + // custom + SYS_MAP_PCI_DEVICE => self.sys_map_pci_device(args[0], args[1]), + SYS_GET_PADDR => self.sys_get_paddr(args[0] as *const u64, args[1] as *mut u64, args[2]), + //SYS_GETRANDOM => self.unimplemented("getrandom", Err(SysError::EINVAL)), + SYS_GETRANDOM => self.sys_getrandom(args[0] as *mut u8, args[1] as usize, args[2] as u32), + SYS_TKILL => self.unimplemented("tkill", Ok(0)), + _ => { + let ret = match () { + #[cfg(target_arch = "x86_64")] + () => self.x86_64_syscall(id, args), + #[cfg(target_arch = "mips")] + () => self.mips_syscall(id, args), + #[cfg(all(not(target_arch = "x86_64"), not(target_arch = "mips")))] + () => None, + }; + if let Some(ret) = ret { + ret + } else { + error!("unknown syscall id: {}, args: {:x?}", id, args); + crate::trap::error(self.tf); + } } + }; + if !pid.is_init() { + // we trust pid 0 process + info!("=> {:x?}", ret); } - }; - if !pid.is_init() { - // we trust pid 0 process - info!("=> {:x?}", ret); - } - #[cfg(feature = "profile")] - { - let end_time = unsafe { core::arch::x86_64::_rdtsc() }; - *SYSCALL_TIMING.lock().entry(id).or_insert(0) += end_time - begin_time; - if end_time % 1000 == 0 { - let timing = SYSCALL_TIMING.lock(); - let mut count_vec: Vec<(&usize, &i64)> = timing.iter().collect(); - count_vec.sort_by(|a, b| b.1.cmp(a.1)); - for (id, time) in count_vec.iter().take(5) { - warn!("timing {:03} time {:012}", id, time); + #[cfg(feature = "profile")] + { + let end_time = unsafe { core::arch::x86_64::_rdtsc() }; + *SYSCALL_TIMING.lock().entry(id).or_insert(0) += end_time - begin_time; + if end_time % 1000 == 0 { + let timing = SYSCALL_TIMING.lock(); + let mut count_vec: Vec<(&usize, &i64)> = timing.iter().collect(); + count_vec.sort_by(|a, b| b.1.cmp(a.1)); + for (id, time) in count_vec.iter().take(5) { + warn!("timing {:03} time {:012}", id, time); + } } } + match ret { + Ok(code) => code as isize, + Err(err) => -(err as isize), + } } - match ret { - Ok(code) => code as isize, - Err(err) => -(err as isize), - } -} -fn unimplemented(name: &str, ret: SysResult) -> SysResult { - warn!("{} is unimplemented", name); - ret -} + fn unimplemented(&self, name: &str, ret: SysResult) -> SysResult { + warn!("{} is unimplemented", name); + ret + } -#[cfg(target_arch = "mips")] -fn mips_syscall(id: usize, args: [usize; 6], tf: &mut TrapFrame) -> Option { - let ret = match id { - SYS_OPEN => sys_open(args[0] as *const u8, args[1], args[2]), - SYS_POLL => sys_poll(args[0] as *mut PollFd, args[1], args[2]), - SYS_DUP2 => sys_dup2(args[0], args[1]), - SYS_FORK => sys_fork(tf), - SYS_MMAP2 => sys_mmap(args[0], args[1], args[2], args[3], args[4], args[5] * 4096), - SYS_FSTAT64 => sys_fstat(args[0], args[1] as *mut Stat), - SYS_LSTAT64 => sys_lstat(args[0] as *const u8, args[1] as *mut Stat), - SYS_STAT64 => sys_stat(args[0] as *const u8, args[1] as *mut Stat), - SYS_PIPE => { - let fd_ptr = args[0] as *mut u32; - match sys_pipe(fd_ptr) { - Ok(code) => { - unsafe { - tf.v0 = *fd_ptr as usize; - tf.v1 = *(fd_ptr.add(1)) as usize; + #[cfg(target_arch = "mips")] + fn mips_syscall(&mut self, id: usize, args: [usize; 6],) -> Option { + let ret = match id { + SYS_OPEN => self.sys_open(args[0] as *const u8, args[1], args[2]), + SYS_POLL => self.sys_poll(args[0] as *mut PollFd, args[1], args[2]), + SYS_DUP2 => self.sys_dup2(args[0], args[1]), + SYS_FORK => self.sys_fork(), + SYS_MMAP2 => self.sys_mmap(args[0], args[1], args[2], args[3], args[4], args[5] * 4096), + SYS_FSTAT64 => self.sys_fstat(args[0], args[1] as *mut Stat), + SYS_LSTAT64 => self.sys_lstat(args[0] as *const u8, args[1] as *mut Stat), + SYS_STAT64 => self.sys_stat(args[0] as *const u8, args[1] as *mut Stat), + SYS_PIPE => { + let fd_ptr = args[0] as *mut u32; + match self.sys_pipe(fd_ptr) { + Ok(code) => { + unsafe { + tf.v0 = *fd_ptr as usize; + tf.v1 = *(fd_ptr.add(1)) as usize; + } + Ok(tf.v0) } - Ok(tf.v0) + Err(err) => Err(err), } - Err(err) => Err(err), - } - } - SYS_FCNTL64 => unimplemented("fcntl64", Ok(0)), - SYS_SET_THREAD_AREA => { - info!("set_thread_area: tls: 0x{:x}", args[0]); - extern "C" { - fn _cur_tls(); } + SYS_FCNTL64 => self.unimplemented("fcntl64", Ok(0)), + SYS_SET_THREAD_AREA => { + info!("set_thread_area: tls: 0x{:x}", args[0]); + extern "C" { + fn _cur_tls(); + } - unsafe { - asm!("mtc0 $0, $$4, 2": :"r"(args[0])); - *(_cur_tls as *mut usize) = args[0]; + unsafe { + asm!("mtc0 $0, $$4, 2": :"r"(args[0])); + *(_cur_tls as *mut usize) = args[0]; + } + Ok(0) } - Ok(0) - } - _ => return None, - }; - Some(ret) -} + _ => return None, + }; + Some(ret) + } -#[cfg(target_arch = "x86_64")] -fn x86_64_syscall(id: usize, args: [usize; 6], tf: &mut TrapFrame) -> Option { - let ret = match id { - SYS_OPEN => sys_open(args[0] as *const u8, args[1], args[2]), - SYS_STAT => sys_stat(args[0] as *const u8, args[1] as *mut Stat), - SYS_LSTAT => sys_lstat(args[0] as *const u8, args[1] as *mut Stat), - SYS_POLL => sys_poll(args[0] as *mut PollFd, args[1], args[2]), - SYS_ACCESS => sys_access(args[0] as *const u8, args[1]), - SYS_PIPE => sys_pipe(args[0] as *mut u32), - SYS_SELECT => sys_select( - args[0], - args[1] as *mut u32, - args[2] as *mut u32, - args[3] as *mut u32, - args[4] as *const TimeVal, - ), - SYS_DUP2 => sys_dup2(args[0], args[1]), - SYS_ALARM => unimplemented("alarm", Ok(0)), - SYS_FORK => sys_fork(tf), - SYS_VFORK => sys_vfork(tf), - SYS_RENAME => sys_rename(args[0] as *const u8, args[1] as *const u8), - SYS_MKDIR => sys_mkdir(args[0] as *const u8, args[1]), - SYS_RMDIR => sys_rmdir(args[0] as *const u8), - SYS_LINK => sys_link(args[0] as *const u8, args[1] as *const u8), - SYS_UNLINK => sys_unlink(args[0] as *const u8), - SYS_READLINK => sys_readlink(args[0] as *const u8, args[1] as *mut u8, args[2]), - SYS_CHMOD => unimplemented("chmod", Ok(0)), - SYS_CHOWN => unimplemented("chown", Ok(0)), - SYS_ARCH_PRCTL => sys_arch_prctl(args[0] as i32, args[1], tf), - SYS_TIME => sys_time(args[0] as *mut u64), - SYS_EPOLL_CREATE => unimplemented("epoll_create", Err(SysError::ENOSYS)), - _ => return None, - }; - Some(ret) + #[cfg(target_arch = "x86_64")] + fn x86_64_syscall(&mut self, id: usize, args: [usize; 6]) -> Option { + let ret = match id { + SYS_OPEN => self.sys_open(args[0] as *const u8, args[1], args[2]), + SYS_STAT => self.sys_stat(args[0] as *const u8, args[1] as *mut Stat), + SYS_LSTAT => self.sys_lstat(args[0] as *const u8, args[1] as *mut Stat), + SYS_POLL => self.sys_poll(args[0] as *mut PollFd, args[1], args[2]), + SYS_ACCESS => self.sys_access(args[0] as *const u8, args[1]), + SYS_PIPE => self.sys_pipe(args[0] as *mut u32), + SYS_SELECT => self.sys_select( + args[0], + args[1] as *mut u32, + args[2] as *mut u32, + args[3] as *mut u32, + args[4] as *const TimeVal, + ), + SYS_DUP2 => self.sys_dup2(args[0], args[1]), + SYS_ALARM => self.unimplemented("alarm", Ok(0)), + SYS_FORK => self.sys_fork(), + SYS_VFORK => self.sys_vfork(), + SYS_RENAME => self.sys_rename(args[0] as *const u8, args[1] as *const u8), + SYS_MKDIR => self.sys_mkdir(args[0] as *const u8, args[1]), + SYS_RMDIR => self.sys_rmdir(args[0] as *const u8), + SYS_LINK => self.sys_link(args[0] as *const u8, args[1] as *const u8), + SYS_UNLINK => self.sys_unlink(args[0] as *const u8), + SYS_READLINK => self.sys_readlink(args[0] as *const u8, args[1] as *mut u8, args[2]), + SYS_CHMOD => self.unimplemented("chmod", Ok(0)), + SYS_CHOWN => self.unimplemented("chown", Ok(0)), + SYS_ARCH_PRCTL => self.sys_arch_prctl(args[0] as i32, args[1]), + SYS_TIME => self.sys_time(args[0] as *mut u64), + SYS_EPOLL_CREATE => self.unimplemented("epoll_create", Err(SysError::ENOSYS)), + _ => return None, + }; + Some(ret) + } } pub type SysResult = Result; diff --git a/kernel/src/syscall/net.rs b/kernel/src/syscall/net.rs index e7c3318..a5183a7 100644 --- a/kernel/src/syscall/net.rs +++ b/kernel/src/syscall/net.rs @@ -12,274 +12,281 @@ use alloc::boxed::Box; use core::cmp::min; use core::mem::size_of; use smoltcp::wire::*; +use crate::memory::MemorySet; + +impl Syscall<'_> { + pub fn sys_socket(&mut self, domain: usize, socket_type: usize, protocol: usize) -> SysResult { + let domain = AddressFamily::from(domain as u16); + let socket_type = SocketType::from(socket_type as u8 & SOCK_TYPE_MASK); + info!( + "socket: domain: {:?}, socket_type: {:?}, protocol: {}", + domain, socket_type, protocol + ); + let mut proc = self.process(); + let socket: Box = match domain { + AddressFamily::Internet | AddressFamily::Unix => match socket_type { + SocketType::Stream => Box::new(TcpSocketState::new()), + SocketType::Datagram => Box::new(UdpSocketState::new()), + SocketType::Raw => Box::new(RawSocketState::new(protocol as u8)), + _ => return Err(SysError::EINVAL), + }, + AddressFamily::Packet => match socket_type { + SocketType::Raw => Box::new(PacketSocketState::new()), + _ => return Err(SysError::EINVAL), + }, + AddressFamily::Netlink => match socket_type { + SocketType::Raw => Box::new(NetlinkSocketState::new()), + _ => return Err(SysError::EINVAL), + }, + _ => return Err(SysError::EAFNOSUPPORT), + }; + let fd = proc.add_file(FileLike::Socket(socket)); + Ok(fd) + } -pub fn sys_socket(domain: usize, socket_type: usize, protocol: usize) -> SysResult { - let domain = AddressFamily::from(domain as u16); - let socket_type = SocketType::from(socket_type as u8 & SOCK_TYPE_MASK); - info!( - "socket: domain: {:?}, socket_type: {:?}, protocol: {}", - domain, socket_type, protocol - ); - let mut proc = process(); - let socket: Box = match domain { - AddressFamily::Internet | AddressFamily::Unix => match socket_type { - SocketType::Stream => Box::new(TcpSocketState::new()), - SocketType::Datagram => Box::new(UdpSocketState::new()), - SocketType::Raw => Box::new(RawSocketState::new(protocol as u8)), - _ => return Err(SysError::EINVAL), - }, - AddressFamily::Packet => match socket_type { - SocketType::Raw => Box::new(PacketSocketState::new()), - _ => return Err(SysError::EINVAL), - }, - AddressFamily::Netlink => match socket_type { - SocketType::Raw => Box::new(NetlinkSocketState::new()), - _ => return Err(SysError::EINVAL), - }, - _ => return Err(SysError::EAFNOSUPPORT), - }; - let fd = proc.add_file(FileLike::Socket(socket)); - Ok(fd) -} - -pub fn sys_setsockopt( - fd: usize, - level: usize, - optname: usize, - optval: *const u8, - optlen: usize, -) -> SysResult { - info!( - "setsockopt: fd: {}, level: {}, optname: {}", - fd, level, optname - ); - let mut proc = process(); - let data = unsafe { proc.vm.check_read_array(optval, optlen)? }; - let socket = proc.get_socket(fd)?; - socket.setsockopt(level, optname, data) -} + pub fn sys_setsockopt( + &mut self, + fd: usize, + level: usize, + optname: usize, + optval: *const u8, + optlen: usize, + ) -> SysResult { + info!( + "setsockopt: fd: {}, level: {}, optname: {}", + fd, level, optname + ); + let mut proc = self.process(); + let data = unsafe { proc.vm.check_read_array(optval, optlen)? }; + let socket = proc.get_socket(fd)?; + socket.setsockopt(level, optname, data) + } -pub fn sys_getsockopt( - fd: usize, - level: usize, - optname: usize, - optval: *mut u8, - optlen: *mut u32, -) -> SysResult { - info!( - "getsockopt: fd: {}, level: {}, optname: {} optval: {:?} optlen: {:?}", - fd, level, optname, optval, optlen - ); - let proc = process(); - let optlen = unsafe { proc.vm.check_write_ptr(optlen)? }; - match level { - SOL_SOCKET => match optname { - SO_SNDBUF => { - let optval = unsafe { proc.vm.check_write_ptr(optval as *mut u32)? }; - *optval = crate::net::TCP_SENDBUF as u32; - *optlen = 4; - Ok(0) - } - SO_RCVBUF => { - let optval = unsafe { proc.vm.check_write_ptr(optval as *mut u32)? }; - *optval = crate::net::TCP_RECVBUF as u32; - *optlen = 4; - Ok(0) - } - _ => Err(SysError::ENOPROTOOPT), - }, - IPPROTO_TCP => match optname { - TCP_CONGESTION => Ok(0), + pub fn sys_getsockopt( + &mut self, + fd: usize, + level: usize, + optname: usize, + optval: *mut u8, + optlen: *mut u32, + ) -> SysResult { + info!( + "getsockopt: fd: {}, level: {}, optname: {} optval: {:?} optlen: {:?}", + fd, level, optname, optval, optlen + ); + let proc = self.process(); + let optlen = unsafe { proc.vm.check_write_ptr(optlen)? }; + match level { + SOL_SOCKET => match optname { + SO_SNDBUF => { + let optval = unsafe { proc.vm.check_write_ptr(optval as *mut u32)? }; + *optval = crate::net::TCP_SENDBUF as u32; + *optlen = 4; + Ok(0) + } + SO_RCVBUF => { + let optval = unsafe { proc.vm.check_write_ptr(optval as *mut u32)? }; + *optval = crate::net::TCP_RECVBUF as u32; + *optlen = 4; + Ok(0) + } + _ => Err(SysError::ENOPROTOOPT), + }, + IPPROTO_TCP => match optname { + TCP_CONGESTION => Ok(0), + _ => Err(SysError::ENOPROTOOPT), + }, _ => Err(SysError::ENOPROTOOPT), - }, - _ => Err(SysError::ENOPROTOOPT), + } } -} -pub fn sys_connect(fd: usize, addr: *const SockAddr, addr_len: usize) -> SysResult { - info!( - "sys_connect: fd: {}, addr: {:?}, addr_len: {}", - fd, addr, addr_len - ); - - let mut proc = process(); - let endpoint = sockaddr_to_endpoint(&mut proc, addr, addr_len)?; - let socket = proc.get_socket(fd)?; - socket.connect(endpoint)?; - Ok(0) -} + pub fn sys_connect(&mut self, fd: usize, addr: *const SockAddr, addr_len: usize) -> SysResult { + info!( + "sys_connect: fd: {}, addr: {:?}, addr_len: {}", + fd, addr, addr_len + ); + + let mut proc = self.process(); + let endpoint = sockaddr_to_endpoint(&mut proc.vm, addr, addr_len)?; + let socket = proc.get_socket(fd)?; + socket.connect(endpoint)?; + Ok(0) + } -pub fn sys_sendto( - fd: usize, - base: *const u8, - len: usize, - _flags: usize, - addr: *const SockAddr, - addr_len: usize, -) -> SysResult { - info!( - "sys_sendto: fd: {} base: {:?} len: {} addr: {:?} addr_len: {}", - fd, base, len, addr, addr_len - ); - - let mut proc = process(); - - let slice = unsafe { proc.vm.check_read_array(base, len)? }; - let endpoint = if addr.is_null() { - None - } else { - let endpoint = sockaddr_to_endpoint(&mut proc, addr, addr_len)?; - info!("sys_sendto: sending to endpoint {:?}", endpoint); - Some(endpoint) - }; - let socket = proc.get_socket(fd)?; - socket.write(&slice, endpoint) -} + pub fn sys_sendto( + &mut self, + fd: usize, + base: *const u8, + len: usize, + _flags: usize, + addr: *const SockAddr, + addr_len: usize, + ) -> SysResult { + info!( + "sys_sendto: fd: {} base: {:?} len: {} addr: {:?} addr_len: {}", + fd, base, len, addr, addr_len + ); -pub fn sys_recvfrom( - fd: usize, - base: *mut u8, - len: usize, - flags: usize, - addr: *mut SockAddr, - addr_len: *mut u32, -) -> SysResult { - info!( - "sys_recvfrom: fd: {} base: {:?} len: {} flags: {} addr: {:?} addr_len: {:?}", - fd, base, len, flags, addr, addr_len - ); - - let mut proc = process(); - - let mut slice = unsafe { proc.vm.check_write_array(base, len)? }; - let socket = proc.get_socket(fd)?; - let (result, endpoint) = socket.read(&mut slice); - - if result.is_ok() && !addr.is_null() { - let sockaddr_in = SockAddr::from(endpoint); - unsafe { - sockaddr_in.write_to(&mut proc, addr, addr_len)?; - } + let mut proc = self.process(); + + let slice = unsafe { proc.vm.check_read_array(base, len)? }; + let endpoint = if addr.is_null() { + None + } else { + let endpoint = sockaddr_to_endpoint(&mut proc.vm, addr, addr_len)?; + info!("sys_sendto: sending to endpoint {:?}", endpoint); + Some(endpoint) + }; + let socket = proc.get_socket(fd)?; + socket.write(&slice, endpoint) } - result -} + pub fn sys_recvfrom( + &mut self, + fd: usize, + base: *mut u8, + len: usize, + flags: usize, + addr: *mut SockAddr, + addr_len: *mut u32, + ) -> SysResult { + info!( + "sys_recvfrom: fd: {} base: {:?} len: {} flags: {} addr: {:?} addr_len: {:?}", + fd, base, len, flags, addr, addr_len + ); -pub fn sys_recvmsg(fd: usize, msg: *mut MsgHdr, flags: usize) -> SysResult { - info!("recvmsg: fd: {}, msg: {:?}, flags: {}", fd, msg, flags); - let mut proc = process(); - let hdr = unsafe { proc.vm.check_write_ptr(msg)? }; - let mut iovs = unsafe { IoVecs::check_and_new(hdr.msg_iov, hdr.msg_iovlen, &proc.vm, true)? }; + let mut proc = self.process(); - let mut buf = iovs.new_buf(true); - let socket = proc.get_socket(fd)?; - let (result, endpoint) = socket.read(&mut buf); + let mut slice = unsafe { proc.vm.check_write_array(base, len)? }; + let socket = proc.get_socket(fd)?; + let (result, endpoint) = socket.read(&mut slice); - if let Ok(len) = result { - // copy data to user - iovs.write_all_from_slice(&buf[..len]); - let sockaddr_in = SockAddr::from(endpoint); - unsafe { - sockaddr_in.write_to(&mut proc, hdr.msg_name, &mut hdr.msg_namelen as *mut u32)?; + if result.is_ok() && !addr.is_null() { + let sockaddr_in = SockAddr::from(endpoint); + unsafe { + sockaddr_in.write_to(&mut proc, addr, addr_len)?; + } } + + result } - result -} -pub fn sys_bind(fd: usize, addr: *const SockAddr, addr_len: usize) -> SysResult { - info!("sys_bind: fd: {} addr: {:?} len: {}", fd, addr, addr_len); - let mut proc = process(); + pub fn sys_recvmsg(&mut self, fd: usize, msg: *mut MsgHdr, flags: usize) -> SysResult { + info!("recvmsg: fd: {}, msg: {:?}, flags: {}", fd, msg, flags); + let mut proc = self.process(); + let hdr = unsafe { proc.vm.check_write_ptr(msg)? }; + let mut iovs = unsafe { IoVecs::check_and_new(hdr.msg_iov, hdr.msg_iovlen, &proc.vm, true)? }; + + let mut buf = iovs.new_buf(true); + let socket = proc.get_socket(fd)?; + let (result, endpoint) = socket.read(&mut buf); + + if let Ok(len) = result { + // copy data to user + iovs.write_all_from_slice(&buf[..len]); + let sockaddr_in = SockAddr::from(endpoint); + unsafe { + sockaddr_in.write_to(&mut proc, hdr.msg_name, &mut hdr.msg_namelen as *mut u32)?; + } + } + result + } - let mut endpoint = sockaddr_to_endpoint(&mut proc, addr, addr_len)?; - info!("sys_bind: fd: {} bind to {:?}", fd, endpoint); + pub fn sys_bind(&mut self, fd: usize, addr: *const SockAddr, addr_len: usize) -> SysResult { + info!("sys_bind: fd: {} addr: {:?} len: {}", fd, addr, addr_len); + let mut proc = self.process(); - let socket = proc.get_socket(fd)?; - socket.bind(endpoint) -} + let mut endpoint = sockaddr_to_endpoint(&mut proc.vm, addr, addr_len)?; + info!("sys_bind: fd: {} bind to {:?}", fd, endpoint); -pub fn sys_listen(fd: usize, backlog: usize) -> SysResult { - info!("sys_listen: fd: {} backlog: {}", fd, backlog); - // smoltcp tcp sockets do not support backlog - // open multiple sockets for each connection - let mut proc = process(); + let socket = proc.get_socket(fd)?; + socket.bind(endpoint) + } - let socket = proc.get_socket(fd)?; - socket.listen() -} + pub fn sys_listen(&mut self, fd: usize, backlog: usize) -> SysResult { + info!("sys_listen: fd: {} backlog: {}", fd, backlog); + // smoltcp tcp sockets do not support backlog + // open multiple sockets for each connection + let mut proc = self.process(); -pub fn sys_shutdown(fd: usize, how: usize) -> SysResult { - info!("sys_shutdown: fd: {} how: {}", fd, how); - let mut proc = process(); + let socket = proc.get_socket(fd)?; + socket.listen() + } - let socket = proc.get_socket(fd)?; - socket.shutdown() -} + pub fn sys_shutdown(&mut self, fd: usize, how: usize) -> SysResult { + info!("sys_shutdown: fd: {} how: {}", fd, how); + let mut proc = self.process(); -pub fn sys_accept(fd: usize, addr: *mut SockAddr, addr_len: *mut u32) -> SysResult { - info!( - "sys_accept: fd: {} addr: {:?} addr_len: {:?}", - fd, addr, addr_len - ); - // smoltcp tcp sockets do not support backlog - // open multiple sockets for each connection - let mut proc = process(); + let socket = proc.get_socket(fd)?; + socket.shutdown() + } - let socket = proc.get_socket(fd)?; - let (new_socket, remote_endpoint) = socket.accept()?; + pub fn sys_accept(&mut self, fd: usize, addr: *mut SockAddr, addr_len: *mut u32) -> SysResult { + info!( + "sys_accept: fd: {} addr: {:?} addr_len: {:?}", + fd, addr, addr_len + ); + // smoltcp tcp sockets do not support backlog + // open multiple sockets for each connection + let mut proc = self.process(); - let new_fd = proc.add_file(FileLike::Socket(new_socket)); + let socket = proc.get_socket(fd)?; + let (new_socket, remote_endpoint) = socket.accept()?; - if !addr.is_null() { - let sockaddr_in = SockAddr::from(remote_endpoint); - unsafe { - sockaddr_in.write_to(&mut proc, addr, addr_len)?; + let new_fd = proc.add_file(FileLike::Socket(new_socket)); + + if !addr.is_null() { + let sockaddr_in = SockAddr::from(remote_endpoint); + unsafe { + sockaddr_in.write_to(&mut proc, addr, addr_len)?; + } } + Ok(new_fd) } - Ok(new_fd) -} -pub fn sys_getsockname(fd: usize, addr: *mut SockAddr, addr_len: *mut u32) -> SysResult { - info!( - "sys_getsockname: fd: {} addr: {:?} addr_len: {:?}", - fd, addr, addr_len - ); + pub fn sys_getsockname(&mut self, fd: usize, addr: *mut SockAddr, addr_len: *mut u32) -> SysResult { + info!( + "sys_getsockname: fd: {} addr: {:?} addr_len: {:?}", + fd, addr, addr_len + ); - let mut proc = process(); + let mut proc = self.process(); - if addr.is_null() { - return Err(SysError::EINVAL); - } + if addr.is_null() { + return Err(SysError::EINVAL); + } - let socket = proc.get_socket(fd)?; - let endpoint = socket.endpoint().ok_or(SysError::EINVAL)?; - let sockaddr_in = SockAddr::from(endpoint); - unsafe { - sockaddr_in.write_to(&mut proc, addr, addr_len)?; + let socket = proc.get_socket(fd)?; + let endpoint = socket.endpoint().ok_or(SysError::EINVAL)?; + let sockaddr_in = SockAddr::from(endpoint); + unsafe { + sockaddr_in.write_to(&mut proc, addr, addr_len)?; + } + Ok(0) } - Ok(0) -} -pub fn sys_getpeername(fd: usize, addr: *mut SockAddr, addr_len: *mut u32) -> SysResult { - info!( - "sys_getpeername: fd: {} addr: {:?} addr_len: {:?}", - fd, addr, addr_len - ); + pub fn sys_getpeername(&mut self, fd: usize, addr: *mut SockAddr, addr_len: *mut u32) -> SysResult { + info!( + "sys_getpeername: fd: {} addr: {:?} addr_len: {:?}", + fd, addr, addr_len + ); - // smoltcp tcp sockets do not support backlog - // open multiple sockets for each connection - let mut proc = process(); + // smoltcp tcp sockets do not support backlog + // open multiple sockets for each connection + let mut proc = self.process(); - if addr as usize == 0 { - return Err(SysError::EINVAL); - } + if addr as usize == 0 { + return Err(SysError::EINVAL); + } - let socket = proc.get_socket(fd)?; - let remote_endpoint = socket.remote_endpoint().ok_or(SysError::EINVAL)?; - let sockaddr_in = SockAddr::from(remote_endpoint); - unsafe { - sockaddr_in.write_to(&mut proc, addr, addr_len)?; + let socket = proc.get_socket(fd)?; + let remote_endpoint = socket.remote_endpoint().ok_or(SysError::EINVAL)?; + let sockaddr_in = SockAddr::from(remote_endpoint); + unsafe { + sockaddr_in.write_to(&mut proc, addr, addr_len)?; + } + Ok(0) } - Ok(0) } impl Process { @@ -390,14 +397,14 @@ impl From for SockAddr { /// Convert sockaddr to endpoint // Check len is long enough fn sockaddr_to_endpoint( - proc: &mut Process, + vm: &MemorySet, addr: *const SockAddr, len: usize, ) -> Result { if len < size_of::() { return Err(SysError::EINVAL); } - let addr = unsafe { proc.vm.check_read_ptr(addr)? }; + let addr = unsafe { vm.check_read_ptr(addr)? }; unsafe { match AddressFamily::from(addr.family) { AddressFamily::Internet => { diff --git a/kernel/src/syscall/proc.rs b/kernel/src/syscall/proc.rs index 54e1981..56b94ee 100644 --- a/kernel/src/syscall/proc.rs +++ b/kernel/src/syscall/proc.rs @@ -3,344 +3,349 @@ use super::*; use crate::fs::INodeExt; -/// Fork the current process. Return the child's PID. -pub fn sys_fork(tf: &TrapFrame) -> SysResult { - let new_thread = current_thread().fork(tf); - let pid = new_thread.proc.lock().pid.get(); - let tid = processor().manager().add(new_thread); - processor().manager().detach(tid); - info!("fork: {} -> {}", thread::current().id(), pid); - Ok(pid) -} - -pub fn sys_vfork(tf: &TrapFrame) -> SysResult { - sys_fork(tf) -} +impl Syscall<'_> { + /// Fork the current process. Return the child's PID. + pub fn sys_fork(&mut self) -> SysResult { + let new_thread = self.thread.fork(self.tf); + let pid = new_thread.proc.lock().pid.get(); + let tid = processor().manager().add(new_thread); + processor().manager().detach(tid); + info!("fork: {} -> {}", thread::current().id(), pid); + Ok(pid) + } -/// Create a new thread in the current process. -/// The new thread's stack pointer will be set to `newsp`, -/// and thread pointer will be set to `newtls`. -/// The child tid will be stored at both `parent_tid` and `child_tid`. -/// This is partially implemented for musl only. -pub fn sys_clone( - flags: usize, - newsp: usize, - parent_tid: *mut u32, - child_tid: *mut u32, - newtls: usize, - tf: &TrapFrame, -) -> SysResult { - let clone_flags = CloneFlags::from_bits_truncate(flags); - info!( - "clone: flags: {:?} == {:#x}, newsp: {:#x}, parent_tid: {:?}, child_tid: {:?}, newtls: {:#x}", - clone_flags, flags, newsp, parent_tid, child_tid, newtls - ); - if flags == 0x4111 || flags == 0x11 { - warn!("sys_clone is calling sys_fork instead, ignoring other args"); - return sys_fork(tf); + pub fn sys_vfork(&mut self) -> SysResult { + self.sys_fork() } - if (flags != 0x7d0f00) && (flags != 0x5d0f00) { - //0x5d0f00 is the args from gcc of alpine linux - //warn!("sys_clone only support musl pthread_create"); - panic!( - "sys_clone only support sys_fork OR musl pthread_create without flags{:x}", - flags + + /// Create a new thread in the current process. + /// The new thread's stack pointer will be set to `newsp`, + /// and thread pointer will be set to `newtls`. + /// The child tid will be stored at both `parent_tid` and `child_tid`. + /// This is partially implemented for musl only. + pub fn sys_clone( + &mut self, + flags: usize, + newsp: usize, + parent_tid: *mut u32, + child_tid: *mut u32, + newtls: usize, + ) -> SysResult { + let clone_flags = CloneFlags::from_bits_truncate(flags); + info!( + "clone: flags: {:?} == {:#x}, newsp: {:#x}, parent_tid: {:?}, child_tid: {:?}, newtls: {:#x}", + clone_flags, flags, newsp, parent_tid, child_tid, newtls ); - //return Err(SysError::ENOSYS); + if flags == 0x4111 || flags == 0x11 { + warn!("sys_clone is calling sys_fork instead, ignoring other args"); + return self.sys_fork(); + } + if (flags != 0x7d0f00) && (flags != 0x5d0f00) { + //0x5d0f00 is the args from gcc of alpine linux + //warn!("sys_clone only support musl pthread_create"); + panic!( + "sys_clone only support sys_fork OR musl pthread_create without flags{:x}", + flags + ); + //return Err(SysError::ENOSYS); + } + let parent_tid_ref = unsafe { self.process().vm.check_write_ptr(parent_tid)? }; + let child_tid_ref = unsafe { self.process().vm.check_write_ptr(child_tid)? }; + let new_thread = self + .thread + .clone(self.tf, newsp, newtls, child_tid as usize); + // FIXME: parent pid + let tid = processor().manager().add(new_thread); + processor().manager().detach(tid); + info!("clone: {} -> {}", thread::current().id(), tid); + *parent_tid_ref = tid as u32; + *child_tid_ref = tid as u32; + Ok(tid) } - let parent_tid_ref = unsafe { process().vm.check_write_ptr(parent_tid)? }; - let child_tid_ref = unsafe { process().vm.check_write_ptr(child_tid)? }; - let new_thread = current_thread().clone(tf, newsp, newtls, child_tid as usize); - // FIXME: parent pid - let tid = processor().manager().add(new_thread); - processor().manager().detach(tid); - info!("clone: {} -> {}", thread::current().id(), tid); - *parent_tid_ref = tid as u32; - *child_tid_ref = tid as u32; - Ok(tid) -} -/// Wait for the process exit. -/// Return the PID. Store exit code to `wstatus` if it's not null. -pub fn sys_wait4(pid: isize, wstatus: *mut i32) -> SysResult { - //info!("wait4: pid: {}, code: {:?}", pid, wstatus); - let wstatus = if !wstatus.is_null() { - Some(unsafe { process().vm.check_write_ptr(wstatus)? }) - } else { - None - }; - #[derive(Debug)] - enum WaitFor { - AnyChild, - Pid(usize), - } - let target = match pid { - -1 | 0 => WaitFor::AnyChild, - p if p > 0 => WaitFor::Pid(p as usize), - _ => unimplemented!(), - }; - loop { - let mut proc = process(); - // check child_exit_code - let find = match target { - WaitFor::AnyChild => proc - .child_exit_code - .iter() - .next() - .map(|(&pid, &code)| (pid, code)), - WaitFor::Pid(pid) => proc.child_exit_code.get(&pid).map(|&code| (pid, code)), + /// Wait for the process exit. + /// Return the PID. Store exit code to `wstatus` if it's not null. + pub fn sys_wait4(&mut self, pid: isize, wstatus: *mut i32) -> SysResult { + //info!("wait4: pid: {}, code: {:?}", pid, wstatus); + let wstatus = if !wstatus.is_null() { + Some(unsafe { self.process().vm.check_write_ptr(wstatus)? }) + } else { + None }; - // if found, return - if let Some((pid, exit_code)) = find { - proc.child_exit_code.remove(&pid); - if let Some(wstatus) = wstatus { - *wstatus = exit_code as i32; - } - return Ok(pid); + #[derive(Debug)] + enum WaitFor { + AnyChild, + Pid(usize), } - // if not, check pid - let children: Vec<_> = proc - .children - .iter() - .filter_map(|weak| weak.upgrade()) - .collect(); - let invalid = match target { - WaitFor::AnyChild => children.len() == 0, - WaitFor::Pid(pid) => children - .iter() - .find(|p| p.lock().pid.get() == pid) - .is_none(), + let target = match pid { + -1 | 0 => WaitFor::AnyChild, + p if p > 0 => WaitFor::Pid(p as usize), + _ => unimplemented!(), }; - if invalid { - return Err(SysError::ECHILD); + loop { + let mut proc = self.process(); + // check child_exit_code + let find = match target { + WaitFor::AnyChild => proc + .child_exit_code + .iter() + .next() + .map(|(&pid, &code)| (pid, code)), + WaitFor::Pid(pid) => proc.child_exit_code.get(&pid).map(|&code| (pid, code)), + }; + // if found, return + if let Some((pid, exit_code)) = find { + proc.child_exit_code.remove(&pid); + if let Some(wstatus) = wstatus { + *wstatus = exit_code as i32; + } + return Ok(pid); + } + // if not, check pid + let children: Vec<_> = proc + .children + .iter() + .filter_map(|weak| weak.upgrade()) + .collect(); + let invalid = match target { + WaitFor::AnyChild => children.len() == 0, + WaitFor::Pid(pid) => children + .iter() + .find(|p| p.lock().pid.get() == pid) + .is_none(), + }; + if invalid { + return Err(SysError::ECHILD); + } + info!( + "wait: thread {} -> {:?}, sleep", + thread::current().id(), + target + ); + let condvar = proc.child_exit.clone(); + condvar.wait(proc); } + } + + /// Replaces the current ** process ** with a new process image + /// + /// `argv` is an array of argument strings passed to the new program. + /// `envp` is an array of strings, conventionally of the form `key=value`, + /// which are passed as environment to the new program. + /// + /// NOTICE: `argv` & `envp` can not be NULL (different from Linux) + /// + /// NOTICE: for multi-thread programs + /// A call to any exec function from a process with more than one thread + /// shall result in all threads being terminated and the new executable image + /// being loaded and executed. + pub fn sys_exec( + &mut self, + path: *const u8, + argv: *const *const u8, + envp: *const *const u8, + ) -> SysResult { info!( - "wait: thread {} -> {:?}, sleep", - thread::current().id(), - target + "exec:BEG: path: {:?}, argv: {:?}, envp: {:?}", + path, argv, envp ); - let condvar = proc.child_exit.clone(); - condvar.wait(proc); - } -} + let mut proc = self.process(); + let path = unsafe { proc.vm.check_and_clone_cstr(path)? }; + let args = unsafe { proc.vm.check_and_clone_cstr_array(argv)? }; + let envs = unsafe { proc.vm.check_and_clone_cstr_array(envp)? }; + + if args.is_empty() { + error!("exec: args is null"); + return Err(SysError::EINVAL); + } -/// Replaces the current ** process ** with a new process image -/// -/// `argv` is an array of argument strings passed to the new program. -/// `envp` is an array of strings, conventionally of the form `key=value`, -/// which are passed as environment to the new program. -/// -/// NOTICE: `argv` & `envp` can not be NULL (different from Linux) -/// -/// NOTICE: for multi-thread programs -/// A call to any exec function from a process with more than one thread -/// shall result in all threads being terminated and the new executable image -/// being loaded and executed. -pub fn sys_exec( - path: *const u8, - argv: *const *const u8, - envp: *const *const u8, - tf: &mut TrapFrame, -) -> SysResult { - info!( - "exec:BEG: path: {:?}, argv: {:?}, envp: {:?}", - path, argv, envp - ); - let mut proc = process(); - let path = unsafe { proc.vm.check_and_clone_cstr(path)? }; - let args = unsafe { proc.vm.check_and_clone_cstr_array(argv)? }; - let envs = unsafe { proc.vm.check_and_clone_cstr_array(envp)? }; - - if args.is_empty() { - error!("exec: args is null"); - return Err(SysError::EINVAL); - } + info!( + "exec:STEP2: path: {:?}, args: {:?}, envs: {:?}", + path, args, envs + ); + + // Kill other threads + proc.threads.retain(|&tid| { + if tid != processor().tid() { + processor().manager().exit(tid, 1); + } + tid == processor().tid() + }); - info!( - "exec:STEP2: path: {:?}, args: {:?}, envs: {:?}", - path, args, envs - ); + // Read program file + let inode = proc.lookup_inode(&path)?; - // Kill other threads - proc.threads.retain(|&tid| { - if tid != processor().tid() { - processor().manager().exit(tid, 1); + // Make new Thread + let (mut vm, entry_addr, ustack_top) = + Thread::new_user_vm(&inode, &path, args, envs).map_err(|_| SysError::EINVAL)?; + + // Activate new page table + core::mem::swap(&mut proc.vm, &mut vm); + unsafe { + proc.vm.activate(); } - tid == processor().tid() - }); - // Read program file - let inode = proc.lookup_inode(&path)?; + // Modify exec path + proc.exec_path = path.clone(); + drop(proc); - // Make new Thread - let (mut vm, entry_addr, ustack_top) = - Thread::new_user_vm(&inode, &path, args, envs).map_err(|_| SysError::EINVAL)?; + // Modify the TrapFrame + *self.tf = TrapFrame::new_user_thread(entry_addr, ustack_top); - // Activate new page table - core::mem::swap(&mut proc.vm, &mut vm); - unsafe { - proc.vm.activate(); + info!("exec:END: path: {:?}", path); + Ok(0) } - // Modify exec path - proc.exec_path = path.clone(); + pub fn sys_yield(&mut self) -> SysResult { + thread::yield_now(); + Ok(0) + } - // Modify the TrapFrame - *tf = TrapFrame::new_user_thread(entry_addr, ustack_top); + /// Kill the process + pub fn sys_kill(&mut self, pid: usize, sig: usize) -> SysResult { + info!( + "kill: {} killed: {} with sig {}", + thread::current().id(), + pid, + sig + ); + let current_pid = self.process().pid.get().clone(); + if current_pid == pid { + // killing myself + self.sys_exit_group(sig); + } else { + if let Some(proc_arc) = PROCESSES.read().get(&pid).and_then(|weak| weak.upgrade()) { + let proc = proc_arc.lock(); + // quit all threads + for tid in proc.threads.iter() { + processor().manager().exit(*tid, sig); + } + // notify parent and fill exit code + // avoid deadlock + let proc_parent = proc.parent.clone(); + let pid = proc.pid.get(); + drop(proc); + if let Some(parent) = proc_parent { + let mut parent = parent.lock(); + parent.child_exit_code.insert(pid, sig); + parent.child_exit.notify_one(); + } + Ok(0) + } else { + Err(SysError::EINVAL) + } + } + } - info!("exec:END: path: {:?}", path); - Ok(0) -} + /// Get the current process id + pub fn sys_getpid(&mut self) -> SysResult { + info!("getpid"); + Ok(self.process().pid.get()) + } -pub fn sys_yield() -> SysResult { - thread::yield_now(); - Ok(0) -} + /// Get the current thread id + pub fn sys_gettid(&mut self) -> SysResult { + info!("gettid"); + // use pid as tid for now + Ok(thread::current().id()) + } -/// Kill the process -pub fn sys_kill(pid: usize, sig: usize) -> SysResult { - info!( - "kill: {} killed: {} with sig {}", - thread::current().id(), - pid, - sig - ); - let current_pid = process().pid.get().clone(); - if current_pid == pid { - // killing myself - sys_exit_group(sig); - } else { - if let Some(proc_arc) = PROCESSES.read().get(&pid).and_then(|weak| weak.upgrade()) { - let proc = proc_arc.lock(); - // quit all threads - for tid in proc.threads.iter() { - processor().manager().exit(*tid, sig); - } - // notify parent and fill exit code - // avoid deadlock - let proc_parent = proc.parent.clone(); - let pid = proc.pid.get(); - drop(proc); + /// Get the parent process id + pub fn sys_getppid(&mut self) -> SysResult { + if let Some(parent) = self.process().parent.as_ref() { + Ok(parent.lock().pid.get()) + } else { + Ok(0) + } + } + + /// Exit the current thread + pub fn sys_exit(&mut self, exit_code: usize) -> ! { + let tid = thread::current().id(); + info!("exit: {}, code: {}", tid, exit_code); + let mut proc = self.process(); + proc.threads.retain(|&id| id != tid); + + // for last thread, + // notify parent and fill exit code + // avoid deadlock + let exit = proc.threads.len() == 0; + let proc_parent = proc.parent.clone(); + let pid = proc.pid.get(); + drop(proc); + if exit { if let Some(parent) = proc_parent { let mut parent = parent.lock(); - parent.child_exit_code.insert(pid, sig); + parent.child_exit_code.insert(pid, exit_code); parent.child_exit.notify_one(); } - Ok(0) - } else { - Err(SysError::EINVAL) } - } -} -/// Get the current process id -pub fn sys_getpid() -> SysResult { - info!("getpid"); - Ok(process().pid.get()) -} - -/// Get the current thread id -pub fn sys_gettid() -> SysResult { - info!("gettid"); - // use pid as tid for now - Ok(thread::current().id()) -} + // perform futex wake 1 + // ref: http://man7.org/linux/man-pages/man2/set_tid_address.2.html + // FIXME: do it in all possible ways a thread can exit + // it has memory access so we can't move it to Thread::drop? + let mut proc = self.process(); + let clear_child_tid = self.thread.clear_child_tid as *mut u32; + if !clear_child_tid.is_null() { + info!("exit: futex {:#?} wake 1", clear_child_tid); + if let Ok(clear_child_tid_ref) = unsafe { proc.vm.check_write_ptr(clear_child_tid) } { + *clear_child_tid_ref = 0; + let queue = proc.get_futex(clear_child_tid as usize); + queue.notify_one(); + } + } + drop(proc); -/// Get the parent process id -pub fn sys_getppid() -> SysResult { - if let Some(ref parent) = process().parent.as_ref() { - Ok(parent.lock().pid.get()) - } else { - Ok(0) + processor().manager().exit(tid, exit_code as usize); + processor().yield_now(); + unreachable!(); } -} -/// Exit the current thread -pub fn sys_exit(exit_code: usize) -> ! { - let tid = thread::current().id(); - info!("exit: {}, code: {}", tid, exit_code); - let mut proc = process(); - proc.threads.retain(|&id| id != tid); - - // for last thread, - // notify parent and fill exit code - // avoid deadlock - let exit = proc.threads.len() == 0; - let proc_parent = proc.parent.clone(); - let pid = proc.pid.get(); - drop(proc); - if exit { + /// Exit the current thread group (i.e. process) + pub fn sys_exit_group(&mut self, exit_code: usize) -> ! { + let proc = self.process(); + info!("exit_group: {}, code: {}", proc.pid, exit_code); + + // quit all threads + for tid in proc.threads.iter() { + processor().manager().exit(*tid, exit_code); + } + + // notify parent and fill exit code + // avoid deadlock + let proc_parent = proc.parent.clone(); + let pid = proc.pid.get(); + drop(proc); if let Some(parent) = proc_parent { let mut parent = parent.lock(); parent.child_exit_code.insert(pid, exit_code); parent.child_exit.notify_one(); } - } - // perform futex wake 1 - // ref: http://man7.org/linux/man-pages/man2/set_tid_address.2.html - // FIXME: do it in all possible ways a thread can exit - // it has memory access so we can't move it to Thread::drop? - let mut proc = process(); - let clear_child_tid = current_thread().clear_child_tid as *mut u32; - if !clear_child_tid.is_null() { - info!("exit: futex {:#?} wake 1", clear_child_tid); - if let Ok(clear_child_tid_ref) = unsafe { proc.vm.check_write_ptr(clear_child_tid) } { - *clear_child_tid_ref = 0; - let queue = proc.get_futex(clear_child_tid as usize); - queue.notify_one(); - } + processor().yield_now(); + unreachable!(); } - drop(proc); - - processor().manager().exit(tid, exit_code as usize); - processor().yield_now(); - unreachable!(); -} - -/// Exit the current thread group (i.e. process) -pub fn sys_exit_group(exit_code: usize) -> ! { - let proc = process(); - info!("exit_group: {}, code: {}", proc.pid, exit_code); - // quit all threads - for tid in proc.threads.iter() { - processor().manager().exit(*tid, exit_code); + pub fn sys_nanosleep(&mut self, req: *const TimeSpec) -> SysResult { + let time = unsafe { *self.process().vm.check_read_ptr(req)? }; + info!("nanosleep: time: {:#?}", time); + // TODO: handle spurious wakeup + thread::sleep(time.to_duration()); + Ok(0) } - // notify parent and fill exit code - // avoid deadlock - let proc_parent = proc.parent.clone(); - let pid = proc.pid.get(); - drop(proc); - if let Some(parent) = proc_parent { - let mut parent = parent.lock(); - parent.child_exit_code.insert(pid, exit_code); - parent.child_exit.notify_one(); + pub fn sys_set_priority(&mut self, priority: usize) -> SysResult { + let pid = thread::current().id(); + processor().manager().set_priority(pid, priority as u8); + Ok(0) } - processor().yield_now(); - unreachable!(); -} - -pub fn sys_nanosleep(req: *const TimeSpec) -> SysResult { - let time = unsafe { *process().vm.check_read_ptr(req)? }; - info!("nanosleep: time: {:#?}", time); - // TODO: handle spurious wakeup - thread::sleep(time.to_duration()); - 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) -} - -pub fn sys_set_tid_address(tidptr: *mut u32) -> SysResult { - info!("set_tid_address: {:?}", tidptr); - current_thread().clear_child_tid = tidptr as usize; - Ok(thread::current().id()) + pub fn sys_set_tid_address(&mut self, tidptr: *mut u32) -> SysResult { + info!("set_tid_address: {:?}", tidptr); + self.thread.clear_child_tid = tidptr as usize; + Ok(thread::current().id()) + } } bitflags! { diff --git a/kernel/src/syscall/time.rs b/kernel/src/syscall/time.rs index 0fc3f39..4b99eeb 100644 --- a/kernel/src/syscall/time.rs +++ b/kernel/src/syscall/time.rs @@ -5,6 +5,85 @@ use crate::consts::USEC_PER_TICK; use core::time::Duration; use lazy_static::lazy_static; +impl Syscall<'_> { + pub fn sys_gettimeofday(&mut self, tv: *mut TimeVal, tz: *const u8) -> SysResult { + info!("gettimeofday: tv: {:?}, tz: {:?}", tv, tz); + if tz as usize != 0 { + return Err(SysError::EINVAL); + } + + let proc = self.process(); + let tv = unsafe { proc.vm.check_write_ptr(tv)? }; + + let timeval = TimeVal::get_epoch(); + *tv = timeval; + Ok(0) + } + + pub fn sys_clock_gettime(&mut self, clock: usize, ts: *mut TimeSpec) -> SysResult { + info!("clock_gettime: clock: {:?}, ts: {:?}", clock, ts); + + let proc = self.process(); + let ts = unsafe { proc.vm.check_write_ptr(ts)? }; + + let timespec = TimeSpec::get_epoch(); + *ts = timespec; + Ok(0) + } + + pub fn sys_time(&mut self, time: *mut u64) -> SysResult { + let sec = get_epoch_usec() / USEC_PER_SEC; + if time as usize != 0 { + let proc = self.process(); + let time = unsafe { proc.vm.check_write_ptr(time)? }; + *time = sec as u64; + } + Ok(sec as usize) + } + + pub fn sys_getrusage(&mut self, who: usize, rusage: *mut RUsage) -> SysResult { + info!("getrusage: who: {}, rusage: {:?}", who, rusage); + let proc = self.process(); + let rusage = unsafe { proc.vm.check_write_ptr(rusage)? }; + + let tick_base = *TICK_BASE; + let tick = unsafe { crate::trap::TICK as u64 }; + + let usec = (tick - tick_base) * USEC_PER_TICK as u64; + let new_rusage = RUsage { + utime: TimeVal { + sec: (usec / USEC_PER_SEC) as usize, + usec: (usec % USEC_PER_SEC) as usize, + }, + stime: TimeVal { + sec: (usec / USEC_PER_SEC) as usize, + usec: (usec % USEC_PER_SEC) as usize, + }, + }; + *rusage = new_rusage; + Ok(0) + } + + pub fn sys_times(&mut self, buf: *mut Tms) -> SysResult { + info!("times: buf: {:?}", buf); + let proc = self.process(); + let buf = unsafe { proc.vm.check_write_ptr(buf)? }; + + let tick_base = *TICK_BASE; + let tick = unsafe { crate::trap::TICK as u64 }; + + let new_buf = Tms { + tms_utime: 0, + tms_stime: 0, + tms_cutime: 0, + tms_cstime: 0, + }; + + *buf = new_buf; + Ok(tick as usize) + } +} + /// should be initialized together lazy_static! { pub static ref EPOCH_BASE: u64 = crate::arch::timer::read_epoch(); @@ -76,41 +155,6 @@ impl TimeSpec { } } -pub fn sys_gettimeofday(tv: *mut TimeVal, tz: *const u8) -> SysResult { - info!("gettimeofday: tv: {:?}, tz: {:?}", tv, tz); - if tz as usize != 0 { - return Err(SysError::EINVAL); - } - - let proc = process(); - let tv = unsafe { proc.vm.check_write_ptr(tv)? }; - - let timeval = TimeVal::get_epoch(); - *tv = timeval; - Ok(0) -} - -pub fn sys_clock_gettime(clock: usize, ts: *mut TimeSpec) -> SysResult { - info!("clock_gettime: clock: {:?}, ts: {:?}", clock, ts); - - let proc = process(); - let ts = unsafe { proc.vm.check_write_ptr(ts)? }; - - let timespec = TimeSpec::get_epoch(); - *ts = timespec; - Ok(0) -} - -pub fn sys_time(time: *mut u64) -> SysResult { - let sec = get_epoch_usec() / USEC_PER_SEC; - if time as usize != 0 { - let proc = process(); - let time = unsafe { proc.vm.check_write_ptr(time)? }; - *time = sec as u64; - } - Ok(sec as usize) -} - // ignore other fields for now #[repr(C)] pub struct RUsage { @@ -118,29 +162,6 @@ pub struct RUsage { stime: TimeVal, } -pub fn sys_getrusage(who: usize, rusage: *mut RUsage) -> SysResult { - info!("getrusage: who: {}, rusage: {:?}", who, rusage); - let proc = process(); - let rusage = unsafe { proc.vm.check_write_ptr(rusage)? }; - - let tick_base = *TICK_BASE; - let tick = unsafe { crate::trap::TICK as u64 }; - - let usec = (tick - tick_base) * USEC_PER_TICK as u64; - let new_rusage = RUsage { - utime: TimeVal { - sec: (usec / USEC_PER_SEC) as usize, - usec: (usec % USEC_PER_SEC) as usize, - }, - stime: TimeVal { - sec: (usec / USEC_PER_SEC) as usize, - usec: (usec % USEC_PER_SEC) as usize, - }, - }; - *rusage = new_rusage; - Ok(0) -} - #[repr(C)] #[derive(Debug, Copy, Clone)] pub struct Tms { @@ -149,22 +170,3 @@ pub struct Tms { tms_cutime: u64, /* user time of children */ tms_cstime: u64, /* system time of children */ } - -pub fn sys_times(buf: *mut Tms) -> SysResult { - info!("times: buf: {:?}", buf); - let proc = process(); - let buf = unsafe { proc.vm.check_write_ptr(buf)? }; - - let tick_base = *TICK_BASE; - let tick = unsafe { crate::trap::TICK as u64 }; - - let new_buf = Tms { - tms_utime: 0, - tms_stime: 0, - tms_cutime: 0, - tms_cstime: 0, - }; - - *buf = new_buf; - Ok(tick as usize) -}