X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=src%2Fsim%2Fsyscall_emul.hh;h=cc430b9492b1c881219f613077887e5bed856594;hb=da0c770943a26cd258fcd9bf608e1c78ff8e6be5;hp=b5a8e49d4bc57a7584f7995db361dc5d1b156dbb;hpb=e232152db6d9cd511a75c41f47b00befe9b7719e;p=gem5.git diff --git a/src/sim/syscall_emul.hh b/src/sim/syscall_emul.hh index b5a8e49d4..cc430b949 100644 --- a/src/sim/syscall_emul.hh +++ b/src/sim/syscall_emul.hh @@ -1,4 +1,16 @@ /* + * 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. * @@ -33,7 +45,8 @@ #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 @@ -62,9 +75,10 @@ #include "cpu/thread_context.hh" #include "debug/SyscallVerbose.hh" #include "mem/page_table.hh" -#include "mem/se_translating_port_proxy.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" @@ -103,73 +117,6 @@ class SyscallDesc { }; -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(SETranslatingPortProxy &memproxy) - { - memproxy.readBlob(addr, bufPtr, size); - return true; // no EFAULT detection for now - } - - // - // copy data out of simulator space (write to target memory) - // - virtual bool copyOut(SETranslatingPortProxy &memproxy) - { - memproxy.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 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 @@ -240,11 +187,17 @@ SyscallReturn gethostnameFunc(SyscallDesc *desc, int num, SyscallReturn getcwdFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc); -/// Target unlink() handler. +/// 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); @@ -334,6 +287,13 @@ SyscallReturn getegidFunc(SyscallDesc *desc, int num, 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 @@ -358,6 +318,7 @@ futexFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 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) { @@ -409,7 +370,7 @@ futexFunc(SyscallDesc *desc, int callnum, LiveProcess *process, "thread contexts\n", wokenUp); return wokenUp; } else { - warn("sys_futex: op %d is not implemented, just returning..."); + warn("sys_futex: op %d is not implemented, just returning...", op); return 0; } @@ -580,11 +541,17 @@ ioctlFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 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; } + if (fdObj->driver != NULL) { + return fdObj->driver->ioctl(process, tc, req); + } + if (OS::isTtyReq(req)) { return -ENOTTY; } @@ -594,26 +561,17 @@ ioctlFunc(SyscallDesc *desc, int callnum, LiveProcess *process, return -ENOTTY; } -/// Target open() handler. template -SyscallReturn +static SyscallReturn openFunc(SyscallDesc *desc, int callnum, LiveProcess *process, - ThreadContext *tc) + ThreadContext *tc, int index) { std::string path; - int index = 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 = process->getSyscallArg(tc, index); int mode = process->getSyscallArg(tc, index); int hostFlags = 0; @@ -639,6 +597,26 @@ openFunc(SyscallDesc *desc, int callnum, LiveProcess *process, DPRINTF(SyscallVerbose, "opening file %s\n", path.c_str()); + 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); + } + + // 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/") || @@ -658,6 +636,68 @@ openFunc(SyscallDesc *desc, int callnum, LiveProcess *process, return process->alloc_fd(fd, path.c_str(), hostFlags, mode, false); } +/// Target open() handler. +template +SyscallReturn +openFunc(SyscallDesc *desc, int callnum, LiveProcess *process, + ThreadContext *tc) +{ + return openFunc(desc, callnum, process, tc, 0); +} + +/// Target openat() handler. +template +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(desc, callnum, process, tc, 1); +} + +/// Target unlinkat() handler. +template +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 +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 +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 SyscallReturn @@ -746,40 +786,59 @@ mremapFunc(SyscallDesc *desc, int callnum, LiveProcess *process, ThreadContext * 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 ((start % TheISA::VMPageSize != 0) || - (new_length % TheISA::VMPageSize != 0)) { + 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) { + 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 { - // sys/mman.h defined MREMAP_MAYMOVE - if (!(flags & 1)) { + if (!use_provided_address && !(flags & OS::TGT_MREMAP_MAYMOVE)) { warn("can't remap here and MREMAP_MAYMOVE flag not set\n"); return -ENOMEM; } else { - process->pTable->remap(start, old_length, process->mmap_end); - warn("mremapping to totally new vaddr %08p-%08p, adding %d\n", - process->mmap_end, process->mmap_end + new_length, new_length); - start = process->mmap_end; + 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(start + old_length, - new_length - old_length); - process->mmap_end += new_length; - warn("returning %08p as start\n", start); - return start; + 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 start; + return use_provided_address ? provided_address : start; } } @@ -847,6 +906,43 @@ stat64Func(SyscallDesc *desc, int callnum, LiveProcess *process, } +/// Target fstatat64() handler. +template +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(tc->getMemProxy(), bufPtr, &hostBuf); + + return 0; +} + + /// Target fstat64() handler. template SyscallReturn @@ -1059,7 +1155,7 @@ writevFunc(SyscallDesc *desc, int callnum, LiveProcess *process, if (result < 0) return -errno; - return 0; + return result; } @@ -1080,7 +1176,7 @@ mmapFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc) 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); + int offset = p->getSyscallArg(tc, index); if (length > 0x100000000ULL) warn("mmap length argument %#x is unreasonably large.\n", length); @@ -1101,11 +1197,13 @@ mmapFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc) } } - 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; } @@ -1123,10 +1221,8 @@ mmapFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc) // whether we clobber them or not depends on whether the caller // specified MAP_FIXED if (flags & OS::TGT_MAP_FIXED) { - // MAP_FIXED specified: clobber existing mappings - warn("mmap: MAP_FIXED at 0x%x overwrites existing mappings\n", - start); - clobber = true; + // 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);