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