1
0
mirror of https://github.com/rcore-os/rCore.git synced 2024-11-22 16:16:16 +04:00

refactor syscall: move all context and functions to struct Syscall

This commit is contained in:
WangRunji 2019-05-04 13:16:42 +08:00
parent 08d10522ff
commit da58486be5
10 changed files with 1991 additions and 1953 deletions

View File

@ -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<InactivePageTable0>;
@ -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() {

View File

@ -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
}

View File

@ -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)?;
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)
}
// 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)
}
#[cfg(not(target_arch = "x86_64"))]
pub fn sys_map_pci_device(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;
#[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(&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)
}

File diff suppressed because it is too large Load Diff

View File

@ -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;
}
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);
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;
}
proc.vm.push(
addr,
addr + len,
prot.to_attr(),
Delay::new(GlobalFrameAlloc),
"mmap_anon",
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);
}
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(&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
);
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);
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);
}
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)
}
}
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
);
let mut proc = 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);
}
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)
}
bitflags! {
pub struct MmapProt: usize {
/// Data cannot be accessed

View File

@ -4,118 +4,184 @@ 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)
}
_ => Err(SysError::EINVAL),
}
}
pub fn sys_uname(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)? };
for i in 0..strings.len() {
unsafe {
util::write_cstr(&mut buf[i * offset], &strings[i]);
}
}
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 {
let proc = process();
let sys_info = unsafe { proc.vm.check_write_ptr(sys_info)? };
let sysinfo = SysInfo::default();
*sys_info = sysinfo;
Ok(0)
}
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::<u32>() != 0 {
return Err(SysError::EINVAL);
}
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);
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)
}
// FIXME: support timeout
// FIXME: fix racing
queue._wait();
Ok(0)
_ => Err(SysError::EINVAL),
}
OP_WAKE => {
let woken_up_count = queue.notify_n(val as usize);
Ok(woken_up_count)
}
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 = 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]);
}
}
_ => {
warn!("unsupported futex operation: {}", op);
Err(SysError::ENOSYS)
Ok(0)
}
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::<u32>())? };
// we only have 4 cpu at most.
// so just set it.
mask[0] = 0b1111;
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)? };
let sysinfo = SysInfo::default();
*sys_info = sysinfo;
Ok(0)
}
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::<u32>() != 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)
}
}
}
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)
}
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),
}
}
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)
}
}
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);
}
}
Ok(0)
}
#[repr(C)]
#[derive(Debug, Default)]
@ -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)
}

View File

