Merge branch 'better_fmap' into 'master'

Demand paging

See merge request redox-os/syscall!77
This commit is contained in:
Jeremy Soller
2023-08-02 13:07:36 +00:00
7 changed files with 152 additions and 153 deletions
+41
View File
@@ -313,3 +313,44 @@ macro_rules! ptrace_event {
}
}
}
bitflags::bitflags! {
#[derive(Default)]
pub struct GrantFlags: usize {
const GRANT_READ = 0x0000_0001;
const GRANT_WRITE = 0x0000_0002;
const GRANT_EXEC = 0x0000_0004;
const GRANT_SHARED = 0x0000_0008;
const GRANT_LAZY = 0x0000_0010;
const GRANT_SCHEME = 0x0000_0020;
const GRANT_PHYS = 0x0000_0040;
const GRANT_PINNED = 0x0000_0080;
}
}
#[derive(Clone, Copy, Debug, Default)]
#[repr(C)]
pub struct GrantDesc {
pub base: usize,
pub size: usize,
pub flags: GrantFlags,
pub offset: u64,
}
impl Deref for GrantDesc {
type Target = [u8];
fn deref(&self) -> &[u8] {
unsafe {
slice::from_raw_parts(self as *const GrantDesc as *const u8, mem::size_of::<GrantDesc>())
}
}
}
impl DerefMut for GrantDesc {
fn deref_mut(&mut self) -> &mut [u8] {
unsafe {
slice::from_raw_parts_mut(self as *mut GrantDesc as *mut u8, mem::size_of::<GrantDesc>())
}
}
}
+37 -1
View File
@@ -54,11 +54,18 @@ pub const FUTEX_WAKE: usize = 1;
pub const FUTEX_REQUEUE: usize = 2;
pub const FUTEX_WAIT64: usize = 3;
// packet.c = fd
pub const SKMSG_FRETURNFD: usize = 0;
// packet.uid:packet.gid = offset, packet.c = base address, packet.d = page count
pub const SKMSG_PROVIDE_MMAP: usize = 1;
bitflags! {
pub struct MapFlags: usize {
// TODO: Downgrade PROT_NONE to global constant? (bitflags specifically states zero flags
// can cause buggy behavior).
const PROT_NONE = 0x0000_0000;
const PROT_EXEC = 0x0001_0000;
const PROT_WRITE = 0x0002_0000;
const PROT_READ = 0x0004_0000;
@@ -66,9 +73,30 @@ bitflags! {
const MAP_SHARED = 0x0001;
const MAP_PRIVATE = 0x0002;
/// Only accepted for mmap2(2).
const MAP_FIXED = 0x0004;
const MAP_FIXED_NOREPLACE = 0x000C;
/// For *userspace-backed mmaps*, return from the mmap call before all pages have been
/// provided by the scheme. This requires the scheme to be trusted, as the current context
/// can block indefinitely, if the scheme does not respond to the page fault handler's
/// request, as it tries to map the page by requesting it from the scheme.
///
/// In some cases however, such as the program loader, the data needs to be trusted as much
/// with or without MAP_LAZY, and if so, mapping lazily will not cause insecureness by
/// itself.
///
/// For kernel-backed mmaps, this flag has no effect at all. It is unspecified whether
/// kernel mmaps are lazy or not.
const MAP_LAZY = 0x0010;
}
}
bitflags! {
pub struct MunmapFlags: usize {
/// Indicates whether the funmap call must implicitly do an msync, for the changes to
/// become visible later.
///
/// This flag will currently be set if and only if MAP_SHARED | PROT_WRITE are set.
const NEEDS_SYNC = 1;
}
}
@@ -336,3 +364,11 @@ pub fn wexitstatus(status: usize) -> usize {
pub fn wcoredump(status: usize) -> bool {
(status & 0x80) != 0
}
bitflags! {
pub struct MremapFlags: usize {
const FIXED = 1;
const FIXED_REPLACE = 3;
// TODO: MAYMOVE, DONTUNMAP
}
}
+18
View File
@@ -25,10 +25,16 @@ pub const SYS_FCHMOD: usize = SYS_CLASS_FILE | 94;
pub const SYS_FCHOWN: usize = SYS_CLASS_FILE | 207;
pub const SYS_FCNTL: usize = SYS_CLASS_FILE | 55;
pub const SYS_FEVENT: usize = SYS_CLASS_FILE | 927;
// TODO: Rename FMAP/FUNMAP to MMAP/MUNMAP
pub const SYS_FMAP_OLD: usize = SYS_CLASS_FILE | SYS_ARG_SLICE | 90;
pub const SYS_FMAP: usize = SYS_CLASS_FILE | SYS_ARG_SLICE | 900;
// TODO: SYS_FUNMAP should be SYS_CLASS_FILE
// TODO: Remove FMAP/FMAP_OLD
pub const SYS_FUNMAP_OLD: usize = SYS_CLASS_FILE | 91;
pub const SYS_FUNMAP: usize = SYS_CLASS_FILE | 92;
pub const SYS_MREMAP: usize = 155;
pub const SYS_FPATH: usize = SYS_CLASS_FILE | SYS_ARG_MSLICE | 928;
pub const SYS_FRENAME: usize = SYS_CLASS_FILE | SYS_ARG_PATH | 38;
pub const SYS_FSTAT: usize = SYS_CLASS_FILE | SYS_ARG_MSLICE | 28;
@@ -37,6 +43,18 @@ pub const SYS_FSYNC: usize = SYS_CLASS_FILE | 118;
pub const SYS_FTRUNCATE: usize = SYS_CLASS_FILE | 93;
pub const SYS_FUTIMENS: usize = SYS_CLASS_FILE | SYS_ARG_SLICE | 320;
// b = file, c = flags, d = required_page_count, uid:gid = offset
pub const KSMSG_MMAP: usize = SYS_CLASS_FILE | 72;
// b = file, c = flags, d = page_count, uid:gid = offset
pub const KSMSG_MSYNC: usize = SYS_CLASS_FILE | 73;
// b = file, c = page_count, uid:gid = offset
pub const KSMSG_MUNMAP: usize = SYS_CLASS_FILE | 74;
// b = file, c = flags, d = page_count, uid:gid = offset
pub const KSMSG_MMAP_PREP: usize = SYS_CLASS_FILE | 75;
pub const SYS_CLOCK_GETTIME: usize = 265;
pub const SYS_EXIT: usize = 1;
pub const SYS_FUTEX: usize = 240;
+14 -38
View File
@@ -36,18 +36,6 @@ pub trait Scheme {
SYS_FCHOWN => self.fchown(packet.b, packet.c as u32, packet.d as u32),
SYS_FCNTL => self.fcntl(packet.b, packet.c, packet.d),
SYS_FEVENT => self.fevent(packet.b, EventFlags::from_bits_truncate(packet.c)).map(|f| f.bits()),
SYS_FMAP_OLD => if packet.d >= mem::size_of::<OldMap>() {
self.fmap_old(packet.b, unsafe { &*(packet.c as *const OldMap) })
} else {
Err(Error::new(EFAULT))
},
SYS_FMAP => if packet.d >= mem::size_of::<Map>() {
self.fmap(packet.b, unsafe { &*(packet.c as *const Map) })
} else {
Err(Error::new(EFAULT))
},
SYS_FUNMAP_OLD => self.funmap_old(packet.b),
SYS_FUNMAP => self.funmap(packet.b, packet.c),
SYS_FPATH => self.fpath(packet.b, unsafe { slice::from_raw_parts_mut(packet.c as *mut u8, packet.d) }),
SYS_FRENAME => if let Some(path) = unsafe { str_from_raw_parts(packet.c as *const u8, packet.d) } {
self.frename(packet.b, path, packet.uid, packet.gid)
@@ -72,6 +60,10 @@ pub trait Scheme {
Err(Error::new(EFAULT))
},
SYS_CLOSE => self.close(packet.b),
KSMSG_MMAP_PREP => self.mmap_prep(packet.b, u64::from(packet.uid) | (u64::from(packet.gid) << 32), packet.c, MapFlags::from_bits_truncate(packet.d)),
KSMSG_MUNMAP => self.munmap(packet.b, u64::from(packet.uid) | (u64::from(packet.gid) << 32), packet.c, MunmapFlags::from_bits_truncate(packet.d)),
_ => Err(Error::new(ENOSYS))
};
@@ -150,32 +142,6 @@ pub trait Scheme {
Err(Error::new(EBADF))
}
#[allow(unused_variables)]
fn fmap_old(&self, id: usize, map: &OldMap) -> Result<usize> {
Err(Error::new(EBADF))
}
#[allow(unused_variables)]
fn fmap(&self, id: usize, map: &Map) -> Result<usize> {
if map.flags.contains(MapFlags::MAP_FIXED) {
return Err(Error::new(EINVAL));
}
self.fmap_old(id, &OldMap {
offset: map.offset,
size: map.size,
flags: map.flags,
})
}
#[allow(unused_variables)]
fn funmap_old(&self, address: usize) -> Result<usize> {
Ok(0)
}
#[allow(unused_variables)]
fn funmap(&self, address: usize, length: usize) -> Result<usize> {
Ok(0)
}
#[allow(unused_variables)]
fn fpath(&self, id: usize, buf: &mut [u8]) -> Result<usize> {
Err(Error::new(EBADF))
@@ -215,4 +181,14 @@ pub trait Scheme {
fn close(&self, id: usize) -> Result<usize> {
Err(Error::new(EBADF))
}
#[allow(unused_variables)]
fn mmap_prep(&self, id: usize, offset: u64, size: usize, flags: MapFlags) -> Result<usize> {
Err(Error::new(EOPNOTSUPP))
}
#[allow(unused_variables)]
fn munmap(&self, id: usize, offset: u64, size: usize, flags: MunmapFlags) -> Result<usize> {
Err(Error::new(EOPNOTSUPP))
}
}
+14 -38
View File
@@ -36,18 +36,6 @@ pub trait SchemeBlock {
SYS_FCHOWN => self.fchown(packet.b, packet.c as u32, packet.d as u32),
SYS_FCNTL => self.fcntl(packet.b, packet.c, packet.d),
SYS_FEVENT => self.fevent(packet.b, EventFlags::from_bits_truncate(packet.c)).map(|f| f.map(|f| f.bits())),
SYS_FMAP_OLD => if packet.d >= mem::size_of::<OldMap>() {
self.fmap_old(packet.b, unsafe { &*(packet.c as *const OldMap) })
} else {
Err(Error::new(EFAULT))
},
SYS_FMAP => if packet.d >= mem::size_of::<Map>() {
self.fmap(packet.b, unsafe { &*(packet.c as *const Map) })
} else {
Err(Error::new(EFAULT))
},
SYS_FUNMAP_OLD => self.funmap_old(packet.b),
SYS_FUNMAP => self.funmap(packet.b, packet.c),
SYS_FPATH => self.fpath(packet.b, unsafe { slice::from_raw_parts_mut(packet.c as *mut u8, packet.d) }),
SYS_FRENAME => if let Some(path) = unsafe { str_from_raw_parts(packet.c as *const u8, packet.d) } {
self.frename(packet.b, path, packet.uid, packet.gid)
@@ -72,6 +60,10 @@ pub trait SchemeBlock {
Err(Error::new(EFAULT))
},
SYS_CLOSE => self.close(packet.b),
KSMSG_MMAP_PREP => self.mmap_prep(packet.b, u64::from(packet.uid) | (u64::from(packet.gid) << 32), packet.c, MapFlags::from_bits_truncate(packet.d)),
KSMSG_MUNMAP => self.munmap(packet.b, u64::from(packet.uid) | (u64::from(packet.gid) << 32), packet.c, MunmapFlags::from_bits_truncate(packet.d)),
_ => Err(Error::new(ENOSYS))
};
@@ -150,32 +142,6 @@ pub trait SchemeBlock {
Err(Error::new(EBADF))
}
#[allow(unused_variables)]
fn fmap_old(&self, id: usize, map: &OldMap) -> Result<Option<usize>> {
Err(Error::new(EBADF))
}
#[allow(unused_variables)]
fn fmap(&self, id: usize, map: &Map) -> Result<Option<usize>> {
if map.flags.contains(MapFlags::MAP_FIXED) {
return Err(Error::new(EINVAL));
}
self.fmap_old(id, &OldMap {
offset: map.offset,
size: map.size,
flags: map.flags,
})
}
#[allow(unused_variables)]
fn funmap_old(&self, address: usize) -> Result<Option<usize>> {
Ok(Some(0))
}
#[allow(unused_variables)]
fn funmap(&self, address: usize, length: usize) -> Result<Option<usize>> {
Ok(Some(0))
}
#[allow(unused_variables)]
fn fpath(&self, id: usize, buf: &mut [u8]) -> Result<Option<usize>> {
Err(Error::new(EBADF))
@@ -215,4 +181,14 @@ pub trait SchemeBlock {
fn close(&self, id: usize) -> Result<Option<usize>> {
Err(Error::new(EBADF))
}
#[allow(unused_variables)]
fn mmap_prep(&self, id: usize, offset: u64, size: usize, flags: MapFlags) -> Result<Option<usize>> {
Err(Error::new(EOPNOTSUPP))
}
#[allow(unused_variables)]
fn munmap(&self, id: usize, offset: u64, size: usize, flags: MunmapFlags) -> Result<Option<usize>> {
Err(Error::new(EOPNOTSUPP))
}
}
+14 -38
View File
@@ -36,18 +36,6 @@ pub trait SchemeBlockMut {
SYS_FCHOWN => self.fchown(packet.b, packet.c as u32, packet.d as u32),
SYS_FCNTL => self.fcntl(packet.b, packet.c, packet.d),
SYS_FEVENT => self.fevent(packet.b, EventFlags::from_bits_truncate(packet.c)).map(|f| f.map(|f| f.bits())),
SYS_FMAP_OLD => if packet.d >= mem::size_of::<OldMap>() {
self.fmap_old(packet.b, unsafe { &*(packet.c as *const OldMap) })
} else {
Err(Error::new(EFAULT))
},
SYS_FMAP => if packet.d >= mem::size_of::<Map>() {
self.fmap(packet.b, unsafe { &*(packet.c as *const Map) })
} else {
Err(Error::new(EFAULT))
},
SYS_FUNMAP_OLD => self.funmap_old(packet.b),
SYS_FUNMAP => self.funmap(packet.b, packet.c),
SYS_FPATH => self.fpath(packet.b, unsafe { slice::from_raw_parts_mut(packet.c as *mut u8, packet.d) }),
SYS_FRENAME => if let Some(path) = unsafe { str_from_raw_parts(packet.c as *const u8, packet.d) } {
self.frename(packet.b, path, packet.uid, packet.gid)
@@ -72,6 +60,10 @@ pub trait SchemeBlockMut {
Err(Error::new(EFAULT))
},
SYS_CLOSE => self.close(packet.b),
KSMSG_MMAP_PREP => self.mmap_prep(packet.b, u64::from(packet.uid) | (u64::from(packet.gid) << 32), packet.c, MapFlags::from_bits_truncate(packet.d)),
KSMSG_MUNMAP => self.munmap(packet.b, u64::from(packet.uid) | (u64::from(packet.gid) << 32), packet.c, MunmapFlags::from_bits_truncate(packet.d)),
_ => Err(Error::new(ENOSYS))
};
@@ -150,32 +142,6 @@ pub trait SchemeBlockMut {
Err(Error::new(EBADF))
}
#[allow(unused_variables)]
fn fmap_old(&mut self, id: usize, map: &OldMap) -> Result<Option<usize>> {
Err(Error::new(EBADF))
}
#[allow(unused_variables)]
fn fmap(&mut self, id: usize, map: &Map) -> Result<Option<usize>> {
if map.flags.contains(MapFlags::MAP_FIXED) {
return Err(Error::new(EINVAL));
}
self.fmap_old(id, &OldMap {
offset: map.offset,
size: map.size,
flags: map.flags,
})
}
#[allow(unused_variables)]
fn funmap_old(&mut self, address: usize) -> Result<Option<usize>> {
Ok(Some(0))
}
#[allow(unused_variables)]
fn funmap(&mut self, address: usize, length: usize) -> Result<Option<usize>> {
Ok(Some(0))
}
#[allow(unused_variables)]
fn fpath(&mut self, id: usize, buf: &mut [u8]) -> Result<Option<usize>> {
Err(Error::new(EBADF))
@@ -215,4 +181,14 @@ pub trait SchemeBlockMut {
fn close(&mut self, id: usize) -> Result<Option<usize>> {
Err(Error::new(EBADF))
}
#[allow(unused_variables)]
fn mmap_prep(&mut self, id: usize, offset: u64, size: usize, flags: MapFlags) -> Result<Option<usize>> {
Err(Error::new(EOPNOTSUPP))
}
#[allow(unused_variables)]
fn munmap(&mut self, id: usize, offset: u64, size: usize, flags: MunmapFlags) -> Result<Option<usize>> {
Err(Error::new(EOPNOTSUPP))
}
}
+14 -38
View File
@@ -36,18 +36,6 @@ pub trait SchemeMut {
SYS_FCHOWN => self.fchown(packet.b, packet.c as u32, packet.d as u32),
SYS_FCNTL => self.fcntl(packet.b, packet.c, packet.d),
SYS_FEVENT => self.fevent(packet.b, EventFlags::from_bits_truncate(packet.c)).map(|f| f.bits()),
SYS_FMAP_OLD => if packet.d >= mem::size_of::<OldMap>() {
self.fmap_old(packet.b, unsafe { &*(packet.c as *const OldMap) })
} else {
Err(Error::new(EFAULT))
},
SYS_FMAP => if packet.d >= mem::size_of::<Map>() {
self.fmap(packet.b, unsafe { &*(packet.c as *const Map) })
} else {
Err(Error::new(EFAULT))
},
SYS_FUNMAP_OLD => self.funmap_old(packet.b),
SYS_FUNMAP => self.funmap(packet.b, packet.c),
SYS_FPATH => self.fpath(packet.b, unsafe { slice::from_raw_parts_mut(packet.c as *mut u8, packet.d) }),
SYS_FRENAME => if let Some(path) = unsafe { str_from_raw_parts(packet.c as *const u8, packet.d) } {
self.frename(packet.b, path, packet.uid, packet.gid)
@@ -72,6 +60,10 @@ pub trait SchemeMut {
Err(Error::new(EFAULT))
},
SYS_CLOSE => self.close(packet.b),
KSMSG_MMAP_PREP => self.mmap_prep(packet.b, u64::from(packet.uid) | (u64::from(packet.gid) << 32), packet.c, MapFlags::from_bits_truncate(packet.d)),
KSMSG_MUNMAP => self.munmap(packet.b, u64::from(packet.uid) | (u64::from(packet.gid) << 32), packet.c, MunmapFlags::from_bits_truncate(packet.d)),
_ => Err(Error::new(ENOSYS))
};
@@ -150,32 +142,6 @@ pub trait SchemeMut {
Err(Error::new(EBADF))
}
#[allow(unused_variables)]
fn fmap_old(&mut self, id: usize, map: &OldMap) -> Result<usize> {
Err(Error::new(EBADF))
}
#[allow(unused_variables)]
fn fmap(&mut self, id: usize, map: &Map) -> Result<usize> {
if map.flags.contains(MapFlags::MAP_FIXED) {
return Err(Error::new(EINVAL));
}
self.fmap_old(id, &OldMap {
offset: map.offset,
size: map.size,
flags: map.flags,
})
}
#[allow(unused_variables)]
fn funmap_old(&mut self, address: usize) -> Result<usize> {
Ok(0)
}
#[allow(unused_variables)]
fn funmap(&mut self, address: usize, length: usize) -> Result<usize> {
Ok(0)
}
#[allow(unused_variables)]
fn fpath(&mut self, id: usize, buf: &mut [u8]) -> Result<usize> {
Err(Error::new(EBADF))
@@ -215,4 +181,14 @@ pub trait SchemeMut {
fn close(&mut self, id: usize) -> Result<usize> {
Err(Error::new(EBADF))
}
#[allow(unused_variables)]
fn mmap_prep(&mut self, id: usize, offset: u64, size: usize, flags: MapFlags) -> Result<usize> {
Err(Error::new(EOPNOTSUPP))
}
#[allow(unused_variables)]
fn munmap(&mut self, id: usize, offset: u64, size: usize, flags: MunmapFlags) -> Result<usize> {
Err(Error::new(EOPNOTSUPP))
}
}