Major changes to how SimObjects are created and initialized. Almost all
[gem5.git] / src / sim / process.cc
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/LiveProcess.hh"
49 #include "sim/process.hh"
50 #include "sim/process_impl.hh"
51 #include "sim/stats.hh"
52 #include "sim/syscall_emul.hh"
53 #include "sim/system.hh"
54
55 #include "arch/isa_specific.hh"
56 #if THE_ISA == ALPHA_ISA
57 #include "arch/alpha/linux/process.hh"
58 #include "arch/alpha/tru64/process.hh"
59 #elif THE_ISA == SPARC_ISA
60 #include "arch/sparc/linux/process.hh"
61 #include "arch/sparc/solaris/process.hh"
62 #elif THE_ISA == MIPS_ISA
63 #include "arch/mips/linux/process.hh"
64 #elif THE_ISA == X86_ISA
65 #include "arch/x86/linux/process.hh"
66 #else
67 #error "THE_ISA not set"
68 #endif
69
70
71 using namespace std;
72 using namespace TheISA;
73
74 //
75 // The purpose of this code is to fake the loader & syscall mechanism
76 // when there's no OS: thus there's no resone to use it in FULL_SYSTEM
77 // mode when we do have an OS
78 //
79 #if FULL_SYSTEM
80 #error "process.cc not compatible with FULL_SYSTEM"
81 #endif
82
83 // current number of allocated processes
84 int num_processes = 0;
85
86 Process::Process(const string &nm,
87 System *_system,
88 int stdin_fd, // initial I/O descriptors
89 int stdout_fd,
90 int stderr_fd)
91 : SimObject(nm), system(_system)
92 {
93 // initialize first 3 fds (stdin, stdout, stderr)
94 fd_map[STDIN_FILENO] = stdin_fd;
95 fd_map[STDOUT_FILENO] = stdout_fd;
96 fd_map[STDERR_FILENO] = stderr_fd;
97
98 // mark remaining fds as free
99 for (int i = 3; i <= MAX_FD; ++i) {
100 fd_map[i] = -1;
101 }
102
103 mmap_start = mmap_end = 0;
104 nxm_start = nxm_end = 0;
105 pTable = new PageTable(system);
106 // other parameters will be initialized when the program is loaded
107 }
108
109
110 void
111 Process::regStats()
112 {
113 using namespace Stats;
114
115 num_syscalls
116 .name(name() + ".PROG:num_syscalls")
117 .desc("Number of system calls")
118 ;
119 }
120
121 //
122 // static helper functions
123 //
124 int
125 Process::openInputFile(const string &filename)
126 {
127 int fd = open(filename.c_str(), O_RDONLY);
128
129 if (fd == -1) {
130 perror(NULL);
131 cerr << "unable to open \"" << filename << "\" for reading\n";
132 fatal("can't open input file");
133 }
134
135 return fd;
136 }
137
138
139 int
140 Process::openOutputFile(const string &filename)
141 {
142 int fd = open(filename.c_str(), O_WRONLY | O_CREAT | O_TRUNC, 0774);
143
144 if (fd == -1) {
145 perror(NULL);
146 cerr << "unable to open \"" << filename << "\" for writing\n";
147 fatal("can't open output file");
148 }
149
150 return fd;
151 }
152
153
154 int
155 Process::registerThreadContext(ThreadContext *tc)
156 {
157 // add to list
158 int myIndex = threadContexts.size();
159 threadContexts.push_back(tc);
160
161 // RemoteGDB *rgdb = new RemoteGDB(system, tc);
162 // GDBListener *gdbl = new GDBListener(rgdb, 7000 + myIndex);
163 // gdbl->listen();
164 //gdbl->accept();
165
166 // remoteGDB.push_back(rgdb);
167
168 // return CPU number to caller
169 return myIndex;
170 }
171
172 void
173 Process::startup()
174 {
175 if (threadContexts.empty())
176 fatal("Process %s is not associated with any CPUs!\n", name());
177
178 // first thread context for this process... initialize & enable
179 ThreadContext *tc = threadContexts[0];
180
181 // mark this context as active so it will start ticking.
182 tc->activate(0);
183
184 Port *mem_port;
185 mem_port = system->physmem->getPort("functional");
186 initVirtMem = new TranslatingPort("process init port", this,
187 TranslatingPort::Always);
188 mem_port->setPeer(initVirtMem);
189 initVirtMem->setPeer(mem_port);
190 }
191
192 void
193 Process::replaceThreadContext(ThreadContext *tc, int tcIndex)
194 {
195 if (tcIndex >= threadContexts.size()) {
196 panic("replaceThreadContext: bad tcIndex, %d >= %d\n",
197 tcIndex, threadContexts.size());
198 }
199
200 threadContexts[tcIndex] = tc;
201 }
202
203 // map simulator fd sim_fd to target fd tgt_fd
204 void
205 Process::dup_fd(int sim_fd, int tgt_fd)
206 {
207 if (tgt_fd < 0 || tgt_fd > MAX_FD)
208 panic("Process::dup_fd tried to dup past MAX_FD (%d)", tgt_fd);
209
210 fd_map[tgt_fd] = sim_fd;
211 }
212
213
214 // generate new target fd for sim_fd
215 int
216 Process::alloc_fd(int sim_fd)
217 {
218 // in case open() returns an error, don't allocate a new fd
219 if (sim_fd == -1)
220 return -1;
221
222 // find first free target fd
223 for (int free_fd = 0; free_fd < MAX_FD; ++free_fd) {
224 if (fd_map[free_fd] == -1) {
225 fd_map[free_fd] = sim_fd;
226 return free_fd;
227 }
228 }
229
230 panic("Process::alloc_fd: out of file descriptors!");
231 }
232
233
234 // free target fd (e.g., after close)
235 void
236 Process::free_fd(int tgt_fd)
237 {
238 if (fd_map[tgt_fd] == -1)
239 warn("Process::free_fd: request to free unused fd %d", tgt_fd);
240
241 fd_map[tgt_fd] = -1;
242 }
243
244
245 // look up simulator fd for given target fd
246 int
247 Process::sim_fd(int tgt_fd)
248 {
249 if (tgt_fd > MAX_FD)
250 return -1;
251
252 return fd_map[tgt_fd];
253 }
254
255 bool
256 Process::checkAndAllocNextPage(Addr vaddr)
257 {
258 // if this is an initial write we might not have
259 if (vaddr >= stack_min && vaddr < stack_base) {
260 pTable->allocate(roundDown(vaddr, VMPageSize), VMPageSize);
261 return true;
262 }
263
264 // We've accessed the next page of the stack, so extend the stack
265 // to cover it.
266 if(vaddr < stack_min && vaddr >= stack_min - TheISA::PageBytes)
267 {
268 stack_min -= TheISA::PageBytes;
269 if(stack_base - stack_min > 8*1024*1024)
270 fatal("Over max stack size for one thread\n");
271 pTable->allocate(stack_min, TheISA::PageBytes);
272 warn("Increasing stack size by one page.");
273 return true;
274 }
275 return false;
276 }
277
278 void
279 Process::serialize(std::ostream &os)
280 {
281 SERIALIZE_SCALAR(initialContextLoaded);
282 SERIALIZE_SCALAR(brk_point);
283 SERIALIZE_SCALAR(stack_base);
284 SERIALIZE_SCALAR(stack_size);
285 SERIALIZE_SCALAR(stack_min);
286 SERIALIZE_SCALAR(next_thread_stack_base);
287 SERIALIZE_SCALAR(mmap_start);
288 SERIALIZE_SCALAR(mmap_end);
289 SERIALIZE_SCALAR(nxm_start);
290 SERIALIZE_SCALAR(nxm_end);
291 SERIALIZE_ARRAY(fd_map, MAX_FD);
292
293 pTable->serialize(os);
294 }
295
296 void
297 Process::unserialize(Checkpoint *cp, const std::string &section)
298 {
299 UNSERIALIZE_SCALAR(initialContextLoaded);
300 UNSERIALIZE_SCALAR(brk_point);
301 UNSERIALIZE_SCALAR(stack_base);
302 UNSERIALIZE_SCALAR(stack_size);
303 UNSERIALIZE_SCALAR(stack_min);
304 UNSERIALIZE_SCALAR(next_thread_stack_base);
305 UNSERIALIZE_SCALAR(mmap_start);
306 UNSERIALIZE_SCALAR(mmap_end);
307 UNSERIALIZE_SCALAR(nxm_start);
308 UNSERIALIZE_SCALAR(nxm_end);
309 UNSERIALIZE_ARRAY(fd_map, MAX_FD);
310
311 pTable->unserialize(cp, section);
312 }
313
314
315 ////////////////////////////////////////////////////////////////////////
316 //
317 // LiveProcess member definitions
318 //
319 ////////////////////////////////////////////////////////////////////////
320
321
322 LiveProcess::LiveProcess(const string &nm, ObjectFile *_objFile,
323 System *_system,
324 int stdin_fd, int stdout_fd, int stderr_fd,
325 vector<string> &_argv, vector<string> &_envp,
326 const string &_cwd,
327 uint64_t _uid, uint64_t _euid,
328 uint64_t _gid, uint64_t _egid,
329 uint64_t _pid, uint64_t _ppid)
330 : Process(nm, _system, stdin_fd, stdout_fd, stderr_fd),
331 objFile(_objFile), argv(_argv), envp(_envp), cwd(_cwd)
332 {
333 __uid = _uid;
334 __euid = _euid;
335 __gid = _gid;
336 __egid = _egid;
337 __pid = _pid;
338 __ppid = _ppid;
339
340 prog_fname = argv[0];
341
342 // load up symbols, if any... these may be used for debugging or
343 // profiling.
344 if (!debugSymbolTable) {
345 debugSymbolTable = new SymbolTable();
346 if (!objFile->loadGlobalSymbols(debugSymbolTable) ||
347 !objFile->loadLocalSymbols(debugSymbolTable)) {
348 // didn't load any symbols
349 delete debugSymbolTable;
350 debugSymbolTable = NULL;
351 }
352 }
353 }
354
355 void
356 LiveProcess::argsInit(int intSize, int pageSize)
357 {
358 Process::startup();
359
360 // load object file into target memory
361 objFile->loadSections(initVirtMem);
362
363 // Calculate how much space we need for arg & env arrays.
364 int argv_array_size = intSize * (argv.size() + 1);
365 int envp_array_size = intSize * (envp.size() + 1);
366 int arg_data_size = 0;
367 for (int i = 0; i < argv.size(); ++i) {
368 arg_data_size += argv[i].size() + 1;
369 }
370 int env_data_size = 0;
371 for (int i = 0; i < envp.size(); ++i) {
372 env_data_size += envp[i].size() + 1;
373 }
374
375 int space_needed =
376 argv_array_size + envp_array_size + arg_data_size + env_data_size;
377 if (space_needed < 32*1024)
378 space_needed = 32*1024;
379
380 // set bottom of stack
381 stack_min = stack_base - space_needed;
382 // align it
383 stack_min = roundDown(stack_min, pageSize);
384 stack_size = stack_base - stack_min;
385 // map memory
386 pTable->allocate(stack_min, roundUp(stack_size, pageSize));
387
388 // map out initial stack contents
389 Addr argv_array_base = stack_min + intSize; // room for argc
390 Addr envp_array_base = argv_array_base + argv_array_size;
391 Addr arg_data_base = envp_array_base + envp_array_size;
392 Addr env_data_base = arg_data_base + arg_data_size;
393
394 // write contents to stack
395 uint64_t argc = argv.size();
396 if (intSize == 8)
397 argc = htog((uint64_t)argc);
398 else if (intSize == 4)
399 argc = htog((uint32_t)argc);
400 else
401 panic("Unknown int size");
402
403 initVirtMem->writeBlob(stack_min, (uint8_t*)&argc, intSize);
404
405 copyStringArray(argv, argv_array_base, arg_data_base, initVirtMem);
406 copyStringArray(envp, envp_array_base, env_data_base, initVirtMem);
407
408 threadContexts[0]->setIntReg(ArgumentReg0, argc);
409 threadContexts[0]->setIntReg(ArgumentReg1, argv_array_base);
410 threadContexts[0]->setIntReg(StackPointerReg, stack_min);
411
412 Addr prog_entry = objFile->entryPoint();
413 threadContexts[0]->setPC(prog_entry);
414 threadContexts[0]->setNextPC(prog_entry + sizeof(MachInst));
415
416 #if THE_ISA != ALPHA_ISA //e.g. MIPS or Sparc
417 threadContexts[0]->setNextNPC(prog_entry + (2 * sizeof(MachInst)));
418 #endif
419
420 num_processes++;
421 }
422
423 void
424 LiveProcess::syscall(int64_t callnum, ThreadContext *tc)
425 {
426 num_syscalls++;
427
428 SyscallDesc *desc = getDesc(callnum);
429 if (desc == NULL)
430 fatal("Syscall %d out of range", callnum);
431
432 desc->doSyscall(callnum, this, tc);
433 }
434
435 LiveProcess *
436 LiveProcess::create(const std::string &nm, System *system, int stdin_fd,
437 int stdout_fd, int stderr_fd, std::string executable,
438 std::vector<std::string> &argv,
439 std::vector<std::string> &envp,
440 const std::string &cwd,
441 uint64_t _uid, uint64_t _euid,
442 uint64_t _gid, uint64_t _egid,
443 uint64_t _pid, uint64_t _ppid)
444 {
445 LiveProcess *process = NULL;
446
447 ObjectFile *objFile = createObjectFile(executable);
448 if (objFile == NULL) {
449 fatal("Can't load object file %s", executable);
450 }
451
452 if (objFile->isDynamic())
453 fatal("Object file is a dynamic executable however only static "
454 "executables are supported!\n Please recompile your "
455 "executable as a static binary and try again.\n");
456
457 #if THE_ISA == ALPHA_ISA
458 if (objFile->getArch() != ObjectFile::Alpha)
459 fatal("Object file architecture does not match compiled ISA (Alpha).");
460 switch (objFile->getOpSys()) {
461 case ObjectFile::Tru64:
462 process = new AlphaTru64Process(nm, objFile, system,
463 stdin_fd, stdout_fd, stderr_fd,
464 argv, envp, cwd,
465 _uid, _euid, _gid, _egid, _pid, _ppid);
466 break;
467
468 case ObjectFile::Linux:
469 process = new AlphaLinuxProcess(nm, objFile, system,
470 stdin_fd, stdout_fd, stderr_fd,
471 argv, envp, cwd,
472 _uid, _euid, _gid, _egid, _pid, _ppid);
473 break;
474
475 default:
476 fatal("Unknown/unsupported operating system.");
477 }
478 #elif THE_ISA == SPARC_ISA
479 if (objFile->getArch() != ObjectFile::SPARC64 && objFile->getArch() != ObjectFile::SPARC32)
480 fatal("Object file architecture does not match compiled ISA (SPARC).");
481 switch (objFile->getOpSys()) {
482 case ObjectFile::Linux:
483 if (objFile->getArch() == ObjectFile::SPARC64) {
484 process = new Sparc64LinuxProcess(nm, objFile, system,
485 stdin_fd, stdout_fd, stderr_fd,
486 argv, envp, cwd,
487 _uid, _euid, _gid,
488 _egid, _pid, _ppid);
489 } else {
490 process = new Sparc32LinuxProcess(nm, objFile, system,
491 stdin_fd, stdout_fd, stderr_fd,
492 argv, envp, cwd,
493 _uid, _euid, _gid,
494 _egid, _pid, _ppid);
495 }
496 break;
497
498
499 case ObjectFile::Solaris:
500 process = new SparcSolarisProcess(nm, objFile, system,
501 stdin_fd, stdout_fd, stderr_fd,
502 argv, envp, cwd,
503 _uid, _euid, _gid, _egid, _pid, _ppid);
504 break;
505 default:
506 fatal("Unknown/unsupported operating system.");
507 }
508 #elif THE_ISA == X86_ISA
509 if (objFile->getArch() != ObjectFile::X86)
510 fatal("Object file architecture does not match compiled ISA (x86).");
511 switch (objFile->getOpSys()) {
512 case ObjectFile::Linux:
513 process = new X86LinuxProcess(nm, objFile, system,
514 stdin_fd, stdout_fd, stderr_fd,
515 argv, envp, cwd,
516 _uid, _euid, _gid,
517 _egid, _pid, _ppid);
518 break;
519 default:
520 fatal("Unknown/unsupported operating system.");
521 }
522 #elif THE_ISA == MIPS_ISA
523 if (objFile->getArch() != ObjectFile::Mips)
524 fatal("Object file architecture does not match compiled ISA (MIPS).");
525 switch (objFile->getOpSys()) {
526 case ObjectFile::Linux:
527 process = new MipsLinuxProcess(nm, objFile, system,
528 stdin_fd, stdout_fd, stderr_fd,
529 argv, envp, cwd,
530 _uid, _euid, _gid, _egid, _pid, _ppid);
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
546 LiveProcess *
547 LiveProcessParams::create()
548 {
549 string in = input;
550 string out = output;
551
552 // initialize file descriptors to default: same as simulator
553 int stdin_fd, stdout_fd, stderr_fd;
554
555 if (in == "stdin" || in == "cin")
556 stdin_fd = STDIN_FILENO;
557 else
558 stdin_fd = Process::openInputFile(input);
559
560 if (out == "stdout" || out == "cout")
561 stdout_fd = STDOUT_FILENO;
562 else if (out == "stderr" || out == "cerr")
563 stdout_fd = STDERR_FILENO;
564 else
565 stdout_fd = Process::openOutputFile(out);
566
567 stderr_fd = (stdout_fd != STDOUT_FILENO) ? stdout_fd : STDERR_FILENO;
568
569 return LiveProcess::create(name, system,
570 stdin_fd, stdout_fd, stderr_fd,
571 (string)executable == "" ? cmd[0] : executable,
572 cmd, env, cwd,
573 uid, euid, gid, egid, pid, ppid);
574 }