syscall_emul.hh revision 13651
16019Shines@cs.fsu.edu/*
211496Sandreas.sandberg@arm.com * Copyright (c) 2012-2013, 2015 ARM Limited
37093Sgblack@eecs.umich.edu * Copyright (c) 2015 Advanced Micro Devices, Inc.
47093Sgblack@eecs.umich.edu * All rights reserved
57093Sgblack@eecs.umich.edu *
67093Sgblack@eecs.umich.edu * The license below extends only to copyright in the software and shall
77093Sgblack@eecs.umich.edu * not be construed as granting a license to any other intellectual
87093Sgblack@eecs.umich.edu * property including but not limited to intellectual property relating
97093Sgblack@eecs.umich.edu * to a hardware implementation of the functionality of the software
107093Sgblack@eecs.umich.edu * licensed hereunder.  You may use the software subject to the license
117093Sgblack@eecs.umich.edu * terms below provided that you ensure that this notice is replicated
127093Sgblack@eecs.umich.edu * unmodified and in its entirety in all distributions of the software,
137093Sgblack@eecs.umich.edu * modified or unmodified, in source code or in binary form.
146019Shines@cs.fsu.edu *
156019Shines@cs.fsu.edu * Copyright (c) 2003-2005 The Regents of The University of Michigan
166019Shines@cs.fsu.edu * All rights reserved.
176019Shines@cs.fsu.edu *
186019Shines@cs.fsu.edu * Redistribution and use in source and binary forms, with or without
196019Shines@cs.fsu.edu * modification, are permitted provided that the following conditions are
206019Shines@cs.fsu.edu * met: redistributions of source code must retain the above copyright
216019Shines@cs.fsu.edu * notice, this list of conditions and the following disclaimer;
226019Shines@cs.fsu.edu * redistributions in binary form must reproduce the above copyright
236019Shines@cs.fsu.edu * notice, this list of conditions and the following disclaimer in the
246019Shines@cs.fsu.edu * documentation and/or other materials provided with the distribution;
256019Shines@cs.fsu.edu * neither the name of the copyright holders nor the names of its
266019Shines@cs.fsu.edu * contributors may be used to endorse or promote products derived from
276019Shines@cs.fsu.edu * this software without specific prior written permission.
286019Shines@cs.fsu.edu *
296019Shines@cs.fsu.edu * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
306019Shines@cs.fsu.edu * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
316019Shines@cs.fsu.edu * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
326019Shines@cs.fsu.edu * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
336019Shines@cs.fsu.edu * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
346019Shines@cs.fsu.edu * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
356019Shines@cs.fsu.edu * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
366019Shines@cs.fsu.edu * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
376019Shines@cs.fsu.edu * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
386019Shines@cs.fsu.edu * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
396019Shines@cs.fsu.edu * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
406019Shines@cs.fsu.edu *
416735Sgblack@eecs.umich.edu * Authors: Steve Reinhardt
426735Sgblack@eecs.umich.edu *          Kevin Lim
4310037SARM gem5 Developers */
4410037SARM gem5 Developers
456019Shines@cs.fsu.edu#ifndef __SIM_SYSCALL_EMUL_HH__
466019Shines@cs.fsu.edu#define __SIM_SYSCALL_EMUL_HH__
476019Shines@cs.fsu.edu
4811793Sbrandon.potter@amd.com#if (defined(__APPLE__) || defined(__OpenBSD__) ||      \
4911793Sbrandon.potter@amd.com     defined(__FreeBSD__) || defined(__CYGWIN__) ||     \
5010037SARM gem5 Developers     defined(__NetBSD__))
5110037SARM gem5 Developers#define NO_STAT64 1
5210037SARM gem5 Developers#else
538229Snate@binkert.org#define NO_STAT64 0
548229Snate@binkert.org#endif
556019Shines@cs.fsu.edu
568232Snate@binkert.org#if (defined(__APPLE__) || defined(__OpenBSD__) ||      \
578782Sgblack@eecs.umich.edu     defined(__FreeBSD__) || defined(__NetBSD__))
586019Shines@cs.fsu.edu#define NO_STATFS 1
596019Shines@cs.fsu.edu#else
606019Shines@cs.fsu.edu#define NO_STATFS 0
616019Shines@cs.fsu.edu#endif
6210037SARM gem5 Developers
6310037SARM gem5 Developers#if (defined(__APPLE__) || defined(__OpenBSD__) ||      \
6410037SARM gem5 Developers     defined(__FreeBSD__) || defined(__NetBSD__))
6510037SARM gem5 Developers#define NO_FALLOCATE 1
6610037SARM gem5 Developers#else
6710037SARM gem5 Developers#define NO_FALLOCATE 0
6810037SARM gem5 Developers#endif
6910037SARM gem5 Developers
7010037SARM gem5 Developers///
7110037SARM gem5 Developers/// @file syscall_emul.hh
7210037SARM gem5 Developers///
7310037SARM gem5 Developers/// This file defines objects used to emulate syscalls from the target
7410037SARM gem5 Developers/// application on the host machine.
7510037SARM gem5 Developers
7610037SARM gem5 Developers#ifdef __CYGWIN32__
7710037SARM gem5 Developers#include <sys/fcntl.h>
7810037SARM gem5 Developers
7910037SARM gem5 Developers#endif
8010037SARM gem5 Developers#include <fcntl.h>
8110037SARM gem5 Developers#include <poll.h>
8210037SARM gem5 Developers#include <sys/mman.h>
8310037SARM gem5 Developers#include <sys/socket.h>
8410037SARM gem5 Developers#include <sys/stat.h>
8510037SARM gem5 Developers#if (NO_STATFS == 0)
8610037SARM gem5 Developers#include <sys/statfs.h>
8710037SARM gem5 Developers#else
8810037SARM gem5 Developers#include <sys/mount.h>
8910037SARM gem5 Developers#endif
9010037SARM gem5 Developers#include <sys/time.h>
9110037SARM gem5 Developers#include <sys/types.h>
9210037SARM gem5 Developers#include <sys/uio.h>
9310037SARM gem5 Developers#include <unistd.h>
9410037SARM gem5 Developers
9510037SARM gem5 Developers#include <cerrno>
9610037SARM gem5 Developers#include <memory>
9710037SARM gem5 Developers#include <string>
9810037SARM gem5 Developers
9910037SARM gem5 Developers#include "arch/generic/tlb.hh"
10010037SARM gem5 Developers#include "arch/utility.hh"
10110037SARM gem5 Developers#include "base/intmath.hh"
1026019Shines@cs.fsu.edu#include "base/loader/object_file.hh"
10310037SARM gem5 Developers#include "base/logging.hh"
10410037SARM gem5 Developers#include "base/trace.hh"
10510037SARM gem5 Developers#include "base/types.hh"
1066019Shines@cs.fsu.edu#include "config/the_isa.hh"
10710037SARM gem5 Developers#include "cpu/base.hh"
10810037SARM gem5 Developers#include "cpu/thread_context.hh"
10910037SARM gem5 Developers#include "mem/page_table.hh"
11010037SARM gem5 Developers#include "params/Process.hh"
11110037SARM gem5 Developers#include "sim/emul_driver.hh"
11210037SARM gem5 Developers#include "sim/futex_map.hh"
11310037SARM gem5 Developers#include "sim/process.hh"
11410037SARM gem5 Developers#include "sim/syscall_debug_macros.hh"
11510037SARM gem5 Developers#include "sim/syscall_desc.hh"
11610037SARM gem5 Developers#include "sim/syscall_emul_buf.hh"
11710037SARM gem5 Developers#include "sim/syscall_return.hh"
11810037SARM gem5 Developers
11910037SARM gem5 Developers#if defined(__APPLE__) && defined(__MACH__) && !defined(CMSG_ALIGN)
12010037SARM gem5 Developers#define CMSG_ALIGN(len) (((len) + sizeof(size_t) - 1) & ~(sizeof(size_t) - 1))
12110037SARM gem5 Developers#endif
12210037SARM gem5 Developers
12310037SARM gem5 Developers//////////////////////////////////////////////////////////////////////
12410037SARM gem5 Developers//
12510037SARM gem5 Developers// The following emulation functions are generic enough that they
12610037SARM gem5 Developers// don't need to be recompiled for different emulated OS's.  They are
12710037SARM gem5 Developers// defined in sim/syscall_emul.cc.
12810037SARM gem5 Developers//
12910037SARM gem5 Developers//////////////////////////////////////////////////////////////////////
13010037SARM gem5 Developers
13110037SARM gem5 Developers
13210037SARM gem5 Developers/// Handler for unimplemented syscalls that we haven't thought about.
13310037SARM gem5 DevelopersSyscallReturn unimplementedFunc(SyscallDesc *desc, int num,
13410037SARM gem5 Developers                                Process *p, ThreadContext *tc);
13510037SARM gem5 Developers
13610037SARM gem5 Developers/// Handler for unimplemented syscalls that we never intend to
13710037SARM gem5 Developers/// implement (signal handling, etc.) and should not affect the correct
13810037SARM gem5 Developers/// behavior of the program.  Print a warning only if the appropriate
13910037SARM gem5 Developers/// trace flag is enabled.  Return success to the target program.
14010037SARM gem5 DevelopersSyscallReturn ignoreFunc(SyscallDesc *desc, int num,
14110037SARM gem5 Developers                         Process *p, ThreadContext *tc);
14210037SARM gem5 Developers
14310037SARM gem5 Developers// Target fallocateFunc() handler.
14410037SARM gem5 DevelopersSyscallReturn fallocateFunc(SyscallDesc *desc, int num,
14510037SARM gem5 Developers                            Process *p, ThreadContext *tc);
14610037SARM gem5 Developers
1476019Shines@cs.fsu.edu/// Target exit() handler: terminate current context.
14810037SARM gem5 DevelopersSyscallReturn exitFunc(SyscallDesc *desc, int num,
14910037SARM gem5 Developers                       Process *p, ThreadContext *tc);
15010037SARM gem5 Developers
1516019Shines@cs.fsu.edu/// Target exit_group() handler: terminate simulation. (exit all threads)
15210037SARM gem5 DevelopersSyscallReturn exitGroupFunc(SyscallDesc *desc, int num,
15310037SARM gem5 Developers                       Process *p, ThreadContext *tc);
15410037SARM gem5 Developers
15510037SARM gem5 Developers/// Target set_tid_address() handler.
15610037SARM gem5 DevelopersSyscallReturn setTidAddressFunc(SyscallDesc *desc, int num,
15710037SARM gem5 Developers                                Process *p, ThreadContext *tc);
15810037SARM gem5 Developers
15910037SARM gem5 Developers/// Target getpagesize() handler.
16010037SARM gem5 DevelopersSyscallReturn getpagesizeFunc(SyscallDesc *desc, int num,
16110037SARM gem5 Developers                              Process *p, ThreadContext *tc);
16210037SARM gem5 Developers
16310037SARM gem5 Developers/// Target brk() handler: set brk address.
16410037SARM gem5 DevelopersSyscallReturn brkFunc(SyscallDesc *desc, int num,
16510037SARM gem5 Developers                      Process *p, ThreadContext *tc);
16610037SARM gem5 Developers
16710037SARM gem5 Developers/// Target close() handler.
16810037SARM gem5 DevelopersSyscallReturn closeFunc(SyscallDesc *desc, int num,
16910037SARM gem5 Developers                        Process *p, ThreadContext *tc);
17010037SARM gem5 Developers
17110037SARM gem5 Developers/// Target lseek() handler.
17210037SARM gem5 DevelopersSyscallReturn lseekFunc(SyscallDesc *desc, int num,
17310037SARM gem5 Developers                        Process *p, ThreadContext *tc);
17410037SARM gem5 Developers
17510037SARM gem5 Developers/// Target _llseek() handler.
17610037SARM gem5 DevelopersSyscallReturn _llseekFunc(SyscallDesc *desc, int num,
17710037SARM gem5 Developers                          Process *p, ThreadContext *tc);
17810037SARM gem5 Developers
17910037SARM gem5 Developers/// Target munmap() handler.
18010037SARM gem5 DevelopersSyscallReturn munmapFunc(SyscallDesc *desc, int num,
18110037SARM gem5 Developers                         Process *p, ThreadContext *tc);
18210037SARM gem5 Developers
18310037SARM gem5 Developers/// Target shutdown() handler.
18410037SARM gem5 DevelopersSyscallReturn shutdownFunc(SyscallDesc *desc, int num,
18510037SARM gem5 Developers                           Process *p, ThreadContext *tc);
18610037SARM gem5 Developers
18710037SARM gem5 Developers/// Target gethostname() handler.
18810037SARM gem5 DevelopersSyscallReturn gethostnameFunc(SyscallDesc *desc, int num,
18910037SARM gem5 Developers                              Process *p, ThreadContext *tc);
19010037SARM gem5 Developers
19110037SARM gem5 Developers/// Target getcwd() handler.
19210037SARM gem5 DevelopersSyscallReturn getcwdFunc(SyscallDesc *desc, int num,
1936019Shines@cs.fsu.edu                         Process *p, ThreadContext *tc);
19410037SARM gem5 Developers
19510037SARM gem5 Developers/// Target readlink() handler.
19610037SARM gem5 DevelopersSyscallReturn readlinkFunc(SyscallDesc *desc, int num,
1976019Shines@cs.fsu.edu                           Process *p, ThreadContext *tc,
19810037SARM gem5 Developers                           int index = 0);
19910037SARM gem5 DevelopersSyscallReturn readlinkFunc(SyscallDesc *desc, int num,
20010037SARM gem5 Developers                           Process *p, ThreadContext *tc);
20110037SARM gem5 Developers
20210037SARM gem5 Developers/// Target unlink() handler.
20310037SARM gem5 DevelopersSyscallReturn unlinkHelper(SyscallDesc *desc, int num,
20410037SARM gem5 Developers                           Process *p, ThreadContext *tc,
20510037SARM gem5 Developers                           int index);
20610037SARM gem5 DevelopersSyscallReturn unlinkFunc(SyscallDesc *desc, int num,
20710037SARM gem5 Developers                         Process *p, ThreadContext *tc);
20810037SARM gem5 Developers
20910037SARM gem5 Developers/// Target link() handler
21010037SARM gem5 DevelopersSyscallReturn linkFunc(SyscallDesc *desc, int num, Process *p,
21110037SARM gem5 Developers                       ThreadContext *tc);
21210037SARM gem5 Developers
21310037SARM gem5 Developers/// Target symlink() handler.
21410037SARM gem5 DevelopersSyscallReturn symlinkFunc(SyscallDesc *desc, int num, Process *p,
21510037SARM gem5 Developers                          ThreadContext *tc);
21610037SARM gem5 Developers
21710037SARM gem5 Developers/// Target mkdir() handler.
21810037SARM gem5 DevelopersSyscallReturn mkdirFunc(SyscallDesc *desc, int num,
21910037SARM gem5 Developers                        Process *p, ThreadContext *tc);
22010037SARM gem5 Developers
22110037SARM gem5 Developers/// Target mknod() handler.
22210037SARM gem5 DevelopersSyscallReturn mknodFunc(SyscallDesc *desc, int num,
22310037SARM gem5 Developers                        Process *p, ThreadContext *tc);
22410037SARM gem5 Developers
22510037SARM gem5 Developers/// Target chdir() handler.
22610037SARM gem5 DevelopersSyscallReturn chdirFunc(SyscallDesc *desc, int num,
22710037SARM gem5 Developers                        Process *p, ThreadContext *tc);
22810037SARM gem5 Developers
22910037SARM gem5 Developers// Target rmdir() handler.
23010037SARM gem5 DevelopersSyscallReturn rmdirFunc(SyscallDesc *desc, int num,
23110037SARM gem5 Developers                        Process *p, ThreadContext *tc);
23210037SARM gem5 Developers
23310037SARM gem5 Developers/// Target rename() handler.
23410037SARM gem5 DevelopersSyscallReturn renameFunc(SyscallDesc *desc, int num,
23510037SARM gem5 Developers                         Process *p, ThreadContext *tc);
23610037SARM gem5 Developers
23710037SARM gem5 Developers
23810037SARM gem5 Developers/// Target truncate() handler.
23910037SARM gem5 DevelopersSyscallReturn truncateFunc(SyscallDesc *desc, int num,
24010037SARM gem5 Developers                           Process *p, ThreadContext *tc);
24110037SARM gem5 Developers
24210037SARM gem5 Developers
24310037SARM gem5 Developers/// Target ftruncate() handler.
24410037SARM gem5 DevelopersSyscallReturn ftruncateFunc(SyscallDesc *desc, int num,
24510037SARM gem5 Developers                            Process *p, ThreadContext *tc);
24610037SARM gem5 Developers
24710037SARM gem5 Developers
24810037SARM gem5 Developers/// Target truncate64() handler.
24910037SARM gem5 DevelopersSyscallReturn truncate64Func(SyscallDesc *desc, int num,
25010037SARM gem5 Developers                             Process *p, ThreadContext *tc);
25110037SARM gem5 Developers
25210037SARM gem5 Developers/// Target ftruncate64() handler.
25310037SARM gem5 DevelopersSyscallReturn ftruncate64Func(SyscallDesc *desc, int num,
25410037SARM gem5 Developers                              Process *p, ThreadContext *tc);
25510037SARM gem5 Developers
25610037SARM gem5 Developers
25710037SARM gem5 Developers/// Target umask() handler.
25810037SARM gem5 DevelopersSyscallReturn umaskFunc(SyscallDesc *desc, int num,
25910037SARM gem5 Developers                        Process *p, ThreadContext *tc);
26010037SARM gem5 Developers
26110037SARM gem5 Developers/// Target gettid() handler.
26210037SARM gem5 DevelopersSyscallReturn gettidFunc(SyscallDesc *desc, int num,
26310037SARM gem5 Developers                         Process *p, ThreadContext *tc);
26410037SARM gem5 Developers
26510037SARM gem5 Developers/// Target chown() handler.
26610037SARM gem5 DevelopersSyscallReturn chownFunc(SyscallDesc *desc, int num,
26710037SARM gem5 Developers                        Process *p, ThreadContext *tc);
26810037SARM gem5 Developers
26910037SARM gem5 Developers/// Target setpgid() handler.
27010037SARM gem5 DevelopersSyscallReturn setpgidFunc(SyscallDesc *desc, int num,
27110037SARM gem5 Developers                          Process *p, ThreadContext *tc);
27210037SARM gem5 Developers
27310037SARM gem5 Developers/// Target fchown() handler.
27410037SARM gem5 DevelopersSyscallReturn fchownFunc(SyscallDesc *desc, int num,
27510037SARM gem5 Developers                         Process *p, ThreadContext *tc);
27610037SARM gem5 Developers
27710037SARM gem5 Developers/// Target dup() handler.
27810037SARM gem5 DevelopersSyscallReturn dupFunc(SyscallDesc *desc, int num,
27910037SARM gem5 Developers                      Process *process, ThreadContext *tc);
28010037SARM gem5 Developers
28110037SARM gem5 Developers/// Target dup2() handler.
28210037SARM gem5 DevelopersSyscallReturn dup2Func(SyscallDesc *desc, int num,
28310037SARM gem5 Developers                       Process *process, ThreadContext *tc);
28410037SARM gem5 Developers
28510037SARM gem5 Developers/// Target fcntl() handler.
28610037SARM gem5 DevelopersSyscallReturn fcntlFunc(SyscallDesc *desc, int num,
28710037SARM gem5 Developers                        Process *process, ThreadContext *tc);
28810037SARM gem5 Developers
28910037SARM gem5 Developers/// Target fcntl64() handler.
29010037SARM gem5 DevelopersSyscallReturn fcntl64Func(SyscallDesc *desc, int num,
29110037SARM gem5 Developers                          Process *process, ThreadContext *tc);
29210037SARM gem5 Developers
29310037SARM gem5 Developers/// Target setuid() handler.
29410037SARM gem5 DevelopersSyscallReturn setuidFunc(SyscallDesc *desc, int num,
29510037SARM gem5 Developers                         Process *p, ThreadContext *tc);
2966019Shines@cs.fsu.edu
29710037SARM gem5 Developers/// Target pipe() handler.
2987362Sgblack@eecs.umich.eduSyscallReturn pipeFunc(SyscallDesc *desc, int num,
2996735Sgblack@eecs.umich.edu                       Process *p, ThreadContext *tc);
30010037SARM gem5 Developers
3016019Shines@cs.fsu.edu/// Internal pipe() handler.
30210037SARM gem5 DevelopersSyscallReturn pipeImpl(SyscallDesc *desc, int num, Process *p,
30310037SARM gem5 Developers                       ThreadContext *tc, bool pseudoPipe);
3047400SAli.Saidi@ARM.com
3056735Sgblack@eecs.umich.edu/// Target getpid() handler.
3066735Sgblack@eecs.umich.eduSyscallReturn getpidFunc(SyscallDesc *desc, int num,
30710037SARM gem5 Developers                         Process *p, ThreadContext *tc);
3086735Sgblack@eecs.umich.edu
30910037SARM gem5 Developers// Target getpeername() handler.
31010037SARM gem5 DevelopersSyscallReturn getpeernameFunc(SyscallDesc *desc, int num,
31110037SARM gem5 Developers                              Process *p, ThreadContext *tc);
31210037SARM gem5 Developers
3137400SAli.Saidi@ARM.com// Target bind() handler.
31410037SARM gem5 DevelopersSyscallReturn bindFunc(SyscallDesc *desc, int num,
31510037SARM gem5 Developers                       Process *p, ThreadContext *tc);
31610037SARM gem5 Developers
31710037SARM gem5 Developers// Target listen() handler.
31810037SARM gem5 DevelopersSyscallReturn listenFunc(SyscallDesc *desc, int num,
31910037SARM gem5 Developers                         Process *p, ThreadContext *tc);
32010037SARM gem5 Developers
32110037SARM gem5 Developers// Target connect() handler.
32210037SARM gem5 DevelopersSyscallReturn connectFunc(SyscallDesc *desc, int num,
32310037SARM gem5 Developers                          Process *p, ThreadContext *tc);
32410037SARM gem5 Developers
32510037SARM gem5 Developers#if defined(SYS_getdents)
32610037SARM gem5 Developers// Target getdents() handler.
32710037SARM gem5 DevelopersSyscallReturn getdentsFunc(SyscallDesc *desc, int num,
32810037SARM gem5 Developers                           Process *p, ThreadContext *tc);
32910037SARM gem5 Developers#endif
33010037SARM gem5 Developers
3316019Shines@cs.fsu.edu#if defined(SYS_getdents64)
3326019Shines@cs.fsu.edu// Target getdents() handler.
33310037SARM gem5 DevelopersSyscallReturn getdents64Func(SyscallDesc *desc, int num,
33410037SARM gem5 Developers                           Process *p, ThreadContext *tc);
33510037SARM gem5 Developers#endif
33610037SARM gem5 Developers
33710037SARM gem5 Developers// Target sendto() handler.
33810037SARM gem5 DevelopersSyscallReturn sendtoFunc(SyscallDesc *desc, int num,
33910037SARM gem5 Developers                         Process *p, ThreadContext *tc);
34010037SARM gem5 Developers
34110037SARM gem5 Developers// Target recvfrom() handler.
34211574SCurtis.Dunham@arm.comSyscallReturn recvfromFunc(SyscallDesc *desc, int num,
34311574SCurtis.Dunham@arm.com                           Process *p, ThreadContext *tc);
34411574SCurtis.Dunham@arm.com
34511574SCurtis.Dunham@arm.com// Target recvmsg() handler.
34610037SARM gem5 DevelopersSyscallReturn recvmsgFunc(SyscallDesc *desc, int num,
34710037SARM gem5 Developers                          Process *p, ThreadContext *tc);
34810037SARM gem5 Developers
34910037SARM gem5 Developers// Target sendmsg() handler.
35010037SARM gem5 DevelopersSyscallReturn sendmsgFunc(SyscallDesc *desc, int num,
35110037SARM gem5 Developers                          Process *p, ThreadContext *tc);
35210037SARM gem5 Developers
35310037SARM gem5 Developers// Target getuid() handler.
35410037SARM gem5 DevelopersSyscallReturn getuidFunc(SyscallDesc *desc, int num,
35510037SARM gem5 Developers                         Process *p, ThreadContext *tc);
35610037SARM gem5 Developers
35710037SARM gem5 Developers/// Target getgid() handler.
35810037SARM gem5 DevelopersSyscallReturn getgidFunc(SyscallDesc *desc, int num,
35910037SARM gem5 Developers                         Process *p, ThreadContext *tc);
36010037SARM gem5 Developers
36110037SARM gem5 Developers/// Target getppid() handler.
36210037SARM gem5 DevelopersSyscallReturn getppidFunc(SyscallDesc *desc, int num,
36310037SARM gem5 Developers                          Process *p, ThreadContext *tc);
36410037SARM gem5 Developers
36510037SARM gem5 Developers/// Target geteuid() handler.
36610037SARM gem5 DevelopersSyscallReturn geteuidFunc(SyscallDesc *desc, int num,
36710037SARM gem5 Developers                          Process *p, ThreadContext *tc);
36810037SARM gem5 Developers
36910037SARM gem5 Developers/// Target getegid() handler.
37010037SARM gem5 DevelopersSyscallReturn getegidFunc(SyscallDesc *desc, int num,
37110037SARM gem5 Developers                          Process *p, ThreadContext *tc);
37210037SARM gem5 Developers
37310037SARM gem5 Developers/// Target access() handler
37410037SARM gem5 DevelopersSyscallReturn accessFunc(SyscallDesc *desc, int num,
37510037SARM gem5 Developers                         Process *p, ThreadContext *tc);
37610037SARM gem5 DevelopersSyscallReturn accessFunc(SyscallDesc *desc, int num,
37710037SARM gem5 Developers                         Process *p, ThreadContext *tc,
37810037SARM gem5 Developers                         int index);
37910037SARM gem5 Developers
38010037SARM gem5 Developers// Target getsockopt() handler.
38110037SARM gem5 DevelopersSyscallReturn getsockoptFunc(SyscallDesc *desc, int num,
38210037SARM gem5 Developers                             Process *p, ThreadContext *tc);
38310037SARM gem5 Developers
38410037SARM gem5 Developers// Target setsockopt() handler.
38510037SARM gem5 DevelopersSyscallReturn setsockoptFunc(SyscallDesc *desc, int num,
38610037SARM gem5 Developers                             Process *p, ThreadContext *tc);
38710037SARM gem5 Developers
38810037SARM gem5 Developers// Target getsockname() handler.
38910037SARM gem5 DevelopersSyscallReturn getsocknameFunc(SyscallDesc *desc, int num,
39010037SARM gem5 Developers                              Process *p, ThreadContext *tc);
39110037SARM gem5 Developers
39210037SARM gem5 Developers/// Futex system call
39310037SARM gem5 Developers/// Implemented by Daniel Sanchez
39410037SARM gem5 Developers/// Used by printf's in multi-threaded apps
39510037SARM gem5 Developerstemplate <class OS>
39610037SARM gem5 DevelopersSyscallReturn
39710037SARM gem5 DevelopersfutexFunc(SyscallDesc *desc, int callnum, Process *process,
39810037SARM gem5 Developers          ThreadContext *tc)
39910037SARM gem5 Developers{
40010037SARM gem5 Developers    using namespace std;
40110037SARM gem5 Developers
40210037SARM gem5 Developers    int index = 0;
40310037SARM gem5 Developers    Addr uaddr = process->getSyscallArg(tc, index);
40410037SARM gem5 Developers    int op = process->getSyscallArg(tc, index);
40510037SARM gem5 Developers    int val = process->getSyscallArg(tc, index);
40610037SARM gem5 Developers    int timeout M5_VAR_USED = process->getSyscallArg(tc, index);
40710037SARM gem5 Developers    Addr uaddr2 M5_VAR_USED = process->getSyscallArg(tc, index);
40810037SARM gem5 Developers    int val3 = process->getSyscallArg(tc, index);
40910037SARM gem5 Developers
41010037SARM gem5 Developers    /*
41110037SARM gem5 Developers     * Unsupported option that does not affect the correctness of the
41210037SARM gem5 Developers     * application. This is a performance optimization utilized by Linux.
41310037SARM gem5 Developers     */
41410037SARM gem5 Developers    op &= ~OS::TGT_FUTEX_PRIVATE_FLAG;
41510037SARM gem5 Developers    op &= ~OS::TGT_FUTEX_CLOCK_REALTIME_FLAG;
41610037SARM gem5 Developers
41710037SARM gem5 Developers    FutexMap &futex_map = tc->getSystemPtr()->futexMap;
41810037SARM gem5 Developers
41910037SARM gem5 Developers    if (OS::TGT_FUTEX_WAIT == op || OS::TGT_FUTEX_WAIT_BITSET == op) {
42010037SARM gem5 Developers        // Ensure futex system call accessed atomically.
42110037SARM gem5 Developers        BufferArg buf(uaddr, sizeof(int));
42210037SARM gem5 Developers        buf.copyIn(tc->getMemProxy());
42310037SARM gem5 Developers        int mem_val = *(int*)buf.bufferPtr();
42410037SARM gem5 Developers
42510037SARM gem5 Developers        /*
42610037SARM gem5 Developers         * The value in memory at uaddr is not equal with the expected val
42710037SARM gem5 Developers         * (a different thread must have changed it before the system call was
42810037SARM gem5 Developers         * invoked). In this case, we need to throw an error.
42910417Sandreas.hansson@arm.com         */
4306019Shines@cs.fsu.edu        if (val != mem_val)
43110037SARM gem5 Developers            return -OS::TGT_EWOULDBLOCK;
43210037SARM gem5 Developers
43310037SARM gem5 Developers        if (OS::TGT_FUTEX_WAIT) {
43410037SARM gem5 Developers            futex_map.suspend(uaddr, process->tgid(), tc);
43510037SARM gem5 Developers        } else {
43610037SARM gem5 Developers            futex_map.suspend_bitset(uaddr, process->tgid(), tc, val3);
43710037SARM gem5 Developers        }
43810037SARM gem5 Developers
43910037SARM gem5 Developers        return 0;
44010037SARM gem5 Developers    } else if (OS::TGT_FUTEX_WAKE == op) {
44110037SARM gem5 Developers        return futex_map.wakeup(uaddr, process->tgid(), val);
44210037SARM gem5 Developers    } else if (OS::TGT_FUTEX_WAKE_BITSET == op) {
44311578SDylan.Johnson@ARM.com        return futex_map.wakeup_bitset(uaddr, process->tgid(), val3);
44411578SDylan.Johnson@ARM.com    } else if (OS::TGT_FUTEX_REQUEUE == op ||
44510037SARM gem5 Developers               OS::TGT_FUTEX_CMP_REQUEUE == op) {
44610037SARM gem5 Developers
44710037SARM gem5 Developers        // Ensure futex system call accessed atomically.
44810037SARM gem5 Developers        BufferArg buf(uaddr, sizeof(int));
44910037SARM gem5 Developers        buf.copyIn(tc->getMemProxy());
45010037SARM gem5 Developers        int mem_val = *(int*)buf.bufferPtr();
45110037SARM gem5 Developers        /*
45210037SARM gem5 Developers         * For CMP_REQUEUE, the whole operation is only started only if
45310037SARM gem5 Developers         * val3 is still the value of the futex pointed to by uaddr.
45410037SARM gem5 Developers         */
45510037SARM gem5 Developers        if (OS::TGT_FUTEX_CMP_REQUEUE && val3 != mem_val)
45610037SARM gem5 Developers            return -OS::TGT_EWOULDBLOCK;
45710037SARM gem5 Developers        return futex_map.requeue(uaddr, process->tgid(), val, timeout, uaddr2);
45810037SARM gem5 Developers    } else if (OS::TGT_FUTEX_WAKE_OP == op) {
45910037SARM gem5 Developers        /*
46010037SARM gem5 Developers         * The FUTEX_WAKE_OP operation is equivalent to executing the
46110037SARM gem5 Developers         * following code atomically and totally ordered with respect to
46210037SARM gem5 Developers         * other futex operations on any of the two supplied futex words:
4636735Sgblack@eecs.umich.edu         *
4648782Sgblack@eecs.umich.edu         *   int oldval = *(int *) addr2;
4658782Sgblack@eecs.umich.edu         *   *(int *) addr2 = oldval op oparg;
4666735Sgblack@eecs.umich.edu         *   futex(addr1, FUTEX_WAKE, val, 0, 0, 0);
4676019Shines@cs.fsu.edu         *   if (oldval cmp cmparg)
4686735Sgblack@eecs.umich.edu         *        futex(addr2, FUTEX_WAKE, val2, 0, 0, 0);
46910037SARM gem5 Developers         *
4708303SAli.Saidi@ARM.com         * (op, oparg, cmp, cmparg are encoded in val3)
47110338SCurtis.Dunham@arm.com         *
47210338SCurtis.Dunham@arm.com         * +---+---+-----------+-----------+
47310338SCurtis.Dunham@arm.com         * |op |cmp|   oparg   |  cmparg   |
47410338SCurtis.Dunham@arm.com         * +---+---+-----------+-----------+
4758303SAli.Saidi@ARM.com         *   4   4       12          12    <== # of bits
4767720Sgblack@eecs.umich.edu         *
4778205SAli.Saidi@ARM.com         * reference: http://man7.org/linux/man-pages/man2/futex.2.html
4788205SAli.Saidi@ARM.com         *
4798205SAli.Saidi@ARM.com         */
4806735Sgblack@eecs.umich.edu        // get value from simulated-space
48110037SARM gem5 Developers        BufferArg buf(uaddr2, sizeof(int));
48210037SARM gem5 Developers        buf.copyIn(tc->getMemProxy());
48310037SARM gem5 Developers        int oldval = *(int*)buf.bufferPtr();
48410037SARM gem5 Developers        int newval = oldval;
48510037SARM gem5 Developers        // extract op, oparg, cmp, cmparg from val3
48610037SARM gem5 Developers        int wake_cmparg =  val3 & 0xfff;
48710037SARM gem5 Developers        int wake_oparg  = (val3 & 0xfff000)   >> 12;
48810037SARM gem5 Developers        int wake_cmp    = (val3 & 0xf000000)  >> 24;
48910037SARM gem5 Developers        int wake_op     = (val3 & 0xf0000000) >> 28;
49010037SARM gem5 Developers        if ((wake_op & OS::TGT_FUTEX_OP_ARG_SHIFT) >> 3 == 1)
49110037SARM gem5 Developers            wake_oparg = (1 << wake_oparg);
49210037SARM gem5 Developers        wake_op &= ~OS::TGT_FUTEX_OP_ARG_SHIFT;
49310037SARM gem5 Developers        // perform operation on the value of the second futex
49410037SARM gem5 Developers        if (wake_op == OS::TGT_FUTEX_OP_SET)
49510037SARM gem5 Developers            newval = wake_oparg;
49610037SARM gem5 Developers        else if (wake_op == OS::TGT_FUTEX_OP_ADD)
49710037SARM gem5 Developers            newval += wake_oparg;
49810037SARM gem5 Developers        else if (wake_op == OS::TGT_FUTEX_OP_OR)
49910037SARM gem5 Developers            newval |= wake_oparg;
50010037SARM gem5 Developers        else if (wake_op == OS::TGT_FUTEX_OP_ANDN)
50110037SARM gem5 Developers            newval &= ~wake_oparg;
50210037SARM gem5 Developers        else if (wake_op == OS::TGT_FUTEX_OP_XOR)
50310037SARM gem5 Developers            newval ^= wake_oparg;
50410037SARM gem5 Developers        // copy updated value back to simulated-space
50510037SARM gem5 Developers        *(int*)buf.bufferPtr() = newval;
50610037SARM gem5 Developers        buf.copyOut(tc->getMemProxy());
50710037SARM gem5 Developers        // perform the first wake-up
50810037SARM gem5 Developers        int woken1 = futex_map.wakeup(uaddr, process->tgid(), val);
50910037SARM gem5 Developers        int woken2 = 0;
51010037SARM gem5 Developers        // calculate the condition of the second wake-up
51110037SARM gem5 Developers        bool is_wake2 = false;
51210037SARM gem5 Developers        if (wake_cmp == OS::TGT_FUTEX_OP_CMP_EQ)
51310037SARM gem5 Developers            is_wake2 = oldval == wake_cmparg;
51410037SARM gem5 Developers        else if (wake_cmp == OS::TGT_FUTEX_OP_CMP_NE)
51510037SARM gem5 Developers            is_wake2 = oldval != wake_cmparg;
51610037SARM gem5 Developers        else if (wake_cmp == OS::TGT_FUTEX_OP_CMP_LT)
51710037SARM gem5 Developers            is_wake2 = oldval < wake_cmparg;
51810037SARM gem5 Developers        else if (wake_cmp == OS::TGT_FUTEX_OP_CMP_LE)
51910037SARM gem5 Developers            is_wake2 = oldval <= wake_cmparg;
52010037SARM gem5 Developers        else if (wake_cmp == OS::TGT_FUTEX_OP_CMP_GT)
52110037SARM gem5 Developers            is_wake2 = oldval > wake_cmparg;
52210037SARM gem5 Developers        else if (wake_cmp == OS::TGT_FUTEX_OP_CMP_GE)
52310037SARM gem5 Developers            is_wake2 = oldval >= wake_cmparg;
52410037SARM gem5 Developers        // perform the second wake-up
52510037SARM gem5 Developers        if (is_wake2)
52610037SARM gem5 Developers            woken2 = futex_map.wakeup(uaddr2, process->tgid(), timeout);
52710037SARM gem5 Developers
52810037SARM gem5 Developers        return woken1 + woken2;
5296735Sgblack@eecs.umich.edu    }
5306735Sgblack@eecs.umich.edu    warn("futex: op %d not implemented; ignoring.", op);
5316735Sgblack@eecs.umich.edu    return -ENOSYS;
53210037SARM gem5 Developers}
5338518Sgeoffrey.blake@arm.com
5348518Sgeoffrey.blake@arm.com
5356735Sgblack@eecs.umich.edu/// Pseudo Funcs  - These functions use a different return convension,
53610037SARM gem5 Developers/// returning a second value in a register other than the normal return register
53710037SARM gem5 DevelopersSyscallReturn pipePseudoFunc(SyscallDesc *desc, int num,
53810037SARM gem5 Developers                             Process *process, ThreadContext *tc);
53910037SARM gem5 Developers
54010037SARM gem5 Developers/// Target getpidPseudo() handler.
54110037SARM gem5 DevelopersSyscallReturn getpidPseudoFunc(SyscallDesc *desc, int num,
54210037SARM gem5 Developers                               Process *p, ThreadContext *tc);
54310037SARM gem5 Developers
54410037SARM gem5 Developers/// Target getuidPseudo() handler.
54510037SARM gem5 DevelopersSyscallReturn getuidPseudoFunc(SyscallDesc *desc, int num,
54610037SARM gem5 Developers                               Process *p, ThreadContext *tc);
54710037SARM gem5 Developers
5486735Sgblack@eecs.umich.edu/// Target getgidPseudo() handler.
5496735Sgblack@eecs.umich.eduSyscallReturn getgidPseudoFunc(SyscallDesc *desc, int num,
5506735Sgblack@eecs.umich.edu                               Process *p, ThreadContext *tc);
5516735Sgblack@eecs.umich.edu
5526735Sgblack@eecs.umich.edu
5536735Sgblack@eecs.umich.edu/// A readable name for 1,000,000, for converting microseconds to seconds.
5546735Sgblack@eecs.umich.educonst int one_million = 1000000;
5556735Sgblack@eecs.umich.edu/// A readable name for 1,000,000,000, for converting nanoseconds to seconds.
5566735Sgblack@eecs.umich.educonst int one_billion = 1000000000;
55710037SARM gem5 Developers
55810037SARM gem5 Developers/// Approximate seconds since the epoch (1/1/1970).  About a billion,
55910037SARM gem5 Developers/// by my reckoning.  We want to keep this a constant (not use the
5606735Sgblack@eecs.umich.edu/// real-world time) to keep simulations repeatable.
5616735Sgblack@eecs.umich.educonst unsigned seconds_since_epoch = 1000000000;
5626735Sgblack@eecs.umich.edu
5636735Sgblack@eecs.umich.edu/// Helper function to convert current elapsed time to seconds and
56410037SARM gem5 Developers/// microseconds.
56510037SARM gem5 Developerstemplate <class T1, class T2>
56610037SARM gem5 Developersvoid
56710037SARM gem5 DevelopersgetElapsedTimeMicro(T1 &sec, T2 &usec)
56810037SARM gem5 Developers{
56910037SARM gem5 Developers    uint64_t elapsed_usecs = curTick() / SimClock::Int::us;
57010037SARM gem5 Developers    sec = elapsed_usecs / one_million;
57110037SARM gem5 Developers    usec = elapsed_usecs % one_million;
57210037SARM gem5 Developers}
57310037SARM gem5 Developers
5746735Sgblack@eecs.umich.edu/// Helper function to convert current elapsed time to seconds and
5756735Sgblack@eecs.umich.edu/// nanoseconds.
5767093Sgblack@eecs.umich.edutemplate <class T1, class T2>
5777093Sgblack@eecs.umich.eduvoid
5787720Sgblack@eecs.umich.edugetElapsedTimeNano(T1 &sec, T2 &nsec)
5797585SAli.Saidi@arm.com{
5807720Sgblack@eecs.umich.edu    uint64_t elapsed_nsecs = curTick() / SimClock::Int::ns;
5817720Sgblack@eecs.umich.edu    sec = elapsed_nsecs / one_billion;
5827720Sgblack@eecs.umich.edu    nsec = elapsed_nsecs % one_billion;
5837720Sgblack@eecs.umich.edu}
5847720Sgblack@eecs.umich.edu
5857720Sgblack@eecs.umich.edu//////////////////////////////////////////////////////////////////////
58610037SARM gem5 Developers//
58710037SARM gem5 Developers// The following emulation functions are generic, but need to be
5887720Sgblack@eecs.umich.edu// templated to account for differences in types, constants, etc.
5896019Shines@cs.fsu.edu//
5907189Sgblack@eecs.umich.edu//////////////////////////////////////////////////////////////////////
5917400SAli.Saidi@ARM.com
59210417Sandreas.hansson@arm.com    typedef struct statfs hst_statfs;
59310037SARM gem5 Developers#if NO_STAT64
59410037SARM gem5 Developers    typedef struct stat hst_stat;
59510037SARM gem5 Developers    typedef struct stat hst_stat64;
59610037SARM gem5 Developers#else
59710037SARM gem5 Developers    typedef struct stat hst_stat;
59810037SARM gem5 Developers    typedef struct stat64 hst_stat64;
59910037SARM gem5 Developers#endif
60010037SARM gem5 Developers
60111574SCurtis.Dunham@arm.com//// Helper function to convert a host stat buffer to a target stat
60211574SCurtis.Dunham@arm.com//// buffer.  Also copies the target buffer out to the simulated
60311574SCurtis.Dunham@arm.com//// memory space.  Used by stat(), fstat(), and lstat().
60411574SCurtis.Dunham@arm.com
60511574SCurtis.Dunham@arm.comtemplate <typename target_stat, typename host_stat>
60610037SARM gem5 Developersvoid
60710037SARM gem5 DevelopersconvertStatBuf(target_stat &tgt, host_stat *host, bool fakeTTY = false)
60810037SARM gem5 Developers{
60910037SARM gem5 Developers    using namespace TheISA;
61010037SARM gem5 Developers
61110037SARM gem5 Developers    if (fakeTTY)
61210037SARM gem5 Developers        tgt->st_dev = 0xA;
61310037SARM gem5 Developers    else
61410037SARM gem5 Developers        tgt->st_dev = host->st_dev;
61510037SARM gem5 Developers    tgt->st_dev = TheISA::htog(tgt->st_dev);
61610037SARM gem5 Developers    tgt->st_ino = host->st_ino;
61710037SARM gem5 Developers    tgt->st_ino = TheISA::htog(tgt->st_ino);
61810037SARM gem5 Developers    tgt->st_mode = host->st_mode;
61910338SCurtis.Dunham@arm.com    if (fakeTTY) {
62010338SCurtis.Dunham@arm.com        // Claim to be a character device
62110338SCurtis.Dunham@arm.com        tgt->st_mode &= ~S_IFMT;    // Clear S_IFMT
62210037SARM gem5 Developers        tgt->st_mode |= S_IFCHR;    // Set S_IFCHR
62310037SARM gem5 Developers    }
62410037SARM gem5 Developers    tgt->st_mode = TheISA::htog(tgt->st_mode);
62510037SARM gem5 Developers    tgt->st_nlink = host->st_nlink;
62610037SARM gem5 Developers    tgt->st_nlink = TheISA::htog(tgt->st_nlink);
62710037SARM gem5 Developers    tgt->st_uid = host->st_uid;
62810037SARM gem5 Developers    tgt->st_uid = TheISA::htog(tgt->st_uid);
62910037SARM gem5 Developers    tgt->st_gid = host->st_gid;
63010037SARM gem5 Developers    tgt->st_gid = TheISA::htog(tgt->st_gid);
63110037SARM gem5 Developers    if (fakeTTY)
63210338SCurtis.Dunham@arm.com        tgt->st_rdev = 0x880d;
63310037SARM gem5 Developers    else
63410037SARM gem5 Developers        tgt->st_rdev = host->st_rdev;
63510037SARM gem5 Developers    tgt->st_rdev = TheISA::htog(tgt->st_rdev);
63610037SARM gem5 Developers    tgt->st_size = host->st_size;
63710037SARM gem5 Developers    tgt->st_size = TheISA::htog(tgt->st_size);
63810037SARM gem5 Developers    tgt->st_atimeX = host->st_atime;
63910037SARM gem5 Developers    tgt->st_atimeX = TheISA::htog(tgt->st_atimeX);
64010037SARM gem5 Developers    tgt->st_mtimeX = host->st_mtime;
64110037SARM gem5 Developers    tgt->st_mtimeX = TheISA::htog(tgt->st_mtimeX);
64210037SARM gem5 Developers    tgt->st_ctimeX = host->st_ctime;
64310037SARM gem5 Developers    tgt->st_ctimeX = TheISA::htog(tgt->st_ctimeX);
64410037SARM gem5 Developers    // Force the block size to be 8KB. This helps to ensure buffered io works
64510037SARM gem5 Developers    // consistently across different hosts.
64610037SARM gem5 Developers    tgt->st_blksize = 0x2000;
64710037SARM gem5 Developers    tgt->st_blksize = TheISA::htog(tgt->st_blksize);
64810037SARM gem5 Developers    tgt->st_blocks = host->st_blocks;
64910037SARM gem5 Developers    tgt->st_blocks = TheISA::htog(tgt->st_blocks);
65010037SARM gem5 Developers}
65110037SARM gem5 Developers
65210037SARM gem5 Developers// Same for stat64
65310037SARM gem5 Developers
65410037SARM gem5 Developerstemplate <typename target_stat, typename host_stat64>
65510037SARM gem5 Developersvoid
65610037SARM gem5 DevelopersconvertStat64Buf(target_stat &tgt, host_stat64 *host, bool fakeTTY = false)
65710037SARM gem5 Developers{
65810037SARM gem5 Developers    using namespace TheISA;
65910037SARM gem5 Developers
66010037SARM gem5 Developers    convertStatBuf<target_stat, host_stat64>(tgt, host, fakeTTY);
66110037SARM gem5 Developers#if defined(STAT_HAVE_NSEC)
66210037SARM gem5 Developers    tgt->st_atime_nsec = host->st_atime_nsec;
66310037SARM gem5 Developers    tgt->st_atime_nsec = TheISA::htog(tgt->st_atime_nsec);
66410037SARM gem5 Developers    tgt->st_mtime_nsec = host->st_mtime_nsec;
66510037SARM gem5 Developers    tgt->st_mtime_nsec = TheISA::htog(tgt->st_mtime_nsec);
66610037SARM gem5 Developers    tgt->st_ctime_nsec = host->st_ctime_nsec;
66710037SARM gem5 Developers    tgt->st_ctime_nsec = TheISA::htog(tgt->st_ctime_nsec);
66810037SARM gem5 Developers#else
66910037SARM gem5 Developers    tgt->st_atime_nsec = 0;
67010037SARM gem5 Developers    tgt->st_mtime_nsec = 0;
67110037SARM gem5 Developers    tgt->st_ctime_nsec = 0;
67210037SARM gem5 Developers#endif
67310037SARM gem5 Developers}
67410037SARM gem5 Developers
67510037SARM gem5 Developers// Here are a couple of convenience functions
67610037SARM gem5 Developerstemplate<class OS>
67710037SARM gem5 Developersvoid
67810037SARM gem5 DeveloperscopyOutStatBuf(SETranslatingPortProxy &mem, Addr addr,
67910037SARM gem5 Developers               hst_stat *host, bool fakeTTY = false)
68010037SARM gem5 Developers{
68110037SARM gem5 Developers    typedef TypedBufferArg<typename OS::tgt_stat> tgt_stat_buf;
68210417Sandreas.hansson@arm.com    tgt_stat_buf tgt(addr);
6837400SAli.Saidi@ARM.com    convertStatBuf<tgt_stat_buf, hst_stat>(tgt, host, fakeTTY);
6848782Sgblack@eecs.umich.edu    tgt.copyOut(mem);
68511150Smitch.hayenga@arm.com}
6868782Sgblack@eecs.umich.edu
6878782Sgblack@eecs.umich.edutemplate<class OS>
68810037SARM gem5 Developersvoid
68910037SARM gem5 DeveloperscopyOutStat64Buf(SETranslatingPortProxy &mem, Addr addr,
69010037SARM gem5 Developers                 hst_stat64 *host, bool fakeTTY = false)
69110037SARM gem5 Developers{
69210037SARM gem5 Developers    typedef TypedBufferArg<typename OS::tgt_stat64> tgt_stat_buf;
69310037SARM gem5 Developers    tgt_stat_buf tgt(addr);
69410037SARM gem5 Developers    convertStat64Buf<tgt_stat_buf, hst_stat64>(tgt, host, fakeTTY);
69510037SARM gem5 Developers    tgt.copyOut(mem);
69610037SARM gem5 Developers}
69710037SARM gem5 Developers
69810037SARM gem5 Developerstemplate <class OS>
69910037SARM gem5 Developersvoid
70010037SARM gem5 DeveloperscopyOutStatfsBuf(SETranslatingPortProxy &mem, Addr addr,
70110037SARM gem5 Developers                 hst_statfs *host)
70210037SARM gem5 Developers{
70310037SARM gem5 Developers    TypedBufferArg<typename OS::tgt_statfs> tgt(addr);
70410037SARM gem5 Developers
70510037SARM gem5 Developers    tgt->f_type = TheISA::htog(host->f_type);
70610037SARM gem5 Developers#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__)
7077400SAli.Saidi@ARM.com    tgt->f_bsize = TheISA::htog(host->f_iosize);
7087400SAli.Saidi@ARM.com#else
7097189Sgblack@eecs.umich.edu    tgt->f_bsize = TheISA::htog(host->f_bsize);
71010417Sandreas.hansson@arm.com#endif
7117189Sgblack@eecs.umich.edu    tgt->f_blocks = TheISA::htog(host->f_blocks);
7128782Sgblack@eecs.umich.edu    tgt->f_bfree = TheISA::htog(host->f_bfree);
7138782Sgblack@eecs.umich.edu    tgt->f_bavail = TheISA::htog(host->f_bavail);
7148806Sgblack@eecs.umich.edu    tgt->f_files = TheISA::htog(host->f_files);
7158806Sgblack@eecs.umich.edu    tgt->f_ffree = TheISA::htog(host->f_ffree);
7168806Sgblack@eecs.umich.edu    memcpy(&tgt->f_fsid, &host->f_fsid, sizeof(host->f_fsid));
7178806Sgblack@eecs.umich.edu#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__)
7188806Sgblack@eecs.umich.edu    tgt->f_namelen = TheISA::htog(host->f_namemax);
7198806Sgblack@eecs.umich.edu    tgt->f_frsize = TheISA::htog(host->f_bsize);
7208806Sgblack@eecs.umich.edu#elif defined(__APPLE__)
7218806Sgblack@eecs.umich.edu    tgt->f_namelen = 0;
7228806Sgblack@eecs.umich.edu    tgt->f_frsize = 0;
7238806Sgblack@eecs.umich.edu#else
7248806Sgblack@eecs.umich.edu    tgt->f_namelen = TheISA::htog(host->f_namelen);
7257189Sgblack@eecs.umich.edu    tgt->f_frsize = TheISA::htog(host->f_frsize);
7268806Sgblack@eecs.umich.edu#endif
7278806Sgblack@eecs.umich.edu#if defined(__linux__)
7287189Sgblack@eecs.umich.edu    memcpy(&tgt->f_spare, &host->f_spare, sizeof(host->f_spare));
7297189Sgblack@eecs.umich.edu#else
7307189Sgblack@eecs.umich.edu    /*
73110037SARM gem5 Developers     * The fields are different sizes per OS. Don't bother with
73210037SARM gem5 Developers     * f_spare or f_reserved on non-Linux for now.
73310037SARM gem5 Developers     */
73410037SARM gem5 Developers    memset(&tgt->f_spare, 0, sizeof(tgt->f_spare));
73510037SARM gem5 Developers#endif
73610037SARM gem5 Developers
73710037SARM gem5 Developers    tgt.copyOut(mem);
73810037SARM gem5 Developers}
73910037SARM gem5 Developers
74010037SARM gem5 Developers/// Target ioctl() handler.  For the most part, programs call ioctl()
74110037SARM gem5 Developers/// only to find out if their stdout is a tty, to determine whether to
74210037SARM gem5 Developers/// do line or block buffering.  We always claim that output fds are
74310037SARM gem5 Developers/// not TTYs to provide repeatable results.
74410037SARM gem5 Developerstemplate <class OS>
74510037SARM gem5 DevelopersSyscallReturn
74610037SARM gem5 DevelopersioctlFunc(SyscallDesc *desc, int callnum, Process *p, ThreadContext *tc)
74710037SARM gem5 Developers{
74810037SARM gem5 Developers    int index = 0;
74910037SARM gem5 Developers    int tgt_fd = p->getSyscallArg(tc, index);
75010037SARM gem5 Developers    unsigned req = p->getSyscallArg(tc, index);
75110037SARM gem5 Developers
75210037SARM gem5 Developers    DPRINTF(SyscallVerbose, "ioctl(%d, 0x%x, ...)\n", tgt_fd, req);
75310037SARM gem5 Developers
75410037SARM gem5 Developers    if (OS::isTtyReq(req))
75510037SARM gem5 Developers        return -ENOTTY;
75610037SARM gem5 Developers
75710037SARM gem5 Developers    auto dfdp = std::dynamic_pointer_cast<DeviceFDEntry>((*p->fds)[tgt_fd]);
75810037SARM gem5 Developers    if (!dfdp)
75910037SARM gem5 Developers        return -EBADF;
76010037SARM gem5 Developers
76110037SARM gem5 Developers    /**
76210037SARM gem5 Developers     * If the driver is valid, issue the ioctl through it. Otherwise,
76310037SARM gem5 Developers     * there's an implicit assumption that the device is a TTY type and we
76410037SARM gem5 Developers     * return that we do not have a valid TTY.
76510037SARM gem5 Developers     */
76610037SARM gem5 Developers    EmulatedDriver *emul_driver = dfdp->getDriver();
76710037SARM gem5 Developers    if (emul_driver)
76810037SARM gem5 Developers        return emul_driver->ioctl(p, tc, req);
76910037SARM gem5 Developers
7707197Sgblack@eecs.umich.edu    /**
77110417Sandreas.hansson@arm.com     * For lack of a better return code, return ENOTTY. Ideally, we should
7727197Sgblack@eecs.umich.edu     * return something better here, but at least we issue the warning.
7738782Sgblack@eecs.umich.edu     */
7748782Sgblack@eecs.umich.edu    warn("Unsupported ioctl call (return ENOTTY): ioctl(%d, 0x%x, ...) @ \n",
7758806Sgblack@eecs.umich.edu         tgt_fd, req, tc->pcState());
7768806Sgblack@eecs.umich.edu    return -ENOTTY;
7777197Sgblack@eecs.umich.edu}
7788806Sgblack@eecs.umich.edu
7798806Sgblack@eecs.umich.edutemplate <class OS>
7808806Sgblack@eecs.umich.eduSyscallReturn
78110037SARM gem5 DevelopersopenImpl(SyscallDesc *desc, int callnum, Process *p, ThreadContext *tc,
78210037SARM gem5 Developers         bool isopenat)
78310037SARM gem5 Developers{
78410037SARM gem5 Developers    int index = 0;
78510037SARM gem5 Developers    int tgt_dirfd = -1;
78610037SARM gem5 Developers
7878806Sgblack@eecs.umich.edu    /**
7888806Sgblack@eecs.umich.edu     * If using the openat variant, read in the target directory file
7898806Sgblack@eecs.umich.edu     * descriptor from the simulated process.
7908806Sgblack@eecs.umich.edu     */
7918806Sgblack@eecs.umich.edu    if (isopenat)
7928806Sgblack@eecs.umich.edu        tgt_dirfd = p->getSyscallArg(tc, index);
7938806Sgblack@eecs.umich.edu
7947197Sgblack@eecs.umich.edu    /**
7957197Sgblack@eecs.umich.edu     * Retrieve the simulated process' memory proxy and then read in the path
79610037SARM gem5 Developers     * string from that memory space into the host's working memory space.
79710037SARM gem5 Developers     */
79810037SARM gem5 Developers    std::string path;
79910037SARM gem5 Developers    if (!tc->getMemProxy().tryReadString(path, p->getSyscallArg(tc, index)))
80010037SARM gem5 Developers        return -EFAULT;
80110037SARM gem5 Developers
80210037SARM gem5 Developers#ifdef __CYGWIN32__
80310037SARM gem5 Developers    int host_flags = O_BINARY;
80410037SARM gem5 Developers#else
80510037SARM gem5 Developers    int host_flags = 0;
80610037SARM gem5 Developers#endif
80710037SARM gem5 Developers    /**
80810037SARM gem5 Developers     * Translate target flags into host flags. Flags exist which are not
80910037SARM gem5 Developers     * ported between architectures which can cause check failures.
81010037SARM gem5 Developers     */
81110037SARM gem5 Developers    int tgt_flags = p->getSyscallArg(tc, index);
81210037SARM gem5 Developers    for (int i = 0; i < OS::NUM_OPEN_FLAGS; i++) {
81310037SARM gem5 Developers        if (tgt_flags & OS::openFlagTable[i].tgtFlag) {
81410037SARM gem5 Developers            tgt_flags &= ~OS::openFlagTable[i].tgtFlag;
81510037SARM gem5 Developers            host_flags |= OS::openFlagTable[i].hostFlag;
81610037SARM gem5 Developers        }
81710037SARM gem5 Developers    }
81810037SARM gem5 Developers    if (tgt_flags) {
81910037SARM gem5 Developers        warn("open%s: cannot decode flags 0x%x",
82010037SARM gem5 Developers             isopenat ? "at" : "", tgt_flags);
82110037SARM gem5 Developers    }
82210037SARM gem5 Developers#ifdef __CYGWIN32__
82310037SARM gem5 Developers    host_flags |= O_BINARY;
82410037SARM gem5 Developers#endif
82510037SARM gem5 Developers
82610037SARM gem5 Developers    int mode = p->getSyscallArg(tc, index);
82710037SARM gem5 Developers
82810037SARM gem5 Developers    /**
82910037SARM gem5 Developers     * If the simulated process called open or openat with AT_FDCWD specified,
83010037SARM gem5 Developers     * take the current working directory value which was passed into the
83110037SARM gem5 Developers     * process class as a Python parameter and append the current path to
83210037SARM gem5 Developers     * create a full path.
83310037SARM gem5 Developers     * Otherwise, openat with a valid target directory file descriptor has
83410037SARM gem5 Developers     * been called. If the path option, which was passed in as a parameter,
83510037SARM gem5 Developers     * is not absolute, retrieve the directory file descriptor's path and
83610037SARM gem5 Developers     * prepend it to the path passed in as a parameter.
83710037SARM gem5 Developers     * In every case, we should have a full path (which is relevant to the
83810037SARM gem5 Developers     * host) to work with after this block has been passed.
83910037SARM gem5 Developers     */
84010037SARM gem5 Developers    if (!isopenat || (isopenat && tgt_dirfd == OS::TGT_AT_FDCWD)) {
84110037SARM gem5 Developers        path = p->fullPath(path);
84210037SARM gem5 Developers    } else if (!startswith(path, "/")) {
84310037SARM gem5 Developers        std::shared_ptr<FDEntry> fdep = ((*p->fds)[tgt_dirfd]);
84410037SARM gem5 Developers        auto ffdp = std::dynamic_pointer_cast<FileFDEntry>(fdep);
84510037SARM gem5 Developers        if (!ffdp)
84610037SARM gem5 Developers            return -EBADF;
84711576SDylan.Johnson@ARM.com        path.insert(0, ffdp->getFileName() + "/");
84811576SDylan.Johnson@ARM.com    }
84911576SDylan.Johnson@ARM.com
85011576SDylan.Johnson@ARM.com    /**
85111576SDylan.Johnson@ARM.com     * Since this is an emulated environment, we create pseudo file
85211576SDylan.Johnson@ARM.com     * descriptors for device requests that have been registered with
85310037SARM gem5 Developers     * the process class through Python; this allows us to create a file
85410037SARM gem5 Developers     * descriptor for subsequent ioctl or mmap calls.
85510037SARM gem5 Developers     */
85610037SARM gem5 Developers    if (startswith(path, "/dev/")) {
85710037SARM gem5 Developers        std::string filename = path.substr(strlen("/dev/"));
85810037SARM gem5 Developers        EmulatedDriver *drv = p->findDriver(filename);
85910037SARM gem5 Developers        if (drv) {
86010037SARM gem5 Developers            DPRINTF_SYSCALL(Verbose, "open%s: passing call to "
86110037SARM gem5 Developers                            "driver open with path[%s]\n",
86210037SARM gem5 Developers                            isopenat ? "at" : "", path.c_str());
86310037SARM gem5 Developers            return drv->open(p, tc, mode, host_flags);
86410037SARM gem5 Developers        }
86510037SARM gem5 Developers        /**
86610037SARM gem5 Developers         * Fall through here for pass through to host devices, such
86710037SARM gem5 Developers         * as /dev/zero
86810037SARM gem5 Developers         */
86910037SARM gem5 Developers    }
87010037SARM gem5 Developers
87110037SARM gem5 Developers    /**
87210037SARM gem5 Developers     * Some special paths and files cannot be called on the host and need
87310037SARM gem5 Developers     * to be handled as special cases inside the simulator.
87410037SARM gem5 Developers     * If the full path that was created above does not match any of the
87510037SARM gem5 Developers     * special cases, pass it through to the open call on the host to let
87610037SARM gem5 Developers     * the host open the file on our behalf.
87710037SARM gem5 Developers     * If the host cannot open the file, return the host's error code back
87810037SARM gem5 Developers     * through the system call to the simulated process.
87910037SARM gem5 Developers     */
88010037SARM gem5 Developers    int sim_fd = -1;
88110037SARM gem5 Developers    std::vector<std::string> special_paths =
88210037SARM gem5 Developers            { "/proc/", "/system/", "/sys/", "/platform/", "/etc/passwd" };
88310037SARM gem5 Developers    for (auto entry : special_paths) {
88410037SARM gem5 Developers        if (startswith(path, entry))
88510037SARM gem5 Developers            sim_fd = OS::openSpecialFile(path, p, tc);
88610037SARM gem5 Developers    }
88710037SARM gem5 Developers    if (sim_fd == -1) {
88810037SARM gem5 Developers        sim_fd = open(path.c_str(), host_flags, mode);
88910037SARM gem5 Developers    }
89010037SARM gem5 Developers    if (sim_fd == -1) {
89110037SARM gem5 Developers        int local = -errno;
89210037SARM gem5 Developers        DPRINTF_SYSCALL(Verbose, "open%s: failed -> path:%s\n",
89310037SARM gem5 Developers                        isopenat ? "at" : "", path.c_str());
89410417Sandreas.hansson@arm.com        return local;
89510037SARM gem5 Developers    }
89610037SARM gem5 Developers
89710037SARM gem5 Developers    /**
89810037SARM gem5 Developers     * The file was opened successfully and needs to be recorded in the
89910037SARM gem5 Developers     * process' file descriptor array so that it can be retrieved later.
90010037SARM gem5 Developers     * The target file descriptor that is chosen will be the lowest unused
90110037SARM gem5 Developers     * file descriptor.
90210037SARM gem5 Developers     * Return the indirect target file descriptor back to the simulated
90310037SARM gem5 Developers     * process to act as a handle for the opened file.
90410037SARM gem5 Developers     */
90510037SARM gem5 Developers    auto ffdp = std::make_shared<FileFDEntry>(sim_fd, host_flags, path, 0);
90610037SARM gem5 Developers    int tgt_fd = p->fds->allocFD(ffdp);
90710037SARM gem5 Developers    DPRINTF_SYSCALL(Verbose, "open%s: sim_fd[%d], target_fd[%d] -> path:%s\n",
90810037SARM gem5 Developers                    isopenat ? "at" : "", sim_fd, tgt_fd, path.c_str());
90910037SARM gem5 Developers    return tgt_fd;
91010037SARM gem5 Developers}
91110037SARM gem5 Developers
91210037SARM gem5 Developers/// Target open() handler.
91310037SARM gem5 Developerstemplate <class OS>
91410037SARM gem5 DevelopersSyscallReturn
91510037SARM gem5 DevelopersopenFunc(SyscallDesc *desc, int callnum, Process *process,
91610037SARM gem5 Developers         ThreadContext *tc)
91710037SARM gem5 Developers{
91810037SARM gem5 Developers    return openImpl<OS>(desc, callnum, process, tc, false);
91910037SARM gem5 Developers}
92010037SARM gem5 Developers
9217362Sgblack@eecs.umich.edu/// Target openat() handler.
9227362Sgblack@eecs.umich.edutemplate <class OS>
92310417Sandreas.hansson@arm.comSyscallReturn
9247362Sgblack@eecs.umich.eduopenatFunc(SyscallDesc *desc, int callnum, Process *process,
92510037SARM gem5 Developers           ThreadContext *tc)
92610037SARM gem5 Developers{
92710037SARM gem5 Developers    return openImpl<OS>(desc, callnum, process, tc, true);
92810037SARM gem5 Developers}
92910037SARM gem5 Developers
93010037SARM gem5 Developers/// Target unlinkat() handler.
93110037SARM gem5 Developerstemplate <class OS>
93210037SARM gem5 DevelopersSyscallReturn
93310037SARM gem5 DevelopersunlinkatFunc(SyscallDesc *desc, int callnum, Process *process,
93410037SARM gem5 Developers             ThreadContext *tc)
93510037SARM gem5 Developers{
93610037SARM gem5 Developers    int index = 0;
93710037SARM gem5 Developers    int dirfd = process->getSyscallArg(tc, index);
93810037SARM gem5 Developers    if (dirfd != OS::TGT_AT_FDCWD)
93910037SARM gem5 Developers        warn("unlinkat: first argument not AT_FDCWD; unlikely to work");
94010037SARM gem5 Developers
94110037SARM gem5 Developers    return unlinkHelper(desc, callnum, process, tc, 1);
94210037SARM gem5 Developers}
94310037SARM gem5 Developers
94410037SARM gem5 Developers/// Target facessat() handler
94510037SARM gem5 Developerstemplate <class OS>
94610037SARM gem5 DevelopersSyscallReturn
94710037SARM gem5 DevelopersfaccessatFunc(SyscallDesc *desc, int callnum, Process *process,
94811150Smitch.hayenga@arm.com              ThreadContext *tc)
94910037SARM gem5 Developers{
95010037SARM gem5 Developers    int index = 0;
95110037SARM gem5 Developers    int dirfd = process->getSyscallArg(tc, index);
95210037SARM gem5 Developers    if (dirfd != OS::TGT_AT_FDCWD)
95310037SARM gem5 Developers        warn("faccessat: first argument not AT_FDCWD; unlikely to work");
95410037SARM gem5 Developers    return accessFunc(desc, callnum, process, tc, 1);
95510037SARM gem5 Developers}
9568205SAli.Saidi@ARM.com
95710037SARM gem5 Developers/// Target readlinkat() handler
95811496Sandreas.sandberg@arm.comtemplate <class OS>
95910037SARM gem5 DevelopersSyscallReturn
96010037SARM gem5 DevelopersreadlinkatFunc(SyscallDesc *desc, int callnum, Process *process,
96110037SARM gem5 Developers               ThreadContext *tc)
96210037SARM gem5 Developers{
96310037SARM gem5 Developers    int index = 0;
96410037SARM gem5 Developers    int dirfd = process->getSyscallArg(tc, index);
96510037SARM gem5 Developers    if (dirfd != OS::TGT_AT_FDCWD)
96610037SARM gem5 Developers        warn("openat: first argument not AT_FDCWD; unlikely to work");
96710037SARM gem5 Developers    return readlinkFunc(desc, callnum, process, tc, 1);
96810037SARM gem5 Developers}
96910037SARM gem5 Developers
97010037SARM gem5 Developers/// Target renameat() handler.
97110037SARM gem5 Developerstemplate <class OS>
97210037SARM gem5 DevelopersSyscallReturn
97311585SDylan.Johnson@ARM.comrenameatFunc(SyscallDesc *desc, int callnum, Process *process,
97411585SDylan.Johnson@ARM.com             ThreadContext *tc)
97511585SDylan.Johnson@ARM.com{
97611585SDylan.Johnson@ARM.com    int index = 0;
97711585SDylan.Johnson@ARM.com
97811585SDylan.Johnson@ARM.com    int olddirfd = process->getSyscallArg(tc, index);
97911585SDylan.Johnson@ARM.com    if (olddirfd != OS::TGT_AT_FDCWD)
98011585SDylan.Johnson@ARM.com        warn("renameat: first argument not AT_FDCWD; unlikely to work");
98111585SDylan.Johnson@ARM.com
98211585SDylan.Johnson@ARM.com    std::string old_name;
98311585SDylan.Johnson@ARM.com
98410037SARM gem5 Developers    if (!tc->getMemProxy().tryReadString(old_name,
98510037SARM gem5 Developers                                         process->getSyscallArg(tc, index)))
98610037SARM gem5 Developers        return -EFAULT;
98710037SARM gem5 Developers
98810037SARM gem5 Developers    int newdirfd = process->getSyscallArg(tc, index);
98910037SARM gem5 Developers    if (newdirfd != OS::TGT_AT_FDCWD)
99010037SARM gem5 Developers        warn("renameat: third argument not AT_FDCWD; unlikely to work");
9917362Sgblack@eecs.umich.edu
9928314Sgeoffrey.blake@arm.com    std::string new_name;
99310037SARM gem5 Developers
99410037SARM gem5 Developers    if (!tc->getMemProxy().tryReadString(new_name,
99510037SARM gem5 Developers                                         process->getSyscallArg(tc, index)))
99610037SARM gem5 Developers        return -EFAULT;
99710037SARM gem5 Developers
99810037SARM gem5 Developers    // Adjust path for current working directory
99910037SARM gem5 Developers    old_name = process->fullPath(old_name);
100010037SARM gem5 Developers    new_name = process->fullPath(new_name);
100110037SARM gem5 Developers
100210037SARM gem5 Developers    int result = rename(old_name.c_str(), new_name.c_str());
100310037SARM gem5 Developers    return (result == -1) ? -errno : result;
100410037SARM gem5 Developers}
100510037SARM gem5 Developers
100610037SARM gem5 Developers/// Target sysinfo() handler.
100710037SARM gem5 Developerstemplate <class OS>
100810037SARM gem5 DevelopersSyscallReturn
100910037SARM gem5 DeveloperssysinfoFunc(SyscallDesc *desc, int callnum, Process *process,
101010037SARM gem5 Developers            ThreadContext *tc)
101110037SARM gem5 Developers{
101210037SARM gem5 Developers
101310037SARM gem5 Developers    int index = 0;
101410037SARM gem5 Developers    TypedBufferArg<typename OS::tgt_sysinfo>
101510037SARM gem5 Developers        sysinfo(process->getSyscallArg(tc, index));
101610037SARM gem5 Developers
101710037SARM gem5 Developers    sysinfo->uptime = seconds_since_epoch;
101810037SARM gem5 Developers    sysinfo->totalram = process->system->memSize();
101910037SARM gem5 Developers    sysinfo->mem_unit = 1;
102010037SARM gem5 Developers
102110037SARM gem5 Developers    sysinfo.copyOut(tc->getMemProxy());
102210037SARM gem5 Developers
102310037SARM gem5 Developers    return 0;
102410037SARM gem5 Developers}
102510037SARM gem5 Developers
102610037SARM gem5 Developers/// Target chmod() handler.
102710037SARM gem5 Developerstemplate <class OS>
102810037SARM gem5 DevelopersSyscallReturn
102910037SARM gem5 DeveloperschmodFunc(SyscallDesc *desc, int callnum, Process *process,
103010037SARM gem5 Developers          ThreadContext *tc)
103110037SARM gem5 Developers{
103210037SARM gem5 Developers    std::string path;
103310037SARM gem5 Developers
103410037SARM gem5 Developers    int index = 0;
103510037SARM gem5 Developers    if (!tc->getMemProxy().tryReadString(path,
103610037SARM gem5 Developers                process->getSyscallArg(tc, index))) {
103710037SARM gem5 Developers        return -EFAULT;
103810037SARM gem5 Developers    }
103910037SARM gem5 Developers
104010037SARM gem5 Developers    uint32_t mode = process->getSyscallArg(tc, index);
104110037SARM gem5 Developers    mode_t hostMode = 0;
104210037SARM gem5 Developers
104310037SARM gem5 Developers    // XXX translate mode flags via OS::something???
104410037SARM gem5 Developers    hostMode = mode;
104510037SARM gem5 Developers
104610037SARM gem5 Developers    // Adjust path for current working directory
104710037SARM gem5 Developers    path = process->fullPath(path);
104810037SARM gem5 Developers
104910037SARM gem5 Developers    // do the chmod
105010037SARM gem5 Developers    int result = chmod(path.c_str(), hostMode);
105110037SARM gem5 Developers    if (result < 0)
105210037SARM gem5 Developers        return -errno;
105310037SARM gem5 Developers
105410037SARM gem5 Developers    return 0;
105510037SARM gem5 Developers}
105610037SARM gem5 Developers
105710037SARM gem5 Developerstemplate <class OS>
105810037SARM gem5 DevelopersSyscallReturn
105910037SARM gem5 DeveloperspollFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
106010037SARM gem5 Developers{
106110037SARM gem5 Developers    int index = 0;
106210037SARM gem5 Developers    Addr fdsPtr = p->getSyscallArg(tc, index);
106310037SARM gem5 Developers    int nfds = p->getSyscallArg(tc, index);
106410037SARM gem5 Developers    int tmout = p->getSyscallArg(tc, index);
106510037SARM gem5 Developers
106610037SARM gem5 Developers    BufferArg fdsBuf(fdsPtr, sizeof(struct pollfd) * nfds);
106710037SARM gem5 Developers    fdsBuf.copyIn(tc->getMemProxy());
106810037SARM gem5 Developers
106910037SARM gem5 Developers    /**
107010037SARM gem5 Developers     * Record the target file descriptors in a local variable. We need to
107110037SARM gem5 Developers     * replace them with host file descriptors but we need a temporary copy
107210037SARM gem5 Developers     * for later. Afterwards, replace each target file descriptor in the
107310037SARM gem5 Developers     * poll_fd array with its host_fd.
107410037SARM gem5 Developers     */
107510037SARM gem5 Developers    int temp_tgt_fds[nfds];
107610037SARM gem5 Developers    for (index = 0; index < nfds; index++) {
107710037SARM gem5 Developers        temp_tgt_fds[index] = ((struct pollfd *)fdsBuf.bufferPtr())[index].fd;
107810037SARM gem5 Developers        auto tgt_fd = temp_tgt_fds[index];
107910037SARM gem5 Developers        auto hbfdp = std::dynamic_pointer_cast<HBFDEntry>((*p->fds)[tgt_fd]);
108010037SARM gem5 Developers        if (!hbfdp)
108110037SARM gem5 Developers            return -EBADF;
108210037SARM gem5 Developers        auto host_fd = hbfdp->getSimFD();
108310037SARM gem5 Developers        ((struct pollfd *)fdsBuf.bufferPtr())[index].fd = host_fd;
108410037SARM gem5 Developers    }
108510037SARM gem5 Developers
108610037SARM gem5 Developers    /**
108710037SARM gem5 Developers     * We cannot allow an infinite poll to occur or it will inevitably cause
108810037SARM gem5 Developers     * a deadlock in the gem5 simulator with clone. We must pass in tmout with
108910037SARM gem5 Developers     * a non-negative value, however it also makes no sense to poll on the
109010037SARM gem5 Developers     * underlying host for any other time than tmout a zero timeout.
109110037SARM gem5 Developers     */
109210037SARM gem5 Developers    int status;
109310037SARM gem5 Developers    if (tmout < 0) {
109410037SARM gem5 Developers        status = poll((struct pollfd *)fdsBuf.bufferPtr(), nfds, 0);
109510037SARM gem5 Developers        if (status == 0) {
109610037SARM gem5 Developers            /**
109710037SARM gem5 Developers             * If blocking indefinitely, check the signal list to see if a
109810037SARM gem5 Developers             * signal would break the poll out of the retry cycle and try
109910037SARM gem5 Developers             * to return the signal interrupt instead.
110010037SARM gem5 Developers             */
110110037SARM gem5 Developers            System *sysh = tc->getSystemPtr();
110210037SARM gem5 Developers            std::list<BasicSignal>::iterator it;
110310037SARM gem5 Developers            for (it=sysh->signalList.begin(); it!=sysh->signalList.end(); it++)
110410037SARM gem5 Developers                if (it->receiver == p)
110510037SARM gem5 Developers                    return -EINTR;
110610037SARM gem5 Developers            return SyscallReturn::retry();
110710037SARM gem5 Developers        }
110810037SARM gem5 Developers    } else
110910037SARM gem5 Developers        status = poll((struct pollfd *)fdsBuf.bufferPtr(), nfds, 0);
111010037SARM gem5 Developers
111110037SARM gem5 Developers    if (status == -1)
111210037SARM gem5 Developers        return -errno;
111310037SARM gem5 Developers
111410037SARM gem5 Developers    /**
111510037SARM gem5 Developers     * Replace each host_fd in the returned poll_fd array with its original
111610037SARM gem5 Developers     * target file descriptor.
111710037SARM gem5 Developers     */
111810037SARM gem5 Developers    for (index = 0; index < nfds; index++) {
111910037SARM gem5 Developers        auto tgt_fd = temp_tgt_fds[index];
112010037SARM gem5 Developers        ((struct pollfd *)fdsBuf.bufferPtr())[index].fd = tgt_fd;
112110037SARM gem5 Developers    }
112210037SARM gem5 Developers
112310037SARM gem5 Developers    /**
112410037SARM gem5 Developers     * Copy out the pollfd struct because the host may have updated fields
112510037SARM gem5 Developers     * in the structure.
112610037SARM gem5 Developers     */
112710037SARM gem5 Developers    fdsBuf.copyOut(tc->getMemProxy());
112810037SARM gem5 Developers
112910037SARM gem5 Developers    return status;
113011581SDylan.Johnson@ARM.com}
113110037SARM gem5 Developers
113210037SARM gem5 Developers/// Target fchmod() handler.
113310037SARM gem5 Developerstemplate <class OS>
113410037SARM gem5 DevelopersSyscallReturn
113510037SARM gem5 DevelopersfchmodFunc(SyscallDesc *desc, int callnum, Process *p, ThreadContext *tc)
113610037SARM gem5 Developers{
113710037SARM gem5 Developers    int index = 0;
113810037SARM gem5 Developers    int tgt_fd = p->getSyscallArg(tc, index);
113910037SARM gem5 Developers    uint32_t mode = p->getSyscallArg(tc, index);
114010367SAndrew.Bardsley@arm.com
114110367SAndrew.Bardsley@arm.com    auto ffdp = std::dynamic_pointer_cast<FileFDEntry>((*p->fds)[tgt_fd]);
114210037SARM gem5 Developers    if (!ffdp)
114310037SARM gem5 Developers        return -EBADF;
114410037SARM gem5 Developers    int sim_fd = ffdp->getSimFD();
114510037SARM gem5 Developers
114610037SARM gem5 Developers    mode_t hostMode = mode;
114710037SARM gem5 Developers
114810037SARM gem5 Developers    int result = fchmod(sim_fd, hostMode);
114910037SARM gem5 Developers
115010037SARM gem5 Developers    return (result < 0) ? -errno : 0;
115110037SARM gem5 Developers}
115210037SARM gem5 Developers
115310037SARM gem5 Developers/// Target mremap() handler.
115410037SARM gem5 Developerstemplate <class OS>
115510037SARM gem5 DevelopersSyscallReturn
115610037SARM gem5 DevelopersmremapFunc(SyscallDesc *desc, int callnum, Process *process, ThreadContext *tc)
115710037SARM gem5 Developers{
115810037SARM gem5 Developers    int index = 0;
115910037SARM gem5 Developers    Addr start = process->getSyscallArg(tc, index);
116010037SARM gem5 Developers    uint64_t old_length = process->getSyscallArg(tc, index);
116110037SARM gem5 Developers    uint64_t new_length = process->getSyscallArg(tc, index);
116210037SARM gem5 Developers    uint64_t flags = process->getSyscallArg(tc, index);
116310037SARM gem5 Developers    uint64_t provided_address = 0;
116410037SARM gem5 Developers    bool use_provided_address = flags & OS::TGT_MREMAP_FIXED;
116510037SARM gem5 Developers
116610037SARM gem5 Developers    if (use_provided_address)
116710037SARM gem5 Developers        provided_address = process->getSyscallArg(tc, index);
116810037SARM gem5 Developers
116910037SARM gem5 Developers    if ((start % TheISA::PageBytes != 0) ||
117010037SARM gem5 Developers        (provided_address % TheISA::PageBytes != 0)) {
117110037SARM gem5 Developers        warn("mremap failing: arguments not page aligned");
117210037SARM gem5 Developers        return -EINVAL;
117310037SARM gem5 Developers    }
117410037SARM gem5 Developers
117510037SARM gem5 Developers    new_length = roundUp(new_length, TheISA::PageBytes);
117610037SARM gem5 Developers
117710037SARM gem5 Developers    if (new_length > old_length) {
117810037SARM gem5 Developers        std::shared_ptr<MemState> mem_state = process->memState;
117910037SARM gem5 Developers        Addr mmap_end = mem_state->getMmapEnd();
118010037SARM gem5 Developers
118110037SARM gem5 Developers        if ((start + old_length) == mmap_end &&
118210037SARM gem5 Developers            (!use_provided_address || provided_address == start)) {
118310037SARM gem5 Developers            // This case cannot occur when growing downward, as
118410037SARM gem5 Developers            // start is greater than or equal to mmap_end.
118510037SARM gem5 Developers            uint64_t diff = new_length - old_length;
118610037SARM gem5 Developers            process->allocateMem(mmap_end, diff);
118710037SARM gem5 Developers            mem_state->setMmapEnd(mmap_end + diff);
118810037SARM gem5 Developers            return start;
118910037SARM gem5 Developers        } else {
119010037SARM gem5 Developers            if (!use_provided_address && !(flags & OS::TGT_MREMAP_MAYMOVE)) {
119110037SARM gem5 Developers                warn("can't remap here and MREMAP_MAYMOVE flag not set\n");
119210037SARM gem5 Developers                return -ENOMEM;
119310037SARM gem5 Developers            } else {
119410037SARM gem5 Developers                uint64_t new_start = provided_address;
119510037SARM gem5 Developers                if (!use_provided_address) {
119611581SDylan.Johnson@ARM.com                    new_start = process->mmapGrowsDown() ?
119710037SARM gem5 Developers                                mmap_end - new_length : mmap_end;
119810037SARM gem5 Developers                    mmap_end = process->mmapGrowsDown() ?
119910037SARM gem5 Developers                               new_start : mmap_end + new_length;
120010037SARM gem5 Developers                    mem_state->setMmapEnd(mmap_end);
120110037SARM gem5 Developers                }
120210037SARM gem5 Developers
120310037SARM gem5 Developers                process->pTable->remap(start, old_length, new_start);
120410037SARM gem5 Developers                warn("mremapping to new vaddr %08p-%08p, adding %d\n",
120510037SARM gem5 Developers                     new_start, new_start + new_length,
120610037SARM gem5 Developers                     new_length - old_length);
120710037SARM gem5 Developers                // add on the remaining unallocated pages
120810037SARM gem5 Developers                process->allocateMem(new_start + old_length,
120910037SARM gem5 Developers                                     new_length - old_length,
121010037SARM gem5 Developers                                     use_provided_address /* clobber */);
121110037SARM gem5 Developers                if (use_provided_address &&
121210037SARM gem5 Developers                    ((new_start + new_length > mem_state->getMmapEnd() &&
121310037SARM gem5 Developers                      !process->mmapGrowsDown()) ||
121410037SARM gem5 Developers                    (new_start < mem_state->getMmapEnd() &&
121510037SARM gem5 Developers                      process->mmapGrowsDown()))) {
121610037SARM gem5 Developers                    // something fishy going on here, at least notify the user
121710037SARM gem5 Developers                    // @todo: increase mmap_end?
121810037SARM gem5 Developers                    warn("mmap region limit exceeded with MREMAP_FIXED\n");
121910037SARM gem5 Developers                }
122010037SARM gem5 Developers                warn("returning %08p as start\n", new_start);
122110037SARM gem5 Developers                return new_start;
122210037SARM gem5 Developers            }
122310037SARM gem5 Developers        }
122410037SARM gem5 Developers    } else {
122510037SARM gem5 Developers        if (use_provided_address && provided_address != start)
122610037SARM gem5 Developers            process->pTable->remap(start, new_length, provided_address);
122710037SARM gem5 Developers        process->pTable->unmap(start + new_length, old_length - new_length);
122810037SARM gem5 Developers        return use_provided_address ? provided_address : start;
122910037SARM gem5 Developers    }
123010037SARM gem5 Developers}
123110037SARM gem5 Developers
123210037SARM gem5 Developers/// Target stat() handler.
123310037SARM gem5 Developerstemplate <class OS>
123410037SARM gem5 DevelopersSyscallReturn
123510037SARM gem5 DevelopersstatFunc(SyscallDesc *desc, int callnum, Process *process,
123610037SARM gem5 Developers         ThreadContext *tc)
123710037SARM gem5 Developers{
123810037SARM gem5 Developers    std::string path;
123910037SARM gem5 Developers
124010037SARM gem5 Developers    int index = 0;
124110037SARM gem5 Developers    if (!tc->getMemProxy().tryReadString(path,
124210037SARM gem5 Developers                process->getSyscallArg(tc, index))) {
124310037SARM gem5 Developers        return -EFAULT;
124410037SARM gem5 Developers    }
124510037SARM gem5 Developers    Addr bufPtr = process->getSyscallArg(tc, index);
124610037SARM gem5 Developers
124710037SARM gem5 Developers    // Adjust path for current working directory
124810037SARM gem5 Developers    path = process->fullPath(path);
124910037SARM gem5 Developers
125010037SARM gem5 Developers    struct stat hostBuf;
125110037SARM gem5 Developers    int result = stat(path.c_str(), &hostBuf);
125210037SARM gem5 Developers
125310037SARM gem5 Developers    if (result < 0)
125410037SARM gem5 Developers        return -errno;
125510037SARM gem5 Developers
125610037SARM gem5 Developers    copyOutStatBuf<OS>(tc->getMemProxy(), bufPtr, &hostBuf);
125710417Sandreas.hansson@arm.com
125810037SARM gem5 Developers    return 0;
125910037SARM gem5 Developers}
126010037SARM gem5 Developers
126110037SARM gem5 Developers
126210037SARM gem5 Developers/// Target stat64() handler.
126310037SARM gem5 Developerstemplate <class OS>
126410037SARM gem5 DevelopersSyscallReturn
126510037SARM gem5 Developersstat64Func(SyscallDesc *desc, int callnum, Process *process,
126610037SARM gem5 Developers           ThreadContext *tc)
126710037SARM gem5 Developers{
126810037SARM gem5 Developers    std::string path;
126910037SARM gem5 Developers
127010037SARM gem5 Developers    int index = 0;
127110037SARM gem5 Developers    if (!tc->getMemProxy().tryReadString(path,
127210037SARM gem5 Developers                process->getSyscallArg(tc, index)))
127310037SARM gem5 Developers        return -EFAULT;
127410037SARM gem5 Developers    Addr bufPtr = process->getSyscallArg(tc, index);
127510037SARM gem5 Developers
127610037SARM gem5 Developers    // Adjust path for current working directory
127710037SARM gem5 Developers    path = process->fullPath(path);
127810037SARM gem5 Developers
127910037SARM gem5 Developers#if NO_STAT64
128010037SARM gem5 Developers    struct stat  hostBuf;
128110037SARM gem5 Developers    int result = stat(path.c_str(), &hostBuf);
128210037SARM gem5 Developers#else
128310037SARM gem5 Developers    struct stat64 hostBuf;
128410037SARM gem5 Developers    int result = stat64(path.c_str(), &hostBuf);
128510037SARM gem5 Developers#endif
128611581SDylan.Johnson@ARM.com
128710037SARM gem5 Developers    if (result < 0)
128810037SARM gem5 Developers        return -errno;
128910037SARM gem5 Developers
129010037SARM gem5 Developers    copyOutStat64Buf<OS>(tc->getMemProxy(), bufPtr, &hostBuf);
129110037SARM gem5 Developers
129210037SARM gem5 Developers    return 0;
129310037SARM gem5 Developers}
129410037SARM gem5 Developers
129510037SARM gem5 Developers
129610037SARM gem5 Developers/// Target fstatat64() handler.
129710037SARM gem5 Developerstemplate <class OS>
129810037SARM gem5 DevelopersSyscallReturn
129910037SARM gem5 Developersfstatat64Func(SyscallDesc *desc, int callnum, Process *process,
130010037SARM gem5 Developers              ThreadContext *tc)
130110037SARM gem5 Developers{
130210037SARM gem5 Developers    int index = 0;
130310037SARM gem5 Developers    int dirfd = process->getSyscallArg(tc, index);
130410037SARM gem5 Developers    if (dirfd != OS::TGT_AT_FDCWD)
130510037SARM gem5 Developers        warn("fstatat64: first argument not AT_FDCWD; unlikely to work");
130610037SARM gem5 Developers
130710037SARM gem5 Developers    std::string path;
130810037SARM gem5 Developers    if (!tc->getMemProxy().tryReadString(path,
130910037SARM gem5 Developers                process->getSyscallArg(tc, index)))
131010037SARM gem5 Developers        return -EFAULT;
131110037SARM gem5 Developers    Addr bufPtr = process->getSyscallArg(tc, index);
131210037SARM gem5 Developers
131310037SARM gem5 Developers    // Adjust path for current working directory
131410037SARM gem5 Developers    path = process->fullPath(path);
131510037SARM gem5 Developers
131610037SARM gem5 Developers#if NO_STAT64
131710037SARM gem5 Developers    struct stat  hostBuf;
131810037SARM gem5 Developers    int result = stat(path.c_str(), &hostBuf);
131910037SARM gem5 Developers#else
132010037SARM gem5 Developers    struct stat64 hostBuf;
132110037SARM gem5 Developers    int result = stat64(path.c_str(), &hostBuf);
132210037SARM gem5 Developers#endif
132310037SARM gem5 Developers
132410037SARM gem5 Developers    if (result < 0)
132511581SDylan.Johnson@ARM.com        return -errno;
132610037SARM gem5 Developers
132710037SARM gem5 Developers    copyOutStat64Buf<OS>(tc->getMemProxy(), bufPtr, &hostBuf);
132810037SARM gem5 Developers
132910037SARM gem5 Developers    return 0;
133010037SARM gem5 Developers}
133110037SARM gem5 Developers
133210037SARM gem5 Developers
133310037SARM gem5 Developers/// Target fstat64() handler.
133410037SARM gem5 Developerstemplate <class OS>
133510037SARM gem5 DevelopersSyscallReturn
133610037SARM gem5 Developersfstat64Func(SyscallDesc *desc, int callnum, Process *p, ThreadContext *tc)
133710037SARM gem5 Developers{
133810037SARM gem5 Developers    int index = 0;
133910037SARM gem5 Developers    int tgt_fd = p->getSyscallArg(tc, index);
134010037SARM gem5 Developers    Addr bufPtr = p->getSyscallArg(tc, index);
134110037SARM gem5 Developers
134210037SARM gem5 Developers    auto ffdp = std::dynamic_pointer_cast<FileFDEntry>((*p->fds)[tgt_fd]);
134310037SARM gem5 Developers    if (!ffdp)
134410037SARM gem5 Developers        return -EBADF;
134510037SARM gem5 Developers    int sim_fd = ffdp->getSimFD();
134610037SARM gem5 Developers
134710037SARM gem5 Developers#if NO_STAT64
134810037SARM gem5 Developers    struct stat  hostBuf;
134910037SARM gem5 Developers    int result = fstat(sim_fd, &hostBuf);
135010037SARM gem5 Developers#else
135110037SARM gem5 Developers    struct stat64  hostBuf;
135210037SARM gem5 Developers    int result = fstat64(sim_fd, &hostBuf);
135310037SARM gem5 Developers#endif
135410037SARM gem5 Developers
135510037SARM gem5 Developers    if (result < 0)
135610417Sandreas.hansson@arm.com        return -errno;
135710037SARM gem5 Developers
135810037SARM gem5 Developers    copyOutStat64Buf<OS>(tc->getMemProxy(), bufPtr, &hostBuf, (sim_fd == 1));
135910037SARM gem5 Developers
136010037SARM gem5 Developers    return 0;
136110037SARM gem5 Developers}
136210037SARM gem5 Developers
136310037SARM gem5 Developers
136410037SARM gem5 Developers/// Target lstat() handler.
136510037SARM gem5 Developerstemplate <class OS>
136610037SARM gem5 DevelopersSyscallReturn
136710037SARM gem5 DeveloperslstatFunc(SyscallDesc *desc, int callnum, Process *process,
136810037SARM gem5 Developers          ThreadContext *tc)
136910037SARM gem5 Developers{
137010037SARM gem5 Developers    std::string path;
137110417Sandreas.hansson@arm.com
137210037SARM gem5 Developers    int index = 0;
137311150Smitch.hayenga@arm.com    if (!tc->getMemProxy().tryReadString(path,
137410037SARM gem5 Developers                process->getSyscallArg(tc, index))) {
137510037SARM gem5 Developers        return -EFAULT;
137610037SARM gem5 Developers    }
137710037SARM gem5 Developers    Addr bufPtr = process->getSyscallArg(tc, index);
137810037SARM gem5 Developers
137910037SARM gem5 Developers    // Adjust path for current working directory
138010037SARM gem5 Developers    path = process->fullPath(path);
138110037SARM gem5 Developers
138210037SARM gem5 Developers    struct stat hostBuf;
138310037SARM gem5 Developers    int result = lstat(path.c_str(), &hostBuf);
138410037SARM gem5 Developers
138510037SARM gem5 Developers    if (result < 0)
138610037SARM gem5 Developers        return -errno;
138710037SARM gem5 Developers
138810037SARM gem5 Developers    copyOutStatBuf<OS>(tc->getMemProxy(), bufPtr, &hostBuf);
138910037SARM gem5 Developers
139010037SARM gem5 Developers    return 0;
139110037SARM gem5 Developers}
139210037SARM gem5 Developers
139310037SARM gem5 Developers/// Target lstat64() handler.
139410037SARM gem5 Developerstemplate <class OS>
139511581SDylan.Johnson@ARM.comSyscallReturn
139611581SDylan.Johnson@ARM.comlstat64Func(SyscallDesc *desc, int callnum, Process *process,
139710037SARM gem5 Developers            ThreadContext *tc)
13987362Sgblack@eecs.umich.edu{
13997362Sgblack@eecs.umich.edu    std::string path;
14007652Sminkyu.jeong@arm.com
140110417Sandreas.hansson@arm.com    int index = 0;
14027652Sminkyu.jeong@arm.com    if (!tc->getMemProxy().tryReadString(path,
14037652Sminkyu.jeong@arm.com                process->getSyscallArg(tc, index))) {
14047652Sminkyu.jeong@arm.com        return -EFAULT;
14057652Sminkyu.jeong@arm.com    }
14067652Sminkyu.jeong@arm.com    Addr bufPtr = process->getSyscallArg(tc, index);
14077720Sgblack@eecs.umich.edu
14087720Sgblack@eecs.umich.edu    // Adjust path for current working directory
14097720Sgblack@eecs.umich.edu    path = process->fullPath(path);
14107720Sgblack@eecs.umich.edu
14117652Sminkyu.jeong@arm.com#if NO_STAT64
14127652Sminkyu.jeong@arm.com    struct stat hostBuf;
14138518Sgeoffrey.blake@arm.com    int result = lstat(path.c_str(), &hostBuf);
141410417Sandreas.hansson@arm.com#else
14158518Sgeoffrey.blake@arm.com    struct stat64 hostBuf;
14168806Sgblack@eecs.umich.edu    int result = lstat64(path.c_str(), &hostBuf);
14178806Sgblack@eecs.umich.edu#endif
14188806Sgblack@eecs.umich.edu
14198806Sgblack@eecs.umich.edu    if (result < 0)
14208806Sgblack@eecs.umich.edu        return -errno;
14218806Sgblack@eecs.umich.edu
14228806Sgblack@eecs.umich.edu    copyOutStat64Buf<OS>(tc->getMemProxy(), bufPtr, &hostBuf);
142311150Smitch.hayenga@arm.com
14248518Sgeoffrey.blake@arm.com    return 0;
14258518Sgeoffrey.blake@arm.com}
142610037SARM gem5 Developers
142710037SARM gem5 Developers/// Target fstat() handler.
142810037SARM gem5 Developerstemplate <class OS>
142910037SARM gem5 DevelopersSyscallReturn
143010037SARM gem5 DevelopersfstatFunc(SyscallDesc *desc, int callnum, Process *p, ThreadContext *tc)
143110037SARM gem5 Developers{
143210037SARM gem5 Developers    int index = 0;
143310037SARM gem5 Developers    int tgt_fd = p->getSyscallArg(tc, index);
143410037SARM gem5 Developers    Addr bufPtr = p->getSyscallArg(tc, index);
143510037SARM gem5 Developers
143610037SARM gem5 Developers    DPRINTF_SYSCALL(Verbose, "fstat(%d, ...)\n", tgt_fd);
143710037SARM gem5 Developers
143810037SARM gem5 Developers    auto ffdp = std::dynamic_pointer_cast<FileFDEntry>((*p->fds)[tgt_fd]);
143910037SARM gem5 Developers    if (!ffdp)
144010037SARM gem5 Developers        return -EBADF;
144110037SARM gem5 Developers    int sim_fd = ffdp->getSimFD();
144210037SARM gem5 Developers
144310037SARM gem5 Developers    struct stat hostBuf;
144410037SARM gem5 Developers    int result = fstat(sim_fd, &hostBuf);
144510037SARM gem5 Developers
144610037SARM gem5 Developers    if (result < 0)
144710037SARM gem5 Developers        return -errno;
144810037SARM gem5 Developers
144910037SARM gem5 Developers    copyOutStatBuf<OS>(tc->getMemProxy(), bufPtr, &hostBuf, (sim_fd == 1));
145010037SARM gem5 Developers
145110037SARM gem5 Developers    return 0;
145210037SARM gem5 Developers}
145310037SARM gem5 Developers
145410037SARM gem5 Developers/// Target statfs() handler.
14556019Shines@cs.fsu.edutemplate <class OS>
14566019Shines@cs.fsu.eduSyscallReturn
1457statfsFunc(SyscallDesc *desc, int callnum, Process *process,
1458           ThreadContext *tc)
1459{
1460#if NO_STATFS
1461    warn("Host OS cannot support calls to statfs. Ignoring syscall");
1462#else
1463    std::string path;
1464
1465    int index = 0;
1466    if (!tc->getMemProxy().tryReadString(path,
1467                process->getSyscallArg(tc, index))) {
1468        return -EFAULT;
1469    }
1470    Addr bufPtr = process->getSyscallArg(tc, index);
1471
1472    // Adjust path for current working directory
1473    path = process->fullPath(path);
1474
1475    struct statfs hostBuf;
1476    int result = statfs(path.c_str(), &hostBuf);
1477
1478    if (result < 0)
1479        return -errno;
1480
1481    copyOutStatfsBuf<OS>(tc->getMemProxy(), bufPtr, &hostBuf);
1482#endif
1483    return 0;
1484}
1485
1486template <class OS>
1487SyscallReturn
1488cloneFunc(SyscallDesc *desc, int callnum, Process *p, ThreadContext *tc)
1489{
1490    int index = 0;
1491
1492    RegVal flags = p->getSyscallArg(tc, index);
1493    RegVal newStack = p->getSyscallArg(tc, index);
1494    Addr ptidPtr = p->getSyscallArg(tc, index);
1495
1496#if THE_ISA == RISCV_ISA or THE_ISA == ARM_ISA
1497    /**
1498     * Linux sets CLONE_BACKWARDS flag for RISC-V and Arm.
1499     * The flag defines the list of clone() arguments in the following
1500     * order: flags -> newStack -> ptidPtr -> tlsPtr -> ctidPtr
1501     */
1502    Addr tlsPtr = p->getSyscallArg(tc, index);
1503    Addr ctidPtr = p->getSyscallArg(tc, index);
1504#else
1505    Addr ctidPtr = p->getSyscallArg(tc, index);
1506    Addr tlsPtr = p->getSyscallArg(tc, index);
1507#endif
1508
1509    if (((flags & OS::TGT_CLONE_SIGHAND)&& !(flags & OS::TGT_CLONE_VM)) ||
1510        ((flags & OS::TGT_CLONE_THREAD) && !(flags & OS::TGT_CLONE_SIGHAND)) ||
1511        ((flags & OS::TGT_CLONE_FS)     &&  (flags & OS::TGT_CLONE_NEWNS)) ||
1512        ((flags & OS::TGT_CLONE_NEWIPC) &&  (flags & OS::TGT_CLONE_SYSVSEM)) ||
1513        ((flags & OS::TGT_CLONE_NEWPID) &&  (flags & OS::TGT_CLONE_THREAD)) ||
1514        ((flags & OS::TGT_CLONE_VM)     && !(newStack)))
1515        return -EINVAL;
1516
1517    ThreadContext *ctc;
1518    if (!(ctc = p->findFreeContext())) {
1519        DPRINTF_SYSCALL(Verbose, "clone: no spare thread context in system"
1520                        "[cpu %d, thread %d]", tc->cpuId(), tc->threadId());
1521        return -EAGAIN;
1522    }
1523
1524    /**
1525     * Note that ProcessParams is generated by swig and there are no other
1526     * examples of how to create anything but this default constructor. The
1527     * fields are manually initialized instead of passing parameters to the
1528     * constructor.
1529     */
1530    ProcessParams *pp = new ProcessParams();
1531    pp->executable.assign(*(new std::string(p->progName())));
1532    pp->cmd.push_back(*(new std::string(p->progName())));
1533    pp->system = p->system;
1534    pp->cwd.assign(p->getcwd());
1535    pp->input.assign("stdin");
1536    pp->output.assign("stdout");
1537    pp->errout.assign("stderr");
1538    pp->uid = p->uid();
1539    pp->euid = p->euid();
1540    pp->gid = p->gid();
1541    pp->egid = p->egid();
1542
1543    /* Find the first free PID that's less than the maximum */
1544    std::set<int> const& pids = p->system->PIDs;
1545    int temp_pid = *pids.begin();
1546    do {
1547        temp_pid++;
1548    } while (pids.find(temp_pid) != pids.end());
1549    if (temp_pid >= System::maxPID)
1550        fatal("temp_pid is too large: %d", temp_pid);
1551
1552    pp->pid = temp_pid;
1553    pp->ppid = (flags & OS::TGT_CLONE_THREAD) ? p->ppid() : p->pid();
1554    Process *cp = pp->create();
1555    delete pp;
1556
1557    Process *owner = ctc->getProcessPtr();
1558    ctc->setProcessPtr(cp);
1559    cp->assignThreadContext(ctc->contextId());
1560    owner->revokeThreadContext(ctc->contextId());
1561
1562    if (flags & OS::TGT_CLONE_PARENT_SETTID) {
1563        BufferArg ptidBuf(ptidPtr, sizeof(long));
1564        long *ptid = (long *)ptidBuf.bufferPtr();
1565        *ptid = cp->pid();
1566        ptidBuf.copyOut(tc->getMemProxy());
1567    }
1568
1569    cp->initState();
1570    p->clone(tc, ctc, cp, flags);
1571
1572    if (flags & OS::TGT_CLONE_THREAD) {
1573        delete cp->sigchld;
1574        cp->sigchld = p->sigchld;
1575    } else if (flags & OS::TGT_SIGCHLD) {
1576        *cp->sigchld = true;
1577    }
1578
1579    if (flags & OS::TGT_CLONE_CHILD_SETTID) {
1580        BufferArg ctidBuf(ctidPtr, sizeof(long));
1581        long *ctid = (long *)ctidBuf.bufferPtr();
1582        *ctid = cp->pid();
1583        ctidBuf.copyOut(ctc->getMemProxy());
1584    }
1585
1586    if (flags & OS::TGT_CLONE_CHILD_CLEARTID)
1587        cp->childClearTID = (uint64_t)ctidPtr;
1588
1589    ctc->clearArchRegs();
1590
1591    OS::archClone(flags, p, cp, tc, ctc, newStack, tlsPtr);
1592
1593    cp->setSyscallReturn(ctc, 0);
1594
1595#if THE_ISA == ALPHA_ISA
1596    ctc->setIntReg(TheISA::SyscallSuccessReg, 0);
1597#elif THE_ISA == SPARC_ISA
1598    tc->setIntReg(TheISA::SyscallPseudoReturnReg, 0);
1599    ctc->setIntReg(TheISA::SyscallPseudoReturnReg, 1);
1600#endif
1601
1602    TheISA::PCState cpc = tc->pcState();
1603    cpc.advance();
1604    ctc->pcState(cpc);
1605    ctc->activate();
1606
1607    return cp->pid();
1608}
1609
1610/// Target fstatfs() handler.
1611template <class OS>
1612SyscallReturn
1613fstatfsFunc(SyscallDesc *desc, int callnum, Process *p, ThreadContext *tc)
1614{
1615    int index = 0;
1616    int tgt_fd = p->getSyscallArg(tc, index);
1617    Addr bufPtr = p->getSyscallArg(tc, index);
1618
1619    auto ffdp = std::dynamic_pointer_cast<FileFDEntry>((*p->fds)[tgt_fd]);
1620    if (!ffdp)
1621        return -EBADF;
1622    int sim_fd = ffdp->getSimFD();
1623
1624    struct statfs hostBuf;
1625    int result = fstatfs(sim_fd, &hostBuf);
1626
1627    if (result < 0)
1628        return -errno;
1629
1630    copyOutStatfsBuf<OS>(tc->getMemProxy(), bufPtr, &hostBuf);
1631
1632    return 0;
1633}
1634
1635/// Target readv() handler.
1636template <class OS>
1637SyscallReturn
1638readvFunc(SyscallDesc *desc, int callnum, Process *p, ThreadContext *tc)
1639{
1640    int index = 0;
1641    int tgt_fd = p->getSyscallArg(tc, index);
1642
1643    auto ffdp = std::dynamic_pointer_cast<FileFDEntry>((*p->fds)[tgt_fd]);
1644    if (!ffdp)
1645        return -EBADF;
1646    int sim_fd = ffdp->getSimFD();
1647
1648    SETranslatingPortProxy &prox = tc->getMemProxy();
1649    uint64_t tiov_base = p->getSyscallArg(tc, index);
1650    size_t count = p->getSyscallArg(tc, index);
1651    typename OS::tgt_iovec tiov[count];
1652    struct iovec hiov[count];
1653    for (size_t i = 0; i < count; ++i) {
1654        prox.readBlob(tiov_base + (i * sizeof(typename OS::tgt_iovec)),
1655                      (uint8_t*)&tiov[i], sizeof(typename OS::tgt_iovec));
1656        hiov[i].iov_len = TheISA::gtoh(tiov[i].iov_len);
1657        hiov[i].iov_base = new char [hiov[i].iov_len];
1658    }
1659
1660    int result = readv(sim_fd, hiov, count);
1661    int local_errno = errno;
1662
1663    for (size_t i = 0; i < count; ++i) {
1664        if (result != -1) {
1665            prox.writeBlob(TheISA::htog(tiov[i].iov_base),
1666                           (uint8_t*)hiov[i].iov_base, hiov[i].iov_len);
1667        }
1668        delete [] (char *)hiov[i].iov_base;
1669    }
1670
1671    return (result == -1) ? -local_errno : result;
1672}
1673
1674/// Target writev() handler.
1675template <class OS>
1676SyscallReturn
1677writevFunc(SyscallDesc *desc, int callnum, Process *p, ThreadContext *tc)
1678{
1679    int index = 0;
1680    int tgt_fd = p->getSyscallArg(tc, index);
1681
1682    auto hbfdp = std::dynamic_pointer_cast<HBFDEntry>((*p->fds)[tgt_fd]);
1683    if (!hbfdp)
1684        return -EBADF;
1685    int sim_fd = hbfdp->getSimFD();
1686
1687    SETranslatingPortProxy &prox = tc->getMemProxy();
1688    uint64_t tiov_base = p->getSyscallArg(tc, index);
1689    size_t count = p->getSyscallArg(tc, index);
1690    struct iovec hiov[count];
1691    for (size_t i = 0; i < count; ++i) {
1692        typename OS::tgt_iovec tiov;
1693
1694        prox.readBlob(tiov_base + i*sizeof(typename OS::tgt_iovec),
1695                      (uint8_t*)&tiov, sizeof(typename OS::tgt_iovec));
1696        hiov[i].iov_len = TheISA::gtoh(tiov.iov_len);
1697        hiov[i].iov_base = new char [hiov[i].iov_len];
1698        prox.readBlob(TheISA::gtoh(tiov.iov_base), (uint8_t *)hiov[i].iov_base,
1699                      hiov[i].iov_len);
1700    }
1701
1702    int result = writev(sim_fd, hiov, count);
1703
1704    for (size_t i = 0; i < count; ++i)
1705        delete [] (char *)hiov[i].iov_base;
1706
1707    return (result == -1) ? -errno : result;
1708}
1709
1710/// Real mmap handler.
1711template <class OS>
1712SyscallReturn
1713mmapImpl(SyscallDesc *desc, int num, Process *p, ThreadContext *tc,
1714         bool is_mmap2)
1715{
1716    int index = 0;
1717    Addr start = p->getSyscallArg(tc, index);
1718    uint64_t length = p->getSyscallArg(tc, index);
1719    int prot = p->getSyscallArg(tc, index);
1720    int tgt_flags = p->getSyscallArg(tc, index);
1721    int tgt_fd = p->getSyscallArg(tc, index);
1722    int offset = p->getSyscallArg(tc, index);
1723
1724    if (is_mmap2)
1725        offset *= TheISA::PageBytes;
1726
1727    if (start & (TheISA::PageBytes - 1) ||
1728        offset & (TheISA::PageBytes - 1) ||
1729        (tgt_flags & OS::TGT_MAP_PRIVATE &&
1730         tgt_flags & OS::TGT_MAP_SHARED) ||
1731        (!(tgt_flags & OS::TGT_MAP_PRIVATE) &&
1732         !(tgt_flags & OS::TGT_MAP_SHARED)) ||
1733        !length) {
1734        return -EINVAL;
1735    }
1736
1737    if ((prot & PROT_WRITE) && (tgt_flags & OS::TGT_MAP_SHARED)) {
1738        // With shared mmaps, there are two cases to consider:
1739        // 1) anonymous: writes should modify the mapping and this should be
1740        // visible to observers who share the mapping. Currently, it's
1741        // difficult to update the shared mapping because there's no
1742        // structure which maintains information about the which virtual
1743        // memory areas are shared. If that structure existed, it would be
1744        // possible to make the translations point to the same frames.
1745        // 2) file-backed: writes should modify the mapping and the file
1746        // which is backed by the mapping. The shared mapping problem is the
1747        // same as what was mentioned about the anonymous mappings. For
1748        // file-backed mappings, the writes to the file are difficult
1749        // because it requires syncing what the mapping holds with the file
1750        // that resides on the host system. So, any write on a real system
1751        // would cause the change to be propagated to the file mapping at
1752        // some point in the future (the inode is tracked along with the
1753        // mapping). This isn't guaranteed to always happen, but it usually
1754        // works well enough. The guarantee is provided by the msync system
1755        // call. We could force the change through with shared mappings with
1756        // a call to msync, but that again would require more information
1757        // than we currently maintain.
1758        warn("mmap: writing to shared mmap region is currently "
1759             "unsupported. The write succeeds on the target, but it "
1760             "will not be propagated to the host or shared mappings");
1761    }
1762
1763    length = roundUp(length, TheISA::PageBytes);
1764
1765    int sim_fd = -1;
1766    uint8_t *pmap = nullptr;
1767    if (!(tgt_flags & OS::TGT_MAP_ANONYMOUS)) {
1768        std::shared_ptr<FDEntry> fdep = (*p->fds)[tgt_fd];
1769
1770        auto dfdp = std::dynamic_pointer_cast<DeviceFDEntry>(fdep);
1771        if (dfdp) {
1772            EmulatedDriver *emul_driver = dfdp->getDriver();
1773            return emul_driver->mmap(p, tc, start, length, prot,
1774                                     tgt_flags, tgt_fd, offset);
1775        }
1776
1777        auto ffdp = std::dynamic_pointer_cast<FileFDEntry>(fdep);
1778        if (!ffdp)
1779            return -EBADF;
1780        sim_fd = ffdp->getSimFD();
1781
1782        pmap = (decltype(pmap))mmap(nullptr, length, PROT_READ, MAP_PRIVATE,
1783                                    sim_fd, offset);
1784
1785        if (pmap == (decltype(pmap))-1) {
1786            warn("mmap: failed to map file into host address space");
1787            return -errno;
1788        }
1789    }
1790
1791    // Extend global mmap region if necessary. Note that we ignore the
1792    // start address unless MAP_FIXED is specified.
1793    if (!(tgt_flags & OS::TGT_MAP_FIXED)) {
1794        std::shared_ptr<MemState> mem_state = p->memState;
1795        Addr mmap_end = mem_state->getMmapEnd();
1796
1797        start = p->mmapGrowsDown() ? mmap_end - length : mmap_end;
1798        mmap_end = p->mmapGrowsDown() ? start : mmap_end + length;
1799
1800        mem_state->setMmapEnd(mmap_end);
1801    }
1802
1803    DPRINTF_SYSCALL(Verbose, " mmap range is 0x%x - 0x%x\n",
1804                    start, start + length - 1);
1805
1806    // We only allow mappings to overwrite existing mappings if
1807    // TGT_MAP_FIXED is set. Otherwise it shouldn't be a problem
1808    // because we ignore the start hint if TGT_MAP_FIXED is not set.
1809    int clobber = tgt_flags & OS::TGT_MAP_FIXED;
1810    if (clobber) {
1811        for (auto tc : p->system->threadContexts) {
1812            // If we might be overwriting old mappings, we need to
1813            // invalidate potentially stale mappings out of the TLBs.
1814            tc->getDTBPtr()->flushAll();
1815            tc->getITBPtr()->flushAll();
1816        }
1817    }
1818
1819    // Allocate physical memory and map it in. If the page table is already
1820    // mapped and clobber is not set, the simulator will issue throw a
1821    // fatal and bail out of the simulation.
1822    p->allocateMem(start, length, clobber);
1823
1824    // Transfer content into target address space.
1825    SETranslatingPortProxy &tp = tc->getMemProxy();
1826    if (tgt_flags & OS::TGT_MAP_ANONYMOUS) {
1827        // In general, we should zero the mapped area for anonymous mappings,
1828        // with something like:
1829        //     tp.memsetBlob(start, 0, length);
1830        // However, given that we don't support sparse mappings, and
1831        // some applications can map a couple of gigabytes of space
1832        // (intending sparse usage), that can get painfully expensive.
1833        // Fortunately, since we don't properly implement munmap either,
1834        // there's no danger of remapping used memory, so for now all
1835        // newly mapped memory should already be zeroed so we can skip it.
1836    } else {
1837        // It is possible to mmap an area larger than a file, however
1838        // accessing unmapped portions the system triggers a "Bus error"
1839        // on the host. We must know when to stop copying the file from
1840        // the host into the target address space.
1841        struct stat file_stat;
1842        if (fstat(sim_fd, &file_stat) > 0)
1843            fatal("mmap: cannot stat file");
1844
1845        // Copy the portion of the file that is resident. This requires
1846        // checking both the mmap size and the filesize that we are
1847        // trying to mmap into this space; the mmap size also depends
1848        // on the specified offset into the file.
1849        uint64_t size = std::min((uint64_t)file_stat.st_size - offset,
1850                                 length);
1851        tp.writeBlob(start, pmap, size);
1852
1853        // Cleanup the mmap region before exiting this function.
1854        munmap(pmap, length);
1855
1856        // Maintain the symbol table for dynamic executables.
1857        // The loader will call mmap to map the images into its address
1858        // space and we intercept that here. We can verify that we are
1859        // executing inside the loader by checking the program counter value.
1860        // XXX: with multiprogrammed workloads or multi-node configurations,
1861        // this will not work since there is a single global symbol table.
1862        ObjectFile *interpreter = p->getInterpreter();
1863        if (interpreter) {
1864            Addr text_start = interpreter->textBase();
1865            Addr text_end = text_start + interpreter->textSize();
1866
1867            Addr pc = tc->pcState().pc();
1868
1869            if (pc >= text_start && pc < text_end) {
1870                std::shared_ptr<FDEntry> fdep = (*p->fds)[tgt_fd];
1871                auto ffdp = std::dynamic_pointer_cast<FileFDEntry>(fdep);
1872                ObjectFile *lib = createObjectFile(ffdp->getFileName());
1873
1874                if (lib) {
1875                    lib->loadAllSymbols(debugSymbolTable,
1876                                        lib->textBase(), start);
1877                }
1878            }
1879        }
1880
1881        // Note that we do not zero out the remainder of the mapping. This
1882        // is done by a real system, but it probably will not affect
1883        // execution (hopefully).
1884    }
1885
1886    return start;
1887}
1888
1889template <class OS>
1890SyscallReturn
1891pwrite64Func(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
1892{
1893    int index = 0;
1894    int tgt_fd = p->getSyscallArg(tc, index);
1895    Addr bufPtr = p->getSyscallArg(tc, index);
1896    int nbytes = p->getSyscallArg(tc, index);
1897    int offset = p->getSyscallArg(tc, index);
1898
1899    auto ffdp = std::dynamic_pointer_cast<FileFDEntry>((*p->fds)[tgt_fd]);
1900    if (!ffdp)
1901        return -EBADF;
1902    int sim_fd = ffdp->getSimFD();
1903
1904    BufferArg bufArg(bufPtr, nbytes);
1905    bufArg.copyIn(tc->getMemProxy());
1906
1907    int bytes_written = pwrite(sim_fd, bufArg.bufferPtr(), nbytes, offset);
1908
1909    return (bytes_written == -1) ? -errno : bytes_written;
1910}
1911
1912/// Target mmap() handler.
1913template <class OS>
1914SyscallReturn
1915mmapFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
1916{
1917    return mmapImpl<OS>(desc, num, p, tc, false);
1918}
1919
1920/// Target mmap2() handler.
1921template <class OS>
1922SyscallReturn
1923mmap2Func(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
1924{
1925    return mmapImpl<OS>(desc, num, p, tc, true);
1926}
1927
1928/// Target getrlimit() handler.
1929template <class OS>
1930SyscallReturn
1931getrlimitFunc(SyscallDesc *desc, int callnum, Process *process,
1932              ThreadContext *tc)
1933{
1934    int index = 0;
1935    unsigned resource = process->getSyscallArg(tc, index);
1936    TypedBufferArg<typename OS::rlimit> rlp(process->getSyscallArg(tc, index));
1937
1938    switch (resource) {
1939      case OS::TGT_RLIMIT_STACK:
1940        // max stack size in bytes: make up a number (8MB for now)
1941        rlp->rlim_cur = rlp->rlim_max = 8 * 1024 * 1024;
1942        rlp->rlim_cur = TheISA::htog(rlp->rlim_cur);
1943        rlp->rlim_max = TheISA::htog(rlp->rlim_max);
1944        break;
1945
1946      case OS::TGT_RLIMIT_DATA:
1947        // max data segment size in bytes: make up a number
1948        rlp->rlim_cur = rlp->rlim_max = 256 * 1024 * 1024;
1949        rlp->rlim_cur = TheISA::htog(rlp->rlim_cur);
1950        rlp->rlim_max = TheISA::htog(rlp->rlim_max);
1951        break;
1952
1953      default:
1954        warn("getrlimit: unimplemented resource %d", resource);
1955        return -EINVAL;
1956        break;
1957    }
1958
1959    rlp.copyOut(tc->getMemProxy());
1960    return 0;
1961}
1962
1963template <class OS>
1964SyscallReturn
1965prlimitFunc(SyscallDesc *desc, int callnum, Process *process,
1966            ThreadContext *tc)
1967{
1968    int index = 0;
1969    if (process->getSyscallArg(tc, index) != 0)
1970    {
1971        warn("prlimit: ignoring rlimits for nonzero pid");
1972        return -EPERM;
1973    }
1974    int resource = process->getSyscallArg(tc, index);
1975    Addr n = process->getSyscallArg(tc, index);
1976    if (n != 0)
1977        warn("prlimit: ignoring new rlimit");
1978    Addr o = process->getSyscallArg(tc, index);
1979    if (o != 0)
1980    {
1981        TypedBufferArg<typename OS::rlimit> rlp(o);
1982        switch (resource) {
1983          case OS::TGT_RLIMIT_STACK:
1984            // max stack size in bytes: make up a number (8MB for now)
1985            rlp->rlim_cur = rlp->rlim_max = 8 * 1024 * 1024;
1986            rlp->rlim_cur = TheISA::htog(rlp->rlim_cur);
1987            rlp->rlim_max = TheISA::htog(rlp->rlim_max);
1988            break;
1989          case OS::TGT_RLIMIT_DATA:
1990            // max data segment size in bytes: make up a number
1991            rlp->rlim_cur = rlp->rlim_max = 256*1024*1024;
1992            rlp->rlim_cur = TheISA::htog(rlp->rlim_cur);
1993            rlp->rlim_max = TheISA::htog(rlp->rlim_max);
1994            break;
1995          default:
1996            warn("prlimit: unimplemented resource %d", resource);
1997            return -EINVAL;
1998            break;
1999        }
2000        rlp.copyOut(tc->getMemProxy());
2001    }
2002    return 0;
2003}
2004
2005/// Target clock_gettime() function.
2006template <class OS>
2007SyscallReturn
2008clock_gettimeFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
2009{
2010    int index = 1;
2011    //int clk_id = p->getSyscallArg(tc, index);
2012    TypedBufferArg<typename OS::timespec> tp(p->getSyscallArg(tc, index));
2013
2014    getElapsedTimeNano(tp->tv_sec, tp->tv_nsec);
2015    tp->tv_sec += seconds_since_epoch;
2016    tp->tv_sec = TheISA::htog(tp->tv_sec);
2017    tp->tv_nsec = TheISA::htog(tp->tv_nsec);
2018
2019    tp.copyOut(tc->getMemProxy());
2020
2021    return 0;
2022}
2023
2024/// Target clock_getres() function.
2025template <class OS>
2026SyscallReturn
2027clock_getresFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
2028{
2029    int index = 1;
2030    TypedBufferArg<typename OS::timespec> tp(p->getSyscallArg(tc, index));
2031
2032    // Set resolution at ns, which is what clock_gettime() returns
2033    tp->tv_sec = 0;
2034    tp->tv_nsec = 1;
2035
2036    tp.copyOut(tc->getMemProxy());
2037
2038    return 0;
2039}
2040
2041/// Target gettimeofday() handler.
2042template <class OS>
2043SyscallReturn
2044gettimeofdayFunc(SyscallDesc *desc, int callnum, Process *process,
2045                 ThreadContext *tc)
2046{
2047    int index = 0;
2048    TypedBufferArg<typename OS::timeval> tp(process->getSyscallArg(tc, index));
2049
2050    getElapsedTimeMicro(tp->tv_sec, tp->tv_usec);
2051    tp->tv_sec += seconds_since_epoch;
2052    tp->tv_sec = TheISA::htog(tp->tv_sec);
2053    tp->tv_usec = TheISA::htog(tp->tv_usec);
2054
2055    tp.copyOut(tc->getMemProxy());
2056
2057    return 0;
2058}
2059
2060
2061/// Target utimes() handler.
2062template <class OS>
2063SyscallReturn
2064utimesFunc(SyscallDesc *desc, int callnum, Process *process,
2065           ThreadContext *tc)
2066{
2067    std::string path;
2068
2069    int index = 0;
2070    if (!tc->getMemProxy().tryReadString(path,
2071                process->getSyscallArg(tc, index))) {
2072        return -EFAULT;
2073    }
2074
2075    TypedBufferArg<typename OS::timeval [2]>
2076        tp(process->getSyscallArg(tc, index));
2077    tp.copyIn(tc->getMemProxy());
2078
2079    struct timeval hostTimeval[2];
2080    for (int i = 0; i < 2; ++i) {
2081        hostTimeval[i].tv_sec = TheISA::gtoh((*tp)[i].tv_sec);
2082        hostTimeval[i].tv_usec = TheISA::gtoh((*tp)[i].tv_usec);
2083    }
2084
2085    // Adjust path for current working directory
2086    path = process->fullPath(path);
2087
2088    int result = utimes(path.c_str(), hostTimeval);
2089
2090    if (result < 0)
2091        return -errno;
2092
2093    return 0;
2094}
2095
2096template <class OS>
2097SyscallReturn
2098execveFunc(SyscallDesc *desc, int callnum, Process *p, ThreadContext *tc)
2099{
2100    desc->setFlags(0);
2101
2102    int index = 0;
2103    std::string path;
2104    SETranslatingPortProxy & mem_proxy = tc->getMemProxy();
2105    if (!mem_proxy.tryReadString(path, p->getSyscallArg(tc, index)))
2106        return -EFAULT;
2107
2108    if (access(path.c_str(), F_OK) == -1)
2109        return -EACCES;
2110
2111    auto read_in = [](std::vector<std::string> & vect,
2112                      SETranslatingPortProxy & mem_proxy,
2113                      Addr mem_loc)
2114    {
2115        for (int inc = 0; ; inc++) {
2116            BufferArg b((mem_loc + sizeof(Addr) * inc), sizeof(Addr));
2117            b.copyIn(mem_proxy);
2118
2119            if (!*(Addr*)b.bufferPtr())
2120                break;
2121
2122            vect.push_back(std::string());
2123            mem_proxy.tryReadString(vect[inc], *(Addr*)b.bufferPtr());
2124        }
2125    };
2126
2127    /**
2128     * Note that ProcessParams is generated by swig and there are no other
2129     * examples of how to create anything but this default constructor. The
2130     * fields are manually initialized instead of passing parameters to the
2131     * constructor.
2132     */
2133    ProcessParams *pp = new ProcessParams();
2134    pp->executable = path;
2135    Addr argv_mem_loc = p->getSyscallArg(tc, index);
2136    read_in(pp->cmd, mem_proxy, argv_mem_loc);
2137    Addr envp_mem_loc = p->getSyscallArg(tc, index);
2138    read_in(pp->env, mem_proxy, envp_mem_loc);
2139    pp->uid = p->uid();
2140    pp->egid = p->egid();
2141    pp->euid = p->euid();
2142    pp->gid = p->gid();
2143    pp->ppid = p->ppid();
2144    pp->pid = p->pid();
2145    pp->input.assign("cin");
2146    pp->output.assign("cout");
2147    pp->errout.assign("cerr");
2148    pp->cwd.assign(p->getcwd());
2149    pp->system = p->system;
2150    /**
2151     * Prevent process object creation with identical PIDs (which will trip
2152     * a fatal check in Process constructor). The execve call is supposed to
2153     * take over the currently executing process' identity but replace
2154     * whatever it is doing with a new process image. Instead of hijacking
2155     * the process object in the simulator, we create a new process object
2156     * and bind to the previous process' thread below (hijacking the thread).
2157     */
2158    p->system->PIDs.erase(p->pid());
2159    Process *new_p = pp->create();
2160    delete pp;
2161
2162    /**
2163     * Work through the file descriptor array and close any files marked
2164     * close-on-exec.
2165     */
2166    new_p->fds = p->fds;
2167    for (int i = 0; i < new_p->fds->getSize(); i++) {
2168        std::shared_ptr<FDEntry> fdep = (*new_p->fds)[i];
2169        if (fdep && fdep->getCOE())
2170            new_p->fds->closeFDEntry(i);
2171    }
2172
2173    *new_p->sigchld = true;
2174
2175    delete p;
2176    tc->clearArchRegs();
2177    tc->setProcessPtr(new_p);
2178    new_p->assignThreadContext(tc->contextId());
2179    new_p->initState();
2180    tc->activate();
2181    TheISA::PCState pcState = tc->pcState();
2182    tc->setNPC(pcState.instAddr());
2183
2184    desc->setFlags(SyscallDesc::SuppressReturnValue);
2185    return 0;
2186}
2187
2188/// Target getrusage() function.
2189template <class OS>
2190SyscallReturn
2191getrusageFunc(SyscallDesc *desc, int callnum, Process *process,
2192              ThreadContext *tc)
2193{
2194    int index = 0;
2195    int who = process->getSyscallArg(tc, index); // THREAD, SELF, or CHILDREN
2196    TypedBufferArg<typename OS::rusage> rup(process->getSyscallArg(tc, index));
2197
2198    rup->ru_utime.tv_sec = 0;
2199    rup->ru_utime.tv_usec = 0;
2200    rup->ru_stime.tv_sec = 0;
2201    rup->ru_stime.tv_usec = 0;
2202    rup->ru_maxrss = 0;
2203    rup->ru_ixrss = 0;
2204    rup->ru_idrss = 0;
2205    rup->ru_isrss = 0;
2206    rup->ru_minflt = 0;
2207    rup->ru_majflt = 0;
2208    rup->ru_nswap = 0;
2209    rup->ru_inblock = 0;
2210    rup->ru_oublock = 0;
2211    rup->ru_msgsnd = 0;
2212    rup->ru_msgrcv = 0;
2213    rup->ru_nsignals = 0;
2214    rup->ru_nvcsw = 0;
2215    rup->ru_nivcsw = 0;
2216
2217    switch (who) {
2218      case OS::TGT_RUSAGE_SELF:
2219        getElapsedTimeMicro(rup->ru_utime.tv_sec, rup->ru_utime.tv_usec);
2220        rup->ru_utime.tv_sec = TheISA::htog(rup->ru_utime.tv_sec);
2221        rup->ru_utime.tv_usec = TheISA::htog(rup->ru_utime.tv_usec);
2222        break;
2223
2224      case OS::TGT_RUSAGE_CHILDREN:
2225        // do nothing.  We have no child processes, so they take no time.
2226        break;
2227
2228      default:
2229        // don't really handle THREAD or CHILDREN, but just warn and
2230        // plow ahead
2231        warn("getrusage() only supports RUSAGE_SELF.  Parameter %d ignored.",
2232             who);
2233    }
2234
2235    rup.copyOut(tc->getMemProxy());
2236
2237    return 0;
2238}
2239
2240/// Target times() function.
2241template <class OS>
2242SyscallReturn
2243timesFunc(SyscallDesc *desc, int callnum, Process *process,
2244          ThreadContext *tc)
2245{
2246    int index = 0;
2247    TypedBufferArg<typename OS::tms> bufp(process->getSyscallArg(tc, index));
2248
2249    // Fill in the time structure (in clocks)
2250    int64_t clocks = curTick() * OS::M5_SC_CLK_TCK / SimClock::Int::s;
2251    bufp->tms_utime = clocks;
2252    bufp->tms_stime = 0;
2253    bufp->tms_cutime = 0;
2254    bufp->tms_cstime = 0;
2255
2256    // Convert to host endianness
2257    bufp->tms_utime = TheISA::htog(bufp->tms_utime);
2258
2259    // Write back
2260    bufp.copyOut(tc->getMemProxy());
2261
2262    // Return clock ticks since system boot
2263    return clocks;
2264}
2265
2266/// Target time() function.
2267template <class OS>
2268SyscallReturn
2269timeFunc(SyscallDesc *desc, int callnum, Process *process, ThreadContext *tc)
2270{
2271    typename OS::time_t sec, usec;
2272    getElapsedTimeMicro(sec, usec);
2273    sec += seconds_since_epoch;
2274
2275    int index = 0;
2276    Addr taddr = (Addr)process->getSyscallArg(tc, index);
2277    if (taddr != 0) {
2278        typename OS::time_t t = sec;
2279        t = TheISA::htog(t);
2280        SETranslatingPortProxy &p = tc->getMemProxy();
2281        p.writeBlob(taddr, (uint8_t*)&t, (int)sizeof(typename OS::time_t));
2282    }
2283    return sec;
2284}
2285
2286template <class OS>
2287SyscallReturn
2288tgkillFunc(SyscallDesc *desc, int num, Process *process, ThreadContext *tc)
2289{
2290    int index = 0;
2291    int tgid = process->getSyscallArg(tc, index);
2292    int tid = process->getSyscallArg(tc, index);
2293    int sig = process->getSyscallArg(tc, index);
2294
2295    /**
2296     * This system call is intended to allow killing a specific thread
2297     * within an arbitrary thread group if sanctioned with permission checks.
2298     * It's usually true that threads share the termination signal as pointed
2299     * out by the pthread_kill man page and this seems to be the intended
2300     * usage. Due to this being an emulated environment, assume the following:
2301     * Threads are allowed to call tgkill because the EUID for all threads
2302     * should be the same. There is no signal handling mechanism for kernel
2303     * registration of signal handlers since signals are poorly supported in
2304     * emulation mode. Since signal handlers cannot be registered, all
2305     * threads within in a thread group must share the termination signal.
2306     * We never exhaust PIDs so there's no chance of finding the wrong one
2307     * due to PID rollover.
2308     */
2309
2310    System *sys = tc->getSystemPtr();
2311    Process *tgt_proc = nullptr;
2312    for (int i = 0; i < sys->numContexts(); i++) {
2313        Process *temp = sys->threadContexts[i]->getProcessPtr();
2314        if (temp->pid() == tid) {
2315            tgt_proc = temp;
2316            break;
2317        }
2318    }
2319
2320    if (sig != 0 || sig != OS::TGT_SIGABRT)
2321        return -EINVAL;
2322
2323    if (tgt_proc == nullptr)
2324        return -ESRCH;
2325
2326    if (tgid != -1 && tgt_proc->tgid() != tgid)
2327        return -ESRCH;
2328
2329    if (sig == OS::TGT_SIGABRT)
2330        exitGroupFunc(desc, 252, process, tc);
2331
2332    return 0;
2333}
2334
2335template <class OS>
2336SyscallReturn
2337socketFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
2338{
2339    int index = 0;
2340    int domain = p->getSyscallArg(tc, index);
2341    int type = p->getSyscallArg(tc, index);
2342    int prot = p->getSyscallArg(tc, index);
2343
2344    int sim_fd = socket(domain, type, prot);
2345    if (sim_fd == -1)
2346        return -errno;
2347
2348    auto sfdp = std::make_shared<SocketFDEntry>(sim_fd, domain, type, prot);
2349    int tgt_fd = p->fds->allocFD(sfdp);
2350
2351    return tgt_fd;
2352}
2353
2354template <class OS>
2355SyscallReturn
2356socketpairFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
2357{
2358    int index = 0;
2359    int domain = p->getSyscallArg(tc, index);
2360    int type = p->getSyscallArg(tc, index);
2361    int prot = p->getSyscallArg(tc, index);
2362    Addr svPtr = p->getSyscallArg(tc, index);
2363
2364    BufferArg svBuf((Addr)svPtr, 2 * sizeof(int));
2365    int status = socketpair(domain, type, prot, (int *)svBuf.bufferPtr());
2366    if (status == -1)
2367        return -errno;
2368
2369    int *fds = (int *)svBuf.bufferPtr();
2370
2371    auto sfdp1 = std::make_shared<SocketFDEntry>(fds[0], domain, type, prot);
2372    fds[0] = p->fds->allocFD(sfdp1);
2373    auto sfdp2 = std::make_shared<SocketFDEntry>(fds[1], domain, type, prot);
2374    fds[1] = p->fds->allocFD(sfdp2);
2375    svBuf.copyOut(tc->getMemProxy());
2376
2377    return status;
2378}
2379
2380template <class OS>
2381SyscallReturn
2382selectFunc(SyscallDesc *desc, int callnum, Process *p, ThreadContext *tc)
2383{
2384    int retval;
2385
2386    int index = 0;
2387    int nfds_t = p->getSyscallArg(tc, index);
2388    Addr fds_read_ptr = p->getSyscallArg(tc, index);
2389    Addr fds_writ_ptr = p->getSyscallArg(tc, index);
2390    Addr fds_excp_ptr = p->getSyscallArg(tc, index);
2391    Addr time_val_ptr = p->getSyscallArg(tc, index);
2392
2393    TypedBufferArg<typename OS::fd_set> rd_t(fds_read_ptr);
2394    TypedBufferArg<typename OS::fd_set> wr_t(fds_writ_ptr);
2395    TypedBufferArg<typename OS::fd_set> ex_t(fds_excp_ptr);
2396    TypedBufferArg<typename OS::timeval> tp(time_val_ptr);
2397
2398    /**
2399     * Host fields. Notice that these use the definitions from the system
2400     * headers instead of the gem5 headers and libraries. If the host and
2401     * target have different header file definitions, this will not work.
2402     */
2403    fd_set rd_h;
2404    FD_ZERO(&rd_h);
2405    fd_set wr_h;
2406    FD_ZERO(&wr_h);
2407    fd_set ex_h;
2408    FD_ZERO(&ex_h);
2409
2410    /**
2411     * Copy in the fd_set from the target.
2412     */
2413    if (fds_read_ptr)
2414        rd_t.copyIn(tc->getMemProxy());
2415    if (fds_writ_ptr)
2416        wr_t.copyIn(tc->getMemProxy());
2417    if (fds_excp_ptr)
2418        ex_t.copyIn(tc->getMemProxy());
2419
2420    /**
2421     * We need to translate the target file descriptor set into a host file
2422     * descriptor set. This involves both our internal process fd array
2423     * and the fd_set defined in Linux header files. The nfds field also
2424     * needs to be updated as it will be only target specific after
2425     * retrieving it from the target; the nfds value is expected to be the
2426     * highest file descriptor that needs to be checked, so we need to extend
2427     * it out for nfds_h when we do the update.
2428     */
2429    int nfds_h = 0;
2430    std::map<int, int> trans_map;
2431    auto try_add_host_set = [&](fd_set *tgt_set_entry,
2432                                fd_set *hst_set_entry,
2433                                int iter) -> bool
2434    {
2435        /**
2436         * By this point, we know that we are looking at a valid file
2437         * descriptor set on the target. We need to check if the target file
2438         * descriptor value passed in as iter is part of the set.
2439         */
2440        if (FD_ISSET(iter, tgt_set_entry)) {
2441            /**
2442             * We know that the target file descriptor belongs to the set,
2443             * but we do not yet know if the file descriptor is valid or
2444             * that we have a host mapping. Check that now.
2445             */
2446            auto hbfdp = std::dynamic_pointer_cast<HBFDEntry>((*p->fds)[iter]);
2447            if (!hbfdp)
2448                return true;
2449            auto sim_fd = hbfdp->getSimFD();
2450
2451            /**
2452             * Add the sim_fd to tgt_fd translation into trans_map for use
2453             * later when we need to zero the target fd_set structures and
2454             * then update them with hits returned from the host select call.
2455             */
2456            trans_map[sim_fd] = iter;
2457
2458            /**
2459             * We know that the host file descriptor exists so now we check
2460             * if we need to update the max count for nfds_h before passing
2461             * the duplicated structure into the host.
2462             */
2463            nfds_h = std::max(nfds_h - 1, sim_fd + 1);
2464
2465            /**
2466             * Add the host file descriptor to the set that we are going to
2467             * pass into the host.
2468             */
2469            FD_SET(sim_fd, hst_set_entry);
2470        }
2471        return false;
2472    };
2473
2474    for (int i = 0; i < nfds_t; i++) {
2475        if (fds_read_ptr) {
2476            bool ebadf = try_add_host_set((fd_set*)&*rd_t, &rd_h, i);
2477            if (ebadf) return -EBADF;
2478        }
2479        if (fds_writ_ptr) {
2480            bool ebadf = try_add_host_set((fd_set*)&*wr_t, &wr_h, i);
2481            if (ebadf) return -EBADF;
2482        }
2483        if (fds_excp_ptr) {
2484            bool ebadf = try_add_host_set((fd_set*)&*ex_t, &ex_h, i);
2485            if (ebadf) return -EBADF;
2486        }
2487    }
2488
2489    if (time_val_ptr) {
2490        /**
2491         * It might be possible to decrement the timeval based on some
2492         * derivation of wall clock determined from elapsed simulator ticks
2493         * but that seems like overkill. Rather, we just set the timeval with
2494         * zero timeout. (There is no reason to block during the simulation
2495         * as it only decreases simulator performance.)
2496         */
2497        tp->tv_sec = 0;
2498        tp->tv_usec = 0;
2499
2500        retval = select(nfds_h,
2501                        fds_read_ptr ? &rd_h : nullptr,
2502                        fds_writ_ptr ? &wr_h : nullptr,
2503                        fds_excp_ptr ? &ex_h : nullptr,
2504                        (timeval*)&*tp);
2505    } else {
2506        /**
2507         * If the timeval pointer is null, setup a new timeval structure to
2508         * pass into the host select call. Unfortunately, we will need to
2509         * manually check the return value and throw a retry fault if the
2510         * return value is zero. Allowing the system call to block will
2511         * likely deadlock the event queue.
2512         */
2513        struct timeval tv = { 0, 0 };
2514
2515        retval = select(nfds_h,
2516                        fds_read_ptr ? &rd_h : nullptr,
2517                        fds_writ_ptr ? &wr_h : nullptr,
2518                        fds_excp_ptr ? &ex_h : nullptr,
2519                        &tv);
2520
2521        if (retval == 0) {
2522            /**
2523             * If blocking indefinitely, check the signal list to see if a
2524             * signal would break the poll out of the retry cycle and try to
2525             * return the signal interrupt instead.
2526             */
2527            for (auto sig : tc->getSystemPtr()->signalList)
2528                if (sig.receiver == p)
2529                    return -EINTR;
2530            return SyscallReturn::retry();
2531        }
2532    }
2533
2534    if (retval == -1)
2535        return -errno;
2536
2537    FD_ZERO((fd_set*)&*rd_t);
2538    FD_ZERO((fd_set*)&*wr_t);
2539    FD_ZERO((fd_set*)&*ex_t);
2540
2541    /**
2542     * We need to translate the host file descriptor set into a target file
2543     * descriptor set. This involves both our internal process fd array
2544     * and the fd_set defined in header files.
2545     */
2546    for (int i = 0; i < nfds_h; i++) {
2547        if (fds_read_ptr) {
2548            if (FD_ISSET(i, &rd_h))
2549                FD_SET(trans_map[i], (fd_set*)&*rd_t);
2550        }
2551
2552        if (fds_writ_ptr) {
2553            if (FD_ISSET(i, &wr_h))
2554                FD_SET(trans_map[i], (fd_set*)&*wr_t);
2555        }
2556
2557        if (fds_excp_ptr) {
2558            if (FD_ISSET(i, &ex_h))
2559                FD_SET(trans_map[i], (fd_set*)&*ex_t);
2560        }
2561    }
2562
2563    if (fds_read_ptr)
2564        rd_t.copyOut(tc->getMemProxy());
2565    if (fds_writ_ptr)
2566        wr_t.copyOut(tc->getMemProxy());
2567    if (fds_excp_ptr)
2568        ex_t.copyOut(tc->getMemProxy());
2569    if (time_val_ptr)
2570        tp.copyOut(tc->getMemProxy());
2571
2572    return retval;
2573}
2574
2575template <class OS>
2576SyscallReturn
2577readFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
2578{
2579    int index = 0;
2580    int tgt_fd = p->getSyscallArg(tc, index);
2581    Addr buf_ptr = p->getSyscallArg(tc, index);
2582    int nbytes = p->getSyscallArg(tc, index);
2583
2584    auto hbfdp = std::dynamic_pointer_cast<HBFDEntry>((*p->fds)[tgt_fd]);
2585    if (!hbfdp)
2586        return -EBADF;
2587    int sim_fd = hbfdp->getSimFD();
2588
2589    struct pollfd pfd;
2590    pfd.fd = sim_fd;
2591    pfd.events = POLLIN | POLLPRI;
2592    if ((poll(&pfd, 1, 0) == 0)
2593        && !(hbfdp->getFlags() & OS::TGT_O_NONBLOCK))
2594        return SyscallReturn::retry();
2595
2596    BufferArg buf_arg(buf_ptr, nbytes);
2597    int bytes_read = read(sim_fd, buf_arg.bufferPtr(), nbytes);
2598
2599    if (bytes_read > 0)
2600        buf_arg.copyOut(tc->getMemProxy());
2601
2602    return (bytes_read == -1) ? -errno : bytes_read;
2603}
2604
2605template <class OS>
2606SyscallReturn
2607writeFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
2608{
2609    int index = 0;
2610    int tgt_fd = p->getSyscallArg(tc, index);
2611    Addr buf_ptr = p->getSyscallArg(tc, index);
2612    int nbytes = p->getSyscallArg(tc, index);
2613
2614    auto hbfdp = std::dynamic_pointer_cast<HBFDEntry>((*p->fds)[tgt_fd]);
2615    if (!hbfdp)
2616        return -EBADF;
2617    int sim_fd = hbfdp->getSimFD();
2618
2619    BufferArg buf_arg(buf_ptr, nbytes);
2620    buf_arg.copyIn(tc->getMemProxy());
2621
2622    struct pollfd pfd;
2623    pfd.fd = sim_fd;
2624    pfd.events = POLLOUT;
2625
2626    /**
2627     * We don't want to poll on /dev/random. The kernel will not enable the
2628     * file descriptor for writing unless the entropy in the system falls
2629     * below write_wakeup_threshold. This is not guaranteed to happen
2630     * depending on host settings.
2631     */
2632    auto ffdp = std::dynamic_pointer_cast<FileFDEntry>(hbfdp);
2633    if (ffdp && (ffdp->getFileName() != "/dev/random")) {
2634        if (!poll(&pfd, 1, 0) && !(ffdp->getFlags() & OS::TGT_O_NONBLOCK))
2635            return SyscallReturn::retry();
2636    }
2637
2638    int bytes_written = write(sim_fd, buf_arg.bufferPtr(), nbytes);
2639
2640    if (bytes_written != -1)
2641        fsync(sim_fd);
2642
2643    return (bytes_written == -1) ? -errno : bytes_written;
2644}
2645
2646template <class OS>
2647SyscallReturn
2648wait4Func(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
2649{
2650    int index = 0;
2651    pid_t pid = p->getSyscallArg(tc, index);
2652    Addr statPtr = p->getSyscallArg(tc, index);
2653    int options = p->getSyscallArg(tc, index);
2654    Addr rusagePtr = p->getSyscallArg(tc, index);
2655
2656    if (rusagePtr)
2657        DPRINTFR(SyscallVerbose,
2658                 "%d: %s: syscall wait4: rusage pointer provided however "
2659                 "functionality not supported. Ignoring rusage pointer.\n",
2660                 curTick(), tc->getCpuPtr()->name());
2661
2662    /**
2663     * Currently, wait4 is only implemented so that it will wait for children
2664     * exit conditions which are denoted by a SIGCHLD signals posted into the
2665     * system signal list. We return no additional information via any of the
2666     * parameters supplied to wait4. If nothing is found in the system signal
2667     * list, we will wait indefinitely for SIGCHLD to post by retrying the
2668     * call.
2669     */
2670    System *sysh = tc->getSystemPtr();
2671    std::list<BasicSignal>::iterator iter;
2672    for (iter=sysh->signalList.begin(); iter!=sysh->signalList.end(); iter++) {
2673        if (iter->receiver == p) {
2674            if (pid < -1) {
2675                if ((iter->sender->pgid() == -pid)
2676                    && (iter->signalValue == OS::TGT_SIGCHLD))
2677                    goto success;
2678            } else if (pid == -1) {
2679                if (iter->signalValue == OS::TGT_SIGCHLD)
2680                    goto success;
2681            } else if (pid == 0) {
2682                if ((iter->sender->pgid() == p->pgid())
2683                    && (iter->signalValue == OS::TGT_SIGCHLD))
2684                    goto success;
2685            } else {
2686                if ((iter->sender->pid() == pid)
2687                    && (iter->signalValue == OS::TGT_SIGCHLD))
2688                    goto success;
2689            }
2690        }
2691    }
2692
2693    return (options & OS::TGT_WNOHANG) ? 0 : SyscallReturn::retry();
2694
2695success:
2696    // Set status to EXITED for WIFEXITED evaluations.
2697    const int EXITED = 0;
2698    BufferArg statusBuf(statPtr, sizeof(int));
2699    *(int *)statusBuf.bufferPtr() = EXITED;
2700    statusBuf.copyOut(tc->getMemProxy());
2701
2702    // Return the child PID.
2703    pid_t retval = iter->sender->pid();
2704    sysh->signalList.erase(iter);
2705    return retval;
2706}
2707
2708template <class OS>
2709SyscallReturn
2710acceptFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
2711{
2712    struct sockaddr sa;
2713    socklen_t addrLen;
2714    int host_fd;
2715    int index = 0;
2716    int tgt_fd = p->getSyscallArg(tc, index);
2717    Addr addrPtr = p->getSyscallArg(tc, index);
2718    Addr lenPtr = p->getSyscallArg(tc, index);
2719
2720    BufferArg *lenBufPtr = nullptr;
2721    BufferArg *addrBufPtr = nullptr;
2722
2723    auto sfdp = std::dynamic_pointer_cast<SocketFDEntry>((*p->fds)[tgt_fd]);
2724    if (!sfdp)
2725        return -EBADF;
2726    int sim_fd = sfdp->getSimFD();
2727
2728    /**
2729     * We poll the socket file descriptor first to guarantee that we do not
2730     * block on our accept call. The socket can be opened without the
2731     * non-blocking flag (it blocks). This will cause deadlocks between
2732     * communicating processes.
2733     */
2734    struct pollfd pfd;
2735    pfd.fd = sim_fd;
2736    pfd.events = POLLIN | POLLPRI;
2737    if ((poll(&pfd, 1, 0) == 0)
2738        && !(sfdp->getFlags() & OS::TGT_O_NONBLOCK))
2739        return SyscallReturn::retry();
2740
2741    if (lenPtr) {
2742        lenBufPtr = new BufferArg(lenPtr, sizeof(socklen_t));
2743        lenBufPtr->copyIn(tc->getMemProxy());
2744        memcpy(&addrLen, (socklen_t *)lenBufPtr->bufferPtr(),
2745               sizeof(socklen_t));
2746    }
2747
2748    if (addrPtr) {
2749        addrBufPtr = new BufferArg(addrPtr, sizeof(struct sockaddr));
2750        addrBufPtr->copyIn(tc->getMemProxy());
2751        memcpy(&sa, (struct sockaddr *)addrBufPtr->bufferPtr(),
2752               sizeof(struct sockaddr));
2753    }
2754
2755    host_fd = accept(sim_fd, &sa, &addrLen);
2756
2757    if (host_fd == -1)
2758        return -errno;
2759
2760    if (addrPtr) {
2761        memcpy(addrBufPtr->bufferPtr(), &sa, sizeof(sa));
2762        addrBufPtr->copyOut(tc->getMemProxy());
2763        delete(addrBufPtr);
2764    }
2765
2766    if (lenPtr) {
2767        *(socklen_t *)lenBufPtr->bufferPtr() = addrLen;
2768        lenBufPtr->copyOut(tc->getMemProxy());
2769        delete(lenBufPtr);
2770    }
2771
2772    auto afdp = std::make_shared<SocketFDEntry>(host_fd, sfdp->_domain,
2773                                                sfdp->_type, sfdp->_protocol);
2774    return p->fds->allocFD(afdp);
2775}
2776
2777#endif // __SIM_SYSCALL_EMUL_HH__
2778