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