3a0db10163f058bb8a54905682f0322eff8de1fe
2 * Copyright (c) 2003-2005 The Regents of The University of Michigan
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.
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.
28 * Authors: Steve Reinhardt
38 #include "sim/syscall_emul.hh"
39 #include "base/chunk_generator.hh"
40 #include "base/trace.hh"
41 #include "cpu/thread_context.hh"
42 #include "cpu/base.hh"
43 #include "mem/page_table.hh"
44 #include "sim/process.hh"
46 #include "sim/sim_exit.hh"
49 using namespace TheISA
;
52 SyscallDesc::doSyscall(int callnum
, LiveProcess
*process
, ThreadContext
*tc
)
54 DPRINTFR(SyscallVerbose
, "%d: %s: syscall %s called w/arguments %d,%d,%d,%d\n",
55 curTick
,tc
->getCpuPtr()->name(), name
,
56 tc
->getSyscallArg(0),tc
->getSyscallArg(1),
57 tc
->getSyscallArg(2),tc
->getSyscallArg(3));
59 SyscallReturn retval
= (*funcPtr
)(this, callnum
, process
, tc
);
61 DPRINTFR(SyscallVerbose
, "%d: %s: syscall %s returns %d\n",
62 curTick
,tc
->getCpuPtr()->name(), name
, retval
.value());
64 if (!(flags
& SyscallDesc::SuppressReturnValue
))
65 tc
->setSyscallReturn(retval
);
70 unimplementedFunc(SyscallDesc
*desc
, int callnum
, LiveProcess
*process
,
73 fatal("syscall %s (#%d) unimplemented.", desc
->name
, callnum
);
80 ignoreFunc(SyscallDesc
*desc
, int callnum
, LiveProcess
*process
,
83 warn("ignoring syscall %s(%d, %d, ...)", desc
->name
,
84 tc
->getSyscallArg(0), tc
->getSyscallArg(1));
91 exitFunc(SyscallDesc
*desc
, int callnum
, LiveProcess
*process
,
95 exitSimLoop("target called exit()", tc
->getSyscallArg(0) & 0xff);
103 getpagesizeFunc(SyscallDesc
*desc
, int num
, LiveProcess
*p
, ThreadContext
*tc
)
105 return (int)VMPageSize
;
110 obreakFunc(SyscallDesc
*desc
, int num
, LiveProcess
*p
, ThreadContext
*tc
)
114 // change brk addr to first arg
115 Addr new_brk
= tc
->getSyscallArg(0);
117 for (ChunkGenerator
gen(p
->brk_point
, new_brk
- p
->brk_point
,
118 VMPageSize
); !gen
.done(); gen
.next()) {
119 if (!p
->pTable
->translate(gen
.addr(), junk
))
120 p
->pTable
->allocate(roundDown(gen
.addr(), VMPageSize
),
123 p
->brk_point
= new_brk
;
125 DPRINTF(SyscallVerbose
, "Break Point changed to: %#X\n", p
->brk_point
);
131 closeFunc(SyscallDesc
*desc
, int num
, LiveProcess
*p
, ThreadContext
*tc
)
133 int target_fd
= tc
->getSyscallArg(0);
134 int status
= close(p
->sim_fd(target_fd
));
136 p
->free_fd(target_fd
);
142 readFunc(SyscallDesc
*desc
, int num
, LiveProcess
*p
, ThreadContext
*tc
)
144 int fd
= p
->sim_fd(tc
->getSyscallArg(0));
145 int nbytes
= tc
->getSyscallArg(2);
146 BufferArg
bufArg(tc
->getSyscallArg(1), nbytes
);
148 int bytes_read
= read(fd
, bufArg
.bufferPtr(), nbytes
);
150 if (bytes_read
!= -1)
151 bufArg
.copyOut(tc
->getMemPort());
157 writeFunc(SyscallDesc
*desc
, int num
, LiveProcess
*p
, ThreadContext
*tc
)
159 int fd
= p
->sim_fd(tc
->getSyscallArg(0));
160 int nbytes
= tc
->getSyscallArg(2);
161 BufferArg
bufArg(tc
->getSyscallArg(1), nbytes
);
163 bufArg
.copyIn(tc
->getMemPort());
165 int bytes_written
= write(fd
, bufArg
.bufferPtr(), nbytes
);
169 return bytes_written
;
174 lseekFunc(SyscallDesc
*desc
, int num
, LiveProcess
*p
, ThreadContext
*tc
)
176 int fd
= p
->sim_fd(tc
->getSyscallArg(0));
177 uint64_t offs
= tc
->getSyscallArg(1);
178 int whence
= tc
->getSyscallArg(2);
180 off_t result
= lseek(fd
, offs
, whence
);
182 return (result
== (off_t
)-1) ? -errno
: result
;
187 _llseekFunc(SyscallDesc
*desc
, int num
, LiveProcess
*p
, ThreadContext
*tc
)
189 int fd
= p
->sim_fd(tc
->getSyscallArg(0));
190 uint64_t offset_high
= tc
->getSyscallArg(1);
191 uint32_t offset_low
= tc
->getSyscallArg(2);
192 Addr result_ptr
= tc
->getSyscallArg(3);
193 int whence
= tc
->getSyscallArg(4);
195 uint64_t offset
= (offset_high
<< 32) | offset_low
;
197 uint64_t result
= lseek(fd
, offset
, whence
);
198 result
= TheISA::htog(result
);
200 if (result
== (off_t
)-1) {
204 //The seek succeeded.
205 //Copy "result" to "result_ptr"
206 //XXX We'll assume that the size of loff_t is 64 bits on the
208 BufferArg
result_buf(result_ptr
, sizeof(result
));
209 memcpy(result_buf
.bufferPtr(), &result
, sizeof(result
));
210 result_buf
.copyOut(tc
->getMemPort());
215 return (result
== (off_t
)-1) ? -errno
: result
;
220 munmapFunc(SyscallDesc
*desc
, int num
, LiveProcess
*p
, ThreadContext
*tc
)
222 // given that we don't really implement mmap, munmap is really easy
227 const char *hostname
= "m5.eecs.umich.edu";
230 gethostnameFunc(SyscallDesc
*desc
, int num
, LiveProcess
*p
, ThreadContext
*tc
)
232 int name_len
= tc
->getSyscallArg(1);
233 BufferArg
name(tc
->getSyscallArg(0), name_len
);
235 strncpy((char *)name
.bufferPtr(), hostname
, name_len
);
237 name
.copyOut(tc
->getMemPort());
243 getcwdFunc(SyscallDesc
*desc
, int num
, LiveProcess
*p
, ThreadContext
*tc
)
246 unsigned long size
= tc
->getSyscallArg(1);
247 BufferArg
buf(tc
->getSyscallArg(0), size
);
249 // Is current working directory defined?
250 string cwd
= p
->getcwd();
252 if (cwd
.length() >= size
) {
256 strncpy((char *)buf
.bufferPtr(), cwd
.c_str(), size
);
257 result
= cwd
.length();
260 if (getcwd((char *)buf
.bufferPtr(), size
) != NULL
) {
261 result
= strlen((char *)buf
.bufferPtr());
268 buf
.copyOut(tc
->getMemPort());
270 return (result
== -1) ? -errno
: result
;
275 readlinkFunc(SyscallDesc
*desc
, int num
, LiveProcess
*p
, ThreadContext
*tc
)
279 if (!tc
->getMemPort()->tryReadString(path
, tc
->getSyscallArg(0)))
280 return (TheISA::IntReg
)-EFAULT
;
282 // Adjust path for current working directory
283 path
= p
->fullPath(path
);
285 size_t bufsiz
= tc
->getSyscallArg(2);
286 BufferArg
buf(tc
->getSyscallArg(1), bufsiz
);
288 int result
= readlink(path
.c_str(), (char *)buf
.bufferPtr(), bufsiz
);
290 buf
.copyOut(tc
->getMemPort());
292 return (result
== -1) ? -errno
: result
;
296 unlinkFunc(SyscallDesc
*desc
, int num
, LiveProcess
*p
, ThreadContext
*tc
)
300 if (!tc
->getMemPort()->tryReadString(path
, tc
->getSyscallArg(0)))
301 return (TheISA::IntReg
)-EFAULT
;
303 // Adjust path for current working directory
304 path
= p
->fullPath(path
);
306 int result
= unlink(path
.c_str());
307 return (result
== -1) ? -errno
: result
;
312 mkdirFunc(SyscallDesc
*desc
, int num
, LiveProcess
*p
, ThreadContext
*tc
)
316 if (!tc
->getMemPort()->tryReadString(path
, tc
->getSyscallArg(0)))
317 return (TheISA::IntReg
)-EFAULT
;
319 // Adjust path for current working directory
320 path
= p
->fullPath(path
);
322 mode_t mode
= tc
->getSyscallArg(1);
324 int result
= mkdir(path
.c_str(), mode
);
325 return (result
== -1) ? -errno
: result
;
329 renameFunc(SyscallDesc
*desc
, int num
, LiveProcess
*p
, ThreadContext
*tc
)
333 if (!tc
->getMemPort()->tryReadString(old_name
, tc
->getSyscallArg(0)))
338 if (!tc
->getMemPort()->tryReadString(new_name
, tc
->getSyscallArg(1)))
341 // Adjust path for current working directory
342 old_name
= p
->fullPath(old_name
);
343 new_name
= p
->fullPath(new_name
);
345 int64_t result
= rename(old_name
.c_str(), new_name
.c_str());
346 return (result
== -1) ? -errno
: result
;
350 truncateFunc(SyscallDesc
*desc
, int num
, LiveProcess
*p
, ThreadContext
*tc
)
354 if (!tc
->getMemPort()->tryReadString(path
, tc
->getSyscallArg(0)))
357 off_t length
= tc
->getSyscallArg(1);
359 // Adjust path for current working directory
360 path
= p
->fullPath(path
);
362 int result
= truncate(path
.c_str(), length
);
363 return (result
== -1) ? -errno
: result
;
367 ftruncateFunc(SyscallDesc
*desc
, int num
, LiveProcess
*process
, ThreadContext
*tc
)
369 int fd
= process
->sim_fd(tc
->getSyscallArg(0));
374 off_t length
= tc
->getSyscallArg(1);
376 int result
= ftruncate(fd
, length
);
377 return (result
== -1) ? -errno
: result
;
381 umaskFunc(SyscallDesc
*desc
, int num
, LiveProcess
*process
, ThreadContext
*tc
)
383 // Letting the simulated program change the simulator's umask seems like
384 // a bad idea. Compromise by just returning the current umask but not
385 // changing anything.
386 mode_t oldMask
= umask(0);
392 chownFunc(SyscallDesc
*desc
, int num
, LiveProcess
*p
, ThreadContext
*tc
)
396 if (!tc
->getMemPort()->tryReadString(path
, tc
->getSyscallArg(0)))
400 uint32_t owner
= tc
->getSyscallArg(1);
401 uid_t hostOwner
= owner
;
402 uint32_t group
= tc
->getSyscallArg(2);
403 gid_t hostGroup
= group
;
405 // Adjust path for current working directory
406 path
= p
->fullPath(path
);
408 int result
= chown(path
.c_str(), hostOwner
, hostGroup
);
409 return (result
== -1) ? -errno
: result
;
413 fchownFunc(SyscallDesc
*desc
, int num
, LiveProcess
*process
, ThreadContext
*tc
)
415 int fd
= process
->sim_fd(tc
->getSyscallArg(0));
421 uint32_t owner
= tc
->getSyscallArg(1);
422 uid_t hostOwner
= owner
;
423 uint32_t group
= tc
->getSyscallArg(2);
424 gid_t hostGroup
= group
;
426 int result
= fchown(fd
, hostOwner
, hostGroup
);
427 return (result
== -1) ? -errno
: result
;
432 dupFunc(SyscallDesc
*desc
, int num
, LiveProcess
*process
, ThreadContext
*tc
)
434 int fd
= process
->sim_fd(tc
->getSyscallArg(0));
438 Process::FdMap
*fdo
= process
->sim_fd_obj(tc
->getSyscallArg(0));
440 int result
= dup(fd
);
441 return (result
== -1) ? -errno
: process
->alloc_fd(result
, fdo
->filename
, fdo
->flags
, fdo
->mode
, false);
446 fcntlFunc(SyscallDesc
*desc
, int num
, LiveProcess
*process
,
449 int fd
= tc
->getSyscallArg(0);
451 if (fd
< 0 || process
->sim_fd(fd
) < 0)
454 int cmd
= tc
->getSyscallArg(1);
457 // if we really wanted to support this, we'd need to do it
458 // in the target fd space.
459 warn("fcntl(%d, F_DUPFD) not supported, error returned\n", fd
);
462 case 1: // F_GETFD (get close-on-exec flag)
463 case 2: // F_SETFD (set close-on-exec flag)
466 case 3: // F_GETFL (get file flags)
467 case 4: // F_SETFL (set file flags)
468 // not sure if this is totally valid, but we'll pass it through
469 // to the underlying OS
470 warn("fcntl(%d, %d) passed through to host\n", fd
, cmd
);
471 return fcntl(process
->sim_fd(fd
), cmd
);
474 case 7: // F_GETLK (get lock)
475 case 8: // F_SETLK (set lock)
476 case 9: // F_SETLKW (set lock and wait)
477 // don't mess with file locking... just act like it's OK
478 warn("File lock call (fcntl(%d, %d)) ignored.\n", fd
, cmd
);
482 warn("Unknown fcntl command %d\n", cmd
);
488 fcntl64Func(SyscallDesc
*desc
, int num
, LiveProcess
*process
,
491 int fd
= tc
->getSyscallArg(0);
493 if (fd
< 0 || process
->sim_fd(fd
) < 0)
496 int cmd
= tc
->getSyscallArg(1);
499 warn("fcntl64(%d, F_GETLK64) not supported, error returned\n", fd
);
502 case 34: // F_SETLK64
503 case 35: // F_SETLKW64
504 warn("fcntl64(%d, F_SETLK(W)64) not supported, error returned\n", fd
);
508 // not sure if this is totally valid, but we'll pass it through
509 // to the underlying OS
510 warn("fcntl64(%d, %d) passed through to host\n", fd
, cmd
);
511 return fcntl(process
->sim_fd(fd
), cmd
);
517 pipePseudoFunc(SyscallDesc
*desc
, int callnum
, LiveProcess
*process
,
520 int fds
[2], sim_fds
[2];
521 int pipe_retval
= pipe(fds
);
523 if (pipe_retval
< 0) {
528 sim_fds
[0] = process
->alloc_fd(fds
[0], "PIPE-READ", O_WRONLY
, -1, true);
529 sim_fds
[1] = process
->alloc_fd(fds
[1], "PIPE-WRITE", O_RDONLY
, -1, true);
531 process
->setReadPipeSource(sim_fds
[0], sim_fds
[1]);
532 // Alpha Linux convention for pipe() is that fd[0] is returned as
533 // the return value of the function, and fd[1] is returned in r20.
534 tc
->setIntReg(SyscallPseudoReturnReg
, sim_fds
[1]);
540 getpidPseudoFunc(SyscallDesc
*desc
, int callnum
, LiveProcess
*process
,
543 // Make up a PID. There's no interprocess communication in
544 // fake_syscall mode, so there's no way for a process to know it's
545 // not getting a unique value.
547 tc
->setIntReg(SyscallPseudoReturnReg
, process
->ppid());
548 return process
->pid();
553 getuidPseudoFunc(SyscallDesc
*desc
, int callnum
, LiveProcess
*process
,
556 // Make up a UID and EUID... it shouldn't matter, and we want the
557 // simulation to be deterministic.
560 tc
->setIntReg(SyscallPseudoReturnReg
, process
->euid()); //EUID
561 return process
->uid(); // UID
566 getgidPseudoFunc(SyscallDesc
*desc
, int callnum
, LiveProcess
*process
,
569 // Get current group ID. EGID goes in r20.
570 tc
->setIntReg(SyscallPseudoReturnReg
, process
->egid()); //EGID
571 return process
->gid();
576 setuidFunc(SyscallDesc
*desc
, int callnum
, LiveProcess
*process
,
579 // can't fathom why a benchmark would call this.
580 warn("Ignoring call to setuid(%d)\n", tc
->getSyscallArg(0));
585 getpidFunc(SyscallDesc
*desc
, int callnum
, LiveProcess
*process
,
588 // Make up a PID. There's no interprocess communication in
589 // fake_syscall mode, so there's no way for a process to know it's
590 // not getting a unique value.
592 tc
->setIntReg(SyscallPseudoReturnReg
, process
->ppid()); //PID
593 return process
->pid();
597 getppidFunc(SyscallDesc
*desc
, int callnum
, LiveProcess
*process
,
600 return process
->ppid();
604 getuidFunc(SyscallDesc
*desc
, int callnum
, LiveProcess
*process
,
607 return process
->uid(); // UID
611 geteuidFunc(SyscallDesc
*desc
, int callnum
, LiveProcess
*process
,
614 return process
->euid(); // UID
618 getgidFunc(SyscallDesc
*desc
, int callnum
, LiveProcess
*process
,
621 return process
->gid();
625 getegidFunc(SyscallDesc
*desc
, int callnum
, LiveProcess
*process
,
628 return process
->egid();