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