syscall_emul.cc revision 8601
12SN/A/*
29428SAndreas.Sandberg@ARM.com * Copyright (c) 2003-2005 The Regents of The University of Michigan
39920Syasuko.eckert@amd.com * All rights reserved.
48733Sgeoffrey.blake@arm.com *
58733Sgeoffrey.blake@arm.com * Redistribution and use in source and binary forms, with or without
68733Sgeoffrey.blake@arm.com * modification, are permitted provided that the following conditions are
78733Sgeoffrey.blake@arm.com * met: redistributions of source code must retain the above copyright
88733Sgeoffrey.blake@arm.com * notice, this list of conditions and the following disclaimer;
98733Sgeoffrey.blake@arm.com * redistributions in binary form must reproduce the above copyright
108733Sgeoffrey.blake@arm.com * notice, this list of conditions and the following disclaimer in the
118733Sgeoffrey.blake@arm.com * documentation and/or other materials provided with the distribution;
128733Sgeoffrey.blake@arm.com * neither the name of the copyright holders nor the names of its
138733Sgeoffrey.blake@arm.com * contributors may be used to endorse or promote products derived from
148733Sgeoffrey.blake@arm.com * this software without specific prior written permission.
152190SN/A *
162SN/A * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
172SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
182SN/A * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
192SN/A * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
202SN/A * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
212SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
222SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
232SN/A * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
242SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
252SN/A * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
262SN/A * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
272SN/A *
282SN/A * Authors: Steve Reinhardt
292SN/A *          Ali Saidi
302SN/A */
312SN/A
322SN/A#include <fcntl.h>
332SN/A#include <unistd.h>
342SN/A
352SN/A#include <cstdio>
362SN/A#include <iostream>
372SN/A#include <string>
382SN/A
392SN/A#include "arch/utility.hh"
402665SN/A#include "base/chunk_generator.hh"
412665SN/A#include "base/trace.hh"
422SN/A#include "config/the_isa.hh"
432SN/A#include "cpu/base.hh"
442680Sktlim@umich.edu#include "cpu/thread_context.hh"
452680Sktlim@umich.edu#include "debug/SyscallVerbose.hh"
462SN/A#include "mem/page_table.hh"
478229Snate@binkert.org#include "sim/process.hh"
487680Sgblack@eecs.umich.edu#include "sim/sim_exit.hh"
497680Sgblack@eecs.umich.edu#include "sim/syscall_emul.hh"
506329Sgblack@eecs.umich.edu#include "sim/system.hh"
513453Sgblack@eecs.umich.edu
526216Snate@binkert.orgusing namespace std;
536658Snate@binkert.orgusing namespace TheISA;
542SN/A
552190SN/Avoid
562190SN/ASyscallDesc::doSyscall(int callnum, LiveProcess *process, ThreadContext *tc)
573453Sgblack@eecs.umich.edu{
583453Sgblack@eecs.umich.edu#if TRACING_ON
599020Sgblack@eecs.umich.edu    int index = 0;
606022Sgblack@eecs.umich.edu#endif
613453Sgblack@eecs.umich.edu    DPRINTFR(SyscallVerbose,
622190SN/A             "%d: %s: syscall %s called w/arguments %d,%d,%d,%d\n",
638887Sgeoffrey.blake@arm.com             curTick(), tc->getCpuPtr()->name(), name,
647680Sgblack@eecs.umich.edu             process->getSyscallArg(tc, index),
652313SN/A             process->getSyscallArg(tc, index),
668706Sandreas.hansson@arm.com             process->getSyscallArg(tc, index),
678706Sandreas.hansson@arm.com             process->getSyscallArg(tc, index));
688706Sandreas.hansson@arm.com
692190SN/A    SyscallReturn retval = (*funcPtr)(this, callnum, process, tc);
702190SN/A
713548Sgblack@eecs.umich.edu    DPRINTFR(SyscallVerbose, "%d: %s: syscall %s returns %d\n",
723548Sgblack@eecs.umich.edu             curTick(),tc->getCpuPtr()->name(), name, retval.value());
733548Sgblack@eecs.umich.edu
748902Sandreas.hansson@arm.com    if (!(flags & SyscallDesc::SuppressReturnValue))
758902Sandreas.hansson@arm.com        process->setSyscallReturn(tc, retval);
762SN/A}
772680Sktlim@umich.edu
782680Sktlim@umich.edu
792680Sktlim@umich.eduSyscallReturn
802680Sktlim@umich.eduunimplementedFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
812680Sktlim@umich.edu                  ThreadContext *tc)
822680Sktlim@umich.edu{
832680Sktlim@umich.edu    fatal("syscall %s (#%d) unimplemented.", desc->name, callnum);
842680Sktlim@umich.edu
852680Sktlim@umich.edu    return 1;
862680Sktlim@umich.edu}
872680Sktlim@umich.edu
882682Sktlim@umich.edu
892680Sktlim@umich.eduSyscallReturn
902680Sktlim@umich.eduignoreFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
912680Sktlim@umich.edu           ThreadContext *tc)
922680Sktlim@umich.edu{
932680Sktlim@umich.edu    int index = 0;
942SN/A    warn("ignoring syscall %s(%d, %d, ...)", desc->name,
952107SN/A         process->getSyscallArg(tc, index), process->getSyscallArg(tc, index));
962107SN/A
972190SN/A    return 0;
982455SN/A}
992455SN/A
1009920Syasuko.eckert@amd.com
1012159SN/ASyscallReturn
1022SN/AignoreWarnOnceFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
1036029Ssteve.reinhardt@amd.com           ThreadContext *tc)
104246SN/A{
105246SN/A    int index = 0;
106246SN/A    warn_once("ignoring syscall %s(%d, %d, ...)", desc->name,
107246SN/A         process->getSyscallArg(tc, index), process->getSyscallArg(tc, index));
108246SN/A
109246SN/A    return 0;
110246SN/A}
1112190SN/A
112246SN/A
113246SN/ASyscallReturn
114246SN/AexitFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
115246SN/A         ThreadContext *tc)
116246SN/A{
117246SN/A    if (process->system->numRunningContexts() == 1) {
118246SN/A        // Last running context... exit simulator
1192SN/A        int index = 0;
1202680Sktlim@umich.edu        exitSimLoop("target called exit()",
1212423SN/A                    process->getSyscallArg(tc, index) & 0xff);
1222190SN/A    } else {
123180SN/A        // other running threads... just halt this one
12410110Sandreas.hansson@arm.com        tc->halt();
1252190SN/A    }
12610110Sandreas.hansson@arm.com
1275715Shsul@eecs.umich.edu    return 1;
1285715Shsul@eecs.umich.edu}
1295714Shsul@eecs.umich.edu
13010110Sandreas.hansson@arm.com
1315714Shsul@eecs.umich.eduSyscallReturn
1325714Shsul@eecs.umich.eduexitGroupFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
1335714Shsul@eecs.umich.edu              ThreadContext *tc)
1346022Sgblack@eecs.umich.edu{
1352190SN/A    // really should just halt all thread contexts belonging to this
1366022Sgblack@eecs.umich.edu    // process in case there's another process running...
1372521SN/A    int index = 0;
1388887Sgeoffrey.blake@arm.com    exitSimLoop("target called exit()",
1398733Sgeoffrey.blake@arm.com                process->getSyscallArg(tc, index) & 0xff);
1409020Sgblack@eecs.umich.edu
1418541Sgblack@eecs.umich.edu    return 1;
1424997Sgblack@eecs.umich.edu}
1434997Sgblack@eecs.umich.edu
1443548Sgblack@eecs.umich.edu
1452654SN/ASyscallReturn
1468852Sandreas.hansson@arm.comgetpagesizeFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc)
1472521SN/A{
1488852Sandreas.hansson@arm.com    return (int)VMPageSize;
1493673Srdreslin@umich.edu}
1508706Sandreas.hansson@arm.com
1518706Sandreas.hansson@arm.com
1528706Sandreas.hansson@arm.comSyscallReturn
1538706Sandreas.hansson@arm.combrkFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc)
1548706Sandreas.hansson@arm.com{
1558706Sandreas.hansson@arm.com    // change brk addr to first arg
1568706Sandreas.hansson@arm.com    int index = 0;
1578799Sgblack@eecs.umich.edu    Addr new_brk = p->getSyscallArg(tc, index);
1588852Sandreas.hansson@arm.com
1592518SN/A    // in Linux at least, brk(0) returns the current break value
1602190SN/A    // (note that the syscall and the glibc function have different behavior)
1612190SN/A    if (new_brk == 0)
1622190SN/A        return p->brk_point;
1632159SN/A
1642235SN/A    if (new_brk > p->brk_point) {
1652103SN/A        // might need to allocate some new pages
166393SN/A        for (ChunkGenerator gen(p->brk_point, new_brk - p->brk_point,
167393SN/A                                VMPageSize); !gen.done(); gen.next()) {
1689180Sandreas.hansson@arm.com            if (!p->pTable->translate(gen.addr()))
169393SN/A                p->allocateMem(roundDown(gen.addr(), VMPageSize), VMPageSize);
170393SN/A
1719180Sandreas.hansson@arm.com            // if the address is already there, zero it out
172393SN/A            else {
173393SN/A                uint8_t zero  = 0;
1749180Sandreas.hansson@arm.com                TranslatingPort *tp = tc->getMemPort();
1752159SN/A
1762190SN/A                // split non-page aligned accesses
1772159SN/A                Addr next_page = roundUp(gen.addr(), VMPageSize);
1782680Sktlim@umich.edu                uint32_t size_needed = next_page - gen.addr();
1792159SN/A                tp->memsetBlob(gen.addr(), zero, size_needed);
1802190SN/A                if (gen.addr() + VMPageSize > next_page &&
1812159SN/A                    next_page < new_brk &&
1822313SN/A                    p->pTable->translate(next_page))
1832235SN/A                {
1842235SN/A                    size_needed = VMPageSize - size_needed;
1852235SN/A                    tp->memsetBlob(next_page, zero, size_needed);
1862235SN/A                }
1872235SN/A            }
1882254SN/A        }
1892254SN/A    }
1902254SN/A
1912235SN/A    p->brk_point = new_brk;
1922680Sktlim@umich.edu    DPRINTF(SyscallVerbose, "Break Point changed to: %#X\n", p->brk_point);
1932159SN/A    return p->brk_point;
1942190SN/A}
1952159SN/A
1962159SN/A
1972159SN/ASyscallReturn
1982159SN/AcloseFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc)
1992190SN/A{
2002159SN/A    int index = 0;
2012455SN/A    int target_fd = p->getSyscallArg(tc, index);
2022159SN/A    int sim_fd = p->sim_fd(target_fd);
2032455SN/A    int status = 0;
2042159SN/A    if (sim_fd > 2)
2059920Syasuko.eckert@amd.com        status = close(sim_fd);
2069920Syasuko.eckert@amd.com    if (status >= 0)
2072190SN/A        p->free_fd(target_fd);
2082159SN/A    return status;
2092455SN/A}
2102159SN/A
2112455SN/A
2122455SN/ASyscallReturn
2139920Syasuko.eckert@amd.comreadFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc)
2149920Syasuko.eckert@amd.com{
2157720Sgblack@eecs.umich.edu    int index = 0;
2162159SN/A    int fd = p->sim_fd(p->getSyscallArg(tc, index));
2177720Sgblack@eecs.umich.edu    Addr bufPtr = p->getSyscallArg(tc, index);
2182159SN/A    int nbytes = p->getSyscallArg(tc, index);
2198733Sgeoffrey.blake@arm.com    BufferArg bufArg(bufPtr, nbytes);
2208733Sgeoffrey.blake@arm.com
2217720Sgblack@eecs.umich.edu    int bytes_read = read(fd, bufArg.bufferPtr(), nbytes);
2222159SN/A
2237720Sgblack@eecs.umich.edu    if (bytes_read != -1)
2242159SN/A        bufArg.copyOut(tc->getMemPort());
2257720Sgblack@eecs.umich.edu
2265260Sksewell@umich.edu    return bytes_read;
2274172Ssaidi@eecs.umich.edu}
2284172Ssaidi@eecs.umich.edu
2292190SN/ASyscallReturn
2302159SN/AwriteFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc)
2314172Ssaidi@eecs.umich.edu{
2322190SN/A    int index = 0;
2333468Sgblack@eecs.umich.edu    int fd = p->sim_fd(p->getSyscallArg(tc, index));
2342190SN/A    Addr bufPtr = p->getSyscallArg(tc, index);
2356313Sgblack@eecs.umich.edu    int nbytes = p->getSyscallArg(tc, index);
2366313Sgblack@eecs.umich.edu    BufferArg bufArg(bufPtr, nbytes);
2379920Syasuko.eckert@amd.com
23810033SAli.Saidi@ARM.com    bufArg.copyIn(tc->getMemPort());
2396313Sgblack@eecs.umich.edu
2406221Snate@binkert.org    int bytes_written = write(fd, bufArg.bufferPtr(), nbytes);
2416221Snate@binkert.org
2426221Snate@binkert.org    fsync(fd);
2436221Snate@binkert.org
2446221Snate@binkert.org    return bytes_written;
2454661Sksewell@umich.edu}
2466221Snate@binkert.org
2476221Snate@binkert.org
2486221Snate@binkert.orgSyscallReturn
2496221Snate@binkert.orglseekFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc)
2504661Sksewell@umich.edu{
2512235SN/A    int index = 0;
2522235SN/A    int fd = p->sim_fd(p->getSyscallArg(tc, index));
2532190SN/A    uint64_t offs = p->getSyscallArg(tc, index);
2542190SN/A    int whence = p->getSyscallArg(tc, index);
2552190SN/A
2562159SN/A    off_t result = lseek(fd, offs, whence);
2572235SN/A
2582190SN/A    return (result == (off_t)-1) ? -errno : result;
2592190SN/A}
2602235SN/A
2612190SN/A
2622834Sksewell@umich.eduSyscallReturn
2634111Sgblack@eecs.umich.edu_llseekFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc)
2644111Sgblack@eecs.umich.edu{
2652834Sksewell@umich.edu    int index = 0;
2662834Sksewell@umich.edu    int fd = p->sim_fd(p->getSyscallArg(tc, index));
2672834Sksewell@umich.edu    uint64_t offset_high = p->getSyscallArg(tc, index);
2682834Sksewell@umich.edu    uint32_t offset_low = p->getSyscallArg(tc, index);
2692525SN/A    Addr result_ptr = p->getSyscallArg(tc, index);
2705217Ssaidi@eecs.umich.edu    int whence = p->getSyscallArg(tc, index);
2715217Ssaidi@eecs.umich.edu
2729426SAndreas.Sandberg@ARM.com    uint64_t offset = (offset_high << 32) | offset_low;
2739426SAndreas.Sandberg@ARM.com
2749426SAndreas.Sandberg@ARM.com    uint64_t result = lseek(fd, offset, whence);
2759426SAndreas.Sandberg@ARM.com    result = TheISA::htog(result);
2769426SAndreas.Sandberg@ARM.com
2779426SAndreas.Sandberg@ARM.com    if (result == (off_t)-1) {
2789426SAndreas.Sandberg@ARM.com        //The seek failed.
2799426SAndreas.Sandberg@ARM.com        return -errno;
2809426SAndreas.Sandberg@ARM.com    } else {
2819426SAndreas.Sandberg@ARM.com        // The seek succeeded.
2829426SAndreas.Sandberg@ARM.com        // Copy "result" to "result_ptr"
2839426SAndreas.Sandberg@ARM.com        // XXX We'll assume that the size of loff_t is 64 bits on the
2849426SAndreas.Sandberg@ARM.com        // target platform
2859426SAndreas.Sandberg@ARM.com        BufferArg result_buf(result_ptr, sizeof(result));
2869426SAndreas.Sandberg@ARM.com        memcpy(result_buf.bufferPtr(), &result, sizeof(result));
2879426SAndreas.Sandberg@ARM.com        result_buf.copyOut(tc->getMemPort());
2889426SAndreas.Sandberg@ARM.com        return 0;
2899426SAndreas.Sandberg@ARM.com    }
2909426SAndreas.Sandberg@ARM.com
2919426SAndreas.Sandberg@ARM.com
2929426SAndreas.Sandberg@ARM.com    return (result == (off_t)-1) ? -errno : result;
2939426SAndreas.Sandberg@ARM.com}
2949920Syasuko.eckert@amd.com
2959920Syasuko.eckert@amd.com
2969426SAndreas.Sandberg@ARM.comSyscallReturn
2979426SAndreas.Sandberg@ARM.communmapFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc)
2982159SN/A{
2992159SN/A    // given that we don't really implement mmap, munmap is really easy
3002682Sktlim@umich.edu    return 0;
3012682Sktlim@umich.edu}
3022682Sktlim@umich.edu
3032682Sktlim@umich.edu
3042682Sktlim@umich.educonst char *hostname = "m5.eecs.umich.edu";
3052682Sktlim@umich.edu
3062682Sktlim@umich.eduSyscallReturn
3072682Sktlim@umich.edugethostnameFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc)
3082682Sktlim@umich.edu{
3092682Sktlim@umich.edu    int index = 0;
3102680Sktlim@umich.edu    Addr bufPtr = p->getSyscallArg(tc, index);
3112680Sktlim@umich.edu    int name_len = p->getSyscallArg(tc, index);
3122190SN/A    BufferArg name(bufPtr, name_len);
3132190SN/A
3142680Sktlim@umich.edu    strncpy((char *)name.bufferPtr(), hostname, name_len);
3152680Sktlim@umich.edu
3162159SN/A    name.copyOut(tc->getMemPort());
3172190SN/A
3182680Sktlim@umich.edu    return 0;
3192SN/A}
3202SN/A
3212SN/ASyscallReturn
3222680Sktlim@umich.edugetcwdFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc)
3232SN/A{
32410110Sandreas.hansson@arm.com    int result = 0;
3252SN/A    int index = 0;
32610110Sandreas.hansson@arm.com    Addr bufPtr = p->getSyscallArg(tc, index);
3275715Shsul@eecs.umich.edu    unsigned long size = p->getSyscallArg(tc, index);
32810110Sandreas.hansson@arm.com    BufferArg buf(bufPtr, size);
3295714Shsul@eecs.umich.edu
33010110Sandreas.hansson@arm.com    // Is current working directory defined?
3315714Shsul@eecs.umich.edu    string cwd = p->getcwd();
3325714Shsul@eecs.umich.edu    if (!cwd.empty()) {
3335714Shsul@eecs.umich.edu        if (cwd.length() >= size) {
3346022Sgblack@eecs.umich.edu            // Buffer too small
3351917SN/A            return -ERANGE;
3366022Sgblack@eecs.umich.edu        }
3372521SN/A        strncpy((char *)buf.bufferPtr(), cwd.c_str(), size);
3388887Sgeoffrey.blake@arm.com        result = cwd.length();
3398733Sgeoffrey.blake@arm.com    }
3409020Sgblack@eecs.umich.edu    else {
3418541Sgblack@eecs.umich.edu        if (getcwd((char *)buf.bufferPtr(), size) != NULL) {
3424997Sgblack@eecs.umich.edu            result = strlen((char *)buf.bufferPtr());
3434997Sgblack@eecs.umich.edu        }
3443548Sgblack@eecs.umich.edu        else {
3453548Sgblack@eecs.umich.edu            result = -1;
3462654SN/A        }
3478852Sandreas.hansson@arm.com    }
3482521SN/A
3498852Sandreas.hansson@arm.com    buf.copyOut(tc->getMemPort());
3503673Srdreslin@umich.edu
3518706Sandreas.hansson@arm.com    return (result == -1) ? -errno : result;
3528799Sgblack@eecs.umich.edu}
3538852Sandreas.hansson@arm.com
3542518SN/A
3552680Sktlim@umich.eduSyscallReturn
3562SN/AreadlinkFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc)
3572680Sktlim@umich.edu{
358595SN/A    string path;
3592680Sktlim@umich.edu
3602SN/A    int index = 0;
3612190SN/A    if (!tc->getMemPort()->tryReadString(path, p->getSyscallArg(tc, index)))
3622190SN/A        return (TheISA::IntReg)-EFAULT;
3639180Sandreas.hansson@arm.com
3649180Sandreas.hansson@arm.com    // Adjust path for current working directory
3652SN/A    path = p->fullPath(path);
3662190SN/A
3679180Sandreas.hansson@arm.com    Addr bufPtr = p->getSyscallArg(tc, index);
3682SN/A    size_t bufsiz = p->getSyscallArg(tc, index);
3692190SN/A
3709180Sandreas.hansson@arm.com    BufferArg buf(bufPtr, bufsiz);
371217SN/A
3722680Sktlim@umich.edu    int result = readlink(path.c_str(), (char *)buf.bufferPtr(), bufsiz);
3732190SN/A
3742680Sktlim@umich.edu    buf.copyOut(tc->getMemPort());
3752680Sktlim@umich.edu
3762190SN/A    return (result == -1) ? -errno : result;
3772680Sktlim@umich.edu}
3782190SN/A
3792680Sktlim@umich.eduSyscallReturn
3802235SN/AunlinkFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc)
3812680Sktlim@umich.edu{
3822680Sktlim@umich.edu    string path;
3832254SN/A
3842680Sktlim@umich.edu    int index = 0;
3852680Sktlim@umich.edu    if (!tc->getMemPort()->tryReadString(path, p->getSyscallArg(tc, index)))
3862SN/A        return (TheISA::IntReg)-EFAULT;
3872190SN/A
3882680Sktlim@umich.edu    // Adjust path for current working directory
3892SN/A    path = p->fullPath(path);
3902680Sktlim@umich.edu
391716SN/A    int result = unlink(path.c_str());
3922SN/A    return (result == -1) ? -errno : result;
3932SN/A}
3942SN/A
3952SN/A
3962680Sktlim@umich.eduSyscallReturn
3972SN/AmkdirFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc)
3982455SN/A{
3992680Sktlim@umich.edu    string path;
4002SN/A
4012455SN/A    int index = 0;
4022680Sktlim@umich.edu    if (!tc->getMemPort()->tryReadString(path, p->getSyscallArg(tc, index)))
4032SN/A        return (TheISA::IntReg)-EFAULT;
4049920Syasuko.eckert@amd.com
4059920Syasuko.eckert@amd.com    // Adjust path for current working directory
4069920Syasuko.eckert@amd.com    path = p->fullPath(path);
4072SN/A
4082680Sktlim@umich.edu    mode_t mode = p->getSyscallArg(tc, index);
4092SN/A
4102455SN/A    int result = mkdir(path.c_str(), mode);
4112680Sktlim@umich.edu    return (result == -1) ? -errno : result;
4122SN/A}
4132455SN/A
4142680Sktlim@umich.eduSyscallReturn
4152SN/ArenameFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc)
4169920Syasuko.eckert@amd.com{
4179920Syasuko.eckert@amd.com    string old_name;
4189920Syasuko.eckert@amd.com
4197720Sgblack@eecs.umich.edu    int index = 0;
4202SN/A    if (!tc->getMemPort()->tryReadString(old_name, p->getSyscallArg(tc, index)))
4217720Sgblack@eecs.umich.edu        return -EFAULT;
4222206SN/A
4238733Sgeoffrey.blake@arm.com    string new_name;
4248733Sgeoffrey.blake@arm.com
4257720Sgblack@eecs.umich.edu    if (!tc->getMemPort()->tryReadString(new_name, p->getSyscallArg(tc, index)))
4267720Sgblack@eecs.umich.edu        return -EFAULT;
4277720Sgblack@eecs.umich.edu
4285260Sksewell@umich.edu    // Adjust path for current working directory
4297597Sminkyu.jeong@arm.com    old_name = p->fullPath(old_name);
4307597Sminkyu.jeong@arm.com    new_name = p->fullPath(new_name);
4317597Sminkyu.jeong@arm.com
4327597Sminkyu.jeong@arm.com    int64_t result = rename(old_name.c_str(), new_name.c_str());
4337597Sminkyu.jeong@arm.com    return (result == -1) ? -errno : result;
4344172Ssaidi@eecs.umich.edu}
4354172Ssaidi@eecs.umich.edu
4364172Ssaidi@eecs.umich.eduSyscallReturn
4372159SN/AtruncateFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc)
4382680Sktlim@umich.edu{
4392SN/A    string path;
4404172Ssaidi@eecs.umich.edu
4414172Ssaidi@eecs.umich.edu    int index = 0;
4422SN/A    if (!tc->getMemPort()->tryReadString(path, p->getSyscallArg(tc, index)))
4433468Sgblack@eecs.umich.edu        return -EFAULT;
4442680Sktlim@umich.edu
4452SN/A    off_t length = p->getSyscallArg(tc, index);
4466313Sgblack@eecs.umich.edu
4476313Sgblack@eecs.umich.edu    // Adjust path for current working directory
4486313Sgblack@eecs.umich.edu    path = p->fullPath(path);
4496313Sgblack@eecs.umich.edu
4506313Sgblack@eecs.umich.edu    int result = truncate(path.c_str(), length);
4516313Sgblack@eecs.umich.edu    return (result == -1) ? -errno : result;
4529920Syasuko.eckert@amd.com}
4539920Syasuko.eckert@amd.com
4549920Syasuko.eckert@amd.comSyscallReturn
45510033SAli.Saidi@ARM.comftruncateFunc(SyscallDesc *desc, int num,
45610033SAli.Saidi@ARM.com              LiveProcess *process, ThreadContext *tc)
45710033SAli.Saidi@ARM.com{
4582190SN/A    int index = 0;
4592680Sktlim@umich.edu    int fd = process->sim_fd(process->getSyscallArg(tc, index));
4602190SN/A
4612190SN/A    if (fd < 0)
4622680Sktlim@umich.edu        return -EBADF;
4632SN/A
4642190SN/A    off_t length = process->getSyscallArg(tc, index);
4652680Sktlim@umich.edu
4662190SN/A    int result = ftruncate(fd, length);
4674111Sgblack@eecs.umich.edu    return (result == -1) ? -errno : result;
4684111Sgblack@eecs.umich.edu}
4694111Sgblack@eecs.umich.edu
4702680Sktlim@umich.eduSyscallReturn
4719426SAndreas.Sandberg@ARM.comtruncate64Func(SyscallDesc *desc, int num,
4729426SAndreas.Sandberg@ARM.com                LiveProcess *process, ThreadContext *tc)
4739426SAndreas.Sandberg@ARM.com{
4749426SAndreas.Sandberg@ARM.com    int index = 0;
4759426SAndreas.Sandberg@ARM.com    string path;
4769426SAndreas.Sandberg@ARM.com
4779426SAndreas.Sandberg@ARM.com    if (!tc->getMemPort()->tryReadString(path, process->getSyscallArg(tc, index)))
4789426SAndreas.Sandberg@ARM.com       return -EFAULT;
4799426SAndreas.Sandberg@ARM.com
4809426SAndreas.Sandberg@ARM.com    int64_t length = process->getSyscallArg(tc, index, 64);
4819426SAndreas.Sandberg@ARM.com
4829426SAndreas.Sandberg@ARM.com    // Adjust path for current working directory
4839426SAndreas.Sandberg@ARM.com    path = process->fullPath(path);
4849426SAndreas.Sandberg@ARM.com
4859426SAndreas.Sandberg@ARM.com#if NO_STAT64
4869426SAndreas.Sandberg@ARM.com    int result = truncate(path.c_str(), length);
4879426SAndreas.Sandberg@ARM.com#else
4889426SAndreas.Sandberg@ARM.com    int result = truncate64(path.c_str(), length);
4899920Syasuko.eckert@amd.com#endif
4909920Syasuko.eckert@amd.com    return (result == -1) ? -errno : result;
4919920Syasuko.eckert@amd.com}
4929920Syasuko.eckert@amd.com
4939920Syasuko.eckert@amd.comSyscallReturn
4949920Syasuko.eckert@amd.comftruncate64Func(SyscallDesc *desc, int num,
4952SN/A                LiveProcess *process, ThreadContext *tc)
4962SN/A{
4979428SAndreas.Sandberg@ARM.com    int index = 0;
4989428SAndreas.Sandberg@ARM.com    int fd = process->sim_fd(process->getSyscallArg(tc, index));
4999428SAndreas.Sandberg@ARM.com
5009428SAndreas.Sandberg@ARM.com    if (fd < 0)
5019428SAndreas.Sandberg@ARM.com        return -EBADF;
5029428SAndreas.Sandberg@ARM.com
5039428SAndreas.Sandberg@ARM.com    int64_t length = process->getSyscallArg(tc, index, 64);
5049428SAndreas.Sandberg@ARM.com
5059428SAndreas.Sandberg@ARM.com#if NO_STAT64
5069428SAndreas.Sandberg@ARM.com    int result = ftruncate(fd, length);
5079428SAndreas.Sandberg@ARM.com#else
5089428SAndreas.Sandberg@ARM.com    int result = ftruncate64(fd, length);
5099428SAndreas.Sandberg@ARM.com#endif
5109428SAndreas.Sandberg@ARM.com    return (result == -1) ? -errno : result;
5119428SAndreas.Sandberg@ARM.com}
5129441SAndreas.Sandberg@ARM.com
5139441SAndreas.Sandberg@ARM.comSyscallReturn
5149441SAndreas.Sandberg@ARM.comumaskFunc(SyscallDesc *desc, int num, LiveProcess *process, ThreadContext *tc)
5159441SAndreas.Sandberg@ARM.com{
5169441SAndreas.Sandberg@ARM.com    // Letting the simulated program change the simulator's umask seems like
5179441SAndreas.Sandberg@ARM.com    // a bad idea.  Compromise by just returning the current umask but not
5189441SAndreas.Sandberg@ARM.com    // changing anything.
5199441SAndreas.Sandberg@ARM.com    mode_t oldMask = umask(0);
5209441SAndreas.Sandberg@ARM.com    umask(oldMask);
5219441SAndreas.Sandberg@ARM.com    return (int)oldMask;
5229441SAndreas.Sandberg@ARM.com}
5239441SAndreas.Sandberg@ARM.com
5249441SAndreas.Sandberg@ARM.comSyscallReturn
5252190SN/AchownFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc)
526{
527    string path;
528
529    int index = 0;
530    if (!tc->getMemPort()->tryReadString(path, p->getSyscallArg(tc, index)))
531        return -EFAULT;
532
533    /* XXX endianess */
534    uint32_t owner = p->getSyscallArg(tc, index);
535    uid_t hostOwner = owner;
536    uint32_t group = p->getSyscallArg(tc, index);
537    gid_t hostGroup = group;
538
539    // Adjust path for current working directory
540    path = p->fullPath(path);
541
542    int result = chown(path.c_str(), hostOwner, hostGroup);
543    return (result == -1) ? -errno : result;
544}
545
546SyscallReturn
547fchownFunc(SyscallDesc *desc, int num, LiveProcess *process, ThreadContext *tc)
548{
549    int index = 0;
550    int fd = process->sim_fd(process->getSyscallArg(tc, index));
551
552    if (fd < 0)
553        return -EBADF;
554
555    /* XXX endianess */
556    uint32_t owner = process->getSyscallArg(tc, index);
557    uid_t hostOwner = owner;
558    uint32_t group = process->getSyscallArg(tc, index);
559    gid_t hostGroup = group;
560
561    int result = fchown(fd, hostOwner, hostGroup);
562    return (result == -1) ? -errno : result;
563}
564
565
566SyscallReturn
567dupFunc(SyscallDesc *desc, int num, LiveProcess *process, ThreadContext *tc)
568{
569    int index = 0;
570    int fd = process->sim_fd(process->getSyscallArg(tc, index));
571    if (fd < 0)
572        return -EBADF;
573
574    Process::FdMap *fdo = process->sim_fd_obj(fd);
575
576    int result = dup(fd);
577    return (result == -1) ? -errno :
578        process->alloc_fd(result, fdo->filename, fdo->flags, fdo->mode, false);
579}
580
581
582SyscallReturn
583fcntlFunc(SyscallDesc *desc, int num, LiveProcess *process,
584          ThreadContext *tc)
585{
586    int index = 0;
587    int fd = process->getSyscallArg(tc, index);
588
589    if (fd < 0 || process->sim_fd(fd) < 0)
590        return -EBADF;
591
592    int cmd = process->getSyscallArg(tc, index);
593    switch (cmd) {
594      case 0: // F_DUPFD
595        // if we really wanted to support this, we'd need to do it
596        // in the target fd space.
597        warn("fcntl(%d, F_DUPFD) not supported, error returned\n", fd);
598        return -EMFILE;
599
600      case 1: // F_GETFD (get close-on-exec flag)
601      case 2: // F_SETFD (set close-on-exec flag)
602        return 0;
603
604      case 3: // F_GETFL (get file flags)
605      case 4: // F_SETFL (set file flags)
606        // not sure if this is totally valid, but we'll pass it through
607        // to the underlying OS
608        warn("fcntl(%d, %d) passed through to host\n", fd, cmd);
609        return fcntl(process->sim_fd(fd), cmd);
610        // return 0;
611
612      case 7: // F_GETLK  (get lock)
613      case 8: // F_SETLK  (set lock)
614      case 9: // F_SETLKW (set lock and wait)
615        // don't mess with file locking... just act like it's OK
616        warn("File lock call (fcntl(%d, %d)) ignored.\n", fd, cmd);
617        return 0;
618
619      default:
620        warn("Unknown fcntl command %d\n", cmd);
621        return 0;
622    }
623}
624
625SyscallReturn
626fcntl64Func(SyscallDesc *desc, int num, LiveProcess *process,
627            ThreadContext *tc)
628{
629    int index = 0;
630    int fd = process->getSyscallArg(tc, index);
631
632    if (fd < 0 || process->sim_fd(fd) < 0)
633        return -EBADF;
634
635    int cmd = process->getSyscallArg(tc, index);
636    switch (cmd) {
637      case 33: //F_GETLK64
638        warn("fcntl64(%d, F_GETLK64) not supported, error returned\n", fd);
639        return -EMFILE;
640
641      case 34: // F_SETLK64
642      case 35: // F_SETLKW64
643        warn("fcntl64(%d, F_SETLK(W)64) not supported, error returned\n", fd);
644        return -EMFILE;
645
646      default:
647        // not sure if this is totally valid, but we'll pass it through
648        // to the underlying OS
649        warn("fcntl64(%d, %d) passed through to host\n", fd, cmd);
650        return fcntl(process->sim_fd(fd), cmd);
651        // return 0;
652    }
653}
654
655SyscallReturn
656pipePseudoFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
657         ThreadContext *tc)
658{
659    int fds[2], sim_fds[2];
660    int pipe_retval = pipe(fds);
661
662    if (pipe_retval < 0) {
663        // error
664        return pipe_retval;
665    }
666
667    sim_fds[0] = process->alloc_fd(fds[0], "PIPE-READ", O_WRONLY, -1, true);
668    sim_fds[1] = process->alloc_fd(fds[1], "PIPE-WRITE", O_RDONLY, -1, true);
669
670    process->setReadPipeSource(sim_fds[0], sim_fds[1]);
671    // Alpha Linux convention for pipe() is that fd[0] is returned as
672    // the return value of the function, and fd[1] is returned in r20.
673    tc->setIntReg(SyscallPseudoReturnReg, sim_fds[1]);
674    return sim_fds[0];
675}
676
677
678SyscallReturn
679getpidPseudoFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
680           ThreadContext *tc)
681{
682    // Make up a PID.  There's no interprocess communication in
683    // fake_syscall mode, so there's no way for a process to know it's
684    // not getting a unique value.
685
686    tc->setIntReg(SyscallPseudoReturnReg, process->ppid());
687    return process->pid();
688}
689
690
691SyscallReturn
692getuidPseudoFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
693           ThreadContext *tc)
694{
695    // Make up a UID and EUID... it shouldn't matter, and we want the
696    // simulation to be deterministic.
697
698    // EUID goes in r20.
699    tc->setIntReg(SyscallPseudoReturnReg, process->euid()); //EUID
700    return process->uid();              // UID
701}
702
703
704SyscallReturn
705getgidPseudoFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
706           ThreadContext *tc)
707{
708    // Get current group ID.  EGID goes in r20.
709    tc->setIntReg(SyscallPseudoReturnReg, process->egid()); //EGID
710    return process->gid();
711}
712
713
714SyscallReturn
715setuidFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
716           ThreadContext *tc)
717{
718    // can't fathom why a benchmark would call this.
719    int index = 0;
720    warn("Ignoring call to setuid(%d)\n", process->getSyscallArg(tc, index));
721    return 0;
722}
723
724SyscallReturn
725getpidFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
726           ThreadContext *tc)
727{
728    // Make up a PID.  There's no interprocess communication in
729    // fake_syscall mode, so there's no way for a process to know it's
730    // not getting a unique value.
731
732    tc->setIntReg(SyscallPseudoReturnReg, process->ppid()); //PID
733    return process->pid();
734}
735
736SyscallReturn
737getppidFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
738           ThreadContext *tc)
739{
740    return process->ppid();
741}
742
743SyscallReturn
744getuidFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
745           ThreadContext *tc)
746{
747    return process->uid();              // UID
748}
749
750SyscallReturn
751geteuidFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
752           ThreadContext *tc)
753{
754    return process->euid();             // UID
755}
756
757SyscallReturn
758getgidFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
759           ThreadContext *tc)
760{
761    return process->gid();
762}
763
764SyscallReturn
765getegidFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
766           ThreadContext *tc)
767{
768    return process->egid();
769}
770
771
772SyscallReturn
773cloneFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
774           ThreadContext *tc)
775{
776    int index = 0;
777    IntReg flags = process->getSyscallArg(tc, index);
778    IntReg newStack = process->getSyscallArg(tc, index);
779
780    DPRINTF(SyscallVerbose, "In sys_clone:\n");
781    DPRINTF(SyscallVerbose, " Flags=%llx\n", flags);
782    DPRINTF(SyscallVerbose, " Child stack=%llx\n", newStack);
783
784
785    if (flags != 0x10f00) {
786        warn("This sys_clone implementation assumes flags "
787             "CLONE_VM|CLONE_FS|CLONE_FILES|CLONE_SIGHAND|CLONE_THREAD "
788             "(0x10f00), and may not work correctly with given flags "
789             "0x%llx\n", flags);
790    }
791
792    ThreadContext* ctc; // child thread context
793    if ( ( ctc = process->findFreeContext() ) != NULL ) {
794        DPRINTF(SyscallVerbose, " Found unallocated thread context\n");
795
796        ctc->clearArchRegs();
797
798        // Arch-specific cloning code
799        #if THE_ISA == ALPHA_ISA or THE_ISA == X86_ISA
800            // Cloning the misc. regs for these archs is enough
801            TheISA::copyMiscRegs(tc, ctc);
802        #elif THE_ISA == SPARC_ISA
803            TheISA::copyRegs(tc, ctc);
804
805            // TODO: Explain what this code actually does :-)
806            ctc->setIntReg(NumIntArchRegs + 6, 0);
807            ctc->setIntReg(NumIntArchRegs + 4, 0);
808            ctc->setIntReg(NumIntArchRegs + 3, NWindows - 2);
809            ctc->setIntReg(NumIntArchRegs + 5, NWindows);
810            ctc->setMiscReg(MISCREG_CWP, 0);
811            ctc->setIntReg(NumIntArchRegs + 7, 0);
812            ctc->setMiscRegNoEffect(MISCREG_TL, 0);
813            ctc->setMiscRegNoEffect(MISCREG_ASI, ASI_PRIMARY);
814
815            for (int y = 8; y < 32; y++)
816                ctc->setIntReg(y, tc->readIntReg(y));
817        #elif THE_ISA == ARM_ISA
818            TheISA::copyRegs(tc, ctc);
819        #else
820            fatal("sys_clone is not implemented for this ISA\n");
821        #endif
822
823        // Set up stack register
824        ctc->setIntReg(TheISA::StackPointerReg, newStack);
825
826        // Set up syscall return values in parent and child
827        ctc->setIntReg(ReturnValueReg, 0); // return value, child
828
829        // Alpha needs SyscallSuccessReg=0 in child
830        #if THE_ISA == ALPHA_ISA
831            ctc->setIntReg(TheISA::SyscallSuccessReg, 0);
832        #endif
833
834        // In SPARC/Linux, clone returns 0 on pseudo-return register if
835        // parent, non-zero if child
836        #if THE_ISA == SPARC_ISA
837            tc->setIntReg(TheISA::SyscallPseudoReturnReg, 0);
838            ctc->setIntReg(TheISA::SyscallPseudoReturnReg, 1);
839        #endif
840
841        ctc->pcState(tc->nextInstAddr());
842
843        ctc->activate();
844
845        // Should return nonzero child TID in parent's syscall return register,
846        // but for our pthread library any non-zero value will work
847        return 1;
848    } else {
849        fatal("Called sys_clone, but no unallocated thread contexts found!\n");
850        return 0;
851    }
852}
853
854