Brandon Potter has uploaded this change for review. ( https://gem5-review.googlesource.com/c/public/gem5/+/12306

Change subject: syscall_emul: move members of Process to MemState
......................................................................

syscall_emul: move members of Process to MemState

This changeset moves memory-related functionality from the
Process class to the MemState class. The goal is to create
an object to manage the memory for Syscall Emulation Mode;
ideally, that object has as much cohesion as possible.

Change-Id: I5e6afecbd47e9c46998c4d6a1091d1f4fb698a71
---
M src/arch/alpha/faults.cc
M src/arch/alpha/process.cc
M src/arch/alpha/process.hh
M src/arch/arm/linux/process.cc
M src/arch/arm/process.cc
M src/arch/arm/remote_gdb.cc
M src/arch/arm/tlb.cc
M src/arch/generic/tlb.cc
M src/arch/mips/process.cc
M src/arch/mips/remote_gdb.cc
M src/arch/mips/tlb.cc
M src/arch/power/process.cc
M src/arch/power/remote_gdb.cc
M src/arch/power/tlb.cc
M src/arch/riscv/process.cc
M src/arch/riscv/process.hh
M src/arch/riscv/remote_gdb.cc
M src/arch/riscv/tlb.cc
M src/arch/sparc/faults.cc
M src/arch/sparc/process.cc
M src/arch/sparc/process.hh
M src/arch/sparc/remote_gdb.cc
M src/arch/x86/process.cc
M src/arch/x86/process.hh
M src/arch/x86/remote_gdb.cc
M src/arch/x86/tlb.cc
M src/cpu/thread_context.hh
M src/gpu-compute/compute_unit.cc
M src/gpu-compute/gpu_tlb.cc
M src/gpu-compute/shader.cc
M src/mem/se_translating_port_proxy.cc
M src/mem/se_translating_port_proxy.hh
M src/sim/SConscript
M src/sim/faults.cc
A src/sim/mem_state.cc
M src/sim/mem_state.hh
R src/sim/mem_state_impl.hh
M src/sim/process.cc
M src/sim/process.hh
M src/sim/syscall_emul.hh
40 files changed, 893 insertions(+), 386 deletions(-)



diff --git a/src/arch/alpha/faults.cc b/src/arch/alpha/faults.cc
index 3433844..38c886f 100644
--- a/src/arch/alpha/faults.cc
+++ b/src/arch/alpha/faults.cc
@@ -196,11 +196,12 @@
     }

     Process *p = tc->getProcessPtr();
-    const EmulationPageTable::Entry *pte = p->pTable->lookup(pc);
+    auto mem_state = p->memState;
+    const EmulationPageTable::Entry *pte = mem_state->_pTable->lookup(pc);
     panic_if(!pte, "Tried to execute unmapped address %#x.\n", pc);

     VAddr vaddr(pc);
-    TlbEntry entry(p->pTable->pid(), vaddr.page(), pte->paddr,
+    TlbEntry entry(mem_state->_pTable->pid(), vaddr.page(), pte->paddr,
                    pte->flags & EmulationPageTable::Uncacheable,
                    pte->flags & EmulationPageTable::ReadOnly);
     dynamic_cast<TLB *>(tc->getITBPtr())->insert(vaddr.page(), entry);
@@ -215,11 +216,10 @@
     }

     Process *p = tc->getProcessPtr();
-    const EmulationPageTable::Entry *pte = p->pTable->lookup(vaddr);
-    if (!pte && p->fixupStackFault(vaddr))
-        pte = p->pTable->lookup(vaddr);
+    auto mem_state = p->memState;
+    const EmulationPageTable::Entry *pte = mem_state->lookup(vaddr);
     panic_if(!pte, "Tried to access unmapped address %#x.\n", (Addr)vaddr);
-    TlbEntry entry(p->pTable->pid(), vaddr.page(), pte->paddr,
+    TlbEntry entry(mem_state->_pTable->pid(), vaddr.page(), pte->paddr,
                    pte->flags & EmulationPageTable::Uncacheable,
                    pte->flags & EmulationPageTable::ReadOnly);
     dynamic_cast<TLB *>(tc->getDTBPtr())->insert(vaddr.page(), entry);
diff --git a/src/arch/alpha/process.cc b/src/arch/alpha/process.cc
index 98931a6..bc7c974 100644
--- a/src/arch/alpha/process.cc
+++ b/src/arch/alpha/process.cc
@@ -41,7 +41,7 @@
 #include "params/Process.hh"
 #include "sim/aux_vector.hh"
 #include "sim/byteswap.hh"
-#include "sim/process_impl.hh"
+#include "sim/mem_state_impl.hh"
 #include "sim/syscall_return.hh"
 #include "sim/system.hh"

@@ -49,11 +49,8 @@
 using namespace std;

 AlphaProcess::AlphaProcess(ProcessParams *params, ObjectFile *objFile)
-    : Process(params,
-              new EmulationPageTable(params->name, params->pid, PageBytes),
-      objFile)
+    : Process(params, objFile)
 {
-    fatal_if(params->useArchPT, "Arch page tables not implemented.");
     Addr brk_point = objFile->dataBase() + objFile->dataSize() +
                      objFile->bssSize();
     brk_point = roundUp(brk_point, PageBytes);
@@ -70,8 +67,11 @@
     // Set pointer for next thread stack.  Reserve 8M for main stack.
     Addr next_thread_stack_base = stack_base - max_stack_size;

-    memState = make_shared<MemState>(brk_point, stack_base, max_stack_size,
-                                     next_thread_stack_base, mmap_end);
+ auto p_table = make_shared<EmulationPageTable>(params->name, params->pid,
+                                                   PageBytes);
+    memState = make_shared<MemState>(this, brk_point, stack_base,
+ max_stack_size, next_thread_stack_base,
+                                     mmap_end, params->system, p_table);
 }

 void
@@ -145,8 +145,9 @@
     memState->setStackMin(roundDown(memState->getStackMin(), pageSize));
memState->setStackSize(memState->getStackBase() - memState->getStackMin());
     // map memory
-    allocateMem(memState->getStackMin(), roundUp(memState->getStackSize(),
-                pageSize));
+    memState->allocateMem(memState->getStackMin(),
+                          roundUp(memState->getStackSize(), pageSize)
+                          -1, 0);

     // map out initial stack contents
Addr argv_array_base = memState->getStackMin() + intSize; // room for argc
diff --git a/src/arch/alpha/process.hh b/src/arch/alpha/process.hh
index 28ecd68..5003fab 100644
--- a/src/arch/alpha/process.hh
+++ b/src/arch/alpha/process.hh
@@ -55,10 +55,6 @@
void setSyscallArg(ThreadContext *tc, int i, AlphaISA::IntReg val) override;
     void setSyscallReturn(ThreadContext *tc,
                           SyscallReturn return_value) override;
-
-    // override default implementation in Process as the mmap
-    // region for Alpha platforms grows upward
-    virtual bool mmapGrowsDown() const override { return false; }
 };

 #endif // __ARCH_ALPHA_PROCESS_HH__
