Add rustfmt from relibc and apply it with cargo fmt

This commit is contained in:
Jeremy Soller
2024-01-17 13:52:01 -07:00
parent 73897bd83d
commit 45f1c4e29e
166 changed files with 7353 additions and 3851 deletions
+41 -143
View File
@@ -1,15 +1,17 @@
use alloc::{string::String, vec::Vec};
use core::{ascii, mem};
use alloc::string::String;
use alloc::vec::Vec;
use super::data::{Map, Stat, TimeSpec};
use super::{flag::*, copy_path_to_buf};
use super::number::*;
use super::usercopy::UserSlice;
use super::{
copy_path_to_buf,
data::{Map, Stat, TimeSpec},
flag::*,
number::*,
usercopy::UserSlice,
};
use crate::syscall::error::Result;
struct ByteStr<'a>(&'a[u8]);
struct ByteStr<'a>(&'a [u8]);
impl<'a> ::core::fmt::Debug for ByteStr<'a> {
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
@@ -29,7 +31,7 @@ fn debug_path(ptr: usize, len: usize) -> Result<String> {
}
fn debug_buf(ptr: usize, len: usize) -> Result<Vec<u8>> {
UserSlice::ro(ptr, len).and_then(|user| {
let mut buf = vec! [0_u8; 4096];
let mut buf = vec![0_u8; 4096];
let count = user.copy_common_bytes_to_slice(&mut buf)?;
buf.truncate(count);
Ok(buf)
@@ -55,9 +57,7 @@ pub fn format_call(a: usize, b: usize, c: usize, d: usize, e: usize, f: usize) -
"unlink({:?})",
debug_path(b, c).as_ref().map(|p| ByteStr(p.as_bytes())),
),
SYS_CLOSE => format!(
"close({})", b
),
SYS_CLOSE => format!("close({})", b),
SYS_DUP => format!(
"dup({}, {:?})",
b,
@@ -69,26 +69,9 @@ pub fn format_call(a: usize, b: usize, c: usize, d: usize, e: usize, f: usize) -
c,
debug_buf(d, e).as_ref().map(|b| ByteStr(&*b)),
),
SYS_SENDFD => format!(
"sendfd({}, {}, {:#0x} {:#0x} {:#0x})",
b,
c,
d,
e,
f,
),
SYS_READ => format!(
"read({}, {:#X}, {})",
b,
c,
d
),
SYS_WRITE => format!(
"write({}, {:#X}, {})",
b,
c,
d
),
SYS_SENDFD => format!("sendfd({}, {}, {:#0x} {:#0x} {:#0x})", b, c, d, e, f,),
SYS_READ => format!("read({}, {:#X}, {})", b, c, d),
SYS_WRITE => format!("write({}, {:#X}, {})", b, c, d),
SYS_LSEEK => format!(
"lseek({}, {}, {} ({}))",
b,
@@ -97,21 +80,12 @@ pub fn format_call(a: usize, b: usize, c: usize, d: usize, e: usize, f: usize) -
SEEK_SET => "SEEK_SET",
SEEK_CUR => "SEEK_CUR",
SEEK_END => "SEEK_END",
_ => "UNKNOWN"
_ => "UNKNOWN",
},
d
),
SYS_FCHMOD => format!(
"fchmod({}, {:#o})",
b,
c
),
SYS_FCHOWN => format!(
"fchown({}, {}, {})",
b,
c,
d
),
SYS_FCHMOD => format!("fchmod({}, {:#o})", b, c),
SYS_FCHOWN => format!("fchown({}, {}, {})", b, c, d),
SYS_FCNTL => format!(
"fcntl({}, {} ({}), {:#X})",
b,
@@ -121,7 +95,7 @@ pub fn format_call(a: usize, b: usize, c: usize, d: usize, e: usize, f: usize) -
F_SETFD => "F_SETFD",
F_SETFL => "F_SETFL",
F_GETFL => "F_GETFL",
_ => "UNKNOWN"
_ => "UNKNOWN",
},
c,
d
@@ -131,47 +105,22 @@ pub fn format_call(a: usize, b: usize, c: usize, d: usize, e: usize, f: usize) -
b,
UserSlice::ro(c, d).and_then(|buf| unsafe { buf.read_exact::<Map>() }),
),
SYS_FUNMAP => format!(
"funmap({:#X}, {:#X})",
b,
c,
),
SYS_FPATH => format!(
"fpath({}, {:#X}, {})",
b,
c,
d
),
SYS_FRENAME => format!(
"frename({}, {:?})",
b,
debug_path(c, d),
),
SYS_FUNMAP => format!("funmap({:#X}, {:#X})", b, c,),
SYS_FPATH => format!("fpath({}, {:#X}, {})", b, c, d),
SYS_FRENAME => format!("frename({}, {:?})", b, debug_path(c, d),),
SYS_FSTAT => format!(
"fstat({}, {:?})",
b,
UserSlice::ro(c, d).and_then(|buf| unsafe { buf.read_exact::<Stat>() }),
),
SYS_FSTATVFS => format!(
"fstatvfs({}, {:#X}, {})",
b,
c,
d
),
SYS_FSYNC => format!(
"fsync({})",
b
),
SYS_FTRUNCATE => format!(
"ftruncate({}, {})",
b,
c
),
SYS_FSTATVFS => format!("fstatvfs({}, {:#X}, {})", b, c, d),
SYS_FSYNC => format!("fsync({})", b),
SYS_FTRUNCATE => format!("ftruncate({}, {})", b, c),
SYS_FUTIMENS => format!(
"futimens({}, {:?})",
b,
UserSlice::ro(c, d).and_then(|buf| {
let mut times = vec! [unsafe { buf.read_exact::<TimeSpec>()? }];
let mut times = vec![unsafe { buf.read_exact::<TimeSpec>()? }];
// One or two timespecs
if let Some(second) = buf.advance(mem::size_of::<TimeSpec>()) {
@@ -181,15 +130,10 @@ pub fn format_call(a: usize, b: usize, c: usize, d: usize, e: usize, f: usize) -
}),
),
SYS_CLOCK_GETTIME => format!(
"clock_gettime({}, {:?})",
b,
unsafe { read_struct::<TimeSpec>(c) }
),
SYS_EXIT => format!(
"exit({})",
b
),
SYS_CLOCK_GETTIME => format!("clock_gettime({}, {:?})", b, unsafe {
read_struct::<TimeSpec>(c)
}),
SYS_EXIT => format!("exit({})", b),
SYS_FUTEX => format!(
"futex({:#X} [{:?}], {}, {}, {}, {})",
b,
@@ -208,23 +152,10 @@ pub fn format_call(a: usize, b: usize, c: usize, d: usize, e: usize, f: usize) -
SYS_GETPID => format!("getpid()"),
SYS_GETPPID => format!("getppid()"),
SYS_GETUID => format!("getuid()"),
SYS_IOPL => format!(
"iopl({})",
b
),
SYS_KILL => format!(
"kill({}, {})",
b,
c
),
SYS_IOPL => format!("iopl({})", b),
SYS_KILL => format!("kill({}, {})", b, c),
SYS_SIGRETURN => format!("sigreturn()"),
SYS_SIGACTION => format!(
"sigaction({}, {:#X}, {:#X}, {:#X})",
b,
c,
d,
e
),
SYS_SIGACTION => format!("sigaction({}, {:#X}, {:#X}, {:#X})", b, c, d, e),
SYS_SIGPROCMASK => format!(
"sigprocmask({}, {:?}, {:?})",
b,
@@ -240,56 +171,23 @@ pub fn format_call(a: usize, b: usize, c: usize, d: usize, e: usize, f: usize) -
b as *const u8,
c,
),
SYS_MPROTECT => format!(
"mprotect({:#X}, {}, {:?})",
b,
c,
MapFlags::from_bits(d)
),
SYS_MPROTECT => format!("mprotect({:#X}, {}, {:?})", b, c, MapFlags::from_bits(d)),
SYS_NANOSLEEP => format!(
"nanosleep({:?}, ({}, {}))",
unsafe { read_struct::<TimeSpec>(b) },
c,
d
),
SYS_VIRTTOPHYS => format!(
"virttophys({:#X})",
b
),
SYS_SETREGID => format!(
"setregid({}, {})",
b,
c
),
SYS_SETRENS => format!(
"setrens({}, {})",
b,
c
),
SYS_SETREUID => format!(
"setreuid({}, {})",
b,
c
),
SYS_UMASK => format!(
"umask({:#o}",
b
),
SYS_WAITPID => format!(
"waitpid({}, {:#X}, {:?})",
b,
c,
WaitFlags::from_bits(d)
),
SYS_VIRTTOPHYS => format!("virttophys({:#X})", b),
SYS_SETREGID => format!("setregid({}, {})", b, c),
SYS_SETRENS => format!("setrens({}, {})", b, c),
SYS_SETREUID => format!("setreuid({}, {})", b, c),
SYS_UMASK => format!("umask({:#o}", b),
SYS_WAITPID => format!("waitpid({}, {:#X}, {:?})", b, c, WaitFlags::from_bits(d)),
SYS_YIELD => format!("yield()"),
_ => format!(
"UNKNOWN{} {:#X}({:#X}, {:#X}, {:#X}, {:#X}, {:#X})",
a, a,
b,
c,
d,
e,
f
)
a, a, b, c, d, e, f
),
}
}
+12 -6
View File
@@ -1,9 +1,11 @@
use alloc::sync::Arc;
use crate::interrupt::InterruptStack;
use crate::paging::VirtualAddress;
use crate::context;
use crate::syscall::error::{Error, EFAULT, EINVAL, EPERM, ESRCH, Result};
use crate::{
context,
interrupt::InterruptStack,
paging::VirtualAddress,
syscall::error::{Error, Result, EFAULT, EINVAL, EPERM, ESRCH},
};
fn enforce_root() -> Result<()> {
let contexts = context::contexts();
let context_lock = contexts.current().ok_or(Error::new(ESRCH))?;
@@ -52,8 +54,12 @@ pub fn virttophys(virtual_address: usize) -> Result<usize> {
let addr_space = Arc::clone(context::current()?.read().addr_space()?);
let addr_space = addr_space.read();
match addr_space.table.utable.translate(VirtualAddress::new(virtual_address)) {
match addr_space
.table
.utable
.translate(VirtualAddress::new(virtual_address))
{
Some((physical_address, _)) => Ok(physical_address.data()),
None => Err(Error::new(EFAULT))
None => Err(Error::new(EFAULT)),
}
}
+153 -54
View File
@@ -1,34 +1,55 @@
//! Filesystem syscalls
use alloc::sync::Arc;
use alloc::vec::Vec;
use alloc::{sync::Arc, vec::Vec};
use spin::RwLock;
use crate::context::file::{FileDescriptor, FileDescription};
use crate::context;
use crate::context::memory::{PageSpan, AddrSpace};
use crate::paging::{PAGE_SIZE, VirtualAddress, Page};
use crate::scheme::{self, FileHandle, OpenResult, KernelScheme, SchemeId, CallerCtx};
use crate::syscall::data::Stat;
use crate::syscall::error::*;
use crate::syscall::flag::*;
use crate::{
context,
context::{
file::{FileDescription, FileDescriptor},
memory::{AddrSpace, PageSpan},
},
paging::{Page, VirtualAddress, PAGE_SIZE},
scheme::{self, CallerCtx, FileHandle, KernelScheme, OpenResult, SchemeId},
syscall::{data::Stat, error::*, flag::*},
};
use super::usercopy::{UserSlice, UserSliceWo, UserSliceRo};
use super::usercopy::{UserSlice, UserSliceRo, UserSliceWo};
pub fn file_op_generic<T>(fd: FileHandle, op: impl FnOnce(&dyn KernelScheme, &CallerCtx, usize) -> Result<T>) -> Result<T> {
pub fn file_op_generic<T>(
fd: FileHandle,
op: impl FnOnce(&dyn KernelScheme, &CallerCtx, usize) -> Result<T>,
) -> Result<T> {
file_op_generic_ext(fd, |s, _, ctx, no| op(s, ctx, no))
}
pub fn file_op_generic_ext<T>(fd: FileHandle, op: impl FnOnce(&dyn KernelScheme, SchemeId, &CallerCtx, usize) -> Result<T>) -> Result<T> {
pub fn file_op_generic_ext<T>(
fd: FileHandle,
op: impl FnOnce(&dyn KernelScheme, SchemeId, &CallerCtx, usize) -> Result<T>,
) -> Result<T> {
let (ctx, file) = match context::current()?.read() {
ref context => (CallerCtx { pid: context.id.into(), uid: context.euid, gid: context.egid }, context.get_file(fd).ok_or(Error::new(EBADF))?),
ref context => (
CallerCtx {
pid: context.id.into(),
uid: context.euid,
gid: context.egid,
},
context.get_file(fd).ok_or(Error::new(EBADF))?,
),
};
let FileDescription { scheme: scheme_id, number, .. } = *file.description.read();
let FileDescription {
scheme: scheme_id,
number,
..
} = *file.description.read();
let scheme = scheme::schemes().get(scheme_id).ok_or(Error::new(EBADF))?.clone();
let scheme = scheme::schemes()
.get(scheme_id)
.ok_or(Error::new(EBADF))?
.clone();
op(&*scheme, scheme_id, &ctx, number)
}
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];
let mut path_buf = vec![0_u8; max_len];
if raw_path.len() > path_buf.len() {
return Err(Error::new(ENAMETOOLONG));
}
@@ -43,7 +64,13 @@ const PATH_MAX: usize = PAGE_SIZE;
/// Open syscall
pub fn open(raw_path: UserSliceRo, flags: usize) -> Result<FileHandle> {
let (pid, uid, gid, scheme_ns, umask) = match context::current()?.read() {
ref context => (context.id.into(), context.euid, context.egid, context.ens, context.umask),
ref context => (
context.id.into(),
context.euid,
context.egid,
context.ens,
context.umask,
),
};
let flags = (flags & (!0o777)) | ((flags & 0o777) & (!(umask & 0o777)));
@@ -63,7 +90,9 @@ pub fn open(raw_path: UserSliceRo, flags: usize) -> Result<FileHandle> {
let description = {
let (scheme_id, scheme) = {
let schemes = scheme::schemes();
let (scheme_id, scheme) = schemes.get_name(scheme_ns, scheme_name).ok_or(Error::new(ENODEV))?;
let (scheme_id, scheme) = schemes
.get_name(scheme_ns, scheme_name)
.ok_or(Error::new(ENODEV))?;
(scheme_id, scheme.clone())
};
@@ -79,10 +108,13 @@ pub fn open(raw_path: UserSliceRo, flags: usize) -> Result<FileHandle> {
};
//drop(path_buf);
context::current()?.read().add_file(FileDescriptor {
description,
cloexec: flags & O_CLOEXEC == O_CLOEXEC,
}).ok_or(Error::new(EMFILE))
context::current()?
.read()
.add_file(FileDescriptor {
description,
cloexec: flags & O_CLOEXEC == O_CLOEXEC,
})
.ok_or(Error::new(EMFILE))
}
/// rmdir syscall
@@ -103,7 +135,9 @@ pub fn rmdir(raw_path: UserSliceRo) -> Result<()> {
let scheme = {
let schemes = scheme::schemes();
let (_scheme_id, scheme) = schemes.get_name(scheme_ns, scheme_name).ok_or(Error::new(ENODEV))?;
let (_scheme_id, scheme) = schemes
.get_name(scheme_ns, scheme_name)
.ok_or(Error::new(ENODEV))?;
scheme.clone()
};
scheme.rmdir(reference, caller_ctx)
@@ -126,7 +160,9 @@ pub fn unlink(raw_path: UserSliceRo) -> Result<()> {
let scheme = {
let schemes = scheme::schemes();
let (_scheme_id, scheme) = schemes.get_name(scheme_ns, scheme_name).ok_or(Error::new(ENODEV))?;
let (_scheme_id, scheme) = schemes
.get_name(scheme_ns, scheme_name)
.ok_or(Error::new(ENODEV))?;
scheme.clone()
};
scheme.unlink(reference, caller_ctx)
@@ -146,7 +182,10 @@ pub fn close(fd: FileHandle) -> Result<()> {
fn duplicate_file(fd: FileHandle, user_buf: UserSliceRo) -> Result<FileDescriptor> {
let (file, caller_ctx) = match context::current()?.read() {
ref context => (context.get_file(fd).ok_or(Error::new(EBADF))?, context.caller_ctx()),
ref context => (
context.get_file(fd).ok_or(Error::new(EBADF))?,
context.caller_ctx(),
),
};
if user_buf.is_empty() {
@@ -159,7 +198,8 @@ fn duplicate_file(fd: FileHandle, user_buf: UserSliceRo) -> Result<FileDescripto
let new_description = {
let scheme = scheme::schemes()
.get(description.scheme).ok_or(Error::new(EBADF))?
.get(description.scheme)
.ok_or(Error::new(EBADF))?
.clone();
match scheme.kdup(description.number, user_buf, caller_ctx)? {
@@ -184,7 +224,10 @@ fn duplicate_file(fd: FileHandle, user_buf: UserSliceRo) -> Result<FileDescripto
pub fn dup(fd: FileHandle, buf: UserSliceRo) -> Result<FileHandle> {
let new_file = duplicate_file(fd, buf)?;
context::current()?.read().add_file(new_file).ok_or(Error::new(EMFILE))
context::current()?
.read()
.add_file(new_file)
.ok_or(Error::new(EMFILE))
}
/// Duplicate file descriptor, replacing another
@@ -199,7 +242,9 @@ pub fn dup2(fd: FileHandle, new_fd: FileHandle, buf: UserSliceRo) -> Result<File
let context_lock = contexts.current().ok_or(Error::new(ESRCH))?;
let context = context_lock.read();
context.insert_file(new_fd, new_file).ok_or(Error::new(EMFILE))
context
.insert_file(new_fd, new_file)
.ok_or(Error::new(EMFILE))
}
}
pub fn sendfd(socket: FileHandle, fd: FileHandle, flags_raw: usize, arg: u64) -> Result<usize> {
@@ -211,12 +256,27 @@ pub fn sendfd(socket: FileHandle, fd: FileHandle, flags_raw: usize, arg: u64) ->
// TODO: Ensure deadlocks can't happen
let (scheme, number) = match current.get_file(socket).ok_or(Error::new(EBADF))?.description.read() {
let (scheme, number) = match current
.get_file(socket)
.ok_or(Error::new(EBADF))?
.description
.read()
{
ref desc => (desc.scheme, desc.number),
};
let scheme = scheme::schemes().get(scheme).ok_or(Error::new(ENODEV))?.clone();
let scheme = scheme::schemes()
.get(scheme)
.ok_or(Error::new(ENODEV))?
.clone();
(scheme, number, current.remove_file(fd).ok_or(Error::new(EBADF))?.description)
(
scheme,
number,
current
.remove_file(fd)
.ok_or(Error::new(EBADF))?
.description,
)
};
// Inform the scheme whether there are still references to the file description to be sent,
@@ -249,7 +309,8 @@ pub fn fcntl(fd: FileHandle, cmd: usize, arg: usize) -> Result<usize> {
// Communicate fcntl with scheme
if cmd != F_DUPFD && cmd != F_GETFD && cmd != F_SETFD {
let scheme = scheme::schemes()
.get(description.scheme).ok_or(Error::new(EBADF))?
.get(description.scheme)
.ok_or(Error::new(EBADF))?
.clone();
scheme.fcntl(description.number, cmd, arg)?;
@@ -265,7 +326,8 @@ pub fn fcntl(fd: FileHandle, cmd: usize, arg: usize) -> Result<usize> {
let context_lock = contexts.current().ok_or(Error::new(ESRCH))?;
let context = context_lock.read();
return context.add_file_min(new_file, arg)
return context
.add_file_min(new_file, arg)
.ok_or(Error::new(EMFILE))
.map(FileHandle::into);
}
@@ -283,32 +345,36 @@ pub fn fcntl(fd: FileHandle, cmd: usize, arg: usize) -> Result<usize> {
} else {
Ok(0)
}
},
}
F_SETFD => {
file.cloexec = arg & O_CLOEXEC == O_CLOEXEC;
Ok(0)
},
F_GETFL => {
Ok(description.flags)
},
}
F_GETFL => Ok(description.flags),
F_SETFL => {
let new_flags = (description.flags & O_ACCMODE) | (arg & ! O_ACCMODE);
let new_flags = (description.flags & O_ACCMODE) | (arg & !O_ACCMODE);
drop(description);
file.description.write().flags = new_flags;
Ok(0)
},
_ => {
Err(Error::new(EINVAL))
}
_ => Err(Error::new(EINVAL)),
},
None => Err(Error::new(EBADF))
None => Err(Error::new(EBADF)),
}
}
}
pub fn frename(fd: FileHandle, raw_path: UserSliceRo) -> Result<()> {
let (file, caller_ctx, scheme_ns) = match context::current()?.read() {
ref context => (context.get_file(fd).ok_or(Error::new(EBADF))?, CallerCtx { uid: context.euid, gid: context.egid, pid: context.id.get() }, context.ens),
ref context => (
context.get_file(fd).ok_or(Error::new(EBADF))?,
CallerCtx {
uid: context.euid,
gid: context.egid,
pid: context.id.get(),
},
context.ens,
),
};
/*
@@ -323,7 +389,9 @@ pub fn frename(fd: FileHandle, raw_path: UserSliceRo) -> Result<()> {
let (scheme_id, scheme) = {
let schemes = scheme::schemes();
let (scheme_id, scheme) = schemes.get_name(scheme_ns, scheme_name).ok_or(Error::new(ENODEV))?;
let (scheme_id, scheme) = schemes
.get_name(scheme_ns, scheme_name)
.ok_or(Error::new(ENODEV))?;
(scheme_id, scheme.clone())
};
@@ -344,8 +412,15 @@ pub fn fstat(fd: FileHandle, user_buf: UserSliceWo) -> Result<()> {
// 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.get().try_into().map_err(|_| Error::new(EOVERFLOW))?;
user_buf.advance(core::mem::offset_of!(Stat, st_dev)).and_then(|b| b.limit(8)).ok_or(Error::new(EIO))?.copy_from_slice(&u64::to_ne_bytes(st_dev))?;
let st_dev = scheme_id
.get()
.try_into()
.map_err(|_| Error::new(EOVERFLOW))?;
user_buf
.advance(core::mem::offset_of!(Stat, st_dev))
.and_then(|b| b.limit(8))
.ok_or(Error::new(EIO))?
.copy_from_slice(&u64::to_ne_bytes(st_dev))?;
Ok(())
})
@@ -360,11 +435,16 @@ pub fn funmap(virtual_address: usize, length: usize) -> Result<usize> {
let length_aligned = length.next_multiple_of(PAGE_SIZE);
if length != length_aligned {
log::warn!("funmap passed length {:#x} instead of {:#x}", length, length_aligned);
log::warn!(
"funmap passed length {:#x} instead of {:#x}",
length,
length_aligned
);
}
let addr_space = Arc::clone(context::current()?.read().addr_space()?);
let span = PageSpan::validate_nonempty(VirtualAddress::new(virtual_address), length_aligned).ok_or(Error::new(EINVAL))?;
let span = PageSpan::validate_nonempty(VirtualAddress::new(virtual_address), length_aligned)
.ok_or(Error::new(EINVAL))?;
let unpin = false;
let notify = addr_space.write().munmap(span, unpin)?;
@@ -375,8 +455,18 @@ pub fn funmap(virtual_address: usize, length: usize) -> Result<usize> {
Ok(0)
}
pub fn mremap(old_address: usize, old_size: usize, new_address: usize, new_size: usize, flags: usize) -> Result<usize> {
if old_address % PAGE_SIZE != 0 || old_size % PAGE_SIZE != 0 || new_address % PAGE_SIZE != 0 || new_size % PAGE_SIZE != 0 {
pub fn mremap(
old_address: usize,
old_size: usize,
new_address: usize,
new_size: usize,
flags: usize,
) -> Result<usize> {
if old_address % PAGE_SIZE != 0
|| old_size % PAGE_SIZE != 0
|| new_address % PAGE_SIZE != 0
|| new_size % PAGE_SIZE != 0
{
return Err(Error::new(EINVAL));
}
if old_size == 0 || new_size == 0 {
@@ -387,7 +477,8 @@ pub fn mremap(old_address: usize, old_size: usize, new_address: usize, new_size:
let new_base = Page::containing_address(VirtualAddress::new(new_address));
let mremap_flags = MremapFlags::from_bits_truncate(flags);
let prot_flags = MapFlags::from_bits_truncate(flags) & (MapFlags::PROT_READ | MapFlags::PROT_WRITE | MapFlags::PROT_EXEC);
let prot_flags = MapFlags::from_bits_truncate(flags)
& (MapFlags::PROT_READ | MapFlags::PROT_WRITE | MapFlags::PROT_EXEC);
let map_flags = if mremap_flags.contains(MremapFlags::FIXED_REPLACE) {
MapFlags::MAP_FIXED
@@ -404,7 +495,15 @@ pub fn mremap(old_address: usize, old_size: usize, new_address: usize, new_size:
let mut guard = addr_space.write();
let base = AddrSpace::r#move(&mut *guard, None, src_span, requested_dst_base, new_page_count, map_flags, &mut Vec::new())?;
let base = AddrSpace::r#move(
&mut *guard,
None,
src_span,
requested_dst_base,
new_page_count,
map_flags,
&mut Vec::new(),
)?;
Ok(base.start_address().data())
}
+22 -14
View File
@@ -2,20 +2,23 @@
//! Futex or Fast Userspace Mutex is "a method for waiting until a certain condition becomes true."
//!
//! For more information about futexes, please read [this](https://eli.thegreenplace.net/2018/basics-of-futexes/) blog post, and the [futex(2)](http://man7.org/linux/man-pages/man2/futex.2.html) man page
use alloc::collections::VecDeque;
use alloc::sync::Arc;
use rmm::Arch;
use alloc::{collections::VecDeque, sync::Arc};
use core::sync::atomic::{AtomicU32, Ordering};
use rmm::Arch;
use spin::RwLock;
use crate::context::{self, memory::AddrSpace, Context};
use crate::memory::PhysicalAddress;
use crate::paging::{Page, VirtualAddress};
use crate::time;
use crate::{
context::{self, memory::AddrSpace, Context},
memory::PhysicalAddress,
paging::{Page, VirtualAddress},
time,
};
use crate::syscall::data::TimeSpec;
use crate::syscall::error::{Error, Result, EAGAIN, EFAULT, EINVAL, ESRCH};
use crate::syscall::flag::{FUTEX_REQUEUE, FUTEX_WAIT, FUTEX_WAIT64, FUTEX_WAKE};
use crate::syscall::{
data::TimeSpec,
error::{Error, Result, EAGAIN, EFAULT, EINVAL, ESRCH},
flag::{FUTEX_REQUEUE, FUTEX_WAIT, FUTEX_WAIT64, FUTEX_WAKE},
};
use super::usercopy::UserSlice;
@@ -58,8 +61,10 @@ pub fn futex(addr: usize, op: usize, val: usize, val2: usize, addr2: usize) -> R
match op {
// TODO: FUTEX_WAIT_MULTIPLE?
FUTEX_WAIT | FUTEX_WAIT64 => {
let timeout_opt = UserSlice::ro(val2, core::mem::size_of::<TimeSpec>())?.none_if_null()
.map(|buf| unsafe { buf.read_exact::<TimeSpec>() }).transpose()?;
let timeout_opt = UserSlice::ro(val2, core::mem::size_of::<TimeSpec>())?
.none_if_null()
.map(|buf| unsafe { buf.read_exact::<TimeSpec>() })
.transpose()?;
{
let mut futexes = FUTEXES.write();
@@ -75,7 +80,8 @@ pub fn futex(addr: usize, op: usize, val: usize, val2: usize, addr2: usize) -> R
// On systems where virtual memory is not abundant, we might instead add an
// atomic usercopy function.
let accessible_addr = unsafe { crate::paging::RmmA::phys_to_virt(target_physaddr) }.data();
let accessible_addr =
unsafe { crate::paging::RmmA::phys_to_virt(target_physaddr) }.data();
(
u64::from(unsafe {
@@ -93,7 +99,9 @@ pub fn futex(addr: usize, op: usize, val: usize, val2: usize, addr2: usize) -> R
return Err(Error::new(EINVAL));
}
(
u64::from(unsafe { (*(addr as *const AtomicU64)).load(Ordering::SeqCst) }),
u64::from(unsafe {
(*(addr as *const AtomicU64)).load(Ordering::SeqCst)
}),
val as u64,
)
}
+110 -55
View File
@@ -7,35 +7,26 @@ extern crate syscall;
use syscall::{EventFlags, EOVERFLOW};
pub use self::syscall::{
FloatRegisters,
IntRegisters,
EnvRegisters,
data,
error,
flag,
io,
number,
ptrace_event,
data, error, flag, io, number, ptrace_event, EnvRegisters, FloatRegisters, IntRegisters,
};
pub use self::driver::*;
pub use self::fs::*;
pub use self::futex::futex;
pub use self::privilege::*;
pub use self::process::*;
pub use self::time::*;
pub use self::usercopy::validate_region;
pub use self::{
driver::*, fs::*, futex::futex, privilege::*, process::*, time::*, usercopy::validate_region,
};
use self::data::{Map, SigAction, TimeSpec};
use self::error::{Error, Result, ENOSYS};
use self::flag::{MapFlags, WaitFlags};
use self::number::*;
use self::{
data::{Map, SigAction, TimeSpec},
error::{Error, Result, ENOSYS},
flag::{MapFlags, WaitFlags},
number::*,
};
use crate::context::ContextId;
use crate::context::memory::AddrSpace;
use crate::interrupt::InterruptStack;
use crate::scheme::{FileHandle, SchemeNamespace, memory::MemoryScheme};
use crate::syscall::usercopy::UserSlice;
use crate::{
context::{memory::AddrSpace, ContextId},
interrupt::InterruptStack,
scheme::{memory::MemoryScheme, FileHandle, SchemeNamespace},
syscall::usercopy::UserSlice,
};
/// Debug
pub mod debug;
@@ -63,79 +54,128 @@ pub mod usercopy;
/// This function is the syscall handler of the kernel, it is composed of an inner function that returns a `Result<usize>`. After the inner function runs, the syscall
/// function calls [`Error::mux`] on it.
pub fn syscall(a: usize, b: usize, c: usize, d: usize, e: usize, f: usize, stack: &mut InterruptStack) -> usize {
pub fn syscall(
a: usize,
b: usize,
c: usize,
d: usize,
e: usize,
f: usize,
stack: &mut InterruptStack,
) -> usize {
#[inline(always)]
fn inner(a: usize, b: usize, c: usize, d: usize, e: usize, f: usize, stack: &mut InterruptStack) -> Result<usize> {
fn inner(
a: usize,
b: usize,
c: usize,
d: usize,
e: usize,
f: usize,
stack: &mut InterruptStack,
) -> Result<usize> {
//SYS_* is declared in kernel/syscall/src/number.rs
match a & SYS_CLASS {
SYS_CLASS_FILE => {
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_WRITE => file_op_generic(fd, |scheme, _, number| {
scheme.kwrite(number, UserSlice::ro(c, d)?)
}),
SYS_FMAP => {
let addrspace = AddrSpace::current()?;
let map = unsafe { UserSlice::ro(c, d)?.read_exact::<Map>()? };
if b == !0 {
MemoryScheme::fmap_anonymous(&addrspace, &map, false)
} else {
file_op_generic(fd, |scheme, _, number| scheme.kfmap(number, &addrspace, &map, false))
file_op_generic(fd, |scheme, _, number| {
scheme.kfmap(number, &addrspace, &map, false)
})
}
},
}
// SYS_FMAP_OLD is ignored
SYS_FUTIMENS => file_op_generic(fd, |scheme, _, number| scheme.kfutimens(number, UserSlice::ro(c, d)?)),
SYS_FUTIMENS => file_op_generic(fd, |scheme, _, number| {
scheme.kfutimens(number, UserSlice::ro(c, d)?)
}),
_ => 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_FPATH => file_op_generic(fd, |scheme, _, number| scheme.kfpath(number, UserSlice::wo(c, d)?)),
SYS_READ => file_op_generic(fd, |scheme, _, number| {
scheme.kread(number, UserSlice::wo(c, d)?)
}),
SYS_FPATH => file_op_generic(fd, |scheme, _, number| {
scheme.kfpath(number, UserSlice::wo(c, d)?)
}),
SYS_FSTAT => fstat(fd, UserSlice::wo(c, d)?).map(|()| 0),
SYS_FSTATVFS => file_op_generic(fd, |scheme, _, number| scheme.kfstatvfs(number, UserSlice::wo(c, d)?).map(|()| 0)),
SYS_FSTATVFS => file_op_generic(fd, |scheme, _, number| {
scheme.kfstatvfs(number, UserSlice::wo(c, d)?).map(|()| 0)
}),
_ => return Err(Error::new(ENOSYS)),
},
_ => match a {
SYS_DUP => dup(fd, UserSlice::ro(c, d)?).map(FileHandle::into),
SYS_DUP2 => dup2(fd, FileHandle::from(c), UserSlice::ro(d, e)?).map(FileHandle::into),
SYS_DUP2 => dup2(fd, FileHandle::from(c), UserSlice::ro(d, e)?)
.map(FileHandle::into),
#[cfg(target_pointer_width = "32")]
SYS_SENDFD => sendfd(fd, FileHandle::from(c), d, e as u64 | ((f as u64) << 32)),
SYS_SENDFD => {
sendfd(fd, FileHandle::from(c), d, e as u64 | ((f as u64) << 32))
}
#[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_FCHMOD => file_op_generic(fd, |scheme, _, number| scheme.fchmod(number, c as u16).map(|()| 0)),
SYS_FCHOWN => file_op_generic(fd, |scheme, _, number| scheme.fchown(number, c as u32, d as u32).map(|()| 0)),
SYS_LSEEK => file_op_generic(fd, |scheme, _, number| {
scheme.seek(number, c as isize, d)
}),
SYS_FCHMOD => file_op_generic(fd, |scheme, _, number| {
scheme.fchmod(number, c as u16).map(|()| 0)
}),
SYS_FCHOWN => file_op_generic(fd, |scheme, _, number| {
scheme.fchown(number, c as u32, d as u32).map(|()| 0)
}),
SYS_FCNTL => fcntl(fd, c, d),
SYS_FEVENT => file_op_generic(fd, |scheme, _, number| Ok(scheme.fevent(number, EventFlags::from_bits_truncate(c))?.bits())),
SYS_FEVENT => file_op_generic(fd, |scheme, _, number| {
Ok(scheme
.fevent(number, EventFlags::from_bits_truncate(c))?
.bits())
}),
SYS_FRENAME => frename(fd, UserSlice::ro(c, d)?).map(|()| 0),
SYS_FUNMAP => funmap(b, c),
SYS_FSYNC => file_op_generic(fd, |scheme, _, number| scheme.fsync(number).map(|()| 0)),
SYS_FSYNC => file_op_generic(fd, |scheme, _, number| {
scheme.fsync(number).map(|()| 0)
}),
// TODO: 64-bit lengths on 32-bit platforms
SYS_FTRUNCATE => file_op_generic(fd, |scheme, _, number| scheme.ftruncate(number, c).map(|()| 0)),
SYS_FTRUNCATE => file_op_generic(fd, |scheme, _, number| {
scheme.ftruncate(number, c).map(|()| 0)
}),
SYS_CLOSE => close(fd).map(|()| 0),
_ => return Err(Error::new(ENOSYS)),
}
},
}
},
}
SYS_CLASS_PATH => match a {
SYS_OPEN => open(UserSlice::ro(b, c)?, d).map(FileHandle::into),
SYS_RMDIR => rmdir(UserSlice::ro(b, c)?).map(|()| 0),
SYS_UNLINK => unlink(UserSlice::ro(b, c)?).map(|()| 0),
_ => Err(Error::new(ENOSYS))
_ => Err(Error::new(ENOSYS)),
},
_ => match a {
SYS_YIELD => sched_yield().map(|()| 0),
SYS_NANOSLEEP => nanosleep(
UserSlice::ro(b, core::mem::size_of::<TimeSpec>())?,
UserSlice::wo(c, core::mem::size_of::<TimeSpec>())?.none_if_null(),
).map(|()| 0),
SYS_CLOCK_GETTIME => clock_gettime(b, UserSlice::wo(c, core::mem::size_of::<TimeSpec>())?).map(|()| 0),
)
.map(|()| 0),
SYS_CLOCK_GETTIME => {
clock_gettime(b, UserSlice::wo(c, core::mem::size_of::<TimeSpec>())?)
.map(|()| 0)
}
SYS_FUTEX => futex(b, c, d, e, f),
SYS_GETPID => getpid().map(ContextId::into),
SYS_GETPGID => getpgid(ContextId::from(b)).map(ContextId::into),
@@ -143,7 +183,16 @@ pub fn syscall(a: usize, b: usize, c: usize, d: usize, e: usize, f: usize, stack
SYS_EXIT => exit((b & 0xFF) << 8),
SYS_KILL => kill(ContextId::from(b), c),
SYS_WAITPID => waitpid(ContextId::from(b), if c == 0 { None } else { Some(UserSlice::wo(c, core::mem::size_of::<usize>())?) }, WaitFlags::from_bits_truncate(d)).map(ContextId::into),
SYS_WAITPID => waitpid(
ContextId::from(b),
if c == 0 {
None
} else {
Some(UserSlice::wo(c, core::mem::size_of::<usize>())?)
},
WaitFlags::from_bits_truncate(d),
)
.map(ContextId::into),
SYS_IOPL => iopl(b, stack),
SYS_GETEGID => getegid(),
SYS_GETENS => getens(),
@@ -152,7 +201,11 @@ pub fn syscall(a: usize, b: usize, c: usize, d: usize, e: usize, f: usize, stack
SYS_GETNS => getns(),
SYS_GETUID => getuid(),
SYS_MPROTECT => mprotect(b, c, MapFlags::from_bits_truncate(d)),
SYS_MKNS => mkns(UserSlice::ro(b, c.checked_mul(core::mem::size_of::<[usize; 2]>()).ok_or(Error::new(EOVERFLOW))?)?),
SYS_MKNS => mkns(UserSlice::ro(
b,
c.checked_mul(core::mem::size_of::<[usize; 2]>())
.ok_or(Error::new(EOVERFLOW))?,
)?),
SYS_SETPGID => setpgid(ContextId::from(b), ContextId::from(c)),
SYS_SETREUID => setreuid(b as u32, c as u32),
SYS_SETRENS => setrens(SchemeNamespace::from(b), SchemeNamespace::from(c)),
@@ -162,20 +215,22 @@ pub fn syscall(a: usize, b: usize, c: usize, d: usize, e: usize, f: usize, stack
UserSlice::ro(c, core::mem::size_of::<SigAction>())?.none_if_null(),
UserSlice::wo(d, core::mem::size_of::<SigAction>())?.none_if_null(),
e,
).map(|()| 0),
)
.map(|()| 0),
SYS_SIGPROCMASK => sigprocmask(
b,
UserSlice::ro(c, 16)?.none_if_null(),
UserSlice::wo(d, 16)?.none_if_null(),
).map(|()| 0),
)
.map(|()| 0),
SYS_SIGRETURN => sigreturn(),
SYS_UMASK => umask(b),
SYS_VIRTTOPHYS => virttophys(b),
SYS_MREMAP => mremap(b, c, d, e, f),
_ => Err(Error::new(ENOSYS))
}
_ => Err(Error::new(ENOSYS)),
},
}
}
@@ -258,7 +313,7 @@ pub fn syscall(a: usize, b: usize, c: usize, d: usize, e: usize, f: usize, stack
match result {
Ok(ref ok) => {
print!("Ok({} ({:#X}))", ok, ok);
},
}
Err(ref err) => {
print!("Err({} ({:#X}))", err, err.errno);
}
+120 -120
View File
@@ -1,11 +1,15 @@
use alloc::vec::Vec;
use crate::context;
use crate::scheme::{self, SchemeNamespace};
use crate::syscall::error::*;
use crate::{
context,
scheme::{self, SchemeNamespace},
syscall::error::*,
};
use super::copy_path_to_buf;
use super::usercopy::{UserSlice, UserSliceRo};
use super::{
copy_path_to_buf,
usercopy::{UserSlice, UserSliceRo},
};
pub fn getegid() -> Result<usize> {
let contexts = context::contexts();
@@ -61,7 +65,9 @@ pub fn mkns(mut user_buf: UserSliceRo) -> Result<usize> {
let mut names = Vec::with_capacity(user_buf.len() / core::mem::size_of::<[usize; 2]>());
while let Some((current_name_ptr_buf, next_part)) = user_buf.split_at(core::mem::size_of::<[usize; 2]>()) {
while let Some((current_name_ptr_buf, next_part)) =
user_buf.split_at(core::mem::size_of::<[usize; 2]>())
{
let mut iter = current_name_ptr_buf.usizes();
let ptr = iter.next().ok_or(Error::new(EINVAL))??;
let len = iter.next().ok_or(Error::new(EINVAL))??;
@@ -85,41 +91,39 @@ pub fn setregid(rgid: u32, egid: u32) -> Result<usize> {
let context_lock = contexts.current().ok_or(Error::new(ESRCH))?;
let mut context = context_lock.write();
let setrgid =
if context.euid == 0 {
// Allow changing RGID if root
true
} else if rgid == context.egid {
// Allow changing RGID if used for EGID
true
} else if rgid == context.rgid {
// Allow changing RGID if used for RGID
true
} else if rgid as i32 == -1 {
// Ignore RGID if -1 is passed
false
} else {
// Not permitted otherwise
return Err(Error::new(EPERM));
};
let setrgid = if context.euid == 0 {
// Allow changing RGID if root
true
} else if rgid == context.egid {
// Allow changing RGID if used for EGID
true
} else if rgid == context.rgid {
// Allow changing RGID if used for RGID
true
} else if rgid as i32 == -1 {
// Ignore RGID if -1 is passed
false
} else {
// Not permitted otherwise
return Err(Error::new(EPERM));
};
let setegid =
if context.euid == 0 {
// Allow changing EGID if root
true
} else if egid == context.egid {
// Allow changing EGID if used for EGID
true
} else if egid == context.rgid {
// Allow changing EGID if used for RGID
true
} else if egid as i32 == -1 {
// Ignore EGID if -1 is passed
false
} else {
// Not permitted otherwise
return Err(Error::new(EPERM));
};
let setegid = if context.euid == 0 {
// Allow changing EGID if root
true
} else if egid == context.egid {
// Allow changing EGID if used for EGID
true
} else if egid == context.rgid {
// Allow changing EGID if used for RGID
true
} else if egid as i32 == -1 {
// Ignore EGID if -1 is passed
false
} else {
// Not permitted otherwise
return Err(Error::new(EPERM));
};
if setrgid {
context.rgid = rgid;
@@ -137,53 +141,51 @@ pub fn setrens(rns: SchemeNamespace, ens: SchemeNamespace) -> Result<usize> {
let context_lock = contexts.current().ok_or(Error::new(ESRCH))?;
let mut context = context_lock.write();
let setrns =
if rns.get() as isize == -1 {
// Ignore RNS if -1 is passed
false
} else if rns.get() == 0 {
// Allow entering capability mode
true
} else if context.rns.get() == 0 {
// Do not allow leaving capability mode
return Err(Error::new(EPERM));
} else if context.euid == 0 {
// Allow setting RNS if root
true
} else if rns == context.ens {
// Allow setting RNS if used for ENS
true
} else if rns == context.rns {
// Allow setting RNS if used for RNS
true
} else {
// Not permitted otherwise
return Err(Error::new(EPERM));
};
let setrns = if rns.get() as isize == -1 {
// Ignore RNS if -1 is passed
false
} else if rns.get() == 0 {
// Allow entering capability mode
true
} else if context.rns.get() == 0 {
// Do not allow leaving capability mode
return Err(Error::new(EPERM));
} else if context.euid == 0 {
// Allow setting RNS if root
true
} else if rns == context.ens {
// Allow setting RNS if used for ENS
true
} else if rns == context.rns {
// Allow setting RNS if used for RNS
true
} else {
// Not permitted otherwise
return Err(Error::new(EPERM));
};
let setens =
if ens.get() as isize == -1 {
// Ignore ENS if -1 is passed
false
} else if ens.get() == 0 {
// Allow entering capability mode
true
} else if context.ens.get() == 0 {
// Do not allow leaving capability mode
return Err(Error::new(EPERM));
} else if context.euid == 0 {
// Allow setting ENS if root
true
} else if ens == context.ens {
// Allow setting ENS if used for ENS
true
} else if ens == context.rns {
// Allow setting ENS if used for RNS
true
} else {
// Not permitted otherwise
return Err(Error::new(EPERM));
};
let setens = if ens.get() as isize == -1 {
// Ignore ENS if -1 is passed
false
} else if ens.get() == 0 {
// Allow entering capability mode
true
} else if context.ens.get() == 0 {
// Do not allow leaving capability mode
return Err(Error::new(EPERM));
} else if context.euid == 0 {
// Allow setting ENS if root
true
} else if ens == context.ens {
// Allow setting ENS if used for ENS
true
} else if ens == context.rns {
// Allow setting ENS if used for RNS
true
} else {
// Not permitted otherwise
return Err(Error::new(EPERM));
};
if setrns {
assert_ne!(rns.get() as isize, -1);
@@ -203,41 +205,39 @@ pub fn setreuid(ruid: u32, euid: u32) -> Result<usize> {
let context_lock = contexts.current().ok_or(Error::new(ESRCH))?;
let mut context = context_lock.write();
let setruid =
if context.euid == 0 {
// Allow setting RUID if root
true
} else if ruid == context.euid {
// Allow setting RUID if used for EUID
true
} else if ruid == context.ruid {
// Allow setting RUID if used for RUID
true
} else if ruid as i32 == -1 {
// Ignore RUID if -1 is passed
false
} else {
// Not permitted otherwise
return Err(Error::new(EPERM));
};
let setruid = if context.euid == 0 {
// Allow setting RUID if root
true
} else if ruid == context.euid {
// Allow setting RUID if used for EUID
true
} else if ruid == context.ruid {
// Allow setting RUID if used for RUID
true
} else if ruid as i32 == -1 {
// Ignore RUID if -1 is passed
false
} else {
// Not permitted otherwise
return Err(Error::new(EPERM));
};
let seteuid =
if context.euid == 0 {
// Allow setting EUID if root
true
} else if euid == context.euid {
// Allow setting EUID if used for EUID
true
} else if euid == context.ruid {
// Allow setting EUID if used for RUID
true
} else if euid as i32 == -1 {
// Ignore EUID if -1 is passed
false
} else {
// Not permitted otherwise
return Err(Error::new(EPERM));
};
let seteuid = if context.euid == 0 {
// Allow setting EUID if root
true
} else if euid == context.euid {
// Allow setting EUID if used for EUID
true
} else if euid == context.ruid {
// Allow setting EUID if used for RUID
true
} else if euid as i32 == -1 {
// Ignore EUID if -1 is passed
false
} else {
// Not permitted otherwise
return Err(Error::new(EPERM));
};
if setruid {
context.ruid = ruid;
+132 -82
View File
@@ -1,32 +1,37 @@
use alloc::{
sync::Arc,
vec::Vec,
};
use alloc::{sync::Arc, vec::Vec};
use core::mem;
use spin::RwLock;
use crate::context::memory::PageSpan;
use crate::context::{ContextId, memory::AddrSpace, WaitpidKey};
use crate::context::{
memory::{AddrSpace, PageSpan},
ContextId, WaitpidKey,
};
use crate::Bootstrap;
use crate::context;
use crate::interrupt;
use crate::paging::mapper::PageFlushAll;
use crate::paging::{Page, PageFlags, VirtualAddress, PAGE_SIZE};
use crate::ptrace;
use crate::start::usermode;
use crate::syscall::data::SigAction;
use crate::syscall::error::*;
use crate::syscall::flag::{wifcontinued, wifstopped, MapFlags,
PTRACE_STOP_EXIT, SIG_BLOCK, SIG_SETMASK, SIG_UNBLOCK,
SIGCONT, SIGTERM, WaitFlags, WCONTINUED, WNOHANG, WUNTRACED};
use crate::syscall::ptrace_event;
use crate::{
context, interrupt,
paging::{mapper::PageFlushAll, Page, PageFlags, VirtualAddress, PAGE_SIZE},
ptrace,
start::usermode,
syscall::{
data::SigAction,
error::*,
flag::{
wifcontinued, wifstopped, MapFlags, WaitFlags, PTRACE_STOP_EXIT, SIGCONT, SIGTERM,
SIG_BLOCK, SIG_SETMASK, SIG_UNBLOCK, WCONTINUED, WNOHANG, WUNTRACED,
},
ptrace_event,
},
Bootstrap,
};
use super::usercopy::{UserSliceWo, UserSliceRo};
use super::usercopy::{UserSliceRo, UserSliceWo};
pub fn exit(status: usize) -> ! {
ptrace::breakpoint_callback(PTRACE_STOP_EXIT, Some(ptrace_event!(PTRACE_STOP_EXIT, status)));
ptrace::breakpoint_callback(
PTRACE_STOP_EXIT,
Some(ptrace_event!(PTRACE_STOP_EXIT, status)),
);
{
let context_lock = context::current().expect("exit failed to find context");
@@ -36,8 +41,10 @@ pub fn exit(status: usize) -> ! {
let pid = {
let mut context = context_lock.write();
close_files = Arc::try_unwrap(mem::take(&mut context.files)).map_or_else(|_| Vec::new(), RwLock::into_inner);
addrspace_opt = mem::take(&mut context.addr_space).and_then(|a| Arc::try_unwrap(a).ok());
close_files = Arc::try_unwrap(mem::take(&mut context.files))
.map_or_else(|_| Vec::new(), RwLock::into_inner);
addrspace_opt =
mem::take(&mut context.addr_space).and_then(|a| Arc::try_unwrap(a).ok());
drop(context.syscall_head.take());
drop(context.syscall_tail.take());
context.id
@@ -47,15 +54,19 @@ pub fn exit(status: usize) -> ! {
if pid == ContextId::from(1) {
println!("Main kernel thread exited with status {:X}", status);
extern {
extern "C" {
fn kreset() -> !;
fn kstop() -> !;
}
if status == SIGTERM {
unsafe { kreset(); }
unsafe {
kreset();
}
} else {
unsafe { kstop(); }
unsafe {
kstop();
}
}
}
@@ -101,10 +112,13 @@ pub fn exit(status: usize) -> ! {
waitpid.send(c_pid, c_status);
}
waitpid.send(WaitpidKey {
pid: Some(pid),
pgid: Some(pgid)
}, (pid, status));
waitpid.send(
WaitpidKey {
pid: Some(pid),
pgid: Some(pgid),
},
(pid, status),
);
}
}
@@ -158,10 +172,7 @@ pub fn kill(pid: ContextId, sig: usize) -> Result<usize> {
let contexts = context::contexts();
let send = |context: &mut context::Context| -> bool {
if euid == 0
|| euid == context.ruid
|| ruid == context.ruid
{
if euid == 0 || euid == context.ruid || ruid == context.ruid {
// If sig = 0, test that process exists and can be
// signalled, but don't send any signal.
if sig != 0 {
@@ -231,7 +242,9 @@ pub fn kill(pid: ContextId, sig: usize) -> Result<usize> {
Err(Error::new(EPERM))
} else {
// Switch to ensure delivery to self
unsafe { context::switch(); }
unsafe {
context::switch();
}
Ok(0)
}
@@ -243,9 +256,13 @@ pub fn kill(pid: ContextId, sig: usize) -> Result<usize> {
pub fn mprotect(address: usize, size: usize, flags: MapFlags) -> Result<usize> {
// println!("mprotect {:#X}, {}, {:#X}", address, size, flags);
let span = PageSpan::validate_nonempty(VirtualAddress::new(address), size).ok_or(Error::new(EINVAL))?;
let span = PageSpan::validate_nonempty(VirtualAddress::new(address), size)
.ok_or(Error::new(EINVAL))?;
AddrSpace::current()?.write().mprotect(span, flags).map(|()| 0)
AddrSpace::current()?
.write()
.mprotect(span, flags)
.map(|()| 0)
}
pub fn setpgid(pid: ContextId, pgid: ContextId) -> Result<usize> {
@@ -276,7 +293,12 @@ pub fn setpgid(pid: ContextId, pgid: ContextId) -> Result<usize> {
}
}
pub fn sigaction(sig: usize, act_opt: Option<UserSliceRo>, oldact_opt: Option<UserSliceWo>, restorer: usize) -> Result<()> {
pub fn sigaction(
sig: usize,
act_opt: Option<UserSliceRo>,
oldact_opt: Option<UserSliceWo>,
restorer: usize,
) -> Result<()> {
if sig == 0 || sig > 0x7F {
return Err(Error::new(EINVAL));
}
@@ -296,7 +318,11 @@ pub fn sigaction(sig: usize, act_opt: Option<UserSliceRo>, oldact_opt: Option<Us
Ok(())
}
pub fn sigprocmask(how: usize, mask_opt: Option<UserSliceRo>, oldmask_opt: Option<UserSliceWo>) -> Result<()> {
pub fn sigprocmask(
how: usize,
mask_opt: Option<UserSliceRo>,
oldmask_opt: Option<UserSliceWo>,
) -> Result<()> {
{
let contexts = context::contexts();
let context_lock = contexts.current().ok_or(Error::new(ESRCH))?;
@@ -306,26 +332,24 @@ pub fn sigprocmask(how: usize, mask_opt: Option<UserSliceRo>, oldmask_opt: Optio
if let Some(oldmask) = oldmask_opt {
// TODO: sigprocmask should be u64
let (lo_dst, hi_dst) = oldmask.split_at(core::mem::size_of::<u64>()).ok_or(Error::new(EINVAL))?;
let (lo_dst, hi_dst) = oldmask
.split_at(core::mem::size_of::<u64>())
.ok_or(Error::new(EINVAL))?;
lo_dst.write_u64(old_lo)?;
hi_dst.write_u64(old_hi)?;
}
if let Some(mask) = mask_opt {
let (lo_src, hi_src) = mask.split_at(core::mem::size_of::<u64>()).ok_or(Error::new(EINVAL))?;
let (lo_src, hi_src) = mask
.split_at(core::mem::size_of::<u64>())
.ok_or(Error::new(EINVAL))?;
let lo_arg = lo_src.read_u64()?;
let hi_arg = hi_src.read_u64()?;
context.sigmask = match how {
SIG_BLOCK => {
[old_lo | lo_arg, old_hi | hi_arg]
},
SIG_UNBLOCK => {
[old_lo & !lo_arg, old_hi & !hi_arg]
},
SIG_SETMASK => {
[lo_arg, hi_arg]
},
SIG_BLOCK => [old_lo | lo_arg, old_hi | hi_arg],
SIG_UNBLOCK => [old_lo & !lo_arg, old_hi & !hi_arg],
SIG_SETMASK => [lo_arg, hi_arg],
_ => {
return Err(Error::new(EINVAL));
}
@@ -382,19 +406,28 @@ fn reap(pid: ContextId) -> Result<ContextId> {
}
let _ = context::contexts_mut()
.remove(pid).ok_or(Error::new(ESRCH))?;
.remove(pid)
.ok_or(Error::new(ESRCH))?;
Ok(pid)
}
pub fn waitpid(pid: ContextId, status_ptr: Option<UserSliceWo>, flags: WaitFlags) -> Result<ContextId> {
pub fn waitpid(
pid: ContextId,
status_ptr: Option<UserSliceWo>,
flags: WaitFlags,
) -> Result<ContextId> {
let (ppid, waitpid) = {
let contexts = context::contexts();
let context_lock = contexts.current().ok_or(Error::new(ESRCH))?;
let context = context_lock.read();
(context.id, Arc::clone(&context.waitpid))
};
let write_status = |value| status_ptr.map(|ptr| ptr.write_usize(value)).unwrap_or(Ok(()));
let write_status = |value| {
status_ptr
.map(|ptr| ptr.write_usize(value))
.unwrap_or(Ok(()))
};
let grim_reaper = |w_pid: ContextId, status: usize| -> Option<Result<ContextId>> {
if wifcontinued(status) {
@@ -429,7 +462,7 @@ pub fn waitpid(pid: ContextId, status_ptr: Option<UserSliceWo>, flags: WaitFlags
}
}
if ! found {
if !found {
return Err(Error::new(ECHILD));
}
}
@@ -460,7 +493,7 @@ pub fn waitpid(pid: ContextId, status_ptr: Option<UserSliceWo>, flags: WaitFlags
}
}
if ! found {
if !found {
return Err(Error::new(ECHILD));
}
}
@@ -468,17 +501,20 @@ pub fn waitpid(pid: ContextId, status_ptr: Option<UserSliceWo>, flags: WaitFlags
if flags & WNOHANG == WNOHANG {
if let Some((w_pid, status)) = waitpid.receive_nonblock(&WaitpidKey {
pid: None,
pgid: Some(pgid)
pgid: Some(pgid),
}) {
grim_reaper(w_pid, status)
} else {
Some(Ok(ContextId::from(0)))
}
} else {
let (w_pid, status) = waitpid.receive(&WaitpidKey {
pid: None,
pgid: Some(pgid)
}, "waitpid pgid");
let (w_pid, status) = waitpid.receive(
&WaitpidKey {
pid: None,
pgid: Some(pgid),
},
"waitpid pgid",
);
grim_reaper(w_pid, status)
}
} else {
@@ -487,7 +523,12 @@ pub fn waitpid(pid: ContextId, status_ptr: Option<UserSliceWo>, flags: WaitFlags
let context_lock = contexts.get(pid).ok_or(Error::new(ECHILD))?;
let mut context = context_lock.write();
if context.ppid != ppid {
println!("TODO: Hack for rustc - changing ppid of {} from {} to {}", context.id.get(), context.ppid.get(), ppid.get());
println!(
"TODO: Hack for rustc - changing ppid of {} from {} to {}",
context.id.get(),
context.ppid.get(),
ppid.get()
);
context.ppid = ppid;
//return Err(Error::new(ECHILD));
Some(context.status.clone())
@@ -499,23 +540,26 @@ pub fn waitpid(pid: ContextId, status_ptr: Option<UserSliceWo>, flags: WaitFlags
if let Some(context::Status::Exited(status)) = hack_status {
let _ = waitpid.receive_nonblock(&WaitpidKey {
pid: Some(pid),
pgid: None
pgid: None,
});
grim_reaper(pid, status)
} else if flags & WNOHANG == WNOHANG {
if let Some((w_pid, status)) = waitpid.receive_nonblock(&WaitpidKey {
pid: Some(pid),
pgid: None
pgid: None,
}) {
grim_reaper(w_pid, status)
} else {
Some(Ok(ContextId::from(0)))
}
} else {
let (w_pid, status) = waitpid.receive(&WaitpidKey {
pid: Some(pid),
pgid: None
}, "waitpid pid");
let (w_pid, status) = waitpid.receive(
&WaitpidKey {
pid: Some(pid),
pgid: None,
},
"waitpid pid",
);
grim_reaper(w_pid, status)
}
};
@@ -530,10 +574,14 @@ pub unsafe fn usermode_bootstrap(bootstrap: &Bootstrap) -> ! {
assert_ne!(bootstrap.page_count, 0);
{
let addr_space = Arc::clone(context::contexts().current()
.expect("expected a context to exist when executing init")
.read().addr_space()
.expect("expected bootstrap context to have an address space"));
let addr_space = Arc::clone(
context::contexts()
.current()
.expect("expected a context to exist when executing init")
.read()
.addr_space()
.expect("expected bootstrap context to have an address space"),
);
// TODO: Use AddrSpace::mmap.
let mut addr_space = addr_space.write();
@@ -541,17 +589,19 @@ pub unsafe fn usermode_bootstrap(bootstrap: &Bootstrap) -> ! {
// TODO: Mark as owned and then support reclaiming the memory to the allocator if
// deallocated?
addr_space.grants.insert(context::memory::Grant::zeroed(
PageSpan::new(
Page::containing_address(VirtualAddress::new(0)),
bootstrap.page_count,
),
PageFlags::new().user(true).write(true).execute(true),
&mut addr_space.table.utable,
PageFlushAll::new(),
false, // is_shared
).expect("failed to physmap bootstrap memory"));
addr_space.grants.insert(
context::memory::Grant::zeroed(
PageSpan::new(
Page::containing_address(VirtualAddress::new(0)),
bootstrap.page_count,
),
PageFlags::new().user(true).write(true).execute(true),
&mut addr_space.table.utable,
PageFlushAll::new(),
false, // is_shared
)
.expect("failed to physmap bootstrap memory"),
);
}
// TODO: Not all arches do linear mapping
UserSliceWo::new(0, bootstrap.page_count * PAGE_SIZE)
+16 -8
View File
@@ -1,8 +1,12 @@
use crate::time;
use crate::context;
use crate::syscall::data::TimeSpec;
use crate::syscall::error::*;
use crate::syscall::flag::{CLOCK_REALTIME, CLOCK_MONOTONIC};
use crate::{
context,
syscall::{
data::TimeSpec,
error::*,
flag::{CLOCK_MONOTONIC, CLOCK_REALTIME},
},
time,
};
use super::usercopy::{UserSliceRo, UserSliceWo};
@@ -10,7 +14,7 @@ pub fn clock_gettime(clock: usize, buf: UserSliceWo) -> Result<()> {
let arch_time = match clock {
CLOCK_REALTIME => time::realtime(),
CLOCK_MONOTONIC => time::monotonic(),
_ => return Err(Error::new(EINVAL))
_ => return Err(Error::new(EINVAL)),
};
buf.copy_exactly(&TimeSpec {
@@ -38,7 +42,9 @@ pub fn nanosleep(req_buf: UserSliceRo, rem_buf_opt: Option<UserSliceWo>) -> Resu
//TODO: Find out wake reason
loop {
unsafe { context::switch(); }
unsafe {
context::switch();
}
let contexts = context::contexts();
let context_lock = contexts.current().ok_or(Error::new(ESRCH))?;
@@ -71,6 +77,8 @@ pub fn nanosleep(req_buf: UserSliceRo, rem_buf_opt: Option<UserSliceWo>) -> Resu
}
pub fn sched_yield() -> Result<()> {
unsafe { context::switch(); }
unsafe {
context::switch();
}
Ok(())
}
+79 -31
View File
@@ -1,9 +1,11 @@
use crate::paging::{Page, VirtualAddress};
use crate::memory::PAGE_SIZE;
use crate::{
memory::PAGE_SIZE,
paging::{Page, VirtualAddress},
};
use crate::arch::{arch_copy_to_user, arch_copy_from_user};
use crate::arch::{arch_copy_from_user, arch_copy_to_user};
use crate::syscall::error::{Error, EINVAL, EFAULT, Result};
use crate::syscall::error::{Error, Result, EFAULT, EINVAL};
#[derive(Clone, Copy)]
pub struct UserSlice<const READ: bool, const WRITE: bool> {
@@ -16,10 +18,7 @@ pub type UserSliceRw = UserSlice<true, true>;
impl<const READ: bool, const WRITE: bool> UserSlice<READ, WRITE> {
pub fn empty() -> Self {
Self {
base: 0,
len: 0,
}
Self { base: 0, len: 0 }
}
pub fn len(&self) -> usize {
self.len
@@ -42,7 +41,16 @@ impl<const READ: bool, const WRITE: bool> UserSlice<READ, WRITE> {
if idx > self.len {
return None;
}
Some((Self { base: self.base, len: idx }, Self { base: self.base + idx, len: self.len - idx }))
Some((
Self {
base: self.base,
len: idx,
},
Self {
base: self.base + idx,
len: self.len - idx,
},
))
}
pub fn advance(self, by: usize) -> Option<Self> {
Some(self.split_at(by)?.1)
@@ -51,25 +59,35 @@ impl<const READ: bool, const WRITE: bool> UserSlice<READ, WRITE> {
Some(self.split_at(to)?.0)
}
pub fn none_if_null(self) -> Option<Self> {
if self.addr() == 0 { None } else { Some(self) }
if self.addr() == 0 {
None
} else {
Some(self)
}
}
/// Not unsafe, because user memory is not covered by the memory model that decides if
/// something is UB, but it can break logic invariants
pub fn reinterpret_unchecked<const NEW_READ: bool, const NEW_WRITE: bool>(self) -> UserSlice<NEW_READ, NEW_WRITE> {
pub fn reinterpret_unchecked<const NEW_READ: bool, const NEW_WRITE: bool>(
self,
) -> UserSlice<NEW_READ, NEW_WRITE> {
UserSlice {
base: self.base,
len: self.len,
}
}
pub fn in_variable_chunks(self, chunk_size: usize) -> impl Iterator<Item = Self> {
(0..self.len()).step_by(chunk_size).map(move |i| self.advance(i).expect("already limited by length, must succeed"))
(0..self.len()).step_by(chunk_size).map(move |i| {
self.advance(i)
.expect("already limited by length, must succeed")
})
}
pub fn in_exact_chunks(self, chunk_size: usize) -> impl Iterator<Item = Self> {
(0..self.len().div_floor(chunk_size))
.map(move |i| {
self.advance(i * chunk_size).expect("already limited by length, must succeed")
.limit(chunk_size).expect("length is aligned")
})
(0..self.len().div_floor(chunk_size)).map(move |i| {
self.advance(i * chunk_size)
.expect("already limited by length, must succeed")
.limit(chunk_size)
.expect("length is aligned")
})
}
}
impl<const WRITE: bool> UserSlice<true, WRITE> {
@@ -88,35 +106,51 @@ impl<const WRITE: bool> UserSlice<true, WRITE> {
}
pub unsafe fn read_exact<T>(self) -> Result<T> {
let mut t: T = core::mem::zeroed();
let slice = unsafe { core::slice::from_raw_parts_mut((&mut t as *mut T).cast::<u8>(), core::mem::size_of::<T>()) };
let slice = unsafe {
core::slice::from_raw_parts_mut(
(&mut t as *mut T).cast::<u8>(),
core::mem::size_of::<T>(),
)
};
self.limit(core::mem::size_of::<T>()).ok_or(Error::new(EINVAL))?.copy_to_slice(slice)?;
self.limit(core::mem::size_of::<T>())
.ok_or(Error::new(EINVAL))?
.copy_to_slice(slice)?;
Ok(t)
}
pub fn copy_common_bytes_to_slice(self, slice: &mut [u8]) -> Result<usize> {
let min = core::cmp::min(self.len(), slice.len());
self.limit(min).expect("min(len, x) is always <= len").copy_to_slice(&mut slice[..min])?;
self.limit(min)
.expect("min(len, x) is always <= len")
.copy_to_slice(&mut slice[..min])?;
Ok(min)
}
// TODO: Merge int IO functions?
pub fn read_usize(self) -> Result<usize> {
let mut ret = 0_usize.to_ne_bytes();
self.limit(core::mem::size_of::<usize>()).ok_or(Error::new(EINVAL))?.copy_to_slice(&mut ret)?;
self.limit(core::mem::size_of::<usize>())
.ok_or(Error::new(EINVAL))?
.copy_to_slice(&mut ret)?;
Ok(usize::from_ne_bytes(ret))
}
pub fn read_u32(self) -> Result<u32> {
let mut ret = 0_u32.to_ne_bytes();
self.limit(4).ok_or(Error::new(EINVAL))?.copy_to_slice(&mut ret)?;
self.limit(4)
.ok_or(Error::new(EINVAL))?
.copy_to_slice(&mut ret)?;
Ok(u32::from_ne_bytes(ret))
}
pub fn read_u64(self) -> Result<u64> {
let mut ret = 0_u64.to_ne_bytes();
self.limit(8).ok_or(Error::new(EINVAL))?.copy_to_slice(&mut ret)?;
self.limit(8)
.ok_or(Error::new(EINVAL))?
.copy_to_slice(&mut ret)?;
Ok(u64::from_ne_bytes(ret))
}
pub fn usizes(self) -> impl Iterator<Item = Result<usize>> {
self.in_exact_chunks(core::mem::size_of::<usize>()).map(Self::read_usize)
self.in_exact_chunks(core::mem::size_of::<usize>())
.map(Self::read_usize)
}
}
impl<const READ: bool> UserSlice<READ, true> {
@@ -135,23 +169,33 @@ impl<const READ: bool> UserSlice<READ, true> {
}
pub fn copy_common_bytes_from_slice(self, slice: &[u8]) -> Result<usize> {
let min = core::cmp::min(self.len(), slice.len());
self.limit(min).expect("min(len, x) is always <= len").copy_from_slice(&slice[..min])?;
self.limit(min)
.expect("min(len, x) is always <= len")
.copy_from_slice(&slice[..min])?;
Ok(min)
}
pub fn copy_exactly(self, slice: &[u8]) -> Result<()> {
self.limit(slice.len()).ok_or(Error::new(EINVAL))?.copy_from_slice(slice)?;
self.limit(slice.len())
.ok_or(Error::new(EINVAL))?
.copy_from_slice(slice)?;
Ok(())
}
pub fn write_usize(self, word: usize) -> Result<()> {
self.limit(core::mem::size_of::<usize>()).ok_or(Error::new(EINVAL))?.copy_from_slice(&word.to_ne_bytes())?;
self.limit(core::mem::size_of::<usize>())
.ok_or(Error::new(EINVAL))?
.copy_from_slice(&word.to_ne_bytes())?;
Ok(())
}
pub fn write_u32(self, int: u32) -> Result<()> {
self.limit(core::mem::size_of::<u32>()).ok_or(Error::new(EINVAL))?.copy_from_slice(&int.to_ne_bytes())?;
self.limit(core::mem::size_of::<u32>())
.ok_or(Error::new(EINVAL))?
.copy_from_slice(&int.to_ne_bytes())?;
Ok(())
}
pub fn write_u64(self, int: u64) -> Result<()> {
self.limit(core::mem::size_of::<u64>()).ok_or(Error::new(EINVAL))?.copy_from_slice(&int.to_ne_bytes())?;
self.limit(core::mem::size_of::<u64>())
.ok_or(Error::new(EINVAL))?
.copy_from_slice(&int.to_ne_bytes())?;
Ok(())
}
}
@@ -173,7 +217,8 @@ impl UserSliceRw {
}
fn is_kernel_mem(slice: &[u8]) -> bool {
(slice.as_ptr() as usize) >= crate::USER_END_OFFSET && (slice.as_ptr() as usize).checked_add(slice.len()).is_some()
(slice.as_ptr() as usize) >= crate::USER_END_OFFSET
&& (slice.as_ptr() as usize).checked_add(slice.len()).is_some()
}
/// Convert `[addr, addr+size)` into `(page, page_count)`.
@@ -192,5 +237,8 @@ pub fn validate_region(address: usize, size: usize) -> Result<(Page, usize)> {
if address.saturating_add(size) > crate::USER_END_OFFSET {
return Err(Error::new(EFAULT));
}
Ok((Page::containing_address(VirtualAddress::new(address)), size / PAGE_SIZE))
Ok((
Page::containing_address(VirtualAddress::new(address)),
size / PAGE_SIZE,
))
}