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:
parent
08d10522ff
commit
da58486be5
@ -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() {
|
||||
|
@ -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
|
||||
}
|
||||
|
||||
|
@ -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
@ -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
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -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>;
|
||||
|
@ -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 => {
|
||||
|
@ -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! {
|
||||
|
@ -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)
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user