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