syscall_emul.hh revision 11383:5ac090acd180
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#endif
61#include <sys/mman.h>
62#include <sys/stat.h>
63#include <sys/time.h>
64#include <sys/uio.h>
65#include <fcntl.h>
66
67#include <cerrno>
68#include <string>
69
70#include "base/chunk_generator.hh"
71#include "base/intmath.hh"      // for RoundUp
72#include "base/misc.hh"
73#include "base/trace.hh"
74#include "base/types.hh"
75#include "config/the_isa.hh"
76#include "cpu/base.hh"
77#include "cpu/thread_context.hh"
78#include "debug/SyscallBase.hh"
79#include "debug/SyscallVerbose.hh"
80#include "mem/page_table.hh"
81#include "sim/byteswap.hh"
82#include "sim/emul_driver.hh"
83#include "sim/process.hh"
84#include "sim/syscall_emul_buf.hh"
85#include "sim/syscallreturn.hh"
86#include "sim/system.hh"
87
88// This wrapper macro helps out with readability a bit. FLAGEXT specifies
89// the verbosity and FMT is the message to be appended to the syscall
90// header information. The syscall header information contains the cpuid
91// and thread id.
92#define DPRINTF_SYSCALL(FLAGEXT, FMT, ...)                                  \
93    DPRINTFS(Syscall##FLAGEXT, tc->getCpuPtr(), "T%d : syscall " FMT,       \
94             tc->threadId(), __VA_ARGS__)
95
96///
97/// System call descriptor.
98///
99class SyscallDesc {
100
101  public:
102
103    /// Typedef for target syscall handler functions.
104    typedef SyscallReturn (*FuncPtr)(SyscallDesc *, int num,
105                           LiveProcess *, ThreadContext *);
106
107    const char *name;   //!< Syscall name (e.g., "open").
108    FuncPtr funcPtr;    //!< Pointer to emulation function.
109    int flags;          //!< Flags (see Flags enum).
110    bool warned;        //!< Have we warned about unimplemented syscall?
111
112    /// Flag values for controlling syscall behavior.
113    enum Flags {
114        /// Don't set return regs according to funcPtr return value.
115        /// Used for syscalls with non-standard return conventions
116        /// that explicitly set the ThreadContext regs (e.g.,
117        /// sigreturn).
118        SuppressReturnValue = 1,
119        WarnOnce = 2
120    };
121
122    /// Constructor.
123    SyscallDesc(const char *_name, FuncPtr _funcPtr, int _flags = 0)
124        : name(_name), funcPtr(_funcPtr), flags(_flags), warned(false)
125    {
126    }
127
128    /// Emulate the syscall.  Public interface for calling through funcPtr.
129    void doSyscall(int callnum, LiveProcess *proc, ThreadContext *tc);
130
131    /// Is the WarnOnce flag set?
132    bool warnOnce() const {  return (flags & WarnOnce); }
133};
134
135
136//////////////////////////////////////////////////////////////////////
137//
138// The following emulation functions are generic enough that they
139// don't need to be recompiled for different emulated OS's.  They are
140// defined in sim/syscall_emul.cc.
141//
142//////////////////////////////////////////////////////////////////////
143
144
145/// Handler for unimplemented syscalls that we haven't thought about.
146SyscallReturn unimplementedFunc(SyscallDesc *desc, int num,
147                                LiveProcess *p, ThreadContext *tc);
148
149/// Handler for unimplemented syscalls that we never intend to
150/// implement (signal handling, etc.) and should not affect the correct
151/// behavior of the program.  Print a warning only if the appropriate
152/// trace flag is enabled.  Return success to the target program.
153SyscallReturn ignoreFunc(SyscallDesc *desc, int num,
154                         LiveProcess *p, ThreadContext *tc);
155
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
1227/// Target mmap() handler.
1228template <class OS>
1229SyscallReturn
1230mmapFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc)
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    DPRINTF_SYSCALL(Verbose, "mmap(0x%x, len %d, prot %d, flags %d, fd %d, "
1241                    "offs %d)\n", start, length, prot, tgt_flags, tgt_fd,
1242                    offset);
1243
1244    if (start & (TheISA::PageBytes - 1) ||
1245        offset & (TheISA::PageBytes - 1) ||
1246        (tgt_flags & OS::TGT_MAP_PRIVATE &&
1247         tgt_flags & OS::TGT_MAP_SHARED) ||
1248        (!(tgt_flags & OS::TGT_MAP_PRIVATE) &&
1249         !(tgt_flags & OS::TGT_MAP_SHARED)) ||
1250        !length) {
1251        return -EINVAL;
1252    }
1253
1254    if ((prot & PROT_WRITE) && (tgt_flags & OS::TGT_MAP_SHARED)) {
1255        // With shared mmaps, there are two cases to consider:
1256        // 1) anonymous: writes should modify the mapping and this should be
1257        // visible to observers who share the mapping. Currently, it's
1258        // difficult to update the shared mapping because there's no
1259        // structure which maintains information about the which virtual
1260        // memory areas are shared. If that structure existed, it would be
1261        // possible to make the translations point to the same frames.
1262        // 2) file-backed: writes should modify the mapping and the file
1263        // which is backed by the mapping. The shared mapping problem is the
1264        // same as what was mentioned about the anonymous mappings. For
1265        // file-backed mappings, the writes to the file are difficult
1266        // because it requires syncing what the mapping holds with the file
1267        // that resides on the host system. So, any write on a real system
1268        // would cause the change to be propagated to the file mapping at
1269        // some point in the future (the inode is tracked along with the
1270        // mapping). This isn't guaranteed to always happen, but it usually
1271        // works well enough. The guarantee is provided by the msync system
1272        // call. We could force the change through with shared mappings with
1273        // a call to msync, but that again would require more information
1274        // than we currently maintain.
1275        warn("mmap: writing to shared mmap region is currently "
1276             "unsupported. The write succeeds on the target, but it "
1277             "will not be propagated to the host or shared mappings");
1278    }
1279
1280    length = roundUp(length, TheISA::PageBytes);
1281
1282    int sim_fd = -1;
1283    uint8_t *pmap = nullptr;
1284    if (!(tgt_flags & OS::TGT_MAP_ANONYMOUS)) {
1285        sim_fd = p->getSimFD(tgt_fd);
1286        if (sim_fd < 0)
1287            return -EBADF;
1288
1289        pmap = (decltype(pmap))mmap(NULL, length, PROT_READ, MAP_PRIVATE,
1290                                    sim_fd, offset);
1291
1292        if (pmap == (decltype(pmap))-1) {
1293            warn("mmap: failed to map file into host address space");
1294            return -errno;
1295        }
1296    }
1297
1298    // Extend global mmap region if necessary. Note that we ignore the
1299    // start address unless MAP_FIXED is specified.
1300    if (!(tgt_flags & OS::TGT_MAP_FIXED)) {
1301        start = (OS::mmapGrowsDown()) ? p->mmap_end - length : p->mmap_end;
1302        p->mmap_end = (OS::mmapGrowsDown()) ? start : p->mmap_end + length;
1303    }
1304
1305    DPRINTF_SYSCALL(Verbose, " mmap range is 0x%x - 0x%x\n",
1306                    start, start + length - 1);
1307
1308    // We only allow mappings to overwrite existing mappings if
1309    // TGT_MAP_FIXED is set. Otherwise it shouldn't be a problem
1310    // because we ignore the start hint if TGT_MAP_FIXED is not set.
1311    int clobber = tgt_flags & OS::TGT_MAP_FIXED;
1312    if (clobber) {
1313        for (auto tc : p->system->threadContexts) {
1314            // If we might be overwriting old mappings, we need to
1315            // invalidate potentially stale mappings out of the TLBs.
1316            tc->getDTBPtr()->flushAll();
1317            tc->getITBPtr()->flushAll();
1318        }
1319    }
1320
1321    // Allocate physical memory and map it in. If the page table is already
1322    // mapped and clobber is not set, the simulator will issue throw a
1323    // fatal and bail out of the simulation.
1324    p->allocateMem(start, length, clobber);
1325
1326    // Transfer content into target address space.
1327    SETranslatingPortProxy &tp = tc->getMemProxy();
1328    if (tgt_flags & OS::TGT_MAP_ANONYMOUS) {
1329        // In general, we should zero the mapped area for anonymous mappings,
1330        // with something like:
1331        //     tp.memsetBlob(start, 0, length);
1332        // However, given that we don't support sparse mappings, and
1333        // some applications can map a couple of gigabytes of space
1334        // (intending sparse usage), that can get painfully expensive.
1335        // Fortunately, since we don't properly implement munmap either,
1336        // there's no danger of remapping used memory, so for now all
1337        // newly mapped memory should already be zeroed so we can skip it.
1338    } else {
1339        // It is possible to mmap an area larger than a file, however
1340        // accessing unmapped portions the system triggers a "Bus error"
1341        // on the host. We must know when to stop copying the file from
1342        // the host into the target address space.
1343        struct stat file_stat;
1344        if (fstat(sim_fd, &file_stat) > 0)
1345            fatal("mmap: cannot stat file");
1346
1347        // Copy the portion of the file that is resident. This requires
1348        // checking both the mmap size and the filesize that we are
1349        // trying to mmap into this space; the mmap size also depends
1350        // on the specified offset into the file.
1351        uint64_t size = std::min((uint64_t)file_stat.st_size - offset,
1352                                 length);
1353        tp.writeBlob(start, pmap, size);
1354
1355        // Cleanup the mmap region before exiting this function.
1356        munmap(pmap, length);
1357
1358        // Note that we do not zero out the remainder of the mapping. This
1359        // is done by a real system, but it probably will not affect
1360        // execution (hopefully).
1361    }
1362
1363    return start;
1364}
1365
1366/// Target getrlimit() handler.
1367template <class OS>
1368SyscallReturn
1369getrlimitFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
1370        ThreadContext *tc)
1371{
1372    int index = 0;
1373    unsigned resource = process->getSyscallArg(tc, index);
1374    TypedBufferArg<typename OS::rlimit> rlp(process->getSyscallArg(tc, index));
1375
1376    switch (resource) {
1377        case OS::TGT_RLIMIT_STACK:
1378            // max stack size in bytes: make up a number (8MB for now)
1379            rlp->rlim_cur = rlp->rlim_max = 8 * 1024 * 1024;
1380            rlp->rlim_cur = TheISA::htog(rlp->rlim_cur);
1381            rlp->rlim_max = TheISA::htog(rlp->rlim_max);
1382            break;
1383
1384        case OS::TGT_RLIMIT_DATA:
1385            // max data segment size in bytes: make up a number
1386            rlp->rlim_cur = rlp->rlim_max = 256 * 1024 * 1024;
1387            rlp->rlim_cur = TheISA::htog(rlp->rlim_cur);
1388            rlp->rlim_max = TheISA::htog(rlp->rlim_max);
1389            break;
1390
1391        default:
1392            warn("getrlimit: unimplemented resource %d", resource);
1393            return -EINVAL;
1394            break;
1395    }
1396
1397    rlp.copyOut(tc->getMemProxy());
1398    return 0;
1399}
1400
1401/// Target clock_gettime() function.
1402template <class OS>
1403SyscallReturn
1404clock_gettimeFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc)
1405{
1406    int index = 1;
1407    //int clk_id = p->getSyscallArg(tc, index);
1408    TypedBufferArg<typename OS::timespec> tp(p->getSyscallArg(tc, index));
1409
1410    getElapsedTimeNano(tp->tv_sec, tp->tv_nsec);
1411    tp->tv_sec += seconds_since_epoch;
1412    tp->tv_sec = TheISA::htog(tp->tv_sec);
1413    tp->tv_nsec = TheISA::htog(tp->tv_nsec);
1414
1415    tp.copyOut(tc->getMemProxy());
1416
1417    return 0;
1418}
1419
1420/// Target clock_getres() function.
1421template <class OS>
1422SyscallReturn
1423clock_getresFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc)
1424{
1425    int index = 1;
1426    TypedBufferArg<typename OS::timespec> tp(p->getSyscallArg(tc, index));
1427
1428    // Set resolution at ns, which is what clock_gettime() returns
1429    tp->tv_sec = 0;
1430    tp->tv_nsec = 1;
1431
1432    tp.copyOut(tc->getMemProxy());
1433
1434    return 0;
1435}
1436
1437/// Target gettimeofday() handler.
1438template <class OS>
1439SyscallReturn
1440gettimeofdayFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
1441        ThreadContext *tc)
1442{
1443    int index = 0;
1444    TypedBufferArg<typename OS::timeval> tp(process->getSyscallArg(tc, index));
1445
1446    getElapsedTimeMicro(tp->tv_sec, tp->tv_usec);
1447    tp->tv_sec += seconds_since_epoch;
1448    tp->tv_sec = TheISA::htog(tp->tv_sec);
1449    tp->tv_usec = TheISA::htog(tp->tv_usec);
1450
1451    tp.copyOut(tc->getMemProxy());
1452
1453    return 0;
1454}
1455
1456
1457/// Target utimes() handler.
1458template <class OS>
1459SyscallReturn
1460utimesFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
1461           ThreadContext *tc)
1462{
1463    std::string path;
1464
1465    int index = 0;
1466    if (!tc->getMemProxy().tryReadString(path,
1467                process->getSyscallArg(tc, index))) {
1468        return -EFAULT;
1469    }
1470
1471    TypedBufferArg<typename OS::timeval [2]>
1472        tp(process->getSyscallArg(tc, index));
1473    tp.copyIn(tc->getMemProxy());
1474
1475    struct timeval hostTimeval[2];
1476    for (int i = 0; i < 2; ++i)
1477    {
1478        hostTimeval[i].tv_sec = TheISA::gtoh((*tp)[i].tv_sec);
1479        hostTimeval[i].tv_usec = TheISA::gtoh((*tp)[i].tv_usec);
1480    }
1481
1482    // Adjust path for current working directory
1483    path = process->fullPath(path);
1484
1485    int result = utimes(path.c_str(), hostTimeval);
1486
1487    if (result < 0)
1488        return -errno;
1489
1490    return 0;
1491}
1492/// Target getrusage() function.
1493template <class OS>
1494SyscallReturn
1495getrusageFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
1496              ThreadContext *tc)
1497{
1498    int index = 0;
1499    int who = process->getSyscallArg(tc, index); // THREAD, SELF, or CHILDREN
1500    TypedBufferArg<typename OS::rusage> rup(process->getSyscallArg(tc, index));
1501
1502    rup->ru_utime.tv_sec = 0;
1503    rup->ru_utime.tv_usec = 0;
1504    rup->ru_stime.tv_sec = 0;
1505    rup->ru_stime.tv_usec = 0;
1506    rup->ru_maxrss = 0;
1507    rup->ru_ixrss = 0;
1508    rup->ru_idrss = 0;
1509    rup->ru_isrss = 0;
1510    rup->ru_minflt = 0;
1511    rup->ru_majflt = 0;
1512    rup->ru_nswap = 0;
1513    rup->ru_inblock = 0;
1514    rup->ru_oublock = 0;
1515    rup->ru_msgsnd = 0;
1516    rup->ru_msgrcv = 0;
1517    rup->ru_nsignals = 0;
1518    rup->ru_nvcsw = 0;
1519    rup->ru_nivcsw = 0;
1520
1521    switch (who) {
1522      case OS::TGT_RUSAGE_SELF:
1523        getElapsedTimeMicro(rup->ru_utime.tv_sec, rup->ru_utime.tv_usec);
1524        rup->ru_utime.tv_sec = TheISA::htog(rup->ru_utime.tv_sec);
1525        rup->ru_utime.tv_usec = TheISA::htog(rup->ru_utime.tv_usec);
1526        break;
1527
1528      case OS::TGT_RUSAGE_CHILDREN:
1529        // do nothing.  We have no child processes, so they take no time.
1530        break;
1531
1532      default:
1533        // don't really handle THREAD or CHILDREN, but just warn and
1534        // plow ahead
1535        warn("getrusage() only supports RUSAGE_SELF.  Parameter %d ignored.",
1536             who);
1537    }
1538
1539    rup.copyOut(tc->getMemProxy());
1540
1541    return 0;
1542}
1543
1544/// Target times() function.
1545template <class OS>
1546SyscallReturn
1547timesFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
1548           ThreadContext *tc)
1549{
1550    int index = 0;
1551    TypedBufferArg<typename OS::tms> bufp(process->getSyscallArg(tc, index));
1552
1553    // Fill in the time structure (in clocks)
1554    int64_t clocks = curTick() * OS::M5_SC_CLK_TCK / SimClock::Int::s;
1555    bufp->tms_utime = clocks;
1556    bufp->tms_stime = 0;
1557    bufp->tms_cutime = 0;
1558    bufp->tms_cstime = 0;
1559
1560    // Convert to host endianness
1561    bufp->tms_utime = TheISA::htog(bufp->tms_utime);
1562
1563    // Write back
1564    bufp.copyOut(tc->getMemProxy());
1565
1566    // Return clock ticks since system boot
1567    return clocks;
1568}
1569
1570/// Target time() function.
1571template <class OS>
1572SyscallReturn
1573timeFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
1574           ThreadContext *tc)
1575{
1576    typename OS::time_t sec, usec;
1577    getElapsedTimeMicro(sec, usec);
1578    sec += seconds_since_epoch;
1579
1580    int index = 0;
1581    Addr taddr = (Addr)process->getSyscallArg(tc, index);
1582    if (taddr != 0) {
1583        typename OS::time_t t = sec;
1584        t = TheISA::htog(t);
1585        SETranslatingPortProxy &p = tc->getMemProxy();
1586        p.writeBlob(taddr, (uint8_t*)&t, (int)sizeof(typename OS::time_t));
1587    }
1588    return sec;
1589}
1590
1591
1592#endif // __SIM_SYSCALL_EMUL_HH__
1593