From 55f2303d2cf45a9e72edb9703ee8fa42621b8147 Mon Sep 17 00:00:00 2001 From: jD91mZM2 <me@krake.one> Date: Thu, 5 Jul 2018 14:17:58 +0200 Subject: [PATCH] Implement fmap for memory: --- src/lib.rs | 1 - src/scheme/memory.rs | 63 ++++++++++++++++++++++++++++++++++++++++--- src/scheme/mod.rs | 2 +- src/syscall/driver.rs | 29 +++++++++++++------- 4 files changed, 80 insertions(+), 15 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index a8e6c59c..77603d92 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -22,7 +22,6 @@ #![feature(const_max_value)] #![feature(const_size_of)] #![feature(core_intrinsics)] -#![feature(global_allocator)] #![feature(integer_atomics)] #![feature(lang_items)] #![feature(naked_functions)] diff --git a/src/scheme/memory.rs b/src/scheme/memory.rs index 6d525c56..32bbcca5 100644 --- a/src/scheme/memory.rs +++ b/src/scheme/memory.rs @@ -1,13 +1,35 @@ +use alloc::{BTreeMap, Vec}; +use core::sync::atomic::{AtomicUsize, Ordering}; use memory::{free_frames, used_frames}; +use spin::Mutex; use syscall::data::StatVfs; use syscall::error::*; use syscall::scheme::Scheme; +use syscall; -pub struct MemoryScheme; +struct Address { + phys: usize, + len: usize, + virt: usize +} +pub struct MemoryScheme { + handles: Mutex<BTreeMap<usize, Vec<Address>>>, + next_id: AtomicUsize +} +impl MemoryScheme { + pub fn new() -> Self { + Self { + handles: Mutex::new(BTreeMap::new()), + next_id: AtomicUsize::new(0) + } + } +} impl Scheme for MemoryScheme { fn open(&self, _path: &[u8], _flags: usize, _uid: u32, _gid: u32) -> Result<usize> { + let id = self.next_id.fetch_add(1, Ordering::SeqCst); + self.handles.lock().insert(id, Vec::new()); Ok(0) } @@ -23,6 +45,26 @@ impl Scheme for MemoryScheme { Ok(0) } + fn fmap(&self, id: usize, _offset: usize, len: usize) -> Result<usize> { + let mut handles = self.handles.lock(); + let handle = handles.get_mut(&id).ok_or(Error::new(ENOENT))?; + + // Warning: These functions are bypassing the root check. + let phys = syscall::inner_physalloc(len)?; + let virt = syscall::inner_physmap(phys, len, syscall::flag::MAP_WRITE).map_err(|err| { + syscall::inner_physfree(phys, len).expect("newly allocated region failed to free"); + err + })?; + + handle.push(Address { + phys, + len, + virt + }); + + Ok(virt) + } + fn fcntl(&self, _id: usize, _cmd: usize, _arg: usize) -> Result<usize> { Ok(0) } @@ -37,8 +79,23 @@ impl Scheme for MemoryScheme { Ok(i) } - /// Close the file `number` - fn close(&self, _file: usize) -> Result<usize> { + fn close(&self, id: usize) -> Result<usize> { + let allocations = self.handles.lock() + .remove(&id) + .ok_or(Error::new(ENOENT))?; + + for addr in allocations { + // physunmap fails if already unmapped + // physfree can't currently fail + // + // What if somebody with root already freed the physical address? + // (But left the mapping, which means we attempt to free it again) + // I'd rather not think about it. + // (Still, that requires root) + let _ = syscall::inner_physunmap(addr.virt) + .and_then(|_| syscall::inner_physfree(addr.phys, addr.len)); + } + Ok(0) } } diff --git a/src/scheme/mod.rs b/src/scheme/mod.rs index d54d655c..fefeb8cb 100644 --- a/src/scheme/mod.rs +++ b/src/scheme/mod.rs @@ -120,7 +120,7 @@ impl SchemeList { self.insert(ns, Box::new(*b""), |scheme_id| Arc::new(Box::new(RootScheme::new(ns, scheme_id)))).unwrap(); self.insert(ns, Box::new(*b"event"), |_| Arc::new(Box::new(EventScheme))).unwrap(); self.insert(ns, Box::new(*b"env"), |_| Arc::new(Box::new(EnvScheme::new()))).unwrap(); - self.insert(ns, Box::new(*b"memory"), |_| Arc::new(Box::new(MemoryScheme))).unwrap(); + self.insert(ns, Box::new(*b"memory"), |_| Arc::new(Box::new(MemoryScheme::new()))).unwrap(); self.insert(ns, Box::new(*b"sys"), |_| Arc::new(Box::new(SysScheme::new()))).unwrap(); self.insert(ns, Box::new(*b"time"), |scheme_id| Arc::new(Box::new(TimeScheme::new(scheme_id)))).unwrap(); diff --git a/src/syscall/driver.rs b/src/syscall/driver.rs index 5ccfa47c..68c9d252 100644 --- a/src/syscall/driver.rs +++ b/src/syscall/driver.rs @@ -30,24 +30,27 @@ pub fn iopl(level: usize, stack: &mut SyscallStack) -> Result<usize> { Ok(0) } -pub fn physalloc(size: usize) -> Result<usize> { - enforce_root()?; - +pub fn inner_physalloc(size: usize) -> Result<usize> { allocate_frames((size + 4095)/4096).ok_or(Error::new(ENOMEM)).map(|frame| frame.start_address().get()) } - -pub fn physfree(physical_address: usize, size: usize) -> Result<usize> { +pub fn physalloc(size: usize) -> Result<usize> { enforce_root()?; + inner_physalloc(size) +} +pub fn inner_physfree(physical_address: usize, size: usize) -> Result<usize> { deallocate_frames(Frame::containing_address(PhysicalAddress::new(physical_address)), (size + 4095)/4096); + //TODO: Check that no double free occured Ok(0) } - -//TODO: verify exlusive access to physical memory -pub fn physmap(physical_address: usize, size: usize, flags: usize) -> Result<usize> { +pub fn physfree(physical_address: usize, size: usize) -> Result<usize> { enforce_root()?; + inner_physfree(physical_address, size) +} +//TODO: verify exlusive access to physical memory +pub fn inner_physmap(physical_address: usize, size: usize, flags: usize) -> Result<usize> { if size == 0 { Ok(0) } else { @@ -98,10 +101,12 @@ pub fn physmap(physical_address: usize, size: usize, flags: usize) -> Result<usi Ok(to_address + offset) } } - -pub fn physunmap(virtual_address: usize) -> Result<usize> { +pub fn physmap(physical_address: usize, size: usize, flags: usize) -> Result<usize> { enforce_root()?; + inner_physmap(physical_address, size, flags) +} +pub fn inner_physunmap(virtual_address: usize) -> Result<usize> { if virtual_address == 0 { Ok(0) } else { @@ -124,6 +129,10 @@ pub fn physunmap(virtual_address: usize) -> Result<usize> { Err(Error::new(EFAULT)) } } +pub fn physunmap(virtual_address: usize) -> Result<usize> { + enforce_root()?; + inner_physunmap(virtual_address) +} pub fn virttophys(virtual_address: usize) -> Result<usize> { enforce_root()?; -- GitLab