arch-arm,cpu: Introduce a getEMI virtual method on StaticInst.
[gem5.git] / src / sim / syscall_emul.hh
1 /*
2 * Copyright (c) 2012-2013, 2015, 2019-2020 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
53 ///
54 /// @file syscall_emul.hh
55 ///
56 /// This file defines objects used to emulate syscalls from the target
57 /// application on the host machine.
58
59 #if defined(__linux__)
60 #include <sys/eventfd.h>
61 #include <sys/statfs.h>
62
63 #else
64 #include <sys/mount.h>
65
66 #endif
67
68 #ifdef __CYGWIN32__
69 #include <sys/fcntl.h>
70
71 #endif
72 #include <fcntl.h>
73 #include <net/if.h>
74 #include <poll.h>
75 #include <sys/ioctl.h>
76 #include <sys/mman.h>
77 #include <sys/socket.h>
78 #include <sys/stat.h>
79 #include <sys/time.h>
80 #include <sys/types.h>
81 #include <sys/uio.h>
82 #include <unistd.h>
83
84 #include <cerrno>
85 #include <memory>
86 #include <string>
87
88 #include "arch/generic/tlb.hh"
89 #include "arch/utility.hh"
90 #include "base/intmath.hh"
91 #include "base/loader/object_file.hh"
92 #include "base/logging.hh"
93 #include "base/trace.hh"
94 #include "base/types.hh"
95 #include "config/the_isa.hh"
96 #include "cpu/base.hh"
97 #include "cpu/thread_context.hh"
98 #include "kern/linux/linux.hh"
99 #include "mem/page_table.hh"
100 #include "params/Process.hh"
101 #include "sim/emul_driver.hh"
102 #include "sim/futex_map.hh"
103 #include "sim/guest_abi.hh"
104 #include "sim/process.hh"
105 #include "sim/proxy_ptr.hh"
106 #include "sim/syscall_debug_macros.hh"
107 #include "sim/syscall_desc.hh"
108 #include "sim/syscall_emul_buf.hh"
109 #include "sim/syscall_return.hh"
110
111 #if defined(__APPLE__) && defined(__MACH__) && !defined(CMSG_ALIGN)
112 #define CMSG_ALIGN(len) (((len) + sizeof(size_t) - 1) & ~(sizeof(size_t) - 1))
113 #endif
114
115 //////////////////////////////////////////////////////////////////////
116 //
117 // The following emulation functions are generic enough that they
118 // don't need to be recompiled for different emulated OS's. They are
119 // defined in sim/syscall_emul.cc.
120 //
121 //////////////////////////////////////////////////////////////////////
122
123 void warnUnsupportedOS(std::string syscall_name);
124
125 /// Handler for unimplemented syscalls that we haven't thought about.
126 SyscallReturn unimplementedFunc(SyscallDesc *desc, ThreadContext *tc);
127
128 /// Handler for unimplemented syscalls that we never intend to
129 /// implement (signal handling, etc.) and should not affect the correct
130 /// behavior of the program. Prints a warning. Return success to the target
131 /// program.
132 SyscallReturn ignoreFunc(SyscallDesc *desc, ThreadContext *tc);
133 /// Like above, but only prints a warning once per syscall desc it's used with.
134 SyscallReturn
135 ignoreWarnOnceFunc(SyscallDesc *desc, ThreadContext *tc);
136
137 // Target fallocateFunc() handler.
138 SyscallReturn fallocateFunc(SyscallDesc *desc, ThreadContext *tc,
139 int tgt_fd, int mode, off_t offset, off_t len);
140
141 /// Target exit() handler: terminate current context.
142 SyscallReturn exitFunc(SyscallDesc *desc, ThreadContext *tc, int status);
143
144 /// Target exit_group() handler: terminate simulation. (exit all threads)
145 SyscallReturn exitGroupFunc(SyscallDesc *desc, ThreadContext *tc, int status);
146
147 /// Target set_tid_address() handler.
148 SyscallReturn setTidAddressFunc(SyscallDesc *desc, ThreadContext *tc,
149 uint64_t tidPtr);
150
151 /// Target getpagesize() handler.
152 SyscallReturn getpagesizeFunc(SyscallDesc *desc, ThreadContext *tc);
153
154 /// Target brk() handler: set brk address.
155 SyscallReturn brkFunc(SyscallDesc *desc, ThreadContext *tc, Addr new_brk);
156
157 /// Target close() handler.
158 SyscallReturn closeFunc(SyscallDesc *desc, ThreadContext *tc, int tgt_fd);
159
160 /// Target lseek() handler.
161 SyscallReturn lseekFunc(SyscallDesc *desc, ThreadContext *tc,
162 int tgt_fd, uint64_t offs, int whence);
163
164 /// Target _llseek() handler.
165 SyscallReturn _llseekFunc(SyscallDesc *desc, ThreadContext *tc,
166 int tgt_fd, uint64_t offset_high,
167 uint32_t offset_low, Addr result_ptr, int whence);
168
169 /// Target munmap() handler.
170 SyscallReturn munmapFunc(SyscallDesc *desc, ThreadContext *tc, Addr start,
171 size_t length);
172
173 /// Target shutdown() handler.
174 SyscallReturn shutdownFunc(SyscallDesc *desc, ThreadContext *tc,
175 int tgt_fd, int how);
176
177 /// Target gethostname() handler.
178 SyscallReturn gethostnameFunc(SyscallDesc *desc, ThreadContext *tc,
179 Addr buf_ptr, int name_len);
180
181 /// Target getcwd() handler.
182 SyscallReturn getcwdFunc(SyscallDesc *desc, ThreadContext *tc,
183 Addr buf_ptr, unsigned long size);
184
185 /// Target readlink() handler.
186 SyscallReturn readlinkFunc(SyscallDesc *desc, ThreadContext *tc,
187 Addr pathname, Addr buf, size_t bufsiz);
188
189 /// Target unlink() handler.
190 SyscallReturn unlinkFunc(SyscallDesc *desc, ThreadContext *tc, Addr pathname);
191
192 /// Target link() handler
193 SyscallReturn linkFunc(SyscallDesc *desc, ThreadContext *tc,
194 Addr pathname, Addr new_pathname);
195
196 /// Target symlink() handler.
197 SyscallReturn symlinkFunc(SyscallDesc *desc, ThreadContext *tc,
198 Addr pathname, Addr new_pathname);
199
200 /// Target mkdir() handler.
201 SyscallReturn mkdirFunc(SyscallDesc *desc, ThreadContext *tc,
202 Addr pathname, mode_t mode);
203
204 /// Target mknod() handler.
205 SyscallReturn mknodFunc(SyscallDesc *desc, ThreadContext *tc,
206 Addr pathname, mode_t mode, dev_t dev);
207
208 /// Target chdir() handler.
209 SyscallReturn chdirFunc(SyscallDesc *desc, ThreadContext *tc, Addr pathname);
210
211 // Target rmdir() handler.
212 SyscallReturn rmdirFunc(SyscallDesc *desc, ThreadContext *tc, Addr pathname);
213
214 /// Target rename() handler.
215 SyscallReturn renameFunc(SyscallDesc *desc, ThreadContext *tc,
216 Addr oldpath, Addr newpath);
217
218
219 /// Target truncate() handler.
220 SyscallReturn truncateFunc(SyscallDesc *desc, ThreadContext *tc,
221 Addr pathname, off_t length);
222
223
224 /// Target ftruncate() handler.
225 SyscallReturn ftruncateFunc(SyscallDesc *desc, ThreadContext *tc,
226 int tgt_fd, off_t length);
227
228
229 /// Target truncate64() handler.
230 SyscallReturn truncate64Func(SyscallDesc *desc, ThreadContext *tc,
231 Addr pathname, int64_t length);
232
233 /// Target ftruncate64() handler.
234 SyscallReturn ftruncate64Func(SyscallDesc *desc, ThreadContext *tc,
235 int tgt_fd, int64_t length);
236
237 /// Target umask() handler.
238 SyscallReturn umaskFunc(SyscallDesc *desc, ThreadContext *tc);
239
240 /// Target gettid() handler.
241 SyscallReturn gettidFunc(SyscallDesc *desc, ThreadContext *tc);
242
243 /// Target chown() handler.
244 SyscallReturn chownFunc(SyscallDesc *desc, ThreadContext *tc,
245 Addr pathname, uint32_t owner, uint32_t group);
246
247 /// Target getpgrpFunc() handler.
248 SyscallReturn getpgrpFunc(SyscallDesc *desc, ThreadContext *tc);
249
250 /// Target setpgid() handler.
251 SyscallReturn setpgidFunc(SyscallDesc *desc, ThreadContext *tc,
252 int pid, int pgid);
253
254 /// Target fchown() handler.
255 SyscallReturn fchownFunc(SyscallDesc *desc, ThreadContext *tc,
256 int tgt_fd, uint32_t owner, uint32_t group);
257
258 /// Target dup() handler.
259 SyscallReturn dupFunc(SyscallDesc *desc, ThreadContext *tc,
260 int tgt_fd);
261
262 /// Target dup2() handler.
263 SyscallReturn dup2Func(SyscallDesc *desc, ThreadContext *tc,
264 int old_tgt_fd, int new_tgt_fd);
265
266 /// Target fcntl() handler.
267 SyscallReturn fcntlFunc(SyscallDesc *desc, ThreadContext *tc,
268 int tgt_fd, int cmd, GuestABI::VarArgs<int> varargs);
269
270 /// Target fcntl64() handler.
271 SyscallReturn fcntl64Func(SyscallDesc *desc, ThreadContext *tc,
272 int tgt_fd, int cmd);
273
274 /// Target pipe() handler.
275 SyscallReturn pipeFunc(SyscallDesc *desc, ThreadContext *tc, Addr tgt_addr);
276
277 /// Target pipe() handler.
278 SyscallReturn pipe2Func(SyscallDesc *desc, ThreadContext *tc,
279 Addr tgt_addr, int flags);
280
281 /// Target getpid() handler.
282 SyscallReturn getpidFunc(SyscallDesc *desc, ThreadContext *tc);
283
284 // Target getpeername() handler.
285 SyscallReturn getpeernameFunc(SyscallDesc *desc, ThreadContext *tc,
286 int tgt_fd, Addr sockAddrPtr, Addr addrlenPtr);
287
288 // Target bind() handler.
289 SyscallReturn bindFunc(SyscallDesc *desc, ThreadContext *tc,
290 int tgt_fd, Addr buf_ptr, int addrlen);
291
292 // Target listen() handler.
293 SyscallReturn listenFunc(SyscallDesc *desc, ThreadContext *tc,
294 int tgt_fd, int backlog);
295
296 // Target connect() handler.
297 SyscallReturn connectFunc(SyscallDesc *desc, ThreadContext *tc,
298 int tgt_fd, Addr buf_ptr, int addrlen);
299
300 #if defined(SYS_getdents)
301 // Target getdents() handler.
302 SyscallReturn getdentsFunc(SyscallDesc *desc, ThreadContext *tc,
303 int tgt_fd, Addr buf_ptr, unsigned count);
304 #endif
305
306 #if defined(SYS_getdents64)
307 // Target getdents() handler.
308 SyscallReturn getdents64Func(SyscallDesc *desc, ThreadContext *tc,
309 int tgt_fd, Addr buf_ptr, unsigned count);
310 #endif
311
312 // Target sendto() handler.
313 SyscallReturn sendtoFunc(SyscallDesc *desc, ThreadContext *tc,
314 int tgt_fd, Addr bufrPtr, size_t bufrLen, int flags,
315 Addr addrPtr, socklen_t addrLen);
316
317 // Target recvfrom() handler.
318 SyscallReturn recvfromFunc(SyscallDesc *desc, ThreadContext *tc,
319 int tgt_fd, Addr bufrPtr, size_t bufrLen,
320 int flags, Addr addrPtr, Addr addrlenPtr);
321
322 // Target recvmsg() handler.
323 SyscallReturn recvmsgFunc(SyscallDesc *desc, ThreadContext *tc,
324 int tgt_fd, Addr msgPtr, int flags);
325
326 // Target sendmsg() handler.
327 SyscallReturn sendmsgFunc(SyscallDesc *desc, ThreadContext *tc,
328 int tgt_fd, Addr msgPtr, int flags);
329
330 // Target getuid() handler.
331 SyscallReturn getuidFunc(SyscallDesc *desc, ThreadContext *tc);
332
333 /// Target getgid() handler.
334 SyscallReturn getgidFunc(SyscallDesc *desc, ThreadContext *tc);
335
336 /// Target getppid() handler.
337 SyscallReturn getppidFunc(SyscallDesc *desc, ThreadContext *tc);
338
339 /// Target geteuid() handler.
340 SyscallReturn geteuidFunc(SyscallDesc *desc, ThreadContext *tc);
341
342 /// Target getegid() handler.
343 SyscallReturn getegidFunc(SyscallDesc *desc, ThreadContext *tc);
344
345 /// Target access() handler
346 SyscallReturn accessFunc(SyscallDesc *desc, ThreadContext *tc,
347 Addr pathname, mode_t mode);
348
349 // Target getsockopt() handler.
350 SyscallReturn getsockoptFunc(SyscallDesc *desc, ThreadContext *tc,
351 int tgt_fd, int level, int optname,
352 Addr valPtr, Addr lenPtr);
353
354 // Target setsockopt() handler.
355 SyscallReturn setsockoptFunc(SyscallDesc *desc, ThreadContext *tc,
356 int tgt_fd, int level, int optname,
357 Addr valPtr, socklen_t len);
358
359 SyscallReturn getcpuFunc(SyscallDesc *desc, ThreadContext *tc,
360 VPtr<uint32_t> cpu, VPtr<uint32_t> node,
361 VPtr<uint32_t> tcache);
362
363 // Target getsockname() handler.
364 SyscallReturn getsocknameFunc(SyscallDesc *desc, ThreadContext *tc,
365 int tgt_fd, Addr addrPtr, Addr lenPtr);
366
367 /// Futex system call
368 /// Implemented by Daniel Sanchez
369 /// Used by printf's in multi-threaded apps
370 template <class OS>
371 SyscallReturn
372 futexFunc(SyscallDesc *desc, ThreadContext *tc,
373 Addr uaddr, int op, int val, int timeout, Addr uaddr2, int val3)
374 {
375 auto process = tc->getProcessPtr();
376
377 /*
378 * Unsupported option that does not affect the correctness of the
379 * application. This is a performance optimization utilized by Linux.
380 */
381 op &= ~OS::TGT_FUTEX_PRIVATE_FLAG;
382 op &= ~OS::TGT_FUTEX_CLOCK_REALTIME_FLAG;
383
384 FutexMap &futex_map = tc->getSystemPtr()->futexMap;
385
386 if (OS::TGT_FUTEX_WAIT == op || OS::TGT_FUTEX_WAIT_BITSET == op) {
387 // Ensure futex system call accessed atomically.
388 BufferArg buf(uaddr, sizeof(int));
389 buf.copyIn(tc->getVirtProxy());
390 int mem_val = *(int*)buf.bufferPtr();
391
392 /*
393 * The value in memory at uaddr is not equal with the expected val
394 * (a different thread must have changed it before the system call was
395 * invoked). In this case, we need to throw an error.
396 */
397 if (val != mem_val)
398 return -OS::TGT_EWOULDBLOCK;
399
400 if (OS::TGT_FUTEX_WAIT == op) {
401 futex_map.suspend(uaddr, process->tgid(), tc);
402 } else {
403 futex_map.suspend_bitset(uaddr, process->tgid(), tc, val3);
404 }
405
406 return 0;
407 } else if (OS::TGT_FUTEX_WAKE == op) {
408 return futex_map.wakeup(uaddr, process->tgid(), val);
409 } else if (OS::TGT_FUTEX_WAKE_BITSET == op) {
410 return futex_map.wakeup_bitset(uaddr, process->tgid(), val3);
411 } else if (OS::TGT_FUTEX_REQUEUE == op ||
412 OS::TGT_FUTEX_CMP_REQUEUE == op) {
413
414 // Ensure futex system call accessed atomically.
415 BufferArg buf(uaddr, sizeof(int));
416 buf.copyIn(tc->getVirtProxy());
417 int mem_val = *(int*)buf.bufferPtr();
418 /*
419 * For CMP_REQUEUE, the whole operation is only started only if
420 * val3 is still the value of the futex pointed to by uaddr.
421 */
422 if (OS::TGT_FUTEX_CMP_REQUEUE && val3 != mem_val)
423 return -OS::TGT_EWOULDBLOCK;
424 return futex_map.requeue(uaddr, process->tgid(), val, timeout, uaddr2);
425 } else if (OS::TGT_FUTEX_WAKE_OP == op) {
426 /*
427 * The FUTEX_WAKE_OP operation is equivalent to executing the
428 * following code atomically and totally ordered with respect to
429 * other futex operations on any of the two supplied futex words:
430 *
431 * int oldval = *(int *) addr2;
432 * *(int *) addr2 = oldval op oparg;
433 * futex(addr1, FUTEX_WAKE, val, 0, 0, 0);
434 * if (oldval cmp cmparg)
435 * futex(addr2, FUTEX_WAKE, val2, 0, 0, 0);
436 *
437 * (op, oparg, cmp, cmparg are encoded in val3)
438 *
439 * +---+---+-----------+-----------+
440 * |op |cmp| oparg | cmparg |
441 * +---+---+-----------+-----------+
442 * 4 4 12 12 <== # of bits
443 *
444 * reference: http://man7.org/linux/man-pages/man2/futex.2.html
445 *
446 */
447 // get value from simulated-space
448 BufferArg buf(uaddr2, sizeof(int));
449 buf.copyIn(tc->getVirtProxy());
450 int oldval = *(int*)buf.bufferPtr();
451 int newval = oldval;
452 // extract op, oparg, cmp, cmparg from val3
453 int wake_cmparg = val3 & 0xfff;
454 int wake_oparg = (val3 & 0xfff000) >> 12;
455 int wake_cmp = (val3 & 0xf000000) >> 24;
456 int wake_op = (val3 & 0xf0000000) >> 28;
457 if ((wake_op & OS::TGT_FUTEX_OP_ARG_SHIFT) >> 3 == 1)
458 wake_oparg = (1 << wake_oparg);
459 wake_op &= ~OS::TGT_FUTEX_OP_ARG_SHIFT;
460 // perform operation on the value of the second futex
461 if (wake_op == OS::TGT_FUTEX_OP_SET)
462 newval = wake_oparg;
463 else if (wake_op == OS::TGT_FUTEX_OP_ADD)
464 newval += wake_oparg;
465 else if (wake_op == OS::TGT_FUTEX_OP_OR)
466 newval |= wake_oparg;
467 else if (wake_op == OS::TGT_FUTEX_OP_ANDN)
468 newval &= ~wake_oparg;
469 else if (wake_op == OS::TGT_FUTEX_OP_XOR)
470 newval ^= wake_oparg;
471 // copy updated value back to simulated-space
472 *(int*)buf.bufferPtr() = newval;
473 buf.copyOut(tc->getVirtProxy());
474 // perform the first wake-up
475 int woken1 = futex_map.wakeup(uaddr, process->tgid(), val);
476 int woken2 = 0;
477 // calculate the condition of the second wake-up
478 bool is_wake2 = false;
479 if (wake_cmp == OS::TGT_FUTEX_OP_CMP_EQ)
480 is_wake2 = oldval == wake_cmparg;
481 else if (wake_cmp == OS::TGT_FUTEX_OP_CMP_NE)
482 is_wake2 = oldval != wake_cmparg;
483 else if (wake_cmp == OS::TGT_FUTEX_OP_CMP_LT)
484 is_wake2 = oldval < wake_cmparg;
485 else if (wake_cmp == OS::TGT_FUTEX_OP_CMP_LE)
486 is_wake2 = oldval <= wake_cmparg;
487 else if (wake_cmp == OS::TGT_FUTEX_OP_CMP_GT)
488 is_wake2 = oldval > wake_cmparg;
489 else if (wake_cmp == OS::TGT_FUTEX_OP_CMP_GE)
490 is_wake2 = oldval >= wake_cmparg;
491 // perform the second wake-up
492 if (is_wake2)
493 woken2 = futex_map.wakeup(uaddr2, process->tgid(), timeout);
494
495 return woken1 + woken2;
496 }
497 warn("futex: op %d not implemented; ignoring.", op);
498 return -ENOSYS;
499 }
500
501 /// Pseudo Funcs - These functions use a different return convension,
502 /// returning a second value in a register other than the normal return register
503 SyscallReturn pipePseudoFunc(SyscallDesc *desc, ThreadContext *tc);
504
505
506 /// Approximate seconds since the epoch (1/1/1970). About a billion,
507 /// by my reckoning. We want to keep this a constant (not use the
508 /// real-world time) to keep simulations repeatable.
509 const unsigned seconds_since_epoch = 1000 * 1000 * 1000;
510
511 /// Helper function to convert current elapsed time to seconds and
512 /// microseconds.
513 template <class T1, class T2>
514 void
515 getElapsedTimeMicro(T1 &sec, T2 &usec)
516 {
517 static const int OneMillion = 1000 * 1000;
518
519 uint64_t elapsed_usecs = curTick() / SimClock::Int::us;
520 sec = elapsed_usecs / OneMillion;
521 usec = elapsed_usecs % OneMillion;
522 }
523
524 /// Helper function to convert current elapsed time to seconds and
525 /// nanoseconds.
526 template <class T1, class T2>
527 void
528 getElapsedTimeNano(T1 &sec, T2 &nsec)
529 {
530 static const int OneBillion = 1000 * 1000 * 1000;
531
532 uint64_t elapsed_nsecs = curTick() / SimClock::Int::ns;
533 sec = elapsed_nsecs / OneBillion;
534 nsec = elapsed_nsecs % OneBillion;
535 }
536
537 //////////////////////////////////////////////////////////////////////
538 //
539 // The following emulation functions are generic, but need to be
540 // templated to account for differences in types, constants, etc.
541 //
542 //////////////////////////////////////////////////////////////////////
543
544 typedef struct statfs hst_statfs;
545 #if NO_STAT64
546 typedef struct stat hst_stat;
547 typedef struct stat hst_stat64;
548 #else
549 typedef struct stat hst_stat;
550 typedef struct stat64 hst_stat64;
551 #endif
552
553 //// Helper function to convert a host stat buffer to a target stat
554 //// buffer. Also copies the target buffer out to the simulated
555 //// memory space. Used by stat(), fstat(), and lstat().
556
557 template <typename OS, typename TgtStatPtr, typename HostStatPtr>
558 void
559 copyOutStatBuf(TgtStatPtr tgt, HostStatPtr host, bool fakeTTY=false)
560 {
561 constexpr ByteOrder bo = OS::byteOrder;
562
563 if (fakeTTY)
564 tgt->st_dev = 0xA;
565 else
566 tgt->st_dev = host->st_dev;
567 tgt->st_dev = htog(tgt->st_dev, bo);
568 tgt->st_ino = host->st_ino;
569 tgt->st_ino = htog(tgt->st_ino, bo);
570 tgt->st_mode = host->st_mode;
571 if (fakeTTY) {
572 // Claim to be a character device
573 tgt->st_mode &= ~S_IFMT; // Clear S_IFMT
574 tgt->st_mode |= S_IFCHR; // Set S_IFCHR
575 }
576 tgt->st_mode = htog(tgt->st_mode, bo);
577 tgt->st_nlink = host->st_nlink;
578 tgt->st_nlink = htog(tgt->st_nlink, bo);
579 tgt->st_uid = host->st_uid;
580 tgt->st_uid = htog(tgt->st_uid, bo);
581 tgt->st_gid = host->st_gid;
582 tgt->st_gid = htog(tgt->st_gid, bo);
583 if (fakeTTY)
584 tgt->st_rdev = 0x880d;
585 else
586 tgt->st_rdev = host->st_rdev;
587 tgt->st_rdev = htog(tgt->st_rdev, bo);
588 tgt->st_size = host->st_size;
589 tgt->st_size = htog(tgt->st_size, bo);
590 tgt->st_atimeX = host->st_atime;
591 tgt->st_atimeX = htog(tgt->st_atimeX, bo);
592 tgt->st_mtimeX = host->st_mtime;
593 tgt->st_mtimeX = htog(tgt->st_mtimeX, bo);
594 tgt->st_ctimeX = host->st_ctime;
595 tgt->st_ctimeX = htog(tgt->st_ctimeX, bo);
596 // Force the block size to be 8KB. This helps to ensure buffered io works
597 // consistently across different hosts.
598 tgt->st_blksize = 0x2000;
599 tgt->st_blksize = htog(tgt->st_blksize, bo);
600 tgt->st_blocks = host->st_blocks;
601 tgt->st_blocks = htog(tgt->st_blocks, bo);
602 }
603
604 // Same for stat64
605
606 template <typename OS, typename TgtStatPtr, typename HostStatPtr>
607 void
608 copyOutStat64Buf(TgtStatPtr tgt, HostStatPtr host,
609 bool fakeTTY=false)
610 {
611 copyOutStatBuf<OS>(tgt, host, fakeTTY);
612 #if defined(STAT_HAVE_NSEC)
613 constexpr ByteOrder bo = OS::byteOrder;
614
615 tgt->st_atime_nsec = host->st_atime_nsec;
616 tgt->st_atime_nsec = htog(tgt->st_atime_nsec, bo);
617 tgt->st_mtime_nsec = host->st_mtime_nsec;
618 tgt->st_mtime_nsec = htog(tgt->st_mtime_nsec, bo);
619 tgt->st_ctime_nsec = host->st_ctime_nsec;
620 tgt->st_ctime_nsec = htog(tgt->st_ctime_nsec, bo);
621 #else
622 tgt->st_atime_nsec = 0;
623 tgt->st_mtime_nsec = 0;
624 tgt->st_ctime_nsec = 0;
625 #endif
626 }
627
628 template <class OS, typename TgtStatPtr, typename HostStatPtr>
629 void
630 copyOutStatfsBuf(TgtStatPtr tgt, HostStatPtr host)
631 {
632 constexpr ByteOrder bo = OS::byteOrder;
633
634 tgt->f_type = htog(host->f_type, bo);
635 #if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__)
636 tgt->f_bsize = htog(host->f_iosize, bo);
637 #else
638 tgt->f_bsize = htog(host->f_bsize, bo);
639 #endif
640 tgt->f_blocks = htog(host->f_blocks, bo);
641 tgt->f_bfree = htog(host->f_bfree, bo);
642 tgt->f_bavail = htog(host->f_bavail, bo);
643 tgt->f_files = htog(host->f_files, bo);
644 tgt->f_ffree = htog(host->f_ffree, bo);
645 memcpy(&tgt->f_fsid, &host->f_fsid, sizeof(host->f_fsid));
646 #if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__)
647 tgt->f_namelen = htog(host->f_namemax, bo);
648 tgt->f_frsize = htog(host->f_bsize, bo);
649 #elif defined(__APPLE__)
650 tgt->f_namelen = 0;
651 tgt->f_frsize = 0;
652 #else
653 tgt->f_namelen = htog(host->f_namelen, bo);
654 tgt->f_frsize = htog(host->f_frsize, bo);
655 #endif
656 #if defined(__linux__)
657 memcpy(&tgt->f_spare, &host->f_spare,
658 std::min(sizeof(host->f_spare), sizeof(tgt->f_spare)));
659 #else
660 /*
661 * The fields are different sizes per OS. Don't bother with
662 * f_spare or f_reserved on non-Linux for now.
663 */
664 memset(&tgt->f_spare, 0, sizeof(tgt->f_spare));
665 #endif
666 }
667
668 /// Target ioctl() handler. For the most part, programs call ioctl()
669 /// only to find out if their stdout is a tty, to determine whether to
670 /// do line or block buffering. We always claim that output fds are
671 /// not TTYs to provide repeatable results.
672 template <class OS>
673 SyscallReturn
674 ioctlFunc(SyscallDesc *desc, ThreadContext *tc,
675 int tgt_fd, unsigned req, Addr addr)
676 {
677 auto p = tc->getProcessPtr();
678
679 DPRINTF_SYSCALL(Verbose, "ioctl(%d, 0x%x, ...)\n", tgt_fd, req);
680
681 if (OS::isTtyReq(req))
682 return -ENOTTY;
683
684 auto dfdp = std::dynamic_pointer_cast<DeviceFDEntry>((*p->fds)[tgt_fd]);
685 if (dfdp) {
686 EmulatedDriver *emul_driver = dfdp->getDriver();
687 if (emul_driver)
688 return emul_driver->ioctl(tc, req, addr);
689 }
690
691 auto sfdp = std::dynamic_pointer_cast<SocketFDEntry>((*p->fds)[tgt_fd]);
692 if (sfdp) {
693 int status;
694
695 switch (req) {
696 case SIOCGIFCONF: {
697 BufferArg conf_arg(addr, sizeof(ifconf));
698 conf_arg.copyIn(tc->getVirtProxy());
699
700 ifconf *conf = (ifconf*)conf_arg.bufferPtr();
701 Addr ifc_buf_addr = (Addr)conf->ifc_buf;
702 BufferArg ifc_buf_arg(ifc_buf_addr, conf->ifc_len);
703 ifc_buf_arg.copyIn(tc->getVirtProxy());
704
705 conf->ifc_buf = (char*)ifc_buf_arg.bufferPtr();
706
707 status = ioctl(sfdp->getSimFD(), req, conf_arg.bufferPtr());
708 if (status != -1) {
709 conf->ifc_buf = (char*)ifc_buf_addr;
710 ifc_buf_arg.copyOut(tc->getVirtProxy());
711 conf_arg.copyOut(tc->getVirtProxy());
712 }
713
714 return status;
715 }
716 case SIOCGIFFLAGS:
717 #if defined(__linux__)
718 case SIOCGIFINDEX:
719 #endif
720 case SIOCGIFNETMASK:
721 case SIOCGIFADDR:
722 #if defined(__linux__)
723 case SIOCGIFHWADDR:
724 #endif
725 case SIOCGIFMTU: {
726 BufferArg req_arg(addr, sizeof(ifreq));
727 req_arg.copyIn(tc->getVirtProxy());
728
729 status = ioctl(sfdp->getSimFD(), req, req_arg.bufferPtr());
730 if (status != -1)
731 req_arg.copyOut(tc->getVirtProxy());
732 return status;
733 }
734 }
735 }
736
737 /**
738 * For lack of a better return code, return ENOTTY. Ideally, we should
739 * return something better here, but at least we issue the warning.
740 */
741 warn("Unsupported ioctl call (return ENOTTY): ioctl(%d, 0x%x, ...) @ \n",
742 tgt_fd, req, tc->pcState());
743 return -ENOTTY;
744 }
745
746 /// Target open() handler.
747 template <class OS>
748 SyscallReturn
749 openatFunc(SyscallDesc *desc, ThreadContext *tc,
750 int tgt_dirfd, Addr pathname, int tgt_flags, int mode)
751 {
752 auto p = tc->getProcessPtr();
753
754 /**
755 * Retrieve the simulated process' memory proxy and then read in the path
756 * string from that memory space into the host's working memory space.
757 */
758 std::string path;
759 if (!tc->getVirtProxy().tryReadString(path, pathname))
760 return -EFAULT;
761
762 #ifdef __CYGWIN32__
763 int host_flags = O_BINARY;
764 #else
765 int host_flags = 0;
766 #endif
767 /**
768 * Translate target flags into host flags. Flags exist which are not
769 * ported between architectures which can cause check failures.
770 */
771 for (int i = 0; i < OS::NUM_OPEN_FLAGS; i++) {
772 if (tgt_flags & OS::openFlagTable[i].tgtFlag) {
773 tgt_flags &= ~OS::openFlagTable[i].tgtFlag;
774 host_flags |= OS::openFlagTable[i].hostFlag;
775 }
776 }
777 if (tgt_flags)
778 warn("%s: cannot decode flags %#x", desc->name(), tgt_flags);
779
780 #ifdef __CYGWIN32__
781 host_flags |= O_BINARY;
782 #endif
783
784 /**
785 * If the simulated process called open or openat with AT_FDCWD specified,
786 * take the current working directory value which was passed into the
787 * process class as a Python parameter and append the current path to
788 * create a full path.
789 * Otherwise, openat with a valid target directory file descriptor has
790 * been called. If the path option, which was passed in as a parameter,
791 * is not absolute, retrieve the directory file descriptor's path and
792 * prepend it to the path passed in as a parameter.
793 * In every case, we should have a full path (which is relevant to the
794 * host) to work with after this block has been passed.
795 */
796 std::string redir_path = path;
797 std::string abs_path = path;
798 if (tgt_dirfd == OS::TGT_AT_FDCWD) {
799 abs_path = p->absolutePath(path, true);
800 redir_path = p->checkPathRedirect(path);
801 } else if (!startswith(path, "/")) {
802 std::shared_ptr<FDEntry> fdep = ((*p->fds)[tgt_dirfd]);
803 auto ffdp = std::dynamic_pointer_cast<FileFDEntry>(fdep);
804 if (!ffdp)
805 return -EBADF;
806 abs_path = ffdp->getFileName() + path;
807 redir_path = p->checkPathRedirect(abs_path);
808 }
809
810 /**
811 * Since this is an emulated environment, we create pseudo file
812 * descriptors for device requests that have been registered with
813 * the process class through Python; this allows us to create a file
814 * descriptor for subsequent ioctl or mmap calls.
815 */
816 if (startswith(abs_path, "/dev/")) {
817 std::string filename = abs_path.substr(strlen("/dev/"));
818 EmulatedDriver *drv = p->findDriver(filename);
819 if (drv) {
820 DPRINTF_SYSCALL(Verbose, "%s: passing call to "
821 "driver open with path[%s]\n",
822 desc->name(), abs_path.c_str());
823 return drv->open(tc, mode, host_flags);
824 }
825 /**
826 * Fall through here for pass through to host devices, such
827 * as /dev/zero
828 */
829 }
830
831 /**
832 * We make several attempts resolve a call to open.
833 *
834 * 1) Resolve any path redirection before hand. This will set the path
835 * up with variable 'redir_path' which may contain a modified path or
836 * the original path value. This should already be done in prior code.
837 * 2) Try to handle the access using 'special_paths'. Some special_paths
838 * and files cannot be called on the host and need to be handled as
839 * special cases inside the simulator. These special_paths are handled by
840 * C++ routines to provide output back to userspace.
841 * 3) If the full path that was created above does not match any of the
842 * special cases, pass it through to the open call on the __HOST__ to let
843 * the host open the file on our behalf. Again, the openImpl tries to
844 * USE_THE_HOST_FILESYSTEM_OPEN (with a possible redirection to the
845 * faux-filesystem files). The faux-filesystem is dynamically created
846 * during simulator configuration using Python functions.
847 * 4) If the host cannot open the file, the open attempt failed in "3)".
848 * Return the host's error code back through the system call to the
849 * simulated process. If running a debug trace, also notify the user that
850 * the open call failed.
851 *
852 * Any success will set sim_fd to something other than -1 and skip the
853 * next conditions effectively bypassing them.
854 */
855 int sim_fd = -1;
856 std::string used_path;
857 std::vector<std::string> special_paths =
858 { "/proc/meminfo/", "/system/", "/platform/", "/etc/passwd",
859 "/proc/self/maps", "/dev/urandom",
860 "/sys/devices/system/cpu/online" };
861 for (auto entry : special_paths) {
862 if (startswith(path, entry)) {
863 sim_fd = OS::openSpecialFile(abs_path, p, tc);
864 used_path = abs_path;
865 }
866 }
867 if (sim_fd == -1) {
868 sim_fd = open(redir_path.c_str(), host_flags, mode);
869 used_path = redir_path;
870 }
871 if (sim_fd == -1) {
872 int local = -errno;
873 DPRINTF_SYSCALL(Verbose, "%s: failed -> path:%s "
874 "(inferred from:%s)\n", desc->name(),
875 used_path.c_str(), path.c_str());
876 return local;
877 }
878
879 /**
880 * The file was opened successfully and needs to be recorded in the
881 * process' file descriptor array so that it can be retrieved later.
882 * The target file descriptor that is chosen will be the lowest unused
883 * file descriptor.
884 * Return the indirect target file descriptor back to the simulated
885 * process to act as a handle for the opened file.
886 */
887 auto ffdp = std::make_shared<FileFDEntry>(sim_fd, host_flags, path, 0);
888 int tgt_fd = p->fds->allocFD(ffdp);
889 DPRINTF_SYSCALL(Verbose, "%s: sim_fd[%d], target_fd[%d] -> path:%s\n"
890 "(inferred from:%s)\n", desc->name(),
891 sim_fd, tgt_fd, used_path.c_str(), path.c_str());
892 return tgt_fd;
893 }
894
895 /// Target open() handler.
896 template <class OS>
897 SyscallReturn
898 openFunc(SyscallDesc *desc, ThreadContext *tc,
899 Addr pathname, int tgt_flags, int mode)
900 {
901 return openatFunc<OS>(
902 desc, tc, OS::TGT_AT_FDCWD, pathname, tgt_flags, mode);
903 }
904
905 /// Target unlinkat() handler.
906 template <class OS>
907 SyscallReturn
908 unlinkatFunc(SyscallDesc *desc, ThreadContext *tc, int dirfd, Addr pathname)
909 {
910 if (dirfd != OS::TGT_AT_FDCWD)
911 warn("unlinkat: first argument not AT_FDCWD; unlikely to work");
912
913 return unlinkFunc(desc, tc, pathname);
914 }
915
916 /// Target facessat() handler
917 template <class OS>
918 SyscallReturn
919 faccessatFunc(SyscallDesc *desc, ThreadContext *tc,
920 int dirfd, Addr pathname, int mode)
921 {
922 if (dirfd != OS::TGT_AT_FDCWD)
923 warn("faccessat: first argument not AT_FDCWD; unlikely to work");
924 return accessFunc(desc, tc, pathname, mode);
925 }
926
927 /// Target readlinkat() handler
928 template <class OS>
929 SyscallReturn
930 readlinkatFunc(SyscallDesc *desc, ThreadContext *tc,
931 int dirfd, Addr pathname, Addr buf, size_t bufsiz)
932 {
933 if (dirfd != OS::TGT_AT_FDCWD)
934 warn("openat: first argument not AT_FDCWD; unlikely to work");
935 return readlinkFunc(desc, tc, pathname, buf, bufsiz);
936 }
937
938 /// Target renameat() handler.
939 template <class OS>
940 SyscallReturn
941 renameatFunc(SyscallDesc *desc, ThreadContext *tc,
942 int olddirfd, Addr oldpath, int newdirfd, Addr newpath)
943 {
944 if (olddirfd != OS::TGT_AT_FDCWD)
945 warn("renameat: first argument not AT_FDCWD; unlikely to work");
946
947 if (newdirfd != OS::TGT_AT_FDCWD)
948 warn("renameat: third argument not AT_FDCWD; unlikely to work");
949
950 return renameFunc(desc, tc, oldpath, newpath);
951 }
952
953 /// Target sysinfo() handler.
954 template <class OS>
955 SyscallReturn
956 sysinfoFunc(SyscallDesc *desc, ThreadContext *tc,
957 VPtr<typename OS::tgt_sysinfo> sysinfo)
958 {
959 auto process = tc->getProcessPtr();
960
961 sysinfo->uptime = seconds_since_epoch;
962 sysinfo->totalram = process->system->memSize();
963 sysinfo->mem_unit = 1;
964
965 return 0;
966 }
967
968 /// Target chmod() handler.
969 template <class OS>
970 SyscallReturn
971 chmodFunc(SyscallDesc *desc, ThreadContext *tc, Addr pathname, mode_t mode)
972 {
973 std::string path;
974 auto process = tc->getProcessPtr();
975
976 if (!tc->getVirtProxy().tryReadString(path, pathname))
977 return -EFAULT;
978
979 mode_t hostMode = 0;
980
981 // XXX translate mode flags via OS::something???
982 hostMode = mode;
983
984 // Adjust path for cwd and redirection
985 path = process->checkPathRedirect(path);
986
987 // do the chmod
988 int result = chmod(path.c_str(), hostMode);
989 if (result < 0)
990 return -errno;
991
992 return 0;
993 }
994
995 template <class OS>
996 SyscallReturn
997 pollFunc(SyscallDesc *desc, ThreadContext *tc,
998 Addr fdsPtr, int nfds, int tmout)
999 {
1000 auto p = tc->getProcessPtr();
1001
1002 BufferArg fdsBuf(fdsPtr, sizeof(struct pollfd) * nfds);
1003 fdsBuf.copyIn(tc->getVirtProxy());
1004
1005 /**
1006 * Record the target file descriptors in a local variable. We need to
1007 * replace them with host file descriptors but we need a temporary copy
1008 * for later. Afterwards, replace each target file descriptor in the
1009 * poll_fd array with its host_fd.
1010 */
1011 int temp_tgt_fds[nfds];
1012 for (int index = 0; index < nfds; index++) {
1013 temp_tgt_fds[index] = ((struct pollfd *)fdsBuf.bufferPtr())[index].fd;
1014 auto tgt_fd = temp_tgt_fds[index];
1015 auto hbfdp = std::dynamic_pointer_cast<HBFDEntry>((*p->fds)[tgt_fd]);
1016 if (!hbfdp)
1017 return -EBADF;
1018 auto host_fd = hbfdp->getSimFD();
1019 ((struct pollfd *)fdsBuf.bufferPtr())[index].fd = host_fd;
1020 }
1021
1022 /**
1023 * We cannot allow an infinite poll to occur or it will inevitably cause
1024 * a deadlock in the gem5 simulator with clone. We must pass in tmout with
1025 * a non-negative value, however it also makes no sense to poll on the
1026 * underlying host for any other time than tmout a zero timeout.
1027 */
1028 int status;
1029 if (tmout < 0) {
1030 status = poll((struct pollfd *)fdsBuf.bufferPtr(), nfds, 0);
1031 if (status == 0) {
1032 /**
1033 * If blocking indefinitely, check the signal list to see if a
1034 * signal would break the poll out of the retry cycle and try
1035 * to return the signal interrupt instead.
1036 */
1037 System *sysh = tc->getSystemPtr();
1038 std::list<BasicSignal>::iterator it;
1039 for (it=sysh->signalList.begin(); it!=sysh->signalList.end(); it++)
1040 if (it->receiver == p)
1041 return -EINTR;
1042 return SyscallReturn::retry();
1043 }
1044 } else
1045 status = poll((struct pollfd *)fdsBuf.bufferPtr(), nfds, 0);
1046
1047 if (status == -1)
1048 return -errno;
1049
1050 /**
1051 * Replace each host_fd in the returned poll_fd array with its original
1052 * target file descriptor.
1053 */
1054 for (int index = 0; index < nfds; index++) {
1055 auto tgt_fd = temp_tgt_fds[index];
1056 ((struct pollfd *)fdsBuf.bufferPtr())[index].fd = tgt_fd;
1057 }
1058
1059 /**
1060 * Copy out the pollfd struct because the host may have updated fields
1061 * in the structure.
1062 */
1063 fdsBuf.copyOut(tc->getVirtProxy());
1064
1065 return status;
1066 }
1067
1068 /// Target fchmod() handler.
1069 template <class OS>
1070 SyscallReturn
1071 fchmodFunc(SyscallDesc *desc, ThreadContext *tc, int tgt_fd, uint32_t mode)
1072 {
1073 auto p = tc->getProcessPtr();
1074
1075 auto ffdp = std::dynamic_pointer_cast<FileFDEntry>((*p->fds)[tgt_fd]);
1076 if (!ffdp)
1077 return -EBADF;
1078 int sim_fd = ffdp->getSimFD();
1079
1080 mode_t hostMode = mode;
1081
1082 int result = fchmod(sim_fd, hostMode);
1083
1084 return (result < 0) ? -errno : 0;
1085 }
1086
1087 /// Target mremap() handler.
1088 template <class OS>
1089 SyscallReturn
1090 mremapFunc(SyscallDesc *desc, ThreadContext *tc,
1091 Addr start, uint64_t old_length, uint64_t new_length, uint64_t flags,
1092 GuestABI::VarArgs<uint64_t> varargs)
1093 {
1094 auto p = tc->getProcessPtr();
1095 Addr page_bytes = p->pTable->pageSize();
1096 uint64_t provided_address = 0;
1097 bool use_provided_address = flags & OS::TGT_MREMAP_FIXED;
1098
1099 if (use_provided_address)
1100 provided_address = varargs.get<uint64_t>();
1101
1102 if ((start % page_bytes != 0) ||
1103 (provided_address % page_bytes != 0)) {
1104 warn("mremap failing: arguments not page aligned");
1105 return -EINVAL;
1106 }
1107
1108 new_length = roundUp(new_length, page_bytes);
1109
1110 if (new_length > old_length) {
1111 Addr mmap_end = p->memState->getMmapEnd();
1112
1113 if ((start + old_length) == mmap_end &&
1114 (!use_provided_address || provided_address == start)) {
1115 // This case cannot occur when growing downward, as
1116 // start is greater than or equal to mmap_end.
1117 uint64_t diff = new_length - old_length;
1118 p->memState->mapRegion(mmap_end, diff, "remapped");
1119 p->memState->setMmapEnd(mmap_end + diff);
1120 return start;
1121 } else {
1122 if (!use_provided_address && !(flags & OS::TGT_MREMAP_MAYMOVE)) {
1123 warn("can't remap here and MREMAP_MAYMOVE flag not set\n");
1124 return -ENOMEM;
1125 } else {
1126 uint64_t new_start = provided_address;
1127 if (!use_provided_address) {
1128 new_start = p->mmapGrowsDown() ?
1129 mmap_end - new_length : mmap_end;
1130 mmap_end = p->mmapGrowsDown() ?
1131 new_start : mmap_end + new_length;
1132 p->memState->setMmapEnd(mmap_end);
1133 }
1134
1135 warn("mremapping to new vaddr %08p-%08p, adding %d\n",
1136 new_start, new_start + new_length,
1137 new_length - old_length);
1138
1139 // add on the remaining unallocated pages
1140 p->allocateMem(new_start + old_length,
1141 new_length - old_length,
1142 use_provided_address /* clobber */);
1143
1144 if (use_provided_address &&
1145 ((new_start + new_length > p->memState->getMmapEnd() &&
1146 !p->mmapGrowsDown()) ||
1147 (new_start < p->memState->getMmapEnd() &&
1148 p->mmapGrowsDown()))) {
1149 // something fishy going on here, at least notify the user
1150 // @todo: increase mmap_end?
1151 warn("mmap region limit exceeded with MREMAP_FIXED\n");
1152 }
1153
1154 warn("returning %08p as start\n", new_start);
1155 p->memState->remapRegion(start, new_start, old_length);
1156 return new_start;
1157 }
1158 }
1159 } else {
1160 // Shrink a region
1161 if (use_provided_address && provided_address != start)
1162 p->memState->remapRegion(start, provided_address, new_length);
1163 if (new_length != old_length)
1164 p->memState->unmapRegion(start + new_length,
1165 old_length - new_length);
1166 return use_provided_address ? provided_address : start;
1167 }
1168 }
1169
1170 /// Target stat() handler.
1171 template <class OS>
1172 SyscallReturn
1173 statFunc(SyscallDesc *desc, ThreadContext *tc,
1174 Addr pathname, VPtr<typename OS::tgt_stat> tgt_stat)
1175 {
1176 std::string path;
1177 auto process = tc->getProcessPtr();
1178
1179 if (!tc->getVirtProxy().tryReadString(path, pathname))
1180 return -EFAULT;
1181
1182 // Adjust path for cwd and redirection
1183 path = process->checkPathRedirect(path);
1184
1185 struct stat hostBuf;
1186 int result = stat(path.c_str(), &hostBuf);
1187
1188 if (result < 0)
1189 return -errno;
1190
1191 copyOutStatBuf<OS>(tgt_stat, &hostBuf);
1192
1193 return 0;
1194 }
1195
1196
1197 /// Target stat64() handler.
1198 template <class OS>
1199 SyscallReturn
1200 stat64Func(SyscallDesc *desc, ThreadContext *tc,
1201 Addr pathname, VPtr<typename OS::tgt_stat64> tgt_stat)
1202 {
1203 std::string path;
1204 auto process = tc->getProcessPtr();
1205
1206 if (!tc->getVirtProxy().tryReadString(path, pathname))
1207 return -EFAULT;
1208
1209 // Adjust path for cwd and redirection
1210 path = process->checkPathRedirect(path);
1211
1212 #if NO_STAT64
1213 struct stat hostBuf;
1214 int result = stat(path.c_str(), &hostBuf);
1215 #else
1216 struct stat64 hostBuf;
1217 int result = stat64(path.c_str(), &hostBuf);
1218 #endif
1219
1220 if (result < 0)
1221 return -errno;
1222
1223 copyOutStat64Buf<OS>(tgt_stat, &hostBuf);
1224
1225 return 0;
1226 }
1227
1228
1229 /// Target fstatat64() handler.
1230 template <class OS>
1231 SyscallReturn
1232 fstatat64Func(SyscallDesc *desc, ThreadContext *tc,
1233 int dirfd, Addr pathname, VPtr<typename OS::tgt_stat64> tgt_stat)
1234 {
1235 auto process = tc->getProcessPtr();
1236 if (dirfd != OS::TGT_AT_FDCWD)
1237 warn("fstatat64: first argument not AT_FDCWD; unlikely to work");
1238
1239 std::string path;
1240 if (!tc->getVirtProxy().tryReadString(path, pathname))
1241 return -EFAULT;
1242
1243 // Adjust path for cwd and redirection
1244 path = process->checkPathRedirect(path);
1245
1246 #if NO_STAT64
1247 struct stat hostBuf;
1248 int result = stat(path.c_str(), &hostBuf);
1249 #else
1250 struct stat64 hostBuf;
1251 int result = stat64(path.c_str(), &hostBuf);
1252 #endif
1253
1254 if (result < 0)
1255 return -errno;
1256
1257 copyOutStat64Buf<OS>(tgt_stat, &hostBuf);
1258
1259 return 0;
1260 }
1261
1262
1263 /// Target fstat64() handler.
1264 template <class OS>
1265 SyscallReturn
1266 fstat64Func(SyscallDesc *desc, ThreadContext *tc,
1267 int tgt_fd, VPtr<typename OS::tgt_stat64> tgt_stat)
1268 {
1269 auto p = tc->getProcessPtr();
1270
1271 auto ffdp = std::dynamic_pointer_cast<HBFDEntry>((*p->fds)[tgt_fd]);
1272 if (!ffdp)
1273 return -EBADF;
1274 int sim_fd = ffdp->getSimFD();
1275
1276 #if NO_STAT64
1277 struct stat hostBuf;
1278 int result = fstat(sim_fd, &hostBuf);
1279 #else
1280 struct stat64 hostBuf;
1281 int result = fstat64(sim_fd, &hostBuf);
1282 #endif
1283
1284 if (result < 0)
1285 return -errno;
1286
1287 copyOutStat64Buf<OS>(tgt_stat, &hostBuf, (sim_fd == 1));
1288
1289 return 0;
1290 }
1291
1292
1293 /// Target lstat() handler.
1294 template <class OS>
1295 SyscallReturn
1296 lstatFunc(SyscallDesc *desc, ThreadContext *tc,
1297 Addr pathname, VPtr<typename OS::tgt_stat> tgt_stat)
1298 {
1299 std::string path;
1300 auto process = tc->getProcessPtr();
1301
1302 if (!tc->getVirtProxy().tryReadString(path, pathname))
1303 return -EFAULT;
1304
1305 // Adjust path for cwd and redirection
1306 path = process->checkPathRedirect(path);
1307
1308 struct stat hostBuf;
1309 int result = lstat(path.c_str(), &hostBuf);
1310
1311 if (result < 0)
1312 return -errno;
1313
1314 copyOutStatBuf<OS>(tgt_stat, &hostBuf);
1315
1316 return 0;
1317 }
1318
1319 /// Target lstat64() handler.
1320 template <class OS>
1321 SyscallReturn
1322 lstat64Func(SyscallDesc *desc, ThreadContext *tc,
1323 Addr pathname, VPtr<typename OS::tgt_stat64> tgt_stat)
1324 {
1325 std::string path;
1326 auto process = tc->getProcessPtr();
1327
1328 if (!tc->getVirtProxy().tryReadString(path, pathname))
1329 return -EFAULT;
1330
1331 // Adjust path for cwd and redirection
1332 path = process->checkPathRedirect(path);
1333
1334 #if NO_STAT64
1335 struct stat hostBuf;
1336 int result = lstat(path.c_str(), &hostBuf);
1337 #else
1338 struct stat64 hostBuf;
1339 int result = lstat64(path.c_str(), &hostBuf);
1340 #endif
1341
1342 if (result < 0)
1343 return -errno;
1344
1345 copyOutStat64Buf<OS>(tgt_stat, &hostBuf);
1346
1347 return 0;
1348 }
1349
1350 /// Target fstat() handler.
1351 template <class OS>
1352 SyscallReturn
1353 fstatFunc(SyscallDesc *desc, ThreadContext *tc,
1354 int tgt_fd, VPtr<typename OS::tgt_stat> tgt_stat)
1355 {
1356 auto p = tc->getProcessPtr();
1357
1358 DPRINTF_SYSCALL(Verbose, "fstat(%d, ...)\n", tgt_fd);
1359
1360 auto ffdp = std::dynamic_pointer_cast<FileFDEntry>((*p->fds)[tgt_fd]);
1361 if (!ffdp)
1362 return -EBADF;
1363 int sim_fd = ffdp->getSimFD();
1364
1365 struct stat hostBuf;
1366 int result = fstat(sim_fd, &hostBuf);
1367
1368 if (result < 0)
1369 return -errno;
1370
1371 copyOutStatBuf<OS>(tgt_stat, &hostBuf, (sim_fd == 1));
1372
1373 return 0;
1374 }
1375
1376 /// Target statfs() handler.
1377 template <class OS>
1378 SyscallReturn
1379 statfsFunc(SyscallDesc *desc, ThreadContext *tc,
1380 Addr pathname, VPtr<typename OS::tgt_statfs> tgt_stat)
1381 {
1382 #if defined(__linux__)
1383 std::string path;
1384 auto process = tc->getProcessPtr();
1385
1386 if (!tc->getVirtProxy().tryReadString(path, pathname))
1387 return -EFAULT;
1388
1389 // Adjust path for cwd and redirection
1390 path = process->checkPathRedirect(path);
1391
1392 struct statfs hostBuf;
1393 int result = statfs(path.c_str(), &hostBuf);
1394
1395 if (result < 0)
1396 return -errno;
1397
1398 copyOutStatfsBuf<OS>(tgt_stat, &hostBuf);
1399 return 0;
1400 #else
1401 warnUnsupportedOS("statfs");
1402 return -1;
1403 #endif
1404 }
1405
1406 template <class OS>
1407 SyscallReturn
1408 cloneFunc(SyscallDesc *desc, ThreadContext *tc, RegVal flags, RegVal newStack,
1409 Addr ptidPtr, Addr ctidPtr, Addr tlsPtr)
1410 {
1411 auto p = tc->getProcessPtr();
1412
1413 if (((flags & OS::TGT_CLONE_SIGHAND)&& !(flags & OS::TGT_CLONE_VM)) ||
1414 ((flags & OS::TGT_CLONE_THREAD) && !(flags & OS::TGT_CLONE_SIGHAND)) ||
1415 ((flags & OS::TGT_CLONE_FS) && (flags & OS::TGT_CLONE_NEWNS)) ||
1416 ((flags & OS::TGT_CLONE_NEWIPC) && (flags & OS::TGT_CLONE_SYSVSEM)) ||
1417 ((flags & OS::TGT_CLONE_NEWPID) && (flags & OS::TGT_CLONE_THREAD)) ||
1418 ((flags & OS::TGT_CLONE_VM) && !(newStack)))
1419 return -EINVAL;
1420
1421 ThreadContext *ctc;
1422 if (!(ctc = tc->getSystemPtr()->threads.findFree())) {
1423 DPRINTF_SYSCALL(Verbose, "clone: no spare thread context in system"
1424 "[cpu %d, thread %d]", tc->cpuId(), tc->threadId());
1425 return -EAGAIN;
1426 }
1427
1428 /**
1429 * Note that ProcessParams is generated by swig and there are no other
1430 * examples of how to create anything but this default constructor. The
1431 * fields are manually initialized instead of passing parameters to the
1432 * constructor.
1433 */
1434 ProcessParams *pp = new ProcessParams();
1435 pp->executable.assign(*(new std::string(p->progName())));
1436 pp->cmd.push_back(*(new std::string(p->progName())));
1437 pp->system = p->system;
1438 pp->cwd.assign(p->tgtCwd);
1439 pp->input.assign("stdin");
1440 pp->output.assign("stdout");
1441 pp->errout.assign("stderr");
1442 pp->uid = p->uid();
1443 pp->euid = p->euid();
1444 pp->gid = p->gid();
1445 pp->egid = p->egid();
1446
1447 /* Find the first free PID that's less than the maximum */
1448 std::set<int> const& pids = p->system->PIDs;
1449 int temp_pid = *pids.begin();
1450 do {
1451 temp_pid++;
1452 } while (pids.find(temp_pid) != pids.end());
1453 if (temp_pid >= System::maxPID)
1454 fatal("temp_pid is too large: %d", temp_pid);
1455
1456 pp->pid = temp_pid;
1457 pp->ppid = (flags & OS::TGT_CLONE_THREAD) ? p->ppid() : p->pid();
1458 pp->useArchPT = p->useArchPT;
1459 pp->kvmInSE = p->kvmInSE;
1460 Process *cp = pp->create();
1461 // TODO: there is no way to know when the Process SimObject is done with
1462 // the params pointer. Both the params pointer (pp) and the process
1463 // pointer (cp) are normally managed in python and are never cleaned up.
1464
1465 Process *owner = ctc->getProcessPtr();
1466 ctc->setProcessPtr(cp);
1467 cp->assignThreadContext(ctc->contextId());
1468 owner->revokeThreadContext(ctc->contextId());
1469
1470 if (flags & OS::TGT_CLONE_PARENT_SETTID) {
1471 BufferArg ptidBuf(ptidPtr, sizeof(long));
1472 long *ptid = (long *)ptidBuf.bufferPtr();
1473 *ptid = cp->pid();
1474 ptidBuf.copyOut(tc->getVirtProxy());
1475 }
1476
1477 if (flags & OS::TGT_CLONE_THREAD) {
1478 cp->pTable->shared = true;
1479 cp->useForClone = true;
1480 }
1481
1482 ctc->setUseForClone(true);
1483 cp->initState();
1484 p->clone(tc, ctc, cp, flags);
1485
1486 if (flags & OS::TGT_CLONE_THREAD) {
1487 delete cp->sigchld;
1488 cp->sigchld = p->sigchld;
1489 } else if (flags & OS::TGT_SIGCHLD) {
1490 *cp->sigchld = true;
1491 }
1492
1493 if (flags & OS::TGT_CLONE_CHILD_SETTID) {
1494 BufferArg ctidBuf(ctidPtr, sizeof(long));
1495 long *ctid = (long *)ctidBuf.bufferPtr();
1496 *ctid = cp->pid();
1497 ctidBuf.copyOut(ctc->getVirtProxy());
1498 }
1499
1500 if (flags & OS::TGT_CLONE_CHILD_CLEARTID)
1501 cp->childClearTID = (uint64_t)ctidPtr;
1502
1503 ctc->clearArchRegs();
1504
1505 OS::archClone(flags, p, cp, tc, ctc, newStack, tlsPtr);
1506
1507 desc->returnInto(ctc, 0);
1508
1509 TheISA::PCState cpc = tc->pcState();
1510 cpc.advance();
1511 ctc->pcState(cpc);
1512 ctc->activate();
1513
1514 return cp->pid();
1515 }
1516
1517 template <class OS>
1518 SyscallReturn
1519 cloneBackwardsFunc(SyscallDesc *desc, ThreadContext *tc, RegVal flags,
1520 RegVal newStack, Addr ptidPtr, Addr tlsPtr, Addr ctidPtr)
1521 {
1522 return cloneFunc<OS>(desc, tc, flags, newStack, ptidPtr, ctidPtr, tlsPtr);
1523 }
1524
1525 /// Target fstatfs() handler.
1526 template <class OS>
1527 SyscallReturn
1528 fstatfsFunc(SyscallDesc *desc, ThreadContext *tc,
1529 int tgt_fd, VPtr<typename OS::tgt_statfs> tgt_stat)
1530 {
1531 auto p = tc->getProcessPtr();
1532
1533 auto ffdp = std::dynamic_pointer_cast<FileFDEntry>((*p->fds)[tgt_fd]);
1534 if (!ffdp)
1535 return -EBADF;
1536 int sim_fd = ffdp->getSimFD();
1537
1538 struct statfs hostBuf;
1539 int result = fstatfs(sim_fd, &hostBuf);
1540
1541 if (result < 0)
1542 return -errno;
1543
1544 copyOutStatfsBuf<OS>(tgt_stat, &hostBuf);
1545
1546 return 0;
1547 }
1548
1549 /// Target readv() handler.
1550 template <class OS>
1551 SyscallReturn
1552 readvFunc(SyscallDesc *desc, ThreadContext *tc,
1553 int tgt_fd, uint64_t tiov_base, size_t count)
1554 {
1555 auto p = tc->getProcessPtr();
1556
1557 auto ffdp = std::dynamic_pointer_cast<FileFDEntry>((*p->fds)[tgt_fd]);
1558 if (!ffdp)
1559 return -EBADF;
1560 int sim_fd = ffdp->getSimFD();
1561
1562 PortProxy &prox = tc->getVirtProxy();
1563 typename OS::tgt_iovec tiov[count];
1564 struct iovec hiov[count];
1565 for (size_t i = 0; i < count; ++i) {
1566 prox.readBlob(tiov_base + (i * sizeof(typename OS::tgt_iovec)),
1567 &tiov[i], sizeof(typename OS::tgt_iovec));
1568 hiov[i].iov_len = gtoh(tiov[i].iov_len, OS::byteOrder);
1569 hiov[i].iov_base = new char [hiov[i].iov_len];
1570 }
1571
1572 int result = readv(sim_fd, hiov, count);
1573 int local_errno = errno;
1574
1575 for (size_t i = 0; i < count; ++i) {
1576 if (result != -1) {
1577 prox.writeBlob(htog(tiov[i].iov_base, OS::byteOrder),
1578 hiov[i].iov_base, hiov[i].iov_len);
1579 }
1580 delete [] (char *)hiov[i].iov_base;
1581 }
1582
1583 return (result == -1) ? -local_errno : result;
1584 }
1585
1586 /// Target writev() handler.
1587 template <class OS>
1588 SyscallReturn
1589 writevFunc(SyscallDesc *desc, ThreadContext *tc,
1590 int tgt_fd, uint64_t tiov_base, size_t count)
1591 {
1592 auto p = tc->getProcessPtr();
1593
1594 auto hbfdp = std::dynamic_pointer_cast<HBFDEntry>((*p->fds)[tgt_fd]);
1595 if (!hbfdp)
1596 return -EBADF;
1597 int sim_fd = hbfdp->getSimFD();
1598
1599 PortProxy &prox = tc->getVirtProxy();
1600 struct iovec hiov[count];
1601 for (size_t i = 0; i < count; ++i) {
1602 typename OS::tgt_iovec tiov;
1603
1604 prox.readBlob(tiov_base + i*sizeof(typename OS::tgt_iovec),
1605 &tiov, sizeof(typename OS::tgt_iovec));
1606 hiov[i].iov_len = gtoh(tiov.iov_len, OS::byteOrder);
1607 hiov[i].iov_base = new char [hiov[i].iov_len];
1608 prox.readBlob(gtoh(tiov.iov_base, OS::byteOrder), hiov[i].iov_base,
1609 hiov[i].iov_len);
1610 }
1611
1612 int result = writev(sim_fd, hiov, count);
1613
1614 for (size_t i = 0; i < count; ++i)
1615 delete [] (char *)hiov[i].iov_base;
1616
1617 return (result == -1) ? -errno : result;
1618 }
1619
1620 /// Target mmap() handler.
1621 template <class OS>
1622 SyscallReturn
1623 mmapFunc(SyscallDesc *desc, ThreadContext *tc,
1624 Addr start, typename OS::size_t length, int prot,
1625 int tgt_flags, int tgt_fd, typename OS::off_t offset)
1626 {
1627 auto p = tc->getProcessPtr();
1628 Addr page_bytes = p->pTable->pageSize();
1629
1630 if (start & (page_bytes - 1) ||
1631 offset & (page_bytes - 1) ||
1632 (tgt_flags & OS::TGT_MAP_PRIVATE &&
1633 tgt_flags & OS::TGT_MAP_SHARED) ||
1634 (!(tgt_flags & OS::TGT_MAP_PRIVATE) &&
1635 !(tgt_flags & OS::TGT_MAP_SHARED)) ||
1636 !length) {
1637 return -EINVAL;
1638 }
1639
1640 if ((prot & PROT_WRITE) && (tgt_flags & OS::TGT_MAP_SHARED)) {
1641 // With shared mmaps, there are two cases to consider:
1642 // 1) anonymous: writes should modify the mapping and this should be
1643 // visible to observers who share the mapping. Currently, it's
1644 // difficult to update the shared mapping because there's no
1645 // structure which maintains information about the which virtual
1646 // memory areas are shared. If that structure existed, it would be
1647 // possible to make the translations point to the same frames.
1648 // 2) file-backed: writes should modify the mapping and the file
1649 // which is backed by the mapping. The shared mapping problem is the
1650 // same as what was mentioned about the anonymous mappings. For
1651 // file-backed mappings, the writes to the file are difficult
1652 // because it requires syncing what the mapping holds with the file
1653 // that resides on the host system. So, any write on a real system
1654 // would cause the change to be propagated to the file mapping at
1655 // some point in the future (the inode is tracked along with the
1656 // mapping). This isn't guaranteed to always happen, but it usually
1657 // works well enough. The guarantee is provided by the msync system
1658 // call. We could force the change through with shared mappings with
1659 // a call to msync, but that again would require more information
1660 // than we currently maintain.
1661 warn_once("mmap: writing to shared mmap region is currently "
1662 "unsupported. The write succeeds on the target, but it "
1663 "will not be propagated to the host or shared mappings");
1664 }
1665
1666 length = roundUp(length, page_bytes);
1667
1668 int sim_fd = -1;
1669 if (!(tgt_flags & OS::TGT_MAP_ANONYMOUS)) {
1670 std::shared_ptr<FDEntry> fdep = (*p->fds)[tgt_fd];
1671
1672 auto dfdp = std::dynamic_pointer_cast<DeviceFDEntry>(fdep);
1673 if (dfdp) {
1674 EmulatedDriver *emul_driver = dfdp->getDriver();
1675 return emul_driver->mmap(tc, start, length, prot, tgt_flags,
1676 tgt_fd, offset);
1677 }
1678
1679 auto ffdp = std::dynamic_pointer_cast<FileFDEntry>(fdep);
1680 if (!ffdp)
1681 return -EBADF;
1682 sim_fd = ffdp->getSimFD();
1683
1684 /**
1685 * Maintain the symbol table for dynamic executables.
1686 * The loader will call mmap to map the images into its address
1687 * space and we intercept that here. We can verify that we are
1688 * executing inside the loader by checking the program counter value.
1689 * XXX: with multiprogrammed workloads or multi-node configurations,
1690 * this will not work since there is a single global symbol table.
1691 */
1692 if (p->interpImage.contains(tc->pcState().instAddr())) {
1693 std::shared_ptr<FDEntry> fdep = (*p->fds)[tgt_fd];
1694 auto ffdp = std::dynamic_pointer_cast<FileFDEntry>(fdep);
1695 auto *lib = Loader::createObjectFile(p->checkPathRedirect(
1696 ffdp->getFileName()));
1697 DPRINTF_SYSCALL(Verbose, "Loading symbols from %s\n",
1698 ffdp->getFileName());
1699
1700 if (lib) {
1701 Addr offset = lib->buildImage().minAddr() + start;
1702 Loader::debugSymbolTable.insert(*lib->symtab().offset(offset));
1703 }
1704 }
1705 }
1706
1707 /**
1708 * Not TGT_MAP_FIXED means we can start wherever we want.
1709 */
1710 if (!(tgt_flags & OS::TGT_MAP_FIXED)) {
1711 /**
1712 * If the application provides us with a hint, we should make some
1713 * small amount of effort to accomodate it. Basically, we check if
1714 * every single VA within the requested range is unused. If it is,
1715 * we give the application the range. If not, we fall back to
1716 * extending the global mmap region.
1717 */
1718 if (!(start && p->memState->isUnmapped(start, length))) {
1719 /**
1720 * Extend global mmap region to give us some room for the app.
1721 */
1722 start = p->memState->extendMmap(length);
1723 }
1724 }
1725
1726 DPRINTF_SYSCALL(Verbose, " mmap range is 0x%x - 0x%x\n",
1727 start, start + length - 1);
1728
1729 /**
1730 * We only allow mappings to overwrite existing mappings if
1731 * TGT_MAP_FIXED is set. Otherwise it shouldn't be a problem
1732 * because we ignore the start hint if TGT_MAP_FIXED is not set.
1733 */
1734 if (tgt_flags & OS::TGT_MAP_FIXED) {
1735 /**
1736 * We might already have some old VMAs mapped to this region, so
1737 * make sure to clear em out!
1738 */
1739 p->memState->unmapRegion(start, length);
1740 }
1741
1742 /**
1743 * Figure out a human-readable name for the mapping.
1744 */
1745 std::string region_name;
1746 if (tgt_flags & OS::TGT_MAP_ANONYMOUS) {
1747 region_name = "anon";
1748 } else {
1749 std::shared_ptr<FDEntry> fdep = (*p->fds)[tgt_fd];
1750 auto ffdp = std::dynamic_pointer_cast<FileFDEntry>(fdep);
1751 region_name = ffdp->getFileName();
1752 }
1753
1754 /**
1755 * Setup the correct VMA for this region. The physical pages will be
1756 * mapped lazily.
1757 */
1758 p->memState->mapRegion(start, length, region_name, sim_fd, offset);
1759
1760 return start;
1761 }
1762
1763 template <class OS>
1764 SyscallReturn
1765 pread64Func(SyscallDesc *desc, ThreadContext *tc,
1766 int tgt_fd, Addr bufPtr, int nbytes, int offset)
1767 {
1768 auto p = tc->getProcessPtr();
1769
1770 auto ffdp = std::dynamic_pointer_cast<FileFDEntry>((*p->fds)[tgt_fd]);
1771 if (!ffdp)
1772 return -EBADF;
1773 int sim_fd = ffdp->getSimFD();
1774
1775 BufferArg bufArg(bufPtr, nbytes);
1776
1777 int bytes_read = pread(sim_fd, bufArg.bufferPtr(), nbytes, offset);
1778
1779 bufArg.copyOut(tc->getVirtProxy());
1780
1781 return (bytes_read == -1) ? -errno : bytes_read;
1782 }
1783
1784 template <class OS>
1785 SyscallReturn
1786 pwrite64Func(SyscallDesc *desc, ThreadContext *tc,
1787 int tgt_fd, Addr bufPtr, int nbytes, int offset)
1788 {
1789 auto p = tc->getProcessPtr();
1790
1791 auto ffdp = std::dynamic_pointer_cast<FileFDEntry>((*p->fds)[tgt_fd]);
1792 if (!ffdp)
1793 return -EBADF;
1794 int sim_fd = ffdp->getSimFD();
1795
1796 BufferArg bufArg(bufPtr, nbytes);
1797 bufArg.copyIn(tc->getVirtProxy());
1798
1799 int bytes_written = pwrite(sim_fd, bufArg.bufferPtr(), nbytes, offset);
1800
1801 return (bytes_written == -1) ? -errno : bytes_written;
1802 }
1803
1804 /// Target mmap2() handler.
1805 template <class OS>
1806 SyscallReturn
1807 mmap2Func(SyscallDesc *desc, ThreadContext *tc,
1808 Addr start, typename OS::size_t length, int prot,
1809 int tgt_flags, int tgt_fd, typename OS::off_t offset)
1810 {
1811 auto page_size = tc->getProcessPtr()->pTable->pageSize();
1812 return mmapFunc<OS>(desc, tc, start, length, prot, tgt_flags,
1813 tgt_fd, offset * page_size);
1814 }
1815
1816 /// Target getrlimit() handler.
1817 template <class OS>
1818 SyscallReturn
1819 getrlimitFunc(SyscallDesc *desc, ThreadContext *tc,
1820 unsigned resource, VPtr<typename OS::rlimit> rlp)
1821 {
1822 const ByteOrder bo = OS::byteOrder;
1823 switch (resource) {
1824 case OS::TGT_RLIMIT_STACK:
1825 // max stack size in bytes: make up a number (8MiB for now)
1826 rlp->rlim_cur = rlp->rlim_max = 8 * 1024 * 1024;
1827 rlp->rlim_cur = htog(rlp->rlim_cur, bo);
1828 rlp->rlim_max = htog(rlp->rlim_max, bo);
1829 break;
1830
1831 case OS::TGT_RLIMIT_DATA:
1832 // max data segment size in bytes: make up a number
1833 rlp->rlim_cur = rlp->rlim_max = 256 * 1024 * 1024;
1834 rlp->rlim_cur = htog(rlp->rlim_cur, bo);
1835 rlp->rlim_max = htog(rlp->rlim_max, bo);
1836 break;
1837
1838 case OS::TGT_RLIMIT_NPROC:
1839 rlp->rlim_cur = rlp->rlim_max = tc->getSystemPtr()->threads.size();
1840 rlp->rlim_cur = htog(rlp->rlim_cur, bo);
1841 rlp->rlim_max = htog(rlp->rlim_max, bo);
1842 break;
1843
1844 default:
1845 warn("getrlimit: unimplemented resource %d", resource);
1846 return -EINVAL;
1847 break;
1848 }
1849
1850 return 0;
1851 }
1852
1853 template <class OS>
1854 SyscallReturn
1855 prlimitFunc(SyscallDesc *desc, ThreadContext *tc,
1856 int pid, int resource, Addr n, VPtr<typename OS::rlimit> rlp)
1857 {
1858 if (pid != 0) {
1859 warn("prlimit: ignoring rlimits for nonzero pid");
1860 return -EPERM;
1861 }
1862 if (n)
1863 warn("prlimit: ignoring new rlimit");
1864 if (rlp) {
1865 const ByteOrder bo = OS::byteOrder;
1866 switch (resource) {
1867 case OS::TGT_RLIMIT_STACK:
1868 // max stack size in bytes: make up a number (8MiB for now)
1869 rlp->rlim_cur = rlp->rlim_max = 8 * 1024 * 1024;
1870 rlp->rlim_cur = htog(rlp->rlim_cur, bo);
1871 rlp->rlim_max = htog(rlp->rlim_max, bo);
1872 break;
1873 case OS::TGT_RLIMIT_DATA:
1874 // max data segment size in bytes: make up a number
1875 rlp->rlim_cur = rlp->rlim_max = 256*1024*1024;
1876 rlp->rlim_cur = htog(rlp->rlim_cur, bo);
1877 rlp->rlim_max = htog(rlp->rlim_max, bo);
1878 break;
1879 default:
1880 warn("prlimit: unimplemented resource %d", resource);
1881 return -EINVAL;
1882 break;
1883 }
1884 }
1885 return 0;
1886 }
1887
1888 /// Target clock_gettime() function.
1889 template <class OS>
1890 SyscallReturn
1891 clock_gettimeFunc(SyscallDesc *desc, ThreadContext *tc,
1892 int clk_id, VPtr<typename OS::timespec> tp)
1893 {
1894 getElapsedTimeNano(tp->tv_sec, tp->tv_nsec);
1895 tp->tv_sec += seconds_since_epoch;
1896 tp->tv_sec = htog(tp->tv_sec, OS::byteOrder);
1897 tp->tv_nsec = htog(tp->tv_nsec, OS::byteOrder);
1898
1899 return 0;
1900 }
1901
1902 /// Target clock_getres() function.
1903 template <class OS>
1904 SyscallReturn
1905 clock_getresFunc(SyscallDesc *desc, ThreadContext *tc, int clk_id,
1906 VPtr<typename OS::timespec> tp)
1907 {
1908 // Set resolution at ns, which is what clock_gettime() returns
1909 tp->tv_sec = 0;
1910 tp->tv_nsec = 1;
1911
1912 return 0;
1913 }
1914
1915 /// Target gettimeofday() handler.
1916 template <class OS>
1917 SyscallReturn
1918 gettimeofdayFunc(SyscallDesc *desc, ThreadContext *tc,
1919 VPtr<typename OS::timeval> tp, Addr tz_ptr)
1920 {
1921 getElapsedTimeMicro(tp->tv_sec, tp->tv_usec);
1922 tp->tv_sec += seconds_since_epoch;
1923 tp->tv_sec = htog(tp->tv_sec, OS::byteOrder);
1924 tp->tv_usec = htog(tp->tv_usec, OS::byteOrder);
1925
1926 return 0;
1927 }
1928
1929
1930 /// Target utimes() handler.
1931 template <class OS>
1932 SyscallReturn
1933 utimesFunc(SyscallDesc *desc, ThreadContext *tc, Addr pathname,
1934 VPtr<typename OS::timeval [2]> tp)
1935 {
1936 std::string path;
1937 auto process = tc->getProcessPtr();
1938
1939 if (!tc->getVirtProxy().tryReadString(path, pathname))
1940 return -EFAULT;
1941
1942 struct timeval hostTimeval[2];
1943 for (int i = 0; i < 2; ++i) {
1944 hostTimeval[i].tv_sec = gtoh((*tp)[i].tv_sec, OS::byteOrder);
1945 hostTimeval[i].tv_usec = gtoh((*tp)[i].tv_usec, OS::byteOrder);
1946 }
1947
1948 // Adjust path for cwd and redirection
1949 path = process->checkPathRedirect(path);
1950
1951 int result = utimes(path.c_str(), hostTimeval);
1952
1953 if (result < 0)
1954 return -errno;
1955
1956 return 0;
1957 }
1958
1959 template <class OS>
1960 SyscallReturn
1961 execveFunc(SyscallDesc *desc, ThreadContext *tc,
1962 Addr pathname, Addr argv_mem_loc, Addr envp_mem_loc)
1963 {
1964 auto p = tc->getProcessPtr();
1965
1966 std::string path;
1967 PortProxy & mem_proxy = tc->getVirtProxy();
1968 if (!mem_proxy.tryReadString(path, pathname))
1969 return -EFAULT;
1970
1971 if (access(path.c_str(), F_OK) == -1)
1972 return -EACCES;
1973
1974 auto read_in = [](std::vector<std::string> &vect,
1975 PortProxy &mem_proxy, Addr mem_loc)
1976 {
1977 for (int inc = 0; ; inc++) {
1978 BufferArg b((mem_loc + sizeof(Addr) * inc), sizeof(Addr));
1979 b.copyIn(mem_proxy);
1980
1981 if (!*(Addr*)b.bufferPtr())
1982 break;
1983
1984 vect.push_back(std::string());
1985 mem_proxy.tryReadString(vect[inc], *(Addr*)b.bufferPtr());
1986 }
1987 };
1988
1989 /**
1990 * Note that ProcessParams is generated by swig and there are no other
1991 * examples of how to create anything but this default constructor. The
1992 * fields are manually initialized instead of passing parameters to the
1993 * constructor.
1994 */
1995 ProcessParams *pp = new ProcessParams();
1996 pp->executable = path;
1997 read_in(pp->cmd, mem_proxy, argv_mem_loc);
1998 read_in(pp->env, mem_proxy, envp_mem_loc);
1999 pp->uid = p->uid();
2000 pp->egid = p->egid();
2001 pp->euid = p->euid();
2002 pp->gid = p->gid();
2003 pp->ppid = p->ppid();
2004 pp->pid = p->pid();
2005 pp->input.assign("cin");
2006 pp->output.assign("cout");
2007 pp->errout.assign("cerr");
2008 pp->cwd.assign(p->tgtCwd);
2009 pp->system = p->system;
2010 /**
2011 * Prevent process object creation with identical PIDs (which will trip
2012 * a fatal check in Process constructor). The execve call is supposed to
2013 * take over the currently executing process' identity but replace
2014 * whatever it is doing with a new process image. Instead of hijacking
2015 * the process object in the simulator, we create a new process object
2016 * and bind to the previous process' thread below (hijacking the thread).
2017 */
2018 p->system->PIDs.erase(p->pid());
2019 Process *new_p = pp->create();
2020 delete pp;
2021
2022 /**
2023 * Work through the file descriptor array and close any files marked
2024 * close-on-exec.
2025 */
2026 new_p->fds = p->fds;
2027 for (int i = 0; i < new_p->fds->getSize(); i++) {
2028 std::shared_ptr<FDEntry> fdep = (*new_p->fds)[i];
2029 if (fdep && fdep->getCOE())
2030 new_p->fds->closeFDEntry(i);
2031 }
2032
2033 *new_p->sigchld = true;
2034
2035 delete p;
2036 tc->clearArchRegs();
2037 tc->setProcessPtr(new_p);
2038 new_p->assignThreadContext(tc->contextId());
2039 new_p->initState();
2040 tc->activate();
2041 TheISA::PCState pcState = tc->pcState();
2042 tc->setNPC(pcState.instAddr());
2043
2044 return SyscallReturn();
2045 }
2046
2047 /// Target getrusage() function.
2048 template <class OS>
2049 SyscallReturn
2050 getrusageFunc(SyscallDesc *desc, ThreadContext *tc,
2051 int who /* THREAD, SELF, or CHILDREN */,
2052 VPtr<typename OS::rusage> rup)
2053 {
2054 rup->ru_utime.tv_sec = 0;
2055 rup->ru_utime.tv_usec = 0;
2056 rup->ru_stime.tv_sec = 0;
2057 rup->ru_stime.tv_usec = 0;
2058 rup->ru_maxrss = 0;
2059 rup->ru_ixrss = 0;
2060 rup->ru_idrss = 0;
2061 rup->ru_isrss = 0;
2062 rup->ru_minflt = 0;
2063 rup->ru_majflt = 0;
2064 rup->ru_nswap = 0;
2065 rup->ru_inblock = 0;
2066 rup->ru_oublock = 0;
2067 rup->ru_msgsnd = 0;
2068 rup->ru_msgrcv = 0;
2069 rup->ru_nsignals = 0;
2070 rup->ru_nvcsw = 0;
2071 rup->ru_nivcsw = 0;
2072
2073 switch (who) {
2074 case OS::TGT_RUSAGE_SELF:
2075 getElapsedTimeMicro(rup->ru_utime.tv_sec, rup->ru_utime.tv_usec);
2076 rup->ru_utime.tv_sec = htog(rup->ru_utime.tv_sec, OS::byteOrder);
2077 rup->ru_utime.tv_usec = htog(rup->ru_utime.tv_usec, OS::byteOrder);
2078 break;
2079
2080 case OS::TGT_RUSAGE_CHILDREN:
2081 // do nothing. We have no child processes, so they take no time.
2082 break;
2083
2084 default:
2085 // don't really handle THREAD or CHILDREN, but just warn and
2086 // plow ahead
2087 warn("getrusage() only supports RUSAGE_SELF. Parameter %d ignored.",
2088 who);
2089 }
2090
2091 return 0;
2092 }
2093
2094 /// Target times() function.
2095 template <class OS>
2096 SyscallReturn
2097 timesFunc(SyscallDesc *desc, ThreadContext *tc, VPtr<typename OS::tms> bufp)
2098 {
2099 // Fill in the time structure (in clocks)
2100 int64_t clocks = curTick() * OS::M5_SC_CLK_TCK / SimClock::Int::s;
2101 bufp->tms_utime = clocks;
2102 bufp->tms_stime = 0;
2103 bufp->tms_cutime = 0;
2104 bufp->tms_cstime = 0;
2105
2106 // Convert to host endianness
2107 bufp->tms_utime = htog(bufp->tms_utime, OS::byteOrder);
2108
2109 // Return clock ticks since system boot
2110 return clocks;
2111 }
2112
2113 /// Target time() function.
2114 template <class OS>
2115 SyscallReturn
2116 timeFunc(SyscallDesc *desc, ThreadContext *tc, Addr taddr)
2117 {
2118 typename OS::time_t sec, usec;
2119 getElapsedTimeMicro(sec, usec);
2120 sec += seconds_since_epoch;
2121
2122 if (taddr != 0) {
2123 typename OS::time_t t = sec;
2124 t = htog(t, OS::byteOrder);
2125 PortProxy &p = tc->getVirtProxy();
2126 p.writeBlob(taddr, &t, (int)sizeof(typename OS::time_t));
2127 }
2128 return sec;
2129 }
2130
2131 template <class OS>
2132 SyscallReturn
2133 tgkillFunc(SyscallDesc *desc, ThreadContext *tc, int tgid, int tid, int sig)
2134 {
2135 /**
2136 * This system call is intended to allow killing a specific thread
2137 * within an arbitrary thread group if sanctioned with permission checks.
2138 * It's usually true that threads share the termination signal as pointed
2139 * out by the pthread_kill man page and this seems to be the intended
2140 * usage. Due to this being an emulated environment, assume the following:
2141 * Threads are allowed to call tgkill because the EUID for all threads
2142 * should be the same. There is no signal handling mechanism for kernel
2143 * registration of signal handlers since signals are poorly supported in
2144 * emulation mode. Since signal handlers cannot be registered, all
2145 * threads within in a thread group must share the termination signal.
2146 * We never exhaust PIDs so there's no chance of finding the wrong one
2147 * due to PID rollover.
2148 */
2149
2150 System *sys = tc->getSystemPtr();
2151 Process *tgt_proc = nullptr;
2152 for (auto *tc: sys->threads) {
2153 Process *temp = tc->getProcessPtr();
2154 if (temp->pid() == tid) {
2155 tgt_proc = temp;
2156 break;
2157 }
2158 }
2159
2160 if (sig != 0 || sig != OS::TGT_SIGABRT)
2161 return -EINVAL;
2162
2163 if (tgt_proc == nullptr)
2164 return -ESRCH;
2165
2166 if (tgid != -1 && tgt_proc->tgid() != tgid)
2167 return -ESRCH;
2168
2169 if (sig == OS::TGT_SIGABRT)
2170 exitGroupFunc(desc, tc, 0);
2171
2172 return 0;
2173 }
2174
2175 template <class OS>
2176 SyscallReturn
2177 socketFunc(SyscallDesc *desc, ThreadContext *tc,
2178 int domain, int type, int prot)
2179 {
2180 auto p = tc->getProcessPtr();
2181
2182 int sim_fd = socket(domain, type, prot);
2183 if (sim_fd == -1)
2184 return -errno;
2185
2186 auto sfdp = std::make_shared<SocketFDEntry>(sim_fd, domain, type, prot);
2187 int tgt_fd = p->fds->allocFD(sfdp);
2188
2189 return tgt_fd;
2190 }
2191
2192 template <class OS>
2193 SyscallReturn
2194 socketpairFunc(SyscallDesc *desc, ThreadContext *tc,
2195 int domain, int type, int prot, Addr svPtr)
2196 {
2197 auto p = tc->getProcessPtr();
2198
2199 BufferArg svBuf((Addr)svPtr, 2 * sizeof(int));
2200 int status = socketpair(domain, type, prot, (int *)svBuf.bufferPtr());
2201 if (status == -1)
2202 return -errno;
2203
2204 int *fds = (int *)svBuf.bufferPtr();
2205
2206 auto sfdp1 = std::make_shared<SocketFDEntry>(fds[0], domain, type, prot);
2207 fds[0] = p->fds->allocFD(sfdp1);
2208 auto sfdp2 = std::make_shared<SocketFDEntry>(fds[1], domain, type, prot);
2209 fds[1] = p->fds->allocFD(sfdp2);
2210 svBuf.copyOut(tc->getVirtProxy());
2211
2212 return status;
2213 }
2214
2215 template <class OS>
2216 SyscallReturn
2217 selectFunc(SyscallDesc *desc, ThreadContext *tc, int nfds,
2218 VPtr<typename OS::fd_set> readfds,
2219 VPtr<typename OS::fd_set> writefds,
2220 VPtr<typename OS::fd_set> errorfds,
2221 VPtr<typename OS::timeval> timeout)
2222 {
2223 int retval;
2224
2225 auto p = tc->getProcessPtr();
2226
2227 /**
2228 * Host fields. Notice that these use the definitions from the system
2229 * headers instead of the gem5 headers and libraries. If the host and
2230 * target have different header file definitions, this will not work.
2231 */
2232 fd_set readfds_h;
2233 FD_ZERO(&readfds_h);
2234 fd_set writefds_h;
2235 FD_ZERO(&writefds_h);
2236 fd_set errorfds_h;
2237 FD_ZERO(&errorfds_h);
2238
2239 /**
2240 * We need to translate the target file descriptor set into a host file
2241 * descriptor set. This involves both our internal process fd array
2242 * and the fd_set defined in Linux header files. The nfds field also
2243 * needs to be updated as it will be only target specific after
2244 * retrieving it from the target; the nfds value is expected to be the
2245 * highest file descriptor that needs to be checked, so we need to extend
2246 * it out for nfds_h when we do the update.
2247 */
2248 int nfds_h = 0;
2249 std::map<int, int> trans_map;
2250 auto try_add_host_set = [&](typename OS::fd_set *tgt_set_entry,
2251 fd_set *hst_set_entry,
2252 int iter) -> bool
2253 {
2254 /**
2255 * By this point, we know that we are looking at a valid file
2256 * descriptor set on the target. We need to check if the target file
2257 * descriptor value passed in as iter is part of the set.
2258 */
2259 if (FD_ISSET(iter, (fd_set *)tgt_set_entry)) {
2260 /**
2261 * We know that the target file descriptor belongs to the set,
2262 * but we do not yet know if the file descriptor is valid or
2263 * that we have a host mapping. Check that now.
2264 */
2265 auto hbfdp = std::dynamic_pointer_cast<HBFDEntry>((*p->fds)[iter]);
2266 if (!hbfdp)
2267 return true;
2268 auto sim_fd = hbfdp->getSimFD();
2269
2270 /**
2271 * Add the sim_fd to tgt_fd translation into trans_map for use
2272 * later when we need to zero the target fd_set structures and
2273 * then update them with hits returned from the host select call.
2274 */
2275 trans_map[sim_fd] = iter;
2276
2277 /**
2278 * We know that the host file descriptor exists so now we check
2279 * if we need to update the max count for nfds_h before passing
2280 * the duplicated structure into the host.
2281 */
2282 nfds_h = std::max(nfds_h - 1, sim_fd + 1);
2283
2284 /**
2285 * Add the host file descriptor to the set that we are going to
2286 * pass into the host.
2287 */
2288 FD_SET(sim_fd, hst_set_entry);
2289 }
2290 return false;
2291 };
2292
2293 for (int i = 0; i < nfds; i++) {
2294 if (readfds) {
2295 bool ebadf = try_add_host_set(readfds, &readfds_h, i);
2296 if (ebadf)
2297 return -EBADF;
2298 }
2299 if (writefds) {
2300 bool ebadf = try_add_host_set(writefds, &writefds_h, i);
2301 if (ebadf)
2302 return -EBADF;
2303 }
2304 if (errorfds) {
2305 bool ebadf = try_add_host_set(errorfds, &errorfds_h, i);
2306 if (ebadf)
2307 return -EBADF;
2308 }
2309 }
2310
2311 if (timeout) {
2312 /**
2313 * It might be possible to decrement the timeval based on some
2314 * derivation of wall clock determined from elapsed simulator ticks
2315 * but that seems like overkill. Rather, we just set the timeval with
2316 * zero timeout. (There is no reason to block during the simulation
2317 * as it only decreases simulator performance.)
2318 */
2319 timeout->tv_sec = 0;
2320 timeout->tv_usec = 0;
2321
2322 retval = select(nfds_h,
2323 readfds ? &readfds_h : nullptr,
2324 writefds ? &writefds_h : nullptr,
2325 errorfds ? &errorfds_h : nullptr,
2326 (timeval *)(typename OS::timeval *)timeout);
2327 } else {
2328 /**
2329 * If the timeval pointer is null, setup a new timeval structure to
2330 * pass into the host select call. Unfortunately, we will need to
2331 * manually check the return value and throw a retry fault if the
2332 * return value is zero. Allowing the system call to block will
2333 * likely deadlock the event queue.
2334 */
2335 struct timeval tv = { 0, 0 };
2336
2337 retval = select(nfds_h,
2338 readfds ? &readfds_h : nullptr,
2339 readfds ? &writefds_h : nullptr,
2340 readfds ? &errorfds_h : nullptr,
2341 &tv);
2342
2343 if (retval == 0) {
2344 /**
2345 * If blocking indefinitely, check the signal list to see if a
2346 * signal would break the poll out of the retry cycle and try to
2347 * return the signal interrupt instead.
2348 */
2349 for (auto sig : tc->getSystemPtr()->signalList)
2350 if (sig.receiver == p)
2351 return -EINTR;
2352 return SyscallReturn::retry();
2353 }
2354 }
2355
2356 if (retval == -1)
2357 return -errno;
2358
2359 FD_ZERO(reinterpret_cast<fd_set *>((typename OS::fd_set *)readfds));
2360 FD_ZERO(reinterpret_cast<fd_set *>((typename OS::fd_set *)writefds));
2361 FD_ZERO(reinterpret_cast<fd_set *>((typename OS::fd_set *)errorfds));
2362
2363 /**
2364 * We need to translate the host file descriptor set into a target file
2365 * descriptor set. This involves both our internal process fd array
2366 * and the fd_set defined in header files.
2367 */
2368 for (int i = 0; i < nfds_h; i++) {
2369 if (readfds && FD_ISSET(i, &readfds_h))
2370 FD_SET(trans_map[i], readfds);
2371
2372 if (writefds && FD_ISSET(i, &writefds_h))
2373 FD_SET(trans_map[i], writefds);
2374
2375 if (errorfds && FD_ISSET(i, &errorfds_h))
2376 FD_SET(trans_map[i], errorfds);
2377 }
2378
2379 return retval;
2380 }
2381
2382 template <class OS>
2383 SyscallReturn
2384 readFunc(SyscallDesc *desc, ThreadContext *tc,
2385 int tgt_fd, Addr buf_ptr, int nbytes)
2386 {
2387 auto p = tc->getProcessPtr();
2388
2389 auto hbfdp = std::dynamic_pointer_cast<HBFDEntry>((*p->fds)[tgt_fd]);
2390 if (!hbfdp)
2391 return -EBADF;
2392 int sim_fd = hbfdp->getSimFD();
2393
2394 struct pollfd pfd;
2395 pfd.fd = sim_fd;
2396 pfd.events = POLLIN | POLLPRI;
2397 if ((poll(&pfd, 1, 0) == 0)
2398 && !(hbfdp->getFlags() & OS::TGT_O_NONBLOCK))
2399 return SyscallReturn::retry();
2400
2401 BufferArg buf_arg(buf_ptr, nbytes);
2402 int bytes_read = read(sim_fd, buf_arg.bufferPtr(), nbytes);
2403
2404 if (bytes_read > 0)
2405 buf_arg.copyOut(tc->getVirtProxy());
2406
2407 return (bytes_read == -1) ? -errno : bytes_read;
2408 }
2409
2410 template <class OS>
2411 SyscallReturn
2412 writeFunc(SyscallDesc *desc, ThreadContext *tc,
2413 int tgt_fd, Addr buf_ptr, int nbytes)
2414 {
2415 auto p = tc->getProcessPtr();
2416
2417 auto hbfdp = std::dynamic_pointer_cast<HBFDEntry>((*p->fds)[tgt_fd]);
2418 if (!hbfdp)
2419 return -EBADF;
2420 int sim_fd = hbfdp->getSimFD();
2421
2422 BufferArg buf_arg(buf_ptr, nbytes);
2423 buf_arg.copyIn(tc->getVirtProxy());
2424
2425 struct pollfd pfd;
2426 pfd.fd = sim_fd;
2427 pfd.events = POLLOUT;
2428
2429 /**
2430 * We don't want to poll on /dev/random. The kernel will not enable the
2431 * file descriptor for writing unless the entropy in the system falls
2432 * below write_wakeup_threshold. This is not guaranteed to happen
2433 * depending on host settings.
2434 */
2435 auto ffdp = std::dynamic_pointer_cast<FileFDEntry>(hbfdp);
2436 if (ffdp && (ffdp->getFileName() != "/dev/random")) {
2437 if (!poll(&pfd, 1, 0) && !(ffdp->getFlags() & OS::TGT_O_NONBLOCK))
2438 return SyscallReturn::retry();
2439 }
2440
2441 int bytes_written = write(sim_fd, buf_arg.bufferPtr(), nbytes);
2442
2443 if (bytes_written != -1)
2444 fsync(sim_fd);
2445
2446 return (bytes_written == -1) ? -errno : bytes_written;
2447 }
2448
2449 template <class OS>
2450 SyscallReturn
2451 wait4Func(SyscallDesc *desc, ThreadContext *tc,
2452 pid_t pid, Addr statPtr, int options, Addr rusagePtr)
2453 {
2454 auto p = tc->getProcessPtr();
2455
2456 if (rusagePtr)
2457 DPRINTF_SYSCALL(Verbose, "wait4: rusage pointer provided %lx, however "
2458 "functionality not supported. Ignoring rusage pointer.\n",
2459 rusagePtr);
2460
2461 /**
2462 * Currently, wait4 is only implemented so that it will wait for children
2463 * exit conditions which are denoted by a SIGCHLD signals posted into the
2464 * system signal list. We return no additional information via any of the
2465 * parameters supplied to wait4. If nothing is found in the system signal
2466 * list, we will wait indefinitely for SIGCHLD to post by retrying the
2467 * call.
2468 */
2469 System *sysh = tc->getSystemPtr();
2470 std::list<BasicSignal>::iterator iter;
2471 for (iter=sysh->signalList.begin(); iter!=sysh->signalList.end(); iter++) {
2472 if (iter->receiver == p) {
2473 if (pid < -1) {
2474 if ((iter->sender->pgid() == -pid)
2475 && (iter->signalValue == OS::TGT_SIGCHLD))
2476 goto success;
2477 } else if (pid == -1) {
2478 if (iter->signalValue == OS::TGT_SIGCHLD)
2479 goto success;
2480 } else if (pid == 0) {
2481 if ((iter->sender->pgid() == p->pgid())
2482 && (iter->signalValue == OS::TGT_SIGCHLD))
2483 goto success;
2484 } else {
2485 if ((iter->sender->pid() == pid)
2486 && (iter->signalValue == OS::TGT_SIGCHLD))
2487 goto success;
2488 }
2489 }
2490 }
2491
2492 return (options & OS::TGT_WNOHANG) ? 0 : SyscallReturn::retry();
2493
2494 success:
2495 // Set status to EXITED for WIFEXITED evaluations.
2496 const int EXITED = 0;
2497 BufferArg statusBuf(statPtr, sizeof(int));
2498 *(int *)statusBuf.bufferPtr() = EXITED;
2499 statusBuf.copyOut(tc->getVirtProxy());
2500
2501 // Return the child PID.
2502 pid_t retval = iter->sender->pid();
2503 sysh->signalList.erase(iter);
2504 return retval;
2505 }
2506
2507 template <class OS>
2508 SyscallReturn
2509 acceptFunc(SyscallDesc *desc, ThreadContext *tc,
2510 int tgt_fd, Addr addrPtr, Addr lenPtr)
2511 {
2512 struct sockaddr sa;
2513 socklen_t addrLen;
2514 int host_fd;
2515 auto p = tc->getProcessPtr();
2516
2517 BufferArg *lenBufPtr = nullptr;
2518 BufferArg *addrBufPtr = nullptr;
2519
2520 auto sfdp = std::dynamic_pointer_cast<SocketFDEntry>((*p->fds)[tgt_fd]);
2521 if (!sfdp)
2522 return -EBADF;
2523 int sim_fd = sfdp->getSimFD();
2524
2525 /**
2526 * We poll the socket file descriptor first to guarantee that we do not
2527 * block on our accept call. The socket can be opened without the
2528 * non-blocking flag (it blocks). This will cause deadlocks between
2529 * communicating processes.
2530 */
2531 struct pollfd pfd;
2532 pfd.fd = sim_fd;
2533 pfd.events = POLLIN | POLLPRI;
2534 if ((poll(&pfd, 1, 0) == 0) && !(sfdp->getFlags() & OS::TGT_O_NONBLOCK))
2535 return SyscallReturn::retry();
2536
2537 if (lenPtr) {
2538 lenBufPtr = new BufferArg(lenPtr, sizeof(socklen_t));
2539 lenBufPtr->copyIn(tc->getVirtProxy());
2540 memcpy(&addrLen, (socklen_t *)lenBufPtr->bufferPtr(),
2541 sizeof(socklen_t));
2542 }
2543
2544 if (addrPtr) {
2545 addrBufPtr = new BufferArg(addrPtr, sizeof(struct sockaddr));
2546 addrBufPtr->copyIn(tc->getVirtProxy());
2547 memcpy(&sa, (struct sockaddr *)addrBufPtr->bufferPtr(),
2548 sizeof(struct sockaddr));
2549 }
2550
2551 host_fd = accept(sim_fd, &sa, &addrLen);
2552
2553 if (host_fd == -1)
2554 return -errno;
2555
2556 if (addrPtr) {
2557 memcpy(addrBufPtr->bufferPtr(), &sa, sizeof(sa));
2558 addrBufPtr->copyOut(tc->getVirtProxy());
2559 delete(addrBufPtr);
2560 }
2561
2562 if (lenPtr) {
2563 *(socklen_t *)lenBufPtr->bufferPtr() = addrLen;
2564 lenBufPtr->copyOut(tc->getVirtProxy());
2565 delete(lenBufPtr);
2566 }
2567
2568 auto afdp = std::make_shared<SocketFDEntry>(host_fd, sfdp->_domain,
2569 sfdp->_type, sfdp->_protocol);
2570 return p->fds->allocFD(afdp);
2571 }
2572
2573 /// Target eventfd() function.
2574 template <class OS>
2575 SyscallReturn
2576 eventfdFunc(SyscallDesc *desc, ThreadContext *tc,
2577 unsigned initval, int in_flags)
2578 {
2579 #if defined(__linux__)
2580 auto p = tc->getProcessPtr();
2581
2582 int sim_fd = eventfd(initval, in_flags);
2583 if (sim_fd == -1)
2584 return -errno;
2585
2586 bool cloexec = in_flags & OS::TGT_O_CLOEXEC;
2587
2588 int flags = cloexec ? OS::TGT_O_CLOEXEC : 0;
2589 flags |= (in_flags & OS::TGT_O_NONBLOCK) ? OS::TGT_O_NONBLOCK : 0;
2590
2591 auto hbfdp = std::make_shared<HBFDEntry>(flags, sim_fd, cloexec);
2592 int tgt_fd = p->fds->allocFD(hbfdp);
2593 return tgt_fd;
2594 #else
2595 warnUnsupportedOS("eventfd");
2596 return -1;
2597 #endif
2598 }
2599
2600 #endif // __SIM_SYSCALL_EMUL_HH__