mem: Make the XBar responsible for tracking response routing
[gem5.git] / src / sim / syscall_emul.cc
1 /*
2 * Copyright (c) 2003-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: Steve Reinhardt
29 * Ali Saidi
30 */
31
32 #include <fcntl.h>
33 #include <unistd.h>
34
35 #include <cstdio>
36 #include <iostream>
37 #include <string>
38
39 #include "arch/utility.hh"
40 #include "base/chunk_generator.hh"
41 #include "base/trace.hh"
42 #include "config/the_isa.hh"
43 #include "cpu/base.hh"
44 #include "cpu/thread_context.hh"
45 #include "debug/SyscallVerbose.hh"
46 #include "mem/page_table.hh"
47 #include "sim/process.hh"
48 #include "sim/sim_exit.hh"
49 #include "sim/syscall_emul.hh"
50 #include "sim/system.hh"
51
52 using namespace std;
53 using namespace TheISA;
54
55 void
56 SyscallDesc::doSyscall(int callnum, LiveProcess *process, ThreadContext *tc)
57 {
58 if (DTRACE(SyscallVerbose)) {
59 int index = 0;
60 IntReg arg[4] M5_VAR_USED;
61
62 // we can't just put the calls to getSyscallArg() in the
63 // DPRINTF arg list, because C++ doesn't guarantee their order
64 for (int i = 0; i < 4; ++i)
65 arg[i] = process->getSyscallArg(tc, index);
66
67 DPRINTFNR("%d: %s: syscall %s called w/arguments %d,%d,%d,%d\n",
68 curTick(), tc->getCpuPtr()->name(), name,
69 arg[0], arg[1], arg[2], arg[3]);
70 }
71
72 SyscallReturn retval = (*funcPtr)(this, callnum, process, tc);
73
74 if (retval.needsRetry()) {
75 DPRINTFS(SyscallVerbose, tc->getCpuPtr(), "syscall %s needs retry\n",
76 name);
77 } else {
78 DPRINTFS(SyscallVerbose, tc->getCpuPtr(), "syscall %s returns %d\n",
79 name, retval.encodedValue());
80 }
81
82 if (!(flags & SyscallDesc::SuppressReturnValue) && !retval.needsRetry())
83 process->setSyscallReturn(tc, retval);
84 }
85
86
87 SyscallReturn
88 unimplementedFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
89 ThreadContext *tc)
90 {
91 fatal("syscall %s (#%d) unimplemented.", desc->name, callnum);
92
93 return 1;
94 }
95
96
97 SyscallReturn
98 ignoreFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
99 ThreadContext *tc)
100 {
101 int index = 0;
102 warn("ignoring syscall %s(%d, ...)", desc->name,
103 process->getSyscallArg(tc, index));
104
105 return 0;
106 }
107
108
109 SyscallReturn
110 ignoreWarnOnceFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
111 ThreadContext *tc)
112 {
113 int index = 0;
114 warn_once("ignoring syscall %s(%d, ...)", desc->name,
115 process->getSyscallArg(tc, index));
116
117 return 0;
118 }
119
120
121 SyscallReturn
122 exitFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
123 ThreadContext *tc)
124 {
125 if (process->system->numRunningContexts() == 1) {
126 // Last running context... exit simulator
127 int index = 0;
128 exitSimLoop("target called exit()",
129 process->getSyscallArg(tc, index) & 0xff);
130 } else {
131 // other running threads... just halt this one
132 tc->halt();
133 }
134
135 return 1;
136 }
137
138
139 SyscallReturn
140 exitGroupFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
141 ThreadContext *tc)
142 {
143 // halt all threads belonging to this process
144 for (auto i: process->contextIds) {
145 process->system->getThreadContext(i)->halt();
146 }
147
148 if (!process->system->numRunningContexts()) {
149 // all threads belonged to this process... exit simulator
150 int index = 0;
151 exitSimLoop("target called exit()",
152 process->getSyscallArg(tc, index) & 0xff);
153 }
154
155 return 1;
156 }
157
158
159 SyscallReturn
160 getpagesizeFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc)
161 {
162 return (int)PageBytes;
163 }
164
165
166 SyscallReturn
167 brkFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc)
168 {
169 // change brk addr to first arg
170 int index = 0;
171 Addr new_brk = p->getSyscallArg(tc, index);
172
173 // in Linux at least, brk(0) returns the current break value
174 // (note that the syscall and the glibc function have different behavior)
175 if (new_brk == 0)
176 return p->brk_point;
177
178 if (new_brk > p->brk_point) {
179 // might need to allocate some new pages
180 for (ChunkGenerator gen(p->brk_point, new_brk - p->brk_point,
181 PageBytes); !gen.done(); gen.next()) {
182 if (!p->pTable->translate(gen.addr()))
183 p->allocateMem(roundDown(gen.addr(), PageBytes), PageBytes);
184
185 // if the address is already there, zero it out
186 else {
187 uint8_t zero = 0;
188 SETranslatingPortProxy &tp = tc->getMemProxy();
189
190 // split non-page aligned accesses
191 Addr next_page = roundUp(gen.addr(), PageBytes);
192 uint32_t size_needed = next_page - gen.addr();
193 tp.memsetBlob(gen.addr(), zero, size_needed);
194 if (gen.addr() + PageBytes > next_page &&
195 next_page < new_brk &&
196 p->pTable->translate(next_page))
197 {
198 size_needed = PageBytes - size_needed;
199 tp.memsetBlob(next_page, zero, size_needed);
200 }
201 }
202 }
203 }
204
205 p->brk_point = new_brk;
206 DPRINTF(SyscallVerbose, "Break Point changed to: %#X\n", p->brk_point);
207 return p->brk_point;
208 }
209
210
211 SyscallReturn
212 closeFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc)
213 {
214 int index = 0;
215 int target_fd = p->getSyscallArg(tc, index);
216 int sim_fd = p->sim_fd(target_fd);
217 int status = 0;
218 if (sim_fd > 2)
219 status = close(sim_fd);
220 if (status >= 0)
221 p->free_fd(target_fd);
222 return status;
223 }
224
225
226 SyscallReturn
227 readFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc)
228 {
229 int index = 0;
230 int fd = p->sim_fd(p->getSyscallArg(tc, index));
231 assert(fd >= 0);
232 Addr bufPtr = p->getSyscallArg(tc, index);
233 int nbytes = p->getSyscallArg(tc, index);
234 BufferArg bufArg(bufPtr, nbytes);
235
236 int bytes_read = read(fd, bufArg.bufferPtr(), nbytes);
237
238 if (bytes_read != -1)
239 bufArg.copyOut(tc->getMemProxy());
240
241 return bytes_read;
242 }
243
244 SyscallReturn
245 writeFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc)
246 {
247 int index = 0;
248 int fd = p->sim_fd(p->getSyscallArg(tc, index));
249 Addr bufPtr = p->getSyscallArg(tc, index);
250 int nbytes = p->getSyscallArg(tc, index);
251 BufferArg bufArg(bufPtr, nbytes);
252
253 bufArg.copyIn(tc->getMemProxy());
254
255 int bytes_written = write(fd, bufArg.bufferPtr(), nbytes);
256
257 fsync(fd);
258
259 return bytes_written;
260 }
261
262
263 SyscallReturn
264 lseekFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc)
265 {
266 int index = 0;
267 int fd = p->sim_fd(p->getSyscallArg(tc, index));
268 assert(fd >= 0);
269 uint64_t offs = p->getSyscallArg(tc, index);
270 int whence = p->getSyscallArg(tc, index);
271
272 off_t result = lseek(fd, offs, whence);
273
274 return (result == (off_t)-1) ? -errno : result;
275 }
276
277
278 SyscallReturn
279 _llseekFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc)
280 {
281 int index = 0;
282 int fd = p->sim_fd(p->getSyscallArg(tc, index));
283 assert(fd >= 0);
284 uint64_t offset_high = p->getSyscallArg(tc, index);
285 uint32_t offset_low = p->getSyscallArg(tc, index);
286 Addr result_ptr = p->getSyscallArg(tc, index);
287 int whence = p->getSyscallArg(tc, index);
288
289 uint64_t offset = (offset_high << 32) | offset_low;
290
291 uint64_t result = lseek(fd, offset, whence);
292 result = TheISA::htog(result);
293
294 if (result == (off_t)-1) {
295 //The seek failed.
296 return -errno;
297 } else {
298 // The seek succeeded.
299 // Copy "result" to "result_ptr"
300 // XXX We'll assume that the size of loff_t is 64 bits on the
301 // target platform
302 BufferArg result_buf(result_ptr, sizeof(result));
303 memcpy(result_buf.bufferPtr(), &result, sizeof(result));
304 result_buf.copyOut(tc->getMemProxy());
305 return 0;
306 }
307 }
308
309
310 SyscallReturn
311 munmapFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc)
312 {
313 // given that we don't really implement mmap, munmap is really easy
314 return 0;
315 }
316
317
318 const char *hostname = "m5.eecs.umich.edu";
319
320 SyscallReturn
321 gethostnameFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc)
322 {
323 int index = 0;
324 Addr bufPtr = p->getSyscallArg(tc, index);
325 int name_len = p->getSyscallArg(tc, index);
326 BufferArg name(bufPtr, name_len);
327
328 strncpy((char *)name.bufferPtr(), hostname, name_len);
329
330 name.copyOut(tc->getMemProxy());
331
332 return 0;
333 }
334
335 SyscallReturn
336 getcwdFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc)
337 {
338 int result = 0;
339 int index = 0;
340 Addr bufPtr = p->getSyscallArg(tc, index);
341 unsigned long size = p->getSyscallArg(tc, index);
342 BufferArg buf(bufPtr, size);
343
344 // Is current working directory defined?
345 string cwd = p->getcwd();
346 if (!cwd.empty()) {
347 if (cwd.length() >= size) {
348 // Buffer too small
349 return -ERANGE;
350 }
351 strncpy((char *)buf.bufferPtr(), cwd.c_str(), size);
352 result = cwd.length();
353 }
354 else {
355 if (getcwd((char *)buf.bufferPtr(), size) != NULL) {
356 result = strlen((char *)buf.bufferPtr());
357 }
358 else {
359 result = -1;
360 }
361 }
362
363 buf.copyOut(tc->getMemProxy());
364
365 return (result == -1) ? -errno : result;
366 }
367
368 /// Target open() handler.
369 SyscallReturn
370 readlinkFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
371 ThreadContext *tc)
372 {
373 return readlinkFunc(desc, callnum, process, tc, 0);
374 }
375
376 SyscallReturn
377 readlinkFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc,
378 int index)
379 {
380 string path;
381
382 if (!tc->getMemProxy().tryReadString(path, p->getSyscallArg(tc, index)))
383 return -EFAULT;
384
385 // Adjust path for current working directory
386 path = p->fullPath(path);
387
388 Addr bufPtr = p->getSyscallArg(tc, index);
389 size_t bufsiz = p->getSyscallArg(tc, index);
390
391 BufferArg buf(bufPtr, bufsiz);
392
393 int result = readlink(path.c_str(), (char *)buf.bufferPtr(), bufsiz);
394
395 buf.copyOut(tc->getMemProxy());
396
397 return (result == -1) ? -errno : result;
398 }
399
400 SyscallReturn
401 unlinkFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc)
402 {
403 return unlinkHelper(desc, num, p, tc, 0);
404 }
405
406 SyscallReturn
407 unlinkHelper(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc,
408 int index)
409 {
410 string path;
411
412 if (!tc->getMemProxy().tryReadString(path, p->getSyscallArg(tc, index)))
413 return -EFAULT;
414
415 // Adjust path for current working directory
416 path = p->fullPath(path);
417
418 int result = unlink(path.c_str());
419 return (result == -1) ? -errno : result;
420 }
421
422
423 SyscallReturn
424 mkdirFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc)
425 {
426 string path;
427
428 int index = 0;
429 if (!tc->getMemProxy().tryReadString(path, p->getSyscallArg(tc, index)))
430 return -EFAULT;
431
432 // Adjust path for current working directory
433 path = p->fullPath(path);
434
435 mode_t mode = p->getSyscallArg(tc, index);
436
437 int result = mkdir(path.c_str(), mode);
438 return (result == -1) ? -errno : result;
439 }
440
441 SyscallReturn
442 renameFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc)
443 {
444 string old_name;
445
446 int index = 0;
447 if (!tc->getMemProxy().tryReadString(old_name, p->getSyscallArg(tc, index)))
448 return -EFAULT;
449
450 string new_name;
451
452 if (!tc->getMemProxy().tryReadString(new_name, p->getSyscallArg(tc, index)))
453 return -EFAULT;
454
455 // Adjust path for current working directory
456 old_name = p->fullPath(old_name);
457 new_name = p->fullPath(new_name);
458
459 int64_t result = rename(old_name.c_str(), new_name.c_str());
460 return (result == -1) ? -errno : result;
461 }
462
463 SyscallReturn
464 truncateFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc)
465 {
466 string path;
467
468 int index = 0;
469 if (!tc->getMemProxy().tryReadString(path, p->getSyscallArg(tc, index)))
470 return -EFAULT;
471
472 off_t length = p->getSyscallArg(tc, index);
473
474 // Adjust path for current working directory
475 path = p->fullPath(path);
476
477 int result = truncate(path.c_str(), length);
478 return (result == -1) ? -errno : result;
479 }
480
481 SyscallReturn
482 ftruncateFunc(SyscallDesc *desc, int num,
483 LiveProcess *process, ThreadContext *tc)
484 {
485 int index = 0;
486 int fd = process->sim_fd(process->getSyscallArg(tc, index));
487
488 if (fd < 0)
489 return -EBADF;
490
491 off_t length = process->getSyscallArg(tc, index);
492
493 int result = ftruncate(fd, length);
494 return (result == -1) ? -errno : result;
495 }
496
497 SyscallReturn
498 truncate64Func(SyscallDesc *desc, int num,
499 LiveProcess *process, ThreadContext *tc)
500 {
501 int index = 0;
502 string path;
503
504 if (!tc->getMemProxy().tryReadString(path, process->getSyscallArg(tc, index)))
505 return -EFAULT;
506
507 int64_t length = process->getSyscallArg(tc, index, 64);
508
509 // Adjust path for current working directory
510 path = process->fullPath(path);
511
512 #if NO_STAT64
513 int result = truncate(path.c_str(), length);
514 #else
515 int result = truncate64(path.c_str(), length);
516 #endif
517 return (result == -1) ? -errno : result;
518 }
519
520 SyscallReturn
521 ftruncate64Func(SyscallDesc *desc, int num,
522 LiveProcess *process, ThreadContext *tc)
523 {
524 int index = 0;
525 int fd = process->sim_fd(process->getSyscallArg(tc, index));
526
527 if (fd < 0)
528 return -EBADF;
529
530 int64_t length = process->getSyscallArg(tc, index, 64);
531
532 #if NO_STAT64
533 int result = ftruncate(fd, length);
534 #else
535 int result = ftruncate64(fd, length);
536 #endif
537 return (result == -1) ? -errno : result;
538 }
539
540 SyscallReturn
541 umaskFunc(SyscallDesc *desc, int num, LiveProcess *process, ThreadContext *tc)
542 {
543 // Letting the simulated program change the simulator's umask seems like
544 // a bad idea. Compromise by just returning the current umask but not
545 // changing anything.
546 mode_t oldMask = umask(0);
547 umask(oldMask);
548 return (int)oldMask;
549 }
550
551 SyscallReturn
552 chownFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc)
553 {
554 string path;
555
556 int index = 0;
557 if (!tc->getMemProxy().tryReadString(path, p->getSyscallArg(tc, index)))
558 return -EFAULT;
559
560 /* XXX endianess */
561 uint32_t owner = p->getSyscallArg(tc, index);
562 uid_t hostOwner = owner;
563 uint32_t group = p->getSyscallArg(tc, index);
564 gid_t hostGroup = group;
565
566 // Adjust path for current working directory
567 path = p->fullPath(path);
568
569 int result = chown(path.c_str(), hostOwner, hostGroup);
570 return (result == -1) ? -errno : result;
571 }
572
573 SyscallReturn
574 fchownFunc(SyscallDesc *desc, int num, LiveProcess *process, ThreadContext *tc)
575 {
576 int index = 0;
577 int fd = process->sim_fd(process->getSyscallArg(tc, index));
578
579 if (fd < 0)
580 return -EBADF;
581
582 /* XXX endianess */
583 uint32_t owner = process->getSyscallArg(tc, index);
584 uid_t hostOwner = owner;
585 uint32_t group = process->getSyscallArg(tc, index);
586 gid_t hostGroup = group;
587
588 int result = fchown(fd, hostOwner, hostGroup);
589 return (result == -1) ? -errno : result;
590 }
591
592
593 SyscallReturn
594 dupFunc(SyscallDesc *desc, int num, LiveProcess *process, ThreadContext *tc)
595 {
596 int index = 0;
597 int fd = process->sim_fd(process->getSyscallArg(tc, index));
598 if (fd < 0)
599 return -EBADF;
600
601 Process::FdMap *fdo = process->sim_fd_obj(fd);
602
603 int result = dup(fd);
604 return (result == -1) ? -errno :
605 process->alloc_fd(result, fdo->filename, fdo->flags, fdo->mode, false);
606 }
607
608
609 SyscallReturn
610 fcntlFunc(SyscallDesc *desc, int num, LiveProcess *process,
611 ThreadContext *tc)
612 {
613 int index = 0;
614 int fd = process->getSyscallArg(tc, index);
615
616 if (fd < 0 || process->sim_fd(fd) < 0)
617 return -EBADF;
618
619 int cmd = process->getSyscallArg(tc, index);
620 switch (cmd) {
621 case 0: // F_DUPFD
622 // if we really wanted to support this, we'd need to do it
623 // in the target fd space.
624 warn("fcntl(%d, F_DUPFD) not supported, error returned\n", fd);
625 return -EMFILE;
626
627 case 1: // F_GETFD (get close-on-exec flag)
628 case 2: // F_SETFD (set close-on-exec flag)
629 return 0;
630
631 case 3: // F_GETFL (get file flags)
632 case 4: // F_SETFL (set file flags)
633 // not sure if this is totally valid, but we'll pass it through
634 // to the underlying OS
635 warn("fcntl(%d, %d) passed through to host\n", fd, cmd);
636 return fcntl(process->sim_fd(fd), cmd);
637 // return 0;
638
639 case 7: // F_GETLK (get lock)
640 case 8: // F_SETLK (set lock)
641 case 9: // F_SETLKW (set lock and wait)
642 // don't mess with file locking... just act like it's OK
643 warn("File lock call (fcntl(%d, %d)) ignored.\n", fd, cmd);
644 return 0;
645
646 default:
647 warn("Unknown fcntl command %d\n", cmd);
648 return 0;
649 }
650 }
651
652 SyscallReturn
653 fcntl64Func(SyscallDesc *desc, int num, LiveProcess *process,
654 ThreadContext *tc)
655 {
656 int index = 0;
657 int fd = process->getSyscallArg(tc, index);
658
659 if (fd < 0 || process->sim_fd(fd) < 0)
660 return -EBADF;
661
662 int cmd = process->getSyscallArg(tc, index);
663 switch (cmd) {
664 case 33: //F_GETLK64
665 warn("fcntl64(%d, F_GETLK64) not supported, error returned\n", fd);
666 return -EMFILE;
667
668 case 34: // F_SETLK64
669 case 35: // F_SETLKW64
670 warn("fcntl64(%d, F_SETLK(W)64) not supported, error returned\n", fd);
671 return -EMFILE;
672
673 default:
674 // not sure if this is totally valid, but we'll pass it through
675 // to the underlying OS
676 warn("fcntl64(%d, %d) passed through to host\n", fd, cmd);
677 return fcntl(process->sim_fd(fd), cmd);
678 // return 0;
679 }
680 }
681
682 SyscallReturn
683 pipePseudoFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
684 ThreadContext *tc)
685 {
686 int fds[2], sim_fds[2];
687 int pipe_retval = pipe(fds);
688
689 if (pipe_retval < 0) {
690 // error
691 return pipe_retval;
692 }
693
694 sim_fds[0] = process->alloc_fd(fds[0], "PIPE-READ", O_WRONLY, -1, true);
695 sim_fds[1] = process->alloc_fd(fds[1], "PIPE-WRITE", O_RDONLY, -1, true);
696
697 process->setReadPipeSource(sim_fds[0], sim_fds[1]);
698 // Alpha Linux convention for pipe() is that fd[0] is returned as
699 // the return value of the function, and fd[1] is returned in r20.
700 tc->setIntReg(SyscallPseudoReturnReg, sim_fds[1]);
701 return sim_fds[0];
702 }
703
704
705 SyscallReturn
706 getpidPseudoFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
707 ThreadContext *tc)
708 {
709 // Make up a PID. There's no interprocess communication in
710 // fake_syscall mode, so there's no way for a process to know it's
711 // not getting a unique value.
712
713 tc->setIntReg(SyscallPseudoReturnReg, process->ppid());
714 return process->pid();
715 }
716
717
718 SyscallReturn
719 getuidPseudoFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
720 ThreadContext *tc)
721 {
722 // Make up a UID and EUID... it shouldn't matter, and we want the
723 // simulation to be deterministic.
724
725 // EUID goes in r20.
726 tc->setIntReg(SyscallPseudoReturnReg, process->euid()); //EUID
727 return process->uid(); // UID
728 }
729
730
731 SyscallReturn
732 getgidPseudoFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
733 ThreadContext *tc)
734 {
735 // Get current group ID. EGID goes in r20.
736 tc->setIntReg(SyscallPseudoReturnReg, process->egid()); //EGID
737 return process->gid();
738 }
739
740
741 SyscallReturn
742 setuidFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
743 ThreadContext *tc)
744 {
745 // can't fathom why a benchmark would call this.
746 int index = 0;
747 warn("Ignoring call to setuid(%d)\n", process->getSyscallArg(tc, index));
748 return 0;
749 }
750
751 SyscallReturn
752 getpidFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
753 ThreadContext *tc)
754 {
755 // Make up a PID. There's no interprocess communication in
756 // fake_syscall mode, so there's no way for a process to know it's
757 // not getting a unique value.
758
759 tc->setIntReg(SyscallPseudoReturnReg, process->ppid()); //PID
760 return process->pid();
761 }
762
763 SyscallReturn
764 getppidFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
765 ThreadContext *tc)
766 {
767 return process->ppid();
768 }
769
770 SyscallReturn
771 getuidFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
772 ThreadContext *tc)
773 {
774 return process->uid(); // UID
775 }
776
777 SyscallReturn
778 geteuidFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
779 ThreadContext *tc)
780 {
781 return process->euid(); // UID
782 }
783
784 SyscallReturn
785 getgidFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
786 ThreadContext *tc)
787 {
788 return process->gid();
789 }
790
791 SyscallReturn
792 getegidFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
793 ThreadContext *tc)
794 {
795 return process->egid();
796 }
797
798
799 SyscallReturn
800 cloneFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
801 ThreadContext *tc)
802 {
803 int index = 0;
804 IntReg flags = process->getSyscallArg(tc, index);
805 IntReg newStack = process->getSyscallArg(tc, index);
806
807 DPRINTF(SyscallVerbose, "In sys_clone:\n");
808 DPRINTF(SyscallVerbose, " Flags=%llx\n", flags);
809 DPRINTF(SyscallVerbose, " Child stack=%llx\n", newStack);
810
811
812 if (flags != 0x10f00) {
813 warn("This sys_clone implementation assumes flags "
814 "CLONE_VM|CLONE_FS|CLONE_FILES|CLONE_SIGHAND|CLONE_THREAD "
815 "(0x10f00), and may not work correctly with given flags "
816 "0x%llx\n", flags);
817 }
818
819 ThreadContext* ctc; // child thread context
820 if ( ( ctc = process->findFreeContext() ) != NULL ) {
821 DPRINTF(SyscallVerbose, " Found unallocated thread context\n");
822
823 ctc->clearArchRegs();
824
825 // Arch-specific cloning code
826 #if THE_ISA == ALPHA_ISA or THE_ISA == X86_ISA
827 // Cloning the misc. regs for these archs is enough
828 TheISA::copyMiscRegs(tc, ctc);
829 #elif THE_ISA == SPARC_ISA
830 TheISA::copyRegs(tc, ctc);
831
832 // TODO: Explain what this code actually does :-)
833 ctc->setIntReg(NumIntArchRegs + 6, 0);
834 ctc->setIntReg(NumIntArchRegs + 4, 0);
835 ctc->setIntReg(NumIntArchRegs + 3, NWindows - 2);
836 ctc->setIntReg(NumIntArchRegs + 5, NWindows);
837 ctc->setMiscReg(MISCREG_CWP, 0);
838 ctc->setIntReg(NumIntArchRegs + 7, 0);
839 ctc->setMiscRegNoEffect(MISCREG_TL, 0);
840 ctc->setMiscReg(MISCREG_ASI, ASI_PRIMARY);
841
842 for (int y = 8; y < 32; y++)
843 ctc->setIntReg(y, tc->readIntReg(y));
844 #elif THE_ISA == ARM_ISA
845 TheISA::copyRegs(tc, ctc);
846 #else
847 fatal("sys_clone is not implemented for this ISA\n");
848 #endif
849
850 // Set up stack register
851 ctc->setIntReg(TheISA::StackPointerReg, newStack);
852
853 // Set up syscall return values in parent and child
854 ctc->setIntReg(ReturnValueReg, 0); // return value, child
855
856 // Alpha needs SyscallSuccessReg=0 in child
857 #if THE_ISA == ALPHA_ISA
858 ctc->setIntReg(TheISA::SyscallSuccessReg, 0);
859 #endif
860
861 // In SPARC/Linux, clone returns 0 on pseudo-return register if
862 // parent, non-zero if child
863 #if THE_ISA == SPARC_ISA
864 tc->setIntReg(TheISA::SyscallPseudoReturnReg, 0);
865 ctc->setIntReg(TheISA::SyscallPseudoReturnReg, 1);
866 #endif
867
868 ctc->pcState(tc->nextInstAddr());
869
870 ctc->activate();
871
872 // Should return nonzero child TID in parent's syscall return register,
873 // but for our pthread library any non-zero value will work
874 return 1;
875 } else {
876 fatal("Called sys_clone, but no unallocated thread contexts found!\n");
877 return 0;
878 }
879 }
880
881 SyscallReturn
882 accessFunc(SyscallDesc *desc, int callnum, LiveProcess *p, ThreadContext *tc,
883 int index)
884 {
885 string path;
886 if (!tc->getMemProxy().tryReadString(path, p->getSyscallArg(tc, index)))
887 return -EFAULT;
888
889 // Adjust path for current working directory
890 path = p->fullPath(path);
891
892 mode_t mode = p->getSyscallArg(tc, index);
893
894 int result = access(path.c_str(), mode);
895 return (result == -1) ? -errno : result;
896 }
897
898 SyscallReturn
899 accessFunc(SyscallDesc *desc, int callnum, LiveProcess *p, ThreadContext *tc)
900 {
901 return accessFunc(desc, callnum, p, tc, 0);
902 }
903