syscall_emul.cc revision 6109:083d8a76b7a6
1/*
2 * Copyright (c) 2003-2005 The Regents of The University of Michigan
3 * All rights reserved.
4 *
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.
15 *
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.
27 *
28 * Authors: Steve Reinhardt
29 *          Ali Saidi
30 */
31
32#include <fcntl.h>
33#include <unistd.h>
34
35#include <string>
36#include <iostream>
37
38#include "sim/syscall_emul.hh"
39#include "base/chunk_generator.hh"
40#include "base/trace.hh"
41#include "cpu/thread_context.hh"
42#include "cpu/base.hh"
43#include "mem/page_table.hh"
44#include "sim/process.hh"
45#include "sim/system.hh"
46
47#include "sim/sim_exit.hh"
48
49using namespace std;
50using namespace TheISA;
51
52void
53SyscallDesc::doSyscall(int callnum, LiveProcess *process, ThreadContext *tc)
54{
55    DPRINTFR(SyscallVerbose, "%d: %s: syscall %s called w/arguments %d,%d,%d,%d\n",
56             curTick,tc->getCpuPtr()->name(), name,
57             process->getSyscallArg(tc, 0), process->getSyscallArg(tc, 1),
58             process->getSyscallArg(tc, 2), process->getSyscallArg(tc, 3));
59
60    SyscallReturn retval = (*funcPtr)(this, callnum, process, tc);
61
62    DPRINTFR(SyscallVerbose, "%d: %s: syscall %s returns %d\n",
63             curTick,tc->getCpuPtr()->name(), name, retval.value());
64
65    if (!(flags & SyscallDesc::SuppressReturnValue))
66        process->setSyscallReturn(tc, retval);
67}
68
69
70SyscallReturn
71unimplementedFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
72                  ThreadContext *tc)
73{
74    fatal("syscall %s (#%d) unimplemented.", desc->name, callnum);
75
76    return 1;
77}
78
79
80SyscallReturn
81ignoreFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
82           ThreadContext *tc)
83{
84    warn("ignoring syscall %s(%d, %d, ...)", desc->name,
85         process->getSyscallArg(tc, 0), process->getSyscallArg(tc, 1));
86
87    return 0;
88}
89
90
91SyscallReturn
92exitFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
93         ThreadContext *tc)
94{
95    if (process->system->numRunningContexts() == 1) {
96        // Last running context... exit simulator
97        exitSimLoop("target called exit()",
98                    process->getSyscallArg(tc, 0) & 0xff);
99    } else {
100        // other running threads... just halt this one
101        tc->halt();
102    }
103
104    return 1;
105}
106
107
108SyscallReturn
109exitGroupFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
110              ThreadContext *tc)
111{
112    // really should just halt all thread contexts belonging to this
113    // process in case there's another process running...
114    exitSimLoop("target called exit()",
115                process->getSyscallArg(tc, 0) & 0xff);
116
117    return 1;
118}
119
120
121SyscallReturn
122getpagesizeFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc)
123{
124    return (int)VMPageSize;
125}
126
127
128SyscallReturn
129brkFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc)
130{
131    // change brk addr to first arg
132    Addr new_brk = p->getSyscallArg(tc, 0);
133
134    // in Linux at least, brk(0) returns the current break value
135    // (note that the syscall and the glibc function have different behavior)
136    if (new_brk == 0)
137        return p->brk_point;
138
139    if (new_brk > p->brk_point) {
140        // might need to allocate some new pages
141        for (ChunkGenerator gen(p->brk_point, new_brk - p->brk_point,
142                                VMPageSize); !gen.done(); gen.next()) {
143            if (!p->pTable->translate(gen.addr()))
144                p->pTable->allocate(roundDown(gen.addr(), VMPageSize),
145                                    VMPageSize);
146        }
147    }
148
149    p->brk_point = new_brk;
150    DPRINTF(SyscallVerbose, "Break Point changed to: %#X\n", p->brk_point);
151    return p->brk_point;
152}
153
154
155SyscallReturn
156closeFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc)
157{
158    int target_fd = p->getSyscallArg(tc, 0);
159    int status = close(p->sim_fd(target_fd));
160    if (status >= 0)
161        p->free_fd(target_fd);
162    return status;
163}
164
165
166SyscallReturn
167readFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc)
168{
169    int fd = p->sim_fd(p->getSyscallArg(tc, 0));
170    int nbytes = p->getSyscallArg(tc, 2);
171    BufferArg bufArg(p->getSyscallArg(tc, 1), nbytes);
172
173    int bytes_read = read(fd, bufArg.bufferPtr(), nbytes);
174
175    if (bytes_read != -1)
176        bufArg.copyOut(tc->getMemPort());
177
178    return bytes_read;
179}
180
181SyscallReturn
182writeFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc)
183{
184    int fd = p->sim_fd(p->getSyscallArg(tc, 0));
185    int nbytes = p->getSyscallArg(tc, 2);
186    BufferArg bufArg(p->getSyscallArg(tc, 1), nbytes);
187
188    bufArg.copyIn(tc->getMemPort());
189
190    int bytes_written = write(fd, bufArg.bufferPtr(), nbytes);
191
192    fsync(fd);
193
194    return bytes_written;
195}
196
197
198SyscallReturn
199lseekFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc)
200{
201    int fd = p->sim_fd(p->getSyscallArg(tc, 0));
202    uint64_t offs = p->getSyscallArg(tc, 1);
203    int whence = p->getSyscallArg(tc, 2);
204
205    off_t result = lseek(fd, offs, whence);
206
207    return (result == (off_t)-1) ? -errno : result;
208}
209
210
211SyscallReturn
212_llseekFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc)
213{
214    int fd = p->sim_fd(p->getSyscallArg(tc, 0));
215    uint64_t offset_high = p->getSyscallArg(tc, 1);
216    uint32_t offset_low = p->getSyscallArg(tc, 2);
217    Addr result_ptr = p->getSyscallArg(tc, 3);
218    int whence = p->getSyscallArg(tc, 4);
219
220    uint64_t offset = (offset_high << 32) | offset_low;
221
222    uint64_t result = lseek(fd, offset, whence);
223    result = TheISA::htog(result);
224
225    if (result == (off_t)-1) {
226        //The seek failed.
227        return -errno;
228    } else {
229        //The seek succeeded.
230        //Copy "result" to "result_ptr"
231        //XXX We'll assume that the size of loff_t is 64 bits on the
232        //target platform
233        BufferArg result_buf(result_ptr, sizeof(result));
234        memcpy(result_buf.bufferPtr(), &result, sizeof(result));
235        result_buf.copyOut(tc->getMemPort());
236        return 0;
237    }
238
239
240    return (result == (off_t)-1) ? -errno : result;
241}
242
243
244SyscallReturn
245munmapFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc)
246{
247    // given that we don't really implement mmap, munmap is really easy
248    return 0;
249}
250
251
252const char *hostname = "m5.eecs.umich.edu";
253
254SyscallReturn
255gethostnameFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc)
256{
257    int name_len = p->getSyscallArg(tc, 1);
258    BufferArg name(p->getSyscallArg(tc, 0), name_len);
259
260    strncpy((char *)name.bufferPtr(), hostname, name_len);
261
262    name.copyOut(tc->getMemPort());
263
264    return 0;
265}
266
267SyscallReturn
268getcwdFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc)
269{
270    int result = 0;
271    unsigned long size = p->getSyscallArg(tc, 1);
272    BufferArg buf(p->getSyscallArg(tc, 0), size);
273
274    // Is current working directory defined?
275    string cwd = p->getcwd();
276    if (!cwd.empty()) {
277        if (cwd.length() >= size) {
278            // Buffer too small
279            return -ERANGE;
280        }
281        strncpy((char *)buf.bufferPtr(), cwd.c_str(), size);
282        result = cwd.length();
283    }
284    else {
285        if (getcwd((char *)buf.bufferPtr(), size) != NULL) {
286            result = strlen((char *)buf.bufferPtr());
287        }
288        else {
289            result = -1;
290        }
291    }
292
293    buf.copyOut(tc->getMemPort());
294
295    return (result == -1) ? -errno : result;
296}
297
298
299SyscallReturn
300readlinkFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc)
301{
302    string path;
303
304    if (!tc->getMemPort()->tryReadString(path, p->getSyscallArg(tc, 0)))
305        return (TheISA::IntReg)-EFAULT;
306
307    // Adjust path for current working directory
308    path = p->fullPath(path);
309
310    size_t bufsiz = p->getSyscallArg(tc, 2);
311    BufferArg buf(p->getSyscallArg(tc, 1), bufsiz);
312
313    int result = readlink(path.c_str(), (char *)buf.bufferPtr(), bufsiz);
314
315    buf.copyOut(tc->getMemPort());
316
317    return (result == -1) ? -errno : result;
318}
319
320SyscallReturn
321unlinkFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc)
322{
323    string path;
324
325    if (!tc->getMemPort()->tryReadString(path, p->getSyscallArg(tc, 0)))
326        return (TheISA::IntReg)-EFAULT;
327
328    // Adjust path for current working directory
329    path = p->fullPath(path);
330
331    int result = unlink(path.c_str());
332    return (result == -1) ? -errno : result;
333}
334
335
336SyscallReturn
337mkdirFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc)
338{
339    string path;
340
341    if (!tc->getMemPort()->tryReadString(path, p->getSyscallArg(tc, 0)))
342        return (TheISA::IntReg)-EFAULT;
343
344    // Adjust path for current working directory
345    path = p->fullPath(path);
346
347    mode_t mode = p->getSyscallArg(tc, 1);
348
349    int result = mkdir(path.c_str(), mode);
350    return (result == -1) ? -errno : result;
351}
352
353SyscallReturn
354renameFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc)
355{
356    string old_name;
357
358    if (!tc->getMemPort()->tryReadString(old_name, p->getSyscallArg(tc, 0)))
359        return -EFAULT;
360
361    string new_name;
362
363    if (!tc->getMemPort()->tryReadString(new_name, p->getSyscallArg(tc, 1)))
364        return -EFAULT;
365
366    // Adjust path for current working directory
367    old_name = p->fullPath(old_name);
368    new_name = p->fullPath(new_name);
369
370    int64_t result = rename(old_name.c_str(), new_name.c_str());
371    return (result == -1) ? -errno : result;
372}
373
374SyscallReturn
375truncateFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc)
376{
377    string path;
378
379    if (!tc->getMemPort()->tryReadString(path, p->getSyscallArg(tc, 0)))
380        return -EFAULT;
381
382    off_t length = p->getSyscallArg(tc, 1);
383
384    // Adjust path for current working directory
385    path = p->fullPath(path);
386
387    int result = truncate(path.c_str(), length);
388    return (result == -1) ? -errno : result;
389}
390
391SyscallReturn
392ftruncateFunc(SyscallDesc *desc, int num, LiveProcess *process, ThreadContext *tc)
393{
394    int fd = process->sim_fd(process->getSyscallArg(tc, 0));
395
396    if (fd < 0)
397        return -EBADF;
398
399    off_t length = process->getSyscallArg(tc, 1);
400
401    int result = ftruncate(fd, length);
402    return (result == -1) ? -errno : result;
403}
404
405SyscallReturn
406umaskFunc(SyscallDesc *desc, int num, LiveProcess *process, ThreadContext *tc)
407{
408    // Letting the simulated program change the simulator's umask seems like
409    // a bad idea.  Compromise by just returning the current umask but not
410    // changing anything.
411    mode_t oldMask = umask(0);
412    umask(oldMask);
413    return (int)oldMask;
414}
415
416SyscallReturn
417chownFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc)
418{
419    string path;
420
421    if (!tc->getMemPort()->tryReadString(path, p->getSyscallArg(tc, 0)))
422        return -EFAULT;
423
424    /* XXX endianess */
425    uint32_t owner = p->getSyscallArg(tc, 1);
426    uid_t hostOwner = owner;
427    uint32_t group = p->getSyscallArg(tc, 2);
428    gid_t hostGroup = group;
429
430    // Adjust path for current working directory
431    path = p->fullPath(path);
432
433    int result = chown(path.c_str(), hostOwner, hostGroup);
434    return (result == -1) ? -errno : result;
435}
436
437SyscallReturn
438fchownFunc(SyscallDesc *desc, int num, LiveProcess *process, ThreadContext *tc)
439{
440    int fd = process->sim_fd(process->getSyscallArg(tc, 0));
441
442    if (fd < 0)
443        return -EBADF;
444
445    /* XXX endianess */
446    uint32_t owner = process->getSyscallArg(tc, 1);
447    uid_t hostOwner = owner;
448    uint32_t group = process->getSyscallArg(tc, 2);
449    gid_t hostGroup = group;
450
451    int result = fchown(fd, hostOwner, hostGroup);
452    return (result == -1) ? -errno : result;
453}
454
455
456SyscallReturn
457dupFunc(SyscallDesc *desc, int num, LiveProcess *process, ThreadContext *tc)
458{
459    int fd = process->sim_fd(process->getSyscallArg(tc, 0));
460    if (fd < 0)
461        return -EBADF;
462
463    Process::FdMap *fdo = process->sim_fd_obj(process->getSyscallArg(tc, 0));
464
465    int result = dup(fd);
466    return (result == -1) ? -errno : process->alloc_fd(result, fdo->filename, fdo->flags, fdo->mode, false);
467}
468
469
470SyscallReturn
471fcntlFunc(SyscallDesc *desc, int num, LiveProcess *process,
472          ThreadContext *tc)
473{
474    int fd = process->getSyscallArg(tc, 0);
475
476    if (fd < 0 || process->sim_fd(fd) < 0)
477        return -EBADF;
478
479    int cmd = process->getSyscallArg(tc, 1);
480    switch (cmd) {
481      case 0: // F_DUPFD
482        // if we really wanted to support this, we'd need to do it
483        // in the target fd space.
484        warn("fcntl(%d, F_DUPFD) not supported, error returned\n", fd);
485        return -EMFILE;
486
487      case 1: // F_GETFD (get close-on-exec flag)
488      case 2: // F_SETFD (set close-on-exec flag)
489        return 0;
490
491      case 3: // F_GETFL (get file flags)
492      case 4: // F_SETFL (set file flags)
493        // not sure if this is totally valid, but we'll pass it through
494        // to the underlying OS
495        warn("fcntl(%d, %d) passed through to host\n", fd, cmd);
496        return fcntl(process->sim_fd(fd), cmd);
497        // return 0;
498
499      case 7: // F_GETLK  (get lock)
500      case 8: // F_SETLK  (set lock)
501      case 9: // F_SETLKW (set lock and wait)
502        // don't mess with file locking... just act like it's OK
503        warn("File lock call (fcntl(%d, %d)) ignored.\n", fd, cmd);
504        return 0;
505
506      default:
507        warn("Unknown fcntl command %d\n", cmd);
508        return 0;
509    }
510}
511
512SyscallReturn
513fcntl64Func(SyscallDesc *desc, int num, LiveProcess *process,
514            ThreadContext *tc)
515{
516    int fd = process->getSyscallArg(tc, 0);
517
518    if (fd < 0 || process->sim_fd(fd) < 0)
519        return -EBADF;
520
521    int cmd = process->getSyscallArg(tc, 1);
522    switch (cmd) {
523      case 33: //F_GETLK64
524        warn("fcntl64(%d, F_GETLK64) not supported, error returned\n", fd);
525        return -EMFILE;
526
527      case 34: // F_SETLK64
528      case 35: // F_SETLKW64
529        warn("fcntl64(%d, F_SETLK(W)64) not supported, error returned\n", fd);
530        return -EMFILE;
531
532      default:
533        // not sure if this is totally valid, but we'll pass it through
534        // to the underlying OS
535        warn("fcntl64(%d, %d) passed through to host\n", fd, cmd);
536        return fcntl(process->sim_fd(fd), cmd);
537        // return 0;
538    }
539}
540
541SyscallReturn
542pipePseudoFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
543         ThreadContext *tc)
544{
545    int fds[2], sim_fds[2];
546    int pipe_retval = pipe(fds);
547
548    if (pipe_retval < 0) {
549        // error
550        return pipe_retval;
551    }
552
553    sim_fds[0] = process->alloc_fd(fds[0], "PIPE-READ", O_WRONLY, -1, true);
554    sim_fds[1] = process->alloc_fd(fds[1], "PIPE-WRITE", O_RDONLY, -1, true);
555
556    process->setReadPipeSource(sim_fds[0], sim_fds[1]);
557    // Alpha Linux convention for pipe() is that fd[0] is returned as
558    // the return value of the function, and fd[1] is returned in r20.
559    tc->setIntReg(SyscallPseudoReturnReg, sim_fds[1]);
560    return sim_fds[0];
561}
562
563
564SyscallReturn
565getpidPseudoFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
566           ThreadContext *tc)
567{
568    // Make up a PID.  There's no interprocess communication in
569    // fake_syscall mode, so there's no way for a process to know it's
570    // not getting a unique value.
571
572    tc->setIntReg(SyscallPseudoReturnReg, process->ppid());
573    return process->pid();
574}
575
576
577SyscallReturn
578getuidPseudoFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
579           ThreadContext *tc)
580{
581    // Make up a UID and EUID... it shouldn't matter, and we want the
582    // simulation to be deterministic.
583
584    // EUID goes in r20.
585    tc->setIntReg(SyscallPseudoReturnReg, process->euid()); //EUID
586    return process->uid();              // UID
587}
588
589
590SyscallReturn
591getgidPseudoFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
592           ThreadContext *tc)
593{
594    // Get current group ID.  EGID goes in r20.
595    tc->setIntReg(SyscallPseudoReturnReg, process->egid()); //EGID
596    return process->gid();
597}
598
599
600SyscallReturn
601setuidFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
602           ThreadContext *tc)
603{
604    // can't fathom why a benchmark would call this.
605    warn("Ignoring call to setuid(%d)\n", process->getSyscallArg(tc, 0));
606    return 0;
607}
608
609SyscallReturn
610getpidFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
611           ThreadContext *tc)
612{
613    // Make up a PID.  There's no interprocess communication in
614    // fake_syscall mode, so there's no way for a process to know it's
615    // not getting a unique value.
616
617    tc->setIntReg(SyscallPseudoReturnReg, process->ppid()); //PID
618    return process->pid();
619}
620
621SyscallReturn
622getppidFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
623           ThreadContext *tc)
624{
625    return process->ppid();
626}
627
628SyscallReturn
629getuidFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
630           ThreadContext *tc)
631{
632    return process->uid();              // UID
633}
634
635SyscallReturn
636geteuidFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
637           ThreadContext *tc)
638{
639    return process->euid();             // UID
640}
641
642SyscallReturn
643getgidFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
644           ThreadContext *tc)
645{
646    return process->gid();
647}
648
649SyscallReturn
650getegidFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
651           ThreadContext *tc)
652{
653    return process->egid();
654}
655
656
657SyscallReturn
658cloneFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
659           ThreadContext *tc)
660{
661    DPRINTF(SyscallVerbose, "In sys_clone:\n");
662    DPRINTF(SyscallVerbose, " Flags=%llx\n", tc->getSyscallArg(0));
663    DPRINTF(SyscallVerbose, " Child stack=%llx\n", tc->getSyscallArg(1));
664
665
666    if (tc->getSyscallArg(0) != 0x10f00) {
667        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));
668    }
669
670    ThreadContext* ctc; //child thread context
671    if ( ( ctc = process->findFreeContext() ) != NULL ) {
672        DPRINTF(SyscallVerbose, " Found unallocated thread context\n");
673
674        ctc->clearArchRegs();
675
676        //Arch-specific cloning code
677        #if THE_ISA == ALPHA_ISA or THE_ISA == X86_ISA
678            //Cloning the misc. regs for these archs is enough
679            TheISA::copyMiscRegs(tc, ctc);
680        #elif THE_ISA == SPARC_ISA
681            TheISA::copyRegs(tc, ctc);
682
683            //TODO: Explain what this code actually does :-)
684            ctc->setIntReg(NumIntArchRegs + 6, 0);
685            ctc->setIntReg(NumIntArchRegs + 4, 0);
686            ctc->setIntReg(NumIntArchRegs + 3, NWindows - 2);
687            ctc->setIntReg(NumIntArchRegs + 5, NWindows);
688            ctc->setMiscRegNoEffect(MISCREG_CWP, 0);
689            ctc->setIntReg(NumIntArchRegs + 7, 0);
690            ctc->setMiscRegNoEffect(MISCREG_TL, 0);
691            ctc->setMiscRegNoEffect(MISCREG_ASI, ASI_PRIMARY);
692
693            for (int y = 8; y < 32; y++)
694                ctc->setIntReg(y, tc->readIntReg(y));
695        #else
696            fatal("sys_clone is not implemented for this ISA\n");
697        #endif
698
699        //Set up stack register
700        ctc->setIntReg(TheISA::StackPointerReg, tc->getSyscallArg(1));
701
702        //Set up syscall return values in parent and child
703        ctc->setIntReg(ReturnValueReg, 0); //return value, child
704
705        //Alpha needs SyscallSuccessReg=0 in child
706        #if THE_ISA == ALPHA_ISA
707            ctc->setIntReg(SyscallSuccessReg, 0);
708        #endif
709
710        //In SPARC/Linux, clone returns 0 on pseudo-return register if parent, non-zero if child
711        #if THE_ISA == SPARC_ISA
712            tc->setIntReg(TheISA::SyscallPseudoReturnReg, 0);
713            ctc->setIntReg(TheISA::SyscallPseudoReturnReg, 1);
714        #endif
715
716        ctc->setPC(tc->readNextPC());
717        ctc->setNextPC(tc->readNextPC() + sizeof(TheISA::MachInst));
718
719        //In SPARC, need NNPC too...
720        #if THE_ISA == SPARC_ISA
721            ctc->setNextNPC(tc->readNextNPC() + sizeof(TheISA::MachInst));
722        #endif
723
724        ctc->activate();
725
726        // Should return nonzero child TID in parent's syscall return register,
727        // but for our pthread library any non-zero value will work
728        return 1;
729    } else {
730        fatal("Called sys_clone, but no unallocated thread contexts found!\n");
731        return 0;
732    }
733}
734
735