diff --git a/Cargo.lock b/Cargo.lock index b58a0892c7..caf48f1542 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -234,8 +234,8 @@ checksum = "64072665120942deff5fd5425d6c1811b854f4939e7f1c01ce755f64432bbea7" [[package]] name = "redox_syscall" -version = "0.5.8" -source = "git+https://gitlab.redox-os.org/redox-os/syscall.git?branch=master#ee30da97005bf4675f5ede8baa3a440abf773883" +version = "0.5.9" +source = "git+https://gitlab.redox-os.org/redox-os/syscall.git#3117ea451c6224a6eb91283d8eb7c41d05fb7d9d" dependencies = [ "bitflags 2.8.0", ] diff --git a/src/scheme/mod.rs b/src/scheme/mod.rs index f8b6f27fc6..1941722171 100644 --- a/src/scheme/mod.rs +++ b/src/scheme/mod.rs @@ -13,7 +13,7 @@ use core::{hash::BuildHasherDefault, sync::atomic::AtomicUsize}; use hashbrown::{hash_map::DefaultHashBuilder, HashMap}; use indexmap::IndexMap; use spin::{Once, RwLock, RwLockReadGuard, RwLockWriteGuard}; -use syscall::{EventFlags, MunmapFlags, SendFdFlags}; +use syscall::{CallFlags, EventFlags, MunmapFlags, SendFdFlags}; use crate::{ context::{ @@ -22,7 +22,7 @@ use crate::{ }, syscall::{ error::*, - usercopy::{UserSliceRo, UserSliceWo}, + usercopy::{UserSliceRo, UserSliceRw, UserSliceWo}, }, }; @@ -505,6 +505,15 @@ pub trait KernelScheme: Send + Sync + 'static { fn on_close(&self, id: usize) -> Result<()> { self.close(id) } + fn kcall( + &self, + id: usize, + payload: UserSliceRw, + flags: CallFlags, + metadata: &[u64], + ) -> Result { + Err(Error::new(EOPNOTSUPP)) + } } #[derive(Debug)] diff --git a/src/scheme/user.rs b/src/scheme/user.rs index 086f461da0..5f1ee257f4 100644 --- a/src/scheme/user.rs +++ b/src/scheme/user.rs @@ -15,8 +15,8 @@ use spin::{Mutex, RwLock}; use spinning_top::RwSpinlock; use syscall::{ schemev2::{Cqe, CqeOpcode, Opcode, Sqe, SqeFlags}, - FobtainFdFlags, MunmapFlags, SendFdFlags, F_SETFL, KSMSG_CANCEL, MAP_FIXED_NOREPLACE, - SKMSG_FOBTAINFD, SKMSG_FRETURNFD, SKMSG_PROVIDE_MMAP, + CallFlags, FobtainFdFlags, MunmapFlags, SendFdFlags, F_SETFL, KSMSG_CANCEL, + MAP_FIXED_NOREPLACE, SKMSG_FOBTAINFD, SKMSG_FRETURNFD, SKMSG_PROVIDE_MMAP, }; use crate::{ @@ -38,9 +38,9 @@ use crate::{ syscall::{ data::{Map, Packet}, error::*, - flag::{EventFlags, MapFlags, EVENT_READ, O_NONBLOCK, PROT_READ, PROT_WRITE}, + flag::{EventFlags, MapFlags, EVENT_READ, O_NONBLOCK, PROT_READ}, number::*, - usercopy::{UserSlice, UserSliceRo, UserSliceWo}, + usercopy::{UserSlice, UserSliceRo, UserSliceRw, UserSliceWo}, }, }; @@ -465,12 +465,10 @@ impl UserInner { context_weak: &Weak>, user_buf: UserSlice, ) -> Result> { - let (mode, map_flags) = match (READ, WRITE) { - (true, false) => (Mode::Ro, PROT_READ), - (false, true) => (Mode::Wo, PROT_WRITE), + let mut map_flags = MapFlags::empty(); + map_flags.set(MapFlags::PROT_READ, READ); + map_flags.set(MapFlags::PROT_WRITE, WRITE); - _ => unreachable!(), - }; if user_buf.is_empty() { // NOTE: Rather than returning NULL, we return a dummy dangling address, that is // happens to be non-canonical on x86. This relieves scheme handlers from having to @@ -549,22 +547,18 @@ impl UserInner { let len = core::cmp::min(PAGE_SIZE - offset, user_buf.len()); - match mode { - Mode::Ro => { - array.buf_mut()[..offset].fill(0_u8); - array.buf_mut()[offset + len..].fill(0_u8); + if READ { + array.buf_mut()[..offset].fill(0_u8); + array.buf_mut()[offset + len..].fill(0_u8); - let slice = &mut array.buf_mut()[offset..][..len]; - let head_part_of_buf = - user_buf.limit(len).expect("always smaller than max len"); + let slice = &mut array.buf_mut()[offset..][..len]; + let head_part_of_buf = user_buf.limit(len).expect("always smaller than max len"); - head_part_of_buf - .reinterpret_unchecked::() - .copy_to_slice(slice)?; - } - Mode::Wo => { - array.buf_mut().fill(0_u8); - } + head_part_of_buf + .reinterpret_unchecked::() + .copy_to_slice(slice)?; + } else { + array.buf_mut().fill(0_u8); } dst_space.mmap( @@ -583,7 +577,7 @@ impl UserInner { let head = CopyInfo { src: Some(array), - dst: (mode == Mode::Wo).then_some(head_part_of_buf.reinterpret_unchecked()), + dst: WRITE.then_some(head_part_of_buf.reinterpret_unchecked()), }; head @@ -651,20 +645,17 @@ impl UserInner { let mut array = BorrowedHtBuf::tail()?; let frame = array.frame(); - match mode { - Mode::Ro => { - let (to_copy, to_zero) = array.buf_mut().split_at_mut(tail_size); + if READ { + let (to_copy, to_zero) = array.buf_mut().split_at_mut(tail_size); - to_zero.fill(0_u8); + to_zero.fill(0_u8); - // FIXME: remove reinterpret_unchecked - tail_part_of_buf - .reinterpret_unchecked::() - .copy_to_slice(to_copy)?; - } - Mode::Wo => { - array.buf_mut().fill(0_u8); - } + // FIXME: remove reinterpret_unchecked + tail_part_of_buf + .reinterpret_unchecked::() + .copy_to_slice(to_copy)?; + } else { + array.buf_mut().fill(0_u8); } dst_space.mmap( @@ -683,7 +674,7 @@ impl UserInner { CopyInfo { src: Some(array), - dst: (mode == Mode::Wo).then_some(tail_part_of_buf.reinterpret_unchecked()), + dst: WRITE.then_some(tail_part_of_buf.reinterpret_unchecked()), } } else { CopyInfo { @@ -1734,12 +1725,44 @@ impl KernelScheme for UserScheme { Response::Fd(_) => Err(Error::new(EIO)), } } -} + fn kcall( + &self, + id: usize, + payload: UserSliceRw, + _flags: CallFlags, + metadata: &[u64], + ) -> Result { + let inner = self.inner.upgrade().ok_or(Error::new(ENODEV))?; -#[derive(PartialEq)] -pub enum Mode { - Ro, - Wo, + let mut address = inner.capture_user(payload)?; + + let mut sqe = Sqe { + opcode: Opcode::Call as u8, + sqe_flags: SqeFlags::empty(), + _rsvd: 0, + tag: inner.next_id()?, + caller: 0, // TODO? + args: [ + id as u64, + address.base() as u64, + address.len() as u64, + 0, + 0, + 0, + ], + }; + { + let dst = &mut sqe.args[3..]; + let len = dst.len().min(metadata.len()); + dst[..len].copy_from_slice(&metadata[..len]); + } + let res = inner.call_extended_inner(None, sqe, &mut address.span())?; + + match res { + Response::Regular(res, _) => Error::demux(res), + Response::Fd(_) => Err(Error::new(EIO)), + } + } } pub trait Args: Copy { diff --git a/src/syscall/debug.rs b/src/syscall/debug.rs index ebb43d6b7e..ffd3d39c13 100644 --- a/src/syscall/debug.rs +++ b/src/syscall/debug.rs @@ -145,6 +145,13 @@ pub fn format_call(a: usize, b: usize, c: usize, d: usize, e: usize, f: usize) - Ok(times) }), ), + SYS_CALL => format!( + "call({b}, {c:x}+{d}, {:?}, {:0x?}", + CallFlags::from_bits_retain(e & !0xff), + // TODO: u64 + UserSlice::ro(f, (e & 0xff) * 8) + .and_then(|buf| buf.usizes().collect::>>()), + ), SYS_CLOCK_GETTIME => format!("clock_gettime({}, {:?})", b, unsafe { read_struct::(c) diff --git a/src/syscall/fs.rs b/src/syscall/fs.rs index 62f0753c29..2c3c1e362e 100644 --- a/src/syscall/fs.rs +++ b/src/syscall/fs.rs @@ -1,5 +1,5 @@ //! Filesystem syscalls -use core::num::NonZeroUsize; +use core::{mem::size_of, num::NonZeroUsize}; use alloc::{sync::Arc, vec::Vec}; use redox_path::RedoxPath; @@ -17,7 +17,7 @@ use crate::{ syscall::{data::Stat, error::*, flag::*}, }; -use super::usercopy::{UserSlice, UserSliceRo, UserSliceWo}; +use super::usercopy::{UserSlice, UserSliceRo, UserSliceRw, UserSliceWo}; pub fn file_op_generic( fd: FileHandle, @@ -248,6 +248,24 @@ pub fn dup2(fd: FileHandle, new_fd: FileHandle, buf: UserSliceRo) -> Result Result { + let mut meta = [0_u64; 3]; + + // TODO: bytemuck/plain + let copied = metadata.copy_common_bytes_to_slice(unsafe { + core::slice::from_raw_parts_mut(meta.as_mut_ptr().cast(), meta.len() * 8) + })?; + + file_op_generic(fd, |scheme, number| { + scheme.kcall(number, payload, flags, &meta[..copied / 8]) + }) +} + pub fn sendfd(socket: FileHandle, fd: FileHandle, flags_raw: usize, arg: u64) -> Result { let requested_flags = SendFdFlags::from_bits(flags_raw).ok_or(Error::new(EINVAL))?; diff --git a/src/syscall/mod.rs b/src/syscall/mod.rs index 6ebcaa570e..d549fa540c 100644 --- a/src/syscall/mod.rs +++ b/src/syscall/mod.rs @@ -6,7 +6,7 @@ extern crate syscall; use core::mem::size_of; -use syscall::{dirent::DirentHeader, RtSigInfo, RwFlags, EINVAL, SIGKILL}; +use syscall::{dirent::DirentHeader, CallFlags, RtSigInfo, RwFlags, EINVAL, SIGKILL}; pub use self::syscall::{ data, error, flag, io, number, ptrace_event, EnvRegisters, FloatRegisters, IntRegisters, @@ -174,6 +174,12 @@ pub fn syscall(a: usize, b: usize, c: usize, d: usize, e: usize, f: usize) -> us } SYS_CLOSE => close(fd).map(|()| 0), + SYS_CALL => call( + fd, + UserSlice::rw(c, d)?, + CallFlags::from_bits(e & !0xff).ok_or(Error::new(EINVAL))?, + UserSlice::ro(f, (e & 0xff) * 8)?, + ), SYS_OPEN => open(UserSlice::ro(b, c)?, d).map(FileHandle::into), SYS_RMDIR => rmdir(UserSlice::ro(b, c)?).map(|()| 0), diff --git a/src/syscall/usercopy.rs b/src/syscall/usercopy.rs index 2c0c5ba2d1..84d1190978 100644 --- a/src/syscall/usercopy.rs +++ b/src/syscall/usercopy.rs @@ -17,6 +17,7 @@ pub struct UserSlice { } pub type UserSliceRo = UserSlice; pub type UserSliceWo = UserSlice; +pub type UserSliceRw = UserSlice; impl UserSlice { pub fn empty() -> Self { @@ -207,6 +208,11 @@ impl UserSliceWo { Self::new(base, size) } } +impl UserSliceRw { + pub fn rw(base: usize, size: usize) -> Result { + Self::new(base, size) + } +} fn is_kernel_mem(slice: &[u8]) -> bool { (slice.as_ptr() as usize) >= crate::USER_END_OFFSET