diff --git a/src/arch/arm/linux/process.cc b/src/arch/arm/linux/process.cc
index d271364..abbac72 100644
--- a/src/arch/arm/linux/process.cc
+++ b/src/arch/arm/linux/process.cc
@@ -1674,8 +1674,8 @@
 ArmLinuxProcess32::initState()
 {
     ArmProcess32::initState();
-    allocateMem(commPage, PageBytes);
-    ThreadContext *tc = system->getThreadContext(contextIds[0]);
+
+    memState->allocateMem(commPage, PageBytes);

     uint8_t swiNeg1[] = {
         0xff, 0xff, 0xff, 0xef  // swi -1
diff --git a/src/arch/arm/process.cc b/src/arch/arm/process.cc
index 3a7e46b..4d6f468 100644
--- a/src/arch/arm/process.cc
+++ b/src/arch/arm/process.cc
@@ -54,7 +54,7 @@
 #include "params/Process.hh"
 #include "sim/aux_vector.hh"
 #include "sim/byteswap.hh"
-#include "sim/process_impl.hh"
+#include "sim/mem_state_impl.hh"
 #include "sim/syscall_return.hh"
 #include "sim/system.hh"

@@ -63,12 +63,9 @@

 ArmProcess::ArmProcess(ProcessParams *params, ObjectFile *objFile,
                        ObjectFile::Arch _arch)
-    : Process(params,
-              new EmulationPageTable(params->name, params->pid, PageBytes),
-              objFile),
+    : Process(params, objFile),
       arch(_arch)
 {
-    fatal_if(params->useArchPT, "Arch page tables not implemented.");
 }

 ArmProcess32::ArmProcess32(ProcessParams *params, ObjectFile *objFile,
@@ -82,8 +79,11 @@
     Addr next_thread_stack_base = stack_base - max_stack_size;
     Addr mmap_end = 0x40000000L;

-    memState = make_shared<MemState>(brk_point, stack_base, max_stack_size,
-                                     next_thread_stack_base, mmap_end);
+ auto p_table = make_shared<EmulationPageTable>(params->name, params->pid,
+                                                   PageBytes);
+    memState = make_shared<MemState>(this, brk_point, stack_base,
+ max_stack_size, next_thread_stack_base,
+                                     mmap_end, params->system, p_table);
 }

 ArmProcess64::ArmProcess64(ProcessParams *params, ObjectFile *objFile,
@@ -97,8 +97,11 @@
     Addr next_thread_stack_base = stack_base - max_stack_size;
     Addr mmap_end = 0x4000000000L;

-    memState = make_shared<MemState>(brk_point, stack_base, max_stack_size,
-                                     next_thread_stack_base, mmap_end);
+ auto p_table = make_shared<EmulationPageTable>(params->name, params->pid,
+                                                   PageBytes);
+    memState = make_shared<MemState>(this, brk_point, stack_base,
+ max_stack_size, next_thread_stack_base,
+                                     mmap_end, params->system, p_table);
 }

 void
@@ -293,7 +296,7 @@
memState->setStackSize(memState->getStackBase() - memState->getStackMin());

     // map memory
-    allocateMem(roundDown(memState->getStackMin(), pageSize),
+    memState->allocateMem(roundDown(memState->getStackMin(), pageSize),
                           roundUp(memState->getStackSize(), pageSize));

     // map out initial stack contents
diff --git a/src/arch/arm/remote_gdb.cc b/src/arch/arm/remote_gdb.cc
index f191937..5ade136 100644
--- a/src/arch/arm/remote_gdb.cc
+++ b/src/arch/arm/remote_gdb.cc
@@ -186,9 +186,11 @@
         DPRINTF(GDBAcc, "acc:   %#x mapping is valid\n", va);
         return true;
     } else {
-        // Check to make sure the first byte is mapped into the processes
-        // address space.
-        return context()->getProcessPtr()->pTable->lookup(va) != nullptr;
+ // Check if the virtual address is valid and map a physical page if it
+        // hasn't been already
+        auto process = context()->getProcessPtr();
+        auto mem_state = process->memState;
+        return mem_state->translate(va);
     }
 }

diff --git a/src/arch/arm/tlb.cc b/src/arch/arm/tlb.cc
index 79eef1b..26b482d 100644
--- a/src/arch/arm/tlb.cc
+++ b/src/arch/arm/tlb.cc
@@ -593,8 +593,9 @@

     Addr paddr;
     Process *p = tc->getProcessPtr();
+    auto mem_state = p->memState;

-    if (!p->pTable->translate(vaddr, paddr))
+    if (!mem_state->_pTable->translate(vaddr, paddr))
         return std::make_shared<GenericPageTableFault>(vaddr_tainted);
     req->setPaddr(paddr);

diff --git a/src/arch/generic/tlb.cc b/src/arch/generic/tlb.cc
index aebdd4b..a5dd858 100644
--- a/src/arch/generic/tlb.cc
+++ b/src/arch/generic/tlb.cc
@@ -42,9 +42,11 @@
     if (FullSystem)
panic("Generic translation shouldn't be used in full system mode.\n");

-    Process * p = tc->getProcessPtr();
+    auto p = tc->getProcessPtr();
+    auto mem_state = p->memState;
+    auto p_table = mem_state->_pTable;

-    Fault fault = p->pTable->translate(req);
+    Fault fault = p_table->translate(req);
     if (fault != NoFault)
         return fault;

diff --git a/src/arch/mips/process.cc b/src/arch/mips/process.cc
index 32c58ae..37831a4 100644
--- a/src/arch/mips/process.cc
+++ b/src/arch/mips/process.cc
@@ -41,8 +41,8 @@
 #include "mem/page_table.hh"
 #include "params/Process.hh"
 #include "sim/aux_vector.hh"
+#include "sim/mem_state_impl.hh"
 #include "sim/process.hh"
-#include "sim/process_impl.hh"
 #include "sim/syscall_return.hh"
 #include "sim/system.hh"

@@ -50,11 +50,8 @@
 using namespace MipsISA;

 MipsProcess::MipsProcess(ProcessParams *params, ObjectFile *objFile)
-    : Process(params,
-              new EmulationPageTable(params->name, params->pid, PageBytes),
-              objFile)
+    : Process(params, objFile)
 {
-    fatal_if(params->useArchPT, "Arch page tables not implemented.");
     // Set up stack. On MIPS, stack starts at the top of kuseg
     // user address space. MIPS stack grows down from here
     Addr stack_base = 0x7FFFFFFF;
@@ -72,8 +69,11 @@
     // Set up region for mmaps.  Start it 1GB above the top of the heap.
     Addr mmap_end = brk_point + 0x40000000L;

-    memState = make_shared<MemState>(brk_point, stack_base, max_stack_size,
-                                     next_thread_stack_base, mmap_end);
+ auto p_table = make_shared<EmulationPageTable>(params->name, params->pid,
+                                                   PageBytes);
+    memState = make_shared<MemState>(this, brk_point, stack_base,
+ max_stack_size, next_thread_stack_base,
+                                     mmap_end, params->system, p_table);
 }

 void
@@ -157,8 +157,8 @@
     memState->setStackMin(roundDown(memState->getStackMin(), pageSize));
memState->setStackSize(memState->getStackBase() - memState->getStackMin());
     // map memory
-    allocateMem(memState->getStackMin(), roundUp(memState->getStackSize(),
-                pageSize));
+    memState->allocateMem(memState->getStackMin(),
+                          roundUp(memState->getStackSize(), pageSize));

     // map out initial stack contents; leave room for argc
     IntType argv_array_base = memState->getStackMin() + intSize;
diff --git a/src/arch/mips/remote_gdb.cc b/src/arch/mips/remote_gdb.cc
index d490fa5..37c3d66 100644
--- a/src/arch/mips/remote_gdb.cc
+++ b/src/arch/mips/remote_gdb.cc
@@ -162,10 +162,12 @@
 bool
 RemoteGDB::acc(Addr va, size_t len)
 {
- // Check to make sure the first byte is mapped into the processes address
-    // space.
+    // Check if the virtual address is valid and map a physical page if it
+    // hasn't been already
     panic_if(FullSystem, "acc not implemented for MIPS FS!");
-    return context()->getProcessPtr()->pTable->lookup(va) != nullptr;
+    auto process = context()->getProcessPtr();
+    auto mem_state = process->memState;
+    return mem_state->translate(va);
 }

 void
diff --git a/src/arch/mips/tlb.cc b/src/arch/mips/tlb.cc
index 46e250b..34845a5 100644
--- a/src/arch/mips/tlb.cc
+++ b/src/arch/mips/tlb.cc
@@ -288,8 +288,9 @@
         panic("translateInst not implemented in MIPS.\n");

     Process * p = tc->getProcessPtr();
+    auto mem_state = p->memState;

-    Fault fault = p->pTable->translate(req);
+    Fault fault = mem_state->_pTable->translate(req);
     if (fault != NoFault)
         return fault;

@@ -302,9 +303,9 @@
     if (FullSystem)
         panic("translateData not implemented in MIPS.\n");

-    Process * p = tc->getProcessPtr();
-
-    Fault fault = p->pTable->translate(req);
+    auto p = tc->getProcessPtr();
+    auto mem_state = p->memState;
+    Fault fault = mem_state->_pTable->translate(req);
     if (fault != NoFault)
         return fault;

diff --git a/src/arch/power/process.cc b/src/arch/power/process.cc
index d02e20b..d52246a 100644
--- a/src/arch/power/process.cc
+++ b/src/arch/power/process.cc
@@ -42,7 +42,7 @@
 #include "mem/page_table.hh"
 #include "params/Process.hh"
 #include "sim/aux_vector.hh"
-#include "sim/process_impl.hh"
+#include "sim/mem_state_impl.hh"
 #include "sim/syscall_return.hh"
 #include "sim/system.hh"

@@ -50,11 +50,8 @@
 using namespace PowerISA;

 PowerProcess::PowerProcess(ProcessParams *params, ObjectFile *objFile)
-    : Process(params,
-              new EmulationPageTable(params->name, params->pid, PageBytes),
-              objFile)
+    : Process(params, objFile)
 {
-    fatal_if(params->useArchPT, "Arch page tables not implemented.");
     // Set up break point (Top of Heap)
     Addr brk_point = objFile->dataBase() + objFile->dataSize() +
                      objFile->bssSize();
@@ -70,8 +67,11 @@
     // Set up region for mmaps. For now, start at bottom of kuseg space.
     Addr mmap_end = 0x70000000L;

-    memState = make_shared<MemState>(brk_point, stack_base, max_stack_size,
-                                     next_thread_stack_base, mmap_end);
+ auto p_table = make_shared<EmulationPageTable>(params->name, params->pid,
+                                                   PageBytes);
+    memState = make_shared<MemState>(this, brk_point, stack_base,
+ max_stack_size, next_thread_stack_base,
+                                     mmap_end, params->system, p_table);
 }

 void
@@ -203,8 +203,8 @@
     memState->setStackSize(memState->getStackBase() - stack_min);

     // map memory
-    allocateMem(roundDown(stack_min, pageSize),
-                roundUp(memState->getStackSize(), pageSize));
+    memState->allocateMem(roundDown(stack_min, pageSize),
+                          roundUp(memState->getStackSize(), pageSize));

     // map out initial stack contents
     uint32_t sentry_base = memState->getStackBase() - sentry_size;
diff --git a/src/arch/power/remote_gdb.cc b/src/arch/power/remote_gdb.cc
index b4082e0..78babd2 100644
--- a/src/arch/power/remote_gdb.cc
+++ b/src/arch/power/remote_gdb.cc
@@ -168,7 +168,9 @@
// port proxy to read/writeBlob. I (bgs) am not convinced the first byte
     // check is enough.
     panic_if(FullSystem, "acc not implemented for POWER FS!");
-    return context()->getProcessPtr()->pTable->lookup(va) != nullptr;
+    auto process = context()->getProcessPtr();
+    auto mem_state = process->memState;
+    return mem_state->translate(va);
 }

 void
diff --git a/src/arch/power/tlb.cc b/src/arch/power/tlb.cc
index 703b92e..2f39a02 100644
--- a/src/arch/power/tlb.cc
+++ b/src/arch/power/tlb.cc
@@ -288,9 +288,9 @@
         return std::make_shared<AlignmentFault>();
     }

-     Process * p = tc->getProcessPtr();
-
-     Fault fault = p->pTable->translate(req);
+    auto p = tc->getProcessPtr();
+    auto mem_state = p->memState;
+    Fault fault = mem_state->_pTable->translate(req);
     if (fault != NoFault)
         return fault;

@@ -301,8 +301,9 @@
 TLB::translateData(const RequestPtr &req, ThreadContext *tc, bool write)
 {
     Process * p = tc->getProcessPtr();
+    auto mem_state = p->memState;

-    Fault fault = p->pTable->translate(req);
+    Fault fault = mem_state->_pTable->translate(req);
     if (fault != NoFault)
         return fault;

diff --git a/src/arch/riscv/process.cc b/src/arch/riscv/process.cc
index 08ab436..a1f0b42 100644
--- a/src/arch/riscv/process.cc
+++ b/src/arch/riscv/process.cc
@@ -53,8 +53,8 @@
 #include "mem/page_table.hh"
 #include "params/Process.hh"
 #include "sim/aux_vector.hh"
+#include "sim/mem_state_impl.hh"
 #include "sim/process.hh"
-#include "sim/process_impl.hh"
 #include "sim/syscall_return.hh"
 #include "sim/system.hh"

@@ -62,19 +62,19 @@
 using namespace RiscvISA;

 RiscvProcess::RiscvProcess(ProcessParams *params, ObjectFile *objFile) :
-        Process(params,
- new EmulationPageTable(params->name, params->pid, PageBytes),
-                objFile)
+        Process(params, objFile)
 {
-    fatal_if(params->useArchPT, "Arch page tables not implemented.");
     const Addr stack_base = 0x7FFFFFFFFFFFFFFFL;
     const Addr max_stack_size = 8 * 1024 * 1024;
     const Addr next_thread_stack_base = stack_base - max_stack_size;
     const Addr brk_point = roundUp(objFile->bssBase() + objFile->bssSize(),
             PageBytes);
     const Addr mmap_end = 0x4000000000000000L;
-    memState = make_shared<MemState>(brk_point, stack_base, max_stack_size,
-            next_thread_stack_base, mmap_end);
+ auto p_table = make_shared<EmulationPageTable>(params->name, params->pid,
+                                                   PageBytes);
+    memState = make_shared<MemState>(this, brk_point, stack_base,
+ max_stack_size, next_thread_stack_base,
+                                     mmap_end, params->system, p_table);
 }

 void
@@ -123,8 +123,8 @@
                    sizeof(Addr) + 2 * sizeof(IntType) * auxv.size();
     stack_top &= -2*sizeof(Addr);
     memState->setStackSize(memState->getStackBase() - stack_top);
-    allocateMem(roundDown(stack_top, pageSize),
-            roundUp(memState->getStackSize(), pageSize));
+    memState->allocateMem(roundDown(stack_top, pageSize),
+                          roundUp(memState->getStackSize(), pageSize));

     // Copy random bytes (for AT_RANDOM) to stack
     memState->setStackMin(memState->getStackMin() - RandomBytes);
diff --git a/src/arch/riscv/process.hh b/src/arch/riscv/process.hh
index bda278e..afc2ad5 100644
--- a/src/arch/riscv/process.hh
+++ b/src/arch/riscv/process.hh
@@ -61,8 +61,6 @@
                        RiscvISA::IntReg val) override;
     void setSyscallReturn(ThreadContext *tc,
                           SyscallReturn return_value) override;
-
-    virtual bool mmapGrowsDown() const override { return false; }
 };

 #endif // __RISCV_PROCESS_HH__
