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