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.
This commit is contained in:
Daniel Sanchez 2009-04-21 08:17:36 -07:00
parent b0489d18ed
commit b0e9654f86
7 changed files with 156 additions and 25 deletions

View 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),

View 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),

View 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());
}

View 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),

View 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)

View 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;
}
}

View 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());