Deleted Added
sdiff udiff text old ( 11875:8e928c0f98d1 ) new ( 11885:79af314e9f0d )
full compact
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 "sim/syscall_emul.hh"
33
34#include <fcntl.h>
35#include <unistd.h>
36
37#include <iostream>
38#include <string>
39
40#include "arch/utility.hh"
41#include "base/chunk_generator.hh"
42#include "base/trace.hh"
43#include "config/the_isa.hh"
44#include "cpu/thread_context.hh"
45#include "mem/page_table.hh"
46#include "sim/process.hh"
47#include "sim/sim_exit.hh"
48#include "sim/syscall_debug_macros.hh"
49#include "sim/syscall_desc.hh"
50#include "sim/system.hh"
51
52using namespace std;
53using namespace TheISA;
54
55SyscallReturn
56unimplementedFunc(SyscallDesc *desc, int callnum, Process *process,
57 ThreadContext *tc)
58{
59 fatal("syscall %s (#%d) unimplemented.", desc->name(), callnum);
60
61 return 1;
62}
63
64
65SyscallReturn
66ignoreFunc(SyscallDesc *desc, int callnum, Process *process,
67 ThreadContext *tc)
68{
69 if (desc->needWarning()) {
70 warn("ignoring syscall %s(...)%s", desc->name(), desc->warnOnce() ?
71 "\n (further warnings will be suppressed)" : "");
72 }
73
74 return 0;
75}
76
77
78SyscallReturn
79exitFunc(SyscallDesc *desc, int callnum, Process *process,
80 ThreadContext *tc)
81{
82 if (process->system->numRunningContexts() == 1) {
83 // Last running context... exit simulator
84 int index = 0;
85 exitSimLoop("target called exit()",
86 process->getSyscallArg(tc, index) & 0xff);
87 } else {
88 // other running threads... just halt this one
89 tc->halt();
90 }
91
92 return 1;
93}
94
95
96SyscallReturn
97exitGroupFunc(SyscallDesc *desc, int callnum, Process *process,
98 ThreadContext *tc)
99{
100 // halt all threads belonging to this process
101 for (auto i: process->contextIds) {
102 process->system->getThreadContext(i)->halt();
103 }
104
105 if (!process->system->numRunningContexts()) {
106 // all threads belonged to this process... exit simulator
107 int index = 0;
108 exitSimLoop("target called exit()",
109 process->getSyscallArg(tc, index) & 0xff);
110 }
111
112 return 1;
113}
114
115
116SyscallReturn
117getpagesizeFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
118{
119 return (int)PageBytes;
120}
121
122
123SyscallReturn
124brkFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
125{
126 // change brk addr to first arg
127 int index = 0;
128 Addr new_brk = p->getSyscallArg(tc, index);
129
130 // in Linux at least, brk(0) returns the current break value
131 // (note that the syscall and the glibc function have different behavior)
132 if (new_brk == 0)
133 return p->brk_point;
134
135 if (new_brk > p->brk_point) {
136 // might need to allocate some new pages
137 for (ChunkGenerator gen(p->brk_point, new_brk - p->brk_point,
138 PageBytes); !gen.done(); gen.next()) {
139 if (!p->pTable->translate(gen.addr()))
140 p->allocateMem(roundDown(gen.addr(), PageBytes), PageBytes);
141
142 // if the address is already there, zero it out
143 else {
144 uint8_t zero = 0;
145 SETranslatingPortProxy &tp = tc->getMemProxy();
146
147 // split non-page aligned accesses
148 Addr next_page = roundUp(gen.addr(), PageBytes);
149 uint32_t size_needed = next_page - gen.addr();
150 tp.memsetBlob(gen.addr(), zero, size_needed);
151 if (gen.addr() + PageBytes > next_page &&
152 next_page < new_brk &&
153 p->pTable->translate(next_page))
154 {
155 size_needed = PageBytes - size_needed;
156 tp.memsetBlob(next_page, zero, size_needed);
157 }
158 }
159 }
160 }
161
162 p->brk_point = new_brk;
163 DPRINTF_SYSCALL(Verbose, "brk: break point changed to: %#X\n",
164 p->brk_point);
165 return p->brk_point;
166}
167
168
169SyscallReturn
170closeFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
171{
172 int index = 0;
173 int tgt_fd = p->getSyscallArg(tc, index);
174
175 return p->fds->closeFDEntry(tgt_fd);
176}
177
178
179SyscallReturn
180readFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
181{
182 int index = 0;
183 int tgt_fd = p->getSyscallArg(tc, index);
184 Addr bufPtr = p->getSyscallArg(tc, index);
185 int nbytes = p->getSyscallArg(tc, index);
186
187 auto hbfdp = std::dynamic_pointer_cast<HBFDEntry>((*p->fds)[tgt_fd]);
188 if (!hbfdp)
189 return -EBADF;
190 int sim_fd = hbfdp->getSimFD();
191
192 BufferArg bufArg(bufPtr, nbytes);
193 int bytes_read = read(sim_fd, bufArg.bufferPtr(), nbytes);
194
195 if (bytes_read > 0)
196 bufArg.copyOut(tc->getMemProxy());
197
198 return bytes_read;
199}
200
201SyscallReturn
202writeFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
203{
204 int index = 0;
205 int tgt_fd = p->getSyscallArg(tc, index);
206 Addr bufPtr = p->getSyscallArg(tc, index);
207 int nbytes = p->getSyscallArg(tc, index);
208
209 auto hbfdp = std::dynamic_pointer_cast<HBFDEntry>((*p->fds)[tgt_fd]);
210 if (!hbfdp)
211 return -EBADF;
212 int sim_fd = hbfdp->getSimFD();
213
214 BufferArg bufArg(bufPtr, nbytes);
215 bufArg.copyIn(tc->getMemProxy());
216
217 int bytes_written = write(sim_fd, bufArg.bufferPtr(), nbytes);
218
219 fsync(sim_fd);
220
221 return bytes_written;
222}
223
224
225SyscallReturn
226lseekFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
227{
228 int index = 0;
229 int tgt_fd = p->getSyscallArg(tc, index);
230 uint64_t offs = p->getSyscallArg(tc, index);
231 int whence = p->getSyscallArg(tc, index);
232
233 auto ffdp = std::dynamic_pointer_cast<FileFDEntry>((*p->fds)[tgt_fd]);
234 if (!ffdp)
235 return -EBADF;
236 int sim_fd = ffdp->getSimFD();
237
238 off_t result = lseek(sim_fd, offs, whence);
239
240 return (result == (off_t)-1) ? -errno : result;
241}
242
243
244SyscallReturn
245_llseekFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
246{
247 int index = 0;
248 int tgt_fd = p->getSyscallArg(tc, index);
249 uint64_t offset_high = p->getSyscallArg(tc, index);
250 uint32_t offset_low = p->getSyscallArg(tc, index);
251 Addr result_ptr = p->getSyscallArg(tc, index);
252 int whence = p->getSyscallArg(tc, index);
253
254 auto ffdp = std::dynamic_pointer_cast<FileFDEntry>((*p->fds)[tgt_fd]);
255 if (!ffdp)
256 return -EBADF;
257 int sim_fd = ffdp->getSimFD();
258
259 uint64_t offset = (offset_high << 32) | offset_low;
260
261 uint64_t result = lseek(sim_fd, offset, whence);
262 result = TheISA::htog(result);
263
264 if (result == (off_t)-1)
265 return -errno;
266 // Assuming that the size of loff_t is 64 bits on the target platform
267 BufferArg result_buf(result_ptr, sizeof(result));
268 memcpy(result_buf.bufferPtr(), &result, sizeof(result));
269 result_buf.copyOut(tc->getMemProxy());
270 return 0;
271}
272
273
274SyscallReturn
275munmapFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
276{
277 // With mmap more fully implemented, it might be worthwhile to bite
278 // the bullet and implement munmap. Should allow us to reuse simulated
279 // memory.
280 return 0;
281}
282
283
284const char *hostname = "m5.eecs.umich.edu";
285
286SyscallReturn
287gethostnameFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
288{
289 int index = 0;
290 Addr bufPtr = p->getSyscallArg(tc, index);
291 int name_len = p->getSyscallArg(tc, index);
292 BufferArg name(bufPtr, name_len);
293
294 strncpy((char *)name.bufferPtr(), hostname, name_len);
295
296 name.copyOut(tc->getMemProxy());
297
298 return 0;
299}
300
301SyscallReturn
302getcwdFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
303{
304 int result = 0;
305 int index = 0;
306 Addr bufPtr = p->getSyscallArg(tc, index);
307 unsigned long size = p->getSyscallArg(tc, index);
308 BufferArg buf(bufPtr, size);
309
310 // Is current working directory defined?
311 string cwd = p->getcwd();
312 if (!cwd.empty()) {
313 if (cwd.length() >= size) {
314 // Buffer too small
315 return -ERANGE;
316 }
317 strncpy((char *)buf.bufferPtr(), cwd.c_str(), size);
318 result = cwd.length();
319 } else {
320 if (getcwd((char *)buf.bufferPtr(), size)) {
321 result = strlen((char *)buf.bufferPtr());
322 } else {
323 result = -1;
324 }
325 }
326
327 buf.copyOut(tc->getMemProxy());
328
329 return (result == -1) ? -errno : result;
330}
331
332/// Target open() handler.
333SyscallReturn
334readlinkFunc(SyscallDesc *desc, int callnum, Process *process,
335 ThreadContext *tc)
336{
337 return readlinkFunc(desc, callnum, process, tc, 0);
338}
339
340SyscallReturn
341readlinkFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc,
342 int index)
343{
344 string path;
345
346 if (!tc->getMemProxy().tryReadString(path, p->getSyscallArg(tc, index)))
347 return -EFAULT;
348
349 // Adjust path for current working directory
350 path = p->fullPath(path);
351
352 Addr bufPtr = p->getSyscallArg(tc, index);
353 size_t bufsiz = p->getSyscallArg(tc, index);
354
355 BufferArg buf(bufPtr, bufsiz);
356
357 int result = -1;
358 if (path != "/proc/self/exe") {
359 result = readlink(path.c_str(), (char *)buf.bufferPtr(), bufsiz);
360 } else {
361 // Emulate readlink() called on '/proc/self/exe' should return the
362 // absolute path of the binary running in the simulated system (the
363 // Process' executable). It is possible that using this path in
364 // the simulated system will result in unexpected behavior if:
365 // 1) One binary runs another (e.g., -c time -o "my_binary"), and
366 // called binary calls readlink().
367 // 2) The host's full path to the running benchmark changes from one
368 // simulation to another. This can result in different simulated
369 // performance since the simulated system will process the binary
370 // path differently, even if the binary itself does not change.
371
372 // Get the absolute canonical path to the running application
373 char real_path[PATH_MAX];
374 char *check_real_path = realpath(p->progName(), real_path);
375 if (!check_real_path) {
376 fatal("readlink('/proc/self/exe') unable to resolve path to "
377 "executable: %s", p->progName());
378 }
379 strncpy((char*)buf.bufferPtr(), real_path, bufsiz);
380 size_t real_path_len = strlen(real_path);
381 if (real_path_len > bufsiz) {
382 // readlink will truncate the contents of the
383 // path to ensure it is no more than bufsiz
384 result = bufsiz;
385 } else {
386 result = real_path_len;
387 }
388
389 // Issue a warning about potential unexpected results
390 warn_once("readlink() called on '/proc/self/exe' may yield unexpected "
391 "results in various settings.\n Returning '%s'\n",
392 (char*)buf.bufferPtr());
393 }
394
395 buf.copyOut(tc->getMemProxy());
396
397 return (result == -1) ? -errno : result;
398}
399
400SyscallReturn
401unlinkFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
402{
403 return unlinkHelper(desc, num, p, tc, 0);
404}
405
406SyscallReturn
407unlinkHelper(SyscallDesc *desc, int num, Process *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
423SyscallReturn
424mkdirFunc(SyscallDesc *desc, int num, Process *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
441SyscallReturn
442renameFunc(SyscallDesc *desc, int num, Process *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
463SyscallReturn
464truncateFunc(SyscallDesc *desc, int num, Process *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
481SyscallReturn
482ftruncateFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
483{
484 int index = 0;
485 int tgt_fd = p->getSyscallArg(tc, index);
486 off_t length = p->getSyscallArg(tc, index);
487
488 auto ffdp = std::dynamic_pointer_cast<FileFDEntry>((*p->fds)[tgt_fd]);
489 if (!ffdp)
490 return -EBADF;
491 int sim_fd = ffdp->getSimFD();
492
493 int result = ftruncate(sim_fd, length);
494 return (result == -1) ? -errno : result;
495}
496
497SyscallReturn
498truncate64Func(SyscallDesc *desc, int num,
499 Process *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
520SyscallReturn
521ftruncate64Func(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
522{
523 int index = 0;
524 int tgt_fd = p->getSyscallArg(tc, index);
525 int64_t length = p->getSyscallArg(tc, index, 64);
526
527 auto ffdp = std::dynamic_pointer_cast<FileFDEntry>((*p->fds)[tgt_fd]);
528 if (!ffdp)
529 return -EBADF;
530 int sim_fd = ffdp->getSimFD();
531
532#if NO_STAT64
533 int result = ftruncate(sim_fd, length);
534#else
535 int result = ftruncate64(sim_fd, length);
536#endif
537 return (result == -1) ? -errno : result;
538}
539
540SyscallReturn
541umaskFunc(SyscallDesc *desc, int num, Process *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
551SyscallReturn
552chownFunc(SyscallDesc *desc, int num, Process *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
573SyscallReturn
574fchownFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
575{
576 int index = 0;
577 int tgt_fd = p->getSyscallArg(tc, index);
578
579 auto ffdp = std::dynamic_pointer_cast<FileFDEntry>((*p->fds)[tgt_fd]);
580 if (!ffdp)
581 return -EBADF;
582 int sim_fd = ffdp->getSimFD();
583
584 /* XXX endianess */
585 uint32_t owner = p->getSyscallArg(tc, index);
586 uid_t hostOwner = owner;
587 uint32_t group = p->getSyscallArg(tc, index);
588 gid_t hostGroup = group;
589
590 int result = fchown(sim_fd, hostOwner, hostGroup);
591 return (result == -1) ? -errno : result;
592}
593
594
595/**
596 * TODO: there's a bit more involved here since file descriptors created with
597 * dup are supposed to share a file description. So, there is a problem with
598 * maintaining fields like file offset or flags since an update to such a
599 * field won't be reflected in the metadata for the fd entries that we
600 * maintain to hold metadata for checkpoint restoration.
601 */
602SyscallReturn
603dupFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
604{
605 int index = 0;
606 int tgt_fd = p->getSyscallArg(tc, index);
607
608 auto old_hbfdp = std::dynamic_pointer_cast<HBFDEntry>((*p->fds)[tgt_fd]);
609 if (!old_hbfdp)
610 return -EBADF;
611 int sim_fd = old_hbfdp->getSimFD();
612
613 int result = dup(sim_fd);
614 int local_errno = errno;
615
616 std::shared_ptr<FDEntry> new_fdep = old_hbfdp->clone();
617 auto new_hbfdp = std::dynamic_pointer_cast<HBFDEntry>(new_fdep);
618 new_hbfdp->setSimFD(result);
619
620 return (result == -1) ? -local_errno : p->fds->allocFD(new_fdep);
621}
622
623SyscallReturn
624fcntlFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
625{
626 int arg;
627 int index = 0;
628 int tgt_fd = p->getSyscallArg(tc, index);
629 int cmd = p->getSyscallArg(tc, index);
630
631 auto hbfdp = std::dynamic_pointer_cast<HBFDEntry>((*p->fds)[tgt_fd]);
632 if (!hbfdp)
633 return -EBADF;
634 int sim_fd = hbfdp->getSimFD();
635
636 int coe = hbfdp->getCOE();
637
638 switch (cmd) {
639 case F_GETFD:
640 return coe & FD_CLOEXEC;
641
642 case F_SETFD: {
643 arg = p->getSyscallArg(tc, index);
644 arg ? hbfdp->setCOE(true) : hbfdp->setCOE(false);
645 return 0;
646 }
647
648 // Rely on the host to maintain the file status flags for this file
649 // description rather than maintain it ourselves. Admittedly, this
650 // is suboptimal (and possibly error prone), but it is difficult to
651 // maintain the flags by tracking them across the different descriptors
652 // (that refer to this file description) caused by clone, dup, and
653 // subsequent fcntls.
654 case F_GETFL:
655 case F_SETFL: {
656 arg = p->getSyscallArg(tc, index);
657 int rv = fcntl(sim_fd, cmd, arg);
658 return (rv == -1) ? -errno : rv;
659 }
660
661 default:
662 warn("fcntl: unsupported command %d\n", cmd);
663 return 0;
664 }
665}
666
667SyscallReturn
668fcntl64Func(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
669{
670 int index = 0;
671 int tgt_fd = p->getSyscallArg(tc, index);
672
673 auto hbfdp = std::dynamic_pointer_cast<HBFDEntry>((*p->fds)[tgt_fd]);
674 if (!hbfdp)
675 return -EBADF;
676 int sim_fd = hbfdp->getSimFD();
677
678 int cmd = p->getSyscallArg(tc, index);
679 switch (cmd) {
680 case 33: //F_GETLK64
681 warn("fcntl64(%d, F_GETLK64) not supported, error returned\n", tgt_fd);
682 return -EMFILE;
683
684 case 34: // F_SETLK64
685 case 35: // F_SETLKW64
686 warn("fcntl64(%d, F_SETLK(W)64) not supported, error returned\n",
687 tgt_fd);
688 return -EMFILE;
689
690 default:
691 // not sure if this is totally valid, but we'll pass it through
692 // to the underlying OS
693 warn("fcntl64(%d, %d) passed through to host\n", tgt_fd, cmd);
694 return fcntl(sim_fd, cmd);
695 // return 0;
696 }
697}
698
699SyscallReturn
700pipePseudoFunc(SyscallDesc *desc, int callnum, Process *process,
701 ThreadContext *tc)
702{
703 int sim_fds[2], tgt_fds[2];
704
705 int pipe_retval = pipe(sim_fds);
706 if (pipe_retval < 0)
707 return pipe_retval;
708
709 auto rend = PipeFDEntry::EndType::read;
710 auto rpfd = std::make_shared<PipeFDEntry>(sim_fds[0], O_WRONLY, rend);
711
712 auto wend = PipeFDEntry::EndType::write;
713 auto wpfd = std::make_shared<PipeFDEntry>(sim_fds[1], O_RDONLY, wend);
714
715 tgt_fds[0] = process->fds->allocFD(rpfd);
716 tgt_fds[1] = process->fds->allocFD(wpfd);
717
718 /**
719 * Now patch the read object to record the target file descriptor chosen
720 * as the write end of the pipe.
721 */
722 rpfd->setPipeReadSource(tgt_fds[1]);
723
724 /**
725 * Alpha Linux convention for pipe() is that fd[0] is returned as
726 * the return value of the function, and fd[1] is returned in r20.
727 */
728 tc->setIntReg(SyscallPseudoReturnReg, tgt_fds[1]);
729 return sim_fds[0];
730}
731
732
733SyscallReturn
734getpidPseudoFunc(SyscallDesc *desc, int callnum, Process *process,
735 ThreadContext *tc)
736{
737 // Make up a PID. There's no interprocess communication in
738 // fake_syscall mode, so there's no way for a process to know it's
739 // not getting a unique value.
740
741 tc->setIntReg(SyscallPseudoReturnReg, process->ppid());
742 return process->pid();
743}
744
745
746SyscallReturn
747getuidPseudoFunc(SyscallDesc *desc, int callnum, Process *process,
748 ThreadContext *tc)
749{
750 // Make up a UID and EUID... it shouldn't matter, and we want the
751 // simulation to be deterministic.
752
753 // EUID goes in r20.
754 tc->setIntReg(SyscallPseudoReturnReg, process->euid()); //EUID
755 return process->uid(); // UID
756}
757
758
759SyscallReturn
760getgidPseudoFunc(SyscallDesc *desc, int callnum, Process *process,
761 ThreadContext *tc)
762{
763 // Get current group ID. EGID goes in r20.
764 tc->setIntReg(SyscallPseudoReturnReg, process->egid()); //EGID
765 return process->gid();
766}
767
768
769SyscallReturn
770setuidFunc(SyscallDesc *desc, int callnum, Process *process,
771 ThreadContext *tc)
772{
773 // can't fathom why a benchmark would call this.
774 int index = 0;
775 warn("Ignoring call to setuid(%d)\n", process->getSyscallArg(tc, index));
776 return 0;
777}
778
779SyscallReturn
780getpidFunc(SyscallDesc *desc, int callnum, Process *process,
781 ThreadContext *tc)
782{
783 // Make up a PID. There's no interprocess communication in
784 // fake_syscall mode, so there's no way for a process to know it's
785 // not getting a unique value.
786
787 tc->setIntReg(SyscallPseudoReturnReg, process->ppid()); //PID
788 return process->pid();
789}
790
791SyscallReturn
792getppidFunc(SyscallDesc *desc, int callnum, Process *process,
793 ThreadContext *tc)
794{
795 return process->ppid();
796}
797
798SyscallReturn
799getuidFunc(SyscallDesc *desc, int callnum, Process *process,
800 ThreadContext *tc)
801{
802 return process->uid(); // UID
803}
804
805SyscallReturn
806geteuidFunc(SyscallDesc *desc, int callnum, Process *process,
807 ThreadContext *tc)
808{
809 return process->euid(); // UID
810}
811
812SyscallReturn
813getgidFunc(SyscallDesc *desc, int callnum, Process *process,
814 ThreadContext *tc)
815{
816 return process->gid();
817}
818
819SyscallReturn
820getegidFunc(SyscallDesc *desc, int callnum, Process *process,
821 ThreadContext *tc)
822{
823 return process->egid();
824}
825
826
827SyscallReturn
828cloneFunc(SyscallDesc *desc, int callnum, Process *process,
829 ThreadContext *tc)
830{
831 int index = 0;
832 IntReg flags = process->getSyscallArg(tc, index);
833 IntReg newStack = process->getSyscallArg(tc, index);
834
835 DPRINTF(SyscallVerbose, "In sys_clone:\n");
836 DPRINTF(SyscallVerbose, " Flags=%llx\n", flags);
837 DPRINTF(SyscallVerbose, " Child stack=%llx\n", newStack);
838
839
840 if (flags != 0x10f00) {
841 warn("This sys_clone implementation assumes flags "
842 "CLONE_VM|CLONE_FS|CLONE_FILES|CLONE_SIGHAND|CLONE_THREAD "
843 "(0x10f00), and may not work correctly with given flags "
844 "0x%llx\n", flags);
845 }
846
847 ThreadContext* ctc; // child thread context
848 if ((ctc = process->findFreeContext())) {
849 DPRINTF(SyscallVerbose, " Found unallocated thread context\n");
850
851 ctc->clearArchRegs();
852
853 // Arch-specific cloning code
854 #if THE_ISA == ALPHA_ISA or THE_ISA == X86_ISA
855 // Cloning the misc. regs for these archs is enough
856 TheISA::copyMiscRegs(tc, ctc);
857 #elif THE_ISA == SPARC_ISA
858 TheISA::copyRegs(tc, ctc);
859
860 // TODO: Explain what this code actually does :-)
861 ctc->setIntReg(NumIntArchRegs + 6, 0);
862 ctc->setIntReg(NumIntArchRegs + 4, 0);
863 ctc->setIntReg(NumIntArchRegs + 3, NWindows - 2);
864 ctc->setIntReg(NumIntArchRegs + 5, NWindows);
865 ctc->setMiscReg(MISCREG_CWP, 0);
866 ctc->setIntReg(NumIntArchRegs + 7, 0);
867 ctc->setMiscRegNoEffect(MISCREG_TL, 0);
868 ctc->setMiscReg(MISCREG_ASI, ASI_PRIMARY);
869
870 for (int y = 8; y < 32; y++)
871 ctc->setIntReg(y, tc->readIntReg(y));
872 #elif THE_ISA == ARM_ISA
873 TheISA::copyRegs(tc, ctc);
874 #else
875 fatal("sys_clone is not implemented for this ISA\n");
876 #endif
877
878 // Set up stack register
879 ctc->setIntReg(TheISA::StackPointerReg, newStack);
880
881 // Set up syscall return values in parent and child
882 ctc->setIntReg(ReturnValueReg, 0); // return value, child
883
884 // Alpha needs SyscallSuccessReg=0 in child
885 #if THE_ISA == ALPHA_ISA
886 ctc->setIntReg(TheISA::SyscallSuccessReg, 0);
887 #endif
888
889 // In SPARC/Linux, clone returns 0 on pseudo-return register if
890 // parent, non-zero if child
891 #if THE_ISA == SPARC_ISA
892 tc->setIntReg(TheISA::SyscallPseudoReturnReg, 0);
893 ctc->setIntReg(TheISA::SyscallPseudoReturnReg, 1);
894 #endif
895
896 ctc->pcState(tc->nextInstAddr());
897
898 ctc->activate();
899
900 // Should return nonzero child TID in parent's syscall return register,
901 // but for our pthread library any non-zero value will work
902 return 1;
903 } else {
904 fatal("Called sys_clone, but no unallocated thread contexts found!\n");
905 return 0;
906 }
907}
908
909SyscallReturn
910fallocateFunc(SyscallDesc *desc, int callnum, Process *p, ThreadContext *tc)
911{
912#if NO_FALLOCATE
913 warn("Host OS cannot support calls to fallocate. Ignoring syscall");
914#else
915 int index = 0;
916 int tgt_fd = p->getSyscallArg(tc, index);
917 int mode = p->getSyscallArg(tc, index);
918 off_t offset = p->getSyscallArg(tc, index);
919 off_t len = p->getSyscallArg(tc, index);
920
921 auto ffdp = std::dynamic_pointer_cast<FileFDEntry>((*p->fds)[tgt_fd]);
922 if (!ffdp)
923 return -EBADF;
924 int sim_fd = ffdp->getSimFD();
925
926 int result = fallocate(sim_fd, mode, offset, len);
927 if (result < 0)
928 return -errno;
929#endif
930 return 0;
931}
932
933SyscallReturn
934accessFunc(SyscallDesc *desc, int callnum, Process *p, ThreadContext *tc,
935 int index)
936{
937 string path;
938 if (!tc->getMemProxy().tryReadString(path, p->getSyscallArg(tc, index)))
939 return -EFAULT;
940
941 // Adjust path for current working directory
942 path = p->fullPath(path);
943
944 mode_t mode = p->getSyscallArg(tc, index);
945
946 int result = access(path.c_str(), mode);
947 return (result == -1) ? -errno : result;
948}
949
950SyscallReturn
951accessFunc(SyscallDesc *desc, int callnum, Process *p, ThreadContext *tc)
952{
953 return accessFunc(desc, callnum, p, tc, 0);
954}
955