process.cc revision 5231
1/*
2 * Copyright (c) 2001-2005 The Regents of The University of Michigan
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are
7 * met: redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer;
9 * redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution;
12 * neither the name of the copyright holders nor the names of its
13 * contributors may be used to endorse or promote products derived from
14 * this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 *
28 * Authors: Nathan Binkert
29 *          Steve Reinhardt
30 *          Ali Saidi
31 */
32
33#include <unistd.h>
34#include <fcntl.h>
35
36#include <string>
37
38#include "arch/remote_gdb.hh"
39#include "base/intmath.hh"
40#include "base/loader/object_file.hh"
41#include "base/loader/symtab.hh"
42#include "base/statistics.hh"
43#include "config/full_system.hh"
44#include "cpu/thread_context.hh"
45#include "mem/page_table.hh"
46#include "mem/physical.hh"
47#include "mem/translating_port.hh"
48#include "params/Process.hh"
49#include "params/LiveProcess.hh"
50#include "sim/process.hh"
51#include "sim/process_impl.hh"
52#include "sim/stats.hh"
53#include "sim/syscall_emul.hh"
54#include "sim/system.hh"
55
56#include "arch/isa_specific.hh"
57#if THE_ISA == ALPHA_ISA
58#include "arch/alpha/linux/process.hh"
59#include "arch/alpha/tru64/process.hh"
60#elif THE_ISA == SPARC_ISA
61#include "arch/sparc/linux/process.hh"
62#include "arch/sparc/solaris/process.hh"
63#elif THE_ISA == MIPS_ISA
64#include "arch/mips/linux/process.hh"
65#elif THE_ISA == X86_ISA
66#include "arch/x86/linux/process.hh"
67#else
68#error "THE_ISA not set"
69#endif
70
71
72using namespace std;
73using namespace TheISA;
74
75//
76// The purpose of this code is to fake the loader & syscall mechanism
77// when there's no OS: thus there's no resone to use it in FULL_SYSTEM
78// mode when we do have an OS
79//
80#if FULL_SYSTEM
81#error "process.cc not compatible with FULL_SYSTEM"
82#endif
83
84// current number of allocated processes
85int num_processes = 0;
86
87Process::Process(ProcessParams * params)
88    : SimObject(params), system(params->system), checkpointRestored(false),
89    max_stack_size(params->max_stack_size)
90{
91    string in = params->input;
92    string out = params->output;
93
94    // initialize file descriptors to default: same as simulator
95    int stdin_fd, stdout_fd, stderr_fd;
96
97    if (in == "stdin" || in == "cin")
98        stdin_fd = STDIN_FILENO;
99    else if (in == "None")
100        stdin_fd = -1;
101    else
102        stdin_fd = Process::openInputFile(in);
103
104    if (out == "stdout" || out == "cout")
105        stdout_fd = STDOUT_FILENO;
106    else if (out == "stderr" || out == "cerr")
107        stdout_fd = STDERR_FILENO;
108    else if (out == "None")
109        stdout_fd = -1;
110    else
111        stdout_fd = Process::openOutputFile(out);
112
113    stderr_fd = (stdout_fd != STDOUT_FILENO) ? stdout_fd : STDERR_FILENO;
114
115    M5_pid = system->allocatePID();
116    // initialize first 3 fds (stdin, stdout, stderr)
117    fd_map[STDIN_FILENO] = stdin_fd;
118    fd_map[STDOUT_FILENO] = stdout_fd;
119    fd_map[STDERR_FILENO] = stderr_fd;
120
121    // mark remaining fds as free
122    for (int i = 3; i <= MAX_FD; ++i) {
123        fd_map[i] = -1;
124    }
125
126    mmap_start = mmap_end = 0;
127    nxm_start = nxm_end = 0;
128    pTable = new PageTable(this);
129    // other parameters will be initialized when the program is loaded
130}
131
132
133void
134Process::regStats()
135{
136    using namespace Stats;
137
138    num_syscalls
139        .name(name() + ".PROG:num_syscalls")
140        .desc("Number of system calls")
141        ;
142}
143
144//
145// static helper functions
146//
147int
148Process::openInputFile(const string &filename)
149{
150    int fd = open(filename.c_str(), O_RDONLY);
151
152    if (fd == -1) {
153        perror(NULL);
154        cerr << "unable to open \"" << filename << "\" for reading\n";
155        fatal("can't open input file");
156    }
157
158    return fd;
159}
160
161
162int
163Process::openOutputFile(const string &filename)
164{
165    int fd = open(filename.c_str(), O_WRONLY | O_CREAT | O_TRUNC, 0774);
166
167    if (fd == -1) {
168        perror(NULL);
169        cerr << "unable to open \"" << filename << "\" for writing\n";
170        fatal("can't open output file");
171    }
172
173    return fd;
174}
175
176
177int
178Process::registerThreadContext(ThreadContext *tc)
179{
180    // add to list
181    int myIndex = threadContexts.size();
182    threadContexts.push_back(tc);
183
184    RemoteGDB *rgdb = new RemoteGDB(system, tc);
185    GDBListener *gdbl = new GDBListener(rgdb, 7000 + myIndex);
186    gdbl->listen();
187    //gdbl->accept();
188
189    remoteGDB.push_back(rgdb);
190
191    // return CPU number to caller
192    return myIndex;
193}
194
195void
196Process::startup()
197{
198    if (threadContexts.empty())
199        fatal("Process %s is not associated with any CPUs!\n", name());
200
201    // first thread context for this process... initialize & enable
202    ThreadContext *tc = threadContexts[0];
203
204    // mark this context as active so it will start ticking.
205    tc->activate(0);
206
207    Port *mem_port;
208    mem_port = system->physmem->getPort("functional");
209    initVirtMem = new TranslatingPort("process init port", this,
210            TranslatingPort::Always);
211    mem_port->setPeer(initVirtMem);
212    initVirtMem->setPeer(mem_port);
213}
214
215void
216Process::replaceThreadContext(ThreadContext *tc, int tcIndex)
217{
218    if (tcIndex >= threadContexts.size()) {
219        panic("replaceThreadContext: bad tcIndex, %d >= %d\n",
220              tcIndex, threadContexts.size());
221    }
222
223    threadContexts[tcIndex] = tc;
224}
225
226// map simulator fd sim_fd to target fd tgt_fd
227void
228Process::dup_fd(int sim_fd, int tgt_fd)
229{
230    if (tgt_fd < 0 || tgt_fd > MAX_FD)
231        panic("Process::dup_fd tried to dup past MAX_FD (%d)", tgt_fd);
232
233    fd_map[tgt_fd] = sim_fd;
234}
235
236
237// generate new target fd for sim_fd
238int
239Process::alloc_fd(int sim_fd)
240{
241    // in case open() returns an error, don't allocate a new fd
242    if (sim_fd == -1)
243        return -1;
244
245    // find first free target fd
246    for (int free_fd = 0; free_fd < MAX_FD; ++free_fd) {
247        if (fd_map[free_fd] == -1) {
248            fd_map[free_fd] = sim_fd;
249            return free_fd;
250        }
251    }
252
253    panic("Process::alloc_fd: out of file descriptors!");
254}
255
256
257// free target fd (e.g., after close)
258void
259Process::free_fd(int tgt_fd)
260{
261    if (fd_map[tgt_fd] == -1)
262        warn("Process::free_fd: request to free unused fd %d", tgt_fd);
263
264    fd_map[tgt_fd] = -1;
265}
266
267
268// look up simulator fd for given target fd
269int
270Process::sim_fd(int tgt_fd)
271{
272    if (tgt_fd > MAX_FD)
273        return -1;
274
275    return fd_map[tgt_fd];
276}
277
278bool
279Process::checkAndAllocNextPage(Addr vaddr)
280{
281    // if this is an initial write we might not have
282    if (vaddr >= stack_min && vaddr < stack_base) {
283        pTable->allocate(roundDown(vaddr, VMPageSize), VMPageSize);
284        return true;
285    }
286
287    // We've accessed the next page of the stack, so extend the stack
288    // to cover it.
289    if (vaddr < stack_min && vaddr >= stack_base - max_stack_size) {
290        while (vaddr < stack_min) {
291            stack_min -= TheISA::PageBytes;
292            if(stack_base - stack_min > max_stack_size)
293                fatal("Maximum stack size exceeded\n");
294            if(stack_base - stack_min > 8*1024*1024)
295                fatal("Over max stack size for one thread\n");
296            pTable->allocate(stack_min, TheISA::PageBytes);
297            warn("Increasing stack size by one page.");
298        };
299        return true;
300    }
301    return false;
302}
303
304void
305Process::serialize(std::ostream &os)
306{
307    SERIALIZE_SCALAR(initialContextLoaded);
308    SERIALIZE_SCALAR(brk_point);
309    SERIALIZE_SCALAR(stack_base);
310    SERIALIZE_SCALAR(stack_size);
311    SERIALIZE_SCALAR(stack_min);
312    SERIALIZE_SCALAR(next_thread_stack_base);
313    SERIALIZE_SCALAR(mmap_start);
314    SERIALIZE_SCALAR(mmap_end);
315    SERIALIZE_SCALAR(nxm_start);
316    SERIALIZE_SCALAR(nxm_end);
317    SERIALIZE_ARRAY(fd_map, MAX_FD);
318
319    pTable->serialize(os);
320}
321
322void
323Process::unserialize(Checkpoint *cp, const std::string &section)
324{
325    UNSERIALIZE_SCALAR(initialContextLoaded);
326    UNSERIALIZE_SCALAR(brk_point);
327    UNSERIALIZE_SCALAR(stack_base);
328    UNSERIALIZE_SCALAR(stack_size);
329    UNSERIALIZE_SCALAR(stack_min);
330    UNSERIALIZE_SCALAR(next_thread_stack_base);
331    UNSERIALIZE_SCALAR(mmap_start);
332    UNSERIALIZE_SCALAR(mmap_end);
333    UNSERIALIZE_SCALAR(nxm_start);
334    UNSERIALIZE_SCALAR(nxm_end);
335    UNSERIALIZE_ARRAY(fd_map, MAX_FD);
336
337    pTable->unserialize(cp, section);
338
339
340    checkpointRestored = true;
341
342}
343
344
345////////////////////////////////////////////////////////////////////////
346//
347// LiveProcess member definitions
348//
349////////////////////////////////////////////////////////////////////////
350
351
352LiveProcess::LiveProcess(LiveProcessParams * params, ObjectFile *_objFile)
353    : Process(params), objFile(_objFile),
354      argv(params->cmd), envp(params->env), cwd(params->cwd)
355{
356    __uid = params->uid;
357    __euid = params->euid;
358    __gid = params->gid;
359    __egid = params->egid;
360    __pid = params->pid;
361    __ppid = params->ppid;
362
363    prog_fname = params->cmd[0];
364
365    // load up symbols, if any... these may be used for debugging or
366    // profiling.
367    if (!debugSymbolTable) {
368        debugSymbolTable = new SymbolTable();
369        if (!objFile->loadGlobalSymbols(debugSymbolTable) ||
370            !objFile->loadLocalSymbols(debugSymbolTable)) {
371            // didn't load any symbols
372            delete debugSymbolTable;
373            debugSymbolTable = NULL;
374        }
375    }
376}
377
378void
379LiveProcess::argsInit(int intSize, int pageSize)
380{
381    Process::startup();
382
383    // load object file into target memory
384    objFile->loadSections(initVirtMem);
385
386    // Calculate how much space we need for arg & env arrays.
387    int argv_array_size = intSize * (argv.size() + 1);
388    int envp_array_size = intSize * (envp.size() + 1);
389    int arg_data_size = 0;
390    for (int i = 0; i < argv.size(); ++i) {
391        arg_data_size += argv[i].size() + 1;
392    }
393    int env_data_size = 0;
394    for (int i = 0; i < envp.size(); ++i) {
395        env_data_size += envp[i].size() + 1;
396    }
397
398    int space_needed =
399        argv_array_size + envp_array_size + arg_data_size + env_data_size;
400    if (space_needed < 32*1024)
401        space_needed = 32*1024;
402
403    // set bottom of stack
404    stack_min = stack_base - space_needed;
405    // align it
406    stack_min = roundDown(stack_min, pageSize);
407    stack_size = stack_base - stack_min;
408    // map memory
409    pTable->allocate(stack_min, roundUp(stack_size, pageSize));
410
411    // map out initial stack contents
412    Addr argv_array_base = stack_min + intSize; // room for argc
413    Addr envp_array_base = argv_array_base + argv_array_size;
414    Addr arg_data_base = envp_array_base + envp_array_size;
415    Addr env_data_base = arg_data_base + arg_data_size;
416
417    // write contents to stack
418    uint64_t argc = argv.size();
419    if (intSize == 8)
420        argc = htog((uint64_t)argc);
421    else if (intSize == 4)
422        argc = htog((uint32_t)argc);
423    else
424        panic("Unknown int size");
425
426    initVirtMem->writeBlob(stack_min, (uint8_t*)&argc, intSize);
427
428    copyStringArray(argv, argv_array_base, arg_data_base, initVirtMem);
429    copyStringArray(envp, envp_array_base, env_data_base, initVirtMem);
430
431    assert(NumArgumentRegs >= 2);
432    threadContexts[0]->setIntReg(ArgumentReg[0], argc);
433    threadContexts[0]->setIntReg(ArgumentReg[1], argv_array_base);
434    threadContexts[0]->setIntReg(StackPointerReg, stack_min);
435
436    Addr prog_entry = objFile->entryPoint();
437    threadContexts[0]->setPC(prog_entry);
438    threadContexts[0]->setNextPC(prog_entry + sizeof(MachInst));
439
440#if THE_ISA != ALPHA_ISA //e.g. MIPS or Sparc
441    threadContexts[0]->setNextNPC(prog_entry + (2 * sizeof(MachInst)));
442#endif
443
444    num_processes++;
445}
446
447void
448LiveProcess::syscall(int64_t callnum, ThreadContext *tc)
449{
450    num_syscalls++;
451
452    SyscallDesc *desc = getDesc(callnum);
453    if (desc == NULL)
454        fatal("Syscall %d out of range", callnum);
455
456    desc->doSyscall(callnum, this, tc);
457}
458
459LiveProcess *
460LiveProcess::create(LiveProcessParams * params)
461{
462    LiveProcess *process = NULL;
463
464    string executable =
465        params->executable == "" ? params->cmd[0] : params->executable;
466    ObjectFile *objFile = createObjectFile(executable);
467    if (objFile == NULL) {
468        fatal("Can't load object file %s", executable);
469    }
470
471    if (objFile->isDynamic())
472       fatal("Object file is a dynamic executable however only static "
473             "executables are supported!\n       Please recompile your "
474             "executable as a static binary and try again.\n");
475
476#if THE_ISA == ALPHA_ISA
477    if (objFile->hasTLS())
478        fatal("Object file has a TLS section and single threaded TLS is not\n"
479              "       currently supported for Alpha! Please recompile your "
480              "executable with \n       a non-TLS toolchain.\n");
481
482    if (objFile->getArch() != ObjectFile::Alpha)
483        fatal("Object file architecture does not match compiled ISA (Alpha).");
484    switch (objFile->getOpSys()) {
485      case ObjectFile::Tru64:
486        process = new AlphaTru64Process(params, objFile);
487        break;
488
489      case ObjectFile::Linux:
490        process = new AlphaLinuxProcess(params, objFile);
491        break;
492
493      default:
494        fatal("Unknown/unsupported operating system.");
495    }
496#elif THE_ISA == SPARC_ISA
497    if (objFile->getArch() != ObjectFile::SPARC64 && objFile->getArch() != ObjectFile::SPARC32)
498        fatal("Object file architecture does not match compiled ISA (SPARC).");
499    switch (objFile->getOpSys()) {
500      case ObjectFile::Linux:
501        if (objFile->getArch() == ObjectFile::SPARC64) {
502            process = new Sparc64LinuxProcess(params, objFile);
503        } else {
504            process = new Sparc32LinuxProcess(params, objFile);
505        }
506        break;
507
508
509      case ObjectFile::Solaris:
510        process = new SparcSolarisProcess(params, objFile);
511        break;
512      default:
513        fatal("Unknown/unsupported operating system.");
514    }
515#elif THE_ISA == X86_ISA
516    if (objFile->getArch() != ObjectFile::X86)
517        fatal("Object file architecture does not match compiled ISA (x86).");
518    switch (objFile->getOpSys()) {
519      case ObjectFile::Linux:
520        process = new X86LinuxProcess(params, objFile);
521        break;
522      default:
523        fatal("Unknown/unsupported operating system.");
524    }
525#elif THE_ISA == MIPS_ISA
526    if (objFile->getArch() != ObjectFile::Mips)
527        fatal("Object file architecture does not match compiled ISA (MIPS).");
528    switch (objFile->getOpSys()) {
529      case ObjectFile::Linux:
530        process = new MipsLinuxProcess(params, objFile);
531        break;
532
533      default:
534        fatal("Unknown/unsupported operating system.");
535    }
536#else
537#error "THE_ISA not set"
538#endif
539
540
541    if (process == NULL)
542        fatal("Unknown error creating process object.");
543    return process;
544}
545
546LiveProcess *
547LiveProcessParams::create()
548{
549    return LiveProcess::create(this);
550}
551