Commit m5threads package.
authorDaniel Sanchez <sanchezd@stanford.edu>
Tue, 21 Apr 2009 15:17:36 +0000 (08:17 -0700)
committerDaniel Sanchez <sanchezd@stanford.edu>
Tue, 21 Apr 2009 15:17:36 +0000 (08:17 -0700)
This patch adds limited multithreading support in syscall-emulation
mode, by using the clone system call.  The clone system call works
for Alpha, SPARC and x86, and multithreaded applications run
correctly in Alpha and SPARC.

src/arch/alpha/linux/process.cc
src/arch/sparc/linux/syscalls.cc
src/arch/sparc/regfile.cc
src/arch/x86/linux/syscalls.cc
src/arch/x86/regfile.cc
src/sim/syscall_emul.cc
src/sim/syscall_emul.hh

index aeff9fbed58ef4d0138befe7fe0526471c833202..9886c7ea7e88ba3bb4f83d7fb6e7a34b195375fc 100644 (file)
@@ -434,7 +434,7 @@ SyscallDesc AlphaLinuxProcess::syscallDescs[] = {
     /* 309 */ SyscallDesc("get_kernel_syms", unimplementedFunc),
     /* 310 */ SyscallDesc("syslog", unimplementedFunc),
     /* 311 */ SyscallDesc("reboot", unimplementedFunc),
-    /* 312 */ SyscallDesc("clone", unimplementedFunc),
+    /* 312 */ SyscallDesc("clone", cloneFunc),
     /* 313 */ SyscallDesc("uselib", unimplementedFunc),
     /* 314 */ SyscallDesc("mlock", unimplementedFunc),
     /* 315 */ SyscallDesc("munlock", unimplementedFunc),
@@ -527,7 +527,7 @@ SyscallDesc AlphaLinuxProcess::syscallDescs[] = {
     /* 402 */ SyscallDesc("io_cancel", unimplementedFunc),
     /* 403 */ SyscallDesc("unknown #403", unimplementedFunc),
     /* 404 */ SyscallDesc("unknown #404", unimplementedFunc),
-    /* 405 */ SyscallDesc("exit_group", exitFunc), // exit all threads...
+    /* 405 */ SyscallDesc("exit_group", exitGroupFunc), // exit all threads...
     /* 406 */ SyscallDesc("lookup_dcookie", unimplementedFunc),
     /* 407 */ SyscallDesc("sys_epoll_create", unimplementedFunc),
     /* 408 */ SyscallDesc("sys_epoll_ctl", unimplementedFunc),
index d9651c85c69f373358b5bdc14465b1c19d2fa642..f4781d886d746b65efd2fdfb228f1138f1b2f8e1 100644 (file)
@@ -162,7 +162,7 @@ SyscallDesc SparcLinuxProcess::syscall32Descs[] = {
     /*  71 */ SyscallDesc("mmap", mmapFunc<Sparc32Linux>),
     /*  72 */ SyscallDesc("setreuid32", unimplementedFunc),
     /*  73 */ SyscallDesc("munmap", munmapFunc),
-    /*  74 */ SyscallDesc("mprotect", unimplementedFunc),
+    /*  74 */ SyscallDesc("mprotect", ignoreFunc),
     /*  75 */ SyscallDesc("madvise", unimplementedFunc),
     /*  76 */ SyscallDesc("vhangup", unimplementedFunc),
     /*  77 */ SyscallDesc("truncate64", unimplementedFunc), //32 bit
@@ -191,20 +191,20 @@ SyscallDesc SparcLinuxProcess::syscall32Descs[] = {
     /* 100 */ SyscallDesc("getpriority", unimplementedFunc), //32 bit
     /* 101 */ SyscallDesc("rt_sigreturn", unimplementedFunc), //32 bit
     /* 102 */ SyscallDesc("rt_sigaction", ignoreFunc), //32 bit
-    /* 103 */ SyscallDesc("rt_sigprocmask", unimplementedFunc), //32 bit
+    /* 103 */ SyscallDesc("rt_sigprocmask", ignoreFunc), //32 bit
     /* 104 */ SyscallDesc("rt_sigpending", unimplementedFunc), //32 bit
     /* 105 */ SyscallDesc("rt_sigtimedwait", unimplementedFunc),
     /* 106 */ SyscallDesc("rt_sigqueueinfo", unimplementedFunc), //32 bit
     /* 107 */ SyscallDesc("rt_sigsuspend", unimplementedFunc),
     /* 108 */ SyscallDesc("setresuid32", unimplementedFunc),
     /* 109 */ SyscallDesc("getresuid32", getresuidFunc),
-    /* 110 */ SyscallDesc("setresgid32", unimplementedFunc),
+    /* 110 */ SyscallDesc("setresgid32", ignoreFunc),
     /* 111 */ SyscallDesc("getresgid32", unimplementedFunc),
     /* 112 */ SyscallDesc("setregid32", unimplementedFunc),
     /* 113 */ SyscallDesc("revcmsg", unimplementedFunc),
     /* 114 */ SyscallDesc("sendmsg", unimplementedFunc),
     /* 115 */ SyscallDesc("getgroups32", unimplementedFunc), //32 bit
-    /* 116 */ SyscallDesc("gettimeofday", unimplementedFunc), //32 bit
+    /* 116 */ SyscallDesc("gettimeofday", gettimeofdayFunc<Sparc32Linux>), //32 bit
     /* 117 */ SyscallDesc("getrusage", unimplementedFunc), //32 bit
     /* 118 */ SyscallDesc("getsockopt", unimplementedFunc),
     /* 119 */ SyscallDesc("getcwd", getcwdFunc),
@@ -276,7 +276,7 @@ SyscallDesc SparcLinuxProcess::syscall32Descs[] = {
     /* 185 */ SyscallDesc("setpgid", unimplementedFunc), //32 bit
     /* 186 */ SyscallDesc("fremovexattr", unimplementedFunc), //32 bit
     /* 187 */ SyscallDesc("tkill", unimplementedFunc), //32 bit
-    /* 188 */ SyscallDesc("exit_group", exitFunc), //32 bit
+    /* 188 */ SyscallDesc("exit_group", exitGroupFunc), //32 bit
     /* 189 */ SyscallDesc("uname", unameFunc),
     /* 190 */ SyscallDesc("init_module", unimplementedFunc), //32 bit
     /* 191 */ SyscallDesc("personality", unimplementedFunc),
@@ -305,7 +305,7 @@ SyscallDesc SparcLinuxProcess::syscall32Descs[] = {
     /* 214 */ SyscallDesc("sysinfo", unimplementedFunc), //32 bit
     /* 215 */ SyscallDesc("ipc", unimplementedFunc), //32 bit
     /* 216 */ SyscallDesc("sigreturn", unimplementedFunc), //32 bit
-    /* 217 */ SyscallDesc("clone", unimplementedFunc),
+    /* 217 */ SyscallDesc("clone", cloneFunc),
     /* 218 */ SyscallDesc("ioprio_get", unimplementedFunc), //32 bit
     /* 219 */ SyscallDesc("adjtimex", unimplementedFunc), //32 bit
     /* 220 */ SyscallDesc("sigprocmask", unimplementedFunc), //32 bit
@@ -468,7 +468,7 @@ SyscallDesc SparcLinuxProcess::syscallDescs[] = {
     /* 71 */ SyscallDesc("mmap", mmapFunc<SparcLinux>),
     /* 72 */ SyscallDesc("setreuid32", unimplementedFunc),
     /* 73 */ SyscallDesc("munmap", munmapFunc),
-    /* 74 */ SyscallDesc("mprotect", unimplementedFunc),
+    /* 74 */ SyscallDesc("mprotect", ignoreFunc),
     /* 75 */ SyscallDesc("madvise", unimplementedFunc),
     /* 76 */ SyscallDesc("vhangup", unimplementedFunc),
     /* 77 */ SyscallDesc("truncate64", unimplementedFunc),
@@ -497,20 +497,20 @@ SyscallDesc SparcLinuxProcess::syscallDescs[] = {
     /* 100 */ SyscallDesc("getpriority", unimplementedFunc),
     /* 101 */ SyscallDesc("rt_sigreturn", unimplementedFunc),
     /* 102 */ SyscallDesc("rt_sigaction", ignoreFunc),
-    /* 103 */ SyscallDesc("rt_sigprocmask", unimplementedFunc),
+    /* 103 */ SyscallDesc("rt_sigprocmask", ignoreFunc),
     /* 104 */ SyscallDesc("rt_sigpending", unimplementedFunc),
     /* 105 */ SyscallDesc("rt_sigtimedwait", unimplementedFunc),
     /* 106 */ SyscallDesc("rt_sigqueueinfo", unimplementedFunc),
     /* 107 */ SyscallDesc("rt_sigsuspend", unimplementedFunc),
     /* 108 */ SyscallDesc("setresuid", unimplementedFunc),
     /* 109 */ SyscallDesc("getresuid", getresuidFunc),
-    /* 110 */ SyscallDesc("setresgid", unimplementedFunc),
+    /* 110 */ SyscallDesc("setresgid", ignoreFunc),
     /* 111 */ SyscallDesc("getresgid", unimplementedFunc),
     /* 112 */ SyscallDesc("setregid32", unimplementedFunc),
     /* 113 */ SyscallDesc("recvmsg", unimplementedFunc),
     /* 114 */ SyscallDesc("sendmsg", unimplementedFunc),
     /* 115 */ SyscallDesc("getgroups32", unimplementedFunc),
-    /* 116 */ SyscallDesc("gettimeofday", unimplementedFunc),
+    /* 116 */ SyscallDesc("gettimeofday", gettimeofdayFunc<SparcLinux>),
     /* 117 */ SyscallDesc("getrusage", unimplementedFunc),
     /* 118 */ SyscallDesc("getsockopt", unimplementedFunc),
     /* 119 */ SyscallDesc("getcwd", unimplementedFunc),
@@ -582,7 +582,7 @@ SyscallDesc SparcLinuxProcess::syscallDescs[] = {
     /* 185 */ SyscallDesc("setpgid", unimplementedFunc),
     /* 186 */ SyscallDesc("fremovexattr", unimplementedFunc),
     /* 187 */ SyscallDesc("tkill", unimplementedFunc),
-    /* 188 */ SyscallDesc("exit_group", exitFunc),
+    /* 188 */ SyscallDesc("exit_group", exitGroupFunc),
     /* 189 */ SyscallDesc("uname", unameFunc),
     /* 190 */ SyscallDesc("init_module", unimplementedFunc),
     /* 191 */ SyscallDesc("personality", unimplementedFunc),
@@ -611,7 +611,7 @@ SyscallDesc SparcLinuxProcess::syscallDescs[] = {
     /* 214 */ SyscallDesc("sysinfo", unimplementedFunc),
     /* 215 */ SyscallDesc("ipc", unimplementedFunc),
     /* 216 */ SyscallDesc("sigreturn", unimplementedFunc),
-    /* 217 */ SyscallDesc("clone", unimplementedFunc),
+    /* 217 */ SyscallDesc("clone", cloneFunc),
     /* 218 */ SyscallDesc("ioprio_get", unimplementedFunc),
     /* 219 */ SyscallDesc("adjtimex", unimplementedFunc),
     /* 220 */ SyscallDesc("sigprocmask", unimplementedFunc),
index 1c172a4d5b19332924a513f85eb4957d94769df5..4efac3d4e7c6f5bce90f3fde2893d35dda5f16ab 100644 (file)
@@ -352,10 +352,31 @@ void SparcISA::copyMiscRegs(ThreadContext *src, ThreadContext *dest)
 
 void SparcISA::copyRegs(ThreadContext *src, ThreadContext *dest)
 {
-    // First loop through the integer registers.
-    for (int i = 0; i < SparcISA::NumIntRegs; ++i) {
-        dest->setIntReg(i, src->readIntReg(i));
+    //First loop through the integer registers.
+    int old_gl = src->readMiscRegNoEffect(MISCREG_GL);
+    int old_cwp = src->readMiscRegNoEffect(MISCREG_CWP);
+    //Globals
+    for (int x = 0; x < MaxGL; ++x) {
+        src->setMiscRegNoEffect(MISCREG_GL, x);
+        dest->setMiscRegNoEffect(MISCREG_GL, x);
+        for (int y = 0; y < 8; y++)
+            dest->setIntReg(y, src->readIntReg(y));
     }
+    //Locals/Ins/Outs
+    for (int x = 0; x < NWindows; ++x) {
+         src->setMiscRegNoEffect(MISCREG_CWP, x);
+         dest->setMiscRegNoEffect(MISCREG_CWP, x);
+         for (int y = 8; y < 32; y++)
+             dest->setIntReg(y, src->readIntReg(y));
+    }
+    //MicroIntRegs
+    for (int y = 0; y < NumMicroIntRegs; ++y)
+        dest->setIntReg(y+32, src->readIntReg(y+32));
+
+    //Restore src's GL, CWP
+    src->setMiscRegNoEffect(MISCREG_GL, old_gl);
+    src->setMiscRegNoEffect(MISCREG_CWP, old_cwp);
+
 
     // Then loop through the floating point registers.
     for (int i = 0; i < SparcISA::NumFloatRegs; ++i) {
@@ -365,8 +386,10 @@ void SparcISA::copyRegs(ThreadContext *src, ThreadContext *dest)
     // Copy misc. registers
     copyMiscRegs(src, dest);
 
+
     // Lastly copy PC/NPC
     dest->setPC(src->readPC());
     dest->setNextPC(src->readNextPC());
     dest->setNextNPC(src->readNextNPC());
 }
+
index 49a7d8b77957e09fb17055a2121f77fbce1a6f4e..4d7bca95c2fae54a37343edeb295156ab73f8756 100644 (file)
@@ -267,7 +267,7 @@ SyscallDesc X86_64LinuxProcess::syscallDescs[] = {
     /*  36 */ SyscallDesc("getitimer", unimplementedFunc),
     /*  37 */ SyscallDesc("alarm", unimplementedFunc),
     /*  38 */ SyscallDesc("setitimer", unimplementedFunc),
-    /*  39 */ SyscallDesc("getpid", unimplementedFunc),
+    /*  39 */ SyscallDesc("getpid", getpidFunc),
     /*  40 */ SyscallDesc("sendfile", unimplementedFunc),
     /*  41 */ SyscallDesc("socket", unimplementedFunc),
     /*  42 */ SyscallDesc("connect", unimplementedFunc),
@@ -284,7 +284,7 @@ SyscallDesc X86_64LinuxProcess::syscallDescs[] = {
     /*  53 */ SyscallDesc("socketpair", unimplementedFunc),
     /*  54 */ SyscallDesc("setsockopt", unimplementedFunc),
     /*  55 */ SyscallDesc("getsockopt", unimplementedFunc),
-    /*  56 */ SyscallDesc("clone", unimplementedFunc),
+    /*  56 */ SyscallDesc("clone", cloneFunc),
     /*  57 */ SyscallDesc("fork", unimplementedFunc),
     /*  58 */ SyscallDesc("vfork", unimplementedFunc),
     /*  59 */ SyscallDesc("execve", unimplementedFunc),
@@ -430,7 +430,7 @@ SyscallDesc X86_64LinuxProcess::syscallDescs[] = {
     /* 199 */ SyscallDesc("fremovexattr", unimplementedFunc),
     /* 200 */ SyscallDesc("tkill", unimplementedFunc),
     /* 201 */ SyscallDesc("time", unimplementedFunc),
-    /* 202 */ SyscallDesc("futex", unimplementedFunc),
+    /* 202 */ SyscallDesc("futex", ignoreFunc),
     /* 203 */ SyscallDesc("sched_setaffinity", unimplementedFunc),
     /* 204 */ SyscallDesc("sched_getaffinity", unimplementedFunc),
     /* 205 */ SyscallDesc("set_thread_area", unimplementedFunc),
@@ -459,7 +459,7 @@ SyscallDesc X86_64LinuxProcess::syscallDescs[] = {
     /* 228 */ SyscallDesc("clock_gettime", unimplementedFunc),
     /* 229 */ SyscallDesc("clock_getres", unimplementedFunc),
     /* 230 */ SyscallDesc("clock_nanosleep", unimplementedFunc),
-    /* 231 */ SyscallDesc("exit_group", exitFunc),
+    /* 231 */ SyscallDesc("exit_group", exitGroupFunc),
     /* 232 */ SyscallDesc("epoll_wait", unimplementedFunc),
     /* 233 */ SyscallDesc("epoll_ctl", unimplementedFunc),
     /* 234 */ SyscallDesc("tgkill", unimplementedFunc),
index 7d01c4bb4e147e62ad742ae676038b47da7c5bed..83279902e42e506fefa3ad9f092c5cff9de27c71 100644 (file)
@@ -250,7 +250,17 @@ RegFile::unserialize(EventManager *em, Checkpoint *cp, const string &section)
 
 void X86ISA::copyMiscRegs(ThreadContext *src, ThreadContext *dest)
 {
-    panic("copyMiscRegs not implemented for x86!\n");
+    //panic("copyMiscRegs not implemented for x86!\n");
+    warn("copyMiscRegs is naively implemented for x86\n");
+    for (int i = 0; i < X86ISA::NumMiscRegs; ++i) {
+        if ( ( i != MISCREG_CR1 &&
+             !(i > MISCREG_CR4 && i < MISCREG_CR8) &&
+             !(i > MISCREG_CR8 && i <= MISCREG_CR15) ) == false) {
+             continue;
+        }
+        dest->setMiscRegNoEffect(i, src->readMiscRegNoEffect(i));
+    }
+
 }
 
 void X86ISA::copyRegs(ThreadContext *src, ThreadContext *dest)
index f0a693db019614aa60219e80116bbc380e6e4b81..d3161de26ce8592f76f17fc062267f19fd320023 100644 (file)
@@ -105,6 +105,19 @@ exitFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
 }
 
 
+SyscallReturn
+exitGroupFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
+              ThreadContext *tc)
+{
+    // really should just halt all thread contexts belonging to this
+    // process in case there's another process running...
+    exitSimLoop("target called exit()",
+                process->getSyscallArg(tc, 0) & 0xff);
+
+    return 1;
+}
+
+
 SyscallReturn
 getpagesizeFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc)
 {
@@ -641,3 +654,81 @@ getegidFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
 }
 
 
+SyscallReturn
+cloneFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
+           ThreadContext *tc)
+{
+    DPRINTF(SyscallVerbose, "In sys_clone:\n");
+    DPRINTF(SyscallVerbose, " Flags=%llx\n", tc->getSyscallArg(0));
+    DPRINTF(SyscallVerbose, " Child stack=%llx\n", tc->getSyscallArg(1));
+
+
+    if (tc->getSyscallArg(0) != 0x10f00) {
+        warn("This sys_clone implementation assumes flags CLONE_VM|CLONE_FS|CLONE_FILES|CLONE_SIGHAND|CLONE_THREAD (0x10f00), and may not work correctly with given flags 0x%llx\n", tc->getSyscallArg(0));
+    }
+
+    ThreadContext* ctc; //child thread context
+    if ( ( ctc = process->findFreeContext() ) != NULL ) {
+        DPRINTF(SyscallVerbose, " Found unallocated thread context\n");
+
+        ctc->clearArchRegs();
+
+        //Arch-specific cloning code
+        #if THE_ISA == ALPHA_ISA or THE_ISA == X86_ISA
+            //Cloning the misc. regs for these archs is enough
+            TheISA::copyMiscRegs(tc, ctc);
+        #elif THE_ISA == SPARC_ISA
+            TheISA::copyRegs(tc, ctc);
+
+            //TODO: Explain what this code actually does :-)
+            ctc->setIntReg(NumIntArchRegs + 6, 0);
+            ctc->setIntReg(NumIntArchRegs + 4, 0);
+            ctc->setIntReg(NumIntArchRegs + 3, NWindows - 2);
+            ctc->setIntReg(NumIntArchRegs + 5, NWindows);
+            ctc->setMiscRegNoEffect(MISCREG_CWP, 0);
+            ctc->setIntReg(NumIntArchRegs + 7, 0);
+            ctc->setMiscRegNoEffect(MISCREG_TL, 0);
+            ctc->setMiscRegNoEffect(MISCREG_ASI, ASI_PRIMARY);
+
+            for (int y = 8; y < 32; y++)
+                ctc->setIntReg(y, tc->readIntReg(y));
+        #else
+            fatal("sys_clone is not implemented for this ISA\n");
+        #endif
+
+        //Set up stack register
+        ctc->setIntReg(TheISA::StackPointerReg, tc->getSyscallArg(1));
+
+        //Set up syscall return values in parent and child
+        ctc->setIntReg(ReturnValueReg, 0); //return value, child
+
+        //Alpha needs SyscallSuccessReg=0 in child
+        #if THE_ISA == ALPHA_ISA
+            ctc->setIntReg(SyscallSuccessReg, 0);
+        #endif
+
+        //In SPARC/Linux, clone returns 0 on pseudo-return register if parent, non-zero if child
+        #if THE_ISA == SPARC_ISA
+            tc->setIntReg(TheISA::SyscallPseudoReturnReg, 0);
+            ctc->setIntReg(TheISA::SyscallPseudoReturnReg, 1);
+        #endif
+
+        ctc->setPC(tc->readNextPC());
+        ctc->setNextPC(tc->readNextPC() + sizeof(TheISA::MachInst));
+
+        //In SPARC, need NNPC too...
+        #if THE_ISA == SPARC_ISA
+            ctc->setNextNPC(tc->readNextNPC() + sizeof(TheISA::MachInst));
+        #endif
+
+        ctc->activate();
+
+        // Should return nonzero child TID in parent's syscall return register,
+        // but for our pthread library any non-zero value will work
+        return 1;
+    } else {
+        fatal("Called sys_clone, but no unallocated thread contexts found!\n");
+        return 0;
+    }
+}
+
index 0b0e736922732a15881ad0206608a03ecd1a8bd0..e995bd487fc1af3a25b13555de1ceeea29b0c14b 100644 (file)
@@ -183,10 +183,14 @@ SyscallReturn unimplementedFunc(SyscallDesc *desc, int num,
 SyscallReturn ignoreFunc(SyscallDesc *desc, int num,
                          LiveProcess *p, ThreadContext *tc);
 
-/// Target exit() handler: terminate simulation.
+/// Target exit() handler: terminate current context.
 SyscallReturn exitFunc(SyscallDesc *desc, int num,
                        LiveProcess *p, ThreadContext *tc);
 
+/// Target exit_group() handler: terminate simulation. (exit all threads)
+SyscallReturn exitGroupFunc(SyscallDesc *desc, int num,
+                       LiveProcess *p, ThreadContext *tc);
+
 /// Target getpagesize() handler.
 SyscallReturn getpagesizeFunc(SyscallDesc *desc, int num,
                               LiveProcess *p, ThreadContext *tc);
@@ -308,6 +312,9 @@ SyscallReturn geteuidFunc(SyscallDesc *desc, int num,
 SyscallReturn getegidFunc(SyscallDesc *desc, int num,
                                LiveProcess *p, ThreadContext *tc);
 
+/// Target clone() handler.
+SyscallReturn cloneFunc(SyscallDesc *desc, int num,
+                               LiveProcess *p, ThreadContext *tc);
 
 
 /// Pseudo Funcs  - These functions use a different return convension,
@@ -1013,8 +1020,8 @@ gettimeofdayFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
 
     getElapsedTime(tp->tv_sec, tp->tv_usec);
     tp->tv_sec += seconds_since_epoch;
-    tp->tv_sec = htog(tp->tv_sec);
-    tp->tv_usec = htog(tp->tv_usec);
+    tp->tv_sec = TheISA::htog(tp->tv_sec);
+    tp->tv_usec = TheISA::htog(tp->tv_usec);
 
     tp.copyOut(tc->getMemPort());