/*
+ * Copyright (c) 2012-2013 ARM Limited
+ * All rights reserved
+ *
+ * The license below extends only to copyright in the software and shall
+ * not be construed as granting a license to any other intellectual
+ * property including but not limited to intellectual property relating
+ * to a hardware implementation of the functionality of the software
+ * licensed hereunder. You may use the software subject to the license
+ * terms below provided that you ensure that this notice is replicated
+ * unmodified and in its entirety in all distributions of the software,
+ * modified or unmodified, in source code or in binary form.
+ *
* Copyright (c) 2003-2005 The Regents of The University of Michigan
* All rights reserved.
*
#define __SIM_SYSCALL_EMUL_HH__
#define NO_STAT64 (defined(__APPLE__) || defined(__OpenBSD__) || \
- defined(__FreeBSD__) || defined(__CYGWIN__))
+ defined(__FreeBSD__) || defined(__CYGWIN__) || \
+ defined(__NetBSD__))
///
/// @file syscall_emul.hh
/// This file defines objects used to emulate syscalls from the target
/// application on the host machine.
-#include <errno.h>
-#include <string>
#ifdef __CYGWIN32__
-#include <sys/fcntl.h> // for O_BINARY
+#include <sys/fcntl.h> // for O_BINARY
#endif
#include <sys/stat.h>
-#include <fcntl.h>
+#include <sys/time.h>
#include <sys/uio.h>
+#include <fcntl.h>
+
+#include <cerrno>
+#include <string>
-#include "sim/host.hh" // for Addr
#include "base/chunk_generator.hh"
-#include "base/intmath.hh" // for RoundUp
+#include "base/intmath.hh" // for RoundUp
#include "base/misc.hh"
#include "base/trace.hh"
+#include "base/types.hh"
+#include "config/the_isa.hh"
#include "cpu/base.hh"
#include "cpu/thread_context.hh"
-#include "mem/translating_port.hh"
+#include "debug/SyscallVerbose.hh"
#include "mem/page_table.hh"
+#include "sim/byteswap.hh"
+#include "sim/emul_driver.hh"
#include "sim/process.hh"
+#include "sim/syscall_emul_buf.hh"
+#include "sim/syscallreturn.hh"
+#include "sim/system.hh"
///
/// System call descriptor.
typedef SyscallReturn (*FuncPtr)(SyscallDesc *, int num,
LiveProcess *, ThreadContext *);
- const char *name; //!< Syscall name (e.g., "open").
- FuncPtr funcPtr; //!< Pointer to emulation function.
- int flags; //!< Flags (see Flags enum).
+ const char *name; //!< Syscall name (e.g., "open").
+ FuncPtr funcPtr; //!< Pointer to emulation function.
+ int flags; //!< Flags (see Flags enum).
/// Flag values for controlling syscall behavior.
enum Flags {
};
-class BaseBufferArg {
-
- public:
-
- BaseBufferArg(Addr _addr, int _size) : addr(_addr), size(_size)
- {
- bufPtr = new uint8_t[size];
- // clear out buffer: in case we only partially populate this,
- // and then do a copyOut(), we want to make sure we don't
- // introduce any random junk into the simulated address space
- memset(bufPtr, 0, size);
- }
-
- virtual ~BaseBufferArg() { delete [] bufPtr; }
-
- //
- // copy data into simulator space (read from target memory)
- //
- virtual bool copyIn(TranslatingPort *memport)
- {
- memport->readBlob(addr, bufPtr, size);
- return true; // no EFAULT detection for now
- }
-
- //
- // copy data out of simulator space (write to target memory)
- //
- virtual bool copyOut(TranslatingPort *memport)
- {
- memport->writeBlob(addr, bufPtr, size);
- return true; // no EFAULT detection for now
- }
-
- protected:
- Addr addr;
- int size;
- uint8_t *bufPtr;
-};
-
-
-class BufferArg : public BaseBufferArg
-{
- public:
- BufferArg(Addr _addr, int _size) : BaseBufferArg(_addr, _size) { }
- void *bufferPtr() { return bufPtr; }
-};
-
-template <class T>
-class TypedBufferArg : public BaseBufferArg
-{
- public:
- // user can optionally specify a specific number of bytes to
- // allocate to deal with those structs that have variable-size
- // arrays at the end
- TypedBufferArg(Addr _addr, int _size = sizeof(T))
- : BaseBufferArg(_addr, _size)
- { }
-
- // type case
- operator T*() { return (T *)bufPtr; }
-
- // dereference operators
- T &operator*() { return *((T *)bufPtr); }
- T* operator->() { return (T *)bufPtr; }
- T &operator[](int i) { return ((T *)bufPtr)[i]; }
-};
-
//////////////////////////////////////////////////////////////////////
//
// The following emulation functions are generic enough that they
/// trace flag is enabled. Return success to the target program.
SyscallReturn ignoreFunc(SyscallDesc *desc, int num,
LiveProcess *p, ThreadContext *tc);
+SyscallReturn ignoreWarnOnceFunc(SyscallDesc *desc, int num,
+ LiveProcess *p, ThreadContext *tc);
-/// Target exit() handler: terminate simulation.
+/// Target exit() handler: terminate current context.
SyscallReturn exitFunc(SyscallDesc *desc, int num,
LiveProcess *p, ThreadContext *tc);
+/// Target exit_group() handler: terminate simulation. (exit all threads)
+SyscallReturn exitGroupFunc(SyscallDesc *desc, int num,
+ LiveProcess *p, ThreadContext *tc);
+
/// Target getpagesize() handler.
SyscallReturn getpagesizeFunc(SyscallDesc *desc, int num,
LiveProcess *p, ThreadContext *tc);
-/// Target obreak() handler: set brk address.
-SyscallReturn obreakFunc(SyscallDesc *desc, int num,
- LiveProcess *p, ThreadContext *tc);
+/// Target brk() handler: set brk address.
+SyscallReturn brkFunc(SyscallDesc *desc, int num,
+ LiveProcess *p, ThreadContext *tc);
/// Target close() handler.
SyscallReturn closeFunc(SyscallDesc *desc, int num,
SyscallReturn gethostnameFunc(SyscallDesc *desc, int num,
LiveProcess *p, ThreadContext *tc);
+/// Target getcwd() handler.
+SyscallReturn getcwdFunc(SyscallDesc *desc, int num,
+ LiveProcess *p, ThreadContext *tc);
+
+/// Target readlink() handler.
+SyscallReturn readlinkFunc(SyscallDesc *desc, int num,
+ LiveProcess *p, ThreadContext *tc,
+ int index = 0);
+SyscallReturn readlinkFunc(SyscallDesc *desc, int num,
+ LiveProcess *p, ThreadContext *tc);
+
/// Target unlink() handler.
+SyscallReturn unlinkHelper(SyscallDesc *desc, int num,
+ LiveProcess *p, ThreadContext *tc,
+ int index);
SyscallReturn unlinkFunc(SyscallDesc *desc, int num,
LiveProcess *p, ThreadContext *tc);
+/// Target mkdir() handler.
+SyscallReturn mkdirFunc(SyscallDesc *desc, int num,
+ LiveProcess *p, ThreadContext *tc);
+
/// Target rename() handler.
SyscallReturn renameFunc(SyscallDesc *desc, int num,
LiveProcess *p, ThreadContext *tc);
LiveProcess *p, ThreadContext *tc);
+/// Target truncate64() handler.
+SyscallReturn truncate64Func(SyscallDesc *desc, int num,
+ LiveProcess *p, ThreadContext *tc);
+
+/// Target ftruncate64() handler.
+SyscallReturn ftruncate64Func(SyscallDesc *desc, int num,
+ LiveProcess *p, ThreadContext *tc);
+
+
+/// Target umask() handler.
+SyscallReturn umaskFunc(SyscallDesc *desc, int num,
+ LiveProcess *p, ThreadContext *tc);
+
+
/// Target chown() handler.
SyscallReturn chownFunc(SyscallDesc *desc, int num,
LiveProcess *p, ThreadContext *tc);
SyscallReturn getegidFunc(SyscallDesc *desc, int num,
LiveProcess *p, ThreadContext *tc);
+/// Target clone() handler.
+SyscallReturn cloneFunc(SyscallDesc *desc, int num,
+ LiveProcess *p, ThreadContext *tc);
+
+/// Target access() handler
+SyscallReturn accessFunc(SyscallDesc *desc, int num,
+ LiveProcess *p, ThreadContext *tc);
+SyscallReturn accessFunc(SyscallDesc *desc, int num,
+ LiveProcess *p, ThreadContext *tc,
+ int index);
+
+/// Futex system call
+/// Implemented by Daniel Sanchez
+/// Used by printf's in multi-threaded apps
+template <class OS>
+SyscallReturn
+futexFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
+ ThreadContext *tc)
+{
+ int index_uaddr = 0;
+ int index_op = 1;
+ int index_val = 2;
+ int index_timeout = 3;
+
+ uint64_t uaddr = process->getSyscallArg(tc, index_uaddr);
+ int op = process->getSyscallArg(tc, index_op);
+ int val = process->getSyscallArg(tc, index_val);
+ uint64_t timeout = process->getSyscallArg(tc, index_timeout);
+
+ std::map<uint64_t, std::list<ThreadContext *> * >
+ &futex_map = tc->getSystemPtr()->futexMap;
+
+ DPRINTF(SyscallVerbose, "In sys_futex: Address=%llx, op=%d, val=%d\n",
+ uaddr, op, val);
+
+ op &= ~OS::TGT_FUTEX_PRIVATE_FLAG;
+
+ if (op == OS::TGT_FUTEX_WAIT) {
+ if (timeout != 0) {
+ warn("sys_futex: FUTEX_WAIT with non-null timeout unimplemented;"
+ "we'll wait indefinitely");
+ }
+
+ uint8_t *buf = new uint8_t[sizeof(int)];
+ tc->getMemProxy().readBlob((Addr)uaddr, buf, (int)sizeof(int));
+ int mem_val = *((int *)buf);
+ delete buf;
+
+ if(val != mem_val) {
+ DPRINTF(SyscallVerbose, "sys_futex: FUTEX_WAKE, read: %d, "
+ "expected: %d\n", mem_val, val);
+ return -OS::TGT_EWOULDBLOCK;
+ }
+
+ // Queue the thread context
+ std::list<ThreadContext *> * tcWaitList;
+ if (futex_map.count(uaddr)) {
+ tcWaitList = futex_map.find(uaddr)->second;
+ } else {
+ tcWaitList = new std::list<ThreadContext *>();
+ futex_map.insert(std::pair< uint64_t,
+ std::list<ThreadContext *> * >(uaddr, tcWaitList));
+ }
+ tcWaitList->push_back(tc);
+ DPRINTF(SyscallVerbose, "sys_futex: FUTEX_WAIT, suspending calling "
+ "thread context\n");
+ tc->suspend();
+ return 0;
+ } else if (op == OS::TGT_FUTEX_WAKE){
+ int wokenUp = 0;
+ std::list<ThreadContext *> * tcWaitList;
+ if (futex_map.count(uaddr)) {
+ tcWaitList = futex_map.find(uaddr)->second;
+ while (tcWaitList->size() > 0 && wokenUp < val) {
+ tcWaitList->front()->activate();
+ tcWaitList->pop_front();
+ wokenUp++;
+ }
+ if(tcWaitList->empty()) {
+ futex_map.erase(uaddr);
+ delete tcWaitList;
+ }
+ }
+ DPRINTF(SyscallVerbose, "sys_futex: FUTEX_WAKE, activated %d waiting "
+ "thread contexts\n", wokenUp);
+ return wokenUp;
+ } else {
+ warn("sys_futex: op %d is not implemented, just returning...", op);
+ return 0;
+ }
+
+}
/// Pseudo Funcs - These functions use a different return convension,
void
getElapsedTime(T1 &sec, T2 &usec)
{
- int elapsed_usecs = curTick / Clock::Int::us;
+ int elapsed_usecs = curTick() / SimClock::Int::us;
sec = elapsed_usecs / one_million;
usec = elapsed_usecs % one_million;
}
tgt->st_dev = 0xA;
else
tgt->st_dev = host->st_dev;
- tgt->st_dev = htog(tgt->st_dev);
+ tgt->st_dev = TheISA::htog(tgt->st_dev);
tgt->st_ino = host->st_ino;
- tgt->st_ino = htog(tgt->st_ino);
+ tgt->st_ino = TheISA::htog(tgt->st_ino);
tgt->st_mode = host->st_mode;
- tgt->st_mode = htog(tgt->st_mode);
+ if (fakeTTY) {
+ // Claim to be a character device
+ tgt->st_mode &= ~S_IFMT; // Clear S_IFMT
+ tgt->st_mode |= S_IFCHR; // Set S_IFCHR
+ }
+ tgt->st_mode = TheISA::htog(tgt->st_mode);
tgt->st_nlink = host->st_nlink;
- tgt->st_nlink = htog(tgt->st_nlink);
+ tgt->st_nlink = TheISA::htog(tgt->st_nlink);
tgt->st_uid = host->st_uid;
- tgt->st_uid = htog(tgt->st_uid);
+ tgt->st_uid = TheISA::htog(tgt->st_uid);
tgt->st_gid = host->st_gid;
- tgt->st_gid = htog(tgt->st_gid);
+ tgt->st_gid = TheISA::htog(tgt->st_gid);
if (fakeTTY)
tgt->st_rdev = 0x880d;
else
tgt->st_rdev = host->st_rdev;
- tgt->st_rdev = htog(tgt->st_rdev);
+ tgt->st_rdev = TheISA::htog(tgt->st_rdev);
tgt->st_size = host->st_size;
- tgt->st_size = htog(tgt->st_size);
+ tgt->st_size = TheISA::htog(tgt->st_size);
tgt->st_atimeX = host->st_atime;
- tgt->st_atimeX = htog(tgt->st_atimeX);
+ tgt->st_atimeX = TheISA::htog(tgt->st_atimeX);
tgt->st_mtimeX = host->st_mtime;
- tgt->st_mtimeX = htog(tgt->st_mtimeX);
+ tgt->st_mtimeX = TheISA::htog(tgt->st_mtimeX);
tgt->st_ctimeX = host->st_ctime;
- tgt->st_ctimeX = htog(tgt->st_ctimeX);
+ tgt->st_ctimeX = TheISA::htog(tgt->st_ctimeX);
// Force the block size to be 8k. This helps to ensure buffered io works
// consistently across different hosts.
tgt->st_blksize = 0x2000;
- tgt->st_blksize = htog(tgt->st_blksize);
+ tgt->st_blksize = TheISA::htog(tgt->st_blksize);
tgt->st_blocks = host->st_blocks;
- tgt->st_blocks = htog(tgt->st_blocks);
+ tgt->st_blocks = TheISA::htog(tgt->st_blocks);
}
// Same for stat64
convertStatBuf<target_stat, host_stat64>(tgt, host, fakeTTY);
#if defined(STAT_HAVE_NSEC)
tgt->st_atime_nsec = host->st_atime_nsec;
- tgt->st_atime_nsec = htog(tgt->st_atime_nsec);
+ tgt->st_atime_nsec = TheISA::htog(tgt->st_atime_nsec);
tgt->st_mtime_nsec = host->st_mtime_nsec;
- tgt->st_mtime_nsec = htog(tgt->st_mtime_nsec);
+ tgt->st_mtime_nsec = TheISA::htog(tgt->st_mtime_nsec);
tgt->st_ctime_nsec = host->st_ctime_nsec;
- tgt->st_ctime_nsec = htog(tgt->st_ctime_nsec);
+ tgt->st_ctime_nsec = TheISA::htog(tgt->st_ctime_nsec);
#else
tgt->st_atime_nsec = 0;
tgt->st_mtime_nsec = 0;
//Here are a couple convenience functions
template<class OS>
static void
-copyOutStatBuf(TranslatingPort * mem, Addr addr,
+copyOutStatBuf(SETranslatingPortProxy &mem, Addr addr,
hst_stat *host, bool fakeTTY = false)
{
typedef TypedBufferArg<typename OS::tgt_stat> tgt_stat_buf;
template<class OS>
static void
-copyOutStat64Buf(TranslatingPort * mem, Addr addr,
+copyOutStat64Buf(SETranslatingPortProxy &mem, Addr addr,
hst_stat64 *host, bool fakeTTY = false)
{
typedef TypedBufferArg<typename OS::tgt_stat64> tgt_stat_buf;
tgt_stat_buf tgt(addr);
- convertStatBuf<tgt_stat_buf, hst_stat64>(tgt, host, fakeTTY);
+ convertStat64Buf<tgt_stat_buf, hst_stat64>(tgt, host, fakeTTY);
tgt.copyOut(mem);
}
/// Target ioctl() handler. For the most part, programs call ioctl()
/// only to find out if their stdout is a tty, to determine whether to
-/// do line or block buffering.
+/// do line or block buffering. We always claim that output fds are
+/// not TTYs to provide repeatable results.
template <class OS>
SyscallReturn
ioctlFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
ThreadContext *tc)
{
- int fd = tc->getSyscallArg(0);
- unsigned req = tc->getSyscallArg(1);
+ int index = 0;
+ int fd = process->getSyscallArg(tc, index);
+ unsigned req = process->getSyscallArg(tc, index);
DPRINTF(SyscallVerbose, "ioctl(%d, 0x%x, ...)\n", fd, req);
- if (fd < 0 || process->sim_fd(fd) < 0) {
+ Process::FdMap *fdObj = process->sim_fd_obj(fd);
+
+ if (fdObj == NULL) {
// doesn't map to any simulator fd: not a valid target fd
return -EBADF;
}
- switch (req) {
- case OS::TIOCISATTY_:
- case OS::TIOCGETP_:
- case OS::TIOCSETP_:
- case OS::TIOCSETN_:
- case OS::TIOCSETC_:
- case OS::TIOCGETC_:
- case OS::TIOCGETS_:
- case OS::TIOCGETA_:
- return -ENOTTY;
+ if (fdObj->driver != NULL) {
+ return fdObj->driver->ioctl(process, tc, req);
+ }
- default:
- fatal("Unsupported ioctl call: ioctl(%d, 0x%x, ...) @ 0x%llx\n",
- fd, req, tc->readPC());
+ if (OS::isTtyReq(req)) {
+ return -ENOTTY;
}
+
+ warn("Unsupported ioctl call: ioctl(%d, 0x%x, ...) @ \n",
+ fd, req, tc->pcState());
+ return -ENOTTY;
}
-/// Target open() handler.
template <class OS>
-SyscallReturn
+static SyscallReturn
openFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
- ThreadContext *tc)
+ ThreadContext *tc, int index)
{
std::string path;
- if (!tc->getMemPort()->tryReadString(path, tc->getSyscallArg(0)))
+ if (!tc->getMemProxy().tryReadString(path,
+ process->getSyscallArg(tc, index)))
return -EFAULT;
- if (path == "/dev/sysdev0") {
- // This is a memory-mapped high-resolution timer device on Alpha.
- // We don't support it, so just punt.
- warn("Ignoring open(%s, ...)\n", path);
- return -ENOENT;
- }
-
- int tgtFlags = tc->getSyscallArg(1);
- int mode = tc->getSyscallArg(2);
+ int tgtFlags = process->getSyscallArg(tc, index);
+ int mode = process->getSyscallArg(tc, index);
int hostFlags = 0;
// translate open flags
DPRINTF(SyscallVerbose, "opening file %s\n", path.c_str());
- // open the file
- int fd = open(path.c_str(), hostFlags, mode);
+ if (startswith(path, "/dev/")) {
+ std::string filename = path.substr(strlen("/dev/"));
+ if (filename == "sysdev0") {
+ // This is a memory-mapped high-resolution timer device on Alpha.
+ // We don't support it, so just punt.
+ warn("Ignoring open(%s, ...)\n", path);
+ return -ENOENT;
+ }
+
+ EmulatedDriver *drv = process->findDriver(filename);
+ if (drv != NULL) {
+ // the driver's open method will allocate a fd from the
+ // process if necessary.
+ return drv->open(process, tc, mode, hostFlags);
+ }
- return (fd == -1) ? -errno : process->alloc_fd(fd);
+ // fall through here for pass through to host devices, such as
+ // /dev/zero
+ }
+
+ int fd;
+ int local_errno;
+ if (startswith(path, "/proc/") || startswith(path, "/system/") ||
+ startswith(path, "/platform/") || startswith(path, "/sys/")) {
+ // It's a proc/sys entry and requires special handling
+ fd = OS::openSpecialFile(path, process, tc);
+ local_errno = ENOENT;
+ } else {
+ // open the file
+ fd = open(path.c_str(), hostFlags, mode);
+ local_errno = errno;
+ }
+
+ if (fd == -1)
+ return -local_errno;
+
+ return process->alloc_fd(fd, path.c_str(), hostFlags, mode, false);
}
+/// Target open() handler.
+template <class OS>
+SyscallReturn
+openFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
+ ThreadContext *tc)
+{
+ return openFunc<OS>(desc, callnum, process, tc, 0);
+}
+
+/// Target openat() handler.
+template <class OS>
+SyscallReturn
+openatFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
+ ThreadContext *tc)
+{
+ int index = 0;
+ int dirfd = process->getSyscallArg(tc, index);
+ if (dirfd != OS::TGT_AT_FDCWD)
+ warn("openat: first argument not AT_FDCWD; unlikely to work");
+ return openFunc<OS>(desc, callnum, process, tc, 1);
+}
+
+/// Target unlinkat() handler.
+template <class OS>
+SyscallReturn
+unlinkatFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
+ ThreadContext *tc)
+{
+ int index = 0;
+ int dirfd = process->getSyscallArg(tc, index);
+ if (dirfd != OS::TGT_AT_FDCWD)
+ warn("unlinkat: first argument not AT_FDCWD; unlikely to work");
+
+ return unlinkHelper(desc, callnum, process, tc, 1);
+}
+
+/// Target facessat() handler
+template <class OS>
+SyscallReturn
+faccessatFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
+ ThreadContext *tc)
+{
+ int index = 0;
+ int dirfd = process->getSyscallArg(tc, index);
+ if (dirfd != OS::TGT_AT_FDCWD)
+ warn("faccessat: first argument not AT_FDCWD; unlikely to work");
+ return accessFunc(desc, callnum, process, tc, 1);
+}
+
+/// Target readlinkat() handler
+template <class OS>
+SyscallReturn
+readlinkatFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
+ ThreadContext *tc)
+{
+ int index = 0;
+ int dirfd = process->getSyscallArg(tc, index);
+ if (dirfd != OS::TGT_AT_FDCWD)
+ warn("openat: first argument not AT_FDCWD; unlikely to work");
+ return readlinkFunc(desc, callnum, process, tc, 1);
+}
+
+/// Target sysinfo() handler.
+template <class OS>
+SyscallReturn
+sysinfoFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
+ ThreadContext *tc)
+{
+
+ int index = 0;
+ TypedBufferArg<typename OS::tgt_sysinfo>
+ sysinfo(process->getSyscallArg(tc, index));
+
+ sysinfo->uptime=seconds_since_epoch;
+ sysinfo->totalram=process->system->memSize();
+
+ sysinfo.copyOut(tc->getMemProxy());
+
+ return 0;
+}
/// Target chmod() handler.
template <class OS>
{
std::string path;
- if (!tc->getMemPort()->tryReadString(path, tc->getSyscallArg(0)))
+ int index = 0;
+ if (!tc->getMemProxy().tryReadString(path,
+ process->getSyscallArg(tc, index))) {
return -EFAULT;
+ }
- uint32_t mode = tc->getSyscallArg(1);
+ uint32_t mode = process->getSyscallArg(tc, index);
mode_t hostMode = 0;
// XXX translate mode flags via OS::something???
fchmodFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
ThreadContext *tc)
{
- int fd = tc->getSyscallArg(0);
+ int index = 0;
+ int fd = process->getSyscallArg(tc, index);
if (fd < 0 || process->sim_fd(fd) < 0) {
// doesn't map to any simulator fd: not a valid target fd
return -EBADF;
}
- uint32_t mode = tc->getSyscallArg(1);
+ uint32_t mode = process->getSyscallArg(tc, index);
mode_t hostMode = 0;
// XXX translate mode flags via OS::someting???
return 0;
}
+/// Target mremap() handler.
+template <class OS>
+SyscallReturn
+mremapFunc(SyscallDesc *desc, int callnum, LiveProcess *process, ThreadContext *tc)
+{
+ int index = 0;
+ Addr start = process->getSyscallArg(tc, index);
+ uint64_t old_length = process->getSyscallArg(tc, index);
+ uint64_t new_length = process->getSyscallArg(tc, index);
+ uint64_t flags = process->getSyscallArg(tc, index);
+ uint64_t provided_address = 0;
+ bool use_provided_address = flags & OS::TGT_MREMAP_FIXED;
+
+ if (use_provided_address)
+ provided_address = process->getSyscallArg(tc, index);
+
+ if ((start % TheISA::PageBytes != 0) ||
+ (provided_address % TheISA::PageBytes != 0)) {
+ warn("mremap failing: arguments not page aligned");
+ return -EINVAL;
+ }
+
+ new_length = roundUp(new_length, TheISA::PageBytes);
+
+ if (new_length > old_length) {
+ if ((start + old_length) == process->mmap_end &&
+ (!use_provided_address || provided_address == start)) {
+ uint64_t diff = new_length - old_length;
+ process->allocateMem(process->mmap_end, diff);
+ process->mmap_end += diff;
+ return start;
+ } else {
+ if (!use_provided_address && !(flags & OS::TGT_MREMAP_MAYMOVE)) {
+ warn("can't remap here and MREMAP_MAYMOVE flag not set\n");
+ return -ENOMEM;
+ } else {
+ uint64_t new_start = use_provided_address ?
+ provided_address : process->mmap_end;
+ process->pTable->remap(start, old_length, new_start);
+ warn("mremapping to new vaddr %08p-%08p, adding %d\n",
+ new_start, new_start + new_length,
+ new_length - old_length);
+ // add on the remaining unallocated pages
+ process->allocateMem(new_start + old_length,
+ new_length - old_length,
+ use_provided_address /* clobber */);
+ if (!use_provided_address)
+ process->mmap_end += new_length;
+ if (use_provided_address &&
+ new_start + new_length > process->mmap_end) {
+ // something fishy going on here, at least notify the user
+ // @todo: increase mmap_end?
+ warn("mmap region limit exceeded with MREMAP_FIXED\n");
+ }
+ warn("returning %08p as start\n", new_start);
+ return new_start;
+ }
+ }
+ } else {
+ if (use_provided_address && provided_address != start)
+ process->pTable->remap(start, new_length, provided_address);
+ process->pTable->unmap(start + new_length, old_length - new_length);
+ return use_provided_address ? provided_address : start;
+ }
+}
/// Target stat() handler.
template <class OS>
{
std::string path;
- if (!tc->getMemPort()->tryReadString(path, tc->getSyscallArg(0)))
- return -EFAULT;
+ int index = 0;
+ if (!tc->getMemProxy().tryReadString(path,
+ process->getSyscallArg(tc, index))) {
+ return -EFAULT;
+ }
+ Addr bufPtr = process->getSyscallArg(tc, index);
// Adjust path for current working directory
path = process->fullPath(path);
if (result < 0)
return -errno;
- copyOutStatBuf<OS>(tc->getMemPort(), tc->getSyscallArg(1), &hostBuf);
+ copyOutStatBuf<OS>(tc->getMemProxy(), bufPtr, &hostBuf);
return 0;
}
{
std::string path;
- if (!tc->getMemPort()->tryReadString(path, tc->getSyscallArg(0)))
+ int index = 0;
+ if (!tc->getMemProxy().tryReadString(path,
+ process->getSyscallArg(tc, index)))
return -EFAULT;
+ Addr bufPtr = process->getSyscallArg(tc, index);
// Adjust path for current working directory
path = process->fullPath(path);
+#if NO_STAT64
+ struct stat hostBuf;
+ int result = stat(path.c_str(), &hostBuf);
+#else
struct stat64 hostBuf;
int result = stat64(path.c_str(), &hostBuf);
+#endif
if (result < 0)
return -errno;
- copyOutStat64Buf<OS>(tc->getMemPort(), tc->getSyscallArg(1), &hostBuf);
+ copyOutStat64Buf<OS>(tc->getMemProxy(), bufPtr, &hostBuf);
+
+ return 0;
+}
+
+
+/// Target fstatat64() handler.
+template <class OS>
+SyscallReturn
+fstatat64Func(SyscallDesc *desc, int callnum, LiveProcess *process,
+ ThreadContext *tc)
+{
+ int index = 0;
+ int dirfd = process->getSyscallArg(tc, index);
+ if (dirfd != OS::TGT_AT_FDCWD)
+ warn("openat: first argument not AT_FDCWD; unlikely to work");
+
+ std::string path;
+ if (!tc->getMemProxy().tryReadString(path,
+ process->getSyscallArg(tc, index)))
+ return -EFAULT;
+ Addr bufPtr = process->getSyscallArg(tc, index);
+
+ // Adjust path for current working directory
+ path = process->fullPath(path);
+
+#if NO_STAT64
+ struct stat hostBuf;
+ int result = stat(path.c_str(), &hostBuf);
+#else
+ struct stat64 hostBuf;
+ int result = stat64(path.c_str(), &hostBuf);
+#endif
+
+ if (result < 0)
+ return -errno;
+
+ copyOutStat64Buf<OS>(tc->getMemProxy(), bufPtr, &hostBuf);
return 0;
}
fstat64Func(SyscallDesc *desc, int callnum, LiveProcess *process,
ThreadContext *tc)
{
- int fd = tc->getSyscallArg(0);
+ int index = 0;
+ int fd = process->getSyscallArg(tc, index);
+ Addr bufPtr = process->getSyscallArg(tc, index);
if (fd < 0 || process->sim_fd(fd) < 0) {
// doesn't map to any simulator fd: not a valid target fd
return -EBADF;
if (result < 0)
return -errno;
- copyOutStat64Buf<OS>(tc->getMemPort(), tc->getSyscallArg(1),
- &hostBuf, (fd == 1));
+ copyOutStat64Buf<OS>(tc->getMemProxy(), bufPtr, &hostBuf, (fd == 1));
return 0;
}
{
std::string path;
- if (!tc->getMemPort()->tryReadString(path, tc->getSyscallArg(0)))
- return -EFAULT;
+ int index = 0;
+ if (!tc->getMemProxy().tryReadString(path,
+ process->getSyscallArg(tc, index))) {
+ return -EFAULT;
+ }
+ Addr bufPtr = process->getSyscallArg(tc, index);
// Adjust path for current working directory
path = process->fullPath(path);
if (result < 0)
return -errno;
- copyOutStatBuf<OS>(tc->getMemPort(), tc->getSyscallArg(1), &hostBuf);
+ copyOutStatBuf<OS>(tc->getMemProxy(), bufPtr, &hostBuf);
return 0;
}
{
std::string path;
- if (!tc->getMemPort()->tryReadString(path, tc->getSyscallArg(0)))
- return -EFAULT;
+ int index = 0;
+ if (!tc->getMemProxy().tryReadString(path,
+ process->getSyscallArg(tc, index))) {
+ return -EFAULT;
+ }
+ Addr bufPtr = process->getSyscallArg(tc, index);
// Adjust path for current working directory
path = process->fullPath(path);
if (result < 0)
return -errno;
- copyOutStat64Buf<OS>(tc->getMemPort(), tc->getSyscallArg(1), &hostBuf);
+ copyOutStat64Buf<OS>(tc->getMemProxy(), bufPtr, &hostBuf);
return 0;
}
fstatFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
ThreadContext *tc)
{
- int fd = process->sim_fd(tc->getSyscallArg(0));
+ int index = 0;
+ int fd = process->sim_fd(process->getSyscallArg(tc, index));
+ Addr bufPtr = process->getSyscallArg(tc, index);
DPRINTF(SyscallVerbose, "fstat(%d, ...)\n", fd);
if (result < 0)
return -errno;
- copyOutStatBuf<OS>(tc->getMemPort(), tc->getSyscallArg(1),
- &hostBuf, (fd == 1));
+ copyOutStatBuf<OS>(tc->getMemProxy(), bufPtr, &hostBuf, (fd == 1));
return 0;
}
{
std::string path;
- if (!tc->getMemPort()->tryReadString(path, tc->getSyscallArg(0)))
- return -EFAULT;
+ int index = 0;
+ if (!tc->getMemProxy().tryReadString(path,
+ process->getSyscallArg(tc, index))) {
+ return -EFAULT;
+ }
+ Addr bufPtr = process->getSyscallArg(tc, index);
// Adjust path for current working directory
path = process->fullPath(path);
if (result < 0)
return -errno;
- OS::copyOutStatfsBuf(tc->getMemPort(),
- (Addr)(tc->getSyscallArg(1)), &hostBuf);
+ OS::copyOutStatfsBuf(tc->getMemProxy(), bufPtr, &hostBuf);
return 0;
}
fstatfsFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
ThreadContext *tc)
{
- int fd = process->sim_fd(tc->getSyscallArg(0));
+ int index = 0;
+ int fd = process->sim_fd(process->getSyscallArg(tc, index));
+ Addr bufPtr = process->getSyscallArg(tc, index);
if (fd < 0)
return -EBADF;
if (result < 0)
return -errno;
- OS::copyOutStatfsBuf(tc->getMemPort(), tc->getSyscallArg(1),
- &hostBuf);
+ OS::copyOutStatfsBuf(tc->getMemProxy(), bufPtr, &hostBuf);
return 0;
}
writevFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
ThreadContext *tc)
{
- int fd = tc->getSyscallArg(0);
+ int index = 0;
+ int fd = process->getSyscallArg(tc, index);
if (fd < 0 || process->sim_fd(fd) < 0) {
// doesn't map to any simulator fd: not a valid target fd
return -EBADF;
}
- TranslatingPort *p = tc->getMemPort();
- uint64_t tiov_base = tc->getSyscallArg(1);
- size_t count = tc->getSyscallArg(2);
+ SETranslatingPortProxy &p = tc->getMemProxy();
+ uint64_t tiov_base = process->getSyscallArg(tc, index);
+ size_t count = process->getSyscallArg(tc, index);
struct iovec hiov[count];
- for (int i = 0; i < count; ++i)
- {
+ for (size_t i = 0; i < count; ++i) {
typename OS::tgt_iovec tiov;
- p->readBlob(tiov_base + i*sizeof(typename OS::tgt_iovec),
- (uint8_t*)&tiov, sizeof(typename OS::tgt_iovec));
- hiov[i].iov_len = gtoh(tiov.iov_len);
+ p.readBlob(tiov_base + i*sizeof(typename OS::tgt_iovec),
+ (uint8_t*)&tiov, sizeof(typename OS::tgt_iovec));
+ hiov[i].iov_len = TheISA::gtoh(tiov.iov_len);
hiov[i].iov_base = new char [hiov[i].iov_len];
- p->readBlob(gtoh(tiov.iov_base), (uint8_t *)hiov[i].iov_base,
- hiov[i].iov_len);
+ p.readBlob(TheISA::gtoh(tiov.iov_base), (uint8_t *)hiov[i].iov_base,
+ hiov[i].iov_len);
}
int result = writev(process->sim_fd(fd), hiov, count);
- for (int i = 0; i < count; ++i)
- {
+ for (size_t i = 0; i < count; ++i)
delete [] (char *)hiov[i].iov_base;
- }
if (result < 0)
return -errno;
- return 0;
+ return result;
}
/// We don't really handle mmap(). If the target is mmaping an
/// anonymous region or /dev/zero, we can get away with doing basically
/// nothing (since memory is initialized to zero and the simulator
-/// doesn't really check addresses anyway). Always print a warning,
-/// since this could be seriously broken if we're not mapping
-/// /dev/zero.
-//
-/// Someday we should explicitly check for /dev/zero in open, flag the
-/// file descriptor, and fail (or implement!) a non-anonymous mmap to
-/// anything else.
+/// doesn't really check addresses anyway).
+///
template <class OS>
SyscallReturn
mmapFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc)
{
- Addr start = tc->getSyscallArg(0);
- uint64_t length = tc->getSyscallArg(1);
- // int prot = tc->getSyscallArg(2);
- int flags = tc->getSyscallArg(3);
- // int fd = p->sim_fd(tc->getSyscallArg(4));
- // int offset = tc->getSyscallArg(5);
+ int index = 0;
+ Addr start = p->getSyscallArg(tc, index);
+ uint64_t length = p->getSyscallArg(tc, index);
+ index++; // int prot = p->getSyscallArg(tc, index);
+ int flags = p->getSyscallArg(tc, index);
+ int tgt_fd = p->getSyscallArg(tc, index);
+ int offset = p->getSyscallArg(tc, index);
+
+ if (length > 0x100000000ULL)
+ warn("mmap length argument %#x is unreasonably large.\n", length);
+
+ if (!(flags & OS::TGT_MAP_ANONYMOUS)) {
+ Process::FdMap *fd_map = p->sim_fd_obj(tgt_fd);
+ if (!fd_map || fd_map->fd < 0) {
+ warn("mmap failing: target fd %d is not valid\n", tgt_fd);
+ return -EBADF;
+ }
+
+ if (fd_map->filename != "/dev/zero") {
+ // This is very likely broken, but leave a warning here
+ // (rather than panic) in case /dev/zero is known by
+ // another name on some platform
+ warn("allowing mmap of file %s; mmap not supported on files"
+ " other than /dev/zero\n", fd_map->filename);
+ }
+ }
- if ((start % TheISA::VMPageSize) != 0 ||
- (length % TheISA::VMPageSize) != 0) {
+ length = roundUp(length, TheISA::PageBytes);
+
+ if ((start % TheISA::PageBytes) != 0 ||
+ (offset % TheISA::PageBytes) != 0) {
warn("mmap failing: arguments not page-aligned: "
- "start 0x%x length 0x%x",
- start, length);
+ "start 0x%x offset 0x%x",
+ start, offset);
return -EINVAL;
}
- if (start != 0) {
- warn("mmap: ignoring suggested map address 0x%x, using 0x%x",
- start, p->mmap_end);
+ // are we ok with clobbering existing mappings? only set this to
+ // true if the user has been warned.
+ bool clobber = false;
+
+ // try to use the caller-provided address if there is one
+ bool use_provided_address = (start != 0);
+
+ if (use_provided_address) {
+ // check to see if the desired address is already in use
+ if (!p->pTable->isUnmapped(start, length)) {
+ // there are existing mappings in the desired range
+ // whether we clobber them or not depends on whether the caller
+ // specified MAP_FIXED
+ if (flags & OS::TGT_MAP_FIXED) {
+ // MAP_FIXED specified: map attempt fails
+ return -EINVAL;
+ } else {
+ // MAP_FIXED not specified: ignore suggested start address
+ warn("mmap: ignoring suggested map address 0x%x\n", start);
+ use_provided_address = false;
+ }
+ }
}
- // pick next address from our "mmap region"
- start = p->mmap_end;
- p->pTable->allocate(start, length);
- p->mmap_end += length;
-
- if (!(flags & OS::TGT_MAP_ANONYMOUS)) {
- warn("allowing mmap of file @ fd %d. "
- "This will break if not /dev/zero.", tc->getSyscallArg(4));
+ if (!use_provided_address) {
+ // no address provided, or provided address unusable:
+ // pick next address from our "mmap region"
+ if (OS::mmapGrowsDown()) {
+ start = p->mmap_end - length;
+ p->mmap_end = start;
+ } else {
+ start = p->mmap_end;
+ p->mmap_end += length;
+ }
}
+ p->allocateMem(start, length, clobber);
+
return start;
}
getrlimitFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
ThreadContext *tc)
{
- unsigned resource = tc->getSyscallArg(0);
- TypedBufferArg<typename OS::rlimit> rlp(tc->getSyscallArg(1));
+ int index = 0;
+ unsigned resource = process->getSyscallArg(tc, index);
+ TypedBufferArg<typename OS::rlimit> rlp(process->getSyscallArg(tc, index));
switch (resource) {
case OS::TGT_RLIMIT_STACK:
- // max stack size in bytes: make up a number (2MB for now)
+ // max stack size in bytes: make up a number (8MB for now)
rlp->rlim_cur = rlp->rlim_max = 8 * 1024 * 1024;
- rlp->rlim_cur = htog(rlp->rlim_cur);
- rlp->rlim_max = htog(rlp->rlim_max);
+ rlp->rlim_cur = TheISA::htog(rlp->rlim_cur);
+ rlp->rlim_max = TheISA::htog(rlp->rlim_max);
+ break;
+
+ case OS::TGT_RLIMIT_DATA:
+ // max data segment size in bytes: make up a number
+ rlp->rlim_cur = rlp->rlim_max = 256 * 1024 * 1024;
+ rlp->rlim_cur = TheISA::htog(rlp->rlim_cur);
+ rlp->rlim_max = TheISA::htog(rlp->rlim_max);
break;
default:
break;
}
- rlp.copyOut(tc->getMemPort());
+ rlp.copyOut(tc->getMemProxy());
return 0;
}
gettimeofdayFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
ThreadContext *tc)
{
- TypedBufferArg<typename OS::timeval> tp(tc->getSyscallArg(0));
+ int index = 0;
+ TypedBufferArg<typename OS::timeval> tp(process->getSyscallArg(tc, index));
getElapsedTime(tp->tv_sec, tp->tv_usec);
tp->tv_sec += seconds_since_epoch;
- tp->tv_sec = htog(tp->tv_sec);
- tp->tv_usec = htog(tp->tv_usec);
+ tp->tv_sec = TheISA::htog(tp->tv_sec);
+ tp->tv_usec = TheISA::htog(tp->tv_usec);
- tp.copyOut(tc->getMemPort());
+ tp.copyOut(tc->getMemProxy());
return 0;
}
{
std::string path;
- if (!tc->getMemPort()->tryReadString(path, tc->getSyscallArg(0)))
- return -EFAULT;
+ int index = 0;
+ if (!tc->getMemProxy().tryReadString(path,
+ process->getSyscallArg(tc, index))) {
+ return -EFAULT;
+ }
- TypedBufferArg<typename OS::timeval [2]> tp(tc->getSyscallArg(1));
- tp.copyIn(tc->getMemPort());
+ TypedBufferArg<typename OS::timeval [2]>
+ tp(process->getSyscallArg(tc, index));
+ tp.copyIn(tc->getMemProxy());
struct timeval hostTimeval[2];
for (int i = 0; i < 2; ++i)
{
- hostTimeval[i].tv_sec = gtoh((*tp)[i].tv_sec);
- hostTimeval[i].tv_usec = gtoh((*tp)[i].tv_usec);
+ hostTimeval[i].tv_sec = TheISA::gtoh((*tp)[i].tv_sec);
+ hostTimeval[i].tv_usec = TheISA::gtoh((*tp)[i].tv_usec);
}
// Adjust path for current working directory
getrusageFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
ThreadContext *tc)
{
- int who = tc->getSyscallArg(0); // THREAD, SELF, or CHILDREN
- TypedBufferArg<typename OS::rusage> rup(tc->getSyscallArg(1));
+ int index = 0;
+ int who = process->getSyscallArg(tc, index); // THREAD, SELF, or CHILDREN
+ TypedBufferArg<typename OS::rusage> rup(process->getSyscallArg(tc, index));
rup->ru_utime.tv_sec = 0;
rup->ru_utime.tv_usec = 0;
switch (who) {
case OS::TGT_RUSAGE_SELF:
getElapsedTime(rup->ru_utime.tv_sec, rup->ru_utime.tv_usec);
- rup->ru_utime.tv_sec = htog(rup->ru_utime.tv_sec);
- rup->ru_utime.tv_usec = htog(rup->ru_utime.tv_usec);
+ rup->ru_utime.tv_sec = TheISA::htog(rup->ru_utime.tv_sec);
+ rup->ru_utime.tv_usec = TheISA::htog(rup->ru_utime.tv_usec);
break;
case OS::TGT_RUSAGE_CHILDREN:
who);
}
- rup.copyOut(tc->getMemPort());
+ rup.copyOut(tc->getMemProxy());
return 0;
}
+/// Target times() function.
+template <class OS>
+SyscallReturn
+timesFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
+ ThreadContext *tc)
+{
+ int index = 0;
+ TypedBufferArg<typename OS::tms> bufp(process->getSyscallArg(tc, index));
+
+ // Fill in the time structure (in clocks)
+ int64_t clocks = curTick() * OS::M5_SC_CLK_TCK / SimClock::Int::s;
+ bufp->tms_utime = clocks;
+ bufp->tms_stime = 0;
+ bufp->tms_cutime = 0;
+ bufp->tms_cstime = 0;
+
+ // Convert to host endianness
+ bufp->tms_utime = TheISA::htog(bufp->tms_utime);
+
+ // Write back
+ bufp.copyOut(tc->getMemProxy());
+
+ // Return clock ticks since system boot
+ return clocks;
+}
+/// Target time() function.
+template <class OS>
+SyscallReturn
+timeFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
+ ThreadContext *tc)
+{
+ typename OS::time_t sec, usec;
+ getElapsedTime(sec, usec);
+ sec += seconds_since_epoch;
+
+ int index = 0;
+ Addr taddr = (Addr)process->getSyscallArg(tc, index);
+ if(taddr != 0) {
+ typename OS::time_t t = sec;
+ t = TheISA::htog(t);
+ SETranslatingPortProxy &p = tc->getMemProxy();
+ p.writeBlob(taddr, (uint8_t*)&t, (int)sizeof(typename OS::time_t));
+ }
+ return sec;
+}
#endif // __SIM_SYSCALL_EMUL_HH__