process.cc revision 2523
110037SARM gem5 Developers/*
210037SARM gem5 Developers * Copyright (c) 2001-2005 The Regents of The University of Michigan
310037SARM gem5 Developers * All rights reserved.
410037SARM gem5 Developers *
510037SARM gem5 Developers * Redistribution and use in source and binary forms, with or without
610037SARM gem5 Developers * modification, are permitted provided that the following conditions are
710037SARM gem5 Developers * met: redistributions of source code must retain the above copyright
810037SARM gem5 Developers * notice, this list of conditions and the following disclaimer;
910037SARM gem5 Developers * redistributions in binary form must reproduce the above copyright
1010037SARM gem5 Developers * notice, this list of conditions and the following disclaimer in the
1110037SARM gem5 Developers * documentation and/or other materials provided with the distribution;
1210037SARM gem5 Developers * neither the name of the copyright holders nor the names of its
1310037SARM gem5 Developers * contributors may be used to endorse or promote products derived from
1410037SARM gem5 Developers * this software without specific prior written permission.
1510037SARM gem5 Developers *
1610037SARM gem5 Developers * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
1710037SARM gem5 Developers * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
1810037SARM gem5 Developers * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
1910037SARM gem5 Developers * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
2010037SARM gem5 Developers * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
2110037SARM gem5 Developers * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
2210037SARM gem5 Developers * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2310037SARM gem5 Developers * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2410037SARM gem5 Developers * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2510037SARM gem5 Developers * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
2610037SARM gem5 Developers * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2710037SARM gem5 Developers */
2810037SARM gem5 Developers
2910037SARM gem5 Developers#include <unistd.h>
3010037SARM gem5 Developers#include <fcntl.h>
3110037SARM gem5 Developers
3210037SARM gem5 Developers#include <cstdio>
3310037SARM gem5 Developers#include <string>
3410037SARM gem5 Developers
3510037SARM gem5 Developers#include "base/intmath.hh"
3610037SARM gem5 Developers#include "base/loader/object_file.hh"
3710037SARM gem5 Developers#include "base/loader/symtab.hh"
3810037SARM gem5 Developers#include "base/statistics.hh"
3910037SARM gem5 Developers#include "config/full_system.hh"
4010037SARM gem5 Developers#include "cpu/exec_context.hh"
4110037SARM gem5 Developers#include "mem/page_table.hh"
4210037SARM gem5 Developers#include "mem/physical.hh"
4310037SARM gem5 Developers#include "mem/translating_port.hh"
4410037SARM gem5 Developers#include "sim/builder.hh"
4510037SARM gem5 Developers#include "sim/process.hh"
4610037SARM gem5 Developers#include "sim/stats.hh"
4710037SARM gem5 Developers#include "sim/syscall_emul.hh"
4810037SARM gem5 Developers#include "sim/system.hh"
4910037SARM gem5 Developers
5010037SARM gem5 Developersusing namespace std;
5110037SARM gem5 Developersusing namespace TheISA;
5210037SARM gem5 Developers
5310037SARM gem5 Developers//
5410037SARM gem5 Developers// The purpose of this code is to fake the loader & syscall mechanism
5510037SARM gem5 Developers// when there's no OS: thus there's no resone to use it in FULL_SYSTEM
5610037SARM gem5 Developers// mode when we do have an OS
5710037SARM gem5 Developers//
5810037SARM gem5 Developers#if FULL_SYSTEM
5910037SARM gem5 Developers#error "process.cc not compatible with FULL_SYSTEM"
6010037SARM gem5 Developers#endif
6110037SARM gem5 Developers
6210037SARM gem5 Developers// current number of allocated processes
6310037SARM gem5 Developersint num_processes = 0;
6410037SARM gem5 Developers
6510037SARM gem5 DevelopersProcess::Process(const string &nm,
6610037SARM gem5 Developers                 System *_system,
6710037SARM gem5 Developers                 int stdin_fd, 	// initial I/O descriptors
6810037SARM gem5 Developers                 int stdout_fd,
6910037SARM gem5 Developers                 int stderr_fd)
7010037SARM gem5 Developers    : SimObject(nm), system(_system)
7110037SARM gem5 Developers{
7210037SARM gem5 Developers    // initialize first 3 fds (stdin, stdout, stderr)
7310037SARM gem5 Developers    fd_map[STDIN_FILENO] = stdin_fd;
7410037SARM gem5 Developers    fd_map[STDOUT_FILENO] = stdout_fd;
7510037SARM gem5 Developers    fd_map[STDERR_FILENO] = stderr_fd;
7610037SARM gem5 Developers
7710037SARM gem5 Developers    // mark remaining fds as free
7810037SARM gem5 Developers    for (int i = 3; i <= MAX_FD; ++i) {
7910037SARM gem5 Developers        fd_map[i] = -1;
8010037SARM gem5 Developers    }
8110037SARM gem5 Developers
8210037SARM gem5 Developers    mmap_start = mmap_end = 0;
8310037SARM gem5 Developers    nxm_start = nxm_end = 0;
8410037SARM gem5 Developers    pTable = new PageTable(system);
8510037SARM gem5 Developers    // other parameters will be initialized when the program is loaded
8610037SARM gem5 Developers}
8710037SARM gem5 Developers
8810037SARM gem5 Developers
8910037SARM gem5 Developersvoid
9010037SARM gem5 DevelopersProcess::regStats()
9110037SARM gem5 Developers{
9210037SARM gem5 Developers    using namespace Stats;
9310037SARM gem5 Developers
9410037SARM gem5 Developers    num_syscalls
9510037SARM gem5 Developers        .name(name() + ".PROG:num_syscalls")
9610037SARM gem5 Developers        .desc("Number of system calls")
9710037SARM gem5 Developers        ;
9810037SARM gem5 Developers}
9910037SARM gem5 Developers
10010037SARM gem5 Developers//
10110037SARM gem5 Developers// static helper functions
10210037SARM gem5 Developers//
10310037SARM gem5 Developersint
10410037SARM gem5 DevelopersProcess::openInputFile(const string &filename)
10510037SARM gem5 Developers{
10610037SARM gem5 Developers    int fd = open(filename.c_str(), O_RDONLY);
10710037SARM gem5 Developers
10810037SARM gem5 Developers    if (fd == -1) {
10910037SARM gem5 Developers        perror(NULL);
11010037SARM gem5 Developers        cerr << "unable to open \"" << filename << "\" for reading\n";
11110037SARM gem5 Developers        fatal("can't open input file");
11210037SARM gem5 Developers    }
11310037SARM gem5 Developers
11410037SARM gem5 Developers    return fd;
11510037SARM gem5 Developers}
11610037SARM gem5 Developers
11710037SARM gem5 Developers
11810037SARM gem5 Developersint
11910037SARM gem5 DevelopersProcess::openOutputFile(const string &filename)
12010037SARM gem5 Developers{
12110037SARM gem5 Developers    int fd = open(filename.c_str(), O_WRONLY | O_CREAT | O_TRUNC, 0774);
12210037SARM gem5 Developers
12310037SARM gem5 Developers    if (fd == -1) {
12410037SARM gem5 Developers        perror(NULL);
12510037SARM gem5 Developers        cerr << "unable to open \"" << filename << "\" for writing\n";
12610037SARM gem5 Developers        fatal("can't open output file");
12710037SARM gem5 Developers    }
12810037SARM gem5 Developers
12910037SARM gem5 Developers    return fd;
13010037SARM gem5 Developers}
13110037SARM gem5 Developers
13210037SARM gem5 Developers
13310037SARM gem5 Developersint
13410037SARM gem5 DevelopersProcess::registerExecContext(ExecContext *xc)
13510037SARM gem5 Developers{
13610037SARM gem5 Developers    // add to list
13710037SARM gem5 Developers    int myIndex = execContexts.size();
13810037SARM gem5 Developers    execContexts.push_back(xc);
13910037SARM gem5 Developers
14010037SARM gem5 Developers    // return CPU number to caller
14110037SARM gem5 Developers    return myIndex;
14210037SARM gem5 Developers}
14310037SARM gem5 Developers
14410037SARM gem5 Developersvoid
14510037SARM gem5 DevelopersProcess::startup()
14610037SARM gem5 Developers{
14710037SARM gem5 Developers    if (execContexts.empty())
14810037SARM gem5 Developers        fatal("Process %s is not associated with any CPUs!\n", name());
14910037SARM gem5 Developers
15010037SARM gem5 Developers    // first exec context for this process... initialize & enable
15110037SARM gem5 Developers    ExecContext *xc = execContexts[0];
15210037SARM gem5 Developers
15310037SARM gem5 Developers    // mark this context as active so it will start ticking.
15410037SARM gem5 Developers    xc->activate(0);
15510037SARM gem5 Developers
15610037SARM gem5 Developers    Port *mem_port;
15710037SARM gem5 Developers    mem_port = system->physmem->getPort("functional");
15810037SARM gem5 Developers    initVirtMem = new TranslatingPort(pTable, true);
15910037SARM gem5 Developers    mem_port->setPeer(initVirtMem);
16010037SARM gem5 Developers    initVirtMem->setPeer(mem_port);
16110037SARM gem5 Developers}
16210037SARM gem5 Developers
16310037SARM gem5 Developersvoid
16410037SARM gem5 DevelopersProcess::replaceExecContext(ExecContext *xc, int xcIndex)
16510037SARM gem5 Developers{
16610037SARM gem5 Developers    if (xcIndex >= execContexts.size()) {
16710037SARM gem5 Developers        panic("replaceExecContext: bad xcIndex, %d >= %d\n",
16810037SARM gem5 Developers              xcIndex, execContexts.size());
16910037SARM gem5 Developers    }
17010037SARM gem5 Developers
17110037SARM gem5 Developers    execContexts[xcIndex] = xc;
17210037SARM gem5 Developers}
17310037SARM gem5 Developers
17410037SARM gem5 Developers// map simulator fd sim_fd to target fd tgt_fd
17510037SARM gem5 Developersvoid
17610037SARM gem5 DevelopersProcess::dup_fd(int sim_fd, int tgt_fd)
17710037SARM gem5 Developers{
17810037SARM gem5 Developers    if (tgt_fd < 0 || tgt_fd > MAX_FD)
17910037SARM gem5 Developers        panic("Process::dup_fd tried to dup past MAX_FD (%d)", tgt_fd);
18010037SARM gem5 Developers
18110037SARM gem5 Developers    fd_map[tgt_fd] = sim_fd;
18210037SARM gem5 Developers}
18310037SARM gem5 Developers
18410037SARM gem5 Developers
18510037SARM gem5 Developers// generate new target fd for sim_fd
18610037SARM gem5 Developersint
18710037SARM gem5 DevelopersProcess::alloc_fd(int sim_fd)
18810037SARM gem5 Developers{
18910037SARM gem5 Developers    // in case open() returns an error, don't allocate a new fd
19010037SARM gem5 Developers    if (sim_fd == -1)
19110037SARM gem5 Developers        return -1;
19210037SARM gem5 Developers
19310037SARM gem5 Developers    // find first free target fd
19410037SARM gem5 Developers    for (int free_fd = 0; free_fd < MAX_FD; ++free_fd) {
19510037SARM gem5 Developers        if (fd_map[free_fd] == -1) {
19610037SARM gem5 Developers            fd_map[free_fd] = sim_fd;
19710037SARM gem5 Developers            return free_fd;
19810037SARM gem5 Developers        }
19910037SARM gem5 Developers    }
20010037SARM gem5 Developers
20110037SARM gem5 Developers    panic("Process::alloc_fd: out of file descriptors!");
20210037SARM gem5 Developers}
20310037SARM gem5 Developers
20410037SARM gem5 Developers
20510037SARM gem5 Developers// free target fd (e.g., after close)
20610037SARM gem5 Developersvoid
20710037SARM gem5 DevelopersProcess::free_fd(int tgt_fd)
20810037SARM gem5 Developers{
20910037SARM gem5 Developers    if (fd_map[tgt_fd] == -1)
21010037SARM gem5 Developers        warn("Process::free_fd: request to free unused fd %d", tgt_fd);
21110037SARM gem5 Developers
21210037SARM gem5 Developers    fd_map[tgt_fd] = -1;
21310037SARM gem5 Developers}
21410037SARM gem5 Developers
21510037SARM gem5 Developers
21610037SARM gem5 Developers// look up simulator fd for given target fd
21710037SARM gem5 Developersint
21810037SARM gem5 DevelopersProcess::sim_fd(int tgt_fd)
21910037SARM gem5 Developers{
22010037SARM gem5 Developers    if (tgt_fd > MAX_FD)
22110037SARM gem5 Developers        return -1;
22210037SARM gem5 Developers
22310037SARM gem5 Developers    return fd_map[tgt_fd];
22410037SARM gem5 Developers}
22510037SARM gem5 Developers
22610037SARM gem5 Developers
22710037SARM gem5 Developers
22810037SARM gem5 Developers//
22910037SARM gem5 Developers// need to declare these here since there is no concrete Process type
23010037SARM gem5 Developers// that can be constructed (i.e., no REGISTER_SIM_OBJECT() macro call,
23110037SARM gem5 Developers// which is where these get declared for concrete types).
23210037SARM gem5 Developers//
23310037SARM gem5 DevelopersDEFINE_SIM_OBJECT_CLASS_NAME("Process", Process)
23410037SARM gem5 Developers
23510037SARM gem5 Developers
23610037SARM gem5 Developers////////////////////////////////////////////////////////////////////////
23710037SARM gem5 Developers//
23810037SARM gem5 Developers// LiveProcess member definitions
23910037SARM gem5 Developers//
24010037SARM gem5 Developers////////////////////////////////////////////////////////////////////////
24110037SARM gem5 Developers
24210037SARM gem5 Developers
24310037SARM gem5 Developersstatic void
24410037SARM gem5 DeveloperscopyStringArray(vector<string> &strings, Addr array_ptr, Addr data_ptr,
24510037SARM gem5 Developers                TranslatingPort* memPort)
24610037SARM gem5 Developers{
24710037SARM gem5 Developers    Addr data_ptr_swap;
24810037SARM gem5 Developers    for (int i = 0; i < strings.size(); ++i) {
24910037SARM gem5 Developers        data_ptr_swap = htog(data_ptr);
25010037SARM gem5 Developers        memPort->writeBlob(array_ptr, (uint8_t*)&data_ptr_swap, sizeof(Addr));
25110037SARM gem5 Developers        memPort->writeString(data_ptr, strings[i].c_str());
25210037SARM gem5 Developers        array_ptr += sizeof(Addr);
25310037SARM gem5 Developers        data_ptr += strings[i].size() + 1;
25410037SARM gem5 Developers    }
25510037SARM gem5 Developers    // add NULL terminator
25610037SARM gem5 Developers    data_ptr = 0;
25710037SARM gem5 Developers
25810037SARM gem5 Developers    memPort->writeBlob(array_ptr, (uint8_t*)&data_ptr, sizeof(Addr));
25910037SARM gem5 Developers}
26010037SARM gem5 Developers
26110037SARM gem5 DevelopersLiveProcess::LiveProcess(const string &nm, ObjectFile *_objFile,
26210037SARM gem5 Developers                         System *_system,
26310037SARM gem5 Developers                         int stdin_fd, int stdout_fd, int stderr_fd,
26410037SARM gem5 Developers                         vector<string> &_argv, vector<string> &_envp)
26510037SARM gem5 Developers    : Process(nm, _system, stdin_fd, stdout_fd, stderr_fd),
26610037SARM gem5 Developers      objFile(_objFile), argv(_argv), envp(_envp)
26710037SARM gem5 Developers{
26810037SARM gem5 Developers    prog_fname = argv[0];
26910037SARM gem5 Developers
27010037SARM gem5 Developers    // load up symbols, if any... these may be used for debugging or
27110037SARM gem5 Developers    // profiling.
27210037SARM gem5 Developers    if (!debugSymbolTable) {
27310037SARM gem5 Developers        debugSymbolTable = new SymbolTable();
27410037SARM gem5 Developers        if (!objFile->loadGlobalSymbols(debugSymbolTable) ||
27510037SARM gem5 Developers            !objFile->loadLocalSymbols(debugSymbolTable)) {
27610037SARM gem5 Developers            // didn't load any symbols
27710037SARM gem5 Developers            delete debugSymbolTable;
27810037SARM gem5 Developers            debugSymbolTable = NULL;
27910037SARM gem5 Developers        }
28010037SARM gem5 Developers    }
28110037SARM gem5 Developers}
28210037SARM gem5 Developers
28310037SARM gem5 Developersvoid
28410037SARM gem5 DevelopersLiveProcess::argsInit(int intSize, int pageSize)
28510037SARM gem5 Developers{
28610037SARM gem5 Developers    Process::startup();
28710037SARM gem5 Developers
28810037SARM gem5 Developers    // load object file into target memory
28910037SARM gem5 Developers    objFile->loadSections(initVirtMem);
29010037SARM gem5 Developers
29110037SARM gem5 Developers    // Calculate how much space we need for arg & env arrays.
29210037SARM gem5 Developers    int argv_array_size = intSize * (argv.size() + 1);
29310037SARM gem5 Developers    int envp_array_size = intSize * (envp.size() + 1);
29410037SARM gem5 Developers    int arg_data_size = 0;
29510037SARM gem5 Developers    for (int i = 0; i < argv.size(); ++i) {
29610037SARM gem5 Developers        arg_data_size += argv[i].size() + 1;
29710037SARM gem5 Developers    }
29810037SARM gem5 Developers    int env_data_size = 0;
29910037SARM gem5 Developers    for (int i = 0; i < envp.size(); ++i) {
30010037SARM gem5 Developers        env_data_size += envp[i].size() + 1;
30110037SARM gem5 Developers    }
30210037SARM gem5 Developers
30310037SARM gem5 Developers    int space_needed =
30410037SARM gem5 Developers        argv_array_size + envp_array_size + arg_data_size + env_data_size;
30510037SARM gem5 Developers    // for SimpleScalar compatibility
30610037SARM gem5 Developers    if (space_needed < 16384)
30710037SARM gem5 Developers        space_needed = 16384;
30810037SARM gem5 Developers
30910037SARM gem5 Developers    // set bottom of stack
31010037SARM gem5 Developers    stack_min = stack_base - space_needed;
31110037SARM gem5 Developers    // align it
31210037SARM gem5 Developers    stack_min &= ~(intSize-1);
31310037SARM gem5 Developers    stack_size = stack_base - stack_min;
31410037SARM gem5 Developers    // map memory
31510037SARM gem5 Developers    pTable->allocate(roundDown(stack_min, pageSize),
31610037SARM gem5 Developers                     roundUp(stack_size, pageSize));
31710037SARM gem5 Developers
31810037SARM gem5 Developers    // map out initial stack contents
31910037SARM gem5 Developers    Addr argv_array_base = stack_min + intSize; // room for argc
32010037SARM gem5 Developers    Addr envp_array_base = argv_array_base + argv_array_size;
32110037SARM gem5 Developers    Addr arg_data_base = envp_array_base + envp_array_size;
32210037SARM gem5 Developers    Addr env_data_base = arg_data_base + arg_data_size;
32310037SARM gem5 Developers
32410037SARM gem5 Developers    // write contents to stack
32510037SARM gem5 Developers    uint64_t argc = argv.size();
32610037SARM gem5 Developers    if (intSize == 8)
32710037SARM gem5 Developers        argc = htog((uint64_t)argc);
32810037SARM gem5 Developers    else if (intSize == 4)
32910037SARM gem5 Developers        argc = htog((uint32_t)argc);
33010037SARM gem5 Developers    else
33110037SARM gem5 Developers        panic("Unknown int size");
33210037SARM gem5 Developers
33310037SARM gem5 Developers    initVirtMem->writeBlob(stack_min, (uint8_t*)&argc, intSize);
33410037SARM gem5 Developers
33510037SARM gem5 Developers    copyStringArray(argv, argv_array_base, arg_data_base, initVirtMem);
33610037SARM gem5 Developers    copyStringArray(envp, envp_array_base, env_data_base, initVirtMem);
33710037SARM gem5 Developers
33810037SARM gem5 Developers    execContexts[0]->setIntReg(ArgumentReg0, argc);
33910037SARM gem5 Developers    execContexts[0]->setIntReg(ArgumentReg1, argv_array_base);
34010037SARM gem5 Developers    execContexts[0]->setIntReg(StackPointerReg, stack_min);
34110037SARM gem5 Developers
34210037SARM gem5 Developers    Addr prog_entry = objFile->entryPoint();
34310037SARM gem5 Developers    execContexts[0]->setPC(prog_entry);
34410037SARM gem5 Developers    execContexts[0]->setNextPC(prog_entry + sizeof(MachInst));
34510037SARM gem5 Developers    execContexts[0]->setNextNPC(prog_entry + (2 * sizeof(MachInst)));
34610037SARM gem5 Developers
34710037SARM gem5 Developers    num_processes++;
34810037SARM gem5 Developers}
34910037SARM gem5 Developers
35010037SARM gem5 Developersvoid
35110037SARM gem5 DevelopersLiveProcess::syscall(ExecContext *xc)
35210037SARM gem5 Developers{
35310037SARM gem5 Developers    num_syscalls++;
35410037SARM gem5 Developers
35510037SARM gem5 Developers    int64_t callnum = xc->readIntReg(SyscallNumReg);
35610037SARM gem5 Developers
35710037SARM gem5 Developers    SyscallDesc *desc = getDesc(callnum);
35810037SARM gem5 Developers    if (desc == NULL)
35910037SARM gem5 Developers        fatal("Syscall %d out of range", callnum);
36010037SARM gem5 Developers
36110037SARM gem5 Developers    desc->doSyscall(callnum, this, xc);
36210037SARM gem5 Developers}
36310037SARM gem5 Developers
36410037SARM gem5 DevelopersDEFINE_SIM_OBJECT_CLASS_NAME("LiveProcess", LiveProcess);
36510037SARM gem5 Developers