Implement bidirectional SYS_CALL support

This commit is contained in:
Jacob Lorentzon
2025-03-03 23:21:56 +00:00
committed by Jeremy Soller
parent 8f24d894eb
commit 4607576006
7 changed files with 118 additions and 49 deletions
Generated
+2 -2
View File
@@ -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",
]
+11 -2
View File
@@ -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<usize> {
Err(Error::new(EOPNOTSUPP))
}
}
#[derive(Debug)]
+65 -42
View File
@@ -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<RwSpinlock<Context>>,
user_buf: UserSlice<READ, WRITE>,
) -> Result<CaptureGuard<READ, WRITE>> {
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::<true, false>()
.copy_to_slice(slice)?;
}
Mode::Wo => {
array.buf_mut().fill(0_u8);
}
head_part_of_buf
.reinterpret_unchecked::<true, false>()
.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::<true, false>()
.copy_to_slice(to_copy)?;
}
Mode::Wo => {
array.buf_mut().fill(0_u8);
}
// FIXME: remove reinterpret_unchecked
tail_part_of_buf
.reinterpret_unchecked::<true, false>()
.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<usize> {
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 {
+7
View File
@@ -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::<Result<Vec<usize>>>()),
),
SYS_CLOCK_GETTIME => format!("clock_gettime({}, {:?})", b, unsafe {
read_struct::<TimeSpec>(c)
+20 -2
View File
@@ -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<T>(
fd: FileHandle,
@@ -248,6 +248,24 @@ pub fn dup2(fd: FileHandle, new_fd: FileHandle, buf: UserSliceRo) -> Result<File
.ok_or(Error::new(EMFILE))
}
}
pub fn call(
fd: FileHandle,
payload: UserSliceRw,
flags: CallFlags,
metadata: UserSliceRo,
) -> Result<usize> {
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<usize> {
let requested_flags = SendFdFlags::from_bits(flags_raw).ok_or(Error::new(EINVAL))?;
+7 -1
View File
@@ -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),
+6
View File
@@ -17,6 +17,7 @@ pub struct UserSlice<const READ: bool, const WRITE: bool> {
}
pub type UserSliceRo = UserSlice<true, false>;
pub type UserSliceWo = UserSlice<false, true>;
pub type UserSliceRw = UserSlice<true, true>;
impl<const READ: bool, const WRITE: bool> UserSlice<READ, WRITE> {
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> {
Self::new(base, size)
}
}
fn is_kernel_mem(slice: &[u8]) -> bool {
(slice.as_ptr() as usize) >= crate::USER_END_OFFSET