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.
28 * Authors: Steve Reinhardt
32 #include "sim/syscall_emul.hh"
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 "mem/page_table.hh"
47 #include "sim/process.hh"
48 #include "sim/sim_exit.hh"
49 #include "sim/syscall_debug_macros.hh"
50 #include "sim/syscall_desc.hh"
51 #include "sim/system.hh"
54 using namespace TheISA
;
57 unimplementedFunc(SyscallDesc
*desc
, int callnum
, Process
*process
,
60 fatal("syscall %s (#%d) unimplemented.", desc
->name(), callnum
);
67 ignoreFunc(SyscallDesc
*desc
, int callnum
, Process
*process
,
70 if (desc
->needWarning()) {
71 warn("ignoring syscall %s(...)%s", desc
->name(), desc
->warnOnce() ?
72 "\n (further warnings will be suppressed)" : "");
79 exitFutexWake(ThreadContext
*tc
, Addr addr
, uint64_t tgid
)
81 // Clear value at address pointed to by thread's childClearTID field.
82 BufferArg
ctidBuf(addr
, sizeof(long));
83 long *ctid
= (long *)ctidBuf
.bufferPtr();
85 ctidBuf
.copyOut(tc
->getMemProxy());
87 FutexMap
&futex_map
= tc
->getSystemPtr()->futexMap
;
88 // Wake one of the waiting threads.
89 futex_map
.wakeup(addr
, tgid
, 1);
93 exitImpl(SyscallDesc
*desc
, int callnum
, Process
*p
, ThreadContext
*tc
,
97 int status
= p
->getSyscallArg(tc
, index
);
99 System
*sys
= tc
->getSystemPtr();
101 int activeContexts
= 0;
102 for (auto &system
: sys
->systemList
)
103 activeContexts
+= system
->numRunningContexts();
104 if (activeContexts
== 1) {
105 exitSimLoop("exiting with last active thread context", status
& 0xff);
110 *p
->exitGroup
= true;
112 if (p
->childClearTID
)
113 exitFutexWake(tc
, p
->childClearTID
, p
->tgid());
115 bool last_thread
= true;
116 Process
*parent
= nullptr, *tg_lead
= nullptr;
117 for (int i
= 0; last_thread
&& i
< sys
->numContexts(); i
++) {
119 if (!(walk
= sys
->threadContexts
[i
]->getProcessPtr()))
123 * Threads in a thread group require special handing. For instance,
124 * we send the SIGCHLD signal so that it appears that it came from
125 * the head of the group. We also only delete file descriptors if
126 * we are the last thread in the thread group.
128 if (walk
->pid() == p
->tgid())
131 if ((sys
->threadContexts
[i
]->status() != ThreadContext::Halted
)
134 * Check if we share thread group with the pointer; this denotes
135 * that we are not the last thread active in the thread group.
136 * Note that setting this to false also prevents further
137 * iterations of the loop.
139 if (walk
->tgid() == p
->tgid())
143 * A corner case exists which involves execve(). After execve(),
144 * the execve will enable SIGCHLD in the process. The problem
145 * occurs when the exiting process is the root process in the
146 * system; there is no parent to receive the signal. We obviate
147 * this problem by setting the root process' ppid to zero in the
148 * Python configuration files. We really should handle the
149 * root/execve specific case more gracefully.
151 if (*p
->sigchld
&& (p
->ppid() != 0) && (walk
->pid() == p
->ppid()))
159 sys
->signalList
.push_back(BasicSignal(tg_lead
, parent
, SIGCHLD
));
163 * Run though FD array of the exiting process and close all file
164 * descriptors except for the standard file descriptors.
165 * (The standard file descriptors are shared with gem5.)
167 for (int i
= 0; i
< p
->fds
->getSize(); i
++) {
169 p
->fds
->closeFDEntry(i
);
178 exitFunc(SyscallDesc
*desc
, int callnum
, Process
*p
, ThreadContext
*tc
)
180 return exitImpl(desc
, callnum
, p
, tc
, false);
184 exitGroupFunc(SyscallDesc
*desc
, int callnum
, Process
*p
, ThreadContext
*tc
)
186 return exitImpl(desc
, callnum
, p
, tc
, true);
190 getpagesizeFunc(SyscallDesc
*desc
, int num
, Process
*p
, ThreadContext
*tc
)
192 return (int)PageBytes
;
197 brkFunc(SyscallDesc
*desc
, int num
, Process
*p
, ThreadContext
*tc
)
199 // change brk addr to first arg
201 Addr new_brk
= p
->getSyscallArg(tc
, index
);
203 std::shared_ptr
<MemState
> mem_state
= p
->memState
;
204 Addr brk_point
= mem_state
->getBrkPoint();
206 // in Linux at least, brk(0) returns the current break value
207 // (note that the syscall and the glibc function have different behavior)
211 if (new_brk
> brk_point
) {
212 // might need to allocate some new pages
213 for (ChunkGenerator
gen(brk_point
,
215 PageBytes
); !gen
.done(); gen
.next()) {
216 if (!p
->pTable
->translate(gen
.addr()))
217 p
->allocateMem(roundDown(gen
.addr(), PageBytes
), PageBytes
);
219 // if the address is already there, zero it out
222 SETranslatingPortProxy
&tp
= tc
->getMemProxy();
224 // split non-page aligned accesses
225 Addr next_page
= roundUp(gen
.addr(), PageBytes
);
226 uint32_t size_needed
= next_page
- gen
.addr();
227 tp
.memsetBlob(gen
.addr(), zero
, size_needed
);
228 if (gen
.addr() + PageBytes
> next_page
&&
229 next_page
< new_brk
&&
230 p
->pTable
->translate(next_page
)) {
231 size_needed
= PageBytes
- size_needed
;
232 tp
.memsetBlob(next_page
, zero
, size_needed
);
238 mem_state
->setBrkPoint(new_brk
);
239 DPRINTF_SYSCALL(Verbose
, "brk: break point changed to: %#X\n",
240 mem_state
->getBrkPoint());
241 return mem_state
->getBrkPoint();
245 setTidAddressFunc(SyscallDesc
*desc
, int callnum
, Process
*process
,
249 uint64_t tidPtr
= process
->getSyscallArg(tc
, index
);
251 process
->childClearTID
= tidPtr
;
252 return process
->pid();
256 closeFunc(SyscallDesc
*desc
, int num
, Process
*p
, ThreadContext
*tc
)
259 int tgt_fd
= p
->getSyscallArg(tc
, index
);
261 return p
->fds
->closeFDEntry(tgt_fd
);
266 readFunc(SyscallDesc
*desc
, int num
, Process
*p
, ThreadContext
*tc
)
269 int tgt_fd
= p
->getSyscallArg(tc
, index
);
270 Addr buf_ptr
= p
->getSyscallArg(tc
, index
);
271 int nbytes
= p
->getSyscallArg(tc
, index
);
273 auto hbfdp
= std::dynamic_pointer_cast
<HBFDEntry
>((*p
->fds
)[tgt_fd
]);
276 int sim_fd
= hbfdp
->getSimFD();
278 BufferArg
bufArg(buf_ptr
, nbytes
);
279 int bytes_read
= read(sim_fd
, bufArg
.bufferPtr(), nbytes
);
282 bufArg
.copyOut(tc
->getMemProxy());
288 writeFunc(SyscallDesc
*desc
, int num
, Process
*p
, ThreadContext
*tc
)
291 int tgt_fd
= p
->getSyscallArg(tc
, index
);
292 Addr buf_ptr
= p
->getSyscallArg(tc
, index
);
293 int nbytes
= p
->getSyscallArg(tc
, index
);
295 auto hbfdp
= std::dynamic_pointer_cast
<HBFDEntry
>((*p
->fds
)[tgt_fd
]);
298 int sim_fd
= hbfdp
->getSimFD();
300 BufferArg
bufArg(buf_ptr
, nbytes
);
301 bufArg
.copyIn(tc
->getMemProxy());
303 int bytes_written
= write(sim_fd
, bufArg
.bufferPtr(), nbytes
);
307 return bytes_written
;
312 lseekFunc(SyscallDesc
*desc
, int num
, Process
*p
, ThreadContext
*tc
)
315 int tgt_fd
= p
->getSyscallArg(tc
, index
);
316 uint64_t offs
= p
->getSyscallArg(tc
, index
);
317 int whence
= p
->getSyscallArg(tc
, index
);
319 auto ffdp
= std::dynamic_pointer_cast
<FileFDEntry
>((*p
->fds
)[tgt_fd
]);
322 int sim_fd
= ffdp
->getSimFD();
324 off_t result
= lseek(sim_fd
, offs
, whence
);
326 return (result
== (off_t
)-1) ? -errno
: result
;
331 _llseekFunc(SyscallDesc
*desc
, int num
, Process
*p
, ThreadContext
*tc
)
334 int tgt_fd
= p
->getSyscallArg(tc
, index
);
335 uint64_t offset_high
= p
->getSyscallArg(tc
, index
);
336 uint32_t offset_low
= p
->getSyscallArg(tc
, index
);
337 Addr result_ptr
= p
->getSyscallArg(tc
, index
);
338 int whence
= p
->getSyscallArg(tc
, index
);
340 auto ffdp
= std::dynamic_pointer_cast
<FileFDEntry
>((*p
->fds
)[tgt_fd
]);
343 int sim_fd
= ffdp
->getSimFD();
345 uint64_t offset
= (offset_high
<< 32) | offset_low
;
347 uint64_t result
= lseek(sim_fd
, offset
, whence
);
348 result
= TheISA::htog(result
);
350 if (result
== (off_t
)-1)
352 // Assuming that the size of loff_t is 64 bits on the target platform
353 BufferArg
result_buf(result_ptr
, sizeof(result
));
354 memcpy(result_buf
.bufferPtr(), &result
, sizeof(result
));
355 result_buf
.copyOut(tc
->getMemProxy());
361 munmapFunc(SyscallDesc
*desc
, int num
, Process
*p
, ThreadContext
*tc
)
363 // With mmap more fully implemented, it might be worthwhile to bite
364 // the bullet and implement munmap. Should allow us to reuse simulated
370 const char *hostname
= "m5.eecs.umich.edu";
373 gethostnameFunc(SyscallDesc
*desc
, int num
, Process
*p
, ThreadContext
*tc
)
376 Addr buf_ptr
= p
->getSyscallArg(tc
, index
);
377 int name_len
= p
->getSyscallArg(tc
, index
);
378 BufferArg
name(buf_ptr
, name_len
);
380 strncpy((char *)name
.bufferPtr(), hostname
, name_len
);
382 name
.copyOut(tc
->getMemProxy());
388 getcwdFunc(SyscallDesc
*desc
, int num
, Process
*p
, ThreadContext
*tc
)
392 Addr buf_ptr
= p
->getSyscallArg(tc
, index
);
393 unsigned long size
= p
->getSyscallArg(tc
, index
);
394 BufferArg
buf(buf_ptr
, size
);
396 // Is current working directory defined?
397 string cwd
= p
->getcwd();
399 if (cwd
.length() >= size
) {
403 strncpy((char *)buf
.bufferPtr(), cwd
.c_str(), size
);
404 result
= cwd
.length();
406 if (getcwd((char *)buf
.bufferPtr(), size
)) {
407 result
= strlen((char *)buf
.bufferPtr());
413 buf
.copyOut(tc
->getMemProxy());
415 return (result
== -1) ? -errno
: result
;
419 readlinkFunc(SyscallDesc
*desc
, int callnum
, Process
*process
,
422 return readlinkFunc(desc
, callnum
, process
, tc
, 0);
426 readlinkFunc(SyscallDesc
*desc
, int num
, Process
*p
, ThreadContext
*tc
,
431 if (!tc
->getMemProxy().tryReadString(path
, p
->getSyscallArg(tc
, index
)))
434 // Adjust path for current working directory
435 path
= p
->fullPath(path
);
437 Addr buf_ptr
= p
->getSyscallArg(tc
, index
);
438 size_t bufsiz
= p
->getSyscallArg(tc
, index
);
440 BufferArg
buf(buf_ptr
, bufsiz
);
443 if (path
!= "/proc/self/exe") {
444 result
= readlink(path
.c_str(), (char *)buf
.bufferPtr(), bufsiz
);
446 // Emulate readlink() called on '/proc/self/exe' should return the
447 // absolute path of the binary running in the simulated system (the
448 // Process' executable). It is possible that using this path in
449 // the simulated system will result in unexpected behavior if:
450 // 1) One binary runs another (e.g., -c time -o "my_binary"), and
451 // called binary calls readlink().
452 // 2) The host's full path to the running benchmark changes from one
453 // simulation to another. This can result in different simulated
454 // performance since the simulated system will process the binary
455 // path differently, even if the binary itself does not change.
457 // Get the absolute canonical path to the running application
458 char real_path
[PATH_MAX
];
459 char *check_real_path
= realpath(p
->progName(), real_path
);
460 if (!check_real_path
) {
461 fatal("readlink('/proc/self/exe') unable to resolve path to "
462 "executable: %s", p
->progName());
464 strncpy((char*)buf
.bufferPtr(), real_path
, bufsiz
);
465 size_t real_path_len
= strlen(real_path
);
466 if (real_path_len
> bufsiz
) {
467 // readlink will truncate the contents of the
468 // path to ensure it is no more than bufsiz
471 result
= real_path_len
;
474 // Issue a warning about potential unexpected results
475 warn_once("readlink() called on '/proc/self/exe' may yield unexpected "
476 "results in various settings.\n Returning '%s'\n",
477 (char*)buf
.bufferPtr());
480 buf
.copyOut(tc
->getMemProxy());
482 return (result
== -1) ? -errno
: result
;
486 unlinkFunc(SyscallDesc
*desc
, int num
, Process
*p
, ThreadContext
*tc
)
488 return unlinkHelper(desc
, num
, p
, tc
, 0);
492 unlinkHelper(SyscallDesc
*desc
, int num
, Process
*p
, ThreadContext
*tc
,
497 if (!tc
->getMemProxy().tryReadString(path
, p
->getSyscallArg(tc
, index
)))
500 // Adjust path for current working directory
501 path
= p
->fullPath(path
);
503 int result
= unlink(path
.c_str());
504 return (result
== -1) ? -errno
: result
;
509 mkdirFunc(SyscallDesc
*desc
, int num
, Process
*p
, ThreadContext
*tc
)
514 if (!tc
->getMemProxy().tryReadString(path
, p
->getSyscallArg(tc
, index
)))
517 // Adjust path for current working directory
518 path
= p
->fullPath(path
);
520 mode_t mode
= p
->getSyscallArg(tc
, index
);
522 int result
= mkdir(path
.c_str(), mode
);
523 return (result
== -1) ? -errno
: result
;
527 renameFunc(SyscallDesc
*desc
, int num
, Process
*p
, ThreadContext
*tc
)
532 if (!tc
->getMemProxy().tryReadString(old_name
, p
->getSyscallArg(tc
, index
)))
537 if (!tc
->getMemProxy().tryReadString(new_name
, p
->getSyscallArg(tc
, index
)))
540 // Adjust path for current working directory
541 old_name
= p
->fullPath(old_name
);
542 new_name
= p
->fullPath(new_name
);
544 int64_t result
= rename(old_name
.c_str(), new_name
.c_str());
545 return (result
== -1) ? -errno
: result
;
549 truncateFunc(SyscallDesc
*desc
, int num
, Process
*p
, ThreadContext
*tc
)
554 if (!tc
->getMemProxy().tryReadString(path
, p
->getSyscallArg(tc
, index
)))
557 off_t length
= p
->getSyscallArg(tc
, index
);
559 // Adjust path for current working directory
560 path
= p
->fullPath(path
);
562 int result
= truncate(path
.c_str(), length
);
563 return (result
== -1) ? -errno
: result
;
567 ftruncateFunc(SyscallDesc
*desc
, int num
, Process
*p
, ThreadContext
*tc
)
570 int tgt_fd
= p
->getSyscallArg(tc
, index
);
571 off_t length
= p
->getSyscallArg(tc
, index
);
573 auto ffdp
= std::dynamic_pointer_cast
<FileFDEntry
>((*p
->fds
)[tgt_fd
]);
576 int sim_fd
= ffdp
->getSimFD();
578 int result
= ftruncate(sim_fd
, length
);
579 return (result
== -1) ? -errno
: result
;
583 truncate64Func(SyscallDesc
*desc
, int num
,
584 Process
*process
, ThreadContext
*tc
)
589 if (!tc
->getMemProxy().tryReadString(path
, process
->getSyscallArg(tc
, index
)))
592 int64_t length
= process
->getSyscallArg(tc
, index
, 64);
594 // Adjust path for current working directory
595 path
= process
->fullPath(path
);
598 int result
= truncate(path
.c_str(), length
);
600 int result
= truncate64(path
.c_str(), length
);
602 return (result
== -1) ? -errno
: result
;
606 ftruncate64Func(SyscallDesc
*desc
, int num
, Process
*p
, ThreadContext
*tc
)
609 int tgt_fd
= p
->getSyscallArg(tc
, index
);
610 int64_t length
= p
->getSyscallArg(tc
, index
, 64);
612 auto ffdp
= std::dynamic_pointer_cast
<FileFDEntry
>((*p
->fds
)[tgt_fd
]);
615 int sim_fd
= ffdp
->getSimFD();
618 int result
= ftruncate(sim_fd
, length
);
620 int result
= ftruncate64(sim_fd
, length
);
622 return (result
== -1) ? -errno
: result
;
626 umaskFunc(SyscallDesc
*desc
, int num
, Process
*process
, ThreadContext
*tc
)
628 // Letting the simulated program change the simulator's umask seems like
629 // a bad idea. Compromise by just returning the current umask but not
630 // changing anything.
631 mode_t oldMask
= umask(0);
637 chownFunc(SyscallDesc
*desc
, int num
, Process
*p
, ThreadContext
*tc
)
642 if (!tc
->getMemProxy().tryReadString(path
, p
->getSyscallArg(tc
, index
)))
646 uint32_t owner
= p
->getSyscallArg(tc
, index
);
647 uid_t hostOwner
= owner
;
648 uint32_t group
= p
->getSyscallArg(tc
, index
);
649 gid_t hostGroup
= group
;
651 // Adjust path for current working directory
652 path
= p
->fullPath(path
);
654 int result
= chown(path
.c_str(), hostOwner
, hostGroup
);
655 return (result
== -1) ? -errno
: result
;
659 fchownFunc(SyscallDesc
*desc
, int num
, Process
*p
, ThreadContext
*tc
)
662 int tgt_fd
= p
->getSyscallArg(tc
, index
);
664 auto ffdp
= std::dynamic_pointer_cast
<FileFDEntry
>((*p
->fds
)[tgt_fd
]);
667 int sim_fd
= ffdp
->getSimFD();
670 uint32_t owner
= p
->getSyscallArg(tc
, index
);
671 uid_t hostOwner
= owner
;
672 uint32_t group
= p
->getSyscallArg(tc
, index
);
673 gid_t hostGroup
= group
;
675 int result
= fchown(sim_fd
, hostOwner
, hostGroup
);
676 return (result
== -1) ? -errno
: result
;
680 * FIXME: The file description is not shared among file descriptors created
681 * with dup. Really, it's difficult to maintain fields like file offset or
682 * flags since an update to such a field won't be reflected in the metadata
683 * for the fd entries that we maintain for checkpoint restoration.
686 dupFunc(SyscallDesc
*desc
, int num
, Process
*p
, ThreadContext
*tc
)
689 int tgt_fd
= p
->getSyscallArg(tc
, index
);
691 auto old_hbfdp
= std::dynamic_pointer_cast
<HBFDEntry
>((*p
->fds
)[tgt_fd
]);
694 int sim_fd
= old_hbfdp
->getSimFD();
696 int result
= dup(sim_fd
);
700 auto new_hbfdp
= std::dynamic_pointer_cast
<HBFDEntry
>(old_hbfdp
->clone());
701 new_hbfdp
->setSimFD(result
);
702 new_hbfdp
->setCOE(false);
703 return p
->fds
->allocFD(new_hbfdp
);
707 dup2Func(SyscallDesc
*desc
, int num
, Process
*p
, ThreadContext
*tc
)
711 int old_tgt_fd
= p
->getSyscallArg(tc
, index
);
712 auto old_hbp
= std::dynamic_pointer_cast
<HBFDEntry
>((*p
->fds
)[old_tgt_fd
]);
715 int old_sim_fd
= old_hbp
->getSimFD();
718 * We need a valid host file descriptor number to be able to pass into
719 * the second parameter for dup2 (newfd), but we don't know what the
720 * viable numbers are; we execute the open call to retrieve one.
722 int res_fd
= dup2(old_sim_fd
, open("/dev/null", O_RDONLY
));
726 int new_tgt_fd
= p
->getSyscallArg(tc
, index
);
727 auto new_hbp
= std::dynamic_pointer_cast
<HBFDEntry
>((*p
->fds
)[new_tgt_fd
]);
729 p
->fds
->closeFDEntry(new_tgt_fd
);
730 new_hbp
= std::dynamic_pointer_cast
<HBFDEntry
>(old_hbp
->clone());
731 new_hbp
->setSimFD(res_fd
);
732 new_hbp
->setCOE(false);
734 return p
->fds
->allocFD(new_hbp
);
738 fcntlFunc(SyscallDesc
*desc
, int num
, Process
*p
, ThreadContext
*tc
)
742 int tgt_fd
= p
->getSyscallArg(tc
, index
);
743 int cmd
= p
->getSyscallArg(tc
, index
);
745 auto hbfdp
= std::dynamic_pointer_cast
<HBFDEntry
>((*p
->fds
)[tgt_fd
]);
748 int sim_fd
= hbfdp
->getSimFD();
750 int coe
= hbfdp
->getCOE();
754 return coe
& FD_CLOEXEC
;
757 arg
= p
->getSyscallArg(tc
, index
);
758 arg
? hbfdp
->setCOE(true) : hbfdp
->setCOE(false);
762 // Rely on the host to maintain the file status flags for this file
763 // description rather than maintain it ourselves. Admittedly, this
764 // is suboptimal (and possibly error prone), but it is difficult to
765 // maintain the flags by tracking them across the different descriptors
766 // (that refer to this file description) caused by clone, dup, and
767 // subsequent fcntls.
770 arg
= p
->getSyscallArg(tc
, index
);
771 int rv
= fcntl(sim_fd
, cmd
, arg
);
772 return (rv
== -1) ? -errno
: rv
;
776 warn("fcntl: unsupported command %d\n", cmd
);
782 fcntl64Func(SyscallDesc
*desc
, int num
, Process
*p
, ThreadContext
*tc
)
785 int tgt_fd
= p
->getSyscallArg(tc
, index
);
787 auto hbfdp
= std::dynamic_pointer_cast
<HBFDEntry
>((*p
->fds
)[tgt_fd
]);
790 int sim_fd
= hbfdp
->getSimFD();
792 int cmd
= p
->getSyscallArg(tc
, index
);
795 warn("fcntl64(%d, F_GETLK64) not supported, error returned\n", tgt_fd
);
798 case 34: // F_SETLK64
799 case 35: // F_SETLKW64
800 warn("fcntl64(%d, F_SETLK(W)64) not supported, error returned\n",
805 // not sure if this is totally valid, but we'll pass it through
806 // to the underlying OS
807 warn("fcntl64(%d, %d) passed through to host\n", tgt_fd
, cmd
);
808 return fcntl(sim_fd
, cmd
);
813 pipeImpl(SyscallDesc
*desc
, int callnum
, Process
*p
, ThreadContext
*tc
,
819 tgt_addr
= p
->getSyscallArg(tc
, index
);
822 int sim_fds
[2], tgt_fds
[2];
824 int pipe_retval
= pipe(sim_fds
);
825 if (pipe_retval
== -1)
828 auto rend
= PipeFDEntry::EndType::read
;
829 auto rpfd
= std::make_shared
<PipeFDEntry
>(sim_fds
[0], O_WRONLY
, rend
);
830 tgt_fds
[0] = p
->fds
->allocFD(rpfd
);
832 auto wend
= PipeFDEntry::EndType::write
;
833 auto wpfd
= std::make_shared
<PipeFDEntry
>(sim_fds
[1], O_RDONLY
, wend
);
834 tgt_fds
[1] = p
->fds
->allocFD(wpfd
);
837 * Now patch the read object to record the target file descriptor chosen
838 * as the write end of the pipe.
840 rpfd
->setPipeReadSource(tgt_fds
[1]);
843 * Alpha Linux convention for pipe() is that fd[0] is returned as
844 * the return value of the function, and fd[1] is returned in r20.
847 tc
->setIntReg(SyscallPseudoReturnReg
, tgt_fds
[1]);
852 * Copy the target file descriptors into buffer space and then copy
853 * the buffer space back into the target address space.
855 BufferArg
tgt_handle(tgt_addr
, sizeof(int[2]));
856 int *buf_ptr
= (int*)tgt_handle
.bufferPtr();
857 buf_ptr
[0] = tgt_fds
[0];
858 buf_ptr
[1] = tgt_fds
[1];
859 tgt_handle
.copyOut(tc
->getMemProxy());
864 pipePseudoFunc(SyscallDesc
*desc
, int callnum
, Process
*process
,
867 return pipeImpl(desc
, callnum
, process
, tc
, true);
871 pipeFunc(SyscallDesc
*desc
, int callnum
, Process
*process
, ThreadContext
*tc
)
873 return pipeImpl(desc
, callnum
, process
, tc
, false);
877 setpgidFunc(SyscallDesc
*desc
, int callnum
, Process
*process
,
881 int pid
= process
->getSyscallArg(tc
, index
);
882 int pgid
= process
->getSyscallArg(tc
, index
);
888 process
->setpgid(process
->pid());
892 Process
*matched_ph
= nullptr;
893 System
*sysh
= tc
->getSystemPtr();
895 // Retrieves process pointer from active/suspended thread contexts.
896 for (int i
= 0; i
< sysh
->numContexts(); i
++) {
897 if (sysh
->threadContexts
[i
]->status() != ThreadContext::Halted
) {
898 Process
*temp_h
= sysh
->threadContexts
[i
]->getProcessPtr();
899 Process
*walk_ph
= (Process
*)temp_h
;
901 if (walk_ph
&& walk_ph
->pid() == process
->pid())
902 matched_ph
= walk_ph
;
907 matched_ph
->setpgid((pgid
== 0) ? matched_ph
->pid() : pgid
);
913 getpidPseudoFunc(SyscallDesc
*desc
, int callnum
, Process
*process
,
916 // Make up a PID. There's no interprocess communication in
917 // fake_syscall mode, so there's no way for a process to know it's
918 // not getting a unique value.
920 tc
->setIntReg(SyscallPseudoReturnReg
, process
->ppid());
921 return process
->pid();
926 getuidPseudoFunc(SyscallDesc
*desc
, int callnum
, Process
*process
,
929 // Make up a UID and EUID... it shouldn't matter, and we want the
930 // simulation to be deterministic.
933 tc
->setIntReg(SyscallPseudoReturnReg
, process
->euid()); // EUID
934 return process
->uid(); // UID
939 getgidPseudoFunc(SyscallDesc
*desc
, int callnum
, Process
*process
,
942 // Get current group ID. EGID goes in r20.
943 tc
->setIntReg(SyscallPseudoReturnReg
, process
->egid()); // EGID
944 return process
->gid();
949 setuidFunc(SyscallDesc
*desc
, int callnum
, Process
*process
,
952 // can't fathom why a benchmark would call this.
954 warn("Ignoring call to setuid(%d)\n", process
->getSyscallArg(tc
, index
));
959 getpidFunc(SyscallDesc
*desc
, int callnum
, Process
*process
,
962 return process
->tgid();
966 gettidFunc(SyscallDesc
*desc
, int callnum
, Process
*process
,
969 return process
->pid();
973 getppidFunc(SyscallDesc
*desc
, int callnum
, Process
*process
,
976 return process
->ppid();
980 getuidFunc(SyscallDesc
*desc
, int callnum
, Process
*process
,
983 return process
->uid(); // UID
987 geteuidFunc(SyscallDesc
*desc
, int callnum
, Process
*process
,
990 return process
->euid(); // UID
994 getgidFunc(SyscallDesc
*desc
, int callnum
, Process
*process
,
997 return process
->gid();
1001 getegidFunc(SyscallDesc
*desc
, int callnum
, Process
*process
,
1004 return process
->egid();
1008 fallocateFunc(SyscallDesc
*desc
, int callnum
, Process
*p
, ThreadContext
*tc
)
1011 warn("Host OS cannot support calls to fallocate. Ignoring syscall");
1014 int tgt_fd
= p
->getSyscallArg(tc
, index
);
1015 int mode
= p
->getSyscallArg(tc
, index
);
1016 off_t offset
= p
->getSyscallArg(tc
, index
);
1017 off_t len
= p
->getSyscallArg(tc
, index
);
1019 auto ffdp
= std::dynamic_pointer_cast
<FileFDEntry
>((*p
->fds
)[tgt_fd
]);
1022 int sim_fd
= ffdp
->getSimFD();
1024 int result
= fallocate(sim_fd
, mode
, offset
, len
);
1032 accessFunc(SyscallDesc
*desc
, int callnum
, Process
*p
, ThreadContext
*tc
,
1036 if (!tc
->getMemProxy().tryReadString(path
, p
->getSyscallArg(tc
, index
)))
1039 // Adjust path for current working directory
1040 path
= p
->fullPath(path
);
1042 mode_t mode
= p
->getSyscallArg(tc
, index
);
1044 int result
= access(path
.c_str(), mode
);
1045 return (result
== -1) ? -errno
: result
;
1049 accessFunc(SyscallDesc
*desc
, int callnum
, Process
*p
, ThreadContext
*tc
)
1051 return accessFunc(desc
, callnum
, p
, tc
, 0);