2 * Copyright (c) 2003-2005 The Regents of The University of Michigan
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are
7 * met: redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer;
9 * redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution;
12 * neither the name of the copyright holders nor the names of its
13 * contributors may be used to endorse or promote products derived from
14 * this software without specific prior written permission.
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 #include "sim/syscall_emul.hh"
32 #include <sys/syscall.h>
39 #include <unordered_map>
41 #include "arch/utility.hh"
42 #include "base/chunk_generator.hh"
43 #include "base/trace.hh"
44 #include "config/the_isa.hh"
45 #include "cpu/thread_context.hh"
46 #include "dev/net/dist_iface.hh"
47 #include "mem/page_table.hh"
48 #include "sim/byteswap.hh"
49 #include "sim/process.hh"
50 #include "sim/sim_exit.hh"
51 #include "sim/syscall_debug_macros.hh"
52 #include "sim/syscall_desc.hh"
53 #include "sim/system.hh"
56 using namespace TheISA
;
59 warnUnsupportedOS(std::string syscall_name
)
61 warn("Cannot invoke %s on host operating system.", syscall_name
);
65 unimplementedFunc(SyscallDesc
*desc
, ThreadContext
*tc
)
67 fatal("syscall %s (#%d) unimplemented.", desc
->name(), desc
->num());
72 ignoreFunc(SyscallDesc
*desc
, ThreadContext
*tc
)
74 warn("ignoring syscall %s(...)", desc
->name());
79 ignoreWarnOnceFunc(SyscallDesc
*desc
, ThreadContext
*tc
)
81 static std::unordered_map
<SyscallDesc
*, bool> bool_map
;
83 bool &warned
= bool_map
[desc
];
85 warn("ignoring syscall %s(...)\n"
86 " (further warnings will be suppressed)", desc
->name());
94 exitFutexWake(ThreadContext
*tc
, Addr addr
, uint64_t tgid
)
96 // Clear value at address pointed to by thread's childClearTID field.
97 BufferArg
ctidBuf(addr
, sizeof(long));
98 long *ctid
= (long *)ctidBuf
.bufferPtr();
100 ctidBuf
.copyOut(tc
->getVirtProxy());
102 FutexMap
&futex_map
= tc
->getSystemPtr()->futexMap
;
103 // Wake one of the waiting threads.
104 futex_map
.wakeup(addr
, tgid
, 1);
108 exitImpl(SyscallDesc
*desc
, ThreadContext
*tc
, bool group
, int status
)
110 auto p
= tc
->getProcessPtr();
112 System
*sys
= tc
->getSystemPtr();
115 *p
->exitGroup
= true;
117 if (p
->childClearTID
)
118 exitFutexWake(tc
, p
->childClearTID
, p
->tgid());
120 bool last_thread
= true;
121 Process
*parent
= nullptr, *tg_lead
= nullptr;
122 for (int i
= 0; last_thread
&& i
< sys
->threads
.size(); i
++) {
124 if (!(walk
= sys
->threads
[i
]->getProcessPtr()))
128 * Threads in a thread group require special handing. For instance,
129 * we send the SIGCHLD signal so that it appears that it came from
130 * the head of the group. We also only delete file descriptors if
131 * we are the last thread in the thread group.
133 if (walk
->pid() == p
->tgid())
136 auto *tc
= sys
->threads
[i
];
137 if ((tc
->status() != ThreadContext::Halted
) &&
138 (tc
->status() != ThreadContext::Halting
) &&
141 * Check if we share thread group with the pointer; this denotes
142 * that we are not the last thread active in the thread group.
143 * Note that setting this to false also prevents further
144 * iterations of the loop.
146 if (walk
->tgid() == p
->tgid()) {
148 * If p is trying to exit_group and both walk and p are in
149 * the same thread group (i.e., sharing the same tgid),
150 * we need to halt walk's thread context. After all threads
151 * except p are halted, p becomes the last thread in the
154 * If p is not doing exit_group and there exists another
155 * active thread context in the group, last_thread is
156 * set to false to prevent the parent thread from killing
157 * all threads in the group.
159 if (*(p
->exitGroup
)) {
167 * A corner case exists which involves execve(). After execve(),
168 * the execve will enable SIGCHLD in the process. The problem
169 * occurs when the exiting process is the root process in the
170 * system; there is no parent to receive the signal. We obviate
171 * this problem by setting the root process' ppid to zero in the
172 * Python configuration files. We really should handle the
173 * root/execve specific case more gracefully.
175 if (*p
->sigchld
&& (p
->ppid() != 0) && (walk
->pid() == p
->ppid()))
183 sys
->signalList
.push_back(BasicSignal(tg_lead
, parent
, SIGCHLD
));
187 * Run though FD array of the exiting process and close all file
188 * descriptors except for the standard file descriptors.
189 * (The standard file descriptors are shared with gem5.)
191 for (int i
= 0; i
< p
->fds
->getSize(); i
++) {
193 p
->fds
->closeFDEntry(i
);
200 * check to see if there is no more active thread in the system. If so,
201 * exit the simulation loop
203 int activeContexts
= 0;
204 for (auto &system
: sys
->systemList
)
205 activeContexts
+= system
->threads
.numRunning();
207 if (activeContexts
== 0) {
209 * Even though we are terminating the final thread context, dist-gem5
210 * requires the simulation to remain active and provide
211 * synchronization messages to the switch process. So we just halt
212 * the last thread context and return. The simulation will be
213 * terminated by dist-gem5 in a coordinated manner once all nodes
214 * have signaled their readiness to exit. For non dist-gem5
215 * simulations, readyToExit() always returns true.
217 if (!DistIface::readyToExit(0)) {
221 exitSimLoop("exiting with last active thread context", status
& 0xff);
229 exitFunc(SyscallDesc
*desc
, ThreadContext
*tc
, int status
)
231 return exitImpl(desc
, tc
, false, status
);
235 exitGroupFunc(SyscallDesc
*desc
, ThreadContext
*tc
, int status
)
237 return exitImpl(desc
, tc
, true, status
);
241 getpagesizeFunc(SyscallDesc
*desc
, ThreadContext
*tc
)
243 return (int)PageBytes
;
248 brkFunc(SyscallDesc
*desc
, ThreadContext
*tc
, Addr new_brk
)
250 // change brk addr to first arg
251 auto p
= tc
->getProcessPtr();
253 std::shared_ptr
<MemState
> mem_state
= p
->memState
;
254 Addr brk_point
= mem_state
->getBrkPoint();
256 // in Linux at least, brk(0) returns the current break value
257 // (note that the syscall and the glibc function have different behavior)
258 if (new_brk
== 0 || (new_brk
== brk_point
))
261 mem_state
->updateBrkRegion(brk_point
, new_brk
);
263 DPRINTF_SYSCALL(Verbose
, "brk: break point changed to: %#X\n",
264 mem_state
->getBrkPoint());
266 return mem_state
->getBrkPoint();
270 setTidAddressFunc(SyscallDesc
*desc
, ThreadContext
*tc
, uint64_t tidPtr
)
272 auto process
= tc
->getProcessPtr();
274 process
->childClearTID
= tidPtr
;
275 return process
->pid();
279 closeFunc(SyscallDesc
*desc
, ThreadContext
*tc
, int tgt_fd
)
281 auto p
= tc
->getProcessPtr();
282 return p
->fds
->closeFDEntry(tgt_fd
);
286 lseekFunc(SyscallDesc
*desc
, ThreadContext
*tc
,
287 int tgt_fd
, uint64_t offs
, int whence
)
289 auto p
= tc
->getProcessPtr();
291 auto ffdp
= std::dynamic_pointer_cast
<FileFDEntry
>((*p
->fds
)[tgt_fd
]);
294 int sim_fd
= ffdp
->getSimFD();
296 off_t result
= lseek(sim_fd
, offs
, whence
);
298 return (result
== (off_t
)-1) ? -errno
: result
;
303 _llseekFunc(SyscallDesc
*desc
, ThreadContext
*tc
,
304 int tgt_fd
, uint64_t offset_high
, uint32_t offset_low
,
305 Addr result_ptr
, int whence
)
307 auto p
= tc
->getProcessPtr();
309 auto ffdp
= std::dynamic_pointer_cast
<FileFDEntry
>((*p
->fds
)[tgt_fd
]);
312 int sim_fd
= ffdp
->getSimFD();
314 uint64_t offset
= (offset_high
<< 32) | offset_low
;
316 uint64_t result
= lseek(sim_fd
, offset
, whence
);
317 result
= htog(result
, tc
->getSystemPtr()->getGuestByteOrder());
319 if (result
== (off_t
)-1)
321 // Assuming that the size of loff_t is 64 bits on the target platform
322 BufferArg
result_buf(result_ptr
, sizeof(result
));
323 memcpy(result_buf
.bufferPtr(), &result
, sizeof(result
));
324 result_buf
.copyOut(tc
->getVirtProxy());
330 munmapFunc(SyscallDesc
*desc
, ThreadContext
*tc
, Addr start
, size_t length
)
332 // Even if the system is currently not capable of recycling physical
333 // pages, there is no reason we can't unmap them so that we trigger
334 // appropriate seg faults when the application mistakenly tries to
335 // access them again.
336 auto p
= tc
->getProcessPtr();
338 if (start
& (tc
->getSystemPtr()->getPageBytes() - 1) || !length
) {
342 length
= roundUp(length
, tc
->getSystemPtr()->getPageBytes());
344 p
->memState
->unmapRegion(start
, length
);
350 const char *hostname
= "m5.eecs.umich.edu";
353 gethostnameFunc(SyscallDesc
*desc
, ThreadContext
*tc
,
354 Addr buf_ptr
, int name_len
)
356 BufferArg
name(buf_ptr
, name_len
);
357 strncpy((char *)name
.bufferPtr(), hostname
, name_len
);
358 name
.copyOut(tc
->getVirtProxy());
363 getcwdFunc(SyscallDesc
*desc
, ThreadContext
*tc
,
364 Addr buf_ptr
, unsigned long size
)
367 auto p
= tc
->getProcessPtr();
368 BufferArg
buf(buf_ptr
, size
);
370 // Is current working directory defined?
371 string cwd
= p
->tgtCwd
;
373 if (cwd
.length() >= size
) {
377 strncpy((char *)buf
.bufferPtr(), cwd
.c_str(), size
);
378 result
= cwd
.length();
380 if (getcwd((char *)buf
.bufferPtr(), size
)) {
381 result
= strlen((char *)buf
.bufferPtr());
387 buf
.copyOut(tc
->getVirtProxy());
389 return (result
== -1) ? -errno
: result
;
393 readlinkFunc(SyscallDesc
*desc
, ThreadContext
*tc
,
394 Addr pathname
, Addr buf_ptr
, size_t bufsiz
)
397 auto p
= tc
->getProcessPtr();
399 if (!tc
->getVirtProxy().tryReadString(path
, pathname
))
402 // Adjust path for cwd and redirection
403 path
= p
->checkPathRedirect(path
);
405 BufferArg
buf(buf_ptr
, bufsiz
);
408 if (path
!= "/proc/self/exe") {
409 result
= readlink(path
.c_str(), (char *)buf
.bufferPtr(), bufsiz
);
411 // Emulate readlink() called on '/proc/self/exe' should return the
412 // absolute path of the binary running in the simulated system (the
413 // Process' executable). It is possible that using this path in
414 // the simulated system will result in unexpected behavior if:
415 // 1) One binary runs another (e.g., -c time -o "my_binary"), and
416 // called binary calls readlink().
417 // 2) The host's full path to the running benchmark changes from one
418 // simulation to another. This can result in different simulated
419 // performance since the simulated system will process the binary
420 // path differently, even if the binary itself does not change.
422 // Get the absolute canonical path to the running application
423 char real_path
[PATH_MAX
];
424 char *check_real_path
= realpath(p
->progName(), real_path
);
425 if (!check_real_path
) {
426 fatal("readlink('/proc/self/exe') unable to resolve path to "
427 "executable: %s", p
->progName());
429 strncpy((char*)buf
.bufferPtr(), real_path
, bufsiz
);
430 size_t real_path_len
= strlen(real_path
);
431 if (real_path_len
> bufsiz
) {
432 // readlink will truncate the contents of the
433 // path to ensure it is no more than bufsiz
436 result
= real_path_len
;
439 // Issue a warning about potential unexpected results
440 warn_once("readlink() called on '/proc/self/exe' may yield unexpected "
441 "results in various settings.\n Returning '%s'\n",
442 (char*)buf
.bufferPtr());
445 buf
.copyOut(tc
->getVirtProxy());
447 return (result
== -1) ? -errno
: result
;
451 unlinkFunc(SyscallDesc
*desc
, ThreadContext
*tc
, Addr pathname
)
454 auto p
= tc
->getProcessPtr();
456 if (!tc
->getVirtProxy().tryReadString(path
, pathname
))
459 path
= p
->checkPathRedirect(path
);
461 int result
= unlink(path
.c_str());
462 return (result
== -1) ? -errno
: result
;
466 linkFunc(SyscallDesc
*desc
, ThreadContext
*tc
,
467 Addr pathname
, Addr new_pathname
)
471 auto p
= tc
->getProcessPtr();
473 auto &virt_mem
= tc
->getVirtProxy();
474 if (!virt_mem
.tryReadString(path
, pathname
))
476 if (!virt_mem
.tryReadString(new_path
, new_pathname
))
479 path
= p
->absolutePath(path
, true);
480 new_path
= p
->absolutePath(new_path
, true);
482 int result
= link(path
.c_str(), new_path
.c_str());
483 return (result
== -1) ? -errno
: result
;
487 symlinkFunc(SyscallDesc
*desc
, ThreadContext
*tc
,
488 Addr pathname
, Addr new_pathname
)
492 auto p
= tc
->getProcessPtr();
494 auto &virt_mem
= tc
->getVirtProxy();
495 if (!virt_mem
.tryReadString(path
, pathname
))
497 if (!virt_mem
.tryReadString(new_path
, new_pathname
))
500 path
= p
->absolutePath(path
, true);
501 new_path
= p
->absolutePath(new_path
, true);
503 int result
= symlink(path
.c_str(), new_path
.c_str());
504 return (result
== -1) ? -errno
: result
;
508 mkdirFunc(SyscallDesc
*desc
, ThreadContext
*tc
, Addr pathname
, mode_t mode
)
510 auto p
= tc
->getProcessPtr();
512 if (!tc
->getVirtProxy().tryReadString(path
, pathname
))
515 path
= p
->checkPathRedirect(path
);
517 auto result
= mkdir(path
.c_str(), mode
);
518 return (result
== -1) ? -errno
: result
;
522 renameFunc(SyscallDesc
*desc
, ThreadContext
*tc
, Addr oldpath
, Addr newpath
)
524 auto p
= tc
->getProcessPtr();
527 if (!tc
->getVirtProxy().tryReadString(old_name
, oldpath
))
531 if (!tc
->getVirtProxy().tryReadString(new_name
, newpath
))
534 // Adjust path for cwd and redirection
535 old_name
= p
->checkPathRedirect(old_name
);
536 new_name
= p
->checkPathRedirect(new_name
);
538 int64_t result
= rename(old_name
.c_str(), new_name
.c_str());
539 return (result
== -1) ? -errno
: result
;
543 truncateFunc(SyscallDesc
*desc
, ThreadContext
*tc
, Addr pathname
, off_t length
)
546 auto p
= tc
->getProcessPtr();
548 if (!tc
->getVirtProxy().tryReadString(path
, pathname
))
551 // Adjust path for cwd and redirection
552 path
= p
->checkPathRedirect(path
);
554 int result
= truncate(path
.c_str(), length
);
555 return (result
== -1) ? -errno
: result
;
559 ftruncateFunc(SyscallDesc
*desc
, ThreadContext
*tc
, int tgt_fd
, off_t length
)
561 auto p
= tc
->getProcessPtr();
563 auto ffdp
= std::dynamic_pointer_cast
<FileFDEntry
>((*p
->fds
)[tgt_fd
]);
566 int sim_fd
= ffdp
->getSimFD();
568 int result
= ftruncate(sim_fd
, length
);
569 return (result
== -1) ? -errno
: result
;
573 truncate64Func(SyscallDesc
*desc
, ThreadContext
*tc
,
574 Addr pathname
, int64_t length
)
576 auto process
= tc
->getProcessPtr();
579 if (!tc
->getVirtProxy().tryReadString(path
, pathname
))
582 // Adjust path for cwd and redirection
583 path
= process
->checkPathRedirect(path
);
586 int result
= truncate(path
.c_str(), length
);
588 int result
= truncate64(path
.c_str(), length
);
590 return (result
== -1) ? -errno
: result
;
594 ftruncate64Func(SyscallDesc
*desc
, ThreadContext
*tc
,
595 int tgt_fd
, int64_t length
)
597 auto p
= tc
->getProcessPtr();
599 auto ffdp
= std::dynamic_pointer_cast
<FileFDEntry
>((*p
->fds
)[tgt_fd
]);
602 int sim_fd
= ffdp
->getSimFD();
605 int result
= ftruncate(sim_fd
, length
);
607 int result
= ftruncate64(sim_fd
, length
);
609 return (result
== -1) ? -errno
: result
;
613 umaskFunc(SyscallDesc
*desc
, ThreadContext
*tc
)
615 // Letting the simulated program change the simulator's umask seems like
616 // a bad idea. Compromise by just returning the current umask but not
617 // changing anything.
618 mode_t oldMask
= umask(0);
624 chownFunc(SyscallDesc
*desc
, ThreadContext
*tc
,
625 Addr pathname
, uint32_t owner
, uint32_t group
)
628 auto p
= tc
->getProcessPtr();
630 if (!tc
->getVirtProxy().tryReadString(path
, pathname
))
634 uid_t hostOwner
= owner
;
635 gid_t hostGroup
= group
;
637 // Adjust path for cwd and redirection
638 path
= p
->checkPathRedirect(path
);
640 int result
= chown(path
.c_str(), hostOwner
, hostGroup
);
641 return (result
== -1) ? -errno
: result
;
645 fchownFunc(SyscallDesc
*desc
, ThreadContext
*tc
,
646 int tgt_fd
, uint32_t owner
, uint32_t group
)
648 auto p
= tc
->getProcessPtr();
650 auto ffdp
= std::dynamic_pointer_cast
<FileFDEntry
>((*p
->fds
)[tgt_fd
]);
653 int sim_fd
= ffdp
->getSimFD();
656 uid_t hostOwner
= owner
;
657 gid_t hostGroup
= group
;
659 int result
= fchown(sim_fd
, hostOwner
, hostGroup
);
660 return (result
== -1) ? -errno
: result
;
664 * FIXME: The file description is not shared among file descriptors created
665 * with dup. Really, it's difficult to maintain fields like file offset or
666 * flags since an update to such a field won't be reflected in the metadata
667 * for the fd entries that we maintain for checkpoint restoration.
670 dupFunc(SyscallDesc
*desc
, ThreadContext
*tc
, int tgt_fd
)
672 auto p
= tc
->getProcessPtr();
674 auto old_hbfdp
= std::dynamic_pointer_cast
<HBFDEntry
>((*p
->fds
)[tgt_fd
]);
677 int sim_fd
= old_hbfdp
->getSimFD();
679 int result
= dup(sim_fd
);
683 auto new_hbfdp
= std::dynamic_pointer_cast
<HBFDEntry
>(old_hbfdp
->clone());
684 new_hbfdp
->setSimFD(result
);
685 new_hbfdp
->setCOE(false);
686 return p
->fds
->allocFD(new_hbfdp
);
690 dup2Func(SyscallDesc
*desc
, ThreadContext
*tc
, int old_tgt_fd
, int new_tgt_fd
)
692 auto p
= tc
->getProcessPtr();
693 auto old_hbp
= std::dynamic_pointer_cast
<HBFDEntry
>((*p
->fds
)[old_tgt_fd
]);
696 int old_sim_fd
= old_hbp
->getSimFD();
699 * We need a valid host file descriptor number to be able to pass into
700 * the second parameter for dup2 (newfd), but we don't know what the
701 * viable numbers are; we execute the open call to retrieve one.
703 int res_fd
= dup2(old_sim_fd
, open("/dev/null", O_RDONLY
));
707 auto new_hbp
= std::dynamic_pointer_cast
<HBFDEntry
>((*p
->fds
)[new_tgt_fd
]);
709 p
->fds
->closeFDEntry(new_tgt_fd
);
710 new_hbp
= std::dynamic_pointer_cast
<HBFDEntry
>(old_hbp
->clone());
711 new_hbp
->setSimFD(res_fd
);
712 new_hbp
->setCOE(false);
714 return p
->fds
->allocFD(new_hbp
);
718 fcntlFunc(SyscallDesc
*desc
, ThreadContext
*tc
,
719 int tgt_fd
, int cmd
, GuestABI::VarArgs
<int> varargs
)
721 auto p
= tc
->getProcessPtr();
723 auto hbfdp
= std::dynamic_pointer_cast
<HBFDEntry
>((*p
->fds
)[tgt_fd
]);
726 int sim_fd
= hbfdp
->getSimFD();
728 int coe
= hbfdp
->getCOE();
732 return coe
& FD_CLOEXEC
;
735 int arg
= varargs
.get
<int>();
736 arg
? hbfdp
->setCOE(true) : hbfdp
->setCOE(false);
740 // Rely on the host to maintain the file status flags for this file
741 // description rather than maintain it ourselves. Admittedly, this
742 // is suboptimal (and possibly error prone), but it is difficult to
743 // maintain the flags by tracking them across the different descriptors
744 // (that refer to this file description) caused by clone, dup, and
745 // subsequent fcntls.
748 int arg
= varargs
.get
<int>();
749 int rv
= fcntl(sim_fd
, cmd
, arg
);
750 return (rv
== -1) ? -errno
: rv
;
754 warn("fcntl: unsupported command %d\n", cmd
);
760 fcntl64Func(SyscallDesc
*desc
, ThreadContext
*tc
, int tgt_fd
, int cmd
)
762 auto p
= tc
->getProcessPtr();
764 auto hbfdp
= std::dynamic_pointer_cast
<HBFDEntry
>((*p
->fds
)[tgt_fd
]);
767 int sim_fd
= hbfdp
->getSimFD();
771 warn("fcntl64(%d, F_GETLK64) not supported, error returned\n", tgt_fd
);
774 case 34: // F_SETLK64
775 case 35: // F_SETLKW64
776 warn("fcntl64(%d, F_SETLK(W)64) not supported, error returned\n",
781 // not sure if this is totally valid, but we'll pass it through
782 // to the underlying OS
783 warn("fcntl64(%d, %d) passed through to host\n", tgt_fd
, cmd
);
784 return fcntl(sim_fd
, cmd
);
789 pipePseudoFunc(SyscallDesc
*desc
, ThreadContext
*tc
)
791 return pipe2Func(desc
, tc
, 0, 0);
795 pipeFunc(SyscallDesc
*desc
, ThreadContext
*tc
, Addr tgt_addr
)
797 return pipe2Func(desc
, tc
, tgt_addr
, 0);
801 pipe2Func(SyscallDesc
*desc
, ThreadContext
*tc
, Addr tgt_addr
, int flags
)
803 auto p
= tc
->getProcessPtr();
805 int sim_fds
[2], tgt_fds
[2];
807 int pipe_retval
= pipe(sim_fds
);
808 if (pipe_retval
== -1)
811 auto rend
= PipeFDEntry::EndType::read
;
812 auto rpfd
= std::make_shared
<PipeFDEntry
>(sim_fds
[0], O_WRONLY
, rend
);
813 tgt_fds
[0] = p
->fds
->allocFD(rpfd
);
814 int sim_fd_rpfd
= rpfd
->getSimFD();
816 auto wend
= PipeFDEntry::EndType::write
;
817 auto wpfd
= std::make_shared
<PipeFDEntry
>(sim_fds
[1], O_RDONLY
, wend
);
818 tgt_fds
[1] = p
->fds
->allocFD(wpfd
);
819 int sim_fd_wpfd
= wpfd
->getSimFD();
822 * Now patch the read object to record the target file descriptor chosen
823 * as the write end of the pipe.
825 rpfd
->setPipeReadSource(tgt_fds
[1]);
828 * On some architectures, it's possible to use more than one register for
829 * a return value. In those cases, pipe returns its values rather than
830 * write them into a buffer.
833 return SyscallReturn(tgt_fds
[0], tgt_fds
[1]);
836 * Copy the target file descriptors into buffer space and then copy
837 * the buffer space back into the target address space.
839 BufferArg
tgt_handle(tgt_addr
, sizeof(int[2]));
840 int *buf_ptr
= (int*)tgt_handle
.bufferPtr();
841 buf_ptr
[0] = tgt_fds
[0];
842 buf_ptr
[1] = tgt_fds
[1];
843 tgt_handle
.copyOut(tc
->getVirtProxy());
846 // pipe2 only uses O_NONBLOCK, O_CLOEXEC, and (O_NONBLOCK | O_CLOEXEC)
847 // if flags set to anything else, return EINVAL
848 if ((flags
!= O_CLOEXEC
) && (flags
!= O_NONBLOCK
) &&
849 (flags
!= (O_CLOEXEC
| O_NONBLOCK
))) {
854 If O_NONBLOCK is passed in as a flag to pipe2, set O_NONBLOCK file
855 status flag for two new open file descriptors.
857 if (flags
& O_NONBLOCK
) {
859 O_NONBLOCK is set when the programmer wants to avoid a separate
860 call(s) to fcntl in their code, so mirror the fcntl
861 implementation for handling file descriptors -- rely on host to
862 maintain file status flags.
864 if (fcntl(sim_fd_rpfd
, F_SETFL
, O_NONBLOCK
)) {
867 if (fcntl(sim_fd_wpfd
, F_SETFL
, O_NONBLOCK
)) {
873 If O_CLOEXEC is passed in as a flag to pipe2, set close-on-exec
874 (FD_CLOEXEC) file status flag for two new open file descriptors.
876 if (flags
& O_CLOEXEC
) {
886 getpgrpFunc(SyscallDesc
*desc
, ThreadContext
*tc
)
888 auto process
= tc
->getProcessPtr();
889 return process
->pgid();
893 setpgidFunc(SyscallDesc
*desc
, ThreadContext
*tc
, int pid
, int pgid
)
895 auto process
= tc
->getProcessPtr();
901 process
->pgid(process
->pid());
905 Process
*matched_ph
= nullptr;
906 System
*sysh
= tc
->getSystemPtr();
908 // Retrieves process pointer from active/suspended thread contexts.
909 for (auto *tc
: sysh
->threads
) {
910 if (tc
->status() != ThreadContext::Halted
) {
911 Process
*temp_h
= tc
->getProcessPtr();
912 Process
*walk_ph
= (Process
*)temp_h
;
914 if (walk_ph
&& walk_ph
->pid() == process
->pid())
915 matched_ph
= walk_ph
;
920 matched_ph
->pgid((pgid
== 0) ? matched_ph
->pid() : pgid
);
927 getpidFunc(SyscallDesc
*desc
, ThreadContext
*tc
)
929 auto process
= tc
->getProcessPtr();
930 return process
->tgid();
934 gettidFunc(SyscallDesc
*desc
, ThreadContext
*tc
)
936 auto process
= tc
->getProcessPtr();
937 return process
->pid();
941 getppidFunc(SyscallDesc
*desc
, ThreadContext
*tc
)
943 auto process
= tc
->getProcessPtr();
944 return process
->ppid();
948 getuidFunc(SyscallDesc
*desc
, ThreadContext
*tc
)
950 auto process
= tc
->getProcessPtr();
951 return process
->uid(); // UID
955 geteuidFunc(SyscallDesc
*desc
, ThreadContext
*tc
)
957 auto process
= tc
->getProcessPtr();
958 return process
->euid(); // UID
962 getgidFunc(SyscallDesc
*desc
, ThreadContext
*tc
)
964 auto process
= tc
->getProcessPtr();
965 return process
->gid();
969 getegidFunc(SyscallDesc
*desc
, ThreadContext
*tc
)
971 auto process
= tc
->getProcessPtr();
972 return process
->egid();
976 fallocateFunc(SyscallDesc
*desc
, ThreadContext
*tc
,
977 int tgt_fd
, int mode
, off_t offset
, off_t len
)
979 #if defined(__linux__)
980 auto p
= tc
->getProcessPtr();
982 auto ffdp
= std::dynamic_pointer_cast
<FileFDEntry
>((*p
->fds
)[tgt_fd
]);
985 int sim_fd
= ffdp
->getSimFD();
987 int result
= fallocate(sim_fd
, mode
, offset
, len
);
992 warnUnsupportedOS("fallocate");
998 accessFunc(SyscallDesc
*desc
, ThreadContext
*tc
,
999 Addr pathname
, mode_t mode
)
1002 auto p
= tc
->getProcessPtr();
1003 if (!tc
->getVirtProxy().tryReadString(path
, pathname
))
1006 // Adjust path for cwd and redirection
1007 path
= p
->checkPathRedirect(path
);
1009 int result
= access(path
.c_str(), mode
);
1010 return (result
== -1) ? -errno
: result
;
1014 mknodFunc(SyscallDesc
*desc
, ThreadContext
*tc
,
1015 Addr pathname
, mode_t mode
, dev_t dev
)
1017 auto p
= tc
->getProcessPtr();
1019 if (!tc
->getVirtProxy().tryReadString(path
, pathname
))
1022 path
= p
->checkPathRedirect(path
);
1024 auto result
= mknod(path
.c_str(), mode
, dev
);
1025 return (result
== -1) ? -errno
: result
;
1029 chdirFunc(SyscallDesc
*desc
, ThreadContext
*tc
, Addr pathname
)
1031 auto p
= tc
->getProcessPtr();
1033 if (!tc
->getVirtProxy().tryReadString(path
, pathname
))
1036 std::string tgt_cwd
;
1037 if (startswith(path
, "/")) {
1041 tgt_cwd
= realpath((p
->tgtCwd
+ "/" + path
).c_str(), buf
);
1043 std::string host_cwd
= p
->checkPathRedirect(tgt_cwd
);
1045 int result
= chdir(host_cwd
.c_str());
1050 p
->hostCwd
= host_cwd
;
1051 p
->tgtCwd
= tgt_cwd
;
1056 rmdirFunc(SyscallDesc
*desc
, ThreadContext
*tc
, Addr pathname
)
1058 auto p
= tc
->getProcessPtr();
1060 if (!tc
->getVirtProxy().tryReadString(path
, pathname
))
1063 path
= p
->checkPathRedirect(path
);
1065 auto result
= rmdir(path
.c_str());
1066 return (result
== -1) ? -errno
: result
;
1069 #if defined(SYS_getdents) || defined(SYS_getdents64)
1070 template<typename DE
, int SYS_NUM
>
1071 static SyscallReturn
1072 getdentsImpl(SyscallDesc
*desc
, ThreadContext
*tc
,
1073 int tgt_fd
, Addr buf_ptr
, unsigned count
)
1075 auto p
= tc
->getProcessPtr();
1077 auto hbfdp
= std::dynamic_pointer_cast
<HBFDEntry
>((*p
->fds
)[tgt_fd
]);
1080 int sim_fd
= hbfdp
->getSimFD();
1082 BufferArg
buf_arg(buf_ptr
, count
);
1083 auto status
= syscall(SYS_NUM
, sim_fd
, buf_arg
.bufferPtr(), count
);
1088 unsigned traversed
= 0;
1089 while (traversed
< status
) {
1090 DE
*buffer
= (DE
*)((Addr
)buf_arg
.bufferPtr() + traversed
);
1092 auto host_reclen
= buffer
->d_reclen
;
1095 * Convert the byte ordering from the host to the target before
1096 * passing the data back into the target's address space to preserve
1099 const ByteOrder bo
= tc
->getSystemPtr()->getGuestByteOrder();
1100 buffer
->d_ino
= htog(buffer
->d_ino
, bo
);
1101 buffer
->d_off
= htog(buffer
->d_off
, bo
);
1102 buffer
->d_reclen
= htog(buffer
->d_reclen
, bo
);
1104 traversed
+= host_reclen
;
1107 buf_arg
.copyOut(tc
->getVirtProxy());
1112 #if defined(SYS_getdents)
1114 getdentsFunc(SyscallDesc
*desc
, ThreadContext
*tc
,
1115 int tgt_fd
, Addr buf_ptr
, unsigned count
)
1117 typedef struct linux_dirent
{
1118 unsigned long d_ino
;
1119 unsigned long d_off
;
1120 unsigned short d_reclen
;
1124 return getdentsImpl
<LinDent
, SYS_getdents
>(desc
, tc
,
1125 tgt_fd
, buf_ptr
, count
);
1129 #if defined(SYS_getdents64)
1131 getdents64Func(SyscallDesc
*desc
, ThreadContext
*tc
,
1132 int tgt_fd
, Addr buf_ptr
, unsigned count
)
1134 typedef struct linux_dirent64
{
1137 unsigned short d_reclen
;
1141 return getdentsImpl
<LinDent64
, SYS_getdents64
>(desc
, tc
,
1142 tgt_fd
, buf_ptr
, count
);
1147 shutdownFunc(SyscallDesc
*desc
, ThreadContext
*tc
, int tgt_fd
, int how
)
1149 auto p
= tc
->getProcessPtr();
1151 auto sfdp
= std::dynamic_pointer_cast
<SocketFDEntry
>((*p
->fds
)[tgt_fd
]);
1154 int sim_fd
= sfdp
->getSimFD();
1156 int retval
= shutdown(sim_fd
, how
);
1158 return (retval
== -1) ? -errno
: retval
;
1162 bindFunc(SyscallDesc
*desc
, ThreadContext
*tc
,
1163 int tgt_fd
, Addr buf_ptr
, int addrlen
)
1165 auto p
= tc
->getProcessPtr();
1167 BufferArg
bufSock(buf_ptr
, addrlen
);
1168 bufSock
.copyIn(tc
->getVirtProxy());
1170 auto sfdp
= std::dynamic_pointer_cast
<SocketFDEntry
>((*p
->fds
)[tgt_fd
]);
1173 int sim_fd
= sfdp
->getSimFD();
1175 int status
= ::bind(sim_fd
,
1176 (struct sockaddr
*)bufSock
.bufferPtr(),
1179 return (status
== -1) ? -errno
: status
;
1183 listenFunc(SyscallDesc
*desc
, ThreadContext
*tc
, int tgt_fd
, int backlog
)
1185 auto p
= tc
->getProcessPtr();
1187 auto sfdp
= std::dynamic_pointer_cast
<SocketFDEntry
>((*p
->fds
)[tgt_fd
]);
1190 int sim_fd
= sfdp
->getSimFD();
1192 int status
= listen(sim_fd
, backlog
);
1194 return (status
== -1) ? -errno
: status
;
1198 connectFunc(SyscallDesc
*desc
, ThreadContext
*tc
,
1199 int tgt_fd
, Addr buf_ptr
, int addrlen
)
1201 auto p
= tc
->getProcessPtr();
1203 BufferArg
addr(buf_ptr
, addrlen
);
1204 addr
.copyIn(tc
->getVirtProxy());
1206 auto sfdp
= std::dynamic_pointer_cast
<SocketFDEntry
>((*p
->fds
)[tgt_fd
]);
1209 int sim_fd
= sfdp
->getSimFD();
1211 int status
= connect(sim_fd
,
1212 (struct sockaddr
*)addr
.bufferPtr(),
1213 (socklen_t
)addrlen
);
1215 return (status
== -1) ? -errno
: status
;
1219 recvfromFunc(SyscallDesc
*desc
, ThreadContext
*tc
,
1220 int tgt_fd
, Addr bufrPtr
, size_t bufrLen
, int flags
,
1221 Addr addrPtr
, Addr addrlenPtr
)
1223 auto p
= tc
->getProcessPtr();
1225 auto sfdp
= std::dynamic_pointer_cast
<SocketFDEntry
>((*p
->fds
)[tgt_fd
]);
1228 int sim_fd
= sfdp
->getSimFD();
1230 // Reserve buffer space.
1231 BufferArg
bufrBuf(bufrPtr
, bufrLen
);
1233 // Get address length.
1234 socklen_t addrLen
= 0;
1235 if (addrlenPtr
!= 0) {
1236 // Read address length parameter.
1237 BufferArg
addrlenBuf(addrlenPtr
, sizeof(socklen_t
));
1238 addrlenBuf
.copyIn(tc
->getVirtProxy());
1239 addrLen
= *((socklen_t
*)addrlenBuf
.bufferPtr());
1242 struct sockaddr sa
, *sap
= NULL
;
1244 BufferArg
addrBuf(addrPtr
, addrLen
);
1245 addrBuf
.copyIn(tc
->getVirtProxy());
1246 memcpy(&sa
, (struct sockaddr
*)addrBuf
.bufferPtr(),
1247 sizeof(struct sockaddr
));
1251 ssize_t recvd_size
= recvfrom(sim_fd
,
1252 (void *)bufrBuf
.bufferPtr(),
1253 bufrLen
, flags
, sap
, (socklen_t
*)&addrLen
);
1255 if (recvd_size
== -1)
1258 // Pass the received data out.
1259 bufrBuf
.copyOut(tc
->getVirtProxy());
1261 // Copy address to addrPtr and pass it on.
1263 BufferArg
addrBuf(addrPtr
, addrLen
);
1264 memcpy(addrBuf
.bufferPtr(), sap
, sizeof(sa
));
1265 addrBuf
.copyOut(tc
->getVirtProxy());
1268 // Copy len to addrlenPtr and pass it on.
1270 BufferArg
addrlenBuf(addrlenPtr
, sizeof(socklen_t
));
1271 *(socklen_t
*)addrlenBuf
.bufferPtr() = addrLen
;
1272 addrlenBuf
.copyOut(tc
->getVirtProxy());
1279 sendtoFunc(SyscallDesc
*desc
, ThreadContext
*tc
,
1280 int tgt_fd
, Addr bufrPtr
, size_t bufrLen
, int flags
,
1281 Addr addrPtr
, socklen_t addrLen
)
1283 auto p
= tc
->getProcessPtr();
1285 auto sfdp
= std::dynamic_pointer_cast
<SocketFDEntry
>((*p
->fds
)[tgt_fd
]);
1288 int sim_fd
= sfdp
->getSimFD();
1290 // Reserve buffer space.
1291 BufferArg
bufrBuf(bufrPtr
, bufrLen
);
1292 bufrBuf
.copyIn(tc
->getVirtProxy());
1294 struct sockaddr sa
, *sap
= nullptr;
1295 memset(&sa
, 0, sizeof(sockaddr
));
1297 BufferArg
addrBuf(addrPtr
, addrLen
);
1298 addrBuf
.copyIn(tc
->getVirtProxy());
1299 memcpy(&sa
, (sockaddr
*)addrBuf
.bufferPtr(), addrLen
);
1303 ssize_t sent_size
= sendto(sim_fd
,
1304 (void *)bufrBuf
.bufferPtr(),
1305 bufrLen
, flags
, sap
, (socklen_t
)addrLen
);
1307 return (sent_size
== -1) ? -errno
: sent_size
;
1311 recvmsgFunc(SyscallDesc
*desc
, ThreadContext
*tc
,
1312 int tgt_fd
, Addr msgPtr
, int flags
)
1314 auto p
= tc
->getProcessPtr();
1316 auto sfdp
= std::dynamic_pointer_cast
<SocketFDEntry
>((*p
->fds
)[tgt_fd
]);
1319 int sim_fd
= sfdp
->getSimFD();
1323 * void *msg_name; // optional address
1324 * socklen_t msg_namelen; // size of address
1325 * struct iovec *msg_iov; // iovec array
1326 * size_t msg_iovlen; // number entries in msg_iov
1327 * i // entries correspond to buffer
1328 * void *msg_control; // ancillary data
1329 * size_t msg_controllen; // ancillary data buffer len
1330 * int msg_flags; // flags on received message
1334 * void *iov_base; // starting address
1335 * size_t iov_len; // number of bytes to transfer
1340 * The plan with this system call is to replace all of the pointers in the
1341 * structure and the substructure with BufferArg class pointers. We will
1342 * copy every field from the structures into our BufferArg classes.
1344 BufferArg
msgBuf(msgPtr
, sizeof(struct msghdr
));
1345 msgBuf
.copyIn(tc
->getVirtProxy());
1346 struct msghdr
*msgHdr
= (struct msghdr
*)msgBuf
.bufferPtr();
1349 * We will use these address place holders to retain the pointers which
1350 * we are going to replace with our own buffers in our simulator address
1353 Addr msg_name_phold
= 0;
1354 Addr msg_iov_phold
= 0;
1355 Addr iovec_base_phold
[msgHdr
->msg_iovlen
];
1356 Addr msg_control_phold
= 0;
1359 * Record msg_name pointer then replace with buffer pointer.
1361 BufferArg
*nameBuf
= NULL
;
1362 if (msgHdr
->msg_name
) {
1363 /*1*/msg_name_phold
= (Addr
)msgHdr
->msg_name
;
1364 /*2*/nameBuf
= new BufferArg(msg_name_phold
, msgHdr
->msg_namelen
);
1365 /*3*/nameBuf
->copyIn(tc
->getVirtProxy());
1366 /*4*/msgHdr
->msg_name
= nameBuf
->bufferPtr();
1370 * Record msg_iov pointer then replace with buffer pointer. Also, setup
1371 * an array of buffer pointers for the iovec structs record and replace
1372 * their pointers with buffer pointers.
1374 BufferArg
*iovBuf
= NULL
;
1375 BufferArg
*iovecBuf
[msgHdr
->msg_iovlen
];
1376 for (int i
= 0; i
< msgHdr
->msg_iovlen
; i
++) {
1377 iovec_base_phold
[i
] = 0;
1381 if (msgHdr
->msg_iov
) {
1382 /*1*/msg_iov_phold
= (Addr
)msgHdr
->msg_iov
;
1383 /*2*/iovBuf
= new BufferArg(msg_iov_phold
, msgHdr
->msg_iovlen
*
1384 sizeof(struct iovec
));
1385 /*3*/iovBuf
->copyIn(tc
->getVirtProxy());
1386 for (int i
= 0; i
< msgHdr
->msg_iovlen
; i
++) {
1387 if (((struct iovec
*)iovBuf
->bufferPtr())[i
].iov_base
) {
1388 /*1*/iovec_base_phold
[i
] =
1389 (Addr
)((struct iovec
*)iovBuf
->bufferPtr())[i
].iov_base
;
1390 /*2*/iovecBuf
[i
] = new BufferArg(iovec_base_phold
[i
],
1391 ((struct iovec
*)iovBuf
->bufferPtr())[i
].iov_len
);
1392 /*3*/iovecBuf
[i
]->copyIn(tc
->getVirtProxy());
1393 /*4*/((struct iovec
*)iovBuf
->bufferPtr())[i
].iov_base
=
1394 iovecBuf
[i
]->bufferPtr();
1397 /*4*/msgHdr
->msg_iov
= (struct iovec
*)iovBuf
->bufferPtr();
1401 * Record msg_control pointer then replace with buffer pointer.
1403 BufferArg
*controlBuf
= NULL
;
1404 if (msgHdr
->msg_control
) {
1405 /*1*/msg_control_phold
= (Addr
)msgHdr
->msg_control
;
1406 /*2*/controlBuf
= new BufferArg(msg_control_phold
,
1407 CMSG_ALIGN(msgHdr
->msg_controllen
));
1408 /*3*/controlBuf
->copyIn(tc
->getVirtProxy());
1409 /*4*/msgHdr
->msg_control
= controlBuf
->bufferPtr();
1412 ssize_t recvd_size
= recvmsg(sim_fd
, msgHdr
, flags
);
1417 if (msgHdr
->msg_name
) {
1418 nameBuf
->copyOut(tc
->getVirtProxy());
1420 msgHdr
->msg_name
= (void *)msg_name_phold
;
1423 if (msgHdr
->msg_iov
) {
1424 for (int i
= 0; i
< msgHdr
->msg_iovlen
; i
++) {
1425 if (((struct iovec
*)iovBuf
->bufferPtr())[i
].iov_base
) {
1426 iovecBuf
[i
]->copyOut(tc
->getVirtProxy());
1428 ((struct iovec
*)iovBuf
->bufferPtr())[i
].iov_base
=
1429 (void *)iovec_base_phold
[i
];
1432 iovBuf
->copyOut(tc
->getVirtProxy());
1434 msgHdr
->msg_iov
= (struct iovec
*)msg_iov_phold
;
1437 if (msgHdr
->msg_control
) {
1438 controlBuf
->copyOut(tc
->getVirtProxy());
1440 msgHdr
->msg_control
= (void *)msg_control_phold
;
1443 msgBuf
.copyOut(tc
->getVirtProxy());
1449 sendmsgFunc(SyscallDesc
*desc
, ThreadContext
*tc
,
1450 int tgt_fd
, Addr msgPtr
, int flags
)
1452 auto p
= tc
->getProcessPtr();
1454 auto sfdp
= std::dynamic_pointer_cast
<SocketFDEntry
>((*p
->fds
)[tgt_fd
]);
1457 int sim_fd
= sfdp
->getSimFD();
1460 * Reserve buffer space.
1462 BufferArg
msgBuf(msgPtr
, sizeof(struct msghdr
));
1463 msgBuf
.copyIn(tc
->getVirtProxy());
1464 struct msghdr msgHdr
= *((struct msghdr
*)msgBuf
.bufferPtr());
1467 * Assuming msgHdr.msg_iovlen >= 1, then there is no point calling
1468 * recvmsg without a buffer.
1470 struct iovec
*iovPtr
= msgHdr
.msg_iov
;
1471 BufferArg
iovBuf((Addr
)iovPtr
, sizeof(struct iovec
) * msgHdr
.msg_iovlen
);
1472 iovBuf
.copyIn(tc
->getVirtProxy());
1473 struct iovec
*iov
= (struct iovec
*)iovBuf
.bufferPtr();
1474 msgHdr
.msg_iov
= iov
;
1477 * Cannot instantiate buffers till inside the loop.
1478 * Create array to hold buffer addresses, to be used during copyIn of
1481 BufferArg
**bufferArray
= (BufferArg
**)malloc(msgHdr
.msg_iovlen
1482 * sizeof(BufferArg
*));
1485 * Iterate through the iovec structures:
1486 * Get the base buffer addreses, reserve iov_len amount of space for each.
1487 * Put the buf address into the bufferArray for later retrieval.
1489 for (int iovIndex
= 0 ; iovIndex
< msgHdr
.msg_iovlen
; iovIndex
++) {
1490 Addr basePtr
= (Addr
) iov
[iovIndex
].iov_base
;
1491 bufferArray
[iovIndex
] = new BufferArg(basePtr
, iov
[iovIndex
].iov_len
);
1492 bufferArray
[iovIndex
]->copyIn(tc
->getVirtProxy());
1493 iov
[iovIndex
].iov_base
= bufferArray
[iovIndex
]->bufferPtr();
1496 ssize_t sent_size
= sendmsg(sim_fd
, &msgHdr
, flags
);
1497 int local_errno
= errno
;
1500 * Free dynamically allocated memory.
1502 for (int iovIndex
= 0 ; iovIndex
< msgHdr
.msg_iovlen
; iovIndex
++) {
1503 BufferArg
*baseBuf
= ( BufferArg
*)bufferArray
[iovIndex
];
1512 return (sent_size
< 0) ? -local_errno
: sent_size
;
1516 getsockoptFunc(SyscallDesc
*desc
, ThreadContext
*tc
,
1517 int tgt_fd
, int level
, int optname
, Addr valPtr
, Addr lenPtr
)
1519 // union of all possible return value types from getsockopt
1523 struct linger linger_val
;
1524 struct timeval timeval_val
;
1527 auto p
= tc
->getProcessPtr();
1529 auto sfdp
= std::dynamic_pointer_cast
<SocketFDEntry
>((*p
->fds
)[tgt_fd
]);
1532 int sim_fd
= sfdp
->getSimFD();
1534 socklen_t len
= sizeof(val
);
1535 int status
= getsockopt(sim_fd
, level
, optname
, &val
, &len
);
1540 // copy val to valPtr and pass it on
1541 BufferArg
valBuf(valPtr
, sizeof(val
));
1542 memcpy(valBuf
.bufferPtr(), &val
, sizeof(val
));
1543 valBuf
.copyOut(tc
->getVirtProxy());
1545 // copy len to lenPtr and pass it on
1546 BufferArg
lenBuf(lenPtr
, sizeof(len
));
1547 memcpy(lenBuf
.bufferPtr(), &len
, sizeof(len
));
1548 lenBuf
.copyOut(tc
->getVirtProxy());
1554 getsocknameFunc(SyscallDesc
*desc
, ThreadContext
*tc
,
1555 int tgt_fd
, Addr addrPtr
, Addr lenPtr
)
1557 auto p
= tc
->getProcessPtr();
1559 auto sfdp
= std::dynamic_pointer_cast
<SocketFDEntry
>((*p
->fds
)[tgt_fd
]);
1562 int sim_fd
= sfdp
->getSimFD();
1564 // lenPtr is an in-out paramenter:
1565 // sending the address length in, conveying the final length out
1567 // Read in the value of len from the passed pointer.
1568 BufferArg
lenBuf(lenPtr
, sizeof(socklen_t
));
1569 lenBuf
.copyIn(tc
->getVirtProxy());
1570 socklen_t len
= *(socklen_t
*)lenBuf
.bufferPtr();
1573 int status
= getsockname(sim_fd
, &sa
, &len
);
1578 // Copy address to addrPtr and pass it on.
1579 BufferArg
addrBuf(addrPtr
, sizeof(sa
));
1580 memcpy(addrBuf
.bufferPtr(), &sa
, sizeof(sa
));
1581 addrBuf
.copyOut(tc
->getVirtProxy());
1583 // Copy len to lenPtr and pass it on.
1584 *(socklen_t
*)lenBuf
.bufferPtr() = len
;
1585 lenBuf
.copyOut(tc
->getVirtProxy());
1591 getpeernameFunc(SyscallDesc
*desc
, ThreadContext
*tc
,
1592 int tgt_fd
, Addr sockAddrPtr
, Addr addrlenPtr
)
1594 auto p
= tc
->getProcessPtr();
1596 auto sfdp
= std::dynamic_pointer_cast
<SocketFDEntry
>((*p
->fds
)[tgt_fd
]);
1599 int sim_fd
= sfdp
->getSimFD();
1601 BufferArg
bufAddrlen(addrlenPtr
, sizeof(unsigned));
1602 bufAddrlen
.copyIn(tc
->getVirtProxy());
1603 BufferArg
bufSock(sockAddrPtr
, *(unsigned *)bufAddrlen
.bufferPtr());
1605 int retval
= getpeername(sim_fd
,
1606 (struct sockaddr
*)bufSock
.bufferPtr(),
1607 (unsigned *)bufAddrlen
.bufferPtr());
1610 bufSock
.copyOut(tc
->getVirtProxy());
1611 bufAddrlen
.copyOut(tc
->getVirtProxy());
1614 return (retval
== -1) ? -errno
: retval
;
1618 setsockoptFunc(SyscallDesc
*desc
, ThreadContext
*tc
,
1619 int tgt_fd
, int level
, int optname
, Addr valPtr
, socklen_t len
)
1621 auto p
= tc
->getProcessPtr();
1623 BufferArg
valBuf(valPtr
, len
);
1624 valBuf
.copyIn(tc
->getVirtProxy());
1626 auto sfdp
= std::dynamic_pointer_cast
<SocketFDEntry
>((*p
->fds
)[tgt_fd
]);
1629 int sim_fd
= sfdp
->getSimFD();
1631 int status
= setsockopt(sim_fd
, level
, optname
,
1632 (struct sockaddr
*)valBuf
.bufferPtr(), len
);
1634 return (status
== -1) ? -errno
: status
;
1638 getcpuFunc(SyscallDesc
*desc
, ThreadContext
*tc
,
1639 Addr cpu_ptr
, Addr node_ptr
, Addr tcache_ptr
)
1643 // unsigned is the same size (4) on all Linux supported ISAs.
1645 TypedBufferArg
<uint32_t> result(cpu_ptr
);
1646 *result
= htog(tc
->contextId(),
1647 tc
->getSystemPtr()->getGuestByteOrder());
1648 error
|= !result
.copyOut(tc
->getVirtProxy());
1651 // Set a fixed NUMA node 0.
1652 if (node_ptr
!= 0) {
1653 TypedBufferArg
<uint32_t> result(node_ptr
);
1655 error
|= !result
.copyOut(tc
->getVirtProxy());
1658 return error
? -EFAULT
: 0;