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