refactor syscall: move all context and functions to struct Syscall

toolchain_update
WangRunji 6 years ago
parent 08d10522ff
commit da58486be5

@ -15,7 +15,6 @@
use super::HEAP_ALLOCATOR; use super::HEAP_ALLOCATOR;
pub use crate::arch::paging::*; pub use crate::arch::paging::*;
use crate::consts::{KERNEL_OFFSET, MEMORY_OFFSET}; use crate::consts::{KERNEL_OFFSET, MEMORY_OFFSET};
use crate::process::process_unsafe;
use crate::sync::SpinNoIrqLock; use crate::sync::SpinNoIrqLock;
use alloc::boxed::Box; use alloc::boxed::Box;
use bitmap_allocator::BitAlloc; use bitmap_allocator::BitAlloc;
@ -25,6 +24,7 @@ use log::*;
pub use rcore_memory::memory_set::{handler::*, MemoryArea, MemoryAttr}; pub use rcore_memory::memory_set::{handler::*, MemoryArea, MemoryAttr};
use rcore_memory::paging::PageTable; use rcore_memory::paging::PageTable;
use rcore_memory::*; use rcore_memory::*;
use crate::process::current_thread;
pub type MemorySet = rcore_memory::memory_set::MemorySet<InactivePageTable0>; pub type MemorySet = rcore_memory::memory_set::MemorySet<InactivePageTable0>;
@ -132,8 +132,12 @@ impl Drop for KernelStack {
pub fn handle_page_fault(addr: usize) -> bool { pub fn handle_page_fault(addr: usize) -> bool {
debug!("page fault @ {:#x}", addr); debug!("page fault @ {:#x}", addr);
// This is safe as long as page fault never happens in page fault handler // FIXME: fix racing caused by force_unlock
unsafe { process_unsafe().vm.handle_page_fault(addr) } unsafe {
let thread = current_thread();
thread.proc.force_unlock();
thread.proc.lock().vm.handle_page_fault(addr)
}
} }
pub fn init_heap() { pub fn init_heap() {

@ -109,25 +109,13 @@ static PROCESSORS: [Processor; MAX_CPU_NUM] = [
// Processor::new(), Processor::new(), Processor::new(), Processor::new(), // 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 /// Get current thread
/// ///
/// FIXME: It's obviously unsafe to get &mut ! /// `Thread` is a thread-local object.
pub fn current_thread() -> &'static mut Thread { /// It is safe to call this once, and pass `&mut Thread` as a function argument.
use core::mem::transmute; pub unsafe fn current_thread() -> &'static mut Thread {
let (process, _): (&mut Thread, *const ()) = unsafe { transmute(processor().context()) }; // trick: force downcast from trait object
let (process, _): (&mut Thread, *const ()) = core::mem::transmute(processor().context());
process process
} }

@ -3,51 +3,53 @@ use super::*;
use rcore_memory::memory_set::handler::Linear; use rcore_memory::memory_set::handler::Linear;
use rcore_memory::memory_set::MemoryAttr; use rcore_memory::memory_set::MemoryAttr;
/// Allocate this PCI device to user space impl Syscall<'_> {
/// The kernel driver using the PCI device will be unloaded /// Allocate this PCI device to user space
#[cfg(target_arch = "x86_64")] /// The kernel driver using the PCI device will be unloaded
pub fn sys_map_pci_device(vendor: usize, product: usize) -> SysResult { #[cfg(target_arch = "x86_64")]
use crate::drivers::bus::pci; pub fn sys_map_pci_device(&mut self, vendor: usize, product: usize) -> SysResult {
info!( use crate::drivers::bus::pci;
"map_pci_device: vendor: {:x}, product: {:x}", info!(
vendor, product "map_pci_device: vendor: {:x}, product: {:x}",
); vendor, product
);
let tag = pci::find_device(vendor as u16, product as u16).ok_or(SysError::ENOENT)?; let tag = pci::find_device(vendor as u16, product as u16).ok_or(SysError::ENOENT)?;
if pci::detach_driver(&tag) { if pci::detach_driver(&tag) {
info!("Kernel driver detached"); info!("Kernel driver detached");
} }
// Get BAR0 memory // Get BAR0 memory
let (base, len) = pci::get_bar0_mem(tag).ok_or(SysError::ENOENT)?; let (base, len) = pci::get_bar0_mem(tag).ok_or(SysError::ENOENT)?;
let mut proc = process(); let mut proc = self.process();
let virt_addr = proc.vm.find_free_area(0, len); let virt_addr = proc.vm.find_free_area(0, len);
let attr = MemoryAttr::default().user(); let attr = MemoryAttr::default().user();
proc.vm.push( proc.vm.push(
virt_addr, virt_addr,
virt_addr + len, virt_addr + len,
attr, attr,
Linear::new(base as isize - virt_addr as isize), Linear::new(base as isize - virt_addr as isize),
"pci", "pci",
); );
Ok(virt_addr) Ok(virt_addr)
} }
#[cfg(not(target_arch = "x86_64"))] #[cfg(not(target_arch = "x86_64"))]
pub fn sys_map_pci_device(vendor: usize, product: usize) -> SysResult { pub fn sys_map_pci_device(&mut self, vendor: usize, product: usize) -> SysResult {
Err(SysError::ENOSYS) Err(SysError::ENOSYS)
} }
/// Get start physical addresses of frames /// Get start physical addresses of frames
/// mapped to a list of virtual addresses. /// mapped to a list of virtual addresses.
pub fn sys_get_paddr(vaddrs: *const u64, paddrs: *mut u64, count: usize) -> SysResult { pub fn sys_get_paddr(&mut self, vaddrs: *const u64, paddrs: *mut u64, count: usize) -> SysResult {
let mut proc = process(); let mut proc = self.process();
let vaddrs = unsafe { proc.vm.check_read_array(vaddrs, count)? }; let vaddrs = unsafe { proc.vm.check_read_array(vaddrs, count)? };
let paddrs = unsafe { proc.vm.check_write_array(paddrs, count)? }; let paddrs = unsafe { proc.vm.check_write_array(paddrs, count)? };
for i in 0..count { for i in 0..count {
let paddr = proc.vm.translate(vaddrs[i] as usize).unwrap_or(0); let paddr = proc.vm.translate(vaddrs[i] as usize).unwrap_or(0);
paddrs[i] = paddr as u64; paddrs[i] = paddr as u64;
}
Ok(0)
} }
Ok(0)
} }

File diff suppressed because it is too large Load Diff

@ -8,96 +8,98 @@ use crate::memory::GlobalFrameAlloc;
use super::*; use super::*;
pub fn sys_mmap( impl Syscall<'_> {
mut addr: usize, pub fn sys_mmap(
len: usize, &mut self,
prot: usize, mut addr: usize,
flags: usize, len: usize,
fd: usize, prot: usize,
offset: usize, flags: usize,
) -> SysResult { fd: usize,
let prot = MmapProt::from_bits_truncate(prot); offset: usize,
let flags = MmapFlags::from_bits_truncate(flags); ) -> SysResult {
info!( let prot = MmapProt::from_bits_truncate(prot);
"mmap: addr={:#x}, size={:#x}, prot={:?}, flags={:?}, fd={}, offset={:#x}", let flags = MmapFlags::from_bits_truncate(flags);
addr, len, prot, flags, fd, offset info!(
); "mmap: addr={:#x}, size={:#x}, prot={:?}, flags={:?}, fd={}, offset={:#x}",
addr, len, prot, flags, fd, offset
);
let mut proc = process(); let mut proc = self.process();
if addr == 0 { if addr == 0 {
// although NULL can be a valid address // although NULL can be a valid address
// but in C, NULL is regarded as allocation failure // but in C, NULL is regarded as allocation failure
// so just skip it // so just skip it
addr = PAGE_SIZE; addr = PAGE_SIZE;
} }
if flags.contains(MmapFlags::FIXED) { if flags.contains(MmapFlags::FIXED) {
// we have to map it to addr, so remove the old mapping first // we have to map it to addr, so remove the old mapping first
proc.vm.pop_with_split(addr, addr + len); proc.vm.pop_with_split(addr, addr + len);
} else { } else {
addr = proc.vm.find_free_area(addr, len); addr = proc.vm.find_free_area(addr, len);
} }
if flags.contains(MmapFlags::ANONYMOUS) { if flags.contains(MmapFlags::ANONYMOUS) {
if flags.contains(MmapFlags::SHARED) { if flags.contains(MmapFlags::SHARED) {
return Err(SysError::EINVAL); 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 { pub fn sys_mprotect(&mut self, addr: usize, len: usize, prot: usize) -> SysResult {
let prot = MmapProt::from_bits_truncate(prot); let prot = MmapProt::from_bits_truncate(prot);
info!( info!(
"mprotect: addr={:#x}, size={:#x}, prot={:?}", "mprotect: addr={:#x}, size={:#x}, prot={:?}",
addr, len, prot addr, len, prot
); );
let mut proc = process(); let mut proc = self.process();
let attr = prot.to_attr(); let attr = prot.to_attr();
// FIXME: properly set the attribute of the area // FIXME: properly set the attribute of the area
// now some mut ptr check is fault // now some mut ptr check is fault
let memory_area = proc let memory_area = proc
.vm .vm
.iter() .iter()
.find(|area| area.is_overlap_with(addr, addr + len)); .find(|area| area.is_overlap_with(addr, addr + len));
if memory_area.is_none() { if memory_area.is_none() {
return Err(SysError::ENOMEM); return Err(SysError::ENOMEM);
}
Ok(0)
} }
Ok(0)
}
pub fn sys_munmap(addr: usize, len: usize) -> SysResult { pub fn sys_munmap(&mut self, addr: usize, len: usize) -> SysResult {
info!("munmap addr={:#x}, size={:#x}", addr, len); info!("munmap addr={:#x}, size={:#x}", addr, len);
let mut proc = process(); let mut proc = self.process();
proc.vm.pop_with_split(addr, addr + len); proc.vm.pop_with_split(addr, addr + len);
Ok(0) Ok(0)
}
} }
bitflags! { bitflags! {
pub struct MmapProt: usize { pub struct MmapProt: usize {
/// Data cannot be accessed /// Data cannot be accessed

@ -4,119 +4,185 @@ use crate::consts::USER_STACK_SIZE;
use core::mem::size_of; use core::mem::size_of;
use core::sync::atomic::{AtomicI32, Ordering}; use core::sync::atomic::{AtomicI32, Ordering};
pub fn sys_arch_prctl(code: i32, addr: usize, tf: &mut TrapFrame) -> SysResult { impl Syscall<'_> {
const ARCH_SET_FS: i32 = 0x1002; #[cfg(target_arch = "x86_64")]
match code { pub fn sys_arch_prctl(&mut self, code: i32, addr: usize) -> SysResult {
#[cfg(target_arch = "x86_64")] const ARCH_SET_FS: i32 = 0x1002;
ARCH_SET_FS => { match code {
info!("sys_arch_prctl: set FS to {:#x}", addr); ARCH_SET_FS => {
tf.fsbase = addr; info!("sys_arch_prctl: set FSBASE to {:#x}", addr);
Ok(0) self.tf.fsbase = addr;
Ok(0)
}
_ => Err(SysError::EINVAL),
} }
_ => Err(SysError::EINVAL),
} }
}
pub fn sys_uname(buf: *mut u8) -> SysResult { pub fn sys_uname(&mut self, buf: *mut u8) -> SysResult {
info!("uname: buf: {:?}", buf); info!("uname: buf: {:?}", buf);
let offset = 65; let offset = 65;
let strings = ["rCore", "orz", "0.1.0", "1", "machine", "domain"]; let strings = ["rCore", "orz", "0.1.0", "1", "machine", "domain"];
let proc = process(); let proc = self.process();
let buf = unsafe { proc.vm.check_write_array(buf, strings.len() * offset)? }; let buf = unsafe { proc.vm.check_write_array(buf, strings.len() * offset)? };
for i in 0..strings.len() { for i in 0..strings.len() {
unsafe { unsafe {
util::write_cstr(&mut buf[i * offset], &strings[i]); 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::<u32>())? };
// 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 { pub fn sys_sched_getaffinity(&mut self, pid: usize, size: usize, mask: *mut u32) -> SysResult {
let proc = process(); info!(
let sys_info = unsafe { proc.vm.check_write_ptr(sys_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::<u32>())? };
// we only have 4 cpu at most.
// so just set it.
mask[0] = 0b1111;
Ok(0)
}
let sysinfo = SysInfo::default(); pub fn sys_sysinfo(&mut self, sys_info: *mut SysInfo) -> SysResult {
*sys_info = sysinfo; let proc = self.process();
Ok(0) 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 { let sysinfo = SysInfo::default();
info!( *sys_info = sysinfo;
"futex: [{}] uaddr: {:#x}, op: {:#x}, val: {}, timeout_ptr: {:?}", Ok(0)
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::<u32>() != 0 {
return Err(SysError::EINVAL);
} }
let atomic = unsafe { process().vm.check_write_ptr(uaddr as *mut AtomicI32)? };
let _timeout = if timeout.is_null() { pub fn sys_futex(&mut self, uaddr: usize, op: u32, val: i32, timeout: *const TimeSpec) -> SysResult {
None info!(
} else { "futex: [{}] uaddr: {:#x}, op: {:#x}, val: {}, timeout_ptr: {:?}",
Some(unsafe { *process().vm.check_read_ptr(timeout)? }) thread::current().id(),
}; uaddr,
op,
const OP_WAIT: u32 = 0; val,
const OP_WAKE: u32 = 1; timeout
const OP_PRIVATE: u32 = 128; );
// if op & OP_PRIVATE == 0 {
let queue = process().get_futex(uaddr); // unimplemented!("futex only support process-private");
// return Err(SysError::ENOSYS);
match op & 0xf { // }
OP_WAIT => { if uaddr % size_of::<u32>() != 0 {
if atomic.load(Ordering::Acquire) != val { return Err(SysError::EINVAL);
return Err(SysError::EAGAIN); }
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);
}
} }
_ => { Ok(0)
warn!("unsupported futex operation: {}", op); }
Err(SysError::ENOSYS)
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_getrandom(&mut self, buf: *mut u8, len: usize, flag: u32) -> SysResult {
pub fn sys_reboot(_magic: u32, magic2: u32, cmd: u32, _arg: *const u8) -> SysResult { //info!("getrandom: buf: {:?}, len: {:?}, falg {:?}", buf, len,flag);
// we will skip verifying magic let mut proc = self.process();
if cmd == LINUX_REBOOT_CMD_HALT { let slice = unsafe { proc.vm.check_write_array(buf, len)? };
unsafe { let mut i = 0;
cpu::exit_in_qemu(1); 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)] #[repr(C)]
#[derive(Debug, Default)] #[derive(Debug, Default)]
pub struct SysInfo { pub struct SysInfo {
@ -139,71 +205,9 @@ const RLIMIT_RSS: usize = 5;
const RLIMIT_NOFILE: usize = 7; const RLIMIT_NOFILE: usize = 7;
const RLIMIT_AS: usize = 9; 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)] #[repr(C)]
#[derive(Debug, Default)] #[derive(Debug, Default)]
pub struct RLimit { pub struct RLimit {
cur: u64, // soft limit cur: u64, // soft limit
max: u64, // hard 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)
}

@ -11,7 +11,7 @@ use crate::arch::cpu;
use crate::arch::interrupt::TrapFrame; use crate::arch::interrupt::TrapFrame;
use crate::arch::syscall::*; use crate::arch::syscall::*;
use crate::process::*; use crate::process::*;
use crate::sync::Condvar; use crate::sync::{Condvar, SpinNoIrq, MutexGuard};
use crate::thread; use crate::thread;
use crate::util; use crate::util;
@ -40,330 +40,348 @@ lazy_static! {
} }
/// System call dispatcher /// 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 { pub fn syscall(id: usize, args: [usize; 6], tf: &mut TrapFrame) -> isize {
#[cfg(feature = "profile")] let thread = unsafe { current_thread() };
let begin_time = unsafe { core::arch::x86_64::_rdtsc() }; let mut syscall = Syscall { thread, tf };
let cid = cpu::id(); syscall.syscall(id, args)
let pid = process().pid.clone(); }
let tid = processor().tid();
if !pid.is_init() { /// All context needed for syscall
// we trust pid 0 process struct Syscall<'a> {
debug!("{}:{}:{} syscall id {} begin", cid, pid, tid, id); 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 /// System call dispatcher
// See https://filippo.io/linux-syscall-table/ // This #[deny(unreachable_patterns)] checks if each match arm is defined
// And https://fedora.juszkiewicz.com.pl/syscalls.html. // See discussion in https://github.com/oscourse-tsinghua/rcore_plus/commit/17e644e54e494835f1a49b34b80c2c4f15ed0dbe.
let ret = match id { #[deny(unreachable_patterns)]
// file fn syscall(&mut self, id: usize, args: [usize; 6]) -> isize {
SYS_READ => sys_read(args[0], args[1] as *mut u8, args[2]), #[cfg(feature = "profile")]
SYS_WRITE => sys_write(args[0], args[1] as *const u8, args[2]), let begin_time = unsafe { core::arch::x86_64::_rdtsc() };
SYS_OPENAT => sys_openat(args[0], args[1] as *const u8, args[2], args[3]), let cid = cpu::id();
SYS_CLOSE => sys_close(args[0]), let pid = self.process().pid.clone();
SYS_FSTAT => sys_fstat(args[0], args[1] as *mut Stat), let tid = processor().tid();
SYS_NEWFSTATAT => sys_fstatat(args[0], args[1] as *const u8, args[2] as *mut Stat, args[3]), if !pid.is_init() {
SYS_LSEEK => sys_lseek(args[0], args[1] as i64, args[2] as u8), // we trust pid 0 process
SYS_IOCTL => sys_ioctl(args[0], args[1], args[2], args[3], args[4]), debug!("{}:{}:{} syscall id {} begin", cid, pid, tid, id);
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])
} }
SYS_FCHMOD => unimplemented("fchmod", Ok(0)),
SYS_FCHMODAT => unimplemented("fchmodat", Ok(0)), // use platform-specific syscal numbers
SYS_FCHOWN => unimplemented("fchown", Ok(0)), // See https://filippo.io/linux-syscall-table/
SYS_FCHOWNAT => unimplemented("fchownat", Ok(0)), // And https://fedora.juszkiewicz.com.pl/syscalls.html.
SYS_FACCESSAT => sys_faccessat(args[0], args[1] as *const u8, args[2], args[3]), let ret = match id {
SYS_DUP3 => sys_dup2(args[0], args[1]), // TODO: handle `flags` // file
SYS_PIPE2 => sys_pipe(args[0] as *mut u32), // TODO: handle `flags` SYS_READ => self.sys_read(args[0], args[1] as *mut u8, args[2]),
SYS_UTIMENSAT => unimplemented("utimensat", Ok(0)), 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]),
// io multiplexing SYS_CLOSE => self.sys_close(args[0]),
SYS_PPOLL => sys_ppoll(args[0] as *mut PollFd, args[1], args[2] as *const TimeSpec), // ignore sigmask SYS_FSTAT => self.sys_fstat(args[0], args[1] as *mut Stat),
SYS_EPOLL_CREATE1 => unimplemented("epoll_create1", Err(SysError::ENOSYS)), 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),
// file system SYS_IOCTL => self.sys_ioctl(args[0], args[1], args[2], args[3], args[4]),
SYS_STATFS => unimplemented("statfs", Err(SysError::EACCES)), SYS_PREAD64 => self.sys_pread(args[0], args[1] as *mut u8, args[2], args[3]),
SYS_FSTATFS => unimplemented("fstatfs", Err(SysError::EACCES)), SYS_PWRITE64 => self.sys_pwrite(args[0], args[1] as *const u8, args[2], args[3]),
SYS_SYNC => sys_sync(), SYS_READV => self.sys_readv(args[0], args[1] as *const IoVec, args[2]),
SYS_MOUNT => unimplemented("mount", Err(SysError::EACCES)), SYS_WRITEV => self.sys_writev(args[0], args[1] as *const IoVec, args[2]),
SYS_UMOUNT2 => unimplemented("umount2", Err(SysError::EACCES)), SYS_SENDFILE => self.sys_sendfile(args[0], args[1], args[2] as *mut usize, args[3]),
SYS_FCNTL => self.unimplemented("fcntl", Ok(0)),
// memory SYS_FLOCK => self.unimplemented("flock", Ok(0)),
SYS_BRK => unimplemented("brk", Err(SysError::ENOMEM)), SYS_FSYNC => self.sys_fsync(args[0]),
SYS_MMAP => sys_mmap(args[0], args[1], args[2], args[3], args[4], args[5]), SYS_FDATASYNC => self.sys_fdatasync(args[0]),
SYS_MPROTECT => sys_mprotect(args[0], args[1], args[2]), SYS_TRUNCATE => self.sys_truncate(args[0] as *const u8, args[1]),
SYS_MUNMAP => sys_munmap(args[0], args[1]), SYS_FTRUNCATE => self.sys_ftruncate(args[0], args[1]),
SYS_MADVISE => unimplemented("madvise", Ok(0)), 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]),
// signal SYS_CHDIR => self.sys_chdir(args[0] as *const u8),
SYS_RT_SIGACTION => unimplemented("sigaction", Ok(0)), SYS_RENAMEAT => self.sys_renameat(args[0], args[1] as *const u8, args[2], args[3] as *const u8),
SYS_RT_SIGPROCMASK => unimplemented("sigprocmask", Ok(0)), SYS_MKDIRAT => self.sys_mkdirat(args[0], args[1] as *const u8, args[2]),
SYS_SIGALTSTACK => unimplemented("sigaltstack", Ok(0)), SYS_LINKAT => self.sys_linkat(
SYS_KILL => sys_kill(args[0], args[1]), args[0],
args[1] as *const u8,
// schedule args[2],
SYS_SCHED_YIELD => sys_yield(), args[3] as *const u8,
SYS_SCHED_GETAFFINITY => sys_sched_getaffinity(args[0], args[1], args[2] as *mut u32), args[4],
),
// socket SYS_UNLINKAT => self.sys_unlinkat(args[0], args[1] as *const u8, args[2]),
SYS_SOCKET => sys_socket(args[0], args[1], args[2]), SYS_SYMLINKAT => self.unimplemented("symlinkat", Err(SysError::EACCES)),
SYS_CONNECT => sys_connect(args[0], args[1] as *const SockAddr, args[2]), SYS_READLINKAT => {
SYS_ACCEPT => sys_accept(args[0], args[1] as *mut SockAddr, args[2] as *mut u32), self.sys_readlinkat(args[0], args[1] as *const u8, args[2] as *mut u8, args[3])
SYS_ACCEPT4 => sys_accept(args[0], args[1] as *mut SockAddr, args[2] as *mut u32), // use accept for accept4 }
SYS_SENDTO => sys_sendto( SYS_FCHMOD => self.unimplemented("fchmod", Ok(0)),
args[0], SYS_FCHMODAT => self.unimplemented("fchmodat", Ok(0)),
args[1] as *const u8, SYS_FCHOWN => self.unimplemented("fchown", Ok(0)),
args[2], SYS_FCHOWNAT => self.unimplemented("fchownat", Ok(0)),
args[3], SYS_FACCESSAT => self.sys_faccessat(args[0], args[1] as *const u8, args[2], args[3]),
args[4] as *const SockAddr, SYS_DUP3 => self.sys_dup2(args[0], args[1]), // TODO: handle `flags`
args[5], SYS_PIPE2 => self.sys_pipe(args[0] as *mut u32), // TODO: handle `flags`
), SYS_UTIMENSAT => self.unimplemented("utimensat", Ok(0)),
SYS_RECVFROM => sys_recvfrom(
args[0], // io multiplexing
args[1] as *mut u8, SYS_PPOLL => self.sys_ppoll(args[0] as *mut PollFd, args[1], args[2] as *const TimeSpec), // ignore sigmask
args[2], SYS_EPOLL_CREATE1 => self.unimplemented("epoll_create1", Err(SysError::ENOSYS)),
args[3],
args[4] as *mut SockAddr, // file system
args[5] as *mut u32, SYS_STATFS => self.unimplemented("statfs", Err(SysError::EACCES)),
), SYS_FSTATFS => self.unimplemented("fstatfs", Err(SysError::EACCES)),
// SYS_SENDMSG => sys_sendmsg(), SYS_SYNC => self.sys_sync(),
SYS_RECVMSG => sys_recvmsg(args[0], args[1] as *mut MsgHdr, args[2]), SYS_MOUNT => self.unimplemented("mount", Err(SysError::EACCES)),
SYS_SHUTDOWN => sys_shutdown(args[0], args[1]), SYS_UMOUNT2 => self.unimplemented("umount2", Err(SysError::EACCES)),
SYS_BIND => sys_bind(args[0], args[1] as *const SockAddr, args[2]),
SYS_LISTEN => sys_listen(args[0], args[1]), // memory
SYS_GETSOCKNAME => sys_getsockname(args[0], args[1] as *mut SockAddr, args[2] as *mut u32), SYS_BRK => self.unimplemented("brk", Err(SysError::ENOMEM)),
SYS_GETPEERNAME => sys_getpeername(args[0], args[1] as *mut SockAddr, args[2] as *mut u32), SYS_MMAP => self.sys_mmap(args[0], args[1], args[2], args[3], args[4], args[5]),
SYS_SETSOCKOPT => sys_setsockopt(args[0], args[1], args[2], args[3] as *const u8, args[4]), SYS_MPROTECT => self.sys_mprotect(args[0], args[1], args[2]),
SYS_GETSOCKOPT => sys_getsockopt( SYS_MUNMAP => self.sys_munmap(args[0], args[1]),
args[0], SYS_MADVISE => self.unimplemented("madvise", Ok(0)),
args[1],
args[2], // signal
args[3] as *mut u8, SYS_RT_SIGACTION => self.unimplemented("sigaction", Ok(0)),
args[4] as *mut u32, SYS_RT_SIGPROCMASK => self.unimplemented("sigprocmask", Ok(0)),
), SYS_SIGALTSTACK => self.unimplemented("sigaltstack", Ok(0)),
SYS_KILL => self.sys_kill(args[0], args[1]),
// process
SYS_CLONE => sys_clone( // schedule
args[0], SYS_SCHED_YIELD => self.sys_yield(),
args[1], SYS_SCHED_GETAFFINITY => self.sys_sched_getaffinity(args[0], args[1], args[2] as *mut u32),
args[2] as *mut u32,
args[3] as *mut u32, // socket
args[4], SYS_SOCKET => self.sys_socket(args[0], args[1], args[2]),
tf, 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_EXECVE => sys_exec( SYS_ACCEPT4 => self.sys_accept(args[0], args[1] as *mut SockAddr, args[2] as *mut u32), // use accept for accept4
args[0] as *const u8, SYS_SENDTO => self.sys_sendto(
args[1] as *const *const u8, args[0],
args[2] as *const *const u8, args[1] as *const u8,
tf, args[2],
), args[3],
SYS_EXIT => sys_exit(args[0] as usize), args[4] as *const SockAddr,
SYS_EXIT_GROUP => sys_exit_group(args[0]), args[5],
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_RECVFROM => self.sys_recvfrom(
SYS_FUTEX => sys_futex( args[0],
args[0], args[1] as *mut u8,
args[1] as u32, args[2],
args[2] as i32, args[3],
args[3] as *const TimeSpec, args[4] as *mut SockAddr,
), args[5] as *mut u32,
),
// time // SYS_SENDMSG => self.sys_sendmsg(),
SYS_NANOSLEEP => sys_nanosleep(args[0] as *const TimeSpec), SYS_RECVMSG => self.sys_recvmsg(args[0], args[1] as *mut MsgHdr, args[2]),
SYS_SETITIMER => unimplemented("setitimer", Ok(0)), SYS_SHUTDOWN => self.sys_shutdown(args[0], args[1]),
SYS_GETTIMEOFDAY => sys_gettimeofday(args[0] as *mut TimeVal, args[1] as *const u8), SYS_BIND => self.sys_bind(args[0], args[1] as *const SockAddr, args[2]),
SYS_CLOCK_GETTIME => sys_clock_gettime(args[0], args[1] as *mut TimeSpec), 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),
// system SYS_GETPEERNAME => self.sys_getpeername(args[0], args[1] as *mut SockAddr, args[2] as *mut u32),
SYS_GETPID => sys_getpid(), SYS_SETSOCKOPT => self.sys_setsockopt(args[0], args[1], args[2], args[3] as *const u8, args[4]),
SYS_GETTID => sys_gettid(), SYS_GETSOCKOPT => self.sys_getsockopt(
SYS_UNAME => sys_uname(args[0] as *mut u8), args[0],
SYS_UMASK => unimplemented("umask", Ok(0o777)), args[1],
// SYS_GETRLIMIT => sys_getrlimit(), args[2],
// SYS_SETRLIMIT => sys_setrlimit(), args[3] as *mut u8,
SYS_GETRUSAGE => sys_getrusage(args[0], args[1] as *mut RUsage), args[4] as *mut u32,
SYS_SYSINFO => sys_sysinfo(args[0] as *mut SysInfo), ),
SYS_TIMES => sys_times(args[0] as *mut Tms),
SYS_GETUID => unimplemented("getuid", Ok(0)), // process
SYS_GETGID => unimplemented("getgid", Ok(0)), SYS_CLONE => self.sys_clone(
SYS_SETUID => unimplemented("setuid", Ok(0)), args[0],
SYS_GETEUID => unimplemented("geteuid", Ok(0)), args[1],
SYS_GETEGID => unimplemented("getegid", Ok(0)), args[2] as *mut u32,
SYS_SETPGID => unimplemented("setpgid", Ok(0)), args[3] as *mut u32,
SYS_GETPPID => sys_getppid(), args[4],
SYS_SETSID => unimplemented("setsid", Ok(0)), ),
SYS_GETPGID => unimplemented("getpgid", Ok(0)), SYS_EXECVE => self.sys_exec(
SYS_GETGROUPS => unimplemented("getgroups", Ok(0)), args[0] as *const u8,
SYS_SETGROUPS => unimplemented("setgroups", Ok(0)), args[1] as *const *const u8,
SYS_SETPRIORITY => sys_set_priority(args[0]), args[2] as *const *const u8,
SYS_PRCTL => unimplemented("prctl", Ok(0)), ),
SYS_PRLIMIT64 => sys_prlimit64( SYS_EXIT => self.sys_exit(args[0] as usize),
args[0], SYS_EXIT_GROUP => self.sys_exit_group(args[0]),
args[1], SYS_WAIT4 => self.sys_wait4(args[0] as isize, args[1] as *mut i32), // TODO: wait4
args[2] as *const RLimit, SYS_SET_TID_ADDRESS => self.sys_set_tid_address(args[0] as *mut u32),
args[3] as *mut RLimit, SYS_FUTEX => self.sys_futex(
), args[0],
SYS_REBOOT => sys_reboot( args[1] as u32,
args[0] as u32, args[2] as i32,
args[1] as u32, args[3] as *const TimeSpec,
args[2] as u32, ),
args[3] as *const u8,
), // time
SYS_NANOSLEEP => self.sys_nanosleep(args[0] as *const TimeSpec),
// custom SYS_SETITIMER => self.unimplemented("setitimer", Ok(0)),
SYS_MAP_PCI_DEVICE => sys_map_pci_device(args[0], args[1]), SYS_GETTIMEOFDAY => self.sys_gettimeofday(args[0] as *mut TimeVal, args[1] as *const u8),
SYS_GET_PADDR => sys_get_paddr(args[0] as *const u64, args[1] as *mut u64, args[2]), SYS_CLOCK_GETTIME => self.sys_clock_gettime(args[0], args[1] as *mut TimeSpec),
//SYS_GETRANDOM => unimplemented("getrandom", Err(SysError::EINVAL)),
SYS_GETRANDOM => sys_getrandom(args[0] as *mut u8, args[1] as usize, args[2] as u32), // system
SYS_TKILL => unimplemented("tkill", Ok(0)), SYS_GETPID => self.sys_getpid(),
_ => { SYS_GETTID => self.sys_gettid(),
let ret = match () { SYS_UNAME => self.sys_uname(args[0] as *mut u8),
#[cfg(target_arch = "x86_64")] SYS_UMASK => self.unimplemented("umask", Ok(0o777)),
() => x86_64_syscall(id, args, tf), // SYS_GETRLIMIT => self.sys_getrlimit(),
#[cfg(target_arch = "mips")] // SYS_SETRLIMIT => self.sys_setrlimit(),
() => mips_syscall(id, args, tf), SYS_GETRUSAGE => self.sys_getrusage(args[0], args[1] as *mut RUsage),
#[cfg(all(not(target_arch = "x86_64"), not(target_arch = "mips")))] SYS_SYSINFO => self.sys_sysinfo(args[0] as *mut SysInfo),
() => None, SYS_TIMES => self.sys_times(args[0] as *mut Tms),
}; SYS_GETUID => self.unimplemented("getuid", Ok(0)),
if let Some(ret) = ret { SYS_GETGID => self.unimplemented("getgid", Ok(0)),
ret SYS_SETUID => self.unimplemented("setuid", Ok(0)),
} else { SYS_GETEUID => self.unimplemented("geteuid", Ok(0)),
error!("unknown syscall id: {}, args: {:x?}", id, args); SYS_GETEGID => self.unimplemented("getegid", Ok(0)),
crate::trap::error(tf); 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);
} }
}; #[cfg(feature = "profile")]
if !pid.is_init() { {
// we trust pid 0 process let end_time = unsafe { core::arch::x86_64::_rdtsc() };
info!("=> {:x?}", ret); *SYSCALL_TIMING.lock().entry(id).or_insert(0) += end_time - begin_time;
} if end_time % 1000 == 0 {
#[cfg(feature = "profile")] let timing = SYSCALL_TIMING.lock();
{ let mut count_vec: Vec<(&usize, &i64)> = timing.iter().collect();
let end_time = unsafe { core::arch::x86_64::_rdtsc() }; count_vec.sort_by(|a, b| b.1.cmp(a.1));
*SYSCALL_TIMING.lock().entry(id).or_insert(0) += end_time - begin_time; for (id, time) in count_vec.iter().take(5) {
if end_time % 1000 == 0 { warn!("timing {:03} time {:012}", id, time);
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 { fn unimplemented(&self, name: &str, ret: SysResult) -> SysResult {
warn!("{} is unimplemented", name); warn!("{} is unimplemented", name);
ret ret
} }
#[cfg(target_arch = "mips")] #[cfg(target_arch = "mips")]
fn mips_syscall(id: usize, args: [usize; 6], tf: &mut TrapFrame) -> Option<SysResult> { fn mips_syscall(&mut self, id: usize, args: [usize; 6],) -> Option<SysResult> {
let ret = match id { let ret = match id {
SYS_OPEN => sys_open(args[0] as *const u8, args[1], args[2]), SYS_OPEN => self.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_POLL => self.sys_poll(args[0] as *mut PollFd, args[1], args[2]),
SYS_DUP2 => sys_dup2(args[0], args[1]), SYS_DUP2 => self.sys_dup2(args[0], args[1]),
SYS_FORK => sys_fork(tf), SYS_FORK => self.sys_fork(),
SYS_MMAP2 => sys_mmap(args[0], args[1], args[2], args[3], args[4], args[5] * 4096), SYS_MMAP2 => self.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_FSTAT64 => self.sys_fstat(args[0], args[1] as *mut Stat),
SYS_LSTAT64 => sys_lstat(args[0] as *const u8, args[1] as *mut Stat), SYS_LSTAT64 => self.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_STAT64 => self.sys_stat(args[0] as *const u8, args[1] as *mut Stat),
SYS_PIPE => { SYS_PIPE => {
let fd_ptr = args[0] as *mut u32; let fd_ptr = args[0] as *mut u32;
match sys_pipe(fd_ptr) { match self.sys_pipe(fd_ptr) {
Ok(code) => { Ok(code) => {
unsafe { unsafe {
tf.v0 = *fd_ptr as usize; tf.v0 = *fd_ptr as usize;
tf.v1 = *(fd_ptr.add(1)) 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 { unsafe {
asm!("mtc0 $0, $$4, 2": :"r"(args[0])); asm!("mtc0 $0, $$4, 2": :"r"(args[0]));
*(_cur_tls as *mut usize) = args[0]; *(_cur_tls as *mut usize) = args[0];
}
Ok(0)
} }
Ok(0) _ => return None,
} };
_ => return None, Some(ret)
}; }
Some(ret)
}
#[cfg(target_arch = "x86_64")] #[cfg(target_arch = "x86_64")]
fn x86_64_syscall(id: usize, args: [usize; 6], tf: &mut TrapFrame) -> Option<SysResult> { fn x86_64_syscall(&mut self, id: usize, args: [usize; 6]) -> Option<SysResult> {
let ret = match id { let ret = match id {
SYS_OPEN => sys_open(args[0] as *const u8, args[1], args[2]), SYS_OPEN => self.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_STAT => self.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_LSTAT => self.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_POLL => self.sys_poll(args[0] as *mut PollFd, args[1], args[2]),
SYS_ACCESS => sys_access(args[0] as *const u8, args[1]), SYS_ACCESS => self.sys_access(args[0] as *const u8, args[1]),
SYS_PIPE => sys_pipe(args[0] as *mut u32), SYS_PIPE => self.sys_pipe(args[0] as *mut u32),
SYS_SELECT => sys_select( SYS_SELECT => self.sys_select(
args[0], args[0],
args[1] as *mut u32, args[1] as *mut u32,
args[2] as *mut u32, args[2] as *mut u32,
args[3] as *mut u32, args[3] as *mut u32,
args[4] as *const TimeVal, args[4] as *const TimeVal,
), ),
SYS_DUP2 => sys_dup2(args[0], args[1]), SYS_DUP2 => self.sys_dup2(args[0], args[1]),
SYS_ALARM => unimplemented("alarm", Ok(0)), SYS_ALARM => self.unimplemented("alarm", Ok(0)),
SYS_FORK => sys_fork(tf), SYS_FORK => self.sys_fork(),
SYS_VFORK => sys_vfork(tf), SYS_VFORK => self.sys_vfork(),
SYS_RENAME => sys_rename(args[0] as *const u8, args[1] as *const u8), SYS_RENAME => self.sys_rename(args[0] as *const u8, args[1] as *const u8),
SYS_MKDIR => sys_mkdir(args[0] as *const u8, args[1]), SYS_MKDIR => self.sys_mkdir(args[0] as *const u8, args[1]),
SYS_RMDIR => sys_rmdir(args[0] as *const u8), SYS_RMDIR => self.sys_rmdir(args[0] as *const u8),
SYS_LINK => sys_link(args[0] as *const u8, args[1] as *const u8), SYS_LINK => self.sys_link(args[0] as *const u8, args[1] as *const u8),
SYS_UNLINK => sys_unlink(args[0] as *const u8), SYS_UNLINK => self.sys_unlink(args[0] as *const u8),
SYS_READLINK => sys_readlink(args[0] as *const u8, args[1] as *mut u8, args[2]), SYS_READLINK => self.sys_readlink(args[0] as *const u8, args[1] as *mut u8, args[2]),
SYS_CHMOD => unimplemented("chmod", Ok(0)), SYS_CHMOD => self.unimplemented("chmod", Ok(0)),
SYS_CHOWN => unimplemented("chown", Ok(0)), SYS_CHOWN => self.unimplemented("chown", Ok(0)),
SYS_ARCH_PRCTL => sys_arch_prctl(args[0] as i32, args[1], tf), SYS_ARCH_PRCTL => self.sys_arch_prctl(args[0] as i32, args[1]),
SYS_TIME => sys_time(args[0] as *mut u64), SYS_TIME => self.sys_time(args[0] as *mut u64),
SYS_EPOLL_CREATE => unimplemented("epoll_create", Err(SysError::ENOSYS)), SYS_EPOLL_CREATE => self.unimplemented("epoll_create", Err(SysError::ENOSYS)),
_ => return None, _ => return None,
}; };
Some(ret) Some(ret)
}
} }
pub type SysResult = Result<usize, SysError>; pub type SysResult = Result<usize, SysError>;

@ -12,274 +12,281 @@ use alloc::boxed::Box;
use core::cmp::min; use core::cmp::min;
use core::mem::size_of; use core::mem::size_of;
use smoltcp::wire::*; 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<dyn Socket> = 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 { pub fn sys_setsockopt(
let domain = AddressFamily::from(domain as u16); &mut self,
let socket_type = SocketType::from(socket_type as u8 & SOCK_TYPE_MASK); fd: usize,
info!( level: usize,
"socket: domain: {:?}, socket_type: {:?}, protocol: {}", optname: usize,
domain, socket_type, protocol optval: *const u8,
); optlen: usize,
let mut proc = process(); ) -> SysResult {
let socket: Box<dyn Socket> = match domain { info!(
AddressFamily::Internet | AddressFamily::Unix => match socket_type { "setsockopt: fd: {}, level: {}, optname: {}",
SocketType::Stream => Box::new(TcpSocketState::new()), fd, level, optname
SocketType::Datagram => Box::new(UdpSocketState::new()), );
SocketType::Raw => Box::new(RawSocketState::new(protocol as u8)), let mut proc = self.process();
_ => return Err(SysError::EINVAL), let data = unsafe { proc.vm.check_read_array(optval, optlen)? };
}, let socket = proc.get_socket(fd)?;
AddressFamily::Packet => match socket_type { socket.setsockopt(level, optname, data)
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_getsockopt( pub fn sys_getsockopt(
fd: usize, &mut self,
level: usize, fd: usize,
optname: usize, level: usize,
optval: *mut u8, optname: usize,
optlen: *mut u32, optval: *mut u8,
) -> SysResult { optlen: *mut u32,
info!( ) -> SysResult {
"getsockopt: fd: {}, level: {}, optname: {} optval: {:?} optlen: {:?}", info!(
fd, level, optname, optval, optlen "getsockopt: fd: {}, level: {}, optname: {} optval: {:?} optlen: {:?}",
); fd, level, optname, optval, optlen
let proc = process(); );
let optlen = unsafe { proc.vm.check_write_ptr(optlen)? }; let proc = self.process();
match level { let optlen = unsafe { proc.vm.check_write_ptr(optlen)? };
SOL_SOCKET => match optname { match level {
SO_SNDBUF => { SOL_SOCKET => match optname {
let optval = unsafe { proc.vm.check_write_ptr(optval as *mut u32)? }; SO_SNDBUF => {
*optval = crate::net::TCP_SENDBUF as u32; let optval = unsafe { proc.vm.check_write_ptr(optval as *mut u32)? };
*optlen = 4; *optval = crate::net::TCP_SENDBUF as u32;
Ok(0) *optlen = 4;
} Ok(0)
SO_RCVBUF => { }
let optval = unsafe { proc.vm.check_write_ptr(optval as *mut u32)? }; SO_RCVBUF => {
*optval = crate::net::TCP_RECVBUF as u32; let optval = unsafe { proc.vm.check_write_ptr(optval as *mut u32)? };
*optlen = 4; *optval = crate::net::TCP_RECVBUF as u32;
Ok(0) *optlen = 4;
} Ok(0)
_ => Err(SysError::ENOPROTOOPT), }
}, _ => Err(SysError::ENOPROTOOPT),
IPPROTO_TCP => match optname { },
TCP_CONGESTION => Ok(0), IPPROTO_TCP => match optname {
TCP_CONGESTION => Ok(0),
_ => Err(SysError::ENOPROTOOPT),
},
_ => Err(SysError::ENOPROTOOPT), _ => Err(SysError::ENOPROTOOPT),
}, }
_ => Err(SysError::ENOPROTOOPT),
} }
}
pub fn sys_connect(fd: usize, addr: *const SockAddr, addr_len: usize) -> SysResult { pub fn sys_connect(&mut self, fd: usize, addr: *const SockAddr, addr_len: usize) -> SysResult {
info!( info!(
"sys_connect: fd: {}, addr: {:?}, addr_len: {}", "sys_connect: fd: {}, addr: {:?}, addr_len: {}",
fd, addr, addr_len fd, addr, addr_len
); );
let mut proc = process(); let mut proc = self.process();
let endpoint = sockaddr_to_endpoint(&mut proc, addr, addr_len)?; let endpoint = sockaddr_to_endpoint(&mut proc.vm, addr, addr_len)?;
let socket = proc.get_socket(fd)?; let socket = proc.get_socket(fd)?;
socket.connect(endpoint)?; socket.connect(endpoint)?;
Ok(0) Ok(0)
} }
pub fn sys_sendto( pub fn sys_sendto(
fd: usize, &mut self,
base: *const u8, fd: usize,
len: usize, base: *const u8,
_flags: usize, len: usize,
addr: *const SockAddr, _flags: usize,
addr_len: usize, addr: *const SockAddr,
) -> SysResult { addr_len: usize,
info!( ) -> SysResult {
"sys_sendto: fd: {} base: {:?} len: {} addr: {:?} addr_len: {}", info!(
fd, base, len, addr, addr_len "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_recvfrom( let mut proc = self.process();
fd: usize,
base: *mut u8, let slice = unsafe { proc.vm.check_read_array(base, len)? };
len: usize, let endpoint = if addr.is_null() {
flags: usize, None
addr: *mut SockAddr, } else {
addr_len: *mut u32, let endpoint = sockaddr_to_endpoint(&mut proc.vm, addr, addr_len)?;
) -> SysResult { info!("sys_sendto: sending to endpoint {:?}", endpoint);
info!( Some(endpoint)
"sys_recvfrom: fd: {} base: {:?} len: {} flags: {} addr: {:?} addr_len: {:?}", };
fd, base, len, flags, addr, addr_len let socket = proc.get_socket(fd)?;
); socket.write(&slice, endpoint)
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)?;
}
} }
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 { let mut proc = self.process();
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 buf = iovs.new_buf(true); let mut slice = unsafe { proc.vm.check_write_array(base, len)? };
let socket = proc.get_socket(fd)?; let socket = proc.get_socket(fd)?;
let (result, endpoint) = socket.read(&mut buf); let (result, endpoint) = socket.read(&mut slice);
if let Ok(len) = result { if result.is_ok() && !addr.is_null() {
// copy data to user let sockaddr_in = SockAddr::from(endpoint);
iovs.write_all_from_slice(&buf[..len]); unsafe {
let sockaddr_in = SockAddr::from(endpoint); sockaddr_in.write_to(&mut proc, addr, addr_len)?;
unsafe { }
sockaddr_in.write_to(&mut proc, hdr.msg_name, &mut hdr.msg_namelen as *mut u32)?;
} }
result
} }
result
}
pub fn sys_bind(fd: usize, addr: *const SockAddr, addr_len: usize) -> SysResult { pub fn sys_recvmsg(&mut self, fd: usize, msg: *mut MsgHdr, flags: usize) -> SysResult {
info!("sys_bind: fd: {} addr: {:?} len: {}", fd, addr, addr_len); info!("recvmsg: fd: {}, msg: {:?}, flags: {}", fd, msg, flags);
let mut proc = process(); 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)?; pub fn sys_bind(&mut self, fd: usize, addr: *const SockAddr, addr_len: usize) -> SysResult {
info!("sys_bind: fd: {} bind to {:?}", fd, endpoint); info!("sys_bind: fd: {} addr: {:?} len: {}", fd, addr, addr_len);
let mut proc = self.process();
let socket = proc.get_socket(fd)?; let mut endpoint = sockaddr_to_endpoint(&mut proc.vm, addr, addr_len)?;
socket.bind(endpoint) info!("sys_bind: fd: {} bind to {:?}", fd, endpoint);
}
pub fn sys_listen(fd: usize, backlog: usize) -> SysResult { let socket = proc.get_socket(fd)?;
info!("sys_listen: fd: {} backlog: {}", fd, backlog); socket.bind(endpoint)
// smoltcp tcp sockets do not support backlog }
// open multiple sockets for each connection
let mut proc = process();
let socket = proc.get_socket(fd)?; pub fn sys_listen(&mut self, fd: usize, backlog: usize) -> SysResult {
socket.listen() 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 { let socket = proc.get_socket(fd)?;
info!("sys_shutdown: fd: {} how: {}", fd, how); socket.listen()
let mut proc = process(); }
let socket = proc.get_socket(fd)?; pub fn sys_shutdown(&mut self, fd: usize, how: usize) -> SysResult {
socket.shutdown() 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 { let socket = proc.get_socket(fd)?;
info!( socket.shutdown()
"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)?; pub fn sys_accept(&mut self, fd: usize, addr: *mut SockAddr, addr_len: *mut u32) -> SysResult {
let (new_socket, remote_endpoint) = socket.accept()?; 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 new_fd = proc.add_file(FileLike::Socket(new_socket));
let sockaddr_in = SockAddr::from(remote_endpoint);
unsafe { if !addr.is_null() {
sockaddr_in.write_to(&mut proc, addr, addr_len)?; 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 { pub fn sys_getsockname(&mut self, fd: usize, addr: *mut SockAddr, addr_len: *mut u32) -> SysResult {
info!( info!(
"sys_getsockname: fd: {} addr: {:?} addr_len: {:?}", "sys_getsockname: fd: {} addr: {:?} addr_len: {:?}",
fd, addr, addr_len fd, addr, addr_len
); );
let mut proc = process(); let mut proc = self.process();
if addr.is_null() { if addr.is_null() {
return Err(SysError::EINVAL); return Err(SysError::EINVAL);
} }
let socket = proc.get_socket(fd)?; let socket = proc.get_socket(fd)?;
let endpoint = socket.endpoint().ok_or(SysError::EINVAL)?; let endpoint = socket.endpoint().ok_or(SysError::EINVAL)?;
let sockaddr_in = SockAddr::from(endpoint); let sockaddr_in = SockAddr::from(endpoint);
unsafe { unsafe {
sockaddr_in.write_to(&mut proc, addr, addr_len)?; 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 { pub fn sys_getpeername(&mut self, fd: usize, addr: *mut SockAddr, addr_len: *mut u32) -> SysResult {
info!( info!(
"sys_getpeername: fd: {} addr: {:?} addr_len: {:?}", "sys_getpeername: fd: {} addr: {:?} addr_len: {:?}",
fd, addr, addr_len fd, addr, addr_len
); );
// smoltcp tcp sockets do not support backlog // smoltcp tcp sockets do not support backlog
// open multiple sockets for each connection // open multiple sockets for each connection
let mut proc = process(); let mut proc = self.process();
if addr as usize == 0 { if addr as usize == 0 {
return Err(SysError::EINVAL); return Err(SysError::EINVAL);
} }
let socket = proc.get_socket(fd)?; let socket = proc.get_socket(fd)?;
let remote_endpoint = socket.remote_endpoint().ok_or(SysError::EINVAL)?; let remote_endpoint = socket.remote_endpoint().ok_or(SysError::EINVAL)?;
let sockaddr_in = SockAddr::from(remote_endpoint); let sockaddr_in = SockAddr::from(remote_endpoint);
unsafe { unsafe {
sockaddr_in.write_to(&mut proc, addr, addr_len)?; sockaddr_in.write_to(&mut proc, addr, addr_len)?;
}
Ok(0)
} }
Ok(0)
} }
impl Process { impl Process {
@ -390,14 +397,14 @@ impl From<Endpoint> for SockAddr {
/// Convert sockaddr to endpoint /// Convert sockaddr to endpoint
// Check len is long enough // Check len is long enough
fn sockaddr_to_endpoint( fn sockaddr_to_endpoint(
proc: &mut Process, vm: &MemorySet,
addr: *const SockAddr, addr: *const SockAddr,
len: usize, len: usize,
) -> Result<Endpoint, SysError> { ) -> Result<Endpoint, SysError> {
if len < size_of::<u16>() { if len < size_of::<u16>() {
return Err(SysError::EINVAL); return Err(SysError::EINVAL);
} }
let addr = unsafe { proc.vm.check_read_ptr(addr)? }; let addr = unsafe { vm.check_read_ptr(addr)? };
unsafe { unsafe {
match AddressFamily::from(addr.family) { match AddressFamily::from(addr.family) {
AddressFamily::Internet => { AddressFamily::Internet => {

@ -3,344 +3,349 @@
use super::*; use super::*;
use crate::fs::INodeExt; use crate::fs::INodeExt;
/// Fork the current process. Return the child's PID. impl Syscall<'_> {
pub fn sys_fork(tf: &TrapFrame) -> SysResult { /// Fork the current process. Return the child's PID.
let new_thread = current_thread().fork(tf); pub fn sys_fork(&mut self) -> SysResult {
let pid = new_thread.proc.lock().pid.get(); let new_thread = self.thread.fork(self.tf);
let tid = processor().manager().add(new_thread); let pid = new_thread.proc.lock().pid.get();
processor().manager().detach(tid); let tid = processor().manager().add(new_thread);
info!("fork: {} -> {}", thread::current().id(), pid); processor().manager().detach(tid);
Ok(pid) info!("fork: {} -> {}", thread::current().id(), pid);
} Ok(pid)
}
pub fn sys_vfork(tf: &TrapFrame) -> SysResult {
sys_fork(tf)
}
/// Create a new thread in the current process. pub fn sys_vfork(&mut self) -> SysResult {
/// The new thread's stack pointer will be set to `newsp`, self.sys_fork()
/// 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);
} }
if (flags != 0x7d0f00) && (flags != 0x5d0f00) {
//0x5d0f00 is the args from gcc of alpine linux /// Create a new thread in the current process.
//warn!("sys_clone only support musl pthread_create"); /// The new thread's stack pointer will be set to `newsp`,
panic!( /// and thread pointer will be set to `newtls`.
"sys_clone only support sys_fork OR musl pthread_create without flags{:x}", /// The child tid will be stored at both `parent_tid` and `child_tid`.
flags /// 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. /// Wait for the process exit.
/// Return the PID. Store exit code to `wstatus` if it's not null. /// Return the PID. Store exit code to `wstatus` if it's not null.
pub fn sys_wait4(pid: isize, wstatus: *mut i32) -> SysResult { pub fn sys_wait4(&mut self, pid: isize, wstatus: *mut i32) -> SysResult {
//info!("wait4: pid: {}, code: {:?}", pid, wstatus); //info!("wait4: pid: {}, code: {:?}", pid, wstatus);
let wstatus = if !wstatus.is_null() { let wstatus = if !wstatus.is_null() {
Some(unsafe { process().vm.check_write_ptr(wstatus)? }) Some(unsafe { self.process().vm.check_write_ptr(wstatus)? })
} else { } else {
None 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)),
}; };
// if found, return #[derive(Debug)]
if let Some((pid, exit_code)) = find { enum WaitFor {
proc.child_exit_code.remove(&pid); AnyChild,
if let Some(wstatus) = wstatus { Pid(usize),
*wstatus = exit_code as i32;
}
return Ok(pid);
} }
// if not, check pid let target = match pid {
let children: Vec<_> = proc -1 | 0 => WaitFor::AnyChild,
.children p if p > 0 => WaitFor::Pid(p as usize),
.iter() _ => unimplemented!(),
.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 { loop {
return Err(SysError::ECHILD); 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!( info!(
"wait: thread {} -> {:?}, sleep", "exec:BEG: path: {:?}, argv: {:?}, envp: {:?}",
thread::current().id(), path, argv, envp
target
); );
let condvar = proc.child_exit.clone(); let mut proc = self.process();
condvar.wait(proc); 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 info!(
/// "exec:STEP2: path: {:?}, args: {:?}, envs: {:?}",
/// `argv` is an array of argument strings passed to the new program. path, args, envs
/// `envp` is an array of strings, conventionally of the form `key=value`, );
/// which are passed as environment to the new program.
/// // Kill other threads
/// NOTICE: `argv` & `envp` can not be NULL (different from Linux) proc.threads.retain(|&tid| {
/// if tid != processor().tid() {
/// NOTICE: for multi-thread programs processor().manager().exit(tid, 1);
/// 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 tid == processor().tid()
/// 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!( // Read program file
"exec:STEP2: path: {:?}, args: {:?}, envs: {:?}", let inode = proc.lookup_inode(&path)?;
path, args, envs
);
// Kill other threads // Make new Thread
proc.threads.retain(|&tid| { let (mut vm, entry_addr, ustack_top) =
if tid != processor().tid() { Thread::new_user_vm(&inode, &path, args, envs).map_err(|_| SysError::EINVAL)?;
processor().manager().exit(tid, 1);
// Activate new page table
core::mem::swap(&mut proc.vm, &mut vm);
unsafe {
proc.vm.activate();
} }
tid == processor().tid()
});
// Read program file // Modify exec path
let inode = proc.lookup_inode(&path)?; proc.exec_path = path.clone();
drop(proc);
// Make new Thread // Modify the TrapFrame
let (mut vm, entry_addr, ustack_top) = *self.tf = TrapFrame::new_user_thread(entry_addr, ustack_top);
Thread::new_user_vm(&inode, &path, args, envs).map_err(|_| SysError::EINVAL)?;
// Activate new page table info!("exec:END: path: {:?}", path);
core::mem::swap(&mut proc.vm, &mut vm); Ok(0)
unsafe {
proc.vm.activate();
} }
// Modify exec path pub fn sys_yield(&mut self) -> SysResult {
proc.exec_path = path.clone(); thread::yield_now();
Ok(0)
}
// Modify the TrapFrame /// Kill the process
*tf = TrapFrame::new_user_thread(entry_addr, ustack_top); 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); /// Get the current process id
Ok(0) pub fn sys_getpid(&mut self) -> SysResult {
} info!("getpid");
Ok(self.process().pid.get())
}
pub fn sys_yield() -> SysResult { /// Get the current thread id
thread::yield_now(); pub fn sys_gettid(&mut self) -> SysResult {
Ok(0) info!("gettid");
} // use pid as tid for now
Ok(thread::current().id())
}
/// Kill the process /// Get the parent process id
pub fn sys_kill(pid: usize, sig: usize) -> SysResult { pub fn sys_getppid(&mut self) -> SysResult {
info!( if let Some(parent) = self.process().parent.as_ref() {
"kill: {} killed: {} with sig {}", Ok(parent.lock().pid.get())
thread::current().id(), } else {
pid, Ok(0)
sig }
); }
let current_pid = process().pid.get().clone();
if current_pid == pid { /// Exit the current thread
// killing myself pub fn sys_exit(&mut self, exit_code: usize) -> ! {
sys_exit_group(sig); let tid = thread::current().id();
} else { info!("exit: {}, code: {}", tid, exit_code);
if let Some(proc_arc) = PROCESSES.read().get(&pid).and_then(|weak| weak.upgrade()) { let mut proc = self.process();
let proc = proc_arc.lock(); proc.threads.retain(|&id| id != tid);
// quit all threads
for tid in proc.threads.iter() { // for last thread,
processor().manager().exit(*tid, sig); // notify parent and fill exit code
} // avoid deadlock
// notify parent and fill exit code let exit = proc.threads.len() == 0;
// avoid deadlock let proc_parent = proc.parent.clone();
let proc_parent = proc.parent.clone(); let pid = proc.pid.get();
let pid = proc.pid.get(); drop(proc);
drop(proc); if exit {
if let Some(parent) = proc_parent { if let Some(parent) = proc_parent {
let mut parent = parent.lock(); 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(); parent.child_exit.notify_one();
} }
Ok(0)
} else {
Err(SysError::EINVAL)
} }
}
}
/// Get the current process id // perform futex wake 1
pub fn sys_getpid() -> SysResult { // ref: http://man7.org/linux/man-pages/man2/set_tid_address.2.html
info!("getpid"); // FIXME: do it in all possible ways a thread can exit
Ok(process().pid.get()) // 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;
/// Get the current thread id if !clear_child_tid.is_null() {
pub fn sys_gettid() -> SysResult { info!("exit: futex {:#?} wake 1", clear_child_tid);
info!("gettid"); if let Ok(clear_child_tid_ref) = unsafe { proc.vm.check_write_ptr(clear_child_tid) } {
// use pid as tid for now *clear_child_tid_ref = 0;
Ok(thread::current().id()) let queue = proc.get_futex(clear_child_tid as usize);
} queue.notify_one();
}
}
drop(proc);
/// Get the parent process id processor().manager().exit(tid, exit_code as usize);
pub fn sys_getppid() -> SysResult { processor().yield_now();
if let Some(ref parent) = process().parent.as_ref() { unreachable!();
Ok(parent.lock().pid.get())
} else {
Ok(0)
} }
}
/// Exit the current thread /// Exit the current thread group (i.e. process)
pub fn sys_exit(exit_code: usize) -> ! { pub fn sys_exit_group(&mut self, exit_code: usize) -> ! {
let tid = thread::current().id(); let proc = self.process();
info!("exit: {}, code: {}", tid, exit_code); info!("exit_group: {}, code: {}", proc.pid, exit_code);
let mut proc = process();
proc.threads.retain(|&id| id != tid); // quit all threads
for tid in proc.threads.iter() {
// for last thread, processor().manager().exit(*tid, exit_code);
// notify parent and fill exit code }
// avoid deadlock
let exit = proc.threads.len() == 0; // notify parent and fill exit code
let proc_parent = proc.parent.clone(); // avoid deadlock
let pid = proc.pid.get(); let proc_parent = proc.parent.clone();
drop(proc); let pid = proc.pid.get();
if exit { drop(proc);
if let Some(parent) = proc_parent { if let Some(parent) = proc_parent {
let mut parent = parent.lock(); let mut parent = parent.lock();
parent.child_exit_code.insert(pid, exit_code); parent.child_exit_code.insert(pid, exit_code);
parent.child_exit.notify_one(); parent.child_exit.notify_one();
} }
}
// perform futex wake 1 processor().yield_now();
// ref: http://man7.org/linux/man-pages/man2/set_tid_address.2.html unreachable!();
// 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();
}
} }
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 pub fn sys_nanosleep(&mut self, req: *const TimeSpec) -> SysResult {
for tid in proc.threads.iter() { let time = unsafe { *self.process().vm.check_read_ptr(req)? };
processor().manager().exit(*tid, exit_code); info!("nanosleep: time: {:#?}", time);
// TODO: handle spurious wakeup
thread::sleep(time.to_duration());
Ok(0)
} }
// notify parent and fill exit code pub fn sys_set_priority(&mut self, priority: usize) -> SysResult {
// avoid deadlock let pid = thread::current().id();
let proc_parent = proc.parent.clone(); processor().manager().set_priority(pid, priority as u8);
let pid = proc.pid.get(); Ok(0)
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();
} }
processor().yield_now(); pub fn sys_set_tid_address(&mut self, tidptr: *mut u32) -> SysResult {
unreachable!(); info!("set_tid_address: {:?}", tidptr);
} self.thread.clear_child_tid = tidptr as usize;
Ok(thread::current().id())
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())
} }
bitflags! { bitflags! {

@ -5,6 +5,85 @@ use crate::consts::USEC_PER_TICK;
use core::time::Duration; use core::time::Duration;
use lazy_static::lazy_static; 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 /// should be initialized together
lazy_static! { lazy_static! {
pub static ref EPOCH_BASE: u64 = crate::arch::timer::read_epoch(); 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 // ignore other fields for now
#[repr(C)] #[repr(C)]
pub struct RUsage { pub struct RUsage {
@ -118,29 +162,6 @@ pub struct RUsage {
stime: TimeVal, 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)] #[repr(C)]
#[derive(Debug, Copy, Clone)] #[derive(Debug, Copy, Clone)]
pub struct Tms { pub struct Tms {
@ -149,22 +170,3 @@ pub struct Tms {
tms_cutime: u64, /* user time of children */ tms_cutime: u64, /* user time of children */
tms_cstime: u64, /* system 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)
}

Loading…
Cancel
Save