Improved scheme protocol.

This commit is contained in:
Jacob Lorentzon
2024-06-14 11:31:51 +00:00
committed by Jeremy Soller
parent e9ba024aaa
commit bf0fc66ac1
23 changed files with 874 additions and 748 deletions
Generated
+10
View File
@@ -131,6 +131,7 @@ dependencies = [
"rmm",
"rustc-cfg",
"rustc-demangle",
"slab",
"slab_allocator",
"spin 0.9.8",
"spinning_top 0.3.0",
@@ -287,6 +288,15 @@ dependencies = [
"serde",
]
[[package]]
name = "slab"
version = "0.4.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67"
dependencies = [
"autocfg",
]
[[package]]
name = "slab_allocator"
version = "0.3.1"
+1
View File
@@ -22,6 +22,7 @@ spin = "0.9.8"
spinning_top = { version = "0.3", features = ["arc_lock"] }
rmm = { path = "rmm", default-features = false }
arrayvec = { version = "0.7.4", default-features = false }
slab = { version = "0.4", default-features = false }
[dependencies.goblin]
version = "0.2.1"
+28 -3
View File
@@ -7,18 +7,43 @@ use crate::{
};
use alloc::sync::Arc;
use spin::RwLock;
use syscall::{schemev2::NewFdFlags, RwFlags, O_APPEND, O_NONBLOCK};
/// A file description
#[derive(Clone, Copy, Debug)]
pub struct FileDescription {
/// The namespace the file was opened from (used for debugging)
pub namespace: SchemeNamespace,
/// The current file offset (seek)
pub offset: u64,
/// The scheme that this file refers to
pub scheme: SchemeId,
/// The number the scheme uses to refer to this file
pub number: usize,
/// The flags passed to open or fcntl(SETFL)
pub flags: usize,
pub flags: u32,
pub internal_flags: InternalFlags,
}
bitflags! {
#[derive(Clone, Copy, Debug)]
pub struct InternalFlags: u32 {
const POSITIONED = 1;
}
}
impl FileDescription {
pub fn rw_flags(&self, rw: RwFlags) -> u32 {
let mut ret = self.flags & !(O_NONBLOCK | O_APPEND) as u32;
if rw.contains(RwFlags::APPEND) {
ret |= O_APPEND as u32;
}
if rw.contains(RwFlags::NONBLOCK) {
ret |= O_NONBLOCK as u32;
}
ret
}
}
impl InternalFlags {
pub fn from_extra0(fl: u8) -> Option<Self> {
Some(NewFdFlags::from_bits(fl)?.iter().map(|fd| if fd == NewFdFlags::POSITIONED { Self::POSITIONED } else { Self::empty() }).collect())
}
}
/// A file descriptor
+2 -2
View File
@@ -30,8 +30,8 @@ impl EventQueue {
}
}
pub fn read(&self, buf: UserSliceWo) -> Result<usize> {
self.queue.receive_into_user(buf, true, "EventQueue::read")
pub fn read(&self, buf: UserSliceWo, block: bool) -> Result<usize> {
self.queue.receive_into_user(buf, block, "EventQueue::read")
}
pub fn write(&self, events: &[Event]) -> Result<usize> {
+2 -2
View File
@@ -3,6 +3,8 @@
//! The Redox OS Kernel is a microkernel that supports `x86_64` systems and
//! provides Unix-like syscalls for primarily Rust applications
// Necessary for alternative! macro.
#![allow(unexpected_cfgs)]
// Useful for adding comments about different branches
#![allow(clippy::if_same_then_else)]
// Useful in the syscall function
@@ -40,14 +42,12 @@
// Ensure that all must_use results are used
#![deny(unused_must_use)]
#![feature(allocator_api)]
#![feature(array_methods)]
#![feature(asm_const)] // TODO: Relax requirements of most asm invocations
#![feature(int_roundings)]
#![feature(iter_next_chunk)]
#![feature(let_chains)]
#![feature(naked_functions)]
#![feature(new_uninit)]
#![feature(offset_of)]
#![feature(sync_unsafe_cell)]
#![feature(variant_count)]
#![no_std]
+20 -55
View File
@@ -9,9 +9,7 @@ use alloc::{boxed::Box, collections::BTreeMap};
use spin::{Mutex, Once, RwLock};
use crate::{
acpi::{RxsdtEnum, RXSDT_ENUM},
event,
sync::WaitCondition,
acpi::{RxsdtEnum, RXSDT_ENUM}, context::file::InternalFlags, event, sync::WaitCondition
};
use crate::syscall::{
@@ -30,7 +28,6 @@ use super::{CallerCtx, GlobalSchemes, KernelScheme, OpenResult};
pub struct AcpiScheme;
struct Handle {
offset: usize,
kind: HandleKind,
stat: bool,
}
@@ -121,25 +118,25 @@ impl KernelScheme for AcpiScheme {
if flags & O_ACCMODE != O_RDONLY && flags & O_STAT != O_STAT {
return Err(Error::new(EROFS));
}
let handle_kind = match path {
let (handle_kind, int_flags) = match path {
"" => {
if flags & O_DIRECTORY != O_DIRECTORY && flags & O_STAT != O_STAT {
return Err(Error::new(EISDIR));
}
HandleKind::TopLevel
(HandleKind::TopLevel, InternalFlags::POSITIONED)
}
"rxsdt" => {
if flags & O_DIRECTORY == O_DIRECTORY && flags & O_STAT != O_STAT {
return Err(Error::new(ENOTDIR));
}
HandleKind::Rxsdt
(HandleKind::Rxsdt, InternalFlags::POSITIONED)
}
"kstop" => {
if flags & O_DIRECTORY == O_DIRECTORY && flags & O_STAT != O_STAT {
return Err(Error::new(ENOTDIR));
}
HandleKind::ShutdownPipe
(HandleKind::ShutdownPipe, InternalFlags::empty())
}
_ => return Err(Error::new(ENOENT)),
};
@@ -150,15 +147,15 @@ impl KernelScheme for AcpiScheme {
let _ = handles_guard.insert(
fd,
Handle {
offset: 0,
kind: handle_kind,
// TODO: Redundant
stat: flags & O_STAT == O_STAT,
},
);
Ok(OpenResult::SchemeLocal(fd))
Ok(OpenResult::SchemeLocal(fd, int_flags))
}
fn seek(&self, id: usize, pos: isize, whence: usize) -> Result<usize> {
fn fsize(&self, id: usize) -> Result<u64> {
let mut handles = HANDLES.write();
let handle = handles.get_mut(&id).ok_or(Error::new(EBADF))?;
@@ -166,39 +163,11 @@ impl KernelScheme for AcpiScheme {
return Err(Error::new(EBADF));
}
let file_len = match handle.kind {
HandleKind::Rxsdt => DATA.get().ok_or(Error::new(EBADFD))?.len(),
Ok(match handle.kind {
HandleKind::Rxsdt => DATA.get().ok_or(Error::new(EBADFD))?.len() as u64,
HandleKind::ShutdownPipe => 1,
HandleKind::TopLevel => TOPLEVEL_CONTENTS.len(),
};
let new_offset = match whence {
SEEK_SET => pos as usize,
SEEK_CUR => {
if pos < 0 {
handle
.offset
.checked_sub((-pos) as usize)
.ok_or(Error::new(EINVAL))?
} else {
handle.offset.saturating_add(pos as usize)
}
}
SEEK_END => {
if pos < 0 {
file_len
.checked_sub((-pos) as usize)
.ok_or(Error::new(EINVAL))?
} else {
file_len
}
}
_ => return Err(Error::new(EINVAL)),
};
handle.offset = new_offset;
Ok(new_offset)
HandleKind::TopLevel => TOPLEVEL_CONTENTS.len() as u64,
})
}
// TODO
fn fevent(&self, id: usize, _flags: EventFlags) -> Result<EventFlags> {
@@ -217,10 +186,11 @@ impl KernelScheme for AcpiScheme {
}
Ok(())
}
fn kwrite(&self, _id: usize, _buf: UserSliceRo) -> Result<usize> {
Err(Error::new(EBADF))
}
fn kread(&self, id: usize, dst_buf: UserSliceWo) -> Result<usize> {
fn kreadoff(&self, id: usize, dst_buf: UserSliceWo, offset: u64, flags: u32, stored_flags: u32) -> Result<usize> {
let Ok(offset) = usize::try_from(offset) else {
return Ok(0);
};
let mut handles = HANDLES.write();
let handle = handles.get_mut(&id).ok_or(Error::new(EBADF))?;
@@ -244,23 +214,18 @@ impl KernelScheme for AcpiScheme {
}
}
dst_buf.copy_exactly(&[0x42])?;
handle.offset = 1;
return Ok(1);
return dst_buf.copy_exactly(&[0x42]).map(|()| 1);
}
HandleKind::Rxsdt => DATA.get().ok_or(Error::new(EBADFD))?,
HandleKind::TopLevel => TOPLEVEL_CONTENTS,
};
let src_offset = core::cmp::min(handle.offset, data.len());
let src_offset = core::cmp::min(offset, data.len());
let src_buf = data
.get(src_offset..)
.expect("expected data to be at least data.len() bytes long");
let bytes_copied = dst_buf.copy_common_bytes_from_slice(src_buf)?;
handle.offset += bytes_copied;
Ok(bytes_copied)
dst_buf.copy_common_bytes_from_slice(src_buf)
}
fn kfstat(&self, id: usize, buf: UserSliceWo) -> Result<()> {
let handles = HANDLES.read();
+5 -23
View File
@@ -19,7 +19,6 @@ static INPUT: WaitQueue<u8> = WaitQueue::new();
#[derive(Clone, Copy)]
struct Handle {
flags: usize,
num: usize,
}
@@ -41,7 +40,7 @@ pub fn debug_notify() {
pub struct DebugScheme;
impl KernelScheme for DebugScheme {
fn kopen(&self, path: &str, flags: usize, ctx: CallerCtx) -> Result<OpenResult> {
fn kopen(&self, path: &str, _flags: usize, ctx: CallerCtx) -> Result<OpenResult> {
if ctx.uid != 0 {
return Err(Error::new(EPERM));
}
@@ -61,28 +60,11 @@ impl KernelScheme for DebugScheme {
HANDLES.write().insert(
id,
Handle {
flags: flags & !O_ACCMODE,
num,
},
);
Ok(OpenResult::SchemeLocal(id))
}
fn fcntl(&self, id: usize, cmd: usize, arg: usize) -> Result<usize> {
let mut handles = HANDLES.write();
if let Some(handle) = handles.get_mut(&id) {
match cmd {
F_GETFL => Ok(handle.flags),
F_SETFL => {
handle.flags = arg & !O_ACCMODE;
Ok(0)
}
_ => Err(Error::new(EINVAL)),
}
} else {
Err(Error::new(EBADF))
}
Ok(OpenResult::SchemeLocal(id, InternalFlags::empty()))
}
fn fevent(&self, id: usize, _flags: EventFlags) -> Result<EventFlags> {
@@ -112,7 +94,7 @@ impl KernelScheme for DebugScheme {
Ok(())
}
fn kread(&self, id: usize, buf: UserSliceWo) -> Result<usize> {
fn kread(&self, id: usize, buf: UserSliceWo, flags: u32, _stored_flags: u32) -> Result<usize> {
let handle = {
let handles = HANDLES.read();
*handles.get(&id).ok_or(Error::new(EBADF))?
@@ -128,12 +110,12 @@ impl KernelScheme for DebugScheme {
INPUT.receive_into_user(
buf,
handle.flags & O_NONBLOCK != O_NONBLOCK,
flags & O_NONBLOCK as u32 == 0,
"DebugScheme::read",
)
}
fn kwrite(&self, id: usize, buf: UserSliceRo) -> Result<usize> {
fn kwrite(&self, id: usize, buf: UserSliceRo, _flags: u32, _stored_flags: u32) -> Result<usize> {
let handle = {
let handles = HANDLES.read();
*handles.get(&id).ok_or(Error::new(EBADF))?
+7 -21
View File
@@ -1,13 +1,13 @@
use alloc::sync::Arc;
use syscall::O_NONBLOCK;
use core::mem;
use crate::{
event::{next_queue_id, queues, queues_mut, EventQueue, EventQueueId},
syscall::{
context::file::InternalFlags, event::{next_queue_id, queues, queues_mut, EventQueue, EventQueueId}, syscall::{
data::Event,
error::*,
usercopy::{UserSliceRo, UserSliceWo},
},
}
};
use super::{CallerCtx, KernelScheme, OpenResult};
@@ -19,21 +19,7 @@ impl KernelScheme for EventScheme {
let id = next_queue_id();
queues_mut().insert(id, Arc::new(EventQueue::new(id)));
Ok(OpenResult::SchemeLocal(id.get()))
}
fn fcntl(&self, id: usize, _cmd: usize, _arg: usize) -> Result<usize> {
let id = EventQueueId::from(id);
let handles = queues();
handles.get(&id).ok_or(Error::new(EBADF)).and(Ok(0))
}
fn fsync(&self, id: usize) -> Result<()> {
let id = EventQueueId::from(id);
let handles = queues();
handles.get(&id).ok_or(Error::new(EBADF)).and(Ok(()))
Ok(OpenResult::SchemeLocal(id.get(), InternalFlags::empty()))
}
fn close(&self, id: usize) -> Result<()> {
@@ -43,7 +29,7 @@ impl KernelScheme for EventScheme {
.ok_or(Error::new(EBADF))
.and(Ok(()))
}
fn kread(&self, id: usize, buf: UserSliceWo) -> Result<usize> {
fn kread(&self, id: usize, buf: UserSliceWo, flags: u32, _stored_flags: u32) -> Result<usize> {
let id = EventQueueId::from(id);
let queue = {
@@ -52,10 +38,10 @@ impl KernelScheme for EventScheme {
handle.clone()
};
queue.read(buf)
queue.read(buf, flags & O_NONBLOCK as u32 == 0)
}
fn kwrite(&self, id: usize, buf: UserSliceRo) -> Result<usize> {
fn kwrite(&self, id: usize, buf: UserSliceRo, flags: u32, _stored_flags: u32) -> Result<usize> {
let id = EventQueueId::from(id);
let queue = {
+52 -60
View File
@@ -1,3 +1,6 @@
// TODO: Rewrite this entire scheme. Legacy x86 APIs should be abstracted by a userspace scheme,
// this scheme should only handle raw IRQ registration and delivery to userspace.
use core::{
mem, str,
str::FromStr,
@@ -8,7 +11,7 @@ use alloc::{collections::BTreeMap, string::String, vec::Vec};
use spin::{Mutex, Once, RwLock};
use crate::arch::interrupt::{available_irqs_iter, bsp_apic_id, is_reserved, set_reserved};
use crate::{arch::interrupt::{available_irqs_iter, bsp_apic_id, is_reserved, set_reserved}, context::file::InternalFlags};
use crate::{
cpu_set::LogicalCpuId,
@@ -22,7 +25,7 @@ use crate::{
},
};
use super::{calc_seek_offset, CallerCtx, GlobalSchemes, OpenResult};
use super::{CallerCtx, GlobalSchemes, OpenResult};
/// IRQ queues
pub(super) static COUNTS: Mutex<[usize; 224]> = Mutex::new([0; 224]);
@@ -62,8 +65,8 @@ pub extern "C" fn irq_trigger(irq: u8) {
enum Handle {
Irq { ack: AtomicUsize, irq: u8 },
Avail(u8, Vec<u8>, AtomicUsize), // CPU id, data, offset
TopLevel(Vec<u8>, AtomicUsize), // data, offset
Avail(u8, Vec<u8>), // CPU id, data, offset
TopLevel(Vec<u8>), // data, offset
Bsp,
}
impl Handle {
@@ -105,7 +108,7 @@ impl IrqScheme {
CPUS.call_once(|| cpus);
}
fn open_ext_irq(flags: usize, cpu_id: u8, path_str: &str) -> Result<Handle> {
fn open_ext_irq(flags: usize, cpu_id: u8, path_str: &str) -> Result<(Handle, InternalFlags)> {
let irq_number = u8::from_str(path_str).or(Err(Error::new(ENOENT)))?;
Ok(
@@ -114,10 +117,10 @@ impl IrqScheme {
//
// The only CPUs don't have the legacy IRQs in their IDTs.
Handle::Irq {
(Handle::Irq {
ack: AtomicUsize::new(0),
irq: irq_number,
}
}, InternalFlags::empty())
} else if irq_number < TOTAL_IRQ_COUNT {
if flags & O_CREAT == 0 && flags & O_STAT == 0 {
return Err(Error::new(EINVAL));
@@ -132,10 +135,10 @@ impl IrqScheme {
true,
);
}
Handle::Irq {
(Handle::Irq {
ack: AtomicUsize::new(0),
irq: irq_number,
}
}, InternalFlags::empty())
} else {
return Err(Error::new(ENOENT));
},
@@ -158,7 +161,7 @@ impl crate::scheme::KernelScheme for IrqScheme {
let path_str = path.trim_start_matches('/');
let handle: Handle = if path_str.is_empty() {
let (handle, int_flags) = if path_str.is_empty() {
if flags & O_DIRECTORY == 0 && flags & O_STAT == 0 {
return Err(Error::new(EISDIR));
}
@@ -180,13 +183,13 @@ impl crate::scheme::KernelScheme for IrqScheme {
// TODO: When signals are used for IRQs, there will probably also be a file
// `irq:signal` that maps IRQ numbers and their source APIC IDs to signal numbers.
Handle::TopLevel(bytes.into_bytes(), AtomicUsize::new(0))
(Handle::TopLevel(bytes.into_bytes()), InternalFlags::POSITIONED)
} else {
if path_str == "bsp" {
if bsp_apic_id().is_none() {
return Err(Error::new(ENOENT));
}
Handle::Bsp
(Handle::Bsp, InternalFlags::empty())
} else if path_str.starts_with("cpu-") {
let path_str = &path_str[4..];
let cpu_id = u8::from_str_radix(&path_str[..2], 16).or(Err(Error::new(ENOENT)))?;
@@ -204,7 +207,7 @@ impl crate::scheme::KernelScheme for IrqScheme {
writeln!(data, "{}", irq).unwrap();
}
Handle::Avail(cpu_id, data.into_bytes(), AtomicUsize::new(0))
(Handle::Avail(cpu_id, data.into_bytes()), InternalFlags::POSITIONED)
} else if path_str.starts_with('/') {
let path_str = &path_str[1..];
Self::open_ext_irq(flags, cpu_id, path_str)?
@@ -213,10 +216,10 @@ impl crate::scheme::KernelScheme for IrqScheme {
}
} else if let Ok(plain_irq_number) = u8::from_str(path_str) {
if plain_irq_number < BASE_IRQ_COUNT {
Handle::Irq {
(Handle::Irq {
ack: AtomicUsize::new(0),
irq: plain_irq_number,
}
}, InternalFlags::empty())
} else {
return Err(Error::new(ENOENT));
}
@@ -226,20 +229,15 @@ impl crate::scheme::KernelScheme for IrqScheme {
};
let fd = NEXT_FD.fetch_add(1, Ordering::Relaxed);
HANDLES.write().insert(fd, handle);
Ok(OpenResult::SchemeLocal(fd))
Ok(OpenResult::SchemeLocal(fd, int_flags))
}
fn seek(&self, id: usize, pos: isize, whence: usize) -> Result<usize> {
fn fsize(&self, id: usize) -> Result<u64> {
let handles_guard = HANDLES.read();
let handle = handles_guard.get(&id).ok_or(Error::new(EBADF))?;
match handle {
&Handle::Avail(_, ref buf, ref offset) | &Handle::TopLevel(ref buf, ref offset) => {
let cur_offset = offset.load(Ordering::SeqCst);
let new_offset = calc_seek_offset(cur_offset, pos, whence, buf.len())?;
offset.store(new_offset as usize, Ordering::SeqCst);
Ok(new_offset as usize)
}
match *handle {
Handle::Avail(_, ref buf) | Handle::TopLevel(ref buf) => Ok(buf.len() as u64),
_ => Err(Error::new(ESPIPE)),
}
}
@@ -270,7 +268,7 @@ impl crate::scheme::KernelScheme for IrqScheme {
}
Ok(())
}
fn kwrite(&self, file: usize, buffer: UserSliceRo) -> Result<usize> {
fn kwrite(&self, file: usize, buffer: UserSliceRo, _flags: u32, _stored_flags: u32) -> Result<usize> {
let handles_guard = HANDLES.read();
let handle = handles_guard.get(&file).ok_or(Error::new(EBADF))?;
@@ -279,22 +277,20 @@ impl crate::scheme::KernelScheme for IrqScheme {
irq: handle_irq,
ack: ref handle_ack,
} => {
if buffer.len() >= mem::size_of::<usize>() {
let ack = buffer.read_usize()?;
let current = COUNTS.lock()[handle_irq as usize];
if ack == current {
handle_ack.store(ack, Ordering::SeqCst);
unsafe {
acknowledge(handle_irq as usize);
}
Ok(mem::size_of::<usize>())
} else {
Ok(0)
}
} else {
Err(Error::new(EINVAL))
if buffer.len() < mem::size_of::<usize>() {
return Err(Error::new(EINVAL));
}
let ack = buffer.read_usize()?;
let current = COUNTS.lock()[handle_irq as usize];
if ack != current {
return Ok(0);
}
handle_ack.store(ack, Ordering::SeqCst);
unsafe {
acknowledge(handle_irq as usize);
}
Ok(mem::size_of::<usize>())
}
_ => Err(Error::new(EBADF)),
}
@@ -325,14 +321,14 @@ impl crate::scheme::KernelScheme for IrqScheme {
st_nlink: 1,
..Default::default()
},
Handle::Avail(cpu_id, ref buf, _) => Stat {
Handle::Avail(cpu_id, ref buf) => Stat {
st_mode: MODE_DIR | 0o700,
st_size: buf.len() as u64,
st_ino: INO_AVAIL | u64::from(cpu_id) << 32,
st_nlink: 2,
..Default::default()
},
Handle::TopLevel(ref buf, _) => Stat {
Handle::TopLevel(ref buf) => Stat {
st_mode: MODE_DIR | 0o500,
st_size: buf.len() as u64,
st_ino: INO_TOPLEVEL,
@@ -350,14 +346,14 @@ impl crate::scheme::KernelScheme for IrqScheme {
let scheme_path = match handle {
Handle::Irq { irq, .. } => format!("irq:{}", irq),
Handle::Bsp => format!("irq:bsp"),
Handle::Avail(cpu_id, _, _) => format!("irq:cpu-{:2x}", cpu_id),
Handle::TopLevel(_, _) => format!("irq:"),
Handle::Avail(cpu_id, _) => format!("irq:cpu-{:2x}", cpu_id),
Handle::TopLevel(_) => format!("irq:"),
}
.into_bytes();
buf.copy_common_bytes_from_slice(&scheme_path)
}
fn kread(&self, file: usize, buffer: UserSliceWo) -> Result<usize> {
fn kreadoff(&self, file: usize, buffer: UserSliceWo, offset: u64, flags: u32, _stored_flags: u32) -> Result<usize> {
let handles_guard = HANDLES.read();
let handle = handles_guard.get(&file).ok_or(Error::new(EBADF))?;
@@ -367,16 +363,15 @@ impl crate::scheme::KernelScheme for IrqScheme {
irq: handle_irq,
ack: ref handle_ack,
} => {
if buffer.len() >= mem::size_of::<usize>() {
let current = COUNTS.lock()[handle_irq as usize];
if handle_ack.load(Ordering::SeqCst) != current {
buffer.write_usize(current)?;
Ok(mem::size_of::<usize>())
} else {
Ok(0)
}
if buffer.len() < mem::size_of::<usize>() {
return Err(Error::new(EINVAL));
}
let current = COUNTS.lock()[handle_irq as usize];
if handle_ack.load(Ordering::SeqCst) != current {
buffer.write_usize(current)?;
Ok(mem::size_of::<usize>())
} else {
Err(Error::new(EINVAL))
Ok(0)
}
}
Handle::Bsp => {
@@ -390,12 +385,9 @@ impl crate::scheme::KernelScheme for IrqScheme {
Err(Error::new(EBADFD))
}
}
Handle::Avail(_, ref buf, ref offset) | Handle::TopLevel(ref buf, ref offset) => {
let cur_offset = offset.load(Ordering::SeqCst);
let avail_buf = buf.get(cur_offset..).unwrap_or(&[]);
let bytes_read = buffer.copy_common_bytes_from_slice(avail_buf)?;
offset.fetch_add(bytes_read, Ordering::SeqCst);
Ok(bytes_read)
Handle::Avail(_, ref buf) | Handle::TopLevel(ref buf) => {
let src = usize::try_from(offset).ok().and_then(|o| buf.get(o..)).unwrap_or(&[]);
buffer.copy_common_bytes_from_slice(src)
}
}
}
+5 -5
View File
@@ -5,12 +5,12 @@ use core::{
};
use spin::RwLock;
use crate::syscall::{
use crate::{context::file::InternalFlags, syscall::{
data::ITimerSpec,
error::*,
flag::{EventFlags, CLOCK_MONOTONIC, CLOCK_REALTIME},
usercopy::{UserSliceRo, UserSliceWo},
};
}};
use super::{CallerCtx, KernelScheme, OpenResult};
pub struct ITimerScheme;
@@ -32,7 +32,7 @@ impl KernelScheme for ITimerScheme {
let id = NEXT_ID.fetch_add(1, Ordering::Relaxed);
HANDLES.write().insert(id, clock);
Ok(OpenResult::SchemeLocal(id))
Ok(OpenResult::SchemeLocal(id, InternalFlags::empty()))
}
fn fcntl(&self, _id: usize, _cmd: usize, _arg: usize) -> Result<usize> {
@@ -58,7 +58,7 @@ impl KernelScheme for ITimerScheme {
.ok_or(Error::new(EBADF))
.and(Ok(()))
}
fn kread(&self, id: usize, buf: UserSliceWo) -> Result<usize> {
fn kread(&self, id: usize, buf: UserSliceWo, _flags: u32, _stored_flags: u32) -> Result<usize> {
let _clock = {
let handles = HANDLES.read();
*handles.get(&id).ok_or(Error::new(EBADF))?
@@ -75,7 +75,7 @@ impl KernelScheme for ITimerScheme {
Ok(specs_read * mem::size_of::<ITimerSpec>())
}
fn kwrite(&self, id: usize, buf: UserSliceRo) -> Result<usize> {
fn kwrite(&self, id: usize, buf: UserSliceRo, _flags: u32, _stored_flags: u32) -> Result<usize> {
let _clock = {
let handles = HANDLES.read();
*handles.get(&id).ok_or(Error::new(EBADF))?
+2 -8
View File
@@ -4,7 +4,7 @@ use alloc::{sync::Arc, vec::Vec};
use rmm::PhysicalAddress;
use crate::{
context::memory::{handle_notify_files, AddrSpace, Grant, PageSpan, AddrSpaceWrapper},
context::{file::InternalFlags, memory::{handle_notify_files, AddrSpace, AddrSpaceWrapper, Grant, PageSpan}},
memory::{free_frames, used_frames, Frame, PAGE_SIZE},
paging::VirtualAddress,
};
@@ -223,16 +223,10 @@ impl KernelScheme for MemoryScheme {
Ok(OpenResult::SchemeLocal(
(handle_ty as usize) | ((mem_ty as usize) << 8) | (usize::from(flags.bits()) << 16),
InternalFlags::empty(),
))
}
fn fcntl(&self, _id: usize, _cmd: usize, _arg: usize) -> Result<usize> {
Ok(0)
}
fn close(&self, _id: usize) -> Result<()> {
Ok(())
}
fn kfmap(
&self,
id: usize,
+24 -26
View File
@@ -13,7 +13,7 @@ use spin::{Once, RwLock, RwLockReadGuard, RwLockWriteGuard};
use syscall::{EventFlags, MunmapFlags, SendFdFlags, SEEK_CUR, SEEK_END, SEEK_SET};
use crate::{
context::{file::FileDescription, memory::AddrSpaceWrapper},
context::{file::{FileDescription, InternalFlags}, memory::AddrSpaceWrapper},
syscall::{
error::*,
usercopy::{UserSliceRo, UserSliceWo},
@@ -394,10 +394,22 @@ pub trait KernelScheme: Send + Sync + 'static {
fn kdup(&self, old_id: usize, buf: UserSliceRo, _caller: CallerCtx) -> Result<OpenResult> {
Err(Error::new(EOPNOTSUPP))
}
fn kwrite(&self, id: usize, buf: UserSliceRo) -> Result<usize> {
fn kwriteoff(&self, id: usize, buf: UserSliceRo, offset: u64, flags: u32, stored_flags: u32) -> Result<usize> {
if offset != u64::MAX {
return Err(Error::new(ESPIPE));
}
self.kwrite(id, buf, flags, stored_flags)
}
fn kreadoff(&self, id: usize, buf: UserSliceWo, offset: u64, flags: u32, stored_flags: u32) -> Result<usize> {
if offset != u64::MAX {
return Err(Error::new(ESPIPE));
}
self.kread(id, buf, flags, stored_flags)
}
fn kwrite(&self, id: usize, buf: UserSliceRo, flags: u32, stored_flags: u32) -> Result<usize> {
Err(Error::new(EBADF))
}
fn kread(&self, id: usize, buf: UserSliceWo) -> Result<usize> {
fn kread(&self, id: usize, buf: UserSliceWo, flags: u32, stored_flags: u32) -> Result<usize> {
Err(Error::new(EBADF))
}
fn kfpath(&self, id: usize, buf: UserSliceWo) -> Result<usize> {
@@ -424,14 +436,17 @@ pub trait KernelScheme: Send + Sync + 'static {
}
fn fsync(&self, id: usize) -> Result<()> {
Err(Error::new(EBADF))
Ok(())
}
fn ftruncate(&self, id: usize, len: usize) -> Result<()> {
Err(Error::new(EBADF))
}
fn seek(&self, id: usize, pos: isize, whence: usize) -> Result<usize> {
fn fsize(&self, id: usize) -> Result<u64> {
Err(Error::new(ESPIPE))
}
fn legacy_seek(&self, id: usize, pos: isize, whence: usize) -> Option<Result<usize>> {
None
}
fn fchmod(&self, id: usize, new_mode: u16) -> Result<()> {
Err(Error::new(EBADF))
}
@@ -439,13 +454,13 @@ pub trait KernelScheme: Send + Sync + 'static {
Err(Error::new(EBADF))
}
fn fevent(&self, id: usize, flags: EventFlags) -> Result<EventFlags> {
Err(Error::new(EBADF))
Ok(EventFlags::empty())
}
fn frename(&self, id: usize, new_path: &str, caller_ctx: CallerCtx) -> Result<()> {
Err(Error::new(EBADF))
}
fn fcntl(&self, id: usize, cmd: usize, arg: usize) -> Result<usize> {
Err(Error::new(EBADF))
Ok(0)
}
fn rmdir(&self, path: &str, ctx: CallerCtx) -> Result<()> {
Err(Error::new(ENOENT))
@@ -454,13 +469,13 @@ pub trait KernelScheme: Send + Sync + 'static {
Err(Error::new(ENOENT))
}
fn close(&self, id: usize) -> Result<()> {
Err(Error::new(EBADF))
Ok(())
}
}
#[derive(Debug)]
pub enum OpenResult {
SchemeLocal(usize),
SchemeLocal(usize, InternalFlags),
External(Arc<RwLock<FileDescription>>),
}
pub struct CallerCtx {
@@ -469,23 +484,6 @@ pub struct CallerCtx {
pub gid: u32,
}
pub fn calc_seek_offset(
cur_pos: usize,
rel_pos: isize,
whence: usize,
len: usize,
) -> Result<usize> {
match whence {
SEEK_SET => usize::try_from(rel_pos).map_err(|_| Error::new(EINVAL)),
SEEK_CUR => cur_pos
.checked_add_signed(rel_pos)
.ok_or(Error::new(EOVERFLOW)),
SEEK_END => len.checked_add_signed(rel_pos).ok_or(Error::new(EOVERFLOW)),
_ => return Err(Error::new(EINVAL)),
}
}
#[derive(Clone)]
pub enum KernelSchemes {
Root(Arc<RootScheme>),
+11 -44
View File
@@ -8,16 +8,14 @@ use alloc::{
use spin::{Mutex, RwLock};
use crate::{
event,
sync::WaitCondition,
syscall::{
context::file::InternalFlags, event, sync::WaitCondition, syscall::{
data::Stat,
error::{Error, Result, EAGAIN, EBADF, EINTR, EINVAL, ENOENT, EPIPE, ESPIPE},
flag::{
EventFlags, EVENT_READ, EVENT_WRITE, F_GETFL, F_SETFL, MODE_FIFO, O_ACCMODE, O_NONBLOCK,
},
usercopy::{UserSliceRo, UserSliceWo},
},
}
};
use super::{CallerCtx, GlobalSchemes, KernelScheme, OpenResult};
@@ -40,14 +38,12 @@ fn from_raw_id(id: usize) -> (bool, usize) {
(id & WRITE_NOT_READ_BIT != 0, id & !WRITE_NOT_READ_BIT)
}
pub fn pipe(flags: usize) -> Result<(usize, usize)> {
pub fn pipe() -> Result<(usize, usize)> {
let id = PIPE_NEXT_ID.fetch_add(1, Ordering::Relaxed);
PIPES.write().insert(
id,
Arc::new(Pipe {
read_flags: AtomicUsize::new(flags),
write_flags: AtomicUsize::new(flags),
queue: Mutex::new(VecDeque::new()),
read_condition: WaitCondition::new(),
write_condition: WaitCondition::new(),
@@ -63,26 +59,6 @@ pub fn pipe(flags: usize) -> Result<(usize, usize)> {
pub struct PipeScheme;
impl KernelScheme for PipeScheme {
fn fcntl(&self, id: usize, cmd: usize, arg: usize) -> Result<usize> {
let (is_writer_not_reader, key) = from_raw_id(id);
let pipe = Arc::clone(PIPES.read().get(&key).ok_or(Error::new(EBADF))?);
let flags = if is_writer_not_reader {
&pipe.write_flags
} else {
&pipe.read_flags
};
match cmd {
F_GETFL => Ok(flags.load(Ordering::SeqCst)),
F_SETFL => {
flags.store(arg & !O_ACCMODE, Ordering::SeqCst);
Ok(0)
}
_ => Err(Error::new(EINVAL)),
}
}
fn fevent(&self, id: usize, flags: EventFlags) -> Result<EventFlags> {
let (is_writer_not_reader, key) = from_raw_id(id);
let pipe = Arc::clone(PIPES.read().get(&key).ok_or(Error::new(EBADF))?);
@@ -99,10 +75,6 @@ impl KernelScheme for PipeScheme {
Ok(ready)
}
fn fsync(&self, _id: usize) -> Result<()> {
Ok(())
}
fn close(&self, id: usize) -> Result<()> {
let (is_write_not_read, key) = from_raw_id(id);
@@ -132,9 +104,6 @@ impl KernelScheme for PipeScheme {
Ok(())
}
fn seek(&self, _id: usize, _pos: isize, _whence: usize) -> Result<usize> {
Err(Error::new(ESPIPE))
}
fn kdup(&self, old_id: usize, user_buf: UserSliceRo, _ctx: CallerCtx) -> Result<OpenResult> {
let (is_writer_not_reader, key) = from_raw_id(old_id);
@@ -154,19 +123,19 @@ impl KernelScheme for PipeScheme {
return Err(Error::new(EBADF));
}
Ok(OpenResult::SchemeLocal(key | WRITE_NOT_READ_BIT))
Ok(OpenResult::SchemeLocal(key | WRITE_NOT_READ_BIT, InternalFlags::empty()))
}
fn kopen(&self, path: &str, flags: usize, _ctx: CallerCtx) -> Result<OpenResult> {
fn kopen(&self, path: &str, _flags: usize, _ctx: CallerCtx) -> Result<OpenResult> {
if !path.trim_start_matches('/').is_empty() {
return Err(Error::new(ENOENT));
}
let (read_id, _) = pipe(flags)?;
let (read_id, _) = pipe()?;
Ok(OpenResult::SchemeLocal(read_id))
Ok(OpenResult::SchemeLocal(read_id, InternalFlags::empty()))
}
fn kread(&self, id: usize, user_buf: UserSliceWo) -> Result<usize> {
fn kread(&self, id: usize, user_buf: UserSliceWo, fcntl_flags: u32, _stored_flags: u32) -> Result<usize> {
let (is_write_not_read, key) = from_raw_id(id);
if is_write_not_read {
@@ -209,14 +178,14 @@ impl KernelScheme for PipeScheme {
if !pipe.writer_is_alive.load(Ordering::SeqCst) {
return Ok(0);
} else if pipe.read_flags.load(Ordering::SeqCst) & O_NONBLOCK == O_NONBLOCK {
} else if fcntl_flags & O_NONBLOCK as u32 != 0 {
return Err(Error::new(EAGAIN));
} else if !pipe.read_condition.wait(vec, "PipeRead::read") {
return Err(Error::new(EINTR));
}
}
}
fn kwrite(&self, id: usize, user_buf: UserSliceRo) -> Result<usize> {
fn kwrite(&self, id: usize, user_buf: UserSliceRo, fcntl_flags: u32, _stored_flags: u32) -> Result<usize> {
let (is_write_not_read, key) = from_raw_id(id);
if !is_write_not_read {
@@ -260,7 +229,7 @@ impl KernelScheme for PipeScheme {
if !pipe.reader_is_alive.load(Ordering::SeqCst) {
return Err(Error::new(EPIPE));
} else if pipe.write_flags.load(Ordering::SeqCst) & O_NONBLOCK == O_NONBLOCK {
} else if fcntl_flags & O_NONBLOCK as u32 != 0 {
return Err(Error::new(EAGAIN));
} else if !pipe.write_condition.wait(vec, "PipeWrite::write") {
return Err(Error::new(EINTR));
@@ -278,8 +247,6 @@ impl KernelScheme for PipeScheme {
}
pub struct Pipe {
read_flags: AtomicUsize, // fcntl read flags
write_flags: AtomicUsize, // fcntl write flags
read_condition: WaitCondition, // signals whether there are available bytes to read
write_condition: WaitCondition, // signals whether there is room for additional bytes
queue: Mutex<VecDeque<u8>>,
+72 -75
View File
@@ -1,17 +1,14 @@
use crate::{
arch::paging::{Page, RmmA, RmmArch, VirtualAddress},
context::{
self,
file::FileDescriptor,
memory::{handle_notify_files, Grant, PageSpan, AddrSpaceWrapper},
Context, ContextId, Status, context::{HardBlockedReason, Altstack, SignalHandler},
self, context::{Altstack, HardBlockedReason, SignalHandler}, file::{FileDescriptor, InternalFlags}, memory::{handle_notify_files, AddrSpaceWrapper, Grant, PageSpan}, Context, ContextId, Status
},
memory::PAGE_SIZE,
ptrace,
scheme::{self, FileHandle, KernelScheme},
syscall::{
self,
data::{GrantDesc, Map, PtraceEvent, SigAction, SetSighandlerData, Stat},
data::{GrantDesc, Map, PtraceEvent, SetSighandlerData, SigAction, Stat},
error::*,
flag::*,
usercopy::{UserSliceRo, UserSliceWo},
@@ -37,13 +34,9 @@ use spinning_top::RwSpinlock;
use super::{CallerCtx, GlobalSchemes, KernelSchemes, OpenResult};
fn read_from(dst: UserSliceWo, src: &[u8], offset: &mut usize) -> Result<usize> {
let avail_src = src.get(*offset..).unwrap_or(&[]);
let bytes_copied = dst.copy_common_bytes_from_slice(avail_src)?;
*offset = offset
.checked_add(bytes_copied)
.ok_or(Error::new(EOVERFLOW))?;
Ok(bytes_copied)
fn read_from(dst: UserSliceWo, src: &[u8], offset: u64) -> Result<usize> {
let avail_src = usize::try_from(offset).ok().and_then(|o| src.get(o..)).unwrap_or(&[]);
dst.copy_common_bytes_from_slice(avail_src)
}
fn with_context<F, T>(pid: ContextId, callback: F) -> Result<T>
@@ -198,17 +191,16 @@ struct TraceData {
}
struct StaticData {
buf: Box<[u8]>,
offset: usize,
}
impl StaticData {
fn new(buf: Box<[u8]>) -> Self {
Self { buf, offset: 0 }
Self { buf }
}
}
enum OperationData {
Trace(TraceData),
Static(StaticData),
Offset(usize),
Offset,
Other,
}
impl OperationData {
@@ -264,10 +256,10 @@ static NEXT_ID: AtomicUsize = AtomicUsize::new(1);
// Using BTreeMap as hashbrown doesn't have a const constructor.
static HANDLES: RwLock<BTreeMap<usize, Handle>> = RwLock::new(BTreeMap::new());
fn new_handle(handle: Handle) -> Result<usize> {
fn new_handle((handle, fl): (Handle, InternalFlags)) -> Result<(usize, InternalFlags)> {
let id = NEXT_ID.fetch_add(1, Ordering::Relaxed);
let _ = HANDLES.write().insert(id, handle);
Ok(id)
Ok((id, fl))
}
fn get_context(id: ContextId) -> Result<Arc<RwSpinlock<Context>>> {
@@ -285,46 +277,46 @@ impl<const FULL: bool> ProcScheme<FULL> {
flags: usize,
uid: u32,
gid: u32,
) -> Result<usize> {
let operation = match operation_str {
Some("addrspace") => Operation::AddrSpace {
) -> Result<(usize, InternalFlags)> {
let (operation, positioned) = match operation_str {
Some("addrspace") => (Operation::AddrSpace {
addrspace: Arc::clone(
get_context(pid)?
.read()
.addr_space()
.map_err(|_| Error::new(ENOENT))?,
),
},
Some("filetable") => Operation::Filetable {
}, true),
Some("filetable") => (Operation::Filetable {
filetable: Arc::downgrade(&get_context(pid)?.read().files),
},
Some("current-addrspace") => Operation::CurrentAddrSpace,
Some("current-filetable") => Operation::CurrentFiletable,
Some("regs/float") => Operation::Regs(RegsKind::Float),
Some("regs/int") => Operation::Regs(RegsKind::Int),
Some("regs/env") => Operation::Regs(RegsKind::Env),
Some("trace") => Operation::Trace,
Some("exe") => Operation::Static("exe"),
Some("name") => Operation::Name,
Some("session_id") => Operation::SessionId,
Some("sighandler") => Operation::Sighandler,
Some("sigprocmask") => Operation::Sigprocmask,
Some("sigignmask") => Operation::Sigignmask,
Some("start") => Operation::Start,
Some("uid") => Operation::Attr(Attr::Uid),
Some("gid") => Operation::Attr(Attr::Gid),
Some("open_via_dup") => Operation::OpenViaDup,
}, true),
Some("current-addrspace") => (Operation::CurrentAddrSpace, false),
Some("current-filetable") => (Operation::CurrentFiletable, false),
Some("regs/float") => (Operation::Regs(RegsKind::Float), false),
Some("regs/int") => (Operation::Regs(RegsKind::Int), false),
Some("regs/env") => (Operation::Regs(RegsKind::Env), false),
Some("trace") => (Operation::Trace, false),
Some("exe") => (Operation::Static("exe"), true),
Some("name") => (Operation::Name, true),
Some("session_id") => (Operation::SessionId, true),
Some("sighandler") => (Operation::Sighandler, false),
Some("sigprocmask") => (Operation::Sigprocmask, false),
Some("sigignmask") => (Operation::Sigignmask, false),
Some("start") => (Operation::Start, false),
Some("uid") => (Operation::Attr(Attr::Uid), true),
Some("gid") => (Operation::Attr(Attr::Gid), true),
Some("open_via_dup") => (Operation::OpenViaDup, false),
Some("sigactions") => {
Operation::Sigactions(Arc::clone(&get_context(pid)?.read().actions))
(Operation::Sigactions(Arc::clone(&get_context(pid)?.read().actions)), false)
}
Some("current-sigactions") => Operation::CurrentSigactions,
Some("mmap-min-addr") => Operation::MmapMinAddr(Arc::clone(
Some("current-sigactions") => (Operation::CurrentSigactions, false),
Some("mmap-min-addr") => (Operation::MmapMinAddr(Arc::clone(
get_context(pid)?
.read()
.addr_space()
.map_err(|_| Error::new(ENOENT))?,
)),
Some("sched-affinity") => Operation::SchedAffinity,
)), false),
Some("sched-affinity") => (Operation::SchedAffinity, true),
_ => return Err(Error::new(EINVAL)),
};
@@ -341,7 +333,7 @@ impl<const FULL: bool> ProcScheme<FULL> {
Operation::Static(_) => OperationData::Static(StaticData::new(
target.name.clone().into_owned().into_bytes().into(),
)),
Operation::AddrSpace { .. } => OperationData::Offset(0),
Operation::AddrSpace { .. } => OperationData::Offset,
_ => OperationData::Other,
};
@@ -403,14 +395,14 @@ impl<const FULL: bool> ProcScheme<FULL> {
}
};
let id = new_handle(Handle {
let (id, int_fl) = new_handle((Handle {
info: Info {
flags,
pid,
operation: operation.clone(),
},
data,
})?;
}, if positioned { InternalFlags::POSITIONED } else { InternalFlags::empty() }))?;
if let Operation::Trace = operation {
if !ptrace::try_new_session(pid, id) {
@@ -425,7 +417,7 @@ impl<const FULL: bool> ProcScheme<FULL> {
}
}
Ok(id)
Ok((id, int_fl))
}
#[cfg(target_arch = "aarch64")]
@@ -599,7 +591,7 @@ impl<const FULL: bool> KernelScheme for ProcScheme<FULL> {
};
self.open_inner(pid, parts.next(), flags, ctx.uid, ctx.gid)
.map(OpenResult::SchemeLocal)
.map(|(r, fl)| OpenResult::SchemeLocal(r, fl))
}
fn fcntl(&self, id: usize, cmd: usize, arg: usize) -> Result<usize> {
@@ -762,7 +754,7 @@ impl<const FULL: bool> KernelScheme for ProcScheme<FULL> {
_ => Err(Error::new(EBADF)),
}
}
fn kread(&self, id: usize, buf: UserSliceWo) -> Result<usize> {
fn kreadoff(&self, id: usize, buf: UserSliceWo, offset: u64, read_flags: u32, _stored_flags: u32) -> Result<usize> {
// Don't hold a global lock during the context switch later on
let info = {
let handles = HANDLES.read();
@@ -774,12 +766,7 @@ impl<const FULL: bool> KernelScheme for ProcScheme<FULL> {
Operation::Static(_) => {
let mut handles = HANDLES.write();
let handle = handles.get_mut(&id).ok_or(Error::new(EBADF))?;
let data = handle.data.static_data().expect("operations can't change");
let src_buf = data.buf.get(data.offset..).unwrap_or(&[]);
let len = buf.copy_common_bytes_from_slice(src_buf)?;
data.offset += len;
Ok(len)
read_from(buf, &handle.data.static_data().ok_or(Error::new(EBADFD))?.buf, offset)
}
Operation::Regs(kind) => {
union Output {
@@ -877,11 +864,15 @@ impl<const FULL: bool> KernelScheme for ProcScheme<FULL> {
Ok(read * mem::size_of::<PtraceEvent>())
}
Operation::AddrSpace { ref addrspace } => {
let OperationData::Offset(orig_offset) =
let OperationData::Offset =
HANDLES.read().get(&id).ok_or(Error::new(EBADF))?.data
else {
return Err(Error::new(EBADFD));
};
let Ok(offset) = usize::try_from(offset) else {
return Ok(0);
};
let grants_to_skip = offset / mem::size_of::<GrantDesc>();
// Output a list of grant descriptors, sufficient to allow relibc's fork()
// implementation to fmap MAP_SHARED grants.
@@ -891,7 +882,7 @@ impl<const FULL: bool> KernelScheme for ProcScheme<FULL> {
for (dst, (grant_base, grant_info)) in dst
.iter_mut()
.zip(addrspace.acquire_read().grants.iter().skip(orig_offset))
.zip(addrspace.acquire_read().grants.iter().skip(grants_to_skip))
{
*dst = GrantDesc {
base: grant_base.start_address().data(),
@@ -911,11 +902,6 @@ impl<const FULL: bool> KernelScheme for ProcScheme<FULL> {
chunk.copy_exactly(src)?;
}
match HANDLES.write().get_mut(&id).ok_or(Error::new(EBADF))?.data {
OperationData::Offset(ref mut offset) => *offset += grants_read,
_ => return Err(Error::new(EBADFD)),
};
Ok(grants_read * mem::size_of::<GrantDesc>())
}
Operation::Name => read_from(
@@ -926,7 +912,7 @@ impl<const FULL: bool> KernelScheme for ProcScheme<FULL> {
.read()
.name
.as_bytes(),
&mut 0,
offset,
),
Operation::SessionId => read_from(
buf,
@@ -937,7 +923,7 @@ impl<const FULL: bool> KernelScheme for ProcScheme<FULL> {
.session_id
.get()
.to_ne_bytes(),
&mut 0,
offset,
),
Operation::Sighandler => {
@@ -985,14 +971,14 @@ impl<const FULL: bool> KernelScheme for ProcScheme<FULL> {
}
.into_bytes();
read_from(buf, &src_buf, &mut 0)
read_from(buf, &src_buf, offset)
}
Operation::Filetable { .. } => {
let mut handles = HANDLES.write();
let handle = handles.get_mut(&id).ok_or(Error::new(EBADF))?;
let data = handle.data.static_data().expect("operations can't change");
read_from(buf, &data.buf, &mut data.offset)
read_from(buf, &data.buf, offset)
}
Operation::MmapMinAddr(ref addrspace) => {
buf.write_usize(addrspace.acquire_read().mmap_min)?;
@@ -1016,7 +1002,9 @@ impl<const FULL: bool> KernelScheme for ProcScheme<FULL> {
_ => Err(Error::new(EBADF)),
}
}
fn kwrite(&self, id: usize, buf: UserSliceRo) -> Result<usize> {
fn kwriteoff(&self, id: usize, buf: UserSliceRo, _offset: u64, fcntl_flags: u32, _stored_flags: u32) -> Result<usize> {
// TODO: offset
// Don't hold a global lock during the context switch later on
let info = {
let mut handles = HANDLES.write();
@@ -1406,7 +1394,7 @@ impl<const FULL: bool> KernelScheme for ProcScheme<FULL> {
buffer.copy_exactly(&Stat {
st_mode: MODE_FILE | 0o666,
st_size: match handle.data {
OperationData::Static(ref data) => (data.buf.len() - data.offset) as u64,
OperationData::Static(ref data) => data.buf.len() as u64,
_ => 0,
},
@@ -1416,6 +1404,14 @@ impl<const FULL: bool> KernelScheme for ProcScheme<FULL> {
Ok(())
}
fn fsize(&self, id: usize) -> Result<u64> {
let mut handles = HANDLES.write();
let handle = handles.get_mut(&id).ok_or(Error::new(EBADF))?;
// TODO: operation-dependent
Ok(handle.data.static_data().ok_or(Error::new(ESPIPE))?.buf.len() as u64)
}
/// Dup is currently used to implement clone() and execve().
fn kdup(&self, old_id: usize, raw_buf: UserSliceRo, _: CallerCtx) -> Result<OpenResult> {
let info = {
@@ -1425,14 +1421,14 @@ impl<const FULL: bool> KernelScheme for ProcScheme<FULL> {
handle.info.clone()
};
let handle = |operation, data| Handle {
let handle = |operation, data, positioned| (Handle {
info: Info {
flags: 0,
pid: info.pid,
operation,
},
data,
};
}, if positioned { InternalFlags::POSITIONED } else { InternalFlags::empty() });
let mut array = [0_u8; 64];
if raw_buf.len() > array.len() {
return Err(Error::new(EINVAL));
@@ -1458,7 +1454,7 @@ impl<const FULL: bool> KernelScheme for ProcScheme<FULL> {
uid,
gid,
)
.map(OpenResult::SchemeLocal);
.map(|(r, fl)| OpenResult::SchemeLocal(r, fl))
}
Operation::Filetable { ref filetable } => {
@@ -1477,6 +1473,7 @@ impl<const FULL: bool> KernelScheme for ProcScheme<FULL> {
filetable: new_filetable,
},
OperationData::Other,
true,
)
}
Operation::AddrSpace { ref addrspace } => {
@@ -1524,7 +1521,7 @@ impl<const FULL: bool> KernelScheme for ProcScheme<FULL> {
_ => return Err(Error::new(EINVAL)),
};
handle(operation, OperationData::Offset(0))
handle(operation, OperationData::Offset, true)
}
Operation::Sigactions(ref sigactions) => {
let new = match buf {
@@ -1532,11 +1529,11 @@ impl<const FULL: bool> KernelScheme for ProcScheme<FULL> {
b"copy" => Arc::new(RwLock::new(sigactions.read().clone())),
_ => return Err(Error::new(EINVAL)),
};
handle(Operation::Sigactions(new), OperationData::Other)
handle(Operation::Sigactions(new), OperationData::Other, false)
}
_ => return Err(Error::new(EINVAL)),
})
.map(OpenResult::SchemeLocal)
.map(|(r, fl)| OpenResult::SchemeLocal(r, fl))
}
}
extern "C" fn clone_handler() {
+20 -28
View File
@@ -1,4 +1,5 @@
use alloc::{boxed::Box, string::ToString, sync::Arc, vec::Vec};
use syscall::O_FSYNC;
use core::{
str,
sync::atomic::{AtomicUsize, Ordering},
@@ -7,7 +8,7 @@ use hashbrown::HashMap;
use spin::{Mutex, RwLock};
use crate::{
context,
context::{self, file::InternalFlags},
scheme::{
self,
user::{UserInner, UserScheme},
@@ -21,29 +22,16 @@ use crate::{
},
};
use super::{calc_seek_offset, CallerCtx, KernelScheme, KernelSchemes, OpenResult};
use super::{CallerCtx, KernelScheme, KernelSchemes, OpenResult};
struct FolderInner {
data: Box<[u8]>,
pos: Mutex<usize>,
}
impl FolderInner {
fn read(&self, buf: UserSliceWo) -> Result<usize> {
let mut pos_guard = self.pos.lock();
let avail_buf = self.data.get(*pos_guard..).unwrap_or(&[]);
let bytes_read = buf.copy_common_bytes_from_slice(avail_buf)?;
*pos_guard += bytes_read;
Ok(bytes_read)
}
fn seek(&self, pos: isize, whence: usize) -> Result<usize> {
let mut seek = self.pos.lock();
let new_offset = calc_seek_offset(*seek, pos, whence, self.data.len())?;
*seek = new_offset as usize;
Ok(new_offset)
fn read(&self, buf: UserSliceWo, offset: u64) -> Result<usize> {
let avail_buf = usize::try_from(offset).ok().and_then(|o| self.data.get(o..)).unwrap_or(&[]);
buf.copy_common_bytes_from_slice(avail_buf)
}
}
@@ -103,6 +91,11 @@ impl KernelScheme for RootScheme {
let inner = Arc::new(UserInner::new(
self.scheme_id,
scheme_id,
// TODO: This is a hack, but eventually the legacy interface will be
// removed.
flags & O_FSYNC == O_FSYNC,
id,
path_box,
flags,
@@ -119,7 +112,7 @@ impl KernelScheme for RootScheme {
self.handles.write().insert(id, Handle::Scheme(inner));
Ok(OpenResult::SchemeLocal(id))
Ok(OpenResult::SchemeLocal(id, InternalFlags::empty()))
} else if path.is_empty() {
let scheme_ns = {
let contexts = context::contexts();
@@ -139,18 +132,17 @@ impl KernelScheme for RootScheme {
let inner = Arc::new(FolderInner {
data: data.into_boxed_slice(),
pos: Mutex::new(0),
});
let id = self.next_id.fetch_add(1, Ordering::Relaxed);
self.handles.write().insert(id, Handle::Folder(inner));
Ok(OpenResult::SchemeLocal(id))
Ok(OpenResult::SchemeLocal(id, InternalFlags::POSITIONED))
} else {
let inner = Arc::new(path.as_bytes().to_vec().into_boxed_slice());
let id = self.next_id.fetch_add(1, Ordering::Relaxed);
self.handles.write().insert(id, Handle::File(inner));
Ok(OpenResult::SchemeLocal(id))
Ok(OpenResult::SchemeLocal(id, InternalFlags::POSITIONED))
}
}
@@ -181,7 +173,7 @@ impl KernelScheme for RootScheme {
inner.unmount()
}
fn seek(&self, file: usize, pos: isize, whence: usize) -> Result<usize> {
fn fsize(&self, file: usize) -> Result<u64> {
let handle = {
let handles = self.handles.read();
let handle = handles.get(&file).ok_or(Error::new(EBADF))?;
@@ -191,7 +183,7 @@ impl KernelScheme for RootScheme {
match handle {
Handle::Scheme(_) => Err(Error::new(EBADF)),
Handle::File(_) => Err(Error::new(EBADF)),
Handle::Folder(inner) => inner.seek(pos, whence),
Handle::Folder(inner) => Ok(inner.data.len() as u64),
}
}
@@ -260,7 +252,7 @@ impl KernelScheme for RootScheme {
}
Ok(())
}
fn kread(&self, file: usize, buf: UserSliceWo) -> Result<usize> {
fn kreadoff(&self, file: usize, buf: UserSliceWo, offset: u64, flags: u32, _stored_flags: u32) -> Result<usize> {
let handle = {
let handles = self.handles.read();
let handle = handles.get(&file).ok_or(Error::new(EBADF))?;
@@ -268,13 +260,13 @@ impl KernelScheme for RootScheme {
};
match handle {
Handle::Scheme(inner) => inner.read(buf),
Handle::Scheme(inner) => inner.read(buf, flags),
Handle::File(_) => Err(Error::new(EBADF)),
Handle::Folder(inner) => inner.read(buf),
Handle::Folder(inner) => inner.read(buf, offset),
}
}
fn kwrite(&self, file: usize, buf: UserSliceRo) -> Result<usize> {
fn kwrite(&self, file: usize, buf: UserSliceRo, _flags: u32, _stored_flags: u32) -> Result<usize> {
let handle = {
let handles = self.handles.read();
let handle = handles.get(&file).ok_or(Error::new(EBADF))?;
+4 -22
View File
@@ -25,7 +25,6 @@ static INPUT: [WaitQueue<u8>; 2] = [WaitQueue::new(), WaitQueue::new()];
#[derive(Clone, Copy)]
struct Handle {
index: usize,
flags: usize,
}
// Using BTreeMap as hashbrown doesn't have a const constructor.
@@ -46,7 +45,7 @@ pub fn serio_input(index: usize, data: u8) {
pub struct SerioScheme;
impl KernelScheme for SerioScheme {
fn kopen(&self, path: &str, flags: usize, ctx: CallerCtx) -> Result<OpenResult> {
fn kopen(&self, path: &str, _flags: usize, ctx: CallerCtx) -> Result<OpenResult> {
if ctx.uid != 0 {
return Err(Error::new(EPERM));
}
@@ -61,27 +60,10 @@ impl KernelScheme for SerioScheme {
id,
Handle {
index,
flags: flags & !O_ACCMODE,
},
);
Ok(OpenResult::SchemeLocal(id))
}
fn fcntl(&self, id: usize, cmd: usize, arg: usize) -> Result<usize> {
let mut handles = HANDLES.write();
if let Some(handle) = handles.get_mut(&id) {
match cmd {
F_GETFL => Ok(handle.flags),
F_SETFL => {
handle.flags = arg & !O_ACCMODE;
Ok(0)
}
_ => Err(Error::new(EINVAL)),
}
} else {
Err(Error::new(EBADF))
}
Ok(OpenResult::SchemeLocal(id, InternalFlags::empty()))
}
fn fevent(&self, id: usize, _flags: EventFlags) -> Result<EventFlags> {
@@ -111,7 +93,7 @@ impl KernelScheme for SerioScheme {
Ok(())
}
fn kread(&self, id: usize, buf: UserSliceWo) -> Result<usize> {
fn kread(&self, id: usize, buf: UserSliceWo, flags: u32, _stored_flags: u32) -> Result<usize> {
let handle = {
let handles = HANDLES.read();
*handles.get(&id).ok_or(Error::new(EBADF))?
@@ -119,7 +101,7 @@ impl KernelScheme for SerioScheme {
INPUT[handle.index].receive_into_user(
buf,
handle.flags & O_NONBLOCK != O_NONBLOCK,
flags & O_NONBLOCK as u32 == 0,
"SerioScheme::read",
)
}
+14 -19
View File
@@ -6,16 +6,15 @@ use core::{
use spin::RwLock;
use crate::{
arch::interrupt,
syscall::{
arch::interrupt, context::file::InternalFlags, syscall::{
data::Stat,
error::{Error, Result, EBADF, ENOENT},
flag::{MODE_DIR, MODE_FILE},
usercopy::UserSliceWo,
},
}
};
use super::{calc_seek_offset, CallerCtx, KernelScheme, OpenResult};
use super::{CallerCtx, KernelScheme, OpenResult};
mod block;
mod context;
@@ -33,7 +32,6 @@ struct Handle {
path: &'static str,
data: Vec<u8>,
mode: u16,
seek: usize,
}
type SysFn = fn() -> Result<Vec<u8>>;
@@ -88,10 +86,9 @@ impl KernelScheme for SysScheme {
path: "",
data,
mode: MODE_DIR | 0o444,
seek: 0,
},
);
return Ok(OpenResult::SchemeLocal(id));
return Ok(OpenResult::SchemeLocal(id, InternalFlags::POSITIONED));
} else {
//Have to iterate to get the path without allocation
for entry in FILES.iter() {
@@ -104,10 +101,9 @@ impl KernelScheme for SysScheme {
path: entry.0,
data,
mode: MODE_FILE | 0o444,
seek: 0,
},
);
return Ok(OpenResult::SchemeLocal(id));
return Ok(OpenResult::SchemeLocal(id, InternalFlags::POSITIONED));
}
}
}
@@ -115,13 +111,11 @@ impl KernelScheme for SysScheme {
Err(Error::new(ENOENT))
}
fn seek(&self, id: usize, pos: isize, whence: usize) -> Result<usize> {
fn fsize(&self, id: usize) -> Result<u64> {
let mut handles = HANDLES.write();
let handle = handles.get_mut(&id).ok_or(Error::new(EBADF))?;
let new_offset = calc_seek_offset(handle.seek, pos, whence, handle.data.len())?;
handle.seek = new_offset;
Ok(new_offset)
Ok(handle.data.len() as u64)
}
fn fsync(&self, _id: usize) -> Result<()> {
@@ -148,16 +142,17 @@ impl KernelScheme for SysScheme {
Ok(bytes_read)
}
fn kread(&self, id: usize, buffer: UserSliceWo) -> Result<usize> {
fn kreadoff(&self, id: usize, buffer: UserSliceWo, pos: u64, _flags: u32, _stored_flags: u32) -> Result<usize> {
let Ok(pos) = usize::try_from(pos) else {
return Ok(0);
};
let mut handles = HANDLES.write();
let handle = handles.get_mut(&id).ok_or(Error::new(EBADF))?;
let avail_buf = handle.data.get(handle.seek..).unwrap_or(&[]);
let avail_buf = handle.data.get(pos..).unwrap_or(&[]);
let byte_count = buffer.copy_common_bytes_from_slice(avail_buf)?;
handle.seek = handle.seek.saturating_add(byte_count);
Ok(byte_count)
buffer.copy_common_bytes_from_slice(avail_buf)
}
fn kfstat(&self, id: usize, buf: UserSliceWo) -> Result<()> {
+4 -4
View File
@@ -6,7 +6,7 @@ use core::{
use spin::RwLock;
use crate::{
context::timeout,
context::{file::InternalFlags, timeout},
syscall::{
data::TimeSpec,
error::*,
@@ -37,7 +37,7 @@ impl KernelScheme for TimeScheme {
let id = NEXT_ID.fetch_add(1, Ordering::Relaxed);
HANDLES.write().insert(id, clock);
Ok(OpenResult::SchemeLocal(id))
Ok(OpenResult::SchemeLocal(id, InternalFlags::empty()))
}
fn fcntl(&self, _id: usize, _cmd: usize, _arg: usize) -> Result<usize> {
@@ -64,7 +64,7 @@ impl KernelScheme for TimeScheme {
.ok_or(Error::new(EBADF))
.and(Ok(()))
}
fn kread(&self, id: usize, buf: UserSliceWo) -> Result<usize> {
fn kread(&self, id: usize, buf: UserSliceWo, _flags: u32, _stored_flags: u32) -> Result<usize> {
let clock = *HANDLES.read().get(&id).ok_or(Error::new(EBADF))?;
let mut bytes_read = 0;
@@ -87,7 +87,7 @@ impl KernelScheme for TimeScheme {
Ok(bytes_read)
}
fn kwrite(&self, id: usize, buf: UserSliceRo) -> Result<usize> {
fn kwrite(&self, id: usize, buf: UserSliceRo, _flags: u32, _stored_flags: u32) -> Result<usize> {
let clock = *HANDLES.read().get(&id).ok_or(Error::new(EBADF))?;
let mut bytes_written = 0;
+472 -299
View File
File diff suppressed because it is too large Load Diff
+17
View File
@@ -24,6 +24,23 @@ impl<T> WaitQueue<T> {
}
}
pub fn receive(&self, block: bool, reason: &'static str) -> Result<T> {
loop {
let mut inner = self.inner.lock();
if let Some(t) = inner.pop_front() {
return Ok(t);
} else if block {
if !self.condition.wait(inner, reason) {
return Err(Error::new(EINTR));
}
continue;
} else {
return Err(Error::new(EAGAIN));
}
}
}
pub fn receive_into_user(
&self,
buf: UserSliceWo,
+90 -44
View File
@@ -4,11 +4,7 @@ use redox_path::RedoxPath;
use spin::RwLock;
use crate::{
context,
context::{
file::{FileDescription, FileDescriptor},
memory::{AddrSpace, PageSpan},
},
context::{self, file::{FileDescription, FileDescriptor, InternalFlags}, memory::{AddrSpace, PageSpan}},
paging::{Page, VirtualAddress, PAGE_SIZE},
scheme::{self, CallerCtx, FileHandle, KernelScheme, OpenResult, SchemeId},
syscall::{data::Stat, error::*, flag::*},
@@ -20,28 +16,24 @@ pub fn file_op_generic<T>(
fd: FileHandle,
op: impl FnOnce(&dyn KernelScheme, usize) -> Result<T>,
) -> Result<T> {
file_op_generic_ext(fd, |s, _, no| op(s, no))
file_op_generic_ext(fd, |s, _, desc| op(s, desc.number))
}
pub fn file_op_generic_ext<T>(
fd: FileHandle,
op: impl FnOnce(&dyn KernelScheme, SchemeId, usize) -> Result<T>,
op: impl FnOnce(&dyn KernelScheme, Arc<RwLock<FileDescription>>, FileDescription) -> Result<T>,
) -> Result<T> {
let file = context::current()?
.read()
.get_file(fd)
.ok_or(Error::new(EBADF))?;
let FileDescription {
scheme: scheme_id,
number,
..
} = *file.description.read();
let desc = *file.description.read();
let scheme = scheme::schemes()
.get(scheme_id)
.get(desc.scheme)
.ok_or(Error::new(EBADF))?
.clone();
op(&*scheme, scheme_id, number)
op(&*scheme, file.description, desc)
}
pub fn copy_path_to_buf(raw_path: UserSliceRo, max_len: usize) -> Result<alloc::string::String> {
let mut path_buf = vec![0_u8; max_len];
@@ -90,11 +82,12 @@ pub fn open(raw_path: UserSliceRo, flags: usize) -> Result<FileHandle> {
};
match scheme.kopen(reference.as_ref(), flags, CallerCtx { uid, gid, pid })? {
OpenResult::SchemeLocal(number) => Arc::new(RwLock::new(FileDescription {
namespace: scheme_ns,
OpenResult::SchemeLocal(number, internal_flags) => Arc::new(RwLock::new(FileDescription {
scheme: scheme_id,
number,
flags: flags & !O_CLOEXEC,
offset: 0,
flags: (flags & !O_CLOEXEC) as u32,
internal_flags,
})),
OpenResult::External(desc) => desc,
}
@@ -192,8 +185,9 @@ fn duplicate_file(fd: FileHandle, user_buf: UserSliceRo) -> Result<FileDescripto
.clone();
match scheme.kdup(description.number, user_buf, caller_ctx)? {
OpenResult::SchemeLocal(number) => Arc::new(RwLock::new(FileDescription {
namespace: description.namespace,
OpenResult::SchemeLocal(number, internal_flags) => Arc::new(RwLock::new(FileDescription {
offset: 0,
internal_flags,
scheme: description.scheme,
number,
flags: description.flags,
@@ -286,17 +280,26 @@ pub fn sendfd(socket: FileHandle, fd: FileHandle, flags_raw: usize, arg: u64) ->
/// File descriptor controls
pub fn fcntl(fd: FileHandle, cmd: usize, arg: usize) -> Result<usize> {
let file = {
let contexts = context::contexts();
let context_lock = contexts.current().ok_or(Error::new(ESRCH))?;
let context = context_lock.read();
context.get_file(fd).ok_or(Error::new(EBADF))?
};
let file = context::current()?.read().get_file(fd).ok_or(Error::new(EBADF))?;
let description = file.description.read();
if cmd == F_DUPFD {
// Not in match because 'files' cannot be locked
let new_file = duplicate_file(fd, UserSlice::empty())?;
let contexts = context::contexts();
let context_lock = contexts.current().ok_or(Error::new(ESRCH))?;
let context = context_lock.read();
return context
.add_file_min(new_file, arg)
.ok_or(Error::new(EMFILE))
.map(FileHandle::into);
}
// Communicate fcntl with scheme
if cmd != F_DUPFD && cmd != F_GETFD && cmd != F_SETFD {
if cmd != F_GETFD && cmd != F_SETFD {
let scheme = scheme::schemes()
.get(description.scheme)
.ok_or(Error::new(EBADF))?
@@ -307,19 +310,6 @@ pub fn fcntl(fd: FileHandle, cmd: usize, arg: usize) -> Result<usize> {
// Perform kernel operation if scheme agrees
{
if cmd == F_DUPFD {
// Not in match because 'files' cannot be locked
let new_file = duplicate_file(fd, UserSlice::empty())?;
let contexts = context::contexts();
let context_lock = contexts.current().ok_or(Error::new(ESRCH))?;
let context = context_lock.read();
return context
.add_file_min(new_file, arg)
.ok_or(Error::new(EMFILE))
.map(FileHandle::into);
}
let contexts = context::contexts();
let context_lock = contexts.current().ok_or(Error::new(ESRCH))?;
@@ -339,9 +329,9 @@ pub fn fcntl(fd: FileHandle, cmd: usize, arg: usize) -> Result<usize> {
file.cloexec = arg & O_CLOEXEC == O_CLOEXEC;
Ok(0)
}
F_GETFL => Ok(description.flags),
F_GETFL => Ok(description.flags as usize),
F_SETFL => {
let new_flags = (description.flags & O_ACCMODE) | (arg & !O_ACCMODE);
let new_flags = (description.flags & O_ACCMODE as u32) | (arg as u32 & !O_ACCMODE as u32);
drop(description);
file.description.write().flags = new_flags;
Ok(0)
@@ -393,13 +383,13 @@ pub fn frename(fd: FileHandle, raw_path: UserSliceRo) -> Result<()> {
/// File status
pub fn fstat(fd: FileHandle, user_buf: UserSliceWo) -> Result<()> {
file_op_generic_ext(fd, |scheme, scheme_id, number| {
scheme.kfstat(number, user_buf)?;
file_op_generic_ext(fd, |scheme, _, desc| {
scheme.kfstat(desc.number, user_buf)?;
// TODO: Ensure only the kernel can access the stat when st_dev is set, or use another API
// for retrieving the scheme ID from a file descriptor.
// TODO: Less hacky method.
let st_dev = scheme_id
let st_dev = desc.scheme
.get()
.try_into()
.map_err(|_| Error::new(EOVERFLOW))?;
@@ -491,3 +481,59 @@ pub fn mremap(
Ok(base.start_address().data())
}
pub fn lseek(fd: FileHandle, pos: i64, whence: usize) -> Result<usize> {
enum Ret {
Legacy(usize),
Fsize((Option<u64>, Arc<RwLock<FileDescription>>)),
}
let fsize_or_legacy = file_op_generic_ext(fd, |scheme, desc_arc, desc| {
Ok(if let Some(new_off) = scheme.legacy_seek(desc.number, pos as isize, whence) {
Ret::Legacy(new_off?)
} else if whence == SEEK_END {
Ret::Fsize((Some(scheme.fsize(desc.number)?), desc_arc))
} else {
Ret::Fsize((None, desc_arc))
})
})?;
let (fsize, desc) = match fsize_or_legacy {
Ret::Fsize(fsize) => fsize,
Ret::Legacy(new_pos) => return Ok(new_pos),
};
let mut guard = desc.write();
let new_pos = match whence {
SEEK_SET => pos,
SEEK_CUR => pos.checked_add_unsigned(guard.offset).ok_or(Error::new(EOVERFLOW))?,
SEEK_END => pos.checked_add_unsigned(fsize.unwrap()).ok_or(Error::new(EOVERFLOW))?,
_ => return Err(Error::new(EINVAL)),
};
guard.offset = new_pos.try_into().map_err(|_| Error::new(EINVAL))?;
Ok(guard.offset as usize)
}
pub fn sys_read(fd: FileHandle, buf: UserSliceWo) -> Result<usize> {
let (bytes_read, desc_arc, desc) = file_op_generic_ext(fd, |scheme, desc_arc, desc| {
let offset = if desc.internal_flags.contains(InternalFlags::POSITIONED) { desc.offset } else { u64::MAX };
Ok((scheme.kreadoff(desc.number, buf, offset, desc.flags, desc.flags)?, desc_arc, desc))
})?;
if desc.internal_flags.contains(InternalFlags::POSITIONED) {
match desc_arc.write().offset {
ref mut offset => *offset = offset.saturating_add(bytes_read as u64),
}
}
Ok(bytes_read)
}
pub fn sys_write(fd: FileHandle, buf: UserSliceRo) -> Result<usize> {
let (bytes_written, desc_arc, desc) = file_op_generic_ext(fd, |scheme, desc_arc, desc| {
let offset = if desc.internal_flags.contains(InternalFlags::POSITIONED) { desc.offset } else { u64::MAX };
Ok((scheme.kwriteoff(desc.number, buf, offset, desc.flags, desc.flags)?, desc_arc, desc))
})?;
if desc.internal_flags.contains(InternalFlags::POSITIONED) {
match desc_arc.write().offset {
ref mut offset => *offset = offset.saturating_add(bytes_written as u64),
}
}
Ok(bytes_written)
}
+11 -7
View File
@@ -4,6 +4,8 @@
extern crate syscall;
use syscall::{RwFlags, EINVAL};
pub use self::syscall::{
data, error, flag, io, number, ptrace_event, EnvRegisters, FloatRegisters, IntRegisters,
};
@@ -81,9 +83,11 @@ pub fn syscall(
let fd = FileHandle::from(b);
match a & SYS_ARG {
SYS_ARG_SLICE => match a {
SYS_WRITE => file_op_generic(fd, |scheme, number| {
scheme.kwrite(number, UserSlice::ro(c, d)?)
SYS_WRITE2 => file_op_generic_ext(fd, |scheme, _, desc| {
let flags = u32::try_from(f).ok().and_then(RwFlags::from_bits).ok_or(Error::new(EINVAL))?;
scheme.kwriteoff(desc.number, UserSlice::ro(c, d)?, e as u64, desc.rw_flags(flags), desc.flags)
}),
SYS_WRITE => sys_write(fd, UserSlice::ro(c, d)?),
SYS_FMAP => {
let addrspace = AddrSpace::current()?;
let map = unsafe { UserSlice::ro(c, d)?.read_exact::<Map>()? };
@@ -103,9 +107,11 @@ pub fn syscall(
_ => return Err(Error::new(ENOSYS)),
},
SYS_ARG_MSLICE => match a {
SYS_READ => file_op_generic(fd, |scheme, number| {
scheme.kread(number, UserSlice::wo(c, d)?)
SYS_READ2 => file_op_generic_ext(fd, |scheme, _, desc| {
let flags = u32::try_from(f).ok().and_then(RwFlags::from_bits).ok_or(Error::new(EINVAL))?;
scheme.kreadoff(desc.number, UserSlice::wo(c, d)?, e as u64, desc.rw_flags(flags), desc.flags)
}),
SYS_READ => sys_read(fd, UserSlice::wo(c, d)?),
SYS_FPATH => file_op_generic(fd, |scheme, number| {
scheme.kfpath(number, UserSlice::wo(c, d)?)
}),
@@ -129,9 +135,7 @@ pub fn syscall(
#[cfg(target_pointer_width = "64")]
SYS_SENDFD => sendfd(fd, FileHandle::from(c), d, e as u64),
SYS_LSEEK => {
file_op_generic(fd, |scheme, number| scheme.seek(number, c as isize, d))
}
SYS_LSEEK => lseek(fd, c as i64, d),
SYS_FCHMOD => file_op_generic(fd, |scheme, number| {
scheme.fchmod(number, c as u16).map(|()| 0)
}),
+1 -1
Submodule syscall updated: 3e9d68c6b2...ef099bdd2e