syscall_emul.hh revision 11385
112027Sjungma@eit.uni-kl.de/*
212027Sjungma@eit.uni-kl.de * Copyright (c) 2012-2013, 2015 ARM Limited
312027Sjungma@eit.uni-kl.de * Copyright (c) 2015 Advanced Micro Devices, Inc.
412027Sjungma@eit.uni-kl.de * All rights reserved
512027Sjungma@eit.uni-kl.de *
612027Sjungma@eit.uni-kl.de * The license below extends only to copyright in the software and shall
712027Sjungma@eit.uni-kl.de * not be construed as granting a license to any other intellectual
812027Sjungma@eit.uni-kl.de * property including but not limited to intellectual property relating
912027Sjungma@eit.uni-kl.de * to a hardware implementation of the functionality of the software
1012027Sjungma@eit.uni-kl.de * licensed hereunder.  You may use the software subject to the license
1112027Sjungma@eit.uni-kl.de * terms below provided that you ensure that this notice is replicated
1212027Sjungma@eit.uni-kl.de * unmodified and in its entirety in all distributions of the software,
1312027Sjungma@eit.uni-kl.de * modified or unmodified, in source code or in binary form.
1412027Sjungma@eit.uni-kl.de *
1512027Sjungma@eit.uni-kl.de * Copyright (c) 2003-2005 The Regents of The University of Michigan
1612027Sjungma@eit.uni-kl.de * All rights reserved.
1712027Sjungma@eit.uni-kl.de *
1812027Sjungma@eit.uni-kl.de * Redistribution and use in source and binary forms, with or without
1912027Sjungma@eit.uni-kl.de * modification, are permitted provided that the following conditions are
2012027Sjungma@eit.uni-kl.de * met: redistributions of source code must retain the above copyright
2112027Sjungma@eit.uni-kl.de * notice, this list of conditions and the following disclaimer;
2212027Sjungma@eit.uni-kl.de * redistributions in binary form must reproduce the above copyright
2312027Sjungma@eit.uni-kl.de * notice, this list of conditions and the following disclaimer in the
2412027Sjungma@eit.uni-kl.de * documentation and/or other materials provided with the distribution;
2512027Sjungma@eit.uni-kl.de * neither the name of the copyright holders nor the names of its
2612027Sjungma@eit.uni-kl.de * contributors may be used to endorse or promote products derived from
2712027Sjungma@eit.uni-kl.de * this software without specific prior written permission.
2812027Sjungma@eit.uni-kl.de *
2912027Sjungma@eit.uni-kl.de * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
3012027Sjungma@eit.uni-kl.de * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
3112027Sjungma@eit.uni-kl.de * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
3212027Sjungma@eit.uni-kl.de * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
3312027Sjungma@eit.uni-kl.de * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
3412027Sjungma@eit.uni-kl.de * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
3512027Sjungma@eit.uni-kl.de * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
3612027Sjungma@eit.uni-kl.de * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
3712027Sjungma@eit.uni-kl.de * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
3812027Sjungma@eit.uni-kl.de * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
3912027Sjungma@eit.uni-kl.de * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
4012027Sjungma@eit.uni-kl.de *
4112027Sjungma@eit.uni-kl.de * Authors: Steve Reinhardt
4212027Sjungma@eit.uni-kl.de *          Kevin Lim
4312027Sjungma@eit.uni-kl.de */
4412027Sjungma@eit.uni-kl.de
4512027Sjungma@eit.uni-kl.de#ifndef __SIM_SYSCALL_EMUL_HH__
4612027Sjungma@eit.uni-kl.de#define __SIM_SYSCALL_EMUL_HH__
4712027Sjungma@eit.uni-kl.de
4812027Sjungma@eit.uni-kl.de#define NO_STAT64 (defined(__APPLE__) || defined(__OpenBSD__) || \
4912027Sjungma@eit.uni-kl.de  defined(__FreeBSD__) || defined(__CYGWIN__) || \
5012027Sjungma@eit.uni-kl.de  defined(__NetBSD__))
5112027Sjungma@eit.uni-kl.de
5212027Sjungma@eit.uni-kl.de///
5312027Sjungma@eit.uni-kl.de/// @file syscall_emul.hh
5412027Sjungma@eit.uni-kl.de///
5512027Sjungma@eit.uni-kl.de/// This file defines objects used to emulate syscalls from the target
5612027Sjungma@eit.uni-kl.de/// application on the host machine.
5712027Sjungma@eit.uni-kl.de
5812027Sjungma@eit.uni-kl.de#ifdef __CYGWIN32__
5912027Sjungma@eit.uni-kl.de#include <sys/fcntl.h>  // for O_BINARY
6012027Sjungma@eit.uni-kl.de#endif
6112027Sjungma@eit.uni-kl.de#include <sys/mman.h>
6212027Sjungma@eit.uni-kl.de#include <sys/stat.h>
6312027Sjungma@eit.uni-kl.de#include <sys/time.h>
6412027Sjungma@eit.uni-kl.de#include <sys/uio.h>
6512027Sjungma@eit.uni-kl.de#include <fcntl.h>
6612027Sjungma@eit.uni-kl.de
6712027Sjungma@eit.uni-kl.de#include <cerrno>
6812027Sjungma@eit.uni-kl.de#include <string>
6912027Sjungma@eit.uni-kl.de
7012027Sjungma@eit.uni-kl.de#include "base/chunk_generator.hh"
7112027Sjungma@eit.uni-kl.de#include "base/intmath.hh"      // for RoundUp
7212027Sjungma@eit.uni-kl.de#include "base/misc.hh"
7312027Sjungma@eit.uni-kl.de#include "base/trace.hh"
7412027Sjungma@eit.uni-kl.de#include "base/types.hh"
7512027Sjungma@eit.uni-kl.de#include "config/the_isa.hh"
7612027Sjungma@eit.uni-kl.de#include "cpu/base.hh"
7712027Sjungma@eit.uni-kl.de#include "cpu/thread_context.hh"
7812027Sjungma@eit.uni-kl.de#include "debug/SyscallBase.hh"
7912027Sjungma@eit.uni-kl.de#include "debug/SyscallVerbose.hh"
8012027Sjungma@eit.uni-kl.de#include "mem/page_table.hh"
8112027Sjungma@eit.uni-kl.de#include "sim/byteswap.hh"
8212027Sjungma@eit.uni-kl.de#include "sim/emul_driver.hh"
8312027Sjungma@eit.uni-kl.de#include "sim/process.hh"
8412027Sjungma@eit.uni-kl.de#include "sim/syscall_emul_buf.hh"
8512027Sjungma@eit.uni-kl.de#include "sim/syscallreturn.hh"
8612027Sjungma@eit.uni-kl.de#include "sim/system.hh"
8712027Sjungma@eit.uni-kl.de
8812027Sjungma@eit.uni-kl.de// This wrapper macro helps out with readability a bit. FLAGEXT specifies
8912027Sjungma@eit.uni-kl.de// the verbosity and FMT is the message to be appended to the syscall
9012027Sjungma@eit.uni-kl.de// header information. The syscall header information contains the cpuid
9112027Sjungma@eit.uni-kl.de// and thread id.
9212027Sjungma@eit.uni-kl.de#define DPRINTF_SYSCALL(FLAGEXT, FMT, ...)                                  \
9312027Sjungma@eit.uni-kl.de    DPRINTFS(Syscall##FLAGEXT, tc->getCpuPtr(), "T%d : syscall " FMT,       \
9412027Sjungma@eit.uni-kl.de             tc->threadId(), __VA_ARGS__)
9512027Sjungma@eit.uni-kl.de
9612027Sjungma@eit.uni-kl.de///
9712027Sjungma@eit.uni-kl.de/// System call descriptor.
9812027Sjungma@eit.uni-kl.de///
9912027Sjungma@eit.uni-kl.declass SyscallDesc {
10012027Sjungma@eit.uni-kl.de
10112027Sjungma@eit.uni-kl.de  public:
10212027Sjungma@eit.uni-kl.de
10312027Sjungma@eit.uni-kl.de    /// Typedef for target syscall handler functions.
10412027Sjungma@eit.uni-kl.de    typedef SyscallReturn (*FuncPtr)(SyscallDesc *, int num,
10512027Sjungma@eit.uni-kl.de                           LiveProcess *, ThreadContext *);
10612027Sjungma@eit.uni-kl.de
10712027Sjungma@eit.uni-kl.de    const char *name;   //!< Syscall name (e.g., "open").
10812027Sjungma@eit.uni-kl.de    FuncPtr funcPtr;    //!< Pointer to emulation function.
10912027Sjungma@eit.uni-kl.de    int flags;          //!< Flags (see Flags enum).
11012027Sjungma@eit.uni-kl.de    bool warned;        //!< Have we warned about unimplemented syscall?
11112027Sjungma@eit.uni-kl.de
11212027Sjungma@eit.uni-kl.de    /// Flag values for controlling syscall behavior.
11312027Sjungma@eit.uni-kl.de    enum Flags {
11412027Sjungma@eit.uni-kl.de        /// Don't set return regs according to funcPtr return value.
11512027Sjungma@eit.uni-kl.de        /// Used for syscalls with non-standard return conventions
11612027Sjungma@eit.uni-kl.de        /// that explicitly set the ThreadContext regs (e.g.,
11712027Sjungma@eit.uni-kl.de        /// sigreturn).
11812027Sjungma@eit.uni-kl.de        SuppressReturnValue = 1,
11912027Sjungma@eit.uni-kl.de        WarnOnce = 2
12012027Sjungma@eit.uni-kl.de    };
12112027Sjungma@eit.uni-kl.de
12212027Sjungma@eit.uni-kl.de    /// Constructor.
12312027Sjungma@eit.uni-kl.de    SyscallDesc(const char *_name, FuncPtr _funcPtr, int _flags = 0)
12412027Sjungma@eit.uni-kl.de        : name(_name), funcPtr(_funcPtr), flags(_flags), warned(false)
12512027Sjungma@eit.uni-kl.de    {
12612027Sjungma@eit.uni-kl.de    }
12712027Sjungma@eit.uni-kl.de
12812027Sjungma@eit.uni-kl.de    /// Emulate the syscall.  Public interface for calling through funcPtr.
12912027Sjungma@eit.uni-kl.de    void doSyscall(int callnum, LiveProcess *proc, ThreadContext *tc);
13012027Sjungma@eit.uni-kl.de
13112027Sjungma@eit.uni-kl.de    /// Is the WarnOnce flag set?
13212027Sjungma@eit.uni-kl.de    bool warnOnce() const {  return (flags & WarnOnce); }
13312027Sjungma@eit.uni-kl.de};
13412027Sjungma@eit.uni-kl.de
13512027Sjungma@eit.uni-kl.de
13612027Sjungma@eit.uni-kl.de//////////////////////////////////////////////////////////////////////
13712027Sjungma@eit.uni-kl.de//
13812027Sjungma@eit.uni-kl.de// The following emulation functions are generic enough that they
13912027Sjungma@eit.uni-kl.de// don't need to be recompiled for different emulated OS's.  They are
14012027Sjungma@eit.uni-kl.de// defined in sim/syscall_emul.cc.
14112027Sjungma@eit.uni-kl.de//
14212027Sjungma@eit.uni-kl.de//////////////////////////////////////////////////////////////////////
14312027Sjungma@eit.uni-kl.de
14412027Sjungma@eit.uni-kl.de
14512027Sjungma@eit.uni-kl.de/// Handler for unimplemented syscalls that we haven't thought about.
14612027Sjungma@eit.uni-kl.deSyscallReturn unimplementedFunc(SyscallDesc *desc, int num,
14712027Sjungma@eit.uni-kl.de                                LiveProcess *p, ThreadContext *tc);
14812027Sjungma@eit.uni-kl.de
14912027Sjungma@eit.uni-kl.de/// Handler for unimplemented syscalls that we never intend to
15012027Sjungma@eit.uni-kl.de/// implement (signal handling, etc.) and should not affect the correct
15112027Sjungma@eit.uni-kl.de/// behavior of the program.  Print a warning only if the appropriate
15212027Sjungma@eit.uni-kl.de/// trace flag is enabled.  Return success to the target program.
15312027Sjungma@eit.uni-kl.deSyscallReturn ignoreFunc(SyscallDesc *desc, int num,
15412027Sjungma@eit.uni-kl.de                         LiveProcess *p, ThreadContext *tc);
15512027Sjungma@eit.uni-kl.de
156/// Target exit() handler: terminate current context.
157SyscallReturn exitFunc(SyscallDesc *desc, int num,
158                       LiveProcess *p, ThreadContext *tc);
159
160/// Target exit_group() handler: terminate simulation. (exit all threads)
161SyscallReturn exitGroupFunc(SyscallDesc *desc, int num,
162                       LiveProcess *p, ThreadContext *tc);
163
164/// Target getpagesize() handler.
165SyscallReturn getpagesizeFunc(SyscallDesc *desc, int num,
166                              LiveProcess *p, ThreadContext *tc);
167
168/// Target brk() handler: set brk address.
169SyscallReturn brkFunc(SyscallDesc *desc, int num,
170                      LiveProcess *p, ThreadContext *tc);
171
172/// Target close() handler.
173SyscallReturn closeFunc(SyscallDesc *desc, int num,
174                        LiveProcess *p, ThreadContext *tc);
175
176/// Target read() handler.
177SyscallReturn readFunc(SyscallDesc *desc, int num,
178                       LiveProcess *p, ThreadContext *tc);
179
180/// Target write() handler.
181SyscallReturn writeFunc(SyscallDesc *desc, int num,
182                        LiveProcess *p, ThreadContext *tc);
183
184/// Target lseek() handler.
185SyscallReturn lseekFunc(SyscallDesc *desc, int num,
186                        LiveProcess *p, ThreadContext *tc);
187
188/// Target _llseek() handler.
189SyscallReturn _llseekFunc(SyscallDesc *desc, int num,
190                        LiveProcess *p, ThreadContext *tc);
191
192/// Target munmap() handler.
193SyscallReturn munmapFunc(SyscallDesc *desc, int num,
194                         LiveProcess *p, ThreadContext *tc);
195
196/// Target gethostname() handler.
197SyscallReturn gethostnameFunc(SyscallDesc *desc, int num,
198                              LiveProcess *p, ThreadContext *tc);
199
200/// Target getcwd() handler.
201SyscallReturn getcwdFunc(SyscallDesc *desc, int num,
202                         LiveProcess *p, ThreadContext *tc);
203
204/// Target readlink() handler.
205SyscallReturn readlinkFunc(SyscallDesc *desc, int num,
206                           LiveProcess *p, ThreadContext *tc,
207                           int index = 0);
208SyscallReturn readlinkFunc(SyscallDesc *desc, int num,
209                           LiveProcess *p, ThreadContext *tc);
210
211/// Target unlink() handler.
212SyscallReturn unlinkHelper(SyscallDesc *desc, int num,
213                           LiveProcess *p, ThreadContext *tc,
214                           int index);
215SyscallReturn unlinkFunc(SyscallDesc *desc, int num,
216                         LiveProcess *p, ThreadContext *tc);
217
218/// Target mkdir() handler.
219SyscallReturn mkdirFunc(SyscallDesc *desc, int num,
220                        LiveProcess *p, ThreadContext *tc);
221
222/// Target rename() handler.
223SyscallReturn renameFunc(SyscallDesc *desc, int num,
224                         LiveProcess *p, ThreadContext *tc);
225
226
227/// Target truncate() handler.
228SyscallReturn truncateFunc(SyscallDesc *desc, int num,
229                           LiveProcess *p, ThreadContext *tc);
230
231
232/// Target ftruncate() handler.
233SyscallReturn ftruncateFunc(SyscallDesc *desc, int num,
234                            LiveProcess *p, ThreadContext *tc);
235
236
237/// Target truncate64() handler.
238SyscallReturn truncate64Func(SyscallDesc *desc, int num,
239                             LiveProcess *p, ThreadContext *tc);
240
241/// Target ftruncate64() handler.
242SyscallReturn ftruncate64Func(SyscallDesc *desc, int num,
243                              LiveProcess *p, ThreadContext *tc);
244
245
246/// Target umask() handler.
247SyscallReturn umaskFunc(SyscallDesc *desc, int num,
248                        LiveProcess *p, ThreadContext *tc);
249
250
251/// Target chown() handler.
252SyscallReturn chownFunc(SyscallDesc *desc, int num,
253                        LiveProcess *p, ThreadContext *tc);
254
255
256/// Target fchown() handler.
257SyscallReturn fchownFunc(SyscallDesc *desc, int num,
258                         LiveProcess *p, ThreadContext *tc);
259
260/// Target dup() handler.
261SyscallReturn dupFunc(SyscallDesc *desc, int num,
262                      LiveProcess *process, ThreadContext *tc);
263
264/// Target fnctl() handler.
265SyscallReturn fcntlFunc(SyscallDesc *desc, int num,
266                        LiveProcess *process, ThreadContext *tc);
267
268/// Target fcntl64() handler.
269SyscallReturn fcntl64Func(SyscallDesc *desc, int num,
270                        LiveProcess *process, ThreadContext *tc);
271
272/// Target setuid() handler.
273SyscallReturn setuidFunc(SyscallDesc *desc, int num,
274                               LiveProcess *p, ThreadContext *tc);
275
276/// Target getpid() handler.
277SyscallReturn getpidFunc(SyscallDesc *desc, int num,
278                               LiveProcess *p, ThreadContext *tc);
279
280/// Target getuid() handler.
281SyscallReturn getuidFunc(SyscallDesc *desc, int num,
282                               LiveProcess *p, ThreadContext *tc);
283
284/// Target getgid() handler.
285SyscallReturn getgidFunc(SyscallDesc *desc, int num,
286                               LiveProcess *p, ThreadContext *tc);
287
288/// Target getppid() handler.
289SyscallReturn getppidFunc(SyscallDesc *desc, int num,
290                               LiveProcess *p, ThreadContext *tc);
291
292/// Target geteuid() handler.
293SyscallReturn geteuidFunc(SyscallDesc *desc, int num,
294                               LiveProcess *p, ThreadContext *tc);
295
296/// Target getegid() handler.
297SyscallReturn getegidFunc(SyscallDesc *desc, int num,
298                               LiveProcess *p, ThreadContext *tc);
299
300/// Target clone() handler.
301SyscallReturn cloneFunc(SyscallDesc *desc, int num,
302                               LiveProcess *p, ThreadContext *tc);
303
304/// Target access() handler
305SyscallReturn accessFunc(SyscallDesc *desc, int num,
306                               LiveProcess *p, ThreadContext *tc);
307SyscallReturn accessFunc(SyscallDesc *desc, int num,
308                               LiveProcess *p, ThreadContext *tc,
309                               int index);
310
311/// Futex system call
312///  Implemented by Daniel Sanchez
313///  Used by printf's in multi-threaded apps
314template <class OS>
315SyscallReturn
316futexFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
317          ThreadContext *tc)
318{
319    int index_uaddr = 0;
320    int index_op = 1;
321    int index_val = 2;
322    int index_timeout = 3;
323
324    uint64_t uaddr = process->getSyscallArg(tc, index_uaddr);
325    int op = process->getSyscallArg(tc, index_op);
326    int val = process->getSyscallArg(tc, index_val);
327    uint64_t timeout = process->getSyscallArg(tc, index_timeout);
328
329    std::map<uint64_t, std::list<ThreadContext *> * >
330        &futex_map = tc->getSystemPtr()->futexMap;
331
332    DPRINTF(SyscallVerbose, "In sys_futex: Address=%llx, op=%d, val=%d\n",
333            uaddr, op, val);
334
335    op &= ~OS::TGT_FUTEX_PRIVATE_FLAG;
336
337    if (op == OS::TGT_FUTEX_WAIT) {
338        if (timeout != 0) {
339            warn("sys_futex: FUTEX_WAIT with non-null timeout unimplemented;"
340                 "we'll wait indefinitely");
341        }
342
343        uint8_t *buf = new uint8_t[sizeof(int)];
344        tc->getMemProxy().readBlob((Addr)uaddr, buf, (int)sizeof(int));
345        int mem_val = *((int *)buf);
346        delete[] buf;
347
348        if (val != mem_val) {
349            DPRINTF(SyscallVerbose, "sys_futex: FUTEX_WAKE, read: %d, "
350                                    "expected: %d\n", mem_val, val);
351            return -OS::TGT_EWOULDBLOCK;
352        }
353
354        // Queue the thread context
355        std::list<ThreadContext *> * tcWaitList;
356        if (futex_map.count(uaddr)) {
357            tcWaitList = futex_map.find(uaddr)->second;
358        } else {
359            tcWaitList = new std::list<ThreadContext *>();
360            futex_map.insert(std::pair< uint64_t,
361                            std::list<ThreadContext *> * >(uaddr, tcWaitList));
362        }
363        tcWaitList->push_back(tc);
364        DPRINTF(SyscallVerbose, "sys_futex: FUTEX_WAIT, suspending calling "
365                                "thread context\n");
366        tc->suspend();
367        return 0;
368    } else if (op == OS::TGT_FUTEX_WAKE){
369        int wokenUp = 0;
370        std::list<ThreadContext *> * tcWaitList;
371        if (futex_map.count(uaddr)) {
372            tcWaitList = futex_map.find(uaddr)->second;
373            while (tcWaitList->size() > 0 && wokenUp < val) {
374                tcWaitList->front()->activate();
375                tcWaitList->pop_front();
376                wokenUp++;
377            }
378            if (tcWaitList->empty()) {
379                futex_map.erase(uaddr);
380                delete tcWaitList;
381            }
382        }
383        DPRINTF(SyscallVerbose, "sys_futex: FUTEX_WAKE, activated %d waiting "
384                                "thread contexts\n", wokenUp);
385        return wokenUp;
386    } else {
387        warn("sys_futex: op %d is not implemented, just returning...", op);
388        return 0;
389    }
390
391}
392
393
394/// Pseudo Funcs  - These functions use a different return convension,
395/// returning a second value in a register other than the normal return register
396SyscallReturn pipePseudoFunc(SyscallDesc *desc, int num,
397                             LiveProcess *process, ThreadContext *tc);
398
399/// Target getpidPseudo() handler.
400SyscallReturn getpidPseudoFunc(SyscallDesc *desc, int num,
401                               LiveProcess *p, ThreadContext *tc);
402
403/// Target getuidPseudo() handler.
404SyscallReturn getuidPseudoFunc(SyscallDesc *desc, int num,
405                               LiveProcess *p, ThreadContext *tc);
406
407/// Target getgidPseudo() handler.
408SyscallReturn getgidPseudoFunc(SyscallDesc *desc, int num,
409                               LiveProcess *p, ThreadContext *tc);
410
411
412/// A readable name for 1,000,000, for converting microseconds to seconds.
413const int one_million = 1000000;
414/// A readable name for 1,000,000,000, for converting nanoseconds to seconds.
415const int one_billion = 1000000000;
416
417/// Approximate seconds since the epoch (1/1/1970).  About a billion,
418/// by my reckoning.  We want to keep this a constant (not use the
419/// real-world time) to keep simulations repeatable.
420const unsigned seconds_since_epoch = 1000000000;
421
422/// Helper function to convert current elapsed time to seconds and
423/// microseconds.
424template <class T1, class T2>
425void
426getElapsedTimeMicro(T1 &sec, T2 &usec)
427{
428    uint64_t elapsed_usecs = curTick() / SimClock::Int::us;
429    sec = elapsed_usecs / one_million;
430    usec = elapsed_usecs % one_million;
431}
432
433/// Helper function to convert current elapsed time to seconds and
434/// nanoseconds.
435template <class T1, class T2>
436void
437getElapsedTimeNano(T1 &sec, T2 &nsec)
438{
439    uint64_t elapsed_nsecs = curTick() / SimClock::Int::ns;
440    sec = elapsed_nsecs / one_billion;
441    nsec = elapsed_nsecs % one_billion;
442}
443
444//////////////////////////////////////////////////////////////////////
445//
446// The following emulation functions are generic, but need to be
447// templated to account for differences in types, constants, etc.
448//
449//////////////////////////////////////////////////////////////////////
450
451#if NO_STAT64
452    typedef struct stat hst_stat;
453    typedef struct stat hst_stat64;
454#else
455    typedef struct stat hst_stat;
456    typedef struct stat64 hst_stat64;
457#endif
458
459//// Helper function to convert a host stat buffer to a target stat
460//// buffer.  Also copies the target buffer out to the simulated
461//// memory space.  Used by stat(), fstat(), and lstat().
462
463template <typename target_stat, typename host_stat>
464static void
465convertStatBuf(target_stat &tgt, host_stat *host, bool fakeTTY = false)
466{
467    using namespace TheISA;
468
469    if (fakeTTY)
470        tgt->st_dev = 0xA;
471    else
472        tgt->st_dev = host->st_dev;
473    tgt->st_dev = TheISA::htog(tgt->st_dev);
474    tgt->st_ino = host->st_ino;
475    tgt->st_ino = TheISA::htog(tgt->st_ino);
476    tgt->st_mode = host->st_mode;
477    if (fakeTTY) {
478        // Claim to be a character device
479        tgt->st_mode &= ~S_IFMT;    // Clear S_IFMT
480        tgt->st_mode |= S_IFCHR;    // Set S_IFCHR
481    }
482    tgt->st_mode = TheISA::htog(tgt->st_mode);
483    tgt->st_nlink = host->st_nlink;
484    tgt->st_nlink = TheISA::htog(tgt->st_nlink);
485    tgt->st_uid = host->st_uid;
486    tgt->st_uid = TheISA::htog(tgt->st_uid);
487    tgt->st_gid = host->st_gid;
488    tgt->st_gid = TheISA::htog(tgt->st_gid);
489    if (fakeTTY)
490        tgt->st_rdev = 0x880d;
491    else
492        tgt->st_rdev = host->st_rdev;
493    tgt->st_rdev = TheISA::htog(tgt->st_rdev);
494    tgt->st_size = host->st_size;
495    tgt->st_size = TheISA::htog(tgt->st_size);
496    tgt->st_atimeX = host->st_atime;
497    tgt->st_atimeX = TheISA::htog(tgt->st_atimeX);
498    tgt->st_mtimeX = host->st_mtime;
499    tgt->st_mtimeX = TheISA::htog(tgt->st_mtimeX);
500    tgt->st_ctimeX = host->st_ctime;
501    tgt->st_ctimeX = TheISA::htog(tgt->st_ctimeX);
502    // Force the block size to be 8k. This helps to ensure buffered io works
503    // consistently across different hosts.
504    tgt->st_blksize = 0x2000;
505    tgt->st_blksize = TheISA::htog(tgt->st_blksize);
506    tgt->st_blocks = host->st_blocks;
507    tgt->st_blocks = TheISA::htog(tgt->st_blocks);
508}
509
510// Same for stat64
511
512template <typename target_stat, typename host_stat64>
513static void
514convertStat64Buf(target_stat &tgt, host_stat64 *host, bool fakeTTY = false)
515{
516    using namespace TheISA;
517
518    convertStatBuf<target_stat, host_stat64>(tgt, host, fakeTTY);
519#if defined(STAT_HAVE_NSEC)
520    tgt->st_atime_nsec = host->st_atime_nsec;
521    tgt->st_atime_nsec = TheISA::htog(tgt->st_atime_nsec);
522    tgt->st_mtime_nsec = host->st_mtime_nsec;
523    tgt->st_mtime_nsec = TheISA::htog(tgt->st_mtime_nsec);
524    tgt->st_ctime_nsec = host->st_ctime_nsec;
525    tgt->st_ctime_nsec = TheISA::htog(tgt->st_ctime_nsec);
526#else
527    tgt->st_atime_nsec = 0;
528    tgt->st_mtime_nsec = 0;
529    tgt->st_ctime_nsec = 0;
530#endif
531}
532
533//Here are a couple convenience functions
534template<class OS>
535static void
536copyOutStatBuf(SETranslatingPortProxy &mem, Addr addr,
537        hst_stat *host, bool fakeTTY = false)
538{
539    typedef TypedBufferArg<typename OS::tgt_stat> tgt_stat_buf;
540    tgt_stat_buf tgt(addr);
541    convertStatBuf<tgt_stat_buf, hst_stat>(tgt, host, fakeTTY);
542    tgt.copyOut(mem);
543}
544
545template<class OS>
546static void
547copyOutStat64Buf(SETranslatingPortProxy &mem, Addr addr,
548        hst_stat64 *host, bool fakeTTY = false)
549{
550    typedef TypedBufferArg<typename OS::tgt_stat64> tgt_stat_buf;
551    tgt_stat_buf tgt(addr);
552    convertStat64Buf<tgt_stat_buf, hst_stat64>(tgt, host, fakeTTY);
553    tgt.copyOut(mem);
554}
555
556/// Target ioctl() handler.  For the most part, programs call ioctl()
557/// only to find out if their stdout is a tty, to determine whether to
558/// do line or block buffering.  We always claim that output fds are
559/// not TTYs to provide repeatable results.
560template <class OS>
561SyscallReturn
562ioctlFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
563          ThreadContext *tc)
564{
565    int index = 0;
566    int tgt_fd = process->getSyscallArg(tc, index);
567    unsigned req = process->getSyscallArg(tc, index);
568
569    DPRINTF(SyscallVerbose, "ioctl(%d, 0x%x, ...)\n", tgt_fd, req);
570
571    FDEntry *fde = process->getFDEntry(tgt_fd);
572
573    if (fde == NULL) {
574        // doesn't map to any simulator fd: not a valid target fd
575        return -EBADF;
576    }
577
578    if (fde->driver != NULL) {
579        return fde->driver->ioctl(process, tc, req);
580    }
581
582    if (OS::isTtyReq(req)) {
583        return -ENOTTY;
584    }
585
586    warn("Unsupported ioctl call: ioctl(%d, 0x%x, ...) @ \n",
587         tgt_fd, req, tc->pcState());
588    return -ENOTTY;
589}
590
591template <class OS>
592static SyscallReturn
593openFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
594         ThreadContext *tc, int index)
595{
596    std::string path;
597
598    if (!tc->getMemProxy().tryReadString(path,
599                process->getSyscallArg(tc, index)))
600        return -EFAULT;
601
602    int tgtFlags = process->getSyscallArg(tc, index);
603    int mode = process->getSyscallArg(tc, index);
604    int hostFlags = 0;
605
606    // translate open flags
607    for (int i = 0; i < OS::NUM_OPEN_FLAGS; i++) {
608        if (tgtFlags & OS::openFlagTable[i].tgtFlag) {
609            tgtFlags &= ~OS::openFlagTable[i].tgtFlag;
610            hostFlags |= OS::openFlagTable[i].hostFlag;
611        }
612    }
613
614    // any target flags left?
615    if (tgtFlags != 0)
616        warn("Syscall: open: cannot decode flags 0x%x", tgtFlags);
617
618#ifdef __CYGWIN32__
619    hostFlags |= O_BINARY;
620#endif
621
622    // Adjust path for current working directory
623    path = process->fullPath(path);
624
625    DPRINTF(SyscallVerbose, "opening file %s\n", path.c_str());
626
627    if (startswith(path, "/dev/")) {
628        std::string filename = path.substr(strlen("/dev/"));
629        if (filename == "sysdev0") {
630            // This is a memory-mapped high-resolution timer device on Alpha.
631            // We don't support it, so just punt.
632            warn("Ignoring open(%s, ...)\n", path);
633            return -ENOENT;
634        }
635
636        EmulatedDriver *drv = process->findDriver(filename);
637        if (drv != NULL) {
638            // the driver's open method will allocate a fd from the
639            // process if necessary.
640            return drv->open(process, tc, mode, hostFlags);
641        }
642
643        // fall through here for pass through to host devices, such as
644        // /dev/zero
645    }
646
647    int fd;
648    int local_errno;
649    if (startswith(path, "/proc/") || startswith(path, "/system/") ||
650        startswith(path, "/platform/") || startswith(path, "/sys/")) {
651        // It's a proc/sys entry and requires special handling
652        fd = OS::openSpecialFile(path, process, tc);
653        local_errno = ENOENT;
654     } else {
655        // open the file
656        fd = open(path.c_str(), hostFlags, mode);
657        local_errno = errno;
658     }
659
660    if (fd == -1)
661        return -local_errno;
662
663    return process->allocFD(fd, path.c_str(), hostFlags, mode, false);
664}
665
666/// Target open() handler.
667template <class OS>
668SyscallReturn
669openFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
670         ThreadContext *tc)
671{
672    return openFunc<OS>(desc, callnum, process, tc, 0);
673}
674
675/// Target openat() handler.
676template <class OS>
677SyscallReturn
678openatFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
679         ThreadContext *tc)
680{
681    int index = 0;
682    int dirfd = process->getSyscallArg(tc, index);
683    if (dirfd != OS::TGT_AT_FDCWD)
684        warn("openat: first argument not AT_FDCWD; unlikely to work");
685    return openFunc<OS>(desc, callnum, process, tc, 1);
686}
687
688/// Target unlinkat() handler.
689template <class OS>
690SyscallReturn
691unlinkatFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
692             ThreadContext *tc)
693{
694    int index = 0;
695    int dirfd = process->getSyscallArg(tc, index);
696    if (dirfd != OS::TGT_AT_FDCWD)
697        warn("unlinkat: first argument not AT_FDCWD; unlikely to work");
698
699    return unlinkHelper(desc, callnum, process, tc, 1);
700}
701
702/// Target facessat() handler
703template <class OS>
704SyscallReturn
705faccessatFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
706        ThreadContext *tc)
707{
708    int index = 0;
709    int dirfd = process->getSyscallArg(tc, index);
710    if (dirfd != OS::TGT_AT_FDCWD)
711        warn("faccessat: first argument not AT_FDCWD; unlikely to work");
712    return accessFunc(desc, callnum, process, tc, 1);
713}
714
715/// Target readlinkat() handler
716template <class OS>
717SyscallReturn
718readlinkatFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
719        ThreadContext *tc)
720{
721    int index = 0;
722    int dirfd = process->getSyscallArg(tc, index);
723    if (dirfd != OS::TGT_AT_FDCWD)
724        warn("openat: first argument not AT_FDCWD; unlikely to work");
725    return readlinkFunc(desc, callnum, process, tc, 1);
726}
727
728/// Target renameat() handler.
729template <class OS>
730SyscallReturn
731renameatFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
732             ThreadContext *tc)
733{
734    int index = 0;
735
736    int olddirfd = process->getSyscallArg(tc, index);
737    if (olddirfd != OS::TGT_AT_FDCWD)
738        warn("renameat: first argument not AT_FDCWD; unlikely to work");
739
740    std::string old_name;
741
742    if (!tc->getMemProxy().tryReadString(old_name,
743                                         process->getSyscallArg(tc, index)))
744        return -EFAULT;
745
746    int newdirfd = process->getSyscallArg(tc, index);
747    if (newdirfd != OS::TGT_AT_FDCWD)
748        warn("renameat: third argument not AT_FDCWD; unlikely to work");
749
750    std::string new_name;
751
752    if (!tc->getMemProxy().tryReadString(new_name,
753                                         process->getSyscallArg(tc, index)))
754        return -EFAULT;
755
756    // Adjust path for current working directory
757    old_name = process->fullPath(old_name);
758    new_name = process->fullPath(new_name);
759
760    int result = rename(old_name.c_str(), new_name.c_str());
761    return (result == -1) ? -errno : result;
762}
763
764/// Target sysinfo() handler.
765template <class OS>
766SyscallReturn
767sysinfoFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
768         ThreadContext *tc)
769{
770
771    int index = 0;
772    TypedBufferArg<typename OS::tgt_sysinfo>
773        sysinfo(process->getSyscallArg(tc, index));
774
775    sysinfo->uptime=seconds_since_epoch;
776    sysinfo->totalram=process->system->memSize();
777
778    sysinfo.copyOut(tc->getMemProxy());
779
780    return 0;
781}
782
783/// Target chmod() handler.
784template <class OS>
785SyscallReturn
786chmodFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
787          ThreadContext *tc)
788{
789    std::string path;
790
791    int index = 0;
792    if (!tc->getMemProxy().tryReadString(path,
793                process->getSyscallArg(tc, index))) {
794        return -EFAULT;
795    }
796
797    uint32_t mode = process->getSyscallArg(tc, index);
798    mode_t hostMode = 0;
799
800    // XXX translate mode flags via OS::something???
801    hostMode = mode;
802
803    // Adjust path for current working directory
804    path = process->fullPath(path);
805
806    // do the chmod
807    int result = chmod(path.c_str(), hostMode);
808    if (result < 0)
809        return -errno;
810
811    return 0;
812}
813
814
815/// Target fchmod() handler.
816template <class OS>
817SyscallReturn
818fchmodFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
819           ThreadContext *tc)
820{
821    int index = 0;
822    int tgt_fd = process->getSyscallArg(tc, index);
823    uint32_t mode = process->getSyscallArg(tc, index);
824
825    int sim_fd = process->getSimFD(tgt_fd);
826    if (sim_fd < 0)
827        return -EBADF;
828
829    mode_t hostMode = 0;
830
831    // XXX translate mode flags via OS::someting???
832    hostMode = mode;
833
834    // do the fchmod
835    int result = fchmod(sim_fd, hostMode);
836    if (result < 0)
837        return -errno;
838
839    return 0;
840}
841
842/// Target mremap() handler.
843template <class OS>
844SyscallReturn
845mremapFunc(SyscallDesc *desc, int callnum, LiveProcess *process, ThreadContext *tc)
846{
847    int index = 0;
848    Addr start = process->getSyscallArg(tc, index);
849    uint64_t old_length = process->getSyscallArg(tc, index);
850    uint64_t new_length = process->getSyscallArg(tc, index);
851    uint64_t flags = process->getSyscallArg(tc, index);
852    uint64_t provided_address = 0;
853    bool use_provided_address = flags & OS::TGT_MREMAP_FIXED;
854
855    if (use_provided_address)
856        provided_address = process->getSyscallArg(tc, index);
857
858    if ((start % TheISA::PageBytes != 0) ||
859        (provided_address % TheISA::PageBytes != 0)) {
860        warn("mremap failing: arguments not page aligned");
861        return -EINVAL;
862    }
863
864    new_length = roundUp(new_length, TheISA::PageBytes);
865
866    if (new_length > old_length) {
867        if ((start + old_length) == process->mmap_end &&
868            (!use_provided_address || provided_address == start)) {
869            uint64_t diff = new_length - old_length;
870            process->allocateMem(process->mmap_end, diff);
871            process->mmap_end += diff;
872            return start;
873        } else {
874            if (!use_provided_address && !(flags & OS::TGT_MREMAP_MAYMOVE)) {
875                warn("can't remap here and MREMAP_MAYMOVE flag not set\n");
876                return -ENOMEM;
877            } else {
878                uint64_t new_start = use_provided_address ?
879                    provided_address : process->mmap_end;
880                process->pTable->remap(start, old_length, new_start);
881                warn("mremapping to new vaddr %08p-%08p, adding %d\n",
882                     new_start, new_start + new_length,
883                     new_length - old_length);
884                // add on the remaining unallocated pages
885                process->allocateMem(new_start + old_length,
886                                     new_length - old_length,
887                                     use_provided_address /* clobber */);
888                if (!use_provided_address)
889                    process->mmap_end += new_length;
890                if (use_provided_address &&
891                    new_start + new_length > process->mmap_end) {
892                    // something fishy going on here, at least notify the user
893                    // @todo: increase mmap_end?
894                    warn("mmap region limit exceeded with MREMAP_FIXED\n");
895                }
896                warn("returning %08p as start\n", new_start);
897                return new_start;
898            }
899        }
900    } else {
901        if (use_provided_address && provided_address != start)
902            process->pTable->remap(start, new_length, provided_address);
903        process->pTable->unmap(start + new_length, old_length - new_length);
904        return use_provided_address ? provided_address : start;
905    }
906}
907
908/// Target stat() handler.
909template <class OS>
910SyscallReturn
911statFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
912         ThreadContext *tc)
913{
914    std::string path;
915
916    int index = 0;
917    if (!tc->getMemProxy().tryReadString(path,
918                process->getSyscallArg(tc, index))) {
919        return -EFAULT;
920    }
921    Addr bufPtr = process->getSyscallArg(tc, index);
922
923    // Adjust path for current working directory
924    path = process->fullPath(path);
925
926    struct stat hostBuf;
927    int result = stat(path.c_str(), &hostBuf);
928
929    if (result < 0)
930        return -errno;
931
932    copyOutStatBuf<OS>(tc->getMemProxy(), bufPtr, &hostBuf);
933
934    return 0;
935}
936
937
938/// Target stat64() handler.
939template <class OS>
940SyscallReturn
941stat64Func(SyscallDesc *desc, int callnum, LiveProcess *process,
942           ThreadContext *tc)
943{
944    std::string path;
945
946    int index = 0;
947    if (!tc->getMemProxy().tryReadString(path,
948                process->getSyscallArg(tc, index)))
949        return -EFAULT;
950    Addr bufPtr = process->getSyscallArg(tc, index);
951
952    // Adjust path for current working directory
953    path = process->fullPath(path);
954
955#if NO_STAT64
956    struct stat  hostBuf;
957    int result = stat(path.c_str(), &hostBuf);
958#else
959    struct stat64 hostBuf;
960    int result = stat64(path.c_str(), &hostBuf);
961#endif
962
963    if (result < 0)
964        return -errno;
965
966    copyOutStat64Buf<OS>(tc->getMemProxy(), bufPtr, &hostBuf);
967
968    return 0;
969}
970
971
972/// Target fstatat64() handler.
973template <class OS>
974SyscallReturn
975fstatat64Func(SyscallDesc *desc, int callnum, LiveProcess *process,
976              ThreadContext *tc)
977{
978    int index = 0;
979    int dirfd = process->getSyscallArg(tc, index);
980    if (dirfd != OS::TGT_AT_FDCWD)
981        warn("fstatat64: first argument not AT_FDCWD; unlikely to work");
982
983    std::string path;
984    if (!tc->getMemProxy().tryReadString(path,
985                process->getSyscallArg(tc, index)))
986        return -EFAULT;
987    Addr bufPtr = process->getSyscallArg(tc, index);
988
989    // Adjust path for current working directory
990    path = process->fullPath(path);
991
992#if NO_STAT64
993    struct stat  hostBuf;
994    int result = stat(path.c_str(), &hostBuf);
995#else
996    struct stat64 hostBuf;
997    int result = stat64(path.c_str(), &hostBuf);
998#endif
999
1000    if (result < 0)
1001        return -errno;
1002
1003    copyOutStat64Buf<OS>(tc->getMemProxy(), bufPtr, &hostBuf);
1004
1005    return 0;
1006}
1007
1008
1009/// Target fstat64() handler.
1010template <class OS>
1011SyscallReturn
1012fstat64Func(SyscallDesc *desc, int callnum, LiveProcess *process,
1013            ThreadContext *tc)
1014{
1015    int index = 0;
1016    int tgt_fd = process->getSyscallArg(tc, index);
1017    Addr bufPtr = process->getSyscallArg(tc, index);
1018
1019    int sim_fd = process->getSimFD(tgt_fd);
1020    if (sim_fd < 0)
1021        return -EBADF;
1022
1023#if NO_STAT64
1024    struct stat  hostBuf;
1025    int result = fstat(sim_fd, &hostBuf);
1026#else
1027    struct stat64  hostBuf;
1028    int result = fstat64(sim_fd, &hostBuf);
1029#endif
1030
1031    if (result < 0)
1032        return -errno;
1033
1034    copyOutStat64Buf<OS>(tc->getMemProxy(), bufPtr, &hostBuf, (sim_fd == 1));
1035
1036    return 0;
1037}
1038
1039
1040/// Target lstat() handler.
1041template <class OS>
1042SyscallReturn
1043lstatFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
1044          ThreadContext *tc)
1045{
1046    std::string path;
1047
1048    int index = 0;
1049    if (!tc->getMemProxy().tryReadString(path,
1050                process->getSyscallArg(tc, index))) {
1051        return -EFAULT;
1052    }
1053    Addr bufPtr = process->getSyscallArg(tc, index);
1054
1055    // Adjust path for current working directory
1056    path = process->fullPath(path);
1057
1058    struct stat hostBuf;
1059    int result = lstat(path.c_str(), &hostBuf);
1060
1061    if (result < 0)
1062        return -errno;
1063
1064    copyOutStatBuf<OS>(tc->getMemProxy(), bufPtr, &hostBuf);
1065
1066    return 0;
1067}
1068
1069/// Target lstat64() handler.
1070template <class OS>
1071SyscallReturn
1072lstat64Func(SyscallDesc *desc, int callnum, LiveProcess *process,
1073            ThreadContext *tc)
1074{
1075    std::string path;
1076
1077    int index = 0;
1078    if (!tc->getMemProxy().tryReadString(path,
1079                process->getSyscallArg(tc, index))) {
1080        return -EFAULT;
1081    }
1082    Addr bufPtr = process->getSyscallArg(tc, index);
1083
1084    // Adjust path for current working directory
1085    path = process->fullPath(path);
1086
1087#if NO_STAT64
1088    struct stat hostBuf;
1089    int result = lstat(path.c_str(), &hostBuf);
1090#else
1091    struct stat64 hostBuf;
1092    int result = lstat64(path.c_str(), &hostBuf);
1093#endif
1094
1095    if (result < 0)
1096        return -errno;
1097
1098    copyOutStat64Buf<OS>(tc->getMemProxy(), bufPtr, &hostBuf);
1099
1100    return 0;
1101}
1102
1103/// Target fstat() handler.
1104template <class OS>
1105SyscallReturn
1106fstatFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
1107          ThreadContext *tc)
1108{
1109    int index = 0;
1110    int tgt_fd = process->getSyscallArg(tc, index);
1111    Addr bufPtr = process->getSyscallArg(tc, index);
1112
1113    DPRINTF_SYSCALL(Verbose, "fstat(%d, ...)\n", tgt_fd);
1114
1115    int sim_fd = process->getSimFD(tgt_fd);
1116    if (sim_fd < 0)
1117        return -EBADF;
1118
1119    struct stat hostBuf;
1120    int result = fstat(sim_fd, &hostBuf);
1121
1122    if (result < 0)
1123        return -errno;
1124
1125    copyOutStatBuf<OS>(tc->getMemProxy(), bufPtr, &hostBuf, (sim_fd == 1));
1126
1127    return 0;
1128}
1129
1130
1131/// Target statfs() handler.
1132template <class OS>
1133SyscallReturn
1134statfsFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
1135           ThreadContext *tc)
1136{
1137    std::string path;
1138
1139    int index = 0;
1140    if (!tc->getMemProxy().tryReadString(path,
1141                process->getSyscallArg(tc, index))) {
1142        return -EFAULT;
1143    }
1144    Addr bufPtr = process->getSyscallArg(tc, index);
1145
1146    // Adjust path for current working directory
1147    path = process->fullPath(path);
1148
1149    struct statfs hostBuf;
1150    int result = statfs(path.c_str(), &hostBuf);
1151
1152    if (result < 0)
1153        return -errno;
1154
1155    OS::copyOutStatfsBuf(tc->getMemProxy(), bufPtr, &hostBuf);
1156
1157    return 0;
1158}
1159
1160
1161/// Target fstatfs() handler.
1162template <class OS>
1163SyscallReturn
1164fstatfsFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
1165            ThreadContext *tc)
1166{
1167    int index = 0;
1168    int tgt_fd = process->getSyscallArg(tc, index);
1169    Addr bufPtr = process->getSyscallArg(tc, index);
1170
1171    int sim_fd = process->getSimFD(tgt_fd);
1172    if (sim_fd < 0)
1173        return -EBADF;
1174
1175    struct statfs hostBuf;
1176    int result = fstatfs(sim_fd, &hostBuf);
1177
1178    if (result < 0)
1179        return -errno;
1180
1181    OS::copyOutStatfsBuf(tc->getMemProxy(), bufPtr, &hostBuf);
1182
1183    return 0;
1184}
1185
1186
1187/// Target writev() handler.
1188template <class OS>
1189SyscallReturn
1190writevFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
1191           ThreadContext *tc)
1192{
1193    int index = 0;
1194    int tgt_fd = process->getSyscallArg(tc, index);
1195
1196    int sim_fd = process->getSimFD(tgt_fd);
1197    if (sim_fd < 0)
1198        return -EBADF;
1199
1200    SETranslatingPortProxy &p = tc->getMemProxy();
1201    uint64_t tiov_base = process->getSyscallArg(tc, index);
1202    size_t count = process->getSyscallArg(tc, index);
1203    struct iovec hiov[count];
1204    for (size_t i = 0; i < count; ++i) {
1205        typename OS::tgt_iovec tiov;
1206
1207        p.readBlob(tiov_base + i*sizeof(typename OS::tgt_iovec),
1208                   (uint8_t*)&tiov, sizeof(typename OS::tgt_iovec));
1209        hiov[i].iov_len = TheISA::gtoh(tiov.iov_len);
1210        hiov[i].iov_base = new char [hiov[i].iov_len];
1211        p.readBlob(TheISA::gtoh(tiov.iov_base), (uint8_t *)hiov[i].iov_base,
1212                   hiov[i].iov_len);
1213    }
1214
1215    int result = writev(sim_fd, hiov, count);
1216
1217    for (size_t i = 0; i < count; ++i)
1218        delete [] (char *)hiov[i].iov_base;
1219
1220    if (result < 0)
1221        return -errno;
1222
1223    return result;
1224}
1225
1226/// Real mmap handler.
1227template <class OS>
1228SyscallReturn
1229mmapImpl(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc,
1230         bool is_mmap2)
1231{
1232    int index = 0;
1233    Addr start = p->getSyscallArg(tc, index);
1234    uint64_t length = p->getSyscallArg(tc, index);
1235    int prot = p->getSyscallArg(tc, index);
1236    int tgt_flags = p->getSyscallArg(tc, index);
1237    int tgt_fd = p->getSyscallArg(tc, index);
1238    int offset = p->getSyscallArg(tc, index);
1239
1240    if (is_mmap2)
1241        offset *= TheISA::PageBytes;
1242
1243    if (start & (TheISA::PageBytes - 1) ||
1244        offset & (TheISA::PageBytes - 1) ||
1245        (tgt_flags & OS::TGT_MAP_PRIVATE &&
1246         tgt_flags & OS::TGT_MAP_SHARED) ||
1247        (!(tgt_flags & OS::TGT_MAP_PRIVATE) &&
1248         !(tgt_flags & OS::TGT_MAP_SHARED)) ||
1249        !length) {
1250        return -EINVAL;
1251    }
1252
1253    if ((prot & PROT_WRITE) && (tgt_flags & OS::TGT_MAP_SHARED)) {
1254        // With shared mmaps, there are two cases to consider:
1255        // 1) anonymous: writes should modify the mapping and this should be
1256        // visible to observers who share the mapping. Currently, it's
1257        // difficult to update the shared mapping because there's no
1258        // structure which maintains information about the which virtual
1259        // memory areas are shared. If that structure existed, it would be
1260        // possible to make the translations point to the same frames.
1261        // 2) file-backed: writes should modify the mapping and the file
1262        // which is backed by the mapping. The shared mapping problem is the
1263        // same as what was mentioned about the anonymous mappings. For
1264        // file-backed mappings, the writes to the file are difficult
1265        // because it requires syncing what the mapping holds with the file
1266        // that resides on the host system. So, any write on a real system
1267        // would cause the change to be propagated to the file mapping at
1268        // some point in the future (the inode is tracked along with the
1269        // mapping). This isn't guaranteed to always happen, but it usually
1270        // works well enough. The guarantee is provided by the msync system
1271        // call. We could force the change through with shared mappings with
1272        // a call to msync, but that again would require more information
1273        // than we currently maintain.
1274        warn("mmap: writing to shared mmap region is currently "
1275             "unsupported. The write succeeds on the target, but it "
1276             "will not be propagated to the host or shared mappings");
1277    }
1278
1279    length = roundUp(length, TheISA::PageBytes);
1280
1281    int sim_fd = -1;
1282    uint8_t *pmap = nullptr;
1283    if (!(tgt_flags & OS::TGT_MAP_ANONYMOUS)) {
1284        sim_fd = p->getSimFD(tgt_fd);
1285        if (sim_fd < 0)
1286            return -EBADF;
1287
1288        pmap = (decltype(pmap))mmap(NULL, length, PROT_READ, MAP_PRIVATE,
1289                                    sim_fd, offset);
1290
1291        if (pmap == (decltype(pmap))-1) {
1292            warn("mmap: failed to map file into host address space");
1293            return -errno;
1294        }
1295    }
1296
1297    // Extend global mmap region if necessary. Note that we ignore the
1298    // start address unless MAP_FIXED is specified.
1299    if (!(tgt_flags & OS::TGT_MAP_FIXED)) {
1300        start = (OS::mmapGrowsDown()) ? p->mmap_end - length : p->mmap_end;
1301        p->mmap_end = (OS::mmapGrowsDown()) ? start : p->mmap_end + length;
1302    }
1303
1304    DPRINTF_SYSCALL(Verbose, " mmap range is 0x%x - 0x%x\n",
1305                    start, start + length - 1);
1306
1307    // We only allow mappings to overwrite existing mappings if
1308    // TGT_MAP_FIXED is set. Otherwise it shouldn't be a problem
1309    // because we ignore the start hint if TGT_MAP_FIXED is not set.
1310    int clobber = tgt_flags & OS::TGT_MAP_FIXED;
1311    if (clobber) {
1312        for (auto tc : p->system->threadContexts) {
1313            // If we might be overwriting old mappings, we need to
1314            // invalidate potentially stale mappings out of the TLBs.
1315            tc->getDTBPtr()->flushAll();
1316            tc->getITBPtr()->flushAll();
1317        }
1318    }
1319
1320    // Allocate physical memory and map it in. If the page table is already
1321    // mapped and clobber is not set, the simulator will issue throw a
1322    // fatal and bail out of the simulation.
1323    p->allocateMem(start, length, clobber);
1324
1325    // Transfer content into target address space.
1326    SETranslatingPortProxy &tp = tc->getMemProxy();
1327    if (tgt_flags & OS::TGT_MAP_ANONYMOUS) {
1328        // In general, we should zero the mapped area for anonymous mappings,
1329        // with something like:
1330        //     tp.memsetBlob(start, 0, length);
1331        // However, given that we don't support sparse mappings, and
1332        // some applications can map a couple of gigabytes of space
1333        // (intending sparse usage), that can get painfully expensive.
1334        // Fortunately, since we don't properly implement munmap either,
1335        // there's no danger of remapping used memory, so for now all
1336        // newly mapped memory should already be zeroed so we can skip it.
1337    } else {
1338        // It is possible to mmap an area larger than a file, however
1339        // accessing unmapped portions the system triggers a "Bus error"
1340        // on the host. We must know when to stop copying the file from
1341        // the host into the target address space.
1342        struct stat file_stat;
1343        if (fstat(sim_fd, &file_stat) > 0)
1344            fatal("mmap: cannot stat file");
1345
1346        // Copy the portion of the file that is resident. This requires
1347        // checking both the mmap size and the filesize that we are
1348        // trying to mmap into this space; the mmap size also depends
1349        // on the specified offset into the file.
1350        uint64_t size = std::min((uint64_t)file_stat.st_size - offset,
1351                                 length);
1352        tp.writeBlob(start, pmap, size);
1353
1354        // Cleanup the mmap region before exiting this function.
1355        munmap(pmap, length);
1356
1357        // Note that we do not zero out the remainder of the mapping. This
1358        // is done by a real system, but it probably will not affect
1359        // execution (hopefully).
1360    }
1361
1362    return start;
1363}
1364
1365/// Target mmap() handler.
1366template <class OS>
1367SyscallReturn
1368mmapFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc)
1369{
1370    return mmapImpl<OS>(desc, num, p, tc, false);
1371}
1372
1373/// Target mmap2() handler.
1374template <class OS>
1375SyscallReturn
1376mmap2Func(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc)
1377{
1378    return mmapImpl<OS>(desc, num, p, tc, true);
1379}
1380
1381/// Target getrlimit() handler.
1382template <class OS>
1383SyscallReturn
1384getrlimitFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
1385        ThreadContext *tc)
1386{
1387    int index = 0;
1388    unsigned resource = process->getSyscallArg(tc, index);
1389    TypedBufferArg<typename OS::rlimit> rlp(process->getSyscallArg(tc, index));
1390
1391    switch (resource) {
1392        case OS::TGT_RLIMIT_STACK:
1393            // max stack size in bytes: make up a number (8MB for now)
1394            rlp->rlim_cur = rlp->rlim_max = 8 * 1024 * 1024;
1395            rlp->rlim_cur = TheISA::htog(rlp->rlim_cur);
1396            rlp->rlim_max = TheISA::htog(rlp->rlim_max);
1397            break;
1398
1399        case OS::TGT_RLIMIT_DATA:
1400            // max data segment size in bytes: make up a number
1401            rlp->rlim_cur = rlp->rlim_max = 256 * 1024 * 1024;
1402            rlp->rlim_cur = TheISA::htog(rlp->rlim_cur);
1403            rlp->rlim_max = TheISA::htog(rlp->rlim_max);
1404            break;
1405
1406        default:
1407            warn("getrlimit: unimplemented resource %d", resource);
1408            return -EINVAL;
1409            break;
1410    }
1411
1412    rlp.copyOut(tc->getMemProxy());
1413    return 0;
1414}
1415
1416/// Target clock_gettime() function.
1417template <class OS>
1418SyscallReturn
1419clock_gettimeFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc)
1420{
1421    int index = 1;
1422    //int clk_id = p->getSyscallArg(tc, index);
1423    TypedBufferArg<typename OS::timespec> tp(p->getSyscallArg(tc, index));
1424
1425    getElapsedTimeNano(tp->tv_sec, tp->tv_nsec);
1426    tp->tv_sec += seconds_since_epoch;
1427    tp->tv_sec = TheISA::htog(tp->tv_sec);
1428    tp->tv_nsec = TheISA::htog(tp->tv_nsec);
1429
1430    tp.copyOut(tc->getMemProxy());
1431
1432    return 0;
1433}
1434
1435/// Target clock_getres() function.
1436template <class OS>
1437SyscallReturn
1438clock_getresFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc)
1439{
1440    int index = 1;
1441    TypedBufferArg<typename OS::timespec> tp(p->getSyscallArg(tc, index));
1442
1443    // Set resolution at ns, which is what clock_gettime() returns
1444    tp->tv_sec = 0;
1445    tp->tv_nsec = 1;
1446
1447    tp.copyOut(tc->getMemProxy());
1448
1449    return 0;
1450}
1451
1452/// Target gettimeofday() handler.
1453template <class OS>
1454SyscallReturn
1455gettimeofdayFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
1456        ThreadContext *tc)
1457{
1458    int index = 0;
1459    TypedBufferArg<typename OS::timeval> tp(process->getSyscallArg(tc, index));
1460
1461    getElapsedTimeMicro(tp->tv_sec, tp->tv_usec);
1462    tp->tv_sec += seconds_since_epoch;
1463    tp->tv_sec = TheISA::htog(tp->tv_sec);
1464    tp->tv_usec = TheISA::htog(tp->tv_usec);
1465
1466    tp.copyOut(tc->getMemProxy());
1467
1468    return 0;
1469}
1470
1471
1472/// Target utimes() handler.
1473template <class OS>
1474SyscallReturn
1475utimesFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
1476           ThreadContext *tc)
1477{
1478    std::string path;
1479
1480    int index = 0;
1481    if (!tc->getMemProxy().tryReadString(path,
1482                process->getSyscallArg(tc, index))) {
1483        return -EFAULT;
1484    }
1485
1486    TypedBufferArg<typename OS::timeval [2]>
1487        tp(process->getSyscallArg(tc, index));
1488    tp.copyIn(tc->getMemProxy());
1489
1490    struct timeval hostTimeval[2];
1491    for (int i = 0; i < 2; ++i)
1492    {
1493        hostTimeval[i].tv_sec = TheISA::gtoh((*tp)[i].tv_sec);
1494        hostTimeval[i].tv_usec = TheISA::gtoh((*tp)[i].tv_usec);
1495    }
1496
1497    // Adjust path for current working directory
1498    path = process->fullPath(path);
1499
1500    int result = utimes(path.c_str(), hostTimeval);
1501
1502    if (result < 0)
1503        return -errno;
1504
1505    return 0;
1506}
1507/// Target getrusage() function.
1508template <class OS>
1509SyscallReturn
1510getrusageFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
1511              ThreadContext *tc)
1512{
1513    int index = 0;
1514    int who = process->getSyscallArg(tc, index); // THREAD, SELF, or CHILDREN
1515    TypedBufferArg<typename OS::rusage> rup(process->getSyscallArg(tc, index));
1516
1517    rup->ru_utime.tv_sec = 0;
1518    rup->ru_utime.tv_usec = 0;
1519    rup->ru_stime.tv_sec = 0;
1520    rup->ru_stime.tv_usec = 0;
1521    rup->ru_maxrss = 0;
1522    rup->ru_ixrss = 0;
1523    rup->ru_idrss = 0;
1524    rup->ru_isrss = 0;
1525    rup->ru_minflt = 0;
1526    rup->ru_majflt = 0;
1527    rup->ru_nswap = 0;
1528    rup->ru_inblock = 0;
1529    rup->ru_oublock = 0;
1530    rup->ru_msgsnd = 0;
1531    rup->ru_msgrcv = 0;
1532    rup->ru_nsignals = 0;
1533    rup->ru_nvcsw = 0;
1534    rup->ru_nivcsw = 0;
1535
1536    switch (who) {
1537      case OS::TGT_RUSAGE_SELF:
1538        getElapsedTimeMicro(rup->ru_utime.tv_sec, rup->ru_utime.tv_usec);
1539        rup->ru_utime.tv_sec = TheISA::htog(rup->ru_utime.tv_sec);
1540        rup->ru_utime.tv_usec = TheISA::htog(rup->ru_utime.tv_usec);
1541        break;
1542
1543      case OS::TGT_RUSAGE_CHILDREN:
1544        // do nothing.  We have no child processes, so they take no time.
1545        break;
1546
1547      default:
1548        // don't really handle THREAD or CHILDREN, but just warn and
1549        // plow ahead
1550        warn("getrusage() only supports RUSAGE_SELF.  Parameter %d ignored.",
1551             who);
1552    }
1553
1554    rup.copyOut(tc->getMemProxy());
1555
1556    return 0;
1557}
1558
1559/// Target times() function.
1560template <class OS>
1561SyscallReturn
1562timesFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
1563           ThreadContext *tc)
1564{
1565    int index = 0;
1566    TypedBufferArg<typename OS::tms> bufp(process->getSyscallArg(tc, index));
1567
1568    // Fill in the time structure (in clocks)
1569    int64_t clocks = curTick() * OS::M5_SC_CLK_TCK / SimClock::Int::s;
1570    bufp->tms_utime = clocks;
1571    bufp->tms_stime = 0;
1572    bufp->tms_cutime = 0;
1573    bufp->tms_cstime = 0;
1574
1575    // Convert to host endianness
1576    bufp->tms_utime = TheISA::htog(bufp->tms_utime);
1577
1578    // Write back
1579    bufp.copyOut(tc->getMemProxy());
1580
1581    // Return clock ticks since system boot
1582    return clocks;
1583}
1584
1585/// Target time() function.
1586template <class OS>
1587SyscallReturn
1588timeFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
1589           ThreadContext *tc)
1590{
1591    typename OS::time_t sec, usec;
1592    getElapsedTimeMicro(sec, usec);
1593    sec += seconds_since_epoch;
1594
1595    int index = 0;
1596    Addr taddr = (Addr)process->getSyscallArg(tc, index);
1597    if (taddr != 0) {
1598        typename OS::time_t t = sec;
1599        t = TheISA::htog(t);
1600        SETranslatingPortProxy &p = tc->getMemProxy();
1601        p.writeBlob(taddr, (uint8_t*)&t, (int)sizeof(typename OS::time_t));
1602    }
1603    return sec;
1604}
1605
1606
1607#endif // __SIM_SYSCALL_EMUL_HH__
1608