syscall_emul.cc revision 11885:79af314e9f0d
1/* 2 * Copyright (c) 2003-2005 The Regents of The University of Michigan 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions are 7 * met: redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer; 9 * redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution; 12 * neither the name of the copyright holders nor the names of its 13 * contributors may be used to endorse or promote products derived from 14 * this software without specific prior written permission. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 17 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 18 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 19 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 20 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 21 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 22 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 * 28 * Authors: Steve Reinhardt 29 * Ali Saidi 30 */ 31 32#include "sim/syscall_emul.hh" 33 34#include <fcntl.h> 35#include <unistd.h> 36 37#include <iostream> 38#include <string> 39 40#include "arch/utility.hh" 41#include "base/chunk_generator.hh" 42#include "base/trace.hh" 43#include "config/the_isa.hh" 44#include "cpu/thread_context.hh" 45#include "mem/page_table.hh" 46#include "sim/process.hh" 47#include "sim/sim_exit.hh" 48#include "sim/syscall_debug_macros.hh" 49#include "sim/syscall_desc.hh" 50#include "sim/system.hh" 51 52using namespace std; 53using namespace TheISA; 54 55SyscallReturn 56unimplementedFunc(SyscallDesc *desc, int callnum, Process *process, 57 ThreadContext *tc) 58{ 59 fatal("syscall %s (#%d) unimplemented.", desc->name(), callnum); 60 61 return 1; 62} 63 64 65SyscallReturn 66ignoreFunc(SyscallDesc *desc, int callnum, Process *process, 67 ThreadContext *tc) 68{ 69 if (desc->needWarning()) { 70 warn("ignoring syscall %s(...)%s", desc->name(), desc->warnOnce() ? 71 "\n (further warnings will be suppressed)" : ""); 72 } 73 74 return 0; 75} 76 77 78SyscallReturn 79exitFunc(SyscallDesc *desc, int callnum, Process *process, 80 ThreadContext *tc) 81{ 82 if (process->system->numRunningContexts() == 1) { 83 // Last running context... exit simulator 84 int index = 0; 85 exitSimLoop("target called exit()", 86 process->getSyscallArg(tc, index) & 0xff); 87 } else { 88 // other running threads... just halt this one 89 tc->halt(); 90 } 91 92 return 1; 93} 94 95 96SyscallReturn 97exitGroupFunc(SyscallDesc *desc, int callnum, Process *process, 98 ThreadContext *tc) 99{ 100 // halt all threads belonging to this process 101 for (auto i: process->contextIds) { 102 process->system->getThreadContext(i)->halt(); 103 } 104 105 if (!process->system->numRunningContexts()) { 106 // all threads belonged to this process... exit simulator 107 int index = 0; 108 exitSimLoop("target called exit()", 109 process->getSyscallArg(tc, index) & 0xff); 110 } 111 112 return 1; 113} 114 115 116SyscallReturn 117getpagesizeFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) 118{ 119 return (int)PageBytes; 120} 121 122 123SyscallReturn 124brkFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) 125{ 126 // change brk addr to first arg 127 int index = 0; 128 Addr new_brk = p->getSyscallArg(tc, index); 129 130 // in Linux at least, brk(0) returns the current break value 131 // (note that the syscall and the glibc function have different behavior) 132 if (new_brk == 0) 133 return p->brk_point; 134 135 if (new_brk > p->brk_point) { 136 // might need to allocate some new pages 137 for (ChunkGenerator gen(p->brk_point, new_brk - p->brk_point, 138 PageBytes); !gen.done(); gen.next()) { 139 if (!p->pTable->translate(gen.addr())) 140 p->allocateMem(roundDown(gen.addr(), PageBytes), PageBytes); 141 142 // if the address is already there, zero it out 143 else { 144 uint8_t zero = 0; 145 SETranslatingPortProxy &tp = tc->getMemProxy(); 146 147 // split non-page aligned accesses 148 Addr next_page = roundUp(gen.addr(), PageBytes); 149 uint32_t size_needed = next_page - gen.addr(); 150 tp.memsetBlob(gen.addr(), zero, size_needed); 151 if (gen.addr() + PageBytes > next_page && 152 next_page < new_brk && 153 p->pTable->translate(next_page)) 154 { 155 size_needed = PageBytes - size_needed; 156 tp.memsetBlob(next_page, zero, size_needed); 157 } 158 } 159 } 160 } 161 162 p->brk_point = new_brk; 163 DPRINTF_SYSCALL(Verbose, "brk: break point changed to: %#X\n", 164 p->brk_point); 165 return p->brk_point; 166} 167 168 169SyscallReturn 170closeFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) 171{ 172 int index = 0; 173 int tgt_fd = p->getSyscallArg(tc, index); 174 175 return p->fds->closeFDEntry(tgt_fd); 176} 177 178 179SyscallReturn 180readFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) 181{ 182 int index = 0; 183 int tgt_fd = p->getSyscallArg(tc, index); 184 Addr bufPtr = p->getSyscallArg(tc, index); 185 int nbytes = p->getSyscallArg(tc, index); 186 187 auto hbfdp = std::dynamic_pointer_cast<HBFDEntry>((*p->fds)[tgt_fd]); 188 if (!hbfdp) 189 return -EBADF; 190 int sim_fd = hbfdp->getSimFD(); 191 192 BufferArg bufArg(bufPtr, nbytes); 193 int bytes_read = read(sim_fd, bufArg.bufferPtr(), nbytes); 194 195 if (bytes_read > 0) 196 bufArg.copyOut(tc->getMemProxy()); 197 198 return bytes_read; 199} 200 201SyscallReturn 202writeFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) 203{ 204 int index = 0; 205 int tgt_fd = p->getSyscallArg(tc, index); 206 Addr bufPtr = p->getSyscallArg(tc, index); 207 int nbytes = p->getSyscallArg(tc, index); 208 209 auto hbfdp = std::dynamic_pointer_cast<HBFDEntry>((*p->fds)[tgt_fd]); 210 if (!hbfdp) 211 return -EBADF; 212 int sim_fd = hbfdp->getSimFD(); 213 214 BufferArg bufArg(bufPtr, nbytes); 215 bufArg.copyIn(tc->getMemProxy()); 216 217 int bytes_written = write(sim_fd, bufArg.bufferPtr(), nbytes); 218 219 fsync(sim_fd); 220 221 return bytes_written; 222} 223 224 225SyscallReturn 226lseekFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) 227{ 228 int index = 0; 229 int tgt_fd = p->getSyscallArg(tc, index); 230 uint64_t offs = p->getSyscallArg(tc, index); 231 int whence = p->getSyscallArg(tc, index); 232 233 auto ffdp = std::dynamic_pointer_cast<FileFDEntry>((*p->fds)[tgt_fd]); 234 if (!ffdp) 235 return -EBADF; 236 int sim_fd = ffdp->getSimFD(); 237 238 off_t result = lseek(sim_fd, offs, whence); 239 240 return (result == (off_t)-1) ? -errno : result; 241} 242 243 244SyscallReturn 245_llseekFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) 246{ 247 int index = 0; 248 int tgt_fd = p->getSyscallArg(tc, index); 249 uint64_t offset_high = p->getSyscallArg(tc, index); 250 uint32_t offset_low = p->getSyscallArg(tc, index); 251 Addr result_ptr = p->getSyscallArg(tc, index); 252 int whence = p->getSyscallArg(tc, index); 253 254 auto ffdp = std::dynamic_pointer_cast<FileFDEntry>((*p->fds)[tgt_fd]); 255 if (!ffdp) 256 return -EBADF; 257 int sim_fd = ffdp->getSimFD(); 258 259 uint64_t offset = (offset_high << 32) | offset_low; 260 261 uint64_t result = lseek(sim_fd, offset, whence); 262 result = TheISA::htog(result); 263 264 if (result == (off_t)-1) 265 return -errno; 266 // Assuming that the size of loff_t is 64 bits on the target platform 267 BufferArg result_buf(result_ptr, sizeof(result)); 268 memcpy(result_buf.bufferPtr(), &result, sizeof(result)); 269 result_buf.copyOut(tc->getMemProxy()); 270 return 0; 271} 272 273 274SyscallReturn 275munmapFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) 276{ 277 // With mmap more fully implemented, it might be worthwhile to bite 278 // the bullet and implement munmap. Should allow us to reuse simulated 279 // memory. 280 return 0; 281} 282 283 284const char *hostname = "m5.eecs.umich.edu"; 285 286SyscallReturn 287gethostnameFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) 288{ 289 int index = 0; 290 Addr bufPtr = p->getSyscallArg(tc, index); 291 int name_len = p->getSyscallArg(tc, index); 292 BufferArg name(bufPtr, name_len); 293 294 strncpy((char *)name.bufferPtr(), hostname, name_len); 295 296 name.copyOut(tc->getMemProxy()); 297 298 return 0; 299} 300 301SyscallReturn 302getcwdFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) 303{ 304 int result = 0; 305 int index = 0; 306 Addr bufPtr = p->getSyscallArg(tc, index); 307 unsigned long size = p->getSyscallArg(tc, index); 308 BufferArg buf(bufPtr, size); 309 310 // Is current working directory defined? 311 string cwd = p->getcwd(); 312 if (!cwd.empty()) { 313 if (cwd.length() >= size) { 314 // Buffer too small 315 return -ERANGE; 316 } 317 strncpy((char *)buf.bufferPtr(), cwd.c_str(), size); 318 result = cwd.length(); 319 } else { 320 if (getcwd((char *)buf.bufferPtr(), size)) { 321 result = strlen((char *)buf.bufferPtr()); 322 } else { 323 result = -1; 324 } 325 } 326 327 buf.copyOut(tc->getMemProxy()); 328 329 return (result == -1) ? -errno : result; 330} 331 332/// Target open() handler. 333SyscallReturn 334readlinkFunc(SyscallDesc *desc, int callnum, Process *process, 335 ThreadContext *tc) 336{ 337 return readlinkFunc(desc, callnum, process, tc, 0); 338} 339 340SyscallReturn 341readlinkFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc, 342 int index) 343{ 344 string path; 345 346 if (!tc->getMemProxy().tryReadString(path, p->getSyscallArg(tc, index))) 347 return -EFAULT; 348 349 // Adjust path for current working directory 350 path = p->fullPath(path); 351 352 Addr bufPtr = p->getSyscallArg(tc, index); 353 size_t bufsiz = p->getSyscallArg(tc, index); 354 355 BufferArg buf(bufPtr, bufsiz); 356 357 int result = -1; 358 if (path != "/proc/self/exe") { 359 result = readlink(path.c_str(), (char *)buf.bufferPtr(), bufsiz); 360 } else { 361 // Emulate readlink() called on '/proc/self/exe' should return the 362 // absolute path of the binary running in the simulated system (the 363 // Process' executable). It is possible that using this path in 364 // the simulated system will result in unexpected behavior if: 365 // 1) One binary runs another (e.g., -c time -o "my_binary"), and 366 // called binary calls readlink(). 367 // 2) The host's full path to the running benchmark changes from one 368 // simulation to another. This can result in different simulated 369 // performance since the simulated system will process the binary 370 // path differently, even if the binary itself does not change. 371 372 // Get the absolute canonical path to the running application 373 char real_path[PATH_MAX]; 374 char *check_real_path = realpath(p->progName(), real_path); 375 if (!check_real_path) { 376 fatal("readlink('/proc/self/exe') unable to resolve path to " 377 "executable: %s", p->progName()); 378 } 379 strncpy((char*)buf.bufferPtr(), real_path, bufsiz); 380 size_t real_path_len = strlen(real_path); 381 if (real_path_len > bufsiz) { 382 // readlink will truncate the contents of the 383 // path to ensure it is no more than bufsiz 384 result = bufsiz; 385 } else { 386 result = real_path_len; 387 } 388 389 // Issue a warning about potential unexpected results 390 warn_once("readlink() called on '/proc/self/exe' may yield unexpected " 391 "results in various settings.\n Returning '%s'\n", 392 (char*)buf.bufferPtr()); 393 } 394 395 buf.copyOut(tc->getMemProxy()); 396 397 return (result == -1) ? -errno : result; 398} 399 400SyscallReturn 401unlinkFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) 402{ 403 return unlinkHelper(desc, num, p, tc, 0); 404} 405 406SyscallReturn 407unlinkHelper(SyscallDesc *desc, int num, Process *p, ThreadContext *tc, 408 int index) 409{ 410 string path; 411 412 if (!tc->getMemProxy().tryReadString(path, p->getSyscallArg(tc, index))) 413 return -EFAULT; 414 415 // Adjust path for current working directory 416 path = p->fullPath(path); 417 418 int result = unlink(path.c_str()); 419 return (result == -1) ? -errno : result; 420} 421 422 423SyscallReturn 424mkdirFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) 425{ 426 string path; 427 428 int index = 0; 429 if (!tc->getMemProxy().tryReadString(path, p->getSyscallArg(tc, index))) 430 return -EFAULT; 431 432 // Adjust path for current working directory 433 path = p->fullPath(path); 434 435 mode_t mode = p->getSyscallArg(tc, index); 436 437 int result = mkdir(path.c_str(), mode); 438 return (result == -1) ? -errno : result; 439} 440 441SyscallReturn 442renameFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) 443{ 444 string old_name; 445 446 int index = 0; 447 if (!tc->getMemProxy().tryReadString(old_name, p->getSyscallArg(tc, index))) 448 return -EFAULT; 449 450 string new_name; 451 452 if (!tc->getMemProxy().tryReadString(new_name, p->getSyscallArg(tc, index))) 453 return -EFAULT; 454 455 // Adjust path for current working directory 456 old_name = p->fullPath(old_name); 457 new_name = p->fullPath(new_name); 458 459 int64_t result = rename(old_name.c_str(), new_name.c_str()); 460 return (result == -1) ? -errno : result; 461} 462 463SyscallReturn 464truncateFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) 465{ 466 string path; 467 468 int index = 0; 469 if (!tc->getMemProxy().tryReadString(path, p->getSyscallArg(tc, index))) 470 return -EFAULT; 471 472 off_t length = p->getSyscallArg(tc, index); 473 474 // Adjust path for current working directory 475 path = p->fullPath(path); 476 477 int result = truncate(path.c_str(), length); 478 return (result == -1) ? -errno : result; 479} 480 481SyscallReturn 482ftruncateFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) 483{ 484 int index = 0; 485 int tgt_fd = p->getSyscallArg(tc, index); 486 off_t length = p->getSyscallArg(tc, index); 487 488 auto ffdp = std::dynamic_pointer_cast<FileFDEntry>((*p->fds)[tgt_fd]); 489 if (!ffdp) 490 return -EBADF; 491 int sim_fd = ffdp->getSimFD(); 492 493 int result = ftruncate(sim_fd, length); 494 return (result == -1) ? -errno : result; 495} 496 497SyscallReturn 498truncate64Func(SyscallDesc *desc, int num, 499 Process *process, ThreadContext *tc) 500{ 501 int index = 0; 502 string path; 503 504 if (!tc->getMemProxy().tryReadString(path, process->getSyscallArg(tc, index))) 505 return -EFAULT; 506 507 int64_t length = process->getSyscallArg(tc, index, 64); 508 509 // Adjust path for current working directory 510 path = process->fullPath(path); 511 512#if NO_STAT64 513 int result = truncate(path.c_str(), length); 514#else 515 int result = truncate64(path.c_str(), length); 516#endif 517 return (result == -1) ? -errno : result; 518} 519 520SyscallReturn 521ftruncate64Func(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) 522{ 523 int index = 0; 524 int tgt_fd = p->getSyscallArg(tc, index); 525 int64_t length = p->getSyscallArg(tc, index, 64); 526 527 auto ffdp = std::dynamic_pointer_cast<FileFDEntry>((*p->fds)[tgt_fd]); 528 if (!ffdp) 529 return -EBADF; 530 int sim_fd = ffdp->getSimFD(); 531 532#if NO_STAT64 533 int result = ftruncate(sim_fd, length); 534#else 535 int result = ftruncate64(sim_fd, length); 536#endif 537 return (result == -1) ? -errno : result; 538} 539 540SyscallReturn 541umaskFunc(SyscallDesc *desc, int num, Process *process, ThreadContext *tc) 542{ 543 // Letting the simulated program change the simulator's umask seems like 544 // a bad idea. Compromise by just returning the current umask but not 545 // changing anything. 546 mode_t oldMask = umask(0); 547 umask(oldMask); 548 return (int)oldMask; 549} 550 551SyscallReturn 552chownFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) 553{ 554 string path; 555 556 int index = 0; 557 if (!tc->getMemProxy().tryReadString(path, p->getSyscallArg(tc, index))) 558 return -EFAULT; 559 560 /* XXX endianess */ 561 uint32_t owner = p->getSyscallArg(tc, index); 562 uid_t hostOwner = owner; 563 uint32_t group = p->getSyscallArg(tc, index); 564 gid_t hostGroup = group; 565 566 // Adjust path for current working directory 567 path = p->fullPath(path); 568 569 int result = chown(path.c_str(), hostOwner, hostGroup); 570 return (result == -1) ? -errno : result; 571} 572 573SyscallReturn 574fchownFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) 575{ 576 int index = 0; 577 int tgt_fd = p->getSyscallArg(tc, index); 578 579 auto ffdp = std::dynamic_pointer_cast<FileFDEntry>((*p->fds)[tgt_fd]); 580 if (!ffdp) 581 return -EBADF; 582 int sim_fd = ffdp->getSimFD(); 583 584 /* XXX endianess */ 585 uint32_t owner = p->getSyscallArg(tc, index); 586 uid_t hostOwner = owner; 587 uint32_t group = p->getSyscallArg(tc, index); 588 gid_t hostGroup = group; 589 590 int result = fchown(sim_fd, hostOwner, hostGroup); 591 return (result == -1) ? -errno : result; 592} 593 594 595/** 596 * TODO: there's a bit more involved here since file descriptors created with 597 * dup are supposed to share a file description. So, there is a problem with 598 * maintaining fields like file offset or flags since an update to such a 599 * field won't be reflected in the metadata for the fd entries that we 600 * maintain to hold metadata for checkpoint restoration. 601 */ 602SyscallReturn 603dupFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) 604{ 605 int index = 0; 606 int tgt_fd = p->getSyscallArg(tc, index); 607 608 auto old_hbfdp = std::dynamic_pointer_cast<HBFDEntry>((*p->fds)[tgt_fd]); 609 if (!old_hbfdp) 610 return -EBADF; 611 int sim_fd = old_hbfdp->getSimFD(); 612 613 int result = dup(sim_fd); 614 int local_errno = errno; 615 616 std::shared_ptr<FDEntry> new_fdep = old_hbfdp->clone(); 617 auto new_hbfdp = std::dynamic_pointer_cast<HBFDEntry>(new_fdep); 618 new_hbfdp->setSimFD(result); 619 620 return (result == -1) ? -local_errno : p->fds->allocFD(new_fdep); 621} 622 623SyscallReturn 624fcntlFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) 625{ 626 int arg; 627 int index = 0; 628 int tgt_fd = p->getSyscallArg(tc, index); 629 int cmd = p->getSyscallArg(tc, index); 630 631 auto hbfdp = std::dynamic_pointer_cast<HBFDEntry>((*p->fds)[tgt_fd]); 632 if (!hbfdp) 633 return -EBADF; 634 int sim_fd = hbfdp->getSimFD(); 635 636 int coe = hbfdp->getCOE(); 637 638 switch (cmd) { 639 case F_GETFD: 640 return coe & FD_CLOEXEC; 641 642 case F_SETFD: { 643 arg = p->getSyscallArg(tc, index); 644 arg ? hbfdp->setCOE(true) : hbfdp->setCOE(false); 645 return 0; 646 } 647 648 // Rely on the host to maintain the file status flags for this file 649 // description rather than maintain it ourselves. Admittedly, this 650 // is suboptimal (and possibly error prone), but it is difficult to 651 // maintain the flags by tracking them across the different descriptors 652 // (that refer to this file description) caused by clone, dup, and 653 // subsequent fcntls. 654 case F_GETFL: 655 case F_SETFL: { 656 arg = p->getSyscallArg(tc, index); 657 int rv = fcntl(sim_fd, cmd, arg); 658 return (rv == -1) ? -errno : rv; 659 } 660 661 default: 662 warn("fcntl: unsupported command %d\n", cmd); 663 return 0; 664 } 665} 666 667SyscallReturn 668fcntl64Func(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) 669{ 670 int index = 0; 671 int tgt_fd = p->getSyscallArg(tc, index); 672 673 auto hbfdp = std::dynamic_pointer_cast<HBFDEntry>((*p->fds)[tgt_fd]); 674 if (!hbfdp) 675 return -EBADF; 676 int sim_fd = hbfdp->getSimFD(); 677 678 int cmd = p->getSyscallArg(tc, index); 679 switch (cmd) { 680 case 33: //F_GETLK64 681 warn("fcntl64(%d, F_GETLK64) not supported, error returned\n", tgt_fd); 682 return -EMFILE; 683 684 case 34: // F_SETLK64 685 case 35: // F_SETLKW64 686 warn("fcntl64(%d, F_SETLK(W)64) not supported, error returned\n", 687 tgt_fd); 688 return -EMFILE; 689 690 default: 691 // not sure if this is totally valid, but we'll pass it through 692 // to the underlying OS 693 warn("fcntl64(%d, %d) passed through to host\n", tgt_fd, cmd); 694 return fcntl(sim_fd, cmd); 695 // return 0; 696 } 697} 698 699SyscallReturn 700pipePseudoFunc(SyscallDesc *desc, int callnum, Process *process, 701 ThreadContext *tc) 702{ 703 int sim_fds[2], tgt_fds[2]; 704 705 int pipe_retval = pipe(sim_fds); 706 if (pipe_retval < 0) 707 return pipe_retval; 708 709 auto rend = PipeFDEntry::EndType::read; 710 auto rpfd = std::make_shared<PipeFDEntry>(sim_fds[0], O_WRONLY, rend); 711 712 auto wend = PipeFDEntry::EndType::write; 713 auto wpfd = std::make_shared<PipeFDEntry>(sim_fds[1], O_RDONLY, wend); 714 715 tgt_fds[0] = process->fds->allocFD(rpfd); 716 tgt_fds[1] = process->fds->allocFD(wpfd); 717 718 /** 719 * Now patch the read object to record the target file descriptor chosen 720 * as the write end of the pipe. 721 */ 722 rpfd->setPipeReadSource(tgt_fds[1]); 723 724 /** 725 * Alpha Linux convention for pipe() is that fd[0] is returned as 726 * the return value of the function, and fd[1] is returned in r20. 727 */ 728 tc->setIntReg(SyscallPseudoReturnReg, tgt_fds[1]); 729 return sim_fds[0]; 730} 731 732SyscallReturn 733setpgidFunc(SyscallDesc *desc, int callnum, Process *process, 734 ThreadContext *tc) 735{ 736 int index = 0; 737 int pid = process->getSyscallArg(tc, index); 738 int pgid = process->getSyscallArg(tc, index); 739 740 if (pgid < 0) 741 return -EINVAL; 742 743 if (pid == 0) { 744 process->setpgid(process->pid()); 745 return 0; 746 } 747 748 Process *matched_ph = NULL; 749 System *sysh = tc->getSystemPtr(); 750 751 // Retrieves process pointer from active/suspended thread contexts. 752 for (int i = 0; i < sysh->numContexts(); i++) { 753 if (sysh->threadContexts[i]->status() != ThreadContext::Halted) { 754 Process *temp_h = sysh->threadContexts[i]->getProcessPtr(); 755 Process *walk_ph = (Process*)temp_h; 756 757 if (walk_ph && walk_ph->pid() == process->pid()) 758 matched_ph = walk_ph; 759 } 760 } 761 762 assert(matched_ph != NULL); 763 matched_ph->setpgid((pgid == 0) ? matched_ph->pid() : pgid); 764 765 return 0; 766} 767 768SyscallReturn 769getpidPseudoFunc(SyscallDesc *desc, int callnum, Process *process, 770 ThreadContext *tc) 771{ 772 // Make up a PID. There's no interprocess communication in 773 // fake_syscall mode, so there's no way for a process to know it's 774 // not getting a unique value. 775 776 tc->setIntReg(SyscallPseudoReturnReg, process->ppid()); 777 return process->pid(); 778} 779 780 781SyscallReturn 782getuidPseudoFunc(SyscallDesc *desc, int callnum, Process *process, 783 ThreadContext *tc) 784{ 785 // Make up a UID and EUID... it shouldn't matter, and we want the 786 // simulation to be deterministic. 787 788 // EUID goes in r20. 789 tc->setIntReg(SyscallPseudoReturnReg, process->euid()); //EUID 790 return process->uid(); // UID 791} 792 793 794SyscallReturn 795getgidPseudoFunc(SyscallDesc *desc, int callnum, Process *process, 796 ThreadContext *tc) 797{ 798 // Get current group ID. EGID goes in r20. 799 tc->setIntReg(SyscallPseudoReturnReg, process->egid()); //EGID 800 return process->gid(); 801} 802 803 804SyscallReturn 805setuidFunc(SyscallDesc *desc, int callnum, Process *process, 806 ThreadContext *tc) 807{ 808 // can't fathom why a benchmark would call this. 809 int index = 0; 810 warn("Ignoring call to setuid(%d)\n", process->getSyscallArg(tc, index)); 811 return 0; 812} 813 814SyscallReturn 815getpidFunc(SyscallDesc *desc, int callnum, Process *process, 816 ThreadContext *tc) 817{ 818 return process->tgid(); 819} 820 821SyscallReturn 822gettidFunc(SyscallDesc *desc, int callnum, Process *process, 823 ThreadContext *tc) 824{ 825 return process->pid(); 826} 827 828SyscallReturn 829getppidFunc(SyscallDesc *desc, int callnum, Process *process, 830 ThreadContext *tc) 831{ 832 return process->ppid(); 833} 834 835SyscallReturn 836getuidFunc(SyscallDesc *desc, int callnum, Process *process, 837 ThreadContext *tc) 838{ 839 return process->uid(); // UID 840} 841 842SyscallReturn 843geteuidFunc(SyscallDesc *desc, int callnum, Process *process, 844 ThreadContext *tc) 845{ 846 return process->euid(); // UID 847} 848 849SyscallReturn 850getgidFunc(SyscallDesc *desc, int callnum, Process *process, 851 ThreadContext *tc) 852{ 853 return process->gid(); 854} 855 856SyscallReturn 857getegidFunc(SyscallDesc *desc, int callnum, Process *process, 858 ThreadContext *tc) 859{ 860 return process->egid(); 861} 862 863 864SyscallReturn 865cloneFunc(SyscallDesc *desc, int callnum, Process *process, 866 ThreadContext *tc) 867{ 868 int index = 0; 869 IntReg flags = process->getSyscallArg(tc, index); 870 IntReg newStack = process->getSyscallArg(tc, index); 871 872 DPRINTF(SyscallVerbose, "In sys_clone:\n"); 873 DPRINTF(SyscallVerbose, " Flags=%llx\n", flags); 874 DPRINTF(SyscallVerbose, " Child stack=%llx\n", newStack); 875 876 877 if (flags != 0x10f00) { 878 warn("This sys_clone implementation assumes flags " 879 "CLONE_VM|CLONE_FS|CLONE_FILES|CLONE_SIGHAND|CLONE_THREAD " 880 "(0x10f00), and may not work correctly with given flags " 881 "0x%llx\n", flags); 882 } 883 884 ThreadContext* ctc; // child thread context 885 if ((ctc = process->findFreeContext())) { 886 DPRINTF(SyscallVerbose, " Found unallocated thread context\n"); 887 888 ctc->clearArchRegs(); 889 890 // Arch-specific cloning code 891 #if THE_ISA == ALPHA_ISA or THE_ISA == X86_ISA 892 // Cloning the misc. regs for these archs is enough 893 TheISA::copyMiscRegs(tc, ctc); 894 #elif THE_ISA == SPARC_ISA 895 TheISA::copyRegs(tc, ctc); 896 897 // TODO: Explain what this code actually does :-) 898 ctc->setIntReg(NumIntArchRegs + 6, 0); 899 ctc->setIntReg(NumIntArchRegs + 4, 0); 900 ctc->setIntReg(NumIntArchRegs + 3, NWindows - 2); 901 ctc->setIntReg(NumIntArchRegs + 5, NWindows); 902 ctc->setMiscReg(MISCREG_CWP, 0); 903 ctc->setIntReg(NumIntArchRegs + 7, 0); 904 ctc->setMiscRegNoEffect(MISCREG_TL, 0); 905 ctc->setMiscReg(MISCREG_ASI, ASI_PRIMARY); 906 907 for (int y = 8; y < 32; y++) 908 ctc->setIntReg(y, tc->readIntReg(y)); 909 #elif THE_ISA == ARM_ISA 910 TheISA::copyRegs(tc, ctc); 911 #else 912 fatal("sys_clone is not implemented for this ISA\n"); 913 #endif 914 915 // Set up stack register 916 ctc->setIntReg(TheISA::StackPointerReg, newStack); 917 918 // Set up syscall return values in parent and child 919 ctc->setIntReg(ReturnValueReg, 0); // return value, child 920 921 // Alpha needs SyscallSuccessReg=0 in child 922 #if THE_ISA == ALPHA_ISA 923 ctc->setIntReg(TheISA::SyscallSuccessReg, 0); 924 #endif 925 926 // In SPARC/Linux, clone returns 0 on pseudo-return register if 927 // parent, non-zero if child 928 #if THE_ISA == SPARC_ISA 929 tc->setIntReg(TheISA::SyscallPseudoReturnReg, 0); 930 ctc->setIntReg(TheISA::SyscallPseudoReturnReg, 1); 931 #endif 932 933 ctc->pcState(tc->nextInstAddr()); 934 935 ctc->activate(); 936 937 // Should return nonzero child TID in parent's syscall return register, 938 // but for our pthread library any non-zero value will work 939 return 1; 940 } else { 941 fatal("Called sys_clone, but no unallocated thread contexts found!\n"); 942 return 0; 943 } 944} 945 946SyscallReturn 947fallocateFunc(SyscallDesc *desc, int callnum, Process *p, ThreadContext *tc) 948{ 949#if NO_FALLOCATE 950 warn("Host OS cannot support calls to fallocate. Ignoring syscall"); 951#else 952 int index = 0; 953 int tgt_fd = p->getSyscallArg(tc, index); 954 int mode = p->getSyscallArg(tc, index); 955 off_t offset = p->getSyscallArg(tc, index); 956 off_t len = p->getSyscallArg(tc, index); 957 958 auto ffdp = std::dynamic_pointer_cast<FileFDEntry>((*p->fds)[tgt_fd]); 959 if (!ffdp) 960 return -EBADF; 961 int sim_fd = ffdp->getSimFD(); 962 963 int result = fallocate(sim_fd, mode, offset, len); 964 if (result < 0) 965 return -errno; 966#endif 967 return 0; 968} 969 970SyscallReturn 971accessFunc(SyscallDesc *desc, int callnum, Process *p, ThreadContext *tc, 972 int index) 973{ 974 string path; 975 if (!tc->getMemProxy().tryReadString(path, p->getSyscallArg(tc, index))) 976 return -EFAULT; 977 978 // Adjust path for current working directory 979 path = p->fullPath(path); 980 981 mode_t mode = p->getSyscallArg(tc, index); 982 983 int result = access(path.c_str(), mode); 984 return (result == -1) ? -errno : result; 985} 986 987SyscallReturn 988accessFunc(SyscallDesc *desc, int callnum, Process *p, ThreadContext *tc) 989{ 990 return accessFunc(desc, callnum, p, tc, 0); 991} 992 993