From: Daniel Sanchez Date: Tue, 21 Apr 2009 15:17:36 +0000 (-0700) Subject: Commit m5threads package. X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=b0e9654f8621729400ba627ed8c9bd0bf3833f7a;p=gem5.git Commit m5threads package. 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. --- diff --git a/src/arch/alpha/linux/process.cc b/src/arch/alpha/linux/process.cc index aeff9fbed..9886c7ea7 100644 --- a/src/arch/alpha/linux/process.cc +++ b/src/arch/alpha/linux/process.cc @@ -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), diff --git a/src/arch/sparc/linux/syscalls.cc b/src/arch/sparc/linux/syscalls.cc index d9651c85c..f4781d886 100644 --- a/src/arch/sparc/linux/syscalls.cc +++ b/src/arch/sparc/linux/syscalls.cc @@ -162,7 +162,7 @@ SyscallDesc SparcLinuxProcess::syscall32Descs[] = { /* 71 */ SyscallDesc("mmap", mmapFunc), /* 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), //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), /* 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), /* 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), diff --git a/src/arch/sparc/regfile.cc b/src/arch/sparc/regfile.cc index 1c172a4d5..4efac3d4e 100644 --- a/src/arch/sparc/regfile.cc +++ b/src/arch/sparc/regfile.cc @@ -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()); } + diff --git a/src/arch/x86/linux/syscalls.cc b/src/arch/x86/linux/syscalls.cc index 49a7d8b77..4d7bca95c 100644 --- a/src/arch/x86/linux/syscalls.cc +++ b/src/arch/x86/linux/syscalls.cc @@ -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), diff --git a/src/arch/x86/regfile.cc b/src/arch/x86/regfile.cc index 7d01c4bb4..83279902e 100644 --- a/src/arch/x86/regfile.cc +++ b/src/arch/x86/regfile.cc @@ -250,7 +250,17 @@ RegFile::unserialize(EventManager *em, Checkpoint *cp, const string §ion) 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) diff --git a/src/sim/syscall_emul.cc b/src/sim/syscall_emul.cc index f0a693db0..d3161de26 100644 --- a/src/sim/syscall_emul.cc +++ b/src/sim/syscall_emul.cc @@ -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; + } +} + diff --git a/src/sim/syscall_emul.hh b/src/sim/syscall_emul.hh index 0b0e73692..e995bd487 100644 --- a/src/sim/syscall_emul.hh +++ b/src/sim/syscall_emul.hh @@ -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());