syscall_emul.hh revision 11885
1360SN/A/*
210850SGiacomo.Gabrielli@arm.com * Copyright (c) 2012-2013, 2015 ARM Limited
310796Sbrandon.potter@amd.com * Copyright (c) 2015 Advanced Micro Devices, Inc.
410027SChris.Adeniyi-Jones@arm.com * All rights reserved
510027SChris.Adeniyi-Jones@arm.com *
610027SChris.Adeniyi-Jones@arm.com * The license below extends only to copyright in the software and shall
710027SChris.Adeniyi-Jones@arm.com * not be construed as granting a license to any other intellectual
810027SChris.Adeniyi-Jones@arm.com * property including but not limited to intellectual property relating
910027SChris.Adeniyi-Jones@arm.com * to a hardware implementation of the functionality of the software
1010027SChris.Adeniyi-Jones@arm.com * licensed hereunder.  You may use the software subject to the license
1110027SChris.Adeniyi-Jones@arm.com * terms below provided that you ensure that this notice is replicated
1210027SChris.Adeniyi-Jones@arm.com * unmodified and in its entirety in all distributions of the software,
1310027SChris.Adeniyi-Jones@arm.com * modified or unmodified, in source code or in binary form.
1410027SChris.Adeniyi-Jones@arm.com *
151458SN/A * Copyright (c) 2003-2005 The Regents of The University of Michigan
16360SN/A * All rights reserved.
17360SN/A *
18360SN/A * Redistribution and use in source and binary forms, with or without
19360SN/A * modification, are permitted provided that the following conditions are
20360SN/A * met: redistributions of source code must retain the above copyright
21360SN/A * notice, this list of conditions and the following disclaimer;
22360SN/A * redistributions in binary form must reproduce the above copyright
23360SN/A * notice, this list of conditions and the following disclaimer in the
24360SN/A * documentation and/or other materials provided with the distribution;
25360SN/A * neither the name of the copyright holders nor the names of its
26360SN/A * contributors may be used to endorse or promote products derived from
27360SN/A * this software without specific prior written permission.
28360SN/A *
29360SN/A * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
30360SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
31360SN/A * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
32360SN/A * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
33360SN/A * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
34360SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
35360SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
36360SN/A * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
37360SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
38360SN/A * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
39360SN/A * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
402665Ssaidi@eecs.umich.edu *
412665Ssaidi@eecs.umich.edu * Authors: Steve Reinhardt
422665Ssaidi@eecs.umich.edu *          Kevin Lim
43360SN/A */
44360SN/A
451354SN/A#ifndef __SIM_SYSCALL_EMUL_HH__
461354SN/A#define __SIM_SYSCALL_EMUL_HH__
47360SN/A
4812018Sandreas.sandberg@arm.com#define NO_STAT64 (defined(__APPLE__) || defined(__OpenBSD__) || \
4912018Sandreas.sandberg@arm.com  defined(__FreeBSD__) || defined(__CYGWIN__) || \
5012018Sandreas.sandberg@arm.com  defined(__NetBSD__))
5112018Sandreas.sandberg@arm.com
5212018Sandreas.sandberg@arm.com#define NO_STATFS (defined(__APPLE__) || defined(__OpenBSD__) || \
5312018Sandreas.sandberg@arm.com  defined(__FreeBSD__) || defined(__NetBSD__))
5412018Sandreas.sandberg@arm.com
552064SN/A#define NO_FALLOCATE (defined(__APPLE__) || defined(__OpenBSD__) || \
56360SN/A  defined(__FreeBSD__) || defined(__NetBSD__))
57360SN/A
58360SN/A///
59360SN/A/// @file syscall_emul.hh
60360SN/A///
61360SN/A/// This file defines objects used to emulate syscalls from the target
6213936SAndrea.Mondelli@ucf.edu/// application on the host machine.
6313933Sbrandon.potter@amd.com
6413933Sbrandon.potter@amd.com#ifdef __CYGWIN32__
6513933Sbrandon.potter@amd.com#include <sys/fcntl.h>
6613936SAndrea.Mondelli@ucf.edu
6713936SAndrea.Mondelli@ucf.edu#endif
6813936SAndrea.Mondelli@ucf.edu#include <fcntl.h>
6913933Sbrandon.potter@amd.com#include <sys/mman.h>
7013933Sbrandon.potter@amd.com#include <sys/stat.h>
711809SN/A#if (NO_STATFS == 0)
7211800Sbrandon.potter@amd.com#include <sys/statfs.h>
7311392Sbrandon.potter@amd.com#else
741809SN/A#include <sys/mount.h>
7511392Sbrandon.potter@amd.com#endif
7613902Sbrandon.potter@amd.com#include <sys/time.h>
7713570Sbrandon.potter@amd.com#include <sys/uio.h>
7813902Sbrandon.potter@amd.com#include <unistd.h>
7911383Sbrandon.potter@amd.com
8013568Sbrandon.potter@amd.com#include <cerrno>
813113Sgblack@eecs.umich.edu#include <memory>
828229Snate@binkert.org#include <string>
8313570Sbrandon.potter@amd.com
848229Snate@binkert.org#include "base/intmath.hh"
8511594Santhony.gutierrez@amd.com#include "base/loader/object_file.hh"
867075Snate@binkert.org#include "base/misc.hh"
878229Snate@binkert.org#include "base/trace.hh"
8811856Sbrandon.potter@amd.com#include "base/types.hh"
897075Snate@binkert.org#include "config/the_isa.hh"
90360SN/A#include "cpu/base.hh"
9112461Sgabeblack@google.com#include "cpu/thread_context.hh"
9211886Sbrandon.potter@amd.com#include "mem/page_table.hh"
9311800Sbrandon.potter@amd.com#include "sim/emul_driver.hh"
9411392Sbrandon.potter@amd.com#include "sim/process.hh"
9512334Sgabeblack@google.com#include "sim/syscall_debug_macros.hh"
961354SN/A#include "sim/syscall_emul_buf.hh"
976216Snate@binkert.org#include "sim/syscall_return.hh"
986658Snate@binkert.org
992474SN/Aclass SyscallDesc;
1002680Sktlim@umich.edu
1018229Snate@binkert.org//////////////////////////////////////////////////////////////////////
10211886Sbrandon.potter@amd.com//
10310496Ssteve.reinhardt@amd.com// The following emulation functions are generic enough that they
10411911SBrandon.Potter@amd.com// don't need to be recompiled for different emulated OS's.  They are
1058229Snate@binkert.org// defined in sim/syscall_emul.cc.
10611794Sbrandon.potter@amd.com//
10711886Sbrandon.potter@amd.com//////////////////////////////////////////////////////////////////////
10810497Ssteve.reinhardt@amd.com
10911794Sbrandon.potter@amd.com
110360SN/A/// Handler for unimplemented syscalls that we haven't thought about.
11113629SAndrea.Mondelli@ucf.eduSyscallReturn unimplementedFunc(SyscallDesc *desc, int num,
11213629SAndrea.Mondelli@ucf.edu                                Process *p, ThreadContext *tc);
11313629SAndrea.Mondelli@ucf.edu
11413629SAndrea.Mondelli@ucf.edu/// Handler for unimplemented syscalls that we never intend to
115360SN/A/// implement (signal handling, etc.) and should not affect the correct
116360SN/A/// behavior of the program.  Print a warning only if the appropriate
117360SN/A/// trace flag is enabled.  Return success to the target program.
118360SN/ASyscallReturn ignoreFunc(SyscallDesc *desc, int num,
119360SN/A                         Process *p, ThreadContext *tc);
120360SN/A
121360SN/A// Target fallocateFunc() handler.
122360SN/ASyscallReturn fallocateFunc(SyscallDesc *desc, int num,
12313933Sbrandon.potter@amd.com                            Process *p, ThreadContext *tc);
124360SN/A
125378SN/A/// Target exit() handler: terminate current context.
12613995Sbrandon.potter@amd.comSyscallReturn exitFunc(SyscallDesc *desc, int num,
127378SN/A                       Process *p, ThreadContext *tc);
128378SN/A
129378SN/A/// Target exit_group() handler: terminate simulation. (exit all threads)
130378SN/ASyscallReturn exitGroupFunc(SyscallDesc *desc, int num,
131378SN/A                       Process *p, ThreadContext *tc);
13213995Sbrandon.potter@amd.com
133360SN/A/// Target getpagesize() handler.
13411760Sbrandon.potter@amd.comSyscallReturn getpagesizeFunc(SyscallDesc *desc, int num,
13513995Sbrandon.potter@amd.com                              Process *p, ThreadContext *tc);
13611760Sbrandon.potter@amd.com
1376109Ssanchezd@stanford.edu/// Target brk() handler: set brk address.
13813995Sbrandon.potter@amd.comSyscallReturn brkFunc(SyscallDesc *desc, int num,
139378SN/A                      Process *p, ThreadContext *tc);
1406109Ssanchezd@stanford.edu
14113995Sbrandon.potter@amd.com/// Target close() handler.
1426109Ssanchezd@stanford.eduSyscallReturn closeFunc(SyscallDesc *desc, int num,
14311886Sbrandon.potter@amd.com                        Process *p, ThreadContext *tc);
14413995Sbrandon.potter@amd.com
14511886Sbrandon.potter@amd.com/// Target read() handler.
146378SN/ASyscallReturn readFunc(SyscallDesc *desc, int num,
14713995Sbrandon.potter@amd.com                       Process *p, ThreadContext *tc);
148378SN/A
1495748SSteve.Reinhardt@amd.com/// Target write() handler.
15013995Sbrandon.potter@amd.comSyscallReturn writeFunc(SyscallDesc *desc, int num,
151378SN/A                        Process *p, ThreadContext *tc);
152378SN/A
15313995Sbrandon.potter@amd.com/// Target lseek() handler.
154378SN/ASyscallReturn lseekFunc(SyscallDesc *desc, int num,
155378SN/A                        Process *p, ThreadContext *tc);
15613995Sbrandon.potter@amd.com
157378SN/A/// Target _llseek() handler.
1584118Sgblack@eecs.umich.eduSyscallReturn _llseekFunc(SyscallDesc *desc, int num,
15913995Sbrandon.potter@amd.com                          Process *p, ThreadContext *tc);
1604118Sgblack@eecs.umich.edu
161378SN/A/// Target munmap() handler.
16213995Sbrandon.potter@amd.comSyscallReturn munmapFunc(SyscallDesc *desc, int num,
163378SN/A                         Process *p, ThreadContext *tc);
16413568Sbrandon.potter@amd.com
16513995Sbrandon.potter@amd.com/// Target gethostname() handler.
16613568Sbrandon.potter@amd.comSyscallReturn gethostnameFunc(SyscallDesc *desc, int num,
167378SN/A                              Process *p, ThreadContext *tc);
16813995Sbrandon.potter@amd.com
169360SN/A/// Target getcwd() handler.
1705513SMichael.Adler@intel.comSyscallReturn getcwdFunc(SyscallDesc *desc, int num,
17113995Sbrandon.potter@amd.com                         Process *p, ThreadContext *tc);
1725513SMichael.Adler@intel.com
17310203SAli.Saidi@ARM.com/// Target readlink() handler.
17413995Sbrandon.potter@amd.comSyscallReturn readlinkFunc(SyscallDesc *desc, int num,
17510203SAli.Saidi@ARM.com                           Process *p, ThreadContext *tc,
17613995Sbrandon.potter@amd.com                           int index = 0);
1775513SMichael.Adler@intel.comSyscallReturn readlinkFunc(SyscallDesc *desc, int num,
178511SN/A                           Process *p, ThreadContext *tc);
17913995Sbrandon.potter@amd.com
18010633Smichaelupton@gmail.com/// Target unlink() handler.
18113995Sbrandon.potter@amd.comSyscallReturn unlinkHelper(SyscallDesc *desc, int num,
182511SN/A                           Process *p, ThreadContext *tc,
18312795Smattdsinclair@gmail.com                           int index);
18413995Sbrandon.potter@amd.comSyscallReturn unlinkFunc(SyscallDesc *desc, int num,
18512795Smattdsinclair@gmail.com                         Process *p, ThreadContext *tc);
18612796Smattdsinclair@gmail.com
18713995Sbrandon.potter@amd.com/// Target mkdir() handler.
18812796Smattdsinclair@gmail.comSyscallReturn mkdirFunc(SyscallDesc *desc, int num,
1895513SMichael.Adler@intel.com                        Process *p, ThreadContext *tc);
19013995Sbrandon.potter@amd.com
1915513SMichael.Adler@intel.com/// Target rename() handler.
19213031Sbrandon.potter@amd.comSyscallReturn renameFunc(SyscallDesc *desc, int num,
19313995Sbrandon.potter@amd.com                         Process *p, ThreadContext *tc);
19413031Sbrandon.potter@amd.com
19513031Sbrandon.potter@amd.com
19613995Sbrandon.potter@amd.com/// Target truncate() handler.
19713031Sbrandon.potter@amd.comSyscallReturn truncateFunc(SyscallDesc *desc, int num,
19813031Sbrandon.potter@amd.com                           Process *p, ThreadContext *tc);
19913995Sbrandon.potter@amd.com
20013031Sbrandon.potter@amd.com
201511SN/A/// Target ftruncate() handler.
20213995Sbrandon.potter@amd.comSyscallReturn ftruncateFunc(SyscallDesc *desc, int num,
2031706SN/A                            Process *p, ThreadContext *tc);
2041706SN/A
2051706SN/A
20613995Sbrandon.potter@amd.com/// Target truncate64() handler.
2071706SN/ASyscallReturn truncate64Func(SyscallDesc *desc, int num,
2081706SN/A                             Process *p, ThreadContext *tc);
2091706SN/A
21013995Sbrandon.potter@amd.com/// Target ftruncate64() handler.
2111706SN/ASyscallReturn ftruncate64Func(SyscallDesc *desc, int num,
212511SN/A                              Process *p, ThreadContext *tc);
2136703Svince@csl.cornell.edu
21413995Sbrandon.potter@amd.com
2156703Svince@csl.cornell.edu/// Target umask() handler.
2166685Stjones1@inf.ed.ac.ukSyscallReturn umaskFunc(SyscallDesc *desc, int num,
21713995Sbrandon.potter@amd.com                        Process *p, ThreadContext *tc);
2186685Stjones1@inf.ed.ac.uk
2196685Stjones1@inf.ed.ac.uk/// Target gettid() handler.
2205513SMichael.Adler@intel.comSyscallReturn gettidFunc(SyscallDesc *desc, int num,
22113995Sbrandon.potter@amd.com                         Process *p, ThreadContext *tc);
2225513SMichael.Adler@intel.com
22311885Sbrandon.potter@amd.com/// Target chown() handler.
22413995Sbrandon.potter@amd.comSyscallReturn chownFunc(SyscallDesc *desc, int num,
2255513SMichael.Adler@intel.com                        Process *p, ThreadContext *tc);
2261999SN/A
22713995Sbrandon.potter@amd.com/// Target setpgid() handler.
2281999SN/ASyscallReturn setpgidFunc(SyscallDesc *desc, int num,
22911885Sbrandon.potter@amd.com                          Process *p, ThreadContext *tc);
23013995Sbrandon.potter@amd.com
2311999SN/A/// Target fchown() handler.
2321999SN/ASyscallReturn fchownFunc(SyscallDesc *desc, int num,
23313995Sbrandon.potter@amd.com                         Process *p, ThreadContext *tc);
2341999SN/A
2353079Sstever@eecs.umich.edu/// Target dup() handler.
23613995Sbrandon.potter@amd.comSyscallReturn dupFunc(SyscallDesc *desc, int num,
2373079Sstever@eecs.umich.edu                      Process *process, ThreadContext *tc);
23811908SBrandon.Potter@amd.com
23913995Sbrandon.potter@amd.com/// Target fcntl() handler.
24011908SBrandon.Potter@amd.comSyscallReturn fcntlFunc(SyscallDesc *desc, int num,
24111875Sbrandon.potter@amd.com                        Process *process, ThreadContext *tc);
24213995Sbrandon.potter@amd.com
2432093SN/A/// Target fcntl64() handler.
2442687Sksewell@umich.eduSyscallReturn fcntl64Func(SyscallDesc *desc, int num,
24513995Sbrandon.potter@amd.com                          Process *process, ThreadContext *tc);
2462687Sksewell@umich.edu
2472238SN/A/// Target setuid() handler.
24813995Sbrandon.potter@amd.comSyscallReturn setuidFunc(SyscallDesc *desc, int num,
2492238SN/A                         Process *p, ThreadContext *tc);
25011908SBrandon.Potter@amd.com
25113995Sbrandon.potter@amd.com/// Target getpid() handler.
25211908SBrandon.Potter@amd.comSyscallReturn getpidFunc(SyscallDesc *desc, int num,
25311908SBrandon.Potter@amd.com                         Process *p, ThreadContext *tc);
25413995Sbrandon.potter@amd.com
25513995Sbrandon.potter@amd.com/// Target getuid() handler.
25611908SBrandon.Potter@amd.comSyscallReturn getuidFunc(SyscallDesc *desc, int num,
2572238SN/A                         Process *p, ThreadContext *tc);
25813995Sbrandon.potter@amd.com
2592238SN/A/// Target getgid() handler.
26013571Sbrandon.potter@amd.comSyscallReturn getgidFunc(SyscallDesc *desc, int num,
26113995Sbrandon.potter@amd.com                         Process *p, ThreadContext *tc);
26213571Sbrandon.potter@amd.com
26313568Sbrandon.potter@amd.com/// Target getppid() handler.
26413995Sbrandon.potter@amd.comSyscallReturn getppidFunc(SyscallDesc *desc, int num,
26513568Sbrandon.potter@amd.com                          Process *p, ThreadContext *tc);
26613568Sbrandon.potter@amd.com
26713995Sbrandon.potter@amd.com/// Target geteuid() handler.
26813568Sbrandon.potter@amd.comSyscallReturn geteuidFunc(SyscallDesc *desc, int num,
26913568Sbrandon.potter@amd.com                          Process *p, ThreadContext *tc);
27013995Sbrandon.potter@amd.com
27113568Sbrandon.potter@amd.com/// Target getegid() handler.
27213448Sciro.santilli@arm.comSyscallReturn getegidFunc(SyscallDesc *desc, int num,
27313031Sbrandon.potter@amd.com                          Process *p, ThreadContext *tc);
27413995Sbrandon.potter@amd.com
27513448Sciro.santilli@arm.com/// Target clone() handler.
27613031Sbrandon.potter@amd.comSyscallReturn cloneFunc(SyscallDesc *desc, int num,
27713539Sjavier.setoain@arm.com                        Process *p, ThreadContext *tc);
27813539Sjavier.setoain@arm.com
27913995Sbrandon.potter@amd.com/// Target access() handler
28013539Sjavier.setoain@arm.comSyscallReturn accessFunc(SyscallDesc *desc, int num,
28113539Sjavier.setoain@arm.com                         Process *p, ThreadContext *tc);
28213569Sbrandon.potter@amd.comSyscallReturn accessFunc(SyscallDesc *desc, int num,
28313995Sbrandon.potter@amd.com                         Process *p, ThreadContext *tc,
28413569Sbrandon.potter@amd.com                         int index);
28513569Sbrandon.potter@amd.com
28613995Sbrandon.potter@amd.com/// Futex system call
28713569Sbrandon.potter@amd.com///  Implemented by Daniel Sanchez
28813569Sbrandon.potter@amd.com///  Used by printf's in multi-threaded apps
28913995Sbrandon.potter@amd.comtemplate <class OS>
29013569Sbrandon.potter@amd.comSyscallReturn
29113569Sbrandon.potter@amd.comfutexFunc(SyscallDesc *desc, int callnum, Process *process,
29213995Sbrandon.potter@amd.com          ThreadContext *tc)
29313569Sbrandon.potter@amd.com{
29413031Sbrandon.potter@amd.com    int index_uaddr = 0;
29513995Sbrandon.potter@amd.com    int index_op = 1;
2962238SN/A    int index_val = 2;
2972238SN/A    int index_timeout = 3;
29813995Sbrandon.potter@amd.com
2992238SN/A    uint64_t uaddr = process->getSyscallArg(tc, index_uaddr);
3002238SN/A    int op = process->getSyscallArg(tc, index_op);
30113995Sbrandon.potter@amd.com    int val = process->getSyscallArg(tc, index_val);
3022238SN/A    uint64_t timeout = process->getSyscallArg(tc, index_timeout);
3032238SN/A
30413995Sbrandon.potter@amd.com    std::map<uint64_t, std::list<ThreadContext *> * >
3052238SN/A        &futex_map = tc->getSystemPtr()->futexMap;
3062238SN/A
30713995Sbrandon.potter@amd.com    DPRINTF(SyscallVerbose, "In sys_futex: Address=%llx, op=%d, val=%d\n",
3082238SN/A            uaddr, op, val);
3099455Smitch.hayenga+gem5@gmail.com
31013995Sbrandon.potter@amd.com    op &= ~OS::TGT_FUTEX_PRIVATE_FLAG;
31113995Sbrandon.potter@amd.com
31211851Sbrandon.potter@amd.com    if (op == OS::TGT_FUTEX_WAIT) {
3139455Smitch.hayenga+gem5@gmail.com        if (timeout != 0) {
31413571Sbrandon.potter@amd.com            warn("sys_futex: FUTEX_WAIT with non-null timeout unimplemented;"
31513995Sbrandon.potter@amd.com                 "we'll wait indefinitely");
31613571Sbrandon.potter@amd.com        }
31713571Sbrandon.potter@amd.com
31813995Sbrandon.potter@amd.com        uint8_t *buf = new uint8_t[sizeof(int)];
31913571Sbrandon.potter@amd.com        tc->getMemProxy().readBlob((Addr)uaddr, buf, (int)sizeof(int));
32013571Sbrandon.potter@amd.com        int mem_val = *((int *)buf);
32113995Sbrandon.potter@amd.com        delete[] buf;
32213571Sbrandon.potter@amd.com
3239112Smarc.orr@gmail.com        if (val != mem_val) {
32411906SBrandon.Potter@amd.com            DPRINTF(SyscallVerbose, "sys_futex: FUTEX_WAKE, read: %d, "
32511906SBrandon.Potter@amd.com                                    "expected: %d\n", mem_val, val);
3269112Smarc.orr@gmail.com            return -OS::TGT_EWOULDBLOCK;
3279112Smarc.orr@gmail.com        }
32813995Sbrandon.potter@amd.com
3299112Smarc.orr@gmail.com        // Queue the thread context
33011911SBrandon.Potter@amd.com        std::list<ThreadContext *> * tcWaitList;
3319112Smarc.orr@gmail.com        if (futex_map.count(uaddr)) {
33211911SBrandon.Potter@amd.com            tcWaitList = futex_map.find(uaddr)->second;
33313995Sbrandon.potter@amd.com        } else {
33413995Sbrandon.potter@amd.com            tcWaitList = new std::list<ThreadContext *>();
33511911SBrandon.Potter@amd.com            futex_map.insert(std::pair< uint64_t,
33611911SBrandon.Potter@amd.com                            std::list<ThreadContext *> * >(uaddr, tcWaitList));
33711911SBrandon.Potter@amd.com        }
33813642Sqtt2@cornell.edu        tcWaitList->push_back(tc);
33913642Sqtt2@cornell.edu        DPRINTF(SyscallVerbose, "sys_futex: FUTEX_WAIT, suspending calling "
34013642Sqtt2@cornell.edu                                "thread context\n");
3419112Smarc.orr@gmail.com        tc->suspend();
34211911SBrandon.Potter@amd.com        return 0;
34311911SBrandon.Potter@amd.com    } else if (op == OS::TGT_FUTEX_WAKE){
34411911SBrandon.Potter@amd.com        int wokenUp = 0;
34511911SBrandon.Potter@amd.com        std::list<ThreadContext *> * tcWaitList;
3469238Slluc.alvarez@bsc.es        if (futex_map.count(uaddr)) {
34713642Sqtt2@cornell.edu            tcWaitList = futex_map.find(uaddr)->second;
3489112Smarc.orr@gmail.com            while (tcWaitList->size() > 0 && wokenUp < val) {
34911911SBrandon.Potter@amd.com                tcWaitList->front()->activate();
3509112Smarc.orr@gmail.com                tcWaitList->pop_front();
35113642Sqtt2@cornell.edu                wokenUp++;
35211911SBrandon.Potter@amd.com            }
35311911SBrandon.Potter@amd.com            if (tcWaitList->empty()) {
35411911SBrandon.Potter@amd.com                futex_map.erase(uaddr);
35511911SBrandon.Potter@amd.com                delete tcWaitList;
3569112Smarc.orr@gmail.com            }
35711911SBrandon.Potter@amd.com        }
35811911SBrandon.Potter@amd.com        DPRINTF(SyscallVerbose, "sys_futex: FUTEX_WAKE, activated %d waiting "
35911911SBrandon.Potter@amd.com                                "thread contexts\n", wokenUp);
36011911SBrandon.Potter@amd.com        return wokenUp;
36111911SBrandon.Potter@amd.com    } else {
36211911SBrandon.Potter@amd.com        warn("sys_futex: op %d is not implemented, just returning...", op);
3639112Smarc.orr@gmail.com        return 0;
3649112Smarc.orr@gmail.com    }
36513642Sqtt2@cornell.edu
36613642Sqtt2@cornell.edu}
36713642Sqtt2@cornell.edu
36813642Sqtt2@cornell.edu
36913642Sqtt2@cornell.edu/// Pseudo Funcs  - These functions use a different return convension,
37011911SBrandon.Potter@amd.com/// returning a second value in a register other than the normal return register
3719112Smarc.orr@gmail.comSyscallReturn pipePseudoFunc(SyscallDesc *desc, int num,
37211911SBrandon.Potter@amd.com                             Process *process, ThreadContext *tc);
37311911SBrandon.Potter@amd.com
37413642Sqtt2@cornell.edu/// Target getpidPseudo() handler.
37513642Sqtt2@cornell.eduSyscallReturn getpidPseudoFunc(SyscallDesc *desc, int num,
37613650Smw828@cornell.edu                               Process *p, ThreadContext *tc);
37713650Smw828@cornell.edu
37813650Smw828@cornell.edu/// Target getuidPseudo() handler.
37913650Smw828@cornell.eduSyscallReturn getuidPseudoFunc(SyscallDesc *desc, int num,
38013650Smw828@cornell.edu                               Process *p, ThreadContext *tc);
38113650Smw828@cornell.edu
38213650Smw828@cornell.edu/// Target getgidPseudo() handler.
38313650Smw828@cornell.eduSyscallReturn getgidPseudoFunc(SyscallDesc *desc, int num,
38413650Smw828@cornell.edu                               Process *p, ThreadContext *tc);
38513650Smw828@cornell.edu
38613650Smw828@cornell.edu
38713650Smw828@cornell.edu/// A readable name for 1,000,000, for converting microseconds to seconds.
38813650Smw828@cornell.educonst int one_million = 1000000;
38913650Smw828@cornell.edu/// A readable name for 1,000,000,000, for converting nanoseconds to seconds.
39013651Smw828@cornell.educonst int one_billion = 1000000000;
39113651Smw828@cornell.edu
39213651Smw828@cornell.edu/// Approximate seconds since the epoch (1/1/1970).  About a billion,
39313651Smw828@cornell.edu/// by my reckoning.  We want to keep this a constant (not use the
39413651Smw828@cornell.edu/// real-world time) to keep simulations repeatable.
39513651Smw828@cornell.educonst unsigned seconds_since_epoch = 1000000000;
39613651Smw828@cornell.edu
39713651Smw828@cornell.edu/// Helper function to convert current elapsed time to seconds and
39813651Smw828@cornell.edu/// microseconds.
39913651Smw828@cornell.edutemplate <class T1, class T2>
40013651Smw828@cornell.eduvoid
40113651Smw828@cornell.edugetElapsedTimeMicro(T1 &sec, T2 &usec)
40213651Smw828@cornell.edu{
40313651Smw828@cornell.edu    uint64_t elapsed_usecs = curTick() / SimClock::Int::us;
40413651Smw828@cornell.edu    sec = elapsed_usecs / one_million;
40513651Smw828@cornell.edu    usec = elapsed_usecs % one_million;
40613651Smw828@cornell.edu}
40713651Smw828@cornell.edu
40813651Smw828@cornell.edu/// Helper function to convert current elapsed time to seconds and
40913651Smw828@cornell.edu/// nanoseconds.
41013651Smw828@cornell.edutemplate <class T1, class T2>
41113651Smw828@cornell.eduvoid
41213651Smw828@cornell.edugetElapsedTimeNano(T1 &sec, T2 &nsec)
41313651Smw828@cornell.edu{
41413651Smw828@cornell.edu    uint64_t elapsed_nsecs = curTick() / SimClock::Int::ns;
41513651Smw828@cornell.edu    sec = elapsed_nsecs / one_billion;
41613651Smw828@cornell.edu    nsec = elapsed_nsecs % one_billion;
41713651Smw828@cornell.edu}
41813651Smw828@cornell.edu
41913651Smw828@cornell.edu//////////////////////////////////////////////////////////////////////
42013651Smw828@cornell.edu//
42113651Smw828@cornell.edu// The following emulation functions are generic, but need to be
42213651Smw828@cornell.edu// templated to account for differences in types, constants, etc.
42313651Smw828@cornell.edu//
42413651Smw828@cornell.edu//////////////////////////////////////////////////////////////////////
42513651Smw828@cornell.edu
42613651Smw828@cornell.edu    typedef struct statfs hst_statfs;
42713651Smw828@cornell.edu#if NO_STAT64
42813651Smw828@cornell.edu    typedef struct stat hst_stat;
42913651Smw828@cornell.edu    typedef struct stat hst_stat64;
43013651Smw828@cornell.edu#else
43113651Smw828@cornell.edu    typedef struct stat hst_stat;
43213651Smw828@cornell.edu    typedef struct stat64 hst_stat64;
43313651Smw828@cornell.edu#endif
43413651Smw828@cornell.edu
43513651Smw828@cornell.edu//// Helper function to convert a host stat buffer to a target stat
43613651Smw828@cornell.edu//// buffer.  Also copies the target buffer out to the simulated
43713651Smw828@cornell.edu//// memory space.  Used by stat(), fstat(), and lstat().
43813651Smw828@cornell.edu
43913651Smw828@cornell.edutemplate <typename target_stat, typename host_stat>
44013651Smw828@cornell.edustatic void
44113651Smw828@cornell.educonvertStatBuf(target_stat &tgt, host_stat *host, bool fakeTTY = false)
44213651Smw828@cornell.edu{
44313651Smw828@cornell.edu    using namespace TheISA;
44413651Smw828@cornell.edu
44513651Smw828@cornell.edu    if (fakeTTY)
44613651Smw828@cornell.edu        tgt->st_dev = 0xA;
44713651Smw828@cornell.edu    else
44813651Smw828@cornell.edu        tgt->st_dev = host->st_dev;
44913651Smw828@cornell.edu    tgt->st_dev = TheISA::htog(tgt->st_dev);
45013651Smw828@cornell.edu    tgt->st_ino = host->st_ino;
45113651Smw828@cornell.edu    tgt->st_ino = TheISA::htog(tgt->st_ino);
45213651Smw828@cornell.edu    tgt->st_mode = host->st_mode;
45313651Smw828@cornell.edu    if (fakeTTY) {
45413651Smw828@cornell.edu        // Claim to be a character device
45513651Smw828@cornell.edu        tgt->st_mode &= ~S_IFMT;    // Clear S_IFMT
45613651Smw828@cornell.edu        tgt->st_mode |= S_IFCHR;    // Set S_IFCHR
45713651Smw828@cornell.edu    }
45813651Smw828@cornell.edu    tgt->st_mode = TheISA::htog(tgt->st_mode);
45913651Smw828@cornell.edu    tgt->st_nlink = host->st_nlink;
46013651Smw828@cornell.edu    tgt->st_nlink = TheISA::htog(tgt->st_nlink);
4619112Smarc.orr@gmail.com    tgt->st_uid = host->st_uid;
46211911SBrandon.Potter@amd.com    tgt->st_uid = TheISA::htog(tgt->st_uid);
46311911SBrandon.Potter@amd.com    tgt->st_gid = host->st_gid;
4649112Smarc.orr@gmail.com    tgt->st_gid = TheISA::htog(tgt->st_gid);
4659112Smarc.orr@gmail.com    if (fakeTTY)
4662238SN/A        tgt->st_rdev = 0x880d;
4672238SN/A    else
4682238SN/A        tgt->st_rdev = host->st_rdev;
46913995Sbrandon.potter@amd.com    tgt->st_rdev = TheISA::htog(tgt->st_rdev);
4702238SN/A    tgt->st_size = host->st_size;
4712238SN/A    tgt->st_size = TheISA::htog(tgt->st_size);
47213995Sbrandon.potter@amd.com    tgt->st_atimeX = host->st_atime;
4732238SN/A    tgt->st_atimeX = TheISA::htog(tgt->st_atimeX);
4742238SN/A    tgt->st_mtimeX = host->st_mtime;
47513995Sbrandon.potter@amd.com    tgt->st_mtimeX = TheISA::htog(tgt->st_mtimeX);
4762238SN/A    tgt->st_ctimeX = host->st_ctime;
4772238SN/A    tgt->st_ctimeX = TheISA::htog(tgt->st_ctimeX);
47813995Sbrandon.potter@amd.com    // Force the block size to be 8k. This helps to ensure buffered io works
4792238SN/A    // consistently across different hosts.
4802238SN/A    tgt->st_blksize = 0x2000;
4811354SN/A    tgt->st_blksize = TheISA::htog(tgt->st_blksize);
4821354SN/A    tgt->st_blocks = host->st_blocks;
48310796Sbrandon.potter@amd.com    tgt->st_blocks = TheISA::htog(tgt->st_blocks);
48410796Sbrandon.potter@amd.com}
4851354SN/A
4861354SN/A// Same for stat64
4871354SN/A
4881354SN/Atemplate <typename target_stat, typename host_stat64>
4891354SN/Astatic void
4901354SN/AconvertStat64Buf(target_stat &tgt, host_stat64 *host, bool fakeTTY = false)
4911354SN/A{
4921354SN/A    using namespace TheISA;
4931354SN/A
4941354SN/A    convertStatBuf<target_stat, host_stat64>(tgt, host, fakeTTY);
49510796Sbrandon.potter@amd.com#if defined(STAT_HAVE_NSEC)
4961354SN/A    tgt->st_atime_nsec = host->st_atime_nsec;
49710796Sbrandon.potter@amd.com    tgt->st_atime_nsec = TheISA::htog(tgt->st_atime_nsec);
4981354SN/A    tgt->st_mtime_nsec = host->st_mtime_nsec;
4991354SN/A    tgt->st_mtime_nsec = TheISA::htog(tgt->st_mtime_nsec);
5001354SN/A    tgt->st_ctime_nsec = host->st_ctime_nsec;
5011354SN/A    tgt->st_ctime_nsec = TheISA::htog(tgt->st_ctime_nsec);
50210796Sbrandon.potter@amd.com#else
50310796Sbrandon.potter@amd.com    tgt->st_atime_nsec = 0;
50410796Sbrandon.potter@amd.com    tgt->st_mtime_nsec = 0;
50510796Sbrandon.potter@amd.com    tgt->st_ctime_nsec = 0;
50610796Sbrandon.potter@amd.com#endif
50710796Sbrandon.potter@amd.com}
50810796Sbrandon.potter@amd.com
50910796Sbrandon.potter@amd.com//Here are a couple convenience functions
51010796Sbrandon.potter@amd.comtemplate<class OS>
51110796Sbrandon.potter@amd.comstatic void
51210796Sbrandon.potter@amd.comcopyOutStatBuf(SETranslatingPortProxy &mem, Addr addr,
513360SN/A        hst_stat *host, bool fakeTTY = false)
514360SN/A{
515360SN/A    typedef TypedBufferArg<typename OS::tgt_stat> tgt_stat_buf;
516360SN/A    tgt_stat_buf tgt(addr);
517360SN/A    convertStatBuf<tgt_stat_buf, hst_stat>(tgt, host, fakeTTY);
518360SN/A    tgt.copyOut(mem);
519360SN/A}
52011759Sbrandon.potter@amd.com
5213113Sgblack@eecs.umich.edutemplate<class OS>
5223113Sgblack@eecs.umich.edustatic void
5233113Sgblack@eecs.umich.educopyOutStat64Buf(SETranslatingPortProxy &mem, Addr addr,
5243113Sgblack@eecs.umich.edu        hst_stat64 *host, bool fakeTTY = false)
5253113Sgblack@eecs.umich.edu{
5263113Sgblack@eecs.umich.edu    typedef TypedBufferArg<typename OS::tgt_stat64> tgt_stat_buf;
5273113Sgblack@eecs.umich.edu    tgt_stat_buf tgt(addr);
5283113Sgblack@eecs.umich.edu    convertStat64Buf<tgt_stat_buf, hst_stat64>(tgt, host, fakeTTY);
5293113Sgblack@eecs.umich.edu    tgt.copyOut(mem);
5303113Sgblack@eecs.umich.edu}
5313113Sgblack@eecs.umich.edu
5323113Sgblack@eecs.umich.edutemplate <class OS>
5333113Sgblack@eecs.umich.edustatic void
53412032Sandreas.sandberg@arm.comcopyOutStatfsBuf(SETranslatingPortProxy &mem, Addr addr,
5353113Sgblack@eecs.umich.edu                 hst_statfs *host)
5363113Sgblack@eecs.umich.edu{
5374189Sgblack@eecs.umich.edu    TypedBufferArg<typename OS::tgt_statfs> tgt(addr);
5384189Sgblack@eecs.umich.edu
5393113Sgblack@eecs.umich.edu    tgt->f_type = TheISA::htog(host->f_type);
5403113Sgblack@eecs.umich.edu#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__)
5413113Sgblack@eecs.umich.edu    tgt->f_bsize = TheISA::htog(host->f_iosize);
5423113Sgblack@eecs.umich.edu#else
5438737Skoansin.tan@gmail.com    tgt->f_bsize = TheISA::htog(host->f_bsize);
5443113Sgblack@eecs.umich.edu#endif
5458737Skoansin.tan@gmail.com    tgt->f_blocks = TheISA::htog(host->f_blocks);
5463277Sgblack@eecs.umich.edu    tgt->f_bfree = TheISA::htog(host->f_bfree);
5475515SMichael.Adler@intel.com    tgt->f_bavail = TheISA::htog(host->f_bavail);
5485515SMichael.Adler@intel.com    tgt->f_files = TheISA::htog(host->f_files);
5495515SMichael.Adler@intel.com    tgt->f_ffree = TheISA::htog(host->f_ffree);
5505515SMichael.Adler@intel.com    memcpy(&tgt->f_fsid, &host->f_fsid, sizeof(host->f_fsid));
5515515SMichael.Adler@intel.com#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__)
5528737Skoansin.tan@gmail.com    tgt->f_namelen = TheISA::htog(host->f_namemax);
5533277Sgblack@eecs.umich.edu    tgt->f_frsize = TheISA::htog(host->f_bsize);
5548737Skoansin.tan@gmail.com#elif defined(__APPLE__)
5553277Sgblack@eecs.umich.edu    tgt->f_namelen = 0;
5568737Skoansin.tan@gmail.com    tgt->f_frsize = 0;
5573277Sgblack@eecs.umich.edu#else
5588737Skoansin.tan@gmail.com    tgt->f_namelen = TheISA::htog(host->f_namelen);
5593113Sgblack@eecs.umich.edu    tgt->f_frsize = TheISA::htog(host->f_frsize);
5603113Sgblack@eecs.umich.edu#endif
5613113Sgblack@eecs.umich.edu#if defined(__linux__)
5623113Sgblack@eecs.umich.edu    memcpy(&tgt->f_spare, &host->f_spare, sizeof(host->f_spare));
5638737Skoansin.tan@gmail.com#else
5643113Sgblack@eecs.umich.edu    /*
5658737Skoansin.tan@gmail.com     * The fields are different sizes per OS. Don't bother with
5663114Sgblack@eecs.umich.edu     * f_spare or f_reserved on non-Linux for now.
5678737Skoansin.tan@gmail.com     */
5683114Sgblack@eecs.umich.edu    memset(&tgt->f_spare, 0, sizeof(tgt->f_spare));
5698737Skoansin.tan@gmail.com#endif
5703114Sgblack@eecs.umich.edu
5718737Skoansin.tan@gmail.com    tgt.copyOut(mem);
57211906SBrandon.Potter@amd.com}
5734061Sgblack@eecs.umich.edu
5744061Sgblack@eecs.umich.edu/// Target ioctl() handler.  For the most part, programs call ioctl()
5758737Skoansin.tan@gmail.com/// only to find out if their stdout is a tty, to determine whether to
5763113Sgblack@eecs.umich.edu/// do line or block buffering.  We always claim that output fds are
5778737Skoansin.tan@gmail.com/// not TTYs to provide repeatable results.
5783113Sgblack@eecs.umich.edutemplate <class OS>
5793113Sgblack@eecs.umich.eduSyscallReturn
5803113Sgblack@eecs.umich.eduioctlFunc(SyscallDesc *desc, int callnum, Process *p, ThreadContext *tc)
5813113Sgblack@eecs.umich.edu{
5823113Sgblack@eecs.umich.edu    int index = 0;
58312032Sandreas.sandberg@arm.com    int tgt_fd = p->getSyscallArg(tc, index);
5843113Sgblack@eecs.umich.edu    unsigned req = p->getSyscallArg(tc, index);
5853113Sgblack@eecs.umich.edu
5864189Sgblack@eecs.umich.edu    DPRINTF(SyscallVerbose, "ioctl(%d, 0x%x, ...)\n", tgt_fd, req);
5874189Sgblack@eecs.umich.edu
5883113Sgblack@eecs.umich.edu    if (OS::isTtyReq(req))
5893113Sgblack@eecs.umich.edu        return -ENOTTY;
5903113Sgblack@eecs.umich.edu
5918737Skoansin.tan@gmail.com    auto dfdp = std::dynamic_pointer_cast<DeviceFDEntry>((*p->fds)[tgt_fd]);
5923113Sgblack@eecs.umich.edu    if (!dfdp)
5938737Skoansin.tan@gmail.com        return -EBADF;
5943113Sgblack@eecs.umich.edu
5958737Skoansin.tan@gmail.com    /**
5963113Sgblack@eecs.umich.edu     * If the driver is valid, issue the ioctl through it. Otherwise,
5973113Sgblack@eecs.umich.edu     * there's an implicit assumption that the device is a TTY type and we
5983113Sgblack@eecs.umich.edu     * return that we do not have a valid TTY.
5993113Sgblack@eecs.umich.edu     */
6003113Sgblack@eecs.umich.edu    EmulatedDriver *emul_driver = dfdp->getDriver();
6013113Sgblack@eecs.umich.edu    if (emul_driver)
6023113Sgblack@eecs.umich.edu        return emul_driver->ioctl(p, tc, req);
60311906SBrandon.Potter@amd.com
6043113Sgblack@eecs.umich.edu    /**
60512032Sandreas.sandberg@arm.com     * For lack of a better return code, return ENOTTY. Ideally, we should
6068852Sandreas.hansson@arm.com     * return something better here, but at least we issue the warning.
60711906SBrandon.Potter@amd.com     */
6083113Sgblack@eecs.umich.edu    warn("Unsupported ioctl call (return ENOTTY): ioctl(%d, 0x%x, ...) @ \n",
6093113Sgblack@eecs.umich.edu         tgt_fd, req, tc->pcState());
6103113Sgblack@eecs.umich.edu    return -ENOTTY;
6113113Sgblack@eecs.umich.edu}
6123113Sgblack@eecs.umich.edu
6133113Sgblack@eecs.umich.edutemplate <class OS>
6143113Sgblack@eecs.umich.edustatic SyscallReturn
6153113Sgblack@eecs.umich.eduopenFunc(SyscallDesc *desc, int callnum, Process *process,
61612032Sandreas.sandberg@arm.com         ThreadContext *tc, int index)
6178852Sandreas.hansson@arm.com{
61811906SBrandon.Potter@amd.com    std::string path;
6193113Sgblack@eecs.umich.edu
6203113Sgblack@eecs.umich.edu    if (!tc->getMemProxy().tryReadString(path,
6213113Sgblack@eecs.umich.edu                process->getSyscallArg(tc, index)))
6226686Stjones1@inf.ed.ac.uk        return -EFAULT;
6233113Sgblack@eecs.umich.edu
6243113Sgblack@eecs.umich.edu    int tgtFlags = process->getSyscallArg(tc, index);
6253113Sgblack@eecs.umich.edu    int mode = process->getSyscallArg(tc, index);
62611759Sbrandon.potter@amd.com    int hostFlags = 0;
62712032Sandreas.sandberg@arm.com
62811759Sbrandon.potter@amd.com    // translate open flags
62911759Sbrandon.potter@amd.com    for (int i = 0; i < OS::NUM_OPEN_FLAGS; i++) {
63011759Sbrandon.potter@amd.com        if (tgtFlags & OS::openFlagTable[i].tgtFlag) {
63111759Sbrandon.potter@amd.com            tgtFlags &= ~OS::openFlagTable[i].tgtFlag;
63211759Sbrandon.potter@amd.com            hostFlags |= OS::openFlagTable[i].hostFlag;
63311812Sbaz21@cam.ac.uk        }
63411812Sbaz21@cam.ac.uk    }
63511812Sbaz21@cam.ac.uk
63611759Sbrandon.potter@amd.com    // any target flags left?
63711812Sbaz21@cam.ac.uk    if (tgtFlags != 0)
63811759Sbrandon.potter@amd.com        warn("Syscall: open: cannot decode flags 0x%x", tgtFlags);
63911759Sbrandon.potter@amd.com
64011759Sbrandon.potter@amd.com#ifdef __CYGWIN32__
64111759Sbrandon.potter@amd.com    hostFlags |= O_BINARY;
64211759Sbrandon.potter@amd.com#endif
64311759Sbrandon.potter@amd.com
64411759Sbrandon.potter@amd.com    // Adjust path for current working directory
64511812Sbaz21@cam.ac.uk    path = process->fullPath(path);
64611812Sbaz21@cam.ac.uk
64711812Sbaz21@cam.ac.uk    DPRINTF(SyscallVerbose, "opening file %s\n", path.c_str());
64811812Sbaz21@cam.ac.uk
64911812Sbaz21@cam.ac.uk    if (startswith(path, "/dev/")) {
65011812Sbaz21@cam.ac.uk        std::string filename = path.substr(strlen("/dev/"));
65111812Sbaz21@cam.ac.uk        if (filename == "sysdev0") {
65211759Sbrandon.potter@amd.com            // This is a memory-mapped high-resolution timer device on Alpha.
65311759Sbrandon.potter@amd.com            // We don't support it, so just punt.
65411812Sbaz21@cam.ac.uk            warn("Ignoring open(%s, ...)\n", path);
65511812Sbaz21@cam.ac.uk            return -ENOENT;
65611759Sbrandon.potter@amd.com        }
65711812Sbaz21@cam.ac.uk
65811812Sbaz21@cam.ac.uk        EmulatedDriver *drv = process->findDriver(filename);
65911812Sbaz21@cam.ac.uk        if (drv) {
66011812Sbaz21@cam.ac.uk            // the driver's open method will allocate a fd from the
66111812Sbaz21@cam.ac.uk            // process if necessary.
66211812Sbaz21@cam.ac.uk            return drv->open(process, tc, mode, hostFlags);
66311812Sbaz21@cam.ac.uk        }
66411759Sbrandon.potter@amd.com
66511759Sbrandon.potter@amd.com        // fall through here for pass through to host devices, such as
66611759Sbrandon.potter@amd.com        // /dev/zero
66711759Sbrandon.potter@amd.com    }
668378SN/A
669378SN/A    int fd;
6709141Smarc.orr@gmail.com    int local_errno;
6719141Smarc.orr@gmail.com    if (startswith(path, "/proc/") || startswith(path, "/system/") ||
672360SN/A        startswith(path, "/platform/") || startswith(path, "/sys/")) {
6731450SN/A        // It's a proc/sys entry and requires special handling
67413995Sbrandon.potter@amd.com        fd = OS::openSpecialFile(path, process, tc);
675360SN/A        local_errno = ENOENT;
6766701Sgblack@eecs.umich.edu     } else {
67713995Sbrandon.potter@amd.com        // open the file
67813995Sbrandon.potter@amd.com        fd = open(path.c_str(), hostFlags, mode);
67911856Sbrandon.potter@amd.com        local_errno = errno;
68011856Sbrandon.potter@amd.com     }
681360SN/A
68213907Salexandru.dutu@amd.com    if (fd == -1)
683360SN/A        return -local_errno;
68411856Sbrandon.potter@amd.com
68511856Sbrandon.potter@amd.com    std::shared_ptr<FileFDEntry> ffdp =
68610496Ssteve.reinhardt@amd.com        std::make_shared<FileFDEntry>(fd, hostFlags, path.c_str(), false);
68711856Sbrandon.potter@amd.com    return process->fds->allocFD(ffdp);
68813902Sbrandon.potter@amd.com}
68913902Sbrandon.potter@amd.com
69013902Sbrandon.potter@amd.com/// Target open() handler.
69113995Sbrandon.potter@amd.comtemplate <class OS>
69213902Sbrandon.potter@amd.comSyscallReturn
69313902Sbrandon.potter@amd.comopenFunc(SyscallDesc *desc, int callnum, Process *process,
69413902Sbrandon.potter@amd.com         ThreadContext *tc)
69513902Sbrandon.potter@amd.com{
69613902Sbrandon.potter@amd.com    return openFunc<OS>(desc, callnum, process, tc, 0);
69713902Sbrandon.potter@amd.com}
69813902Sbrandon.potter@amd.com
69913902Sbrandon.potter@amd.com/// Target openat() handler.
70013902Sbrandon.potter@amd.comtemplate <class OS>
70113902Sbrandon.potter@amd.comSyscallReturn
70213902Sbrandon.potter@amd.comopenatFunc(SyscallDesc *desc, int callnum, Process *process,
70313902Sbrandon.potter@amd.com           ThreadContext *tc)
70413902Sbrandon.potter@amd.com{
70513902Sbrandon.potter@amd.com    int index = 0;
70613902Sbrandon.potter@amd.com    int dirfd = process->getSyscallArg(tc, index);
70713902Sbrandon.potter@amd.com    if (dirfd != OS::TGT_AT_FDCWD)
70813902Sbrandon.potter@amd.com        warn("openat: first argument not AT_FDCWD; unlikely to work");
70913902Sbrandon.potter@amd.com    return openFunc<OS>(desc, callnum, process, tc, 1);
71013902Sbrandon.potter@amd.com}
71113902Sbrandon.potter@amd.com
71213902Sbrandon.potter@amd.com/// Target unlinkat() handler.
71313902Sbrandon.potter@amd.comtemplate <class OS>
71413902Sbrandon.potter@amd.comSyscallReturn
71513902Sbrandon.potter@amd.comunlinkatFunc(SyscallDesc *desc, int callnum, Process *process,
71613902Sbrandon.potter@amd.com             ThreadContext *tc)
71713902Sbrandon.potter@amd.com{
71813902Sbrandon.potter@amd.com    int index = 0;
71913902Sbrandon.potter@amd.com    int dirfd = process->getSyscallArg(tc, index);
72013902Sbrandon.potter@amd.com    if (dirfd != OS::TGT_AT_FDCWD)
72113936SAndrea.Mondelli@ucf.edu        warn("unlinkat: first argument not AT_FDCWD; unlikely to work");
72213902Sbrandon.potter@amd.com
72313902Sbrandon.potter@amd.com    return unlinkHelper(desc, callnum, process, tc, 1);
72413902Sbrandon.potter@amd.com}
72513902Sbrandon.potter@amd.com
72613936SAndrea.Mondelli@ucf.edu/// Target facessat() handler
72713902Sbrandon.potter@amd.comtemplate <class OS>
72813902Sbrandon.potter@amd.comSyscallReturn
72913902Sbrandon.potter@amd.comfaccessatFunc(SyscallDesc *desc, int callnum, Process *process,
73013902Sbrandon.potter@amd.com              ThreadContext *tc)
73113902Sbrandon.potter@amd.com{
73213902Sbrandon.potter@amd.com    int index = 0;
73313902Sbrandon.potter@amd.com    int dirfd = process->getSyscallArg(tc, index);
73413902Sbrandon.potter@amd.com    if (dirfd != OS::TGT_AT_FDCWD)
73513902Sbrandon.potter@amd.com        warn("faccessat: first argument not AT_FDCWD; unlikely to work");
73613902Sbrandon.potter@amd.com    return accessFunc(desc, callnum, process, tc, 1);
73713902Sbrandon.potter@amd.com}
73813902Sbrandon.potter@amd.com
73913902Sbrandon.potter@amd.com/// Target readlinkat() handler
74013902Sbrandon.potter@amd.comtemplate <class OS>
74110496Ssteve.reinhardt@amd.comSyscallReturn
74211856Sbrandon.potter@amd.comreadlinkatFunc(SyscallDesc *desc, int callnum, Process *process,
74311856Sbrandon.potter@amd.com               ThreadContext *tc)
74411856Sbrandon.potter@amd.com{
74511856Sbrandon.potter@amd.com    int index = 0;
74611856Sbrandon.potter@amd.com    int dirfd = process->getSyscallArg(tc, index);
74710930Sbrandon.potter@amd.com    if (dirfd != OS::TGT_AT_FDCWD)
7489141Smarc.orr@gmail.com        warn("openat: first argument not AT_FDCWD; unlikely to work");
749360SN/A    return readlinkFunc(desc, callnum, process, tc, 1);
750360SN/A}
751360SN/A
75211907SBrandon.Potter@amd.com/// Target renameat() handler.
75313995Sbrandon.potter@amd.comtemplate <class OS>
754360SN/ASyscallReturn
75511907SBrandon.Potter@amd.comrenameatFunc(SyscallDesc *desc, int callnum, Process *process,
75613995Sbrandon.potter@amd.com             ThreadContext *tc)
75711907SBrandon.Potter@amd.com{
75811907SBrandon.Potter@amd.com    int index = 0;
75911907SBrandon.Potter@amd.com
76011907SBrandon.Potter@amd.com    int olddirfd = process->getSyscallArg(tc, index);
76111907SBrandon.Potter@amd.com    if (olddirfd != OS::TGT_AT_FDCWD)
76211907SBrandon.Potter@amd.com        warn("renameat: first argument not AT_FDCWD; unlikely to work");
76311907SBrandon.Potter@amd.com
76411907SBrandon.Potter@amd.com    std::string old_name;
76511907SBrandon.Potter@amd.com
76611907SBrandon.Potter@amd.com    if (!tc->getMemProxy().tryReadString(old_name,
76711907SBrandon.Potter@amd.com                                         process->getSyscallArg(tc, index)))
76811907SBrandon.Potter@amd.com        return -EFAULT;
76911907SBrandon.Potter@amd.com
770360SN/A    int newdirfd = process->getSyscallArg(tc, index);
77111907SBrandon.Potter@amd.com    if (newdirfd != OS::TGT_AT_FDCWD)
7721458SN/A        warn("renameat: third argument not AT_FDCWD; unlikely to work");
773360SN/A
77411907SBrandon.Potter@amd.com    std::string new_name;
77511907SBrandon.Potter@amd.com
77611907SBrandon.Potter@amd.com    if (!tc->getMemProxy().tryReadString(new_name,
77711907SBrandon.Potter@amd.com                                         process->getSyscallArg(tc, index)))
77811907SBrandon.Potter@amd.com        return -EFAULT;
77911907SBrandon.Potter@amd.com
78011907SBrandon.Potter@amd.com    // Adjust path for current working directory
78111907SBrandon.Potter@amd.com    old_name = process->fullPath(old_name);
78211907SBrandon.Potter@amd.com    new_name = process->fullPath(new_name);
78311907SBrandon.Potter@amd.com
784360SN/A    int result = rename(old_name.c_str(), new_name.c_str());
78511907SBrandon.Potter@amd.com    return (result == -1) ? -errno : result;
78611907SBrandon.Potter@amd.com}
78711907SBrandon.Potter@amd.com
788360SN/A/// Target sysinfo() handler.
789360SN/Atemplate <class OS>
79011907SBrandon.Potter@amd.comSyscallReturn
79111907SBrandon.Potter@amd.comsysinfoFunc(SyscallDesc *desc, int callnum, Process *process,
79211907SBrandon.Potter@amd.com            ThreadContext *tc)
79311907SBrandon.Potter@amd.com{
794360SN/A
79511907SBrandon.Potter@amd.com    int index = 0;
796360SN/A    TypedBufferArg<typename OS::tgt_sysinfo>
797360SN/A        sysinfo(process->getSyscallArg(tc, index));
79811907SBrandon.Potter@amd.com
7993669Sbinkertn@umich.edu    sysinfo->uptime = seconds_since_epoch;
80011907SBrandon.Potter@amd.com    sysinfo->totalram = process->system->memSize();
80111907SBrandon.Potter@amd.com    sysinfo->mem_unit = 1;
80211907SBrandon.Potter@amd.com
80311907SBrandon.Potter@amd.com    sysinfo.copyOut(tc->getMemProxy());
80411907SBrandon.Potter@amd.com
80511907SBrandon.Potter@amd.com    return 0;
80611907SBrandon.Potter@amd.com}
80711907SBrandon.Potter@amd.com
80811907SBrandon.Potter@amd.com/// Target chmod() handler.
80911907SBrandon.Potter@amd.comtemplate <class OS>
81011907SBrandon.Potter@amd.comSyscallReturn
81111907SBrandon.Potter@amd.comchmodFunc(SyscallDesc *desc, int callnum, Process *process,
81213883Sdavid.hashe@amd.com          ThreadContext *tc)
81313883Sdavid.hashe@amd.com{
81413883Sdavid.hashe@amd.com    std::string path;
81513883Sdavid.hashe@amd.com
81613883Sdavid.hashe@amd.com    int index = 0;
81711907SBrandon.Potter@amd.com    if (!tc->getMemProxy().tryReadString(path,
81811907SBrandon.Potter@amd.com                process->getSyscallArg(tc, index))) {
81911907SBrandon.Potter@amd.com        return -EFAULT;
82011907SBrandon.Potter@amd.com    }
82111907SBrandon.Potter@amd.com
82213883Sdavid.hashe@amd.com    uint32_t mode = process->getSyscallArg(tc, index);
82313883Sdavid.hashe@amd.com    mode_t hostMode = 0;
82411907SBrandon.Potter@amd.com
8251706SN/A    // XXX translate mode flags via OS::something???
82611907SBrandon.Potter@amd.com    hostMode = mode;
82711907SBrandon.Potter@amd.com
82811907SBrandon.Potter@amd.com    // Adjust path for current working directory
82911907SBrandon.Potter@amd.com    path = process->fullPath(path);
83011907SBrandon.Potter@amd.com
83111907SBrandon.Potter@amd.com    // do the chmod
83213883Sdavid.hashe@amd.com    int result = chmod(path.c_str(), hostMode);
83313883Sdavid.hashe@amd.com    if (result < 0)
83411907SBrandon.Potter@amd.com        return -errno;
83511907SBrandon.Potter@amd.com
83611907SBrandon.Potter@amd.com    return 0;
83711907SBrandon.Potter@amd.com}
83813883Sdavid.hashe@amd.com
83913995Sbrandon.potter@amd.com
84010496Ssteve.reinhardt@amd.com/// Target fchmod() handler.
84111907SBrandon.Potter@amd.comtemplate <class OS>
84211907SBrandon.Potter@amd.comSyscallReturn
84311907SBrandon.Potter@amd.comfchmodFunc(SyscallDesc *desc, int callnum, Process *p, ThreadContext *tc)
84411907SBrandon.Potter@amd.com{
84510496Ssteve.reinhardt@amd.com    int index = 0;
84610496Ssteve.reinhardt@amd.com    int tgt_fd = p->getSyscallArg(tc, index);
84711907SBrandon.Potter@amd.com    uint32_t mode = p->getSyscallArg(tc, index);
84813883Sdavid.hashe@amd.com
84913883Sdavid.hashe@amd.com    auto ffdp = std::dynamic_pointer_cast<FileFDEntry>((*p->fds)[tgt_fd]);
85013883Sdavid.hashe@amd.com    if (!ffdp)
85113883Sdavid.hashe@amd.com        return -EBADF;
85213883Sdavid.hashe@amd.com    int sim_fd = ffdp->getSimFD();
85313883Sdavid.hashe@amd.com
85413883Sdavid.hashe@amd.com    mode_t hostMode = mode;
85513883Sdavid.hashe@amd.com
85613883Sdavid.hashe@amd.com    int result = fchmod(sim_fd, hostMode);
85713883Sdavid.hashe@amd.com
85813883Sdavid.hashe@amd.com    return (result < 0) ? -errno : 0;
85913883Sdavid.hashe@amd.com}
86013883Sdavid.hashe@amd.com
86113883Sdavid.hashe@amd.com/// Target mremap() handler.
86213883Sdavid.hashe@amd.comtemplate <class OS>
86313883Sdavid.hashe@amd.comSyscallReturn
86413883Sdavid.hashe@amd.commremapFunc(SyscallDesc *desc, int callnum, Process *process, ThreadContext *tc)
86513883Sdavid.hashe@amd.com{
86613883Sdavid.hashe@amd.com    int index = 0;
86713883Sdavid.hashe@amd.com    Addr start = process->getSyscallArg(tc, index);
86813883Sdavid.hashe@amd.com    uint64_t old_length = process->getSyscallArg(tc, index);
86913883Sdavid.hashe@amd.com    uint64_t new_length = process->getSyscallArg(tc, index);
87011907SBrandon.Potter@amd.com    uint64_t flags = process->getSyscallArg(tc, index);
87111907SBrandon.Potter@amd.com    uint64_t provided_address = 0;
87213883Sdavid.hashe@amd.com    bool use_provided_address = flags & OS::TGT_MREMAP_FIXED;
87311907SBrandon.Potter@amd.com
87413994Santhony.gutierrez@amd.com    if (use_provided_address)
87511907SBrandon.Potter@amd.com        provided_address = process->getSyscallArg(tc, index);
87613883Sdavid.hashe@amd.com
87713883Sdavid.hashe@amd.com    if ((start % TheISA::PageBytes != 0) ||
87813883Sdavid.hashe@amd.com        (provided_address % TheISA::PageBytes != 0)) {
87913883Sdavid.hashe@amd.com        warn("mremap failing: arguments not page aligned");
88011907SBrandon.Potter@amd.com        return -EINVAL;
88111907SBrandon.Potter@amd.com    }
88213883Sdavid.hashe@amd.com
88313883Sdavid.hashe@amd.com    new_length = roundUp(new_length, TheISA::PageBytes);
88411907SBrandon.Potter@amd.com
88511907SBrandon.Potter@amd.com    if (new_length > old_length) {
88611907SBrandon.Potter@amd.com        if ((start + old_length) == process->mmap_end &&
88713883Sdavid.hashe@amd.com            (!use_provided_address || provided_address == start)) {
88813883Sdavid.hashe@amd.com            uint64_t diff = new_length - old_length;
88913883Sdavid.hashe@amd.com            process->allocateMem(process->mmap_end, diff);
89011907SBrandon.Potter@amd.com            process->mmap_end += diff;
89111907SBrandon.Potter@amd.com            return start;
892360SN/A        } else {
89311907SBrandon.Potter@amd.com            if (!use_provided_address && !(flags & OS::TGT_MREMAP_MAYMOVE)) {
89411907SBrandon.Potter@amd.com                warn("can't remap here and MREMAP_MAYMOVE flag not set\n");
89511907SBrandon.Potter@amd.com                return -ENOMEM;
89611907SBrandon.Potter@amd.com            } else {
89711907SBrandon.Potter@amd.com                uint64_t new_start = use_provided_address ?
89811907SBrandon.Potter@amd.com                    provided_address : process->mmap_end;
89911907SBrandon.Potter@amd.com                process->pTable->remap(start, old_length, new_start);
90011907SBrandon.Potter@amd.com                warn("mremapping to new vaddr %08p-%08p, adding %d\n",
90111907SBrandon.Potter@amd.com                     new_start, new_start + new_length,
90211907SBrandon.Potter@amd.com                     new_length - old_length);
90313883Sdavid.hashe@amd.com                // add on the remaining unallocated pages
90413883Sdavid.hashe@amd.com                process->allocateMem(new_start + old_length,
90513883Sdavid.hashe@amd.com                                     new_length - old_length,
90611907SBrandon.Potter@amd.com                                     use_provided_address /* clobber */);
907360SN/A                if (!use_provided_address)
908360SN/A                    process->mmap_end += new_length;
90910027SChris.Adeniyi-Jones@arm.com                if (use_provided_address &&
91010027SChris.Adeniyi-Jones@arm.com                    new_start + new_length > process->mmap_end) {
91110027SChris.Adeniyi-Jones@arm.com                    // something fishy going on here, at least notify the user
91213995Sbrandon.potter@amd.com                    // @todo: increase mmap_end?
91310027SChris.Adeniyi-Jones@arm.com                    warn("mmap region limit exceeded with MREMAP_FIXED\n");
91413995Sbrandon.potter@amd.com                }
91510027SChris.Adeniyi-Jones@arm.com                warn("returning %08p as start\n", new_start);
91610027SChris.Adeniyi-Jones@arm.com                return new_start;
91710027SChris.Adeniyi-Jones@arm.com            }
91810027SChris.Adeniyi-Jones@arm.com        }
91910027SChris.Adeniyi-Jones@arm.com    } else {
92013995Sbrandon.potter@amd.com        if (use_provided_address && provided_address != start)
92110027SChris.Adeniyi-Jones@arm.com            process->pTable->remap(start, new_length, provided_address);
92213995Sbrandon.potter@amd.com        process->pTable->unmap(start + new_length, old_length - new_length);
92310027SChris.Adeniyi-Jones@arm.com        return use_provided_address ? provided_address : start;
92410027SChris.Adeniyi-Jones@arm.com    }
92510633Smichaelupton@gmail.com}
92610633Smichaelupton@gmail.com
92710633Smichaelupton@gmail.com/// Target stat() handler.
92813995Sbrandon.potter@amd.comtemplate <class OS>
92910633Smichaelupton@gmail.comSyscallReturn
93010633Smichaelupton@gmail.comstatFunc(SyscallDesc *desc, int callnum, Process *process,
93113995Sbrandon.potter@amd.com         ThreadContext *tc)
93210633Smichaelupton@gmail.com{
93310633Smichaelupton@gmail.com    std::string path;
93410633Smichaelupton@gmail.com
93510633Smichaelupton@gmail.com    int index = 0;
93613995Sbrandon.potter@amd.com    if (!tc->getMemProxy().tryReadString(path,
93710633Smichaelupton@gmail.com                process->getSyscallArg(tc, index))) {
93810633Smichaelupton@gmail.com        return -EFAULT;
93910203SAli.Saidi@ARM.com    }
94010203SAli.Saidi@ARM.com    Addr bufPtr = process->getSyscallArg(tc, index);
94110203SAli.Saidi@ARM.com
94213995Sbrandon.potter@amd.com    // Adjust path for current working directory
94310203SAli.Saidi@ARM.com    path = process->fullPath(path);
94410203SAli.Saidi@ARM.com
94513995Sbrandon.potter@amd.com    struct stat hostBuf;
94610203SAli.Saidi@ARM.com    int result = stat(path.c_str(), &hostBuf);
94710203SAli.Saidi@ARM.com
94810203SAli.Saidi@ARM.com    if (result < 0)
94913995Sbrandon.potter@amd.com        return -errno;
95010203SAli.Saidi@ARM.com
95110203SAli.Saidi@ARM.com    copyOutStatBuf<OS>(tc->getMemProxy(), bufPtr, &hostBuf);
95210203SAli.Saidi@ARM.com
95310203SAli.Saidi@ARM.com    return 0;
95410203SAli.Saidi@ARM.com}
95513995Sbrandon.potter@amd.com
95610203SAli.Saidi@ARM.com
95710203SAli.Saidi@ARM.com/// Target stat64() handler.
95813995Sbrandon.potter@amd.comtemplate <class OS>
95910203SAli.Saidi@ARM.comSyscallReturn
96010203SAli.Saidi@ARM.comstat64Func(SyscallDesc *desc, int callnum, Process *process,
96110203SAli.Saidi@ARM.com           ThreadContext *tc)
96213995Sbrandon.potter@amd.com{
96310203SAli.Saidi@ARM.com    std::string path;
96410203SAli.Saidi@ARM.com
96510850SGiacomo.Gabrielli@arm.com    int index = 0;
96610850SGiacomo.Gabrielli@arm.com    if (!tc->getMemProxy().tryReadString(path,
96710850SGiacomo.Gabrielli@arm.com                process->getSyscallArg(tc, index)))
96813995Sbrandon.potter@amd.com        return -EFAULT;
96910850SGiacomo.Gabrielli@arm.com    Addr bufPtr = process->getSyscallArg(tc, index);
97010850SGiacomo.Gabrielli@arm.com
97113995Sbrandon.potter@amd.com    // Adjust path for current working directory
97210850SGiacomo.Gabrielli@arm.com    path = process->fullPath(path);
97310850SGiacomo.Gabrielli@arm.com
97410850SGiacomo.Gabrielli@arm.com#if NO_STAT64
97510850SGiacomo.Gabrielli@arm.com    struct stat  hostBuf;
97610850SGiacomo.Gabrielli@arm.com    int result = stat(path.c_str(), &hostBuf);
97710850SGiacomo.Gabrielli@arm.com#else
97810850SGiacomo.Gabrielli@arm.com    struct stat64 hostBuf;
97910850SGiacomo.Gabrielli@arm.com    int result = stat64(path.c_str(), &hostBuf);
98010850SGiacomo.Gabrielli@arm.com#endif
98110850SGiacomo.Gabrielli@arm.com
98210850SGiacomo.Gabrielli@arm.com    if (result < 0)
98310850SGiacomo.Gabrielli@arm.com        return -errno;
98410850SGiacomo.Gabrielli@arm.com
98510850SGiacomo.Gabrielli@arm.com    copyOutStat64Buf<OS>(tc->getMemProxy(), bufPtr, &hostBuf);
98610850SGiacomo.Gabrielli@arm.com
98710850SGiacomo.Gabrielli@arm.com    return 0;
98810850SGiacomo.Gabrielli@arm.com}
98910850SGiacomo.Gabrielli@arm.com
99010850SGiacomo.Gabrielli@arm.com
99110850SGiacomo.Gabrielli@arm.com/// Target fstatat64() handler.
99210850SGiacomo.Gabrielli@arm.comtemplate <class OS>
99313883Sdavid.hashe@amd.comSyscallReturn
99413883Sdavid.hashe@amd.comfstatat64Func(SyscallDesc *desc, int callnum, Process *process,
99513883Sdavid.hashe@amd.com              ThreadContext *tc)
99610850SGiacomo.Gabrielli@arm.com{
99710850SGiacomo.Gabrielli@arm.com    int index = 0;
99810850SGiacomo.Gabrielli@arm.com    int dirfd = process->getSyscallArg(tc, index);
99910850SGiacomo.Gabrielli@arm.com    if (dirfd != OS::TGT_AT_FDCWD)
100010850SGiacomo.Gabrielli@arm.com        warn("fstatat64: first argument not AT_FDCWD; unlikely to work");
10016640Svince@csl.cornell.edu
10026640Svince@csl.cornell.edu    std::string path;
10036640Svince@csl.cornell.edu    if (!tc->getMemProxy().tryReadString(path,
100413995Sbrandon.potter@amd.com                process->getSyscallArg(tc, index)))
10056640Svince@csl.cornell.edu        return -EFAULT;
10066701Sgblack@eecs.umich.edu    Addr bufPtr = process->getSyscallArg(tc, index);
100713995Sbrandon.potter@amd.com
100813995Sbrandon.potter@amd.com    // Adjust path for current working directory
10096701Sgblack@eecs.umich.edu    path = process->fullPath(path);
101010793Sbrandon.potter@amd.com
10116640Svince@csl.cornell.edu#if NO_STAT64
101211758Sbrandon.potter@amd.com    struct stat  hostBuf;
101311758Sbrandon.potter@amd.com    int result = stat(path.c_str(), &hostBuf);
101411758Sbrandon.potter@amd.com#else
10156640Svince@csl.cornell.edu    struct stat64 hostBuf;
10168706Sandreas.hansson@arm.com    int result = stat64(path.c_str(), &hostBuf);
10176640Svince@csl.cornell.edu#endif
10186701Sgblack@eecs.umich.edu
10196640Svince@csl.cornell.edu    if (result < 0)
1020360SN/A        return -errno;
10211999SN/A
10221999SN/A    copyOutStat64Buf<OS>(tc->getMemProxy(), bufPtr, &hostBuf);
10231999SN/A
102413995Sbrandon.potter@amd.com    return 0;
10251999SN/A}
10261999SN/A
102713995Sbrandon.potter@amd.com
10281999SN/A/// Target fstat64() handler.
10296701Sgblack@eecs.umich.edutemplate <class OS>
10308852Sandreas.hansson@arm.comSyscallReturn
10316701Sgblack@eecs.umich.edufstat64Func(SyscallDesc *desc, int callnum, Process *p, ThreadContext *tc)
10321999SN/A{
10336701Sgblack@eecs.umich.edu    int index = 0;
10341999SN/A    int tgt_fd = p->getSyscallArg(tc, index);
10356701Sgblack@eecs.umich.edu    Addr bufPtr = p->getSyscallArg(tc, index);
10361999SN/A
10371999SN/A    auto ffdp = std::dynamic_pointer_cast<FileFDEntry>((*p->fds)[tgt_fd]);
10381999SN/A    if (!ffdp)
10391999SN/A        return -EBADF;
10401999SN/A    int sim_fd = ffdp->getSimFD();
104113883Sdavid.hashe@amd.com
104213883Sdavid.hashe@amd.com#if NO_STAT64
10433669Sbinkertn@umich.edu    struct stat  hostBuf;
10441999SN/A    int result = fstat(sim_fd, &hostBuf);
10451999SN/A#else
10461999SN/A    struct stat64  hostBuf;
10472218SN/A    int result = fstat64(sim_fd, &hostBuf);
10481999SN/A#endif
10491999SN/A
10501999SN/A    if (result < 0)
10511999SN/A        return -errno;
105213570Sbrandon.potter@amd.com
105313570Sbrandon.potter@amd.com    copyOutStat64Buf<OS>(tc->getMemProxy(), bufPtr, &hostBuf, (sim_fd == 1));
105413995Sbrandon.potter@amd.com
105513570Sbrandon.potter@amd.com    return 0;
105613570Sbrandon.potter@amd.com}
105713995Sbrandon.potter@amd.com
105813570Sbrandon.potter@amd.com
105913570Sbrandon.potter@amd.com/// Target lstat() handler.
106013570Sbrandon.potter@amd.comtemplate <class OS>
106113570Sbrandon.potter@amd.comSyscallReturn
106213570Sbrandon.potter@amd.comlstatFunc(SyscallDesc *desc, int callnum, Process *process,
106313570Sbrandon.potter@amd.com          ThreadContext *tc)
106413570Sbrandon.potter@amd.com{
106513570Sbrandon.potter@amd.com    std::string path;
106613570Sbrandon.potter@amd.com
106713570Sbrandon.potter@amd.com    int index = 0;
106813570Sbrandon.potter@amd.com    if (!tc->getMemProxy().tryReadString(path,
106913570Sbrandon.potter@amd.com                process->getSyscallArg(tc, index))) {
107013570Sbrandon.potter@amd.com        return -EFAULT;
107113570Sbrandon.potter@amd.com    }
107213570Sbrandon.potter@amd.com    Addr bufPtr = process->getSyscallArg(tc, index);
107313570Sbrandon.potter@amd.com
107413570Sbrandon.potter@amd.com    // Adjust path for current working directory
107513570Sbrandon.potter@amd.com    path = process->fullPath(path);
107613570Sbrandon.potter@amd.com
107713570Sbrandon.potter@amd.com    struct stat hostBuf;
107813570Sbrandon.potter@amd.com    int result = lstat(path.c_str(), &hostBuf);
107913570Sbrandon.potter@amd.com
108013570Sbrandon.potter@amd.com    if (result < 0)
108113570Sbrandon.potter@amd.com        return -errno;
108213570Sbrandon.potter@amd.com
108313570Sbrandon.potter@amd.com    copyOutStatBuf<OS>(tc->getMemProxy(), bufPtr, &hostBuf);
108413570Sbrandon.potter@amd.com
108513570Sbrandon.potter@amd.com    return 0;
108613570Sbrandon.potter@amd.com}
108713570Sbrandon.potter@amd.com
108813570Sbrandon.potter@amd.com/// Target lstat64() handler.
108913570Sbrandon.potter@amd.comtemplate <class OS>
109013570Sbrandon.potter@amd.comSyscallReturn
109113570Sbrandon.potter@amd.comlstat64Func(SyscallDesc *desc, int callnum, Process *process,
109213570Sbrandon.potter@amd.com            ThreadContext *tc)
109313570Sbrandon.potter@amd.com{
109413570Sbrandon.potter@amd.com    std::string path;
109513570Sbrandon.potter@amd.com
109613570Sbrandon.potter@amd.com    int index = 0;
109713570Sbrandon.potter@amd.com    if (!tc->getMemProxy().tryReadString(path,
109813570Sbrandon.potter@amd.com                process->getSyscallArg(tc, index))) {
109913570Sbrandon.potter@amd.com        return -EFAULT;
110013570Sbrandon.potter@amd.com    }
110113570Sbrandon.potter@amd.com    Addr bufPtr = process->getSyscallArg(tc, index);
110213570Sbrandon.potter@amd.com
110313570Sbrandon.potter@amd.com    // Adjust path for current working directory
110413570Sbrandon.potter@amd.com    path = process->fullPath(path);
110513570Sbrandon.potter@amd.com
110613570Sbrandon.potter@amd.com#if NO_STAT64
110713570Sbrandon.potter@amd.com    struct stat hostBuf;
110813570Sbrandon.potter@amd.com    int result = lstat(path.c_str(), &hostBuf);
110913570Sbrandon.potter@amd.com#else
111013570Sbrandon.potter@amd.com    struct stat64 hostBuf;
111113570Sbrandon.potter@amd.com    int result = lstat64(path.c_str(), &hostBuf);
111213570Sbrandon.potter@amd.com#endif
111313570Sbrandon.potter@amd.com
111413570Sbrandon.potter@amd.com    if (result < 0)
111513570Sbrandon.potter@amd.com        return -errno;
111613570Sbrandon.potter@amd.com
111713570Sbrandon.potter@amd.com    copyOutStat64Buf<OS>(tc->getMemProxy(), bufPtr, &hostBuf);
111813570Sbrandon.potter@amd.com
111913570Sbrandon.potter@amd.com    return 0;
112013570Sbrandon.potter@amd.com}
112113570Sbrandon.potter@amd.com
112213570Sbrandon.potter@amd.com/// Target fstat() handler.
112313570Sbrandon.potter@amd.comtemplate <class OS>
112413570Sbrandon.potter@amd.comSyscallReturn
112513570Sbrandon.potter@amd.comfstatFunc(SyscallDesc *desc, int callnum, Process *p, ThreadContext *tc)
112613570Sbrandon.potter@amd.com{
11271999SN/A    int index = 0;
11281999SN/A    int tgt_fd = p->getSyscallArg(tc, index);
11291999SN/A    Addr bufPtr = p->getSyscallArg(tc, index);
11301999SN/A
113113995Sbrandon.potter@amd.com    DPRINTF_SYSCALL(Verbose, "fstat(%d, ...)\n", tgt_fd);
11321999SN/A
11336701Sgblack@eecs.umich.edu    auto ffdp = std::dynamic_pointer_cast<FileFDEntry>((*p->fds)[tgt_fd]);
113413995Sbrandon.potter@amd.com    if (!ffdp)
113511856Sbrandon.potter@amd.com        return -EBADF;
113611856Sbrandon.potter@amd.com    int sim_fd = ffdp->getSimFD();
113710931Sbrandon.potter@amd.com
113811856Sbrandon.potter@amd.com    struct stat hostBuf;
113911856Sbrandon.potter@amd.com    int result = fstat(sim_fd, &hostBuf);
11401999SN/A
114111856Sbrandon.potter@amd.com    if (result < 0)
11421999SN/A        return -errno;
114311856Sbrandon.potter@amd.com
11441999SN/A    copyOutStatBuf<OS>(tc->getMemProxy(), bufPtr, &hostBuf, (sim_fd == 1));
114511856Sbrandon.potter@amd.com
11461999SN/A    return 0;
114711856Sbrandon.potter@amd.com}
11481999SN/A
11491999SN/A
11505877Shsul@eecs.umich.edu/// Target statfs() handler.
11515877Shsul@eecs.umich.edutemplate <class OS>
11525877Shsul@eecs.umich.eduSyscallReturn
115313995Sbrandon.potter@amd.comstatfsFunc(SyscallDesc *desc, int callnum, Process *process,
11545877Shsul@eecs.umich.edu           ThreadContext *tc)
11556701Sgblack@eecs.umich.edu{
115613995Sbrandon.potter@amd.com#if NO_STATFS
11576701Sgblack@eecs.umich.edu    warn("Host OS cannot support calls to statfs. Ignoring syscall");
11586701Sgblack@eecs.umich.edu#else
11596701Sgblack@eecs.umich.edu    std::string path;
11606701Sgblack@eecs.umich.edu
116110027SChris.Adeniyi-Jones@arm.com    int index = 0;
116210027SChris.Adeniyi-Jones@arm.com    if (!tc->getMemProxy().tryReadString(path,
116310027SChris.Adeniyi-Jones@arm.com                process->getSyscallArg(tc, index))) {
116410027SChris.Adeniyi-Jones@arm.com        return -EFAULT;
116510027SChris.Adeniyi-Jones@arm.com    }
11665877Shsul@eecs.umich.edu    Addr bufPtr = process->getSyscallArg(tc, index);
116710318Sandreas.hansson@arm.com
116810318Sandreas.hansson@arm.com    // Adjust path for current working directory
11695877Shsul@eecs.umich.edu    path = process->fullPath(path);
11705877Shsul@eecs.umich.edu
11715877Shsul@eecs.umich.edu    struct statfs hostBuf;
11725877Shsul@eecs.umich.edu    int result = statfs(path.c_str(), &hostBuf);
117310486Stjablin@gmail.com
117410486Stjablin@gmail.com    if (result < 0)
11755877Shsul@eecs.umich.edu        return -errno;
117611905SBrandon.Potter@amd.com
117711905SBrandon.Potter@amd.com    copyOutStatfsBuf<OS>(tc->getMemProxy(), bufPtr, &hostBuf);
117811905SBrandon.Potter@amd.com#endif
117911905SBrandon.Potter@amd.com    return 0;
118010027SChris.Adeniyi-Jones@arm.com}
118112206Srico.amslinger@informatik.uni-augsburg.de
118212206Srico.amslinger@informatik.uni-augsburg.de
11835877Shsul@eecs.umich.edu/// Target fstatfs() handler.
118411905SBrandon.Potter@amd.comtemplate <class OS>
118511905SBrandon.Potter@amd.comSyscallReturn
11865877Shsul@eecs.umich.edufstatfsFunc(SyscallDesc *desc, int callnum, Process *p, ThreadContext *tc)
11875877Shsul@eecs.umich.edu{
118810027SChris.Adeniyi-Jones@arm.com    int index = 0;
11895877Shsul@eecs.umich.edu    int tgt_fd = p->getSyscallArg(tc, index);
11905877Shsul@eecs.umich.edu    Addr bufPtr = p->getSyscallArg(tc, index);
11915877Shsul@eecs.umich.edu
119212206Srico.amslinger@informatik.uni-augsburg.de    auto ffdp = std::dynamic_pointer_cast<FileFDEntry>((*p->fds)[tgt_fd]);
119312206Srico.amslinger@informatik.uni-augsburg.de    if (!ffdp)
119412206Srico.amslinger@informatik.uni-augsburg.de        return -EBADF;
119512206Srico.amslinger@informatik.uni-augsburg.de    int sim_fd = ffdp->getSimFD();
119612206Srico.amslinger@informatik.uni-augsburg.de
119712206Srico.amslinger@informatik.uni-augsburg.de    struct statfs hostBuf;
119812206Srico.amslinger@informatik.uni-augsburg.de    int result = fstatfs(sim_fd, &hostBuf);
119912206Srico.amslinger@informatik.uni-augsburg.de
120012206Srico.amslinger@informatik.uni-augsburg.de    if (result < 0)
120110027SChris.Adeniyi-Jones@arm.com        return -errno;
120210027SChris.Adeniyi-Jones@arm.com
120310027SChris.Adeniyi-Jones@arm.com    copyOutStatfsBuf<OS>(tc->getMemProxy(), bufPtr, &hostBuf);
120410027SChris.Adeniyi-Jones@arm.com
12055877Shsul@eecs.umich.edu    return 0;
120610027SChris.Adeniyi-Jones@arm.com}
120710027SChris.Adeniyi-Jones@arm.com
120810027SChris.Adeniyi-Jones@arm.com
120910027SChris.Adeniyi-Jones@arm.com/// Target writev() handler.
121012206Srico.amslinger@informatik.uni-augsburg.detemplate <class OS>
121112206Srico.amslinger@informatik.uni-augsburg.deSyscallReturn
121212206Srico.amslinger@informatik.uni-augsburg.dewritevFunc(SyscallDesc *desc, int callnum, Process *p, ThreadContext *tc)
121312206Srico.amslinger@informatik.uni-augsburg.de{
121410027SChris.Adeniyi-Jones@arm.com    int index = 0;
121510027SChris.Adeniyi-Jones@arm.com    int tgt_fd = p->getSyscallArg(tc, index);
121610027SChris.Adeniyi-Jones@arm.com
121710027SChris.Adeniyi-Jones@arm.com    auto hbfdp = std::dynamic_pointer_cast<HBFDEntry>((*p->fds)[tgt_fd]);
121810027SChris.Adeniyi-Jones@arm.com    if (!hbfdp)
121910027SChris.Adeniyi-Jones@arm.com        return -EBADF;
12205877Shsul@eecs.umich.edu    int sim_fd = hbfdp->getSimFD();
12215877Shsul@eecs.umich.edu
12225877Shsul@eecs.umich.edu    SETranslatingPortProxy &prox = tc->getMemProxy();
122310027SChris.Adeniyi-Jones@arm.com    uint64_t tiov_base = p->getSyscallArg(tc, index);
122410027SChris.Adeniyi-Jones@arm.com    size_t count = p->getSyscallArg(tc, index);
12258601Ssteve.reinhardt@amd.com    struct iovec hiov[count];
122610027SChris.Adeniyi-Jones@arm.com    for (size_t i = 0; i < count; ++i) {
12275877Shsul@eecs.umich.edu        typename OS::tgt_iovec tiov;
12285877Shsul@eecs.umich.edu
12291999SN/A        prox.readBlob(tiov_base + i*sizeof(typename OS::tgt_iovec),
1230378SN/A                      (uint8_t*)&tiov, sizeof(typename OS::tgt_iovec));
1231360SN/A        hiov[i].iov_len = TheISA::gtoh(tiov.iov_len);
12321450SN/A        hiov[i].iov_base = new char [hiov[i].iov_len];
123313995Sbrandon.potter@amd.com        prox.readBlob(TheISA::gtoh(tiov.iov_base), (uint8_t *)hiov[i].iov_base,
1234360SN/A                      hiov[i].iov_len);
1235360SN/A    }
123613995Sbrandon.potter@amd.com
1237360SN/A    int result = writev(sim_fd, hiov, count);
12386701Sgblack@eecs.umich.edu
12398852Sandreas.hansson@arm.com    for (size_t i = 0; i < count; ++i)
12406701Sgblack@eecs.umich.edu        delete [] (char *)hiov[i].iov_base;
12416701Sgblack@eecs.umich.edu
12426701Sgblack@eecs.umich.edu    if (result < 0)
12436701Sgblack@eecs.umich.edu        return -errno;
1244360SN/A
124513883Sdavid.hashe@amd.com    return result;
124613883Sdavid.hashe@amd.com}
12473669Sbinkertn@umich.edu
1248360SN/A/// Real mmap handler.
1249360SN/Atemplate <class OS>
1250360SN/ASyscallReturn
1251360SN/AmmapImpl(SyscallDesc *desc, int num, Process *p, ThreadContext *tc,
12522218SN/A         bool is_mmap2)
1253360SN/A{
12548706Sandreas.hansson@arm.com    int index = 0;
1255360SN/A    Addr start = p->getSyscallArg(tc, index);
12561458SN/A    uint64_t length = p->getSyscallArg(tc, index);
1257360SN/A    int prot = p->getSyscallArg(tc, index);
1258360SN/A    int tgt_flags = p->getSyscallArg(tc, index);
1259360SN/A    int tgt_fd = p->getSyscallArg(tc, index);
12605074Ssaidi@eecs.umich.edu    int offset = p->getSyscallArg(tc, index);
12615074Ssaidi@eecs.umich.edu
12625074Ssaidi@eecs.umich.edu    if (is_mmap2)
126313995Sbrandon.potter@amd.com        offset *= TheISA::PageBytes;
12645074Ssaidi@eecs.umich.edu
12655074Ssaidi@eecs.umich.edu    if (start & (TheISA::PageBytes - 1) ||
126613995Sbrandon.potter@amd.com        offset & (TheISA::PageBytes - 1) ||
12675074Ssaidi@eecs.umich.edu        (tgt_flags & OS::TGT_MAP_PRIVATE &&
12686701Sgblack@eecs.umich.edu         tgt_flags & OS::TGT_MAP_SHARED) ||
12698852Sandreas.hansson@arm.com        (!(tgt_flags & OS::TGT_MAP_PRIVATE) &&
12706701Sgblack@eecs.umich.edu         !(tgt_flags & OS::TGT_MAP_SHARED)) ||
12715074Ssaidi@eecs.umich.edu        !length) {
12726701Sgblack@eecs.umich.edu        return -EINVAL;
12735074Ssaidi@eecs.umich.edu    }
127413883Sdavid.hashe@amd.com
127513883Sdavid.hashe@amd.com    if ((prot & PROT_WRITE) && (tgt_flags & OS::TGT_MAP_SHARED)) {
12765074Ssaidi@eecs.umich.edu        // With shared mmaps, there are two cases to consider:
12775208Ssaidi@eecs.umich.edu        // 1) anonymous: writes should modify the mapping and this should be
12785208Ssaidi@eecs.umich.edu        // visible to observers who share the mapping. Currently, it's
12795208Ssaidi@eecs.umich.edu        // difficult to update the shared mapping because there's no
12805208Ssaidi@eecs.umich.edu        // structure which maintains information about the which virtual
12815074Ssaidi@eecs.umich.edu        // memory areas are shared. If that structure existed, it would be
12825074Ssaidi@eecs.umich.edu        // possible to make the translations point to the same frames.
12835208Ssaidi@eecs.umich.edu        // 2) file-backed: writes should modify the mapping and the file
12845074Ssaidi@eecs.umich.edu        // which is backed by the mapping. The shared mapping problem is the
12855074Ssaidi@eecs.umich.edu        // same as what was mentioned about the anonymous mappings. For
12865074Ssaidi@eecs.umich.edu        // file-backed mappings, the writes to the file are difficult
12875074Ssaidi@eecs.umich.edu        // because it requires syncing what the mapping holds with the file
12888706Sandreas.hansson@arm.com        // that resides on the host system. So, any write on a real system
12895074Ssaidi@eecs.umich.edu        // would cause the change to be propagated to the file mapping at
12905074Ssaidi@eecs.umich.edu        // some point in the future (the inode is tracked along with the
12915074Ssaidi@eecs.umich.edu        // mapping). This isn't guaranteed to always happen, but it usually
12925074Ssaidi@eecs.umich.edu        // works well enough. The guarantee is provided by the msync system
12935074Ssaidi@eecs.umich.edu        // call. We could force the change through with shared mappings with
129410027SChris.Adeniyi-Jones@arm.com        // a call to msync, but that again would require more information
129510027SChris.Adeniyi-Jones@arm.com        // than we currently maintain.
129610027SChris.Adeniyi-Jones@arm.com        warn("mmap: writing to shared mmap region is currently "
129713995Sbrandon.potter@amd.com             "unsupported. The write succeeds on the target, but it "
129810027SChris.Adeniyi-Jones@arm.com             "will not be propagated to the host or shared mappings");
129910027SChris.Adeniyi-Jones@arm.com    }
130013995Sbrandon.potter@amd.com
130110027SChris.Adeniyi-Jones@arm.com    length = roundUp(length, TheISA::PageBytes);
130210027SChris.Adeniyi-Jones@arm.com
130310793Sbrandon.potter@amd.com    int sim_fd = -1;
130410027SChris.Adeniyi-Jones@arm.com    uint8_t *pmap = nullptr;
130510027SChris.Adeniyi-Jones@arm.com    if (!(tgt_flags & OS::TGT_MAP_ANONYMOUS)) {
130610027SChris.Adeniyi-Jones@arm.com        std::shared_ptr<FDEntry> fdep = (*p->fds)[tgt_fd];
130710027SChris.Adeniyi-Jones@arm.com
130810027SChris.Adeniyi-Jones@arm.com        auto dfdp = std::dynamic_pointer_cast<DeviceFDEntry>(fdep);
130910027SChris.Adeniyi-Jones@arm.com        if (dfdp) {
131010027SChris.Adeniyi-Jones@arm.com            EmulatedDriver *emul_driver = dfdp->getDriver();
131113883Sdavid.hashe@amd.com            return emul_driver->mmap(p, tc, start, length, prot,
131213883Sdavid.hashe@amd.com                                     tgt_flags, tgt_fd, offset);
131310027SChris.Adeniyi-Jones@arm.com        }
131410027SChris.Adeniyi-Jones@arm.com
131510027SChris.Adeniyi-Jones@arm.com        auto ffdp = std::dynamic_pointer_cast<FileFDEntry>(fdep);
131610027SChris.Adeniyi-Jones@arm.com        if (!ffdp)
131710027SChris.Adeniyi-Jones@arm.com            return -EBADF;
131810027SChris.Adeniyi-Jones@arm.com        sim_fd = ffdp->getSimFD();
131910027SChris.Adeniyi-Jones@arm.com
132010027SChris.Adeniyi-Jones@arm.com        pmap = (decltype(pmap))mmap(NULL, length, PROT_READ, MAP_PRIVATE,
132110027SChris.Adeniyi-Jones@arm.com                                    sim_fd, offset);
132210027SChris.Adeniyi-Jones@arm.com
132310027SChris.Adeniyi-Jones@arm.com        if (pmap == (decltype(pmap))-1) {
132410027SChris.Adeniyi-Jones@arm.com            warn("mmap: failed to map file into host address space");
132510027SChris.Adeniyi-Jones@arm.com            return -errno;
132610027SChris.Adeniyi-Jones@arm.com        }
132710027SChris.Adeniyi-Jones@arm.com    }
132810027SChris.Adeniyi-Jones@arm.com
132910027SChris.Adeniyi-Jones@arm.com    // Extend global mmap region if necessary. Note that we ignore the
133010027SChris.Adeniyi-Jones@arm.com    // start address unless MAP_FIXED is specified.
13311999SN/A    if (!(tgt_flags & OS::TGT_MAP_FIXED)) {
13321999SN/A        start = p->mmapGrowsDown() ? p->mmap_end - length : p->mmap_end;
13331999SN/A        p->mmap_end = p->mmapGrowsDown() ? start : p->mmap_end + length;
133413995Sbrandon.potter@amd.com    }
13351999SN/A
13366701Sgblack@eecs.umich.edu    DPRINTF_SYSCALL(Verbose, " mmap range is 0x%x - 0x%x\n",
133713995Sbrandon.potter@amd.com                    start, start + length - 1);
133811856Sbrandon.potter@amd.com
133911856Sbrandon.potter@amd.com    // We only allow mappings to overwrite existing mappings if
134010931Sbrandon.potter@amd.com    // TGT_MAP_FIXED is set. Otherwise it shouldn't be a problem
134111856Sbrandon.potter@amd.com    // because we ignore the start hint if TGT_MAP_FIXED is not set.
134211856Sbrandon.potter@amd.com    int clobber = tgt_flags & OS::TGT_MAP_FIXED;
13431999SN/A    if (clobber) {
134411856Sbrandon.potter@amd.com        for (auto tc : p->system->threadContexts) {
13451999SN/A            // If we might be overwriting old mappings, we need to
13462764Sstever@eecs.umich.edu            // invalidate potentially stale mappings out of the TLBs.
13472064SN/A            tc->getDTBPtr()->flushAll();
134810931Sbrandon.potter@amd.com            tc->getITBPtr()->flushAll();
13492064SN/A        }
13502064SN/A    }
135110931Sbrandon.potter@amd.com
13522064SN/A    // Allocate physical memory and map it in. If the page table is already
13531999SN/A    // mapped and clobber is not set, the simulator will issue throw a
13541999SN/A    // fatal and bail out of the simulation.
13552218SN/A    p->allocateMem(start, length, clobber);
13561999SN/A
135710931Sbrandon.potter@amd.com    // Transfer content into target address space.
13581999SN/A    SETranslatingPortProxy &tp = tc->getMemProxy();
13591999SN/A    if (tgt_flags & OS::TGT_MAP_ANONYMOUS) {
13601999SN/A        // In general, we should zero the mapped area for anonymous mappings,
13611999SN/A        // with something like:
13621999SN/A        //     tp.memsetBlob(start, 0, length);
1363378SN/A        // However, given that we don't support sparse mappings, and
1364360SN/A        // some applications can map a couple of gigabytes of space
13651450SN/A        // (intending sparse usage), that can get painfully expensive.
136613995Sbrandon.potter@amd.com        // Fortunately, since we don't properly implement munmap either,
1367360SN/A        // there's no danger of remapping used memory, so for now all
1368360SN/A        // newly mapped memory should already be zeroed so we can skip it.
136913995Sbrandon.potter@amd.com    } else {
1370360SN/A        // It is possible to mmap an area larger than a file, however
13716701Sgblack@eecs.umich.edu        // accessing unmapped portions the system triggers a "Bus error"
13728852Sandreas.hansson@arm.com        // on the host. We must know when to stop copying the file from
13736701Sgblack@eecs.umich.edu        // the host into the target address space.
13746701Sgblack@eecs.umich.edu        struct stat file_stat;
13756701Sgblack@eecs.umich.edu        if (fstat(sim_fd, &file_stat) > 0)
13766701Sgblack@eecs.umich.edu            fatal("mmap: cannot stat file");
1377360SN/A
137813883Sdavid.hashe@amd.com        // Copy the portion of the file that is resident. This requires
137913883Sdavid.hashe@amd.com        // checking both the mmap size and the filesize that we are
13803669Sbinkertn@umich.edu        // trying to mmap into this space; the mmap size also depends
1381360SN/A        // on the specified offset into the file.
1382360SN/A        uint64_t size = std::min((uint64_t)file_stat.st_size - offset,
1383360SN/A                                 length);
1384360SN/A        tp.writeBlob(start, pmap, size);
13851458SN/A
1386360SN/A        // Cleanup the mmap region before exiting this function.
13878706Sandreas.hansson@arm.com        munmap(pmap, length);
1388360SN/A
13891458SN/A        // Maintain the symbol table for dynamic executables.
1390360SN/A        // The loader will call mmap to map the images into its address
1391360SN/A        // space and we intercept that here. We can verify that we are
13921999SN/A        // executing inside the loader by checking the program counter value.
13931999SN/A        // XXX: with multiprogrammed workloads or multi-node configurations,
13941999SN/A        // this will not work since there is a single global symbol table.
139513995Sbrandon.potter@amd.com        ObjectFile *interpreter = p->getInterpreter();
13961999SN/A        if (interpreter) {
13971999SN/A            Addr text_start = interpreter->textBase();
139813995Sbrandon.potter@amd.com            Addr text_end = text_start + interpreter->textSize();
13991999SN/A
14006701Sgblack@eecs.umich.edu            Addr pc = tc->pcState().pc();
14018852Sandreas.hansson@arm.com
14026701Sgblack@eecs.umich.edu            if (pc >= text_start && pc < text_end) {
14036701Sgblack@eecs.umich.edu                std::shared_ptr<FDEntry> fdep = (*p->fds)[tgt_fd];
14046701Sgblack@eecs.umich.edu                auto ffdp = std::dynamic_pointer_cast<FileFDEntry>(fdep);
14056701Sgblack@eecs.umich.edu                ObjectFile *lib = createObjectFile(ffdp->getFileName());
14061999SN/A
140713883Sdavid.hashe@amd.com                if (lib) {
140813883Sdavid.hashe@amd.com                    lib->loadAllSymbols(debugSymbolTable,
14093669Sbinkertn@umich.edu                                        lib->textBase(), start);
14102764Sstever@eecs.umich.edu                }
14112064SN/A            }
14122064SN/A        }
14132064SN/A
14141999SN/A        // Note that we do not zero out the remainder of the mapping. This
14151999SN/A        // is done by a real system, but it probably will not affect
14162064SN/A        // execution (hopefully).
14171999SN/A    }
14181999SN/A
14191999SN/A    return start;
14201999SN/A}
14218706Sandreas.hansson@arm.com
14221999SN/Atemplate <class OS>
14231999SN/ASyscallReturn
14241999SN/Apwrite64Func(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
14251999SN/A{
1426378SN/A    int index = 0;
1427360SN/A    int tgt_fd = p->getSyscallArg(tc, index);
14281450SN/A    Addr bufPtr = p->getSyscallArg(tc, index);
142913995Sbrandon.potter@amd.com    int nbytes = p->getSyscallArg(tc, index);
1430360SN/A    int offset = p->getSyscallArg(tc, index);
14316701Sgblack@eecs.umich.edu
143213995Sbrandon.potter@amd.com    auto ffdp = std::dynamic_pointer_cast<FileFDEntry>((*p->fds)[tgt_fd]);
143311856Sbrandon.potter@amd.com    if (!ffdp)
143411856Sbrandon.potter@amd.com        return -EBADF;
1435360SN/A    int sim_fd = ffdp->getSimFD();
143611380Salexandru.dutu@amd.com
1437360SN/A    BufferArg bufArg(bufPtr, nbytes);
143811856Sbrandon.potter@amd.com    bufArg.copyIn(tc->getMemProxy());
143911856Sbrandon.potter@amd.com
14401458SN/A    int bytes_written = pwrite(sim_fd, bufArg.bufferPtr(), nbytes, offset);
144111856Sbrandon.potter@amd.com
1442360SN/A    return (bytes_written == -1) ? -errno : bytes_written;
1443360SN/A}
144410931Sbrandon.potter@amd.com
1445360SN/A/// Target mmap() handler.
1446360SN/Atemplate <class OS>
14471458SN/ASyscallReturn
1448360SN/AmmapFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
144910931Sbrandon.potter@amd.com{
14502021SN/A    return mmapImpl<OS>(desc, num, p, tc, false);
14511458SN/A}
1452360SN/A
1453360SN/A/// Target mmap2() handler.
14541706SN/Atemplate <class OS>
14551706SN/ASyscallReturn
14561706SN/Ammap2Func(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
145713995Sbrandon.potter@amd.com{
14581706SN/A    return mmapImpl<OS>(desc, num, p, tc, true);
145913936SAndrea.Mondelli@ucf.edu}
14601706SN/A
146113995Sbrandon.potter@amd.com/// Target getrlimit() handler.
14621706SN/Atemplate <class OS>
14636701Sgblack@eecs.umich.eduSyscallReturn
14648852Sandreas.hansson@arm.comgetrlimitFunc(SyscallDesc *desc, int callnum, Process *process,
14656701Sgblack@eecs.umich.edu              ThreadContext *tc)
14666701Sgblack@eecs.umich.edu{
14676701Sgblack@eecs.umich.edu    int index = 0;
14686701Sgblack@eecs.umich.edu    unsigned resource = process->getSyscallArg(tc, index);
14691706SN/A    TypedBufferArg<typename OS::rlimit> rlp(process->getSyscallArg(tc, index));
147013883Sdavid.hashe@amd.com
147113883Sdavid.hashe@amd.com    switch (resource) {
14723669Sbinkertn@umich.edu        case OS::TGT_RLIMIT_STACK:
14731706SN/A            // max stack size in bytes: make up a number (8MB for now)
14741706SN/A            rlp->rlim_cur = rlp->rlim_max = 8 * 1024 * 1024;
14751706SN/A            rlp->rlim_cur = TheISA::htog(rlp->rlim_cur);
14761706SN/A            rlp->rlim_max = TheISA::htog(rlp->rlim_max);
14772218SN/A            break;
14781706SN/A
147911759Sbrandon.potter@amd.com        case OS::TGT_RLIMIT_DATA:
148013933Sbrandon.potter@amd.com            // max data segment size in bytes: make up a number
148113933Sbrandon.potter@amd.com            rlp->rlim_cur = rlp->rlim_max = 256 * 1024 * 1024;
148213933Sbrandon.potter@amd.com            rlp->rlim_cur = TheISA::htog(rlp->rlim_cur);
148313933Sbrandon.potter@amd.com            rlp->rlim_max = TheISA::htog(rlp->rlim_max);
148411799Sbrandon.potter@amd.com            break;
14851706SN/A
14861706SN/A        default:
148711886Sbrandon.potter@amd.com            warn("getrlimit: unimplemented resource %d", resource);
148811886Sbrandon.potter@amd.com            return -EINVAL;
148913995Sbrandon.potter@amd.com            break;
149011886Sbrandon.potter@amd.com    }
149111886Sbrandon.potter@amd.com
149212426Sqtt2@cornell.edu    rlp.copyOut(tc->getMemProxy());
149313995Sbrandon.potter@amd.com    return 0;
149413557Sgabeblack@google.com}
149513557Sgabeblack@google.com
149611886Sbrandon.potter@amd.com/// Target clock_gettime() function.
149712426Sqtt2@cornell.edutemplate <class OS>
149813534Sandreas.sandberg@arm.comSyscallReturn
149912426Sqtt2@cornell.educlock_gettimeFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
150013534Sandreas.sandberg@arm.com{
150112426Sqtt2@cornell.edu    int index = 1;
150212426Sqtt2@cornell.edu    //int clk_id = p->getSyscallArg(tc, index);
150312426Sqtt2@cornell.edu    TypedBufferArg<typename OS::timespec> tp(p->getSyscallArg(tc, index));
150413536Sandreas.sandberg@arm.com
150512426Sqtt2@cornell.edu    getElapsedTimeNano(tp->tv_sec, tp->tv_nsec);
150612426Sqtt2@cornell.edu    tp->tv_sec += seconds_since_epoch;
150711886Sbrandon.potter@amd.com    tp->tv_sec = TheISA::htog(tp->tv_sec);
150813536Sandreas.sandberg@arm.com    tp->tv_nsec = TheISA::htog(tp->tv_nsec);
150912426Sqtt2@cornell.edu
151011886Sbrandon.potter@amd.com    tp.copyOut(tc->getMemProxy());
151111886Sbrandon.potter@amd.com
151211886Sbrandon.potter@amd.com    return 0;
151311886Sbrandon.potter@amd.com}
151411886Sbrandon.potter@amd.com
151511886Sbrandon.potter@amd.com/// Target clock_getres() function.
151611886Sbrandon.potter@amd.comtemplate <class OS>
151711886Sbrandon.potter@amd.comSyscallReturn
151811886Sbrandon.potter@amd.comclock_getresFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
151911886Sbrandon.potter@amd.com{
152013649Sqtt2@cornell.edu    int index = 1;
152113649Sqtt2@cornell.edu    TypedBufferArg<typename OS::timespec> tp(p->getSyscallArg(tc, index));
152213649Sqtt2@cornell.edu
152313649Sqtt2@cornell.edu    // Set resolution at ns, which is what clock_gettime() returns
152413649Sqtt2@cornell.edu    tp->tv_sec = 0;
152511886Sbrandon.potter@amd.com    tp->tv_nsec = 1;
152611886Sbrandon.potter@amd.com
152711886Sbrandon.potter@amd.com    tp.copyOut(tc->getMemProxy());
152811886Sbrandon.potter@amd.com
152911886Sbrandon.potter@amd.com    return 0;
153011886Sbrandon.potter@amd.com}
153111886Sbrandon.potter@amd.com
153211886Sbrandon.potter@amd.com/// Target gettimeofday() handler.
153311886Sbrandon.potter@amd.comtemplate <class OS>
153411886Sbrandon.potter@amd.comSyscallReturn
153511886Sbrandon.potter@amd.comgettimeofdayFunc(SyscallDesc *desc, int callnum, Process *process,
153613883Sdavid.hashe@amd.com                 ThreadContext *tc)
153711886Sbrandon.potter@amd.com{
153811886Sbrandon.potter@amd.com    int index = 0;
153911886Sbrandon.potter@amd.com    TypedBufferArg<typename OS::timeval> tp(process->getSyscallArg(tc, index));
154011886Sbrandon.potter@amd.com
154111886Sbrandon.potter@amd.com    getElapsedTimeMicro(tp->tv_sec, tp->tv_usec);
154211886Sbrandon.potter@amd.com    tp->tv_sec += seconds_since_epoch;
154311886Sbrandon.potter@amd.com    tp->tv_sec = TheISA::htog(tp->tv_sec);
154411886Sbrandon.potter@amd.com    tp->tv_usec = TheISA::htog(tp->tv_usec);
154511886Sbrandon.potter@amd.com
154611886Sbrandon.potter@amd.com    tp.copyOut(tc->getMemProxy());
154711886Sbrandon.potter@amd.com
154811886Sbrandon.potter@amd.com    return 0;
154911886Sbrandon.potter@amd.com}
155011886Sbrandon.potter@amd.com
155111886Sbrandon.potter@amd.com
155211886Sbrandon.potter@amd.com/// Target utimes() handler.
155311886Sbrandon.potter@amd.comtemplate <class OS>
155411886Sbrandon.potter@amd.comSyscallReturn
155511886Sbrandon.potter@amd.comutimesFunc(SyscallDesc *desc, int callnum, Process *process,
155613867Salexandru.dutu@amd.com           ThreadContext *tc)
155713867Salexandru.dutu@amd.com{
155811886Sbrandon.potter@amd.com    std::string path;
155911886Sbrandon.potter@amd.com
156011886Sbrandon.potter@amd.com    int index = 0;
156111886Sbrandon.potter@amd.com    if (!tc->getMemProxy().tryReadString(path,
156211886Sbrandon.potter@amd.com                process->getSyscallArg(tc, index))) {
156311886Sbrandon.potter@amd.com        return -EFAULT;
156411886Sbrandon.potter@amd.com    }
156511886Sbrandon.potter@amd.com
156611886Sbrandon.potter@amd.com    TypedBufferArg<typename OS::timeval [2]>
156711886Sbrandon.potter@amd.com        tp(process->getSyscallArg(tc, index));
156811886Sbrandon.potter@amd.com    tp.copyIn(tc->getMemProxy());
156911886Sbrandon.potter@amd.com
157011886Sbrandon.potter@amd.com    struct timeval hostTimeval[2];
157111886Sbrandon.potter@amd.com    for (int i = 0; i < 2; ++i)
157211886Sbrandon.potter@amd.com    {
157313867Salexandru.dutu@amd.com        hostTimeval[i].tv_sec = TheISA::gtoh((*tp)[i].tv_sec);
157413867Salexandru.dutu@amd.com        hostTimeval[i].tv_usec = TheISA::gtoh((*tp)[i].tv_usec);
157513867Salexandru.dutu@amd.com    }
157613867Salexandru.dutu@amd.com
157711886Sbrandon.potter@amd.com    // Adjust path for current working directory
157811886Sbrandon.potter@amd.com    path = process->fullPath(path);
157911886Sbrandon.potter@amd.com
158011911SBrandon.Potter@amd.com    int result = utimes(path.c_str(), hostTimeval);
158111911SBrandon.Potter@amd.com
158211911SBrandon.Potter@amd.com    if (result < 0)
158311911SBrandon.Potter@amd.com        return -errno;
158411911SBrandon.Potter@amd.com
158511911SBrandon.Potter@amd.com    return 0;
158611911SBrandon.Potter@amd.com}
158711886Sbrandon.potter@amd.com/// Target getrusage() function.
158811886Sbrandon.potter@amd.comtemplate <class OS>
158911886Sbrandon.potter@amd.comSyscallReturn
159011886Sbrandon.potter@amd.comgetrusageFunc(SyscallDesc *desc, int callnum, Process *process,
159111886Sbrandon.potter@amd.com              ThreadContext *tc)
159211886Sbrandon.potter@amd.com{
159311886Sbrandon.potter@amd.com    int index = 0;
159411886Sbrandon.potter@amd.com    int who = process->getSyscallArg(tc, index); // THREAD, SELF, or CHILDREN
159511886Sbrandon.potter@amd.com    TypedBufferArg<typename OS::rusage> rup(process->getSyscallArg(tc, index));
159611886Sbrandon.potter@amd.com
159711886Sbrandon.potter@amd.com    rup->ru_utime.tv_sec = 0;
159811886Sbrandon.potter@amd.com    rup->ru_utime.tv_usec = 0;
159913536Sandreas.sandberg@arm.com    rup->ru_stime.tv_sec = 0;
160011886Sbrandon.potter@amd.com    rup->ru_stime.tv_usec = 0;
160111886Sbrandon.potter@amd.com    rup->ru_maxrss = 0;
160211886Sbrandon.potter@amd.com    rup->ru_ixrss = 0;
160311886Sbrandon.potter@amd.com    rup->ru_idrss = 0;
160411886Sbrandon.potter@amd.com    rup->ru_isrss = 0;
160511886Sbrandon.potter@amd.com    rup->ru_minflt = 0;
160611886Sbrandon.potter@amd.com    rup->ru_majflt = 0;
160711886Sbrandon.potter@amd.com    rup->ru_nswap = 0;
160811886Sbrandon.potter@amd.com    rup->ru_inblock = 0;
160911886Sbrandon.potter@amd.com    rup->ru_oublock = 0;
161013867Salexandru.dutu@amd.com    rup->ru_msgsnd = 0;
161113867Salexandru.dutu@amd.com    rup->ru_msgrcv = 0;
161213867Salexandru.dutu@amd.com    rup->ru_nsignals = 0;
161313867Salexandru.dutu@amd.com    rup->ru_nvcsw = 0;
161413867Salexandru.dutu@amd.com    rup->ru_nivcsw = 0;
161513867Salexandru.dutu@amd.com
161613867Salexandru.dutu@amd.com    switch (who) {
161713867Salexandru.dutu@amd.com      case OS::TGT_RUSAGE_SELF:
161813867Salexandru.dutu@amd.com        getElapsedTimeMicro(rup->ru_utime.tv_sec, rup->ru_utime.tv_usec);
161913867Salexandru.dutu@amd.com        rup->ru_utime.tv_sec = TheISA::htog(rup->ru_utime.tv_sec);
162013867Salexandru.dutu@amd.com        rup->ru_utime.tv_usec = TheISA::htog(rup->ru_utime.tv_usec);
162111886Sbrandon.potter@amd.com        break;
162211886Sbrandon.potter@amd.com
162311886Sbrandon.potter@amd.com      case OS::TGT_RUSAGE_CHILDREN:
162411886Sbrandon.potter@amd.com        // do nothing.  We have no child processes, so they take no time.
16251706SN/A        break;
16261706SN/A
16271706SN/A      default:
16281706SN/A        // don't really handle THREAD or CHILDREN, but just warn and
162913995Sbrandon.potter@amd.com        // plow ahead
16301706SN/A        warn("getrusage() only supports RUSAGE_SELF.  Parameter %d ignored.",
16316701Sgblack@eecs.umich.edu             who);
163213995Sbrandon.potter@amd.com    }
163311856Sbrandon.potter@amd.com
163411856Sbrandon.potter@amd.com    rup.copyOut(tc->getMemProxy());
16351706SN/A
163611856Sbrandon.potter@amd.com    return 0;
163711856Sbrandon.potter@amd.com}
16381706SN/A
163911856Sbrandon.potter@amd.com/// Target times() function.
16401706SN/Atemplate <class OS>
16411706SN/ASyscallReturn
164210931Sbrandon.potter@amd.comtimesFunc(SyscallDesc *desc, int callnum, Process *process,
16431706SN/A          ThreadContext *tc)
16441706SN/A{
16452218SN/A    int index = 0;
16461706SN/A    TypedBufferArg<typename OS::tms> bufp(process->getSyscallArg(tc, index));
164711759Sbrandon.potter@amd.com
16481706SN/A    // Fill in the time structure (in clocks)
16491706SN/A    int64_t clocks = curTick() * OS::M5_SC_CLK_TCK / SimClock::Int::s;
16501706SN/A    bufp->tms_utime = clocks;
16511706SN/A    bufp->tms_stime = 0;
165213572Sbrandon.potter@amd.com    bufp->tms_cutime = 0;
165313572Sbrandon.potter@amd.com    bufp->tms_cstime = 0;
165413572Sbrandon.potter@amd.com
165513995Sbrandon.potter@amd.com    // Convert to host endianness
165613572Sbrandon.potter@amd.com    bufp->tms_utime = TheISA::htog(bufp->tms_utime);
165713572Sbrandon.potter@amd.com
165813995Sbrandon.potter@amd.com    // Write back
165913572Sbrandon.potter@amd.com    bufp.copyOut(tc->getMemProxy());
166013572Sbrandon.potter@amd.com
166113572Sbrandon.potter@amd.com    // Return clock ticks since system boot
166213572Sbrandon.potter@amd.com    return clocks;
166313572Sbrandon.potter@amd.com}
166413572Sbrandon.potter@amd.com
166513572Sbrandon.potter@amd.com/// Target time() function.
166613572Sbrandon.potter@amd.comtemplate <class OS>
166713572Sbrandon.potter@amd.comSyscallReturn
166813572Sbrandon.potter@amd.comtimeFunc(SyscallDesc *desc, int callnum, Process *process, ThreadContext *tc)
166913572Sbrandon.potter@amd.com{
167013572Sbrandon.potter@amd.com    typename OS::time_t sec, usec;
167113572Sbrandon.potter@amd.com    getElapsedTimeMicro(sec, usec);
167213572Sbrandon.potter@amd.com    sec += seconds_since_epoch;
167313572Sbrandon.potter@amd.com
167413572Sbrandon.potter@amd.com    int index = 0;
167513572Sbrandon.potter@amd.com    Addr taddr = (Addr)process->getSyscallArg(tc, index);
167613572Sbrandon.potter@amd.com    if (taddr != 0) {
167713572Sbrandon.potter@amd.com        typename OS::time_t t = sec;
167813572Sbrandon.potter@amd.com        t = TheISA::htog(t);
167913572Sbrandon.potter@amd.com        SETranslatingPortProxy &p = tc->getMemProxy();
168013572Sbrandon.potter@amd.com        p.writeBlob(taddr, (uint8_t*)&t, (int)sizeof(typename OS::time_t));
168113572Sbrandon.potter@amd.com    }
168213572Sbrandon.potter@amd.com    return sec;
168313572Sbrandon.potter@amd.com}
168413572Sbrandon.potter@amd.com
168513572Sbrandon.potter@amd.com
168613572Sbrandon.potter@amd.com#endif // __SIM_SYSCALL_EMUL_HH__
168713572Sbrandon.potter@amd.com