process.cc revision 2107
11060SN/A/*
21762SN/A * Copyright (c) 2001-2005 The Regents of The University of Michigan
31060SN/A * All rights reserved.
41060SN/A *
51060SN/A * Redistribution and use in source and binary forms, with or without
61060SN/A * modification, are permitted provided that the following conditions are
71060SN/A * met: redistributions of source code must retain the above copyright
81060SN/A * notice, this list of conditions and the following disclaimer;
91060SN/A * redistributions in binary form must reproduce the above copyright
101060SN/A * notice, this list of conditions and the following disclaimer in the
111060SN/A * documentation and/or other materials provided with the distribution;
121060SN/A * neither the name of the copyright holders nor the names of its
131060SN/A * contributors may be used to endorse or promote products derived from
141060SN/A * this software without specific prior written permission.
151060SN/A *
161060SN/A * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
171060SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
181060SN/A * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
191060SN/A * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
201060SN/A * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
211060SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
221060SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
231060SN/A * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
241060SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
251060SN/A * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
261060SN/A * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
272665Ssaidi@eecs.umich.edu */
282665Ssaidi@eecs.umich.edu
291060SN/A#include <unistd.h>
301060SN/A#include <fcntl.h>
311464SN/A
321464SN/A#include <cstdio>
331060SN/A#include <string>
342292SN/A
351464SN/A#include "base/intmath.hh"
361060SN/A#include "base/loader/object_file.hh"
372669Sktlim@umich.edu#include "base/loader/symtab.hh"
381060SN/A#include "base/statistics.hh"
391060SN/A#include "config/full_system.hh"
401858SN/A#include "cpu/exec_context.hh"
411464SN/A#include "cpu/smt.hh"
421464SN/A#include "encumbered/cpu/full/thread.hh"
432669Sktlim@umich.edu#include "encumbered/eio/eio.hh"
441060SN/A#include "encumbered/mem/functional/main.hh"
452669Sktlim@umich.edu#include "sim/builder.hh"
462292SN/A#include "sim/fake_syscall.hh"
472292SN/A#include "sim/process.hh"
481717SN/A#include "sim/stats.hh"
491717SN/A
501717SN/A#ifdef TARGET_ALPHA
511717SN/A#include "arch/alpha/alpha_tru64_process.hh"
522292SN/A#include "arch/alpha/alpha_linux_process.hh"
531060SN/A#endif
541060SN/A
551060SN/Ausing namespace std;
561060SN/Ausing namespace TheISA;
571060SN/A
581060SN/A//
591061SN/A// The purpose of this code is to fake the loader & syscall mechanism
601061SN/A// when there's no OS: thus there's no resone to use it in FULL_SYSTEM
611060SN/A// mode when we do have an OS
621060SN/A//
631061SN/A#if FULL_SYSTEM
641060SN/A#error "process.cc not compatible with FULL_SYSTEM"
651060SN/A#endif
661060SN/A
671060SN/A// current number of allocated processes
682292SN/Aint num_processes = 0;
691060SN/A
702292SN/AProcess::Process(const string &nm,
712107SN/A                 int stdin_fd, 	// initial I/O descriptors
722292SN/A                 int stdout_fd,
732292SN/A                 int stderr_fd)
742292SN/A    : SimObject(nm)
752107SN/A{
762292SN/A    // allocate memory space
772107SN/A    memory = new MainMemory(nm + ".MainMem");
781060SN/A
792292SN/A    // allocate initial register file
802292SN/A    init_regs = new RegFile;
812292SN/A    memset(init_regs, 0, sizeof(RegFile));
822292SN/A
832292SN/A    // initialize first 3 fds (stdin, stdout, stderr)
842292SN/A    fd_map[STDIN_FILENO] = stdin_fd;
851060SN/A    fd_map[STDOUT_FILENO] = stdout_fd;
862292SN/A    fd_map[STDERR_FILENO] = stderr_fd;
872292SN/A
881060SN/A    // mark remaining fds as free
891060SN/A    for (int i = 3; i <= MAX_FD; ++i) {
902292SN/A        fd_map[i] = -1;
912107SN/A    }
921060SN/A
931060SN/A    mmap_start = mmap_end = 0;
941060SN/A    nxm_start = nxm_end = 0;
951060SN/A    // other parameters will be initialized when the program is loaded
961060SN/A}
971060SN/A
982292SN/Avoid
991060SN/AProcess::regStats()
1001060SN/A{
1012292SN/A    using namespace Stats;
1022292SN/A
1032292SN/A    num_syscalls
1042292SN/A        .name(name() + ".PROG:num_syscalls")
1052292SN/A        .desc("Number of system calls")
1062292SN/A        ;
1072292SN/A}
1081060SN/A
1092132SN/A//
1101060SN/A// static helper functions
1112292SN/A//
1122292SN/Aint
1132292SN/AProcess::openInputFile(const string &filename)
1142292SN/A{
1152292SN/A    int fd = open(filename.c_str(), O_RDONLY);
1162292SN/A
1172292SN/A    if (fd == -1) {
1182292SN/A        perror(NULL);
1191060SN/A        cerr << "unable to open \"" << filename << "\" for reading\n";
1202132SN/A        fatal("can't open input file");
1211060SN/A    }
1221060SN/A
1231060SN/A    return fd;
1241060SN/A}
1252132SN/A
1262132SN/A
1271060SN/Aint
1281684SN/AProcess::openOutputFile(const string &filename)
1291060SN/A{
1301060SN/A    int fd = open(filename.c_str(), O_WRONLY | O_CREAT | O_TRUNC, 0774);
1311060SN/A
1321060SN/A    if (fd == -1) {
1332292SN/A        perror(NULL);
1342292SN/A        cerr << "unable to open \"" << filename << "\" for writing\n";
1352292SN/A        fatal("can't open output file");
1362292SN/A    }
1372292SN/A
1382292SN/A    return fd;
1392292SN/A}
1402292SN/A
1411060SN/A
1421464SN/Aint
1431464SN/AProcess::registerExecContext(ExecContext *xc)
1441464SN/A{
1452308SN/A    // add to list
1462308SN/A    int myIndex = execContexts.size();
1472308SN/A    execContexts.push_back(xc);
1481060SN/A
1491060SN/A    if (myIndex == 0) {
1501060SN/A        // copy process's initial regs struct
1511060SN/A        xc->regs = *init_regs;
1521060SN/A    }
1531060SN/A
1541060SN/A    // return CPU number to caller and increment available CPU count
1551060SN/A    return myIndex;
1561060SN/A}
1571060SN/A
1581060SN/Avoid
1591060SN/AProcess::startup()
1602292SN/A{
1612292SN/A    if (execContexts.empty())
1622292SN/A        return;
1631060SN/A
1641060SN/A    // first exec context for this process... initialize & enable
1651060SN/A    ExecContext *xc = execContexts[0];
1661060SN/A
1671060SN/A    // mark this context as active so it will start ticking.
1681060SN/A    xc->activate(0);
1692292SN/A}
1702292SN/A
1712292SN/Avoid
1722292SN/AProcess::replaceExecContext(ExecContext *xc, int xcIndex)
1732292SN/A{
1742292SN/A    if (xcIndex >= execContexts.size()) {
1751060SN/A        panic("replaceExecContext: bad xcIndex, %d >= %d\n",
1761060SN/A              xcIndex, execContexts.size());
1771060SN/A    }
1781060SN/A
1791060SN/A    execContexts[xcIndex] = xc;
1801060SN/A}
1811060SN/A
1821060SN/A// map simulator fd sim_fd to target fd tgt_fd
1831060SN/Avoid
1841060SN/AProcess::dup_fd(int sim_fd, int tgt_fd)
1851060SN/A{
1861060SN/A    if (tgt_fd < 0 || tgt_fd > MAX_FD)
1871060SN/A        panic("Process::dup_fd tried to dup past MAX_FD (%d)", tgt_fd);
1881060SN/A
1891060SN/A    fd_map[tgt_fd] = sim_fd;
1902292SN/A}
1912292SN/A
1922292SN/A
1931060SN/A// generate new target fd for sim_fd
1941060SN/Aint
1951060SN/AProcess::alloc_fd(int sim_fd)
1962308SN/A{
1972292SN/A    // in case open() returns an error, don't allocate a new fd
1981060SN/A    if (sim_fd == -1)
1991060SN/A        return -1;
2002132SN/A
2011060SN/A    // find first free target fd
2022292SN/A    for (int free_fd = 0; free_fd < MAX_FD; ++free_fd) {
2032669Sktlim@umich.edu        if (fd_map[free_fd] == -1) {
2042669Sktlim@umich.edu            fd_map[free_fd] = sim_fd;
2052669Sktlim@umich.edu            return free_fd;
2062669Sktlim@umich.edu        }
2072669Sktlim@umich.edu    }
2082292SN/A
2091060SN/A    panic("Process::alloc_fd: out of file descriptors!");
2101060SN/A}
2111060SN/A
2121060SN/A
2131060SN/A// free target fd (e.g., after close)
2141060SN/Avoid
2151060SN/AProcess::free_fd(int tgt_fd)
2161060SN/A{
2171060SN/A    if (fd_map[tgt_fd] == -1)
2181060SN/A        warn("Process::free_fd: request to free unused fd %d", tgt_fd);
2191060SN/A
2201060SN/A    fd_map[tgt_fd] = -1;
2211060SN/A}
2221060SN/A
2231060SN/A
2241060SN/A// look up simulator fd for given target fd
2251060SN/Aint
2261060SN/AProcess::sim_fd(int tgt_fd)
2271060SN/A{
2281060SN/A    if (tgt_fd > MAX_FD)
2291060SN/A        return -1;
2301464SN/A
2311464SN/A    return fd_map[tgt_fd];
2321464SN/A}
2331464SN/A
2341464SN/A
2351060SN/A
2361464SN/A//
2371464SN/A// need to declare these here since there is no concrete Process type
2381464SN/A// that can be constructed (i.e., no REGISTER_SIM_OBJECT() macro call,
2391464SN/A// which is where these get declared for concrete types).
2401060SN/A//
2411060SN/ADEFINE_SIM_OBJECT_CLASS_NAME("Process", Process)
2421060SN/A
2431060SN/A
2441060SN/A////////////////////////////////////////////////////////////////////////
2451060SN/A//
2461060SN/A// LiveProcess member definitions
2471060SN/A//
2481060SN/A////////////////////////////////////////////////////////////////////////
2491060SN/A
2501060SN/A
2511060SN/Astatic void
2521060SN/AcopyStringArray(vector<string> &strings, Addr array_ptr, Addr data_ptr,
2531060SN/A                FunctionalMemory *memory)
2541060SN/A{
2551060SN/A    Addr data_ptr_swap;
2562292SN/A    for (int i = 0; i < strings.size(); ++i) {
2572292SN/A        data_ptr_swap = htog(data_ptr);
2582292SN/A        memory->access(Write, array_ptr, &data_ptr_swap, sizeof(Addr));
2592292SN/A        memory->writeString(data_ptr, strings[i].c_str());
2602292SN/A        array_ptr += sizeof(Addr);
2612292SN/A        data_ptr += strings[i].size() + 1;
2621060SN/A    }
2631060SN/A    // add NULL terminator
2641060SN/A    data_ptr = 0;
2651060SN/A    memory->access(Write, array_ptr, &data_ptr, sizeof(Addr));
2662292SN/A}
2672292SN/A
2682292SN/ALiveProcess::LiveProcess(const string &nm, ObjectFile *objFile,
2692292SN/A                         int stdin_fd, int stdout_fd, int stderr_fd,
2702292SN/A                         vector<string> &argv, vector<string> &envp)
2712292SN/A    : Process(nm, stdin_fd, stdout_fd, stderr_fd)
2722292SN/A{
2732292SN/A    prog_fname = argv[0];
2741060SN/A
2751060SN/A    prog_entry = objFile->entryPoint();
2762292SN/A    text_base = objFile->textBase();
2772292SN/A    text_size = objFile->textSize();
2782292SN/A    data_base = objFile->dataBase();
2792107SN/A    data_size = objFile->dataSize() + objFile->bssSize();
2801060SN/A    brk_point = roundUp(data_base + data_size, VMPageSize);
2811060SN/A
2821060SN/A    // load object file into target memory
2831060SN/A    objFile->loadSections(memory);
2841464SN/A
2851684SN/A    // load up symbols, if any... these may be used for debugging or
2861464SN/A    // profiling.
2871060SN/A    if (!debugSymbolTable) {
2881464SN/A        debugSymbolTable = new SymbolTable();
2892292SN/A        if (!objFile->loadGlobalSymbols(debugSymbolTable) ||
2902292SN/A            !objFile->loadLocalSymbols(debugSymbolTable)) {
2912292SN/A            // didn't load any symbols
2922292SN/A            delete debugSymbolTable;
2932292SN/A            debugSymbolTable = NULL;
2942292SN/A        }
2952292SN/A    }
2962292SN/A
2972669Sktlim@umich.edu    // Set up stack.  On Alpha, stack goes below text section.  This
2982669Sktlim@umich.edu    // code should get moved to some architecture-specific spot.
2992669Sktlim@umich.edu    stack_base = text_base - (409600+4096);
3002669Sktlim@umich.edu
3012669Sktlim@umich.edu    // Set up region for mmaps.  Tru64 seems to start just above 0 and
3022669Sktlim@umich.edu    // grow up from there.
3031060SN/A    mmap_start = mmap_end = 0x10000;
3041060SN/A
3051060SN/A    // Set pointer for next thread stack.  Reserve 8M for main stack.
3061060SN/A    next_thread_stack_base = stack_base - (8 * 1024 * 1024);
3071060SN/A
3081060SN/A    // Calculate how much space we need for arg & env arrays.
3091060SN/A    int argv_array_size = sizeof(Addr) * (argv.size() + 1);
3101060SN/A    int envp_array_size = sizeof(Addr) * (envp.size() + 1);
3112132SN/A    int arg_data_size = 0;
3121060SN/A    for (int i = 0; i < argv.size(); ++i) {
3131060SN/A        arg_data_size += argv[i].size() + 1;
3141060SN/A    }
3151060SN/A    int env_data_size = 0;
3162292SN/A    for (int i = 0; i < envp.size(); ++i) {
3171060SN/A        env_data_size += envp[i].size() + 1;
3181060SN/A    }
3191060SN/A
3201684SN/A    int space_needed =
3211684SN/A        argv_array_size + envp_array_size + arg_data_size + env_data_size;
3221684SN/A    // for SimpleScalar compatibility
3231060SN/A    if (space_needed < 16384)
3241060SN/A        space_needed = 16384;
3251060SN/A
3261060SN/A    // set bottom of stack
3271060SN/A    stack_min = stack_base - space_needed;
3281060SN/A    // align it
3291060SN/A    stack_min &= ~7;
3301060SN/A    stack_size = stack_base - stack_min;
3311060SN/A
3322292SN/A    // map out initial stack contents
3331060SN/A    Addr argv_array_base = stack_min + sizeof(uint64_t); // room for argc
3341060SN/A    Addr envp_array_base = argv_array_base + argv_array_size;
3352292SN/A    Addr arg_data_base = envp_array_base + envp_array_size;
3361060SN/A    Addr env_data_base = arg_data_base + arg_data_size;
3371060SN/A
3381060SN/A    // write contents to stack
3391060SN/A    uint64_t argc = argv.size();
3401060SN/A    argc = htog(argc);
3411060SN/A    memory->access(Write, stack_min, &argc, sizeof(uint64_t));
3421060SN/A
3431060SN/A    copyStringArray(argv, argv_array_base, arg_data_base, memory);
3442336SN/A    copyStringArray(envp, envp_array_base, env_data_base, memory);
3452336SN/A
3461060SN/A    init_regs->intRegFile[ArgumentReg0] = argc;
3471060SN/A    init_regs->intRegFile[ArgumentReg1] = argv_array_base;
3481060SN/A    init_regs->intRegFile[StackPointerReg] = stack_min;
3491060SN/A    init_regs->intRegFile[GlobalPointerReg] = objFile->globalPointer();
3501060SN/A    init_regs->pc = prog_entry;
3511060SN/A    init_regs->npc = prog_entry + sizeof(MachInst);
3521060SN/A}
3531060SN/A
3541060SN/A
3551060SN/ALiveProcess *
3561060SN/ALiveProcess::create(const string &nm,
3571060SN/A                    int stdin_fd, int stdout_fd, int stderr_fd,
3581060SN/A                    string executable,
3591060SN/A                    vector<string> &argv, vector<string> &envp)
3602292SN/A{
3612292SN/A    LiveProcess *process = NULL;
3622292SN/A    ObjectFile *objFile = createObjectFile(executable);
3632292SN/A    if (objFile == NULL) {
3641060SN/A        fatal("Can't load object file %s", executable);
3651060SN/A    }
3661060SN/A
3672292SN/A    // check object type & set up syscall emulation pointer
3682336SN/A    if (objFile->getArch() == ObjectFile::Alpha) {
3692308SN/A        switch (objFile->getOpSys()) {
3702292SN/A          case ObjectFile::Tru64:
3712292SN/A            process = new AlphaTru64Process(nm, objFile,
3722292SN/A                                            stdin_fd, stdout_fd, stderr_fd,
3732292SN/A                                            argv, envp);
3742292SN/A            break;
3752292SN/A
3762292SN/A          case ObjectFile::Linux:
3772292SN/A            process = new AlphaLinuxProcess(nm, objFile,
3782292SN/A                                            stdin_fd, stdout_fd, stderr_fd,
3792292SN/A                                            argv, envp);
3802292SN/A            break;
3812292SN/A
3822292SN/A          default:
3832292SN/A            fatal("Unknown/unsupported operating system.");
3842292SN/A        }
3852292SN/A    } else {
3862292SN/A        fatal("Unknown object file architecture.");
3872292SN/A    }
3882292SN/A
3892292SN/A    delete objFile;
3902292SN/A
3912292SN/A    if (process == NULL)
3922292SN/A        fatal("Unknown error creating process object.");
3932292SN/A
3942292SN/A    return process;
3952292SN/A}
3962292SN/A
3972292SN/A
3982292SN/ABEGIN_DECLARE_SIM_OBJECT_PARAMS(LiveProcess)
3992292SN/A
4002292SN/A    VectorParam<string> cmd;
4012292SN/A    Param<string> executable;
4022292SN/A    Param<string> input;
4032292SN/A    Param<string> output;
4042292SN/A    VectorParam<string> env;
4052292SN/A
4062292SN/AEND_DECLARE_SIM_OBJECT_PARAMS(LiveProcess)
4071060SN/A
4081464SN/A
4091464SN/ABEGIN_INIT_SIM_OBJECT_PARAMS(LiveProcess)
4101464SN/A
4111464SN/A    INIT_PARAM(cmd, "command line (executable plus arguments)"),
4121464SN/A    INIT_PARAM(executable, "executable (overrides cmd[0] if set)"),
4131464SN/A    INIT_PARAM(input, "filename for stdin (dflt: use sim stdin)"),
4142292SN/A    INIT_PARAM(output, "filename for stdout/stderr (dflt: use sim stdout)"),
4152292SN/A    INIT_PARAM(env, "environment settings")
4161684SN/A
4172292SN/AEND_INIT_SIM_OBJECT_PARAMS(LiveProcess)
4181060SN/A
4191060SN/A
4201060SN/ACREATE_SIM_OBJECT(LiveProcess)
4211060SN/A{
4221060SN/A    string in = input;
4231060SN/A    string out = output;
4241060SN/A
4251060SN/A    // initialize file descriptors to default: same as simulator
4262292SN/A    int stdin_fd, stdout_fd, stderr_fd;
4271060SN/A
4281060SN/A    if (in == "stdin" || in == "cin")
4292292SN/A        stdin_fd = STDIN_FILENO;
4301060SN/A    else
4311684SN/A        stdin_fd = Process::openInputFile(input);
4321464SN/A
4331684SN/A    if (out == "stdout" || out == "cout")
4341684SN/A        stdout_fd = STDOUT_FILENO;
4351464SN/A    else if (out == "stderr" || out == "cerr")
4361684SN/A        stdout_fd = STDERR_FILENO;
4371684SN/A    else
4381464SN/A        stdout_fd = Process::openOutputFile(out);
4391060SN/A
4402308SN/A    stderr_fd = (stdout_fd != STDOUT_FILENO) ? stdout_fd : STDERR_FILENO;
4411060SN/A
4422308SN/A    return LiveProcess::create(getInstanceName(),
4431060SN/A                               stdin_fd, stdout_fd, stderr_fd,
4441060SN/A                               (string)executable == "" ? cmd[0] : executable,
4452308SN/A                               cmd, env);
4461060SN/A}
4472308SN/A
4482308SN/AREGISTER_SIM_OBJECT("LiveProcess", LiveProcess)
4491060SN/A