summaryrefslogtreecommitdiff
path: root/src/sim/syscall_emul.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/sim/syscall_emul.cc')
-rw-r--r--src/sim/syscall_emul.cc487
1 files changed, 487 insertions, 0 deletions
diff --git a/src/sim/syscall_emul.cc b/src/sim/syscall_emul.cc
new file mode 100644
index 000000000..848b6f869
--- /dev/null
+++ b/src/sim/syscall_emul.cc
@@ -0,0 +1,487 @@
+/*
+ * Copyright (c) 2003-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: Steve Reinhardt
+ * Ali Saidi
+ * Korey Sewell
+ */
+
+#include <fcntl.h>
+#include <unistd.h>
+
+#include <string>
+#include <iostream>
+
+#include "sim/syscall_emul.hh"
+#include "base/chunk_generator.hh"
+#include "base/trace.hh"
+#include "cpu/thread_context.hh"
+#include "cpu/base.hh"
+#include "mem/page_table.hh"
+#include "sim/process.hh"
+
+#include "sim/sim_exit.hh"
+
+using namespace std;
+using namespace TheISA;
+
+void
+SyscallDesc::doSyscall(int callnum, Process *process, ThreadContext *tc)
+{
+ DPRINTFR(SyscallVerbose, "%d: %s: syscall %s called w/arguments %d,%d,%d,%d\n",
+ curTick,tc->getCpuPtr()->name(), name,
+ tc->getSyscallArg(0),tc->getSyscallArg(1),
+ tc->getSyscallArg(2),tc->getSyscallArg(3));
+
+ SyscallReturn retval = (*funcPtr)(this, callnum, process, tc);
+
+ DPRINTFR(SyscallVerbose, "%d: %s: syscall %s returns %d\n",
+ curTick,tc->getCpuPtr()->name(), name, retval.value());
+
+ if (!(flags & SyscallDesc::SuppressReturnValue))
+ tc->setSyscallReturn(retval);
+}
+
+
+SyscallReturn
+unimplementedFunc(SyscallDesc *desc, int callnum, Process *process,
+ ThreadContext *tc)
+{
+ fatal("syscall %s (#%d) unimplemented.", desc->name, callnum);
+
+ return 1;
+}
+
+
+SyscallReturn
+ignoreFunc(SyscallDesc *desc, int callnum, Process *process,
+ ThreadContext *tc)
+{
+ warn("ignoring syscall %s(%d, %d, ...)", desc->name,
+ tc->getSyscallArg(0), tc->getSyscallArg(1));
+
+ return 0;
+}
+
+
+SyscallReturn
+exitFunc(SyscallDesc *desc, int callnum, Process *process,
+ ThreadContext *tc)
+{
+ exitSimLoop("target called exit()", tc->getSyscallArg(0) & 0xff);
+
+ return 1;
+}
+
+
+SyscallReturn
+getpagesizeFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
+{
+ return (int)VMPageSize;
+}
+
+
+SyscallReturn
+obreakFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
+{
+ Addr junk;
+
+ // change brk addr to first arg
+ Addr new_brk = tc->getSyscallArg(0);
+ if (new_brk != 0) {
+ for (ChunkGenerator gen(p->brk_point, new_brk - p->brk_point,
+ VMPageSize); !gen.done(); gen.next()) {
+ if (!p->pTable->translate(gen.addr(), junk))
+ p->pTable->allocate(roundDown(gen.addr(), VMPageSize),
+ VMPageSize);
+ }
+ p->brk_point = new_brk;
+ }
+ DPRINTF(SyscallVerbose, "Break Point changed to: %#X\n", p->brk_point);
+ return p->brk_point;
+}
+
+
+SyscallReturn
+closeFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
+{
+ int target_fd = tc->getSyscallArg(0);
+ int status = close(p->sim_fd(target_fd));
+ if (status >= 0)
+ p->free_fd(target_fd);
+ return status;
+}
+
+
+SyscallReturn
+readFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
+{
+ int fd = p->sim_fd(tc->getSyscallArg(0));
+ int nbytes = tc->getSyscallArg(2);
+ BufferArg bufArg(tc->getSyscallArg(1), nbytes);
+
+ int bytes_read = read(fd, bufArg.bufferPtr(), nbytes);
+
+ if (bytes_read != -1)
+ bufArg.copyOut(tc->getMemPort());
+
+ return bytes_read;
+}
+
+SyscallReturn
+writeFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
+{
+ int fd = p->sim_fd(tc->getSyscallArg(0));
+ int nbytes = tc->getSyscallArg(2);
+ BufferArg bufArg(tc->getSyscallArg(1), nbytes);
+
+ bufArg.copyIn(tc->getMemPort());
+
+ int bytes_written = write(fd, bufArg.bufferPtr(), nbytes);
+
+ fsync(fd);
+
+ return bytes_written;
+}
+
+
+SyscallReturn
+lseekFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
+{
+ int fd = p->sim_fd(tc->getSyscallArg(0));
+ uint64_t offs = tc->getSyscallArg(1);
+ int whence = tc->getSyscallArg(2);
+
+ off_t result = lseek(fd, offs, whence);
+
+ return (result == (off_t)-1) ? -errno : result;
+}
+
+
+SyscallReturn
+munmapFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
+{
+ // given that we don't really implement mmap, munmap is really easy
+ return 0;
+}
+
+
+const char *hostname = "m5.eecs.umich.edu";
+
+SyscallReturn
+gethostnameFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
+{
+ int name_len = tc->getSyscallArg(1);
+ BufferArg name(tc->getSyscallArg(0), name_len);
+
+ strncpy((char *)name.bufferPtr(), hostname, name_len);
+
+ name.copyOut(tc->getMemPort());
+
+ return 0;
+}
+
+SyscallReturn
+unlinkFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
+{
+ string path;
+
+ if (!tc->getMemPort()->tryReadString(path, tc->getSyscallArg(0)))
+ return (TheISA::IntReg)-EFAULT;
+
+ int result = unlink(path.c_str());
+ return (result == -1) ? -errno : result;
+}
+
+SyscallReturn
+renameFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
+{
+ string old_name;
+
+ if (!tc->getMemPort()->tryReadString(old_name, tc->getSyscallArg(0)))
+ return -EFAULT;
+
+ string new_name;
+
+ if (!tc->getMemPort()->tryReadString(new_name, tc->getSyscallArg(1)))
+ return -EFAULT;
+
+ int64_t result = rename(old_name.c_str(), new_name.c_str());
+ return (result == -1) ? -errno : result;
+}
+
+SyscallReturn
+truncateFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
+{
+ string path;
+
+ if (!tc->getMemPort()->tryReadString(path, tc->getSyscallArg(0)))
+ return -EFAULT;
+
+ off_t length = tc->getSyscallArg(1);
+
+ int result = truncate(path.c_str(), length);
+ return (result == -1) ? -errno : result;
+}
+
+SyscallReturn
+ftruncateFunc(SyscallDesc *desc, int num, Process *process, ThreadContext *tc)
+{
+ int fd = process->sim_fd(tc->getSyscallArg(0));
+
+ if (fd < 0)
+ return -EBADF;
+
+ off_t length = tc->getSyscallArg(1);
+
+ int result = ftruncate(fd, length);
+ return (result == -1) ? -errno : result;
+}
+
+SyscallReturn
+chownFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
+{
+ string path;
+
+ if (!tc->getMemPort()->tryReadString(path, tc->getSyscallArg(0)))
+ return -EFAULT;
+
+ /* XXX endianess */
+ uint32_t owner = tc->getSyscallArg(1);
+ uid_t hostOwner = owner;
+ uint32_t group = tc->getSyscallArg(2);
+ gid_t hostGroup = group;
+
+ int result = chown(path.c_str(), hostOwner, hostGroup);
+ return (result == -1) ? -errno : result;
+}
+
+SyscallReturn
+fchownFunc(SyscallDesc *desc, int num, Process *process, ThreadContext *tc)
+{
+ int fd = process->sim_fd(tc->getSyscallArg(0));
+
+ if (fd < 0)
+ return -EBADF;
+
+ /* XXX endianess */
+ uint32_t owner = tc->getSyscallArg(1);
+ uid_t hostOwner = owner;
+ uint32_t group = tc->getSyscallArg(2);
+ gid_t hostGroup = group;
+
+ int result = fchown(fd, hostOwner, hostGroup);
+ return (result == -1) ? -errno : result;
+}
+
+
+SyscallReturn
+fcntlFunc(SyscallDesc *desc, int num, Process *process,
+ ThreadContext *tc)
+{
+ int fd = tc->getSyscallArg(0);
+
+ if (fd < 0 || process->sim_fd(fd) < 0)
+ return -EBADF;
+
+ int cmd = tc->getSyscallArg(1);
+ switch (cmd) {
+ case 0: // F_DUPFD
+ // if we really wanted to support this, we'd need to do it
+ // in the target fd space.
+ warn("fcntl(%d, F_DUPFD) not supported, error returned\n", fd);
+ return -EMFILE;
+
+ case 1: // F_GETFD (get close-on-exec flag)
+ case 2: // F_SETFD (set close-on-exec flag)
+ return 0;
+
+ case 3: // F_GETFL (get file flags)
+ case 4: // F_SETFL (set file flags)
+ // not sure if this is totally valid, but we'll pass it through
+ // to the underlying OS
+ warn("fcntl(%d, %d) passed through to host\n", fd, cmd);
+ return fcntl(process->sim_fd(fd), cmd);
+ // return 0;
+
+ case 7: // F_GETLK (get lock)
+ case 8: // F_SETLK (set lock)
+ case 9: // F_SETLKW (set lock and wait)
+ // don't mess with file locking... just act like it's OK
+ warn("File lock call (fcntl(%d, %d)) ignored.\n", fd, cmd);
+ return 0;
+
+ default:
+ warn("Unknown fcntl command %d\n", cmd);
+ return 0;
+ }
+}
+
+SyscallReturn
+fcntl64Func(SyscallDesc *desc, int num, Process *process,
+ ThreadContext *tc)
+{
+ int fd = tc->getSyscallArg(0);
+
+ if (fd < 0 || process->sim_fd(fd) < 0)
+ return -EBADF;
+
+ int cmd = tc->getSyscallArg(1);
+ switch (cmd) {
+ case 33: //F_GETLK64
+ warn("fcntl64(%d, F_GETLK64) not supported, error returned\n", fd);
+ return -EMFILE;
+
+ case 34: // F_SETLK64
+ case 35: // F_SETLKW64
+ warn("fcntl64(%d, F_SETLK(W)64) not supported, error returned\n", fd);
+ return -EMFILE;
+
+ default:
+ // not sure if this is totally valid, but we'll pass it through
+ // to the underlying OS
+ warn("fcntl64(%d, %d) passed through to host\n", fd, cmd);
+ return fcntl(process->sim_fd(fd), cmd);
+ // return 0;
+ }
+}
+
+SyscallReturn
+pipePseudoFunc(SyscallDesc *desc, int callnum, Process *process,
+ ThreadContext *tc)
+{
+ int fds[2], sim_fds[2];
+ int pipe_retval = pipe(fds);
+
+ if (pipe_retval < 0) {
+ // error
+ return pipe_retval;
+ }
+
+ sim_fds[0] = process->alloc_fd(fds[0]);
+ sim_fds[1] = process->alloc_fd(fds[1]);
+
+ // Alpha Linux convention for pipe() is that fd[0] is returned as
+ // the return value of the function, and fd[1] is returned in r20.
+ tc->setIntReg(SyscallPseudoReturnReg, sim_fds[1]);
+ return sim_fds[0];
+}
+
+
+SyscallReturn
+getpidPseudoFunc(SyscallDesc *desc, int callnum, Process *process,
+ ThreadContext *tc)
+{
+ // Make up a PID. There's no interprocess communication in
+ // fake_syscall mode, so there's no way for a process to know it's
+ // not getting a unique value.
+
+ tc->setIntReg(SyscallPseudoReturnReg, 99);
+ return 100;
+}
+
+
+SyscallReturn
+getuidPseudoFunc(SyscallDesc *desc, int callnum, Process *process,
+ ThreadContext *tc)
+{
+ // Make up a UID and EUID... it shouldn't matter, and we want the
+ // simulation to be deterministic.
+
+ // EUID goes in r20.
+ tc->setIntReg(SyscallPseudoReturnReg, 100); //EUID
+ return 100; // UID
+}
+
+
+SyscallReturn
+getgidPseudoFunc(SyscallDesc *desc, int callnum, Process *process,
+ ThreadContext *tc)
+{
+ // Get current group ID. EGID goes in r20.
+ tc->setIntReg(SyscallPseudoReturnReg, 100); //EGID
+ return 100;
+}
+
+
+SyscallReturn
+setuidFunc(SyscallDesc *desc, int callnum, Process *process,
+ ThreadContext *tc)
+{
+ // can't fathom why a benchmark would call this.
+ warn("Ignoring call to setuid(%d)\n", tc->getSyscallArg(0));
+ return 0;
+}
+
+SyscallReturn
+getpidFunc(SyscallDesc *desc, int callnum, Process *process,
+ ThreadContext *tc)
+{
+ // Make up a PID. There's no interprocess communication in
+ // fake_syscall mode, so there's no way for a process to know it's
+ // not getting a unique value.
+
+ tc->setIntReg(SyscallPseudoReturnReg, 99); //PID
+ return 100;
+}
+
+SyscallReturn
+getppidFunc(SyscallDesc *desc, int callnum, Process *process,
+ ThreadContext *tc)
+{
+ return 99;
+}
+
+SyscallReturn
+getuidFunc(SyscallDesc *desc, int callnum, Process *process,
+ ThreadContext *tc)
+{
+ return 100; // UID
+}
+
+SyscallReturn
+geteuidFunc(SyscallDesc *desc, int callnum, Process *process,
+ ThreadContext *tc)
+{
+ return 100; // UID
+}
+
+SyscallReturn
+getgidFunc(SyscallDesc *desc, int callnum, Process *process,
+ ThreadContext *tc)
+{
+ return 100;
+}
+
+SyscallReturn
+getegidFunc(SyscallDesc *desc, int callnum, Process *process,
+ ThreadContext *tc)
+{
+ return 100;
+}
+
+