mem-cache: Add multiple eviction stats
[gem5.git] / src / arch / x86 / process.cc
index 5a00ce78c1841ee50e88327e5f7e3787daea81c5..f270b2d8f258c0ca645b65e580ec20ed272d8639 100644 (file)
  *          Ali Saidi
  */
 
+#include "arch/x86/process.hh"
+
+#include <string>
+#include <vector>
+
+#include "arch/x86/isa_traits.hh"
 #include "arch/x86/regs/misc.hh"
 #include "arch/x86/regs/segment.hh"
-#include "arch/x86/isa_traits.hh"
-#include "arch/x86/process.hh"
 #include "arch/x86/system.hh"
 #include "arch/x86/types.hh"
 #include "base/loader/elf_object.hh"
 #include "base/loader/object_file.hh"
-#include "base/misc.hh"
+#include "base/logging.hh"
 #include "base/trace.hh"
 #include "cpu/thread_context.hh"
 #include "debug/Stack.hh"
 #include "mem/multi_level_page_table.hh"
 #include "mem/page_table.hh"
+#include "params/Process.hh"
+#include "sim/aux_vector.hh"
 #include "sim/process_impl.hh"
-#include "sim/syscall_emul.hh"
+#include "sim/syscall_desc.hh"
+#include "sim/syscall_return.hh"
 #include "sim/system.hh"
 
 using namespace std;
@@ -67,35 +74,61 @@ static const int ArgumentReg[] = {
     INTREG_RDI,
     INTREG_RSI,
     INTREG_RDX,
-    //This argument register is r10 for syscalls and rcx for C.
+    // This argument register is r10 for syscalls and rcx for C.
     INTREG_R10W,
-    //INTREG_RCX,
+    // INTREG_RCX,
     INTREG_R8W,
     INTREG_R9W
 };
-static const int NumArgumentRegs = sizeof(ArgumentReg) / sizeof(const int);
+
+static const int NumArgumentRegs M5_VAR_USED =
+    sizeof(ArgumentReg) / sizeof(const int);
+
 static const int ArgumentReg32[] = {
     INTREG_EBX,
     INTREG_ECX,
     INTREG_EDX,
     INTREG_ESI,
     INTREG_EDI,
+    INTREG_EBP
 };
-static const int NumArgumentRegs32 = sizeof(ArgumentReg) / sizeof(const int);
 
-X86LiveProcess::X86LiveProcess(LiveProcessParams * params, ObjectFile *objFile,
-        SyscallDesc *_syscallDescs, int _numSyscallDescs) :
-    LiveProcess(params, objFile), syscallDescs(_syscallDescs),
-    numSyscallDescs(_numSyscallDescs)
+static const int NumArgumentRegs32 M5_VAR_USED =
+    sizeof(ArgumentReg) / sizeof(const int);
+
+template class MultiLevelPageTable<LongModePTE<47, 39>,
+                                   LongModePTE<38, 30>,
+                                   LongModePTE<29, 21>,
+                                   LongModePTE<20, 12> >;
+typedef MultiLevelPageTable<LongModePTE<47, 39>,
+                            LongModePTE<38, 30>,
+                            LongModePTE<29, 21>,
+                            LongModePTE<20, 12> > ArchPageTable;
+
+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)
 {
-    brk_point = objFile->dataBase() + objFile->dataSize() + objFile->bssSize();
-    brk_point = roundUp(brk_point, PageBytes);
 }
 
