gem5 [DEVELOP-FOR-25.0]
Loading...
Searching...
No Matches
syscall_emul.hh
Go to the documentation of this file.
1/*
2 * Copyright (c) 2012-2013, 2015, 2019-2021, 2023-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,
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
350// Target sched_getparam() handler.
351SyscallReturn sched_getparamFunc(SyscallDesc *desc, ThreadContext *tc,
352 int pid, VPtr<int> paramPtr);
353
354template <class OS>
355SyscallReturn
356atSyscallPath(ThreadContext *tc, int dirfd, std::string &path)
357{
358 // If pathname is absolute, then dirfd is ignored.
359 if (dirfd != OS::TGT_AT_FDCWD && !startswith(path, "/")) {
360 auto process = tc->getProcessPtr();
361
362 std::shared_ptr<FDEntry> fdep = ((*process->fds)[dirfd]);
363 auto ffdp = std::dynamic_pointer_cast<FileFDEntry>(fdep);
364 if (!ffdp)
365 return -EBADF;
366
367 if (path.empty())
368 path = ffdp->getFileName();
369 else
370 path = ffdp->getFileName() + "/" + path;
371 }
372
373 return 0;
374}
375
379template <class OS>
380SyscallReturn
382 VPtr<> uaddr, int op, int val, int timeout, VPtr<> uaddr2, int val3)
383{
384 auto process = tc->getProcessPtr();
385
386 /*
387 * Unsupported option that does not affect the correctness of the
388 * application. This is a performance optimization utilized by Linux.
389 */
390 op &= ~OS::TGT_FUTEX_PRIVATE_FLAG;
391 op &= ~OS::TGT_FUTEX_CLOCK_REALTIME_FLAG;
392
393 FutexMap &futex_map = tc->getSystemPtr()->futexMap;
394
395 if (OS::TGT_FUTEX_WAIT == op || OS::TGT_FUTEX_WAIT_BITSET == op) {
396 // Ensure futex system call accessed atomically.
397 BufferArg buf(uaddr, sizeof(int));
399 int mem_val = *(int*)buf.bufferPtr();
400
401 /*
402 * The value in memory at uaddr is not equal with the expected val
403 * (a different thread must have changed it before the system call was
404 * invoked). In this case, we need to throw an error.
405 */
406 if (val != mem_val)
407 return -OS::TGT_EWOULDBLOCK;
408
409 if (OS::TGT_FUTEX_WAIT == op) {
410 futex_map.suspend(uaddr, process->tgid(), tc);
411 } else {
412 futex_map.suspend_bitset(uaddr, process->tgid(), tc, val3);
413 }
414
415 return 0;
416 } else if (OS::TGT_FUTEX_WAKE == op) {
417 return futex_map.wakeup(uaddr, process->tgid(), val);
418 } else if (OS::TGT_FUTEX_WAKE_BITSET == op) {
419 return futex_map.wakeup_bitset(uaddr, process->tgid(), val3);
420 } else if (OS::TGT_FUTEX_REQUEUE == op ||
421 OS::TGT_FUTEX_CMP_REQUEUE == op) {
422
423 // Ensure futex system call accessed atomically.
424 BufferArg buf(uaddr, sizeof(int));
426 int mem_val = *(int*)buf.bufferPtr();
427 /*
428 * For CMP_REQUEUE, the whole operation is only started only if
429 * val3 is still the value of the futex pointed to by uaddr.
430 */
431 if (OS::TGT_FUTEX_CMP_REQUEUE && val3 != mem_val)
432 return -OS::TGT_EWOULDBLOCK;
433 return futex_map.requeue(uaddr, process->tgid(), val, timeout, uaddr2);
434 } else if (OS::TGT_FUTEX_WAKE_OP == op) {
435 /*
436 * The FUTEX_WAKE_OP operation is equivalent to executing the
437 * following code atomically and totally ordered with respect to
438 * other futex operations on any of the two supplied futex words:
439 *
440 * int oldval = *(int *) addr2;
441 * *(int *) addr2 = oldval op oparg;
442 * futex(addr1, FUTEX_WAKE, val, 0, 0, 0);
443 * if (oldval cmp cmparg)
444 * futex(addr2, FUTEX_WAKE, val2, 0, 0, 0);
445 *
446 * (op, oparg, cmp, cmparg are encoded in val3)
447 *
448 * +---+---+-----------+-----------+
449 * |op |cmp| oparg | cmparg |
450 * +---+---+-----------+-----------+
451 * 4 4 12 12 <== # of bits
452 *
453 * reference: http://man7.org/linux/man-pages/man2/futex.2.html
454 *
455 */
456 // get value from simulated-space
457 BufferArg buf(uaddr2, sizeof(int));
459 int oldval = *(int*)buf.bufferPtr();
460 int newval = oldval;
461 // extract op, oparg, cmp, cmparg from val3
462 int wake_cmparg = val3 & 0xfff;
463 int wake_oparg = (val3 & 0xfff000) >> 12;
464 int wake_cmp = (val3 & 0xf000000) >> 24;
465 int wake_op = (val3 & 0xf0000000) >> 28;
466 if ((wake_op & OS::TGT_FUTEX_OP_ARG_SHIFT) >> 3 == 1)
467 wake_oparg = (1 << wake_oparg);
468 wake_op &= ~OS::TGT_FUTEX_OP_ARG_SHIFT;
469 // perform operation on the value of the second futex
470 if (wake_op == OS::TGT_FUTEX_OP_SET)
471 newval = wake_oparg;
472 else if (wake_op == OS::TGT_FUTEX_OP_ADD)
473 newval += wake_oparg;
474 else if (wake_op == OS::TGT_FUTEX_OP_OR)
475 newval |= wake_oparg;
476 else if (wake_op == OS::TGT_FUTEX_OP_ANDN)
477 newval &= ~wake_oparg;
478 else if (wake_op == OS::TGT_FUTEX_OP_XOR)
479 newval ^= wake_oparg;
480 // copy updated value back to simulated-space
481 *(int*)buf.bufferPtr() = newval;
483 // perform the first wake-up
484 int woken1 = futex_map.wakeup(uaddr, process->tgid(), val);
485 int woken2 = 0;
486 // calculate the condition of the second wake-up
487 bool is_wake2 = false;
488 if (wake_cmp == OS::TGT_FUTEX_OP_CMP_EQ)
489 is_wake2 = oldval == wake_cmparg;
490 else if (wake_cmp == OS::TGT_FUTEX_OP_CMP_NE)
491 is_wake2 = oldval != wake_cmparg;
492 else if (wake_cmp == OS::TGT_FUTEX_OP_CMP_LT)
493 is_wake2 = oldval < wake_cmparg;
494 else if (wake_cmp == OS::TGT_FUTEX_OP_CMP_LE)
495 is_wake2 = oldval <= wake_cmparg;
496 else if (wake_cmp == OS::TGT_FUTEX_OP_CMP_GT)
497 is_wake2 = oldval > wake_cmparg;
498 else if (wake_cmp == OS::TGT_FUTEX_OP_CMP_GE)
499 is_wake2 = oldval >= wake_cmparg;
500 // perform the second wake-up
501 if (is_wake2)
502 woken2 = futex_map.wakeup(uaddr2, process->tgid(), timeout);
503
504 return woken1 + woken2;
505 }
506 warn("futex: op %d not implemented; ignoring.", op);
507 return -ENOSYS;
508}
509
512SyscallReturn pipePseudoFunc(SyscallDesc *desc, ThreadContext *tc);
513
514
518const unsigned seconds_since_epoch = 1000 * 1000 * 1000;
519
522template <class T1, class T2>
523void
524getElapsedTimeMicro(T1 &sec, T2 &usec)
525{
526 static const int OneMillion = 1000 * 1000;
527
528 uint64_t elapsed_usecs = curTick() / sim_clock::as_int::us;
529 sec = elapsed_usecs / OneMillion;
530 usec = elapsed_usecs % OneMillion;
531}
532
535template <class T1, class T2>
536void
537getElapsedTimeNano(T1 &sec, T2 &nsec)
538{
539 static const int OneBillion = 1000 * 1000 * 1000;
540
541 uint64_t elapsed_nsecs = curTick() / sim_clock::as_int::ns;
542 sec = elapsed_nsecs / OneBillion;
543 nsec = elapsed_nsecs % OneBillion;
544}
545
547//
548// The following emulation functions are generic, but need to be
549// templated to account for differences in types, constants, etc.
550//
552
553 typedef struct statfs hst_statfs;
554#if NO_STAT64
555 typedef struct stat hst_stat;
556 typedef struct stat hst_stat64;
557#else
558 typedef struct stat hst_stat;
559 typedef struct stat64 hst_stat64;
560#endif
561
565
566template <typename OS, typename TgtStatPtr, typename HostStatPtr>
567void
568copyOutStatBuf(TgtStatPtr tgt, HostStatPtr host, bool fakeTTY=false)
569{
570 constexpr ByteOrder bo = OS::byteOrder;
571
572 if (fakeTTY)
573 tgt->st_dev = 0xA;
574 else
575 tgt->st_dev = host->st_dev;
576 tgt->st_dev = htog(tgt->st_dev, bo);
577 tgt->st_ino = host->st_ino;
578 tgt->st_ino = htog(tgt->st_ino, bo);
579 tgt->st_mode = host->st_mode;
580 if (fakeTTY) {
581 // Claim to be a character device
582 tgt->st_mode &= ~S_IFMT; // Clear S_IFMT
583 tgt->st_mode |= S_IFCHR; // Set S_IFCHR
584 }
585 tgt->st_mode = htog(tgt->st_mode, bo);
586 tgt->st_nlink = host->st_nlink;
587 tgt->st_nlink = htog(tgt->st_nlink, bo);
588 tgt->st_uid = host->st_uid;
589 tgt->st_uid = htog(tgt->st_uid, bo);
590 tgt->st_gid = host->st_gid;
591 tgt->st_gid = htog(tgt->st_gid, bo);
592 if (fakeTTY)
593 tgt->st_rdev = 0x880d;
594 else
595 tgt->st_rdev = host->st_rdev;
596 tgt->st_rdev = htog(tgt->st_rdev, bo);
597 tgt->st_size = host->st_size;
598 tgt->st_size = htog(tgt->st_size, bo);
599 tgt->st_atimeX = host->st_atime;
600 tgt->st_atimeX = htog(tgt->st_atimeX, bo);
601 tgt->st_mtimeX = host->st_mtime;
602 tgt->st_mtimeX = htog(tgt->st_mtimeX, bo);
603 tgt->st_ctimeX = host->st_ctime;
604 tgt->st_ctimeX = htog(tgt->st_ctimeX, bo);
605 // Force the block size to be 8KB. This helps to ensure buffered io works
606 // consistently across different hosts.
607 tgt->st_blksize = 0x2000;
608 tgt->st_blksize = htog(tgt->st_blksize, bo);
609 tgt->st_blocks = host->st_blocks;
610 tgt->st_blocks = htog(tgt->st_blocks, bo);
611}
612
613// Same for stat64
614
615template <typename OS, typename TgtStatPtr, typename HostStatPtr>
616void
617copyOutStat64Buf(TgtStatPtr tgt, HostStatPtr host,
618 bool fakeTTY=false)
619{
620 copyOutStatBuf<OS>(tgt, host, fakeTTY);
621#if defined(STAT_HAVE_NSEC)
622 constexpr ByteOrder bo = OS::byteOrder;
623
624 tgt->st_atime_nsec = host->st_atime_nsec;
625 tgt->st_atime_nsec = htog(tgt->st_atime_nsec, bo);
626 tgt->st_mtime_nsec = host->st_mtime_nsec;
627 tgt->st_mtime_nsec = htog(tgt->st_mtime_nsec, bo);
628 tgt->st_ctime_nsec = host->st_ctime_nsec;
629 tgt->st_ctime_nsec = htog(tgt->st_ctime_nsec, bo);
630#else
631 tgt->st_atime_nsec = 0;
632 tgt->st_mtime_nsec = 0;
633 tgt->st_ctime_nsec = 0;
634#endif
635}
636
637template <class OS, typename TgtStatPtr, typename HostStatPtr>
638void
639copyOutStatfsBuf(TgtStatPtr tgt, HostStatPtr host)
640{
641 constexpr ByteOrder bo = OS::byteOrder;
642
643 tgt->f_type = htog(host->f_type, bo);
644#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__)
645 tgt->f_bsize = htog(host->f_iosize, bo);
646#else
647 tgt->f_bsize = htog(host->f_bsize, bo);
648#endif
649 tgt->f_blocks = htog(host->f_blocks, bo);
650 tgt->f_bfree = htog(host->f_bfree, bo);
651 tgt->f_bavail = htog(host->f_bavail, bo);
652 tgt->f_files = htog(host->f_files, bo);
653 tgt->f_ffree = htog(host->f_ffree, bo);
654 memcpy(&tgt->f_fsid, &host->f_fsid, sizeof(host->f_fsid));
655#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__)
656 tgt->f_namelen = htog(host->f_namemax, bo);
657 tgt->f_frsize = htog(host->f_bsize, bo);
658#elif defined(__APPLE__)
659 tgt->f_namelen = 0;
660 tgt->f_frsize = 0;
661#else
662 tgt->f_namelen = htog(host->f_namelen, bo);
663 tgt->f_frsize = htog(host->f_frsize, bo);
664#endif
665#if defined(__linux__)
666 memcpy(&tgt->f_spare, &host->f_spare,
667 std::min(sizeof(host->f_spare), sizeof(tgt->f_spare)));
668#else
669 /*
670 * The fields are different sizes per OS. Don't bother with
671 * f_spare or f_reserved on non-Linux for now.
672 */
673 memset(&tgt->f_spare, 0, sizeof(tgt->f_spare));
674#endif
675}
676
677template <typename OS, typename TgtStatPtr, typename HostStatPtr>
678void
679copyOutStatxBuf(TgtStatPtr tgt, HostStatPtr host, bool fakeTTY = false)
680{
681 constexpr ByteOrder bo = OS::byteOrder;
682
683 if (fakeTTY) {
684 tgt->stx_dev_major = 0x00;
685 tgt->stx_dev_minor = 0x0A;
686 } else {
687 tgt->stx_dev_major = host->st_dev >> 8;
688 tgt->stx_dev_minor = host->st_dev & 0xFF;
689 }
690 tgt->stx_dev_major = htog(tgt->stx_dev_major, bo);
691 tgt->stx_dev_minor = htog(tgt->stx_dev_minor, bo);
692 tgt->stx_ino = host->st_ino;
693 tgt->stx_ino = htog(tgt->stx_ino, bo);
694 tgt->stx_mode = host->st_mode;
695 if (fakeTTY) {
696 // Claim to be character device.
697 tgt->stx_mode &= ~S_IFMT;
698 tgt->stx_mode |= S_IFCHR;
699 }
700 tgt->stx_mode = htog(tgt->stx_mode, bo);
701 tgt->stx_nlink = host->st_nlink;
702 tgt->stx_nlink = htog(tgt->stx_nlink, bo);
703 tgt->stx_uid = host->st_uid;
704 tgt->stx_uid = htog(tgt->stx_uid, bo);
705 tgt->stx_gid = host->st_gid;
706 tgt->stx_gid = htog(tgt->stx_gid, bo);
707 if (fakeTTY) {
708 tgt->stx_rdev_major = 0x880d >> 8;
709 tgt->stx_rdev_minor = 0x880d & 0xFF;
710 } else {
711 tgt->stx_rdev_major = host->st_rdev >> 8;
712 tgt->stx_rdev_minor = host->st_rdev & 0xFF;
713 }
714 tgt->stx_rdev_major = htog(tgt->stx_rdev_major, bo);
715 tgt->stx_rdev_minor = htog(tgt->stx_rdev_minor, bo);
716 tgt->stx_size = host->st_size;
717 tgt->stx_size = htog(tgt->stx_size, bo);
718 tgt->stx_atimeX = host->st_atime;
719 tgt->stx_atimeX = htog(tgt->stx_atimeX, bo);
720 tgt->stx_ctimeX = host->st_ctime;
721 tgt->stx_ctimeX = htog(tgt->stx_ctimeX, bo);
722 tgt->stx_mtimeX = host->st_mtime;
723 tgt->stx_mtimeX = htog(tgt->stx_mtimeX, bo);
724 // Force the block size to be 8KB. This helps to ensure buffered io works
725 // consistently across different hosts.
726 tgt->stx_blksize = 0x2000;
727 tgt->stx_blksize = htog(tgt->stx_blksize, bo);
728 tgt->stx_blocks = host->st_blocks;
729 tgt->stx_blocks = htog(tgt->stx_blocks, bo);
730 tgt->stx_mask = 0x000007ffU; // STATX_BASIC_STATS on Linux.
731 tgt->stx_mask = htog(tgt->stx_mask, bo);
732 tgt->stx_attributes = 0;
733 tgt->stx_attributes_mask = 0;
734 tgt->stx_attributes_mask = htog(tgt->stx_attributes_mask, bo);
735}
736
741template <class OS>
742SyscallReturn
744 int tgt_fd, unsigned req, VPtr<> addr)
745{
746 auto p = tc->getProcessPtr();
747
748 DPRINTF_SYSCALL(Verbose, "ioctl(%d, 0x%x, ...)\n", tgt_fd, req);
749
750 if (OS::isTtyReq(req))
751 return -ENOTTY;
752
753 auto dfdp = std::dynamic_pointer_cast<DeviceFDEntry>((*p->fds)[tgt_fd]);
754 if (dfdp) {
755 EmulatedDriver *emul_driver = dfdp->getDriver();
756 if (emul_driver)
757 return emul_driver->ioctl(tc, req, addr);
758 }
759
760 auto sfdp = std::dynamic_pointer_cast<SocketFDEntry>((*p->fds)[tgt_fd]);
761 if (sfdp) {
762 int status;
763
764 switch (req) {
765 case SIOCGIFCONF: {
766 BufferArg conf_arg(addr, sizeof(ifconf));
767 conf_arg.copyIn(SETranslatingPortProxy(tc));
768
769 ifconf *conf = (ifconf*)conf_arg.bufferPtr();
770 Addr ifc_buf_addr = (Addr)conf->ifc_buf;
771 BufferArg ifc_buf_arg(ifc_buf_addr, conf->ifc_len);
772 ifc_buf_arg.copyIn(SETranslatingPortProxy(tc));
773
774 conf->ifc_buf = (char*)ifc_buf_arg.bufferPtr();
775
776 status = ioctl(sfdp->getSimFD(), req, conf_arg.bufferPtr());
777 if (status != -1) {
778 conf->ifc_buf = (char*)ifc_buf_addr;
779 ifc_buf_arg.copyOut(SETranslatingPortProxy(tc));
780 conf_arg.copyOut(SETranslatingPortProxy(tc));
781 }
782
783 return status;
784 }
785 case SIOCGIFFLAGS:
786#if defined(__linux__)
787 case SIOCGIFINDEX:
788#endif
789 case SIOCGIFNETMASK:
790 case SIOCGIFADDR:
791#if defined(__linux__)
792 case SIOCGIFHWADDR:
793#endif
794 case SIOCGIFMTU: {
795 BufferArg req_arg(addr, sizeof(ifreq));
796 req_arg.copyIn(SETranslatingPortProxy(tc));
797
798 status = ioctl(sfdp->getSimFD(), req, req_arg.bufferPtr());
799 if (status != -1)
800 req_arg.copyOut(SETranslatingPortProxy(tc));
801 return status;
802 }
803 }
804 }
805
810 warn("Unsupported ioctl call (return ENOTTY): ioctl(%d, 0x%x, ...) @ %s\n",
811 tgt_fd, req, tc->pcState());
812 return -ENOTTY;
813}
814
816template <class OS>
817SyscallReturn
819 int tgt_dirfd, VPtr<> pathname, int tgt_flags, int mode)
820{
821 auto p = tc->getProcessPtr();
822
827 std::string path;
828 if (!SETranslatingPortProxy(tc).tryReadString(path, pathname))
829 return -EFAULT;
830
831#ifdef __CYGWIN32__
832 int host_flags = O_BINARY;
833#else
834 int host_flags = 0;
835#endif
840 for (const auto &p: OS::openFlagTable) {
841 if (tgt_flags & p.first) {
842 tgt_flags &= ~p.first;
843 host_flags |= p.second;
844 }
845 }
846 warn_if(tgt_flags, "%s: cannot decode flags %#x", desc->name(), tgt_flags);
847
848#ifdef __CYGWIN32__
849 host_flags |= O_BINARY;
850#endif
851
864 std::string redir_path = path;
865 std::string abs_path = path;
866 if (tgt_dirfd == OS::TGT_AT_FDCWD) {
867 abs_path = p->absolutePath(path, true);
868 redir_path = p->checkPathRedirect(path);
869 } else if (!startswith(path, "/")) {
870 std::shared_ptr<FDEntry> fdep = ((*p->fds)[tgt_dirfd]);
871 auto ffdp = std::dynamic_pointer_cast<FileFDEntry>(fdep);
872 if (!ffdp)
873 return -EBADF;
874 abs_path = ffdp->getFileName() + path;
875 redir_path = p->checkPathRedirect(abs_path);
876 }
877
884 if (startswith(abs_path, "/dev/")) {
885 std::string filename = abs_path.substr(strlen("/dev/"));
886 EmulatedDriver *drv = p->findDriver(filename);
887 if (drv) {
888 DPRINTF_SYSCALL(Verbose, "%s: passing call to "
889 "driver open with path[%s]\n",
890 desc->name(), abs_path.c_str());
891 return drv->open(tc, mode, host_flags);
892 }
897 }
898
923 int sim_fd = -1;
924 std::string used_path;
925 std::vector<std::string> special_paths =
926 { "/proc/meminfo", "/system/", "/platform/", "/etc/passwd",
927 "/proc/self/maps", "/dev/urandom",
928 "/sys/devices/system/cpu/online" };
929 for (auto entry : special_paths) {
930 if (startswith(path, entry)) {
931 sim_fd = OS::openSpecialFile(abs_path, p, tc);
932 used_path = abs_path;
933 }
934 }
935 if (sim_fd == -1) {
936 sim_fd = open(redir_path.c_str(), host_flags, mode);
937 used_path = redir_path;
938 }
939 if (sim_fd == -1) {
940 int local = -errno;
941 DPRINTF_SYSCALL(Verbose, "%s: failed -> path:%s "
942 "(inferred from:%s)\n", desc->name(),
943 used_path.c_str(), path.c_str());
944 return local;
945 }
946
955 auto ffdp = std::make_shared<FileFDEntry>(sim_fd, host_flags, path, 0);
956 // Record the file mode for checkpoint restoring
957 ffdp->setFileMode(mode);
958 int tgt_fd = p->fds->allocFD(ffdp);
959 DPRINTF_SYSCALL(Verbose, "%s: sim_fd[%d], target_fd[%d] -> path:%s\n"
960 "(inferred from:%s)\n", desc->name(),
961 sim_fd, tgt_fd, used_path.c_str(), path.c_str());
962 return tgt_fd;
963}
964
966template <class OS>
967SyscallReturn
969 VPtr<> pathname, int tgt_flags, int mode)
970{
971 return openatFunc<OS>(
972 desc, tc, OS::TGT_AT_FDCWD, pathname, tgt_flags, mode);
973}
974
976template <class OS>
977SyscallReturn
979 VPtr<> buf_ptr, typename OS::size_t size)
980{
981 int result = 0;
982 auto p = tc->getProcessPtr();
983 BufferArg buf(buf_ptr, size);
984
985 // Is current working directory defined?
986 std::string cwd = p->tgtCwd;
987 if (!cwd.empty()) {
988 if (cwd.length() >= size) {
989 // Buffer too small
990 return -ERANGE;
991 }
992 strncpy((char *)buf.bufferPtr(), cwd.c_str(), size);
993 result = cwd.length();
994 } else {
995 if (getcwd((char *)buf.bufferPtr(), size)) {
996 result = strlen((char *)buf.bufferPtr());
997 } else {
998 result = -1;
999 }
1000 }
1001
1003
1004 return (result == -1) ? -errno : result;
1005}
1006
1008template <class OS>
1009SyscallReturn
1011 int tgt_fd, typename OS::off_t offs, int whence)
1012{
1013 auto p = tc->getProcessPtr();
1014
1015 auto ffdp = std::dynamic_pointer_cast<FileFDEntry>((*p->fds)[tgt_fd]);
1016 if (!ffdp)
1017 return -EBADF;
1018 int sim_fd = ffdp->getSimFD();
1019
1020 off_t result = lseek(sim_fd, offs, whence);
1021
1022 return (result == (off_t)-1) ? -errno : result;
1023}
1024
1026template <class OS>
1027SyscallReturn
1029 int dirfd, VPtr<> pathname, int flags)
1030{
1031 std::string path;
1032 if (!SETranslatingPortProxy(tc).tryReadString(path, pathname))
1033 return -EFAULT;
1034
1035 // Modifying path from the directory descriptor
1036 if (auto res = atSyscallPath<OS>(tc, dirfd, path); !res.successful()) {
1037 return res;
1038 }
1039
1040 if (flags & OS::TGT_AT_REMOVEDIR) {
1041 return rmdirImpl(desc, tc, path);
1042 } else {
1043 return unlinkImpl(desc, tc, path);
1044 }
1045}
1046
1048template <class OS>
1049SyscallReturn
1051 int dirfd, VPtr<> pathname, int mode)
1052{
1053 std::string path;
1054 if (!SETranslatingPortProxy(tc).tryReadString(path, pathname))
1055 return -EFAULT;
1056
1057 // Modifying path from the directory descriptor
1058 if (auto res = atSyscallPath<OS>(tc, dirfd, path); !res.successful()) {
1059 return res;
1060 }
1061
1062 return accessImpl(desc, tc, path, mode);
1063}
1064
1066template <class OS>
1067SyscallReturn
1069 int dirfd, VPtr<> pathname, VPtr<> buf_ptr,
1070 typename OS::size_t bufsiz)
1071{
1072 std::string path;
1073 if (!SETranslatingPortProxy(tc).tryReadString(path, pathname))
1074 return -EFAULT;
1075
1076 // Modifying path from the directory descriptor
1077 if (auto res = atSyscallPath<OS>(tc, dirfd, path); !res.successful()) {
1078 return res;
1079 }
1080
1081 auto p = tc->getProcessPtr();
1082
1083 // Adjust path for cwd and redirection
1084 path = p->checkPathRedirect(path);
1085
1086 BufferArg buf(buf_ptr, bufsiz);
1087
1088 int result = -1;
1089 if (path != "/proc/self/exe") {
1090 result = readlink(path.c_str(), (char *)buf.bufferPtr(), bufsiz);
1091 } else {
1092 // Emulate readlink() called on '/proc/self/exe' should return the
1093 // absolute path of the binary running in the simulated system (the
1094 // Process' executable). It is possible that using this path in
1095 // the simulated system will result in unexpected behavior if:
1096 // 1) One binary runs another (e.g., -c time -o "my_binary"), and
1097 // called binary calls readlink().
1098 // 2) The host's full path to the running benchmark changes from one
1099 // simulation to another. This can result in different simulated
1100 // performance since the simulated system will process the binary
1101 // path differently, even if the binary itself does not change.
1102
1103 // Get the absolute canonical path to the running application
1104 char real_path[PATH_MAX];
1105 char *check_real_path = realpath(p->progName(), real_path);
1106 if (!check_real_path) {
1107 fatal("readlink('/proc/self/exe') unable to resolve path to "
1108 "executable: %s", p->progName());
1109 }
1110 strncpy((char*)buf.bufferPtr(), real_path, bufsiz);
1111 typename OS::size_t real_path_len = strlen(real_path);
1112 if (real_path_len > bufsiz) {
1113 // readlink will truncate the contents of the
1114 // path to ensure it is no more than bufsiz
1115 result = bufsiz;
1116 } else {
1117 result = real_path_len;
1118 }
1119
1120 // Issue a warning about potential unexpected results
1121 warn_once("readlink() called on '/proc/self/exe' may yield unexpected "
1122 "results in various settings.\n Returning '%s'\n",
1123 (char*)buf.bufferPtr());
1124 }
1125
1127
1128 return (result == -1) ? -errno : result;
1129}
1130
1132template <class OS>
1133SyscallReturn
1135 VPtr<> pathname, VPtr<> buf_ptr,
1136 typename OS::size_t bufsiz)
1137{
1138 return readlinkatFunc<OS>(desc, tc, OS::TGT_AT_FDCWD,
1139 pathname, buf_ptr, bufsiz);
1140}
1141
1143template <class OS>
1144SyscallReturn
1146 int olddirfd, VPtr<> oldpath, int newdirfd, VPtr<> newpath)
1147{
1148 SETranslatingPortProxy proxy(tc);
1149 std::string old_name;
1150 if (!proxy.tryReadString(old_name, oldpath))
1151 return -EFAULT;
1152
1153 std::string new_name;
1154 if (!proxy.tryReadString(new_name, newpath))
1155 return -EFAULT;
1156
1157 // Modifying old_name from the directory descriptor
1158 if (auto res = atSyscallPath<OS>(tc, olddirfd, old_name); !res.successful()) {
1159 return res;
1160 }
1161
1162 // Modifying new_name from the directory descriptor
1163 if (auto res = atSyscallPath<OS>(tc, newdirfd, new_name); !res.successful()) {
1164 return res;
1165 }
1166
1167 return renameImpl(desc, tc, old_name, new_name);
1168}
1169
1171template <class OS>
1172SyscallReturn
1174 int dirfd, VPtr<> pathname, uint32_t owner, uint32_t group,
1175 int flags)
1176{
1177 std::string path;
1178 if (!SETranslatingPortProxy(tc).tryReadString(path, pathname))
1179 return -EFAULT;
1180
1181 // Modifying path from the directory descriptor
1182 if (auto res = atSyscallPath<OS>(tc, dirfd, path); !res.successful()) {
1183 return res;
1184 }
1185
1186 return chownImpl(desc, tc, path, owner, group);
1187}
1188
1190template <class OS>
1191SyscallReturn
1193 int dirfd, VPtr<> pathname, mode_t mode)
1194{
1195 std::string path;
1196 if (!SETranslatingPortProxy(tc).tryReadString(path, pathname))
1197 return -EFAULT;
1198
1199 // Modifying path from the directory descriptor
1200 if (auto res = atSyscallPath<OS>(tc, dirfd, path); !res.successful()) {
1201 return res;
1202 }
1203
1204 return mkdirImpl(desc, tc, path, mode);
1205}
1206
1208template <class OS>
1209SyscallReturn
1211 int dirfd, VPtr<> pathname, mode_t mode, dev_t dev)
1212{
1213 std::string path;
1214 if (!SETranslatingPortProxy(tc).tryReadString(path, pathname))
1215 return -EFAULT;
1216
1217 // Modifying path from the directory descriptor
1218 if (auto res = atSyscallPath<OS>(tc, dirfd, path); !res.successful()) {
1219 return res;
1220 }
1221
1222 return mknodImpl(desc, tc, path, mode, dev);
1223}
1224
1226template <class OS>
1227SyscallReturn
1230{
1231 auto process = tc->getProcessPtr();
1232
1233 sysinfo->uptime = seconds_since_epoch;
1234 sysinfo->totalram = process->system->memSize();
1235 sysinfo->mem_unit = 1;
1236
1237 return 0;
1238}
1239
1241template <class OS>
1242SyscallReturn
1244 int dirfd, VPtr<> pathname, mode_t mode)
1245{
1246 std::string path;
1247 if (!SETranslatingPortProxy(tc).tryReadString(path, pathname))
1248 return -EFAULT;
1249
1250 // Modifying path from the directory descriptor
1251 if (auto res = atSyscallPath<OS>(tc, dirfd, path); !res.successful()) {
1252 return res;
1253 }
1254
1255 mode_t hostMode = 0;
1256
1257 // XXX translate mode flags via OS::something???
1258 hostMode = mode;
1259
1260 auto process = tc->getProcessPtr();
1261 // Adjust path for cwd and redirection
1262 path = process->checkPathRedirect(path);
1263
1264 // do the chmod
1265 int result = chmod(path.c_str(), hostMode);
1266 if (result < 0)
1267 return -errno;
1268
1269 return 0;
1270}
1271
1273template <class OS>
1274SyscallReturn
1275chmodFunc(SyscallDesc *desc, ThreadContext *tc, VPtr<> pathname, mode_t mode)
1276{
1277 return fchmodatFunc<OS>(desc, tc, OS::TGT_AT_FDCWD, pathname, mode);
1278}
1279
1280template <class OS>
1281SyscallReturn
1283 VPtr<> fdsPtr, int nfds, int tmout)
1284{
1285 auto p = tc->getProcessPtr();
1286
1287 BufferArg fdsBuf(fdsPtr, sizeof(struct pollfd) * nfds);
1288 fdsBuf.copyIn(SETranslatingPortProxy(tc));
1289
1296 auto temp_tgt_fds = std::make_unique<int[]>(nfds);
1297 for (int index = 0; index < nfds; index++) {
1298 temp_tgt_fds[index] = ((struct pollfd *)fdsBuf.bufferPtr())[index].fd;
1299 int tgt_fd = temp_tgt_fds[index];
1300 auto hbfdp = std::dynamic_pointer_cast<HBFDEntry>((*p->fds)[tgt_fd]);
1301 if (!hbfdp)
1302 return -EBADF;
1303 auto host_fd = hbfdp->getSimFD();
1304 ((struct pollfd *)fdsBuf.bufferPtr())[index].fd = host_fd;
1305 }
1306
1313 int status;
1314 if (tmout < 0) {
1315 status = poll((struct pollfd *)fdsBuf.bufferPtr(), nfds, 0);
1316 if (status == 0) {
1322 System *sysh = tc->getSystemPtr();
1324 for (it=sysh->signalList.begin(); it!=sysh->signalList.end(); it++)
1325 if (it->receiver == p)
1326 return -EINTR;
1327 return SyscallReturn::retry();
1328 }
1329 } else
1330 status = poll((struct pollfd *)fdsBuf.bufferPtr(), nfds, 0);
1331
1332 if (status == -1)
1333 return -errno;
1334
1339 for (int index = 0; index < nfds; index++) {
1340 int tgt_fd = temp_tgt_fds[index];
1341 ((struct pollfd *)fdsBuf.bufferPtr())[index].fd = tgt_fd;
1342 }
1343
1348 fdsBuf.copyOut(SETranslatingPortProxy(tc));
1349
1350 return status;
1351}
1352
1354template <class OS>
1355SyscallReturn
1356fchmodFunc(SyscallDesc *desc, ThreadContext *tc, int tgt_fd, uint32_t mode)
1357{
1358 auto p = tc->getProcessPtr();
1359
1360 auto ffdp = std::dynamic_pointer_cast<FileFDEntry>((*p->fds)[tgt_fd]);
1361 if (!ffdp)
1362 return -EBADF;
1363 int sim_fd = ffdp->getSimFD();
1364
1365 mode_t hostMode = mode;
1366
1367 int result = fchmod(sim_fd, hostMode);
1368
1369 return (result < 0) ? -errno : 0;
1370}
1371
1373template <class OS>
1374SyscallReturn
1376 VPtr<> start, typename OS::size_t old_length,
1377 typename OS::size_t new_length, int flags,
1379{
1380 auto p = tc->getProcessPtr();
1381 Addr page_bytes = p->pTable->pageSize();
1382 uint64_t provided_address = 0;
1383 bool use_provided_address = flags & OS::TGT_MREMAP_FIXED;
1384
1385 if (use_provided_address)
1386 provided_address = varargs.get<uint64_t>();
1387
1388 if ((start % page_bytes != 0) ||
1389 (provided_address % page_bytes != 0)) {
1390 warn("mremap failing: arguments not page aligned");
1391 return -EINVAL;
1392 }
1393
1394 new_length = roundUp(new_length, page_bytes);
1395
1396 if (new_length > old_length) {
1397 Addr mmap_end = p->memState->getMmapEnd();
1398
1399 if ((start + old_length) == mmap_end &&
1400 (!use_provided_address || provided_address == start)) {
1401 // This case cannot occur when growing downward, as
1402 // start is greater than or equal to mmap_end.
1403 uint64_t diff = new_length - old_length;
1404 p->memState->mapRegion(mmap_end, diff, "remapped");
1405 p->memState->setMmapEnd(mmap_end + diff);
1406 return (Addr)start;
1407 } else {
1408 if (!use_provided_address && !(flags & OS::TGT_MREMAP_MAYMOVE)) {
1409 warn("can't remap here and MREMAP_MAYMOVE flag not set\n");
1410 return -ENOMEM;
1411 } else {
1412 uint64_t new_start = provided_address;
1413 if (!use_provided_address) {
1414 new_start = p->mmapGrowsDown() ?
1415 mmap_end - new_length : mmap_end;
1416 mmap_end = p->mmapGrowsDown() ?
1417 new_start : mmap_end + new_length;
1418 p->memState->setMmapEnd(mmap_end);
1419 }
1420
1421 warn("mremapping to new vaddr %08p-%08p, adding %d\n",
1422 new_start, new_start + new_length,
1423 new_length - old_length);
1424
1425 // add on the remaining unallocated pages
1426 p->allocateMem(new_start + old_length,
1427 new_length - old_length,
1428 use_provided_address /* clobber */);
1429
1430 if (use_provided_address &&
1431 ((new_start + new_length > p->memState->getMmapEnd() &&
1432 !p->mmapGrowsDown()) ||
1433 (new_start < p->memState->getMmapEnd() &&
1434 p->mmapGrowsDown()))) {
1435 // something fishy going on here, at least notify the user
1436 // @todo: increase mmap_end?
1437 warn("mmap region limit exceeded with MREMAP_FIXED\n");
1438 }
1439
1440 warn("returning %08p as start\n", new_start);
1441 p->memState->remapRegion(start, new_start, old_length);
1442 return new_start;
1443 }
1444 }
1445 } else {
1446 // Shrink a region
1447 if (use_provided_address && provided_address != start)
1448 p->memState->remapRegion(start, provided_address, new_length);
1449 if (new_length != old_length)
1450 p->memState->unmapRegion(start + new_length,
1451 old_length - new_length);
1452 return use_provided_address ? provided_address : (Addr)start;
1453 }
1454}
1455
1457template <class OS>
1458SyscallReturn
1460 VPtr<> pathname, VPtr<typename OS::tgt_stat> tgt_stat)
1461{
1462 std::string path;
1463 auto process = tc->getProcessPtr();
1464
1465 if (!SETranslatingPortProxy(tc).tryReadString(path, pathname))
1466 return -EFAULT;
1467
1468 // Adjust path for cwd and redirection
1469 path = process->checkPathRedirect(path);
1470
1471 struct stat hostBuf;
1472 int result = stat(path.c_str(), &hostBuf);
1473
1474 if (result < 0)
1475 return -errno;
1476
1477 copyOutStatBuf<OS>(tgt_stat, &hostBuf);
1478
1479 return 0;
1480}
1481
1483template <class OS>
1484SyscallReturn
1486 VPtr<> pathname, VPtr<typename OS::tgt_stat64> tgt_stat,
1487 int flags)
1488{
1489 std::string path;
1490
1491 if (!SETranslatingPortProxy(tc).tryReadString(path, pathname))
1492 return -EFAULT;
1493
1494 if (path.empty() && !(flags & OS::TGT_AT_EMPTY_PATH))
1495 return -ENOENT;
1496 flags = flags & ~OS::TGT_AT_EMPTY_PATH;
1497
1498 warn_if(flags != 0, "newfstatat: Flag bits %#x not supported.", flags);
1499
1500 // Modifying path from the directory descriptor
1501 if (auto res = atSyscallPath<OS>(tc, dirfd, path); !res.successful()) {
1502 return res;
1503 }
1504
1505 auto p = tc->getProcessPtr();
1506
1507 // Adjust path for cwd and redirection
1508 path = p->checkPathRedirect(path);
1509
1510 struct stat host_buf;
1511 int result = stat(path.c_str(), &host_buf);
1512
1513 if (result < 0)
1514 return -errno;
1515
1516 copyOutStat64Buf<OS>(tgt_stat, &host_buf);
1517
1518 return 0;
1519}
1520
1522template <class OS>
1523SyscallReturn
1525 int dirfd, VPtr<> pathname,
1527{
1528 std::string path;
1529 if (!SETranslatingPortProxy(tc).tryReadString(path, pathname))
1530 return -EFAULT;
1531
1532 // Modifying path from the directory descriptor
1533 if (auto res = atSyscallPath<OS>(tc, dirfd, path); !res.successful()) {
1534 return res;
1535 }
1536
1537 auto p = tc->getProcessPtr();
1538
1539 // Adjust path for cwd and redirection
1540 path = p->checkPathRedirect(path);
1541
1542#if NO_STAT64
1543 struct stat hostBuf;
1544 int result = stat(path.c_str(), &hostBuf);
1545#else
1546 struct stat64 hostBuf;
1547 int result = stat64(path.c_str(), &hostBuf);
1548#endif
1549
1550 if (result < 0)
1551 return -errno;
1552
1553 copyOutStat64Buf<OS>(tgt_stat, &hostBuf);
1554
1555 return 0;
1556}
1557
1559template <class OS>
1560SyscallReturn
1562 VPtr<> pathname, VPtr<typename OS::tgt_stat64> tgt_stat)
1563{
1564 return fstatat64Func<OS>(desc, tc, OS::TGT_AT_FDCWD, pathname, tgt_stat);
1565}
1566
1568template <class OS>
1569SyscallReturn
1571 int dirfd, VPtr<> pathname, int flags,
1572 unsigned int mask, VPtr<typename OS::tgt_statx> tgt_statx)
1573{
1574 std::string path;
1575
1576 if (!SETranslatingPortProxy(tc).tryReadString(path, pathname))
1577 return -EFAULT;
1578
1579 if (path.empty() && !(flags & OS::TGT_AT_EMPTY_PATH))
1580 return -ENOENT;
1581 flags = flags & ~OS::TGT_AT_EMPTY_PATH;
1582
1583 warn_if(flags != 0, "statx: Flag bits %#x not supported.", flags);
1584
1585 // Modifying path from the directory descriptor
1586 if (auto res = atSyscallPath<OS>(tc, dirfd, path); !res.successful()) {
1587 return res;
1588 }
1589
1590 auto p = tc->getProcessPtr();
1591
1592 // Adjust path for cwd and redirection
1593 path = p->checkPathRedirect(path);
1594
1595 struct stat host_buf;
1596 int result = stat(path.c_str(), &host_buf);
1597
1598 if (result < 0)
1599 return -errno;
1600
1601 copyOutStatxBuf<OS>(tgt_statx, &host_buf);
1602
1603 return 0;
1604}
1605
1607template <class OS>
1608SyscallReturn
1610 int tgt_fd, VPtr<typename OS::tgt_stat64> tgt_stat)
1611{
1612 auto p = tc->getProcessPtr();
1613
1614 auto ffdp = std::dynamic_pointer_cast<HBFDEntry>((*p->fds)[tgt_fd]);
1615 if (!ffdp)
1616 return -EBADF;
1617 int sim_fd = ffdp->getSimFD();
1618
1619#if NO_STAT64
1620 struct stat hostBuf;
1621 int result = fstat(sim_fd, &hostBuf);
1622#else
1623 struct stat64 hostBuf;
1624 int result = fstat64(sim_fd, &hostBuf);
1625#endif
1626
1627 if (result < 0)
1628 return -errno;
1629
1630 copyOutStat64Buf<OS>(tgt_stat, &hostBuf, (sim_fd == 1));
1631
1632 return 0;
1633}
1634
1635
1637template <class OS>
1638SyscallReturn
1640 VPtr<> pathname, VPtr<typename OS::tgt_stat> tgt_stat)
1641{
1642 std::string path;
1643 auto process = tc->getProcessPtr();
1644
1645 if (!SETranslatingPortProxy(tc).tryReadString(path, pathname))
1646 return -EFAULT;
1647
1648 // Adjust path for cwd and redirection
1649 path = process->checkPathRedirect(path);
1650
1651 struct stat hostBuf;
1652 int result = lstat(path.c_str(), &hostBuf);
1653
1654 if (result < 0)
1655 return -errno;
1656
1657 copyOutStatBuf<OS>(tgt_stat, &hostBuf);
1658
1659 return 0;
1660}
1661
1663template <class OS>
1664SyscallReturn
1666 VPtr<> pathname, VPtr<typename OS::tgt_stat64> tgt_stat)
1667{
1668 std::string path;
1669 auto process = tc->getProcessPtr();
1670
1671 if (!SETranslatingPortProxy(tc).tryReadString(path, pathname))
1672 return -EFAULT;
1673
1674 // Adjust path for cwd and redirection
1675 path = process->checkPathRedirect(path);
1676
1677#if NO_STAT64
1678 struct stat hostBuf;
1679 int result = lstat(path.c_str(), &hostBuf);
1680#else
1681 struct stat64 hostBuf;
1682 int result = lstat64(path.c_str(), &hostBuf);
1683#endif
1684
1685 if (result < 0)
1686 return -errno;
1687
1688 copyOutStat64Buf<OS>(tgt_stat, &hostBuf);
1689
1690 return 0;
1691}
1692
1694template <class OS>
1695SyscallReturn
1697 int tgt_fd, VPtr<typename OS::tgt_stat> tgt_stat)
1698{
1699 auto p = tc->getProcessPtr();
1700
1701 DPRINTF_SYSCALL(Verbose, "fstat(%d, ...)\n", tgt_fd);
1702
1703 auto ffdp = std::dynamic_pointer_cast<FileFDEntry>((*p->fds)[tgt_fd]);
1704 if (!ffdp)
1705 return -EBADF;
1706 int sim_fd = ffdp->getSimFD();
1707
1708 struct stat hostBuf;
1709 int result = fstat(sim_fd, &hostBuf);
1710
1711 if (result < 0)
1712 return -errno;
1713
1714 copyOutStatBuf<OS>(tgt_stat, &hostBuf, (sim_fd == 1));
1715
1716 return 0;
1717}
1718
1720template <class OS>
1721SyscallReturn
1723 VPtr<> pathname, VPtr<typename OS::tgt_statfs> tgt_stat)
1724{
1725#if defined(__linux__)
1726 std::string path;
1727 auto process = tc->getProcessPtr();
1728
1729 if (!SETranslatingPortProxy(tc).tryReadString(path, pathname))
1730 return -EFAULT;
1731
1732 // Adjust path for cwd and redirection
1733 path = process->checkPathRedirect(path);
1734
1735 struct statfs hostBuf;
1736 int result = statfs(path.c_str(), &hostBuf);
1737
1738 if (result < 0)
1739 return -errno;
1740
1741 copyOutStatfsBuf<OS>(tgt_stat, &hostBuf);
1742 return 0;
1743#else
1744 warnUnsupportedOS("statfs");
1745 return -1;
1746#endif
1747}
1748
1749template <class OS>
1750SyscallReturn
1751doClone(SyscallDesc *desc, ThreadContext *tc, RegVal flags, RegVal newStack,
1752 VPtr<> ptidPtr, VPtr<> ctidPtr, VPtr<> tlsPtr)
1753{
1754 DPRINTF(SyscallVerbose, "Doing clone. pid: %#llx, ctid: %#llx, tls: %#llx"
1755 " flags: %#llx, stack: %#llx\n",
1756 ptidPtr.addr(), ctidPtr.addr(), tlsPtr.addr(), flags, newStack);
1757 auto p = tc->getProcessPtr();
1758
1759 if (((flags & OS::TGT_CLONE_SIGHAND)&& !(flags & OS::TGT_CLONE_VM)) ||
1760 ((flags & OS::TGT_CLONE_THREAD) && !(flags & OS::TGT_CLONE_SIGHAND)) ||
1761 ((flags & OS::TGT_CLONE_FS) && (flags & OS::TGT_CLONE_NEWNS)) ||
1762 ((flags & OS::TGT_CLONE_NEWIPC) && (flags & OS::TGT_CLONE_SYSVSEM)) ||
1763 ((flags & OS::TGT_CLONE_NEWPID) && (flags & OS::TGT_CLONE_THREAD)) ||
1764 ((flags & OS::TGT_CLONE_VM) && !(newStack)))
1765 return -EINVAL;
1766
1767 ThreadContext *ctc;
1768 if (!(ctc = tc->getSystemPtr()->threads.findFree())) {
1769 DPRINTF_SYSCALL(Verbose, "clone: no spare thread context in system"
1770 "[cpu %d, thread %d]", tc->cpuId(), tc->threadId());
1771 return -EAGAIN;
1772 }
1773
1780 ProcessParams *pp = new ProcessParams();
1781 pp->executable.assign(*(new std::string(p->progName())));
1782 pp->cmd.push_back(*(new std::string(p->progName())));
1783 pp->system = p->system;
1784 pp->cwd.assign(p->tgtCwd);
1785 pp->input.assign("stdin");
1786 pp->output.assign("stdout");
1787 pp->errout.assign("stderr");
1788 pp->uid = p->uid();
1789 pp->euid = p->euid();
1790 pp->gid = p->gid();
1791 pp->egid = p->egid();
1792 pp->release = p->release;
1793
1794 /* Find the first free PID that's less than the maximum */
1795 std::set<int> const& pids = p->system->PIDs;
1796 int temp_pid = *pids.begin();
1797 do {
1798 temp_pid++;
1799 } while (pids.find(temp_pid) != pids.end());
1800 if (temp_pid >= System::maxPID)
1801 fatal("temp_pid is too large: %d", temp_pid);
1802
1803 pp->pid = temp_pid;
1804 pp->ppid = (flags & OS::TGT_CLONE_THREAD) ? p->ppid() : p->pid();
1805 pp->useArchPT = p->useArchPT;
1806 pp->kvmInSE = p->kvmInSE;
1807 Process *cp = pp->create();
1808 // TODO: there is no way to know when the Process SimObject is done with
1809 // the params pointer. Both the params pointer (pp) and the process
1810 // pointer (cp) are normally managed in python and are never cleaned up.
1811
1812 Process *owner = ctc->getProcessPtr();
1813 ctc->setProcessPtr(cp);
1814 cp->assignThreadContext(ctc->contextId());
1815 owner->revokeThreadContext(ctc->contextId());
1816
1817 if (flags & OS::TGT_CLONE_PARENT_SETTID) {
1818 BufferArg ptidBuf(ptidPtr, sizeof(long));
1819 long *ptid = (long *)ptidBuf.bufferPtr();
1820 *ptid = cp->pid();
1821 ptidBuf.copyOut(SETranslatingPortProxy(tc));
1822 }
1823
1824 if (flags & OS::TGT_CLONE_THREAD) {
1825 cp->pTable->initState();
1826 cp->pTable->shared = true;
1827 cp->useForClone = true;
1828 }
1829
1830 ctc->setUseForClone(true);
1831 cp->initState();
1832 p->clone(tc, ctc, cp, flags);
1833
1834 if (flags & OS::TGT_CLONE_THREAD) {
1835 delete cp->sigchld;
1836 cp->sigchld = p->sigchld;
1837 } else if (flags & OS::TGT_SIGCHLD) {
1838 *cp->sigchld = true;
1839 }
1840
1841 if (flags & OS::TGT_CLONE_CHILD_SETTID) {
1842 BufferArg ctidBuf(ctidPtr, sizeof(long));
1843 long *ctid = (long *)ctidBuf.bufferPtr();
1844 *ctid = cp->pid();
1845 ctidBuf.copyOut(SETranslatingPortProxy(ctc));
1846 }
1847
1848 if (flags & OS::TGT_CLONE_CHILD_CLEARTID)
1849 cp->childClearTID = (uint64_t)ctidPtr;
1850
1851 ctc->clearArchRegs();
1852
1853 OS::archClone(flags, p, cp, tc, ctc, newStack, tlsPtr);
1854
1855 desc->returnInto(ctc, 0);
1856
1857 ctc->activate();
1858
1859 if (flags & OS::TGT_CLONE_VFORK) {
1860 tc->suspend();
1861 }
1862
1863 return cp->pid();
1864}
1865
1866template <class OS>
1867SyscallReturn
1870{
1871 VPtr<uint64_t> ptidPtr((Addr)cl_args->parent_tid, tc);
1872 VPtr<uint64_t> ctidPtr((Addr)cl_args->child_tid, tc);
1873 VPtr<uint64_t> tlsPtr((Addr)cl_args->tls, tc);
1874 // Clone3 gives the stack as the *lowest* address, but clone/__clone2
1875 // expects the stack parameter to be the actual stack pointer
1876 uint64_t new_stack = cl_args->stack + cl_args->stack_size;
1877 uint64_t flags = cl_args->flags;
1878
1879 return doClone<OS>(desc, tc, flags, new_stack, ptidPtr, ctidPtr, tlsPtr);
1880}
1881
1882template <class OS>
1883SyscallReturn
1885 VPtr<> ptidPtr, VPtr<> ctidPtr, VPtr<> tlsPtr)
1886{
1887 return doClone<OS>(desc, tc, flags, newStack, ptidPtr, ctidPtr, tlsPtr);
1888}
1889
1890template <class OS>
1891SyscallReturn
1893 RegVal newStack, VPtr<> ptidPtr, VPtr<> tlsPtr,
1894 VPtr<> ctidPtr)
1895{
1896 return cloneFunc<OS>(desc, tc, flags, newStack, ptidPtr, ctidPtr, tlsPtr);
1897}
1898
1900template <class OS>
1901SyscallReturn
1903 int tgt_fd, VPtr<typename OS::tgt_statfs> tgt_stat)
1904{
1905 auto p = tc->getProcessPtr();
1906
1907 auto ffdp = std::dynamic_pointer_cast<FileFDEntry>((*p->fds)[tgt_fd]);
1908 if (!ffdp)
1909 return -EBADF;
1910 int sim_fd = ffdp->getSimFD();
1911
1912 struct statfs hostBuf;
1913 int result = fstatfs(sim_fd, &hostBuf);
1914
1915 if (result < 0)
1916 return -errno;
1917
1918 copyOutStatfsBuf<OS>(tgt_stat, &hostBuf);
1919
1920 return 0;
1921}
1922
1924template <class OS>
1925SyscallReturn
1927 int tgt_fd, VPtr<> tiov_base,
1928 typename OS::size_t count)
1929{
1930 auto p = tc->getProcessPtr();
1931
1932 auto ffdp = std::dynamic_pointer_cast<FileFDEntry>((*p->fds)[tgt_fd]);
1933 if (!ffdp)
1934 return -EBADF;
1935 int sim_fd = ffdp->getSimFD();
1936
1937 SETranslatingPortProxy prox(tc);
1938 auto tiov = std::make_unique<typename OS::tgt_iovec[]>(count);
1939 auto hiov = std::make_unique<struct iovec[]>(count);
1940 for (typename OS::size_t i = 0; i < count; ++i) {
1941 prox.readBlob(tiov_base + (i * sizeof(typename OS::tgt_iovec)),
1942 &tiov[i], sizeof(typename OS::tgt_iovec));
1943 hiov[i].iov_len = gtoh(tiov[i].iov_len, OS::byteOrder);
1944 hiov[i].iov_base = new char [hiov[i].iov_len];
1945 }
1946
1947 int result = readv(sim_fd, hiov.get(), count);
1948 int local_errno = errno;
1949
1950 for (typename OS::size_t i = 0; i < count; ++i) {
1951 if (result != -1) {
1952 prox.writeBlob(htog(tiov[i].iov_base, OS::byteOrder),
1953 hiov[i].iov_base, hiov[i].iov_len);
1954 }
1955 delete [] (char *)hiov[i].iov_base;
1956 }
1957
1958 return (result == -1) ? -local_errno : result;
1959}
1960
1962template <class OS>
1963SyscallReturn
1965 int tgt_fd, VPtr<> tiov_base,
1966 typename OS::size_t count)
1967{
1968 auto p = tc->getProcessPtr();
1969
1970 auto hbfdp = std::dynamic_pointer_cast<HBFDEntry>((*p->fds)[tgt_fd]);
1971 if (!hbfdp)
1972 return -EBADF;
1973 int sim_fd = hbfdp->getSimFD();
1974
1975 SETranslatingPortProxy prox(tc);
1976 auto hiov = std::make_unique<struct iovec[]>(count);
1977 for (typename OS::size_t i = 0; i < count; ++i) {
1978 typename OS::tgt_iovec tiov;
1979
1980 prox.readBlob(tiov_base + i*sizeof(typename OS::tgt_iovec),
1981 &tiov, sizeof(typename OS::tgt_iovec));
1982 hiov[i].iov_len = gtoh(tiov.iov_len, OS::byteOrder);
1983 hiov[i].iov_base = new char [hiov[i].iov_len];
1984 prox.readBlob(gtoh(tiov.iov_base, OS::byteOrder), hiov[i].iov_base,
1985 hiov[i].iov_len);
1986 }
1987
1988 int result = writev(sim_fd, hiov.get(), count);
1989
1990 for (typename OS::size_t i = 0; i < count; ++i)
1991 delete [] (char *)hiov[i].iov_base;
1992
1993 return (result == -1) ? -errno : result;
1994}
1995
1997template <class OS>
1998SyscallReturn
2000 VPtr<> start, typename OS::size_t length, int prot,
2001 int tgt_flags, int tgt_fd, typename OS::off_t offset)
2002{
2003 auto p = tc->getProcessPtr();
2004 Addr page_bytes = p->pTable->pageSize();
2005
2006 if (start & (page_bytes - 1) ||
2007 offset & (page_bytes - 1) ||
2008 (tgt_flags & OS::TGT_MAP_PRIVATE &&
2009 tgt_flags & OS::TGT_MAP_SHARED) ||
2010 (!(tgt_flags & OS::TGT_MAP_PRIVATE) &&
2011 !(tgt_flags & OS::TGT_MAP_SHARED)) ||
2012 !length) {
2013 return -EINVAL;
2014 }
2015
2016 if ((prot & PROT_WRITE) && (tgt_flags & OS::TGT_MAP_SHARED)) {
2017 // With shared mmaps, there are two cases to consider:
2018 // 1) anonymous: writes should modify the mapping and this should be
2019 // visible to observers who share the mapping. Currently, it's
2020 // difficult to update the shared mapping because there's no
2021 // structure which maintains information about the which virtual
2022 // memory areas are shared. If that structure existed, it would be
2023 // possible to make the translations point to the same frames.
2024 // 2) file-backed: writes should modify the mapping and the file
2025 // which is backed by the mapping. The shared mapping problem is the
2026 // same as what was mentioned about the anonymous mappings. For
2027 // file-backed mappings, the writes to the file are difficult
2028 // because it requires syncing what the mapping holds with the file
2029 // that resides on the host system. So, any write on a real system
2030 // would cause the change to be propagated to the file mapping at
2031 // some point in the future (the inode is tracked along with the
2032 // mapping). This isn't guaranteed to always happen, but it usually
2033 // works well enough. The guarantee is provided by the msync system
2034 // call. We could force the change through with shared mappings with
2035 // a call to msync, but that again would require more information
2036 // than we currently maintain.
2037 warn_once("mmap: writing to shared mmap region is currently "
2038 "unsupported. The write succeeds on the target, but it "
2039 "will not be propagated to the host or shared mappings");
2040 }
2041
2042 length = roundUp(length, page_bytes);
2043
2044 int sim_fd = -1;
2045 if (!(tgt_flags & OS::TGT_MAP_ANONYMOUS)) {
2046 std::shared_ptr<FDEntry> fdep = (*p->fds)[tgt_fd];
2047
2048 auto dfdp = std::dynamic_pointer_cast<DeviceFDEntry>(fdep);
2049 if (dfdp) {
2050 EmulatedDriver *emul_driver = dfdp->getDriver();
2051 return emul_driver->mmap(tc, start, length, prot, tgt_flags,
2052 tgt_fd, offset);
2053 }
2054
2055 auto ffdp = std::dynamic_pointer_cast<FileFDEntry>(fdep);
2056 if (!ffdp)
2057 return -EBADF;
2058 sim_fd = ffdp->getSimFD();
2059
2068 if (p->interpImage.contains(tc->pcState().instAddr())) {
2069 std::shared_ptr<FDEntry> fdep = (*p->fds)[tgt_fd];
2070 auto ffdp = std::dynamic_pointer_cast<FileFDEntry>(fdep);
2071 auto *lib = loader::createObjectFile(p->checkPathRedirect(
2072 ffdp->getFileName()));
2073 DPRINTF_SYSCALL(Verbose, "Loading symbols from %s\n",
2074 ffdp->getFileName());
2075
2076 if (lib) {
2077 Addr offset = lib->buildImage().minAddr() + start;
2078 loader::debugSymbolTable.insert(*lib->symtab().offset(offset));
2079 }
2080 }
2081 }
2082
2086 if (!(tgt_flags & OS::TGT_MAP_FIXED)) {
2094 if (!(start && p->memState->isUnmapped(start, length))) {
2098 start = p->memState->extendMmap(length);
2099 }
2100 }
2101
2102 DPRINTF_SYSCALL(Verbose, " mmap range is 0x%x - 0x%x\n",
2103 start, start + length - 1);
2104
2110 if (tgt_flags & OS::TGT_MAP_FIXED) {
2115 p->memState->unmapRegion(start, length);
2116 }
2117
2121 std::string region_name;
2122 if (tgt_flags & OS::TGT_MAP_ANONYMOUS) {
2123 region_name = "anon";
2124 } else {
2125 std::shared_ptr<FDEntry> fdep = (*p->fds)[tgt_fd];
2126 auto ffdp = std::dynamic_pointer_cast<FileFDEntry>(fdep);
2127 region_name = ffdp->getFileName();
2128 }
2129
2134 p->memState->mapRegion(start, length, region_name, sim_fd, offset);
2135
2136 return (Addr)start;
2137}
2138
2139template <class OS>
2140SyscallReturn
2142 int tgt_fd, VPtr<> bufPtr, typename OS::size_t nbytes,
2143 typename OS::off_t offset)
2144{
2145 auto p = tc->getProcessPtr();
2146
2147 auto ffdp = std::dynamic_pointer_cast<FileFDEntry>((*p->fds)[tgt_fd]);
2148 if (!ffdp)
2149 return -EBADF;
2150 int sim_fd = ffdp->getSimFD();
2151
2152 BufferArg bufArg(bufPtr, nbytes);
2153
2154 int bytes_read = pread(sim_fd, bufArg.bufferPtr(), nbytes, offset);
2155
2156 bufArg.copyOut(SETranslatingPortProxy(tc));
2157
2158 return (bytes_read == -1) ? -errno : bytes_read;
2159}
2160
2161template <class OS>
2162SyscallReturn
2164 int tgt_fd, VPtr<> bufPtr, typename OS::size_t nbytes,
2165 typename OS::off_t offset)
2166{
2167 auto p = tc->getProcessPtr();
2168
2169 auto ffdp = std::dynamic_pointer_cast<FileFDEntry>((*p->fds)[tgt_fd]);
2170 if (!ffdp)
2171 return -EBADF;
2172 int sim_fd = ffdp->getSimFD();
2173
2174 BufferArg bufArg(bufPtr, nbytes);
2175 bufArg.copyIn(SETranslatingPortProxy(tc));
2176
2177 int bytes_written = pwrite(sim_fd, bufArg.bufferPtr(), nbytes, offset);
2178
2179 return (bytes_written == -1) ? -errno : bytes_written;
2180}
2181
2183template <class OS>
2184SyscallReturn
2186 VPtr<> start, typename OS::size_t length, int prot,
2187 int tgt_flags, int tgt_fd, typename OS::off_t offset)
2188{
2189 auto page_size = tc->getProcessPtr()->pTable->pageSize();
2190 return mmapFunc<OS>(desc, tc, start, length, prot, tgt_flags,
2191 tgt_fd, offset * page_size);
2192}
2193
2195template <class OS>
2196SyscallReturn
2198 unsigned resource, VPtr<typename OS::rlimit> rlp)
2199{
2200 const ByteOrder bo = OS::byteOrder;
2201 switch (resource) {
2202 case OS::TGT_RLIMIT_STACK:
2203 // max stack size in bytes: make up a number (8MiB for now)
2204 rlp->rlim_cur = rlp->rlim_max = 8 * 1024 * 1024;
2205 rlp->rlim_cur = htog(rlp->rlim_cur, bo);
2206 rlp->rlim_max = htog(rlp->rlim_max, bo);
2207 break;
2208
2209 case OS::TGT_RLIMIT_DATA:
2210 // max data segment size in bytes: make up a number
2211 rlp->rlim_cur = rlp->rlim_max = 256 * 1024 * 1024;
2212 rlp->rlim_cur = htog(rlp->rlim_cur, bo);
2213 rlp->rlim_max = htog(rlp->rlim_max, bo);
2214 break;
2215
2216 case OS::TGT_RLIMIT_NPROC:
2217 rlp->rlim_cur = rlp->rlim_max = tc->getSystemPtr()->threads.size();
2218 rlp->rlim_cur = htog(rlp->rlim_cur, bo);
2219 rlp->rlim_max = htog(rlp->rlim_max, bo);
2220 break;
2221
2222 default:
2223 warn("getrlimit: unimplemented resource %d", resource);
2224 return -EINVAL;
2225 break;
2226 }
2227
2228 return 0;
2229}
2230
2231template <class OS>
2232SyscallReturn
2234 int pid, int resource, VPtr<> n, VPtr<typename OS::rlimit> rlp)
2235{
2236 if (pid != 0) {
2237 warn("prlimit: ignoring rlimits for nonzero pid");
2238 return -EPERM;
2239 }
2240 if (n)
2241 warn("prlimit: ignoring new rlimit");
2242 if (rlp) {
2243 const ByteOrder bo = OS::byteOrder;
2244 switch (resource) {
2245 case OS::TGT_RLIMIT_STACK:
2246 // max stack size in bytes: make up a number (8MiB for now)
2247 rlp->rlim_cur = rlp->rlim_max = 8 * 1024 * 1024;
2248 rlp->rlim_cur = htog(rlp->rlim_cur, bo);
2249 rlp->rlim_max = htog(rlp->rlim_max, bo);
2250 break;
2251 case OS::TGT_RLIMIT_DATA:
2252 // max data segment size in bytes: make up a number
2253 rlp->rlim_cur = rlp->rlim_max = 256*1024*1024;
2254 rlp->rlim_cur = htog(rlp->rlim_cur, bo);
2255 rlp->rlim_max = htog(rlp->rlim_max, bo);
2256 break;
2257 default:
2258 warn("prlimit: unimplemented resource %d", resource);
2259 return -EINVAL;
2260 break;
2261 }
2262 }
2263 return 0;
2264}
2265
2267template <class OS>
2268SyscallReturn
2270 int clk_id, VPtr<typename OS::timespec> tp)
2271{
2272 getElapsedTimeNano(tp->tv_sec, tp->tv_nsec);
2273 tp->tv_sec += seconds_since_epoch;
2274 tp->tv_sec = htog(tp->tv_sec, OS::byteOrder);
2275 tp->tv_nsec = htog(tp->tv_nsec, OS::byteOrder);
2276
2277 return 0;
2278}
2279
2281template <class OS>
2282SyscallReturn
2285{
2286 // Set resolution at ns, which is what clock_gettime() returns
2287 tp->tv_sec = 0;
2288 tp->tv_nsec = 1;
2289
2290 return 0;
2291}
2292
2294template <class OS>
2295SyscallReturn
2298{
2299 getElapsedTimeMicro(tp->tv_sec, tp->tv_usec);
2300 tp->tv_sec += seconds_since_epoch;
2301 tp->tv_sec = htog(tp->tv_sec, OS::byteOrder);
2302 tp->tv_usec = htog(tp->tv_usec, OS::byteOrder);
2303
2304 return 0;
2305}
2306
2308template <class OS>
2309SyscallReturn
2311 int dirfd, VPtr<> pathname, VPtr<typename OS::timeval [2]> tp)
2312{
2313 std::string path;
2314 if (!SETranslatingPortProxy(tc).tryReadString(path, pathname))
2315 return -EFAULT;
2316
2317 // Modifying path from the directory descriptor
2318 if (auto res = atSyscallPath<OS>(tc, dirfd, path); !res.successful()) {
2319 return res;
2320 }
2321
2322 struct timeval hostTimeval[2];
2323 for (int i = 0; i < 2; ++i) {
2324 hostTimeval[i].tv_sec = gtoh((*tp)[i].tv_sec, OS::byteOrder);
2325 hostTimeval[i].tv_usec = gtoh((*tp)[i].tv_usec, OS::byteOrder);
2326 }
2327
2328 // Adjust path for cwd and redirection
2329 auto process = tc->getProcessPtr();
2330 path = process->checkPathRedirect(path);
2331
2332 int result = utimes(path.c_str(), hostTimeval);
2333
2334 if (result < 0)
2335 return -errno;
2336
2337 return 0;
2338}
2339
2341template <class OS>
2342SyscallReturn
2344 VPtr<typename OS::timeval [2]> tp)
2345{
2346 return futimesatFunc<OS>(desc, tc, OS::TGT_AT_FDCWD, pathname, tp);
2347}
2348
2349template <class OS>
2350SyscallReturn
2352 VPtr<> pathname, VPtr<> argv_mem_loc, VPtr<> envp_mem_loc)
2353{
2354 auto p = tc->getProcessPtr();
2355
2356 std::string path;
2357 SETranslatingPortProxy mem_proxy(tc);
2358 if (!mem_proxy.tryReadString(path, pathname))
2359 return -EFAULT;
2360
2361 if (access(path.c_str(), F_OK) == -1)
2362 return -EACCES;
2363
2364 auto read_in = [](std::vector<std::string> &vect,
2365 PortProxy &mem_proxy, VPtr<> mem_loc)
2366 {
2367 for (int inc = 0; ; inc++) {
2368 BufferArg b((mem_loc + sizeof(Addr) * inc), sizeof(Addr));
2369 b.copyIn(mem_proxy);
2370
2371 if (!*(Addr*)b.bufferPtr())
2372 break;
2373
2374 vect.push_back(std::string());
2375 mem_proxy.tryReadString(vect[inc], *(Addr*)b.bufferPtr());
2376 }
2377 };
2378
2383 if (!p->vforkContexts.empty()) {
2384 ThreadContext *vtc = p->system->threads[p->vforkContexts.front()];
2385 assert(vtc->status() == ThreadContext::Suspended);
2386 vtc->activate();
2387 }
2388
2395 ProcessParams *pp = new ProcessParams();
2396 pp->executable = path;
2397 read_in(pp->cmd, mem_proxy, argv_mem_loc);
2398 read_in(pp->env, mem_proxy, envp_mem_loc);
2399 pp->uid = p->uid();
2400 pp->egid = p->egid();
2401 pp->euid = p->euid();
2402 pp->gid = p->gid();
2403 pp->ppid = p->ppid();
2404 pp->pid = p->pid();
2405 pp->input.assign("cin");
2406 pp->output.assign("cout");
2407 pp->errout.assign("cerr");
2408 pp->cwd.assign(p->tgtCwd);
2409 pp->system = p->system;
2410 pp->release = p->release;
2411 pp->maxStackSize = p->memState->getMaxStackSize();
2420 p->system->PIDs.erase(p->pid());
2421 Process *new_p = pp->create();
2422 // TODO: there is no way to know when the Process SimObject is done with
2423 // the params pointer. Both the params pointer (pp) and the process
2424 // pointer (p) are normally managed in python and are never cleaned up.
2425
2430 new_p->fds = p->fds;
2431 for (int i = 0; i < new_p->fds->getSize(); i++) {
2432 std::shared_ptr<FDEntry> fdep = (*new_p->fds)[i];
2433 if (fdep && fdep->getCOE())
2434 new_p->fds->closeFDEntry(i);
2435 }
2436
2437 *new_p->sigchld = true;
2438
2439 tc->clearArchRegs();
2440 tc->setProcessPtr(new_p);
2441 new_p->assignThreadContext(tc->contextId());
2442 new_p->init();
2443 new_p->initState();
2444 tc->activate();
2445
2446 return SyscallReturn();
2447}
2448
2450template <class OS>
2451SyscallReturn
2453 int who /* THREAD, SELF, or CHILDREN */,
2455{
2456 rup->ru_utime.tv_sec = 0;
2457 rup->ru_utime.tv_usec = 0;
2458 rup->ru_stime.tv_sec = 0;
2459 rup->ru_stime.tv_usec = 0;
2460 rup->ru_maxrss = 0;
2461 rup->ru_ixrss = 0;
2462 rup->ru_idrss = 0;
2463 rup->ru_isrss = 0;
2464 rup->ru_minflt = 0;
2465 rup->ru_majflt = 0;
2466 rup->ru_nswap = 0;
2467 rup->ru_inblock = 0;
2468 rup->ru_oublock = 0;
2469 rup->ru_msgsnd = 0;
2470 rup->ru_msgrcv = 0;
2471 rup->ru_nsignals = 0;
2472 rup->ru_nvcsw = 0;
2473 rup->ru_nivcsw = 0;
2474
2475 switch (who) {
2476 case OS::TGT_RUSAGE_SELF:
2477 getElapsedTimeMicro(rup->ru_utime.tv_sec, rup->ru_utime.tv_usec);
2478 rup->ru_utime.tv_sec = htog(rup->ru_utime.tv_sec, OS::byteOrder);
2479 rup->ru_utime.tv_usec = htog(rup->ru_utime.tv_usec, OS::byteOrder);
2480 break;
2481
2482 case OS::TGT_RUSAGE_CHILDREN:
2483 // do nothing. We have no child processes, so they take no time.
2484 break;
2485
2486 default:
2487 // don't really handle THREAD or CHILDREN, but just warn and
2488 // plow ahead
2489 warn("getrusage() only supports RUSAGE_SELF. Parameter %d ignored.",
2490 who);
2491 }
2492
2493 return 0;
2494}
2495
2497template <class OS>
2498SyscallReturn
2500{
2501 // Fill in the time structure (in clocks)
2502 int64_t clocks = curTick() * OS::M5_SC_CLK_TCK / sim_clock::as_int::s;
2503 bufp->tms_utime = clocks;
2504 bufp->tms_stime = 0;
2505 bufp->tms_cutime = 0;
2506 bufp->tms_cstime = 0;
2507
2508 // Convert to host endianness
2509 bufp->tms_utime = htog(bufp->tms_utime, OS::byteOrder);
2510
2511 // Return clock ticks since system boot
2512 return clocks;
2513}
2514
2516template <class OS>
2517SyscallReturn
2519{
2520 typename OS::time_t sec, usec;
2521 getElapsedTimeMicro(sec, usec);
2522 sec += seconds_since_epoch;
2523
2525 if (taddr != 0) {
2526 typename OS::time_t t = sec;
2527 t = htog(t, OS::byteOrder);
2528 p.writeBlob(taddr, &t, (int)sizeof(typename OS::time_t));
2529 }
2530 return sec;
2531}
2532
2533template <class OS>
2534SyscallReturn
2535tgkillFunc(SyscallDesc *desc, ThreadContext *tc, int tgid, int tid, int sig)
2536{
2551
2552 System *sys = tc->getSystemPtr();
2553 Process *tgt_proc = nullptr;
2554 for (auto *tc: sys->threads) {
2555 Process *temp = tc->getProcessPtr();
2556 if (temp->pid() == tid) {
2557 tgt_proc = temp;
2558 break;
2559 }
2560 }
2561
2562 if (sig != 0 && sig != OS::TGT_SIGABRT)
2563 return -EINVAL;
2564
2565 if (tgt_proc == nullptr)
2566 return -ESRCH;
2567
2568 if (tgid != -1 && tgt_proc->tgid() != tgid)
2569 return -ESRCH;
2570
2571 if (sig == OS::TGT_SIGABRT)
2572 exitGroupFunc(desc, tc, 0);
2573
2574 return 0;
2575}
2576
2577template <class OS>
2578SyscallReturn
2580 int domain, int type, int prot)
2581{
2582 auto p = tc->getProcessPtr();
2583
2584 int sim_fd = socket(domain, type, prot);
2585 if (sim_fd == -1)
2586 return -errno;
2587
2588 auto sfdp = std::make_shared<SocketFDEntry>(sim_fd, domain, type, prot);
2589 int tgt_fd = p->fds->allocFD(sfdp);
2590
2591 return tgt_fd;
2592}
2593
2594template <class OS>
2595SyscallReturn
2597 int domain, int type, int prot, VPtr<> svPtr)
2598{
2599 auto p = tc->getProcessPtr();
2600
2601 BufferArg svBuf((Addr)svPtr, 2 * sizeof(int));
2602 int status = socketpair(domain, type, prot, (int *)svBuf.bufferPtr());
2603 if (status == -1)
2604 return -errno;
2605
2606 int *fds = (int *)svBuf.bufferPtr();
2607
2608 auto sfdp1 = std::make_shared<SocketFDEntry>(fds[0], domain, type, prot);
2609 fds[0] = p->fds->allocFD(sfdp1);
2610 auto sfdp2 = std::make_shared<SocketFDEntry>(fds[1], domain, type, prot);
2611 fds[1] = p->fds->allocFD(sfdp2);
2613
2614 return status;
2615}
2616
2617template <class OS>
2618SyscallReturn
2624{
2625 int retval;
2626
2627 auto p = tc->getProcessPtr();
2628
2634 fd_set readfds_h;
2635 FD_ZERO(&readfds_h);
2636 fd_set writefds_h;
2637 FD_ZERO(&writefds_h);
2638 fd_set errorfds_h;
2639 FD_ZERO(&errorfds_h);
2640
2650 int nfds_h = 0;
2651 std::map<int, int> trans_map;
2652 auto try_add_host_set = [&](typename OS::fd_set *tgt_set_entry,
2653 fd_set *hst_set_entry,
2654 int iter) -> bool
2655 {
2661 if (FD_ISSET(iter, (fd_set *)tgt_set_entry)) {
2667 auto hbfdp = std::dynamic_pointer_cast<HBFDEntry>((*p->fds)[iter]);
2668 if (!hbfdp)
2669 return true;
2670 auto sim_fd = hbfdp->getSimFD();
2671
2677 trans_map[sim_fd] = iter;
2678
2684 nfds_h = std::max(nfds_h - 1, sim_fd + 1);
2685
2690 FD_SET(sim_fd, hst_set_entry);
2691 }
2692 return false;
2693 };
2694
2695 for (int i = 0; i < nfds; i++) {
2696 if (readfds) {
2697 bool ebadf = try_add_host_set(readfds, &readfds_h, i);
2698 if (ebadf)
2699 return -EBADF;
2700 }
2701 if (writefds) {
2702 bool ebadf = try_add_host_set(writefds, &writefds_h, i);
2703 if (ebadf)
2704 return -EBADF;
2705 }
2706 if (errorfds) {
2707 bool ebadf = try_add_host_set(errorfds, &errorfds_h, i);
2708 if (ebadf)
2709 return -EBADF;
2710 }
2711 }
2712
2713 if (timeout) {
2721 timeout->tv_sec = 0;
2722 timeout->tv_usec = 0;
2723
2724 retval = select(nfds_h,
2725 readfds ? &readfds_h : nullptr,
2726 writefds ? &writefds_h : nullptr,
2727 errorfds ? &errorfds_h : nullptr,
2728 (timeval *)(typename OS::timeval *)timeout);
2729 } else {
2737 struct timeval tv = { 0, 0 };
2738
2739 retval = select(nfds_h,
2740 readfds ? &readfds_h : nullptr,
2741 readfds ? &writefds_h : nullptr,
2742 readfds ? &errorfds_h : nullptr,
2743 &tv);
2744
2745 if (retval == 0) {
2751 for (auto sig : tc->getSystemPtr()->signalList)
2752 if (sig.receiver == p)
2753 return -EINTR;
2754 return SyscallReturn::retry();
2755 }
2756 }
2757
2758 if (retval == -1)
2759 return -errno;
2760
2761 if (readfds) {
2762 FD_ZERO(reinterpret_cast<fd_set *>((typename OS::fd_set *)readfds));
2763 }
2764 if (writefds) {
2765 FD_ZERO(reinterpret_cast<fd_set *>((typename OS::fd_set *)writefds));
2766 }
2767 if (errorfds) {
2768 FD_ZERO(reinterpret_cast<fd_set *>((typename OS::fd_set *)errorfds));
2769 }
2770
2776 for (int i = 0; i < nfds_h; i++) {
2777 if (readfds && FD_ISSET(i, &readfds_h))
2778 FD_SET(trans_map[i],
2779 reinterpret_cast<fd_set *>(
2780 (typename OS::fd_set *)readfds));
2781
2782 if (writefds && FD_ISSET(i, &writefds_h))
2783 FD_SET(trans_map[i],
2784 reinterpret_cast<fd_set *>(
2785 (typename OS::fd_set *)writefds));
2786
2787 if (errorfds && FD_ISSET(i, &errorfds_h))
2788 FD_SET(trans_map[i],
2789 reinterpret_cast<fd_set *>(
2790 (typename OS::fd_set *)errorfds));
2791 }
2792
2793 return retval;
2794}
2795
2796template <class OS>
2797SyscallReturn
2799 int tgt_fd, VPtr<> buf_ptr, typename OS::size_t nbytes)
2800{
2801 auto p = tc->getProcessPtr();
2802
2803 auto hbfdp = std::dynamic_pointer_cast<HBFDEntry>((*p->fds)[tgt_fd]);
2804 if (!hbfdp)
2805 return -EBADF;
2806 int sim_fd = hbfdp->getSimFD();
2807
2808 struct pollfd pfd;
2809 pfd.fd = sim_fd;
2810 pfd.events = POLLIN | POLLPRI;
2811 if ((poll(&pfd, 1, 0) == 0)
2812 && !(hbfdp->getFlags() & OS::TGT_O_NONBLOCK))
2813 return SyscallReturn::retry();
2814
2815 BufferArg buf_arg(buf_ptr, nbytes);
2816 int bytes_read = read(sim_fd, buf_arg.bufferPtr(), nbytes);
2817
2818 if (bytes_read > 0)
2819 buf_arg.copyOut(SETranslatingPortProxy(tc));
2820
2821 return (bytes_read == -1) ? -errno : bytes_read;
2822}
2823
2824template <class OS>
2825SyscallReturn
2827 int tgt_fd, VPtr<> buf_ptr, typename OS::size_t nbytes)
2828{
2829 auto p = tc->getProcessPtr();
2830
2831 auto hbfdp = std::dynamic_pointer_cast<HBFDEntry>((*p->fds)[tgt_fd]);
2832 if (!hbfdp)
2833 return -EBADF;
2834 int sim_fd = hbfdp->getSimFD();
2835
2836 BufferArg buf_arg(buf_ptr, nbytes);
2837 buf_arg.copyIn(SETranslatingPortProxy(tc));
2838
2839 struct pollfd pfd;
2840 pfd.fd = sim_fd;
2841 pfd.events = POLLOUT;
2842
2849 auto ffdp = std::dynamic_pointer_cast<FileFDEntry>(hbfdp);
2850 if (ffdp && (ffdp->getFileName() != "/dev/random")) {
2851 if (!poll(&pfd, 1, 0) && !(ffdp->getFlags() & OS::TGT_O_NONBLOCK))
2852 return SyscallReturn::retry();
2853 }
2854
2855 int bytes_written = write(sim_fd, buf_arg.bufferPtr(), nbytes);
2856
2857 if (bytes_written != -1)
2858 fsync(sim_fd);
2859
2860 return (bytes_written == -1) ? -errno : bytes_written;
2861}
2862
2863template <class OS>
2864SyscallReturn
2866 pid_t pid, VPtr<> statPtr, int options, VPtr<> rusagePtr)
2867{
2868 auto p = tc->getProcessPtr();
2869
2870 if (rusagePtr)
2871 DPRINTF_SYSCALL(Verbose, "wait4: rusage pointer provided %lx, however "
2872 "functionality not supported. Ignoring rusage pointer.\n",
2873 rusagePtr);
2874
2883 System *sysh = tc->getSystemPtr();
2885 for (iter=sysh->signalList.begin(); iter!=sysh->signalList.end(); iter++) {
2886 if (iter->receiver == p) {
2887 if (pid < -1) {
2888 if ((iter->sender->pgid() == -pid)
2889 && (iter->signalValue == OS::TGT_SIGCHLD))
2890 goto success;
2891 } else if (pid == -1) {
2892 if (iter->signalValue == OS::TGT_SIGCHLD)
2893 goto success;
2894 } else if (pid == 0) {
2895 if ((iter->sender->pgid() == p->pgid())
2896 && (iter->signalValue == OS::TGT_SIGCHLD))
2897 goto success;
2898 } else {
2899 if ((iter->sender->pid() == pid)
2900 && (iter->signalValue == OS::TGT_SIGCHLD))
2901 goto success;
2902 }
2903 }
2904 }
2905
2906 return (options & OS::TGT_WNOHANG) ? 0 : SyscallReturn::retry();
2907
2908success:
2909 // Set status to EXITED for WIFEXITED evaluations.
2910 const int EXITED = 0;
2911 BufferArg statusBuf(statPtr, sizeof(int));
2912 *(int *)statusBuf.bufferPtr() = EXITED;
2913 statusBuf.copyOut(SETranslatingPortProxy(tc));
2914
2915 // Return the child PID.
2916 pid_t retval = iter->sender->pid();
2917 sysh->signalList.erase(iter);
2918 return retval;
2919}
2920
2921template <class OS>
2922SyscallReturn
2924 int tgt_fd, VPtr<> addrPtr, VPtr<> lenPtr)
2925{
2926 struct sockaddr sa;
2927 socklen_t addrLen;
2928 int host_fd;
2929 auto p = tc->getProcessPtr();
2930
2931 BufferArg *lenBufPtr = nullptr;
2932 BufferArg *addrBufPtr = nullptr;
2933
2934 auto sfdp = std::dynamic_pointer_cast<SocketFDEntry>((*p->fds)[tgt_fd]);
2935 if (!sfdp)
2936 return -EBADF;
2937 int sim_fd = sfdp->getSimFD();
2938
2945 struct pollfd pfd;
2946 pfd.fd = sim_fd;
2947 pfd.events = POLLIN | POLLPRI;
2948 if ((poll(&pfd, 1, 0) == 0) && !(sfdp->getFlags() & OS::TGT_O_NONBLOCK))
2949 return SyscallReturn::retry();
2950
2951 if (lenPtr) {
2952 lenBufPtr = new BufferArg(lenPtr, sizeof(socklen_t));
2953 lenBufPtr->copyIn(SETranslatingPortProxy(tc));
2954 memcpy(&addrLen, (socklen_t *)lenBufPtr->bufferPtr(),
2955 sizeof(socklen_t));
2956 }
2957
2958 if (addrPtr) {
2959 addrBufPtr = new BufferArg(addrPtr, sizeof(struct sockaddr));
2960 addrBufPtr->copyIn(SETranslatingPortProxy(tc));
2961 memcpy(&sa, (struct sockaddr *)addrBufPtr->bufferPtr(),
2962 sizeof(struct sockaddr));
2963 }
2964
2965 host_fd = accept(sim_fd, &sa, &addrLen);
2966
2967 if (host_fd == -1)
2968 return -errno;
2969
2970 if (addrPtr) {
2971 memcpy(addrBufPtr->bufferPtr(), &sa, sizeof(sa));
2972 addrBufPtr->copyOut(SETranslatingPortProxy(tc));
2973 delete(addrBufPtr);
2974 }
2975
2976 if (lenPtr) {
2977 *(socklen_t *)lenBufPtr->bufferPtr() = addrLen;
2978 lenBufPtr->copyOut(SETranslatingPortProxy(tc));
2979 delete(lenBufPtr);
2980 }
2981
2982 auto afdp = std::make_shared<SocketFDEntry>(host_fd, sfdp->_domain,
2983 sfdp->_type, sfdp->_protocol);
2984 return p->fds->allocFD(afdp);
2985}
2986
2988template <class OS>
2989SyscallReturn
2991 unsigned initval, int in_flags)
2992{
2993#if defined(__linux__)
2994 auto p = tc->getProcessPtr();
2995
2996 int sim_fd = eventfd(initval, in_flags);
2997 if (sim_fd == -1)
2998 return -errno;
2999
3000 bool cloexec = in_flags & OS::TGT_O_CLOEXEC;
3001
3002 int flags = cloexec ? OS::TGT_O_CLOEXEC : 0;
3003 flags |= (in_flags & OS::TGT_O_NONBLOCK) ? OS::TGT_O_NONBLOCK : 0;
3004
3005 auto hbfdp = std::make_shared<HBFDEntry>(flags, sim_fd, cloexec);
3006 int tgt_fd = p->fds->allocFD(hbfdp);
3007 return tgt_fd;
3008#else
3009 warnUnsupportedOS("eventfd");
3010 return -1;
3011#endif
3012}
3013
3015template <class OS>
3016SyscallReturn
3018 pid_t pid, typename OS::size_t cpusetsize,
3019 VPtr<> cpu_set_mask)
3020{
3021#if defined(__linux__)
3022 if (cpusetsize < CPU_ALLOC_SIZE(tc->getSystemPtr()->threads.size()))
3023 return -EINVAL;
3024
3025 SETranslatingPortProxy proxy(tc);
3026 BufferArg maskBuf(cpu_set_mask, cpusetsize);
3027 maskBuf.copyIn(proxy);
3028 for (int i = 0; i < tc->getSystemPtr()->threads.size(); i++) {
3029 CPU_SET(i, (cpu_set_t *)maskBuf.bufferPtr());
3030 }
3031 maskBuf.copyOut(proxy);
3032 return CPU_ALLOC_SIZE(tc->getSystemPtr()->threads.size());
3033#else
3034 warnUnsupportedOS("sched_getaffinity");
3035 return -1;
3036#endif
3037}
3038
3039// Target recvfrom() handler.
3040template <class OS>
3041SyscallReturn
3043 int tgt_fd, VPtr<> buf_ptr, typename OS::size_t buf_len,
3044 int flags, VPtr<> addr_ptr, VPtr<> addrlen_ptr)
3045{
3046 auto p = tc->getProcessPtr();
3047
3048 auto sfdp = std::dynamic_pointer_cast<SocketFDEntry>((*p->fds)[tgt_fd]);
3049 if (!sfdp)
3050 return -EBADF;
3051 int sim_fd = sfdp->getSimFD();
3052
3053 // Reserve buffer space.
3054 BufferArg buf(buf_ptr, buf_len);
3055
3056 SETranslatingPortProxy proxy(tc);
3057
3058 // Get address length.
3059 socklen_t addr_len = 0;
3060 if (addrlen_ptr != 0) {
3061 // Read address length parameter.
3062 BufferArg addrlen_buf(addrlen_ptr, sizeof(socklen_t));
3063 addrlen_buf.copyIn(proxy);
3064 addr_len = *((socklen_t *)addrlen_buf.bufferPtr());
3065 }
3066
3067 struct sockaddr sa, *sap = NULL;
3068 if (addr_len != 0) {
3069 BufferArg addr_buf(addr_ptr, addr_len);
3070 addr_buf.copyIn(proxy);
3071 memcpy(&sa, (struct sockaddr *)addr_buf.bufferPtr(),
3072 sizeof(struct sockaddr));
3073 sap = &sa;
3074 }
3075
3076 ssize_t recvd_size = recvfrom(sim_fd,
3077 (void *)buf.bufferPtr(),
3078 buf_len, flags, sap, (socklen_t *)&addr_len);
3079
3080 if (recvd_size == -1)
3081 return -errno;
3082
3083 // Pass the received data out.
3084 buf.copyOut(proxy);
3085
3086 // Copy address to addr_ptr and pass it on.
3087 if (sap != NULL) {
3088 BufferArg addr_buf(addr_ptr, addr_len);
3089 memcpy(addr_buf.bufferPtr(), sap, sizeof(sa));
3090 addr_buf.copyOut(proxy);
3091 }
3092
3093 // Copy len to addrlen_ptr and pass it on.
3094 if (addr_len != 0) {
3095 BufferArg addrlen_buf(addrlen_ptr, sizeof(socklen_t));
3096 *(socklen_t *)addrlen_buf.bufferPtr() = addr_len;
3097 addrlen_buf.copyOut(proxy);
3098 }
3099
3100 return recvd_size;
3101}
3102
3103// Target sendto() handler.
3104template <typename OS>
3105SyscallReturn
3107 int tgt_fd, VPtr<> buf_ptr, typename OS::size_t buf_len, int flags,
3108 VPtr<> addr_ptr, socklen_t addr_len)
3109{
3110 auto p = tc->getProcessPtr();
3111
3112 auto sfdp = std::dynamic_pointer_cast<SocketFDEntry>((*p->fds)[tgt_fd]);
3113 if (!sfdp)
3114 return -EBADF;
3115 int sim_fd = sfdp->getSimFD();
3116
3117 // Reserve buffer space.
3118 BufferArg buf(buf_ptr, buf_len);
3120
3121 struct sockaddr sa, *sap = nullptr;
3122 memset(&sa, 0, sizeof(sockaddr));
3123 if (addr_len != 0) {
3124 BufferArg addr_buf(addr_ptr, addr_len);
3125 addr_buf.copyIn(SETranslatingPortProxy(tc));
3126 memcpy(&sa, (sockaddr*)addr_buf.bufferPtr(), addr_len);
3127 sap = &sa;
3128 }
3129
3130 ssize_t sent_size = sendto(sim_fd,
3131 (void *)buf.bufferPtr(),
3132 buf_len, flags, sap, (socklen_t)addr_len);
3133
3134 return (sent_size == -1) ? -errno : sent_size;
3135}
3136
3138template <typename OS>
3139SyscallReturn
3141 typename OS::size_t length)
3142{
3143 // Even if the system is currently not capable of recycling physical
3144 // pages, there is no reason we can't unmap them so that we trigger
3145 // appropriate seg faults when the application mistakenly tries to
3146 // access them again.
3147 auto p = tc->getProcessPtr();
3148
3149 if (p->pTable->pageOffset(start))
3150 return -EINVAL;
3151
3152 length = roundUp(length, p->pTable->pageSize());
3153
3154 p->memState->unmapRegion(start, length);
3155
3156 return 0;
3157}
3158
3159// Target fallocate() handler.
3160template <typename OS>
3161SyscallReturn
3163 int tgt_fd, int mode, typename OS::off_t offset,
3164 typename OS::off_t len)
3165{
3166#if defined(__linux__)
3167 auto p = tc->getProcessPtr();
3168
3169 auto ffdp = std::dynamic_pointer_cast<FileFDEntry>((*p->fds)[tgt_fd]);
3170 if (!ffdp)
3171 return -EBADF;
3172 int sim_fd = ffdp->getSimFD();
3173
3174 int result = fallocate(sim_fd, mode, offset, len);
3175 if (result < 0)
3176 return -errno;
3177 return 0;
3178#else
3179 warnUnsupportedOS("fallocate");
3180 return -1;
3181#endif
3182}
3183
3185template <typename OS>
3186SyscallReturn
3188 typename OS::off_t length)
3189{
3190 std::string path;
3191 auto p = tc->getProcessPtr();
3192
3193 if (!SETranslatingPortProxy(tc).tryReadString(path, pathname))
3194 return -EFAULT;
3195
3196 // Adjust path for cwd and redirection
3197 path = p->checkPathRedirect(path);
3198
3199 int result = truncate(path.c_str(), length);
3200 return (result == -1) ? -errno : result;
3201}
3202
3204template <typename OS>
3205SyscallReturn
3207 typename OS::off_t length)
3208{
3209 auto p = tc->getProcessPtr();
3210
3211 auto ffdp = std::dynamic_pointer_cast<FileFDEntry>((*p->fds)[tgt_fd]);
3212 if (!ffdp)
3213 return -EBADF;
3214 int sim_fd = ffdp->getSimFD();
3215
3216 int result = ftruncate(sim_fd, length);
3217 return (result == -1) ? -errno : result;
3218}
3219
3220template <typename OS>
3221SyscallReturn
3223 VPtr<> buf_ptr, typename OS::size_t count,
3224 unsigned int flags)
3225{
3226 static Random::RandomPtr se_prng(Random::genRandom());
3227 SETranslatingPortProxy proxy(tc);
3228
3229 TypedBufferArg<uint8_t> buf(buf_ptr, count);
3230 for (int i = 0; i < count; ++i) {
3231 buf[i] = se_prng->random<uint8_t>();
3232 }
3233 buf.copyOut(proxy);
3234
3235 return count;
3236}
3237
3238} // namespace gem5
3239
3240#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...
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:279
uint64_t pid()
Definition process.hh:86
std::shared_ptr< FDArray > fds
Definition process.hh:298
void assignThreadContext(ContextID context_id)
Definition process.hh:136
bool * sigchld
Definition process.hh:310
std::string checkPathRedirect(const std::string &filename)
Redirect file path if it matches any keys initialized by system object.
Definition process.cc:464
void initState() override
initState() is called on each SimObject when not restoring from a checkpoint.
Definition process.cc:289
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:266
EmulationPageTable * pTable
Definition process.hh:196
static RandomPtr genRandom(Random *r=nullptr)
Definition random.hh:68
std::shared_ptr< Random > RandomPtr
Definition random.hh:65
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:215
ThreadContext * findFree()
Definition system.cc:121
static const int maxPID
Definition system.hh:605
std::list< BasicSignal > signalList
Definition system.hh:612
FutexMap futexMap
Definition system.hh:603
Threads threads
Definition system.hh:315
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...
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:232
#define warn(...)
Definition logging.hh:288
#define warn_once(...)
Definition logging.hh:292
#define warn_if(cond,...)
Conditional warning macro that checks the supplied condition and only prints a warning if the conditi...
Definition logging.hh:315
Bitfield< 3 > sa
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)
uint64_t RegVal
Definition types.hh:173
SyscallReturn pipePseudoFunc(SyscallDesc *desc, ThreadContext *tc)
Pseudo Funcs - These functions use a different return convension, returning a second value in a regis...
SyscallReturn recvfromFunc(SyscallDesc *desc, ThreadContext *tc, int tgt_fd, VPtr<> buf_ptr, typename OS::size_t buf_len, int flags, VPtr<> addr_ptr, VPtr<> addrlen_ptr)
SyscallReturn selectFunc(SyscallDesc *desc, ThreadContext *tc, int nfds, VPtr< typename OS::fd_set > readfds, VPtr< typename OS::fd_set > writefds, VPtr< typename OS::fd_set > errorfds, VPtr< typename OS::timeval > timeout)
SyscallReturn utimesFunc(SyscallDesc *desc, ThreadContext *tc, VPtr<> pathname, VPtr< typename OS::timeval[2]> tp)
Target utimes() handler.
SyscallReturn socketFunc(SyscallDesc *desc, ThreadContext *tc, int domain, int type, int prot)
SyscallReturn chownFunc(SyscallDesc *desc, ThreadContext *tc, VPtr<> pathname, uint32_t owner, uint32_t group)
Target chown() handler.
SyscallReturn statFunc(SyscallDesc *desc, ThreadContext *tc, VPtr<> pathname, VPtr< typename OS::tgt_stat > tgt_stat)
Target stat() handler.
void copyOutStatBuf(TgtStatPtr tgt, HostStatPtr host, bool fakeTTY=false)
SyscallReturn renameImpl(SyscallDesc *desc, ThreadContext *tc, std::string old_name, std::string new_name)
SyscallReturn _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)
ProxyPtr< T, SETranslatingPortProxy > VPtr
Definition proxy_ptr.hh:400
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.
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 sched_getparamFunc(SyscallDesc *desc, ThreadContext *tc, int pid, VPtr< int > paramPtr)
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 May 26 2025 09:19:13 for gem5 by doxygen 1.13.2