syscall_emul.hh revision 11385
112027Sjungma@eit.uni-kl.de/* 212027Sjungma@eit.uni-kl.de * Copyright (c) 2012-2013, 2015 ARM Limited 312027Sjungma@eit.uni-kl.de * Copyright (c) 2015 Advanced Micro Devices, Inc. 412027Sjungma@eit.uni-kl.de * All rights reserved 512027Sjungma@eit.uni-kl.de * 612027Sjungma@eit.uni-kl.de * The license below extends only to copyright in the software and shall 712027Sjungma@eit.uni-kl.de * not be construed as granting a license to any other intellectual 812027Sjungma@eit.uni-kl.de * property including but not limited to intellectual property relating 912027Sjungma@eit.uni-kl.de * to a hardware implementation of the functionality of the software 1012027Sjungma@eit.uni-kl.de * licensed hereunder. You may use the software subject to the license 1112027Sjungma@eit.uni-kl.de * terms below provided that you ensure that this notice is replicated 1212027Sjungma@eit.uni-kl.de * unmodified and in its entirety in all distributions of the software, 1312027Sjungma@eit.uni-kl.de * modified or unmodified, in source code or in binary form. 1412027Sjungma@eit.uni-kl.de * 1512027Sjungma@eit.uni-kl.de * Copyright (c) 2003-2005 The Regents of The University of Michigan 1612027Sjungma@eit.uni-kl.de * All rights reserved. 1712027Sjungma@eit.uni-kl.de * 1812027Sjungma@eit.uni-kl.de * Redistribution and use in source and binary forms, with or without 1912027Sjungma@eit.uni-kl.de * modification, are permitted provided that the following conditions are 2012027Sjungma@eit.uni-kl.de * met: redistributions of source code must retain the above copyright 2112027Sjungma@eit.uni-kl.de * notice, this list of conditions and the following disclaimer; 2212027Sjungma@eit.uni-kl.de * redistributions in binary form must reproduce the above copyright 2312027Sjungma@eit.uni-kl.de * notice, this list of conditions and the following disclaimer in the 2412027Sjungma@eit.uni-kl.de * documentation and/or other materials provided with the distribution; 2512027Sjungma@eit.uni-kl.de * neither the name of the copyright holders nor the names of its 2612027Sjungma@eit.uni-kl.de * contributors may be used to endorse or promote products derived from 2712027Sjungma@eit.uni-kl.de * this software without specific prior written permission. 2812027Sjungma@eit.uni-kl.de * 2912027Sjungma@eit.uni-kl.de * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 3012027Sjungma@eit.uni-kl.de * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 3112027Sjungma@eit.uni-kl.de * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 3212027Sjungma@eit.uni-kl.de * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 3312027Sjungma@eit.uni-kl.de * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 3412027Sjungma@eit.uni-kl.de * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 3512027Sjungma@eit.uni-kl.de * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 3612027Sjungma@eit.uni-kl.de * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 3712027Sjungma@eit.uni-kl.de * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 3812027Sjungma@eit.uni-kl.de * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 3912027Sjungma@eit.uni-kl.de * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 4012027Sjungma@eit.uni-kl.de * 4112027Sjungma@eit.uni-kl.de * Authors: Steve Reinhardt 4212027Sjungma@eit.uni-kl.de * Kevin Lim 4312027Sjungma@eit.uni-kl.de */ 4412027Sjungma@eit.uni-kl.de 4512027Sjungma@eit.uni-kl.de#ifndef __SIM_SYSCALL_EMUL_HH__ 4612027Sjungma@eit.uni-kl.de#define __SIM_SYSCALL_EMUL_HH__ 4712027Sjungma@eit.uni-kl.de 4812027Sjungma@eit.uni-kl.de#define NO_STAT64 (defined(__APPLE__) || defined(__OpenBSD__) || \ 4912027Sjungma@eit.uni-kl.de defined(__FreeBSD__) || defined(__CYGWIN__) || \ 5012027Sjungma@eit.uni-kl.de defined(__NetBSD__)) 5112027Sjungma@eit.uni-kl.de 5212027Sjungma@eit.uni-kl.de/// 5312027Sjungma@eit.uni-kl.de/// @file syscall_emul.hh 5412027Sjungma@eit.uni-kl.de/// 5512027Sjungma@eit.uni-kl.de/// This file defines objects used to emulate syscalls from the target 5612027Sjungma@eit.uni-kl.de/// application on the host machine. 5712027Sjungma@eit.uni-kl.de 5812027Sjungma@eit.uni-kl.de#ifdef __CYGWIN32__ 5912027Sjungma@eit.uni-kl.de#include <sys/fcntl.h> // for O_BINARY 6012027Sjungma@eit.uni-kl.de#endif 6112027Sjungma@eit.uni-kl.de#include <sys/mman.h> 6212027Sjungma@eit.uni-kl.de#include <sys/stat.h> 6312027Sjungma@eit.uni-kl.de#include <sys/time.h> 6412027Sjungma@eit.uni-kl.de#include <sys/uio.h> 6512027Sjungma@eit.uni-kl.de#include <fcntl.h> 6612027Sjungma@eit.uni-kl.de 6712027Sjungma@eit.uni-kl.de#include <cerrno> 6812027Sjungma@eit.uni-kl.de#include <string> 6912027Sjungma@eit.uni-kl.de 7012027Sjungma@eit.uni-kl.de#include "base/chunk_generator.hh" 7112027Sjungma@eit.uni-kl.de#include "base/intmath.hh" // for RoundUp 7212027Sjungma@eit.uni-kl.de#include "base/misc.hh" 7312027Sjungma@eit.uni-kl.de#include "base/trace.hh" 7412027Sjungma@eit.uni-kl.de#include "base/types.hh" 7512027Sjungma@eit.uni-kl.de#include "config/the_isa.hh" 7612027Sjungma@eit.uni-kl.de#include "cpu/base.hh" 7712027Sjungma@eit.uni-kl.de#include "cpu/thread_context.hh" 7812027Sjungma@eit.uni-kl.de#include "debug/SyscallBase.hh" 7912027Sjungma@eit.uni-kl.de#include "debug/SyscallVerbose.hh" 8012027Sjungma@eit.uni-kl.de#include "mem/page_table.hh" 8112027Sjungma@eit.uni-kl.de#include "sim/byteswap.hh" 8212027Sjungma@eit.uni-kl.de#include "sim/emul_driver.hh" 8312027Sjungma@eit.uni-kl.de#include "sim/process.hh" 8412027Sjungma@eit.uni-kl.de#include "sim/syscall_emul_buf.hh" 8512027Sjungma@eit.uni-kl.de#include "sim/syscallreturn.hh" 8612027Sjungma@eit.uni-kl.de#include "sim/system.hh" 8712027Sjungma@eit.uni-kl.de 8812027Sjungma@eit.uni-kl.de// This wrapper macro helps out with readability a bit. FLAGEXT specifies 8912027Sjungma@eit.uni-kl.de// the verbosity and FMT is the message to be appended to the syscall 9012027Sjungma@eit.uni-kl.de// header information. The syscall header information contains the cpuid 9112027Sjungma@eit.uni-kl.de// and thread id. 9212027Sjungma@eit.uni-kl.de#define DPRINTF_SYSCALL(FLAGEXT, FMT, ...) \ 9312027Sjungma@eit.uni-kl.de DPRINTFS(Syscall##FLAGEXT, tc->getCpuPtr(), "T%d : syscall " FMT, \ 9412027Sjungma@eit.uni-kl.de tc->threadId(), __VA_ARGS__) 9512027Sjungma@eit.uni-kl.de 9612027Sjungma@eit.uni-kl.de/// 9712027Sjungma@eit.uni-kl.de/// System call descriptor. 9812027Sjungma@eit.uni-kl.de/// 9912027Sjungma@eit.uni-kl.declass SyscallDesc { 10012027Sjungma@eit.uni-kl.de 10112027Sjungma@eit.uni-kl.de public: 10212027Sjungma@eit.uni-kl.de 10312027Sjungma@eit.uni-kl.de /// Typedef for target syscall handler functions. 10412027Sjungma@eit.uni-kl.de typedef SyscallReturn (*FuncPtr)(SyscallDesc *, int num, 10512027Sjungma@eit.uni-kl.de LiveProcess *, ThreadContext *); 10612027Sjungma@eit.uni-kl.de 10712027Sjungma@eit.uni-kl.de const char *name; //!< Syscall name (e.g., "open"). 10812027Sjungma@eit.uni-kl.de FuncPtr funcPtr; //!< Pointer to emulation function. 10912027Sjungma@eit.uni-kl.de int flags; //!< Flags (see Flags enum). 11012027Sjungma@eit.uni-kl.de bool warned; //!< Have we warned about unimplemented syscall? 11112027Sjungma@eit.uni-kl.de 11212027Sjungma@eit.uni-kl.de /// Flag values for controlling syscall behavior. 11312027Sjungma@eit.uni-kl.de enum Flags { 11412027Sjungma@eit.uni-kl.de /// Don't set return regs according to funcPtr return value. 11512027Sjungma@eit.uni-kl.de /// Used for syscalls with non-standard return conventions 11612027Sjungma@eit.uni-kl.de /// that explicitly set the ThreadContext regs (e.g., 11712027Sjungma@eit.uni-kl.de /// sigreturn). 11812027Sjungma@eit.uni-kl.de SuppressReturnValue = 1, 11912027Sjungma@eit.uni-kl.de WarnOnce = 2 12012027Sjungma@eit.uni-kl.de }; 12112027Sjungma@eit.uni-kl.de 12212027Sjungma@eit.uni-kl.de /// Constructor. 12312027Sjungma@eit.uni-kl.de SyscallDesc(const char *_name, FuncPtr _funcPtr, int _flags = 0) 12412027Sjungma@eit.uni-kl.de : name(_name), funcPtr(_funcPtr), flags(_flags), warned(false) 12512027Sjungma@eit.uni-kl.de { 12612027Sjungma@eit.uni-kl.de } 12712027Sjungma@eit.uni-kl.de 12812027Sjungma@eit.uni-kl.de /// Emulate the syscall. Public interface for calling through funcPtr. 12912027Sjungma@eit.uni-kl.de void doSyscall(int callnum, LiveProcess *proc, ThreadContext *tc); 13012027Sjungma@eit.uni-kl.de 13112027Sjungma@eit.uni-kl.de /// Is the WarnOnce flag set? 13212027Sjungma@eit.uni-kl.de bool warnOnce() const { return (flags & WarnOnce); } 13312027Sjungma@eit.uni-kl.de}; 13412027Sjungma@eit.uni-kl.de 13512027Sjungma@eit.uni-kl.de 13612027Sjungma@eit.uni-kl.de////////////////////////////////////////////////////////////////////// 13712027Sjungma@eit.uni-kl.de// 13812027Sjungma@eit.uni-kl.de// The following emulation functions are generic enough that they 13912027Sjungma@eit.uni-kl.de// don't need to be recompiled for different emulated OS's. They are 14012027Sjungma@eit.uni-kl.de// defined in sim/syscall_emul.cc. 14112027Sjungma@eit.uni-kl.de// 14212027Sjungma@eit.uni-kl.de////////////////////////////////////////////////////////////////////// 14312027Sjungma@eit.uni-kl.de 14412027Sjungma@eit.uni-kl.de 14512027Sjungma@eit.uni-kl.de/// Handler for unimplemented syscalls that we haven't thought about. 14612027Sjungma@eit.uni-kl.deSyscallReturn unimplementedFunc(SyscallDesc *desc, int num, 14712027Sjungma@eit.uni-kl.de LiveProcess *p, ThreadContext *tc); 14812027Sjungma@eit.uni-kl.de 14912027Sjungma@eit.uni-kl.de/// Handler for unimplemented syscalls that we never intend to 15012027Sjungma@eit.uni-kl.de/// implement (signal handling, etc.) and should not affect the correct 15112027Sjungma@eit.uni-kl.de/// behavior of the program. Print a warning only if the appropriate 15212027Sjungma@eit.uni-kl.de/// trace flag is enabled. Return success to the target program. 15312027Sjungma@eit.uni-kl.deSyscallReturn ignoreFunc(SyscallDesc *desc, int num, 15412027Sjungma@eit.uni-kl.de LiveProcess *p, ThreadContext *tc); 15512027Sjungma@eit.uni-kl.de 156/// Target exit() handler: terminate current context. 157SyscallReturn exitFunc(SyscallDesc *desc, int num, 158 LiveProcess *p, ThreadContext *tc); 159 160/// Target exit_group() handler: terminate simulation. (exit all threads) 161SyscallReturn exitGroupFunc(SyscallDesc *desc, int num, 162 LiveProcess *p, ThreadContext *tc); 163 164/// Target getpagesize() handler. 165SyscallReturn getpagesizeFunc(SyscallDesc *desc, int num, 166 LiveProcess *p, ThreadContext *tc); 167 168/// Target brk() handler: set brk address. 169SyscallReturn brkFunc(SyscallDesc *desc, int num, 170 LiveProcess *p, ThreadContext *tc); 171 172/// Target close() handler. 173SyscallReturn closeFunc(SyscallDesc *desc, int num, 174 LiveProcess *p, ThreadContext *tc); 175 176/// Target read() handler. 177SyscallReturn readFunc(SyscallDesc *desc, int num, 178 LiveProcess *p, ThreadContext *tc); 179 180/// Target write() handler. 181SyscallReturn writeFunc(SyscallDesc *desc, int num, 182 LiveProcess *p, ThreadContext *tc); 183 184/// Target lseek() handler. 185SyscallReturn lseekFunc(SyscallDesc *desc, int num, 186 LiveProcess *p, ThreadContext *tc); 187 188/// Target _llseek() handler. 189SyscallReturn _llseekFunc(SyscallDesc *desc, int num, 190 LiveProcess *p, ThreadContext *tc); 191 192/// Target munmap() handler. 193SyscallReturn munmapFunc(SyscallDesc *desc, int num, 194 LiveProcess *p, ThreadContext *tc); 195 196/// Target gethostname() handler. 197SyscallReturn gethostnameFunc(SyscallDesc *desc, int num, 198 LiveProcess *p, ThreadContext *tc); 199 200/// Target getcwd() handler. 201SyscallReturn getcwdFunc(SyscallDesc *desc, int num, 202 LiveProcess *p, ThreadContext *tc); 203 204/// Target readlink() handler. 205SyscallReturn readlinkFunc(SyscallDesc *desc, int num, 206 LiveProcess *p, ThreadContext *tc, 207 int index = 0); 208SyscallReturn readlinkFunc(SyscallDesc *desc, int num, 209 LiveProcess *p, ThreadContext *tc); 210 211/// Target unlink() handler. 212SyscallReturn unlinkHelper(SyscallDesc *desc, int num, 213 LiveProcess *p, ThreadContext *tc, 214 int index); 215SyscallReturn unlinkFunc(SyscallDesc *desc, int num, 216 LiveProcess *p, ThreadContext *tc); 217 218/// Target mkdir() handler. 219SyscallReturn mkdirFunc(SyscallDesc *desc, int num, 220 LiveProcess *p, ThreadContext *tc); 221 222/// Target rename() handler. 223SyscallReturn renameFunc(SyscallDesc *desc, int num, 224 LiveProcess *p, ThreadContext *tc); 225 226 227/// Target truncate() handler. 228SyscallReturn truncateFunc(SyscallDesc *desc, int num, 229 LiveProcess *p, ThreadContext *tc); 230 231 232/// Target ftruncate() handler. 233SyscallReturn ftruncateFunc(SyscallDesc *desc, int num, 234 LiveProcess *p, ThreadContext *tc); 235 236 237/// Target truncate64() handler. 238SyscallReturn truncate64Func(SyscallDesc *desc, int num, 239 LiveProcess *p, ThreadContext *tc); 240 241/// Target ftruncate64() handler. 242SyscallReturn ftruncate64Func(SyscallDesc *desc, int num, 243 LiveProcess *p, ThreadContext *tc); 244 245 246/// Target umask() handler. 247SyscallReturn umaskFunc(SyscallDesc *desc, int num, 248 LiveProcess *p, ThreadContext *tc); 249 250 251/// Target chown() handler. 252SyscallReturn chownFunc(SyscallDesc *desc, int num, 253 LiveProcess *p, ThreadContext *tc); 254 255 256/// Target fchown() handler. 257SyscallReturn fchownFunc(SyscallDesc *desc, int num, 258 LiveProcess *p, ThreadContext *tc); 259 260/// Target dup() handler. 261SyscallReturn dupFunc(SyscallDesc *desc, int num, 262 LiveProcess *process, ThreadContext *tc); 263 264/// Target fnctl() handler. 265SyscallReturn fcntlFunc(SyscallDesc *desc, int num, 266 LiveProcess *process, ThreadContext *tc); 267 268/// Target fcntl64() handler. 269SyscallReturn fcntl64Func(SyscallDesc *desc, int num, 270 LiveProcess *process, ThreadContext *tc); 271 272/// Target setuid() handler. 273SyscallReturn setuidFunc(SyscallDesc *desc, int num, 274 LiveProcess *p, ThreadContext *tc); 275 276/// Target getpid() handler. 277SyscallReturn getpidFunc(SyscallDesc *desc, int num, 278 LiveProcess *p, ThreadContext *tc); 279 280/// Target getuid() handler. 281SyscallReturn getuidFunc(SyscallDesc *desc, int num, 282 LiveProcess *p, ThreadContext *tc); 283 284/// Target getgid() handler. 285SyscallReturn getgidFunc(SyscallDesc *desc, int num, 286 LiveProcess *p, ThreadContext *tc); 287 288/// Target getppid() handler. 289SyscallReturn getppidFunc(SyscallDesc *desc, int num, 290 LiveProcess *p, ThreadContext *tc); 291 292/// Target geteuid() handler. 293SyscallReturn geteuidFunc(SyscallDesc *desc, int num, 294 LiveProcess *p, ThreadContext *tc); 295 296/// Target getegid() handler. 297SyscallReturn getegidFunc(SyscallDesc *desc, int num, 298 LiveProcess *p, ThreadContext *tc); 299 300/// Target clone() handler. 301SyscallReturn cloneFunc(SyscallDesc *desc, int num, 302 LiveProcess *p, ThreadContext *tc); 303 304/// Target access() handler 305SyscallReturn accessFunc(SyscallDesc *desc, int num, 306 LiveProcess *p, ThreadContext *tc); 307SyscallReturn accessFunc(SyscallDesc *desc, int num, 308 LiveProcess *p, ThreadContext *tc, 309 int index); 310 311/// Futex system call 312/// Implemented by Daniel Sanchez 313/// Used by printf's in multi-threaded apps 314template <class OS> 315SyscallReturn 316futexFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 317 ThreadContext *tc) 318{ 319 int index_uaddr = 0; 320 int index_op = 1; 321 int index_val = 2; 322 int index_timeout = 3; 323 324 uint64_t uaddr = process->getSyscallArg(tc, index_uaddr); 325 int op = process->getSyscallArg(tc, index_op); 326 int val = process->getSyscallArg(tc, index_val); 327 uint64_t timeout = process->getSyscallArg(tc, index_timeout); 328 329 std::map<uint64_t, std::list<ThreadContext *> * > 330 &futex_map = tc->getSystemPtr()->futexMap; 331 332 DPRINTF(SyscallVerbose, "In sys_futex: Address=%llx, op=%d, val=%d\n", 333 uaddr, op, val); 334 335 op &= ~OS::TGT_FUTEX_PRIVATE_FLAG; 336 337 if (op == OS::TGT_FUTEX_WAIT) { 338 if (timeout != 0) { 339 warn("sys_futex: FUTEX_WAIT with non-null timeout unimplemented;" 340 "we'll wait indefinitely"); 341 } 342 343 uint8_t *buf = new uint8_t[sizeof(int)]; 344 tc->getMemProxy().readBlob((Addr)uaddr, buf, (int)sizeof(int)); 345 int mem_val = *((int *)buf); 346 delete[] buf; 347 348 if (val != mem_val) { 349 DPRINTF(SyscallVerbose, "sys_futex: FUTEX_WAKE, read: %d, " 350 "expected: %d\n", mem_val, val); 351 return -OS::TGT_EWOULDBLOCK; 352 } 353 354 // Queue the thread context 355 std::list<ThreadContext *> * tcWaitList; 356 if (futex_map.count(uaddr)) { 357 tcWaitList = futex_map.find(uaddr)->second; 358 } else { 359 tcWaitList = new std::list<ThreadContext *>(); 360 futex_map.insert(std::pair< uint64_t, 361 std::list<ThreadContext *> * >(uaddr, tcWaitList)); 362 } 363 tcWaitList->push_back(tc); 364 DPRINTF(SyscallVerbose, "sys_futex: FUTEX_WAIT, suspending calling " 365 "thread context\n"); 366 tc->suspend(); 367 return 0; 368 } else if (op == OS::TGT_FUTEX_WAKE){ 369 int wokenUp = 0; 370 std::list<ThreadContext *> * tcWaitList; 371 if (futex_map.count(uaddr)) { 372 tcWaitList = futex_map.find(uaddr)->second; 373 while (tcWaitList->size() > 0 && wokenUp < val) { 374 tcWaitList->front()->activate(); 375 tcWaitList->pop_front(); 376 wokenUp++; 377 } 378 if (tcWaitList->empty()) { 379 futex_map.erase(uaddr); 380 delete tcWaitList; 381 } 382 } 383 DPRINTF(SyscallVerbose, "sys_futex: FUTEX_WAKE, activated %d waiting " 384 "thread contexts\n", wokenUp); 385 return wokenUp; 386 } else { 387 warn("sys_futex: op %d is not implemented, just returning...", op); 388 return 0; 389 } 390 391} 392 393 394/// Pseudo Funcs - These functions use a different return convension, 395/// returning a second value in a register other than the normal return register 396SyscallReturn pipePseudoFunc(SyscallDesc *desc, int num, 397 LiveProcess *process, ThreadContext *tc); 398 399/// Target getpidPseudo() handler. 400SyscallReturn getpidPseudoFunc(SyscallDesc *desc, int num, 401 LiveProcess *p, ThreadContext *tc); 402 403/// Target getuidPseudo() handler. 404SyscallReturn getuidPseudoFunc(SyscallDesc *desc, int num, 405 LiveProcess *p, ThreadContext *tc); 406 407/// Target getgidPseudo() handler. 408SyscallReturn getgidPseudoFunc(SyscallDesc *desc, int num, 409 LiveProcess *p, ThreadContext *tc); 410 411 412/// A readable name for 1,000,000, for converting microseconds to seconds. 413const int one_million = 1000000; 414/// A readable name for 1,000,000,000, for converting nanoseconds to seconds. 415const int one_billion = 1000000000; 416 417/// Approximate seconds since the epoch (1/1/1970). About a billion, 418/// by my reckoning. We want to keep this a constant (not use the 419/// real-world time) to keep simulations repeatable. 420const unsigned seconds_since_epoch = 1000000000; 421 422/// Helper function to convert current elapsed time to seconds and 423/// microseconds. 424template <class T1, class T2> 425void 426getElapsedTimeMicro(T1 &sec, T2 &usec) 427{ 428 uint64_t elapsed_usecs = curTick() / SimClock::Int::us; 429 sec = elapsed_usecs / one_million; 430 usec = elapsed_usecs % one_million; 431} 432 433/// Helper function to convert current elapsed time to seconds and 434/// nanoseconds. 435template <class T1, class T2> 436void 437getElapsedTimeNano(T1 &sec, T2 &nsec) 438{ 439 uint64_t elapsed_nsecs = curTick() / SimClock::Int::ns; 440 sec = elapsed_nsecs / one_billion; 441 nsec = elapsed_nsecs % one_billion; 442} 443 444////////////////////////////////////////////////////////////////////// 445// 446// The following emulation functions are generic, but need to be 447// templated to account for differences in types, constants, etc. 448// 449////////////////////////////////////////////////////////////////////// 450 451#if NO_STAT64 452 typedef struct stat hst_stat; 453 typedef struct stat hst_stat64; 454#else 455 typedef struct stat hst_stat; 456 typedef struct stat64 hst_stat64; 457#endif 458 459//// Helper function to convert a host stat buffer to a target stat 460//// buffer. Also copies the target buffer out to the simulated 461//// memory space. Used by stat(), fstat(), and lstat(). 462 463template <typename target_stat, typename host_stat> 464static void 465convertStatBuf(target_stat &tgt, host_stat *host, bool fakeTTY = false) 466{ 467 using namespace TheISA; 468 469 if (fakeTTY) 470 tgt->st_dev = 0xA; 471 else 472 tgt->st_dev = host->st_dev; 473 tgt->st_dev = TheISA::htog(tgt->st_dev); 474 tgt->st_ino = host->st_ino; 475 tgt->st_ino = TheISA::htog(tgt->st_ino); 476 tgt->st_mode = host->st_mode; 477 if (fakeTTY) { 478 // Claim to be a character device 479 tgt->st_mode &= ~S_IFMT; // Clear S_IFMT 480 tgt->st_mode |= S_IFCHR; // Set S_IFCHR 481 } 482 tgt->st_mode = TheISA::htog(tgt->st_mode); 483 tgt->st_nlink = host->st_nlink; 484 tgt->st_nlink = TheISA::htog(tgt->st_nlink); 485 tgt->st_uid = host->st_uid; 486 tgt->st_uid = TheISA::htog(tgt->st_uid); 487 tgt->st_gid = host->st_gid; 488 tgt->st_gid = TheISA::htog(tgt->st_gid); 489 if (fakeTTY) 490 tgt->st_rdev = 0x880d; 491 else 492 tgt->st_rdev = host->st_rdev; 493 tgt->st_rdev = TheISA::htog(tgt->st_rdev); 494 tgt->st_size = host->st_size; 495 tgt->st_size = TheISA::htog(tgt->st_size); 496 tgt->st_atimeX = host->st_atime; 497 tgt->st_atimeX = TheISA::htog(tgt->st_atimeX); 498 tgt->st_mtimeX = host->st_mtime; 499 tgt->st_mtimeX = TheISA::htog(tgt->st_mtimeX); 500 tgt->st_ctimeX = host->st_ctime; 501 tgt->st_ctimeX = TheISA::htog(tgt->st_ctimeX); 502 // Force the block size to be 8k. This helps to ensure buffered io works 503 // consistently across different hosts. 504 tgt->st_blksize = 0x2000; 505 tgt->st_blksize = TheISA::htog(tgt->st_blksize); 506 tgt->st_blocks = host->st_blocks; 507 tgt->st_blocks = TheISA::htog(tgt->st_blocks); 508} 509 510// Same for stat64 511 512template <typename target_stat, typename host_stat64> 513static void 514convertStat64Buf(target_stat &tgt, host_stat64 *host, bool fakeTTY = false) 515{ 516 using namespace TheISA; 517 518 convertStatBuf<target_stat, host_stat64>(tgt, host, fakeTTY); 519#if defined(STAT_HAVE_NSEC) 520 tgt->st_atime_nsec = host->st_atime_nsec; 521 tgt->st_atime_nsec = TheISA::htog(tgt->st_atime_nsec); 522 tgt->st_mtime_nsec = host->st_mtime_nsec; 523 tgt->st_mtime_nsec = TheISA::htog(tgt->st_mtime_nsec); 524 tgt->st_ctime_nsec = host->st_ctime_nsec; 525 tgt->st_ctime_nsec = TheISA::htog(tgt->st_ctime_nsec); 526#else 527 tgt->st_atime_nsec = 0; 528 tgt->st_mtime_nsec = 0; 529 tgt->st_ctime_nsec = 0; 530#endif 531} 532 533//Here are a couple convenience functions 534template<class OS> 535static void 536copyOutStatBuf(SETranslatingPortProxy &mem, Addr addr, 537 hst_stat *host, bool fakeTTY = false) 538{ 539 typedef TypedBufferArg<typename OS::tgt_stat> tgt_stat_buf; 540 tgt_stat_buf tgt(addr); 541 convertStatBuf<tgt_stat_buf, hst_stat>(tgt, host, fakeTTY); 542 tgt.copyOut(mem); 543} 544 545template<class OS> 546static void 547copyOutStat64Buf(SETranslatingPortProxy &mem, Addr addr, 548 hst_stat64 *host, bool fakeTTY = false) 549{ 550 typedef TypedBufferArg<typename OS::tgt_stat64> tgt_stat_buf; 551 tgt_stat_buf tgt(addr); 552 convertStat64Buf<tgt_stat_buf, hst_stat64>(tgt, host, fakeTTY); 553 tgt.copyOut(mem); 554} 555 556/// Target ioctl() handler. For the most part, programs call ioctl() 557/// only to find out if their stdout is a tty, to determine whether to 558/// do line or block buffering. We always claim that output fds are 559/// not TTYs to provide repeatable results. 560template <class OS> 561SyscallReturn 562ioctlFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 563 ThreadContext *tc) 564{ 565 int index = 0; 566 int tgt_fd = process->getSyscallArg(tc, index); 567 unsigned req = process->getSyscallArg(tc, index); 568 569 DPRINTF(SyscallVerbose, "ioctl(%d, 0x%x, ...)\n", tgt_fd, req); 570 571 FDEntry *fde = process->getFDEntry(tgt_fd); 572 573 if (fde == NULL) { 574 // doesn't map to any simulator fd: not a valid target fd 575 return -EBADF; 576 } 577 578 if (fde->driver != NULL) { 579 return fde->driver->ioctl(process, tc, req); 580 } 581 582 if (OS::isTtyReq(req)) { 583 return -ENOTTY; 584 } 585 586 warn("Unsupported ioctl call: ioctl(%d, 0x%x, ...) @ \n", 587 tgt_fd, req, tc->pcState()); 588 return -ENOTTY; 589} 590 591template <class OS> 592static SyscallReturn 593openFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 594 ThreadContext *tc, int index) 595{ 596 std::string path; 597 598 if (!tc->getMemProxy().tryReadString(path, 599 process->getSyscallArg(tc, index))) 600 return -EFAULT; 601 602 int tgtFlags = process->getSyscallArg(tc, index); 603 int mode = process->getSyscallArg(tc, index); 604 int hostFlags = 0; 605 606 // translate open flags 607 for (int i = 0; i < OS::NUM_OPEN_FLAGS; i++) { 608 if (tgtFlags & OS::openFlagTable[i].tgtFlag) { 609 tgtFlags &= ~OS::openFlagTable[i].tgtFlag; 610 hostFlags |= OS::openFlagTable[i].hostFlag; 611 } 612 } 613 614 // any target flags left? 615 if (tgtFlags != 0) 616 warn("Syscall: open: cannot decode flags 0x%x", tgtFlags); 617 618#ifdef __CYGWIN32__ 619 hostFlags |= O_BINARY; 620#endif 621 622 // Adjust path for current working directory 623 path = process->fullPath(path); 624 625 DPRINTF(SyscallVerbose, "opening file %s\n", path.c_str()); 626 627 if (startswith(path, "/dev/")) { 628 std::string filename = path.substr(strlen("/dev/")); 629 if (filename == "sysdev0") { 630 // This is a memory-mapped high-resolution timer device on Alpha. 631 // We don't support it, so just punt. 632 warn("Ignoring open(%s, ...)\n", path); 633 return -ENOENT; 634 } 635 636 EmulatedDriver *drv = process->findDriver(filename); 637 if (drv != NULL) { 638 // the driver's open method will allocate a fd from the 639 // process if necessary. 640 return drv->open(process, tc, mode, hostFlags); 641 } 642 643 // fall through here for pass through to host devices, such as 644 // /dev/zero 645 } 646 647 int fd; 648 int local_errno; 649 if (startswith(path, "/proc/") || startswith(path, "/system/") || 650 startswith(path, "/platform/") || startswith(path, "/sys/")) { 651 // It's a proc/sys entry and requires special handling 652 fd = OS::openSpecialFile(path, process, tc); 653 local_errno = ENOENT; 654 } else { 655 // open the file 656 fd = open(path.c_str(), hostFlags, mode); 657 local_errno = errno; 658 } 659 660 if (fd == -1) 661 return -local_errno; 662 663 return process->allocFD(fd, path.c_str(), hostFlags, mode, false); 664} 665 666/// Target open() handler. 667template <class OS> 668SyscallReturn 669openFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 670 ThreadContext *tc) 671{ 672 return openFunc<OS>(desc, callnum, process, tc, 0); 673} 674 675/// Target openat() handler. 676template <class OS> 677SyscallReturn 678openatFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 679 ThreadContext *tc) 680{ 681 int index = 0; 682 int dirfd = process->getSyscallArg(tc, index); 683 if (dirfd != OS::TGT_AT_FDCWD) 684 warn("openat: first argument not AT_FDCWD; unlikely to work"); 685 return openFunc<OS>(desc, callnum, process, tc, 1); 686} 687 688/// Target unlinkat() handler. 689template <class OS> 690SyscallReturn 691unlinkatFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 692 ThreadContext *tc) 693{ 694 int index = 0; 695 int dirfd = process->getSyscallArg(tc, index); 696 if (dirfd != OS::TGT_AT_FDCWD) 697 warn("unlinkat: first argument not AT_FDCWD; unlikely to work"); 698 699 return unlinkHelper(desc, callnum, process, tc, 1); 700} 701 702/// Target facessat() handler 703template <class OS> 704SyscallReturn 705faccessatFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 706 ThreadContext *tc) 707{ 708 int index = 0; 709 int dirfd = process->getSyscallArg(tc, index); 710 if (dirfd != OS::TGT_AT_FDCWD) 711 warn("faccessat: first argument not AT_FDCWD; unlikely to work"); 712 return accessFunc(desc, callnum, process, tc, 1); 713} 714 715/// Target readlinkat() handler 716template <class OS> 717SyscallReturn 718readlinkatFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 719 ThreadContext *tc) 720{ 721 int index = 0; 722 int dirfd = process->getSyscallArg(tc, index); 723 if (dirfd != OS::TGT_AT_FDCWD) 724 warn("openat: first argument not AT_FDCWD; unlikely to work"); 725 return readlinkFunc(desc, callnum, process, tc, 1); 726} 727 728/// Target renameat() handler. 729template <class OS> 730SyscallReturn 731renameatFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 732 ThreadContext *tc) 733{ 734 int index = 0; 735 736 int olddirfd = process->getSyscallArg(tc, index); 737 if (olddirfd != OS::TGT_AT_FDCWD) 738 warn("renameat: first argument not AT_FDCWD; unlikely to work"); 739 740 std::string old_name; 741 742 if (!tc->getMemProxy().tryReadString(old_name, 743 process->getSyscallArg(tc, index))) 744 return -EFAULT; 745 746 int newdirfd = process->getSyscallArg(tc, index); 747 if (newdirfd != OS::TGT_AT_FDCWD) 748 warn("renameat: third argument not AT_FDCWD; unlikely to work"); 749 750 std::string new_name; 751 752 if (!tc->getMemProxy().tryReadString(new_name, 753 process->getSyscallArg(tc, index))) 754 return -EFAULT; 755 756 // Adjust path for current working directory 757 old_name = process->fullPath(old_name); 758 new_name = process->fullPath(new_name); 759 760 int result = rename(old_name.c_str(), new_name.c_str()); 761 return (result == -1) ? -errno : result; 762} 763 764/// Target sysinfo() handler. 765template <class OS> 766SyscallReturn 767sysinfoFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 768 ThreadContext *tc) 769{ 770 771 int index = 0; 772 TypedBufferArg<typename OS::tgt_sysinfo> 773 sysinfo(process->getSyscallArg(tc, index)); 774 775 sysinfo->uptime=seconds_since_epoch; 776 sysinfo->totalram=process->system->memSize(); 777 778 sysinfo.copyOut(tc->getMemProxy()); 779 780 return 0; 781} 782 783/// Target chmod() handler. 784template <class OS> 785SyscallReturn 786chmodFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 787 ThreadContext *tc) 788{ 789 std::string path; 790 791 int index = 0; 792 if (!tc->getMemProxy().tryReadString(path, 793 process->getSyscallArg(tc, index))) { 794 return -EFAULT; 795 } 796 797 uint32_t mode = process->getSyscallArg(tc, index); 798 mode_t hostMode = 0; 799 800 // XXX translate mode flags via OS::something??? 801 hostMode = mode; 802 803 // Adjust path for current working directory 804 path = process->fullPath(path); 805 806 // do the chmod 807 int result = chmod(path.c_str(), hostMode); 808 if (result < 0) 809 return -errno; 810 811 return 0; 812} 813 814 815/// Target fchmod() handler. 816template <class OS> 817SyscallReturn 818fchmodFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 819 ThreadContext *tc) 820{ 821 int index = 0; 822 int tgt_fd = process->getSyscallArg(tc, index); 823 uint32_t mode = process->getSyscallArg(tc, index); 824 825 int sim_fd = process->getSimFD(tgt_fd); 826 if (sim_fd < 0) 827 return -EBADF; 828 829 mode_t hostMode = 0; 830 831 // XXX translate mode flags via OS::someting??? 832 hostMode = mode; 833 834 // do the fchmod 835 int result = fchmod(sim_fd, hostMode); 836 if (result < 0) 837 return -errno; 838 839 return 0; 840} 841 842/// Target mremap() handler. 843template <class OS> 844SyscallReturn 845mremapFunc(SyscallDesc *desc, int callnum, LiveProcess *process, ThreadContext *tc) 846{ 847 int index = 0; 848 Addr start = process->getSyscallArg(tc, index); 849 uint64_t old_length = process->getSyscallArg(tc, index); 850 uint64_t new_length = process->getSyscallArg(tc, index); 851 uint64_t flags = process->getSyscallArg(tc, index); 852 uint64_t provided_address = 0; 853 bool use_provided_address = flags & OS::TGT_MREMAP_FIXED; 854 855 if (use_provided_address) 856 provided_address = process->getSyscallArg(tc, index); 857 858 if ((start % TheISA::PageBytes != 0) || 859 (provided_address % TheISA::PageBytes != 0)) { 860 warn("mremap failing: arguments not page aligned"); 861 return -EINVAL; 862 } 863 864 new_length = roundUp(new_length, TheISA::PageBytes); 865 866 if (new_length > old_length) { 867 if ((start + old_length) == process->mmap_end && 868 (!use_provided_address || provided_address == start)) { 869 uint64_t diff = new_length - old_length; 870 process->allocateMem(process->mmap_end, diff); 871 process->mmap_end += diff; 872 return start; 873 } else { 874 if (!use_provided_address && !(flags & OS::TGT_MREMAP_MAYMOVE)) { 875 warn("can't remap here and MREMAP_MAYMOVE flag not set\n"); 876 return -ENOMEM; 877 } else { 878 uint64_t new_start = use_provided_address ? 879 provided_address : process->mmap_end; 880 process->pTable->remap(start, old_length, new_start); 881 warn("mremapping to new vaddr %08p-%08p, adding %d\n", 882 new_start, new_start + new_length, 883 new_length - old_length); 884 // add on the remaining unallocated pages 885 process->allocateMem(new_start + old_length, 886 new_length - old_length, 887 use_provided_address /* clobber */); 888 if (!use_provided_address) 889 process->mmap_end += new_length; 890 if (use_provided_address && 891 new_start + new_length > process->mmap_end) { 892 // something fishy going on here, at least notify the user 893 // @todo: increase mmap_end? 894 warn("mmap region limit exceeded with MREMAP_FIXED\n"); 895 } 896 warn("returning %08p as start\n", new_start); 897 return new_start; 898 } 899 } 900 } else { 901 if (use_provided_address && provided_address != start) 902 process->pTable->remap(start, new_length, provided_address); 903 process->pTable->unmap(start + new_length, old_length - new_length); 904 return use_provided_address ? provided_address : start; 905 } 906} 907 908/// Target stat() handler. 909template <class OS> 910SyscallReturn 911statFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 912 ThreadContext *tc) 913{ 914 std::string path; 915 916 int index = 0; 917 if (!tc->getMemProxy().tryReadString(path, 918 process->getSyscallArg(tc, index))) { 919 return -EFAULT; 920 } 921 Addr bufPtr = process->getSyscallArg(tc, index); 922 923 // Adjust path for current working directory 924 path = process->fullPath(path); 925 926 struct stat hostBuf; 927 int result = stat(path.c_str(), &hostBuf); 928 929 if (result < 0) 930 return -errno; 931 932 copyOutStatBuf<OS>(tc->getMemProxy(), bufPtr, &hostBuf); 933 934 return 0; 935} 936 937 938/// Target stat64() handler. 939template <class OS> 940SyscallReturn 941stat64Func(SyscallDesc *desc, int callnum, LiveProcess *process, 942 ThreadContext *tc) 943{ 944 std::string path; 945 946 int index = 0; 947 if (!tc->getMemProxy().tryReadString(path, 948 process->getSyscallArg(tc, index))) 949 return -EFAULT; 950 Addr bufPtr = process->getSyscallArg(tc, index); 951 952 // Adjust path for current working directory 953 path = process->fullPath(path); 954 955#if NO_STAT64 956 struct stat hostBuf; 957 int result = stat(path.c_str(), &hostBuf); 958#else 959 struct stat64 hostBuf; 960 int result = stat64(path.c_str(), &hostBuf); 961#endif 962 963 if (result < 0) 964 return -errno; 965 966 copyOutStat64Buf<OS>(tc->getMemProxy(), bufPtr, &hostBuf); 967 968 return 0; 969} 970 971 972/// Target fstatat64() handler. 973template <class OS> 974SyscallReturn 975fstatat64Func(SyscallDesc *desc, int callnum, LiveProcess *process, 976 ThreadContext *tc) 977{ 978 int index = 0; 979 int dirfd = process->getSyscallArg(tc, index); 980 if (dirfd != OS::TGT_AT_FDCWD) 981 warn("fstatat64: first argument not AT_FDCWD; unlikely to work"); 982 983 std::string path; 984 if (!tc->getMemProxy().tryReadString(path, 985 process->getSyscallArg(tc, index))) 986 return -EFAULT; 987 Addr bufPtr = process->getSyscallArg(tc, index); 988 989 // Adjust path for current working directory 990 path = process->fullPath(path); 991 992#if NO_STAT64 993 struct stat hostBuf; 994 int result = stat(path.c_str(), &hostBuf); 995#else 996 struct stat64 hostBuf; 997 int result = stat64(path.c_str(), &hostBuf); 998#endif 999 1000 if (result < 0) 1001 return -errno; 1002 1003 copyOutStat64Buf<OS>(tc->getMemProxy(), bufPtr, &hostBuf); 1004 1005 return 0; 1006} 1007 1008 1009/// Target fstat64() handler. 1010template <class OS> 1011SyscallReturn 1012fstat64Func(SyscallDesc *desc, int callnum, LiveProcess *process, 1013 ThreadContext *tc) 1014{ 1015 int index = 0; 1016 int tgt_fd = process->getSyscallArg(tc, index); 1017 Addr bufPtr = process->getSyscallArg(tc, index); 1018 1019 int sim_fd = process->getSimFD(tgt_fd); 1020 if (sim_fd < 0) 1021 return -EBADF; 1022 1023#if NO_STAT64 1024 struct stat hostBuf; 1025 int result = fstat(sim_fd, &hostBuf); 1026#else 1027 struct stat64 hostBuf; 1028 int result = fstat64(sim_fd, &hostBuf); 1029#endif 1030 1031 if (result < 0) 1032 return -errno; 1033 1034 copyOutStat64Buf<OS>(tc->getMemProxy(), bufPtr, &hostBuf, (sim_fd == 1)); 1035 1036 return 0; 1037} 1038 1039 1040/// Target lstat() handler. 1041template <class OS> 1042SyscallReturn 1043lstatFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 1044 ThreadContext *tc) 1045{ 1046 std::string path; 1047 1048 int index = 0; 1049 if (!tc->getMemProxy().tryReadString(path, 1050 process->getSyscallArg(tc, index))) { 1051 return -EFAULT; 1052 } 1053 Addr bufPtr = process->getSyscallArg(tc, index); 1054 1055 // Adjust path for current working directory 1056 path = process->fullPath(path); 1057 1058 struct stat hostBuf; 1059 int result = lstat(path.c_str(), &hostBuf); 1060 1061 if (result < 0) 1062 return -errno; 1063 1064 copyOutStatBuf<OS>(tc->getMemProxy(), bufPtr, &hostBuf); 1065 1066 return 0; 1067} 1068 1069/// Target lstat64() handler. 1070template <class OS> 1071SyscallReturn 1072lstat64Func(SyscallDesc *desc, int callnum, LiveProcess *process, 1073 ThreadContext *tc) 1074{ 1075 std::string path; 1076 1077 int index = 0; 1078 if (!tc->getMemProxy().tryReadString(path, 1079 process->getSyscallArg(tc, index))) { 1080 return -EFAULT; 1081 } 1082 Addr bufPtr = process->getSyscallArg(tc, index); 1083 1084 // Adjust path for current working directory 1085 path = process->fullPath(path); 1086 1087#if NO_STAT64 1088 struct stat hostBuf; 1089 int result = lstat(path.c_str(), &hostBuf); 1090#else 1091 struct stat64 hostBuf; 1092 int result = lstat64(path.c_str(), &hostBuf); 1093#endif 1094 1095 if (result < 0) 1096 return -errno; 1097 1098 copyOutStat64Buf<OS>(tc->getMemProxy(), bufPtr, &hostBuf); 1099 1100 return 0; 1101} 1102 1103/// Target fstat() handler. 1104template <class OS> 1105SyscallReturn 1106fstatFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 1107 ThreadContext *tc) 1108{ 1109 int index = 0; 1110 int tgt_fd = process->getSyscallArg(tc, index); 1111 Addr bufPtr = process->getSyscallArg(tc, index); 1112 1113 DPRINTF_SYSCALL(Verbose, "fstat(%d, ...)\n", tgt_fd); 1114 1115 int sim_fd = process->getSimFD(tgt_fd); 1116 if (sim_fd < 0) 1117 return -EBADF; 1118 1119 struct stat hostBuf; 1120 int result = fstat(sim_fd, &hostBuf); 1121 1122 if (result < 0) 1123 return -errno; 1124 1125 copyOutStatBuf<OS>(tc->getMemProxy(), bufPtr, &hostBuf, (sim_fd == 1)); 1126 1127 return 0; 1128} 1129 1130 1131/// Target statfs() handler. 1132template <class OS> 1133SyscallReturn 1134statfsFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 1135 ThreadContext *tc) 1136{ 1137 std::string path; 1138 1139 int index = 0; 1140 if (!tc->getMemProxy().tryReadString(path, 1141 process->getSyscallArg(tc, index))) { 1142 return -EFAULT; 1143 } 1144 Addr bufPtr = process->getSyscallArg(tc, index); 1145 1146 // Adjust path for current working directory 1147 path = process->fullPath(path); 1148 1149 struct statfs hostBuf; 1150 int result = statfs(path.c_str(), &hostBuf); 1151 1152 if (result < 0) 1153 return -errno; 1154 1155 OS::copyOutStatfsBuf(tc->getMemProxy(), bufPtr, &hostBuf); 1156 1157 return 0; 1158} 1159 1160 1161/// Target fstatfs() handler. 1162template <class OS> 1163SyscallReturn 1164fstatfsFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 1165 ThreadContext *tc) 1166{ 1167 int index = 0; 1168 int tgt_fd = process->getSyscallArg(tc, index); 1169 Addr bufPtr = process->getSyscallArg(tc, index); 1170 1171 int sim_fd = process->getSimFD(tgt_fd); 1172 if (sim_fd < 0) 1173 return -EBADF; 1174 1175 struct statfs hostBuf; 1176 int result = fstatfs(sim_fd, &hostBuf); 1177 1178 if (result < 0) 1179 return -errno; 1180 1181 OS::copyOutStatfsBuf(tc->getMemProxy(), bufPtr, &hostBuf); 1182 1183 return 0; 1184} 1185 1186 1187/// Target writev() handler. 1188template <class OS> 1189SyscallReturn 1190writevFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 1191 ThreadContext *tc) 1192{ 1193 int index = 0; 1194 int tgt_fd = process->getSyscallArg(tc, index); 1195 1196 int sim_fd = process->getSimFD(tgt_fd); 1197 if (sim_fd < 0) 1198 return -EBADF; 1199 1200 SETranslatingPortProxy &p = tc->getMemProxy(); 1201 uint64_t tiov_base = process->getSyscallArg(tc, index); 1202 size_t count = process->getSyscallArg(tc, index); 1203 struct iovec hiov[count]; 1204 for (size_t i = 0; i < count; ++i) { 1205 typename OS::tgt_iovec tiov; 1206 1207 p.readBlob(tiov_base + i*sizeof(typename OS::tgt_iovec), 1208 (uint8_t*)&tiov, sizeof(typename OS::tgt_iovec)); 1209 hiov[i].iov_len = TheISA::gtoh(tiov.iov_len); 1210 hiov[i].iov_base = new char [hiov[i].iov_len]; 1211 p.readBlob(TheISA::gtoh(tiov.iov_base), (uint8_t *)hiov[i].iov_base, 1212 hiov[i].iov_len); 1213 } 1214 1215 int result = writev(sim_fd, hiov, count); 1216 1217 for (size_t i = 0; i < count; ++i) 1218 delete [] (char *)hiov[i].iov_base; 1219 1220 if (result < 0) 1221 return -errno; 1222 1223 return result; 1224} 1225 1226/// Real mmap handler. 1227template <class OS> 1228SyscallReturn 1229mmapImpl(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc, 1230 bool is_mmap2) 1231{ 1232 int index = 0; 1233 Addr start = p->getSyscallArg(tc, index); 1234 uint64_t length = p->getSyscallArg(tc, index); 1235 int prot = p->getSyscallArg(tc, index); 1236 int tgt_flags = p->getSyscallArg(tc, index); 1237 int tgt_fd = p->getSyscallArg(tc, index); 1238 int offset = p->getSyscallArg(tc, index); 1239 1240 if (is_mmap2) 1241 offset *= TheISA::PageBytes; 1242 1243 if (start & (TheISA::PageBytes - 1) || 1244 offset & (TheISA::PageBytes - 1) || 1245 (tgt_flags & OS::TGT_MAP_PRIVATE && 1246 tgt_flags & OS::TGT_MAP_SHARED) || 1247 (!(tgt_flags & OS::TGT_MAP_PRIVATE) && 1248 !(tgt_flags & OS::TGT_MAP_SHARED)) || 1249 !length) { 1250 return -EINVAL; 1251 } 1252 1253 if ((prot & PROT_WRITE) && (tgt_flags & OS::TGT_MAP_SHARED)) { 1254 // With shared mmaps, there are two cases to consider: 1255 // 1) anonymous: writes should modify the mapping and this should be 1256 // visible to observers who share the mapping. Currently, it's 1257 // difficult to update the shared mapping because there's no 1258 // structure which maintains information about the which virtual 1259 // memory areas are shared. If that structure existed, it would be 1260 // possible to make the translations point to the same frames. 1261 // 2) file-backed: writes should modify the mapping and the file 1262 // which is backed by the mapping. The shared mapping problem is the 1263 // same as what was mentioned about the anonymous mappings. For 1264 // file-backed mappings, the writes to the file are difficult 1265 // because it requires syncing what the mapping holds with the file 1266 // that resides on the host system. So, any write on a real system 1267 // would cause the change to be propagated to the file mapping at 1268 // some point in the future (the inode is tracked along with the 1269 // mapping). This isn't guaranteed to always happen, but it usually 1270 // works well enough. The guarantee is provided by the msync system 1271 // call. We could force the change through with shared mappings with 1272 // a call to msync, but that again would require more information 1273 // than we currently maintain. 1274 warn("mmap: writing to shared mmap region is currently " 1275 "unsupported. The write succeeds on the target, but it " 1276 "will not be propagated to the host or shared mappings"); 1277 } 1278 1279 length = roundUp(length, TheISA::PageBytes); 1280 1281 int sim_fd = -1; 1282 uint8_t *pmap = nullptr; 1283 if (!(tgt_flags & OS::TGT_MAP_ANONYMOUS)) { 1284 sim_fd = p->getSimFD(tgt_fd); 1285 if (sim_fd < 0) 1286 return -EBADF; 1287 1288 pmap = (decltype(pmap))mmap(NULL, length, PROT_READ, MAP_PRIVATE, 1289 sim_fd, offset); 1290 1291 if (pmap == (decltype(pmap))-1) { 1292 warn("mmap: failed to map file into host address space"); 1293 return -errno; 1294 } 1295 } 1296 1297 // Extend global mmap region if necessary. Note that we ignore the 1298 // start address unless MAP_FIXED is specified. 1299 if (!(tgt_flags & OS::TGT_MAP_FIXED)) { 1300 start = (OS::mmapGrowsDown()) ? p->mmap_end - length : p->mmap_end; 1301 p->mmap_end = (OS::mmapGrowsDown()) ? start : p->mmap_end + length; 1302 } 1303 1304 DPRINTF_SYSCALL(Verbose, " mmap range is 0x%x - 0x%x\n", 1305 start, start + length - 1); 1306 1307 // We only allow mappings to overwrite existing mappings if 1308 // TGT_MAP_FIXED is set. Otherwise it shouldn't be a problem 1309 // because we ignore the start hint if TGT_MAP_FIXED is not set. 1310 int clobber = tgt_flags & OS::TGT_MAP_FIXED; 1311 if (clobber) { 1312 for (auto tc : p->system->threadContexts) { 1313 // If we might be overwriting old mappings, we need to 1314 // invalidate potentially stale mappings out of the TLBs. 1315 tc->getDTBPtr()->flushAll(); 1316 tc->getITBPtr()->flushAll(); 1317 } 1318 } 1319 1320 // Allocate physical memory and map it in. If the page table is already 1321 // mapped and clobber is not set, the simulator will issue throw a 1322 // fatal and bail out of the simulation. 1323 p->allocateMem(start, length, clobber); 1324 1325 // Transfer content into target address space. 1326 SETranslatingPortProxy &tp = tc->getMemProxy(); 1327 if (tgt_flags & OS::TGT_MAP_ANONYMOUS) { 1328 // In general, we should zero the mapped area for anonymous mappings, 1329 // with something like: 1330 // tp.memsetBlob(start, 0, length); 1331 // However, given that we don't support sparse mappings, and 1332 // some applications can map a couple of gigabytes of space 1333 // (intending sparse usage), that can get painfully expensive. 1334 // Fortunately, since we don't properly implement munmap either, 1335 // there's no danger of remapping used memory, so for now all 1336 // newly mapped memory should already be zeroed so we can skip it. 1337 } else { 1338 // It is possible to mmap an area larger than a file, however 1339 // accessing unmapped portions the system triggers a "Bus error" 1340 // on the host. We must know when to stop copying the file from 1341 // the host into the target address space. 1342 struct stat file_stat; 1343 if (fstat(sim_fd, &file_stat) > 0) 1344 fatal("mmap: cannot stat file"); 1345 1346 // Copy the portion of the file that is resident. This requires 1347 // checking both the mmap size and the filesize that we are 1348 // trying to mmap into this space; the mmap size also depends 1349 // on the specified offset into the file. 1350 uint64_t size = std::min((uint64_t)file_stat.st_size - offset, 1351 length); 1352 tp.writeBlob(start, pmap, size); 1353 1354 // Cleanup the mmap region before exiting this function. 1355 munmap(pmap, length); 1356 1357 // Note that we do not zero out the remainder of the mapping. This 1358 // is done by a real system, but it probably will not affect 1359 // execution (hopefully). 1360 } 1361 1362 return start; 1363} 1364 1365/// Target mmap() handler. 1366template <class OS> 1367SyscallReturn 1368mmapFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc) 1369{ 1370 return mmapImpl<OS>(desc, num, p, tc, false); 1371} 1372 1373/// Target mmap2() handler. 1374template <class OS> 1375SyscallReturn 1376mmap2Func(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc) 1377{ 1378 return mmapImpl<OS>(desc, num, p, tc, true); 1379} 1380 1381/// Target getrlimit() handler. 1382template <class OS> 1383SyscallReturn 1384getrlimitFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 1385 ThreadContext *tc) 1386{ 1387 int index = 0; 1388 unsigned resource = process->getSyscallArg(tc, index); 1389 TypedBufferArg<typename OS::rlimit> rlp(process->getSyscallArg(tc, index)); 1390 1391 switch (resource) { 1392 case OS::TGT_RLIMIT_STACK: 1393 // max stack size in bytes: make up a number (8MB for now) 1394 rlp->rlim_cur = rlp->rlim_max = 8 * 1024 * 1024; 1395 rlp->rlim_cur = TheISA::htog(rlp->rlim_cur); 1396 rlp->rlim_max = TheISA::htog(rlp->rlim_max); 1397 break; 1398 1399 case OS::TGT_RLIMIT_DATA: 1400 // max data segment size in bytes: make up a number 1401 rlp->rlim_cur = rlp->rlim_max = 256 * 1024 * 1024; 1402 rlp->rlim_cur = TheISA::htog(rlp->rlim_cur); 1403 rlp->rlim_max = TheISA::htog(rlp->rlim_max); 1404 break; 1405 1406 default: 1407 warn("getrlimit: unimplemented resource %d", resource); 1408 return -EINVAL; 1409 break; 1410 } 1411 1412 rlp.copyOut(tc->getMemProxy()); 1413 return 0; 1414} 1415 1416/// Target clock_gettime() function. 1417template <class OS> 1418SyscallReturn 1419clock_gettimeFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc) 1420{ 1421 int index = 1; 1422 //int clk_id = p->getSyscallArg(tc, index); 1423 TypedBufferArg<typename OS::timespec> tp(p->getSyscallArg(tc, index)); 1424 1425 getElapsedTimeNano(tp->tv_sec, tp->tv_nsec); 1426 tp->tv_sec += seconds_since_epoch; 1427 tp->tv_sec = TheISA::htog(tp->tv_sec); 1428 tp->tv_nsec = TheISA::htog(tp->tv_nsec); 1429 1430 tp.copyOut(tc->getMemProxy()); 1431 1432 return 0; 1433} 1434 1435/// Target clock_getres() function. 1436template <class OS> 1437SyscallReturn 1438clock_getresFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc) 1439{ 1440 int index = 1; 1441 TypedBufferArg<typename OS::timespec> tp(p->getSyscallArg(tc, index)); 1442 1443 // Set resolution at ns, which is what clock_gettime() returns 1444 tp->tv_sec = 0; 1445 tp->tv_nsec = 1; 1446 1447 tp.copyOut(tc->getMemProxy()); 1448 1449 return 0; 1450} 1451 1452/// Target gettimeofday() handler. 1453template <class OS> 1454SyscallReturn 1455gettimeofdayFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 1456 ThreadContext *tc) 1457{ 1458 int index = 0; 1459 TypedBufferArg<typename OS::timeval> tp(process->getSyscallArg(tc, index)); 1460 1461 getElapsedTimeMicro(tp->tv_sec, tp->tv_usec); 1462 tp->tv_sec += seconds_since_epoch; 1463 tp->tv_sec = TheISA::htog(tp->tv_sec); 1464 tp->tv_usec = TheISA::htog(tp->tv_usec); 1465 1466 tp.copyOut(tc->getMemProxy()); 1467 1468 return 0; 1469} 1470 1471 1472/// Target utimes() handler. 1473template <class OS> 1474SyscallReturn 1475utimesFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 1476 ThreadContext *tc) 1477{ 1478 std::string path; 1479 1480 int index = 0; 1481 if (!tc->getMemProxy().tryReadString(path, 1482 process->getSyscallArg(tc, index))) { 1483 return -EFAULT; 1484 } 1485 1486 TypedBufferArg<typename OS::timeval [2]> 1487 tp(process->getSyscallArg(tc, index)); 1488 tp.copyIn(tc->getMemProxy()); 1489 1490 struct timeval hostTimeval[2]; 1491 for (int i = 0; i < 2; ++i) 1492 { 1493 hostTimeval[i].tv_sec = TheISA::gtoh((*tp)[i].tv_sec); 1494 hostTimeval[i].tv_usec = TheISA::gtoh((*tp)[i].tv_usec); 1495 } 1496 1497 // Adjust path for current working directory 1498 path = process->fullPath(path); 1499 1500 int result = utimes(path.c_str(), hostTimeval); 1501 1502 if (result < 0) 1503 return -errno; 1504 1505 return 0; 1506} 1507/// Target getrusage() function. 1508template <class OS> 1509SyscallReturn 1510getrusageFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 1511 ThreadContext *tc) 1512{ 1513 int index = 0; 1514 int who = process->getSyscallArg(tc, index); // THREAD, SELF, or CHILDREN 1515 TypedBufferArg<typename OS::rusage> rup(process->getSyscallArg(tc, index)); 1516 1517 rup->ru_utime.tv_sec = 0; 1518 rup->ru_utime.tv_usec = 0; 1519 rup->ru_stime.tv_sec = 0; 1520 rup->ru_stime.tv_usec = 0; 1521 rup->ru_maxrss = 0; 1522 rup->ru_ixrss = 0; 1523 rup->ru_idrss = 0; 1524 rup->ru_isrss = 0; 1525 rup->ru_minflt = 0; 1526 rup->ru_majflt = 0; 1527 rup->ru_nswap = 0; 1528 rup->ru_inblock = 0; 1529 rup->ru_oublock = 0; 1530 rup->ru_msgsnd = 0; 1531 rup->ru_msgrcv = 0; 1532 rup->ru_nsignals = 0; 1533 rup->ru_nvcsw = 0; 1534 rup->ru_nivcsw = 0; 1535 1536 switch (who) { 1537 case OS::TGT_RUSAGE_SELF: 1538 getElapsedTimeMicro(rup->ru_utime.tv_sec, rup->ru_utime.tv_usec); 1539 rup->ru_utime.tv_sec = TheISA::htog(rup->ru_utime.tv_sec); 1540 rup->ru_utime.tv_usec = TheISA::htog(rup->ru_utime.tv_usec); 1541 break; 1542 1543 case OS::TGT_RUSAGE_CHILDREN: 1544 // do nothing. We have no child processes, so they take no time. 1545 break; 1546 1547 default: 1548 // don't really handle THREAD or CHILDREN, but just warn and 1549 // plow ahead 1550 warn("getrusage() only supports RUSAGE_SELF. Parameter %d ignored.", 1551 who); 1552 } 1553 1554 rup.copyOut(tc->getMemProxy()); 1555 1556 return 0; 1557} 1558 1559/// Target times() function. 1560template <class OS> 1561SyscallReturn 1562timesFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 1563 ThreadContext *tc) 1564{ 1565 int index = 0; 1566 TypedBufferArg<typename OS::tms> bufp(process->getSyscallArg(tc, index)); 1567 1568 // Fill in the time structure (in clocks) 1569 int64_t clocks = curTick() * OS::M5_SC_CLK_TCK / SimClock::Int::s; 1570 bufp->tms_utime = clocks; 1571 bufp->tms_stime = 0; 1572 bufp->tms_cutime = 0; 1573 bufp->tms_cstime = 0; 1574 1575 // Convert to host endianness 1576 bufp->tms_utime = TheISA::htog(bufp->tms_utime); 1577 1578 // Write back 1579 bufp.copyOut(tc->getMemProxy()); 1580 1581 // Return clock ticks since system boot 1582 return clocks; 1583} 1584 1585/// Target time() function. 1586template <class OS> 1587SyscallReturn 1588timeFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 1589 ThreadContext *tc) 1590{ 1591 typename OS::time_t sec, usec; 1592 getElapsedTimeMicro(sec, usec); 1593 sec += seconds_since_epoch; 1594 1595 int index = 0; 1596 Addr taddr = (Addr)process->getSyscallArg(tc, index); 1597 if (taddr != 0) { 1598 typename OS::time_t t = sec; 1599 t = TheISA::htog(t); 1600 SETranslatingPortProxy &p = tc->getMemProxy(); 1601 p.writeBlob(taddr, (uint8_t*)&t, (int)sizeof(typename OS::time_t)); 1602 } 1603 return sec; 1604} 1605 1606 1607#endif // __SIM_SYSCALL_EMUL_HH__ 1608