70#include "sim/system.hh" 71 72#if THE_ISA == ALPHA_ISA 73#include "arch/alpha/linux/process.hh" 74#elif THE_ISA == SPARC_ISA 75#include "arch/sparc/linux/process.hh" 76#include "arch/sparc/solaris/process.hh" 77#elif THE_ISA == MIPS_ISA 78#include "arch/mips/linux/process.hh" 79#elif THE_ISA == ARM_ISA 80#include "arch/arm/linux/process.hh" 81#include "arch/arm/freebsd/process.hh" 82#elif THE_ISA == X86_ISA 83#include "arch/x86/linux/process.hh" 84#elif THE_ISA == POWER_ISA 85#include "arch/power/linux/process.hh" 86#elif THE_ISA == RISCV_ISA 87#include "arch/riscv/linux/process.hh" 88#else 89#error "THE_ISA not set" 90#endif 91 92 93using namespace std; 94using namespace TheISA; 95 96// current number of allocated processes 97int num_processes = 0; 98 99template<class IntType> 100 101AuxVector<IntType>::AuxVector(IntType type, IntType val) 102{ 103 a_type = TheISA::htog(type); 104 a_val = TheISA::htog(val); 105} 106 107template struct AuxVector<uint32_t>; 108template struct AuxVector<uint64_t>; 109 110static int 111openFile(const string& filename, int flags, mode_t mode) 112{ 113 int sim_fd = open(filename.c_str(), flags, mode); 114 if (sim_fd != -1) 115 return sim_fd; 116 fatal("Unable to open %s with mode %O", filename, mode); 117} 118 119static int 120openInputFile(const string &filename) 121{ 122 return openFile(filename, O_RDONLY, 0); 123} 124 125static int 126openOutputFile(const string &filename) 127{ 128 return openFile(filename, O_WRONLY | O_CREAT | O_TRUNC, 0664); 129} 130 131Process::Process(ProcessParams * params) 132 : SimObject(params), system(params->system), 133 brk_point(0), stack_base(0), stack_size(0), stack_min(0), 134 max_stack_size(params->max_stack_size), 135 next_thread_stack_base(0), 136 M5_pid(system->allocatePID()), 137 useArchPT(params->useArchPT), 138 kvmInSE(params->kvmInSE), 139 pTable(useArchPT ? 140 static_cast<PageTableBase *>(new ArchPageTable(name(), M5_pid, system)) : 141 static_cast<PageTableBase *>(new FuncPageTable(name(), M5_pid)) ), 142 initVirtMem(system->getSystemPort(), this, 143 SETranslatingPortProxy::Always), 144 fd_array(make_shared<array<FDEntry, NUM_FDS>>()), 145 imap {{"", -1}, 146 {"cin", STDIN_FILENO}, 147 {"stdin", STDIN_FILENO}}, 148 oemap{{"", -1}, 149 {"cout", STDOUT_FILENO}, 150 {"stdout", STDOUT_FILENO}, 151 {"cerr", STDERR_FILENO}, 152 {"stderr", STDERR_FILENO}} 153{ 154 int sim_fd; 155 std::map<string,int>::iterator it; 156 157 // Search through the input options and set fd if match is found; 158 // otherwise, open an input file and seek to location. 159 FDEntry *fde_stdin = getFDEntry(STDIN_FILENO); 160 if ((it = imap.find(params->input)) != imap.end()) 161 sim_fd = it->second; 162 else 163 sim_fd = openInputFile(params->input); 164 fde_stdin->set(sim_fd, params->input, O_RDONLY, -1, false); 165 166 // Search through the output/error options and set fd if match is found; 167 // otherwise, open an output file and seek to location. 168 FDEntry *fde_stdout = getFDEntry(STDOUT_FILENO); 169 if ((it = oemap.find(params->output)) != oemap.end()) 170 sim_fd = it->second; 171 else 172 sim_fd = openOutputFile(params->output); 173 fde_stdout->set(sim_fd, params->output, O_WRONLY | O_CREAT | O_TRUNC, 174 0664, false); 175 176 FDEntry *fde_stderr = getFDEntry(STDERR_FILENO); 177 if (params->output == params->errout) 178 // Reuse the same file descriptor if these match. 179 sim_fd = fde_stdout->fd; 180 else if ((it = oemap.find(params->errout)) != oemap.end()) 181 sim_fd = it->second; 182 else 183 sim_fd = openOutputFile(params->errout); 184 fde_stderr->set(sim_fd, params->errout, O_WRONLY | O_CREAT | O_TRUNC, 185 0664, false); 186 187 mmap_end = 0; 188 nxm_start = nxm_end = 0; 189 // other parameters will be initialized when the program is loaded 190} 191 192 193void 194Process::regStats() 195{ 196 SimObject::regStats(); 197 198 using namespace Stats; 199 200 num_syscalls 201 .name(name() + ".num_syscalls") 202 .desc("Number of system calls") 203 ; 204} 205 206void 207Process::inheritFDArray(Process *p) 208{ 209 fd_array = p->fd_array; 210} 211 212ThreadContext * 213Process::findFreeContext() 214{ 215 for (int id : contextIds) { 216 ThreadContext *tc = system->getThreadContext(id); 217 if (tc->status() == ThreadContext::Halted) 218 return tc; 219 } 220 return NULL; 221} 222 223void 224Process::initState() 225{ 226 if (contextIds.empty()) 227 fatal("Process %s is not associated with any HW contexts!\n", name()); 228 229 // first thread context for this process... initialize & enable 230 ThreadContext *tc = system->getThreadContext(contextIds[0]); 231 232 // mark this context as active so it will start ticking. 233 tc->activate(); 234 235 pTable->initState(tc); 236} 237 238DrainState 239Process::drain() 240{ 241 findFileOffsets(); 242 return DrainState::Drained; 243} 244 245int 246Process::allocFD(int sim_fd, const string& filename, int flags, int mode, 247 bool pipe) 248{ 249 for (int free_fd = 0; free_fd < fd_array->size(); free_fd++) { 250 FDEntry *fde = getFDEntry(free_fd); 251 if (fde->isFree()) { 252 fde->set(sim_fd, filename, flags, mode, pipe); 253 return free_fd; 254 } 255 } 256 257 fatal("Out of target file descriptors"); 258} 259 260void 261Process::resetFDEntry(int tgt_fd) 262{ 263 FDEntry *fde = getFDEntry(tgt_fd); 264 assert(fde->fd > -1); 265 266 fde->reset(); 267} 268 269int 270Process::getSimFD(int tgt_fd) 271{ 272 FDEntry *entry = getFDEntry(tgt_fd); 273 return entry ? entry->fd : -1; 274} 275 276FDEntry * 277Process::getFDEntry(int tgt_fd) 278{ 279 assert(0 <= tgt_fd && tgt_fd < fd_array->size()); 280 return &(*fd_array)[tgt_fd]; 281} 282 283int 284Process::getTgtFD(int sim_fd) 285{ 286 for (int index = 0; index < fd_array->size(); index++) 287 if ((*fd_array)[index].fd == sim_fd) 288 return index; 289 return -1; 290} 291 292void 293Process::allocateMem(Addr vaddr, int64_t size, bool clobber) 294{ 295 int npages = divCeil(size, (int64_t)PageBytes); 296 Addr paddr = system->allocPhysPages(npages); 297 pTable->map(vaddr, paddr, size, 298 clobber ? PageTableBase::Clobber : PageTableBase::Zero); 299} 300 301bool 302Process::fixupStackFault(Addr vaddr) 303{ 304 // Check if this is already on the stack and there's just no page there 305 // yet. 306 if (vaddr >= stack_min && vaddr < stack_base) { 307 allocateMem(roundDown(vaddr, PageBytes), PageBytes); 308 return true; 309 } 310 311 // We've accessed the next page of the stack, so extend it to include 312 // this address. 313 if (vaddr < stack_min && vaddr >= stack_base - max_stack_size) { 314 while (vaddr < stack_min) { 315 stack_min -= TheISA::PageBytes; 316 if (stack_base - stack_min > max_stack_size) 317 fatal("Maximum stack size exceeded\n"); 318 allocateMem(stack_min, TheISA::PageBytes); 319 inform("Increasing stack size by one page."); 320 }; 321 return true; 322 } 323 return false; 324} 325 326void 327Process::fixFileOffsets() 328{ 329 auto seek = [] (FDEntry *fde) 330 { 331 if (lseek(fde->fd, fde->fileOffset, SEEK_SET) < 0) 332 fatal("Unable to see to location in %s", fde->filename); 333 }; 334 335 std::map<string,int>::iterator it; 336 337 // Search through the input options and set fd if match is found; 338 // otherwise, open an input file and seek to location. 339 FDEntry *fde_stdin = getFDEntry(STDIN_FILENO); 340 341 // Check if user has specified a different input file, and if so, use it 342 // instead of the file specified in the checkpoint. This also resets the 343 // file offset from the checkpointed value 344 string new_in = ((ProcessParams*)params())->input; 345 if (new_in != fde_stdin->filename) { 346 warn("Using new input file (%s) rather than checkpointed (%s)\n", 347 new_in, fde_stdin->filename); 348 fde_stdin->filename = new_in; 349 fde_stdin->fileOffset = 0; 350 } 351 352 if ((it = imap.find(fde_stdin->filename)) != imap.end()) { 353 fde_stdin->fd = it->second; 354 } else { 355 fde_stdin->fd = openInputFile(fde_stdin->filename); 356 seek(fde_stdin); 357 } 358 359 // Search through the output/error options and set fd if match is found; 360 // otherwise, open an output file and seek to location. 361 FDEntry *fde_stdout = getFDEntry(STDOUT_FILENO); 362 363 // Check if user has specified a different output file, and if so, use it 364 // instead of the file specified in the checkpoint. This also resets the 365 // file offset from the checkpointed value 366 string new_out = ((ProcessParams*)params())->output; 367 if (new_out != fde_stdout->filename) { 368 warn("Using new output file (%s) rather than checkpointed (%s)\n", 369 new_out, fde_stdout->filename); 370 fde_stdout->filename = new_out; 371 fde_stdout->fileOffset = 0; 372 } 373 374 if ((it = oemap.find(fde_stdout->filename)) != oemap.end()) { 375 fde_stdout->fd = it->second; 376 } else { 377 fde_stdout->fd = openOutputFile(fde_stdout->filename); 378 seek(fde_stdout); 379 } 380 381 FDEntry *fde_stderr = getFDEntry(STDERR_FILENO); 382 383 // Check if user has specified a different error file, and if so, use it 384 // instead of the file specified in the checkpoint. This also resets the 385 // file offset from the checkpointed value 386 string new_err = ((ProcessParams*)params())->errout; 387 if (new_err != fde_stderr->filename) { 388 warn("Using new error file (%s) rather than checkpointed (%s)\n", 389 new_err, fde_stderr->filename); 390 fde_stderr->filename = new_err; 391 fde_stderr->fileOffset = 0; 392 } 393 394 if (fde_stdout->filename == fde_stderr->filename) { 395 // Reuse the same file descriptor if these match. 396 fde_stderr->fd = fde_stdout->fd; 397 } else if ((it = oemap.find(fde_stderr->filename)) != oemap.end()) { 398 fde_stderr->fd = it->second; 399 } else { 400 fde_stderr->fd = openOutputFile(fde_stderr->filename); 401 seek(fde_stderr); 402 } 403 404 for (int tgt_fd = 3; tgt_fd < fd_array->size(); tgt_fd++) { 405 FDEntry *fde = getFDEntry(tgt_fd); 406 if (fde->fd == -1) 407 continue; 408 409 if (fde->isPipe) { 410 if (fde->filename == "PIPE-WRITE") 411 continue; 412 assert(fde->filename == "PIPE-READ"); 413 414 int fds[2]; 415 if (pipe(fds) < 0) 416 fatal("Unable to create new pipe"); 417 418 fde->fd = fds[0]; 419 420 FDEntry *fde_write = getFDEntry(fde->readPipeSource); 421 assert(fde_write->filename == "PIPE-WRITE"); 422 fde_write->fd = fds[1]; 423 } else { 424 fde->fd = openFile(fde->filename.c_str(), fde->flags, fde->mode); 425 seek(fde); 426 } 427 } 428} 429 430void 431Process::findFileOffsets() 432{ 433 for (auto& fde : *fd_array) { 434 if (fde.fd != -1) 435 fde.fileOffset = lseek(fde.fd, 0, SEEK_CUR); 436 } 437} 438 439void 440Process::setReadPipeSource(int read_pipe_fd, int source_fd) 441{ 442 FDEntry *fde = getFDEntry(read_pipe_fd); 443 assert(source_fd >= -1); 444 fde->readPipeSource = source_fd; 445} 446 447void 448Process::serialize(CheckpointOut &cp) const 449{ 450 SERIALIZE_SCALAR(brk_point); 451 SERIALIZE_SCALAR(stack_base); 452 SERIALIZE_SCALAR(stack_size); 453 SERIALIZE_SCALAR(stack_min); 454 SERIALIZE_SCALAR(next_thread_stack_base); 455 SERIALIZE_SCALAR(mmap_end); 456 SERIALIZE_SCALAR(nxm_start); 457 SERIALIZE_SCALAR(nxm_end); 458 pTable->serialize(cp); 459 for (int x = 0; x < fd_array->size(); x++) { 460 (*fd_array)[x].serializeSection(cp, csprintf("FDEntry%d", x)); 461 } 462 SERIALIZE_SCALAR(M5_pid); 463 464} 465 466void 467Process::unserialize(CheckpointIn &cp) 468{ 469 UNSERIALIZE_SCALAR(brk_point); 470 UNSERIALIZE_SCALAR(stack_base); 471 UNSERIALIZE_SCALAR(stack_size); 472 UNSERIALIZE_SCALAR(stack_min); 473 UNSERIALIZE_SCALAR(next_thread_stack_base); 474 UNSERIALIZE_SCALAR(mmap_end); 475 UNSERIALIZE_SCALAR(nxm_start); 476 UNSERIALIZE_SCALAR(nxm_end); 477 pTable->unserialize(cp); 478 for (int x = 0; x < fd_array->size(); x++) { 479 FDEntry *fde = getFDEntry(x); 480 fde->unserializeSection(cp, csprintf("FDEntry%d", x)); 481 } 482 fixFileOffsets(); 483 UNSERIALIZE_OPT_SCALAR(M5_pid); 484 // The above returns a bool so that you could do something if you don't 485 // find the param in the checkpoint if you wanted to, like set a default 486 // but in this case we'll just stick with the instantiated value if not 487 // found. 488} 489 490 491bool 492Process::map(Addr vaddr, Addr paddr, int size, bool cacheable) 493{ 494 pTable->map(vaddr, paddr, size, 495 cacheable ? PageTableBase::Zero : PageTableBase::Uncacheable); 496 return true; 497} 498 499 500//////////////////////////////////////////////////////////////////////// 501// 502// LiveProcess member definitions 503// 504//////////////////////////////////////////////////////////////////////// 505 506 507LiveProcess::LiveProcess(LiveProcessParams *params, ObjectFile *_objFile) 508 : Process(params), objFile(_objFile), 509 argv(params->cmd), envp(params->env), cwd(params->cwd), 510 executable(params->executable), 511 __uid(params->uid), __euid(params->euid), 512 __gid(params->gid), __egid(params->egid), 513 __pid(params->pid), __ppid(params->ppid), 514 drivers(params->drivers) 515{ 516 517 // load up symbols, if any... these may be used for debugging or 518 // profiling. 519 if (!debugSymbolTable) { 520 debugSymbolTable = new SymbolTable(); 521 if (!objFile->loadGlobalSymbols(debugSymbolTable) || 522 !objFile->loadLocalSymbols(debugSymbolTable) || 523 !objFile->loadWeakSymbols(debugSymbolTable)) { 524 // didn't load any symbols 525 delete debugSymbolTable; 526 debugSymbolTable = NULL; 527 } 528 } 529} 530 531void 532LiveProcess::syscall(int64_t callnum, ThreadContext *tc) 533{ 534 num_syscalls++; 535 536 SyscallDesc *desc = getDesc(callnum); 537 if (desc == NULL) 538 fatal("Syscall %d out of range", callnum); 539 540 desc->doSyscall(callnum, this, tc); 541} 542 543IntReg 544LiveProcess::getSyscallArg(ThreadContext *tc, int &i, int width) 545{ 546 return getSyscallArg(tc, i); 547} 548 549 550EmulatedDriver * 551LiveProcess::findDriver(std::string filename) 552{ 553 for (EmulatedDriver *d : drivers) { 554 if (d->match(filename)) 555 return d; 556 } 557 558 return NULL; 559} 560 561void 562LiveProcess::updateBias() 563{ 564 ObjectFile *interp = objFile->getInterpreter(); 565 566 if (!interp || !interp->relocatable()) 567 return; 568 569 // Determine how large the interpreters footprint will be in the process 570 // address space. 571 Addr interp_mapsize = roundUp(interp->mapSize(), TheISA::PageBytes); 572 573 // We are allocating the memory area; set the bias to the lowest address 574 // in the allocated memory region. 575 Addr ld_bias = mmapGrowsDown() ? mmap_end - interp_mapsize : mmap_end; 576 577 // Adjust the process mmap area to give the interpreter room; the real 578 // execve system call would just invoke the kernel's internal mmap 579 // functions to make these adjustments. 580 mmap_end = mmapGrowsDown() ? ld_bias : mmap_end + interp_mapsize; 581 582 interp->updateBias(ld_bias); 583} 584 585 586ObjectFile * 587LiveProcess::getInterpreter() 588{ 589 return objFile->getInterpreter(); 590} 591 592 593Addr 594LiveProcess::getBias() 595{ 596 ObjectFile *interp = getInterpreter(); 597 598 return interp ? interp->bias() : objFile->bias(); 599} 600 601 602Addr 603LiveProcess::getStartPC() 604{ 605 ObjectFile *interp = getInterpreter(); 606 607 return interp ? interp->entryPoint() : objFile->entryPoint(); 608} 609 610 611LiveProcess * 612LiveProcess::create(LiveProcessParams * params) 613{ 614 LiveProcess *process = NULL; 615 616 // If not specified, set the executable parameter equal to the 617 // simulated system's zeroth command line parameter 618 if (params->executable == "") { 619 params->executable = params->cmd[0]; 620 } 621 622 ObjectFile *objFile = createObjectFile(params->executable); 623 if (objFile == NULL) { 624 fatal("Can't load object file %s", params->executable); 625 } 626 627#if THE_ISA == ALPHA_ISA 628 if (objFile->getArch() != ObjectFile::Alpha) 629 fatal("Object file architecture does not match compiled ISA (Alpha)."); 630 631 switch (objFile->getOpSys()) { 632 case ObjectFile::UnknownOpSys: 633 warn("Unknown operating system; assuming Linux."); 634 // fall through 635 case ObjectFile::Linux: 636 process = new AlphaLinuxProcess(params, objFile); 637 break; 638 639 default: 640 fatal("Unknown/unsupported operating system."); 641 } 642#elif THE_ISA == SPARC_ISA 643 if (objFile->getArch() != ObjectFile::SPARC64 && 644 objFile->getArch() != ObjectFile::SPARC32) 645 fatal("Object file architecture does not match compiled ISA (SPARC)."); 646 switch (objFile->getOpSys()) { 647 case ObjectFile::UnknownOpSys: 648 warn("Unknown operating system; assuming Linux."); 649 // fall through 650 case ObjectFile::Linux: 651 if (objFile->getArch() == ObjectFile::SPARC64) { 652 process = new Sparc64LinuxProcess(params, objFile); 653 } else { 654 process = new Sparc32LinuxProcess(params, objFile); 655 } 656 break; 657 658 659 case ObjectFile::Solaris: 660 process = new SparcSolarisProcess(params, objFile); 661 break; 662 663 default: 664 fatal("Unknown/unsupported operating system."); 665 } 666#elif THE_ISA == X86_ISA 667 if (objFile->getArch() != ObjectFile::X86_64 && 668 objFile->getArch() != ObjectFile::I386) 669 fatal("Object file architecture does not match compiled ISA (x86)."); 670 switch (objFile->getOpSys()) { 671 case ObjectFile::UnknownOpSys: 672 warn("Unknown operating system; assuming Linux."); 673 // fall through 674 case ObjectFile::Linux: 675 if (objFile->getArch() == ObjectFile::X86_64) { 676 process = new X86_64LinuxProcess(params, objFile); 677 } else { 678 process = new I386LinuxProcess(params, objFile); 679 } 680 break; 681 682 default: 683 fatal("Unknown/unsupported operating system."); 684 } 685#elif THE_ISA == MIPS_ISA 686 if (objFile->getArch() != ObjectFile::Mips) 687 fatal("Object file architecture does not match compiled ISA (MIPS)."); 688 switch (objFile->getOpSys()) { 689 case ObjectFile::UnknownOpSys: 690 warn("Unknown operating system; assuming Linux."); 691 // fall through 692 case ObjectFile::Linux: 693 process = new MipsLinuxProcess(params, objFile); 694 break; 695 696 default: 697 fatal("Unknown/unsupported operating system."); 698 } 699#elif THE_ISA == ARM_ISA 700 ObjectFile::Arch arch = objFile->getArch(); 701 if (arch != ObjectFile::Arm && arch != ObjectFile::Thumb && 702 arch != ObjectFile::Arm64) 703 fatal("Object file architecture does not match compiled ISA (ARM)."); 704 switch (objFile->getOpSys()) { 705 case ObjectFile::UnknownOpSys: 706 warn("Unknown operating system; assuming Linux."); 707 // fall through 708 case ObjectFile::Linux: 709 if (arch == ObjectFile::Arm64) { 710 process = new ArmLinuxProcess64(params, objFile, 711 objFile->getArch()); 712 } else { 713 process = new ArmLinuxProcess32(params, objFile, 714 objFile->getArch()); 715 } 716 break; 717 case ObjectFile::FreeBSD: 718 if (arch == ObjectFile::Arm64) { 719 process = new ArmFreebsdProcess64(params, objFile, 720 objFile->getArch()); 721 } else { 722 process = new ArmFreebsdProcess32(params, objFile, 723 objFile->getArch()); 724 } 725 break; 726 case ObjectFile::LinuxArmOABI: 727 fatal("M5 does not support ARM OABI binaries. Please recompile with an" 728 " EABI compiler."); 729 default: 730 fatal("Unknown/unsupported operating system."); 731 } 732#elif THE_ISA == POWER_ISA 733 if (objFile->getArch() != ObjectFile::Power) 734 fatal("Object file architecture does not match compiled ISA (Power)."); 735 switch (objFile->getOpSys()) { 736 case ObjectFile::UnknownOpSys: 737 warn("Unknown operating system; assuming Linux."); 738 // fall through 739 case ObjectFile::Linux: 740 process = new PowerLinuxProcess(params, objFile); 741 break; 742 743 default: 744 fatal("Unknown/unsupported operating system."); 745 } 746#elif THE_ISA == RISCV_ISA 747 if (objFile->getArch() != ObjectFile::Riscv) 748 fatal("Object file architecture does not match compiled ISA (RISCV)."); 749 switch (objFile->getOpSys()) { 750 case ObjectFile::UnknownOpSys: 751 warn("Unknown operating system; assuming Linux."); 752 // fall through 753 case ObjectFile::Linux: 754 process = new RiscvLinuxProcess(params, objFile); 755 break; 756 default: 757 fatal("Unknown/unsupported operating system."); 758 } 759#else 760#error "THE_ISA not set" 761#endif 762 763 if (process == NULL) 764 fatal("Unknown error creating process object."); 765 return process; 766} 767 768LiveProcess * 769LiveProcessParams::create() 770{ 771 return LiveProcess::create(this); 772}
| 70#include "sim/system.hh" 71 72#if THE_ISA == ALPHA_ISA 73#include "arch/alpha/linux/process.hh" 74#elif THE_ISA == SPARC_ISA 75#include "arch/sparc/linux/process.hh" 76#include "arch/sparc/solaris/process.hh" 77#elif THE_ISA == MIPS_ISA 78#include "arch/mips/linux/process.hh" 79#elif THE_ISA == ARM_ISA 80#include "arch/arm/linux/process.hh" 81#include "arch/arm/freebsd/process.hh" 82#elif THE_ISA == X86_ISA 83#include "arch/x86/linux/process.hh" 84#elif THE_ISA == POWER_ISA 85#include "arch/power/linux/process.hh" 86#elif THE_ISA == RISCV_ISA 87#include "arch/riscv/linux/process.hh" 88#else 89#error "THE_ISA not set" 90#endif 91 92 93using namespace std; 94using namespace TheISA; 95 96// current number of allocated processes 97int num_processes = 0; 98 99template<class IntType> 100 101AuxVector<IntType>::AuxVector(IntType type, IntType val) 102{ 103 a_type = TheISA::htog(type); 104 a_val = TheISA::htog(val); 105} 106 107template struct AuxVector<uint32_t>; 108template struct AuxVector<uint64_t>; 109 110static int 111openFile(const string& filename, int flags, mode_t mode) 112{ 113 int sim_fd = open(filename.c_str(), flags, mode); 114 if (sim_fd != -1) 115 return sim_fd; 116 fatal("Unable to open %s with mode %O", filename, mode); 117} 118 119static int 120openInputFile(const string &filename) 121{ 122 return openFile(filename, O_RDONLY, 0); 123} 124 125static int 126openOutputFile(const string &filename) 127{ 128 return openFile(filename, O_WRONLY | O_CREAT | O_TRUNC, 0664); 129} 130 131Process::Process(ProcessParams * params) 132 : SimObject(params), system(params->system), 133 brk_point(0), stack_base(0), stack_size(0), stack_min(0), 134 max_stack_size(params->max_stack_size), 135 next_thread_stack_base(0), 136 M5_pid(system->allocatePID()), 137 useArchPT(params->useArchPT), 138 kvmInSE(params->kvmInSE), 139 pTable(useArchPT ? 140 static_cast<PageTableBase *>(new ArchPageTable(name(), M5_pid, system)) : 141 static_cast<PageTableBase *>(new FuncPageTable(name(), M5_pid)) ), 142 initVirtMem(system->getSystemPort(), this, 143 SETranslatingPortProxy::Always), 144 fd_array(make_shared<array<FDEntry, NUM_FDS>>()), 145 imap {{"", -1}, 146 {"cin", STDIN_FILENO}, 147 {"stdin", STDIN_FILENO}}, 148 oemap{{"", -1}, 149 {"cout", STDOUT_FILENO}, 150 {"stdout", STDOUT_FILENO}, 151 {"cerr", STDERR_FILENO}, 152 {"stderr", STDERR_FILENO}} 153{ 154 int sim_fd; 155 std::map<string,int>::iterator it; 156 157 // Search through the input options and set fd if match is found; 158 // otherwise, open an input file and seek to location. 159 FDEntry *fde_stdin = getFDEntry(STDIN_FILENO); 160 if ((it = imap.find(params->input)) != imap.end()) 161 sim_fd = it->second; 162 else 163 sim_fd = openInputFile(params->input); 164 fde_stdin->set(sim_fd, params->input, O_RDONLY, -1, false); 165 166 // Search through the output/error options and set fd if match is found; 167 // otherwise, open an output file and seek to location. 168 FDEntry *fde_stdout = getFDEntry(STDOUT_FILENO); 169 if ((it = oemap.find(params->output)) != oemap.end()) 170 sim_fd = it->second; 171 else 172 sim_fd = openOutputFile(params->output); 173 fde_stdout->set(sim_fd, params->output, O_WRONLY | O_CREAT | O_TRUNC, 174 0664, false); 175 176 FDEntry *fde_stderr = getFDEntry(STDERR_FILENO); 177 if (params->output == params->errout) 178 // Reuse the same file descriptor if these match. 179 sim_fd = fde_stdout->fd; 180 else if ((it = oemap.find(params->errout)) != oemap.end()) 181 sim_fd = it->second; 182 else 183 sim_fd = openOutputFile(params->errout); 184 fde_stderr->set(sim_fd, params->errout, O_WRONLY | O_CREAT | O_TRUNC, 185 0664, false); 186 187 mmap_end = 0; 188 nxm_start = nxm_end = 0; 189 // other parameters will be initialized when the program is loaded 190} 191 192 193void 194Process::regStats() 195{ 196 SimObject::regStats(); 197 198 using namespace Stats; 199 200 num_syscalls 201 .name(name() + ".num_syscalls") 202 .desc("Number of system calls") 203 ; 204} 205 206void 207Process::inheritFDArray(Process *p) 208{ 209 fd_array = p->fd_array; 210} 211 212ThreadContext * 213Process::findFreeContext() 214{ 215 for (int id : contextIds) { 216 ThreadContext *tc = system->getThreadContext(id); 217 if (tc->status() == ThreadContext::Halted) 218 return tc; 219 } 220 return NULL; 221} 222 223void 224Process::initState() 225{ 226 if (contextIds.empty()) 227 fatal("Process %s is not associated with any HW contexts!\n", name()); 228 229 // first thread context for this process... initialize & enable 230 ThreadContext *tc = system->getThreadContext(contextIds[0]); 231 232 // mark this context as active so it will start ticking. 233 tc->activate(); 234 235 pTable->initState(tc); 236} 237 238DrainState 239Process::drain() 240{ 241 findFileOffsets(); 242 return DrainState::Drained; 243} 244 245int 246Process::allocFD(int sim_fd, const string& filename, int flags, int mode, 247 bool pipe) 248{ 249 for (int free_fd = 0; free_fd < fd_array->size(); free_fd++) { 250 FDEntry *fde = getFDEntry(free_fd); 251 if (fde->isFree()) { 252 fde->set(sim_fd, filename, flags, mode, pipe); 253 return free_fd; 254 } 255 } 256 257 fatal("Out of target file descriptors"); 258} 259 260void 261Process::resetFDEntry(int tgt_fd) 262{ 263 FDEntry *fde = getFDEntry(tgt_fd); 264 assert(fde->fd > -1); 265 266 fde->reset(); 267} 268 269int 270Process::getSimFD(int tgt_fd) 271{ 272 FDEntry *entry = getFDEntry(tgt_fd); 273 return entry ? entry->fd : -1; 274} 275 276FDEntry * 277Process::getFDEntry(int tgt_fd) 278{ 279 assert(0 <= tgt_fd && tgt_fd < fd_array->size()); 280 return &(*fd_array)[tgt_fd]; 281} 282 283int 284Process::getTgtFD(int sim_fd) 285{ 286 for (int index = 0; index < fd_array->size(); index++) 287 if ((*fd_array)[index].fd == sim_fd) 288 return index; 289 return -1; 290} 291 292void 293Process::allocateMem(Addr vaddr, int64_t size, bool clobber) 294{ 295 int npages = divCeil(size, (int64_t)PageBytes); 296 Addr paddr = system->allocPhysPages(npages); 297 pTable->map(vaddr, paddr, size, 298 clobber ? PageTableBase::Clobber : PageTableBase::Zero); 299} 300 301bool 302Process::fixupStackFault(Addr vaddr) 303{ 304 // Check if this is already on the stack and there's just no page there 305 // yet. 306 if (vaddr >= stack_min && vaddr < stack_base) { 307 allocateMem(roundDown(vaddr, PageBytes), PageBytes); 308 return true; 309 } 310 311 // We've accessed the next page of the stack, so extend it to include 312 // this address. 313 if (vaddr < stack_min && vaddr >= stack_base - max_stack_size) { 314 while (vaddr < stack_min) { 315 stack_min -= TheISA::PageBytes; 316 if (stack_base - stack_min > max_stack_size) 317 fatal("Maximum stack size exceeded\n"); 318 allocateMem(stack_min, TheISA::PageBytes); 319 inform("Increasing stack size by one page."); 320 }; 321 return true; 322 } 323 return false; 324} 325 326void 327Process::fixFileOffsets() 328{ 329 auto seek = [] (FDEntry *fde) 330 { 331 if (lseek(fde->fd, fde->fileOffset, SEEK_SET) < 0) 332 fatal("Unable to see to location in %s", fde->filename); 333 }; 334 335 std::map<string,int>::iterator it; 336 337 // Search through the input options and set fd if match is found; 338 // otherwise, open an input file and seek to location. 339 FDEntry *fde_stdin = getFDEntry(STDIN_FILENO); 340 341 // Check if user has specified a different input file, and if so, use it 342 // instead of the file specified in the checkpoint. This also resets the 343 // file offset from the checkpointed value 344 string new_in = ((ProcessParams*)params())->input; 345 if (new_in != fde_stdin->filename) { 346 warn("Using new input file (%s) rather than checkpointed (%s)\n", 347 new_in, fde_stdin->filename); 348 fde_stdin->filename = new_in; 349 fde_stdin->fileOffset = 0; 350 } 351 352 if ((it = imap.find(fde_stdin->filename)) != imap.end()) { 353 fde_stdin->fd = it->second; 354 } else { 355 fde_stdin->fd = openInputFile(fde_stdin->filename); 356 seek(fde_stdin); 357 } 358 359 // Search through the output/error options and set fd if match is found; 360 // otherwise, open an output file and seek to location. 361 FDEntry *fde_stdout = getFDEntry(STDOUT_FILENO); 362 363 // Check if user has specified a different output file, and if so, use it 364 // instead of the file specified in the checkpoint. This also resets the 365 // file offset from the checkpointed value 366 string new_out = ((ProcessParams*)params())->output; 367 if (new_out != fde_stdout->filename) { 368 warn("Using new output file (%s) rather than checkpointed (%s)\n", 369 new_out, fde_stdout->filename); 370 fde_stdout->filename = new_out; 371 fde_stdout->fileOffset = 0; 372 } 373 374 if ((it = oemap.find(fde_stdout->filename)) != oemap.end()) { 375 fde_stdout->fd = it->second; 376 } else { 377 fde_stdout->fd = openOutputFile(fde_stdout->filename); 378 seek(fde_stdout); 379 } 380 381 FDEntry *fde_stderr = getFDEntry(STDERR_FILENO); 382 383 // Check if user has specified a different error file, and if so, use it 384 // instead of the file specified in the checkpoint. This also resets the 385 // file offset from the checkpointed value 386 string new_err = ((ProcessParams*)params())->errout; 387 if (new_err != fde_stderr->filename) { 388 warn("Using new error file (%s) rather than checkpointed (%s)\n", 389 new_err, fde_stderr->filename); 390 fde_stderr->filename = new_err; 391 fde_stderr->fileOffset = 0; 392 } 393 394 if (fde_stdout->filename == fde_stderr->filename) { 395 // Reuse the same file descriptor if these match. 396 fde_stderr->fd = fde_stdout->fd; 397 } else if ((it = oemap.find(fde_stderr->filename)) != oemap.end()) { 398 fde_stderr->fd = it->second; 399 } else { 400 fde_stderr->fd = openOutputFile(fde_stderr->filename); 401 seek(fde_stderr); 402 } 403 404 for (int tgt_fd = 3; tgt_fd < fd_array->size(); tgt_fd++) { 405 FDEntry *fde = getFDEntry(tgt_fd); 406 if (fde->fd == -1) 407 continue; 408 409 if (fde->isPipe) { 410 if (fde->filename == "PIPE-WRITE") 411 continue; 412 assert(fde->filename == "PIPE-READ"); 413 414 int fds[2]; 415 if (pipe(fds) < 0) 416 fatal("Unable to create new pipe"); 417 418 fde->fd = fds[0]; 419 420 FDEntry *fde_write = getFDEntry(fde->readPipeSource); 421 assert(fde_write->filename == "PIPE-WRITE"); 422 fde_write->fd = fds[1]; 423 } else { 424 fde->fd = openFile(fde->filename.c_str(), fde->flags, fde->mode); 425 seek(fde); 426 } 427 } 428} 429 430void 431Process::findFileOffsets() 432{ 433 for (auto& fde : *fd_array) { 434 if (fde.fd != -1) 435 fde.fileOffset = lseek(fde.fd, 0, SEEK_CUR); 436 } 437} 438 439void 440Process::setReadPipeSource(int read_pipe_fd, int source_fd) 441{ 442 FDEntry *fde = getFDEntry(read_pipe_fd); 443 assert(source_fd >= -1); 444 fde->readPipeSource = source_fd; 445} 446 447void 448Process::serialize(CheckpointOut &cp) const 449{ 450 SERIALIZE_SCALAR(brk_point); 451 SERIALIZE_SCALAR(stack_base); 452 SERIALIZE_SCALAR(stack_size); 453 SERIALIZE_SCALAR(stack_min); 454 SERIALIZE_SCALAR(next_thread_stack_base); 455 SERIALIZE_SCALAR(mmap_end); 456 SERIALIZE_SCALAR(nxm_start); 457 SERIALIZE_SCALAR(nxm_end); 458 pTable->serialize(cp); 459 for (int x = 0; x < fd_array->size(); x++) { 460 (*fd_array)[x].serializeSection(cp, csprintf("FDEntry%d", x)); 461 } 462 SERIALIZE_SCALAR(M5_pid); 463 464} 465 466void 467Process::unserialize(CheckpointIn &cp) 468{ 469 UNSERIALIZE_SCALAR(brk_point); 470 UNSERIALIZE_SCALAR(stack_base); 471 UNSERIALIZE_SCALAR(stack_size); 472 UNSERIALIZE_SCALAR(stack_min); 473 UNSERIALIZE_SCALAR(next_thread_stack_base); 474 UNSERIALIZE_SCALAR(mmap_end); 475 UNSERIALIZE_SCALAR(nxm_start); 476 UNSERIALIZE_SCALAR(nxm_end); 477 pTable->unserialize(cp); 478 for (int x = 0; x < fd_array->size(); x++) { 479 FDEntry *fde = getFDEntry(x); 480 fde->unserializeSection(cp, csprintf("FDEntry%d", x)); 481 } 482 fixFileOffsets(); 483 UNSERIALIZE_OPT_SCALAR(M5_pid); 484 // The above returns a bool so that you could do something if you don't 485 // find the param in the checkpoint if you wanted to, like set a default 486 // but in this case we'll just stick with the instantiated value if not 487 // found. 488} 489 490 491bool 492Process::map(Addr vaddr, Addr paddr, int size, bool cacheable) 493{ 494 pTable->map(vaddr, paddr, size, 495 cacheable ? PageTableBase::Zero : PageTableBase::Uncacheable); 496 return true; 497} 498 499 500//////////////////////////////////////////////////////////////////////// 501// 502// LiveProcess member definitions 503// 504//////////////////////////////////////////////////////////////////////// 505 506 507LiveProcess::LiveProcess(LiveProcessParams *params, ObjectFile *_objFile) 508 : Process(params), objFile(_objFile), 509 argv(params->cmd), envp(params->env), cwd(params->cwd), 510 executable(params->executable), 511 __uid(params->uid), __euid(params->euid), 512 __gid(params->gid), __egid(params->egid), 513 __pid(params->pid), __ppid(params->ppid), 514 drivers(params->drivers) 515{ 516 517 // load up symbols, if any... these may be used for debugging or 518 // profiling. 519 if (!debugSymbolTable) { 520 debugSymbolTable = new SymbolTable(); 521 if (!objFile->loadGlobalSymbols(debugSymbolTable) || 522 !objFile->loadLocalSymbols(debugSymbolTable) || 523 !objFile->loadWeakSymbols(debugSymbolTable)) { 524 // didn't load any symbols 525 delete debugSymbolTable; 526 debugSymbolTable = NULL; 527 } 528 } 529} 530 531void 532LiveProcess::syscall(int64_t callnum, ThreadContext *tc) 533{ 534 num_syscalls++; 535 536 SyscallDesc *desc = getDesc(callnum); 537 if (desc == NULL) 538 fatal("Syscall %d out of range", callnum); 539 540 desc->doSyscall(callnum, this, tc); 541} 542 543IntReg 544LiveProcess::getSyscallArg(ThreadContext *tc, int &i, int width) 545{ 546 return getSyscallArg(tc, i); 547} 548 549 550EmulatedDriver * 551LiveProcess::findDriver(std::string filename) 552{ 553 for (EmulatedDriver *d : drivers) { 554 if (d->match(filename)) 555 return d; 556 } 557 558 return NULL; 559} 560 561void 562LiveProcess::updateBias() 563{ 564 ObjectFile *interp = objFile->getInterpreter(); 565 566 if (!interp || !interp->relocatable()) 567 return; 568 569 // Determine how large the interpreters footprint will be in the process 570 // address space. 571 Addr interp_mapsize = roundUp(interp->mapSize(), TheISA::PageBytes); 572 573 // We are allocating the memory area; set the bias to the lowest address 574 // in the allocated memory region. 575 Addr ld_bias = mmapGrowsDown() ? mmap_end - interp_mapsize : mmap_end; 576 577 // Adjust the process mmap area to give the interpreter room; the real 578 // execve system call would just invoke the kernel's internal mmap 579 // functions to make these adjustments. 580 mmap_end = mmapGrowsDown() ? ld_bias : mmap_end + interp_mapsize; 581 582 interp->updateBias(ld_bias); 583} 584 585 586ObjectFile * 587LiveProcess::getInterpreter() 588{ 589 return objFile->getInterpreter(); 590} 591 592 593Addr 594LiveProcess::getBias() 595{ 596 ObjectFile *interp = getInterpreter(); 597 598 return interp ? interp->bias() : objFile->bias(); 599} 600 601 602Addr 603LiveProcess::getStartPC() 604{ 605 ObjectFile *interp = getInterpreter(); 606 607 return interp ? interp->entryPoint() : objFile->entryPoint(); 608} 609 610 611LiveProcess * 612LiveProcess::create(LiveProcessParams * params) 613{ 614 LiveProcess *process = NULL; 615 616 // If not specified, set the executable parameter equal to the 617 // simulated system's zeroth command line parameter 618 if (params->executable == "") { 619 params->executable = params->cmd[0]; 620 } 621 622 ObjectFile *objFile = createObjectFile(params->executable); 623 if (objFile == NULL) { 624 fatal("Can't load object file %s", params->executable); 625 } 626 627#if THE_ISA == ALPHA_ISA 628 if (objFile->getArch() != ObjectFile::Alpha) 629 fatal("Object file architecture does not match compiled ISA (Alpha)."); 630 631 switch (objFile->getOpSys()) { 632 case ObjectFile::UnknownOpSys: 633 warn("Unknown operating system; assuming Linux."); 634 // fall through 635 case ObjectFile::Linux: 636 process = new AlphaLinuxProcess(params, objFile); 637 break; 638 639 default: 640 fatal("Unknown/unsupported operating system."); 641 } 642#elif THE_ISA == SPARC_ISA 643 if (objFile->getArch() != ObjectFile::SPARC64 && 644 objFile->getArch() != ObjectFile::SPARC32) 645 fatal("Object file architecture does not match compiled ISA (SPARC)."); 646 switch (objFile->getOpSys()) { 647 case ObjectFile::UnknownOpSys: 648 warn("Unknown operating system; assuming Linux."); 649 // fall through 650 case ObjectFile::Linux: 651 if (objFile->getArch() == ObjectFile::SPARC64) { 652 process = new Sparc64LinuxProcess(params, objFile); 653 } else { 654 process = new Sparc32LinuxProcess(params, objFile); 655 } 656 break; 657 658 659 case ObjectFile::Solaris: 660 process = new SparcSolarisProcess(params, objFile); 661 break; 662 663 default: 664 fatal("Unknown/unsupported operating system."); 665 } 666#elif THE_ISA == X86_ISA 667 if (objFile->getArch() != ObjectFile::X86_64 && 668 objFile->getArch() != ObjectFile::I386) 669 fatal("Object file architecture does not match compiled ISA (x86)."); 670 switch (objFile->getOpSys()) { 671 case ObjectFile::UnknownOpSys: 672 warn("Unknown operating system; assuming Linux."); 673 // fall through 674 case ObjectFile::Linux: 675 if (objFile->getArch() == ObjectFile::X86_64) { 676 process = new X86_64LinuxProcess(params, objFile); 677 } else { 678 process = new I386LinuxProcess(params, objFile); 679 } 680 break; 681 682 default: 683 fatal("Unknown/unsupported operating system."); 684 } 685#elif THE_ISA == MIPS_ISA 686 if (objFile->getArch() != ObjectFile::Mips) 687 fatal("Object file architecture does not match compiled ISA (MIPS)."); 688 switch (objFile->getOpSys()) { 689 case ObjectFile::UnknownOpSys: 690 warn("Unknown operating system; assuming Linux."); 691 // fall through 692 case ObjectFile::Linux: 693 process = new MipsLinuxProcess(params, objFile); 694 break; 695 696 default: 697 fatal("Unknown/unsupported operating system."); 698 } 699#elif THE_ISA == ARM_ISA 700 ObjectFile::Arch arch = objFile->getArch(); 701 if (arch != ObjectFile::Arm && arch != ObjectFile::Thumb && 702 arch != ObjectFile::Arm64) 703 fatal("Object file architecture does not match compiled ISA (ARM)."); 704 switch (objFile->getOpSys()) { 705 case ObjectFile::UnknownOpSys: 706 warn("Unknown operating system; assuming Linux."); 707 // fall through 708 case ObjectFile::Linux: 709 if (arch == ObjectFile::Arm64) { 710 process = new ArmLinuxProcess64(params, objFile, 711 objFile->getArch()); 712 } else { 713 process = new ArmLinuxProcess32(params, objFile, 714 objFile->getArch()); 715 } 716 break; 717 case ObjectFile::FreeBSD: 718 if (arch == ObjectFile::Arm64) { 719 process = new ArmFreebsdProcess64(params, objFile, 720 objFile->getArch()); 721 } else { 722 process = new ArmFreebsdProcess32(params, objFile, 723 objFile->getArch()); 724 } 725 break; 726 case ObjectFile::LinuxArmOABI: 727 fatal("M5 does not support ARM OABI binaries. Please recompile with an" 728 " EABI compiler."); 729 default: 730 fatal("Unknown/unsupported operating system."); 731 } 732#elif THE_ISA == POWER_ISA 733 if (objFile->getArch() != ObjectFile::Power) 734 fatal("Object file architecture does not match compiled ISA (Power)."); 735 switch (objFile->getOpSys()) { 736 case ObjectFile::UnknownOpSys: 737 warn("Unknown operating system; assuming Linux."); 738 // fall through 739 case ObjectFile::Linux: 740 process = new PowerLinuxProcess(params, objFile); 741 break; 742 743 default: 744 fatal("Unknown/unsupported operating system."); 745 } 746#elif THE_ISA == RISCV_ISA 747 if (objFile->getArch() != ObjectFile::Riscv) 748 fatal("Object file architecture does not match compiled ISA (RISCV)."); 749 switch (objFile->getOpSys()) { 750 case ObjectFile::UnknownOpSys: 751 warn("Unknown operating system; assuming Linux."); 752 // fall through 753 case ObjectFile::Linux: 754 process = new RiscvLinuxProcess(params, objFile); 755 break; 756 default: 757 fatal("Unknown/unsupported operating system."); 758 } 759#else 760#error "THE_ISA not set" 761#endif 762 763 if (process == NULL) 764 fatal("Unknown error creating process object."); 765 return process; 766} 767 768LiveProcess * 769LiveProcessParams::create() 770{ 771 return LiveProcess::create(this); 772}
|