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