Major changes to how SimObjects are created and initialized. Almost all
[gem5.git] / src / sim / process.cc
index 1261b84367cdeb6f1b17e1d1dd4bb06080567c29..c556ade127b09c711d179e2eb4be7966c66a86cf 100644 (file)
  * 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.
+ *
+ * Authors: Nathan Binkert
+ *          Steve Reinhardt
+ *          Ali Saidi
  */
 
 #include <unistd.h>
 
 #include <string>
 
+#include "arch/remote_gdb.hh"
 #include "base/intmath.hh"
 #include "base/loader/object_file.hh"
 #include "base/loader/symtab.hh"
 #include "base/statistics.hh"
 #include "config/full_system.hh"
-#include "cpu/exec_context.hh"
+#include "cpu/thread_context.hh"
 #include "mem/page_table.hh"
 #include "mem/physical.hh"
 #include "mem/translating_port.hh"
-#include "sim/builder.hh"
+#include "params/LiveProcess.hh"
 #include "sim/process.hh"
+#include "sim/process_impl.hh"
 #include "sim/stats.hh"
 #include "sim/syscall_emul.hh"
 #include "sim/system.hh"
 
+#include "arch/isa_specific.hh"
+#if THE_ISA == ALPHA_ISA
+#include "arch/alpha/linux/process.hh"
+#include "arch/alpha/tru64/process.hh"
+#elif THE_ISA == SPARC_ISA
+#include "arch/sparc/linux/process.hh"
+#include "arch/sparc/solaris/process.hh"
+#elif THE_ISA == MIPS_ISA
+#include "arch/mips/linux/process.hh"
+#elif THE_ISA == X86_ISA
+#include "arch/x86/linux/process.hh"
+#else
+#error "THE_ISA not set"
+#endif
+
+
 using namespace std;
 using namespace TheISA;
 
@@ -130,11 +152,18 @@ Process::openOutputFile(const string &filename)
 
 
 int
