syscall_emul.cc revision 6703:2707e7b63f53
1955SN/A/*
2955SN/A * Copyright (c) 2003-2005 The Regents of The University of Michigan
31762SN/A * All rights reserved.
4955SN/A *
5955SN/A * Redistribution and use in source and binary forms, with or without
6955SN/A * modification, are permitted provided that the following conditions are
7955SN/A * met: redistributions of source code must retain the above copyright
8955SN/A * notice, this list of conditions and the following disclaimer;
9955SN/A * redistributions in binary form must reproduce the above copyright
10955SN/A * notice, this list of conditions and the following disclaimer in the
11955SN/A * documentation and/or other materials provided with the distribution;
12955SN/A * neither the name of the copyright holders nor the names of its
13955SN/A * contributors may be used to endorse or promote products derived from
14955SN/A * this software without specific prior written permission.
15955SN/A *
16955SN/A * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17955SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18955SN/A * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19955SN/A * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20955SN/A * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21955SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22955SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23955SN/A * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24955SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25955SN/A * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26955SN/A * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27955SN/A *
282665Ssaidi@eecs.umich.edu * Authors: Steve Reinhardt
292665Ssaidi@eecs.umich.edu *          Ali Saidi
30955SN/A */
31955SN/A
32955SN/A#include <fcntl.h>
331608SN/A#include <unistd.h>
34955SN/A
35955SN/A#include <string>
36955SN/A#include <iostream>
37955SN/A
38955SN/A#include "sim/syscall_emul.hh"
39955SN/A#include "base/chunk_generator.hh"
40955SN/A#include "base/trace.hh"
41955SN/A#include "config/the_isa.hh"
42955SN/A#include "cpu/thread_context.hh"
43955SN/A#include "cpu/base.hh"
44955SN/A#include "mem/page_table.hh"
45955SN/A#include "sim/process.hh"
46955SN/A#include "sim/system.hh"
47955SN/A#include "sim/sim_exit.hh"
482023SN/A
49955SN/Ausing namespace std;
503089Ssaidi@eecs.umich.eduusing namespace TheISA;
51955SN/A
52955SN/Avoid
53955SN/ASyscallDesc::doSyscall(int callnum, LiveProcess *process, ThreadContext *tc)
54955SN/A{
55955SN/A#if TRACING_ON
56955SN/A    int index = 0;
57955SN/A#endif
58955SN/A    DPRINTFR(SyscallVerbose,
591031SN/A             "%d: %s: syscall %s called w/arguments %d,%d,%d,%d\n",
60955SN/A             curTick, tc->getCpuPtr()->name(), name,
611388SN/A             process->getSyscallArg(tc, index),
62955SN/A             process->getSyscallArg(tc, index),
63955SN/A             process->getSyscallArg(tc, index),
641296SN/A             process->getSyscallArg(tc, index));
65955SN/A
66955SN/A    SyscallReturn retval = (*funcPtr)(this, callnum, process, tc);
67955SN/A
68955SN/A    DPRINTFR(SyscallVerbose, "%d: %s: syscall %s returns %d\n",
69955SN/A             curTick,tc->getCpuPtr()->name(), name, retval.value());
70955SN/A
71955SN/A    if (!(flags & SyscallDesc::SuppressReturnValue))
72955SN/A        process->setSyscallReturn(tc, retval);
73955SN/A}
74955SN/A
75955SN/A
76955SN/ASyscallReturn
77955SN/AunimplementedFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
78955SN/A                  ThreadContext *tc)
79955SN/A{
80955SN/A    fatal("syscall %s (#%d) unimplemented.", desc->name, callnum);
81955SN/A
82955SN/A    return 1;
83955SN/A}
842325SN/A
851717SN/A
862652Ssaidi@eecs.umich.eduSyscallReturn
87955SN/AignoreFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
882736Sktlim@umich.edu           ThreadContext *tc)
892410SN/A{
90955SN/A    int index = 0;
912290SN/A    warn("ignoring syscall %s(%d, %d, ...)", desc->name,
92955SN/A         process->getSyscallArg(tc, index), process->getSyscallArg(tc, index));
932683Sktlim@umich.edu
942683Sktlim@umich.edu    return 0;
952669Sktlim@umich.edu}
962568SN/A
972568SN/A
983012Ssaidi@eecs.umich.eduSyscallReturn
992462SN/AexitFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
1002568SN/A         ThreadContext *tc)
1012395SN/A{
1022405SN/A    if (process->system->numRunningContexts() == 1) {
1032914Ssaidi@eecs.umich.edu        // Last running context... exit simulator
104955SN/A        int index = 0;
1052811Srdreslin@umich.edu        exitSimLoop("target called exit()",
1062811Srdreslin@umich.edu                    process->getSyscallArg(tc, index) & 0xff);
1072811Srdreslin@umich.edu    } else {
1082811Srdreslin@umich.edu        // other running threads... just halt this one
1092811Srdreslin@umich.edu        tc->halt();
1102811Srdreslin@umich.edu    }
1112811Srdreslin@umich.edu
1122811Srdreslin@umich.edu    return 1;
1132811Srdreslin@umich.edu}
1142811Srdreslin@umich.edu
1152811Srdreslin@umich.edu
1162811Srdreslin@umich.eduSyscallReturn
1172811Srdreslin@umich.eduexitGroupFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
1182811Srdreslin@umich.edu              ThreadContext *tc)
1192811Srdreslin@umich.edu{
1202811Srdreslin@umich.edu    // really should just halt all thread contexts belonging to this
1212814Srdreslin@umich.edu    // process in case there's another process running...
1222811Srdreslin@umich.edu    int index = 0;
1232811Srdreslin@umich.edu    exitSimLoop("target called exit()",
1242811Srdreslin@umich.edu                process->getSyscallArg(tc, index) & 0xff);
1252811Srdreslin@umich.edu
1262811Srdreslin@umich.edu    return 1;
1272811Srdreslin@umich.edu}
1282811Srdreslin@umich.edu
1292813Srdreslin@umich.edu
1302813Srdreslin@umich.eduSyscallReturn
131955SN/AgetpagesizeFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc)
132955SN/A{
133955SN/A    return (int)VMPageSize;
1342090SN/A}
135955SN/A
1362763Sstever@eecs.umich.edu
137955SN/ASyscallReturn
1381696SN/AbrkFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc)
139955SN/A{
140955SN/A    // change brk addr to first arg
141955SN/A    int index = 0;
1421127SN/A    Addr new_brk = p->getSyscallArg(tc, index);
143955SN/A
144955SN/A    // in Linux at least, brk(0) returns the current break value
1452379SN/A    // (note that the syscall and the glibc function have different behavior)
146955SN/A    if (new_brk == 0)
147955SN/A        return p->brk_point;
148955SN/A
1492155SN/A    if (new_brk > p->brk_point) {
1502155SN/A        // might need to allocate some new pages
1512155SN/A        for (ChunkGenerator gen(p->brk_point, new_brk - p->brk_point,
1522155SN/A                                VMPageSize); !gen.done(); gen.next()) {
1532155SN/A            if (!p->pTable->translate(gen.addr()))
1542155SN/A                p->pTable->allocate(roundDown(gen.addr(), VMPageSize),
1552155SN/A                                    VMPageSize);
1562155SN/A
1572155SN/A            // if the address is already there, zero it out
1582155SN/A            else {
1592155SN/A                uint8_t zero  = 0;
1602155SN/A                TranslatingPort *tp = tc->getMemPort();
1612155SN/A
1622155SN/A                // split non-page aligned accesses
1632155SN/A                Addr next_page = roundUp(gen.addr(), VMPageSize);
1642155SN/A                uint32_t size_needed = next_page - gen.addr();
1652155SN/A                tp->memsetBlob(gen.addr(), zero, size_needed);
1662155SN/A                if (gen.addr() + VMPageSize > next_page &&
1672155SN/A                    next_page < new_brk &&
1682155SN/A                    p->pTable->translate(next_page))
1692155SN/A                {
1702155SN/A                    size_needed = VMPageSize - size_needed;
1712155SN/A                    tp->memsetBlob(next_page, zero, size_needed);
1722155SN/A                }
1732155SN/A            }
1742155SN/A        }
1752155SN/A    }
1762155SN/A
1772155SN/A    p->brk_point = new_brk;
1782155SN/A    DPRINTF(SyscallVerbose, "Break Point changed to: %#X\n", p->brk_point);
1792155SN/A    return p->brk_point;
1802155SN/A}
1812155SN/A
1822155SN/A
1832155SN/ASyscallReturn
1842155SN/AcloseFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc)
1852155SN/A{
1862155SN/A    int index = 0;
1872155SN/A    int target_fd = p->getSyscallArg(tc, index);
1882422SN/A    int status = close(p->sim_fd(target_fd));
1892422SN/A    if (status >= 0)
1902422SN/A        p->free_fd(target_fd);
1912422SN/A    return status;
1922422SN/A}
1932422SN/A
1942422SN/A
1952397SN/ASyscallReturn
1962397SN/AreadFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc)
1972422SN/A{
1982422SN/A    int index = 0;
199955SN/A    int fd = p->sim_fd(p->getSyscallArg(tc, index));
200955SN/A    Addr bufPtr = p->getSyscallArg(tc, index);
201955SN/A    int nbytes = p->getSyscallArg(tc, index);
202955SN/A    BufferArg bufArg(bufPtr, nbytes);
203955SN/A
204955SN/A    int bytes_read = read(fd, bufArg.bufferPtr(), nbytes);
205955SN/A
206955SN/A    if (bytes_read != -1)
2071078SN/A        bufArg.copyOut(tc->getMemPort());
208955SN/A
209955SN/A    return bytes_read;
210955SN/A}
211955SN/A
2121917SN/ASyscallReturn
213955SN/AwriteFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc)
214955SN/A{
215955SN/A    int index = 0;
216955SN/A    int fd = p->sim_fd(p->getSyscallArg(tc, index));
217974SN/A    Addr bufPtr = p->getSyscallArg(tc, index);
218955SN/A    int nbytes = p->getSyscallArg(tc, index);
219955SN/A    BufferArg bufArg(bufPtr, nbytes);
220955SN/A
221955SN/A    bufArg.copyIn(tc->getMemPort());
2222566SN/A
2232566SN/A    int bytes_written = write(fd, bufArg.bufferPtr(), nbytes);
224955SN/A
225955SN/A    fsync(fd);
2262539SN/A
227955SN/A    return bytes_written;
228955SN/A}
229955SN/A
2301154SN/A
2311840SN/ASyscallReturn
2322522SN/AlseekFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc)
2332522SN/A{
234955SN/A    int index = 0;
235955SN/A    int fd = p->sim_fd(p->getSyscallArg(tc, index));
236955SN/A    uint64_t offs = p->getSyscallArg(tc, index);
237955SN/A    int whence = p->getSyscallArg(tc, index);
2382539SN/A
239955SN/A    off_t result = lseek(fd, offs, whence);
2401730SN/A
241955SN/A    return (result == (off_t)-1) ? -errno : result;
242955SN/A}
243955SN/A
2442212SN/A
245955SN/ASyscallReturn
2461040SN/A_llseekFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc)
2472507SN/A{
2482521SN/A    int index = 0;
2492521SN/A    int fd = p->sim_fd(p->getSyscallArg(tc, index));
2502507SN/A    uint64_t offset_high = p->getSyscallArg(tc, index);
2512507SN/A    uint32_t offset_low = p->getSyscallArg(tc, index);
2522989Ssaidi@eecs.umich.edu    Addr result_ptr = p->getSyscallArg(tc, index);
2533408Ssaidi@eecs.umich.edu    int whence = p->getSyscallArg(tc, index);
2542507SN/A
2552521SN/A    uint64_t offset = (offset_high << 32) | offset_low;
2562507SN/A
2572507SN/A    uint64_t result = lseek(fd, offset, whence);
258955SN/A    result = TheISA::htog(result);
259955SN/A
260955SN/A    if (result == (off_t)-1) {
261955SN/A        //The seek failed.
262955SN/A        return -errno;
263955SN/A    } else {
2641742SN/A        // The seek succeeded.
2651742SN/A        // Copy "result" to "result_ptr"
2661742SN/A        // XXX We'll assume that the size of loff_t is 64 bits on the
2671742SN/A        // target platform
2681742SN/A        BufferArg result_buf(result_ptr, sizeof(result));
2691742SN/A        memcpy(result_buf.bufferPtr(), &result, sizeof(result));
2701742SN/A        result_buf.copyOut(tc->getMemPort());
2711742SN/A        return 0;
2721742SN/A    }
2731742SN/A
2741742SN/A
2751742SN/A    return (result == (off_t)-1) ? -errno : result;
2761742SN/A}
2771742SN/A
2781742SN/A
2791742SN/ASyscallReturn
2801742SN/AmunmapFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc)
2811742SN/A{
2821742SN/A    // given that we don't really implement mmap, munmap is really easy
2831742SN/A    return 0;
284955SN/A}
285955SN/A
2862520SN/A
2872517SN/Aconst char *hostname = "m5.eecs.umich.edu";
2882253SN/A
2892253SN/ASyscallReturn
2902253SN/AgethostnameFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc)
2912253SN/A{
2922553SN/A    int index = 0;
2932553SN/A    Addr bufPtr = p->getSyscallArg(tc, index);
2942553SN/A    int name_len = p->getSyscallArg(tc, index);
2952553SN/A    BufferArg name(bufPtr, name_len);
2962507SN/A
2972470SN/A    strncpy((char *)name.bufferPtr(), hostname, name_len);
2981744SN/A
2991744SN/A    name.copyOut(tc->getMemPort());
3002470SN/A
3012470SN/A    return 0;
3022470SN/A}
3032919Sktlim@umich.edu
3042470SN/ASyscallReturn
3052470SN/AgetcwdFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc)
3062400SN/A{
3072400SN/A    int result = 0;
308955SN/A    int index;
309955SN/A    Addr bufPtr = p->getSyscallArg(tc, index);
3102667Sstever@eecs.umich.edu    unsigned long size = p->getSyscallArg(tc, index);
3112667Sstever@eecs.umich.edu    BufferArg buf(bufPtr, size);
3122667Sstever@eecs.umich.edu
3132667Sstever@eecs.umich.edu    // Is current working directory defined?
3142667Sstever@eecs.umich.edu    string cwd = p->getcwd();
3152667Sstever@eecs.umich.edu    if (!cwd.empty()) {
3162037SN/A        if (cwd.length() >= size) {
3172037SN/A            // Buffer too small
3182037SN/A            return -ERANGE;
3192667Sstever@eecs.umich.edu        }
3202139SN/A        strncpy((char *)buf.bufferPtr(), cwd.c_str(), size);
3212667Sstever@eecs.umich.edu        result = cwd.length();
3222155SN/A    }
3232155SN/A    else {
3242155SN/A        if (getcwd((char *)buf.bufferPtr(), size) != NULL) {
3252155SN/A            result = strlen((char *)buf.bufferPtr());
3262155SN/A        }
3272155SN/A        else {
328955SN/A            result = -1;
3292155SN/A        }
330955SN/A    }
331955SN/A
332955SN/A    buf.copyOut(tc->getMemPort());
3331742SN/A
3341742SN/A    return (result == -1) ? -errno : result;
335955SN/A}
336955SN/A
337955SN/A
3381858SN/ASyscallReturn
339955SN/AreadlinkFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc)
3401858SN/A{
3411858SN/A    string path;
3421858SN/A
3431085SN/A    int index = 0;
344955SN/A    if (!tc->getMemPort()->tryReadString(path, p->getSyscallArg(tc, index)))
345955SN/A        return (TheISA::IntReg)-EFAULT;
346955SN/A
347955SN/A    // Adjust path for current working directory
348955SN/A    path = p->fullPath(path);
349955SN/A
350955SN/A    Addr bufPtr = p->getSyscallArg(tc, index);
351955SN/A    size_t bufsiz = p->getSyscallArg(tc, index);
352955SN/A
353955SN/A    BufferArg buf(bufPtr, bufsiz);
354955SN/A
355955SN/A    int result = readlink(path.c_str(), (char *)buf.bufferPtr(), bufsiz);
3562667Sstever@eecs.umich.edu
3571045SN/A    buf.copyOut(tc->getMemPort());
358955SN/A
359955SN/A    return (result == -1) ? -errno : result;
360955SN/A}
361955SN/A
3621108SN/ASyscallReturn
363955SN/AunlinkFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc)
364955SN/A{
365955SN/A    string path;
366955SN/A
367955SN/A    int index = 0;
368955SN/A    if (!tc->getMemPort()->tryReadString(path, p->getSyscallArg(tc, index)))
369955SN/A        return (TheISA::IntReg)-EFAULT;
370955SN/A
371955SN/A    // Adjust path for current working directory
372955SN/A    path = p->fullPath(path);
373955SN/A
374955SN/A    int result = unlink(path.c_str());
375955SN/A    return (result == -1) ? -errno : result;
376955SN/A}
377955SN/A
378955SN/A
3792655Sstever@eecs.umich.eduSyscallReturn
3802655Sstever@eecs.umich.edumkdirFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc)
3812655Sstever@eecs.umich.edu{
3822655Sstever@eecs.umich.edu    string path;
3832655Sstever@eecs.umich.edu
3842655Sstever@eecs.umich.edu    int index = 0;
3852655Sstever@eecs.umich.edu    if (!tc->getMemPort()->tryReadString(path, p->getSyscallArg(tc, index)))
3862655Sstever@eecs.umich.edu        return (TheISA::IntReg)-EFAULT;
3872655Sstever@eecs.umich.edu
3882655Sstever@eecs.umich.edu    // Adjust path for current working directory
3892655Sstever@eecs.umich.edu    path = p->fullPath(path);
3902655Sstever@eecs.umich.edu
3912655Sstever@eecs.umich.edu    mode_t mode = p->getSyscallArg(tc, index);
3922655Sstever@eecs.umich.edu
3932655Sstever@eecs.umich.edu    int result = mkdir(path.c_str(), mode);
3942655Sstever@eecs.umich.edu    return (result == -1) ? -errno : result;
3952655Sstever@eecs.umich.edu}
3962655Sstever@eecs.umich.edu
3972655Sstever@eecs.umich.eduSyscallReturn
3982655Sstever@eecs.umich.edurenameFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc)
3992655Sstever@eecs.umich.edu{
4002655Sstever@eecs.umich.edu    string old_name;
401955SN/A
4022655Sstever@eecs.umich.edu    int index = 0;
4032655Sstever@eecs.umich.edu    if (!tc->getMemPort()->tryReadString(old_name, p->getSyscallArg(tc, index)))
4042655Sstever@eecs.umich.edu        return -EFAULT;
405955SN/A
406955SN/A    string new_name;
4072655Sstever@eecs.umich.edu
4082655Sstever@eecs.umich.edu    if (!tc->getMemPort()->tryReadString(new_name, p->getSyscallArg(tc, index)))
409955SN/A        return -EFAULT;
410955SN/A
4112655Sstever@eecs.umich.edu    // Adjust path for current working directory
4122655Sstever@eecs.umich.edu    old_name = p->fullPath(old_name);
4132655Sstever@eecs.umich.edu    new_name = p->fullPath(new_name);
414955SN/A
415955SN/A    int64_t result = rename(old_name.c_str(), new_name.c_str());
4162655Sstever@eecs.umich.edu    return (result == -1) ? -errno : result;
4172655Sstever@eecs.umich.edu}
4182655Sstever@eecs.umich.edu
4191869SN/ASyscallReturn
4201869SN/AtruncateFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc)
421{
422    string path;
423
424    int index = 0;
425    if (!tc->getMemPort()->tryReadString(path, p->getSyscallArg(tc, index)))
426        return -EFAULT;
427
428    off_t length = p->getSyscallArg(tc, index);
429
430    // Adjust path for current working directory
431    path = p->fullPath(path);
432
433    int result = truncate(path.c_str(), length);
434    return (result == -1) ? -errno : result;
435}
436
437SyscallReturn
438ftruncateFunc(SyscallDesc *desc, int num,
439              LiveProcess *process, ThreadContext *tc)
440{
441    int index = 0;
442    int fd = process->sim_fd(process->getSyscallArg(tc, index));
443
444    if (fd < 0)
445        return -EBADF;
446
447    off_t length = process->getSyscallArg(tc, index);
448
449    int result = ftruncate(fd, length);
450    return (result == -1) ? -errno : result;
451}
452
453SyscallReturn
454truncate64Func(SyscallDesc *desc, int num,
455                LiveProcess *process, ThreadContext *tc)
456{
457    int index = 0;
458    string path;
459
460    if (!tc->getMemPort()->tryReadString(path, process->getSyscallArg(tc, index)))
461       return -EFAULT;
462
463    loff_t length = process->getSyscallArg(tc, index, 64);
464
465    // Adjust path for current working directory
466    path = process->fullPath(path);
467
468    int result = truncate64(path.c_str(), length);
469    return (result == -1) ? -errno : result;
470}
471
472SyscallReturn
473ftruncate64Func(SyscallDesc *desc, int num,
474                LiveProcess *process, ThreadContext *tc)
475{
476    int index = 0;
477    int fd = process->sim_fd(process->getSyscallArg(tc, index));
478
479    if (fd < 0)
480        return -EBADF;
481
482    loff_t length = process->getSyscallArg(tc, index, 64);
483
484    int result = ftruncate64(fd, length);
485    return (result == -1) ? -errno : result;
486}
487
488SyscallReturn
489umaskFunc(SyscallDesc *desc, int num, LiveProcess *process, ThreadContext *tc)
490{
491    // Letting the simulated program change the simulator's umask seems like
492    // a bad idea.  Compromise by just returning the current umask but not
493    // changing anything.
494    mode_t oldMask = umask(0);
495    umask(oldMask);
496    return (int)oldMask;
497}
498
499SyscallReturn
500chownFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc)
501{
502    string path;
503
504    int index = 0;
505    if (!tc->getMemPort()->tryReadString(path, p->getSyscallArg(tc, index)))
506        return -EFAULT;
507
508    /* XXX endianess */
509    uint32_t owner = p->getSyscallArg(tc, index);
510    uid_t hostOwner = owner;
511    uint32_t group = p->getSyscallArg(tc, index);
512    gid_t hostGroup = group;
513
514    // Adjust path for current working directory
515    path = p->fullPath(path);
516
517    int result = chown(path.c_str(), hostOwner, hostGroup);
518    return (result == -1) ? -errno : result;
519}
520
521SyscallReturn
522fchownFunc(SyscallDesc *desc, int num, LiveProcess *process, ThreadContext *tc)
523{
524    int index = 0;
525    int fd = process->sim_fd(process->getSyscallArg(tc, index));
526
527    if (fd < 0)
528        return -EBADF;
529
530    /* XXX endianess */
531    uint32_t owner = process->getSyscallArg(tc, index);
532    uid_t hostOwner = owner;
533    uint32_t group = process->getSyscallArg(tc, index);
534    gid_t hostGroup = group;
535
536    int result = fchown(fd, hostOwner, hostGroup);
537    return (result == -1) ? -errno : result;
538}
539
540
541SyscallReturn
542dupFunc(SyscallDesc *desc, int num, LiveProcess *process, ThreadContext *tc)
543{
544    int index = 0;
545    int fd = process->sim_fd(process->getSyscallArg(tc, index));
546    if (fd < 0)
547        return -EBADF;
548
549    Process::FdMap *fdo = process->sim_fd_obj(fd);
550
551    int result = dup(fd);
552    return (result == -1) ? -errno :
553        process->alloc_fd(result, fdo->filename, fdo->flags, fdo->mode, false);
554}
555
556
557SyscallReturn
558fcntlFunc(SyscallDesc *desc, int num, LiveProcess *process,
559          ThreadContext *tc)
560{
561    int index = 0;
562    int fd = process->getSyscallArg(tc, index);
563
564    if (fd < 0 || process->sim_fd(fd) < 0)
565        return -EBADF;
566
567    int cmd = process->getSyscallArg(tc, index);
568    switch (cmd) {
569      case 0: // F_DUPFD
570        // if we really wanted to support this, we'd need to do it
571        // in the target fd space.
572        warn("fcntl(%d, F_DUPFD) not supported, error returned\n", fd);
573        return -EMFILE;
574
575      case 1: // F_GETFD (get close-on-exec flag)
576      case 2: // F_SETFD (set close-on-exec flag)
577        return 0;
578
579      case 3: // F_GETFL (get file flags)
580      case 4: // F_SETFL (set file flags)
581        // not sure if this is totally valid, but we'll pass it through
582        // to the underlying OS
583        warn("fcntl(%d, %d) passed through to host\n", fd, cmd);
584        return fcntl(process->sim_fd(fd), cmd);
585        // return 0;
586
587      case 7: // F_GETLK  (get lock)
588      case 8: // F_SETLK  (set lock)
589      case 9: // F_SETLKW (set lock and wait)
590        // don't mess with file locking... just act like it's OK
591        warn("File lock call (fcntl(%d, %d)) ignored.\n", fd, cmd);
592        return 0;
593
594      default:
595        warn("Unknown fcntl command %d\n", cmd);
596        return 0;
597    }
598}
599
600SyscallReturn
601fcntl64Func(SyscallDesc *desc, int num, LiveProcess *process,
602            ThreadContext *tc)
603{
604    int index = 0;
605    int fd = process->getSyscallArg(tc, index);
606
607    if (fd < 0 || process->sim_fd(fd) < 0)
608        return -EBADF;
609
610    int cmd = process->getSyscallArg(tc, index);
611    switch (cmd) {
612      case 33: //F_GETLK64
613        warn("fcntl64(%d, F_GETLK64) not supported, error returned\n", fd);
614        return -EMFILE;
615
616      case 34: // F_SETLK64
617      case 35: // F_SETLKW64
618        warn("fcntl64(%d, F_SETLK(W)64) not supported, error returned\n", fd);
619        return -EMFILE;
620
621      default:
622        // not sure if this is totally valid, but we'll pass it through
623        // to the underlying OS
624        warn("fcntl64(%d, %d) passed through to host\n", fd, cmd);
625        return fcntl(process->sim_fd(fd), cmd);
626        // return 0;
627    }
628}
629
630SyscallReturn
631pipePseudoFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
632         ThreadContext *tc)
633{
634    int fds[2], sim_fds[2];
635    int pipe_retval = pipe(fds);
636
637    if (pipe_retval < 0) {
638        // error
639        return pipe_retval;
640    }
641
642    sim_fds[0] = process->alloc_fd(fds[0], "PIPE-READ", O_WRONLY, -1, true);
643    sim_fds[1] = process->alloc_fd(fds[1], "PIPE-WRITE", O_RDONLY, -1, true);
644
645    process->setReadPipeSource(sim_fds[0], sim_fds[1]);
646    // Alpha Linux convention for pipe() is that fd[0] is returned as
647    // the return value of the function, and fd[1] is returned in r20.
648    tc->setIntReg(SyscallPseudoReturnReg, sim_fds[1]);
649    return sim_fds[0];
650}
651
652
653SyscallReturn
654getpidPseudoFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
655           ThreadContext *tc)
656{
657    // Make up a PID.  There's no interprocess communication in
658    // fake_syscall mode, so there's no way for a process to know it's
659    // not getting a unique value.
660
661    tc->setIntReg(SyscallPseudoReturnReg, process->ppid());
662    return process->pid();
663}
664
665
666SyscallReturn
667getuidPseudoFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
668           ThreadContext *tc)
669{
670    // Make up a UID and EUID... it shouldn't matter, and we want the
671    // simulation to be deterministic.
672
673    // EUID goes in r20.
674    tc->setIntReg(SyscallPseudoReturnReg, process->euid()); //EUID
675    return process->uid();              // UID
676}
677
678
679SyscallReturn
680getgidPseudoFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
681           ThreadContext *tc)
682{
683    // Get current group ID.  EGID goes in r20.
684    tc->setIntReg(SyscallPseudoReturnReg, process->egid()); //EGID
685    return process->gid();
686}
687
688
689SyscallReturn
690setuidFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
691           ThreadContext *tc)
692{
693    // can't fathom why a benchmark would call this.
694    int index = 0;
695    warn("Ignoring call to setuid(%d)\n", process->getSyscallArg(tc, index));
696    return 0;
697}
698
699SyscallReturn
700getpidFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
701           ThreadContext *tc)
702{
703    // Make up a PID.  There's no interprocess communication in
704    // fake_syscall mode, so there's no way for a process to know it's
705    // not getting a unique value.
706
707    tc->setIntReg(SyscallPseudoReturnReg, process->ppid()); //PID
708    return process->pid();
709}
710
711SyscallReturn
712getppidFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
713           ThreadContext *tc)
714{
715    return process->ppid();
716}
717
718SyscallReturn
719getuidFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
720           ThreadContext *tc)
721{
722    return process->uid();              // UID
723}
724
725SyscallReturn
726geteuidFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
727           ThreadContext *tc)
728{
729    return process->euid();             // UID
730}
731
732SyscallReturn
733getgidFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
734           ThreadContext *tc)
735{
736    return process->gid();
737}
738
739SyscallReturn
740getegidFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
741           ThreadContext *tc)
742{
743    return process->egid();
744}
745
746
747SyscallReturn
748cloneFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
749           ThreadContext *tc)
750{
751    int index = 0;
752    IntReg flags = process->getSyscallArg(tc, index);
753    IntReg newStack = process->getSyscallArg(tc, index);
754
755    DPRINTF(SyscallVerbose, "In sys_clone:\n");
756    DPRINTF(SyscallVerbose, " Flags=%llx\n", flags);
757    DPRINTF(SyscallVerbose, " Child stack=%llx\n", newStack);
758
759
760    if (flags != 0x10f00) {
761        warn("This sys_clone implementation assumes flags "
762             "CLONE_VM|CLONE_FS|CLONE_FILES|CLONE_SIGHAND|CLONE_THREAD "
763             "(0x10f00), and may not work correctly with given flags "
764             "0x%llx\n", flags);
765    }
766
767    ThreadContext* ctc; // child thread context
768    if ( ( ctc = process->findFreeContext() ) != NULL ) {
769        DPRINTF(SyscallVerbose, " Found unallocated thread context\n");
770
771        ctc->clearArchRegs();
772
773        // Arch-specific cloning code
774        #if THE_ISA == ALPHA_ISA or THE_ISA == X86_ISA
775            // Cloning the misc. regs for these archs is enough
776            TheISA::copyMiscRegs(tc, ctc);
777        #elif THE_ISA == SPARC_ISA
778            TheISA::copyRegs(tc, ctc);
779
780            // TODO: Explain what this code actually does :-)
781            ctc->setIntReg(NumIntArchRegs + 6, 0);
782            ctc->setIntReg(NumIntArchRegs + 4, 0);
783            ctc->setIntReg(NumIntArchRegs + 3, NWindows - 2);
784            ctc->setIntReg(NumIntArchRegs + 5, NWindows);
785            ctc->setMiscReg(MISCREG_CWP, 0);
786            ctc->setIntReg(NumIntArchRegs + 7, 0);
787            ctc->setMiscRegNoEffect(MISCREG_TL, 0);
788            ctc->setMiscRegNoEffect(MISCREG_ASI, ASI_PRIMARY);
789
790            for (int y = 8; y < 32; y++)
791                ctc->setIntReg(y, tc->readIntReg(y));
792        #else
793            fatal("sys_clone is not implemented for this ISA\n");
794        #endif
795
796        // Set up stack register
797        ctc->setIntReg(TheISA::StackPointerReg, newStack);
798
799        // Set up syscall return values in parent and child
800        ctc->setIntReg(ReturnValueReg, 0); // return value, child
801
802        // Alpha needs SyscallSuccessReg=0 in child
803        #if THE_ISA == ALPHA_ISA
804            ctc->setIntReg(TheISA::SyscallSuccessReg, 0);
805        #endif
806
807        // In SPARC/Linux, clone returns 0 on pseudo-return register if
808        // parent, non-zero if child
809        #if THE_ISA == SPARC_ISA
810            tc->setIntReg(TheISA::SyscallPseudoReturnReg, 0);
811            ctc->setIntReg(TheISA::SyscallPseudoReturnReg, 1);
812        #endif
813
814        ctc->setPC(tc->readNextPC());
815        ctc->setNextPC(tc->readNextPC() + sizeof(TheISA::MachInst));
816        ctc->setNextNPC(tc->readNextNPC() + sizeof(TheISA::MachInst));
817
818        ctc->activate();
819
820        // Should return nonzero child TID in parent's syscall return register,
821        // but for our pthread library any non-zero value will work
822        return 1;
823    } else {
824        fatal("Called sys_clone, but no unallocated thread contexts found!\n");
825        return 0;
826    }
827}
828
829