e0469744e51e48f7a9568e36c84ceb2ffff772c4
2 * Copyright (c) 2003-2005 The Regents of The University of Michigan
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are
7 * met: redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer;
9 * redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution;
12 * neither the name of the copyright holders nor the names of its
13 * contributors may be used to endorse or promote products derived from
14 * this software without specific prior written permission.
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 * Authors: Steve Reinhardt
39 #include "arch/utility.hh"
40 #include "sim/syscall_emul.hh"
41 #include "base/chunk_generator.hh"
42 #include "base/trace.hh"
43 #include "config/the_isa.hh"
44 #include "cpu/thread_context.hh"
45 #include "cpu/base.hh"
46 #include "mem/page_table.hh"
47 #include "sim/process.hh"
48 #include "sim/system.hh"
49 #include "sim/sim_exit.hh"
52 using namespace TheISA
;
55 SyscallDesc::doSyscall(int callnum
, LiveProcess
*process
, ThreadContext
*tc
)
60 DPRINTFR(SyscallVerbose
,
61 "%d: %s: syscall %s called w/arguments %d,%d,%d,%d\n",
62 curTick(), tc
->getCpuPtr()->name(), name
,
63 process
->getSyscallArg(tc
, index
),
64 process
->getSyscallArg(tc
, index
),
65 process
->getSyscallArg(tc
, index
),
66 process
->getSyscallArg(tc
, index
));
68 SyscallReturn retval
= (*funcPtr
)(this, callnum
, process
, tc
);
70 DPRINTFR(SyscallVerbose
, "%d: %s: syscall %s returns %d\n",
71 curTick(),tc
->getCpuPtr()->name(), name
, retval
.value());
73 if (!(flags
& SyscallDesc::SuppressReturnValue
))
74 process
->setSyscallReturn(tc
, retval
);
79 unimplementedFunc(SyscallDesc
*desc
, int callnum
, LiveProcess
*process
,
82 fatal("syscall %s (#%d) unimplemented.", desc
->name
, callnum
);
89 ignoreFunc(SyscallDesc
*desc
, int callnum
, LiveProcess
*process
,
93 warn("ignoring syscall %s(%d, %d, ...)", desc
->name
,
94 process
->getSyscallArg(tc
, index
), process
->getSyscallArg(tc
, index
));
101 exitFunc(SyscallDesc
*desc
, int callnum
, LiveProcess
*process
,
104 if (process
->system
->numRunningContexts() == 1) {
105 // Last running context... exit simulator
107 exitSimLoop("target called exit()",
108 process
->getSyscallArg(tc
, index
) & 0xff);
110 // other running threads... just halt this one
119 exitGroupFunc(SyscallDesc
*desc
, int callnum
, LiveProcess
*process
,
122 // really should just halt all thread contexts belonging to this
123 // process in case there's another process running...
125 exitSimLoop("target called exit()",
126 process
->getSyscallArg(tc
, index
) & 0xff);
133 getpagesizeFunc(SyscallDesc
*desc
, int num
, LiveProcess
*p
, ThreadContext
*tc
)
135 return (int)VMPageSize
;
140 brkFunc(SyscallDesc
*desc
, int num
, LiveProcess
*p
, ThreadContext
*tc
)
142 // change brk addr to first arg
144 Addr new_brk
= p
->getSyscallArg(tc
, index
);
146 // in Linux at least, brk(0) returns the current break value
147 // (note that the syscall and the glibc function have different behavior)
151 if (new_brk
> p
->brk_point
) {
152 // might need to allocate some new pages
153 for (ChunkGenerator
gen(p
->brk_point
, new_brk
- p
->brk_point
,
154 VMPageSize
); !gen
.done(); gen
.next()) {
155 if (!p
->pTable
->translate(gen
.addr()))
156 p
->pTable
->allocate(roundDown(gen
.addr(), VMPageSize
),
159 // if the address is already there, zero it out
162 TranslatingPort
*tp
= tc
->getMemPort();
164 // split non-page aligned accesses
165 Addr next_page
= roundUp(gen
.addr(), VMPageSize
);
166 uint32_t size_needed
= next_page
- gen
.addr();
167 tp
->memsetBlob(gen
.addr(), zero
, size_needed
);
168 if (gen
.addr() + VMPageSize
> next_page
&&
169 next_page
< new_brk
&&
170 p
->pTable
->translate(next_page
))
172 size_needed
= VMPageSize
- size_needed
;
173 tp
->memsetBlob(next_page
, zero
, size_needed
);
179 p
->brk_point
= new_brk
;
180 DPRINTF(SyscallVerbose
, "Break Point changed to: %#X\n", p
->brk_point
);
186 closeFunc(SyscallDesc
*desc
, int num
, LiveProcess
*p
, ThreadContext
*tc
)
189 int target_fd
= p
->getSyscallArg(tc
, index
);
190 int sim_fd
= p
->sim_fd(target_fd
);
193 status
= close(sim_fd
);
195 p
->free_fd(target_fd
);
201 readFunc(SyscallDesc
*desc
, int num
, LiveProcess
*p
, ThreadContext
*tc
)
204 int fd
= p
->sim_fd(p
->getSyscallArg(tc
, index
));
205 Addr bufPtr
= p
->getSyscallArg(tc
, index
);
206 int nbytes
= p
->getSyscallArg(tc
, index
);
207 BufferArg
bufArg(bufPtr
, nbytes
);
209 int bytes_read
= read(fd
, bufArg
.bufferPtr(), nbytes
);
211 if (bytes_read
!= -1)
212 bufArg
.copyOut(tc
->getMemPort());
218 writeFunc(SyscallDesc
*desc
, int num
, LiveProcess
*p
, ThreadContext
*tc
)
221 int fd
= p
->sim_fd(p
->getSyscallArg(tc
, index
));
222 Addr bufPtr
= p
->getSyscallArg(tc
, index
);
223 int nbytes
= p
->getSyscallArg(tc
, index
);
224 BufferArg
bufArg(bufPtr
, nbytes
);
226 bufArg
.copyIn(tc
->getMemPort());
228 int bytes_written
= write(fd
, bufArg
.bufferPtr(), nbytes
);
232 return bytes_written
;
237 lseekFunc(SyscallDesc
*desc
, int num
, LiveProcess
*p
, ThreadContext
*tc
)
240 int fd
= p
->sim_fd(p
->getSyscallArg(tc
, index
));
241 uint64_t offs
= p
->getSyscallArg(tc
, index
);
242 int whence
= p
->getSyscallArg(tc
, index
);
244 off_t result
= lseek(fd
, offs
, whence
);
246 return (result
== (off_t
)-1) ? -errno
: result
;
251 _llseekFunc(SyscallDesc
*desc
, int num
, LiveProcess
*p
, ThreadContext
*tc
)
254 int fd
= p
->sim_fd(p
->getSyscallArg(tc
, index
));
255 uint64_t offset_high
= p
->getSyscallArg(tc
, index
);
256 uint32_t offset_low
= p
->getSyscallArg(tc
, index
);
257 Addr result_ptr
= p
->getSyscallArg(tc
, index
);
258 int whence
= p
->getSyscallArg(tc
, index
);
260 uint64_t offset
= (offset_high
<< 32) | offset_low
;
262 uint64_t result
= lseek(fd
, offset
, whence
);
263 result
= TheISA::htog(result
);
265 if (result
== (off_t
)-1) {
269 // The seek succeeded.
270 // Copy "result" to "result_ptr"
271 // XXX We'll assume that the size of loff_t is 64 bits on the
273 BufferArg
result_buf(result_ptr
, sizeof(result
));
274 memcpy(result_buf
.bufferPtr(), &result
, sizeof(result
));
275 result_buf
.copyOut(tc
->getMemPort());
280 return (result
== (off_t
)-1) ? -errno
: result
;
285 munmapFunc(SyscallDesc
*desc
, int num
, LiveProcess
*p
, ThreadContext
*tc
)
287 // given that we don't really implement mmap, munmap is really easy
292 const char *hostname
= "m5.eecs.umich.edu";
295 gethostnameFunc(SyscallDesc
*desc
, int num
, LiveProcess
*p
, ThreadContext
*tc
)
298 Addr bufPtr
= p
->getSyscallArg(tc
, index
);
299 int name_len
= p
->getSyscallArg(tc
, index
);
300 BufferArg
name(bufPtr
, name_len
);
302 strncpy((char *)name
.bufferPtr(), hostname
, name_len
);
304 name
.copyOut(tc
->getMemPort());
310 getcwdFunc(SyscallDesc
*desc
, int num
, LiveProcess
*p
, ThreadContext
*tc
)
314 Addr bufPtr
= p
->getSyscallArg(tc
, index
);
315 unsigned long size
= p
->getSyscallArg(tc
, index
);
316 BufferArg
buf(bufPtr
, size
);
318 // Is current working directory defined?
319 string cwd
= p
->getcwd();
321 if (cwd
.length() >= size
) {
325 strncpy((char *)buf
.bufferPtr(), cwd
.c_str(), size
);
326 result
= cwd
.length();
329 if (getcwd((char *)buf
.bufferPtr(), size
) != NULL
) {
330 result
= strlen((char *)buf
.bufferPtr());
337 buf
.copyOut(tc
->getMemPort());
339 return (result
== -1) ? -errno
: result
;
344 readlinkFunc(SyscallDesc
*desc
, int num
, LiveProcess
*p
, ThreadContext
*tc
)
349 if (!tc
->getMemPort()->tryReadString(path
, p
->getSyscallArg(tc
, index
)))
350 return (TheISA::IntReg
)-EFAULT
;
352 // Adjust path for current working directory
353 path
= p
->fullPath(path
);
355 Addr bufPtr
= p
->getSyscallArg(tc
, index
);
356 size_t bufsiz
= p
->getSyscallArg(tc
, index
);
358 BufferArg
buf(bufPtr
, bufsiz
);
360 int result
= readlink(path
.c_str(), (char *)buf
.bufferPtr(), bufsiz
);
362 buf
.copyOut(tc
->getMemPort());
364 return (result
== -1) ? -errno
: result
;
368 unlinkFunc(SyscallDesc
*desc
, int num
, LiveProcess
*p
, ThreadContext
*tc
)
373 if (!tc
->getMemPort()->tryReadString(path
, p
->getSyscallArg(tc
, index
)))
374 return (TheISA::IntReg
)-EFAULT
;
376 // Adjust path for current working directory
377 path
= p
->fullPath(path
);
379 int result
= unlink(path
.c_str());
380 return (result
== -1) ? -errno
: result
;
385 mkdirFunc(SyscallDesc
*desc
, int num
, LiveProcess
*p
, ThreadContext
*tc
)
390 if (!tc
->getMemPort()->tryReadString(path
, p
->getSyscallArg(tc
, index
)))
391 return (TheISA::IntReg
)-EFAULT
;
393 // Adjust path for current working directory
394 path
= p
->fullPath(path
);
396 mode_t mode
= p
->getSyscallArg(tc
, index
);
398 int result
= mkdir(path
.c_str(), mode
);
399 return (result
== -1) ? -errno
: result
;
403 renameFunc(SyscallDesc
*desc
, int num
, LiveProcess
*p
, ThreadContext
*tc
)
408 if (!tc
->getMemPort()->tryReadString(old_name
, p
->getSyscallArg(tc
, index
)))
413 if (!tc
->getMemPort()->tryReadString(new_name
, p
->getSyscallArg(tc
, index
)))
416 // Adjust path for current working directory
417 old_name
= p
->fullPath(old_name
);
418 new_name
= p
->fullPath(new_name
);
420 int64_t result
= rename(old_name
.c_str(), new_name
.c_str());
421 return (result
== -1) ? -errno
: result
;
425 truncateFunc(SyscallDesc
*desc
, int num
, LiveProcess
*p
, ThreadContext
*tc
)
430 if (!tc
->getMemPort()->tryReadString(path
, p
->getSyscallArg(tc
, index
)))
433 off_t length
= p
->getSyscallArg(tc
, index
);
435 // Adjust path for current working directory
436 path
= p
->fullPath(path
);
438 int result
= truncate(path
.c_str(), length
);
439 return (result
== -1) ? -errno
: result
;
443 ftruncateFunc(SyscallDesc
*desc
, int num
,
444 LiveProcess
*process
, ThreadContext
*tc
)
447 int fd
= process
->sim_fd(process
->getSyscallArg(tc
, index
));
452 off_t length
= process
->getSyscallArg(tc
, index
);
454 int result
= ftruncate(fd
, length
);
455 return (result
== -1) ? -errno
: result
;
459 truncate64Func(SyscallDesc
*desc
, int num
,
460 LiveProcess
*process
, ThreadContext
*tc
)
465 if (!tc
->getMemPort()->tryReadString(path
, process
->getSyscallArg(tc
, index
)))
468 int64_t length
= process
->getSyscallArg(tc
, index
, 64);
470 // Adjust path for current working directory
471 path
= process
->fullPath(path
);
474 int result
= truncate(path
.c_str(), length
);
476 int result
= truncate64(path
.c_str(), length
);
478 return (result
== -1) ? -errno
: result
;
482 ftruncate64Func(SyscallDesc
*desc
, int num
,
483 LiveProcess
*process
, ThreadContext
*tc
)
486 int fd
= process
->sim_fd(process
->getSyscallArg(tc
, index
));
491 int64_t length
= process
->getSyscallArg(tc
, index
, 64);
494 int result
= ftruncate(fd
, length
);
496 int result
= ftruncate64(fd
, length
);
498 return (result
== -1) ? -errno
: result
;
502 umaskFunc(SyscallDesc
*desc
, int num
, LiveProcess
*process
, ThreadContext
*tc
)
504 // Letting the simulated program change the simulator's umask seems like
505 // a bad idea. Compromise by just returning the current umask but not
506 // changing anything.
507 mode_t oldMask
= umask(0);
513 chownFunc(SyscallDesc
*desc
, int num
, LiveProcess
*p
, ThreadContext
*tc
)
518 if (!tc
->getMemPort()->tryReadString(path
, p
->getSyscallArg(tc
, index
)))
522 uint32_t owner
= p
->getSyscallArg(tc
, index
);
523 uid_t hostOwner
= owner
;
524 uint32_t group
= p
->getSyscallArg(tc
, index
);
525 gid_t hostGroup
= group
;
527 // Adjust path for current working directory
528 path
= p
->fullPath(path
);
530 int result
= chown(path
.c_str(), hostOwner
, hostGroup
);
531 return (result
== -1) ? -errno
: result
;
535 fchownFunc(SyscallDesc
*desc
, int num
, LiveProcess
*process
, ThreadContext
*tc
)
538 int fd
= process
->sim_fd(process
->getSyscallArg(tc
, index
));
544 uint32_t owner
= process
->getSyscallArg(tc
, index
);
545 uid_t hostOwner
= owner
;
546 uint32_t group
= process
->getSyscallArg(tc
, index
);
547 gid_t hostGroup
= group
;
549 int result
= fchown(fd
, hostOwner
, hostGroup
);
550 return (result
== -1) ? -errno
: result
;
555 dupFunc(SyscallDesc
*desc
, int num
, LiveProcess
*process
, ThreadContext
*tc
)
558 int fd
= process
->sim_fd(process
->getSyscallArg(tc
, index
));
562 Process::FdMap
*fdo
= process
->sim_fd_obj(fd
);
564 int result
= dup(fd
);
565 return (result
== -1) ? -errno
:
566 process
->alloc_fd(result
, fdo
->filename
, fdo
->flags
, fdo
->mode
, false);
571 fcntlFunc(SyscallDesc
*desc
, int num
, LiveProcess
*process
,
575 int fd
= process
->getSyscallArg(tc
, index
);
577 if (fd
< 0 || process
->sim_fd(fd
) < 0)
580 int cmd
= process
->getSyscallArg(tc
, index
);
583 // if we really wanted to support this, we'd need to do it
584 // in the target fd space.
585 warn("fcntl(%d, F_DUPFD) not supported, error returned\n", fd
);
588 case 1: // F_GETFD (get close-on-exec flag)
589 case 2: // F_SETFD (set close-on-exec flag)
592 case 3: // F_GETFL (get file flags)
593 case 4: // F_SETFL (set file flags)
594 // not sure if this is totally valid, but we'll pass it through
595 // to the underlying OS
596 warn("fcntl(%d, %d) passed through to host\n", fd
, cmd
);
597 return fcntl(process
->sim_fd(fd
), cmd
);
600 case 7: // F_GETLK (get lock)
601 case 8: // F_SETLK (set lock)
602 case 9: // F_SETLKW (set lock and wait)
603 // don't mess with file locking... just act like it's OK
604 warn("File lock call (fcntl(%d, %d)) ignored.\n", fd
, cmd
);
608 warn("Unknown fcntl command %d\n", cmd
);
614 fcntl64Func(SyscallDesc
*desc
, int num
, LiveProcess
*process
,
618 int fd
= process
->getSyscallArg(tc
, index
);
620 if (fd
< 0 || process
->sim_fd(fd
) < 0)
623 int cmd
= process
->getSyscallArg(tc
, index
);
626 warn("fcntl64(%d, F_GETLK64) not supported, error returned\n", fd
);
629 case 34: // F_SETLK64
630 case 35: // F_SETLKW64
631 warn("fcntl64(%d, F_SETLK(W)64) not supported, error returned\n", fd
);
635 // not sure if this is totally valid, but we'll pass it through
636 // to the underlying OS
637 warn("fcntl64(%d, %d) passed through to host\n", fd
, cmd
);
638 return fcntl(process
->sim_fd(fd
), cmd
);
644 pipePseudoFunc(SyscallDesc
*desc
, int callnum
, LiveProcess
*process
,
647 int fds
[2], sim_fds
[2];
648 int pipe_retval
= pipe(fds
);
650 if (pipe_retval
< 0) {
655 sim_fds
[0] = process
->alloc_fd(fds
[0], "PIPE-READ", O_WRONLY
, -1, true);
656 sim_fds
[1] = process
->alloc_fd(fds
[1], "PIPE-WRITE", O_RDONLY
, -1, true);
658 process
->setReadPipeSource(sim_fds
[0], sim_fds
[1]);
659 // Alpha Linux convention for pipe() is that fd[0] is returned as
660 // the return value of the function, and fd[1] is returned in r20.
661 tc
->setIntReg(SyscallPseudoReturnReg
, sim_fds
[1]);
667 getpidPseudoFunc(SyscallDesc
*desc
, int callnum
, LiveProcess
*process
,
670 // Make up a PID. There's no interprocess communication in
671 // fake_syscall mode, so there's no way for a process to know it's
672 // not getting a unique value.
674 tc
->setIntReg(SyscallPseudoReturnReg
, process
->ppid());
675 return process
->pid();
680 getuidPseudoFunc(SyscallDesc
*desc
, int callnum
, LiveProcess
*process
,
683 // Make up a UID and EUID... it shouldn't matter, and we want the
684 // simulation to be deterministic.
687 tc
->setIntReg(SyscallPseudoReturnReg
, process
->euid()); //EUID
688 return process
->uid(); // UID
693 getgidPseudoFunc(SyscallDesc
*desc
, int callnum
, LiveProcess
*process
,
696 // Get current group ID. EGID goes in r20.
697 tc
->setIntReg(SyscallPseudoReturnReg
, process
->egid()); //EGID
698 return process
->gid();
703 setuidFunc(SyscallDesc
*desc
, int callnum
, LiveProcess
*process
,
706 // can't fathom why a benchmark would call this.
708 warn("Ignoring call to setuid(%d)\n", process
->getSyscallArg(tc
, index
));
713 getpidFunc(SyscallDesc
*desc
, int callnum
, LiveProcess
*process
,
716 // Make up a PID. There's no interprocess communication in
717 // fake_syscall mode, so there's no way for a process to know it's
718 // not getting a unique value.
720 tc
->setIntReg(SyscallPseudoReturnReg
, process
->ppid()); //PID
721 return process
->pid();
725 getppidFunc(SyscallDesc
*desc
, int callnum
, LiveProcess
*process
,
728 return process
->ppid();
732 getuidFunc(SyscallDesc
*desc
, int callnum
, LiveProcess
*process
,
735 return process
->uid(); // UID
739 geteuidFunc(SyscallDesc
*desc
, int callnum
, LiveProcess
*process
,
742 return process
->euid(); // UID
746 getgidFunc(SyscallDesc
*desc
, int callnum
, LiveProcess
*process
,
749 return process
->gid();
753 getegidFunc(SyscallDesc
*desc
, int callnum
, LiveProcess
*process
,
756 return process
->egid();
761 cloneFunc(SyscallDesc
*desc
, int callnum
, LiveProcess
*process
,
765 IntReg flags
= process
->getSyscallArg(tc
, index
);
766 IntReg newStack
= process
->getSyscallArg(tc
, index
);
768 DPRINTF(SyscallVerbose
, "In sys_clone:\n");
769 DPRINTF(SyscallVerbose
, " Flags=%llx\n", flags
);
770 DPRINTF(SyscallVerbose
, " Child stack=%llx\n", newStack
);
773 if (flags
!= 0x10f00) {
774 warn("This sys_clone implementation assumes flags "
775 "CLONE_VM|CLONE_FS|CLONE_FILES|CLONE_SIGHAND|CLONE_THREAD "
776 "(0x10f00), and may not work correctly with given flags "
780 ThreadContext
* ctc
; // child thread context
781 if ( ( ctc
= process
->findFreeContext() ) != NULL
) {
782 DPRINTF(SyscallVerbose
, " Found unallocated thread context\n");
784 ctc
->clearArchRegs();
786 // Arch-specific cloning code
787 #if THE_ISA == ALPHA_ISA or THE_ISA == X86_ISA
788 // Cloning the misc. regs for these archs is enough
789 TheISA::copyMiscRegs(tc
, ctc
);
790 #elif THE_ISA == SPARC_ISA
791 TheISA::copyRegs(tc
, ctc
);
793 // TODO: Explain what this code actually does :-)
794 ctc
->setIntReg(NumIntArchRegs
+ 6, 0);
795 ctc
->setIntReg(NumIntArchRegs
+ 4, 0);
796 ctc
->setIntReg(NumIntArchRegs
+ 3, NWindows
- 2);
797 ctc
->setIntReg(NumIntArchRegs
+ 5, NWindows
);
798 ctc
->setMiscReg(MISCREG_CWP
, 0);
799 ctc
->setIntReg(NumIntArchRegs
+ 7, 0);
800 ctc
->setMiscRegNoEffect(MISCREG_TL
, 0);
801 ctc
->setMiscRegNoEffect(MISCREG_ASI
, ASI_PRIMARY
);
803 for (int y
= 8; y
< 32; y
++)
804 ctc
->setIntReg(y
, tc
->readIntReg(y
));
806 fatal("sys_clone is not implemented for this ISA\n");
809 // Set up stack register
810 ctc
->setIntReg(TheISA::StackPointerReg
, newStack
);
812 // Set up syscall return values in parent and child
813 ctc
->setIntReg(ReturnValueReg
, 0); // return value, child
815 // Alpha needs SyscallSuccessReg=0 in child
816 #if THE_ISA == ALPHA_ISA
817 ctc
->setIntReg(TheISA::SyscallSuccessReg
, 0);
820 // In SPARC/Linux, clone returns 0 on pseudo-return register if
821 // parent, non-zero if child
822 #if THE_ISA == SPARC_ISA
823 tc
->setIntReg(TheISA::SyscallPseudoReturnReg
, 0);
824 ctc
->setIntReg(TheISA::SyscallPseudoReturnReg
, 1);
827 ctc
->pcState(tc
->nextInstAddr());
831 // Should return nonzero child TID in parent's syscall return register,
832 // but for our pthread library any non-zero value will work
835 fatal("Called sys_clone, but no unallocated thread contexts found!\n");