syscall_emul.cc revision 13883
1360SN/A/*
21458SN/A * Copyright (c) 2003-2005 The Regents of The University of Michigan
3360SN/A * All rights reserved.
4360SN/A *
5360SN/A * Redistribution and use in source and binary forms, with or without
6360SN/A * modification, are permitted provided that the following conditions are
7360SN/A * met: redistributions of source code must retain the above copyright
8360SN/A * notice, this list of conditions and the following disclaimer;
9360SN/A * redistributions in binary form must reproduce the above copyright
10360SN/A * notice, this list of conditions and the following disclaimer in the
11360SN/A * documentation and/or other materials provided with the distribution;
12360SN/A * neither the name of the copyright holders nor the names of its
13360SN/A * contributors may be used to endorse or promote products derived from
14360SN/A * this software without specific prior written permission.
15360SN/A *
16360SN/A * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17360SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18360SN/A * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19360SN/A * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20360SN/A * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21360SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22360SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23360SN/A * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24360SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25360SN/A * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26360SN/A * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
272665Ssaidi@eecs.umich.edu *
282665Ssaidi@eecs.umich.edu * Authors: Steve Reinhardt
292665Ssaidi@eecs.umich.edu *          Ali Saidi
30360SN/A */
31360SN/A
3211793Sbrandon.potter@amd.com#include "sim/syscall_emul.hh"
3311793Sbrandon.potter@amd.com
342093SN/A#include <fcntl.h>
3513479Santhony.gutierrez@amd.com#include <sys/syscall.h>
36360SN/A#include <unistd.h>
37360SN/A
3811911SBrandon.Potter@amd.com#include <csignal>
396712Snate@binkert.org#include <iostream>
4013031Sbrandon.potter@amd.com#include <mutex>
41360SN/A#include <string>
42360SN/A
437680Sgblack@eecs.umich.edu#include "arch/utility.hh"
442474SN/A#include "base/chunk_generator.hh"
45360SN/A#include "base/trace.hh"
466658Snate@binkert.org#include "config/the_isa.hh"
472680Sktlim@umich.edu#include "cpu/thread_context.hh"
4812716Smichael.lebeane@amd.com#include "dev/net/dist_iface.hh"
492474SN/A#include "mem/page_table.hh"
5013031Sbrandon.potter@amd.com#include "sim/byteswap.hh"
51360SN/A#include "sim/process.hh"
528229Snate@binkert.org#include "sim/sim_exit.hh"
5311794Sbrandon.potter@amd.com#include "sim/syscall_debug_macros.hh"
5411794Sbrandon.potter@amd.com#include "sim/syscall_desc.hh"
556029Ssteve.reinhardt@amd.com#include "sim/system.hh"
56360SN/A
57360SN/Ausing namespace std;
582107SN/Ausing namespace TheISA;
59360SN/A
601450SN/ASyscallReturn
6111851Sbrandon.potter@amd.comunimplementedFunc(SyscallDesc *desc, int callnum, Process *process,
622680Sktlim@umich.edu                  ThreadContext *tc)
63360SN/A{
6411794Sbrandon.potter@amd.com    fatal("syscall %s (#%d) unimplemented.", desc->name(), callnum);
652484SN/A
662484SN/A    return 1;
67360SN/A}
68360SN/A
69360SN/A
701450SN/ASyscallReturn
7111851Sbrandon.potter@amd.comignoreFunc(SyscallDesc *desc, int callnum, Process *process,
722680Sktlim@umich.edu           ThreadContext *tc)
73360SN/A{
7411794Sbrandon.potter@amd.com    if (desc->needWarning()) {
7511794Sbrandon.potter@amd.com        warn("ignoring syscall %s(...)%s", desc->name(), desc->warnOnce() ?
7611794Sbrandon.potter@amd.com             "\n      (further warnings will be suppressed)" : "");
7710831Ssteve.reinhardt@amd.com    }
78360SN/A
798149SChris.Emmons@ARM.com    return 0;
808149SChris.Emmons@ARM.com}
818149SChris.Emmons@ARM.com
8211886Sbrandon.potter@amd.comstatic void
8311911SBrandon.Potter@amd.comexitFutexWake(ThreadContext *tc, Addr addr, uint64_t tgid)
8411886Sbrandon.potter@amd.com{
8511911SBrandon.Potter@amd.com    // Clear value at address pointed to by thread's childClearTID field.
8611911SBrandon.Potter@amd.com    BufferArg ctidBuf(addr, sizeof(long));
8711911SBrandon.Potter@amd.com    long *ctid = (long *)ctidBuf.bufferPtr();
8811911SBrandon.Potter@amd.com    *ctid = 0;
8911911SBrandon.Potter@amd.com    ctidBuf.copyOut(tc->getMemProxy());
9011886Sbrandon.potter@amd.com
9111911SBrandon.Potter@amd.com    FutexMap &futex_map = tc->getSystemPtr()->futexMap;
9211911SBrandon.Potter@amd.com    // Wake one of the waiting threads.
9311911SBrandon.Potter@amd.com    futex_map.wakeup(addr, tgid, 1);
9411911SBrandon.Potter@amd.com}
9511911SBrandon.Potter@amd.com
9611911SBrandon.Potter@amd.comstatic SyscallReturn
9711911SBrandon.Potter@amd.comexitImpl(SyscallDesc *desc, int callnum, Process *p, ThreadContext *tc,
9811911SBrandon.Potter@amd.com         bool group)
9911911SBrandon.Potter@amd.com{
10011911SBrandon.Potter@amd.com    int index = 0;
10111911SBrandon.Potter@amd.com    int status = p->getSyscallArg(tc, index);
10211911SBrandon.Potter@amd.com
10311911SBrandon.Potter@amd.com    System *sys = tc->getSystemPtr();
10411911SBrandon.Potter@amd.com
10511911SBrandon.Potter@amd.com    if (group)
10611911SBrandon.Potter@amd.com        *p->exitGroup = true;
10711911SBrandon.Potter@amd.com
10811911SBrandon.Potter@amd.com    if (p->childClearTID)
10911911SBrandon.Potter@amd.com        exitFutexWake(tc, p->childClearTID, p->tgid());
11011911SBrandon.Potter@amd.com
11111911SBrandon.Potter@amd.com    bool last_thread = true;
11211911SBrandon.Potter@amd.com    Process *parent = nullptr, *tg_lead = nullptr;
11311911SBrandon.Potter@amd.com    for (int i = 0; last_thread && i < sys->numContexts(); i++) {
11411911SBrandon.Potter@amd.com        Process *walk;
11511911SBrandon.Potter@amd.com        if (!(walk = sys->threadContexts[i]->getProcessPtr()))
11611911SBrandon.Potter@amd.com            continue;
11711911SBrandon.Potter@amd.com
11811911SBrandon.Potter@amd.com        /**
11911911SBrandon.Potter@amd.com         * Threads in a thread group require special handing. For instance,
12011911SBrandon.Potter@amd.com         * we send the SIGCHLD signal so that it appears that it came from
12111911SBrandon.Potter@amd.com         * the head of the group. We also only delete file descriptors if
12211911SBrandon.Potter@amd.com         * we are the last thread in the thread group.
12311911SBrandon.Potter@amd.com         */
12411911SBrandon.Potter@amd.com        if (walk->pid() == p->tgid())
12511911SBrandon.Potter@amd.com            tg_lead = walk;
12611911SBrandon.Potter@amd.com
12713644Sqtt2@cornell.edu        if ((sys->threadContexts[i]->status() != ThreadContext::Halted) &&
12813644Sqtt2@cornell.edu            (sys->threadContexts[i]->status() != ThreadContext::Halting) &&
12913644Sqtt2@cornell.edu            (walk != p)) {
13011911SBrandon.Potter@amd.com            /**
13111911SBrandon.Potter@amd.com             * Check if we share thread group with the pointer; this denotes
13211911SBrandon.Potter@amd.com             * that we are not the last thread active in the thread group.
13311911SBrandon.Potter@amd.com             * Note that setting this to false also prevents further
13411911SBrandon.Potter@amd.com             * iterations of the loop.
13511911SBrandon.Potter@amd.com             */
13613644Sqtt2@cornell.edu            if (walk->tgid() == p->tgid()) {
13713644Sqtt2@cornell.edu                /**
13813644Sqtt2@cornell.edu                 * If p is trying to exit_group and both walk and p are in
13913644Sqtt2@cornell.edu                 * the same thread group (i.e., sharing the same tgid),
14013644Sqtt2@cornell.edu                 * we need to halt walk's thread context. After all threads
14113644Sqtt2@cornell.edu                 * except p are halted, p becomes the last thread in the
14213644Sqtt2@cornell.edu                 * group.
14313644Sqtt2@cornell.edu                 *
14413644Sqtt2@cornell.edu                 * If p is not doing exit_group and there exists another
14513644Sqtt2@cornell.edu                 * active thread context in the group, last_thread is
14613644Sqtt2@cornell.edu                 * set to false to prevent the parent thread from killing
14713644Sqtt2@cornell.edu                 * all threads in the group.
14813644Sqtt2@cornell.edu                 */
14913644Sqtt2@cornell.edu                if (*(p->exitGroup)) {
15013644Sqtt2@cornell.edu                    sys->threadContexts[i]->halt();
15113644Sqtt2@cornell.edu                } else {
15213644Sqtt2@cornell.edu                    last_thread = false;
15313644Sqtt2@cornell.edu                }
15413644Sqtt2@cornell.edu            }
15511911SBrandon.Potter@amd.com
15611911SBrandon.Potter@amd.com            /**
15711911SBrandon.Potter@amd.com             * A corner case exists which involves execve(). After execve(),
15811911SBrandon.Potter@amd.com             * the execve will enable SIGCHLD in the process. The problem
15911911SBrandon.Potter@amd.com             * occurs when the exiting process is the root process in the
16011911SBrandon.Potter@amd.com             * system; there is no parent to receive the signal. We obviate
16111911SBrandon.Potter@amd.com             * this problem by setting the root process' ppid to zero in the
16211911SBrandon.Potter@amd.com             * Python configuration files. We really should handle the
16311911SBrandon.Potter@amd.com             * root/execve specific case more gracefully.
16411911SBrandon.Potter@amd.com             */
16511911SBrandon.Potter@amd.com            if (*p->sigchld && (p->ppid() != 0) && (walk->pid() == p->ppid()))
16611911SBrandon.Potter@amd.com                parent = walk;
16711886Sbrandon.potter@amd.com        }
16811886Sbrandon.potter@amd.com    }
16911911SBrandon.Potter@amd.com
17011911SBrandon.Potter@amd.com    if (last_thread) {
17111911SBrandon.Potter@amd.com        if (parent) {
17211911SBrandon.Potter@amd.com            assert(tg_lead);
17311911SBrandon.Potter@amd.com            sys->signalList.push_back(BasicSignal(tg_lead, parent, SIGCHLD));
17411911SBrandon.Potter@amd.com        }
17511911SBrandon.Potter@amd.com
17611911SBrandon.Potter@amd.com        /**
17711911SBrandon.Potter@amd.com         * Run though FD array of the exiting process and close all file
17811911SBrandon.Potter@amd.com         * descriptors except for the standard file descriptors.
17911911SBrandon.Potter@amd.com         * (The standard file descriptors are shared with gem5.)
18011911SBrandon.Potter@amd.com         */
18111911SBrandon.Potter@amd.com        for (int i = 0; i < p->fds->getSize(); i++) {
18211911SBrandon.Potter@amd.com            if ((*p->fds)[i])
18311911SBrandon.Potter@amd.com                p->fds->closeFDEntry(i);
18411911SBrandon.Potter@amd.com        }
18511911SBrandon.Potter@amd.com    }
18611911SBrandon.Potter@amd.com
18711911SBrandon.Potter@amd.com    tc->halt();
18813644Sqtt2@cornell.edu
18913644Sqtt2@cornell.edu    /**
19013644Sqtt2@cornell.edu     * check to see if there is no more active thread in the system. If so,
19113644Sqtt2@cornell.edu     * exit the simulation loop
19213644Sqtt2@cornell.edu     */
19313644Sqtt2@cornell.edu    int activeContexts = 0;
19413644Sqtt2@cornell.edu    for (auto &system: sys->systemList)
19513644Sqtt2@cornell.edu        activeContexts += system->numRunningContexts();
19613644Sqtt2@cornell.edu
19713644Sqtt2@cornell.edu    if (activeContexts == 0) {
19813644Sqtt2@cornell.edu        /**
19913644Sqtt2@cornell.edu         * Even though we are terminating the final thread context, dist-gem5
20013644Sqtt2@cornell.edu         * requires the simulation to remain active and provide
20113644Sqtt2@cornell.edu         * synchronization messages to the switch process. So we just halt
20213644Sqtt2@cornell.edu         * the last thread context and return. The simulation will be
20313644Sqtt2@cornell.edu         * terminated by dist-gem5 in a coordinated manner once all nodes
20413644Sqtt2@cornell.edu         * have signaled their readiness to exit. For non dist-gem5
20513644Sqtt2@cornell.edu         * simulations, readyToExit() always returns true.
20613644Sqtt2@cornell.edu         */
20713644Sqtt2@cornell.edu        if (!DistIface::readyToExit(0)) {
20813644Sqtt2@cornell.edu            return status;
20913644Sqtt2@cornell.edu        }
21013644Sqtt2@cornell.edu
21113644Sqtt2@cornell.edu        exitSimLoop("exiting with last active thread context", status & 0xff);
21213644Sqtt2@cornell.edu        return status;
21313644Sqtt2@cornell.edu    }
21413644Sqtt2@cornell.edu
21511911SBrandon.Potter@amd.com    return status;
21611886Sbrandon.potter@amd.com}
2178149SChris.Emmons@ARM.com
2188149SChris.Emmons@ARM.comSyscallReturn
21911886Sbrandon.potter@amd.comexitFunc(SyscallDesc *desc, int callnum, Process *p, ThreadContext *tc)
220360SN/A{
22111911SBrandon.Potter@amd.com    return exitImpl(desc, callnum, p, tc, false);
222360SN/A}
223360SN/A
2241450SN/ASyscallReturn
22511911SBrandon.Potter@amd.comexitGroupFunc(SyscallDesc *desc, int callnum, Process *p, ThreadContext *tc)
2266109Ssanchezd@stanford.edu{
22711911SBrandon.Potter@amd.com    return exitImpl(desc, callnum, p, tc, true);
2286109Ssanchezd@stanford.edu}
2296109Ssanchezd@stanford.edu
2306109Ssanchezd@stanford.eduSyscallReturn
23111851Sbrandon.potter@amd.comgetpagesizeFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
232360SN/A{
23310318Sandreas.hansson@arm.com    return (int)PageBytes;
234360SN/A}
235360SN/A
236360SN/A
2371450SN/ASyscallReturn
23811851Sbrandon.potter@amd.combrkFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
239360SN/A{
240360SN/A    // change brk addr to first arg
2416701Sgblack@eecs.umich.edu    int index = 0;
2426701Sgblack@eecs.umich.edu    Addr new_brk = p->getSyscallArg(tc, index);
2435748SSteve.Reinhardt@amd.com
24411905SBrandon.Potter@amd.com    std::shared_ptr<MemState> mem_state = p->memState;
24511905SBrandon.Potter@amd.com    Addr brk_point = mem_state->getBrkPoint();
24611905SBrandon.Potter@amd.com
2475748SSteve.Reinhardt@amd.com    // in Linux at least, brk(0) returns the current break value
2485748SSteve.Reinhardt@amd.com    // (note that the syscall and the glibc function have different behavior)
2495748SSteve.Reinhardt@amd.com    if (new_brk == 0)
25011905SBrandon.Potter@amd.com        return brk_point;
2515748SSteve.Reinhardt@amd.com
25211905SBrandon.Potter@amd.com    if (new_brk > brk_point) {
2535748SSteve.Reinhardt@amd.com        // might need to allocate some new pages
25411905SBrandon.Potter@amd.com        for (ChunkGenerator gen(brk_point,
25511905SBrandon.Potter@amd.com                                new_brk - brk_point,
25610318Sandreas.hansson@arm.com                                PageBytes); !gen.done(); gen.next()) {
2575748SSteve.Reinhardt@amd.com            if (!p->pTable->translate(gen.addr()))
25810318Sandreas.hansson@arm.com                p->allocateMem(roundDown(gen.addr(), PageBytes), PageBytes);
2596687Stjones1@inf.ed.ac.uk
2606687Stjones1@inf.ed.ac.uk            // if the address is already there, zero it out
2616687Stjones1@inf.ed.ac.uk            else {
26211905SBrandon.Potter@amd.com                uint8_t zero = 0;
2638852Sandreas.hansson@arm.com                SETranslatingPortProxy &tp = tc->getMemProxy();
2646687Stjones1@inf.ed.ac.uk
2656687Stjones1@inf.ed.ac.uk                // split non-page aligned accesses
26610318Sandreas.hansson@arm.com                Addr next_page = roundUp(gen.addr(), PageBytes);
2676687Stjones1@inf.ed.ac.uk                uint32_t size_needed = next_page - gen.addr();
2688852Sandreas.hansson@arm.com                tp.memsetBlob(gen.addr(), zero, size_needed);
26910318Sandreas.hansson@arm.com                if (gen.addr() + PageBytes > next_page &&
2706687Stjones1@inf.ed.ac.uk                    next_page < new_brk &&
27111906SBrandon.Potter@amd.com                    p->pTable->translate(next_page)) {
27210318Sandreas.hansson@arm.com                    size_needed = PageBytes - size_needed;
2738852Sandreas.hansson@arm.com                    tp.memsetBlob(next_page, zero, size_needed);
2746687Stjones1@inf.ed.ac.uk                }
2756687Stjones1@inf.ed.ac.uk            }
2762474SN/A        }
2771450SN/A    }
2785748SSteve.Reinhardt@amd.com
27911905SBrandon.Potter@amd.com    mem_state->setBrkPoint(new_brk);
28011380Salexandru.dutu@amd.com    DPRINTF_SYSCALL(Verbose, "brk: break point changed to: %#X\n",
28111905SBrandon.Potter@amd.com                    mem_state->getBrkPoint());
28211905SBrandon.Potter@amd.com    return mem_state->getBrkPoint();
283360SN/A}
284360SN/A
28511886Sbrandon.potter@amd.comSyscallReturn
28611886Sbrandon.potter@amd.comsetTidAddressFunc(SyscallDesc *desc, int callnum, Process *process,
28711886Sbrandon.potter@amd.com                  ThreadContext *tc)
28811886Sbrandon.potter@amd.com{
28911886Sbrandon.potter@amd.com    int index = 0;
29011886Sbrandon.potter@amd.com    uint64_t tidPtr = process->getSyscallArg(tc, index);
29111886Sbrandon.potter@amd.com
29211886Sbrandon.potter@amd.com    process->childClearTID = tidPtr;
29311886Sbrandon.potter@amd.com    return process->pid();
29411886Sbrandon.potter@amd.com}
295360SN/A
2961450SN/ASyscallReturn
29711851Sbrandon.potter@amd.comcloseFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
298360SN/A{
2996701Sgblack@eecs.umich.edu    int index = 0;
30010931Sbrandon.potter@amd.com    int tgt_fd = p->getSyscallArg(tc, index);
30110931Sbrandon.potter@amd.com
30211856Sbrandon.potter@amd.com    return p->fds->closeFDEntry(tgt_fd);
303360SN/A}
304360SN/A
3051450SN/ASyscallReturn
30611851Sbrandon.potter@amd.comlseekFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
307360SN/A{
3086701Sgblack@eecs.umich.edu    int index = 0;
30910931Sbrandon.potter@amd.com    int tgt_fd = p->getSyscallArg(tc, index);
3106701Sgblack@eecs.umich.edu    uint64_t offs = p->getSyscallArg(tc, index);
3116701Sgblack@eecs.umich.edu    int whence = p->getSyscallArg(tc, index);
312360SN/A
31311856Sbrandon.potter@amd.com    auto ffdp = std::dynamic_pointer_cast<FileFDEntry>((*p->fds)[tgt_fd]);
31411856Sbrandon.potter@amd.com    if (!ffdp)
31510931Sbrandon.potter@amd.com        return -EBADF;
31611856Sbrandon.potter@amd.com    int sim_fd = ffdp->getSimFD();
31710931Sbrandon.potter@amd.com
31810931Sbrandon.potter@amd.com    off_t result = lseek(sim_fd, offs, whence);
319360SN/A
3201458SN/A    return (result == (off_t)-1) ? -errno : result;
321360SN/A}
322360SN/A
323360SN/A
3241450SN/ASyscallReturn
32511851Sbrandon.potter@amd.com_llseekFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
3264118Sgblack@eecs.umich.edu{
3276701Sgblack@eecs.umich.edu    int index = 0;
32810931Sbrandon.potter@amd.com    int tgt_fd = p->getSyscallArg(tc, index);
3296701Sgblack@eecs.umich.edu    uint64_t offset_high = p->getSyscallArg(tc, index);
3306701Sgblack@eecs.umich.edu    uint32_t offset_low = p->getSyscallArg(tc, index);
3316701Sgblack@eecs.umich.edu    Addr result_ptr = p->getSyscallArg(tc, index);
3326701Sgblack@eecs.umich.edu    int whence = p->getSyscallArg(tc, index);
3334118Sgblack@eecs.umich.edu
33411856Sbrandon.potter@amd.com    auto ffdp = std::dynamic_pointer_cast<FileFDEntry>((*p->fds)[tgt_fd]);
33511856Sbrandon.potter@amd.com    if (!ffdp)
33610931Sbrandon.potter@amd.com        return -EBADF;
33711856Sbrandon.potter@amd.com    int sim_fd = ffdp->getSimFD();
33810931Sbrandon.potter@amd.com
3394118Sgblack@eecs.umich.edu    uint64_t offset = (offset_high << 32) | offset_low;
3404118Sgblack@eecs.umich.edu
34110931Sbrandon.potter@amd.com    uint64_t result = lseek(sim_fd, offset, whence);
3424118Sgblack@eecs.umich.edu    result = TheISA::htog(result);
3434118Sgblack@eecs.umich.edu
34411379Sbrandon.potter@amd.com    if (result == (off_t)-1)
3454118Sgblack@eecs.umich.edu        return -errno;
34611379Sbrandon.potter@amd.com    // Assuming that the size of loff_t is 64 bits on the target platform
34711379Sbrandon.potter@amd.com    BufferArg result_buf(result_ptr, sizeof(result));
34811379Sbrandon.potter@amd.com    memcpy(result_buf.bufferPtr(), &result, sizeof(result));
34911379Sbrandon.potter@amd.com    result_buf.copyOut(tc->getMemProxy());
35011379Sbrandon.potter@amd.com    return 0;
3514118Sgblack@eecs.umich.edu}
3524118Sgblack@eecs.umich.edu
3534118Sgblack@eecs.umich.edu
3544118Sgblack@eecs.umich.eduSyscallReturn
35511851Sbrandon.potter@amd.communmapFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
356360SN/A{
35711383Sbrandon.potter@amd.com    // With mmap more fully implemented, it might be worthwhile to bite
35811383Sbrandon.potter@amd.com    // the bullet and implement munmap. Should allow us to reuse simulated
35911383Sbrandon.potter@amd.com    // memory.
3601458SN/A    return 0;
361360SN/A}
362360SN/A
363360SN/A
364360SN/Aconst char *hostname = "m5.eecs.umich.edu";
365360SN/A
3661450SN/ASyscallReturn
36711851Sbrandon.potter@amd.comgethostnameFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
368360SN/A{
3696701Sgblack@eecs.umich.edu    int index = 0;
37011906SBrandon.Potter@amd.com    Addr buf_ptr = p->getSyscallArg(tc, index);
3716701Sgblack@eecs.umich.edu    int name_len = p->getSyscallArg(tc, index);
37211906SBrandon.Potter@amd.com    BufferArg name(buf_ptr, name_len);
373360SN/A
374360SN/A    strncpy((char *)name.bufferPtr(), hostname, name_len);
375360SN/A
3768706Sandreas.hansson@arm.com    name.copyOut(tc->getMemProxy());
377360SN/A
3781458SN/A    return 0;
379360SN/A}
380360SN/A
3811450SN/ASyscallReturn
38211851Sbrandon.potter@amd.comgetcwdFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
3835513SMichael.Adler@intel.com{
3845513SMichael.Adler@intel.com    int result = 0;
3856731Svince@csl.cornell.edu    int index = 0;
38611906SBrandon.Potter@amd.com    Addr buf_ptr = p->getSyscallArg(tc, index);
3876701Sgblack@eecs.umich.edu    unsigned long size = p->getSyscallArg(tc, index);
38811906SBrandon.Potter@amd.com    BufferArg buf(buf_ptr, size);
3895513SMichael.Adler@intel.com
3905513SMichael.Adler@intel.com    // Is current working directory defined?
39113883Sdavid.hashe@amd.com    string cwd = p->tgtCwd;
3925513SMichael.Adler@intel.com    if (!cwd.empty()) {
3935513SMichael.Adler@intel.com        if (cwd.length() >= size) {
3945513SMichael.Adler@intel.com            // Buffer too small
3955513SMichael.Adler@intel.com            return -ERANGE;
3965513SMichael.Adler@intel.com        }
3975513SMichael.Adler@intel.com        strncpy((char *)buf.bufferPtr(), cwd.c_str(), size);
3985513SMichael.Adler@intel.com        result = cwd.length();
39910955Sdavid.hashe@amd.com    } else {
40011856Sbrandon.potter@amd.com        if (getcwd((char *)buf.bufferPtr(), size)) {
4015513SMichael.Adler@intel.com            result = strlen((char *)buf.bufferPtr());
40210955Sdavid.hashe@amd.com        } else {
4035513SMichael.Adler@intel.com            result = -1;
4045513SMichael.Adler@intel.com        }
4055513SMichael.Adler@intel.com    }
4065513SMichael.Adler@intel.com
4078706Sandreas.hansson@arm.com    buf.copyOut(tc->getMemProxy());
4085513SMichael.Adler@intel.com
4095513SMichael.Adler@intel.com    return (result == -1) ? -errno : result;
4105513SMichael.Adler@intel.com}
4115513SMichael.Adler@intel.com
41210203SAli.Saidi@ARM.comSyscallReturn
41311851Sbrandon.potter@amd.comreadlinkFunc(SyscallDesc *desc, int callnum, Process *process,
41411851Sbrandon.potter@amd.com             ThreadContext *tc)
41510203SAli.Saidi@ARM.com{
41610203SAli.Saidi@ARM.com    return readlinkFunc(desc, callnum, process, tc, 0);
41710203SAli.Saidi@ARM.com}
4185513SMichael.Adler@intel.com
4195513SMichael.Adler@intel.comSyscallReturn
42011851Sbrandon.potter@amd.comreadlinkFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc,
42111851Sbrandon.potter@amd.com             int index)
4225513SMichael.Adler@intel.com{
4235513SMichael.Adler@intel.com    string path;
4245513SMichael.Adler@intel.com
4258852Sandreas.hansson@arm.com    if (!tc->getMemProxy().tryReadString(path, p->getSyscallArg(tc, index)))
42610223Ssteve.reinhardt@amd.com        return -EFAULT;
4275513SMichael.Adler@intel.com
42813883Sdavid.hashe@amd.com    // Adjust path for cwd and redirection
42913883Sdavid.hashe@amd.com    path = p->checkPathRedirect(path);
4305513SMichael.Adler@intel.com
43111906SBrandon.Potter@amd.com    Addr buf_ptr = p->getSyscallArg(tc, index);
4326701Sgblack@eecs.umich.edu    size_t bufsiz = p->getSyscallArg(tc, index);
4336701Sgblack@eecs.umich.edu
43411906SBrandon.Potter@amd.com    BufferArg buf(buf_ptr, bufsiz);
4355513SMichael.Adler@intel.com
43610955Sdavid.hashe@amd.com    int result = -1;
43710955Sdavid.hashe@amd.com    if (path != "/proc/self/exe") {
43810955Sdavid.hashe@amd.com        result = readlink(path.c_str(), (char *)buf.bufferPtr(), bufsiz);
43910955Sdavid.hashe@amd.com    } else {
44011140Sjthestness@gmail.com        // Emulate readlink() called on '/proc/self/exe' should return the
44111140Sjthestness@gmail.com        // absolute path of the binary running in the simulated system (the
44211851Sbrandon.potter@amd.com        // Process' executable). It is possible that using this path in
44311140Sjthestness@gmail.com        // the simulated system will result in unexpected behavior if:
44411140Sjthestness@gmail.com        //  1) One binary runs another (e.g., -c time -o "my_binary"), and
44511140Sjthestness@gmail.com        //     called binary calls readlink().
44611140Sjthestness@gmail.com        //  2) The host's full path to the running benchmark changes from one
44711140Sjthestness@gmail.com        //     simulation to another. This can result in different simulated
44811140Sjthestness@gmail.com        //     performance since the simulated system will process the binary
44911140Sjthestness@gmail.com        //     path differently, even if the binary itself does not change.
45011140Sjthestness@gmail.com
45111140Sjthestness@gmail.com        // Get the absolute canonical path to the running application
45211140Sjthestness@gmail.com        char real_path[PATH_MAX];
45311140Sjthestness@gmail.com        char *check_real_path = realpath(p->progName(), real_path);
45411140Sjthestness@gmail.com        if (!check_real_path) {
45511140Sjthestness@gmail.com            fatal("readlink('/proc/self/exe') unable to resolve path to "
45611140Sjthestness@gmail.com                  "executable: %s", p->progName());
45711140Sjthestness@gmail.com        }
45811140Sjthestness@gmail.com        strncpy((char*)buf.bufferPtr(), real_path, bufsiz);
45911140Sjthestness@gmail.com        size_t real_path_len = strlen(real_path);
46011140Sjthestness@gmail.com        if (real_path_len > bufsiz) {
46110955Sdavid.hashe@amd.com            // readlink will truncate the contents of the
46210955Sdavid.hashe@amd.com            // path to ensure it is no more than bufsiz
46310955Sdavid.hashe@amd.com            result = bufsiz;
46410955Sdavid.hashe@amd.com        } else {
46511140Sjthestness@gmail.com            result = real_path_len;
46610955Sdavid.hashe@amd.com        }
46711140Sjthestness@gmail.com
46811140Sjthestness@gmail.com        // Issue a warning about potential unexpected results
46911140Sjthestness@gmail.com        warn_once("readlink() called on '/proc/self/exe' may yield unexpected "
47011140Sjthestness@gmail.com                  "results in various settings.\n      Returning '%s'\n",
47111140Sjthestness@gmail.com                  (char*)buf.bufferPtr());
47210955Sdavid.hashe@amd.com    }
4735513SMichael.Adler@intel.com
4748706Sandreas.hansson@arm.com    buf.copyOut(tc->getMemProxy());
4755513SMichael.Adler@intel.com
4765513SMichael.Adler@intel.com    return (result == -1) ? -errno : result;
4775513SMichael.Adler@intel.com}
4785513SMichael.Adler@intel.com
4795513SMichael.Adler@intel.comSyscallReturn
48011851Sbrandon.potter@amd.comunlinkFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
481511SN/A{
48210633Smichaelupton@gmail.com    return unlinkHelper(desc, num, p, tc, 0);
48310633Smichaelupton@gmail.com}
48410633Smichaelupton@gmail.com
48510633Smichaelupton@gmail.comSyscallReturn
48611851Sbrandon.potter@amd.comunlinkHelper(SyscallDesc *desc, int num, Process *p, ThreadContext *tc,
48711851Sbrandon.potter@amd.com             int index)
48810633Smichaelupton@gmail.com{
4891706SN/A    string path;
490360SN/A
4918852Sandreas.hansson@arm.com    if (!tc->getMemProxy().tryReadString(path, p->getSyscallArg(tc, index)))
49210223Ssteve.reinhardt@amd.com        return -EFAULT;
493511SN/A
49413883Sdavid.hashe@amd.com    path = p->checkPathRedirect(path);
4953669Sbinkertn@umich.edu
496511SN/A    int result = unlink(path.c_str());
4971458SN/A    return (result == -1) ? -errno : result;
498511SN/A}
499511SN/A
50012795Smattdsinclair@gmail.comSyscallReturn
50112795Smattdsinclair@gmail.comlinkFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
50212795Smattdsinclair@gmail.com{
50312795Smattdsinclair@gmail.com    string path;
50412795Smattdsinclair@gmail.com    string new_path;
50512795Smattdsinclair@gmail.com
50612795Smattdsinclair@gmail.com    int index = 0;
50712795Smattdsinclair@gmail.com    auto &virt_mem = tc->getMemProxy();
50812795Smattdsinclair@gmail.com    if (!virt_mem.tryReadString(path, p->getSyscallArg(tc, index)))
50912795Smattdsinclair@gmail.com        return -EFAULT;
51012795Smattdsinclair@gmail.com    if (!virt_mem.tryReadString(new_path, p->getSyscallArg(tc, index)))
51112795Smattdsinclair@gmail.com        return -EFAULT;
51212795Smattdsinclair@gmail.com
51313883Sdavid.hashe@amd.com    path = p->absolutePath(path, true);
51413883Sdavid.hashe@amd.com    new_path = p->absolutePath(new_path, true);
51512795Smattdsinclair@gmail.com
51612795Smattdsinclair@gmail.com    int result = link(path.c_str(), new_path.c_str());
51712795Smattdsinclair@gmail.com    return (result == -1) ? -errno : result;
51812795Smattdsinclair@gmail.com}
5195513SMichael.Adler@intel.com
5205513SMichael.Adler@intel.comSyscallReturn
52112796Smattdsinclair@gmail.comsymlinkFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
52212796Smattdsinclair@gmail.com{
52312796Smattdsinclair@gmail.com    string path;
52412796Smattdsinclair@gmail.com    string new_path;
52512796Smattdsinclair@gmail.com
52612796Smattdsinclair@gmail.com    int index = 0;
52712796Smattdsinclair@gmail.com    auto &virt_mem = tc->getMemProxy();
52812796Smattdsinclair@gmail.com    if (!virt_mem.tryReadString(path, p->getSyscallArg(tc, index)))
52912796Smattdsinclair@gmail.com        return -EFAULT;
53012796Smattdsinclair@gmail.com    if (!virt_mem.tryReadString(new_path, p->getSyscallArg(tc, index)))
53112796Smattdsinclair@gmail.com        return -EFAULT;
53212796Smattdsinclair@gmail.com
53313883Sdavid.hashe@amd.com    path = p->absolutePath(path, true);
53413883Sdavid.hashe@amd.com    new_path = p->absolutePath(new_path, true);
53512796Smattdsinclair@gmail.com
53612796Smattdsinclair@gmail.com    int result = symlink(path.c_str(), new_path.c_str());
53712796Smattdsinclair@gmail.com    return (result == -1) ? -errno : result;
53812796Smattdsinclair@gmail.com}
53912796Smattdsinclair@gmail.com
54012796Smattdsinclair@gmail.comSyscallReturn
54111851Sbrandon.potter@amd.commkdirFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
5425513SMichael.Adler@intel.com{
5436701Sgblack@eecs.umich.edu    int index = 0;
54413883Sdavid.hashe@amd.com    std::string path;
5458852Sandreas.hansson@arm.com    if (!tc->getMemProxy().tryReadString(path, p->getSyscallArg(tc, index)))
54610223Ssteve.reinhardt@amd.com        return -EFAULT;
5475513SMichael.Adler@intel.com
54813883Sdavid.hashe@amd.com    path = p->checkPathRedirect(path);
5496701Sgblack@eecs.umich.edu    mode_t mode = p->getSyscallArg(tc, index);
5505513SMichael.Adler@intel.com
55113883Sdavid.hashe@amd.com    auto result = mkdir(path.c_str(), mode);
5525513SMichael.Adler@intel.com    return (result == -1) ? -errno : result;
5535513SMichael.Adler@intel.com}
5545513SMichael.Adler@intel.com
5551450SN/ASyscallReturn
55611851Sbrandon.potter@amd.comrenameFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
557511SN/A{
5581706SN/A    string old_name;
559511SN/A
5606701Sgblack@eecs.umich.edu    int index = 0;
5618852Sandreas.hansson@arm.com    if (!tc->getMemProxy().tryReadString(old_name, p->getSyscallArg(tc, index)))
5621458SN/A        return -EFAULT;
563511SN/A
5641706SN/A    string new_name;
565511SN/A
5668852Sandreas.hansson@arm.com    if (!tc->getMemProxy().tryReadString(new_name, p->getSyscallArg(tc, index)))
5671458SN/A        return -EFAULT;
568511SN/A
56913883Sdavid.hashe@amd.com    // Adjust path for cwd and redirection
57013883Sdavid.hashe@amd.com    old_name = p->checkPathRedirect(old_name);
57113883Sdavid.hashe@amd.com    new_name = p->checkPathRedirect(new_name);
5723669Sbinkertn@umich.edu
5731706SN/A    int64_t result = rename(old_name.c_str(), new_name.c_str());
5741458SN/A    return (result == -1) ? -errno : result;
575511SN/A}
576511SN/A
5771706SN/ASyscallReturn
57811851Sbrandon.potter@amd.comtruncateFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
5791706SN/A{
5801706SN/A    string path;
5811706SN/A
5826701Sgblack@eecs.umich.edu    int index = 0;
5838852Sandreas.hansson@arm.com    if (!tc->getMemProxy().tryReadString(path, p->getSyscallArg(tc, index)))
5841706SN/A        return -EFAULT;
5851706SN/A
5866701Sgblack@eecs.umich.edu    off_t length = p->getSyscallArg(tc, index);
5871706SN/A
58813883Sdavid.hashe@amd.com    // Adjust path for cwd and redirection
58913883Sdavid.hashe@amd.com    path = p->checkPathRedirect(path);
5903669Sbinkertn@umich.edu
5911706SN/A    int result = truncate(path.c_str(), length);
5921706SN/A    return (result == -1) ? -errno : result;
5931706SN/A}
5941706SN/A
5951706SN/ASyscallReturn
59611856Sbrandon.potter@amd.comftruncateFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
5971706SN/A{
5986701Sgblack@eecs.umich.edu    int index = 0;
59911856Sbrandon.potter@amd.com    int tgt_fd = p->getSyscallArg(tc, index);
60011856Sbrandon.potter@amd.com    off_t length = p->getSyscallArg(tc, index);
6011706SN/A
60211856Sbrandon.potter@amd.com    auto ffdp = std::dynamic_pointer_cast<FileFDEntry>((*p->fds)[tgt_fd]);
60311856Sbrandon.potter@amd.com    if (!ffdp)
6041706SN/A        return -EBADF;
60511856Sbrandon.potter@amd.com    int sim_fd = ffdp->getSimFD();
6061706SN/A
60710931Sbrandon.potter@amd.com    int result = ftruncate(sim_fd, length);
6081706SN/A    return (result == -1) ? -errno : result;
6091706SN/A}
6101999SN/A
6111999SN/ASyscallReturn
6126703Svince@csl.cornell.edutruncate64Func(SyscallDesc *desc, int num,
61311851Sbrandon.potter@amd.com               Process *process, ThreadContext *tc)
6146703Svince@csl.cornell.edu{
6156703Svince@csl.cornell.edu    int index = 0;
6166703Svince@csl.cornell.edu    string path;
6176703Svince@csl.cornell.edu
6188852Sandreas.hansson@arm.com    if (!tc->getMemProxy().tryReadString(path, process->getSyscallArg(tc, index)))
61911906SBrandon.Potter@amd.com        return -EFAULT;
6206703Svince@csl.cornell.edu
6216744SAli.Saidi@arm.com    int64_t length = process->getSyscallArg(tc, index, 64);
6226703Svince@csl.cornell.edu
62313883Sdavid.hashe@amd.com    // Adjust path for cwd and redirection
62413883Sdavid.hashe@amd.com    path = process->checkPathRedirect(path);
6256703Svince@csl.cornell.edu
6266744SAli.Saidi@arm.com#if NO_STAT64
6276744SAli.Saidi@arm.com    int result = truncate(path.c_str(), length);
6286744SAli.Saidi@arm.com#else
6296703Svince@csl.cornell.edu    int result = truncate64(path.c_str(), length);
6306744SAli.Saidi@arm.com#endif
6316703Svince@csl.cornell.edu    return (result == -1) ? -errno : result;
6326703Svince@csl.cornell.edu}
6336703Svince@csl.cornell.edu
6346703Svince@csl.cornell.eduSyscallReturn
63511856Sbrandon.potter@amd.comftruncate64Func(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
6366685Stjones1@inf.ed.ac.uk{
6376701Sgblack@eecs.umich.edu    int index = 0;
63811856Sbrandon.potter@amd.com    int tgt_fd = p->getSyscallArg(tc, index);
63911856Sbrandon.potter@amd.com    int64_t length = p->getSyscallArg(tc, index, 64);
6406685Stjones1@inf.ed.ac.uk
64111856Sbrandon.potter@amd.com    auto ffdp = std::dynamic_pointer_cast<FileFDEntry>((*p->fds)[tgt_fd]);
64211856Sbrandon.potter@amd.com    if (!ffdp)
6436685Stjones1@inf.ed.ac.uk        return -EBADF;
64411856Sbrandon.potter@amd.com    int sim_fd = ffdp->getSimFD();
6456685Stjones1@inf.ed.ac.uk
6466744SAli.Saidi@arm.com#if NO_STAT64
64710931Sbrandon.potter@amd.com    int result = ftruncate(sim_fd, length);
6486744SAli.Saidi@arm.com#else
64910931Sbrandon.potter@amd.com    int result = ftruncate64(sim_fd, length);
6506744SAli.Saidi@arm.com#endif
6516685Stjones1@inf.ed.ac.uk    return (result == -1) ? -errno : result;
6526685Stjones1@inf.ed.ac.uk}
6536685Stjones1@inf.ed.ac.uk
6546685Stjones1@inf.ed.ac.ukSyscallReturn
65511851Sbrandon.potter@amd.comumaskFunc(SyscallDesc *desc, int num, Process *process, ThreadContext *tc)
6565513SMichael.Adler@intel.com{
6575513SMichael.Adler@intel.com    // Letting the simulated program change the simulator's umask seems like
6585513SMichael.Adler@intel.com    // a bad idea.  Compromise by just returning the current umask but not
6595513SMichael.Adler@intel.com    // changing anything.
6605513SMichael.Adler@intel.com    mode_t oldMask = umask(0);
6615513SMichael.Adler@intel.com    umask(oldMask);
6625521Snate@binkert.org    return (int)oldMask;
6635513SMichael.Adler@intel.com}
6645513SMichael.Adler@intel.com
6655513SMichael.Adler@intel.comSyscallReturn
66611851Sbrandon.potter@amd.comchownFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
6671999SN/A{
6681999SN/A    string path;
6691999SN/A
6706701Sgblack@eecs.umich.edu    int index = 0;
6718852Sandreas.hansson@arm.com    if (!tc->getMemProxy().tryReadString(path, p->getSyscallArg(tc, index)))
6721999SN/A        return -EFAULT;
6731999SN/A
6741999SN/A    /* XXX endianess */
6756701Sgblack@eecs.umich.edu    uint32_t owner = p->getSyscallArg(tc, index);
6761999SN/A    uid_t hostOwner = owner;
6776701Sgblack@eecs.umich.edu    uint32_t group = p->getSyscallArg(tc, index);
6781999SN/A    gid_t hostGroup = group;
6791999SN/A
68013883Sdavid.hashe@amd.com    // Adjust path for cwd and redirection
68113883Sdavid.hashe@amd.com    path = p->checkPathRedirect(path);
6823669Sbinkertn@umich.edu
6831999SN/A    int result = chown(path.c_str(), hostOwner, hostGroup);
6841999SN/A    return (result == -1) ? -errno : result;
6851999SN/A}
6861999SN/A
6871999SN/ASyscallReturn
68811856Sbrandon.potter@amd.comfchownFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
6891999SN/A{
6906701Sgblack@eecs.umich.edu    int index = 0;
69111856Sbrandon.potter@amd.com    int tgt_fd = p->getSyscallArg(tc, index);
6921999SN/A
69311856Sbrandon.potter@amd.com    auto ffdp = std::dynamic_pointer_cast<FileFDEntry>((*p->fds)[tgt_fd]);
69411856Sbrandon.potter@amd.com    if (!ffdp)
6951999SN/A        return -EBADF;
69611856Sbrandon.potter@amd.com    int sim_fd = ffdp->getSimFD();
6971999SN/A
6981999SN/A    /* XXX endianess */
69911856Sbrandon.potter@amd.com    uint32_t owner = p->getSyscallArg(tc, index);
7001999SN/A    uid_t hostOwner = owner;
70111856Sbrandon.potter@amd.com    uint32_t group = p->getSyscallArg(tc, index);
7021999SN/A    gid_t hostGroup = group;
7031999SN/A
70410931Sbrandon.potter@amd.com    int result = fchown(sim_fd, hostOwner, hostGroup);
7051999SN/A    return (result == -1) ? -errno : result;
7061999SN/A}
7072093SN/A
70811856Sbrandon.potter@amd.com/**
70911908SBrandon.Potter@amd.com * FIXME: The file description is not shared among file descriptors created
71011908SBrandon.Potter@amd.com * with dup. Really, it's difficult to maintain fields like file offset or
71111908SBrandon.Potter@amd.com * flags since an update to such a field won't be reflected in the metadata
71211908SBrandon.Potter@amd.com * for the fd entries that we maintain for checkpoint restoration.
71311856Sbrandon.potter@amd.com */
7142093SN/ASyscallReturn
71511856Sbrandon.potter@amd.comdupFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
7163079Sstever@eecs.umich.edu{
7176701Sgblack@eecs.umich.edu    int index = 0;
71811856Sbrandon.potter@amd.com    int tgt_fd = p->getSyscallArg(tc, index);
71910931Sbrandon.potter@amd.com
72011856Sbrandon.potter@amd.com    auto old_hbfdp = std::dynamic_pointer_cast<HBFDEntry>((*p->fds)[tgt_fd]);
72111856Sbrandon.potter@amd.com    if (!old_hbfdp)
7223079Sstever@eecs.umich.edu        return -EBADF;
72311856Sbrandon.potter@amd.com    int sim_fd = old_hbfdp->getSimFD();
7245282Srstrong@cs.ucsd.edu
72510781Snilay@cs.wisc.edu    int result = dup(sim_fd);
72611908SBrandon.Potter@amd.com    if (result == -1)
72711908SBrandon.Potter@amd.com        return -errno;
72811856Sbrandon.potter@amd.com
72911908SBrandon.Potter@amd.com    auto new_hbfdp = std::dynamic_pointer_cast<HBFDEntry>(old_hbfdp->clone());
73011856Sbrandon.potter@amd.com    new_hbfdp->setSimFD(result);
73111908SBrandon.Potter@amd.com    new_hbfdp->setCOE(false);
73211908SBrandon.Potter@amd.com    return p->fds->allocFD(new_hbfdp);
73311908SBrandon.Potter@amd.com}
73411856Sbrandon.potter@amd.com
73511908SBrandon.Potter@amd.comSyscallReturn
73611908SBrandon.Potter@amd.comdup2Func(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
73711908SBrandon.Potter@amd.com{
73811908SBrandon.Potter@amd.com    int index = 0;
73911908SBrandon.Potter@amd.com
74011908SBrandon.Potter@amd.com    int old_tgt_fd = p->getSyscallArg(tc, index);
74111908SBrandon.Potter@amd.com    auto old_hbp = std::dynamic_pointer_cast<HBFDEntry>((*p->fds)[old_tgt_fd]);
74211908SBrandon.Potter@amd.com    if (!old_hbp)
74311908SBrandon.Potter@amd.com        return -EBADF;
74411908SBrandon.Potter@amd.com    int old_sim_fd = old_hbp->getSimFD();
74511908SBrandon.Potter@amd.com
74611908SBrandon.Potter@amd.com    /**
74711908SBrandon.Potter@amd.com     * We need a valid host file descriptor number to be able to pass into
74811908SBrandon.Potter@amd.com     * the second parameter for dup2 (newfd), but we don't know what the
74911908SBrandon.Potter@amd.com     * viable numbers are; we execute the open call to retrieve one.
75011908SBrandon.Potter@amd.com     */
75111908SBrandon.Potter@amd.com    int res_fd = dup2(old_sim_fd, open("/dev/null", O_RDONLY));
75211908SBrandon.Potter@amd.com    if (res_fd == -1)
75311908SBrandon.Potter@amd.com        return -errno;
75411908SBrandon.Potter@amd.com
75511908SBrandon.Potter@amd.com    int new_tgt_fd = p->getSyscallArg(tc, index);
75611908SBrandon.Potter@amd.com    auto new_hbp = std::dynamic_pointer_cast<HBFDEntry>((*p->fds)[new_tgt_fd]);
75711908SBrandon.Potter@amd.com    if (new_hbp)
75811908SBrandon.Potter@amd.com        p->fds->closeFDEntry(new_tgt_fd);
75911908SBrandon.Potter@amd.com    new_hbp = std::dynamic_pointer_cast<HBFDEntry>(old_hbp->clone());
76011908SBrandon.Potter@amd.com    new_hbp->setSimFD(res_fd);
76111908SBrandon.Potter@amd.com    new_hbp->setCOE(false);
76211908SBrandon.Potter@amd.com
76311908SBrandon.Potter@amd.com    return p->fds->allocFD(new_hbp);
7643079Sstever@eecs.umich.edu}
7653079Sstever@eecs.umich.edu
7663079Sstever@eecs.umich.eduSyscallReturn
76711856Sbrandon.potter@amd.comfcntlFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
7682093SN/A{
76911875Sbrandon.potter@amd.com    int arg;
7706701Sgblack@eecs.umich.edu    int index = 0;
77111856Sbrandon.potter@amd.com    int tgt_fd = p->getSyscallArg(tc, index);
77211875Sbrandon.potter@amd.com    int cmd = p->getSyscallArg(tc, index);
7732093SN/A
77411856Sbrandon.potter@amd.com    auto hbfdp = std::dynamic_pointer_cast<HBFDEntry>((*p->fds)[tgt_fd]);
77511856Sbrandon.potter@amd.com    if (!hbfdp)
7762093SN/A        return -EBADF;
77711856Sbrandon.potter@amd.com    int sim_fd = hbfdp->getSimFD();
7782093SN/A
77911875Sbrandon.potter@amd.com    int coe = hbfdp->getCOE();
78011875Sbrandon.potter@amd.com
7812093SN/A    switch (cmd) {
78211875Sbrandon.potter@amd.com      case F_GETFD:
78311875Sbrandon.potter@amd.com        return coe & FD_CLOEXEC;
7842093SN/A
78511875Sbrandon.potter@amd.com      case F_SETFD: {
78611875Sbrandon.potter@amd.com        arg = p->getSyscallArg(tc, index);
78711875Sbrandon.potter@amd.com        arg ? hbfdp->setCOE(true) : hbfdp->setCOE(false);
7882093SN/A        return 0;
78911875Sbrandon.potter@amd.com      }
7902093SN/A
79111875Sbrandon.potter@amd.com      // Rely on the host to maintain the file status flags for this file
79211875Sbrandon.potter@amd.com      // description rather than maintain it ourselves. Admittedly, this
79311875Sbrandon.potter@amd.com      // is suboptimal (and possibly error prone), but it is difficult to
79411875Sbrandon.potter@amd.com      // maintain the flags by tracking them across the different descriptors
79511875Sbrandon.potter@amd.com      // (that refer to this file description) caused by clone, dup, and
79611875Sbrandon.potter@amd.com      // subsequent fcntls.
79711875Sbrandon.potter@amd.com      case F_GETFL:
79811875Sbrandon.potter@amd.com      case F_SETFL: {
79911875Sbrandon.potter@amd.com        arg = p->getSyscallArg(tc, index);
80011875Sbrandon.potter@amd.com        int rv = fcntl(sim_fd, cmd, arg);
80111875Sbrandon.potter@amd.com        return (rv == -1) ? -errno : rv;
80211875Sbrandon.potter@amd.com      }
8032093SN/A
8042093SN/A      default:
80511875Sbrandon.potter@amd.com        warn("fcntl: unsupported command %d\n", cmd);
8062093SN/A        return 0;
8072093SN/A    }
8082093SN/A}
8092093SN/A
8102238SN/ASyscallReturn
81111856Sbrandon.potter@amd.comfcntl64Func(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
8122687Sksewell@umich.edu{
8136701Sgblack@eecs.umich.edu    int index = 0;
81411856Sbrandon.potter@amd.com    int tgt_fd = p->getSyscallArg(tc, index);
8152687Sksewell@umich.edu
81611856Sbrandon.potter@amd.com    auto hbfdp = std::dynamic_pointer_cast<HBFDEntry>((*p->fds)[tgt_fd]);
81711856Sbrandon.potter@amd.com    if (!hbfdp)
8182687Sksewell@umich.edu        return -EBADF;
81911856Sbrandon.potter@amd.com    int sim_fd = hbfdp->getSimFD();
8202687Sksewell@umich.edu
82111856Sbrandon.potter@amd.com    int cmd = p->getSyscallArg(tc, index);
8222687Sksewell@umich.edu    switch (cmd) {
8232687Sksewell@umich.edu      case 33: //F_GETLK64
82410931Sbrandon.potter@amd.com        warn("fcntl64(%d, F_GETLK64) not supported, error returned\n", tgt_fd);
8252687Sksewell@umich.edu        return -EMFILE;
8262687Sksewell@umich.edu
8272687Sksewell@umich.edu      case 34: // F_SETLK64
8282687Sksewell@umich.edu      case 35: // F_SETLKW64
82910931Sbrandon.potter@amd.com        warn("fcntl64(%d, F_SETLK(W)64) not supported, error returned\n",
83010931Sbrandon.potter@amd.com             tgt_fd);
8312687Sksewell@umich.edu        return -EMFILE;
8322687Sksewell@umich.edu
8332687Sksewell@umich.edu      default:
8342687Sksewell@umich.edu        // not sure if this is totally valid, but we'll pass it through
8352687Sksewell@umich.edu        // to the underlying OS
83610931Sbrandon.potter@amd.com        warn("fcntl64(%d, %d) passed through to host\n", tgt_fd, cmd);
83710931Sbrandon.potter@amd.com        return fcntl(sim_fd, cmd);
8382687Sksewell@umich.edu    }
8392687Sksewell@umich.edu}
8402687Sksewell@umich.edu
8412687Sksewell@umich.eduSyscallReturn
84211908SBrandon.Potter@amd.compipeImpl(SyscallDesc *desc, int callnum, Process *p, ThreadContext *tc,
84311908SBrandon.Potter@amd.com         bool pseudoPipe)
8442238SN/A{
84511908SBrandon.Potter@amd.com    Addr tgt_addr = 0;
84611908SBrandon.Potter@amd.com    if (!pseudoPipe) {
84711908SBrandon.Potter@amd.com        int index = 0;
84811908SBrandon.Potter@amd.com        tgt_addr = p->getSyscallArg(tc, index);
84911908SBrandon.Potter@amd.com    }
85011908SBrandon.Potter@amd.com
85111856Sbrandon.potter@amd.com    int sim_fds[2], tgt_fds[2];
8522093SN/A
85311856Sbrandon.potter@amd.com    int pipe_retval = pipe(sim_fds);
85411908SBrandon.Potter@amd.com    if (pipe_retval == -1)
85511908SBrandon.Potter@amd.com        return -errno;
8562238SN/A
85711856Sbrandon.potter@amd.com    auto rend = PipeFDEntry::EndType::read;
85811856Sbrandon.potter@amd.com    auto rpfd = std::make_shared<PipeFDEntry>(sim_fds[0], O_WRONLY, rend);
85911908SBrandon.Potter@amd.com    tgt_fds[0] = p->fds->allocFD(rpfd);
8602238SN/A
86111856Sbrandon.potter@amd.com    auto wend = PipeFDEntry::EndType::write;
86211856Sbrandon.potter@amd.com    auto wpfd = std::make_shared<PipeFDEntry>(sim_fds[1], O_RDONLY, wend);
86311908SBrandon.Potter@amd.com    tgt_fds[1] = p->fds->allocFD(wpfd);
86411856Sbrandon.potter@amd.com
86511856Sbrandon.potter@amd.com    /**
86611856Sbrandon.potter@amd.com     * Now patch the read object to record the target file descriptor chosen
86711856Sbrandon.potter@amd.com     * as the write end of the pipe.
86811856Sbrandon.potter@amd.com     */
86911856Sbrandon.potter@amd.com    rpfd->setPipeReadSource(tgt_fds[1]);
87011856Sbrandon.potter@amd.com
87111856Sbrandon.potter@amd.com    /**
87211856Sbrandon.potter@amd.com     * Alpha Linux convention for pipe() is that fd[0] is returned as
87311856Sbrandon.potter@amd.com     * the return value of the function, and fd[1] is returned in r20.
87411856Sbrandon.potter@amd.com     */
87511908SBrandon.Potter@amd.com    if (pseudoPipe) {
87611908SBrandon.Potter@amd.com        tc->setIntReg(SyscallPseudoReturnReg, tgt_fds[1]);
87711908SBrandon.Potter@amd.com        return tgt_fds[0];
87811908SBrandon.Potter@amd.com    }
87911908SBrandon.Potter@amd.com
88011908SBrandon.Potter@amd.com    /**
88111908SBrandon.Potter@amd.com     * Copy the target file descriptors into buffer space and then copy
88211908SBrandon.Potter@amd.com     * the buffer space back into the target address space.
88311908SBrandon.Potter@amd.com     */
88411908SBrandon.Potter@amd.com    BufferArg tgt_handle(tgt_addr, sizeof(int[2]));
88511908SBrandon.Potter@amd.com    int *buf_ptr = (int*)tgt_handle.bufferPtr();
88611908SBrandon.Potter@amd.com    buf_ptr[0] = tgt_fds[0];
88711908SBrandon.Potter@amd.com    buf_ptr[1] = tgt_fds[1];
88811908SBrandon.Potter@amd.com    tgt_handle.copyOut(tc->getMemProxy());
88911908SBrandon.Potter@amd.com    return 0;
89011908SBrandon.Potter@amd.com}
89111908SBrandon.Potter@amd.com
89211908SBrandon.Potter@amd.comSyscallReturn
89311908SBrandon.Potter@amd.compipePseudoFunc(SyscallDesc *desc, int callnum, Process *process,
89411908SBrandon.Potter@amd.com               ThreadContext *tc)
89511908SBrandon.Potter@amd.com{
89611908SBrandon.Potter@amd.com    return pipeImpl(desc, callnum, process, tc, true);
89711908SBrandon.Potter@amd.com}
89811908SBrandon.Potter@amd.com
89911908SBrandon.Potter@amd.comSyscallReturn
90011908SBrandon.Potter@amd.compipeFunc(SyscallDesc *desc, int callnum, Process *process, ThreadContext *tc)
90111908SBrandon.Potter@amd.com{
90211908SBrandon.Potter@amd.com    return pipeImpl(desc, callnum, process, tc, false);
9032238SN/A}
9042238SN/A
90511885Sbrandon.potter@amd.comSyscallReturn
90611885Sbrandon.potter@amd.comsetpgidFunc(SyscallDesc *desc, int callnum, Process *process,
90711885Sbrandon.potter@amd.com            ThreadContext *tc)
90811885Sbrandon.potter@amd.com{
90911885Sbrandon.potter@amd.com    int index = 0;
91011885Sbrandon.potter@amd.com    int pid = process->getSyscallArg(tc, index);
91111885Sbrandon.potter@amd.com    int pgid = process->getSyscallArg(tc, index);
91211885Sbrandon.potter@amd.com
91311885Sbrandon.potter@amd.com    if (pgid < 0)
91411885Sbrandon.potter@amd.com        return -EINVAL;
91511885Sbrandon.potter@amd.com
91611885Sbrandon.potter@amd.com    if (pid == 0) {
91711885Sbrandon.potter@amd.com        process->setpgid(process->pid());
91811885Sbrandon.potter@amd.com        return 0;
91911885Sbrandon.potter@amd.com    }
92011885Sbrandon.potter@amd.com
92111913SBrandon.Potter@amd.com    Process *matched_ph = nullptr;
92211885Sbrandon.potter@amd.com    System *sysh = tc->getSystemPtr();
92311885Sbrandon.potter@amd.com
92411885Sbrandon.potter@amd.com    // Retrieves process pointer from active/suspended thread contexts.
92511885Sbrandon.potter@amd.com    for (int i = 0; i < sysh->numContexts(); i++) {
92611885Sbrandon.potter@amd.com        if (sysh->threadContexts[i]->status() != ThreadContext::Halted) {
92711885Sbrandon.potter@amd.com            Process *temp_h = sysh->threadContexts[i]->getProcessPtr();
92811885Sbrandon.potter@amd.com            Process *walk_ph = (Process*)temp_h;
92911885Sbrandon.potter@amd.com
93011885Sbrandon.potter@amd.com            if (walk_ph && walk_ph->pid() == process->pid())
93111885Sbrandon.potter@amd.com                matched_ph = walk_ph;
93211885Sbrandon.potter@amd.com        }
93311885Sbrandon.potter@amd.com    }
93411885Sbrandon.potter@amd.com
93511913SBrandon.Potter@amd.com    assert(matched_ph);
93611885Sbrandon.potter@amd.com    matched_ph->setpgid((pgid == 0) ? matched_ph->pid() : pgid);
93711885Sbrandon.potter@amd.com
93811885Sbrandon.potter@amd.com    return 0;
93911885Sbrandon.potter@amd.com}
9402238SN/A
9412238SN/ASyscallReturn
94211851Sbrandon.potter@amd.comgetpidPseudoFunc(SyscallDesc *desc, int callnum, Process *process,
94311851Sbrandon.potter@amd.com                 ThreadContext *tc)
9442238SN/A{
9452238SN/A    // Make up a PID.  There's no interprocess communication in
9462238SN/A    // fake_syscall mode, so there's no way for a process to know it's
9472238SN/A    // not getting a unique value.
9482238SN/A
9493114Sgblack@eecs.umich.edu    tc->setIntReg(SyscallPseudoReturnReg, process->ppid());
9503114Sgblack@eecs.umich.edu    return process->pid();
9512238SN/A}
9522238SN/A
9532238SN/A
9542238SN/ASyscallReturn
95511851Sbrandon.potter@amd.comgetuidPseudoFunc(SyscallDesc *desc, int callnum, Process *process,
95611851Sbrandon.potter@amd.com                 ThreadContext *tc)
9572238SN/A{
9582238SN/A    // Make up a UID and EUID... it shouldn't matter, and we want the
9592238SN/A    // simulation to be deterministic.
9602238SN/A
9612238SN/A    // EUID goes in r20.
96211906SBrandon.Potter@amd.com    tc->setIntReg(SyscallPseudoReturnReg, process->euid()); // EUID
96311906SBrandon.Potter@amd.com    return process->uid(); // UID
9642238SN/A}
9652238SN/A
9662238SN/A
9672238SN/ASyscallReturn
96811851Sbrandon.potter@amd.comgetgidPseudoFunc(SyscallDesc *desc, int callnum, Process *process,
96911851Sbrandon.potter@amd.com                 ThreadContext *tc)
9702238SN/A{
9712238SN/A    // Get current group ID.  EGID goes in r20.
97211906SBrandon.Potter@amd.com    tc->setIntReg(SyscallPseudoReturnReg, process->egid()); // EGID
9733114Sgblack@eecs.umich.edu    return process->gid();
9742238SN/A}
9752238SN/A
9762238SN/A
9772238SN/ASyscallReturn
97811851Sbrandon.potter@amd.comsetuidFunc(SyscallDesc *desc, int callnum, Process *process,
9792680Sktlim@umich.edu           ThreadContext *tc)
9802238SN/A{
9812238SN/A    // can't fathom why a benchmark would call this.
9826701Sgblack@eecs.umich.edu    int index = 0;
9836701Sgblack@eecs.umich.edu    warn("Ignoring call to setuid(%d)\n", process->getSyscallArg(tc, index));
9842238SN/A    return 0;
9852238SN/A}
9862238SN/A
9872238SN/ASyscallReturn
98811851Sbrandon.potter@amd.comgetpidFunc(SyscallDesc *desc, int callnum, Process *process,
9892680Sktlim@umich.edu           ThreadContext *tc)
9902238SN/A{
99111885Sbrandon.potter@amd.com    return process->tgid();
99211885Sbrandon.potter@amd.com}
9932238SN/A
99411885Sbrandon.potter@amd.comSyscallReturn
99511885Sbrandon.potter@amd.comgettidFunc(SyscallDesc *desc, int callnum, Process *process,
99611885Sbrandon.potter@amd.com           ThreadContext *tc)
99711885Sbrandon.potter@amd.com{
9983114Sgblack@eecs.umich.edu    return process->pid();
9992238SN/A}
10002238SN/A
10012238SN/ASyscallReturn
100211851Sbrandon.potter@amd.comgetppidFunc(SyscallDesc *desc, int callnum, Process *process,
100311851Sbrandon.potter@amd.com            ThreadContext *tc)
10042238SN/A{
10053114Sgblack@eecs.umich.edu    return process->ppid();
10062238SN/A}
10072238SN/A
10082238SN/ASyscallReturn
100911851Sbrandon.potter@amd.comgetuidFunc(SyscallDesc *desc, int callnum, Process *process,
10102680Sktlim@umich.edu           ThreadContext *tc)
10112238SN/A{
10125543Ssaidi@eecs.umich.edu    return process->uid();              // UID
10132238SN/A}
10142238SN/A
10152238SN/ASyscallReturn
101611851Sbrandon.potter@amd.comgeteuidFunc(SyscallDesc *desc, int callnum, Process *process,
101711851Sbrandon.potter@amd.com            ThreadContext *tc)
10182238SN/A{
10195543Ssaidi@eecs.umich.edu    return process->euid();             // UID
10202238SN/A}
10212238SN/A
10222238SN/ASyscallReturn
102311851Sbrandon.potter@amd.comgetgidFunc(SyscallDesc *desc, int callnum, Process *process,
10242680Sktlim@umich.edu           ThreadContext *tc)
10252238SN/A{
10263114Sgblack@eecs.umich.edu    return process->gid();
10272238SN/A}
10282238SN/A
10292238SN/ASyscallReturn
103011851Sbrandon.potter@amd.comgetegidFunc(SyscallDesc *desc, int callnum, Process *process,
103111851Sbrandon.potter@amd.com            ThreadContext *tc)
10322238SN/A{
10333114Sgblack@eecs.umich.edu    return process->egid();
10342238SN/A}
10352238SN/A
10369455Smitch.hayenga+gem5@gmail.comSyscallReturn
103711856Sbrandon.potter@amd.comfallocateFunc(SyscallDesc *desc, int callnum, Process *p, ThreadContext *tc)
103811760Sbrandon.potter@amd.com{
103911799Sbrandon.potter@amd.com#if NO_FALLOCATE
104011799Sbrandon.potter@amd.com    warn("Host OS cannot support calls to fallocate. Ignoring syscall");
104111799Sbrandon.potter@amd.com#else
104211760Sbrandon.potter@amd.com    int index = 0;
104311856Sbrandon.potter@amd.com    int tgt_fd = p->getSyscallArg(tc, index);
104411856Sbrandon.potter@amd.com    int mode = p->getSyscallArg(tc, index);
104511856Sbrandon.potter@amd.com    off_t offset = p->getSyscallArg(tc, index);
104611856Sbrandon.potter@amd.com    off_t len = p->getSyscallArg(tc, index);
104711760Sbrandon.potter@amd.com
104811856Sbrandon.potter@amd.com    auto ffdp = std::dynamic_pointer_cast<FileFDEntry>((*p->fds)[tgt_fd]);
104911856Sbrandon.potter@amd.com    if (!ffdp)
105011760Sbrandon.potter@amd.com        return -EBADF;
105111856Sbrandon.potter@amd.com    int sim_fd = ffdp->getSimFD();
105211760Sbrandon.potter@amd.com
105311760Sbrandon.potter@amd.com    int result = fallocate(sim_fd, mode, offset, len);
105411760Sbrandon.potter@amd.com    if (result < 0)
105511760Sbrandon.potter@amd.com        return -errno;
105611799Sbrandon.potter@amd.com#endif
105711760Sbrandon.potter@amd.com    return 0;
105811760Sbrandon.potter@amd.com}
105911760Sbrandon.potter@amd.com
106011760Sbrandon.potter@amd.comSyscallReturn
106111851Sbrandon.potter@amd.comaccessFunc(SyscallDesc *desc, int callnum, Process *p, ThreadContext *tc,
106211851Sbrandon.potter@amd.com           int index)
10639455Smitch.hayenga+gem5@gmail.com{
10649455Smitch.hayenga+gem5@gmail.com    string path;
10659455Smitch.hayenga+gem5@gmail.com    if (!tc->getMemProxy().tryReadString(path, p->getSyscallArg(tc, index)))
106610223Ssteve.reinhardt@amd.com        return -EFAULT;
10679455Smitch.hayenga+gem5@gmail.com
106813883Sdavid.hashe@amd.com    // Adjust path for cwd and redirection
106913883Sdavid.hashe@amd.com    path = p->checkPathRedirect(path);
10709455Smitch.hayenga+gem5@gmail.com
10719455Smitch.hayenga+gem5@gmail.com    mode_t mode = p->getSyscallArg(tc, index);
10729455Smitch.hayenga+gem5@gmail.com
10739455Smitch.hayenga+gem5@gmail.com    int result = access(path.c_str(), mode);
10749455Smitch.hayenga+gem5@gmail.com    return (result == -1) ? -errno : result;
10759455Smitch.hayenga+gem5@gmail.com}
107610203SAli.Saidi@ARM.com
107710203SAli.Saidi@ARM.comSyscallReturn
107811851Sbrandon.potter@amd.comaccessFunc(SyscallDesc *desc, int callnum, Process *p, ThreadContext *tc)
107910203SAli.Saidi@ARM.com{
108010203SAli.Saidi@ARM.com    return accessFunc(desc, callnum, p, tc, 0);
108110203SAli.Saidi@ARM.com}
108210203SAli.Saidi@ARM.com
108313031Sbrandon.potter@amd.comSyscallReturn
108413031Sbrandon.potter@amd.commknodFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
108513031Sbrandon.potter@amd.com{
108613031Sbrandon.potter@amd.com    int index = 0;
108713031Sbrandon.potter@amd.com    std::string path;
108813031Sbrandon.potter@amd.com    if (!tc->getMemProxy().tryReadString(path, p->getSyscallArg(tc, index)))
108913031Sbrandon.potter@amd.com        return -EFAULT;
109013031Sbrandon.potter@amd.com
109113883Sdavid.hashe@amd.com    path = p->checkPathRedirect(path);
109213031Sbrandon.potter@amd.com    mode_t mode = p->getSyscallArg(tc, index);
109313031Sbrandon.potter@amd.com    dev_t dev = p->getSyscallArg(tc, index);
109413031Sbrandon.potter@amd.com
109513031Sbrandon.potter@amd.com    auto result = mknod(path.c_str(), mode, dev);
109613031Sbrandon.potter@amd.com    return (result == -1) ? -errno : result;
109713031Sbrandon.potter@amd.com}
109813031Sbrandon.potter@amd.com
109913031Sbrandon.potter@amd.comSyscallReturn
110013031Sbrandon.potter@amd.comchdirFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
110113031Sbrandon.potter@amd.com{
110213031Sbrandon.potter@amd.com    int index = 0;
110313031Sbrandon.potter@amd.com    std::string path;
110413031Sbrandon.potter@amd.com    if (!tc->getMemProxy().tryReadString(path, p->getSyscallArg(tc, index)))
110513031Sbrandon.potter@amd.com        return -EFAULT;
110613031Sbrandon.potter@amd.com
110713883Sdavid.hashe@amd.com    std::string tgt_cwd;
110813883Sdavid.hashe@amd.com    if (startswith(path, "/")) {
110913883Sdavid.hashe@amd.com        tgt_cwd = path;
111013883Sdavid.hashe@amd.com    } else {
111113883Sdavid.hashe@amd.com        char buf[PATH_MAX];
111213883Sdavid.hashe@amd.com        tgt_cwd = realpath((p->tgtCwd + "/" + path).c_str(), buf);
111313883Sdavid.hashe@amd.com    }
111413883Sdavid.hashe@amd.com    std::string host_cwd = p->checkPathRedirect(tgt_cwd);
111513031Sbrandon.potter@amd.com
111613883Sdavid.hashe@amd.com    int result = chdir(host_cwd.c_str());
111713883Sdavid.hashe@amd.com
111813883Sdavid.hashe@amd.com    if (result == -1)
111913883Sdavid.hashe@amd.com        return -errno;
112013883Sdavid.hashe@amd.com
112113883Sdavid.hashe@amd.com    p->hostCwd = host_cwd;
112213883Sdavid.hashe@amd.com    p->tgtCwd = tgt_cwd;
112313883Sdavid.hashe@amd.com    return result;
112413031Sbrandon.potter@amd.com}
112513031Sbrandon.potter@amd.com
112613031Sbrandon.potter@amd.comSyscallReturn
112713031Sbrandon.potter@amd.comrmdirFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
112813031Sbrandon.potter@amd.com{
112913031Sbrandon.potter@amd.com    int index = 0;
113013031Sbrandon.potter@amd.com    std::string path;
113113031Sbrandon.potter@amd.com    if (!tc->getMemProxy().tryReadString(path, p->getSyscallArg(tc, index)))
113213031Sbrandon.potter@amd.com        return -EFAULT;
113313031Sbrandon.potter@amd.com
113413883Sdavid.hashe@amd.com    path = p->checkPathRedirect(path);
113513031Sbrandon.potter@amd.com
113613031Sbrandon.potter@amd.com    auto result = rmdir(path.c_str());
113713031Sbrandon.potter@amd.com    return (result == -1) ? -errno : result;
113813031Sbrandon.potter@amd.com}
113913031Sbrandon.potter@amd.com
114013539Sjavier.setoain@arm.com#if defined(SYS_getdents) || defined(SYS_getdents64)
114113539Sjavier.setoain@arm.comtemplate<typename DE, int SYS_NUM>
114213539Sjavier.setoain@arm.comstatic SyscallReturn
114313539Sjavier.setoain@arm.comgetdentsImpl(SyscallDesc *desc, int callnum, Process *p, ThreadContext *tc)
114413031Sbrandon.potter@amd.com{
114513031Sbrandon.potter@amd.com    int index = 0;
114613031Sbrandon.potter@amd.com    int tgt_fd = p->getSyscallArg(tc, index);
114713031Sbrandon.potter@amd.com    Addr buf_ptr = p->getSyscallArg(tc, index);
114813031Sbrandon.potter@amd.com    unsigned count = p->getSyscallArg(tc, index);
114913031Sbrandon.potter@amd.com
115013031Sbrandon.potter@amd.com    auto hbfdp = std::dynamic_pointer_cast<HBFDEntry>((*p->fds)[tgt_fd]);
115113031Sbrandon.potter@amd.com    if (!hbfdp)
115213031Sbrandon.potter@amd.com        return -EBADF;
115313031Sbrandon.potter@amd.com    int sim_fd = hbfdp->getSimFD();
115413031Sbrandon.potter@amd.com
115513031Sbrandon.potter@amd.com    BufferArg buf_arg(buf_ptr, count);
115613539Sjavier.setoain@arm.com    auto status = syscall(SYS_NUM, sim_fd, buf_arg.bufferPtr(), count);
115713031Sbrandon.potter@amd.com
115813031Sbrandon.potter@amd.com    if (status == -1)
115913031Sbrandon.potter@amd.com        return -errno;
116013031Sbrandon.potter@amd.com
116113031Sbrandon.potter@amd.com    unsigned traversed = 0;
116213031Sbrandon.potter@amd.com    while (traversed < status) {
116313539Sjavier.setoain@arm.com        DE *buffer = (DE*)((Addr)buf_arg.bufferPtr() + traversed);
116413031Sbrandon.potter@amd.com
116513031Sbrandon.potter@amd.com        auto host_reclen = buffer->d_reclen;
116613031Sbrandon.potter@amd.com
116713031Sbrandon.potter@amd.com        /**
116813031Sbrandon.potter@amd.com         * Convert the byte ordering from the host to the target before
116913031Sbrandon.potter@amd.com         * passing the data back into the target's address space to preserve
117013031Sbrandon.potter@amd.com         * endianness.
117113031Sbrandon.potter@amd.com         */
117213031Sbrandon.potter@amd.com        buffer->d_ino = htog(buffer->d_ino);
117313031Sbrandon.potter@amd.com        buffer->d_off = htog(buffer->d_off);
117413031Sbrandon.potter@amd.com        buffer->d_reclen = htog(buffer->d_reclen);
117513031Sbrandon.potter@amd.com
117613031Sbrandon.potter@amd.com        traversed += host_reclen;
117713031Sbrandon.potter@amd.com    }
117813031Sbrandon.potter@amd.com
117913031Sbrandon.potter@amd.com    buf_arg.copyOut(tc->getMemProxy());
118013031Sbrandon.potter@amd.com    return status;
118113031Sbrandon.potter@amd.com}
118213448Sciro.santilli@arm.com#endif
118313539Sjavier.setoain@arm.com
118413539Sjavier.setoain@arm.com#if defined(SYS_getdents)
118513539Sjavier.setoain@arm.comSyscallReturn
118613539Sjavier.setoain@arm.comgetdentsFunc(SyscallDesc *desc, int callnum, Process *p, ThreadContext *tc)
118713539Sjavier.setoain@arm.com{
118813539Sjavier.setoain@arm.com    typedef struct linux_dirent {
118913539Sjavier.setoain@arm.com        unsigned long d_ino;
119013539Sjavier.setoain@arm.com        unsigned long d_off;
119113539Sjavier.setoain@arm.com        unsigned short d_reclen;
119213539Sjavier.setoain@arm.com        char dname[];
119313539Sjavier.setoain@arm.com    } LinDent;
119413539Sjavier.setoain@arm.com
119513539Sjavier.setoain@arm.com    return getdentsImpl<LinDent, SYS_getdents>(desc, callnum, p, tc);
119613539Sjavier.setoain@arm.com}
119713539Sjavier.setoain@arm.com#endif
119813539Sjavier.setoain@arm.com
119913539Sjavier.setoain@arm.com#if defined(SYS_getdents64)
120013539Sjavier.setoain@arm.comSyscallReturn
120113539Sjavier.setoain@arm.comgetdents64Func(SyscallDesc *desc, int callnum, Process *p, ThreadContext *tc)
120213539Sjavier.setoain@arm.com{
120313539Sjavier.setoain@arm.com    typedef struct linux_dirent64 {
120413539Sjavier.setoain@arm.com        ino64_t d_ino;
120513539Sjavier.setoain@arm.com        off64_t d_off;
120613539Sjavier.setoain@arm.com        unsigned short d_reclen;
120713539Sjavier.setoain@arm.com        char dname[];
120813539Sjavier.setoain@arm.com    } LinDent64;
120913539Sjavier.setoain@arm.com
121013539Sjavier.setoain@arm.com    return getdentsImpl<LinDent64, SYS_getdents64>(desc, callnum, p, tc);
121113539Sjavier.setoain@arm.com}
121213539Sjavier.setoain@arm.com#endif
121313568Sbrandon.potter@amd.com
121413568Sbrandon.potter@amd.comSyscallReturn
121513568Sbrandon.potter@amd.comshutdownFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
121613568Sbrandon.potter@amd.com{
121713568Sbrandon.potter@amd.com    int index = 0;
121813568Sbrandon.potter@amd.com    int tgt_fd = p->getSyscallArg(tc, index);
121913568Sbrandon.potter@amd.com    int how = p->getSyscallArg(tc, index);
122013568Sbrandon.potter@amd.com
122113568Sbrandon.potter@amd.com    auto sfdp = std::dynamic_pointer_cast<SocketFDEntry>((*p->fds)[tgt_fd]);
122213568Sbrandon.potter@amd.com    if (!sfdp)
122313568Sbrandon.potter@amd.com        return -EBADF;
122413568Sbrandon.potter@amd.com    int sim_fd = sfdp->getSimFD();
122513568Sbrandon.potter@amd.com
122613568Sbrandon.potter@amd.com    int retval = shutdown(sim_fd, how);
122713568Sbrandon.potter@amd.com
122813568Sbrandon.potter@amd.com    return (retval == -1) ? -errno : retval;
122913568Sbrandon.potter@amd.com}
123013568Sbrandon.potter@amd.com
123113568Sbrandon.potter@amd.comSyscallReturn
123213568Sbrandon.potter@amd.combindFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
123313568Sbrandon.potter@amd.com{
123413568Sbrandon.potter@amd.com    int index = 0;
123513568Sbrandon.potter@amd.com    int tgt_fd = p->getSyscallArg(tc, index);
123613568Sbrandon.potter@amd.com    Addr buf_ptr = p->getSyscallArg(tc, index);
123713568Sbrandon.potter@amd.com    int addrlen = p->getSyscallArg(tc, index);
123813568Sbrandon.potter@amd.com
123913568Sbrandon.potter@amd.com    BufferArg bufSock(buf_ptr, addrlen);
124013568Sbrandon.potter@amd.com    bufSock.copyIn(tc->getMemProxy());
124113568Sbrandon.potter@amd.com
124213568Sbrandon.potter@amd.com    auto sfdp = std::dynamic_pointer_cast<SocketFDEntry>((*p->fds)[tgt_fd]);
124313568Sbrandon.potter@amd.com    if (!sfdp)
124413568Sbrandon.potter@amd.com        return -EBADF;
124513568Sbrandon.potter@amd.com    int sim_fd = sfdp->getSimFD();
124613568Sbrandon.potter@amd.com
124713568Sbrandon.potter@amd.com    int status = ::bind(sim_fd,
124813568Sbrandon.potter@amd.com                        (struct sockaddr *)bufSock.bufferPtr(),
124913568Sbrandon.potter@amd.com                        addrlen);
125013568Sbrandon.potter@amd.com
125113568Sbrandon.potter@amd.com    return (status == -1) ? -errno : status;
125213568Sbrandon.potter@amd.com}
125313568Sbrandon.potter@amd.com
125413568Sbrandon.potter@amd.comSyscallReturn
125513568Sbrandon.potter@amd.comlistenFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
125613568Sbrandon.potter@amd.com{
125713568Sbrandon.potter@amd.com    int index = 0;
125813568Sbrandon.potter@amd.com    int tgt_fd = p->getSyscallArg(tc, index);
125913568Sbrandon.potter@amd.com    int backlog = p->getSyscallArg(tc, index);
126013568Sbrandon.potter@amd.com
126113568Sbrandon.potter@amd.com    auto sfdp = std::dynamic_pointer_cast<SocketFDEntry>((*p->fds)[tgt_fd]);
126213568Sbrandon.potter@amd.com    if (!sfdp)
126313568Sbrandon.potter@amd.com        return -EBADF;
126413568Sbrandon.potter@amd.com    int sim_fd = sfdp->getSimFD();
126513568Sbrandon.potter@amd.com
126613568Sbrandon.potter@amd.com    int status = listen(sim_fd, backlog);
126713568Sbrandon.potter@amd.com
126813568Sbrandon.potter@amd.com    return (status == -1) ? -errno : status;
126913568Sbrandon.potter@amd.com}
127013568Sbrandon.potter@amd.com
127113568Sbrandon.potter@amd.comSyscallReturn
127213568Sbrandon.potter@amd.comconnectFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
127313568Sbrandon.potter@amd.com{
127413568Sbrandon.potter@amd.com    int index = 0;
127513568Sbrandon.potter@amd.com    int tgt_fd = p->getSyscallArg(tc, index);
127613568Sbrandon.potter@amd.com    Addr buf_ptr = p->getSyscallArg(tc, index);
127713568Sbrandon.potter@amd.com    int addrlen = p->getSyscallArg(tc, index);
127813568Sbrandon.potter@amd.com
127913568Sbrandon.potter@amd.com    BufferArg addr(buf_ptr, addrlen);
128013568Sbrandon.potter@amd.com    addr.copyIn(tc->getMemProxy());
128113568Sbrandon.potter@amd.com
128213568Sbrandon.potter@amd.com    auto sfdp = std::dynamic_pointer_cast<SocketFDEntry>((*p->fds)[tgt_fd]);
128313568Sbrandon.potter@amd.com    if (!sfdp)
128413568Sbrandon.potter@amd.com        return -EBADF;
128513568Sbrandon.potter@amd.com    int sim_fd = sfdp->getSimFD();
128613568Sbrandon.potter@amd.com
128713568Sbrandon.potter@amd.com    int status = connect(sim_fd,
128813568Sbrandon.potter@amd.com                         (struct sockaddr *)addr.bufferPtr(),
128913568Sbrandon.potter@amd.com                         (socklen_t)addrlen);
129013568Sbrandon.potter@amd.com
129113568Sbrandon.potter@amd.com    return (status == -1) ? -errno : status;
129213568Sbrandon.potter@amd.com}
129313569Sbrandon.potter@amd.com
129413569Sbrandon.potter@amd.comSyscallReturn
129513569Sbrandon.potter@amd.comrecvfromFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
129613569Sbrandon.potter@amd.com{
129713569Sbrandon.potter@amd.com    int index = 0;
129813569Sbrandon.potter@amd.com    int tgt_fd = p->getSyscallArg(tc, index);
129913569Sbrandon.potter@amd.com    Addr bufrPtr = p->getSyscallArg(tc, index);
130013569Sbrandon.potter@amd.com    size_t bufrLen = p->getSyscallArg(tc, index);
130113569Sbrandon.potter@amd.com    int flags = p->getSyscallArg(tc, index);
130213569Sbrandon.potter@amd.com    Addr addrPtr = p->getSyscallArg(tc, index);
130313569Sbrandon.potter@amd.com    Addr addrlenPtr = p->getSyscallArg(tc, index);
130413569Sbrandon.potter@amd.com
130513569Sbrandon.potter@amd.com    auto sfdp = std::dynamic_pointer_cast<SocketFDEntry>((*p->fds)[tgt_fd]);
130613569Sbrandon.potter@amd.com    if (!sfdp)
130713569Sbrandon.potter@amd.com        return -EBADF;
130813569Sbrandon.potter@amd.com    int sim_fd = sfdp->getSimFD();
130913569Sbrandon.potter@amd.com
131013569Sbrandon.potter@amd.com    // Reserve buffer space.
131113569Sbrandon.potter@amd.com    BufferArg bufrBuf(bufrPtr, bufrLen);
131213569Sbrandon.potter@amd.com
131313569Sbrandon.potter@amd.com    // Get address length.
131413569Sbrandon.potter@amd.com    socklen_t addrLen = 0;
131513569Sbrandon.potter@amd.com    if (addrlenPtr != 0) {
131613569Sbrandon.potter@amd.com        // Read address length parameter.
131713569Sbrandon.potter@amd.com        BufferArg addrlenBuf(addrlenPtr, sizeof(socklen_t));
131813569Sbrandon.potter@amd.com        addrlenBuf.copyIn(tc->getMemProxy());
131913569Sbrandon.potter@amd.com        addrLen = *((socklen_t *)addrlenBuf.bufferPtr());
132013569Sbrandon.potter@amd.com    }
132113569Sbrandon.potter@amd.com
132213569Sbrandon.potter@amd.com    struct sockaddr sa, *sap = NULL;
132313569Sbrandon.potter@amd.com    if (addrLen != 0) {
132413569Sbrandon.potter@amd.com        BufferArg addrBuf(addrPtr, addrLen);
132513569Sbrandon.potter@amd.com        addrBuf.copyIn(tc->getMemProxy());
132613569Sbrandon.potter@amd.com        memcpy(&sa, (struct sockaddr *)addrBuf.bufferPtr(),
132713569Sbrandon.potter@amd.com               sizeof(struct sockaddr));
132813569Sbrandon.potter@amd.com        sap = &sa;
132913569Sbrandon.potter@amd.com    }
133013569Sbrandon.potter@amd.com
133113569Sbrandon.potter@amd.com    ssize_t recvd_size = recvfrom(sim_fd,
133213569Sbrandon.potter@amd.com                                  (void *)bufrBuf.bufferPtr(),
133313569Sbrandon.potter@amd.com                                  bufrLen, flags, sap, (socklen_t *)&addrLen);
133413569Sbrandon.potter@amd.com
133513569Sbrandon.potter@amd.com    if (recvd_size == -1)
133613569Sbrandon.potter@amd.com        return -errno;
133713569Sbrandon.potter@amd.com
133813569Sbrandon.potter@amd.com    // Pass the received data out.
133913569Sbrandon.potter@amd.com    bufrBuf.copyOut(tc->getMemProxy());
134013569Sbrandon.potter@amd.com
134113569Sbrandon.potter@amd.com    // Copy address to addrPtr and pass it on.
134213569Sbrandon.potter@amd.com    if (sap != NULL) {
134313569Sbrandon.potter@amd.com        BufferArg addrBuf(addrPtr, addrLen);
134413569Sbrandon.potter@amd.com        memcpy(addrBuf.bufferPtr(), sap, sizeof(sa));
134513569Sbrandon.potter@amd.com        addrBuf.copyOut(tc->getMemProxy());
134613569Sbrandon.potter@amd.com    }
134713569Sbrandon.potter@amd.com
134813569Sbrandon.potter@amd.com    // Copy len to addrlenPtr and pass it on.
134913569Sbrandon.potter@amd.com    if (addrLen != 0) {
135013569Sbrandon.potter@amd.com        BufferArg addrlenBuf(addrlenPtr, sizeof(socklen_t));
135113569Sbrandon.potter@amd.com        *(socklen_t *)addrlenBuf.bufferPtr() = addrLen;
135213569Sbrandon.potter@amd.com        addrlenBuf.copyOut(tc->getMemProxy());
135313569Sbrandon.potter@amd.com    }
135413569Sbrandon.potter@amd.com
135513569Sbrandon.potter@amd.com    return recvd_size;
135613569Sbrandon.potter@amd.com}
135713569Sbrandon.potter@amd.com
135813569Sbrandon.potter@amd.comSyscallReturn
135913569Sbrandon.potter@amd.comsendtoFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
136013569Sbrandon.potter@amd.com{
136113569Sbrandon.potter@amd.com    int index = 0;
136213569Sbrandon.potter@amd.com    int tgt_fd = p->getSyscallArg(tc, index);
136313569Sbrandon.potter@amd.com    Addr bufrPtr = p->getSyscallArg(tc, index);
136413569Sbrandon.potter@amd.com    size_t bufrLen = p->getSyscallArg(tc, index);
136513569Sbrandon.potter@amd.com    int flags = p->getSyscallArg(tc, index);
136613569Sbrandon.potter@amd.com    Addr addrPtr = p->getSyscallArg(tc, index);
136713569Sbrandon.potter@amd.com    socklen_t addrLen = p->getSyscallArg(tc, index);
136813569Sbrandon.potter@amd.com
136913569Sbrandon.potter@amd.com    auto sfdp = std::dynamic_pointer_cast<SocketFDEntry>((*p->fds)[tgt_fd]);
137013569Sbrandon.potter@amd.com    if (!sfdp)
137113569Sbrandon.potter@amd.com        return -EBADF;
137213569Sbrandon.potter@amd.com    int sim_fd = sfdp->getSimFD();
137313569Sbrandon.potter@amd.com
137413569Sbrandon.potter@amd.com    // Reserve buffer space.
137513569Sbrandon.potter@amd.com    BufferArg bufrBuf(bufrPtr, bufrLen);
137613569Sbrandon.potter@amd.com    bufrBuf.copyIn(tc->getMemProxy());
137713569Sbrandon.potter@amd.com
137813569Sbrandon.potter@amd.com    struct sockaddr sa, *sap = nullptr;
137913569Sbrandon.potter@amd.com    memset(&sa, 0, sizeof(sockaddr));
138013569Sbrandon.potter@amd.com    if (addrLen != 0) {
138113569Sbrandon.potter@amd.com        BufferArg addrBuf(addrPtr, addrLen);
138213569Sbrandon.potter@amd.com        addrBuf.copyIn(tc->getMemProxy());
138313569Sbrandon.potter@amd.com        memcpy(&sa, (sockaddr*)addrBuf.bufferPtr(), addrLen);
138413569Sbrandon.potter@amd.com        sap = &sa;
138513569Sbrandon.potter@amd.com    }
138613569Sbrandon.potter@amd.com
138713569Sbrandon.potter@amd.com    ssize_t sent_size = sendto(sim_fd,
138813569Sbrandon.potter@amd.com                               (void *)bufrBuf.bufferPtr(),
138913569Sbrandon.potter@amd.com                               bufrLen, flags, sap, (socklen_t)addrLen);
139013569Sbrandon.potter@amd.com
139113569Sbrandon.potter@amd.com    return (sent_size == -1) ? -errno : sent_size;
139213569Sbrandon.potter@amd.com}
139313569Sbrandon.potter@amd.com
139413569Sbrandon.potter@amd.comSyscallReturn
139513569Sbrandon.potter@amd.comrecvmsgFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
139613569Sbrandon.potter@amd.com{
139713569Sbrandon.potter@amd.com    int index = 0;
139813569Sbrandon.potter@amd.com    int tgt_fd = p->getSyscallArg(tc, index);
139913569Sbrandon.potter@amd.com    Addr msgPtr = p->getSyscallArg(tc, index);
140013569Sbrandon.potter@amd.com    int flags = p->getSyscallArg(tc, index);
140113569Sbrandon.potter@amd.com
140213569Sbrandon.potter@amd.com    auto sfdp = std::dynamic_pointer_cast<SocketFDEntry>((*p->fds)[tgt_fd]);
140313569Sbrandon.potter@amd.com    if (!sfdp)
140413569Sbrandon.potter@amd.com        return -EBADF;
140513569Sbrandon.potter@amd.com    int sim_fd = sfdp->getSimFD();
140613569Sbrandon.potter@amd.com
140713569Sbrandon.potter@amd.com     /**
140813569Sbrandon.potter@amd.com      *  struct msghdr {
140913569Sbrandon.potter@amd.com      *     void         *msg_name;       // optional address
141013569Sbrandon.potter@amd.com      *    socklen_t     msg_namelen;    // size of address
141113569Sbrandon.potter@amd.com      *    struct iovec *msg_iov;        // iovec array
141213569Sbrandon.potter@amd.com      *    size_t        msg_iovlen;     // number entries in msg_iov
141313569Sbrandon.potter@amd.com      *    i                             // entries correspond to buffer
141413569Sbrandon.potter@amd.com      *    void         *msg_control;    // ancillary data
141513569Sbrandon.potter@amd.com      *    size_t        msg_controllen; // ancillary data buffer len
141613569Sbrandon.potter@amd.com      *    int           msg_flags;      // flags on received message
141713569Sbrandon.potter@amd.com      *  };
141813569Sbrandon.potter@amd.com      *
141913569Sbrandon.potter@amd.com      *  struct iovec {
142013569Sbrandon.potter@amd.com      *    void  *iov_base;              // starting address
142113569Sbrandon.potter@amd.com      *    size_t iov_len;               // number of bytes to transfer
142213569Sbrandon.potter@amd.com      *  };
142313569Sbrandon.potter@amd.com      */
142413569Sbrandon.potter@amd.com
142513569Sbrandon.potter@amd.com    /**
142613569Sbrandon.potter@amd.com     * The plan with this system call is to replace all of the pointers in the
142713569Sbrandon.potter@amd.com     * structure and the substructure with BufferArg class pointers. We will
142813569Sbrandon.potter@amd.com     * copy every field from the structures into our BufferArg classes.
142913569Sbrandon.potter@amd.com     */
143013569Sbrandon.potter@amd.com    BufferArg msgBuf(msgPtr, sizeof(struct msghdr));
143113569Sbrandon.potter@amd.com    msgBuf.copyIn(tc->getMemProxy());
143213569Sbrandon.potter@amd.com    struct msghdr *msgHdr = (struct msghdr *)msgBuf.bufferPtr();
143313569Sbrandon.potter@amd.com
143413569Sbrandon.potter@amd.com    /**
143513569Sbrandon.potter@amd.com     * We will use these address place holders to retain the pointers which
143613569Sbrandon.potter@amd.com     * we are going to replace with our own buffers in our simulator address
143713569Sbrandon.potter@amd.com     * space.
143813569Sbrandon.potter@amd.com     */
143913569Sbrandon.potter@amd.com    Addr msg_name_phold = 0;
144013569Sbrandon.potter@amd.com    Addr msg_iov_phold = 0;
144113569Sbrandon.potter@amd.com    Addr iovec_base_phold[msgHdr->msg_iovlen];
144213569Sbrandon.potter@amd.com    Addr msg_control_phold = 0;
144313569Sbrandon.potter@amd.com
144413569Sbrandon.potter@amd.com    /**
144513569Sbrandon.potter@amd.com     * Record msg_name pointer then replace with buffer pointer.
144613569Sbrandon.potter@amd.com     */
144713569Sbrandon.potter@amd.com    BufferArg *nameBuf = NULL;
144813569Sbrandon.potter@amd.com    if (msgHdr->msg_name) {
144913569Sbrandon.potter@amd.com        /*1*/msg_name_phold = (Addr)msgHdr->msg_name;
145013569Sbrandon.potter@amd.com        /*2*/nameBuf = new BufferArg(msg_name_phold, msgHdr->msg_namelen);
145113569Sbrandon.potter@amd.com        /*3*/nameBuf->copyIn(tc->getMemProxy());
145213569Sbrandon.potter@amd.com        /*4*/msgHdr->msg_name = nameBuf->bufferPtr();
145313569Sbrandon.potter@amd.com    }
145413569Sbrandon.potter@amd.com
145513569Sbrandon.potter@amd.com    /**
145613569Sbrandon.potter@amd.com     * Record msg_iov pointer then replace with buffer pointer. Also, setup
145713569Sbrandon.potter@amd.com     * an array of buffer pointers for the iovec structs record and replace
145813569Sbrandon.potter@amd.com     * their pointers with buffer pointers.
145913569Sbrandon.potter@amd.com     */
146013569Sbrandon.potter@amd.com    BufferArg *iovBuf = NULL;
146113569Sbrandon.potter@amd.com    BufferArg *iovecBuf[msgHdr->msg_iovlen];
146213569Sbrandon.potter@amd.com    for (int i = 0; i < msgHdr->msg_iovlen; i++) {
146313569Sbrandon.potter@amd.com        iovec_base_phold[i] = 0;
146413569Sbrandon.potter@amd.com        iovecBuf[i] = NULL;
146513569Sbrandon.potter@amd.com    }
146613569Sbrandon.potter@amd.com
146713569Sbrandon.potter@amd.com    if (msgHdr->msg_iov) {
146813569Sbrandon.potter@amd.com        /*1*/msg_iov_phold = (Addr)msgHdr->msg_iov;
146913569Sbrandon.potter@amd.com        /*2*/iovBuf = new BufferArg(msg_iov_phold, msgHdr->msg_iovlen *
147013569Sbrandon.potter@amd.com                                    sizeof(struct iovec));
147113569Sbrandon.potter@amd.com        /*3*/iovBuf->copyIn(tc->getMemProxy());
147213569Sbrandon.potter@amd.com        for (int i = 0; i < msgHdr->msg_iovlen; i++) {
147313569Sbrandon.potter@amd.com            if (((struct iovec *)iovBuf->bufferPtr())[i].iov_base) {
147413569Sbrandon.potter@amd.com                /*1*/iovec_base_phold[i] =
147513569Sbrandon.potter@amd.com                     (Addr)((struct iovec *)iovBuf->bufferPtr())[i].iov_base;
147613569Sbrandon.potter@amd.com                /*2*/iovecBuf[i] = new BufferArg(iovec_base_phold[i],
147713569Sbrandon.potter@amd.com                     ((struct iovec *)iovBuf->bufferPtr())[i].iov_len);
147813569Sbrandon.potter@amd.com                /*3*/iovecBuf[i]->copyIn(tc->getMemProxy());
147913569Sbrandon.potter@amd.com                /*4*/((struct iovec *)iovBuf->bufferPtr())[i].iov_base =
148013569Sbrandon.potter@amd.com                     iovecBuf[i]->bufferPtr();
148113569Sbrandon.potter@amd.com            }
148213569Sbrandon.potter@amd.com        }
148313569Sbrandon.potter@amd.com        /*4*/msgHdr->msg_iov = (struct iovec *)iovBuf->bufferPtr();
148413569Sbrandon.potter@amd.com    }
148513569Sbrandon.potter@amd.com
148613569Sbrandon.potter@amd.com    /**
148713569Sbrandon.potter@amd.com     * Record msg_control pointer then replace with buffer pointer.
148813569Sbrandon.potter@amd.com     */
148913569Sbrandon.potter@amd.com    BufferArg *controlBuf = NULL;
149013569Sbrandon.potter@amd.com    if (msgHdr->msg_control) {
149113569Sbrandon.potter@amd.com        /*1*/msg_control_phold = (Addr)msgHdr->msg_control;
149213569Sbrandon.potter@amd.com        /*2*/controlBuf = new BufferArg(msg_control_phold,
149313569Sbrandon.potter@amd.com                                        CMSG_ALIGN(msgHdr->msg_controllen));
149413569Sbrandon.potter@amd.com        /*3*/controlBuf->copyIn(tc->getMemProxy());
149513569Sbrandon.potter@amd.com        /*4*/msgHdr->msg_control = controlBuf->bufferPtr();
149613569Sbrandon.potter@amd.com    }
149713569Sbrandon.potter@amd.com
149813569Sbrandon.potter@amd.com    ssize_t recvd_size = recvmsg(sim_fd, msgHdr, flags);
149913569Sbrandon.potter@amd.com
150013569Sbrandon.potter@amd.com    if (recvd_size < 0)
150113569Sbrandon.potter@amd.com        return -errno;
150213569Sbrandon.potter@amd.com
150313569Sbrandon.potter@amd.com    if (msgHdr->msg_name) {
150413569Sbrandon.potter@amd.com        nameBuf->copyOut(tc->getMemProxy());
150513569Sbrandon.potter@amd.com        delete(nameBuf);
150613569Sbrandon.potter@amd.com        msgHdr->msg_name = (void *)msg_name_phold;
150713569Sbrandon.potter@amd.com    }
150813569Sbrandon.potter@amd.com
150913569Sbrandon.potter@amd.com    if (msgHdr->msg_iov) {
151013569Sbrandon.potter@amd.com        for (int i = 0; i< msgHdr->msg_iovlen; i++) {
151113569Sbrandon.potter@amd.com            if (((struct iovec *)iovBuf->bufferPtr())[i].iov_base) {
151213569Sbrandon.potter@amd.com                iovecBuf[i]->copyOut(tc->getMemProxy());
151313569Sbrandon.potter@amd.com                delete iovecBuf[i];
151413569Sbrandon.potter@amd.com                ((struct iovec *)iovBuf->bufferPtr())[i].iov_base =
151513569Sbrandon.potter@amd.com                (void *)iovec_base_phold[i];
151613569Sbrandon.potter@amd.com            }
151713569Sbrandon.potter@amd.com        }
151813569Sbrandon.potter@amd.com        iovBuf->copyOut(tc->getMemProxy());
151913569Sbrandon.potter@amd.com        delete iovBuf;
152013569Sbrandon.potter@amd.com        msgHdr->msg_iov = (struct iovec *)msg_iov_phold;
152113569Sbrandon.potter@amd.com    }
152213569Sbrandon.potter@amd.com
152313569Sbrandon.potter@amd.com    if (msgHdr->msg_control) {
152413569Sbrandon.potter@amd.com        controlBuf->copyOut(tc->getMemProxy());
152513569Sbrandon.potter@amd.com        delete(controlBuf);
152613569Sbrandon.potter@amd.com        msgHdr->msg_control = (void *)msg_control_phold;
152713569Sbrandon.potter@amd.com    }
152813569Sbrandon.potter@amd.com
152913569Sbrandon.potter@amd.com    msgBuf.copyOut(tc->getMemProxy());
153013569Sbrandon.potter@amd.com
153113569Sbrandon.potter@amd.com    return recvd_size;
153213569Sbrandon.potter@amd.com}
153313569Sbrandon.potter@amd.com
153413569Sbrandon.potter@amd.comSyscallReturn
153513569Sbrandon.potter@amd.comsendmsgFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
153613569Sbrandon.potter@amd.com{
153713569Sbrandon.potter@amd.com    int index = 0;
153813569Sbrandon.potter@amd.com    int tgt_fd = p->getSyscallArg(tc, index);
153913569Sbrandon.potter@amd.com    Addr msgPtr = p->getSyscallArg(tc, index);
154013569Sbrandon.potter@amd.com    int flags = p->getSyscallArg(tc, index);
154113569Sbrandon.potter@amd.com
154213569Sbrandon.potter@amd.com    auto sfdp = std::dynamic_pointer_cast<SocketFDEntry>((*p->fds)[tgt_fd]);
154313569Sbrandon.potter@amd.com    if (!sfdp)
154413569Sbrandon.potter@amd.com        return -EBADF;
154513569Sbrandon.potter@amd.com    int sim_fd = sfdp->getSimFD();
154613569Sbrandon.potter@amd.com
154713569Sbrandon.potter@amd.com    /**
154813569Sbrandon.potter@amd.com     * Reserve buffer space.
154913569Sbrandon.potter@amd.com     */
155013569Sbrandon.potter@amd.com    BufferArg msgBuf(msgPtr, sizeof(struct msghdr));
155113569Sbrandon.potter@amd.com    msgBuf.copyIn(tc->getMemProxy());
155213569Sbrandon.potter@amd.com    struct msghdr msgHdr = *((struct msghdr *)msgBuf.bufferPtr());
155313569Sbrandon.potter@amd.com
155413569Sbrandon.potter@amd.com    /**
155513569Sbrandon.potter@amd.com     * Assuming msgHdr.msg_iovlen >= 1, then there is no point calling
155613569Sbrandon.potter@amd.com     * recvmsg without a buffer.
155713569Sbrandon.potter@amd.com     */
155813569Sbrandon.potter@amd.com    struct iovec *iovPtr = msgHdr.msg_iov;
155913569Sbrandon.potter@amd.com    BufferArg iovBuf((Addr)iovPtr, sizeof(struct iovec) * msgHdr.msg_iovlen);
156013569Sbrandon.potter@amd.com    iovBuf.copyIn(tc->getMemProxy());
156113569Sbrandon.potter@amd.com    struct iovec *iov = (struct iovec *)iovBuf.bufferPtr();
156213569Sbrandon.potter@amd.com    msgHdr.msg_iov = iov;
156313569Sbrandon.potter@amd.com
156413569Sbrandon.potter@amd.com    /**
156513569Sbrandon.potter@amd.com     * Cannot instantiate buffers till inside the loop.
156613569Sbrandon.potter@amd.com     * Create array to hold buffer addresses, to be used during copyIn of
156713569Sbrandon.potter@amd.com     * send data.
156813569Sbrandon.potter@amd.com     */
156913569Sbrandon.potter@amd.com    BufferArg **bufferArray = (BufferArg **)malloc(msgHdr.msg_iovlen
157013569Sbrandon.potter@amd.com                                                   * sizeof(BufferArg *));
157113569Sbrandon.potter@amd.com
157213569Sbrandon.potter@amd.com    /**
157313569Sbrandon.potter@amd.com     * Iterate through the iovec structures:
157413569Sbrandon.potter@amd.com     * Get the base buffer addreses, reserve iov_len amount of space for each.
157513569Sbrandon.potter@amd.com     * Put the buf address into the bufferArray for later retrieval.
157613569Sbrandon.potter@amd.com     */
157713569Sbrandon.potter@amd.com    for (int iovIndex = 0 ; iovIndex < msgHdr.msg_iovlen; iovIndex++) {
157813569Sbrandon.potter@amd.com        Addr basePtr = (Addr) iov[iovIndex].iov_base;
157913569Sbrandon.potter@amd.com        bufferArray[iovIndex] = new BufferArg(basePtr, iov[iovIndex].iov_len);
158013569Sbrandon.potter@amd.com        bufferArray[iovIndex]->copyIn(tc->getMemProxy());
158113569Sbrandon.potter@amd.com        iov[iovIndex].iov_base = bufferArray[iovIndex]->bufferPtr();
158213569Sbrandon.potter@amd.com    }
158313569Sbrandon.potter@amd.com
158413569Sbrandon.potter@amd.com    ssize_t sent_size = sendmsg(sim_fd, &msgHdr, flags);
158513569Sbrandon.potter@amd.com    int local_errno = errno;
158613569Sbrandon.potter@amd.com
158713569Sbrandon.potter@amd.com    /**
158813569Sbrandon.potter@amd.com     * Free dynamically allocated memory.
158913569Sbrandon.potter@amd.com     */
159013569Sbrandon.potter@amd.com    for (int iovIndex = 0 ; iovIndex < msgHdr.msg_iovlen; iovIndex++) {
159113569Sbrandon.potter@amd.com        BufferArg *baseBuf = ( BufferArg *)bufferArray[iovIndex];
159213569Sbrandon.potter@amd.com        delete(baseBuf);
159313569Sbrandon.potter@amd.com    }
159413569Sbrandon.potter@amd.com
159513569Sbrandon.potter@amd.com    /**
159613569Sbrandon.potter@amd.com     * Malloced above.
159713569Sbrandon.potter@amd.com     */
159813569Sbrandon.potter@amd.com    free(bufferArray);
159913569Sbrandon.potter@amd.com
160013569Sbrandon.potter@amd.com    return (sent_size < 0) ? -local_errno : sent_size;
160113569Sbrandon.potter@amd.com}
160213569Sbrandon.potter@amd.com
160313571Sbrandon.potter@amd.comSyscallReturn
160413571Sbrandon.potter@amd.comgetsockoptFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
160513571Sbrandon.potter@amd.com{
160613571Sbrandon.potter@amd.com    // union of all possible return value types from getsockopt
160713571Sbrandon.potter@amd.com    union val {
160813571Sbrandon.potter@amd.com        int i_val;
160913571Sbrandon.potter@amd.com        long l_val;
161013571Sbrandon.potter@amd.com        struct linger linger_val;
161113571Sbrandon.potter@amd.com        struct timeval timeval_val;
161213571Sbrandon.potter@amd.com    } val;
161313571Sbrandon.potter@amd.com
161413571Sbrandon.potter@amd.com    int index = 0;
161513571Sbrandon.potter@amd.com    int tgt_fd = p->getSyscallArg(tc, index);
161613571Sbrandon.potter@amd.com    int level = p->getSyscallArg(tc, index);
161713571Sbrandon.potter@amd.com    int optname = p->getSyscallArg(tc, index);
161813571Sbrandon.potter@amd.com    Addr valPtr = p->getSyscallArg(tc, index);
161913571Sbrandon.potter@amd.com    Addr lenPtr = p->getSyscallArg(tc, index);
162013571Sbrandon.potter@amd.com
162113571Sbrandon.potter@amd.com    auto sfdp = std::dynamic_pointer_cast<SocketFDEntry>((*p->fds)[tgt_fd]);
162213571Sbrandon.potter@amd.com    if (!sfdp)
162313571Sbrandon.potter@amd.com        return -EBADF;
162413571Sbrandon.potter@amd.com    int sim_fd = sfdp->getSimFD();
162513571Sbrandon.potter@amd.com
162613571Sbrandon.potter@amd.com    socklen_t len = sizeof(val);
162713571Sbrandon.potter@amd.com    int status = getsockopt(sim_fd, level, optname, &val, &len);
162813571Sbrandon.potter@amd.com
162913571Sbrandon.potter@amd.com    if (status == -1)
163013571Sbrandon.potter@amd.com        return -errno;
163113571Sbrandon.potter@amd.com
163213571Sbrandon.potter@amd.com    // copy val to valPtr and pass it on
163313571Sbrandon.potter@amd.com    BufferArg valBuf(valPtr, sizeof(val));
163413571Sbrandon.potter@amd.com    memcpy(valBuf.bufferPtr(), &val, sizeof(val));
163513571Sbrandon.potter@amd.com    valBuf.copyOut(tc->getMemProxy());
163613571Sbrandon.potter@amd.com
163713571Sbrandon.potter@amd.com    // copy len to lenPtr and pass  it on
163813571Sbrandon.potter@amd.com    BufferArg lenBuf(lenPtr, sizeof(len));
163913571Sbrandon.potter@amd.com    memcpy(lenBuf.bufferPtr(), &len, sizeof(len));
164013571Sbrandon.potter@amd.com    lenBuf.copyOut(tc->getMemProxy());
164113571Sbrandon.potter@amd.com
164213571Sbrandon.potter@amd.com    return status;
164313571Sbrandon.potter@amd.com}
164413571Sbrandon.potter@amd.com
164513571Sbrandon.potter@amd.comSyscallReturn
164613571Sbrandon.potter@amd.comgetsocknameFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
164713571Sbrandon.potter@amd.com{
164813571Sbrandon.potter@amd.com    int index = 0;
164913571Sbrandon.potter@amd.com    int tgt_fd = p->getSyscallArg(tc, index);
165013571Sbrandon.potter@amd.com    Addr addrPtr = p->getSyscallArg(tc, index);
165113571Sbrandon.potter@amd.com    Addr lenPtr = p->getSyscallArg(tc, index);
165213571Sbrandon.potter@amd.com
165313571Sbrandon.potter@amd.com    auto sfdp = std::dynamic_pointer_cast<SocketFDEntry>((*p->fds)[tgt_fd]);
165413571Sbrandon.potter@amd.com    if (!sfdp)
165513571Sbrandon.potter@amd.com        return -EBADF;
165613571Sbrandon.potter@amd.com    int sim_fd = sfdp->getSimFD();
165713571Sbrandon.potter@amd.com
165813571Sbrandon.potter@amd.com    // lenPtr is an in-out paramenter:
165913571Sbrandon.potter@amd.com    // sending the address length in, conveying the final length out
166013571Sbrandon.potter@amd.com
166113571Sbrandon.potter@amd.com    // Read in the value of len from the passed pointer.
166213571Sbrandon.potter@amd.com    BufferArg lenBuf(lenPtr, sizeof(socklen_t));
166313571Sbrandon.potter@amd.com    lenBuf.copyIn(tc->getMemProxy());
166413571Sbrandon.potter@amd.com    socklen_t len = *(socklen_t *)lenBuf.bufferPtr();
166513571Sbrandon.potter@amd.com
166613571Sbrandon.potter@amd.com    struct sockaddr sa;
166713571Sbrandon.potter@amd.com    int status = getsockname(sim_fd, &sa, &len);
166813571Sbrandon.potter@amd.com
166913571Sbrandon.potter@amd.com    if (status == -1)
167013571Sbrandon.potter@amd.com        return -errno;
167113571Sbrandon.potter@amd.com
167213571Sbrandon.potter@amd.com    // Copy address to addrPtr and pass it on.
167313571Sbrandon.potter@amd.com    BufferArg addrBuf(addrPtr, sizeof(sa));
167413571Sbrandon.potter@amd.com    memcpy(addrBuf.bufferPtr(), &sa, sizeof(sa));
167513571Sbrandon.potter@amd.com    addrBuf.copyOut(tc->getMemProxy());
167613571Sbrandon.potter@amd.com
167713571Sbrandon.potter@amd.com    // Copy len to lenPtr and pass  it on.
167813571Sbrandon.potter@amd.com    *(socklen_t *)lenBuf.bufferPtr() = len;
167913571Sbrandon.potter@amd.com    lenBuf.copyOut(tc->getMemProxy());
168013571Sbrandon.potter@amd.com
168113571Sbrandon.potter@amd.com    return status;
168213571Sbrandon.potter@amd.com}
168313571Sbrandon.potter@amd.com
168413571Sbrandon.potter@amd.comSyscallReturn
168513571Sbrandon.potter@amd.comgetpeernameFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
168613571Sbrandon.potter@amd.com{
168713571Sbrandon.potter@amd.com    int index = 0;
168813571Sbrandon.potter@amd.com    int tgt_fd = p->getSyscallArg(tc, index);
168913571Sbrandon.potter@amd.com    Addr sockAddrPtr = p->getSyscallArg(tc, index);
169013571Sbrandon.potter@amd.com    Addr addrlenPtr = p->getSyscallArg(tc, index);
169113571Sbrandon.potter@amd.com
169213571Sbrandon.potter@amd.com    auto sfdp = std::dynamic_pointer_cast<SocketFDEntry>((*p->fds)[tgt_fd]);
169313571Sbrandon.potter@amd.com    if (!sfdp)
169413571Sbrandon.potter@amd.com        return -EBADF;
169513571Sbrandon.potter@amd.com    int sim_fd = sfdp->getSimFD();
169613571Sbrandon.potter@amd.com
169713571Sbrandon.potter@amd.com    BufferArg bufAddrlen(addrlenPtr, sizeof(unsigned));
169813571Sbrandon.potter@amd.com    bufAddrlen.copyIn(tc->getMemProxy());
169913571Sbrandon.potter@amd.com    BufferArg bufSock(sockAddrPtr, *(unsigned *)bufAddrlen.bufferPtr());
170013571Sbrandon.potter@amd.com
170113571Sbrandon.potter@amd.com    int retval = getpeername(sim_fd,
170213571Sbrandon.potter@amd.com                             (struct sockaddr *)bufSock.bufferPtr(),
170313571Sbrandon.potter@amd.com                             (unsigned *)bufAddrlen.bufferPtr());
170413571Sbrandon.potter@amd.com
170513571Sbrandon.potter@amd.com    if (retval != -1) {
170613571Sbrandon.potter@amd.com        bufSock.copyOut(tc->getMemProxy());
170713571Sbrandon.potter@amd.com        bufAddrlen.copyOut(tc->getMemProxy());
170813571Sbrandon.potter@amd.com    }
170913571Sbrandon.potter@amd.com
171013571Sbrandon.potter@amd.com    return (retval == -1) ? -errno : retval;
171113571Sbrandon.potter@amd.com}
171213571Sbrandon.potter@amd.com
171313571Sbrandon.potter@amd.comSyscallReturn
171413571Sbrandon.potter@amd.comsetsockoptFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
171513571Sbrandon.potter@amd.com{
171613571Sbrandon.potter@amd.com    int index = 0;
171713571Sbrandon.potter@amd.com    int tgt_fd = p->getSyscallArg(tc, index);
171813571Sbrandon.potter@amd.com    int level = p->getSyscallArg(tc, index);
171913571Sbrandon.potter@amd.com    int optname = p->getSyscallArg(tc, index);
172013571Sbrandon.potter@amd.com    Addr valPtr = p->getSyscallArg(tc, index);
172113571Sbrandon.potter@amd.com    socklen_t len = p->getSyscallArg(tc, index);
172213571Sbrandon.potter@amd.com
172313571Sbrandon.potter@amd.com    BufferArg valBuf(valPtr, len);
172413571Sbrandon.potter@amd.com    valBuf.copyIn(tc->getMemProxy());
172513571Sbrandon.potter@amd.com
172613571Sbrandon.potter@amd.com    auto sfdp = std::dynamic_pointer_cast<SocketFDEntry>((*p->fds)[tgt_fd]);
172713571Sbrandon.potter@amd.com    if (!sfdp)
172813571Sbrandon.potter@amd.com        return -EBADF;
172913571Sbrandon.potter@amd.com    int sim_fd = sfdp->getSimFD();
173013571Sbrandon.potter@amd.com
173113571Sbrandon.potter@amd.com    int status = setsockopt(sim_fd, level, optname,
173213571Sbrandon.potter@amd.com                            (struct sockaddr *)valBuf.bufferPtr(), len);
173313571Sbrandon.potter@amd.com
173413571Sbrandon.potter@amd.com    return (status == -1) ? -errno : status;
173513571Sbrandon.potter@amd.com}
173613571Sbrandon.potter@amd.com
1737