gem5 v24.0.0.0
Loading...
Searching...
No Matches
syscall_emul.hh
Go to the documentation of this file.
1/*
2 * Copyright (c) 2012-2013, 2015, 2019-2021, 2023 Arm Limited
3 * Copyright (c) 2015 Advanced Micro Devices, Inc.
4 * All rights reserved
5 *
6 * The license below extends only to copyright in the software and shall
7 * not be construed as granting a license to any other intellectual
8 * property including but not limited to intellectual property relating
9 * to a hardware implementation of the functionality of the software
10 * licensed hereunder. You may use the software subject to the license
11 * terms below provided that you ensure that this notice is replicated
12 * unmodified and in its entirety in all distributions of the software,
13 * modified or unmodified, in source code or in binary form.
14 *
15 * Copyright (c) 2003-2005 The Regents of The University of Michigan
16 * All rights reserved.
17 *
18 * Redistribution and use in source and binary forms, with or without
19 * modification, are permitted provided that the following conditions are
20 * met: redistributions of source code must retain the above copyright
21 * notice, this list of conditions and the following disclaimer;
22 * redistributions in binary form must reproduce the above copyright
23 * notice, this list of conditions and the following disclaimer in the
24 * documentation and/or other materials provided with the distribution;
25 * neither the name of the copyright holders nor the names of its
26 * contributors may be used to endorse or promote products derived from
27 * this software without specific prior written permission.
28 *
29 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
30 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
31 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
32 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
33 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
34 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
35 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
36 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
37 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
38 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
39 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
40 */
41
42#ifndef __SIM_SYSCALL_EMUL_HH__
43#define __SIM_SYSCALL_EMUL_HH__
44
45#if (defined(__APPLE__) || defined(__OpenBSD__) || \
46 defined(__FreeBSD__) || defined(__CYGWIN__) || \
47 defined(__NetBSD__))
48#define NO_STAT64 1
49#else
50#define NO_STAT64 0
51#endif
52
58
59#if defined(__linux__)
60#include <linux/kdev_t.h>
61#include <sched.h>
62#include <sys/eventfd.h>
63#include <sys/statfs.h>
64
65#else
66#include <sys/mount.h>
67
68#endif
69
70#ifdef __CYGWIN32__
71#include <sys/fcntl.h>
72
73#endif
74#include <fcntl.h>
75#include <net/if.h>
76#include <poll.h>
77#include <sys/ioctl.h>
78#include <sys/mman.h>
79#include <sys/socket.h>
80#include <sys/stat.h>
81#include <sys/time.h>
82#include <sys/types.h>
83#include <sys/uio.h>
84#include <unistd.h>
85
86#include <cerrno>
87#include <memory>
88#include <string>
89
90#include "arch/generic/tlb.hh"
91#include "base/intmath.hh"
93#include "base/logging.hh"
94#include "base/random.hh"
95#include "base/trace.hh"
96#include "base/types.hh"
97#include "cpu/base.hh"
98#include "cpu/thread_context.hh"
99#include "kern/linux/linux.hh"
100#include "mem/page_table.hh"
102#include "params/Process.hh"
103#include "sim/emul_driver.hh"
104#include "sim/futex_map.hh"
105#include "sim/guest_abi.hh"
106#include "sim/process.hh"
107#include "sim/proxy_ptr.hh"
109#include "sim/syscall_desc.hh"
111#include "sim/syscall_return.hh"
112
113#if defined(__APPLE__) && defined(__MACH__) && !defined(CMSG_ALIGN)
114#define CMSG_ALIGN(len) (((len) + sizeof(size_t) - 1) & ~(sizeof(size_t) - 1))
115#elif defined(__FreeBSD__) && !defined(CMSG_ALIGN)
116#define CMSG_ALIGN(n) _ALIGN(n)
117#endif
118
119namespace gem5
120{
121
123//
124// The following emulation functions are generic enough that they
125// don't need to be recompiled for different emulated OS's. They are
126// defined in sim/syscall_emul.cc.
127//
129
130void warnUnsupportedOS(std::string syscall_name);
131
133SyscallReturn unimplementedFunc(SyscallDesc *desc, ThreadContext *tc);
134
139SyscallReturn ignoreFunc(SyscallDesc *desc, ThreadContext *tc);
141SyscallReturn
142ignoreWarnOnceFunc(SyscallDesc *desc, ThreadContext *tc);
143
145SyscallReturn exitFunc(SyscallDesc *desc, ThreadContext *tc, int status);
146
148SyscallReturn exitGroupFunc(SyscallDesc *desc, ThreadContext *tc, int status);
149
151SyscallReturn setTidAddressFunc(SyscallDesc *desc, ThreadContext *tc,
152 uint64_t tidPtr);
153
155SyscallReturn getpagesizeFunc(SyscallDesc *desc, ThreadContext *tc);
156
158SyscallReturn brkFunc(SyscallDesc *desc, ThreadContext *tc, VPtr<> new_brk);
159
161SyscallReturn closeFunc(SyscallDesc *desc, ThreadContext *tc, int tgt_fd);
162
164SyscallReturn lseekFunc(SyscallDesc *desc, ThreadContext *tc,
165 int tgt_fd, uint64_t offs, int whence);
166
168SyscallReturn _llseekFunc(SyscallDesc *desc, ThreadContext *tc,
169 int tgt_fd, uint64_t offset_high,
170 uint32_t offset_low, VPtr<> result_ptr, int whence);
171
173SyscallReturn shutdownFunc(SyscallDesc *desc, ThreadContext *tc,
174 int tgt_fd, int how);
175
177SyscallReturn gethostnameFunc(SyscallDesc *desc, ThreadContext *tc,
178 VPtr<> buf_ptr, int name_len);
179
181SyscallReturn getcwdFunc(SyscallDesc *desc, ThreadContext *tc,
182 VPtr<> buf_ptr, unsigned long size);
183
185SyscallReturn unlinkFunc(SyscallDesc *desc, ThreadContext *tc,
186 VPtr<> pathname);
187SyscallReturn unlinkImpl(SyscallDesc *desc, ThreadContext *tc,
188 std::string path);
189
191SyscallReturn linkFunc(SyscallDesc *desc, ThreadContext *tc,
192 VPtr<> pathname, VPtr<> new_pathname);
193
195SyscallReturn symlinkFunc(SyscallDesc *desc, ThreadContext *tc,
196 VPtr<> pathname, VPtr<> new_pathname);
197
199SyscallReturn mkdirFunc(SyscallDesc *desc, ThreadContext *tc,
200 VPtr<> pathname, mode_t mode);
201SyscallReturn mkdirImpl(SyscallDesc *desc, ThreadContext *tc,
202 std::string path, mode_t mode);
203
205SyscallReturn mknodFunc(SyscallDesc *desc, ThreadContext *tc,
206 VPtr<> pathname, mode_t mode, dev_t dev);
207SyscallReturn mknodImpl(SyscallDesc *desc, ThreadContext *tc,
208 std::string path, mode_t mode, dev_t dev);
209
211SyscallReturn chdirFunc(SyscallDesc *desc, ThreadContext *tc, VPtr<> pathname);
212
213// Target rmdir() handler.
214SyscallReturn rmdirFunc(SyscallDesc *desc, ThreadContext *tc,
215 VPtr<> pathname);
216SyscallReturn rmdirImpl(SyscallDesc *desc, ThreadContext *tc,
217 std::string path);
218
220SyscallReturn renameFunc(SyscallDesc *desc, ThreadContext *tc,
221 VPtr<> oldpath, VPtr<> newpath);
222SyscallReturn renameImpl(SyscallDesc *desc, ThreadContext *tc,
223 std::string oldpath, std::string newpath);
224
226SyscallReturn truncate64Func(SyscallDesc *desc, ThreadContext *tc,
227 VPtr<> pathname, int64_t length);
228
230SyscallReturn ftruncate64Func(SyscallDesc *desc, ThreadContext *tc,
231 int tgt_fd, int64_t length);
232
234SyscallReturn umaskFunc(SyscallDesc *desc, ThreadContext *tc);
235
237SyscallReturn gettidFunc(SyscallDesc *desc, ThreadContext *tc);
238
240SyscallReturn chownFunc(SyscallDesc *desc, ThreadContext *tc,
241 VPtr<> pathname, uint32_t owner, uint32_t group);
242SyscallReturn chownImpl(SyscallDesc *desc, ThreadContext *tc,
243 std::string path, uint32_t owner, uint32_t group);
244
246SyscallReturn getpgrpFunc(SyscallDesc *desc, ThreadContext *tc);
247
249SyscallReturn setpgidFunc(SyscallDesc *desc, ThreadContext *tc,
250 int pid, int pgid);
251
253SyscallReturn fchownFunc(SyscallDesc *desc, ThreadContext *tc,
254 int tgt_fd, uint32_t owner, uint32_t group);
255
257SyscallReturn dupFunc(SyscallDesc *desc, ThreadContext *tc,
258 int tgt_fd);
259
261SyscallReturn dup2Func(SyscallDesc *desc, ThreadContext *tc,
262 int old_tgt_fd, int new_tgt_fd);
263
265SyscallReturn fcntlFunc(SyscallDesc *desc, ThreadContext *tc,
266 int tgt_fd, int cmd, guest_abi::VarArgs<int> varargs);
267
269SyscallReturn fcntl64Func(SyscallDesc *desc, ThreadContext *tc,
270 int tgt_fd, int cmd);
271
273SyscallReturn pipeFunc(SyscallDesc *desc, ThreadContext *tc, VPtr<> tgt_addr);
274
276SyscallReturn pipe2Func(SyscallDesc *desc, ThreadContext *tc,
277 VPtr<> tgt_addr, int flags);
278
280SyscallReturn getpidFunc(SyscallDesc *desc, ThreadContext *tc);
281
282// Target getpeername() handler.
283SyscallReturn getpeernameFunc(SyscallDesc *desc, ThreadContext *tc,
284 int tgt_fd, VPtr<> sockAddrPtr,
285 VPtr<> addrlenPtr);
286
287// Target bind() handler.
288SyscallReturn bindFunc(SyscallDesc *desc, ThreadContext *tc,
289 int tgt_fd, VPtr<> buf_ptr, int addrlen);
290
291// Target listen() handler.
292SyscallReturn listenFunc(SyscallDesc *desc, ThreadContext *tc,
293 int tgt_fd, int backlog);
294
295// Target connect() handler.
296SyscallReturn connectFunc(SyscallDesc *desc, ThreadContext *tc,
297 int tgt_fd, VPtr<> buf_ptr, int addrlen);
298
299#if defined(SYS_getdents)
300// Target getdents() handler.
301SyscallReturn getdentsFunc(SyscallDesc *desc, ThreadContext *tc,
302 int tgt_fd, VPtr<> buf_ptr, unsigned count);
303#endif
304
305#if defined(SYS_getdents64)
306// Target getdents() handler.
307SyscallReturn getdents64Func(SyscallDesc *desc, ThreadContext *tc,
308 int tgt_fd, VPtr<> buf_ptr, unsigned count);
309#endif
310
311// Target recvmsg() handler.
312SyscallReturn recvmsgFunc(SyscallDesc *desc, ThreadContext *tc,
313 int tgt_fd, VPtr<> msgPtr, int flags);
314
315// Target sendmsg() handler.
316SyscallReturn sendmsgFunc(SyscallDesc *desc, ThreadContext *tc,
317 int tgt_fd, VPtr<> msgPtr, int flags);
318
319// Target getuid() handler.
320SyscallReturn getuidFunc(SyscallDesc *desc, ThreadContext *tc);
321
323SyscallReturn getgidFunc(SyscallDesc *desc, ThreadContext *tc);
324
326SyscallReturn getppidFunc(SyscallDesc *desc, ThreadContext *tc);
327
329SyscallReturn geteuidFunc(SyscallDesc *desc, ThreadContext *tc);
330
332SyscallReturn getegidFunc(SyscallDesc *desc, ThreadContext *tc);
333
335SyscallReturn accessFunc(SyscallDesc *desc, ThreadContext *tc,
336 VPtr<> pathname, mode_t mode);
337SyscallReturn accessImpl(SyscallDesc *desc, ThreadContext *tc,
338 std::string path, mode_t mode);
339
340// Target getsockopt() handler.
341SyscallReturn getsockoptFunc(SyscallDesc *desc, ThreadContext *tc,
342 int tgt_fd, int level, int optname,
343 VPtr<> valPtr, VPtr<> lenPtr);
344
345// Target setsockopt() handler.
346SyscallReturn setsockoptFunc(SyscallDesc *desc, ThreadContext *tc,
347 int tgt_fd, int level, int optname,
348 VPtr<> valPtr, socklen_t len);
349
350SyscallReturn getcpuFunc(SyscallDesc *desc, ThreadContext *tc,
352 VPtr<uint32_t> tcache);
353
354// Target getsockname() handler.
355SyscallReturn getsocknameFunc(SyscallDesc *desc, ThreadContext *tc,
356 int tgt_fd, VPtr<> addrPtr, VPtr<> lenPtr);
357
358template <class OS>
359SyscallReturn
360atSyscallPath(ThreadContext *tc, int dirfd, std::string &path)
361{
362 // If pathname is absolute, then dirfd is ignored.
363 if (dirfd != OS::TGT_AT_FDCWD && !startswith(path, "/")) {
364 auto process = tc->getProcessPtr();
365
366 std::shared_ptr<FDEntry> fdep = ((*process->fds)[dirfd]);
367 auto ffdp = std::dynamic_pointer_cast<FileFDEntry>(fdep);
368 if (!ffdp)
369 return -EBADF;
370
371 if (path.empty())
372 path = ffdp->getFileName();
373 else
374 path = ffdp->getFileName() + "/" + path;
375 }
376
377 return 0;
378}
379
383template <class OS>
384SyscallReturn
386 VPtr<> uaddr, int op, int val, int timeout, VPtr<> uaddr2, int val3)
387{
388 auto process = tc->getProcessPtr();
389
390 /*
391 * Unsupported option that does not affect the correctness of the
392 * application. This is a performance optimization utilized by Linux.
393 */
394 op &= ~OS::TGT_FUTEX_PRIVATE_FLAG;
395 op &= ~OS::TGT_FUTEX_CLOCK_REALTIME_FLAG;
396
397 FutexMap &futex_map = tc->getSystemPtr()->futexMap;
398
399 if (OS::TGT_FUTEX_WAIT == op || OS::TGT_FUTEX_WAIT_BITSET == op) {
400 // Ensure futex system call accessed atomically.
401 BufferArg buf(uaddr, sizeof(int));
403 int mem_val = *(int*)buf.bufferPtr();
404
405 /*
406 * The value in memory at uaddr is not equal with the expected val
407 * (a different thread must have changed it before the system call was
408 * invoked). In this case, we need to throw an error.
409 */
410 if (val != mem_val)
411 return -OS::TGT_EWOULDBLOCK;
412
413 if (OS::TGT_FUTEX_WAIT == op) {
414 futex_map.suspend(uaddr, process->tgid(), tc);
415 } else {
416 futex_map.suspend_bitset(uaddr, process->tgid(), tc, val3);
417 }
418
419 return 0;
420 } else if (OS::TGT_FUTEX_WAKE == op) {
421 return futex_map.wakeup(uaddr, process->tgid(), val);
422 } else if (OS::TGT_FUTEX_WAKE_BITSET == op) {
423 return futex_map.wakeup_bitset(uaddr, process->tgid(), val3);
424 } else if (OS::TGT_FUTEX_REQUEUE == op ||
425 OS::TGT_FUTEX_CMP_REQUEUE == op) {
426
427 // Ensure futex system call accessed atomically.
428 BufferArg buf(uaddr, sizeof(int));
430 int mem_val = *(int*)buf.bufferPtr();
431 /*
432 * For CMP_REQUEUE, the whole operation is only started only if
433 * val3 is still the value of the futex pointed to by uaddr.
434 */
435 if (OS::TGT_FUTEX_CMP_REQUEUE && val3 != mem_val)
436 return -OS::TGT_EWOULDBLOCK;
437 return futex_map.requeue(uaddr, process->tgid(), val, timeout, uaddr2);
438 } else if (OS::TGT_FUTEX_WAKE_OP == op) {
439 /*
440 * The FUTEX_WAKE_OP operation is equivalent to executing the
441 * following code atomically and totally ordered with respect to
442 * other futex operations on any of the two supplied futex words:
443 *
444 * int oldval = *(int *) addr2;
445 * *(int *) addr2 = oldval op oparg;
446 * futex(addr1, FUTEX_WAKE, val, 0, 0, 0);
447 * if (oldval cmp cmparg)
448 * futex(addr2, FUTEX_WAKE, val2, 0, 0, 0);
449 *
450 * (op, oparg, cmp, cmparg are encoded in val3)
451 *
452 * +---+---+-----------+-----------+
453 * |op |cmp| oparg | cmparg |
454 * +---+---+-----------+-----------+
455 * 4 4 12 12 <== # of bits
456 *
457 * reference: http://man7.org/linux/man-pages/man2/futex.2.html
458 *
459 */
460 // get value from simulated-space
461 BufferArg buf(uaddr2, sizeof(int));
463 int oldval = *(int*)buf.bufferPtr();
464 int newval = oldval;
465 // extract op, oparg, cmp, cmparg from val3
466 int wake_cmparg = val3 & 0xfff;
467 int wake_oparg = (val3 & 0xfff000) >> 12;
468 int wake_cmp = (val3 & 0xf000000) >> 24;
469 int wake_op = (val3 & 0xf0000000) >> 28;
470 if ((wake_op & OS::TGT_FUTEX_OP_ARG_SHIFT) >> 3 == 1)
471 wake_oparg = (1 << wake_oparg);
472 wake_op &= ~OS::TGT_FUTEX_OP_ARG_SHIFT;
473 // perform operation on the value of the second futex
474 if (wake_op == OS::TGT_FUTEX_OP_SET)
475 newval = wake_oparg;
476 else if (wake_op == OS::TGT_FUTEX_OP_ADD)
477 newval += wake_oparg;
478 else if (wake_op == OS::TGT_FUTEX_OP_OR)
479 newval |= wake_oparg;
480 else if (wake_op == OS::TGT_FUTEX_OP_ANDN)
481 newval &= ~wake_oparg;
482 else if (wake_op == OS::TGT_FUTEX_OP_XOR)
483 newval ^= wake_oparg;
484 // copy updated value back to simulated-space
485 *(int*)buf.bufferPtr() = newval;
487 // perform the first wake-up
488 int woken1 = futex_map.wakeup(uaddr, process->tgid(), val);
489 int woken2 = 0;
490 // calculate the condition of the second wake-up
491 bool is_wake2 = false;
492 if (wake_cmp == OS::TGT_FUTEX_OP_CMP_EQ)
493 is_wake2 = oldval == wake_cmparg;
494 else if (wake_cmp == OS::TGT_FUTEX_OP_CMP_NE)
495 is_wake2 = oldval != wake_cmparg;
496 else if (wake_cmp == OS::TGT_FUTEX_OP_CMP_LT)
497 is_wake2 = oldval < wake_cmparg;
498 else if (wake_cmp == OS::TGT_FUTEX_OP_CMP_LE)
499 is_wake2 = oldval <= wake_cmparg;
500 else if (wake_cmp == OS::TGT_FUTEX_OP_CMP_GT)
501 is_wake2 = oldval > wake_cmparg;
502 else if (wake_cmp == OS::TGT_FUTEX_OP_CMP_GE)
503 is_wake2 = oldval >= wake_cmparg;
504 // perform the second wake-up
505 if (is_wake2)
506 woken2 = futex_map.wakeup(uaddr2, process->tgid(), timeout);
507
508 return woken1 + woken2;
509 }
510 warn("futex: op %d not implemented; ignoring.", op);
511 return -ENOSYS;
512}
513
516SyscallReturn pipePseudoFunc(SyscallDesc *desc, ThreadContext *tc);
517
518
522const unsigned seconds_since_epoch = 1000 * 1000 * 1000;
523
526template <class T1, class T2>
527void
528getElapsedTimeMicro(T1 &sec, T2 &usec)
529{
530 static const int OneMillion = 1000 * 1000;
531
532 uint64_t elapsed_usecs = curTick() / sim_clock::as_int::us;
533 sec = elapsed_usecs / OneMillion;
534 usec = elapsed_usecs % OneMillion;
535}
536
539template <class T1, class T2>
540void
541getElapsedTimeNano(T1 &sec, T2 &nsec)
542{
543 static const int OneBillion = 1000 * 1000 * 1000;
544
545 uint64_t elapsed_nsecs = curTick() / sim_clock::as_int::ns;
546 sec = elapsed_nsecs / OneBillion;
547 nsec = elapsed_nsecs % OneBillion;
548}
549
551//
552// The following emulation functions are generic, but need to be
553// templated to account for differences in types, constants, etc.
554//
556
557 typedef struct statfs hst_statfs;
558#if NO_STAT64
559 typedef struct stat hst_stat;
560 typedef struct stat hst_stat64;
561#else
562 typedef struct stat hst_stat;
563 typedef struct stat64 hst_stat64;
564#endif
565
569
570template <typename OS, typename TgtStatPtr, typename HostStatPtr>
571void
572copyOutStatBuf(TgtStatPtr tgt, HostStatPtr host, bool fakeTTY=false)
573{
574 constexpr ByteOrder bo = OS::byteOrder;
575
576 if (fakeTTY)
577 tgt->st_dev = 0xA;
578 else
579 tgt->st_dev = host->st_dev;
580 tgt->st_dev = htog(tgt->st_dev, bo);
581 tgt->st_ino = host->st_ino;
582 tgt->st_ino = htog(tgt->st_ino, bo);
583 tgt->st_mode = host->st_mode;
584 if (fakeTTY) {
585 // Claim to be a character device
586 tgt->st_mode &= ~S_IFMT; // Clear S_IFMT
587 tgt->st_mode |= S_IFCHR; // Set S_IFCHR
588 }
589 tgt->st_mode = htog(tgt->st_mode, bo);
590 tgt->st_nlink = host->st_nlink;
591 tgt->st_nlink = htog(tgt->st_nlink, bo);
592 tgt->st_uid = host->st_uid;
593 tgt->st_uid = htog(tgt->st_uid, bo);
594 tgt->st_gid = host->st_gid;
595 tgt->st_gid = htog(tgt->st_gid, bo);
596 if (fakeTTY)
597 tgt->st_rdev = 0x880d;
598 else
599 tgt->st_rdev = host->st_rdev;
600 tgt->st_rdev = htog(tgt->st_rdev, bo);
601 tgt->st_size = host->st_size;
602 tgt->st_size = htog(tgt->st_size, bo);
603 tgt->st_atimeX = host->st_atime;
604 tgt->st_atimeX = htog(tgt->st_atimeX, bo);
605 tgt->st_mtimeX = host->st_mtime;
606 tgt->st_mtimeX = htog(tgt->st_mtimeX, bo);
607 tgt->st_ctimeX = host->st_ctime;
608 tgt->st_ctimeX = htog(tgt->st_ctimeX, bo);
609 // Force the block size to be 8KB. This helps to ensure buffered io works
610 // consistently across different hosts.
611 tgt->st_blksize = 0x2000;
612 tgt->st_blksize = htog(tgt->st_blksize, bo);
613 tgt->st_blocks = host->st_blocks;
614 tgt->st_blocks = htog(tgt->st_blocks, bo);
615}
616
617// Same for stat64
618
619template <typename OS, typename TgtStatPtr, typename HostStatPtr>
620void
621copyOutStat64Buf(TgtStatPtr tgt, HostStatPtr host,
622 bool fakeTTY=false)
623{
624 copyOutStatBuf<OS>(tgt, host, fakeTTY);
625#if defined(STAT_HAVE_NSEC)
626 constexpr ByteOrder bo = OS::byteOrder;
627
628 tgt->st_atime_nsec = host->st_atime_nsec;
629 tgt->st_atime_nsec = htog(tgt->st_atime_nsec, bo);
630 tgt->st_mtime_nsec = host->st_mtime_nsec;
631 tgt->st_mtime_nsec = htog(tgt->st_mtime_nsec, bo);
632 tgt->st_ctime_nsec = host->st_ctime_nsec;
633 tgt->st_ctime_nsec = htog(tgt->st_ctime_nsec, bo);
634#else
635 tgt->st_atime_nsec = 0;
636 tgt->st_mtime_nsec = 0;
637 tgt->st_ctime_nsec = 0;
638#endif
639}
640
641template <class OS, typename TgtStatPtr, typename HostStatPtr>
642void
643copyOutStatfsBuf(TgtStatPtr tgt, HostStatPtr host)
644{
645 constexpr ByteOrder bo = OS::byteOrder;
646
647 tgt->f_type = htog(host->f_type, bo);
648#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__)
649 tgt->f_bsize = htog(host->f_iosize, bo);
650#else
651 tgt->f_bsize = htog(host->f_bsize, bo);
652#endif
653 tgt->f_blocks = htog(host->f_blocks, bo);
654 tgt->f_bfree = htog(host->f_bfree, bo);
655 tgt->f_bavail = htog(host->f_bavail, bo);
656 tgt->f_files = htog(host->f_files, bo);
657 tgt->f_ffree = htog(host->f_ffree, bo);
658 memcpy(&tgt->f_fsid, &host->f_fsid, sizeof(host->f_fsid));
659#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__)
660 tgt->f_namelen = htog(host->f_namemax, bo);
661 tgt->f_frsize = htog(host->f_bsize, bo);
662#elif defined(__APPLE__)
663 tgt->f_namelen = 0;
664 tgt->f_frsize = 0;
665#else
666 tgt->f_namelen = htog(host->f_namelen, bo);
667 tgt->f_frsize = htog(host->f_frsize, bo);
668#endif
669#if defined(__linux__)
670 memcpy(&tgt->f_spare, &host->f_spare,
671 std::min(sizeof(host->f_spare), sizeof(tgt->f_spare)));
672#else
673 /*
674 * The fields are different sizes per OS. Don't bother with
675 * f_spare or f_reserved on non-Linux for now.
676 */
677 memset(&tgt->f_spare, 0, sizeof(tgt->f_spare));
678#endif
679}
680
681template <typename OS, typename TgtStatPtr, typename HostStatPtr>
682void
683copyOutStatxBuf(TgtStatPtr tgt, HostStatPtr host, bool fakeTTY = false)
684{
685 constexpr ByteOrder bo = OS::byteOrder;
686
687 if (fakeTTY) {
688 tgt->stx_dev_major = 0x00;
689 tgt->stx_dev_minor = 0x0A;
690 } else {
691 tgt->stx_dev_major = host->st_dev >> 8;
692 tgt->stx_dev_minor = host->st_dev & 0xFF;
693 }
694 tgt->stx_dev_major = htog(tgt->stx_dev_major, bo);
695 tgt->stx_dev_minor = htog(tgt->stx_dev_minor, bo);
696 tgt->stx_ino = host->st_ino;
697 tgt->stx_ino = htog(tgt->stx_ino, bo);
698 tgt->stx_mode = host->st_mode;
699 if (fakeTTY) {
700 // Claim to be character device.
701 tgt->stx_mode &= ~S_IFMT;
702 tgt->stx_mode |= S_IFCHR;
703 }
704 tgt->stx_mode = htog(tgt->stx_mode, bo);
705 tgt->stx_nlink = host->st_nlink;
706 tgt->stx_nlink = htog(tgt->stx_nlink, bo);
707 tgt->stx_uid = host->st_uid;
708 tgt->stx_uid = htog(tgt->stx_uid, bo);
709 tgt->stx_gid = host->st_gid;
710 tgt->stx_gid = htog(tgt->stx_gid, bo);
711 if (fakeTTY) {
712 tgt->stx_rdev_major = 0x880d >> 8;
713 tgt->stx_rdev_minor = 0x880d & 0xFF;
714 } else {
715 tgt->stx_rdev_major = host->st_rdev >> 8;
716 tgt->stx_rdev_minor = host->st_rdev & 0xFF;
717 }
718 tgt->stx_rdev_major = htog(tgt->stx_rdev_major, bo);
719 tgt->stx_rdev_minor = htog(tgt->stx_rdev_minor, bo);
720 tgt->stx_size = host->st_size;
721 tgt->stx_size = htog(tgt->stx_size, bo);
722 tgt->stx_atimeX = host->st_atime;
723 tgt->stx_atimeX = htog(tgt->stx_atimeX, bo);
724 tgt->stx_ctimeX = host->st_ctime;
725 tgt->stx_ctimeX = htog(tgt->stx_ctimeX, bo);
726 tgt->stx_mtimeX = host->st_mtime;
727 tgt->stx_mtimeX = htog(tgt->stx_mtimeX, bo);
728 // Force the block size to be 8KB. This helps to ensure buffered io works
729 // consistently across different hosts.
730 tgt->stx_blksize = 0x2000;
731 tgt->stx_blksize = htog(tgt->stx_blksize, bo);
732 tgt->stx_blocks = host->st_blocks;
733 tgt->stx_blocks = htog(tgt->stx_blocks, bo);
734 tgt->stx_mask = 0x000007ffU; // STATX_BASIC_STATS on Linux.
735 tgt->stx_mask = htog(tgt->stx_mask, bo);
736 tgt->stx_attributes = 0;
737 tgt->stx_attributes_mask = 0;
738 tgt->stx_attributes_mask = htog(tgt->stx_attributes_mask, bo);
739}
740
745template <class OS>
746SyscallReturn
748 int tgt_fd, unsigned req, VPtr<> addr)
749{
750 auto p = tc->getProcessPtr();
751
752 DPRINTF_SYSCALL(Verbose, "ioctl(%d, 0x%x, ...)\n", tgt_fd, req);
753
754 if (OS::isTtyReq(req))
755 return -ENOTTY;
756
757 auto dfdp = std::dynamic_pointer_cast<DeviceFDEntry>((*p->fds)[tgt_fd]);
758 if (dfdp) {
759 EmulatedDriver *emul_driver = dfdp->getDriver();
760 if (emul_driver)
761 return emul_driver->ioctl(tc, req, addr);
762 }
763
764 auto sfdp = std::dynamic_pointer_cast<SocketFDEntry>((*p->fds)[tgt_fd]);
765 if (sfdp) {
766 int status;
767
768 switch (req) {
769 case SIOCGIFCONF: {
770 BufferArg conf_arg(addr, sizeof(ifconf));
771 conf_arg.copyIn(SETranslatingPortProxy(tc));
772
773 ifconf *conf = (ifconf*)conf_arg.bufferPtr();
774 Addr ifc_buf_addr = (Addr)conf->ifc_buf;
775 BufferArg ifc_buf_arg(ifc_buf_addr, conf->ifc_len);
776 ifc_buf_arg.copyIn(SETranslatingPortProxy(tc));
777
778 conf->ifc_buf = (char*)ifc_buf_arg.bufferPtr();
779
780 status = ioctl(sfdp->getSimFD(), req, conf_arg.bufferPtr());
781 if (status != -1) {
782 conf->ifc_buf = (char*)ifc_buf_addr;
783 ifc_buf_arg.copyOut(SETranslatingPortProxy(tc));
784 conf_arg.copyOut(SETranslatingPortProxy(tc));
785 }
786
787 return status;
788 }
789 case SIOCGIFFLAGS:
790#if defined(__linux__)
791 case SIOCGIFINDEX:
792#endif
793 case SIOCGIFNETMASK:
794 case SIOCGIFADDR:
795#if defined(__linux__)
796 case SIOCGIFHWADDR:
797#endif
798 case SIOCGIFMTU: {
799 BufferArg req_arg(addr, sizeof(ifreq));
800 req_arg.copyIn(SETranslatingPortProxy(tc));
801
802 status = ioctl(sfdp->getSimFD(), req, req_arg.bufferPtr());
803 if (status != -1)
804 req_arg.copyOut(SETranslatingPortProxy(tc));
805 return status;
806 }
807 }
808 }
809
814 warn("Unsupported ioctl call (return ENOTTY): ioctl(%d, 0x%x, ...) @ \n",
815 tgt_fd, req, tc->pcState());
816 return -ENOTTY;
817}
818
820template <class OS>
821SyscallReturn
823 int tgt_dirfd, VPtr<> pathname, int tgt_flags, int mode)
824{
825 auto p = tc->getProcessPtr();
826
831 std::string path;
832 if (!SETranslatingPortProxy(tc).tryReadString(path, pathname))
833 return -EFAULT;
834
835#ifdef __CYGWIN32__
836 int host_flags = O_BINARY;
837#else
838 int host_flags = 0;
839#endif
844 for (const auto &p: OS::openFlagTable) {
845 if (tgt_flags & p.first) {
846 tgt_flags &= ~p.first;
847 host_flags |= p.second;
848 }
849 }
850 warn_if(tgt_flags, "%s: cannot decode flags %#x", desc->name(), tgt_flags);
851
852#ifdef __CYGWIN32__
853 host_flags |= O_BINARY;
854#endif
855
868 std::string redir_path = path;
869 std::string abs_path = path;
870 if (tgt_dirfd == OS::TGT_AT_FDCWD) {
871 abs_path = p->absolutePath(path, true);
872 redir_path = p->checkPathRedirect(path);
873 } else if (!startswith(path, "/")) {
874 std::shared_ptr<FDEntry> fdep = ((*p->fds)[tgt_dirfd]);
875 auto ffdp = std::dynamic_pointer_cast<FileFDEntry>(fdep);
876 if (!ffdp)
877 return -EBADF;
878 abs_path = ffdp->getFileName() + path;
879 redir_path = p->checkPathRedirect(abs_path);
880 }
881
888 if (startswith(abs_path, "/dev/")) {
889 std::string filename = abs_path.substr(strlen("/dev/"));
890 EmulatedDriver *drv = p->findDriver(filename);
891 if (drv) {
892 DPRINTF_SYSCALL(Verbose, "%s: passing call to "
893 "driver open with path[%s]\n",
894 desc->name(), abs_path.c_str());
895 return drv->open(tc, mode, host_flags);
896 }
901 }
902
927 int sim_fd = -1;
928 std::string used_path;
929 std::vector<std::string> special_paths =
930 { "/proc/meminfo", "/system/", "/platform/", "/etc/passwd",
931 "/proc/self/maps", "/dev/urandom",
932 "/sys/devices/system/cpu/online" };
933 for (auto entry : special_paths) {
934 if (startswith(path, entry)) {
935 sim_fd = OS::openSpecialFile(abs_path, p, tc);
936 used_path = abs_path;
937 }
938 }
939 if (sim_fd == -1) {
940 sim_fd = open(redir_path.c_str(), host_flags, mode);
941 used_path = redir_path;
942 }
943 if (sim_fd == -1) {
944 int local = -errno;
945 DPRINTF_SYSCALL(Verbose, "%s: failed -> path:%s "
946 "(inferred from:%s)\n", desc->name(),
947 used_path.c_str(), path.c_str());
948 return local;
949 }
950
959 auto ffdp = std::make_shared<FileFDEntry>(sim_fd, host_flags, path, 0);
960 // Record the file mode for checkpoint restoring
961 ffdp->setFileMode(mode);
962 int tgt_fd = p->fds->allocFD(ffdp);
963 DPRINTF_SYSCALL(Verbose, "%s: sim_fd[%d], target_fd[%d] -> path:%s\n"
964 "(inferred from:%s)\n", desc->name(),
965 sim_fd, tgt_fd, used_path.c_str(), path.c_str());
966 return tgt_fd;
967}
968
970template <class OS>
971SyscallReturn
973 VPtr<> pathname, int tgt_flags, int mode)
974{
975 return openatFunc<OS>(
976 desc, tc, OS::TGT_AT_FDCWD, pathname, tgt_flags, mode);
977}
978
980template <class OS>
981SyscallReturn
983 int dirfd, VPtr<> pathname, int flags)
984{
985 std::string path;
986 if (!SETranslatingPortProxy(tc).tryReadString(path, pathname))
987 return -EFAULT;
988
989 // Modifying path from the directory descriptor
990 if (auto res = atSyscallPath<OS>(tc, dirfd, path); !res.successful()) {
991 return res;
992 }
993
994 if (flags & OS::TGT_AT_REMOVEDIR) {
995 return rmdirImpl(desc, tc, path);
996 } else {
997 return unlinkImpl(desc, tc, path);
998 }
999}
1000
1002template <class OS>
1003SyscallReturn
1005 int dirfd, VPtr<> pathname, int mode)
1006{
1007 std::string path;
1008 if (!SETranslatingPortProxy(tc).tryReadString(path, pathname))
1009 return -EFAULT;
1010
1011 // Modifying path from the directory descriptor
1012 if (auto res = atSyscallPath<OS>(tc, dirfd, path); !res.successful()) {
1013 return res;
1014 }
1015
1016 return accessImpl(desc, tc, path, mode);
1017}
1018
1020template <class OS>
1021SyscallReturn
1023 int dirfd, VPtr<> pathname, VPtr<> buf_ptr,
1024 typename OS::size_t bufsiz)
1025{
1026 std::string path;
1027 if (!SETranslatingPortProxy(tc).tryReadString(path, pathname))
1028 return -EFAULT;
1029
1030 // Modifying path from the directory descriptor
1031 if (auto res = atSyscallPath<OS>(tc, dirfd, path); !res.successful()) {
1032 return res;
1033 }
1034
1035 auto p = tc->getProcessPtr();
1036
1037 // Adjust path for cwd and redirection
1038 path = p->checkPathRedirect(path);
1039
1040 BufferArg buf(buf_ptr, bufsiz);
1041
1042 int result = -1;
1043 if (path != "/proc/self/exe") {
1044 result = readlink(path.c_str(), (char *)buf.bufferPtr(), bufsiz);
1045 } else {
1046 // Emulate readlink() called on '/proc/self/exe' should return the
1047 // absolute path of the binary running in the simulated system (the
1048 // Process' executable). It is possible that using this path in
1049 // the simulated system will result in unexpected behavior if:
1050 // 1) One binary runs another (e.g., -c time -o "my_binary"), and
1051 // called binary calls readlink().
1052 // 2) The host's full path to the running benchmark changes from one
1053 // simulation to another. This can result in different simulated
1054 // performance since the simulated system will process the binary
1055 // path differently, even if the binary itself does not change.
1056
1057 // Get the absolute canonical path to the running application
1058 char real_path[PATH_MAX];
1059 char *check_real_path = realpath(p->progName(), real_path);
1060 if (!check_real_path) {
1061 fatal("readlink('/proc/self/exe') unable to resolve path to "
1062 "executable: %s", p->progName());
1063 }
1064 strncpy((char*)buf.bufferPtr(), real_path, bufsiz);
1065 typename OS::size_t real_path_len = strlen(real_path);
1066 if (real_path_len > bufsiz) {
1067 // readlink will truncate the contents of the
1068 // path to ensure it is no more than bufsiz
1069 result = bufsiz;
1070 } else {
1071 result = real_path_len;
1072 }
1073
1074 // Issue a warning about potential unexpected results
1075 warn_once("readlink() called on '/proc/self/exe' may yield unexpected "
1076 "results in various settings.\n Returning '%s'\n",
1077 (char*)buf.bufferPtr());
1078 }
1079
1081
1082 return (result == -1) ? -errno : result;
1083}
1084
1086template <class OS>
1087SyscallReturn
1089 VPtr<> pathname, VPtr<> buf_ptr,
1090 typename OS::size_t bufsiz)
1091{
1092 return readlinkatFunc<OS>(desc, tc, OS::TGT_AT_FDCWD,
1093 pathname, buf_ptr, bufsiz);
1094}
1095
1097template <class OS>
1098SyscallReturn
1100 int olddirfd, VPtr<> oldpath, int newdirfd, VPtr<> newpath)
1101{
1102 SETranslatingPortProxy proxy(tc);
1103 std::string old_name;
1104 if (!proxy.tryReadString(old_name, oldpath))
1105 return -EFAULT;
1106
1107 std::string new_name;
1108 if (!proxy.tryReadString(new_name, newpath))
1109 return -EFAULT;
1110
1111 // Modifying old_name from the directory descriptor
1112 if (auto res = atSyscallPath<OS>(tc, olddirfd, old_name); !res.successful()) {
1113 return res;
1114 }
1115
1116 // Modifying new_name from the directory descriptor
1117 if (auto res = atSyscallPath<OS>(tc, newdirfd, new_name); !res.successful()) {
1118 return res;
1119 }
1120
1121 return renameImpl(desc, tc, old_name, new_name);
1122}
1123
1125template <class OS>
1126SyscallReturn
1128 int dirfd, VPtr<> pathname, uint32_t owner, uint32_t group,
1129 int flags)
1130{
1131 std::string path;
1132 if (!SETranslatingPortProxy(tc).tryReadString(path, pathname))
1133 return -EFAULT;
1134
1135 // Modifying path from the directory descriptor
1136 if (auto res = atSyscallPath<OS>(tc, dirfd, path); !res.successful()) {
1137 return res;
1138 }
1139
1140 return chownImpl(desc, tc, path, owner, group);
1141}
1142
1144template <class OS>
1145SyscallReturn
1147 int dirfd, VPtr<> pathname, mode_t mode)
1148{
1149 std::string path;
1150 if (!SETranslatingPortProxy(tc).tryReadString(path, pathname))
1151 return -EFAULT;
1152
1153 // Modifying path from the directory descriptor
1154 if (auto res = atSyscallPath<OS>(tc, dirfd, path); !res.successful()) {
1155 return res;
1156 }
1157
1158 return mkdirImpl(desc, tc, path, mode);
1159}
1160
1162template <class OS>
1163SyscallReturn
1165 int dirfd, VPtr<> pathname, mode_t mode, dev_t dev)
1166{
1167 std::string path;
1168 if (!SETranslatingPortProxy(tc).tryReadString(path, pathname))
1169 return -EFAULT;
1170
1171 // Modifying path from the directory descriptor
1172 if (auto res = atSyscallPath<OS>(tc, dirfd, path); !res.successful()) {
1173 return res;
1174 }
1175
1176 return mknodImpl(desc, tc, path, mode, dev);
1177}
1178
1180template <class OS>
1181SyscallReturn
1184{
1185 auto process = tc->getProcessPtr();
1186
1187 sysinfo->uptime = seconds_since_epoch;
1188 sysinfo->totalram = process->system->memSize();
1189 sysinfo->mem_unit = 1;
1190
1191 return 0;
1192}
1193
1195template <class OS>
1196SyscallReturn
1198 int dirfd, VPtr<> pathname, mode_t mode)
1199{
1200 std::string path;
1201 if (!SETranslatingPortProxy(tc).tryReadString(path, pathname))
1202 return -EFAULT;
1203
1204 // Modifying path from the directory descriptor
1205 if (auto res = atSyscallPath<OS>(tc, dirfd, path); !res.successful()) {
1206 return res;
1207 }
1208
1209 mode_t hostMode = 0;
1210
1211 // XXX translate mode flags via OS::something???
1212 hostMode = mode;
1213
1214 auto process = tc->getProcessPtr();
1215 // Adjust path for cwd and redirection
1216 path = process->checkPathRedirect(path);
1217
1218 // do the chmod
1219 int result = chmod(path.c_str(), hostMode);
1220 if (result < 0)
1221 return -errno;
1222
1223 return 0;
1224}
1225
1227template <class OS>
1228SyscallReturn
1229chmodFunc(SyscallDesc *desc, ThreadContext *tc, VPtr<> pathname, mode_t mode)
1230{
1231 return fchmodatFunc<OS>(desc, tc, OS::TGT_AT_FDCWD, pathname, mode);
1232}
1233
1234template <class OS>
1235SyscallReturn
1237 VPtr<> fdsPtr, int nfds, int tmout)
1238{
1239 auto p = tc->getProcessPtr();
1240
1241 BufferArg fdsBuf(fdsPtr, sizeof(struct pollfd) * nfds);
1242 fdsBuf.copyIn(SETranslatingPortProxy(tc));
1243
1250 int temp_tgt_fds[nfds];
1251 for (int index = 0; index < nfds; index++) {
1252 temp_tgt_fds[index] = ((struct pollfd *)fdsBuf.bufferPtr())[index].fd;
1253 auto tgt_fd = temp_tgt_fds[index];
1254 auto hbfdp = std::dynamic_pointer_cast<HBFDEntry>((*p->fds)[tgt_fd]);
1255 if (!hbfdp)
1256 return -EBADF;
1257 auto host_fd = hbfdp->getSimFD();
1258 ((struct pollfd *)fdsBuf.bufferPtr())[index].fd = host_fd;
1259 }
1260
1267 int status;
1268 if (tmout < 0) {
1269 status = poll((struct pollfd *)fdsBuf.bufferPtr(), nfds, 0);
1270 if (status == 0) {
1276 System *sysh = tc->getSystemPtr();
1278 for (it=sysh->signalList.begin(); it!=sysh->signalList.end(); it++)
1279 if (it->receiver == p)
1280 return -EINTR;
1281 return SyscallReturn::retry();
1282 }
1283 } else
1284 status = poll((struct pollfd *)fdsBuf.bufferPtr(), nfds, 0);
1285
1286 if (status == -1)
1287 return -errno;
1288
1293 for (int index = 0; index < nfds; index++) {
1294 auto tgt_fd = temp_tgt_fds[index];
1295 ((struct pollfd *)fdsBuf.bufferPtr())[index].fd = tgt_fd;
1296 }
1297
1302 fdsBuf.copyOut(SETranslatingPortProxy(tc));
1303
1304 return status;
1305}
1306
1308template <class OS>
1309SyscallReturn
1310fchmodFunc(SyscallDesc *desc, ThreadContext *tc, int tgt_fd, uint32_t mode)
1311{
1312 auto p = tc->getProcessPtr();
1313
1314 auto ffdp = std::dynamic_pointer_cast<FileFDEntry>((*p->fds)[tgt_fd]);
1315 if (!ffdp)
1316 return -EBADF;
1317 int sim_fd = ffdp->getSimFD();
1318
1319 mode_t hostMode = mode;
1320
1321 int result = fchmod(sim_fd, hostMode);
1322
1323 return (result < 0) ? -errno : 0;
1324}
1325
1327template <class OS>
1328SyscallReturn
1330 VPtr<> start, uint64_t old_length, uint64_t new_length, uint64_t flags,
1332{
1333 auto p = tc->getProcessPtr();
1334 Addr page_bytes = p->pTable->pageSize();
1335 uint64_t provided_address = 0;
1336 bool use_provided_address = flags & OS::TGT_MREMAP_FIXED;
1337
1338 if (use_provided_address)
1339 provided_address = varargs.get<uint64_t>();
1340
1341 if ((start % page_bytes != 0) ||
1342 (provided_address % page_bytes != 0)) {
1343 warn("mremap failing: arguments not page aligned");
1344 return -EINVAL;
1345 }
1346
1347 new_length = roundUp(new_length, page_bytes);
1348
1349 if (new_length > old_length) {
1350 Addr mmap_end = p->memState->getMmapEnd();
1351
1352 if ((start + old_length) == mmap_end &&
1353 (!use_provided_address || provided_address == start)) {
1354 // This case cannot occur when growing downward, as
1355 // start is greater than or equal to mmap_end.
1356 uint64_t diff = new_length - old_length;
1357 p->memState->mapRegion(mmap_end, diff, "remapped");
1358 p->memState->setMmapEnd(mmap_end + diff);
1359 return (Addr)start;
1360 } else {
1361 if (!use_provided_address && !(flags & OS::TGT_MREMAP_MAYMOVE)) {
1362 warn("can't remap here and MREMAP_MAYMOVE flag not set\n");
1363 return -ENOMEM;
1364 } else {
1365 uint64_t new_start = provided_address;
1366 if (!use_provided_address) {
1367 new_start = p->mmapGrowsDown() ?
1368 mmap_end - new_length : mmap_end;
1369 mmap_end = p->mmapGrowsDown() ?
1370 new_start : mmap_end + new_length;
1371 p->memState->setMmapEnd(mmap_end);
1372 }
1373
1374 warn("mremapping to new vaddr %08p-%08p, adding %d\n",
1375 new_start, new_start + new_length,
1376 new_length - old_length);
1377
1378 // add on the remaining unallocated pages
1379 p->allocateMem(new_start + old_length,
1380 new_length - old_length,
1381 use_provided_address /* clobber */);
1382
1383 if (use_provided_address &&
1384 ((new_start + new_length > p->memState->getMmapEnd() &&
1385 !p->mmapGrowsDown()) ||
1386 (new_start < p->memState->getMmapEnd() &&
1387 p->mmapGrowsDown()))) {
1388 // something fishy going on here, at least notify the user
1389 // @todo: increase mmap_end?
1390 warn("mmap region limit exceeded with MREMAP_FIXED\n");
1391 }
1392
1393 warn("returning %08p as start\n", new_start);
1394 p->memState->remapRegion(start, new_start, old_length);
1395 return new_start;
1396 }
1397 }
1398 } else {
1399 // Shrink a region
1400 if (use_provided_address && provided_address != start)
1401 p->memState->remapRegion(start, provided_address, new_length);
1402 if (new_length != old_length)
1403 p->memState->unmapRegion(start + new_length,
1404 old_length - new_length);
1405 return use_provided_address ? provided_address : (Addr)start;
1406 }
1407}
1408
1410template <class OS>
1411SyscallReturn
1413 VPtr<> pathname, VPtr<typename OS::tgt_stat> tgt_stat)
1414{
1415 std::string path;
1416 auto process = tc->getProcessPtr();
1417
1418 if (!SETranslatingPortProxy(tc).tryReadString(path, pathname))
1419 return -EFAULT;
1420
1421 // Adjust path for cwd and redirection
1422 path = process->checkPathRedirect(path);
1423
1424 struct stat hostBuf;
1425 int result = stat(path.c_str(), &hostBuf);
1426
1427 if (result < 0)
1428 return -errno;
1429
1430 copyOutStatBuf<OS>(tgt_stat, &hostBuf);
1431
1432 return 0;
1433}
1434
1436template <class OS>
1437SyscallReturn
1439 VPtr<> pathname, VPtr<typename OS::tgt_stat64> tgt_stat,
1440 int flags)
1441{
1442 std::string path;
1443
1444 if (!SETranslatingPortProxy(tc).tryReadString(path, pathname))
1445 return -EFAULT;
1446
1447 if (path.empty() && !(flags & OS::TGT_AT_EMPTY_PATH))
1448 return -ENOENT;
1449 flags = flags & ~OS::TGT_AT_EMPTY_PATH;
1450
1451 warn_if(flags != 0, "newfstatat: Flag bits %#x not supported.", flags);
1452
1453 // Modifying path from the directory descriptor
1454 if (auto res = atSyscallPath<OS>(tc, dirfd, path); !res.successful()) {
1455 return res;
1456 }
1457
1458 auto p = tc->getProcessPtr();
1459
1460 // Adjust path for cwd and redirection
1461 path = p->checkPathRedirect(path);
1462
1463 struct stat host_buf;
1464 int result = stat(path.c_str(), &host_buf);
1465
1466 if (result < 0)
1467 return -errno;
1468
1469 copyOutStat64Buf<OS>(tgt_stat, &host_buf);
1470
1471 return 0;
1472}
1473
1475template <class OS>
1476SyscallReturn
1478 int dirfd, VPtr<> pathname,
1480{
1481 std::string path;
1482 if (!SETranslatingPortProxy(tc).tryReadString(path, pathname))
1483 return -EFAULT;
1484
1485 // Modifying path from the directory descriptor
1486 if (auto res = atSyscallPath<OS>(tc, dirfd, path); !res.successful()) {
1487 return res;
1488 }
1489
1490 auto p = tc->getProcessPtr();
1491
1492 // Adjust path for cwd and redirection
1493 path = p->checkPathRedirect(path);
1494
1495#if NO_STAT64
1496 struct stat hostBuf;
1497 int result = stat(path.c_str(), &hostBuf);
1498#else
1499 struct stat64 hostBuf;
1500 int result = stat64(path.c_str(), &hostBuf);
1501#endif
1502
1503 if (result < 0)
1504 return -errno;
1505
1506 copyOutStat64Buf<OS>(tgt_stat, &hostBuf);
1507
1508 return 0;
1509}
1510
1512template <class OS>
1513SyscallReturn
1515 VPtr<> pathname, VPtr<typename OS::tgt_stat64> tgt_stat)
1516{
1517 return fstatat64Func<OS>(desc, tc, OS::TGT_AT_FDCWD, pathname, tgt_stat);
1518}
1519
1521template <class OS>
1522SyscallReturn
1524 int dirfd, VPtr<> pathname, int flags,
1525 unsigned int mask, VPtr<typename OS::tgt_statx> tgt_statx)
1526{
1527 std::string path;
1528
1529 if (!SETranslatingPortProxy(tc).tryReadString(path, pathname))
1530 return -EFAULT;
1531
1532 if (path.empty() && !(flags & OS::TGT_AT_EMPTY_PATH))
1533 return -ENOENT;
1534 flags = flags & ~OS::TGT_AT_EMPTY_PATH;
1535
1536 warn_if(flags != 0, "statx: Flag bits %#x not supported.", flags);
1537
1538 // Modifying path from the directory descriptor
1539 if (auto res = atSyscallPath<OS>(tc, dirfd, path); !res.successful()) {
1540 return res;
1541 }
1542
1543 auto p = tc->getProcessPtr();
1544
1545 // Adjust path for cwd and redirection
1546 path = p->checkPathRedirect(path);
1547
1548 struct stat host_buf;
1549 int result = stat(path.c_str(), &host_buf);
1550
1551 if (result < 0)
1552 return -errno;
1553
1554 copyOutStatxBuf<OS>(tgt_statx, &host_buf);
1555
1556 return 0;
1557}
1558
1560template <class OS>
1561SyscallReturn
1563 int tgt_fd, VPtr<typename OS::tgt_stat64> tgt_stat)
1564{
1565 auto p = tc->getProcessPtr();
1566
1567 auto ffdp = std::dynamic_pointer_cast<HBFDEntry>((*p->fds)[tgt_fd]);
1568 if (!ffdp)
1569 return -EBADF;
1570 int sim_fd = ffdp->getSimFD();
1571
1572#if NO_STAT64
1573 struct stat hostBuf;
1574 int result = fstat(sim_fd, &hostBuf);
1575#else
1576 struct stat64 hostBuf;
1577 int result = fstat64(sim_fd, &hostBuf);
1578#endif
1579
1580 if (result < 0)
1581 return -errno;
1582
1583 copyOutStat64Buf<OS>(tgt_stat, &hostBuf, (sim_fd == 1));
1584
1585 return 0;
1586}
1587
1588
1590template <class OS>
1591SyscallReturn
1593 VPtr<> pathname, VPtr<typename OS::tgt_stat> tgt_stat)
1594{
1595 std::string path;
1596 auto process = tc->getProcessPtr();
1597
1598 if (!SETranslatingPortProxy(tc).tryReadString(path, pathname))
1599 return -EFAULT;
1600
1601 // Adjust path for cwd and redirection
1602 path = process->checkPathRedirect(path);
1603
1604 struct stat hostBuf;
1605 int result = lstat(path.c_str(), &hostBuf);
1606
1607 if (result < 0)
1608 return -errno;
1609
1610 copyOutStatBuf<OS>(tgt_stat, &hostBuf);
1611
1612 return 0;
1613}
1614
1616template <class OS>
1617SyscallReturn
1619 VPtr<> pathname, VPtr<typename OS::tgt_stat64> tgt_stat)
1620{
1621 std::string path;
1622 auto process = tc->getProcessPtr();
1623
1624 if (!SETranslatingPortProxy(tc).tryReadString(path, pathname))
1625 return -EFAULT;
1626
1627 // Adjust path for cwd and redirection
1628 path = process->checkPathRedirect(path);
1629
1630#if NO_STAT64
1631 struct stat hostBuf;
1632 int result = lstat(path.c_str(), &hostBuf);
1633#else
1634 struct stat64 hostBuf;
1635 int result = lstat64(path.c_str(), &hostBuf);
1636#endif
1637
1638 if (result < 0)
1639 return -errno;
1640
1641 copyOutStat64Buf<OS>(tgt_stat, &hostBuf);
1642
1643 return 0;
1644}
1645
1647template <class OS>
1648SyscallReturn
1650 int tgt_fd, VPtr<typename OS::tgt_stat> tgt_stat)
1651{
1652 auto p = tc->getProcessPtr();
1653
1654 DPRINTF_SYSCALL(Verbose, "fstat(%d, ...)\n", tgt_fd);
1655
1656 auto ffdp = std::dynamic_pointer_cast<FileFDEntry>((*p->fds)[tgt_fd]);
1657 if (!ffdp)
1658 return -EBADF;
1659 int sim_fd = ffdp->getSimFD();
1660
1661 struct stat hostBuf;
1662 int result = fstat(sim_fd, &hostBuf);
1663
1664 if (result < 0)
1665 return -errno;
1666
1667 copyOutStatBuf<OS>(tgt_stat, &hostBuf, (sim_fd == 1));
1668
1669 return 0;
1670}
1671
1673template <class OS>
1674SyscallReturn
1676 VPtr<> pathname, VPtr<typename OS::tgt_statfs> tgt_stat)
1677{
1678#if defined(__linux__)
1679 std::string path;
1680 auto process = tc->getProcessPtr();
1681
1682 if (!SETranslatingPortProxy(tc).tryReadString(path, pathname))
1683 return -EFAULT;
1684
1685 // Adjust path for cwd and redirection
1686 path = process->checkPathRedirect(path);
1687
1688 struct statfs hostBuf;
1689 int result = statfs(path.c_str(), &hostBuf);
1690
1691 if (result < 0)
1692 return -errno;
1693
1694 copyOutStatfsBuf<OS>(tgt_stat, &hostBuf);
1695 return 0;
1696#else
1697 warnUnsupportedOS("statfs");
1698 return -1;
1699#endif
1700}
1701
1702template <class OS>
1703SyscallReturn
1705 VPtr<> ptidPtr, VPtr<> ctidPtr, VPtr<> tlsPtr)
1706{
1707 DPRINTF(SyscallVerbose, "Doing clone. pid: %#llx, ctid: %#llx, tls: %#llx"
1708 " flags: %#llx, stack: %#llx\n",
1709 ptidPtr.addr(), ctidPtr.addr(), tlsPtr.addr(), flags, newStack);
1710 auto p = tc->getProcessPtr();
1711
1712 if (((flags & OS::TGT_CLONE_SIGHAND)&& !(flags & OS::TGT_CLONE_VM)) ||
1713 ((flags & OS::TGT_CLONE_THREAD) && !(flags & OS::TGT_CLONE_SIGHAND)) ||
1714 ((flags & OS::TGT_CLONE_FS) && (flags & OS::TGT_CLONE_NEWNS)) ||
1715 ((flags & OS::TGT_CLONE_NEWIPC) && (flags & OS::TGT_CLONE_SYSVSEM)) ||
1716 ((flags & OS::TGT_CLONE_NEWPID) && (flags & OS::TGT_CLONE_THREAD)) ||
1717 ((flags & OS::TGT_CLONE_VM) && !(newStack)))
1718 return -EINVAL;
1719
1720 ThreadContext *ctc;
1721 if (!(ctc = tc->getSystemPtr()->threads.findFree())) {
1722 DPRINTF_SYSCALL(Verbose, "clone: no spare thread context in system"
1723 "[cpu %d, thread %d]", tc->cpuId(), tc->threadId());
1724 return -EAGAIN;
1725 }
1726
1733 ProcessParams *pp = new ProcessParams();
1734 pp->executable.assign(*(new std::string(p->progName())));
1735 pp->cmd.push_back(*(new std::string(p->progName())));
1736 pp->system = p->system;
1737 pp->cwd.assign(p->tgtCwd);
1738 pp->input.assign("stdin");
1739 pp->output.assign("stdout");
1740 pp->errout.assign("stderr");
1741 pp->uid = p->uid();
1742 pp->euid = p->euid();
1743 pp->gid = p->gid();
1744 pp->egid = p->egid();
1745 pp->release = p->release;
1746
1747 /* Find the first free PID that's less than the maximum */
1748 std::set<int> const& pids = p->system->PIDs;
1749 int temp_pid = *pids.begin();
1750 do {
1751 temp_pid++;
1752 } while (pids.find(temp_pid) != pids.end());
1753 if (temp_pid >= System::maxPID)
1754 fatal("temp_pid is too large: %d", temp_pid);
1755
1756 pp->pid = temp_pid;
1757 pp->ppid = (flags & OS::TGT_CLONE_THREAD) ? p->ppid() : p->pid();
1758 pp->useArchPT = p->useArchPT;
1759 pp->kvmInSE = p->kvmInSE;
1760 Process *cp = pp->create();
1761 // TODO: there is no way to know when the Process SimObject is done with
1762 // the params pointer. Both the params pointer (pp) and the process
1763 // pointer (cp) are normally managed in python and are never cleaned up.
1764
1765 Process *owner = ctc->getProcessPtr();
1766 ctc->setProcessPtr(cp);
1767 cp->assignThreadContext(ctc->contextId());
1768 owner->revokeThreadContext(ctc->contextId());
1769
1770 if (flags & OS::TGT_CLONE_PARENT_SETTID) {
1771 BufferArg ptidBuf(ptidPtr, sizeof(long));
1772 long *ptid = (long *)ptidBuf.bufferPtr();
1773 *ptid = cp->pid();
1774 ptidBuf.copyOut(SETranslatingPortProxy(tc));
1775 }
1776
1777 if (flags & OS::TGT_CLONE_THREAD) {
1778 cp->pTable->initState();
1779 cp->pTable->shared = true;
1780 cp->useForClone = true;
1781 }
1782
1783 ctc->setUseForClone(true);
1784 cp->initState();
1785 p->clone(tc, ctc, cp, flags);
1786
1787 if (flags & OS::TGT_CLONE_THREAD) {
1788 delete cp->sigchld;
1789 cp->sigchld = p->sigchld;
1790 } else if (flags & OS::TGT_SIGCHLD) {
1791 *cp->sigchld = true;
1792 }
1793
1794 if (flags & OS::TGT_CLONE_CHILD_SETTID) {
1795 BufferArg ctidBuf(ctidPtr, sizeof(long));
1796 long *ctid = (long *)ctidBuf.bufferPtr();
1797 *ctid = cp->pid();
1798 ctidBuf.copyOut(SETranslatingPortProxy(ctc));
1799 }
1800
1801 if (flags & OS::TGT_CLONE_CHILD_CLEARTID)
1802 cp->childClearTID = (uint64_t)ctidPtr;
1803
1804 ctc->clearArchRegs();
1805
1806 OS::archClone(flags, p, cp, tc, ctc, newStack, tlsPtr);
1807
1808 desc->returnInto(ctc, 0);
1809
1810 ctc->activate();
1811
1812 if (flags & OS::TGT_CLONE_VFORK) {
1813 tc->suspend();
1814 }
1815
1816 return cp->pid();
1817}
1818
1819template <class OS>
1820SyscallReturn
1823{
1824 VPtr<uint64_t> ptidPtr((Addr)cl_args->parent_tid, tc);
1825 VPtr<uint64_t> ctidPtr((Addr)cl_args->child_tid, tc);
1826 VPtr<uint64_t> tlsPtr((Addr)cl_args->tls, tc);
1827 // Clone3 gives the stack as the *lowest* address, but clone/__clone2
1828 // expects the stack parameter to be the actual stack pointer
1829 uint64_t new_stack = cl_args->stack + cl_args->stack_size;
1830 uint64_t flags = cl_args->flags;
1831
1832 return doClone<OS>(desc, tc, flags, new_stack, ptidPtr, ctidPtr, tlsPtr);
1833}
1834
1835template <class OS>
1836SyscallReturn
1838 VPtr<> ptidPtr, VPtr<> ctidPtr, VPtr<> tlsPtr)
1839{
1840 return doClone<OS>(desc, tc, flags, newStack, ptidPtr, ctidPtr, tlsPtr);
1841}
1842
1843template <class OS>
1844SyscallReturn
1846 RegVal newStack, VPtr<> ptidPtr, VPtr<> tlsPtr,
1847 VPtr<> ctidPtr)
1848{
1849 return cloneFunc<OS>(desc, tc, flags, newStack, ptidPtr, ctidPtr, tlsPtr);
1850}
1851
1853template <class OS>
1854SyscallReturn
1856 int tgt_fd, VPtr<typename OS::tgt_statfs> tgt_stat)
1857{
1858 auto p = tc->getProcessPtr();
1859
1860 auto ffdp = std::dynamic_pointer_cast<FileFDEntry>((*p->fds)[tgt_fd]);
1861 if (!ffdp)
1862 return -EBADF;
1863 int sim_fd = ffdp->getSimFD();
1864
1865 struct statfs hostBuf;
1866 int result = fstatfs(sim_fd, &hostBuf);
1867
1868 if (result < 0)
1869 return -errno;
1870
1871 copyOutStatfsBuf<OS>(tgt_stat, &hostBuf);
1872
1873 return 0;
1874}
1875
1877template <class OS>
1878SyscallReturn
1880 int tgt_fd, uint64_t tiov_base,
1881 typename OS::size_t count)
1882{
1883 auto p = tc->getProcessPtr();
1884
1885 auto ffdp = std::dynamic_pointer_cast<FileFDEntry>((*p->fds)[tgt_fd]);
1886 if (!ffdp)
1887 return -EBADF;
1888 int sim_fd = ffdp->getSimFD();
1889
1890 SETranslatingPortProxy prox(tc);
1891 typename OS::tgt_iovec tiov[count];
1892 struct iovec hiov[count];
1893 for (typename OS::size_t i = 0; i < count; ++i) {
1894 prox.readBlob(tiov_base + (i * sizeof(typename OS::tgt_iovec)),
1895 &tiov[i], sizeof(typename OS::tgt_iovec));
1896 hiov[i].iov_len = gtoh(tiov[i].iov_len, OS::byteOrder);
1897 hiov[i].iov_base = new char [hiov[i].iov_len];
1898 }
1899
1900 int result = readv(sim_fd, hiov, count);
1901 int local_errno = errno;
1902
1903 for (typename OS::size_t i = 0; i < count; ++i) {
1904 if (result != -1) {
1905 prox.writeBlob(htog(tiov[i].iov_base, OS::byteOrder),
1906 hiov[i].iov_base, hiov[i].iov_len);
1907 }
1908 delete [] (char *)hiov[i].iov_base;
1909 }
1910
1911 return (result == -1) ? -local_errno : result;
1912}
1913
1915template <class OS>
1916SyscallReturn
1918 int tgt_fd, uint64_t tiov_base,
1919 typename OS::size_t count)
1920{
1921 auto p = tc->getProcessPtr();
1922
1923 auto hbfdp = std::dynamic_pointer_cast<HBFDEntry>((*p->fds)[tgt_fd]);
1924 if (!hbfdp)
1925 return -EBADF;
1926 int sim_fd = hbfdp->getSimFD();
1927
1928 SETranslatingPortProxy prox(tc);
1929 struct iovec hiov[count];
1930 for (typename OS::size_t i = 0; i < count; ++i) {
1931 typename OS::tgt_iovec tiov;
1932
1933 prox.readBlob(tiov_base + i*sizeof(typename OS::tgt_iovec),
1934 &tiov, sizeof(typename OS::tgt_iovec));
1935 hiov[i].iov_len = gtoh(tiov.iov_len, OS::byteOrder);
1936 hiov[i].iov_base = new char [hiov[i].iov_len];
1937 prox.readBlob(gtoh(tiov.iov_base, OS::byteOrder), hiov[i].iov_base,
1938 hiov[i].iov_len);
1939 }
1940
1941 int result = writev(sim_fd, hiov, count);
1942
1943 for (typename OS::size_t i = 0; i < count; ++i)
1944 delete [] (char *)hiov[i].iov_base;
1945
1946 return (result == -1) ? -errno : result;
1947}
1948
1950template <class OS>
1951SyscallReturn
1953 VPtr<> start, typename OS::size_t length, int prot,
1954 int tgt_flags, int tgt_fd, typename OS::off_t offset)
1955{
1956 auto p = tc->getProcessPtr();
1957 Addr page_bytes = p->pTable->pageSize();
1958
1959 if (start & (page_bytes - 1) ||
1960 offset & (page_bytes - 1) ||
1961 (tgt_flags & OS::TGT_MAP_PRIVATE &&
1962 tgt_flags & OS::TGT_MAP_SHARED) ||
1963 (!(tgt_flags & OS::TGT_MAP_PRIVATE) &&
1964 !(tgt_flags & OS::TGT_MAP_SHARED)) ||
1965 !length) {
1966 return -EINVAL;
1967 }
1968
1969 if ((prot & PROT_WRITE) && (tgt_flags & OS::TGT_MAP_SHARED)) {
1970 // With shared mmaps, there are two cases to consider:
1971 // 1) anonymous: writes should modify the mapping and this should be
1972 // visible to observers who share the mapping. Currently, it's
1973 // difficult to update the shared mapping because there's no
1974 // structure which maintains information about the which virtual
1975 // memory areas are shared. If that structure existed, it would be
1976 // possible to make the translations point to the same frames.
1977 // 2) file-backed: writes should modify the mapping and the file
1978 // which is backed by the mapping. The shared mapping problem is the
1979 // same as what was mentioned about the anonymous mappings. For
1980 // file-backed mappings, the writes to the file are difficult
1981 // because it requires syncing what the mapping holds with the file
1982 // that resides on the host system. So, any write on a real system
1983 // would cause the change to be propagated to the file mapping at
1984 // some point in the future (the inode is tracked along with the
1985 // mapping). This isn't guaranteed to always happen, but it usually
1986 // works well enough. The guarantee is provided by the msync system
1987 // call. We could force the change through with shared mappings with
1988 // a call to msync, but that again would require more information
1989 // than we currently maintain.
1990 warn_once("mmap: writing to shared mmap region is currently "
1991 "unsupported. The write succeeds on the target, but it "
1992 "will not be propagated to the host or shared mappings");
1993 }
1994
1995 length = roundUp(length, page_bytes);
1996
1997 int sim_fd = -1;
1998 if (!(tgt_flags & OS::TGT_MAP_ANONYMOUS)) {
1999 std::shared_ptr<FDEntry> fdep = (*p->fds)[tgt_fd];
2000
2001 auto dfdp = std::dynamic_pointer_cast<DeviceFDEntry>(fdep);
2002 if (dfdp) {
2003 EmulatedDriver *emul_driver = dfdp->getDriver();
2004 return emul_driver->mmap(tc, start, length, prot, tgt_flags,
2005 tgt_fd, offset);
2006 }
2007
2008 auto ffdp = std::dynamic_pointer_cast<FileFDEntry>(fdep);
2009 if (!ffdp)
2010 return -EBADF;
2011 sim_fd = ffdp->getSimFD();
2012
2021 if (p->interpImage.contains(tc->pcState().instAddr())) {
2022 std::shared_ptr<FDEntry> fdep = (*p->fds)[tgt_fd];
2023 auto ffdp = std::dynamic_pointer_cast<FileFDEntry>(fdep);
2024 auto *lib = loader::createObjectFile(p->checkPathRedirect(
2025 ffdp->getFileName()));
2026 DPRINTF_SYSCALL(Verbose, "Loading symbols from %s\n",
2027 ffdp->getFileName());
2028
2029 if (lib) {
2030 Addr offset = lib->buildImage().minAddr() + start;
2031 loader::debugSymbolTable.insert(*lib->symtab().offset(offset));
2032 }
2033 }
2034 }
2035
2039 if (!(tgt_flags & OS::TGT_MAP_FIXED)) {
2047 if (!(start && p->memState->isUnmapped(start, length))) {
2051 start = p->memState->extendMmap(length);
2052 }
2053 }
2054
2055 DPRINTF_SYSCALL(Verbose, " mmap range is 0x%x - 0x%x\n",
2056 start, start + length - 1);
2057
2063 if (tgt_flags & OS::TGT_MAP_FIXED) {
2068 p->memState->unmapRegion(start, length);
2069 }
2070
2074 std::string region_name;
2075 if (tgt_flags & OS::TGT_MAP_ANONYMOUS) {
2076 region_name = "anon";
2077 } else {
2078 std::shared_ptr<FDEntry> fdep = (*p->fds)[tgt_fd];
2079 auto ffdp = std::dynamic_pointer_cast<FileFDEntry>(fdep);
2080 region_name = ffdp->getFileName();
2081 }
2082
2087 p->memState->mapRegion(start, length, region_name, sim_fd, offset);
2088
2089 return (Addr)start;
2090}
2091
2092template <class OS>
2093SyscallReturn
2095 int tgt_fd, VPtr<> bufPtr, int nbytes, int offset)
2096{
2097 auto p = tc->getProcessPtr();
2098
2099 auto ffdp = std::dynamic_pointer_cast<FileFDEntry>((*p->fds)[tgt_fd]);
2100 if (!ffdp)
2101 return -EBADF;
2102 int sim_fd = ffdp->getSimFD();
2103
2104 BufferArg bufArg(bufPtr, nbytes);
2105
2106 int bytes_read = pread(sim_fd, bufArg.bufferPtr(), nbytes, offset);
2107
2108 bufArg.copyOut(SETranslatingPortProxy(tc));
2109
2110 return (bytes_read == -1) ? -errno : bytes_read;
2111}
2112
2113template <class OS>
2114SyscallReturn
2116 int tgt_fd, VPtr<> bufPtr, int nbytes, int offset)
2117{
2118 auto p = tc->getProcessPtr();
2119
2120 auto ffdp = std::dynamic_pointer_cast<FileFDEntry>((*p->fds)[tgt_fd]);
2121 if (!ffdp)
2122 return -EBADF;
2123 int sim_fd = ffdp->getSimFD();
2124
2125 BufferArg bufArg(bufPtr, nbytes);
2126 bufArg.copyIn(SETranslatingPortProxy(tc));
2127
2128 int bytes_written = pwrite(sim_fd, bufArg.bufferPtr(), nbytes, offset);
2129
2130 return (bytes_written == -1) ? -errno : bytes_written;
2131}
2132
2134template <class OS>
2135SyscallReturn
2137 VPtr<> start, typename OS::size_t length, int prot,
2138 int tgt_flags, int tgt_fd, typename OS::off_t offset)
2139{
2140 auto page_size = tc->getProcessPtr()->pTable->pageSize();
2141 return mmapFunc<OS>(desc, tc, start, length, prot, tgt_flags,
2142 tgt_fd, offset * page_size);
2143}
2144
2146template <class OS>
2147SyscallReturn
2149 unsigned resource, VPtr<typename OS::rlimit> rlp)
2150{
2151 const ByteOrder bo = OS::byteOrder;
2152 switch (resource) {
2153 case OS::TGT_RLIMIT_STACK:
2154 // max stack size in bytes: make up a number (8MiB for now)
2155 rlp->rlim_cur = rlp->rlim_max = 8 * 1024 * 1024;
2156 rlp->rlim_cur = htog(rlp->rlim_cur, bo);
2157 rlp->rlim_max = htog(rlp->rlim_max, bo);
2158 break;
2159
2160 case OS::TGT_RLIMIT_DATA:
2161 // max data segment size in bytes: make up a number
2162 rlp->rlim_cur = rlp->rlim_max = 256 * 1024 * 1024;
2163 rlp->rlim_cur = htog(rlp->rlim_cur, bo);
2164 rlp->rlim_max = htog(rlp->rlim_max, bo);
2165 break;
2166
2167 case OS::TGT_RLIMIT_NPROC:
2168 rlp->rlim_cur = rlp->rlim_max = tc->getSystemPtr()->threads.size();
2169 rlp->rlim_cur = htog(rlp->rlim_cur, bo);
2170 rlp->rlim_max = htog(rlp->rlim_max, bo);
2171 break;
2172
2173 default:
2174 warn("getrlimit: unimplemented resource %d", resource);
2175 return -EINVAL;
2176 break;
2177 }
2178
2179 return 0;
2180}
2181
2182template <class OS>
2183SyscallReturn
2185 int pid, int resource, VPtr<> n, VPtr<typename OS::rlimit> rlp)
2186{
2187 if (pid != 0) {
2188 warn("prlimit: ignoring rlimits for nonzero pid");
2189 return -EPERM;
2190 }
2191 if (n)
2192 warn("prlimit: ignoring new rlimit");
2193 if (rlp) {
2194 const ByteOrder bo = OS::byteOrder;
2195 switch (resource) {
2196 case OS::TGT_RLIMIT_STACK:
2197 // max stack size in bytes: make up a number (8MiB for now)
2198 rlp->rlim_cur = rlp->rlim_max = 8 * 1024 * 1024;
2199 rlp->rlim_cur = htog(rlp->rlim_cur, bo);
2200 rlp->rlim_max = htog(rlp->rlim_max, bo);
2201 break;
2202 case OS::TGT_RLIMIT_DATA:
2203 // max data segment size in bytes: make up a number
2204 rlp->rlim_cur = rlp->rlim_max = 256*1024*1024;
2205 rlp->rlim_cur = htog(rlp->rlim_cur, bo);
2206 rlp->rlim_max = htog(rlp->rlim_max, bo);
2207 break;
2208 default:
2209 warn("prlimit: unimplemented resource %d", resource);
2210 return -EINVAL;
2211 break;
2212 }
2213 }
2214 return 0;
2215}
2216
2218template <class OS>
2219SyscallReturn
2221 int clk_id, VPtr<typename OS::timespec> tp)
2222{
2223 getElapsedTimeNano(tp->tv_sec, tp->tv_nsec);
2224 tp->tv_sec += seconds_since_epoch;
2225 tp->tv_sec = htog(tp->tv_sec, OS::byteOrder);
2226 tp->tv_nsec = htog(tp->tv_nsec, OS::byteOrder);
2227
2228 return 0;
2229}
2230
2232template <class OS>
2233SyscallReturn
2236{
2237 // Set resolution at ns, which is what clock_gettime() returns
2238 tp->tv_sec = 0;
2239 tp->tv_nsec = 1;
2240
2241 return 0;
2242}
2243
2245template <class OS>
2246SyscallReturn
2249{
2250 getElapsedTimeMicro(tp->tv_sec, tp->tv_usec);
2251 tp->tv_sec += seconds_since_epoch;
2252 tp->tv_sec = htog(tp->tv_sec, OS::byteOrder);
2253 tp->tv_usec = htog(tp->tv_usec, OS::byteOrder);
2254
2255 return 0;
2256}
2257
2259template <class OS>
2260SyscallReturn
2262 int dirfd, VPtr<> pathname, VPtr<typename OS::timeval [2]> tp)
2263{
2264 std::string path;
2265 if (!SETranslatingPortProxy(tc).tryReadString(path, pathname))
2266 return -EFAULT;
2267
2268 // Modifying path from the directory descriptor
2269 if (auto res = atSyscallPath<OS>(tc, dirfd, path); !res.successful()) {
2270 return res;
2271 }
2272
2273 struct timeval hostTimeval[2];
2274 for (int i = 0; i < 2; ++i) {
2275 hostTimeval[i].tv_sec = gtoh((*tp)[i].tv_sec, OS::byteOrder);
2276 hostTimeval[i].tv_usec = gtoh((*tp)[i].tv_usec, OS::byteOrder);
2277 }
2278
2279 // Adjust path for cwd and redirection
2280 auto process = tc->getProcessPtr();
2281 path = process->checkPathRedirect(path);
2282
2283 int result = utimes(path.c_str(), hostTimeval);
2284
2285 if (result < 0)
2286 return -errno;
2287
2288 return 0;
2289}
2290
2292template <class OS>
2293SyscallReturn
2295 VPtr<typename OS::timeval [2]> tp)
2296{
2297 return futimesatFunc<OS>(desc, tc, OS::TGT_AT_FDCWD, pathname, tp);
2298}
2299
2300template <class OS>
2301SyscallReturn
2303 VPtr<> pathname, VPtr<> argv_mem_loc, VPtr<> envp_mem_loc)
2304{
2305 auto p = tc->getProcessPtr();
2306
2307 std::string path;
2308 SETranslatingPortProxy mem_proxy(tc);
2309 if (!mem_proxy.tryReadString(path, pathname))
2310 return -EFAULT;
2311
2312 if (access(path.c_str(), F_OK) == -1)
2313 return -EACCES;
2314
2315 auto read_in = [](std::vector<std::string> &vect,
2316 PortProxy &mem_proxy, VPtr<> mem_loc)
2317 {
2318 for (int inc = 0; ; inc++) {
2319 BufferArg b((mem_loc + sizeof(Addr) * inc), sizeof(Addr));
2320 b.copyIn(mem_proxy);
2321
2322 if (!*(Addr*)b.bufferPtr())
2323 break;
2324
2325 vect.push_back(std::string());
2326 mem_proxy.tryReadString(vect[inc], *(Addr*)b.bufferPtr());
2327 }
2328 };
2329
2334 if (!p->vforkContexts.empty()) {
2335 ThreadContext *vtc = p->system->threads[p->vforkContexts.front()];
2336 assert(vtc->status() == ThreadContext::Suspended);
2337 vtc->activate();
2338 }
2339
2346 ProcessParams *pp = new ProcessParams();
2347 pp->executable = path;
2348 read_in(pp->cmd, mem_proxy, argv_mem_loc);
2349 read_in(pp->env, mem_proxy, envp_mem_loc);
2350 pp->uid = p->uid();
2351 pp->egid = p->egid();
2352 pp->euid = p->euid();
2353 pp->gid = p->gid();
2354 pp->ppid = p->ppid();
2355 pp->pid = p->pid();
2356 pp->input.assign("cin");
2357 pp->output.assign("cout");
2358 pp->errout.assign("cerr");
2359 pp->cwd.assign(p->tgtCwd);
2360 pp->system = p->system;
2361 pp->release = p->release;
2370 p->system->PIDs.erase(p->pid());
2371 Process *new_p = pp->create();
2372 // TODO: there is no way to know when the Process SimObject is done with
2373 // the params pointer. Both the params pointer (pp) and the process
2374 // pointer (p) are normally managed in python and are never cleaned up.
2375
2380 new_p->fds = p->fds;
2381 for (int i = 0; i < new_p->fds->getSize(); i++) {
2382 std::shared_ptr<FDEntry> fdep = (*new_p->fds)[i];
2383 if (fdep && fdep->getCOE())
2384 new_p->fds->closeFDEntry(i);
2385 }
2386
2387 *new_p->sigchld = true;
2388
2389 tc->clearArchRegs();
2390 tc->setProcessPtr(new_p);
2391 new_p->assignThreadContext(tc->contextId());
2392 new_p->init();
2393 new_p->initState();
2394 tc->activate();
2395
2396 return SyscallReturn();
2397}
2398
2400template <class OS>
2401SyscallReturn
2403 int who /* THREAD, SELF, or CHILDREN */,
2405{
2406 rup->ru_utime.tv_sec = 0;
2407 rup->ru_utime.tv_usec = 0;
2408 rup->ru_stime.tv_sec = 0;
2409 rup->ru_stime.tv_usec = 0;
2410 rup->ru_maxrss = 0;
2411 rup->ru_ixrss = 0;
2412 rup->ru_idrss = 0;
2413 rup->ru_isrss = 0;
2414 rup->ru_minflt = 0;
2415 rup->ru_majflt = 0;
2416 rup->ru_nswap = 0;
2417 rup->ru_inblock = 0;
2418 rup->ru_oublock = 0;
2419 rup->ru_msgsnd = 0;
2420 rup->ru_msgrcv = 0;
2421 rup->ru_nsignals = 0;
2422 rup->ru_nvcsw = 0;
2423 rup->ru_nivcsw = 0;
2424
2425 switch (who) {
2426 case OS::TGT_RUSAGE_SELF:
2427 getElapsedTimeMicro(rup->ru_utime.tv_sec, rup->ru_utime.tv_usec);
2428 rup->ru_utime.tv_sec = htog(rup->ru_utime.tv_sec, OS::byteOrder);
2429 rup->ru_utime.tv_usec = htog(rup->ru_utime.tv_usec, OS::byteOrder);
2430 break;
2431
2432 case OS::TGT_RUSAGE_CHILDREN:
2433 // do nothing. We have no child processes, so they take no time.
2434 break;
2435
2436 default:
2437 // don't really handle THREAD or CHILDREN, but just warn and
2438 // plow ahead
2439 warn("getrusage() only supports RUSAGE_SELF. Parameter %d ignored.",
2440 who);
2441 }
2442
2443 return 0;
2444}
2445
2447template <class OS>
2448SyscallReturn
2450{
2451 // Fill in the time structure (in clocks)
2452 int64_t clocks = curTick() * OS::M5_SC_CLK_TCK / sim_clock::as_int::s;
2453 bufp->tms_utime = clocks;
2454 bufp->tms_stime = 0;
2455 bufp->tms_cutime = 0;
2456 bufp->tms_cstime = 0;
2457
2458 // Convert to host endianness
2459 bufp->tms_utime = htog(bufp->tms_utime, OS::byteOrder);
2460
2461 // Return clock ticks since system boot
2462 return clocks;
2463}
2464
2466template <class OS>
2467SyscallReturn
2469{
2470 typename OS::time_t sec, usec;
2471 getElapsedTimeMicro(sec, usec);
2472 sec += seconds_since_epoch;
2473
2475 if (taddr != 0) {
2476 typename OS::time_t t = sec;
2477 t = htog(t, OS::byteOrder);
2478 p.writeBlob(taddr, &t, (int)sizeof(typename OS::time_t));
2479 }
2480 return sec;
2481}
2482
2483template <class OS>
2484SyscallReturn
2485tgkillFunc(SyscallDesc *desc, ThreadContext *tc, int tgid, int tid, int sig)
2486{
2502 System *sys = tc->getSystemPtr();
2503 Process *tgt_proc = nullptr;
2504 for (auto *tc: sys->threads) {
2505 Process *temp = tc->getProcessPtr();
2506 if (temp->pid() == tid) {
2507 tgt_proc = temp;
2508 break;
2509 }
2510 }
2511
2512 if (sig != 0 && sig != OS::TGT_SIGABRT)
2513 return -EINVAL;
2514
2515 if (tgt_proc == nullptr)
2516 return -ESRCH;
2517
2518 if (tgid != -1 && tgt_proc->tgid() != tgid)
2519 return -ESRCH;
2520
2521 if (sig == OS::TGT_SIGABRT)
2522 exitGroupFunc(desc, tc, 0);
2523
2524 return 0;
2525}
2526
2527template <class OS>
2528SyscallReturn
2530 int domain, int type, int prot)
2531{
2532 auto p = tc->getProcessPtr();
2533
2534 int sim_fd = socket(domain, type, prot);
2535 if (sim_fd == -1)
2536 return -errno;
2537
2538 auto sfdp = std::make_shared<SocketFDEntry>(sim_fd, domain, type, prot);
2539 int tgt_fd = p->fds->allocFD(sfdp);
2540
2541 return tgt_fd;
2542}
2543
2544template <class OS>
2545SyscallReturn
2547 int domain, int type, int prot, VPtr<> svPtr)
2548{
2549 auto p = tc->getProcessPtr();
2550
2551 BufferArg svBuf((Addr)svPtr, 2 * sizeof(int));
2552 int status = socketpair(domain, type, prot, (int *)svBuf.bufferPtr());
2553 if (status == -1)
2554 return -errno;
2555
2556 int *fds = (int *)svBuf.bufferPtr();
2557
2558 auto sfdp1 = std::make_shared<SocketFDEntry>(fds[0], domain, type, prot);
2559 fds[0] = p->fds->allocFD(sfdp1);
2560 auto sfdp2 = std::make_shared<SocketFDEntry>(fds[1], domain, type, prot);
2561 fds[1] = p->fds->allocFD(sfdp2);
2563
2564 return status;
2565}
2566
2567template <class OS>
2568SyscallReturn
2574{
2575 int retval;
2576
2577 auto p = tc->getProcessPtr();
2578
2584 fd_set readfds_h;
2585 FD_ZERO(&readfds_h);
2586 fd_set writefds_h;
2587 FD_ZERO(&writefds_h);
2588 fd_set errorfds_h;
2589 FD_ZERO(&errorfds_h);
2590
2600 int nfds_h = 0;
2601 std::map<int, int> trans_map;
2602 auto try_add_host_set = [&](typename OS::fd_set *tgt_set_entry,
2603 fd_set *hst_set_entry,
2604 int iter) -> bool
2605 {
2611 if (FD_ISSET(iter, (fd_set *)tgt_set_entry)) {
2617 auto hbfdp = std::dynamic_pointer_cast<HBFDEntry>((*p->fds)[iter]);
2618 if (!hbfdp)
2619 return true;
2620 auto sim_fd = hbfdp->getSimFD();
2621
2627 trans_map[sim_fd] = iter;
2628
2634 nfds_h = std::max(nfds_h - 1, sim_fd + 1);
2635
2640 FD_SET(sim_fd, hst_set_entry);
2641 }
2642 return false;
2643 };
2644
2645 for (int i = 0; i < nfds; i++) {
2646 if (readfds) {
2647 bool ebadf = try_add_host_set(readfds, &readfds_h, i);
2648 if (ebadf)
2649 return -EBADF;
2650 }
2651 if (writefds) {
2652 bool ebadf = try_add_host_set(writefds, &writefds_h, i);
2653 if (ebadf)
2654 return -EBADF;
2655 }
2656 if (errorfds) {
2657 bool ebadf = try_add_host_set(errorfds, &errorfds_h, i);
2658 if (ebadf)
2659 return -EBADF;
2660 }
2661 }
2662
2663 if (timeout) {
2671 timeout->tv_sec = 0;
2672 timeout->tv_usec = 0;
2673
2674 retval = select(nfds_h,
2675 readfds ? &readfds_h : nullptr,
2676 writefds ? &writefds_h : nullptr,
2677 errorfds ? &errorfds_h : nullptr,
2678 (timeval *)(typename OS::timeval *)timeout);
2679 } else {
2687 struct timeval tv = { 0, 0 };
2688
2689 retval = select(nfds_h,
2690 readfds ? &readfds_h : nullptr,
2691 readfds ? &writefds_h : nullptr,
2692 readfds ? &errorfds_h : nullptr,
2693 &tv);
2694
2695 if (retval == 0) {
2701 for (auto sig : tc->getSystemPtr()->signalList)
2702 if (sig.receiver == p)
2703 return -EINTR;
2704 return SyscallReturn::retry();
2705 }
2706 }
2707
2708 if (retval == -1)
2709 return -errno;
2710
2711 if (readfds) {
2712 FD_ZERO(reinterpret_cast<fd_set *>((typename OS::fd_set *)readfds));
2713 }
2714 if (writefds) {
2715 FD_ZERO(reinterpret_cast<fd_set *>((typename OS::fd_set *)writefds));
2716 }
2717 if (errorfds) {
2718 FD_ZERO(reinterpret_cast<fd_set *>((typename OS::fd_set *)errorfds));
2719 }
2720
2726 for (int i = 0; i < nfds_h; i++) {
2727 if (readfds && FD_ISSET(i, &readfds_h))
2728 FD_SET(trans_map[i],
2729 reinterpret_cast<fd_set *>(
2730 (typename OS::fd_set *)readfds));
2731
2732 if (writefds && FD_ISSET(i, &writefds_h))
2733 FD_SET(trans_map[i],
2734 reinterpret_cast<fd_set *>(
2735 (typename OS::fd_set *)writefds));
2736
2737 if (errorfds && FD_ISSET(i, &errorfds_h))
2738 FD_SET(trans_map[i],
2739 reinterpret_cast<fd_set *>(
2740 (typename OS::fd_set *)errorfds));
2741 }
2742
2743 return retval;
2744}
2745
2746template <class OS>
2747SyscallReturn
2749 int tgt_fd, VPtr<> buf_ptr, int nbytes)
2750{
2751 auto p = tc->getProcessPtr();
2752
2753 auto hbfdp = std::dynamic_pointer_cast<HBFDEntry>((*p->fds)[tgt_fd]);
2754 if (!hbfdp)
2755 return -EBADF;
2756 int sim_fd = hbfdp->getSimFD();
2757
2758 struct pollfd pfd;
2759 pfd.fd = sim_fd;
2760 pfd.events = POLLIN | POLLPRI;
2761 if ((poll(&pfd, 1, 0) == 0)
2762 && !(hbfdp->getFlags() & OS::TGT_O_NONBLOCK))
2763 return SyscallReturn::retry();
2764
2765 BufferArg buf_arg(buf_ptr, nbytes);
2766 int bytes_read = read(sim_fd, buf_arg.bufferPtr(), nbytes);
2767
2768 if (bytes_read > 0)
2769 buf_arg.copyOut(SETranslatingPortProxy(tc));
2770
2771 return (bytes_read == -1) ? -errno : bytes_read;
2772}
2773
2774template <class OS>
2775SyscallReturn
2777 int tgt_fd, VPtr<> buf_ptr, int nbytes)
2778{
2779 auto p = tc->getProcessPtr();
2780
2781 auto hbfdp = std::dynamic_pointer_cast<HBFDEntry>((*p->fds)[tgt_fd]);
2782 if (!hbfdp)
2783 return -EBADF;
2784 int sim_fd = hbfdp->getSimFD();
2785
2786 BufferArg buf_arg(buf_ptr, nbytes);
2787 buf_arg.copyIn(SETranslatingPortProxy(tc));
2788
2789 struct pollfd pfd;
2790 pfd.fd = sim_fd;
2791 pfd.events = POLLOUT;
2792
2799 auto ffdp = std::dynamic_pointer_cast<FileFDEntry>(hbfdp);
2800 if (ffdp && (ffdp->getFileName() != "/dev/random")) {
2801 if (!poll(&pfd, 1, 0) && !(ffdp->getFlags() & OS::TGT_O_NONBLOCK))
2802 return SyscallReturn::retry();
2803 }
2804
2805 int bytes_written = write(sim_fd, buf_arg.bufferPtr(), nbytes);
2806
2807 if (bytes_written != -1)
2808 fsync(sim_fd);
2809
2810 return (bytes_written == -1) ? -errno : bytes_written;
2811}
2812
2813template <class OS>
2814SyscallReturn
2816 pid_t pid, VPtr<> statPtr, int options, VPtr<> rusagePtr)
2817{
2818 auto p = tc->getProcessPtr();
2819
2820 if (rusagePtr)
2821 DPRINTF_SYSCALL(Verbose, "wait4: rusage pointer provided %lx, however "
2822 "functionality not supported. Ignoring rusage pointer.\n",
2823 rusagePtr);
2824
2833 System *sysh = tc->getSystemPtr();
2835 for (iter=sysh->signalList.begin(); iter!=sysh->signalList.end(); iter++) {
2836 if (iter->receiver == p) {
2837 if (pid < -1) {
2838 if ((iter->sender->pgid() == -pid)
2839 && (iter->signalValue == OS::TGT_SIGCHLD))
2840 goto success;
2841 } else if (pid == -1) {
2842 if (iter->signalValue == OS::TGT_SIGCHLD)
2843 goto success;
2844 } else if (pid == 0) {
2845 if ((iter->sender->pgid() == p->pgid())
2846 && (iter->signalValue == OS::TGT_SIGCHLD))
2847 goto success;
2848 } else {
2849 if ((iter->sender->pid() == pid)
2850 && (iter->signalValue == OS::TGT_SIGCHLD))
2851 goto success;
2852 }
2853 }
2854 }
2855
2856 return (options & OS::TGT_WNOHANG) ? 0 : SyscallReturn::retry();
2857
2858success:
2859 // Set status to EXITED for WIFEXITED evaluations.
2860 const int EXITED = 0;
2861 BufferArg statusBuf(statPtr, sizeof(int));
2862 *(int *)statusBuf.bufferPtr() = EXITED;
2863 statusBuf.copyOut(SETranslatingPortProxy(tc));
2864
2865 // Return the child PID.
2866 pid_t retval = iter->sender->pid();
2867 sysh->signalList.erase(iter);
2868 return retval;
2869}
2870
2871template <class OS>
2872SyscallReturn
2874 int tgt_fd, VPtr<> addrPtr, VPtr<> lenPtr)
2875{
2876 struct sockaddr sa;
2877 socklen_t addrLen;
2878 int host_fd;
2879 auto p = tc->getProcessPtr();
2880
2881 BufferArg *lenBufPtr = nullptr;
2882 BufferArg *addrBufPtr = nullptr;
2883
2884 auto sfdp = std::dynamic_pointer_cast<SocketFDEntry>((*p->fds)[tgt_fd]);
2885 if (!sfdp)
2886 return -EBADF;
2887 int sim_fd = sfdp->getSimFD();
2888
2895 struct pollfd pfd;
2896 pfd.fd = sim_fd;
2897 pfd.events = POLLIN | POLLPRI;
2898 if ((poll(&pfd, 1, 0) == 0) && !(sfdp->getFlags() & OS::TGT_O_NONBLOCK))
2899 return SyscallReturn::retry();
2900
2901 if (lenPtr) {
2902 lenBufPtr = new BufferArg(lenPtr, sizeof(socklen_t));
2903 lenBufPtr->copyIn(SETranslatingPortProxy(tc));
2904 memcpy(&addrLen, (socklen_t *)lenBufPtr->bufferPtr(),
2905 sizeof(socklen_t));
2906 }
2907
2908 if (addrPtr) {
2909 addrBufPtr = new BufferArg(addrPtr, sizeof(struct sockaddr));
2910 addrBufPtr->copyIn(SETranslatingPortProxy(tc));
2911 memcpy(&sa, (struct sockaddr *)addrBufPtr->bufferPtr(),
2912 sizeof(struct sockaddr));
2913 }
2914
2915 host_fd = accept(sim_fd, &sa, &addrLen);
2916
2917 if (host_fd == -1)
2918 return -errno;
2919
2920 if (addrPtr) {
2921 memcpy(addrBufPtr->bufferPtr(), &sa, sizeof(sa));
2922 addrBufPtr->copyOut(SETranslatingPortProxy(tc));
2923 delete(addrBufPtr);
2924 }
2925
2926 if (lenPtr) {
2927 *(socklen_t *)lenBufPtr->bufferPtr() = addrLen;
2928 lenBufPtr->copyOut(SETranslatingPortProxy(tc));
2929 delete(lenBufPtr);
2930 }
2931
2932 auto afdp = std::make_shared<SocketFDEntry>(host_fd, sfdp->_domain,
2933 sfdp->_type, sfdp->_protocol);
2934 return p->fds->allocFD(afdp);
2935}
2936
2938template <class OS>
2939SyscallReturn
2941 unsigned initval, int in_flags)
2942{
2943#if defined(__linux__)
2944 auto p = tc->getProcessPtr();
2945
2946 int sim_fd = eventfd(initval, in_flags);
2947 if (sim_fd == -1)
2948 return -errno;
2949
2950 bool cloexec = in_flags & OS::TGT_O_CLOEXEC;
2951
2952 int flags = cloexec ? OS::TGT_O_CLOEXEC : 0;
2953 flags |= (in_flags & OS::TGT_O_NONBLOCK) ? OS::TGT_O_NONBLOCK : 0;
2954
2955 auto hbfdp = std::make_shared<HBFDEntry>(flags, sim_fd, cloexec);
2956 int tgt_fd = p->fds->allocFD(hbfdp);
2957 return tgt_fd;
2958#else
2959 warnUnsupportedOS("eventfd");
2960 return -1;
2961#endif
2962}
2963
2965template <class OS>
2966SyscallReturn
2968 pid_t pid, typename OS::size_t cpusetsize,
2969 VPtr<> cpu_set_mask)
2970{
2971#if defined(__linux__)
2972 if (cpusetsize < CPU_ALLOC_SIZE(tc->getSystemPtr()->threads.size()))
2973 return -EINVAL;
2974
2975 SETranslatingPortProxy proxy(tc);
2976 BufferArg maskBuf(cpu_set_mask, cpusetsize);
2977 maskBuf.copyIn(proxy);
2978 for (int i = 0; i < tc->getSystemPtr()->threads.size(); i++) {
2979 CPU_SET(i, (cpu_set_t *)maskBuf.bufferPtr());
2980 }
2981 maskBuf.copyOut(proxy);
2982 return CPU_ALLOC_SIZE(tc->getSystemPtr()->threads.size());
2983#else
2984 warnUnsupportedOS("sched_getaffinity");
2985 return -1;
2986#endif
2987}
2988
2989// Target recvfrom() handler.
2990template <class OS>
2991SyscallReturn
2993 int tgt_fd, VPtr<> buf_ptr, typename OS::size_t buf_len,
2994 int flags, VPtr<> addr_ptr, VPtr<> addrlen_ptr)
2995{
2996 auto p = tc->getProcessPtr();
2997
2998 auto sfdp = std::dynamic_pointer_cast<SocketFDEntry>((*p->fds)[tgt_fd]);
2999 if (!sfdp)
3000 return -EBADF;
3001 int sim_fd = sfdp->getSimFD();
3002
3003 // Reserve buffer space.
3004 BufferArg buf(buf_ptr, buf_len);
3005
3006 SETranslatingPortProxy proxy(tc);
3007
3008 // Get address length.
3009 socklen_t addr_len = 0;
3010 if (addrlen_ptr != 0) {
3011 // Read address length parameter.
3012 BufferArg addrlen_buf(addrlen_ptr, sizeof(socklen_t));
3013 addrlen_buf.copyIn(proxy);
3014 addr_len = *((socklen_t *)addrlen_buf.bufferPtr());
3015 }
3016
3017 struct sockaddr sa, *sap = NULL;
3018 if (addr_len != 0) {
3019 BufferArg addr_buf(addr_ptr, addr_len);
3020 addr_buf.copyIn(proxy);
3021 memcpy(&sa, (struct sockaddr *)addr_buf.bufferPtr(),
3022 sizeof(struct sockaddr));
3023 sap = &sa;
3024 }
3025
3026 ssize_t recvd_size = recvfrom(sim_fd,
3027 (void *)buf.bufferPtr(),
3028 buf_len, flags, sap, (socklen_t *)&addr_len);
3029
3030 if (recvd_size == -1)
3031 return -errno;
3032
3033 // Pass the received data out.
3034 buf.copyOut(proxy);
3035
3036 // Copy address to addr_ptr and pass it on.
3037 if (sap != NULL) {
3038 BufferArg addr_buf(addr_ptr, addr_len);
3039 memcpy(addr_buf.bufferPtr(), sap, sizeof(sa));
3040 addr_buf.copyOut(proxy);
3041 }
3042
3043 // Copy len to addrlen_ptr and pass it on.
3044 if (addr_len != 0) {
3045 BufferArg addrlen_buf(addrlen_ptr, sizeof(socklen_t));
3046 *(socklen_t *)addrlen_buf.bufferPtr() = addr_len;
3047 addrlen_buf.copyOut(proxy);
3048 }
3049
3050 return recvd_size;
3051}
3052
3053// Target sendto() handler.
3054template <typename OS>
3055SyscallReturn
3057 int tgt_fd, VPtr<> buf_ptr, typename OS::size_t buf_len, int flags,
3058 VPtr<> addr_ptr, socklen_t addr_len)
3059{
3060 auto p = tc->getProcessPtr();
3061
3062 auto sfdp = std::dynamic_pointer_cast<SocketFDEntry>((*p->fds)[tgt_fd]);
3063 if (!sfdp)
3064 return -EBADF;
3065 int sim_fd = sfdp->getSimFD();
3066
3067 // Reserve buffer space.
3068 BufferArg buf(buf_ptr, buf_len);
3070
3071 struct sockaddr sa, *sap = nullptr;
3072 memset(&sa, 0, sizeof(sockaddr));
3073 if (addr_len != 0) {
3074 BufferArg addr_buf(addr_ptr, addr_len);
3075 addr_buf.copyIn(SETranslatingPortProxy(tc));
3076 memcpy(&sa, (sockaddr*)addr_buf.bufferPtr(), addr_len);
3077 sap = &sa;
3078 }
3079
3080 ssize_t sent_size = sendto(sim_fd,
3081 (void *)buf.bufferPtr(),
3082 buf_len, flags, sap, (socklen_t)addr_len);
3083
3084 return (sent_size == -1) ? -errno : sent_size;
3085}
3086
3088template <typename OS>
3089SyscallReturn
3091 typename OS::size_t length)
3092{
3093 // Even if the system is currently not capable of recycling physical
3094 // pages, there is no reason we can't unmap them so that we trigger
3095 // appropriate seg faults when the application mistakenly tries to
3096 // access them again.
3097 auto p = tc->getProcessPtr();
3098
3099 if (p->pTable->pageOffset(start))
3100 return -EINVAL;
3101
3102 length = roundUp(length, p->pTable->pageSize());
3103
3104 p->memState->unmapRegion(start, length);
3105
3106 return 0;
3107}
3108
3109// Target fallocate() handler.
3110template <typename OS>
3111SyscallReturn
3113 int tgt_fd, int mode, typename OS::off_t offset,
3114 typename OS::off_t len)
3115{
3116#if defined(__linux__)
3117 auto p = tc->getProcessPtr();
3118
3119 auto ffdp = std::dynamic_pointer_cast<FileFDEntry>((*p->fds)[tgt_fd]);
3120 if (!ffdp)
3121 return -EBADF;
3122 int sim_fd = ffdp->getSimFD();
3123
3124 int result = fallocate(sim_fd, mode, offset, len);
3125 if (result < 0)
3126 return -errno;
3127 return 0;
3128#else
3129 warnUnsupportedOS("fallocate");
3130 return -1;
3131#endif
3132}
3133
3135template <typename OS>
3136SyscallReturn
3138 typename OS::off_t length)
3139{
3140 std::string path;
3141 auto p = tc->getProcessPtr();
3142
3143 if (!SETranslatingPortProxy(tc).tryReadString(path, pathname))
3144 return -EFAULT;
3145
3146 // Adjust path for cwd and redirection
3147 path = p->checkPathRedirect(path);
3148
3149 int result = truncate(path.c_str(), length);
3150 return (result == -1) ? -errno : result;
3151}
3152
3154template <typename OS>
3155SyscallReturn
3157 typename OS::off_t length)
3158{
3159 auto p = tc->getProcessPtr();
3160
3161 auto ffdp = std::dynamic_pointer_cast<FileFDEntry>((*p->fds)[tgt_fd]);
3162 if (!ffdp)
3163 return -EBADF;
3164 int sim_fd = ffdp->getSimFD();
3165
3166 int result = ftruncate(sim_fd, length);
3167 return (result == -1) ? -errno : result;
3168}
3169
3170template <typename OS>
3171SyscallReturn
3173 VPtr<> buf_ptr, typename OS::size_t count,
3174 unsigned int flags)
3175{
3176 SETranslatingPortProxy proxy(tc);
3177
3178 TypedBufferArg<uint8_t> buf(buf_ptr, count);
3179 for (int i = 0; i < count; ++i) {
3180 buf[i] = gem5::random_mt.random<uint8_t>();
3181 }
3182 buf.copyOut(proxy);
3183
3184 return count;
3185}
3186
3187} // namespace gem5
3188
3189#endif // __SIM_SYSCALL_EMUL_HH__
#define DPRINTF(x,...)
Definition trace.hh:210
Defines global host-dependent types: Counter, Tick, and (indirectly) {int,uint}{8,...
bool copyIn(const PortProxy &memproxy)
copy data into simulator space (read from target memory)
bool copyOut(const PortProxy &memproxy)
copy data out of simulator space (write to target memory)
BufferArg represents an untyped buffer in target user space that is passed by reference to an (emulat...
void * bufferPtr()
Return a pointer to the internal simulator-space buffer.
Addr addr() const
Definition proxy_ptr.hh:173
EmulatedDriver is an abstract base class for fake SE-mode device drivers.
virtual int ioctl(ThreadContext *tc, unsigned req, Addr buf)=0
Abstract method, invoked when the user program calls ioctl() on the file descriptor returned by a pre...
virtual int open(ThreadContext *tc, int mode, int flags)=0
Abstract method, invoked when the user program calls open() on the device driver.
virtual Addr mmap(ThreadContext *tc, Addr start, uint64_t length, int prot, int tgtFlags, int tgtFd, off_t offset)
Virtual method, invoked when the user program calls mmap() on the file descriptor returned by a previ...
virtual void initState()
FutexMap class holds a map of all futexes used in the system.
Definition futex_map.hh:110
void suspend_bitset(Addr addr, uint64_t tgid, ThreadContext *tc, int bitmask)
Definition futex_map.cc:89
int requeue(Addr addr1, uint64_t tgid, int count, int count2, Addr addr2)
This operation wakes a given number (val) of waiters.
Definition futex_map.cc:141
void suspend(Addr addr, uint64_t tgid, ThreadContext *tc)
Inserts a futex into the map with one waiting TC.
Definition futex_map.cc:53
int wakeup(Addr addr, uint64_t tgid, int count)
Wakes up at most count waiting threads on a futex.
Definition futex_map.cc:59
int wakeup_bitset(Addr addr, uint64_t tgid, int bitmask)
Definition futex_map.cc:108
Addr instAddr() const
Returns the memory address of the instruction this PC points to.
Definition pcstate.hh:108
This object is a proxy for a port or other object which implements the functional response protocol,...
Definition port_proxy.hh:87
void readBlob(Addr addr, void *p, uint64_t size) const
Higher level interfaces based on the above.
void writeBlob(Addr addr, const void *p, uint64_t size) const
Same as tryWriteBlob, but insists on success.
bool tryReadString(std::string &str, Addr addr) const
Reads the string at guest address addr into the std::string str.
void init() override
init() is called after all C++ SimObjects have been created and all ports are connected.
Definition process.cc:278
uint64_t pid()
Definition process.hh:86
std::shared_ptr< FDArray > fds
Definition process.hh:286
void assignThreadContext(ContextID context_id)
Definition process.hh:130
bool useForClone
Definition process.hh:182
bool * sigchld
Definition process.hh:298
std::string checkPathRedirect(const std::string &filename)
Redirect file path if it matches any keys initialized by system object.
Definition process.cc:424
void initState() override
initState() is called on each SimObject when not restoring from a checkpoint.
Definition process.cc:288
uint64_t tgid()
Definition process.hh:90
void revokeThreadContext(int context_id)
After delegating a thread context to a child process no longer should relate to the ThreadContext.
Definition process.cc:265
EmulationPageTable * pTable
Definition process.hh:184
uint64_t childClearTID
Calls a futex wakeup at the address specified by this pointer when this process exits.
Definition process.hh:295
This class provides the wrapper interface for the system call implementations which are defined in th...
std::string name() const
virtual void returnInto(ThreadContext *tc, const SyscallReturn &ret)=0
For use within the system call executor if new threads are created and need something returned into t...
This class represents the return value from an emulated system call, including any errno setting.
static SyscallReturn retry()
Pseudo-constructor to create an instance with the retry flag set.
bool successful() const
Was the system call successful?
int size() const
Definition system.hh:210
ThreadContext * findFree()
Definition system.cc:121
static const int maxPID
Definition system.hh:600
std::list< BasicSignal > signalList
Definition system.hh:607
FutexMap futexMap
Definition system.hh:598
Threads threads
Definition system.hh:310
ThreadContext is the external interface to all thread state for anything outside of the CPU.
virtual void activate()=0
Set the status to Active.
virtual System * getSystemPtr()=0
virtual void clearArchRegs()=0
virtual void setProcessPtr(Process *p)=0
@ Suspended
Temporarily inactive.
virtual const PCStateBase & pcState() const =0
virtual int threadId() const =0
virtual Status status() const =0
virtual Process * getProcessPtr()=0
virtual ContextID contextId() const =0
virtual void suspend()=0
Set the status to Suspended.
void setUseForClone(bool new_val)
virtual int cpuId() const =0
TypedBufferArg is a class template; instances of this template represent typed buffers in target user...
bool insert(const Symbol &symbol)
Insert a new symbol in the table if it does not already exist.
Definition symtab.cc:66
STL list class.
Definition stl.hh:51
STL vector class.
Definition stl.hh:37
Random random_mt
Definition random.cc:99
std::enable_if_t< std::is_integral_v< T >, T > random()
Use the SFINAE idiom to choose an implementation based on whether the type is integral or floating po...
Definition random.hh:90
static constexpr T roundUp(const T &val, const U &align)
This function is used to align addresses in memory.
Definition intmath.hh:260
#define fatal(...)
This implements a cprintf based fatal() function.
Definition logging.hh:200
uint8_t flags
Definition helpers.cc:87
#define warn(...)
Definition logging.hh:256
#define warn_once(...)
Definition logging.hh:260
#define warn_if(cond,...)
Conditional warning macro that checks the supplied condition and only prints a warning if the conditi...
Definition logging.hh:283
Bitfield< 14, 12 > fd
Definition types.hh:150
Bitfield< 31 > n
Bitfield< 3 > sa
Bitfield< 3, 0 > mask
Definition pcstate.hh:63
Bitfield< 18, 16 > len
Bitfield< 4, 0 > mode
Definition misc_types.hh:74
Bitfield< 5 > t
Definition misc_types.hh:71
Bitfield< 7 > b
Bitfield< 7 > i
Definition misc_types.hh:67
Bitfield< 23, 0 > offset
Definition types.hh:144
Bitfield< 7, 4 > domain
Bitfield< 5, 0 > status
Bitfield< 30, 0 > index
Bitfield< 0 > p
Bitfield< 25, 21 > bo
Definition types.hh:82
Bitfield< 4 > op
Definition types.hh:83
Bitfield< 63 > val
Definition misc.hh:804
Bitfield< 20 > level
Definition intmessage.hh:51
Bitfield< 3 > addr
Definition types.hh:84
Bitfield< 7 > prot
Definition misc.hh:597
SymbolTable debugSymbolTable
Global unified debugging symbol table (for target).
Definition symtab.cc:55
ObjectFile * createObjectFile(const std::string &fname, bool raw)
Tick ns
nanosecond
Definition core.cc:68
Tick us
microsecond
Definition core.cc:67
Copyright (c) 2024 - Pranith Kumar Copyright (c) 2020 Inria All rights reserved.
Definition binary32.hh:36
SyscallReturn linkFunc(SyscallDesc *desc, ThreadContext *tc, VPtr<> pathname, VPtr<> new_pathname)
Target link() handler.
SyscallReturn getppidFunc(SyscallDesc *desc, ThreadContext *tc)
Target getppid() handler.
SyscallReturn exitGroupFunc(SyscallDesc *desc, ThreadContext *tc, int status)
Target exit_group() handler: terminate simulation. (exit all threads)
SyscallReturn gettidFunc(SyscallDesc *desc, ThreadContext *tc)
Target gettid() handler.
SyscallReturn getrandomFunc(SyscallDesc *desc, ThreadContext *tc, VPtr<> buf_ptr, typename OS::size_t count, unsigned int flags)
SyscallReturn pread64Func(SyscallDesc *desc, ThreadContext *tc, int tgt_fd, VPtr<> bufPtr, int nbytes, int offset)
SyscallReturn recvmsgFunc(SyscallDesc *desc, ThreadContext *tc, int tgt_fd, VPtr<> msgPtr, int flags)
SyscallReturn fstat64Func(SyscallDesc *desc, ThreadContext *tc, int tgt_fd, VPtr< typename OS::tgt_stat64 > tgt_stat)
Target fstat64() handler.
SyscallReturn wait4Func(SyscallDesc *desc, ThreadContext *tc, pid_t pid, VPtr<> statPtr, int options, VPtr<> rusagePtr)
SyscallReturn clock_gettimeFunc(SyscallDesc *desc, ThreadContext *tc, int clk_id, VPtr< typename OS::timespec > tp)
Target clock_gettime() function.
void warnUnsupportedOS(std::string syscall_name)
SyscallReturn brkFunc(SyscallDesc *desc, ThreadContext *tc, VPtr<> new_brk)
Target brk() handler: set brk address.
SyscallReturn mmapFunc(SyscallDesc *desc, ThreadContext *tc, VPtr<> start, typename OS::size_t length, int prot, int tgt_flags, int tgt_fd, typename OS::off_t offset)
Target mmap() handler.
SyscallReturn pipe2Func(SyscallDesc *desc, ThreadContext *tc, VPtr<> tgt_addr, int flags)
Target pipe() handler.
SyscallReturn getpidFunc(SyscallDesc *desc, ThreadContext *tc)
Target getpid() handler.
bool startswith(const char *s, const char *prefix)
Return true if 's' starts with the prefix string 'prefix'.
Definition str.hh:230
SyscallReturn chdirFunc(SyscallDesc *desc, ThreadContext *tc, VPtr<> pathname)
Target chdir() handler.
SyscallReturn fstatFunc(SyscallDesc *desc, ThreadContext *tc, int tgt_fd, VPtr< typename OS::tgt_stat > tgt_stat)
Target fstat() handler.
struct stat hst_stat
SyscallReturn truncate64Func(SyscallDesc *desc, ThreadContext *tc, VPtr<> pathname, int64_t length)
Target truncate64() handler.
SyscallReturn getuidFunc(SyscallDesc *desc, ThreadContext *tc)
SyscallReturn getrusageFunc(SyscallDesc *desc, ThreadContext *tc, int who, VPtr< typename OS::rusage > rup)
Target getrusage() function.
SyscallReturn cloneFunc(SyscallDesc *desc, ThreadContext *tc, RegVal flags, RegVal newStack, VPtr<> ptidPtr, VPtr<> ctidPtr, VPtr<> tlsPtr)
SyscallReturn readFunc(SyscallDesc *desc, ThreadContext *tc, int tgt_fd, VPtr<> buf_ptr, int nbytes)
uint64_t RegVal
Definition types.hh:173
SyscallReturn pipePseudoFunc(SyscallDesc *desc, ThreadContext *tc)
Pseudo Funcs - These functions use a different return convension, returning a second value in a regis...
SyscallReturn recvfromFunc(SyscallDesc *desc, ThreadContext *tc, int tgt_fd, VPtr<> buf_ptr, typename OS::size_t buf_len, int flags, VPtr<> addr_ptr, VPtr<> addrlen_ptr)
SyscallReturn selectFunc(SyscallDesc *desc, ThreadContext *tc, int nfds, VPtr< typename OS::fd_set > readfds, VPtr< typename OS::fd_set > writefds, VPtr< typename OS::fd_set > errorfds, VPtr< typename OS::timeval > timeout)
SyscallReturn utimesFunc(SyscallDesc *desc, ThreadContext *tc, VPtr<> pathname, VPtr< typename OS::timeval[2]> tp)
Target utimes() handler.
SyscallReturn socketFunc(SyscallDesc *desc, ThreadContext *tc, int domain, int type, int prot)
SyscallReturn chownFunc(SyscallDesc *desc, ThreadContext *tc, VPtr<> pathname, uint32_t owner, uint32_t group)
Target chown() handler.
SyscallReturn statFunc(SyscallDesc *desc, ThreadContext *tc, VPtr<> pathname, VPtr< typename OS::tgt_stat > tgt_stat)
Target stat() handler.
void copyOutStatBuf(TgtStatPtr tgt, HostStatPtr host, bool fakeTTY=false)
SyscallReturn renameImpl(SyscallDesc *desc, ThreadContext *tc, std::string old_name, std::string new_name)
SyscallReturn doClone(SyscallDesc *desc, ThreadContext *tc, RegVal flags, RegVal newStack, VPtr<> ptidPtr, VPtr<> ctidPtr, VPtr<> tlsPtr)
SyscallReturn chmodFunc(SyscallDesc *desc, ThreadContext *tc, VPtr<> pathname, mode_t mode)
Target chmod() handler.
SyscallReturn mknodImpl(SyscallDesc *desc, ThreadContext *tc, std::string path, mode_t mode, dev_t dev)
SyscallReturn renameFunc(SyscallDesc *desc, ThreadContext *tc, VPtr<> oldpath, VPtr<> newpath)
Target rename() handler.
SyscallReturn mknodFunc(SyscallDesc *desc, ThreadContext *tc, VPtr<> pathname, mode_t mode, dev_t dev)
Target mknod() handler.
SyscallReturn _llseekFunc(SyscallDesc *desc, ThreadContext *tc, int tgt_fd, uint64_t offset_high, uint32_t offset_low, VPtr<> result_ptr, int whence)
Target _llseek() handler.
Tick curTick()
The universal simulation clock.
Definition cur_tick.hh:46
SyscallReturn setTidAddressFunc(SyscallDesc *desc, ThreadContext *tc, uint64_t tidPtr)
Target set_tid_address() handler.
SyscallReturn setpgidFunc(SyscallDesc *desc, ThreadContext *tc, int pid, int pgid)
Target setpgid() handler.
SyscallReturn truncateFunc(SyscallDesc *desc, ThreadContext *tc, VPtr<> pathname, typename OS::off_t length)
Target truncate() handler.
SyscallReturn geteuidFunc(SyscallDesc *desc, ThreadContext *tc)
Target geteuid() handler.
SyscallReturn getcwdFunc(SyscallDesc *desc, ThreadContext *tc, VPtr<> buf_ptr, unsigned long size)
Target getcwd() handler.
SyscallReturn symlinkFunc(SyscallDesc *desc, ThreadContext *tc, VPtr<> pathname, VPtr<> new_pathname)
Target symlink() handler.
SyscallReturn atSyscallPath(ThreadContext *tc, int dirfd, std::string &path)
ProxyPtr< T, SETranslatingPortProxy > VPtr
Definition proxy_ptr.hh:400
SyscallReturn unlinkFunc(SyscallDesc *desc, ThreadContext *tc, VPtr<> pathname)
Target unlink() handler.
uint64_t Addr
Address type This will probably be moved somewhere else in the near future.
Definition types.hh:147
T gtoh(T value, ByteOrder guest_byte_order)
Definition byteswap.hh:194
SyscallReturn accessImpl(SyscallDesc *desc, ThreadContext *tc, std::string path, mode_t mode)
SyscallReturn sysinfoFunc(SyscallDesc *desc, ThreadContext *tc, VPtr< typename OS::tgt_sysinfo > sysinfo)
Target sysinfo() handler.
SyscallReturn fchownatFunc(SyscallDesc *desc, ThreadContext *tc, int dirfd, VPtr<> pathname, uint32_t owner, uint32_t group, int flags)
Target fchownat() handler.
SyscallReturn chownImpl(SyscallDesc *desc, ThreadContext *tc, std::string path, uint32_t owner, uint32_t group)
SyscallReturn gettimeofdayFunc(SyscallDesc *desc, ThreadContext *tc, VPtr< typename OS::timeval > tp, VPtr<> tz_ptr)
Target gettimeofday() handler.
SyscallReturn unlinkatFunc(SyscallDesc *desc, ThreadContext *tc, int dirfd, VPtr<> pathname, int flags)
Target unlinkat() handler.
SyscallReturn pipeFunc(SyscallDesc *desc, ThreadContext *tc, VPtr<> tgt_addr)
Target pipe() handler.
SyscallReturn prlimitFunc(SyscallDesc *desc, ThreadContext *tc, int pid, int resource, VPtr<> n, VPtr< typename OS::rlimit > rlp)
SyscallReturn clock_getresFunc(SyscallDesc *desc, ThreadContext *tc, int clk_id, VPtr< typename OS::timespec > tp)
Target clock_getres() function.
void copyOutStat64Buf(TgtStatPtr tgt, HostStatPtr host, bool fakeTTY=false)
SyscallReturn faccessatFunc(SyscallDesc *desc, ThreadContext *tc, int dirfd, VPtr<> pathname, int mode)
Target facessat() handler.
SyscallReturn getsockoptFunc(SyscallDesc *desc, ThreadContext *tc, int tgt_fd, int level, int optname, VPtr<> valPtr, VPtr<> lenPtr)
SyscallReturn getrlimitFunc(SyscallDesc *desc, ThreadContext *tc, unsigned resource, VPtr< typename OS::rlimit > rlp)
Target getrlimit() handler.
SyscallReturn mknodatFunc(SyscallDesc *desc, ThreadContext *tc, int dirfd, VPtr<> pathname, mode_t mode, dev_t dev)
Target mknodat() handler.
SyscallReturn fallocateFunc(SyscallDesc *desc, ThreadContext *tc, int tgt_fd, int mode, typename OS::off_t offset, typename OS::off_t len)
SyscallReturn fcntl64Func(SyscallDesc *desc, ThreadContext *tc, int tgt_fd, int cmd)
Target fcntl64() handler.
SyscallReturn futimesatFunc(SyscallDesc *desc, ThreadContext *tc, int dirfd, VPtr<> pathname, VPtr< typename OS::timeval[2]> tp)
Target futimesat() handler.
SyscallReturn ignoreWarnOnceFunc(SyscallDesc *desc, ThreadContext *tc)
Like above, but only prints a warning once per syscall desc it's used with.
SyscallReturn socketpairFunc(SyscallDesc *desc, ThreadContext *tc, int domain, int type, int prot, VPtr<> svPtr)
void copyOutStatfsBuf(TgtStatPtr tgt, HostStatPtr host)
SyscallReturn ftruncateFunc(SyscallDesc *desc, ThreadContext *tc, int tgt_fd, typename OS::off_t length)
Target ftruncate() handler.
SyscallReturn statfsFunc(SyscallDesc *desc, ThreadContext *tc, VPtr<> pathname, VPtr< typename OS::tgt_statfs > tgt_stat)
Target statfs() handler.
SyscallReturn setsockoptFunc(SyscallDesc *desc, ThreadContext *tc, int tgt_fd, int level, int optname, VPtr<> valPtr, socklen_t len)
SyscallReturn getpagesizeFunc(SyscallDesc *desc, ThreadContext *tc)
Target getpagesize() handler.
SyscallReturn lstatFunc(SyscallDesc *desc, ThreadContext *tc, VPtr<> pathname, VPtr< typename OS::tgt_stat > tgt_stat)
Target lstat() handler.
SyscallReturn rmdirFunc(SyscallDesc *desc, ThreadContext *tc, VPtr<> pathname)
SyscallReturn mkdirFunc(SyscallDesc *desc, ThreadContext *tc, VPtr<> pathname, mode_t mode)
Target mkdir() handler.
SyscallReturn readlinkatFunc(SyscallDesc *desc, ThreadContext *tc, int dirfd, VPtr<> pathname, VPtr<> buf_ptr, typename OS::size_t bufsiz)
Target readlinkat() handler.
SyscallReturn getpgrpFunc(SyscallDesc *desc, ThreadContext *tc)
Target getpgrpFunc() handler.
void copyOutStatxBuf(TgtStatPtr tgt, HostStatPtr host, bool fakeTTY=false)
SyscallReturn eventfdFunc(SyscallDesc *desc, ThreadContext *tc, unsigned initval, int in_flags)
Target eventfd() function.
SyscallReturn unlinkImpl(SyscallDesc *desc, ThreadContext *tc, std::string path)
SyscallReturn dupFunc(SyscallDesc *desc, ThreadContext *tc, int tgt_fd)
FIXME: The file description is not shared among file descriptors created with dup.
SyscallReturn listenFunc(SyscallDesc *desc, ThreadContext *tc, int tgt_fd, int backlog)
SyscallReturn ftruncate64Func(SyscallDesc *desc, ThreadContext *tc, int tgt_fd, int64_t length)
Target ftruncate64() handler.
SyscallReturn fchmodatFunc(SyscallDesc *desc, ThreadContext *tc, int dirfd, VPtr<> pathname, mode_t mode)
Target chmod() handler.
SyscallReturn openatFunc(SyscallDesc *desc, ThreadContext *tc, int tgt_dirfd, VPtr<> pathname, int tgt_flags, int mode)
Target open() handler.
SyscallReturn fchownFunc(SyscallDesc *desc, ThreadContext *tc, int tgt_fd, uint32_t owner, uint32_t group)
Target fchown() handler.
struct statfs hst_statfs
SyscallReturn munmapFunc(SyscallDesc *desc, ThreadContext *tc, VPtr<> start, typename OS::size_t length)
Target munmap() handler.
SyscallReturn readlinkFunc(SyscallDesc *desc, ThreadContext *tc, VPtr<> pathname, VPtr<> buf_ptr, typename OS::size_t bufsiz)
Target readlink() handler.
void getElapsedTimeMicro(T1 &sec, T2 &usec)
Helper function to convert current elapsed time to seconds and microseconds.
const unsigned seconds_since_epoch
Approximate seconds since the epoch (1/1/1970).
SyscallReturn timesFunc(SyscallDesc *desc, ThreadContext *tc, VPtr< typename OS::tms > bufp)
Target times() function.
SyscallReturn fcntlFunc(SyscallDesc *desc, ThreadContext *tc, int tgt_fd, int cmd, guest_abi::VarArgs< int > varargs)
Target fcntl() handler.
SyscallReturn openFunc(SyscallDesc *desc, ThreadContext *tc, VPtr<> pathname, int tgt_flags, int mode)
Target open() handler.
void getElapsedTimeNano(T1 &sec, T2 &nsec)
Helper function to convert current elapsed time to seconds and nanoseconds.
T htog(T value, ByteOrder guest_byte_order)
Definition byteswap.hh:187
SyscallReturn schedGetaffinityFunc(SyscallDesc *desc, ThreadContext *tc, pid_t pid, typename OS::size_t cpusetsize, VPtr<> cpu_set_mask)
Target sched_getaffinity.
SyscallReturn bindFunc(SyscallDesc *desc, ThreadContext *tc, int tgt_fd, VPtr<> buf_ptr, int addrlen)
SyscallReturn pollFunc(SyscallDesc *desc, ThreadContext *tc, VPtr<> fdsPtr, int nfds, int tmout)
SyscallReturn getegidFunc(SyscallDesc *desc, ThreadContext *tc)
Target getegid() handler.
SyscallReturn timeFunc(SyscallDesc *desc, ThreadContext *tc, VPtr<> taddr)
Target time() function.
SyscallReturn newfstatatFunc(SyscallDesc *desc, ThreadContext *tc, int dirfd, VPtr<> pathname, VPtr< typename OS::tgt_stat64 > tgt_stat, int flags)
Target newfstatat() handler.
SyscallReturn fchmodFunc(SyscallDesc *desc, ThreadContext *tc, int tgt_fd, uint32_t mode)
Target fchmod() handler.
SyscallReturn shutdownFunc(SyscallDesc *desc, ThreadContext *tc, int tgt_fd, int how)
Target shutdown() handler.
SyscallReturn renameatFunc(SyscallDesc *desc, ThreadContext *tc, int olddirfd, VPtr<> oldpath, int newdirfd, VPtr<> newpath)
Target renameat() handler.
SyscallReturn getcpuFunc(SyscallDesc *desc, ThreadContext *tc, VPtr< uint32_t > cpu, VPtr< uint32_t > node, VPtr< uint32_t > tcache)
SyscallReturn getsocknameFunc(SyscallDesc *desc, ThreadContext *tc, int tgt_fd, VPtr<> addrPtr, VPtr<> lenPtr)
SyscallReturn clone3Func(SyscallDesc *desc, ThreadContext *tc, VPtr< typename OS::tgt_clone_args > cl_args, RegVal size)
SyscallReturn mkdirImpl(SyscallDesc *desc, ThreadContext *tc, std::string path, mode_t mode)
SyscallReturn ioctlFunc(SyscallDesc *desc, ThreadContext *tc, int tgt_fd, unsigned req, VPtr<> addr)
Target ioctl() handler.
SyscallReturn writevFunc(SyscallDesc *desc, ThreadContext *tc, int tgt_fd, uint64_t tiov_base, typename OS::size_t count)
Target writev() handler.
SyscallReturn getpeernameFunc(SyscallDesc *desc, ThreadContext *tc, int tgt_fd, VPtr<> sockAddrPtr, VPtr<> addrlenPtr)
SyscallReturn lseekFunc(SyscallDesc *desc, ThreadContext *tc, int tgt_fd, uint64_t offs, int whence)
Target lseek() handler.
SyscallReturn unimplementedFunc(SyscallDesc *desc, ThreadContext *tc)
Handler for unimplemented syscalls that we haven't thought about.
SyscallReturn gethostnameFunc(SyscallDesc *desc, ThreadContext *tc, VPtr<> buf_ptr, int name_len)
Target gethostname() handler.
SyscallReturn accessFunc(SyscallDesc *desc, ThreadContext *tc, VPtr<> pathname, mode_t mode)
Target access() handler.
SyscallReturn tgkillFunc(SyscallDesc *desc, ThreadContext *tc, int tgid, int tid, int sig)
SyscallReturn sendmsgFunc(SyscallDesc *desc, ThreadContext *tc, int tgt_fd, VPtr<> msgPtr, int flags)
SyscallReturn cloneBackwardsFunc(SyscallDesc *desc, ThreadContext *tc, RegVal flags, RegVal newStack, VPtr<> ptidPtr, VPtr<> tlsPtr, VPtr<> ctidPtr)
SyscallReturn mremapFunc(SyscallDesc *desc, ThreadContext *tc, VPtr<> start, uint64_t old_length, uint64_t new_length, uint64_t flags, guest_abi::VarArgs< uint64_t > varargs)
Target mremap() handler.
SyscallReturn lstat64Func(SyscallDesc *desc, ThreadContext *tc, VPtr<> pathname, VPtr< typename OS::tgt_stat64 > tgt_stat)
Target lstat64() handler.
SyscallReturn pwrite64Func(SyscallDesc *desc, ThreadContext *tc, int tgt_fd, VPtr<> bufPtr, int nbytes, int offset)
SyscallReturn fstatat64Func(SyscallDesc *desc, ThreadContext *tc, int dirfd, VPtr<> pathname, VPtr< typename OS::tgt_stat64 > tgt_stat)
Target fstatat64() handler.
SyscallReturn ignoreFunc(SyscallDesc *desc, ThreadContext *tc)
Handler for unimplemented syscalls that we never intend to implement (signal handling,...
SyscallReturn rmdirImpl(SyscallDesc *desc, ThreadContext *tc, std::string path)
SyscallReturn acceptFunc(SyscallDesc *desc, ThreadContext *tc, int tgt_fd, VPtr<> addrPtr, VPtr<> lenPtr)
SyscallReturn futexFunc(SyscallDesc *desc, ThreadContext *tc, VPtr<> uaddr, int op, int val, int timeout, VPtr<> uaddr2, int val3)
Futex system call Implemented by Daniel Sanchez Used by printf's in multi-threaded apps.
SyscallReturn fstatfsFunc(SyscallDesc *desc, ThreadContext *tc, int tgt_fd, VPtr< typename OS::tgt_statfs > tgt_stat)
Target fstatfs() handler.
SyscallReturn statxFunc(SyscallDesc *desc, ThreadContext *tc, int dirfd, VPtr<> pathname, int flags, unsigned int mask, VPtr< typename OS::tgt_statx > tgt_statx)
Target statx() handler.
SyscallReturn stat64Func(SyscallDesc *desc, ThreadContext *tc, VPtr<> pathname, VPtr< typename OS::tgt_stat64 > tgt_stat)
Target stat64() handler.
struct stat64 hst_stat64
SyscallReturn connectFunc(SyscallDesc *desc, ThreadContext *tc, int tgt_fd, VPtr<> buf_ptr, int addrlen)
SyscallReturn execveFunc(SyscallDesc *desc, ThreadContext *tc, VPtr<> pathname, VPtr<> argv_mem_loc, VPtr<> envp_mem_loc)
SyscallReturn exitFunc(SyscallDesc *desc, ThreadContext *tc, int status)
Target exit() handler: terminate current context.
SyscallReturn dup2Func(SyscallDesc *desc, ThreadContext *tc, int old_tgt_fd, int new_tgt_fd)
Target dup2() handler.
SyscallReturn getgidFunc(SyscallDesc *desc, ThreadContext *tc)
Target getgid() handler.
SyscallReturn writeFunc(SyscallDesc *desc, ThreadContext *tc, int tgt_fd, VPtr<> buf_ptr, int nbytes)
SyscallReturn closeFunc(SyscallDesc *desc, ThreadContext *tc, int tgt_fd)
Target close() handler.
SyscallReturn umaskFunc(SyscallDesc *desc, ThreadContext *tc)
Target umask() handler.
SyscallReturn mmap2Func(SyscallDesc *desc, ThreadContext *tc, VPtr<> start, typename OS::size_t length, int prot, int tgt_flags, int tgt_fd, typename OS::off_t offset)
Target mmap2() handler.
SyscallReturn sendtoFunc(SyscallDesc *desc, ThreadContext *tc, int tgt_fd, VPtr<> buf_ptr, typename OS::size_t buf_len, int flags, VPtr<> addr_ptr, socklen_t addr_len)
SyscallReturn readvFunc(SyscallDesc *desc, ThreadContext *tc, int tgt_fd, uint64_t tiov_base, typename OS::size_t count)
Target readv() handler.
SyscallReturn mkdiratFunc(SyscallDesc *desc, ThreadContext *tc, int dirfd, VPtr<> pathname, mode_t mode)
Target mkdirat() handler.
Declarations of a non-full system Page Table.
#define DPRINTF_SYSCALL(FLAGEXT, FMT,...)
This macro is intended to help with readability.
This file defines buffer classes used to handle pointer arguments in emulated syscalls.

Generated on Tue Jun 18 2024 16:24:06 for gem5 by doxygen 1.11.0