syscall_emul.cc revision 6701:4842482e1bd1
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 <fcntl.h> 33#include <unistd.h> 34 35#include <string> 36#include <iostream> 37 38#include "sim/syscall_emul.hh" 39#include "base/chunk_generator.hh" 40#include "base/trace.hh" 41#include "config/the_isa.hh" 42#include "cpu/thread_context.hh" 43#include "cpu/base.hh" 44#include "mem/page_table.hh" 45#include "sim/process.hh" 46#include "sim/system.hh" 47#include "sim/sim_exit.hh" 48 49using namespace std; 50using namespace TheISA; 51 52void 53SyscallDesc::doSyscall(int callnum, LiveProcess *process, ThreadContext *tc) 54{ 55 int index = 0; 56 DPRINTFR(SyscallVerbose, 57 "%d: %s: syscall %s called w/arguments %d,%d,%d,%d\n", 58 curTick, tc->getCpuPtr()->name(), name, 59 process->getSyscallArg(tc, index), 60 process->getSyscallArg(tc, index), 61 process->getSyscallArg(tc, index), 62 process->getSyscallArg(tc, index)); 63 64 SyscallReturn retval = (*funcPtr)(this, callnum, process, tc); 65 66 DPRINTFR(SyscallVerbose, "%d: %s: syscall %s returns %d\n", 67 curTick,tc->getCpuPtr()->name(), name, retval.value()); 68 69 if (!(flags & SyscallDesc::SuppressReturnValue)) 70 process->setSyscallReturn(tc, retval); 71} 72 73 74SyscallReturn 75unimplementedFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 76 ThreadContext *tc) 77{ 78 fatal("syscall %s (#%d) unimplemented.", desc->name, callnum); 79 80 return 1; 81} 82 83 84SyscallReturn 85ignoreFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 86 ThreadContext *tc) 87{ 88 int index = 0; 89 warn("ignoring syscall %s(%d, %d, ...)", desc->name, 90 process->getSyscallArg(tc, index), process->getSyscallArg(tc, index)); 91 92 return 0; 93} 94 95 96SyscallReturn 97exitFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 98 ThreadContext *tc) 99{ 100 if (process->system->numRunningContexts() == 1) { 101 // Last running context... exit simulator 102 int index = 0; 103 exitSimLoop("target called exit()", 104 process->getSyscallArg(tc, index) & 0xff); 105 } else { 106 // other running threads... just halt this one 107 tc->halt(); 108 } 109 110 return 1; 111} 112 113 114SyscallReturn 115exitGroupFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 116 ThreadContext *tc) 117{ 118 // really should just halt all thread contexts belonging to this 119 // process in case there's another process running... 120 int index = 0; 121 exitSimLoop("target called exit()", 122 process->getSyscallArg(tc, index) & 0xff); 123 124 return 1; 125} 126 127 128SyscallReturn 129getpagesizeFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc) 130{ 131 return (int)VMPageSize; 132} 133 134 135SyscallReturn 136brkFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc) 137{ 138 // change brk addr to first arg 139 int index = 0; 140 Addr new_brk = p->getSyscallArg(tc, index); 141 142 // in Linux at least, brk(0) returns the current break value 143 // (note that the syscall and the glibc function have different behavior) 144 if (new_brk == 0) 145 return p->brk_point; 146 147 if (new_brk > p->brk_point) { 148 // might need to allocate some new pages 149 for (ChunkGenerator gen(p->brk_point, new_brk - p->brk_point, 150 VMPageSize); !gen.done(); gen.next()) { 151 if (!p->pTable->translate(gen.addr())) 152 p->pTable->allocate(roundDown(gen.addr(), VMPageSize), 153 VMPageSize); 154 155 // if the address is already there, zero it out 156 else { 157 uint8_t zero = 0; 158 TranslatingPort *tp = tc->getMemPort(); 159 160 // split non-page aligned accesses 161 Addr next_page = roundUp(gen.addr(), VMPageSize); 162 uint32_t size_needed = next_page - gen.addr(); 163 tp->memsetBlob(gen.addr(), zero, size_needed); 164 if (gen.addr() + VMPageSize > next_page && 165 next_page < new_brk && 166 p->pTable->translate(next_page)) 167 { 168 size_needed = VMPageSize - size_needed; 169 tp->memsetBlob(next_page, zero, size_needed); 170 } 171 } 172 } 173 } 174 175 p->brk_point = new_brk; 176 DPRINTF(SyscallVerbose, "Break Point changed to: %#X\n", p->brk_point); 177 return p->brk_point; 178} 179 180 181SyscallReturn 182closeFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc) 183{ 184 int index = 0; 185 int target_fd = p->getSyscallArg(tc, index); 186 int status = close(p->sim_fd(target_fd)); 187 if (status >= 0) 188 p->free_fd(target_fd); 189 return status; 190} 191 192 193SyscallReturn 194readFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc) 195{ 196 int index = 0; 197 int fd = p->sim_fd(p->getSyscallArg(tc, index)); 198 Addr bufPtr = p->getSyscallArg(tc, index); 199 int nbytes = p->getSyscallArg(tc, index); 200 BufferArg bufArg(bufPtr, nbytes); 201 202 int bytes_read = read(fd, bufArg.bufferPtr(), nbytes); 203 204 if (bytes_read != -1) 205 bufArg.copyOut(tc->getMemPort()); 206 207 return bytes_read; 208} 209 210SyscallReturn 211writeFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc) 212{ 213 int index = 0; 214 int fd = p->sim_fd(p->getSyscallArg(tc, index)); 215 Addr bufPtr = p->getSyscallArg(tc, index); 216 int nbytes = p->getSyscallArg(tc, index); 217 BufferArg bufArg(bufPtr, nbytes); 218 219 bufArg.copyIn(tc->getMemPort()); 220 221 int bytes_written = write(fd, bufArg.bufferPtr(), nbytes); 222 223 fsync(fd); 224 225 return bytes_written; 226} 227 228 229SyscallReturn 230lseekFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc) 231{ 232 int index = 0; 233 int fd = p->sim_fd(p->getSyscallArg(tc, index)); 234 uint64_t offs = p->getSyscallArg(tc, index); 235 int whence = p->getSyscallArg(tc, index); 236 237 off_t result = lseek(fd, offs, whence); 238 239 return (result == (off_t)-1) ? -errno : result; 240} 241 242 243SyscallReturn 244_llseekFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc) 245{ 246 int index = 0; 247 int fd = p->sim_fd(p->getSyscallArg(tc, index)); 248 uint64_t offset_high = p->getSyscallArg(tc, index); 249 uint32_t offset_low = p->getSyscallArg(tc, index); 250 Addr result_ptr = p->getSyscallArg(tc, index); 251 int whence = p->getSyscallArg(tc, index); 252 253 uint64_t offset = (offset_high << 32) | offset_low; 254 255 uint64_t result = lseek(fd, offset, whence); 256 result = TheISA::htog(result); 257 258 if (result == (off_t)-1) { 259 //The seek failed. 260 return -errno; 261 } else { 262 // The seek succeeded. 263 // Copy "result" to "result_ptr" 264 // XXX We'll assume that the size of loff_t is 64 bits on the 265 // target platform 266 BufferArg result_buf(result_ptr, sizeof(result)); 267 memcpy(result_buf.bufferPtr(), &result, sizeof(result)); 268 result_buf.copyOut(tc->getMemPort()); 269 return 0; 270 } 271 272 273 return (result == (off_t)-1) ? -errno : result; 274} 275 276 277SyscallReturn 278munmapFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc) 279{ 280 // given that we don't really implement mmap, munmap is really easy 281 return 0; 282} 283 284 285const char *hostname = "m5.eecs.umich.edu"; 286 287SyscallReturn 288gethostnameFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc) 289{ 290 int index = 0; 291 Addr bufPtr = p->getSyscallArg(tc, index); 292 int name_len = p->getSyscallArg(tc, index); 293 BufferArg name(bufPtr, name_len); 294 295 strncpy((char *)name.bufferPtr(), hostname, name_len); 296 297 name.copyOut(tc->getMemPort()); 298 299 return 0; 300} 301 302SyscallReturn 303getcwdFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc) 304{ 305 int result = 0; 306 int index; 307 Addr bufPtr = p->getSyscallArg(tc, index); 308 unsigned long size = p->getSyscallArg(tc, index); 309 BufferArg buf(bufPtr, size); 310 311 // Is current working directory defined? 312 string cwd = p->getcwd(); 313 if (!cwd.empty()) { 314 if (cwd.length() >= size) { 315 // Buffer too small 316 return -ERANGE; 317 } 318 strncpy((char *)buf.bufferPtr(), cwd.c_str(), size); 319 result = cwd.length(); 320 } 321 else { 322 if (getcwd((char *)buf.bufferPtr(), size) != NULL) { 323 result = strlen((char *)buf.bufferPtr()); 324 } 325 else { 326 result = -1; 327 } 328 } 329 330 buf.copyOut(tc->getMemPort()); 331 332 return (result == -1) ? -errno : result; 333} 334 335 336SyscallReturn 337readlinkFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc) 338{ 339 string path; 340 341 int index = 0; 342 if (!tc->getMemPort()->tryReadString(path, p->getSyscallArg(tc, index))) 343 return (TheISA::IntReg)-EFAULT; 344 345 // Adjust path for current working directory 346 path = p->fullPath(path); 347 348 Addr bufPtr = p->getSyscallArg(tc, index); 349 size_t bufsiz = p->getSyscallArg(tc, index); 350 351 BufferArg buf(bufPtr, bufsiz); 352 353 int result = readlink(path.c_str(), (char *)buf.bufferPtr(), bufsiz); 354 355 buf.copyOut(tc->getMemPort()); 356 357 return (result == -1) ? -errno : result; 358} 359 360SyscallReturn 361unlinkFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc) 362{ 363 string path; 364 365 int index = 0; 366 if (!tc->getMemPort()->tryReadString(path, p->getSyscallArg(tc, index))) 367 return (TheISA::IntReg)-EFAULT; 368 369 // Adjust path for current working directory 370 path = p->fullPath(path); 371 372 int result = unlink(path.c_str()); 373 return (result == -1) ? -errno : result; 374} 375 376 377SyscallReturn 378mkdirFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc) 379{ 380 string path; 381 382 int index = 0; 383 if (!tc->getMemPort()->tryReadString(path, p->getSyscallArg(tc, index))) 384 return (TheISA::IntReg)-EFAULT; 385 386 // Adjust path for current working directory 387 path = p->fullPath(path); 388 389 mode_t mode = p->getSyscallArg(tc, index); 390 391 int result = mkdir(path.c_str(), mode); 392 return (result == -1) ? -errno : result; 393} 394 395SyscallReturn 396renameFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc) 397{ 398 string old_name; 399 400 int index = 0; 401 if (!tc->getMemPort()->tryReadString(old_name, p->getSyscallArg(tc, index))) 402 return -EFAULT; 403 404 string new_name; 405 406 if (!tc->getMemPort()->tryReadString(new_name, p->getSyscallArg(tc, index))) 407 return -EFAULT; 408 409 // Adjust path for current working directory 410 old_name = p->fullPath(old_name); 411 new_name = p->fullPath(new_name); 412 413 int64_t result = rename(old_name.c_str(), new_name.c_str()); 414 return (result == -1) ? -errno : result; 415} 416 417SyscallReturn 418truncateFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc) 419{ 420 string path; 421 422 int index = 0; 423 if (!tc->getMemPort()->tryReadString(path, p->getSyscallArg(tc, index))) 424 return -EFAULT; 425 426 off_t length = p->getSyscallArg(tc, index); 427 428 // Adjust path for current working directory 429 path = p->fullPath(path); 430 431 int result = truncate(path.c_str(), length); 432 return (result == -1) ? -errno : result; 433} 434 435SyscallReturn 436ftruncateFunc(SyscallDesc *desc, int num, 437 LiveProcess *process, ThreadContext *tc) 438{ 439 int index = 0; 440 int fd = process->sim_fd(process->getSyscallArg(tc, index)); 441 442 if (fd < 0) 443 return -EBADF; 444 445 off_t length = process->getSyscallArg(tc, index); 446 447 int result = ftruncate(fd, length); 448 return (result == -1) ? -errno : result; 449} 450 451SyscallReturn 452ftruncate64Func(SyscallDesc *desc, int num, 453 LiveProcess *process, ThreadContext *tc) 454{ 455 int index = 0; 456 int fd = process->sim_fd(process->getSyscallArg(tc, index)); 457 458 if (fd < 0) 459 return -EBADF; 460 461 loff_t length = process->getSyscallArg(tc, index, 64); 462 463 int result = ftruncate64(fd, length); 464 return (result == -1) ? -errno : result; 465} 466 467SyscallReturn 468umaskFunc(SyscallDesc *desc, int num, LiveProcess *process, ThreadContext *tc) 469{ 470 // Letting the simulated program change the simulator's umask seems like 471 // a bad idea. Compromise by just returning the current umask but not 472 // changing anything. 473 mode_t oldMask = umask(0); 474 umask(oldMask); 475 return (int)oldMask; 476} 477 478SyscallReturn 479chownFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc) 480{ 481 string path; 482 483 int index = 0; 484 if (!tc->getMemPort()->tryReadString(path, p->getSyscallArg(tc, index))) 485 return -EFAULT; 486 487 /* XXX endianess */ 488 uint32_t owner = p->getSyscallArg(tc, index); 489 uid_t hostOwner = owner; 490 uint32_t group = p->getSyscallArg(tc, index); 491 gid_t hostGroup = group; 492 493 // Adjust path for current working directory 494 path = p->fullPath(path); 495 496 int result = chown(path.c_str(), hostOwner, hostGroup); 497 return (result == -1) ? -errno : result; 498} 499 500SyscallReturn 501fchownFunc(SyscallDesc *desc, int num, LiveProcess *process, ThreadContext *tc) 502{ 503 int index = 0; 504 int fd = process->sim_fd(process->getSyscallArg(tc, index)); 505 506 if (fd < 0) 507 return -EBADF; 508 509 /* XXX endianess */ 510 uint32_t owner = process->getSyscallArg(tc, index); 511 uid_t hostOwner = owner; 512 uint32_t group = process->getSyscallArg(tc, index); 513 gid_t hostGroup = group; 514 515 int result = fchown(fd, hostOwner, hostGroup); 516 return (result == -1) ? -errno : result; 517} 518 519 520SyscallReturn 521dupFunc(SyscallDesc *desc, int num, LiveProcess *process, ThreadContext *tc) 522{ 523 int index = 0; 524 int fd = process->sim_fd(process->getSyscallArg(tc, index)); 525 if (fd < 0) 526 return -EBADF; 527 528 Process::FdMap *fdo = process->sim_fd_obj(fd); 529 530 int result = dup(fd); 531 return (result == -1) ? -errno : 532 process->alloc_fd(result, fdo->filename, fdo->flags, fdo->mode, false); 533} 534 535 536SyscallReturn 537fcntlFunc(SyscallDesc *desc, int num, LiveProcess *process, 538 ThreadContext *tc) 539{ 540 int index = 0; 541 int fd = process->getSyscallArg(tc, index); 542 543 if (fd < 0 || process->sim_fd(fd) < 0) 544 return -EBADF; 545 546 int cmd = process->getSyscallArg(tc, index); 547 switch (cmd) { 548 case 0: // F_DUPFD 549 // if we really wanted to support this, we'd need to do it 550 // in the target fd space. 551 warn("fcntl(%d, F_DUPFD) not supported, error returned\n", fd); 552 return -EMFILE; 553 554 case 1: // F_GETFD (get close-on-exec flag) 555 case 2: // F_SETFD (set close-on-exec flag) 556 return 0; 557 558 case 3: // F_GETFL (get file flags) 559 case 4: // F_SETFL (set file flags) 560 // not sure if this is totally valid, but we'll pass it through 561 // to the underlying OS 562 warn("fcntl(%d, %d) passed through to host\n", fd, cmd); 563 return fcntl(process->sim_fd(fd), cmd); 564 // return 0; 565 566 case 7: // F_GETLK (get lock) 567 case 8: // F_SETLK (set lock) 568 case 9: // F_SETLKW (set lock and wait) 569 // don't mess with file locking... just act like it's OK 570 warn("File lock call (fcntl(%d, %d)) ignored.\n", fd, cmd); 571 return 0; 572 573 default: 574 warn("Unknown fcntl command %d\n", cmd); 575 return 0; 576 } 577} 578 579SyscallReturn 580fcntl64Func(SyscallDesc *desc, int num, LiveProcess *process, 581 ThreadContext *tc) 582{ 583 int index = 0; 584 int fd = process->getSyscallArg(tc, index); 585 586 if (fd < 0 || process->sim_fd(fd) < 0) 587 return -EBADF; 588 589 int cmd = process->getSyscallArg(tc, index); 590 switch (cmd) { 591 case 33: //F_GETLK64 592 warn("fcntl64(%d, F_GETLK64) not supported, error returned\n", fd); 593 return -EMFILE; 594 595 case 34: // F_SETLK64 596 case 35: // F_SETLKW64 597 warn("fcntl64(%d, F_SETLK(W)64) not supported, error returned\n", fd); 598 return -EMFILE; 599 600 default: 601 // not sure if this is totally valid, but we'll pass it through 602 // to the underlying OS 603 warn("fcntl64(%d, %d) passed through to host\n", fd, cmd); 604 return fcntl(process->sim_fd(fd), cmd); 605 // return 0; 606 } 607} 608 609SyscallReturn 610pipePseudoFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 611 ThreadContext *tc) 612{ 613 int fds[2], sim_fds[2]; 614 int pipe_retval = pipe(fds); 615 616 if (pipe_retval < 0) { 617 // error 618 return pipe_retval; 619 } 620 621 sim_fds[0] = process->alloc_fd(fds[0], "PIPE-READ", O_WRONLY, -1, true); 622 sim_fds[1] = process->alloc_fd(fds[1], "PIPE-WRITE", O_RDONLY, -1, true); 623 624 process->setReadPipeSource(sim_fds[0], sim_fds[1]); 625 // Alpha Linux convention for pipe() is that fd[0] is returned as 626 // the return value of the function, and fd[1] is returned in r20. 627 tc->setIntReg(SyscallPseudoReturnReg, sim_fds[1]); 628 return sim_fds[0]; 629} 630 631 632SyscallReturn 633getpidPseudoFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 634 ThreadContext *tc) 635{ 636 // Make up a PID. There's no interprocess communication in 637 // fake_syscall mode, so there's no way for a process to know it's 638 // not getting a unique value. 639 640 tc->setIntReg(SyscallPseudoReturnReg, process->ppid()); 641 return process->pid(); 642} 643 644 645SyscallReturn 646getuidPseudoFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 647 ThreadContext *tc) 648{ 649 // Make up a UID and EUID... it shouldn't matter, and we want the 650 // simulation to be deterministic. 651 652 // EUID goes in r20. 653 tc->setIntReg(SyscallPseudoReturnReg, process->euid()); //EUID 654 return process->uid(); // UID 655} 656 657 658SyscallReturn 659getgidPseudoFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 660 ThreadContext *tc) 661{ 662 // Get current group ID. EGID goes in r20. 663 tc->setIntReg(SyscallPseudoReturnReg, process->egid()); //EGID 664 return process->gid(); 665} 666 667 668SyscallReturn 669setuidFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 670 ThreadContext *tc) 671{ 672 // can't fathom why a benchmark would call this. 673 int index = 0; 674 warn("Ignoring call to setuid(%d)\n", process->getSyscallArg(tc, index)); 675 return 0; 676} 677 678SyscallReturn 679getpidFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 680 ThreadContext *tc) 681{ 682 // Make up a PID. There's no interprocess communication in 683 // fake_syscall mode, so there's no way for a process to know it's 684 // not getting a unique value. 685 686 tc->setIntReg(SyscallPseudoReturnReg, process->ppid()); //PID 687 return process->pid(); 688} 689 690SyscallReturn 691getppidFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 692 ThreadContext *tc) 693{ 694 return process->ppid(); 695} 696 697SyscallReturn 698getuidFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 699 ThreadContext *tc) 700{ 701 return process->uid(); // UID 702} 703 704SyscallReturn 705geteuidFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 706 ThreadContext *tc) 707{ 708 return process->euid(); // UID 709} 710 711SyscallReturn 712getgidFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 713 ThreadContext *tc) 714{ 715 return process->gid(); 716} 717 718SyscallReturn 719getegidFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 720 ThreadContext *tc) 721{ 722 return process->egid(); 723} 724 725 726SyscallReturn 727cloneFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 728 ThreadContext *tc) 729{ 730 int index = 0; 731 IntReg flags = process->getSyscallArg(tc, index); 732 IntReg newStack = process->getSyscallArg(tc, index); 733 734 DPRINTF(SyscallVerbose, "In sys_clone:\n"); 735 DPRINTF(SyscallVerbose, " Flags=%llx\n", flags); 736 DPRINTF(SyscallVerbose, " Child stack=%llx\n", newStack); 737 738 739 if (flags != 0x10f00) { 740 warn("This sys_clone implementation assumes flags " 741 "CLONE_VM|CLONE_FS|CLONE_FILES|CLONE_SIGHAND|CLONE_THREAD " 742 "(0x10f00), and may not work correctly with given flags " 743 "0x%llx\n", flags); 744 } 745 746 ThreadContext* ctc; // child thread context 747 if ( ( ctc = process->findFreeContext() ) != NULL ) { 748 DPRINTF(SyscallVerbose, " Found unallocated thread context\n"); 749 750 ctc->clearArchRegs(); 751 752 // Arch-specific cloning code 753 #if THE_ISA == ALPHA_ISA or THE_ISA == X86_ISA 754 // Cloning the misc. regs for these archs is enough 755 TheISA::copyMiscRegs(tc, ctc); 756 #elif THE_ISA == SPARC_ISA 757 TheISA::copyRegs(tc, ctc); 758 759 // TODO: Explain what this code actually does :-) 760 ctc->setIntReg(NumIntArchRegs + 6, 0); 761 ctc->setIntReg(NumIntArchRegs + 4, 0); 762 ctc->setIntReg(NumIntArchRegs + 3, NWindows - 2); 763 ctc->setIntReg(NumIntArchRegs + 5, NWindows); 764 ctc->setMiscReg(MISCREG_CWP, 0); 765 ctc->setIntReg(NumIntArchRegs + 7, 0); 766 ctc->setMiscRegNoEffect(MISCREG_TL, 0); 767 ctc->setMiscRegNoEffect(MISCREG_ASI, ASI_PRIMARY); 768 769 for (int y = 8; y < 32; y++) 770 ctc->setIntReg(y, tc->readIntReg(y)); 771 #else 772 fatal("sys_clone is not implemented for this ISA\n"); 773 #endif 774 775 // Set up stack register 776 ctc->setIntReg(TheISA::StackPointerReg, newStack); 777 778 // Set up syscall return values in parent and child 779 ctc->setIntReg(ReturnValueReg, 0); // return value, child 780 781 // Alpha needs SyscallSuccessReg=0 in child 782 #if THE_ISA == ALPHA_ISA 783 ctc->setIntReg(TheISA::SyscallSuccessReg, 0); 784 #endif 785 786 // In SPARC/Linux, clone returns 0 on pseudo-return register if 787 // parent, non-zero if child 788 #if THE_ISA == SPARC_ISA 789 tc->setIntReg(TheISA::SyscallPseudoReturnReg, 0); 790 ctc->setIntReg(TheISA::SyscallPseudoReturnReg, 1); 791 #endif 792 793 ctc->setPC(tc->readNextPC()); 794 ctc->setNextPC(tc->readNextPC() + sizeof(TheISA::MachInst)); 795 ctc->setNextNPC(tc->readNextNPC() + sizeof(TheISA::MachInst)); 796 797 ctc->activate(); 798 799 // Should return nonzero child TID in parent's syscall return register, 800 // but for our pthread library any non-zero value will work 801 return 1; 802 } else { 803 fatal("Called sys_clone, but no unallocated thread contexts found!\n"); 804 return 0; 805 } 806} 807 808