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