syscall_emul.cc revision 11856:103e2f92c965
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 "sim/syscall_emul.hh"
33
34#include <fcntl.h>
35#include <unistd.h>
36
37#include <iostream>
38#include <string>
39
40#include "arch/utility.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 "mem/page_table.hh"
46#include "sim/process.hh"
47#include "sim/sim_exit.hh"
48#include "sim/syscall_debug_macros.hh"
49#include "sim/syscall_desc.hh"
50#include "sim/system.hh"
51
52using namespace std;
53using namespace TheISA;
54
55SyscallReturn
56unimplementedFunc(SyscallDesc *desc, int callnum, Process *process,
57                  ThreadContext *tc)
58{
59    fatal("syscall %s (#%d) unimplemented.", desc->name(), callnum);
60
61    return 1;
62}
63
64
65SyscallReturn
66ignoreFunc(SyscallDesc *desc, int callnum, Process *process,
67           ThreadContext *tc)
68{
69    if (desc->needWarning()) {
70        warn("ignoring syscall %s(...)%s", desc->name(), desc->warnOnce() ?
71             "\n      (further warnings will be suppressed)" : "");
72    }
73
74    return 0;
75}
76
77
78SyscallReturn
79exitFunc(SyscallDesc *desc, int callnum, Process *process,
80         ThreadContext *tc)
81{
82    if (process->system->numRunningContexts() == 1) {
83        // Last running context... exit simulator
84        int index = 0;
85        exitSimLoop("target called exit()",
86                    process->getSyscallArg(tc, index) & 0xff);
87    } else {
88        // other running threads... just halt this one
89        tc->halt();
90    }
91
92    return 1;
93}
94
95
96SyscallReturn
97exitGroupFunc(SyscallDesc *desc, int callnum, Process *process,
98              ThreadContext *tc)
99{
100    // halt all threads belonging to this process
101    for (auto i: process->contextIds) {
102        process->system->getThreadContext(i)->halt();
103    }
104
105    if (!process->system->numRunningContexts()) {
106        // all threads belonged to this process... exit simulator
107        int index = 0;
108        exitSimLoop("target called exit()",
109                    process->getSyscallArg(tc, index) & 0xff);
110    }
111
112    return 1;
113}
114
115
116SyscallReturn
117getpagesizeFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
118{
119    return (int)PageBytes;
120}
121
122
123SyscallReturn
124brkFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
125{
126    // change brk addr to first arg
127    int index = 0;
128    Addr new_brk = p->getSyscallArg(tc, index);
129
130    // in Linux at least, brk(0) returns the current break value
131    // (note that the syscall and the glibc function have different behavior)
132    if (new_brk == 0)
133        return p->brk_point;
134
135    if (new_brk > p->brk_point) {
136        // might need to allocate some new pages
137        for (ChunkGenerator gen(p->brk_point, new_brk - p->brk_point,
138                                PageBytes); !gen.done(); gen.next()) {
139            if (!p->pTable->translate(gen.addr()))
140                p->allocateMem(roundDown(gen.addr(), PageBytes), PageBytes);
141
142            // if the address is already there, zero it out
143            else {
144                uint8_t zero  = 0;
145                SETranslatingPortProxy &tp = tc->getMemProxy();
146
147                // split non-page aligned accesses
148                Addr next_page = roundUp(gen.addr(), PageBytes);
149                uint32_t size_needed = next_page - gen.addr();
150                tp.memsetBlob(gen.addr(), zero, size_needed);
151                if (gen.addr() + PageBytes > next_page &&
152                    next_page < new_brk &&
153                    p->pTable->translate(next_page))
154                {
155                    size_needed = PageBytes - size_needed;
156                    tp.memsetBlob(next_page, zero, size_needed);
157                }
158            }
159        }
160    }
161
162    p->brk_point = new_brk;
163    DPRINTF_SYSCALL(Verbose, "brk: break point changed to: %#X\n",
164                    p->brk_point);
165    return p->brk_point;
166}
167
168
169SyscallReturn
170closeFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
171{
172    int index = 0;
173    int tgt_fd = p->getSyscallArg(tc, index);
174
175    return p->fds->closeFDEntry(tgt_fd);
176}
177
178
179SyscallReturn
180readFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
181{
182    int index = 0;
183    int tgt_fd = p->getSyscallArg(tc, index);
184    Addr bufPtr = p->getSyscallArg(tc, index);
185    int nbytes = p->getSyscallArg(tc, index);
186
187    auto hbfdp = std::dynamic_pointer_cast<HBFDEntry>((*p->fds)[tgt_fd]);
188    if (!hbfdp)
189        return -EBADF;
190    int sim_fd = hbfdp->getSimFD();
191
192    BufferArg bufArg(bufPtr, nbytes);
193    int bytes_read = read(sim_fd, bufArg.bufferPtr(), nbytes);
194
195    if (bytes_read > 0)
196        bufArg.copyOut(tc->getMemProxy());
197
198    return bytes_read;
199}
200
201SyscallReturn
202writeFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
203{
204    int index = 0;
205    int tgt_fd = p->getSyscallArg(tc, index);
206    Addr bufPtr = p->getSyscallArg(tc, index);
207    int nbytes = p->getSyscallArg(tc, index);
208
209    auto hbfdp = std::dynamic_pointer_cast<HBFDEntry>((*p->fds)[tgt_fd]);
210    if (!hbfdp)
211        return -EBADF;
212    int sim_fd = hbfdp->getSimFD();
213
214    BufferArg bufArg(bufPtr, nbytes);
215    bufArg.copyIn(tc->getMemProxy());
216
217    int bytes_written = write(sim_fd, bufArg.bufferPtr(), nbytes);
218
219    fsync(sim_fd);
220
221    return bytes_written;
222}
223
224
225SyscallReturn
226lseekFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
227{
228    int index = 0;
229    int tgt_fd = p->getSyscallArg(tc, index);
230    uint64_t offs = p->getSyscallArg(tc, index);
231    int whence = p->getSyscallArg(tc, index);
232
233    auto ffdp = std::dynamic_pointer_cast<FileFDEntry>((*p->fds)[tgt_fd]);
234    if (!ffdp)
235        return -EBADF;
236    int sim_fd = ffdp->getSimFD();
237
238    off_t result = lseek(sim_fd, offs, whence);
239
240    return (result == (off_t)-1) ? -errno : result;
241}
242
243
244SyscallReturn
245_llseekFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
246{
247    int index = 0;
248    int tgt_fd = p->getSyscallArg(tc, index);
249    uint64_t offset_high = p->getSyscallArg(tc, index);
250    uint32_t offset_low = p->getSyscallArg(tc, index);
251    Addr result_ptr = p->getSyscallArg(tc, index);
252    int whence = p->getSyscallArg(tc, index);
253
254    auto ffdp = std::dynamic_pointer_cast<FileFDEntry>((*p->fds)[tgt_fd]);
255    if (!ffdp)
256        return -EBADF;
257    int sim_fd = ffdp->getSimFD();
258
259    uint64_t offset = (offset_high << 32) | offset_low;
260
261    uint64_t result = lseek(sim_fd, offset, whence);
262    result = TheISA::htog(result);
263
264    if (result == (off_t)-1)
265        return -errno;
266    // Assuming that the size of loff_t is 64 bits on the target platform
267    BufferArg result_buf(result_ptr, sizeof(result));
268    memcpy(result_buf.bufferPtr(), &result, sizeof(result));
269    result_buf.copyOut(tc->getMemProxy());
270    return 0;
271}
272
273
274SyscallReturn
275munmapFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
276{
277    // With mmap more fully implemented, it might be worthwhile to bite
278    // the bullet and implement munmap. Should allow us to reuse simulated
279    // memory.
280    return 0;
281}
282
283
284const char *hostname = "m5.eecs.umich.edu";
285
286SyscallReturn
287gethostnameFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
288{
289    int index = 0;
290    Addr bufPtr = p->getSyscallArg(tc, index);
291    int name_len = p->getSyscallArg(tc, index);
292    BufferArg name(bufPtr, name_len);
293
294    strncpy((char *)name.bufferPtr(), hostname, name_len);
295
296    name.copyOut(tc->getMemProxy());
297
298    return 0;
299}
300
301SyscallReturn
302getcwdFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
303{
304    int result = 0;
305    int index = 0;
306    Addr bufPtr = p->getSyscallArg(tc, index);
307    unsigned long size = p->getSyscallArg(tc, index);
308    BufferArg buf(bufPtr, size);
309
310    // Is current working directory defined?
311    string cwd = p->getcwd();
312    if (!cwd.empty()) {
313        if (cwd.length() >= size) {
314            // Buffer too small
315            return -ERANGE;
316        }
317        strncpy((char *)buf.bufferPtr(), cwd.c_str(), size);
318        result = cwd.length();
319    } else {
320        if (getcwd((char *)buf.bufferPtr(), size)) {
321            result = strlen((char *)buf.bufferPtr());
322        } else {
323            result = -1;
324        }
325    }
326
327    buf.copyOut(tc->getMemProxy());
328
329    return (result == -1) ? -errno : result;
330}
331
332/// Target open() handler.
333SyscallReturn
334readlinkFunc(SyscallDesc *desc, int callnum, Process *process,
335             ThreadContext *tc)
336{
337    return readlinkFunc(desc, callnum, process, tc, 0);
338}
339
340SyscallReturn
341readlinkFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc,
342             int index)
343{
344    string path;
345
346    if (!tc->getMemProxy().tryReadString(path, p->getSyscallArg(tc, index)))
347        return -EFAULT;
348
349    // Adjust path for current working directory
350    path = p->fullPath(path);
351
352    Addr bufPtr = p->getSyscallArg(tc, index);
353    size_t bufsiz = p->getSyscallArg(tc, index);
354
355    BufferArg buf(bufPtr, bufsiz);
356
357    int result = -1;
358    if (path != "/proc/self/exe") {
359        result = readlink(path.c_str(), (char *)buf.bufferPtr(), bufsiz);
360    } else {
361        // Emulate readlink() called on '/proc/self/exe' should return the
362        // absolute path of the binary running in the simulated system (the
363        // Process' executable). It is possible that using this path in
364        // the simulated system will result in unexpected behavior if:
365        //  1) One binary runs another (e.g., -c time -o "my_binary"), and
366        //     called binary calls readlink().
367        //  2) The host's full path to the running benchmark changes from one
368        //     simulation to another. This can result in different simulated
369        //     performance since the simulated system will process the binary
370        //     path differently, even if the binary itself does not change.
371
372        // Get the absolute canonical path to the running application
373        char real_path[PATH_MAX];
374        char *check_real_path = realpath(p->progName(), real_path);
375        if (!check_real_path) {
376            fatal("readlink('/proc/self/exe') unable to resolve path to "
377                  "executable: %s", p->progName());
378        }
379        strncpy((char*)buf.bufferPtr(), real_path, bufsiz);
380        size_t real_path_len = strlen(real_path);
381        if (real_path_len > bufsiz) {
382            // readlink will truncate the contents of the
383            // path to ensure it is no more than bufsiz
384            result = bufsiz;
385        } else {
386            result = real_path_len;
387        }
388
389        // Issue a warning about potential unexpected results
390        warn_once("readlink() called on '/proc/self/exe' may yield unexpected "
391                  "results in various settings.\n      Returning '%s'\n",
392                  (char*)buf.bufferPtr());
393    }
394
395    buf.copyOut(tc->getMemProxy());
396
397    return (result == -1) ? -errno : result;
398}
399
400SyscallReturn
401unlinkFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
402{
403    return unlinkHelper(desc, num, p, tc, 0);
404}
405
406SyscallReturn
407unlinkHelper(SyscallDesc *desc, int num, Process *p, ThreadContext *tc,
408             int index)
409{
410    string path;
411
412    if (!tc->getMemProxy().tryReadString(path, p->getSyscallArg(tc, index)))
413        return -EFAULT;
414
415    // Adjust path for current working directory
416    path = p->fullPath(path);
417
418    int result = unlink(path.c_str());
419    return (result == -1) ? -errno : result;
420}
421
422
423SyscallReturn
424mkdirFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
425{
426    string path;
427
428    int index = 0;
429    if (!tc->getMemProxy().tryReadString(path, p->getSyscallArg(tc, index)))
430        return -EFAULT;
431
432    // Adjust path for current working directory
433    path = p->fullPath(path);
434
435    mode_t mode = p->getSyscallArg(tc, index);
436
437    int result = mkdir(path.c_str(), mode);
438    return (result == -1) ? -errno : result;
439}
440
441SyscallReturn
442renameFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
443{
444    string old_name;
445
446    int index = 0;
447    if (!tc->getMemProxy().tryReadString(old_name, p->getSyscallArg(tc, index)))
448        return -EFAULT;
449
450    string new_name;
451
452    if (!tc->getMemProxy().tryReadString(new_name, p->getSyscallArg(tc, index)))
453        return -EFAULT;
454
455    // Adjust path for current working directory
456    old_name = p->fullPath(old_name);
457    new_name = p->fullPath(new_name);
458
459    int64_t result = rename(old_name.c_str(), new_name.c_str());
460    return (result == -1) ? -errno : result;
461}
462
463SyscallReturn
464truncateFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
465{
466    string path;
467
468    int index = 0;
469    if (!tc->getMemProxy().tryReadString(path, p->getSyscallArg(tc, index)))
470        return -EFAULT;
471
472    off_t length = p->getSyscallArg(tc, index);
473
474    // Adjust path for current working directory
475    path = p->fullPath(path);
476
477    int result = truncate(path.c_str(), length);
478    return (result == -1) ? -errno : result;
479}
480
481SyscallReturn
482ftruncateFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
483{
484    int index = 0;
485    int tgt_fd = p->getSyscallArg(tc, index);
486    off_t length = p->getSyscallArg(tc, index);
487
488    auto ffdp = std::dynamic_pointer_cast<FileFDEntry>((*p->fds)[tgt_fd]);
489    if (!ffdp)
490        return -EBADF;
491    int sim_fd = ffdp->getSimFD();
492
493    int result = ftruncate(sim_fd, length);
494    return (result == -1) ? -errno : result;
495}
496
497SyscallReturn
498truncate64Func(SyscallDesc *desc, int num,
499               Process *process, ThreadContext *tc)
500{
501    int index = 0;
502    string path;
503
504    if (!tc->getMemProxy().tryReadString(path, process->getSyscallArg(tc, index)))
505       return -EFAULT;
506
507    int64_t length = process->getSyscallArg(tc, index, 64);
508
509    // Adjust path for current working directory
510    path = process->fullPath(path);
511
512#if NO_STAT64
513    int result = truncate(path.c_str(), length);
514#else
515    int result = truncate64(path.c_str(), length);
516#endif
517    return (result == -1) ? -errno : result;
518}
519
520SyscallReturn
521ftruncate64Func(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
522{
523    int index = 0;
524    int tgt_fd = p->getSyscallArg(tc, index);
525    int64_t length = p->getSyscallArg(tc, index, 64);
526
527    auto ffdp = std::dynamic_pointer_cast<FileFDEntry>((*p->fds)[tgt_fd]);
528    if (!ffdp)
529        return -EBADF;
530    int sim_fd = ffdp->getSimFD();
531
532#if NO_STAT64
533    int result = ftruncate(sim_fd, length);
534#else
535    int result = ftruncate64(sim_fd, length);
536#endif
537    return (result == -1) ? -errno : result;
538}
539
540SyscallReturn
541umaskFunc(SyscallDesc *desc, int num, Process *process, ThreadContext *tc)
542{
543    // Letting the simulated program change the simulator's umask seems like
544    // a bad idea.  Compromise by just returning the current umask but not
545    // changing anything.
546    mode_t oldMask = umask(0);
547    umask(oldMask);
548    return (int)oldMask;
549}
550
551SyscallReturn
552chownFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
553{
554    string path;
555
556    int index = 0;
557    if (!tc->getMemProxy().tryReadString(path, p->getSyscallArg(tc, index)))
558        return -EFAULT;
559
560    /* XXX endianess */
561    uint32_t owner = p->getSyscallArg(tc, index);
562    uid_t hostOwner = owner;
563    uint32_t group = p->getSyscallArg(tc, index);
564    gid_t hostGroup = group;
565
566    // Adjust path for current working directory
567    path = p->fullPath(path);
568
569    int result = chown(path.c_str(), hostOwner, hostGroup);
570    return (result == -1) ? -errno : result;
571}
572
573SyscallReturn
574fchownFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
575{
576    int index = 0;
577    int tgt_fd = p->getSyscallArg(tc, index);
578
579    auto ffdp = std::dynamic_pointer_cast<FileFDEntry>((*p->fds)[tgt_fd]);
580    if (!ffdp)
581        return -EBADF;
582    int sim_fd = ffdp->getSimFD();
583
584    /* XXX endianess */
585    uint32_t owner = p->getSyscallArg(tc, index);
586    uid_t hostOwner = owner;
587    uint32_t group = p->getSyscallArg(tc, index);
588    gid_t hostGroup = group;
589
590    int result = fchown(sim_fd, hostOwner, hostGroup);
591    return (result == -1) ? -errno : result;
592}
593
594
595/**
596 * TODO: there's a bit more involved here since file descriptors created with
597 * dup are supposed to share a file description. So, there is a problem with
598 * maintaining fields like file offset or flags since an update to such a
599 * field won't be reflected in the metadata for the fd entries that we
600 * maintain to hold metadata for checkpoint restoration.
601 */
602SyscallReturn
603dupFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
604{
605    int index = 0;
606    int tgt_fd = p->getSyscallArg(tc, index);
607
608    auto old_hbfdp = std::dynamic_pointer_cast<HBFDEntry>((*p->fds)[tgt_fd]);
609    if (!old_hbfdp)
610        return -EBADF;
611    int sim_fd = old_hbfdp->getSimFD();
612
613    int result = dup(sim_fd);
614    int local_errno = errno;
615
616    std::shared_ptr<FDEntry> new_fdep = old_hbfdp->clone();
617    auto new_hbfdp = std::dynamic_pointer_cast<HBFDEntry>(new_fdep);
618    new_hbfdp->setSimFD(result);
619
620    return (result == -1) ? -local_errno : p->fds->allocFD(new_fdep);
621}
622
623
624SyscallReturn
625fcntlFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
626{
627    int index = 0;
628    int tgt_fd = p->getSyscallArg(tc, index);
629
630    auto hbfdp = std::dynamic_pointer_cast<HBFDEntry>((*p->fds)[tgt_fd]);
631    if (!hbfdp)
632        return -EBADF;
633    int sim_fd = hbfdp->getSimFD();
634
635    int cmd = p->getSyscallArg(tc, index);
636    switch (cmd) {
637      case 0: // F_DUPFD
638        // if we really wanted to support this, we'd need to do it
639        // in the target fd space.
640        warn("fcntl(%d, F_DUPFD) not supported, error returned\n", tgt_fd);
641        return -EMFILE;
642
643      case 1: // F_GETFD (get close-on-exec flag)
644      case 2: // F_SETFD (set close-on-exec flag)
645        return 0;
646
647      case 3: // F_GETFL (get file flags)
648      case 4: // F_SETFL (set file flags)
649        // not sure if this is totally valid, but we'll pass it through
650        // to the underlying OS
651        warn("fcntl(%d, %d) passed through to host\n", tgt_fd, cmd);
652        return fcntl(sim_fd, cmd);
653        // return 0;
654
655      case 7: // F_GETLK  (get lock)
656      case 8: // F_SETLK  (set lock)
657      case 9: // F_SETLKW (set lock and wait)
658        // don't mess with file locking... just act like it's OK
659        warn("File lock call (fcntl(%d, %d)) ignored.\n", tgt_fd, cmd);
660        return 0;
661
662      default:
663        warn("Unknown fcntl command %d\n", cmd);
664        return 0;
665    }
666}
667
668SyscallReturn
669fcntl64Func(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
670{
671    int index = 0;
672    int tgt_fd = p->getSyscallArg(tc, index);
673
674    auto hbfdp = std::dynamic_pointer_cast<HBFDEntry>((*p->fds)[tgt_fd]);
675    if (!hbfdp)
676        return -EBADF;
677    int sim_fd = hbfdp->getSimFD();
678
679    int cmd = p->getSyscallArg(tc, index);
680    switch (cmd) {
681      case 33: //F_GETLK64
682        warn("fcntl64(%d, F_GETLK64) not supported, error returned\n", tgt_fd);
683        return -EMFILE;
684
685      case 34: // F_SETLK64
686      case 35: // F_SETLKW64
687        warn("fcntl64(%d, F_SETLK(W)64) not supported, error returned\n",
688             tgt_fd);
689        return -EMFILE;
690
691      default:
692        // not sure if this is totally valid, but we'll pass it through
693        // to the underlying OS
694        warn("fcntl64(%d, %d) passed through to host\n", tgt_fd, cmd);
695        return fcntl(sim_fd, cmd);
696        // return 0;
697    }
698}
699
700SyscallReturn
701pipePseudoFunc(SyscallDesc *desc, int callnum, Process *process,
702               ThreadContext *tc)
703{
704    int sim_fds[2], tgt_fds[2];
705
706    int pipe_retval = pipe(sim_fds);
707    if (pipe_retval < 0)
708        return pipe_retval;
709
710    auto rend = PipeFDEntry::EndType::read;
711    auto rpfd = std::make_shared<PipeFDEntry>(sim_fds[0], O_WRONLY, rend);
712
713    auto wend = PipeFDEntry::EndType::write;
714    auto wpfd = std::make_shared<PipeFDEntry>(sim_fds[1], O_RDONLY, wend);
715
716    tgt_fds[0] = process->fds->allocFD(rpfd);
717    tgt_fds[1] = process->fds->allocFD(wpfd);
718
719    /**
720     * Now patch the read object to record the target file descriptor chosen
721     * as the write end of the pipe.
722     */
723    rpfd->setPipeReadSource(tgt_fds[1]);
724
725    /**
726     * Alpha Linux convention for pipe() is that fd[0] is returned as
727     * the return value of the function, and fd[1] is returned in r20.
728     */
729    tc->setIntReg(SyscallPseudoReturnReg, tgt_fds[1]);
730    return sim_fds[0];
731}
732
733
734SyscallReturn
735getpidPseudoFunc(SyscallDesc *desc, int callnum, Process *process,
736                 ThreadContext *tc)
737{
738    // Make up a PID.  There's no interprocess communication in
739    // fake_syscall mode, so there's no way for a process to know it's
740    // not getting a unique value.
741
742    tc->setIntReg(SyscallPseudoReturnReg, process->ppid());
743    return process->pid();
744}
745
746
747SyscallReturn
748getuidPseudoFunc(SyscallDesc *desc, int callnum, Process *process,
749                 ThreadContext *tc)
750{
751    // Make up a UID and EUID... it shouldn't matter, and we want the
752    // simulation to be deterministic.
753
754    // EUID goes in r20.
755    tc->setIntReg(SyscallPseudoReturnReg, process->euid()); //EUID
756    return process->uid();              // UID
757}
758
759
760SyscallReturn
761getgidPseudoFunc(SyscallDesc *desc, int callnum, Process *process,
762                 ThreadContext *tc)
763{
764    // Get current group ID.  EGID goes in r20.
765    tc->setIntReg(SyscallPseudoReturnReg, process->egid()); //EGID
766    return process->gid();
767}
768
769
770SyscallReturn
771setuidFunc(SyscallDesc *desc, int callnum, Process *process,
772           ThreadContext *tc)
773{
774    // can't fathom why a benchmark would call this.
775    int index = 0;
776    warn("Ignoring call to setuid(%d)\n", process->getSyscallArg(tc, index));
777    return 0;
778}
779
780SyscallReturn
781getpidFunc(SyscallDesc *desc, int callnum, Process *process,
782           ThreadContext *tc)
783{
784    // Make up a PID.  There's no interprocess communication in
785    // fake_syscall mode, so there's no way for a process to know it's
786    // not getting a unique value.
787
788    tc->setIntReg(SyscallPseudoReturnReg, process->ppid()); //PID
789    return process->pid();
790}
791
792SyscallReturn
793getppidFunc(SyscallDesc *desc, int callnum, Process *process,
794            ThreadContext *tc)
795{
796    return process->ppid();
797}
798
799SyscallReturn
800getuidFunc(SyscallDesc *desc, int callnum, Process *process,
801           ThreadContext *tc)
802{
803    return process->uid();              // UID
804}
805
806SyscallReturn
807geteuidFunc(SyscallDesc *desc, int callnum, Process *process,
808            ThreadContext *tc)
809{
810    return process->euid();             // UID
811}
812
813SyscallReturn
814getgidFunc(SyscallDesc *desc, int callnum, Process *process,
815           ThreadContext *tc)
816{
817    return process->gid();
818}
819
820SyscallReturn
821getegidFunc(SyscallDesc *desc, int callnum, Process *process,
822            ThreadContext *tc)
823{
824    return process->egid();
825}
826
827
828SyscallReturn
829cloneFunc(SyscallDesc *desc, int callnum, Process *process,
830          ThreadContext *tc)
831{
832    int index = 0;
833    IntReg flags = process->getSyscallArg(tc, index);
834    IntReg newStack = process->getSyscallArg(tc, index);
835
836    DPRINTF(SyscallVerbose, "In sys_clone:\n");
837    DPRINTF(SyscallVerbose, " Flags=%llx\n", flags);
838    DPRINTF(SyscallVerbose, " Child stack=%llx\n", newStack);
839
840
841    if (flags != 0x10f00) {
842        warn("This sys_clone implementation assumes flags "
843             "CLONE_VM|CLONE_FS|CLONE_FILES|CLONE_SIGHAND|CLONE_THREAD "
844             "(0x10f00), and may not work correctly with given flags "
845             "0x%llx\n", flags);
846    }
847
848    ThreadContext* ctc; // child thread context
849    if ((ctc = process->findFreeContext())) {
850        DPRINTF(SyscallVerbose, " Found unallocated thread context\n");
851
852        ctc->clearArchRegs();
853
854        // Arch-specific cloning code
855        #if THE_ISA == ALPHA_ISA or THE_ISA == X86_ISA
856            // Cloning the misc. regs for these archs is enough
857            TheISA::copyMiscRegs(tc, ctc);
858        #elif THE_ISA == SPARC_ISA
859            TheISA::copyRegs(tc, ctc);
860
861            // TODO: Explain what this code actually does :-)
862            ctc->setIntReg(NumIntArchRegs + 6, 0);
863            ctc->setIntReg(NumIntArchRegs + 4, 0);
864            ctc->setIntReg(NumIntArchRegs + 3, NWindows - 2);
865            ctc->setIntReg(NumIntArchRegs + 5, NWindows);
866            ctc->setMiscReg(MISCREG_CWP, 0);
867            ctc->setIntReg(NumIntArchRegs + 7, 0);
868            ctc->setMiscRegNoEffect(MISCREG_TL, 0);
869            ctc->setMiscReg(MISCREG_ASI, ASI_PRIMARY);
870
871            for (int y = 8; y < 32; y++)
872                ctc->setIntReg(y, tc->readIntReg(y));
873        #elif THE_ISA == ARM_ISA
874            TheISA::copyRegs(tc, ctc);
875        #else
876            fatal("sys_clone is not implemented for this ISA\n");
877        #endif
878
879        // Set up stack register
880        ctc->setIntReg(TheISA::StackPointerReg, newStack);
881
882        // Set up syscall return values in parent and child
883        ctc->setIntReg(ReturnValueReg, 0); // return value, child
884
885        // Alpha needs SyscallSuccessReg=0 in child
886        #if THE_ISA == ALPHA_ISA
887            ctc->setIntReg(TheISA::SyscallSuccessReg, 0);
888        #endif
889
890        // In SPARC/Linux, clone returns 0 on pseudo-return register if
891        // parent, non-zero if child
892        #if THE_ISA == SPARC_ISA
893            tc->setIntReg(TheISA::SyscallPseudoReturnReg, 0);
894            ctc->setIntReg(TheISA::SyscallPseudoReturnReg, 1);
895        #endif
896
897        ctc->pcState(tc->nextInstAddr());
898
899        ctc->activate();
900
901        // Should return nonzero child TID in parent's syscall return register,
902        // but for our pthread library any non-zero value will work
903        return 1;
904    } else {
905        fatal("Called sys_clone, but no unallocated thread contexts found!\n");
906        return 0;
907    }
908}
909
910SyscallReturn
911fallocateFunc(SyscallDesc *desc, int callnum, Process *p, ThreadContext *tc)
912{
913#if NO_FALLOCATE
914    warn("Host OS cannot support calls to fallocate. Ignoring syscall");
915#else
916    int index = 0;
917    int tgt_fd = p->getSyscallArg(tc, index);
918    int mode = p->getSyscallArg(tc, index);
919    off_t offset = p->getSyscallArg(tc, index);
920    off_t len = p->getSyscallArg(tc, index);
921
922    auto ffdp = std::dynamic_pointer_cast<FileFDEntry>((*p->fds)[tgt_fd]);
923    if (!ffdp)
924        return -EBADF;
925    int sim_fd = ffdp->getSimFD();
926
927    int result = fallocate(sim_fd, mode, offset, len);
928    if (result < 0)
929        return -errno;
930#endif
931    return 0;
932}
933
934SyscallReturn
935accessFunc(SyscallDesc *desc, int callnum, Process *p, ThreadContext *tc,
936           int index)
937{
938    string path;
939    if (!tc->getMemProxy().tryReadString(path, p->getSyscallArg(tc, index)))
940        return -EFAULT;
941
942    // Adjust path for current working directory
943    path = p->fullPath(path);
944
945    mode_t mode = p->getSyscallArg(tc, index);
946
947    int result = access(path.c_str(), mode);
948    return (result == -1) ? -errno : result;
949}
950
951SyscallReturn
952accessFunc(SyscallDesc *desc, int callnum, Process *p, ThreadContext *tc)
953{
954    return accessFunc(desc, callnum, p, tc, 0);
955}
956
957