diff --git a/src/arch/riscv/remote_gdb.cc b/src/arch/riscv/remote_gdb.cc
index 6d56a93..3ba5b14 100644
--- a/src/arch/riscv/remote_gdb.cc
+++ b/src/arch/riscv/remote_gdb.cc
@@ -157,7 +157,9 @@
 RemoteGDB::acc(Addr va, size_t len)
 {
     panic_if(FullSystem, "acc not implemented for RISCV FS!");
-    return context()->getProcessPtr()->pTable->lookup(va) != nullptr;
+    auto process = context()->getProcessPtr();
+    auto mem_state = process->memState;
+    return mem_state->translate(va);
 }

 void
diff --git a/src/arch/riscv/tlb.cc b/src/arch/riscv/tlb.cc
index 494ec4c..c1cfcd0 100644
--- a/src/arch/riscv/tlb.cc
+++ b/src/arch/riscv/tlb.cc
@@ -309,8 +309,9 @@
         }
     } else {
         Process * p = tc->getProcessPtr();
+        auto mem_state = p->memState;

-        Fault fault = p->pTable->translate(req);
+        Fault fault = mem_state->_pTable->translate(req);
         if (fault != NoFault)
             return fault;

@@ -355,8 +356,9 @@
             return make_shared<GenericPageTableFault>(req->getVaddr());

         Process * p = tc->getProcessPtr();
+        auto mem_state = p->memState;

-        Fault fault = p->pTable->translate(req);
+        Fault fault = mem_state->_pTable->translate(req);
         if (fault != NoFault)
             return fault;

diff --git a/src/arch/sparc/faults.cc b/src/arch/sparc/faults.cc
index 6375fa5..018cf0a 100644
--- a/src/arch/sparc/faults.cc
+++ b/src/arch/sparc/faults.cc
@@ -630,10 +630,11 @@
     }

     Process *p = tc->getProcessPtr();
-    const EmulationPageTable::Entry *pte = p->pTable->lookup(vaddr);
+    auto mem_state = p->memState;
+ const EmulationPageTable::Entry *pte = mem_state->_pTable->lookup(vaddr);
     panic_if(!pte, "Tried to execute unmapped address %#x.\n", vaddr);

-    Addr alignedvaddr = p->pTable->pageAlign(vaddr);
+    Addr alignedvaddr = mem_state->_pTable->pageAlign(vaddr);

     // Grab fields used during instruction translation to figure out
     // which context to use.
@@ -663,7 +664,7 @@
     // the logic works out to the following for the context.
     int context_id = (is_real_address || trapped) ? 0 : primary_context;

-    TlbEntry entry(p->pTable->pid(), alignedvaddr, pte->paddr,
+    TlbEntry entry(mem_state->_pTable->pid(), alignedvaddr, pte->paddr,
                    pte->flags & EmulationPageTable::Uncacheable,
                    pte->flags & EmulationPageTable::ReadOnly);

@@ -685,12 +686,11 @@
     }

     Process *p = tc->getProcessPtr();
-    const EmulationPageTable::Entry *pte = p->pTable->lookup(vaddr);
-    if (!pte && p->fixupStackFault(vaddr))
-        pte = p->pTable->lookup(vaddr);
+    auto mem_state = p->memState;
+    const EmulationPageTable::Entry *pte = mem_state->lookup(vaddr);
     panic_if(!pte, "Tried to access unmapped address %#x.\n", vaddr);

-    Addr alignedvaddr = p->pTable->pageAlign(vaddr);
+    Addr alignedvaddr = mem_state->_pTable->pageAlign(vaddr);

     // Grab fields used during data translation to figure out
     // which context to use.
@@ -750,7 +750,7 @@
     // The partition id distinguishes between virtualized environments.
     int const partition_id = 0;

-    TlbEntry entry(p->pTable->pid(), alignedvaddr, pte->paddr,
+    TlbEntry entry(mem_state->_pTable->pid(), alignedvaddr, pte->paddr,
                    pte->flags & EmulationPageTable::Uncacheable,
                    pte->flags & EmulationPageTable::ReadOnly);

diff --git a/src/arch/sparc/process.cc b/src/arch/sparc/process.cc
index c98c9b7..68c4b22 100644
--- a/src/arch/sparc/process.cc
+++ b/src/arch/sparc/process.cc
@@ -44,7 +44,7 @@
 #include "mem/page_table.hh"
 #include "params/Process.hh"
 #include "sim/aux_vector.hh"
-#include "sim/process_impl.hh"
+#include "sim/mem_state_impl.hh"
 #include "sim/syscall_return.hh"
 #include "sim/system.hh"

@@ -56,12 +56,9 @@

 SparcProcess::SparcProcess(ProcessParams *params, ObjectFile *objFile,
                            Addr _StackBias)
-    : Process(params,
-              new EmulationPageTable(params->name, params->pid, PageBytes),
-              objFile),
+    : Process(params, objFile),
       StackBias(_StackBias)
 {
-    fatal_if(params->useArchPT, "Arch page tables not implemented.");
     // Initialize these to 0s
     fillStart = 0;
     spillStart = 0;
@@ -328,8 +325,8 @@
memState->setStackSize(memState->getStackBase() - memState->getStackMin());

     // Allocate space for the stack
-    allocateMem(roundDown(memState->getStackMin(), pageSize),
-                roundUp(memState->getStackSize(), pageSize));
+    memState->allocateMem(roundDown(memState->getStackMin(), pageSize),
+                          roundUp(memState->getStackSize(), pageSize));

     // map out initial stack contents
     IntType sentry_base = memState->getStackBase() - sentry_size;
diff --git a/src/arch/sparc/process.hh b/src/arch/sparc/process.hh
index d7e0967..10a89e9 100644
--- a/src/arch/sparc/process.hh
+++ b/src/arch/sparc/process.hh
@@ -39,6 +39,7 @@
 #include "arch/sparc/isa_traits.hh"
 #include "base/loader/object_file.hh"
 #include "mem/page_table.hh"
+#include "params/Process.hh"
 #include "sim/byteswap.hh"
 #include "sim/process.hh"

@@ -95,10 +96,14 @@
         // Set up region for mmaps.
         Addr mmap_end = 0x70000000;

-        memState = std::make_shared<MemState>(brk_point, stack_base,
+        auto p_table = std::make_shared<EmulationPageTable>(params->name,
+                                                        params->pid,
+ SparcISA::PageBytes);
+        memState = std::make_shared<MemState>(this, brk_point, stack_base,
                                               max_stack_size,
                                               next_thread_stack_base,
-                                              mmap_end);
+                                              mmap_end, params->system,
+                                              p_table);
     }

     void initState();
@@ -139,10 +144,14 @@
         // Set up region for mmaps.
         Addr mmap_end = 0xfffff80000000000ULL;

-        memState = std::make_shared<MemState>(brk_point, stack_base,
+        auto p_table = std::make_shared<EmulationPageTable>(params->name,
+                                                        params->pid,
+ SparcISA::PageBytes);
+        memState = std::make_shared<MemState>(this, brk_point, stack_base,
                                               max_stack_size,
                                               next_thread_stack_base,
-                                              mmap_end);
+                                              mmap_end, params->system,
+                                              p_table);
     }

     void initState();
diff --git a/src/arch/sparc/remote_gdb.cc b/src/arch/sparc/remote_gdb.cc
index 057cea1..c4b96dc 100644
--- a/src/arch/sparc/remote_gdb.cc
+++ b/src/arch/sparc/remote_gdb.cc
@@ -167,7 +167,9 @@
     } else {
         // Check to make sure the first byte is mapped into the processes
         // address space.
-        return context()->getProcessPtr()->pTable->lookup(va) != nullptr;
+        auto process = context()->getProcessPtr();
+        auto mem_state = process->memState;
+        return mem_state->translate(va);
     }
 }

diff --git a/src/arch/x86/process.cc b/src/arch/x86/process.cc
index f5fccf0..a19ec43 100644
--- a/src/arch/x86/process.cc
+++ b/src/arch/x86/process.cc
@@ -62,7 +62,7 @@
 #include "mem/page_table.hh"
 #include "params/Process.hh"
 #include "sim/aux_vector.hh"
-#include "sim/process_impl.hh"
+#include "sim/mem_state_impl.hh"
 #include "sim/syscall_desc.hh"
 #include "sim/syscall_return.hh"
 #include "sim/system.hh"
@@ -107,14 +107,8 @@

 X86Process::X86Process(ProcessParams *params, ObjectFile *objFile,
                        SyscallDesc *_syscallDescs, int _numSyscallDescs)
-    : Process(params, params->useArchPT ?
-                      static_cast<EmulationPageTable *>(
-                              new ArchPageTable(params->name, params->pid,
- params->system, PageBytes)) :
-                      new EmulationPageTable(params->name, params->pid,
-                                             PageBytes),
-              objFile),
-      syscallDescs(_syscallDescs), numSyscallDescs(_numSyscallDescs)
+    : Process(params, objFile), syscallDescs(_syscallDescs),
+      numSyscallDescs(_numSyscallDescs)
 {
 }

@@ -143,8 +137,20 @@
     Addr next_thread_stack_base = stack_base - max_stack_size;
     Addr mmap_end = 0x7FFFF7FFF000ULL;

-    memState = make_shared<MemState>(brk_point, stack_base, max_stack_size,
-                                     next_thread_stack_base, mmap_end);
+    auto p_table = params->useArchPT ?
+                   static_pointer_cast<EmulationPageTable>(
+ make_shared<ArchPageTable>(params->name, params->pid, + params->system, PageBytes)) : + make_shared<EmulationPageTable>(params->name, params->pid,
+                                                   PageBytes);
+    memState = make_shared<MemState>(this, brk_point, stack_base,
+ max_stack_size, next_thread_stack_base,
+                                     mmap_end, params->system, p_table);
+}
+
+void
+X86_64Process::init()
+{
 }

 void
@@ -180,8 +186,15 @@
     Addr next_thread_stack_base = stack_base - max_stack_size;
     Addr mmap_end = 0xB7FFF000ULL;

-    memState = make_shared<MemState>(brk_point, stack_base, max_stack_size,
-                                     next_thread_stack_base, mmap_end);
+    auto p_table = params->useArchPT ?
+                   static_pointer_cast<EmulationPageTable>(
+ make_shared<ArchPageTable>(params->name, params->pid, + params->system, PageBytes)) : + make_shared<EmulationPageTable>(params->name, params->pid,
+                                                   PageBytes);
+    memState = make_shared<MemState>(this, brk_point, stack_base,
+ max_stack_size, next_thread_stack_base,
+                                     mmap_end, params->system, p_table);
 }

 SyscallDesc*
@@ -199,8 +212,11 @@

     argsInit(PageBytes);

+    auto p_table = memState->_pTable;
+
     // Set up the vsyscall page for this process.