@ -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);
}
// 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])
}
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);
}
}
};
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);
}
}
}
match ret {
Ok(code) => code as isize,
Err(err) => -(err as isize),
}
let thread = unsafe { current_thread() };
let mut syscall = Syscall { thread, tf };
syscall.syscall(id, args)
}
fn unimplemented(name: &str, ret: SysResult) -> SysResult {
warn!("{} is unimplemented", name);
ret
/// All context needed for syscall
struct Syscall<'a> {
thread: &'a mut Thread,
tf: &'a mut TrapFrame,
}
#[cfg(target_arch = "mips")]
fn mips_syscall(id: usize, args: [usize; 6], tf: &mut TrapFrame) -> Option<SysResult> {
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;
}
Ok(tf.v0)
impl Syscall<'_> {
/// Get current process
pub fn process(&self) -> MutexGuard<'_, Process, SpinNoIrq> {
self.thread.proc.lock()
}
/// 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);
}
// 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);
}
#[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);
}
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();
}
unsafe {
asm!("mtc0 $0, $$4, 2": :"r"(args[0]));
*(_cur_tls as *mut usize) = args[0];
}
Ok(0)
match ret {
Ok(code) => code as isize,
Err(err) => -(err as isize),
}
_ => return None,
};
Some(ret)
}
}
#[cfg(target_arch = "x86_64")]
fn x86_64_syscall(id: usize, args: [usize; 6], tf: &mut TrapFrame) -> Option<SysResult> {
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)
fn unimplemented(&self, name: &str, ret: SysResult) -> SysResult {
warn!("{} is unimplemented", name);
ret
}
#[cfg(target_arch = "mips")]
fn mips_syscall(&mut self, id: usize, args: [usize; 6],) -> Option<SysResult> {
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)
}
Err(err) => Err(err),
}
}
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];
}
Ok(0)
}
_ => return None,
};
Some(ret)
}
#[cfg(target_arch = "x86_64")]
fn x86_64_syscall(&mut self, id: usize, args: [usize; 6]) -> Option<SysResult> {
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<usize, SysError>;

View File

@ -12,274 +12,281 @@ use alloc::boxed::Box;
use core::cmp::min;
use core::mem::size_of;
use smoltcp::wire::*;
use crate::memory::MemorySet;
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<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_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(
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),
_ => Err(SysError::ENOPROTOOPT),
},
_ => Err(SysError::ENOPROTOOPT),
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_connect(fd: usize, addr: *const SockAddr, addr_len: usize) -> SysResult {
info!(
"sys_connect: fd: {}, addr: {:?}, addr_len: {}",
fd, addr, addr_len
);
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)
}
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_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),
}
}
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
);
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 = process();
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)
}
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 = self.process();
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.vm, addr, addr_len)?;
info!("sys_sendto: sending to endpoint {:?}", endpoint);
Some(endpoint)
};
let socket = proc.get_socket(fd)?;
socket.write(&slice, endpoint)
}
let mut slice = unsafe { proc.vm.check_write_array(base, len)? };
let socket = proc.get_socket(fd)?;
let (result, endpoint) = socket.read(&mut slice);
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
);
if result.is_ok() && !addr.is_null() {
let mut proc = self.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_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
}
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 mut endpoint = sockaddr_to_endpoint(&mut proc.vm, addr, addr_len)?;
info!("sys_bind: fd: {} bind to {:?}", fd, endpoint);
let socket = proc.get_socket(fd)?;
socket.bind(endpoint)
}
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();
let socket = proc.get_socket(fd)?;
socket.listen()
}
pub fn sys_shutdown(&mut self, fd: usize, how: usize) -> SysResult {
info!("sys_shutdown: fd: {} how: {}", fd, how);
let mut proc = self.process();
let socket = proc.get_socket(fd)?;
socket.shutdown()
}
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 socket = proc.get_socket(fd)?;
let (new_socket, remote_endpoint) = socket.accept()?;
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)
}
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 = self.process();
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)?;
}
Ok(0)
}
result
}
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
);
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)? };
// smoltcp tcp sockets do not support backlog
// open multiple sockets for each connection
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);
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 addr as usize == 0 {
return Err(SysError::EINVAL);
}
}
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();
let mut endpoint = sockaddr_to_endpoint(&mut proc, addr, addr_len)?;
info!("sys_bind: fd: {} bind to {:?}", fd, endpoint);
let socket = proc.get_socket(fd)?;
socket.bind(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.listen()
}
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.shutdown()
}
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)?;
let (new_socket, remote_endpoint) = socket.accept()?;
let new_fd = proc.add_file(FileLike::Socket(new_socket));
if !addr.is_null() {
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(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
);
let mut proc = process();
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)?;
}
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
);
// smoltcp tcp sockets do not support backlog
// open multiple sockets for each connection
let mut proc = process();
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)?;
}
Ok(0)
}
impl Process {
@ -390,14 +397,14 @@ impl From<Endpoint> 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<Endpoint, SysError> {
if len < size_of::<u16>() {
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 => {

View File

@ -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)
}
/// 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);
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)
}
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 { 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),
pub fn sys_vfork(&mut self) -> SysResult {
self.sys_fork()
}
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
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);
}
/// 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!(
"wait: thread {} -> {:?}, sleep",
thread::current().id(),
target
"clone: flags: {:?} == {:#x}, newsp: {:#x}, parent_tid: {:?}, child_tid: {:?}, newtls: {:#x}",
clone_flags, flags, newsp, parent_tid, child_tid, newtls
);
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(
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);
if flags == 0x4111 || flags == 0x11 {
warn!("sys_clone is calling sys_fork instead, ignoring other args");
return self.sys_fork();
}
tid == processor().tid()
});
// Read program file
let inode = proc.lookup_inode(&path)?;
// 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();
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)
}
// Modify exec path
proc.exec_path = path.clone();
// Modify the TrapFrame
*tf = TrapFrame::new_user_thread(entry_addr, ustack_top);
info!("exec:END: path: {:?}", path);
Ok(0)
}
pub fn sys_yield() -> SysResult {
thread::yield_now();
Ok(0)
}
/// 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);
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)
/// 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 {
Err(SysError::EINVAL)
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 = 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);
}
}
}
/// Get the current process id
pub fn sys_getpid() -> SysResult {
info!("getpid");
Ok(process().pid.get())
}
/// 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!(
"exec:BEG: path: {:?}, argv: {:?}, envp: {:?}",
path, argv, envp
);
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)? };
/// Get the current thread id
pub fn sys_gettid() -> SysResult {
info!("gettid");
// use pid as tid for now
Ok(thread::current().id())
}
if args.is_empty() {
error!("exec: args is null");
return Err(SysError::EINVAL);
}
/// 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 {
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()
});
// Read program file
let inode = proc.lookup_inode(&path)?;
// 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();
}
// Modify exec path
proc.exec_path = path.clone();
drop(proc);
// Modify the TrapFrame
*self.tf = TrapFrame::new_user_thread(entry_addr, ustack_top);
info!("exec:END: path: {:?}", path);
Ok(0)
}
}
/// 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);
pub fn sys_yield(&mut self) -> SysResult {
thread::yield_now();
Ok(0)
}
// 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 {
/// 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)
}
}
}
/// Get the current process id
pub fn sys_getpid(&mut self) -> SysResult {
info!("getpid");
Ok(self.process().pid.get())
}
/// Get the current thread id
pub fn sys_gettid(&mut self) -> SysResult {
info!("gettid");
// use pid as tid for now
Ok(thread::current().id())
}
/// 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, 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 = 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);
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(&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();
}
processor().yield_now();
unreachable!();
}
// 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();
}
}
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! {

View File

@ -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)
}