-Process::registerExecContext(ExecContext *xc)
+Process::registerThreadContext(ThreadContext *tc)
 {
     // add to list
-    int myIndex = execContexts.size();
-    execContexts.push_back(xc);
+    int myIndex = threadContexts.size();
+    threadContexts.push_back(tc);
+
+//    RemoteGDB *rgdb = new RemoteGDB(system, tc);
+//    GDBListener *gdbl = new GDBListener(rgdb, 7000 + myIndex);
+//    gdbl->listen();
+    //gdbl->accept();
+
+//    remoteGDB.push_back(rgdb);
 
     // return CPU number to caller
     return myIndex;
@@ -143,31 +172,32 @@ Process::registerExecContext(ExecContext *xc)
 void
 Process::startup()
 {
-    if (execContexts.empty())
+    if (threadContexts.empty())
         fatal("Process %s is not associated with any CPUs!\n", name());
 
-    // first exec context for this process... initialize & enable
-    ExecContext *xc = execContexts[0];
+    // first thread context for this process... initialize & enable
+    ThreadContext *tc = threadContexts[0];
 
     // mark this context as active so it will start ticking.
-    xc->activate(0);
+    tc->activate(0);
 
     Port *mem_port;
     mem_port = system->physmem->getPort("functional");
-    initVirtMem = new TranslatingPort(pTable, true);
+    initVirtMem = new TranslatingPort("process init port", this,
+            TranslatingPort::Always);
     mem_port->setPeer(initVirtMem);
     initVirtMem->setPeer(mem_port);
 }
 
 void
-Process::replaceExecContext(ExecContext *xc, int xcIndex)
+Process::replaceThreadContext(ThreadContext *tc, int tcIndex)
 {
-    if (xcIndex >= execContexts.size()) {
-        panic("replaceExecContext: bad xcIndex, %d >= %d\n",
-              xcIndex, execContexts.size());
+    if (tcIndex >= threadContexts.size()) {
+        panic("replaceThreadContext: bad tcIndex, %d >= %d\n",
+              tcIndex, threadContexts.size());
     }
 
-    execContexts[xcIndex] = xc;
+    threadContexts[tcIndex] = tc;
 }
 
 // map simulator fd sim_fd to target fd tgt_fd
@@ -222,14 +252,64 @@ Process::sim_fd(int tgt_fd)
     return fd_map[tgt_fd];
 }
 
+bool
+Process::checkAndAllocNextPage(Addr vaddr)
+{
+    // if this is an initial write we might not have
+    if (vaddr >= stack_min && vaddr < stack_base) {
+        pTable->allocate(roundDown(vaddr, VMPageSize), VMPageSize);
+        return true;
+    }
 
+    // We've accessed the next page of the stack, so extend the stack
+    // to cover it.
+    if(vaddr < stack_min && vaddr >= stack_min - TheISA::PageBytes)
+    {
+        stack_min -= TheISA::PageBytes;
+        if(stack_base - stack_min > 8*1024*1024)
+            fatal("Over max stack size for one thread\n");
+        pTable->allocate(stack_min, TheISA::PageBytes);
+        warn("Increasing stack size by one page.");
+        return true;
+    }
+    return false;
+}
 
-//
-// need to declare these here since there is no concrete Process type
-// that can be constructed (i.e., no REGISTER_SIM_OBJECT() macro call,
-// which is where these get declared for concrete types).
-//
-DEFINE_SIM_OBJECT_CLASS_NAME("Process", Process)
+void
+Process::serialize(std::ostream &os)
+{
+    SERIALIZE_SCALAR(initialContextLoaded);
+    SERIALIZE_SCALAR(brk_point);
+    SERIALIZE_SCALAR(stack_base);
+    SERIALIZE_SCALAR(stack_size);
+    SERIALIZE_SCALAR(stack_min);
+    SERIALIZE_SCALAR(next_thread_stack_base);
+    SERIALIZE_SCALAR(mmap_start);
+    SERIALIZE_SCALAR(mmap_end);
+    SERIALIZE_SCALAR(nxm_start);
+    SERIALIZE_SCALAR(nxm_end);
+    SERIALIZE_ARRAY(fd_map, MAX_FD);
+
+    pTable->serialize(os);
+}
+
+void
+Process::unserialize(Checkpoint *cp, const std::string &section)
+{
+    UNSERIALIZE_SCALAR(initialContextLoaded);
+    UNSERIALIZE_SCALAR(brk_point);
+    UNSERIALIZE_SCALAR(stack_base);
+    UNSERIALIZE_SCALAR(stack_size);
+    UNSERIALIZE_SCALAR(stack_min);
+    UNSERIALIZE_SCALAR(next_thread_stack_base);
+    UNSERIALIZE_SCALAR(mmap_start);
+    UNSERIALIZE_SCALAR(mmap_end);
+    UNSERIALIZE_SCALAR(nxm_start);
+    UNSERIALIZE_SCALAR(nxm_end);
+    UNSERIALIZE_ARRAY(fd_map, MAX_FD);
+
+    pTable->unserialize(cp, section);
+}
 
 
 ////////////////////////////////////////////////////////////////////////
@@ -239,31 +319,24 @@ DEFINE_SIM_OBJECT_CLASS_NAME("Process", Process)
 ////////////////////////////////////////////////////////////////////////
 
 
-void
-copyStringArray(vector<string> &strings, Addr array_ptr, Addr data_ptr,
-                TranslatingPort* memPort)
-{
-    Addr data_ptr_swap;
-    for (int i = 0; i < strings.size(); ++i) {
-        data_ptr_swap = htog(data_ptr);
-        memPort->writeBlob(array_ptr, (uint8_t*)&data_ptr_swap, sizeof(Addr));
-        memPort->writeString(data_ptr, strings[i].c_str());
-        array_ptr += sizeof(Addr);
-        data_ptr += strings[i].size() + 1;
-    }
-    // add NULL terminator
-    data_ptr = 0;
-
-    memPort->writeBlob(array_ptr, (uint8_t*)&data_ptr, sizeof(Addr));
-}
-
 LiveProcess::LiveProcess(const string &nm, ObjectFile *_objFile,
                          System *_system,
                          int stdin_fd, int stdout_fd, int stderr_fd,
-                         vector<string> &_argv, vector<string> &_envp)
+                         vector<string> &_argv, vector<string> &_envp,
+                         const string &_cwd,
+                         uint64_t _uid, uint64_t _euid,
+                         uint64_t _gid, uint64_t _egid,
+                         uint64_t _pid, uint64_t _ppid)
     : Process(nm, _system, stdin_fd, stdout_fd, stderr_fd),