-X86_64LiveProcess::X86_64LiveProcess(LiveProcessParams *params,
-        ObjectFile *objFile, SyscallDesc *_syscallDescs,
-        int _numSyscallDescs) :
-    X86LiveProcess(params, objFile, _syscallDescs, _numSyscallDescs)
+void X86Process::clone(ThreadContext *old_tc, ThreadContext *new_tc,
+                       Process *p, RegVal flags)
+{
+    Process::clone(old_tc, new_tc, p, flags);
+    X86Process *process = (X86Process*)p;
+    *process = *this;
+}
+
+X86_64Process::X86_64Process(ProcessParams *params, ObjectFile *objFile,
+                             SyscallDesc *_syscallDescs, int _numSyscallDescs)
+    : X86Process(params, objFile, _syscallDescs, _numSyscallDescs)
 {
 
     vsyscallPage.base = 0xffffffffff600000ULL;
@@ -103,38 +136,24 @@ X86_64LiveProcess::X86_64LiveProcess(LiveProcessParams *params,
     vsyscallPage.vtimeOffset = 0x400;
     vsyscallPage.vgettimeofdayOffset = 0x0;
 
-    // Set up stack. On X86_64 Linux, stack goes from the top of memory
-    // downward, less the hole for the kernel address space plus one page
-    // for undertermined purposes.
-    stack_base = (Addr)0x7FFFFFFFF000ULL;
-
-    // Set pointer for next thread stack.  Reserve 8M for main stack.
-    next_thread_stack_base = stack_base - (8 * 1024 * 1024);
-
-    // Set up region for mmaps. This was determined empirically and may not
-    // always be correct.
-    mmap_start = mmap_end = (Addr)0x2aaaaaaab000ULL;
-}
+    Addr brk_point = roundUp(image.maxAddr(), PageBytes);
+    Addr stack_base = 0x7FFFFFFFF000ULL;
+    Addr max_stack_size = 8 * 1024 * 1024;
+    Addr next_thread_stack_base = stack_base - max_stack_size;
+    Addr mmap_end = 0x7FFFF7FFF000ULL;
 
-void
-I386LiveProcess::syscall(int64_t callnum, ThreadContext *tc)
-{
-    TheISA::PCState pc = tc->pcState();
-    Addr eip = pc.pc();
-    if (eip >= vsyscallPage.base &&
-            eip < vsyscallPage.base + vsyscallPage.size) {
-        pc.npc(vsyscallPage.base + vsyscallPage.vsysexitOffset);
-        tc->pcState(pc);
-    }
-    X86LiveProcess::syscall(callnum, tc);
+    memState = make_shared<MemState>(brk_point, stack_base, max_stack_size,
+                                     next_thread_stack_base, mmap_end);
 }
 
 
-I386LiveProcess::I386LiveProcess(LiveProcessParams *params,
-        ObjectFile *objFile, SyscallDesc *_syscallDescs,
-        int _numSyscallDescs) :
-    X86LiveProcess(params, objFile, _syscallDescs, _numSyscallDescs)
+I386Process::I386Process(ProcessParams *params, ObjectFile *objFile,
+                         SyscallDesc *_syscallDescs, int _numSyscallDescs)
+    : X86Process(params, objFile, _syscallDescs, _numSyscallDescs)
 {
+    if (kvmInSE)
+        panic("KVM CPU model does not support 32 bit processes");
+
     _gdtStart = ULL(0xffffd000);
     _gdtSize = PageBytes;
 
@@ -143,18 +162,18 @@ I386LiveProcess::I386LiveProcess(LiveProcessParams *params,
     vsyscallPage.vsyscallOffset = 0x400;
     vsyscallPage.vsysexitOffset = 0x410;
 
-    stack_base = _gdtStart;
-
-    // Set pointer for next thread stack.  Reserve 8M for main stack.
-    next_thread_stack_base = stack_base - (8 * 1024 * 1024);
+    Addr brk_point = roundUp(image.maxAddr(), PageBytes);
+    Addr stack_base = _gdtStart;
+    Addr max_stack_size = 8 * 1024 * 1024;
+    Addr next_thread_stack_base = stack_base - max_stack_size;
+    Addr mmap_end = 0xB7FFF000ULL;
 
-    // Set up region for mmaps. This was determined empirically and may not
-    // always be correct.
-    mmap_start = mmap_end = (Addr)0xf7ffe000ULL;
+    memState = make_shared<MemState>(brk_point, stack_base, max_stack_size,
+                                     next_thread_stack_base, mmap_end);
 }
 
 SyscallDesc*
-X86LiveProcess::getDesc(int callnum)
+X86Process::getDesc(int callnum)
 {
     if (callnum < 0 || callnum >= numSyscallDescs)
         return NULL;
@@ -162,13 +181,16 @@ X86LiveProcess::getDesc(int callnum)
 }
 
 void
-X86_64LiveProcess::initState()
+X86_64Process::initState()
 {
-    X86LiveProcess::initState();
+    X86Process::initState();
+
+    if (useForClone)
+        return;
 
-    argsInit(sizeof(uint64_t), PageBytes);
+    argsInit(PageBytes);
 
-       // Set up the vsyscall page for this process.
+    // Set up the vsyscall page for this process.
     allocateMem(vsyscallPage.base, vsyscallPage.size);
     uint8_t vtimeBlob[] = {
         0x48,0xc7,0xc0,0xc9,0x00,0x00,0x00,    // mov    $0xc9,%rax
@@ -189,13 +211,20 @@ X86_64LiveProcess::initState()
     if (kvmInSE) {
         PortProxy physProxy = system->physProxy;
 
+        Addr syscallCodePhysAddr = system->allocPhysPages(1);
+        Addr gdtPhysAddr = system->allocPhysPages(1);
+        Addr idtPhysAddr = system->allocPhysPages(1);
+        Addr istPhysAddr = system->allocPhysPages(1);
+        Addr tssPhysAddr = system->allocPhysPages(1);
+        Addr pfHandlerPhysAddr = system->allocPhysPages(1);
+
         /*
          * Set up the gdt.
          */
         uint8_t numGDTEntries = 0;
         uint64_t nullDescriptor = 0;
-        physProxy.writeBlob(GDTPhysAddr + numGDTEntries * 8,
-                            (uint8_t *)(&nullDescriptor), 8);
+        physProxy.writeBlob(gdtPhysAddr + numGDTEntries * 8,
+                            &nullDescriptor, 8);
         numGDTEntries++;
 
         SegDescriptor initDesc = 0;
@@ -206,20 +235,18 @@ X86_64LiveProcess::initState()
         initDesc.p = 1;               // present
         initDesc.l = 1;               // longmode - 64 bit
         initDesc.d = 0;               // operand size
-        initDesc.g = 1;               // granularity
+        initDesc.g = 1;
         initDesc.s = 1;               // system segment
-        initDesc.limitHigh = 0xFFFF;
-        initDesc.limitLow = 0xF;
-        initDesc.baseHigh = 0x0;
-        initDesc.baseLow = 0x0;
+        initDesc.limit = 0xFFFFFFFF;
+        initDesc.base = 0;
 
         //64 bit code segment
         SegDescriptor csLowPLDesc = initDesc;
         csLowPLDesc.type.codeOrData = 1;
         csLowPLDesc.dpl = 0;
         uint64_t csLowPLDescVal = csLowPLDesc;
-        physProxy.writeBlob(GDTPhysAddr + numGDTEntries * 8,
-                            (uint8_t *)(&csLowPLDescVal), 8);
+        physProxy.writeBlob(gdtPhysAddr + numGDTEntries * 8,
+                            &csLowPLDescVal, 8);
 
         numGDTEntries++;
 
@@ -232,8 +259,8 @@ X86_64LiveProcess::initState()
         dsLowPLDesc.type.codeOrData = 0;
         dsLowPLDesc.dpl = 0;
         uint64_t dsLowPLDescVal = dsLowPLDesc;
-        physProxy.writeBlob(GDTPhysAddr + numGDTEntries * 8,
-                            (uint8_t *)(&dsLowPLDescVal), 8);
+        physProxy.writeBlob(gdtPhysAddr + numGDTEntries * 8,
+                            &dsLowPLDescVal, 8);
 
         numGDTEntries++;
 
@@ -246,8 +273,8 @@ X86_64LiveProcess::initState()
         dsDesc.type.codeOrData = 0;
         dsDesc.dpl = 3;
         uint64_t dsDescVal = dsDesc;
-        physProxy.writeBlob(GDTPhysAddr + numGDTEntries * 8,
-                            (uint8_t *)(&dsDescVal), 8);
+        physProxy.writeBlob(gdtPhysAddr + numGDTEntries * 8,
+                            &dsDescVal, 8);
 
         numGDTEntries++;
 
@@ -260,8 +287,8 @@ X86_64LiveProcess::initState()
         csDesc.type.codeOrData = 1;
         csDesc.dpl = 3;
         uint64_t csDescVal = csDesc;
-        physProxy.writeBlob(GDTPhysAddr + numGDTEntries * 8,
-                            (uint8_t *)(&csDescVal), 8);
+        physProxy.writeBlob(gdtPhysAddr + numGDTEntries * 8,
+                            &csDescVal, 8);
 
         numGDTEntries++;
 
@@ -282,11 +309,8 @@ X86_64LiveProcess::initState()
         TSSDescLow.type = 0xB;
         TSSDescLow.dpl = 0; // Privelege level 0
         TSSDescLow.p = 1; // Present
-        TSSDescLow.g = 1; // Page granularity
-        TSSDescLow.limitHigh = 0xF;
-        TSSDescLow.limitLow = 0xFFFF;
-        TSSDescLow.baseLow = bits(TSSVirtAddr, 23, 0);
-        TSSDescLow.baseHigh = bits(TSSVirtAddr, 31, 24);
+        TSSDescLow.limit = 0xFFFFFFFF;
+        TSSDescLow.base = bits(TSSVirtAddr, 31, 0);
 
         TSShigh TSSDescHigh = 0;
         TSSDescHigh.base = bits(TSSVirtAddr, 63, 32);
@@ -296,18 +320,16 @@ X86_64LiveProcess::initState()
             uint64_t high;
         } tssDescVal = {TSSDescLow, TSSDescHigh};
 
-        physProxy.writeBlob(GDTPhysAddr + numGDTEntries * 8,
-                            (uint8_t *)(&tssDescVal), sizeof(tssDescVal));
+        physProxy.writeBlob(gdtPhysAddr + numGDTEntries * 8,
+                            &tssDescVal, sizeof(tssDescVal));
 
         numGDTEntries++;
 
         SegSelector tssSel = 0;
         tssSel.si = numGDTEntries - 1;
 
-        uint64_t tss_base_addr = (TSSDescHigh.base << 32) |
-                                 (TSSDescLow.baseHigh << 24) |
-                                  TSSDescLow.baseLow;
-        uint64_t tss_limit = TSSDescLow.limitLow | (TSSDescLow.limitHigh << 16);
+        uint64_t tss_base_addr = (TSSDescHigh.base << 32) | TSSDescLow.base;
+        uint64_t tss_limit = TSSDescLow.limit;
 
         SegAttr tss_attr = 0;
 
@@ -355,8 +377,8 @@ X86_64LiveProcess::initState()
             efer.sce = 1; // Enable system call extensions.
             efer.lme = 1; // Enable long mode.
             efer.lma = 1; // Activate long mode.
-            efer.nxe = 0; // Enable nx support.
-            efer.svme = 1; // Enable svm support for now.
+            efer.nxe = 1; // Enable nx support.
+            efer.svme = 0; // Enable svm support for now.
             efer.ffxsr = 0; // Turn on fast fxsave and fxrstor.
             tc->setMiscReg(MISCREG_EFER, efer);
 
@@ -380,13 +402,13 @@ X86_64LiveProcess::initState()
             CR0 cr2 = 0;
             tc->setMiscReg(MISCREG_CR2, cr2);
 
-            CR3 cr3 = pageTablePhysAddr;
+            CR3 cr3 = dynamic_cast<ArchPageTable *>(pTable)->basePtr();
             tc->setMiscReg(MISCREG_CR3, cr3);
 
             CR4 cr4 = 0;
             //Turn on pae.
-            cr4.osxsave = 1; // Enable XSAVE and Proc Extended States
-            cr4.osxmmexcpt = 1; // Operating System Unmasked Exception
+            cr4.osxsave = 0; // Enable XSAVE and Proc Extended States
+            cr4.osxmmexcpt = 0; // Operating System Unmasked Exception
             cr4.osfxsr = 1; // Operating System FXSave/FSRSTOR Support
             cr4.pce = 0; // Performance-Monitoring Counter Enable
             cr4.pge = 0; // Page-Global Enable
@@ -403,10 +425,6 @@ X86_64LiveProcess::initState()
             CR4 cr8 = 0;
             tc->setMiscReg(MISCREG_CR8, cr8);
 
-            const Addr PageMapLevel4 = pageTablePhysAddr;
-            //Point to the page tables.
-            tc->setMiscReg(MISCREG_CR3, PageMapLevel4);
-
             tc->setMiscReg(MISCREG_MXCSR, 0x1f80);
 
             tc->setMiscReg(MISCREG_APIC_BASE, 0xfee00900);
@@ -418,11 +436,11 @@ X86_64LiveProcess::initState()
             tc->setMiscReg(MISCREG_IDTR_LIMIT, 0xffff);
 
             /* enabling syscall and sysret */
-            MiscReg star = ((MiscReg)sret << 48) | ((MiscReg)scall << 32);
+            RegVal star = ((RegVal)sret << 48) | ((RegVal)scall << 32);
             tc->setMiscReg(MISCREG_STAR, star);
-            MiscReg lstar = (MiscReg)syscallCodeVirtAddr;
+            RegVal lstar = (RegVal)syscallCodeVirtAddr;
             tc->setMiscReg(MISCREG_LSTAR, lstar);
-            MiscReg sfmask = (1 << 8) | (1 << 10); // TF | DF
+            RegVal sfmask = (1 << 8) | (1 << 10); // TF | DF
             tc->setMiscReg(MISCREG_SF_MASK, sfmask);
         }
 
@@ -468,7 +486,7 @@ X86_64LiveProcess::initState()
         tss.RSP1_high = tss.IST1_high;
         tss.RSP2_low  = tss.IST1_low;
         tss.RSP2_high = tss.IST1_high;
-        physProxy.writeBlob(TSSPhysAddr, (uint8_t *)(&tss), sizeof(tss));
+        physProxy.writeBlob(tssPhysAddr, &tss, sizeof(tss));
 
         /* Setting IDT gates */
         GateDescriptorLow PFGateLow = 0;
@@ -488,8 +506,7 @@ X86_64LiveProcess::initState()
             uint64_t high;
         } PFGate = {PFGateLow, PFGateHigh};
 
-        physProxy.writeBlob(IDTPhysAddr + 0xE0,
-                            (uint8_t *)(&PFGate), sizeof(PFGate));
+        physProxy.writeBlob(idtPhysAddr + 0xE0, &PFGate, sizeof(PFGate));
 
         /* System call handler */
         uint8_t syscallBlob[] = {
@@ -514,25 +531,24 @@ X86_64LiveProcess::initState()
             0x48, 0xcf
         };
 
-        physProxy.writeBlob(PFHandlerPhysAddr, faultBlob, sizeof(faultBlob));
-
-        MultiLevelPageTable<PageTableOps> *pt =
-            dynamic_cast<MultiLevelPageTable<PageTableOps> *>(pTable);
+        physProxy.writeBlob(pfHandlerPhysAddr, faultBlob, sizeof(faultBlob));
 
         /* Syscall handler */
-        pt->map(syscallCodeVirtAddr, syscallCodePhysAddr, PageBytes, false);
+        pTable->map(syscallCodeVirtAddr, syscallCodePhysAddr,
+                    PageBytes, false);
         /* GDT */
-        pt->map(GDTVirtAddr, GDTPhysAddr, PageBytes, false);
+        pTable->map(GDTVirtAddr, gdtPhysAddr, PageBytes, false);
         /* IDT */
-        pt->map(IDTVirtAddr, IDTPhysAddr, PageBytes, false);
+        pTable->map(IDTVirtAddr, idtPhysAddr, PageBytes, false);
         /* TSS */
-        pt->map(TSSVirtAddr, TSSPhysAddr, PageBytes, false);
+        pTable->map(TSSVirtAddr, tssPhysAddr, PageBytes, false);
         /* IST */
-        pt->map(ISTVirtAddr, ISTPhysAddr, PageBytes, false);
+        pTable->map(ISTVirtAddr, istPhysAddr, PageBytes, false);
         /* PF handler */
-        pt->map(PFHandlerVirtAddr, PFHandlerPhysAddr, PageBytes, false);
+        pTable->map(PFHandlerVirtAddr, pfHandlerPhysAddr, PageBytes, false);
         /* MMIO region for m5ops */
-        pt->map(MMIORegionVirtAddr, MMIORegionPhysAddr, 16*PageBytes, false);
+        pTable->map(MMIORegionVirtAddr, MMIORegionPhysAddr,
+                    16 * PageBytes, false);
     } else {
         for (int i = 0; i < contextIds.size(); i++) {
             ThreadContext * tc = system->getThreadContext(contextIds[i]);
@@ -551,8 +567,8 @@ X86_64LiveProcess::initState()
             dataAttr.expandDown = 0;
             dataAttr.system = 1;
 
-            //Initialize the segment registers.
-            for(int seg = 0; seg < NUM_SEGMENTREGS; seg++) {
+            // Initialize the segment registers.
+            for (int seg = 0; seg < NUM_SEGMENTREGS; seg++) {
                 tc->setMiscRegNoEffect(MISCREG_SEG_BASE(seg), 0);
                 tc->setMiscRegNoEffect(MISCREG_SEG_EFF_BASE(seg), 0);
                 tc->setMiscRegNoEffect(MISCREG_SEG_ATTR(seg), dataAttr);
@@ -583,7 +599,7 @@ X86_64LiveProcess::initState()
             efer.ffxsr = 1; // Turn on fast fxsave and fxrstor.
             tc->setMiscReg(MISCREG_EFER, efer);
 
-            //Set up the registers that describe the operating mode.
+            // Set up the registers that describe the operating mode.
             CR0 cr0 = 0;
             cr0.pg = 1; // Turn on paging.
             cr0.cd = 0; // Don't disable caching.
@@ -606,13 +622,13 @@ X86_64LiveProcess::initState()
 }
 
 void
-I386LiveProcess::initState()
+I386Process::initState()
 {
-    X86LiveProcess::initState();
+    X86Process::initState();
 
-    argsInit(sizeof(uint32_t), PageBytes);
+    argsInit(PageBytes);
 
-    /* 
+    /*
      * 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.
      */
@@ -662,8 +678,8 @@ I386LiveProcess::initState()
         dataAttr.expandDown = 0;
         dataAttr.system = 1;
 
-        //Initialize the segment registers.
-        for(int seg = 0; seg < NUM_SEGMENTREGS; seg++) {
+        // Initialize the segment registers.
+        for (int seg = 0; seg < NUM_SEGMENTREGS; seg++) {
             tc->setMiscRegNoEffect(MISCREG_SEG_BASE(seg), 0);
             tc->setMiscRegNoEffect(MISCREG_SEG_EFF_BASE(seg), 0);
             tc->setMiscRegNoEffect(MISCREG_SEG_ATTR(seg), dataAttr);
@@ -703,7 +719,7 @@ I386LiveProcess::initState()
         efer.ffxsr = 1; // Turn on fast fxsave and fxrstor.
         tc->setMiscReg(MISCREG_EFER, efer);
 
-        //Set up the registers that describe the operating mode.
+        // Set up the registers that describe the operating mode.
         CR0 cr0 = 0;
         cr0.pg = 1; // Turn on paging.
         cr0.cd = 0; // Don't disable caching.
@@ -726,26 +742,22 @@ I386LiveProcess::initState()
 
 template<class IntType>
 void
-X86LiveProcess::argsInit(int pageSize,
-        std::vector<AuxVector<IntType> > extraAuxvs)
+X86Process::argsInit(int pageSize,
+                     std::vector<AuxVector<IntType> > extraAuxvs)
 {
     int intSize = sizeof(IntType);
 
-    typedef AuxVector<IntType> auxv_t;
-    std::vector<auxv_t> auxv = extraAuxvs;
+    std::vector<AuxVector<IntType>> auxv = extraAuxvs;
 
     string filename;
-    if(argv.size() < 1)
+    if (argv.size() < 1)
         filename = "";
     else
         filename = argv[0];
 
-    //We want 16 byte alignment
+    // We want 16 byte alignment
     uint64_t align = 16;
 
-    // load object file into target memory
-    objFile->loadSections(initVirtMem);
-
     enum X86CpuFeature {
         X86_OnboardFPU = 1 << 0,
         X86_VirtualModeExtensions = 1 << 1,
@@ -785,8 +797,10 @@ X86LiveProcess::argsInit(int pageSize,
         X86_IA64Processor = 1 << 30
     };
 
-    // Setup the auxilliary vectors. These will already have endian conversion.
-    // Auxilliary vectors are loaded only for elf formatted executables.
+    // Setup the auxiliary vectors. These will already have endian
+    // conversion. Auxiliary vectors are loaded only for elf formatted
+    // executables; the auxv is responsible for passing information from
+    // the OS to the interpreter.
     ElfObject * elfObject = dynamic_cast<ElfObject *>(objFile);
     if (elfObject) {
         uint64_t features =
@@ -821,52 +835,51 @@ X86LiveProcess::argsInit(int pageSize,
 //            X86_IA64Processor |
             0;
 
-        //Bits which describe the system hardware capabilities
-        //XXX Figure out what these should be
-        auxv.push_back(auxv_t(M5_AT_HWCAP, features));
-        //The system page size
-        auxv.push_back(auxv_t(M5_AT_PAGESZ, X86ISA::PageBytes));
-        //Frequency at which times() increments
-        //Defined to be 100 in the kernel source.
-        auxv.push_back(auxv_t(M5_AT_CLKTCK, 100));
-        // For statically linked executables, this is the virtual address of the
-        // program header tables if they appear in the executable image
-        auxv.push_back(auxv_t(M5_AT_PHDR, elfObject->programHeaderTable()));
+        // Bits which describe the system hardware capabilities
+        // XXX Figure out what these should be
+        auxv.emplace_back(M5_AT_HWCAP, features);
+        // The system page size
+        auxv.emplace_back(M5_AT_PAGESZ, X86ISA::PageBytes);
+        // Frequency at which times() increments
+        // Defined to be 100 in the kernel source.
+        auxv.emplace_back(M5_AT_CLKTCK, 100);
+        // This is the virtual address of the program header tables if they
+        // appear in the executable image.
+        auxv.emplace_back(M5_AT_PHDR, elfObject->programHeaderTable());
         // This is the size of a program header entry from the elf file.
-        auxv.push_back(auxv_t(M5_AT_PHENT, elfObject->programHeaderSize()));
+        auxv.emplace_back(M5_AT_PHENT, elfObject->programHeaderSize());
         // This is the number of program headers from the original elf file.
-        auxv.push_back(auxv_t(M5_AT_PHNUM, elfObject->programHeaderCount()));
-        //This is the address of the elf "interpreter", It should be set
-        //to 0 for regular executables. It should be something else
-        //(not sure what) for dynamic libraries.
-        auxv.push_back(auxv_t(M5_AT_BASE, 0));
-
-        //XXX Figure out what this should be.
-        auxv.push_back(auxv_t(M5_AT_FLAGS, 0));
-        //The entry point to the program
-        auxv.push_back(auxv_t(M5_AT_ENTRY, objFile->entryPoint()));
-        //Different user and group IDs
-        auxv.push_back(auxv_t(M5_AT_UID, uid()));
-        auxv.push_back(auxv_t(M5_AT_EUID, euid()));
-        auxv.push_back(auxv_t(M5_AT_GID, gid()));
-        auxv.push_back(auxv_t(M5_AT_EGID, egid()));
-        //Whether to enable "secure mode" in the executable
-        auxv.push_back(auxv_t(M5_AT_SECURE, 0));
-        //The address of 16 "random" bytes.
-        auxv.push_back(auxv_t(M5_AT_RANDOM, 0));
-        //The name of the program
-        auxv.push_back(auxv_t(M5_AT_EXECFN, 0));
-        //The platform string
-        auxv.push_back(auxv_t(M5_AT_PLATFORM, 0));
+        auxv.emplace_back(M5_AT_PHNUM, elfObject->programHeaderCount());
+        // This is the base address of the ELF interpreter; it should be
+        // zero for static executables or contain the base address for
+        // dynamic executables.
+        auxv.emplace_back(M5_AT_BASE, getBias());
+        // XXX Figure out what this should be.
+        auxv.emplace_back(M5_AT_FLAGS, 0);
+        // The entry point to the program
+        auxv.emplace_back(M5_AT_ENTRY, objFile->entryPoint());
+        // Different user and group IDs
+        auxv.emplace_back(M5_AT_UID, uid());
+        auxv.emplace_back(M5_AT_EUID, euid());
+        auxv.emplace_back(M5_AT_GID, gid());
+        auxv.emplace_back(M5_AT_EGID, egid());
+        // Whether to enable "secure mode" in the executable
+        auxv.emplace_back(M5_AT_SECURE, 0);
+        // The address of 16 "random" bytes.
+        auxv.emplace_back(M5_AT_RANDOM, 0);
+        // The name of the program
+        auxv.emplace_back(M5_AT_EXECFN, 0);
+        // The platform string
+        auxv.emplace_back(M5_AT_PLATFORM, 0);
     }
 
-    //Figure out how big the initial stack needs to be
+    // Figure out how big the initial stack needs to be
 
     // A sentry NULL void pointer at the top of the stack.
     int sentry_size = intSize;
 
-    //This is the name of the file which is present on the initial stack
-    //It's purpose is to let the user space linker examine the original file.
+    // This is the name of the file which is present on the initial stack
+    // It's purpose is to let the user space linker examine the original file.
     int file_name_size = filename.size() + 1;
 
     const int numRandomBytes = 16;
@@ -882,10 +895,10 @@ X86LiveProcess::argsInit(int pageSize,
     for (int i = 0; i < argv.size(); ++i)
         arg_data_size += argv[i].size() + 1;
 
-    //The info_block needs to be padded so it's size is a multiple of the
-    //alignment mask. Also, it appears that there needs to be at least some
-    //padding, so if the size is already a multiple, we need to increase it
-    //anyway.
+    // The info_block needs to be padded so its size is a multiple of the
+    // alignment mask. Also, it appears that there needs to be at least some
+    // padding, so if the size is already a multiple, we need to increase it
+    // anyway.
     int base_info_block_size =
         sentry_size + file_name_size + env_data_size + arg_data_size;
 
@@ -893,7 +906,7 @@ X86LiveProcess::argsInit(int pageSize,
 
     int info_block_padding = info_block_size - base_info_block_size;
 
-    //Each auxilliary vector is two 8 byte words
+    // Each auxiliary vector is two 8 byte words
     int aux_array_size = intSize * 2 * (auxv.size() + 1);
 
     int envp_array_size = intSize * (envp.size() + 1);
@@ -901,15 +914,15 @@ X86LiveProcess::argsInit(int pageSize,
 
     int argc_size = intSize;
 
-    //Figure out the size of the contents of the actual initial frame
+    // Figure out the size of the contents of the actual initial frame
     int frame_size =
         aux_array_size +
         envp_array_size +
         argv_array_size +
         argc_size;
 
-    //There needs to be padding after the auxiliary vector data so that the
-    //very bottom of the stack is aligned properly.
+    // There needs to be padding after the auxiliary vector data so that the
+    // very bottom of the stack is aligned properly.
     int partial_size = frame_size + aux_data_size;
     int aligned_partial_size = roundUp(partial_size, align);
     int aux_padding = aligned_partial_size - partial_size;
@@ -920,9 +933,14 @@ X86LiveProcess::argsInit(int pageSize,
         aux_padding +
         frame_size;
 
-    stack_min = stack_base - space_needed;
+    Addr stack_base = memState->getStackBase();
+
+    Addr stack_min = stack_base - space_needed;
     stack_min = roundDown(stack_min, align);
-    stack_size = roundUp(stack_base - stack_min, pageSize);
+
+    unsigned stack_size = stack_base - stack_min;
+    stack_size = roundUp(stack_size, pageSize);
+    memState->setStackSize(stack_size);
 
     // map memory
     Addr stack_end = roundDown(stack_base - stack_size, pageSize);
@@ -956,107 +974,105 @@ X86LiveProcess::argsInit(int pageSize,
 
     // figure out argc
     IntType argc = argv.size();
-    IntType guestArgc = X86ISA::htog(argc);
+    IntType guestArgc = htole(argc);
 
-    //Write out the sentry void *
+    // Write out the sentry void *
     IntType sentry_NULL = 0;
-    initVirtMem.writeBlob(sentry_base,
-            (uint8_t*)&sentry_NULL, sentry_size);
+    initVirtMem.writeBlob(sentry_base, &sentry_NULL, sentry_size);
 
-    //Write the file name
+    // Write the file name
     initVirtMem.writeString(file_name_base, filename.c_str());
 
-    //Fix up the aux vectors which point to data
-    assert(auxv[auxv.size() - 3].a_type == M5_AT_RANDOM);
-    auxv[auxv.size() - 3].a_val = aux_data_base;
-    assert(auxv[auxv.size() - 2].a_type == M5_AT_EXECFN);
-    auxv[auxv.size() - 2].a_val = argv_array_base;
-    assert(auxv[auxv.size() - 1].a_type == M5_AT_PLATFORM);
-    auxv[auxv.size() - 1].a_val = aux_data_base + numRandomBytes;
-
-    //Copy the aux stuff
-    for (int x = 0; x < auxv.size(); x++) {
-        initVirtMem.writeBlob(auxv_array_base + x * 2 * intSize,
-                (uint8_t*)&(auxv[x].a_type), intSize);
-        initVirtMem.writeBlob(auxv_array_base + (x * 2 + 1) * intSize,
-                (uint8_t*)&(auxv[x].a_val), intSize);
+    // Fix up the aux vectors which point to data
+    assert(auxv[auxv.size() - 3].type == M5_AT_RANDOM);
+    auxv[auxv.size() - 3].val = aux_data_base;
+    assert(auxv[auxv.size() - 2].type == M5_AT_EXECFN);
+    auxv[auxv.size() - 2].val = argv_array_base;
+    assert(auxv[auxv.size() - 1].type == M5_AT_PLATFORM);
+    auxv[auxv.size() - 1].val = aux_data_base + numRandomBytes;
+
+
+    // Copy the aux stuff
+    Addr auxv_array_end = auxv_array_base;
+    for (const auto &aux: auxv) {
+        initVirtMem.write(auxv_array_end, aux, GuestByteOrder);
+        auxv_array_end += sizeof(aux);
     }
-    //Write out the terminating zeroed auxilliary vector
-    const uint64_t zero = 0;
-    initVirtMem.writeBlob(auxv_array_base + 2 * intSize * auxv.size(),
-            (uint8_t*)&zero, 2 * intSize);
+    // Write out the terminating zeroed auxiliary vector
+    const AuxVector<uint64_t> zero(0, 0);
+    initVirtMem.write(auxv_array_end, zero);
+    auxv_array_end += sizeof(zero);
 
     initVirtMem.writeString(aux_data_base, platform.c_str());
 
-    copyStringArray(envp, envp_array_base, env_data_base, initVirtMem);
-    copyStringArray(argv, argv_array_base, arg_data_base, initVirtMem);
+    copyStringArray(envp, envp_array_base, env_data_base,
+                    LittleEndianByteOrder, initVirtMem);
+    copyStringArray(argv, argv_array_base, arg_data_base,
+                    LittleEndianByteOrder, initVirtMem);
 
-    initVirtMem.writeBlob(argc_base, (uint8_t*)&guestArgc, intSize);
+    initVirtMem.writeBlob(argc_base, &guestArgc, intSize);
 
     ThreadContext *tc = system->getThreadContext(contextIds[0]);
-    //Set the stack pointer register
+    // Set the stack pointer register
     tc->setIntReg(StackPointerReg, stack_min);
 
     // There doesn't need to be any segment base added in since we're dealing
     // with the flat segmentation model.
-    tc->pcState(objFile->entryPoint());
-
-    //Align the "stack_min" to a page boundary.
-    stack_min = roundDown(stack_min, pageSize);
+    tc->pcState(getStartPC());
 
-//    num_processes++;
+    // Align the "stack_min" to a page boundary.
+    memState->setStackMin(roundDown(stack_min, pageSize));
 }
 
 void
-X86_64LiveProcess::argsInit(int intSize, int pageSize)
+X86_64Process::argsInit(int pageSize)
 {
     std::vector<AuxVector<uint64_t> > extraAuxvs;
-    extraAuxvs.push_back(AuxVector<uint64_t>(M5_AT_SYSINFO_EHDR,
-                vsyscallPage.base));
-    X86LiveProcess::argsInit<uint64_t>(pageSize, extraAuxvs);
+    extraAuxvs.emplace_back(M5_AT_SYSINFO_EHDR, vsyscallPage.base);
+    X86Process::argsInit<uint64_t>(pageSize, extraAuxvs);
 }
 
 void
-I386LiveProcess::argsInit(int intSize, int pageSize)
+I386Process::argsInit(int pageSize)
 {
     std::vector<AuxVector<uint32_t> > extraAuxvs;
     //Tell the binary where the vsyscall part of the vsyscall page is.
-    extraAuxvs.push_back(AuxVector<uint32_t>(M5_AT_SYSINFO,
-                vsyscallPage.base + vsyscallPage.vsyscallOffset));
-    extraAuxvs.push_back(AuxVector<uint32_t>(M5_AT_SYSINFO_EHDR,
-                vsyscallPage.base));
-    X86LiveProcess::argsInit<uint32_t>(pageSize, extraAuxvs);
+    extraAuxvs.emplace_back(M5_AT_SYSINFO,
+            vsyscallPage.base + vsyscallPage.vsyscallOffset);
+    extraAuxvs.emplace_back(M5_AT_SYSINFO_EHDR, vsyscallPage.base);
+    X86Process::argsInit<uint32_t>(pageSize, extraAuxvs);
 }
 
 void
-X86LiveProcess::setSyscallReturn(ThreadContext *tc, SyscallReturn retval)
+X86Process::setSyscallReturn(ThreadContext *tc, SyscallReturn retval)
 {
     tc->setIntReg(INTREG_RAX, retval.encodedValue());
 }
 
-X86ISA::IntReg
-X86_64LiveProcess::getSyscallArg(ThreadContext *tc, int &i)
+RegVal
+X86_64Process::getSyscallArg(ThreadContext *tc, int &i)
 {
     assert(i < NumArgumentRegs);
     return tc->readIntReg(ArgumentReg[i++]);
 }
 
 void
-X86_64LiveProcess::setSyscallArg(ThreadContext *tc, int i, X86ISA::IntReg val)
+X86_64Process::clone(ThreadContext *old_tc, ThreadContext *new_tc,
+                     Process *p, RegVal flags)
 {
-    assert(i < NumArgumentRegs);
-    return tc->setIntReg(ArgumentReg[i], val);
+    X86Process::clone(old_tc, new_tc, p, flags);
+    ((X86_64Process*)p)->vsyscallPage = vsyscallPage;
 }
 
-X86ISA::IntReg
-I386LiveProcess::getSyscallArg(ThreadContext *tc, int &i)
+RegVal
+I386Process::getSyscallArg(ThreadContext *tc, int &i)
 {
     assert(i < NumArgumentRegs32);
     return tc->readIntReg(ArgumentReg32[i++]);
 }
 
-X86ISA::IntReg
-I386LiveProcess::getSyscallArg(ThreadContext *tc, int &i, int width)
+RegVal
+I386Process::getSyscallArg(ThreadContext *tc, int &i, int width)
 {
     assert(width == 32 || width == 64);
     assert(i < NumArgumentRegs);
@@ -1067,8 +1083,9 @@ I386LiveProcess::getSyscallArg(ThreadContext *tc, int &i, int width)
 }
 
 void
-I386LiveProcess::setSyscallArg(ThreadContext *tc, int i, X86ISA::IntReg val)
+I386Process::clone(ThreadContext *old_tc, ThreadContext *new_tc,
+                   Process *p, RegVal flags)
 {
-    assert(i < NumArgumentRegs);
-    return tc->setIntReg(ArgumentReg[i], val);
+    X86Process::clone(old_tc, new_tc, p, flags);
+    ((I386Process*)p)->vsyscallPage = vsyscallPage;
 }