process.cc revision 10905
12207SN/A/*
22207SN/A * Copyright (c) 2014 Advanced Micro Devices, Inc.
32207SN/A * Copyright (c) 2012 ARM Limited
42207SN/A * All rights reserved
52207SN/A *
62207SN/A * The license below extends only to copyright in the software and shall
72207SN/A * not be construed as granting a license to any other intellectual
82207SN/A * property including but not limited to intellectual property relating
92207SN/A * to a hardware implementation of the functionality of the software
102207SN/A * licensed hereunder.  You may use the software subject to the license
112207SN/A * terms below provided that you ensure that this notice is replicated
122207SN/A * unmodified and in its entirety in all distributions of the software,
132207SN/A * modified or unmodified, in source code or in binary form.
142207SN/A *
152207SN/A * Copyright (c) 2001-2005 The Regents of The University of Michigan
162207SN/A * All rights reserved.
172207SN/A *
182207SN/A * Redistribution and use in source and binary forms, with or without
192207SN/A * modification, are permitted provided that the following conditions are
202207SN/A * met: redistributions of source code must retain the above copyright
212207SN/A * notice, this list of conditions and the following disclaimer;
222207SN/A * redistributions in binary form must reproduce the above copyright
232207SN/A * notice, this list of conditions and the following disclaimer in the
242207SN/A * documentation and/or other materials provided with the distribution;
252207SN/A * neither the name of the copyright holders nor the names of its
262207SN/A * contributors may be used to endorse or promote products derived from
272665Ssaidi@eecs.umich.edu * this software without specific prior written permission.
282665Ssaidi@eecs.umich.edu *
292665Ssaidi@eecs.umich.edu * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
302207SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
312207SN/A * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
323589Sgblack@eecs.umich.edu * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
334111Sgblack@eecs.umich.edu * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
342474SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
352207SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
363760Sgblack@eecs.umich.edu * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
372454SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
382976Sgblack@eecs.umich.edu * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
392454SN/A * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
402680Sktlim@umich.edu *
412561SN/A * Authors: Nathan Binkert
424434Ssaidi@eecs.umich.edu *          Steve Reinhardt
432561SN/A *          Ali Saidi
442474SN/A */
452207SN/A
462458SN/A#include <fcntl.h>
472474SN/A#include <unistd.h>
482458SN/A
492207SN/A#include <cstdio>
505154Sgblack@eecs.umich.edu#include <string>
515285Sgblack@eecs.umich.edu
525285Sgblack@eecs.umich.edu#include "base/loader/object_file.hh"
532474SN/A#include "base/loader/symtab.hh"
542474SN/A#include "base/intmath.hh"
552474SN/A#include "base/statistics.hh"
562474SN/A#include "config/the_isa.hh"
572474SN/A#include "cpu/thread_context.hh"
582474SN/A#include "mem/page_table.hh"
592474SN/A#include "mem/multi_level_page_table.hh"
602474SN/A#include "mem/se_translating_port_proxy.hh"
613415Sgblack@eecs.umich.edu#include "params/LiveProcess.hh"
623415Sgblack@eecs.umich.edu#include "params/Process.hh"
633415Sgblack@eecs.umich.edu#include "sim/debug.hh"
643415Sgblack@eecs.umich.edu#include "sim/process.hh"
652474SN/A#include "sim/process_impl.hh"
662474SN/A#include "sim/stats.hh"
674111Sgblack@eecs.umich.edu#include "sim/syscall_emul.hh"
684111Sgblack@eecs.umich.edu#include "sim/system.hh"
694111Sgblack@eecs.umich.edu
704111Sgblack@eecs.umich.edu#if THE_ISA == ALPHA_ISA
715128Sgblack@eecs.umich.edu#include "arch/alpha/linux/process.hh"
725128Sgblack@eecs.umich.edu#include "arch/alpha/tru64/process.hh"
735128Sgblack@eecs.umich.edu#elif THE_ISA == SPARC_ISA
745128Sgblack@eecs.umich.edu#include "arch/sparc/linux/process.hh"
755128Sgblack@eecs.umich.edu#include "arch/sparc/solaris/process.hh"
765128Sgblack@eecs.umich.edu#elif THE_ISA == MIPS_ISA
775128Sgblack@eecs.umich.edu#include "arch/mips/linux/process.hh"
784111Sgblack@eecs.umich.edu#elif THE_ISA == ARM_ISA
795128Sgblack@eecs.umich.edu#include "arch/arm/linux/process.hh"
805128Sgblack@eecs.umich.edu#include "arch/arm/freebsd/process.hh"
815128Sgblack@eecs.umich.edu#elif THE_ISA == X86_ISA
825128Sgblack@eecs.umich.edu#include "arch/x86/linux/process.hh"
835128Sgblack@eecs.umich.edu#elif THE_ISA == POWER_ISA
845128Sgblack@eecs.umich.edu#include "arch/power/linux/process.hh"
855128Sgblack@eecs.umich.edu#else
865128Sgblack@eecs.umich.edu#error "THE_ISA not set"
875128Sgblack@eecs.umich.edu#endif
885128Sgblack@eecs.umich.edu
895128Sgblack@eecs.umich.edu
905128Sgblack@eecs.umich.eduusing namespace std;
915128Sgblack@eecs.umich.eduusing namespace TheISA;
925128Sgblack@eecs.umich.edu
935128Sgblack@eecs.umich.edu// current number of allocated processes
945128Sgblack@eecs.umich.eduint num_processes = 0;
955128Sgblack@eecs.umich.edu
965128Sgblack@eecs.umich.edutemplate<class IntType>
975128Sgblack@eecs.umich.eduAuxVector<IntType>::AuxVector(IntType type, IntType val)
985128Sgblack@eecs.umich.edu{
995128Sgblack@eecs.umich.edu    a_type = TheISA::htog(type);
1005128Sgblack@eecs.umich.edu    a_val = TheISA::htog(val);
1015128Sgblack@eecs.umich.edu}
1025128Sgblack@eecs.umich.edu
1035128Sgblack@eecs.umich.edutemplate struct AuxVector<uint32_t>;
1044111Sgblack@eecs.umich.edutemplate struct AuxVector<uint64_t>;
1054111Sgblack@eecs.umich.edu
1064111Sgblack@eecs.umich.eduProcess::Process(ProcessParams * params)
1074111Sgblack@eecs.umich.edu    : SimObject(params), system(params->system),
1084111Sgblack@eecs.umich.edu      brk_point(0), stack_base(0), stack_size(0), stack_min(0),
1094111Sgblack@eecs.umich.edu      max_stack_size(params->max_stack_size),
1102474SN/A      next_thread_stack_base(0),
1115285Sgblack@eecs.umich.edu      M5_pid(system->allocatePID()),
1124111Sgblack@eecs.umich.edu      useArchPT(params->useArchPT),
1135285Sgblack@eecs.umich.edu      kvmInSE(params->kvmInSE),
1144111Sgblack@eecs.umich.edu      pTable(useArchPT ?
1155713Shsul@eecs.umich.edu        static_cast<PageTableBase *>(new ArchPageTable(name(), M5_pid, system)) :
1164111Sgblack@eecs.umich.edu        static_cast<PageTableBase *>(new FuncPageTable(name(), M5_pid)) ),
1174111Sgblack@eecs.umich.edu      initVirtMem(system->getSystemPort(), this,
1182646Ssaidi@eecs.umich.edu                  SETranslatingPortProxy::Always)
1195713Shsul@eecs.umich.edu{
1202646Ssaidi@eecs.umich.edu    string in = params->input;
1215713Shsul@eecs.umich.edu    string out = params->output;
1224997Sgblack@eecs.umich.edu    string err = params->errout;
1232561SN/A
1242561SN/A    // initialize file descriptors to default: same as simulator
1252561SN/A    int stdin_fd, stdout_fd, stderr_fd;
1262561SN/A
1272561SN/A    if (in == "stdin" || in == "cin")
1285713Shsul@eecs.umich.edu        stdin_fd = STDIN_FILENO;
1295713Shsul@eecs.umich.edu    else if (in == "None")
1302561SN/A        stdin_fd = -1;
1315713Shsul@eecs.umich.edu    else
1325713Shsul@eecs.umich.edu        stdin_fd = Process::openInputFile(in);
1332561SN/A
1345713Shsul@eecs.umich.edu    if (out == "stdout" || out == "cout")
1355713Shsul@eecs.umich.edu        stdout_fd = STDOUT_FILENO;
1362561SN/A    else if (out == "stderr" || out == "cerr")
1375713Shsul@eecs.umich.edu        stdout_fd = STDERR_FILENO;
1385713Shsul@eecs.umich.edu    else if (out == "None")
1392561SN/A        stdout_fd = -1;
1405713Shsul@eecs.umich.edu    else
1413415Sgblack@eecs.umich.edu        stdout_fd = Process::openOutputFile(out);
1425713Shsul@eecs.umich.edu
1435713Shsul@eecs.umich.edu    if (err == "stdout" || err == "cout")
1443415Sgblack@eecs.umich.edu        stderr_fd = STDOUT_FILENO;
1455713Shsul@eecs.umich.edu    else if (err == "stderr" || err == "cerr")
1463589Sgblack@eecs.umich.edu        stderr_fd = STDERR_FILENO;
1475713Shsul@eecs.umich.edu    else if (err == "None")
1484997Sgblack@eecs.umich.edu        stderr_fd = -1;
1494997Sgblack@eecs.umich.edu    else if (err == out)
1504997Sgblack@eecs.umich.edu        stderr_fd = stdout_fd;
1514997Sgblack@eecs.umich.edu    else
1524997Sgblack@eecs.umich.edu        stderr_fd = Process::openOutputFile(err);
1535713Shsul@eecs.umich.edu
1542474SN/A    // initialize first 3 fds (stdin, stdout, stderr)
1552474SN/A    Process::FdMap *fdo = &fd_map[STDIN_FILENO];
1565285Sgblack@eecs.umich.edu    fdo->fd = stdin_fd;
1575285Sgblack@eecs.umich.edu    fdo->filename = in;
1582585SN/A    fdo->flags = O_RDONLY;
1595285Sgblack@eecs.umich.edu    fdo->mode = -1;
1605285Sgblack@eecs.umich.edu    fdo->fileOffset = 0;
1612585SN/A
1625285Sgblack@eecs.umich.edu    fdo =  &fd_map[STDOUT_FILENO];
1635285Sgblack@eecs.umich.edu    fdo->fd = stdout_fd;
1645713Shsul@eecs.umich.edu    fdo->filename = out;
1655285Sgblack@eecs.umich.edu    fdo->flags =  O_WRONLY | O_CREAT | O_TRUNC;
1665713Shsul@eecs.umich.edu    fdo->mode = 0774;
1675285Sgblack@eecs.umich.edu    fdo->fileOffset = 0;
1685285Sgblack@eecs.umich.edu
1694111Sgblack@eecs.umich.edu    fdo = &fd_map[STDERR_FILENO];
1703415Sgblack@eecs.umich.edu    fdo->fd = stderr_fd;
1712561SN/A    fdo->filename = err;
1725285Sgblack@eecs.umich.edu    fdo->flags = O_WRONLY;
1732561SN/A    fdo->mode = -1;
1745285Sgblack@eecs.umich.edu    fdo->fileOffset = 0;
1755285Sgblack@eecs.umich.edu
1765285Sgblack@eecs.umich.edu
1775285Sgblack@eecs.umich.edu    // mark remaining fds as free
1785285Sgblack@eecs.umich.edu    for (int i = 3; i <= MAX_FD; ++i) {
1795713Shsul@eecs.umich.edu        fdo = &fd_map[i];
1805285Sgblack@eecs.umich.edu        fdo->fd = -1;
1815713Shsul@eecs.umich.edu    }
1825285Sgblack@eecs.umich.edu
1835285Sgblack@eecs.umich.edu    mmap_start = mmap_end = 0;
1845285Sgblack@eecs.umich.edu    nxm_start = nxm_end = 0;
1855285Sgblack@eecs.umich.edu    // other parameters will be initialized when the program is loaded
1865285Sgblack@eecs.umich.edu}
1875285Sgblack@eecs.umich.edu
1885285Sgblack@eecs.umich.edu
1895285Sgblack@eecs.umich.eduvoid
1905285Sgblack@eecs.umich.eduProcess::regStats()
1915285Sgblack@eecs.umich.edu{
1925771Shsul@eecs.umich.edu    using namespace Stats;
1935285Sgblack@eecs.umich.edu
1945285Sgblack@eecs.umich.edu    num_syscalls
1952474SN/A        .name(name() + ".num_syscalls")
1963044Sgblack@eecs.umich.edu        .desc("Number of system calls")
1973044Sgblack@eecs.umich.edu        ;
1983044Sgblack@eecs.umich.edu}
1993044Sgblack@eecs.umich.edu
2003044Sgblack@eecs.umich.edu//
2013044Sgblack@eecs.umich.edu// static helper functions
2025285Sgblack@eecs.umich.edu//
2035285Sgblack@eecs.umich.eduint
2045286Sgblack@eecs.umich.eduProcess::openInputFile(const string &filename)
2052561SN/A{
2062561SN/A    int fd = open(filename.c_str(), O_RDONLY);
2072561SN/A
2082561SN/A    if (fd == -1) {
2092585SN/A        perror(NULL);
2102585SN/A        cerr << "unable to open \"" << filename << "\" for reading\n";
2112585SN/A        fatal("can't open input file");
2122585SN/A    }
2132585SN/A
2142585SN/A    return fd;
2152585SN/A}
2162585SN/A
2172585SN/A
2182585SN/Aint
2192585SN/AProcess::openOutputFile(const string &filename)
2202585SN/A{
2212585SN/A    int fd = open(filename.c_str(), O_WRONLY | O_CREAT | O_TRUNC, 0664);
2222585SN/A
2232585SN/A    if (fd == -1) {
2242585SN/A        perror(NULL);
2252585SN/A        cerr << "unable to open \"" << filename << "\" for writing\n";
2262585SN/A        fatal("can't open output file");
2272585SN/A    }
2282585SN/A
2292585SN/A    return fd;
2302976Sgblack@eecs.umich.edu}
2312976Sgblack@eecs.umich.edu
2322976Sgblack@eecs.umich.eduThreadContext *
2332976Sgblack@eecs.umich.eduProcess::findFreeContext()
2342976Sgblack@eecs.umich.edu{
2352976Sgblack@eecs.umich.edu    int size = contextIds.size();
2364793Sgblack@eecs.umich.edu    ThreadContext *tc;
2372976Sgblack@eecs.umich.edu    for (int i = 0; i < size; ++i) {
2384793Sgblack@eecs.umich.edu        tc = system->getThreadContext(contextIds[i]);
2392976Sgblack@eecs.umich.edu        if (tc->status() == ThreadContext::Halted) {
2402976Sgblack@eecs.umich.edu            // inactive context, free to use
2414793Sgblack@eecs.umich.edu            return tc;
2422976Sgblack@eecs.umich.edu        }
2432976Sgblack@eecs.umich.edu    }
2444793Sgblack@eecs.umich.edu    return NULL;
2452976Sgblack@eecs.umich.edu}
2464793Sgblack@eecs.umich.edu
2472976Sgblack@eecs.umich.eduvoid
2484793Sgblack@eecs.umich.eduProcess::initState()
2492976Sgblack@eecs.umich.edu{
2502976Sgblack@eecs.umich.edu    if (contextIds.empty())
2512976Sgblack@eecs.umich.edu        fatal("Process %s is not associated with any HW contexts!\n", name());
2524793Sgblack@eecs.umich.edu
2532976Sgblack@eecs.umich.edu    // first thread context for this process... initialize & enable
2544793Sgblack@eecs.umich.edu    ThreadContext *tc = system->getThreadContext(contextIds[0]);
2552976Sgblack@eecs.umich.edu
2564793Sgblack@eecs.umich.edu    // mark this context as active so it will start ticking.
2572976Sgblack@eecs.umich.edu    tc->activate();
2584793Sgblack@eecs.umich.edu
2594793Sgblack@eecs.umich.edu    pTable->initState(tc);
2604793Sgblack@eecs.umich.edu}
2614793Sgblack@eecs.umich.edu
2622976Sgblack@eecs.umich.eduunsigned int
2634793Sgblack@eecs.umich.eduProcess::drain(DrainManager *dm)
2642976Sgblack@eecs.umich.edu{
2652585SN/A    find_file_offsets();
2662561SN/A    return 0;
2672561SN/A}
2684164Sgblack@eecs.umich.edu
2695286Sgblack@eecs.umich.edu// map simulator fd sim_fd to target fd tgt_fd
2704111Sgblack@eecs.umich.eduvoid
2714111Sgblack@eecs.umich.eduProcess::dup_fd(int sim_fd, int tgt_fd)
2724111Sgblack@eecs.umich.edu{
2734111Sgblack@eecs.umich.edu    if (tgt_fd < 0 || tgt_fd > MAX_FD)
2744111Sgblack@eecs.umich.edu        panic("Process::dup_fd tried to dup past MAX_FD (%d)", tgt_fd);
2754111Sgblack@eecs.umich.edu
2764111Sgblack@eecs.umich.edu    Process::FdMap *fdo = &fd_map[tgt_fd];
2774111Sgblack@eecs.umich.edu    fdo->fd = sim_fd;
2784111Sgblack@eecs.umich.edu}
2794111Sgblack@eecs.umich.edu
2804111Sgblack@eecs.umich.edu
2814111Sgblack@eecs.umich.edu// generate new target fd for sim_fd
2824111Sgblack@eecs.umich.eduint
2834111Sgblack@eecs.umich.eduProcess::alloc_fd(int sim_fd, const string& filename, int flags, int mode,
2845286Sgblack@eecs.umich.edu                  bool pipe)
2855286Sgblack@eecs.umich.edu{
2865286Sgblack@eecs.umich.edu    // in case open() returns an error, don't allocate a new fd
2875286Sgblack@eecs.umich.edu    if (sim_fd == -1)
2885286Sgblack@eecs.umich.edu        return -1;
2895286Sgblack@eecs.umich.edu
2905286Sgblack@eecs.umich.edu    // find first free target fd
2914111Sgblack@eecs.umich.edu    for (int free_fd = 0; free_fd <= MAX_FD; ++free_fd) {
2925285Sgblack@eecs.umich.edu        Process::FdMap *fdo = &fd_map[free_fd];
2934111Sgblack@eecs.umich.edu        if (fdo->fd == -1 && fdo->driver == NULL) {
2944111Sgblack@eecs.umich.edu            fdo->fd = sim_fd;
2954111Sgblack@eecs.umich.edu            fdo->filename = filename;
2964111Sgblack@eecs.umich.edu            fdo->mode = mode;
2974111Sgblack@eecs.umich.edu            fdo->fileOffset = 0;
2984111Sgblack@eecs.umich.edu            fdo->flags = flags;
2994111Sgblack@eecs.umich.edu            fdo->isPipe = pipe;
3004111Sgblack@eecs.umich.edu            fdo->readPipeSource = 0;
3015286Sgblack@eecs.umich.edu            return free_fd;
3025286Sgblack@eecs.umich.edu        }
3034111Sgblack@eecs.umich.edu    }
3044111Sgblack@eecs.umich.edu
3054111Sgblack@eecs.umich.edu    panic("Process::alloc_fd: out of file descriptors!");
3064111Sgblack@eecs.umich.edu}
3074111Sgblack@eecs.umich.edu
3084111Sgblack@eecs.umich.edu
3095286Sgblack@eecs.umich.edu// free target fd (e.g., after close)
3105286Sgblack@eecs.umich.eduvoid
3115286Sgblack@eecs.umich.eduProcess::free_fd(int tgt_fd)
3125286Sgblack@eecs.umich.edu{
3135286Sgblack@eecs.umich.edu    Process::FdMap *fdo = &fd_map[tgt_fd];
3145286Sgblack@eecs.umich.edu    if (fdo->fd == -1)
3155286Sgblack@eecs.umich.edu        warn("Process::free_fd: request to free unused fd %d", tgt_fd);
3165286Sgblack@eecs.umich.edu
3175286Sgblack@eecs.umich.edu    fdo->fd = -1;
3185286Sgblack@eecs.umich.edu    fdo->filename = "NULL";
3194111Sgblack@eecs.umich.edu    fdo->mode = 0;
3205286Sgblack@eecs.umich.edu    fdo->fileOffset = 0;
3214111Sgblack@eecs.umich.edu    fdo->flags = 0;
3224111Sgblack@eecs.umich.edu    fdo->isPipe = false;
3235285Sgblack@eecs.umich.edu    fdo->readPipeSource = 0;
3244111Sgblack@eecs.umich.edu    fdo->driver = NULL;
3254111Sgblack@eecs.umich.edu}
3264111Sgblack@eecs.umich.edu
3274111Sgblack@eecs.umich.edu
3285286Sgblack@eecs.umich.edu// look up simulator fd for given target fd
3295286Sgblack@eecs.umich.eduint
3305286Sgblack@eecs.umich.eduProcess::sim_fd(int tgt_fd)
3315286Sgblack@eecs.umich.edu{
3325286Sgblack@eecs.umich.edu    if (tgt_fd < 0 || tgt_fd > MAX_FD)
3335286Sgblack@eecs.umich.edu        return -1;
3345286Sgblack@eecs.umich.edu
3355286Sgblack@eecs.umich.edu    return fd_map[tgt_fd].fd;
3365286Sgblack@eecs.umich.edu}
3375286Sgblack@eecs.umich.edu
3385286Sgblack@eecs.umich.eduProcess::FdMap *
3395286Sgblack@eecs.umich.eduProcess::sim_fd_obj(int tgt_fd)
3404111Sgblack@eecs.umich.edu{
3415941Sgblack@eecs.umich.edu    if (tgt_fd < 0 || tgt_fd > MAX_FD)
3425941Sgblack@eecs.umich.edu        return NULL;
3435941Sgblack@eecs.umich.edu
3445941Sgblack@eecs.umich.edu    return &fd_map[tgt_fd];
3455941Sgblack@eecs.umich.edu}
3465941Sgblack@eecs.umich.edu
3475941Sgblack@eecs.umich.eduvoid
3485941Sgblack@eecs.umich.eduProcess::allocateMem(Addr vaddr, int64_t size, bool clobber)
3495941Sgblack@eecs.umich.edu{
3505941Sgblack@eecs.umich.edu    int npages = divCeil(size, (int64_t)PageBytes);
3515941Sgblack@eecs.umich.edu    Addr paddr = system->allocPhysPages(npages);
3525941Sgblack@eecs.umich.edu    pTable->map(vaddr, paddr, size, clobber ? PageTableBase::Clobber : 0);
3534111Sgblack@eecs.umich.edu}
3545286Sgblack@eecs.umich.edu
3555286Sgblack@eecs.umich.edubool
3564111Sgblack@eecs.umich.eduProcess::fixupStackFault(Addr vaddr)
3574111Sgblack@eecs.umich.edu{
3584111Sgblack@eecs.umich.edu    // Check if this is already on the stack and there's just no page there
3595285Sgblack@eecs.umich.edu    // yet.
3605567Snate@binkert.org    if (vaddr >= stack_min && vaddr < stack_base) {
3614111Sgblack@eecs.umich.edu        allocateMem(roundDown(vaddr, PageBytes), PageBytes);
3625286Sgblack@eecs.umich.edu        return true;
3635286Sgblack@eecs.umich.edu    }
3645286Sgblack@eecs.umich.edu
3655286Sgblack@eecs.umich.edu    // We've accessed the next page of the stack, so extend it to include
3664111Sgblack@eecs.umich.edu    // this address.
3674111Sgblack@eecs.umich.edu    if (vaddr < stack_min && vaddr >= stack_base - max_stack_size) {
3684111Sgblack@eecs.umich.edu        while (vaddr < stack_min) {
3694111Sgblack@eecs.umich.edu            stack_min -= TheISA::PageBytes;
3704111Sgblack@eecs.umich.edu            if (stack_base - stack_min > max_stack_size)
3714111Sgblack@eecs.umich.edu                fatal("Maximum stack size exceeded\n");
3724111Sgblack@eecs.umich.edu            allocateMem(stack_min, TheISA::PageBytes);
3734111Sgblack@eecs.umich.edu            inform("Increasing stack size by one page.");
3744111Sgblack@eecs.umich.edu        };
3754111Sgblack@eecs.umich.edu        return true;
3764111Sgblack@eecs.umich.edu    }
3774111Sgblack@eecs.umich.edu    return false;
3785285Sgblack@eecs.umich.edu}
3794111Sgblack@eecs.umich.edu
3805285Sgblack@eecs.umich.edu// find all offsets for currently open files and save them
3815286Sgblack@eecs.umich.eduvoid
3825286Sgblack@eecs.umich.eduProcess::fix_file_offsets()
3835286Sgblack@eecs.umich.edu{
3845286Sgblack@eecs.umich.edu    Process::FdMap *fdo_stdin = &fd_map[STDIN_FILENO];
3854111Sgblack@eecs.umich.edu    Process::FdMap *fdo_stdout = &fd_map[STDOUT_FILENO];
3864117Sgblack@eecs.umich.edu    Process::FdMap *fdo_stderr = &fd_map[STDERR_FILENO];
3874117Sgblack@eecs.umich.edu    string in = fdo_stdin->filename;
3884111Sgblack@eecs.umich.edu    string out = fdo_stdout->filename;
3894111Sgblack@eecs.umich.edu    string err = fdo_stderr->filename;
3904111Sgblack@eecs.umich.edu
3915285Sgblack@eecs.umich.edu    // initialize file descriptors to default: same as simulator
3925285Sgblack@eecs.umich.edu    int stdin_fd, stdout_fd, stderr_fd;
3935285Sgblack@eecs.umich.edu
3944111Sgblack@eecs.umich.edu    if (in == "stdin" || in == "cin")
3955285Sgblack@eecs.umich.edu        stdin_fd = STDIN_FILENO;
3964111Sgblack@eecs.umich.edu    else if (in == "NULL")
3975713Shsul@eecs.umich.edu        stdin_fd = -1;
3984111Sgblack@eecs.umich.edu    else {
3994772Sgblack@eecs.umich.edu        // open standard in and seek to the right location
4005713Shsul@eecs.umich.edu        stdin_fd = Process::openInputFile(in);
4015713Shsul@eecs.umich.edu        if (lseek(stdin_fd, fdo_stdin->fileOffset, SEEK_SET) < 0)
4025713Shsul@eecs.umich.edu            panic("Unable to seek to correct location in file: %s", in);
4034111Sgblack@eecs.umich.edu    }
4045231Sgblack@eecs.umich.edu
4055231Sgblack@eecs.umich.edu    if (out == "stdout" || out == "cout")
4065713Shsul@eecs.umich.edu        stdout_fd = STDOUT_FILENO;
4075231Sgblack@eecs.umich.edu    else if (out == "stderr" || out == "cerr")
4085285Sgblack@eecs.umich.edu        stdout_fd = STDERR_FILENO;
4095713Shsul@eecs.umich.edu    else if (out == "NULL")
4105713Shsul@eecs.umich.edu        stdout_fd = -1;
4115713Shsul@eecs.umich.edu    else {
4124111Sgblack@eecs.umich.edu        stdout_fd = Process::openOutputFile(out);
4134111Sgblack@eecs.umich.edu        if (lseek(stdout_fd, fdo_stdout->fileOffset, SEEK_SET) < 0)
4144111Sgblack@eecs.umich.edu            panic("Unable to seek to correct location in file: %s", out);
4154111Sgblack@eecs.umich.edu    }
4164111Sgblack@eecs.umich.edu
4174111Sgblack@eecs.umich.edu    if (err == "stdout" || err == "cout")
4185128Sgblack@eecs.umich.edu        stderr_fd = STDOUT_FILENO;
4195285Sgblack@eecs.umich.edu    else if (err == "stderr" || err == "cerr")
4205285Sgblack@eecs.umich.edu        stderr_fd = STDERR_FILENO;
4215285Sgblack@eecs.umich.edu    else if (err == "NULL")
4225285Sgblack@eecs.umich.edu        stderr_fd = -1;
4235285Sgblack@eecs.umich.edu    else if (err == out)
4245285Sgblack@eecs.umich.edu        stderr_fd = stdout_fd;
4255285Sgblack@eecs.umich.edu    else {
4265285Sgblack@eecs.umich.edu        stderr_fd = Process::openOutputFile(err);
4275285Sgblack@eecs.umich.edu        if (lseek(stderr_fd, fdo_stderr->fileOffset, SEEK_SET) < 0)
4285285Sgblack@eecs.umich.edu            panic("Unable to seek to correct location in file: %s", err);
4295285Sgblack@eecs.umich.edu    }
4305285Sgblack@eecs.umich.edu
4315285Sgblack@eecs.umich.edu    fdo_stdin->fd = stdin_fd;
4325285Sgblack@eecs.umich.edu    fdo_stdout->fd = stdout_fd;
4335285Sgblack@eecs.umich.edu    fdo_stderr->fd = stderr_fd;
4345285Sgblack@eecs.umich.edu
4355285Sgblack@eecs.umich.edu
4365285Sgblack@eecs.umich.edu    for (int free_fd = 3; free_fd <= MAX_FD; ++free_fd) {
4375285Sgblack@eecs.umich.edu        Process::FdMap *fdo = &fd_map[free_fd];
4385285Sgblack@eecs.umich.edu        if (fdo->fd != -1) {
4395285Sgblack@eecs.umich.edu            if (fdo->isPipe){
4405285Sgblack@eecs.umich.edu                if (fdo->filename == "PIPE-WRITE")
4415285Sgblack@eecs.umich.edu                    continue;
4425285Sgblack@eecs.umich.edu                else {
4435128Sgblack@eecs.umich.edu                    assert (fdo->filename == "PIPE-READ");
4445128Sgblack@eecs.umich.edu                    //create a new pipe
4455128Sgblack@eecs.umich.edu                    int fds[2];
4465128Sgblack@eecs.umich.edu                    int pipe_retval = pipe(fds);
4475128Sgblack@eecs.umich.edu
4485128Sgblack@eecs.umich.edu                    if (pipe_retval < 0) {
4495128Sgblack@eecs.umich.edu                        // error
4505128Sgblack@eecs.umich.edu                        panic("Unable to create new pipe.");
4515128Sgblack@eecs.umich.edu                    }
4525128Sgblack@eecs.umich.edu                    fdo->fd = fds[0]; //set read pipe
4535128Sgblack@eecs.umich.edu                    Process::FdMap *fdo_write = &fd_map[fdo->readPipeSource];
4545128Sgblack@eecs.umich.edu                    if (fdo_write->filename != "PIPE-WRITE")
4555128Sgblack@eecs.umich.edu                        panic ("Couldn't find write end of the pipe");
4565128Sgblack@eecs.umich.edu
4575128Sgblack@eecs.umich.edu                    fdo_write->fd = fds[1];//set write pipe
4585128Sgblack@eecs.umich.edu               }
4595128Sgblack@eecs.umich.edu            } else {
4605287Sgblack@eecs.umich.edu                //Open file
4615128Sgblack@eecs.umich.edu                int fd = open(fdo->filename.c_str(), fdo->flags, fdo->mode);
4625128Sgblack@eecs.umich.edu
4635128Sgblack@eecs.umich.edu                if (fd == -1)
4645128Sgblack@eecs.umich.edu                    panic("Unable to open file: %s", fdo->filename);
4655128Sgblack@eecs.umich.edu                fdo->fd = fd;
4665128Sgblack@eecs.umich.edu
4675128Sgblack@eecs.umich.edu                //Seek to correct location before checkpoint
4685128Sgblack@eecs.umich.edu                if (lseek(fd, fdo->fileOffset, SEEK_SET) < 0)
4695128Sgblack@eecs.umich.edu                    panic("Unable to seek to correct location in file: %s",
4705128Sgblack@eecs.umich.edu                          fdo->filename);
4715128Sgblack@eecs.umich.edu            }
4725128Sgblack@eecs.umich.edu        }
4735128Sgblack@eecs.umich.edu    }
4745128Sgblack@eecs.umich.edu}
4755128Sgblack@eecs.umich.edu
4765128Sgblack@eecs.umich.eduvoid
4775128Sgblack@eecs.umich.eduProcess::find_file_offsets()
4785128Sgblack@eecs.umich.edu{
4795128Sgblack@eecs.umich.edu    for (int free_fd = 0; free_fd <= MAX_FD; ++free_fd) {
4805128Sgblack@eecs.umich.edu        Process::FdMap *fdo = &fd_map[free_fd];
4815128Sgblack@eecs.umich.edu        if (fdo->fd != -1) {
4825128Sgblack@eecs.umich.edu            fdo->fileOffset = lseek(fdo->fd, 0, SEEK_CUR);
4835128Sgblack@eecs.umich.edu        } else {
4845128Sgblack@eecs.umich.edu            fdo->filename = "NULL";
4855128Sgblack@eecs.umich.edu            fdo->fileOffset = 0;
4865128Sgblack@eecs.umich.edu        }
4875128Sgblack@eecs.umich.edu    }
4885128Sgblack@eecs.umich.edu}
4895128Sgblack@eecs.umich.edu
4905128Sgblack@eecs.umich.eduvoid
4915128Sgblack@eecs.umich.eduProcess::setReadPipeSource(int read_pipe_fd, int source_fd)
4925128Sgblack@eecs.umich.edu{
4935128Sgblack@eecs.umich.edu    Process::FdMap *fdo = &fd_map[read_pipe_fd];
4945128Sgblack@eecs.umich.edu    fdo->readPipeSource = source_fd;
4955128Sgblack@eecs.umich.edu}
4965128Sgblack@eecs.umich.edu
4975128Sgblack@eecs.umich.eduvoid
4985128Sgblack@eecs.umich.eduProcess::FdMap::serialize(CheckpointOut &cp) const
4995128Sgblack@eecs.umich.edu{
5005128Sgblack@eecs.umich.edu    SERIALIZE_SCALAR(fd);
5015128Sgblack@eecs.umich.edu    SERIALIZE_SCALAR(isPipe);
5025128Sgblack@eecs.umich.edu    SERIALIZE_SCALAR(filename);
5035128Sgblack@eecs.umich.edu    SERIALIZE_SCALAR(flags);
5045128Sgblack@eecs.umich.edu    SERIALIZE_SCALAR(readPipeSource);
5055128Sgblack@eecs.umich.edu    SERIALIZE_SCALAR(fileOffset);
5065128Sgblack@eecs.umich.edu}
5075128Sgblack@eecs.umich.edu
5085128Sgblack@eecs.umich.eduvoid
5095128Sgblack@eecs.umich.eduProcess::FdMap::unserialize(CheckpointIn &cp)
5105128Sgblack@eecs.umich.edu{
5115128Sgblack@eecs.umich.edu    UNSERIALIZE_SCALAR(fd);
512    UNSERIALIZE_SCALAR(isPipe);
513    UNSERIALIZE_SCALAR(filename);
514    UNSERIALIZE_SCALAR(flags);
515    UNSERIALIZE_SCALAR(readPipeSource);
516    UNSERIALIZE_SCALAR(fileOffset);
517}
518
519void
520Process::serialize(CheckpointOut &cp) const
521{
522    SERIALIZE_SCALAR(brk_point);
523    SERIALIZE_SCALAR(stack_base);
524    SERIALIZE_SCALAR(stack_size);
525    SERIALIZE_SCALAR(stack_min);
526    SERIALIZE_SCALAR(next_thread_stack_base);
527    SERIALIZE_SCALAR(mmap_start);
528    SERIALIZE_SCALAR(mmap_end);
529    SERIALIZE_SCALAR(nxm_start);
530    SERIALIZE_SCALAR(nxm_end);
531    pTable->serialize(cp);
532    for (int x = 0; x <= MAX_FD; x++) {
533        fd_map[x].serializeSection(cp, csprintf("FdMap%d", x));
534    }
535    SERIALIZE_SCALAR(M5_pid);
536
537}
538
539void
540Process::unserialize(CheckpointIn &cp)
541{
542    UNSERIALIZE_SCALAR(brk_point);
543    UNSERIALIZE_SCALAR(stack_base);
544    UNSERIALIZE_SCALAR(stack_size);
545    UNSERIALIZE_SCALAR(stack_min);
546    UNSERIALIZE_SCALAR(next_thread_stack_base);
547    UNSERIALIZE_SCALAR(mmap_start);
548    UNSERIALIZE_SCALAR(mmap_end);
549    UNSERIALIZE_SCALAR(nxm_start);
550    UNSERIALIZE_SCALAR(nxm_end);
551    pTable->unserialize(cp);
552    for (int x = 0; x <= MAX_FD; x++) {
553        fd_map[x].unserializeSection(cp, csprintf("FdMap%d", x));
554    }
555    fix_file_offsets();
556    UNSERIALIZE_OPT_SCALAR(M5_pid);
557    // The above returns a bool so that you could do something if you don't
558    // find the param in the checkpoint if you wanted to, like set a default
559    // but in this case we'll just stick with the instantianted value if not
560    // found.
561}
562
563
564bool
565Process::map(Addr vaddr, Addr paddr, int size, bool cacheable)
566{
567    pTable->map(vaddr, paddr, size,
568                cacheable ? 0 : PageTableBase::Uncacheable);
569    return true;
570}
571
572
573////////////////////////////////////////////////////////////////////////
574//
575// LiveProcess member definitions
576//
577////////////////////////////////////////////////////////////////////////
578
579
580LiveProcess::LiveProcess(LiveProcessParams *params, ObjectFile *_objFile)
581    : Process(params), objFile(_objFile),
582      argv(params->cmd), envp(params->env), cwd(params->cwd),
583      __uid(params->uid), __euid(params->euid),
584      __gid(params->gid), __egid(params->egid),
585      __pid(params->pid), __ppid(params->ppid),
586      drivers(params->drivers)
587{
588
589    // load up symbols, if any... these may be used for debugging or
590    // profiling.
591    if (!debugSymbolTable) {
592        debugSymbolTable = new SymbolTable();
593        if (!objFile->loadGlobalSymbols(debugSymbolTable) ||
594            !objFile->loadLocalSymbols(debugSymbolTable) ||
595            !objFile->loadWeakSymbols(debugSymbolTable)) {
596            // didn't load any symbols
597            delete debugSymbolTable;
598            debugSymbolTable = NULL;
599        }
600    }
601}
602
603void
604LiveProcess::syscall(int64_t callnum, ThreadContext *tc)
605{
606    num_syscalls++;
607
608    SyscallDesc *desc = getDesc(callnum);
609    if (desc == NULL)
610        fatal("Syscall %d out of range", callnum);
611
612    desc->doSyscall(callnum, this, tc);
613}
614
615IntReg
616LiveProcess::getSyscallArg(ThreadContext *tc, int &i, int width)
617{
618    return getSyscallArg(tc, i);
619}
620
621
622EmulatedDriver *
623LiveProcess::findDriver(std::string filename)
624{
625    for (EmulatedDriver *d : drivers) {
626        if (d->match(filename))
627            return d;
628    }
629
630    return NULL;
631}
632
633
634LiveProcess *
635LiveProcess::create(LiveProcessParams * params)
636{
637    LiveProcess *process = NULL;
638
639    string executable =
640        params->executable == "" ? params->cmd[0] : params->executable;
641    ObjectFile *objFile = createObjectFile(executable);
642    if (objFile == NULL) {
643        fatal("Can't load object file %s", executable);
644    }
645
646    if (objFile->isDynamic())
647       fatal("Object file is a dynamic executable however only static "
648             "executables are supported!\n       Please recompile your "
649             "executable as a static binary and try again.\n");
650
651#if THE_ISA == ALPHA_ISA
652    if (objFile->getArch() != ObjectFile::Alpha)
653        fatal("Object file architecture does not match compiled ISA (Alpha).");
654
655    switch (objFile->getOpSys()) {
656      case ObjectFile::Tru64:
657        process = new AlphaTru64Process(params, objFile);
658        break;
659
660      case ObjectFile::UnknownOpSys:
661        warn("Unknown operating system; assuming Linux.");
662        // fall through
663      case ObjectFile::Linux:
664        process = new AlphaLinuxProcess(params, objFile);
665        break;
666
667      default:
668        fatal("Unknown/unsupported operating system.");
669    }
670#elif THE_ISA == SPARC_ISA
671    if (objFile->getArch() != ObjectFile::SPARC64 &&
672        objFile->getArch() != ObjectFile::SPARC32)
673        fatal("Object file architecture does not match compiled ISA (SPARC).");
674    switch (objFile->getOpSys()) {
675      case ObjectFile::UnknownOpSys:
676        warn("Unknown operating system; assuming Linux.");
677        // fall through
678      case ObjectFile::Linux:
679        if (objFile->getArch() == ObjectFile::SPARC64) {
680            process = new Sparc64LinuxProcess(params, objFile);
681        } else {
682            process = new Sparc32LinuxProcess(params, objFile);
683        }
684        break;
685
686
687      case ObjectFile::Solaris:
688        process = new SparcSolarisProcess(params, objFile);
689        break;
690
691      default:
692        fatal("Unknown/unsupported operating system.");
693    }
694#elif THE_ISA == X86_ISA
695    if (objFile->getArch() != ObjectFile::X86_64 &&
696        objFile->getArch() != ObjectFile::I386)
697        fatal("Object file architecture does not match compiled ISA (x86).");
698    switch (objFile->getOpSys()) {
699      case ObjectFile::UnknownOpSys:
700        warn("Unknown operating system; assuming Linux.");
701        // fall through
702      case ObjectFile::Linux:
703        if (objFile->getArch() == ObjectFile::X86_64) {
704            process = new X86_64LinuxProcess(params, objFile);
705        } else {
706            process = new I386LinuxProcess(params, objFile);
707        }
708        break;
709
710      default:
711        fatal("Unknown/unsupported operating system.");
712    }
713#elif THE_ISA == MIPS_ISA
714    if (objFile->getArch() != ObjectFile::Mips)
715        fatal("Object file architecture does not match compiled ISA (MIPS).");
716    switch (objFile->getOpSys()) {
717      case ObjectFile::UnknownOpSys:
718        warn("Unknown operating system; assuming Linux.");
719        // fall through
720      case ObjectFile::Linux:
721        process = new MipsLinuxProcess(params, objFile);
722        break;
723
724      default:
725        fatal("Unknown/unsupported operating system.");
726    }
727#elif THE_ISA == ARM_ISA
728    ObjectFile::Arch arch = objFile->getArch();
729    if (arch != ObjectFile::Arm && arch != ObjectFile::Thumb &&
730        arch != ObjectFile::Arm64)
731        fatal("Object file architecture does not match compiled ISA (ARM).");
732    switch (objFile->getOpSys()) {
733      case ObjectFile::UnknownOpSys:
734        warn("Unknown operating system; assuming Linux.");
735        // fall through
736      case ObjectFile::Linux:
737        if (arch == ObjectFile::Arm64) {
738            process = new ArmLinuxProcess64(params, objFile,
739                                            objFile->getArch());
740        } else {
741            process = new ArmLinuxProcess32(params, objFile,
742                                            objFile->getArch());
743        }
744        break;
745      case ObjectFile::FreeBSD:
746        if (arch == ObjectFile::Arm64) {
747            process = new ArmFreebsdProcess64(params, objFile,
748                                              objFile->getArch());
749        } else {
750            process = new ArmFreebsdProcess32(params, objFile,
751                                              objFile->getArch());
752        }
753        break;
754      case ObjectFile::LinuxArmOABI:
755        fatal("M5 does not support ARM OABI binaries. Please recompile with an"
756              " EABI compiler.");
757      default:
758        fatal("Unknown/unsupported operating system.");
759    }
760#elif THE_ISA == POWER_ISA
761    if (objFile->getArch() != ObjectFile::Power)
762        fatal("Object file architecture does not match compiled ISA (Power).");
763    switch (objFile->getOpSys()) {
764      case ObjectFile::UnknownOpSys:
765        warn("Unknown operating system; assuming Linux.");
766        // fall through
767      case ObjectFile::Linux:
768        process = new PowerLinuxProcess(params, objFile);
769        break;
770
771      default:
772        fatal("Unknown/unsupported operating system.");
773    }
774#else
775#error "THE_ISA not set"
776#endif
777
778    if (process == NULL)
779        fatal("Unknown error creating process object.");
780    return process;
781}
782
783LiveProcess *
784LiveProcessParams::create()
785{
786    return LiveProcess::create(this);
787}
788