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