-    allocateMem(vsyscallPage.base, vsyscallPage.size);
+    memState->mapVMARegion(vsyscallPage.base, vsyscallPage.size, -1, 0);
+    const auto &virt_mem = memState->getVirtMem();
     uint8_t vtimeBlob[] = {
         0x48,0xc7,0xc0,0xc9,0x00,0x00,0x00,    // mov    $0xc9,%rax
         0x0f,0x05,                             // syscall
@@ -410,7 +426,7 @@
             CR0 cr2 = 0;
             tc->setMiscReg(MISCREG_CR2, cr2);

-            CR3 cr3 = dynamic_cast<ArchPageTable *>(pTable)->basePtr();
+ CR3 cr3 = dynamic_pointer_cast<ArchPageTable>(p_table)->basePtr();
             tc->setMiscReg(MISCREG_CR3, cr3);

             CR4 cr4 = 0;
@@ -543,21 +559,21 @@
physProxy.writeBlob(pfHandlerPhysAddr, faultBlob, sizeof(faultBlob));

         /* Syscall handler */
-        pTable->map(syscallCodeVirtAddr, syscallCodePhysAddr,
-                    PageBytes, false);
+        p_table->map(syscallCodeVirtAddr, syscallCodePhysAddr,
+                     PageBytes, false);
         /* GDT */
-        pTable->map(GDTVirtAddr, gdtPhysAddr, PageBytes, false);
+        p_table->map(GDTVirtAddr, gdtPhysAddr, PageBytes, false);
         /* IDT */
-        pTable->map(IDTVirtAddr, idtPhysAddr, PageBytes, false);
+        p_table->map(IDTVirtAddr, idtPhysAddr, PageBytes, false);
         /* TSS */
-        pTable->map(TSSVirtAddr, tssPhysAddr, PageBytes, false);
+        p_table->map(TSSVirtAddr, tssPhysAddr, PageBytes, false);
         /* IST */
-        pTable->map(ISTVirtAddr, istPhysAddr, PageBytes, false);
+        p_table->map(ISTVirtAddr, istPhysAddr, PageBytes, false);
         /* PF handler */
- pTable->map(PFHandlerVirtAddr, pfHandlerPhysAddr, PageBytes, false); + p_table->map(PFHandlerVirtAddr, pfHandlerPhysAddr, PageBytes, false);
         /* MMIO region for m5ops */
-        pTable->map(MMIORegionVirtAddr, MMIORegionPhysAddr,
-                    16 * PageBytes, false);
+        p_table->map(MMIORegionVirtAddr, MMIORegionPhysAddr,
+                     16 * PageBytes, false);
     } else {
         for (int i = 0; i < contextIds.size(); i++) {
             ThreadContext * tc = system->getThreadContext(contextIds[i]);
@@ -641,7 +657,8 @@
      * Set up a GDT for this process. The whole GDT wouldn't really be for
      * this process, but the only parts we care about are.
      */
-    allocateMem(_gdtStart, _gdtSize);
+    memState->allocateMem(_gdtStart, _gdtSize);
+    const auto &virt_mem = memState->getVirtMem();
     uint64_t zero = 0;
     assert(_gdtSize % sizeof(zero) == 0);
     for (Addr gdtCurrent = _gdtStart;
@@ -650,7 +667,7 @@
     }

     // Set up the vsyscall page for this process.
-    allocateMem(vsyscallPage.base, vsyscallPage.size);
+    memState->allocateMem(vsyscallPage.base, vsyscallPage.size);
     uint8_t vsyscallBlob[] = {
         0x51,       // push %ecx
         0x52,       // push %edp
@@ -955,15 +972,17 @@
     Addr stack_min = stack_base - space_needed;
     stack_min = roundDown(stack_min, align);

-    unsigned stack_size = stack_base - stack_min;
-    stack_size = roundUp(stack_size, pageSize);
-    memState->setStackSize(stack_size);
+    /**
+ * Map the maximum stack area as valid to make things easier to maintain.
+     * Keep in mind that the stack grows downward so the mapping looks
+     * backwards here.
+     */
+    Addr max_stack_size = memState->getMaxStackSize();
+    Addr stack_end = roundDown(stack_base - max_stack_size, pageSize);

-    // map memory
-    Addr stack_end = roundDown(stack_base - stack_size, pageSize);
+    memState->mapVMARegion(stack_end, max_stack_size, -1, 0);

-    DPRINTF(Stack, "Mapping the stack: 0x%x %dB\n", stack_end, stack_size);
-    allocateMem(stack_end, stack_size);
+ DPRINTF(Stack, "Mapping the stack: 0x%x %dB\n", stack_end, max_stack_size);

     // map out initial stack contents
     IntType sentry_base = stack_base - sentry_size;
@@ -1037,9 +1056,6 @@
// There doesn't need to be any segment base added in since we're dealing
     // with the flat segmentation model.
     tc->pcState(getStartPC());
-
-    // Align the "stack_min" to a page boundary.
-    memState->setStackMin(roundDown(stack_min, pageSize));
 }

 void
diff --git a/src/arch/x86/process.hh b/src/arch/x86/process.hh
index b9052c4..53eabe0 100644
--- a/src/arch/x86/process.hh
+++ b/src/arch/x86/process.hh
@@ -132,6 +132,7 @@
         VSyscallPage vsyscallPage;

       public:
+        void init() override;
         void argsInit(int pageSize);
         void initState() override;

diff --git a/src/arch/x86/remote_gdb.cc b/src/arch/x86/remote_gdb.cc
index 9564593..5d4ea4f 100644
--- a/src/arch/x86/remote_gdb.cc
+++ b/src/arch/x86/remote_gdb.cc
@@ -88,7 +88,11 @@
                                         BaseTLB::Read);
         return fault == NoFault;
     } else {
-        return context()->getProcessPtr()->pTable->lookup(va) != nullptr;
+ // Check if the virtual address is valid and map a physical page if it
+        // hasn't been already
+        auto process = context()->getProcessPtr();
+        auto mem_state = process->memState;
+        return mem_state->translate(va);
     }
 }

diff --git a/src/arch/x86/tlb.cc b/src/arch/x86/tlb.cc
index 8e83208..b4bc66a 100644
--- a/src/arch/x86/tlb.cc
+++ b/src/arch/x86/tlb.cc
@@ -231,7 +231,7 @@

     AddrRange m5opRange(0xFFFF0000, 0xFFFFFFFF);

