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