8f3d08cd7ddb9ba52de1ee730a05c1e3b8ae3c5f
[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 tgt_fd = process->getSyscallArg(tc, index);
598 int sim_fd = process->sim_fd(tgt_fd);
599 if (sim_fd < 0)
600 return -EBADF;
601
602 Process::FdMap *fdo = process->sim_fd_obj(tgt_fd);
603
604 int result = dup(sim_fd);
605 return (result == -1) ? -errno :
606 process->alloc_fd(result, fdo->filename, fdo->flags, fdo->mode, false);
607 }
608
609
610 SyscallReturn
611 fcntlFunc(SyscallDesc *desc, int num, LiveProcess *process,
612 ThreadContext *tc)
613 {
614 int index = 0;
615 int fd = process->getSyscallArg(tc, index);
616
617 if (fd < 0 || process->sim_fd(fd) < 0)
618 return -EBADF;
619
620 int cmd = process->getSyscallArg(tc, index);
621 switch (cmd) {
622 case 0: // F_DUPFD
623 // if we really wanted to support this, we'd need to do it
624 // in the target fd space.
625 warn("fcntl(%d, F_DUPFD) not supported, error returned\n", fd);
626 return -EMFILE;
627
628 case 1: // F_GETFD (get close-on-exec flag)
629 case 2: // F_SETFD (set close-on-exec flag)
630 return 0;
631
632 case 3: // F_GETFL (get file flags)
633 case 4: // F_SETFL (set file flags)
634 // not sure if this is totally valid, but we'll pass it through
635 // to the underlying OS
636 warn("fcntl(%d, %d) passed through to host\n", fd, cmd);
637 return fcntl(process->sim_fd(fd), cmd);
638 // return 0;
639
640 case 7: // F_GETLK (get lock)
641 case 8: // F_SETLK (set lock)
642 case 9: // F_SETLKW (set lock and wait)
643 // don't mess with file locking... just act like it's OK
644 warn("File lock call (fcntl(%d, %d)) ignored.\n", fd, cmd);
645 return 0;
646
647 default:
648 warn("Unknown fcntl command %d\n", cmd);
649 return 0;
650 }
651 }
652
653 SyscallReturn
654 fcntl64Func(SyscallDesc *desc, int num, LiveProcess *process,
655 ThreadContext *tc)
656 {
657 int index = 0;
658 int fd = process->getSyscallArg(tc, index);
659
660 if (fd < 0 || process->sim_fd(fd) < 0)
661 return -EBADF;
662
663 int cmd = process->getSyscallArg(tc, index);
664 switch (cmd) {
665 case 33: //F_GETLK64
666 warn("fcntl64(%d, F_GETLK64) not supported, error returned\n", fd);
667 return -EMFILE;
668
669 case 34: // F_SETLK64
670 case 35: // F_SETLKW64
671 warn("fcntl64(%d, F_SETLK(W)64) not supported, error returned\n", fd);
672 return -EMFILE;
673
674 default:
675 // not sure if this is totally valid, but we'll pass it through
676 // to the underlying OS
677 warn("fcntl64(%d, %d) passed through to host\n", fd, cmd);
678 return fcntl(process->sim_fd(fd), cmd);
679 // return 0;
680 }
681 }
682
683 SyscallReturn
684 pipePseudoFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
685 ThreadContext *tc)
686 {
687 int fds[2], sim_fds[2];
688 int pipe_retval = pipe(fds);
689
690 if (pipe_retval < 0) {
691 // error
692 return pipe_retval;
693 }
694
695 sim_fds[0] = process->alloc_fd(fds[0], "PIPE-READ", O_WRONLY, -1, true);
696 sim_fds[1] = process->alloc_fd(fds[1], "PIPE-WRITE", O_RDONLY, -1, true);
697
698 process->setReadPipeSource(sim_fds[0], sim_fds[1]);
699 // Alpha Linux convention for pipe() is that fd[0] is returned as
700 // the return value of the function, and fd[1] is returned in r20.
701 tc->setIntReg(SyscallPseudoReturnReg, sim_fds[1]);
702 return sim_fds[0];
703 }
704
705
706 SyscallReturn
707 getpidPseudoFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
708 ThreadContext *tc)
709 {
710 // Make up a PID. There's no interprocess communication in
711 // fake_syscall mode, so there's no way for a process to know it's
712 // not getting a unique value.
713
714 tc->setIntReg(SyscallPseudoReturnReg, process->ppid());
715 return process->pid();
716 }
717
718
719 SyscallReturn
720 getuidPseudoFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
721 ThreadContext *tc)
722 {
723 // Make up a UID and EUID... it shouldn't matter, and we want the
724 // simulation to be deterministic.
725
726 // EUID goes in r20.
727 tc->setIntReg(SyscallPseudoReturnReg, process->euid()); //EUID
728 return process->uid(); // UID
729 }
730
731
732 SyscallReturn
733 getgidPseudoFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
734 ThreadContext *tc)
735 {
736 // Get current group ID. EGID goes in r20.
737 tc->setIntReg(SyscallPseudoReturnReg, process->egid()); //EGID
738 return process->gid();
739 }
740
741
742 SyscallReturn
743 setuidFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
744 ThreadContext *tc)
745 {
746 // can't fathom why a benchmark would call this.
747 int index = 0;
748 warn("Ignoring call to setuid(%d)\n", process->getSyscallArg(tc, index));
749 return 0;
750 }
751
752 SyscallReturn
753 getpidFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
754 ThreadContext *tc)
755 {
756 // Make up a PID. There's no interprocess communication in
757 // fake_syscall mode, so there's no way for a process to know it's
758 // not getting a unique value.
759
760 tc->setIntReg(SyscallPseudoReturnReg, process->ppid()); //PID
761 return process->pid();
762 }
763
764 SyscallReturn
765 getppidFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
766 ThreadContext *tc)
767 {
768 return process->ppid();
769 }
770
771 SyscallReturn
772 getuidFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
773 ThreadContext *tc)
774 {
775 return process->uid(); // UID
776 }
777
778 SyscallReturn
779 geteuidFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
780 ThreadContext *tc)
781 {
782 return process->euid(); // UID
783 }
784
785 SyscallReturn
786 getgidFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
787 ThreadContext *tc)
788 {
789 return process->gid();
790 }
791
792 SyscallReturn
793 getegidFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
794 ThreadContext *tc)
795 {
796 return process->egid();
797 }
798
799
800 SyscallReturn
801 cloneFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
802 ThreadContext *tc)
803 {
804 int index = 0;
805 IntReg flags = process->getSyscallArg(tc, index);
806 IntReg newStack = process->getSyscallArg(tc, index);
807
808 DPRINTF(SyscallVerbose, "In sys_clone:\n");
809 DPRINTF(SyscallVerbose, " Flags=%llx\n", flags);
810 DPRINTF(SyscallVerbose, " Child stack=%llx\n", newStack);
811
812
813 if (flags != 0x10f00) {
814 warn("This sys_clone implementation assumes flags "
815 "CLONE_VM|CLONE_FS|CLONE_FILES|CLONE_SIGHAND|CLONE_THREAD "
816 "(0x10f00), and may not work correctly with given flags "
817 "0x%llx\n", flags);
818 }
819
820 ThreadContext* ctc; // child thread context
821 if ( ( ctc = process->findFreeContext() ) != NULL ) {
822 DPRINTF(SyscallVerbose, " Found unallocated thread context\n");
823
824 ctc->clearArchRegs();
825
826 // Arch-specific cloning code
827 #if THE_ISA == ALPHA_ISA or THE_ISA == X86_ISA
828 // Cloning the misc. regs for these archs is enough
829 TheISA::copyMiscRegs(tc, ctc);
830 #elif THE_ISA == SPARC_ISA
831 TheISA::copyRegs(tc, ctc);
832
833 // TODO: Explain what this code actually does :-)
834 ctc->setIntReg(NumIntArchRegs + 6, 0);
835 ctc->setIntReg(NumIntArchRegs + 4, 0);
836 ctc->setIntReg(NumIntArchRegs + 3, NWindows - 2);
837 ctc->setIntReg(NumIntArchRegs + 5, NWindows);
838 ctc->setMiscReg(MISCREG_CWP, 0);
839 ctc->setIntReg(NumIntArchRegs + 7, 0);
840 ctc->setMiscRegNoEffect(MISCREG_TL, 0);
841 ctc->setMiscReg(MISCREG_ASI, ASI_PRIMARY);
842
843 for (int y = 8; y < 32; y++)
844 ctc->setIntReg(y, tc->readIntReg(y));
845 #elif THE_ISA == ARM_ISA
846 TheISA::copyRegs(tc, ctc);
847 #else
848 fatal("sys_clone is not implemented for this ISA\n");
849 #endif
850
851 // Set up stack register
852 ctc->setIntReg(TheISA::StackPointerReg, newStack);
853
854 // Set up syscall return values in parent and child
855 ctc->setIntReg(ReturnValueReg, 0); // return value, child
856
857 // Alpha needs SyscallSuccessReg=0 in child
858 #if THE_ISA == ALPHA_ISA
859 ctc->setIntReg(TheISA::SyscallSuccessReg, 0);
860 #endif
861
862 // In SPARC/Linux, clone returns 0 on pseudo-return register if
863 // parent, non-zero if child
864 #if THE_ISA == SPARC_ISA
865 tc->setIntReg(TheISA::SyscallPseudoReturnReg, 0);
866 ctc->setIntReg(TheISA::SyscallPseudoReturnReg, 1);
867 #endif
868
869 ctc->pcState(tc->nextInstAddr());
870
871 ctc->activate();
872
873 // Should return nonzero child TID in parent's syscall return register,
874 // but for our pthread library any non-zero value will work
875 return 1;
876 } else {
877 fatal("Called sys_clone, but no unallocated thread contexts found!\n");
878 return 0;
879 }
880 }
881
882 SyscallReturn
883 accessFunc(SyscallDesc *desc, int callnum, LiveProcess *p, ThreadContext *tc,
884 int index)
885 {
886 string path;
887 if (!tc->getMemProxy().tryReadString(path, p->getSyscallArg(tc, index)))
888 return -EFAULT;
889
890 // Adjust path for current working directory
891 path = p->fullPath(path);
892
893 mode_t mode = p->getSyscallArg(tc, index);
894
895 int result = access(path.c_str(), mode);
896 return (result == -1) ? -errno : result;
897 }
898
899 SyscallReturn
900 accessFunc(SyscallDesc *desc, int callnum, LiveProcess *p, ThreadContext *tc)
901 {
902 return accessFunc(desc, callnum, p, tc, 0);
903 }
904