gem5 v24.1.0.1
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
syscall_emul.hh
Go to the documentation of this file.
1/*
2 * Copyright (c) 2012-2013, 2015, 2019-2021, 2023-2024 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 VPtr<> 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 _llseekFunc(SyscallDesc *desc, ThreadContext *tc,
165 int tgt_fd, uint32_t offset_high,
166 uint32_t offset_low, VPtr<> result_ptr, int whence);
167
169SyscallReturn shutdownFunc(SyscallDesc *desc, ThreadContext *tc,
170 int tgt_fd, int how);
171
173SyscallReturn gethostnameFunc(SyscallDesc *desc, ThreadContext *tc,
174 VPtr<> buf_ptr, int name_len);
175
177SyscallReturn unlinkFunc(SyscallDesc *desc, ThreadContext *tc,
178 VPtr<> pathname);
179SyscallReturn unlinkImpl(SyscallDesc *desc, ThreadContext *tc,
180 std::string path);
181
183SyscallReturn linkFunc(SyscallDesc *desc, ThreadContext *tc,
184 VPtr<> pathname, VPtr<> new_pathname);
185
187SyscallReturn symlinkFunc(SyscallDesc *desc, ThreadContext *tc,
188 VPtr<> pathname, VPtr<> new_pathname);
189
191SyscallReturn mkdirFunc(SyscallDesc *desc, ThreadContext *tc,
192 VPtr<> pathname, mode_t mode);
193SyscallReturn mkdirImpl(SyscallDesc *desc, ThreadContext *tc,
194 std::string path, mode_t mode);
195
197SyscallReturn mknodFunc(SyscallDesc *desc, ThreadContext *tc,
198 VPtr<> pathname, mode_t mode, dev_t dev);
199SyscallReturn mknodImpl(SyscallDesc *desc, ThreadContext *tc,
200 std::string path, mode_t mode, dev_t dev);
201
203SyscallReturn chdirFunc(SyscallDesc *desc, ThreadContext *tc, VPtr<> pathname);
204
205// Target rmdir() handler.
206SyscallReturn rmdirFunc(SyscallDesc *desc, ThreadContext *tc,
207 VPtr<> pathname);
208SyscallReturn rmdirImpl(SyscallDesc *desc, ThreadContext *tc,
209 std::string path);
210
212SyscallReturn renameFunc(SyscallDesc *desc, ThreadContext *tc,
213 VPtr<> oldpath, VPtr<> newpath);
214SyscallReturn renameImpl(SyscallDesc *desc, ThreadContext *tc,
215 std::string oldpath, std::string newpath);
216
218SyscallReturn truncate64Func(SyscallDesc *desc, ThreadContext *tc,
219 VPtr<> pathname, int64_t length);
220
222SyscallReturn ftruncate64Func(SyscallDesc *desc, ThreadContext *tc,
223 int tgt_fd, int64_t length);
224
226SyscallReturn umaskFunc(SyscallDesc *desc, ThreadContext *tc);
227
229SyscallReturn gettidFunc(SyscallDesc *desc, ThreadContext *tc);
230
232SyscallReturn chownFunc(SyscallDesc *desc, ThreadContext *tc,
233 VPtr<> pathname, uint32_t owner, uint32_t group);
234SyscallReturn chownImpl(SyscallDesc *desc, ThreadContext *tc,
235 std::string path, uint32_t owner, uint32_t group);
236
238SyscallReturn getpgrpFunc(SyscallDesc *desc, ThreadContext *tc);
239
241SyscallReturn setpgidFunc(SyscallDesc *desc, ThreadContext *tc,
242 int pid, int pgid);
243
245SyscallReturn fchownFunc(SyscallDesc *desc, ThreadContext *tc,
246 int tgt_fd, uint32_t owner, uint32_t group);
247
249SyscallReturn dupFunc(SyscallDesc *desc, ThreadContext *tc,
250 int tgt_fd);
251
253SyscallReturn dup2Func(SyscallDesc *desc, ThreadContext *tc,
254 int old_tgt_fd, int new_tgt_fd);
255
257SyscallReturn fcntlFunc(SyscallDesc *desc, ThreadContext *tc,
258 int tgt_fd, int cmd, guest_abi::VarArgs<int> varargs);
259
261SyscallReturn fcntl64Func(SyscallDesc *desc, ThreadContext *tc,
262 int tgt_fd, int cmd);
263
265SyscallReturn pipeFunc(SyscallDesc *desc, ThreadContext *tc, VPtr<> tgt_addr);
266
268SyscallReturn pipe2Func(SyscallDesc *desc, ThreadContext *tc,
269 VPtr<> tgt_addr, int flags);
270
272SyscallReturn getpidFunc(SyscallDesc *desc, ThreadContext *tc);
273
274// Target getpeername() handler.
275SyscallReturn getpeernameFunc(SyscallDesc *desc, ThreadContext *tc,
276 int tgt_fd, VPtr<> sockAddrPtr,
277 VPtr<> addrlenPtr);
278
279// Target bind() handler.
280SyscallReturn bindFunc(SyscallDesc *desc, ThreadContext *tc,
281 int tgt_fd, VPtr<> buf_ptr, int addrlen);
282
283// Target listen() handler.
284SyscallReturn listenFunc(SyscallDesc *desc, ThreadContext *tc,
285 int tgt_fd, int backlog);
286
287// Target connect() handler.
288SyscallReturn connectFunc(SyscallDesc *desc, ThreadContext *tc,
289 int tgt_fd, VPtr<> buf_ptr, int addrlen);
290
291#if defined(SYS_getdents)
292// Target getdents() handler.
293SyscallReturn getdentsFunc(SyscallDesc *desc, ThreadContext *tc,
294 int tgt_fd, VPtr<> buf_ptr, unsigned count);
295#endif
296
297#if defined(SYS_getdents64)
298// Target getdents() handler.
299SyscallReturn getdents64Func(SyscallDesc *desc, ThreadContext *tc,
300 int tgt_fd, VPtr<> buf_ptr, unsigned count);
301#endif
302
303// Target recvmsg() handler.
304SyscallReturn recvmsgFunc(SyscallDesc *desc, ThreadContext *tc,
305 int tgt_fd, VPtr<> msgPtr, int flags);
306
307// Target sendmsg() handler.
308SyscallReturn sendmsgFunc(SyscallDesc *desc, ThreadContext *tc,
309 int tgt_fd, VPtr<> msgPtr, int flags);
310
311// Target getuid() handler.
312SyscallReturn getuidFunc(SyscallDesc *desc, ThreadContext *tc);
313
315SyscallReturn getgidFunc(SyscallDesc *desc, ThreadContext *tc);
316
318SyscallReturn getppidFunc(SyscallDesc *desc, ThreadContext *tc);
319
321SyscallReturn geteuidFunc(SyscallDesc *desc, ThreadContext *tc);
322
324SyscallReturn getegidFunc(SyscallDesc *desc, ThreadContext *tc);
325
327SyscallReturn accessFunc(SyscallDesc *desc, ThreadContext *tc,
328 VPtr<> pathname, mode_t mode);
329SyscallReturn accessImpl(SyscallDesc *desc, ThreadContext *tc,
330 std::string path, mode_t mode);
331
332// Target getsockopt() handler.
333SyscallReturn getsockoptFunc(SyscallDesc *desc, ThreadContext *tc,
334 int tgt_fd, int level, int optname,
335 VPtr<> valPtr, VPtr<> lenPtr);
336
337// Target setsockopt() handler.
338SyscallReturn setsockoptFunc(SyscallDesc *desc, ThreadContext *tc,
339 int tgt_fd, int level, int optname,
340 VPtr<> valPtr, socklen_t len);
341
342SyscallReturn getcpuFunc(SyscallDesc *desc, ThreadContext *tc,
343 VPtr<uint32_t> cpu, VPtr<uint32_t> node,
344 VPtr<uint32_t> tcache);
345
346// Target getsockname() handler.
347SyscallReturn getsocknameFunc(SyscallDesc *desc, ThreadContext *tc,
348 int tgt_fd, VPtr<> addrPtr, VPtr<> lenPtr);
349
350template <class OS>
351SyscallReturn
352atSyscallPath(ThreadContext *tc, int dirfd, std::string &path)
353{
354 // If pathname is absolute, then dirfd is ignored.
355 if (dirfd != OS::TGT_AT_FDCWD && !startswith(path, "/")) {
356 auto process = tc->getProcessPtr();
357
358 std::shared_ptr<FDEntry> fdep = ((*process->fds)[dirfd]);
359 auto ffdp = std::dynamic_pointer_cast<FileFDEntry>(fdep);
360 if (!ffdp)
361 return -EBADF;
362
363 if (path.empty())
364 path = ffdp->getFileName();
365 else
366 path = ffdp->getFileName() + "/" + path;
367 }
368
369 return 0;
370}
371
375template <class OS>
376SyscallReturn
378 VPtr<> uaddr, int op, int val, int timeout, VPtr<> uaddr2, int val3)
379{
380 auto process = tc->getProcessPtr();
381
382 /*
383 * Unsupported option that does not affect the correctness of the
384 * application. This is a performance optimization utilized by Linux.
385 */
386 op &= ~OS::TGT_FUTEX_PRIVATE_FLAG;
387 op &= ~OS::TGT_FUTEX_CLOCK_REALTIME_FLAG;
388
389 FutexMap &futex_map = tc->getSystemPtr()->futexMap;
390
391 if (OS::TGT_FUTEX_WAIT == op || OS::TGT_FUTEX_WAIT_BITSET == op) {
392 // Ensure futex system call accessed atomically.
393 BufferArg buf(uaddr, sizeof(int));
395 int mem_val = *(int*)buf.bufferPtr();
396
397 /*
398 * The value in memory at uaddr is not equal with the expected val
399 * (a different thread must have changed it before the system call was
400 * invoked). In this case, we need to throw an error.
401 */
402 if (val != mem_val)
403 return -OS::TGT_EWOULDBLOCK;
404
405 if (OS::TGT_FUTEX_WAIT == op) {
406 futex_map.suspend(uaddr, process->tgid(), tc);
407 } else {
408 futex_map.suspend_bitset(uaddr, process->tgid(), tc, val3);
409 }
410
411 return 0;
412 } else if (OS::TGT_FUTEX_WAKE == op) {
413 return futex_map.wakeup(uaddr, process->tgid(), val);
414 } else if (OS::TGT_FUTEX_WAKE_BITSET == op) {
415 return futex_map.wakeup_bitset(uaddr, process->tgid(), val3);
416 } else if (OS::TGT_FUTEX_REQUEUE == op ||
417 OS::TGT_FUTEX_CMP_REQUEUE == op) {
418
419 // Ensure futex system call accessed atomically.
420 BufferArg buf(uaddr, sizeof(int));
422 int mem_val = *(int*)buf.bufferPtr();
423 /*
424 * For CMP_REQUEUE, the whole operation is only started only if
425 * val3 is still the value of the futex pointed to by uaddr.
426 */
427 if (OS::TGT_FUTEX_CMP_REQUEUE && val3 != mem_val)
428 return -OS::TGT_EWOULDBLOCK;
429 return futex_map.requeue(uaddr, process->tgid(), val, timeout, uaddr2);
430 } else if (OS::TGT_FUTEX_WAKE_OP == op) {
431 /*
432 * The FUTEX_WAKE_OP operation is equivalent to executing the
433 * following code atomically and totally ordered with respect to
434 * other futex operations on any of the two supplied futex words:
435 *
436 * int oldval = *(int *) addr2;
437 * *(int *) addr2 = oldval op oparg;
438 * futex(addr1, FUTEX_WAKE, val, 0, 0, 0);
439 * if (oldval cmp cmparg)
440 * futex(addr2, FUTEX_WAKE, val2, 0, 0, 0);
441 *
442 * (op, oparg, cmp, cmparg are encoded in val3)
443 *
444 * +---+---+-----------+-----------+
445 * |op |cmp| oparg | cmparg |
446 * +---+---+-----------+-----------+
447 * 4 4 12 12 <== # of bits
448 *
449 * reference: http://man7.org/linux/man-pages/man2/futex.2.html
450 *
451 */
452 // get value from simulated-space
453 BufferArg buf(uaddr2, sizeof(int));
455 int oldval = *(int*)buf.bufferPtr();
456 int newval = oldval;
457 // extract op, oparg, cmp, cmparg from val3
458 int wake_cmparg = val3 & 0xfff;
459 int wake_oparg = (val3 & 0xfff000) >> 12;
460 int wake_cmp = (val3 & 0xf000000) >> 24;
461 int wake_op = (val3 & 0xf0000000) >> 28;
462 if ((wake_op & OS::TGT_FUTEX_OP_ARG_SHIFT) >> 3 == 1)
463 wake_oparg = (1 << wake_oparg);
464 wake_op &= ~OS::TGT_FUTEX_OP_ARG_SHIFT;
465 // perform operation on the value of the second futex
466 if (wake_op == OS::TGT_FUTEX_OP_SET)
467 newval = wake_oparg;
468 else if (wake_op == OS::TGT_FUTEX_OP_ADD)
469 newval += wake_oparg;
470 else if (wake_op == OS::TGT_FUTEX_OP_OR)
471 newval |= wake_oparg;
472 else if (wake_op == OS::TGT_FUTEX_OP_ANDN)
473 newval &= ~wake_oparg;
474 else if (wake_op == OS::TGT_FUTEX_OP_XOR)
475 newval ^= wake_oparg;
476 // copy updated value back to simulated-space
477 *(int*)buf.bufferPtr() = newval;
479 // perform the first wake-up
480 int woken1 = futex_map.wakeup(uaddr, process->tgid(), val);
481 int woken2 = 0;
482 // calculate the condition of the second wake-up
483 bool is_wake2 = false;
484 if (wake_cmp == OS::TGT_FUTEX_OP_CMP_EQ)
485 is_wake2 = oldval == wake_cmparg;
486 else if (wake_cmp == OS::TGT_FUTEX_OP_CMP_NE)
487 is_wake2 = oldval != wake_cmparg;
488 else if (wake_cmp == OS::TGT_FUTEX_OP_CMP_LT)
489 is_wake2 = oldval < wake_cmparg;
490 else if (wake_cmp == OS::TGT_FUTEX_OP_CMP_LE)
491 is_wake2 = oldval <= wake_cmparg;
492 else if (wake_cmp == OS::TGT_FUTEX_OP_CMP_GT)
493 is_wake2 = oldval > wake_cmparg;
494 else if (wake_cmp == OS::TGT_FUTEX_OP_CMP_GE)
495 is_wake2 = oldval >= wake_cmparg;
496 // perform the second wake-up
497 if (is_wake2)
498 woken2 = futex_map.wakeup(uaddr2, process->tgid(), timeout);
499
500 return woken1 + woken2;
501 }
502 warn("futex: op %d not implemented; ignoring.", op);
503 return -ENOSYS;
504}
505
508SyscallReturn pipePseudoFunc(SyscallDesc *desc, ThreadContext *tc);
509
510
514const unsigned seconds_since_epoch = 1000 * 1000 * 1000;
515
518template <class T1, class T2>
519void
520getElapsedTimeMicro(T1 &sec, T2 &usec)
521{
522 static const int OneMillion = 1000 * 1000;
523
524 uint64_t elapsed_usecs = curTick() / sim_clock::as_int::us;
525 sec = elapsed_usecs / OneMillion;
526 usec = elapsed_usecs % OneMillion;
527}
528
531template <class T1, class T2>
532void
533getElapsedTimeNano(T1 &sec, T2 &nsec)
534{
535 static const int OneBillion = 1000 * 1000 * 1000;
536
537 uint64_t elapsed_nsecs = curTick() / sim_clock::as_int::ns;
538 sec = elapsed_nsecs / OneBillion;
539 nsec = elapsed_nsecs % OneBillion;
540}
541
543//
544// The following emulation functions are generic, but need to be
545// templated to account for differences in types, constants, etc.
546//
548
549 typedef struct statfs hst_statfs;
550#if NO_STAT64
551 typedef struct stat hst_stat;
552 typedef struct stat hst_stat64;
553#else
554 typedef struct stat hst_stat;
555 typedef struct stat64 hst_stat64;
556#endif
557
561
562template <typename OS, typename TgtStatPtr, typename HostStatPtr>
563void
564copyOutStatBuf(TgtStatPtr tgt, HostStatPtr host, bool fakeTTY=false)
565{
566 constexpr ByteOrder bo = OS::byteOrder;
567
568 if (fakeTTY)
569 tgt->st_dev = 0xA;
570 else
571 tgt->st_dev = host->st_dev;
572 tgt->st_dev = htog(tgt->st_dev, bo);
573 tgt->st_ino = host->st_ino;
574 tgt->st_ino = htog(tgt->st_ino, bo);
575 tgt->st_mode = host->st_mode;
576 if (fakeTTY) {
577 // Claim to be a character device
578 tgt->st_mode &= ~S_IFMT; // Clear S_IFMT
579 tgt->st_mode |= S_IFCHR; // Set S_IFCHR
580 }
581 tgt->st_mode = htog(tgt->st_mode, bo);
582 tgt->st_nlink = host->st_nlink;
583 tgt->st_nlink = htog(tgt->st_nlink, bo);
584 tgt->st_uid = host->st_uid;
585 tgt->st_uid = htog(tgt->st_uid, bo);
586 tgt->st_gid = host->st_gid;
587 tgt->st_gid = htog(tgt->st_gid, bo);
588 if (fakeTTY)
589 tgt->st_rdev = 0x880d;
590 else
591 tgt->st_rdev = host->st_rdev;
592 tgt->st_rdev = htog(tgt->st_rdev, bo);
593 tgt->st_size = host->st_size;
594 tgt->st_size = htog(tgt->st_size, bo);
595 tgt->st_atimeX = host->st_atime;
596 tgt->st_atimeX = htog(tgt->st_atimeX, bo);
597 tgt->st_mtimeX = host->st_mtime;
598 tgt->st_mtimeX = htog(tgt->st_mtimeX, bo);
599 tgt->st_ctimeX = host->st_ctime;
600 tgt->st_ctimeX = htog(tgt->st_ctimeX, bo);
601 // Force the block size to be 8KB. This helps to ensure buffered io works
602 // consistently across different hosts.
603 tgt->st_blksize = 0x2000;
604 tgt->st_blksize = htog(tgt->st_blksize, bo);
605 tgt->st_blocks = host->st_blocks;
606 tgt->st_blocks = htog(tgt->st_blocks, bo);
607}
608
609// Same for stat64
610
611template <typename OS, typename TgtStatPtr, typename HostStatPtr>
612void
613copyOutStat64Buf(TgtStatPtr tgt, HostStatPtr host,
614 bool fakeTTY=false)
615{
616 copyOutStatBuf<OS>(tgt, host, fakeTTY);
617#if defined(STAT_HAVE_NSEC)
618 constexpr ByteOrder bo = OS::byteOrder;
619
620 tgt->st_atime_nsec = host->st_atime_nsec;
621 tgt->st_atime_nsec = htog(tgt->st_atime_nsec, bo);
622 tgt->st_mtime_nsec = host->st_mtime_nsec;
623 tgt->st_mtime_nsec = htog(tgt->st_mtime_nsec, bo);
624 tgt->st_ctime_nsec = host->st_ctime_nsec;
625 tgt->st_ctime_nsec = htog(tgt->st_ctime_nsec, bo);
626#else
627 tgt->st_atime_nsec = 0;
628 tgt->st_mtime_nsec = 0;
629 tgt->st_ctime_nsec = 0;
630#endif
631}
632
633template <class OS, typename TgtStatPtr, typename HostStatPtr>
634void
635copyOutStatfsBuf(TgtStatPtr tgt, HostStatPtr host)
636{
637 constexpr ByteOrder bo = OS::byteOrder;
638
639 tgt->f_type = htog(host->f_type, bo);
640#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__)
641 tgt->f_bsize = htog(host->f_iosize, bo);
642#else
643 tgt->f_bsize = htog(host->f_bsize, bo);
644#endif
645 tgt->f_blocks = htog(host->f_blocks, bo);
646 tgt->f_bfree = htog(host->f_bfree, bo);
647 tgt->f_bavail = htog(host->f_bavail, bo);
648 tgt->f_files = htog(host->f_files, bo);
649 tgt->f_ffree = htog(host->f_ffree, bo);
650 memcpy(&tgt->f_fsid, &host->f_fsid, sizeof(host->f_fsid));
651#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__)
652 tgt->f_namelen = htog(host->f_namemax, bo);
653 tgt->f_frsize = htog(host->f_bsize, bo);
654#elif defined(__APPLE__)
655 tgt->f_namelen = 0;
656 tgt->f_frsize = 0;
657#else
658 tgt->f_namelen = htog(host->f_namelen, bo);
659 tgt->f_frsize = htog(host->f_frsize, bo);
660#endif
661#if defined(__linux__)
662 memcpy(&tgt->f_spare, &host->f_spare,
663 std::min(sizeof(host->f_spare), sizeof(tgt->f_spare)));
664#else
665 /*
666 * The fields are different sizes per OS. Don't bother with
667 * f_spare or f_reserved on non-Linux for now.
668 */
669 memset(&tgt->f_spare, 0, sizeof(tgt->f_spare));
670#endif
671}
672
673template <typename OS, typename TgtStatPtr, typename HostStatPtr>
674void
675copyOutStatxBuf(TgtStatPtr tgt, HostStatPtr host, bool fakeTTY = false)
676{
677 constexpr ByteOrder bo = OS::byteOrder;
678
679 if (fakeTTY) {
680 tgt->stx_dev_major = 0x00;
681 tgt->stx_dev_minor = 0x0A;
682 } else {
683 tgt->stx_dev_major = host->st_dev >> 8;
684 tgt->stx_dev_minor = host->st_dev & 0xFF;
685 }
686 tgt->stx_dev_major = htog(tgt->stx_dev_major, bo);
687 tgt->stx_dev_minor = htog(tgt->stx_dev_minor, bo);
688 tgt->stx_ino = host->st_ino;
689 tgt->stx_ino = htog(tgt->stx_ino, bo);
690 tgt->stx_mode = host->st_mode;
691 if (fakeTTY) {
692 // Claim to be character device.
693 tgt->stx_mode &= ~S_IFMT;
694 tgt->stx_mode |= S_IFCHR;
695 }
696 tgt->stx_mode = htog(tgt->stx_mode, bo);
697 tgt->stx_nlink = host->st_nlink;
698 tgt->stx_nlink = htog(tgt->stx_nlink, bo);
699 tgt->stx_uid = host->st_uid;
700 tgt->stx_uid = htog(tgt->stx_uid, bo);
701 tgt->stx_gid = host->st_gid;
702 tgt->stx_gid = htog(tgt->stx_gid, bo);
703 if (fakeTTY) {
704 tgt->stx_rdev_major = 0x880d >> 8;
705 tgt->stx_rdev_minor = 0x880d & 0xFF;
706 } else {
707 tgt->stx_rdev_major = host->st_rdev >> 8;
708 tgt->stx_rdev_minor = host->st_rdev & 0xFF;
709 }
710 tgt->stx_rdev_major = htog(tgt->stx_rdev_major, bo);
711 tgt->stx_rdev_minor = htog(tgt->stx_rdev_minor, bo);
712 tgt->stx_size = host->st_size;
713 tgt->stx_size = htog(tgt->stx_size, bo);
714 tgt->stx_atimeX = host->st_atime;
715 tgt->stx_atimeX = htog(tgt->stx_atimeX, bo);
716 tgt->stx_ctimeX = host->st_ctime;
717 tgt->stx_ctimeX = htog(tgt->stx_ctimeX, bo);
718 tgt->stx_mtimeX = host->st_mtime;
719 tgt->stx_mtimeX = htog(tgt->stx_mtimeX, bo);
720 // Force the block size to be 8KB. This helps to ensure buffered io works
721 // consistently across different hosts.
722 tgt->stx_blksize = 0x2000;
723 tgt->stx_blksize = htog(tgt->stx_blksize, bo);
724 tgt->stx_blocks = host->st_blocks;
725 tgt->stx_blocks = htog(tgt->stx_blocks, bo);
726 tgt->stx_mask = 0x000007ffU; // STATX_BASIC_STATS on Linux.
727 tgt->stx_mask = htog(tgt->stx_mask, bo);
728 tgt->stx_attributes = 0;
729 tgt->stx_attributes_mask = 0;
730 tgt->stx_attributes_mask = htog(tgt->stx_attributes_mask, bo);
731}
732
737template <class OS>
738SyscallReturn
740 int tgt_fd, unsigned req, VPtr<> addr)
741{
742 auto p = tc->getProcessPtr();
743
744 DPRINTF_SYSCALL(Verbose, "ioctl(%d, 0x%x, ...)\n", tgt_fd, req);
745
746 if (OS::isTtyReq(req))
747 return -ENOTTY;
748
749 auto dfdp = std::dynamic_pointer_cast<DeviceFDEntry>((*p->fds)[tgt_fd]);
750 if (dfdp) {
751 EmulatedDriver *emul_driver = dfdp->getDriver();
752 if (emul_driver)
753 return emul_driver->ioctl(tc, req, addr);
754 }
755
756 auto sfdp = std::dynamic_pointer_cast<SocketFDEntry>((*p->fds)[tgt_fd]);
757 if (sfdp) {
758 int status;
759
760 switch (req) {
761 case SIOCGIFCONF: {
762 BufferArg conf_arg(addr, sizeof(ifconf));
763 conf_arg.copyIn(SETranslatingPortProxy(tc));
764
765 ifconf *conf = (ifconf*)conf_arg.bufferPtr();
766 Addr ifc_buf_addr = (Addr)conf->ifc_buf;
767 BufferArg ifc_buf_arg(ifc_buf_addr, conf->ifc_len);
768 ifc_buf_arg.copyIn(SETranslatingPortProxy(tc));
769
770 conf->ifc_buf = (char*)ifc_buf_arg.bufferPtr();
771
772 status = ioctl(sfdp->getSimFD(), req, conf_arg.bufferPtr());
773 if (status != -1) {
774 conf->ifc_buf = (char*)ifc_buf_addr;
775 ifc_buf_arg.copyOut(SETranslatingPortProxy(tc));
776 conf_arg.copyOut(SETranslatingPortProxy(tc));
777 }
778
779 return status;
780 }
781 case SIOCGIFFLAGS:
782#if defined(__linux__)
783 case SIOCGIFINDEX:
784#endif
785 case SIOCGIFNETMASK:
786 case SIOCGIFADDR:
787#if defined(__linux__)
788 case SIOCGIFHWADDR:
789#endif
790 case SIOCGIFMTU: {
791 BufferArg req_arg(addr, sizeof(ifreq));
792 req_arg.copyIn(SETranslatingPortProxy(tc));
793
794 status = ioctl(sfdp->getSimFD(), req, req_arg.bufferPtr());
795 if (status != -1)
796 req_arg.copyOut(SETranslatingPortProxy(tc));
797 return status;
798 }
799 }
800 }
801
806 warn("Unsupported ioctl call (return ENOTTY): ioctl(%d, 0x%x, ...) @ \n",
807 tgt_fd, req, tc->pcState());
808 return -ENOTTY;
809}
810
812template <class OS>
813SyscallReturn
815 int tgt_dirfd, VPtr<> pathname, int tgt_flags, int mode)
816{
817 auto p = tc->getProcessPtr();
818
823 std::string path;
824 if (!SETranslatingPortProxy(tc).tryReadString(path, pathname))
825 return -EFAULT;
826
827#ifdef __CYGWIN32__
828 int host_flags = O_BINARY;
829#else
830 int host_flags = 0;
831#endif
836 for (const auto &p: OS::openFlagTable) {
837 if (tgt_flags & p.first) {
838 tgt_flags &= ~p.first;
839 host_flags |= p.second;
840 }
841 }
842 warn_if(tgt_flags, "%s: cannot decode flags %#x", desc->name(), tgt_flags);
843
844#ifdef __CYGWIN32__
845 host_flags |= O_BINARY;
846#endif
847
860 std::string redir_path = path;
861 std::string abs_path = path;
862 if (tgt_dirfd == OS::TGT_AT_FDCWD) {
863 abs_path = p->absolutePath(path, true);
864 redir_path = p->checkPathRedirect(path);
865 } else if (!startswith(path, "/")) {
866 std::shared_ptr<FDEntry> fdep = ((*p->fds)[tgt_dirfd]);
867 auto ffdp = std::dynamic_pointer_cast<FileFDEntry>(fdep);
868 if (!ffdp)
869 return -EBADF;
870 abs_path = ffdp->getFileName() + path;
871 redir_path = p->checkPathRedirect(abs_path);
872 }
873
880 if (startswith(abs_path, "/dev/")) {
881 std::string filename = abs_path.substr(strlen("/dev/"));
882 EmulatedDriver *drv = p->findDriver(filename);
883 if (drv) {
884 DPRINTF_SYSCALL(Verbose, "%s: passing call to "
885 "driver open with path[%s]\n",
886 desc->name(), abs_path.c_str());
887 return drv->open(tc, mode, host_flags);
888 }
893 }
894
919 int sim_fd = -1;
920 std::string used_path;
921 std::vector<std::string> special_paths =
922 { "/proc/meminfo", "/system/", "/platform/", "/etc/passwd",
923 "/proc/self/maps", "/dev/urandom",
924 "/sys/devices/system/cpu/online" };
925 for (auto entry : special_paths) {
926 if (startswith(path, entry)) {
927 sim_fd = OS::openSpecialFile(abs_path, p, tc);
928 used_path = abs_path;
929 }
930 }
931 if (sim_fd == -1) {
932 sim_fd = open(redir_path.c_str(), host_flags, mode);
933 used_path = redir_path;
934 }
935 if (sim_fd == -1) {
936 int local = -errno;
937 DPRINTF_SYSCALL(Verbose, "%s: failed -> path:%s "
938 "(inferred from:%s)\n", desc->name(),
939 used_path.c_str(), path.c_str());
940 return local;
941 }
942
951 auto ffdp = std::make_shared<FileFDEntry>(sim_fd, host_flags, path, 0);
952 // Record the file mode for checkpoint restoring
953 ffdp->setFileMode(mode);
954 int tgt_fd = p->fds->allocFD(ffdp);
955 DPRINTF_SYSCALL(Verbose, "%s: sim_fd[%d], target_fd[%d] -> path:%s\n"
956 "(inferred from:%s)\n", desc->name(),
957 sim_fd, tgt_fd, used_path.c_str(), path.c_str());
958 return tgt_fd;
959}
960
962template <class OS>
963SyscallReturn
965 VPtr<> pathname, int tgt_flags, int mode)
966{
967 return openatFunc<OS>(
968 desc, tc, OS::TGT_AT_FDCWD, pathname, tgt_flags, mode);
969}
970
972template <class OS>
973SyscallReturn
975 VPtr<> buf_ptr, typename OS::size_t size)
976{
977 int result = 0;
978 auto p = tc->getProcessPtr();
979 BufferArg buf(buf_ptr, size);
980
981 // Is current working directory defined?
982 std::string cwd = p->tgtCwd;
983 if (!cwd.empty()) {
984 if (cwd.length() >= size) {
985 // Buffer too small
986 return -ERANGE;
987 }
988 strncpy((char *)buf.bufferPtr(), cwd.c_str(), size);
989 result = cwd.length();
990 } else {
991 if (getcwd((char *)buf.bufferPtr(), size)) {
992 result = strlen((char *)buf.bufferPtr());
993 } else {
994 result = -1;
995 }
996 }
997
999
1000 return (result == -1) ? -errno : result;
1001}
1002
1004template <class OS>
1005SyscallReturn
1007 int tgt_fd, typename OS::off_t offs, int whence)
1008{
1009 auto p = tc->getProcessPtr();
1010
1011 auto ffdp = std::dynamic_pointer_cast<FileFDEntry>((*p->fds)[tgt_fd]);
1012 if (!ffdp)
1013 return -EBADF;
1014 int sim_fd = ffdp->getSimFD();
1015
1016 off_t result = lseek(sim_fd, offs, whence);
1017
1018 return (result == (off_t)-1) ? -errno : result;
1019}
1020
1022template <class OS>
1023SyscallReturn
1025 int dirfd, VPtr<> pathname, int flags)
1026{
1027 std::string path;
1028 if (!SETranslatingPortProxy(tc).tryReadString(path, pathname))
1029 return -EFAULT;
1030
1031 // Modifying path from the directory descriptor
1032 if (auto res = atSyscallPath<OS>(tc, dirfd, path); !res.successful()) {
1033 return res;
1034 }
1035
1036 if (flags & OS::TGT_AT_REMOVEDIR) {
1037 return rmdirImpl(desc, tc, path);
1038 } else {
1039 return unlinkImpl(desc, tc, path);
1040 }
1041}
1042
1044template <class OS>
1045SyscallReturn
1047 int dirfd, VPtr<> pathname, int mode)
1048{
1049 std::string path;
1050 if (!SETranslatingPortProxy(tc).tryReadString(path, pathname))
1051 return -EFAULT;
1052
1053 // Modifying path from the directory descriptor
1054 if (auto res = atSyscallPath<OS>(tc, dirfd, path); !res.successful()) {
1055 return res;
1056 }
1057
1058 return accessImpl(desc, tc, path, mode);
1059}
1060
1062template <class OS>
1063SyscallReturn
1065 int dirfd, VPtr<> pathname, VPtr<> buf_ptr,
1066 typename OS::size_t bufsiz)
1067{
1068 std::string path;
1069 if (!SETranslatingPortProxy(tc).tryReadString(path, pathname))
1070 return -EFAULT;
1071
1072 // Modifying path from the directory descriptor
1073 if (auto res = atSyscallPath<OS>(tc, dirfd, path); !res.successful()) {
1074 return res;
1075 }
1076
1077 auto p = tc->getProcessPtr();
1078
1079 // Adjust path for cwd and redirection
1080 path = p->checkPathRedirect(path);
1081
1082 BufferArg buf(buf_ptr, bufsiz);
1083
1084 int result = -1;
1085 if (path != "/proc/self/exe") {
1086 result = readlink(path.c_str(), (char *)buf.bufferPtr(), bufsiz);
1087 } else {
1088 // Emulate readlink() called on '/proc/self/exe' should return the
1089 // absolute path of the binary running in the simulated system (the
1090 // Process' executable). It is possible that using this path in
1091 // the simulated system will result in unexpected behavior if:
1092 // 1) One binary runs another (e.g., -c time -o "my_binary"), and
1093 // called binary calls readlink().
1094 // 2) The host's full path to the running benchmark changes from one
1095 // simulation to another. This can result in different simulated
1096 // performance since the simulated system will process the binary
1097 // path differently, even if the binary itself does not change.
1098
1099 // Get the absolute canonical path to the running application
1100 char real_path[PATH_MAX];
1101 char *check_real_path = realpath(p->progName(), real_path);
1102 if (!check_real_path) {
1103 fatal("readlink('/proc/self/exe') unable to resolve path to "
1104 "executable: %s", p->progName());
1105 }
1106 strncpy((char*)buf.bufferPtr(), real_path, bufsiz);
1107 typename OS::size_t real_path_len = strlen(real_path);
1108 if (real_path_len > bufsiz) {
1109 // readlink will truncate the contents of the
1110 // path to ensure it is no more than bufsiz
1111 result = bufsiz;
1112 } else {
1113 result = real_path_len;
1114 }
1115
1116 // Issue a warning about potential unexpected results
1117 warn_once("readlink() called on '/proc/self/exe' may yield unexpected "
1118 "results in various settings.\n Returning '%s'\n",
1119 (char*)buf.bufferPtr());
1120 }
1121
1123
1124 return (result == -1) ? -errno : result;
1125}
1126
1128template <class OS>
1129SyscallReturn
1131 VPtr<> pathname, VPtr<> buf_ptr,
1132 typename OS::size_t bufsiz)
1133{
1134 return readlinkatFunc<OS>(desc, tc, OS::TGT_AT_FDCWD,
1135 pathname, buf_ptr, bufsiz);
1136}
1137
1139template <class OS>
1140SyscallReturn
1142 int olddirfd, VPtr<> oldpath, int newdirfd, VPtr<> newpath)
1143{
1144 SETranslatingPortProxy proxy(tc);
1145 std::string old_name;
1146 if (!proxy.tryReadString(old_name, oldpath))
1147 return -EFAULT;
1148
1149 std::string new_name;
1150 if (!proxy.tryReadString(new_name, newpath))
1151 return -EFAULT;
1152
1153 // Modifying old_name from the directory descriptor
1154 if (auto res = atSyscallPath<OS>(tc, olddirfd, old_name); !res.successful()) {
1155 return res;
1156 }
1157
1158 // Modifying new_name from the directory descriptor
1159 if (auto res = atSyscallPath<OS>(tc, newdirfd, new_name); !res.successful()) {
1160 return res;
1161 }
1162
1163 return renameImpl(desc, tc, old_name, new_name);
1164}
1165
1167template <class OS>
1168SyscallReturn
1170 int dirfd, VPtr<> pathname, uint32_t owner, uint32_t group,
1171 int flags)
1172{
1173 std::string path;
1174 if (!SETranslatingPortProxy(tc).tryReadString(path, pathname))
1175 return -EFAULT;
1176
1177 // Modifying path from the directory descriptor
1178 if (auto res = atSyscallPath<OS>(tc, dirfd, path); !res.successful()) {
1179 return res;
1180 }
1181
1182 return chownImpl(desc, tc, path, owner, group);
1183}
1184
1186template <class OS>
1187SyscallReturn
1189 int dirfd, VPtr<> pathname, mode_t mode)
1190{
1191 std::string path;
1192 if (!SETranslatingPortProxy(tc).tryReadString(path, pathname))
1193 return -EFAULT;
1194
1195 // Modifying path from the directory descriptor
1196 if (auto res = atSyscallPath<OS>(tc, dirfd, path); !res.successful()) {
1197 return res;
1198 }
1199
1200 return mkdirImpl(desc, tc, path, mode);
1201}
1202
1204template <class OS>
1205SyscallReturn
1207 int dirfd, VPtr<> pathname, mode_t mode, dev_t dev)
1208{
1209 std::string path;
1210 if (!SETranslatingPortProxy(tc).tryReadString(path, pathname))
1211 return -EFAULT;
1212
1213 // Modifying path from the directory descriptor
1214 if (auto res = atSyscallPath<OS>(tc, dirfd, path); !res.successful()) {
1215 return res;
1216 }
1217
1218 return mknodImpl(desc, tc, path, mode, dev);
1219}
1220
1222template <class OS>
1223SyscallReturn
1226{
1227 auto process = tc->getProcessPtr();
1228
1229 sysinfo->uptime = seconds_since_epoch;
1230 sysinfo->totalram = process->system->memSize();
1231 sysinfo->mem_unit = 1;
1232
1233 return 0;
1234}
1235
1237template <class OS>
1238SyscallReturn
1240 int dirfd, VPtr<> pathname, mode_t mode)
1241{
1242 std::string path;
1243 if (!SETranslatingPortProxy(tc).tryReadString(path, pathname))
1244 return -EFAULT;
1245
1246 // Modifying path from the directory descriptor
1247 if (auto res = atSyscallPath<OS>(tc, dirfd, path); !res.successful()) {
1248 return res;
1249 }
1250
1251 mode_t hostMode = 0;
1252
1253 // XXX translate mode flags via OS::something???
1254 hostMode = mode;
1255
1256 auto process = tc->getProcessPtr();
1257 // Adjust path for cwd and redirection
1258 path = process->checkPathRedirect(path);
1259
1260 // do the chmod
1261 int result = chmod(path.c_str(), hostMode);
1262 if (result < 0)
1263 return -errno;
1264
1265 return 0;
1266}
1267
1269template <class OS>
1270SyscallReturn
1271chmodFunc(SyscallDesc *desc, ThreadContext *tc, VPtr<> pathname, mode_t mode)
1272{
1273 return fchmodatFunc<OS>(desc, tc, OS::TGT_AT_FDCWD, pathname, mode);
1274}
1275
1276template <class OS>
1277SyscallReturn
1279 VPtr<> fdsPtr, int nfds, int tmout)
1280{
1281 auto p = tc->getProcessPtr();
1282
1283 BufferArg fdsBuf(fdsPtr, sizeof(struct pollfd) * nfds);
1284 fdsBuf.copyIn(SETranslatingPortProxy(tc));
1285
1292 int temp_tgt_fds[nfds];
1293 for (int index = 0; index < nfds; index++) {
1294 temp_tgt_fds[index] = ((struct pollfd *)fdsBuf.bufferPtr())[index].fd;
1295 auto tgt_fd = temp_tgt_fds[index];
1296 auto hbfdp = std::dynamic_pointer_cast<HBFDEntry>((*p->fds)[tgt_fd]);
1297 if (!hbfdp)
1298 return -EBADF;
1299 auto host_fd = hbfdp->getSimFD();
1300 ((struct pollfd *)fdsBuf.bufferPtr())[index].fd = host_fd;
1301 }
1302
1309 int status;
1310 if (tmout < 0) {
1311 status = poll((struct pollfd *)fdsBuf.bufferPtr(), nfds, 0);
1312 if (status == 0) {
1318 System *sysh = tc->getSystemPtr();
1320 for (it=sysh->signalList.begin(); it!=sysh->signalList.end(); it++)
1321 if (it->receiver == p)
1322 return -EINTR;
1323 return SyscallReturn::retry();
1324 }
1325 } else
1326 status = poll((struct pollfd *)fdsBuf.bufferPtr(), nfds, 0);
1327
1328 if (status == -1)
1329 return -errno;
1330
1335 for (int index = 0; index < nfds; index++) {
1336 auto tgt_fd = temp_tgt_fds[index];
1337 ((struct pollfd *)fdsBuf.bufferPtr())[index].fd = tgt_fd;
1338 }
1339
1344 fdsBuf.copyOut(SETranslatingPortProxy(tc));
1345
1346 return status;
1347}
1348
1350template <class OS>
1351SyscallReturn
1352fchmodFunc(SyscallDesc *desc, ThreadContext *tc, int tgt_fd, uint32_t mode)
1353{
1354 auto p = tc->getProcessPtr();
1355
1356 auto ffdp = std::dynamic_pointer_cast<FileFDEntry>((*p->fds)[tgt_fd]);
1357 if (!ffdp)
1358 return -EBADF;
1359 int sim_fd = ffdp->getSimFD();
1360
1361 mode_t hostMode = mode;
1362
1363 int result = fchmod(sim_fd, hostMode);
1364
1365 return (result < 0) ? -errno : 0;
1366}
1367
1369template <class OS>
1370SyscallReturn
1372 VPtr<> start, typename OS::size_t old_length,
1373 typename OS::size_t new_length, int flags,
1375{
1376 auto p = tc->getProcessPtr();
1377 Addr page_bytes = p->pTable->pageSize();
1378 uint64_t provided_address = 0;
1379 bool use_provided_address = flags & OS::TGT_MREMAP_FIXED;
1380
1381 if (use_provided_address)
1382 provided_address = varargs.get<uint64_t>();
1383
1384 if ((start % page_bytes != 0) ||
1385 (provided_address % page_bytes != 0)) {
1386 warn("mremap failing: arguments not page aligned");
1387 return -EINVAL;
1388 }
1389
1390 new_length = roundUp(new_length, page_bytes);
1391
1392 if (new_length > old_length) {
1393 Addr mmap_end = p->memState->getMmapEnd();
1394
1395 if ((start + old_length) == mmap_end &&
1396 (!use_provided_address || provided_address == start)) {
1397 // This case cannot occur when growing downward, as
1398 // start is greater than or equal to mmap_end.
1399 uint64_t diff = new_length - old_length;
1400 p->memState->mapRegion(mmap_end, diff, "remapped");
1401 p->memState->setMmapEnd(mmap_end + diff);
1402 return (Addr)start;
1403 } else {
1404 if (!use_provided_address && !(flags & OS::TGT_MREMAP_MAYMOVE)) {
1405 warn("can't remap here and MREMAP_MAYMOVE flag not set\n");
1406 return -ENOMEM;
1407 } else {
1408 uint64_t new_start = provided_address;
1409 if (!use_provided_address) {
1410 new_start = p->mmapGrowsDown() ?
1411 mmap_end - new_length : mmap_end;
1412 mmap_end = p->mmapGrowsDown() ?
1413 new_start : mmap_end + new_length;
1414 p->memState->setMmapEnd(mmap_end);
1415 }
1416
1417 warn("mremapping to new vaddr %08p-%08p, adding %d\n",
1418 new_start, new_start + new_length,
1419 new_length - old_length);
1420
1421 // add on the remaining unallocated pages
1422 p->allocateMem(new_start + old_length,
1423 new_length - old_length,
1424 use_provided_address /* clobber */);
1425
1426 if (use_provided_address &&
1427 ((new_start + new_length > p->memState->getMmapEnd() &&
1428 !p->mmapGrowsDown()) ||
1429 (new_start < p->memState->getMmapEnd() &&
1430 p->mmapGrowsDown()))) {
1431 // something fishy going on here, at least notify the user
1432 // @todo: increase mmap_end?
1433 warn("mmap region limit exceeded with MREMAP_FIXED\n");
1434 }
1435
1436 warn("returning %08p as start\n", new_start);
1437 p->memState->remapRegion(start, new_start, old_length);
1438 return new_start;
1439 }
1440 }
1441 } else {
1442 // Shrink a region
1443 if (use_provided_address && provided_address != start)
1444 p->memState->remapRegion(start, provided_address, new_length);
1445 if (new_length != old_length)
1446 p->memState->unmapRegion(start + new_length,
1447 old_length - new_length);
1448 return use_provided_address ? provided_address : (Addr)start;
1449 }
1450}
1451
1453template <class OS>
1454SyscallReturn
1456 VPtr<> pathname, VPtr<typename OS::tgt_stat> tgt_stat)
1457{
1458 std::string path;
1459 auto process = tc->getProcessPtr();
1460
1461 if (!SETranslatingPortProxy(tc).tryReadString(path, pathname))
1462 return -EFAULT;
1463
1464 // Adjust path for cwd and redirection
1465 path = process->checkPathRedirect(path);
1466
1467 struct stat hostBuf;
1468 int result = stat(path.c_str(), &hostBuf);
1469
1470 if (result < 0)
1471 return -errno;
1472
1473 copyOutStatBuf<OS>(tgt_stat, &hostBuf);
1474
1475 return 0;
1476}
1477
1479template <class OS>
1480SyscallReturn
1482 VPtr<> pathname, VPtr<typename OS::tgt_stat64> tgt_stat,
1483 int flags)
1484{
1485 std::string path;
1486
1487 if (!SETranslatingPortProxy(tc).tryReadString(path, pathname))
1488 return -EFAULT;
1489
1490 if (path.empty() && !(flags & OS::TGT_AT_EMPTY_PATH))
1491 return -ENOENT;
1492 flags = flags & ~OS::TGT_AT_EMPTY_PATH;
1493
1494 warn_if(flags != 0, "newfstatat: Flag bits %#x not supported.", flags);
1495
1496 // Modifying path from the directory descriptor
1497 if (auto res = atSyscallPath<OS>(tc, dirfd, path); !res.successful()) {
1498 return res;
1499 }
1500
1501 auto p = tc->getProcessPtr();
1502
1503 // Adjust path for cwd and redirection
1504 path = p->checkPathRedirect(path);
1505
1506 struct stat host_buf;
1507 int result = stat(path.c_str(), &host_buf);
1508
1509 if (result < 0)
1510 return -errno;
1511
1512 copyOutStat64Buf<OS>(tgt_stat, &host_buf);
1513
1514 return 0;
1515}
1516
1518template <class OS>
1519SyscallReturn
1521 int dirfd, VPtr<> pathname,
1523{
1524 std::string path;
1525 if (!SETranslatingPortProxy(tc).tryReadString(path, pathname))
1526 return -EFAULT;
1527
1528 // Modifying path from the directory descriptor
1529 if (auto res = atSyscallPath<OS>(tc, dirfd, path); !res.successful()) {
1530 return res;
1531 }
1532
1533 auto p = tc->getProcessPtr();
1534
1535 // Adjust path for cwd and redirection
1536 path = p->checkPathRedirect(path);
1537
1538#if NO_STAT64
1539 struct stat hostBuf;
1540 int result = stat(path.c_str(), &hostBuf);
1541#else
1542 struct stat64 hostBuf;
1543 int result = stat64(path.c_str(), &hostBuf);
1544#endif
1545
1546 if (result < 0)
1547 return -errno;
1548
1549 copyOutStat64Buf<OS>(tgt_stat, &hostBuf);
1550
1551 return 0;
1552}
1553
1555template <class OS>
1556SyscallReturn
1558 VPtr<> pathname, VPtr<typename OS::tgt_stat64> tgt_stat)
1559{
1560 return fstatat64Func<OS>(desc, tc, OS::TGT_AT_FDCWD, pathname, tgt_stat);
1561}
1562
1564template <class OS>
1565SyscallReturn
1567 int dirfd, VPtr<> pathname, int flags,
1568 unsigned int mask, VPtr<typename OS::tgt_statx> tgt_statx)
1569{
1570 std::string path;
1571
1572 if (!SETranslatingPortProxy(tc).tryReadString(path, pathname))
1573 return -EFAULT;
1574
1575 if (path.empty() && !(flags & OS::TGT_AT_EMPTY_PATH))
1576 return -ENOENT;
1577 flags = flags & ~OS::TGT_AT_EMPTY_PATH;
1578
1579 warn_if(flags != 0, "statx: Flag bits %#x not supported.", flags);
1580
1581 // Modifying path from the directory descriptor
1582 if (auto res = atSyscallPath<OS>(tc, dirfd, path); !res.successful()) {
1583 return res;
1584 }
1585
1586 auto p = tc->getProcessPtr();
1587
1588 // Adjust path for cwd and redirection
1589 path = p->checkPathRedirect(path);
1590
1591 struct stat host_buf;
1592 int result = stat(path.c_str(), &host_buf);
1593
1594 if (result < 0)
1595 return -errno;
1596
1597 copyOutStatxBuf<OS>(tgt_statx, &host_buf);
1598
1599 return 0;
1600}
1601
1603template <class OS>
1604SyscallReturn
1606 int tgt_fd, VPtr<typename OS::tgt_stat64> tgt_stat)
1607{
1608 auto p = tc->getProcessPtr();
1609
1610 auto ffdp = std::dynamic_pointer_cast<HBFDEntry>((*p->fds)[tgt_fd]);
1611 if (!ffdp)
1612 return -EBADF;
1613 int sim_fd = ffdp->getSimFD();
1614
1615#if NO_STAT64
1616 struct stat hostBuf;
1617 int result = fstat(sim_fd, &hostBuf);
1618#else
1619 struct stat64 hostBuf;
1620 int result = fstat64(sim_fd, &hostBuf);
1621#endif
1622
1623 if (result < 0)
1624 return -errno;
1625
1626 copyOutStat64Buf<OS>(tgt_stat, &hostBuf, (sim_fd == 1));
1627
1628 return 0;
1629}
1630
1631
1633template <class OS>
1634SyscallReturn
1636 VPtr<> pathname, VPtr<typename OS::tgt_stat> tgt_stat)
1637{
1638 std::string path;
1639 auto process = tc->getProcessPtr();
1640
1641 if (!SETranslatingPortProxy(tc).tryReadString(path, pathname))
1642 return -EFAULT;
1643
1644 // Adjust path for cwd and redirection
1645 path = process->checkPathRedirect(path);
1646
1647 struct stat hostBuf;
1648 int result = lstat(path.c_str(), &hostBuf);
1649
1650 if (result < 0)
1651 return -errno;
1652
1653 copyOutStatBuf<OS>(tgt_stat, &hostBuf);
1654
1655 return 0;
1656}
1657
1659template <class OS>
1660SyscallReturn
1662 VPtr<> pathname, VPtr<typename OS::tgt_stat64> tgt_stat)
1663{
1664 std::string path;
1665 auto process = tc->getProcessPtr();
1666
1667 if (!SETranslatingPortProxy(tc).tryReadString(path, pathname))
1668 return -EFAULT;
1669
1670 // Adjust path for cwd and redirection
1671 path = process->checkPathRedirect(path);
1672
1673#if NO_STAT64
1674 struct stat hostBuf;
1675 int result = lstat(path.c_str(), &hostBuf);
1676#else
1677 struct stat64 hostBuf;
1678 int result = lstat64(path.c_str(), &hostBuf);
1679#endif
1680
1681 if (result < 0)
1682 return -errno;
1683
1684 copyOutStat64Buf<OS>(tgt_stat, &hostBuf);
1685
1686 return 0;
1687}
1688
1690template <class OS>
1691SyscallReturn
1693 int tgt_fd, VPtr<typename OS::tgt_stat> tgt_stat)
1694{
1695 auto p = tc->getProcessPtr();
1696
1697 DPRINTF_SYSCALL(Verbose, "fstat(%d, ...)\n", tgt_fd);
1698
1699 auto ffdp = std::dynamic_pointer_cast<FileFDEntry>((*p->fds)[tgt_fd]);
1700 if (!ffdp)
1701 return -EBADF;
1702 int sim_fd = ffdp->getSimFD();
1703
1704 struct stat hostBuf;
1705 int result = fstat(sim_fd, &hostBuf);
1706
1707 if (result < 0)
1708 return -errno;
1709
1710 copyOutStatBuf<OS>(tgt_stat, &hostBuf, (sim_fd == 1));
1711
1712 return 0;
1713}
1714
1716template <class OS>
1717SyscallReturn
1719 VPtr<> pathname, VPtr<typename OS::tgt_statfs> tgt_stat)
1720{
1721#if defined(__linux__)
1722 std::string path;
1723 auto process = tc->getProcessPtr();
1724
1725 if (!SETranslatingPortProxy(tc).tryReadString(path, pathname))
1726 return -EFAULT;
1727
1728 // Adjust path for cwd and redirection
1729 path = process->checkPathRedirect(path);
1730
1731 struct statfs hostBuf;
1732 int result = statfs(path.c_str(), &hostBuf);
1733
1734 if (result < 0)
1735 return -errno;
1736
1737 copyOutStatfsBuf<OS>(tgt_stat, &hostBuf);
1738 return 0;
1739#else
1740 warnUnsupportedOS("statfs");
1741 return -1;
1742#endif
1743}
1744
1745template <class OS>
1746SyscallReturn
1748 VPtr<> ptidPtr, VPtr<> ctidPtr, VPtr<> tlsPtr)
1749{
1750 DPRINTF(SyscallVerbose, "Doing clone. pid: %#llx, ctid: %#llx, tls: %#llx"
1751 " flags: %#llx, stack: %#llx\n",
1752 ptidPtr.addr(), ctidPtr.addr(), tlsPtr.addr(), flags, newStack);
1753 auto p = tc->getProcessPtr();
1754
1755 if (((flags & OS::TGT_CLONE_SIGHAND)&& !(flags & OS::TGT_CLONE_VM)) ||
1756 ((flags & OS::TGT_CLONE_THREAD) && !(flags & OS::TGT_CLONE_SIGHAND)) ||
1757 ((flags & OS::TGT_CLONE_FS) && (flags & OS::TGT_CLONE_NEWNS)) ||
1758 ((flags & OS::TGT_CLONE_NEWIPC) && (flags & OS::TGT_CLONE_SYSVSEM)) ||
1759 ((flags & OS::TGT_CLONE_NEWPID) && (flags & OS::TGT_CLONE_THREAD)) ||
1760 ((flags & OS::TGT_CLONE_VM) && !(newStack)))
1761 return -EINVAL;
1762
1763 ThreadContext *ctc;
1764 if (!(ctc = tc->getSystemPtr()->threads.findFree())) {
1765 DPRINTF_SYSCALL(Verbose, "clone: no spare thread context in system"
1766 "[cpu %d, thread %d]", tc->cpuId(), tc->threadId());
1767 return -EAGAIN;
1768 }
1769
1776 ProcessParams *pp = new ProcessParams();
1777 pp->executable.assign(*(new std::string(p->progName())));
1778 pp->cmd.push_back(*(new std::string(p->progName())));
1779 pp->system = p->system;
1780 pp->cwd.assign(p->tgtCwd);
1781 pp->input.assign("stdin");
1782 pp->output.assign("stdout");
1783 pp->errout.assign("stderr");
1784 pp->uid = p->uid();
1785 pp->euid = p->euid();
1786 pp->gid = p->gid();
1787 pp->egid = p->egid();
1788 pp->release = p->release;
1789
1790 /* Find the first free PID that's less than the maximum */
1791 std::set<int> const& pids = p->system->PIDs;
1792 int temp_pid = *pids.begin();
1793 do {
1794 temp_pid++;
1795 } while (pids.find(temp_pid) != pids.end());
1796 if (temp_pid >= System::maxPID)
1797 fatal("temp_pid is too large: %d", temp_pid);
1798
1799 pp->pid = temp_pid;
1800 pp->ppid = (flags & OS::TGT_CLONE_THREAD) ? p->ppid() : p->pid();
1801 pp->useArchPT = p->useArchPT;
1802 pp->kvmInSE = p->kvmInSE;
1803 Process *cp = pp->create();
1804 // TODO: there is no way to know when the Process SimObject is done with
1805 // the params pointer. Both the params pointer (pp) and the process
1806 // pointer (cp) are normally managed in python and are never cleaned up.
1807
1808 Process *owner = ctc->getProcessPtr();
1809 ctc->setProcessPtr(cp);
1810 cp->assignThreadContext(ctc->contextId());
1811 owner->revokeThreadContext(ctc->contextId());
1812
1813 if (flags & OS::TGT_CLONE_PARENT_SETTID) {
1814 BufferArg ptidBuf(ptidPtr, sizeof(long));
1815 long *ptid = (long *)ptidBuf.bufferPtr();
1816 *ptid = cp->pid();
1817 ptidBuf.copyOut(SETranslatingPortProxy(tc));
1818 }
1819
1820 if (flags & OS::TGT_CLONE_THREAD) {
1821 cp->pTable->initState();
1822 cp->pTable->shared = true;
1823 cp->useForClone = true;
1824 }
1825
1826 ctc->setUseForClone(true);
1827 cp->initState();
1828 p->clone(tc, ctc, cp, flags);
1829
1830 if (flags & OS::TGT_CLONE_THREAD) {
1831 delete cp->sigchld;
1832 cp->sigchld = p->sigchld;
1833 } else if (flags & OS::TGT_SIGCHLD) {
1834 *cp->sigchld = true;
1835 }
1836
1837 if (flags & OS::TGT_CLONE_CHILD_SETTID) {
1838 BufferArg ctidBuf(ctidPtr, sizeof(long));
1839 long *ctid = (long *)ctidBuf.bufferPtr();
1840 *ctid = cp->pid();
1841 ctidBuf.copyOut(SETranslatingPortProxy(ctc));
1842 }
1843
1844 if (flags & OS::TGT_CLONE_CHILD_CLEARTID)
1845 cp->childClearTID = (uint64_t)ctidPtr;
1846
1847 ctc->clearArchRegs();
1848
1849 OS::archClone(flags, p, cp, tc, ctc, newStack, tlsPtr);
1850
1851 desc->returnInto(ctc, 0);
1852
1853 ctc->activate();
1854
1855 if (flags & OS::TGT_CLONE_VFORK) {
1856 tc->suspend();
1857 }
1858
1859 return cp->pid();
1860}
1861
1862template <class OS>
1863SyscallReturn
1866{
1867 VPtr<uint64_t> ptidPtr((Addr)cl_args->parent_tid, tc);
1868 VPtr<uint64_t> ctidPtr((Addr)cl_args->child_tid, tc);
1869 VPtr<uint64_t> tlsPtr((Addr)cl_args->tls, tc);
1870 // Clone3 gives the stack as the *lowest* address, but clone/__clone2
1871 // expects the stack parameter to be the actual stack pointer
1872 uint64_t new_stack = cl_args->stack + cl_args->stack_size;
1873 uint64_t flags = cl_args->flags;
1874
1875 return doClone<OS>(desc, tc, flags, new_stack, ptidPtr, ctidPtr, tlsPtr);
1876}
1877
1878template <class OS>
1879SyscallReturn
1881 VPtr<> ptidPtr, VPtr<> ctidPtr, VPtr<> tlsPtr)
1882{
1883 return doClone<OS>(desc, tc, flags, newStack, ptidPtr, ctidPtr, tlsPtr);
1884}
1885
1886template <class OS>
1887SyscallReturn
1889 RegVal newStack, VPtr<> ptidPtr, VPtr<> tlsPtr,
1890 VPtr<> ctidPtr)
1891{
1892 return cloneFunc<OS>(desc, tc, flags, newStack, ptidPtr, ctidPtr, tlsPtr);
1893}
1894
1896template <class OS>
1897SyscallReturn
1899 int tgt_fd, VPtr<typename OS::tgt_statfs> tgt_stat)
1900{
1901 auto p = tc->getProcessPtr();
1902
1903 auto ffdp = std::dynamic_pointer_cast<FileFDEntry>((*p->fds)[tgt_fd]);
1904 if (!ffdp)
1905 return -EBADF;
1906 int sim_fd = ffdp->getSimFD();
1907
1908 struct statfs hostBuf;
1909 int result = fstatfs(sim_fd, &hostBuf);
1910
1911 if (result < 0)
1912 return -errno;
1913
1914 copyOutStatfsBuf<OS>(tgt_stat, &hostBuf);
1915
1916 return 0;
1917}
1918
1920template <class OS>
1921SyscallReturn
1923 int tgt_fd, VPtr<> tiov_base,
1924 typename OS::size_t count)
1925{
1926 auto p = tc->getProcessPtr();
1927
1928 auto ffdp = std::dynamic_pointer_cast<FileFDEntry>((*p->fds)[tgt_fd]);
1929 if (!ffdp)
1930 return -EBADF;
1931 int sim_fd = ffdp->getSimFD();
1932
1933 SETranslatingPortProxy prox(tc);
1934 typename OS::tgt_iovec tiov[count];
1935 struct iovec hiov[count];
1936 for (typename OS::size_t i = 0; i < count; ++i) {
1937 prox.readBlob(tiov_base + (i * sizeof(typename OS::tgt_iovec)),
1938 &tiov[i], sizeof(typename OS::tgt_iovec));
1939 hiov[i].iov_len = gtoh(tiov[i].iov_len, OS::byteOrder);
1940 hiov[i].iov_base = new char [hiov[i].iov_len];
1941 }
1942
1943 int result = readv(sim_fd, hiov, count);
1944 int local_errno = errno;
1945
1946 for (typename OS::size_t i = 0; i < count; ++i) {
1947 if (result != -1) {
1948 prox.writeBlob(htog(tiov[i].iov_base, OS::byteOrder),
1949 hiov[i].iov_base, hiov[i].iov_len);
1950 }
1951 delete [] (char *)hiov[i].iov_base;
1952 }
1953
1954 return (result == -1) ? -local_errno : result;
1955}
1956
1958template <class OS>
1959SyscallReturn
1961 int tgt_fd, VPtr<> tiov_base,
1962 typename OS::size_t count)
1963{
1964 auto p = tc->getProcessPtr();
1965
1966 auto hbfdp = std::dynamic_pointer_cast<HBFDEntry>((*p->fds)[tgt_fd]);
1967 if (!hbfdp)
1968 return -EBADF;
1969 int sim_fd = hbfdp->getSimFD();
1970
1971 SETranslatingPortProxy prox(tc);
1972 struct iovec hiov[count];
1973 for (typename OS::size_t i = 0; i < count; ++i) {
1974 typename OS::tgt_iovec tiov;
1975
1976 prox.readBlob(tiov_base + i*sizeof(typename OS::tgt_iovec),
1977 &tiov, sizeof(typename OS::tgt_iovec));
1978 hiov[i].iov_len = gtoh(tiov.iov_len, OS::byteOrder);
1979 hiov[i].iov_base = new char [hiov[i].iov_len];
1980 prox.readBlob(gtoh(tiov.iov_base, OS::byteOrder), hiov[i].iov_base,
1981 hiov[i].iov_len);
1982 }
1983
1984 int result = writev(sim_fd, hiov, count);
1985
1986 for (typename OS::size_t i = 0; i < count; ++i)
1987 delete [] (char *)hiov[i].iov_base;
1988
1989 return (result == -1) ? -errno : result;
1990}
1991
1993template <class OS>
1994SyscallReturn
1996 VPtr<> start, typename OS::size_t length, int prot,
1997 int tgt_flags, int tgt_fd, typename OS::off_t offset)
1998{
1999 auto p = tc->getProcessPtr();
2000 Addr page_bytes = p->pTable->pageSize();
2001
2002 if (start & (page_bytes - 1) ||
2003 offset & (page_bytes - 1) ||
2004 (tgt_flags & OS::TGT_MAP_PRIVATE &&
2005 tgt_flags & OS::TGT_MAP_SHARED) ||
2006 (!(tgt_flags & OS::TGT_MAP_PRIVATE) &&
2007 !(tgt_flags & OS::TGT_MAP_SHARED)) ||
2008 !length) {
2009 return -EINVAL;
2010 }
2011
2012 if ((prot & PROT_WRITE) && (tgt_flags & OS::TGT_MAP_SHARED)) {
2013 // With shared mmaps, there are two cases to consider:
2014 // 1) anonymous: writes should modify the mapping and this should be
2015 // visible to observers who share the mapping. Currently, it's
2016 // difficult to update the shared mapping because there's no
2017 // structure which maintains information about the which virtual
2018 // memory areas are shared. If that structure existed, it would be
2019 // possible to make the translations point to the same frames.
2020 // 2) file-backed: writes should modify the mapping and the file
2021 // which is backed by the mapping. The shared mapping problem is the
2022 // same as what was mentioned about the anonymous mappings. For
2023 // file-backed mappings, the writes to the file are difficult
2024 // because it requires syncing what the mapping holds with the file
2025 // that resides on the host system. So, any write on a real system
2026 // would cause the change to be propagated to the file mapping at
2027 // some point in the future (the inode is tracked along with the
2028 // mapping). This isn't guaranteed to always happen, but it usually
2029 // works well enough. The guarantee is provided by the msync system
2030 // call. We could force the change through with shared mappings with
2031 // a call to msync, but that again would require more information
2032 // than we currently maintain.
2033 warn_once("mmap: writing to shared mmap region is currently "
2034 "unsupported. The write succeeds on the target, but it "
2035 "will not be propagated to the host or shared mappings");
2036 }
2037
2038 length = roundUp(length, page_bytes);
2039
2040 int sim_fd = -1;
2041 if (!(tgt_flags & OS::TGT_MAP_ANONYMOUS)) {
2042 std::shared_ptr<FDEntry> fdep = (*p->fds)[tgt_fd];
2043
2044 auto dfdp = std::dynamic_pointer_cast<DeviceFDEntry>(fdep);
2045 if (dfdp) {
2046 EmulatedDriver *emul_driver = dfdp->getDriver();
2047 return emul_driver->mmap(tc, start, length, prot, tgt_flags,
2048 tgt_fd, offset);
2049 }
2050
2051 auto ffdp = std::dynamic_pointer_cast<FileFDEntry>(fdep);
2052 if (!ffdp)
2053 return -EBADF;
2054 sim_fd = ffdp->getSimFD();
2055
2064 if (p->interpImage.contains(tc->pcState().instAddr())) {
2065 std::shared_ptr<FDEntry> fdep = (*p->fds)[tgt_fd];
2066 auto ffdp = std::dynamic_pointer_cast<FileFDEntry>(fdep);
2067 auto *lib = loader::createObjectFile(p->checkPathRedirect(
2068 ffdp->getFileName()));
2069 DPRINTF_SYSCALL(Verbose, "Loading symbols from %s\n",
2070 ffdp->getFileName());
2071
2072 if (lib) {
2073 Addr offset = lib->buildImage().minAddr() + start;
2074 loader::debugSymbolTable.insert(*lib->symtab().offset(offset));
2075 }
2076 }
2077 }
2078
2082 if (!(tgt_flags & OS::TGT_MAP_FIXED)) {
2090 if (!(start && p->memState->isUnmapped(start, length))) {
2094 start = p->memState->extendMmap(length);
2095 }
2096 }
2097
2098 DPRINTF_SYSCALL(Verbose, " mmap range is 0x%x - 0x%x\n",
2099 start, start + length - 1);
2100
2106 if (tgt_flags & OS::TGT_MAP_FIXED) {
2111 p->memState->unmapRegion(start, length);
2112 }
2113
2117 std::string region_name;
2118 if (tgt_flags & OS::TGT_MAP_ANONYMOUS) {
2119 region_name = "anon";
2120 } else {
2121 std::shared_ptr<FDEntry> fdep = (*p->fds)[tgt_fd];
2122 auto ffdp = std::dynamic_pointer_cast<FileFDEntry>(fdep);
2123 region_name = ffdp->getFileName();
2124 }
2125
2130 p->memState->mapRegion(start, length, region_name, sim_fd, offset);
2131
2132 return (Addr)start;
2133}
2134
2135template <class OS>
2136SyscallReturn
2138 int tgt_fd, VPtr<> bufPtr, typename OS::size_t nbytes,
2139 typename OS::off_t offset)
2140{
2141 auto p = tc->getProcessPtr();
2142
2143 auto ffdp = std::dynamic_pointer_cast<FileFDEntry>((*p->fds)[tgt_fd]);
2144 if (!ffdp)
2145 return -EBADF;
2146 int sim_fd = ffdp->getSimFD();
2147
2148 BufferArg bufArg(bufPtr, nbytes);
2149
2150 int bytes_read = pread(sim_fd, bufArg.bufferPtr(), nbytes, offset);
2151
2152 bufArg.copyOut(SETranslatingPortProxy(tc));
2153
2154 return (bytes_read == -1) ? -errno : bytes_read;
2155}
2156
2157template <class OS>
2158SyscallReturn
2160 int tgt_fd, VPtr<> bufPtr, typename OS::size_t nbytes,
2161 typename OS::off_t offset)
2162{
2163 auto p = tc->getProcessPtr();
2164
2165 auto ffdp = std::dynamic_pointer_cast<FileFDEntry>((*p->fds)[tgt_fd]);
2166 if (!ffdp)
2167 return -EBADF;
2168 int sim_fd = ffdp->getSimFD();
2169
2170 BufferArg bufArg(bufPtr, nbytes);
2171 bufArg.copyIn(SETranslatingPortProxy(tc));
2172
2173 int bytes_written = pwrite(sim_fd, bufArg.bufferPtr(), nbytes, offset);
2174
2175 return (bytes_written == -1) ? -errno : bytes_written;
2176}
2177
2179template <class OS>
2180SyscallReturn
2182 VPtr<> start, typename OS::size_t length, int prot,
2183 int tgt_flags, int tgt_fd, typename OS::off_t offset)
2184{
2185 auto page_size = tc->getProcessPtr()->pTable->pageSize();
2186 return mmapFunc<OS>(desc, tc, start, length, prot, tgt_flags,
2187 tgt_fd, offset * page_size);
2188}
2189
2191template <class OS>
2192SyscallReturn
2194 unsigned resource, VPtr<typename OS::rlimit> rlp)
2195{
2196 const ByteOrder bo = OS::byteOrder;
2197 switch (resource) {
2198 case OS::TGT_RLIMIT_STACK:
2199 // max stack size in bytes: make up a number (8MiB for now)
2200 rlp->rlim_cur = rlp->rlim_max = 8 * 1024 * 1024;
2201 rlp->rlim_cur = htog(rlp->rlim_cur, bo);
2202 rlp->rlim_max = htog(rlp->rlim_max, bo);
2203 break;
2204
2205 case OS::TGT_RLIMIT_DATA:
2206 // max data segment size in bytes: make up a number
2207 rlp->rlim_cur = rlp->rlim_max = 256 * 1024 * 1024;
2208 rlp->rlim_cur = htog(rlp->rlim_cur, bo);
2209 rlp->rlim_max = htog(rlp->rlim_max, bo);
2210 break;
2211
2212 case OS::TGT_RLIMIT_NPROC:
2213 rlp->rlim_cur = rlp->rlim_max = tc->getSystemPtr()->threads.size();
2214 rlp->rlim_cur = htog(rlp->rlim_cur, bo);
2215 rlp->rlim_max = htog(rlp->rlim_max, bo);
2216 break;
2217
2218 default:
2219 warn("getrlimit: unimplemented resource %d", resource);
2220 return -EINVAL;
2221 break;
2222 }
2223
2224 return 0;
2225}
2226
2227template <class OS>
2228SyscallReturn
2230 int pid, int resource, VPtr<> n, VPtr<typename OS::rlimit> rlp)
2231{
2232 if (pid != 0) {
2233 warn("prlimit: ignoring rlimits for nonzero pid");
2234 return -EPERM;
2235 }
2236 if (n)
2237 warn("prlimit: ignoring new rlimit");
2238 if (rlp) {
2239 const ByteOrder bo = OS::byteOrder;
2240 switch (resource) {
2241 case OS::TGT_RLIMIT_STACK:
2242 // max stack size in bytes: make up a number (8MiB for now)
2243 rlp->rlim_cur = rlp->rlim_max = 8 * 1024 * 1024;
2244 rlp->rlim_cur = htog(rlp->rlim_cur, bo);
2245 rlp->rlim_max = htog(rlp->rlim_max, bo);
2246 break;
2247 case OS::TGT_RLIMIT_DATA:
2248 // max data segment size in bytes: make up a number
2249 rlp->rlim_cur = rlp->rlim_max = 256*1024*1024;
2250 rlp->rlim_cur = htog(rlp->rlim_cur, bo);
2251 rlp->rlim_max = htog(rlp->rlim_max, bo);
2252 break;
2253 default:
2254 warn("prlimit: unimplemented resource %d", resource);
2255 return -EINVAL;
2256 break;
2257 }
2258 }
2259 return 0;
2260}
2261
2263template <class OS>
2264SyscallReturn
2266 int clk_id, VPtr<typename OS::timespec> tp)
2267{
2268 getElapsedTimeNano(tp->tv_sec, tp->tv_nsec);
2269 tp->tv_sec += seconds_since_epoch;
2270 tp->tv_sec = htog(tp->tv_sec, OS::byteOrder);
2271 tp->tv_nsec = htog(tp->tv_nsec, OS::byteOrder);
2272
2273 return 0;
2274}
2275
2277template <class OS>
2278SyscallReturn
2281{
2282 // Set resolution at ns, which is what clock_gettime() returns
2283 tp->tv_sec = 0;
2284 tp->tv_nsec = 1;
2285
2286 return 0;
2287}
2288
2290template <class OS>
2291SyscallReturn
2294{
2295 getElapsedTimeMicro(tp->tv_sec, tp->tv_usec);
2296 tp->tv_sec += seconds_since_epoch;
2297 tp->tv_sec = htog(tp->tv_sec, OS::byteOrder);
2298 tp->tv_usec = htog(tp->tv_usec, OS::byteOrder);
2299
2300 return 0;
2301}
2302
2304template <class OS>
2305SyscallReturn
2307 int dirfd, VPtr<> pathname, VPtr<typename OS::timeval [2]> tp)
2308{
2309 std::string path;
2310 if (!SETranslatingPortProxy(tc).tryReadString(path, pathname))
2311 return -EFAULT;
2312
2313 // Modifying path from the directory descriptor
2314 if (auto res = atSyscallPath<OS>(tc, dirfd, path); !res.successful()) {
2315 return res;
2316 }
2317
2318 struct timeval hostTimeval[2];
2319 for (int i = 0; i < 2; ++i) {
2320 hostTimeval[i].tv_sec = gtoh((*tp)[i].tv_sec, OS::byteOrder);
2321 hostTimeval[i].tv_usec = gtoh((*tp)[i].tv_usec, OS::byteOrder);
2322 }
2323
2324 // Adjust path for cwd and redirection
2325 auto process = tc->getProcessPtr();
2326 path = process->checkPathRedirect(path);
2327
2328 int result = utimes(path.c_str(), hostTimeval);
2329
2330 if (result < 0)
2331 return -errno;
2332
2333 return 0;
2334}
2335
2337template <class OS>
2338SyscallReturn
2340 VPtr<typename OS::timeval [2]> tp)
2341{
2342 return futimesatFunc<OS>(desc, tc, OS::TGT_AT_FDCWD, pathname, tp);
2343}
2344
2345template <class OS>
2346SyscallReturn
2348 VPtr<> pathname, VPtr<> argv_mem_loc, VPtr<> envp_mem_loc)
2349{
2350 auto p = tc->getProcessPtr();
2351
2352 std::string path;
2353 SETranslatingPortProxy mem_proxy(tc);
2354 if (!mem_proxy.tryReadString(path, pathname))
2355 return -EFAULT;
2356
2357 if (access(path.c_str(), F_OK) == -1)
2358 return -EACCES;
2359
2360 auto read_in = [](std::vector<std::string> &vect,
2361 PortProxy &mem_proxy, VPtr<> mem_loc)
2362 {
2363 for (int inc = 0; ; inc++) {
2364 BufferArg b((mem_loc + sizeof(Addr) * inc), sizeof(Addr));
2365 b.copyIn(mem_proxy);
2366
2367 if (!*(Addr*)b.bufferPtr())
2368 break;
2369
2370 vect.push_back(std::string());
2371 mem_proxy.tryReadString(vect[inc], *(Addr*)b.bufferPtr());
2372 }
2373 };
2374
2379 if (!p->vforkContexts.empty()) {
2380 ThreadContext *vtc = p->system->threads[p->vforkContexts.front()];
2381 assert(vtc->status() == ThreadContext::Suspended);
2382 vtc->activate();
2383 }
2384
2391 ProcessParams *pp = new ProcessParams();
2392 pp->executable = path;
2393 read_in(pp->cmd, mem_proxy, argv_mem_loc);
2394 read_in(pp->env, mem_proxy, envp_mem_loc);
2395 pp->uid = p->uid();
2396 pp->egid = p->egid();
2397 pp->euid = p->euid();
2398 pp->gid = p->gid();
2399 pp->ppid = p->ppid();
2400 pp->pid = p->pid();
2401 pp->input.assign("cin");
2402 pp->output.assign("cout");
2403 pp->errout.assign("cerr");
2404 pp->cwd.assign(p->tgtCwd);
2405 pp->system = p->system;
2406 pp->release = p->release;
2415 p->system->PIDs.erase(p->pid());
2416 Process *new_p = pp->create();
2417 // TODO: there is no way to know when the Process SimObject is done with
2418 // the params pointer. Both the params pointer (pp) and the process
2419 // pointer (p) are normally managed in python and are never cleaned up.
2420
2425 new_p->fds = p->fds;
2426 for (int i = 0; i < new_p->fds->getSize(); i++) {
2427 std::shared_ptr<FDEntry> fdep = (*new_p->fds)[i];
2428 if (fdep && fdep->getCOE())
2429 new_p->fds->closeFDEntry(i);
2430 }
2431
2432 *new_p->sigchld = true;
2433
2434 tc->clearArchRegs();
2435 tc->setProcessPtr(new_p);
2436 new_p->assignThreadContext(tc->contextId());
2437 new_p->init();
2438 new_p->initState();
2439 tc->activate();
2440
2441 return SyscallReturn();
2442}
2443
2445template <class OS>
2446SyscallReturn
2448 int who /* THREAD, SELF, or CHILDREN */,
2450{
2451 rup->ru_utime.tv_sec = 0;
2452 rup->ru_utime.tv_usec = 0;
2453 rup->ru_stime.tv_sec = 0;
2454 rup->ru_stime.tv_usec = 0;
2455 rup->ru_maxrss = 0;
2456 rup->ru_ixrss = 0;
2457 rup->ru_idrss = 0;
2458 rup->ru_isrss = 0;
2459 rup->ru_minflt = 0;
2460 rup->ru_majflt = 0;
2461 rup->ru_nswap = 0;
2462 rup->ru_inblock = 0;
2463 rup->ru_oublock = 0;
2464 rup->ru_msgsnd = 0;
2465 rup->ru_msgrcv = 0;
2466 rup->ru_nsignals = 0;
2467 rup->ru_nvcsw = 0;
2468 rup->ru_nivcsw = 0;
2469
2470 switch (who) {
2471 case OS::TGT_RUSAGE_SELF:
2472 getElapsedTimeMicro(rup->ru_utime.tv_sec, rup->ru_utime.tv_usec);
2473 rup->ru_utime.tv_sec = htog(rup->ru_utime.tv_sec, OS::byteOrder);
2474 rup->ru_utime.tv_usec = htog(rup->ru_utime.tv_usec, OS::byteOrder);
2475 break;
2476
2477 case OS::TGT_RUSAGE_CHILDREN:
2478 // do nothing. We have no child processes, so they take no time.
2479 break;
2480
2481 default:
2482 // don't really handle THREAD or CHILDREN, but just warn and
2483 // plow ahead
2484 warn("getrusage() only supports RUSAGE_SELF. Parameter %d ignored.",
2485 who);
2486 }
2487
2488 return 0;
2489}
2490
2492template <class OS>
2493SyscallReturn
2495{
2496 // Fill in the time structure (in clocks)
2497 int64_t clocks = curTick() * OS::M5_SC_CLK_TCK / sim_clock::as_int::s;
2498 bufp->tms_utime = clocks;
2499 bufp->tms_stime = 0;
2500 bufp->tms_cutime = 0;
2501 bufp->tms_cstime = 0;
2502
2503 // Convert to host endianness
2504 bufp->tms_utime = htog(bufp->tms_utime, OS::byteOrder);
2505
2506 // Return clock ticks since system boot
2507 return clocks;
2508}
2509
2511template <class OS>
2512SyscallReturn
2514{
2515 typename OS::time_t sec, usec;
2516 getElapsedTimeMicro(sec, usec);
2517 sec += seconds_since_epoch;
2518
2520 if (taddr != 0) {
2521 typename OS::time_t t = sec;
2522 t = htog(t, OS::byteOrder);
2523 p.writeBlob(taddr, &t, (int)sizeof(typename OS::time_t));
2524 }
2525 return sec;
2526}
2527
2528template <class OS>
2529SyscallReturn
2530tgkillFunc(SyscallDesc *desc, ThreadContext *tc, int tgid, int tid, int sig)
2531{
2547 System *sys = tc->getSystemPtr();
2548 Process *tgt_proc = nullptr;
2549 for (auto *tc: sys->threads) {
2550 Process *temp = tc->getProcessPtr();
2551 if (temp->pid() == tid) {
2552 tgt_proc = temp;
2553 break;
2554 }
2555 }
2556
2557 if (sig != 0 && sig != OS::TGT_SIGABRT)
2558 return -EINVAL;
2559
2560 if (tgt_proc == nullptr)
2561 return -ESRCH;
2562
2563 if (tgid != -1 && tgt_proc->tgid() != tgid)
2564 return -ESRCH;
2565
2566 if (sig == OS::TGT_SIGABRT)
2567 exitGroupFunc(desc, tc, 0);
2568
2569 return 0;
2570}
2571
2572template <class OS>
2573SyscallReturn
2575 int domain, int type, int prot)
2576{
2577 auto p = tc->getProcessPtr();
2578
2579 int sim_fd = socket(domain, type, prot);
2580 if (sim_fd == -1)
2581 return -errno;
2582
2583 auto sfdp = std::make_shared<SocketFDEntry>(sim_fd, domain, type, prot);
2584 int tgt_fd = p->fds->allocFD(sfdp);
2585
2586 return tgt_fd;
2587}
2588
2589template <class OS>
2590SyscallReturn
2592 int domain, int type, int prot, VPtr<> svPtr)
2593{
2594 auto p = tc->getProcessPtr();
2595
2596 BufferArg svBuf((Addr)svPtr, 2 * sizeof(int));
2597 int status = socketpair(domain, type, prot, (int *)svBuf.bufferPtr());
2598 if (status == -1)
2599 return -errno;
2600
2601 int *fds = (int *)svBuf.bufferPtr();
2602
2603 auto sfdp1 = std::make_shared<SocketFDEntry>(fds[0], domain, type, prot);
2604 fds[0] = p->fds->allocFD(sfdp1);
2605 auto sfdp2 = std::make_shared<SocketFDEntry>(fds[1], domain, type, prot);
2606 fds[1] = p->fds->allocFD(sfdp2);
2608
2609 return status;
2610}
2611
2612template <class OS>
2613SyscallReturn
2619{
2620 int retval;
2621
2622 auto p = tc->getProcessPtr();
2623
2629 fd_set readfds_h;
2630 FD_ZERO(&readfds_h);
2631 fd_set writefds_h;
2632 FD_ZERO(&writefds_h);
2633 fd_set errorfds_h;
2634 FD_ZERO(&errorfds_h);
2635
2645 int nfds_h = 0;
2646 std::map<int, int> trans_map;
2647 auto try_add_host_set = [&](typename OS::fd_set *tgt_set_entry,
2648 fd_set *hst_set_entry,
2649 int iter) -> bool
2650 {
2656 if (FD_ISSET(iter, (fd_set *)tgt_set_entry)) {
2662 auto hbfdp = std::dynamic_pointer_cast<HBFDEntry>((*p->fds)[iter]);
2663 if (!hbfdp)
2664 return true;
2665 auto sim_fd = hbfdp->getSimFD();
2666
2672 trans_map[sim_fd] = iter;
2673
2679 nfds_h = std::max(nfds_h - 1, sim_fd + 1);
2680
2685 FD_SET(sim_fd, hst_set_entry);
2686 }
2687 return false;
2688 };
2689
2690 for (int i = 0; i < nfds; i++) {
2691 if (readfds) {
2692 bool ebadf = try_add_host_set(readfds, &readfds_h, i);
2693 if (ebadf)
2694 return -EBADF;
2695 }
2696 if (writefds) {
2697 bool ebadf = try_add_host_set(writefds, &writefds_h, i);
2698 if (ebadf)
2699 return -EBADF;
2700 }
2701 if (errorfds) {
2702 bool ebadf = try_add_host_set(errorfds, &errorfds_h, i);
2703 if (ebadf)
2704 return -EBADF;
2705 }
2706 }
2707
2708 if (timeout) {
2716 timeout->tv_sec = 0;
2717 timeout->tv_usec = 0;
2718
2719 retval = select(nfds_h,
2720 readfds ? &readfds_h : nullptr,
2721 writefds ? &writefds_h : nullptr,
2722 errorfds ? &errorfds_h : nullptr,
2723 (timeval *)(typename OS::timeval *)timeout);
2724 } else {
2732 struct timeval tv = { 0, 0 };
2733
2734 retval = select(nfds_h,
2735 readfds ? &readfds_h : nullptr,
2736 readfds ? &writefds_h : nullptr,
2737 readfds ? &errorfds_h : nullptr,
2738 &tv);
2739
2740 if (retval == 0) {
2746 for (auto sig : tc->getSystemPtr()->signalList)
2747 if (sig.receiver == p)
2748 return -EINTR;
2749 return SyscallReturn::retry();
2750 }
2751 }
2752
2753 if (retval == -1)
2754 return -errno;
2755
2756 if (readfds) {
2757 FD_ZERO(reinterpret_cast<fd_set *>((typename OS::fd_set *)readfds));
2758 }
2759 if (writefds) {
2760 FD_ZERO(reinterpret_cast<fd_set *>((typename OS::fd_set *)writefds));
2761 }
2762 if (errorfds) {
2763 FD_ZERO(reinterpret_cast<fd_set *>((typename OS::fd_set *)errorfds));
2764 }
2765
2771 for (int i = 0; i < nfds_h; i++) {
2772 if (readfds && FD_ISSET(i, &readfds_h))
2773 FD_SET(trans_map[i],
2774 reinterpret_cast<fd_set *>(
2775 (typename OS::fd_set *)readfds));
2776
2777 if (writefds && FD_ISSET(i, &writefds_h))
2778 FD_SET(trans_map[i],
2779 reinterpret_cast<fd_set *>(
2780 (typename OS::fd_set *)writefds));
2781
2782 if (errorfds && FD_ISSET(i, &errorfds_h))
2783 FD_SET(trans_map[i],
2784 reinterpret_cast<fd_set *>(
2785 (typename OS::fd_set *)errorfds));
2786 }
2787
2788 return retval;
2789}
2790
2791template <class OS>
2792SyscallReturn
2794 int tgt_fd, VPtr<> buf_ptr, typename OS::size_t nbytes)
2795{
2796 auto p = tc->getProcessPtr();
2797
2798 auto hbfdp = std::dynamic_pointer_cast<HBFDEntry>((*p->fds)[tgt_fd]);
2799 if (!hbfdp)
2800 return -EBADF;
2801 int sim_fd = hbfdp->getSimFD();
2802
2803 struct pollfd pfd;
2804 pfd.fd = sim_fd;
2805 pfd.events = POLLIN | POLLPRI;
2806 if ((poll(&pfd, 1, 0) == 0)
2807 && !(hbfdp->getFlags() & OS::TGT_O_NONBLOCK))
2808 return SyscallReturn::retry();
2809
2810 BufferArg buf_arg(buf_ptr, nbytes);
2811 int bytes_read = read(sim_fd, buf_arg.bufferPtr(), nbytes);
2812
2813 if (bytes_read > 0)
2814 buf_arg.copyOut(SETranslatingPortProxy(tc));
2815
2816 return (bytes_read == -1) ? -errno : bytes_read;
2817}
2818
2819template <class OS>
2820SyscallReturn
2822 int tgt_fd, VPtr<> buf_ptr, typename OS::size_t nbytes)
2823{
2824 auto p = tc->getProcessPtr();
2825
2826 auto hbfdp = std::dynamic_pointer_cast<HBFDEntry>((*p->fds)[tgt_fd]);
2827 if (!hbfdp)
2828 return -EBADF;
2829 int sim_fd = hbfdp->getSimFD();
2830
2831 BufferArg buf_arg(buf_ptr, nbytes);
2832 buf_arg.copyIn(SETranslatingPortProxy(tc));
2833
2834 struct pollfd pfd;
2835 pfd.fd = sim_fd;
2836 pfd.events = POLLOUT;
2837
2844 auto ffdp = std::dynamic_pointer_cast<FileFDEntry>(hbfdp);
2845 if (ffdp && (ffdp->getFileName() != "/dev/random")) {
2846 if (!poll(&pfd, 1, 0) && !(ffdp->getFlags() & OS::TGT_O_NONBLOCK))
2847 return SyscallReturn::retry();
2848 }
2849
2850 int bytes_written = write(sim_fd, buf_arg.bufferPtr(), nbytes);
2851
2852 if (bytes_written != -1)
2853 fsync(sim_fd);
2854
2855 return (bytes_written == -1) ? -errno : bytes_written;
2856}
2857
2858template <class OS>
2859SyscallReturn
2861 pid_t pid, VPtr<> statPtr, int options, VPtr<> rusagePtr)
2862{
2863 auto p = tc->getProcessPtr();
2864
2865 if (rusagePtr)
2866 DPRINTF_SYSCALL(Verbose, "wait4: rusage pointer provided %lx, however "
2867 "functionality not supported. Ignoring rusage pointer.\n",
2868 rusagePtr);
2869
2878 System *sysh = tc->getSystemPtr();
2880 for (iter=sysh->signalList.begin(); iter!=sysh->signalList.end(); iter++) {
2881 if (iter->receiver == p) {
2882 if (pid < -1) {
2883 if ((iter->sender->pgid() == -pid)
2884 && (iter->signalValue == OS::TGT_SIGCHLD))
2885 goto success;
2886 } else if (pid == -1) {
2887 if (iter->signalValue == OS::TGT_SIGCHLD)
2888 goto success;
2889 } else if (pid == 0) {
2890 if ((iter->sender->pgid() == p->pgid())
2891 && (iter->signalValue == OS::TGT_SIGCHLD))
2892 goto success;
2893 } else {
2894 if ((iter->sender->pid() == pid)
2895 && (iter->signalValue == OS::TGT_SIGCHLD))
2896 goto success;
2897 }
2898 }
2899 }
2900
2901 return (options & OS::TGT_WNOHANG) ? 0 : SyscallReturn::retry();
2902
2903success:
2904 // Set status to EXITED for WIFEXITED evaluations.
2905 const int EXITED = 0;
2906 BufferArg statusBuf(statPtr, sizeof(int));
2907 *(int *)statusBuf.bufferPtr() = EXITED;
2908 statusBuf.copyOut(SETranslatingPortProxy(tc));
2909
2910 // Return the child PID.
2911 pid_t retval = iter->sender->pid();
2912 sysh->signalList.erase(iter);
2913 return retval;
2914}
2915
2916template <class OS>
2917SyscallReturn
2919 int tgt_fd, VPtr<> addrPtr, VPtr<> lenPtr)
2920{
2921 struct sockaddr sa;
2922 socklen_t addrLen;
2923 int host_fd;
2924 auto p = tc->getProcessPtr();
2925
2926 BufferArg *lenBufPtr = nullptr;
2927 BufferArg *addrBufPtr = nullptr;
2928
2929 auto sfdp = std::dynamic_pointer_cast<SocketFDEntry>((*p->fds)[tgt_fd]);
2930 if (!sfdp)
2931 return -EBADF;
2932 int sim_fd = sfdp->getSimFD();
2933
2940 struct pollfd pfd;
2941 pfd.fd = sim_fd;
2942 pfd.events = POLLIN | POLLPRI;
2943 if ((poll(&pfd, 1, 0) == 0) && !(sfdp->getFlags() & OS::TGT_O_NONBLOCK))
2944 return SyscallReturn::retry();
2945
2946 if (lenPtr) {
2947 lenBufPtr = new BufferArg(lenPtr, sizeof(socklen_t));
2948 lenBufPtr->copyIn(SETranslatingPortProxy(tc));
2949 memcpy(&addrLen, (socklen_t *)lenBufPtr->bufferPtr(),
2950 sizeof(socklen_t));
2951 }
2952
2953 if (addrPtr) {
2954 addrBufPtr = new BufferArg(addrPtr, sizeof(struct sockaddr));
2955 addrBufPtr->copyIn(SETranslatingPortProxy(tc));
2956 memcpy(&sa, (struct sockaddr *)addrBufPtr->bufferPtr(),
2957 sizeof(struct sockaddr));
2958 }
2959
2960 host_fd = accept(sim_fd, &sa, &addrLen);
2961
2962 if (host_fd == -1)
2963 return -errno;
2964
2965 if (addrPtr) {
2966 memcpy(addrBufPtr->bufferPtr(), &sa, sizeof(sa));
2967 addrBufPtr->copyOut(SETranslatingPortProxy(tc));
2968 delete(addrBufPtr);
2969 }
2970
2971 if (lenPtr) {
2972 *(socklen_t *)lenBufPtr->bufferPtr() = addrLen;
2973 lenBufPtr->copyOut(SETranslatingPortProxy(tc));
2974 delete(lenBufPtr);
2975 }
2976
2977 auto afdp = std::make_shared<SocketFDEntry>(host_fd, sfdp->_domain,
2978 sfdp->_type, sfdp->_protocol);
2979 return p->fds->allocFD(afdp);
2980}
2981
2983template <class OS>
2984SyscallReturn
2986 unsigned initval, int in_flags)
2987{
2988#if defined(__linux__)
2989 auto p = tc->getProcessPtr();
2990
2991 int sim_fd = eventfd(initval, in_flags);
2992 if (sim_fd == -1)
2993 return -errno;
2994
2995 bool cloexec = in_flags & OS::TGT_O_CLOEXEC;
2996
2997 int flags = cloexec ? OS::TGT_O_CLOEXEC : 0;
2998 flags |= (in_flags & OS::TGT_O_NONBLOCK) ? OS::TGT_O_NONBLOCK : 0;
2999
3000 auto hbfdp = std::make_shared<HBFDEntry>(flags, sim_fd, cloexec);
3001 int tgt_fd = p->fds->allocFD(hbfdp);
3002 return tgt_fd;
3003#else
3004 warnUnsupportedOS("eventfd");
3005 return -1;
3006#endif
3007}
3008
3010template <class OS>
3011SyscallReturn
3013 pid_t pid, typename OS::size_t cpusetsize,
3014 VPtr<> cpu_set_mask)
3015{
3016#if defined(__linux__)
3017 if (cpusetsize < CPU_ALLOC_SIZE(tc->getSystemPtr()->threads.size()))
3018 return -EINVAL;
3019
3020 SETranslatingPortProxy proxy(tc);
3021 BufferArg maskBuf(cpu_set_mask, cpusetsize);
3022 maskBuf.copyIn(proxy);
3023 for (int i = 0; i < tc->getSystemPtr()->threads.size(); i++) {
3024 CPU_SET(i, (cpu_set_t *)maskBuf.bufferPtr());
3025 }
3026 maskBuf.copyOut(proxy);
3027 return CPU_ALLOC_SIZE(tc->getSystemPtr()->threads.size());
3028#else
3029 warnUnsupportedOS("sched_getaffinity");
3030 return -1;
3031#endif
3032}
3033
3034// Target recvfrom() handler.
3035template <class OS>
3036SyscallReturn
3038 int tgt_fd, VPtr<> buf_ptr, typename OS::size_t buf_len,
3039 int flags, VPtr<> addr_ptr, VPtr<> addrlen_ptr)
3040{
3041 auto p = tc->getProcessPtr();
3042
3043 auto sfdp = std::dynamic_pointer_cast<SocketFDEntry>((*p->fds)[tgt_fd]);
3044 if (!sfdp)
3045 return -EBADF;
3046 int sim_fd = sfdp->getSimFD();
3047
3048 // Reserve buffer space.
3049 BufferArg buf(buf_ptr, buf_len);
3050
3051 SETranslatingPortProxy proxy(tc);
3052
3053 // Get address length.
3054 socklen_t addr_len = 0;
3055 if (addrlen_ptr != 0) {
3056 // Read address length parameter.
3057 BufferArg addrlen_buf(addrlen_ptr, sizeof(socklen_t));
3058 addrlen_buf.copyIn(proxy);
3059 addr_len = *((socklen_t *)addrlen_buf.bufferPtr());
3060 }
3061
3062 struct sockaddr sa, *sap = NULL;
3063 if (addr_len != 0) {
3064 BufferArg addr_buf(addr_ptr, addr_len);
3065 addr_buf.copyIn(proxy);
3066 memcpy(&sa, (struct sockaddr *)addr_buf.bufferPtr(),
3067 sizeof(struct sockaddr));
3068 sap = &sa;
3069 }
3070
3071 ssize_t recvd_size = recvfrom(sim_fd,
3072 (void *)buf.bufferPtr(),
3073 buf_len, flags, sap, (socklen_t *)&addr_len);
3074
3075 if (recvd_size == -1)
3076 return -errno;
3077
3078 // Pass the received data out.
3079 buf.copyOut(proxy);
3080
3081 // Copy address to addr_ptr and pass it on.
3082 if (sap != NULL) {
3083 BufferArg addr_buf(addr_ptr, addr_len);
3084 memcpy(addr_buf.bufferPtr(), sap, sizeof(sa));
3085 addr_buf.copyOut(proxy);
3086 }
3087
3088 // Copy len to addrlen_ptr and pass it on.
3089 if (addr_len != 0) {
3090 BufferArg addrlen_buf(addrlen_ptr, sizeof(socklen_t));
3091 *(socklen_t *)addrlen_buf.bufferPtr() = addr_len;
3092 addrlen_buf.copyOut(proxy);
3093 }
3094
3095 return recvd_size;
3096}
3097
3098// Target sendto() handler.
3099template <typename OS>
3100SyscallReturn
3102 int tgt_fd, VPtr<> buf_ptr, typename OS::size_t buf_len, int flags,
3103 VPtr<> addr_ptr, socklen_t addr_len)
3104{
3105 auto p = tc->getProcessPtr();
3106
3107 auto sfdp = std::dynamic_pointer_cast<SocketFDEntry>((*p->fds)[tgt_fd]);
3108 if (!sfdp)
3109 return -EBADF;
3110 int sim_fd = sfdp->getSimFD();
3111
3112 // Reserve buffer space.
3113 BufferArg buf(buf_ptr, buf_len);
3115
3116 struct sockaddr sa, *sap = nullptr;
3117 memset(&sa, 0, sizeof(sockaddr));
3118 if (addr_len != 0) {
3119 BufferArg addr_buf(addr_ptr, addr_len);
3120 addr_buf.copyIn(SETranslatingPortProxy(tc));
3121 memcpy(&sa, (sockaddr*)addr_buf.bufferPtr(), addr_len);
3122 sap = &sa;
3123 }
3124
3125 ssize_t sent_size = sendto(sim_fd,
3126 (void *)buf.bufferPtr(),
3127 buf_len, flags, sap, (socklen_t)addr_len);
3128
3129 return (sent_size == -1) ? -errno : sent_size;
3130}
3131
3133template <typename OS>
3134SyscallReturn
3136 typename OS::size_t length)
3137{
3138 // Even if the system is currently not capable of recycling physical
3139 // pages, there is no reason we can't unmap them so that we trigger
3140 // appropriate seg faults when the application mistakenly tries to
3141 // access them again.
3142 auto p = tc->getProcessPtr();
3143
3144 if (p->pTable->pageOffset(start))
3145 return -EINVAL;
3146
3147 length = roundUp(length, p->pTable->pageSize());
3148
3149 p->memState->unmapRegion(start, length);
3150
3151 return 0;
3152}
3153
3154// Target fallocate() handler.
3155template <typename OS>
3156SyscallReturn
3158 int tgt_fd, int mode, typename OS::off_t offset,
3159 typename OS::off_t len)
3160{
3161#if defined(__linux__)
3162 auto p = tc->getProcessPtr();
3163
3164 auto ffdp = std::dynamic_pointer_cast<FileFDEntry>((*p->fds)[tgt_fd]);
3165 if (!ffdp)
3166 return -EBADF;
3167 int sim_fd = ffdp->getSimFD();
3168
3169 int result = fallocate(sim_fd, mode, offset, len);
3170 if (result < 0)
3171 return -errno;
3172 return 0;
3173#else
3174 warnUnsupportedOS("fallocate");
3175 return -1;
3176#endif
3177}
3178
3180template <typename OS>
3181SyscallReturn
3183 typename OS::off_t length)
3184{
3185 std::string path;
3186 auto p = tc->getProcessPtr();
3187
3188 if (!SETranslatingPortProxy(tc).tryReadString(path, pathname))
3189 return -EFAULT;
3190
3191 // Adjust path for cwd and redirection
3192 path = p->checkPathRedirect(path);
3193
3194 int result = truncate(path.c_str(), length);
3195 return (result == -1) ? -errno : result;
3196}
3197
3199template <typename OS>
3200SyscallReturn
3202 typename OS::off_t length)
3203{
3204 auto p = tc->getProcessPtr();
3205
3206 auto ffdp = std::dynamic_pointer_cast<FileFDEntry>((*p->fds)[tgt_fd]);
3207 if (!ffdp)
3208 return -EBADF;
3209 int sim_fd = ffdp->getSimFD();
3210
3211 int result = ftruncate(sim_fd, length);
3212 return (result == -1) ? -errno : result;
3213}
3214
3215template <typename OS>
3216SyscallReturn
3218 VPtr<> buf_ptr, typename OS::size_t count,
3219 unsigned int flags)
3220{
3221 static Random::RandomPtr se_prng = Random::genRandom();
3222 SETranslatingPortProxy proxy(tc);
3223
3224 TypedBufferArg<uint8_t> buf(buf_ptr, count);
3225 for (int i = 0; i < count; ++i) {
3226 buf[i] = se_prng->random<uint8_t>();
3227 }
3228 buf.copyOut(proxy);
3229
3230 return count;
3231}
3232
3233} // namespace gem5
3234
3235#endif // __SIM_SYSCALL_EMUL_HH__
#define DPRINTF(x,...)
Definition trace.hh:209
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
std::shared_ptr< Random > RandomPtr
Definition random.hh:65
static RandomPtr genRandom()
Definition random.hh:68
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.
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
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< 3 > sa
Bitfield< 14, 12 > fd
Definition types.hh:150
Bitfield< 31 > n
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 Arm Limited 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 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 pwrite64Func(SyscallDesc *desc, ThreadContext *tc, int tgt_fd, VPtr<> bufPtr, typename OS::size_t nbytes, typename OS::off_t offset)
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 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 _llseekFunc(SyscallDesc *desc, ThreadContext *tc, int tgt_fd, uint32_t offset_high, uint32_t offset_low, VPtr<> result_ptr, int whence)
Target _llseek() handler.
SyscallReturn writeFunc(SyscallDesc *desc, ThreadContext *tc, int tgt_fd, VPtr<> buf_ptr, typename OS::size_t nbytes)
SyscallReturn writevFunc(SyscallDesc *desc, ThreadContext *tc, int tgt_fd, VPtr<> tiov_base, typename OS::size_t count)
Target writev() handler.
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.
Tick curTick()
The universal simulation clock.
Definition cur_tick.hh:46
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 symlinkFunc(SyscallDesc *desc, ThreadContext *tc, VPtr<> pathname, VPtr<> new_pathname)
Target symlink() handler.
SyscallReturn atSyscallPath(ThreadContext *tc, int dirfd, std::string &path)
SyscallReturn unlinkFunc(SyscallDesc *desc, ThreadContext *tc, VPtr<> pathname)
Target unlink() handler.
SyscallReturn lseekFunc(SyscallDesc *desc, ThreadContext *tc, int tgt_fd, typename OS::off_t offs, int whence)
Target lseek() 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 readvFunc(SyscallDesc *desc, ThreadContext *tc, int tgt_fd, VPtr<> tiov_base, typename OS::size_t count)
Target readv() handler.
SyscallReturn ftruncate64Func(SyscallDesc *desc, ThreadContext *tc, int tgt_fd, int64_t length)
Target ftruncate64() handler.
SyscallReturn getcwdFunc(SyscallDesc *desc, ThreadContext *tc, VPtr<> buf_ptr, typename OS::size_t size)
Target getcwd() 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.
SyscallReturn pread64Func(SyscallDesc *desc, ThreadContext *tc, int tgt_fd, VPtr<> bufPtr, typename OS::size_t nbytes, typename OS::off_t offset)
SyscallReturn setTidAddressFunc(SyscallDesc *desc, ThreadContext *tc, VPtr<> tidPtr)
Target set_tid_address() 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.
uint64_t RegVal
Definition types.hh:173
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 getpeernameFunc(SyscallDesc *desc, ThreadContext *tc, int tgt_fd, VPtr<> sockAddrPtr, VPtr<> addrlenPtr)
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 lstat64Func(SyscallDesc *desc, ThreadContext *tc, VPtr<> pathname, VPtr< typename OS::tgt_stat64 > tgt_stat)
Target lstat64() handler.
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 mremapFunc(SyscallDesc *desc, ThreadContext *tc, VPtr<> start, typename OS::size_t old_length, typename OS::size_t new_length, int flags, guest_abi::VarArgs< uint64_t > varargs)
Target mremap() 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 readFunc(SyscallDesc *desc, ThreadContext *tc, int tgt_fd, VPtr<> buf_ptr, typename OS::size_t 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 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 Mon Jan 13 2025 04:28:42 for gem5 by doxygen 1.9.8