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