syscall_emul.cc revision 13569
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    int activeContexts = 0;
10611911SBrandon.Potter@amd.com    for (auto &system: sys->systemList)
10711911SBrandon.Potter@amd.com        activeContexts += system->numRunningContexts();
10811911SBrandon.Potter@amd.com    if (activeContexts == 1) {
10912716Smichael.lebeane@amd.com        /**
11012716Smichael.lebeane@amd.com         * Even though we are terminating the final thread context, dist-gem5
11112716Smichael.lebeane@amd.com         * requires the simulation to remain active and provide
11212716Smichael.lebeane@amd.com         * synchronization messages to the switch process. So we just halt
11312716Smichael.lebeane@amd.com         * the last thread context and return. The simulation will be
11412716Smichael.lebeane@amd.com         * terminated by dist-gem5 in a coordinated manner once all nodes
11512716Smichael.lebeane@amd.com         * have signaled their readiness to exit. For non dist-gem5
11612716Smichael.lebeane@amd.com         * simulations, readyToExit() always returns true.
11712716Smichael.lebeane@amd.com         */
11812716Smichael.lebeane@amd.com        if (!DistIface::readyToExit(0)) {
11912716Smichael.lebeane@amd.com            tc->halt();
12012716Smichael.lebeane@amd.com            return status;
12112716Smichael.lebeane@amd.com        }
12212716Smichael.lebeane@amd.com
12311911SBrandon.Potter@amd.com        exitSimLoop("exiting with last active thread context", status & 0xff);
12411911SBrandon.Potter@amd.com        return status;
12511911SBrandon.Potter@amd.com    }
12611911SBrandon.Potter@amd.com
12711911SBrandon.Potter@amd.com    if (group)
12811911SBrandon.Potter@amd.com        *p->exitGroup = true;
12911911SBrandon.Potter@amd.com
13011911SBrandon.Potter@amd.com    if (p->childClearTID)
13111911SBrandon.Potter@amd.com        exitFutexWake(tc, p->childClearTID, p->tgid());
13211911SBrandon.Potter@amd.com
13311911SBrandon.Potter@amd.com    bool last_thread = true;
13411911SBrandon.Potter@amd.com    Process *parent = nullptr, *tg_lead = nullptr;
13511911SBrandon.Potter@amd.com    for (int i = 0; last_thread && i < sys->numContexts(); i++) {
13611911SBrandon.Potter@amd.com        Process *walk;
13711911SBrandon.Potter@amd.com        if (!(walk = sys->threadContexts[i]->getProcessPtr()))
13811911SBrandon.Potter@amd.com            continue;
13911911SBrandon.Potter@amd.com
14011911SBrandon.Potter@amd.com        /**
14111911SBrandon.Potter@amd.com         * Threads in a thread group require special handing. For instance,
14211911SBrandon.Potter@amd.com         * we send the SIGCHLD signal so that it appears that it came from
14311911SBrandon.Potter@amd.com         * the head of the group. We also only delete file descriptors if
14411911SBrandon.Potter@amd.com         * we are the last thread in the thread group.
14511911SBrandon.Potter@amd.com         */
14611911SBrandon.Potter@amd.com        if (walk->pid() == p->tgid())
14711911SBrandon.Potter@amd.com            tg_lead = walk;
14811911SBrandon.Potter@amd.com
14911911SBrandon.Potter@amd.com        if ((sys->threadContexts[i]->status() != ThreadContext::Halted)
15011911SBrandon.Potter@amd.com            && (walk != p)) {
15111911SBrandon.Potter@amd.com            /**
15211911SBrandon.Potter@amd.com             * Check if we share thread group with the pointer; this denotes
15311911SBrandon.Potter@amd.com             * that we are not the last thread active in the thread group.
15411911SBrandon.Potter@amd.com             * Note that setting this to false also prevents further
15511911SBrandon.Potter@amd.com             * iterations of the loop.
15611911SBrandon.Potter@amd.com             */
15711911SBrandon.Potter@amd.com            if (walk->tgid() == p->tgid())
15811911SBrandon.Potter@amd.com                last_thread = false;
15911911SBrandon.Potter@amd.com
16011911SBrandon.Potter@amd.com            /**
16111911SBrandon.Potter@amd.com             * A corner case exists which involves execve(). After execve(),
16211911SBrandon.Potter@amd.com             * the execve will enable SIGCHLD in the process. The problem
16311911SBrandon.Potter@amd.com             * occurs when the exiting process is the root process in the
16411911SBrandon.Potter@amd.com             * system; there is no parent to receive the signal. We obviate
16511911SBrandon.Potter@amd.com             * this problem by setting the root process' ppid to zero in the
16611911SBrandon.Potter@amd.com             * Python configuration files. We really should handle the
16711911SBrandon.Potter@amd.com             * root/execve specific case more gracefully.
16811911SBrandon.Potter@amd.com             */
16911911SBrandon.Potter@amd.com            if (*p->sigchld && (p->ppid() != 0) && (walk->pid() == p->ppid()))
17011911SBrandon.Potter@amd.com                parent = walk;
17111886Sbrandon.potter@amd.com        }
17211886Sbrandon.potter@amd.com    }
17311911SBrandon.Potter@amd.com
17411911SBrandon.Potter@amd.com    if (last_thread) {
17511911SBrandon.Potter@amd.com        if (parent) {
17611911SBrandon.Potter@amd.com            assert(tg_lead);
17711911SBrandon.Potter@amd.com            sys->signalList.push_back(BasicSignal(tg_lead, parent, SIGCHLD));
17811911SBrandon.Potter@amd.com        }
17911911SBrandon.Potter@amd.com
18011911SBrandon.Potter@amd.com        /**
18111911SBrandon.Potter@amd.com         * Run though FD array of the exiting process and close all file
18211911SBrandon.Potter@amd.com         * descriptors except for the standard file descriptors.
18311911SBrandon.Potter@amd.com         * (The standard file descriptors are shared with gem5.)
18411911SBrandon.Potter@amd.com         */
18511911SBrandon.Potter@amd.com        for (int i = 0; i < p->fds->getSize(); i++) {
18611911SBrandon.Potter@amd.com            if ((*p->fds)[i])
18711911SBrandon.Potter@amd.com                p->fds->closeFDEntry(i);
18811911SBrandon.Potter@amd.com        }
18911911SBrandon.Potter@amd.com    }
19011911SBrandon.Potter@amd.com
19111911SBrandon.Potter@amd.com    tc->halt();
19211911SBrandon.Potter@amd.com    return status;
19311886Sbrandon.potter@amd.com}
1948149SChris.Emmons@ARM.com
1958149SChris.Emmons@ARM.comSyscallReturn
19611886Sbrandon.potter@amd.comexitFunc(SyscallDesc *desc, int callnum, Process *p, ThreadContext *tc)
197360SN/A{
19811911SBrandon.Potter@amd.com    return exitImpl(desc, callnum, p, tc, false);
199360SN/A}
200360SN/A
2011450SN/ASyscallReturn
20211911SBrandon.Potter@amd.comexitGroupFunc(SyscallDesc *desc, int callnum, Process *p, ThreadContext *tc)
2036109Ssanchezd@stanford.edu{
20411911SBrandon.Potter@amd.com    return exitImpl(desc, callnum, p, tc, true);
2056109Ssanchezd@stanford.edu}
2066109Ssanchezd@stanford.edu
2076109Ssanchezd@stanford.eduSyscallReturn
20811851Sbrandon.potter@amd.comgetpagesizeFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
209360SN/A{
21010318Sandreas.hansson@arm.com    return (int)PageBytes;
211360SN/A}
212360SN/A
213360SN/A
2141450SN/ASyscallReturn
21511851Sbrandon.potter@amd.combrkFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
216360SN/A{
217360SN/A    // change brk addr to first arg
2186701Sgblack@eecs.umich.edu    int index = 0;
2196701Sgblack@eecs.umich.edu    Addr new_brk = p->getSyscallArg(tc, index);
2205748SSteve.Reinhardt@amd.com
22111905SBrandon.Potter@amd.com    std::shared_ptr<MemState> mem_state = p->memState;
22211905SBrandon.Potter@amd.com    Addr brk_point = mem_state->getBrkPoint();
22311905SBrandon.Potter@amd.com
2245748SSteve.Reinhardt@amd.com    // in Linux at least, brk(0) returns the current break value
2255748SSteve.Reinhardt@amd.com    // (note that the syscall and the glibc function have different behavior)
2265748SSteve.Reinhardt@amd.com    if (new_brk == 0)
22711905SBrandon.Potter@amd.com        return brk_point;
2285748SSteve.Reinhardt@amd.com
22911905SBrandon.Potter@amd.com    if (new_brk > brk_point) {
2305748SSteve.Reinhardt@amd.com        // might need to allocate some new pages
23111905SBrandon.Potter@amd.com        for (ChunkGenerator gen(brk_point,
23211905SBrandon.Potter@amd.com                                new_brk - brk_point,
23310318Sandreas.hansson@arm.com                                PageBytes); !gen.done(); gen.next()) {
2345748SSteve.Reinhardt@amd.com            if (!p->pTable->translate(gen.addr()))
23510318Sandreas.hansson@arm.com                p->allocateMem(roundDown(gen.addr(), PageBytes), PageBytes);
2366687Stjones1@inf.ed.ac.uk
2376687Stjones1@inf.ed.ac.uk            // if the address is already there, zero it out
2386687Stjones1@inf.ed.ac.uk            else {
23911905SBrandon.Potter@amd.com                uint8_t zero = 0;
2408852Sandreas.hansson@arm.com                SETranslatingPortProxy &tp = tc->getMemProxy();
2416687Stjones1@inf.ed.ac.uk
2426687Stjones1@inf.ed.ac.uk                // split non-page aligned accesses
24310318Sandreas.hansson@arm.com                Addr next_page = roundUp(gen.addr(), PageBytes);
2446687Stjones1@inf.ed.ac.uk                uint32_t size_needed = next_page - gen.addr();
2458852Sandreas.hansson@arm.com                tp.memsetBlob(gen.addr(), zero, size_needed);
24610318Sandreas.hansson@arm.com                if (gen.addr() + PageBytes > next_page &&
2476687Stjones1@inf.ed.ac.uk                    next_page < new_brk &&
24811906SBrandon.Potter@amd.com                    p->pTable->translate(next_page)) {
24910318Sandreas.hansson@arm.com                    size_needed = PageBytes - size_needed;
2508852Sandreas.hansson@arm.com                    tp.memsetBlob(next_page, zero, size_needed);
2516687Stjones1@inf.ed.ac.uk                }
2526687Stjones1@inf.ed.ac.uk            }
2532474SN/A        }
2541450SN/A    }
2555748SSteve.Reinhardt@amd.com
25611905SBrandon.Potter@amd.com    mem_state->setBrkPoint(new_brk);
25711380Salexandru.dutu@amd.com    DPRINTF_SYSCALL(Verbose, "brk: break point changed to: %#X\n",
25811905SBrandon.Potter@amd.com                    mem_state->getBrkPoint());
25911905SBrandon.Potter@amd.com    return mem_state->getBrkPoint();
260360SN/A}
261360SN/A
26211886Sbrandon.potter@amd.comSyscallReturn
26311886Sbrandon.potter@amd.comsetTidAddressFunc(SyscallDesc *desc, int callnum, Process *process,
26411886Sbrandon.potter@amd.com                  ThreadContext *tc)
26511886Sbrandon.potter@amd.com{
26611886Sbrandon.potter@amd.com    int index = 0;
26711886Sbrandon.potter@amd.com    uint64_t tidPtr = process->getSyscallArg(tc, index);
26811886Sbrandon.potter@amd.com
26911886Sbrandon.potter@amd.com    process->childClearTID = tidPtr;
27011886Sbrandon.potter@amd.com    return process->pid();
27111886Sbrandon.potter@amd.com}
272360SN/A
2731450SN/ASyscallReturn
27411851Sbrandon.potter@amd.comcloseFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
275360SN/A{
2766701Sgblack@eecs.umich.edu    int index = 0;
27710931Sbrandon.potter@amd.com    int tgt_fd = p->getSyscallArg(tc, index);
27810931Sbrandon.potter@amd.com
27911856Sbrandon.potter@amd.com    return p->fds->closeFDEntry(tgt_fd);
280360SN/A}
281360SN/A
282360SN/A
2831450SN/ASyscallReturn
28411851Sbrandon.potter@amd.comreadFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
285360SN/A{
2866701Sgblack@eecs.umich.edu    int index = 0;
28710931Sbrandon.potter@amd.com    int tgt_fd = p->getSyscallArg(tc, index);
28811906SBrandon.Potter@amd.com    Addr buf_ptr = p->getSyscallArg(tc, index);
2896701Sgblack@eecs.umich.edu    int nbytes = p->getSyscallArg(tc, index);
29011856Sbrandon.potter@amd.com
29111856Sbrandon.potter@amd.com    auto hbfdp = std::dynamic_pointer_cast<HBFDEntry>((*p->fds)[tgt_fd]);
29211856Sbrandon.potter@amd.com    if (!hbfdp)
29311856Sbrandon.potter@amd.com        return -EBADF;
29411856Sbrandon.potter@amd.com    int sim_fd = hbfdp->getSimFD();
29511856Sbrandon.potter@amd.com
29611906SBrandon.Potter@amd.com    BufferArg bufArg(buf_ptr, nbytes);
29710931Sbrandon.potter@amd.com    int bytes_read = read(sim_fd, bufArg.bufferPtr(), nbytes);
298360SN/A
29911684Snderumigny@gmail.com    if (bytes_read > 0)
3008706Sandreas.hansson@arm.com        bufArg.copyOut(tc->getMemProxy());
301360SN/A
3021458SN/A    return bytes_read;
303360SN/A}
304360SN/A
3051450SN/ASyscallReturn
30611851Sbrandon.potter@amd.comwriteFunc(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);
31011906SBrandon.Potter@amd.com    Addr buf_ptr = p->getSyscallArg(tc, index);
3116701Sgblack@eecs.umich.edu    int nbytes = p->getSyscallArg(tc, index);
31211856Sbrandon.potter@amd.com
31311856Sbrandon.potter@amd.com    auto hbfdp = std::dynamic_pointer_cast<HBFDEntry>((*p->fds)[tgt_fd]);
31411856Sbrandon.potter@amd.com    if (!hbfdp)
31511856Sbrandon.potter@amd.com        return -EBADF;
31611856Sbrandon.potter@amd.com    int sim_fd = hbfdp->getSimFD();
31711856Sbrandon.potter@amd.com
31811906SBrandon.Potter@amd.com    BufferArg bufArg(buf_ptr, nbytes);
3198706Sandreas.hansson@arm.com    bufArg.copyIn(tc->getMemProxy());
320360SN/A
32110931Sbrandon.potter@amd.com    int bytes_written = write(sim_fd, bufArg.bufferPtr(), nbytes);
322360SN/A
32310931Sbrandon.potter@amd.com    fsync(sim_fd);
324360SN/A
3251458SN/A    return bytes_written;
326360SN/A}
327360SN/A
328360SN/A
3291450SN/ASyscallReturn
33011851Sbrandon.potter@amd.comlseekFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
331360SN/A{
3326701Sgblack@eecs.umich.edu    int index = 0;
33310931Sbrandon.potter@amd.com    int tgt_fd = p->getSyscallArg(tc, index);
3346701Sgblack@eecs.umich.edu    uint64_t offs = p->getSyscallArg(tc, index);
3356701Sgblack@eecs.umich.edu    int whence = p->getSyscallArg(tc, index);
336360SN/A
33711856Sbrandon.potter@amd.com    auto ffdp = std::dynamic_pointer_cast<FileFDEntry>((*p->fds)[tgt_fd]);
33811856Sbrandon.potter@amd.com    if (!ffdp)
33910931Sbrandon.potter@amd.com        return -EBADF;
34011856Sbrandon.potter@amd.com    int sim_fd = ffdp->getSimFD();
34110931Sbrandon.potter@amd.com
34210931Sbrandon.potter@amd.com    off_t result = lseek(sim_fd, offs, whence);
343360SN/A
3441458SN/A    return (result == (off_t)-1) ? -errno : result;
345360SN/A}
346360SN/A
347360SN/A
3481450SN/ASyscallReturn
34911851Sbrandon.potter@amd.com_llseekFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
3504118Sgblack@eecs.umich.edu{
3516701Sgblack@eecs.umich.edu    int index = 0;
35210931Sbrandon.potter@amd.com    int tgt_fd = p->getSyscallArg(tc, index);
3536701Sgblack@eecs.umich.edu    uint64_t offset_high = p->getSyscallArg(tc, index);
3546701Sgblack@eecs.umich.edu    uint32_t offset_low = p->getSyscallArg(tc, index);
3556701Sgblack@eecs.umich.edu    Addr result_ptr = p->getSyscallArg(tc, index);
3566701Sgblack@eecs.umich.edu    int whence = p->getSyscallArg(tc, index);
3574118Sgblack@eecs.umich.edu
35811856Sbrandon.potter@amd.com    auto ffdp = std::dynamic_pointer_cast<FileFDEntry>((*p->fds)[tgt_fd]);
35911856Sbrandon.potter@amd.com    if (!ffdp)
36010931Sbrandon.potter@amd.com        return -EBADF;
36111856Sbrandon.potter@amd.com    int sim_fd = ffdp->getSimFD();
36210931Sbrandon.potter@amd.com
3634118Sgblack@eecs.umich.edu    uint64_t offset = (offset_high << 32) | offset_low;
3644118Sgblack@eecs.umich.edu
36510931Sbrandon.potter@amd.com    uint64_t result = lseek(sim_fd, offset, whence);
3664118Sgblack@eecs.umich.edu    result = TheISA::htog(result);
3674118Sgblack@eecs.umich.edu
36811379Sbrandon.potter@amd.com    if (result == (off_t)-1)
3694118Sgblack@eecs.umich.edu        return -errno;
37011379Sbrandon.potter@amd.com    // Assuming that the size of loff_t is 64 bits on the target platform
37111379Sbrandon.potter@amd.com    BufferArg result_buf(result_ptr, sizeof(result));
37211379Sbrandon.potter@amd.com    memcpy(result_buf.bufferPtr(), &result, sizeof(result));
37311379Sbrandon.potter@amd.com    result_buf.copyOut(tc->getMemProxy());
37411379Sbrandon.potter@amd.com    return 0;
3754118Sgblack@eecs.umich.edu}
3764118Sgblack@eecs.umich.edu
3774118Sgblack@eecs.umich.edu
3784118Sgblack@eecs.umich.eduSyscallReturn
37911851Sbrandon.potter@amd.communmapFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
380360SN/A{
38111383Sbrandon.potter@amd.com    // With mmap more fully implemented, it might be worthwhile to bite
38211383Sbrandon.potter@amd.com    // the bullet and implement munmap. Should allow us to reuse simulated
38311383Sbrandon.potter@amd.com    // memory.
3841458SN/A    return 0;
385360SN/A}
386360SN/A
387360SN/A
388360SN/Aconst char *hostname = "m5.eecs.umich.edu";
389360SN/A
3901450SN/ASyscallReturn
39111851Sbrandon.potter@amd.comgethostnameFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
392360SN/A{
3936701Sgblack@eecs.umich.edu    int index = 0;
39411906SBrandon.Potter@amd.com    Addr buf_ptr = p->getSyscallArg(tc, index);
3956701Sgblack@eecs.umich.edu    int name_len = p->getSyscallArg(tc, index);
39611906SBrandon.Potter@amd.com    BufferArg name(buf_ptr, name_len);
397360SN/A
398360SN/A    strncpy((char *)name.bufferPtr(), hostname, name_len);
399360SN/A
4008706Sandreas.hansson@arm.com    name.copyOut(tc->getMemProxy());
401360SN/A
4021458SN/A    return 0;
403360SN/A}
404360SN/A
4051450SN/ASyscallReturn
40611851Sbrandon.potter@amd.comgetcwdFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
4075513SMichael.Adler@intel.com{
4085513SMichael.Adler@intel.com    int result = 0;
4096731Svince@csl.cornell.edu    int index = 0;
41011906SBrandon.Potter@amd.com    Addr buf_ptr = p->getSyscallArg(tc, index);
4116701Sgblack@eecs.umich.edu    unsigned long size = p->getSyscallArg(tc, index);
41211906SBrandon.Potter@amd.com    BufferArg buf(buf_ptr, size);
4135513SMichael.Adler@intel.com
4145513SMichael.Adler@intel.com    // Is current working directory defined?
4155513SMichael.Adler@intel.com    string cwd = p->getcwd();
4165513SMichael.Adler@intel.com    if (!cwd.empty()) {
4175513SMichael.Adler@intel.com        if (cwd.length() >= size) {
4185513SMichael.Adler@intel.com            // Buffer too small
4195513SMichael.Adler@intel.com            return -ERANGE;
4205513SMichael.Adler@intel.com        }
4215513SMichael.Adler@intel.com        strncpy((char *)buf.bufferPtr(), cwd.c_str(), size);
4225513SMichael.Adler@intel.com        result = cwd.length();
42310955Sdavid.hashe@amd.com    } else {
42411856Sbrandon.potter@amd.com        if (getcwd((char *)buf.bufferPtr(), size)) {
4255513SMichael.Adler@intel.com            result = strlen((char *)buf.bufferPtr());
42610955Sdavid.hashe@amd.com        } else {
4275513SMichael.Adler@intel.com            result = -1;
4285513SMichael.Adler@intel.com        }
4295513SMichael.Adler@intel.com    }
4305513SMichael.Adler@intel.com
4318706Sandreas.hansson@arm.com    buf.copyOut(tc->getMemProxy());
4325513SMichael.Adler@intel.com
4335513SMichael.Adler@intel.com    return (result == -1) ? -errno : result;
4345513SMichael.Adler@intel.com}
4355513SMichael.Adler@intel.com
43610203SAli.Saidi@ARM.comSyscallReturn
43711851Sbrandon.potter@amd.comreadlinkFunc(SyscallDesc *desc, int callnum, Process *process,
43811851Sbrandon.potter@amd.com             ThreadContext *tc)
43910203SAli.Saidi@ARM.com{
44010203SAli.Saidi@ARM.com    return readlinkFunc(desc, callnum, process, tc, 0);
44110203SAli.Saidi@ARM.com}
4425513SMichael.Adler@intel.com
4435513SMichael.Adler@intel.comSyscallReturn
44411851Sbrandon.potter@amd.comreadlinkFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc,
44511851Sbrandon.potter@amd.com             int index)
4465513SMichael.Adler@intel.com{
4475513SMichael.Adler@intel.com    string path;
4485513SMichael.Adler@intel.com
4498852Sandreas.hansson@arm.com    if (!tc->getMemProxy().tryReadString(path, p->getSyscallArg(tc, index)))
45010223Ssteve.reinhardt@amd.com        return -EFAULT;
4515513SMichael.Adler@intel.com
4525513SMichael.Adler@intel.com    // Adjust path for current working directory
4535513SMichael.Adler@intel.com    path = p->fullPath(path);
4545513SMichael.Adler@intel.com
45511906SBrandon.Potter@amd.com    Addr buf_ptr = p->getSyscallArg(tc, index);
4566701Sgblack@eecs.umich.edu    size_t bufsiz = p->getSyscallArg(tc, index);
4576701Sgblack@eecs.umich.edu
45811906SBrandon.Potter@amd.com    BufferArg buf(buf_ptr, bufsiz);
4595513SMichael.Adler@intel.com
46010955Sdavid.hashe@amd.com    int result = -1;
46110955Sdavid.hashe@amd.com    if (path != "/proc/self/exe") {
46210955Sdavid.hashe@amd.com        result = readlink(path.c_str(), (char *)buf.bufferPtr(), bufsiz);
46310955Sdavid.hashe@amd.com    } else {
46411140Sjthestness@gmail.com        // Emulate readlink() called on '/proc/self/exe' should return the
46511140Sjthestness@gmail.com        // absolute path of the binary running in the simulated system (the
46611851Sbrandon.potter@amd.com        // Process' executable). It is possible that using this path in
46711140Sjthestness@gmail.com        // the simulated system will result in unexpected behavior if:
46811140Sjthestness@gmail.com        //  1) One binary runs another (e.g., -c time -o "my_binary"), and
46911140Sjthestness@gmail.com        //     called binary calls readlink().
47011140Sjthestness@gmail.com        //  2) The host's full path to the running benchmark changes from one
47111140Sjthestness@gmail.com        //     simulation to another. This can result in different simulated
47211140Sjthestness@gmail.com        //     performance since the simulated system will process the binary
47311140Sjthestness@gmail.com        //     path differently, even if the binary itself does not change.
47411140Sjthestness@gmail.com
47511140Sjthestness@gmail.com        // Get the absolute canonical path to the running application
47611140Sjthestness@gmail.com        char real_path[PATH_MAX];
47711140Sjthestness@gmail.com        char *check_real_path = realpath(p->progName(), real_path);
47811140Sjthestness@gmail.com        if (!check_real_path) {
47911140Sjthestness@gmail.com            fatal("readlink('/proc/self/exe') unable to resolve path to "
48011140Sjthestness@gmail.com                  "executable: %s", p->progName());
48111140Sjthestness@gmail.com        }
48211140Sjthestness@gmail.com        strncpy((char*)buf.bufferPtr(), real_path, bufsiz);
48311140Sjthestness@gmail.com        size_t real_path_len = strlen(real_path);
48411140Sjthestness@gmail.com        if (real_path_len > bufsiz) {
48510955Sdavid.hashe@amd.com            // readlink will truncate the contents of the
48610955Sdavid.hashe@amd.com            // path to ensure it is no more than bufsiz
48710955Sdavid.hashe@amd.com            result = bufsiz;
48810955Sdavid.hashe@amd.com        } else {
48911140Sjthestness@gmail.com            result = real_path_len;
49010955Sdavid.hashe@amd.com        }
49111140Sjthestness@gmail.com
49211140Sjthestness@gmail.com        // Issue a warning about potential unexpected results
49311140Sjthestness@gmail.com        warn_once("readlink() called on '/proc/self/exe' may yield unexpected "
49411140Sjthestness@gmail.com                  "results in various settings.\n      Returning '%s'\n",
49511140Sjthestness@gmail.com                  (char*)buf.bufferPtr());
49610955Sdavid.hashe@amd.com    }
4975513SMichael.Adler@intel.com
4988706Sandreas.hansson@arm.com    buf.copyOut(tc->getMemProxy());
4995513SMichael.Adler@intel.com
5005513SMichael.Adler@intel.com    return (result == -1) ? -errno : result;
5015513SMichael.Adler@intel.com}
5025513SMichael.Adler@intel.com
5035513SMichael.Adler@intel.comSyscallReturn
50411851Sbrandon.potter@amd.comunlinkFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
505511SN/A{
50610633Smichaelupton@gmail.com    return unlinkHelper(desc, num, p, tc, 0);
50710633Smichaelupton@gmail.com}
50810633Smichaelupton@gmail.com
50910633Smichaelupton@gmail.comSyscallReturn
51011851Sbrandon.potter@amd.comunlinkHelper(SyscallDesc *desc, int num, Process *p, ThreadContext *tc,
51111851Sbrandon.potter@amd.com             int index)
51210633Smichaelupton@gmail.com{
5131706SN/A    string path;
514360SN/A
5158852Sandreas.hansson@arm.com    if (!tc->getMemProxy().tryReadString(path, p->getSyscallArg(tc, index)))
51610223Ssteve.reinhardt@amd.com        return -EFAULT;
517511SN/A
5183669Sbinkertn@umich.edu    path = p->fullPath(path);
5193669Sbinkertn@umich.edu
520511SN/A    int result = unlink(path.c_str());
5211458SN/A    return (result == -1) ? -errno : result;
522511SN/A}
523511SN/A
52412795Smattdsinclair@gmail.comSyscallReturn
52512795Smattdsinclair@gmail.comlinkFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
52612795Smattdsinclair@gmail.com{
52712795Smattdsinclair@gmail.com    string path;
52812795Smattdsinclair@gmail.com    string new_path;
52912795Smattdsinclair@gmail.com
53012795Smattdsinclair@gmail.com    int index = 0;
53112795Smattdsinclair@gmail.com    auto &virt_mem = tc->getMemProxy();
53212795Smattdsinclair@gmail.com    if (!virt_mem.tryReadString(path, p->getSyscallArg(tc, index)))
53312795Smattdsinclair@gmail.com        return -EFAULT;
53412795Smattdsinclair@gmail.com    if (!virt_mem.tryReadString(new_path, p->getSyscallArg(tc, index)))
53512795Smattdsinclair@gmail.com        return -EFAULT;
53612795Smattdsinclair@gmail.com
53712795Smattdsinclair@gmail.com    path = p->fullPath(path);
53812795Smattdsinclair@gmail.com    new_path = p->fullPath(new_path);
53912795Smattdsinclair@gmail.com
54012795Smattdsinclair@gmail.com    int result = link(path.c_str(), new_path.c_str());
54112795Smattdsinclair@gmail.com    return (result == -1) ? -errno : result;
54212795Smattdsinclair@gmail.com}
5435513SMichael.Adler@intel.com
5445513SMichael.Adler@intel.comSyscallReturn
54512796Smattdsinclair@gmail.comsymlinkFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
54612796Smattdsinclair@gmail.com{
54712796Smattdsinclair@gmail.com    string path;
54812796Smattdsinclair@gmail.com    string new_path;
54912796Smattdsinclair@gmail.com
55012796Smattdsinclair@gmail.com    int index = 0;
55112796Smattdsinclair@gmail.com    auto &virt_mem = tc->getMemProxy();
55212796Smattdsinclair@gmail.com    if (!virt_mem.tryReadString(path, p->getSyscallArg(tc, index)))
55312796Smattdsinclair@gmail.com        return -EFAULT;
55412796Smattdsinclair@gmail.com    if (!virt_mem.tryReadString(new_path, p->getSyscallArg(tc, index)))
55512796Smattdsinclair@gmail.com        return -EFAULT;
55612796Smattdsinclair@gmail.com
55712796Smattdsinclair@gmail.com    path = p->fullPath(path);
55812796Smattdsinclair@gmail.com    new_path = p->fullPath(new_path);
55912796Smattdsinclair@gmail.com
56012796Smattdsinclair@gmail.com    int result = symlink(path.c_str(), new_path.c_str());
56112796Smattdsinclair@gmail.com    return (result == -1) ? -errno : result;
56212796Smattdsinclair@gmail.com}
56312796Smattdsinclair@gmail.com
56412796Smattdsinclair@gmail.comSyscallReturn
56511851Sbrandon.potter@amd.commkdirFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
5665513SMichael.Adler@intel.com{
5675513SMichael.Adler@intel.com    string path;
5685513SMichael.Adler@intel.com
5696701Sgblack@eecs.umich.edu    int index = 0;
5708852Sandreas.hansson@arm.com    if (!tc->getMemProxy().tryReadString(path, p->getSyscallArg(tc, index)))
57110223Ssteve.reinhardt@amd.com        return -EFAULT;
5725513SMichael.Adler@intel.com
5735513SMichael.Adler@intel.com    // Adjust path for current working directory
5745513SMichael.Adler@intel.com    path = p->fullPath(path);
5755513SMichael.Adler@intel.com
5766701Sgblack@eecs.umich.edu    mode_t mode = p->getSyscallArg(tc, index);
5775513SMichael.Adler@intel.com
5785513SMichael.Adler@intel.com    int result = mkdir(path.c_str(), mode);
5795513SMichael.Adler@intel.com    return (result == -1) ? -errno : result;
5805513SMichael.Adler@intel.com}
5815513SMichael.Adler@intel.com
5821450SN/ASyscallReturn
58311851Sbrandon.potter@amd.comrenameFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
584511SN/A{
5851706SN/A    string old_name;
586511SN/A
5876701Sgblack@eecs.umich.edu    int index = 0;
5888852Sandreas.hansson@arm.com    if (!tc->getMemProxy().tryReadString(old_name, p->getSyscallArg(tc, index)))
5891458SN/A        return -EFAULT;
590511SN/A
5911706SN/A    string new_name;
592511SN/A
5938852Sandreas.hansson@arm.com    if (!tc->getMemProxy().tryReadString(new_name, p->getSyscallArg(tc, index)))
5941458SN/A        return -EFAULT;
595511SN/A
5963669Sbinkertn@umich.edu    // Adjust path for current working directory
5973669Sbinkertn@umich.edu    old_name = p->fullPath(old_name);
5983669Sbinkertn@umich.edu    new_name = p->fullPath(new_name);
5993669Sbinkertn@umich.edu
6001706SN/A    int64_t result = rename(old_name.c_str(), new_name.c_str());
6011458SN/A    return (result == -1) ? -errno : result;
602511SN/A}
603511SN/A
6041706SN/ASyscallReturn
60511851Sbrandon.potter@amd.comtruncateFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
6061706SN/A{
6071706SN/A    string path;
6081706SN/A
6096701Sgblack@eecs.umich.edu    int index = 0;
6108852Sandreas.hansson@arm.com    if (!tc->getMemProxy().tryReadString(path, p->getSyscallArg(tc, index)))
6111706SN/A        return -EFAULT;
6121706SN/A
6136701Sgblack@eecs.umich.edu    off_t length = p->getSyscallArg(tc, index);
6141706SN/A
6153669Sbinkertn@umich.edu    // Adjust path for current working directory
6163669Sbinkertn@umich.edu    path = p->fullPath(path);
6173669Sbinkertn@umich.edu
6181706SN/A    int result = truncate(path.c_str(), length);
6191706SN/A    return (result == -1) ? -errno : result;
6201706SN/A}
6211706SN/A
6221706SN/ASyscallReturn
62311856Sbrandon.potter@amd.comftruncateFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
6241706SN/A{
6256701Sgblack@eecs.umich.edu    int index = 0;
62611856Sbrandon.potter@amd.com    int tgt_fd = p->getSyscallArg(tc, index);
62711856Sbrandon.potter@amd.com    off_t length = p->getSyscallArg(tc, index);
6281706SN/A
62911856Sbrandon.potter@amd.com    auto ffdp = std::dynamic_pointer_cast<FileFDEntry>((*p->fds)[tgt_fd]);
63011856Sbrandon.potter@amd.com    if (!ffdp)
6311706SN/A        return -EBADF;
63211856Sbrandon.potter@amd.com    int sim_fd = ffdp->getSimFD();
6331706SN/A
63410931Sbrandon.potter@amd.com    int result = ftruncate(sim_fd, length);
6351706SN/A    return (result == -1) ? -errno : result;
6361706SN/A}
6371999SN/A
6381999SN/ASyscallReturn
6396703Svince@csl.cornell.edutruncate64Func(SyscallDesc *desc, int num,
64011851Sbrandon.potter@amd.com               Process *process, ThreadContext *tc)
6416703Svince@csl.cornell.edu{
6426703Svince@csl.cornell.edu    int index = 0;
6436703Svince@csl.cornell.edu    string path;
6446703Svince@csl.cornell.edu
6458852Sandreas.hansson@arm.com    if (!tc->getMemProxy().tryReadString(path, process->getSyscallArg(tc, index)))
64611906SBrandon.Potter@amd.com        return -EFAULT;
6476703Svince@csl.cornell.edu
6486744SAli.Saidi@arm.com    int64_t length = process->getSyscallArg(tc, index, 64);
6496703Svince@csl.cornell.edu
6506703Svince@csl.cornell.edu    // Adjust path for current working directory
6516703Svince@csl.cornell.edu    path = process->fullPath(path);
6526703Svince@csl.cornell.edu
6536744SAli.Saidi@arm.com#if NO_STAT64
6546744SAli.Saidi@arm.com    int result = truncate(path.c_str(), length);
6556744SAli.Saidi@arm.com#else
6566703Svince@csl.cornell.edu    int result = truncate64(path.c_str(), length);
6576744SAli.Saidi@arm.com#endif
6586703Svince@csl.cornell.edu    return (result == -1) ? -errno : result;
6596703Svince@csl.cornell.edu}
6606703Svince@csl.cornell.edu
6616703Svince@csl.cornell.eduSyscallReturn
66211856Sbrandon.potter@amd.comftruncate64Func(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
6636685Stjones1@inf.ed.ac.uk{
6646701Sgblack@eecs.umich.edu    int index = 0;
66511856Sbrandon.potter@amd.com    int tgt_fd = p->getSyscallArg(tc, index);
66611856Sbrandon.potter@amd.com    int64_t length = p->getSyscallArg(tc, index, 64);
6676685Stjones1@inf.ed.ac.uk
66811856Sbrandon.potter@amd.com    auto ffdp = std::dynamic_pointer_cast<FileFDEntry>((*p->fds)[tgt_fd]);
66911856Sbrandon.potter@amd.com    if (!ffdp)
6706685Stjones1@inf.ed.ac.uk        return -EBADF;
67111856Sbrandon.potter@amd.com    int sim_fd = ffdp->getSimFD();
6726685Stjones1@inf.ed.ac.uk
6736744SAli.Saidi@arm.com#if NO_STAT64
67410931Sbrandon.potter@amd.com    int result = ftruncate(sim_fd, length);
6756744SAli.Saidi@arm.com#else
67610931Sbrandon.potter@amd.com    int result = ftruncate64(sim_fd, length);
6776744SAli.Saidi@arm.com#endif
6786685Stjones1@inf.ed.ac.uk    return (result == -1) ? -errno : result;
6796685Stjones1@inf.ed.ac.uk}
6806685Stjones1@inf.ed.ac.uk
6816685Stjones1@inf.ed.ac.ukSyscallReturn
68211851Sbrandon.potter@amd.comumaskFunc(SyscallDesc *desc, int num, Process *process, ThreadContext *tc)
6835513SMichael.Adler@intel.com{
6845513SMichael.Adler@intel.com    // Letting the simulated program change the simulator's umask seems like
6855513SMichael.Adler@intel.com    // a bad idea.  Compromise by just returning the current umask but not
6865513SMichael.Adler@intel.com    // changing anything.
6875513SMichael.Adler@intel.com    mode_t oldMask = umask(0);
6885513SMichael.Adler@intel.com    umask(oldMask);
6895521Snate@binkert.org    return (int)oldMask;
6905513SMichael.Adler@intel.com}
6915513SMichael.Adler@intel.com
6925513SMichael.Adler@intel.comSyscallReturn
69311851Sbrandon.potter@amd.comchownFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
6941999SN/A{
6951999SN/A    string path;
6961999SN/A
6976701Sgblack@eecs.umich.edu    int index = 0;
6988852Sandreas.hansson@arm.com    if (!tc->getMemProxy().tryReadString(path, p->getSyscallArg(tc, index)))
6991999SN/A        return -EFAULT;
7001999SN/A
7011999SN/A    /* XXX endianess */
7026701Sgblack@eecs.umich.edu    uint32_t owner = p->getSyscallArg(tc, index);
7031999SN/A    uid_t hostOwner = owner;
7046701Sgblack@eecs.umich.edu    uint32_t group = p->getSyscallArg(tc, index);
7051999SN/A    gid_t hostGroup = group;
7061999SN/A
7073669Sbinkertn@umich.edu    // Adjust path for current working directory
7083669Sbinkertn@umich.edu    path = p->fullPath(path);
7093669Sbinkertn@umich.edu
7101999SN/A    int result = chown(path.c_str(), hostOwner, hostGroup);
7111999SN/A    return (result == -1) ? -errno : result;
7121999SN/A}
7131999SN/A
7141999SN/ASyscallReturn
71511856Sbrandon.potter@amd.comfchownFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
7161999SN/A{
7176701Sgblack@eecs.umich.edu    int index = 0;
71811856Sbrandon.potter@amd.com    int tgt_fd = p->getSyscallArg(tc, index);
7191999SN/A
72011856Sbrandon.potter@amd.com    auto ffdp = std::dynamic_pointer_cast<FileFDEntry>((*p->fds)[tgt_fd]);
72111856Sbrandon.potter@amd.com    if (!ffdp)
7221999SN/A        return -EBADF;
72311856Sbrandon.potter@amd.com    int sim_fd = ffdp->getSimFD();
7241999SN/A
7251999SN/A    /* XXX endianess */
72611856Sbrandon.potter@amd.com    uint32_t owner = p->getSyscallArg(tc, index);
7271999SN/A    uid_t hostOwner = owner;
72811856Sbrandon.potter@amd.com    uint32_t group = p->getSyscallArg(tc, index);
7291999SN/A    gid_t hostGroup = group;
7301999SN/A
73110931Sbrandon.potter@amd.com    int result = fchown(sim_fd, hostOwner, hostGroup);
7321999SN/A    return (result == -1) ? -errno : result;
7331999SN/A}
7342093SN/A
73511856Sbrandon.potter@amd.com/**
73611908SBrandon.Potter@amd.com * FIXME: The file description is not shared among file descriptors created
73711908SBrandon.Potter@amd.com * with dup. Really, it's difficult to maintain fields like file offset or
73811908SBrandon.Potter@amd.com * flags since an update to such a field won't be reflected in the metadata
73911908SBrandon.Potter@amd.com * for the fd entries that we maintain for checkpoint restoration.
74011856Sbrandon.potter@amd.com */
7412093SN/ASyscallReturn
74211856Sbrandon.potter@amd.comdupFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
7433079Sstever@eecs.umich.edu{
7446701Sgblack@eecs.umich.edu    int index = 0;
74511856Sbrandon.potter@amd.com    int tgt_fd = p->getSyscallArg(tc, index);
74610931Sbrandon.potter@amd.com
74711856Sbrandon.potter@amd.com    auto old_hbfdp = std::dynamic_pointer_cast<HBFDEntry>((*p->fds)[tgt_fd]);
74811856Sbrandon.potter@amd.com    if (!old_hbfdp)
7493079Sstever@eecs.umich.edu        return -EBADF;
75011856Sbrandon.potter@amd.com    int sim_fd = old_hbfdp->getSimFD();
7515282Srstrong@cs.ucsd.edu
75210781Snilay@cs.wisc.edu    int result = dup(sim_fd);
75311908SBrandon.Potter@amd.com    if (result == -1)
75411908SBrandon.Potter@amd.com        return -errno;
75511856Sbrandon.potter@amd.com
75611908SBrandon.Potter@amd.com    auto new_hbfdp = std::dynamic_pointer_cast<HBFDEntry>(old_hbfdp->clone());
75711856Sbrandon.potter@amd.com    new_hbfdp->setSimFD(result);
75811908SBrandon.Potter@amd.com    new_hbfdp->setCOE(false);
75911908SBrandon.Potter@amd.com    return p->fds->allocFD(new_hbfdp);
76011908SBrandon.Potter@amd.com}
76111856Sbrandon.potter@amd.com
76211908SBrandon.Potter@amd.comSyscallReturn
76311908SBrandon.Potter@amd.comdup2Func(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
76411908SBrandon.Potter@amd.com{
76511908SBrandon.Potter@amd.com    int index = 0;
76611908SBrandon.Potter@amd.com
76711908SBrandon.Potter@amd.com    int old_tgt_fd = p->getSyscallArg(tc, index);
76811908SBrandon.Potter@amd.com    auto old_hbp = std::dynamic_pointer_cast<HBFDEntry>((*p->fds)[old_tgt_fd]);
76911908SBrandon.Potter@amd.com    if (!old_hbp)
77011908SBrandon.Potter@amd.com        return -EBADF;
77111908SBrandon.Potter@amd.com    int old_sim_fd = old_hbp->getSimFD();
77211908SBrandon.Potter@amd.com
77311908SBrandon.Potter@amd.com    /**
77411908SBrandon.Potter@amd.com     * We need a valid host file descriptor number to be able to pass into
77511908SBrandon.Potter@amd.com     * the second parameter for dup2 (newfd), but we don't know what the
77611908SBrandon.Potter@amd.com     * viable numbers are; we execute the open call to retrieve one.
77711908SBrandon.Potter@amd.com     */
77811908SBrandon.Potter@amd.com    int res_fd = dup2(old_sim_fd, open("/dev/null", O_RDONLY));
77911908SBrandon.Potter@amd.com    if (res_fd == -1)
78011908SBrandon.Potter@amd.com        return -errno;
78111908SBrandon.Potter@amd.com
78211908SBrandon.Potter@amd.com    int new_tgt_fd = p->getSyscallArg(tc, index);
78311908SBrandon.Potter@amd.com    auto new_hbp = std::dynamic_pointer_cast<HBFDEntry>((*p->fds)[new_tgt_fd]);
78411908SBrandon.Potter@amd.com    if (new_hbp)
78511908SBrandon.Potter@amd.com        p->fds->closeFDEntry(new_tgt_fd);
78611908SBrandon.Potter@amd.com    new_hbp = std::dynamic_pointer_cast<HBFDEntry>(old_hbp->clone());
78711908SBrandon.Potter@amd.com    new_hbp->setSimFD(res_fd);
78811908SBrandon.Potter@amd.com    new_hbp->setCOE(false);
78911908SBrandon.Potter@amd.com
79011908SBrandon.Potter@amd.com    return p->fds->allocFD(new_hbp);
7913079Sstever@eecs.umich.edu}
7923079Sstever@eecs.umich.edu
7933079Sstever@eecs.umich.eduSyscallReturn
79411856Sbrandon.potter@amd.comfcntlFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
7952093SN/A{
79611875Sbrandon.potter@amd.com    int arg;
7976701Sgblack@eecs.umich.edu    int index = 0;
79811856Sbrandon.potter@amd.com    int tgt_fd = p->getSyscallArg(tc, index);
79911875Sbrandon.potter@amd.com    int cmd = p->getSyscallArg(tc, index);
8002093SN/A
80111856Sbrandon.potter@amd.com    auto hbfdp = std::dynamic_pointer_cast<HBFDEntry>((*p->fds)[tgt_fd]);
80211856Sbrandon.potter@amd.com    if (!hbfdp)
8032093SN/A        return -EBADF;
80411856Sbrandon.potter@amd.com    int sim_fd = hbfdp->getSimFD();
8052093SN/A
80611875Sbrandon.potter@amd.com    int coe = hbfdp->getCOE();
80711875Sbrandon.potter@amd.com
8082093SN/A    switch (cmd) {
80911875Sbrandon.potter@amd.com      case F_GETFD:
81011875Sbrandon.potter@amd.com        return coe & FD_CLOEXEC;
8112093SN/A
81211875Sbrandon.potter@amd.com      case F_SETFD: {
81311875Sbrandon.potter@amd.com        arg = p->getSyscallArg(tc, index);
81411875Sbrandon.potter@amd.com        arg ? hbfdp->setCOE(true) : hbfdp->setCOE(false);
8152093SN/A        return 0;
81611875Sbrandon.potter@amd.com      }
8172093SN/A
81811875Sbrandon.potter@amd.com      // Rely on the host to maintain the file status flags for this file
81911875Sbrandon.potter@amd.com      // description rather than maintain it ourselves. Admittedly, this
82011875Sbrandon.potter@amd.com      // is suboptimal (and possibly error prone), but it is difficult to
82111875Sbrandon.potter@amd.com      // maintain the flags by tracking them across the different descriptors
82211875Sbrandon.potter@amd.com      // (that refer to this file description) caused by clone, dup, and
82311875Sbrandon.potter@amd.com      // subsequent fcntls.
82411875Sbrandon.potter@amd.com      case F_GETFL:
82511875Sbrandon.potter@amd.com      case F_SETFL: {
82611875Sbrandon.potter@amd.com        arg = p->getSyscallArg(tc, index);
82711875Sbrandon.potter@amd.com        int rv = fcntl(sim_fd, cmd, arg);
82811875Sbrandon.potter@amd.com        return (rv == -1) ? -errno : rv;
82911875Sbrandon.potter@amd.com      }
8302093SN/A
8312093SN/A      default:
83211875Sbrandon.potter@amd.com        warn("fcntl: unsupported command %d\n", cmd);
8332093SN/A        return 0;
8342093SN/A    }
8352093SN/A}
8362093SN/A
8372238SN/ASyscallReturn
83811856Sbrandon.potter@amd.comfcntl64Func(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
8392687Sksewell@umich.edu{
8406701Sgblack@eecs.umich.edu    int index = 0;
84111856Sbrandon.potter@amd.com    int tgt_fd = p->getSyscallArg(tc, index);
8422687Sksewell@umich.edu
84311856Sbrandon.potter@amd.com    auto hbfdp = std::dynamic_pointer_cast<HBFDEntry>((*p->fds)[tgt_fd]);
84411856Sbrandon.potter@amd.com    if (!hbfdp)
8452687Sksewell@umich.edu        return -EBADF;
84611856Sbrandon.potter@amd.com    int sim_fd = hbfdp->getSimFD();
8472687Sksewell@umich.edu
84811856Sbrandon.potter@amd.com    int cmd = p->getSyscallArg(tc, index);
8492687Sksewell@umich.edu    switch (cmd) {
8502687Sksewell@umich.edu      case 33: //F_GETLK64
85110931Sbrandon.potter@amd.com        warn("fcntl64(%d, F_GETLK64) not supported, error returned\n", tgt_fd);
8522687Sksewell@umich.edu        return -EMFILE;
8532687Sksewell@umich.edu
8542687Sksewell@umich.edu      case 34: // F_SETLK64
8552687Sksewell@umich.edu      case 35: // F_SETLKW64
85610931Sbrandon.potter@amd.com        warn("fcntl64(%d, F_SETLK(W)64) not supported, error returned\n",
85710931Sbrandon.potter@amd.com             tgt_fd);
8582687Sksewell@umich.edu        return -EMFILE;
8592687Sksewell@umich.edu
8602687Sksewell@umich.edu      default:
8612687Sksewell@umich.edu        // not sure if this is totally valid, but we'll pass it through
8622687Sksewell@umich.edu        // to the underlying OS
86310931Sbrandon.potter@amd.com        warn("fcntl64(%d, %d) passed through to host\n", tgt_fd, cmd);
86410931Sbrandon.potter@amd.com        return fcntl(sim_fd, cmd);
8652687Sksewell@umich.edu    }
8662687Sksewell@umich.edu}
8672687Sksewell@umich.edu
8682687Sksewell@umich.eduSyscallReturn
86911908SBrandon.Potter@amd.compipeImpl(SyscallDesc *desc, int callnum, Process *p, ThreadContext *tc,
87011908SBrandon.Potter@amd.com         bool pseudoPipe)
8712238SN/A{
87211908SBrandon.Potter@amd.com    Addr tgt_addr = 0;
87311908SBrandon.Potter@amd.com    if (!pseudoPipe) {
87411908SBrandon.Potter@amd.com        int index = 0;
87511908SBrandon.Potter@amd.com        tgt_addr = p->getSyscallArg(tc, index);
87611908SBrandon.Potter@amd.com    }
87711908SBrandon.Potter@amd.com
87811856Sbrandon.potter@amd.com    int sim_fds[2], tgt_fds[2];
8792093SN/A
88011856Sbrandon.potter@amd.com    int pipe_retval = pipe(sim_fds);
88111908SBrandon.Potter@amd.com    if (pipe_retval == -1)
88211908SBrandon.Potter@amd.com        return -errno;
8832238SN/A
88411856Sbrandon.potter@amd.com    auto rend = PipeFDEntry::EndType::read;
88511856Sbrandon.potter@amd.com    auto rpfd = std::make_shared<PipeFDEntry>(sim_fds[0], O_WRONLY, rend);
88611908SBrandon.Potter@amd.com    tgt_fds[0] = p->fds->allocFD(rpfd);
8872238SN/A
88811856Sbrandon.potter@amd.com    auto wend = PipeFDEntry::EndType::write;
88911856Sbrandon.potter@amd.com    auto wpfd = std::make_shared<PipeFDEntry>(sim_fds[1], O_RDONLY, wend);
89011908SBrandon.Potter@amd.com    tgt_fds[1] = p->fds->allocFD(wpfd);
89111856Sbrandon.potter@amd.com
89211856Sbrandon.potter@amd.com    /**
89311856Sbrandon.potter@amd.com     * Now patch the read object to record the target file descriptor chosen
89411856Sbrandon.potter@amd.com     * as the write end of the pipe.
89511856Sbrandon.potter@amd.com     */
89611856Sbrandon.potter@amd.com    rpfd->setPipeReadSource(tgt_fds[1]);
89711856Sbrandon.potter@amd.com
89811856Sbrandon.potter@amd.com    /**
89911856Sbrandon.potter@amd.com     * Alpha Linux convention for pipe() is that fd[0] is returned as
90011856Sbrandon.potter@amd.com     * the return value of the function, and fd[1] is returned in r20.
90111856Sbrandon.potter@amd.com     */
90211908SBrandon.Potter@amd.com    if (pseudoPipe) {
90311908SBrandon.Potter@amd.com        tc->setIntReg(SyscallPseudoReturnReg, tgt_fds[1]);
90411908SBrandon.Potter@amd.com        return tgt_fds[0];
90511908SBrandon.Potter@amd.com    }
90611908SBrandon.Potter@amd.com
90711908SBrandon.Potter@amd.com    /**
90811908SBrandon.Potter@amd.com     * Copy the target file descriptors into buffer space and then copy
90911908SBrandon.Potter@amd.com     * the buffer space back into the target address space.
91011908SBrandon.Potter@amd.com     */
91111908SBrandon.Potter@amd.com    BufferArg tgt_handle(tgt_addr, sizeof(int[2]));
91211908SBrandon.Potter@amd.com    int *buf_ptr = (int*)tgt_handle.bufferPtr();
91311908SBrandon.Potter@amd.com    buf_ptr[0] = tgt_fds[0];
91411908SBrandon.Potter@amd.com    buf_ptr[1] = tgt_fds[1];
91511908SBrandon.Potter@amd.com    tgt_handle.copyOut(tc->getMemProxy());
91611908SBrandon.Potter@amd.com    return 0;
91711908SBrandon.Potter@amd.com}
91811908SBrandon.Potter@amd.com
91911908SBrandon.Potter@amd.comSyscallReturn
92011908SBrandon.Potter@amd.compipePseudoFunc(SyscallDesc *desc, int callnum, Process *process,
92111908SBrandon.Potter@amd.com               ThreadContext *tc)
92211908SBrandon.Potter@amd.com{
92311908SBrandon.Potter@amd.com    return pipeImpl(desc, callnum, process, tc, true);
92411908SBrandon.Potter@amd.com}
92511908SBrandon.Potter@amd.com
92611908SBrandon.Potter@amd.comSyscallReturn
92711908SBrandon.Potter@amd.compipeFunc(SyscallDesc *desc, int callnum, Process *process, ThreadContext *tc)
92811908SBrandon.Potter@amd.com{
92911908SBrandon.Potter@amd.com    return pipeImpl(desc, callnum, process, tc, false);
9302238SN/A}
9312238SN/A
93211885Sbrandon.potter@amd.comSyscallReturn
93311885Sbrandon.potter@amd.comsetpgidFunc(SyscallDesc *desc, int callnum, Process *process,
93411885Sbrandon.potter@amd.com            ThreadContext *tc)
93511885Sbrandon.potter@amd.com{
93611885Sbrandon.potter@amd.com    int index = 0;
93711885Sbrandon.potter@amd.com    int pid = process->getSyscallArg(tc, index);
93811885Sbrandon.potter@amd.com    int pgid = process->getSyscallArg(tc, index);
93911885Sbrandon.potter@amd.com
94011885Sbrandon.potter@amd.com    if (pgid < 0)
94111885Sbrandon.potter@amd.com        return -EINVAL;
94211885Sbrandon.potter@amd.com
94311885Sbrandon.potter@amd.com    if (pid == 0) {
94411885Sbrandon.potter@amd.com        process->setpgid(process->pid());
94511885Sbrandon.potter@amd.com        return 0;
94611885Sbrandon.potter@amd.com    }
94711885Sbrandon.potter@amd.com
94811913SBrandon.Potter@amd.com    Process *matched_ph = nullptr;
94911885Sbrandon.potter@amd.com    System *sysh = tc->getSystemPtr();
95011885Sbrandon.potter@amd.com
95111885Sbrandon.potter@amd.com    // Retrieves process pointer from active/suspended thread contexts.
95211885Sbrandon.potter@amd.com    for (int i = 0; i < sysh->numContexts(); i++) {
95311885Sbrandon.potter@amd.com        if (sysh->threadContexts[i]->status() != ThreadContext::Halted) {
95411885Sbrandon.potter@amd.com            Process *temp_h = sysh->threadContexts[i]->getProcessPtr();
95511885Sbrandon.potter@amd.com            Process *walk_ph = (Process*)temp_h;
95611885Sbrandon.potter@amd.com
95711885Sbrandon.potter@amd.com            if (walk_ph && walk_ph->pid() == process->pid())
95811885Sbrandon.potter@amd.com                matched_ph = walk_ph;
95911885Sbrandon.potter@amd.com        }
96011885Sbrandon.potter@amd.com    }
96111885Sbrandon.potter@amd.com
96211913SBrandon.Potter@amd.com    assert(matched_ph);
96311885Sbrandon.potter@amd.com    matched_ph->setpgid((pgid == 0) ? matched_ph->pid() : pgid);
96411885Sbrandon.potter@amd.com
96511885Sbrandon.potter@amd.com    return 0;
96611885Sbrandon.potter@amd.com}
9672238SN/A
9682238SN/ASyscallReturn
96911851Sbrandon.potter@amd.comgetpidPseudoFunc(SyscallDesc *desc, int callnum, Process *process,
97011851Sbrandon.potter@amd.com                 ThreadContext *tc)
9712238SN/A{
9722238SN/A    // Make up a PID.  There's no interprocess communication in
9732238SN/A    // fake_syscall mode, so there's no way for a process to know it's
9742238SN/A    // not getting a unique value.
9752238SN/A
9763114Sgblack@eecs.umich.edu    tc->setIntReg(SyscallPseudoReturnReg, process->ppid());
9773114Sgblack@eecs.umich.edu    return process->pid();
9782238SN/A}
9792238SN/A
9802238SN/A
9812238SN/ASyscallReturn
98211851Sbrandon.potter@amd.comgetuidPseudoFunc(SyscallDesc *desc, int callnum, Process *process,
98311851Sbrandon.potter@amd.com                 ThreadContext *tc)
9842238SN/A{
9852238SN/A    // Make up a UID and EUID... it shouldn't matter, and we want the
9862238SN/A    // simulation to be deterministic.
9872238SN/A
9882238SN/A    // EUID goes in r20.
98911906SBrandon.Potter@amd.com    tc->setIntReg(SyscallPseudoReturnReg, process->euid()); // EUID
99011906SBrandon.Potter@amd.com    return process->uid(); // UID
9912238SN/A}
9922238SN/A
9932238SN/A
9942238SN/ASyscallReturn
99511851Sbrandon.potter@amd.comgetgidPseudoFunc(SyscallDesc *desc, int callnum, Process *process,
99611851Sbrandon.potter@amd.com                 ThreadContext *tc)
9972238SN/A{
9982238SN/A    // Get current group ID.  EGID goes in r20.
99911906SBrandon.Potter@amd.com    tc->setIntReg(SyscallPseudoReturnReg, process->egid()); // EGID
10003114Sgblack@eecs.umich.edu    return process->gid();
10012238SN/A}
10022238SN/A
10032238SN/A
10042238SN/ASyscallReturn
100511851Sbrandon.potter@amd.comsetuidFunc(SyscallDesc *desc, int callnum, Process *process,
10062680Sktlim@umich.edu           ThreadContext *tc)
10072238SN/A{
10082238SN/A    // can't fathom why a benchmark would call this.
10096701Sgblack@eecs.umich.edu    int index = 0;
10106701Sgblack@eecs.umich.edu    warn("Ignoring call to setuid(%d)\n", process->getSyscallArg(tc, index));
10112238SN/A    return 0;
10122238SN/A}
10132238SN/A
10142238SN/ASyscallReturn
101511851Sbrandon.potter@amd.comgetpidFunc(SyscallDesc *desc, int callnum, Process *process,
10162680Sktlim@umich.edu           ThreadContext *tc)
10172238SN/A{
101811885Sbrandon.potter@amd.com    return process->tgid();
101911885Sbrandon.potter@amd.com}
10202238SN/A
102111885Sbrandon.potter@amd.comSyscallReturn
102211885Sbrandon.potter@amd.comgettidFunc(SyscallDesc *desc, int callnum, Process *process,
102311885Sbrandon.potter@amd.com           ThreadContext *tc)
102411885Sbrandon.potter@amd.com{
10253114Sgblack@eecs.umich.edu    return process->pid();
10262238SN/A}
10272238SN/A
10282238SN/ASyscallReturn
102911851Sbrandon.potter@amd.comgetppidFunc(SyscallDesc *desc, int callnum, Process *process,
103011851Sbrandon.potter@amd.com            ThreadContext *tc)
10312238SN/A{
10323114Sgblack@eecs.umich.edu    return process->ppid();
10332238SN/A}
10342238SN/A
10352238SN/ASyscallReturn
103611851Sbrandon.potter@amd.comgetuidFunc(SyscallDesc *desc, int callnum, Process *process,
10372680Sktlim@umich.edu           ThreadContext *tc)
10382238SN/A{
10395543Ssaidi@eecs.umich.edu    return process->uid();              // UID
10402238SN/A}
10412238SN/A
10422238SN/ASyscallReturn
104311851Sbrandon.potter@amd.comgeteuidFunc(SyscallDesc *desc, int callnum, Process *process,
104411851Sbrandon.potter@amd.com            ThreadContext *tc)
10452238SN/A{
10465543Ssaidi@eecs.umich.edu    return process->euid();             // UID
10472238SN/A}
10482238SN/A
10492238SN/ASyscallReturn
105011851Sbrandon.potter@amd.comgetgidFunc(SyscallDesc *desc, int callnum, Process *process,
10512680Sktlim@umich.edu           ThreadContext *tc)
10522238SN/A{
10533114Sgblack@eecs.umich.edu    return process->gid();
10542238SN/A}
10552238SN/A
10562238SN/ASyscallReturn
105711851Sbrandon.potter@amd.comgetegidFunc(SyscallDesc *desc, int callnum, Process *process,
105811851Sbrandon.potter@amd.com            ThreadContext *tc)
10592238SN/A{
10603114Sgblack@eecs.umich.edu    return process->egid();
10612238SN/A}
10622238SN/A
10639455Smitch.hayenga+gem5@gmail.comSyscallReturn
106411856Sbrandon.potter@amd.comfallocateFunc(SyscallDesc *desc, int callnum, Process *p, ThreadContext *tc)
106511760Sbrandon.potter@amd.com{
106611799Sbrandon.potter@amd.com#if NO_FALLOCATE
106711799Sbrandon.potter@amd.com    warn("Host OS cannot support calls to fallocate. Ignoring syscall");
106811799Sbrandon.potter@amd.com#else
106911760Sbrandon.potter@amd.com    int index = 0;
107011856Sbrandon.potter@amd.com    int tgt_fd = p->getSyscallArg(tc, index);
107111856Sbrandon.potter@amd.com    int mode = p->getSyscallArg(tc, index);
107211856Sbrandon.potter@amd.com    off_t offset = p->getSyscallArg(tc, index);
107311856Sbrandon.potter@amd.com    off_t len = p->getSyscallArg(tc, index);
107411760Sbrandon.potter@amd.com
107511856Sbrandon.potter@amd.com    auto ffdp = std::dynamic_pointer_cast<FileFDEntry>((*p->fds)[tgt_fd]);
107611856Sbrandon.potter@amd.com    if (!ffdp)
107711760Sbrandon.potter@amd.com        return -EBADF;
107811856Sbrandon.potter@amd.com    int sim_fd = ffdp->getSimFD();
107911760Sbrandon.potter@amd.com
108011760Sbrandon.potter@amd.com    int result = fallocate(sim_fd, mode, offset, len);
108111760Sbrandon.potter@amd.com    if (result < 0)
108211760Sbrandon.potter@amd.com        return -errno;
108311799Sbrandon.potter@amd.com#endif
108411760Sbrandon.potter@amd.com    return 0;
108511760Sbrandon.potter@amd.com}
108611760Sbrandon.potter@amd.com
108711760Sbrandon.potter@amd.comSyscallReturn
108811851Sbrandon.potter@amd.comaccessFunc(SyscallDesc *desc, int callnum, Process *p, ThreadContext *tc,
108911851Sbrandon.potter@amd.com           int index)
10909455Smitch.hayenga+gem5@gmail.com{
10919455Smitch.hayenga+gem5@gmail.com    string path;
10929455Smitch.hayenga+gem5@gmail.com    if (!tc->getMemProxy().tryReadString(path, p->getSyscallArg(tc, index)))
109310223Ssteve.reinhardt@amd.com        return -EFAULT;
10949455Smitch.hayenga+gem5@gmail.com
10959455Smitch.hayenga+gem5@gmail.com    // Adjust path for current working directory
10969455Smitch.hayenga+gem5@gmail.com    path = p->fullPath(path);
10979455Smitch.hayenga+gem5@gmail.com
10989455Smitch.hayenga+gem5@gmail.com    mode_t mode = p->getSyscallArg(tc, index);
10999455Smitch.hayenga+gem5@gmail.com
11009455Smitch.hayenga+gem5@gmail.com    int result = access(path.c_str(), mode);
11019455Smitch.hayenga+gem5@gmail.com    return (result == -1) ? -errno : result;
11029455Smitch.hayenga+gem5@gmail.com}
110310203SAli.Saidi@ARM.com
110410203SAli.Saidi@ARM.comSyscallReturn
110511851Sbrandon.potter@amd.comaccessFunc(SyscallDesc *desc, int callnum, Process *p, ThreadContext *tc)
110610203SAli.Saidi@ARM.com{
110710203SAli.Saidi@ARM.com    return accessFunc(desc, callnum, p, tc, 0);
110810203SAli.Saidi@ARM.com}
110910203SAli.Saidi@ARM.com
111013031Sbrandon.potter@amd.comSyscallReturn
111113031Sbrandon.potter@amd.commknodFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
111213031Sbrandon.potter@amd.com{
111313031Sbrandon.potter@amd.com    int index = 0;
111413031Sbrandon.potter@amd.com    std::string path;
111513031Sbrandon.potter@amd.com    if (!tc->getMemProxy().tryReadString(path, p->getSyscallArg(tc, index)))
111613031Sbrandon.potter@amd.com        return -EFAULT;
111713031Sbrandon.potter@amd.com
111813031Sbrandon.potter@amd.com    path = p->fullPath(path);
111913031Sbrandon.potter@amd.com    mode_t mode = p->getSyscallArg(tc, index);
112013031Sbrandon.potter@amd.com    dev_t dev = p->getSyscallArg(tc, index);
112113031Sbrandon.potter@amd.com
112213031Sbrandon.potter@amd.com    auto result = mknod(path.c_str(), mode, dev);
112313031Sbrandon.potter@amd.com    return (result == -1) ? -errno : result;
112413031Sbrandon.potter@amd.com}
112513031Sbrandon.potter@amd.com
112613031Sbrandon.potter@amd.comSyscallReturn
112713031Sbrandon.potter@amd.comchdirFunc(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
113413031Sbrandon.potter@amd.com    path = p->fullPath(path);
113513031Sbrandon.potter@amd.com
113613031Sbrandon.potter@amd.com    auto result = chdir(path.c_str());
113713031Sbrandon.potter@amd.com    return (result == -1) ? -errno : result;
113813031Sbrandon.potter@amd.com}
113913031Sbrandon.potter@amd.com
114013031Sbrandon.potter@amd.comSyscallReturn
114113031Sbrandon.potter@amd.comrmdirFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
114213031Sbrandon.potter@amd.com{
114313031Sbrandon.potter@amd.com    int index = 0;
114413031Sbrandon.potter@amd.com    std::string path;
114513031Sbrandon.potter@amd.com    if (!tc->getMemProxy().tryReadString(path, p->getSyscallArg(tc, index)))
114613031Sbrandon.potter@amd.com        return -EFAULT;
114713031Sbrandon.potter@amd.com
114813031Sbrandon.potter@amd.com    path = p->fullPath(path);
114913031Sbrandon.potter@amd.com
115013031Sbrandon.potter@amd.com    auto result = rmdir(path.c_str());
115113031Sbrandon.potter@amd.com    return (result == -1) ? -errno : result;
115213031Sbrandon.potter@amd.com}
115313031Sbrandon.potter@amd.com
115413539Sjavier.setoain@arm.com#if defined(SYS_getdents) || defined(SYS_getdents64)
115513539Sjavier.setoain@arm.comtemplate<typename DE, int SYS_NUM>
115613539Sjavier.setoain@arm.comstatic SyscallReturn
115713539Sjavier.setoain@arm.comgetdentsImpl(SyscallDesc *desc, int callnum, Process *p, ThreadContext *tc)
115813031Sbrandon.potter@amd.com{
115913031Sbrandon.potter@amd.com    int index = 0;
116013031Sbrandon.potter@amd.com    int tgt_fd = p->getSyscallArg(tc, index);
116113031Sbrandon.potter@amd.com    Addr buf_ptr = p->getSyscallArg(tc, index);
116213031Sbrandon.potter@amd.com    unsigned count = p->getSyscallArg(tc, index);
116313031Sbrandon.potter@amd.com
116413031Sbrandon.potter@amd.com    auto hbfdp = std::dynamic_pointer_cast<HBFDEntry>((*p->fds)[tgt_fd]);
116513031Sbrandon.potter@amd.com    if (!hbfdp)
116613031Sbrandon.potter@amd.com        return -EBADF;
116713031Sbrandon.potter@amd.com    int sim_fd = hbfdp->getSimFD();
116813031Sbrandon.potter@amd.com
116913031Sbrandon.potter@amd.com    BufferArg buf_arg(buf_ptr, count);
117013539Sjavier.setoain@arm.com    auto status = syscall(SYS_NUM, sim_fd, buf_arg.bufferPtr(), count);
117113031Sbrandon.potter@amd.com
117213031Sbrandon.potter@amd.com    if (status == -1)
117313031Sbrandon.potter@amd.com        return -errno;
117413031Sbrandon.potter@amd.com
117513031Sbrandon.potter@amd.com    unsigned traversed = 0;
117613031Sbrandon.potter@amd.com    while (traversed < status) {
117713539Sjavier.setoain@arm.com        DE *buffer = (DE*)((Addr)buf_arg.bufferPtr() + traversed);
117813031Sbrandon.potter@amd.com
117913031Sbrandon.potter@amd.com        auto host_reclen = buffer->d_reclen;
118013031Sbrandon.potter@amd.com
118113031Sbrandon.potter@amd.com        /**
118213031Sbrandon.potter@amd.com         * Convert the byte ordering from the host to the target before
118313031Sbrandon.potter@amd.com         * passing the data back into the target's address space to preserve
118413031Sbrandon.potter@amd.com         * endianness.
118513031Sbrandon.potter@amd.com         */
118613031Sbrandon.potter@amd.com        buffer->d_ino = htog(buffer->d_ino);
118713031Sbrandon.potter@amd.com        buffer->d_off = htog(buffer->d_off);
118813031Sbrandon.potter@amd.com        buffer->d_reclen = htog(buffer->d_reclen);
118913031Sbrandon.potter@amd.com
119013031Sbrandon.potter@amd.com        traversed += host_reclen;
119113031Sbrandon.potter@amd.com    }
119213031Sbrandon.potter@amd.com
119313031Sbrandon.potter@amd.com    buf_arg.copyOut(tc->getMemProxy());
119413031Sbrandon.potter@amd.com    return status;
119513031Sbrandon.potter@amd.com}
119613448Sciro.santilli@arm.com#endif
119713539Sjavier.setoain@arm.com
119813539Sjavier.setoain@arm.com#if defined(SYS_getdents)
119913539Sjavier.setoain@arm.comSyscallReturn
120013539Sjavier.setoain@arm.comgetdentsFunc(SyscallDesc *desc, int callnum, Process *p, ThreadContext *tc)
120113539Sjavier.setoain@arm.com{
120213539Sjavier.setoain@arm.com    typedef struct linux_dirent {
120313539Sjavier.setoain@arm.com        unsigned long d_ino;
120413539Sjavier.setoain@arm.com        unsigned long d_off;
120513539Sjavier.setoain@arm.com        unsigned short d_reclen;
120613539Sjavier.setoain@arm.com        char dname[];
120713539Sjavier.setoain@arm.com    } LinDent;
120813539Sjavier.setoain@arm.com
120913539Sjavier.setoain@arm.com    return getdentsImpl<LinDent, SYS_getdents>(desc, callnum, p, tc);
121013539Sjavier.setoain@arm.com}
121113539Sjavier.setoain@arm.com#endif
121213539Sjavier.setoain@arm.com
121313539Sjavier.setoain@arm.com#if defined(SYS_getdents64)
121413539Sjavier.setoain@arm.comSyscallReturn
121513539Sjavier.setoain@arm.comgetdents64Func(SyscallDesc *desc, int callnum, Process *p, ThreadContext *tc)
121613539Sjavier.setoain@arm.com{
121713539Sjavier.setoain@arm.com    typedef struct linux_dirent64 {
121813539Sjavier.setoain@arm.com        ino64_t d_ino;
121913539Sjavier.setoain@arm.com        off64_t d_off;
122013539Sjavier.setoain@arm.com        unsigned short d_reclen;
122113539Sjavier.setoain@arm.com        char dname[];
122213539Sjavier.setoain@arm.com    } LinDent64;
122313539Sjavier.setoain@arm.com
122413539Sjavier.setoain@arm.com    return getdentsImpl<LinDent64, SYS_getdents64>(desc, callnum, p, tc);
122513539Sjavier.setoain@arm.com}
122613539Sjavier.setoain@arm.com#endif
122713568Sbrandon.potter@amd.com
122813568Sbrandon.potter@amd.comSyscallReturn
122913568Sbrandon.potter@amd.comshutdownFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
123013568Sbrandon.potter@amd.com{
123113568Sbrandon.potter@amd.com    int index = 0;
123213568Sbrandon.potter@amd.com    int tgt_fd = p->getSyscallArg(tc, index);
123313568Sbrandon.potter@amd.com    int how = p->getSyscallArg(tc, index);
123413568Sbrandon.potter@amd.com
123513568Sbrandon.potter@amd.com    auto sfdp = std::dynamic_pointer_cast<SocketFDEntry>((*p->fds)[tgt_fd]);
123613568Sbrandon.potter@amd.com    if (!sfdp)
123713568Sbrandon.potter@amd.com        return -EBADF;
123813568Sbrandon.potter@amd.com    int sim_fd = sfdp->getSimFD();
123913568Sbrandon.potter@amd.com
124013568Sbrandon.potter@amd.com    int retval = shutdown(sim_fd, how);
124113568Sbrandon.potter@amd.com
124213568Sbrandon.potter@amd.com    return (retval == -1) ? -errno : retval;
124313568Sbrandon.potter@amd.com}
124413568Sbrandon.potter@amd.com
124513568Sbrandon.potter@amd.comSyscallReturn
124613568Sbrandon.potter@amd.combindFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
124713568Sbrandon.potter@amd.com{
124813568Sbrandon.potter@amd.com    int index = 0;
124913568Sbrandon.potter@amd.com    int tgt_fd = p->getSyscallArg(tc, index);
125013568Sbrandon.potter@amd.com    Addr buf_ptr = p->getSyscallArg(tc, index);
125113568Sbrandon.potter@amd.com    int addrlen = p->getSyscallArg(tc, index);
125213568Sbrandon.potter@amd.com
125313568Sbrandon.potter@amd.com    BufferArg bufSock(buf_ptr, addrlen);
125413568Sbrandon.potter@amd.com    bufSock.copyIn(tc->getMemProxy());
125513568Sbrandon.potter@amd.com
125613568Sbrandon.potter@amd.com    auto sfdp = std::dynamic_pointer_cast<SocketFDEntry>((*p->fds)[tgt_fd]);
125713568Sbrandon.potter@amd.com    if (!sfdp)
125813568Sbrandon.potter@amd.com        return -EBADF;
125913568Sbrandon.potter@amd.com    int sim_fd = sfdp->getSimFD();
126013568Sbrandon.potter@amd.com
126113568Sbrandon.potter@amd.com    int status = ::bind(sim_fd,
126213568Sbrandon.potter@amd.com                        (struct sockaddr *)bufSock.bufferPtr(),
126313568Sbrandon.potter@amd.com                        addrlen);
126413568Sbrandon.potter@amd.com
126513568Sbrandon.potter@amd.com    return (status == -1) ? -errno : status;
126613568Sbrandon.potter@amd.com}
126713568Sbrandon.potter@amd.com
126813568Sbrandon.potter@amd.comSyscallReturn
126913568Sbrandon.potter@amd.comlistenFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
127013568Sbrandon.potter@amd.com{
127113568Sbrandon.potter@amd.com    int index = 0;
127213568Sbrandon.potter@amd.com    int tgt_fd = p->getSyscallArg(tc, index);
127313568Sbrandon.potter@amd.com    int backlog = p->getSyscallArg(tc, index);
127413568Sbrandon.potter@amd.com
127513568Sbrandon.potter@amd.com    auto sfdp = std::dynamic_pointer_cast<SocketFDEntry>((*p->fds)[tgt_fd]);
127613568Sbrandon.potter@amd.com    if (!sfdp)
127713568Sbrandon.potter@amd.com        return -EBADF;
127813568Sbrandon.potter@amd.com    int sim_fd = sfdp->getSimFD();
127913568Sbrandon.potter@amd.com
128013568Sbrandon.potter@amd.com    int status = listen(sim_fd, backlog);
128113568Sbrandon.potter@amd.com
128213568Sbrandon.potter@amd.com    return (status == -1) ? -errno : status;
128313568Sbrandon.potter@amd.com}
128413568Sbrandon.potter@amd.com
128513568Sbrandon.potter@amd.comSyscallReturn
128613568Sbrandon.potter@amd.comconnectFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
128713568Sbrandon.potter@amd.com{
128813568Sbrandon.potter@amd.com    int index = 0;
128913568Sbrandon.potter@amd.com    int tgt_fd = p->getSyscallArg(tc, index);
129013568Sbrandon.potter@amd.com    Addr buf_ptr = p->getSyscallArg(tc, index);
129113568Sbrandon.potter@amd.com    int addrlen = p->getSyscallArg(tc, index);
129213568Sbrandon.potter@amd.com
129313568Sbrandon.potter@amd.com    BufferArg addr(buf_ptr, addrlen);
129413568Sbrandon.potter@amd.com    addr.copyIn(tc->getMemProxy());
129513568Sbrandon.potter@amd.com
129613568Sbrandon.potter@amd.com    auto sfdp = std::dynamic_pointer_cast<SocketFDEntry>((*p->fds)[tgt_fd]);
129713568Sbrandon.potter@amd.com    if (!sfdp)
129813568Sbrandon.potter@amd.com        return -EBADF;
129913568Sbrandon.potter@amd.com    int sim_fd = sfdp->getSimFD();
130013568Sbrandon.potter@amd.com
130113568Sbrandon.potter@amd.com    int status = connect(sim_fd,
130213568Sbrandon.potter@amd.com                         (struct sockaddr *)addr.bufferPtr(),
130313568Sbrandon.potter@amd.com                         (socklen_t)addrlen);
130413568Sbrandon.potter@amd.com
130513568Sbrandon.potter@amd.com    return (status == -1) ? -errno : status;
130613568Sbrandon.potter@amd.com}
130713569Sbrandon.potter@amd.com
130813569Sbrandon.potter@amd.comSyscallReturn
130913569Sbrandon.potter@amd.comrecvfromFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
131013569Sbrandon.potter@amd.com{
131113569Sbrandon.potter@amd.com    int index = 0;
131213569Sbrandon.potter@amd.com    int tgt_fd = p->getSyscallArg(tc, index);
131313569Sbrandon.potter@amd.com    Addr bufrPtr = p->getSyscallArg(tc, index);
131413569Sbrandon.potter@amd.com    size_t bufrLen = p->getSyscallArg(tc, index);
131513569Sbrandon.potter@amd.com    int flags = p->getSyscallArg(tc, index);
131613569Sbrandon.potter@amd.com    Addr addrPtr = p->getSyscallArg(tc, index);
131713569Sbrandon.potter@amd.com    Addr addrlenPtr = p->getSyscallArg(tc, index);
131813569Sbrandon.potter@amd.com
131913569Sbrandon.potter@amd.com    auto sfdp = std::dynamic_pointer_cast<SocketFDEntry>((*p->fds)[tgt_fd]);
132013569Sbrandon.potter@amd.com    if (!sfdp)
132113569Sbrandon.potter@amd.com        return -EBADF;
132213569Sbrandon.potter@amd.com    int sim_fd = sfdp->getSimFD();
132313569Sbrandon.potter@amd.com
132413569Sbrandon.potter@amd.com    // Reserve buffer space.
132513569Sbrandon.potter@amd.com    BufferArg bufrBuf(bufrPtr, bufrLen);
132613569Sbrandon.potter@amd.com
132713569Sbrandon.potter@amd.com    // Get address length.
132813569Sbrandon.potter@amd.com    socklen_t addrLen = 0;
132913569Sbrandon.potter@amd.com    if (addrlenPtr != 0) {
133013569Sbrandon.potter@amd.com        // Read address length parameter.
133113569Sbrandon.potter@amd.com        BufferArg addrlenBuf(addrlenPtr, sizeof(socklen_t));
133213569Sbrandon.potter@amd.com        addrlenBuf.copyIn(tc->getMemProxy());
133313569Sbrandon.potter@amd.com        addrLen = *((socklen_t *)addrlenBuf.bufferPtr());
133413569Sbrandon.potter@amd.com    }
133513569Sbrandon.potter@amd.com
133613569Sbrandon.potter@amd.com    struct sockaddr sa, *sap = NULL;
133713569Sbrandon.potter@amd.com    if (addrLen != 0) {
133813569Sbrandon.potter@amd.com        BufferArg addrBuf(addrPtr, addrLen);
133913569Sbrandon.potter@amd.com        addrBuf.copyIn(tc->getMemProxy());
134013569Sbrandon.potter@amd.com        memcpy(&sa, (struct sockaddr *)addrBuf.bufferPtr(),
134113569Sbrandon.potter@amd.com               sizeof(struct sockaddr));
134213569Sbrandon.potter@amd.com        sap = &sa;
134313569Sbrandon.potter@amd.com    }
134413569Sbrandon.potter@amd.com
134513569Sbrandon.potter@amd.com    ssize_t recvd_size = recvfrom(sim_fd,
134613569Sbrandon.potter@amd.com                                  (void *)bufrBuf.bufferPtr(),
134713569Sbrandon.potter@amd.com                                  bufrLen, flags, sap, (socklen_t *)&addrLen);
134813569Sbrandon.potter@amd.com
134913569Sbrandon.potter@amd.com    if (recvd_size == -1)
135013569Sbrandon.potter@amd.com        return -errno;
135113569Sbrandon.potter@amd.com
135213569Sbrandon.potter@amd.com    // Pass the received data out.
135313569Sbrandon.potter@amd.com    bufrBuf.copyOut(tc->getMemProxy());
135413569Sbrandon.potter@amd.com
135513569Sbrandon.potter@amd.com    // Copy address to addrPtr and pass it on.
135613569Sbrandon.potter@amd.com    if (sap != NULL) {
135713569Sbrandon.potter@amd.com        BufferArg addrBuf(addrPtr, addrLen);
135813569Sbrandon.potter@amd.com        memcpy(addrBuf.bufferPtr(), sap, sizeof(sa));
135913569Sbrandon.potter@amd.com        addrBuf.copyOut(tc->getMemProxy());
136013569Sbrandon.potter@amd.com    }
136113569Sbrandon.potter@amd.com
136213569Sbrandon.potter@amd.com    // Copy len to addrlenPtr and pass it on.
136313569Sbrandon.potter@amd.com    if (addrLen != 0) {
136413569Sbrandon.potter@amd.com        BufferArg addrlenBuf(addrlenPtr, sizeof(socklen_t));
136513569Sbrandon.potter@amd.com        *(socklen_t *)addrlenBuf.bufferPtr() = addrLen;
136613569Sbrandon.potter@amd.com        addrlenBuf.copyOut(tc->getMemProxy());
136713569Sbrandon.potter@amd.com    }
136813569Sbrandon.potter@amd.com
136913569Sbrandon.potter@amd.com    return recvd_size;
137013569Sbrandon.potter@amd.com}
137113569Sbrandon.potter@amd.com
137213569Sbrandon.potter@amd.comSyscallReturn
137313569Sbrandon.potter@amd.comsendtoFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
137413569Sbrandon.potter@amd.com{
137513569Sbrandon.potter@amd.com    int index = 0;
137613569Sbrandon.potter@amd.com    int tgt_fd = p->getSyscallArg(tc, index);
137713569Sbrandon.potter@amd.com    Addr bufrPtr = p->getSyscallArg(tc, index);
137813569Sbrandon.potter@amd.com    size_t bufrLen = p->getSyscallArg(tc, index);
137913569Sbrandon.potter@amd.com    int flags = p->getSyscallArg(tc, index);
138013569Sbrandon.potter@amd.com    Addr addrPtr = p->getSyscallArg(tc, index);
138113569Sbrandon.potter@amd.com    socklen_t addrLen = p->getSyscallArg(tc, index);
138213569Sbrandon.potter@amd.com
138313569Sbrandon.potter@amd.com    auto sfdp = std::dynamic_pointer_cast<SocketFDEntry>((*p->fds)[tgt_fd]);
138413569Sbrandon.potter@amd.com    if (!sfdp)
138513569Sbrandon.potter@amd.com        return -EBADF;
138613569Sbrandon.potter@amd.com    int sim_fd = sfdp->getSimFD();
138713569Sbrandon.potter@amd.com
138813569Sbrandon.potter@amd.com    // Reserve buffer space.
138913569Sbrandon.potter@amd.com    BufferArg bufrBuf(bufrPtr, bufrLen);
139013569Sbrandon.potter@amd.com    bufrBuf.copyIn(tc->getMemProxy());
139113569Sbrandon.potter@amd.com
139213569Sbrandon.potter@amd.com    struct sockaddr sa, *sap = nullptr;
139313569Sbrandon.potter@amd.com    memset(&sa, 0, sizeof(sockaddr));
139413569Sbrandon.potter@amd.com    if (addrLen != 0) {
139513569Sbrandon.potter@amd.com        BufferArg addrBuf(addrPtr, addrLen);
139613569Sbrandon.potter@amd.com        addrBuf.copyIn(tc->getMemProxy());
139713569Sbrandon.potter@amd.com        memcpy(&sa, (sockaddr*)addrBuf.bufferPtr(), addrLen);
139813569Sbrandon.potter@amd.com        sap = &sa;
139913569Sbrandon.potter@amd.com    }
140013569Sbrandon.potter@amd.com
140113569Sbrandon.potter@amd.com    ssize_t sent_size = sendto(sim_fd,
140213569Sbrandon.potter@amd.com                               (void *)bufrBuf.bufferPtr(),
140313569Sbrandon.potter@amd.com                               bufrLen, flags, sap, (socklen_t)addrLen);
140413569Sbrandon.potter@amd.com
140513569Sbrandon.potter@amd.com    return (sent_size == -1) ? -errno : sent_size;
140613569Sbrandon.potter@amd.com}
140713569Sbrandon.potter@amd.com
140813569Sbrandon.potter@amd.comSyscallReturn
140913569Sbrandon.potter@amd.comrecvmsgFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
141013569Sbrandon.potter@amd.com{
141113569Sbrandon.potter@amd.com    int index = 0;
141213569Sbrandon.potter@amd.com    int tgt_fd = p->getSyscallArg(tc, index);
141313569Sbrandon.potter@amd.com    Addr msgPtr = p->getSyscallArg(tc, index);
141413569Sbrandon.potter@amd.com    int flags = p->getSyscallArg(tc, index);
141513569Sbrandon.potter@amd.com
141613569Sbrandon.potter@amd.com    auto sfdp = std::dynamic_pointer_cast<SocketFDEntry>((*p->fds)[tgt_fd]);
141713569Sbrandon.potter@amd.com    if (!sfdp)
141813569Sbrandon.potter@amd.com        return -EBADF;
141913569Sbrandon.potter@amd.com    int sim_fd = sfdp->getSimFD();
142013569Sbrandon.potter@amd.com
142113569Sbrandon.potter@amd.com     /**
142213569Sbrandon.potter@amd.com      *  struct msghdr {
142313569Sbrandon.potter@amd.com      *     void         *msg_name;       // optional address
142413569Sbrandon.potter@amd.com      *    socklen_t     msg_namelen;    // size of address
142513569Sbrandon.potter@amd.com      *    struct iovec *msg_iov;        // iovec array
142613569Sbrandon.potter@amd.com      *    size_t        msg_iovlen;     // number entries in msg_iov
142713569Sbrandon.potter@amd.com      *    i                             // entries correspond to buffer
142813569Sbrandon.potter@amd.com      *    void         *msg_control;    // ancillary data
142913569Sbrandon.potter@amd.com      *    size_t        msg_controllen; // ancillary data buffer len
143013569Sbrandon.potter@amd.com      *    int           msg_flags;      // flags on received message
143113569Sbrandon.potter@amd.com      *  };
143213569Sbrandon.potter@amd.com      *
143313569Sbrandon.potter@amd.com      *  struct iovec {
143413569Sbrandon.potter@amd.com      *    void  *iov_base;              // starting address
143513569Sbrandon.potter@amd.com      *    size_t iov_len;               // number of bytes to transfer
143613569Sbrandon.potter@amd.com      *  };
143713569Sbrandon.potter@amd.com      */
143813569Sbrandon.potter@amd.com
143913569Sbrandon.potter@amd.com    /**
144013569Sbrandon.potter@amd.com     * The plan with this system call is to replace all of the pointers in the
144113569Sbrandon.potter@amd.com     * structure and the substructure with BufferArg class pointers. We will
144213569Sbrandon.potter@amd.com     * copy every field from the structures into our BufferArg classes.
144313569Sbrandon.potter@amd.com     */
144413569Sbrandon.potter@amd.com    BufferArg msgBuf(msgPtr, sizeof(struct msghdr));
144513569Sbrandon.potter@amd.com    msgBuf.copyIn(tc->getMemProxy());
144613569Sbrandon.potter@amd.com    struct msghdr *msgHdr = (struct msghdr *)msgBuf.bufferPtr();
144713569Sbrandon.potter@amd.com
144813569Sbrandon.potter@amd.com    /**
144913569Sbrandon.potter@amd.com     * We will use these address place holders to retain the pointers which
145013569Sbrandon.potter@amd.com     * we are going to replace with our own buffers in our simulator address
145113569Sbrandon.potter@amd.com     * space.
145213569Sbrandon.potter@amd.com     */
145313569Sbrandon.potter@amd.com    Addr msg_name_phold = 0;
145413569Sbrandon.potter@amd.com    Addr msg_iov_phold = 0;
145513569Sbrandon.potter@amd.com    Addr iovec_base_phold[msgHdr->msg_iovlen];
145613569Sbrandon.potter@amd.com    Addr msg_control_phold = 0;
145713569Sbrandon.potter@amd.com
145813569Sbrandon.potter@amd.com    /**
145913569Sbrandon.potter@amd.com     * Record msg_name pointer then replace with buffer pointer.
146013569Sbrandon.potter@amd.com     */
146113569Sbrandon.potter@amd.com    BufferArg *nameBuf = NULL;
146213569Sbrandon.potter@amd.com    if (msgHdr->msg_name) {
146313569Sbrandon.potter@amd.com        /*1*/msg_name_phold = (Addr)msgHdr->msg_name;
146413569Sbrandon.potter@amd.com        /*2*/nameBuf = new BufferArg(msg_name_phold, msgHdr->msg_namelen);
146513569Sbrandon.potter@amd.com        /*3*/nameBuf->copyIn(tc->getMemProxy());
146613569Sbrandon.potter@amd.com        /*4*/msgHdr->msg_name = nameBuf->bufferPtr();
146713569Sbrandon.potter@amd.com    }
146813569Sbrandon.potter@amd.com
146913569Sbrandon.potter@amd.com    /**
147013569Sbrandon.potter@amd.com     * Record msg_iov pointer then replace with buffer pointer. Also, setup
147113569Sbrandon.potter@amd.com     * an array of buffer pointers for the iovec structs record and replace
147213569Sbrandon.potter@amd.com     * their pointers with buffer pointers.
147313569Sbrandon.potter@amd.com     */
147413569Sbrandon.potter@amd.com    BufferArg *iovBuf = NULL;
147513569Sbrandon.potter@amd.com    BufferArg *iovecBuf[msgHdr->msg_iovlen];
147613569Sbrandon.potter@amd.com    for (int i = 0; i < msgHdr->msg_iovlen; i++) {
147713569Sbrandon.potter@amd.com        iovec_base_phold[i] = 0;
147813569Sbrandon.potter@amd.com        iovecBuf[i] = NULL;
147913569Sbrandon.potter@amd.com    }
148013569Sbrandon.potter@amd.com
148113569Sbrandon.potter@amd.com    if (msgHdr->msg_iov) {
148213569Sbrandon.potter@amd.com        /*1*/msg_iov_phold = (Addr)msgHdr->msg_iov;
148313569Sbrandon.potter@amd.com        /*2*/iovBuf = new BufferArg(msg_iov_phold, msgHdr->msg_iovlen *
148413569Sbrandon.potter@amd.com                                    sizeof(struct iovec));
148513569Sbrandon.potter@amd.com        /*3*/iovBuf->copyIn(tc->getMemProxy());
148613569Sbrandon.potter@amd.com        for (int i = 0; i < msgHdr->msg_iovlen; i++) {
148713569Sbrandon.potter@amd.com            if (((struct iovec *)iovBuf->bufferPtr())[i].iov_base) {
148813569Sbrandon.potter@amd.com                /*1*/iovec_base_phold[i] =
148913569Sbrandon.potter@amd.com                     (Addr)((struct iovec *)iovBuf->bufferPtr())[i].iov_base;
149013569Sbrandon.potter@amd.com                /*2*/iovecBuf[i] = new BufferArg(iovec_base_phold[i],
149113569Sbrandon.potter@amd.com                     ((struct iovec *)iovBuf->bufferPtr())[i].iov_len);
149213569Sbrandon.potter@amd.com                /*3*/iovecBuf[i]->copyIn(tc->getMemProxy());
149313569Sbrandon.potter@amd.com                /*4*/((struct iovec *)iovBuf->bufferPtr())[i].iov_base =
149413569Sbrandon.potter@amd.com                     iovecBuf[i]->bufferPtr();
149513569Sbrandon.potter@amd.com            }
149613569Sbrandon.potter@amd.com        }
149713569Sbrandon.potter@amd.com        /*4*/msgHdr->msg_iov = (struct iovec *)iovBuf->bufferPtr();
149813569Sbrandon.potter@amd.com    }
149913569Sbrandon.potter@amd.com
150013569Sbrandon.potter@amd.com    /**
150113569Sbrandon.potter@amd.com     * Record msg_control pointer then replace with buffer pointer.
150213569Sbrandon.potter@amd.com     */
150313569Sbrandon.potter@amd.com    BufferArg *controlBuf = NULL;
150413569Sbrandon.potter@amd.com    if (msgHdr->msg_control) {
150513569Sbrandon.potter@amd.com        /*1*/msg_control_phold = (Addr)msgHdr->msg_control;
150613569Sbrandon.potter@amd.com        /*2*/controlBuf = new BufferArg(msg_control_phold,
150713569Sbrandon.potter@amd.com                                        CMSG_ALIGN(msgHdr->msg_controllen));
150813569Sbrandon.potter@amd.com        /*3*/controlBuf->copyIn(tc->getMemProxy());
150913569Sbrandon.potter@amd.com        /*4*/msgHdr->msg_control = controlBuf->bufferPtr();
151013569Sbrandon.potter@amd.com    }
151113569Sbrandon.potter@amd.com
151213569Sbrandon.potter@amd.com    ssize_t recvd_size = recvmsg(sim_fd, msgHdr, flags);
151313569Sbrandon.potter@amd.com
151413569Sbrandon.potter@amd.com    if (recvd_size < 0)
151513569Sbrandon.potter@amd.com        return -errno;
151613569Sbrandon.potter@amd.com
151713569Sbrandon.potter@amd.com    if (msgHdr->msg_name) {
151813569Sbrandon.potter@amd.com        nameBuf->copyOut(tc->getMemProxy());
151913569Sbrandon.potter@amd.com        delete(nameBuf);
152013569Sbrandon.potter@amd.com        msgHdr->msg_name = (void *)msg_name_phold;
152113569Sbrandon.potter@amd.com    }
152213569Sbrandon.potter@amd.com
152313569Sbrandon.potter@amd.com    if (msgHdr->msg_iov) {
152413569Sbrandon.potter@amd.com        for (int i = 0; i< msgHdr->msg_iovlen; i++) {
152513569Sbrandon.potter@amd.com            if (((struct iovec *)iovBuf->bufferPtr())[i].iov_base) {
152613569Sbrandon.potter@amd.com                iovecBuf[i]->copyOut(tc->getMemProxy());
152713569Sbrandon.potter@amd.com                delete iovecBuf[i];
152813569Sbrandon.potter@amd.com                ((struct iovec *)iovBuf->bufferPtr())[i].iov_base =
152913569Sbrandon.potter@amd.com                (void *)iovec_base_phold[i];
153013569Sbrandon.potter@amd.com            }
153113569Sbrandon.potter@amd.com        }
153213569Sbrandon.potter@amd.com        iovBuf->copyOut(tc->getMemProxy());
153313569Sbrandon.potter@amd.com        delete iovBuf;
153413569Sbrandon.potter@amd.com        msgHdr->msg_iov = (struct iovec *)msg_iov_phold;
153513569Sbrandon.potter@amd.com    }
153613569Sbrandon.potter@amd.com
153713569Sbrandon.potter@amd.com    if (msgHdr->msg_control) {
153813569Sbrandon.potter@amd.com        controlBuf->copyOut(tc->getMemProxy());
153913569Sbrandon.potter@amd.com        delete(controlBuf);
154013569Sbrandon.potter@amd.com        msgHdr->msg_control = (void *)msg_control_phold;
154113569Sbrandon.potter@amd.com    }
154213569Sbrandon.potter@amd.com
154313569Sbrandon.potter@amd.com    msgBuf.copyOut(tc->getMemProxy());
154413569Sbrandon.potter@amd.com
154513569Sbrandon.potter@amd.com    return recvd_size;
154613569Sbrandon.potter@amd.com}
154713569Sbrandon.potter@amd.com
154813569Sbrandon.potter@amd.comSyscallReturn
154913569Sbrandon.potter@amd.comsendmsgFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
155013569Sbrandon.potter@amd.com{
155113569Sbrandon.potter@amd.com    int index = 0;
155213569Sbrandon.potter@amd.com    int tgt_fd = p->getSyscallArg(tc, index);
155313569Sbrandon.potter@amd.com    Addr msgPtr = p->getSyscallArg(tc, index);
155413569Sbrandon.potter@amd.com    int flags = p->getSyscallArg(tc, index);
155513569Sbrandon.potter@amd.com
155613569Sbrandon.potter@amd.com    auto sfdp = std::dynamic_pointer_cast<SocketFDEntry>((*p->fds)[tgt_fd]);
155713569Sbrandon.potter@amd.com    if (!sfdp)
155813569Sbrandon.potter@amd.com        return -EBADF;
155913569Sbrandon.potter@amd.com    int sim_fd = sfdp->getSimFD();
156013569Sbrandon.potter@amd.com
156113569Sbrandon.potter@amd.com    /**
156213569Sbrandon.potter@amd.com     * Reserve buffer space.
156313569Sbrandon.potter@amd.com     */
156413569Sbrandon.potter@amd.com    BufferArg msgBuf(msgPtr, sizeof(struct msghdr));
156513569Sbrandon.potter@amd.com    msgBuf.copyIn(tc->getMemProxy());
156613569Sbrandon.potter@amd.com    struct msghdr msgHdr = *((struct msghdr *)msgBuf.bufferPtr());
156713569Sbrandon.potter@amd.com
156813569Sbrandon.potter@amd.com    /**
156913569Sbrandon.potter@amd.com     * Assuming msgHdr.msg_iovlen >= 1, then there is no point calling
157013569Sbrandon.potter@amd.com     * recvmsg without a buffer.
157113569Sbrandon.potter@amd.com     */
157213569Sbrandon.potter@amd.com    struct iovec *iovPtr = msgHdr.msg_iov;
157313569Sbrandon.potter@amd.com    BufferArg iovBuf((Addr)iovPtr, sizeof(struct iovec) * msgHdr.msg_iovlen);
157413569Sbrandon.potter@amd.com    iovBuf.copyIn(tc->getMemProxy());
157513569Sbrandon.potter@amd.com    struct iovec *iov = (struct iovec *)iovBuf.bufferPtr();
157613569Sbrandon.potter@amd.com    msgHdr.msg_iov = iov;
157713569Sbrandon.potter@amd.com
157813569Sbrandon.potter@amd.com    /**
157913569Sbrandon.potter@amd.com     * Cannot instantiate buffers till inside the loop.
158013569Sbrandon.potter@amd.com     * Create array to hold buffer addresses, to be used during copyIn of
158113569Sbrandon.potter@amd.com     * send data.
158213569Sbrandon.potter@amd.com     */
158313569Sbrandon.potter@amd.com    BufferArg **bufferArray = (BufferArg **)malloc(msgHdr.msg_iovlen
158413569Sbrandon.potter@amd.com                                                   * sizeof(BufferArg *));
158513569Sbrandon.potter@amd.com
158613569Sbrandon.potter@amd.com    /**
158713569Sbrandon.potter@amd.com     * Iterate through the iovec structures:
158813569Sbrandon.potter@amd.com     * Get the base buffer addreses, reserve iov_len amount of space for each.
158913569Sbrandon.potter@amd.com     * Put the buf address into the bufferArray for later retrieval.
159013569Sbrandon.potter@amd.com     */
159113569Sbrandon.potter@amd.com    for (int iovIndex = 0 ; iovIndex < msgHdr.msg_iovlen; iovIndex++) {
159213569Sbrandon.potter@amd.com        Addr basePtr = (Addr) iov[iovIndex].iov_base;
159313569Sbrandon.potter@amd.com        bufferArray[iovIndex] = new BufferArg(basePtr, iov[iovIndex].iov_len);
159413569Sbrandon.potter@amd.com        bufferArray[iovIndex]->copyIn(tc->getMemProxy());
159513569Sbrandon.potter@amd.com        iov[iovIndex].iov_base = bufferArray[iovIndex]->bufferPtr();
159613569Sbrandon.potter@amd.com    }
159713569Sbrandon.potter@amd.com
159813569Sbrandon.potter@amd.com    ssize_t sent_size = sendmsg(sim_fd, &msgHdr, flags);
159913569Sbrandon.potter@amd.com    int local_errno = errno;
160013569Sbrandon.potter@amd.com
160113569Sbrandon.potter@amd.com    /**
160213569Sbrandon.potter@amd.com     * Free dynamically allocated memory.
160313569Sbrandon.potter@amd.com     */
160413569Sbrandon.potter@amd.com    for (int iovIndex = 0 ; iovIndex < msgHdr.msg_iovlen; iovIndex++) {
160513569Sbrandon.potter@amd.com        BufferArg *baseBuf = ( BufferArg *)bufferArray[iovIndex];
160613569Sbrandon.potter@amd.com        delete(baseBuf);
160713569Sbrandon.potter@amd.com    }
160813569Sbrandon.potter@amd.com
160913569Sbrandon.potter@amd.com    /**
161013569Sbrandon.potter@amd.com     * Malloced above.
161113569Sbrandon.potter@amd.com     */
161213569Sbrandon.potter@amd.com    free(bufferArray);
161313569Sbrandon.potter@amd.com
161413569Sbrandon.potter@amd.com    return (sent_size < 0) ? -local_errno : sent_size;
161513569Sbrandon.potter@amd.com}
161613569Sbrandon.potter@amd.com
1617