2 * Copyright (c) 2012-2013, 2015, 2019-2020 ARM Limited
3 * Copyright (c) 2015 Advanced Micro Devices, Inc.
6 * The license below extends only to copyright in the software and shall
7 * not be construed as granting a license to any other intellectual
8 * property including but not limited to intellectual property relating
9 * to a hardware implementation of the functionality of the software
10 * licensed hereunder. You may use the software subject to the license
11 * terms below provided that you ensure that this notice is replicated
12 * unmodified and in its entirety in all distributions of the software,
13 * modified or unmodified, in source code or in binary form.
15 * Copyright (c) 2003-2005 The Regents of The University of Michigan
16 * All rights reserved.
18 * Redistribution and use in source and binary forms, with or without
19 * modification, are permitted provided that the following conditions are
20 * met: redistributions of source code must retain the above copyright
21 * notice, this list of conditions and the following disclaimer;
22 * redistributions in binary form must reproduce the above copyright
23 * notice, this list of conditions and the following disclaimer in the
24 * documentation and/or other materials provided with the distribution;
25 * neither the name of the copyright holders nor the names of its
26 * contributors may be used to endorse or promote products derived from
27 * this software without specific prior written permission.
29 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
30 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
31 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
32 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
33 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
34 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
35 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
36 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
37 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
38 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
39 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
42 #ifndef __SIM_SYSCALL_EMUL_HH__
43 #define __SIM_SYSCALL_EMUL_HH__
45 #if (defined(__APPLE__) || defined(__OpenBSD__) || \
46 defined(__FreeBSD__) || defined(__CYGWIN__) || \
54 /// @file syscall_emul.hh
56 /// This file defines objects used to emulate syscalls from the target
57 /// application on the host machine.
59 #if defined(__linux__)
60 #include <sys/eventfd.h>
61 #include <sys/statfs.h>
64 #include <sys/mount.h>
69 #include <sys/fcntl.h>
75 #include <sys/ioctl.h>
77 #include <sys/socket.h>
80 #include <sys/types.h>
88 #include "arch/generic/tlb.hh"
89 #include "arch/utility.hh"
90 #include "base/intmath.hh"
91 #include "base/loader/object_file.hh"
92 #include "base/logging.hh"
93 #include "base/trace.hh"
94 #include "base/types.hh"
95 #include "config/the_isa.hh"
96 #include "cpu/base.hh"
97 #include "cpu/thread_context.hh"
98 #include "kern/linux/linux.hh"
99 #include "mem/page_table.hh"
100 #include "params/Process.hh"
101 #include "sim/emul_driver.hh"
102 #include "sim/futex_map.hh"
103 #include "sim/guest_abi.hh"
104 #include "sim/process.hh"
105 #include "sim/proxy_ptr.hh"
106 #include "sim/syscall_debug_macros.hh"
107 #include "sim/syscall_desc.hh"
108 #include "sim/syscall_emul_buf.hh"
109 #include "sim/syscall_return.hh"
111 #if defined(__APPLE__) && defined(__MACH__) && !defined(CMSG_ALIGN)
112 #define CMSG_ALIGN(len) (((len) + sizeof(size_t) - 1) & ~(sizeof(size_t) - 1))
115 //////////////////////////////////////////////////////////////////////
117 // The following emulation functions are generic enough that they
118 // don't need to be recompiled for different emulated OS's. They are
119 // defined in sim/syscall_emul.cc.
121 //////////////////////////////////////////////////////////////////////
123 void warnUnsupportedOS(std::string syscall_name);
125 /// Handler for unimplemented syscalls that we haven't thought about.
126 SyscallReturn unimplementedFunc(SyscallDesc *desc, ThreadContext *tc);
128 /// Handler for unimplemented syscalls that we never intend to
129 /// implement (signal handling, etc.) and should not affect the correct
130 /// behavior of the program. Prints a warning. Return success to the target
132 SyscallReturn ignoreFunc(SyscallDesc *desc, ThreadContext *tc);
133 /// Like above, but only prints a warning once per syscall desc it's used with.
135 ignoreWarnOnceFunc(SyscallDesc *desc, ThreadContext *tc);
137 // Target fallocateFunc() handler.
138 SyscallReturn fallocateFunc(SyscallDesc *desc, ThreadContext *tc,
139 int tgt_fd, int mode, off_t offset, off_t len);
141 /// Target exit() handler: terminate current context.
142 SyscallReturn exitFunc(SyscallDesc *desc, ThreadContext *tc, int status);
144 /// Target exit_group() handler: terminate simulation. (exit all threads)
145 SyscallReturn exitGroupFunc(SyscallDesc *desc, ThreadContext *tc, int status);
147 /// Target set_tid_address() handler.
148 SyscallReturn setTidAddressFunc(SyscallDesc *desc, ThreadContext *tc,
151 /// Target getpagesize() handler.
152 SyscallReturn getpagesizeFunc(SyscallDesc *desc, ThreadContext *tc);
154 /// Target brk() handler: set brk address.
155 SyscallReturn brkFunc(SyscallDesc *desc, ThreadContext *tc, Addr new_brk);
157 /// Target close() handler.
158 SyscallReturn closeFunc(SyscallDesc *desc, ThreadContext *tc, int tgt_fd);
160 /// Target lseek() handler.
161 SyscallReturn lseekFunc(SyscallDesc *desc, ThreadContext *tc,
162 int tgt_fd, uint64_t offs, int whence);
164 /// Target _llseek() handler.
165 SyscallReturn _llseekFunc(SyscallDesc *desc, ThreadContext *tc,
166 int tgt_fd, uint64_t offset_high,
167 uint32_t offset_low, Addr result_ptr, int whence);
169 /// Target munmap() handler.
170 SyscallReturn munmapFunc(SyscallDesc *desc, ThreadContext *tc, Addr start,
173 /// Target shutdown() handler.
174 SyscallReturn shutdownFunc(SyscallDesc *desc, ThreadContext *tc,
175 int tgt_fd, int how);
177 /// Target gethostname() handler.
178 SyscallReturn gethostnameFunc(SyscallDesc *desc, ThreadContext *tc,
179 Addr buf_ptr, int name_len);
181 /// Target getcwd() handler.
182 SyscallReturn getcwdFunc(SyscallDesc *desc, ThreadContext *tc,
183 Addr buf_ptr, unsigned long size);
185 /// Target readlink() handler.
186 SyscallReturn readlinkFunc(SyscallDesc *desc, ThreadContext *tc,
187 Addr pathname, Addr buf, size_t bufsiz);
189 /// Target unlink() handler.
190 SyscallReturn unlinkFunc(SyscallDesc *desc, ThreadContext *tc, Addr pathname);
192 /// Target link() handler
193 SyscallReturn linkFunc(SyscallDesc *desc, ThreadContext *tc,
194 Addr pathname, Addr new_pathname);
196 /// Target symlink() handler.
197 SyscallReturn symlinkFunc(SyscallDesc *desc, ThreadContext *tc,
198 Addr pathname, Addr new_pathname);
200 /// Target mkdir() handler.
201 SyscallReturn mkdirFunc(SyscallDesc *desc, ThreadContext *tc,
202 Addr pathname, mode_t mode);
204 /// Target mknod() handler.
205 SyscallReturn mknodFunc(SyscallDesc *desc, ThreadContext *tc,
206 Addr pathname, mode_t mode, dev_t dev);
208 /// Target chdir() handler.
209 SyscallReturn chdirFunc(SyscallDesc *desc, ThreadContext *tc, Addr pathname);
211 // Target rmdir() handler.
212 SyscallReturn rmdirFunc(SyscallDesc *desc, ThreadContext *tc, Addr pathname);
214 /// Target rename() handler.
215 SyscallReturn renameFunc(SyscallDesc *desc, ThreadContext *tc,
216 Addr oldpath, Addr newpath);
219 /// Target truncate() handler.
220 SyscallReturn truncateFunc(SyscallDesc *desc, ThreadContext *tc,
221 Addr pathname, off_t length);
224 /// Target ftruncate() handler.
225 SyscallReturn ftruncateFunc(SyscallDesc *desc, ThreadContext *tc,
226 int tgt_fd, off_t length);
229 /// Target truncate64() handler.
230 SyscallReturn truncate64Func(SyscallDesc *desc, ThreadContext *tc,
231 Addr pathname, int64_t length);
233 /// Target ftruncate64() handler.
234 SyscallReturn ftruncate64Func(SyscallDesc *desc, ThreadContext *tc,
235 int tgt_fd, int64_t length);
237 /// Target umask() handler.
238 SyscallReturn umaskFunc(SyscallDesc *desc, ThreadContext *tc);
240 /// Target gettid() handler.
241 SyscallReturn gettidFunc(SyscallDesc *desc, ThreadContext *tc);
243 /// Target chown() handler.
244 SyscallReturn chownFunc(SyscallDesc *desc, ThreadContext *tc,
245 Addr pathname, uint32_t owner, uint32_t group);
247 /// Target getpgrpFunc() handler.
248 SyscallReturn getpgrpFunc(SyscallDesc *desc, ThreadContext *tc);
250 /// Target setpgid() handler.
251 SyscallReturn setpgidFunc(SyscallDesc *desc, ThreadContext *tc,
254 /// Target fchown() handler.
255 SyscallReturn fchownFunc(SyscallDesc *desc, ThreadContext *tc,
256 int tgt_fd, uint32_t owner, uint32_t group);
258 /// Target dup() handler.
259 SyscallReturn dupFunc(SyscallDesc *desc, ThreadContext *tc,
262 /// Target dup2() handler.
263 SyscallReturn dup2Func(SyscallDesc *desc, ThreadContext *tc,
264 int old_tgt_fd, int new_tgt_fd);
266 /// Target fcntl() handler.
267 SyscallReturn fcntlFunc(SyscallDesc *desc, ThreadContext *tc,
268 int tgt_fd, int cmd, GuestABI::VarArgs<int> varargs);
270 /// Target fcntl64() handler.
271 SyscallReturn fcntl64Func(SyscallDesc *desc, ThreadContext *tc,
272 int tgt_fd, int cmd);
274 /// Target pipe() handler.
275 SyscallReturn pipeFunc(SyscallDesc *desc, ThreadContext *tc, Addr tgt_addr);
277 /// Target pipe() handler.
278 SyscallReturn pipe2Func(SyscallDesc *desc, ThreadContext *tc,
279 Addr tgt_addr, int flags);
281 /// Target getpid() handler.
282 SyscallReturn getpidFunc(SyscallDesc *desc, ThreadContext *tc);
284 // Target getpeername() handler.
285 SyscallReturn getpeernameFunc(SyscallDesc *desc, ThreadContext *tc,
286 int tgt_fd, Addr sockAddrPtr, Addr addrlenPtr);
288 // Target bind() handler.
289 SyscallReturn bindFunc(SyscallDesc *desc, ThreadContext *tc,
290 int tgt_fd, Addr buf_ptr, int addrlen);
292 // Target listen() handler.
293 SyscallReturn listenFunc(SyscallDesc *desc, ThreadContext *tc,
294 int tgt_fd, int backlog);
296 // Target connect() handler.
297 SyscallReturn connectFunc(SyscallDesc *desc, ThreadContext *tc,
298 int tgt_fd, Addr buf_ptr, int addrlen);
300 #if defined(SYS_getdents)
301 // Target getdents() handler.
302 SyscallReturn getdentsFunc(SyscallDesc *desc, ThreadContext *tc,
303 int tgt_fd, Addr buf_ptr, unsigned count);
306 #if defined(SYS_getdents64)
307 // Target getdents() handler.
308 SyscallReturn getdents64Func(SyscallDesc *desc, ThreadContext *tc,
309 int tgt_fd, Addr buf_ptr, unsigned count);
312 // Target sendto() handler.
313 SyscallReturn sendtoFunc(SyscallDesc *desc, ThreadContext *tc,
314 int tgt_fd, Addr bufrPtr, size_t bufrLen, int flags,
315 Addr addrPtr, socklen_t addrLen);
317 // Target recvfrom() handler.
318 SyscallReturn recvfromFunc(SyscallDesc *desc, ThreadContext *tc,
319 int tgt_fd, Addr bufrPtr, size_t bufrLen,
320 int flags, Addr addrPtr, Addr addrlenPtr);
322 // Target recvmsg() handler.
323 SyscallReturn recvmsgFunc(SyscallDesc *desc, ThreadContext *tc,
324 int tgt_fd, Addr msgPtr, int flags);
326 // Target sendmsg() handler.
327 SyscallReturn sendmsgFunc(SyscallDesc *desc, ThreadContext *tc,
328 int tgt_fd, Addr msgPtr, int flags);
330 // Target getuid() handler.
331 SyscallReturn getuidFunc(SyscallDesc *desc, ThreadContext *tc);
333 /// Target getgid() handler.
334 SyscallReturn getgidFunc(SyscallDesc *desc, ThreadContext *tc);
336 /// Target getppid() handler.
337 SyscallReturn getppidFunc(SyscallDesc *desc, ThreadContext *tc);
339 /// Target geteuid() handler.
340 SyscallReturn geteuidFunc(SyscallDesc *desc, ThreadContext *tc);
342 /// Target getegid() handler.
343 SyscallReturn getegidFunc(SyscallDesc *desc, ThreadContext *tc);
345 /// Target access() handler
346 SyscallReturn accessFunc(SyscallDesc *desc, ThreadContext *tc,
347 Addr pathname, mode_t mode);
349 // Target getsockopt() handler.
350 SyscallReturn getsockoptFunc(SyscallDesc *desc, ThreadContext *tc,
351 int tgt_fd, int level, int optname,
352 Addr valPtr, Addr lenPtr);
354 // Target setsockopt() handler.
355 SyscallReturn setsockoptFunc(SyscallDesc *desc, ThreadContext *tc,
356 int tgt_fd, int level, int optname,
357 Addr valPtr, socklen_t len);
359 SyscallReturn getcpuFunc(SyscallDesc *desc, ThreadContext *tc,
360 VPtr<uint32_t> cpu, VPtr<uint32_t> node,
361 VPtr<uint32_t> tcache);
363 // Target getsockname() handler.
364 SyscallReturn getsocknameFunc(SyscallDesc *desc, ThreadContext *tc,
365 int tgt_fd, Addr addrPtr, Addr lenPtr);
367 /// Futex system call
368 /// Implemented by Daniel Sanchez
369 /// Used by printf's in multi-threaded apps
372 futexFunc(SyscallDesc *desc, ThreadContext *tc,
373 Addr uaddr, int op, int val, int timeout, Addr uaddr2, int val3)
375 auto process = tc->getProcessPtr();
378 * Unsupported option that does not affect the correctness of the
379 * application. This is a performance optimization utilized by Linux.
381 op &= ~OS::TGT_FUTEX_PRIVATE_FLAG;
382 op &= ~OS::TGT_FUTEX_CLOCK_REALTIME_FLAG;
384 FutexMap &futex_map = tc->getSystemPtr()->futexMap;
386 if (OS::TGT_FUTEX_WAIT == op || OS::TGT_FUTEX_WAIT_BITSET == op) {
387 // Ensure futex system call accessed atomically.
388 BufferArg buf(uaddr, sizeof(int));
389 buf.copyIn(tc->getVirtProxy());
390 int mem_val = *(int*)buf.bufferPtr();
393 * The value in memory at uaddr is not equal with the expected val
394 * (a different thread must have changed it before the system call was
395 * invoked). In this case, we need to throw an error.
398 return -OS::TGT_EWOULDBLOCK;
400 if (OS::TGT_FUTEX_WAIT == op) {
401 futex_map.suspend(uaddr, process->tgid(), tc);
403 futex_map.suspend_bitset(uaddr, process->tgid(), tc, val3);
407 } else if (OS::TGT_FUTEX_WAKE == op) {
408 return futex_map.wakeup(uaddr, process->tgid(), val);
409 } else if (OS::TGT_FUTEX_WAKE_BITSET == op) {
410 return futex_map.wakeup_bitset(uaddr, process->tgid(), val3);
411 } else if (OS::TGT_FUTEX_REQUEUE == op ||
412 OS::TGT_FUTEX_CMP_REQUEUE == op) {
414 // Ensure futex system call accessed atomically.
415 BufferArg buf(uaddr, sizeof(int));
416 buf.copyIn(tc->getVirtProxy());
417 int mem_val = *(int*)buf.bufferPtr();
419 * For CMP_REQUEUE, the whole operation is only started only if
420 * val3 is still the value of the futex pointed to by uaddr.
422 if (OS::TGT_FUTEX_CMP_REQUEUE && val3 != mem_val)
423 return -OS::TGT_EWOULDBLOCK;
424 return futex_map.requeue(uaddr, process->tgid(), val, timeout, uaddr2);
425 } else if (OS::TGT_FUTEX_WAKE_OP == op) {
427 * The FUTEX_WAKE_OP operation is equivalent to executing the
428 * following code atomically and totally ordered with respect to
429 * other futex operations on any of the two supplied futex words:
431 * int oldval = *(int *) addr2;
432 * *(int *) addr2 = oldval op oparg;
433 * futex(addr1, FUTEX_WAKE, val, 0, 0, 0);
434 * if (oldval cmp cmparg)
435 * futex(addr2, FUTEX_WAKE, val2, 0, 0, 0);
437 * (op, oparg, cmp, cmparg are encoded in val3)
439 * +---+---+-----------+-----------+
440 * |op |cmp| oparg | cmparg |
441 * +---+---+-----------+-----------+
442 * 4 4 12 12 <== # of bits
444 * reference: http://man7.org/linux/man-pages/man2/futex.2.html
447 // get value from simulated-space
448 BufferArg buf(uaddr2, sizeof(int));
449 buf.copyIn(tc->getVirtProxy());
450 int oldval = *(int*)buf.bufferPtr();
452 // extract op, oparg, cmp, cmparg from val3
453 int wake_cmparg = val3 & 0xfff;
454 int wake_oparg = (val3 & 0xfff000) >> 12;
455 int wake_cmp = (val3 & 0xf000000) >> 24;
456 int wake_op = (val3 & 0xf0000000) >> 28;
457 if ((wake_op & OS::TGT_FUTEX_OP_ARG_SHIFT) >> 3 == 1)
458 wake_oparg = (1 << wake_oparg);
459 wake_op &= ~OS::TGT_FUTEX_OP_ARG_SHIFT;
460 // perform operation on the value of the second futex
461 if (wake_op == OS::TGT_FUTEX_OP_SET)
463 else if (wake_op == OS::TGT_FUTEX_OP_ADD)
464 newval += wake_oparg;
465 else if (wake_op == OS::TGT_FUTEX_OP_OR)
466 newval |= wake_oparg;
467 else if (wake_op == OS::TGT_FUTEX_OP_ANDN)
468 newval &= ~wake_oparg;
469 else if (wake_op == OS::TGT_FUTEX_OP_XOR)
470 newval ^= wake_oparg;
471 // copy updated value back to simulated-space
472 *(int*)buf.bufferPtr() = newval;
473 buf.copyOut(tc->getVirtProxy());
474 // perform the first wake-up
475 int woken1 = futex_map.wakeup(uaddr, process->tgid(), val);
477 // calculate the condition of the second wake-up
478 bool is_wake2 = false;
479 if (wake_cmp == OS::TGT_FUTEX_OP_CMP_EQ)
480 is_wake2 = oldval == wake_cmparg;
481 else if (wake_cmp == OS::TGT_FUTEX_OP_CMP_NE)
482 is_wake2 = oldval != wake_cmparg;
483 else if (wake_cmp == OS::TGT_FUTEX_OP_CMP_LT)
484 is_wake2 = oldval < wake_cmparg;
485 else if (wake_cmp == OS::TGT_FUTEX_OP_CMP_LE)
486 is_wake2 = oldval <= wake_cmparg;
487 else if (wake_cmp == OS::TGT_FUTEX_OP_CMP_GT)
488 is_wake2 = oldval > wake_cmparg;
489 else if (wake_cmp == OS::TGT_FUTEX_OP_CMP_GE)
490 is_wake2 = oldval >= wake_cmparg;
491 // perform the second wake-up
493 woken2 = futex_map.wakeup(uaddr2, process->tgid(), timeout);
495 return woken1 + woken2;
497 warn("futex: op %d not implemented; ignoring.", op);
501 /// Pseudo Funcs - These functions use a different return convension,
502 /// returning a second value in a register other than the normal return register
503 SyscallReturn pipePseudoFunc(SyscallDesc *desc, ThreadContext *tc);
506 /// Approximate seconds since the epoch (1/1/1970). About a billion,
507 /// by my reckoning. We want to keep this a constant (not use the
508 /// real-world time) to keep simulations repeatable.
509 const unsigned seconds_since_epoch = 1000 * 1000 * 1000;
511 /// Helper function to convert current elapsed time to seconds and
513 template <class T1, class T2>
515 getElapsedTimeMicro(T1 &sec, T2 &usec)
517 static const int OneMillion = 1000 * 1000;
519 uint64_t elapsed_usecs = curTick() / SimClock::Int::us;
520 sec = elapsed_usecs / OneMillion;
521 usec = elapsed_usecs % OneMillion;
524 /// Helper function to convert current elapsed time to seconds and
526 template <class T1, class T2>
528 getElapsedTimeNano(T1 &sec, T2 &nsec)
530 static const int OneBillion = 1000 * 1000 * 1000;
532 uint64_t elapsed_nsecs = curTick() / SimClock::Int::ns;
533 sec = elapsed_nsecs / OneBillion;
534 nsec = elapsed_nsecs % OneBillion;
537 //////////////////////////////////////////////////////////////////////
539 // The following emulation functions are generic, but need to be
540 // templated to account for differences in types, constants, etc.
542 //////////////////////////////////////////////////////////////////////
544 typedef struct statfs hst_statfs;
546 typedef struct stat hst_stat;
547 typedef struct stat hst_stat64;
549 typedef struct stat hst_stat;
550 typedef struct stat64 hst_stat64;
553 //// Helper function to convert a host stat buffer to a target stat
554 //// buffer. Also copies the target buffer out to the simulated
555 //// memory space. Used by stat(), fstat(), and lstat().
557 template <typename OS, typename TgtStatPtr, typename HostStatPtr>
559 copyOutStatBuf(TgtStatPtr tgt, HostStatPtr host, bool fakeTTY=false)
561 constexpr ByteOrder bo = OS::byteOrder;
566 tgt->st_dev = host->st_dev;
567 tgt->st_dev = htog(tgt->st_dev, bo);
568 tgt->st_ino = host->st_ino;
569 tgt->st_ino = htog(tgt->st_ino, bo);
570 tgt->st_mode = host->st_mode;
572 // Claim to be a character device
573 tgt->st_mode &= ~S_IFMT; // Clear S_IFMT
574 tgt->st_mode |= S_IFCHR; // Set S_IFCHR
576 tgt->st_mode = htog(tgt->st_mode, bo);
577 tgt->st_nlink = host->st_nlink;
578 tgt->st_nlink = htog(tgt->st_nlink, bo);
579 tgt->st_uid = host->st_uid;
580 tgt->st_uid = htog(tgt->st_uid, bo);
581 tgt->st_gid = host->st_gid;
582 tgt->st_gid = htog(tgt->st_gid, bo);
584 tgt->st_rdev = 0x880d;
586 tgt->st_rdev = host->st_rdev;
587 tgt->st_rdev = htog(tgt->st_rdev, bo);
588 tgt->st_size = host->st_size;
589 tgt->st_size = htog(tgt->st_size, bo);
590 tgt->st_atimeX = host->st_atime;
591 tgt->st_atimeX = htog(tgt->st_atimeX, bo);
592 tgt->st_mtimeX = host->st_mtime;
593 tgt->st_mtimeX = htog(tgt->st_mtimeX, bo);
594 tgt->st_ctimeX = host->st_ctime;
595 tgt->st_ctimeX = htog(tgt->st_ctimeX, bo);
596 // Force the block size to be 8KB. This helps to ensure buffered io works
597 // consistently across different hosts.
598 tgt->st_blksize = 0x2000;
599 tgt->st_blksize = htog(tgt->st_blksize, bo);
600 tgt->st_blocks = host->st_blocks;
601 tgt->st_blocks = htog(tgt->st_blocks, bo);
606 template <typename OS, typename TgtStatPtr, typename HostStatPtr>
608 copyOutStat64Buf(TgtStatPtr tgt, HostStatPtr host,
611 copyOutStatBuf<OS>(tgt, host, fakeTTY);
612 #if defined(STAT_HAVE_NSEC)
613 constexpr ByteOrder bo = OS::byteOrder;
615 tgt->st_atime_nsec = host->st_atime_nsec;
616 tgt->st_atime_nsec = htog(tgt->st_atime_nsec, bo);
617 tgt->st_mtime_nsec = host->st_mtime_nsec;
618 tgt->st_mtime_nsec = htog(tgt->st_mtime_nsec, bo);
619 tgt->st_ctime_nsec = host->st_ctime_nsec;
620 tgt->st_ctime_nsec = htog(tgt->st_ctime_nsec, bo);
622 tgt->st_atime_nsec = 0;
623 tgt->st_mtime_nsec = 0;
624 tgt->st_ctime_nsec = 0;
628 template <class OS, typename TgtStatPtr, typename HostStatPtr>
630 copyOutStatfsBuf(TgtStatPtr tgt, HostStatPtr host)
632 constexpr ByteOrder bo = OS::byteOrder;
634 tgt->f_type = htog(host->f_type, bo);
635 #if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__)
636 tgt->f_bsize = htog(host->f_iosize, bo);
638 tgt->f_bsize = htog(host->f_bsize, bo);
640 tgt->f_blocks = htog(host->f_blocks, bo);
641 tgt->f_bfree = htog(host->f_bfree, bo);
642 tgt->f_bavail = htog(host->f_bavail, bo);
643 tgt->f_files = htog(host->f_files, bo);
644 tgt->f_ffree = htog(host->f_ffree, bo);
645 memcpy(&tgt->f_fsid, &host->f_fsid, sizeof(host->f_fsid));
646 #if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__)
647 tgt->f_namelen = htog(host->f_namemax, bo);
648 tgt->f_frsize = htog(host->f_bsize, bo);
649 #elif defined(__APPLE__)
653 tgt->f_namelen = htog(host->f_namelen, bo);
654 tgt->f_frsize = htog(host->f_frsize, bo);
656 #if defined(__linux__)
657 memcpy(&tgt->f_spare, &host->f_spare,
658 std::min(sizeof(host->f_spare), sizeof(tgt->f_spare)));
661 * The fields are different sizes per OS. Don't bother with
662 * f_spare or f_reserved on non-Linux for now.
664 memset(&tgt->f_spare, 0, sizeof(tgt->f_spare));
668 /// Target ioctl() handler. For the most part, programs call ioctl()
669 /// only to find out if their stdout is a tty, to determine whether to
670 /// do line or block buffering. We always claim that output fds are
671 /// not TTYs to provide repeatable results.
674 ioctlFunc(SyscallDesc *desc, ThreadContext *tc,
675 int tgt_fd, unsigned req, Addr addr)
677 auto p = tc->getProcessPtr();
679 DPRINTF_SYSCALL(Verbose, "ioctl(%d, 0x%x, ...)\n", tgt_fd, req);
681 if (OS::isTtyReq(req))
684 auto dfdp = std::dynamic_pointer_cast<DeviceFDEntry>((*p->fds)[tgt_fd]);
686 EmulatedDriver *emul_driver = dfdp->getDriver();
688 return emul_driver->ioctl(tc, req, addr);
691 auto sfdp = std::dynamic_pointer_cast<SocketFDEntry>((*p->fds)[tgt_fd]);
697 BufferArg conf_arg(addr, sizeof(ifconf));
698 conf_arg.copyIn(tc->getVirtProxy());
700 ifconf *conf = (ifconf*)conf_arg.bufferPtr();
701 Addr ifc_buf_addr = (Addr)conf->ifc_buf;
702 BufferArg ifc_buf_arg(ifc_buf_addr, conf->ifc_len);
703 ifc_buf_arg.copyIn(tc->getVirtProxy());
705 conf->ifc_buf = (char*)ifc_buf_arg.bufferPtr();
707 status = ioctl(sfdp->getSimFD(), req, conf_arg.bufferPtr());
709 conf->ifc_buf = (char*)ifc_buf_addr;
710 ifc_buf_arg.copyOut(tc->getVirtProxy());
711 conf_arg.copyOut(tc->getVirtProxy());
717 #if defined(__linux__)
722 #if defined(__linux__)
726 BufferArg req_arg(addr, sizeof(ifreq));
727 req_arg.copyIn(tc->getVirtProxy());
729 status = ioctl(sfdp->getSimFD(), req, req_arg.bufferPtr());
731 req_arg.copyOut(tc->getVirtProxy());
738 * For lack of a better return code, return ENOTTY. Ideally, we should
739 * return something better here, but at least we issue the warning.
741 warn("Unsupported ioctl call (return ENOTTY): ioctl(%d, 0x%x, ...) @ \n",
742 tgt_fd, req, tc->pcState());
746 /// Target open() handler.
749 openatFunc(SyscallDesc *desc, ThreadContext *tc,
750 int tgt_dirfd, Addr pathname, int tgt_flags, int mode)
752 auto p = tc->getProcessPtr();
755 * Retrieve the simulated process' memory proxy and then read in the path
756 * string from that memory space into the host's working memory space.
759 if (!tc->getVirtProxy().tryReadString(path, pathname))
763 int host_flags = O_BINARY;
768 * Translate target flags into host flags. Flags exist which are not
769 * ported between architectures which can cause check failures.
771 for (int i = 0; i < OS::NUM_OPEN_FLAGS; i++) {
772 if (tgt_flags & OS::openFlagTable[i].tgtFlag) {
773 tgt_flags &= ~OS::openFlagTable[i].tgtFlag;
774 host_flags |= OS::openFlagTable[i].hostFlag;
778 warn("%s: cannot decode flags %#x", desc->name(), tgt_flags);
781 host_flags |= O_BINARY;
785 * If the simulated process called open or openat with AT_FDCWD specified,
786 * take the current working directory value which was passed into the
787 * process class as a Python parameter and append the current path to
788 * create a full path.
789 * Otherwise, openat with a valid target directory file descriptor has
790 * been called. If the path option, which was passed in as a parameter,
791 * is not absolute, retrieve the directory file descriptor's path and
792 * prepend it to the path passed in as a parameter.
793 * In every case, we should have a full path (which is relevant to the
794 * host) to work with after this block has been passed.
796 std::string redir_path = path;
797 std::string abs_path = path;
798 if (tgt_dirfd == OS::TGT_AT_FDCWD) {
799 abs_path = p->absolutePath(path, true);
800 redir_path = p->checkPathRedirect(path);
801 } else if (!startswith(path, "/")) {
802 std::shared_ptr<FDEntry> fdep = ((*p->fds)[tgt_dirfd]);
803 auto ffdp = std::dynamic_pointer_cast<FileFDEntry>(fdep);
806 abs_path = ffdp->getFileName() + path;
807 redir_path = p->checkPathRedirect(abs_path);
811 * Since this is an emulated environment, we create pseudo file
812 * descriptors for device requests that have been registered with
813 * the process class through Python; this allows us to create a file
814 * descriptor for subsequent ioctl or mmap calls.
816 if (startswith(abs_path, "/dev/")) {
817 std::string filename = abs_path.substr(strlen("/dev/"));
818 EmulatedDriver *drv = p->findDriver(filename);
820 DPRINTF_SYSCALL(Verbose, "%s: passing call to "
821 "driver open with path[%s]\n",
822 desc->name(), abs_path.c_str());
823 return drv->open(tc, mode, host_flags);
826 * Fall through here for pass through to host devices, such
832 * We make several attempts resolve a call to open.
834 * 1) Resolve any path redirection before hand. This will set the path
835 * up with variable 'redir_path' which may contain a modified path or
836 * the original path value. This should already be done in prior code.
837 * 2) Try to handle the access using 'special_paths'. Some special_paths
838 * and files cannot be called on the host and need to be handled as
839 * special cases inside the simulator. These special_paths are handled by
840 * C++ routines to provide output back to userspace.
841 * 3) If the full path that was created above does not match any of the
842 * special cases, pass it through to the open call on the __HOST__ to let
843 * the host open the file on our behalf. Again, the openImpl tries to
844 * USE_THE_HOST_FILESYSTEM_OPEN (with a possible redirection to the
845 * faux-filesystem files). The faux-filesystem is dynamically created
846 * during simulator configuration using Python functions.
847 * 4) If the host cannot open the file, the open attempt failed in "3)".
848 * Return the host's error code back through the system call to the
849 * simulated process. If running a debug trace, also notify the user that
850 * the open call failed.
852 * Any success will set sim_fd to something other than -1 and skip the
853 * next conditions effectively bypassing them.
856 std::string used_path;
857 std::vector<std::string> special_paths =
858 { "/proc/meminfo/", "/system/", "/platform/", "/etc/passwd",
859 "/proc/self/maps", "/dev/urandom",
860 "/sys/devices/system/cpu/online" };
861 for (auto entry : special_paths) {
862 if (startswith(path, entry)) {
863 sim_fd = OS::openSpecialFile(abs_path, p, tc);
864 used_path = abs_path;
868 sim_fd = open(redir_path.c_str(), host_flags, mode);
869 used_path = redir_path;
873 DPRINTF_SYSCALL(Verbose, "%s: failed -> path:%s "
874 "(inferred from:%s)\n", desc->name(),
875 used_path.c_str(), path.c_str());
880 * The file was opened successfully and needs to be recorded in the
881 * process' file descriptor array so that it can be retrieved later.
882 * The target file descriptor that is chosen will be the lowest unused
884 * Return the indirect target file descriptor back to the simulated
885 * process to act as a handle for the opened file.
887 auto ffdp = std::make_shared<FileFDEntry>(sim_fd, host_flags, path, 0);
888 int tgt_fd = p->fds->allocFD(ffdp);
889 DPRINTF_SYSCALL(Verbose, "%s: sim_fd[%d], target_fd[%d] -> path:%s\n"
890 "(inferred from:%s)\n", desc->name(),
891 sim_fd, tgt_fd, used_path.c_str(), path.c_str());
895 /// Target open() handler.
898 openFunc(SyscallDesc *desc, ThreadContext *tc,
899 Addr pathname, int tgt_flags, int mode)
901 return openatFunc<OS>(
902 desc, tc, OS::TGT_AT_FDCWD, pathname, tgt_flags, mode);
905 /// Target unlinkat() handler.
908 unlinkatFunc(SyscallDesc *desc, ThreadContext *tc, int dirfd, Addr pathname)
910 if (dirfd != OS::TGT_AT_FDCWD)
911 warn("unlinkat: first argument not AT_FDCWD; unlikely to work");
913 return unlinkFunc(desc, tc, pathname);
916 /// Target facessat() handler
919 faccessatFunc(SyscallDesc *desc, ThreadContext *tc,
920 int dirfd, Addr pathname, int mode)
922 if (dirfd != OS::TGT_AT_FDCWD)
923 warn("faccessat: first argument not AT_FDCWD; unlikely to work");
924 return accessFunc(desc, tc, pathname, mode);
927 /// Target readlinkat() handler
930 readlinkatFunc(SyscallDesc *desc, ThreadContext *tc,
931 int dirfd, Addr pathname, Addr buf, size_t bufsiz)
933 if (dirfd != OS::TGT_AT_FDCWD)
934 warn("openat: first argument not AT_FDCWD; unlikely to work");
935 return readlinkFunc(desc, tc, pathname, buf, bufsiz);
938 /// Target renameat() handler.
941 renameatFunc(SyscallDesc *desc, ThreadContext *tc,
942 int olddirfd, Addr oldpath, int newdirfd, Addr newpath)
944 if (olddirfd != OS::TGT_AT_FDCWD)
945 warn("renameat: first argument not AT_FDCWD; unlikely to work");
947 if (newdirfd != OS::TGT_AT_FDCWD)
948 warn("renameat: third argument not AT_FDCWD; unlikely to work");
950 return renameFunc(desc, tc, oldpath, newpath);
953 /// Target sysinfo() handler.
956 sysinfoFunc(SyscallDesc *desc, ThreadContext *tc,
957 VPtr<typename OS::tgt_sysinfo> sysinfo)
959 auto process = tc->getProcessPtr();
961 sysinfo->uptime = seconds_since_epoch;
962 sysinfo->totalram = process->system->memSize();
963 sysinfo->mem_unit = 1;
968 /// Target chmod() handler.
971 chmodFunc(SyscallDesc *desc, ThreadContext *tc, Addr pathname, mode_t mode)
974 auto process = tc->getProcessPtr();
976 if (!tc->getVirtProxy().tryReadString(path, pathname))
981 // XXX translate mode flags via OS::something???
984 // Adjust path for cwd and redirection
985 path = process->checkPathRedirect(path);
988 int result = chmod(path.c_str(), hostMode);
997 pollFunc(SyscallDesc *desc, ThreadContext *tc,
998 Addr fdsPtr, int nfds, int tmout)
1000 auto p = tc->getProcessPtr();
1002 BufferArg fdsBuf(fdsPtr, sizeof(struct pollfd) * nfds);
1003 fdsBuf.copyIn(tc->getVirtProxy());
1006 * Record the target file descriptors in a local variable. We need to
1007 * replace them with host file descriptors but we need a temporary copy
1008 * for later. Afterwards, replace each target file descriptor in the
1009 * poll_fd array with its host_fd.
1011 int temp_tgt_fds[nfds];
1012 for (int index = 0; index < nfds; index++) {
1013 temp_tgt_fds[index] = ((struct pollfd *)fdsBuf.bufferPtr())[index].fd;
1014 auto tgt_fd = temp_tgt_fds[index];
1015 auto hbfdp = std::dynamic_pointer_cast<HBFDEntry>((*p->fds)[tgt_fd]);
1018 auto host_fd = hbfdp->getSimFD();
1019 ((struct pollfd *)fdsBuf.bufferPtr())[index].fd = host_fd;
1023 * We cannot allow an infinite poll to occur or it will inevitably cause
1024 * a deadlock in the gem5 simulator with clone. We must pass in tmout with
1025 * a non-negative value, however it also makes no sense to poll on the
1026 * underlying host for any other time than tmout a zero timeout.
1030 status = poll((struct pollfd *)fdsBuf.bufferPtr(), nfds, 0);
1033 * If blocking indefinitely, check the signal list to see if a
1034 * signal would break the poll out of the retry cycle and try
1035 * to return the signal interrupt instead.
1037 System *sysh = tc->getSystemPtr();
1038 std::list<BasicSignal>::iterator it;
1039 for (it=sysh->signalList.begin(); it!=sysh->signalList.end(); it++)
1040 if (it->receiver == p)
1042 return SyscallReturn::retry();
1045 status = poll((struct pollfd *)fdsBuf.bufferPtr(), nfds, 0);
1051 * Replace each host_fd in the returned poll_fd array with its original
1052 * target file descriptor.
1054 for (int index = 0; index < nfds; index++) {
1055 auto tgt_fd = temp_tgt_fds[index];
1056 ((struct pollfd *)fdsBuf.bufferPtr())[index].fd = tgt_fd;
1060 * Copy out the pollfd struct because the host may have updated fields
1063 fdsBuf.copyOut(tc->getVirtProxy());
1068 /// Target fchmod() handler.
1071 fchmodFunc(SyscallDesc *desc, ThreadContext *tc, int tgt_fd, uint32_t mode)
1073 auto p = tc->getProcessPtr();
1075 auto ffdp = std::dynamic_pointer_cast<FileFDEntry>((*p->fds)[tgt_fd]);
1078 int sim_fd = ffdp->getSimFD();
1080 mode_t hostMode = mode;
1082 int result = fchmod(sim_fd, hostMode);
1084 return (result < 0) ? -errno : 0;
1087 /// Target mremap() handler.
1090 mremapFunc(SyscallDesc *desc, ThreadContext *tc,
1091 Addr start, uint64_t old_length, uint64_t new_length, uint64_t flags,
1092 GuestABI::VarArgs<uint64_t> varargs)
1094 auto p = tc->getProcessPtr();
1095 Addr page_bytes = p->pTable->pageSize();
1096 uint64_t provided_address = 0;
1097 bool use_provided_address = flags & OS::TGT_MREMAP_FIXED;
1099 if (use_provided_address)
1100 provided_address = varargs.get<uint64_t>();
1102 if ((start % page_bytes != 0) ||
1103 (provided_address % page_bytes != 0)) {
1104 warn("mremap failing: arguments not page aligned");
1108 new_length = roundUp(new_length, page_bytes);
1110 if (new_length > old_length) {
1111 Addr mmap_end = p->memState->getMmapEnd();
1113 if ((start + old_length) == mmap_end &&
1114 (!use_provided_address || provided_address == start)) {
1115 // This case cannot occur when growing downward, as
1116 // start is greater than or equal to mmap_end.
1117 uint64_t diff = new_length - old_length;
1118 p->memState->mapRegion(mmap_end, diff, "remapped");
1119 p->memState->setMmapEnd(mmap_end + diff);
1122 if (!use_provided_address && !(flags & OS::TGT_MREMAP_MAYMOVE)) {
1123 warn("can't remap here and MREMAP_MAYMOVE flag not set\n");
1126 uint64_t new_start = provided_address;
1127 if (!use_provided_address) {
1128 new_start = p->mmapGrowsDown() ?
1129 mmap_end - new_length : mmap_end;
1130 mmap_end = p->mmapGrowsDown() ?
1131 new_start : mmap_end + new_length;
1132 p->memState->setMmapEnd(mmap_end);
1135 warn("mremapping to new vaddr %08p-%08p, adding %d\n",
1136 new_start, new_start + new_length,
1137 new_length - old_length);
1139 // add on the remaining unallocated pages
1140 p->allocateMem(new_start + old_length,
1141 new_length - old_length,
1142 use_provided_address /* clobber */);
1144 if (use_provided_address &&
1145 ((new_start + new_length > p->memState->getMmapEnd() &&
1146 !p->mmapGrowsDown()) ||
1147 (new_start < p->memState->getMmapEnd() &&
1148 p->mmapGrowsDown()))) {
1149 // something fishy going on here, at least notify the user
1150 // @todo: increase mmap_end?
1151 warn("mmap region limit exceeded with MREMAP_FIXED\n");
1154 warn("returning %08p as start\n", new_start);
1155 p->memState->remapRegion(start, new_start, old_length);
1161 if (use_provided_address && provided_address != start)
1162 p->memState->remapRegion(start, provided_address, new_length);
1163 if (new_length != old_length)
1164 p->memState->unmapRegion(start + new_length,
1165 old_length - new_length);
1166 return use_provided_address ? provided_address : start;
1170 /// Target stat() handler.
1173 statFunc(SyscallDesc *desc, ThreadContext *tc,
1174 Addr pathname, VPtr<typename OS::tgt_stat> tgt_stat)
1177 auto process = tc->getProcessPtr();
1179 if (!tc->getVirtProxy().tryReadString(path, pathname))
1182 // Adjust path for cwd and redirection
1183 path = process->checkPathRedirect(path);
1185 struct stat hostBuf;
1186 int result = stat(path.c_str(), &hostBuf);
1191 copyOutStatBuf<OS>(tgt_stat, &hostBuf);
1197 /// Target stat64() handler.
1200 stat64Func(SyscallDesc *desc, ThreadContext *tc,
1201 Addr pathname, VPtr<typename OS::tgt_stat64> tgt_stat)
1204 auto process = tc->getProcessPtr();
1206 if (!tc->getVirtProxy().tryReadString(path, pathname))
1209 // Adjust path for cwd and redirection
1210 path = process->checkPathRedirect(path);
1213 struct stat hostBuf;
1214 int result = stat(path.c_str(), &hostBuf);
1216 struct stat64 hostBuf;
1217 int result = stat64(path.c_str(), &hostBuf);
1223 copyOutStat64Buf<OS>(tgt_stat, &hostBuf);
1229 /// Target fstatat64() handler.
1232 fstatat64Func(SyscallDesc *desc, ThreadContext *tc,
1233 int dirfd, Addr pathname, VPtr<typename OS::tgt_stat64> tgt_stat)
1235 auto process = tc->getProcessPtr();
1236 if (dirfd != OS::TGT_AT_FDCWD)
1237 warn("fstatat64: first argument not AT_FDCWD; unlikely to work");
1240 if (!tc->getVirtProxy().tryReadString(path, pathname))
1243 // Adjust path for cwd and redirection
1244 path = process->checkPathRedirect(path);
1247 struct stat hostBuf;
1248 int result = stat(path.c_str(), &hostBuf);
1250 struct stat64 hostBuf;
1251 int result = stat64(path.c_str(), &hostBuf);
1257 copyOutStat64Buf<OS>(tgt_stat, &hostBuf);
1263 /// Target fstat64() handler.
1266 fstat64Func(SyscallDesc *desc, ThreadContext *tc,
1267 int tgt_fd, VPtr<typename OS::tgt_stat64> tgt_stat)
1269 auto p = tc->getProcessPtr();
1271 auto ffdp = std::dynamic_pointer_cast<HBFDEntry>((*p->fds)[tgt_fd]);
1274 int sim_fd = ffdp->getSimFD();
1277 struct stat hostBuf;
1278 int result = fstat(sim_fd, &hostBuf);
1280 struct stat64 hostBuf;
1281 int result = fstat64(sim_fd, &hostBuf);
1287 copyOutStat64Buf<OS>(tgt_stat, &hostBuf, (sim_fd == 1));
1293 /// Target lstat() handler.
1296 lstatFunc(SyscallDesc *desc, ThreadContext *tc,
1297 Addr pathname, VPtr<typename OS::tgt_stat> tgt_stat)
1300 auto process = tc->getProcessPtr();
1302 if (!tc->getVirtProxy().tryReadString(path, pathname))
1305 // Adjust path for cwd and redirection
1306 path = process->checkPathRedirect(path);
1308 struct stat hostBuf;
1309 int result = lstat(path.c_str(), &hostBuf);
1314 copyOutStatBuf<OS>(tgt_stat, &hostBuf);
1319 /// Target lstat64() handler.
1322 lstat64Func(SyscallDesc *desc, ThreadContext *tc,
1323 Addr pathname, VPtr<typename OS::tgt_stat64> tgt_stat)
1326 auto process = tc->getProcessPtr();
1328 if (!tc->getVirtProxy().tryReadString(path, pathname))
1331 // Adjust path for cwd and redirection
1332 path = process->checkPathRedirect(path);
1335 struct stat hostBuf;
1336 int result = lstat(path.c_str(), &hostBuf);
1338 struct stat64 hostBuf;
1339 int result = lstat64(path.c_str(), &hostBuf);
1345 copyOutStat64Buf<OS>(tgt_stat, &hostBuf);
1350 /// Target fstat() handler.
1353 fstatFunc(SyscallDesc *desc, ThreadContext *tc,
1354 int tgt_fd, VPtr<typename OS::tgt_stat> tgt_stat)
1356 auto p = tc->getProcessPtr();
1358 DPRINTF_SYSCALL(Verbose, "fstat(%d, ...)\n", tgt_fd);
1360 auto ffdp = std::dynamic_pointer_cast<FileFDEntry>((*p->fds)[tgt_fd]);
1363 int sim_fd = ffdp->getSimFD();
1365 struct stat hostBuf;
1366 int result = fstat(sim_fd, &hostBuf);
1371 copyOutStatBuf<OS>(tgt_stat, &hostBuf, (sim_fd == 1));
1376 /// Target statfs() handler.
1379 statfsFunc(SyscallDesc *desc, ThreadContext *tc,
1380 Addr pathname, VPtr<typename OS::tgt_statfs> tgt_stat)
1382 #if defined(__linux__)
1384 auto process = tc->getProcessPtr();
1386 if (!tc->getVirtProxy().tryReadString(path, pathname))
1389 // Adjust path for cwd and redirection
1390 path = process->checkPathRedirect(path);
1392 struct statfs hostBuf;
1393 int result = statfs(path.c_str(), &hostBuf);
1398 copyOutStatfsBuf<OS>(tgt_stat, &hostBuf);
1401 warnUnsupportedOS("statfs");
1408 cloneFunc(SyscallDesc *desc, ThreadContext *tc, RegVal flags, RegVal newStack,
1409 Addr ptidPtr, Addr ctidPtr, Addr tlsPtr)
1411 auto p = tc->getProcessPtr();
1413 if (((flags & OS::TGT_CLONE_SIGHAND)&& !(flags & OS::TGT_CLONE_VM)) ||
1414 ((flags & OS::TGT_CLONE_THREAD) && !(flags & OS::TGT_CLONE_SIGHAND)) ||
1415 ((flags & OS::TGT_CLONE_FS) && (flags & OS::TGT_CLONE_NEWNS)) ||
1416 ((flags & OS::TGT_CLONE_NEWIPC) && (flags & OS::TGT_CLONE_SYSVSEM)) ||
1417 ((flags & OS::TGT_CLONE_NEWPID) && (flags & OS::TGT_CLONE_THREAD)) ||
1418 ((flags & OS::TGT_CLONE_VM) && !(newStack)))
1422 if (!(ctc = tc->getSystemPtr()->threads.findFree())) {
1423 DPRINTF_SYSCALL(Verbose, "clone: no spare thread context in system"
1424 "[cpu %d, thread %d]", tc->cpuId(), tc->threadId());
1429 * Note that ProcessParams is generated by swig and there are no other
1430 * examples of how to create anything but this default constructor. The
1431 * fields are manually initialized instead of passing parameters to the
1434 ProcessParams *pp = new ProcessParams();
1435 pp->executable.assign(*(new std::string(p->progName())));
1436 pp->cmd.push_back(*(new std::string(p->progName())));
1437 pp->system = p->system;
1438 pp->cwd.assign(p->tgtCwd);
1439 pp->input.assign("stdin");
1440 pp->output.assign("stdout");
1441 pp->errout.assign("stderr");
1443 pp->euid = p->euid();
1445 pp->egid = p->egid();
1447 /* Find the first free PID that's less than the maximum */
1448 std::set<int> const& pids = p->system->PIDs;
1449 int temp_pid = *pids.begin();
1452 } while (pids.find(temp_pid) != pids.end());
1453 if (temp_pid >= System::maxPID)
1454 fatal("temp_pid is too large: %d", temp_pid);
1457 pp->ppid = (flags & OS::TGT_CLONE_THREAD) ? p->ppid() : p->pid();
1458 pp->useArchPT = p->useArchPT;
1459 pp->kvmInSE = p->kvmInSE;
1460 Process *cp = pp->create();
1461 // TODO: there is no way to know when the Process SimObject is done with
1462 // the params pointer. Both the params pointer (pp) and the process
1463 // pointer (cp) are normally managed in python and are never cleaned up.
1465 Process *owner = ctc->getProcessPtr();
1466 ctc->setProcessPtr(cp);
1467 cp->assignThreadContext(ctc->contextId());
1468 owner->revokeThreadContext(ctc->contextId());
1470 if (flags & OS::TGT_CLONE_PARENT_SETTID) {
1471 BufferArg ptidBuf(ptidPtr, sizeof(long));
1472 long *ptid = (long *)ptidBuf.bufferPtr();
1474 ptidBuf.copyOut(tc->getVirtProxy());
1477 if (flags & OS::TGT_CLONE_THREAD) {
1478 cp->pTable->shared = true;
1479 cp->useForClone = true;
1482 ctc->setUseForClone(true);
1484 p->clone(tc, ctc, cp, flags);
1486 if (flags & OS::TGT_CLONE_THREAD) {
1488 cp->sigchld = p->sigchld;
1489 } else if (flags & OS::TGT_SIGCHLD) {
1490 *cp->sigchld = true;
1493 if (flags & OS::TGT_CLONE_CHILD_SETTID) {
1494 BufferArg ctidBuf(ctidPtr, sizeof(long));
1495 long *ctid = (long *)ctidBuf.bufferPtr();
1497 ctidBuf.copyOut(ctc->getVirtProxy());
1500 if (flags & OS::TGT_CLONE_CHILD_CLEARTID)
1501 cp->childClearTID = (uint64_t)ctidPtr;
1503 ctc->clearArchRegs();
1505 OS::archClone(flags, p, cp, tc, ctc, newStack, tlsPtr);
1507 desc->returnInto(ctc, 0);
1509 TheISA::PCState cpc = tc->pcState();
1519 cloneBackwardsFunc(SyscallDesc *desc, ThreadContext *tc, RegVal flags,
1520 RegVal newStack, Addr ptidPtr, Addr tlsPtr, Addr ctidPtr)
1522 return cloneFunc<OS>(desc, tc, flags, newStack, ptidPtr, ctidPtr, tlsPtr);
1525 /// Target fstatfs() handler.
1528 fstatfsFunc(SyscallDesc *desc, ThreadContext *tc,
1529 int tgt_fd, VPtr<typename OS::tgt_statfs> tgt_stat)
1531 auto p = tc->getProcessPtr();
1533 auto ffdp = std::dynamic_pointer_cast<FileFDEntry>((*p->fds)[tgt_fd]);
1536 int sim_fd = ffdp->getSimFD();
1538 struct statfs hostBuf;
1539 int result = fstatfs(sim_fd, &hostBuf);
1544 copyOutStatfsBuf<OS>(tgt_stat, &hostBuf);
1549 /// Target readv() handler.
1552 readvFunc(SyscallDesc *desc, ThreadContext *tc,
1553 int tgt_fd, uint64_t tiov_base, size_t count)
1555 auto p = tc->getProcessPtr();
1557 auto ffdp = std::dynamic_pointer_cast<FileFDEntry>((*p->fds)[tgt_fd]);
1560 int sim_fd = ffdp->getSimFD();
1562 PortProxy &prox = tc->getVirtProxy();
1563 typename OS::tgt_iovec tiov[count];
1564 struct iovec hiov[count];
1565 for (size_t i = 0; i < count; ++i) {
1566 prox.readBlob(tiov_base + (i * sizeof(typename OS::tgt_iovec)),
1567 &tiov[i], sizeof(typename OS::tgt_iovec));
1568 hiov[i].iov_len = gtoh(tiov[i].iov_len, OS::byteOrder);
1569 hiov[i].iov_base = new char [hiov[i].iov_len];
1572 int result = readv(sim_fd, hiov, count);
1573 int local_errno = errno;
1575 for (size_t i = 0; i < count; ++i) {
1577 prox.writeBlob(htog(tiov[i].iov_base, OS::byteOrder),
1578 hiov[i].iov_base, hiov[i].iov_len);
1580 delete [] (char *)hiov[i].iov_base;
1583 return (result == -1) ? -local_errno : result;
1586 /// Target writev() handler.
1589 writevFunc(SyscallDesc *desc, ThreadContext *tc,
1590 int tgt_fd, uint64_t tiov_base, size_t count)
1592 auto p = tc->getProcessPtr();
1594 auto hbfdp = std::dynamic_pointer_cast<HBFDEntry>((*p->fds)[tgt_fd]);
1597 int sim_fd = hbfdp->getSimFD();
1599 PortProxy &prox = tc->getVirtProxy();
1600 struct iovec hiov[count];
1601 for (size_t i = 0; i < count; ++i) {
1602 typename OS::tgt_iovec tiov;
1604 prox.readBlob(tiov_base + i*sizeof(typename OS::tgt_iovec),
1605 &tiov, sizeof(typename OS::tgt_iovec));
1606 hiov[i].iov_len = gtoh(tiov.iov_len, OS::byteOrder);
1607 hiov[i].iov_base = new char [hiov[i].iov_len];
1608 prox.readBlob(gtoh(tiov.iov_base, OS::byteOrder), hiov[i].iov_base,
1612 int result = writev(sim_fd, hiov, count);
1614 for (size_t i = 0; i < count; ++i)
1615 delete [] (char *)hiov[i].iov_base;
1617 return (result == -1) ? -errno : result;
1620 /// Target mmap() handler.
1623 mmapFunc(SyscallDesc *desc, ThreadContext *tc,
1624 Addr start, typename OS::size_t length, int prot,
1625 int tgt_flags, int tgt_fd, typename OS::off_t offset)
1627 auto p = tc->getProcessPtr();
1628 Addr page_bytes = p->pTable->pageSize();
1630 if (start & (page_bytes - 1) ||
1631 offset & (page_bytes - 1) ||
1632 (tgt_flags & OS::TGT_MAP_PRIVATE &&
1633 tgt_flags & OS::TGT_MAP_SHARED) ||
1634 (!(tgt_flags & OS::TGT_MAP_PRIVATE) &&
1635 !(tgt_flags & OS::TGT_MAP_SHARED)) ||
1640 if ((prot & PROT_WRITE) && (tgt_flags & OS::TGT_MAP_SHARED)) {
1641 // With shared mmaps, there are two cases to consider:
1642 // 1) anonymous: writes should modify the mapping and this should be
1643 // visible to observers who share the mapping. Currently, it's
1644 // difficult to update the shared mapping because there's no
1645 // structure which maintains information about the which virtual
1646 // memory areas are shared. If that structure existed, it would be
1647 // possible to make the translations point to the same frames.
1648 // 2) file-backed: writes should modify the mapping and the file
1649 // which is backed by the mapping. The shared mapping problem is the
1650 // same as what was mentioned about the anonymous mappings. For
1651 // file-backed mappings, the writes to the file are difficult
1652 // because it requires syncing what the mapping holds with the file
1653 // that resides on the host system. So, any write on a real system
1654 // would cause the change to be propagated to the file mapping at
1655 // some point in the future (the inode is tracked along with the
1656 // mapping). This isn't guaranteed to always happen, but it usually
1657 // works well enough. The guarantee is provided by the msync system
1658 // call. We could force the change through with shared mappings with
1659 // a call to msync, but that again would require more information
1660 // than we currently maintain.
1661 warn_once("mmap: writing to shared mmap region is currently "
1662 "unsupported. The write succeeds on the target, but it "
1663 "will not be propagated to the host or shared mappings");
1666 length = roundUp(length, page_bytes);
1669 if (!(tgt_flags & OS::TGT_MAP_ANONYMOUS)) {
1670 std::shared_ptr<FDEntry> fdep = (*p->fds)[tgt_fd];
1672 auto dfdp = std::dynamic_pointer_cast<DeviceFDEntry>(fdep);
1674 EmulatedDriver *emul_driver = dfdp->getDriver();
1675 return emul_driver->mmap(tc, start, length, prot, tgt_flags,
1679 auto ffdp = std::dynamic_pointer_cast<FileFDEntry>(fdep);
1682 sim_fd = ffdp->getSimFD();
1685 * Maintain the symbol table for dynamic executables.
1686 * The loader will call mmap to map the images into its address
1687 * space and we intercept that here. We can verify that we are
1688 * executing inside the loader by checking the program counter value.
1689 * XXX: with multiprogrammed workloads or multi-node configurations,
1690 * this will not work since there is a single global symbol table.
1692 if (p->interpImage.contains(tc->pcState().instAddr())) {
1693 std::shared_ptr<FDEntry> fdep = (*p->fds)[tgt_fd];
1694 auto ffdp = std::dynamic_pointer_cast<FileFDEntry>(fdep);
1695 auto *lib = Loader::createObjectFile(p->checkPathRedirect(
1696 ffdp->getFileName()));
1697 DPRINTF_SYSCALL(Verbose, "Loading symbols from %s\n",
1698 ffdp->getFileName());
1701 Addr offset = lib->buildImage().minAddr() + start;
1702 Loader::debugSymbolTable.insert(*lib->symtab().offset(offset));
1708 * Not TGT_MAP_FIXED means we can start wherever we want.
1710 if (!(tgt_flags & OS::TGT_MAP_FIXED)) {
1712 * If the application provides us with a hint, we should make some
1713 * small amount of effort to accomodate it. Basically, we check if
1714 * every single VA within the requested range is unused. If it is,
1715 * we give the application the range. If not, we fall back to
1716 * extending the global mmap region.
1718 if (!(start && p->memState->isUnmapped(start, length))) {
1720 * Extend global mmap region to give us some room for the app.
1722 start = p->memState->extendMmap(length);
1726 DPRINTF_SYSCALL(Verbose, " mmap range is 0x%x - 0x%x\n",
1727 start, start + length - 1);
1730 * We only allow mappings to overwrite existing mappings if
1731 * TGT_MAP_FIXED is set. Otherwise it shouldn't be a problem
1732 * because we ignore the start hint if TGT_MAP_FIXED is not set.
1734 if (tgt_flags & OS::TGT_MAP_FIXED) {
1736 * We might already have some old VMAs mapped to this region, so
1737 * make sure to clear em out!
1739 p->memState->unmapRegion(start, length);
1743 * Figure out a human-readable name for the mapping.
1745 std::string region_name;
1746 if (tgt_flags & OS::TGT_MAP_ANONYMOUS) {
1747 region_name = "anon";
1749 std::shared_ptr<FDEntry> fdep = (*p->fds)[tgt_fd];
1750 auto ffdp = std::dynamic_pointer_cast<FileFDEntry>(fdep);
1751 region_name = ffdp->getFileName();
1755 * Setup the correct VMA for this region. The physical pages will be
1758 p->memState->mapRegion(start, length, region_name, sim_fd, offset);
1765 pread64Func(SyscallDesc *desc, ThreadContext *tc,
1766 int tgt_fd, Addr bufPtr, int nbytes, int offset)
1768 auto p = tc->getProcessPtr();
1770 auto ffdp = std::dynamic_pointer_cast<FileFDEntry>((*p->fds)[tgt_fd]);
1773 int sim_fd = ffdp->getSimFD();
1775 BufferArg bufArg(bufPtr, nbytes);
1777 int bytes_read = pread(sim_fd, bufArg.bufferPtr(), nbytes, offset);
1779 bufArg.copyOut(tc->getVirtProxy());
1781 return (bytes_read == -1) ? -errno : bytes_read;
1786 pwrite64Func(SyscallDesc *desc, ThreadContext *tc,
1787 int tgt_fd, Addr bufPtr, int nbytes, int offset)
1789 auto p = tc->getProcessPtr();
1791 auto ffdp = std::dynamic_pointer_cast<FileFDEntry>((*p->fds)[tgt_fd]);
1794 int sim_fd = ffdp->getSimFD();
1796 BufferArg bufArg(bufPtr, nbytes);
1797 bufArg.copyIn(tc->getVirtProxy());
1799 int bytes_written = pwrite(sim_fd, bufArg.bufferPtr(), nbytes, offset);
1801 return (bytes_written == -1) ? -errno : bytes_written;
1804 /// Target mmap2() handler.
1807 mmap2Func(SyscallDesc *desc, ThreadContext *tc,
1808 Addr start, typename OS::size_t length, int prot,
1809 int tgt_flags, int tgt_fd, typename OS::off_t offset)
1811 auto page_size = tc->getProcessPtr()->pTable->pageSize();
1812 return mmapFunc<OS>(desc, tc, start, length, prot, tgt_flags,
1813 tgt_fd, offset * page_size);
1816 /// Target getrlimit() handler.
1819 getrlimitFunc(SyscallDesc *desc, ThreadContext *tc,
1820 unsigned resource, VPtr<typename OS::rlimit> rlp)
1822 const ByteOrder bo = OS::byteOrder;
1824 case OS::TGT_RLIMIT_STACK:
1825 // max stack size in bytes: make up a number (8MiB for now)
1826 rlp->rlim_cur = rlp->rlim_max = 8 * 1024 * 1024;
1827 rlp->rlim_cur = htog(rlp->rlim_cur, bo);
1828 rlp->rlim_max = htog(rlp->rlim_max, bo);
1831 case OS::TGT_RLIMIT_DATA:
1832 // max data segment size in bytes: make up a number
1833 rlp->rlim_cur = rlp->rlim_max = 256 * 1024 * 1024;
1834 rlp->rlim_cur = htog(rlp->rlim_cur, bo);
1835 rlp->rlim_max = htog(rlp->rlim_max, bo);
1838 case OS::TGT_RLIMIT_NPROC:
1839 rlp->rlim_cur = rlp->rlim_max = tc->getSystemPtr()->threads.size();
1840 rlp->rlim_cur = htog(rlp->rlim_cur, bo);
1841 rlp->rlim_max = htog(rlp->rlim_max, bo);
1845 warn("getrlimit: unimplemented resource %d", resource);
1855 prlimitFunc(SyscallDesc *desc, ThreadContext *tc,
1856 int pid, int resource, Addr n, VPtr<typename OS::rlimit> rlp)
1859 warn("prlimit: ignoring rlimits for nonzero pid");
1863 warn("prlimit: ignoring new rlimit");
1865 const ByteOrder bo = OS::byteOrder;
1867 case OS::TGT_RLIMIT_STACK:
1868 // max stack size in bytes: make up a number (8MiB for now)
1869 rlp->rlim_cur = rlp->rlim_max = 8 * 1024 * 1024;
1870 rlp->rlim_cur = htog(rlp->rlim_cur, bo);
1871 rlp->rlim_max = htog(rlp->rlim_max, bo);
1873 case OS::TGT_RLIMIT_DATA:
1874 // max data segment size in bytes: make up a number
1875 rlp->rlim_cur = rlp->rlim_max = 256*1024*1024;
1876 rlp->rlim_cur = htog(rlp->rlim_cur, bo);
1877 rlp->rlim_max = htog(rlp->rlim_max, bo);
1880 warn("prlimit: unimplemented resource %d", resource);
1888 /// Target clock_gettime() function.
1891 clock_gettimeFunc(SyscallDesc *desc, ThreadContext *tc,
1892 int clk_id, VPtr<typename OS::timespec> tp)
1894 getElapsedTimeNano(tp->tv_sec, tp->tv_nsec);
1895 tp->tv_sec += seconds_since_epoch;
1896 tp->tv_sec = htog(tp->tv_sec, OS::byteOrder);
1897 tp->tv_nsec = htog(tp->tv_nsec, OS::byteOrder);
1902 /// Target clock_getres() function.
1905 clock_getresFunc(SyscallDesc *desc, ThreadContext *tc, int clk_id,
1906 VPtr<typename OS::timespec> tp)
1908 // Set resolution at ns, which is what clock_gettime() returns
1915 /// Target gettimeofday() handler.
1918 gettimeofdayFunc(SyscallDesc *desc, ThreadContext *tc,
1919 VPtr<typename OS::timeval> tp, Addr tz_ptr)
1921 getElapsedTimeMicro(tp->tv_sec, tp->tv_usec);
1922 tp->tv_sec += seconds_since_epoch;
1923 tp->tv_sec = htog(tp->tv_sec, OS::byteOrder);
1924 tp->tv_usec = htog(tp->tv_usec, OS::byteOrder);
1930 /// Target utimes() handler.
1933 utimesFunc(SyscallDesc *desc, ThreadContext *tc, Addr pathname,
1934 VPtr<typename OS::timeval [2]> tp)
1937 auto process = tc->getProcessPtr();
1939 if (!tc->getVirtProxy().tryReadString(path, pathname))
1942 struct timeval hostTimeval[2];
1943 for (int i = 0; i < 2; ++i) {
1944 hostTimeval[i].tv_sec = gtoh((*tp)[i].tv_sec, OS::byteOrder);
1945 hostTimeval[i].tv_usec = gtoh((*tp)[i].tv_usec, OS::byteOrder);
1948 // Adjust path for cwd and redirection
1949 path = process->checkPathRedirect(path);
1951 int result = utimes(path.c_str(), hostTimeval);
1961 execveFunc(SyscallDesc *desc, ThreadContext *tc,
1962 Addr pathname, Addr argv_mem_loc, Addr envp_mem_loc)
1964 auto p = tc->getProcessPtr();
1967 PortProxy & mem_proxy = tc->getVirtProxy();
1968 if (!mem_proxy.tryReadString(path, pathname))
1971 if (access(path.c_str(), F_OK) == -1)
1974 auto read_in = [](std::vector<std::string> &vect,
1975 PortProxy &mem_proxy, Addr mem_loc)
1977 for (int inc = 0; ; inc++) {
1978 BufferArg b((mem_loc + sizeof(Addr) * inc), sizeof(Addr));
1979 b.copyIn(mem_proxy);
1981 if (!*(Addr*)b.bufferPtr())
1984 vect.push_back(std::string());
1985 mem_proxy.tryReadString(vect[inc], *(Addr*)b.bufferPtr());
1990 * Note that ProcessParams is generated by swig and there are no other
1991 * examples of how to create anything but this default constructor. The
1992 * fields are manually initialized instead of passing parameters to the
1995 ProcessParams *pp = new ProcessParams();
1996 pp->executable = path;
1997 read_in(pp->cmd, mem_proxy, argv_mem_loc);
1998 read_in(pp->env, mem_proxy, envp_mem_loc);
2000 pp->egid = p->egid();
2001 pp->euid = p->euid();
2003 pp->ppid = p->ppid();
2005 pp->input.assign("cin");
2006 pp->output.assign("cout");
2007 pp->errout.assign("cerr");
2008 pp->cwd.assign(p->tgtCwd);
2009 pp->system = p->system;
2011 * Prevent process object creation with identical PIDs (which will trip
2012 * a fatal check in Process constructor). The execve call is supposed to
2013 * take over the currently executing process' identity but replace
2014 * whatever it is doing with a new process image. Instead of hijacking
2015 * the process object in the simulator, we create a new process object
2016 * and bind to the previous process' thread below (hijacking the thread).
2018 p->system->PIDs.erase(p->pid());
2019 Process *new_p = pp->create();
2023 * Work through the file descriptor array and close any files marked
2026 new_p->fds = p->fds;
2027 for (int i = 0; i < new_p->fds->getSize(); i++) {
2028 std::shared_ptr<FDEntry> fdep = (*new_p->fds)[i];
2029 if (fdep && fdep->getCOE())
2030 new_p->fds->closeFDEntry(i);
2033 *new_p->sigchld = true;
2036 tc->clearArchRegs();
2037 tc->setProcessPtr(new_p);
2038 new_p->assignThreadContext(tc->contextId());
2041 TheISA::PCState pcState = tc->pcState();
2042 tc->setNPC(pcState.instAddr());
2044 return SyscallReturn();
2047 /// Target getrusage() function.
2050 getrusageFunc(SyscallDesc *desc, ThreadContext *tc,
2051 int who /* THREAD, SELF, or CHILDREN */,
2052 VPtr<typename OS::rusage> rup)
2054 rup->ru_utime.tv_sec = 0;
2055 rup->ru_utime.tv_usec = 0;
2056 rup->ru_stime.tv_sec = 0;
2057 rup->ru_stime.tv_usec = 0;
2065 rup->ru_inblock = 0;
2066 rup->ru_oublock = 0;
2069 rup->ru_nsignals = 0;
2074 case OS::TGT_RUSAGE_SELF:
2075 getElapsedTimeMicro(rup->ru_utime.tv_sec, rup->ru_utime.tv_usec);
2076 rup->ru_utime.tv_sec = htog(rup->ru_utime.tv_sec, OS::byteOrder);
2077 rup->ru_utime.tv_usec = htog(rup->ru_utime.tv_usec, OS::byteOrder);
2080 case OS::TGT_RUSAGE_CHILDREN:
2081 // do nothing. We have no child processes, so they take no time.
2085 // don't really handle THREAD or CHILDREN, but just warn and
2087 warn("getrusage() only supports RUSAGE_SELF. Parameter %d ignored.",
2094 /// Target times() function.
2097 timesFunc(SyscallDesc *desc, ThreadContext *tc, VPtr<typename OS::tms> bufp)
2099 // Fill in the time structure (in clocks)
2100 int64_t clocks = curTick() * OS::M5_SC_CLK_TCK / SimClock::Int::s;
2101 bufp->tms_utime = clocks;
2102 bufp->tms_stime = 0;
2103 bufp->tms_cutime = 0;
2104 bufp->tms_cstime = 0;
2106 // Convert to host endianness
2107 bufp->tms_utime = htog(bufp->tms_utime, OS::byteOrder);
2109 // Return clock ticks since system boot
2113 /// Target time() function.
2116 timeFunc(SyscallDesc *desc, ThreadContext *tc, Addr taddr)
2118 typename OS::time_t sec, usec;
2119 getElapsedTimeMicro(sec, usec);
2120 sec += seconds_since_epoch;
2123 typename OS::time_t t = sec;
2124 t = htog(t, OS::byteOrder);
2125 PortProxy &p = tc->getVirtProxy();
2126 p.writeBlob(taddr, &t, (int)sizeof(typename OS::time_t));
2133 tgkillFunc(SyscallDesc *desc, ThreadContext *tc, int tgid, int tid, int sig)
2136 * This system call is intended to allow killing a specific thread
2137 * within an arbitrary thread group if sanctioned with permission checks.
2138 * It's usually true that threads share the termination signal as pointed
2139 * out by the pthread_kill man page and this seems to be the intended
2140 * usage. Due to this being an emulated environment, assume the following:
2141 * Threads are allowed to call tgkill because the EUID for all threads
2142 * should be the same. There is no signal handling mechanism for kernel
2143 * registration of signal handlers since signals are poorly supported in
2144 * emulation mode. Since signal handlers cannot be registered, all
2145 * threads within in a thread group must share the termination signal.
2146 * We never exhaust PIDs so there's no chance of finding the wrong one
2147 * due to PID rollover.
2150 System *sys = tc->getSystemPtr();
2151 Process *tgt_proc = nullptr;
2152 for (auto *tc: sys->threads) {
2153 Process *temp = tc->getProcessPtr();
2154 if (temp->pid() == tid) {
2160 if (sig != 0 || sig != OS::TGT_SIGABRT)
2163 if (tgt_proc == nullptr)
2166 if (tgid != -1 && tgt_proc->tgid() != tgid)
2169 if (sig == OS::TGT_SIGABRT)
2170 exitGroupFunc(desc, tc, 0);
2177 socketFunc(SyscallDesc *desc, ThreadContext *tc,
2178 int domain, int type, int prot)
2180 auto p = tc->getProcessPtr();
2182 int sim_fd = socket(domain, type, prot);
2186 auto sfdp = std::make_shared<SocketFDEntry>(sim_fd, domain, type, prot);
2187 int tgt_fd = p->fds->allocFD(sfdp);
2194 socketpairFunc(SyscallDesc *desc, ThreadContext *tc,
2195 int domain, int type, int prot, Addr svPtr)
2197 auto p = tc->getProcessPtr();
2199 BufferArg svBuf((Addr)svPtr, 2 * sizeof(int));
2200 int status = socketpair(domain, type, prot, (int *)svBuf.bufferPtr());
2204 int *fds = (int *)svBuf.bufferPtr();
2206 auto sfdp1 = std::make_shared<SocketFDEntry>(fds[0], domain, type, prot);
2207 fds[0] = p->fds->allocFD(sfdp1);
2208 auto sfdp2 = std::make_shared<SocketFDEntry>(fds[1], domain, type, prot);
2209 fds[1] = p->fds->allocFD(sfdp2);
2210 svBuf.copyOut(tc->getVirtProxy());
2217 selectFunc(SyscallDesc *desc, ThreadContext *tc, int nfds,
2218 VPtr<typename OS::fd_set> readfds,
2219 VPtr<typename OS::fd_set> writefds,
2220 VPtr<typename OS::fd_set> errorfds,
2221 VPtr<typename OS::timeval> timeout)
2225 auto p = tc->getProcessPtr();
2228 * Host fields. Notice that these use the definitions from the system
2229 * headers instead of the gem5 headers and libraries. If the host and
2230 * target have different header file definitions, this will not work.
2233 FD_ZERO(&readfds_h);
2235 FD_ZERO(&writefds_h);
2237 FD_ZERO(&errorfds_h);
2240 * We need to translate the target file descriptor set into a host file
2241 * descriptor set. This involves both our internal process fd array
2242 * and the fd_set defined in Linux header files. The nfds field also
2243 * needs to be updated as it will be only target specific after
2244 * retrieving it from the target; the nfds value is expected to be the
2245 * highest file descriptor that needs to be checked, so we need to extend
2246 * it out for nfds_h when we do the update.
2249 std::map<int, int> trans_map;
2250 auto try_add_host_set = [&](typename OS::fd_set *tgt_set_entry,
2251 fd_set *hst_set_entry,
2255 * By this point, we know that we are looking at a valid file
2256 * descriptor set on the target. We need to check if the target file
2257 * descriptor value passed in as iter is part of the set.
2259 if (FD_ISSET(iter, (fd_set *)tgt_set_entry)) {
2261 * We know that the target file descriptor belongs to the set,
2262 * but we do not yet know if the file descriptor is valid or
2263 * that we have a host mapping. Check that now.
2265 auto hbfdp = std::dynamic_pointer_cast<HBFDEntry>((*p->fds)[iter]);
2268 auto sim_fd = hbfdp->getSimFD();
2271 * Add the sim_fd to tgt_fd translation into trans_map for use
2272 * later when we need to zero the target fd_set structures and
2273 * then update them with hits returned from the host select call.
2275 trans_map[sim_fd] = iter;
2278 * We know that the host file descriptor exists so now we check
2279 * if we need to update the max count for nfds_h before passing
2280 * the duplicated structure into the host.
2282 nfds_h = std::max(nfds_h - 1, sim_fd + 1);
2285 * Add the host file descriptor to the set that we are going to
2286 * pass into the host.
2288 FD_SET(sim_fd, hst_set_entry);
2293 for (int i = 0; i < nfds; i++) {
2295 bool ebadf = try_add_host_set(readfds, &readfds_h, i);
2300 bool ebadf = try_add_host_set(writefds, &writefds_h, i);
2305 bool ebadf = try_add_host_set(errorfds, &errorfds_h, i);
2313 * It might be possible to decrement the timeval based on some
2314 * derivation of wall clock determined from elapsed simulator ticks
2315 * but that seems like overkill. Rather, we just set the timeval with
2316 * zero timeout. (There is no reason to block during the simulation
2317 * as it only decreases simulator performance.)
2319 timeout->tv_sec = 0;
2320 timeout->tv_usec = 0;
2322 retval = select(nfds_h,
2323 readfds ? &readfds_h : nullptr,
2324 writefds ? &writefds_h : nullptr,
2325 errorfds ? &errorfds_h : nullptr,
2326 (timeval *)(typename OS::timeval *)timeout);
2329 * If the timeval pointer is null, setup a new timeval structure to
2330 * pass into the host select call. Unfortunately, we will need to
2331 * manually check the return value and throw a retry fault if the
2332 * return value is zero. Allowing the system call to block will
2333 * likely deadlock the event queue.
2335 struct timeval tv = { 0, 0 };
2337 retval = select(nfds_h,
2338 readfds ? &readfds_h : nullptr,
2339 readfds ? &writefds_h : nullptr,
2340 readfds ? &errorfds_h : nullptr,
2345 * If blocking indefinitely, check the signal list to see if a
2346 * signal would break the poll out of the retry cycle and try to
2347 * return the signal interrupt instead.
2349 for (auto sig : tc->getSystemPtr()->signalList)
2350 if (sig.receiver == p)
2352 return SyscallReturn::retry();
2359 FD_ZERO(reinterpret_cast<fd_set *>((typename OS::fd_set *)readfds));
2360 FD_ZERO(reinterpret_cast<fd_set *>((typename OS::fd_set *)writefds));
2361 FD_ZERO(reinterpret_cast<fd_set *>((typename OS::fd_set *)errorfds));
2364 * We need to translate the host file descriptor set into a target file
2365 * descriptor set. This involves both our internal process fd array
2366 * and the fd_set defined in header files.
2368 for (int i = 0; i < nfds_h; i++) {
2369 if (readfds && FD_ISSET(i, &readfds_h))
2370 FD_SET(trans_map[i], readfds);
2372 if (writefds && FD_ISSET(i, &writefds_h))
2373 FD_SET(trans_map[i], writefds);
2375 if (errorfds && FD_ISSET(i, &errorfds_h))
2376 FD_SET(trans_map[i], errorfds);
2384 readFunc(SyscallDesc *desc, ThreadContext *tc,
2385 int tgt_fd, Addr buf_ptr, int nbytes)
2387 auto p = tc->getProcessPtr();
2389 auto hbfdp = std::dynamic_pointer_cast<HBFDEntry>((*p->fds)[tgt_fd]);
2392 int sim_fd = hbfdp->getSimFD();
2396 pfd.events = POLLIN | POLLPRI;
2397 if ((poll(&pfd, 1, 0) == 0)
2398 && !(hbfdp->getFlags() & OS::TGT_O_NONBLOCK))
2399 return SyscallReturn::retry();
2401 BufferArg buf_arg(buf_ptr, nbytes);
2402 int bytes_read = read(sim_fd, buf_arg.bufferPtr(), nbytes);
2405 buf_arg.copyOut(tc->getVirtProxy());
2407 return (bytes_read == -1) ? -errno : bytes_read;
2412 writeFunc(SyscallDesc *desc, ThreadContext *tc,
2413 int tgt_fd, Addr buf_ptr, int nbytes)
2415 auto p = tc->getProcessPtr();
2417 auto hbfdp = std::dynamic_pointer_cast<HBFDEntry>((*p->fds)[tgt_fd]);
2420 int sim_fd = hbfdp->getSimFD();
2422 BufferArg buf_arg(buf_ptr, nbytes);
2423 buf_arg.copyIn(tc->getVirtProxy());
2427 pfd.events = POLLOUT;
2430 * We don't want to poll on /dev/random. The kernel will not enable the
2431 * file descriptor for writing unless the entropy in the system falls
2432 * below write_wakeup_threshold. This is not guaranteed to happen
2433 * depending on host settings.
2435 auto ffdp = std::dynamic_pointer_cast<FileFDEntry>(hbfdp);
2436 if (ffdp && (ffdp->getFileName() != "/dev/random")) {
2437 if (!poll(&pfd, 1, 0) && !(ffdp->getFlags() & OS::TGT_O_NONBLOCK))
2438 return SyscallReturn::retry();
2441 int bytes_written = write(sim_fd, buf_arg.bufferPtr(), nbytes);
2443 if (bytes_written != -1)
2446 return (bytes_written == -1) ? -errno : bytes_written;
2451 wait4Func(SyscallDesc *desc, ThreadContext *tc,
2452 pid_t pid, Addr statPtr, int options, Addr rusagePtr)
2454 auto p = tc->getProcessPtr();
2457 DPRINTF_SYSCALL(Verbose, "wait4: rusage pointer provided %lx, however "
2458 "functionality not supported. Ignoring rusage pointer.\n",
2462 * Currently, wait4 is only implemented so that it will wait for children
2463 * exit conditions which are denoted by a SIGCHLD signals posted into the
2464 * system signal list. We return no additional information via any of the
2465 * parameters supplied to wait4. If nothing is found in the system signal
2466 * list, we will wait indefinitely for SIGCHLD to post by retrying the
2469 System *sysh = tc->getSystemPtr();
2470 std::list<BasicSignal>::iterator iter;
2471 for (iter=sysh->signalList.begin(); iter!=sysh->signalList.end(); iter++) {
2472 if (iter->receiver == p) {
2474 if ((iter->sender->pgid() == -pid)
2475 && (iter->signalValue == OS::TGT_SIGCHLD))
2477 } else if (pid == -1) {
2478 if (iter->signalValue == OS::TGT_SIGCHLD)
2480 } else if (pid == 0) {
2481 if ((iter->sender->pgid() == p->pgid())
2482 && (iter->signalValue == OS::TGT_SIGCHLD))
2485 if ((iter->sender->pid() == pid)
2486 && (iter->signalValue == OS::TGT_SIGCHLD))
2492 return (options & OS::TGT_WNOHANG) ? 0 : SyscallReturn::retry();
2495 // Set status to EXITED for WIFEXITED evaluations.
2496 const int EXITED = 0;
2497 BufferArg statusBuf(statPtr, sizeof(int));
2498 *(int *)statusBuf.bufferPtr() = EXITED;
2499 statusBuf.copyOut(tc->getVirtProxy());
2501 // Return the child PID.
2502 pid_t retval = iter->sender->pid();
2503 sysh->signalList.erase(iter);
2509 acceptFunc(SyscallDesc *desc, ThreadContext *tc,
2510 int tgt_fd, Addr addrPtr, Addr lenPtr)
2515 auto p = tc->getProcessPtr();
2517 BufferArg *lenBufPtr = nullptr;
2518 BufferArg *addrBufPtr = nullptr;
2520 auto sfdp = std::dynamic_pointer_cast<SocketFDEntry>((*p->fds)[tgt_fd]);
2523 int sim_fd = sfdp->getSimFD();
2526 * We poll the socket file descriptor first to guarantee that we do not
2527 * block on our accept call. The socket can be opened without the
2528 * non-blocking flag (it blocks). This will cause deadlocks between
2529 * communicating processes.
2533 pfd.events = POLLIN | POLLPRI;
2534 if ((poll(&pfd, 1, 0) == 0) && !(sfdp->getFlags() & OS::TGT_O_NONBLOCK))
2535 return SyscallReturn::retry();
2538 lenBufPtr = new BufferArg(lenPtr, sizeof(socklen_t));
2539 lenBufPtr->copyIn(tc->getVirtProxy());
2540 memcpy(&addrLen, (socklen_t *)lenBufPtr->bufferPtr(),
2545 addrBufPtr = new BufferArg(addrPtr, sizeof(struct sockaddr));
2546 addrBufPtr->copyIn(tc->getVirtProxy());
2547 memcpy(&sa, (struct sockaddr *)addrBufPtr->bufferPtr(),
2548 sizeof(struct sockaddr));
2551 host_fd = accept(sim_fd, &sa, &addrLen);
2557 memcpy(addrBufPtr->bufferPtr(), &sa, sizeof(sa));
2558 addrBufPtr->copyOut(tc->getVirtProxy());
2563 *(socklen_t *)lenBufPtr->bufferPtr() = addrLen;
2564 lenBufPtr->copyOut(tc->getVirtProxy());
2568 auto afdp = std::make_shared<SocketFDEntry>(host_fd, sfdp->_domain,
2569 sfdp->_type, sfdp->_protocol);
2570 return p->fds->allocFD(afdp);
2573 /// Target eventfd() function.
2576 eventfdFunc(SyscallDesc *desc, ThreadContext *tc,
2577 unsigned initval, int in_flags)
2579 #if defined(__linux__)
2580 auto p = tc->getProcessPtr();
2582 int sim_fd = eventfd(initval, in_flags);
2586 bool cloexec = in_flags & OS::TGT_O_CLOEXEC;
2588 int flags = cloexec ? OS::TGT_O_CLOEXEC : 0;
2589 flags |= (in_flags & OS::TGT_O_NONBLOCK) ? OS::TGT_O_NONBLOCK : 0;
2591 auto hbfdp = std::make_shared<HBFDEntry>(flags, sim_fd, cloexec);
2592 int tgt_fd = p->fds->allocFD(hbfdp);
2595 warnUnsupportedOS("eventfd");
2600 #endif // __SIM_SYSCALL_EMUL_HH__