-      objFile(_objFile), argv(_argv), envp(_envp)
+      objFile(_objFile), argv(_argv), envp(_envp), cwd(_cwd)
 {
+    __uid = _uid;
+    __euid = _euid;
+    __gid = _gid;
+    __egid = _egid;
+    __pid = _pid;
+    __ppid = _ppid;
+
     prog_fname = argv[0];
 
     // load up symbols, if any... these may be used for debugging or
@@ -301,18 +374,16 @@ LiveProcess::argsInit(int intSize, int pageSize)
 
     int space_needed =
         argv_array_size + envp_array_size + arg_data_size + env_data_size;
-    // for SimpleScalar compatibility
-    if (space_needed < 16384)
-        space_needed = 16384;
+    if (space_needed < 32*1024)
+        space_needed = 32*1024;
 
     // set bottom of stack
     stack_min = stack_base - space_needed;
     // align it
-    stack_min &= ~(intSize-1);
+    stack_min = roundDown(stack_min, pageSize);
     stack_size = stack_base - stack_min;
     // map memory
-    pTable->allocate(roundDown(stack_min, pageSize),
-                     roundUp(stack_size, pageSize));
+    pTable->allocate(stack_min, roundUp(stack_size, pageSize));
 
     // map out initial stack contents
     Addr argv_array_base = stack_min + intSize; // room for argc
@@ -334,20 +405,23 @@ LiveProcess::argsInit(int intSize, int pageSize)
     copyStringArray(argv, argv_array_base, arg_data_base, initVirtMem);
     copyStringArray(envp, envp_array_base, env_data_base, initVirtMem);
 
-    execContexts[0]->setIntReg(ArgumentReg0, argc);
-    execContexts[0]->setIntReg(ArgumentReg1, argv_array_base);
-    execContexts[0]->setIntReg(StackPointerReg, stack_min);
+    threadContexts[0]->setIntReg(ArgumentReg0, argc);
+    threadContexts[0]->setIntReg(ArgumentReg1, argv_array_base);
+    threadContexts[0]->setIntReg(StackPointerReg, stack_min);
 
     Addr prog_entry = objFile->entryPoint();
-    execContexts[0]->setPC(prog_entry);
-    execContexts[0]->setNextPC(prog_entry + sizeof(MachInst));
-    execContexts[0]->setNextNPC(prog_entry + (2 * sizeof(MachInst)));
+    threadContexts[0]->setPC(prog_entry);
+    threadContexts[0]->setNextPC(prog_entry + sizeof(MachInst));
+
+#if THE_ISA != ALPHA_ISA //e.g. MIPS or Sparc
+    threadContexts[0]->setNextNPC(prog_entry + (2 * sizeof(MachInst)));
+#endif
 
     num_processes++;
 }
 
 void
