syscall_emul.hh revision 13572
1360SN/A/*
210027SChris.Adeniyi-Jones@arm.com * Copyright (c) 2012-2013, 2015 ARM Limited
310027SChris.Adeniyi-Jones@arm.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.
141458SN/A *
15360SN/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
392665Ssaidi@eecs.umich.edu * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
402665Ssaidi@eecs.umich.edu *
412665Ssaidi@eecs.umich.edu * Authors: Steve Reinhardt
42360SN/A *          Kevin Lim
43360SN/A */
441354SN/A
451354SN/A#ifndef __SIM_SYSCALL_EMUL_HH__
46360SN/A#define __SIM_SYSCALL_EMUL_HH__
472764Sstever@eecs.umich.edu
489202Spalle@lyckegaard.dk#if (defined(__APPLE__) || defined(__OpenBSD__) ||      \
499202Spalle@lyckegaard.dk     defined(__FreeBSD__) || defined(__CYGWIN__) ||     \
502064SN/A     defined(__NetBSD__))
51360SN/A#define NO_STAT64 1
52360SN/A#else
53360SN/A#define NO_STAT64 0
54360SN/A#endif
55360SN/A
56360SN/A#if (defined(__APPLE__) || defined(__OpenBSD__) ||      \
571809SN/A     defined(__FreeBSD__) || defined(__NetBSD__))
585543Ssaidi@eecs.umich.edu#define NO_STATFS 1
591809SN/A#else
603113Sgblack@eecs.umich.edu#define NO_STATFS 0
618229Snate@binkert.org#endif
628229Snate@binkert.org
633113Sgblack@eecs.umich.edu#if (defined(__APPLE__) || defined(__OpenBSD__) ||      \
647075Snate@binkert.org     defined(__FreeBSD__) || defined(__NetBSD__))
658229Snate@binkert.org#define NO_FALLOCATE 1
667075Snate@binkert.org#else
67360SN/A#define NO_FALLOCATE 0
682474SN/A#endif
695543Ssaidi@eecs.umich.edu
702462SN/A///
711354SN/A/// @file syscall_emul.hh
726216Snate@binkert.org///
736658Snate@binkert.org/// This file defines objects used to emulate syscalls from the target
742474SN/A/// application on the host machine.
752680Sktlim@umich.edu
768232Snate@binkert.org#ifdef __CYGWIN32__
778229Snate@binkert.org#include <sys/fcntl.h>
788706Sandreas.hansson@arm.com
797678Sgblack@eecs.umich.edu#endif
808229Snate@binkert.org#include <fcntl.h>
818766Sgblack@eecs.umich.edu#include <poll.h>
826640Svince@csl.cornell.edu#include <sys/mman.h>
83360SN/A#include <sys/socket.h>
84360SN/A#include <sys/stat.h>
85360SN/A#if (NO_STATFS == 0)
86360SN/A#include <sys/statfs.h>
87360SN/A#else
88360SN/A#include <sys/mount.h>
89360SN/A#endif
90360SN/A#include <sys/time.h>
91378SN/A#include <sys/types.h>
921450SN/A#include <sys/uio.h>
933114Sgblack@eecs.umich.edu#include <unistd.h>
94360SN/A
955543Ssaidi@eecs.umich.edu#include <cerrno>
965543Ssaidi@eecs.umich.edu#include <memory>
975543Ssaidi@eecs.umich.edu#include <string>
98360SN/A
99360SN/A#include "arch/generic/tlb.hh"
100360SN/A#include "arch/utility.hh"
101360SN/A#include "base/intmath.hh"
102360SN/A#include "base/loader/object_file.hh"
1032680Sktlim@umich.edu#include "base/logging.hh"
104360SN/A#include "base/trace.hh"
105360SN/A#include "base/types.hh"
106360SN/A#include "config/the_isa.hh"
107360SN/A#include "cpu/base.hh"
108360SN/A#include "cpu/thread_context.hh"
109360SN/A#include "mem/page_table.hh"
110360SN/A#include "params/Process.hh"
111360SN/A#include "sim/emul_driver.hh"
112360SN/A#include "sim/futex_map.hh"
113360SN/A#include "sim/process.hh"
114360SN/A#include "sim/syscall_debug_macros.hh"
1153114Sgblack@eecs.umich.edu#include "sim/syscall_desc.hh"
116360SN/A#include "sim/syscall_emul_buf.hh"
117360SN/A#include "sim/syscall_return.hh"
118360SN/A
119360SN/A//////////////////////////////////////////////////////////////////////
120360SN/A//
121360SN/A// The following emulation functions are generic enough that they
122360SN/A// don't need to be recompiled for different emulated OS's.  They are
123360SN/A// defined in sim/syscall_emul.cc.
124360SN/A//
125360SN/A//////////////////////////////////////////////////////////////////////
126360SN/A
127360SN/A
128360SN/A/// Handler for unimplemented syscalls that we haven't thought about.
129360SN/ASyscallReturn unimplementedFunc(SyscallDesc *desc, int num,
130360SN/A                                Process *p, ThreadContext *tc);
131360SN/A
132360SN/A/// Handler for unimplemented syscalls that we never intend to
133360SN/A/// implement (signal handling, etc.) and should not affect the correct
134360SN/A/// behavior of the program.  Print a warning only if the appropriate
135360SN/A/// trace flag is enabled.  Return success to the target program.
136360SN/ASyscallReturn ignoreFunc(SyscallDesc *desc, int num,
1378852Sandreas.hansson@arm.com                         Process *p, ThreadContext *tc);
138360SN/A
1398852Sandreas.hansson@arm.com// Target fallocateFunc() handler.
1405543Ssaidi@eecs.umich.eduSyscallReturn fallocateFunc(SyscallDesc *desc, int num,
141360SN/A                            Process *p, ThreadContext *tc);
142360SN/A
143360SN/A/// Target exit() handler: terminate current context.
144360SN/ASyscallReturn exitFunc(SyscallDesc *desc, int num,
145360SN/A                       Process *p, ThreadContext *tc);
1468852Sandreas.hansson@arm.com
147360SN/A/// Target exit_group() handler: terminate simulation. (exit all threads)
1488852Sandreas.hansson@arm.comSyscallReturn exitGroupFunc(SyscallDesc *desc, int num,
1495543Ssaidi@eecs.umich.edu                       Process *p, ThreadContext *tc);
150360SN/A
151360SN/A/// Target set_tid_address() handler.
152360SN/ASyscallReturn setTidAddressFunc(SyscallDesc *desc, int num,
153360SN/A                                Process *p, ThreadContext *tc);
154360SN/A
155360SN/A/// Target getpagesize() handler.
156360SN/ASyscallReturn getpagesizeFunc(SyscallDesc *desc, int num,
157360SN/A                              Process *p, ThreadContext *tc);
158360SN/A
159360SN/A/// Target brk() handler: set brk address.
160360SN/ASyscallReturn brkFunc(SyscallDesc *desc, int num,
161360SN/A                      Process *p, ThreadContext *tc);
162360SN/A
1635543Ssaidi@eecs.umich.edu/// Target close() handler.
164360SN/ASyscallReturn closeFunc(SyscallDesc *desc, int num,
165360SN/A                        Process *p, ThreadContext *tc);
166360SN/A
167360SN/A/// Target lseek() handler.
168360SN/ASyscallReturn lseekFunc(SyscallDesc *desc, int num,
169360SN/A                        Process *p, ThreadContext *tc);
170360SN/A
171360SN/A/// Target _llseek() handler.
172360SN/ASyscallReturn _llseekFunc(SyscallDesc *desc, int num,
173360SN/A                          Process *p, ThreadContext *tc);
174360SN/A
175360SN/A/// Target munmap() handler.
176360SN/ASyscallReturn munmapFunc(SyscallDesc *desc, int num,
177360SN/A                         Process *p, ThreadContext *tc);
178360SN/A
179360SN/A/// Target shutdown() handler.
180360SN/ASyscallReturn shutdownFunc(SyscallDesc *desc, int num,
1815543Ssaidi@eecs.umich.edu                           Process *p, ThreadContext *tc);
1825543Ssaidi@eecs.umich.edu
183502SN/A/// Target gethostname() handler.
184360SN/ASyscallReturn gethostnameFunc(SyscallDesc *desc, int num,
185360SN/A                              Process *p, ThreadContext *tc);
186360SN/A
187360SN/A/// Target getcwd() handler.
188360SN/ASyscallReturn getcwdFunc(SyscallDesc *desc, int num,
189360SN/A                         Process *p, ThreadContext *tc);
190360SN/A
191360SN/A/// Target readlink() handler.
192360SN/ASyscallReturn readlinkFunc(SyscallDesc *desc, int num,
193360SN/A                           Process *p, ThreadContext *tc,
194360SN/A                           int index = 0);
195378SN/ASyscallReturn readlinkFunc(SyscallDesc *desc, int num,
1961706SN/A                           Process *p, ThreadContext *tc);
1973114Sgblack@eecs.umich.edu
198378SN/A/// Target unlink() handler.
199378SN/ASyscallReturn unlinkHelper(SyscallDesc *desc, int num,
200378SN/A                           Process *p, ThreadContext *tc,
201378SN/A                           int index);
202378SN/ASyscallReturn unlinkFunc(SyscallDesc *desc, int num,
2031706SN/A                         Process *p, ThreadContext *tc);
2043114Sgblack@eecs.umich.edu
2058149SChris.Emmons@ARM.com/// Target link() handler
2068149SChris.Emmons@ARM.comSyscallReturn linkFunc(SyscallDesc *desc, int num, Process *p,
207360SN/A                       ThreadContext *tc);
2086109Ssanchezd@stanford.edu
2091706SN/A/// Target symlink() handler.
2103114Sgblack@eecs.umich.eduSyscallReturn symlinkFunc(SyscallDesc *desc, int num, Process *p,
211378SN/A                          ThreadContext *tc);
2126109Ssanchezd@stanford.edu
2136109Ssanchezd@stanford.edu/// Target mkdir() handler.
2146109Ssanchezd@stanford.eduSyscallReturn mkdirFunc(SyscallDesc *desc, int num,
2156109Ssanchezd@stanford.edu                        Process *p, ThreadContext *tc);
216378SN/A
2171706SN/A/// Target mknod() handler.
2183114Sgblack@eecs.umich.eduSyscallReturn mknodFunc(SyscallDesc *desc, int num,
219378SN/A                        Process *p, ThreadContext *tc);
2205748SSteve.Reinhardt@amd.com
2215748SSteve.Reinhardt@amd.com/// Target chdir() handler.
2225748SSteve.Reinhardt@amd.comSyscallReturn chdirFunc(SyscallDesc *desc, int num,
223378SN/A                        Process *p, ThreadContext *tc);
224378SN/A
2251706SN/A// Target rmdir() handler.
2263114Sgblack@eecs.umich.eduSyscallReturn rmdirFunc(SyscallDesc *desc, int num,
227378SN/A                        Process *p, ThreadContext *tc);
228378SN/A
2291706SN/A/// Target rename() handler.
2303114Sgblack@eecs.umich.eduSyscallReturn renameFunc(SyscallDesc *desc, int num,
231378SN/A                         Process *p, ThreadContext *tc);
232378SN/A
2331706SN/A
2343114Sgblack@eecs.umich.edu/// Target truncate() handler.
235378SN/ASyscallReturn truncateFunc(SyscallDesc *desc, int num,
236378SN/A                           Process *p, ThreadContext *tc);
2371706SN/A
2383114Sgblack@eecs.umich.edu
239378SN/A/// Target ftruncate() handler.
2404118Sgblack@eecs.umich.eduSyscallReturn ftruncateFunc(SyscallDesc *desc, int num,
2414118Sgblack@eecs.umich.edu                            Process *p, ThreadContext *tc);
2424118Sgblack@eecs.umich.edu
2434118Sgblack@eecs.umich.edu
244378SN/A/// Target truncate64() handler.
2451706SN/ASyscallReturn truncate64Func(SyscallDesc *desc, int num,
2463114Sgblack@eecs.umich.edu                             Process *p, ThreadContext *tc);
247378SN/A
248378SN/A/// Target ftruncate64() handler.
2491706SN/ASyscallReturn ftruncate64Func(SyscallDesc *desc, int num,
2503114Sgblack@eecs.umich.edu                              Process *p, ThreadContext *tc);
251360SN/A
2525513SMichael.Adler@intel.com
2535513SMichael.Adler@intel.com/// Target umask() handler.
2545513SMichael.Adler@intel.comSyscallReturn umaskFunc(SyscallDesc *desc, int num,
2555513SMichael.Adler@intel.com                        Process *p, ThreadContext *tc);
2565513SMichael.Adler@intel.com
2575513SMichael.Adler@intel.com/// Target gettid() handler.
2585513SMichael.Adler@intel.comSyscallReturn gettidFunc(SyscallDesc *desc, int num,
2595513SMichael.Adler@intel.com                         Process *p, ThreadContext *tc);
260511SN/A
2611706SN/A/// Target chown() handler.
2623114Sgblack@eecs.umich.eduSyscallReturn chownFunc(SyscallDesc *desc, int num,
263511SN/A                        Process *p, ThreadContext *tc);
2645513SMichael.Adler@intel.com
2655513SMichael.Adler@intel.com/// Target setpgid() handler.
2665513SMichael.Adler@intel.comSyscallReturn setpgidFunc(SyscallDesc *desc, int num,
2675513SMichael.Adler@intel.com                          Process *p, ThreadContext *tc);
268511SN/A
2691706SN/A/// Target fchown() handler.
2703114Sgblack@eecs.umich.eduSyscallReturn fchownFunc(SyscallDesc *desc, int num,
2711706SN/A                         Process *p, ThreadContext *tc);
2721706SN/A
2731706SN/A/// Target dup() handler.
2741706SN/ASyscallReturn dupFunc(SyscallDesc *desc, int num,
2753114Sgblack@eecs.umich.edu                      Process *process, ThreadContext *tc);
2761706SN/A
2771706SN/A/// Target dup2() handler.
2781706SN/ASyscallReturn dup2Func(SyscallDesc *desc, int num,
2791706SN/A                       Process *process, ThreadContext *tc);
2803114Sgblack@eecs.umich.edu
2811706SN/A/// Target fcntl() handler.
282511SN/ASyscallReturn fcntlFunc(SyscallDesc *desc, int num,
2836703Svince@csl.cornell.edu                        Process *process, ThreadContext *tc);
2846703Svince@csl.cornell.edu
2856703Svince@csl.cornell.edu/// Target fcntl64() handler.
2866703Svince@csl.cornell.eduSyscallReturn fcntl64Func(SyscallDesc *desc, int num,
2876685Stjones1@inf.ed.ac.uk                          Process *process, ThreadContext *tc);
2886685Stjones1@inf.ed.ac.uk
2896685Stjones1@inf.ed.ac.uk/// Target setuid() handler.
2906685Stjones1@inf.ed.ac.ukSyscallReturn setuidFunc(SyscallDesc *desc, int num,
2916685Stjones1@inf.ed.ac.uk                         Process *p, ThreadContext *tc);
2925513SMichael.Adler@intel.com
2935513SMichael.Adler@intel.com/// Target pipe() handler.
2945513SMichael.Adler@intel.comSyscallReturn pipeFunc(SyscallDesc *desc, int num,
2955513SMichael.Adler@intel.com                       Process *p, ThreadContext *tc);
2965513SMichael.Adler@intel.com
2971999SN/A/// Internal pipe() handler.
2981999SN/ASyscallReturn pipeImpl(SyscallDesc *desc, int num, Process *p,
2993114Sgblack@eecs.umich.edu                       ThreadContext *tc, bool pseudoPipe);
3001999SN/A
3011999SN/A/// Target getpid() handler.
3021999SN/ASyscallReturn getpidFunc(SyscallDesc *desc, int num,
3031999SN/A                         Process *p, ThreadContext *tc);
3043114Sgblack@eecs.umich.edu
3051999SN/A// Target getpeername() handler.
3063079Sstever@eecs.umich.eduSyscallReturn getpeernameFunc(SyscallDesc *desc, int num,
3073079Sstever@eecs.umich.edu                              Process *p, ThreadContext *tc);
3083114Sgblack@eecs.umich.edu
3093079Sstever@eecs.umich.edu// Target bind() handler.
3102093SN/ASyscallReturn bindFunc(SyscallDesc *desc, int num,
3112093SN/A                       Process *p, ThreadContext *tc);
3123114Sgblack@eecs.umich.edu
3132093SN/A// Target listen() handler.
3142687Sksewell@umich.eduSyscallReturn listenFunc(SyscallDesc *desc, int num,
3152687Sksewell@umich.edu                         Process *p, ThreadContext *tc);
3163114Sgblack@eecs.umich.edu
3172687Sksewell@umich.edu// Target connect() handler.
3182238SN/ASyscallReturn connectFunc(SyscallDesc *desc, int num,
3192238SN/A                          Process *p, ThreadContext *tc);
3203114Sgblack@eecs.umich.edu
3212238SN/A#if defined(SYS_getdents)
3222238SN/A// Target getdents() handler.
3232238SN/ASyscallReturn getdentsFunc(SyscallDesc *desc, int num,
3243114Sgblack@eecs.umich.edu                           Process *p, ThreadContext *tc);
3252238SN/A#endif
3262238SN/A
3272238SN/A#if defined(SYS_getdents64)
3283114Sgblack@eecs.umich.edu// Target getdents() handler.
3292238SN/ASyscallReturn getdents64Func(SyscallDesc *desc, int num,
3302238SN/A                           Process *p, ThreadContext *tc);
3312238SN/A#endif
3323114Sgblack@eecs.umich.edu
3332238SN/A// Target sendto() handler.
3342238SN/ASyscallReturn sendtoFunc(SyscallDesc *desc, int num,
3352238SN/A                         Process *p, ThreadContext *tc);
3363114Sgblack@eecs.umich.edu
3372238SN/A// Target recvfrom() handler.
3382238SN/ASyscallReturn recvfromFunc(SyscallDesc *desc, int num,
3392238SN/A                           Process *p, ThreadContext *tc);
3403114Sgblack@eecs.umich.edu
3412238SN/A// Target recvmsg() handler.
3422238SN/ASyscallReturn recvmsgFunc(SyscallDesc *desc, int num,
3432238SN/A                          Process *p, ThreadContext *tc);
3443114Sgblack@eecs.umich.edu
3452238SN/A// Target sendmsg() handler.
3466109Ssanchezd@stanford.eduSyscallReturn sendmsgFunc(SyscallDesc *desc, int num,
3476109Ssanchezd@stanford.edu                          Process *p, ThreadContext *tc);
3486109Ssanchezd@stanford.edu
3492238SN/A// Target getuid() handler.
3509455Smitch.hayenga+gem5@gmail.comSyscallReturn getuidFunc(SyscallDesc *desc, int num,
3519455Smitch.hayenga+gem5@gmail.com                         Process *p, ThreadContext *tc);
3529455Smitch.hayenga+gem5@gmail.com
3539455Smitch.hayenga+gem5@gmail.com/// Target getgid() handler.
3549112Smarc.orr@gmail.comSyscallReturn getgidFunc(SyscallDesc *desc, int num,
3559112Smarc.orr@gmail.com                         Process *p, ThreadContext *tc);
3569112Smarc.orr@gmail.com
3579112Smarc.orr@gmail.com/// Target getppid() handler.
3589112Smarc.orr@gmail.comSyscallReturn getppidFunc(SyscallDesc *desc, int num,
3599112Smarc.orr@gmail.com                          Process *p, ThreadContext *tc);
3609112Smarc.orr@gmail.com
3619112Smarc.orr@gmail.com/// Target geteuid() handler.
3629112Smarc.orr@gmail.comSyscallReturn geteuidFunc(SyscallDesc *desc, int num,
3639112Smarc.orr@gmail.com                          Process *p, ThreadContext *tc);
3649112Smarc.orr@gmail.com
3659112Smarc.orr@gmail.com/// Target getegid() handler.
3669112Smarc.orr@gmail.comSyscallReturn getegidFunc(SyscallDesc *desc, int num,
3679112Smarc.orr@gmail.com                          Process *p, ThreadContext *tc);
3689112Smarc.orr@gmail.com
3699112Smarc.orr@gmail.com/// Target access() handler
3709112Smarc.orr@gmail.comSyscallReturn accessFunc(SyscallDesc *desc, int num,
3719112Smarc.orr@gmail.com                         Process *p, ThreadContext *tc);
3729112Smarc.orr@gmail.comSyscallReturn accessFunc(SyscallDesc *desc, int num,
3739112Smarc.orr@gmail.com                         Process *p, ThreadContext *tc,
3749112Smarc.orr@gmail.com                         int index);
3759112Smarc.orr@gmail.com
3769112Smarc.orr@gmail.com// Target getsockopt() handler.
3779112Smarc.orr@gmail.comSyscallReturn getsockoptFunc(SyscallDesc *desc, int num,
3789238Slluc.alvarez@bsc.es                             Process *p, ThreadContext *tc);
3799112Smarc.orr@gmail.com
3809112Smarc.orr@gmail.com// Target setsockopt() handler.
3819112Smarc.orr@gmail.comSyscallReturn setsockoptFunc(SyscallDesc *desc, int num,
3829112Smarc.orr@gmail.com                             Process *p, ThreadContext *tc);
3839112Smarc.orr@gmail.com
3849112Smarc.orr@gmail.com// Target getsockname() handler.
3859112Smarc.orr@gmail.comSyscallReturn getsocknameFunc(SyscallDesc *desc, int num,
3869112Smarc.orr@gmail.com                              Process *p, ThreadContext *tc);
3879112Smarc.orr@gmail.com
3889112Smarc.orr@gmail.com/// Futex system call
3899112Smarc.orr@gmail.com/// Implemented by Daniel Sanchez
3909112Smarc.orr@gmail.com/// Used by printf's in multi-threaded apps
3919112Smarc.orr@gmail.comtemplate <class OS>
3929112Smarc.orr@gmail.comSyscallReturn
3939112Smarc.orr@gmail.comfutexFunc(SyscallDesc *desc, int callnum, Process *process,
3949112Smarc.orr@gmail.com          ThreadContext *tc)
3959112Smarc.orr@gmail.com{
3969112Smarc.orr@gmail.com    using namespace std;
3979112Smarc.orr@gmail.com
3989112Smarc.orr@gmail.com    int index = 0;
3999112Smarc.orr@gmail.com    Addr uaddr = process->getSyscallArg(tc, index);
4009112Smarc.orr@gmail.com    int op = process->getSyscallArg(tc, index);
4019112Smarc.orr@gmail.com    int val = process->getSyscallArg(tc, index);
4029112Smarc.orr@gmail.com
4039112Smarc.orr@gmail.com    /*
4049112Smarc.orr@gmail.com     * Unsupported option that does not affect the correctness of the
4059112Smarc.orr@gmail.com     * application. This is a performance optimization utilized by Linux.
4069112Smarc.orr@gmail.com     */
4079112Smarc.orr@gmail.com    op &= ~OS::TGT_FUTEX_PRIVATE_FLAG;
4089112Smarc.orr@gmail.com
4099112Smarc.orr@gmail.com    FutexMap &futex_map = tc->getSystemPtr()->futexMap;
4109112Smarc.orr@gmail.com
4119112Smarc.orr@gmail.com    if (OS::TGT_FUTEX_WAIT == op) {
4129112Smarc.orr@gmail.com        // Ensure futex system call accessed atomically.
4139112Smarc.orr@gmail.com        BufferArg buf(uaddr, sizeof(int));
4149112Smarc.orr@gmail.com        buf.copyIn(tc->getMemProxy());
4159112Smarc.orr@gmail.com        int mem_val = *(int*)buf.bufferPtr();
4169112Smarc.orr@gmail.com
4179112Smarc.orr@gmail.com        /*
4189112Smarc.orr@gmail.com         * The value in memory at uaddr is not equal with the expected val
4199112Smarc.orr@gmail.com         * (a different thread must have changed it before the system call was
4209112Smarc.orr@gmail.com         * invoked). In this case, we need to throw an error.
4219112Smarc.orr@gmail.com         */
4229112Smarc.orr@gmail.com        if (val != mem_val)
4239112Smarc.orr@gmail.com            return -OS::TGT_EWOULDBLOCK;
4249112Smarc.orr@gmail.com
4259112Smarc.orr@gmail.com        futex_map.suspend(uaddr, process->tgid(), tc);
4269112Smarc.orr@gmail.com
4279112Smarc.orr@gmail.com        return 0;
4289112Smarc.orr@gmail.com    } else if (OS::TGT_FUTEX_WAKE == op) {
4299112Smarc.orr@gmail.com        return futex_map.wakeup(uaddr, process->tgid(), val);
4309238Slluc.alvarez@bsc.es    }
4319112Smarc.orr@gmail.com
4329112Smarc.orr@gmail.com    warn("futex: op %d not implemented; ignoring.", op);
4339112Smarc.orr@gmail.com    return -ENOSYS;
4349112Smarc.orr@gmail.com}
4359112Smarc.orr@gmail.com
4362238SN/A
4372238SN/A/// Pseudo Funcs  - These functions use a different return convension,
4382238SN/A/// returning a second value in a register other than the normal return register
4392238SN/ASyscallReturn pipePseudoFunc(SyscallDesc *desc, int num,
4403114Sgblack@eecs.umich.edu                             Process *process, ThreadContext *tc);
4412238SN/A
4422238SN/A/// Target getpidPseudo() handler.
4432238SN/ASyscallReturn getpidPseudoFunc(SyscallDesc *desc, int num,
4443114Sgblack@eecs.umich.edu                               Process *p, ThreadContext *tc);
4452238SN/A
4462238SN/A/// Target getuidPseudo() handler.
4472238SN/ASyscallReturn getuidPseudoFunc(SyscallDesc *desc, int num,
4483114Sgblack@eecs.umich.edu                               Process *p, ThreadContext *tc);
4492238SN/A
4502238SN/A/// Target getgidPseudo() handler.
4512238SN/ASyscallReturn getgidPseudoFunc(SyscallDesc *desc, int num,
4523114Sgblack@eecs.umich.edu                               Process *p, ThreadContext *tc);
4532238SN/A
4542238SN/A
4551354SN/A/// A readable name for 1,000,000, for converting microseconds to seconds.
4561354SN/Aconst int one_million = 1000000;
4571354SN/A/// A readable name for 1,000,000,000, for converting nanoseconds to seconds.
4581354SN/Aconst int one_billion = 1000000000;
4591354SN/A
4601354SN/A/// Approximate seconds since the epoch (1/1/1970).  About a billion,
4611354SN/A/// by my reckoning.  We want to keep this a constant (not use the
4621354SN/A/// real-world time) to keep simulations repeatable.
4631354SN/Aconst unsigned seconds_since_epoch = 1000000000;
4641354SN/A
4651354SN/A/// Helper function to convert current elapsed time to seconds and
4661354SN/A/// microseconds.
4671354SN/Atemplate <class T1, class T2>
4681354SN/Avoid
4697823Ssteve.reinhardt@amd.comgetElapsedTimeMicro(T1 &sec, T2 &usec)
4701354SN/A{
4711354SN/A    uint64_t elapsed_usecs = curTick() / SimClock::Int::us;
4721354SN/A    sec = elapsed_usecs / one_million;
4731354SN/A    usec = elapsed_usecs % one_million;
474360SN/A}
475360SN/A
476360SN/A/// Helper function to convert current elapsed time to seconds and
477360SN/A/// nanoseconds.
478360SN/Atemplate <class T1, class T2>
479360SN/Avoid
480360SN/AgetElapsedTimeNano(T1 &sec, T2 &nsec)
4813113Sgblack@eecs.umich.edu{
4823113Sgblack@eecs.umich.edu    uint64_t elapsed_nsecs = curTick() / SimClock::Int::ns;
4833113Sgblack@eecs.umich.edu    sec = elapsed_nsecs / one_billion;
4843113Sgblack@eecs.umich.edu    nsec = elapsed_nsecs % one_billion;
4853113Sgblack@eecs.umich.edu}
4863113Sgblack@eecs.umich.edu
4873113Sgblack@eecs.umich.edu//////////////////////////////////////////////////////////////////////
4883113Sgblack@eecs.umich.edu//
4893113Sgblack@eecs.umich.edu// The following emulation functions are generic, but need to be
4903113Sgblack@eecs.umich.edu// templated to account for differences in types, constants, etc.
4913113Sgblack@eecs.umich.edu//
4923113Sgblack@eecs.umich.edu//////////////////////////////////////////////////////////////////////
4933113Sgblack@eecs.umich.edu
4943113Sgblack@eecs.umich.edu    typedef struct statfs hst_statfs;
4953113Sgblack@eecs.umich.edu#if NO_STAT64
4963113Sgblack@eecs.umich.edu    typedef struct stat hst_stat;
4974189Sgblack@eecs.umich.edu    typedef struct stat hst_stat64;
4984189Sgblack@eecs.umich.edu#else
4993113Sgblack@eecs.umich.edu    typedef struct stat hst_stat;
5003113Sgblack@eecs.umich.edu    typedef struct stat64 hst_stat64;
5013113Sgblack@eecs.umich.edu#endif
5023113Sgblack@eecs.umich.edu
5038737Skoansin.tan@gmail.com//// Helper function to convert a host stat buffer to a target stat
5043113Sgblack@eecs.umich.edu//// buffer.  Also copies the target buffer out to the simulated
5058737Skoansin.tan@gmail.com//// memory space.  Used by stat(), fstat(), and lstat().
5063277Sgblack@eecs.umich.edu
5075515SMichael.Adler@intel.comtemplate <typename target_stat, typename host_stat>
5085515SMichael.Adler@intel.comvoid
5095515SMichael.Adler@intel.comconvertStatBuf(target_stat &tgt, host_stat *host, bool fakeTTY = false)
5105515SMichael.Adler@intel.com{
5115515SMichael.Adler@intel.com    using namespace TheISA;
5128737Skoansin.tan@gmail.com
5133277Sgblack@eecs.umich.edu    if (fakeTTY)
5148737Skoansin.tan@gmail.com        tgt->st_dev = 0xA;
5153277Sgblack@eecs.umich.edu    else
5168737Skoansin.tan@gmail.com        tgt->st_dev = host->st_dev;
5173277Sgblack@eecs.umich.edu    tgt->st_dev = TheISA::htog(tgt->st_dev);
5188737Skoansin.tan@gmail.com    tgt->st_ino = host->st_ino;
5193113Sgblack@eecs.umich.edu    tgt->st_ino = TheISA::htog(tgt->st_ino);
5203113Sgblack@eecs.umich.edu    tgt->st_mode = host->st_mode;
5213113Sgblack@eecs.umich.edu    if (fakeTTY) {
5223113Sgblack@eecs.umich.edu        // Claim to be a character device
5238737Skoansin.tan@gmail.com        tgt->st_mode &= ~S_IFMT;    // Clear S_IFMT
5243113Sgblack@eecs.umich.edu        tgt->st_mode |= S_IFCHR;    // Set S_IFCHR
5258737Skoansin.tan@gmail.com    }
5263114Sgblack@eecs.umich.edu    tgt->st_mode = TheISA::htog(tgt->st_mode);
5278737Skoansin.tan@gmail.com    tgt->st_nlink = host->st_nlink;
5283114Sgblack@eecs.umich.edu    tgt->st_nlink = TheISA::htog(tgt->st_nlink);
5298737Skoansin.tan@gmail.com    tgt->st_uid = host->st_uid;
5303114Sgblack@eecs.umich.edu    tgt->st_uid = TheISA::htog(tgt->st_uid);
5318737Skoansin.tan@gmail.com    tgt->st_gid = host->st_gid;
5324061Sgblack@eecs.umich.edu    tgt->st_gid = TheISA::htog(tgt->st_gid);
5334061Sgblack@eecs.umich.edu    if (fakeTTY)
5344061Sgblack@eecs.umich.edu        tgt->st_rdev = 0x880d;
5358737Skoansin.tan@gmail.com    else
5363113Sgblack@eecs.umich.edu        tgt->st_rdev = host->st_rdev;
5378737Skoansin.tan@gmail.com    tgt->st_rdev = TheISA::htog(tgt->st_rdev);
5383113Sgblack@eecs.umich.edu    tgt->st_size = host->st_size;
5393113Sgblack@eecs.umich.edu    tgt->st_size = TheISA::htog(tgt->st_size);
5403113Sgblack@eecs.umich.edu    tgt->st_atimeX = host->st_atime;
5413113Sgblack@eecs.umich.edu    tgt->st_atimeX = TheISA::htog(tgt->st_atimeX);
5423113Sgblack@eecs.umich.edu    tgt->st_mtimeX = host->st_mtime;
5433113Sgblack@eecs.umich.edu    tgt->st_mtimeX = TheISA::htog(tgt->st_mtimeX);
5443113Sgblack@eecs.umich.edu    tgt->st_ctimeX = host->st_ctime;
5453113Sgblack@eecs.umich.edu    tgt->st_ctimeX = TheISA::htog(tgt->st_ctimeX);
5464189Sgblack@eecs.umich.edu    // Force the block size to be 8KB. This helps to ensure buffered io works
5474189Sgblack@eecs.umich.edu    // consistently across different hosts.
5483113Sgblack@eecs.umich.edu    tgt->st_blksize = 0x2000;
5493113Sgblack@eecs.umich.edu    tgt->st_blksize = TheISA::htog(tgt->st_blksize);
5503113Sgblack@eecs.umich.edu    tgt->st_blocks = host->st_blocks;
5518737Skoansin.tan@gmail.com    tgt->st_blocks = TheISA::htog(tgt->st_blocks);
5523113Sgblack@eecs.umich.edu}
5538737Skoansin.tan@gmail.com
5543113Sgblack@eecs.umich.edu// Same for stat64
5558737Skoansin.tan@gmail.com
5563113Sgblack@eecs.umich.edutemplate <typename target_stat, typename host_stat64>
5573113Sgblack@eecs.umich.eduvoid
5583113Sgblack@eecs.umich.educonvertStat64Buf(target_stat &tgt, host_stat64 *host, bool fakeTTY = false)
5593113Sgblack@eecs.umich.edu{
5603113Sgblack@eecs.umich.edu    using namespace TheISA;
5613113Sgblack@eecs.umich.edu
5623113Sgblack@eecs.umich.edu    convertStatBuf<target_stat, host_stat64>(tgt, host, fakeTTY);
5633113Sgblack@eecs.umich.edu#if defined(STAT_HAVE_NSEC)
5643113Sgblack@eecs.umich.edu    tgt->st_atime_nsec = host->st_atime_nsec;
5653113Sgblack@eecs.umich.edu    tgt->st_atime_nsec = TheISA::htog(tgt->st_atime_nsec);
5668852Sandreas.hansson@arm.com    tgt->st_mtime_nsec = host->st_mtime_nsec;
5673113Sgblack@eecs.umich.edu    tgt->st_mtime_nsec = TheISA::htog(tgt->st_mtime_nsec);
5683113Sgblack@eecs.umich.edu    tgt->st_ctime_nsec = host->st_ctime_nsec;
5693113Sgblack@eecs.umich.edu    tgt->st_ctime_nsec = TheISA::htog(tgt->st_ctime_nsec);
5703113Sgblack@eecs.umich.edu#else
5713113Sgblack@eecs.umich.edu    tgt->st_atime_nsec = 0;
5723113Sgblack@eecs.umich.edu    tgt->st_mtime_nsec = 0;
5733113Sgblack@eecs.umich.edu    tgt->st_ctime_nsec = 0;
5743113Sgblack@eecs.umich.edu#endif
5753113Sgblack@eecs.umich.edu}
5763113Sgblack@eecs.umich.edu
5778852Sandreas.hansson@arm.com// Here are a couple of convenience functions
5783113Sgblack@eecs.umich.edutemplate<class OS>
5793113Sgblack@eecs.umich.eduvoid
5803113Sgblack@eecs.umich.educopyOutStatBuf(SETranslatingPortProxy &mem, Addr addr,
5813113Sgblack@eecs.umich.edu               hst_stat *host, bool fakeTTY = false)
5826686Stjones1@inf.ed.ac.uk{
5833113Sgblack@eecs.umich.edu    typedef TypedBufferArg<typename OS::tgt_stat> tgt_stat_buf;
5843113Sgblack@eecs.umich.edu    tgt_stat_buf tgt(addr);
5853113Sgblack@eecs.umich.edu    convertStatBuf<tgt_stat_buf, hst_stat>(tgt, host, fakeTTY);
586378SN/A    tgt.copyOut(mem);
587378SN/A}
5889141Smarc.orr@gmail.com
5899141Smarc.orr@gmail.comtemplate<class OS>
590360SN/Avoid
5911450SN/AcopyOutStat64Buf(SETranslatingPortProxy &mem, Addr addr,
5923114Sgblack@eecs.umich.edu                 hst_stat64 *host, bool fakeTTY = false)
5932680Sktlim@umich.edu{
594360SN/A    typedef TypedBufferArg<typename OS::tgt_stat64> tgt_stat_buf;
5956701Sgblack@eecs.umich.edu    tgt_stat_buf tgt(addr);
5966701Sgblack@eecs.umich.edu    convertStat64Buf<tgt_stat_buf, hst_stat64>(tgt, host, fakeTTY);
5976701Sgblack@eecs.umich.edu    tgt.copyOut(mem);
598360SN/A}
5991969SN/A
600360SN/Atemplate <class OS>
601360SN/Avoid
602360SN/AcopyOutStatfsBuf(SETranslatingPortProxy &mem, Addr addr,
6031458SN/A                 hst_statfs *host)
604360SN/A{
605360SN/A    TypedBufferArg<typename OS::tgt_statfs> tgt(addr);
6069141Smarc.orr@gmail.com
6071458SN/A    tgt->f_type = TheISA::htog(host->f_type);
6089141Smarc.orr@gmail.com#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__)
609360SN/A    tgt->f_bsize = TheISA::htog(host->f_iosize);
6109141Smarc.orr@gmail.com#else
6119141Smarc.orr@gmail.com    tgt->f_bsize = TheISA::htog(host->f_bsize);
6129141Smarc.orr@gmail.com#endif
613360SN/A    tgt->f_blocks = TheISA::htog(host->f_blocks);
614360SN/A    tgt->f_bfree = TheISA::htog(host->f_bfree);
615360SN/A    tgt->f_bavail = TheISA::htog(host->f_bavail);
61610027SChris.Adeniyi-Jones@arm.com    tgt->f_files = TheISA::htog(host->f_files);
6173114Sgblack@eecs.umich.edu    tgt->f_ffree = TheISA::htog(host->f_ffree);
61810027SChris.Adeniyi-Jones@arm.com    memcpy(&tgt->f_fsid, &host->f_fsid, sizeof(host->f_fsid));
619360SN/A#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__)
620360SN/A    tgt->f_namelen = TheISA::htog(host->f_namemax);
621360SN/A    tgt->f_frsize = TheISA::htog(host->f_bsize);
6228852Sandreas.hansson@arm.com#elif defined(__APPLE__)
6236701Sgblack@eecs.umich.edu    tgt->f_namelen = 0;
6241458SN/A    tgt->f_frsize = 0;
625360SN/A#else
626360SN/A    tgt->f_namelen = TheISA::htog(host->f_namelen);
627360SN/A    tgt->f_frsize = TheISA::htog(host->f_frsize);
628360SN/A#endif
6291706SN/A#if defined(__linux__)
6301458SN/A    memcpy(&tgt->f_spare, &host->f_spare, sizeof(host->f_spare));
631360SN/A#else
632360SN/A    /*
6336701Sgblack@eecs.umich.edu     * The fields are different sizes per OS. Don't bother with
6346701Sgblack@eecs.umich.edu     * f_spare or f_reserved on non-Linux for now.
635360SN/A     */
636360SN/A    memset(&tgt->f_spare, 0, sizeof(tgt->f_spare));
637360SN/A#endif
638360SN/A
639360SN/A    tgt.copyOut(mem);
640360SN/A}
641360SN/A
642360SN/A/// Target ioctl() handler.  For the most part, programs call ioctl()
643360SN/A/// only to find out if their stdout is a tty, to determine whether to
644360SN/A/// do line or block buffering.  We always claim that output fds are
645360SN/A/// not TTYs to provide repeatable results.
646360SN/Atemplate <class OS>
6471706SN/ASyscallReturn
648360SN/AioctlFunc(SyscallDesc *desc, int callnum, Process *p, ThreadContext *tc)
649360SN/A{
650360SN/A    int index = 0;
651360SN/A    int tgt_fd = p->getSyscallArg(tc, index);
652360SN/A    unsigned req = p->getSyscallArg(tc, index);
6533669Sbinkertn@umich.edu
6543669Sbinkertn@umich.edu    DPRINTF(SyscallVerbose, "ioctl(%d, 0x%x, ...)\n", tgt_fd, req);
6553669Sbinkertn@umich.edu
6561706SN/A    if (OS::isTtyReq(req))
6571706SN/A        return -ENOTTY;
6585795Ssaidi@eecs.umich.edu
6599143Ssteve.reinhardt@amd.com    auto dfdp = std::dynamic_pointer_cast<DeviceFDEntry>((*p->fds)[tgt_fd]);
6609142Ssteve.reinhardt@amd.com    if (!dfdp)
6619142Ssteve.reinhardt@amd.com        return -EBADF;
6629143Ssteve.reinhardt@amd.com
6635795Ssaidi@eecs.umich.edu    /**
6649143Ssteve.reinhardt@amd.com     * If the driver is valid, issue the ioctl through it. Otherwise,
6655795Ssaidi@eecs.umich.edu     * there's an implicit assumption that the device is a TTY type and we
6665795Ssaidi@eecs.umich.edu     * return that we do not have a valid TTY.
6675795Ssaidi@eecs.umich.edu     */
6689143Ssteve.reinhardt@amd.com    EmulatedDriver *emul_driver = dfdp->getDriver();
6695795Ssaidi@eecs.umich.edu    if (emul_driver)
670360SN/A        return emul_driver->ioctl(p, tc, req);
6719143Ssteve.reinhardt@amd.com
6729143Ssteve.reinhardt@amd.com    /**
6739143Ssteve.reinhardt@amd.com     * For lack of a better return code, return ENOTTY. Ideally, we should
6749143Ssteve.reinhardt@amd.com     * return something better here, but at least we issue the warning.
675360SN/A     */
676360SN/A    warn("Unsupported ioctl call (return ENOTTY): ioctl(%d, 0x%x, ...) @ \n",
67710027SChris.Adeniyi-Jones@arm.com         tgt_fd, req, tc->pcState());
67810027SChris.Adeniyi-Jones@arm.com    return -ENOTTY;
67910027SChris.Adeniyi-Jones@arm.com}
68010027SChris.Adeniyi-Jones@arm.com
68110027SChris.Adeniyi-Jones@arm.comtemplate <class OS>
68210027SChris.Adeniyi-Jones@arm.comSyscallReturn
68310027SChris.Adeniyi-Jones@arm.comopenImpl(SyscallDesc *desc, int callnum, Process *p, ThreadContext *tc,
68410027SChris.Adeniyi-Jones@arm.com         bool isopenat)
68510027SChris.Adeniyi-Jones@arm.com{
68610027SChris.Adeniyi-Jones@arm.com    int index = 0;
68710027SChris.Adeniyi-Jones@arm.com    int tgt_dirfd = -1;
68810027SChris.Adeniyi-Jones@arm.com
68910027SChris.Adeniyi-Jones@arm.com    /**
69010027SChris.Adeniyi-Jones@arm.com     * If using the openat variant, read in the target directory file
69110027SChris.Adeniyi-Jones@arm.com     * descriptor from the simulated process.
69210027SChris.Adeniyi-Jones@arm.com     */
69310027SChris.Adeniyi-Jones@arm.com    if (isopenat)
69410027SChris.Adeniyi-Jones@arm.com        tgt_dirfd = p->getSyscallArg(tc, index);
69510027SChris.Adeniyi-Jones@arm.com
69610027SChris.Adeniyi-Jones@arm.com    /**
69710027SChris.Adeniyi-Jones@arm.com     * Retrieve the simulated process' memory proxy and then read in the path
69810027SChris.Adeniyi-Jones@arm.com     * string from that memory space into the host's working memory space.
6996640Svince@csl.cornell.edu     */
7006640Svince@csl.cornell.edu    std::string path;
7016640Svince@csl.cornell.edu    if (!tc->getMemProxy().tryReadString(path, p->getSyscallArg(tc, index)))
7026640Svince@csl.cornell.edu        return -EFAULT;
7036640Svince@csl.cornell.edu
7046640Svince@csl.cornell.edu#ifdef __CYGWIN32__
7056640Svince@csl.cornell.edu    int host_flags = O_BINARY;
7066701Sgblack@eecs.umich.edu#else
7076701Sgblack@eecs.umich.edu    int host_flags = 0;
7086701Sgblack@eecs.umich.edu#endif
7096640Svince@csl.cornell.edu    /**
7106701Sgblack@eecs.umich.edu     * Translate target flags into host flags. Flags exist which are not
7116701Sgblack@eecs.umich.edu     * ported between architectures which can cause check failures.
7126640Svince@csl.cornell.edu     */
7138706Sandreas.hansson@arm.com    int tgt_flags = p->getSyscallArg(tc, index);
7146640Svince@csl.cornell.edu    for (int i = 0; i < OS::NUM_OPEN_FLAGS; i++) {
7156701Sgblack@eecs.umich.edu        if (tgt_flags & OS::openFlagTable[i].tgtFlag) {
7166640Svince@csl.cornell.edu            tgt_flags &= ~OS::openFlagTable[i].tgtFlag;
717360SN/A            host_flags |= OS::openFlagTable[i].hostFlag;
7181999SN/A        }
7191999SN/A    }
7201999SN/A    if (tgt_flags) {
7213114Sgblack@eecs.umich.edu        warn("open%s: cannot decode flags 0x%x",
7222680Sktlim@umich.edu             isopenat ? "at" : "", tgt_flags);
7231999SN/A    }
7241999SN/A#ifdef __CYGWIN32__
7251999SN/A    host_flags |= O_BINARY;
7266701Sgblack@eecs.umich.edu#endif
7278852Sandreas.hansson@arm.com
7286701Sgblack@eecs.umich.edu    int mode = p->getSyscallArg(tc, index);
7291999SN/A
7306701Sgblack@eecs.umich.edu    /**
7311999SN/A     * If the simulated process called open or openat with AT_FDCWD specified,
7326701Sgblack@eecs.umich.edu     * take the current working directory value which was passed into the
7331999SN/A     * process class as a Python parameter and append the current path to
7341999SN/A     * create a full path.
7351999SN/A     * Otherwise, openat with a valid target directory file descriptor has
7361999SN/A     * been called. If the path option, which was passed in as a parameter,
7371999SN/A     * is not absolute, retrieve the directory file descriptor's path and
7383669Sbinkertn@umich.edu     * prepend it to the path passed in as a parameter.
7393669Sbinkertn@umich.edu     * In every case, we should have a full path (which is relevant to the
7403669Sbinkertn@umich.edu     * host) to work with after this block has been passed.
7411999SN/A     */
7421999SN/A    if (!isopenat || (isopenat && tgt_dirfd == OS::TGT_AT_FDCWD)) {
7431999SN/A        path = p->fullPath(path);
7442218SN/A    } else if (!startswith(path, "/")) {
7451999SN/A        std::shared_ptr<FDEntry> fdep = ((*p->fds)[tgt_dirfd]);
7461999SN/A        auto ffdp = std::dynamic_pointer_cast<FileFDEntry>(fdep);
7471999SN/A        if (!ffdp)
7481999SN/A            return -EBADF;
7491999SN/A        path.insert(0, ffdp->getFileName() + "/");
7501999SN/A    }
7511999SN/A
7521999SN/A    /**
7533114Sgblack@eecs.umich.edu     * Since this is an emulated environment, we create pseudo file
7542680Sktlim@umich.edu     * descriptors for device requests that have been registered with
7551999SN/A     * the process class through Python; this allows us to create a file
7566701Sgblack@eecs.umich.edu     * descriptor for subsequent ioctl or mmap calls.
7576701Sgblack@eecs.umich.edu     */
7581999SN/A    if (startswith(path, "/dev/")) {
7591999SN/A        std::string filename = path.substr(strlen("/dev/"));
7601999SN/A        EmulatedDriver *drv = p->findDriver(filename);
7611999SN/A        if (drv) {
7621999SN/A            DPRINTF_SYSCALL(Verbose, "open%s: passing call to "
7636701Sgblack@eecs.umich.edu                            "driver open with path[%s]\n",
7641999SN/A                            isopenat ? "at" : "", path.c_str());
7651999SN/A            return drv->open(p, tc, mode, host_flags);
7661999SN/A        }
7671999SN/A        /**
7681999SN/A         * Fall through here for pass through to host devices, such
7691999SN/A         * as /dev/zero
7701999SN/A         */
7711999SN/A    }
7722218SN/A
7731999SN/A    /**
7741999SN/A     * Some special paths and files cannot be called on the host and need
7751999SN/A     * to be handled as special cases inside the simulator.
7761999SN/A     * If the full path that was created above does not match any of the
7775877Shsul@eecs.umich.edu     * special cases, pass it through to the open call on the host to let
7785877Shsul@eecs.umich.edu     * the host open the file on our behalf.
7795877Shsul@eecs.umich.edu     * If the host cannot open the file, return the host's error code back
7805877Shsul@eecs.umich.edu     * through the system call to the simulated process.
7815877Shsul@eecs.umich.edu     */
7826701Sgblack@eecs.umich.edu    int sim_fd = -1;
7836701Sgblack@eecs.umich.edu    std::vector<std::string> special_paths =
7846701Sgblack@eecs.umich.edu            { "/proc/", "/system/", "/sys/", "/platform/", "/etc/passwd" };
7856701Sgblack@eecs.umich.edu    for (auto entry : special_paths) {
7866701Sgblack@eecs.umich.edu        if (startswith(path, entry))
78710027SChris.Adeniyi-Jones@arm.com            sim_fd = OS::openSpecialFile(path, p, tc);
78810027SChris.Adeniyi-Jones@arm.com    }
78910027SChris.Adeniyi-Jones@arm.com    if (sim_fd == -1) {
79010027SChris.Adeniyi-Jones@arm.com        sim_fd = open(path.c_str(), host_flags, mode);
79110027SChris.Adeniyi-Jones@arm.com    }
7925877Shsul@eecs.umich.edu    if (sim_fd == -1) {
7935877Shsul@eecs.umich.edu        int local = -errno;
79410027SChris.Adeniyi-Jones@arm.com        DPRINTF_SYSCALL(Verbose, "open%s: failed -> path:%s\n",
79510027SChris.Adeniyi-Jones@arm.com                        isopenat ? "at" : "", path.c_str());
7965877Shsul@eecs.umich.edu        return local;
7975877Shsul@eecs.umich.edu    }
7985877Shsul@eecs.umich.edu
7995877Shsul@eecs.umich.edu    /**
8005877Shsul@eecs.umich.edu     * The file was opened successfully and needs to be recorded in the
80110027SChris.Adeniyi-Jones@arm.com     * process' file descriptor array so that it can be retrieved later.
80210027SChris.Adeniyi-Jones@arm.com     * The target file descriptor that is chosen will be the lowest unused
8035877Shsul@eecs.umich.edu     * file descriptor.
8048601Ssteve.reinhardt@amd.com     * Return the indirect target file descriptor back to the simulated
8055877Shsul@eecs.umich.edu     * process to act as a handle for the opened file.
8065877Shsul@eecs.umich.edu     */
8075877Shsul@eecs.umich.edu    auto ffdp = std::make_shared<FileFDEntry>(sim_fd, host_flags, path, 0);
80810027SChris.Adeniyi-Jones@arm.com    int tgt_fd = p->fds->allocFD(ffdp);
8095877Shsul@eecs.umich.edu    DPRINTF_SYSCALL(Verbose, "open%s: sim_fd[%d], target_fd[%d] -> path:%s\n",
8105877Shsul@eecs.umich.edu                    isopenat ? "at" : "", sim_fd, tgt_fd, path.c_str());
8115877Shsul@eecs.umich.edu    return tgt_fd;
81210027SChris.Adeniyi-Jones@arm.com}
81310027SChris.Adeniyi-Jones@arm.com
81410027SChris.Adeniyi-Jones@arm.com/// Target open() handler.
81510027SChris.Adeniyi-Jones@arm.comtemplate <class OS>
81610027SChris.Adeniyi-Jones@arm.comSyscallReturn
81710027SChris.Adeniyi-Jones@arm.comopenFunc(SyscallDesc *desc, int callnum, Process *process,
8185877Shsul@eecs.umich.edu         ThreadContext *tc)
81910027SChris.Adeniyi-Jones@arm.com{
82010027SChris.Adeniyi-Jones@arm.com    return openImpl<OS>(desc, callnum, process, tc, false);
82110027SChris.Adeniyi-Jones@arm.com}
82210027SChris.Adeniyi-Jones@arm.com
82310027SChris.Adeniyi-Jones@arm.com/// Target openat() handler.
82410027SChris.Adeniyi-Jones@arm.comtemplate <class OS>
82510027SChris.Adeniyi-Jones@arm.comSyscallReturn
82610027SChris.Adeniyi-Jones@arm.comopenatFunc(SyscallDesc *desc, int callnum, Process *process,
82710027SChris.Adeniyi-Jones@arm.com           ThreadContext *tc)
82810027SChris.Adeniyi-Jones@arm.com{
82910027SChris.Adeniyi-Jones@arm.com    return openImpl<OS>(desc, callnum, process, tc, true);
83010027SChris.Adeniyi-Jones@arm.com}
83110027SChris.Adeniyi-Jones@arm.com
8325877Shsul@eecs.umich.edu/// Target unlinkat() handler.
8335877Shsul@eecs.umich.edutemplate <class OS>
8345877Shsul@eecs.umich.eduSyscallReturn
83510027SChris.Adeniyi-Jones@arm.comunlinkatFunc(SyscallDesc *desc, int callnum, Process *process,
83610027SChris.Adeniyi-Jones@arm.com             ThreadContext *tc)
8378601Ssteve.reinhardt@amd.com{
83810027SChris.Adeniyi-Jones@arm.com    int index = 0;
8395877Shsul@eecs.umich.edu    int dirfd = process->getSyscallArg(tc, index);
8405877Shsul@eecs.umich.edu    if (dirfd != OS::TGT_AT_FDCWD)
8411999SN/A        warn("unlinkat: first argument not AT_FDCWD; unlikely to work");
842378SN/A
843360SN/A    return unlinkHelper(desc, callnum, process, tc, 1);
8441450SN/A}
8453114Sgblack@eecs.umich.edu
8462680Sktlim@umich.edu/// Target facessat() handler
847360SN/Atemplate <class OS>
848360SN/ASyscallReturn
849360SN/AfaccessatFunc(SyscallDesc *desc, int callnum, Process *process,
8506701Sgblack@eecs.umich.edu              ThreadContext *tc)
8518852Sandreas.hansson@arm.com{
8526701Sgblack@eecs.umich.edu    int index = 0;
8536701Sgblack@eecs.umich.edu    int dirfd = process->getSyscallArg(tc, index);
8546701Sgblack@eecs.umich.edu    if (dirfd != OS::TGT_AT_FDCWD)
8556701Sgblack@eecs.umich.edu        warn("faccessat: first argument not AT_FDCWD; unlikely to work");
856360SN/A    return accessFunc(desc, callnum, process, tc, 1);
8573669Sbinkertn@umich.edu}
8583669Sbinkertn@umich.edu
8593669Sbinkertn@umich.edu/// Target readlinkat() handler
860360SN/Atemplate <class OS>
861360SN/ASyscallReturn
862360SN/AreadlinkatFunc(SyscallDesc *desc, int callnum, Process *process,
863360SN/A               ThreadContext *tc)
8642218SN/A{
865360SN/A    int index = 0;
8668706Sandreas.hansson@arm.com    int dirfd = process->getSyscallArg(tc, index);
867360SN/A    if (dirfd != OS::TGT_AT_FDCWD)
8681458SN/A        warn("openat: first argument not AT_FDCWD; unlikely to work");
869360SN/A    return readlinkFunc(desc, callnum, process, tc, 1);
870360SN/A}
871360SN/A
8725074Ssaidi@eecs.umich.edu/// Target renameat() handler.
8735074Ssaidi@eecs.umich.edutemplate <class OS>
8745074Ssaidi@eecs.umich.eduSyscallReturn
8755074Ssaidi@eecs.umich.edurenameatFunc(SyscallDesc *desc, int callnum, Process *process,
8765074Ssaidi@eecs.umich.edu             ThreadContext *tc)
8775074Ssaidi@eecs.umich.edu{
8785074Ssaidi@eecs.umich.edu    int index = 0;
8795074Ssaidi@eecs.umich.edu
8806701Sgblack@eecs.umich.edu    int olddirfd = process->getSyscallArg(tc, index);
8818852Sandreas.hansson@arm.com    if (olddirfd != OS::TGT_AT_FDCWD)
8826701Sgblack@eecs.umich.edu        warn("renameat: first argument not AT_FDCWD; unlikely to work");
8835074Ssaidi@eecs.umich.edu
8846701Sgblack@eecs.umich.edu    std::string old_name;
8855074Ssaidi@eecs.umich.edu
8865074Ssaidi@eecs.umich.edu    if (!tc->getMemProxy().tryReadString(old_name,
8875074Ssaidi@eecs.umich.edu                                         process->getSyscallArg(tc, index)))
8885074Ssaidi@eecs.umich.edu        return -EFAULT;
8895208Ssaidi@eecs.umich.edu
8905208Ssaidi@eecs.umich.edu    int newdirfd = process->getSyscallArg(tc, index);
8915208Ssaidi@eecs.umich.edu    if (newdirfd != OS::TGT_AT_FDCWD)
8925208Ssaidi@eecs.umich.edu        warn("renameat: third argument not AT_FDCWD; unlikely to work");
8935074Ssaidi@eecs.umich.edu
8945074Ssaidi@eecs.umich.edu    std::string new_name;
8955208Ssaidi@eecs.umich.edu
8965074Ssaidi@eecs.umich.edu    if (!tc->getMemProxy().tryReadString(new_name,
8975074Ssaidi@eecs.umich.edu                                         process->getSyscallArg(tc, index)))
8985074Ssaidi@eecs.umich.edu        return -EFAULT;
8995074Ssaidi@eecs.umich.edu
9008706Sandreas.hansson@arm.com    // Adjust path for current working directory
9015074Ssaidi@eecs.umich.edu    old_name = process->fullPath(old_name);
9025074Ssaidi@eecs.umich.edu    new_name = process->fullPath(new_name);
9035074Ssaidi@eecs.umich.edu
9045074Ssaidi@eecs.umich.edu    int result = rename(old_name.c_str(), new_name.c_str());
9055074Ssaidi@eecs.umich.edu    return (result == -1) ? -errno : result;
90610027SChris.Adeniyi-Jones@arm.com}
90710027SChris.Adeniyi-Jones@arm.com
90810027SChris.Adeniyi-Jones@arm.com/// Target sysinfo() handler.
90910027SChris.Adeniyi-Jones@arm.comtemplate <class OS>
91010027SChris.Adeniyi-Jones@arm.comSyscallReturn
91110027SChris.Adeniyi-Jones@arm.comsysinfoFunc(SyscallDesc *desc, int callnum, Process *process,
91210027SChris.Adeniyi-Jones@arm.com            ThreadContext *tc)
91310027SChris.Adeniyi-Jones@arm.com{
91410027SChris.Adeniyi-Jones@arm.com
91510027SChris.Adeniyi-Jones@arm.com    int index = 0;
91610027SChris.Adeniyi-Jones@arm.com    TypedBufferArg<typename OS::tgt_sysinfo>
91710027SChris.Adeniyi-Jones@arm.com        sysinfo(process->getSyscallArg(tc, index));
91810027SChris.Adeniyi-Jones@arm.com
91910027SChris.Adeniyi-Jones@arm.com    sysinfo->uptime = seconds_since_epoch;
92010027SChris.Adeniyi-Jones@arm.com    sysinfo->totalram = process->system->memSize();
92110027SChris.Adeniyi-Jones@arm.com    sysinfo->mem_unit = 1;
92210027SChris.Adeniyi-Jones@arm.com
92310027SChris.Adeniyi-Jones@arm.com    sysinfo.copyOut(tc->getMemProxy());
92410027SChris.Adeniyi-Jones@arm.com
92510027SChris.Adeniyi-Jones@arm.com    return 0;
92610027SChris.Adeniyi-Jones@arm.com}
92710027SChris.Adeniyi-Jones@arm.com
92810027SChris.Adeniyi-Jones@arm.com/// Target chmod() handler.
92910027SChris.Adeniyi-Jones@arm.comtemplate <class OS>
93010027SChris.Adeniyi-Jones@arm.comSyscallReturn
93110027SChris.Adeniyi-Jones@arm.comchmodFunc(SyscallDesc *desc, int callnum, Process *process,
93210027SChris.Adeniyi-Jones@arm.com          ThreadContext *tc)
93310027SChris.Adeniyi-Jones@arm.com{
93410027SChris.Adeniyi-Jones@arm.com    std::string path;
93510027SChris.Adeniyi-Jones@arm.com
93610027SChris.Adeniyi-Jones@arm.com    int index = 0;
93710027SChris.Adeniyi-Jones@arm.com    if (!tc->getMemProxy().tryReadString(path,
93810027SChris.Adeniyi-Jones@arm.com                process->getSyscallArg(tc, index))) {
93910027SChris.Adeniyi-Jones@arm.com        return -EFAULT;
94010027SChris.Adeniyi-Jones@arm.com    }
94110027SChris.Adeniyi-Jones@arm.com
94210027SChris.Adeniyi-Jones@arm.com    uint32_t mode = process->getSyscallArg(tc, index);
9431999SN/A    mode_t hostMode = 0;
9441999SN/A
9451999SN/A    // XXX translate mode flags via OS::something???
9463114Sgblack@eecs.umich.edu    hostMode = mode;
9472680Sktlim@umich.edu
9481999SN/A    // Adjust path for current working directory
9496701Sgblack@eecs.umich.edu    path = process->fullPath(path);
9506701Sgblack@eecs.umich.edu
9516701Sgblack@eecs.umich.edu    // do the chmod
9521999SN/A    int result = chmod(path.c_str(), hostMode);
9531999SN/A    if (result < 0)
9541999SN/A        return -errno;
9551999SN/A
9561999SN/A    return 0;
9572764Sstever@eecs.umich.edu}
9582064SN/A
9592064SN/Atemplate <class OS>
9602064SN/ASyscallReturn
9612064SN/ApollFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
9621999SN/A{
9632064SN/A    int index = 0;
9641999SN/A    Addr fdsPtr = p->getSyscallArg(tc, index);
9651999SN/A    int nfds = p->getSyscallArg(tc, index);
9662218SN/A    int tmout = p->getSyscallArg(tc, index);
9671999SN/A
9688706Sandreas.hansson@arm.com    BufferArg fdsBuf(fdsPtr, sizeof(struct pollfd) * nfds);
9691999SN/A    fdsBuf.copyIn(tc->getMemProxy());
9701999SN/A
9711999SN/A    /**
9721999SN/A     * Record the target file descriptors in a local variable. We need to
9731999SN/A     * replace them with host file descriptors but we need a temporary copy
974378SN/A     * for later. Afterwards, replace each target file descriptor in the
975360SN/A     * poll_fd array with its host_fd.
9761450SN/A     */
9773114Sgblack@eecs.umich.edu    int temp_tgt_fds[nfds];
9782680Sktlim@umich.edu    for (index = 0; index < nfds; index++) {
979360SN/A        temp_tgt_fds[index] = ((struct pollfd *)fdsBuf.bufferPtr())[index].fd;
980360SN/A        auto tgt_fd = temp_tgt_fds[index];
981360SN/A        auto hbfdp = std::dynamic_pointer_cast<HBFDEntry>((*p->fds)[tgt_fd]);
9826701Sgblack@eecs.umich.edu        if (!hbfdp)
9838852Sandreas.hansson@arm.com            return -EBADF;
9846701Sgblack@eecs.umich.edu        auto host_fd = hbfdp->getSimFD();
9856701Sgblack@eecs.umich.edu        ((struct pollfd *)fdsBuf.bufferPtr())[index].fd = host_fd;
9866701Sgblack@eecs.umich.edu    }
9876701Sgblack@eecs.umich.edu
988360SN/A    /**
9893669Sbinkertn@umich.edu     * We cannot allow an infinite poll to occur or it will inevitably cause
9903669Sbinkertn@umich.edu     * a deadlock in the gem5 simulator with clone. We must pass in tmout with
9913669Sbinkertn@umich.edu     * a non-negative value, however it also makes no sense to poll on the
992360SN/A     * underlying host for any other time than tmout a zero timeout.
993360SN/A     */
994360SN/A    int status;
995360SN/A    if (tmout < 0) {
9961458SN/A        status = poll((struct pollfd *)fdsBuf.bufferPtr(), nfds, 0);
997360SN/A        if (status == 0) {
9988706Sandreas.hansson@arm.com            /**
999360SN/A             * If blocking indefinitely, check the signal list to see if a
10001458SN/A             * signal would break the poll out of the retry cycle and try
1001360SN/A             * to return the signal interrupt instead.
1002360SN/A             */
10031999SN/A            System *sysh = tc->getSystemPtr();
10041999SN/A            std::list<BasicSignal>::iterator it;
10051999SN/A            for (it=sysh->signalList.begin(); it!=sysh->signalList.end(); it++)
10063114Sgblack@eecs.umich.edu                if (it->receiver == p)
10072680Sktlim@umich.edu                    return -EINTR;
10081999SN/A            return SyscallReturn::retry();
10091999SN/A        }
10101999SN/A    } else
10116701Sgblack@eecs.umich.edu        status = poll((struct pollfd *)fdsBuf.bufferPtr(), nfds, 0);
10128852Sandreas.hansson@arm.com
10136701Sgblack@eecs.umich.edu    if (status == -1)
10146701Sgblack@eecs.umich.edu        return -errno;
10156701Sgblack@eecs.umich.edu
10166701Sgblack@eecs.umich.edu    /**
10171999SN/A     * Replace each host_fd in the returned poll_fd array with its original
10183669Sbinkertn@umich.edu     * target file descriptor.
10193669Sbinkertn@umich.edu     */
10203669Sbinkertn@umich.edu    for (index = 0; index < nfds; index++) {
10212764Sstever@eecs.umich.edu        auto tgt_fd = temp_tgt_fds[index];
10222064SN/A        ((struct pollfd *)fdsBuf.bufferPtr())[index].fd = tgt_fd;
10232064SN/A    }
10242064SN/A
10251999SN/A    /**
10261999SN/A     * Copy out the pollfd struct because the host may have updated fields
10272064SN/A     * in the structure.
10281999SN/A     */
10291999SN/A    fdsBuf.copyOut(tc->getMemProxy());
10301999SN/A
10311999SN/A    return status;
10328706Sandreas.hansson@arm.com}
10331999SN/A
10341999SN/A/// Target fchmod() handler.
10351999SN/Atemplate <class OS>
10361999SN/ASyscallReturn
1037378SN/AfchmodFunc(SyscallDesc *desc, int callnum, Process *p, ThreadContext *tc)
1038360SN/A{
10391450SN/A    int index = 0;
10403114Sgblack@eecs.umich.edu    int tgt_fd = p->getSyscallArg(tc, index);
10412680Sktlim@umich.edu    uint32_t mode = p->getSyscallArg(tc, index);
1042360SN/A
10436701Sgblack@eecs.umich.edu    auto ffdp = std::dynamic_pointer_cast<FileFDEntry>((*p->fds)[tgt_fd]);
10446701Sgblack@eecs.umich.edu    if (!ffdp)
10456701Sgblack@eecs.umich.edu        return -EBADF;
1046360SN/A    int sim_fd = ffdp->getSimFD();
10471969SN/A
1048360SN/A    mode_t hostMode = mode;
1049360SN/A
10501458SN/A    int result = fchmod(sim_fd, hostMode);
1051360SN/A
1052360SN/A    return (result < 0) ? -errno : 0;
1053360SN/A}
1054360SN/A
1055360SN/A/// Target mremap() handler.
10561458SN/Atemplate <class OS>
1057360SN/ASyscallReturn
10588706Sandreas.hansson@arm.commremapFunc(SyscallDesc *desc, int callnum, Process *process, ThreadContext *tc)
10592021SN/A{
10601458SN/A    int index = 0;
1061360SN/A    Addr start = process->getSyscallArg(tc, index);
1062360SN/A    uint64_t old_length = process->getSyscallArg(tc, index);
1063360SN/A    uint64_t new_length = process->getSyscallArg(tc, index);
10641706SN/A    uint64_t flags = process->getSyscallArg(tc, index);
10651706SN/A    uint64_t provided_address = 0;
10661706SN/A    bool use_provided_address = flags & OS::TGT_MREMAP_FIXED;
10673114Sgblack@eecs.umich.edu
10682680Sktlim@umich.edu    if (use_provided_address)
10691706SN/A        provided_address = process->getSyscallArg(tc, index);
10701706SN/A
10711706SN/A    if ((start % TheISA::PageBytes != 0) ||
10726701Sgblack@eecs.umich.edu        (provided_address % TheISA::PageBytes != 0)) {
10738852Sandreas.hansson@arm.com        warn("mremap failing: arguments not page aligned");
10746701Sgblack@eecs.umich.edu        return -EINVAL;
10756701Sgblack@eecs.umich.edu    }
10766701Sgblack@eecs.umich.edu
10776701Sgblack@eecs.umich.edu    new_length = roundUp(new_length, TheISA::PageBytes);
10781706SN/A
10793669Sbinkertn@umich.edu    if (new_length > old_length) {
10803669Sbinkertn@umich.edu        std::shared_ptr<MemState> mem_state = process->memState;
10813669Sbinkertn@umich.edu        Addr mmap_end = mem_state->getMmapEnd();
10821706SN/A
10831706SN/A        if ((start + old_length) == mmap_end &&
10841706SN/A            (!use_provided_address || provided_address == start)) {
10851706SN/A            // This case cannot occur when growing downward, as
10862218SN/A            // start is greater than or equal to mmap_end.
10871706SN/A            uint64_t diff = new_length - old_length;
10888706Sandreas.hansson@arm.com            process->allocateMem(mmap_end, diff);
10891706SN/A            mem_state->setMmapEnd(mmap_end + diff);
10901706SN/A            return start;
10911706SN/A        } else {
10921706SN/A            if (!use_provided_address && !(flags & OS::TGT_MREMAP_MAYMOVE)) {
10931706SN/A                warn("can't remap here and MREMAP_MAYMOVE flag not set\n");
10941706SN/A                return -ENOMEM;
10951706SN/A            } else {
10961706SN/A                uint64_t new_start = provided_address;
10973114Sgblack@eecs.umich.edu                if (!use_provided_address) {
10982680Sktlim@umich.edu                    new_start = process->mmapGrowsDown() ?
10991706SN/A                                mmap_end - new_length : mmap_end;
11006701Sgblack@eecs.umich.edu                    mmap_end = process->mmapGrowsDown() ?
11016701Sgblack@eecs.umich.edu                               new_start : mmap_end + new_length;
11026701Sgblack@eecs.umich.edu                    mem_state->setMmapEnd(mmap_end);
11031706SN/A                }
11041706SN/A
11051706SN/A                process->pTable->remap(start, old_length, new_start);
11061706SN/A                warn("mremapping to new vaddr %08p-%08p, adding %d\n",
11071706SN/A                     new_start, new_start + new_length,
11081706SN/A                     new_length - old_length);
11091706SN/A                // add on the remaining unallocated pages
11101706SN/A                process->allocateMem(new_start + old_length,
11112218SN/A                                     new_length - old_length,
11121706SN/A                                     use_provided_address /* clobber */);
11138706Sandreas.hansson@arm.com                if (use_provided_address &&
11141706SN/A                    ((new_start + new_length > mem_state->getMmapEnd() &&
11151706SN/A                      !process->mmapGrowsDown()) ||
11161706SN/A                    (new_start < mem_state->getMmapEnd() &&
11171706SN/A                      process->mmapGrowsDown()))) {
11181706SN/A                    // something fishy going on here, at least notify the user
11191999SN/A                    // @todo: increase mmap_end?
11201999SN/A                    warn("mmap region limit exceeded with MREMAP_FIXED\n");
11211999SN/A                }
11223114Sgblack@eecs.umich.edu                warn("returning %08p as start\n", new_start);
11232680Sktlim@umich.edu                return new_start;
11241999SN/A            }
11256701Sgblack@eecs.umich.edu        }
11266701Sgblack@eecs.umich.edu    } else {
11271999SN/A        if (use_provided_address && provided_address != start)
11281999SN/A            process->pTable->remap(start, new_length, provided_address);
11291999SN/A        process->pTable->unmap(start + new_length, old_length - new_length);
11301999SN/A        return use_provided_address ? provided_address : start;
11311999SN/A    }
11328852Sandreas.hansson@arm.com}
11336701Sgblack@eecs.umich.edu
11346701Sgblack@eecs.umich.edu/// Target stat() handler.
11351999SN/Atemplate <class OS>
11366227Snate@binkert.orgSyscallReturn
11371999SN/AstatFunc(SyscallDesc *desc, int callnum, Process *process,
11382461SN/A         ThreadContext *tc)
11398852Sandreas.hansson@arm.com{
11408852Sandreas.hansson@arm.com    std::string path;
11418737Skoansin.tan@gmail.com
11421999SN/A    int index = 0;
11438852Sandreas.hansson@arm.com    if (!tc->getMemProxy().tryReadString(path,
11448852Sandreas.hansson@arm.com                process->getSyscallArg(tc, index))) {
11451999SN/A        return -EFAULT;
11461999SN/A    }
11471999SN/A    Addr bufPtr = process->getSyscallArg(tc, index);
11481999SN/A
11496227Snate@binkert.org    // Adjust path for current working directory
11501999SN/A    path = process->fullPath(path);
11511999SN/A
11521999SN/A    struct stat hostBuf;
11532218SN/A    int result = stat(path.c_str(), &hostBuf);
11541999SN/A
11551999SN/A    if (result < 0)
11561999SN/A        return -errno;
11571999SN/A
11581999SN/A    copyOutStatBuf<OS>(tc->getMemProxy(), bufPtr, &hostBuf);
1159378SN/A
1160378SN/A    return 0;
1161378SN/A}
1162378SN/A
1163378SN/A
11648324Ssteve.reinhardt@amd.com/// Target stat64() handler.
11658324Ssteve.reinhardt@amd.comtemplate <class OS>
1166360SN/ASyscallReturn
11671450SN/Astat64Func(SyscallDesc *desc, int callnum, Process *process,
11683114Sgblack@eecs.umich.edu           ThreadContext *tc)
1169360SN/A{
11706701Sgblack@eecs.umich.edu    std::string path;
11716701Sgblack@eecs.umich.edu
11726701Sgblack@eecs.umich.edu    int index = 0;
11736701Sgblack@eecs.umich.edu    if (!tc->getMemProxy().tryReadString(path,
11746701Sgblack@eecs.umich.edu                process->getSyscallArg(tc, index)))
11758324Ssteve.reinhardt@amd.com        return -EFAULT;
11766701Sgblack@eecs.umich.edu    Addr bufPtr = process->getSyscallArg(tc, index);
1177360SN/A
11789008Sgblack@eecs.umich.edu    // Adjust path for current working directory
11799008Sgblack@eecs.umich.edu    path = process->fullPath(path);
11809008Sgblack@eecs.umich.edu
11818324Ssteve.reinhardt@amd.com#if NO_STAT64
11828324Ssteve.reinhardt@amd.com    struct stat  hostBuf;
11838324Ssteve.reinhardt@amd.com    int result = stat(path.c_str(), &hostBuf);
11848324Ssteve.reinhardt@amd.com#else
11858324Ssteve.reinhardt@amd.com    struct stat64 hostBuf;
11868324Ssteve.reinhardt@amd.com    int result = stat64(path.c_str(), &hostBuf);
11878324Ssteve.reinhardt@amd.com#endif
11888324Ssteve.reinhardt@amd.com
11898324Ssteve.reinhardt@amd.com    if (result < 0)
11908324Ssteve.reinhardt@amd.com        return -errno;
11918324Ssteve.reinhardt@amd.com
11928324Ssteve.reinhardt@amd.com    copyOutStat64Buf<OS>(tc->getMemProxy(), bufPtr, &hostBuf);
11938324Ssteve.reinhardt@amd.com
11948324Ssteve.reinhardt@amd.com    return 0;
11958324Ssteve.reinhardt@amd.com}
11965877Shsul@eecs.umich.edu
11972544SN/A
11982544SN/A/// Target fstatat64() handler.
11992544SN/Atemplate <class OS>
12002544SN/ASyscallReturn
12012544SN/Afstatat64Func(SyscallDesc *desc, int callnum, Process *process,
12022544SN/A              ThreadContext *tc)
1203360SN/A{
1204360SN/A    int index = 0;
12058600Ssteve.reinhardt@amd.com    int dirfd = process->getSyscallArg(tc, index);
12068600Ssteve.reinhardt@amd.com    if (dirfd != OS::TGT_AT_FDCWD)
12078600Ssteve.reinhardt@amd.com        warn("fstatat64: first argument not AT_FDCWD; unlikely to work");
12088600Ssteve.reinhardt@amd.com
12098600Ssteve.reinhardt@amd.com    std::string path;
12108600Ssteve.reinhardt@amd.com    if (!tc->getMemProxy().tryReadString(path,
12118600Ssteve.reinhardt@amd.com                process->getSyscallArg(tc, index)))
12128600Ssteve.reinhardt@amd.com        return -EFAULT;
12138600Ssteve.reinhardt@amd.com    Addr bufPtr = process->getSyscallArg(tc, index);
12148600Ssteve.reinhardt@amd.com
12158600Ssteve.reinhardt@amd.com    // Adjust path for current working directory
12168600Ssteve.reinhardt@amd.com    path = process->fullPath(path);
12178600Ssteve.reinhardt@amd.com
12188600Ssteve.reinhardt@amd.com#if NO_STAT64
12198600Ssteve.reinhardt@amd.com    struct stat  hostBuf;
12208600Ssteve.reinhardt@amd.com    int result = stat(path.c_str(), &hostBuf);
12218600Ssteve.reinhardt@amd.com#else
12228600Ssteve.reinhardt@amd.com    struct stat64 hostBuf;
12238600Ssteve.reinhardt@amd.com    int result = stat64(path.c_str(), &hostBuf);
12248600Ssteve.reinhardt@amd.com#endif
12258600Ssteve.reinhardt@amd.com
12268600Ssteve.reinhardt@amd.com    if (result < 0)
12278600Ssteve.reinhardt@amd.com        return -errno;
12288600Ssteve.reinhardt@amd.com
12292544SN/A    copyOutStat64Buf<OS>(tc->getMemProxy(), bufPtr, &hostBuf);
12302544SN/A
12318600Ssteve.reinhardt@amd.com    return 0;
12328600Ssteve.reinhardt@amd.com}
12338600Ssteve.reinhardt@amd.com
12348600Ssteve.reinhardt@amd.com
12358600Ssteve.reinhardt@amd.com/// Target fstat64() handler.
12368600Ssteve.reinhardt@amd.comtemplate <class OS>
12378600Ssteve.reinhardt@amd.comSyscallReturn
12388600Ssteve.reinhardt@amd.comfstat64Func(SyscallDesc *desc, int callnum, Process *p, ThreadContext *tc)
12398600Ssteve.reinhardt@amd.com{
12408600Ssteve.reinhardt@amd.com    int index = 0;
12416672Sgblack@eecs.umich.edu    int tgt_fd = p->getSyscallArg(tc, index);
12428600Ssteve.reinhardt@amd.com    Addr bufPtr = p->getSyscallArg(tc, index);
12438601Ssteve.reinhardt@amd.com
12442544SN/A    auto ffdp = std::dynamic_pointer_cast<FileFDEntry>((*p->fds)[tgt_fd]);
12451458SN/A    if (!ffdp)
1246360SN/A        return -EBADF;
1247360SN/A    int sim_fd = ffdp->getSimFD();
1248378SN/A
1249360SN/A#if NO_STAT64
12501450SN/A    struct stat  hostBuf;
12513114Sgblack@eecs.umich.edu    int result = fstat(sim_fd, &hostBuf);
12522680Sktlim@umich.edu#else
1253360SN/A    struct stat64  hostBuf;
12546701Sgblack@eecs.umich.edu    int result = fstat64(sim_fd, &hostBuf);
12556701Sgblack@eecs.umich.edu#endif
12566701Sgblack@eecs.umich.edu
1257360SN/A    if (result < 0)
1258360SN/A        return -errno;
12592064SN/A
12605877Shsul@eecs.umich.edu    copyOutStat64Buf<OS>(tc->getMemProxy(), bufPtr, &hostBuf, (sim_fd == 1));
12612064SN/A
12628737Skoansin.tan@gmail.com    return 0;
12638737Skoansin.tan@gmail.com}
12642064SN/A
1265360SN/A
12665877Shsul@eecs.umich.edu/// Target lstat() handler.
12675877Shsul@eecs.umich.edutemplate <class OS>
12685877Shsul@eecs.umich.eduSyscallReturn
12698737Skoansin.tan@gmail.comlstatFunc(SyscallDesc *desc, int callnum, Process *process,
12708737Skoansin.tan@gmail.com          ThreadContext *tc)
12715877Shsul@eecs.umich.edu{
12725877Shsul@eecs.umich.edu    std::string path;
12732064SN/A
12742064SN/A    int index = 0;
12752064SN/A    if (!tc->getMemProxy().tryReadString(path,
12762064SN/A                process->getSyscallArg(tc, index))) {
12772064SN/A        return -EFAULT;
1278360SN/A    }
1279360SN/A    Addr bufPtr = process->getSyscallArg(tc, index);
12808706Sandreas.hansson@arm.com
12811458SN/A    // Adjust path for current working directory
1282360SN/A    path = process->fullPath(path);
1283360SN/A
1284378SN/A    struct stat hostBuf;
1285360SN/A    int result = lstat(path.c_str(), &hostBuf);
12861450SN/A
12873114Sgblack@eecs.umich.edu    if (result < 0)
12882680Sktlim@umich.edu        return -errno;
1289360SN/A
12906701Sgblack@eecs.umich.edu    copyOutStatBuf<OS>(tc->getMemProxy(), bufPtr, &hostBuf);
12916701Sgblack@eecs.umich.edu
1292360SN/A    return 0;
1293360SN/A}
1294360SN/A
12956109Ssanchezd@stanford.edu/// Target lstat64() handler.
12966109Ssanchezd@stanford.edutemplate <class OS>
1297360SN/ASyscallReturn
12988706Sandreas.hansson@arm.comlstat64Func(SyscallDesc *desc, int callnum, Process *process,
1299360SN/A            ThreadContext *tc)
13001458SN/A{
1301360SN/A    std::string path;
1302360SN/A
1303360SN/A    int index = 0;
13041999SN/A    if (!tc->getMemProxy().tryReadString(path,
13051999SN/A                process->getSyscallArg(tc, index))) {
13061999SN/A        return -EFAULT;
13073114Sgblack@eecs.umich.edu    }
13082680Sktlim@umich.edu    Addr bufPtr = process->getSyscallArg(tc, index);
13091999SN/A
13101999SN/A    // Adjust path for current working directory
13111999SN/A    path = process->fullPath(path);
13126701Sgblack@eecs.umich.edu
13138852Sandreas.hansson@arm.com#if NO_STAT64
13146701Sgblack@eecs.umich.edu    struct stat hostBuf;
13156701Sgblack@eecs.umich.edu    int result = lstat(path.c_str(), &hostBuf);
13166701Sgblack@eecs.umich.edu#else
13171999SN/A    struct stat64 hostBuf;
13186701Sgblack@eecs.umich.edu    int result = lstat64(path.c_str(), &hostBuf);
13196701Sgblack@eecs.umich.edu#endif
13208706Sandreas.hansson@arm.com
13211999SN/A    if (result < 0)
13221999SN/A        return -errno;
13231999SN/A
13241999SN/A    copyOutStat64Buf<OS>(tc->getMemProxy(), bufPtr, &hostBuf);
13258737Skoansin.tan@gmail.com
13268737Skoansin.tan@gmail.com    return 0;
13271999SN/A}
13283669Sbinkertn@umich.edu
13293669Sbinkertn@umich.edu/// Target fstat() handler.
13303669Sbinkertn@umich.edutemplate <class OS>
13313669Sbinkertn@umich.eduSyscallReturn
13321999SN/AfstatFunc(SyscallDesc *desc, int callnum, Process *p, ThreadContext *tc)
13331999SN/A{
13341999SN/A    int index = 0;
13351999SN/A    int tgt_fd = p->getSyscallArg(tc, index);
13361999SN/A    Addr bufPtr = p->getSyscallArg(tc, index);
13371999SN/A
13381999SN/A    DPRINTF_SYSCALL(Verbose, "fstat(%d, ...)\n", tgt_fd);
1339378SN/A
1340360SN/A    auto ffdp = std::dynamic_pointer_cast<FileFDEntry>((*p->fds)[tgt_fd]);
13411450SN/A    if (!ffdp)
13423114Sgblack@eecs.umich.edu        return -EBADF;
13432680Sktlim@umich.edu    int sim_fd = ffdp->getSimFD();
1344360SN/A
13456701Sgblack@eecs.umich.edu    struct stat hostBuf;
13466701Sgblack@eecs.umich.edu    int result = fstat(sim_fd, &hostBuf);
13476701Sgblack@eecs.umich.edu
1348360SN/A    if (result < 0)
13493670Sbinkertn@umich.edu        return -errno;
13503670Sbinkertn@umich.edu
1351360SN/A    copyOutStatBuf<OS>(tc->getMemProxy(), bufPtr, &hostBuf, (sim_fd == 1));
1352360SN/A
1353360SN/A    return 0;
1354360SN/A}
1355360SN/A
1356360SN/A/// Target statfs() handler.
1357360SN/Atemplate <class OS>
1358360SN/ASyscallReturn
1359360SN/AstatfsFunc(SyscallDesc *desc, int callnum, Process *process,
1360360SN/A           ThreadContext *tc)
1361360SN/A{
1362360SN/A#if NO_STATFS
1363360SN/A    warn("Host OS cannot support calls to statfs. Ignoring syscall");
1364360SN/A#else
1365360SN/A    std::string path;
1366360SN/A
1367360SN/A    int index = 0;
13683670Sbinkertn@umich.edu    if (!tc->getMemProxy().tryReadString(path,
13693670Sbinkertn@umich.edu                process->getSyscallArg(tc, index))) {
13703670Sbinkertn@umich.edu        return -EFAULT;
13718737Skoansin.tan@gmail.com    }
13728737Skoansin.tan@gmail.com    Addr bufPtr = process->getSyscallArg(tc, index);
13733670Sbinkertn@umich.edu
13743670Sbinkertn@umich.edu    // Adjust path for current working directory
13753670Sbinkertn@umich.edu    path = process->fullPath(path);
13763670Sbinkertn@umich.edu
13773670Sbinkertn@umich.edu    struct statfs hostBuf;
13783670Sbinkertn@umich.edu    int result = statfs(path.c_str(), &hostBuf);
13793670Sbinkertn@umich.edu
13803670Sbinkertn@umich.edu    if (result < 0)
13813670Sbinkertn@umich.edu        return -errno;
13823670Sbinkertn@umich.edu
13833670Sbinkertn@umich.edu    copyOutStatfsBuf<OS>(tc->getMemProxy(), bufPtr, &hostBuf);
13843670Sbinkertn@umich.edu#endif
13853670Sbinkertn@umich.edu    return 0;
13868706Sandreas.hansson@arm.com}
1387360SN/A
13881458SN/Atemplate <class OS>
1389360SN/ASyscallReturn
1390360SN/AcloneFunc(SyscallDesc *desc, int callnum, Process *p, ThreadContext *tc)
13916683Stjones1@inf.ed.ac.uk{
13926683Stjones1@inf.ed.ac.uk    int index = 0;
13936683Stjones1@inf.ed.ac.uk
13946683Stjones1@inf.ed.ac.uk    RegVal flags = p->getSyscallArg(tc, index);
13956683Stjones1@inf.ed.ac.uk    RegVal newStack = p->getSyscallArg(tc, index);
13966683Stjones1@inf.ed.ac.uk    Addr ptidPtr = p->getSyscallArg(tc, index);
13976701Sgblack@eecs.umich.edu
13986701Sgblack@eecs.umich.edu#if THE_ISA == RISCV_ISA or THE_ISA == ARM_ISA
13996683Stjones1@inf.ed.ac.uk    /**
14006683Stjones1@inf.ed.ac.uk     * Linux sets CLONE_BACKWARDS flag for RISC-V and Arm.
14017823Ssteve.reinhardt@amd.com     * The flag defines the list of clone() arguments in the following
14026683Stjones1@inf.ed.ac.uk     * order: flags -> newStack -> ptidPtr -> tlsPtr -> ctidPtr
14036683Stjones1@inf.ed.ac.uk     */
14046683Stjones1@inf.ed.ac.uk    Addr tlsPtr = p->getSyscallArg(tc, index);
14056683Stjones1@inf.ed.ac.uk    Addr ctidPtr = p->getSyscallArg(tc, index);
14066683Stjones1@inf.ed.ac.uk#else
14076683Stjones1@inf.ed.ac.uk    Addr ctidPtr = p->getSyscallArg(tc, index);
14088737Skoansin.tan@gmail.com    Addr tlsPtr = p->getSyscallArg(tc, index);
14096683Stjones1@inf.ed.ac.uk#endif
14106683Stjones1@inf.ed.ac.uk
14118706Sandreas.hansson@arm.com    if (((flags & OS::TGT_CLONE_SIGHAND)&& !(flags & OS::TGT_CLONE_VM)) ||
14126683Stjones1@inf.ed.ac.uk        ((flags & OS::TGT_CLONE_THREAD) && !(flags & OS::TGT_CLONE_SIGHAND)) ||
14136683Stjones1@inf.ed.ac.uk        ((flags & OS::TGT_CLONE_FS)     &&  (flags & OS::TGT_CLONE_NEWNS)) ||
14146683Stjones1@inf.ed.ac.uk        ((flags & OS::TGT_CLONE_NEWIPC) &&  (flags & OS::TGT_CLONE_SYSVSEM)) ||
14156683Stjones1@inf.ed.ac.uk        ((flags & OS::TGT_CLONE_NEWPID) &&  (flags & OS::TGT_CLONE_THREAD)) ||
14162553SN/A        ((flags & OS::TGT_CLONE_VM)     && !(newStack)))
14176684Stjones1@inf.ed.ac.uk        return -EINVAL;
14186684Stjones1@inf.ed.ac.uk
14196684Stjones1@inf.ed.ac.uk    ThreadContext *ctc;
14206684Stjones1@inf.ed.ac.uk    if (!(ctc = p->findFreeContext()))
14216684Stjones1@inf.ed.ac.uk        fatal("clone: no spare thread context in system");
14226684Stjones1@inf.ed.ac.uk
14236684Stjones1@inf.ed.ac.uk    /**
14246684Stjones1@inf.ed.ac.uk     * Note that ProcessParams is generated by swig and there are no other
14256684Stjones1@inf.ed.ac.uk     * examples of how to create anything but this default constructor. The
14266684Stjones1@inf.ed.ac.uk     * fields are manually initialized instead of passing parameters to the
14276701Sgblack@eecs.umich.edu     * constructor.
14286701Sgblack@eecs.umich.edu     */
14296684Stjones1@inf.ed.ac.uk    ProcessParams *pp = new ProcessParams();
14306684Stjones1@inf.ed.ac.uk    pp->executable.assign(*(new std::string(p->progName())));
14318737Skoansin.tan@gmail.com    pp->cmd.push_back(*(new std::string(p->progName())));
14328852Sandreas.hansson@arm.com    pp->system = p->system;
14338852Sandreas.hansson@arm.com    pp->cwd.assign(p->getcwd());
14346684Stjones1@inf.ed.ac.uk    pp->input.assign("stdin");
14356684Stjones1@inf.ed.ac.uk    pp->output.assign("stdout");
14366684Stjones1@inf.ed.ac.uk    pp->errout.assign("stderr");
14372553SN/A    pp->uid = p->uid();
14382553SN/A    pp->euid = p->euid();
14391354SN/A    pp->gid = p->gid();
1440    pp->egid = p->egid();
1441
1442    /* Find the first free PID that's less than the maximum */
1443    std::set<int> const& pids = p->system->PIDs;
1444    int temp_pid = *pids.begin();
1445    do {
1446        temp_pid++;
1447    } while (pids.find(temp_pid) != pids.end());
1448    if (temp_pid >= System::maxPID)
1449        fatal("temp_pid is too large: %d", temp_pid);
1450
1451    pp->pid = temp_pid;
1452    pp->ppid = (flags & OS::TGT_CLONE_THREAD) ? p->ppid() : p->pid();
1453    Process *cp = pp->create();
1454    delete pp;
1455
1456    Process *owner = ctc->getProcessPtr();
1457    ctc->setProcessPtr(cp);
1458    cp->assignThreadContext(ctc->contextId());
1459    owner->revokeThreadContext(ctc->contextId());
1460
1461    if (flags & OS::TGT_CLONE_PARENT_SETTID) {
1462        BufferArg ptidBuf(ptidPtr, sizeof(long));
1463        long *ptid = (long *)ptidBuf.bufferPtr();
1464        *ptid = cp->pid();
1465        ptidBuf.copyOut(tc->getMemProxy());
1466    }
1467
1468    cp->initState();
1469    p->clone(tc, ctc, cp, flags);
1470
1471    if (flags & OS::TGT_CLONE_THREAD) {
1472        delete cp->sigchld;
1473        cp->sigchld = p->sigchld;
1474    } else if (flags & OS::TGT_SIGCHLD) {
1475        *cp->sigchld = true;
1476    }
1477
1478    if (flags & OS::TGT_CLONE_CHILD_SETTID) {
1479        BufferArg ctidBuf(ctidPtr, sizeof(long));
1480        long *ctid = (long *)ctidBuf.bufferPtr();
1481        *ctid = cp->pid();
1482        ctidBuf.copyOut(ctc->getMemProxy());
1483    }
1484
1485    if (flags & OS::TGT_CLONE_CHILD_CLEARTID)
1486        cp->childClearTID = (uint64_t)ctidPtr;
1487
1488    ctc->clearArchRegs();
1489
1490    OS::archClone(flags, p, cp, tc, ctc, newStack, tlsPtr);
1491
1492    cp->setSyscallReturn(ctc, 0);
1493
1494#if THE_ISA == ALPHA_ISA
1495    ctc->setIntReg(TheISA::SyscallSuccessReg, 0);
1496#elif THE_ISA == SPARC_ISA
1497    tc->setIntReg(TheISA::SyscallPseudoReturnReg, 0);
1498    ctc->setIntReg(TheISA::SyscallPseudoReturnReg, 1);
1499#endif
1500
1501    TheISA::PCState cpc = tc->pcState();
1502    cpc.advance();
1503    ctc->pcState(cpc);
1504    ctc->activate();
1505
1506    return cp->pid();
1507}
1508
1509/// Target fstatfs() handler.
1510template <class OS>
1511SyscallReturn
1512fstatfsFunc(SyscallDesc *desc, int callnum, Process *p, ThreadContext *tc)
1513{
1514    int index = 0;
1515    int tgt_fd = p->getSyscallArg(tc, index);
1516    Addr bufPtr = p->getSyscallArg(tc, index);
1517
1518    auto ffdp = std::dynamic_pointer_cast<FileFDEntry>((*p->fds)[tgt_fd]);
1519    if (!ffdp)
1520        return -EBADF;
1521    int sim_fd = ffdp->getSimFD();
1522
1523    struct statfs hostBuf;
1524    int result = fstatfs(sim_fd, &hostBuf);
1525
1526    if (result < 0)
1527        return -errno;
1528
1529    copyOutStatfsBuf<OS>(tc->getMemProxy(), bufPtr, &hostBuf);
1530
1531    return 0;
1532}
1533
1534/// Target readv() handler.
1535template <class OS>
1536SyscallReturn
1537readvFunc(SyscallDesc *desc, int callnum, Process *p, ThreadContext *tc)
1538{
1539    int index = 0;
1540    int tgt_fd = p->getSyscallArg(tc, index);
1541
1542    auto ffdp = std::dynamic_pointer_cast<FileFDEntry>((*p->fds)[tgt_fd]);
1543    if (!ffdp)
1544        return -EBADF;
1545    int sim_fd = ffdp->getSimFD();
1546
1547    SETranslatingPortProxy &prox = tc->getMemProxy();
1548    uint64_t tiov_base = p->getSyscallArg(tc, index);
1549    size_t count = p->getSyscallArg(tc, index);
1550    typename OS::tgt_iovec tiov[count];
1551    struct iovec hiov[count];
1552    for (size_t i = 0; i < count; ++i) {
1553        prox.readBlob(tiov_base + (i * sizeof(typename OS::tgt_iovec)),
1554                      (uint8_t*)&tiov[i], sizeof(typename OS::tgt_iovec));
1555        hiov[i].iov_len = TheISA::gtoh(tiov[i].iov_len);
1556        hiov[i].iov_base = new char [hiov[i].iov_len];
1557    }
1558
1559    int result = readv(sim_fd, hiov, count);
1560    int local_errno = errno;
1561
1562    for (size_t i = 0; i < count; ++i) {
1563        if (result != -1) {
1564            prox.writeBlob(TheISA::htog(tiov[i].iov_base),
1565                           (uint8_t*)hiov[i].iov_base, hiov[i].iov_len);
1566        }
1567        delete [] (char *)hiov[i].iov_base;
1568    }
1569
1570    return (result == -1) ? -local_errno : result;
1571}
1572
1573/// Target writev() handler.
1574template <class OS>
1575SyscallReturn
1576writevFunc(SyscallDesc *desc, int callnum, Process *p, ThreadContext *tc)
1577{
1578    int index = 0;
1579    int tgt_fd = p->getSyscallArg(tc, index);
1580
1581    auto hbfdp = std::dynamic_pointer_cast<HBFDEntry>((*p->fds)[tgt_fd]);
1582    if (!hbfdp)
1583        return -EBADF;
1584    int sim_fd = hbfdp->getSimFD();
1585
1586    SETranslatingPortProxy &prox = tc->getMemProxy();
1587    uint64_t tiov_base = p->getSyscallArg(tc, index);
1588    size_t count = p->getSyscallArg(tc, index);
1589    struct iovec hiov[count];
1590    for (size_t i = 0; i < count; ++i) {
1591        typename OS::tgt_iovec tiov;
1592
1593        prox.readBlob(tiov_base + i*sizeof(typename OS::tgt_iovec),
1594                      (uint8_t*)&tiov, sizeof(typename OS::tgt_iovec));
1595        hiov[i].iov_len = TheISA::gtoh(tiov.iov_len);
1596        hiov[i].iov_base = new char [hiov[i].iov_len];
1597        prox.readBlob(TheISA::gtoh(tiov.iov_base), (uint8_t *)hiov[i].iov_base,
1598                      hiov[i].iov_len);
1599    }
1600
1601    int result = writev(sim_fd, hiov, count);
1602
1603    for (size_t i = 0; i < count; ++i)
1604        delete [] (char *)hiov[i].iov_base;
1605
1606    return (result == -1) ? -errno : result;
1607}
1608
1609/// Real mmap handler.
1610template <class OS>
1611SyscallReturn
1612mmapImpl(SyscallDesc *desc, int num, Process *p, ThreadContext *tc,
1613         bool is_mmap2)
1614{
1615    int index = 0;
1616    Addr start = p->getSyscallArg(tc, index);
1617    uint64_t length = p->getSyscallArg(tc, index);
1618    int prot = p->getSyscallArg(tc, index);
1619    int tgt_flags = p->getSyscallArg(tc, index);
1620    int tgt_fd = p->getSyscallArg(tc, index);
1621    int offset = p->getSyscallArg(tc, index);
1622
1623    if (is_mmap2)
1624        offset *= TheISA::PageBytes;
1625
1626    if (start & (TheISA::PageBytes - 1) ||
1627        offset & (TheISA::PageBytes - 1) ||
1628        (tgt_flags & OS::TGT_MAP_PRIVATE &&
1629         tgt_flags & OS::TGT_MAP_SHARED) ||
1630        (!(tgt_flags & OS::TGT_MAP_PRIVATE) &&
1631         !(tgt_flags & OS::TGT_MAP_SHARED)) ||
1632        !length) {
1633        return -EINVAL;
1634    }
1635
1636    if ((prot & PROT_WRITE) && (tgt_flags & OS::TGT_MAP_SHARED)) {
1637        // With shared mmaps, there are two cases to consider:
1638        // 1) anonymous: writes should modify the mapping and this should be
1639        // visible to observers who share the mapping. Currently, it's
1640        // difficult to update the shared mapping because there's no
1641        // structure which maintains information about the which virtual
1642        // memory areas are shared. If that structure existed, it would be
1643        // possible to make the translations point to the same frames.
1644        // 2) file-backed: writes should modify the mapping and the file
1645        // which is backed by the mapping. The shared mapping problem is the
1646        // same as what was mentioned about the anonymous mappings. For
1647        // file-backed mappings, the writes to the file are difficult
1648        // because it requires syncing what the mapping holds with the file
1649        // that resides on the host system. So, any write on a real system
1650        // would cause the change to be propagated to the file mapping at
1651        // some point in the future (the inode is tracked along with the
1652        // mapping). This isn't guaranteed to always happen, but it usually
1653        // works well enough. The guarantee is provided by the msync system
1654        // call. We could force the change through with shared mappings with
1655        // a call to msync, but that again would require more information
1656        // than we currently maintain.
1657        warn("mmap: writing to shared mmap region is currently "
1658             "unsupported. The write succeeds on the target, but it "
1659             "will not be propagated to the host or shared mappings");
1660    }
1661
1662    length = roundUp(length, TheISA::PageBytes);
1663
1664    int sim_fd = -1;
1665    uint8_t *pmap = nullptr;
1666    if (!(tgt_flags & OS::TGT_MAP_ANONYMOUS)) {
1667        std::shared_ptr<FDEntry> fdep = (*p->fds)[tgt_fd];
1668
1669        auto dfdp = std::dynamic_pointer_cast<DeviceFDEntry>(fdep);
1670        if (dfdp) {
1671            EmulatedDriver *emul_driver = dfdp->getDriver();
1672            return emul_driver->mmap(p, tc, start, length, prot,
1673                                     tgt_flags, tgt_fd, offset);
1674        }
1675
1676        auto ffdp = std::dynamic_pointer_cast<FileFDEntry>(fdep);
1677        if (!ffdp)
1678            return -EBADF;
1679        sim_fd = ffdp->getSimFD();
1680
1681        pmap = (decltype(pmap))mmap(nullptr, length, PROT_READ, MAP_PRIVATE,
1682                                    sim_fd, offset);
1683
1684        if (pmap == (decltype(pmap))-1) {
1685            warn("mmap: failed to map file into host address space");
1686            return -errno;
1687        }
1688    }
1689
1690    // Extend global mmap region if necessary. Note that we ignore the
1691    // start address unless MAP_FIXED is specified.
1692    if (!(tgt_flags & OS::TGT_MAP_FIXED)) {
1693        std::shared_ptr<MemState> mem_state = p->memState;
1694        Addr mmap_end = mem_state->getMmapEnd();
1695
1696        start = p->mmapGrowsDown() ? mmap_end - length : mmap_end;
1697        mmap_end = p->mmapGrowsDown() ? start : mmap_end + length;
1698
1699        mem_state->setMmapEnd(mmap_end);
1700    }
1701
1702    DPRINTF_SYSCALL(Verbose, " mmap range is 0x%x - 0x%x\n",
1703                    start, start + length - 1);
1704
1705    // We only allow mappings to overwrite existing mappings if
1706    // TGT_MAP_FIXED is set. Otherwise it shouldn't be a problem
1707    // because we ignore the start hint if TGT_MAP_FIXED is not set.
1708    int clobber = tgt_flags & OS::TGT_MAP_FIXED;
1709    if (clobber) {
1710        for (auto tc : p->system->threadContexts) {
1711            // If we might be overwriting old mappings, we need to
1712            // invalidate potentially stale mappings out of the TLBs.
1713            tc->getDTBPtr()->flushAll();
1714            tc->getITBPtr()->flushAll();
1715        }
1716    }
1717
1718    // Allocate physical memory and map it in. If the page table is already
1719    // mapped and clobber is not set, the simulator will issue throw a
1720    // fatal and bail out of the simulation.
1721    p->allocateMem(start, length, clobber);
1722
1723    // Transfer content into target address space.
1724    SETranslatingPortProxy &tp = tc->getMemProxy();
1725    if (tgt_flags & OS::TGT_MAP_ANONYMOUS) {
1726        // In general, we should zero the mapped area for anonymous mappings,
1727        // with something like:
1728        //     tp.memsetBlob(start, 0, length);
1729        // However, given that we don't support sparse mappings, and
1730        // some applications can map a couple of gigabytes of space
1731        // (intending sparse usage), that can get painfully expensive.
1732        // Fortunately, since we don't properly implement munmap either,
1733        // there's no danger of remapping used memory, so for now all
1734        // newly mapped memory should already be zeroed so we can skip it.
1735    } else {
1736        // It is possible to mmap an area larger than a file, however
1737        // accessing unmapped portions the system triggers a "Bus error"
1738        // on the host. We must know when to stop copying the file from
1739        // the host into the target address space.
1740        struct stat file_stat;
1741        if (fstat(sim_fd, &file_stat) > 0)
1742            fatal("mmap: cannot stat file");
1743
1744        // Copy the portion of the file that is resident. This requires
1745        // checking both the mmap size and the filesize that we are
1746        // trying to mmap into this space; the mmap size also depends
1747        // on the specified offset into the file.
1748        uint64_t size = std::min((uint64_t)file_stat.st_size - offset,
1749                                 length);
1750        tp.writeBlob(start, pmap, size);
1751
1752        // Cleanup the mmap region before exiting this function.
1753        munmap(pmap, length);
1754
1755        // Maintain the symbol table for dynamic executables.
1756        // The loader will call mmap to map the images into its address
1757        // space and we intercept that here. We can verify that we are
1758        // executing inside the loader by checking the program counter value.
1759        // XXX: with multiprogrammed workloads or multi-node configurations,
1760        // this will not work since there is a single global symbol table.
1761        ObjectFile *interpreter = p->getInterpreter();
1762        if (interpreter) {
1763            Addr text_start = interpreter->textBase();
1764            Addr text_end = text_start + interpreter->textSize();
1765
1766            Addr pc = tc->pcState().pc();
1767
1768            if (pc >= text_start && pc < text_end) {
1769                std::shared_ptr<FDEntry> fdep = (*p->fds)[tgt_fd];
1770                auto ffdp = std::dynamic_pointer_cast<FileFDEntry>(fdep);
1771                ObjectFile *lib = createObjectFile(ffdp->getFileName());
1772
1773                if (lib) {
1774                    lib->loadAllSymbols(debugSymbolTable,
1775                                        lib->textBase(), start);
1776                }
1777            }
1778        }
1779
1780        // Note that we do not zero out the remainder of the mapping. This
1781        // is done by a real system, but it probably will not affect
1782        // execution (hopefully).
1783    }
1784
1785    return start;
1786}
1787
1788template <class OS>
1789SyscallReturn
1790pwrite64Func(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
1791{
1792    int index = 0;
1793    int tgt_fd = p->getSyscallArg(tc, index);
1794    Addr bufPtr = p->getSyscallArg(tc, index);
1795    int nbytes = p->getSyscallArg(tc, index);
1796    int offset = p->getSyscallArg(tc, index);
1797
1798    auto ffdp = std::dynamic_pointer_cast<FileFDEntry>((*p->fds)[tgt_fd]);
1799    if (!ffdp)
1800        return -EBADF;
1801    int sim_fd = ffdp->getSimFD();
1802
1803    BufferArg bufArg(bufPtr, nbytes);
1804    bufArg.copyIn(tc->getMemProxy());
1805
1806    int bytes_written = pwrite(sim_fd, bufArg.bufferPtr(), nbytes, offset);
1807
1808    return (bytes_written == -1) ? -errno : bytes_written;
1809}
1810
1811/// Target mmap() handler.
1812template <class OS>
1813SyscallReturn
1814mmapFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
1815{
1816    return mmapImpl<OS>(desc, num, p, tc, false);
1817}
1818
1819/// Target mmap2() handler.
1820template <class OS>
1821SyscallReturn
1822mmap2Func(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
1823{
1824    return mmapImpl<OS>(desc, num, p, tc, true);
1825}
1826
1827/// Target getrlimit() handler.
1828template <class OS>
1829SyscallReturn
1830getrlimitFunc(SyscallDesc *desc, int callnum, Process *process,
1831              ThreadContext *tc)
1832{
1833    int index = 0;
1834    unsigned resource = process->getSyscallArg(tc, index);
1835    TypedBufferArg<typename OS::rlimit> rlp(process->getSyscallArg(tc, index));
1836
1837    switch (resource) {
1838      case OS::TGT_RLIMIT_STACK:
1839        // max stack size in bytes: make up a number (8MB for now)
1840        rlp->rlim_cur = rlp->rlim_max = 8 * 1024 * 1024;
1841        rlp->rlim_cur = TheISA::htog(rlp->rlim_cur);
1842        rlp->rlim_max = TheISA::htog(rlp->rlim_max);
1843        break;
1844
1845      case OS::TGT_RLIMIT_DATA:
1846        // max data segment size in bytes: make up a number
1847        rlp->rlim_cur = rlp->rlim_max = 256 * 1024 * 1024;
1848        rlp->rlim_cur = TheISA::htog(rlp->rlim_cur);
1849        rlp->rlim_max = TheISA::htog(rlp->rlim_max);
1850        break;
1851
1852      default:
1853        warn("getrlimit: unimplemented resource %d", resource);
1854        return -EINVAL;
1855        break;
1856    }
1857
1858    rlp.copyOut(tc->getMemProxy());
1859    return 0;
1860}
1861
1862template <class OS>
1863SyscallReturn
1864prlimitFunc(SyscallDesc *desc, int callnum, Process *process,
1865            ThreadContext *tc)
1866{
1867    int index = 0;
1868    if (process->getSyscallArg(tc, index) != 0)
1869    {
1870        warn("prlimit: ignoring rlimits for nonzero pid");
1871        return -EPERM;
1872    }
1873    int resource = process->getSyscallArg(tc, index);
1874    Addr n = process->getSyscallArg(tc, index);
1875    if (n != 0)
1876        warn("prlimit: ignoring new rlimit");
1877    Addr o = process->getSyscallArg(tc, index);
1878    if (o != 0)
1879    {
1880        TypedBufferArg<typename OS::rlimit> rlp(o);
1881        switch (resource) {
1882          case OS::TGT_RLIMIT_STACK:
1883            // max stack size in bytes: make up a number (8MB for now)
1884            rlp->rlim_cur = rlp->rlim_max = 8 * 1024 * 1024;
1885            rlp->rlim_cur = TheISA::htog(rlp->rlim_cur);
1886            rlp->rlim_max = TheISA::htog(rlp->rlim_max);
1887            break;
1888          case OS::TGT_RLIMIT_DATA:
1889            // max data segment size in bytes: make up a number
1890            rlp->rlim_cur = rlp->rlim_max = 256*1024*1024;
1891            rlp->rlim_cur = TheISA::htog(rlp->rlim_cur);
1892            rlp->rlim_max = TheISA::htog(rlp->rlim_max);
1893            break;
1894          default:
1895            warn("prlimit: unimplemented resource %d", resource);
1896            return -EINVAL;
1897            break;
1898        }
1899        rlp.copyOut(tc->getMemProxy());
1900    }
1901    return 0;
1902}
1903
1904/// Target clock_gettime() function.
1905template <class OS>
1906SyscallReturn
1907clock_gettimeFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
1908{
1909    int index = 1;
1910    //int clk_id = p->getSyscallArg(tc, index);
1911    TypedBufferArg<typename OS::timespec> tp(p->getSyscallArg(tc, index));
1912
1913    getElapsedTimeNano(tp->tv_sec, tp->tv_nsec);
1914    tp->tv_sec += seconds_since_epoch;
1915    tp->tv_sec = TheISA::htog(tp->tv_sec);
1916    tp->tv_nsec = TheISA::htog(tp->tv_nsec);
1917
1918    tp.copyOut(tc->getMemProxy());
1919
1920    return 0;
1921}
1922
1923/// Target clock_getres() function.
1924template <class OS>
1925SyscallReturn
1926clock_getresFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
1927{
1928    int index = 1;
1929    TypedBufferArg<typename OS::timespec> tp(p->getSyscallArg(tc, index));
1930
1931    // Set resolution at ns, which is what clock_gettime() returns
1932    tp->tv_sec = 0;
1933    tp->tv_nsec = 1;
1934
1935    tp.copyOut(tc->getMemProxy());
1936
1937    return 0;
1938}
1939
1940/// Target gettimeofday() handler.
1941template <class OS>
1942SyscallReturn
1943gettimeofdayFunc(SyscallDesc *desc, int callnum, Process *process,
1944                 ThreadContext *tc)
1945{
1946    int index = 0;
1947    TypedBufferArg<typename OS::timeval> tp(process->getSyscallArg(tc, index));
1948
1949    getElapsedTimeMicro(tp->tv_sec, tp->tv_usec);
1950    tp->tv_sec += seconds_since_epoch;
1951    tp->tv_sec = TheISA::htog(tp->tv_sec);
1952    tp->tv_usec = TheISA::htog(tp->tv_usec);
1953
1954    tp.copyOut(tc->getMemProxy());
1955
1956    return 0;
1957}
1958
1959
1960/// Target utimes() handler.
1961template <class OS>
1962SyscallReturn
1963utimesFunc(SyscallDesc *desc, int callnum, Process *process,
1964           ThreadContext *tc)
1965{
1966    std::string path;
1967
1968    int index = 0;
1969    if (!tc->getMemProxy().tryReadString(path,
1970                process->getSyscallArg(tc, index))) {
1971        return -EFAULT;
1972    }
1973
1974    TypedBufferArg<typename OS::timeval [2]>
1975        tp(process->getSyscallArg(tc, index));
1976    tp.copyIn(tc->getMemProxy());
1977
1978    struct timeval hostTimeval[2];
1979    for (int i = 0; i < 2; ++i) {
1980        hostTimeval[i].tv_sec = TheISA::gtoh((*tp)[i].tv_sec);
1981        hostTimeval[i].tv_usec = TheISA::gtoh((*tp)[i].tv_usec);
1982    }
1983
1984    // Adjust path for current working directory
1985    path = process->fullPath(path);
1986
1987    int result = utimes(path.c_str(), hostTimeval);
1988
1989    if (result < 0)
1990        return -errno;
1991
1992    return 0;
1993}
1994
1995template <class OS>
1996SyscallReturn
1997execveFunc(SyscallDesc *desc, int callnum, Process *p, ThreadContext *tc)
1998{
1999    desc->setFlags(0);
2000
2001    int index = 0;
2002    std::string path;
2003    SETranslatingPortProxy & mem_proxy = tc->getMemProxy();
2004    if (!mem_proxy.tryReadString(path, p->getSyscallArg(tc, index)))
2005        return -EFAULT;
2006
2007    if (access(path.c_str(), F_OK) == -1)
2008        return -EACCES;
2009
2010    auto read_in = [](std::vector<std::string> & vect,
2011                      SETranslatingPortProxy & mem_proxy,
2012                      Addr mem_loc)
2013    {
2014        for (int inc = 0; ; inc++) {
2015            BufferArg b((mem_loc + sizeof(Addr) * inc), sizeof(Addr));
2016            b.copyIn(mem_proxy);
2017
2018            if (!*(Addr*)b.bufferPtr())
2019                break;
2020
2021            vect.push_back(std::string());
2022            mem_proxy.tryReadString(vect[inc], *(Addr*)b.bufferPtr());
2023        }
2024    };
2025
2026    /**
2027     * Note that ProcessParams is generated by swig and there are no other
2028     * examples of how to create anything but this default constructor. The
2029     * fields are manually initialized instead of passing parameters to the
2030     * constructor.
2031     */
2032    ProcessParams *pp = new ProcessParams();
2033    pp->executable = path;
2034    Addr argv_mem_loc = p->getSyscallArg(tc, index);
2035    read_in(pp->cmd, mem_proxy, argv_mem_loc);
2036    Addr envp_mem_loc = p->getSyscallArg(tc, index);
2037    read_in(pp->env, mem_proxy, envp_mem_loc);
2038    pp->uid = p->uid();
2039    pp->egid = p->egid();
2040    pp->euid = p->euid();
2041    pp->gid = p->gid();
2042    pp->ppid = p->ppid();
2043    pp->pid = p->pid();
2044    pp->input.assign("cin");
2045    pp->output.assign("cout");
2046    pp->errout.assign("cerr");
2047    pp->cwd.assign(p->getcwd());
2048    pp->system = p->system;
2049    /**
2050     * Prevent process object creation with identical PIDs (which will trip
2051     * a fatal check in Process constructor). The execve call is supposed to
2052     * take over the currently executing process' identity but replace
2053     * whatever it is doing with a new process image. Instead of hijacking
2054     * the process object in the simulator, we create a new process object
2055     * and bind to the previous process' thread below (hijacking the thread).
2056     */
2057    p->system->PIDs.erase(p->pid());
2058    Process *new_p = pp->create();
2059    delete pp;
2060
2061    /**
2062     * Work through the file descriptor array and close any files marked
2063     * close-on-exec.
2064     */
2065    new_p->fds = p->fds;
2066    for (int i = 0; i < new_p->fds->getSize(); i++) {
2067        std::shared_ptr<FDEntry> fdep = (*new_p->fds)[i];
2068        if (fdep && fdep->getCOE())
2069            new_p->fds->closeFDEntry(i);
2070    }
2071
2072    *new_p->sigchld = true;
2073
2074    delete p;
2075    tc->clearArchRegs();
2076    tc->setProcessPtr(new_p);
2077    new_p->assignThreadContext(tc->contextId());
2078    new_p->initState();
2079    tc->activate();
2080    TheISA::PCState pcState = tc->pcState();
2081    tc->setNPC(pcState.instAddr());
2082
2083    desc->setFlags(SyscallDesc::SuppressReturnValue);
2084    return 0;
2085}
2086
2087/// Target getrusage() function.
2088template <class OS>
2089SyscallReturn
2090getrusageFunc(SyscallDesc *desc, int callnum, Process *process,
2091              ThreadContext *tc)
2092{
2093    int index = 0;
2094    int who = process->getSyscallArg(tc, index); // THREAD, SELF, or CHILDREN
2095    TypedBufferArg<typename OS::rusage> rup(process->getSyscallArg(tc, index));
2096
2097    rup->ru_utime.tv_sec = 0;
2098    rup->ru_utime.tv_usec = 0;
2099    rup->ru_stime.tv_sec = 0;
2100    rup->ru_stime.tv_usec = 0;
2101    rup->ru_maxrss = 0;
2102    rup->ru_ixrss = 0;
2103    rup->ru_idrss = 0;
2104    rup->ru_isrss = 0;
2105    rup->ru_minflt = 0;
2106    rup->ru_majflt = 0;
2107    rup->ru_nswap = 0;
2108    rup->ru_inblock = 0;
2109    rup->ru_oublock = 0;
2110    rup->ru_msgsnd = 0;
2111    rup->ru_msgrcv = 0;
2112    rup->ru_nsignals = 0;
2113    rup->ru_nvcsw = 0;
2114    rup->ru_nivcsw = 0;
2115
2116    switch (who) {
2117      case OS::TGT_RUSAGE_SELF:
2118        getElapsedTimeMicro(rup->ru_utime.tv_sec, rup->ru_utime.tv_usec);
2119        rup->ru_utime.tv_sec = TheISA::htog(rup->ru_utime.tv_sec);
2120        rup->ru_utime.tv_usec = TheISA::htog(rup->ru_utime.tv_usec);
2121        break;
2122
2123      case OS::TGT_RUSAGE_CHILDREN:
2124        // do nothing.  We have no child processes, so they take no time.
2125        break;
2126
2127      default:
2128        // don't really handle THREAD or CHILDREN, but just warn and
2129        // plow ahead
2130        warn("getrusage() only supports RUSAGE_SELF.  Parameter %d ignored.",
2131             who);
2132    }
2133
2134    rup.copyOut(tc->getMemProxy());
2135
2136    return 0;
2137}
2138
2139/// Target times() function.
2140template <class OS>
2141SyscallReturn
2142timesFunc(SyscallDesc *desc, int callnum, Process *process,
2143          ThreadContext *tc)
2144{
2145    int index = 0;
2146    TypedBufferArg<typename OS::tms> bufp(process->getSyscallArg(tc, index));
2147
2148    // Fill in the time structure (in clocks)
2149    int64_t clocks = curTick() * OS::M5_SC_CLK_TCK / SimClock::Int::s;
2150    bufp->tms_utime = clocks;
2151    bufp->tms_stime = 0;
2152    bufp->tms_cutime = 0;
2153    bufp->tms_cstime = 0;
2154
2155    // Convert to host endianness
2156    bufp->tms_utime = TheISA::htog(bufp->tms_utime);
2157
2158    // Write back
2159    bufp.copyOut(tc->getMemProxy());
2160
2161    // Return clock ticks since system boot
2162    return clocks;
2163}
2164
2165/// Target time() function.
2166template <class OS>
2167SyscallReturn
2168timeFunc(SyscallDesc *desc, int callnum, Process *process, ThreadContext *tc)
2169{
2170    typename OS::time_t sec, usec;
2171    getElapsedTimeMicro(sec, usec);
2172    sec += seconds_since_epoch;
2173
2174    int index = 0;
2175    Addr taddr = (Addr)process->getSyscallArg(tc, index);
2176    if (taddr != 0) {
2177        typename OS::time_t t = sec;
2178        t = TheISA::htog(t);
2179        SETranslatingPortProxy &p = tc->getMemProxy();
2180        p.writeBlob(taddr, (uint8_t*)&t, (int)sizeof(typename OS::time_t));
2181    }
2182    return sec;
2183}
2184
2185template <class OS>
2186SyscallReturn
2187tgkillFunc(SyscallDesc *desc, int num, Process *process, ThreadContext *tc)
2188{
2189    int index = 0;
2190    int tgid = process->getSyscallArg(tc, index);
2191    int tid = process->getSyscallArg(tc, index);
2192    int sig = process->getSyscallArg(tc, index);
2193
2194    /**
2195     * This system call is intended to allow killing a specific thread
2196     * within an arbitrary thread group if sanctioned with permission checks.
2197     * It's usually true that threads share the termination signal as pointed
2198     * out by the pthread_kill man page and this seems to be the intended
2199     * usage. Due to this being an emulated environment, assume the following:
2200     * Threads are allowed to call tgkill because the EUID for all threads
2201     * should be the same. There is no signal handling mechanism for kernel
2202     * registration of signal handlers since signals are poorly supported in
2203     * emulation mode. Since signal handlers cannot be registered, all
2204     * threads within in a thread group must share the termination signal.
2205     * We never exhaust PIDs so there's no chance of finding the wrong one
2206     * due to PID rollover.
2207     */
2208
2209    System *sys = tc->getSystemPtr();
2210    Process *tgt_proc = nullptr;
2211    for (int i = 0; i < sys->numContexts(); i++) {
2212        Process *temp = sys->threadContexts[i]->getProcessPtr();
2213        if (temp->pid() == tid) {
2214            tgt_proc = temp;
2215            break;
2216        }
2217    }
2218
2219    if (sig != 0 || sig != OS::TGT_SIGABRT)
2220        return -EINVAL;
2221
2222    if (tgt_proc == nullptr)
2223        return -ESRCH;
2224
2225    if (tgid != -1 && tgt_proc->tgid() != tgid)
2226        return -ESRCH;
2227
2228    if (sig == OS::TGT_SIGABRT)
2229        exitGroupFunc(desc, 252, process, tc);
2230
2231    return 0;
2232}
2233
2234template <class OS>
2235SyscallReturn
2236socketFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
2237{
2238    int index = 0;
2239    int domain = p->getSyscallArg(tc, index);
2240    int type = p->getSyscallArg(tc, index);
2241    int prot = p->getSyscallArg(tc, index);
2242
2243    int sim_fd = socket(domain, type, prot);
2244    if (sim_fd == -1)
2245        return -errno;
2246
2247    auto sfdp = std::make_shared<SocketFDEntry>(sim_fd, domain, type, prot);
2248    int tgt_fd = p->fds->allocFD(sfdp);
2249
2250    return tgt_fd;
2251}
2252
2253template <class OS>
2254SyscallReturn
2255socketpairFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
2256{
2257    int index = 0;
2258    int domain = p->getSyscallArg(tc, index);
2259    int type = p->getSyscallArg(tc, index);
2260    int prot = p->getSyscallArg(tc, index);
2261    Addr svPtr = p->getSyscallArg(tc, index);
2262
2263    BufferArg svBuf((Addr)svPtr, 2 * sizeof(int));
2264    int status = socketpair(domain, type, prot, (int *)svBuf.bufferPtr());
2265    if (status == -1)
2266        return -errno;
2267
2268    int *fds = (int *)svBuf.bufferPtr();
2269
2270    auto sfdp1 = std::make_shared<SocketFDEntry>(fds[0], domain, type, prot);
2271    fds[0] = p->fds->allocFD(sfdp1);
2272    auto sfdp2 = std::make_shared<SocketFDEntry>(fds[1], domain, type, prot);
2273    fds[1] = p->fds->allocFD(sfdp2);
2274    svBuf.copyOut(tc->getMemProxy());
2275
2276    return status;
2277}
2278
2279template <class OS>
2280SyscallReturn
2281selectFunc(SyscallDesc *desc, int callnum, Process *p, ThreadContext *tc)
2282{
2283    int retval;
2284
2285    int index = 0;
2286    int nfds_t = p->getSyscallArg(tc, index);
2287    Addr fds_read_ptr = p->getSyscallArg(tc, index);
2288    Addr fds_writ_ptr = p->getSyscallArg(tc, index);
2289    Addr fds_excp_ptr = p->getSyscallArg(tc, index);
2290    Addr time_val_ptr = p->getSyscallArg(tc, index);
2291
2292    TypedBufferArg<typename OS::fd_set> rd_t(fds_read_ptr);
2293    TypedBufferArg<typename OS::fd_set> wr_t(fds_writ_ptr);
2294    TypedBufferArg<typename OS::fd_set> ex_t(fds_excp_ptr);
2295    TypedBufferArg<typename OS::timeval> tp(time_val_ptr);
2296
2297    /**
2298     * Host fields. Notice that these use the definitions from the system
2299     * headers instead of the gem5 headers and libraries. If the host and
2300     * target have different header file definitions, this will not work.
2301     */
2302    fd_set rd_h;
2303    FD_ZERO(&rd_h);
2304    fd_set wr_h;
2305    FD_ZERO(&wr_h);
2306    fd_set ex_h;
2307    FD_ZERO(&ex_h);
2308
2309    /**
2310     * Copy in the fd_set from the target.
2311     */
2312    if (fds_read_ptr)
2313        rd_t.copyIn(tc->getMemProxy());
2314    if (fds_writ_ptr)
2315        wr_t.copyIn(tc->getMemProxy());
2316    if (fds_excp_ptr)
2317        ex_t.copyIn(tc->getMemProxy());
2318
2319    /**
2320     * We need to translate the target file descriptor set into a host file
2321     * descriptor set. This involves both our internal process fd array
2322     * and the fd_set defined in Linux header files. The nfds field also
2323     * needs to be updated as it will be only target specific after
2324     * retrieving it from the target; the nfds value is expected to be the
2325     * highest file descriptor that needs to be checked, so we need to extend
2326     * it out for nfds_h when we do the update.
2327     */
2328    int nfds_h = 0;
2329    std::map<int, int> trans_map;
2330    auto try_add_host_set = [&](fd_set *tgt_set_entry,
2331                                fd_set *hst_set_entry,
2332                                int iter) -> bool
2333    {
2334        /**
2335         * By this point, we know that we are looking at a valid file
2336         * descriptor set on the target. We need to check if the target file
2337         * descriptor value passed in as iter is part of the set.
2338         */
2339        if (FD_ISSET(iter, tgt_set_entry)) {
2340            /**
2341             * We know that the target file descriptor belongs to the set,
2342             * but we do not yet know if the file descriptor is valid or
2343             * that we have a host mapping. Check that now.
2344             */
2345            auto hbfdp = std::dynamic_pointer_cast<HBFDEntry>((*p->fds)[iter]);
2346            if (!hbfdp)
2347                return true;
2348            auto sim_fd = hbfdp->getSimFD();
2349
2350            /**
2351             * Add the sim_fd to tgt_fd translation into trans_map for use
2352             * later when we need to zero the target fd_set structures and
2353             * then update them with hits returned from the host select call.
2354             */
2355            trans_map[sim_fd] = iter;
2356
2357            /**
2358             * We know that the host file descriptor exists so now we check
2359             * if we need to update the max count for nfds_h before passing
2360             * the duplicated structure into the host.
2361             */
2362            nfds_h = std::max(nfds_h - 1, sim_fd + 1);
2363
2364            /**
2365             * Add the host file descriptor to the set that we are going to
2366             * pass into the host.
2367             */
2368            FD_SET(sim_fd, hst_set_entry);
2369        }
2370        return false;
2371    };
2372
2373    for (int i = 0; i < nfds_t; i++) {
2374        if (fds_read_ptr) {
2375            bool ebadf = try_add_host_set((fd_set*)&*rd_t, &rd_h, i);
2376            if (ebadf) return -EBADF;
2377        }
2378        if (fds_writ_ptr) {
2379            bool ebadf = try_add_host_set((fd_set*)&*wr_t, &wr_h, i);
2380            if (ebadf) return -EBADF;
2381        }
2382        if (fds_excp_ptr) {
2383            bool ebadf = try_add_host_set((fd_set*)&*ex_t, &ex_h, i);
2384            if (ebadf) return -EBADF;
2385        }
2386    }
2387
2388    if (time_val_ptr) {
2389        /**
2390         * It might be possible to decrement the timeval based on some
2391         * derivation of wall clock determined from elapsed simulator ticks
2392         * but that seems like overkill. Rather, we just set the timeval with
2393         * zero timeout. (There is no reason to block during the simulation
2394         * as it only decreases simulator performance.)
2395         */
2396        tp->tv_sec = 0;
2397        tp->tv_usec = 0;
2398
2399        retval = select(nfds_h,
2400                        fds_read_ptr ? &rd_h : nullptr,
2401                        fds_writ_ptr ? &wr_h : nullptr,
2402                        fds_excp_ptr ? &ex_h : nullptr,
2403                        (timeval*)&*tp);
2404    } else {
2405        /**
2406         * If the timeval pointer is null, setup a new timeval structure to
2407         * pass into the host select call. Unfortunately, we will need to
2408         * manually check the return value and throw a retry fault if the
2409         * return value is zero. Allowing the system call to block will
2410         * likely deadlock the event queue.
2411         */
2412        struct timeval tv = { 0, 0 };
2413
2414        retval = select(nfds_h,
2415                        fds_read_ptr ? &rd_h : nullptr,
2416                        fds_writ_ptr ? &wr_h : nullptr,
2417                        fds_excp_ptr ? &ex_h : nullptr,
2418                        &tv);
2419
2420        if (retval == 0) {
2421            /**
2422             * If blocking indefinitely, check the signal list to see if a
2423             * signal would break the poll out of the retry cycle and try to
2424             * return the signal interrupt instead.
2425             */
2426            for (auto sig : tc->getSystemPtr()->signalList)
2427                if (sig.receiver == p)
2428                    return -EINTR;
2429            return SyscallReturn::retry();
2430        }
2431    }
2432
2433    if (retval == -1)
2434        return -errno;
2435
2436    FD_ZERO((fd_set*)&*rd_t);
2437    FD_ZERO((fd_set*)&*wr_t);
2438    FD_ZERO((fd_set*)&*ex_t);
2439
2440    /**
2441     * We need to translate the host file descriptor set into a target file
2442     * descriptor set. This involves both our internal process fd array
2443     * and the fd_set defined in header files.
2444     */
2445    for (int i = 0; i < nfds_h; i++) {
2446        if (fds_read_ptr) {
2447            if (FD_ISSET(i, &rd_h))
2448                FD_SET(trans_map[i], (fd_set*)&*rd_t);
2449        }
2450
2451        if (fds_writ_ptr) {
2452            if (FD_ISSET(i, &wr_h))
2453                FD_SET(trans_map[i], (fd_set*)&*wr_t);
2454        }
2455
2456        if (fds_excp_ptr) {
2457            if (FD_ISSET(i, &ex_h))
2458                FD_SET(trans_map[i], (fd_set*)&*ex_t);
2459        }
2460    }
2461
2462    if (fds_read_ptr)
2463        rd_t.copyOut(tc->getMemProxy());
2464    if (fds_writ_ptr)
2465        wr_t.copyOut(tc->getMemProxy());
2466    if (fds_excp_ptr)
2467        ex_t.copyOut(tc->getMemProxy());
2468    if (time_val_ptr)
2469        tp.copyOut(tc->getMemProxy());
2470
2471    return retval;
2472}
2473
2474template <class OS>
2475SyscallReturn
2476readFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
2477{
2478    int index = 0;
2479    int tgt_fd = p->getSyscallArg(tc, index);
2480    Addr buf_ptr = p->getSyscallArg(tc, index);
2481    int nbytes = p->getSyscallArg(tc, index);
2482
2483    auto hbfdp = std::dynamic_pointer_cast<HBFDEntry>((*p->fds)[tgt_fd]);
2484    if (!hbfdp)
2485        return -EBADF;
2486    int sim_fd = hbfdp->getSimFD();
2487
2488    struct pollfd pfd;
2489    pfd.fd = sim_fd;
2490    pfd.events = POLLIN | POLLPRI;
2491    if ((poll(&pfd, 1, 0) == 0)
2492        && !(hbfdp->getFlags() & OS::TGT_O_NONBLOCK))
2493        return SyscallReturn::retry();
2494
2495    BufferArg buf_arg(buf_ptr, nbytes);
2496    int bytes_read = read(sim_fd, buf_arg.bufferPtr(), nbytes);
2497
2498    if (bytes_read > 0)
2499        buf_arg.copyOut(tc->getMemProxy());
2500
2501    return (bytes_read == -1) ? -errno : bytes_read;
2502}
2503
2504template <class OS>
2505SyscallReturn
2506writeFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
2507{
2508    int index = 0;
2509    int tgt_fd = p->getSyscallArg(tc, index);
2510    Addr buf_ptr = p->getSyscallArg(tc, index);
2511    int nbytes = p->getSyscallArg(tc, index);
2512
2513    auto hbfdp = std::dynamic_pointer_cast<HBFDEntry>((*p->fds)[tgt_fd]);
2514    if (!hbfdp)
2515        return -EBADF;
2516    int sim_fd = hbfdp->getSimFD();
2517
2518    BufferArg buf_arg(buf_ptr, nbytes);
2519    buf_arg.copyIn(tc->getMemProxy());
2520
2521    struct pollfd pfd;
2522    pfd.fd = sim_fd;
2523    pfd.events = POLLOUT;
2524
2525    /**
2526     * We don't want to poll on /dev/random. The kernel will not enable the
2527     * file descriptor for writing unless the entropy in the system falls
2528     * below write_wakeup_threshold. This is not guaranteed to happen
2529     * depending on host settings.
2530     */
2531    auto ffdp = std::dynamic_pointer_cast<FileFDEntry>(hbfdp);
2532    if (ffdp && (ffdp->getFileName() != "/dev/random")) {
2533        if (!poll(&pfd, 1, 0) && !(ffdp->getFlags() & OS::TGT_O_NONBLOCK))
2534            return SyscallReturn::retry();
2535    }
2536
2537    int bytes_written = write(sim_fd, buf_arg.bufferPtr(), nbytes);
2538
2539    if (bytes_written != -1)
2540        fsync(sim_fd);
2541
2542    return (bytes_written == -1) ? -errno : bytes_written;
2543}
2544
2545template <class OS>
2546SyscallReturn
2547wait4Func(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
2548{
2549    int index = 0;
2550    pid_t pid = p->getSyscallArg(tc, index);
2551    Addr statPtr = p->getSyscallArg(tc, index);
2552    int options = p->getSyscallArg(tc, index);
2553    Addr rusagePtr = p->getSyscallArg(tc, index);
2554
2555    if (rusagePtr)
2556        DPRINTFR(SyscallVerbose,
2557                 "%d: %s: syscall wait4: rusage pointer provided however "
2558                 "functionality not supported. Ignoring rusage pointer.\n",
2559                 curTick(), tc->getCpuPtr()->name());
2560
2561    /**
2562     * Currently, wait4 is only implemented so that it will wait for children
2563     * exit conditions which are denoted by a SIGCHLD signals posted into the
2564     * system signal list. We return no additional information via any of the
2565     * parameters supplied to wait4. If nothing is found in the system signal
2566     * list, we will wait indefinitely for SIGCHLD to post by retrying the
2567     * call.
2568     */
2569    System *sysh = tc->getSystemPtr();
2570    std::list<BasicSignal>::iterator iter;
2571    for (iter=sysh->signalList.begin(); iter!=sysh->signalList.end(); iter++) {
2572        if (iter->receiver == p) {
2573            if (pid < -1) {
2574                if ((iter->sender->pgid() == -pid)
2575                    && (iter->signalValue == OS::TGT_SIGCHLD))
2576                    goto success;
2577            } else if (pid == -1) {
2578                if (iter->signalValue == OS::TGT_SIGCHLD)
2579                    goto success;
2580            } else if (pid == 0) {
2581                if ((iter->sender->pgid() == p->pgid())
2582                    && (iter->signalValue == OS::TGT_SIGCHLD))
2583                    goto success;
2584            } else {
2585                if ((iter->sender->pid() == pid)
2586                    && (iter->signalValue == OS::TGT_SIGCHLD))
2587                    goto success;
2588            }
2589        }
2590    }
2591
2592    return (options & OS::TGT_WNOHANG) ? 0 : SyscallReturn::retry();
2593
2594success:
2595    // Set status to EXITED for WIFEXITED evaluations.
2596    const int EXITED = 0;
2597    BufferArg statusBuf(statPtr, sizeof(int));
2598    *(int *)statusBuf.bufferPtr() = EXITED;
2599    statusBuf.copyOut(tc->getMemProxy());
2600
2601    // Return the child PID.
2602    pid_t retval = iter->sender->pid();
2603    sysh->signalList.erase(iter);
2604    return retval;
2605}
2606
2607template <class OS>
2608SyscallReturn
2609acceptFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
2610{
2611    struct sockaddr sa;
2612    socklen_t addrLen;
2613    int host_fd;
2614    int index = 0;
2615    int tgt_fd = p->getSyscallArg(tc, index);
2616    Addr addrPtr = p->getSyscallArg(tc, index);
2617    Addr lenPtr = p->getSyscallArg(tc, index);
2618
2619    BufferArg *lenBufPtr = nullptr;
2620    BufferArg *addrBufPtr = nullptr;
2621
2622    auto sfdp = std::dynamic_pointer_cast<SocketFDEntry>((*p->fds)[tgt_fd]);
2623    if (!sfdp)
2624        return -EBADF;
2625    int sim_fd = sfdp->getSimFD();
2626
2627    /**
2628     * We poll the socket file descriptor first to guarantee that we do not
2629     * block on our accept call. The socket can be opened without the
2630     * non-blocking flag (it blocks). This will cause deadlocks between
2631     * communicating processes.
2632     */
2633    struct pollfd pfd;
2634    pfd.fd = sim_fd;
2635    pfd.events = POLLIN | POLLPRI;
2636    if ((poll(&pfd, 1, 0) == 0)
2637        && !(sfdp->getFlags() & OS::TGT_O_NONBLOCK))
2638        return SyscallReturn::retry();
2639
2640    if (lenPtr) {
2641        lenBufPtr = new BufferArg(lenPtr, sizeof(socklen_t));
2642        lenBufPtr->copyIn(tc->getMemProxy());
2643        memcpy(&addrLen, (socklen_t *)lenBufPtr->bufferPtr(),
2644               sizeof(socklen_t));
2645    }
2646
2647    if (addrPtr) {
2648        addrBufPtr = new BufferArg(addrPtr, sizeof(struct sockaddr));
2649        addrBufPtr->copyIn(tc->getMemProxy());
2650        memcpy(&sa, (struct sockaddr *)addrBufPtr->bufferPtr(),
2651               sizeof(struct sockaddr));
2652    }
2653
2654    host_fd = accept(sim_fd, &sa, &addrLen);
2655
2656    if (host_fd == -1)
2657        return -errno;
2658
2659    if (addrPtr) {
2660        memcpy(addrBufPtr->bufferPtr(), &sa, sizeof(sa));
2661        addrBufPtr->copyOut(tc->getMemProxy());
2662        delete(addrBufPtr);
2663    }
2664
2665    if (lenPtr) {
2666        *(socklen_t *)lenBufPtr->bufferPtr() = addrLen;
2667        lenBufPtr->copyOut(tc->getMemProxy());
2668        delete(lenBufPtr);
2669    }
2670
2671    auto afdp = std::make_shared<SocketFDEntry>(host_fd, sfdp->_domain,
2672                                                sfdp->_type, sfdp->_protocol);
2673    return p->fds->allocFD(afdp);
2674}
2675
2676#endif // __SIM_SYSCALL_EMUL_HH__
2677