From 86073670586d161f3d749b6a3d66a9ab0ac0d6f3 Mon Sep 17 00:00:00 2001
From: Jeremy Soller <jackpot51@gmail.com>
Date: Wed, 14 Sep 2016 22:21:52 -0600
Subject: [PATCH] WIP: Create new page table for clone

---
 context/memory.rs  | 37 ++++++++++++++++++-------------------
 syscall/process.rs | 31 ++++++++++++++++++++++++++-----
 2 files changed, 44 insertions(+), 24 deletions(-)

diff --git a/context/memory.rs b/context/memory.rs
index ab9033bc..e0eaa5fc 100644
--- a/context/memory.rs
+++ b/context/memory.rs
@@ -1,6 +1,7 @@
 use arch::externs::memset;
-use arch::paging::{ActivePageTable, Page, PageIter, VirtualAddress};
+use arch::paging::{ActivePageTable, InactivePageTable, Page, PageIter, VirtualAddress};
 use arch::paging::entry::EntryFlags;
+use arch::paging::temporary_page::TemporaryPage;
 
 #[derive(Debug)]
 pub struct Memory {
@@ -36,7 +37,7 @@ impl Memory {
         Page::range_inclusive(start_page, end_page)
     }
 
-    pub fn map(&mut self, flush: bool, clear: bool) {
+    fn map(&mut self, flush: bool, clear: bool) {
         let mut active_table = unsafe { ActivePageTable::new() };
 
         let mut flush_all = false;
@@ -61,7 +62,7 @@ impl Memory {
         }
     }
 
-    pub fn unmap(&mut self, flush: bool) {
+    fn unmap(&mut self, flush: bool) {
         let mut active_table = unsafe { ActivePageTable::new() };
 
         let mut flush_all = false;
@@ -80,13 +81,20 @@ impl Memory {
         }
     }
 
-    pub fn remap(&mut self, new_flags: EntryFlags, flush: bool) {
+    /// A complicated operation to move a piece of memory to a new page table
+    /// It also allows for changing the address at the same time
+    pub fn move_to(&mut self, new_start: VirtualAddress, new_table: &mut InactivePageTable, temporary_page: &mut TemporaryPage, flush: bool) {
         let mut active_table = unsafe { ActivePageTable::new() };
 
         let mut flush_all = false;
 
         for page in self.pages() {
-            active_table.remap(page, new_flags);
+            let frame = active_table.unmap_return(page);
+
+            active_table.with(new_table, temporary_page, |mapper| {
+                let new_page = Page::containing_address(VirtualAddress::new(page.start_address().get() - self.start.get() + new_start.get()));
+                mapper.map_to(new_page, frame, self.flags);
+            });
 
             if flush {
                 //active_table.flush(page);
@@ -98,27 +106,16 @@ impl Memory {
             active_table.flush_all();
         }
 
-        self.flags = new_flags;
+        self.start = new_start;
     }
 
-    pub fn replace(&mut self, new_start: VirtualAddress, flush: bool) {
+    pub fn remap(&mut self, new_flags: EntryFlags, flush: bool) {
         let mut active_table = unsafe { ActivePageTable::new() };
 
         let mut flush_all = false;
 
         for page in self.pages() {
-            active_table.unmap(page);
-
-            if flush {
-                //active_table.flush(page);
-                flush_all = true;
-            }
-        }
-
-        self.start = new_start;
-
-        for page in self.pages() {
-            active_table.map(page, self.flags);
+            active_table.remap(page, new_flags);
 
             if flush {
                 //active_table.flush(page);
@@ -129,6 +126,8 @@ impl Memory {
         if flush_all {
             active_table.flush_all();
         }
+
+        self.flags = new_flags;
     }
 
     pub fn resize(&mut self, new_size: usize, flush: bool, clear: bool) {
diff --git a/syscall/process.rs b/syscall/process.rs
index c7ff1ee4..d760d5c5 100644
--- a/syscall/process.rs
+++ b/syscall/process.rs
@@ -4,7 +4,9 @@ use core::mem;
 use core::str;
 
 use arch;
-use arch::paging::{VirtualAddress, entry};
+use arch::memory::allocate_frame;
+use arch::paging::{ActivePageTable, InactivePageTable, Page, VirtualAddress, entry};
+use arch::paging::temporary_page::TemporaryPage;
 use context;
 use elf;
 use syscall::{self, Error, Result};
@@ -67,7 +69,7 @@ pub fn clone(flags: usize, stack_base: usize) -> Result<usize> {
             kstack_option = Some(new_stack);
         }
         if let Some(ref stack) = context.stack {
-            let mut new_stack = context::memory::Memory::new(
+            let new_stack = context::memory::Memory::new(
                 VirtualAddress::new(arch::USER_TMP_STACK_OFFSET),
                 stack.size(),
                 entry::NO_EXECUTE | entry::WRITABLE | entry::USER_ACCESSIBLE,
@@ -79,7 +81,6 @@ pub fn clone(flags: usize, stack_base: usize) -> Result<usize> {
                                       stack.start_address().get() as *const u8,
                                       stack.size());
             }
-            new_stack.unmap(true);
             stack_option = Some(new_stack);
         }
     }
@@ -91,19 +92,39 @@ pub fn clone(flags: usize, stack_base: usize) -> Result<usize> {
         let context_lock = contexts.new_context()?;
         let mut context = context_lock.write();
         context.arch = arch;
+
+        let mut active_table = unsafe { ActivePageTable::new() };
+
+        let mut temporary_page = TemporaryPage::new(Page::containing_address(VirtualAddress::new(0x8_0000_0000)));
+
+        let mut new_table = {
+            let frame = allocate_frame().expect("no more frames in syscall::clone new_table");
+            InactivePageTable::new(frame, &mut active_table, &mut temporary_page)
+        };
+
+        // Copy kernel mapping
+        let kernel_frame = active_table.p4()[510].pointed_frame().expect("kernel table not mapped");
+        active_table.with(&mut new_table, &mut temporary_page, |mapper| {
+            mapper.p4_mut()[510].set(kernel_frame, entry::PRESENT | entry::WRITABLE);
+        });
+
         if let Some(stack) = kstack_option.take() {
             context.arch.set_stack(stack.as_ptr() as usize + offset);
             context.kstack = Some(stack);
         }
+
         if let Some(mut stack) = stack_option.take() {
-            //stack.replace(VirtualAddress::new(arch::USER_STACK_OFFSET), true);
+            stack.move_to(VirtualAddress::new(arch::USER_STACK_OFFSET), &mut new_table, &mut temporary_page, true);
             context.stack = Some(stack);
         }
+
+        context.arch.set_page_table(unsafe { new_table.address() });
+
         context.blocked = false;
         pid = context.id;
     }
 
-    //unsafe { context::switch(); }
+    unsafe { context::switch(); }
 
     Ok(pid)
 }
-- 
GitLab