-    if (m5opRange.contains(paddr)) {
+    if (!FullSystem && m5opRange.contains(paddr)) {
         req->setFlags(Request::MMAPPED_IPR | Request::GENERIC_IPR |
                       Request::STRICT_ORDER);
         req->setPaddr(GenericISA::iprAddressPseudoInst((paddr >> 8) & 0xFF,
@@ -358,25 +358,24 @@
                     entry = lookup(vaddr);
                     assert(entry);
                 } else {
-                    Process *p = tc->getProcessPtr();
+                    DPRINTF(TLB, "Handling a TLB miss for "
+                            "address %#x at pc %#x.\n",
+                            vaddr, tc->instAddr());
+
+                    auto p = tc->getProcessPtr();
+                    auto mem_state = p->memState;
                     const EmulationPageTable::Entry *pte =
-                        p->pTable->lookup(vaddr);
-                    if (!pte && mode != Execute) {
-                        // Check if we just need to grow the stack.
-                        if (p->fixupStackFault(vaddr)) {
- // If we did, lookup the entry for the new page.
-                            pte = p->pTable->lookup(vaddr);
-                        }
-                    }
+                        mem_state->lookup(vaddr);
                     if (!pte) {
return std::make_shared<PageFault>(vaddr, true, mode,
                                                            true, false);
                     } else {
-                        Addr alignedVaddr = p->pTable->pageAlign(vaddr);
+                        Addr alignedVaddr =
+                            mem_state->_pTable->pageAlign(vaddr);
                         DPRINTF(TLB, "Mapping %#x to %#x\n", alignedVaddr,
                                 pte->paddr);
                         entry = insert(alignedVaddr, TlbEntry(
-                                p->pTable->pid(), alignedVaddr, pte->paddr,
+                                p->pid(), alignedVaddr, pte->paddr,
pte->flags & EmulationPageTable::Uncacheable, pte->flags & EmulationPageTable::ReadOnly));
                     }
diff --git a/src/cpu/thread_context.hh b/src/cpu/thread_context.hh
index 1c534a1..b4a037d 100644
--- a/src/cpu/thread_context.hh
+++ b/src/cpu/thread_context.hh
@@ -47,6 +47,7 @@
 #include <iostream>
 #include <string>

+#include "arch/generic/tlb.hh"
 #include "arch/registers.hh"
 #include "arch/types.hh"
 #include "base/types.hh"
@@ -60,7 +61,6 @@
     class Decoder;
 }
 class BaseCPU;
-class BaseTLB;
 class CheckerCPU;
 class Checkpoint;
 class EndQuiesceEvent;
diff --git a/src/gpu-compute/compute_unit.cc b/src/gpu-compute/compute_unit.cc
index fd328ad..158ae64 100644
--- a/src/gpu-compute/compute_unit.cc
+++ b/src/gpu-compute/compute_unit.cc
@@ -784,12 +784,10 @@

             Addr paddr;

-            if (!p->pTable->translate(vaddr, paddr)) {
-                if (!p->fixupStackFault(vaddr)) {
+            if (!p->memState->translate(vaddr, paddr)) {
                     panic("CU%d: WF[%d][%d]: Fault on addr %#x!\n",
                           cu_id, gpuDynInst->simdId, gpuDynInst->wfSlotId,
                           vaddr);
-                }
             }
         }

diff --git a/src/gpu-compute/gpu_tlb.cc b/src/gpu-compute/gpu_tlb.cc
index fea6183..9e116af 100644
--- a/src/gpu-compute/gpu_tlb.cc
+++ b/src/gpu-compute/gpu_tlb.cc
@@ -808,17 +808,19 @@
DPRINTF(GPUTLB, "Handling a TLB miss for address %#x "
                                 "at pc %#x.\n", vaddr, tc->instAddr());

-                        Process *p = tc->getProcessPtr();
+                        auto p = tc->getProcessPtr();
+                        auto mem_state = p->memState;
+                        auto p_table = mem_state->_pTable;
                         const EmulationPageTable::Entry *pte =
-                            p->pTable->lookup(vaddr);
+                            p_table->lookup(vaddr);

                         if (!pte && mode != BaseTLB::Execute) {
                             // penalize a "page fault" more
                             if (timing)
                                 latency += missLatency2;

-                            if (p->fixupStackFault(vaddr))
-                                pte = p->pTable->lookup(vaddr);
+                            if (mem_state->fixupFault(vaddr))
+                                pte = p_table->lookup(vaddr);
                         }

                         if (!pte) {
@@ -826,7 +828,7 @@
                                                                mode, true,
                                                                false);
                         } else {
- Addr alignedVaddr = p->pTable->pageAlign(vaddr);
+                            Addr alignedVaddr = p_table->pageAlign(vaddr);

                             DPRINTF(GPUTLB, "Mapping %#x to %#x\n",
                                     alignedVaddr, pte->paddr);
@@ -1332,17 +1334,15 @@
             TranslationState *sender_state =
                 safe_cast<TranslationState*>(pkt->senderState);

-            Process *p = sender_state->tc->getProcessPtr();
+            auto p = sender_state->tc->getProcessPtr();
+            auto mem_state = p->memState;
             Addr vaddr = pkt->req->getVaddr();
     #ifndef NDEBUG
-            Addr alignedVaddr = p->pTable->pageAlign(vaddr);
+            auto p_table = mem_state->_pTable;
+            Addr alignedVaddr = p_table->pageAlign(vaddr);
             assert(alignedVaddr == virtPageAddr);
     #endif
- const EmulationPageTable::Entry *pte = p->pTable->lookup(vaddr);
-            if (!pte && sender_state->tlbMode != BaseTLB::Execute &&
-                    p->fixupStackFault(vaddr)) {
-                pte = p->pTable->lookup(vaddr);
-            }
+ const EmulationPageTable::Entry *pte = mem_state->lookup(vaddr);

             if (pte) {
                 DPRINTF(GPUTLB, "Mapping %#x to %#x\n", alignedVaddr,
@@ -1533,20 +1533,18 @@
                 DPRINTF(GPUTLB, "Doing a page walk for address %#x\n",
                         virt_page_addr);

-                Process *p = tc->getProcessPtr();
+                auto p = tc->getProcessPtr();
+                auto mem_state = p->memState;

                 Addr vaddr = pkt->req->getVaddr();
     #ifndef NDEBUG
-                Addr alignedVaddr = p->pTable->pageAlign(vaddr);
+                auto p_table = mem_state->_pTable;
+                Addr alignedVaddr = p_table->pageAlign(vaddr);
                 assert(alignedVaddr == virt_page_addr);
     #endif

                 const EmulationPageTable::Entry *pte =
-                        p->pTable->lookup(vaddr);
-                if (!pte && sender_state->tlbMode != BaseTLB::Execute &&
-                        p->fixupStackFault(vaddr)) {
-                    pte = p->pTable->lookup(vaddr);
-                }
+                        mem_state->lookup(vaddr);

                 if (!sender_state->prefetch) {
                     // no PageFaults are permitted after
diff --git a/src/gpu-compute/shader.cc b/src/gpu-compute/shader.cc
index d0bd41a..f3cb9ef 100644
--- a/src/gpu-compute/shader.cc
+++ b/src/gpu-compute/shader.cc
@@ -84,7 +84,7 @@
     Process *proc = gpuTc->getProcessPtr();
     auto mem_state = proc->memState;

-    if (proc->mmapGrowsDown()) {
+    if (mem_state->mmapGrowsDown()) {
         DPRINTF(HSAIL, "GROWS DOWN");
         start = mem_state->getMmapEnd() - length;
         mem_state->setMmapEnd(start);
@@ -100,7 +100,7 @@

     DPRINTF(HSAIL,"Shader::mmap start= %#x, %#x\n", start, length);

-    proc->allocateMem(start, length);
+    mem_state->allocateMem(start, length);

     return start;
 }
diff --git a/src/mem/se_translating_port_proxy.cc b/src/mem/se_translating_port_proxy.cc
index bb30ffb..c0dbdcc 100644
--- a/src/mem/se_translating_port_proxy.cc
+++ b/src/mem/se_translating_port_proxy.cc
@@ -44,21 +44,22 @@

 #include "mem/se_translating_port_proxy.hh"

+#include <cassert>
 #include <string>

 #include "arch/isa_traits.hh"
 #include "base/chunk_generator.hh"
 #include "config/the_isa.hh"
 #include "mem/page_table.hh"
-#include "sim/process.hh"
-#include "sim/system.hh"
+#include "sim/mem_state.hh"

 using namespace TheISA;

-SETranslatingPortProxy::SETranslatingPortProxy(MasterPort& port, Process *p,
-                                           AllocType alloc)
-    : PortProxy(port, p->system->cacheLineSize()), pTable(p->pTable),
-      process(p), allocating(alloc)
+SETranslatingPortProxy::SETranslatingPortProxy(MasterPort& port,
+                                               unsigned cache_line_size,
+                                               MemState *mem_state,
+                                               AllocType alloc)
+ : PortProxy(port, cache_line_size), _memState(mem_state), allocating(alloc)
 { }

 SETranslatingPortProxy::~SETranslatingPortProxy()
@@ -72,8 +73,8 @@
for (ChunkGenerator gen(addr, size, PageBytes); !gen.done(); gen.next()) {
         Addr paddr;

-        if (!pTable->translate(gen.addr(),paddr))
-            return false;
+        if (!_memState->translate(gen.addr(), paddr))
+                return false;

         PortProxy::readBlobPhys(paddr, 0, p + prevSize, gen.size());
         prevSize += gen.size();
@@ -99,19 +100,19 @@
for (ChunkGenerator gen(addr, size, PageBytes); !gen.done(); gen.next()) {
         Addr paddr;

-        if (!pTable->translate(gen.addr(), paddr)) {
+        if (!_memState->translate(gen.addr(), paddr)) {
             if (allocating == Always) {
-                process->allocateMem(roundDown(gen.addr(), PageBytes),
-                                     PageBytes);
-            } else if (allocating == NextPage) {
-                // check if we've accessed the next page on the stack
-                if (!process->fixupStackFault(gen.addr()))
- panic("Page table fault when accessing virtual address %#x "
-                            "during functional write\n", gen.addr());
+                _memState->allocateMem(roundDown(gen.addr(), PageBytes),
+                                       PageBytes);
+            } else if (allocating == OnDemand) {
+                // check if we've accessed an unallocated physical page
+                if (!_memState->fixupFault(gen.addr()))
+ panic("Page table fault when accessing virtual address %#x"
+                            " during functional write\n", gen.addr());
             } else {
                 return false;
             }
-            pTable->translate(gen.addr(), paddr);
+            _memState->translate(gen.addr(), paddr);
         }

         PortProxy::writeBlobPhys(paddr, 0, p + prevSize, gen.size());
@@ -135,11 +136,11 @@
for (ChunkGenerator gen(addr, size, PageBytes); !gen.done(); gen.next()) {
         Addr paddr;

-        if (!pTable->translate(gen.addr(), paddr)) {
+        if (!_memState->translate(gen.addr(), paddr)) {
             if (allocating == Always) {
-                process->allocateMem(roundDown(gen.addr(), PageBytes),
-                                     PageBytes);
-                pTable->translate(gen.addr(), paddr);
+                _memState->allocateMem(roundDown(gen.addr(), PageBytes),
+                                       PageBytes);
+                _memState->translate(gen.addr(), paddr);
             } else {
                 return false;
             }
@@ -170,7 +171,7 @@
         c = *str++;
         Addr paddr;

-        if (!pTable->translate(vaddr++, paddr))
+        if (!_memState->translate(vaddr++, paddr))
             return false;

         PortProxy::writeBlob(paddr, &c, 1);
@@ -196,7 +197,7 @@
     while (true) {
         Addr paddr;

-        if (!pTable->translate(vaddr++, paddr))
+        if (!_memState->translate(vaddr++, paddr))
             return false;

         PortProxy::readBlob(paddr, &c, 1);
diff --git a/src/mem/se_translating_port_proxy.hh b/src/mem/se_translating_port_proxy.hh
index 04bfd8a..1ebb8cb 100644
--- a/src/mem/se_translating_port_proxy.hh
+++ b/src/mem/se_translating_port_proxy.hh
@@ -45,10 +45,11 @@
 #ifndef __MEM_SE_TRANSLATING_PORT_PROXY_HH__
 #define __MEM_SE_TRANSLATING_PORT_PROXY_HH__

+#include <memory>
+
 #include "mem/port_proxy.hh"

-class EmulationPageTable;
-class Process;
+class MemState;

 /**
  * @file
@@ -71,20 +72,18 @@
     enum AllocType {
         Always,
         Never,
-        NextPage
+        OnDemand
     };

   private:
-    EmulationPageTable *pTable;
-    Process *process;
+    MemState *_memState;
     AllocType allocating;

   public:
-    SETranslatingPortProxy(MasterPort& port, Process* p, AllocType alloc);
-    ~SETranslatingPortProxy();
+    SETranslatingPortProxy(MasterPort& port, unsigned cache_line_size,
+                           MemState *mem_state, AllocType alloc);
+    virtual ~SETranslatingPortProxy();

-    void setPageTable(EmulationPageTable *p) { pTable = p; }
-    void setProcess(Process *p) { process = p; }
     bool tryReadBlob(Addr addr, uint8_t *p, int size) const;
     bool tryWriteBlob(Addr addr, const uint8_t *p, int size) const;
     bool tryMemsetBlob(Addr addr, uint8_t val, int size) const;
diff --git a/src/sim/SConscript b/src/sim/SConscript
index ed3da4c..321159a 100644
--- a/src/sim/SConscript
+++ b/src/sim/SConscript
@@ -83,6 +83,7 @@
     Source('process.cc')
     Source('fd_array.cc')
     Source('fd_entry.cc')
+    Source('mem_state.cc')
     Source('pseudo_inst.cc')
     Source('syscall_emul.cc')
     Source('syscall_desc.cc')
diff --git a/src/sim/faults.cc b/src/sim/faults.cc
index 0606080..c3c1919 100644
--- a/src/sim/faults.cc
+++ b/src/sim/faults.cc
@@ -68,8 +68,9 @@
 {
     bool handled = false;
     if (!FullSystem) {
-        Process *p = tc->getProcessPtr();
-        handled = p->fixupStackFault(vaddr);
+        auto p = tc->getProcessPtr();
+        auto mem_state = p->memState;
+        handled = mem_state->fixupFault(vaddr);
     }
     if (!handled)
panic("Page table fault when accessing virtual address %#x\n", vaddr);
diff --git a/src/sim/mem_state.cc b/src/sim/mem_state.cc
new file mode 100644
index 0000000..794d25b
--- /dev/null
+++ b/src/sim/mem_state.cc
@@ -0,0 +1,473 @@
+/*
+ * Copyright (c) 2017 Advanced Micro Devices, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Author: Michael LeBeane
+ *         Brandon Potter
+ */
+
+#include "sim/mem_state.hh"
+
+#include <cassert>
+
+#include "mem/se_translating_port_proxy.hh"
+#include "mem/vma.hh"
+#include "sim/process.hh"
+#include "sim/syscall_debug_macros.hh"
+#include "sim/system.hh"
+
+MemState::MemState(Process *owner, Addr brk_point, Addr stack_base,
+                   Addr max_stack_size, Addr next_thread_stack_base,
+                   Addr mmap_end, System *system,
+                   std::shared_ptr<EmulationPageTable> p_table)
+    : _pTable(p_table), _ownerProcesses{owner}, _brkPoint(brk_point),
+      _stackBase(stack_base), _maxStackSize(max_stack_size),
+      _nextThreadStackBase(next_thread_stack_base),
+      _mmapEnd(mmap_end),
+      _endBrkPoint(brk_point),
+      _virtMem(system->getSystemPort(), system->cacheLineSize(), this,
+               SETranslatingPortProxy::Always)
+{
+}
+
+MemState&
+MemState::operator=(const MemState &other)
+{
+    if (this == &other)
+        return *this;
+
+    _brkPoint = other._brkPoint;
+    _stackBase = other._stackBase;
+    _maxStackSize = other._maxStackSize;
+    _nextThreadStackBase = other._nextThreadStackBase;
+    _mmapEnd = other._mmapEnd;
+    _vmaList = other._vmaList; /* This assignment does a deep copy. */
+
+    /* Do a page-table deep copy between the two MemState objects. */
+    typedef std::vector<std::pair<Addr,Addr>> MapVec;
+    MapVec mappings;
+    other._pTable->getMappings(&mappings);
+    for (auto map : mappings) {
+        Addr paddr, vaddr = map.first;
+        bool alloc_page = !(_pTable->translate(vaddr, paddr));
+        replicatePage(other, vaddr, paddr, alloc_page);
+    }
+
+    return *this;
+}
+
+void
+MemState::addOwner(Process *owner)
+{
+    auto it = _ownerProcesses.begin();
+    while (it != _ownerProcesses.end()) {
+        if (*it == owner)
+            break;
+        it++;
+    }
+
+    if (it == _ownerProcesses.end())
+        _ownerProcesses.push_back(owner);
+}
+
+void
+MemState::removeOwner(Process *owner)
+{
+    auto it = _ownerProcesses.begin();
+    while (it != _ownerProcesses.end()) {
+        if (*it == owner)
+            break;
+        it++;
+    }
+
+    if (it != _ownerProcesses.end())
+        _ownerProcesses.erase(it);
+}
+
+void
+MemState::updateBrkRegion(Addr old_brk, Addr new_brk)
+{
+    /**
+     * To make this simple, avoid reducing the heap memory area if the
+     * new_brk point is less than the old_brk; this occurs when the heap is
+ * receding because the application has given back memory. The brk point + * is still tracked in the MemState class as an independent field so that
+     * it can be returned to the application; we just do not update the
+     * VMA region unless we expand it out.
+     */
+    if (new_brk < old_brk)
+        return;
+
+    /**
+     * The VMAs must be page aligned but the break point can be set on
+     * byte boundaries. Ensure that the restriction is maintained here by
+     * extending the request out to the end of the page. (The roundUp
+     * function will not round up an already aligned page.)
+     */
+    new_brk = roundUp(new_brk, TheISA::PageBytes);
+
+    /**
+     * Create a new mapping for the heap region. We only create a mapping
+ * for the extra memory that is requested so we do not create a situation
+     * where there can be overlapping mappings in the VMA regions.
+     * Since we do not track the type of the region and we also do not
+     * coalesce the regions together, we can create a fragmented set of
+     * heap VMAs. To resolve this, we keep the furthest point ever mapped
+     * by the _endBrkPoint field.
+     */
+    if (new_brk > _endBrkPoint) {
+        /**
+         * Note that the heap regions are always contiguous but there is no
+         * mechanism right now to coalesce VMAs together that belong to the
+         * same region with similar access permissions. This could be
+         * implemented if it actually becomes necessary; probably only
+         * necessary if the list becomes too long to walk.
+         */
+        mapVMARegion(_endBrkPoint, new_brk - _endBrkPoint, -1, 0);
+        _endBrkPoint = new_brk;
+    }
+}
+
+void
+MemState::mapVMARegion(Addr start_addr, Addr length, int sim_fd, Addr offset)
+{
+    DPRINTF(SyscallVerbose, "vma: creating region [0x%x - 0x%x]\n",
+            start_addr, start_addr + length - 1);
+
+    /**
+     * Avoid creating a region that has preexisting mappings. This should
+     * not happen under normal circumstances so consider this to be a bug.
+     */
+    auto end = start_addr + length;
+    for (auto start = start_addr; start < end; start += TheISA::PageBytes)
+        assert(_pTable->lookup(start) == nullptr);
+
+    /**
+     * Record the region in our list structure.
+     */
+    _vmaList.emplace_back(start_addr, length, sim_fd, offset);
+}
+
+void
+MemState::unmapVMARegion(Addr start_addr, Addr length)
+{
+    Addr end_addr = start_addr + length - 1;
+    const AddrRange range(start_addr, end_addr);
+
+    auto vma = std::begin(_vmaList);
+    while (vma != std::end(_vmaList)) {
+        if (vma->isStrictSuperset(range)) {
+            DPRINTF(SyscallVerbose, "vma: split region [0x%x - 0x%x] into "
+                                    "[0x%x - 0x%x] and [0x%x - 0x%x]\n",
+                                    vma->start(), vma->end(),
+                                    vma->start(), start_addr - 1,
+                                    end_addr + 1, vma->end());
+            /**
+             * Need to split into two smaller regions.
+             * Create a clone of the old VMA and slice it to the right.
+             */
+            _vmaList.push_back(*vma);
+            _vmaList.back().sliceRegionRight(start_addr);
+
+            /**
+             * Slice old VMA to encapsulate the left region.
+             */
+            vma->sliceRegionLeft(end_addr);
+
+            /**
+             * Region cannot be in any more VMA, because it is completely
+             * contained in this one!
+             */
+            break;
+        } else if (vma->isSubset(range)) {
+ DPRINTF(SyscallVerbose, "vma: destroying region [0x%x - 0x%x]\n",
+                                    vma->start(), vma->end());
+            /**
+             * Need to nuke the existing VMA.
+             */
+            vma = _vmaList.erase(vma);
+
+            continue;
+
+        } else if (vma->intersects(range)) {
+            /**
+             * Trim up the existing VMA.
+             */
+            if (vma->start() < start_addr) {
+ DPRINTF(SyscallVerbose, "vma: resizing region [0x%x - 0x%x] "
+                                        "into [0x%x - 0x%x]\n",
+                                        vma->start(), vma->end(),
+                                        vma->start(), start_addr - 1);
+                /**
+                 * Overlaps from the right.
+                 */
+                vma->sliceRegionRight(start_addr);
+            } else {
+ DPRINTF(SyscallVerbose, "vma: resizing region [0x%x - 0x%x] "
+                                        "into [0x%x - 0x%x]\n",
+                                        vma->start(), vma->end(),
+                                        end_addr + 1, vma->end());
+                /**
+                 * Overlaps from the left.
+                 */
+                vma->sliceRegionLeft(end_addr);
+            }
+        }
+
+        vma++;
+    }
+
+    updateTLBs();
+
+    do {
+        if (!_pTable->isUnmapped(start_addr, TheISA::PageBytes))
+            _pTable->unmap(start_addr, TheISA::PageBytes);
+
+        start_addr += TheISA::PageBytes;
+
+        /**
+         * The regions need to always be page-aligned otherwise the while
+         * condition will loop indefinitely. (The Addr type is currently
+         * defined to be uint64_t in src/base/types.hh; it can underflow
+         * since it is unsigned.)
+         */
+        length -= TheISA::PageBytes;
+    } while (length > 0);
+}
+
+void
+MemState::remapVMARegion(Addr start_addr, Addr new_start_addr,
+                         Addr length)
+{
+    Addr end_addr = start_addr + length - 1;
+    const AddrRange range(start_addr, end_addr);
+
+    auto vma = std::begin(_vmaList);
+    while (vma != std::end(_vmaList)) {
+        if (vma->isStrictSuperset(range)) {
+            /**
+             * Create clone of the old VMA and slice right.
+             */
+            _vmaList.push_back(*vma);
+            _vmaList.back().sliceRegionRight(start_addr);
+
+            /**
+             * Create clone of the old VMA and slice it left.
+             */
+            _vmaList.push_back(*vma);
+            _vmaList.back().sliceRegionLeft(end_addr);
+
+            /**
+             * Slice the old VMA left and right to adjust the file backing,
+             * then overwrite the virtual addresses!
+             */
+            vma->sliceRegionLeft(start_addr - 1);
+            vma->sliceRegionRight(end_addr + 1);
+            vma->remap(new_start_addr);
+
+            /**
+             * The region cannot be in any more VMAs, because it is
+             * completely contained in this one!
+             */
+            break;
+        } else if (vma->isSubset(range)) {
+            /**
+             * Just go ahead and remap it!
+             */
+            vma->remap(vma->start() - start_addr + new_start_addr);
+        } else if (vma->intersects(range)) {
+            /**
+             * Create a clone of the old VMA.
+             */
+            _vmaList.push_back(*vma);
+
+            if (vma->start() < start_addr) {
+                /**
+                 * Overlaps from the right.
+                 */
+                _vmaList.back().sliceRegionRight(start_addr);
+
+                /**
+                 * Remap the old region.
+                 */
+                vma->sliceRegionLeft(start_addr - 1);
+                vma->remap(new_start_addr);
+            } else {
+                /**
+                 * Overlaps from the left.
+                 */
+                _vmaList.back().sliceRegionLeft(end_addr);
+
+                /**
+                 * Remap the old region.
+                 */
+                vma->sliceRegionRight(end_addr + 1);
+                vma->remap(new_start_addr + vma->start() - start_addr);
+            }
+        }
+
+        vma++;
+    }
+
+    updateTLBs();
+
+    do {
+        if (!_pTable->isUnmapped(start_addr, TheISA::PageBytes))
+            _pTable->remap(start_addr, TheISA::PageBytes, new_start_addr);
+
+        start_addr += TheISA::PageBytes;
+
+        /**
+         * The regions need to always be page-aligned otherwise the while
+         * condition will loop indefinitely. (The Addr type is currently
+         * defined to be uint64_t in src/base/types.hh; it can underflow
+         * since it is unsigned.)
+         */
+        length -= TheISA::PageBytes;
+    } while (length > 0);
+}
+
+bool
+MemState::translate(Addr va)
+{
+    return (_pTable->translate(va) || fixupFault(va));
+}
+
+bool
+MemState::translate(Addr va, Addr &pa)
+{
+    return (_pTable->translate(va, pa) || (fixupFault(va) &&
+            _pTable->translate(va, pa)));
+}
+
+const EmulationPageTable::Entry*
+MemState::lookup(Addr va)
+{
+    auto entry = _pTable->lookup(va);
+    if (entry == nullptr) {
+        fixupFault(va);
+        entry = _pTable->lookup(va);
+    }
+    return entry;
+}
+
+bool
+MemState::fixupFault(Addr vaddr)
+{
+    /**
+     * Check if we are accessing a mapped virtual address. If so then we
+     * just haven't allocated it a physical page yet and can do so here.
+     */
+    for (const auto &vma : _vmaList) {
+        if (vma.contains(vaddr)) {
+            Addr vpage_start = roundDown(vaddr, TheISA::PageBytes);
+            allocateMem(vpage_start, TheISA::PageBytes);
+
+            /**
+ * We are assuming that fresh pages are zero-filled, so there is
+             * no need to zero them out when there is no backing file.
+             * This assumption will not hold true if/when physical pages
+             * are recycled.
+             */
+            if (vma.hasHostBuf()) {
+                vma.fillMemPages(vpage_start, TheISA::PageBytes, _virtMem);
+            }
+            return true;
+        }
+    }
+    return false;
+}
+
+bool
+MemState::map(Addr vaddr, Addr paddr, int size, bool cacheable)
+{
+    auto flags = cacheable ? EmulationPageTable::MappingFlags(0) :
+                             EmulationPageTable::Uncacheable;
+    _pTable->map(vaddr, paddr, size, flags);
+    return true;
+}
+
+void
+MemState::allocateMem(Addr vaddr, int64_t size, bool clobber)
+{
+    int npages = divCeil(size, (int64_t)TheISA::PageBytes);
+    Addr paddr = system()->allocPhysPages(npages);
+    auto flags = clobber ? EmulationPageTable::Clobber :
+                           EmulationPageTable::MappingFlags(0);
+    _pTable->map(vaddr, paddr, size, flags);
+}
+
+void
+MemState::replicatePage(const MemState &in, Addr vaddr, Addr new_paddr,
+                        bool allocate_page)
+{
+    if (allocate_page)
+        new_paddr = system()->allocPhysPages(1);
+
+    /**
+     * Read from old physical page.
+     */
+    uint8_t *buf_p = new uint8_t[TheISA::PageBytes];
+    in._virtMem.readBlob(vaddr, buf_p, TheISA::PageBytes);
+
+    /**
+     * Create new mapping in process address space by clobbering existing
+     * mapping (if any existed) and then write to the new physical page.
+     */
+    bool clobber = true;
+    _pTable->map(vaddr, new_paddr, TheISA::PageBytes, clobber);
+    _virtMem.writeBlob(vaddr, buf_p, TheISA::PageBytes);
+    delete[] buf_p;
+}
+
+System *
+MemState::system() const
+{
+    /**
+     * Grab the system field from one of our parent processes; we assume
+     * that the processes will all belong to the same system object.
+     */
+    assert(_ownerProcesses.size());
+    return _ownerProcesses[0]->system;
+}
+
+void
+MemState::updateTLBs()
+{
+    /**
+ * FIXME: Flush only the necessary translation look-aside buffer entries.
+     *
+ * The following code results in functionally correct execution, but real
+     * systems do not flush all entries when a single mapping changes since
+     * it tanks performance. The problem is that there is no general method
+     * across all of the implementations which can flush just part of the
+     * address space.
+     */
+    for (auto tc : system()->threadContexts) {
+        tc->getDTBPtr()->flushAll();
+        tc->getITBPtr()->flushAll();
+    }
+}
diff --git a/src/sim/mem_state.hh b/src/sim/mem_state.hh
index ca07a64..a8485c8 100644
--- a/src/sim/mem_state.hh
+++ b/src/sim/mem_state.hh
@@ -31,47 +31,44 @@
 #ifndef SRC_SIM_MEM_STATE_HH
 #define SRC_SIM_MEM_STATE_HH

+#include <sys/mman.h>
+
+#include <list>
+#include <memory>
+#include <vector>
+
+#include "mem/page_table.hh"
+#include "mem/se_translating_port_proxy.hh"
 #include "sim/serialize.hh"

+class Process;
+class ProcessParams;
+class System;
+
 /**
  * This class holds the memory state for the Process class and all of its
  * derived, architecture-specific children.
  *
- * The fields held in this class dynamically change as the process object
- * is run in the simulator. They are updated by system calls and faults;
- * each change represents a modification to the process address space.
- * The stack, heap, and mmap boundaries are held with this class along with
- * the base of the next thread stack.
+ * The class fields change dynamically as the process object is run in the
+ * simulator. They are updated by system calls and faults. Each change
+ * represents a modification to the process address space.
  *
  * The class is meant to be allocated dynamically and shared through a
- * pointer interface because two process can potentially share their virtual
- * address space if certain options are passed into the clone(2).
+ * pointer interface. Multiple process can potentially share their virtual
+ * address space if specific options are passed into the clone(2) system call.
  */
 class MemState : public Serializable
 {
   public:
-    MemState(Addr brk_point, Addr stack_base, Addr max_stack_size,
-             Addr next_thread_stack_base, Addr mmap_end)
-        : _brkPoint(brk_point), _stackBase(stack_base), _stackSize(0),
-          _maxStackSize(max_stack_size), _stackMin(0),
-          _nextThreadStackBase(next_thread_stack_base), _mmapEnd(mmap_end)
-    { }
+    MemState(Process *owner, Addr brk_point, Addr stack_base,
+             Addr max_stack_size, Addr next_thread_stack_base,
+             Addr mmap_end, System *system,
+             std::shared_ptr<EmulationPageTable> p_table);

-    MemState&
-    operator=(const MemState &in)
-    {
-        if (this == &in)
-            return *this;
+    MemState& operator=(const MemState &in);

-        _brkPoint = in._brkPoint;
-        _stackBase = in._stackBase;
-        _stackSize = in._stackSize;
-        _maxStackSize = in._maxStackSize;
-        _stackMin = in._stackMin;
-        _nextThreadStackBase = in._nextThreadStackBase;
-        _mmapEnd = in._mmapEnd;
-        return *this;
-    }
+    void addOwner(Process *owner);
+    void removeOwner(Process *owner);

     Addr getBrkPoint() const { return _brkPoint; }
     Addr getStackBase() const { return _stackBase; }
@@ -80,7 +77,6 @@
     Addr getStackMin() const { return _stackMin; }
     Addr getNextThreadStackBase() const { return _nextThreadStackBase; }
     Addr getMmapEnd() const { return _mmapEnd; }
-
     void setBrkPoint(Addr brk_point) { _brkPoint = brk_point; }
     void setStackBase(Addr stack_base) { _stackBase = stack_base; }
     void setStackSize(Addr stack_size) { _stackSize = stack_size; }
@@ -89,6 +85,91 @@
     void setNextThreadStackBase(Addr ntsb) { _nextThreadStackBase = ntsb; }
     void setMmapEnd(Addr mmap_end) { _mmapEnd = mmap_end; }

+    const SETranslatingPortProxy& getVirtMem() const { return _virtMem; }
+
+    /**
+ * This method returns a flag which specifies the direction of growth for
+     * the mmap region in process address space.
+     *
+     * @return true if the mmap region grows downward and false otherwise
+     */
+    virtual bool mmapGrowsDown() const
+#if THE_ISA == ALPHA_ISA || THE_ISA == RISCV_ISA
+        { return false; }
+#else
+        { return true; }
+#endif
+
+    /**
+     * These methods perform the same behavior as the methods in the
+ * PageTable class with the additional semantic that they will attempt to
+     * allocate physical pages (frames) to resolve faults.
+     * vaddr is valid but the page table does not have an entry yet.
+     */
+    bool translate(Addr va);
+    bool translate(Addr va, Addr &pa);
+    const EmulationPageTable::Entry *lookup(Addr va);
+
+    /**
+     * Maps a contiguous range of virtual addresses in this process's
+     * address space to a contiguous range of physical addresses.
+     * This function exists primarily to expose the map operation to
+ * python, so that configuration scripts can set up mappings in SE mode.
+     *
+     * @param vaddr The starting virtual address of the range.
+     * @param paddr The starting physical address of the range.
+     * @param size The length of the range in bytes.
+     * @param cacheable Specifies whether accesses are cacheable.
+     * @return True if the map operation was successful. (At this point in
+     *         time, the map operation always succeeds.)
+     */
+    bool map(Addr vaddr, Addr paddr, int size, bool cacheable = true);
+
+    /**
+     * Attempt to fix up a fault at vaddr by allocating a page. The fault
+     * likely occurred because a virtual page which does not have physical
+     * page assignment is being accessed.
+     *
+     * @param vaddr The virtual address which is causing the fault.
+     * @return Whether the fault has been fixed.
+     */
+    bool fixupFault(Addr vaddr);
+
+    /**
+     * Given the vaddr and size, this method will chunk the allocation into
+     * page granularity and then request physical pages (frames) from the
+     * system object. After retrieving a frame, the method updates the page
+     * table mappings.
+     *
+     * @param vaddr The virtual address in need of a frame allocation.
+     * @param size The size in bytes of the requested mapping.
+ * @param clobber This flag specifies whether mappings in the page tables
+     *        can be overwritten and replaced with the new mapping.
+     */
+    void allocateMem(Addr vaddr, int64_t size, bool clobber = false);
+
+    /**
+     * The _pTable member is either an architectural page table object or a
+ * functional page table object. Both implementations share the same API
+     * and can be accessed through this base class object.
+     */
+    std::shared_ptr<EmulationPageTable> _pTable;
+
+    /**
+ * This port proxy provides a handle to access the process address space
+     * (represented by this object). In SE Mode, all references to the
+     * process address space (using virtual addresses) should be directed
+     * through this proxy.
+     *
+     * Creating duplicates or storing copies of this proxy in other
+     * objects is frowned upon; please do not do it! Note, the proxy is
+     * owned by this object and will become obsolete if this object
+     * deconstructs. (This will happen if all processes release their hold
+     * on this object; this is particularly an issue when calling the exec
+     * system call.)
+     */
+    const SETranslatingPortProxy& getVirtProxy() { return _virtMem; }
+
     void
     serialize(CheckpointOut &cp) const override
     {
@@ -113,6 +194,22 @@
     }

   private:
+    void replicatePage(const MemState &in, Addr vaddr, Addr new_paddr,
+                       bool alloc_page);
+
+    void updateTLBs();
+
+    System * system() const;
+
+    void checkAlign(Addr start, Addr length);
+
+    /**
+     * Holds the list of Process objects which have a reference to this
+ * MemState object. The owner Processes act as parents in an object tree
+     * for MemState.
+     */
+    std::vector<Process*> _ownerProcesses;
+
     Addr _brkPoint;
     Addr _stackBase;
     Addr _stackSize;
@@ -120,6 +217,18 @@
     Addr _stackMin;
     Addr _nextThreadStackBase;
     Addr _mmapEnd;
+
+    /**
+     * Keeps record of the furthest mapped heap location for the VMAs.
+     */
+    Addr _endBrkPoint;
+
+    /**
+ * The _virtMem member acts as a proxy for accessing virtual memory. This + * handle is responsible for reading and writing blobs and strings both to
+     * and from the virtual memory space for Process objects.
+     */
+    SETranslatingPortProxy _virtMem;
 };

 #endif
diff --git a/src/sim/process_impl.hh b/src/sim/mem_state_impl.hh
similarity index 82%
rename from src/sim/process_impl.hh
rename to src/sim/mem_state_impl.hh
index 3f3d6ae..b3c59e2 100644
--- a/src/sim/process_impl.hh
+++ b/src/sim/mem_state_impl.hh
@@ -1,5 +1,6 @@
 /*
  * Copyright (c) 2001-2005 The Regents of The University of Michigan
+ * Copyright (c) 2017 Advanced Micro Devices, Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -27,10 +28,12 @@
  *
  * Authors: Nathan Binkert
  *          Steve Reinhardt
+ *          Brandon Potter
  */

-#ifndef __SIM_PROCESS_IMPL_HH__
-#define __SIM_PROCESS_IMPL_HH__
+
+#ifndef __SIM_MEM_STATE_IMPL_HH__
+#define __SIM_MEM_STATE_IMPL_HH__

 #include <string>
 #include <vector>
@@ -41,22 +44,22 @@
 template<class AddrType>
 void
 copyStringArray(std::vector<std::string> &strings,
-        AddrType array_ptr, AddrType data_ptr,
-        SETranslatingPortProxy& memProxy)
+                AddrType array_ptr, AddrType data_ptr,
+                const SETranslatingPortProxy& mem_proxy)
 {
     AddrType data_ptr_swap;
for (std::vector<std::string>::size_type i = 0; i < strings.size(); ++i) {
         data_ptr_swap = TheISA::htog(data_ptr);
-        memProxy.writeBlob(array_ptr, (uint8_t*)&data_ptr_swap,
+        mem_proxy.writeBlob(array_ptr, (uint8_t*)&data_ptr_swap,
                 sizeof(AddrType));
-        memProxy.writeString(data_ptr, strings[i].c_str());
+        mem_proxy.writeString(data_ptr, strings[i].c_str());
         array_ptr += sizeof(AddrType);
         data_ptr += strings[i].size() + 1;
     }
     // add NULL terminator
     data_ptr = 0;

-    memProxy.writeBlob(array_ptr, (uint8_t*)&data_ptr, sizeof(AddrType));
+    mem_proxy.writeBlob(array_ptr, (uint8_t*)&data_ptr, sizeof(AddrType));
 }

 #endif
diff --git a/src/sim/process.cc b/src/sim/process.cc
index 5a4f3d5..3a3f66a 100644
--- a/src/sim/process.cc
+++ b/src/sim/process.cc
@@ -63,7 +63,6 @@
 #include "base/statistics.hh"
 #include "config/the_isa.hh"
 #include "cpu/thread_context.hh"
-#include "mem/page_table.hh"
 #include "params/Process.hh"
 #include "sim/emul_driver.hh"
 #include "sim/fd_array.hh"
@@ -103,12 +102,9 @@
 using namespace std;
 using namespace TheISA;

-Process::Process(ProcessParams *params, EmulationPageTable *pTable,
-                 ObjectFile *obj_file)
+Process::Process(ProcessParams *params, ObjectFile *obj_file)
     : SimObject(params), system(params->system),
-      useArchPT(params->useArchPT),
       kvmInSE(params->kvmInSE),
-      pTable(pTable),
       objFile(obj_file),
       argv(params->cmd), envp(params->env),
       host_cwd(checkPathRedirect(params->cwd)), tgt_cwd(params->cwd),
@@ -118,7 +114,8 @@
       _pid(params->pid), _ppid(params->ppid),
       _pgid(params->pgid), drivers(params->drivers),
fds(make_shared<FDArray>(params->input, params->output, params->errout)),
-      childClearTID(0)
+      childClearTID(0),
+      _params(params)
 {
     if (_pid >= System::maxPID)
         fatal("_pid is too large: %d", _pid);
@@ -174,26 +171,9 @@
          * and the old process. Changes in one will be visible in the other
          * due to the pointer use.
          */
-        delete np->pTable;
-        np->pTable = pTable;
-        ntc->getMemProxy().setPageTable(np->pTable);
-
         np->memState = memState;
+        memState->addOwner(np);
     } else {
-        /**
- * Duplicate the process memory address space. The state needs to be
-         * copied over (rather than using pointers to share everything).
-         */
-        typedef std::vector<pair<Addr,Addr>> MapVec;
-        MapVec mappings;
-        pTable->getMappings(&mappings);
-
-        for (auto map : mappings) {
-            Addr paddr, vaddr = map.first;
-            bool alloc_page = !(np->pTable->translate(vaddr, paddr));
-            np->replicatePage(vaddr, paddr, otc, ntc, alloc_page);
-        }
-
         *np->memState = *memState;
     }

@@ -294,8 +274,6 @@

     // mark this context as active so it will start ticking.
     tc->activate();
-
-    pTable->initState(tc);
 }

 DrainState
@@ -306,76 +284,17 @@
 }

 void
-Process::allocateMem(Addr vaddr, int64_t size, bool clobber)
-{
-    int npages = divCeil(size, (int64_t)PageBytes);
-    Addr paddr = system->allocPhysPages(npages);
-    pTable->map(vaddr, paddr, size,
-                clobber ? EmulationPageTable::Clobber :
-                          EmulationPageTable::MappingFlags(0));
-}
-
-void
-Process::replicatePage(Addr vaddr, Addr new_paddr, ThreadContext *old_tc,
-                       ThreadContext *new_tc, bool allocate_page)
-{
-    if (allocate_page)
-        new_paddr = system->allocPhysPages(1);
-
-    // Read from old physical page.
-    uint8_t *buf_p = new uint8_t[PageBytes];
-    old_tc->getMemProxy().readBlob(vaddr, buf_p, PageBytes);
-
-    // Create new mapping in process address space by clobbering existing
-    // mapping (if any existed) and then write to the new physical page.
-    bool clobber = true;
-    pTable->map(vaddr, new_paddr, PageBytes, clobber);
-    new_tc->getMemProxy().writeBlob(vaddr, buf_p, PageBytes);
-    delete[] buf_p;
-}
-
-bool
-Process::fixupStackFault(Addr vaddr)
-{
-    Addr stack_min = memState->getStackMin();
-    Addr stack_base = memState->getStackBase();
-    Addr max_stack_size = memState->getMaxStackSize();
-
-    // Check if this is already on the stack and there's just no page there
-    // yet.
-    if (vaddr >= stack_min && vaddr < stack_base) {
-        allocateMem(roundDown(vaddr, PageBytes), PageBytes);
-        return true;
-    }
-
-    // We've accessed the next page of the stack, so extend it to include
-    // this address.
-    if (vaddr < stack_min && vaddr >= stack_base - max_stack_size) {
-        while (vaddr < stack_min) {
-            stack_min -= TheISA::PageBytes;
-            if (stack_base - stack_min > max_stack_size)
-                fatal("Maximum stack size exceeded\n");
-            allocateMem(stack_min, TheISA::PageBytes);
-            inform("Increasing stack size by one page.");
-        }
-        memState->setStackMin(stack_min);
-        return true;
-    }
-    return false;
-}
-
-void
 Process::serialize(CheckpointOut &cp) const
 {
-    memState->serialize(cp);
-    pTable->serialize(cp);
+    warn("Checkpoints in SE mode currently do not work.");
     /**
      * Checkpoints for file descriptors currently do not work. Need to
      * come back and fix them at a later date.
      */

-    warn("Checkpoints for file descriptors currently do not work.");
 #if 0
+    memState->serialize(cp);
+     pTable->serialize(cp);
     for (int x = 0; x < fds->getSize(); x++)
         (*fds)[x].serializeSection(cp, csprintf("FDEntry%d", x));
 #endif
@@ -385,14 +304,10 @@
 void
 Process::unserialize(CheckpointIn &cp)
 {
+    warn("Checkpoints in SE mode currently do not work.");
+#if 0
     memState->unserialize(cp);
     pTable->unserialize(cp);
-    /**
-     * Checkpoints for file descriptors currently do not work. Need to
-     * come back and fix them at a later date.
-     */
-    warn("Checkpoints for file descriptors currently do not work.");
-#if 0
     for (int x = 0; x < fds->getSize(); x++)
         (*fds)[x]->unserializeSection(cp, csprintf("FDEntry%d", x));
     fds->restoreFileOffsets();
@@ -403,15 +318,6 @@
     // found.
 }

-bool
-Process::map(Addr vaddr, Addr paddr, int size, bool cacheable)
-{
-    pTable->map(vaddr, paddr, size,
-                cacheable ? EmulationPageTable::MappingFlags(0) :
-                            EmulationPageTable::Uncacheable);
-    return true;
-}
-
 void
 Process::syscall(int64_t callnum, ThreadContext *tc, Fault *fault)
 {
@@ -503,12 +409,13 @@
// We are allocating the memory area; set the bias to the lowest address
     // in the allocated memory region.
     Addr mmap_end = memState->getMmapEnd();
-    Addr ld_bias = mmapGrowsDown() ? mmap_end - interp_mapsize : mmap_end;
+    Addr ld_bias = memState->mmapGrowsDown() ?
+                   mmap_end - interp_mapsize : mmap_end;

     // Adjust the process mmap area to give the interpreter room; the real
     // execve system call would just invoke the kernel's internal mmap
     // functions to make these adjustments.
-    mmap_end = mmapGrowsDown() ? ld_bias : mmap_end + interp_mapsize;
+ mmap_end = memState->mmapGrowsDown() ? ld_bias : mmap_end + interp_mapsize;
     memState->setMmapEnd(mmap_end);

     interp->updateBias(ld_bias);
diff --git a/src/sim/process.hh b/src/sim/process.hh
index a888b1b..35d1c31 100644
--- a/src/sim/process.hh
+++ b/src/sim/process.hh
@@ -36,7 +36,6 @@

 #include <inttypes.h>

-#include <map>
 #include <string>
 #include <vector>

@@ -62,8 +61,7 @@
 class Process : public SimObject
 {
   public:
-    Process(ProcessParams *params, EmulationPageTable *pTable,
-            ObjectFile *obj_file);
+    Process(ProcessParams *params, ObjectFile *obj_file);

     void serialize(CheckpointOut &cp) const override;
     void unserialize(CheckpointIn &cp) override;
@@ -123,12 +121,6 @@
     // override of virtual SimObject method: register statistics
     void regStats() override;

-    void allocateMem(Addr vaddr, int64_t size, bool clobber = false);
-
- /// Attempt to fix up a fault at vaddr by allocating a page on the stack.
-    /// @return Whether the fault has been fixed.
-    bool fixupStackFault(Addr vaddr);
-
     // After getting registered with system object, tell process which
     // system-wide context id it is assigned.
     void
@@ -146,30 +138,10 @@
      */
     void revokeThreadContext(int context_id);

-    /**
-     * Does mmap region grow upward or downward from mmapEnd?  Most
-     * platforms grow downward, but a few (such as Alpha) grow upward
-     * instead, so they can override this method to return false.
-     */
-    virtual bool mmapGrowsDown() const { return true; }
-
-    /**
-     * Maps a contiguous range of virtual addresses in this process's
-     * address space to a contiguous range of physical addresses.
-     * This function exists primarily to expose the map operation to
- * python, so that configuration scripts can set up mappings in SE mode.
-     *
-     * @param vaddr The starting virtual address of the range.
-     * @param paddr The starting physical address of the range.
-     * @param size The length of the range in bytes.
-     * @param cacheable Specifies whether accesses are cacheable.
-     * @return True if the map operation was successful.  (At this
-     *           point in time, the map operation always succeeds.)
-     */
-    bool map(Addr vaddr, Addr paddr, int size, bool cacheable = true);
-
-    void replicatePage(Addr vaddr, Addr new_paddr, ThreadContext *old_tc,
-                       ThreadContext *new_tc, bool alloc_page);
+    bool map(Addr vaddr, Addr paddr, int size, bool cacheable = true)
+    {
+        return memState->map(vaddr, paddr, size, cacheable);
+    };

     virtual void clone(ThreadContext *old_tc, ThreadContext *new_tc,
                        Process *new_p, TheISA::IntReg flags);
@@ -182,11 +154,8 @@

     Stats::Scalar numSyscalls;  // track how many system calls are executed

-    bool useArchPT; // flag for using architecture specific page table
     bool kvmInSE;   // running KVM requires special initialization

-    EmulationPageTable *pTable;
-
     ObjectFile *objFile;
     std::vector<std::string> argv;
     std::vector<std::string> envp;
@@ -212,7 +181,6 @@
     std::shared_ptr<FDArray> fds;

     bool *exitGroup;
-    std::shared_ptr<MemState> memState;

     /**
      * Calls a futex wakeup at the address specified by this pointer when
@@ -222,6 +190,10 @@

     // Process was forked with SIGCHLD set.
     bool *sigchld;
+
+    ProcessParams *_params;
+
+    std::shared_ptr<MemState> memState;
 };

 #endif // __PROCESS_HH__
diff --git a/src/sim/syscall_emul.hh b/src/sim/syscall_emul.hh
index 41c0c51..dfc6ac0 100644
--- a/src/sim/syscall_emul.hh
+++ b/src/sim/syscall_emul.hh
@@ -1477,6 +1477,10 @@
         ptidBuf.copyOut(parent_virt_mem);
     }

+    auto child_mem_state = cp->memState;
+    if (flags & OS::TGT_CLONE_THREAD) {
+        auto child_p_table = child_mem_state->_pTable;
+    }
     cp->initState();
     p->clone(tc, ctc, cp, flags);


--
To view, visit https://gem5-review.googlesource.com/c/public/gem5/+/12306
To unsubscribe, or for help writing mail filters, visit https://gem5-review.googlesource.com/settings

Gerrit-Project: public/gem5
Gerrit-Branch: master
Gerrit-Change-Id: I5e6afecbd47e9c46998c4d6a1091d1f4fb698a71
Gerrit-Change-Number: 12306
Gerrit-PatchSet: 1
Gerrit-Owner: Brandon Potter <[email protected]>
Gerrit-MessageType: newchange
_______________________________________________
gem5-dev mailing list
[email protected]
http://m5sim.org/mailman/listinfo/gem5-dev

Reply via email to