-LiveProcess::syscall(int64_t callnum, ExecContext *xc)
+LiveProcess::syscall(int64_t callnum, ThreadContext *tc)
 {
     num_syscalls++;
 
@@ -355,7 +429,146 @@ LiveProcess::syscall(int64_t callnum, ExecContext *xc)
     if (desc == NULL)
         fatal("Syscall %d out of range", callnum);
 
-    desc->doSyscall(callnum, this, xc);
+    desc->doSyscall(callnum, this, tc);
+}
+
+LiveProcess *
+LiveProcess::create(const std::string &nm, System *system, int stdin_fd,
+                    int stdout_fd, int stderr_fd, std::string executable,
+                    std::vector<std::string> &argv,
+                    std::vector<std::string> &envp,
+                    const std::string &cwd,
+                    uint64_t _uid, uint64_t _euid,
+                    uint64_t _gid, uint64_t _egid,
+                    uint64_t _pid, uint64_t _ppid)
+{
+    LiveProcess *process = NULL;
+
+    ObjectFile *objFile = createObjectFile(executable);
+    if (objFile == NULL) {
+        fatal("Can't load object file %s", executable);
+    }
+
+    if (objFile->isDynamic())
+       fatal("Object file is a dynamic executable however only static "
+             "executables are supported!\n        Please recompile your "
+             "executable as a static binary and try again.\n");
+
+#if THE_ISA == ALPHA_ISA
+    if (objFile->getArch() != ObjectFile::Alpha)
+        fatal("Object file architecture does not match compiled ISA (Alpha).");
+    switch (objFile->getOpSys()) {
+      case ObjectFile::Tru64:
+        process = new AlphaTru64Process(nm, objFile, system,
+                                        stdin_fd, stdout_fd, stderr_fd,
+                                        argv, envp, cwd,
+                                        _uid, _euid, _gid, _egid, _pid, _ppid);
+        break;
+
+      case ObjectFile::Linux:
+        process = new AlphaLinuxProcess(nm, objFile, system,
+                                        stdin_fd, stdout_fd, stderr_fd,
+                                        argv, envp, cwd,
+                                        _uid, _euid, _gid, _egid, _pid, _ppid);
+        break;
+
+      default:
+        fatal("Unknown/unsupported operating system.");
+    }
+#elif THE_ISA == SPARC_ISA
+    if (objFile->getArch() != ObjectFile::SPARC64 && objFile->getArch() != ObjectFile::SPARC32)
+        fatal("Object file architecture does not match compiled ISA (SPARC).");
+    switch (objFile->getOpSys()) {
+      case ObjectFile::Linux:
+        if (objFile->getArch() == ObjectFile::SPARC64) {
+            process = new Sparc64LinuxProcess(nm, objFile, system,
+                                              stdin_fd, stdout_fd, stderr_fd,
+                                              argv, envp, cwd,
+                                              _uid, _euid, _gid,
+                                              _egid, _pid, _ppid);
+        } else {
+            process = new Sparc32LinuxProcess(nm, objFile, system,
+                                              stdin_fd, stdout_fd, stderr_fd,
+                                              argv, envp, cwd,
+                                              _uid, _euid, _gid,
+                                              _egid, _pid, _ppid);
+        }
+        break;
+
+
+      case ObjectFile::Solaris:
+        process = new SparcSolarisProcess(nm, objFile, system,
+                                        stdin_fd, stdout_fd, stderr_fd,
+                                        argv, envp, cwd,
+                                        _uid, _euid, _gid, _egid, _pid, _ppid);
+        break;
+      default:
+        fatal("Unknown/unsupported operating system.");
+    }
+#elif THE_ISA == X86_ISA
+    if (objFile->getArch() != ObjectFile::X86)
+        fatal("Object file architecture does not match compiled ISA (x86).");
+    switch (objFile->getOpSys()) {
+      case ObjectFile::Linux:
+        process = new X86LinuxProcess(nm, objFile, system,
+                                          stdin_fd, stdout_fd, stderr_fd,
+                                          argv, envp, cwd,
+                                          _uid, _euid, _gid,
+                                          _egid, _pid, _ppid);
+        break;
+      default:
+        fatal("Unknown/unsupported operating system.");
+    }
+#elif THE_ISA == MIPS_ISA
+    if (objFile->getArch() != ObjectFile::Mips)
+        fatal("Object file architecture does not match compiled ISA (MIPS).");
+    switch (objFile->getOpSys()) {
+      case ObjectFile::Linux:
+        process = new MipsLinuxProcess(nm, objFile, system,
+                                        stdin_fd, stdout_fd, stderr_fd,
+                                        argv, envp, cwd,
+                                        _uid, _euid, _gid, _egid, _pid, _ppid);
+        break;
+
+      default:
+        fatal("Unknown/unsupported operating system.");
+    }
+#else
+#error "THE_ISA not set"
+#endif
+
+
+    if (process == NULL)
+        fatal("Unknown error creating process object.");
+    return process;
 }
 
-DEFINE_SIM_OBJECT_CLASS_NAME("LiveProcess", LiveProcess);
+LiveProcess *
+LiveProcessParams::create()
+{
+    string in = input;
+    string out = output;
+
+    // initialize file descriptors to default: same as simulator
+    int stdin_fd, stdout_fd, stderr_fd;
+
+    if (in == "stdin" || in == "cin")
+        stdin_fd = STDIN_FILENO;
+    else
+        stdin_fd = Process::openInputFile(input);
+
+    if (out == "stdout" || out == "cout")
+        stdout_fd = STDOUT_FILENO;
+    else if (out == "stderr" || out == "cerr")
+        stdout_fd = STDERR_FILENO;
+    else
+        stdout_fd = Process::openOutputFile(out);
+
+    stderr_fd = (stdout_fd != STDOUT_FILENO) ? stdout_fd : STDERR_FILENO;
+
+    return LiveProcess::create(name, system,
+                               stdin_fd, stdout_fd, stderr_fd,
+                               (string)executable == "" ? cmd[0] : executable,
+                               cmd, env, cwd,
+                               uid, euid, gid, egid, pid, ppid);
+}